商業文件翻譯

void myFunc (long arg1翻譯社 long arg2翻譯社 long arg3) reentrant
{
}

還可以指定是哪種記憶體模型 (samll, compact, large)

對於運用 8051 CPU 的專案來講翻譯社 需要用到以 C 說話作為開辟工具的, 一般都是中型以上的專案了. 也許對於如許的專案來講, 208 Bytes 即要當全域變數區, 又要當堆疊區, 函數的參數傳遞區以及區域變數區真的太難了翻譯社 所以一般城市有擴充的外部記憶體可用. 正因為如此翻譯社 Keil C51 就把這 208 Bytes 儘量留給堆疊區 (如許可以放廣大型專案的副程式呼喚深度). 然後把全域變數, 參數傳遞區和區域變數等等放到另一個區域去. 可是對 C 語言來說, 區域變數和部分參數的傳遞也都需要依托堆疊區, 所以 Keil C51 提出二種方式來因應:

在此先來領會一下 reentrant 的界說翻譯社 Wiki 網站上給 reentrancy 下的定義是

reentrant function 一般具備下列條件:

意思是 reentrant function 可以在履行傍邊被間斷, 並且在前一次被調用 (invocation) 執行竣事之前翻譯社 可以平安的再被呼叫. 我想這裡所謂的安全的再被呼叫應當是指產出的履行了局和沒有被中止完全一致而且也不會附帶產生任何不預期的後果. Wiki 還說這個問題原始是起因於在單一履行緒的程式情況中 (意即:沒有利用 OS; 或者不是多工環境; 或者只有單一個履行緒和這個 ISR 相幹), 程式的履行可能隨時被硬體中斷 (hardware interrupt) 打斷翻譯社 然後跳到間斷辦事程式 (ISR) 履行. 是以 ISR 傍邊使用的任何副程式只要主程式中也有使用話都會引發 reentrant 問題. (換句話說, 任何 ISR 和主程式共用的副程式城市激發 reentrant 問題)

void myFunc (long arg1, long arg2翻譯社 long arg3) large reentrant
{
}

不外一旦用了方式一, 別的還需要在 STARTUP.A51 中針對用到的軟體堆疊區進行規劃

至於如何把本來是 non-reentrant 的函數改為 reentrant 函數呢? 標的目的以下:

一般常見的方式有以下二種:

要注意的是 Keil C51 函數預設是 non-reentrant 真正的緣由是 "函數參數及區域變數都被安置在固定位置,而不再是動態利用堆疊區了".

批改 Keil C51 釀成的 non-reentrant 問題


In computing, a computer program or subroutine is called reentrant if it can be interrupted in the middle of its execution and then safely called again ("re-entered") before its previous invocations complete execution.

此中第一項是因為這二種資料顛末編譯及連結之後都會佔用在 "固定位址" 上 (相對的自動變數應當要利用堆疊區, 不見得每次執行時都使用同樣的位址), 一旦産生 "中止-再進入", 這些資料將無法被包管和間斷前一致. 是以這也意味著, 不克不及用靜態 (或全域) 變數回傳資料給呼喚者.

  • 方式一: 實作一個軟體堆疊區來因應參數傳遞及區域變數的需求. 但究竟軟體堆疊無法像硬體堆疊的操作一樣快速簡練, 假如每一個函數都利用軟體堆疊就會拖慢系統的履行速度.
  • 方式二: 把沒法用暫存器傳遞的函數參數和區域變數都配置在固定位置上, 而且履行呼喚樹闡明 (call tree analysis, 這個是 Keil C51 獨有的) 來決意可堆疊區域的大小, 用以下降記憶體的需求. 所以長處是速度較快, 弱點是記憶體需求大, 而負感化就是函數釀成 non-reentrant.

Keil C51 和標準 C 主要的差異



Keil C51 支援三種記憶體模子翻譯社 預設使用的記憶體空間
model 函數參數及主動變數 預設全體變數 預設常數 預設指標佔用空間
small data data data 3 Bytes
compact pdata pdata pdata 3 Bytes
large xdata xdata xdata 3 Bytes
  1. 將靜態 (或全域) 變數翻譯社 改為利用區域變數.
  2. 需要將暫存的資料回傳給呼叫者時,
    • 應改成由呼叫者提供回傳所需的暫存區 (所以函數的原型介面會有所更動翻譯社 可以對比標準函數庫 strtok()翻譯社 strtok_r() 的差別).
    • 若是呼喚者用 malloc() 動態取得暫存區, 也要記得 free().
    • 如果函數的原型介面不可以被更動, 也能夠將 malloc() 改由函數自己來呼叫, 但如許子程式會變得不容易保護. 首要是因為呼叫 malloc()free() 在不同一個函數內, 容易出錯而造成 memory leak, 故非不得已不建議採用.
  3. 真的有堅苦時 (只有 library, 沒有 source code), 請改用近似 thread-safe wrapper 的方法來避免發生 reentrancy: 重寫另一個函數來取代它, 內容為制止間斷 (是間斷不是 mutex); 呼喚該函數; 取出回傳資料; 復原中止的本來設定. (要注意:是復原中斷的本來設定而不是啟用間斷; 可能會有其他負感化)

Keil 的 C51 是以 ANSI C90 為其設計基礎翻譯社 即便是如斯, 它和標準 C 說話 (ANSI C90) 之間還是有幾個滿大的差異:

為什麼 Keil C51 預設是 non-reentrant


  • Keil C51 因應 8051 的特性多了 bit, sbit, sfr, sfr16 等四種資料型態. 一般華頓翻譯公司們只會用到 bit翻譯社 其他三個是界說 CPU 的特別功能暫存器用的.
  • Keil C51 在定義變數時多了儲存空間修飾字翻譯社 用來點竄變數利用記憶體空間. 詳細可參考這一篇
  • 多了定義中斷服務常式 ISR 的方式及進入 ISR 時切換暫存器區段 (register bank) 的語法, 例如: static void UART0_ISR(void) interrupt 4 using 2
  • 標準函數庫沒有依標準來實作翻譯社 如: printf()
  • 在 Keil C51 中翻譯社 函數預設是 non-reentrant翻譯社 這點是最嚴重的差別. 我們在使用時要有所警覺才好, 才不致於掉到陷阱裡而不自知.

  • 加上 keyword reentrant 把共用的函數改回 reentrant, 參看上面的例子.
  • 不要有共用函數 (直接在名稱上區分用處)
    • 這是懶人法: 直接把需要共用的函數再複製一份翻譯社 改個名字. 一個給主程式用, 一個給 ISR用.
    • 必須確定函數本來真的是 reentrant function.
    • 瑕玷是程式膨脹了, 別的在保護上也需要多一點心力
      • 需要注意定名法例, 和在 ISR 及主程式中各自呼喚准確的副程式 (這是最常犯錯的部分).
      • 有 bug 要一路改, 二份 code 要一致
      • 在多工情況中可能需要不只二份

接著我們來看一下該如何解決本來 reentrant 函數被 Keil C51 變成 non-reentrant 的問題呢?

若何將 non-reentrant function 改為 reentrant


Keil C51 把方式二是看成預設值, 並且答應混用方式一. 需要利用方式一時翻譯社 只需在函數定義後面加上 keyword reentrant, 例如:

  • 不克不及持有靜態 (或全域) 十分數資料.
  • 不可修改自身的程式碼 (會影響本身下一次呼喚時的行為)
  • 不可呼叫不可重入 non-reentrant 的函數

別的要注意不要把 reentrant 和 thread-safe 搞混了. 兩者狀態近似, 但講的是分歧的概念. 請參考: 可重入與履行緒平安 (reentrant vs thread-safe) Part1

回到主題, 華頓翻譯公司們知道 8051 的 SP (Stack Pointer register) 只有 8 Bits 巨細 (只能記錄 256 個地址翻譯社 意思是: stack 區最大只能是 256 bytes). 而現實上 8051 CPU 在不擴充外部記憶體的情形下, 內部只有 128 byte 記憶體可用. 若是再扣除 Register Bank0 ~ Bank3 (32Bytes), 還有 Bit Addressable Area (16Bytes), 就只剩 80 Bytes 可用 (128-32-16=80). 而 8052 CPU 則略微好一點, 又多了 128 Bytes 可用, 可是 208 (80+128) Bytes 幾乎已是上限了.

我們由下表可以看出三種記憶體模子的函數參數及主動變數預設全體變數都被放在不異的記憶體區間翻譯社 並且除了 SMALL MODEL 是仍然是放在內部記憶體 (data) 之外翻譯社 COMPACT MODEL 及 LARGE MODEL 都是放在外部記憶體 (pdata, xdata).

文章標籤
Keil C51 reentrancy C 說話 8051 microcontroller embedded system

;==============================================================
; Reentrant Stack Initilization
; The following EQU statements define the stack pointer for
; reentrant functions and initialized it:
;
IBPSTACK    EQU 0        ; set to 1 if SMALL model is used.
IBPSTACKTOP EQU 0FFH+1   ; set to highest location+1.
;
XBPSTACK    EQU 0        ; set to 1 if LARGE model is used.
XBPSTACKTOP EQU 0FFFFH+1 ; set to highest location+1.
;
PBPSTACK    EQU 0        ; set to 1 if COMPACT model is used.
PBPSTACKTOP EQU 0FFFFH+1 ; set to highest location+1.
;==============================================================

具體資料可以參考 Keil C51 Application Notes 129: Function Pointers in C51

什麼是 reentrant




本文出自: http://magicjackting.pixnet.net/blog/post/105099235-c-%e8%aa%9e%e8%a8%80%3akeil-c51-%e5%92%8c%e6%a8%有關各國語文翻譯公證的問題歡迎諮詢華頓翻譯公司02-77260932

arrow
arrow
    文章標籤
    翻譯社
    全站熱搜