Codewarrior_
中电网深山老林
//.stackstart
eventuallyusedforoseKkernelawareness:Main-StackStart*/
SSTACK
/*allocatestackfirsttoavoidoverwritingvariablesonoverflow*/
/.stacked
eventuallyusedforOSEKkernelawareness:Main-StackEnd*
PAGEDRAM
/thereisnoneedforpageddataaccessesonthisderivative*/
DEFAULTRAM
/xallvariables,thedefaultrAmlocation%
INTO
RAM
DISTRIBUTE
DISTRIBUTEINTO
ROM4000,PAGEFE,PAGEFCPAGEFB,PAGEFAPAGeF9,PAGEF8
CONSTDISTRIBUTEDISTRIBUTEINTO
ROM4000,PAGEFEPAGEFC.PAGEFB.PAGEFAPaGeF9PAGEF8
DATADISTRIBUTEDISTRIBUTEINTO
RAM
7/vectors
INToOSVECTORS:/*OSEKvectortable*
END
ENTRIES/keepthefollowingunreferencedvariables*/
/OSEK:alwaysallocatethevectortableandalldependentobjects*/
//vectabOsBuildNumberOsStartOsOrtiStart
END
STACKSIZE0x100/*sizeofthestack(willbeallocatedinDEFAULT_RAM)*/
/*usethesedefinitionsinplaneofthevectortable('vectors)above*/
VECTOR0_Startup/*resetvector:thisisthedefaultentrypointforaC/C++application.*
//ECTOROEntry/resetvector:thisisthedefaultentrypointforanAssemblyapplication."
//INITEntry
/forassemblyapplicationsthatthisisaswelltheinitializationentrypoint*
1prm文件组成结构
按所含的信息的不同pm文件有六个组成部分构成,这里仅讨论和内存空间映射关系
紧密的三个部分,其他的不做讨论。
SEGMENTS∴END
定义和划分芯片所有可用的内存资源,包括程序空间和数据空间。一般我们将程序空间
定义成ROM,把数据空间定义成RAM,但这些名字都不是系统保留的关键词,可以由用户
随意修改。用户也可以把内存空间按地址和属性随意分割成大小不同的块,每块可以自由命
名。例如同样是RAM,可以使用不同的属性,使其有复位后变量清零和不清零之分。
李宁大连Inmaomao@gmail.com200910-21
中电网深山老林
关于内存划分的具体方法在后面详解。
●PLACEMENT,END
将指派源程序中所定义的各种段,如数据段DATASEG、CONSTSEG和代码段CODESEG
被具体放置到哪一个内存块中。它是将源程序中的定义描述和实际物理内存挂钩的桥梁。
●STACKSIZE
定义系统堆栈长度,其后给岀的长度字芍数可以根据实际应用需要进行修改。堆栈的实
际定位取决于RAM内存的划分和使用情况。默认的情况下,堆栈放在RAM区域的起始部分。
当然,堆栈的定义不只有这种方式,还可以使用STACKTOP关键字。后面将详细讨论
2内存划分的具体方式
由SEGMENTS开始到END为止,中间可以添加任意多行内存划分的定义,每一行用分号
结尾。定义行的语法型式为
块名属性1属性2,,属性n起始地址TO结束地址
其中,
“块名”的定义和C语言变量定义相同,是以英文字母开头的一个字符串,用户可以自凵
任意定义块名。
“属性”用户是不能自己定义的,因为属性名指定了上面所说的“块名”所对应的不同的
内存类型和访问方式,而不同物理内存的类型和访问方式是一定的。
对于“属性1”,Codewarrior50中可以有三种不同的类型,对于只读的Fash-ROM区属
性一定是READONLY,对于可读写的RAM区属性可以是READWRITE,也可以是NOINIT。它
们两者的关键区别是ANSI-C的初始化代码会把定位在READWRITE块中的所有全局和静态变
量自动清零,而NOINIT块中的变量将不会被自动清零。当然只是复位时不清零,掉电时还
是清零的,但是对于单片机系统,变量在复位时不被自动清零这一特性有时是很关键的,在
某些应用中有特殊的用途
对于“属性2….属性n”,根据上面给出的prm的氾例文件可以看出来,可能的形式有
DATAFAR”、“DATANEAR”、“IBCCFAR”、“IBCCNEAR”四和类型。其中,“DATAFAR”
李宁大连Inmaomao@gmail.com200910-21
中电网深山老林
和“DATANEAR”相对应,当内存区域包含变量或者是常量时(通常是RAM、Fash和EEPROM)
必须指明上面两种属性中的一种,由于涉及到内存的分页,可以这样理解:“DATAFAR”
属性指定的内存块为可以保存数据的非固定页,而“DATANEAR”属性指定的内存块为可
以保存数据的固定页;同理“IBCCFAR”和“IBCCNEAR”相对应,当内存区域包含代码时
(Fash和EEPROM),必须指明上面两种属性中的·种,“1BCCFAR”属性指定的内存块为
可以保存代码的非固定页,而“IBCCNEAR”属性指定的内存块为叮以保存代码的固定页
讨论到这里,细心的读者已经发现,在上面的pm文件范例中,RAM的属性有“DATAFAR
和“DATANEAR”两种,Fash的属性中也是四种都有,但是EEPROM中却只有“DATAFAR”
和“IBcC_FAR”两种,这正好验证了上一篇文章(飞思卡尔16位单片机的资源配置)中所提
到的,RAM、Fash中都有固定页,但是EEPROM中全部是非固定页。
●起始地址和结束地址决定了一内存块的物理位置,对于固定页,用4位16进制数表示,而
对于非固定页,则用6位16进制表示,多出来的两位其实是寄存器EPAGE、RPAGE或PAGE的
值,可见,对于分页的资源,是通过寄存器(EPAGE、RPAGE或PPAGE)和16位的地址总线
的组合来进行寻址的。
TO”是系统保留的关键字,必须大写。
下面,根据上面范例提供的内容,举几个例子:
A1RAM=READWRITEDATANEAR0x2000TOOX3FFF
上面这句话的意思是:分配0x2000-0X3FF的区域的块名为“RAM”(当然可以定义别
的名称),由上一篇文章而知,这一区域的物理内存的性质为RAM,属性应该为“READWRITE”,
并且这一区域中的两页都为固定页,所以为“DATANEAR
例2将&K字节RAM的后面4K字节定义成非自动清零的数据保留区,则应如下定义:
SEGMENTS
面面面
RAM
READWRITEDATANEAR0x2000TO0x2FFF:
RAMNOINITNOINIT
DATANEAR0X3000TO0x3FFF
看
END
李宁大连Inmaomao@gmail.com200910-21
中电网深山老林
注意,各部分RAM的分配地址不应该存在重叠的部分,否则会发生错误
1]3EEPROM_00READONLYDATA_FARIBCCFAR0X000800TOOX00OBFF
XS128单片机中的EEPROM由Data-Flash模拟,所以属性为READ_ONLY。EEPROM全部为
非固定页,所以用“DATAFAR”、“IBCCFAR”。后面的起始地址和结束地址分别为6位的
16进制数,前两位的“00”实质指的是EEPROM分页寄存器EPAGE的值为0x00。
用segmentS只是从单片机的物理内存这一角度对其进行空间划分。源程序本身并不知
道物理内存被分割和属性定义的这些细节。它们两者之问必须通过下面的PLACEMENT建立
联系。
3程序段和数据段的放置
PLACEMENT-END内所描述的信息是告诉连接器源程序中所定义的各类段应该被具体放
置到哪一个内存块中去。其语法型式为:
段名段名
,段名INTo内存块名1,内存块名2,
内存块名n
段名段名,
段名DISTRIBUTEINTO内存块名1,内存块名2,
内存块名n
其中
段名就是在源程序中用“#pragma”声明的数据段、常数段或代码段的名字。如果用缺省
名“DEFAULT”,则默认的数据段名为DEFAULTRAM,代码段和常数段名为DEFAULTROM
若程序中定义的段名没有在PLACEMENT中提及,则将被视同为DEFAULT。几个相同性质但不
同名字的段可以被放置到同一个内存块中,相互之间用逗号分隔
INTO是系统保留的关键词,在这里为“放入”的意思
·DISTRIBUTEINTO也是系统的保留关键宇。Codewarrior具有内存自动优化的功能,但是
在“Smallmemory”模式中,这种功能不会被启用,只有当16-bit的地址空间不能存放下所
有的变量和代码时,才会启用这种功能。
李宁大连Inmaomao@gmail.com200910-21
中电网深山老林
在SEGMENTS-END区域中,当在内存模块的属性中加上“DATAFAR”、“DATANEAR
“BCCFAR”、“IBCCNEAR”四种属性中的任何一种时,那么在PLACEMENT-END区域中,
就需要指定段名“DISTRIBUTE”“CONSTDISTRIBUTE”“DATADISTRIBUTE”(系统默
认的,非关键字,用户可以自行更改)所分配的内存空间,这就需要使用“DISTRIBUTEINTO”
关键字
关于内存自动优化功能,可以参考freescale的官方技术手册“
内存块名就是前面介绍的用SEGMENTS划分好的不同的内存块名字。
利用这样直观的定位描述文本可以方便灭活的将数据或代码定位到芯片内存任意可能
的位賀,实现某些特殊日的的应用。
下面的例子,说明了各种段名、PLACEMENT和SEGMENTS之间的对应关系。
例4定义非自动清零的数据段
SEGMENTS
RAM
READWRITEDATANEAR0x2000TO0X2FFF
RAMNOINITNOINIT
DATANEAR
Ox3000TOOX3FFF
END
PLACEMENT
DATAPERSISTENTINTORAMNOINIT
END
//源程序编写:
#pragmaDATA_SEGDATA_PERSISTENT//定义复位时非自定清零数据段
bytesysState
#pragmaDATA_SEGDEFAULT
4堆栈的设置
李宁大连Inmaomao@gmail.com200910-21
中电网深山老林
关于堆栈的设置,Codewarrior提供了两种方式:“STACKSIZE”命令方式和“STACKTOP”
命令方式。这两种方式在同一个prm文件中,不能同时存在。当用户只关心堆栈的大小而不
关心堆栈的存放位置时,推荐使用STACKSIZE方式
系统默认的方式为使用STACKSIZE方式。
STACKSIZE命令方式:
当使用STACKSIZE命令方式时,如果在PLACEMENT-END部分声明」“SSTACKINTORAM
这样的话,堆栈区就被放在RAM区域的起始部分,下面的例子说明了这种方式
例5
SEGMENTS
RAM
READWRITEDATANEAR0x2000TOOX3FFF
END
PLACEMENT
SSTACKPAGEDRAMDEFAULTRAMINTORAM
END
STACKSIZEOx100
上面的例子将堆栈区域存放的地址为0x20FF-0x2000,初始的堆栈指针指向栈顶地址
0x20FF。
相反,如果在PLACEMENT-END部分没有声明“SSTACKINTORAN”,则堆栈被分配
在RAM区域中已分配空间的后面。请参见例6
例6
SEGMENTS
RAM
READWRITEDATANEaR0x2000T0x3FFF
END
李宁大连Inmaomao@gmail.com200910-21
中电网深山老林
ACEMENT
PAGEDRAMDEFAULTRAMINTORAM
END
STACKSIZEOx100
在这个例子中,如果RAM区域中已经分配的变量占用了4个字节(从0x2000到0x2003),
则堆栈放在这四个字节的后面,从0x2103到0x2004,初始的堆栈指针指向0x2103。
STACKYOP命令方式:
当使用STACKTOP命令方式时,如果在PLACEMENT-END部分声明了“SSTACKINTORAM”,
同样,堆栈区就被放在RAM区域的起始部分,初始的栈顶则由STACKTOP指定。若没有相应
的声明,则初始的栈顶由STACKTOP指定,而堆栈的大小则根据处理器的不同由编译器自行
设定,其人小足够装下处理器的PC寄存器的值。
李宁大连Inmaomao@gmail.com200910-21
用户评论