对于接收端(慢时钟)
- 每个模块有一个请求req信号和一个应答ack信号。
- 对单bit的信号跨时钟域传输打两拍处理,
- 若要获得单bit信号的上升沿,打三拍处理,使用后两拍,可以避免亚稳态的产生。
- 对于count和data,在一次传输结束后只变化一次,要使用ack的上升沿信号,因为ack可能会持续多个周期。
- 对于req信号,当ack有效时,req为0,可以直接使用ack打两拍后的信号,也可以使用上升沿信号。
对于接收端(快时钟)
- 对于data_ack,使用打两拍后的data_req信号,在data_req_r[1]信号有效时,data_ack信号有效,
- 对于data_r数据存储信号,一次握手只采集一次data信号(安全合理),使用data_req打两拍之后的上升沿信号。
- data_r若使用打两拍后的data_req信号,会采集多次data,因为data_req信号会持续多个周期有效。
`timescale 1ns/1ns
module data_driver(
input clk_a,
input rst_n,
input data_ack,
output reg [3:0]data,
output reg data_req
);
reg [2:0] count;
reg [2:0] data_ack_r;
//data_ack_r
always@(posedge clk_a or negedge rst_n) begin
if(!rst_n)
data_ack_r <= 3'b00;
else
data_ack_r <= {data_ack_r[1:0], data_ack};
end
//count
always@(posedge clk_a or negedge rst_n) begin
if(!rst_n)
count <= 3'd0;
else if(data_ack_r[1]&(~data_ack_r[2])) //使用三个寄存器的后两拍产生上升沿,防止亚稳态
count <= 3'd0;
else if(data_req)
count <= count;
else
count <= count + 1'b1;
end
//data_req
always@(posedge clk_a or negedge rst_n) begin
if(!rst_n)
data_req <= 1'b0;
else if(data_ack_r[1])
data_req <= 1'b0;
else if(count == 3'd4)
data_req <= 1'b1;
end
//data
always@(posedge clk_a or negedge rst_n) begin
if(!rst_n) begin
data <= 4'd0;
end
else if(data_ack_r[1]&(~data_ack_r[2])) begin
data <= (data == 4'd7) ? 4'd0 : (data + 1'b1);
end
end
endmodule
module data_receiver(
input clk_b,
input rst_n,
input [3:0] data,
input data_req,
output reg data_ack
);
reg [3:0] data_r;
reg [2:0] data_req_r;
//data_req_r
always@(posedge clk_b or negedge rst_n) begin
if(!rst_n)
data_req_r <= 3'b00;
else
data_req_r <= {data_req_r[1:0], data_req};
end
//data_ack
always@(posedge clk_b or negedge rst_n) begin
if(!rst_n)
data_ack <= 1'b0;
else if(data_req_r[1])
data_ack <= 1'b1;
else
data_ack <= 1'b0;
end
always@(posedge clk_b or negedge rst_n) begin
if(!rst_n)
data_r <= 4'b0;
else if(data_req_r[1]&(~data_req_r[2])) //上升沿 只采入一次数据
data_r <= data;
end
endmodule
`timescale 1ns/1ns
module testbench();
reg clk_a,clk_b,rst_n;
wire data_req,data_ack;
wire [3:0]data;
initial begin
clk_a = 1;
clk_b = 1;
rst_n = 0;
#30
rst_n = 1;
#500 $finish();
end
always #15 clk_a = ~clk_a;
always #10 clk_b = ~clk_b;
data_driver dut_1
( .clk_a(clk_a),
.rst_n(rst_n),
.data(data),
.data_ack(data_ack),
.data_req(data_req)
);
data_receiver dut_2
( .clk_b(clk_b),
.rst_n(rst_n),
.data(data),
.data_ack(data_ack),
.data_req(data_req)
);
endmodule