题解 | #使用握手信号实现跨时钟域数据传输#

使用握手信号实现跨时钟域数据传输

https://www.nowcoder.com/practice/2bf1b28a4e634d1ba447d3495134baac

main.v+tb.v

main分为两个模块:发送机和接收机

发送机和接收机分别又有几个模块在always作用下同时工作。

发送机:

1.发送数据0-7,重要的是改变数据的时间节点:当上次发送的数据已被成功接收,数据就加一,当数据等于7时,数据归零。那么数据何时被成功接收:当ack信号变为1时,代表数据被成功接收。

2.发送信号req,当数据被接收之后 req=0,等待五个周期的时间内 req=0,五个周期结束后开始发送数据 req=1,且在ack拉高之前req一直=1。

3.等待五个时钟周期,rst时 cnt=0,数据刚被接收后 ack拉高后,表示数据被接收,重新开始计数 置cnt=0,且在传输数据(req=1)期间cnt不变。

4.接受数据ack,打两拍 信号变化表示数据已经被接收(上升沿,但是用来做if判断的话 不能用上升沿这个语句,就用两拍之间数据不一样作为判断)

(整个过程就是等待五个周期后,req=1开始传数据,传数据期间cnt不变,数据传输完毕ack=1,req=0,cnt=0)

接收机:

1.接收数据data 打两拍,重要的是什么时候接收数据,当等待完五个周期 且req=1时接收数据

2.发送数据 ack 当接收到数据后ack被拉高 ,何以见得数据被接收,参见上一条。

module data_driver(

input clk_a,

input rst_n,

input data_ack,

output reg [3:0]data,

output reg data_req

);

reg data_ack_d0_r;

reg data_ack_d1_r;

reg data_ack_d2_r;

always @(posedge clk_a or negedge rst_n) begin

if (!rst_n) begin

data_ack_d0_r <= 'd0;

data_ack_d1_r <= 'd0;

data_ack_d2_r <= 'd0;

end

else begin

data_ack_d0_r <= data_ack;

data_ack_d1_r <= data_ack_d0_r;

data_ack_d2_r <= data_ack_d1_r;

end

end

//data

always @(posedge clk_a or negedge rst_n) begin

if (!rst_n) begin

data <= 'd0;

end

else if (data_ack_d1_r & !data_ack_d2_r) begin

data <= data == 'd7 ? 'd0 : data + 'd1;

end

end

//cnt

reg [3-1:0] cnt_r;

always @(posedge clk_a or negedge rst_n) begin

if (!rst_n) begin

cnt_r <= 'd0;

end

else if (data_ack_d1_r & !data_ack_d2_r) begin

cnt_r <= 'd0;

end

else if (data_req) begin

cnt_r <= cnt_r;

end

else begin

cnt_r <= cnt_r + 'd1;

end

end

//req

always @(posedge clk_a or negedge rst_n) begin

if (!rst_n) begin

data_req <= 'd0;

end

else if (data_ack_d1_r & !data_ack_d2_r) begin

data_req <= 'd0;

end

else if (cnt_r == 'd4) begin

data_req <= 'd1;

end

end

endmodule

module data_receiver(

input clk_b,

input rst_n,

input [3:0]data,

input data_req,

output reg data_ack

);

reg data_req_d0_r;

reg data_req_d1_r;

reg data_r;

always @(posedge clk_b or negedge rst_n) begin

if (!rst_n) begin

data_req_d0_r <= 'd0;

data_req_d1_r <= 'd0;

end

else begin

data_req_d0_r <= data_req;

data_req_d1_r <= data_req_d0_r;

end

end

always @(posedge clk_b or negedge rst_n) begin

if (!rst_n) begin

data_r <= 'd0;

data_ack <= 'd0;

end

else if (data_req_d1_r) begin

data_r <= data;

data_ack <= 'd1;

end

else begin

data_ack <= 'd0;

end

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;

end

always #10 clk_a=~clk_a;

always #15 clk_b=~clk_b;

initial begin

rst_n=0;

#30

rst_n=1;

end

data_driver u_1(

clk_a,

rst_n,

data_ack,

data,

data_req);

data_receiver u_2(

clk_b,

rst_n,

data,

data_req,

data_ack);

endmodule

全部评论
确实不打第三拍也可以
点赞 回复 分享
发布于 04-08 11:17 四川

相关推荐

孤寡孤寡的牛牛很热情:为什么我2本9硕投了很多,都是简历或者挂,难道那个恶心人的测评真的得认真做吗
点赞 评论 收藏
分享
1 收藏 评论
分享
牛客网
牛客企业服务