(笔记)Verilog HDL设计时关于阻塞赋值和非阻塞赋值的8条指导原则以及原因。
对《Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill》一文的笔记
介绍
在逻辑解码的时候,两个众所周知的编码指导规则是:
• Guideline: Use blocking assignments in always blocks that are written to generate combinational logic.
• Guideline: Use nonblocking assignments in always blocks that are written to generate sequential logic.
实际上,它只与仿真有关。
In general, the answer is simulation related. Ignoring the above guidelines can still infer the correct synthesized logic, but the pre-synthesis simulation might not match the behavior of the synthesized circuit.
To understand the reasons behind the above guidelines, one needs to have a full understanding of the functionality and scheduling of Verilog blocking and nonblocking assignments. This paper will detail the functionality and scheduling of blocking and nonblocking assignments.
如何完全理解blocking和nonblocking赋值的功能和时序。这篇文章的重点。
简写
RHS: right-hand-side
LHS: left-hand-side
Verilog race conditions
The IEEE Verilog Standard [2] defines: which statements have a guaranteed order of execution ("Determinism", section 5.4.1), and which statements do not have a guaranteed order of execution ("Nondeterminism", section 5.4.2 & "Race conditions", section 5.5).
竞争的产生条件,两个或两个以上的statement在同一个仿真的time-step中发生。
A Verilog race condition occurs when two or more statements that are scheduled to execute in the same simulation time-step, would give different results when the order of statement execution is changed, as permitted by the IEEE Verilog Standard.
Blocking assignments
Blocking assignment 产生的条件
A problem with blocking assignments occurs when the RHS variable of one assignment in one procedural block is also the LHS variable of another assignment in another procedural block and both equations are scheduled to execute in the same simulation time step, such as on the same clock edge. If blocking assignments are not properly ordered, a race condition can occur. When blocking assignments are scheduled to execute in the same time step, the order execution is unknown.
race condition的产生,example。
module fbosc1 (y1, y2, clk, rst);
output y1, y2;
input clk, rst;
reg y1, y2;
always@(posedge clk orposedge rst)
if(rst) y1 =0; // reset
else y1 = y2;
always@(posedge clk orposedge rst)
if(rst) y2 =1; // preset
else y2 = y1;
endmodule
According to the IEEE Verilog Standard, the two always blocks can be scheduled in any order. If the first always block executes first after a reset, both y1 and y2 will take on the value of 1. If the second always block executes first after a reset, both y1 and y2 will take on the value 0. This clearly represents a Verilog race condition.
时间槽的开始和结束,noblocking的行为。
A nonblocking assignment gets its name because the assignment evaluates the RHS expression of a nonblocking statement at the beginning of a time step and schedules the LHS update to take place at the end of the time step.
nonblocking的两步
1. Evaluate the RHS of nonblocking statements at the beginning of the time step.
2. Update the LHS of nonblocking statements at the end of the time step.
这两步之间还可能有其它的statement发生。
只在两种块中发生:initial和always
Nonblocking assignments are only made to register data types and are therefore only permitted inside of procedural blocks, such as initial blocks and always blocks. Nonblocking assignments are not permitted in continuous assignments.
module fbosc2 (y1, y2, clk, rst);
output y1, y2;
input clk, rst;
reg y1, y2;
always@(posedge clk orposedge rst)
if(rst) y1 <=0; // reset
else y1 <= y2;
always@(posedge clk orposedge rst)
if(rst) y2 <=1; // preset
else y2 <= y1;
endmodule
因为分两步,所以无race情况出现。
Again, according to the IEEE Verilog Standard, the two always blocks can be scheduled in any order. No matter which always block starts first after a reset, both nonblocking RHS expressions will be evaluated at the beginning of the time step and then both nonblocking LHS variables will be updated at the end of the same time step. From a users perspective, the execution of these two nonblocking statements happen in parallel.
Verilog coding guidelines
Before giving further explanation and examples of both blocking and nonblocking assignments, it would be useful to outline eight guidelines that help to accurately simulate hardware, modeled using Verilog. Adherence to these guidelines will also remove 90-100% of the Verilog race conditions encountered by most Verilog designers.
遵守以下这8条guidline,90-100%的race可以避免。
l Guideline #1: When modeling sequential logic, use nonblocking assignments.//时序逻辑
l Guideline #2: When modeling latches, use nonblocking assignments.//锁存器
l Guideline #3:When modeling combinational logic with an always block, use blocking assignments.//always块中组合逻辑
l Guideline #4: When modeling both sequential and combinational logic within the same always block, use nonblocking assignments.//同一个always块中,既有组合逻辑又有时序逻辑
l Guideline #5: Do not mix blocking and nonblocking assignments in the same always block.//同一个always块中,blocking和nonblocking不可混用
l Guideline #6: Do not make assignments to the same variable from more than one always block.//
l Guideline #7: Use $strobe to display values that have been assigned using nonblocking assignments.//显示已经用nonblocking赋值的value,用$strobe
l Guideline #8: Do not make assignments using #0 delays.//不要用#0的delay
The Verilog "stratified event queue"
stratified: 分层的
仿真事件时序图。
stratified event queue可以分成4段:每段之中event的顺序是任意的,不定的。
active events: including
blocking assignments,
continuous assignments,
$display commands,
Evaluate inputs and change outputs of primitives
the evaluation of nonblocking RHS expressions.
注意:LHS of nonblocking assignments的更新,不在这active event queue中
Nonblocking assign updates event queue中LHS expression是随机的。
The nonblocking assign updates event queue is where updates to the LHS expression of nonblocking assignments are scheduled. The RHS expression is evaluated in random order at the beginning of a simulation time step along with the other active events described above.
$strobe和$monitor与$display不同的地方
The monitor events queue is where $strobe and $monitor display command values are scheduled. $strobe and $monitor show the updated values of all requested variables at the end of a simulation time step, after all other assignments for that simulation time step are complete.
0-delayed assignment所达到的效果和为什么不建议使用。
可以在多个block中对同一个value赋值。
A fourth event queue described in section 5.3 of the Verilog Standard is the inactive events queue, where #0-delayed assignments are scheduled. The practice of making #0-delay assignments is generally a flawed practice employed by designers who try to make assignments to the same variable from two separate procedural blocks, attempting to beat Verilog race conditions by scheduling one of the assignments to take place slightly later in the same simulation time step. Adding #0-delay assignments to Verilog models needlessly complicates the analysis of scheduled events. The author knows of no condition that requires making #0-delay assignments that could not be easily replaced with a different and more efficient coding style and hence discourages the practice.
Self-triggering always blocks
以下两种情况,那种可以触发,为什么。
关键在于first @(clk)的这个time-step中
Non-self-triggering oscillator using blocking assignments
module osc1 (clk);
output clk;
reg clk;
initial#10 clk =0;
always@(clk)#10 clk =~clk;
endmodule
Self-triggering oscillator using nonblocking assignments
module osc2 (clk);
output clk;
reg clk;
initial#10 clk =0;
always@(clk)#10 clk <=~clk;
endmodule
Pipeline modeling
这个电路如何建模
Bad blocking-assignment sequential coding style #1
module pipeb1 (q3, d, clk);
output[7:0] q3;
input [7:0] d;
input clk;
reg [7:0] q3, q2, q1;
always@(posedge clk)begin
q1 = d;
q2 = q1;
q3 = q2;
end
endmodule
Bad blocking-assignment sequential coding style #2 - but it works!
module pipeb2 (q3, d, clk);
output[7:0] q3;
input [7:0] d;
input clk;
reg [7:0] q3, q2, q1;
always@(posedge clk)begin
q3 = q2;
q2 = q1;
q1 = d;
end
endmodule
Bad blocking-assignment sequential coding style #3
module pipeb3 (q3, d, clk);
output[7:0] q3;
input [7:0] d;
input clk;
reg [7:0] q3, q2, q1;
always@(posedge clk) q1=d;
always@(posedge clk) q2=q1;
always@(posedge clk) q3=q2;
endmodule
会产生race condition
Bad blocking-assignment sequential coding style #4
module pipeb4 (q3, d, clk);
output[7:0] q3;
input [7:0] d;
input clk;
reg [7:0] q3, q2, q1;
always@(posedge clk) q2=q1;
always@(posedge clk) q3=q2;
always@(posedge clk) q1=d;
endmodule
可以综合成正确的逻辑,但是仿真不正确。
Good nonblocking-assignment sequential coding style #1
module pipen1 (q3, d, clk);
output [7:0] q3;
input [7:0] d;
input clk;
reg [7:0] q3, q2, q1;
always @(posedge clk) begin
q1 <= d;
q2 <= q1;
q3 <= q2;
end
endmodule
Good nonblocking-assignment sequential coding style #2
module pipen2 (q3, d, clk);
output [7:0] q3;
input [7:0] d;
input clk;
reg [7:0] q3, q2, q1;
always @(posedge clk) begin
q3 <= q2;
q2 <= q1;
q1 <= d;
end
endmodule
Good nonblocking-assignment sequential coding style #3
module pipen3 (q3, d, clk);
output [7:0] q3;
input [7:0] d;
input clk;
reg [7:0] q3, q2, q1;
always @(posedge clk) q1<=d;
always @(posedge clk) q2<=q1;
always @(posedge clk) q3<=q2;
endmodule
Good nonblocking-assignment sequential coding style #4
module pipen4 (q3, d, clk);
output [7:0] q3;
input [7:0] d;
input clk;
reg [7:0] q3, q2, q1;
always@(posedge clk) q2<=q1;
always@(posedge clk) q3<=q2;
always@(posedge clk) q1<=d;
endmodule
这些编码的仿真与综合是否正确?
• 1 out of 4 blocking assignment coding styles was guaranteed to simulate correctly
• 3 out of 4 blocking assignment coding styles were guaranteed to synthesize correctly
• 4 out of 4 nonblocking assignment coding styles were guaranteed to simulate correctly
• 4 out of 4 blocking assignment coding styles were guaranteed to synthesize correctly.
用阻塞赋值和非阻塞赋值描述pipeline的优劣
Although, if confined to one always block with carefully sequenced assignments, it was possible to code the pipeline logic using blocking assignments. On the other hand, it was easy to code the same pipeline logic using nonblocking assignments; indeed, the nonblocking assignment coding styles all would work for both synthesis and simulation.
Blocking assignments & simple examples
a flipflop model that appears in most Verilog text book
Simple flawed blocking-assignment D-flipflop model - but it works!
module dffb (q, d, clk, rst);
output q;
input d, clk, rst;
reg q;
always@(posedge clk)
if(rst) q =1'b0;
else q = d;
endmodule
Preferred D-flipflop coding style with nonblocking assignments
module dffx (q, d, clk, rst);
output q;
input d, clk, rst;
reg q;
always@(posedge clk)
if(rst) q <=1'b0;
else q <= d;
endmodule
Sequential feedback modeling
A Linear Feedback Shift-Register (LFSR) is a piece of sequential logic with a feedback loop. The feedback loop poses a problem for engineers attempting to code this piece of sequential logic with correctly ordered blocking assignments as shown in
module lfsrb1 (q3, clk, pre_n);
output q3;
input clk, pre_n;
reg q3, q2, q1;
wire n1;
assign n1 = q1 ^ q3;
always@(posedge clk ornegedge pre_n)
if(!pre_n)begin
q3 =1'b1;
q2 =1'b1;
q1 =1'b1;
end
elsebegin
q3 = q2;
q2 = n1;
q1 = q3;
end
endmodule
Non-functional LFSR with blocking assignments
它是不可能实现的.怎样解决,临时变量.
There is no way to order the assignments in Example 15 to model the feedback loop unless a temporary variable is used.
Functional but cryptic LFSR with blocking assignments
module lfsrb2 (q3, clk, pre_n);
output q3;
input clk, pre_n;
reg q3, q2, q1;
always@(posedge clk ornegedge pre_n)
if(!pre_n){q3,q2,q1}=3'b111;
else {q3,q2,q1}={q2,(q1^q3),q3};
endmodule
写成单行是可以完成功能的,但是缺点:
One could group all of the assignments into one-line equations to avoid using a temporary variable, as shown in Example 16, but the code is now more cryptic. For larger examples, one-line equations might become very difficult to code and debug. One-line equation coding styles are not necessarily encouraged.
module lfsrn1 (q3, clk, pre_n);
output q3;
input clk, pre_n;
reg q3, q2, q1;
wire n1;
assign n1 = q1 ^ q3;
always@(posedge clk ornegedge pre_n)
if(!pre_n)begin
q3 <=1'b1;
q2 <=1'b1;
q1 <=1'b1;
end
elsebegin
q3 <= q2;
q2 <= n1;
q1 <= q3;
end
endmodule
如果换成nonblocking则可以正常工作。
结合Pipeline modeling一节可以得出:
Based on the pipeline examples of section 8.0 and the LFSR examples of section 10.0, it is recommended to model all sequential logic using nonblocking assignments. A similar analysis would show that it is also safest to use nonblocking assignments to model latches
Guideline #1: When modeling sequential logic, use nonblocking assignments.
Guideline #2: When modeling latches, use nonblocking assignments.
用nonbloking assignment描述时序逻辑和latches是最安全的。
Combinational logic - use blocking assignments
什么情况下用nonblocking赋值描述组合逻辑,以及什么情况下可以用blocking 赋值描述组合逻辑。
If only a single assignment is made in the always block, using either blocking or nonblocking assignments will work; but in the interest of developing good coding habits one should always using blocking assignments to code combinational logic. It has been suggested by some Verilog designers that nonblocking assignments should not only be used for coding sequential logic, but also for coding combinational logic. For coding simple combinational always blocks this would work, but if multiple assignments are included in the always block, such as the and-or code shown in Example 19, using nonblocking assignments with no delays will either simulate incorrectly, or require additional sensitivity list entries and multiple passes through the always block to simulate correctly. The latter would be inefficient from a simulation time perspective.
Bad combinational logic coding style using nonblocking assignments
module ao4 (y, a, b, c, d);
output y;
input a, b, c, d;
reg y, tmp1, tmp2;
always@(a or b or c or d)begin
tmp1 <= a & b;
tmp2 <= c & d;
y <= tmp1 | tmp2;
end
endmodule
这样写仿真有问题
Inefficient multi-pass combinational logic coding style with nonblocking assignments
module ao5 (y, a, b, c, d);
output y;
input a, b, c, d;
reg y, tmp1, tmp2;
always@(a or b or c or d or tmp1 or tmp2)begin
tmp1 <= a & b;
tmp2 <= c & d;
y <= tmp1 | tmp2;
end
endmodule
这样写仿真和综合都是正确的,但是是低效的。
Efficient combinational logic coding style using blocking assignments
module ao2 (y, a, b, c, d);
output y;
input a, b, c, d;
reg y, tmp1, tmp2;
always@(a or b or c or d)begin
tmp1 = a & b;
tmp2 = c & d;
y = tmp1 | tmp2;
end
endmodule
比较提倡的写法
所以
Guideline #3: When modeling combinational logic with an always block, use blocking assignments.
Mixed sequential & combinational logic - use nonblocking assignments
组合逻辑和时序逻辑在一个always block中时的情况
Combinational and sequential logic in a single always block
module nbex2 (q, a, b, clk, rst_n);
output q;
input clk, rst_n;
input a, b;
reg q;
always@(posedge clk ornegedge rst_n)
if(!rst_n) q <=1'b0;
else q <= a ^ b;
endmodule
The same logic that is implemented in Example 22 could also be implemented as two separate always blocks, one with purely combinational logic coded with blocking assignments and one with purely sequential logic coded with nonblocking assignments
module nbex1 (q, a, b, clk, rst_n);
output q;
input clk, rst_n;
input a, b;
reg q, y;
always@(a or b)
y = a ^ b;
always@(posedge clk ornegedge rst_n)
if(!rst_n) q <=1'b0;
else q <= y;
endmodule
Guideline #4: When modeling both sequential and combinational logic within the same always block, use nonblocking assignments.
Other mixed blocking & nonblocking assignment guidelines
Blocking and nonblocking assignment in the same always block - generally a bad idea!
module ba_nba2 (q, a, b, clk, rst_n);
output q;
input a, b, rst_n;
input clk;
reg q;
always@(posedge clk ornegedge rst_n)begin: ff
reg tmp;
if(!rst_n) q <=1'b0;
elsebegin
tmp = a & b;
q <= tmp;
end
end
endmodule
可综合的
Synthesis syntax error - blocking and nonblocking assignment to the same variable
module ba_nba6 (q, a, b, clk, rst_n);
output q;
input a, b, rst_n;
input clk;
reg q, tmp;
always@(posedge clk ornegedge rst_n)
if(!rst_n) q =1'b0; // blocking assignment to "q"
elsebegin
tmp = a & b;
q <= tmp; // nonblocking assignment to "q"
end
endmodule
Guideline #5: Do not mix blocking and nonblocking assignments in the same always block.
Multiple assignments to the same variable
Race condition coding style using nonblocking assignments
module badcode1 (q, d1, d2, clk, rst_n);
output q;
input d1, d2, clk, rst_n;
reg q;
always@(posedge clk ornegedge rst_n)
if(!rst_n) q <=1'b0;
else q <= d1;
always@(posedge clk ornegedge rst_n)
if(!rst_n) q <=1'b0;
else q <= d2;
endmodule
Warning: In design 'badcode1', there is 1 multiple-driver net with unknown wired-logic type.
Guideline #6: Do not make assignments to the same variable from more than one always block.
Common nonblocking myths
1. Nonblocking assignments & $display
对nonblocking assignment,$display不工作吗?
Myth: “Using the $display command with nonblocking assignments does not work”
Truth: Nonblocking assignments are updated after all $display commands
module display_cmds;
reg a;
initial$monitor("\$monitor: a = %b", a);
initialbegin
$strobe ("\$strobe : a = %b", a);
a =0;
a <=1;
$display("\$display: a = %b", a);
#1$finish;
end
endmodule
结果是什么?
$display: a =0
$monitor: a =1
$strobe: a =1
2. #0-delay assignments
Myth: “#0 forces an assignment to the end of a time step”
Truth: #0 forces an assignment to the "inactive events queue"
module nb_schedule1;
reg a, b;
initialbegin
a =0;
b =1;
a <= b;
b <= a;
$monitor("%0dns: \$monitor: a=%b b=%b",$stime, a, b);
$display("%0dns: \$display: a=%b b=%b",$stime, a, b);
$strobe ("%0dns: \$strobe : a=%b b=%b\n",$stime, a, b);
#0$display("%0dns: #0 : a=%b b=%b",$stime, a, b);
#1$monitor("%0dns: \$monitor: a=%b b=%b",$stime, a, b);
$display("%0dns: \$display: a=%b b=%b",$stime, a, b);
$strobe ("%0dns: \$strobe : a=%b b=%b\n",$stime, a, b);
$display("%0dns: #0 : a=%b b=%b",$stime, a, b);
#1$finish;
end
endmodule
输出结果:
0ns: $display: a=0 b=1
0ns: #0 : a=0 b=1
0ns: $monitor: a=1 b=0
0ns: $strobe : a=1 b=0
1ns: $display: a=1 b=0
1ns: #0 : a=1 b=0
1ns: $monitor: a=1 b=0
1ns: $strobe : a=1 b=0
Multiple nonblocking assignments to the same variable
Myth: “Making multiple nonblocking assignments to the same variable in the same always block is undefined”
Truth: Making multiple nonblocking assignments to the same variable in the same always block is defined by the Verilog Standard. The last nonblocking assignment to the same variable wins! Quoting from the IEEE 1364-1995 Verilog Standard [2], pg. 47, section 5.4.1 - Determinism
"Nonblocking assignments shall be performed in the order the statements were executed.
Consider the following example:
initialbegin
a <=0;
a <=1;
end
When this block is executed, there will be two events added to the nonblocking assign update queue. The previous rule requires that they be entered on the queue in source order; this rule requires that they be taken from the queue and performed in source order as well. Hence, at the end of time-step 1, the variable a will be assigned 0 and then 1."