写在前面:
- 在module、program、interface、task和function之外声明的变量拥有静态的生命周期,即存在于整个仿真阶段。
- 在module、interface和program内部声明,且在task、process或者function外部声明的变量也是static变量,且作用域在该块中。
- 在module、interface和program中定义的task、function默认都是static类型。
- 在过程块中(task、function、process)定义的变量均跟随它的作用域,即过程块的类型,如果过程块为static,则它们也默认为static,反之亦然。这些变量也可以由用户显式声明为automatic或者static。
针对以上内容我们进行简单的代码练习,以做到更深入的了解其中含义,话不多说,直接上号!!!
练习主代码:
module top_tb; //定义module模块
parameter DLY = 2; //定义parameter参数,方便复用,且易于修改
reg [1:0] result_1, result_2; //声明变量
reg co_1,co_2; //声明变量
initial fork
begin //p1
#1; //延迟一个时钟单位
add2x2(2'b01,result_1,co_1); //调用add2x2方法
end
begin //p2
#DLY; //延迟2个时钟单位
add2x2(2'b01,result_2,co_2); //调用add2x2方法
#(DLY*4); //延迟8个时钟单位
end
join
//defaut static task
task add2x2(input[1:0] opt,output[1:0] result,output co);
reg [1:0] temp; //定义中间变量
begin
temp=opt; //将方法输入值赋值中间变量temp
#(DLY*2); //延时4个时间单位
$display("static task: %t :temp is %0d",$time,temp);
{co,result}=temp+2'b10; //输出
end
endtask
endmodule
代码分析:
仿真运行解析:
1.@0ns,编译完成,initial结构中使用fork...join块结构,内部的两个begin...end是并行运行的,但是每个begin...end是顺序执行。所以在0ns,语句被阻塞到断点1(进程1)和3(进程2);
2.@1000(由于时间精度是ps,时间单位是ns,此处1个时间单位显示1000ps),等到1000ps后,进程1执行断点2的方法,方法内部的赋值语句temp=opt同时执行,temp=2‘b01, 阻塞到断点7;
3.@2000由于DLY=2,在2000ns时,原本阻塞在断点3的进程2开始执行,进入方法内部,
赋值语句temp=opt同时执行,temp=2‘b10, 阻塞到断点7;
4.@5000,进程1在断点7等到执行信号,开始执行display和下边的断点8语句。
5.@6000,进程2在断点7等到执行信号,开始执行display和下边的断点8语句
??????????????????????????????????????????
上边的解析是否可以帮助你理清前5个时钟周期的运行顺序呢?在理解仿真运行的过程中,不知你是否会有以下疑问:
在1000ns时,进程1temp被赋值 2‘b01,在2000ps时,进程2temp被赋值 2‘b10, 那5000ps时进程1display 中temp打印的值究竟是多少?6000ps时进程2display 中temp打印的值究竟是多少?
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
仿真结果:
为什么会使这样呢?
这是因为在module模块中,如果没有特殊声明, 在task、process或者function外部声明的变量都是static变量,且作用域在该块中。在module、interface和program中定义的task、function默认都是static类型。那是不是可以认为在module中,如果没有特殊声明,内部的变量和方法,函数都是static,从仿真开始时被创建,在执行过程中不会被销毁,类似于全局变量,具有静态的声明周期,可以被多个进程和方法共享。(目前看应该是这样的),所以进程1与进程2调用同一个task时,后调用的进程会覆盖前边调用进程的值,就会出现进程1的temp=2‘b01被进程2的temp=2‘b10覆盖掉,最后5000ps和6000ps temp的输出结果都是2.
=============================static终止线===================================
那有什么方法可以使最后5000ps时temp的输出值为进程1的输入值1,6000ps时temp的输出值为进程2呢?不妨先分析一下,上边在5000ps和6000ps输出一样的结果,原因是两个进程公用了同一个储存空间,使得后边进来的值会一直将前边的值覆盖掉,那是不是给每个进程的值都有自己的进程空间,就会避免这样的情况发生,赶快尝试一下吧!
============================automatic起始线================================
将静态方法修改为动态方法
仿真结果:
将task声明为automatic,得到预想中的答案,automatic task为每一个进程中的temp都开辟了临时的储存空间,但是它的生命周期只局限于从task开始执行到结束。
可有曾想过,如果不将task定义为automatic,只将task内部的temp变量声明为automatic是不是最后得到的结果和将task声明为automatic一样呢?
各位小伙伴赶快动手试一下吧!!!