CCS之CMD(链接命令)文件讲解

CCS之CMD(链接命令)文件讲解

CMD文件是TI编译工具链中链接器的配置文件,它通过MEMORY块声明芯片各块RAM和Flash的物理地址与大小,通过SECTIONS块将编译器生成的各种段(代码、变量、常量、栈堆等)分配到指定内存,本质上是给链接器画一张"内存地图",决定程序每个部分在芯片上电后实际存放在哪里、从哪里取指和执行。

本文以 F28388S 为例说明,不同系列芯片内存分布不同,此处仅做参考

一、C28x 与 CM 的 RAM 类型及归属

C2000 的 RAM 不是一块连续的通用内存随便用,而是按访问主体(哪个核/外设能用)、访问权限(只读/读写/取指)和延迟特性(紧耦合/共享/带 ECC)划分的。理解硬件归属是写 CMD 的前提

1.1 RAMM0 / RAMM1(专用RAM)

M0 和 M1 是 C28x 最靠近 CPU 流水线的两块紧耦合小容量 RAM,各 1K×16 = 2 KB。每个 C28x 子系统物理独立,双核工程中 CPU1 和 CPU2 各有自己的 M0/M1,互不干扰。特点是零等待,但容量极小,不适合放大块数据。

M0 的起始段(0x000002 起约 0x1AF 字)被 Boot ROM 占用,上电自举时当临时栈和变量区,这部分在 CMD 里声明为 BOOT_RSVD,用户代码绝对不能覆盖。剩余可用部分从 0x0001B1 开始,总共约 600 字,只适合放冷启动关键的小标志或查表数据。

M1 传统上放 .stack(C 函数调用栈),起始地址 0x000400,长度 0x3F8(而非 0x400),尾部 8 个字(0x07F8–0x07FF)按芯片勘误保留,防止预取越界。如果中断嵌套深或局部变量大,1K 字栈不够用,需要把栈改到 LSx 或 D0/D1 块。

1.2 RAMD0 / RAMD1(专用RAM)

D0 和 D1 各 2K×16 = 4 KB,地址分别为 0x00C000 和 0x00C800,归属本 C28x 子系统独占。与 M/LS/GS 不同,D 块带 ECC(单比特纠错、双比特报错),并且可配置写保护、取指保护和 DCSM 安全分区。

适合存放安全密钥、功能安全关键状态、不希望被 DMA 或 CLA 意外改写的变量。如果单核工程不跑安全功能,也可以当普通高速数据区,但要注意别和 CLA/DMA 共享同一块。

1.3 RAMLS0 ~ RAMLS7(本地共享RAM)

LS 块共 8 块,每块 2K×16 = 4 KB,地址范围 0x008000–0x00BFFF,合计 32KB。归属本 C28x 子系统加本 CLA 子系统,带 ECC,可通过 MemCfg 寄存器动态切换用途。默认仅供CPU使用,可通过配置选择与CLA共享这段存储器。

1.4 GSX RAM(全局共享 RAM)

GS可以有多块,如RAMGS0、RAMGS1等,每块 4K×16 = 8 KB。双 C28x 核以及各自的 DMA 都能看到这块地址空间,通过 GSxMSEL 寄存器指定主从关系。带 parity 校验(非 ECC),硬件强制主从权限。

主核(Master)可读可写可取指;从核(Slave)默认只读,写操作会触发 NMI 或被忽略。上电默认 CPU1 为所有 GS 的主人,CPU1 通过 MemCfg_setGSRAMMasterSel() 把某块判给 CPU2。

GS 适合双核大容量数据交换——通信帧缓冲、日志存储、DMA 中转等。小块核间通信不要用 GS,应当走专用消息 RAM。

1.5 消息 RAM(MSG RAM)—— 核间/外设专用邮箱

消息 RAM 不是通用 RAM,硬件固定了访问方向,只适合放命令字、状态标志、小结构体,不存放大数组。

CPU 间通信:CPU1TOCPU2RAM(0x03A000,CPU1 写→CPU2 读)和 CPU2TOCPU1RAM(0x03B000,CPU2 写→CPU1 读),各 0x800 字(4KB)。

CPU 与 CM 通信:CPUTOCMRAM(0x039000,C28x 写→CM 读)和 CMTOCPURAM(0x038000,CM 写→C28x 读),各 0x800 字。

CPU 与 CLA 通信:CLA1_MSGRAMLOW(0x001480,CPU 写→CLA 读,256 字)和 CLA1_MSGRAMHIGH(0x001500,CLA 写→CPU 读,256 字)。另有 CLA1_DMA_MSGRAM 和 DMA_CLA1_MSGRAM 各 128 字供 DMA 与 CLA 交互。

CAN 邮箱:CANA_MSG_RAM(0x049000)和 CANB_MSG_RAM(0x04B000),各 0x800 字,由 DCAN 硬件直接管理 message object。

所有消息 RAM 通常设为 type=NOINIT(上电不自动清零),配合 IPC 中断使用。

1.6 CM(Cortex-M4)独立 RAM

在高级的DSP系列中,会有ARM内核,F2838x 的 CM 子系统有自己独立的地址空间,不按 C28x 的 M/LS/GS 分类。CM 工程使用 Arm 链接脚本(.ld 格式),C28x 的 CMD 里只能声明 CPUTOCMRAM / CMTOCPURAM 消息块,不能分配 CM 的业务 RAM。

二、CMD 文件基本结构

CMD 文件只干两件事:声明物理内存(MEMORY)和分配段到内存(SECTIONS)。

2.1 SECTIONS 常见段

段名 描述
codestart 复位引导分支,跳 _c_int00/main。固定 2 字,放 BEGIN。
.reset 复位向量伪段。固定 2 字,设 TYPE=DSECT 不分配用户数据。
.text 普通函数代码。大小取决于函数数量和库的使用。代码量大时用 >> 分散到多块 RAM。
.TI.ramfunc Flash 加载、RAM 执行的关键函数。Flash 启动时需 LOAD=Flash, RUN=RAM 分离。
.switch switch-case 跳转表。通常几十字,放小块 RAM 即可。
.cinit C 全局变量初始化表。大小取决于有初值的全局变量数量。必须连续存放(用 > 不用 >>)。
.const 常量数据(const 数组、字符串等)。EABI 下使用,通常放 Flash 或 GS 块。
.econst COFF 常量数据。用法同 .const,COFF ABI 下使用。
.bss 未初始化全局/静态变量。RAM 消耗大户,启动时自动清零。
.bss:output .bss 的子段,用于将特定变量单独分配到指定 RAM 块。
.data 已初始化数据本体。运行时在 RAM,初值由 .cinit 表从 Flash 拷贝(RAM运行无需拷贝)。
.sysmem malloc 堆。大小由 --heap_size 配置,单独划一块 RAM。
.init_array C++ 构造函数表。C 工程可忽略。
.pinit COFF 下的 C++ 构造函数表。EABI 下用 .init_array 替代。
.ebss COFF 下的未初始化变量段。EABI 下用 .bss 替代。
.esysmem COFF 下的 malloc 堆。EABI 下用 .sysmem 替代。
.stack C 调用栈。取决于调用深度和中断嵌套。传统放 RAMM1,不够时改 LS/D 块。
MSGRAM_CPU1_TO_CPU2 CPU1→CPU2 核间消息区。单向邮箱,设 type=NOINIT。
MSGRAM_CPU2_TO_CPU1 CPU2→CPU1 核间消息区。单向邮箱,设 type=NOINIT。
MSGRAM_CPU_TO_CM C28x→CM 核间消息区。单向邮箱,设 type=NOINIT。
MSGRAM_CM_TO_CPU CM→C28x 核间消息区。单向邮箱,设 type=NOINIT。
ramgs0 用户自定义段,放 RAMGS0,设 type=NOINIT。用于精确控制变量位置。
ramgs1 用户自定义段,放 RAMGS1,设 type=NOINIT。用于精确控制变量位置。
dclfuncs DCL(数字控制库)函数段。放高速 RAM 以保证控制周期性能。

上表中 ramgs0、ramgs1 等为用户自定义段,配合 #pragma DATA_SECTION 可将变量精确放置到指定 RAM 块:

#pragma DATA_SECTION(adcAResult, "ramgs0")
volatile uint16_t adcAResult[6];  // 变量固定分配到 RAMGS0

CLA 相关段名多为用户/库自定义,核心仅两点:Cla1Prog 独占 LS0(CLA 程序模式),共享数据放 LS1/LS2。实际工程按需删减即可,下文示例仅作参考。

2.4 示例

以下为 RAM 启动配置(F28388S 的 CPU1+CLA),所有段直接下载到 RAM,上电即用。

MEMORY
{
   /* BEGIN is used for the "boot to SARAM" bootloader mode   */
   BEGIN            : origin = 0x000000, length = 0x000002
   BOOT_RSVD        : origin = 0x000002, length = 0x0001AF     /* Part of M0, BOOT rom will use this for stack */
   RAMM0            : origin = 0x0001B1, length = 0x00024F
   RAMM1            : origin = 0x000400, length = 0x0003F8     /* on-chip RAM block M1 */
//   RAMM1_RSVD       : origin = 0x0007F8, length = 0x000008     /* Reserve and do not use for code as per the errata advisory "Memory: Prefetching Beyond Valid Memory" */
   RAMD0            : origin = 0x00C000, length = 0x000800
   RAMD1            : origin = 0x00C800, length = 0x000800
   RAMLS0           : origin = 0x008000, length = 0x000800
   RAMLS1           : origin = 0x008800, length = 0x000800
   RAMLS2           : origin = 0x009000, length = 0x000800
   RAMLS3           : origin = 0x009800, length = 0x000800
   RAMLS4           : origin = 0x00A000, length = 0x000800
   RAMLS5           : origin = 0x00A800, length = 0x000800
   RAMLS6           : origin = 0x00B000, length = 0x000800
   RAMLS7           : origin = 0x00B800, length = 0x000800
   RAMGS0           : origin = 0x00D000, length = 0x001000
   RAMGS1           : origin = 0x00E000, length = 0x001000
   RAMGS2           : origin = 0x00F000, length = 0x001000
   RAMGS3           : origin = 0x010000, length = 0x001000
   RAMGS4           : origin = 0x011000, length = 0x001000
   RAMGS5           : origin = 0x012000, length = 0x001000
   RAMGS6           : origin = 0x013000, length = 0x001000
   RAMGS7           : origin = 0x014000, length = 0x001000
   RAMGS8           : origin = 0x015000, length = 0x001000
   RAMGS9           : origin = 0x016000, length = 0x001000
   RAMGS10          : origin = 0x017000, length = 0x001000
   RAMGS11          : origin = 0x018000, length = 0x001000
   RAMGS12          : origin = 0x019000, length = 0x001000
   RAMGS13          : origin = 0x01A000, length = 0x001000
   RAMGS14          : origin = 0x01B000, length = 0x001000
   RAMGS15          : origin = 0x01C000, length = 0x000FF8
//   RAMGS15_RSVD     : origin = 0x01CFF8, length = 0x000008     /* Reserve and do not use for code as per the errata advisory "Memory: Prefetching Beyond Valid Memory" */

   /* Flash sectors */
   FLASH0           : origin = 0x080000, length = 0x002000	/* on-chip Flash */
   FLASH1           : origin = 0x082000, length = 0x002000	/* on-chip Flash */
   FLASH2           : origin = 0x084000, length = 0x002000	/* on-chip Flash */
   FLASH3           : origin = 0x086000, length = 0x002000	/* on-chip Flash */
   FLASH4           : origin = 0x088000, length = 0x008000	/* on-chip Flash */
   FLASH5           : origin = 0x090000, length = 0x008000	/* on-chip Flash */
   FLASH6           : origin = 0x098000, length = 0x008000	/* on-chip Flash */
   FLASH7           : origin = 0x0A0000, length = 0x008000	/* on-chip Flash */
   FLASH8           : origin = 0x0A8000, length = 0x008000	/* on-chip Flash */
   FLASH9           : origin = 0x0B0000, length = 0x008000	/* on-chip Flash */
   FLASH10          : origin = 0x0B8000, length = 0x002000	/* on-chip Flash */
   FLASH11          : origin = 0x0BA000, length = 0x002000	/* on-chip Flash */
   FLASH12          : origin = 0x0BC000, length = 0x002000	/* on-chip Flash */
   FLASH13          : origin = 0x0BE000, length = 0x002000	/* on-chip Flash */
   CPU1TOCPU2RAM    : origin = 0x03A000, length = 0x000800
   CPU2TOCPU1RAM    : origin = 0x03B000, length = 0x000800

   CPUTOCMRAM       : origin = 0x039000, length = 0x000800
   CMTOCPURAM       : origin = 0x038000, length = 0x000800

   CANA_MSG_RAM     : origin = 0x049000, length = 0x000800
   CANB_MSG_RAM     : origin = 0x04B000, length = 0x000800
   RESET           	: origin = 0x3FFFC0, length = 0x000002

   CLA1_MSGRAMLOW   : origin = 0x001480,   length = 0x000080
   CLA1_MSGRAMHIGH  : origin = 0x001500,   length = 0x000080
   CLA1_DMA_MSGRAM  : origin = 0x001680,   length = 0x000080
   DMA_CLA1_MSGRAM  : origin = 0x001700,   length = 0x000080
}


SECTIONS
{
   /* 复位与入口 */
   codestart        : > BEGIN
   .reset           : > RESET, TYPE = DSECT

   /* ========== 代码段 ========== */
   /* RAM启动:所有代码进RAM,铺到D0/D1/LS/GS大块 */
   .text            : >> RAMD0 | RAMD1 | RAMLS2 | RAMLS3 | RAMLS4 | RAMLS5 | RAMLS6 | RAMLS7 | RAMGS0
   .TI.ramfunc      : >> RAMD0 | RAMGS0          /* RAM启动下并入大块RAM */
   .switch          : > RAMM0                   /* 跳转表,很小,留M0 */

   /* ========== 初始化与常量 ========== */
   .cinit           : >  RAMGS1         	     /* 初始化表,给足空间 */
   .const           : >> RAMGS2 | RAMGS3         /* EABI常量 */
   .econst          : >> RAMGS2 | RAMGS3         /* COFF常量 */

#if defined(__TI_EABI__)
   .bss             : >> RAMGS3 | RAMGS4 | RAMGS5   /* 未初始化变量,大块GS */
   .bss:output      : >  RAMGS3
   .data            : >> RAMGS3 | RAMGS4            /* 已初始化数据 */
   .sysmem          : >  RAMGS6                    /* malloc堆 */
   .init_array      : >  RAMM0                     /* C++构造,很小 */
#else
   .pinit           : >  RAMM0
   .ebss            : >> RAMGS3 | RAMGS4 | RAMGS5   /* COFF未初始化变量 */
   .esysmem         : >  RAMGS6
#endif

   /* ========== 栈 ========== */
   .stack           : > RAMM1                     /* 1K字栈,够用 */

   /* ========== 核间消息RAM(NOINIT) ========== */
   MSGRAM_CPU1_TO_CPU2 : > CPU1TOCPU2RAM, type=NOINIT
   MSGRAM_CPU2_TO_CPU1 : > CPU2TOCPU1RAM, type=NOINIT
   MSGRAM_CPU_TO_CM    : > CPUTOCMRAM,    type=NOINIT
   MSGRAM_CM_TO_CPU    : > CMTOCPURAM,    type=NOINIT

   /* ========== CLA 配置 ========== */
   /* CLA程序:独占LS0,CPU不能当数据访问 */
   Cla1Prog         : > RAMLS0

   /* CLA共享数据:LS1+LS2 */
   Cla1DataRam      : >> RAMLS1 | RAMLS2
   CLADataLS0       : > RAMLS1
   CLADataLS1       : > RAMLS2
   *****ared       : > RAMLS1
   .bss_cla         : > RAMLS1
   .const_cla       : > RAMLS1

   /* CLA消息RAM —— 修正方向 */
   CpuToCla1MsgRAM  : > CLA1_MSGRAMLOW,  type=NOINIT   /* CPU写→CLA读,LOW块 */
   Cla1ToCpuMsgRAM  : > CLA1_MSGRAMHIGH, type=NOINIT   /* CLA写→CPU读,HIGH块 */
   Cla1ToDmaMsgRAM  : > CLA1_DMA_MSGRAM, type=NOINIT
   DmaToCla1MsgRAM  : > DMA_CLA1_MSGRAM, type=NOINIT

   /* CLA编译器要求的scratch区 */
   CLAscratch       :
   {
      *.obj(CLAscratch)
      . += CLA_SCRATCHPAD_SIZE;
      *.obj(CLAscratch_end)
   } > RAMLS2

   .scratchpad      : > RAMLS2

   /* ========== 用户自定义GS区 ========== */
   ramgs0           : > RAMGS0, type=NOINIT
   ramgs1           : > RAMGS1, type=NOINIT

   /* ========== 其他 ========== */
   dclfuncs         : >> RAMD0 | RAMGS0          /* DCL库函数,放高速RAM */
}

posted @ 2026-10-22 19:13  比特向阳  阅读(3)  评论(0)    收藏  举报