“少就是多”系列:数字IC设计知识与手撕代码(二)跨时钟域处理

一、所谓同步电路

电路设计中的所有寄存器,它的时钟都来自于同一个时钟源,满足时序时,同一时钟沿会触发所有寄存器同时作出采样动作,则称这些寄存器是同步的。
在这里插入图片描述

推论一

对概念进行推广,假设设计中的有些寄存器被同一个时钟所驱动,而另一些则被该时钟的分频时钟所驱动,这样的电路仍然属于同步电路。

推论二

进一步对概念进行推广,凡是时钟相位有关系的电路,都可以看作同步电路。
例如,如图所示的数字电路设计中从模拟电路中引入了两个时钟,分别是clk1、clk2。两个时钟在模拟电路中有着相同的源头,相位关系也是固定的,因而可以视为是同步的。
在这里插入图片描述

二、所谓异步时钟

如果数字设计中的若干个时钟之间,不存在任何的相位关系和频率关系,则称TA们两两之间为异步时钟。如图所示的clk1和clk3为异步时钟,分管不同的时钟域。
而处在不同时钟域下的信号成为异步信号。
在这里插入图片描述

跨时钟域问题的产生

两个处在异步时钟域下的信号不会完全保持隔离,有时也需要相互交流。这样就衍生出了跨时钟域的问题。

三、所谓跨时钟域处理

如上文所述,异步信号之间也存在相互交流的需求,但这样的信号之间不能直接用金属线相连,因为异步时钟之间的关系是不确定的。

当寄存器要采集异步信号后,其建立时间和保持时间无法保证符合要求,很可能在寄存器输出端产生亚稳态。

至于什么是亚稳态,这也是值得细细探讨的课题,为了秉持本系列文章“少就是多”的原则,笔者不作深入说明,可以简单的认为信号在此时处于一种不确定的状态,不是0也不是1,需要经过一段时间才能恢复到稳定的0/1状态。

为了避免上述的亚稳态问题,需要对异步信号跨时钟域做特殊的处理,即:跨时钟域处理。

四、所谓最重要的手撕代码环节

1、单比特,慢时钟域到快时钟域,打两拍

如图为著名的背靠背跨时钟域处理方法,也就是我们常说的打两拍、双锁存器法。请编写Verilog代码实现这一电路。
在这里插入图片描述

always@(posedge clk1, negedge rst1_n) begin
	if (rst1_n == 1'b0) begin
		b <= 1'b0;
	end else begin
		b <= a;
end

always@(posedge clk2, negedge rst2_n) begin
	if (rst2_n == 1'b0) begin
		c <= 1'b0;
		d <= 1'b0;
	end else begin
		c <= b;
		d <= c;
	end
 end

预期的波形图如图所示。
在这里插入图片描述

2、单比特,慢到快,快到慢,通用

跨时钟域处理问题中,针对快时钟域到慢时钟域的情况,一般有脉冲同步器、脉冲展宽法等。根据这些同步器的思想,设计1个单比特通用的跨时钟域结构,使用Verilog实现。
(提示:信号锁存)。

always@(posedge clk1, negedge rst1_n) begin
	if (rst1_n == 1'b0) begin
		a_latch <= 1'b0;
	end else if (a == 1'b1) begin
		a_latch <= 1'b1;
	end else if (c_latch_r == 1'b1) begin
		a_latch <= 1'b0;
	end
end

always@(posedge clk2, negedge rst2_n) begin
	if (rst_n == 1'b0) 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_2r;
	end
end

assign b = (b_latch_r == 1'b1) && (b_latch_2r == 1'b0);

always@(posedge clk2, negedge rst2_n) begin
	if (rst_n == 1'b0) begin
		b_feedback_latch <= 1'b0;
	end else if (b == 1'b1) begin
		b_feedback_latch <= 1'b1;
	end else if (b_latch_r == 1'b0) begin
		b_feedback_latch <= 1'b0;
	end
end

always@(posedge clk1, negedge rst1_n) begin
	if (rst1_n == 1'b0) 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;

预期波形图如下:
在这里插入图片描述

3、多比特,握手,handshake

多比特跨时钟域处理的方法有很多,比如:格雷码同步法、DMUX、握手、FIFO。其中,握手同步法的通用性更强且不相FIFO那样占用较大的存储空间,是比较常用的跨时钟域方法。请用Verilog实现。

always@(posedge clk1, negedge rst1_n) begin
	if (rst1_n == 1'b0) begin
		vld1_latch <= 1'b0;
	end else if (a == 1'b1) begin
		vld1_latch <= 1'b1;
	end else if (c_latch_r == 1'b1) begin
		vld1_latch <= 1'b0;
	end
end

always@(posedge clk2, negedge rst2_n) begin
	if (rst_n == 1'b0) begin
		vld2_latch <= 1'b0;
		vld2_latch_r <= 1'b0;
		vld2_latch_2r <= 1'b0;
	end else begin
		vld2_latch <= vld1_latch;
		vld2_latch_r <= vld1_latch;
		vld2_latch_2r <= vld1_latch_2r;
	end
end

assign vld2 = (vld2_latch_r == 1'b1) && (vld2_latch_2r == 1'b0);

always@(posedge clk2, negedge rst2_n) begin
	if (rst_n == 1'b0) begin
		vld2_feedback_latch <= 1'b0;
	end else if (vld2 == 1'b1) begin
		vld2_feedback_latch <= 1'b1;
	end else if (vld2_latch_r == 1'b0) begin
		vld2_feedback_latch <= 1'b0;
	end
end

always@(posedge clk1, negedge rst1_n) begin
	if (rst1_n == 1'b0) begin
		c_latch <= 1'b0;
		c_latch_r <= 1'b0;
	end else begin
		c_latch <= vld2_feedback_latch;
		c_latch_r <= c_latch;
	end
end

assign busy = vld1_latch | c_latch_r;

always@(posedge clk2, negedge rst2_n) begin
	if (rst2_n == 1'b0) begin
		dat2 <= 'd0;
	end else if (vld2 == 1'b1) begin
		dat2 <= dat1;
	end
end

五、参考文献

《数字IC设计入门》。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值