pc 相关 ldr 指令的拇指编码最近刚刚在 SO 上介绍过。当您查看指令集上的文档时,您会如我们所指出的那样知道 PC 从文档的角度来看,在拇指前 2 天的早期是两个字节,但现在对于拇指来说,它比指令地址提前 4 个字节. pc 偏移量以字为单位进行编码,因此使用的地址是
((instruction address + 4 ) & 0xFFFFFFFC) + (immed<<2)
消除对前面两个事情的所有困惑。
现实情况是有多个程序计数器,单个程序计数器用于实际获取内容和进行 pc 相对寻址的日子是旧的、更简单的体系结构的历史的一部分。
这两个领先的东西是过去的一部分,但出于兼容性的原因,已经从 acorn 延续到现在的 arm 产品,就像 x86 和其他人有不再是他们所说的那样的遗留东西(分支阴影/延迟插槽米)。
管道是不同的,人们会假设每个不同的 arm 产品(不是架构,而是产品 cortex-m0、cortex-m4、cortex-a7 等)的管道实现以及核心跟踪事物的方式各不相同。前面的两个是由某种形式的程序计数器合成的,它跟踪管道中的指令。同样,提取/预取/分支预测都是程序计数器的所有形式,但不假定为单个程序计数器。r15 本身也是来自寄存器文件的真实或假的或两者兼而有之(我希望不在寄存器文件中,为什么要烧掉这些周期而不增加任何价值)。
就像在软件中你可以有一个 reg[15] 数组项、一个 pc_fetch、一个 pc_current_inst、pc_execution、一个 pc_possible_branch、一个 pc_branch_prediction 变量集来跟踪处理器的模拟,逻辑也可以。而在什么时间使用哪一个取决于你在做什么。正如在指令操作中所描述的那样,作为 PC 的程序员,我们所理解的是一个地址,该地址比指令所在的地址“提前两个”。使用 thumb2 时,前面的两个不再有意义,因此对于拇指模式,它是 4 个字节,对于 arm 模式,它比指令地址提前 8 个字节。然后您按照文档了解在执行指令期间如何使用该 PC。
对于 BX 和其他能够切换模式的指令,成为“程序计数器”的地址的定义是不同的,lsbit 驱动模式切换到(并被它不在程序计数器中的分支剥离,有是一个 psr 来处理这个问题)。这些地址也是程序计数器的一种形式,至少暂时是要跳转到的指令的实际地址,而不是两个前面的地址。
在许多早期的处理器实现中,你有一个或一个程序计数器的想法,你一次获取、解码和执行一条指令,然后再继续下一条(并不意味着人们不再做这些设计,你可以小而高效的小控制器是老式的方式,人们仍然这样做,并且在我们使用的产品中)。在这种情况下,pc 用于获取可能超过一个字节的指令,一旦指令被完全获取,那么程序计数器至少暂时指向下一条指令。现在可以开始执行该指令,因为获取和解码已经完成。如果程序计数器用作该指令的输入,则它指向下一条指令,如果用作跳转或分支中的目的地,那么它会被修改,完成后下一次提取发生在它碰巧指向的任何地方。这些架构中有许多是可变长度指令集,因此,一条指令可能是一、二、三……字节长,因此在执行时相对于指令地址的 pc 地址是不同的。早期的 arm 来自具有固定大小指令的管道类型解决方案,因此,如果您有单个程序计数器,那么根据管道设计,如果您使用教科书式的,那么执行在管道含义中的固定深度当您执行时,程序计数器会提前获取那么多。字节长,因此执行时相对于指令地址的 pc 地址是不同的。早期的 arm 来自具有固定大小指令的管道类型解决方案,因此,如果您有单个程序计数器,那么根据管道设计,如果您使用教科书式的,那么执行在管道含义中的固定深度当您执行时,程序计数器会提前获取那么多。字节长,因此执行时相对于指令地址的 pc 地址是不同的。早期的 arm 来自具有固定大小指令的管道类型解决方案,因此,如果您有单个程序计数器,那么根据管道设计,如果您使用教科书式的,那么执行在管道含义中的固定深度当您执行时,程序计数器会提前获取那么多。