要開始編寫verilog代碼了,以常用的分頻為例,編寫一個(gè)簡(jiǎn)單的代碼。
FPGA設(shè)計(jì)中,分頻分為偶數(shù)分頻和奇數(shù)分頻。
偶數(shù)分頻只要計(jì)上升沿的個(gè)數(shù),然后按照分頻要求的不同計(jì)相應(yīng)個(gè)數(shù)的上升沿并進(jìn)行波形翻轉(zhuǎn)即可。
例如二分頻,每計(jì)到一個(gè)上升沿,波形翻轉(zhuǎn)一次;
例如四分頻,每計(jì)到兩個(gè)上升沿,波形翻轉(zhuǎn)一次。
奇數(shù)分頻相對(duì)比較麻煩,因?yàn)槠鏀?shù)分頻經(jīng)常要在給出時(shí)鐘的下降沿進(jìn)行翻轉(zhuǎn),而Verilog本質(zhì)上是硬件描述,設(shè)計(jì)的本質(zhì)仍然是硬件設(shè)計(jì)。在綜合設(shè)計(jì)時(shí),Verilog代碼必須映射到FPGA上的可用硬件上。
FPGA常用的電路是觸發(fā)器,觸發(fā)器是一個(gè)具有時(shí)鐘且僅對(duì)該時(shí)鐘的一個(gè)邊沿敏感的器件。
always@(posedge clk)綜合后映射到只對(duì)一個(gè)時(shí)鐘邊沿敏感的觸發(fā)器,always@(posedge
clk or negedge rst)綜合后映射到有一個(gè)異步控制端且僅對(duì)時(shí)鐘的一個(gè)邊沿敏感的觸發(fā)器。
不管always@()綜合后映射到哪種觸發(fā)器,它都只能使用一個(gè)時(shí)鐘沿觸發(fā)。
奇數(shù)分頻注定要比偶數(shù)分頻復(fù)雜,可以采用這樣的方式進(jìn)行奇數(shù)分頻:
假設(shè)要對(duì)給定的時(shí)鐘進(jìn)行2N+1分頻:先計(jì)數(shù);將計(jì)數(shù)分成N、N+1的兩段;前一段將變量div1置0,后一段將變量div1置1;用一個(gè)下降沿觸發(fā)的觸發(fā)器,div1延遲半個(gè)時(shí)鐘周期后輸出,生成div2;div1和div2相與,即得到分頻后的時(shí)鐘。
module FreDivDou(
input? clk_i,
input? rst_n_i,
output div2_o,
output div3_o,
output div4_o,
output dou2_o,
output dou3_o
??? );
// 二分頻:在原來時(shí)鐘的上升沿翻轉(zhuǎn)
reg div2_o_r;
always @(posedge clk_i or negedge rst_n_i)
begin
? if(!rst_n_i)
??? div2_o_r <= 0;
? else
??? div2_o_r <= ~div2_o_r;
end
//div2_o_r要在always塊內(nèi)賦值,需要定義成reg型
//assign相當(dāng)于一條連線,將表達(dá)式右邊的電路直接通過wire(線網(wǎng)型)連接到左邊,
//左邊信號(hào)必須是wire型(output屬于wire型)。當(dāng)右邊變化時(shí),左邊立刻發(fā)生變化。
assign div2_o = div2_o_r;?
//四分頻,計(jì)數(shù),每計(jì)夠兩個(gè)上升沿翻轉(zhuǎn)一次
reg [1:0]? counter_div4;
reg div4_o_r;
always @(posedge clk_i or negedge rst_n_i)
begin
? if(!rst_n_i)? begin
??? counter_div4 <= 0;
??? div4_o_r <= 0;
? end
? else
??? if(counter_div4 <= 0)begin
????? counter_div4 <= 'b1;
????? div4_o_r <= div4_o_r;
??? end
??? else if(counter_div4 <='b1) begin
???? counter_div4 <= 0;
????? div4_o_r <=~div4_o_r;
??? end???
?end
assign div4_o = div4_o_r;
//3分頻,第0個(gè)上升沿div1為1,第1、2個(gè)上升沿div1為0
reg div1,div2;
reg [1:0] counter_div3;
always @(posedge clk_i or negedge rst_n_i)
begin
? if(!rst_n_i) begin
??? div1 <= 0;
??? counter_div3 <= 0;
? end
? else if(counter_div3 == 'd0)begin
??? div1 <= 'b1;
??? counter_div3 <=counter_div3 + 'b1;
? end
? else if(counter_div3 == 'd1)begin
??? div1 <= 0;
??? counter_div3 <=counter_div3 + 'b1;
? end
? else? begin
??? div1 <= 0;
??? counter_div3 <= 0;
? end
end
//3分頻,div1在時(shí)鐘的下降沿產(chǎn)生div2
always @(negedge clk_i or negedge rst_n_i)
if(!rst_n_i)
? div2 <= 0;
else
? div2 <= div1;
assign div3_o = div1 | div2;???
endmodule