reentrant聲明的函數爲可重入函數。可重入的函數能夠被多個進程同時調用。可重入函數在執行時,另外的進程可以中斷當前執行的函數,並且調用同一個函數。正常情況下,C51程序中的函數不能被遞歸地調用,這是由於函數的參數和局部變量都被保存在固定的地址,在遞歸調用時操作了相同存儲位置,導致數據被覆蓋。
使用reentrant聲明函數爲可遞歸調用的可重入函數:
int calc (char i, int b) reentrant { int x; x = table [i]; return (x * b); }可重入函數,能夠被遞歸調用,也能被兩個以上的進程同時調用。可重入函數通常在實時應用或者中斷與非中斷程序共享相同函數這兩種情況下被使用。
每個可重入函數都有一個位於內部ram或外部ram的模擬堆棧:
1)SMALL內存模型下,可重入函數模擬堆棧位於idata區;
2)COMPACT內存模型下,可重入函數模擬堆棧位於pdata區;
3)LARGE內存模型下,可重入函數模擬堆棧位於xdata區;
使用reentrant聲明可重入函數須遵循的規則:
1)可重入函數不支持位尋址變量,比如bit類型的參數;
2)可重入函數不能被alien函數調用;
3)可重入函數不能被聲明爲alien屬性(alien用於使能PL/M-51參數傳遞約定);
4)可重入函數可以同時擁有其他屬性,比如using、interrupt、small、compact、large;
5)返回地址被保存在硬件堆棧中;
6)使用不同存儲模型的可重入函數能夠混合,但是各自函數聲明時必須指定存儲模型;
7)三種內存模型的可重入函數都有自己的對戰區和棧指針。比如在相同模塊中,定義了small和large類型的可重入函數,則small和large類型的堆棧及其堆棧指針都被創建;
可重入堆棧模擬體系,效率比較低下,但是由於8051自身缺乏適當尋址方法的硬件特性,所以推出這種堆棧模擬體系來滿足我們的可重入需求,在應用中 ,我們應該儘量不用或少用可衝入函數。
可重入函數使用的模擬堆棧擁有獨立於8051硬件堆棧的棧指針。堆棧和堆棧指針在STARTUP.A51文件中被定義和初始化。
下表列出了三種內存模型下的模擬堆棧指針名稱、大小、數據區域:
內存模型 | 指針 | 堆棧信息 |
---|---|---|
SMALL | ?C_IBP (1 字節) |
堆棧位於間接尋址的內部ram(idata). 最大可重入堆棧容量256字節. 訪問該模擬堆棧,須要使用 R0 或 R1裝載?C_IBP 的值,然後使用 MOV A, @R0/@R1 或 MOV @R0/@R1, A 指令。 |
COMPACT | ?C_PBP (1 字節) |
堆棧位於可頁尋址的外部ram。 最大容量256 字節。 訪問該模擬堆棧,須要使用 R0 或 R1裝載?C_PBP 的值,然後使用MOVX A, @R0/@R1 或 MOVX @R0/@R1, A 指令。 |
LARGE | ?C_XBP (2 字節) |
堆棧位於外部ram。 T最大堆棧容量64KB。 訪問該模擬堆棧,須要使用DPTR 裝載?C_XBP 的值,然後使用MOVX A, @DPTR 或 MOVX @DPTR, A 指令。 |
STARTUP.A51啓動代碼聲明並初始化了模擬堆棧及其堆棧指針,如果使用可重入函數就必須修改啓動代碼指出哪個模擬堆棧須要初始化。可以在啓動代碼中修改模擬堆棧的起始地址。
可重入函數的參數傳遞,通過模擬堆棧的壓棧、出棧完成。
可重入函數的局部變量,也保存在模擬堆棧中,通過模擬堆棧指針訪問。