(笔记)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.

如何完全理解blockingnonblocking赋值的功能和时序。这篇文章的重点。

 

简写

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发生。

 

只在两种块中发生:initialalways

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.

 

遵守以下这8guidline90-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块中,blockingnonblocking不可混用

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.//不要用#0delay

 

The Verilog "stratified event queue"

clip_image002

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 queueLHS 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

这个电路如何建模

clip_image004

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

clip_image006

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."

 

posted @ 2011-05-09 16:44  任怀鲁  阅读(3622)  评论(2编辑  收藏  举报