C28x 上下文保存和恢复
介绍
本文介绍了 C28x CPU 的自动上下文保存/恢复。这也适用于带有 FPU 和 VCU 扩展的设备。
其他资源
上下文保存和恢复的详细内容在 《C28x TMS320C28x CPU 和指令集参考指南》(TMS320C28x CPU and Instruction Set Reference Guide (Rev. F)-spru430f.pdf)文档中。
堆栈 基础
首先是关于 C28x 堆栈指针的一些事实:
- C28x 堆栈指针 (SP) 始终指向堆栈中的第一个空地址。
- C28x 堆栈从低地址增长到高地址。
- 上下文保存执行 32 位 PUSH 操作(不是 16 位)。
- 上下文还原执行 32 位 POP 操作(不是 16 位)。
- 堆栈指针本身是 16 位。因此堆栈必须始终位于低内存中,不得超过地址 0xFFFF。
32 位写入和读取
32 位写入和读取在 C28x 上始终是偶数对齐的。也就是说,无论写入到哪个地址,32 位值都使用偶数地址和下一个奇数地址。这适用于 C28x 上的所有 32 位读/写。您永远不会看到 32 位值使用奇数位置和下一个偶数位置。
下图显示了对偶数地址的 32 位 PUSH:
下图显示了 32 位 PUSH 到奇数地址。 请注意,写入是偶数对齐的,并且与堆栈指针指向前一个偶数地址相同。
注意:如果在push之前0xC140位置有数据,会被覆盖!! 我们将在下一节中使用这些知识。
说明:
在PUSH ACC之前,SP指向地址C141(奇数)。本来,希望将32位的ACC保存到C141和C142.但是,实际上,却保存到C140和C141了。PUSH之后,SP加了2,指向C143.
自动上下文保存
当 CPU 接受中断时,无法知道堆栈指针 (SP) 是偶数还是奇数。正如我们在上一节中看到的,如果 SP 是奇数,那么上下文保存有可能覆盖堆栈中已经存在的先前值。
为了解决这个问题,自动上下文保存将首先将堆栈增加 1。这保证了保存的数据不会覆盖堆栈中已有的内容。
堆栈指针加1后,会自动将多个寄存器压入堆栈。这些寄存器记录在《TMS320C28x CPU 和指令集参考指南》中。每次推送都是对内存的 32 位写入。这在 C28x 上始终保持一致;一个 32 位的字总是占用一个偶数和下一个奇数。
下图显示了在中断发生时堆栈指针为奇数时的保存。请注意,向 SP 加 1 可防止第一个 PUSH 覆盖地址 0xC140 中的任何数据。
ISR 中的第一条指令应始终是 ASP 指令。如果你用 C 编写,那么编译器会自动为你添加 ASP(参见附录2)。如果 SP 是奇数对齐,则 ASP 指令会将其加 1,以便它是偶数对齐。在下面所示的情况下,ISR 中的 ASP 指令不起作用。然而,它仍然应该被使用,因为在发生中断时没有办法控制 SP 是偶数还是奇数。
下图显示了在中断发生时堆栈指针为偶数时的上下文保存。 在这种情况下,可以跳过保存之前向 SP 加 1,但无法知道 SP 是偶数还是奇数时发生了中断。 SP 加 1 没有不良影响。 请注意,在这种情况下,ISR 中的 ASP 指令将强制重新对齐堆栈。 这样做是为了使 ISR 内堆栈上的任何值都不会覆盖部分上下文保存。 拥有一个偶数对齐的堆栈对于 C 编译器很重要。 此外,遵循此约定可以使在汇编中编程时更容易。
请注意,在这两种情况下,每个 32 位推送都是偶数对齐的。 即无论SP指向哪个地址,它都占用一个偶数地址和下一个奇数地址。 这适用于 C28x 上的所有 32 位读/写。 您永远不会看到 32 位值使用奇数位置和下一个偶数位置。
自动上下文还原
当 IRET 指令执行时,将在代码返回到中断发生点之前进行自动上下文恢复。 自动上下文恢复只是自动上下文保存的反向操作。
在 IRET 指令之前,ISR 必须执行 NASP 指令。 这将取消由 ASP 指令执行的任何对齐。 如果您使用 C 语言编写,那么编译器会自动将 ASP 和 NASP 指令添加到您的中断服务程序中。
作为最后一步,SP 会自动减 1,因此最终回到中断发生前的位置。
附录1:ASP指令和NASP指令
SPA
先看一下ST1寄存器中的SPA位:Stack pointer alignment bit
ASP
确保堆栈指针 (SP) 与偶数地址对齐。 如果 SP 的最低有效位为 1,则 SP 指向奇数地址,必须通过将 SP 加 1 来移动。SPA 位设置为该对齐的记录。 相反,如果 ASP 指令发现 SP 已经指向偶数地址,则 SP 保持不变并且 SPA 位被清除以指示没有发生对齐。 在任何一种情况下,对 SPA 位的更改都是在流水线的解码 2 阶段进行的。
NASP
如果 SPA 位为 1,则 NASP 指令将堆栈指针 (SP) 减 1,然后清除 SPA 状态位。 这会撤销之前由 ASP 指令执行的堆栈指针对齐。 如果 SPA 位为 0,则 NASP 指令不执行任何操作。
附录2 C语言的中断服务函数生成的汇编模板
HWI_Timer0_ISR():
0120b3: 761B ASP
0120b4: FFF0 PUSH RB
0120b5: 0005 PUSH AR1H:AR0H
0120b6: ABBD MOVL *SP++, XT
0120b7: A8BD MOVL *SP++, XAR4
0120b8: A0BD MOVL *SP++, XAR5
0120b9: C2BD MOVL *SP++, XAR6
0120ba: C3BD MOVL *SP++, XAR7
0120bb: E20000BD MOV32 *SP++, STF
0120bd: E20300BD MOV32 *SP++, R0H
0120bf: E20301BD MOV32 *SP++, R1H
0120c1: E20302BD MOV32 *SP++, R2H
0120c3: E20303BD MOV32 *SP++, R3H
0120c5: E6300600 SETFLG RNDF32=1,RNDF64=1
0120c7: FF69 SPM #0
0120c8: 2942 CLRC OVM|PAGE0
0120c9: 5616 CLRC AMODE
// 以上是进入中断服务函数时的操作
//
/这中间是用户编写的中断服务函数的内容///
//
// 以下是退出中断服务函数时的操作
0120e1: E2AF03BE MOV32 R3H, *--SP, UNCF
0120e3: E2AF02BE MOV32 R2H, *--SP, UNCF
0120e5: E2AF01BE MOV32 R1H, *--SP, UNCF
0120e7: E2AF00BE MOV32 R0H, *--SP, UNCF
0120e9: E28000BE MOV32 STF, *--SP
0120eb: C5BE MOVL XAR7, *--SP
0120ec: C4BE MOVL XAR6, *--SP
0120ed: 83BE MOVL XAR5, *--SP
0120ee: 8ABE MOVL XAR4, *--SP
0120ef: 87BE MOVL XT, *--SP
0120f0: 0003 POP AR1H:AR0H
0120f1: 3B30 SETC INTM|DBGM
0120f2: FFF1 POP RB
0120f3: 7617 NASP
0120f4: 7602 IRET
参考文档
X:/ti/c2000/C2000Ware_3_04_00_00/docs/c28x_context_save_restore/html/index.html