每天进步一点点。
分类: C/C++
2009-08-07 15:21:21
最近用freescale的codewarrior,对它的工程文件.prm有些迷惑,网上资料也很少,freescale的help中也没找到像样的说明,最后找到这篇,转过来,收藏。
通过项目模板建立的新项目中都有一个名字为project.prm的文件,位于图1-8
所示项目文件列表的Linker Files一栏。一个标准的prm文件起始内容如下:
例4.1 prm 文件内容实例
/* This is a linker parameter file for the AW32 */
NAMES END /* CodeWarrior will pass all the needed files to the linker by command line. But here you may add your own
files too. */
SEGMENTS /* Here all RAM/ROM areas of the device are listed. Used in PLACEMENT below. */
ROM = READ_ONLY 0x8000 TO 0xFFAF;
Z_RAM = READ_WRITE 0x0070 TO 0x00FF;
RAM = READ_WRITE 0x0100 TO 0x086F;
ROM1 = READ_ONLY 0xFFC0 TO 0xFFCB;
END
PLACEMENT /* Here all predefined and user segments are placed into the SEGMENTS defined above. */
DEFAULT_RAM INTO RAM;
DEFAULT_ROM, ROM_VAR, STRINGS INTO ROM;
_DATA_ZEROPAGE, MY_ZEROPAGE INTO Z_RAM;
END
STACKSIZE 0x50
VECTOR 0 _Startup /* Reset vector: this is the default entry point for an application. */
prm 文件组成结构
按所含的信息prm 文件有五个组成部分构成:
?
"NAMES-END"部分用以指定在连接时加入除本项目文件列表之外的额外的目标代码模块文件,这些文件都是事先经C
编译器或汇编器编译好的机器码目标文件而不是源代码文件。不过这种用法比较少见,因为我们可以在图1-8
所示项目文件列表的?Libs?一栏中添加这些目标代码文件来实现同样的任务,而且由项目列表管理这些模块文件比较直观方便。
?
"SEGMENTS-END"部分定义和划分芯片所有可用的内存资源,包括程序空间和数据空间。一般我们将程序空间定义成"ROM",把数据空间划分成第
0
页的?Z_RAM?和普通区域的?RAM?,但实际上这些名字都不是系统保留的关键词,可以由用户随意修改。用户也可以把内存空间按地址和属性随意分割成
大小不同的块,每块可以自由命名。关于内存划分的具体方法在后面详解。
? "PLACEMENT - END"部分将指派源程序中所定义的各种段,例如数据段DATA_SEG、CONST_SEG 和代码段CODE_SEG 被具体放置到哪一个内存块中。它是将源程序中的定义描述和实际物理内存挂钩的桥梁。
?
"STACKSIZE"定义系统堆栈长度,其后给出的长度字节数可以根据实际应用需要进行修改。堆栈的实际定位取决于RAM
内存的划分和使用情况。在常见的RAM 线性划分变量连续分配的情况下,堆栈将紧挨在用户所定义的所有变量区域的高端。但如果你将RAM
区分成几个不同的块,请确保其
中至少有一个块能容纳已经定义的堆栈长度。
? "VECTOR"定义所有矢量入口地址。模板在生成prm
文件时已经定义了复位矢量的入口地址。对于各类中断矢量用户必须自己按矢量编号和中断服务函数名相关联,请参考3.4.2
中代码范例。如果中断函数的定义是用"interrupt"加上矢量号,则无需在这里重复定义。
prm 文件中可以添加注释,语法和C语言相同,可以是"/*?*/"或"//"。
4.2 内存划分的具体方式
由"SEGMENTS"开始到"END"为止,中间可以添加任意多行内存划分的定义,每一行用分号";"结尾。定义行的语法型式为:
[块名] = [属性] [起始地址 ] TO [结束地址];
其中,
? "块名"的定义和C 语言变量定义相同,是以英文字母开头的一个字符串。
?
"属性"可以有三种不同的类型。对于只读的Flash-ROM 区属性一定是"READ_ONLY",对于可读写的RAM
区属性可以是"READ_WRITE",也可以是"NO_INIT"。它们两者的关键区别是ANSI-C
的初始化代码会把定位在"READ_WRITE"块中的所有全局和静态变量自动清零,而"NO_INIT"块中的变量将不会被自动清零。对于单片机系统,
变量在复位时不被自动清零这一特性有时是很关键的。
? 起始地址和结束地址决定了一内存块的物理位置,用16进制表示。
下面举几个例子来进一步说明:
例4.2 划分Flash-ROM 区,定义512 字节EEPROM 模拟区
SEGMENTS
EEPROM = READ_ONLY 0x8000 TO 0x81FF;
ROM = READ_ONLY 0x8200 TO 0xFFAF;
Z_RAM = READ_WRITE 0x0070 TO 0x00FF;
RAM = READ_WRITE 0x0100 TO 0x086F;
END
例4.3 划分RAM 区,定义16 字节非自动清零的数据保留区
SEGMENTS
ROM = READ_ONLY 0x8000 TO 0xFFAF;
Z_RAM = READ_WRITE 0x0070 TO 0x00FF;
RAM_KEEP = NO_INIT 0x0100 TO 0x010F;
RAM = READ_WRITE 0x0110 TO 0x086F;
END
用"SEGMENTS"只是从单片机的物理内存这一角度对其进行空间划分。源程序本身并不知道物理内存被分割和属性定义的这些细节。它们两者之间必须通过下面的"PLACEMENT"建立联系。
4.3 程序段和数据段的放置
"PLACEMENT - END"内所描述的信息是告诉连接器源程序中所定义的各类段应该被具体放置到哪一个内存块中去。其语法型式为:
[段名1], [段名2],... [段名n] INTO [内存块名];
其中
?
段名就是在源程序中用"#pragma"声明的数据段、常数段或代码段的名字。如果用缺省名"DEFAULT " ,
则默认的数据段名为?DEFAULT_RAM?,代码段和常数段名为"DEFAULT_ROM"。若程序中定义的段名没有在PLACEMENT
中提及,则将被视同为DEFAULT。几个相同性质但不同名字的段可以被放置到同一个内存块中,相互之间用逗号","分隔。
INTO 是系统保留的关键词,在这里为"放入"的意思。
?
内存块名就是前面介绍的用"SEGMENTS"划分好的不同的内存块名字。利用这样直观的定位描述文本可以方便灵活的将你的数据或代码定位到芯片内存任意
可能的位置,实现某些特殊目的的应用。下面举几个例子,注意各种段名、PLACEMENT 和SEGMENTS 之间的对应关系。
例4.4 定义并保留512 字节Flash 字节作为EEPROM 模拟
//prm 文件SEGMENTS 定义:
SEGMENTS
EEPROM = READ_ONLY 0x8000 TO 0x81FF;
ROM = READ_ONLY 0x8200 TO 0xFFAF;
Z_RAM = READ_WRITE 0x0070 TO 0x00FF;
RAM = READ_WRITE 0x0100 TO 0x086F;
END
//prm 文件PLACEMENT 定义:
PLACEMENT
DEFAULT_RAM INTO RAM;
DEFAULT_ROM, ROM_VAR, STRINGS INTO ROM;
_DATA_ZEROPAGE, MY_ZEROPAGE INTO Z_RAM;
EE_DATA INTO EEPROM;
END
//源程序编写:
#pragma CONST_SEG EE_DATA
const byte eeDataBuff[512]="123456";
例4.5 将不同的代码段分别放置于不同的程序区
//prm 文件SEGMENTS 定义:
SEGMENTS
BOOT_SECTOR = READ_ONLY 0x8000 TO 0x87FF; //2KB 作为加载引导专用区
ROM = READ_ONLY 0x8800 TO 0xFFAF;
Z_RAM = READ_WRITE 0x0070 TO 0x00FF;
RAM = READ_WRITE 0x0100 TO 0x086F;
END
//prm 文件PLACEMENT 定义:
PLACEMENT
DEFAULT_RAM INTO RAM;
DEFAULT_ROM, ROM_VAR, STRINGS INTO ROM;
_DATA_ZEROPAGE, MY_ZEROPAGE INTO Z_RAM;
BOOT_LOADER INTO BOOT_SECTOR;
END
//源程序编写:
#pragma CODE_SEG BOOT_LOADER //定义专用的加载引导代码段
void CodeLoader(void)
{
...
}
#pragma CODE_SEG DEFAULT //普通代码段
void main(void)
{
...
}
例4.6 定义非自动清零的数据段
//prm 文件SEGMENTS 定义:
SEGMENTS
ROM = READ_ONLY 0x8000 TO 0xFFAF;
Z_RAM = READ_WRITE 0x0070 TO 0x00FF;
RAM_KEEP = NO_INIT 0x0100 TO 0x011F; //32 字节非自动清零数据段
RAM = READ_WRITE 0x0120 TO 0x086F;
END
//prm 文件PLACEMENT 定义:
PLACEMENT
DEFAULT_RAM INTO RAM;
DEFAULT_ROM, ROM_VAR, STRINGS INTO ROM;
_DATA_ZEROPAGE, MY_ZEROPAGE INTO Z_RAM;
DATA_PERSISTENT INTO RAM_KEEP;
END
//源程序编写:
#pragma DATA_SEG DATA_PERSISTENT //定义复位时非自定清零数据段
byte sysState;
word pulseCounter;