首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

学好verilog的关键一步---阻塞和非阻塞赋值3

学好verilog的关键一步---阻塞和非阻塞赋值3

近来在论坛上看到一些朋友,经常就程序的阻塞和非阻塞赋值提出疑问,当然还有一些问题也属于此,只是大家还不清楚自己遇到的问题也属于阻塞和非阻塞赋值问题。这是一个比较重要又很难理解的地方,尤其是一些原先写软件的或者是新手。这里我给出一篇我学到现在觉得比较经典的文章,大家一起参考一下,一定对大家有帮助的。好好加油学吧1

##说明:为了节省大家的EDA元,我直接把文章贴出来,不过文章中有些图或者列表没有办法显示,所以我把附件也带上,大家自己看着选吧##

没有办法通过调整描述次序的方法来正确建模除非引入一个临时的变量(
外注:例如引入“wire n2”――>
module xxxxx (q3, clk, pre_n);
output q3;
input clk, pre_n;
reg q3, q2, q1;
wire n1,n2;
assign n1 = q1 ^ q3;
assign n2 = q3;
always @(posedge clk or negedge pre_n)
if (!pre_n) begin
q3 = 1'b1;
q2 = 1'b1;
q1 = 1'b1;
end
else begin
q3 = q2;
q2 = n1;
q1 = n2;
end
endmodule

这样可以得到正确的综合结果:
Found 1-bit register for signal .
Found 1-bit xor2 for signal .
Found 1-bit register for signal .
Found 1-bit register for signal .
Summary:
inferred 3 D-type flip-flop(s).)。
可以通过把所有赋值弄到一个等式的方式(one-line equations)来避免使用临时变量,例如下面的例16所示。但是现在编码显得更难于理解尤其当涉及的表达式更大更长时,编写代码和调试都变得比较困难,因此不鼓励使用这种风格。

module lfsrb2 (q3, clk, pre_n);
output q3;
input clk, pre_n;
reg q3, q2, q1;
always @(posedge clk or negedge pre_n)
if (!pre_n) {q3,q2,q1} = 3'b111;
else {q3,q2,q1} = {q2,(q1^q3),q3};
endmodule
Example 16 - Functional but cryptic LFSR with blocking assignments

如果把例15和例16的阻塞赋值(blocking assignment)都替换为非阻塞赋值(nonblocking assignment),如下面例17和18所示,那么所有的仿真都将如我们对一个LFSR所期望的那样。
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 or negedge pre_n)
if (!pre_n) begin
q3 <= 1'b1;
q2 <= 1'b1;
q1 <= 1'b1;
end
else begin
q3 <= q2;
q2 <= n1;
q1 <= q3;
end
endmodule
Example 17 - Functional LFSR with nonblocking assignments

module lfsrn2 (q3, clk, pre_n);
output q3;
input clk, pre_n;
reg q3, q2, q1;
always @(posedge clk or negedge pre_n)
if (!pre_n) {q3,q2,q1} <= 3'b111;
else {q3,q2,q1} <= {q2,(q1^q3),q3};
endmodule
Example 18 - Functional but cryptic LFSR with nonblocking assignments

根据8.0段例子pipeline和10.0段例子LFSR,我们推荐对所有时序逻辑建模时使用非阻塞赋值(nonblocking assignment)。相似的分析也将显示出对latch建模时使用非阻塞赋值(nonblocking assignment)是最安全的。

#1: 当为时序逻辑建模,使用“非阻塞赋值”。
#2: 当为锁存器(latch)建模,使用“非阻塞赋值”。

11.0 组合逻辑―使用阻塞赋值(blocking assignment)

用Verilog可以有很多种方法为组合逻辑建模,但是当使用always块来为组合逻辑建模时,应该使用阻塞赋值(blocking assignment)。

如果在某个always块里面只有一个赋值(表达),那么使用阻塞或者非阻塞赋值都可以正确工作。但是如果您对养成好的编码习惯有兴趣的话,还是要“总是用阻塞赋值对组合逻辑建模”。
一些设计师建议非阻塞赋值不应该只为编写时序逻辑,它也可以用来编写组合逻辑。当然对于简单的组合逻辑always块这是可以的,但是对于在一个always块里面含有多个赋值陈述,例如例19含有and-or的陈述,使用了不含延迟(delay)的非阻塞赋值会造成仿真不正确,或者要使仿真正确您需要另外的添加敏感事件列表(sensitivity list entries),和“多登入路径”(multiple passes)来贯穿always 块以使得仿真正确。接下来的问题是从仿真需要多长时间来看,这是低效率的(外注:即降低仿真的performance)。 例19的y输出建立在3个依次执行的陈述上(外注:tmp1 <= a & b; tmp2 <= c & d; y <= tmp1 | tmp2;)。由于非阻塞赋值的LHS变量值更新是在对RHS表达式估值之后,所以tmp1和tmp2的值仍然是该always块上一个登入口的值而不是在这一个仿真时间步(simulation time step)结束时被更新的值。因此y的值将受旧的tmp1和tmp2影响,而不是这次扫描过的always块内被更新的值。 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 Example 19 - Bad combinational logic coding style using nonblocking assignments 例20与例19是一样的,不同之处在于tmp1和tmp2被添加到事件列表中去了。如第7段(section 7.0)中所述,在“非阻塞赋值更新事件队列”中当非阻塞赋值更新LHS变量时,always块将会“自触发”并使用最新的tmp1和tmp2来更新y输出。现在y输出值正确了因为增加使用了两条“登入路径”(two passes)贯穿整个always块。使用更多的“登入路径”来贯穿always块等于降低仿真器的性能,因此如果可以有合理的一些代码变化可以取代这种用法的话,就尽量避免这种用法。 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 Example 20 - Inefficient multi-pass combinational logic coding style with nonblocking assignments 发展一个好的习惯可以避免使用“多登入路径”(multiple passes)贯穿always块,即使用阻塞赋值为组合逻辑建模。 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 Example 21 - Efficient combinational logic coding style using blocking assignments 例21与例19一样,不同之处只在于用阻塞赋值替代了非阻塞赋值。这保证了在一个“登入路径”贯穿always后y输出的正确(guarantee that the y-output assumes the correct value after only one pass through the always block?)。因此有下面的编码方针: #3: 当用always块为组合逻辑建模,使用“阻塞赋值” 12.0 时序-组合混合逻辑建模:使用非阻塞赋值 很多时候为了方便我们把时序和一些简单的组合逻辑放在一起。当我们把时序和组合编码放在一个always块的时候,像编写时序逻辑一样使用非阻塞赋值为这种混合逻辑建模,如下面的例22: module nbex2 (q, a, b, clk, rst_n); output q; input clk, rst_n; input a, b; reg q; always @(posedge clk or negedge rst_n) if (!rst_n) q <= 1'b0; else q <= a ^ b; endmodule Example 22 - Combinational and sequential logic in a single always block 与例22相同的逻辑也可以使用两个分立的always块------一个是纯粹的时序逻辑(使用非阻塞赋值),另一个是纯粹的组合逻辑(使用阻塞赋值)------建模,例如下面的例23: 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 or negedge rst_n) if (!rst_n) q <= 1'b0; else q <= y; endmodule Example 23 - Combinational and sequential logic separated into two always blocks #4: 当在同一个always块里面既为组合逻辑又为时序逻辑建模,使用“非阻塞赋值”。 13.0 其它混合“阻塞”与“非阻塞”赋值建模方针 Verilog允许在一个always块里面自由混合“阻塞”与“非阻塞”赋值。一般情况下在同一个always块里面混合“阻塞”与“非阻塞”赋值是“衰婆”风格(poor coding style,呵呵,借用电影《钢琴教师》里的翻译“衰婆”,刚好poor发音与“婆”有些相近。不过可能引起大家一阵反胃,女士们一阵痛恨------向导演,可不要向我!),尽管Verilog允许这样做。 下面的例24的仿真和综合都将是正确的,因为“阻塞”与“非阻塞”赋值不是针对同一个变量来的。尽管这可以“正常工作”,但是作者不推荐这种风格。 module ba_nba2 (q, a, b, clk, rst_n); output q; input a, b, rst_n; input clk; reg q; always @(posedge clk or negedge rst_n) begin: ff reg tmp; if (!rst_n) q <= 1'b0; else begin tmp = a & b; q <= tmp; end end endmodule Example 24 - Blocking and nonblocking assignment in the same always block - generally a bad idea! 下面的例25在大多数情况下仿真是正确的,但是新思(Synopsys)工具会报告语法错误因为针对同一个既进行了“阻塞赋值”又进行了“非阻塞赋值”。这样的编码必须进行修改才可以综合。(Error:Cannot mix blocking and non blocking assignments on signal .) module ba_nba6 (q, a, b, clk, rst_n); output q; input a, b, rst_n; input clk; reg q, tmp; always @(posedge clk or negedge rst_n) if (!rst_n) q = 1'b0; // blocking assignment to "q" else begin tmp = a & b; q <= tmp; // nonblocking assignment to "q" end endmodule Example 25 - Synthesis syntax error - blocking and nonblocking assignment to the same variable 为了养成好的编写习惯,作者推荐始终坚持: #5: 不要在同一个always块里面混合使用“阻塞赋值”和“非阻塞赋值”。 14.0 对同一变量多处赋值(Multiple assignments to the same variable) 对同一变量在二个以上(包括二个)always块里面进行赋值就是一种Verilog竞争生成环境------即使使用非阻塞赋值。
返回列表