RTL design (10)-glitch-free clock switching

Clock switching circuit

1. MUX clock switch

This is the simplest way to implement clock switching, but this may cause glitches and is not recommended.
Insert picture description here

2. Glitch-free clock switching

Insert picture description here
Detailed circuit diagram:
(1) Since sel is an asynchronous signal for at least one of the clocks , the two-level DFF is introduced to complete the cross-clock domain of the sel signal.
(2) The input end introduces output feedback to ensure that the control signal of the other end is low (the output of the other end is off) to switch .
(3) Insert the falling edge trigger flip-flop in the last stage to ensure that the switch only occurs when the clock is low and avoid glitch.

Program example

clock_switch.v

`timescale 1ns / 1ps

// Company: 
// Engineer: 
// 
// Create Date: 2020/12/19
// Author Name: Sniper
// Module Name: clock_switch
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 


module clock_switch(
    input rst_n,
    input clk0,
    input clk1,
	//async select
	input select,
	output clk_out
);

wire DFF0_in;
wire DFF1_in;
reg [2:0] DFF0_out;
reg [2:0] DFF1_out;

assign DFF0_in = ~DFF1_out[2] & ~select;
assign DFF1_in = ~DFF0_out[2] & select;

always @(posedge clk0 or negedge rst_n)
    if(!rst_n)
        DFF0_out[1:0] <= 2'b00;
    else
        DFF0_out[1:0] <= {
    
    DFF0_out[0],DFF0_in};

always @(negedge clk0 or negedge rst_n)
    if(!rst_n)
        DFF0_out[2] <= 1'b0;
    else
        DFF0_out[2] <= DFF0_out[1];


always @(posedge clk1 or negedge rst_n)
    if(!rst_n)
        DFF1_out[1:0] <= 2'b00;
    else
        DFF1_out[1:0] <= {
    
    DFF1_out[0],DFF1_in};

always @(negedge clk1 or negedge rst_n)
    if(!rst_n)
        DFF1_out[2] <= 1'b0;
    else
        DFF1_out[2] <= DFF1_out[1];


wire clk_out0;
wire clk_out1;

assign clk_out0 = clk0 & DFF0_out[2];
assign clk_out1 = clk1 & DFF1_out[2];
assign clk_out = clk_out0 | clk_out1;


endmodule

tb_clock_switch.v

`timescale 1ns / 1ps

// Company:
// Engineer:
//
// Create Date: 2020/12/19
// Author Name: Sniper
// Module Name: tb_clock_switch
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//


module tb_clock_switch;

//input
reg rst_n;
reg clk0;
reg clk1;
reg select;


//output
wire clk_out;



initial
begin
    rst_n = 0;
    clk0 = 0;
    clk1 = 0;
    select = 0;

	#100;
    rst_n = 1;

	#200;
    select = 1;
	#500;
    select = 0;


end

//clock
always #5 clk0 = ~clk0;
always #22 clk1 = ~clk1;



//DUT
clock_switch DUT
(
    .rst_n(rst_n),
    .clk0(clk0),
    .clk1(clk1),
    .select(select),
    .clk_out(clk_out)
);

initial
begin
    $dumpfile("tb_clock_switch.vcd");
    $dumpvars(0,tb_clock_switch);
end

initial #1000 $finish;

endmodule

Simulation results

vcs -R clock_switch.v tb_clock_switch.v

Insert picture description here

Guess you like

Origin blog.csdn.net/meng1506789/article/details/111410368