第1章:亚稳态
1.亚稳态来源:是由于违背了触发器的建立和保持时间而产生的。
2.在同步时序电路中发生概率较小,在异步时序电路中发生概率较大,这是由于时钟和数据关系在异步时序电路中不固定。
3.数据信号在时钟沿到来的建立保持时间窗口中应当保持稳定。
4.产生亚稳态可能的条件:
1.输入信号是异步信号;
2.时钟偏移/摆动(上升/下降时间)高于容限值;
3.信号在不同频率或同频率不同相位和偏移的跨时钟域传输;
4.组合逻辑延迟使得数据信号在窗口变化。
5.解决方法:
1.采用同步器;
2.延长时钟周期(不适用)。
6.亚稳态测试电路:
原理:
异步输入async_in输入到由时钟上升沿触发的寄存器qa。qb和qc都是由时钟的下降沿来触发。
当两个互为反相的信号分别传递到qb和qc的输入时,无论qa什么时候出现亚稳态,异或非(XNOR)门的输出都会变为高电平。在寄存器qd输出端捕捉到高电平就表明已经检测到亚稳态时间。
当出现亚稳态时,qa输出信号不稳定,qb与qc接受到的信号不能保持稳定的反相关系,故当不稳定时,在XNOR门输出为1.
电路图:
亚稳态测试电路代码:
module metastab_test(
input clk,
input rstn,
input async_in,
output async_det
);
reg qa,qb,qc,qd;
always @ (posedge clk or negedge rstn)
begin
if(!rstn)
qa <= 1'b0;
else
qa <= async_in;
end
assign clk_inv = !clk;
always @ (posedge clk_inv or negedge rstn)
begin
if(!rstn)
qb <= 1'b0;
else
qb <= qa;
end
always @ (posedge clk_inv or negedge rstn)
begin
if(!rstn)
qc <= 1'b0;
else
qc <= !qa;
end
assign temp = !(qb ^ qc);
always @ (posedge clk or negedge rstn)
begin
if(!rstn)
qd <= 1'b0;
else
qd <= temp;
end
assign async_det = qd;
endmodule
7.MTBF(平均无故障时间)
MTBF = 1/故障率 = e(tr/τ)/Wfcfd
tr 为允许超出器件正常传输延迟时间的解析时间;
τ为触发器的亚稳态(解析)时间常数;
W为亚稳态窗口;
fc为时钟频率;
fd为异步信号边沿频率。
8.单比特信号异步传输
(1)由快到慢(clk_a>clk_b)
主要原理就是先把脉冲信号在clk_a下展宽,变成足够宽的电平信号signal_a,再向clk_b传递,当确认clk_b已经“看见”信号同步过去之后,再清掉signal_a。
代码框架如下:
module Sync_Pulse (
clk_a,
clk_b,
rst_n,
pulse_a_in,
pulse_b_out,
lev_out
);
/****************************************************/
input clk_a;
input clk_b;
input rst_n;
input pulse_a;
output pulse_b_out;
output b_out;
/****************************************************/
reg signal_a;
reg signal_b;
reg signal_b_r1;
reg signal_b_r2;
reg signal_b_a1;
reg signal_b_a2;
/****************************************************/
//在时钟域clk_a下,生成展宽信号signal_a
always @ (posedge clk_a or negedge rst_n)
begin
if (rst_n == 1'b0)
signal_a <= 1'b0;
else if (pulse_a_in) //检测到到输入信号pulse_a_in被拉高,则拉高signal_a
signal_a <= 1'b1;
else if (signal_b_a2) //检测到signal_b1_a2被拉高,则拉低signal_a
signal_a <= 1'b0;
else;
end
//在时钟域clk_b下,采集signal_a,生成signal_b
always @ (posedge clk_b or negedge rst_n)
begin
if (rst_n == 1'b0)
signal_b <= 1'b0;
else
signal_b <= signal_a;
end
//多级触发器处理,对接收到的跨时钟信号signal_b打两拍
always @ (posedge clk_b or negedge rst_n)
begin
if (rst_n == 1'b0)
begin
signal_b_r1 <= 1'b0;
signal_b_r2 <= 1'b0;
end
else
begin
signal_b_r1 <= signal_b; //对signal_b打两拍
signal_b_r2 <= signal_b_r1;
end
end
//在时钟域clk_a下,采集signal_b_r1,signal_b_a2用于反馈来拉低展宽信号signal_a
always @ (posedge clk_a or negedge rst_n)
begin
if (rst_n == 1'b0)
begin
signal_b_a1 <= 1'b0;
signal_b_a2 <= 1'b0;
end
else
begin
signal_b_a1 <= signal_b_r1; //对signal_b_r1打两拍,因为同样涉及到跨时钟域
signal_b_a2 <= signal_b_a1;
end
end
assign pulse_b_out = signal_b_r1 & (~signal_b_r2); //clk_b时钟域下的上升沿检测
assign lev_out = signal_b_r1; //电平输出
endmodule
(2)由慢到快(clk_a < clk_b)
经验设计采集过程必须寄存两拍。第一拍将输入信号同步化,同步化后的输出可能带来建立/保持时间的冲突,产生亚稳态。需要再寄存一拍,减少亚稳态带来的影响。一般来说两级是最基本要求,如果是高频率设计,则需要增加寄存级数来大幅降低系统的不稳定性。也就是说采用多级触发器来采样来自异步时钟域的信号,级数越多,同步过来的信号越稳定。
此时pulse_b必须是clk_b下的寄存器信号,如果pulse_b是clk_b下的组合逻辑信号,一定要先在clk_b先用D触发器(DFF)抓一拍,再使用两级DFF向clk_a传递。这是因为clk_b下的组合逻辑信号会有毛刺,在clk_b下使用时会由setup/hold时间保证毛刺不会被clk_b采到,但由于异步相位不确定,组合逻辑的毛刺却极有可能被clk_a采到。
代码框架如下:
always @ (posedge clk_a or negedge rst_n)
begin
if (rst_n == 1'b0)
begin
pules_a_r1 <= 1'b0;
pules_a_r2 <= 1'b0;
pules_a_r3 <= 1'b0;
end
else
begin //打3拍
pules_a_r1 <= pulse_b;
pules_a_r2 <= pules_a_r1;
pules_a_r3 <= pules_a_r2;
end
end
assign pulse_a_pos = pules_a_r2 & (~pules_a_r3); //上升沿检测
assign pulse_a_neg = pules_a_r3 & (~pules_a_r2); //下降沿检测
assign pulse_a = pules_a_r2;