ic验证需要学习ic设计的什么知识(free时钟选择器的设计过程)
ic验证需要学习ic设计的什么知识(free时钟选择器的设计过程)q1和q2之间,q3和q4之间的控制逻辑应该是相似的。该组合逻辑有两个输入,以clka时钟为例,应该满足以下条件:在q1和q2之间还存在简单的组合逻辑,该组合逻辑的输入分别是sel和feedback_b,feedback_b与q4输出相关,也就是与clkb输出状态相关;同理,在q3和q4之间也存在这样的组合逻辑。这两部分组合逻辑的作用是为了实现sel信号对时钟使能/禁止的控制。为了满足上述条件,在最简的实现下,clka时钟域至少存在一个寄存器,该寄存器输出clka的时钟控制信号,用于实现clka的同步输出/禁止控制,该寄存器记为q2;同理clkb时钟域也存在这样一个寄存器,记为q4。除了clka同步禁止外,禁止和启动顺序也很重要。clka需要先被禁止,然后clkb同步使能。所以,clkb的控制逻辑需要知道何时clka被禁止。为了实现该过程,那么q2的输出一定会被反馈给clkb的控制逻辑,然
芯片设计,包括FPGA程序设计中,都可能出现时钟选择器。在时钟选择器设计中,非常重要的一点就是避免在时钟切换时产生毛刺。
关于glitch free时钟选择器设计的文章很多,但大多数都是直接给出了几种设计方法,而没有思考过程。本文则记录了自己的这一过程。
1. glitch free时钟选择器的基本结构会是什么样的?假设存在两个时钟,clka和clkb,sel为0时clka输出,为1时clkb输出;当前sel为0,clka正在输出。在上述假设下,如果sel切换为1,那么clkb需要输出。
首先从考虑实现glitch free需要满足什么样的条件。第一,clka的输出需要先被同步关闭;第二,clkb需要在clka同步关闭后,再被同步开启。
为了满足上述条件,在最简的实现下,clka时钟域至少存在一个寄存器,该寄存器输出clka的时钟控制信号,用于实现clka的同步输出/禁止控制,该寄存器记为q2;同理clkb时钟域也存在这样一个寄存器,记为q4。
除了clka同步禁止外,禁止和启动顺序也很重要。clka需要先被禁止,然后clkb同步使能。所以,clkb的控制逻辑需要知道何时clka被禁止。为了实现该过程,那么q2的输出一定会被反馈给clkb的控制逻辑,然后送给q4。q2的输出为clka时钟域的信号,当他被送给q4前,需要经由clkb重新进行同步处理。同理,q4到q2之间也存在同样的反馈回路和同步过程。
基于上述分析,glitch free时钟选择器的最简实现中,至少包含4个寄存器。q2和q4分别产生clka和clkb的同步时钟控制信号。在q2之前还存在q1,在q4之前还存在q3,分别实现对上文提到的反馈信号的同步处理。
在q1和q2之间还存在简单的组合逻辑,该组合逻辑的输入分别是sel和feedback_b,feedback_b与q4输出相关,也就是与clkb输出状态相关;同理,在q3和q4之间也存在这样的组合逻辑。这两部分组合逻辑的作用是为了实现sel信号对时钟使能/禁止的控制。
2. q1和q2,q3和q4之间的组合逻辑是什么样的?q1和q2之间,q3和q4之间的控制逻辑应该是相似的。该组合逻辑有两个输入,以clka时钟为例,应该满足以下条件:
当sel为1时,clka输出被禁止,feedback_b的值不重要;
当sel由1切换为0时,组合逻辑输出不会立即发生变化。而是等待feedback_b,当feedback_b也发生变化时,组合逻辑输出才会变化,最终使能clka。
基于上述思考,可以考虑在q1和q2之间使用“与”逻辑。该“与”逻辑的行为是:当sel为1时,组合逻辑输出立即变化,导致clka最先被同步关闭;当sel由1变为0时,只是满足了“与”逻辑输出值变化的一个条件,需要继续等待feedback_b变化后,输出才会翻转,最终使能clka。
3. 时钟使能/禁止逻辑这部分选择的自由度应该比较大。我们就选择使用或逻辑来实现时钟输出的使能和禁止,当时钟被禁止时,输出为常1。clka和clkb的“或”逻辑输出,进行“与”操作后作为最终的时钟输出。如下图。
4. 分析并确定具体的实现逻辑当我们确定基本结构和组合逻辑的基本形式后,需要找到一个切入点来确定最终的实现形式。个人认为最好的切入点是sel变化时,被禁止的时钟。因为禁止行为最先发生,使能行为后发生。
假设sel由0变为1,此时q2的输出需要在下一个clka上升沿后立即变为1,从而实现clka的禁止操作。
代码如下。
`timescale 1ps / 1ps
module clk_switch (
input clka
input clkb
input sel // 0: clka 1: clkb
output clk_o
);
reg ff1 ff2 ff3 ff4;
wire clka_inner_src clkb_inner_src;
always_ff @ (posedge clka) begin
ff2 <= ~sel & ~ff1;
ff1 <= ff4;
end
always_ff @ (posedge clkb) begin
ff3 <= ff2;
ff4 <= sel & ~ff3;
end
assign clka_inner_src = ~ff2 | clka;
assign clkb_inner_src = ~ff4 | clkb;
assign clk_o = clka_inner_src & clkb_inner_src;
endmodule