文章目录
一、亚稳态简介
亚稳态的产生:一个信号在一个时钟域变化,并在另一个时钟域被采样,就会导致输出成为亚稳态。
本质上是由于违背了触发器的建立和保持时间产生的;
亚稳态的危害:导致逻辑判断错误、亚稳态传播(下一级电路同样产生亚稳态)
建立时间(Tsu,set up time):时钟有效边沿到来前,要求数据保持稳定的最小时间;
保持时间(Th, hold time):时钟有效边沿到来后,要求数据保持稳定的最小时间;
输出延迟值(Tco):规定的时钟到输出的延迟值;
决断时间(Tmet):亚稳态输出恢复到稳态所超出tco的额外的时间;
亚稳态导致触发器在原有的输出延迟tco上多出一段决断时间tmet,在这段时间之后,触发器最终由亚稳态转向稳态;
一般来说,触发器会在一个或两个时钟周期内返回稳态;
二、亚稳态窗口
具有特定时间长度的窗口,在这段时间内,输入数据与时钟均应该保持不变;
亚稳态窗口越大,进入亚稳态的概率越高;
三、平均无故障时间(MTBF)
单级触发器的平均无故障时间:
MTBF1 = e(tr/τ)/W·fc·fd
tr : 允许超出器件正常传输延迟时间的解析时间
τ: 触发器的亚稳态解析时间常数
W: 亚稳态窗口
fc: 时钟频率
fd: 异步信号边沿频率
两级触发器的平均无故障时间:
MTBF2 = e(tr1/τ)/W·fc·fd × e(tr2/τ)
若单级同步器的MTBF为40s,则两级同步器的MTBF为40 × 40 = 26.6min
可见信号经过两级触发器后,平均无故障时间明显增加,这也是多级同步器的原理;
四、亚稳态产生场景
亚稳态产生:违背时序要求
1.输入信号为异步(中断、复位)
2.时钟偏移、时钟抖动,高于容限值
3.信号在两个不同频率或者相同频率但相位、偏移不同的时钟下工作(跨时钟域)
4.组合逻辑延迟使得触发器的数据输入在亚稳态窗口内发生变化
五、解决亚稳态的技术
5.1 单比特信号跨时钟域
5.1.1 多级同步器
多级同步器的原理可参考第三节平均无故障时间的计算;
使用一个完整的时钟周期来降低亚稳态发生的概率(不能解决);
应用场景:
单/多比特数据,从慢时钟域进入到快时钟域(频率差2倍),此时不会丢失数据;
若处理的数据从快时钟域到慢时钟域 ,可能会发生数据丢失(漏采样);
输出会有Lantency,视级数而定(1级-1Lantency 2级-2Lantency);
module Multiple_stage_synchronizermodule#(
parameter integer DFF_LEVEL = 2,
parameter integer DATA_WIDTH = 1
)(
input wire clk,
input wire [DATA_WIDTH - 1:0] din,
input wire [DATA_WIDTH - 1:0] dout,
input wire nrst
);
reg [DATA_WIDTH - 1:0] din_buff [DFF_LEVEL-1:0];
assign dout = din_buff[DFF_LEVEL-1];
integer i;
always @(posedge clk or negedge nrst) begin
if (~nrst) begin
// reset
for(i=0;i<DFF_LEVEL;i=i+1)
begin
din_buff[i] <= 'b0;
end
end
else begin
for(i=1;i<DFF_LEVEL;i=i+1)
begin
din_buff[i] <= din_buff[i-1];
end
din_buff[0] <= din;
end
end
endmodule
综合电路:
5.1.2 另一种多级同步器
普通多级同步器存在的问题:
要求异步信号的脉宽必须大于时钟周期(采样不到);
要求异步信号的时钟域1时钟频率小于时钟域2(漏采);
同步器B模式:
可以从快时钟域采样信号;
不需要异步信号的脉宽大于时钟周期;
常用于中断信号、复位信号的同步;
module Multiple_stage_synchronizermoduleB(
input wire din,
input wire s_clk,
input wire en,
input wire nrst,
output wire dout
);
wire Q1_Clr;//µÚÒ»¼¶´¥·¢Æ÷¸´Î»ÐźÅ
reg Q1_out,Q2_out,Q3_out;
assign Q1_Clr = ~din & dout;
assign dout = Q3_out;
always@(posedge din,posedge Q1_Clr)
begin
if(Q1_Clr)
begin
Q1_out <= 1'b0;
end
else
begin
Q1_out <= 1'b1;
end
end
always@(posedge s_clk)
begin
if(~nrst)
begin
Q2_out <= 1'b0;
Q3_out <= 1'b0;
end
else
begin
if(en)
begin
Q3_out <= Q2_out;
Q2_out <= Q1_out;
end
else
begin
Q3_out <= Q3_out;
Q2_out <= Q2_out;
end
end
end
endmodule
综合电路:
5.2 多比特信号跨时钟域处理
5.2.3 握手协议
应用于单比特或多比特信号的跨时钟域处理上;
发送端在dout数据准备好后,拉高dqvldo信号;
接收端在可以接收数据时拉高ready信号,当检测到dqvldi与ready信号同时为高时,立即取走数据,并拉低ready信号;
发送端在接收到ready信号为低时,拉低dqvld信号;
发送端:
module Handshake_M#(
parameter integer DATA_WIDTH = 8
)(
input wire m_clk,
input wire nrst,
input wire [DATA_WIDTH - 1 : 0] din,
input wire dinvalid,
output wire [DATA_WIDTH - 1 : 0] dout,
input wire readyi,
output wire wren,
output wire dqvldo
);
reg [DATA_WIDTH - 1 : 0] dout_o;
reg dqvld_o;
reg wr_en;
//inner signals connect
assign dout = dout_o;
assign dqvldo = dqvld_o;
assign wren = wr_en;
always@(posedge m_clk)
begin
if(~nrst)
begin
dout_o <= 'b0;
end
else begin
if(wr_en&dinvalid)
dout_o <= din;
else begin
dout_o <= dout_o;
end
end
end
always @(posedge m_clk ) begin
if (~nrst) begin
// reset
dqvld_o <= 1'b0;
wr_en <= 1'b1;
end
else
begin
if((wr_en == 1'b1) && (dqvld_o == 1'b0)&(dinvalid==1'b1))
begin
dqvld_o <= 1'b1;
wr_en <= 1'b0;
end
else if((wr_en == 1'b0) && (dqvld_o == 1'b1) && (readyi == 1'b1))
begin
dqvld_o <= 1'b0;
wr_en <= 1'b1;
end
end
end
endmodule
接收端:
module Handshake_S#(
parameter integer DATA_WIDTH = 8
)(
input wire s_clk,
input wire nrst,
input wire [DATA_WIDTH - 1 : 0] din,
input wire doutvalid,
output wire [DATA_WIDTH - 1 : 0] dout,
output wire readyo,
input wire dqvldi
);
wire r_en;
reg [DATA_WIDTH - 1 : 0] dout_o;
reg ready_o;
assign r_en = dqvldi & readyo & doutvalid;
//inner signal connect
assign dout = dout_o;
assign readyo = ready_o;
always @(posedge s_clk) begin
if (~nrst) begin
// reset
ready_o <= 1'b1;
end
else
begin
if((readyo & dqvldi)||(doutvalid == 1'b0))
begin
ready_o <= 1'b0;
end
else begin
ready_o <= 1'b1;
end
end
end
always @(posedge s_clk)
begin
if(~nrst)
begin
dout_o <= 'b0;
end
else begin
if(r_en)
begin
dout_o <= din;
end
else begin
dout_o <= dout_o;
end
end
end
endmodule
握手协议的三种握手情况:
1.valid信号与ready信号同时有效:立即完成传输
测试程序:
`timescale 1ns / 1ps
module cdc_test(
);
parameter integer DATA_WIDTH = 8;
reg clk;
reg nrst;
reg [DATA_WIDTH - 1 : 0] m_din;
reg dinvalid;
wire [DATA_WIDTH - 1 : 0] dout;
wire [DATA_WIDTH - 1 : 0] s_dout;
wire ready;
wire wren;
wire dqvld;
initial begin
clk = 0;
forever begin
#1 clk = ~clk;
end
end
initial begin
nrst = 0;
#2 nrst = 1;
end
always @(posedge clk ) begin
if (~nrst) begin
// reset
m_din <= 'b0;
dinvalid <= 1'b0;
end
else if (wren) begin
dinvalid <= 1'b1;
m_din <=m_din + 1'b1;
end
end
Handshake_M#(
.DATA_WIDTH (DATA_WIDTH)
)Handshake_M_inist0(
. m_clk(clk),
. nrst(nrst),
. din(m_din),
. dinvalid(dinvalid),
. dout(dout),
.readyi(ready),
. wren(wren),
.dqvldo(dqvld)
);
Handshake_S#(
.DATA_WIDTH (DATA_WIDTH)
)Handshake_S_inist0(
. s_clk(clk),
. nrst(nrst),
. din(dout),
. dout(s_dout),
. readyo(ready),
. dqvldi(dqvld)
);
endmodule
2.ready信号先有效,valid信号后有效
3.valid信号先有效,ready信号后有效
5.2.4 FIFO
可以看之前FIFO的文章《各种FIFO硬件设计(FIFO概念、异步、同步、非2次幂深度FIFO)》
5.2.5 FIFO实现握手协议
握手协议也可以看成一个深度的FIFO
所以也可以通过FIFO来实现;
输入端readyo产生条件:
FIFO非满(FIFO可以继续写入,允许数据进入)
输出端valido产生条件:
FIFO非空(FIFO中有数据,可以继续读出)
FIFO写使能 wr_en产生条件:
FIFO非满且输入数据有效信号validi有效;
FIFO读使能rd_en产生条件:
FIFO非空且来自下一级的readyi信号有效;
module Handshake_fifo#(
parameter integer DATA_WIDTH = 8
)(
input wire clk_w,
input wire clk_r,
input wire nrst,
input wire [DATA_WIDTH-1:0] din,
input wire validi,
input wire readyi,
output wire valido,
output wire readyo,
output wire [DATA_WIDTH-1:0] dout
);
//BLOCK RAM address width
parameter integer RAM_ADDR_WIDTH = 5;
//FIFO true depth
parameter integer FIFO_DATA_DEPTH = 1;
//FIFO degth's margin
parameter integer FIFO_DATA_DEPTH_MARGIN = 2;
//FIFO compensate depth,(FIFO_DATA_DEPTH+FIFO_DEPTH_COMPLE) must be the data of power 2
parameter integer FIFO_DEPTH_COMPLE = 0;
parameter integer FIFO_DATA_WIDTH = 8;
wire fifo_full;
wire fifo_empty;
wire wr_en;
wire rd_en;
assign valido = ~fifo_empty;
assign readyo = ~fifo_full;
assign wr_en = (~fifo_full) & validi;
assign rd_en = readyi & (~fifo_empty);
Asynchronous_FIFO_npow2#(
//BLOCK RAM address width
. RAM_ADDR_WIDTH (RAM_ADDR_WIDTH),
//FIFO true depth
. FIFO_DATA_DEPTH(FIFO_DATA_DEPTH),
//FIFO degth's margin
. FIFO_DATA_DEPTH_MARGIN(FIFO_DATA_DEPTH_MARGIN),
//FIFO compensate depth,(FIFO_DATA_DEPTH+FIFO_DEPTH_COMPLE) must be the data of power 2
. FIFO_DEPTH_COMPLE(FIFO_DEPTH_COMPLE),
. FIFO_DATA_WIDTH (FIFO_DATA_WIDTH)
)Asynchronous_FIFO_npow2_inist0(
. nrst(nrst),
. clk_w(clk_w),
. wr_en(wr_en),
. wrdata(din),
. fifo_full(fifo_full),
. clk_r(clk_r),
. rd_en(rd_en),
. rddata(dout),
. fifo_empty(fifo_empty)
);
endmodule
module cdc_test(
);
parameter integer DATA_WIDTH = 8;
reg clk_w;
reg clk_r;
reg nrst;
reg [DATA_WIDTH-1:0] din;
reg validi;
reg readyi;
wire valido;
wire readyo;
wire [DATA_WIDTH-1:0] dout;
initial begin
nrst = 0;
#2 nrst = 1;
clk_w = 0;
clk_r = 0;
forever begin
#1 clk_w = ~clk_w;
clk_r = ~clk_r;
end
end
initial begin
readyi = 1;
din = 0;
forever begin
#10 din = din + 1;
validi = 1;
#10 validi = 0;
end
end
Handshake_fifo#(
.DATA_WIDTH (DATA_WIDTH)
)Handshake_fifo_inist0(
. clk_w( clk_w),
. clk_r( clk_r),
. nrst( nrst),
. din( din),
. validi(validi),
. readyi(readyi),
. valido(valido),
. readyo(readyo),
. dout( dout)
);
endmodule
六、总结
技术 | 适用场景 | 同步信号位宽 | 例子 |
---|---|---|---|
普通多级同步器 | 慢到快的数据同步 | 单/多 | 低速外设与高速CPU |
多级同步器B型 | 快到慢的数据同步或慢到快的数据同步 | 单 | 外部中断信号、复位信号 |
FIFO | 快到慢的数据同步或慢到快的数据同步 | 多 | 高速总线与低速总线之间的缓冲(AXI与UART,并->串) |
握手协议 | 快到慢的数据同步或慢到快的数据同步 | 多 | AXI数据传递(每个通道的数据均以握手协议传播) |
使用FIFO实现的握手协议 | 快到慢的数据同步或慢到快的数据同步 | 多 |