Veriog: ¿Cómo pasar un registro a un módulo?

0

Supongamos que tenemos un módulo con una salida de 32 bits como este:

module ModuleLow(foo,...);
output [31:0] foo;

Ahora queremos usarlo en otro módulo (¡un ejemplo muy simple!):

module ModuleHigh( ..,reset,..);
input reset;

wire [31:0] fooWire;
reg  [31:0] fooReg;
ModuleLow module1(.foo(fooWire), ...)

always @(posedge GCLK)
 if(reset)
    begin
      fooReg<= fooWire;   // TRIAL-1: fooReg<=  12345.....;  => 2.3ns
    end
 else
     fooReg<=fooReg+1;    //TRIAL-2 :  fooReg<=fooWire+1; => 18ns

Este es un método muy común para pasar un valor entre módulos (wire - > reg). Pero en mi caso, conduce a un cable de 2028 bits que reduce notablemente la velocidad de un Spartan-III a 12ns .

He intentado estos:

1- Cuando sustituyo la instrucción fooReg<= fooWire con un número (como: fooReg<=12345....; TRIAL-1 en el código), el rendimiento salta alto (GCLK valor de restricción de tiempo < 2.5 ns ).

2- Cuando uso el cable (usando fooReg<=fooWire+1 ; TRIAL-2 en el ejemplo de código), el rendimiento disminuye aún más ( 18ns )

De estos experimentos, llegué a la conclusión de que es mucho más fácil de usar usar registros dentro de un bloque en lugar de cables (¿problemas de enrutamiento y DRC?).

Estaba pensando si hay una manera de omitir ese cable intermedio entre los módulos. Esto puede eliminar el cableado en la parte "TRIAL-1" (asignación inicial) que conduce a un mayor rendimiento. Algo como esto:

ModuleLow module1(.foo(fooReg), ...); // using registry without a wire.

Creo que esto es ilegal en Verilog (ISE WebPack v14.7 da error como problema de asignación de valores) pero estoy buscando algún truco o algo si existe.

    
pregunta Aug

3 respuestas

2

Tu conclusión no es correcta. No importa al hardware si usa reg o wire , los problemas que está discutiendo son parte de la sintaxis de Verilog.

La razón por la que su diseño se vuelve mucho más rápido cuando reemplaza fooWire con un número es que su lógica no está haciendo nada y todo se optimiza. La asignación de fooWire a fooReg requiere que las señales se propaguen realmente de una parte del chip a otra, y eso lleva tiempo. Cambiar la asignación de fooWire a fooWire+1 obliga a las herramientas a crear un sumador de 32 bits e insertarlo en la ruta de retardo, por lo que, por supuesto, el diseño se volverá más lento.

Por cierto, es registrar , no registro .

    
respondido por el Joe Hass
2

Acabo de responder una de tus tres preguntas principales aquí, ya que esto se prolongó lo suficiente como para centrarme en la pregunta.

  

Cuando sustituyo la declaración fooReg < = fooWire con un número (como: fooReg < = 12345 ....; TRIAL-1 en el código), el rendimiento salta alto (valor de restricción de tiempo GCLK < 2.5 ns).

Supongo que estás preguntando, "¿por qué es esto?" Veamos su código:

always @(posedge GCLK)
 if(reset)
    begin
      fooReg<= fooWire;   
    end
 else
     fooReg<=fooReg+1;    

Este código no representa correctamente un registro con RESET. Una entrada RESET (también conocida como PRESET / CLEAR) borra la salida a un valor fijo, ya sea 1 o 0, cada vez que se utiliza. Su código establece que la salida sea igual a un valor de entrada que podría cambiar cada vez que se vea la señal reset .

Tu código también podría escribirse como

always @(posedge GCLK)
  fooReg <= SEL ? fooWire : fooReg+1;

donde cambié el nombre de reset a SEL para enfatizar que actúa como la línea de selección en un multiplexor.

Cuando cambias el código a

always @(posedge GCLK)
 if(reset)
    begin
      fooReg<= 12345;  
    end
 else ...

Entonces, en realidad estás implementando un circuito de reinicio, y el código puede sintetizarse para usar las líneas de reinicio de hardware en los flip-flops que contienen fooReg .

El reinicio del hardware puede ser más rápido por varias razones:

  • la señal reset se puede transportar en una interconexión de restablecimiento global en lugar de cables normales.
  • Se elimina una capa de lógica (el multiplexor) entre el sumador (fooReg + 1) y el registro.
  • Un contador con restablecimiento probablemente esté disponible como un bloque predefinido altamente optimizado, no sujeto a los caprichos del lugar y al proceso de optimización de ruta de la herramienta.
respondido por el The Photon
1

Esta respuesta solo hablará sobre una parte de tu pregunta,

  

ModuleLow module1(.foo(fooReg), ...); // using registry without a wire.

El problema principal aquí es que si fooReg es un registro, desea que todas las asignaciones a ese registro estén en el mismo bloque always .

No puede (o al menos no quiere) tener un bloque always en ModuleLow que establece el valor inicial, y otro bloque always en ModuleHigh que lo incrementa cuando llega el borde del reloj.

Tal cosa podría funcionar en simulación (usando tareas en lugar de módulos) pero lo más probable es que rompa la síntesis, y también confunda el hecho de que alguien lea su código (incluyéndolo a usted si vuelve a leerlo después). un par de días).

    
respondido por el The Photon

Lea otras preguntas en las etiquetas