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

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

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

参考思路

初始化:复位,所有信号复位为0
发送方:
复位解除后,计数器计数到4,data_req 置1;发送 data_req 和 data 给接收方;
等待接收方返回 data_ack 后,利用两级同步器同步 data_ack;
当满足 data_ack_r1 && !data_ack_r2时,data增加1‘b1,data_req 置0,同时计数器cnt置0;
至此,一次完整的握手结束
等待计数器cnt == 4,发送下一次 data_req。
接收方:
接受到 data_req 和 data 后,利用两级同步器同步 data_req
当 data_req_r1 && !data_req_r2 时,输出data_ack置1,并且 data 存入到 data_reg;
过了一个周期,data_ack 必须置0,(否则下一次握手无法完成,因为data_ack 一直为1,使得 data_ack_r1 和 data_ack_r2 都一直为 1);
至此,接收方任务完成。

疑问

按题目给出data 位宽为4位 ,仿真结果data是0-15, 那么应该是循环发送0-15,而不是循环发送0-7.

代码实现

`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 data_ack_r1, data_ack_r2;
    reg [2:0] cnt;
    //--------------两级同步------------------//
    always @(posedge clk_a, negedge rst_n) begin
        if(!rst_n) begin
            data_ack_r1 <= 0;
            data_ack_r2 <= 0;
        end else begin
            data_ack_r1 <= data_ack;
            data_ack_r2 <= data_ack_r1;
        end
    end
    //-----------------数据产生----------------------//
    always @(posedge clk_a, negedge rst_n) begin
        if(!rst_n) begin
            data <= 0;
        end else if(data_ack_r1 && !data_ack_r2) begin
            data <= data + 1;
        end else begin
            data <= data;
        end
    end
    //-----------------data_req----------------------//
    always @(posedge clk_a, negedge rst_n) begin
        if(!rst_n) begin
            data_req <= 0;
        end else if(data_ack_r1 && !data_ack_r2) begin
            data_req <= 0;
        end else if(cnt == 3'd4) begin
            data_req <= 1'b1;
        end else begin
            data_req <= data_req;
        end
    end
    //-----------------计数器----------------------//
    always @(posedge clk_a, negedge rst_n) begin
        if(!rst_n) begin
            cnt <= 0;
        end else if(data_ack_r1 && !data_ack_r2) begin
            cnt <= 0;
        end else if(data_req) begin
            cnt <= cnt;
        end else begin
            cnt <= cnt + 1;
        end
    end
endmodule

module data_receiver(
	input clk_b,
	input rst_n,
    input [3:0]data,
	output reg data_ack,
	input data_req
	);
   
    reg data_req_r1, data_req_r2;
    reg [3:0] data_reg;
    //--------------两级同步------------------//
    always @(posedge clk_b, negedge rst_n) begin
        if(!rst_n) begin
            data_req_r1 <= 0;
            data_req_r2 <= 0;
        end else begin
            data_req_r1 <= data_req;
            data_req_r2 <= data_req_r1;
        end
    end
    //-----------------数据存储----------------------//
    always @(posedge clk_b, negedge rst_n) begin
        if(!rst_n) begin
            data_reg <= 0;
        end else if(data_req_r1 && !data_req_r2) begin
            data_reg <= data;
        end else begin
            data_reg <= data_reg;
        end
    end
    //-----------------data_ack----------------------//
    always @(posedge clk_b, negedge rst_n) begin
        if(!rst_n) begin
            data_ack <= 0;
        end else if(data_req_r1 && !data_req_r2) begin
            data_ack <= 1'b1;
        end else begin
            data_ack <= 0;
        end
    end
   
endmodule

仿真结果


全部评论
data_ack跟随data_req_r2变化就好了,只在data_req的上升沿持续太短了吧,如果发送端是慢时钟域,会不会存在同步不过去的情况?
点赞 回复 分享
发布于 2023-09-06 10:10 江苏
我也觉得,data给三位是不是就可以0~7
点赞 回复 分享
发布于 2023-04-20 00:52 山东

相关推荐

不愿透露姓名的神秘牛友
07-18 18:23
点赞 评论 收藏
分享
Lorn的意义:你这种岗位在中国现在要么牛马天天加班,要么关系户进去好吃好喝,8年时间,真的天翻地覆了,对于资本来说你就说一头体力更好的牛马,哎,退伍没有包分配你真的亏了。
点赞 评论 收藏
分享
评论
2
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务