关于时钟模块完备性验证方法第四章

系列文章目录


第四章 时钟相位检查



前言

之所以要进行时钟相位检查,是因为设计中经常会出现一些时钟具有固定相位关系的情况,比如说两个时钟同相位或者反相位,又或者两个时钟差一个高频时钟的相位等等。那么当系统运行过程中,随着各功能模块的启动,各个时钟运行起来后相位关系会变得错综复杂,尤其在时钟切换过程中,很有可能RTL设计缺陷导致某些时钟在切换频率或时钟源的过程中,相位关系不满足spec要求,因此本文提供了一个自动化check时钟相位关系的方法,不管系统中各个时钟如何变化,一旦该自动化checker运行起来,可以随时check各时钟之间的相位关系,当发生不满足spec要求时就会向testbench上报错误信息,及时发现设计缺陷。


提示:以下是本篇文章正文内容,下面案例可供参考

一、什么时钟相位?

总体来说,时钟相关关系有以下几种:

首先是同源同频同相位,即两个时钟之间属于同一个时钟源分频得到的,而且频率也相同,相位也相同,理论上来说可以认为是同一个时钟,只不过去了不同的模块,受不同的clk enable控制。

其次,同源非同频同相位,即两个时钟之间同于同一个时钟源分频得到的,但是频率不同,相位相同;

然后,同源非同频不同相位,即两个时钟之间属于同一个时钟源分频得到的,频率不同,且差1个或几个高频时钟相位。

至于非同源的时钟之间的相位关系,因为每次仿真run起来后相位关系是随机且不固定的,因此这里很难对其相位进行自动化检查,本文中我们只针对同源之间的时钟进行自动化检查。

二、使用步骤

1.自动化check代码代码如下:

代码如下(示例):

`define CLK_PHASE_CHECK(clk_1,clk_2,jitter_margin,sign) \
begin \
   real t_delta,t_clk_1,t_clk_2; \
   t_clk_1=0; \
   t_clk_2=0; \
   fork \
      begin \
         while(1)begin \
            #0.1; \
            if(clk_check_en==0)begin \
               break; \
            end \
         end \ //while
      end \ //first begin
      begin \
         while(1)begin \
            @(posedge clk_2); \
            t_clk_2 = $realtime; \
         end \
      end \//second begin
      begin \
         while(1) begin\
            wait(t_clk_2 > 0); \
            @(posedge clk_1); \
            t_clk_1 = $realtime; \
            t_delta = t_clk_1 - t_clk_2; \
            if(t_delta > jitter_margin) begin\
                err_num++;
            end \
         end \
      end \ //the third begin
   join_any \
   disable fork; \
end

2. 代码解析

首先是这部分代码的主体结构,如下

`define CLK_PHASE_CHECK(clk_1,clk_2,jitter_margin,sign) \
begin \
   real t_delta,t_clk_1,t_clk_2; \
   t_clk_1=0; \
   t_clk_2=0; \
   fork \
      begin \
         xxx;
      end \ //first begin
      begin \
         xxx;
      end \//second begin
      begin \
         xxx
      end \ //the third begin
   join_any \
   disable fork; \
end

 这部分主体代码建立了一个fork join的并行执行语句,当三个begin end语句中任意一个执行完毕后退出检查。这样做的目的是为了更好的控制整个flow,第一个begin end语句中我们添加了使能信号,当clk_check_en为0时,退出检查,这样可以在更上层testbench中随时使能或关闭,第二个begin end为实时上报clk_2的上升沿部分,第三个begin end为记录clk_1的上升沿时钟以及计算与clk_2上升沿的差值部分,通过计算两个时钟沿的差与设定的jitter_margin进行比较,当误差范围超过设定的偏差值时,向testbench上报频率检查错误。

 第三个begin end的算法结构如下:


begin \
   while(1) begin\
       wait(t_clk_2 > 0); \
       @(posedge clk_1); \
       t_clk_1 = $realtime; \
       t_delta = t_clk_1 - t_clk_2; \
       if(t_delta > jitter_margin) begin\
          err_num++;
       end \
   end \
end \ //the third begin
 

 即利用两个时钟沿的时钟做差值,这里需要注意,在调用该define时,上层传参需要根据两个时钟沿的先后情况进行传参,否则可能会现差值为负的情况,当然也可以根据实际应用对该checker做进一步优化,比如查看两个沿的绝对值来规避这个问题,但是需要注意两个沿之间的差大于半个周期或者更多的情况,因此最好最简单的方式就是在传参过程中,根据spec内容,来合理分配参数传递,才能更好的验证这部分功能。

`CLK_PHASE_CHECK(clk_24m_adc, clk_24m_dac, 0.2, "clk_adc and clk_dac phase check")

上图举例,假设系统中有两个同源同频的时钟,分别是clk_24m_adc,clk_24m_dac,因为是同频,所以这里传参不存在对应关系,可以是任意的,但是一旦两个时钟相位关系有先后,比如clk_24m_adc上升沿先到来,clk_24m_dac上述沿后到来,且相位差为一个192M的高频时钟周期,那么传参就需要按照下图进行

`CLK_PHASE_CHECK(clk_24m_dac, clk_24m_adc, 5.208, " adc clk first, dac last")

总结

通过宏定义的方式对检查进行主体建模,然后在验证bench中对所有待检查的时钟进行扩展建模,很大程度上减少代码的复杂度,使代码通俗易懂,易维护。同时,通过这种自动化的时钟相位检查,可以检查出任意时刻,当时钟相位不满足设定的目标值时随时向testbench上报错误信息,大大提高验证效率。

  • 28
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

love混世_魔王

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值