RTL设计(10)- 无毛刺时钟切换

时钟切换电路

1.MUX时钟切换

这是时钟切换的最简单实现方式,但是这种可能会产生毛刺(glitch),不推荐使用。
在这里插入图片描述

2.无毛刺时钟切换

在这里插入图片描述
电路图详解:
(1)由于sel至少对于其中一个时钟是异步信号,前面引入两级DFF是为了完成sel信号的跨时钟域。
(2)输入端引入输出反馈确保另一端的控制信号为低电平(另一端的输出关断)时发生切换
(3)最后一级插入下降沿触发触发器确保切换只发生在时钟为低电平时,避免glitch。

程序实例

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

仿真结果

vcs -R clock_switch.v tb_clock_switch.v

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/meng1506789/article/details/111410368