• Verilog -- 无glitch时钟切换电路


    Verilog -- 无glitch时钟切换电路

    https://blog.csdn.net/bleauchat/article/details/96180815

    题目:用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
    

    缺点: 输出会有一个周期延时(较长的那个周期)

    仿真波形:

  • 相关阅读:
    fiddler使用
    Laravel数据库操作
    mysql 小知识点备忘(一)
    移动端和服务器端通信
    js函数和代码片段
    tomcat9目录结构解析
    数据库三范式的理解
    win10修改hosts文件
    Java十六进制字符串与二进制数组互转、&0xff的作用
    15、SpringBoot实现Excel的导入导出
  • 原文地址:https://www.cnblogs.com/lyc-seu/p/12627297.html
Copyright © 2020-2023  润新知