[sv] timescale

在验证仿真过程中,很多人遇到过timescale的问题,其中典型的场景是这样的:“验证环境里加了一个#200ns的延时,希望通过这样带有明确单位的延时,避免timescale设置不同而导致不同的结果;可是奇妙是就是在设置timescale为1ns/1ps和100ps/1ps时,实际的延迟就成了200ns和2000ns,而把#200ns改为#200后,反而无论怎么改timescale,实际延迟都是200ns。”(此案例使用的是vcs 2013)。

本文将详细分析timescale,复现此案例,同时说明如何正确使用timescale。

1 仿真时间的相对性和绝对性

仿真时间是由一系列延时累积起来的。

1.1 延时

没有单位的延时,比如#100,是相对的,实际延时取决于当前时间单位;有单位的延时,比如#100ns,则是绝对的。假设当前时间单位是1ns,则#100ns等价于#100;假设当前时间单位是100ps,则#100ns等价于#1000。

延时除了单位,还需要精度,它们分别对应time_unit和time_precision。对于1ns/1ps的time_unit/time_precision设置,#100.1234会被四舍五入为#100.123。

1.2 仿真时间

我们可以通过波形测量和log打印两种方式得到仿真时间,波形测量相对简单,这里只讨论log打印。

有三个系统函数可以得到当前仿真时间:$realtime返回64bit real类型时间数值,$time返回64bit整数,$stime返回32bt无符号整数。$time和$stime会对小数进行四舍五入,鉴于现在时钟频率越来越高,验证环境中只建议使用$realtime。

这三个函数都会按照当前的时间单位按比例缩放,这句话不好理解。换种说法,它们返回的都是延时相对值的累积。

比如对于下面代码(module、program、packages或interface中):

realtime vr_t
#100;
.….
#20.123ns;
vr_t=$realtime;

如果当前时间单位/精度是1ns/1ps,则vr_t=100+20.123=120.123(单位为ns);

如果当前时间单位/精度是100ps/10ps,则首先根据时间精度10ps将#20.123ns四舍五入为#20.12ns,再根据时间单位100ps换算为相对值#201.2,最后得到vr_t=100+201.2=301.2(单位为100ps)。

这就是仿真时间的相对性。相对仿真时间对我们来说意义不大,因为不同模块/线程的时间单位/精度可能是不一样的。为得到仿真时间的绝对值,就需要$timeformat和%t出场了;$timeformat影响%t和交互式输入的延时单位,我们只讨论使用%t打印时的情况。

SV标准中$timeformat的定义如图:

$timeformat四个参数分别对应%t的打印单位、精度、后缀和打印的最小位宽。

典型设置如:$timeformat(-9, 3, “”, 5)

那么此后的%t打印,将以ns为单位,小数点后3位的精度打印仿真时间。

回到上面的例子,当我们用:

$display(“time=%f”,vr_t);

打印时,会得到120.123(单位/精度是1ns/1ps)和301.200(时间单位/精度是100ps/10ps),这是相对时间,因为它们的单位不同。而当我们用

$display(“time=%t”,vr_t);

打印时,会得到120.123(单位/精度是1ns/1ps)和30.120(时间单位/精度是100ps/10ps),这是绝对时间,它们的单位都已被换算为ns。

用上述的$timeformat设置,再看两个例子(还是在module、program、package或interface中):

 上结果无论对于vcs还是xrun都是一样的。

整个仿真系统中,必须使用单一的时间单位,比如ns,来打印各模块/线程的绝对仿真时间,这样才不会造成时间错乱。因此需要正确设置$timeformat和%t,为仿真时间找一把尺子,而不是松紧带。遇到延时问题,先测试尺子准不准。测试尺子的标准就是绝对延迟,比如#100ns,如果确实延迟了100ns,尺子就没有问题(注是在module、program、package或interface中测试)。
 

$timeformat通常在公共打印组件中已经被设置好。如果$timeforma没有被调用过,这时%t打印的时间单位是所有timescale中的最小time precision,而不是time unit。

2 正确设置时间单位和精度

前面反复提到了时间单位和精度,在了解如何设置它们之前,首先要说一下compilation-unit scope。

2.1 compilation-unit scope

compilation-unit:一个或多个SV文件编译到一起的合集;compilation-unit scope就是这个合集的范围,通过$unit::访问compilation-unit scope中的元素。要更详细地解释compilation-unit scope有点难,因为SV标准说它是工具决定的。简单的可以认为除了module、program、package、interface、checker、primitive之外的SV文件,都会编译到一个compilation-unit scope中,比如全局的class、task、function和全局变量等,展开Verdi Declaration中的$root,就可以比较清晰的看到这种层次关系。


2.2 关键字timeunit/timeprecision

SV标准要求关键字timeunit/timeprecision只能定义在module、program、package、interface和compilation-unit scope中,并且必须定义在最前面。下面的使用是合法的:

module A (…);
  timeunit 1ns;
  timeprecision 1ps;
  ……
endmodule

下面的使用是非法的,不能在class/task/function等中:

class A;
  timeunit 1ns;
  timeprecision 1ps;
endclass

下面的使用,如果A是除module、program、package、inteface外,第一个编译的SV文件,则是合法的,否则是非法的。

timeunit 1ns;
timeprecision 1ps;
 
classA
  .……
endclass

2.3 编译指令`timescale

按照编译顺序,`timescale指定之后,下一个`timescale之前,不含有关键字timeunit/timeprecision的module、program、package和interface的时间单位和精度。

使用方式是`timescale time_unit/time_precision,例如:

`timescale 1ns/10ps
 
module A (…)
  timeunit 100ps;
  timeprecision 1ps;
endmodule
 
module B (…);
endmodule
 
`timescale 1ps/lps
 
module C (…);
endmodule

module A的时间单位/精度是100ps/1ps,module B的时间单位/精度是1ns/10ps,module C的时间单位/精度是1ps/1ps。

`timescale没有作用域的概念,比如:

`timescale 1ns/10ps
 
module B (…);
  `timescale 1ps/1ps
endmodule
 
module C (…);
endmodule

module B使用的是,在它之前离它最近的`timescale,因此时间单位/精度是1ns/10ps;而module C的时间单位/精度取离它最近的`timescale,即1ps/1ps。

2.4 编译选项-timescale

在vcs编译选项中添加-timescale=time_unit/time_precision(对于xrun是-timescale time_unit/time_precision),该选项指定仿真默认的时间单位/精度,等价于第一个`timescale。此后代码中出现的`timescale将会替换-timescale。

如里没有添加编译选项-timescale,代码中也没有出现任何`timescale,则vcs默认时间单位/精度是1s/1s,xrun默认时间单位/精度是1ns/1ns。

SV不允许有的横块有timescale,有的没有timescale,比如下面的代码:

module B (…)
endmodule
 
`timescale 1ps/1ps;
 
module C (…);
endmodule

如果编译选项没有添加-timescale,则是非法的。如果添加了-timescale=1ns/1ps,mooule B的时间单位/精度是1ns/1ps,moodule C的时间单位/精度是1ps/1ps。

2.5 编译选项-unit_timescale(仅vcs)

SV标准要求compilation-unit scope仅受关键字timeunit/timeprecision控制,`timescale不起作用,在没有timeunit/timeprecision时,compilation-unit scope使用默认的时间单位/精度。

为此VCS提供了-unit_timescale编译选项,compilation-unit scope的时间单位/精度优先级为:

a)当-unit_timescale和关键字timeunit/timeprecision同时存在时,使用关键字timeunit/timeprecision指定的时间单位/精度,无论-unit_timescale等于什么;

b)只有-unit_timescale选项时,使用-unit_timescale指定的时间单位/精度;

c)没有-unit_timescale选项时,无论是否存在关键字timeunit/timeprecision,都使用最后一个被使用的`timescale指定的时间单位/精度,这条与SV标准稍有区别。例如:

注意如果最后一个`timescale没有被module、program、package或interface使用,那么它将对compilation-unit scope不起作用,例如无-unit_timescale时:

`timescale 100ps/1ps
 
class A;
endclass
 
`timescale 10ps/1ps
 
module B(…);
endmodule
 
`timescale 1ns/1ps

class A的时间单位/精度是10ps/1ps,而不是1ns/1ps。

2.6 编译选项-override timescale

该选项强制覆盖所有的timescale。对于使用相对延时#xxx的模块,可以利用`timescale巧妙地增加或减小延迟时间,而不用修改任何代码,库文件和interface中可能会有这样的用法。如果使用了-overide_timescale,即使仿真结果对了,也是不真实的,因此应禁止使用。


2.7 打印timescale

有三种方式打印timescale(后两种仅限vcs),以方便调试:

  • 系统任务$printtimescale,打印当前模块的timescale;
  • 编译选项-diag timescale,加入该选项后,所有module、program、package和interface的timescale都会打印在编译log中;
  • 编译选项-Xman=12或28,加入该选项后,所有代码会被打印到token.v文件中,宏代码会展开:该选项本来为了方便宏调试,但它同时也会在每个module、program、package、interface和compilation-unit scope前,打印它们的timescale对应的文件和代码行号,比-diag timescale更进一步。
     

特别的,VCS在编译时,编译log也会打印出一个Timescale,它的时间单位/精度,分别对应整个系统中出现过的最小时间单位/精度,而并非具体哪一个`timescale。

3 compilation-unit scope特殊之处(vcs)

前面代码例子,都注明了是“mdule、program、package或interface”中的代码,这是因为vcs(实验较早,当时用的版本是2013.06)对compilation-unit scope的处理有特殊的地方。

如果编译时没有加-unit_timescale,那么compilation-unit scope中,绝对延时(比如#200ns)并不遵守上面的分析;相对延时(比如#200)依然遵守。
 

3.1 compilation-unit scope中的绝对延时

假设编译选项-timescale=10ns/1ps,下面的代码:

class A
  task aa;
    $printtimescale;
    harness.a=0;
    #200ns;
    harness.a=1;
    $display("%0t”,$realtime);
  endtask
endclass
`timescale 100ps/1ps
module harmess(…);
  bit a;
endmodule

$printtimescale打印出的timescale是100ps/1ps,没有问题。但是对于#200ns,vcs很神奇的先根据#200ns之前,高它最近的`timescale进行一次转换(如果在此之前没出现过`timescale,则使用-timescale),再使用默认的`timescale进行第二次转换。

比如此例中,编译选项中的-timescale=10ns/1ps,将它换算为#20。然后,再根据前文分析的compilation-unit scope的要默认时间单位/精度100ps/1ps,将#20换算为#2ns。
 

3.2 复现本文开头的例子

构造代码如下:

class A;
  task aa;
    #200ns;
    $dlisplay("aa: %0t, $realtime);
  endtask
  task bb;
    #200;
    $display(“bb: %0t; $realime);
  endtask
endclass
`timescale 1ns/1ps
module harness(…);
endmodule
  • 对于#200ns:

当-timescale=1ns/1ps时,由于默认时间单位/精度也是1ns/1ps,因此延时200ns;

当-timescale=100ps/1ps时,#200ns首先转换为#2000,再按照1ns/1ps的默认时间单位精度,转换为2000ns,因此无论使用%t打印还是波形直接测量,都是延时了2000ns。
 

  • 对于#200:

遵循前文分析,不受-timescale选项影响,直接使用默认时间单位/精度也是1ns/1ps,因此无论-timescale=1ns/1ps还是100ps/1ps时,都延时200ns。

注:本文初稿写的较早,因此不确定2013以后的vcs行为是否依然如此。由于-unit_timescale已经能够完美解决问题,所以也就没有再重复实验确认了。
 

4 timescale使用建议

  • 关键字timeunit/timeprecision只使用在需要不受`timescale影响的module、program、package或interface的内部;
  • 用vcs编译时应同时添加-timescale和-unit_timescale;对于xrun有更多的timescale选项,建议参考手册;但无论vcs还是xrun,都不应使用-override_timescale;
  • 验证环境顶层module声明前应设置`timescale,且和编译选项保持一致:
  • 如果rtl代码在非阻塞赋值前加了#DELAY延迟,则建议在代码最前面设置`timescale,以防止库文件篡改`timescale
  • 项目组统一设置$timeformat,并使用%t打印仿真时间,至于#100和#100ns,如果能够按照上面的建议,将timescale正确设置,比如常用的1ns/1ps,那么#100和#100ns就没有区别。
     


————————————————
版权声明:本文为CSDN博主「木头坛子」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_47782224/article/details/121365738

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值