目录
前言
验证random模块时,模块中的rst和soft_rst都是模块的端口,rst为高有效,soft_rst为低有效。前期并没有测试soft_rst,后期发现本测试点,并进行验证时,发现在vip中并没有soft_rst以端口形式存在。刚开始想自己加上,后来觉着将soft_rst和rst连接比较方便。尝试使用forever、initial和always,发现自己对这几个使用有所欠缺。
top_test中对rst的赋值
reg rst_n = 'b0;
initial begin
#200;
rst_n = 1'b1;
end
过程
刚开始rst_n为0,在200ns之后再赋值为1,所以想在300ns后再将soft_rst赋值为rst,所以使用以下代码,代码可以编译通过,但是,仿真跑不起来,说明这种方法会导致仿真从一开始hang住,sim.log是空白的,猜测是rst_n刚开始有。
reg soft_rst = 'b0;
initial begin
#300;
forever begin
rst_n = ~soft_rst;
end
end
后面将forever改为always,编译就会有问题,Error: Syntax error : token is 'always'
reg soft_rst = 'b0;
initial begin
#300;
if ($test$plusargs("random_soft_rst")) begin
always@(soft_rst) begin
rst_n = ~soft_rst;
end
end
end
后面查了一下这几个的用法和思考哪里出了问题,发现always和initial是从仿真一开始同时立即执行,所以always块不能放在initial块中,更加不能加上延时。后面又尝试将initial块和延时去掉,出现elab fail,原因是if语句不能孤立的放在module中。
改为下面,就没有问题了,但是rst_n在刚开始就为1,没办法像之前一样在200ns之后再改变,仿真暂时可以通过,就先这样了,如果有知道的小伙伴,告诉一下,感谢~
reg soft_rst = 'b0;
always@(soft_rst) begin
if ($test$plusargs("random_soft_rst")) begin
rst_n = ~soft_rst;
end
end
总结
initial和always
verilog在本质上是并发而非顺序的。verilog中的各个执行流程(进程)并发执行,而不是顺序执行的。每个initial语句和always语句代表一个独立的执行过程,每个执行过程从仿真时间0开始执行并且两种语句不能嵌套使用。
所有的initial语句内的语句构成了一个initial块。initial块从仿真0时刻开始执行,在整个仿真过程中只执行一次。如果一个模块中包括了若干个initial块,则这些initial块从仿真0时刻开始并发执行,且每个块的执行是各自独立的。如果在块内包含了多条行为语句,那么需要将这些语句组成一组,一般式使用关键字begin和end将他们组合在一个块语句;如果块内只有一条语句,则不必使用begin和end。
两者的关系: 一个程序块可以有多个initial和always过程块。每个initial和always过程快在仿真的一开始同时立即执行,initial语句只执行一次,而always语句则不断重复的活动着,直到仿真结束。但always块语句后面跟着的过程快是否运行,满足则运行一次,满足则运行一次,直到程序结束。一段程序中使用的initial和always语句的次数不受限制,他们都是同时开始运行的。
相同点
1:always语句 和 initial语句;可以多次使用;
2:always语句 和 initial语句;各语句块 整体 是独立运行;
3:always语句 和 initial语句;各语句块 整体 是并行执行;
不同点
1:initial语句不带触发条件; always语句:带触发条件;
2:initial语句只执行一次; always语句:每当“控制时间敏感表”条件满足时,就会执行一次always语句内的块语句;
3:initial语句不可综合; always语句:可以被综合;
4:initial语句主要用于仿真测试中的初始化; always语句:没有限定;always语句一般含有 “@(控制事情敏感表)”,如果控制事情敏感表的条件被满足,那么执行always语句内的块语句;如果没有控制事情敏感表,那就表示 always语句的条件一直被满足,可以不断执行always语句你内的块语句。
1、initial
(1)语句格式:
initial begin .......end : 省略号中是 语句块,begin...end中按照顺序依次执行,仿真开始对各变量进行初始化,这个初始化不需要仿真时间,即在0ns时间内。
注意
一个模块中可以有许多个initial块,它们都是并行运行的。initial语句最常见的是用于测试文件里面的初始化语句,用来产生测试环境和设置信号记录。
2、always
always语句在仿真过程中不断的运行着。initial语句只执行一次,而always语句则不断重复的活动着,直到仿真结束。
但always块语句后面跟着的过程快是否运行,满足则运行一次,满足则运行一次,直到程序结束。
always语句注意点:
1、不要在不同的always块内为同一个变量赋值。即某个信号出现在<=或者=左边时,只能在一个always块内。
2、不要在同一个always块内同时使用阻塞赋值(=)和非阻塞赋值(<=)。
3、在使用always块描述组合逻辑时使用阻塞赋值(=);使用always块描述时序逻辑时使用非阻塞赋值(<=)。
4、任何在always块内被赋值的变量都必须是寄存器型(reg)。
5、always的敏感列表中可以同时包括多个电平敏感事件,也可以包括多个边沿敏感事件,但不能同时有电平和边沿敏感事件。另外,在敏感列表中,同时包括一个信号的上升沿敏感事件和下降沿敏感事件是不容许的,因为这两个事件可以合并为一个电平事件。
(1)语句格式:
always <时序控制> <语句>
always语句由于其不断活动的特性,只有和一定的时序控制逻辑结合在一起才有用。如果一个always没有时序控制,它将会产生死锁,例如: always clk = ~clk;
加上时序控制 always可以用来产生时钟信号:always #10 clk = ~clk 表示10个时间单位翻转一次。
3、always@()
(1)always块的边沿触发和电平触发
always的时序控制可以使边沿触发(上升沿或者下降沿)也可以用电平触发,可以是单个信号也可以是多个信号,中间需要用关键字or连接。
边沿触发时,always只要其中一个沿到来,就立即执行一次过程块,然后等待下一次的边沿到来。
电平触发时,多个电平触发的的always块,只要a,b,c中的任何一个发生变化,从高到低或者从低到高都会执行一次过程。
> 边沿触发
always@(posedge clk or negedge rst)
begin
....
end
> 电平触发
always@(a or b or c)
begin
....
end
一个模块可以包含多个always块,它们都是并行执行的。
示例
//有异步复位的电平敏感锁存器
always@(reset or clock or d)//也可以写成always@(a,b,c) 用,代替or
begin
if(reset)
q = 1‘b0;
else if(clock)
q = d;
end
//用reset异步下降沿复位,clock的正条边沿触发的D寄存器
always@(negedge reset , posedge clk)
if(!reset)
q <= 0;
else
q <= d;
(2)always@ (*)
用符号always@(*)可以把所有输入变量都包含进敏感列表
例如:
always@(a,b,c,d,e,f,g,h,r,m) begin
out1 = a?(b+c):(d+e);
out2 = f?(g+h):(r+m)
end
可以用下面代码来代替
always@(*) begin
out1 = a?(b+c):(d+e);
out2 = f?(g+h):(r+m)
end
(3)always wait()
前面所讨论的时间控制都需要等待信号值的变化或者事件的触发,使用符号@和后面的敏感列表来表示。
verilog允许另外一种形式表示的电平敏感时序控制(即后面的语句或者语句块必须等到某个条件诶真是才能执行),具体请看下面例子:
always
wait(count_enabel) # 20 count = count +1;
```
上面例子中,仿真器连续监视count_enable的值,若其值为1,在20个时间单位过后执行后面的语句,若其值为0,则不执行后面的语句。若其值始终为1,那么count将每过20个时间单位加1.
未完。。。
本文详细介绍了Verilog中initial和always块的使用,包括initial块的初始化功能,always块的边沿触发和电平触发,以及always@(*)和always wait()的应用。在Verilog编程中,initial块仅执行一次,而always块会根据条件反复执行,对于信号赋值和时序逻辑描述至关重要。
5593

被折叠的 条评论
为什么被折叠?



