TMS320C28x汇编:替换LCR指令实现地址入栈供ExitBoot加载
问题根源
你碰到的启动数据损坏问题,根源是LCR指令执行时会自动把返回地址压进硬件栈,后面ExitBoot流程重置栈指针、初始化栈空间的时候,会把这部分提前压入的残留地址当成栈初始化内容,导致栈数据错位、内存异常。
汇编侧修改方案(替换LCR、无栈污染跳转)
你不需要手动压栈传地址,也别直接用LB _c_int00跳过ExitBoot的标准初始化流程——ExitBoot本身的逻辑就是从ACC寄存器读入口地址,完成栈重置、寄存器清零、状态寄存器恢复后,通过LRETR跳转到入口,全程不会产生多余的栈写入。
- 修改
codestart段的分支逻辑,把直接跳_c_int00的代码替换为「加载入口地址到ACC + 跳转到ExitBoot」:code_start: .if WD_DISABLE == 1 LB wd_disable ;Branch to watchdog disable code .else ; 删除原有的LB _c_int00指令,替换为以下两行 MOVL ACC, #_c_int00 ; 把_c_int00的入口地址加载到ACC寄存器 BF ExitBoot, UNC ; 无条件跳转到ExitBoot完成初始化 .endif - 修改
wd_disable段的尾部逻辑,删掉提前跳转_c_int00的指令,让代码走到加载地址、跳ExitBoot的流程:wd_disable: SETC OBJMODE ;Set OBJMODE for 28x object code EALLOW ;Enable EALLOW protected register access MOVZ DP, #7029h>>6 ;Set data page for WDCR register MOV @7029h, #0068h ;Set WDDIS bit in WDCR to disable WD EDIS ;Disable EALLOW protected register access ; 删除原有的LB _c_int00指令,替换为以下两行 MOVL ACC, #_c_int00 ; 加载入口地址到ACC BF ExitBoot, UNC ; 跳转到ExitBoot
这套逻辑和TI官方BootROM的跳转流程完全一致,不会产生多余的栈操作,从根源避免数据损坏。
C函数侧操作:将地址存入ACC寄存器的方法
针对TMS320C28x架构的TI C2000编译器,有两种不需要复杂汇编适配的实现方式:
- 利用编译器默认调用约定(无额外汇编代码)
C28x编译器的默认规则是:32位宽度的函数返回值默认存放在ACC寄存器中。你只要定义一个返回void*类型指针的函数,把需要跳转的入口地址作为返回值返回,编译器会自动把地址加载到ACC中,示例:
汇编侧调用这个函数后,不需要额外操作,ACC里已经存好入口地址,直接跳// 函数返回32位指针,返回值自动存入ACC void* GetBootEntryAddr(void) { // 可以返回_c_int00、main,也可以返回固定地址的APP入口,比如return (void*)0x300000; return (void*)_c_int00; }ExitBoot即可。 - 内联汇编直接赋值(可控性更高)
如果需要直接在C代码中完成地址加载和跳转,可以用内联汇编直接操作ACC,注意提前声明ExitBoot为外部符号:// 声明外部汇编实现的ExitBoot extern void ExitBoot(void); void JumpToEntry(uint32_t entry_addr) { // 把传入的入口地址直接加载到ACC asm("MOVL ACC, @_entry_addr"); // 直接跳转到ExitBoot完成启动 asm("BF ExitBoot, UNC"); }
注意:C28x的程序地址为22位宽度,存入ACC时使用低22位、高10位保留为0即可,使用
MOVL指令加载地址时,编译器会自动处理地址对齐,不需要手动移位。
内容的提问来源于stack exchange,提问作者HansPeterLoft
相关产品推荐
相关产品推荐

