Registro de desplazamiento de 3 etapas usando asignación de bloqueo en Verilog - Diferencias entre simuladores

La simulación de un registro de desplazamiento de 3 etapas utilizando la declaración de asignación de bloqueo en Verilog brinda diferentes resultados de simulación en los simuladores:

El código RTL es el siguiente:

`include "timescale.hv"
module shift_register 
#(
parameter DATA_WIDTH = 3
)
(
input  wire  [(DATA_WIDTH-1):0] din   ,
input  wire                     clk   ,
input  wire                     rst_n ,
output wire  [(DATA_WIDTH-1):0] out
);

reg [(DATA_WIDTH-1):0] q1,q2,q3;

assign out = q3;

always @ (posedge clk or negedge rst_n) begin
   if(~rst_n) begin
      q1 = {(DATA_WIDTH){1'b0}};
      q2 = {(DATA_WIDTH){1'b0}};
      q3 = {(DATA_WIDTH){1'b0}};
   end else begin
      q3 = q2;
      q2 = q1;
      q1 = din;
   end
end

endmodule

El código del banco de pruebas para la simulación del RTL anterior es el siguiente:

`include "timescale.hv"
module tb_shift_register ();

localparam DATA_WIDTH = 4;

reg [(DATA_WIDTH-1):0]  din   ;
reg                     clk   ;
reg                     rst_n ;

wire [(DATA_WIDTH-1):0] out   ;

shift_register 
#(
.DATA_WIDTH(DATA_WIDTH)
)
inst_shift_register
(
.din   ( din   ),
.clk   ( clk   ),
.rst_n ( rst_n ),
.out   ( out   )
);

initial begin
   clk   = 1'b0;
   rst_n = 1'b0;
   din   = {(DATA_WIDTH){1'b0}};
   #20;
   rst_n = 1'b1;
end

always #5 clk = ~clk;

always@(posedge clk) begin
   if(rst_n) begin
      din = 4'd15;
   end
end

endmodule

Cuando la simulación funcional se realiza utilizando el TB anterior para el RTL (mencionado anteriormente) en ModelSim, se observa la siguiente forma de onda:

ingrese la descripción de la imagen aquí

La simulación aparece exactamente igual que la de un registro de desplazamiento de 3 etapas que usa asignación sin bloqueo, donde la salida aparece después de 3 ciclos de reloj y la entrada "din" aparece en "q1" solo en el siguiente ciclo de reloj.

Cuando se realiza la simulación para el mismo RTL y TB utilizando Xilinx Vivado, se observa la siguiente forma de onda:

ingrese la descripción de la imagen aquí

Se observa que la salida aparece en "q3" después de solo 2 ciclos de reloj y la entrada "din" aparece en "q1" en el mismo ciclo de reloj.

Entonces, tengo 2 preguntas:

  1. Aunque se espera que para la asignación de bloqueo, la entrada "din" debe aparecer en "q1" en el mismo ciclo de reloj, ¿por qué la simulación de ModelSim muestra que la entrada "din" aparece en "q1" en el siguiente ciclo de reloj? ¿Cuál de los simuladores es el correcto?
  2. ¿Cómo modelar un registro de desplazamiento perfecto de 3 etapas utilizando la declaración de asignación de bloqueo en Verilog? (que se sintetiza como un registro de tubería de 3 etapas y que, cuando se simula, muestra que la salida en "q3" aparece después de 3 ciclos de reloj).

Nota: soy consciente del hecho de que la declaración de asignación de bloqueo debe usarse para modelar una lógica combinacional, mientras que una declaración de asignación sin bloqueo debe usarse para modelar una lógica secuencial. Hago esta pregunta porque esta fue una pregunta de la entrevista que me hicieron sobre la implementación de un registro de desplazamiento de 3 etapas usando una declaración de bloqueo.

sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf , creo que puedes leer este documento

Respuestas (1)

Usted dinestá cambiando al mismo tiempo que el borde del reloj. Esta es una condición de carrera y como tal, el comportamiento del simulador no está definido.

Esto se debe a que usa la asignación de bloqueo aquí:

always@(posedge clk) begin
   if(rst_n) begin
      din = 4'd15;  // << WRONG!
   end
end

Cambie eso a una asignación sin bloqueo:

always@(posedge clk) begin
   if(rst_n) begin
      din <= 4'd15;  
   end
end

Pero también cambie todas sus otras asignaciones a no bloqueantes: la única razón por la que está funcionando en este momento es accidentalmente porque colocó las asignaciones en el orden q3..q1.

always @ (posedge clk or negedge rst_n) begin
   if(~rst_n) begin
      q1 <= {(DATA_WIDTH){1'b0}};
      q2 <= {(DATA_WIDTH){1'b0}};
      q3 <= {(DATA_WIDTH){1'b0}};
   end else begin
      q3 <= q2;
      q2 <= q1;
      q1 <= din;
   end
end