¿Qué valor se utilizará en un bloque siempre?

0

Aquí hay un código verilog: (Este código no es para síntesis)

'timescale 1 ns / 1 ns

module test;
    reg r1, r2, r3, r4;
    reg clk_at_time, clk_from_clk;


    // Initialize signals 
    initial begin
      r1 <= 1;
      r2 <= 0;
      clk_at_time <= 1;
      #200
      $finish();
    end


    // Generating simple a clock (period time is 10ns)  (as expected)
    always #5
        clk_at_time <= ~clk_at_time;


    // Generating a clock based on the clk_at_time.
    // This clk_from_clk is always equals the clk_at_time (as expected)
    always @ clk_at_time
        clk_from_clk <= clk_at_time;


    // r1 and r2 inverted at all posedge event. (as expected)
    // r3 is constant 0 (as expected)
    always @(posedge clk_at_time) begin
        r1 <= r2;
        r2 <= r1;
        r3 <= clk_from_clk;
    end


    // r4 is constant 1  ???!!!??? HOW ???!!!???
    always @(posedge clk_from_clk) begin
        r4 <= clk_at_time;
    end

endmodule

Y la forma de onda de la simulación:

En el código hay dos relojes: primero es el reloj tradicional generado por el tiempo always #5 el segundo es generado por este reloj always @ clk_at_time Los dos relojes siempre son iguales (como se esperaba)

Lo extraño es que si uso clk_from_clk en el bloque de clk_at_time, se usará el valor anterior de clk_from_clk. (OK), PERO si uso clk_at_time en el bloque de clk_from_clk, se usará el valor NEW de clk_at_time.

Aclarar: Vea la forma de onda: clk_from_clk y clk_at_time son siempre iguales.

Ver código: r3 y r4 son analógicos:

  • r3 está en el bloque de clk_at_time y es impulsado por clk_from_clk
  • r4 está en el bloque de clk_from_clk y es impulsado por clk_at_time

Entonces, si clk_from_clk y clk_at_time son realmente los mismos r3 y r4 deberían ser iguales siempre. PERO vea la forma de onda: r3 siempre es 0 y r4 siempre es 1

¿CÓMO? ¿Cuál es la regla?

    
pregunta betontalpfa

1 respuesta

1

clk_at_time lleva a clk_from_time y hay un retardo de tiempo cero entre los dos. No puede ver el desplazamiento en una forma de onda o una instrucción $monitor , pero está ahí. Para comprender los resultados de la simulación, debe comprender el programador del proceso Verilog.

La región activa evalúa todas las asignaciones. En un bloque de procedimiento, si se usa la asignación de bloqueo ( = ), el valor calculado se aplica a la variable inmediatamente. Si se usa una asignación sin bloqueo ( <= ), el valor calculado se aplica a la variable en la región NBA. Cualquier referencia de reverencia a la variable con asignaciones no bloqueantes antes de que se ejecute la región NBA utilizará el valor antiguo (no el actualizado).

Estos son los pasos a través del programador que su simulador está tomando para su código:

  1. región ACTIVA
    • eval initial bloquea y calcula pero pospone la actualización en r1, r2, clk_at_time
  2. región de la NBA
    • actualice r1, r2, clk_at_time (valores calculados en el paso 1)
  3. región ACTIVA
    • eval always @ clk_at_time block (cambie 1'bx - > 1'b1 ) y calcula pero pospone la actualización en clk_from_time
    • eval always @(posedge clk_at_time) block ( 1'bx - > 1'b1 es posedge) y calcula pero pospone la actualización en r1, r2, r3
  4. región de la NBA
    • actualice r1, r2, r3, clk_from_time (valores calculados en el paso 3)
  5. región ACTIVA
    • eval always @(posedge clk_from_time) block ( 1'bx - > 1'b1 es posedge) y calcula pero pospone la actualización en r4
  6. región de la NBA
    • actualizar r4 (valor calculado en el paso 5)
  7. # 5 progresión de tiempo
  8. región ACTIVA
    • eval ~clk_at_time y pospone clk_at_time update
  9. región de la NBA
    • actualice clk_at_time (valores calculados en el paso 8)
  10. región ACTIVA
    • eval always @ clk_at_time block (cambie 1'b1 - > 1'b0 ) y calcula pero pospone la actualización en clk_from_time
  11. región de la NBA
    • actualizar clk_from_time (valores calculados en el paso 10)
  12. # 5 progresión de tiempo
  13. región ACTIVA
    • eval always @ clk_at_time block (cambie 1'b0 - > 1'b1 ) y calcula pero pospone la actualización en clk_from_time
    • eval always @(posedge clk_at_time) block ( 1'b0 - > 1'b1 es posedge) y calcula pero pospone la actualización en r1, r2, r3
  14. región de la NBA
    • actualice r1, r2, r3, clk_from_time (valores calculados en el paso 13)
  15. región ACTIVA
    • eval always @(posedge clk_from_time) block ( 1'bx - > 1'b1 es posedge) y calcula pero pospone la actualización en r4
  16. región de la NBA
    • actualizar r4 (valor calculado en el paso 15)
  17. Vuelva al paso 7 hasta que la progresión del tiempo sea # 200 y salga

La forma en que funciona la propagación debería ser más fácil para ti visualizar que cambias todos los <= a <= #1 .

FYI: Por definición, Verilog (intencionalmente) no especifica el orden de evaluación entre dos bloques siempre activados al mismo tiempo. Esto significa que si cambia clk_from_clk <= clk_at_time; a clk_from_clk = clk_at_time; , entonces el valor asignado a r3 puede ser indeterminado porque always @ clk_at_time y always @(posedge clk_at_time) se activan en la misma región ACTIVE. En las prácticas es poco probable que vea el comportamiento indeterminado en la simulación

    
respondido por el Greg

Lea otras preguntas en las etiquetas