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