玩轉(zhuǎn)Zynq連載20——基于FPGA的模塊化設(shè)計(jì) 更多資料共享 騰訊微云鏈接:https://share.weiyun.com/5s6bA0s 百度網(wǎng)盤(pán)鏈接:https://pan.baidu.com/s/1XTQtP5LZAedkCwQtllAEyw 提取碼:ld9c ![]() 騰訊微云鏈接:https://share.weiyun.com/5s6bA0s 百度網(wǎng)盤(pán)鏈接:https://pan.baidu.com/s/1XTQtP5LZAedkCwQtllAEyw 提取碼:ld9c 模塊化設(shè)計(jì)是FPGA設(shè)計(jì)中一個(gè)很重要的技巧,它能夠使一個(gè)大型設(shè)計(jì)的分工協(xié)作、仿真測(cè)試更加容易,代碼維護(hù)或升級(jí)更加便利。 如圖所示,一般整個(gè)設(shè)計(jì)工程的頂層文件里只做例化,不做邏輯處理。然后一個(gè)頂層下面會(huì)有模塊A、模塊B、模塊C等等,模塊A/B/C下又可以分多個(gè)子模塊實(shí)現(xiàn)。
![]() 圖模塊設(shè)計(jì)示意圖 如此一來(lái),就可以將大規(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)步驟是整個(gè)模塊化設(shè)計(jì)流程中最重要、最特殊的,它包含: ●初始預(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)。 模塊劃分的基本原則是,子模塊功能相對(duì)獨(dú)立,模塊內(nèi)部聯(lián)系盡量緊密,而模塊間的連接盡量簡(jiǎn)單。對(duì)于那些難以滿足模塊劃分準(zhǔn)則的具有強(qiáng)內(nèi)部關(guān)聯(lián)的復(fù)雜設(shè)計(jì),并不適合采用模塊化設(shè)計(jì)方法。 下面以zstar_ex03工程的頂層源碼zstar.v為例,講解在Verilog代碼中如何實(shí)現(xiàn)模塊化設(shè)計(jì)。在zstar.v模塊下面有4個(gè)模塊,包括1個(gè)PLL時(shí)鐘產(chǎn)生模塊,以及3個(gè)控制LED閃爍的模塊。 module zstar( input ext_clk_25m, //外部輸入25MHz時(shí)鐘信號(hào) output[2:0] led //LED指示燈接口 ); //------------------------------------- wire clk_25m; //PLL輸出25MHz時(shí)鐘 wire clk_50m; //PLL輸出50MHz時(shí)鐘 wire clk_100m; //PLL輸出100MHz時(shí)鐘 wire sys_rst_n; //PLL輸出的locked信號(hào),作為FPGA內(nèi)部的復(fù)位信號(hào),低電平復(fù)位,高電平正常工作 clk_wiz_0 uut_clk_wiz_0 ( // Clock in ports .clk_in1(ext_clk_25m), // input clk_in1 // Clock out ports .clk_out1(clk_25m), // output clk_out1 .clk_out2(clk_50m), // output clk_out2 .clk_out3(clk_100m), // output clk_out3 // Status and control signals .reset(1'b0), // input reset .locked(sys_rst_n)); // output locked //------------------------------------- //25MHz時(shí)鐘進(jìn)行分頻閃爍,計(jì)數(shù)器為24位 led_controller #(24) uut_led_controller_clk25m( .clk(clk_25m), //時(shí)鐘信號(hào) .rst_n(sys_rst_n), //復(fù)位信號(hào),低電平有效 .sled(led[2]) //LED指示燈接口 ); //------------------------------------- //25MHz時(shí)鐘進(jìn)行分頻閃爍,計(jì)數(shù)器為25位 led_controller #(25) uut_led_controller_clk50m( .clk(clk_50m), //時(shí)鐘信號(hào) .rst_n(sys_rst_n), //復(fù)位信號(hào),低電平有效 .sled(led[1]) //LED指示燈接口 ); //------------------------------------- //25MHz時(shí)鐘進(jìn)行分頻閃爍,計(jì)數(shù)器為26位 led_controller #(26) uut_led_controller_clk100m( .clk(clk_100m), //時(shí)鐘信號(hào) .rst_n(sys_rst_n), //復(fù)位信號(hào),低電平有效 .sled(led[0]) //LED指示燈接口 ); endmodule ★ 語(yǔ)法要點(diǎn) 注意zstar.v模塊的代碼中例化了4個(gè)子模塊,這是一個(gè)不折不扣的模塊化設(shè)計(jì)工程。下面是對(duì)led_controller.v模塊的一個(gè)例化代碼。 led_controller #(24) uut_led_controller_clk25m( .clk(clk_25m), //時(shí)鐘信號(hào) .rst_n(sys_rst_n), //復(fù)位信號(hào),低電平有效 .sled(led[2]) //LED指示燈接口 ); 以上面這段代碼為例,模塊例化大體有下面幾個(gè)要點(diǎn): ● led_controller是原始工程源碼本身的模塊名稱(chēng)。 ● uut_led_controller_clk25m的名稱(chēng)是可以隨意起的,只要不和已有的名稱(chēng)重名即可,它表示我們對(duì)當(dāng)前例化工程led_controller.v的唯一識(shí)別名。在這個(gè)工程中,我們看到led_controller.v模塊被例化了多次,但它和uut_led_controller_clk25m對(duì)應(yīng)位置的命名是不一樣的,而且必須是不一樣的,表示工程中有多個(gè)完全一樣的功能模塊。這和軟件程序里面的調(diào)用不一樣,軟件程序由于運(yùn)行起來(lái)總是串行的,所以多次調(diào)用同一個(gè)函數(shù)時(shí),這個(gè)函數(shù)可以只占一個(gè)函數(shù)所需的物理存儲(chǔ)空間即可;但是FPGA是并行處理的,它的模塊例化,哪怕是完全一樣的模塊,往往也是需要多個(gè)完全一樣的物理資源與余對(duì)應(yīng)的。 ● “.clk(clk_25m),”是接口的映射,“.(),”是固定格式。clk是led_controller.v模塊內(nèi)部的接口,clk_25m是zstar.v模塊的接口。 如圖所示,當(dāng)工程編譯后,我們便可以在工程管理窗口中看到整個(gè)工程的模塊結(jié)構(gòu)。在zstar.v模塊下面對(duì)應(yīng)了4個(gè)子模塊。
![]() 圖 at7_ex03模塊結(jié)構(gòu) led_controller.v模塊代碼如下。 module led_controller( input clk, //時(shí)鐘信號(hào) input rst_n, //復(fù)位信號(hào),低電平有效 output sled //LED指示燈接口 ); parameter CNT_HIGH = 24; //計(jì)數(shù)器最高位 //------------------------------------- reg[(CNT_HIGH-1):0] cnt; //24位計(jì)數(shù)器 //cnt計(jì)數(shù)器進(jìn)行循環(huán)計(jì)數(shù) always @ (posedgeclk or negedgerst_n) if(!rst_n) cnt<= 0; else cnt<= cnt+1'b1; assign sled = cnt[CNT_HIGH-1]; endmodule |