Verilog -- 无glitch时钟切换电路
题目:用Verilog实现glitch free时钟切换电路。输入sel,clka,clkb,sel为1输出clka,sel为0输出clkb
第一种
纯组合逻辑
module clk_select1(
input clk1,
input clk2,
input rst_n,
input sel,
output clk_out
);
assign clk_out = sel?clk1:clk2;
endmodule
缺点:会有毛刺
第二种
在时钟的下降沿寄存选择信号(SELECT)可确保在任一时钟处于高电平时输出端不会发生变化,从而防止斩波输出时钟(意思是下降沿寄存,可以保证下降沿到来之前输出端保持不变,这样就不会斩断当前时钟了)
缺点:当sel信号出现再clk的下降沿,或者两个寄存器的下降沿重合的地方可能会产生亚稳态
代码:
module clk_select2(
input clk1,
input clk2,
input rst_n,
input sel,
output clk_out
);
reg ff1;
reg ff2;
always @(negedge clk1 or negedge rst_n) begin
if(!rst_n) ff1 <= 1'b0;
else begin
ff1 <= ~ff2 & sel;
end
end
always @(negedge clk2 or negedge rst_n) begin
if(!rst_n) ff2 <= 1'b0;
else begin
ff2 <= ~ff1 & ~sel;
end
end
assign clk_out = (ff1 & clk1) | (ff2 & clk2);
endmodule
对于第一种会有毛刺,而第二种则不会,但是当clk1和clk2是纯异步的情况下(有skew) :
第三种
第二种可能会有亚稳态,所以可以加两级寄存器缓冲。
代码如下:
`timescale 1ns/1ps
module clk_select3(
input clk1,
input clk2,
input rst_n,
input sel,
output clk_out
);
reg ff1,ff1_d;
reg ff2,ff2_d;
always @(negedge clk1 or negedge rst_n) begin
if(!rst_n) {ff1,ff1_d} <= 2'b00;
else begin
ff1_d <= ~ff2 & sel;
ff1 <= ff1_d;
end
end
always @(negedge clk2 or negedge rst_n) begin
if(!rst_n) {ff2,ff2_d} <= 2'b00;
else begin
ff2_d <= ~ff1 & ~sel;
ff2 <= ff2_d;
end
end
assign clk_out = (ff1 & clk1) | (ff2 & clk2);
endmodule
testbench:
`timescale 1ns/1ps
module clk_select_tb;
reg clk1;
reg clk2;
reg rst_n;
reg sel;
wire clk_comb;
wire clk_reg1;
wire clk_reg2;
initial begin
clk1 = 1;
clk2 = 1;
fork
forever #1 clk1 = ~clk1;
begin
#1.2;
clk2 = 1;
forever #5 clk2 = ~clk2;
end
join_none
rst_n = 1;
sel = 0;
#2 rst_n = 0;
#10 rst_n = 1;
#21.7 sel = 1;
end
initial begin
$fsdbDumpvars();
$fsdbDumpMDA();
$dumpvars();
#100 $finish;
end
clk_select1 U_CLK_SEL_0(
.clk1 ( clk1 ),
.clk2 ( clk2 ),
.clk_out ( clk_comb ),
.sel ( sel ),
.rst_n ( rst_n )
);
clk_select2 U_CLK_SEL_1(
.clk1 ( clk1 ),
.clk2 ( clk2 ),
.clk_out ( clk_reg1 ),
.sel ( sel ),
.rst_n ( rst_n )
);
clk_select3 U_CLK_SEL_2(
.clk1 ( clk1 ),
.clk2 ( clk2 ),
.clk_out ( clk_reg2 ),
.sel ( sel ),
.rst_n ( rst_n )
);
endmodule
缺点: 输出会有一个周期延时(较长的那个周期)
仿真波形: