用途:一般用在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.youkuaiyun.com/u013668469/article/details/99643154