4. 多核启动脚本编写

多核调试与单核调试最大的差别,不在于“能不能连上”,而在于“连上之后,调试器是否知道每个核此刻处于什么状态、由谁控制、下一步该对谁下命令”。TRACE32 的启动脚本(通常保存为 .cmm)正是用来把这件事一次说清楚的地方。本节围绕 SYStem.CPU、SYStem.MultiCore、CORE.select 三条核心命令,讲清它们各自解决什么问题,以及如何按正确顺序组织成一段可复用的启动序列。

三条命令的职责边界

先明确分工,避免把命令堆在一起却不知道谁在起作用。

  • SYStem.CPU:声明当前调试会话面向的处理器类型。它决定调试器使用哪套内核寄存器模型、哪套断点/观察点资源描述、以及默认的复位与运行控制方式。多核场景下,它通常先声明主核(或首个被调试的核)的 CPU 类型。
  • SYStem.MultiCore:声明这是一个多核系统,并给出核间拓扑与同步方式。它告诉调试器“这里不止一个核,它们之间如何被统一控制”,是后续按核选择、按核复位、按核运行的前提。
  • CORE.select:在已经建立的多核会话中,把“当前操作对象”切换到指定核。之后执行的寄存器读写、断点设置、单步、运行/停止,默认都作用于被选中的核。

三者的关系可以概括为:SYStem.CPU 定义“是什么核”,SYStem.MultiCore 定义“有几个核、怎么协同”,CORE.select 定义“现在操作哪一个核”。顺序颠倒或缺失,往往表现为“能连上但选不中核”“断点只在一个核生效”“复位后其他核跑飞”等典型问题。

多核启动脚本命令序列与作用域 ① 声明处理器 SYStem.CPU <type> 确定内核模型 / 断点资源 确定复位与运行控制方式 作用域:整个调试会话 ② 声明多核拓扑 SYStem.MultiCore <mode> 核数量 / 同步方式 / 主从关系 建立统一控制通道 作用域:全部核 ③ 选择目标核 CORE.select <n> 切换当前操作对象 后续命令默认作用于该核 作用域:单个核 CORE.select 在多核阵列中的切换效果 CORE 0 主核 / 引导核 复位入口 CORE 1 从核 等待唤醒 CORE 2 从核 等待唤醒 CORE 3 从核 等待唤醒 当前选中:CORE 1 典型启动序列(顺序不可随意调换) SYStem.CPU → SYStem.MultiCore → CORE.select 0 → 复位/加载 → CORE.select n → 按核调试 先声明“是什么”,再声明“有几个”,最后声明“操作谁”;复位与加载通常在主核完成后再逐核接管。 若先 CORE.select 后 MultiCore,选择可能落在未建立的会话上,导致命令无效或作用到错误核。

启动序列的组织原则

把三条命令串起来时,遵循“先声明、后选择、再操作”的层次。一个可参考的骨架如下(参数为示例,需按实际芯片手册替换):

; 1. 声明处理器类型
SYStem.CPU CortexA53

; 2. 声明多核拓扑与同步方式
SYStem.MultiCore SMP4      ; 示例:4 核 SMP 结构

; 3. 建立调试会话
SYStem.Up

; 4. 选择主核,完成系统级初始化
CORE.select 0
SYStem.Up
Data.LOAD.Elf boot.elf /NoClear

; 5. 逐核接管,设置各自断点
CORE.select 1
Break.Set core1_main

CORE.select 2
Break.Set core2_main

CORE.select 3
Break.Set core3_main

; 6. 回到主核统一运行
CORE.select 0
Go

这里有几个容易踩的坑。第一,SYStem.MultiCore 必须在 SYStem.Up 之前声明,否则调试器会按单核会话建立连接,之后再补声明往往需要重新初始化。第二,CORE.select 只改变“当前操作对象”,不会自动让该核停止或运行;如果目标核还在运行,直接读寄存器可能读到不一致的值,通常先 Break 或 Halt 再操作。第三,主核与从核的复位入口不同,从核常处于等待唤醒状态,脚本里应明确“先主核、后从核”的接管顺序,而不是一次性对所有核下同一命令。

参数与模式的选择依据

SYStem.MultiCore 的模式参数决定了核间同步的粒度。常见取值包括 SMP(对称多处理,核间共享一致视图)与 AMP(非对称多处理,各核独立运行不同镜像)。选择依据是软件架构:如果多个核跑同一份 OS 且共享内存,用 SMP 模式更便于统一断点和统一步进;如果各核跑独立固件、互不共享地址空间,用 AMP 模式分别管理更清晰。选错模式不会立刻报错,但会在“单步时其他核是否跟随停止”“断点是否在所有核生效”上表现出差异,调试时容易误判为硬件问题。

CORE.select 的编号与芯片的物理核编号一致,但要注意某些架构存在“核簇(cluster)”概念,编号可能是“簇号+核号”的组合。脚本中建议用注释标明每个编号对应的物理核,避免换芯片后编号错位。

建议把启动脚本拆成两段:init.cmm 负责 SYStem.CPU 与 SYStem.MultiCore 的声明,attach.cmm 负责 CORE.select 与断点设置。这样换芯片时只改 init,调试逻辑复用 attach。

结果如何判断

脚本执行后,不要只看“没有报错”就认为成功。应逐项确认:SYStem.CPU 后,寄存器窗口显示的内核名称与目标一致;SYStem.MultiCore 后,核列表中出现预期数量的核且状态可读;每次 CORE.select n 后,寄存器窗口标题或核指示器切换到对应编号;在各核设置的断点,能在对应核运行时命中,且不会误触发到其他核。若出现“断点只在 CORE 0 命中”,优先检查 MultiCore 模式是否声明正确、以及断点是否在正确的核上下文中设置。