Verilog系列:赋值过程中的不同延迟

在进行行为模型建模设计时,经常要在各种语句的估值过程中增加各种延迟用以模拟特定的时序行为,如果在赋值过程中延迟设置不合理,可能会得不到期望的结果.为此,本文从大家经常使用的三种赋值方式(连续赋值语句、过程语句中的阻塞赋值和非阻塞赋值)触发,针对具体的应用,以示例说明不同延迟在其中的应用.

0 概念

惯性延迟(Inertial Delay)考虑了电路中存在大量的分布电容,信号在电路中传输存在对电容充放电效应,当输入较小宽度的脉冲将会被滤除,即不允许所有宽度小于指定延迟的脉冲通过电路单元,那么能够让对应输出有变化的最小脉冲宽度即为惯性延迟,是所有的电子器件均存在的一种延迟特性,因此为了使器件对输入信号的变化产生响应,信号变化后要维持足够长的时间,在仿真过程中,该延迟用于模拟元件延迟。一般原语、门单元、开关单元、连续赋值等中的延迟在模拟时均为惯性延迟。

传输延迟(Transport Delay)一般为输入信号变化到对应输出信号变化经过的时间,不会对输入信号进行滤除处理,所以传输延迟是一种绝对延迟,这种延迟类似于物理传输线的延迟,在仿真中用于模拟连线延迟。

具体关于延迟的示例可参考之前已发的一篇总结:《惯性延迟(inertial delay)和传输延迟(transport delay)》

1 连续赋值语句

连续赋值语句一般用于驱动线网,常用于连线.连续赋值语句中的延迟一般用于模拟赋值语句RHS的变化经过多长时间传递到LHS.一般连续赋值语句中设置延迟有以下几种方式:

  • 在线网声明时指定.在该种情形下,任何给该线网赋值的语句中,任何值变化都要等待指定的延迟时间后才能将值赋予给该线网,其特点是使用该线网的语句都会受到该延迟值的影响.

【示例】

【仿真结果】

从仿真结果可以观测到,在线网声明中指定延迟后,当输入信号宽度小于指定的延迟值时,该输入信号将不能传递到输出端。

  • 在具体的连续赋值过程中指定延迟:延迟时间在LHS设定,用于指定RHS值变化体现到LHS需要延迟的时间;

【示例】

【仿真结果】

从仿真结果可以观测到,在连续赋值语句中指定延迟后,当输入信号的宽度小于指定的延迟值时,该输入信号将不能传递到输出端,此时输出端表现为不定态。

  • 以上两种延迟方式的组合,即在线网声明和连续赋值语句中同时指定延迟,此时当输入信号宽度大于等于指定延迟中最大的延迟时将可以传递到LHS

【示例】

【仿真结果】

【示例】

注:此例与上例延迟值进行了交换。

【仿真结果】

通过上述两个示例的仿真结果可以观测到,当线网声明和连续赋值的过程中都是指定了延迟,且输入信号的宽度小于指定延迟中最大的延迟值时,连续赋值表达式中的RHS将不能传递到LHS。如果RHS能够传递到LHS,此时输出至LHS的信号相对于输入信号的延迟为声明和赋值过程中指定的延迟之和。另外,这里需要注意,在连续赋值语句中,延迟值只能在赋值语句的左侧出现,不能出现在右侧,如下式指定的延迟是错误的:

【示例】


通过上述几个示例还可以得到以下结论,当指定延迟后,在延迟的过程中输入发生多次变化时,连续赋值的最终结果按照如下规则确定:

  • 解析RHS表达式;

  • 如果重新解析的RHS的值与当前将要发送给LHS的值不同,那么当前将要发送给LHS的值的事件将会被取消,而被重新解析新的RHS值的事件替换;

  • 如果重新解析的RHS的值与当前将要发送给LHS的值相同,那么当前事件队列将会保持不变,即原有已经安排将要发送给LHS的值不会被更新;

  • 如果重新解析的RHS的值与当前将要发送的LHS的值不同,且赋值过程中指定了延迟,那么原有的事件队列中将要发送给LHS值的事件将会被替换,并且延迟值也将重新开始延迟;

由此可见,当有新的事件发生时,原有的旧事件将会被更新,连续赋值并不具备事件队列等候的特征。因此,连续赋值结构经常被用来模拟惯性延迟的行为。

2 阻塞赋值语句

阻塞赋值语句在顺序结构(begin-end)中,其后的语句执行将发生在阻塞语句执行完之后,但是在并行结构(fork-join)中,阻塞赋值语句与其前后的语句是并行执行的。在过程语句结构中使用的阻塞赋值语句中经常也需要增加延迟用于模拟特定的仿真行为,常见的增加延迟的方式有如下两种:

  • 延迟出现在赋值语句左侧,即延迟位于LHS

  • 延迟出现在赋值语句右侧,即延迟位于RHS

【示例】延迟出现在赋值语句左侧,即延迟位于LHS

【仿真结果】


in1第一次发生变化时,进程被触发.此时"#`DLY {co,sum} = in1+ in2 +ci;"相当于"#`DLY;{co,sum} = in1 + in2 +ci;",即需要等待DLY个时间单位后才执行后续的阻塞赋值,又因为该赋值方式为阻塞赋值,所以触发的进程只有阻塞赋值执行完毕后才向下进行.在等待DLY个时间单位的过程中,"in1,in2,ci"都发生了变化,因为发生变化的过程中阻塞赋值还并未执行,当阻塞赋值执行时,"in1,in2,ci"都更新为最新的值,所以最终进行计算的值是"in1='hf,in2='h3,ci='b1".

【示例】

【仿真结果


从上述仿真中可以观测到,test1与上例中test仿真结果相同,主要是因为两个模块中的阻塞赋值都发生在DLY个时间单位延迟之后.test2中,in1发生变化后always进程触发,执行到“{tmpo,tmp} = in1 + in2 +ci;”时,其中的“{tmpo,tmp}”的值立即被更新。下一行的执行过程相当于先进行DLY个时间单位的延迟,在这DLY个时间单位延迟的过程中虽然in1in2ci发生变化,但是{tmpo,tmp}在进程开始时已经执行完毕,即{tmpo,tmp}不会被更新,所以test2实际计算的时刻是in1第一次发生变化的时刻。

【示例】延迟出现在赋值语句右侧

【仿真结果】

为了分析方便,延迟出现在RHS的结构“lhs_sig = # delay_value rhs_sig;”可以理解为“tmp_value=rhs_sig;#delay_value;lhs_sig=tmp_value;.in1第一次发生变化时,进程被触发,此时 {cosum}=#`DLYin1 + in2 + ci”相当于“{tmpotmp}= in1 + in2 + ci#`DLY{cosum}={tmpotmp}”,即“in1 + in2 + ci”在进程第一次触发时就立即经过计算赋值给了临时变量“{tmpotmp}”,之后需要等待DLY个时间单位后才执行后续的阻塞赋值。在等待DLY个时间单位的过程中,虽然“in1in2ci”都发生了变化,但是其变化不会影响已经执行的“{tmpotmp}= in1 + in2 + ci”,所以最终赋值的结果为第一次进入进程时in1in2ci计算的值。test1test2过程与test分析类似,此处不再赘述。

3 非阻塞赋值语句

非阻塞赋值与阻塞赋值最大的不同之处在于其执行并不阻塞进程当执行。也因为这个特点,Verilog本身对于两者的处理机制也存在不同,特别是在赋值过程中延迟的处理方式上。在对应的进程触发后,非阻塞赋值过程一般可以分为两部分理解:

  • 解析RHS表达式并且将赋值操作排在non-blockingassign update event队列的最后;

  • 当前时间槽最后non-blockingassign update event被激活,仿真器更新LHS

与阻塞赋值中延迟出现的位置类似,非阻塞赋值过程中延迟出现的赋值过程中的位置也分为LHSRHS两种,以下示例说明。

【示例】延迟出现在赋值语句左侧

【仿真结果】

in1第一次发生变化时进程触发,进入begin-end后等待DLY个时间单位,在这DLY个时间单位的等待过程中,“in1in2ci”的值发生了变化,但是发生变化的过程中并没有执行到“#DLY”个时间单位后的非阻塞赋值语句,也即非阻塞赋值语句的RHS并没有解析执行,那么在DLY个时间单位后开始执行非阻塞赋值语句,此时按照非阻塞赋值语句执行的两步进行,第一步,对RHS进行解析,此时RHS中“in1in2ci”的值并不是in1第一次发生变化时的值“in1='hain2='h0ci=0”,而是“in1='hfin2='h3ci=1”,所以此时计算的值为仿真所示结果。

【示例】延迟出现在赋值语句右侧

【仿真结果】

in1第一次发生变化时触发always进程,“{co,sum} <= #`DLY in1 + in2 +ci;”的非阻塞赋值RHS解析,解析结果作为输出在DLY个时间单位后输出至LHS,解析结果将存放在一个队列中(non-blocking assign update events queue)中。另外因为非阻塞赋值不阻塞进程的执行,所以解析结果存放到队列中后将继续向下运行直到当前进程最后。此时,in2发生变化再次触发always进程,“{co,sum} <= #`DLY in1 + in2 +ci;”的非阻塞赋值RHS解析,解析结果将作为输出在DLY个时间单位后输出值LHS,解析结果依然存在队列中等待执行,后续in1ci发生变化的处理过程类似。所有的解析结果都会存放在解析结果的队列中等待执行。当in1第一次变化的延迟时间到了之后,第一次压入解析结果队列中的解析结果将被取出输出至LHS,后续的解析结果也将在其对应的延迟等待时间到了之后顺序从队列中取出并且输出至LHS。其中存放解析结果的队列实际上就是Verilog层次化事件队列中指的non-blocking assign update events queue。通过上述仿真可以观测到,非阻塞复制的这种行为类似于传输延迟的行为,即输入将在指定延迟后输出,通过分析也可以知道,当缓存较多内容时,可能会影响仿真器的仿真速度。

4 总结

在任何的过程语句或者行为建模中,尽量不要使用具体的延迟在赋值语句中,虽然在仿真时可能能够模拟出具体的硬件行为,但是这些延迟在物理综合的过程中是不支持的(将会被综合掉),并且很有可能导致综合后结果与行为仿真时不一致,但是在实际的仿真环境构建过程中,恰当的使用延迟,往往可以构建出期望的时序激励。因此,在实际的设计和验证过程中,正确使用延迟可以避免一些不必要的错误。

全部评论

相关推荐

KPLACE:首先是板面看起来不够,有很多奖,比我厉害。项目要精减,大概详细描述两到三个,要把技术栈写清楚,分点,什么算法,什么外设,怎么优化,不要写一大堆,分点,你写上去的目的,一是让别人知道你做了这个知识点,然后在面试官技术面的时侯,他知道你会这个,那么就会跟你深挖这个,然后就是个人评价改为专业技能
点赞 评论 收藏
分享
01-07 07:54
已编辑
门头沟学院 前端工程师
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务