verilog 跨时钟域 单bit延迟打拍 多bit延迟采样 多bit计数延迟采样

慢到快时钟域:

单bit数据 延迟打拍法

// 慢时钟域到快时钟域 单bit数据 延迟打拍法
// 一般设计中使用两级触发器进行缓存即可满足设计时序需求
// 两级触发器延迟打拍并检测信号上升沿的 Verilog 描述如下

module slow2fast_delay_clap(
	input	clk1,	// 异步慢时钟
	input	sig1,	// 异步信号
	input	rstn,	// 复位
	input	clk2,	// 目的快时钟
	output	sig2);	// 快时钟域同步后的信号
  
	reg[2:0] sig2_r;  // 寄存三拍,前两级用于同步,后两级用于边沿检测
	always@(posedge clk2 or negedge rstn)begin
	    if(~rstn) sig2_r <= 3'b0;
	    else sig2_r <= {sig2_r[1:0], sig1};  // 缓存
	end
	 
	assign sig2 = sig2_r[1] && !sig2_r[2];  // 上升沿检测
  
endmodule 

//---------testbench--------

`timescale 1ns/10ps
module slow2fast_delay_clap_tb;
  
	  reg clk1,clk2,rstn,sig1;
	  wire sig2;
	  
	  slow2fast_delay_clap m(
	  	clk1,
	    sig1,
	    rstn,
	    clk2,
	    sig2);
  	
  	initial begin
    	clk1=0; clk2=0; sig1=0; rstn=0;
    #20	rstn=1; 
    #30 sig1=1;
    #20 sig1=0;  // 一个慢时钟周期后sig1=0
    #400 $stop;
	end
	  
	always #10 clk1 = ~clk1;  // 慢时钟
	always #5  clk2 = ~clk2;  // 快时钟
  
endmodule

在这里插入图片描述

多bit数据 延迟采样法

例如当两个异步时钟频率比为 5 时,可以先用延迟打拍的方法对数据使能信号进行 2 级打拍缓存,然后再在快时钟域对慢时钟域的数据信号进行采集。该方法的基本思想是保证信号被安全采集的时刻,而不用同步多位宽的数据信号,可节省部分硬件资源。

// 慢时钟 20MHz 
// 快时钟 100MHz
module delay_sample(
    input               rstn,
    input               clk1,
    input [31:0]        din,
    input               din_en,

    input               clk2,
    output [31:0]       dout,
    output              dout_en);

   //sync din_en 同步数据输入使能信号 2级打拍缓存
   reg [2:0]    din_en_r ;
   always @(posedge clk2 or negedge rstn) begin
     if (!rstn) din_en_r  <= 3'b0 ;
     else       din_en_r  <= {din_en_r[1:0], din_en} ;  // 缓存
   end
   wire din_en_pos = din_en_r[1] && !din_en_r[2] ;  // 同步使能信号上升沿检测

   // 同步数据
   reg [31:0]           dout_r ;
   reg                  dout_en_r ;
   always @(posedge clk2 or negedge rstn) begin
      if (!rstn)
        dout_r         <= 'b0 ;
      else if (din_en_pos)
        dout_r         <= din ;
   end
   //dout_en delay 同步数据输出使能信号
   always @(posedge clk2 or negedge rstn) begin
      if (!rstn)        dout_en_r      <= 1'b0 ;
      else              dout_en_r      <= din_en_pos ;  // 输入有效,则输出有效
   end
   
   assign       dout    = dout_r ; 
   assign       dout_en = dout_en_r ;

endmodule

在这里插入图片描述

din_en 拉高后,dout_en 在快时钟域延迟2拍 (第3个上升沿) 才拉高。


多bit 计数延迟采样:

但如果慢时钟域没有数据使能信号 din_en, 或数据使能信号一直有效,此时在快时钟域对数据使能信号进行上升沿检测的方法将会失效。因为数据使能信号一直有效,除了第一个数据,快时钟域将无法检测到后继数据的传输时刻。解决方法就是,在快时钟域对慢时钟信号的边沿进行检测。

如果两个时钟的频率相差较小,可能还需要对数据进行延迟缓存,以保证采集到的是当拍时钟的数据;如果两个时钟的频率相差较大,数据采样时刻可以通过计数的方法获得,而不用对数据进行缓存。

// 利用计数延迟采样的方法对慢时钟边沿进行检测的 Verilog 描述如下。

// 慢时钟 999KHz 
// 快时钟 100MHz (快慢差100倍)
module delay_cnt_sample(
    input               rstn,
    input               clk1,
    input [31:0]        din,
    input               din_en,

    input               clk2,
    output [31:0]       dout,
    output              dout_en);

   //4级缓存:3级用于打拍同步,一级用于边沿检测
   reg [3:0]    edge_r ;
   always @(posedge clk2 or negedge rstn) begin
     if (!rstn) edge_r  <= 3'b0 ;
     else       edge_r  <= {edge_r[3:0], clk1} ;
   end
   wire edge_pos = edge_r[2] && !edge_r[3] ;  // 慢时钟上升沿延时3拍

   //延迟计数器,检测到慢时钟上升沿时开始计数
   reg [5:0] cnt ;
   always @(posedge clk2 or negedge rstn) begin
      if (!rstn)            	    cnt <= 6'h3f ;
      else if (edge_pos && din_en)	cnt <= 6'h0 ;
      else if (cnt != 6'h3f) 	    cnt <= cnt + 1'b1 ;
   end

   //数据同步
   reg [31:0]           dout_r ;
   reg                  dout_en_r ;
   always @(posedge clk2 or negedge rstn) begin
      if (!rstn)
        dout_r   <= 'b0 ;
      else if (din_en && cnt == 47) // 大约在慢时钟周期中间时刻采样 (3+47=50)
        dout_r   <= din ;
   end
   
   //数据使能信号较数据采样时刻延迟一个周期输出
   always @(posedge clk2 or negedge rstn) begin
	  if (!rstn)   				    dout_en_r  <= 1'b0 ;
      else if (din_en && cnt==48)	dout_en_r  <= 1'b1 ;
      else           				dout_en_r  <= 1'b0 ;
   end
   assign       dout    = dout_r ;
   assign       dout_en = dout_en_r ;

endmodule

在这里插入图片描述

频率相差较大的数据同步采样结果图如下。由图可知,快时钟采样时刻在慢时钟周期中央时刻左右,此时是非常安全的。


寄存n拍


// 不对输入信号进行寄存
always @ (posedge clk) begin
	if (inputs) begin
		...
	end
	...
end

// 对输入信号寄存一拍
always @ (posedge clk) begin
	inputs_reg <= inputs;
	if (inputs_reg == 1'b0 && inputs == 1'b1)begin
		...
	end
	...
end

//对输入信号寄存三拍
always @ (posedge clk) begin
	inputs_reg1 <= inputs;
	inputs_reg2 <= inputs_reg1;
	inputs_reg3 <= inputs_reg2;
	if (inputs_reg2 == 1'b1 && inputs_reg3 == 1'b0) begin
		...
	end
	...
end

  • 3
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值