C51編譯器-語言擴(kuò)展(4)-函數(shù)
Function Declarations函數(shù)聲明
Cx51對(duì)標(biāo)準(zhǔn)C進(jìn)行了一定的擴(kuò)展,使用這些擴(kuò)展可以:
(1)把一個(gè)函數(shù)聲明為一個(gè)中斷過程
(2)選擇使用的寄存器組
(3)選擇存儲(chǔ)器模式
(4)聲時(shí)可重入
(5)聲明外部函數(shù)
在函數(shù)聲中包含這些擴(kuò)展或?qū)傩裕褂孟旅娴姆椒暶鰿x51函數(shù)
[return_type]funcname([args]) [{small | compact | large}][reentrant][interruptn][usingn]
這里
return_type 返回值類型
funcname 函數(shù)名稱
args參數(shù)
small, compact, or large 存儲(chǔ)器模式
reentrant 是否可重入
interrupt 是否是中斷函數(shù)
using 使用哪個(gè)寄存器組
Function Parameters and the Stack函數(shù)參和堆棧
經(jīng)典的8051堆棧指針只訪問內(nèi)部的數(shù)據(jù)存儲(chǔ)器。Cx51緊接著在所有的數(shù)據(jù)之后放堆棧區(qū)。堆棧指針間接地訪問內(nèi)部數(shù)據(jù)存儲(chǔ)器,可以訪問所有的00-FFH的空間
在經(jīng)典的8051中堆棧的空間是受限制的,最大只有256字節(jié)。除了函數(shù)參數(shù)消耗堆??臻g,Cx51為每個(gè)函數(shù)指定了一些固定的內(nèi)存空間。當(dāng)函數(shù)被調(diào)用時(shí),調(diào)用者必須在進(jìn)入函數(shù)之前把參數(shù)拷貝到這個(gè)固定的空間中。然后函數(shù)從這個(gè)固定的空間中讀取并使用這些參數(shù)。在這個(gè)過程中只有返回地址存放在堆棧中。中斷函數(shù)會(huì)需要更多的堆??臻g,因?yàn)槌绦虮仨毲袚Q寄存器組并且保存一些寄存器的值到堆棧中。
注:Cx51允許使用在某些8051的增強(qiáng)型變種中可用的擴(kuò)展的堆棧區(qū)。通過這種方式,堆棧區(qū)域的大小可以增加到幾K字節(jié)。
在缺省的情況下,Cx51使用三個(gè)寄存器傳遞函數(shù)的參數(shù),這樣可以提高代碼的執(zhí)行速度。
注:有些8051變種僅提供64字節(jié)的片上數(shù)據(jù)存儲(chǔ)器,大多數(shù)器件有256字節(jié)。在使用存儲(chǔ)器模式時(shí)應(yīng)該把這些都考慮進(jìn)去,畢竟片上的data和idata數(shù)據(jù)存儲(chǔ)器直接影響到堆棧空間的大小。
Passing Parameters in Registers通過寄存器傳遞參數(shù)
Cx51允許使用CPU寄存器傳遞三個(gè)參數(shù),由于這種方式不需將參數(shù)寫入存儲(chǔ)器和從存儲(chǔ)器中讀出,所以明顯地提高了系統(tǒng)的性能。參數(shù)的傳遞受上一章講到的REGPARMS 和NOREGPARMS指令控制。
下表列出了用于不同位置參數(shù)和數(shù)據(jù)類型的寄存器。
參數(shù)個(gè)數(shù)
Char, 1-yte ptr
Int, 2-byte ptr
Long, float
Generic ptr
1
R7
R6&R7
R4-R7
R1-R3
2
R5
R4&R5
R4-R7
R1-R3
3
R3
R2&R3
R1-R3
沒有可用的寄存器來傳遞參數(shù),則用一個(gè)固定的存儲(chǔ)器區(qū)域來傳遞函數(shù)參數(shù)。
Function Return Values函數(shù)返回值
函數(shù)返回值總是使用CPU寄存器。下表列出了返回值的類型和所用的寄存器。
返回值
寄存器
描述
Bit
進(jìn)位標(biāo)志
Char, unsigned char, 1-byte ptr
R7
Int, unsigned int, 2-byte ptr
R6&R7
高位字節(jié)為R6,低位字節(jié)為R7
Long, unsigned long
R4-R7
高位字節(jié)為R4,低位字節(jié)為R7
Float
R4-R7
32位IEEE格式
Generic ptr
R1-R3
存儲(chǔ)器類型在R3,高位R2,低位R1
注:如果函數(shù)的第一個(gè)參數(shù)是bit類型的,其他的參數(shù)據(jù)是不通過寄存器傳遞的。這是因?yàn)槟茉诩拇嫫髦袀鬟f的參數(shù)與前述的編號(hào)方案都不相同。因此,bit類型的參數(shù)應(yīng)該在參數(shù)列表中末尾聲明。
Specifying the Memory Model for a Function
聲明函數(shù)的存儲(chǔ)器模式
Cx51函數(shù)通常采用缺省的存儲(chǔ)器模式來決定哪個(gè)存儲(chǔ)器空間用于函數(shù)的參數(shù)和局部變量。
可以通過包含small, compact,或large在函數(shù)的屬性中來指定函數(shù)的存儲(chǔ)器類型。
如:
int large_func (int i, int k) large /* Large model */
{
return (mtest (i, k) + 2);
}
函數(shù)使用small存儲(chǔ)器模式的好處是函數(shù)的參數(shù)和局部變量都放在8051的RAM中。因此,數(shù)據(jù)訪問效率非常高。然而,內(nèi)部的數(shù)存儲(chǔ)器有限。有時(shí)候有限的內(nèi)部數(shù)據(jù)存儲(chǔ)器的大小不能滿足需要,就必須使用其他的存儲(chǔ)器模式。在這種情況下,可以使用上面的方法定義一個(gè)函數(shù)使不同的存儲(chǔ)器模式。
通過指定函數(shù)的存儲(chǔ)器模式,可以從三種可能的可重入堆棧和結(jié)構(gòu)指針中擇優(yōu)使用。堆訪問SMALL模式要比訪問LARGE模式快得多。
Specifying the Register Bank for a Function
指定函數(shù)使用的寄存器組
8051系列器件的低32字節(jié)被分成了4個(gè)組,每個(gè)組8個(gè)寄存器。程序可以通過R0-R7訪問這些寄存器。寄存器組可以通過程序狀態(tài)字(PSW)的兩個(gè)位選擇。寄存器組對(duì)中斷處理或者是使用實(shí)時(shí)操作系統(tǒng)非常有用。在中斷服務(wù)程序中CPU切換寄存器組而不把不當(dāng)前的寄存器都保存起來。
關(guān)鍵字using用來指定函數(shù)使用的寄存器組:
void rb_function (void) using 3
{
。。。。。。。
}
關(guān)鍵字using的參數(shù)是一個(gè)0-3的整型常量,而且表達(dá)式中不允許有操作符出現(xiàn)。在函數(shù)的原型中不允許出現(xiàn)using關(guān)鍵字。這個(gè)關(guān)鍵詞對(duì)函數(shù)代碼有如下影響:
(1)當(dāng)前選擇的寄存器組在函數(shù)的入口處被保存在堆棧中
(2)指定的寄存器組被設(shè)定
(3)前面使用的寄存器組被保存下來直到當(dāng)前的函數(shù)退出
不能關(guān)鍵字using來聲明一個(gè)返回值在寄存器中的函數(shù)。在使用的時(shí)候必須非常小心,確保寄存器組切換只出現(xiàn)在謹(jǐn)慎地控制地區(qū)域。稍不小心會(huì)得到錯(cuò)誤的返回值。即使用同一個(gè)寄存器組,使用了using關(guān)鍵字聲明了屬性的函數(shù)也不能返回一個(gè)bit類型的值。
典型地,using屬性對(duì)于聲明了interrupt屬的函數(shù)是非常有用的。為每一個(gè)級(jí)別的中斷都聲明一個(gè)不同寄存器組是比較常見的。因此,你可以在所有非中斷程序中使用一個(gè)寄存器組,在高優(yōu)先級(jí)中斷中使用一個(gè)寄存器組,在低優(yōu)先級(jí)中斷中使用一個(gè)寄存器組。
Register Bank Access寄存器訪問
Cx51允許在一函數(shù)中定義缺省的寄存器組??刂浦噶頡EGISTERBANK允許程序員在源文件中指定在所有函數(shù)另使用哪一個(gè)寄存器組。然而這個(gè)指令并不產(chǎn)生切換寄存器的代碼。
復(fù)位后,8051在PSW中裝入00h從而選擇寄存器組0。所以缺省地所有非中斷程序代碼都使寄存器組0。要想改變,必須:
(1)修改startup代碼以選擇其他的寄存器組
(2)使用REGISTERBANK指令進(jìn)行聲明
缺省地,Cx51編譯器生成用絕對(duì)地址訪問R0-R7的代碼。這是為了最高的執(zhí)行效率。絕對(duì)地址的使用通過指令A(yù)REGS和NOAREGS控制。使用絕對(duì)址進(jìn)行寄存器訪問的函數(shù)不能被使用其他寄存器組的函數(shù)調(diào)用。由于調(diào)用者使用了不同的寄存器組,這樣做會(huì)引起不可預(yù)料的后果。要使用函數(shù)對(duì)當(dāng)前的寄存器組不敏感,函數(shù)必須在編譯前使用控制指令NOAREGS。這對(duì)于那種可能在主函數(shù)中調(diào)用,也可能被使用不同寄存器組的中斷程序調(diào)用的函數(shù)很有用。注:Cx51編譯器并不檢查函數(shù)間的寄存器組是否一致。因此,必須確保使用不寄存器組的函數(shù)只調(diào)用那些不指定缺省寄存器組的函數(shù)。