非堵塞赋值和堵塞赋值
在Verilog HDL言语中,信号有两种赋值办法:非堵塞(Non_Blocking)赋值办法和堵塞(Blocking)赋值办法。
(1)非堵塞赋值办法。
典型句子:b = a;
① 块完毕后才完结赋值操作。
② b的值并不是立刻就改动的。
③ 这是一种比较常用的赋值办法,特别在编写可归纳模块时。
(2)堵塞赋值办法。
典型句子:b = a;
① 赋值句子履行完后,块才完毕。
② b的值在赋值句子履行完后立刻就改动。
③ 或许会发生意想不到的成果。
非堵塞赋值办法和堵塞赋值办法的差异常给规划人员带来问题。问题主要是给“always”块内的reg型信号的赋值办法不易掌握。到目前为止,前面所举的比如中的“always”模块内的reg型信号都是选用下面的这种赋值办法:
b = a;
这种办法的赋值并不是立刻履行的,也便是说“always”块内的下一条句子履行后,b并不等于a,而是坚持本来的值。“always”块完毕后,才进行赋值。而另一种赋值办法堵塞赋值办法,如下所示:
b = a;
这种赋值办法是立刻履行的,也便是说履行下一条句子时,b已等于a。虽然这种办法看起来很直观,可是或许引起费事。下面举例阐明。
例1:非堵塞赋值。
always @( posedge clk ) begin
b=a;
c=b;
end
例1中的“always”块顶用了非堵塞赋值办法,界说了两个reg型信号b和c。clk信号的上升沿到来时,b就等于a,c就等于b,这儿应该用到了两个触发器。需求留意的是赋值是在“always”块完毕后履行的,c应为本来b的值。这个“always”块实践描绘的电路功用如图1所示。
例2:堵塞型赋值。
always @(posedge clk) begin
b=a;
c=b;
end
例2中的“always”块用了堵塞赋值办法。clk信号的上升沿到来时,将发生如下的改变:b立刻取a的值,c立刻取b的值(即等于a)。归纳的电路如图2所示。
图1 非堵塞赋值归纳电路 图2 堵塞赋值归纳电路
它只用了一个触发器来存放a的值,并一起输出给b和c。这不是规划者的初衷,假如选用例3.5所示的非堵塞赋值办法就能够防止这种过错。
块句子
块句子一般用来将两条或多条句子组合在一起,使其在格局上看更像一条句子。块句子有两种:一种是begin_end句子,一般用来标识次序履行的句子,用它来标识的块称为次序块;另一种是fork_join句子,一般用来标识并行履行的句子,用它来标识的块称为并行块。下面进行具体的介绍。
1.次序块
次序块有以下特色。
(1)块内的句子是按次序履行的,即只要上面一条句子履行完后下面的句子才干履行。
(2)每条句子的推迟时刻是相关于前一条句子的仿真时刻而言的。
(3)直到最终一条句子履行完,程序流程操控才跳出该句子块。
次序块的格局如下:
begin
句子1;
句子2;
……
句子n;
end
或许:
begin:块名
块内声明句子
句子1;
句子2;
……
句子n;
end
其间:
(1)块名即该块的姓名,是一个标识符,其效果后边再具体介绍。
(2)块内声明句子可所以参数声明句子,reg型变量声明句子,integer型变量声明句子或许real型变量声明句子。
下面举例阐明。
例3:次序块。
begin
areg = breg;
creg = areg; //creg的值为breg的值
end
从该例能够看出,第一条赋值句子先履行,areg的值更新为breg的值。然后程序流程操控转到第二条赋值句子,creg的值更新为areg的值。由于这两条赋值句子之间没有任何推迟时刻,creg的值实为breg的值。当然能够在次序块里推迟操控时刻来分隔两个赋值句子的履行时刻,如例4所示。
例4:加延时次序块。
begin
areg = breg;
#10 creg = areg; //在两条赋值句子间推迟10个时刻单位
end
2.并行块
并行块有以下4个特色。
(1)块内句子是一起履行的,即程序流程操控一进入该并行块,块内句子则开端一起并行地履行。
(2)块内每条句子的推迟时刻是相关于程序流程操控进入到块内时的仿真时刻的。
(3)推迟时刻是用来给赋值句子供给履行时序的。
(4)当按时刻时序排序在最终的句子履行完后或一个disable句子履行时,程序流程操控跳出该程序块。
并行块的格局如下:
fork
句子1;
句子2;
…….
句子n;
join
或许:
fork:块名
块内声明句子
句子1;
句子2;
……
句子n;
join
其间:
(1)块名即标识该块的一个姓名,相当于一个标识符。
(2)块内阐明句子可所以参数阐明句子、reg型变量声明句子、integer型变量声明句子、real型变量声明句子、ime型变量声明句子或许事情(event)阐明句子。
下面举例阐明。
例5:并行块1。
fork
#50 r = h35; //在肯定时刻50单位后,r被赋值
#100 r = hE2; //在肯定时刻100单位后(非肯定时刻150),r再次被赋值
#150 r = h00;
#200 r = hF7;
#250 -> end_wave; //在肯定时刻250单位后,触发事情end_wave
join
在这个比如顶用并行块来代替前面比如中的次序块来发生波形,用这两种办法生成的波形是相同的。
3.块名
在Verilog HDL言语中,能够给每一个块取姓名,只需将姓名加在关键词begin或fork后边即可,这样做的原因有以下几点。
(1)这样能够在块内界说局部变量,即只在块内运用的变量。
(2)这样能够答应块被其他句子调用,如被disable句子调用。
(3)在Verilog言语里,一切的变量都是静态的,即一切的变量都只要一个专一的存储地址,因而进入或跳出块并不影响存储在变量内的值。
根据以上原因,块名就供给了一个在任何仿真时刻承认变量值的办法。需求留意的是,块名和变量名相同,都不能是关键词。
4.开端时刻和完毕时刻
在并行块和次序块中都有一个开端时刻和完毕时刻的概念。关于次序块,开端时刻便是第一条句子开端被履行的时刻,完毕时刻便是最终一条句子履行完的时刻。而关于并行块来说,开端时刻关于块内一切的句子是相同的,即程序流程操控进入该块的时刻,其完毕时刻是按时刻排序在最终的句子履行完的时刻。
当一个块嵌入另一个块时,块的开端时刻和完毕时刻是很重要的。跟在块后边的句子只要在该块的完毕时刻到了才干开端履行,也便是说,只要该块彻底履行完后,后边的句子才干够履行。
在fork_join块内,各条句子不用按次序给出,因而在并行块里,各条句子在前仍是在后是无关紧要的,如下所示。
例6:并行块2。
fork
#250 -> end_wave; //按下面几条句子次序履行成果和例[6]的履行成果相同
#200 r = hF7;
#150 r = h00;
#100 r = hE2;
#50 r = h35;
join
在这个比如中,各条句子并不是按被履行的先后次序给出的,但相同能够生成前面比如中的波形。
关键词
在Verilog HDL中,一切的关键词是事前界说好的承认符,用来安排言语结构。关键词是用小写字母界说的,因而在编写原程序时要留意关键词的书写,以防止犯错。下面是Verilog HDL中运用的关键词(请参阅附录:Verilog言语参考手册):
always、and、assign、begin、buf、bufif0、bufif1、case、casex、casez、cmos、deassign、default、defparam、disable、edge、else、end、endcase、endmodule、endfunction、endprimitive、endspecify、endtable、endtask、event、for、force、forever、fork、function、highz0、highz1、if、initial、inout、input、integer、join、large、macromodule、medium、module、nand、negedge、nmos、nor、not、notif0、notifl、or、output、parameter、pmos、posedge、primitive、pull0、pull1、pullup、pulldown、rcmos、reg、releses、repeat、mmos、rpmos、rtran、rtranif0、rtranif1、scalared、small、specify、specparam、strength、strong0、strong1、supply0、supply1、table、task、time、tran、tranif0、tranif1、tri、tri0、tri1、triand、trior、trireg、vectored、wait、wand、weak0、weak1、while、wire、wor、xnor、xor。
在编写Verilog HDL程序时,变量名、端口名、块名等的界说不要与这些关键词抵触。