跨时钟域处理 & 亚稳态处理
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)异步信号处理是一种常见的异步信号处理方法。
.
.
常见的握手协议异步信号处理行为波形图大致如下图2:
信号d_in 所处时钟域是clk_in,且d_in只有1T 的宽度,想要传送到clk_out 时钟域(clk_out 跟clk_in不相关)。
(1)因为clk_out 和 clk_in相位关系不确定,时钟周期大小关系不确定,无法保证一定能采样到d_in。因此需要把d_in展宽,产生d_req 信号;
(2)d_req 信号一直拉高,经过clk_out时钟域两级DFF 同步器后,得到d_reg_sync;取d_req_sync 上升沿1T,即可得到传送到clk_out 时钟域的d_out。此时,d_in 从clk_in 传送到clk_out 的任务就算是结束了。
(3)但对于handshake 电路来说,任务还没结束,因为d_req 还一直是高电平。因此,需要把d_req_sync 信号再用两级DFF同步器,传回clk_in 时钟域,得到d_ack信号;当clk_in 看到d_ack拉高后,就可以把d_req 信号拉低,到这里一个handshake电路行为才算是结束了。
.
根据上面的波形图,可以看到握手协议异步信号处理并不复杂,但是细心的朋友应该会注意到,这个处理方法信号传递的速度相对较慢。
从图2 的波形来看,至少需要3个clk_in 和2个clk_out时钟周期。根据不同的应用需求,人们会对图2的波形做不同的改造。但万变不离其宗,原理都是一样的,电路也大同小异。
RTL代码
该代码基于以上的原理实现,改动之处:
din做成了多位的输入,通过临时寄存器将输入间接传入dout,代码可能有冗余之处,还请多多指正。
module AsynBus_shakehand(
din,clk_in,clk_out,dout,rst
);
input [31:0] din; //din为32bit
input clk_in,clk_out; //clk_in 100M clk_out 10M
input rst;
output dout;
reg [31:0]dout; //dout为32bit
reg [31:0]dstore; //储存input信号
reg d_req;
reg d_req_syn_1; //第一级同步
reg d_req_syn_2; //第二级同步
reg d_ask;
reg d_ask_syn;
always@(posedge clk_in or negedge rst) //输入数据存放在dstore
if(!rst)
dstore<=32'b0;
else if(!d_req)
dstore<=din;
always@(posedge clk_in or negedge rst) //拉高和拉低d_req
if(!rst)
d_req<=1'b0;
else if(din!=dstore)
d_req<=1'b1;
else if(d_ask)
d_req<=1'b0;
always@(posedge clk_out or negedge rst) //经过两级DFF
if(!rst)
begin
d_req_syn_1<=1'b0;
d_req_syn_2<=1'b0;
end
else
begin
d_req_syn_1<=d_req;
d_req_syn_2<=d_req_syn_1;
end
always@(posedge clk_out or negedge rst) //输出改变
if(!rst)
dout<=32'b0;
else if(d_req_syn_2)
dout<=dstore;
always@(posedge clk_in or negedge rst) //拉高和拉低d_ask
if(!rst)
begin
d_ask_syn<=1'b0;
d_ask<=1'b0;
end
else
begin
d_ask_syn<=d_req_syn_2;
d_ask<=d_ask_syn;
end
endmodule