3. TriCore内核编程模型
TriCore 的编程模型可以理解为“一套寄存器窗口 + 一套特权分级 + 一套中断与上下文机制”的组合。要写出可运行的启动代码,必须先把这三件事对齐:CPU 复位后从哪个地址取第一条指令、哪些寄存器在函数调用和中断中必须保存、以及代码运行在什么特权级别上。本节以 AURIX TC3xx 为例,围绕这些对象展开,并给出一段可参考的启动流程。
一、内核寄存器组与调用约定
TriCore 的通用寄存器为 D0–D15(32 位数据寄存器)和 A0–A15(32 位地址寄存器),其中 A0、A1、A8、A9 具有隐含用途:A0 为全局数据指针(小数据区基址),A1 为栈指针 SP,A8 为返回地址寄存器(函数调用时保存返回地址),A9 为上下文指针,用于保存上层上下文。A10 在部分工具链中作为栈边界或帧指针使用,A11 常作为隐式参数指针。D0、D1 用于函数返回值,D2、D3 在除法等指令中作为高低位配对。
调用约定上,D0–D7 与 A2–A7 属于调用者保存(caller-saved),被调用函数可以自由改写;D8–D15 与 A10–A15 属于被调用者保存(callee-saved),函数若使用必须先压栈、返回前恢复。A8 由 call 指令自动写入返回地址,A9 由中断或上下文切换机制使用。理解这一点,才能判断中断入口处到底需要保存哪些寄存器。
二、特权模式与保护机制
TriCore 将执行权限分为两种:Supervisor Mode(管理模式)和 User Mode(用户模式)。复位后 CPU 处于管理模式,可访问全部系统寄存器(如 PCXI、PSW、ISP、ICR)和全部地址空间。用户模式下访问系统寄存器或受保护外设会触发保护陷阱(Protection Trap)。
PSW(程序状态字)中的 CDC、S、IO 等位控制当前上下文与中断使能状态。进入中断时硬件自动切换到中断栈(ISP),并把当前上下文指针写入 PCXI。若在用户模式下发生中断,硬件会先切回管理模式再取向量。因此启动代码必须在初始化阶段完成栈指针设置、PSW 配置和必要的 MPU 设置,否则后续任何中断或系统调用都会失败。
三、中断向量与上下文切换
TriCore 的中断向量表由 BIV(Base Interrupt Vector Table)寄存器指定基址。每个中断源对应一个向量入口,入口处通常只放一条跳转指令,跳到实际的中断服务程序(ISR)。中断发生时,硬件自动完成:保存 PCXI、切换 ISP、压入返回地址与 PSW,然后跳转到 BIV + 偏移。ISR 返回时使用 rfe(Return From Exception)指令恢复上下文。
上下文切换的核心是 PCXI(Previous Context Information)与 CSA(Context Save Area)。每个上下文块包含 16 个字,保存 A0–A15 与 D0–D15 中的部分寄存器。硬件在中断或函数调用时按需分配 CSA 块,通过 PCXI 形成链表。若 CSA 空间不足,会触发上下文溢出陷阱(Context Overflow),此时需要在陷阱处理中扩展 CSA 或调整 CSA 列表。启动代码必须为 CSA 预留足够空间,并初始化 FCX(Free Context List)与 LCX(Limit Context List)指针。
四、启动代码的编写要点
启动代码通常分为复位入口、C 运行时初始化、主函数调用三部分。复位入口必须放在链接脚本指定的地址(如 0xA0000000),第一条指令通常是跳转到真正的启动代码。以下是一段参考结构,参数为示例值,实际需按芯片手册和链接脚本调整。
/* 复位入口:跳转到 _start */
.section .reset, "ax"
.global _reset
_reset:
j _start
/* 启动代码 */
.section .startup, "ax"
.global _start
_start:
/* 1. 设置栈指针:A1 = SP,A9 = 上下文指针 */
movh.a %a1, 0x7000 /* 示例:栈顶 0x70000000 */
lea %a1, [%a1]0x0000
movh.a %a9, 0x7001 /* 示例:上下文区基址 */
lea %a9, [%a9]0x0000
/* 2. 初始化 CSA:FCX 指向空闲块,LCX 设上限 */
movh.a %a2, 0x7002
lea %a2, [%a2]0x0000
mtcr %a2, $fcx
movh.a %a3, 0x7003
lea %a3, [%a3]0x0000
mtcr %a3, $lcx
/* 3. 配置 BIV:向量表基址 */
movh.a %a4, 0x8000
lea %a4, [%a4]0x0000
mtcr %a4, $biv
/* 4. 切换到管理模式并开中断 */
mfcr %d0, $psw
or %d0, %d0, 0x0000 /* 示例:保持管理模式 */
mtcr %d0, $psw
enable
/* 5. 跳转到 C 入口 */
j main
这段代码的关键点在于:栈指针和上下文指针必须在任何函数调用之前设置,因为 C 函数会使用 A1 和 A9;CSA 的 FCX/LCX 必须在使能中断之前初始化,否则第一个中断就会触发上下文溢出;BIV 必须在使能中断之前写入,否则向量表指向未定义地址。使能中断用 enable 指令,对应 PSW 的 IO 位。
五、常见问题与判断依据
启动代码调试时,最常见的现象是“复位后直接进入陷阱”或“第一个中断后跑飞”。判断方法:若复位后立即进入陷阱,检查 BIV 是否已写入、栈指针是否指向有效 RAM;若中断后跑飞,检查 CSA 空间是否足够、FCX 链表是否初始化、ISR 是否以 rfe 结尾。另一个常见问题是用户模式下访问外设寄存器触发保护陷阱,此时需要确认 PSW 的 S 位是否仍为管理模式,或是否已正确配置 MPU 允许该外设访问。
总结来看,TriCore 内核编程模型的核心是“寄存器—特权—上下文”三者的联动。寄存器决定函数调用和中断保存的边界,特权模式决定哪些指令和地址可访问,上下文机制决定中断和任务切换时现场如何保存与恢复。启动代码的任务就是按正确顺序把这三者初始化到位,使后续的 C 代码和中断服务程序能够正常运行。