Verilog-数字时钟无毛刺切换


参考博客:https://blog.csdn.net/u014070258/article/details/90052426

原题(卓胜微电子2020)

时钟输入clk, sel为时钟控制信号,sel=0输出clk, sel = 1 输出clk的四分频,要求异步复位,保持时钟信号的完整性。

实现思路

  • 毛刺产生的根本原因:是切换控制信号sel相对于时钟信号可以在任何时间里发生改变,本质是切换信号为异步信号。

  • 解决办法:任何时钟的高电平状态下的切换都需要避免。当两个输入时钟之间是倍数关系时,插入下降沿触发触发器确保切换只发生在本时钟为低电平时候,引入输出反馈确保另外一路的时钟为低电平时候发生切换。

Verilog代码

`timescale 1ns / 1ps

module clk_switch(
	input clk,
	input rstn,
	
	input sel,
	output clk_o
    );

// 产生4分频时钟
reg [1:0] cnt;
wire clk_div4;

always @(posedge clk or negedge rstn) begin
	if(!rstn) cnt <= 2'd0;
	else cnt <= cnt + 1'b1;
end

assign clk_div4 = cnt[1];

// 时钟切换电路: sel=0输出clk, sel=1输出clk_div4
reg clk_en;
reg clk_div4_en;

always @(negedge clk or negedge rstn) begin
	if(!rstn) clk_en <= 1'b0;
	else clk_en <= ~sel & ~clk_div4_en;
end

always @(negedge clk_div4 or negedge rstn) begin
	if(!rstn) clk_div4_en <= 1'b0;
	else clk_div4_en <= sel & ~clk_en;
end

// 时钟输出电路
assign clk_o = (clk_en & clk) | (clk_div4_en & clk_div4);


endmodule

测试激励

`timescale 1ns / 1ps

module clk_switch_tb;

	// Inputs
	reg clk;
	reg rstn;
	reg sel;

	// Outputs
	wire clk_o;

	// Instantiate the Unit Under Test (UUT)
	clk_switch uut (
		.clk(clk), 
		.rstn(rstn), 
		.sel(sel), 
		.clk_o(clk_o)
	);

	initial begin
		// Initialize Inputs
		clk = 0;
		rstn = 0;
		sel = 0;

		// Wait 100 ns for global reset to finish
		#500;
		rstn = 1;
		
		#400;
		sel = 1;
		
		#210;
		sel = 0;
		
		#315;
		sel = 1;
		
		#205;
		sel = 0;
		
        
		// Add stimulus here

	end
	
	always #20 clk=~clk;
      
endmodule


仿真波形

亚稳态问题

因为sel为异步信号,为了降低亚稳态,可以再加一级寄存器来帮助稳定数据,然后将数据传递到下一级。首级寄存器正沿触发,次级寄存器负沿触发。

考虑亚稳态的代码

reg clk_reg1,clk_en;
reg clk_div4_reg1,clk_div4_en;


// 消亚稳态
always @(posedge clk or negedge rstn) begin
	if(!rstn) clk_reg1 <= 1'b0;
	else clk_reg1 <= ~sel & ~clk_div4_en;
end

always @(posedge clk_div4 or negedge rstn) begin
	if(!rstn) clk_div4_reg1 <= 1'b0;
	else clk_div4_reg1 <= sel & ~clk_en;
end

// 本时钟低电平切换
always @(negedge clk or negedge rstn) begin
	if(!rstn) clk_en <= 1'b0;
	else clk_en <= clk_reg1;
end

always @(negedge clk_div4 or negedge rstn) begin
	if(!rstn) clk_div4_en <=1'b0;
	else clk_div4_en <= clk_div4_reg1;
end

assign clk_o = (clk_en & clk) | (clk_div4_en & clk_div4);

仿真波形

原文地址:https://www.cnblogs.com/wt-seu/p/12868190.html