跨时钟域处理的概念
简单来讲,“跨时钟域处理”即:
①输入和输出的参照时钟不同。
②中间过程的多个步骤会由不同的时钟控制。
跨时钟域处理一般涉及“打拍”,即输入和输出中间空几个时钟周期作为缓冲,其目的在于:
打拍(缓冲)可以减小亚稳态概率。
打拍的经验原则:
一般的,在时钟切换的时候,依照后来的时钟打两拍。
(如由clk_a切换到clk_b,那么需要clk_b先空打两拍,再进行别的操作。)
【详细了解:CDC:跨时钟域处理】
多bit MUX同步的概念和框架
在data_en为高期间,data_in将保持不变,data_en为高至少保持3个B时钟周期。表明,当data_en为高时,可将数据进行同步。data_in端数据变化频率很低,相邻两个数据间的变化,至少间隔10个B时钟周期。
多bit MUX同步 解析
时钟clk_a负责:
① 数据data_in输入时,参照时钟a。(打一拍)
② 使能信号data_en输入时,参照时钟a。(打一拍)
时钟clk_b负责:
① 使能信号data_en延时打两拍,即过两个D触发器。这个过程参照时钟b。
② 数据最终输出dataout,输出时参照时钟b。
多bit MUX同步 代码实现
1. 时钟域clk_a: data_in和data_en寄存。(打一拍)
//clk_a打一拍接受数据和接受使能信号en
reg [3:0] data_reg;
always@(posedge clk_a or negedge arstn)
begin
if(!arstn) data_reg <= 0;
else data_reg <= data_in;
end
reg en_data_reg;
always@(posedge clk_a or negedge arstn)
begin
if(!brstn) en_data_reg <= 0;
else en_data_reg <= data_en; //存入
end
2. 时钟域clk_b: en信号打两拍 + dataout输出
//clk_b负责使能信号en的打拍
reg en_clap_one; //1
reg en_clap_two; //2
always@(posedge clk_b or negedge brstn)
begin
if(!brstn) en_clap_one <= 0;
else en_clap_one <= en_data_reg; //第一拍
end
always@(posedge clk_b or negedge brstn)
begin
if(!brstn) en_clap_two <= 0;
else en_clap_two <= en_clap_one; //第二拍
end
//clk_b负责输出
always@(posedge clk_b or negedge brstn)
begin
if(!brstn) dataout <= 0;
else dataout <= (en_clap_two) ? data_reg : dataout;
end
完整代码:
module mux(
input clk_a ,
input clk_b ,
input arstn ,
input brstn ,
input [3:0] data_in ,
input data_en ,
output reg [3:0] dataout
);
/*
跨时钟域传输:输入和输出的参照时钟不同。中间过程的多个步骤会由不同的时钟控制。
本题:clk_a接受数据--->clk_b延时两拍,然后数据才输出。
*/
//clk_a打一拍接受数据和接受使能信号en
reg [3:0] data_reg;
always@(posedge clk_a or negedge arstn)
begin
if(!arstn) data_reg <= 0;
else data_reg <= data_in;
end
reg en_data_reg;
always@(posedge clk_a or negedge arstn)
begin
if(!brstn) en_data_reg <= 0;
else en_data_reg <= data_en; //存入
end
//clk_b负责使能信号en的打拍
reg en_clap_one; //1
reg en_clap_two; //2
always@(posedge clk_b or negedge brstn)
begin
if(!brstn) en_clap_one <= 0;
else en_clap_one <= en_data_reg; //第一拍
end
always@(posedge clk_b or negedge brstn)
begin
if(!brstn) en_clap_two <= 0;
else en_clap_two <= en_clap_one; //第二拍
end
//clk_b负责输出
always@(posedge clk_b or negedge brstn)
begin
if(!brstn) dataout <= 0;
else dataout <= (en_clap_two) ? data_reg : dataout;
end
endmodule