CMD 文件那些事(下) - 创龙小识堂 - 嵌入式开发者社区 - 51ele.net
设为首页收藏本站

嵌入式开发者社区

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 4804|回复: 0
打印 上一主题 下一主题

CMD 文件那些事(下)

[复制链接]

26

主题

29

帖子

158

积分

QQ游客

积分
158
跳转到指定楼层
楼主
发表于 2016-10-23 18:22:41 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
CMD 文件那些事()
本文介绍 CMD 文件的基本功能及一些小技巧
实例分析
上回,我们讲到 CMD 文件的一些基本概念和编程方法。这回,就以 C665x C6678   CMD 文件为例,给大家做实例分析。当然,根据需要做了一点的修改。本文所述内容均是经过实际测试的,所有文本(注释除外)都是英文半角格式。
1./**************************************************************************
2. *                                                               
3. *    广州创龙电子科技有限公司                                 
4. *                                                                 
5. *    Copyright (C) 2014 -2016 Tronlong Electronic Technology Co.,Ltd
6. *                                                                  
7. **************************************************************************/
8./**************************************************************************
9. *                                                                       
10. *              DSP C665x 及 DSP C6678 内存空间分配定义               
11. *                                                                  
12. *              2016年04月19日                              
13. *                                                               
14. *************************************************************************/
15./* 注意:该 CMD 文件描述的仅为默认 MPAX配置下的内存分配 */
16./* 堆栈 */
17.-heap  0x00001000
18.-stack 0x00001000
19.
20./* 库 */
21.-l "../../../Library/Debug/Tronlong.DSP.Driver.le66"
22.
23./* 目标文件 */
24.main.o
25.
26./* 内存段描述 */
27.MEMORY
28.{
29./*************************************************************************
30. *                                                                 
31. *              DSP 本地内存区域                                    
32. *                                                                 
33. *************************************************************************/
34./* 本地内存地址空间仅能够被当前 DSP 核心访问*/
35./* 其它核心和外设访问时请使用全局地址
36. *
37. * 核心 0 - 0x10800000(L2) / 0x10E00000(L1P) /0x10F00000(L1D) (DSP C6654/55/57 / DSP C6678)
38. * 核心 1 - 0x11800000(L2) / 0x11E00000(L1P) /0x11F00000(L1D) (DSP C6657 / DSP C6678)
39. * 核心 2 - 0x12800000(L2) / 0x12E00000(L1P) /0x12F00000(L1D) (DSP C6678)
40. * 核心 3 - 0x13800000(L2) / 0x13E00000(L1P) /0x13F00000(L1D) (DSP C6678)
41. * 核心 4 - 0x14800000(L2) / 0x14E00000(L1P) /0x14F00000(L1D) (DSP C6678)
42. * 核心 5 - 0x15800000(L2) / 0x15E00000(L1P) /0x15F00000(L1D) (DSP C6678)
43. * 核心 6 - 0x16800000(L2) / 0x16E00000(L1P) /0x16F00000(L1D) (DSP C6678)
44. * 核心 7 - 0x17800000(L2) / 0x17E00000(L1P) /0x17F00000(L1D) (DSP C6678)
45. *
46. */
47.
48./* 本地 L1(默认被配置为缓存) */
49.//  LL1PRAM    o = 0x00E00000  l = 0x00008000   /*32KB  L1 本地程序缓存/静态内存 */
50.//  LL1DRAM    o = 0x00F00000  l = 0x00008000   /*32KB  L1 本地缓存/静态内存 */
51.
52./* 本地 L2 */
53./* 当启动完成后下述两段内存空间可以被应用程序使用! */
54./* 注意:核心 0  的 0x00800000 - 0x0081FFFF 这段地址空间启动的时候被Intermediate BootLoader(IBL) 占用! */
55.#ifdef SOC_C665x
56./* 注意:每个核心的 0x008EFD00 - 0x008FFFFF 这段地址空间启动的时候被 ROM BootLoader(RBL) 占用! */
57.    LL2RAM     o = 0x00800000  l = 0x00100000    /* 1MB   L2 本地缓存/静态内存 (DSP C6654/55/57) */
58.#else
59./* 注意:每个核心的 0x00872DC0 - 0x0087FFFF 这段地址空间启动的时候被 ROM BootLoader(RBL) 占用! */
60.    LL2RAM     o = 0x00800000  l = 0x00080000    /* 512KB L2 本地缓存/静态内存 (DSP C6678) */
61.#endif
62.
63./*************************************************************************
64. *                                                                     
65. *              DSP 全局内存区域                                          
66. *                                                                     
67. *************************************************************************/
68./* Boot ROM */
69.//  SL3ROM(RX) o =0x20B00000 l = 0x20B20000   /* 128K  L3 ROM */
70./* EMIF 支持 NAND NOR 及 SRAM */
71./* 16位 NOR 及 SRAM 32MB 每片选(CS) */
72./*  8位 NOR 及 SRAM 16MB 每片选(CS)*/
73./* NandFlash 不受地址空间限制 */
74.//  EMIF16_CS2 o =0x70000000 l = 0x04000000   /* 64MB  数据内存 (CS2)*/
75.//  EMIF16_CS3 o =0x74000000 l = 0x04000000   /* 64MB  数据内存 (CS3)*/
76.//  EMIF16_CS4 o =0x78000000 l = 0x04000000   /* 64MB  数据内存 (CS4)*/
77.//  EMIF16_CS5 o =0x7C000000 l = 0x04000000   /* 64MB  数据内存 (CS5)*/
78.
79./* 多核共享内存及 DDR3 */
80.#ifdef SOC_C6678
81.    MSMCSRAM o = 0x0C000000 l = 0x00400000     /* 4MB   多核共享内存 (DSP C6678) */
82.    DDR3     o = 0x80000000 l = 0x40000000     /* 1GB   DDR3 (DSP C6678)*/
83.#else
84.  #ifndef SOC_C6654
85.    MSMCSRAM o = 0x0C000000 l = 0x00100000     /* 1MB   多核共享内存 (DSP C6655/57) */
86.  #endif
87.    DDR3     o = 0x80000000 l = 0x20000000     /* 512MB DDR3 (DSP C6655/57) */
88.#endif
89.}
90.
91./* 程序段分配 */
92.SECTIONS
93.{
94.    .text:_c_int00  >  0x00800000           /* C 语言入口 */
95.    .text               > DDR3                 /* 可执行代码及常数 */
96.    .cinit          >  DDR3                 /* 初始化表(全局及静态变量) */
97.    .const          >  DDR3                 /* 全局及静态常量 */
98.    .switch          > DDR3                 /* 跳转表 */
99.    .stack          >  DDR3 (HIGH)          /* 栈 */
100.    .far               >  DDR3                 /* 全局及静态变量(远) */
101.   .fardata         >  DDR3                 /* 已初始化的非静态全局及静态变量(远) */
102.   .cio             >  DDR3                 /* C 输入输出缓存 */
103.   .sysmem         >  DDR3                 /* 动态内存分配区域(堆) */
104.
105.   GROUP
106.   {
107.       .neardata                            /* 已初始化的非静态全局及静态变量(近) */
108.       .rodata                             /* 全局及静态常量(近) */
109.       .bss                                 /* 未初始化的全局及静态常量 */
110.   }                    >  DDR3
111.
112.   .L2RAM_CODE0     >   LL2RAM| MSMCSRAM   /* 自定义段[代码] */
113.   .L2RAM_CODE1     >>  LL2RAM| MSMCSRAM   /* 自定义段[代码] */
114.   .L2RAM           >   LOAD= LL2RAM, ALIGN(128), FILL = 0, START(RAM_START),END(RAM_END), SIZE(RAM_SIZE)                                       /* 自定义段[数据] */
115.   .DDR3                >   LOAD = DDR3, RUN = MSMCSRAM
116.                                                /* 自定义段[数据] */
117.
118.   .Local                                   /* 自定义段[代码] */
119.   {
120.      "*Tronlong*.ae66" (.text)
121.   }                 > L2SRAM
122.}
注释
注释可以使用 // 或者 /* */ 实现,与 C 语言一致。
条件链接
行 55 - 61,行 80 - 88。条件链接,功能与 C 语言的条件编译类似,符合条件的部分才会链接。要启用这样的条件,可以在该文件内  #define SOC_C6678 这样的宏。
或者修改全局链接宏定义。

除去注释和条件链接的部分,总体上来看这份 CMD 文件,分为三个部分,连接选项部分、内存段描述部分以及程序段分配部分。
链接选项
-heap 0x00001000 指定堆大小,对应程序段 .sysmem。也就是动态分配内存区域大小为 0x1000 即4096字节。所谓动态分配,就是我们调用 C 语言 malloc 或者类似的函数分配内存时候,就从这个区域分配,最大分配大小就是这样参数的大小。
-stack 0x00001000 指定栈大小,对应程序段 .stack。
    -l 指定库文件。需要注意的是,库文件扩展名没有影响。这里,.le66 是指 C66x 平台小端 ELF 格式文件的意思。还可以看到 .ae66 或者 .lib 格式,.a扩展名的文件一般指静态库,e66 跟 le66 含义相同,都是代表 ELF C66x 格式。
这里顺带说下,对于 DSP 的应用程序,如果引用了 RTSC 组件,编译出来的文件扩展名一般不是 .out 而是 .xe66 之类的,x 代表executable 可执行,e66 同样代表 ELFC66x 平台格式。

内存段描述
行 27 - 89。这里特别特别要注意的是,这里的描述只在当前文件有效。描述的内容不一定是完全按照数据手册来,可以根据实际需要对内存空间做出划分。比如,LL2RAM 可以分成,LL2RAM_CODE 和 LL2RAM_DATA 等等。
对于,很多 DSP 来说,C6748、C6655/57 和 C6678。DSPCPU 内部的 RAM/ROM 往往会被映射到两个地址,一个本地地址和一个全局地址。本地地址仅能够被当前 CPU 核心访问当前 CPU 的片上内存,而全局地址可以被所有 CPU 核心,以及外设访问。
从 C6748 的内存映射表格可以明显看出来[TMS320C6748定点与浮点数字信号处理器 (Rev. F) 20页](只截取了需要的部分)。
......

表格的表头部分,DSP、EDMA、PRUSS、主外设、LCDC 这些都是可以主动发起内存访问请求的。表格中,灰色的部分是该模块无法访问的内存区域。可以看到,0x00700000 - 0x0184FFFF 这段空间只能被 DSP 访问,而其中的 L1/L2 RAM/ROM 同时被映射到 0x11700000 -0x11F07FFF 全局地址,而这部分地址可以被除了 LCDC 以外的模块访问。所以,在使用的时候要注意如果需要 DSP CPU 和 EDMA 或者其它外设都可以访问的数据,要使用全局地址。
此外,这里描述的仅仅是可以被用地址方式访问的内存空间。像 NandFlash 这样通过 I/O 协议访问的设备,在这里描述没有意义。
程序段分配
行 92 - 122。第 92 行,.text:_c_int00 代表为 .text 段的子段 _c_int00 分配一个固定地址 0x00800000。一般情况下,这里都是指定一个内存段名,也就是 MEMORY 伪指令描述的内存区域。但在某些情况下,如果需要某个段起始地址固定,可以这样指定。
在 OMAPL138 中,DSP 程序的入口地址必须对齐到 1K 边界,入口地址对于 C 语言来说,就是 _C_int00 函数的起始地址,这是一个用于初始化 C 语言环境的函数。我们可以,指定固定 1K 对齐的地址给这个函数,比如 0x11800000。方法就是通过这样来实现。
对于,多核 DSP 处理器 C6655/57 以及 C6678 来说也有这样的需求,为了多核启动方面往往也需要固定分配入口地址。
第 99 行,(HIGH) 关键字,括号可以省略。代表为栈空间在指定的内存空间中往高地址分配。
未添加该关键字
......
MSMCSRAM              0c100000   00100000 000130fa  000ecf06  RWIX
......
0c10ff40    0c10ff40   00001000   00000000    rw- .stack

添加该关键字
......
MSMCSRAM              0c100000   00100000 000130fa  000ecf06  RWIX
......
0c1ff000    0c1ff000   00001000   00000000    rw- .stack

第 105 - 110 行,GROUP 关键字,用于为一组段连续分配空间。在 ELF 格式镜像中,这三个段必须放到一起,否则会出现警告,当然前提是应用程序中用到了这些段。
GROUP
{
    .neardata
    .rodata
    .bss
}   

第 112 - 113 行,这是自定义段,段的名称随便取即可“.” 加不加都可以,不是必须的。
   .L2RAM_CODE0      >   LL2RAM| MSMCSRAM
| 的意思代表,当前程序段可以分配到后面多个内存段当中,可以指定一个、两个、三个.....内存段。需要注意的是,存在先后顺序,分配的时候第一个内存段能放下就全部方下,放不下就尝试第二个,然后第三个.....第 N 个。
   .L2RAM_CODE1      >>  LL2RAM| MSMCSRAM
与上一行有一个符号的差别, > 和 >> 区别是后者会拆分程序段,然后把它们分别放到后面的内存段中,直到把所有的数据分配完。
第 114 行,
.L2RAM        >   LOAD= LL2RAM, ALIGN(128), FILL = 0, START(RAM_START), END(RAM_END), SIZE(RAM_SIZE)   
这一个段,指定了一些额外参数。
ALIGN(128) 段起始地址对齐到 128 字节,一般很多算法或者高速外设 PCIe SRIO 等等,为了保证效率都会要求内存对齐。
FILL = 0 填充段的内容为指定值,这个要注意的是如果段太大,会消耗比较长时间。
START(RAM_START),END(RAM_END), SIZE(RAM_SIZE) 如果在应用程序代码中需要知道这些段的地址、大小,可以通过这种方式定义变量。注意,这里指的是运行地址。
在 C 代码中可以这样使用
externunsignedintfar RAM_START;
externunsignedintfar RAM_END;
externunsignedintfar RAM_SIZE;
第 115 行,
.DDR3            >   LOAD= DDR3, RUN = MSMCSRAM
这里为段,指定了不同的加载地址和运行地址。这个,主要的需求是高速 RAM 空间比较小,但是执行代码比较大,所以把整个代码先加载到大容量内存中,需要的时候再分割后复制到高速内存,从而提高效率。不过,复制操作需要应用程序完成。
上面定义了那么多自定义段,但是究竟该怎么分配呢?这时候,需要用到编译器伪指令。
CODE_SECTION
DATA_SECTION
SET_CODE_SECTION
SET_DATA_SECTION
当然伪指令有很多,这里只需要这四个就够了。
CODE_SECTION 用于为单个函数分配内存空间。
1.#pragma CODE_SECTION(fn, ".L2RAM_CODE0")
2.int fn(int x)
3.{
4.    return x;
5.}
但是如果需要一次性分配多个函数,需要使用 SET_CODE_SECTION。需要分配的函数声明,放在两条预编译指令中间,需要注意的是CODE_SECTION 设置可以覆盖 SET_CODE_SECTION设置。
1.#pragma SET_CODE_SECTION(".L2RAM_CODE0")
2.extern void func1();
3.extern void func2();
4.extern void func3();
5.#pragma SET_CODE_SECTION()
6....
7.void func1() { ... }
8.void func2() { ... }
9.void func3() { ... }
上面所述是为代码分配空间,那么怎么为数据分配空间呢?类似的,使用 CODE_SECTION 用于为单个变量分配内存空间。
1.#pragma DATA_SECTION(bufferB, ".L2RAM")
2.char bufferA[512];
3.char bufferB[512];
但是如果需要一次性分配多个变量,需要使用 SET_DATA_SECTION。需要分配的函数声明,放在两条预编译指令中间,需要注意的是DATA_SECTION 设置可以覆盖 SET_DATA_SECTION设置。
1.#pragmaSET_DATA_SECTION(".L2RAM")
2.int x;
3.int y;
4.#pragmaSET_DATA_SECTION()

第 118 - 121 行
.Local
{
     "*Tronlong*.ae66" (.text)
}                    >L2SRAM
这里是把指定库中的指定段,重新分配内存空间。* 是通配符,代表任意字符。这里的意思是,包含有 Tronlong 字符的所有引用的库文件中的所有 .text 段,重新分配到 L2SRAM 中。这样,覆盖了之前对于 .text 的分配。
有关 CMD 文件的基本内容就讲这么多了。实际上 CMD 文件的灵活性是很强的,还有很多其它的用法,感兴趣的话可以参阅 TMS320C6000Assembly Language Tools v7.4 User's Guide 章节7.5 Linker Command Files。有关更多预编译指令的使用方法,可以参阅TMS320C6000 Optimizing Compiler v7.4 User's Guide 章节 6.9 Pragma Directives
如果有机会,还可以给大家讲讲在 RTSC 组件或者说 SYS/BIOS 下 CMD 文件的使用。
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|嵌入式开发者社区 ( 粤ICP备15055271号

GMT+8, 2024-5-3 21:16 , Processed in 0.045501 second(s), 29 queries .

Powered by Discuz! X3.2

© 2001-2015 Comsenz Inc.

快速回复 返回顶部 返回列表