FPGA杂记(三)

一、时序浅谈

时序路径是两个节点的连接,如一个寄存器的输出到另一个寄存器的输入。
Edge paths(边缘路径):从端口(port)到引脚(pin),引脚到引脚,以及引脚到端口的连接。
clock paths(时钟路径):从器件端口或内部产生的时钟引脚到寄存器的时钟引脚之间的路径。
Data paths(数据路径):从一个端口或一个时序电路的数据输出引脚,到另一个端口或者另一个时序电路的数据输入引脚之间的连接。
Asynchronous paths(异步路径):从端口到另一个时序电路的异步引脚之间的连接,如异步置位或异步清除。在这里插入图片描述
f_MAX(最大时钟频率):在不违背内部建立时间tSU和保持时间tH要求下可以达到的最大时钟频率。
T_CO(时钟到输出延时):时钟信号在寄存器引脚上发生转变以后,在由寄存器馈送信号的输出引脚上获得有效输出所需的最大时间;
T_PD(引脚到引脚延时):输入引脚上的信号在经由组合逻辑进行处理传输,出现在外部输出引脚上时所需的时间;
T_SU(建立时间):是指在时钟沿到来之前数据从不稳定到稳定所需的时间,如果建立的时间不满足要求那么数据将不能在这个时钟上升沿被稳定的打入触发器。在这里插入图片描述
T_H(保持时间):是指数据稳定后保持的时间,如果保持时间不满足要求那么数据同样也不能被稳定的打入触发器。在这里插入图片描述
Launch Edge Time(启动沿时刻):时序分析起点(launch edge):指的是一个时钟沿,这个时钟沿将一个寄存器或一个时序电路的数据送出,即第一级寄存器数据变化的时钟边沿,因此这个时钟沿充当数据传输的源,即静态时序分析的起点,只是一个开始时刻的概念。
Latch Edge Time(锁存沿时刻):时序分析终点(latch edge):指的也是一个时钟沿,这个时钟沿将一个寄存器或一个时序电路的输入端口的数据锁存起来,即数据锁存的时钟边沿,因此这个时钟沿充当数据传输的目的,也是静态时序分析的终点,同样只是一个结束时刻的概念。在这里插入图片描述
蓝色的启动沿(即Launch Edge Time时刻)之后由REG1输出有效数据,并在红色的边沿被锁存(即锁存沿时刻)进REG2并输出到下级。一般时序分析,就是分析的从启动沿到锁存沿之间的时间,看是否满足需求。在这里插入图片描述
理解上图,launch edge在0ns将数据data_a从寄存器REG1输出,但是注意,这并不意味着data_a在0ns就从REG1中输出,这儿存在一个延迟,这个延迟指的是当时钟有效沿变化后,将数据推倒同步时序路径的输出端的最小时间间隔,即utCO。数据data_a顺着路径传递到REG2,REG2在10ns处的latch edge捕捉data_a。显然在10ns处的data_a必须到达REG2,因此这就是一个数据建立的时间关系,也就是图中红线所谓的Setup Relationship。

如何理解图中的Hold relationship呢?显然,图中所指示的Hold relationship并不是与当前这个数据(data_a,就是0ns要launch的数据,或10ns要latch的数据)有保持关系,而是上一个数据(比如data_b)的Hold关系。

Data Arrival Time(数据到达时间) : TimeQuest计算数据到达时间,包括以下4部分时间之和:启动沿时间(Launch Edge Time)、从时钟源到源寄存器的时钟pin的延迟(Source Clock Delay)、时钟源寄存器的micro clock-to-output延迟(utCO,这个时间指的是当时钟有效沿变化后,将数据推倒同步时序路径的输出端的最小时间间隔。)以及从源寄存器的数据输出Q到目的寄存器的数据输入D的延迟(Register-to-Register Delay)。在这里插入图片描述

Data Arrival Time = Launch Edge + Source Clock Delay + μtCO + Register-to-Register Delay

eg:
在这里插入图片描述
T_clk1(即从时钟源到源寄存器的时钟pin的延迟,Source Clock Delay):时钟信号从起点(一般是PLL输出或者外部时钟输入引脚)到达启动寄存器(或说启动触发器)的相应clk端口所耗的时间。假如CLK是由PLL发出的时钟信号(称之为源时钟),这个信号经过FPGA内部的“连线”最终来到了REG1(启动触发器)的clk端,所以此时在REG1的clk端口处也会有周期性的时钟信号REG1.CLK,如图所示;可以看到,此时的CLK(源时钟)和REG1.CLK实际上有个时间差(相位差),这个时间差就是Tclk1;

T_CO:启动寄存器内部延时,是寄存器REG1在接收到有效的上升沿后,到数据真正从从REG1的Q输出之间延时,这是内部寄存器的固有属性,一般取最小值,即文档中的μtCO;请注意:上述所谓的有效的上升沿,就是REG1.CLK,而不是CLK;所以实际的有效数据输出的时序如上图的REG1.Q;

T_data(即Register-to-Register Delay):数据从上级寄存器输出Q(经过所有其他组合逻辑以及FPGA内部走线)到下级寄存器的数据输入D之间的延时;如图所示,数据从从REG1的Q流向了REG2的D,所以REG2.D实际接收到的数据时序是REG2.D,注意这里没有涉及到REG2的锁存;

假如将上图中的launch Edge作为0点时刻,将一系列的延时累加,所得结果称之为数据到达时间,DAT:

DAT= T_clk1+T_co+T_data;

Data Required Time(数据要求时间) TimeQuest计算数据要求时间,包括以下3部分时间:锁存沿时间(Latch Edge)、时钟端口到目的寄存器的时钟引脚之间的所有延迟(这包括时钟端口所有缓冲的延迟,Destination Clock Delay)、减掉目标寄存器的最小建立时间(μt_SU,这是FPGA内部寄存器的固有属性)。

Data Required Time = Latch Edge + Destination Clock Delay – μt_SU

数据建立要求时间
在这里插入图片描述
T_clk2(即Destination Clock Delay):不同于上述的T_clk1,这个延时是时钟从起点(一般是PLL或者时钟输入引脚)到锁存触发器之间的延时;如上图所示,REG2实际感受到的时钟来自于其本身的clk端口,而不是源时钟CLK,他们之间存在一个延时,即T_clk2;所以REG2实际感受到的时钟,实际上是上图的REG2.CLK;

T_su:上面分析过了,每一个数据被锁存都要满足建立时间和保持时间,T_su就是建立时间,也就是在REG2实际感受到Latch Edge时,数据如果需要被正确锁存,就必须提前Tsu这么长的时间到达REG2的D端口;

综合时钟走线延时Tclk2以及T_su,我们得到了数据建立时间DRT_su:

DRT_su=锁存沿+T_clk2-T_su。

在DRTsu时刻之前,数据必须已经有效且稳定。

数据保持要求时间
在这里插入图片描述

DRTh=锁存沿+T_clk2+T_h;

也就是说,数据在DRT_h时间之前必须保持住不变;

Clock Setup Check(时钟建立检查)在这里插入图片描述
对于每个目标寄存器的锁存沿,TimeQuest analyzer利用源寄存器先前最近的一个时钟沿作为启动沿(launch edge)。举例说明,如上图所示为两个建立关系,建立关系A和建立关系B。10ns处的锁存沿,先前离它最近的源时钟位于3ns处,因此就将该时钟沿作为启动沿,从而确定了建立关系A(图中已表明)。同样,20ns处的锁存沿,它的启动沿是位于19ns处的源时钟沿,从而确定了建立关系B。TimQuest会分析出最严苛的建立关系,在本例中即为关系B。如果关系B都能满足设计需求,那么关系A自然也就满足需求了。

TimeQuest analyzer将时钟建立检查的结果表示为裕量(slack)。裕量是表示是否满足设计需求的时序余量。建立时间裕量指的是数据到达时间和数据建立时间之间的关系,裕量为正,表示余量满足设计需求。为负,则表示余量不满足设计需求。

在这里插入图片描述
如上图所示,在0时刻(launch edge),源时钟clk产生一个上升沿表示准备让REG1发送数据,但是该启动沿并没有马上传到REG1,而是经过了延时Tclk1,所以在T_clk1时刻,REG1才准备发送数据,再经过寄存器内部固有延时Tco,终于在REG1的Q端输出了数据Data_Valid(时序REG1.Q)。Data_Valid再经过内部延时T_data到达REG2的D端(时序REG2.D),所以数据经历了T_clk1+T_co+T_data才到达REG2,这就是我们之前分析的数据到达时间。源时钟CLK在第一个时钟上升沿完成了数据的发送,在第二时钟的上升沿要实现数据的锁存,这个上升沿即为锁存沿(latch edge)。但是源时钟产生的锁存沿要经过T_clk2才能到达REG2,此时REG2要“识别”D端口有没有数据,同时还要判断该数据是否满足建立时间要求和保持时间要求,如果都满足,则REG2能正确锁存该数据。如果REG1的数据传递太慢(没有提前T_su到达),或者消失太快(T_h太短),则都不能稳定接收数据。

Clock Setup Slack =(锁存沿+T_clk2-T_su)-( T_clk1+T_co+T_data)
Clock Setup Slack = Data Required Time – Data Arrival Time

TimeQuest analyzer在执行建立检查时,计算数据到达时间时用最大延迟,而计算数据需求时间是采用最小延迟。

内部寄存器-寄存器时间的时钟建立裕量:

Clock Setup Slack = Data Required Time – Data Arrival Time
Data Arrival Time = Launch Edge + Clock Network Delay to Source Register + μt_CO + Register-to-Register Delay
Data Required Time = Latch Edge + Clock Network Delay to Destination Register – μt_SU – Setup Uncertainty

输入端口到内部寄存器的时钟建立裕量:

Clock Setup Slack = Data Required Time – Data Arrival Time
Data Arrival Time = Launch Edge + Clock Network Delay + Input Maximum Delay + Port-to-Register Delay
Data Required Time = Latch Edge + Clock Network Delay to Destination Register – μt_SU – Setup Uncertainty

内部寄存器到输出端口的时钟建立裕量:

Clock Setup Slack = Data Required Time – Data Arrival Time
Data Required Time = Latch Edge + Clock Network Delay to Output Port – Output Maximum Delay
Data Arrival Time = Launch Edge + Clock Network Delay to Source Register +μt_CO + Register-to-Port Delay

Clock Hold Check(时钟保持检查)
TimeQuest analyzer对每一个建立关系执行两次保持检查。第一次检查确定被当前启动沿推送的数据,但该数据并没有被先前的锁存沿给捕获。第二次检查确定被第二个启动沿推送的数据,但该数据并未被当前的锁存沿给捕获。从所有可能的保持关系中,TimeQuest analyzer选择最苛刻的一个保持关系,它的锁存沿和启动沿之间的差异最小,并且决定了寄存器之间路径的最小延迟。下面的例子中,TimeQuest analyzer选择保持检查A2作为最苛刻的保持关系。在这里插入图片描述
在这里插入图片描述
在分析时钟保持裕量的时候要注意到,之前在分析时钟建立裕量时的锁存沿(latch edge)恰好又是下一个数据的启动沿(launch edge),所以要求新的数据到达REG2之前,REG2要有足够时间将上一个数据Data_Valid正确锁存,这个时间即为时钟保持时间裕量。

Clock Hold Slack = (T_clk1+T_co+T_data)-(锁存沿+T_clk2+T_h)
Clock Hold Slack = Data Arrival Time – Data Required Time

TimeQuest analyzer在执行保持检查时,计算数据到达时间时用最小延迟,而计算数据需求时间是采用最大延迟。

内部寄存器之间路径的时钟保持裕量

Clock Hold Slack = Data Arrival Time – Data Required Time
Data Arrival Time = Launch Edge + Clock Network Delay to Source Register + μt_CO + Register-to-Register Delay
Data Required Time = Latch Edge + Clock Network Delay to Destination Register + μt_H + Hold Uncertainty

输入端口到内部寄存器的时钟保持裕量

Clock Hold Slack = Data Arrival Time – Data Required Time
Data Arrival Time = Launch Edge + Clock Network Delay + Input Minimum Delay + Pin-to-Register Delay
Data Required Time = Latch Edge + Clock Network Delay to Destination Register + μt_H

内部寄存器到输出端口的时钟保持裕量

Clock Hold Slack = Data Arrival Time – Data Required Time
Data Arrival Time = Launch Edge + Clock Network Delay to Source Register + μt_CO + Register-to-Pin Delay
Data Required Time = Latch Edge + Clock Network Delay – Output Minimum Delay

一般而言,在综合之后,我们需要特别关注的是建立时间的时序违例,因为可以通过增加布线长度来保证保持时间。大多数保持时间违例在实现之后自然会被优化掉。

二、复位浅谈

关于复位设计的问题大概有以下几类:
(1)、板子上没有设计按键复位,怎么办?
(2)、怎么设计上电复位?不可能上电都要去按键吧?
(3)、同步复位还是异步复位?各自优势是啥?
(4)、高电平复位还是低电平复位?

常见的复位方式有三种:
(1)、硬件开关:复位信号接一个拨码开关或按键,或者RC电路
(2)、电源芯片:上电时候电源芯片产生,可以长时间维持,直到稳定
(3)、控制芯片:控制芯片产生复位脉冲

合理的复位设计:
(1)、低电平复位并不是最合理的处理方式
(2)、建议采用异步复位同步释放
(3)、全局复位并不是最佳方式
(4)、并不是所有时序电路都要加复位
(5)、复位电平的选择和芯片有关

 //异步复位同步化,Xilinx 7系列,高电平有效
 module rst_signal(
    input       clk,
    input       rst,
    output      sys_rst 
 );
    reg         r1_rst,r2_rst;
  
    always@(posedge clk or posedge rst) begin
        if(rst) begin
            r1_rst <= 1'b1;
            r2_rst <= 1'b1;
        end else begin
            r1_rst <= 1'b0;
            r2_rst <= r1_rst;
        end
    end
 
    assign sys_rst = r2_rst;
    
endmodule

在这里插入图片描述
可以看到,模块将系统输入的异步复位信号进行同步,产生了一个后续逻辑使用的同步化了的异步复位,随后即可将该复位信号sys_rst用于其他模块的复位。为了减少亚稳态对上述同步器中的两个寄存器的影响,这两个寄存器应该在FPGA中被放置的越靠近越好(相应的约束:set_property ASYNC_REG TRUE [get_cells [list r1_rst_reg r2_rst_reg]]),尽量减少布线延迟。

外部输入异步复位信号应该增加滤波和去抖处理;
在复位之前,确保由 MMCM 或PLL 生成的时钟是稳定且被锁定的;
将异步复位信号分别引入不同的时钟域进行同步化

什么时候可以叫复位呢?
类似于移位寄存器这类直通型电路,只起到一个传输信号的作用,本身不会对信号产生任何影响。其传输信号正确与否,在于其输入端的信号是否正确。因此,此类电路自身无需加复位信号,而只需再起输入端口加复位信号(也就是数据来源处的电路),以控制输入数据。

上电初始化?
当一个Xilinx的FPGA芯片被重新配置时,每一个单元都将被初始化。在某种意义上讲,这是一个上电之后的“终极的”全局复位操作,因为它不仅仅是对所有的触发器进行了复位操作,还初始化了所有的RAM单元。随着Xilinx FPGA芯片内部的嵌入式RAM资源越来越多,这种“终极的”全局复位操作越来越有意义。对所有的RAM单元进行预定义,在软件仿真和实际操作中都是非常有帮助的,因为这样避免了在上电时采用复杂的启动顺序来清除存储单元内容的操作。

三、状态机

格雷码:相邻之间只变1bit,编码密度高。
独热码:任何状态只有1bit为1,其余皆为0,编码密度低。

比如说,表示4个状态,那么状态机寄存器采用格雷码编码只需要2bit:00(S0),01(S1),11(S2),10(S3);
采用独热码需要4bit:0001(S0),0010(S1),0100(S2),1000(S3)。

所以很明显采用格雷码可以省2bit寄存器。难理解的是,为什么独热码更节省组合逻辑: 其实很简单,

例一:假如我们要在代码中判断状态机是否处于某状态S1,

对于格雷码的状态机来说,代码是这样的:assign S1 = (STATUS==2’b01);

对于独热码来说,代码是这样的就行:assign S1=STATUS[1];

所以独热码的译码非常简单。

例二:考虑最简单的跳变,当A为1时,状态机会从S0跳到S1:。

采用格雷码写:STATUS[1:0] <= (STATUS==2’h00) & A ? 2’h01 : 2’h00;

采用独热码写:STATUS[1] <= STATUS[0] & A;

有人怀疑这里的逻辑,认为只check独热码的一个bit有问题。当然是没问题的,0110,0011等编码属于不care的编码,在卡诺图化简中,不care的编码可以与其余的有效编码合并化简。实际上综合器也会这么做,所以独热码非常容易化简。

假如说S0跳到S1条件为A;
S1跳到S2条件为B;
S2跳到S3条件为C;
S3跳到S0条件为D;
那么整个状态机化简之后代码就是:
STATUS[0] <= STATUS[3] & D;
STATUS[1] <= STATUS[0] & A;
STATUS[2] <= STATUS[1] & B;
STATUS[3] <= STATUS[2] & C;

总结一下:
独热码适合写条件复杂但是状态少的状态机;
格雷码适合写条件不复杂但是状态多的状态机。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值