快时钟域同步到慢时钟域--握手协议--verilog实现
前文分析请看:https://www.cnblogs.com/shadow-fish/p/13451214.html
快时钟域同步到慢时钟域--单bit同步代码:
module test ( input clka, input clkb, input rst, input d_in, output reg d_out ); reg req_a; reg req_a_1; reg req_a_2; reg req_a_3; reg ack_b; reg ack_b_1; reg ack_b_2; always @(posedge clkb or negedge rst) begin//将req_a同步到慢时钟域,告诉慢时钟域,数据已经准备好 if(!rst) begin req_a_1 <= 'b0; req_a_2 <= 'b0; req_a_3 <= 'b0; end else begin req_a_1 <= req_a; req_a_2 <= req_a_1; req_a_3 <= req_a_2; end end always @(posedge clkb or negedge rst) begin if(!rst) begin d_out <= 'b0; end else if (req_a_2 == 1'b1) begin d_out <= req_a_2 & (~req_a_3); end else begin d_out <= d_out; end end always @(posedge clkb or negedge rst) begin//发送ack,告诉慢时钟域,数据已经读取结束 if(!rst) begin ack_b <= 'b0; end else if(req_a_2 == 1'b1) begin ack_b <= 'b1; end else begin ack_b <= 'b0; end end always @(posedge clka or negedge rst) begin//将慢时钟域发出的ack信号同步到快时钟域,表示读取结束 if(!rst) begin ack_b_1 <= 'b0; ack_b_2 <= 'b0; end else begin ack_b_1 <= ack_b; ack_b_2 <= ack_b_1; end end
//assign req_a = (d_in==1'b1)?1'b1:((ack_b_2==1'b1)?1'b0:req_a);有可能下面的两个时序逻辑不能正确捕捉到d_in的信号导致出错 always @(posedge clka or negedge rst) begin//快时钟将数据放到总线上,然后发送req信号继续提醒 if(!rst) begin req_a <= 'b0; end else if(d_in == 1'b1)begin req_a <= 1'b1; end else begin req_a <= 'b0; end end always @(posedge clka or negedge rst) begin if(!rst) begin req_a <= 'b0; end else if (ack_b_2 == 1'b1) begin req_a <= 'b0; end else begin req_a <= req_a; end end endmodule
测试用例:
`timescale 1ns/10ps module test_tb; reg clka; reg clkb; reg rst; reg d_in; wire d_out; test u1( .clka(clka), .clkb(clkb), .rst(rst), .d_in(d_in), .d_out(d_out) ); initial begin clka = 'b1; clkb = 'b1; rst = 'b0; #8 rst = 'b1; end always #5 clka = ~clka; always #12 clkb = ~clkb; initial begin d_in = 'b0; #20; d_in = 'd1; #10 d_in = 'd0; end endmodule
questasim仿真波形:
快时钟域同步到慢时钟域--多bit同步代码:多bit的代码透露着一丝古怪,如发现问题请留言,以便改进。
module test (
input clka,
input clkb,
input rst,
input [7:0]d_in,
output reg [7:0]d_out
);
reg req_a;
reg req_a_1;
reg req_a_2;
reg ack_b;
reg ack_b_1;
reg ack_b_2;
reg [7:0]d_in_line;
always @(posedge clkb or negedge rst) begin//将req_a同步到慢时钟域,告诉慢时钟域,数据已经准备好
if(!rst) begin
req_a_1 <= 'b0;
req_a_2 <= 'b0;
end
else begin
req_a_1 <= req_a;
req_a_2 <= req_a_1;
end
end
always @(posedge clkb or negedge rst) begin//检测到req_a,将读取需要传输的数据
if(!rst) begin
d_out <= 'b0;
end
else if (req_a_2 == 1'b1) begin
d_out <= d_in_line;
end
else begin
d_out <= d_out;
end
end
always @(posedge clkb or negedge rst) begin//发送ack,告诉慢时钟域,数据已经读取结束
if(!rst) begin
ack_b <= 'b0;
end
else if(req_a_2 == 1'b1) begin
ack_b <= 'b1;
end
else begin
ack_b <= 'b0;
end
end
always @(posedge clka or negedge rst) begin//将慢时钟域发出的ack信号同步到快时钟域,表示读取结束
if(!rst) begin
ack_b_1 <= 'b0;
ack_b_2 <= 'b0;
end
else begin
ack_b_1 <= ack_b;
ack_b_2 <= ack_b_1;
end
end
always @(posedge clka or negedge rst) begin//快时钟将数据放到总线上,然后发送req信号继续提醒
if(!rst) begin
req_a <= 'b0;
end
else if(d_in_line != 'b0)begin
req_a <= 1'b1;
end
else begin
req_a <= 'b0;
end
end
always @(posedge clka or negedge rst) begin
if(!rst) begin
d_in_line <= 'b0;
end
else begin
d_in_line <= d_in;
end
end
always @(posedge clka or negedge rst) begin
if(!rst) begin
req_a <= 'b0;
end
else if (ack_b_2 == 1'b1) begin
req_a <= 'b0;
end
else begin
req_a <= req_a;
end
end
endmodule
测试用例:
`timescale 1ns/10ps module test_tb; reg clka; reg clkb; reg rst; reg [7:0]d_in; wire [7:0]d_out; test u1( .clka(clka), .clkb(clkb), .rst(rst), .d_in(d_in), .d_out(d_out) ); initial begin clka = 'b1; clkb = 'b1; rst = 'b0; #6 rst = 'b1; end always #5 clka = ~clka; always #22 clkb = ~clkb; initial begin d_in = 'b0; #80; d_in = 'd1; #160 d_in = 'd2; #160 d_in = 'd3; #160 d_in = 'd4; #160 d_in = 'd5; #160 d_in = 'd6; #160; end endmodule