题目描述
两个时钟域传单bit数据,输入A持续一个cycle,要求输出B一个cycle。两个时钟域的时钟是任意的。
题目分析
对于慢时钟到快时钟的单bit传输,我们通常采用的方式是打两拍。对于快时钟到慢时钟的单bit传输,我们通常采用的方式是脉冲展宽,但通常这种单bit传输的目的是去传输边沿,譬如rstn信号的单bit传输,它持续低有效的时间足够长,所以我们异步释放在目的时钟域打两拍可以传递下降沿。
但这里题目要求:第一、A、B时钟的频率是未知的,所以我们写的设计必须与频率无关;第二、A输出一个cycle,B也输出一个cycle。也就是说A时钟域的数据传输到B时钟域,数据个数不能变,数据不能错。我们可以使用多bit跨时钟域的handshake方法来做这个东西。
解题思路
使用多bit跨时钟域的handshake方法,来实现数据的握手。
①:当A时钟域的A拉高1周期时,我们令A有效一直为高(快到慢时,脉冲展宽用。)
②:把A_en信号在B时钟域打两拍之后,在B时钟域检测A_en_two的上升沿,若检测到了,则B输出1周期高。满足题意的同时,其实是代表B时钟域看到了A时钟域的信号。
③:把A_en_tre再在A时钟域打两拍,得到B_en_two,当B_en_two等于1时,我们就可以把A_en信号拉低,代表我在A时钟域看到了B时钟域已经接受了我的信号。
当A是慢时钟域,B是快时钟域时,容易推断得到:也能满足上面的波形。
代码
module one_bit_cdc(
input rstn ,
input clk_A ,
input A ,
input clk_B ,
output B
);
reg A_en,A_en_one,A_en_two,A_en_tre;
reg B_en_one,B_en_two;
always @(posedge clk_A)begin
if(!rstn)begin
A_en <= 1'b0;
end
else if(A)begin
A_en <= 1'b1;
end
else if(B_en_two)begin
A_en <= 1'b0;
end
end
always @(posedge clk_B)begin
if(!rstn)begin
A_en_one <= 1'b0;
A_en_two <= 1'b0;
A_en_tre <= 1'b0;
end
else begin
A_en_one <= A_en;
A_en_two <= A_en_one;
A_en_tre <= A_en_two;
end
end
assign B = A_en_two && (!A_en_tre);
always @(posedge clk_A)begin
if(!rstn)begin
B_en_one <= 1'b0;
B_en_two <= 1'b0;
end
else begin
B_en_one <= A_en_tre;
B_en_two <= B_en_one;
end
end
endmodule
testbench
module tb();
wire B;
reg rstn,clk_A,clk_B,A;
initial begin
rstn <= 1'b0;
clk_A <= 1'b0;
clk_B <= 1'b0;
A <= 1'b0;
#20
rstn <= 1'b1;
#15
A <= #1 1'b1;
#10
A <= #1 1'b0;
#300
$finish();
end
initial begin
forever #5 clk_A <= ~clk_A;
end
initial begin
forever #10 clk_B <= ~clk_B;
end
one_bit_cdc u_one_bit_cdc(
.rstn (rstn ),
.clk_A (clk_A ),
.A (A ),
.clk_B (clk_B ),
.B (B )
);
initial begin
$fsdbDumpfile("one_bit_cdc.fsdb");
$fsdbDumpvars(0);
end
endmodule
波形图
快时钟域A到慢时钟域B
慢时钟域A到快时钟域B
波形和我们设计之前画的预想波形一致。