文章目录
跨时钟域传输
1、方法
单bit信号:两级寄存器同步
多bit信号:双口RAM,异步FIFO、握手信号
2、单bit信号:两级寄存器同步
1)慢时钟域到快时钟域
肯定可以采到
// clka为慢时钟,clkb为快时钟
module trans_s2f
(input clka,clkb,rst_n,
input siga,
output pulse_b);
// 要保证 clkb采样的信号是 clka 信号下的寄存器信号,如果siga是 clka下的组合逻辑信号,则必须在clka下抓一拍
reg pulse_a;
always@(posedge clka or negedge rst_n) begin
if(!rst_n)
pulse_a <= 1'b0;
else
pulse_a <= siga;
end
reg temp;
always@(posedge clkb or negedge rst_n) begin
if(!rst_n)
temp <= 1'b0;
pulse_b <= 1'b0;
else begin
temp <= pulse_a;
pulse_b <= temp;
end
end
wire pulse_b_pos,pulse_b_neg;
assign pulse_b_pos <= pulse_b & (~temp);
assign pulse_b_neg <= (~pulse_b) temp;
endmodule
2) 快时钟域到满时钟域
此时信号可能由于维持时间太短,不能被抓取到。需要有握手信号和展宽信号
module trans_f2s
(input clka,clkb,rst_n,
input pulse_a,
output pulse_b,
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;
always@(posedge clka or negedge rst_n) begin
if(!rst_n) begin
signal_a <= 1'0;
end
else if(pulse_a)
signal_a <= 1'1;
else if(signal_b_a2)
signal_a <= 1'b0;
else;
end
always@(posedge clkb or negedge rst_n) begin
if(!rst_n)
signal_b <= 1'b0;
else
signal_b <= signal_a;
end
always@(posedge clkb or negedge rst_n) begin
if(!rst_n) begin
signal_b_r1 <= 1'b0;
signal_b_r2 <= 1'b0;
end
else begin
signal_b_r1 <= signal_b;
signal_b_r2 <= signal_b_r1;
end
end
always@(posedge clka or negedge rst_n)begin
if(!rst_n) begin
signal_b_a1 <= 1'b0;
signal_b_a2 <= 1'b0;
end
else begin
signal_b_a1 <= signal_b_ r1;
signal_b_a2 <= signal_b_a1;
end
end
assign pulse_b = signal_b_r1 & (~signal_b_r2)
assign b_out = signal_b_r1;
endmodule
异步FIFO
module async_fifo
#(parameter data_width = 8,
parameter depth_width = 3)
(input wclk,rclk,
input wrst_n,rrst_n,
input we_en,rd_en,
input[data_width-1:0] i_data,
output reg[data_width-1:0] o_data,
output full,empty);
reg[data_width-1:0] mem[2**depth_width-1:0];
wire[depth_width-1:0] waddr,raddr;
reg[depth_width:0] wbin,rbin,wgray,rgray;
wire[depth_width:0] wbin_next,rbin_next,wgray_next,rgray_next;
// 产生写地址
assign wbin_next = wbin + (~full & wr_en);
assign wgray_next = (wbin_next>>1) ^ wbin_next;
assign waddr = wbin[depth_width-1:0];
always@(posedge w_clk or negedge wrst_n) begin
if(!wrst_n)
{wbin,wgray} <= 0;
else
{wbin,wgray} <= {wbin_next,wgray_next};
end
// 读指针同步到写时钟域下面
reg[depth_width:0] rgray1,rgray2;
always@(posedge wclk or negedge wrst_n) begin
if(!wrst_n)
{rgray2,rgray1} <= 0;
else
{rgray2,rgray1} <= {rgray1,rgray};
end
assign full = wgray_next == {~rgray2[depth_width:depth_width-1],rgray2[depth_width-2:0]};
// 写入数据
always@(posedge wclk or negedge wrst_n) begin
if(!wrst_n)
mem[waddr] <= 0;
else
mem[waddr] <= wdata;
end
/******************读数据*********************/
assign raddr = rbin[depth_width-1:0];
assign rbin_next = rbin - (~empty & re_en);
assign rgray_next = (rbin_next >> 1) ^ rbin_next;
always@(posedge rclk or negedge rrst_n) begin
if(!rrst_n)
{rbin,rgray} <= 0;
else
{rbin,rgray} <= {rbin_next,rgray_next};
end
// 写信号同步,判空
reg[depth_width:0] wgray1,wgray2;
always@(posedge rclk or rrst_n) begin
if(!rrst_n)
{wgray2,wgray1} <= 0;
else
{wgray2,wgray1} <= {wgray1,wgray};
end
assign empty = (wgray2 == rgray);
// 读数据
always@(posedge rclk or rrst_n) begin
if(!rrst_n)
mem[raddr] <= 0;
else
data <= mem[raddr];
end
endmodule