? 模塊化設(shè)計(jì)是FPGA設(shè)計(jì)中一個(gè)很重要的技巧,它能夠使一個(gè)大型設(shè)計(jì)的分工協(xié)作、仿真測(cè)試更加容易,代碼維護(hù)或升級(jí)也更加便利。
? 如圖3.28所示,一般整個(gè)設(shè)計(jì)工程的頂層文件里只做例化,不做邏輯處理。頂層模塊下會(huì)包含多個(gè)子模塊,比如圖中的模塊A、模塊B、模塊C等等,而模塊A、B、C下又可以再為分多個(gè)子模塊實(shí)現(xiàn),如A模塊可以包含子模塊A1、A2和A3等。
圖3.28 模塊設(shè)計(jì)示意圖
? 采用模塊化的設(shè)計(jì),就可以將大規(guī)模復(fù)雜系統(tǒng)按照一定規(guī)則劃分成若干模塊,然后對(duì)每個(gè)模塊分別進(jìn)行設(shè)計(jì)輸入、綜合與實(shí)現(xiàn),并將實(shí)現(xiàn)結(jié)果約束在預(yù)先設(shè)置好的區(qū)域內(nèi),最后將所有模塊的實(shí)現(xiàn)結(jié)果進(jìn)行整合集成,就能完成整個(gè)系統(tǒng)的設(shè)計(jì)。
? 模塊化設(shè)計(jì)的實(shí)現(xiàn)一般包含以下步驟。
●初始預(yù)算,本階段是實(shí)現(xiàn)步驟的第一步,對(duì)整個(gè)模塊化設(shè)計(jì)起著指導(dǎo)性的作用。在初始預(yù)算階段,項(xiàng)目管理者需要為設(shè)計(jì)的整體進(jìn)行位置布局,只有布局合理,才能夠在最大程度上體現(xiàn)模塊化設(shè)計(jì)的優(yōu)勢(shì);反之,如果因布局不合理而在較后的階段需要再次進(jìn)行初始預(yù)算,則需要對(duì)整個(gè)實(shí)現(xiàn)步驟全面返工。
●子模塊的設(shè)計(jì)實(shí)現(xiàn),在該階段,每個(gè)項(xiàng)目成員并行完成各自子模塊的實(shí)現(xiàn)。
●模塊的最終集成,在該階段項(xiàng)目管理者將頂層的實(shí)現(xiàn)結(jié)果和所有子模塊的實(shí)現(xiàn)結(jié)果進(jìn)行整合集成,完成整個(gè)設(shè)計(jì)的實(shí)現(xiàn)。
? 模塊劃分的基本原則是:各個(gè)子模塊的功能相對(duì)獨(dú)立,模塊內(nèi)部聯(lián)系盡量緊密,模塊間的連接盡量簡(jiǎn)單。對(duì)于那些難以滿足模塊劃分準(zhǔn)則的具有強(qiáng)內(nèi)部關(guān)聯(lián)的復(fù)雜設(shè)計(jì),并不適合采用模塊化設(shè)計(jì)方法。
? 以工程note10_prj004為例,我們用模塊復(fù)用的方式,在頂層模塊vlg_design.v下定義了4個(gè)子模塊uut1_pulse_counter.v、uut2_pulse_counter.v、uut3_pulse_counter.v和uut4_pulse_counter.v,這4個(gè)子模塊雖然代碼一樣,都是pulse_counter.v這個(gè)模塊的代碼,但是由于引到頂層模塊的接口信號(hào)不同,所以它們最終實(shí)現(xiàn)了4個(gè)完全獨(dú)立的模塊,即4個(gè)完全相同的硬件電路。
圖3.29 代碼的模塊化層次視圖
? 頂層模塊vlg_design.v中沒有邏輯處理的代碼,只有子模塊的例化和接口的連接。代碼如下。
module vlg_design(
input i_clk,
input i_rst_n,
input[3:0]i_pulse,
input i_en,
output[15:0]o_pulse_cnt1,o_pulse_cnt2,
output[15:0]o_pulse_cnt3,o_pulse_cnt4
);
pulse_counter uut1_pulse_counter(
.i_clk????????????????? (i_clk),
.i_rst_n???????????? (i_rst_n),
.i_pulse???????????? (i_pulse[0]),
.i_en?????????????????? (i_en),
.o_pulse_cnt??? (o_pulse_cnt1)
);
pulse_counter uut2_pulse_counter(
.i_clk????????????????? (i_clk),
.i_rst_n???????????? (i_rst_n),
.i_pulse???????????? (i_pulse[1]),
.i_en?????????????????? (i_en),
.o_pulse_cnt??? (o_pulse_cnt2)
);
pulse_counter uut3_pulse_counter(
.i_clk????????????????? (i_clk),
.i_rst_n???????????? (i_rst_n),
.i_pulse???????????? (i_pulse[2]),
.i_en?????????????????? (i_en),
.o_pulse_cnt??? (o_pulse_cnt3)
);
pulse_counter uut4_pulse_counter(
.i_clk????????????????? (i_clk),
.i_rst_n???????????? (i_rst_n),
.i_pulse???????????? (i_pulse[3]),
.i_en?????????????????? (i_en),
.o_pulse_cnt??? (o_pulse_cnt4)
);
endmodule
? 下面是對(duì)pulse_counter.v模塊的例化代碼。
pulse_counter uut1_pulse_counter(
.i_clk????????????????? (i_clk),
.i_rst_n???????????? (i_rst_n),
.i_pulse???????????? (i_pulse[0]),
.i_en?????????????????? (i_en),
.o_pulse_cnt??? (o_pulse_cnt1)
);
? 以上面這段代碼為例,模塊例化大體有下面幾個(gè)要點(diǎn):
● pulse_counter是原始工程源碼本身的模塊名稱,同一個(gè)工程源碼,可以多次被例化。
●uut1_pulse_counter的名稱是可以隨意起的,只要不和已有的名稱重名即可,它表示我們對(duì)當(dāng)前例化模塊pulse_counter.v的唯一識(shí)別名。在這個(gè)工程中,我們看到pulse_counter.v模塊被例化了多次,但它和uut1_pulse_counter對(duì)應(yīng)位置的命名是不一樣的,而且必須是不一樣的,表示工程中有多個(gè)完全一樣的功能模塊。這和軟件程序里面的調(diào)用不一樣,軟件程序由于運(yùn)行起來總是串行的,所以多次調(diào)用同一個(gè)函數(shù)時(shí),這個(gè)函數(shù)可以只占一個(gè)函數(shù)所需的物理存儲(chǔ)空間即可;但是FPGA是并行處理的,它的模塊例化,哪怕是完全一樣的模塊,往往也是需要多個(gè)完全一樣的物理資源與其對(duì)應(yīng)的。
●“. i_clk (i_clk),”是接口的映射,“.(),”是固定格式。點(diǎn)號(hào)后面的i_clk是pulse_counter.v模塊內(nèi)部的接口,括號(hào)內(nèi)的i_clk是vlg_design.v模塊的接口。
? pulse_counter.v模塊是具體的邏輯處理源碼,其代碼如下。
module pulse_counter(
input i_clk,
input i_rst_n,
input i_pulse,
input i_en,
output reg[15:0]o_pulse_cnt
);
reg[1:0] r_pulse;
wire w_rise_edge;
//////////////////////////////////////////
//脈沖邊沿檢測(cè)邏輯
always @(posedge i_clk)
if(!i_rst_n)r_pulse <= 2'b00;
else r_pulse<= {r_pulse[0],i_pulse};
assign w_rise_edge = r_pulse[0] & ~r_pulse[1];
//////////////////////////////////////////
//脈沖計(jì)數(shù)邏輯
always @(posedge i_clk)
if(i_en) begin
if(w_rise_edge)o_pulse_cnt <= o_pulse_cnt+1;
else/*o_pulse_cnt <= o_pulse_cnt*/;
end
elseo_pulse_cnt <= 'b0;
endmodule
審核編輯:劉清
評(píng)論
查看更多