首页 > 解决方案 > 如果程序计数器 (PC) 在 arm 中复位,如何恢复启动?

问题描述

我有一个手臂控制器,并且可以选择使用 Lauterbach Trace32 重置 CPU 寄存器。现在,在重置 CPU 寄存器后,当我在 Trace32 中按“播放”时,我的板子启动并运行了 2 次。因此,当无法知道从哪里获取命令时(因为我认为 PC 是告诉在哪里寻找指令的人)这是如何工作的?我去看了代码,我可以看到 CPU 寄存器复位后 PC 值为 0。行为是这样的

  1. 我重置所有 CPU 寄存器
  2. 恢复运行
  3. 处理器以消息停止,“由向量捕获停止”
  4. 我再次恢复跑步

董事会已启动并运行!

标签: armembeddedbootloadertrace32

解决方案


infocenter.arm.com 包含有关您所要求的重要文档,请阅读这些文档。

但是您需要知道要阅读哪些内容。可以说手臂的三种主要口味和一些子口味。一个是从橡子开始的传统 arm 转换,从 ARMv4T 开始,这是我们今天所知道的经典 ARM7TDMI 内核,它开始了 ARM。该架构包括经典的 32 位 ARM 指令以及更小的拇指指令。我们通过 ARMv5T、ARMv6(认为它不再需要携带 T),然后是 ARMv6M。ARMv7 和 ARMv7m。

第一个不是 ARM7TDMI 的微控制器是基于 ARMv7m 的 cortex-m3,它是一个仅限拇指的机器,没有全尺寸的 arm 指令,它确实有大约 150 个拇指 2 扩展,它们是两个半字大小的指令,前半字按照你的预期进行解码使用 thumb 解码器,以前未定义的指令现在定义为 thumb2 扩展,下一个半字被解码。cortex-m3 只是先上街,然后是基于 armv6m 的 cortex-m0。ARMv8 是一个包含 64 位寄存器的全新指令集,通常也将具有 ARMv7 兼容模式,这是经典 32 位 arm 指令集的行尾。是的,有一个用于微控制器的 ARMv8m,它主要是带有一些 ARMv7m thumb2 扩展的 ARMv6m 指令,但如果我没记错的话,它是编译(逻辑的)时间可选的。在撰写本文时,街上很少有这些。

因此,arm 不制造芯片,而是制造内核,请查看您的芯片供应商文档,如果没有,则首先查找 cortex-a 或 cortex-m,然后再查找 arm7 或 arm9 或 arm11。然后,您可以转到 arm 信息中心页面并查找该特定内核的技术参考手册,在该文档中您将找到架构(例如 cortex-m3),然后您转到参考手册并找到架构参考手册那个架构,你的答案就在其中。

对于传统的核心,没有 m 的核心,即非 cortexms,因此 arm7(不是 armv7、arm7)arm9、arm10、arm11、cortex-a 和 cortex-r。

通常地址 0x00000000 包含释放复位后执行的第一个指令,内核上有条带允许获取高地址,但通常假设 0x00000000 也芯片供应商必须以某种方式使用该条带允许您访问或他们将其用于引导加载程序。如果芯片供应商首先在他们的引导加载程序上启动内核,那么所有关于您的应用程序代码可以从哪里开始的赌注都没有了,通常他们会通过使用该内核的库存重置解决方案(许多微控制器 ARM7TDMI 和皮质-ms,但并非全部取决于芯片设计)。

所以不要对程序计数器的作用感到困惑,实际上,现代处理器认为有多个程序计数器,当然在 arm 中,您有一个用于预取的地址,用于在其中获取地址,使用的地址至少执行。对我们来说重要的是,架构文档说第一条指令 EXECUTED 位于这些全尺寸经典手臂的地址 0x00000000 处。对于此类 ARM 体系结构,还有一个异常,它的第一条指令在地址 0x00000004 处执行,因此您必须避开这些特殊地址(如果不期望或使用其他事件,您正在使用的地址则可以从零开始您的代码)您需要通过使用无条件分支或 ldr pc 来进行分支。

cortex-ms (cortex-m0, cortex-m0+, cortex-m1.....) 使用经典的中断向量表方法,一个简单的例外,但它仍然是向量表方法。

对于这些,并且可以在核心上覆盖一条带子,但假设地址 0x00000000 的正常用例包含您想要初始化堆栈指针的值,许多芯片供应商从 0x20000000 开始他们的 ram 但不是全部所以你可以把 0x20004000 放在这里,例如你在那部分有 0x4000 字节的 sram。内核地址空间中的地址 0x00000004 包含复位向量,在这里,您作为程序员将地址放置到您的复位代码中,即您要执行的第一条指令。作为拇指机器,由于我们在用于互通时会考虑拇指地址,因此设置了 lsbit 并且您需要设置 lsbit 因此,如果您要执行的第一条指令位于地址 0x00000100,那么您需要将地址 0x00000004 设置为 0x00000101,

可以使用地址 0x00000008 以及上百个或两个条目,具体取决于内核和芯片供应商的实现。这个想法是性能,每个可以产生中断的微小事物都有可能拥有自己的向量,这取决于芯片供应商的设计。与过去的单个中断不同,您必须读取一堆中断控制器寄存器,然后可能通过一些外围设备进行轮询以找出造成中断的原因,您可以节省一些步骤,并通常针对具有这种设计的一个外围设备。

64位核心。这些在经典的 arm 方法中有历史,但具有不同的执行模式和与保护和控制相关的无数功能,我会让您自己阅读。对于无聊的重置,您进入地址 0x00000000 并在那里执行第一条指令。但要注意 mpcore,它是 arm11/armv6,armv7 全尺寸和 armv8s 具有多核风格,每个内核都有一个单独的时钟启用和复位,芯片供应商(不是 ARM)连接起来,所以两个基本设计是一个内核是从复位释放它开始在地址 0x00000000 处执行,然后该内核与芯片供应商逻辑对话以释放其他内核,在此之前它可以更改代码或执行路径,以便该内核运行与 core0 不同的代码,和/或编写的代码可以“排序核心”

您可能会发现的另一件事(想想 raspberry pi,但这仅仅是因为我们不会弄乱 gpu 并且不知道这些芯片特定的寄存器在哪里)是所有内核同时发布,所以你有多个处理器同时或几乎同时执行地址零,您必须对它们进行排序,以使一个引导芯片的其余部分,而其他的不干扰。但是对于简单的重置 aarch64 内核(armv8 目前是唯一的架构),执行的第一条指令位于地址 0x00000000。

作为程序员,您最终负责链接,以便正确的指令或地址位于正确的位置。很多时候,您会从已经为您完成所有这些工作的工具链或其他人的代码开始您的裸机体验,也许您正处于想要理解这一点的地方。因此,您必须在地址 0 处编写代码或构建您想要的表,然后您必须正确链接它,然后第三次将其加载到处理器中或正确地馈送处理器,以便一切正常。

一些微控制器的引导加载程序会以某种方式干扰这一点,但对于小程序,我认为我没有见过一个不会让你为地址零构建的程序。有些将镜像地址零和更高的地址,例如 ST 部分的 0x08000000,您可以将 0x08000101 之类的向量放入向量表中,以直接提取到应用程序闪存空间中。一般来说,对于 mcus,虽然您在了解所使用的内核之后的第一项工作是找到 sram 和 flash/rom 的位置并开始处理您的链接描述文件。


推荐阅读