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 中
C51和MDK的ROM大小及变量绝对地址初始化_第1张图片
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编译通过

你可能感兴趣的:(嵌入式,前端,javascript,服务器)