跨时钟域单bit信号处理--握手信号

 

 

用途:一般用在AB两个时钟关系不确定的时候,可能是快到慢,也可能是慢到快;

基本原理:双方电路在声明或终止各自的握手信号信号前都要等待对方的相应。完整的同步过程(A→B)可有以下4个步骤:

请求信号的产生:当同步器处于空闲状态时,在输入脉冲到来时,A声明它的请求信号sync_reg;
请求信号的跨越与应答信号的产生:sync_reg信号需要跨时钟域同步到B,与此同时,B产生同步脉冲,并产生应答信号sync_ack,此时,已经给出了要输出的脉冲
应答信号的跨越与请求信号的清除:sync_ack信号跨时钟域同步到A,与此同时,A清除之前产生的sync_reg;
应答信号的清除:在sync_reg信号清除之后,B清除sync_ack信号。此时,一次信号的跨时钟域完成,等待同步下一个脉冲。

缺点:延时大

握手代码

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2021/01/11 16:35:34
// Design Name: 
// Module Name: top
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module top(
    input wire din,
	input wire clk_A, 			
	input wire rst_n_A,				
	input wire clk_B,			
	input wire rst_n_B, 		
						
	output wire sync_idle,		//给出同步器是否空闲的信号
	output reg sync_fail, 		//同步失败:位于原时钟域
	
	output wire dout 			
);	
	
    reg src_sync_req;			//原时钟产生同步请求
	reg req_state_dly1;
	reg req_state_dly2;			//同步器的输出
	reg req_state_dly3;			//目的时钟延后信号,以保证脉冲输出
	
	reg dst_sync_ack;			//目的时钟产生应答
	reg ack_state_dly1;
	reg ack_state_dly2;			//同步器的输出
	wire src_sync_ack;			//原时钟接收应答

	
	//同步器空闲状态的判断:原时钟下:请求和应答信号同时无效
	assign sync_idle = ~(src_sync_req | src_sync_ack );
	
	//同步失败的判断
	always @(posedge clk_A or negedge rst_n_A)
	begin
		if(rst_n_A == 1'b0) 
			sync_fail <= 1'b0;
		else if(din & (~sync_idle))		//源时钟脉冲到来,此时同步器不空闲,给出同步失败
			sync_fail <= 1'b1;
		else
			sync_fail <= 1'b0;
	end
	
	//原时钟产生请求信号,请求信号的产生相当于将脉冲转化为了电平
	always @(posedge clk_A or negedge rst_n_A)
	begin
		if(rst_n_A == 1'b0)
			src_sync_req <= 1'b0;
		else if(din & sync_idle)			//源时钟脉冲到来,且源时钟空闲,传递请求。同时完成了脉冲转电平
			src_sync_req <= 1'b1;
		else if(src_sync_ack)						//检测到应答以后,清除请求
			src_sync_req <= 1'b0;
	end
	
	//同步原时钟请求信号到目的时钟,利用请求信号跨时钟域
	always @(posedge clk_B or negedge rst_n_B)
	begin
		if(rst_n_B == 1'b0)
		begin
			req_state_dly1 <= 1'b0;
			req_state_dly2 <= 1'b0;
			req_state_dly3 <= 1'b0;
		end
		else
		begin
			req_state_dly1 <= src_sync_req;
			req_state_dly2 <= req_state_dly1;		//打两拍结束
			req_state_dly3 <= req_state_dly2;		//再外接一个寄存器,以保证脉冲输出
		end
	end
	
	//上升沿检测,产生输出脉冲
	assign dout = (~req_state_dly3) & req_state_dly2;		//完成输出脉冲
	
	//目的时钟产生应答信号
	always @(posedge clk_B or negedge rst_n_B)
	begin
		if(rst_n_B == 1'b0)
			dst_sync_ack <= 1'b0;
		else if (req_state_dly2)		//同步高电平已到达
			dst_sync_ack <= 1'b1;
		else begin
			dst_sync_ack <= 1'b0;
	   end
			
	end
	
	//同步目的时钟产生的应答信号到原时钟
	always @(posedge clk_A or negedge rst_n_A)
	begin
		if(rst_n_A == 1'b0)
		begin
			ack_state_dly1 <= 1'b0;
			ack_state_dly2 <= 1'b0;
		end
		else
		begin
			ack_state_dly1 <= dst_sync_ack;
			ack_state_dly2 <= ack_state_dly1;			
		end
	end
assign src_sync_ack = ack_state_dly2;
	
endmodule

测试代码:


`timescale  1ns/1ns


module  top_tb;

reg   clk_A;
reg   clk_B;
reg   rst_n;
wire  clk_write;
reg din;
initial begin 
 clk_A=1;
 clk_B=1;
 end

always #20 clk_A=~clk_A; //50
always #40 clk_B=~clk_B; //25


initial begin 
   rst_n=0;
   #10
   rst_n=1;
 end
 

        
assign clk_write = clk_A&rst_n;         //复位期间不应写入数据
reg [31:0] cnt;
always@(posedge clk_write or negedge rst_n) begin
    if(rst_n==1'b0) begin
        cnt <= 32'd0;
    end
    else begin
        cnt <=cnt + 1;
    end
end

always@(posedge clk_write or negedge rst_n) begin
    if(rst_n==1'b0) begin
        din <= 32'd0;
    end
    else if(cnt==10) begin
        din <=1;
    end
    else begin
        din <=0;
    end
end


top top_inst(
    .din        (din),
   .clk_A    (clk_A),
   .rst_n_A   (rst_n),
   .clk_B     (clk_B),
   .rst_n_B   (rst_n)
  
   
);



   
endmodule

 

原文链接:https://blog.csdn.net/u013668469/article/details/99643154

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值