慢到快时钟域:
单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