Verilog编程艺术(4)——第五部分 时钟和复位


Verilog编程艺术(4)

异步时序

异步时序设计的关键就是保证控制和数据信号正常地跨时钟域传输。

亚稳态

每一个触发器都有规定的建立时间(Setup)和保持时间(Hold)。
建立时间是指在时钟沿到来之前,输入信号必须保持稳定的时间。保持时间则是指在时钟沿到来之后,输入信号必须保持稳定的时间。在这个时间参数内,输入信号是不允许发生变化的。如果在这个时间参数内输入信号发生了变化,那么得到的结果将是不可预知的,这个状态就是亚稳态,既不是0状态,也不是1状态。

亚稳态产生的主要原因是:在触发器的采样窗口内,无法保证输入信号始终保持在一个稳定的电平上。为了解决亚稳态问题,我们可以通过减小采样窗口来增加采样成功率(例如,使用边沿触发器件替换电平触发器件,就是一种减小采样窗口的方法),或者通过移动时钟沿的采样窗口或移动输入数据的稳定窗口来保证采样成功。

综合工具虽然可以保证同步信号满足触发器建立与保持的时间要求,但是综合工具却不能判定异步信号是否满足触发器的时间要求。因为在一个跨时钟域的交界面上,外部发来数据的到达时间,根本不能与本地时钟产生什么必然的时序上关系,或者更确切地说,外部数据在本地输入端口的稳定时间与本地触发器的采样窗口在时序上没有必然的联系。因此造成了跨时钟域接口间的亚稳态问题。

MTBF

触发器进入亚稳态的时间可以用参数MTBF(Mean Time Between Failures)来描述,MTBF即触发器采样失败的时间间隔。

为了避免亚稳态问题,就应当使参数MTBF尽可能的大,通常采用的方法是双触发器法,即在一个信号进入另一个时钟域之前,将该信号用两个触发器连续锁存两次,最后得到的采样结果就可以消除亚稳态问题。

同步器

同步器基本上可分三种:电平同步、边沿检测和脉冲检测。

电平同步器是所有同步器电路的基础。在电平同步器中,跨时钟域的信号在新时钟域中保持高电平或低电平至少两个时钟周期,而且在信号再次变成有效状态之前,信号需要先变成无效状态。每一次信号有效时,接收逻辑都会把它看做单个事件,而不管信号保持有效状态有多长时间。
简单的电平同步器由两个触发器串联而成,中间没有其他组合电路。这种设计可以保证后面触发器使用前面触发器的输出时,前面触发器已经退出亚稳态,并且输出己经稳定。设计中要注意将两个触发器放得尽可能近,以确保二者之间有最小的时钟偏差(Clock skew)。

边沿检测同步器在电平同步器的输出端增加了一个触发器。新增触发器的输出经反相后和电平同步器的输出进行与(nd)操作,产生一个与时钟周期等宽的高电平有效的脉冲。如果将与门的两个输入端交换使用,就可以构成一个检测输入信号下降沿的同步器。如果将与门改为与非门,就可以构建一个产生低电平有效脉冲的电路。
当一个脉冲进入更快的时钟域中时,边沿检测同步器可以工作得很好。这一电路会产生一个脉冲,用来指示输入信号上升沿或下降沿。这种同步器有一个限制,即输入脉冲的宽度必须大于同步时钟周期与第一个同步触发器所需保持时间之和。最保险的脉冲宽度是同步器时钟周期的两倍。如果输入是一个单时钟宽度脉冲而且进入较慢的时钟域,则这种同步器没有作用。在这种情况下,就要采用脉冲检测同步器。

脉冲检测同步器的输入信号是一个单时钟宽度脉冲,它触发原时钟域中的一个翻转电路。每当翻转电路接收到一个脉冲时,它就会在高、低电平间进行转换,然后通过电平同步器输出的信号到达异或门的一个输入端,而这个输出的信号再经过一个时钟周期的延迟进入异或门的另一端,翻转电路每转换一次状态,这个同步器的输出端就产生一个单时钟宽度的脉冲。
脉冲同步器的基本功能是从某个时钟域取出一个单时钟宽度脉冲,然后在新的时钟域中建立另一个单时钟宽度的脉冲。脉冲同步器也有一个限制,即输入脉冲之间的最小间隔必须等于两个同步器时钟周期。如果输入脉冲相互过近,则新时钟域中的输出脉冲也紧密相邻,结果是输出脉冲宽度比一个时钟周期宽。当输入脉冲时钟周期大于两个同步器时钟周期时,这个问题更加严重。这种情况下,如果输入脉冲相邻太近,则同步器就不能检测到每个脉冲。

同步多位数据

同步多位数据不能使用多位电平同步器,也不能使用脉冲同步器多位控制位。
同步多位数据应该按照下面的步骤进行。

1.确保in data在传送期间不会发生改变,所以尽量采用寄存器输出。
2.使用脉冲检测同步器,传送in clk域的脉冲in pulse到out_clk域的out pulse,通知多位数据in data已经准备好。
3.在out clk域检测到out pulse之后,才把in data直接锁存到out data中。

异步FIFO

数据在时钟域之间传递,虽然可以使用握手控制信号的方法,但是存在很大的缺点,就是在传送每一个数据的时候,传递和识别握手信号需要很大的延迟,性能很不好。

最流行的用于时钟域之间传递数据的方法是异步FO。双端口的内存用于FFO保存数据,一个端口由发送者控制,用于放入数据,另一个端口由接收者控制,用于取出数据。发送者和接收者各自维护一套FIFO的状态:empty、almost empty、half、almost full和full,然后根据状态进行存取数据的操作。
FFO的状态是由读指针(接收者)和写指针(发送者)之间的运算和比较决定的。问题是这两个指针分别处于不同的时钟域,不能在一个时钟域直接使用另一个时钟域的指针,所以在计算和比较之前,需要把这两个指针同步到对应的时钟域。
简单地直接把二进制的指针从一个时钟域锁存到另一个时钟域,这样是有问题的。例如写指针当前位置是4’b0111,把它同步到接收者的时钟域,在接收者锁存的时候,如果写指针变为4’b1000,那么接收者实际锁存到的值可能是4’0000~4b’1111之间的任意一个,因为在锁存时每一位都在变化着。
为了解决同步指针的问题,就要使用格雷码传递指针。因为对格雷码每次做加1或减1操作时只能改变其中的一位,所以对格雷码使用同步器,格雷码的每次改变只会导致一根信号线发生改变。于是就消除了数据通过同步器时的错误情况。在传递指针时,要把二进制的指针变换到格雷码的指针并保存到寄存器中,在新时钟域同步后,再把格雷码的指针变换到二进制的指针,最后计算比较生成FIFO的状态。
在实际使用异步FIFO时,我们要严格根据FIFO的状态存取数据,不要出现上溢(Overflow)和下溢(Underflow)的错误。

Design Ware

Synopsys Design Ware已经提供了很好的跨时钟域解决方案。这些方案应用简便,设计人员只需知道它们的工作原理,知道在什么时候应用它们即可。这些方案包括如下:

l.基本同步:DW_sync。
2.I临时事件同步:DWpulse_sync,DW_pulseack_sync。
3.复位排序:DW_reset_sync。
4.简单数据传输同步:DW_data_sync、DW_data_sync_na、DW_data_sync_lc。
5.相关时钟系统数据同步:DW data_qsync_hl、DW_data_qsync_lh。
6.数据流同步:DW_fifo s2sf、DW_fifo_2c_df、DW_stream_sync。

门级仿真

信号在通过同步器穿越时钟边界的时候,可能要违反Setup和Hold时间的要求。这就是在设计中加入同步器的原因,就是要把亚稳态过滤掉。

ASIC库中的触发器为了符合实际触发器的时间要求,要用Setup和Hold时间的表达式做模型。在违反Setup和Hold时间要求的时候,触发器一般会在输出端驱动出不定态(X,Unknown)。

在对同步器做门级仿真的时候,Setup和Hold时间的违反会导致ASIC库输出Setup和Hold时间错误的信息,同时在违反的信号上输出X值。这些X值就会传播到设计的其他部分,从而导致整个设计的门级仿真出现问题,使仿真不能再进行下去。


时钟生成

如果说总线互连(Bus Matrix)是系统的骨架,CPU是系统的大脑,那么时钟生成模块(CGM)就是系统的心脏,整个系统就是在时钟的脉搏下有序协调地工作。
我们在设计时钟生成模块时,我们需要考虑下面这些问题。

  1.芯片需要多少个时钟?它们之间的关系是同步的还是异步的?
  2.芯片需要几个时钟源?时钟源是在芯片内还是在芯片外?
  3.需要使用PLL吗?需要几个PLL?PLL最高工作频率是多少?
  4.如何分频生成各个模块所需要的时钟频率?
  5.为了节省功耗需要几种工作模式?它们之间如何切换?
  6.测试模式下如何处理时钟信号?综合时如何插入扫描链?
  7.代码如何编写才能方便后端做时钟树综合?后端如何做时钟树综合?

同步电路

同步电路,就是电路中所有受时钟控制的单元,如触发器或寄存器,由一个或几个全局时钟控制。
同步电路的首要问题是时序收敛问题,就是要保证触发器的输入端和时钟端之间要满足Stup和Hold时间要求,否则就会出现亚稳态,就会导致电路不能正常工作。时序收敛工作都是由EDA工具自动完成的,只要设置合理的时间约束,综合及布局布线工具就可以实现时钟平衡,时序分析工具就可以检查电路是否满足时序收敛。所以同步电路具有如下的优点。

1.EDA工具可以保证电路系统的时序收敛,有效地避免了电路设计中的竞争条件。
2.因为触发器只在时钟有效沿才改变取值,所以很大限度地减少了整个电路受毛刺和噪声
的影响。
同步电路并不是没有缺点,它的最主要问题就是时钟偏差(Clock skew)和功耗问题。

由于时钟信号到达每个触发器时钟端口的连线长度不同,驱动单元的负载也不同,这就导致了时钟信号到达每个触发器时钟端口的时间也不同,这就是时钟偏差。时钟偏差的后果很严重,它会导致Setup或Hold的时间不能满足。当违反Setup时,还可以通过降频让芯片工作;当违反Hold时,芯片根本就不能正常工作。解决时钟偏差的方法就是采用EDA工具进行时钟树综合。它的原理就是按照时钟树的最大长度去平衡其他的时钟路径。但是,它会导致大量延迟单元的插入,使得电路的面积和功耗大量地增加。
另外,同步电路还受时钟抖动(Clock jitter)的影响。时钟抖动就是时钟周期在不同的时间段并不相同,变来变去。

设计原则

下面是设计时钟生成模块(CGM)时要遵循的一些原则。

1.CGM要独立于系统的其他模块,其他模块所用时钟都要从CGM中引出。
2.CGM要有很好的层次结构,便于前端定义时钟和分析时序,便于后端做时钟树综合。
3.为了调整性能和降低功耗,CGM应该支持分频器和停时钟,而且软件能够灵活控制。
4.在时钟切换和启停时钟时,一定不能出现毛刺,否则电路不能正确工作。

分频器

在一个系统里,各个模块可能需要不同的工作频率,这就需要通过PLL把时钟源的频率提高到高频率,然后通过不同的分频器为每个模块分出不同的工作频率。分频器可以分为以下几种类型。

1. 1/n:sre clk和dst clk之间的周期关系是1/1、1/2、1/4、1/8、1/16、1/32…,分母始终是2的n次方。
2. 1/x:sre_clk和dst clk之间的周期关系是1/1、1/2、1/3、1/4、1/5、1/6,分母可以是任意整数。
3. 1/s:sre cll和dst clk之间的周期关系是1/1、1/2、1/3、1/4、1/5、1/6…,分母可以是任意整数。1/s和1/x是相同的,只不过1/s的sre clk和dst clk还有同步关系,还要产生一个dst clk en。例如,对于ARM926EJS,我们就要使用1/s分频器,生成ARM CLK、HCLK和HCLKEN信号。
4. n/d:sre clk和dst clk之间的周期关系是3/25、67/325…,它们之间是分数关系(小于等于1/2的分数),用于生成一些特殊的频率。例如,从96MHz使用106/345分频出29.4912MHz
(=1.8432MHz*16,用于UART)

注:书中此处的 1/n 分频器例子值得复现。

对于/d分频器,实现起来有一定的技巧,要使用吞脉冲的方法。例如,我们要实现7/68分频,68=97+5,即商为7,余数为5。
这样对于9/68分频,可以看成5个8分频和4个7分频,即9/68=9/(5
8+4*7)。这个7分频和8分频中的数字7和8就是从商中得出来的。那5个8分频和4个7分频中的数字5和4就是从余数中的出来的,5是余数,4是(9-5)。
我们得出了5个8分频和4个7分频可以实现这个分数分频,但这5个8分频和4个7分频怎么放置呢?先放5个8分频,再放4个7分频,这样绝对是不行的。为了均匀地放置这两种频率,我们可以使用小数分频中的一种方法。找个临时变量temp,初始化为0。每次分频完让它加上余数,判断是否大于分子,如果小于分子,则输出7分频,否则输出8分频,并且将这个值减去分子(让它小于分子)。这样temp值就变成了5、1、6、2、7、3、8、4、0、5。


复位设计

复位一般分为异步复位和同步复位两种。不管异步复位还是同步复位都有明显的优点和缺点,在实际的设计中可以有效地使用任何方法。但是当选择一种复位方法的时候,就应该仔细考虑与这种方法相关的问题,然后做出明智的设计决定,这是非常重要的。

下面就是关于复位设计的总结。

1.正确使用同步复位和异步复位可以保证可靠的复位起效。
2.虽然异步复位对复位电路是一个安全可靠的方法,但是如果处理不正确,那么复位撤销就会导致明显的问题。
3.正确使用异步复位的方法是增加复位同步器,保证同步复位撤销,从而让正常设计的功能得到安全的恢复。
4.只要异步复位在测试期间是可控的,那么可以对异步复位做DFT。、
5.不管是同步复位还是异步复位,这里描述的分布式寄存器树是值得设计者考虑的,因为分布式寄存器树方法可以消除许多与buffering、timing和layout相关的问题。  

注:简单的复位不存在!


参考

[1] 《Verilog 编程艺术》 魏家明 编著
[2] 个人博客地址

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Verilog编程艺术是指在Verilog硬件描述语言中写出高质量、高效的代码的技巧和实践。下面是一些Verilog编程艺术的建议: 1. 模块化设计:将设计划分为多个模块,每个模块负责不同的功能,使代码结构清晰,并且便于维护和重用。 2. 规范命名:使用有意义的名称来命名信号、模块和变量,以增强代码的可读性和可维护性。 3. 注释:添加详细的注释,解释代码的意图、功能和特殊考虑事项。这有助于他人理解和修改你的代码。 4. 仿真测试:使用仿真工具来验证设计的正确性。编写全面的测试用例,覆盖各种情况和边界条件。 5. 时序规范:确保在设计中正确处理时序问题,包括时钟边沿、时钟交叉、同步复位等。 6. 避免多驱动冲突:确保每个信号只有一个驱动器,避免多个驱动器之间产生冲突。 7. 优化资源利用:使用合适的Verilog语法和技巧,以减少硬件资源的使用,并提高设计的性能和功耗。 8. 灵活使用生成语法:使用generate语法和宏定义来实现可复用的硬件设计,从而简化代码和提高模块的灵活性。 9. 良好的布局和格式:对代码进行良好的缩进、对齐和分组,以提高代码的可读性和可维护性。 10. 不断学习和改进:跟随Verilog的最新发展,学习新的技术和技巧,不断改进自己的编程能力。 希望这些建议对你在Verilog编程中有所帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值