實現信號分頻的Verilog方法有很多種,如果從本質上理解了分頻這一思路則遇到任何的分頻情況都能迎刃而解。因此首先來談談什麼是分頻。
對於偶數分屏,如四分頻,我們可以發現其分頻後的時鐘的跳變,無論是上升沿還是下降沿都是統一在原始時鐘信號的上升沿如clk1, 或者是下降沿如clk2。如下圖所示;
因此對於偶數的分頻,我們可以用一個計數器來實現;
module div_2(clk,rst,clk2);
input clk,rst;
output clk2;
reg [2:0] cnt;
always@(posedge clk or negedge rst)
if(!rst)
begin
cnt<=0;
clk2<=0;
end
else if(cnt == 3'b011)
begin
cnt <= 0
clk2 = clk2;
end
else if(cnt == 0)
begin
cnt <= cnt +1;
clk2 = ~clk2
end
else
begin
cnt <= cnt + 1;
clk2 = clk;
end
endmodule
而對於奇數分頻,顯然一個輸出時鐘的週期包含原始週期個數爲奇數個,則該輸出的時鐘的跳變則必定會出現在原始時鐘的不同跳變沿上,如圖2所示,這是一個5分頻的信號圖。可以看到原始信號clk的上升沿和下降沿都可能存在着clk_out的跳變。而計數器實現的倍頻信號則只能實現但跳變沿的輸出時鐘,因此,該奇數分頻的信號需要兩個不同跳變沿的輸出信號(Sig_1和Sig_2)進行合成。所以通過分析clk_out的波形,即當clk_out在clk上升沿時跳變時(紅色線),則讓Sig_2起作用;反之,則讓Sig_1起作用(藍線)。因此我們可以得到兩個不是50%佔空比的時鐘信號Sig_1和Sig_2.因此我們可以開始用計數器實現這一功能,但相比偶數計數器,這兩個計數器需要在0和中間某個數字處進行翻轉,當設計5分頻時,該數字爲3。推理可得當需要設計N分頻時鐘時,需要在0和(N+1)/2處設置翻轉。
示例如下,當設計13分頻的時鐘信號時需要在0和7處進行翻轉:
module tclk_gena(clk, rst_n,tclk);
input clk;
input rst_n;
reg [4:0] cnt1;
reg [4:0] cnt2;
output wire tclk;
reg clk1;
reg clk2;
always@(posedge clk or negedge rst_n)
if(!rst_n)
begin
cnt1 <= 0;
clk1 = 1'b1;
end
else if(cnt1 == 0)
begin
cnt1 <= cnt1 + 1'b1;
clk1 = ~clk1;
end
else if(cnt1 == 4'b00111)
begin
cnt1 <= cnt1 + 1'b1;
clk1 = ~clk1;
end
else if(cnt1 == 4'b01100)
begin
cnt1 <= 4'b00000;
clk1 <= clk1;
end
else
begin
cnt1 <= clk1;
cnt1 <= cnt1 + 4'b1;
end
always@(negedge clk or negedge rst_n)
if(!rst_n)
begin
cnt2 <= 0;
clk2 = 1'b1;
end
else if(cnt2 == 0)
begin
cnt2 <= cnt2 + 1'b1;
clk2 = ~clk2;
end
else if(cnt2 == 4'b00111)
begin
cnt2 <= cnt2 + 1'b1;
clk2 = ~clk2;
end
else if(cnt2 == 4'b01100)
begin
cnt2 <= 4'b00000;
clk2 <= clk2;
end
else
begin
cnt2 <= clk2;
cnt2 <= cnt2 + 4'b1;
end
assign tclk = ~(clk1 | clk2);
endmodule
測試代碼如下
`timescale 1ns/1ns
`define clk_period 20
module tclk_gena_tb;
reg clk;
reg rst_n;
wire tclk;
tclk_gena tclk_gena(
.clk(clk),
.rst_n(rst_n),
.tclk(tclk)
);
initial
clk = 1'b1;
always #(`clk_period/2) clk = ~clk;
initial
begin
rst_n = 0;
#(`clk_period*20);
rst_n = 1;
#(`clk_period*200);
$stop;
end
endmodule