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

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

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

在下面例26里,二个always块对q进行赋值,同时使用非阻塞赋值。因为这些always块可以以同一次序安排执行,仿真输出呈竞争条件。

module badcode1 (q, d1, d2, clk, rst_n);
output q;
input d1, d2, clk, rst_n;
reg q;
always @(posedge clk or negedge rst_n)
if (!rst_n) q <= 1'b0;
else q <= d1;
always @(posedge clk or negedge rst_n)
if (!rst_n) q <= 1'b0;
else q <= d2;
endmodule
Example 26 - Race condition coding style using nonblocking assignments
当新思(Synopsys)工具读这段编码时,会产生如下警告:
Warning: In design 'badcode1', there is 1 multiple-driver net with unknown wired-logic type.
当忽略这个警告并编译上面的例子时,推断结果是二个触发器的输出将作为一个and门的输入。在这个例子里综合前(pre-synthesis)仿真结果与综合后(post-synthesis)仿真结果不匹配。

#6: 不要在两个或两个以上always块里面对同一个变量进行赋值。

15.0 常见的“非阻塞”神话(外注:指与事实不符或严格说不正确的见解、想法)

15.1 非阻塞赋值和$display
神话:“对‘非阻塞赋值’使用$display命令不起作用。”
事实:非阻塞赋值在$display命令之后才被更新赋值。
module display_cmds;
reg a;
initial $monitor("\$monitor: a = %b", a);
initial begin
$strobe ("\$strobe : a = %b", a);
a = 0;
a <= 1;
$display ("\$display: a = %b", a);
#1 $finish;
end
endmodule
下面的仿真输出结果显示出$display命令在“激活事件列”(the active event queue)里被执行的情形:在“非阻塞赋值更新”这个事件被执行之前。
$display: a = 0
$monitor: a = 1
$strobe : a = 1

15.2 赋“零延迟”
神话:“‘零延迟’#0 使得该赋值事件在时间步结束时发生”
事实:零延迟’#0 使得赋值事件处于“非激活事件列”
module nb_schedule1;
reg a, b;
initial begin
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", $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
下面的仿真输出结果显示出$display命令在“非激活事件列”(the inactive event queue)里被执行的情形:在“非阻塞赋值更新”这个事件被执行之前。

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

#7: 使用$strobe以显示已被“非阻塞赋值”的值。

15.3 对同一变量多处进行“非阻塞赋值”
神话:“‘在同一个always块里对同一变量多处进行非阻塞赋值’ 没有被明确定义。”
事实:Verilog标准定义了以上操作。最后一个非阻塞赋值操作将赢得最后结果。引用IEEE1364-1995 Verilog Standard [2], pg. 47, section 5.4.1 – Determinism 如下:

“非阻塞赋值由它们被陈述的次序决定被执行的情况,考虑下面的例子:
initial begin
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."
换句话说:“最后一个非阻塞赋值操作将赢得优先权。”

指导方针和结论(概要):


#1: 当为时序逻辑建模,使用“非阻塞赋值”。
#2: 当为锁存器(latch)建模,使用“非阻塞赋值”。
#3: 当用always块为组合逻辑建模,使用“阻塞赋值”
#4: 当在同一个always块里面既为组合逻辑又为时序逻辑建模,使用“非阻塞赋值”。
#5: 不要在同一个always块里面混合使用“阻塞赋值”和“非阻塞赋值”。
#6: 不要在两个或两个以上always块里面对同一个变量进行赋值。
#7: 使用$strobe以显示已被“非阻塞赋值”的值。
#8: 不要使用#0延迟的赋值。

谨遵这些方针可以帮助Verilog设计者减少所遇到的90-100%的Verilog竞争。


16.0 最后注意:“nonblocking”的拼写
“nonblocking”经常被拼错为“non-blocking”。作者认为这是“微软化”的拼写方式。工程师们在“non”和“blocking”之间插入一个“-”是为了满足微软的拼写检查不致报错。在IEEE 1364-1995里正确的拼写应该是:nonblocking。(外注:呵呵,你已经看到了,在这个文档里面所有的nonblocking都被下划了红色波浪线。)

参考文献:
[1] IEEE P1364.1 Draft Standard For Verilog Register Transfer Level Synthesis
[2] IEEE Standard Hardware Description Language Based on the Verilog Hardware
Description Language, IEEE Computer Society, IEEE Std 1364-1995
[3] Clifford Cummings, "Correct Methods For Adding Delays To Verilog Behavioral
Models," International HDL Conference 1999 Proceedings, pp. 23-29, April 1999.

(外注:以上参考文献原文的。译文中第4页“事件轴”引自中科院计算所张亮编著、人民邮电出版社2000年10月出版的《数字电路设计与Verilog HDL》;一些综合报告来自Xilinx公司的综合软件XST。)

作者和联系方式 (外注:偷懒省略。总之“Mr. Cummings, a member of the IEEE 1364 Verilog Standards Group (VSG) since 1994”,虽然文章所涉很使我们感到“离”众书“叛道”,但其实是足够可信的【并且使我疑团大释,所以拿出来让使用Verilog的家伙一齐“开怀”,译文中太多错误和缺点请大家不吝指正!】。本文英文原文可以从下面的 web site下载: www.fpga.com.cn 或 www.sunburst-design.com/papers 。)
返回列表