由一道某科笔试开始,如下:
解析:
电路功能:两个异步时钟源切换电路;
DFF1和DFF3作用:在选择路径插入一个上升沿触发器,用于缓存数据,将数据传递给下一级;若去掉,会电路产生由异步信号引起的亚稳态;
DFF2和DFF4采用负沿采用原因:SELECT与反馈输出相与,下降沿采样反馈可以保证一个时钟被完全取消选择后,输出才输出另一个时钟,从而避免产生毛刺。
前言
纯组合逻辑时钟切换电路:电平相反时,切换时钟不可避免产生毛刺;
相关时钟切换:下降沿切换(反馈实现),下个上升沿切换生效,消除毛刺;
无关时钟切换:下降沿触发之前添加一个上升沿触发器,消除亚稳态;
一、有毛刺的时钟切换
纯组合逻辑的时钟切换,由于为电平触发,不可避免会产生毛刺;
如图所示,这个时钟切换电路是一个纯组合逻辑,输出时钟(OUT CLOCK)由选择信号(SELECT)控制,当SELECT为1时输出CLK1,反之,输出CLK0.
看似很简单,实现了时钟的切换,实则存在着很大的隐患,如下图所示:
由图中可知,SELECT信号变化的位置没有和切换的时钟对齐;当SELECT信号发生改变时,当前时钟源(CLK0)正好处于高电平,因此,会在输出端产生毛刺。
对上图的Verilog描述:
代码语言:javascript复制assign outclk = (clk1 & select) | (~select & clk0);
二、相关时钟源的时钟切换
以下为两个时钟源成倍数的关系的时钟切换电路:
在每个时钟源的选择路径中插入一个负边沿触发的D触发器。确保在切换时钟源时,即使时钟正处在高电平,也不会影响输出变化;
当时钟源切换时,这个反馈可以保证一个时钟被完全取消选择后,输出才输出另一个时钟,从而避免产生毛刺;
电路描述:
当SELECT为0时,CLK1的那部分通路到输出无效,仅看下半部分电路即可,在CLK0的下降沿采样SELECT(取反后)信号,与CLK0相与之后输出;
当SELECT为1时,同理上半部分电路有效;
如图首先SELECT为0,也就是在CLK0的下降沿采样寄存SELECT(取反后)信号与CLK0相与,输出时钟为CLK0;
当在图中时刻SELECT由低电平变为高电平,此时未到CLK0的下降沿,寄存器的输出还将一直是高电平(SELECT之前为0,取反为1),当到达CLK0的下降沿时刻,采样到SELECT为高电平,此时SELECT为1,也就是下半部分电路从此无效,上半部分电路有效,此时需要等到CLK1的下降沿采样SELECT值,在此之前,输出仍为 CLK0,到达CLK1的下降沿后,输出变成了CLK1和SELECT的与,也就是CLK1。由图可见,输出时钟完成切换,并没有出现毛刺。
代码语言:javascript复制module glitch_2 (
input clk0,
input clk1,
input select,
input rst_n,
output clkout);
reg out1;
reg out0;
always @(negedge clk1 or negedge rst_n)begin
if(rst_n == 1'b0)begin
out1 <= 0;
end
else begin
out1 <= ~out0 & select;
end
end
always @(negedge clk0 or negedge rst_n)begin
if(rst_n == 1'b0)begin
out0 <= 0;
end
else begin
out0 <= ~select & ~out1;
end
end
assign clkout = (out1 & clk1) | (out0 & clk0);
endmodule
三、异步时钟源的时钟切换
异步时钟源的切换是在相关时钟源切换的基础上插入一个上升沿D触发器,对选择信号进行同步处理,避免产生亚稳态。
第一个触发器采样数据寄存,然后到第二个触发器输出第一个触发器寄存的数据。
还是按这张图进行仿真:
SELECT为0时候,clk0时钟上升沿采样得到DFF3Q,之后得到DFF4Q,下降沿采样得到DFF4_Q反馈,DFF4Q信号与clk0相与得到F;
DFF4_Q反馈到时钟域clk1,与SELECT相与,用clk1上升沿采样得到DFF1Q,之后得到DFF2Q,再用clk1下降沿采样得到DFF2_Q,DFF2Q信号与clk1相与得到输出E;
最终的输出为E与F的或,即输出clkout为无毛刺的时钟切换波形。
代码语言:javascript复制module glitch_DFF (
input clk0,
input clk1,
input select,
input rst_n,
output clkout
);
wire B;
reg DFF3Q, DFF4Q, DFF4_Q; //DFF4Q=Q,DFF4_Q=~Q
wire A;
reg DFF1Q, DFF2Q, DFF2_Q; //DFF2Q=Q,DFF2_Q=~Q
assign A = select & DFF4_Q;
assign B = ~select & DFF2_Q;
//第一级触发器用上升沿采样,选择信号与反馈信号的与运算
always@(posedge clk1 or negedge rst_n) begin
if(~rst_n)
DFF1Q <= 0;
else
DFF1Q <= A;
end
//第二级触发器用下降沿采样
always@(negedge clk1 or negedge rst_n) begin
if(~rst_n) begin
DFF2Q <= 0;
DFF2_Q <= 1;
end
else begin
DFF2Q <= DFF1Q;
DFF2_Q <= ~DFF1Q;
end
end //====================================================================
//第一级触发器用上升沿采样,选择信号与反馈信号的与运算
always@(posedge clk0 or negedge rst_n) begin
if(~rst_n)
DFF3Q <= 0;
else
DFF3Q <= B;
end
//第二级触发器用下降沿采样
always@(negedge clk0 or negedge rst_n) begin
if(~rst_n) begin
DFF4Q <= 0;
DFF4_Q <= 1;
end
else begin
DFF4Q <= DFF3Q;
DFF4_Q <= ~DFF3Q;
end
end
wire E, F;
assign E = clk1 & DFF2Q;
assign F = clk0 & DFF4Q;
assign clkout = E | F;
endmodule
参考资料:
https://www.eetimes.com/techniques-to-make-clock-switching-glitch-free/