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);

仿真波形


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM