如果程序计数器(PC)在arm中重置,如何恢复启动?

If the program counter (PC) reset in arm, how the booting resumes?

我有一个手臂控制器,我可以选择使用 Lauterbach Trace32 重置 CPU 寄存器。现在,在重置 CPU 寄存器后,当我在 Trace32 中按下 "Play" 时,我的电路板启动了 2 次并且 运行。所以当没有办法知道从哪里获取命令时(因为我假设 PC 是告诉在哪里寻找指令的人)这是怎么回事?我去看了代码,我可以看到 CPU 寄存器重置后 PC 值为 0。行为是这样的

  1. 我重置了所有 CPU 个寄存器
  2. 继续 运行
  3. 处理器停止并显示消息 ,"stopped by vector catch"
  4. 我又恢复了运行

董事会已经成立 运行 !!

infocenter.arm.com 包含您所问内容的重要文档,请阅读这些文档。

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

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

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

对于传统的核心,没有m的那些,非cortexms,所以arm7(不是armv7,arm7)arm9,arm10,arm11,cortex-a和cortex-r。

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

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

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

对于这些,核心上可以有一个 strap 来覆盖,但假设地址 0x00000000 的正常用例包含您想要初始化堆栈指针的值,许多芯片供应商启动他们的 ram在 0x20000000 但不是全部,所以你可以把 0x20004000 放在这里,例如你在那个部分有 0x4000 字节的 sram。内核地址 space 中的地址 0x00000004 包含复位向量,作为程序员,您将地址放置到您的复位代码中,这是您要执行的第一条指令。作为拇指机器,由于我们在用于互通时考虑拇指地址,因此设置了 lsbit 并且您需要设置 lsbit 因此如果您要执行的第一条指令位于地址 0x00000100,那么您需要将地址 0x00000004 设置为 0x00000101,处理器逻辑(停止考虑程序计数器)将在复位检查 lsbit 后读取地址 0x00000004,剥离它并使用 0x100 获取第一条指令。

地址 0x00000008 以及多达一百或两个条目可以使用,取决于核心和芯片供应商的实施。这个想法是性能,每个可以中断的微小事物都有可能拥有自己的向量,这取决于芯片供应商的设计。与单一中断的过去不同,你必须去读取一堆中断控制器寄存器,然后可能通过一些外围设备进行轮询以找出是谁导致了中断你节省了几个步骤并通常瞄准具有这种设计的一个外围设备。

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

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

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

有些微控制器的引导加载程序会以某种方式干扰这一点,但对于小程序,我认为我还没有看到不允许您为地址零构建的程序。对于 ST 部分,有些会镜像地址零和更高的地址,例如 0x08000000,您可以将诸如 0x08000101 之类的向量放入向量 table 中,以直接获取到应用程序闪存 space 中。一般来说,对于 mcus,虽然你在知道所使用的核心之后的第一份工作是找到 sram 和 flash/rom 的位置,然后开始处理你的 linker 脚本。