作者:David Katz,Tomasz Lukasiak,Rick Gentile
數(shù)字信號處理器(DSP)在性能、外設(shè)、功耗和價格上已經(jīng)結(jié)合得非常好了,許多系統(tǒng)工程師希望利用DSP的優(yōu)勢,取代傳統(tǒng)設(shè)計方案中使用的處理器,但一個潛在難題是設(shè)計工程師已經(jīng)為他們的應(yīng)用開發(fā)了大量C和C++代碼。很明顯,工程師都愿意在DSP平臺上利用現(xiàn)有的高級代碼,同時利用DSP的體系結(jié)構(gòu)特性以獲得更好的性能。
HLL與匯編語言
當(dāng)開發(fā)基于DSP的軟件時,必須要做的一項工作就是確定使用哪一種程序設(shè)計方法學(xué),通常是在匯編語言和高級語言(HLL)(例如C或C++語言)之間進(jìn)行選擇。
C和C++的優(yōu)點包括模塊性、便攜性以及可重復(fù)利用性。
傳統(tǒng)的匯編語言由于其語法和縮寫難以理解和使用,長期以來不被人們所看好。目前的“代數(shù)語法”體系結(jié)構(gòu)有了很大改進(jìn)。表1是使用傳統(tǒng)風(fēng)格和使用代數(shù)格式的典型DSP指令實例,很顯然后者的結(jié)構(gòu)更加直觀。在所提供的實例中,r寄存器是數(shù)據(jù)寄存器,p寄存器是指針寄存器。
用匯編語言編程困難的一個原因是由于其數(shù)據(jù)流集中在DSP實際寄存器組、計算單元和存儲器之間。用C或C++語言編程,這種操作通常通過使用變量和函數(shù),或過程調(diào)用出現(xiàn)在更加抽象的處理等級之間,從而使得代碼更容易跟隨。
為提高DSP執(zhí)行效率,工具開發(fā)商會使用匯編語言對重要的數(shù)據(jù)密集代碼模塊進(jìn)行優(yōu)化。HLL編譯優(yōu)化轉(zhuǎn)換可以很好地完成該項工作,而且對DSP數(shù)據(jù)流和計算的直接控制能力是極為出色的。這就是為什么設(shè)計工程師通常結(jié)合使用C/C++和匯編語言。HLL適合于控制和基本的數(shù)據(jù)操作,而匯編語言適合于高效的數(shù)字計算。
適合高效編程的體系結(jié)構(gòu)的特性
為了使匯編語言程序員能夠有效地完成工作,需要了解處理器的結(jié)構(gòu)類型,以便能夠區(qū)分不適合高速數(shù)字計算的那些DSP處理器。這些適合高效編程的體系結(jié)構(gòu)結(jié)構(gòu)特性包括:
● 專用尋址模式
● 硬件環(huán)路結(jié)構(gòu)
● 高速緩沖存儲器
● 每周期多次操作
● 互鎖流水線
● 靈活的數(shù)據(jù)寄存器文擋
專用尋址模式
允許處理器在單周期內(nèi)訪問多個數(shù)據(jù)字需要靈活的地址產(chǎn)生方式。除了需要更大的以DSP為中心的16bit和32bit邊界的訪問尺寸外,還需要字節(jié)尋址以達(dá)到最有效的處理。這是非常重要的,因為一些普通應(yīng)用(例如許多基于視頻的系統(tǒng))都是按照8bit數(shù)據(jù)操作。當(dāng)處理器訪問限制在單一邊界內(nèi)時,處理器可能需要額外的周期來掩蔽掉相關(guān)的位。
另外一種有利的尋址能力是“循環(huán)緩沖”。該特性必須直接由處理器支持,無須專門的軟件管理開銷。循環(huán)緩沖允許程序員定義存儲器中的緩沖器,并且自動跨越它們。一旦緩沖器設(shè)置好,則無須專門的軟件交互操作數(shù)據(jù)。地址發(fā)生器處理非同式跨幅,更重要的是可以處理圖1所示的“環(huán)繞式”特性。如果沒有這種自動地址產(chǎn)生功能,程序員必須手動跟蹤緩沖器,從而浪費了寶貴的處理周期。
圖1 環(huán)繞式緩沖的例子
在此例中,基地址和起始索引地址=0x0;索引地址寄存器I0指向地址0x0;緩沖器長度L=44(11個數(shù)據(jù)元素×4字節(jié)/元素);修改寄存器M0=16(4個數(shù)據(jù)元素×4字節(jié)/元素)
實例代碼:
R0 = [I0++M0]; //R0 = 1,I0在代碼執(zhí)行后指向0x10
R1 = [I0++M0]; //R1 = 5,I0在代碼執(zhí)行后指向0x20
R2 = [I0++M0]; //R2 = 9,I0在代碼執(zhí)行后指向0x04
R3 = [I0++M0]; //R3 = 2,I0在代碼執(zhí)行后指向0x14
R4 = [I0++M0]; //R4 = 6,I0在代碼執(zhí)行后指向0x24
用于高效信號處理運算(例如快速傅立葉變換(FFT)和離散余弦變換(DCT))的一種重要尋址模式是比特翻轉(zhuǎn)。顧名思義,“比特翻轉(zhuǎn)”就是將二進(jìn)制地址中的比特翻轉(zhuǎn),也就是說將權(quán)值最小的比特與權(quán)值最大的比特交換位置。由基為2的蝶形所要求的數(shù)據(jù)順序是“已翻轉(zhuǎn)比特”的順序,因此比特翻轉(zhuǎn)索引用來組合FFT級??梢杂嬎丬浖械倪@些比特翻轉(zhuǎn)索引,但是這樣做的效率非常低。圖2所示是比特翻轉(zhuǎn)地址流實例。
圖2 硬件比特翻轉(zhuǎn)機(jī)理
實例代碼:
LSETUP(起始, 終止)LC0=P0; //循環(huán)數(shù)P0=8
起始:R0 = [I0] || I0 += M0(BREV); //I0指向輸入緩沖器,在比特翻轉(zhuǎn)過程中自動增加
終止:[I2++] = R0; ; //I2指向比特翻轉(zhuǎn)緩沖器
硬件循環(huán)結(jié)構(gòu)
循環(huán)在通信處理算法中是一項很重要的特性。有兩個與循環(huán)有關(guān)的關(guān)鍵特性能夠改進(jìn)多種算法的性能。第一個特性稱作“零開銷硬件循環(huán)”。隨著尋址能力的提高,循環(huán)結(jié)構(gòu)可以在硬件中實現(xiàn)。此外,當(dāng)該項功能用軟件實現(xiàn)時,相關(guān)的開銷可減小到實時處理預(yù)算。零開銷循環(huán)允許程序員通過設(shè)置計數(shù)值并且定義循環(huán)邊界初始化循環(huán)。處理器將繼續(xù)執(zhí)行循環(huán)直到計數(shù)結(jié)束。
零開銷循環(huán)是大多數(shù)處理器必不可少的一部分,但“硬件循環(huán)緩沖器”實際上可以提高循環(huán)結(jié)構(gòu)的性能。它們用作循環(huán)中所執(zhí)行指令的一種高速緩沖存儲器。例如,在第一次執(zhí)行完一個循環(huán)之后,可將該指令保存在循環(huán)緩沖器中,從而無須在每一次循環(huán)都反復(fù)重取相同指令。通過將循環(huán)指令保存在能夠在單周期內(nèi)訪問的緩沖器中,能夠節(jié)省大量的周期數(shù)。該特性不需要程序員進(jìn)行額外的設(shè)置,但是需要知道循環(huán)緩沖器的尺寸以合理地選擇循環(huán)大小。
高速緩沖存儲器
通常典型的DSP具有少量的快速、內(nèi)置存儲器。MCU通??梢栽L問大量的外部存儲器。分層存儲器體系結(jié)構(gòu)將這兩種方案的優(yōu)點結(jié)合在一起,從而可提供幾種等級具有不同性能的存儲器。對于需要最高性能應(yīng)用,可以在單個核心時鐘周期內(nèi)訪問內(nèi)置SRAM。對于具有大代碼尺寸的系統(tǒng),可提供大量、較長等待延遲的片內(nèi)和片外存儲器。
這種分層存儲器體系結(jié)構(gòu)本身僅僅是發(fā)揮一定的作用,由于現(xiàn)在的高性能處理器常常運行在較低的時鐘頻率下,因此大的應(yīng)用程序只能裝在較慢的外部存儲器中。此外,程序員被迫手動將關(guān)鍵代碼移入和移出內(nèi)部SRAM。但是,通過將數(shù)據(jù)和指令高速緩沖存儲器加到該體系結(jié)構(gòu)中后,外部存儲器更易于管理,高速緩沖存儲器可以減少將指令和數(shù)據(jù)移入處理器內(nèi)核的手工操作。由于不需要考慮進(jìn)入內(nèi)核的數(shù)據(jù)和指令流管理,可以大大簡化編程模式。
指令高速緩存通常采用了某種類型的最近最少使用(LRU)算法,從而確保更常用的指令代替較少使用的指令。將一些內(nèi)置數(shù)據(jù)存儲器配置為高速緩存和部分SRAM的能力可以優(yōu)化性能。直接存儲器訪問(DMA)控制器能夠直接控制內(nèi)核,同時當(dāng)需要表中數(shù)據(jù)時將其讀入數(shù)據(jù)高速緩存。一旦高速緩存允許并且DMA控制器配置完畢,則程序員即可集中精力于內(nèi)核算法的開發(fā)。
每周期多次操作
通常以每秒執(zhí)行多少百萬條指令(MIPS)來衡量處理器。曾經(jīng)被保留用在高成本并行處理器中的多發(fā)布指令目前也可用在低成本、定點處理器中。除了在每個核心處理器周期內(nèi)完成多條ALU或MAC操作外,在相同周期內(nèi)還可完成額外的數(shù)據(jù)處理和數(shù)據(jù)存儲。存儲器通常劃分為子若干個存儲器組,這些存儲器組可以被內(nèi)核雙向訪問并且被DMA控制器隨機(jī)訪問。鑒于上述的基于硬件的尋址算法的分解方法,很明顯其可以在單個周期內(nèi)完成許多操作。
圖3示出多操作指令的一個實例。如圖3所示,在一個周期內(nèi)除了完成兩條獨立的MAC操作外,在相同的處理器時鐘周期內(nèi)還完成了數(shù)據(jù)讀取和數(shù)據(jù)存儲。
圖3 Blackfin多發(fā)布指令在單周期內(nèi)完成幾次操作
互鎖流水線
隨著處理器速度的增加,從整個電路級來看處理流水線必定會變得更深。然而,有些處理器具有“互鎖”流水線。這意味著當(dāng)完成匯編語言編程時,程序員不必手動調(diào)度或跟蹤通過流水線的數(shù)據(jù)和指令。處理器會自動處理這些時序的事情。
靈活的數(shù)據(jù)寄存器文檔
最后,另外一個補(bǔ)充特性是通用數(shù)據(jù)寄存器集。在傳統(tǒng)的定點DSP中,字長通常是固定的。然而,具有能夠用作一個32bit(例如R0)或兩個16bit(例如分別用于低8bit和高8bit的R0.L和R0.H)的數(shù)據(jù)寄存器是非常有利的。在雙MAC系統(tǒng)中,這允許在單周期內(nèi)操作四個16bit的數(shù)據(jù)。
內(nèi)積
內(nèi)積或者標(biāo)量積在度量兩個向量的正交性時是很有效的操作。大多數(shù)C語言程序員應(yīng)該熟悉以下的內(nèi)積操作: short dot(short a[], short b[], int size) {
int i;
int output = 0;
for(i=0; i }
return output;
下面是Blackfin處理器匯編代碼的主要部分:
//P0=loop count, I0 & P1 are address registers
A1 = A0 = 0; // A0 & A1 are accumulators
LSETUP (loop1,loop1) LC0 = P0 ;// Setup hardware loop starting at label loop1:
loop1: A1 +=R1.H*R0.H, A0+=R1.L*R0.L||R1=[P1++]||R0=[I0++];
下面幾點說明了簡化這種緊湊編碼的DSP體系結(jié)構(gòu)特性。
硬件循環(huán)緩沖器和循環(huán)計數(shù)器在每次迭代的末端不需要跳轉(zhuǎn)指令。由于內(nèi)積是乘積總和,因此可在一次循環(huán)中完成。該匯編程序所示是LSETUP指令,它是執(zhí)行循環(huán)所需的唯一指令。
多發(fā)布指令允許在相同的周期內(nèi)執(zhí)行多條指令和兩次數(shù)據(jù)訪問。在每一次迭代時,必須先讀取a和b值,然后相乘,最后寫回到可變輸出的運行總和中。在許多MCU平臺上,這實際上等于四條指令。匯編代碼的最后一行示出在一個周期內(nèi)可執(zhí)行的所有操作。
并行ALU操作允許同時執(zhí)行兩條16bit指令。匯編代碼示出在每次迭代中使用的兩個累加器單元(A0和A1),這將迭代次數(shù)減少了50%,從而將原來的執(zhí)行時間減少了一半。
FIR算法
有限脈沖響應(yīng)(FIR)濾波器是一種等價于卷積操作很常見的濾波器結(jié)構(gòu)。A通過C操作看起來非常類似于內(nèi)積。
//將信號取樣到循環(huán)緩沖器中
x[cur] = sampling_function();
cur = (cur+1)%TAPS; // 在循環(huán)中增加cur指針
//完成乘加
y = 0;
for (k=0; k }
使用匯編語言編寫的FIR內(nèi)核格式有些類似于內(nèi)積。在這個特定的例子中,取樣值存儲在R0寄存器中,同時系數(shù)存儲在R1寄存器中。
// P0 存有濾波器抽頭
R0=[I0++] || R1=[I1++]; // 設(shè)置R0和R1的初始值
A1=A0=0; // 將累加器置零
LSETUP (loop1, loop1) LC0 = P0;//設(shè)置內(nèi)部循環(huán)
loop1: A1+=R0.L*R1.L, A0+=R0.H*R1.H||R0=[I0++]||R1=[I1++]; //計算
除了具有所描述的用于內(nèi)積的特性外,上面所示的FIR算法也可使用循環(huán)緩沖。
循環(huán)緩沖器不需要直接取余運算。在C代碼片段中,%(取余)運算符可提供一種用于循環(huán)緩沖的機(jī)理。正如匯編內(nèi)核中所示,這些取余運算符不能被編譯為內(nèi)循環(huán)中的其他指令。相反,數(shù)據(jù)地址發(fā)生器寄存器I0和I1可在外循環(huán)中配置,以便在循環(huán)到達(dá)系數(shù)緩沖器邊界時能夠自動返回起始處。
FFT算法
快速傅立葉變換(FFT)是許多信號處理算法不可缺少的一部分,其特點之一是輸入向量按照連續(xù)時間順序排列,但輸出按比特翻轉(zhuǎn)順序排列。大多數(shù)傳統(tǒng)的通用處理器要求程序員用單獨的程序整理比特翻轉(zhuǎn)輸出。在DSP平臺上,比特翻轉(zhuǎn)可用于尋址引擎。
比特翻轉(zhuǎn)尋址在實現(xiàn)FFT時不需要單獨的比特翻轉(zhuǎn)程序,允許硬件自動將FFT算法的輸出進(jìn)行比特翻轉(zhuǎn),無須程序員編寫額外的程序,從而改進(jìn)了性能。
除了上面所提到的指令外,有些處理器也包括額外一套專用指令以支持多種應(yīng)用。提供這些指令的目的就是進(jìn)一步提高對算法的處理能力,例如維特比算法、Huffman編碼以及許多其他比特操作程序。
zrbj:gt
評論