ARM微处理器程序状态寄存器

ARM 185浏览

寄存器 15 (26-bit 模式):

R15 构造如下:

  Bit  31  30  29  28  27  26  25------------2  1  0

       N   Z   C   V   I   F    程 序 计 数 器  S1 S0

标志的意义:

  N  Negative        如果结果是负数则置位
  Z  Zero            如果结果是零则置位
  C  Carry           如果发生进位则置位
  O  Overflow        如果发生溢出则置位
  I  IRQ             中断禁用
  F  FIQ             快速中断禁用

  S1 和 S0 是处理器模式标志:

           S1   S0   模式
           0    0    USR - 用户模式
           0    1    FIQ - 快速中断模式
           1    0    IRQ - 中断模式
           1    1    SVC - 超级用户模式

在 R15 作为一个指令的第一个操作数的时候,只有程序计数器部分是可以获得的。所以,下列指令把 PC 复制到一个寄存器中并向这个目标寄存器加上 256:
  ADD    R0, R15, #256
(对于 BASIC 汇编器 R15 和 PC 的意思是相同的)

在 R15 作为第二个操作数的时候,所有 32 位都是可以获得的: 程序计数器、标志、和状态。下列代码段将标识当前的处理器模式:

   MOV     R0, #3          ; 装载一个位掩码(%11)到 R0 中
   AND     R0, R0, PC      ; 把 R15 与 R0 做逻辑与并把结果放入 R0,来得到模式状态
   CMP     R0, #3          ; 把模式与 '3' 相比较(SVC)
   BEQ     svc             ; 如果等于 SVC 模式,分支到 'svc'
   CMP     R0, #2          ; 把模式与 '2' 相比较 (IRQ)
   BEQ     irq             ; 如果等于 IRQ 模式,分支到 'irq'
   CMP     R0, #1          ; 把模式与 '1' 相比较(FIQ)
   BEQ     fiq             ; 如果等于 FIQ 模式,分支到 'fiq'
   CMP     R0, #0          ; 把模式与 '0' 相比较(USR)
   BEQ     usr             ; 如果等于 USR 模式,分支到 'usr'

这个例子不遵从 32-bit 体系。 

改变处理器的状态:

要改变处理器模式、或者任何标志,我们需要用想要的标志 EOR(异或)状态标志,新状态 = 旧状态 EOR (1 << 28) 可以成为改变 oVerflow 标志的伪码。但是我们不能做这个简单的 EORS 操作,原因是这将导致随后的两个指令被跳过。不要担心,指令 TEQ 做一个假装的 EOR (结果不存储到任何地方)。把它与 P 后缀组合,则把结果的第 0、1、和 26 至 31 位直接写到 R15 的第 0、1、和 26 至 31 位,这是改变标志的一个简便的方法:   TEQP   R15, bit_mask

如果你处在允许你设置一个标志的一个模式中,则你只可以改变这个标志。

这个例子不遵从 32-bit 体系。

可以被扩充它来改变处理器模式。示例,要进入 SVC 模式你可以:

   MOV     R6, PC          ; 把 PC 的最初状态存储到 R6 中
   ORR     R7, R6, #3      ; 设置 SVC 模式
   TEQP    R7, #0          ; 把(在 R7 中的)模式标志写入 PC

而返回最初的模式是:

   TEQP    R6, #0          ; 把(在 R6 中的)最初的模式写入 PC

在改变了模式之后,你应该进行一个空操作来允许这个寄存器安定下来。比如 MOV R0, R0 之类的东西就可以。废弃使用 NV 后缀的指令。

  

32 位 PSR

如同在32 位操作中描述的那样,ARM 3 之后的处理器提供一个 32 bit 地址空间,它们把 PSR 移出 R15 并给予 R15 完整的 32 位位域,在其中存储当前位置的地址。目前,除了一些不太可能遇到的情况之外,RISC OS 工作在 26 位模式。

32 位模式是重要的,因为 26 位(在老的 PSR 中)把每个应用程序的可寻址内存的最大数量限制为 28Mb。这就是不管你安装了多少内存你不能拖动超过 28Mb 的下一个槽(drag the Next slot beyond 28Mb)的原因。

CPSR 寄存器(和保存它的 SPSR 寄存器)中的位分配如下:

  31 30 29 28  ---   7   6   -   4   3   2   1   0
  N  Z  C  V         I   F       M4  M3  M2  M1  M0

                                 0   0   0   0   0     User26 模式
                                 0   0   0   0   1     FIQ26 模式
                                 0   0   0   1   0     IRQ26 模式
                                 0   0   0   1   1     SVC26 模式
                                 1   0   0   0   0     User 模式
                                 1   0   0   0   1     FIQ 模式
                                 1   0   0   1   0     IRQ 模式
                                 1   0   0   1   1     SVC 模式
                                 1   0   1   1   1     ABT 模式
                                 1   1   0   1   1     UND 模式

典型的,处理器将在 User26、FIQ26、IRQ26 和 SVC26 下操作。可以进入一个 32 位模式,但要格外小心。RISC OS 不希望这样,并且如果它发现自己在其中会非常生气!

操纵 32 位 PSR 的指令

你不能在 32 位模式中使用 MOVS PC, R14LDMFD R13!, {registers, PC}^。也不能使用 ORRS PC, R14, #1<<28 来设置 V 标志。现在需要使用 MRSMSR

复制一个寄存器到 PSR 中
  MSR     CPSR, R0                ; 复制 R0 到 CPSR 中
  MSR     SPSR, R0                ; 复制 R0 到 SPSR 中
  MSR     CPSR_flg, R0            ; 复制 R0 的标志位到 CPSR 中
  MSR     CPSR_flg, #1<<28        ; 复制(立即值)标志位到 CPSR 中
复制 PSR 到一个寄存器中
  MRS     R0, CPSR                ; 复制 CPSR 到 R0 中
  MRS     R0, SPSR                ; 复制 SPSR 到 R0 中

指令格式

你有两个 PSR - CPSR 是当前的程序状态寄存器(Current Program Status Register),而 SPSR 是保存的程序状态寄存器(Saved Program Status Register)(前面的处理器模式的 PSR)。每个有特权的模式都有自己的 SPSR,可获得的 PSR 有:

  • CPSR_all - 当前的
  • SPSR_svc - 保存的,SVC(32) 模式
  • SPSR_irq - 保存的,IRQ(32) 模式
  • SPSR_abt - 保存的,ABT(32) 模式
  • SPSR_und - 保存的,UND(32) 模式
  • SPSR_fiq - 保存的,FIQ(32) 模式

你不能显式的指定把 CPSR 保存到哪个 SPSR 中,比如 SPSR_fiq。而是必须变更到 FIQ 模式并接着保存到 SPSR。换句话说,你只能在你所在的模式中改变这个模式的 SPSR。使用 _flg 后缀允许你改变标志位而不影响控制位。

在 user(32) 模式中,保护 CPSR 的控制位,你只能改变条件标志。在其他模式中,可获得整个 CPSR。你不应该指定 R15 为一个源寄存器或一个目标寄存器。最后,在 user(32) 模式中,你不能尝试访问 SPSR,因为它不存在!

要设置 V 标志:

  MSR     CPSR_flg, #&10000000

这将设置 V 标志但不影响控制位。

要改变模式:

  MRS     R0, CPSR_all            ; 复制 PSR
  BIC     R0, R0, #&1F            ; 清除模式位
  ORR     R0, R0, #new_mode       ; 把模式位设置为新模式
  MSR     CPSR_all, R0            ; 写回 PSR,变更模式

现在我们要做的是进入 SVC32 模式并设置 Z 标志。接着我们返回 SVC26 模式并‘测试’是否设置了 Z。
RISC OS 不希望发现自己处在 32 位模式中,所以我们要禁止所有中断并保持它们这样(keep them that way)。尽管这些代码应该执行的非常快,但我们不应当冒任何风险...

你可能觉得 32 位模式不是非常有用。在当前版本的 RISC OS 下,这是事实。实际上,就我而言,32 位模式提供给你的只是:

  • 访问大于 28Mb 的区域。在 RISC OS 上这不是真的很重要,在这个系统里 web 浏览器适合于 1 M 或 2 M,而重要的艺术程序为那些非常巨大的图象提供它们自己的虚拟内存系统。

本文档的最初版本,和最初的 ARM 汇编器指南包括...

  • StrongARM 提供了两个指令(UMUL 和 UMLA、IIRC),它们处理 64 位乘法。这只能在 32 位模式下获得。

这是错误的。在 26 位模式下可以使用扩展的乘法;MP3 解码器就使用了它!

尽管 32 位模式的利益好象不是多的那么惊人,新近的处理器(比如 Xscale)不再支持 26 位模式,所以 RISC OS 和它的应用程序要在 32 位环境下工作则必须经过修改。听起来不是很多,但是如果所有补偿/改变 R15 中的 PSR 位的引用都必须被变更为对不在 R15 中的独立的 PSR 的引用,这就突然变成一个非常重大的问题了。还有你不能继续用一个指令来恢复 PSR 并分支回到调用者,现在这需要两个独立的指令。为此代码必须重写。你不能简单的用另一个指令来修补...