嵌入式系统/ARM 微处理器
ARM 架构是一种广泛使用的 32 位 RISC 处理器架构。事实上,ARM 系列约占所有 32 位 CPU 的 75%,约占所有嵌入式 32 位 CPU 的 90%。ARM 有限公司将几个流行的微处理器核心授权给许多供应商(ARM 不出售物理微处理器)。最初,ARM 代表高级精简指令集机器。
ARM 提供的一些核心
- ARM7TDMI
- ARM9
- ARM11
一些基于 ARM 的处理器的示例
- 英特尔 X-Scale(PXA-255 和 PXA-270),用于 Palm PDA
- 飞利浦 LPC2000 系列 (ARM7TDMI-S 核心),LPC3000 系列 (ARM9 核心)
- Atmel AT91SAM7 (ARM7TDMI 核心)
- 意法半导体 STR710 (ARM7TDMI 核心)
- 飞思卡尔 MCIMX27 系列 (ARM9 核心)
最便宜的 ARM 处理器(LPC2000 系列)的价格已降至 5 美元以下,低于许多 16 位和 8 位微处理器的价格。
在 ARM Thumb 代码中,16 个寄存器 r0 - r15 通常在所有 ARM 代码中具有相同的角色
- r0 - r3,称为 a1 - a4:参数/临时/结果寄存器。
- r4 - r9,称为 v1 - v6:变量
- r10,称为 sl:堆栈限制
- r11,称为 fp:帧指针(通常在 Thumb 代码中不使用)
- r12,称为 ip
- r13,称为 sp:堆栈指针
- r14,称为 lr:链接寄存器
- r15,称为 pc:程序计数器
ARM Thumb 的标准 C 调用约定是:[1]
当返回地址放置在 pc (r15) 中时,从子程序返回时,sp、fp、sl 和 v1-v6 寄存器必须包含与调用子程序时相同的
每个执行环境都对堆栈在内存中下降的范围有限制——“最小 sp”。
为了让中断(可能在任何时候发生)有空间工作,在任何时刻,sp 和“最小 sp”之间的内存必须不包含对正在执行的程序
应用程序及其库支持代码负责检测和处理堆栈溢出的系统称为“显式堆栈限制”。在这样的系统中,sl 寄存器必须始终
子程序可以随意覆盖 a1-a4、ip 和 lr。
如果子程序返回一个不超过一个字的简单值,则该值必须在 a1 (r0) 中。
如果子程序返回一个简单的浮点值,则该值编码在 a1 中;或者 {a1, a2} 中;或者 {a1, a2, a3} 中,以
Thumb 函数最简单的入口和退出序列是:[1]
an_example_Thumb_subroutine:
PUSH {save-registers, lr} ; one-line entry sequence
; ... first part of function ...
BL subroutine_name ;Must be in a space of +/- 4 MB
; ... rest of function goes here, perhaps including other function calls
; ...
POP {save-registers, pc} ; one-line exit sequence
ARM 的标准 C 调用约定由 ARM PLC 详细说明。[2]
32 位 ARM 函数最简单的入口和退出序列与 Thumb 函数非常相似:[3][4][5]
an_example_ARM32_subroutine:
PUSH {r4-r11, lr} ; one-line function prologue
; ... first part of function ...
BL subroutine_name ;Must be in a space of +/- 4 MB
; ... rest of function goes here, perhaps including other function calls
; ...
POP {r4-r11, pc} ; one-line exit sequence (function epilogue)
使用相同指令的备用助记符,
an_example_ARM32_subroutine:
; Push the return address (in LR) and the work registers
; "store multiple registers, full descending"
STMFD sp!,{r4-r11, lr} ; aka PUSH {r4-r11, lr}
; (A "sp" alone would leave the stack pointer unchanged.
; We must use "sp!" to update the stack pointer appropriately.)
; ... first part of function ...
BL subroutine_name ;Must be in a space of +/- 4 MB
; ... rest of function goes here, perhaps including other function calls
; ...
; Pop the return address (into PC) and the work registers
; and return automatically.
; "load multiple registers, full descending"
LDMFD sp!,{r4-r11, pc} ; aka POP {r4-r11, pc}
BL(分支并链接)指令将返回地址存储在链接寄存器 LR(r14)中,并将程序计数器 PC(r15)加载到子程序地址。典型
通常,r4-r11 用于保存当前正在执行的例程的局部变量。
寄存器 r4-r11 是“子程序保留寄存器”——当子程序将返回地址放置在 pc (r15) 中时,从子程序返回时,寄存器 r4-r11
典型的子程序(如上所示)会立即将这些寄存器的值压入堆栈。这释放了 r4-r11 以保存当前正在执行的子程序的局部
优化的 ARM 编译器会保存和恢复 r4-r11 和 r14(如果有)的精确子集,这些子集实际上被该子程序修改了,因为保存和
子程序可以随意覆盖 r0-r3、r12 和链接寄存器 lr (r14)。
前四个寄存器 r0-r3 用于将参数值传递给子程序,并从函数返回结果值。
使用 BL 指令可以轻松进行正常的函数调用。一个人输入
BL destination_subroutine
汇编器和链接器会自动执行“正确的事情” - 插入适当的(32 位长)ARM32 BL 指令用于 ARM32 到 ARM32 或 ARM32 到 Thumb 的调用,或插入适当的(32 位长)[6] Thumb BL 指令用于 Thumb 到 Thumb 或 Thumb 到 ARM32 的指令。
(一些混合调用和一些长分支需要链接器插入代码,用临时值覆盖 scratch register r12。 链接器究竟是如何做到的可能会令人困惑,尤其是在混合使用 BX 和 BLX 指令时。[7][8])
进一步阅读
[edit | edit source]- ↑ a b ARM. ARM 软件开发工具包. 1997. 第 9 章:ARM 过程调用标准。 第 10 章:Thumb 过程调用标准。
- ↑ "ARM 架构过程调用标准"
- ↑ RealView 编译工具开发者指南 "在 C、C++ 和 ARM 汇编语言之间调用"
- ↑ [1] 第 59 页“堆栈和子程序”部分
- ↑ "为嵌套子程序堆叠寄存器"
- ↑ [infocenter.arm.com/help/topic/com.arm.doc.ddi0234b/i107462.html "带有链接的 Thumb 分支 (BL)"]
- ↑ "Arm/Thumb:在 Thumb 代码中使用 BX,调用 Thumb 函数,或跳转到另一个函数中的 Thumb 指令"
- ↑ "Arm / Thumb 互操作"
- 嵌入式系统/汇编语言
- Embedded_Systems/Mixed_C_and_Assembly_Programming#ARM
- ARM 微控制器维基
- "ARM 概述" 位于 OS Dev 维基
- ARM 汇编语言速览
- GCC ARM 改进项目 位于塞格德大学
- ARM Linux 项目:适用于所有基于 ARM 的机器的 Linux
- ARM
- ARM 开发人员讨论论坛
- ARM Cortex-M3 技术参考手册
- ARM 汇编器 由 Richard Murray 提供