FPGA设计-如何处理逻辑设计中的时钟域

<<FPGA设计实战演练(高级技巧篇)>>王敏志
<<数字设计原理与实践中文版 (Jpohn F. Wakerly) (2019)>>

在讨论跨时钟域问题前,先介绍一些基本概念。
MOS管用在数字电路上是工作在线性区,意味着触发器有进入界于1和0之间的第三种状态,及亚稳态;
同步器(synchronizer):对一个一部输入信号进行采样,并且产生的输出满足同步系统的建立时间和保持时间要求的电路;
同步器故障:如果一个系统在同步器的输出还处于亚稳态时,就使用这个输出信号,则称为同步器故障;
脱离亚稳态有俩种方法:
1)利用满足最小脉冲宽度、建立时间等规定的输入信号,迫使触发器进入一个有效的逻辑状态;
2)等待“足够长”的时间,以便触发器自己脱离亚稳态;
亚稳定性消解时间Tr:表示在不引起同步器(和系统)故障的情况下,输出会停留在亚稳态的最大时间,此时间不是保证触发器脱离亚稳态的时间,而是触发器还处于亚稳态,此时同步器出现故障的时间,Tr=Tclk-Tsetup-Tcomb;也叫亚稳态最大分辨时间,是指触发器能够保持亚稳态输出,并不会引起故障的时间(从时钟沿开始)。
判决窗(decision window):时钟边沿前的建立时间和边沿后的保持时间要求时间宽度;
快速时钟信号到低俗时钟域,信号的延拓要宽于低俗时钟的2.5倍(一个芯片设计时给我说的,不过个人觉得宽于1.5倍就行了);
打两拍的同步,芯片设计时,有人用第二级触发器的输出与第二级的触发器的输入再进行判断,如果值一样,那么输出,若值不一样,输出保持不变(那个芯片设计师给我说的);
那个芯片设计师的意思应该是,前级时钟域过来的信号要是后级时钟域的时钟2.5倍宽度,然后我们可以对于延展后的信号(如果本身宽度够长就不用延展)做俩级D触发器的打拍处理,对于真正要输出的信号,要来判断D2,D2如果为1,则输出值为Q2,如果D2为0,则输出值保持不变(2.5倍的宽度正是基于此);
MTBF(Tr)同步器的平均故障时间,如果亚稳定性从时钟边沿起一直持续了Tr时间,那么就认为同步器出现故障。T0和τ(tao)是由触发器的电气特性所决定的一个常数。f是触发器的频率,a是触发器上异步输入每秒变化的次数。
在这里插入图片描述

所谓的时钟域,指一组逻辑中所有的同步单元(触发器、同步RAM块及流水乘法器等)都使用一个网络作为时钟。

FPGA设计时常需要在不同的时钟域系统之间交换数据:

  • 在系统之间通过总线I/O接口接收和发送数据;
  • 处理异步信号;
  • 为带门控时钟的低功耗ASIC设计进行原型验证;
  • 衍生时钟;

锁相环对时钟域的管理

FPGA内部都是有PLL模块的,建议在FPGA内部将外部时钟从FPGA的专用引脚扇入后,经过PLL再扇出。
静态时序分析工具TimeQuest对于PLL的输出时钟约束:
create_clock -period 10.000 -name clkin -waveform{0 5}[get_ports {clkin}]
derive_pll_clocks

默认PLL输出都是有相关性的,若是时钟之间无数据交换,则需要给这些时钟之间设置假路径约束,或者设置时钟分组约束;
set_false_path -from[get_clocks{inst | altpll_component | pll |clk[2]}] -to [get_clocks{inst | altpll_component | pll |clk[0]}]

如果时钟之间存在数据交换,则要用以下关于单bit信号的跨时钟域处理方法。此外,由于PLL的输出时钟之间都具有固定的相关性,所以有时候可以使用多周期路径来进行约束;
set_multicycle_path -from [get_clocks {inst | altpll_component | pll | clk[0]}] -to \ [get_clocks {inst | altpll_component | pll | clk[2]}] -end -setup 4
set_multicycle_path -from [get_clocks {inst | altpll_component | pll | clk[0]}] -to \ [get_clocks {inst | altpll_component | pll | clk[2]}] -end -hold 3

单bit信号夸时钟域(Clock Domain Crossing)的同步处理

TimeQuest分析夸时钟域时,需要制定伪路径或多周期路径约束,而且默认情况下,TimeQuest认为所有时钟之间都是相关的。
对于边沿触发器来说,触发器的建立时间和保持时间在时钟上升沿左右定义了一个时间窗口,如果触发器数据输入端口上的数据在这个时间窗口内发生变化(或者数据更新),那么就会产生时序违规。存在这个时序违规是因为建立时间和保持时间要求被违反了,此时触发器内部的某个节点可能会在一个电压范围内浮动,无法稳定维持在逻辑0或者逻辑1状态。换句话说,如果数据在上述窗口中被采集,触发器中的管子不可能可靠地置0或置1。
RTL仿真,并不会出现建立时间和保持时间违规,所以也就不会有信号出现亚稳态状态。尽管门级仿真会检查建立时间和保持时间是否违规,但是仿真由俩个异步信号对齐而导致一个同步故障依然是一件十分困难的事情。尤其困难的是,设计或者验证工程师并不是在设计伊始就查找问题。
那么,理解如何保持设计的可靠性以及如何避免需要通过仿真来揭露设计的同步问题,就显得十分重要了。
在这里插入图片描述
时钟2在刚好在数据1发生变化时刻对其进行采样,意味着第二个寄存器的输出不会是逻辑0或者逻辑1对应的确定电平,而是他们之间的一个中间电平。

双触发

当需要在俩时钟域处理信号的时候,需考虑,是否需要采样从一个时钟域传输到另一个时钟域的这个信号的每一个值?
若是没有必要采样每一个值,则只需要确保传输精确度。若是要求采样每一个值,则意味着夸时钟域信号必须被正确识别,或者说在其允许发生改变之前必须被正确识别。这两种情况中,跨时钟域信号都需要被同步到其接收时钟域之中。
最常见的同步器(同步器就是采样一个异步信号,采样输出能够同步到本地或采样时钟的模块)就是使用两级寄存器,即使用寄存器打两拍的方式进行同步。这种情况下俩点说明:1)初衷只是想电路稳定,夸时钟域的信号不一定能被正确识别;2)打两拍不意味着一定把亚稳态消除。

三级触发

打两拍不见得一定消除亚稳态。MTBF(Mean Time Between Failure,平均故障间隔时间),是衡量一个产品可靠性指标。对于双触发的亚稳态同步器来说,这里的故障是指一个被传输到同步触发器的信号,当他经过第一级同步触发器时处于亚稳态,在随后的一个时钟周期内若继续保持亚稳态并被采样到第二级同步触发器时,则信号亚稳态相当于继续被第二级触发器传递到了接收时钟域,会给到后面继续带来故障。
所以MTBF值越大越好,表示两次故障间隔时间长。

其他单bit同步器

介绍几种更可靠的同步器设计,第一种方法是采用更快的触发器,也就是说,减小τ(tao)。第二种方法是增加Tr的值。
在这里插入图片描述
图中对CLOCK进行N分频就是相当于提高了Tr,Tr=Tclk-Tcomb(0)-Tsetup(定),即Tr=(N X Tclk)-Tsetup,通常n=2或n=3时提供的可靠性就足够了。注意图中,CLOCKN的边沿要比CLOCK的边沿滞后。反过来意味着,与同步系统中其他的信号(从以CLOCK为时钟信号的触发器直接传来的信号)相比,SYNCIN信号会滞后或失真,如果在到达相应的触发器的输入端之前,SYNCIN还要经过另外的组合逻辑电路,那么相应的触发器建立时间就可能不够用了。在这种情况下,可以采用下图的方案来解决问题,这里FF3来产生信号的DSYNCIN,使得SYNCIN信号的时钟信号变成了CLOCK,于是DSYNCIN信号的时序就与同步系统中其他触发器的输出信号的时序一样了。当然还是要求从CLOCK到CLOCKN的延迟时间必须足够短,以便SYNCIN信号能够满足FF3的建立时间要求。
在这里插入图片描述
在n循环同步器中,n值越大,同步系统接收到异步输入信号的变化所需要的时间就越长。这是为了系统可靠工作必须付出的代价。在典型的微处理系统中,大多数的异步输入都用于外部事件,如中断、DMA请求等,这些外部事件需要被快速识别,而信号的快速性又与同步器的延迟有关。在主存访问的临界时间区域内,如果可能,又经验的设计者都会让存储子系统以处理器的时钟频率运行,这样就可以不需要同步器,并且让系统在可能的范围内以最快速度运行。
在频率较高的情况下,多循环同步器的设计可行性收到时钟偏移的限制。为此,有些设计者就采用级联同步器,而不是n分频的同步器时钟信号。也就是采用n个触发器级联(即移位寄存器)的结构形式,所有的触发器都是采用高速系统时钟信号。
在这里插入图片描述13-25
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

下面一个小插曲,我在设计原理与实践里看到的一段话觉得挺有意思所以截图下来了,并参考了几篇关于静态RAM结构的文章。
《微型计算机原理与接口技术》周荷琴、冯焕清
https://blog.csdn.net/mjldejavazhanghu/article/details/128277128
https://blog.csdn.net/edward_zcl/article/details/100086555
https://blog.csdn.net/qq_37654178
在这里插入图片描述

多bit信号跨时钟域处理

当在时钟域之间传递多bit数据时,普通的同步器并不能保证数据传递的安全性。跨时钟域传递多bit信号的问题是,在同步多个信号到一个时钟域时将可能偶发数据变化歪斜,这种数据歪斜最终会在第二个时钟域的不同时钟上升沿上被采集。即便能够完美地控制和匹配这些多比特信号的走线长度,随着芯片衬底工艺的不同,上升和下降时间也会不一样,这些因素都会产生足够的歪斜导致在精心匹配的多余信号上采样失败。
为了避免这种多比特跨时钟域信号上的采样歪斜,需要掌握一些不一样的策略。这些策略大致可以分为三种:

  • 多比特信号融合策略,即在可能的情况下,将多比特跨时钟域信号融合成单比特跨时钟域信号。
  • 多周期路径规划策略,即使用同步加载信号来安全地传递多比特夸时钟域信号
  • 使用格雷码传递多比特跨时钟域信号。

例子一,在接收时钟域有一个寄存器,它需要一个加载信号和一个使能信号来加载一个数值到寄存器。如果加载和使能信号在发送时钟域的同一个时钟沿被驱动有效(即俩个控制信号需要同时有效),那么这俩个控制信号之间就有可能存在产生一个小歪斜的机会,这就导致在接收时钟域中这俩个信号被同步到不同的时钟周期。这种情况下,数据是不能被加载到寄存器的。
在这里插入图片描述
解决如上所述问题的方法非常简单,就是将加载和使能俩个控制信号融合成一个单bit控制信号,单比特控制信号同步到接收时钟域后作为一个“加载使能”信号同时驱动寄存器的加载和使能输入端口。
在这里插入图片描述
例子二,在发送时钟域先后有俩个使能信号(注意不同于之前的同时有效),同步到接收时钟域用于控制两级流水寄存器寄存数据。问题是在第一个时钟域中,B_en1控制信号正好稍微在B_en2有效前结束有效,这就导致在接收时钟域时钟上升沿采集B_en1和B_en2脉冲时产生一个细微的缝隙。同步后俩个使能控制信号间隔了俩个时钟周期,而不是流水一个时钟周期。这样导致数据a2没有及时加载到第二个寄存器。这里需要注意的是,图中的数据如果能一直保持有效,那么在间隔一个时钟周期后,数据还是会加载到第二个寄存器,但这里要求的是严丝合缝的流水操作,所以问题就出现了。图中第二个使能信号推迟了一个时钟周期,数据a2如果能保持有效,应该在第二个使能有效的时候加载进第二个寄存器,图中a3并未显示出来。
在这里插入图片描述
解决这个问题,首先是在发送时钟域将俩个使能控制信号融合为一个控制信号,其次是要增加一个额外的寄存器将同步后的使能控制信号寄存一拍,这样数据和控制信号形成匹配的流水,下图所示的处理方式在HDL代码设计时非常简单,就是将同步后的控制信号在同步时钟域寄存一拍来产生第二级寄存器使能信号。
在这里插入图片描述
多周期路径规划,多周期路径规划是一种通用的安全传递多比特跨时钟域信号技术。多周期路径规划是指在传输非同步数据到接收时钟域时配上一个同步控制信号,数据和控制信号被同时发送到接收时钟域,同时控制信号在接收时钟域使用两级寄存器同步到接收时钟域,使用此同步后的控制信号来加载数据,这样数据就可以在目的寄存器被安全加载。使用这种技术有以下俩个好处:

  • 在时钟域之间发送数据的时候,发送时钟域无须计算对应脉冲宽度;
  • 发生时钟域只需要切换一个使能到接收时钟域来显示数据已经被传递且已准备加载。使能信号无须返回到其原始状态。
    使用这种方式传递多比特跨时钟域信号时,数据不需要同步,只需要同时传递一个同步的使能信号到接收时钟域即可。接收时钟域在同步使能信号通过同步方式传递到接收时钟域之前不允许采集数据。
    这种方式之所以被称为多周期路径规划,是由于非同步的数据字是被直接传递到接收时钟域并在接收时钟域保持多个时钟周期,只有在一个使能信号被同步到接收时钟域并被识别以后才允许该非同步数据字发生变化。
    正是因为非同步数据传递到接收时钟域并在对各时钟周期内保持稳定,使用数据的传递是安全的,数据值并无陷入亚稳态的危险。这种方式非常类似在单时钟域中经常采用的“数据有效”技术,比如读、写FIFO的读有效和写有效等,只是这里谈论的是跨时钟域。有效信号一般是和数据对齐的,那么在传递数据和使能(或有效)信号到下一个时钟域的时候,只需要同步使能信号。下图所示为常用的跨时钟域传递使能控制信号处理方法。将使能信号经过同步器同步后传递到一个同步脉冲发生器,然后产生一个指示信号用于指示非同步多周期数据,即可在下一个接收时钟上升沿进行采集。
    在这里插入图片描述
    如上图所示,关键一点在于产生同步使能脉冲时,输入的控制信号的极性并不重要。图中显示输入信号d从低切换到高,在第7个时钟上升沿处再从高切换到低,看到只要输入信号d发生切换变化,都能产生同步使能脉冲信号,所以输入信号的每次切换对应一次数据的变化。值得一提的是,在单时钟域应用设计当中,经常用到类似技术来产生数据有效信号。上图中使用的是异或门,该技术的缺点是在脉冲的上升沿和下降沿都会产生一个同步脉冲,当只需要一个同步脉冲,或者说需要检测脉冲上升沿的时候,可以使用q3取反后与q2相与即可得到一个单一的同步脉冲,也即只会在上升沿处产生一个同步脉冲。

使用FIFO结构处理多比特跨时钟域信号
FIFO用在俩个异步时钟域之间传输多比特信号。通常看到的FIFO应用包括在俩个标准总线之间传输数据,以及从可突发访问存储器中读出数据或者对其写入数据。
在这里插入图片描述
通过使用异步FIFO,数据发送端可以随意地间隔发送数据,而接收端也可以其固有的带宽从数据序列里取出数据并进行处理。由于任何由FIFO实现的数据序列长度都不能无限制,所以需要一些控制来防止FIFO溢出。有俩种选项可以采用:

  • 根据事先定义好的发送速率(可突发或不可突发)、最小接收速率等来确定序列尺寸大小
  • 采用握手控制来对收发双方进行控制

先来讨论场景一,如何根据双方的速率来确定FIFO深度使数据不溢出?在数据传输中,数据可能到达某个时钟域的间隔是完全随机的,有时候或许会面临一个很大的突发数据块。在用FIOF核的时候,就要知道能达到的最大突发长度等,以此来确定FIFO的最小深度。
FIFO深度讨论
突发传输一般表示的是两个设备之间进行数据传送的一种模式,也可将其称为突发模式下的数据传输。而突发(Burst)是指在同一行中相邻的存储单元连续进行数据传输的方式,连续传输的周期数就是突发长度(Burst Lengths,简称BL)

1、每个时钟都在有效传递数据:
假设"背靠背”时发送的数据 = Burst_lengthL,那么”背靠背”的时间:
在这里插入图片描述
在这里插入图片描述
笔试题1:一个8bit宽的FIFO,输入时钟为100MHz,输出时钟为95MHz,设一个package为4Kbit, 且两个package之间的发送间距足够大。问FIFO的深度。

异步FIFO,读写频率不同,读写位宽相同。发送一次Burst突发数据量为4Kbit。 发送Burst的时间 T =4000/100MHz。
接收方接受的数据量 T95MHz = (4000 / 100) 95 bit
FIFO需要缓存的数据量 4000 - 4000 * 95 / 100 = 200bit
FIFO_Depth >= 200bit/8bit = 25。那么FIFO的深度至少要大于等于25才行。

2、每个时钟非有效传递数据:
写时钟频率w_ clk,读时钟频率r_ clk,写时钟周期里,每B个时钟周期会有A个数据写入FIFO读时钟周期里,每Y个时钟周期会有X个数据读出FIFO。
在这里插入图片描述
假设"背靠背”时发送的数据 = Burst_lengthL,那么”背靠背”的时间:
在这里插入图片描述
注意,这个时间不是wr_rate’ 时,意味着B=A=1;
在这段时间内,接收方可以接收的数据
在这里插入图片描述
缓存数据为
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
若是B>A时,那么t=Burst_length/wr_rate’=Burst_length(B/A)wr_clk

笔试题2:对于同步fifo,每100个cycle可以写入80个数据,每10个cycle可以读出8个数据,fifo的深度至少为?
答:
每100个cycle可以写入80个数据,我们考虑最坏的情况,背靠背模式,空20个时钟,剩下80个时钟写80个数据,再用80个时钟写80个数据,空20个时钟,这样的结果就是连着写了160个数据,共用了200个时钟,突发数据个数是160
所以
fifo_depth = burst_length - burst_length * X/Y * r_clk/w_clk
同步FIFO,读写时钟相同,r_clk=w_clk;
fifo_depth = 160 - 160 *(8/10) * 1 = 160-128=32

笔试题3:
写时钟快于读时钟,写和读的过程中没有空闲周期,也即在突发(burst)过程中,读和写都在各自的时钟域内连续进行
在这里插入图片描述
答:
第一种方法:采取公式计算
fifo_depth = burst_length - burst_length * X/Y * r_clk/w_clk
fifo_depth = 120 - 120 * 1 * 50/80 = 120 - 75 = 45
第二种方法:分析
写时钟周期Tw = 1000/80 = 12.5ns
读时钟周期Tr = 1000/50 = 20ns
突发长度是120,写120个数据,需要的写时间为120*12.5 = 1500ns
在1500ns的时间,读了数据个数为1500/20 = 75
所以120-75 = 45

笔试题4:
写时钟频率大于读时钟频率,但在读写的过程中存在空闲周期。
在这里插入图片描述
答:
两个写数据之间空一个时钟,即2个时钟写1个数据
两个读数据之间空3个时钟,即4个时钟读1个数据
第一种方法:采取公式计算
fifo_depth = burst_length - burst_length * X/Y* r_clk/w_clkB/A
fifo_depth = 120 - 120 * 1/4 * 50/80 * 2 = 120 - 18.7
2 = 82.5=83
第二种方法:分析
写时钟周期Tw = 1000/80 = 12.5ns
读时钟周期Tr = 1000/50 = 20ns
突发长度是120,写120个数据,需要240个时钟,需要的写时间为24012.5 = 3000ns
在3000ns的时间,读了数据个数为3000/(20
4) = 37.5
最后0.5是不完整数据,取整为37,
所以120-37 = 83

笔试题5:
写时钟慢于读时钟,且读写过程中没有空闲周期;
答: 读写没有空闲,而且写时钟慢于读时钟,所以应该是永远不会写满,即不会溢出,fifo的深度为1即可。

笔试题6:
写时钟频率小于读时钟频率,但读写过程中存在空闲周期;
在这里插入图片描述
答:
两个写数据之间空一个时钟,即2个时钟写1个数据
两个读数据之间空3个时钟,即4个时钟读1个数据
第一种方法:采取公式计算
fifo_depth = burst_length - burst_length * X/Y * r_clk/w_clk * B/A
fifo_depth = 120 - 120 * 1/4 * 50/30 * 2 = 120 - 100 = 20
第二种方法:分析
写时钟周期Tw = 1000/30
读时钟周期Tr = 1000/50 = 20ns
突发长度是120,写120个数据,需要240个时钟,需要的写时间为2401000/30= 8000ns
在8000ns的时间,读了数据个数为8000/(20
4) = 100
所以120-100 = 20

笔试题7:
读写时钟速率相同,且无空闲时钟。
在这里插入图片描述
答:
第一种方法:采取公式计算
fifo_depth = burst_length - burst_length * X/Y * r_clk/w_clk
fifo_depth = 120 - 120 * 1/* 1 = 0
如果读写时钟之间没有相位差,则不需要FIFO就可以进行读写呀;
如果二者存在相位差,只需要FIFO的深度为1即可。

笔试题8:
读写时钟频率一致,但在读写过程中存在空闲周期。
在这里插入图片描述
答:
两个写数据之间空一个时钟,即2个时钟写1个数据
两个读数据之间空3个时钟,即4个时钟读1个数据
第一种方法:采取公式计算
fifo_depth = burst_length - burst_length * X/Y * r_clk/w_clk *B/A
fifo_depth = 120 - 120 * 1/4 * 50/50 *2= 120 - 60 = 60
第二种方法:分析
写时钟周期Tw = 1000/50=20ns
读时钟周期Tr = 1000/50 = 20ns
突发长度是120,写120个数据,需要240个时钟,需要的写时间为24020= 4800ns
在4800ns的时间,读了数据个数为4800/(204) =60
所以120-60 = 60

笔试题9:特定条件下,最坏情况分析FIFO最小深度;
在这里插入图片描述
答:
100个时钟周期写80个数据,考虑最坏的情况,即背靠背的方式,空闲20个时钟,剩余80个时钟写80个数据,接着80个时钟写80个数据,空20个时钟,最后的结果就是用160个时钟要写160个数据,即突发长度是160,
每10个时钟读8个数据,160个时钟读了128个数据,
FIFO的深度=160-128 = 32

从以上讨论可知,FIFO的最大尺寸要大于或等于突发的尺寸;

在很多情况下,不管是突发尺寸还是数据到达的分配都无法很好地定义。这种时候,就有必要使用握手机制来防止FIFO产生数据溢出。FIFO在FPGA内一般是通过封装一个双口RAM来实现。
表面上看来微不足道的空满标志信号,实际上实现起来反而比较困难。原因在于输入控制常常需要依据输出产生,同样输出控制也常常需要依据输入来产生。例如,驱动输入的逻辑必须知道FIFO是否已满,而这只能通过获取从输出端读出的数据量才能得知。同样在输出侧从FIFO读数据的逻辑必须要了解FIFO中是否还有数据(FIFO是否已空),而这只能通过输入端口的写指针才能判决。所以意味着FIFO需在俩个时钟域之间传递必要的标志信号,所以需要用到打俩拍技术。
另外在产生空满标志信号时,写地址和读地址都是异步传递到对方时钟域中,这样在重新同步多比特地址总线时问题就出现了,即根据各比特的不同走线,总线中某些比特可能会比其他比特晚一个时钟周期。换句话说,由于俩个时钟域异步的自然属性,使得地址总线有些比特在一个时钟沿上被采集,而另一些比特在下一个时钟沿被采集,如果这种情况发生,那么会给系统带来严重后果,因为二进制地址中有些变化有些位却没有,因此接收逻辑将会得到一个完全无效的地址,这个地址既不是当前地址也不是上一个地址。那么,此问题可以通过把二进制地址转换为格雷码的方式来进行解决。在一组数的编码中,若任意两个相邻的代码只有一位二进制数不同,则称这种编码为格雷码(Gray Code),另外由于最大数与最小数之间也仅一位数不同,即“首尾相连”,因此又称循环码或反射码。
在这里插入图片描述
二进制码转化成格雷码原理:如果二进制码字的第 i 位和 i+1 位(从右边开始数)相同,则对应的格雷码的第i位为0,否则为1(当i+1=n时,二进制码字的第n位被认为是0,即第n-1位不变)
在这里插入图片描述
在这里插入图片描述
运用格雷码后,当地址改变时,只需要改变地址中的一个比特即可,这样就避免上面提到的问题。如果发生变化的那个比特并没有被下一个时钟正确采集,地址线上会“同步地”保留旧的地址值。对于写地址变化如果没有传递到读时钟域,还需看看那些FIFO IP是如何处理的。
那么,任何不正确的地址(既不是当前地址,也不是旧地址)操作都会被消除。需要注意的是,由于读写地址在异步时钟域之间传递,所以地址有可能比预想的晚一个时钟周期,同时意味着空或者满标志置位晚一个时钟周期,但是这个并不表示错误导致了数据溢出状况。如果这种情况在传递地址到读时钟域时,读逻辑将简单的认为数据没有写入,且将认为FIFO已空,尽管此时FIFO已经被写入一个数据。同样,当地址被传递到写时钟域时,如果读地址被延时了,那么写逻辑会认为FIFO里没有多余空间,尽管此时FIFO还未满。

多时钟域设计分区划分

时钟边界分区

在顶层设计划分好设计分区,这样任何功能模块外面都包含一个独立的同步器模块。有利于在划分模块的基础上实现所谓的理想时钟域情况,即整个子设计模块只有一个时钟。
在这里插入图片描述

时钟分区后的静态时序分析

使用时钟划分设计分区策略后,每个设计模块就完全同步于唯一的时钟。这种设计类型是静态时序分析(STA)工具(如Altera的TimeQuest)最容易分析验证,因为整个设计模块无伪路径(False Paths)。
使用这种源自时钟的分区划分策略时,设计中在每个跨时钟边界由同步器模块进行隔离。每个同步器模块只包含由ASIC或FPGA厂家提供的同步器单元,或者只是由两级触发器对组成的同步器单元。在对RTL代码实现的同步器进行静态时序分析时,需要使用set_false_path命令将输入从STA中删除。因为同步器的输入会出现时序问题,这也是为什么需要在设计中使用同步器的原因。经过基于时钟域的分区划分以后,静态时序分析就变得简易很多,反而,如何将相同时钟域组合到一起并识别出伪路径变得相当最要了。

对多周期规划逻辑设计的分区划分

在设计中,将时钟边界划分成多个单独的设计模块和同步器模块在大部分情况下效果会很好。然而,如果多比特信号使用多周期规划方式跨越时钟域边界,则有些信号从一个设计模块传递到另一个时钟域设计模块时的情况如下图所示:
在这里插入图片描述
在进行静态时序分析之前,需要对那些异步输入信号排除在分析之外,也即在TimeQuest中经常碰到的所谓时序例外。换句话说,这些路径是不需要进行分析的。通常,只有同步器模块的输入和多周期路径规划数据路径需要使用set_false_path命令。对于上图,可以在TimeQuest进行时序分析时使用下面的命令来将时钟乙所有从adata总线输入的路径排除:set_false_path - from{a*}

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值