跨时钟域处理 & 亚稳态处理
1.概述
常见的跨时钟域信号处理方法都有哪些呢?有如下的三种:
(1)两级DFF同步器
(2)握手协议
(3)异步FIFO
.
.
2.一个简单的握手信号
如果频率较高的时钟域A中的信号D1 要传到频率较低的时钟域B,但是D1只有一个时钟脉冲宽度(1T),clkb 就有几率采不到D1了,如图1。
因此只有当D1 在很长一段时间内为1或0,确保一定可以被clkb采样到,才能用两级DFF同步器处理。
如果信号D1 只有1T或几个T的脉宽,又需要传到时钟频率较低甚至或快或慢不确定的时钟域B,这种情况该怎么如何处理呢?
握手协议(handshake)异步信号处理是一种常见的异步信号处理方法。
使用握手信号“xreq”和“yack”,“系统x”将数据发送给“系统y”。下面是使用握手信号传输数据的例子。
-
发送器“系统x”将数据放在数据总线上并发出“xreq”(请求)信号,表示有效数据已经发到接收器“系统y”的数据总线上。
-
采用两级D触发器缓存,把“xreq”信号同步到接收器的时钟域“yclk”上,得到“yreq2”信号,当采样到yreq2有效后,将数据锁存到系统y的总线上,同时接收器发出“yack”信号(相应信号)。
3) 发送器接收到接收器发送来的“yack”信号,然后将“yack”信号同步到“xclk”时钟域上,同步的原理同上,采用两级的D触发器采样,采样时钟为“xclk”,得到同步后的“xack2”信号,xclk时钟采样到“xack2”有效后,发出下一个数据,同时让“xreq”有效一个时钟(xclk)。
案例RTL代码
module handshake_y(clky, rst_n_y, xdata, xreq, yack, ydata);
input clky;
input rst_n_y;
input[7:0] xdata;
input xreq;
output yack;
output[7:0] ydata;
reg[7:0] ydata;
reg yack;
reg yreq1, yreq2;
always@(posedge clky or negedge rst_n_y)
begin
if(!rst_n_y) yreq1 <= 1'b0;
else yreq1 <= xreq;
end
always@(posedge clky or negedge rst_n_y)
begin
if(!rst_n_y) yreq2 <= 1'b0;
else yreq2 <= yreq1;
end
always@(posedge clky or negedge rst_n_y)
begin
if(!rst_n_y) ydata <= 8'h00;
else if(yreq2) ydata <= xdata;
else ydata <= ydata;
end
always@(posedge clky or negedge rst_n_y)
begin
if(!rst_n_y)
yack <= 1'b0;
else if(yreq2)
yack <= 1'b1;
else yack <= 1'b0;
end
endmodule
//
module handshake_x(clkx, yack, rst_n_x, xreq, xdata);
input clkx;
input yack;
input rst_n_x;
output xreq;
output [7:0] xdata;
reg xreq;
reg xack1,xack2;
reg [7:0] data;
reg [7:0] xdata;
always@(posedge clkx or negedge rst_n_x)
begin
if(!rst_n_x) xack1 <= 1'b0;
else xack1 <= yack;
end
always@(posedge clkx or negedge rst_n_x)
begin
if(!rst_n_x) xack2 <= 1'b0;
else xack2 <= xack1;
end
always@(posedge clkx or negedge rst_n_x)
begin
if(!rst_n_x) data <= 8'h00;
else if(xack2) data <= data + 1;
else data <= data;
end
always@(posedge clkx or negedge rst_n_x)
begin
if(!rst_n_x) xdata <= 8'h00;
else if(xack2) xdata <= data;
else xdata <= xdata;
end
always@(posedge clkx or negedge rst_n_x)
begin
if(!rst_n_x) xreq <= 1'b0;
else if(xack2) xreq <= 1'b1;
else xreq <= 1'b0;
end
endmodule
测试代码
module tb;
reg clkx;
reg clky;
reg rst_n_x;
reg rst_n_y;
wire yack;
wire xreq;
wire [7:0] xdata;
wire [7:0] ydata;
initial
begin
//xdata = 8'h32;
clkx =1'b0;
clky =1'b0;
rst_n_x= 1'b0;
rst_n_y= 1'b0;
# 100;
//xdata = 8'h01;
rst_n_x= 1'b1;
rst_n_y= 1'b1;
# 100;
//xdata = 8'h01;
rst_n_x= 1'b0;
rst_n_y= 1'b1;
# 100;
//xdata = 8'h01;
rst_n_x= 1'b1;
rst_n_y= 1'b0;
end
always#5 clkx = ~clkx;
always#6 clky = ~clky;
handshake_x x1( // transmiter
.clkx(clkx),//in
.yack(yack),//in
.rst_n_x(rst_n_x),//in
.xreq(xreq),//out
.xdata(xdata)//out
);
handshake_y y1( //receiver
.clky(clky),//in
.rst_n_y(rst_n_y),//in
.xdata(xdata),//in
.xreq(xreq),//in
.yack(yack),//out
.ydata(ydata)
);
endmodule