石 磊, 孫 倩
(魯東大學(xué),1. 信息與電氣工程學(xué)院,2. 數(shù)學(xué)與統(tǒng)計(jì)科學(xué)學(xué)院, 山東 煙臺(tái)264025)
數(shù)字信號(hào)處理器 DSP(digital signal processor)是將傳統(tǒng)的基于硬件設(shè)計(jì)的數(shù)字信號(hào)處理變成軟件設(shè)計(jì),其中TI公司的TMS320C6000芯片是高校教學(xué)以及工程應(yīng)用中較為常用的一款高端的DSP型號(hào)。在DSP的教學(xué)過程中,教師和學(xué)生往往注重DSP的C語言編程以及對(duì)外設(shè)的使用,因?yàn)閷W(xué)會(huì)這些就可以很容易地使用C語言來操作DSP的外設(shè)且比較容易獲得成就感。但是DSP是一個(gè)算法處理芯片,軟件優(yōu)化是其更重要的內(nèi)容,因?yàn)镈SP上運(yùn)行的可能是實(shí)時(shí)的圖像或者視頻處理軟件[1~2]。
軟件優(yōu)化中匯編代碼的軟件流水是其核心,TMS320C6000系列DSP的開發(fā)工具比如CCS(Code Composer Studio)的編譯器里可以設(shè)置自動(dòng)進(jìn)行軟件流水[3~5]。但是想要真正理解DSP的CPU內(nèi)核架構(gòu)以及理解DSP的軟件優(yōu)化,學(xué)會(huì)匯編代碼的軟件流水是非常重要的。
匯編代碼的軟件流水較為復(fù)雜,在教學(xué)過程中,選擇一個(gè)好的實(shí)例來講好此內(nèi)容是非常具有挑戰(zhàn)性的。為此,我們以有限沖擊響應(yīng)(FIR)的線性匯編代碼為例來討論DSP的匯編軟件流水方法。首先是編寫有限沖擊響應(yīng)的C語言代碼,并根據(jù)C語言代碼將其改為線性匯編代碼;然后根據(jù)線性匯編代碼進(jìn)行軟件流水[5];再比較未進(jìn)行軟件流水以及進(jìn)行軟件流水代碼的不同性能,最后是教學(xué)效果評(píng)估以及總結(jié)。講解此內(nèi)容的目標(biāo)是讓學(xué)生能夠理解軟件優(yōu)化的思想和掌握匯編軟件流水的方法,難點(diǎn)在于軟件流水中編排表的建立。
有限沖擊響應(yīng)公式為
可以簡寫為
實(shí)現(xiàn)此式的C語言函數(shù)為
int fir_example(short h[], short x[],N)
{
int y1=0,y2=0,i;
for (i=0; i y1+= h[i]*x[i]; y2+=h[i+1]*x[i+1];} return y1+y2; } 根據(jù)TMS320C6000系列DSP的CPU內(nèi)核特點(diǎn)可知,CPU的數(shù)據(jù)讀取通路至少支持一次讀取32位的數(shù)據(jù),也即支持LDW匯編指令,那么我們使用LDW指令,一次讀取兩個(gè)short類型(16位)的數(shù)據(jù),使用MPY和MPYH指令分別對(duì)讀取的32位數(shù)據(jù)進(jìn)行低位相乘和高位相乘,也即對(duì)讀取的兩個(gè)short類型數(shù)據(jù)分別進(jìn)行相乘。這樣可以使循環(huán)的次數(shù)減少一半。 將此C語言函數(shù)中for循環(huán)部分用線性匯編代碼改寫變成: loop: LDW *h++,hi; LDW *x++,xi; MPY hi,xi,pi_1; MPYH hi,xi,pi_2; ADD pi_1,y_1,y_1 ADD pi_2,y_2,y_2 [cnt] SUB cnt,1,cnt; [cnt] B loop; ADD y_1,y_2,y TMS320C6000系列DSP都是支持超長指令字(VLIW)的,8個(gè)32位指令的取指包組成一個(gè)VLIW,最多一個(gè)CPU時(shí)鐘周期執(zhí)行8條指令,也即CPU的8個(gè)功能單元全部都在執(zhí)行指令。軟件流水是對(duì)循環(huán)代碼進(jìn)行編排,使得循環(huán)迭代代碼能夠并行執(zhí)行,其目的是上一次循環(huán)未完成時(shí)就開始下一次循環(huán)迭代。對(duì)于加載(LDH指令)兩個(gè)半字?jǐn)?shù)據(jù),相乘(MPY指令)之后并進(jìn)行累加(ADD指令)這樣的循環(huán)代碼,其軟件流水執(zhí)行過程如圖1所示: 圖1 軟件流水指令執(zhí)行 圖1最左一列代表時(shí)鐘周期,最上一行代表指令使用的功能單元,這里我們不考慮指令完成需要的時(shí)鐘周期。相同底色的指令代表是同一個(gè)循環(huán),這樣在第3個(gè)時(shí)鐘周期,循環(huán)的四條指令就可以同時(shí)運(yùn)行了,大大提高了程序運(yùn)行的效率,也即在一個(gè)時(shí)鐘周期內(nèi),充分利用每一個(gè)功能單元,進(jìn)行下一次或者下下次數(shù)據(jù)的加載以及數(shù)據(jù)的相乘來提高程序的性能。 匯編的軟件流水需要以下步驟:資源分配、畫相關(guān)圖、建立流水編排表以及寫流水代碼[5],以下分別加以介紹。 資源分配就是對(duì)匯編指令使用的功能單元以及DSP可用的功能單元進(jìn)行分析,對(duì)于FIR的線性匯編代碼,我們可得表1: 表1 資源分配表 從表1中可得,在一個(gè)循環(huán)周期內(nèi),所有的匯編指令都有相應(yīng)的功能單元使用,沒有兩條指令使用同一個(gè)功能單元的情況,也即有可能將一個(gè)循環(huán)所有的指令在一個(gè)時(shí)鐘周期內(nèi)安排執(zhí)行。 相關(guān)圖展示了指令以及數(shù)據(jù)的執(zhí)行流程,可以用于分析程序的循環(huán)或者分析指令的相關(guān)性。畫相關(guān)圖需要畫出節(jié)點(diǎn)以及通路。節(jié)點(diǎn)是數(shù)據(jù)流入和流出的點(diǎn),包括數(shù)據(jù)變量、分配的寄存器、使用的指令和功能單元;通路指示數(shù)據(jù)流的方向,其旁邊的數(shù)字是指令完成需要的周期數(shù)。FIR程序的相關(guān)圖如圖2所示: 圖2 FIR程序相關(guān)圖 由圖2可知,變量hi和xi的讀取,分別使用LDW指令,執(zhí)行此指令需要5個(gè)周期;hi和xi變量的低16位和高16位分別相乘,使用MPY和MPYH指令,完成需要2個(gè)周期;然后分別進(jìn)行累加,使用ADD指令,需要1個(gè)周期。SUB指令對(duì)循環(huán)計(jì)數(shù)變量cnt進(jìn)行減1計(jì)數(shù),當(dāng)計(jì)數(shù)不為0則使用跳轉(zhuǎn)指令B進(jìn)行跳轉(zhuǎn),跳轉(zhuǎn)指令需要6個(gè)周期。分配功能單元時(shí)盡量平分A組和B組的功能單元,同時(shí)變量使用相應(yīng)組側(cè)的寄存器。 根據(jù)2.1節(jié)資源分配的分析可知,可以在一個(gè)循環(huán)周期內(nèi)編排這些指令。根據(jù)圖2找到最長的數(shù)據(jù)通路來編排周期,最長的數(shù)據(jù)通路為LDW->MPY->ADD或者LDW->MPYH->ADD,需要的時(shí)鐘周期為5+2+1=8。在建立編排表的過程中,需要從最長的數(shù)據(jù)通路開始建立,并且從第一個(gè)時(shí)鐘周期就開始編排指令,對(duì)于跳轉(zhuǎn)和循環(huán)計(jì)數(shù)指令可以使用倒推的方法來安排。其中軟件流水編排表如表2所示: 表2 軟件流水編排表 對(duì)于表2來說,每一行代表CPU內(nèi)核的某一個(gè)功能單元,每一列代表一個(gè)循環(huán)中某個(gè)時(shí)鐘周期。需要注意LDW需要5個(gè)周期才能執(zhí)行完畢,所以MPY和MPYH指令安排在第5周期。MPY和MPYH需要2個(gè)周期才能執(zhí)行完畢,所以ADD指令安排在其后2個(gè)周期處。跳轉(zhuǎn)指令B需要6個(gè)時(shí)鐘周期才可以完成,所以倒推至第2周期安排。如表2中灰色部分所示。 在表2中每一個(gè)時(shí)鐘周期還有很多功能單元沒有用到,因此需要進(jìn)行完全流水的編排。為了實(shí)現(xiàn)完全流水的編排表,則還需要確定最小的迭代間隔,也即相鄰的兩次循環(huán)迭代開始之間必須要間隔的最小時(shí)鐘周期數(shù)。如果一次循環(huán)里有N條指令占用同一個(gè)功能單元,則最小迭代數(shù)至少為N,對(duì)于FIR的代碼來說,一次循環(huán)里的指令都有相應(yīng)功能單元使用,不存在多個(gè)指令占用情況,因此迭代間隔為1。那么下次迭代和上次迭代可以只隔一個(gè)周期,則可以將LDW指令填充每一個(gè)周期, MPY和MPYH等指令都可以相應(yīng)進(jìn)行編排,如表2所示。其中指令的下標(biāo)代表某一次迭代,下標(biāo)相同的代表同一次迭代。 表2中最后一列是包括了所有循環(huán)指令的一個(gè)周期,進(jìn)行循環(huán)迭代即是執(zhí)行此周期的代碼。對(duì)于循環(huán)內(nèi)任意一次迭代,比如第n次迭代,正在執(zhí)行的指令為:ADD指令進(jìn)行第n次迭代的相加,MPY和MPYH指令進(jìn)行第n+2次迭代的乘,LDW指令進(jìn)行第n+7次迭代的數(shù)據(jù)讀取,SUB指令進(jìn)行第n+6次迭代的減1,B指令進(jìn)行第n+5次迭代的跳轉(zhuǎn)。 根據(jù)表2依次寫出每個(gè)周期的軟件流水匯編代碼,如下所示: ;第0周期 LDW .D1 *A4++,A2;第0次迭代的hi加載 || LDW .D2 *B4++,B2;第0次迭代的xi加載 || MV .S1 A6,A1;設(shè)置循環(huán)次數(shù) || ZERO .L1 A7;清零y_1 || ZERO .L2 B7;清零y_2 ;第1周期 [A1] SUB .S1 A1,2,A1;第0次迭代的減循環(huán)次數(shù) || LDW .D1 *A4++,A2;第1次迭代的hi加載 || LDW .D2 *B4++,B2;第1次迭代的xi加載 ;第2周期 [A1] SUB .S1 A1,2,A1;第1次迭代的減循環(huán)次數(shù) || [A1]B .S2 LOOP;第0次迭代的跳轉(zhuǎn) || LDW .D1 *A4++,A2; 第2次迭代的hi加載 || LDW .D2 *B4++,B2; 第2次迭代的xi加載 ;第3、4周期和第2周期代碼一致,這里省略 ;第5周期 MPY .M1X A2,B2,A6;第0次迭代的乘積pi_1 || MPYH .M2X A2,B2,B6;第0次迭代的乘積pi_2 ||[A1] SUB .S1 A1,2,A1;第4次迭代的減循環(huán)次數(shù) ||[A1]B .S2 LOOP;第3次迭代的跳轉(zhuǎn) || LDW .D1 *A4++,A2;第5次迭代的hi加載 || LDW .D2 *B4++,B2;第5次迭代的xi加載 ;第6周期和第5周期代碼一致,這里省略 ;第7周期 LOOP: ADD .L1 A6,A7,A7;第0次迭代的累加y_1 || ADD .L2 B6,B7,B7;第0次迭代的累加y_2 || MPY .M1X A2,B2,A6;第2次迭代的乘積pi_1 || MPYH .M2X A2,B2,B6;第2次迭代的乘積pi_2 || [A1]SUB .S1 A1,2,A1;第6次迭代的減循環(huán)次數(shù) || [A1]B .S2 LOOP; 第5次迭代的跳轉(zhuǎn) || LDW .D1 *A4++,A2;第7次迭代的hi加載 || LDW .D2 *B4++,B2;第7次迭代的xi加載 ADD .L1X A7,B7,A4 對(duì)于第1節(jié)中線性匯編代碼,如果不進(jìn)行軟件流水優(yōu)化,直接語句對(duì)應(yīng)改成匯編代碼,那么對(duì)應(yīng)的一次FIR計(jì)算循環(huán),需要兩個(gè)LDW指令進(jìn)行32位數(shù)據(jù)讀取,MPY和MPYH指令進(jìn)行32位數(shù)據(jù)的高低位相乘,兩個(gè)ADD指令進(jìn)行相應(yīng)數(shù)據(jù)相加,以及一個(gè)SUB指令進(jìn)行循環(huán)次數(shù)的減計(jì)數(shù),還有一個(gè)B指令進(jìn)行循環(huán)跳轉(zhuǎn),這8條指令是順序執(zhí)行的,沒有充分利用CPU的8個(gè)功能單元。由于LDW需要5個(gè)時(shí)鐘周期,MPY和MPYH需要2個(gè)時(shí)鐘周期,B需要6個(gè)時(shí)鐘周期,則一次FIR循環(huán)需要18個(gè)時(shí)鐘周期,100次循環(huán)迭代需要1800個(gè)時(shí)鐘周期。 對(duì)于軟件流水后的匯編代碼,因?yàn)槟軌虺浞掷肅PU的8個(gè)功能單元,使得一次FIR計(jì)算循環(huán)的8個(gè)指令能夠在一個(gè)時(shí)鐘周期內(nèi)并行執(zhí)行。所以100次循環(huán)迭代則需要7+100=107個(gè)時(shí)鐘周期,其中前7個(gè)周期用于軟件流水的填充。同樣100次的FIR迭代計(jì)算,軟件流水后運(yùn)行時(shí)間約為未進(jìn)行流水代碼運(yùn)行時(shí)間的1/10,極大地提高了程序的運(yùn)行效率。 “DSP原理與應(yīng)用”是我校一門偏實(shí)踐性的專業(yè)選修課程。由于對(duì)該領(lǐng)域應(yīng)用缺乏了解,以及缺乏編程語言方面的訓(xùn)練,學(xué)生難以理解教學(xué)內(nèi)容從而容易失去對(duì)該課程的學(xué)習(xí)興趣。在該課程的教學(xué)過程中,我們采用了案例、實(shí)驗(yàn)以及理論相結(jié)合的形式授課,這樣可以提高學(xué)生的學(xué)習(xí)興趣,并取得了很好的效果。本課程設(shè)計(jì)了6次實(shí)驗(yàn),前四次偏重DSP的軟件設(shè)計(jì),后兩次是關(guān)于DSP外設(shè)的使用。前四次分別是CCS軟件使用和C語言編程、線性匯編和匯編代碼編寫、軟件流水優(yōu)化、濾波器軟件設(shè)計(jì)及優(yōu)化。前四次實(shí)驗(yàn)整體是由簡單到復(fù)雜,由基礎(chǔ)到應(yīng)用。實(shí)驗(yàn)成績是根據(jù)實(shí)驗(yàn)情況以及實(shí)驗(yàn)報(bào)告進(jìn)行打分,分為A、B、C、D四個(gè)等級(jí),其中D為不及格。由于學(xué)生對(duì)開發(fā)環(huán)境的不熟悉以及之前沒有較好的C語言編程訓(xùn)練,第一次實(shí)驗(yàn)成績較差,之后隨著理論和實(shí)驗(yàn)教學(xué)的深入以及學(xué)生編程能力的強(qiáng)化,學(xué)生實(shí)驗(yàn)成績逐漸提升,如圖3所示,代碼軟件流水為第3次實(shí)驗(yàn),第4次實(shí)驗(yàn)由于是綜合性設(shè)計(jì)實(shí)驗(yàn),學(xué)生成績?yōu)锳和B的稍微少于第3次實(shí)驗(yàn)。通過本教學(xué)方法的實(shí)施,學(xué)生能理解DSP的CPU內(nèi)核硬件和軟件流水優(yōu)化之間的關(guān)系,并能夠在以后的DSP軟件設(shè)計(jì)中有程序優(yōu)化的思想。 圖3 學(xué)生前4次實(shí)驗(yàn)成績 本文以FIR為例給出了匯編代碼軟件流水的詳細(xì)方法,通過資源分配、畫相關(guān)圖、建立流水編排表以及寫流水代碼四個(gè)過程完成軟件流水。通過這樣的教學(xué)案例及教學(xué)方法,學(xué)生對(duì)于TMS320C6000的CPU內(nèi)核和流水線硬件內(nèi)容以及軟件優(yōu)化方面的軟件內(nèi)容有了更深刻的理解,這為后續(xù)的DSP課程設(shè)計(jì)奠定了基礎(chǔ)。2 匯編代碼的軟件流水
2.1 資源分配
2.2 畫相關(guān)圖
2.3 建立編排表
2.4 編寫匯編流水代碼
3 性能比較
4 教學(xué)效果評(píng)估
5 結(jié)語