Verilog中的延时、阻塞与非阻塞赋值仿真
阻塞赋值和非阻塞赋值的用法
阻塞赋值和非阻塞赋值的用法说到Verilog编程里的阻塞赋值和非阻塞赋值,哎呀,简直就是两个“冤家”。
你可能听说过它们,但是可能还没有搞清楚到底哪个是“王者”,哪个又是“二把手”。
阻塞赋值和非阻塞赋值就像是两种性格截然不同的人,碰到的情况不同,做的事也不一样,它们互不干涉,但又相互影响。
来聊聊阻塞赋值吧。
阻塞赋值就像你在厨房做饭时,先把锅里的菜炒熟,等菜完全做好了,你才能开始准备下一道菜。
明白了吧?它的特点就是按顺序执行,你要做完当前的事,下一件事才会开始,完全不会“跳过”什么。
比如在Verilog代码里,如果你写了一个“=`赋值语句”,那这个赋值语句就会“阻塞”当前进程,必须等这个赋值完成后,才会继续执行后面的操作。
所以,如果你把多个赋值语句写在一起,执行的顺序是很重要的!有时候你会发现,哎,这个赋值好像搞得我有点儿“慢慢吞吞”了。
对,没错,它就是这么不急不躁。
比方说你要计算一个信号值时,必须等上一个信号的值被计算出来,再处理下一个,这种“循序渐进”的方式就是阻塞赋值的代表作。
但是,说到非阻塞赋值,它就完全不一样了。
非阻塞赋值好像一个特别会multitasking(多任务处理)的家伙,啥事都不急,做得也不慢,反正一心二用,顾得了这边又能管得了那边。
在Verilog中,非阻塞赋值就是用“<=”来表示的。
它和阻塞赋值最大的区别就是:它不会等前一个赋值操作完成后才去做下一个,而是直接“放手一搏”,按自己的节奏走。
就好像你炒菜的时候,一边看着锅里的菜,另一边手里已经开始切别的蔬菜了。
这种“同步进行”的方式让你的代码看起来很高效,也能避免在一些需要并行执行的场景下,出现拖沓的情况。
你会发现非阻塞赋值让代码看起来好像更“灵活”一些。
因为它可以在同一时刻进行多个赋值操作,减少了等待的时间,所以特别适合那些需要并行处理的复杂设计。
想象一下,当你在做一台计算机模拟的设计时,非阻塞赋值就好比是一个多线程的系统,不停地切换工作,任何时候都能看似同时处理多个任务,而不会因为一个赋值的完成而停顿下来。
Verilog的delay与阻塞or非阻塞的仿真
仿真、延迟时序ftang 代码技巧用【$display()】+【$time】引入【$display()】对仿真的影响------display若打印变量、变量也作为敏感信号无$display()时候【$monitor()类似】有$display()时候+$display()不使用变量===不会影响逻辑例子---------------2个变量例子1=阻塞+delay在右侧==【process在sleep期间忽略其他事件+唤醒后使用old 右值】在T=100时,触发always块的process执行#50会导致该process进入sleep且因为是=阻塞赋值,则在该process过程中、其不会被新的事件唤醒【也阻塞其他事件】当该process被唤醒的时候,使用旧的右值、并赋给左值【右侧delay使用旧值】例子1续=阻塞+delay在右侧==【更清晰看出sleep期间忽略新的事件】在T=100时候,#50导致process进入sleep------sleep期间忽略、其他事件例子2=阻塞+delay在左侧==【process在sleep期间忽略其他事件+唤醒后使用new 右值】在T=100时,触发always块的process执行#50导致该线程进入睡眠-----在睡眠会忽略其他的事件【添加$display()可知】例子3=非阻塞+delay在右侧==【process立即返回+对new事件敏感+使用old值】在T=100时,触发always块的process执行#50会导致该process进入sleep且因为是<=非阻塞赋值,则不会阻塞后面的语句执行,因后面没有语句该process相当于立即返回【若加打印可以看的比较清楚,立即返回了】在T=120时,因该process返回了,则可以被再次触发对比=若后面还有其他阻塞语句话【如#30】,则该process不会立即返回------在sleep期间、会忽略新的事件例子4=非阻塞+delay在左侧==在T=100时,触发always块的process执行因为#50在左侧=则该process进入sleep------在sleep期间、忽略新的触发事件【则上面提取的概念】--------sleep方面+process返回【整个process做sleep】+【部分子式做sleep,但process返回】【process做sleep】与【process返回】-----process返回后,才会响应new触发事件----------实例阻塞赋值----会阻塞整个process,导致process不能返回【left = right】【left=#delay right】会先计算right,在做赋值#delay在左侧-----会阻塞整个process-------------------3个变量例子a1=阻塞+delay在右侧+级联在T=100时,触发always块的process执行#50导致process做sleep在process Wakeup后,做更新leftValue的操作【先计算右值+产生update事件+process做sleep+唤醒后更新左值+再做本process后面操作】在T=150时,process唤醒因第1条语句是阻塞、则process没有返回的----执行完b更新后、b的值变化但第2句仍为阻塞赋值、则其阻塞process返回-----则前面的b变化、不会导致process重新被触发对比=若第2句为非阻塞、则在T=150时候,先计算第2句右值+process返回+再更新第2句左值【因b在第1句更新的、那时process未返回,则也不会触发新的process】再对比=非阻塞赋值,是先process返回、再执行更新左值例子a2=阻塞+delay在右侧+平行例子a3=阻塞+delay在左侧+级联阻塞=会阻塞process的返回+阻塞process返回前、对敏感信号的响应例子a4=阻塞+delay在左侧+平行例子a5=非阻塞+delay在右侧+级联例子a6=非阻塞+delay在左侧+级联例子a7=非阻塞+delay在右侧+平行【上面提取】【产生update事件】+【更新左值】是不同的概念,也是不同的调度顺序-----【<=为先产生updateEvent+再process返回+最新更新左值】+【=先产生updateEvent+更新左值+最后process返回】即阻塞---不仅阻塞后面的语句执行,也阻塞process返回+也阻塞process对newEvent敏感【left=#delay right】==【先计算右值+产生update事件+process做sleep+唤醒后更新左值+再做本process后面操作(若无操作则process返回)】【left<=#delay right】==【先计算右值+产生update事件+process做sleep+唤醒后process 返回(若后续无阻塞语句)+更新左值】【process在返回前、会忽略new触发事件】【#delay】从某种程度上、相当于阻塞在左侧则#delay相当于单独的1句,【#delay left=right;】等价于【#delay; left=right; 】在右侧则这里有1个语法相关执行顺序,先执行右侧表达式,再执行delay【left=#delay right;】等价于【tmp= right ; #delay; left= tmp;】小结组合逻辑中,#delay即不能加在左侧,也不能放在右侧----因为在process做sleep时候、会忽略敏感事件时序逻辑中,#delay只能加在右侧---------------编译错误例子3=wire不能用于always中例子4=assign不能带#delay例子2=带反馈的+【always@(*)】与【always】区别波形1=【仅always】产生clk信号波形2=【always@(*)】产生的仅1个脉冲always@(event)=不断的等事件----因@(event)可以单独的使用,则always@(event)=不断的等事件----即@(event)可以理解为=1条语句----则一般而言仿真的process会在等event时候,处于睡眠上面的说明可能存在一些错误,这里想说明的是:当理解上出现问题的时候,用实际的例子来帮助理解;并不断的修正;注重:仿真vs可综合语句是有差异的,仿真便于debug(特别是大型的工程),多做coding自然会讲这2者分辨出来;。
FPGA-Verilog试题(西安电子科技大学)
西安电子科技大学考试时间分钟试题题号一二三四五六七八九十总分分数1.考试形式:闭(开)卷;2.本试卷共四大题,满分100分。
班级学号姓名任课教师一、选择题(每题2分,共18分)1. 下面哪个是可以用verilog语言进行描述,而不能用VHDL语言进行描述的级别?( A )(A) 开关级 (B)门电路级 (C) 体系结构级 (D) 寄存器传输级2.在verilog中,下列语句哪个不是分支语句?( D )(A) if-else (B) case (C) casez (D) repeat3.下列哪些Verilog的基本门级元件是多输出( D )(A) nand (B) nor (C) and (D) not4.Verilog连线类型的驱动强度说明被省略时,则默认的输出驱动强度为( B )(A) supply (B) strong (C) pull (D) weak5.元件实例语句“notif1 #(1:3:4,2:3:4,1:2:4) U1(out,in,ctrl);”中截至延迟的典型值为( B )(A) 1 (B) 2 (C) 3 (D) 46.已知“a =1b’1; b=3b'001;”那么{a,b}=( C )(A) 4b'0011 (B) 3b'001 (C) 4b'1001 (D) 3b'101第 2 页共 8 页7.根据调用子模块的不同抽象级别,模块的结构描述可以分为(ABC )(A) 模块级 (B)门级 (C) 开关级 (D) 寄存器级8.在verilog语言中,a=4b'1011,那么 &a=(D )(A) 4b'1011 (B) 4b'1111 (C) 1b'1 (D) 1b'09.在verilog语言中整型数据与( C )位寄存器数据在实际意义上是相同的。
(A) 8 (B) 16 (C) 32 (D) 64二、简答题(2题,共16分)1.Verilog HDL语言进行电路设计方法有哪几种(8分)1、自上而下的设计方法(Top-Down)2、自下而上的设计方法(Bottom-Up)3、综合设计的方法2.specparam语句和parameter语句在参数说明方面不同之处是什么(8分)。
verilog assign用法
verilog assign用法VerilogAssign是Verilog编程语言中的一种重要语句,用于定义从变量到表达式的赋值关系,并将表达式计算结果存储在变量中,主要被用于模拟电路仿真计算与测试任务,也可应用于软件模拟和测试电路的编写与调试。
Verilog Assign的用法有以下几种:1.续赋值:Verilog语言支持连续赋值,也就是在一个语句中,对多个变量进行赋值。
一般来说,连续赋值是由一个变量到表达式一次性计算出若干变量的值,例如:a=b=c=5;三个变量a、b、c的值都赋值为5。
2.连续赋值:Verilog语言中还支持非连续赋值,即在一个语句中,每个变量都有不同的表达式,例如:a=5; b=c+5; d=2*a;将变量a、b、d分别赋不同的值。
3.合赋值:Verilog Assign语句还支持集合赋值,即一个变量被赋予一系列值,例如:a={1’b0,3’b100,4’b1010};变量a赋值为一组不同的数值。
4.阻塞赋值:Verilog Assign语句支持非阻塞赋值,也就是在一条指令中书写多个赋值语句,Verilog会先处理后面的赋值语句,然后再处理前面的赋值语句,例如:a<=b+c; d<=e-f;变量a、d分别赋值,其中a=b+c,d=e-f。
5.塞赋值:Verilog Assign语句也支持阻塞赋值,也就是在一条指令中书写多个赋值语句,但是Verilog会依次处理其中的赋值语句,例如:a=b+c; d=e-f;变量a、d分别赋值,其中a=b+c,d=e-f。
Verilog Assign语句是Verilog编程语言中一种重要的控制语句,用于定义从变量到表达式的赋值关系,其用法有连续赋值,非连续赋值,集合赋值,非阻塞赋值和阻塞赋值等几种。
Verilog Assign 用法掌握良好,可以帮助程序员有效地编写Verilog程序,节省编程时间,提高程序的效率。
阻塞赋值和非阻塞赋值深度解析——仿真事件的调度
阻塞赋值和⾮阻塞赋值深度解析——仿真事件的调度来源:EETOP BLOG 作者:acgoal/blog/html/46/553746-51456.html下⾯有⼀段verilog代码和仿真⽂件,⽤的是VCS仿真和编译⼯具。
我们来研究⼀下不同的驱动赋值⽅式对仿真结果的影响。
下⾯我把我做的例⼦和⼤家分享⼀下。
设计源代码如下:`timescale 1ns/1psmodule counter (data_out0, data_out1,clk,rst_n, data_in0, data_in1);output[3:0] data_out0;output [3:0] data_out1;input [3:0] data_in0;input [3:0] data_in1;input clk;inputrst_n;reg [3:0] data_out0;reg [3:0] data_out1;always @(posedge clk or negedge rst_n)begin if(!rst_n) begin data_out0 <= 4'd0; end else begin data_out0 <=data_in0; endendalways @(posedge clk) begin if(!rst_n) begin data_out1 <= 4'd0; end elsebegin data_out1 <= data_in1; endendendmodule这⾥有两段,分别表⽰带异步复位和带同步复位的。
测试程序如下:`timescale 1ns/1psmodule tb_top;reg clk;reg rst_n;wire [3:0] data_out0;wire [3:0] data_out1;reg[3:0] data_in0;reg [3:0] data_in1;counter u_counter0(.clk(clk), .rst_n(rst_n),.data_out0(data_out0), .data_out1(data_out1), .data_in0(data_in0),.data_in1(data_in1));initial begin clk=1'b0;endalways begin #3 clk=~clk;endinitial begin rst_n= 1'b1; #15 rst_n = 1'b0; #180 rst_n = 1'b1; #200 $finish;endinitial begin data_in0 <= 0;wait(!rst_n); wait(rst_n); @(posedge clk); data_in0 <= 1; @(posedge clk); data_in0 <= 2;@(posedge clk); data_in0 <= 4; @(posedge clk); data_in0 <= 8; @(posedge clk); data_in0<= 0;endinitial begin data_in1 <= 0; wait(!rst_n); wait(rst_n); @(posedge clk); data_in1 <= 1;@(posedge clk); data_in1 <= 2; @(posedge clk); data_in1 <= 4; @(posedge clk); data_in1<= 8; @(posedge clk); data_in1 <= 0;endinitial begin $vcdpluson();endendmodule注意这⾥红⾊的部分,data0和data1的驱动都⽤⾮阻塞赋值。
verilog的延时赋值语法
Verilog的延时赋值语法1. 延时赋值语法简介在Verilog硬件描述语言中,延时赋值语法是一种用于描述数字电路中信号延时行为的关键语法。
延时赋值语法允许设计者指定信号变化的时间延迟,从而模拟现实世界中电路元件的传播延迟。
通过准确地描述信号之间的延时关系,可以更好地实现电路设计、优化性能和解决时序问题。
2. 延时赋值的基本语法在Verilog中,延时赋值可以通过#符号和一个时间值来实现。
基本的延时赋值语法如下:#<时间值> <变量> = <值>;其中: - <时间值>:表示延时的时间,可以使用数字和时间单位来表示,如1ns表示1纳秒,10us表示10微秒,100ps表示100皮秒等。
- <变量>:表示信号变量,用于接收赋值后的结果。
- <值>:表示要赋给变量的值,可以是一个数字、一个表达式或者是其他信号。
3. 延时赋值的作用和用途延时赋值语法在Verilog中具有重要的作用和用途,主要包括以下几个方面:3.1 时序约束时序约束是指设计中对于信号的变化时间和时序关系的要求。
通过在Verilog代码中使用延时赋值语法,可以对电路中各个信号的变化时间和时序关系进行约束,从而确保电路的正确功能和正常工作。
3.2 电路仿真延时赋值语法对于电路仿真非常重要。
在进行数字电路仿真时,需要考虑信号在电路中的传播延迟,以模拟实际电路的运行情况。
通过使用延时赋值语法,可以在仿真过程中添加合适的延时,使得仿真结果更加准确和可靠。
3.3 时钟域切换在设计复杂的数字电路时,常常涉及到时钟域切换的问题。
不同时钟域的时钟信号在电路中的传播延迟可能存在差异,需要进行合适的时钟域切换处理。
使用延时赋值语法,可以实现时钟域切换的需求,确保电路在不同时钟域之间的正确协作和数据传输。
3.4 优化性能延时赋值语法还能够用于优化电路性能。
通过对电路中关键路径的延时进行调整,可以降低电路的时序问题和功耗,并提高电路的性能指标。
verilog非阻塞幅值
verilog非阻塞幅值Verilog Non-Blocking assignmentVerilog 是一种被广泛使用的 HDL(硬件描述语言),它可以用来描述复杂的电路,包括数字电路,模拟电路以及杂波电路。
Verilog 有一种特殊类型的赋值语句,叫作“非阻塞赋值(non-blocking assignment)”,它可以用来实现高速数字电路的模拟,这也是Verilog 中一个比较复杂的概念。
非阻塞赋值语句有两种形式:<=:不同时刻的信号,一个时刻覆盖另一个。
< =:不同时刻的信号,一个覆盖另一个,但更新时顺延至下一个时刻。
简单来说,非阻塞赋值语句用于比较连续时刻上的信号状态,并且把更新动作从当前时刻顺延到下一个时刻,即当前时刻不更新该信号,而是延迟到下一个时刻才更新。
以下示例演示了非阻塞赋值语句的使用:`timescale 1ns / 1psmodule clk_div ( clk, clk1, clk2 );input clk;output clk1, clk2;reg clk_div1, clk_div2;always @(posedge clk)beginclk_div1 <= ~clk_div1; // <= 赋值语句clk_div2 <= ~clk_div2; // < = 赋值语句endassign clk1 = clk_div1;assign clk2 = clk_div2;endmodule在上述示例中,使用了两种非阻塞赋值语句。
clk_div1 使用“<=”赋值语句,在 posedge 信号到达时立即更新;而clk_div2 使用“<=”赋值语句,在 posedge 信号到达时不立即更新,而是延迟到下一个周期才更新。
非阻塞赋值语句同样可以用于“赋值”(assign)语句,如下: reg [7:0] reg_a;always @(posedge clk)beginassign reg_a = 8'h80; // <= 赋值语句end上述代码中,使用了“<=”赋值语句,该语句在 posedge 信号到达时立即更新,即将 reg_a 的值变为 8'h80。
verilog reg 赋值用法
verilog reg 赋值用法Verilog作为一种硬件描述语言,广泛应用于数字电路的设计和验证。
在Verilog中,reg是一种用来声明寄存器的数据类型。
它可以用于存储和传输信号,用于顺序逻辑电路的实现。
在本文中,我们将深入探讨Verilog的reg赋值用法,包括阻塞赋值和非阻塞赋值,并结合具体的例子进行说明。
首先我们来介绍阻塞赋值。
在Verilog中,阻塞赋值使用“=”符号进行赋值。
在阻塞赋值中,当将一个值赋给reg时,该值立即传递给reg。
这意味着当一个阻塞赋值语句执行时,程序会等待该语句完成后再继续执行下一条语句。
下面是一个阻塞赋值的例子:```verilogmodule example_module;reg [7:0] data_reg;initialbegindata_reg = 8'b10101010; // 阻塞赋值$display("data_reg = %b", data_reg);endendmodule```在上述例子中,data_reg被赋值为8'b10101010。
当程序执行到阻塞赋值语句时,会立即将该值传递给data_reg,并且在下一条语句中将该值打印出来。
因此,程序的输出将是"data_reg = 10101010"。
接下来我们介绍非阻塞赋值。
在Verilog中,非阻塞赋值使用“<=”符号进行赋值。
与阻塞赋值不同,非阻塞赋值延迟一次时间步骤后再传递给reg。
这意味着当一个非阻塞赋值语句执行时,程序会继续执行下一条语句,不等待该语句完成。
下面是一个非阻塞赋值的例子:```verilogmodule example_module;reg [7:0] data_reg;reg [2:0] counter;always@(posedge clk)begincounter <= counter + 1; // 非阻塞赋值data_reg <= counter;endinitialbeginclk = 0;foreverbegin#5 clk = ~clk;endendendmodule```在上述例子中,我们使用一个时钟信号clk来驱动always块中的循环。
Verilog中阻塞与非阻塞的区别
从上面的例子中,我们可以看出,在阻塞赋值语句中,赋值的次序非常重要,而在非阻塞赋值语句中,赋值的次序并不重要。
下面我们具体分析一下阻塞和非阻塞赋值的语义本质:阻塞:在本语句中“右式计算”和“左式更新”完全完成之后,才开始执行下一条语句;非阻塞:当前语句的执行不会阻塞下一语句的执行。
先看阻塞赋值的情况:我们来看这段代码:always @(posedge Clk)beginQ1 = D;Q2 = Q1;Q3 = Q2;endalways语句块对Clk的上升沿敏感,当发生Clk 0~1的跳变时,执行该always语句。
在begin...end语句块中所有语句是顺序执行的,而且最关键的是,阻塞赋值是在本语句中“右式计算”和“左式更新”完全完成之后,才开始执行下一条语句的。
在本例中,D的值赋给Q1以后,再执行Q2 = Q1;同样在Q2的值更新以后,才执行Q 3 = Q2。
这样,最终的计算结果就是Q3 = D。
所有的语句执行完以后,该always语句等待Clk的上升沿,从而再一次触发begin...end 语句。
接下来,再看看非阻塞赋值的情况。
所谓非阻塞赋值,顾名思义,就是指当前语句的执行不会阻塞下一语句的执行。
always @(posedge Clk)beginQ1 <= D;Q2 <= Q1;Q3 <= Q2;end首先执行Q1 <= D,产生一个更新事件,将D的当前值赋给Q1,但是这个赋值过程并没有立刻执行,而是在事件队列中处于等待状态。
然后执行Q2 <= Q1,同样产生一个更新事件,将Q1的当前值(注意上一语句中将D值赋给Q1的过程并没有完成,Q1还是旧值)赋给Q2,这个赋值事件也将在事件队列中处于等待状态。
再执行Q3 <= Q2,产生一个更新事件,将Q2的当前值赋给Q3,这个赋值事件也将在事件队列中等待执行。
这时always语句块执行完成,开始对下一个Clk上升沿敏感。
verilog的延时赋值语法
verilog的延时赋值语法
Verilog是一种硬件描述语言,通常用于设计数字电路。
在Verilog中,延时赋值语法是一种重要的赋值方式,用于指定不同延迟时间的信号
赋值。
延时赋值语法的基本形式是:
<variable> = #<delay> <value>;
其中,<variable>是要赋值的信号名称,<delay>是延时时间(以仿
真时间为单位),<value>是要赋给信号的值。
举个例子,下面的代码片段演示了延时赋值语法的使用:
wire clk;
reg r = 0;
always begin
#10 clk = ~clk;
end
always@(posedge clk) begin
#5 r = ~r;
end
上述代码中,使用了两个always块来定义模块的行为。
第一个always块通过十个时钟周期交替将时钟信号clk赋值为0和1。
第二个always块在clk信号上升沿触发时,将寄存器r的值取反,并延迟5个时钟周期。
需要注意的是,延迟时间只在仿真时有意义,在实际 FPGA 中运行时不会生效。
因此,延时赋值的使用需要谨慎,需要充分考虑系统的实际响应时间,以避免产生意想不到的结果。
总的来说,Verilog中的延时赋值语法是设计数字电路时极为有用的一种机制,能够准确地指定信号在不同延迟时间内的赋值,从而实现更加复杂的功能。
但需要注意的是,它也容易导致设计出现不可预测的行为,因此需要谨慎使用。
Verilog中的延时、阻塞与非阻塞赋值仿真
从仿真语义的角度看Verilog中的延时、阻塞与非阻塞赋值1 Verilog中的延时Verilog没有和VHDL中类似的最小延时概念,所有的延时都由符号“#”来定义,如果没有这个符号就意味着没有延时,清单1中描述了一个有关延时的简单例子。
清单1 简单的延时wire #5 Y = A & B;清单1 中使用持续赋值语句描述了一个两输入端与门逻辑,并且在表达式前插入了5ns (#5)的延时,意义为Verilog仿真器会在5ns的延时后将A和B相与赋值给Y。
通过这个例子可以看出,延时的插入只需要在原本的语句中加入“#”关键字即可,但在实际的使用中却经常产生错误,实际中的延时时间是由具体的硬件电路来决定的。
使我们更深入的理解Verilog中的延时,更加关注描述的电路意义而不是描述语句本身,Verilog也是一种机于硬件的语言。
1.1 实际中的延时在实际的电路中,只存在着两种延时行为,一个是惯性延时,另一个是传输延时。
1.1.1 惯性延时(Inertial Day)惯性延时通常在信号通过逻辑门的时候发生,图1所示是信号通过一个具有5ns延迟的非门时的行为。
图1 惯性延时输入信号WireIn有两个高电平脉冲,一个宽度为3ns,另一个宽度为9ns。
当第一个3ns 的脉冲到达非门时,因为其宽度小于非门的本身延时(5ns),输出还来不及建立低电平,输入脉冲就已经过去,所以在输出信号WireOut上没有体现出第一个3ns脉冲的响应。
第二个脉冲宽度为9ns,大于非门的本身延时,所以在脉冲上升沿5ns之后,WireOut输出了一个宽度为9ns的低脉冲,这个脉冲与输入脉冲等宽、反向而且延迟了5ns。
这种延时称为惯性延时或惰性延时。
如果输入的变化过快,小于逻辑门本身的延时,就不会被体现在输出上。
1.1.2 传输延时(Transport Delay)传输延时相对于惯性延时更容易理解,相当于信号通过了一条拥有固定延时的传输线。
阻塞赋值与非阻塞赋值
阻塞赋值与非阻塞赋值作者:zhsj 日期:2015-7-27在Verilog语法中,阻塞赋值和非阻塞赋值是非常难理解的一个概念,尤其是对于初学者,往往搞不懂何时使用非阻塞赋值及何时使用阻塞赋值才能设计出符合要求的电路。
本文是笔者学习此概念时的学习笔记,主要分为概念解析和实例分析,并对一些编程要点进行总结分析,希望对各位初学者有所帮助。
在正式讲解之前先定义两个英文缩写字:RHS——赋值符合右边的表达式或变量;LHS——赋值符号左边的表达式或变量。
一、概念解析1.1 阻塞赋值阻塞赋值操作符为等号(即“=”),当采用阻塞赋值方式赋值时,需要先计算等号右手方向(RHS)部分的值,这时赋值语句不允许任何别的Verilog语句的干扰,直到现行的赋值完成时刻,即把RHS赋值给LHS的时刻,它才允许别的赋值语句的执行。
一般可综合的阻塞赋值操作在RHS不能设定有延迟,即使是零延迟也不允许。
若在RHS上加上延迟,则在延迟期间会阻止赋值语句的执行,延迟后才执行赋值,这种赋值语句是不可综合的,在需要综合的模块中不可使用这种风格的代码。
阻塞赋值的执行可以认为是只有一个步骤的操作,即计算RHS并更新LHS,此时不允许有来自任何其他Verilog语句的干扰。
所谓阻塞的概念是指在同一个always块中,其后面的赋值语句从概念上是前一句赋值语句结束后在开始赋值的,请注意,这只是概念上的先后,而无实质上的延迟。
在使用阻塞赋值时,如果在一个过程块中阻塞赋值的RHS变量正好是另一个过程块中阻塞赋值的LHS变量,这两个过程块又使用同一个时钟沿触发,这时阻塞赋值操作会出现问题,即如果阻塞赋值的顺序安排不好,就会出现竞争。
若这两个赋值操作用同一个时钟沿触发,则执行的顺序是无法确定的,在后面的例子中会看到这一问题。
1.2 非阻塞赋值非阻塞赋值操作符为小于等于号(即“<=”),当采用非阻塞赋值时,在赋值操作开始的时刻计算非阻塞赋值符RHS表达式,赋值操作结束的时刻才更新LHS。
verilog中for循环与阻塞赋值
Verilog中for循环与阻塞赋值初学fpga,对阻塞赋值和非阻塞赋值的区别不是很清楚,于是死记了一条原则:组合逻辑电路时用阻塞赋值,时序逻辑电路用非阻塞赋值。
好像还挺管用的,一直都没有遇到啥错误。
但是,最近写了一个简单八位的移位乘法运算,简单的几行代码,怎么也看不出有错,可是怎么也不出结果,想了很久都没找到原因。
我的代码如下:modulemul(ina,inb,clk,rst,cout); //8位移位乘法器input clk,rst;input [7:0] ina,inb;output[15:0] cout;reg [15:0] cout;integer i;reg [15:0] temp_a; //用来移位的中间变量reg [7:0] temp_b;always@(posedge clk )beginif(!rst) cout<=0;else if(!inb || !ina) cout<=0;else begintemp_a<=ina;temp_b<=inb;cout<=0;for(i=0;i<=7;i=i+1)beginif(temp_b[0]) cout<= cout +(temp_a<<i) ;else cout<= cout;temp_b<= temp_b>>1 ;endendendendmodu leISE仿真图:查阅了相关书籍,终于想通了,原来都是非阻塞语句惹的祸,“非阻塞赋值”是指在进程语句(initial和alway s)中,当前的赋值语句不会阻断其后的语句。
非阻塞语句可以认为是分为两个步骤进行的:①计算等号右边的表达式的值②在本条赋值语句结束时,将等号右边的值赋给等号左边的变量。
虽然我的程序里有for循环语句,由于用了非阻塞语句赋值,不管我的for内部循环有多少次,在一个时钟周期内我的for语句它只执行了一次,也就是将cou t初始化的值0(或者未知状态)又赋给了cou t,结果导致我的c o ut至始至终都是0 了。
verilog赋值原则之阻塞赋值与非阻塞赋值
verilog赋值原则之阻塞赋值与⾮阻塞赋值⼀. 阻塞赋值与⾮阻塞赋值的区别阻塞赋值(Blocking)符号为“ = ”,如:b = a ;可以认为是只有⼀个步骤的操作,计算RHS(等号右边)并更新LHS(等号左边),和C语⾔的赋值很类似。
其中“阻塞”⼆字的意思是在同⼀个块语句中,后⾯的赋值语句是在前⼀个语句赋值结束后才开始赋值的。
⾮阻塞赋值(Non_blocking)符号为“ <= ”,如:b <= a ;当⼀个块语句中有多条赋值语句时,同时计算RHS,计算完成后同时更新LHS。
举⼀个例⼦:`timescale 1ns/1nsmodule blocking ();reg[1:0] a,b,c;initial begina = 2'd1;b = 2'd2;c = 2'd3;#10a = 2'd0;b = a;c = b;$display("a=%d b=%d c=%d ",a,b,c);endendmodule运⾏结果为:若将上述代码的阻塞赋值都改为⾮阻塞赋值,则运⾏结果为:⼆. 赋值原则1. ⾮阻塞赋值只能⽤于寄存器型变量,只能在initial块和always块中使⽤。
阻塞赋值既可以⽤于寄存器型变量,也可以⽤于线⽹型变量。
2. 通常在设计可综合的RTL代码时,描述组合逻辑⽤阻塞赋值,描述时序逻辑⽤⾮阻塞赋值。
3. 在同⼀个块语句中描述组合逻辑和时序逻辑的混合逻辑时,⽤⾮阻塞赋值。
4. 尽量不要在同⼀个always块中同时使⽤阻塞赋值和⾮阻塞赋值。
5. 不能在多个always块中对同⼀个变量进⾏赋值(如果⽤两个always块对同⼀个变量赋值,⽆论其中经过了怎样的条件判断,最终都相当于将两个触发信号连在同⼀个寄存器的CLK端,这显然不合符数字逻辑电路的规则,这样的代码在综合时会报错)。
关于Verilog中的几种赋值语句(assign-deassign-force-release)
关于Verilog中的几种赋值语句(assign/deassign/force/release)1. 连续赋值语句(Continuous Assignments)连续赋值语句是Verilog数据流建模的基本语句,用于对线网进行赋值,等价于门级描述,是从更高的抽象角度来对电路进行描述。
连续赋值语句必须以关键词assign开始。
连续复制的主要特点是:•连续赋值语句的左值可以是一下类型之一:①标量线网②向量线网③矩阵中的一个元素(该矩阵可以是标量线网类型的,也可以是向量线网类型的)④向量线网的某一位⑤向量线网的部分位以及上述各种类型的拼接体但是,不能是向量或向量寄存器。
•连续赋值语句总是处于激活状态。
只要任意一个操作数发生变化,表达式就会被立即重新计算,并且将结果赋给等号左边的线网。
•操作数可以是标量或向量的线网或寄存器,也可以是函数的调用。
•赋值延迟用于控制对线网赋予新值的时间,根据仿真时间单位进行说明。
赋值延迟类似于门延迟,对于描述实际电路中的时序是非常重要的。
2. 过程赋值语句(Procedural Assignments)过程赋值语句的更新对象是寄存器、整数、实数或时间变量等。
这些类型的变量在被赋值后,其值将保持不变,直到被其他过程赋值语句赋予新值。
过程赋值语句只有在执行到的时候才会起作用。
过程赋值语句只能在initial或always语句内进行赋值,只能对变量数据类型赋值,同时initial和always中只能使用过程赋值语句。
过程赋值语句的左值可以是以下类型之一:①reg、整形数、实型数、时间寄存器变量或存储器单元②上述各种类型的位选(例如:addr[3])③上述各种类型的域选(例如:addr[31:16])④上面三种类型的拼接过程性赋值语句包括两种类型的赋值语句:阻塞赋值(=)和非阻塞赋值(<=)(其主要区别详见各类Verilog参考书,这里不再详述)。
3. 过程连续赋值语句(Procedural ContinuousAssignments)过程连续赋值是在过程块内对变量或线网型数据进行连续赋值,是一种过程性赋值,换言之,过程性连续赋值语句是一种能够在always或initial语句块中出现的语句。
【转】VeriLogHDL阻塞性过程赋值与非阻塞性过程赋值
【转】VeriLogHDL阻塞性过程赋值与⾮阻塞性过程赋值VeriLog HDL 阻塞性过程赋值与⾮阻塞性过程赋值⾸先来看⼀下定义:阻塞性过程赋值 “=” :即,在下⼀条语句执⾏前,完成当前语句执⾏。
⾮阻塞性过程赋值 “<=”:即,在当前输出时间同步结束后,或者任意输出被调度时,完成该语句执⾏。
下⾯解释⼀下上⾯的说法,根据以上说法与实际综合来看,即:阻塞赋值 “=” 为同⼀个时钟时刻内赋值完成所有操作。
如果模块⽐较⼤,则会增加逻辑速度延迟开销。
⾮阻塞赋值 “<=” 为当且仅当下⼀个时钟到来时候,或者本次触发完毕,进⾏赋值操作。
如果模块⽐较⼤,则插⼊寄存器,增⼤逻辑模块数量开销。
下⾯我们看⼀段代码来通过综合⽐较上⾯的说法:1:“=”阻塞性赋值:`default_nettype wand`timescale 1ns/100psmodule top(clk,rst,d,q,qout);input clk,rst,d;output q,qout;reg q,qout;/*********************************/always @(posedge clk or negedge rst)beginif(!rst)beginq = 0;qout = 0;endelsebeginq = d;qout = ~q;endendendmodule通过以上代码⽣成电路如图所⽰:此图表明,在同⼀个时钟周期到来的时候,即完成 q 与qout 的完全赋值。
2:“<=”⾮阻塞性赋值:`default_nettype wand`timescale 1ns/100psmodule top(clk,rst,d,q,qout);input clk,rst,d;output q,qout;reg q,qout;/*********************************/always @(posedge clk or negedge rst)beginif(!rst)beginq <= 0;qout <= 0;endelsebeginq <= d;qout <= ~q;endendendmodule通过以上代码⽣成电路如图所⽰:此图表明,在下⼀个时钟周期或者本次时钟周期结束时才进⾏赋值操作。
关于Verilog中的几种赋值语句
关于Verilog中的⼏种赋值语句关键字:assign deassign force release1. 连续赋值语句(Continuous Assignments)连续赋值语句是Verilog数据流建模的基本语句,⽤于对线⽹进⾏赋值,等价于门级描述,是从更⾼的抽象⾓度来对电路进⾏描述。
连续赋值语句必须以关键词assign开始。
连续复制的主要特点是:连续赋值语句的左值可以是⼀下类型之⼀:①标量线⽹②向量线⽹③矩阵中的⼀个元素(该矩阵可以是标量线⽹类型的,也可以是向量线⽹类型的)④向量线⽹的某⼀位⑤向量线⽹的部分位以及上述各种类型的拼接体但是,不能是向量或向量寄存器。
连续赋值语句总是处于激活状态。
只要任意⼀个操作数发⽣变化,表达式就会被⽴即重新计算,并且将结果赋给等号左边的线⽹。
操作数可以是标量或向量的线⽹或寄存器,也可以是函数的调⽤。
赋值延迟⽤于控制对线⽹赋予新值的时间,根据仿真时间单位进⾏说明。
赋值延迟类似于门延迟,对于描述实际电路中的时序是⾮常重要的。
2. 过程赋值语句(Procedural Assignments)过程赋值语句的更新对象是寄存器、整数、实数或时间变量等。
这些类型的变量在被赋值后,其值将保持不变,直到被其他过程赋值语句赋予新值。
过程赋值语句只有在执⾏到的时候才会起作⽤。
过程赋值语句只能在initial或always语句内进⾏赋值,只能对变量数据类型赋值,同时initial和always中只能使⽤过程赋值语句。
过程赋值语句的左值可以是以下类型之⼀:①reg、整形数、实型数、时间寄存器变量或存储器单元②上述各种类型的位选(例如:addr[3])③上述各种类型的域选(例如:addr[31:16])④上⾯三种类型的拼接过程性赋值语句包括两种类型的赋值语句:阻塞赋值(=)和⾮阻塞赋值(<=)(其主要区别详见各类Verilog参考书,这⾥不再详述)。
3. 过程连续赋值语句(Procedural Continuous Assignments)过程连续赋值是在过程块内对变量或线⽹型数据进⾏连续赋值,是⼀种过程性赋值,换⾔之,过程性连续赋值语句是⼀种能够在always或initial语句块中出现的语句。
Verilog非阻塞赋值的仿真综合问题(转)
Verilog非阻塞赋值的仿真综合问题(转)在Verilog语言最难弄明白的结构中“非阻塞赋值”要算一个。
甚至是一些很有经验的工程师也不完全明白“非阻塞赋值”在仿真器(符合IEEE标准的)里是怎样被设定执行的,以及什么时候该用“非阻塞赋值”。
这篇文章将介绍怎样设定“非阻塞赋值”和“阻塞赋值”,给出了重要的使得编码可以被正确地综合的编码指导方针,和避免仿真竞争的编码风格细节。
1.0 介绍众所周知的逻辑建模方针是:* 在always 块里用“阻塞赋值”产生组合逻辑。
* 在always 块里用“非阻塞赋值”产生时序逻辑。
但是为什么?(外注:在实现组合逻辑的assign结构中,当然采用阻塞赋值语句否则的话编译工具会提醒你进行修改的。
)普通的回答是:那只是关于仿真的,即使不遵照上面的规则也照样可以产生正确的综合结果。
但问题是综合前的仿真结果也许会跟综合后的电路行为仿真不匹配。
要明白上述建模方针背后的原因,就必须明白“非阻塞赋值”和“阻塞赋值”它们的功能和时序安排(the functionality and schedulingof blocking and nonblocking assignments.)。
这篇文章将详细描述有关问题。
文章里将用到两个缩写形式:RHS(right-hand-side)和LHS(left-hand-side)。
前者指等式右边的表达式或者变量(RHS expression or RHS variable),后者指指等式左边的表达式或者变量(RHS expression or RHS variable)。
2.0 Verilog 仿真竞争条件IEEE Verilog Standard [2] 定义:“保证性的赋值描述”和“非保证性的赋值”描述分别用“非阻塞赋值”和“阻塞赋值”。
("Determinism", section 5.4.1;"Nondeterminism", section 5.4.2 & "Race conditions", section 5.5)IEEE Verilog 标准允许在同一仿真时间里赋值竞争的产生。
always语句中延时非阻塞赋值
always语句中延时非阻塞赋值1. 延时非阻塞赋值是一种编程技术,可以在程序中使用always语句来实现。
在Verilog中,always语句用于描述时序逻辑,其中可以使用非阻塞赋值(<=)来实现延时非阻塞赋值。
2. 延时非阻塞赋值的特点是可以在同一时刻同时进行多个赋值操作,而不需要等待前一个赋值操作完成。
这是因为延时非阻塞赋值的赋值操作是并行执行的,不会阻塞其他赋值操作。
3. 与阻塞赋值(=)不同,延时非阻塞赋值的赋值操作是在时钟上升沿之后的一个延时周期内执行的。
这样可以避免在同一个时钟周期内出现多个赋值操作,从而避免出现竞争条件和冒险问题。
4. 在Verilog中,延时非阻塞赋值的延时值可以使用常量、参数或者变量来指定。
常用的延时单位有纳秒(ns)、微秒(us)和毫秒(ms)。
5. 延时非阻塞赋值的语法格式为:always @(posedge clk) begin ... <= #delay value; ... end。
其中,posedge clk表示时钟上升沿触发always语句,#delay value表示延时值。
6. 延时非阻塞赋值可以用于描述复杂的时序逻辑,例如状态机、计数器和FIFO等。
它可以确保时序逻辑的正确性和稳定性。
7. 延时非阻塞赋值还可以用于解决时序逻辑中的冒险问题。
冒险问题是指在时钟上升沿之后的一个延时周期内,由于信号传播延迟不同,可能会出现电平竞争和不确定的结果。
使用延时非阻塞赋值可以解决冒险问题,确保信号的稳定性和正确性。
8. 延时非阻塞赋值还可以用于描述时钟和数据的同步问题。
在时钟和数据的同步电路中,延时非阻塞赋值可以确保数据在时钟上升沿之后的一个延时周期内传输到目标寄存器,从而避免数据传输的错误和不确定性。
9. 延时非阻塞赋值在硬件描述语言中广泛应用于数字电路设计。
它是描述时序逻辑的重要工具,可以提高电路的性能和可靠性。
10. 延时非阻塞赋值在实际的数字电路设计中具有很大的灵活性和适应性。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
从仿真语义的角度看Verilog中的延时、阻塞与非阻塞赋值1 Verilog中的延时Verilog没有和VHDL中类似的最小延时概念,所有的延时都由符号“#”来定义,如果没有这个符号就意味着没有延时,清单1中描述了一个有关延时的简单例子。
清单1 简单的延时wire #5 Y = A & B;清单1 中使用持续赋值语句描述了一个两输入端与门逻辑,并且在表达式前插入了5ns (#5)的延时,意义为Verilog仿真器会在5ns的延时后将A和B相与赋值给Y。
通过这个例子可以看出,延时的插入只需要在原本的语句中加入“#”关键字即可,但在实际的使用中却经常产生错误,实际中的延时时间是由具体的硬件电路来决定的。
使我们更深入的理解Verilog中的延时,更加关注描述的电路意义而不是描述语句本身,Verilog也是一种机于硬件的语言。
1.1 实际中的延时在实际的电路中,只存在着两种延时行为,一个是惯性延时,另一个是传输延时。
1.1.1 惯性延时(Inertial Day)惯性延时通常在信号通过逻辑门的时候发生,图1所示是信号通过一个具有5ns延迟的非门时的行为。
图1 惯性延时输入信号WireIn有两个高电平脉冲,一个宽度为3ns,另一个宽度为9ns。
当第一个3ns 的脉冲到达非门时,因为其宽度小于非门的本身延时(5ns),输出还来不及建立低电平,输入脉冲就已经过去,所以在输出信号WireOut上没有体现出第一个3ns脉冲的响应。
第二个脉冲宽度为9ns,大于非门的本身延时,所以在脉冲上升沿5ns之后,WireOut输出了一个宽度为9ns的低脉冲,这个脉冲与输入脉冲等宽、反向而且延迟了5ns。
这种延时称为惯性延时或惰性延时。
如果输入的变化过快,小于逻辑门本身的延时,就不会被体现在输出上。
1.1.2 传输延时(Transport Delay)传输延时相对于惯性延时更容易理解,相当于信号通过了一条拥有固定延时的传输线。
如图2所示是信号通过一条5ns的延时线地示意图与波形。
图2 传输延时容易看出来,WireOut实际上就是被延迟了5ns的WireIn。
所以传输延时的意义就是将输入信号延迟一定时间后体现在输出上,而且输入信号上的所有细节都不会丢失。
1.2 持续赋值语句中的延时在持续赋值语句只有一种合法的延时描述,如清单2所示:清单2 持续赋值语句中的延时assign #5 WireOut = ~ WireIn;这种描述用语表示电路中的惯性延时,任何小于5ns的输入变化都会被过滤而不会体现在输出上。
1.3 过程赋值语句中的延时过程赋值语句中的延时情况比较复杂,但是结论很简单:●在持续赋值语句中使用正规延时,可以描述惯性延时。
●在非阻塞赋值语句中使用内定延时,可以描述传输延时。
1.3.1 正规延时和内定延时正规延时和内定延时的定义见清单3。
清单3 正规延时和内定延时#N sum = a+b; //正规延时sum = #N a+b; //内定延时定义于赋值语句前面的延时称为正规延时,其意义是:若赋值语句的执行条件在T时刻得到满足,该语句并不会立即执行,而是在延时N时间后,也就是在T+N时刻将T+N时刻的a+b赋值给sum。
内定延时定义于赋值语句的右式之前,其意义是:若赋值语句的执行条件在T时刻得到满足,立即将T时刻的a与b相加,并不是立即赋值给sum,而是在延时N时间后,也就是在延时N时间后将a+b赋值给sum。
了解了正规延时和内定延时的概念,不难想象出,对应Verilog中的持续性赋值、阻塞性赋值和非阻塞赋值这三种赋值形式,一共有六种插入延时的方法。
但是在持续赋值中插入内定延时是非法的,这是因为内定延时需要将T时刻的结果保持到T+N时刻进行赋值,表现出记忆特性,与持续赋值的意义相冲突。
下文介绍阻塞赋值和非阻塞赋值中的延时。
1.3.2 阻塞赋值中的延时在阻塞赋值中可以插入正规延时和内定延时,示例如清单4所示。
由Quartus II综合后得到时间戳report和RTL图形分别如图3和图4所示,由Modelsim仿真产生的仿真波形如图5所示。
清单4阻塞赋值语句中的延时module DelayDemo(A,B,C,D);output A,B,C,D;reg [3:0] A,B,C,D;initialbeginA=4'd0;B=4'd0;#4 A=4'd2;B=4'd4;#2 A=4'd3;#2 A=4'd4;#9 A=4'd3;#2 A=4'd5;B=4'd5;#5 B=4'd8;endalways@(A or B)beginC =#3 A+B; //阻塞赋值中的内定延时endalways@(A or B)begin#3 D= A+B; //阻塞赋值中的正规延时endendmodule图3清单4的message图4清单4的RTL图5清单4的仿真波形在图5的仿真图中,对于不断变化的输入A和B,C为插入了3ns内定延时的A+B,D 为插入了3ns正规延时的A+B。
先讨论在阻塞赋值中插入内定延时的效果:●0ns时刻(Start1):always进程启动,仿真器计算0时刻A+B的值后进程挂起,等待3ns后赋值给C。
●3ns时刻(Display1):C接受赋值更新,由未知出跳变为0。
●4ns时刻(Start2):A和B同时变化,启动进程,仿真器计算A+B的值,并在等待3ns后赋值给C。
●6ns时刻:由于阻塞赋值的特性,A由2到3的跳变被忽略,不会反应在C上。
●7ns时刻(Start2):C由0跳变为4ns时刻A+B的值6…再来讨论在阻塞赋值中插入正规延时的效果:●0ns时刻(Start1):always进程启动,由于设定了3ns的正规延时,进程被挂起等待3ns后执行。
●3ns时刻(Display1):执行赋值,将该时刻的A+B=0赋值给C。
●4ns时刻(Start2):A和B同时变化,启动进程,仿真器计算A+B的值,并在等待3ns的延时,在7ns时刻再次执行。
●6ns时刻:由于阻塞赋值的特性,A由2到3的跳变被忽略,不会反应在C上。
●7ns时刻(Start2):执行赋值,将该时刻的A+B=7赋值给C。
…由上面的分析可知,在阻塞赋值语句中插入延时的效果是;在语句启动后延时的一段时间输出当前时刻(正规延时)或语句启动时刻(内定延时)的逻辑结果,并且会忽略这段时间内所有的输入改变事件。
但是这种行为不能模拟实际电路中的惯性延时或者传输延时,因此不适合在阻塞赋值中插入延时。
1.3.3 非阻塞赋值中的延时与阻塞赋值一样,非阻塞赋值也可以插入正规延时和内定延时,示例如清单5,图6和图7分别是Quartus II综合产生的时间戳report和RTL图形,图8是由Modelsim仿真产生的波形。
清单5 非阻塞赋值语句中的延时always@(A or B)beginC <=#3 A+B; //非阻塞赋值中的内定延时endalways@(A or B)begin#3 D<= A+B; //非阻塞赋值中的正规延时end/*其余部分与清单4相同*/图6清单5的时间戳report图7清单5的RTL图形图8清单5的仿真波形在图8的仿真图中,对于不断变化的输入A和B,C为插入了3ns内定延时的A+B,D为插入了3ns正规延时的A+B。
先讨论在非阻塞赋值中插入内定延时的效果:●0ns时刻(Start1):always进程启动,计算A+B的值,然后进程挂起,等待3ns后赋值给C。
●3ns时刻(Display1):C接受赋值更新,由未知出跳变为0。
●4ns时刻(Start2):A和B同时变化,启动进程,仿真器计算A+B的值,并在等待3ns后赋值给C。
●6ns时刻:由于非阻塞赋值的左式更新操作在仿真事件中的优先级要低于阻塞赋值的右式计算、左式更新,也低于由于输入改变而启动的非阻塞赋值本身的右式计算,所以在该时刻C的更新操作会被放入执行队列,并在3ns后执行赋值。
●7ns时刻(Display2):C由0跳变为4ns时刻A+B的值6●8ns时刻(Start3):进程再次启动,并会在3ns以后将C赋值为8ns的A+B值●9ns时刻:执行6ns时刻放入队列中的赋值操作,C被赋值为7…通过上面的分析可以看出在非阻塞赋值中插入内定延时可以很好的描述实际电路行为中的传输延时,这也是在过程赋值中唯一推荐使用的延时描述。
而非阻塞赋值中插入正规延时的效果大致与阻塞赋值中相同,会在当前的语句启动以后,延时一段时间输出当前时刻的逻辑结果,并且会忽略这段时间内的所有输入改变事件,不符合惯性延时和内定延时的行为特点。
2 阻塞赋值与非阻塞赋值2.1说明阻塞赋值与非阻塞赋值统称为过程赋值。
2.2组合逻辑Verilog中使用等号“=”来表示阻塞赋值,被赋值的变量放在等号的左边,计算赋值的表达式置于等号右边。
阻塞赋值可以很好的建模电路中的数据流,请考虑清单6中的代码片断。
清单6 组合逻辑的阻塞赋值reg temp1,temp2;always @(X or Y or CIN)begintemp1 = X ^ Y;temp2 = temp1 & CIN;SUM = temp1 ^ CIN;COUT = temp2 | (X & Y);End清单6是一个全加器的描述,其中所有的赋值语句都是阻塞赋值,特点是:等号“=”右边表达式的结果计算和将计算结果赋值给左边变量的操作,是一个统一、连续的过程,不允许在其中插入其他动作;阻塞赋值语句会阻塞其后代码中语句的执行,也就是说Verilog仿真器在完成一句阻塞赋值语句前,不会响应其他事件。
由此可见清单6中各语句的意义是:首先将X异或Y的结果赋值给temp1,接着执行第二条语句将temp1和CIN相与的结果赋值给temp2,并最终计算出SUM和COUT。
很好的反映了组合逻辑中的数据流动顺序。
如果将这里的阻塞赋值替换为非阻塞赋值,如清单7所示。
清单7 组合逻辑的非阻塞赋值1reg temp1,temp2;always @(X or Y or CIN)begintemp1 <= X ^ Y;temp2 <= temp1 & CIN;SUM <= temp1 ^ CIN;COUT <= temp2 | (X & Y);endVerilog中使用小于等号“<=”来表示非阻塞赋值,被赋值的变量放在等号的左边,计算赋值的表达式置于等号的右边。
与阻塞赋值不同,非阻塞赋值不能反映电路的数据流。
因为在Verilog仿真语义中规定:非阻塞赋值对于左边赋值变量的更新操作的优先级要低于阻塞赋值,也要低于非阻塞赋值本身等号右边的表达式计算,需要等到当前仿真周期结束时才被执行。