1.慢速时钟域同步到快速时钟域
输入:singal_in,来自10MHz慢速时钟域的单比特信号 输出:singal_out,输出100MHz快速时钟域的单比特信号 10MHz = 100ns 100MHz = 10ns
因为慢速时钟域的最短信号长度为1个时钟时钟周期即:100ns,大于快速时钟域的时钟周期10ns,所以只需要打3拍即可:
/* 从慢速时钟域同步到快速时钟域 */ module top( //inputs input clk, //快速时钟,时钟100MHz input rst_n, input signal_in, //来自慢速时钟域,时钟10MHz //outputs output signal_out //同步到快速时钟域之后的信号 ); reg signal_in_reg1; reg signal_in_reg2; reg signal_in_reg3; assign signal_out = signal_in_reg3; always @ (posedge clk) begin if(!rst_n) begin signal_in_reg1 <= 0; signal_in_reg2 <= 0; signal_in_reg3 <= 0; end else begin signal_in_reg1 <= signal_in; signal_in_reg2 <= signal_in_reg1; signal_in_reg3 <= signal_in_reg2; end end endmodule
仿真TB文件:
`timescale 1ns/1ps module top_tb; reg clk_100m; //Period=10ns; reg rst_n; reg signal_in; wire signal_out; initial begin clk_100m = 1; rst_n = 0; signal_in = 0; #50 rst_n = 1; #100 signal_in = 1; #100 signal_in = 0; #100 $stop; end always #(10/2) clk_100m <= !clk_100m; top top_ut( //inputs .clk(clk_100m), .rst_n(rst_n), .signal_in(signal_in), //outputs .signal_out(signal_out) ); endmodule
仿真波形:
慢速时钟域信号到快速时钟域信号的同步
2.快速时钟域同步到慢速时钟域
输入:singal_a,来自100MHz快速时钟域的单比特信号 输出:singal_b,输出10MHz慢速时钟域的单比特信号 10MHz = 100ns 100MHz = 10ns
这里仅仅针对输入信号的脉冲宽度仅有1个快速时钟周期宽度的信号,即singal_a的信号宽度仅有10ns宽,且两个脉冲间隔时间大于两个慢速时钟周期,即2*100ns=200ns。
先在快速时钟域下把边沿信号转换为电平信号,再在慢速时钟域下把电平信号打3拍,再在慢速时钟域下把电平信号转换为边沿信号:
/* 快速时钟域同步到慢速时钟域,针对脉冲宽度只有1个clk的信号 */ module fast_to_low( //inputs input clk_a, //快速时钟100MHz input rst_n_a, //复位信号 input signal_a, //快速时钟信号,单比特,1个clk宽度脉冲 input clk_b, //慢速时钟20MHz input rst_n_b, //outputs output signal_b //同步之后的慢速时钟域的信号 ); reg tmp; reg tmp_reg1; reg tmp_reg2; reg tmp_reg3; assign signal_b = tmp_reg2 ^ tmp_reg3; //电平信号转换为边沿 /* 在快速时钟域下,把单clk脉冲信号,转换为边沿信号,在高电平时翻转,要求两个脉冲间隔时间不能太短 */ always @ (posedge clk_a) begin if(!rst_n_a) tmp <= 0; else if(signal_a) tmp <= ~tmp; end /* 在慢速时钟域下对 */ always @ (posedge clk_b) begin if(!rst_n_b) begin tmp_reg1 <= 0; tmp_reg2 <= 0; tmp_reg3 <= 0; end else begin tmp_reg1 <= tmp; tmp_reg2 <= tmp_reg1; tmp_reg3 <= tmp_reg2; end end endmodule;
仿真TB文件:
`timescale 1ns/1ps module top_tb; reg clk_a; //100MHz = 10ns; reg clk_b; //10MHz = 100ns; reg rst_n_a; reg rst_n_b; reg signal_a; //快速时钟域信号 wire signal_b; //慢速时钟域信号 initial begin clk_a = 1; clk_b = 1; rst_n_a = 0; rst_n_b = 0; signal_a = 0; #300 rst_n_a = 1; rst_n_b = 1; #500 signal_a = 1; #10 signal_a = 0; #500 //两次脉冲时间间隔应该大于2*100ns=200ns,否则不能还原 signal_a = 1; #10 signal_a = 0; #1000 $stop; end always #(10/2) clk_a <= !clk_a; //100MHz = 10ns always #(100/2) clk_b <= !clk_b; //10MHz = 100ns fast_to_low fast_to_low_ut( //inputs .clk_a(clk_a), .rst_n_a(rst_n_a), .signal_a(signal_a), .clk_b(clk_b), .rst_n_b(rst_n_b), //outputs .signal_b(signal_b) ); endmodule
仿真波形:
快速时钟域信号到慢速时钟域信号的同步
详细的原理解释:单比特信号跨时钟域问题详解