一、导言
在具体讨论同步复位和异步之前,我们先提出一些基本原则以及涉及到的问题,在系统中使用同步复位还是异步复位?他们各有什么优劣?如何处理这些劣势?每个触发器都需要实现复位吗?如何在复杂多时钟域应用复位?怎么处理复位信号的毛刺?有很多相关的问题需要讨论,我想深入讨论这些问题有助于理解系统设计的很多关键点。
二、复位目的
一句话概述,复位是为了系统进入一个确定的状态。
三、Flip-Flop的编码风格
每个Verilog 的时序模块和VHDL的Process都应该使用一种FF,即不要混合带复位的FF和不带复位的FF,例一a、例一b显示的Verilog和VHDL代码都是通过同步复位的方式复位一个FF,但另一个FF并没有被复位,会让rst_n成为第二个FF的enable信号,那么设计模块就引入了无关的逻辑,如图一。相对较好的处理方式,例二a、例二b,将两个FF放入不同always和process中,产生的电路图也没有多余的逻辑,如图二。
module badFFstyle ( output reg q2, input d, clk, rst_n); reg q1; always @(posedge clk) if (!rst_n) q1 <= 1'b0; else begin q1 <= d; q2 <= q1; end endmodule
例一a、一个模块中含有不同类型的FF的Verilog代码
library ieee; use ieee.std_logic_1164.all; entity badFFstyle is port ( clk : in std_logic; rst_n : in std_logic; d : in std_logic; q2 : out std_logic); end badFFstyle; architecture rtl of badFFstyle is signal q1 : std_logic; begin process (clk) begin if (clk'event and clk = '1') then if (rst_n = '0') then q1 <= '0'; else q1 <= d; q2 <= q1; end if; end if; end process; end rtl;
例一b、一个模块中含有不同类型的FF的VHDL代码
图一、产生无关逻辑的电路
module goodFFstyle ( output reg q2, input d, clk, rst_n); reg q1; always @(posedge clk) if (!rst_n) q1 <= 1'b0; else q1 <= d; always @(posedge clk) q2 <= q1; endmodule
例二a、处理不同类型FF的合适方法的Verilog代码
library ieee; use ieee.std_logic_1164.all; entity goodFFstyle is port ( clk : in std_logic; rst_n : in std_logic; d : in std_logic; q2 : out std_logic); end goodFFstyle; architecture rtl of goodFFstyle is signal q1 : std_logic; begin process (clk) begin if (clk'event and clk = '1') then if (rst_n = '0') then q1 <= '0'; else q1 <= d; end if; end if; end process; process (clk) begin if (clk'event and clk = '1') then q2 <= q1; end if; end process; end rtl;
例二a、处理不同类型FF的合适方法的VHDL代码
图二、没有将复位信号引入第二个FF
但请注意,例一a、例一b,产生的无关逻辑是因为使用同步复位的结果,如果使用异步复位的方法,例一例二的代码都会得到同一种电路,不同风格的代码生成的电路很大程度取决于敏感列表和if-else语句。
四、同步复位
同步复位有个基本的前提,复位信号永远是在时钟的触发边沿才有效,复位可以作为组合逻辑的一部分作用于触发器,为触发器生成 d 输入。如果是这种情况,则对复位进行建模的编码样式应该是 if/else 更优先使用,在 if 条件中具有复位,在 else 部分中包含所有其他组合逻辑。如果不严格遵守这种风格,可能会出现两个问题。首先,在一些仿真器中,根据逻辑方程,逻辑可以阻止复位到达触发器。尽管这只是一个模拟问题,而不是硬件问题,但请记住,复位的主要目标之一是将 ASIC 置于已知状态以进行仿真。其次,由于复位树的高扇出,复位可能是相对于时钟周期的“迟到信号”。尽管复位将从复位缓冲树中缓冲,但明智的做法是限制复位到达本地逻辑后必须遍历的逻辑量。这种同步复位方式可用于任何逻辑或库。示例 3 显示了这种同步复位作为带进位的可加载计数器的一部分的实现。
module ctr8sr ( output reg [7:0] q, output reg co, input [7:0] d, input ld, clk, rst_n); always @(posedge clk) if (!rst_n) {co,q} <= 9'b0; // sync reset else if (ld) {co,q} <= d; // sync load else {co,q} <= q + 1'b1; // sync increment endmodule
例三a、Verilog-2001 代码,用于同步复位的可加载计数器
library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; entity ctr8sr is port ( clk : in std_logic; rst_n : in std_logic; d : in std_logic; ld : in std_logic; q : out std_logic_vector(7 downto 0); co : out std_logic); end ctr8sr; architecture rtl of ctr8sr is signal count : std_logic_vector(8 downto 0); begin co <= count(8); q <= count(7 downto 0); process (clk) begin if (clk'event and clk = '1') then if (rst_n = '0') then count <= (others => '0'); -- sync reset elsif (ld = '1') then count <= '0' & d; -- sync load else count <= count + 1; -- sync increment end if; end if; end process; end rtl;
例三b、VHDL代码,用于同步复位的可加载计数器
图 3 – 带同步复位的可加载计数器
4.1 编码风格和示例电路
复位信号不应该在敏感列表中,示例四展示正确的复位方式,Verilog只要不在敏感列表写复位信号即可,VHDL是时钟上升沿(clk’event and clk = ‘1’,这是1998版支持写法)或者(rising_edge(clk),2008版新支持的写法)之后处理复位信号,如例四b所示代码。
module sync_resetFFstyle ( output reg q, input d, clk, rst_n); always @(posedge clk) if (!rst_n) q <= 1'b0; else q <= d; endmodule
例四a,Verilog同步复位
library ieee; use ieee.std_logic_1164.all; entity syncresetFFstyle is port ( clk : in std_logic; rst_n : in std_logic; d : in std_logic; q : out std_logic); end syncresetFFstyle; architecture rtl of syncresetFFstyle is begin process (clk) begin if (clk'event and clk = '1') then if (rst_n = '0') then q <= '0'; else q <= d; end if; end if; end process; end rtl;
例四b,VHDL同步复位
同步复位带来一个问题,编译器没有办法区分复位信号和其它的信号。
4.2 同步复位的优势
同步复位可以综合出更少的FF,尤其是复位信号通过门逻辑生成dff的输入,当处于这种情况的时候,也会增加组合逻辑的数量,所以总的资源的数量节约可能不明显。但坦白说,按照目前的FPGA/ASIC的资源裕量,这些资源的节约几乎不值一提。
同步复位能够保证电路是100%同步的。
同步复位确保复位只发生在时钟的有效边沿(一般是上升沿),时钟也能充当复位信号小毛刺的滤波器,但如果毛刺发生在时钟边沿,可能会让复位信号进入亚稳态。这其实和其它数据信号违反建立时间和保持时间而导致亚稳态的情况一样。
在有些设计中,复位信号由内部某些情况下产生,那么建议在这种情况下使用同步复位,可以过滤掉小的毛刺。
通过使用同步复位和预定数量的时钟作为复位过程的一部分(因为是同步复位,时钟沿来才会复位,所以复位需要保持一定的时间,所以复位信号需要的时间需要预设一定的时钟周期),可以在复位缓冲树中使用触发器来帮助缓冲树的时序保持在一个时钟周期内。
4.3 同步复位的劣势
并非所有 ASIC 库都具有内置同步复位的触发器。但是,由于同步复位只是另一个数据输入,因此实际上也并不需要特殊的触发器。复位逻辑可以很容易地在触发器本身之外综合。
同步复位可能需要一个时钟计数器来保证复位脉冲宽度足够宽,以确保在时钟的有效边沿期间出现复位。这是进行多时钟设计时需要考虑的重要问题。可以使用一个小计数器来保证一定周期数的复位脉冲宽度。
就其本质而言,同步复位需要一个时钟来复位电路。这对某些设计风格来说可能不是缺点,但对有些设计风格来说,这可能是一个麻烦。例如,如果有一个门控时钟来节省功耗,则该时钟可能会在复位断言时被禁用。在这种情况下,只有异步复位会起作用,因为复位可能会在时钟恢复之前被移除。
如果 ASIC/FPGA 具有内部三态总线,则需要时钟来引起复位条件。为防止芯片上电时内部三态总线上的总线争用,芯片应具有上电异步复位功能(见图 4)。可以使用同步复位,但还必须使用复位信号直接取消断言三态使能(见图 5)。这种同步技术的优点是复位到 Hi-Z 路径的时序分析更简单。
图4、输出使能的异步复位
图5、输出使能的同步复位
五、异步复位
数字逻辑设计中异步复位的不当实现会导致严重的操作设计失败。许多工程师喜欢能够将复位应用于他们的电路并使逻辑进入已知状态。异步复位的最大问题是复位释放,也称为复位移除。异步复位触发器在触发器设计中包含一个复位引脚。复位引脚通常为低电平有效(当连接到触发器复位引脚的信号变为逻辑低电平时,触发器进入复位状态)。
5.1 编码风格和示例电路
对于Verilog而言,仅需要在敏感列表中包含复位信号即可,但VHDL除了敏感列表有复位信号以外,还需要按照例五b的代码风格,即if后reset(reset优先于其它分配包括时钟),elsif包含其它逻辑。对于Verilog语言而言,如果敏感列表包含除时钟和复位信号以外的信号,这就属于非法的综合编码风格,仿真模型对于触发器将不正确,并且 Synopsys 在读取综合模型时会报告错误。(这是对 Synopsys而言,但Verilog敏感列表不建议出现时钟复位以外的信号)
module async_resetFFstyle ( output reg q, input d, clk, rst_n); // Verilog-2001: permits comma-separation // @(posedge clk, negedge rst_n) always @(posedge clk or negedge rst_n) if (!rst_n) q <= 1'b0; else q <= d; endmodule
例五a,异步复位的Verilog代码
library ieee; use ieee.std_logic_1164.all; entity asyncresetFFstyle is port ( clk : in std_logic; rst_n : in std_logic; d : in std_logic; q : out std_logic); end asyncresetFFstyle; architecture rtl of asyncresetFFstyle is begin process (clk, rst_n) begin if (rst_n = '0') then q <= '0'; elsif (clk'event and clk = '1') then q <= d; end if; end process; end rtl;
例五b,异步复位的VHDL代码
5.2 异步复位的优势
使用异步复位的最大优势在于,只要具有可异步复位的触发器,就可以保证数据路径是干净的(相比较于同步复位)。如果为处理同步复位而插入的逻辑,那些正在推动数据路径时序极限的设计无法承受在数据路径中增加门和额外的网络延迟。使用异步复位,设计人员可以保证不会将复位添加到数据路径中。示例 6 中的代码推断不会添加到数据路径中的异步复位。
module ctr8ar ( output reg [7:0] q, output reg co; input [7:0] d; input ld, rst_n, clk; always @(posedge clk or negedge rst_n) if (!rst_n) {co,q} <= 9'b0; // async reset else if (ld) {co,q} <= d; // sync load else {co,q} <= q + 1'b1; // sync increment endmodule
例六a、具有异步复位功能的可加载计数器的 Verilog-2001 代码
library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; entity ctr8ar is port ( clk : in std_logic; rst_n : in std_logic; d : in std_logic; ld : in std_logic; q : out std_logic_vector(7 downto 0); co : out std_logic); end ctr8ar; architecture rtl of ctr8ar is signal count : std_logic_vector(8 downto 0); begin co <= count(8); q <= count(7 downto 0); process (clk, rst_n) begin if (rst_n = '0') then count <= (others => '0'); -- async reset elsif (clk'event and clk = '1') then if (ld = '1') then count <= '0' & d; -- sync load else count <= count + 1; -- sync increment end if; end if; end process; end rtl;
例六b、具有异步复位功能的可加载计数器的 VHDL 代码
图5- 具有异步复位的可加载计数器
对于异步复位,还有一个优势是,在没有时钟的情况下也可以完成复位。
5.3 异步复位的劣势
异步复位的最大问题是它们是异步的,无论是在复位时还是在复位时。断言不是问题,反断言是问题。如果在触发器的有效时钟边沿或附近释放异步复位,则触发器的输出可能会进入亚稳态,因此 ASIC/FPGA 的复位状态可能会丢失。
异步复位可能存在的另一个问题(取决于其来源)是由于电路板上的噪声或毛刺或系统复位引起的虚假复位。如果这是系统中的一个真正问题,那么人们可能会认为使用同步复位是解决方案。如果这些虚假复位脉冲发生在时钟边沿附近,则同步复位存在一个不同但相似的问题,触发器仍然可以达到亚稳态(但对于任何违反设置要求的数据输入都是如此)。
六、异步复位问题
太多工程师只是应用异步复位,认为没有问题。他们在受控仿真环境中测试复位,一切正常,但随后在系统中,设计间歇性失败。设计人员没有考虑在系统(非受控环境)中释放复位可能导致芯片进入亚稳态未知状态,从而使复位全部无效的想法。必须注意reset的释放,防止reset释放时芯片进入亚稳态未知状态。当使用同步复位时,复位的前沿和后沿都必须远离时钟的有效沿。
如图 6 所示,异步复位信号将与时钟信号异步解除。这种情况有两个潜在的问题:(1) 违反复位恢复时间,(2) 复位移除发生在不同时序元件的不同时钟周期内。
图六、异步复位移除/恢复时间问题
6.1 复位恢复时间
恢复时间是作为异步控制信号在时钟有效边沿转换之前必须稳定的最短时间。换句话说,该检查确保在异步信号变为非活动状态后,有足够的时间进行恢复,以便下一个活动时钟沿有效,类似setup time。(注意讨论的是复位从活跃转为非活跃,也就是反断言,下面两个图一个rst_n,一个rst)
低有效复位
6.2 复位移除时间
移除时间是在时钟有效边沿转换后异步控制必须保持稳定的最短时间长度。该检查确保活动时钟边沿无效,因为异步控制信号保持活动状态直到活动时钟边沿之后的移除时间,类似holdup time。
高有效复位
七、复位同步器
指南:每个使用异步复位的 ASIC 都应该包括一个复位同步器电路!!
如果没有复位同步器,即使复位在仿真期间工作,最终系统中异步复位的用处也是无效的。图 7 的复位同步器逻辑旨在利用异步和同步复位方式的最佳优势。
图七、复位同步器框图
外部复位信号复位(异步复位)一对主复位触发器,后者又通过复位缓冲树异步驱动主复位信号到设计中的其余触发器,整个设计将被异步复位。
复位移除是通过反断言复位信号来完成的,然后允许第一个主复位触发器(连接为高电平)的 d 输入通过复位同步器计时。复位移除后通常需要两个时钟上升沿来同步主复位的移除。
需要两个触发器来将复位信号与时钟脉冲同步,其中第二个触发器用于消除可能因复位信号被异步消除且太靠近时钟上升沿而引起的任何亚稳态。
图八、可预测的复位移除以满足复位恢复时间
现在仔细检查时序表明,复位分布时序是 clk-to-q 传播延迟、通过复位分布树的总延迟以及满足目标寄存器和触发器的复位恢复时间的总和,如图所示 在图 8 中。
module async_resetFFstyle2 ( output reg rst_n, input clk, asyncrst_n); reg rff1; always @(posedge clk or negedge asyncrst_n) if (!asyncrst_n) {rst_n,rff1} <= 2'b0; else {rst_n,rff1} <= {rff1,1'b1}; endmodule
例七a、使用 Verilog-2001 正确编码的复位同步器
library ieee; use ieee.std_logic_1164.all; entity asyncresetFFstyle is port ( clk : in std_logic; asyncrst_n : in std_logic; rst_n : out std_logic); end asyncresetFFstyle; architecture rtl of asyncresetFFstyle is signal rff1 : std_logic; begin process (clk, asyncrst_n) begin if (asyncrst_n = '0') then rff1 <= '0'; rst_n <= '0'; elsif (clk'event and clk = '1') then rff1 <= '1'; rst_n <= rff1; end if; end process; end rtl;
例七b、使用 VHDL 正确编码的复位同步器
7.1 复位同步器亚稳态
复位同步器不会有亚稳态问题。
复位同步器的第一个触发器确实存在潜在的亚稳态问题,因为输入被拉高,输出被异步复位为 0,并且可以在触发器指定的复位恢复时间内移除复位(复位可能会在接近同一触发器的时钟输入的上升沿时变高)。这就是为什么需要第二个触发器的原因。
复位同步器的第二个触发器不受恢复时间亚稳态的影响,因为复位时触发器的输入和输出都为低电平。触发器的输入和输出之间没有逻辑差异,因此输出不可能在两个不同的逻辑值之间振荡。
关于亚稳态去毛刺问题,参阅编码风格这篇文章
总结:文章基本到这里就算结束,但原文还有其它的部分描述,感兴趣的可以找原文阅读,对于复位的相关问题,这篇文章算是很经典的论文,比较值得看,推荐大家看英文版原文。
FPGA交流2群(Q群):327133229
这篇文章主要来自Clifford E. Cummings的论文:Asynchronous & Synchronous Reset Design Techniques – Part Deux
没有回复内容