时钟设计总结
时钟和复位是FPGA设计的基础,本章总结了一些逻辑时钟复位设计、使用中出现的问题,给出了设计要点,避免后续问题重犯。时钟和复位,本文都先从板级谈起,再到FPGA芯片级,最后到模块级别。仅在此做部分总结,不足或不正确之处,还望指正。
板级时钟方案
- 严禁出现 CPU接口时钟来源于片外锁相环且锁相环的初始化、配置同时依赖 FPGA。遇到这种情况必须硬件改板或修改时钟方案。
【解析】
localbus时钟依赖FPGA片外锁相环LMK04828,而LMK04828的初始化配置又同时依赖FPGA,形成死循环(不配置LMK04828将没有localbus时钟,没有localbus时钟将无法配置LMK04828)。无解决办法,需要硬件改板或修改时钟方案。
- 对于CPU接口时钟(localbus时钟),推荐直接来源于片外晶振。如CPU接口时钟来源于片外锁相环,则需要保证片外锁相环的初始化、配置不依赖FPGA。
【解析】
如上图(a),localbus时钟来源FPGA片外晶振,LMK04828配置来源CPU。CPU先初始化LMK04828,再加载FPGA,推荐该方案。
如上图(b),如果localbus时钟也来源于LMK04828,而CPU对LMK04828的初始化配置等又不依赖FPGA,则此方案在原则上也可以被接受。CPU先初始化LMK04828,再加载使用FPGA。
- 对于片外锁相环,推荐直接通过CPU初始化;配置不依赖FPGA,软件先初始化片外锁相环再加载 FPGA。如果片外锁相环初始化配置依赖FPGA,则必须保证CPU接口时钟不依赖片外锁相环。上电流程为先加载FPGA,再初始化片外锁相环(需注意片外锁相环初始化过程中,锁相环输出时钟对FPGA的影响)。
【解析】
如上图(a),localbus时钟来源FPGA片外晶振,LMK04828配置来源CPU。CPU先初始化LMK04828,再加载FPGA,可以确保FPGA在加载前,输入FPGA的时钟已经稳定,此为完美方案。
如上图(b),如果片外锁相环初始化、配置依赖FPGA,则必须保证CPU接口时钟不依赖片外锁相环(推荐使用晶振时钟或CPU接口随路时钟)。先加载FPGA,再初始化片外锁相环。此时需要注意片外锁相环初始化过程中,锁相环输出时钟对FPGA的影响,不能导致FPGA过流、异常、复位等发生。
如必须通过FPGA初始化,此时需要确保片外锁相环送给FPGA的时钟管脚默认都是powerdown状态。如果片外锁相环送给FPGA的时钟管脚默认不是powerdown状态,推荐FPGA默认对该时钟域进行复位,最后采用软件解复位。整体流程为:软件先加载 FPGA,再初始化片外锁相环,最后解复位非 powerdown 状态的时钟逻辑(防止异常时钟频率过大导致FPGA过流而掉版本、复位等异常情况)。
片内时钟方案
门控时钟设计
不能使用组合逻辑时钟或门控时钟,组合逻辑很容易产生毛刺,用组合逻辑的输出作为时钟很容易使系统产生误动作,应当尽量避免门控时钟的出现,此时尽可能的将需要用做门控时钟的控制信号综合到数据端,比如时钟使能CE端等。如果有节能需求,或者一定要用门控时钟,推荐两种方案:
- 使用芯片商提供的时钟控制专用IPcore实现时钟门控或选择,如Altera公司的ALTCLKCTRL,Xilinx的BUFGCTRL。对于ASIC也有专用的CG cell.
- 门控时钟的输出只能跟着时钟信号进行跳变,而不能跟着控制信号跳变。
图x 或门门控时钟电路
图x 与门门控时钟电路
也就是说,对于使用与门实现的门控电路,控制信号只能在时钟的低电平进行跳变。如果在时钟高电平跳变,由于gate信号为异步信号,在边沿采样时,寄存器的输出gate_1d有可能出现亚稳态,那么和时钟相与后,得到的信号如图xx(a),会存在毛刺。如果是在时钟低电平跳变,gate_1d虽然会出现亚稳态,但和低电平的时钟相与后,被掩掉了,如图(b)。同理,对于使用或门实现的门控时钟,控制信号只能在时钟的高电平处跳变。
(a)
(b)
异步的时钟选择电路
不推荐使用异步的时钟选择电路,如果选择信号sel与时钟异步的话,则选择的时钟就可能出现展宽或变窄的情况,甚至有尖脉冲(glitch)的出现。
所以建议使用如下的时钟选择电路,特别是对时钟的要求比较高的电路中。
图x 无毛刺异步时钟切换电路
clk1和clk2是两个相位、频率完全没有关系的时钟,我们希望进行切换。如果设计要求不能有毛刺,我们在开启另一个时钟时,先要关断另一个时钟,这种关断一个并开启另一个操作可能会引发输出一个“死”周期,例如clk0在低电平时被关断,同时clk1已开启。
这个电路中,电路起始所以触发器都需要清零,如果是异步触发器,异步清零很容易在上电时刻实现。当控制信号sel = 0,在电路上电后,只要异步清零,clk2 = 0,当异步清零结束后,q11在clk0的第一个下降沿跳变成1,下一个时钟周期q12置1,这样clk2 = clk0;这个状态一直持续到sel的值改变。当sel = 1,且没有建立/保持时间violation时,q11变低,再过一个时钟周期,q12变低,这样就关断了clk2,如果此时q11存在亚稳态,就需要更长时间来关断clk2。clk2被关断后才进行切换,最差的情况就是存在亚稳态需要更长的时间,但整个切换操作不会引入毛刺。
加入反馈电路的目的就是为了确保时钟被真正关闭了,才进行切换。中间的2级触发器是用来做同步处理,如果clk0或clk1时钟频率较高,则需要至少3级触发器同步。
思考:为什么触发器要用下降沿去做同步处理?
这里用下降沿触发与最后一级门电路有关,与门控时钟处理的原则是一致的。如果采用“与或门”,则需要用下降沿触发;如果是采用“或与门”,则需要用上升沿触发,当然设计电路会与上面稍微有差异。
还有在sel由低跳变到高时,T0时刻与T2时刻中间有段异常信号,但是clk2输出对clk1时钟域的电路来说,都是同步时序电路(切换后,clk2的沿与clk1的沿完全对齐);同理,在sel由高跳变到低时,T3时刻与T4时刻中间有段异常信号,但是clk2输出对clk0时钟域的电路来说,都是同步时序电路(切换后,clk2的沿与clk0的沿完全对齐),这段异常对后面的逻辑电路无影响。
行波时钟设计
在方案设计时,时钟建立应尽量避免采用多时钟网络。可以采用适当的措施减少时钟的个数,使用频率低的时钟尽量简化消除,多使用触发器的使能端来解决。在源时钟域产生“行波时钟“的上升沿/下降沿作为源时钟域的使能信号代替行波时钟。
- 不要试图将行波时钟驱动到全局时钟网络规避行波时钟可能导致的问题。
- 建议DDR/DDRO应用场景外不要在设计中使用multicycle约束。
思考:行波时钟的上升沿/下降沿作源时钟驱动电路的时钟使能端更好,还是数据使能端更好?
//代码1:
always@(posedge clk) beginif(clk_div_r == 1’b1)data <= a;elsedata <= b;
end
//代码2:
always@(posedge clk) begindata <= (clk_div_r == 1’b1) ? a : b;
end
一般情况下,综合工具对上面两种的综合结果可能不同,有的综合工具把clk_div_r综合到触发器的时钟使能端,不占用LUT的输入,有的会将clk_div_r综合到LUT的输入端做一个选择,则占用LUT的输入。
如果该clk_div_r驱动电路很多,建议使用代码1的描述方式;但也要看综合结果,如果综合工具还是将clk_div_r综合到LUT输入端,且比较关注LUT的资源,可以考虑采用原语方式描述该区域触发器,或更换综合工具。
其他要点
- altgx_reconfig/gtx_drp的clk必须满足器件频率要求且稳定,altgx_reconfig的offset cancellation 在FPGA加载后,只进行一次,中间过程不能被打断。加载FPGA后,需要确保reconfig_rst一直有效直到 reconfig_clk 稳定,再释放reconfig_rst。reconfig_rst 释放后,直到 offset cancellation 完成前,reconfig_clk 必须保持稳定、reconfia rst 不能被异常拉起。
【解析】
优先推荐:由FPGA外部提供时钟,并在逻辑加载前已稳定(需要注意时钟频率是否满足器件要求)。
推荐:FPGA内部PLL生成reconfig_clk/drp_clk,并altgx_reconfig/drp
进行延迟复位,必须等PLL锁定后一段时间才解复位,复位信号必须在reconfig_clk/drp_clk时钟域同步化(上电就复位,同步解复位)。
不推荐:FPGA内部计数分频生成reconfig_clk/drp_clk,并且不对计数分频器、altgx_reconfig/gtx_drp模块进行复位处理。
- 要防止DCM假锁情况,除了判断locked信号外还需要对DCM输出时钟进行频率检测(使用稳定晶振时钟做检测),如果失锁或输出时钟频率不正确(+5%或+10%),则需要对DCM进行复位处理。
【解析】
Xilinx的DCM的locked信号是不可靠的,需要同时对DCM输出时钟频率做检测,如果DCM输出频率不在合理范围内,则需要对DCM进行复位处理(复位即可恢复异常,不需要重配置DCM或重加载FPGA)。锁定指示可能出错,即本来已经锁定,但上报失锁(此时也进行复位,统一操作)或者本来失锁但上报锁定,此时需要配合输出时钟频率检测来判断DCM是否正常。
- PLL输出时钟间、输出时钟与输入时钟间有固定相位关系的,如果环路时钟有变化,则需要对 PLL 进行复位处理,才能保证各时钟的相位关系。
【解析】
PLL输出时钟间、输出时钟与输入时钟间有固定相位关系的,如果环路时钟有变化,需要对PLL进行复位处理,才能保证各时钟相位关系。如有反馈参考时钟的,要求输入时钟与反馈参考时钟同频率,否则可能导致相位差问题。
- DCM/PLL失锁后,需要对输出时钟域进行复位处理。
【解析】
DCM/PLL失锁后,为了可靠性,需要对输出时钟域进行复位,复位信号在DCM/PLL锁定后需要保持一段时间,等待锁相环输出时钟真正稳定后才解复位。同时需要注意复位不能影响CPU等已经下发的配置信息,不能擦除已有的配置,即使做了擦除操作也需要及时知会软件进行后处理。
- ROM/RAM的地址线、数据线、控制线必须同步到 ROM/RAM对应的读写时钟域。
【解析】
ROM/RAM的地址线、数据线、控制线必须同步到ROM/RAM的读写时钟域,否则有可能导致ROM/RAM内容被异常算改(典型案例: ROM/RAM读操作,读地址与读时钟不是同一个时钟域。ROM/RAM的内容被异常改写不恢复--并不是写操作出问题,而是只读操作时序出问题导致内容被算改)。
【解析】
- SERDES恢复钟,需要确保走线最短,且满足相噪要求。
【解析】
SERDES恢复钟,需要确保走线最短,避免走线长导致时钟畸变,满足相噪要求。
时钟方案的设计方法
1、确定serdes接口速率,计算serdes参考时钟,同一个serdes支持多种速率时要分别计算;
2、确定I0接口(localbus、SPI、DDR等)速率,计算IO接口时钟频率;
3根据总体方案,整理系统时钟需求,并分析哪些系统时钟可由内部PLL产生;
4、根据以上几点确定需要单板硬件提供的时钟数目,及其频率、同源关系等。
时钟举例
该项目的时钟方案按业务处理模块进行划分:OTN线路时钟334MHz、OTN系统时钟314MHz、SDH系统时钟311MHZ、GFP系统时钟200MHz、ETH系统时钟156MHz此外还有开销接口时钟155MHz和CPU接口时钟77MHz。不同业务处理模块、不同的接口速率不同,因此采用不同频率的时钟,这样在满足处理要求的前提下使用尽量低频的时钟,减低后端时序收敛的难度同时使系统功耗较优。
复位设计
为什么ASIC芯片需要复位?对于绝大多数芯片来说,复位模块的功能基本相同。复位电路在ASIC芯片设计中必不可少,状态机使用前或死机需要复位以进入确定的状态;RAM使用前需要复位和初始化;为降低功耗需要对不使用的逻辑复位、配置复位等等功能。
那FPGA芯片需要复位吗?FPGA复位是需要在设计中考虑并加以限制的较为常见且重要的控制信号之一。复位会对设计的最高时钟频率、面积和功耗产生显著影响。经推断的同步代码可能产生如下资源:LUT、寄存器、 SRL、块存储器或 LUT 存储器、DSP48 寄存器。复位的选择和使用会影响这些组件的选择,导致针对给定设计选择的资源欠佳。任何阵列上复位布局错误都可能导致截然不同的结果,比如推断 1 个块 RAM 或推断数千个寄存器。多路复用器的输入输出中所描述的异步复位可能导致将寄存器放置到 slice 中而不是放置到 DSP 块中。在此类情况下,将使用额外逻辑资源,从而对功耗和设计性能产生负面影响。
Xilinx强烈建议谨慎判断何时设计需要复位以及何时不需要复位。大多数情况下,在控制路径逻辑上可能需要复位以确保正常运行。然而在数据路径逻辑上通常不需要复位。复位的使用限制如下:限制复位信号线的总体扇出、减少复位布线所需的互连数量、简化复位路径的时序、在大多数情况下,这样即可整体改善时钟频率、面积和功耗。建议评估每个同步块,尝试判断是否需要复位以确保正常运行。默认情况下,除非确定确实有需要,否则请勿编写复位代码。功能仿真可轻松判断是否需要复位。对于不含复位编码的逻辑,可以灵活选择用于映射逻辑的器件资源。随后,综合工具即可选择最适合代码的资源,并通过考量如下因素来尽可能实现最佳结果:请求的功能、时钟周期要求、可用器件资源、功耗等。
另外Xilinx FPGA在系统上电配置时,会有一个GSR(Global Set/Reset)的信号,这个信号有以下几个特点:预布线、高扇出、可靠的。全局置位/复位 (GSR) 信号是一种特殊的预布线复位信号,能够在 FPGA配置的过程中让设计保持初始状态(这个信号可初始化所有的cell,包括所有的Flip-Flop和BRAM。如果我们在程序里用自己生成的复位信号,也只能复位Flip-Flop)。在配置完成后,GSR 会被释放,所有的触发器及其它资源都加载的是 INIT 值。如果未指定初始状态,将为时序原语分配默认值。在大多数情况下,默认值为 0。FDSE 和 FDPE 原语是例外,其默认为逻辑 1。每个寄存器在配置结束时都将处于已知状态。
除了在配置进程中运行 GSR,用户设计还可以通过实例化 STARTUPE2 模块并连接到 GSR 端口的方法来访问 GSR 网。使用该端口,设计可以重新断言 GSR网,相应地 FPGA 中的所有存储元件将返回到它们的 INIT 属性所规定的状态。
虽然有GSR,但这并不是说要避免使用复位信号。取消断言 GSR 是异步的,需要使用多个时钟才能影响到设计中的所有触发器。而且FPGA会把像系统复位这种高扇出的信号放到高速布线资源上,这比使用GSR要快,而且更容易进行时序分析。对于状态机、计数器或者其它能够自动改变状态的逻辑,需要一个显式的复位,用于同步取消用户时钟断言。因此,使用 GSR 作为唯一的复位机制可能导致系统不可靠,最好是综合采用多种方法来有效地管理启动。以下几种情况就必须要加复位:
- 环状结构的设计,例如CIC的积分器,如果出现计算错误,由于反馈电路的存在,错误就会一直累积下去,这时就需要进行定时复位。
- 关键控制信号,如状态机等,让其工作前处于确定的初始状态。在基站或者WIFI芯片里面,在发包前,都会对链路进行初始化;接收链路在AGC失锁后也会进行复位。
- 一些需要自愈设计的场景,如FIFO挂死、状态机跑飞、PLL/DCM失锁、中断异常等,这个时候就可以对电路进行复位,让它从错误的状态回到一个正常的状态。
- 电路仿真时需要电路具有已知的初始值。在仿真的时候,信号在初始状态是x态,而且会逐级传播。
但就像Xilinx建议的,一些只用于流水打拍、同步打拍的寄存器或者期望使用SRL等场景就没必要复位了;还有一些数据通路,在实际电路中,只要输入是有效数据(开始的时候可能不是有效的),输出后的状态也是确定的。也就是说,初始不定态对数据通路的影响不明显,这种情况也无需复位的。所以,需不需要复位完全看具体的设计。复位设计是指复位信号的生成,面临的问题主要是毛刺过滤、时钟域的同步、可否做STA检查以及达到这一目的对时钟的依赖程度有多大等。
板级复位方案
- CPU先初始化片外锁相环,再拉FPGA复位管脚,再加载FPGA,再等待DLY_X解复位FPGA。此方案能保证FPGA加载前时钟稳定,且复位信号在加载前置位,加载后才取消。
【解析】
CPU先初始化LMK04828,再复位FPGA(FPGA复位管脚置位),再加载FPGA,再等待DLY_X解复位FPGA。确保FPGA在加载前,时钟稳定复位已经置位。FPGA加载成功后一段时间复位信号才取消,确保FPGA的复位操作连续,不出现不复位->复位->不复位的情况。
如果先加载FPGA,再对FPGA复位,就有可能产生解复位>复位->解复位的过程,不如直接产生复位->解复位来的干净利落,避免了逻辑CDR自校准被打断或者接口送出异常时序的可能。
- CPU先拉FPGA复位管脚,加载FPGA,等待DLY_X解复位FPGA,再初始化片外锁相环,最后解复位片外锁相环时钟域的复位信号。FPGA 管脚复位对全芯片所有时钟域进行复位,锁相环时钟域新增寄存器进行复位,默认是复位,需要CPU解复位。
【解析】
CPU先拉FPGA复位管脚,然后加载FPGA,再等待DLY_X解复位FPGA,再初始化LMK04828,最后解复位sys_clk域复位信号。
先确保FPGA被复位,再加载FPGA。但FPGA加载后才初始化LMK04828时钟,需要对LMK04828输出时钟域做默认复位处理,待CPU初始化好LMK04828时钟后,再对LMK04828输出时钟域做解复位处理。
- CPU先加载FPGA,再拉 FPGA复位管脚,后等待DLY_X解复位 FPGA,再初始化片外锁相环。此操作有可能导致 FPGA CDR自校正过程被异常打断,且初始化片外锁相环后又不对 FPGA相应时钟域进行复位,可能带来异常可靠性风险。
【解析】
如果先加载FPGA,再对FPGA进行复位,再解复位。就有可能导致FPGA加载后,由于没有复位信号,CDR等自校准过程就自动开始,但在校准过程中,可能CPU对FPGA发起复位操作,导致自校准过程异常打断,进而影响逻辑功能。同时FPGA从解复位->复位->解复位的过程,可能导致FPGA输出的管脚时序相对于片外器件是异常时序,可能导致片外对端器件挂死的可能。
片内复位方案
复位方式
同步复位
同步复位代码如下,编码方式必须是if/else 优先级的方式,而且复位信号只能作为if条件,其他逻辑放到else条件下。复位信号只会在时钟的有效边沿生效,去影响或者复位flip-flop。
always @ (posedge clk) begin
if (rst_n==1'b0) begin
q <= 1'd0;
end else begin
q <= d;
end
end
优点:同步复位确保电路100%是同步的,可以对复位信号进行时序分析,可以滤除复位信号的毛刺(脉宽小于一个时钟周期)。
缺点:复位时需要相应时钟域的时钟,否则无法复位。复位信号有效时间必须大于时钟周期。
异步复位
异步复位如下,复位信号出现在敏感列表中,编码方式必须是if/else 优先级的方式,复位信号只能作为if条件,而且有效电平类型必须与敏感列表的沿类型匹配。
always @ (posedge clk or negedge rst_n) begin
if (rst_n==1'b0) begin
q <= 1'd0;
end else begin
q <= d;
end
end
优点:可以实时复位,复位时无需时钟。
缺点: 复位信号释放(release)的时候容易出现亚稳态,复位信号容易受到毛刺的影响。
如需复位,Xilinx 建议使用同步复位。同步复位相比于异步复位具有如下优势:
• 同步复位可以直接映射至器件架构中的更多资源元件。
• 异步复位会影响通用逻辑结构的最大时钟频率。由于所有 Xilinx 器件的通用寄存器均可将置位/复位编程为异步或同步,可能看似使用异步复位不会受到任何面积消耗。使用全局异步复位并不会增加控制集,但由于需要将此复位信号布局到所有寄存器元件,因此会增加布线复杂性。
• 复位断言有效期间,异步复位导致块 RAM、LUTRAM、以及 SRL 的存储器内容损坏的可能性更高。对于含异步复位(用于驱动块 RAM、LUTRAM 和 SRL 的输入管脚)的寄存器尤其如此。
• 需要更高密度或者微调布局时,同步复位会为控制集重新映射提供更多的灵活性。如果在布局更优化的 slice 中发现不兼容的复位,那么可将同步复位重新映射到寄存器的数据路径。这样即可根据需要减少布线资源使用率并增加布局密度,从而实现正确的适配并改善可实现的时钟频率。
• DSP48 和块 RAM 等部分资源仅包含同步复位以供块内的寄存器元件使用。在与这些元件关联的寄存器元件上使用
异步复位时,可能无法在不影响功能的前提下直接将这些寄存器推断到这些块中。
以下另提供了其他注意事项:
• 对于同步复位的复位小毛刺,时钟会充当滤波器的角色。但如果这些毛刺出现在有效时钟沿附近,那么触发器可能会变为亚稳态。
• 同步复位可能需要扩大脉冲宽度,以确保复位信号脉冲宽度足够容纳时钟沿有效期间存在的复位。
• 使用异步复位时,请务必对异步复位断言无效操作进行同步。虽然在复位断言有效期间可以忽略时钟与复位之间的相对时序,但复位释放必须同步到时钟。不执行复位释放时钟沿同步可能导致亚稳态。复位释放期间,与寄存器的时钟管脚相关的复位管脚必须满足建立时间和保持时间的时序条件。异步复位的建立时间和保持时间条件违例(例如,复位的恢复和移除时序)可能导致触发器变为亚稳态,从而因切换至未知状态而导致设计失败。请注意,此状况与触发器数据管脚的建立时间和保持时间条件违例相似。
如下所示,Slice中寄存器同步复位和异步复位使用的资源是一样的,正如前面章节讲过,同步复位和异步复位都是占用一个Storage Element, Storage Element可以配置为Latch,也可以配置为FDRE和FDCE,而且在7Series手册中也并未提到配置成FDRE或FDCE时是否会占用更多资源,因此在Xilinx FPGA Slice中的寄存器,同步复位和异步复位在资源占用上,并没有区别。
要使用控制集映射,可向已连接到使能信号/复位信号的信号线应用属性,这将强制综合使用 CE/R 管脚。在下图中,使能信号 (en) 只能连接到 1 个触发器。因此,综合工具已将 en 信号连接到逻辑的 FDRE/D 管脚。请注意,CE 管脚已绑定到逻辑 1。
使用数据路径逻辑完成时钟使能实现
要覆盖此默认行为,可使用 DIRECT_ENABLE 属性。例如,下图显示了如何通过将 DIRECT_ENABLE 属性添加到端口/信号来将使能信号 (en) 连接到寄存器的 CE 管脚。
使用 direct_enable 完成专用时钟使能实现
下图显示了 RTL 代码,其中 global_rst 或 int_rst 可将寄存器复位。默认情况下,两者都映射到逻辑的复位管脚椎。
通过数据路径逻辑映射的多个复位条件
在 Xilinx 7 系列器件中,1个Slice内的8个寄存器的control信号相同,不能把具有不同控制信号的触发器打包到同一个 Slice中。对于低扇出复位,这样会给 Slice的总体利用率造成不利影响。在同步复位的情况下,工具会对扇出不大的同步control信号与D端信号进行逻辑运算合并,而不是使用触发器的控制端口,故而可将复位当作控制端口移除。这样就可以把得到的 LUT/触发器对与其它不使用其 SR端口的触发器打包。这样的好处是提高资源利用率:虽然是LUT 使用率虽然会上升,但 Slice 的使用率可以得到改善。从这个角度讲的话,同步复位的资源利用率比异步复位高。另外也可以添加综合约束强制工具将信号连到寄存器的
(* direct_reset = “yes” *) input reset;
(* direct_enable = “yes” *) input ena;
综合选项“control_set_opt_threshold”可以设置产生同步使能端信号的扇出门限。
如果希望使用到DSP48或Block Memory内部的寄存器时,只能使用同步复位。如果 RTL 代码描述的是异步置位/复位,那么综合工具就无法使用这些内部寄存器。作为替代,它将使用 Slice触发器,因为它们能够实现要求的异步置位/复位功能。这样不仅会导致器件利用率降低,还会给性能和功耗造成不利影响。从这个角度讲,同步复位也会比异步复位更节约资源。
下图是基于DSP48的16*16bits乘法器的综合结果,该乘法器输入输出均有使用异步复位的流水线寄存器。由于DSP48模块内部的寄存器只支持同步复位,综合时只能用Slice中的寄存器来实现输入端两级流水线寄存器,输出端则用一个Slice寄存器以及32个LUT2来实现异步复位的功能。
如果将流水线寄存器的复位改为同步复位(或者不要复位),那么综合时便可以充分利用DSP48内部的寄存器,从而节省Slice资源的消耗。改为同步复位综合后的电路如下图所示;可以看到,流水线寄存器全部由DSP48内部的寄存器实现,相比上图的电路有更高的资源利用率,更低的延迟和更低的功耗。
当最优化代码以消除复位时,注释掉复位声明中的条件无法生成期望的结构,反而导致出现问题。例如,下图显示了 3个分别使用异步复位的流水线阶段。如果尝试通过注释掉含复位条件的代码来消除其中 2 个流水线阶段的复位条件,则将启用异步复位(rst 的逻辑取反)。
移除复位的最佳途径是创建独立的顺序逻辑过程,其中一个过程用于复位条件,另一个过程用于非复位条件。为含复位和无复位的寄存器创建独立的过程声明,如下图所示。
另外高扇出复位可以变换为平衡复位树,如下图所示。建议:在全局高扇出信号上使用 MAX_FANOUT 属性会导致复制结果欠佳,与在综合中降低全局扇出限制时类似。因此,Xilinx 建议仅在支持中低扇出的局部信号上的层级内使用 MAX_FANOUT。
切勿复制用于同步跨时钟域的信号的寄存器。如果这些寄存器上存在 ASYNC_REG 属性,将导致工具无法复制这些寄存器。如果同步链扇出极高且复制必须满足时序要求,那么请在不含 ASYNC_REG 约束的同步链之后添加额外的寄存器。下表提供了可能适用于中等性能的 7 系列器件的扇出指南。
如果时序报告表明高扇出信号正在限制设计性能,请考虑使用实现工具选项(例如,opt_design -hier_fanout_limit、place_design 和 phys_opt_design)来复制信号。
总结来说,RTL代码中使用的复位类型对FPGA 底层资源有重大影响,复位电路的设计和选择会在较大程度上影响综合后资源的利用率、延迟和功耗。在编写 RTL 代码的时候,设计人员应根据情况,定制化设计复位的方式,以便工具能够把设计映射到相应的资源上。Xilinx FPGA内的寄存器同时支持同步和异步复位,但同步复位可给综合工具更大的灵活性(对于Block Memory、DSP48内的寄存器只支持同步复位;综合工具也可以优化控制集,例如把复位映射到数据路径去)。根据个人项目经验,推荐最好不要复位(例如使用SRL、流水打拍或者数据流单向的数据通路等),对于控制通路需要复位且推荐同步复位(如果实在需要异步复位,则一定要使用异步复位、同步释放的方法);另外优先使用局部复位,低扇出复位信号不会走时钟网络;对于高扇出的全局复位信号布局布线工具会优化其布线延时,会在其路径上插入BUFG走全局时钟网络,使用更多的布线资源,同时增加功耗(全局复位一般具有高扇出,因为它需要扩展到设计中的每一个触发器。这样会消耗大量的布线资源,对器件的利用率和时序性能造成不利影响)。对于内部分频出来的时钟域,可以不用另外增加复位信号,而是直接使用其源时钟域的复位信号。因为其源时钟域的复位信号与分频时钟是可以通过STA保证其相位关系的。
异步复位同步撤离
前面同步复位需要时钟才能正常复位,但异步复位在时钟有效沿附近释放时,就容易使寄存器输出亚稳态。取其精华去其糟粕,结合两者的优点,异步复位同步释放方式应运而生。
reg rst_n_1d;
reg rst_n_2d;
always @ (posedge clk or negedge rst_n) begin
if (rst_n==1'b0) begin
rst_n_1d <= 1'd0;
rst_n_2d <= 1'd0;
end else begin
rst_n_1d <= 1'd1;
rst_n_2d <= rst_n_1d;
end
end
assign rst_n_sync = rst_n_2d;
当rst_n有效时,输出的复位信号rst_n_sync立即有效;当rst_n撤销时,rst_n_sync必须等到时钟上升沿才能撤销,从而保证了rst_n复位不依赖于时钟,同时又能跟时钟信号同步释放。
逻辑自复位
逻辑自复位的目的是防止模块挂死,提升可靠性,常见的自复位:
- serdes自复位,利用serdes接收方向的业务层告警(失步,lof等)复位serdes_rx;
- PLL自复位,利用pll输入时钟丢失告警、pll失锁告警等对pll进行复位。
注意:复位后要等待一段时间后才能再次复位,防止反复自复位。自研模块的挂死问题要从设计上解决,不建议采用自复位方式规避问题
高复位和低复位
采用高复位还是低复位取决于FPGA底层寄存器的复位方式, Altera的寄存器使用低复位,Xiinx寄存器的 SR 控制端口属于高电平有效。如果Xiinx RTL 代码描述的是低电平有效的设置/重设/预设/清除功能,那么综合工具在驱动寄存器的控制端口之前,必须首先推断出一个反相器。由于必须使用查找表来完成反相操作,所以需要一个 LUT 输入。这个因使用低电平有效的控制信号而增加的逻辑可能导致运行时间延长,器件利用率下降。而且它还会给时序和功耗造成不利影响。
那么底线是什么呢?在 HDL 代码或者实例化组件中尽量使用高电平有效的控制信号。在无法控制设计中控制信号的极性的时候,应在代码的最顶层对信号进行反相操作。用这种方法进行描述,推断出的反相器可以并入 I/O 逻辑中,无需占用额外的 FPGA 逻辑或者布线。同时建议代码code中,采用宏定义方式处理,可以同时支持高或低复位:
always @(posedge clk or `RST_EDGE rst) begin
if(rst== `RST_VALUE) begin
…
end else begin
…
end
end
高复位时项目的define文件定义:
define RST_EDGE posedge
define RST_VALUE 1’b1
低复位时项目的define文件定义:
define RST_EDGE negedge
define RST_VALUE 1’b0
硬复位和软复位
根据复位的来源可以分为硬复位(芯片管脚输入)和软复位(内部配置寄存器产生)。
硬复位一般是整芯片甚至芯片组复位(包含PLL等),这个过程可以说是比较简单粗暴的。逻辑加载后由外部芯片产生,要求逻辑外部输入时钟稳定后才能撤销硬复位,并保证硬复位管脚无毛刺。
软复位一般是芯片的部分系统进行复位重启,有时也称为快速复位、动态复位、配置复位,包括:芯片全局软复位 (包括配置寄存器)、全局软复位(不包括配置寄存器)、功能模块软复位。大多是通过一系列的流程来完成的。软复位作用范围是除PLL等以外的模块,是逻辑内部配置产生,分全局软复位和模块级软复位,用于逻辑功能模块初始化,问题界定、分区节能等。软复位是通过软件的程序代码或者寄存器配置等方式触发的复位过程,上述的电路描述是对于管脚硬复位的描述,来自于CPU的软复位信号不需要经过滤毛刺处理,但软复位信号也需要使用相关时钟域的时钟信号进行同步处理。
当软复位被触发时,系统一般需要执行特定的步骤来响应软复位需求,确认进入待复位状态后才会进入复位流程,将系统的内部状态恢复到一个已知的初始状态。软复位通常是在程序执行中的某个特定条件下发生,例如检测到一个错误或者需要重新初始化系统时。
典型的系统软复位流程如下:
1.触发软复位启动条件。这一般是系统内部或SOC出现了致命的错误比如任务执行超时、总线数据错误或安全机制报错等,上位的MCU或者CPU判断需要对该系统进行软复位操作以恢复功能;
2.停止下发任务。判断需要对系统软复位后,应当从任务层停止下发新的任务,避免系统错误进一步的蔓延影响其他进程;
3.下达软复位请求。请求可能通过配置系统的寄存器或者从控制接口下发使能信号;
4.系统接收到软复位的请求后,需要做出一系列的处理。这时一般有两种方向选择,一种是主动停止工作,比如停止执行接下来的取指、在指令或者卷积层边界停止进一步的计算;另一种是被动停止工作,也就是内部逻辑不停止工作,而通过系统边界的模块响应软复位,进而对内部通路进行阻塞或者假握手假接收等行为使内部被动停止工作。
5.系统边界的模块监听所有通路,等待所有已经发出的请求全部收回应答(典型的比如AW请求收回Bresp,AR请求收回Rdata),这样做的目的是避免本系统的复位对SOC或其他系统产生影响,也避免对解除复位后的本系统产生影响(如未收全,本系统复位解除后总线返回了一笔复位前的Bresp,那本系统直接就乱了);
6.边界的模块收全所有应有的返回信息后,或者未能收全但是到达超时阈值后,系统进入待复位状态;
7.此时如果本系统仍然保留着访问DDR和sram的备份通路,那么上位机可以通过配置寄存器去间接访问内存和寄存器进行保留现场。如果没有规划该功能,则略过这一步骤;
8.上位机配置复位保护寄存器使能复位保护电路,避免系统复位过程中有毛刺或者使能信号扩散到总线或其他系统;
9.上位机配置对系统进行时钟降配或者关断时钟等操作,这个是可选操作,一般来说如果复位保护做的比较严格,这里不对时钟进行处理也没关系;
10.配置复位或拉低系统的复位信号,持续一段时间,这个时间没有太严格的要求,按毫秒计时也没有关系,少的话也得几十拍确保系统内所有寄存器都完成了复位;
11.复位已经完成,之后配置解复位或拉高系统的复位信号,解除系统的复位状态,之后等待一段时间等内部电路稳定下来;
12.配置时钟恢复工作频率或恢复时钟,可选;
13.配置复位保护寄存器解除复位保护,恢复总线连接;
14.可以再等待一段时间后,重新下任务或恢复现场,重启系统完成。
软复位的流程没有特别严格的规定,通常是根据芯片的需求而规划。大抵都遵循停任务 - 收应答 - 断连接 - 复位 - 解复位 - 重连接 - 下任务的思路。
复位滤毛刺
复位信号在使用前一般需要进行消抖处理,也称为复位滤毛刺。复位的抖动可能会导致芯片产生多次复位动作(由于异步复位和时钟无关,任何一个毛刺都可以引起复位,这是一个reset源的问题),给系统带来不确定性和误差。通过消抖,可以消除复位信号的抖动干扰,保证复位信号的可靠性和稳定性,避免系统故障和数据丢失等问题。
如下图:外部输入的复位信号prst_n经过滤除毛刺电路后,接到复位信号寄存器的异步复位控制端口。prst_n只有达到稳定后,才会真正的使rst_n有效,从而进行复位操作。
方案1:寄存器组+或门滤毛刺
如下图所示,寄存器组+或门的方式可以稳定的滤掉毛刺,不会再次引入新的窄脉冲。在或门前放置了N个延时D触发器,就可以滤除N*T(T为消抖时钟的周期)时长以下的复位毛刺信号。对于clk时钟域中的寄存器,可以进行异步复位端removal/recovery的STA分析。但这种方式存在一个巨大隐患,系统复位的时候,需要clk有效,否则复位信号无法正常生成。一旦消抖时钟信号出了什么问题,复位信号将永远无法从消抖电路传递出去,因此消抖时钟一般是晶振时钟或者CPU时钟。
方案2:计数器滤毛刺
第二种方案通过计数器来完成,简单来说就是数一下prst_n连续出现了多少拍低电平。假如需要通过100M消抖时钟来滤除100ns以下的复位抖动,那么prst_n要连续出现10拍低电平才达到100ns的复位标准。将prst_n打两拍rst_n_1d/rst_n_2d进行同步,当rst_n_2d持续达到10拍低电平时,对外输出复位信号rst_n,对应的波形示意如下:
这个消抖方案同样存在上面的问题,时钟是无法CG的。但相对于方案1,可以实现更宽的滤波能力,例如假设要实现滤1us毛刺,方案2只需要7比特计数器即可,但方案1需要100个寄存器相或,会占用更多资源。
方案3:器件延迟+或门滤毛刺
第三种方案采用器件延迟+或门实现,组合逻辑滤毛刺不需要时钟。即使在时钟丢失的情况下,仍然能够通过复位管脚对芯片内的寄存器进行复位,使其处于确定的状态。但这也不是一个很完美的设计,主要原因是器件延迟delay单元的实现,在不同温度不同制程下,delay值可能会不同。另外或门是组合逻辑,本身也容易产生毛刺。
对于多时钟域的复位方案,可以由管脚输入的复位信号经过公共的滤毛刺电路以及脉冲展宽后,利用各个时钟域的时钟分别进行同步,生成各个时钟域内部的复位信号。其中reset_exp目的是做脉冲展宽,让复位信号能够被所有时钟都能采样到;reset_exp必须是寄存器输出。
这种异步复位树,复位时可以将所有的FF都同时复位,但是解复位必须要几个cycle才能完成。这种结构的问题就是,不同层级解复位的时间点可能是不一样的。如果设计要求整个芯片在同一个cycle来解复位,那么就需要对复位同步器做平衡设计,保证到达每个复位终点是同一个时钟。
解复位顺序
模块间的复位顺序
同步撤离这个操作解决的是异步复位可能的亚稳态问题,并不是说能够保证所有的寄存器在同一时间收到复位撤离的操作。在多时钟域时,复位信号到达各个寄存器的时间可能不一致:复位信号在系统内是有很大的扇出的,连接到所有需要复位的寄存器的复位端;这也就导致了复位在系统中的走线特别长,过长的走线又会导致工具在复位信号上增加buffer以提升驱动能力,那么如果时钟频率很高,复位信号最终到达各个寄存器的时间也就无法保证在同一拍。对于大部分多时钟域的设计,解复位的顺序并没有特殊要求;即当前时钟域解复位的时间点,在另一个时钟域的精确时间点并不重要。通常来说,跨时钟域的设计,本身就会带来延时的不确定性。这种情况下,采用上面的复位结构就足够了。但如下两种情况下解复位顺序可能会比较重要:第一,在多个时钟域中存在时钟频率差异比较大的几个时钟时,复位逻辑将会导致某个时钟域先复位完毕,而部分时钟域仍然处于复位状态,由此可能会造成逻辑的错误。第二,设计本身对复位顺序有严格要求。
通常的复位撤离原则:优先释放被动响应的功能电路的复位信号,而对于会主动产生激励的电路(接口、CPU等)需要最后才能撤离复位,避免电路复位撤离后出现功能异常。
- 对于FPGA芯片,可以让复位信号走全局时钟网络,来保证各个模块同时解复位。
FPGA内部逻辑复位由外部管脚直接输入,复位信号经过IBUF后插入了BUFG再route到对应的寄存器的复位端口。由于输入复位管脚分配的是非时钟专用管脚,导致vivado在PR阶段会报错,因此需要加额外的约束才能跑过去。新增额外约束语法为:
set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets rst_b_ibuf/0]
因为复位信号要走全局时钟网络,所以工具把复位信号当成时钟信号处理了,但是信号输入管脚非时钟管脚,所以加这行约束告诉PR工具该信号可以走全局时钟网络。
- 采用如下图所示结构,
时钟和复位信号间的顺序
- 关钟复位
如下图,先解rst_n再开钟,必须rst_n先释放,之后时钟再产生(或者clk_genp打开产生clk)。并且二次复位随时都可以进行,但也必须满足图中时序。这种情况,理论上是可以不用同步释放的。例:rst_n释放->clk_genp打开(产生clk)->工作 ->clk_genp关闭(关闭clk) ->rst_n拉低 ->rst_n释放......
- 开钟复位
如下图,该复位的rst_n可以在clk开启时释放,有可能导致电路内部产生亚稳态。为了避免开钟复位的rst_n释放在clk的上升沿,在电路中加入了同步器,保证了rst_n的释放不在时钟沿,避免了电路中亚稳态的产生。
复位特殊处理
前面讲过,复位走线到达各个寄存器可能不在同一拍,这样会有什么后果呢?这个不能一概而论。有些寄存器之间可能存在依赖关系,如果只部分寄存器被复位或解复位,可能会导致不一致的状态,从而影响系统的正确运行。同时呢,如果复位方案做的不好,某系统进行复位时一部分复位了一部分没有复位,也可能会产生毛刺被未复位的寄存器采样,进而输出影响到其他系统的正常工作。总之呢,复位走线到各个寄存器不在同一拍,可能存在系统稳定性的风险。因此在对复位还需要对系统的复位做一些特殊的处理。
复位保护的基本思路是把系统裹起来:将对模块内部有影响的输入信号mask掉,同时其它对本模块有依赖的信号一直输出ok状态(把所有的对外输出使能、握手这类信号都先和低电平与在一起,保证不管一会发生啥事,都不会有关键信号发生跳变)。保护好之后,再去拉复位信号,过一会再解复位,再等会时间等系统稳定下来了,再把保护电路解除开始正常工作。
其他要点
- 片外复位信号释放前,片内应该一直处于复位状态。需要对片外复位信号进行滤毛刺处理,同时需要对复位进行做展宽处理。芯片加载后默认处于复位状态,在片外复位信号撤销前,不产生任何异常解复位行为。
【解析】
片外复位信号释放前,片内应该一直处于复位状态。芯片加载后默认处于复位状态,在片外复位信号撤销前,不产生任何异常解复位行为,即芯片内部复位信号应该是启动->复位->解复位状态,而不应该是启动->解复位->复位->解复位状态,或者其他复位流程状态。
同时需要对复位进行做展宽处理,即经过滤波处理后认为有效的复位信号,输出给后级做全局复位使用,需要对此信号做展宽处理,满足芯片对最小复位信号宽度的要求(FPGA的PLL等的复位都需要满足一定时间要求)。
- 如果有全局复位信号,可以使用时钟网络的布线资源
我们对复位常用的做法是将系统中的每个FF都连接到某个复位信号,但这样就造成了复位信号的高扇出,高扇出就容易导致时序的违规。而且全局复位占用的资源比我们想象中要高的多:布线资源占用;其他网络的布线空间就相应减少;可能会降低系统性能;增加布局布线时间;逻辑资源占用;占用FF作为专门的复位电路;如果该复位信号还受其他信号控制,会导致FF的输入前增加门电路;会增加整个设计的size;增加的逻辑资源会影响系统性能;增加布局布线时间;全局复位不会使用像SRL16E这种高效结构;在LUT中SRL16E可当作16个FF;这些Virtual FF不支持复位;增加设计的size,并降低系统性能;因此,Xilinx推荐尽量使用局部复位的方式。
但是,前面也讲过,要不要复位,要怎么样的复位,都是取决于具体的应用和设计方案的。如果确实需要全局复位信号,一般FPGA器件中没有复位信号的专用布线资源,为了提高资源利用率并获得更好的时序,我们可以用时钟网络的专用布线资源。
- 锁相环失锁后,推荐对锁相环输出时钟域进行复位处理。
【解析】
锁相环失锁后,推荐对锁相环输出时钟域进行复位处理,复位信号持续到锁相环锁定后的一段时间才撤销(确保时钟真正稳定)。在释放复位信号之前一定要确保时钟是锁定的(可以对pll_locked延迟一段时间后,再解复位)。如果时钟还没锁定就释放复位信号,可能会导致寄存器复位失败进入亚稳态。
全局复位信号复位芯片,需要同时复位锁相环,全局复位撤销后,锁相环过一段时间才锁定,锁相环输出时钟域的复位信号,要等锁相环输出时钟完全稳定后才撤销,即锁相环的复位信号撤销要慢于全局复位信号。
- RAM/ROM的地址、数据、控制线的复位信号,必须是同步复位同步解复位。
【解析】
ROM 或 RAM(存在初始值场景),相关输入信号(addr,rden、wren等)的复位信号,其产生机制必须是同步复位和同步解复位。当前逻辑复位信号产生习惯使用异步复位和同步解复位。由于复位信号的产生是异步复位同步解复位,时序分析只能分析复位释放时刻的时序,无法分析到异步复位生效时刻的时序,所以异步复位生效时刻会引起寄存器短暂亚稳态的风险,该风险会引起 ROM 或RAM(存在初始值场景)数据可能被改写。所以 ROM 或 RAM(存在初始值场景),其相关输入信号(addr,rden、wren、byteena 等)的复位信号产生机制必须是同步复位和同步解复位,保证 ROM/RAM 相关控制寄存器在复位生效和释放时刻都不会引入亚稳态。因此复位信号产生或解复位的过程,都必须同步到地址、数据、控制线的时钟域。常规做法是采用地址、数据、控制线的时钟域时钟,对复位信号进行打拍同步处理。
如上图的addr 寄存器的复位信号reset_n,如果 pll_locked_signal信号是 clk时钟域,则 reset_n 产生是同步复位和同步解复位。如果 pll_locked_signal信号不是clk时钟域,则 reset_n 产生是异步复位和同步解复位,异步复位会导致读地址addr的跳变,此跳变与时钟之间的关系是完全异步的,从而无法保证RAM内部的输入寄存器满足建立时间和保持时间,即内部寄存器在异步复位的时刻可能产生亚稳态:地址亚稳态导致多个存储单元被选中,形成短路,存储单元的值因为充放电而发生改变。
解决措施:
方法一:ram的地址和写使能信号去掉复位控制;
方法二:ram的地址和写使能信号使用同步复位方式实现软复位,即将 reset_n同步到clk时钟域,再送给addr寄存器的使能端,这样同步后的复位信号也是同步复位,同步解复位,此时使用最安全。
厂家解释如下:
IMPORTANT: The setup/hold time of the block RAM address and write enable pins must not be violated. Violating the address or write enable setup/hold time (even if write enable is Low) can corrupt the data contents of the block RAM, This most commonly occurs when flip-flops driving block RAM control pins are asynchronously reset, such as a system wide reset. To avoid this issue, design with svnchronous resets only for both assertion and deassertion.
- SERDES的CDR 上电校准操作,如果校准操作已经开始,则不能被复位信号中途打断。
【解析】
SERDES的CDR上电校准操作,只在FPGA加载后进行一次(解复位后进行一次),如果此过程被异常打断(校准过程中对其进行复位),则无法恢复,会导致SERDES接收CDR永久异常,重新恢复的办法只能重新加载FPGA。
- 随路时钟域信号的复位方案需要确保随路时钟域信号得到可靠的复位。
【解析】
随路时钟可能在系统初始化后才输出,此时复位信号已经产生并结束,如果采用同步复位同步解复位,则很有可能随路时钟错过系统复位信号,导致无法复位。
推荐对随路时钟域信号采用异步复位同步解复位方式,同时对初值有要求的信号,建议定义寄存器时给初值,而不依靠复位信号给初值。如ESPI的CPU接口,系统复位撤销后ESPI时钟可能还没有送到。如果ESPI接口时钟域的复位信号采用同步复位同步解复位,则很有可能采集不到系统复位信号,从而无法对ESPI接口寄存器进行初始化。
推荐方式
reg [5:0] count = 'd19;
不推荐方式:
always @ (posedge clk_sys or posedge rst_sys) begin
if( rst_sys == 1’b1)
hsi_send_cnt <= 6’d19;
…
end
- FPGA片内复位过程,不能导致FPGA输出管脚送出杂乱时序影响对端器件。
【解析】
FPGA片内复位过程,不能导致FPGA输出管脚送出杂乱时序,影响对端器件。需要仔细分析复位过程,不能因复位导致FPGA管脚输出杂乱时序给对端器件,对端器件可能因杂乱时序导致挂死。
- FPGA片内复位信号,必须同步到各时钟域使用,每个时钟域必须有自己的独立复位信号
【解析】
FPGA片内复位信号,必须同步到各时钟域使用,每个时钟域必须有自己的独立复位信号。不能使用某一个复位信号,给所有的时钟域进行复位。同时需要分析各时钟域对复位信号撤销是否有时间要求,如果有要求则必须严格控制复位信号撤销的顺序。
复位举例
管脚输入的硬复位hard_rst_n经过cpu时钟滤毛刺、同步、延迟后上bufg,驱动芯片内的所有需要硬复位的模块(pll,cib等); cib_base是全局配置模块,产生全局软复位(rst_sft_glb_n)和各子模块的独立软复位信号(rst_sft_a_n、rst_sft_b_n、…)。
软复位信号经clk_cpu(受hard_rst_n复位,后面会做跨时钟域,crg_top必须是寄存器输出,为了方便布线,一般会采用2级寄存器)寄存后,再同步化到各子模块的处理时钟域,最后控制各子模块的复位(如果各个子模块的扇出较大,crg_top的输出也可以先上BUF)。