Verilog 的实现,实现多位数据的跨时钟域传输,存在一定的数据延迟。
源码:
module class_3_clka_clkb#( parameter Width = 31 )( input wire i_clk_a , input wire i_clk_b , input wire i_rst_n , input wire [Width-1:00] i_data , input wire i_data_sign , output reg [Width-1:00] o_data , output wire o_data_sign ); reg sign_a; wire sign_a_neg; reg [01:00] sign_a_tmp; /*****i_clk_a 时钟域下 i_data_sign 发送数据信号下降沿*************/ always@(posedge i_clk_a or negedge i_rst_n) begin if(!i_rst_n) sign_a_tmp <= #1 2'b00; else sign_a_tmp <= #1 {sign_a_tmp[0],i_data_sign}; end assign sign_a_neg = sign_a_tmp[1] & (~sign_a_tmp[0]); /*****i_clk_a 时钟域下 i_data_sign 发送数据信号下降沿*************/ /*****i_clk_a 时钟域下生成展宽信号 sign_a*************/ always@(posedge i_clk_a or negedge i_rst_n) begin if(!i_rst_n) sign_a <= #1 1'b0; else if(sign_a_neg) sign_a <= #1 1'b1; else if(sign_a_pos) sign_a <= #1 1'b0; else sign_a <= #1 sign_a; end /*****i_clk_a 时钟域下生成展宽信号 sign_a*************/ /****i_clk_b 时钟域下生成展宽信号 sign_a,延展 i_clk_b N 个时钟此处为 5 个********/ reg [04:00] sign_b_tmp; wire sign_b_pos; always@(posedge i_clk_b or negedge i_rst_n) begin if(!i_rst_n) sign_b_tmp <= #1 5'b00_000; else sign_b_tmp <= #1 {sign_b_tmp[04:00],sign_a}; end /***i_clk_b 时钟域下生成展宽信号 sign_a,延展 i_clk_b N 个时钟此处为 5 个********/ /*****i_clk_b 时钟域下展宽信号中间数据输出*************/ assign sign_b_pos = (~sign_b_tmp[4]) & sign_b_tmp[3]; always@(posedge i_clk_b or negedge i_rst_n) begin if(!i_rst_n) o_data <= #1 'd0; else if(sign_b_pos) o_data <= #1 i_data; end /*****i_clk_b 时钟域下展宽信号中间数据输出*************/ /*****i_clk_a 时钟域下展宽信号结束位置,同时生成输出应答信号*************/ reg [01:00] sign_a_ff; wire sign_a_pos; always@(posedge i_clk_a or negedge i_rst_n) begin if(!i_rst_n) sign_a_ff <= #1 2'b00; else sign_a_ff <= #1 {sign_a_ff[0],sign_b_tmp[4]}; end assign sign_a_pos = (~sign_a_ff[1]) & sign_a_ff[0]; assign o_data_sign = sign_a_ff[1]; /*****i_clk_a 时钟域下展宽信号结束位置,同时生成输出应答信号*************/ endmodule
test bench:
2、testbench 仿真文件 `timescale 1ns/1ns module tb_class_3#( parameter Width = 31 , parameter clk_a_period = 10 , parameter clk_b_period = 1000 ); reg i_clk_a ; reg i_clk_b ; reg i_rst_n ; reg i_data_sign ; reg [Width-1:00] i_data ; wire [Width-1:00] o_data ; wire o_data_sign ; class_3_clka_clkb#( .Width (Width ) )u_class_3_clka_clkb( .i_clk_a (i_clk_a ) , .i_clk_b (i_clk_b ) , .i_data_sign (i_data_sign) , .i_rst_n (i_rst_n ) , .i_data (i_data ) , .o_data (o_data ) , .o_data_sign (o_data_sign) ); initial i_clk_a = 0 ; always #(clk_a_period/2) i_clk_a = ~i_clk_a; initial i_clk_b = 0 ; always #(clk_b_period/2) i_clk_b = ~i_clk_b; initial begin i_rst_n = 0; #1000; i_rst_n = 1; end /************发送信号和应答信号形成回环******************************/ reg sign_ff; always@(posedge i_clk_a or negedge i_rst_n) begin if(!i_rst_n) begin i_data_sign <= #1 1'b1; sign_ff <= #1 1'b0; end else begin sign_ff <= #1 o_data_sign; i_data_sign <= #1 (~o_data_sign) & sign_ff; end end always@(posedge i_clk_a or negedge i_rst_n) begin if(!i_rst_n) i_data <= #1 'd0; else if(i_data_sign) i_data <= #1 $random; end /************发送信号和应答信号形成回环******************************/ endmodule
功能仿真验证
扫码关注尚为网微信公众号
每天学习电路设计和嵌入式系统的专业知识,关注一波,没准就用上了。
原创文章,作者:sunev,如若转载,请注明出处:https://www.sunev.cn/embedded/1275.html