【芯片前端】仿真向/基于静态随机函数的单比特跨时钟同步器

简介: 【芯片前端】仿真向/基于静态随机函数的单比特跨时钟同步器

前言

因为后面我想做一些其他的实验,需要一个用于仿真的模拟亚稳态的单比特同步模块,需要满足几个需求:

1.在第一拍出发跨异步亚稳态,即发生信号跳变时,同步器第一拍的结果随机为0或者为1;

2.同步器例化多份,每一个inst亚稳态的恢复值随机,横向之间互相没有关系;

3.同一个inst,输入信号跳变,每次亚稳态恢复的值随机,纵向之间相互没有关系;

4.亚稳态恢复结果能够被seed控制,稳定复现;

其实这几个需求,核心还是之前在另外一个博文里探讨过的内容,如何在静态模块中做可控制的随机:

【验证小白】静态模块module/interface中的$urandom可控随机探索

这次实际是一次具体的使用吧。

代码

每次有信号跳变时,需要在RTL中触发一次随机,将同步器的第一拍输出随机为0或者1(实际就是把打三拍之后的亚稳态恢复值,聚在第一拍模拟完成)。

第一步,做用来产生随机数的function,思路就是另一篇博客中说的方式,通过%m来差异化每一个inst随机时的%urandom的种子;

1. /*for module random ctrl by seed*/
2. string   path_str;
3. initial  path_str = $psprintf(path_str, "%m");
4. 
5. function integer urandom_range(); 
6.     input integer min, max; 
7.     integer seed, i; 
8.     begin 
9.         seed = $urandom(); 
10.         for(i=path_str.len; i>=0; i=i-1)begin 
11.             seed = seed ^ path_str.getc(i); 
12.             seed = $urandom(seed); 
13.         end
14.         urandom_range = min + $abs(seed % (max - min));
15.     end 
16. endfunction
17. /*end*/

第二步,判定输入信号是否跳变,我的做法就是,在i_clk和o_clk分别做一个i_sync_ff(i_sync_ff为实际的跨异步信号)的打拍i_sync_ff1/o_sync_org0,当i_sync_ff与i_sync_ff1保持一致或i_sync_ff与o_sync_org0保持一致时就认为i_sync_ff稳定了足够长的时间,不会触发亚稳态的问题(分别对应快转慢和慢转快);

1. reg o_sync_org0;
2. always @(posedge o_clk or negedge o_rst_n) begin
3.     if(o_rst_n == 1'b0)begin
4.         o_sync_org0 <= 1'b0;
5.     end
6.     else begin
7.         o_sync_org0 <= i_sync_ff;
8.     end
9. end
10. wire i_sync_hold = (i_sync_ff1 == i_sync_ff0) | (o_sync_org0 == i_sync_ff0);

第三步,在判定信号跳变时,触发亚稳态问题以及随机恢复;

1. reg o_sync_ff0;
2. always @(posedge o_clk or negedge o_rst_n) begin
3.     if(o_rst_n == 1'b0)begin
4.         o_sync_ff0 <= 1'b0;
5.     end
6.     else begin
7.         if(i_sync_hold)begin
8.             o_sync_ff0 <= i_sync_ff;
9.         end
10.         else begin
11.             if(urandom_range(1,10) >= 5)begin
12.                 o_sync_ff0 <= ~i_sync_ff;
13.             end
14.             else begin
15.                 o_sync_ff0 <= i_sync_ff;
16.             end
17.         end
18.     end
19. end

第四步,把o_sync_ff0再打两拍,作为同步器的最终输出;

1. reg o_sync_ff1, o_sync_ff2;
2. always @(posedge o_clk or negedge o_rst_n) begin
3.     if(o_rst_n == 1'b0)begin
4.         o_sync_ff1 <= 1'b0;
5.         o_sync_ff2 <= 1'b0;
6.     end
7.     else begin
8.         o_sync_ff1 <= o_sync_ff0;
9.         o_sync_ff2 <= o_sync_ff1;
10.     end
11. end
12. 
13. assign o_sync     = o_sync_ff2;

第五步,把o_sync_org0也打两拍输出,作为完全没有亚稳态情况下的参考输出;

1. reg o_sync_org1, o_sync_org2;
2. always @(posedge o_clk or negedge o_rst_n) begin
3.     if(o_rst_n == 1'b0)begin
4.         o_sync_org1 <= 1'b0;
5.         o_sync_org2 <= 1'b0;
6.     end
7.     else begin
8.         o_sync_org1 <= o_sync_org0;
9.         o_sync_org2 <= o_sync_org1;
10.     end
11. end
12. assign o_sync_org = o_sync_org2;

第六步,搭一个简易定向验证环境,测一下各种功能是否能出现,这个就请参考下文吧:

【验证小白】编译、仿真与波形 —— 基于VCS的通用superbench平台搭建

OK,模拟亚稳态的单比特三拍同步器就完成了,仿真一下波形看看各种情况是否有触发;

波形

电平信号跳变为1时,亚稳态恢复为错误值,导致晚一拍采样到 1;

电平信号跳变为0时,亚稳态恢复为错误值,导致晚一拍采样到 0;

电平信号跳变为0时,亚稳态恢复为正确值;

电平信号跳变为1时,亚稳态恢复为正确值;

脉冲信号,被完全正确采样;

脉冲信号,跳变为1时亚稳态恢复为错误值0,跳变为0时亚稳态恢复为正确值0,亚稳态导致这个脉冲被吃掉了;

脉冲输入过窄,导致这个脉冲被吃掉了;

上升沿亚稳态恢复正常,下降沿恢复异常;

上升沿 恢复异常,下降沿恢复异常;

波形看着好像情况是比较完备的哈,我准备先用着如果后面发现问题再说吧~~~


相关文章
|
7月前
|
前端开发 芯片
【芯片前端】保持代码手感——握手协议ready打拍时序优化
【芯片前端】保持代码手感——握手协议ready打拍时序优化
|
7月前
|
前端开发 芯片
【芯片前端】延迟一拍出数的握手型ram结构的一次探索
【芯片前端】延迟一拍出数的握手型ram结构的一次探索
|
7月前
|
前端开发 芯片
【芯片前端】保持代码手感——一对多的握手拆分模块
【芯片前端】保持代码手感——一对多的握手拆分模块
|
7月前
|
前端开发 调度 芯片
【芯片前端】根据数据有效选择输出的握手型FIFO结构探究
【芯片前端】根据数据有效选择输出的握手型FIFO结构探究
|
7月前
|
前端开发 芯片
【芯片前端】关于set_input_delay/set_output_delay慢信号约束到快时钟的思考
【芯片前端】关于set_input_delay/set_output_delay慢信号约束到快时钟的思考
|
7月前
|
前端开发 芯片
【芯片前端】保持代码手感——握手型同步fifo的进一步拓展
【芯片前端】保持代码手感——握手型同步fifo的进一步拓展
|
7月前
|
前端开发 芯片
【芯片前端】保持代码手感——握手型同步FIFO设计
【芯片前端】保持代码手感——握手型同步FIFO设计
|
7月前
|
前端开发 芯片
【芯片前端】“异步FIFO全解析”的BUG——格雷码连续性
【芯片前端】“异步FIFO全解析”的BUG——格雷码连续性
|
7月前
|
存储 前端开发 芯片
【芯片前端】保持代码手感——异步FIFO全解析
【芯片前端】保持代码手感——异步FIFO全解析
|
7月前
|
前端开发 芯片
【芯片前端】保持代码手感——数据累加输出
【芯片前端】保持代码手感——数据累加输出