单bit 跨时钟域,从慢时钟域到快时钟域
- 1,首先,了解一些问题
- 2,RTL代码设计
- 3,testbench测试代码
- 4,RTL代码和testbench综合的电路原理图
- 5,前仿真,验证![在这里插入图片描述](https://img-blog.csdnimg.cn/adf0a6ae5ee047abaca98f8deb6ed97e.png)
参考文献1,我的专栏,多bitMUX同步器
参考文献2,本文主要参考
1,首先,了解一些问题
(1)怎么进行跨时钟域的处理? 打两拍进行同步。
(2)同步前后时钟域的快慢延伸出了两种情况:
1,先快后慢;确保在快时钟域内能采样到值,本题解决这个问题。
2,先慢后快;
怎么将信号从快时钟域同步到慢时钟域呢?
答:将一个脉冲信号展宽为电平信号,让一个很短的脉冲信号变成一个很长的电平信号,就可以实现被快时钟域采样到。为了实现这个目的
,我们在慢时钟域重新通过组合逻辑设计寄存器外围电路,这里我们使用异或门来进行展宽。
区分电平同步、脉冲同步、边沿同步。
电平同步,就是正常的打两拍;
边沿同步,是在正常的打两拍的基础上,clkb
时钟域用边沿检测电路处理一下output
信号,让这个信号保证为一个周期。
脉冲同步,是指在clka
时钟域将脉冲信号处理成电平信号,再进行打两拍,再重复边沿同步的边沿检测电路的操作。
2,RTL代码设计
// 单bit 跨时钟域,从慢时钟域到快时钟域
module one_bit_cdc(
data, clka, clkb, rst_n, data_out
);
input data;
input clka;
input clkb;
input rst_n;
output data_out;
reg data_r;
reg [1:0] data_b_r;
always@(posedge clka or negedge rst_n)
if(!rst_n)
data_r <= 0;
else
data_r <= data;
// 打两拍,解决亚稳态
always@(posedge clkb or negedge rst_n)
if(!rst_n)
data_b_r <= 0;
else
begin
data_b_r[0] <= data_r;
data_b_r[1] <= data_b_r[0];
end
assign data_out = data_b_r[1];
endmodule
3,testbench测试代码
// 单bit 测试信号
module one_bit_cdc_tb;
reg data;
reg clka;
reg clkb;
reg rst_n;
wire data_out;
always #20 data = $random;
always #10 clka = ~clka; // 时钟 周期20
always #4 clkb = ~clkb; // 时钟 周期8
initial begin
rst_n = 0; clka = 1; clkb = 1;
#15; rst_n = 1;
end
one_bit_cdc uu(
.data(data),
.clka(clka),
.clkb(clkb),
.rst_n(rst_n),
.data_out(data_out)
);
endmodule