¿Cómo está la secuencia de asignación en Verilog?

1

¿Quiero saber si asignamos algo a un registro (o hacemos algo más) en un ciclo de reloj específico, esta asignación se realiza en el ciclo de reloj actual o en el siguiente ciclo? (Configuración: Xilinx, Spartan-3. Codificado por Verilog a través de ISE Webpack)

Ejemplo:

always @(negedge GCLK)
   foo<= bar; // foo is equal to bar in this cycle or next?
    
pregunta Aug

3 respuestas

1
always @(negedge GCLK)
   foo<= bar; // foo is equal to bar in this cycle or next?

En los casos simples en los que no hay nada en el código que haga que bar cambie simultáneamente con GCLK , este bloque dice que cuando se ve un margen negativo en GCLK, "inmediatamente" cambia el valor de foo a lo que sea bar está en ese instante.

"Inmediatamente" significa algo así como una marca de simulación después de que llegó el borde negativo.

Esto significa que cualquier otra transición que ocurra en el mismo borde negativo de GCLK y que dependa del valor de foo verá el valor anterior de foo . Pero foo tendrá el nuevo valor comenzando de inmediato hasta el siguiente borde negativo de GCLK.

Editar en respuesta a los comentarios,

  

Si "cualquier otra transición" ve el valor anterior de foo, ¿podemos asumir que foo es "está disponible en el próximo reloj"?

En el simulador, sí. En la vida real, debe verificar los retrasos de propagación y los tiempos de configuración y de espera para estar seguro.

  

¿qué pasa si ponemos siempre código con begin ... end? ¿Todos serán inmediatos? como: siempre @ (negedge GCLK) comienza .. foo < = bar; x < = foo + 1; fin En este ejemplo, ¿x será barra + 1 en el mismo ciclo que la asignación foo?

No, como se mencionó anteriormente, cualquier otra transición que ocurra en el mismo borde negativo de GCLK y que dependa del valor de foo verá el valor anterior de foo.

Si desea el otro comportamiento, puede usar la asignación de bloqueo:

...
foo = bar; 
x = foo+1; 
...

Las herramientas de síntesis modernas deberían poder compilar esto correctamente, pero las herramientas antiguas podrían no ser capaces de hacerlo. Lo que hará la herramienta moderna es simplemente traducir esto a

foo <= bar;
x <= bar+1;

y compila eso. Desde que aprendí Verilog antes de que este comportamiento fuera confiable, me resulta menos familiar leer el código con tareas de bloqueo.

  

¿Podemos usar asignaciones de bloqueo para tareas inmediatas y no bloqueadas para tareas "retrasadas"?

No tengo muy claro lo que quieres decir con esto. Lo que hace una asignación de bloqueo (en el simulador) es evitar que la siguiente instrucción se ejecute hasta que se complete. Ambos tipos de asignación son inmediatos, pero la evaluación de bloqueo hace que la siguiente instrucción se retrase.

  

Si es así, puede ser un enfoque muy útil para hacer pequeños retrasos en el código

Para pequeños retrasos en la simulación, puede usar eventos de retardo

always @(event) begin
   foo <= x;
   #5 
   bar <= foo;
end

Para pequeños retrasos en el código sintetizado, es mejor que se asegure de que el hardware realmente pueda hacer lo que está pidiendo.

    
respondido por el The Photon
3

La respuesta a esta pregunta está fuertemente relacionada con los conceptos de Verilog que describí en mi respuesta a otra pregunta sobre Verilog asignación sin bloqueo (NBA).

La respuesta directa a su pregunta es muy simple: todas las asignaciones se realizan en el mismo intervalo de tiempo de simulación, es decir, tanto las asignaciones de bloqueo como las de no bloqueo se evaluarán y asignarán antes del siguiente intervalo de tiempo (que comienza con negedge GCLK en su caso).

Los detalles, sin embargo, son importantes!

Las NBA no se asignan en el momento de la evaluación, sino al final del intervalo de tiempo. Esto significa que si usa foo para la evaluación de otras expresiones (por ejemplo, assign blocking = foo; o always @( negedge GCLK ) non_blocking <= foo; ), el valor utilizado será el valor que foo tenía al comienzo del intervalo de tiempo. El resultado neto de este comportamiento es que parece que foo obtiene su nuevo valor solo en el siguiente ciclo de reloj.

Sin embargo, la descripción anterior es solo una simplificación. Le recomiendo que lea este documento de SNUG a fondo y asegúrese de que entienda los detalles finos: esto lo hará sentir mucho más cómodo con Verilog y puede evitar muchos errores desagradables y desajustes entre las simulaciones RTL y FPGA. Específicamente, la sección 2.0 (Verilog Event Queue) contiene la información directamente relacionada con su pregunta.

Espero que esto ayude.

    
respondido por el Vasiliy
1

Verilog tiene varias instrucciones de asignación diferentes con diferencias sutiles

1) 'a = b' asigna algo ahora mismo

2) 'a < = b' toma una copia de b en este momento y la asigna a lo que es esencialmente el final de la marca de tiempo actual (justo antes de que el tiempo esté por avanzar)

3) 'a = #N b' toma una copia de b, detiene la simulación de este bloque durante N segundos y luego asigna una y luego continúa ejecutando el resto del bloque

4) 'a < = #N b' toma una copia de b y continúa simulando este bloque (en la misma marca de reloj) N segundos más tarde se asignará el valor copiado de b

Así que cualquiera de estos cuatro intercambiará de forma segura a y b

siempre @ (mensaje de posición) {    a < = b;    b < = a; }

siempre @ (mensaje de posición) {    a < = # 1 b;    b < = # 1 a; }

siempre @ (mensaje de posición)    a < = b; siempre @ (marcador de posición)    b < = a;

siempre @ (mensaje de posición)    a = # 1 b; siempre @ (marcador de posición)    b = # 1 a;

Si bien todos estos no son seguros para la simulación:

siempre @ (mensaje de posición) {    a = b;    b = a; }

siempre @ (mensaje de posición) {    a = # 1 b;    b = # 1 a; }

siempre @ (mensaje de posición)    a = b; siempre @ (marcador de posición)    b = a;

    
respondido por el Taniwha

Lea otras preguntas en las etiquetas