參數(shù)的訪問與堆棧指針的調(diào)整
如果希望被C程序調(diào)用的匯編函數(shù)含有參數(shù),那么就必須按照編譯器對含參數(shù)的C函數(shù)的參數(shù)處理原則,利用任務(wù)堆棧指針訪問參數(shù)。其方式如上例中所示。在DSP中,堆棧指針的調(diào)整借助輔助寄存器(ARx或者XARx)實現(xiàn)。如例,通過AR2實現(xiàn)了帶符號數(shù)的補碼運算,這樣可以根據(jù)需要移動堆棧指針,實現(xiàn)對函數(shù)參數(shù)的訪問,此外,調(diào)用者與被調(diào)用函數(shù)的局部數(shù)據(jù)結(jié)構(gòu)的創(chuàng)建與釋放也是通過堆棧指針實現(xiàn)的。值得一提的是,在μC/OS-II移植中任務(wù)調(diào)度與中斷部分程序需要注意因參數(shù)而產(chǎn)生的堆棧指針調(diào)整,應(yīng)用任務(wù)的參數(shù)定義也必須與之保持一致。
混合編程中程序運行環(huán)境的改變與保持
不管采用哪種混合編程方式,運行環(huán)境的改變與保持對程序運行正常與否有著重要影響。正常的運行環(huán)境不僅關(guān)系到DSP狀態(tài)寄存器的各狀態(tài)位,也關(guān)系到編譯器的函數(shù)調(diào)用規(guī)則,寄存器和堆棧的使用規(guī)則。尤其在使用第三方提供的函數(shù)時,應(yīng)該特別注意這個問題。在允許的情況下函數(shù)調(diào)用前后也可采用保存與恢復(fù)現(xiàn)場的手段。這樣做不利于提高耦合性和減少冗余,但有利于增加可移植性。此外,對運行環(huán)境的關(guān)注也有利于提高程序的擴展性。
mC/OS-II及應(yīng)用程序在DSP上運行關(guān)鍵問題的解決
堆棧的使用。I$$SAVE,I$$REST函數(shù)
函數(shù)調(diào)用是否正常,任務(wù)調(diào)度與中斷是否正常,在很大程度上都取決于堆棧的使用正確與否。對于240xA系列, TI提供了保存與恢復(fù)堆棧的函數(shù)I$$SAVE、I$$REST,這兩個函數(shù)都位于rts2xx.lib庫中,所在的源文件是saverest.asm。它們在發(fā)生任務(wù)調(diào)度和中斷的時候使用,保存或恢復(fù)了所有編譯器所使用的寄存器以及硬件堆棧。I$$SAVE函數(shù)的代碼如下:
I$$SAVE:
MAR *, AR1 AR1存放堆棧指針
ADRK #1h
SST #1, *+ 保存狀態(tài)寄存器
SST #0, *+
SACH *+, 0 保存ACC內(nèi)容
SACL *+, 0
CLRC OVM
SPM
SPH *+ 保存PREG
SPL *+
MPY #1h 保存TREG
SPL *+
SAR AR0, *+ 保存輔助寄存器
SAR AR2, *+
SAR AR3, *+
SAR AR4, *+
SAR AR5, *+
SAR AR6, *+
SAR AR7, *+
POPD * I$$SAVE的返回
地址壓入任務(wù)堆棧
LACC *, 0
RPT #6h 硬件堆棧其它內(nèi)容
壓入任務(wù)堆棧
POPD *+
BACC
與I$$SAVE函數(shù)相反,I$$REST恢復(fù)各寄存器與硬件堆棧的值。但是現(xiàn)場恢復(fù)的順序與保存有所不同,其中利用了TREG將PREG的低16位彈出堆棧,再彈出TREG本身,這里彈棧的過程相對于壓棧而言不是順序的。另外,I$$SAVE函數(shù)將8級硬件堆棧全部壓入任務(wù)棧,但棧頂內(nèi)容被其下的內(nèi)容覆蓋,同時最后使用了跳轉(zhuǎn)指令,因此調(diào)用I$$SAVE函數(shù)必須使用CALL指令,而I$$REST函數(shù)只需恢復(fù)除了原棧頂以外其它7級硬件堆棧的內(nèi)容。
AR1自始至終存放著堆棧指針。在I$$SAVE與I$$REST函數(shù)的首尾對堆棧指針作了調(diào)整。兩個函數(shù)對指針的調(diào)整是相互對應(yīng)的,確保了堆棧指針位置正確。
在現(xiàn)場保存要求較高情況下,這兩個函數(shù)可以用修改庫文件的方法改進,添加某些用戶希望在調(diào)度與中斷過程中保存的量,特別是對于大型嵌入式軟件中具有類似C語言volatile屬性的量。當(dāng)堆?臻g緊張時,也可以用同樣的方式去除某些不必保存的量。
對操作系統(tǒng)的移植而言,堆棧在初始化中必須模仿被中斷時保存堆棧的情形,只是在任務(wù)返回地址處不使用硬件堆棧中的值,而是使用任務(wù)的入口地址。
某些DSP并不具有硬件堆棧,因而保存與恢復(fù)寄存器的方式有較大的不同,給編程帶來了更大的靈活性。他們通常采用了TRAP與IRET這樣的保存恢復(fù)現(xiàn)場的指令,在執(zhí)行這些指令前需要對堆棧指針進行調(diào)整。
程序及數(shù)據(jù)的ROM初始化
混合編程的程序在DSP中的固化涉及到程序是否能夠徹底脫機運行。其內(nèi)容包括設(shè)置微處理器/微控制器位,合理的編寫.cmd文件等。而程序固化的關(guān)鍵問題是如何在程序存儲器中分配存儲空間給常量和用const關(guān)鍵字定義的靜態(tài)、全局變量。
上述這些量被分配到存儲空間中的.const段。它在DSP中的初始化一般有三種方式,一種是去除const關(guān)鍵字,在程序中賦初值使用。并且需要在.cmd文件中將.cinit段分配到程序區(qū)FLASH存儲空間,然后在編譯器的編譯選項中選中“-C”,即ROM初始化。第二種方法不對定義作修改,.const段保存在FLASH存儲器中,數(shù)據(jù)不向數(shù)據(jù)存儲器移動,程序運行時直接在程序存儲空間中訪問這些量。由于C語言缺乏訪問程序區(qū)數(shù)據(jù)的有效手段,因此這些語句只能使用匯編語言編寫。由于在每一處訪問這些常量時都必須使用這些語句,因此這樣編寫程序改動量較大。
第三種方法較之前兩種,運用起來要方便得多。它不需要修改常量定義,也不必編寫專門的程序。主要的工作是修改.cmd文件并對工程中使用的庫文件作簡單的修改,修改工作量小而且集中,極大地方便了程序的編寫。同前兩種方式不同,這種方式需要設(shè)置.const段的裝載地址和運行地址。其表達式如下。
.const : LOAD = FLASH PAGE 0 , RUN = EXT PAGE 1
{
__const_run = .; /* 獲取運行地址 */
*(.c_mark) /* 標(biāo)志裝載地址 */
*(.const) /* 分配.const段 */
__const_length = .- __const_run; /* 計算段長 */
}
采用了裝載地址與運行地址分離的方式后,為了使程序正常運行,在初始化時,需要將.const段的內(nèi)容從裝載地址拷貝到運行地址內(nèi)。這段程序可以在編譯時由編譯器自動生成。這還需要對軟件所使用的庫文件作簡單的修改。該庫名稱即是rts.lib(表示不同類型的DSP,有2xx,25,50等等)。修改該庫的方法是將源文件從庫中提取出來,作修改,編譯后再替代原有的文件。具體的操作如下:先執(zhí)行DOS命令:
dspar -x rts.src boot.asm
這句的功能是從rts.src文件中提取出boot.asm文件。這個rts.src即是rts.lib的源文件。在boot.asm文件中能找到CONST_COPY這個標(biāo)志量,為了實現(xiàn)所需要的功能它應(yīng)被賦值為1。對boot.asm文件的編輯完成之后,就可以將其編譯生成目標(biāo)文件,執(zhí)行語句:
dspa -v boot.asm
其中對于不同的DSP需要使用不同的參數(shù),對于240xA來說,應(yīng)該使用2xx來代替“”。語句執(zhí)行完后會生成boot.obj文件。再執(zhí)行語句:
dspar -r rts.lib boot.obj
這時它就替換了庫里的同名文件。在編譯時編譯器就會自動增加拷貝.const段到數(shù)據(jù)空間的語句。這種方法不必修改程序,代價是犧牲了一定數(shù)據(jù)存儲空間,時間開銷主要出現(xiàn)在初始化中。這是最經(jīng)濟實用的方法之一。
使用代碼工具
各種各樣的代碼生成工具可以大大增加編程的靈活性。除了前面提到的dspar與dspa兩個指令外,C文法分析程序dspac.exe對.C文件進行文法分析,生成.IF中間文件,dspopt.exe對.IF文件進行優(yōu)化,生成.OPT文件。此外,還有其它多種功能不同的代碼工具。對于應(yīng)用環(huán)境苛刻的程序,它們有利于分析如何對其進行優(yōu)化。
混合編程的實際運用及結(jié)論
本項目全面采用了C與匯編混合編程,采用這種方式是為了提高程序的運行效率,節(jié)省空間。本項目軟件包括模擬量采集與計算,頻率采集與計算,開關(guān)量、數(shù)字量采集與控制,總線通訊,歷史數(shù)據(jù)備份,BIT等諸多功能;程序運行一方面依據(jù)mC/OS-II提供的時鐘節(jié)拍并考慮數(shù)據(jù)采集分辨率的要求,另一方面需要兼顧總線上的大小定時周期。如果全部采用C語言編程,那么16路交流模擬量以16個點采樣并計算時CPU資源緊張,而使用C與匯編混合編程,CPU利用率有超過5%的降幅。每個周期內(nèi)CPU仍然有一定的空閑時間。這其中,數(shù)學(xué)運算函數(shù)也使用了TI提供的由匯編程序生成的庫。
我們的實踐證明,采用混合編程的軟件更加契合一般嵌入式系統(tǒng)對時間和空間的嚴格約束。設(shè)計良好的混合編程軟件既能有效地滿足嵌入式系統(tǒng)對功能與性能的需求;同時,它也可以為程序的擴展和移植預(yù)留足夠的空間;旌暇幊淌乔度胧较到y(tǒng)軟件最優(yōu)化的重要途徑。
參考文獻:
1.TMS320C1x/C2x/C2xx/C5x Assemble Language Tools User's Guide, Texas Instruments, 1999
2.TMS320C2x/C2xx/C5x Optimizing C Compiler User's Guide, Texas Instruments, 1999
3.TMS320C28x DSP Reference Guide, Texas Instruments, 2001





