原创 TI的CMD文件

2012-12-4 01:19 2337 14 14 分类: 工程师职场

CMD文件有两种产生方式:一种是手写,一种是由DSP/BIOS配置工具产生。CMD的作用很多,但它的最基本的功能就是实现对存储空间的说明和配置。

如下关于CMD配置的例程主要完成的功能有:
1. 说明系统有片内静态RAM(ISRAM,256KB)和片外动态RAM(SDRAM,32MB)组成,其起始地址和长度分别为...
2. 构建一个C工程需要多个段,SECTIONS中说明如何分配这些段。都放在ISRAM里当然快,但是工程大了肯定放不下,如何权衡自己考虑了。
3. 指明系统的堆和栈的大小。



-heap  0x800000
-stack 0x8000

MEMORY {
   ISRAM       : origin = 0x0,         len = 0x40000
   SDRAM       : origin = 0x80000000,  len = 0x2000000
}

SECTIONS
{
        .vectors > ISRAM
        .text    > ISRAM
        .satext  > ISRAM
        .wjpdata > ISRAM
        .sadata  > ISRAM
        .bss     > ISRAM
        .cinit   > ISRAM
        .const   > ISRAM
        .far     > ISRAM
        .stack   > ISRAM
        .cio     > SDRAM
        .switch  > SDRAM
        .sysmem  > SDRAM
        .wjpout  > ISRAM
}

这里各段(包括程序区,静态数据和动态数据区)注释为:

.vectors 中断向量表所在的段;
.text     程序代码所在的段;
.satext   非标准段,放置线性汇编程序代码;
.bss      非初始化变量段
.cinit    程序初始化段,经常放置一些没有用const说明的带初值变量的初始化值。
.const    使用const声明的变量和数组
.far      不可使用DP指针而必须使用全地址访问的变量所在的段,与far关键字和编译选项有关
.stack    系统栈使用的段
.cio      printf等输入输出函数使用的缓冲区所在的段
.switch   程序中switch语句的跳转地址表
.system   系统堆,内存的动态开辟即使用这个段

最近开始研究TI的DSP。初步接触,对CMD文件很有些头疼,经过多方学习,也和TI的一些第三方支持如北京瑞泰等接触学习了一下,终于弄明白的CMD文件的相关信息,特此共享之。

CMD的专业名称叫链接器配置文件,是存放链接器的配置信息的,我们简称为命令文件。从其名称可以看出,该文件的作用是指明如何链接程序的。

那么我们知道,在编写TI DSP程序时,是可以将程序分为很多段,比如text、bss等,各段的作用均不相同。实际在片中运行时,所处的位置也不相同。比如text代码一般应该放在flash内,而bss的变量应该放在ram内。等等。但是对于不同的芯片,其各存储器的起止地址都是不一样的,而且,用户希望将某一段,尤其是自定义段,放在什么存储器的什么位置,这也是链接器不知道的。为了告诉链接器,即将使用的芯片其内部存储空间的分配和程序各段的具体存放位置,这就需要编写一个配置文件,即CMD文件了。

所以,CMD文件里面最重要的就是两段,即由MEMORY和SECTIONS两个伪指令指定的两段配置。简单的说,MEMORY就是用来建立目标存储器的模型,而SECTIONS指令就是根据这个模型来安排各个段的位置。

MEMORY指令可以定义目标系统的各种类型的存储器,及容量。MEMORY的语法如下:

MEMORY

{

PAGE 0 : name1[(attr)] : origin = constant,length = constant

name1n[(attr)] : origin = constant,length = constant

PAGE 1 : name2[(attr)] : origin = constant,length = constant

name2n[(attr)] : origin = constant,length = constant

PAGE n : namen[(attr)] : origin = constant,length = constant

namenn[(attr)] : origin = constant,length = constant

}

其中。PAGE关键词对独立的存储空间进行标记,页号n的最大值为255,实际应用中一般分为三页,PAGE 0程序存储器、PAGE 1数据存储器和PAGE 2 IO空间存储器。name为自定义的存储区间的名字,不超过8个字符,不同的PAGE上可以出现相同的名字(最好不用,免的搞混),一个PAGE内不许有相同的name。 attr的属性标识,为R表示可读;W可写X表示区间可以装入可执行代码;I表示存储器可以进行初始化,什么属性代码也不写,表示存储区间具有上述的四种属性,基本上我们都选择这种写法。origin标识了该段存储区间的起始地址,而length则是标识了该段存储区间的长度。以2407A为例,根据这个定义,参考2407A的Datasheet,可以得出2407A内存储器的标准描述为:

MEMORY
{
PAGE 0:
PM: ORIGIN=0h, LENGTH=08000h
SARAM_P:ORIGIN=08000h, LENGTH=0800h
EX1_PM: ORIGIN=08800h, LENGTH=07600h
B0_PM: ORIGIN=0FF00h, LENGTH=0100h

PAGE 1:
REGS: ORIGIN=0h, LENGTH=60h
BLK_B2: ORIGIN=60h, LENGTH=20h
BLK_B0: ORIGIN=200h, LENGTH=100h
BLK_B1: ORIGIN=300h, LENGTH=100h
SARAM_D:ORIGIN=0800h, LENGTH=0800h
PERIPH: ORIGIN=7000h, LENGTH=1000h
EX2_DM: ORIGIN=8000h, LENGTH=8000h

PAGE 2:
IO_EX: ORIGIN=0000h, LENGTH=0FFF0h
IO_IN: ORIGIN=0FFF0h, LENGTH=0Fh
}

有了这个模型。我们就可以定义各个代码段在内存的具体位置了。就是使用SECTIONS伪指令。其格式为:

SECTIONS
{
.text:  {所有.text输入段名}  load=加载地址  run =运行地址
.data:  {所有.data输入段名}  load=加载地址  run =运行地址
.bss:  {所有.bss输入段名}    load=加载地址  run =运行地址
.other: {所有.other输入段名}  load=加载地址  run =运行地址
}

SECTIONS必须用大写字母,其后的大括号里是输出段的说明性语句,每一个输出段的说明都是从段名开始,段名之后是如何对输入段进行组织和给段分配存储器的参数说明。以.text段的属性语句为例,“{所有.text输入段名}”这段内容用来说明连接器输出段的.text段由哪些子目标文件的段组成。接下来的load和run,链接器为每个输出段都在目标存储器里分配两个地址:一个是加载地址,一个是运行地址。通常情况下两个地址是相同的,可以认为输出段只有一个地址,这时就可以不加“run =运行地址”这条语句了;但有时需要将两个地址分开,比如将程序加载到FLASH,然后放到RAM中高速运行,这就用到了运行地址和加载地址的分别配置了。

load和run有一些简化写法,首先“load”关键字可以省略,“=”可以写成“>”, “加载地址”可以是:地址值、存储区间的名字、PAGE关键词等,所以大家见到“.text:{ } > 0×0080”这样的语句可千万不要奇怪。“run =运行地址”中的“ = ”可以用“>”其它的简化写法就没有了。大家不要乱用。

由此,一个简单的SECTIONS的代码就是:

SECTIONS
{
vectors:{}> PM PAGE 0
.text: {}> PM PAGE 0
.data: {}> PM PAGE 0
.bss: {}> BLK_B1 PAGE 1   
}

这样的话,基本就可以理解CMD文件了。至于CMD的其他高级应用,暂时可以不用关心。

这里还需要补充说明的是:以2407A为例,0×40-0×43是加密位,一般编写CMD时最好错开此位,以免误加密。如果使用我这里的示例代码,那就应该在代码中以.word之类预留出加密位位置。否则一旦误加密,那。。。。本人不承担任何责任。。。呵呵

cmd
PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
我要评论
0
14
关闭 站长推荐上一条 /1 下一条