【优秀文章评选活动】静态对象中的随机函数特性(一)
专栏:IC技术圈官方 June 20, 2024, 11:16 p.m. 51 阅读
为什么会探究讨论下静态对象中随机的事情呢?因为多时钟域同步模块的随机仿真是一个在工程交付中常常隐藏 bug 的地方,所以希望对静态对象中构建可控随机进行讨论。而这个问题本身是一个挺庞大的话题,而我也没有太多的经验因此主要以探究和谈论为主。说到对跨异步模块和逻辑进行功能仿真,很多地方都提到了在模块里引入随机延时的思路,这个思路没有什么问题但是引入的随机却很容易让我们掉坑里。在验证环境中我们见得最多的随机函数有两个:$random 和$urandom,对于这两个函数在环境中的随机特性相信大家都是非常熟悉,并且牢记了应该用$urandom 进行随机而不要使用$random。但是一旦在静态对象中(环境是automatic 记得吧)比如 module、interface 中使用这两个函数,他们的特性就和在环境中不一样了。
作者简介
尼德兰的喵,数字芯片前端,ai与智驾赛道打工人。常年在csdn、知乎、稀土掘金、博客园、github、gitee等各大论坛与社区打地铺久住,公众号“芯时代青年”。

为什么会探究讨论下静态对象中随机的事情呢?因为多时钟域同步模块的随机仿真是一个在工程交付中常常隐藏 bug 的地方,所以希望对静态对象中构建可控随机进行讨论。而这个问题本身是一个挺庞大的话题,而我也没有太多的经验因此主要以探究和谈论为主。

说到对跨异步模块和逻辑进行功能仿真,很多地方都提到了在模块里引入随机延时的思路,这个思路没有什么问题但是引入的随机却很容易让我们掉坑里。在验证环境中我们见得最多的随机函数有两个:$random 和$urandom,对于这两个函数在环境中的随机特性相信大家都是非常熟悉,并且牢记了应该用$urandom 进行随机而不要使用$random。但是一旦在静态对象中(环境是automatic 记得吧)比如 module、interface 中使用这两个函数,他们的特性就和在环境中不一样了。

实验环境搭建

为了直观的总结特性,我先做了一个简单的模块,核心代码就是这样:

reg [7:0]rand_value, urand_value;
always @*begin
   if(power)begin
       rand_value = $random;
       urand_value = $urandom;
       $display("----------------------------------------------");
       $display("%m rand_value = 'h%0h", rand_value);
       $display("%m urand_value = 'h%0h", urand_value);
       $display("----------------------------------------------");
   end
end

power 是输入接口,每当 power 跳转为 1 时会分别进行一次$random 和$urandom 的随机并将随机结果打印出来。之后通过 auto_testbench 生成环境,并在环境中例化了两个 rand_test 模块:

rand_test
u_rand_test0(.power(power));
rand_test
u_rand_test1(.power(power));

而后在 testbench 驱动 power 信号,共使能 3 次:

logic power;
initial begin
    wait(sim_start === 1'b1);
    `DELAY(10, clk);
    power = 1'b1;
    `DELAY(1, clk);
    power = 1'b0;
    `DELAY(10, clk);
    power = 1'b1;
    `DELAY(1, clk);
    power = 1'b0;
    `DELAY(10, clk);
    power = 1'b1;
    `DELAY(1, clk);
    power = 1'b0;
   sim_finish = 1'b1;
end

实验环境搭建完成。

实验现象

为展示结果,分别以 seed=0/1234/5678 三个种子进行了三次仿真,仿真结果如下:

image.png

image.png

image.png

这样看起来并不是很直观,那么通过表格对三次仿真结果进行汇总:

image.png

image.png

image.png

特性分析

先对单一仿真结果如 seed=4567 进行分析,将时间轴称之为纵向维度,将并行例化轴称之为横向维度:

image.png

观察仿真结果可以发现如下的特性:

1.纵向看,无论是$random 还是$urandom 都实现了随机功能,且每次随机值不同;
2.横向看,两个例化模块对比,$random 每次随机的结果不同,而$urandom 每次随机的结果相同;

之后观察三次仿真结果,进一步得出另外的特性:

3.以不同的种子进行仿真时,同一个例化模块,$random 的随机结果每次都相同,而$urandom 每次的随机结果是不同的;

将这三个结论汇总在表格上:

image.png

而在我们的需求是什么呢?让我们思考下,假设我们现在是对多比特信号进行跨异步的处理,在异步路径上我们对每个比特加入了随机延迟(或者在同步器出口亚稳态随机恢复为正确值或错误值),那么在通过验证环境进行仿真时,我们必然希望:

1.随机数值是可控且可以复现的,不同的种子随机出不同的结果,相同的种子随机出相同的结果,这样可以充分覆盖随机场景,且出错后稳定可复现;
2.横向看,不同的比特(即每条异步走线路径)随机的结果不同,例如随机延迟时,每条路径的延迟本身就不同,如果随机结果一致那就没有意义了;
3.纵向看,单比特走线每次随机的结果不同,例如这次跳变随机恢复为正确值,下次随机恢复为错误值;

因此最符合我们预期的特性应该是这样的:

image.png

那么显然,$random 和$urandom 都是不符合我们的需求的,$urandom_range(min, max)、std:randomize()甚至 randcase 都和$urandom 有相近的性质,也无法解决问题。所以在静态模块中怎么构造我们需要特性的随机方法呢?

 

感谢阅读,更多文章点击这里:【专栏:IC技术圈官方】