跨时钟域处理:全握手信号处理多比特数据跨时钟域

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

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022年9月3日
下一篇 2022年9月8日

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注