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

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

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

在第一个@(clk)触发之后,非阻塞赋值的RHS expression被估值,并且LHS值被送入“非阻塞赋值更新”事件列。在“非阻塞赋值更新事件列”被激活以前,仿真过程遇到@clk触发描述,所以always块又一次对clk信号变化敏感------然后在同一时间步的结束当LHS被更新时,@clk被又一次触发。所以osc2是可以自触发的(尽管不是我们有必要推荐的风格)。
x
clk==0
RHS估值
time step
RHS估值 10,LHS更新,clk==1
@(clk) 发生clk事件!等待、开始RHS估值
#10 估值完毕,clk_reg==1
@(clk),等待、开始RHS估值
(外注:这个另外添加的仿真波形可以帮助理解,原文里并没有。其中clk_reg表示寄存在内存的clk值。)

8.0 流水线建模
图二示意了一个简单的时序(sequential)流水线寄存器。

从例5到例8列举了一个工程师可能选用的4种使用阻塞赋值为它建模的方案。

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
Example 5 - Bad blocking-assignment sequential coding style #1
(外注:综合报告:WARNING: Signal is assigned but never used.
WARNING:Signal is assigned but never used.)
在例5里面,接连的“阻塞赋值”命令将使得输入D连续地覆盖所有寄存器输出(在下一个posedge clk到来时)。即在每一个clk边沿,输入值被无延迟地传到q3的输出。这很明显并没有建立一个流水线而只是为一个寄存器建模------实际综合结果将是上面的图3。

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
Example 6 - Bad blocking-assignment sequential coding style #2 - but it works!
上面的pipeb2里面,阻塞赋值被仔细地安排了次序以使得行为仿真正确。这种建模同样也可以得到正确的综合结果。(外注:Found 3-bit shift register for signal .
Summary: inferred 8 Shift register(s). )

在下面的例3里,“阻塞赋值”被安排在不同的always块里面。这样Verilog标准允许以任意的次序 来仿真执行3个always块-------这也许会使得该流水线仿真结果产生错误,因为这产生了Verilog竞争条件。由不同的always块执行顺序会产生不同的结果。尽管这样,它的综合结果将是正确的! 这就意味着综合前仿真和综合后仿真不匹配。Pipeb4或者其它的类似always块同样也许会产生仿真与综合不匹配的结果------综合结果是对的,但是仿真结果也许不正确。(外注:pipeb4只是又颠倒了一下次序,对实际仿真次序却不产生决定作用.)

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
Example 7 - Bad blocking-assignment sequential coding style #3

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
Example 8 - Bad blocking-assignment sequential coding style #4
近来在论坛上看到一些朋友,经常就程序的阻塞和非阻塞赋值提出疑问,当然还有一些问题也属于此,只是大家还不清楚自己遇到的问题也属于阻塞和非阻塞赋值问题。这是一个比较重要又很难理解的地方,尤其是一些原先写软件的或者是新手。这里我给出一篇我学到现在觉得比较经典的文章,大家一起参考一下,一定对大家有帮助的。好好加油学吧1 ##说明:为了节省大家的EDA元,我直接把文章贴出来,不过文章中有些图或者列表没有办法显示,所以我把附件也带上,大家自己看着选吧## endmodule Example 4 - Self-triggering oscillator using nonblocking assignments 在第一个@(clk)触发之后,非阻塞赋值的RHS expression被估值,并且LHS值被送入“非阻塞赋值更新”事件列。在“非阻塞赋值更新事件列”被激活以前,仿真过程遇到@clk触发描述,所以always块又一次对clk信号变化敏感------然后在同一时间步的结束当LHS被更新时,@clk被又一次触发。所以osc2是可以自触发的(尽管不是我们有必要推荐的风格)。 x clk==0 RHS估值 time step RHS估值 10,LHS更新,clk==1 @(clk) 发生clk事件!等待、开始RHS估值 #10 估值完毕,clk_reg==1 @(clk),等待、开始RHS估值 (外注:这个另外添加的仿真波形可以帮助理解,原文里并没有。其中clk_reg表示寄存在内存的clk值。) 8.0 流水线建模 图二示意了一个简单的时序(sequential)流水线寄存器。 从例5到例8列举了一个工程师可能选用的4种使用阻塞赋值为它建模的方案。 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 Example 5 - Bad blocking-assignment sequential coding style #1 (外注:综合报告:WARNING: Signal is assigned but never used. WARNING:Signal is assigned but never used.) 在例5里面,接连的“阻塞赋值”命令将使得输入D连续地覆盖所有寄存器输出(在下一个posedge clk到来时)。即在每一个clk边沿,输入值被无延迟地传到q3的输出。这很明显并没有建立一个流水线而只是为一个寄存器建模------实际综合结果将是上面的图3。 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 Example 6 - Bad blocking-assignment sequential coding style #2 - but it works! 上面的pipeb2里面,阻塞赋值被仔细地安排了次序以使得行为仿真正确。这种建模同样也可以得到正确的综合结果。(外注:Found 3-bit shift register for signal . Summary: inferred 8 Shift register(s). ) 在下面的例3里,“阻塞赋值”被安排在不同的always块里面。这样Verilog标准允许以任意的次序 来仿真执行3个always块-------这也许会使得该流水线仿真结果产生错误,因为这产生了Verilog竞争条件。由不同的always块执行顺序会产生不同的结果。尽管这样,它的综合结果将是正确的! 这就意味着综合前仿真和综合后仿真不匹配。Pipeb4或者其它的类似always块同样也许会产生仿真与综合不匹配的结果------综合结果是对的,但是仿真结果也许不正确。(外注:pipeb4只是又颠倒了一下次序,对实际仿真次序却不产生决定作用.) 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 Example 7 - Bad blocking-assignment sequential coding style #3 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 Example 8 - Bad blocking-assignment sequential coding style #4 假如每一个上面的例子都改用“非阻塞赋值”那么将会都能得到正确的仿真结果,并综合出想要的流水线逻辑。 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 Example 9 - Good nonblocking-assignment sequential coding style #1 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 Example 10 - Good nonblocking-assignment sequential coding style #2 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 Example 11 - Good nonblocking-assignment sequential coding style #3 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 Example 12 - Good nonblocking-assignment sequential coding style #4 从上面的流水线编码风格例子可以看出: 仅一个“阻塞赋值”的描述可以保证仿真正确。 三个“阻塞赋值”的描述可以得到正确综合结果。 四个“非阻塞赋值”描述都可以保证仿真结果正确。 四个“非阻塞赋值”描述都可以得到正确综合结果。(原文这一条是“阻塞赋值”大概是有误?) 虽然,如果限制在一个always块里面,并小心地组织好一个always块里面阻塞赋值的次序(外注:一个always块里面的几个“阻塞赋值”是按照陈述的次序串行仿真执行的,综合执行次序也是?)同样可能会正确地为流水线建模;但是另一方面,我们可以很容易地使用“非阻塞赋值”来为上面的流水线建模------它们既可以正确仿真也可以正确综合。 9.0 阻塞赋值 & 简单例子 有许多将Verilog和Verilog综合的书,它们举了很多成功地利用“阻塞赋值”为一些简单的时序电路建模的小例子。例13是一个在大多数Verilog书本里用来为一个触发器(flip-flop)建模的例子(这是简单而有缺陷的阻塞赋值建模,但是它确实可以工作): 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 Example 13 - Simple flawed blocking-assignment D-flipflop model - but it works! 如果工程师们想把所有的模块(module)都集中到一个always里面描述,“阻塞赋值”可以用来正确地为所需要的逻辑建模、仿真和综合。但是不幸的是这个原因导致了喜欢在其它情况下也使用“阻塞赋值”的习惯,并且更复杂的时序always块将会产生竞争条件------在前面已经详细阐述过。 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 Example 14 - Preferred D-flipflop coding style with nonblocking assignments 应该努力养成使用“非阻塞赋值”为 所有的 时序逻辑建模的习惯------象上面的例14一样------即使是为了对付任何一个简单的模块。 下面考虑一下一个稍微复杂的时序逻辑,一个线性反馈移位寄存器(Linear Feedback shift-Register)或称之为LFSR。 10.0 为时序反馈建模 (Sequential feedback modeling) 一个LFSR是一种带反馈环路(feedback loop)的时序逻辑。反馈环路(feedback loop)为工程师们带来了一个难题使得他们试图使用细心组织次序的“阻塞赋值”来为它正确建模,如下面的例子: 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 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 15 - Non-functional LFSR with blocking assignments(外注:综合报告―――> Register equivalent to has been removed Found 1-bit register for signal . Found 1-bit xor2 for signal . Found 1-bit register for signal .) Summary: inferred 2 D-type flip-flop(s).

实在是太好了

好啊!

好是比较好

但是太长了

看完真的会晕的

大家记住:

组合电路用“阻塞”

时序电路用 “非阻塞”

养成这种习惯不易出错

组合逻辑电路用“阻塞”

时序电路用 “非阻塞”

这个版主不太冷 =========================== 我的中电网博客:http://blog.chinaecnet.com/u/20/index.htm
返回列表