3-Stufen-Schieberegister mit Blockierungszuweisung in Verilog - Unterschiede zwischen Simulatoren

Die Simulation eines 3-Stufen-Schieberegisters mit Blocking Assignment Statement in Verilog führt zu unterschiedlichen Simulationsergebnissen über die Simulatoren hinweg:

Der RTL-Code lautet wie folgt:

`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

Der Testbench-Code für die Simulation der obigen RTL lautet wie folgt:

`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

Wenn die Funktionssimulation unter Verwendung des obigen TB für die RTL (oben erwähnt) in ModelSim durchgeführt wird, wird die folgende Wellenform beobachtet:

Geben Sie hier die Bildbeschreibung ein

Die Simulation erscheint genauso wie die eines 3-Stufen-Schieberegisters mit nicht-blockierender Zuweisung, wo die Ausgabe nach 3 Taktzyklen erscheint und die Eingabe "din" erst beim nächsten Taktzyklus bei "q1" erscheint.

Wenn die Simulation für dieselbe RTL und TB mit Xilinx Vivado durchgeführt wird, wird die folgende Wellenform beobachtet:

Geben Sie hier die Bildbeschreibung ein

Es wird beobachtet, dass die Ausgabe bei "q3" nach nur 2 Taktzyklen erscheint und die Eingabe "din" bei "q1" im selben Taktzyklus erscheint.

Da stellen sich mir 2 Fragen:

  1. Obwohl erwartet wird, dass für die Sperrzuweisung der Eingang „din“ im selben Taktzyklus bei „q1“ erscheinen muss, warum zeigt die ModelSim-Simulation, dass der Eingang „din“ im nächsten Taktzyklus bei „q1“ erscheint. Welcher der Simulatoren ist richtig?
  2. Wie modelliere ich ein perfektes 3-Stufen-Schieberegister mithilfe der Blockzuweisungsanweisung in Verilog? (das als 3-stufiges Pipeline-Register synthetisiert ist und das bei Simulation zeigt, dass die Ausgabe bei "q3" nach 3 Taktzyklen erscheint).

Hinweis: Ich bin mir der Tatsache bewusst, dass eine blockierende Zuweisungsanweisung zum Modellieren einer kombinatorischen Logik verwendet werden sollte, während eine nicht blockierende Zuweisungsanweisung zum Modellieren einer sequentiellen Logik verwendet werden sollte. Ich stelle diese Frage, da dies eine Interviewfrage war, die mir bezüglich der Implementierung eines 3-stufigen Schieberegisters mit Sperranweisung gestellt wurde.

sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf , ich denke, Sie können dieses Papier durchgehen

Antworten (1)

Sie dinändert sich gleichzeitig mit der Taktflanke. Dies ist eine Racebedingung und als solche ist das Verhalten des Simulators nicht definiert.

Dies liegt daran, dass Sie hier eine blockierende Zuweisung verwenden:

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

Ändern Sie das in eine nicht blockierende Zuweisung:

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

Aber ändern Sie auch alle Ihre anderen Zuweisungen auf nicht blockierend: Der einzige Grund, warum es im Moment funktioniert, ist versehentlich, weil Sie die Zuweisungen in die Reihenfolge q3..q1 gesetzt haben.

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