在数字电路设计中,模块的运行时钟切换时,需要考虑到是否会产生glitch,小小的glitch有可能导致电路运行的错误。所以时钟切换时需要特别的处理。
下面是收集的几种无毛刺的时钟切换电路。
1. openMSP430 ipcore中的时钟切换电路
(来源:OpenCore)
`timescale 1ns/10ps
module clock_mux (
// OUTPUTs
//=========
output clk_out, // Clock output
// INPUTs
//=========
input clk_in0, // Clock input 0
input clk_in1, // Clock input 1
input reset, // Reset
input select_in // Clock selection
);
//==================================================================================================================//
// 1) CLOCK MUX //
//==================================================================================================================//
// //
// The following (glitch free) clock mux is implemented as following: //
// //
// //
// //
// dff0a dff0b //
// +-----. +--------+ +--------+ //
// select_in >>----+-------------O| \ | | | | +-----. //
// | | |---| D Q |---| D Q |--+-------| \ //
// | +-------O| / | | | | | | |O-+ //
// | | +-----' | | | | | +--O| / | //
// | | | /\ | | /\ | | | +-----' | //
// | | +--+--+--+ +--+--+--+ | | | //
// | | O | | | | //
// | | | | | | | +-----. //
// clk_in0 >>----------------------------------+------------+-----------+ +--| \ //
// | | | | |----<< clk_out//
// | | +---------------------------------------+ +--| / //
// | | | | +-----' //
// | +---------------------------------------------+ | //
// | | dff1a dff1b | | //
// | | +-----. +--------+ +--------+ | | //
// | +-O| \ | | | | | +-----. | //
// | | |---| D Q |---| D Q |--+-------| \ | //
// +--------------| / | | | | | |O-+ //
// +-----' | | | | +--O| / //
// | /\ | | /\ | | +-----' //
// +--+--+--+ +--+--+--+ | //
// O | | //
// | | | //
// clk_in1 >>----------------------------------+------------+-----------+ //
// //
// //
//==================================================================================================================//
//----------------------------------------
// Regs declare
//----------------------------------------
reg dff0a,dff0b;
reg dff1a,dff1b;
wire clk_in0_inv = ~clk_in0;
wire clk_in1_inv = ~clk_in1;
//----------------------------------------
// clk_in0 path
//----------------------------------------
// negedge of clk_in0
always @(posedge clk_in0_inv or posedge reset)
if(reset) dff0a <= 1'b1;
else dff0a <= !select_in & !dff1b;
always @(posedge clk_in0 or posedge reset)
if(reset) dff0b <= 1'b1;
else dff0b <= dff0a;
wire clk_in0_gate = ~(~clk_in0 & dff0b);
//----------------------------------------
// clk_in1 path
//----------------------------------------
// negedge of clk_in1
always @(posedge clk_in1_inv or posedge reset)
if(reset) dff1a <= 1'b0;
else dff1a <= select_in & !dff0b;
always @(posedge clk_in1 or posedge reset)
if(reset) dff1b <= 1'b0;
else dff1b <= dff1a;
wire clk_in1_gate = ~(~clk_in1 & dff1b);
//-----------------------
// clock mux out
//-----------------------
assign clk_out = clk_in0_gate & clk_in1_gate;
endmodule
- 《verilog编程艺术》中的时钟切换电路
`timescale 1ns/1ns
module clk_switch
(
input clk_a,
input clk_b,
input select,
output out_clk
);
reg q1,q2,q3,q4;
wire or_one,or_two,or_three,or_four;
always @(posedge clk_a)
if(clk_a==1'b1) begin
q1 <= q4;
q3 <= or_one;
end
always @(posedge clk_b)
if(clk_b==1'b1) begin
q2 <= q3;
q4 <= or_two;
end
assign or_one = (!q1) | (select == 1'b1);
assign or_two = (!q2) | (select == 1'b0);
assign or_three = (q3) | (clk_a);
assign or_four = (q4) | (clk_b);
assign out_clk = or_three & or_four;
endmodule
module clk_switch_tb;
reg clk_a,clk_b;
reg select;
wire out_clk;
clk_switch clk_switch(clk_a,clk_b,select,out_clk);
initial begin
clk_a = 0;
forever #50 clk_a = !clk_a;
end
initial begin
clk_b = 0;
forever #10 clk_b = !clk_b;
end
initial begin
select = 0;
#1000;
select = 1;
#1000;
select = 0;
#1000;
select = 1;
#1000;
$finish;
end
endmodule