第6章-基于C語言的DSP芯片開發(fā)-課件_第1頁
第6章-基于C語言的DSP芯片開發(fā)-課件_第2頁
第6章-基于C語言的DSP芯片開發(fā)-課件_第3頁
第6章-基于C語言的DSP芯片開發(fā)-課件_第4頁
第6章-基于C語言的DSP芯片開發(fā)-課件_第5頁
已閱讀5頁,還剩204頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

第6章基于C語言的DSP芯片開發(fā)

6.1引言6.2ANSIC編譯器6.3C語言編程基礎(chǔ)知識6.4基于C語言的DSP芯片開發(fā)的運行環(huán)境6.5C語言與匯編語言的混合編程本章小結(jié)

思考題與習題

第6章基于C語言的DSP芯片開發(fā)6.1引言6.1

引言

DSP的C語言編程的主要內(nèi)容包括ANSIC語言編譯器,運行環(huán)境,運行支持庫的使用與建立,I/O編程,C語言編程的各種工具的使用,以及C調(diào)試器的使用等主要內(nèi)容。限于篇幅,本章主要對ANSIC編譯器和與C語言編程息息相關(guān)的運行環(huán)境以及有關(guān)C語言基礎(chǔ)知識做一介紹。6.1引言

DSP的C語言編程的主要內(nèi)容包6.2ANSIC編譯器6.2.1優(yōu)化ANSIC編譯器

TMS320C3x/C4x編譯器支持ANSI(AmericanNationalStandardsInstitute)開發(fā)的C語言標準。該標準是使用最廣泛的C語言標準,它規(guī)定C語言的一些特征受目標處理器、運行環(huán)境或主機環(huán)境影響。下面就TMS320C3x/C4xC語言的一些不同于標準C語言的特征給予介紹。6.2ANSIC編譯器6.2.1優(yōu)化ANSIC編

1.標識符和常數(shù)

(1)所有標識符的前100個字符有意義,區(qū)分大小寫。這些標示符適用于內(nèi)部和外部的標識符。

(2)源(主機)和執(zhí)行(目標)字符集為ASCII碼,不存在多字節(jié)字符。

(3)字符常數(shù)或字符串常數(shù)中的十六進制或八進制轉(zhuǎn)義序列可具有高達32位的值。

(4)具有多個字符的字符常數(shù)按序列中的最后一個字符來編碼,例如:'abc'=='c'。1.標識符和常數(shù)

2.數(shù)據(jù)類型

(1)整數(shù)、雙精度等數(shù)據(jù)類型長度與常見編譯器中的數(shù)據(jù)類型不同,所有的浮點數(shù)型都是用二進制浮點數(shù)格式來表示的。

(2)?size_t(sizeof操作符的結(jié)果)定義為unsignedint。

(3)?ptrdiff_t(指針加減的結(jié)果)定義為int。

3.數(shù)據(jù)轉(zhuǎn)換

(1)浮點數(shù)到整數(shù)的轉(zhuǎn)換部分取整數(shù)部分。

(2)指針和整數(shù)可自由轉(zhuǎn)換。2.數(shù)據(jù)類型

4.表達式

(1)當兩個帶符號的整數(shù)相除時,若其中一個為負,則其商為負,余數(shù)的符號與分子的符號相同?!?”表示求商,“%”表示求余。帶符號的模運算取被除數(shù)的符號。如:10/-3?=-3;-10/3?=-3;10%-3=1;-10%3?=-1

(2)帶符號數(shù)的右移為算術(shù)右移,即保留符號。4.表達式

5.聲明

(1)寄存器存儲類對所有character、short、integer和pointer類型都有效。

(2)結(jié)構(gòu)成員不能被打包成字,除位域外,每個成員對準在16位字的邊界。

(3)整數(shù)類型的位域帶有符號,位域從字的低位開始被打包成字,并且不超過字邊界。

6.預處理器預處理器忽略所有不支持的#pragma偽指令,支持#pragma的偽指令見后面的內(nèi)容。5.聲明

ANSIC編譯器的主要功能是:首先將DSP的C語言程序轉(zhuǎn)化為匯編語言程序,然后按匯編語言程序調(diào)試手段進行調(diào)試;ANSIC編譯器支持代碼級調(diào)試。采用ANSIC語言進行DSP軟件編程具有的優(yōu)點包括:

1.標準化

C語言是一種非常便于移植的編程語言,尤其是在語言的擴展方面,但缺乏標準化,而ANSIC則為這些擴展提供了新的標準。ANSIC編譯器的主要功能是:首先將DSP的C語言程序

2.兼容性

ANSIC標準是K&R標準的超集。在絕大多數(shù)編譯器下調(diào)試并運行的程序都可以在優(yōu)化ANSIC編譯器下運行。ANSIC的兼容性還有另一個含義,就是通過簡單的修改即可適用于TI公司的其他芯片。

3.補充新類型補充的新類型主要是指新的const以及Volatile類型。它們允許對C語言程序進行更有效的優(yōu)化。2.兼容性

4.改進的函數(shù)約定函數(shù)原型允許改進的類型檢查并允許對函數(shù)調(diào)用進行優(yōu)化。優(yōu)化ANSIC編譯器時主要考慮了三個方面的優(yōu)化:

(1)產(chǎn)生的匯編程序在效率上可與手工編寫的匯編程序相比;

(2)提供簡單的C運行環(huán)境的程序接口,使得關(guān)鍵的DSP算法可用匯編語言實現(xiàn);

(3)為用C語言開發(fā)高性能DSP應(yīng)用程序建立一定規(guī)模的庫,它們都可以被方便地使用。4.改進的函數(shù)約定總的來說,優(yōu)化ANSIC編譯器的主要特征包括:

·與ANSIC功能規(guī)范完全兼容。

·具有ANSIC標準運行支持庫。

·程序可轉(zhuǎn)化為ROM裝載的格式,可重定位、重入。

·提供與匯編語言的接口,允許對時間敏感的程序用匯編語言編寫。

·靈活而全面的鏈接器可以對內(nèi)存重定位、內(nèi)存設(shè)置、部分鏈接進行全面的控制,而且還可以對代碼進行運行時的重定位。總的來說,優(yōu)化ANSIC編譯器的主要特征包括:

·提供了一個外殼程序(shell),允許進一步將C語言轉(zhuǎn)化為可執(zhí)行文件。

·快速的開發(fā)速度。

·提供大量有用的提示,以支持對C程序進行方便的編程和調(diào)試。

·支持行內(nèi)擴展。

·可以對庫進行管理,包括對庫進行文件的增加、刪除、或替換,還可以將目標文件庫用作鏈接器的輸入?!ぬ峁┝艘粋€外殼程序(shell),允許進一步將C語言

·提供豐富的列表文件,如源代碼和匯編的交叉列表、預處理輸出文件等。

·

TMS320C3x/4xANSIC編譯器具有可為全局變量、靜態(tài)變量和常數(shù)提供無限空間的大存儲器模式。缺省的小存儲模式,其空間限制為64K字,使編碼執(zhí)行速度更快、效率更高。C外殼程序提供了許多選項用于控制C編譯匯編和鏈接的過程。

C語言編譯匯編和鏈接的常用的選項如表6.1所示?!ぬ峁┴S富的列表文件,如源代碼和匯編的交叉列表、預處理輸表6.1C語言編譯匯編和鏈接的常用選項表6.1C語言編譯匯編和鏈接的常用選項6.2.2優(yōu)化編譯器

C編譯器提供了一個優(yōu)化編譯器。采用優(yōu)化編譯可以生成高效率的匯編代碼,從而提高程序的運行速度,減少目標代碼的長度。在一定程度上可以認為,C編譯器的效率主要取決于C編譯器所能進行優(yōu)化的范圍和數(shù)量。C編譯器的優(yōu)化方法可以分為兩類,即通用優(yōu)化和特定優(yōu)化。6.2.2優(yōu)化編譯器對C語言的通用優(yōu)化的范圍主要包括:·簡化表達式;·優(yōu)化數(shù)據(jù)流;·刪除公共子表達式和冗余分配;·優(yōu)化跳轉(zhuǎn);·簡化控制流;·優(yōu)化與循環(huán)有關(guān)的重復;·將循環(huán)體內(nèi)的計算值不變的表達式移至循環(huán)體前;·運行支持庫函數(shù)的行內(nèi)擴展;

對C語言的通用優(yōu)化的范圍主要包括:對DSP芯片的特定優(yōu)化的主要內(nèi)容包括:·有效地使用寄存器;·自動增減寄存器尋址方式;·使用塊重復;·使用并行指令;·使用延遲跳轉(zhuǎn)。對DSP芯片的特定優(yōu)化的主要內(nèi)容包括:下面主要對浮點DSP芯片的特定優(yōu)化作一詳細介紹。

1)優(yōu)化寄存器變量的使用編譯器將最大程度地利用寄存器存儲局部變量、參數(shù)及中間值。將數(shù)據(jù)存儲在寄存器中要比將數(shù)據(jù)存儲在存儲器中的程序的運行效率高。在將數(shù)組結(jié)構(gòu)轉(zhuǎn)化為循環(huán)時,這一優(yōu)化顯得尤其有效。下面主要對浮點DSP芯片的特定優(yōu)化作一詳細介紹。例6.1優(yōu)化寄存器變量的使用。

C語言程序:

intgvar;

reg(inti,intj)

{

gvar=call()&i;

j=gvar+i;

}浮點DSP編譯器輸出程序:

_reg:***R4分配給用戶變量i

*R5分配給用戶變量j例6.1優(yōu)化寄存器變量的使用。

CALL_call ;R0=call()

ANDR4,R0 ;R0&=i

STIR0,@_gvar ;gvar=R0

ADDIR4,R0,R5 ;將gvar保留在R0中

… ;將結(jié)果放到R5(j)中編譯器在編譯時,將i,j分別賦予R4,R5,將gvar保留在R0。這樣gvar的運算成了3操作數(shù)運算,結(jié)果j直接放在RS中??梢?,充分利用寄存器可提高程序的運行效率?!?/p>

2)效率最優(yōu)的寄存器分配編譯器根據(jù)用戶變量和中間值的類型與使用頻率來對寄存器進行分配,在循環(huán)體內(nèi)的變量比其他變量有更高的優(yōu)先級,相互之間不覆蓋的變量可以被分配給同一寄存器。

3)并行指令許多類型的指令,如裝載/裝載、存儲/操作/乘/加,可以配對并行執(zhí)行。當相鄰符號滿足并行運行的尋址要求時,編譯器使它們并行運行。雖然這一功能已由代碼生產(chǎn)工具完成,但優(yōu)化還是對提高上述情況的運行效率起了很大的作用,因為操作數(shù)被更多地放到了寄存器中,進一步提高了運行速度。2)效率最優(yōu)的寄存器分配

4)自增尋址模式對于*P++,*--P這樣的表達式,編譯器可以使用高效的自增尋址模式。在許多場合,循環(huán)中的數(shù)組值被逐個使用。如:

for(i=0;i,=N;++i)a[i]…;這時,編譯器通過自增寄存器變量指針把數(shù)組參數(shù)轉(zhuǎn)化為間接尋址參數(shù)。

5)塊重復浮點編譯器通過RPTS和RPTB指令實現(xiàn)過零循環(huán)。編譯器能發(fā)現(xiàn)通過計算機控制的循環(huán),并使用高效的RPTB和RPTS來實現(xiàn)循環(huán)。這兩種方式中,調(diào)整量可以是常數(shù),也可以是表達式。4)自增尋址模式例6.2塊重復,自增尋址模式和并行運算。

C語言程序:

floata[1],b[10];

scale(floatk)

{

inti;

for(i=0;i<10;++i)

a[i]=b[i]*k;

…例6.2塊重復,自增尋址模式和并行運算。浮點DSP編譯器輸出:_scale…LDI@CONST+0,AR4 ;AR4=&a[0]LDI@CONST+1,AR5 ;AR5=&b[0]MPYFR4,*AR5++,R0 ;計算第一個結(jié)果RPTS8 ;STFR0,*AR4++ ;保存這一結(jié)果||MPYFR4,*AR5++,R0;開始計算另一個結(jié)果STFR0,*AR4++ ;保存最后一個結(jié)果浮點DSP編譯器輸出:

6)延遲跳轉(zhuǎn)指令浮點DSP支持延遲跳轉(zhuǎn)指令。它與普通的跳轉(zhuǎn)指令比起來,可以節(jié)省三個指令周期的運行時間。延遲跳轉(zhuǎn)指令是在執(zhí)行完其后的三條指令后才發(fā)生真正的跳轉(zhuǎn),編譯器盡可能實現(xiàn)無條件的延遲跳轉(zhuǎn)指令,并在計數(shù)循環(huán)的場合使用條件延遲跳轉(zhuǎn)指令。6)延遲跳轉(zhuǎn)指令例6.3延遲跳轉(zhuǎn)指令。

C語言程序:

wait(volatileint*p)

{

for(;;)

if(*p&0x80)*p|=0xf0;

}浮點DSP編譯器輸出程序:

_wait:

L6:例6.3延遲跳轉(zhuǎn)指令。LDI*AR4,R0 ;R0=*p(AR4被分配給p)TSTB128,R0 ;test*p&0x80BZL6 ;結(jié)果為假,采用直接跳轉(zhuǎn)返回BDL6;結(jié)果為真,采用延遲跳轉(zhuǎn)返回LDI*AR4,R0 ;R0=*pOR0F0h,R0 ;R0=*p|0xF0STIR0,*AR4 ;*p=R0***BL6;結(jié)果為真時的真正跳轉(zhuǎn)發(fā)生在這里LDI*AR4,R0 ;R0=*p(AR4被分配給p)

7)使用寄存器避免沖突編譯器支持一項新的可選用的調(diào)用順序。它通過寄存器而非壓入堆棧的方法來避免沖突。這在程序調(diào)用時,可以明顯改善程序的性能。

8)條件指令在C語言中往往有條件語句,如:

a=conditionalexpr1:expr2或(condition)a=b這時編譯器使用條件指令來減少分支。7)使用寄存器避免沖突

9)循環(huán)體重復塊重復并不是用的越多越好,這要視具體情況而定。當編譯器發(fā)現(xiàn)循環(huán)次數(shù)與循環(huán)體長度都很小時,它將不使用循環(huán)結(jié)構(gòu),改為使用多次重復運行代碼段的循環(huán)體重復的方式。這樣可以避免分支或塊重復造成的跳轉(zhuǎn)或判斷開銷,提高運行效率。9)循環(huán)體重復6.3C語言編程基礎(chǔ)知識6.3.1數(shù)據(jù)類型所有整數(shù)類型(char、short、int、long以及對應(yīng)的無符號數(shù))都是相同的,即都是由32位的二進制數(shù)來表示的。有符號類型由基2的補碼表示;字符型類型是有符號類型,等同于整型;枚舉類型的對象用32位數(shù)來表示,在表達上與整型相似;6.3C語言編程基礎(chǔ)知識6.3.1數(shù)據(jù)類型所有的浮點型(float、double)都是相似的,在TMS320C3x/4x中都是由32位的單精度浮點格式表示的;

Longdouble型浮點格式在TMS320C3x/4x中是由40位的擴展精度格式表示的;數(shù)據(jù)類型的字長、表達方法、數(shù)據(jù)范圍列于下表6.2;一些值的范圍在頭文件limits.h作為標準宏利用,頭文件limits.h應(yīng)用在編譯器中。注:TMS320C3x/4x類型為32位所有的浮點型(float、double)都是相似的,在T表6.2數(shù)據(jù)格式表6.2數(shù)據(jù)格式長雙精度浮點數(shù)據(jù)類型不同于其他的浮點數(shù)據(jù)類型。長雙精度浮點數(shù)據(jù)的特性如下:

(1)長雙精度浮點數(shù)據(jù)類型不是用浮點和雙精度所用的單精度32位格式表示的,而是用40位擴展精度格式表示。

(2)長雙精度要求兩個存儲器字:第一個字保存高24位,第二個字保存低24位,操作的數(shù)據(jù)長度為40位,在裝載和保存該長雙精度浮點格式需要兩條指令。長雙精度浮點數(shù)據(jù)類型不同于其他的浮點數(shù)據(jù)類型。長雙精度浮

(3)長雙精度保存在一個浮點寄存器中,像短浮點和雙精度浮點一樣,在寄存器中傳輸參數(shù)。

(4)寄存器變量都不是40位值;因此長雙精度不能通過CALL保存為寄存器變量。在CALL之前保存在存儲器中,在需要時還可以重新裝載。

(5)在浮點數(shù)/雙精度浮點到長雙精度浮點轉(zhuǎn)換時,40位寄存器的低8位用0填滿。在長雙精度浮點到浮點/雙精度浮點轉(zhuǎn)換時,常用RND指令把此值取舍為最接近的單精度浮點數(shù)值。(3)長雙精度保存在一個浮點寄存器中,像短浮點和雙精度

(6)若加、減和負值(取反)指令用擴展精度浮點數(shù)作為輸入,可以用匯編指令實現(xiàn),如C3X乘法用函數(shù)MPY_LD,除法用函數(shù)DIV_LD實現(xiàn)。

(7)?40位的匯編函數(shù)鏈接到名為?.float40的自身的段中。(6)若加、減和負值(取反)指令用擴展精度浮點數(shù)作為輸6.3.2關(guān)鍵字

C編譯器中涉及的關(guān)鍵字主要包括C寄存器關(guān)鍵字和說明C編譯器如何訪問全局和靜態(tài)變量以及如何調(diào)用函數(shù)的near和far關(guān)鍵字。

1.C寄存器關(guān)鍵字

TMS320C3x/4x編譯器通過增加C寄存器關(guān)鍵字擴展C語言,從而使高級語言訪問寄存器。6.3.2關(guān)鍵字當用戶在目標文件中用C寄存器關(guān)鍵字時,編譯器就會把目標文件名稱與為C3x/C4x列出的標準控制寄存器的名稱作比較。如果名稱匹配,則編譯器就生成控制寄存器的參考代碼。如果名稱不匹配,則編譯器就報告出錯。有效的控制寄存器如表6.3所示。當用戶在目標文件中用C寄存器關(guān)鍵字時,編譯器就會把目標文表6.3有效的控制寄存器表6.3有效的控制寄存器

C寄存器關(guān)鍵字僅用在顯示文件中,不必在函數(shù)中作任何的聲明??蓱?yīng)用在整數(shù)或指針類型對象中,但不允許應(yīng)用在浮點或結(jié)構(gòu)型或邏輯對象中。

C寄存器關(guān)鍵字指明對象不能是變量。如果所用的控制寄存器是變量(即可通過外部控制來改變其值),那么這個對象也可以用變量關(guān)鍵字聲明。如果要用表6.3中的控制寄存器,用戶必須按照下面方式聲明:externcregistervolatileunsignedintregister;一旦聲明了寄存器,用戶就可以直接用這個寄存器的名稱。C寄存器關(guān)鍵字僅用在顯示文件中,不必在函數(shù)中作任何的聲例6.4定義和使用控制寄存器

externcreglsgervolatileunsignedintIE;

externcreglstervolatiltunsignedintIF;

externcreglsgervolatileunsignedintIOF;

externcreglstervolatiltunsignedintST;

unsignedmyfunc{unsignedintmask}

{

while{ST&maskintmask–0}/*Donothing;wait*/;

returnIOF;

}例6.4定義和使用控制寄存器

2.near和far關(guān)鍵字

C3x/C4x的C編譯器擴展了C語言功能,增加的near和far關(guān)鍵字是用來說明C編譯器是如何訪問全局和靜態(tài)變量以及如何調(diào)用函數(shù)的。在句法上,near和far關(guān)鍵字被看做存儲類變址數(shù),它們可以出現(xiàn)在保存類聲明和類型的之前、之后和中間。兩個保存類變址不可以在一個聲明中同時應(yīng)用,例如:

farstaticintx;

staticnearintx;

staticintfatx;

farintf∞();

staticfarintf∞();2.near和far關(guān)鍵字

1)?near和far數(shù)據(jù)對象全局和靜態(tài)數(shù)據(jù)對象可以通過下面兩種方式訪問:near關(guān)鍵字——編譯器對數(shù)據(jù)的訪問采取相對數(shù)據(jù)頁指針方式,如:stir0,@_var

far關(guān)鍵字——編譯器不能通過DP訪問數(shù)據(jù)。但是如果數(shù)據(jù)的量大于DP所允許的32K字時,就可以采用DP訪問,例如:

ldiu@cll,ar0stir0,*ar0這里cll是包含在.bss中的變量的地址。1)?near和far數(shù)據(jù)對象默認情況下,編譯器產(chǎn)生小的存儲模型代碼,這意味每個數(shù)據(jù)對象都被當作near關(guān)鍵字,除非它被聲明為far關(guān)鍵字。如果對象聲明為near關(guān)鍵字,一般的用相對于數(shù)據(jù)頁指針的偏移尋址。數(shù)據(jù)頁指針指向?.bss段的開始。如果-ml,-mb和-mf這些選項被用,則可改變默認的設(shè)定值。大存儲器模型代碼,意思是每個數(shù)據(jù)對象被當作far關(guān)鍵字來處理并生成相應(yīng)的代碼。如果用DATA_SECTION,對象就會被確認為far變量,并且不能更改。這樣就保證對不同數(shù)據(jù)頁中的變量進行存取。默認情況下,編譯器產(chǎn)生小的存儲模型代碼,這意味每個數(shù)據(jù)對

2)?near和far函數(shù)調(diào)用函數(shù)調(diào)用可采用以下兩種方式之一

near關(guān)鍵字——編譯器假定調(diào)用的目的操作數(shù)在所調(diào)用的224字節(jié)內(nèi),編譯器用PC相對尋址方式調(diào)用指令:

call_func

far關(guān)鍵字——用戶通知編譯器調(diào)用的不在調(diào)用的224字節(jié)之內(nèi),編譯器所用的調(diào)用指令為寄存器尋址模式:

ldiu@cll,ro

callu,ro這里cll常量在.bss中為函數(shù)的地址。2)?near和far函數(shù)調(diào)用6.3.3寄存器變量

TMS320C3x/4xC編譯器對寄存器變量的處理依靠用戶是否用優(yōu)化器來決定。用優(yōu)化器的編譯——編譯器忽略寄存器的任何聲明,在優(yōu)化時把所有的變量都當作寄存器變量來處理。不用優(yōu)化器的編譯——如果用戶用了寄存器關(guān)鍵字,建議把該變量分配到所選的寄存器中。6.3.3寄存器變量8個寄存器在每個函數(shù)中都用作寄存器變量?!ぜ拇嫫鱎4和R5保留為整數(shù)寄存器變量;·

寄存器R6和R7保留為浮點數(shù)寄存器變量;·四個寄存器AR4~AR7保留指針或整數(shù)變量。任何標量(整數(shù)、浮點數(shù)或指針)的對象都可以聲明為寄存器變量。寄存器標示符被忽略為任何類型的對象。8個寄存器在每個函數(shù)中都用作寄存器變量。寄存器保存類是有其意義的參數(shù),或是邏輯變量。如果應(yīng)用基于棧的調(diào)用約定,那么聲明作寄存器的參數(shù)正常地傳入到堆棧并通過函數(shù)入口移入到寄存器中。這有利于參數(shù)在函數(shù)中訪問該參數(shù)。如果參數(shù)不被聲明為寄存器,那么參數(shù)就會在函數(shù)中分配一定的邏輯空間并保存起來,作為函數(shù)開始執(zhí)行的地方。寄存器保存類是有其意義的參數(shù),或是邏輯變量。如果應(yīng)用基于6.3.4Pragma指令(預處理指令)

Pragma指令指示編譯器所對應(yīng)的處理器如何處理函數(shù)。TMS320C3x/C4xC編譯器支持下面的pragmas:

CODE_SECTION

DATA_SECTION

FUNC_CANNOT_INLINE

FUNC_EXT_CALLED6.3.4Pragma指令(預處理指令)

FUNC_IS_PURE

FUNC_IS_SYSTEM

FUNC_NEVER_RETURNS

FUNC_NO_GLOBAL_ASG

FUNC_NO_IND_ASG

INTERRUPT

這里所指的func和symbol必須在文件內(nèi),也就是說,用戶不能在函數(shù)體內(nèi)定義和聲明它們。即用戶必須確定該pragma在函數(shù)體外,并且必須聲明、定義所用到的func和symbol操作。如果用戶不遵循以下規(guī)則,則編譯器會發(fā)出警告。FUNC_IS_PURE

1)?CODE_SECTIONPragma此pragma為段名sectionname分配一個代碼空間,語法如下:#pragmaCODE_SECTION(symbol,"sectionname");該段在編譯器用?.sect匯編器指令聲明。如果段名的長度大于8個字符,用戶需要應(yīng)用COFF2聲時。如果用戶想把目標代碼與從.bss段分離出來的空間鏈接,則該pragma是有用的。1)?CODE_SECTIONPragma例6.5CODE_SECTION預處理的使用

(a)Csourcefile

#pragmaCODE_SECTION{fn,"my_sect"}

intfn(intx)

{

returnc;

}

(b)Assemblysourcefile

.sect"my_sect"

.global_fn例6.5CODE_SECTION預處理的使用

2)?DATA_SECTIONPragma此pragma為段名sectionname分配一個數(shù)據(jù)空間,語法如下:

#pragmaDATA_SECTION(symbol,"sectionname");如果用戶想把目標數(shù)據(jù)與從.bss段分離出來的空間鏈接,則該pragma是有用的。如果段名的長度大于8個字符,則用戶需要應(yīng)用COFF2。2)?DATA_SECTIONPragma例6.6DATA_SECTION預處理的使用。

(a)Csourcefile

#pragmaCODE_SECTION{fn,"my_sect"}

charbufferA[512];

charbufferB[512];

(b)Assemblysourcefile

.global_bufferA

.bss_bufferA,512

.blobal_bufferB

_bufferB: .usect"my_sect",512,1例6.6DATA_SECTION預處理的使用。

3)?FUNC_CANNOT_INLINEPragma該pragma指示編譯器不能擴展有名稱的函數(shù)。任何用該pragma命名的函數(shù)優(yōu)于用戶以任何其他方式(例如用內(nèi)部的關(guān)鍵字)指出inlining。該pragma必須出現(xiàn)在聲明或用戶參考函數(shù)內(nèi)。此pragma的語法如下:

#pragmaFUNC_CANNOT_INLINE(func);自變量func是C函數(shù)的名稱,此函數(shù)不能是內(nèi)嵌的。3)?FUNC_CANNOT_INLINEPragm

4)?FUNC_EXT_CALLEDPragma當用戶用-pm選項時,編譯器用程序等級最優(yōu)化。當用戶用這種最優(yōu)化的類型時,編譯器將通過主函數(shù)直接或間接的去掉沒調(diào)用的函數(shù)。這樣,用戶可以通過手控代碼調(diào)用而不是用主函數(shù)。該pragma指明了優(yōu)化器可以控制C函數(shù),并調(diào)用這些C函數(shù)或其他的函數(shù)。這些函數(shù)就作為C語言的入口地址。該pragma的定義必須在聲明或用戶想引用的函數(shù)之前。語法如下:

#pragmaFUNC_EXT_CALLED(func);

變量func是用戶所定義的C函數(shù)的名稱。4)?FUNC_EXT_CALLEDPragma

5)?FUNC_IS_PUREPragma該pragma指明了優(yōu)化器對有名稱函數(shù)的影響。編譯器按照下面情況處理這種影響:

·如果函數(shù)的值不需要,則刪除調(diào)用的函數(shù);

·刪除相同的函數(shù)。該pragma的定義必須在聲明或用到的函數(shù)之前,語法如下:

#pragmaFUNC_IS_PURE(func);變量func是C函數(shù)的名稱。5)?FUNC_IS_PUREPragma

6)?FUNC_IS_SYSTEMPragma

該pragma指明優(yōu)化器可優(yōu)化有名稱的函數(shù)的行為,此行為是針對有名稱函數(shù)的ANSI標準定義的。該pragma的定義必須出現(xiàn)在聲明或所用到的函數(shù)之前,語法如下:

#pragmaFUNC_IS_SYSTEM(func);變量func是C函數(shù)的名稱,此函數(shù)被當作ANSI標準函數(shù)來處理。6)?FUNC_IS_SYSTEMPragma

7)?FUNC_NEVER_RETURNSPragma該pragma指明優(yōu)化器優(yōu)化從不返回到所調(diào)用函數(shù)的位置。該pragma的定義必須出現(xiàn)在聲明或所用到的函數(shù)之前,語法如下:

#pragmaFUNC_NEVER_RETURNS(func);變量func是不可返回調(diào)用C函數(shù)的名稱。7)?FUNC_NEVER_RETURNSPragm

8)?FUNC_NO_GLOBAL_ASGPragma該pragma指明優(yōu)化器優(yōu)化沒有配置有名稱的全局變量和不包含asm語句的函數(shù)。該pragma的定義必須出現(xiàn)在聲明或所用到的函數(shù)之前,語法如下:

#pragmaFUNC_NO_GLOBAL_ASG(func);變量func是沒有配置的C函數(shù)的名稱。8)?FUNC_NO_GLOBAL_ASGPragm

9)?FUNC_NO_IND_ASGPragma該pragma指明優(yōu)化器優(yōu)化通過指針沒有配置和不包含asm語句的函數(shù)。該pragma的定義必須出現(xiàn)在聲明或所用到的函數(shù)之前,語法如下:

#pragmaFUNC_NO_IND_ASG(func);變量func是沒有配置的C函數(shù)的名稱。9)?FUNC_NO_IND_ASGPragma

10)?INTERRUPTPragma該pragma可使用戶用C代碼直接處理中斷。變量func是函數(shù)的名稱。語法如下:

#pragmaINTERRUPT(func);除了c_int00需要保留為C程序復位中斷名稱外,其他中斷名稱都不需要遵循賦名的規(guī)則。10)?INTERRUPTPragma6.3.5asm語句

TMS320C3x/C4xC編譯器允許用戶嵌套TMS320C3x/C4x匯編語言指令。Asm語句在語法構(gòu)成上與調(diào)用有名稱的asm一樣,用一個常量串聲明:

asm("assemblertext");編譯器直接把聲明串拷貝到用戶輸出文件?.assemblertext中,并且數(shù)據(jù)格式必須是雙精度的。所有的字符串輸出代碼保留它們的初始值。例如,用戶可以插入一個.string命令,格式如下:

asm("STR:.string\"abc"\");6.3.5asm語句所插入的代碼必須是合法的匯編語言語句。像所有的匯編語言語句一樣,這一行必須以標識符(label)開始,接下來是空格(blank)、標號(tab),或注釋(星號或分號開始)。編譯器不檢查字符串,如果有錯,將由匯編器檢查。若需要更多的信息,請參考TMS320C3x/C4x匯編語言工具用戶手冊。這里寫asm語句不必嚴格按照正常的C語言語法:它們將作為語句或聲明甚至在塊外出現(xiàn)。在編譯模塊的開始處插入即可。所插入的代碼必須是合法的匯編語言語句。像所有的匯編語言注意:需要特別小心用asm語句時不要破壞C環(huán)境。編譯器不檢查插入的指令。若插入跳轉(zhuǎn)和標識符到C代碼中,則可能引起不可預料的結(jié)果;若用到改變段或其他影響匯編環(huán)境的指令也可能引起麻煩。在用優(yōu)化器對匯編語句進行優(yōu)化時要特別小心。盡管優(yōu)化器不能刪除asm指令,但它可以重新安排asm指令附近的代碼順序,這樣就可能引起不可預料的結(jié)果。asm命令可使用戶訪問硬件,而C語言則不可以。注意:需要特別小心用asm語句時不要破壞C環(huán)境。編譯器不6.3.6初始化靜態(tài)和全局變量

ANSIC標準指明在沒有初始化的靜態(tài)和全局變量時,必須在程序執(zhí)行前明確地初始化(賦初始化值0)。在程序被裝載時,初始化的工作就已經(jīng)完成。因為裝載過程依靠系統(tǒng)的環(huán)境,TMS320C3x/C4xC編譯器本身不能預先初始化變量。如果用戶導入的程序不是預先初始化的變量,用戶必須用連接器在目標文件中初始化變量(賦初始值0)。在連接器命令文件中,.bss段用0填充,如下:6.3.6初始化靜態(tài)和全局變量

SECTIONS

{

...

.bss:{}=0x00;

...

}由于鏈接器向輸出COFF文件中寫入了一個賦0的.bss段,這種方法可能使輸出文件的尺寸急劇增加。用常量可限定類初始化靜態(tài)和全局變量。限定類的靜態(tài)常量和全局變量初始化不同于其他類型的靜態(tài)常量和全局變量。沒有明確初始化的靜態(tài)常量和全局變量可能會在初始化前被賦0。SECTIONS例如:constintzero;/*maynotbeinitializedtozero*/

初始化為全局變量的所有常量被放置在.cinit段中。在表達式中,初始化為局部變量的所有常量或者放置在CONST表或者用立即尋址裝載。限定類常量的初始化值不被放在.const段,因為這個值必須用直接尋址對其訪問。利用小的存儲器模塊,如果該值被放在.const段,則要求.bss和.const段必須在同一頁中。CONST表和.const段是不一樣的。CONST表包括如下內(nèi)容:例如:整數(shù)常量表達式的寬度多于16位;浮點數(shù)常量表達式為指數(shù)多于4位或尾數(shù)多于11位;整數(shù)局部變量初始化值多于16位;浮點數(shù)局部變量初始化值為指數(shù)多于4位或尾數(shù)多于11位;全局變量的地址;字符串常量的地址。.const段內(nèi)容如下:轉(zhuǎn)變聲明表;不許初始化全局變量的字符串常量;用作big模型的CONST表。整數(shù)常量表達式的寬度多于16位;6.4基于C語言的DSP芯片開發(fā)的運行環(huán)境6.4.1存儲器模式

C編譯器把存儲器作為單個線性塊處理,這個線性塊被分成代碼和數(shù)據(jù)子塊。C程序生成的每個代碼和數(shù)據(jù)塊都被放置在連續(xù)的存儲器空間中。編譯器假定32位的目標存儲器地址空間都是可利用的。6.4基于C語言的DSP芯片開發(fā)的運行環(huán)境6.4.1特別需要注意的是由鏈接器定義的存儲器映射。鏈接器定義的存儲器映射把代碼和數(shù)據(jù)分配到目標存儲器中。如果編譯器不清楚存儲器映射的類型,則所有位置都不能裝載代碼或數(shù)據(jù),或任何位置都被保留為I/O段。編譯器生成的可重置代碼允許鏈接器把代碼和數(shù)據(jù)分配到合適的存儲器空間中。例如,用戶可以用鏈接器分配全局變量到內(nèi)部快速RAM中或分配可執(zhí)行代碼到內(nèi)部ROM中。特別需要注意的是由鏈接器定義的存儲器映射。鏈接器定義的存

1.C編譯器生成的段

C編譯器對C語言程序編譯后可產(chǎn)生6個重定位的代碼和數(shù)據(jù)塊,這些塊也就是所謂的段,它們可以用不同的方式分配至存儲器中,以符合不同系統(tǒng)配置的需要。這6個段可以分為兩種類型,一種是已初始化段,另一種是未初始化段。已初始化的段主要包含數(shù)據(jù)表和可執(zhí)行代碼。C編譯器有3個已初始化的段:.text、

.cinit和?.const。

.text段包含所有可執(zhí)行代碼以及浮點數(shù)常量;

.cinit段包含初始化變量和常量表;

.const段包含浮點數(shù)常量和swich表。1.C編譯器生成的段未初始化段用于保留存儲器空間,程序可以用這些空間在運行時創(chuàng)建和存儲變量。編譯器支持3個未初始化的段:.bss,.stack和.sysmem。

.bss段為全局和靜態(tài)變量保留空間,在小模型中,.bss段也為常量表保留空間。在程序運行時,C初始化程序從.cinit段中拷貝數(shù)據(jù)(可能在ROM中)并把它保存在.bss段中。

.stack段為系統(tǒng)堆棧分配空間。這時存儲器用作向函數(shù)傳遞變量以及分配局部變量。

.system段為存儲器組合或存儲器組,為動態(tài)存儲器函數(shù)malloc、calloc和realloc分配存儲器空間。當然,若C程序沒有用到這些函數(shù),編譯器就不創(chuàng)建.system段。未初始化段用于保留存儲器空間,程序可以用這些空間在運行時鏈接器從不同的模式下取出的單個段并且把名字相同的段合并在一起生成輸出段。需要清楚的是匯編器可產(chǎn)生3個默認的段((.text、.bss和.data);然而C編譯器不用.data段。

C語言程序是由編譯器的輸出段和匯編器?.data段組成的。連接器從不同的模塊取出單個的段并且把名字相同的段合并在一起生成輸出段。用戶可以把這些輸出段放在所需要的任何地址處以滿足系統(tǒng)的需要。.text、.cinit、.const和.data段在ROM或RAM中連在一起;.bss、.stack和.system段在RAM中連在一起。需要注意的是,.bss和.const段必須被分配在同一64K的數(shù)據(jù)頁內(nèi)。鏈接器從不同的模式下取出的單個段并且把名字相同的段合并在

2.C系統(tǒng)堆棧

C編譯器利用TMS320C3x/C4x內(nèi)置的堆棧機制實現(xiàn)如下功能:

(1)保護函數(shù)返回的地址;

(2)分配局部變量;

(3)傳遞函數(shù)變量;

(4)保存臨時結(jié)果;

(5)保護寄存器;

(6)保護處理器的狀態(tài)。2.C系統(tǒng)堆棧堆棧操作是從低地址向高地址增加的。編譯器利用兩個輔助寄存器來管理堆棧:SP:堆棧指針(SP),指向當前堆棧的棧頂;

AR3:幀指針,指向當前局部幀的開始,每一個函數(shù)調(diào)用時都要在棧頂建立一個新的局部幀,用來保存局部和臨時的變量。

C運行環(huán)境在調(diào)用C函數(shù)時自動管理這些寄存器。如果用戶在匯編語言使用這些堆棧,一定要確保正確的使用它們。堆棧操作是從低地址向高地址增加的。編譯器利用兩個輔助寄存堆棧尺寸可由鏈接器利用全局符號__STACK_SIZE來設(shè)定,對其賦值即定義堆棧的大小。默認的堆棧大小為1K(400h)字,它適合于片內(nèi)的任何一RAM塊。用戶也可在鏈接器的命令行中利用-stack選項和在選項后用常量指明堆棧的大小,以改變堆棧的大小。在系統(tǒng)初始化后,SP所指定的地址為堆棧的的底部。這個地址為.stack段中的首地址。由于堆棧的位置是由.stack段分配所決定的,而實際的位置是在連接階段確定的。如果用戶配置的堆棧在存儲器的最后的段(高地址),則堆??稍诖鎯ζ骺臻g中無限增長。堆棧尺寸可由鏈接器利用全局符號__STACK_SIZE來特別注意的是,由于C編譯器不提供檢查堆棧溢出的方法,因此必須保證有足夠的空間用于堆棧;否則將發(fā)生溢出現(xiàn)象而破壞程序的運行環(huán)境,從而導致程序的癱瘓。所以在編寫DSP程序和存儲器資源分配時,要注意防止堆棧溢出的發(fā)生。特別注意的是,由于C編譯器不提供檢查堆棧溢出的方法,因此

3.動態(tài)存儲器分配由編譯器提供的運行支持庫包含了幾個允許用戶在運行時動態(tài)分配存儲器函數(shù)(例如malloc、calloc和realloc)。動態(tài)分配并不是C語言本身的標準,而是由標準的運行支持函數(shù)提供的。為全局pool或heap分配的存儲器定義在?.system段中。.system段的大小在鏈接時用-heap選項來設(shè)定,設(shè)置的方法是在-heap選項后面加一個常量來指定。同樣,鏈接器也創(chuàng)建一個全局符號__SYSMEM_SIZE,它的值為heap中的字數(shù)目,默認大小為1K字。3.動態(tài)存儲器分配動態(tài)分配目標不是直接尋址(經(jīng)常用指針訪問),并且存儲器區(qū)在一個獨立的塊中,因此動態(tài)存儲器區(qū)甚至在小的存儲器模式下也有無限的尺寸。所以,即使在程序中申請了大的數(shù)據(jù)目標,也可以使用效率更高的小存儲器模式。為了在?.bss段中保留空間,用戶可用heap分配大的數(shù)組,以代替聲明為全局或靜態(tài)的。例如如下的聲明:

structbigtable[10000];用指針和調(diào)用函數(shù)來替代:

structbig*table

table=(structbig*)malloc(10000*sizeof(structbig));動態(tài)分配目標不是直接尋址(經(jīng)常用指針訪問),并且存儲器區(qū)

4.存儲器大小模式編譯器支持兩個存儲器模式:大存儲器模式和小存儲器模式。這兩種模式影響.bss如何分配存儲器空間。兩種模型下的.text和/或?.cinit段的尺寸都不受限制。但兩種模型下的單個函數(shù)限制在32K字的代碼或更少內(nèi),這允許編譯器在整個函數(shù)范圍內(nèi)利用相對條件跳轉(zhuǎn)。4.存儲器大小模式

(1)小存儲器模式:編譯器默認的存儲器模式。在這種模式下,要求整個.bss段能匹配一個64?KB字的存儲器在數(shù)據(jù)頁內(nèi)。這意味著在程序中的靜態(tài)和全局數(shù)據(jù)的空間必須小于64?K字,并且.bss也不能超過64?K字地址范圍。編譯器在運行初始化時,將數(shù)據(jù)頁指針寄存器指向.bss的開始。隨后,編譯器就可以用直接尋址(@)訪問.bss中所有的目標(如全局變量、靜態(tài)變量和常數(shù)表),而不用修改DP寄存器。(1)小存儲器模式:編譯器默認的存儲器模式。在這種模式

(2)大存儲器模式:大模式和小模式的區(qū)別是它不限制.bss塊的大小,因此對于全局和靜態(tài)變量來說,可用空間是無限的。然而當編譯器訪問保存在.bss中的任何全局或靜態(tài)變量時,編譯器首先保證DP準確的指向目標所在的存儲頁。為了做到這一點,編譯器在每次訪問靜態(tài)或全局數(shù)據(jù)時,必須用LDP或LDPK指令設(shè)置DP寄存器。由于加了這條指令,不僅增加了一個指令字,而且可能引入3個指令周期或2個指令周期。例如,下面是C編譯器生成的匯編語言,它是使用LPD指令在訪問全局變量x之前設(shè)置DP寄存器的例子:(2)大存儲器模式:大模式和小模式的區(qū)別是它不限制.b***_xisaglobalvariable***

LDP_x;1extraword,1cycle

LDI@_x,R0;3cycles(2pipelinedelays)為了應(yīng)用大存儲器模式,-mb選項調(diào)用編譯器。兩種模式下都不限制.text和.cinit段的大小,單個函數(shù)的大小限制在32K字之內(nèi)。***_xisaglobalvariable

5.RAM和ROM模型

C編譯器產(chǎn)生的代碼適合于基于ROM系統(tǒng)中的應(yīng)用。在這樣一個系統(tǒng)中,.cinit段中的初始化表保存在ROM中。在系統(tǒng)初始化期間,C初始化程序把這些表中的數(shù)據(jù)從ROM拷貝到?.bss中。5.RAM和ROM模型程序是直接從目標文件裝載到存儲器中,然后運行該程序的。這樣做,避免了.cinit段占用存儲器中的空間。用戶定義的初始化程序直接從目標文件讀取初始化表(而不是從ROM中)并且在裝載時間(而非運行時間)直接執(zhí)行初始化。用戶可通過應(yīng)用-cr鏈接器選項把部分內(nèi)容送到鏈接器。程序是直接從目標文件裝載到存儲器中,然后運行該程序的。這6.4.2目標請求本節(jié)說明不同的數(shù)據(jù)目標如何配置大小、排列和訪問。

1.數(shù)據(jù)類型保存所有的基本類型都是32位寬度并且保存在存儲器中。除了位元被合成字,其他的都不能被合并。位元以聲明的順序從低位到高位配置。并不是所有的對象有排列請求的類型,任何類型被保存32位字寬。結(jié)構(gòu)或數(shù)組類的單元目標被單個保存,但單元不被排列為結(jié)構(gòu)或數(shù)據(jù)(除非單元是位元)。6.4.2目標請求整數(shù)類型的char,shortint和long與無符號的是一樣的。列舉類型的目標作為32位的字對待。浮點數(shù)和雙精度類型與TMS320C3x/4x指明的32位浮點數(shù)格式相同。長雙精度類型為40位整數(shù)類型的char,shortint和long與無符

2.長立即數(shù)

TMS320C3x/C4x指令沒有立即操作數(shù)長度超過16位的。編譯器有時需要用常量長度大于16位。有符號整數(shù)常量有效的非符號位多于15位,無符號整數(shù)的有效位多于16位,或浮點數(shù)常量的尾數(shù)有效非符號位多于11位。

3.尋址全局變量編譯器生成的全局和靜態(tài)符號的地址為變址寄存器或操作指針。因為這些地址為32位寬度,而立即操作數(shù)限制在16位,所以這些地址當作長常量處理。2.長立即數(shù)

4.字符串常量在C語言中,字符串常量以下面兩種方式應(yīng)用:

(1)初始化字符數(shù)組,例如:chars[]="abc";當字符串被初始化時,它常常被當作已初始化數(shù)組處理,每個字符都必須被初始化。

(2)字符串用在表達式中,例如:strcpy(s,,"abc");

當字符串用在表達式中時,字符串本身用.byte匯編器指令在.const段中定義,與唯一的標號一起指向字符串。在下面的例子中,標號SL5指向上面例子的字符串:

.const

SL5.byte“abc”,04.字符串常量字符串標號有SLn,其中n為編譯器分配的一個標號,這些標號從0開始逐漸加1,在源模塊中所有的字符串都在編譯的匯編語言模塊的結(jié)束處定義。標號SLn代表字符串常量的地址。編譯器用這個標號在表達式中引用該字符串。像所有的靜態(tài)目標一樣,為了能對這個地址訪問,它必須保存在常量表中。因此處理在.const段中保存字符串本身外,編譯器還用下面的指令保存常量表中字符串地址:.wordSLn。字符串標號有SLn,其中n為編譯器分配的一個標號,這些標如果同樣的字符串在源模塊中被多次引用,則該字符串將不在存儲器中復制。一個確定的字符串常量所有應(yīng)用都必須先對字符串單個定義。因為字符串保存在.const段(可能在ROM)并被分享,因此對于程序來說,修改字符串常量是不實際的。下面的例子是一個不正確的使用字符串的例子:

char*a="abc"

a[1]='x' ;/*Incorrect!*/如果同樣的字符串在源模塊中被多次引用,則該字符串將不在存

5.常量表常量表包含了所有編譯器訪問的所有的目標,但是字長太寬時不能用作立即操作數(shù)。這樣的目標如下:

(1)整數(shù)常量寬度多于16位;

(2)浮點常量指數(shù)多于4位或尾數(shù)位數(shù)多于11位;

(3)整數(shù)局部變量初始化長度多于16位;

(4)浮點數(shù)局部變量初始化指數(shù)多于4位或尾數(shù)多于11位;

(5)全局變量的地址;

(6)字符串常量的地址。5.常量表常量表僅僅是一個存儲器塊包含了所有的目標。編譯器建立的常量表通過應(yīng)用.word和.float匯編指令在源模塊的結(jié)束處。表中的每一個入口占用一個字。CONST標號為表的起始地址,例如:

CONST: .word011223344h;32bitconstant

.float3.14159265;floating–point

.word_globvar;addressofglobal

.wordSL23;addressofstring在表中的目標用直接尋址訪問,如:

LDI@const+offset,R0常量表僅僅是一個存儲器塊包含了所有的目標。編譯器建立的常在這個例子中,偏移offset被放入到所需目標的常量表中。它與字符串常量一起,用在源模塊中明確的常量。在常量表中它們分享一個入口。在大存儲器模式中,常量表在.const段中建立(不能在RAM中拷貝)。編譯器必須保證DP寄存器在訪問表中的目標之前(與訪問全局變量完全一樣)正確的裝載。這就要求在對常量表的每一次訪問時都需要LDP指令。在這個例子中,偏移offset被放入到所需目標的常量表中然而,在小存儲器模式中,為了避免正裝載的DP被覆蓋,故要求直接尋址的所有全局變量以及常量表目標被保存在同一存儲器頁中。當然,全局變量必須保存在RAM中。對于ROM中的代碼,常量表必須在ROM中,為了在同一頁取出它們,引導程序必須從臨時保存在ROM的常量表拷貝到RAM中全局頁中。編譯器通過向?.cinit段中的常量表放置數(shù)據(jù)來完成該項工作并且在表?.bss中分配空間。這樣常量表就通過自動操作自動地在RAM中建立。然而,在小存儲器模式中,為了避免正裝載的DP被覆蓋,故要特別需要注意是,小存儲器模式對全局數(shù)據(jù)頁的總尺寸限制在為64K字以內(nèi)。正如所有的初始化一樣,用戶需要避免.cinit段要求的存儲器的額外應(yīng)用通過-cr鏈接器選項和智能的引導程序直接實現(xiàn)初始化。特別需要注意是,小存儲器模式對全局數(shù)據(jù)頁的總尺寸限制在為6.4.3寄存器規(guī)則在C編譯環(huán)境中,對寄存器分配和操作有嚴格的規(guī)則。如果用戶要求匯編語言程序與C程序接口,掌握這些寄存器規(guī)則是很重要的。寄存器規(guī)則明確了編譯器如何使用寄存器以及在函數(shù)調(diào)用過程中如何保護寄存器。有兩種寄存器變量:在調(diào)用時得到保護和在入口時得到保護。這兩種方式的不同在于,調(diào)用程序時保護的方法不一樣。調(diào)用函數(shù)時,被調(diào)用函數(shù)的功能是保護某些寄存器,這些寄存器就不必由調(diào)用者保護。如果調(diào)用者需要使用沒有保護的寄存器,則調(diào)用者在調(diào)用函數(shù)之前必須予以保護。6.4.3寄存器規(guī)則需要注意的是,編譯器使用寄存器的方式對是否使用優(yōu)化選項(-o)是不同的。對優(yōu)化編譯來說,需用額外的寄存器作為寄存器變量以提高程序的運行效率。但是函數(shù)調(diào)用時保護寄存器的規(guī)則是一樣的。表6.4列出了編譯器如何應(yīng)用寄存器并指明了哪些寄存器在函數(shù)調(diào)用時得到保護。需要注意的是,編譯器使用寄存器的方式對是否使用優(yōu)化選項(表6.4寄存器使用和保護規(guī)則寄存器未優(yōu)化時的使用優(yōu)化時的使用調(diào)用時的保護情況R0整數(shù)和FP表達式標量返回值整數(shù)和FP表達式標量返回值不保護R1整數(shù)和FP表達式整數(shù)和FP表達式不保護R2~R3整數(shù)和FP表達式整數(shù)和FP寄存器變量不保護R4~R5整數(shù)寄存器變量整數(shù)和FP寄存器變量保護整數(shù)部分R6~R7FP寄存器變量整數(shù)和FP寄存器變量整數(shù)寄存器變量保護浮點數(shù)部分AR0~AR1指針表達式指針表達式不保護AR2指針表達式整數(shù)和指針寄存器變量不保護AR3幀指針(FP)幀指針(FP)保護AR4~AR7指針寄存器變量指針寄存器變量保護IR0擴展的幀偏移量擴展的幀偏移量不保護IR1擴展的幀偏移量整數(shù)寄存器變量不保護BK不使用整數(shù)寄存器變量不保護RS、RC、RE塊(結(jié)構(gòu))拷貝塊結(jié)構(gòu)拷貝,塊重復循環(huán),整數(shù)寄存器變量不保護SP堆棧指針堆棧指針保護DP訪問全局變量(僅大模式)訪問全局變量(僅大模式)小模式保護大模式不保護表6.4寄存器使用和保護規(guī)則寄存器未優(yōu)化時的使用優(yōu)化

1.寄存器變量寄存器變量是定義在寄存器而不是在存儲器中的局部變量或編譯器臨存值。在寄存器中保存局部變量可以加快訪問的速度,從而提高編譯代碼的執(zhí)行效率。有8個寄存器用于存儲寄存器變量,如表6.5所示。1.寄存器變量表6.5用于寄存器變量的寄存器表6.5用于寄存器變量的寄存器上述寄存器在函數(shù)調(diào)用時得以保護。當函數(shù)使用寄存器變量時,必須在在每次使用時保護寄存器的內(nèi)容,然后在函數(shù)返回時予以恢復保存的內(nèi)容。這樣就保證了被調(diào)用函數(shù)不破壞調(diào)用者的寄存器變量。當用戶不用優(yōu)化器時,用戶用寄存器關(guān)鍵字分配寄存器變量。如果寄存器中的值在調(diào)用時需要保護,那么就需要代碼生成器按照表6.4列出的分配寄存器變量。如果函數(shù)聲明的寄存器變量多于所能用的,那么多余變量被處理為自動變量并且被保存在存儲器的局部幀中。上述寄存器在函數(shù)調(diào)用時得以保護。當函數(shù)使用寄存器變量時,當用戶用優(yōu)化器時,編譯器則忽略寄存器關(guān)鍵字,并且把所有的變量當作寄存器變量處理。編譯器分配盡可能多的變量給寄存器,這基于變量維持的時間以及應(yīng)用變量的時間。優(yōu)化器使用的額外寄存器如表6.6所示。表6.6優(yōu)化器使用的額外寄存器當用戶用優(yōu)化器時,編譯器則忽略寄存器關(guān)鍵字,并且把所有的一般地,未列在表6.5中的寄存器不能在函數(shù)調(diào)用時得到保護,因此它們僅用作變量,該變量在任何調(diào)用時都不覆蓋。然而,如果-pm殼選項被用來產(chǎn)生一個匯編文件,編譯器就更加準確地決定寄存器的用途并且可以安全地使用在表6.4中列出的寄存器中。一般地,未列在表6.5中的寄存器不能在函數(shù)調(diào)用時得到保護

2.表達式寄存器編譯器可將那些不被用作存儲變量的寄存器用來存儲計算式的中間結(jié)果。編譯器可跟蹤每個寄存器當前的內(nèi)容,并且以保護寄存器內(nèi)容的方式盡可能地將寄存器分配給表達式。這使得編譯器能夠重復使用寄存器數(shù)據(jù),充分利用TMS320C3x/C4x的高效的寄存器尋址模式,從而可避免對變量和常量不必要的訪問。2.表達式寄存器表達寄存器中的內(nèi)容在函數(shù)調(diào)用時不被保護。當函數(shù)調(diào)用時,被用作保存臨時數(shù)據(jù)的任何寄存器在函數(shù)調(diào)用前被保存為局部幀。這樣就避免了被調(diào)用函數(shù)必須得到保護和重復使用表達式寄存器。如果編譯器需要另外一個寄存器保存計算表達式,則正被用作保存臨時數(shù)據(jù)的寄存器被保存為局部幀并用作分析表達式。表達寄存器中的內(nèi)容在函數(shù)調(diào)用時不被保護。當函數(shù)調(diào)用時,被

3.函數(shù)返回值一般地,當函數(shù)返回任何類型的數(shù)據(jù)(整數(shù)、指針或浮點數(shù))時,函數(shù)返回的值都存放在R0。然而,在寄存器變量調(diào)用規(guī)則中,指針從AR0中返回。

4.堆棧和幀指針

TMS320C3x/C4xC編譯器采用傳統(tǒng)的機制來分配局部變量(非寄存器變量)并把參數(shù)傳遞給函數(shù)。當函數(shù)要求局部保存時,函數(shù)就會在堆棧中產(chǎn)生它自己的工作區(qū)(即局部幀)。局部幀在函數(shù)調(diào)用時建立,在函數(shù)返回時撤銷并重新分配。3.函數(shù)返回值堆棧指針(SP)和幀指針(FP)這兩個寄存器用于管理堆棧和局部幀。SP是堆棧管理的寄存器,編譯器使用SP的傳統(tǒng)方法為:隨著高地址,堆棧增加并且堆棧指針指向堆棧的頂部。寄存器AR3定義為幀指針(FP)。FP對當前的函數(shù)來說指向局部幀起始或底部。所有在局部幀保存的所有數(shù)據(jù)用FP間接尋址。

SP和FP在函數(shù)調(diào)用時必須得到保護。函數(shù)調(diào)用自動保護SP是因為在調(diào)用函數(shù)時被壓入堆棧,從而在返回時彈出堆棧。堆棧指針(SP)和幀指針(FP)這兩個寄存器用于管理堆棧

5.其它寄存器除了上述寄存器外,其他寄存器具有特殊的功能。數(shù)據(jù)頁指針(DP):用來訪問全局和靜態(tài)變量。在小存儲模式下,DP在程序開始運行時設(shè)置并且設(shè)置后從不改變。DP在小模式下可通過匯編語言修改,此時必須給予保護。5.其它寄存器索引寄存器(IR0和IR1):用于數(shù)組下標及偏移量超過8位時的間接尋址。另外,這兩個寄存器在不用作其它目的時,優(yōu)化器把其用作通用的整數(shù)型寄存器變量。在函數(shù)調(diào)用時都不被保護。

BK寄存器:僅被優(yōu)化器用作整數(shù)寄存器變量,其值在函數(shù)調(diào)用時不被保護。塊重復寄存器(RC,RE和RS):在分配大于5個字的結(jié)構(gòu)時,編譯器用以產(chǎn)生有效的塊重復操作。這些寄存器如果不被用作塊重復操作時將被用作整數(shù)寄存器變量。重復寄存器值在函數(shù)調(diào)用時不被保護;因此RPTB和RPTS指令不能在循環(huán)結(jié)構(gòu)內(nèi)部。索引寄存器(IR0和IR1):用于數(shù)組下標及偏移量超過86.4.4函數(shù)結(jié)構(gòu)和調(diào)用規(guī)則

C編譯器對函數(shù)調(diào)用有一系列嚴格的規(guī)則。除了特殊的運行支持函數(shù)外,任何函數(shù)被C函數(shù)調(diào)用或調(diào)用C函數(shù)的匯編語言時均必須遵守這個規(guī)則。否則可能破壞C運行環(huán)境,造成程序失敗。6.4.4函數(shù)結(jié)構(gòu)和調(diào)用規(guī)則典型的函數(shù)調(diào)用的例子如圖6.1所示。在這個例子中,表示出了函數(shù)中參數(shù)傳遞及函數(shù)應(yīng)用局部變量的情況。在調(diào)用函數(shù)之前的堆棧SP指向最后保存的寄存器,F(xiàn)P指向前一個FP。壓入自變量堆棧顯示的是在執(zhí)行已經(jīng)調(diào)用函數(shù)的第一匯編指令之前的堆棧。局部幀堆棧顯示的為所有幀分配后的堆棧。此堆棧中,SP指向最后保存的寄存器。這個例子說明了已調(diào)用函數(shù)的局部幀的分配情況。函數(shù)沒有參數(shù)傳遞給堆棧以及沒有局部變量分配給局部幀。如果用戶用寄存器參數(shù)模式,則某些變量或全部變量將通過寄存器傳遞而不是用堆棧傳遞。典型的函數(shù)調(diào)用的例子如圖6.1所示。在這個例子中,表示出

1.采用標準運行模式的函數(shù)調(diào)用一般地,采用標準運行模式進行函數(shù)調(diào)用時,需要執(zhí)行下面一系列工作:

(1)調(diào)用程序?qū)?shù)壓入堆棧。壓入時按照反序進行,即最右邊的參數(shù)被首先壓入,最左邊參數(shù)被最后壓入。因此,當函數(shù)調(diào)用時,把最右邊的參數(shù)放入堆棧的頂端。

(2)調(diào)用程序調(diào)用函數(shù)。

(3)當被調(diào)用函數(shù)執(zhí)行結(jié)束時,調(diào)用程序用下面指令將參數(shù)彈出堆棧:SUBIn,SP其中,n是為壓入堆棧的參數(shù)的序號。1.采用標準運行模式的函數(shù)調(diào)用圖6.1在函數(shù)調(diào)用期間的堆棧的應(yīng)用圖6.1在函數(shù)調(diào)用期間的堆棧的應(yīng)用

2.采用寄存器參數(shù)運行模式的函數(shù)調(diào)用一般地,采用寄存器參數(shù)運行模式進行函數(shù)調(diào)用時,需要進行下面一系列的工作:

(1)有6個寄存器用來傳遞參數(shù)。它們是AR2、R2、R3、RC、RS和RE。按照下面用法傳遞參數(shù):①前2個浮點參數(shù)(float、double、longdouble)用R2和R3傳遞。2.采用寄存器參數(shù)運行模式的函數(shù)調(diào)用②整數(shù)或指針變量用上面列出的其它寄存器傳遞,順序如6個寄存器列出的順序。注意structuresandunions作為整型自變量通過地址傳遞。③所有沒有分配給寄存器的參數(shù),或者由于類型不匹配或所有寄存器已經(jīng)用完,按照反序壓入堆棧。第7個寄存器AR0通過地址返回到structuresandunions。下面列出幾個函數(shù)原型及其寄存器的參數(shù)情況。②整數(shù)或指針變量用上面列出的其它寄存器傳遞,順序如6個例6.7寄存器參數(shù)規(guī)則。

intf1(int*a,intb,intc); /*函數(shù)調(diào)用*/AR2 R2R3用來放參數(shù)的寄存器

intf2(inta,floatb,int*c,structAd,floate,intf);

AR2 R2RCRSR3RE

intf3(inta,int*b,floatc,intd,floate);

R2 AR2R3RCSTACKintf4(structxa,intb,intc,intd,inte,intf,intg,inth);

AR2 R2R3RCRSRESTACKSTACK例6.7寄存器參數(shù)規(guī)則。當一個函數(shù)在說明中用省略號表明參數(shù)數(shù)目可變時,上述規(guī)則稍作變化。最后一個明確說明的參數(shù)用堆棧傳遞,這樣它的堆棧地址可用作訪問沒有說明的參數(shù)的參考,如:

intvararg(inta,intb,…);

AR2STACKSTACK…

(2)調(diào)用程序調(diào)用函數(shù)。

(3)如果有參數(shù)被壓入堆棧,則調(diào)用程序?qū)?shù)彈出堆棧。當一個函數(shù)在說明中用省略號表明參數(shù)數(shù)目可變時,上述規(guī)則稍

3.支持運行函數(shù)的寄存器變量模式運行支持的匯編文件采用了寄存器參數(shù)調(diào)用規(guī)則的修正版本。有4個寄存器,它們是R1、R2、R3和R4,按照下面的方式傳遞參數(shù):

(1)整數(shù)、浮點和指針參數(shù)可在在上面列出的寄存器中傳遞;

(2)沒有分配給寄存器的參數(shù)(原因是類型不匹配或者是寄存器已用完)按照反序壓入堆棧。第5個寄存器AR0被用來通過地址返回到structuresandunions。AR0也可以用來返回指針。3.支持運行函數(shù)的寄存器變量模式

4.被調(diào)用函數(shù)的工作當一個函數(shù)被另一個函數(shù)調(diào)用時,必須按照下面的步驟(1)~(7)工作。但是如果函數(shù)沒有局部變量、沒有堆棧參數(shù)和不需要保存局部臨時參數(shù)時,下面的(1)和(6)不執(zhí)行。

(1)被調(diào)用函數(shù)設(shè)置局部幀。局部幀以下面的方式分配:①將原來的幀指針FP壓入堆棧保護;②將新的幀指針設(shè)置為當前的SP;③將幀的大小加到SP。4.被調(diào)用函數(shù)的工作

(2)如果所調(diào)用的函數(shù)改變下面任一個寄存器,則必須壓入堆棧以保護它們的值。被調(diào)用函數(shù)可能在沒有保護寄存器內(nèi)容時就修正寄存器。(2)如果所調(diào)用的函數(shù)改變下面任一個寄存器,則必須壓入

(3)執(zhí)行函數(shù)代碼。

(4)若函數(shù)的返回值為整數(shù)、指針或浮點數(shù),函就數(shù)會把返回的值放入R0寄存器中。在修訂的寄存器參數(shù)調(diào)用規(guī)則中,指針返回到AR0寄存器。若函數(shù)返回置是一個結(jié)構(gòu),則調(diào)用函數(shù)為這個結(jié)構(gòu)分配空間,然后返回空間的地址用AR0傳遞給已調(diào)用的函數(shù)。為了返回一個結(jié)構(gòu),被調(diào)用的函數(shù)將結(jié)構(gòu)拷貝到AR0指向的存儲器塊中。但是調(diào)用函數(shù)如果不用返回值,則將AR0置為0,通知被調(diào)用函數(shù)不用拷貝返回結(jié)構(gòu)。(3)執(zhí)行函數(shù)代碼。

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論