C51和MDK的ROM大小及變量絕對地址初始化

1. C51的ROM大小

Keil編譯完之後,顯示的Program Size: data=9.0 xdata=8 const=15 code=180,則
The Total ROM(const + code + code-gap + const-gap) is 199BYTE
實際生成的bin文件大小:
這裏寫圖片描述
在.MAP中的C O D E M E M O R Y 中
這裏寫圖片描述
code-gap爲0,cosnt-gap爲4,則const + code + const-gap=15 + 180 + 4 = 199,剛好和實際生成的bin文件大小一致。

2. C51的ROM大小優化

如果實際編譯顯示的const + code遠小於實際的Bin文件,表明有非常大的空隙,需要優化。
優化空間,有幾個查找方向:

  • .A51文件中的代碼段起始地址CSEG AT 0xXX是否與Off-chip Code Memory設置的起始位置一致,如果不一致可能導致GAP。
  • 函數及變量指定的絕對地址超出Off-chip Code Memory設置的範圍。
  • interrupt vectors at adress: 0xXX設置的中斷向量地址是否超出Off-chip Code Memory設置的範圍。interrupt vectors at adress必須設置,因爲Keil C51默認的是0x03,可能不在Off-chip Code Memory設置的範圍內,導致GAP。
  • 打開.MAP文件,搜索GAP,如果存在一些GAP,則可能是多個指定的絕對地址之間有GAP導致的,可以將絕對地址調整對齊。
  • 因爲xdata + const + code將佔用整個Off-chip(1581爲58KB),所以可以將一些const,code類型的變量轉換成xdata。總之,根據這三者根據實際情況進行一個調整,總大小不超過58KB即可。有時ROM存放在EEPROM上,所以適當減少const+code的大小,一些變量轉換成Xdata是一種方法。

3. C51變量絕對地址定位及初始化

3.1. 關鍵字_at_

int xdata nValA _at_ 0x1114;
int xdata nValA = 0x2222; // nValA絕對地址定位於x:0x1114,初始化值爲0x2222

char code nValD _at_ 0xD2;
char code nValD = 0x22; // 此句無效,nValD絕對地址定位於c:0xD2,初始值爲0

3.2. LX51 Locate

當勾選Use Extended liker(LX51) instead of BL51時,即使用LX51 Locate
- LX 51 Locate->User Segments->?CO?MAIN(C:0xD2), ?XD?MAIN(x:0x1114)
- LX51 Misc->use linker control file->edit->SEGMENTS (?CO?MAIN(C:0xD2), ?XD?MAIN(x:0x1114))
以上兩種設置均可,推薦用前面一種更方便,且還能夠添加REMOVEUNUSED等編譯關鍵字。

?CO?MAIN和?XD?MAIN作爲segment name,是以變量類型縮寫+文件名大寫組合而成,對此不熟練,可以打開生成的.MAP文件,查看MEMORY MAP OF MODULE區域的描述也可以找到

當指定了當前文件Segment所在,那麼當前文件所有的全局變量,均會在指定的絕對地址之後順序排列,並且可以對變量進行初始化。

int xdata nValA = 0x2222; // nValA絕對地址定位於x:0x1114,初始化值爲0x2222
int xdata nValB = 0x1111; // nValB絕對地址定位於x:0x1116,初始化值爲0x1111
char code nValD = 0x22;   // nValD絕對地址定位於c:0xD2,初始值爲x22
char code nValD = 0x11;   // nValD絕對地址定位於c:0xD2,初始值爲x11

3.3. BL51 Locate

當不勾選Use Extended liker(LX51) instead of BL51時,即使用BX51 Locate
- BL 51 Locate->code->?CO?MAIN(0xD2)
- BL 51 Locate->Xdata->?XD?MAIN(0x1114)
- BL1 Misc->use linker control file->edit->CODE( 0X0000-0X0FFF , ?CO?MAIN(0XD2) )
XDATA( 0X1000-0X2FFF , ?XD?MAIN(0x1002) )

以上兩種設置均可,推薦使用LX51,這是新的鏈接器,性能更好。

4. MDK的ROM大小

此處主要是針對M0而言。Keil編譯之後,在.MAP文件結尾會顯示:

Code (inc. data) RO Data RW Data ZI Data Debug
26864 2124 1284 2040 26632 118060 Grand Totals
26864 2124 1284 72 26632 118060 ELF Image Totals (compressed)
26864 2124 1284 72 0 0 ROM Totals
===================================================================
Total RO Size (Code + RO Data) 28148 ( 27.49kB)
Total RW Size (RW Data + ZI Data) 28672 ( 28.00kB)
Total ROM Size (Code + RO Data + RW Data) 28220 ( 27.56kB)

  • Code,不僅包括生成的代碼,還包括inline data, literal pools, and short strings
  • RO Data,Read Only data,用const修飾的變量,或是地址定位到RO Data的變量。
  • ZI Data,Zero Initialie data,編譯器進行0初始化的數據。所有未顯示初始化,或是顯式初始化爲0的變量均是ZI Data(包括棧變量和堆變量)。
  • RW Data,Read Write Data,顯式初始化爲非0的全局變量。
  • Total Rom Size即是生成的bin文件大小。ROM Size所包含的RW Data爲28220-28148=72,而不是2040。
    實際的代碼:
int nArr[500] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

nArr作爲RW Data,實際大小有2000B,那麼爲什麼通過ROM計算出的RW Data只有72B呢?
首先,RW Data爲什麼要記錄在ROM中呢?這是因爲RW Data的初始化值是編譯期生成的,所以這些初始化值要記錄在ROM中,這樣一上電就能夠初始化。正因爲只記錄初始化的值,所以上面的nArr只初始化了10個值,其他未初始化的其實都沒有放進ROM中。所以這才導致了兩者的不同。
- Total RW Size即運行時存放變量的RAM的大小。

5. MDK的ROM優化

  • 打開.MAP文件,找到Memory Map of the image處,搜查看是否有PAD,如果存在一些PAD,則可能是多個指定的絕對地址之間有GAP導致的,可以將絕對地址調整對齊PAD的大小然後編譯再查看.MAP文件的PAD。
  • 因爲Code + RO Data + RW Data + ZI Data將佔用整個SRAM(5081爲60KB),Code一般不易修改,所以可以動態調整RO Data、RW Data以及ZI Data的分佈,只要總的大小不超過60KB即可,來優化ROM的大小。有時ROM存放在EEPROM上,所以適當減少ROM的大小,一些變量轉換成ZI Data是一種方法。

6. MDK的變量絕對地址定位及初始化

3.1. 關鍵字__attribute__((at(address)))

const int MAX_LUN_CNT __at(0x2000E000) = 10;      // IROM1
const int MY_COLOR[4] __at(0x2000E004) = {1, 2, 3, 4}; // IROM1
int g_Val __at(0x2000E004); // 正確                 // IROM1
int g_Val1 __at(0x2000E200); // 正確              // IRAM1
// 錯誤.This is fixed with ARM Compiler V5.06u2, released in combination with MDK-ARM V5.20.
int g_Val __at(0x2000E200) = 10;  // Keil 4編譯錯誤,Keil 5.20編譯通過
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章