VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > 汇编语言 >
  • 32 位操作

这里的许多信息取自 ARM 汇编器手册。我现在没有 32 位处理器,就只能信任文档了... 这个文档中表述的 UMUL 和 UMLA 只能在 32bit 模式下进行是错误的。如果你的处理器(比如: StrongARM)可以这么做,则它可以在 32bit 或 26bit 下工作...

 

ARM2 和 ARM3 有一个 32 位数据总线和一个 26 位地址总线。在以后版本的 ARM 上,数据总线和地址总二者都是完全的 32 位宽。这解释了为什么一个“32 位处理器”被称为 26 位。数据宽度和指令/字大小是 32 位,并总是这样,但地址总线只是 24 位。因为 PC 总是字对齐的,一个地址中的低两位总是零,所以在 ARM2/ARM3 处理器上这些位持有处理器模式设置。尽管实际上只使用了 24 位,PC 的有效宽度仍是 26 位。

在老机器上这没有问题。4Mb 内存是基准的。一些人升级到 8Mb、和 16Mb 是理论上的限制。(Some people upgraded to 8Mb, and 16Mb was the theoretical limit.) 但是 RiscPC 使用一个 26 位程序计数器是不可能的,因为 RiscPC 允许安装 258Mb 内存,而 26 位只允许你寻址到 %11111111111111111111111100 (或 67108860 字节,或 64Mb)。这附带的解释了对应用任务的 28Mb 大小限制;就是希望系统与老的 RISC OS API 相容。

尽管这个汇编器站点的某些部分覆盖了 32 位模式(比如运行在 SVC32 下的一个简要的例子!),但多数部分是关于 26 位模式操作的,这是为了与 RISC OS 的当前可获得的版本相兼容(就是 RISC OS 2 到 RISC OS 4);我注意到部分例子不适用于 32 位。

RiscPC、Mico、RiscStation、A7000 等都有能力运行完全的 32 位操作系统;实际上 ARMLinux 就是这样的一个操作系统。RISC OS 不是,因为 RISC OS 需要,至少一个时期,保持与现存版本的兼容。这是个古老的两分问题(dichotomy),有一个崭新的完全 32 位版本的 RISC OS 版本是美妙的,但当你发现许多你的现存软件不能继续运行(so much as load)就不那么美妙了!

RISC OS 不是完全的 26 位。一些处理程序(handler)需要工作在 32 位模式下;限制它的是金钱(就是说,谁为完全转换 RISC OS 付钱;谁为用来重建它们的代码的开发工具付钱(PD 在 RISC OS 上是强壮的))和必要性(就是说,很多人使用 Impression 而 CC 不再与我们同在;Impression 好象不能在更新的 RISC OS 上工作,所以如果人们需要的软件将不能工作,那么他们不会认为有升级的必要)。

为什么这如此重要? 新的 ARM 处理器将不支持 26 位操作。尽管做了一些融合(ARM6、ARM7、StrongARM),但气数就要尽了。你可以增加一个 26/32 位系统的复杂性,或者只用 32 位而得到更简单、更小的处理器。我们要么随波逐流,要么被甩下... 所以我们别无选择。

32 位体系

ARM 体系在 ARM6 系列中进行了重大变更。下面我将描述 26 位 和 32 位操作行为的不同之处。

在 ARM 6 中,程序计数器被扩展到完整的 32 位。结果是:

  • PSR 从 PC 中分离到自己的寄存器 CPSR(当前的程序状态寄存器)中。
  • 在改变处理器模式的时候,不再与 PC 一起保存 PSR;现在是每个有特权的模式都有一个额外的寄存器 - SPSR (保存的程序状态寄存器) - 用来持有前面模式的 PSR。
  • 增加了使用这些新寄存器的指令。
除了允许 PC 使用完全的 32 位之外,还有进一步的变更,就是给 PSR 增加了额外的有特权的模式。这些模式用于处理未定义指令和异常终止例外:
  • 未定义指令、异常终止、和超级用户不再共享同一个模式。去掉了在早期 ARM 上存在的对超级用户的那些限制。
  • 在 ARM6 系列(和以后的其他兼容芯片)中通过设置片上某个控制寄存器来确定这些特征的可获得性。可以选择三个处理器配置中的一个:
    • 26 位程序和数据空间,这个配置强制 ARM 在 26 位地址空间中进行操作。在这个配置中只能获得四个 26 位模式(参照处理器模式描述);不可能选择任何 32 位模式。在所有当前的 ARM6 和 7 系列上复位(reset)时被设置为这个模式。
    • 26 位程序空间和 32 位数据空间。除了禁止地址例外来允许数据传送操作访问完整的 32 位地址空间之外,与 26 位程序和地址空间配置相同。
    • 32 位程序和数据空间。这个配置把地址空间扩展成 32 位,并介入了对处理器模型的重大变更。在这个配置中你可以选择任何 26 位和 32 位处理器模式(参见下面的处理器模式)。

 在配置成 32 位程序和数据空间的时候,ARM6 和 ARM7 系列支持十个有所重叠的处理器操作模式:

  • 用户模式: 正常的程序执行状态;
    User26 模式: 一个 26 位版本。
  • FIQ 模式: 设计来支持一个数据传送或通道处理;
    FIQ26 模式: 一个 26 位版本。
  • IRQ 模式: 用于通用中断处理;
    IRQ26 模式: 一个 26 位版本。
  • SVC 模式: 用于操作系统的保护模式
    SVC26模式: 一个 26 位模式。
  • 异常终止模式(ABT 模式): 在一个数据或指令预取异常终止(abort)的时候进入的模式。
  • 未定义模式(UND 模式): 在执行了一个未定义的指令的时候进入的模式。
当在一个 26 位处理器模式中的时候,编程模型倒退成早期的 26 位 ARM 处理器。除了下列变动之外,它的行为与 ARM2aS 宏单元(macrocell)相同:
  • 只在 ARM 被配置为 26 位程序和数据空间的时候,它才生成地址例外。在其他配置下 OS 仍然可以通过使用外部逻辑模拟地址例外的行为,比如用一个内存管理单元在超出 64Mbyte 范围的时候生成一个异常终止,并把这个异常终止转换成给这个应用程序的一个‘地址例外陷入’。
  • 保持在通用寄存器和程序状态寄存器之间传送数据的新指令可操作。在调用了包含 26 位的 ARM 二进制代码的之后,操作系统可以使用这些新指令返回到一个 32 位模式。
  • 当在一个 32 位程序和数据空间配置下的时候,所有例外(包括未定义指令和软件中断)把处理器返回到一个 32 位模式,所以必须修改操作系统来处理它们。
  • 如果处理器尝试写到在 &0 和 &1F 之间包括二者(就是例外向量)的一个位置,则硬件将禁止写操作并生成一个数据异常终止。这允许操作系统来截获对例外向量的变动并把向量重定向到一些伪装(veneer)代码上。在调用 26 位例外处理程序之前,这些伪装代码应该把处理器置于一个 26 位模式中。
在所有其他方面,当在一个 26 位模式下进行操作的时候,ARM 表现的如同一个 26 位 ARM。CPSR 的相关的位将被组建(incorporated)回到 R15 中,来形成 I 和 F 位在位 27 和 26 的 PC/PSR。指令集表现的如同增加了 MRS 和 MSR 指令的 ARM2aS 宏单元。

在 ARM 6(和以后)的 32 位模式下可获得的寄存器有:

User26   SVC26    IRQ26    FIQ26      User     SVC      IRQ      ABT      UND      FIQ

R0 ----- R0 ----- R0 ----- R0 --   -- R0 ----- R0 ----- R0 ----- R0 ----- R0 ----- R1
R1 ----- R1 ----- R1 ----- R1 --   -- R1 ----- R1 ----- R1 ----- R1 ----- R1 ----- R2
R2 ----- R2 ----- R2 ----- R2 --   -- R2 ----- R2 ----- R2 ----- R2 ----- R2 ----- R2
R3 ----- R3 ----- R3 ----- R3 --   -- R3 ----- R3 ----- R3 ----- R3 ----- R3 ----- R3
R4 ----- R4 ----- R4 ----- R4 --   -- R4 ----- R4 ----- R4 ----- R4 ----- R4 ----- R4
R5 ----- R5 ----- R5 ----- R5 --   -- R5 ----- R5 ----- R5 ----- R5 ----- R5 ----- R5
R6 ----- R6 ----- R6 ----- R6 --   -- R6 ----- R6 ----- R6 ----- R6 ----- R6 ----- R6
R7 ----- R7 ----- R7 ----- R7 --   -- R7 ----- R7 ----- R7 ----- R7 ----- R7 ----- R7
R8 ----- R8 ----- R8       R8_fiq     R8 ----- R8 ----- R8 ----- R8 ----- R8       R8_fiq
R9 ----- R9 ----- R9       R9_fiq     R9 ----- R9 ----- R9 ----- R9 ----- R9       R9_fiq
R10 ---- R10 ---- R10      R10_fiq    R10 ---- R10 ---- R10 ---- R10 ---- R10      R10_fiq
R11 ---- R11 ---- R11      R11_fiq    R11 ---- R11 ---- R11 ---- R11 ---- R11      R11_fiq
R12 ---- R12 ---- R12      R12_fiq    R12 ---- R12 ---- R12 ---- R12 ---- R12      R12_fiq
R13      R13_svc  R13_irq  R13_fiq    R13      R13_svc  R13_irq  R13_abt  R13_und  R13_fiq
R14      R14_svc  R14_irq  R14_fiq    R14      R14_svc  R14_irq  R14_abt  R14_und  R14_fiq
--------- R15 (PC / PSR) ---------    --------------------- R15 (PC) ---------------------
                                      ----------------------- CPSR -----------------------
                                               SPSR_svc SPSR_irq SPSR_abt SPSR_und SPSR_fiq
简要的说,32 位的与 26 位的不同是:
  • PC 是完全的 32 位宽,并只用做程序计数器。
  • PSR 包含在它自己的寄存器 CPSR 中。
  • 每个有特权的模式都有一个专有的 SPSR 寄存器,用来保存 CPSR。
  • 这里有两个新的特权模式,每个有特权的模式都有 R13 和 R14 的专有复件。

 

CPSR 和 SPSR 寄存器

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 模式
关于 N、Z、C、V 标志和 I、F 中断标志请参见(26 位) PSR。

 

这在实践中意味着什么?

多数 ARM 代码将正确的工作。唯一不能工作的是通过摆弄 R15 来设置处理器状态的那些操作。不幸的是,好象没有简便的方法修理这个问题。我检查了一个有潜在问题的 9K 程序(一个 MODE 7 teletext frame viewer,用 C 写的),基本上查找:
  • 用 R15 作为目的寄存器的 MOVS 指令。
  • 以‘^’作为后缀并装载 R15 的 LDMFD 指令。
大约有 64 个指令被归入此类。

好象有没有什么方式来自动进行转换。基本上...

  • 系统如何知道哪个是数据哪个是代码。实际上,一个灵巧的基于规则的程序能够可以做非常准确的猜测,但“非常准确的猜测”就足够了吗?
  • 没有简单的指令替代。一个自动系统可以修补需要的指令并调整(jiggle)周围的代码,但这将导致不希望的副作用,比如一个 ADR 宏指令(directive)不在范围内(in range)。
  • 需要难以置信的技巧(It is incredibly hacky)。当然,最好重新编译,或修改源代码。

 这是很不容易的。这样小的变更,竟有如此严重(far-reaching)的后果。 


相关教程