《VHDL时间控制和赋值语句.ppt》由会员分享,可在线阅读,更多相关《VHDL时间控制和赋值语句.ppt(108页珍藏版)》请在三一办公上搜索。
1、1,第6章行为描述(二):时间控制 和赋值语句,6.1 时间控制 6.2 赋值语句,2,6.1 时 间 控 制时间控制可以用来对过程块中各条语句的执行时间(时序)进行控制。时间控制可以分为两类:(1)延时控制:为行为语句的执行指定一个延时时间的时间控制方式。(2)事件控制:为行为语句的执行指定触发事件的时间控制方式。其中事件控制方式又可以分成两类:边沿触发事件控制 电平敏感事件控制,3,6.1.1 延时控制延时控制的格式为:#行为语句;或#;其中:符号“#”是延时控制的标识符;“”是直接指定的延迟时间量,它是以多少个仿真时间单位的形式给出的,可以是一个立即数、变量或表达式。,4,1.第一种形式
2、的延时控制语句在上面给出的第一种延时控制格式中,的后面跟着一条行为语句。在这种情况下,仿真进程在遇到这条带有延时控制的行为语句后并不立即执行行为语句指定的操作,而是要延迟等待到“”所指定的时间量过去后才真正开始执行行为语句指定的操作,如例6-1所示的程序。,5,【例6-1】第一种形式的延时控制语句。module clk_gen(clk);output clk;reg clk;initialbeginclk=0;/语句S1#10 clk=1;/语句S2#20 clk=0;/语句S3#30 clk=1;/语句S4endendmodule,串行块内共有四条赋值语句,其中语句S1没有时间控制部分,而语
3、句S2、S3和S4带有延时控制。,6,表6.1给出了例6-1在进行仿真时的时序以及输出信号clk的变化情况:,7,2.第二种形式的延时控制语句延时控制的第二种格式中,在“”后面没有出现任何行为语句,而只有一个语句结束符号“;”。在这种情况下,仿真进程在遇到这条延时控制语句后不执行任何操作,而是进入一种等待状态,等到过了由“”所指定的时间量后仿真流程,结束这条延时控制语句的执行。这种形式的延时语句出现在串行块和并行块中时产生的作用是不同的,下面我们举例说明。,8,【例6-2】第二种形式的延时控制语句使用于串行块。module clk_gen(clk);output clk;reg clk;ini
4、tial begin/串行块clk=0;/语句S1#10 clk=1;/语句S2#10;/语句S3#10 clk=0;/语句S4#30 clk=1;/语句S5endendmodule,9,表6.2给出了例6-2所示代码进行仿真时的程序控制流程和输出变化情况:,10,在例6-2的执行中我们可以看出:第二种形式的延时控制语句在串行块中的作用是使该控制语句后的下一条语句的执行时刻延迟了指定的时间量。因此,如下语句:begin#10;a=b;end 将等价于下面这一条语句:#10 a=b;下面我们给出另一个例子来说明第二种形式的延时控制语句在并行块中使用的情况。,11,【例6-3】第二种形式的延时控制
5、语句使用于并行块。module clk_gen(clk);output clk;reg clk;initial fork/并行块clk=0;/语句P1#10 clk=1;/语句P2#10;/语句P3#20 clk=0;/语句P4#30 clk=1;/语句P5joinendmodule,12,在这种情况下延时控制语句P3既没有产生具体的操作,又没有对并行块仿真执行的时序产生影响,所以在上例中有没有延时控制语句P3对于要实现的功能不会产生任何影响。如果我们将例6-3中的延时控制语句P3改为“#40;”,那么情况如何?,13,在介绍了如上两种形式的延时控制语句后,还必须对语法定义中的“”这一项进行说
6、明。“”这一项还可以是一个变量或表达式,而不必将其局限于某一立即数,比如:initialbegin:SEQ_1parameter DELAY_TIME=50;#DELAY_TIME out_1=0;/第一条赋值语句#(DELAY_TIME/2)out_2=1;/第二条赋值语句end,14,当“”是由一个变量或由一个表达式表示时,有可能出现该变量或表达式的值为负值以及取值为x或z的情况。Verilog语法规定:如果代表延时时间的变量或表达式的值为x或z,那么该延时控制等效于零时延控制;如果代表延时时间的变量或表达式的值为负值,则以该负值的二进制补码值作为实际的延时量。,15,6.1.2 边沿触发
7、事件控制事件控制方式是时间控制的另一种方式。在这种时间控制方式下,行为语句的执行需要由指定事件的发生来触发,该事件被称为“触发事件”。在always语句块格式中所使用的敏感事件列表就是一种事件控制。事件控制方式不仅能用于always语句块,而且还可以用于其它的行为语句。事件控制方式又可以进一步分成两类:边沿触发事件控制和电平敏感事件控制。,16,1.边沿触发事件控制这一类时间控制方式在指定的信号变化时刻,也就是在指定的信号的跳变边沿才触发语句的执行;而当信号处于稳定状态时则不会触发语句的执行。边沿触发事件控制的语法格式可以为如下几种:第一种:()行为语句;第二种:();第三种:(or or o
8、r)行为语句;第四种:(or or or);,符号“”是边沿触发事件控制的标识符,“事件表达式”代表着触发语句执行的触发事件;而“行为语句”则指出了触发事件所要触发执行的具体操作,17,1)事件表达式事件表达式可以是如下三种形式之一:。posedge negedge 其中,“”可以是任何数据类型的标量或矢量。,18,2)语法格式下面讨论前面给出的边沿触发事件控制的四种语法格式:(1)边沿触发事件控制的第一种语法格式:()行为语句;这种语法格式的敏感事件列表内只包含了一个触发事件,只有当这个指定的触发事件发生之后,后面的行为语句才能启动执行;,19,【例6-4】时钟脉冲计数器。module cl
9、k_counter(clk,count_out);input clk,output count_out;reg 3:0 count_out;initialcount_out=0;/给count_out赋初值0always(posedge clk)count_out=count_out+1;/在clk的每个正跳变边沿count_out增加1endmodule,所指定的触发事件是时钟信号“clk”发生正跳变。因此在执行这条事件控制语句时,仿真进程将等待时钟“clk”正跳变的发生,然后为计数寄存器“count_out”增值。,20,(2)边沿触发事件控制的第二种语法格式:();这种格式的事件控制语句
10、的执行过程与延时控制语句中没有行为语句的情况类似,仿真进程在遇到这条事件控制语句后会进入等待状态,直到指定的触发事件发生后才结束等待状态,退出该事件控制语句的执行并开始下一条语句的执行。比如例6-5中程序所示。,21,【例6-5】用于测定输入时钟正电平,负电平持续时间以及时钟周期的模块。module clk_time_mea(clk);input clk;time pos_edge_time,neg_edge_time;time high_last_time,low_last_time,last_time;initial begin(posedge clk);/*等待,直到时钟发生正跳变后退出
11、等待状态,继续执行下一条语句*/pos_edge_time=$time;(negedge clk);/*等待,直到时钟发生负跳变后退出等待状态,继续执行下一条语句*/neg_edge_time=$time;,22,(posedge clk);/*等待,直到时钟再次正跳变后退出等待状态,继续执行下一条语句*/last_time=$time-pos_edge_time;high_last_time=neg_edge_time pos_edge_time;low_last_time=last_time-high_last_time;$display(The clk stay in High leve
12、l for:%t,high_last_time);$display(The clk stay in Low level for:%t,low_last_time);$display(The clk signal Period is:%t,last_time);endendmodule,23,(3)边沿触发事件控制的第三种语法格式:(or or or)行为语句;在仿真进程遇到这种格式的边沿触发事件控制语句时如果所有的触发事件都没有发生,则仿真进程就会进入等待状态,直到其中的某一个触发事件发生后才启动执行后面给出的行为语句,仿真进程继续向下进行。例如例6-6给出的initial语句块所示。,24,
13、【例6-6】边沿触发事件控制语句的例子。initialbegina=1;(posedge clk1 or negedge clk2 or b)a=b;end只要发生了这三个触发事件中的任一个,赋值语句“a=b;”的执行就被启动。程序实现的功能是:给a赋初值1,然后等到clk1发生正跳变或clk2发生负跳变或信号b发生跳变时,将b的逻辑值赋值给a。,25,(4)边沿触发事件控制的第四种语法格式:(or or or);仿真进程在遇到这条事件控制语句后会进入等待状态,直到敏感事件列表所包含的多个触发事件中的任何一个得到发生后才结束等待状态,退出该事件控制语句并开始执行该事件控制语句后的下一条语句。,
14、26,【例6-7】连续监测信号a或b发生变化的时间。module display_information_of_change(a,b);input a,b;wire a,b;always/always过程块,重复进行监测begin(a or b);/*等待,直到a或b发生变化后退出等待状态,并开始下一条语句的执行*/$display(One of a and b changed in time:%t,$time);endendmodule,27,可以看出,例6-7中begin-end串行块内的两条语句可以用如下一条语句替换:(a or b)$display(One of a and b cha
15、nged in time:%t,$time);,28,2.敏感事件列表在always过程块中的使用always过程块可以带有事件控制。带有事件控制的always过程块既可以实现组合逻辑又可以实现时序逻辑;在用于实现这两种不同逻辑功能种类时,always过程块内的敏感事件列表会具有不同的特点。下面分别加以讨论。1)用always过程块实现组合逻辑功能(1)事件表达式内不能包含“posedge”和“negedge”关键词,也就是说敏感事件列表中的事件表达式只能是前面所述的第一种事件表达式形式。,上面给出的第一个特点是因为组合逻辑电路的输出是由输入电平所决定的,输入不同的跳变方式对输出不会产生任何影
16、响,因此敏感事件列表中的事件表达式不能是其余两种对跳变边沿加以指定的形式。,29,(2)组合逻辑的所有输入信号都要作为“”出现在敏感事件列表中。是因为组合逻辑电路的输入输出关系在每个时刻都应该是严格成立的,也就是说,无论什么时刻输入发生了变化,在输出端都应该立即有反应。如果某个输入信号没有出现在敏感事件列表中,那么过程块就没有办法检测到该信号的变化,这个输入信号对输出的影响就不能实现,这样就不能在任意时刻保证组合逻辑的输入输出关系。,30,【例6-8】不能正确实现三输入与门的模块。module three_input_and(a,b,c,out);input a,b,c;/三个输入a,b,co
17、utput out;reg out;always(a or b)/敏感事件列表中只包含了两个输入:a,bbeginout=a&b&c;endendmodule,31,【例6-9】正确实现三输入与门的模块。module three_input_and(a,b,c,out);input a,b,c;/三个输入a,b,coutput out;reg out;always(a or b or c)/敏感事件列表中包含了所有输入beginout=a&b&c;endendmodule,32,下面再举一个用always过程块实现组合逻辑功能的例子。【例6-10】利用敏感事件列表来对组合逻辑建模。module
18、 selective_adder_and_multiplier(a,b,sel,y);input a,b,sel;output y;wire3:0 a,b;reg7:0 y;always(a or b or sel)beginif(sel=0)y=a+b;else if(sel=1)y=a*b;endendmodule,always过程块中的敏感事件列表内包含了所有的输入信号,当任何一个输入发生变化都能及时地对输出进行更新。,33,2)用always过程块实现时序逻辑功能(1)事件表达式可以是事件表达式三种形式中的任何一种,也就是说所采用的事件表达式既可以是带有“posedge”或“neged
19、ge”关键词的事件表达式,也可以是只包含“信号名”的事件表达式。,34,(2)不要求所有的输入信号都出现在敏感事件列表的“信号名”中。这是由于时序逻辑电路逻辑状态的改变只发生在某个或某几个时钟输入信号的变化边沿,而在其它输入信号发生变化时电路逻辑状态保持不变。所以这时事件控制只需对这几个时钟输入信号进行监测就可以了,没有必要把其它输入信号也放入敏感事件列表中。,35,下面我们举几个例子来说明敏感事件列表在描述时序逻辑功能时的使用。【例6-11】时钟下降沿触发的D触发器。module d_ff(q,clk,d);input clk,d;output q;reg q;always(negedge
20、clk)begin q=d;endendmodule,always过程块的敏感事件列表包含了事件表达式“negedge clk”。这个事件表达式带有“negedge”关键词,它指出该D触发器状态的改变发生在clk信号的负跳变边沿,在其余时刻D触发器状态将保持不变。,36,【例6-12】同时由两个时钟沿:clk1上升沿和clk2下降沿进行控制的8位移位寄存器。module 8bits_shift_register(d_in,d_out,clk1,clk2);input clk1,clk2,d_in;output d_out;reg d_out;/d_out保存1bitreg1:7 data;/r
21、eg1:7保存其余7bitsreg1:4 i;/i用于循环计数always(posedge clk1 or negedge clk2)begind_out=data1;for(i=1;i7;i=i+1)datai=datai+1;data7=d_in;endendmodule,37,3)always过程块实现组合和时序混合的逻辑功能要实现组合和时序混合的逻辑功能,我们可以在一个模块中建立多个并行结构来实现。用一个或多个带有事件控制的always过程块来实现时序逻辑部分的功能;再用连续赋值语句或另外一个(或多个)always过程块来实现组合逻辑部分功能。在这种情况下,每一个always过程块只实
22、现了一类逻辑,而我们现在要讨论的是用同一个always过程块来实现组合和时序混合的逻辑功能的情况。,38,在组合逻辑和时序逻辑混合的情况下,模块逻辑状态和输出发生变化时刻要同时受时钟信号跳变沿和某些输入控制信号的控制,典型的例子是带有异步置位(清零)控制输入的时钟边沿触发器。比如一个带有异步清零控制输入位clr的时钟上升沿T触发器,其输入输出真值表如表6.4所示。,39,真值表的第1行说明:当清零信号clr为1时,无论其它输入信号和触发器当前状态如何(用“?”表示“任何状态”),触发器状态(也就是输出q)将始终为0;真值表的第2行到第5行说明了清零信号clr为0时,T触发器处于正常工作状态:若
23、在时钟上升沿输入t=0则触发器状态保持不变,而如果在时钟上升沿输入t=1则触发器的状态将发生翻转。,40,因此在输入clr为0时,触发器的逻辑功能是普通的时序逻辑,其状态和输出在时钟上升沿发生变化;而在输入clr变为1时,T触发器的输出立即变为0,这时的逻辑功能就是关于控制信号clr的组合逻辑。我们可以用一个always过程块来实现这种混合的逻辑功能,如例6-13所示。,41,【例6-13】带有异步清零位clr(高电平有效)的时钟上升沿T触发器。module asyn_clear_Tff(clk,clr,t,q);input clk,clr,t;output q;reg q;always(po
24、sedge clk or posedge clr)beginif(clr=1)q=0;else if(t=1)q=q;endendmodule,可以看出:在实现组合和时序混合逻辑时,always语句的敏感事件列表内要包含时序逻辑部分的时钟信号和组合逻辑部分的输入控制信号。clk和 clr就出现在敏感事件列表中。这两个信号中的任何一个发生变化都会启动语句块的执行:根据控制信号clr的逻辑电平取值,分别实现组合逻辑和时序逻辑,42,虽然可以利用一个always过程块来实现组合逻辑功能或者混合的逻辑功能,但必须注意到always过程块主要是为了对时序逻辑建模而引入的一种描述方式。所以在实际硬件设计工
25、作中应该尽量使用结构描述方式来描述组合逻辑,这样可以使综合后的结果更加接近实际硬件的结构。,43,6.1.3 电平敏感事件控制(wait语句)“电平敏感事件控制”是与“边沿触发事件控制”对应的另一种事件控制类别。与边沿触发事件控制不同,在电平敏感事件控制方式下启动语句执行的触发条件是某一个指定的条件表达式为真。电平敏感事件控制用关键词“wait”来表示。它可以有如下三种形式:wait(条件表达式)语句块;wait(条件表达式)行为语句;wait(条件表达式);,44,电平敏感事件控制的第一种形式中包含了一个语句块,它可以是串行块(begin-end块)或并行块(fork-join块)。在这种事
26、件控制语句形式下,语句块启动执行的触发条件是:条件表达式的值为“真(逻辑1)”。如果当仿真进程执行到这条电平敏感事件控制语句时条件表达式的值是“真”,那么语句块立即得到执行;否则语句块要一直等到条件表达式变为“真”时再开始执行。比如如下语句:wait(enable=1)begind=a&b;d=d|c;end,45,电平敏感事件控制的第二种形式中包含了一条行为语句,在这种事件控制语句形式下,行为语句启动执行的触发条件与前面第一种形式下的触发条件相同。两者之间惟一不同之处在于:这里启动的是一条行为语句的执行,而在第一种形式下启动的是一个语句块的执行。比如:wait(enable=1)d=(a&b
27、)|c;同样实现了“等待使能信号变为1后执行a,b,c的与或逻辑操作”的功能。在这里wait语句触发执行的是单条赋值语句“d=(a&b)|c;”。,46,在电平敏感事件控制的第三种形式中没有包含行为语句或语句块。wait(条件表达式);这种形式的电平敏感事件控制常常用来对串行块中各条语句的执行时序进行控制。比如如下语句:beginwait(enable=1);d=a&b;d=d|c;end,注意这种形式的wait语句在串行结构(串行块)中 才能实现时序控制功能。,47,电平敏感事件控制语句(wait语句)与“边沿触发事件控制”的区别:以“”开头的边沿触发事件控制只对信号的跳变边沿敏感,它给出的
28、触发事件是指定的信号跳变边沿;以“wait”开头的电平敏感事件控制只对信号的电平敏感,它给出的触发事件是指定的信号稳定逻辑状态。举一例加以说明:,48,【例6-14】电平敏感事件控制与边沿触发事件控制的比较。module level_and_edge_sensitive_compare(flag1,flag2);output flag1,flag2;reg enable,flag1,flag2;initial/第一个initial过程块,用于产生enable信号beginflag1=1;flag2=1;enable=1;#10 enable=0;#10 enable=1;#10$finish;
29、end,49,initial/第二个initial过程块,用于实现电平敏感事件控制begin#10;wait(enable=1)flag1=flag1;/若触发条件成立,flag1翻转endinitial/第三个initial过程块,用于实现边沿触发事件控制begin#10;(posedge enable)flag2=flag2;/若触发条件成立,flag2翻转endendmodule,50,51,6.2 赋 值 语 句6.2.1 过程赋值语句的基本格式过程赋值语句是使用于两种结构化过程块(initial过程块和always过程块)中的赋值语句。在过程块中只能使用过程赋值语句(不能在过程块中出
30、现连续赋值语句),同时过程赋值语句也只能用在过程块中。过程赋值语句的基本格式为:其中是“=”或“=”之一,它们分别代表了阻塞型赋值和非阻塞型赋值类型。,52,过程赋值语句只能用于对寄存器类的变量(寄存器reg、整型integer、实型real或时间型time变量)进行赋值操作。在经过过程赋值后,上面的这些变量的取值将保持不变,直到另一条过程赋值语句对变量重新赋值为止。,53,【例6-15】过程赋值语句赋值操作的各种目标变量形式。reg a;reg 0:7 b;integer i;reg0:7 mem_10:1023;initialbegina=0;/对一个1位寄存器a赋值i=356;/对一个整
31、型变量i赋值b2=1b1;/对8位寄存器b的第3位赋值b0:3=4b1111;/对8位寄存器b的前4位赋值mem_1 200=8hfd;/对存储器mem_1的第201个存储单元进行赋值a,b=9b101110110;/对用连接运算符构成的一个整体进行赋值end,54,根据对被赋值变量产生作用的优先级差别,可以将过程赋值语句分为如下两种类型:普通过程赋值语句(简称过程赋值语句)。过程连续赋值语句。其中普通过程赋值语句又可以根据赋值操作执行时的不同时序特点分成阻塞型过程赋值语句和非阻塞型过程赋值语句。,55,6.2.2 过程赋值的两种延时方式各种过程赋值语句都可以带有时间控制,过程赋值语句中可以出
32、现延时控制形式的时间控制和事件控制形式的时间控制。根据时间控制部分在过程赋值语句中出现的位置,可以把过程赋值语句中的时间控制方式分为如下两类:外部时间控制方式。内部时间控制方式。,56,1.外部时间控制方式如果时间控制部分出现在整个过程赋值语句的最左端,也就是出现在赋值目标变量的左边,那么这种时间控制方式就是外部时间控制方式。在外部时间控制方式下,过程赋值语句的仿真执行过程:比如语句:#5 a=b;,57,在仿真执行时就相当于如下几条语句的执行:initialbegin#5;/先延时a=b;/再求b值并将其赋值给aend可见,在外部时间控制方式下,时间控制所“控制”的是过程赋值语句开始执行时刻
33、到赋值表达式被计算以及赋值操作执行时刻之间的时间差。赋值表达式的计算以及对左端变量的赋值操作是发生在由时间控制部分所指定的时刻之后的。,58,【例6-16】外部时间控制方式。module timing_control_out_mode(b,c,d,clk,enable);input clk,enable;output b,c,d;reg b,c,d;initial/此过程块用于对输出进行初始化forkb=0;c=0;d=0;joininitial/此过程块用于对输出进行赋值,其中包含了外部时间控制,59,fork#5 b=b;/语句S1(posedge clk)c=c;/语句S2wait(en
34、able)d=d;/语句S3joinendmodule,60,2.内部时间控制方式 过程赋值语句中的时间控制部分还可以出现在“赋值操作符”和“赋值表达式”之间。这种情况下的时间控制称为“内部时间控制方式”。在内部时间控制方式下,过程赋值语句执行步骤:仿真进程遇到带有内部时间控制的过程赋值语句后,立即计算赋值语句中“赋值表达式”的值进入时间控制部分指定的等待状态,一直等待指定的延时时间量 或者是指定的触发事件发生将赋值表达式的取值赋给左端的被赋值变量。,61,比如语句:a=#5 b;它的执行等价于:initialbegintemp=b;/先求b的值#5;/再延时a=temp;/延时结束后再进行赋
35、值操作End可见,在内部时间控制方式下,时间控制所“控制”的是赋值表达式被计算时刻到赋值操作被执行时刻之间的时间差。,62,【例6-17】过程赋值语句中的内部时间控制方式。module timing_control_inner_mode(a,b,c,d,clk,enable);input a,clk,enable;output b,c,d;reg b,c,d;initial/此过程块用于对输出进行初始化forkb=0;c=0;d=0;join,63,initial/此模块用于对输出进行赋值,其中包含了内部时间控制forkb=#5 a;/语句S1c=(posedge clk)a;/语句S2d=w
36、ait(enable)a;/语句S3joinendmodule例6-17中第二个initial过程块内出现的三条过程赋值语句都带有内部方式的时间控制。,64,6.2.3 阻塞型过程赋值以赋值操作符“”来标识的赋值操作称为“阻塞型过程赋值”。阻塞型过程赋值语句的特点如下:(1)串行块(begin-end语句块)中的各条阻塞型过程赋值语句将以它们在顺序块中的先后排列次序依次得到执行;而fork-join并行块中的各条阻塞型过程赋值语句则是同时得到执行的。(2)阻塞型过程赋值语句的执行过程:首先计算右端赋值表达式的取值,然后立即将计算结果赋值给“=”左端的被赋值变量。,65,【例6-18】阻塞型过程
37、赋值语句带有延时控制时的情况。initialbegina=0;/语句S1a=#5 1;/语句S2a=#10 0;/语句S3a=#15 1;/语句S4end,66,图6.4 带有延时控制的阻塞型过程赋值产生的波形,图6.4给出了例618所示模块仿真执行时输出信号a的波形。,67,6.2.4 非阻塞型过程赋值 以赋值操作符“=”来标识的赋值操作称为“非阻塞型过程赋值”非阻塞型过程赋值语句的特点是:(1)在begin-end串行语句块中,一条非阻塞型过程赋值语句的执行不会阻塞下一条语句的执行。(2)仿真进程在遇到非阻塞型过程赋值语句后首先计算其右端赋值表达式的值,然后要等到当前仿真时间步结束时再将该
38、计算结果赋值给赋值变量。,68,为了了解非阻塞型过程赋值语句的上述两个特点,我们可以观察如下语句:initialbeginA=B;/语句S1B=A;/语句S2end,69,非阻塞型过程赋值语句带有外部延时控制它的执行相当于在指定的延时之后执行一条不带时间控制的非阻塞型过程赋值语句。并且这条非阻塞型过程赋值语句不会阻塞其后面语句的执行。,70,【例6-19】带有外部延时控制的非阻塞型过程赋值语句。initial/过程块1begin#5 a=b;/语句S1#10 c=d;/语句S2end,71,上面的过程块1相当于如下的过程块2:initial/过程块2forkbegin/语句块1#5;a=b;e
39、ndbegin/语句块2#10;c=d;endjoin,72,图6.5 带有外部延时控制的非阻塞型过程赋值语句的执行时序,过程块的执行时序如图6.5所示。,73,非阻塞型过程赋值语句带有内部延时控制 仿真进程在遇到这种赋值语句后将立即计算语句右端赋值表达式的值,然后进入延时控制部分所指定的等待状态,直到退出等待状态时刻所在时间步的末尾才执行赋值操作,将已计算得到的赋值表达式结果值赋给被赋值变量。例如如下语句:a=#10 b;,74,同时使用了阻塞型过程赋值语句和非阻塞型过程赋值语句的一个例子,注意两种赋值方式的区别。【例6-21】同时使用阻塞型过程赋值语句和非阻塞型过程赋值语句。reg a,b
40、,c;initialbegin a=0;/语句S1a=1;/语句S2b=a;/语句S3#5;/等待一定的时延c=a;/语句S4end,75,6.2.5 连续赋值语句Verilog HDL语言中的连续赋值语句与过程块一样也是一种行为描述语句。主要对组合逻辑电路的行为进行描述。连续赋值语句只能用来对连线型变量进行驱动(赋值),而不能对寄存器型变量进行赋值,它可以采取如下两种格式:(1)显式连续赋值语句:连线型变量类型 连线型变量位宽 连线型变量名;assign#(延时量)连线型变量名=赋值表达式;(2)隐式连续赋值语句:连线型变量类型(赋值驱动强度)连线型变量位宽#(延时量)连线型变量名=赋值表达
41、式;,它包含了两条语句:第一条语句是对连线型变量进行类型说明的说明语句;第二条语句是对这个已得到声明的连线型变量进行连续赋值的赋值语句。,76,【例6-22】显式连续赋值语句。module and_cont_assignment(z,x,y);input 3:0 x,y;output 3:0 z;wire 3:0 z,x,y;/连线型变量说明assign#(1.5,1.0,2.0)z=x&y;/连续赋值语句endmodule,其中指定的延时量为“(1.5,1.0,2.0)”,它指明了从信号x或y发生变化时刻到变量z被更新时刻之间的延时时间量:上升延时为1.5个时间单位,下降延时为1个时间单位,
42、关断延时为2个时间单位。,一个显式连续赋值语句的例子:,77,【例6-23】隐式连续赋值语句。module and_cont_assignment(z,x,y);input 3:0 x,y;output 3:0 z;wire 3:0 x,y;/输入连线型变量说明wire 3:0#(1.5,1.0,2.0)z=x&y;/隐式连续赋值语句endmodule,再给出一个隐式连续赋值语句的例子,它描述了与上例相同的硬件行为。,78,在实际使用中,连续赋值语句的赋值目标可以是如下几种:(1)标量连线型变量。如wire a,b;assign a=b;(2)向量连线型变量。如wire 7:0 a,b;ass
43、ign a=b;(3)向量连线型变量中的某一位。如wire 7:0 a,b;assign a3=b3;,79,(4)向量连线型变量中的某几位。如:wire 7:0 a,b;assign a3:2=b3:2;(5)上面几种类型的任意拼接运算结果。如wire a,c;wire 2:1 b;assign a,c=b;在需要对多个连线型变量进行连续赋值时,还可以采用如下形式的连续赋值语句,它可以实现对多个变量进行连续赋值:assign out_and=a&b;out_or=a|b;out_xor=ab;out_not_a=a;out_not_b=b;,上述语句是下面5条独立的连续赋值语句的简化形式:a
44、ssign out_and=a&b;assign out_or=a|b;assign out_xor=ab;assign out_not_a=a;assign out_not_b=b;,80,连续赋值语句特点:正如“连续赋值”这一名称所表述的含义,连续赋值语句对连线型变量(wire)进行的是连续的驱动。与寄存器型变量类型不同,连线型变量没有数据保持能力,只有在被连续驱动后才能取得确定值,若一个连线型变量没有得到任何连续驱动则它的取值将为不定态“x”。连续赋值就是实现对连线型变量进行连续驱动的一种方法。,81,一个连线型变量一旦被连续赋值语句赋值后,赋值语句右端赋值表达式的值将始终对被赋值连线型
45、变量产生驱动(连续驱动)。在仿真执行时,只要右端赋值表达式内的任一操作数发生变化,就会立即触发对被赋值连线型变量的更新操作:重新计算赋值表达式的取值,然后将计算得到的结果赋值给被赋值连线型变量。例6.24 AND 例6.25,82,【例6-24】连续赋值语句的例子。module or_by_cont_assignment(c,a,b);input a,b;output c;assign c=a|b;endmodule,83,【例6-25】与例624等价的描述。module or_by_proc_assignment(c,a,b);input a,b;output c;reg c;initial
46、/initial过程块用于对c赋初值beginc=x;endalways(a or b)/always过程块用于更新c的取值c=a|b;endmodule,84,如果连续赋值语句带有延时(#delay),则在仿真执行时,只要右端赋值表达式中的任一信号发生变化,都将立即对赋值表达式进行重新计算,然后进入延时等待状态,等到指定的延时时间过去后再将计算得到的赋值表达式取值结果赋值给被赋值连线型变量。,85,例如,下面这条连续赋值语句:assign#5 a=b;指定的驱动方式就是:当b的值发生变化时,立即对赋值表达式“b”的取值进行计算,然后进入“5”指定的延时等待状态,直到过了5个时间单位的延时时间
47、后才对a执行赋值操作,赋值表达式取值的计算结果(b发生变化后的采样值)赋值给a。图6.7给出了这条连续赋值语句在仿真执行时的时序图。,86,图6.7 连续赋值语句“assign#5 a=b;”执行时的时序图,87,如果在一个模块内包含了多条连续赋值语句,或者在一个模块中同时包含了连续赋值语句、过程块、模块实例或原语实例时,各条连续赋值语句和其它的过程块、模块实例和原语实例之间是以并行方式执行的:各条连续赋值语句、模块实例和原语实例都是同时在零仿真时刻产生作用,并且过程块也是从零时刻开始执行的。下面给出用连续赋值语句实现4位全加器的一个例子,如例6-26所示。,88,【例6-26】4位全加器。m
48、odule adder_4(a,b,ci,sum,co);input 3:0 a,b;input ci;output 3:0sum;output co;assign co,sum=a+b+ci;/连续赋值语句endmodule,89,最后总结一下连续赋值语句和过程赋值语句之间的区别:(1)从语法上来看,连续赋值语句由“assign”关键词来标识,而过程赋值语句中则不包含这个关键词。(2)连续赋值语句左边的被赋值变量必须是连线类型的变量,而过程赋值语句中的被赋值变量则必须是寄存器类型的变量。(3)连续赋值语不能出现在过程块(initial过程块或always过程块)中,而过程赋值语句则只能出现在
49、过程块内。,90,(4)连续赋值语句主要用来对组合逻辑电路进行建模以及对连线型变量间的连接进行描述,而过程赋值语句则主要用来对时序逻辑电路进行行为描述。(5)连续赋值语句对被赋值变量(连线类型变量)的赋值是“连续”的,而在过程赋值语句情况下,只有在过程赋值语句被执行时才执行赋值操作,语句执行完后被赋值变量的取值不再受到赋值表达式的影响。,91,6.2.6 过程连续赋值语句过程连续赋值语句也是一种过程性赋值语句,它用来实现过程连续赋值。过程连续赋值是在过程块内对变量进行连续赋值。过程连续赋值语句与连续赋值语句的不同之处在于:过程连续赋值语句只能用在过程块(initial过程块或always过程块
50、)中,而连续赋值语句则不能出现在过程块中。过程连续赋值语句可以对寄存器类变量进行连续赋值,它的赋值目标不可以是变量的某一位或者某几位,而连续赋值语句只能对连线型变量产生作用,它的赋值目标可以是变量的某一位或者某几位。,92,过程连续赋值语句执行的是一种“连续赋值”:一旦对某个变量进行了过程连续赋值,则该变量将一直受到过程连续赋值语句内“赋值表达式”的连续驱动,“赋值表达式”内操作数的任何变化都会引起被赋值变量取值的更新,直到对该变量执行了“撤销过程连续赋值”操作为止。在Verilog HDL中有两组过程连续赋值语句可以实现过程连续赋值,它们是“assigndeassign”语句组和“force