一、前言
多比特一般为数据,其在跨时钟域传输的过程中有多种处理方式,比如DMUX,异步FIFO,双口RAM,握手处理。本文介绍通过DMUX的方式传输多比特信号。
二、DMUX同步跨时钟域数据
dmux表示数据分配器,该方法适合带数据有效标志信号的多bit数据做跨时钟域传输。其典型结构如下:
慢时钟域到快时钟域
快时钟域到慢时钟域只要将红框中换成单bit快时钟域到慢时钟域处理单元即可。
DMUX遵循的原则就是,数据不同步只对控制信号同步,这点其实和异步fifo里的思路一样,只不多异步fifo中的控制信号是多比特的格雷码,而这个场景下的控制信号是data_valid。继续观察结构可以发现,DMUX是将单bit控制信号同步之后将其最为mux的选择信号。因此使用这个结构需要满足一些要求:
1.数据和使能信号在源时钟域为同步到来的信号;
2.在目的时钟域对数据完成采样前,数据信号不能跳变;
如果不满足以上的要求,那么就可能造成数据漏同步、错同步等问题。
三、DMUX Verilog代码
3.1 慢时钟域数据到快时钟域
module mult_bit_slow_to_fast_dmux
#(parameter DATAWIDTH = 8)
(
input rst_n,
input clk_slow,
input [DATAWIDTH-1:0] data_slow,
input data_valid_slow,
input clk_fast,
output reg [DATAWIDTH-1:0] data_fast,
output reg data_valid_fast
);
//signal valid slow to fast cdc
reg data_valid_slow_reg;
always@(posedge clk_slow or negedge rst_n)begin
if(!rst_n)
data_valid_slow_reg <= 1'b0;
else
data_valid_slow_reg <= data_valid_slow;
end
reg data_valid_slow2fast_reg0,data_valid_slow2fast_reg1;
always@(posedge clk_fast or negedge rst_n)begin
if(!rst_n)
begin
data_valid_slow2fast_reg0 <= 1'b0;
data_valid_slow2fast_reg0 <= 1'b0;
end
else
begin
data_valid_slow2fast_reg0 <= data_valid_slow_reg ;
data_valid_slow2fast_reg1 <= data_valid_slow2fast_reg0 ;
end
end
always@(posedge clk_fast or negedge rst_n)begin
if(!rst_n)
data_valid_fast <= 1'b0;
else
data_valid_fast <= data_valid_slow2fast_reg1 ;
end
//data slow to fast cdc
reg [DATAWIDTH-1:0] data_slow_reg,
always@(posedge clk_slow or negedge rst_n)begin
if(!rst_n)
data_slow_reg <= 0;
else
data_slow_reg <= data_slow ;
end
always@(posedge clk_fast or negedge rst_n)begin
if(!rst_n)
data_fast<= 0;
else if(data_valid_slow2fast_reg1 == 1'b1)
data_fast <= data_slow_reg ;
end
endmodule
3.2 快时钟域数据到慢时钟域
module mult_bit_fast_to_slow_dmux
#(parameter DATAWIDTH = 8)
(
input rst_n,
input clk_fast,
input [DATAWIDTH-1:0] data_fast,
input data_valid_fast,
input clk_slow,
output reg [DATAWIDTH-1:0] data_slow,
output reg data_valid_slow
);
//signal valid fast to slow cdc
reg data_valid_fast_reg;
always@(posedge clk_fast or negedge rst_n)begin
if(!rst_n)
data_valid_fast_reg <= 1'b0;
else if(data_valid_fast == 1'b1)
data_valid_fast_reg <= ~data_valid_fast_reg ;
end
reg data_valid_fast2slow_reg0,data_valid_fast2slow_reg1;
always@(posedge clk_slow or negedge rst_n)begin
if(!rst_n)
begin
data_valid_fast2slow_reg0 <= 1'b0;
data_valid_fast2slow_reg1 <= 1'b0;
end
else
begin
data_valid_fast2slow_reg0<= data_valid_fast_reg ;
data_valid_fast2slow_reg1<= data_valid_fast2slow_reg0;
end
end
reg data_valid_fast2slow_reg2
always@(posedge clk_slow or negedge rst_n)begin
if(!rst_n)
data_valid_fast2slow_reg2 <= 1'b0;
else
data_valid_fast2slow_reg2 <= data_valid_fast2slow_reg1;
end
assign data_valid_slow_ready = data_valid_fast2slow_reg1 ^ data_valid_fast2slow_reg2 ;
always@(posedge clk_slow or negedge rst_n)begin
if(!rst_n)
data_valid_slow<= 0;
else
data_valid_slow<= data_valid_slow_ready ;
end
//data fast to slow cdc
reg [DATAWIDTH-1:0] data_fast_reg,
always@(posedge clk_fast or negedge rst_n)begin
if(!rst_n)
data_fast_reg<= 0;
else
data_fast_reg<= data_fast;
end
always@(posedge clk_slow or negedge rst_n)begin
if(!rst_n)
data_slow <= 0;
else if(data_valid_slow_ready == 1'b1)
data_slow <= data_fast_reg ;
end
endmodule