ASIC-WORLD Verilog(7)过程语句
写在前面
在自己准备写一些简单的verilog教程之前,参考了许多资料----asic-world网站的这套verilog教程即是其一。这套教程写得极好,奈何没有中文,在下只好斗胆翻译过来(加了自己的理解)分享给大家。
这是网站原文:Verilog Tutorial
这是系列导航:Verilog教程系列文章导航
Verilog的抽象层级
- 行为模型(Behavioral Models):对逻辑行为进行建模的更高级别的建模
- RTL 模型(RTL Models):逻辑在寄存器级建模
- 结构模型(Structural Models):逻辑在寄存器级和门级都被建模
过程块(Procedural Blocks)
Verilog行为代码在过程块内部,但有一个例外:一些行为代码也存在于过程块之外。随着文章的深入,我们可以详细了解这一点。
Verilog 中有两种类型的过程块:
- initial :initial 仅在时间零执行一次(从时间零开始执行)
- always : always 循环一遍又一遍地执行;顾名思义,它总是在执行
initial 的使用示例
module initial_example();
reg clk,reset,enable,data;initial beginclk = 0;reset = 0;enable = 0;data = 0;
endendmodule
在上面的示例中,initial的执行从时间 0 开始。initial中的语句执行一次后就不会再次被执行了。
always 的使用示例
module always_example();
reg clk,reset,enable,q_in,data;always @ (posedge clk)
if (reset) begindata <= 0;
end else if (enable) begin data <= q_in;
endendmodule
在always中,当触发事件发生时,就会执行begin和end里面的代码;然后再次等待下一个事件触发。重复这个等待和执行事件的过程,直到仿真停止。
过程赋值语句
- 过程赋值语句可以将值赋给 reg、interger、real和time变量,但不能将值赋给net(wire数据类型)
- 您可以将net(wire)、常量、另一个寄存器或某个特定值赋值给寄存器(reg 数据类型)
下面的代码是错误的:在initial中对wire变量进行了赋值。
module initial_bad();
reg clk,reset;
wire enable,data;initial beginclk = 0;reset = 0;enable = 0;data = 0;
endendmodule
下面的代码是正确的:在initial中仅对reg变量进行了赋值。
module initial_good();
reg clk,reset,enable,data;initial beginclk = 0;reset = 0;enable = 0;data = 0;
endendmodule
如果需要同时实现多个过程赋值语句,则这些语句必须包含在:
- 顺序的 begin-end 块中
- 并行的 fork-join 块中
begin-end语句的示例
begin-end是顺序执行的,所以赋值语句会按照时间顺序一条一条地执行----在时间1对clk赋值,在时间1+10对reset赋值,在时间1+10+5对enable赋值,等等······
module initial_begin_end();
reg clk,reset,enable,data;initial begin$monitor("%g clk=%b reset=%b enable=%b data=%b", $time, clk, reset, enable, data);#1 clk = 0;#10 reset = 0;#5 enable = 0;#3 data = 0;#1 $finish;
endendmodule
这个代码的仿真结果是这样的:
0 clk=x reset=x enable=x data=x
1 clk=0 reset=x enable=x data=x
11 clk=0 reset=0 enable=x data=x
16 clk=0 reset=0 enable=0 data=x
19 clk=0 reset=0 enable=0 data=0
fork-join语句的示例
fork-join是顺序执行的,所以赋值语句会同时执行----在时间1对clk赋值,在时间10对reset赋值,在时间5对enable赋值,等等······
module initial_fork_join();
reg clk,reset,enable,data;initial begin$monitor("%g clk=%b reset=%b enable=%b data=%b", $time, clk, reset, enable, data);fork#1 clk = 0;#10 reset = 0;#5 enable = 0;#3 data = 0;join#1 $display ("%g Terminating simulation", $time);$finish;
endendmodule
这个代码的仿真结果是这样的:
0 clk=x reset=x enable=x data=x
1 clk=0 reset=x enable=x data=x
3 clk=0 reset=x enable=x data=0
5 clk=0 reset=x enable=0 data=0
10 clk=0 reset=0 enable=0 data=0
11 Terminating simulation
阻塞赋值与非阻塞赋值(Blocking and Nonblocking assignment)
阻塞赋值按照顺序执行,它们会阻塞下一条语句的执行,直到执行完当前语句,因此被称为阻塞赋值。使用符号“=”进行赋值,示例:a = b;
非阻塞赋值是并行执行的,下一条语句的执行不会因为当前语句的执行而阻塞,因此它们被称为非阻塞语句。使用符号“<=”符号进行赋值,示例:a <= b;
来看个例子:
module blocking_nonblocking();reg a,b,c,d;
// Blocking Assignment
initial begin#10 a = 0;#11 a = 1;#12 a = 0;#13 a = 1;
endinitial begin#10 b <= 0;#11 b <= 1;#12 b <= 0;#13 b <= 1;
endinitial beginc = #10 0;c = #11 1;c = #12 0;c = #13 1;
endinitial begind <= #10 0;d <= #11 1;d <= #12 0;d <= #13 1;
endinitial begin$monitor("TIME = %g a = %b b = %b c = %b d = %b",$time, a, b, c, d);#50 $finish;
endendmodule
这是仿真结果和仿真波形:
TIME = 0 a = x b = x c = x d = x
TIME = 10 a = 0 b = 0 c = 0 d = 0
TIME = 11 a = 0 b = 0 c = 0 d = 1
TIME = 12 a = 0 b = 0 c = 0 d = 0
TIME = 13 a = 0 b = 0 c = 0 d = 1
TIME = 21 a = 1 b = 1 c = 1 d = 1
TIME = 33 a = 0 b = 0 c = 0 d = 1
TIME = 46 a = 1 b = 1 c = 1 d = 1