模块之间有数据交互,但是用的不是一个时钟进行驱动,存在相位与频率的不同,由于电路本身的特性(中间态存在时间长),在同一时刻不同元器件对同一信号的判断出现不一致现象,称为亚稳态。这就需要同步器进行同步,减小亚稳态传播下去的概率。
跨时钟域:模块之间有数据交互,但是用的不是同一个时钟进行驱动。
在跨时钟处理单bit信号时,慢时钟域到快时钟域下的处理方式比较简单,将在慢时钟域下的信号在快时钟域下打三拍处理,取二拍与三拍信号进行处理,将慢时钟域的信号分解为在快时钟域下的上升沿脉冲信号与下降沿脉冲信号。
//将慢时钟域下的信号能在快时钟域下采集
//clka为快时钟、clkb为慢时钟
module slow2quick (
// input
input rst_n , // system reset
input clka , // clockA
input clkb , // clockB
input level_a_in , // pulsee input from clka
// output
output pulse_b_neg , // pulsee output in clkb
output pulse_b_pos , // pulsee output in clkb
output level_b_out // level output in clkb
);
parameter DLY = 1 ; //
reg level_b_d1, level_b_d2, level_b_d3;
//
always @ (posedge clka or negedge rst_n)
begin
if (!rst_n) begin
level_b_d1 <= #DLY 1'b0;
level_b_d2 <= #DLY 1'b0;
level_b_d3 <= #DLY 1'b0;
end
else begin
level_b_d1 <= #DLY level_a_in;
level_b_d2 <= #DLY level_b_d1;
level_b_d3 <= #DLY level_b_d2;
end
end
assign pulse_b_pos = level_b_d2 & (~level_b_d3);
assign pulse_b_neg = level_b_d3 & (~level_b_d2);
assign level_b_out = level_b_d2;
endmodule
在跨时钟域处理单bit信号时,快时钟域的信号由于频率较快,信号的脉宽如果不足,就不会被慢时钟采样到,因此需要将快时钟产生的信号进行展宽,然后在进行打两拍来处理亚稳态。具体处理方式如下:
快到慢时钟域
//目的:使在clka下的脉冲信号pluse_a_in也能在clkb下采集到
module quick2slow (
// input
input rst_n , // system reset
input clka , // clockA
input clkb , // clockB
input pulse_a_in , // pulsee input from clka
// output
output pulse_b_out , // pulsee output in clkb
output level_b_out // level output in clkb
);
parameter DLY = 1 ; //模拟真实电路加入DLY
reg signal_a;
reg signal_b;
reg signal_b_b1;
reg signal_b_b2;
reg signal_b1_a1;
reg signal_b1_a2;
//对脉冲信号进行展宽处理
//引入signsl_a作为展宽信号,脉冲信号为1时拉高signal_a,signal_b1_a2为1时拉低signal_a,
//signal_b1_a2在后边进行定义
always @ (posedge clka or negedge rst_n)
begin
if (rst_n == 1'b0)
signal_a <= # DLY 1'b0 ;
else if (pulse_a_in)
signal_a <= # DLY 1'b1 ;
else if (signal_b1_a2)
signal_a <= # DLY 1'b0 ;
else ;
end
//将展宽后的信号signal_a引入到clkb下,定义为signal_b
always @ (posedge clkb or negedge rst_n)
begin
if (rst_n == 1'b0)
signal_b <= # DLY 1'b0 ;
else
signal_b <= # DLY signal_a ;
end
//在clkb下对signal_b打一拍得到signal_b_b1,
//在clkb下对signal_b打二拍得到signal_b_b2,
always @ (posedge clkb or negedge rst_n)
begin
if (rst_n == 1'b0) begin
signal_b_b1 <= # DLY 1'b0 ;
signal_b_b2 <= # DLY 1'b0 ;
end
else begin
signal_b_b1 <= # DLY signal_b ;
signal_b_b2 <= # DLY signal_b_b1 ;
end
end
//确定signal_a的信号下降沿
//选取 signal_b_b1作为signal_a的下降沿,但是他是在clkb下的信号,而signal_a是clka下的信号,可能存在踩不到的现象,因此对signal_b_b1在clka下同步打两拍得到signal_b1_a2
always @ (posedge clka or negedge rst_n)
begin
if (rst_n == 1'b0) begin
signal_b1_a1 <= # DLY 1'b0 ;
signal_b1_a2 <= # DLY 1'b0 ;
end
else begin
signal_b1_a1 <= # DLY signal_b_b1 ;
signal_b1_a2 <= # DLY signal_b1_a1 ;
end
end
assign pulse_b_out = signal_b_b1 & (~signal_b_b2) ;
assign level_b_out = signal_b_b1 ;
endmodule