题解 | 使用握手信号实现跨时钟域数据传输
使用握手信号实现跨时钟域数据传输
https://www.nowcoder.com/practice/2bf1b28a4e634d1ba447d3495134baac
`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_r, data_ack_rr; wire pos_data_ack; assign pos_data_ack = !data_ack_rr & data_ack_r; always @(posedge clk_a or negedge rst_n) begin if (!rst_n) begin data_ack_r <= 0; data_ack_rr <= 0; end else begin data_ack_r <= data_ack; data_ack_rr <= data_ack_r; end end reg [2:0] cnt; always @(posedge clk_a or negedge rst_n) begin if (!rst_n) begin cnt <= 0; end else if (cnt == 'd4) begin cnt <= 0; end else if (!data_req) begin cnt <= cnt + 1; end end always @(posedge clk_a or negedge rst_n) begin if (!rst_n) begin data_req <= 0; end else if (cnt == 'd4) begin data_req <= 1; end else if (pos_data_ack) begin data_req <= 0; end end always @(posedge clk_a or negedge rst_n) begin if (!rst_n) begin data <= 0; end else if (pos_data_ack) begin data <= data + 1; end else if (data == 'd7) begin data <= 0; end end endmodule module data_receiver ( input clk_b, input rst_n, output reg data_ack, input [3:0] data, input data_req ); reg [3:0] data_reg; reg data_req_r, data_req_rr; wire pos_data_req; assign pos_data_req = !data_req_rr & data_req_r; always @(posedge clk_b or negedge rst_n) begin if (!rst_n) begin data_ack <= 0; end else if (pos_data_req) begin data_ack <= 1; end else begin data_ack <= 0; end end always @(posedge clk_b or negedge rst_n) begin if (!rst_n) begin data_reg <= 0; end else if (pos_data_req) begin data_reg <= data; end end endmodule
如果一个always块中的寄存器信号只有一种则不需要加begin end:
`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_r, data_ack_rr; wire pos_data_ack; assign pos_data_ack = !data_ack_rr & data_ack_r; always @(posedge clk_a or negedge rst_n) begin if (!rst_n) begin data_ack_r <= 0; data_ack_rr <= 0; end else begin data_ack_r <= data_ack; data_ack_rr <= data_ack_r; end end reg [2:0] cnt; always @(posedge clk_a or negedge rst_n) begin if (!rst_n) cnt <= 0; else if (cnt == 'd4) cnt <= 0; else if (!data_req) cnt <= cnt + 1; end always @(posedge clk_a or negedge rst_n) begin if (!rst_n) data_req <= 0; else if (cnt == 'd4) data_req <= 1; else if (pos_data_ack) data_req <= 0; end always @(posedge clk_a or negedge rst_n) begin if (!rst_n) data <= 0; else if (pos_data_ack) data <= data + 1; else if (data == 'd7) data <= 0; end endmodule module data_receiver ( input clk_b, input rst_n, output reg data_ack, input [3:0] data, input data_req ); reg [3:0] data_reg; reg data_req_r, data_req_rr; wire pos_data_req; assign pos_data_req = !data_req_rr & data_req_r; always @(posedge clk_b or negedge rst_n) begin if (!rst_n) data_ack <= 0; else if (pos_data_req) data_ack <= 1; else data_ack <= 0; end always @(posedge clk_b or negedge rst_n) begin if (!rst_n) data_reg <= 0; else if (pos_data_req) data_reg <= data; end endmodule
本题一次性答对,要点在于:
- data_ack和data_req握手信号在不同时钟域产生,因此均需要寄存器打两拍生成边沿检测
- 通过边沿控制握手信号的翻转和数据发射与接收
- 注意边界条件,data为0-7,cnt为0-4
该题可视为数据传输协议的最简版本