作者简介
尼德兰的喵,数字芯片前端,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 三个种子进行了三次仿真,仿真结果如下:
这样看起来并不是很直观,那么通过表格对三次仿真结果进行汇总:
先对单一仿真结果如 seed=4567 进行分析,将时间轴称之为纵向维度,将并行例化轴称之为横向维度:
观察仿真结果可以发现如下的特性:
1.纵向看,无论是$random 还是$urandom 都实现了随机功能,且每次随机值不同;
2.横向看,两个例化模块对比,$random 每次随机的结果不同,而$urandom 每次随机的结果相同;
之后观察三次仿真结果,进一步得出另外的特性:
3.以不同的种子进行仿真时,同一个例化模块,$random 的随机结果每次都相同,而$urandom 每次的随机结果是不同的;
将这三个结论汇总在表格上:
而在我们的需求是什么呢?让我们思考下,假设我们现在是对多比特信号进行跨异步的处理,在异步路径上我们对每个比特加入了随机延迟(或者在同步器出口亚稳态随机恢复为正确值或错误值),那么在通过验证环境进行仿真时,我们必然希望:
1.随机数值是可控且可以复现的,不同的种子随机出不同的结果,相同的种子随机出相同的结果,这样可以充分覆盖随机场景,且出错后稳定可复现;
2.横向看,不同的比特(即每条异步走线路径)随机的结果不同,例如随机延迟时,每条路径的延迟本身就不同,如果随机结果一致那就没有意义了;
3.纵向看,单比特走线每次随机的结果不同,例如这次跳变随机恢复为正确值,下次随机恢复为错误值;
因此最符合我们预期的特性应该是这样的:
那么显然,$random 和$urandom 都是不符合我们的需求的,$urandom_range(min, max)、std:randomize()甚至 randcase 都和$urandom 有相近的性质,也无法解决问题。所以在静态模块中怎么构造我们需要特性的随机方法呢?