上一篇文章中对两个典型的随机方法在静态对象中的随机特性进行了探究:
【芯片验证】异步电路碎碎念(九)静态对象中的随机函数特性探究
在此基础上这一篇来讨论如何在静态对象内构建可控的随机方法。先把上一篇的结论拿出来:
1.纵向看,无论是$random还是$urandom都实现了随机功能,且每次随机值不同;
2.横向看,两个例化模块对比,$random每次随机的结果不同,而$urandom每次随机的结果相同;
3.以不同的种子进行仿真时,同一个例化模块,$random的随机结果每次都相同,而$urandom每次的随机结果是不同的;
再把我们的需求明确下:
1.随机数值是可控且可以复现的,不同的种子随机出不同的结果,相同的种子随机出相同的结果,这样可以充分覆盖随机场景,且出错后稳定可复现;
2.横向看,不同的比特(即每条异步走线路径)随机的结果不同,例如随机延迟时,每条路径的延迟本身就不同,如果随机结果一致那就没有意义了;
3.纵向看,单比特走线每次随机的结果不同,例如这次跳变随机恢复为正确值,下次随机恢复为错误值;
基于这两个表格,很容易想到一种比较容易实现的可控随机方法:$random+$urandom,既然你来都是有YES有NO,那两个加在一起不就都是YES了么!
多说无益,咱们来做一做实验看看吧,修改之前实验的RTL代码为:
reg [7:0]rand_value, urand_value;
reg [7:0]new_rand_value;
always @*begin
if(power)begin
rand_value = $random;
urand_value = $urandom;
new_rand_value = $random + $urandom;
//$display("----------------------------------------------");
//$display("%m rand_value = 'h%0h", rand_value);
//$display("%m urand_value = 'h%0h", urand_value);
$display("%m new_rand_value = 'h%0h", new_rand_value);
//$display("----------------------------------------------");
end
end仍旧以0/1234/5678三个种子进行三次仿真:tc seed = 0
testbench.u_rand_test1 new_rand_value = 'hbd
testbench.u_rand_test0 new_rand_value = 'h9f
testbench.u_rand_test1 new_rand_value = 'h6f
testbench.u_rand_test0 new_rand_value = 'hf4
testbench.u_rand_test1 new_rand_value = 'hec
testbench.u_rand_test0 new_rand_value = 'h1c
tc seed = 1234
testbench.u_rand_test1 new_rand_value = 'hd8
testbench.u_rand_test0 new_rand_value = 'hba
testbench.u_rand_test1 new_rand_value = 'h7
testbench.u_rand_test0 new_rand_value = 'h8c
testbench.u_rand_test1 new_rand_value = 'h37
testbench.u_rand_test0 new_rand_value = 'h67
tc seed = 5678
testbench.u_rand_test1 new_rand_value = 'h78
testbench.u_rand_test0 new_rand_value = 'h5a
testbench.u_rand_test1 new_rand_value = 'h24
testbench.u_rand_test0 new_rand_value = 'ha9
testbench.u_rand_test1 new_rand_value = 'ha0
testbench.u_rand_test0 new_rand_value = 'hd0通过观察这个结果不难得出结论,无论从时间维度、例化维度还是仿真种子的维度看,随机结果都是不同的,初步分析是可以满足我们的需求。再看看是否可以稳定复现,重新以seed=1234跑一下仿真看下:tc seed = 1234
testbench.u_rand_test1 new_rand_value = 'hd8
testbench.u_rand_test0 new_rand_value = 'hba
testbench.u_rand_test1 new_rand_value = 'h7
testbench.u_rand_test0 new_rand_value = 'h8c
testbench.u_rand_test1 new_rand_value = 'h37
testbench.u_rand_test0 new_rand_value = 'h67确实可以稳定复现随机的结果。从实验结果上看,$random+$urandom是能够满足我们的需求的。那么进一步对这个方法进行分析,从之前的特性上能够看出来,我们最常用的$urandom之所以不能满足需求是因为对于静态模块的不同例化体而言,同一回合的$urandom会随机出完全一样结果,可以理解为其不感知静态模块的多个例化实体。而此时以能够感知静态模块不同例化实体的$random作为补充把这个作为随机的“地基”引入到$urandom的结果上来,那么就填补了$urandom的“功能缺失”。而$random这个地基恰好又是在每个回合随机结果也不一样,缺失是对于不同的seed同样的模块中随机结果一致,这也没关系,$urandom补充了这个功能上的问题。这样以$random和$urandom互为补充的方式,满足了我们构造可控随机的需求,同样这两个函数的其他组合方式也是可以的,比如$random*$urandom:tc seed = 0
testbench.u_rand_test1 new_rand_value = 'h3c
testbench.u_rand_test0 new_rand_value = 'h34
testbench.u_rand_test1 new_rand_value = 'h7a
testbench.u_rand_test0 new_rand_value = 'he4
testbench.u_rand_test1 new_rand_value = 'h53
testbench.u_rand_test0 new_rand_value = 'h23
tc seed = 1234
testbench.u_rand_test1 new_rand_value = 'hd7
testbench.u_rand_test0 new_rand_value = 'ha5
testbench.u_rand_test1 new_rand_value = 'h32
testbench.u_rand_test0 new_rand_value = 'h94
testbench.u_rand_test1 new_rand_value = 'h22
testbench.u_rand_test0 new_rand_value = 'h2
系列文章入口——
【芯片设计】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? | 芯片搬砖日常·逼死强迫症的关键词不对齐事件 | 熟人社会里,一群没有社会价值的局外人 |
|