當(dāng)前位置: 首頁 > 行業(yè)動態(tài)
發(fā)布日期:2022-07-14 點(diǎn)擊率:26
一般而言,DMA控制器將包括一條地址總線、一條數(shù)據(jù)總線和控制寄存器。高效率的DMA控制器將具有訪問其所需要的任意資源的能力,而無須處理器本身的介入,它必須能產(chǎn)生中斷。最后,它必須能在控制器內(nèi)部計(jì)算出地址。
一個處理器可以包含多個DMA控制器。每個控制器有多個DMA通道,以及多條直接與存儲器站(memory bank)和外設(shè)連接的總線,如圖1所示。在很多高性能處理器中集成了兩種類型的DMA控制器。第一類通常稱為“系統(tǒng)DMA控制器”,可以實(shí)現(xiàn)對任何資源(外設(shè)和存儲器)的訪問,對于這種類型的控制器來說,信號周期數(shù)是以系統(tǒng)時鐘(SCLK)來計(jì)數(shù)的,以ADI的Blackfin處理器為例,頻率最高可達(dá)133MHz。第二類稱為內(nèi)部存儲器DMA控制器(IMDMA),專門用于內(nèi)部存儲器所處位置之間的相互存取操作。因?yàn)榇嫒《及l(fā)生在內(nèi)部(L1-L1、L1-L2,或者L2-L2),周期數(shù)的計(jì)數(shù)則以內(nèi)核時鐘(CCLK)為基準(zhǔn)來進(jìn)行,該時鐘的速度可以超過600MHz。
每個DMA控制器有一組FIFO,起到DMA子系統(tǒng)和外設(shè)或存儲器之間的緩沖器的作用。對于MemDMA(Memory DMA)來說,傳輸?shù)脑炊撕湍繕?biāo)端都有一組FIFO存在。當(dāng)資源緊張而不能完成數(shù)據(jù)傳輸?shù)脑?則FIFO可以提供數(shù)據(jù)的暫存區(qū),從而提高性能。
因?yàn)槟阃ǔ诖a初始化過程中對DMA控制器進(jìn)行配置,內(nèi)核就只需要在數(shù)據(jù)傳輸完成后對中斷做出響應(yīng)即可。你可以對DMA控制進(jìn)行編程,讓其與內(nèi)核并行地移動數(shù)據(jù),而同時讓內(nèi)核執(zhí)行其基本的處理任務(wù)—那些應(yīng)該讓它專注完成的工作。
圖1:系統(tǒng)和存儲器DMA架構(gòu)。
在一個優(yōu)化的應(yīng)用中,內(nèi)核永遠(yuǎn)不用參與任何數(shù)據(jù)的移動,而僅僅對L1存儲器中的數(shù)據(jù)進(jìn)行讀寫。于是,內(nèi)核不需要等待數(shù)據(jù)的到來,因?yàn)镈MA引擎會在內(nèi)核準(zhǔn)備讀取數(shù)據(jù)之前將數(shù)據(jù)準(zhǔn)備好。圖2給出了處理器和DMA控制器間的交互關(guān)系。由處理器完成的操作步驟包括:建立傳輸,啟用中斷,生成中斷時執(zhí)行代碼。返回到處理器的中斷輸入可以用來指示“數(shù)據(jù)已經(jīng)準(zhǔn)備好,可進(jìn)行處理”。
圖2:DMA控制器。
數(shù)據(jù)除了往來外設(shè)之外,還需要從一個存儲器空間轉(zhuǎn)移到另一個空間中。例如,視頻源可以從一個視頻端口直接流入L3存儲器,因?yàn)楣ぷ骶彌_區(qū)規(guī)模太大,無法放入到存儲器中。我們并不希望讓處理器在每次需要執(zhí)行計(jì)算時都從外部存儲讀取像素信息,因此為了提高存取的效率,可以用一個存儲器到存儲器的DMA(MemDMA)來將像素轉(zhuǎn)移到L1或者L2存儲器中。
到目前為之,我們還僅專注于數(shù)據(jù)的移動,但是DMA的傳送能力并不總是用來移動數(shù)據(jù)。我們可以用代碼覆蓋的辦法來提高性能,將DMA的控制器配置為在執(zhí)行前把代碼送入L1指令存儲器。代碼往往存儲于較大的外部存儲器中,而根據(jù)需要有選擇性的送入L1。
DMA控制器的編程
讓我們考察一下在定義DMA活動的過程中可以有哪些選項(xiàng)。我們將從最簡單的模型開始,并在此基礎(chǔ)上過渡到更為靈活的模型,這反過來增加了設(shè)置的復(fù)雜度。
對于任何類型的DMA傳輸,我們都需要規(guī)定數(shù)據(jù)的起始源和目標(biāo)地址。對于外設(shè)DMA的情況來說,外設(shè)的FIFO可以作為數(shù)據(jù)源或者目標(biāo)端。當(dāng)外設(shè)作為源端時,某個存儲器的位置(內(nèi)部或外部)則成為目標(biāo)端地址。當(dāng)外設(shè)作為目標(biāo)端,存儲的位置(內(nèi)部或者外部)則成為源端地址。
在最簡單的MemDMA情況中,我們需要告訴DMA控制器源端地址、目標(biāo)端地址和待傳送的字的個數(shù)。采用外設(shè)DMA的情況下,我們規(guī)定數(shù)據(jù)的源端或者目標(biāo)端,具體則取決于傳輸?shù)姆较颉C看蝹鬏數(shù)淖值拇笮】梢允?、16或者12位。這種類型的事務(wù)代表了簡單的1維(“1D”)統(tǒng)一“跨度”(unity stride)的傳輸。作為這一傳輸機(jī)制的一部分,DMA控制器連續(xù)跟蹤不斷增加的源端和目標(biāo)端地址。采用這種傳輸方式時,8位的傳輸產(chǎn)生1字節(jié)的地址增量,而16位傳輸產(chǎn)生的增量為2字節(jié),32位傳輸則產(chǎn)生4字節(jié)的增量。上面的參數(shù)是基本的1D DMA傳輸?shù)脑O(shè)置參數(shù)。
我們只需要改變數(shù)據(jù)傳輸每次的數(shù)據(jù)大小,就可以簡單地增加一維DMA的靈活性。例如,采用非單一大小的傳輸方式時,我們以傳輸數(shù)據(jù)塊的大小的倍數(shù)來作為地址增量。也就是說,若規(guī)定32位的傳輸和4個采樣的跨度,則每次傳輸結(jié)束后,地址的增量為16字節(jié)(4個32位字)。
雖然1D DMA得到了廣泛的應(yīng)用,但用處更大的則是2維(2D) DMA,特別是在視頻應(yīng)用中。2D功能是我們所討論的1D DMA的情形的一種直接擴(kuò)展。除了XCOUNT和XMODIFY值之外,我們還需對對應(yīng)的YCOUNT和YMODIFY值進(jìn)行編程設(shè)定。2D DMA可以簡單地理解為一個嵌套的循環(huán),即內(nèi)循環(huán)由XCOUNT和XMODIFY來規(guī)定,外循環(huán)由YCOUNT和YMODIFY規(guī)定。一個1D DMA可以被簡單的視為2D傳輸?shù)摹皟?nèi)循環(huán)”,如下形式:
for y = 1 to YCOUNT /* 2D的外循環(huán)*/
for x = 1 to XCOUNT /* 1D的內(nèi)循環(huán) */
{
/* 傳輸循環(huán)主體轉(zhuǎn)移到這里 */
}
XMODIFY決定了XCOUNT每次減少時的DMA控制器的跨度值,而YMODIFY則決定了YCOUNT每次減少時對應(yīng)的跨度值。與XCOUNT和XMODIFY一樣,YOUNT可以以傳輸數(shù)量來定義,而YMODIFY則以字節(jié)數(shù)來定義。值得注意的是,YMODIFY可以為負(fù)值,這會讓DMA控制器回轉(zhuǎn)到緩沖器的起始點(diǎn)。
對于外設(shè)DMA來說,傳輸?shù)摹按鎯ζ鞫恕笨梢允?D或2D。不過,在外設(shè)端,傳輸始終是1D的。唯一的限制是在DMA每一端(源端和目標(biāo)端)傳輸?shù)淖止?jié)總數(shù)必須相同。例如,如果我們從3個10字節(jié)的緩沖器向外設(shè)饋入數(shù)據(jù)。例如,如果我們從3個10字節(jié)的緩沖器向外設(shè)發(fā)送數(shù)據(jù),外設(shè)必須被設(shè)定為傳送30字節(jié),具體方式則可以是任何可能的、所支持的傳輸寬度和傳輸計(jì)數(shù)值的組合。
MemDMA提供的靈活度則要更高一些。例如,如果我們可以建立一個1D-2D傳輸、一個1D-2D傳輸、1個2D-1D傳輸,且可自然而然建立一個2D-2D傳輸,唯一的限制條件是,在DMA傳輸模塊的兩端所傳送的字節(jié)總數(shù)必須相等。
DMA的設(shè)置
目前有兩類主要的DMA傳輸結(jié)構(gòu):寄存器模式和描述符模式。無論屬于哪一類DMA,表1所描述的幾類信息都會在DMA控制器中出現(xiàn)。當(dāng)DMA以寄存器模式工作時,DMA控制器只是簡單地利用寄存器中所存儲的參數(shù)值。在描述符模式中,DMA控制器在存儲器中查找自己的配置參數(shù)。
表1:DMA寄存器
基于寄存器的DMA
在基于寄存器的DMA內(nèi)部,處理器直接對DMA控制寄存器進(jìn)行編程,來啟動傳輸。基于寄存器的DMA提供了最佳的DMA控制器性能,因?yàn)榧拇嫫鞑⒉恍枰粩嗟貜拇鎯ζ髦械拿枋龇陷d入數(shù)據(jù),而內(nèi)核也不需要保持描述符。
基于寄存器的DMA由兩種子模式組成:自動緩沖(Autobuffer)模式和停止模式。在自動緩沖DMA中,當(dāng)一個傳輸塊傳輸完畢,控制寄存器就自動重新載入其最初的設(shè)定值,同一個DMA進(jìn)程重新啟動,開銷為零。
正如我們在圖3中所看到的那樣,如果將一個自動緩沖DMA設(shè)定為從外設(shè)傳輸一定數(shù)量的字到L1數(shù)據(jù)存儲器的緩沖器上,則DMA控制器將會在最后一個字傳輸完成的時刻就迅速重新載入初始的參數(shù)。這構(gòu)成了一個“循環(huán)緩沖器”,因?yàn)楫?dāng)一個量值被寫入到緩沖器的最后一個位置上時,下一個值將被寫入到緩沖器的第一個位置上。
圖3:用DMA實(shí)現(xiàn)循環(huán)緩沖器。
自動緩沖DMA特別適合于對性能敏感的、存在持續(xù)數(shù)據(jù)流的應(yīng)用。DMA控制器可以在獨(dú)立于處理器其他活動的情況下讀入數(shù)據(jù)流,然后在每次傳輸結(jié)束時,向內(nèi)核發(fā)出中斷。雖然有可能以恰當(dāng)?shù)姆绞阶柚棺詣泳彌_模式,但如果DMA進(jìn)程需要定期啟動和停止時,采用這種工作方式就沒有什么意義。
停止模式的工作方式與自動緩沖DMA類似,區(qū)別在于各寄存器在DMA結(jié)束后不會重新載入,因此整個DMA傳輸只發(fā)生一次。停止模式對于基于某種事件的一次性傳輸來說十分有用。例如,非定期地將數(shù)據(jù)塊從一個位置轉(zhuǎn)移到另一個位置。當(dāng)你需要對事件進(jìn)行同步時,這種模式也非常有用。例如,如果一個任務(wù)必須在下一次傳輸前完成的話,則停止模式可以確保各事件發(fā)生的先后順序。此外,停止模式對于緩沖器的初始化來說非常有用。
描述符模型
基于描述符(descriptor)的DMA要求在存儲器中存入一組參數(shù),以啟動DMA的系列操作。該描述符所包含的參數(shù)與那些通常通過編程寫入DMA控制寄存器組的所有參數(shù)相同。不過,描述符還可以容許多個DMA操作序列串在一起。在基于描述符的DMA操作中,我們可以對一個DMA通道進(jìn)行編程,在當(dāng)前的操作序列完成后,自動設(shè)置并啟動另一次DMA傳輸。基于描述符的方式為管理系統(tǒng)中的DMA傳輸提供了最大的靈活性。
ADI 的Blackfin處理器上有兩種主要的描述符方式—描述符陣列和描述符列表,這兩種操作方式所要實(shí)現(xiàn)的目標(biāo)是在靈活性和性能之間實(shí)現(xiàn)一種折中平衡。
在描述符陣列模式下,描述符駐留在連續(xù)的存儲器位置上。DMA控制器依然從存儲器取用描述符,但是因?yàn)橄乱粋€描述符緊跟著當(dāng)前的描述符,說明到何處去尋找下一個描述符(以及它們相應(yīng)的描述符取用)的兩個數(shù)據(jù)字就并不必要。因?yàn)槊枋龇⒉话@一“下一描述符”指針項(xiàng),DMA控制器希望一組描述符在存儲器相互挨在一起,如同陣列一般。
當(dāng)各描述符在存儲器中的分布位置并非“背對背”時,可以使用一個描述符列表。實(shí)際上這里涉及多種子模式,從而再一次實(shí)現(xiàn)了性能和靈活性之間的折中平衡。在“小描述符”模型中,描述符包括了一個單16位的域,用來給出“下一描述符指針”域的低位部分;高位部分則通過寄存器來獨(dú)立編程設(shè)定,并且不發(fā)生改變。當(dāng)然,這將描述符限制在存儲器中一個特定的64K(=216)頁面上。當(dāng)描述符的位置需要跨越這一邊界時,也可以提供一個“大”模型,它可以為“下一描述符指針”項(xiàng)提供32位的位置。
無論采用何種描述符模式,描述符的量值數(shù)越多,則描述符取用的次數(shù)就越多。這也就是為何Blackfin處理器定義了一個“柔性描述符方式”的原因,該模式可以修改描述符的長度,使之僅僅包括特定傳輸所需要的數(shù)據(jù)。例如,如果不需要2D DMA,YMODIFY和 YCOUNT 寄存器就不需要成為描述符數(shù)據(jù)塊的一部分。
描述符管理
管理描述符列表的最佳方法是什么?其實(shí),這個問題的答案需要根據(jù)應(yīng)用來定,但要明白存在何種替代方法很重要。
我們將描述的第一種選擇,其工作方式非常類似于一個自動緩沖DMA。它需要設(shè)定多種描述符,并將其串連到一起,正如圖4a所示的那樣。“串連”一詞意味著一個描述符指向下一個描述符,描述符的載入是自動的。為了使鏈條完整,最后一個描述符反向指向第一個描述符,于是整個流程就重復(fù)下去。使用這種技術(shù)而不是自動緩沖的一個理由就是,這些描述符可以保證傳輸?shù)囊?guī)模和方向上具有更大的靈活性。
圖4:由處理器進(jìn)行調(diào)控的DMA描述符:(a)鏈接的描述符列表;(b)“節(jié)流調(diào)節(jié)式”的描述符管理。
第二個選擇則是由處理器來管理描述符列表。回想一下,描述符實(shí)際上是存儲器中的一個結(jié)構(gòu),每個描述符包含了一個配置字。每個配置字包含了“使能”位,其作用是在傳輸開始時進(jìn)行調(diào)節(jié)。如果我們需要讓處理器在做好準(zhǔn)備時去啟動每次具體的傳輸,我們就可以事先設(shè)定好所有的描述符,但把“使能”位清零。當(dāng)處理器確定啟動描述符的時機(jī)已經(jīng)到來時,它只需簡單地更新存儲器中的描述符,然后寫入DMA寄存器中,以讓處于停止?fàn)顟B(tài)的通道啟動起來。圖4b示出了這一流程的一個例子。
這種類型的傳輸什么時候有用呢?請考慮一個需要將輸入流與輸出流實(shí)現(xiàn)同步的多媒體應(yīng)用。例如,我們接收視頻采樣,將其傳輸?shù)酱鎯ζ鞯乃俾士赡軙煌趯⒃撘曨l輸出顯示的速度。在實(shí)際系統(tǒng)中,即使你試圖讓流以恰好相同的時鐘傳輸,也會發(fā)生這種情況。在同步成問題的情況下,處理器可以調(diào)整對應(yīng)于輸出緩沖器的DMA描述符。在下一個描述符啟用時,處理器可以通過調(diào)整目前的輸出描述符來實(shí)現(xiàn)流的同步,具體方式是利用一種信號量機(jī)制(semaphore mechanism)來確保每次只有一個項(xiàng)訪問共享資源。
在處理器之間使用內(nèi)部的DMA描述符鏈或者基于DMA的流時,一種有用的做法是在所傳輸?shù)臄?shù)據(jù)塊的末尾添加一個額外的字,用以幫助標(biāo)識正被發(fā)送的包,包括關(guān)于應(yīng)該如何處理數(shù)據(jù)的信息和時間戳。圖4b中虛線所劃出的區(qū)域則示出了這種方案。
大多數(shù)成熟的應(yīng)用都有以軟件形式實(shí)現(xiàn)的“DMA 管理器”功能。這可以作為操作系統(tǒng)或者實(shí)時內(nèi)核的一部分來提供,但它也可以在沒有這兩者的條件下運(yùn)行。在Blackfin處理器上,該功能可以作為VisualDSP++工具包的‘System Services’的一部分提供。這一管理功能可以讓你通過標(biāo)準(zhǔn)的API來轉(zhuǎn)移數(shù)據(jù),而不必手工去配置每一個控制寄存器。
基本上,一個應(yīng)用將DMA描述符的要求提交給DMA隊(duì)列管理器,其責(zé)任是處理每一次請求。請求的處理則是按照它們被應(yīng)用軟件接收到的順序來進(jìn)行的。指向“回調(diào)”函數(shù)的地址指針往往也是系統(tǒng)的一部分。該函數(shù)可以完成在數(shù)據(jù)緩沖準(zhǔn)備好時你希望處理器來完成的工作,無需讓內(nèi)核停留在高優(yōu)先級的中斷服務(wù)例程的執(zhí)行中。總的來說,DMA管理器可以簡化編程模型,因?yàn)樗鼘?shù)據(jù)的傳輸進(jìn)行了抽象。
管理采用中斷的描述符隊(duì)列可以有兩種通用的方法:第一種基于在每次描述符完結(jié)時所發(fā)出的中斷,只有當(dāng)你能確保每個中斷事件將單獨(dú)得到服務(wù)、無中斷溢出時,才使用這種方法;第二種方法是僅僅在由一個工作塊的最后一個描述符所規(guī)定的工作傳輸結(jié)束時發(fā)出中斷。工作塊是一個或者多個描述符的集合。
為了保持描述符隊(duì)列的同步,非中斷型軟件就必須維持一個添加到隊(duì)列中的描述符數(shù)量的計(jì)數(shù),而中斷處理程序則維持一個對已完結(jié)的、從隊(duì)列中除去的描述符的計(jì)數(shù)。計(jì)數(shù)次數(shù)僅僅在DMA完成對所有的描述符的處理后暫停時才會相等。
本文小結(jié)
本文中,我們討論了DMA數(shù)據(jù)流的結(jié)構(gòu):基于寄存器的和基于描述符的,以及何時使用其中的某種結(jié)構(gòu)。在下一期中,我們將分析某些先進(jìn)的DMA功能特色,這些功能將協(xié)助數(shù)據(jù)在多媒體系統(tǒng)中有效地移動。
作者:
David Katz
Rick Gentile
美國模擬器件公司