賀 孟,蘇永海
(中國(guó)電子科技集團(tuán)公司 第三十研究所,四川 成都 610041)
隨著SoC 芯片性能的提高,處理器系統(tǒng)模塊間的數(shù)據(jù)傳輸能力是提升系統(tǒng)性能的關(guān)鍵.在數(shù)據(jù)傳輸系統(tǒng)中通常采用直接存儲(chǔ)器存取,即DMA 傳送方式,可以最大限度提高數(shù)據(jù)傳輸?shù)男剩?].一般的DMA 控制器結(jié)構(gòu)專用性強(qiáng)而擴(kuò)展性不足,面對(duì)系統(tǒng)規(guī)模的不斷擴(kuò)大和系統(tǒng)業(yè)務(wù)的多樣化,需要一種多通道DMA 控制器結(jié)構(gòu)以使系統(tǒng)設(shè)計(jì)能夠適應(yīng)各種帶寬需求的業(yè)務(wù).隨著可編程邏輯技術(shù)的發(fā)展,基于IP 核復(fù)用技術(shù)的IP 核設(shè)計(jì)成了提高可編程邏輯設(shè)計(jì)效率的重要組成部分[2].本研究針對(duì)工作中的實(shí)際應(yīng)用,結(jié)合IP 核復(fù)用技術(shù),重點(diǎn)介紹了一種基于FPGA 的自動(dòng)仲裁多通道無緩存結(jié)構(gòu)DMA 控制器IP 核的設(shè)計(jì)方法,并給出了Linux 下該IP 核驅(qū)動(dòng)的設(shè)計(jì),從而完整地實(shí)現(xiàn)了一個(gè)多通道無延遲DMA 系統(tǒng).
DMA 控制器是為使用32 位PCI 總線的SoC 項(xiàng)目設(shè)計(jì)的,在設(shè)計(jì)中考慮到對(duì)不同系統(tǒng)的移植,并采用了IP 復(fù)用的設(shè)計(jì)思想.該控制器向處理器單元申請(qǐng)總線控制權(quán),用DMA 方式完成存儲(chǔ)器和外設(shè)之間的數(shù)據(jù)傳輸.DMA 控制器最多8 個(gè)獨(dú)立通道,每個(gè)通道獨(dú)立編程,通道之間支持用戶定義優(yōu)先級(jí)和round robin 仲裁,通道與總線間無緩存無延遲傳輸,每個(gè)通道支持收發(fā)數(shù)據(jù)包完整性檢查和包計(jì)數(shù).
DMA 控制器的總體結(jié)構(gòu)如圖1 所示.
圖1 DMA 控制器總體框圖
各功能模塊說明如下:
1)DMA 通道模塊.完成通道內(nèi)的DMA 傳輸請(qǐng)求和判斷以及與用戶邏輯和接口.
2)DMA 仲裁模塊.對(duì)所有DMA 通道模塊發(fā)送的DMA 請(qǐng)求進(jìn)行仲裁,根據(jù)仲裁結(jié)果選擇哪個(gè)通道占用總線.
DMA 控制器從總線的占用角度分2 種工作狀態(tài):空閑狀態(tài)和工作狀態(tài).當(dāng)無通道發(fā)出數(shù)據(jù)傳輸請(qǐng)求時(shí),就處于空閑狀態(tài),此時(shí)由處理器占用總線對(duì)DMA 控制器內(nèi)部寄存器進(jìn)行讀寫操作.當(dāng)通道發(fā)出數(shù)據(jù)傳輸請(qǐng)求后,就處于工作狀態(tài),此時(shí)DMA 控制器占用總線直接對(duì)內(nèi)存進(jìn)行數(shù)據(jù)操作.
DMA 控制器的工作機(jī)制采用消息循環(huán)隊(duì)列機(jī)制,即DMA 控制器每個(gè)通道按操作內(nèi)存的方向設(shè)置讀寫2 個(gè)消息隊(duì)列,隊(duì)列元素為描述數(shù)據(jù)緩存區(qū)信息的描述符(Buffer Descriptor,BD),隊(duì)列元素存儲(chǔ)在內(nèi)存中,BD 信息符由數(shù)據(jù)地址、數(shù)據(jù)長(zhǎng)度、標(biāo)志位組成.通常,每個(gè)隊(duì)列定義以下寄存器由處理器在空閑狀態(tài)時(shí)操作:隊(duì)列長(zhǎng)度寄存器(BDL),讀寫緩存區(qū)信息基地址寄存器(BDA),緩存區(qū)信息隊(duì)列頭部位置寄存器(BDH),緩存區(qū)信息隊(duì)列尾部位置寄存器(BDT).
1)DMA 控制器寫內(nèi)存時(shí),首先處理器初始化配置BDA 寄存器和BDL 寄存器,此時(shí)BDH 和BDT 初始值都為0,表示內(nèi)存無空余緩存區(qū).當(dāng)處理器增加一個(gè)空余緩存區(qū)時(shí)將該緩存區(qū)在內(nèi)存中的地址轉(zhuǎn)換為總線地址寫入BD 中,然后更新BDT 的值,此時(shí)DMA 控制器檢測(cè)到BDH 不等于BDT,即知道已有空閑緩存區(qū),這時(shí)DMA 控制器檢測(cè)用戶邏輯有無DMA 傳輸請(qǐng)求,有則向DMA 仲裁器發(fā)出總線占用請(qǐng)求,DMA 仲裁器響應(yīng)后,該DMA 控制器首先按BDA 加偏移量定義的地址讀取內(nèi)存中的BD 信息符,然后將用戶數(shù)據(jù)寫入該BD 信息符定義的數(shù)據(jù)地址對(duì)應(yīng)的數(shù)據(jù)塊中,最后將用戶數(shù)據(jù)長(zhǎng)度寫到BD的數(shù)據(jù)長(zhǎng)度部分,同時(shí)更新標(biāo)志位中的完成以及狀態(tài)標(biāo)志,然后將BDH 值加1.整個(gè)流程如圖2(A)所示.
2)DMA 控制器讀內(nèi)存時(shí),首先處理器初始化配置BDA 寄存器和BDL 寄存器,此時(shí)BDH 和BDT 初始值都為0,表示內(nèi)存無待讀緩存區(qū).當(dāng)處理器增加一個(gè)待讀緩存區(qū)時(shí),將該緩存區(qū)在內(nèi)存中的地址轉(zhuǎn)換為總線地址和數(shù)據(jù)長(zhǎng)度寫入BD 中,然后更新BDT 的值,此時(shí)DMA 控制器檢測(cè)到BDH 不等于BDT,即知道已有待讀數(shù)據(jù)在緩存區(qū),這時(shí)DMA 控制器檢測(cè)用戶邏輯是否允許DMA 傳輸請(qǐng)求,有則向DMA 仲裁器發(fā)出總線占用請(qǐng)求,DMA 仲裁器響應(yīng)后,該DMA 控制器首先按BDA 加偏移量定義的地址讀取內(nèi)存中的BD 信息符,然后到按照BD 信息符中的數(shù)據(jù)長(zhǎng)度將該BD 信息符定義的數(shù)據(jù)區(qū)地址將待讀數(shù)據(jù)傳輸給用戶邏輯中,最后更新標(biāo)志位中的傳輸完成標(biāo)志同時(shí)將BDH 值加1.整個(gè)流程如圖2(B)所示.
1.3.1 DMA 通道模塊.
DMA 通道模塊設(shè)計(jì)如圖3,分為配置管理單元、用戶接口單元、總線處理單元、監(jiān)控統(tǒng)計(jì)單元.
1)配置寄存器單元.在空閑狀態(tài)接收處理器初始化指令,讀寫B(tài)DL/BDA/BDH/BDT 寄存器,并將寄存器信息傳遞給總線處理單元.
2)總線處理單元.接收配置寄存器單元BDH 和BDT 信息,以及用戶邏輯處理單元的空滿標(biāo)志信息,決定是否向仲裁模塊發(fā)起DMA 讀寫請(qǐng)求并決定DMA 操作的順序,核心如圖4 所示狀態(tài)機(jī).
圖2 DMA 控制器工作流程圖
圖3 DMA 控制器通道模塊原理框圖
3)狀態(tài)說明.Idle 為初始態(tài),Request 為請(qǐng)求態(tài),Rbd-r0 為寫內(nèi)存讀BD 信息符態(tài),Rbd-w1 為寫內(nèi)存寫B(tài)D 信息符態(tài),Rbd-wd 為寫內(nèi)存數(shù)據(jù)態(tài),Tbd-r0 為讀內(nèi)存讀BD 信息符態(tài);Tbd-w1 為讀內(nèi)存寫B(tài)D 信息符態(tài);Tbd-rd 為讀內(nèi)存數(shù)據(jù)態(tài).
4)用戶邏輯處理單元.設(shè)計(jì)供用戶使用的標(biāo)準(zhǔn)接口,該單元不帶任何緩存結(jié)構(gòu),在讀寫內(nèi)存數(shù)據(jù)態(tài)時(shí)直接將總線接口時(shí)序匹配為帶數(shù)據(jù)起始標(biāo)志的異步FIFO 接口和帶讀寫使能,讀寫地址的異步雙口RAM 接口,數(shù)據(jù)起始標(biāo)志同時(shí)作為數(shù)據(jù)幀完整性校驗(yàn)的指示.用戶邏輯接口時(shí)序圖如圖5.
圖4 總線處理狀態(tài)機(jī)
圖5 用戶邏輯接口時(shí)序圖
5)監(jiān)控統(tǒng)計(jì)單元.監(jiān)測(cè)總線端和用戶端的數(shù)據(jù)收發(fā),對(duì)兩側(cè)的數(shù)據(jù)包數(shù)進(jìn)行統(tǒng)計(jì).
1.3.2 DMA 仲裁模塊.
仲裁模塊對(duì)所有通道的占用總線請(qǐng)求進(jìn)行排隊(duì)仲裁,根據(jù)策略決定通道的響應(yīng)順序以及和總線接口的匹配,在這里指PCI32 接口的匹配.圖6 為round robin 的設(shè)計(jì)原理圖.
該設(shè)計(jì)的特點(diǎn)為通道切換無延遲,在傳輸一個(gè)通道數(shù)據(jù)時(shí)已經(jīng)解算出下一個(gè)將要占用總線的通道,不浪費(fèi)總線帶寬,并與通道模塊的無緩存結(jié)構(gòu)結(jié)合,該IP 核在總線到用戶數(shù)據(jù)傳輸上無延遲,保證了實(shí)時(shí)性.
圖6 仲裁單元round robin 設(shè)計(jì)原理圖
設(shè)計(jì)IP 化的關(guān)鍵點(diǎn)是在硬件上對(duì)用戶和總線接口提供標(biāo)準(zhǔn)統(tǒng)一的接口,在設(shè)計(jì)流程上對(duì)設(shè)計(jì)進(jìn)行參數(shù)化和腳本化,這樣就只需使用邏輯綜合腳本改變參數(shù)就可綜合得出適應(yīng)不同的使用場(chǎng)景的網(wǎng)表文件.
接口的標(biāo)準(zhǔn)化在用戶端提供帶數(shù)據(jù)幀起始標(biāo)志和數(shù)據(jù)有效指示的FIFO 接口,也提供帶地址信息的雙口RAM 接口,這樣用戶既可只用簡(jiǎn)單的FIFO接口緩存數(shù)據(jù),也可按需求直接按地址直接處理數(shù)據(jù).
在總線端直接根據(jù)腳本指定使用標(biāo)準(zhǔn)的總線類型,本研究中使用的是PCI32 位總線.
參數(shù)化設(shè)計(jì)是設(shè)計(jì)IP 化的必要點(diǎn),將設(shè)計(jì)中的功能點(diǎn)和性能點(diǎn)提出并參數(shù)化,用戶只需按照自己的需求使用腳本改變這些參數(shù),即可綜合出適應(yīng)不同場(chǎng)景的IP 核.下面是一部分描述參數(shù)的VHDL 代碼及其說明,描述參數(shù)的代碼全部在一個(gè)庫(kù)文件中編寫,以利于邏輯綜合腳本調(diào)用修改.
constant c-family:string:=spartan6;
指定使用FPGA 型號(hào)為Spartan-6
constant bus-type:string:=pci;
前些日子,老伴突然暈倒,住院不到一個(gè)月就去世了。聽醫(yī)生說,老伴早就有發(fā)病的征兆,只是誰都沒在意,耽誤了治療。三個(gè)女兒為她們疏忽老爸的生活愧疚不已,也對(duì)我平時(shí)對(duì)老伴的不管不問很是生氣。
指定總線類型為PCI 總線.
constant bus-datawid-bits:integer:=32;
指定總線寬度為32 bit.
constant dmacfg-addrwid-bits:integer:=6;
指定配置寄存器地址寬度為6 bit.
constant transfer-lengthwid-bits:integer:=9;
指定配置寄存器地址寬度為6 bit.
constant dmastate-datawid-bits:integer:=16;
constant dma-channel-number:integer:=4;
指定通道數(shù)為4 個(gè).
圖7 為dma 通 道數(shù)dma-channel-number =4時(shí)匹配PCI32 的synplify 綜合視圖.
圖7 DMA 控制器IP 核綜合視圖
在Linux 系統(tǒng)中,針對(duì)不同的外部設(shè)備,其驅(qū)動(dòng)程序的框架結(jié)構(gòu)是一致的.通常,Linux 系統(tǒng)分為內(nèi)核空間與用戶空間,設(shè)備驅(qū)動(dòng)程序是工作在內(nèi)核空間的,它通過特定的方式與用戶空間交換數(shù)據(jù).Linux 系統(tǒng)的設(shè)備可分為字符設(shè)備、塊設(shè)備和網(wǎng)絡(luò)設(shè)備3 種類型.所有的設(shè)備驅(qū)動(dòng)程序都支持文件操作接口.因此,每個(gè)設(shè)備都可以當(dāng)作是文件系統(tǒng)中的一個(gè)文件來進(jìn)行訪問[3].Linux 系統(tǒng)分為3 層:應(yīng)用層、內(nèi)核層和物理層.應(yīng)用層主要運(yùn)行與應(yīng)用相關(guān)的應(yīng)用程序,內(nèi)核層主要是Linux 操作系統(tǒng)運(yùn)行的空間,包括驅(qū)動(dòng)程序也運(yùn)行在該層,物理層就是各種物理外設(shè),應(yīng)用程序要訪問外部的設(shè)備必須通過驅(qū)動(dòng)程序來實(shí)現(xiàn).
Linux 操作系統(tǒng)中,所有的外圍設(shè)備都是通過文件節(jié)點(diǎn)來進(jìn)行訪問的.Linux 的虛擬文件系統(tǒng)為各種不同文件系統(tǒng)提高了統(tǒng)一的訪問接口,包括PCI 外圍設(shè)備.通過這些接口,應(yīng)用程序可以直接使用open、close、read、write 和ioctl 等系統(tǒng)調(diào)用來對(duì)各種設(shè)備進(jìn)行訪問和控制,而為一個(gè)外圍設(shè)備提供這些系統(tǒng)調(diào)用的響應(yīng)函數(shù)正是該設(shè)備驅(qū)動(dòng)程序的責(zé)任.
Linux 將所有外部設(shè)備看成是一類特殊文件,稱之為“設(shè)備文件”,設(shè)備驅(qū)動(dòng)程序則可以看成是Linux 內(nèi)核與外部設(shè)備之間的接口.在Linux 操作系統(tǒng)下,有3 類主要的設(shè)備文件類型:字符設(shè)備、塊設(shè)備和網(wǎng)絡(luò)設(shè)備.對(duì)于設(shè)備文件和普通文件的訪問都是通過其I/O 子系統(tǒng)向內(nèi)核中的其他部分提供統(tǒng)一的標(biāo)準(zhǔn)設(shè)備接口,包含在include/linux/fs.h 中的數(shù)據(jù)結(jié)構(gòu)file-oPerations 來完成的[4].
Linux 為設(shè)備驅(qū)動(dòng)程序訪問I/O 端口、硬件中斷、DMA 提供了簡(jiǎn)便方法.Linux 提供的I/O 端口訪問方法主要有inb()、inw()、outb()、outw()等.需注意的是設(shè)備驅(qū)動(dòng)程序在使用端口前,應(yīng)該先用check-region()檢查端口的占用情況,如果指定的端口可用,再用request-region()向系統(tǒng)登記.
設(shè)備驅(qū)動(dòng)程序作為內(nèi)核的一部分,不能使用虛擬內(nèi)存,利用內(nèi)核提供的kmalloc()和kfree()來申請(qǐng)和釋放內(nèi)核存儲(chǔ)空間.kmalloc 帶2 個(gè)參數(shù).第1個(gè)參數(shù)是要申請(qǐng)內(nèi)存的數(shù)量,要求這個(gè)數(shù)量是2 的整數(shù)冪,如128、256;第2 個(gè)參數(shù)是優(yōu)先權(quán),最常用的優(yōu)先權(quán)是GFP-KERNEL,它的意思是該內(nèi)存分配是由運(yùn)行在內(nèi)核模式的進(jìn)程調(diào)用的[5].
DMA 控制器可控制多個(gè)DMA 傳輸通道,并且可以實(shí)現(xiàn)總線和存儲(chǔ)器總線之間的相互傳輸,其實(shí)現(xiàn)步驟如下:
1)在系統(tǒng)內(nèi)存中分配大塊的存儲(chǔ)區(qū)用于DMA傳輸必須確保屬于低端內(nèi)存得到用于DMA 傳輸?shù)目偩€地址,且不能換入換出,通常會(huì)用到GFP-KERNEL GFP-DMA 等標(biāo)志.
2)在內(nèi)核中調(diào)用request_dma 函數(shù)請(qǐng)求并注冊(cè)一個(gè)DMA 通道并為該通道注冊(cè)一個(gè)DMA 傳輸完成中斷并實(shí)現(xiàn)其中斷服務(wù)程序與驅(qū)動(dòng)程序的其他中斷注冊(cè)方法相同,不再描述.
3)通過內(nèi)核函數(shù)獲得總線地址對(duì)于PCI 設(shè)備其中一個(gè)存儲(chǔ)器資源的實(shí)現(xiàn)如下其余段的存儲(chǔ)器資源處理相同.
4)當(dāng)數(shù)據(jù)準(zhǔn)備就緒,通過中斷或者命令通知CPU 初始化DMA 通道的各個(gè)參數(shù),如DMA 的源總線地址寄存器、目的總線地址寄存器以及傳輸數(shù)據(jù)長(zhǎng)度寄存器等,并啟動(dòng)DMA 傳輸后CPU 就不再參與數(shù)據(jù)的傳輸.在DMA 傳輸完成后,在其DMA 傳輸完成中斷服務(wù)程序中,CPU 只需要清理中斷現(xiàn)場(chǎng)就結(jié)束數(shù)據(jù)傳輸.
因此,在數(shù)據(jù)傳輸?shù)倪^程中,只需要占用極少的CPU 時(shí)間初始化DMA 寄存器及DMA 中斷管理,有利于優(yōu)化整個(gè)系統(tǒng)的性能.
本研究討論了一種實(shí)時(shí)多通道DMA 控制器IP核的實(shí)現(xiàn),結(jié)合該設(shè)計(jì),探討了基于IP 復(fù)用技術(shù)的IP 核實(shí)現(xiàn)方法,并給出了Linux 下驅(qū)動(dòng)的實(shí)現(xiàn)方法.FPGA 使用Xilinx Spartan-6,最終適配PCI32 總線4通道IP 核的邏輯資源消耗只有648 個(gè)slice,整個(gè)設(shè)計(jì)相當(dāng)精簡(jiǎn)可靠.最后,本研究在PCI 機(jī)箱使用該FPGA 硬件板卡進(jìn)行了實(shí)驗(yàn)測(cè)試,對(duì)全部四通道進(jìn)行并行收發(fā)數(shù)據(jù)測(cè)試,測(cè)得數(shù)據(jù)收發(fā)達(dá)到55 MB/s(兆字節(jié)/秒),且對(duì)優(yōu)先級(jí)設(shè)定反應(yīng)靈敏.
[1]史昕蕾,楊軍,陸生禮.嵌入式SoC 中的DMA 控制器的設(shè)計(jì)與優(yōu)化[J].電子工程師,2004,30(1):5-7.
[2]朱運(yùn)航,李雪東.基于IP 核復(fù)用的SoC 設(shè)計(jì)技術(shù)探討[J].微計(jì)算機(jī)信息,2006,22(3-2):47-48.
[3]Corbet J,Rubini A,Kroah-Hartman G.LINUX 設(shè)備驅(qū)動(dòng)程序[M].第2 版.魏永明,耿岳,鐘書毅譯.北京:中國(guó)電力出版社,2002.
[4]Matthew N,Stones R.Linux 程序設(shè)計(jì)[M].第2 版.楊曉云,譯.北京:機(jī)械工業(yè)出版社,2002.
[5]李遠(yuǎn)征,任傳倫,楊義先.PCI 設(shè)備的DMA 驅(qū)動(dòng)程序設(shè)計(jì)[J].計(jì)算機(jī)工程與應(yīng)用,2003,39(14):135-138.