问题现象
在仿真时,有时候会遇到仿真结束时间与"设置值不符的现象"。 比如通过 uvm_root::set_timeout(1us); 结果uvm在仿真进行到1ms的时候,才会自动timeout结束。
问题原因
上述问题的原因是,对于sv而言,time这个类型其实有点骗人,其本质并不是"特定的时间"而只是64位的数字而已。仿真器在运行仿真时,对于不同的“单元”,仿真时间精度可能是不同的。 这里的时间精度单元可以module,interface,pkg和program。
举例说明,例如仿真的testbench设置的timescale值为1ps/1ps, 则uvm_pkg的timescale 值为1ns/1ps, 在testcase中做如下配置。
time timeout_value=1us;
uvm_root::get().set_timeout(timeout_value);
那么在testcaes中,timeout_value变量的值是1us/1ps =1000000,只是单纯的数字值; uvm_root拿到该参数后,会根据自身的仿真步长1ns,持续1000000个仿真步长后停止仿真,所以在uvm_pkg,停止仿真的时间就变成了1000000*1ns = 1ms;
timescale的思考
对于仿真器而言,timescale声明的作用范围和宏很像。 如果单元文件前面有`timescale 的声明,则仿真器在编译(xmvlog)的时候会为其添加timescale 的编译信息。 现在来看 如果一个文件此前都没有声明过`timescale , 则该文件单元的timescale 会被仿真器设为UN_SET。 如果当前文件未声明timescale,但是之前的文件声明了,则编译器沿用之前的timesacle.
简单来说`timescale 有点像一个宏。 如果该文件头有声明则会改写timescale , 如果没有声明,则沿用此前的声明。
如下图 的三个文件, 如果编译顺序是 1 , 2 , 3 则3个模块的timescale 都是1声明的 1ns/10ps , 如果编译2再编译1,3, 则2是UN_SET, 1,3是1声明的1ns/10ps.
解决方法
解决方法很简单,让timescale的值保持一致就可以了。需要注意的是,有时仿真器使用的是已经编译好的uvm_pkg lib文件,比如xrun 在命令行中加上-uvm选项,仿真器使用的就是提前编译好的uvm_pkg lib(默认仿真步长为1ns),这就有可能导致uvm_pkg的timescale和tb的timescale不一致。
在仿真时可以用$printtimescale 函数查看当前仿真域的timescale, 或者xrun支持-print_timescale选项,会在编译的时候打印出各个单元的timescale。
在确认仿真步长不一致后可以有以下方法:
1. 不用仿真器提前编译好的uvm_pkg lib ,手动编译uvm_pkg文件,在编译文件前设置好对应的timescale。
2. 在elabration 阶段,使用-timescale 选项为未声明timescale的单元添加默认的timescale。或者使用-override_timescale选项override某个单元的timescale。