好,在前面铺垫了八篇文章之后,终于来到了这个专栏里最想讨论的地方了。
为什么好好地要在探究异步逻辑的专栏中讨论起随机的事情了呢?因为想聊一聊对跨异步模块的仿真随机问题。这个问题本身是一个挺庞大的话题,而我也没有太多的经验因此主要以探究和谈论为主。说到对跨异步模块和逻辑进行功能仿真,很多地方都提到了在模块里引入随机延时的思路,这个思路没有什么问题但是引入的随机却很容易让我们掉坑里。
在验证环境中我们见得最多的随机函数有两个:$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
endpower是输入接口,每当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有相近的性质,也无法解决问题。
所以在静态模块中怎么构造我们需要特性的随机方法呢?
系列文章入口——
【芯片设计】SoC 101(一):绪论 | 【芯片设计】FIFO漫谈(零)从无处不在的FIFO开始说起 | 【芯片设计】计算机体系结构(一)虚拟内存 | 【芯片设计】深入理解AMBA总线(零)绪论
| 【芯片设计】握手协议的介绍与时序说明 | 【芯片设计】复位那些小事 —— 复位消抖 | 【芯片设计】快速入门数字芯片设计(一)Introduction | 【芯片验证】UVM源码计划(零)下定决心读源码前的自测环节
| 【芯片设计】异步电路碎碎念(一) 到底什么是异步电路
| 【芯片设计】从RTL到GDS(一):Introduction
| 其他文章链接——
【芯片验证】sva_assertion: 15道助力飞升的断言练习 | 【芯片验证】可能是RTL定向验证的巅峰之作 | 【芯片验证】RTL仿真中X态行为的传播 —— 从xprop说起 | 【芯片验证】年轻人的第一个systemVerilog验证环境全工程与解析 |
【芯片设计】verilog中有符号数和无符号数的本质探究
| 【芯片设计】论RTL中always语法的消失术 | 【芯片设计】代码即注释,注释即代码 | 【芯片设计】700行代码的risc处理器你确实不能要求太多了 |
入职芯片开发部门后,每天摸鱼之外的时间我们要做些什么呢 | 如何计算系统的outstanding 和 burst length? | 芯片搬砖日常·逼死强迫症的关键词不对齐事件 | 熟人社会里,一群没有社会价值的局外人 |
|