> 文章列表 > ASIC-WORLD Verilog(7)过程语句

ASIC-WORLD Verilog(7)过程语句

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