微信公众号上线,搜索公众号小灰灰的FPGA,关注可获取相关源码,定期更新有关FPGA的项目以及开源项目源码,包括但不限于各类检测芯片驱动、低速接口驱动、高速接口驱动、数据信号处理、图像处理以及AXI总线等
跨时钟域之全握手信号(Verilog)
1、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
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
3、功能仿真验证