1. 单线的CDC
①latch信号(电平信号),采用打拍方式,源时钟打一拍输出,目的时钟打两拍接收。
②脉冲信号,对于快到慢时钟,脉冲会被当毛刺滤掉,对于慢到快时钟,脉冲会变成电平信号,或者不清楚时钟关系,都可以采用握手方式。
2. 总线的CDC
总线:多根线都叫总线,并非指某种协议。
①异步fifo:原理是需要足够大的存储空间而达到源时钟域和目的时钟域数据吞吐速率的平衡。
②握手wave(fast—>slow/不清楚关系)
A信号latch住 —> 同步到B时钟 —>取B时钟上升沿 —> 同步到A时钟latch —> A的latch信号识别到上一步的latch拉低 —> B的latch也识别后拉低
reg a_latch;
reg b_latch;
reg b_latch_2r;
wire b;
reg b_feedback_latch;
reg c_latch;
reg c_latch_r;
wire busy;
//------------------------------------------------
always @(posege clk1 or negedge rst1_n)
begin
if (!rst1_n)
a_latch <= 1’b0;
else if (a)
a_latch <= 1’b1; //先在clk1域把a变成电平
else if (c_latch_r) //当目的时钟域反馈称脉冲b已产生,本电平会归0
a_latch <= 1’b0;
end
always @(posedge clk2 or negedge rst2_n)
begin
if (!rst2_n)
begin
b_latch <= 1’b0;
b_latch_r <= 1’b0;
b_latch_2r <= 1’b0;
end
else
begin
b_latch <= a_latch; //跨时钟第一拍,容易产生亚稳态
b_latch_r <= b_latch; //跨时钟第二拍,几乎没有亚稳态
b_latch_2r <= b_latch_r; //为了转换为脉冲而打拍
end
end
assign b = b_latch_r & (~b_latch_2r); //抓取b_latch_r的上升脉冲
always @(posedge clk2 or negedge rst2_n)
begin
if (!rst2_n)
b_feedback_latch <= 1’b0;
else if (b)
b_feedback_latch <= 1’b1; //反馈信号,当b起来以后它也Latch住
else if (~b_latch_r) //“~”和“!”对于单比特是可以混用的
b_feedback_latch <= 1’b0; //当源时钟的电平已归0后,反馈电平也归0
end
always @(posege clk1 or negedge rst1_n)
begin
if (!rst1_n)
begin
c_latch <= 1’b0;
c_latch_r <= 1’b0;
end
else
begin
c_latch <= b_feedback_latch; //跨时钟第一拍,容易产生亚稳态
c_latch_r <= c_latch; //跨时钟第二拍,几乎没有亚稳态
end
end
assign busy = a_latch | c_latch_r; //产生忙信号阻止新的握手请求 作者:皮特派 https://www.bilibili.com/read/cv15990283/ 出处:bilibili
总结:数据传输时可以采用异步fifo或者握手,握手结构较于异步fifo简单,根据实际应用环境考虑具体采用哪种方式,例如允许源时钟域在数据到达目的时钟域之前可以等待一段时间,该段时间不会有数据更新,则采用握手处理更好,结构简单,节省资源;如果应用环境存在允许数据不更新的情况下,也可以直接采用直接打拍的方式处理。
参考链接: