基于握手原理的,网上很多,这里记录一下自己亲测试了能用的(知乎上看的,自己稍微改了一下,他那个原版跨大时钟域就用不了了
module handshake_sync (
input clk1 , //快时钟信号
input sys_rst_n , //复位信号,低电平有效
input read , //信号,快时钟阈的
input clk2 , //慢时钟信号
output read_sync_pulse //输出信号
);
//in1表示该信号在clk1时钟域
reg req_in1 ;
reg ack_in1 ;
reg ack_in1_dly1 ;
//in2表示该信号在clk2时钟域
reg req_in2 ;
reg req_in2_dly1 ;
//*****************************************************
//** main code
//*****************************************************
//1、clk1时钟域下req信号的生成
always @(posedge clk1 or negedge sys_rst_n) begin
if (sys_rst_n == 1'b0)
req_in1 <= 1'b0;
else if(read == 1'b1)
req_in1 <= 1'b1;
else if(ack_in1_dly1 == 1'b1)
req_in1 <= 1'b0;
else
req_in1 <= req_in1;
end
//2、clk2时钟域下req信号的采样
always @(posedge clk2 or negedge sys_rst_n) begin
if (sys_rst_n == 1'b0) begin
req_in2 <= 1'b0;
req_in2_dly1 <= 1'b0;
end
else begin
req_in2 <= req_in1;
req_in2_dly1 <= req_in2;
end
end
//3、clk1时钟域下ack信号的采样 直接采样req_in2_dly1作为ack信号即可
//这是因为有了req_in2和req_in2_dly1之后我们就可以生成dout,所以此时就可以返回ack信号了
always @(posedge clk1 or negedge sys_rst_n) begin
if (sys_rst_n == 1'b0) begin
ack_in1 <= 1'b0;
ack_in1_dly1 <= 1'b0;
end
else begin
ack_in1 <= req_in2_dly1 ;
ack_in1_dly1 <= ack_in1;
end
end
//4、dout信号的产生
assign read_sync_pulse = req_in2 & ~req_in2_dly1;
endmodule
测试代码:
module TB();
reg sys_clk1;
reg sys_clk2;
reg sys_rst_n;
reg read ;
wire read_sync_pulse;
initial begin
sys_clk1 = 1'b0;
sys_clk2 = 1'b0;
sys_rst_n = 1'b0;
read = 1'b0;
#200
sys_rst_n = 1'b1;
#100
read = 1'b1;
#8
read = 1'b0;
#500
read = 1'b1;
#8
read = 1'b0;
end
always #4 sys_clk1 = ~sys_clk1;
always #55.5 sys_clk2 = ~sys_clk2;
handshake_sync u_handshake_sync(
.clk1 (sys_clk1 ),
.clk2 (sys_clk2 ),
.sys_rst_n (sys_rst_n),
.read (read ),
.read_sync_pulse(read_sync_pulse )
);
endmodule
仿真结果:
原作者文章链接:原文链接