写在前面
这篇文章主要是对过去对于亚稳态以及跨时钟域传输问题的一次总结,作为这个系列博文的一次梳理吧。
注:微信公众号也会更新,欢迎大家关注,我有了新文章会通过微信公众号推送通知大家,让你有选择的看到我的最新动态。
- 个人微信公众号: FPGA LAB
正文
FPGA或ASIC中的传播延迟
在以前秋招的时候,我常常遇到时序分析的题目,其中全英文的题目中出现过传播延迟这个单词,即:Propagation Delay!
当然 ,如果你读惯了中文的表达,例如我们常常遇到这样的说法,门延迟,布线延迟等等,这时当你遇到了Propagation Delay的时候也许会不确定是什么东西,是Tco?还是Tlogic?还是什么?等等,Forget it !这就会影响你分析问题的状态!
今天这里给出明确的定义:
Propagation Delay is the amount of time it takes for a signal to travel from a source to a destination.
意思是传播延迟是信号从源触发器到目的触发器所需要的时间!这一看不就是逻辑延迟加上布线延迟吗?
确实如此!
在FPGA或ASIC内部,到处都有成千上万的细线。 当您实际将电线的物理长度加在一起时,它们很容易超过一英尺长( 经验法则是,信号可以在一纳秒内传输一英尺的导线。),考虑到芯片有多小,这非常惊人。 此外,您的代码执行的每个逻辑都需要一定的延迟时间。 由于确实存在这些延迟,因此数字设计人员需要了解它们如何影响FPGA或ASIC。
如下图为传播延迟示意图:
传播延迟对时序逻辑至关重要。 我们知道,时序逻辑是由时钟驱动的逻辑。 在上图中,有两个触发器,它们之间通过一些逻辑和布线(电线)连接在一起。第一个触发器的输出传播到第二个触发器的输入所花费的时间为传播延迟。 这两个触发器相距越远,或者中间的组合逻辑越多,则它们之间的传播延迟就越长。 传播延迟时间越长,时钟的运行速度就越慢。
这样做的原因是两个触发器使用相同的时钟。 第一个触发器在时钟沿1处驱动其输出。第二个触发器直到时钟沿2才看到第一个触发器的输出变化,此时它驱动其输出。 如果信号可以在一个时钟周期内安全地从触发器1传输到触发器2,则您的设计很好! 如果没有,您将遇到问题。
例如,考虑两个触发器相距10纳秒(ns)的情况。 如果您使用的时钟频率为50 MHz(周期为20 ns),则将是安全的。 您还有10 ns的空闲时间。 但是,如果使用200 MHz时钟(周期为5 ns),则设计将无法进行时序分析,并且无法按预期方式工作。
FPGA或ASIC工具中任何时序分析器的目的都是告诉您在时序方面是否存在问题。 如果您的设计太慢而无法以所需的时钟频率运行,则会出现时序错误,并且您的设计可能无法正常工作。
这是解决高传播延迟的方法:
- 降低时钟频率
- 将您的逻辑分解为多个阶段(流水线)
降低时钟频率是最明显的事情。 如果您能够较慢地运行FPGA,那么您的时序将会改善。 将您的逻辑分解成多个阶段是更可靠的解决方案。 如果在两个触发器之间逻辑较少,则传播延迟将减小,并且您的设计将满足时序要求。(回顾下retiming是不是也需要这么做呢?)
示意图如下:
在上图中,两个触发器之间存在大量逻辑。 如此之多,以至于设计的传播延迟太大,并且导致时序不满足。 如果设计人员在三个触发器之间分解逻辑,则逻辑的一半可以在前两个触发器之间完成,逻辑的另一半可以在后两个触发器之间完成。 现在,这些工具将在一个时钟周期内完成所需工作的时间几乎增加了一倍。 这就是所谓的流水线,对于成为一名优秀的数字设计师来说非常重要。 当你使用流水线的方式设计电路时,在高时钟频率下满足时序的机会会更大。
建立和保持时间是什么?
建立时间和保持时间,是数字设计师最基础的问题,他是时序分析的核心,或者说时序分析其实就是围绕着建立时间以及保持时间来分析的,你的设计满足建立时间要求以及保持时间要求,就能通过时序检测,否则就会违例!
下面就详细讲解他们!
我们都知道,传播延迟是信号在两个触发器之间通过所花费的时间。 当信号沿导线传输时,它可以从0-> 1或1-> 0改变。 触发器的输入必须稳定(不变),以使FPGA设计正常工作。 在时钟采样之前,输入必须稳定一小段时间。 该时间量称为建立时间。 建立时间是指在时钟沿之前,输入到触发器稳定所需的时间。 保持时间类似于建立时间,但是它在时钟沿发生后处理事件。 保持时间是在时钟沿之后输入到触发器稳定所需的最短时间。
如下示意图:
在图中,绿色区域代表tsu或Setup Time。 蓝色区域代表时间或保持时间。 在这些区域中,触发器中的数据必须为稳定的0或1,否则会发生不良情况。
建立和保持时间与传播延迟和时钟频率有何关系?
建立时间,保持时间和传播延迟都会影响您的FPGA设计时序。FPGA工具将检查以确保您的设计满足时序要求,这意味着时钟的运行速度不超过逻辑允许的速度。可以计算出FPGA时钟所允许的最短时间(其周期,由T表示)。从中可以找到时钟的频率,因为频率是周期的倒数(F = 1 / T)。
就以下图为例吧:
假设Tco表示触发器时钟有效到数据输出的时间;Tpd表示传播延迟,Tsu表示建立时间,不考虑时钟偏斜,那么最小时钟周期为:
Tmin = Tco + Tpd + Tsu;
通常,在您的FPGA设计中,t su和t h对于触发器是固定的,因此,您可以控制的唯一变量是t p或传播延迟。这种延迟代表了多少东西,你想在一个时钟周期内完成。您尝试做的事情越多,t p越长,t clk(min)越高,这意味着您将无法尽快对FPGA设计进行计时。这是FPGA设计的基本权衡。您需要权衡一个时钟周期内可以为时钟频率执行多少操作。这两个是相反的关系……没有免费的午餐!
思考:参考资料中把最小时钟周期Tmin写成如下的形式:
这是为什么呢?
如果违反建立和保持时间会发生什么?
如果您的设计违反设置或保持时间,则不能保证触发器输出稳定。可能为零,可能为一,可能在中间的某个地方,未知。这称为亚稳态。FPGA内部的亚稳定性不是所希望的,它可能导致您的FPGA表现异常。
FPGA设计人员发现他们是否违反设置或保持时间的主要方法是通过布局布线(Place and Route)运行FPGA时。布局布线(Place and Route)是将VHDL或Verilog代码放入FPGA时发生的情况。作为此过程的一部分,FPGA工具将带您进行设计并进行时序分析。在此时序分析中,您将看到任何时序错误,这些错误实际上只是违反设置时间或保持时间。如何解决这些错误将在后面给出!
总之,建立时间和保持时间是FPGA设计人员要理解的重要概念。如果违反这些时间,FPGA将无法达到预期的效果!
FPGA中的亚稳定是什么?
上面也说了,如果设计放到FPGA中(ASIC一致),违反了建立时间或保持时间,则输出会处于亚稳态!
那亚稳态是什么呢?
如下图:
如上图所示, 红色区域代表tsu或Setup Time。 如您所见,在触发器建立期间,输入到触发器的数据从低到高。如果数据在时钟上升沿的建立时间内发生跳变,则会产生亚稳态输出,即输出值在短时间内处于不确定态,有可能是1,有可能是0,也可能什么都不是,处于中间态!之后稳定为0或1。但是我们仍然不知道输出以哪种状态结束。有时可能是0,有时其他情况会发生 再次为1.。这不是理想的行为。 您必须始终知道您的FPGA在做什么。
为了更清晰说明,我们参考资料提出一个类似的例子 :
下图说明了亚稳信号。当时钟信号变化时,输入信号从低电平转换为高电平,这违反了寄存器的tsu(建立时间)要求。数据输出信号示例从低电平开始,然后变为亚稳态,在高电平和低电平之间徘徊。信号输出A解析为输入数据的新逻辑1状态,而输出B返回数据输入的原始逻辑0状态。在这两种情况下,输出到定义的1或0状态的转换的延迟都超过寄存器的指定tco(寄存器时钟到输出时间)。
上面所说的是建立时间不足导致的亚稳态,其实导致亚稳态还有可能是保持时间不足!
亚稳态何时会导致设计失败?
如果在下一个寄存器捕获数据之前数据输出信号稳定为有效状态,则亚稳信号不会对系统操作产生负面影响。但是,如果亚稳态信号在到达下一个设计寄存器之前未稳定为低电平或高电平状态,则可能导致系统故障。
同步寄存器
大多数亚稳态条件以下列两种方式之一发生:
- 您正在采样FPGA外部的信号
- 您正在跨时钟域传输数据
这两种情况都可以用相同的方式解决。 每当遇到可能引入亚稳定性的情况时,您都可以简单地“double-flop”您的数据(两级触发器采样)。
在左图中,第一个触发器正在采样与时钟异步的信号。 这将在输出处创建一个亚稳态条件。 如果再次采样此输出,则现在可以修复亚稳态事件。 第二个触发器的输出将保持稳定。
当然这只是最简单的处理方式,当考虑到跨时钟域信号处理时,还需具体情况具体分析。
跨时钟域传输
在FPGA内部跨越时钟域是一项常见的任务,但这是许多数字设计人员遇到的麻烦。如果数字设计人员不了解从一个时钟域转换到另一个时钟域所涉及的所有细节,则可能会出现问题。
下面对跨时钟域处理可能出现的问题进行总结!
从较慢的时钟域过渡到较快的时钟域
最简单的跨时钟域传输类型是从一个时钟域到一个更快的时钟域。在这种类型的传输中,您仍然会受到Metastability的影响,但是该文章中描述的解决方案在这种情况下非常有效。您需要做的就是将数据“两级同步”,如下图所示。
较慢的时钟是您的源时钟域,更快的时钟是您的目标时钟域。在较快的时钟域中,第一个触发器具有亚稳态输出。发生这种情况的原因是,在执行此跨时钟域传输操作时,会违反设置和保持时间,这是造成亚稳性的原因。我们可以通过在较快的时钟域中简单地重新采样数据或对数据进行两次寄存来解决此问题,如上图所示。第二个触发器的输出将保持稳定,现在可以在更快的时钟域中使用数据。
下面的Verilog设计显示了当从慢速时钟域过渡到快速时钟域时,如何寻找信号的上升沿。请注意,用于边缘检测的逻辑必须在快速时钟域中完成。
// Verilog Example:
reg r1_Data, r2_Data, r3_Data, trig_pos=0;
always @(posedge i_Fast_Clock)
begin
// r1_Data is METASTABLE, r2_Data and r3_Data are STABLE
r1_Data <= i_Slow_Data;
r2_Data <= r1_Data;
r3_Data <= r2_Data;
if (r3_Data == 1'b0 && r2_Data == 1'b1)
begin
// Positive Edge Condition
trig_pos <= 1;
end
end
注 :这里说明的是提取采样信号的上升沿,如果你不需要这样,就直接两级同步即可得到非亚稳态的采样信号。
从较快的时钟域过渡到较慢的时钟域
这种情况比前一种情况稍微复杂一些。在这里,我们正在从快速时钟域转向较慢的时钟域。在这种情况下,很容易想到一个示例,其中快速时钟域中的数据可能在慢速时钟域甚至没有看到之前就发生了变化。例如,考虑一个在100 MHz时钟域中发生1个时钟周期的脉冲,您正在尝试在25 MHz时钟域中进行采样。如果仅使用25 MHz时钟对数据进行采样,则很有可能永远不会看到此脉冲! 为了将信号从快速时钟域传输到慢速时钟域,您必须扩展信号。请参见下图,以直观的方式查看。
当您将脉冲或数据延长足够长的时间以确保慢时钟域有机会对其进行采样时,就会发生数据拉伸。在上面的示例中,您需要扩展数据以确保无论何时采样数据都满足建立和保持时间。为了正确保证满足建立时间和保持时间,我建议延长脉冲,使它们在慢速时钟域中至少占用2个时钟周期。因此,在上面的示例中,您应该将100 MHz脉冲扩展到至少8个时钟周期(您可以随时增加)。
这种从快时钟域到慢时钟域的信号传输,其设计可以参考我之前的博文:谈谈跨时钟域传输问题(CDC)
博文里给出了设计:
module Sync_Pulse(
input clka,
input clkb,
input rst_n,
input pulse_ina,
output pulse_outb,
output signal_outb
);
//-------------------------------------------------------
reg signal_a;
reg signal_b;
reg signal_b_r;
reg signal_b_rr;
reg signal_a_r;
reg signal_a_rr;
//-------------------------------------------------------
//在clka下,生成展宽信号signal_a
always @(posedge clka or negedge rst_n)begin
if(rst_n == 1'b0)begin
signal_a <= 1'b0;
end
else if(pulse_ina == 1'b1)begin
signal_a <= 1'b1;
end
else if(signal_a_rr == 1'b1)
signal_a <= 1'b0;
else
signal_a <= signal_a;
end
//-------------------------------------------------------
//在clkb下同步signal_a
always @(posedge clkb or negedge rst_n)begin
if(rst_n == 1'b0)begin
signal_b <= 1'b0;
end
else begin
signal_b <= signal_a;
end
end
//-------------------------------------------------------
//在clkb下生成脉冲信号和输出信号
always @(posedge clkb or negedge rst_n)begin
if(rst_n == 1'b0)begin
signal_b_r <= 'b0;
signal_b_rr <= 'b0;
end
else begin
signal_b_rr <= signal_b_r;
signal_b_r <= signal_b;
end
end
assign pulse_outb = ~signal_b_rr & signal_b_r;
assign signal_outb = signal_b_rr;
//-------------------------------------------------------
//在clka下采集signal_b_rr,生成signal_a_rr用于反馈拉低signal_a
always @(posedge clka or negedge rst_n)begin
if(rst_n == 1'b0)begin
signal_a_r <= 'b0;
signal_a_rr <= 'b0;
end
else begin
signal_a_rr <= signal_a_r;
signal_a_r <= signal_b_rr;
end
end
endmodule
如何理解,可以参照仿真图或者波形图:
异步FIFO
上面所说的还都是单比特信号,对于多比特信号,我们可以使用异步FIFO来处理跨时钟域传输问题,至于异步FIFO的设计,我是真的没必要在赘余了,见博客:FPGA基础知识极简教程(4)从FIFO设计讲起之异步FIFO篇
这是我最新写的比较好理解的一种设计版本。
时序错误和跨时钟域
通常,当您跨时钟域时,会遇到计时错误。这个是正常的!这是告诉您的情况,您的设置和保持时间将无法保持,并且您将处于亚稳状态。如前所述,亚稳定是这项工作的常识,因此,只要您了解并可以围绕它进行设计,就可以了。
总之,作为FPGA设计人员,您将遇到跨时钟域的情况。您需要清楚地了解在这些情况下发生的常见陷阱。如果跨时钟域的情况足够简单,则可以将数据两级寄存器采样或执行脉冲展宽。在大多数情况下,您可能需要使用支持两个时钟的FIFO(异步FIFO),一个用于读取,一个用于写入。
参考资料
交个朋友
个人微信公众号:FPGA LAB
知乎:李锐博恩