亚稳态是违背了触发器的建立和保持时间而产生的。设计中任何触发器都有特定的建立和保持时间,在时钟上升沿前后的这段时间窗口内,数据输入信号必须保持稳定。如果信号在这段时间发生了变化,那么输出将是未知的或者称为“亚稳的”。这种有害的传播就叫做亚稳态。
触发器都会在一个或者两个时钟周期内返回稳态
建立时间:触发器在时钟上升沿到来之前,其数据输入端的数据必须保持不变的最小时间。
保持时间:触发器在时钟上升沿到来之后,其数据输入端的数据必须保持不变的最小时间。
建立时间:Tsetup
保持时间:Thold
触发器从接受到时钟上升沿到触发器输出延迟:Tco
时序逻辑中大量使用D触发器,D触发器的一般结构是:两个串联的反相器加两个传输门构成锁存器,两个锁存器串联构成D触发器。D触发器是一种双稳态电路,两个稳定状态”1“、”0“。两个反向器构成的反馈回路可能会产生亚稳态
如图所示,当在输入数据在亚稳时间窗变化时,Tco增大,在Tco_max之后还没有稳定的情况就是亚稳态。
这也是一个异步电路同步化的问题。亚稳态是指触发器无法在某个规定的时间段内到达一个可以确认的状态。使用两级触发器来使异步电路同步化的电路其实叫做“一位同步器”,他只能用来对一位异步信号进行同步。两级触发器可防止亚稳态传播的原理:假 设第一级触发器的输入不满足其建立保持时间**,它在第一个脉冲沿到来后输出的数据就为亚稳态,那么在下一个脉冲沿到来之前,其输出的亚稳态数据在一段恢复时 间后必须稳定下来,而且稳定的数据必须满足第二级触发器的建立时间**,如果都满足了,在下一个脉冲沿到来时,第二级触发器将不会出现亚稳态,因为其输入端的 数据满足其建立保持时间。同步器有效的条件:第一级触发器进入亚稳态后的恢复时间 + 第二级触发器的建立时间 < = 时钟周期。
关机:第一级输出可能为亚稳态,经过回复时间满足第二级触发器的建立好保持时间。那么亚稳态就消除了,并防止传播
触发器出现亚稳态
(1)建立/保持时间内输入信号不稳定。
(2)时钟脉冲太窄。
(3)异步信号对时钟有效沿是随机的,易产生亚稳态。异步信号包括:不被时钟控制的信号;或被不同时钟域的时钟同步的信号。
异步输入信号的脉冲宽度小于时钟周期时的同步电路(高速时钟域→低速时钟域):脉冲同步器
资料:Verilog基础知识(亚稳态和跨时钟域的同步电路).
能保持两个周期,可以用到复位同步当中
1.对异步脉冲信号的处理——不归0翻转电路
**原理(脉冲扩展):**把在源时钟域,把脉冲信号翻转(翻转条件信号由0变到1),这样单个脉冲就被扩展到电平信号,在同步时钟域抓边沿就行了。
注意:源时钟域的每个脉冲之间(即每个0到1变换上升沿)长度,必须大于同步时钟域的一个时钟周期,这样保证同步时钟域不会漏采,注意:边沿使用异或检测。
2**.反馈设计:很巧妙**:结绳法可以解决快时钟域向慢时钟域过渡的问题,且适用的范围很广
初始状态:寄存器全都为0,目标检测高脉冲,与门 ,或门都为0
原链接握手机制的verilog实现
// 发送模块
module rst_csdn(
input rst_n,
input t_clk,
input ack,
output [7:0] dout,
output reg req
);
reg ack_reg1,ack_reg2;
reg [7:0] data_buf;
reg [2:0]tr_state;
reg [7:0] TR_MEM_Addr;
reg [7:0] TR_MEM [255:0]; //保持寄存器 深度256
parameter TR_IDLE=3'b000, SND_DATA_REQ=3'b001, CHK_ACK_ACTIVE=3'b010, CHK_COMM_END=3'b100;
always@(negedge rst_n or posedge t_clk)
begin
if(!rst_n)begin
ack_reg1 <= 1'b0;
ack_reg2 <= 1'b0;
end
else begin
ack_reg1 <= ack;
ack_reg2 <= ack_reg1;
end
end
//
always@(posedge t_clk or negedge rst_n)
begin
if(!rst_n)
begin
data_buf <= 1'b0;
tr_state <= TR_IDLE;
TR_MEM_Addr <= 1'b0;
end
else
case(tr_state)
TR_IDLE: //初始化状态
begin
req <= 1'b0;
TR_MEM_Addr <= 1'b0;
tr_state <= SND_DATA_REQ;
end
SND_DATA_REQ: //送数据到总线上和发送请求信号
begin
data_buf <= TR_MEM[TR_MEM_Addr];
req <= 1'b1; //发送请求信号,请求信号为高,表示请求接收
TR_MEM_Addr <= TR_MEM_Addr + 1;
tr_state <= CHK_ACK_ACTIVE;
end
CHK_ACK_ACTIVE: //检测应答信号为高,释放请求信号
begin
if(ack_reg2 == 1'b1) //便于时序收敛
begin
req <= 1'b0; //释放请求信号
tr_state <= CHK_COMM_END;
end
else tr_state <= CHK_ACK_ACTIVE;
end
CHK_COMM_END: //检测握手通信结束,如果应答信号被释放,一次握手结束
begin
if(ack_reg2 == 1'b0)
tr_state <= SND_DATA_REQ;
else
tr_state <= CHK_COMM_END;
end
default:tr_state <= TR_IDLE;
endcase
end
assign dout = data_buf;
endmodule
//接收模块
module woshou_rx(
input rst_n,
input r_clk,
input req,
input [7:0] din,
output reg ack
);
reg req_reg1,req_reg2;
reg [2:0] re_state;
reg [7:0] RE_MEM_Addr;
reg [7:0] RE_MEM[255:0];
parameter RE_IDLE=3'b000, CHK_REQ_ACTIVE=3'b001, CHK_REQ_RELEASE=3'b010;
always@(posedge r_clk or negedge rst_n)
begin
if(!rst_n)
begin
req_reg1 <= 1'b0;
req_reg2 <= 1'b0;
end
else
begin
req_reg1 <= req;
req_reg2 <= req_reg1;
end
end
//
always@(posedge r_clk or negedge rst_n)
begin
if(!rst_n)
begin
re_state <= RE_IDLE;
ack <= 1'b0;
RE_MEM_Addr <= 1'b0;
end
else
case(re_state)
RE_IDLE: //初始化状态
begin
RE_MEM_Addr <= 0;
re_state <= CHK_REQ_ACTIVE;
end
CHK_REQ_ACTIVE: //检测发送端的数据发送请求信号
begin
if(req_reg2 == 1) //如果有请求信号,接收数据
begin
re_state <= CHK_REQ_RELEASE;
RE_MEM_Addr <= RE_MEM_Addr + 1;
RE_MEM[RE_MEM_Addr] <= din; //接收数据存放到MEM
ack <= 1'b1; //检测到请求信号,发送接收端应答信号
end
else re_state <= CHK_REQ_ACTIVE;
end
CHK_REQ_RELEASE: //检测请求信号释放,释放应答信号
begin
if(req_reg2 == 0)
begin
ack <= 1'b0; //释放应答信号,一次握手通信结束
re_state <= CHK_REQ_ACTIVE;
end
else re_state <= RE_IDLE;
end
default: re_state <= RE_IDLE;
endcase
end
endmodule
同步电路的速度是指同步系统时钟的速度,同步时钟愈快,电路处理数据的时间间隔越短,电路在单位时间内处理的数据量就愈大。假设Tco是触发器的输入数据被时钟打入到触发器到数据到达触发器输出端的延时时间(Tco=Tsetpup+Thold);Tdelay是组合逻辑的延时;Tsetup是D触发器的建立时间。假设数据已被时钟打入D触发器,那么数据到达第一个触发器的Q输出端需要的延时时间是Tco,经过组合逻辑的延时时间为Tdelay,然后到达第二个触发器的D端,要希望时钟能在第二个触发器再次被稳定地打入触发器,则时钟的延迟必须大于Tco+Tdelay+Tsetup,也就是说最小的时钟周期Tmin =Tco+Tdelay+Tsetup,即最快的时钟频率Fmax =1/Tmin。
提高频率的方法:
时序约束主要包括周期约束,偏移约束,静态时序路径约束三种**。通过附加时序约束可以综合布线工具调整映射和布局布线,使设计达到时序要求。**
附加时序约束的一般策略是先附加全局约束,然后对快速和慢速例外路径附加专门约束。附加全局约束时,首先定义设计的所有时钟,对各时钟域内的同步元件进行分组,对分组附加周期约束
时钟的定义
1.定义一个引脚
2.通过周期和波形的属性描述时钟边沿强鲁昂
3.纳秒为周期,它对应重复波形所需要的时间
4.波形是时钟周期内以纳秒描述的上升沿和下降沿绝对值列表,第一个值是上升沿,第二个下降沿
以上是时钟的理想特性,实际中包括时钟的网络延迟和时钟的不确定性
**时钟的不确定性:**时钟抖动,相位误差,由设计者指定的其他不确定性(HLS中设置的是时钟的时间。
1.一个输入端口
2.一个吉比特收发器的输入引脚,如一个恢复时钟
//周期为10ns 占空比为50,相位为0
create_clock -period 10 [get_ports clk]
//pcb上名字devclk,通过端口clk输入FPGA,周期为10ns 占空比25% 相移90
create_clock -name devclk -period 10 -waveform{2.5,5} [get_ports clk]
//GT基本时钟 gt0/RXOUTCLK//FPGA 硬件上MMCM的原点
create_clock -name rxclk -period 3.33 [get_pins gt0/RXOUTCLK]
定义:没有任何物理连接和生成网表器件。
使用的目的:在约束中使用,通过虚拟时钟说明输入输出延迟约束
定义:有MMCM,PLL,或者用户逻辑生成
与主时钟的关系:
//创建基本时钟
create_clock -name clkin -period 10 [get_ports clk]
//生成时钟
create_generated_clock -name clkdiv2 -source[get_ports clkin] -div_by 2 \ [get_pins REGA/Q] //REGA/Q表示是这个寄存器的Q端生成的时钟驱动后面电路
//生成一个时钟,占空比比25%,相位移动90
create_generated_clock -name clkshift -source[get_ports clkin] -edges{1,2,3}\ -edge_shift{2.5,0 2.5}[get_pins mmcm0/CLKOUT]
-set_clock_groups 禁止在所标识的时钟组之间,以及在一个时钟组内的时钟进行时序分析。Vivado默认全部计算,忽略不代表两个时钟路径之间的工作是正常的,需要自己分析
同步时钟(相位可以预测):同一个时钟源,或者具有公共周期(vivado最大可算1000的公共周期,大于还没有公共周期就是不可扩展的,无法进行安全时序分析)
异步时钟:相位不可知
互斥时钟组:就是理论上不能同时存在的(mux),但是却能进行时序分析
对以一位的异步信号可以使用“一位同步器进行同步”(使用两级触发器),而对于多位的异步信号,可以采用如下方法:1:可以采用保持寄存器加握手信号的方法(多数据,控制,地址);2:特殊的具体应用电路结构,根据应用的不同而不同;3:异步FIFO。(最常用的缓存单元是DPRAM)
RTL:握手信号
异步复位,同步复位,异步复位同步释放。
为什么使用:
注意生成的硬件电路,只有异步复位是与寄存机直接连接,其他都是与D触发器输入端口D逻辑相连
同步复位与异步复位的优缺点
同步复位的优点:
一般能够确保电路是百分之百同步的。
确保复位只发生在有效时钟沿,可以作为过滤掉毛刺的手段。
同步复位的缺点:
复位信号的有效时长必须大于时钟周期,才能真正被系统识别并完成复位。同时还要考虑如:时钟偏移、组合逻辑路径延时、复位延时等因素。
由于大多数的厂商目标库内的触发器都只有异步复位端口,采用同步复位的话,就会耗费较多的逻辑资源。
异步复位优点:
异步复位信号识别方便,而且可以很方便的使用全局复位。
由于大多数的厂商目标库内的触发器都有异步复位端口,可以节约逻辑资源。
异步复位缺点:
复位信号容易受到毛刺的影响。
复位结束时刻恰在亚稳态窗口内时,无法决定现在的复位状态是1还是0,会导致亚稳态。
使用异步复位同步释放就可以消除上述缺点。所谓异步复位,同步释放就是在复位信号到来的时候不受时钟信号的同步,而是在复位信号释放的时候受到时钟信号的同步。异步复位同步释放的原理图和代码如下
复位时:是异步复位,显而易见,rst_async_n异步复位后,,与时钟无关,rst_sync_n将拉低,即实现异步复位。
释放时:这个是关键,看如何实现同步释放,即当复位信号rst_async_n撤除时,由于双缓冲电路的作用,rst_sync_n复位信号不会随着rst_async_n的撤除而撤除。,这样复位与时钟同步,在满足保持建立时间的情况下,不会出现亚稳态
如此一来,既解决了同步复位的资源消耗问题,也解决了异步复位的亚稳态问题。其根本思想,也是将异步信号同步化。
module reset_best(clk,asyn_reset,syn_reset);
input clk;
input asyn_reset;
output syn_reset;
reg rst_s1;
reg rst_s2;
always @( posedge clk ,posedge asyn_reset)
begin
if(asyn_reset)
begin
rst_s1<=1'b0;
rst_s2<=1'b0;
end
else
begin
rst_s1<=1'b1;
rst_s2<=rst_s1;
end
end
assign syn_reset=rst_s2;
endmodule