任务(task)可以用来描述共同的代码段,并在模块内任意位置被调用,让代码更加的直观易读。task 更像一个过程,过程内一般按顺序执行,完成各种逻辑控制。
调试 testbench 中的 task 时,新手可能会遇到一些问题。典型的问题有两个,一个是 task 内部声明使用的变量为什么不能在 Verdi 波形中查看,另一个是 task 输出端连接的信号为什么不随 task 内部赋值变量的变化而变化。本节将对这两个问题进行讲解说明。
Verdi 查看 task 内部变量
创建一个简单的 task,包含内部变量 reg 和 output,如下所示。
//varialbes in task
task reg_in_task ;
output [7:0] data_test1 ;
reg [7:0] data_test2 ;
begin
#100 ;
data_test1 = 8'h13 ;
data_test2 = 8'h24 ;
#100 ;
data_test1 = 8'h1a ;
data_test2 = 8'h2b ;
end
endtask
在 testbench 的 initial 语句中调用该task,并定义变量 data_test1_t,连接到该 task 输出端,如下所示。
`timescale 1ns/1ps
module test ;
......
reg [7:0] data_test1_t ;
initial begin
reg_in_task(data_test1_t) ;
end
endmodule
使用 simv 进行仿真,不用添加特殊选项,如下所示。
./simv -ucli -i wave_gen.tcl -l sim.log
打开 Verdi 和 fsdb 波形文件,添加 task 内部的变量 data_test1 和输出端 data_test2 时,会提示相关信号无法找到。
为解决上述问题,使用 simv 进行仿真时需要添加特殊选项 +fsdb+functions,如下所示。
./simv +fsdb+functions -ucli -i wave_gen.tcl -l sim.log
此时再在 Verdi 中添加 task 内部的变量 data_test2 和输出端 data_test1,其变化过程会在波形上显示,如下所示。
◆ 小结:VCS 仿真时,需要在 simv 仿真时添加 fsdb+functions 参数,才可在 Verdi 中打开 fsdb 波形并查看 task 内部变量的变化情况。
TASK 操作全局变量
上述仿真波形中,细心的读者可能会看到,虽然连线信号 data_test1_t 连接的是 task 输出端,但是 data_test1_t 并不随 task 输出端的变化而变化。
这是因为 testbench 中的代码一般是顺序执行,并没有对应的实际硬件结构。所以 task 输出端连接的对应信号不可以理解为连续赋值,而是理解为一个返回值。即 task 执行完毕时,只返回输出端连接的信号一个最终结果。所以,data_test1_t 只会在 task 结束时 (对应200ns) 被赋值为 8'h1a,并不会体现中间的变化过程。
如果一个信号在 task 中的变化能够体现在 task 外部,则该信号需要定义为全局变量。即信号需要定义在 task 外部,但是在 task 内部中驱动。
上述示例中,删除输出端 data_test1,并在 task 中直接对全局变量 data_test1_t 进行赋值驱动。
`timescale 1ns/1ps
module test ;
reg [7:0] data_test1_t
//varialbes in task
task reg_in_task ;
reg [7:0] data_test2 ;
begin
#100 ;
data_test1_t = 8'h13 ;
data_test2 = 8'h24 ;
#100 ;
data_test1_t = 8'h1a ;
data_test2 = 8'h2b ;
end
endtask
initial begin
reg_in_task ;
end
endmodule
仿真结果如下。此时全局变量 data_test1_t 的变化过程并不局限于 task 内部。
testbench 不用“Think In Hardware”,写法比较自由。在多个 task 中对同一个全局变量信号进行多驱动也是没有问题的,只要时间轴上分开驱动事件的先后顺序即可。
上述示例中再增加一个 task ,用以驱动全局信号 data_test1_t,则代码和仿真结果如下。这里不再分析。
task task_mult_drive ;
begin
#150 ;
data_test1_t = 8'hc8 ;
end
endtask
initial begin
task_mult_drive ;
end
小结:task 执行完毕时,只返回输出端连接的信号一个最终结果。如果 task 中信号的变化过程能够在 task 外部实时体现,则该信号也需要定义在 task 外部。
全部0条评论
快来发表一下你的评论吧 !