【问题标题】:Intel X86 -- How is memory accessing / writing affected by a machine being '32-bit'?英特尔 X86——“32 位”机器如何影响内存访问/写入?
【发布时间】:2018-08-26 03:41:40
【问题描述】:

维基百科说:

32 位 CPU 和 ALU 架构是基于该大小的寄存器、地址总线或数据总线的架构。

所以每个内存地址都是指 32 位的。

但这到底意味着什么?在约定为 32 位的 Intel X86-32 汇编中,有 32 位寄存器、16 位寄存器和 8 位寄存器。

考虑以下程序集

mov ax, bx  ; move 16-bit bx into 16-bit ax
mov ah, bh  ; move 8-bit bh into 8-bit ah
movzx eax, ax ; move 16-bit ax into 32-bit eax (zero-extending ax)

所有这些行都可以接受吗?如果是这样,为什么我们坚持认为这是一个 32 位系统?不可避免地,程序集管理较小的地址大小。

【问题讨论】:

  • 是的,所有这些都是合法的。请注意,较小的寄存器都是较大寄存器的一部分。 32 位只是本机“最大”大小。你得到了“每个内存地址指的是 32 位”部分错误。
  • 32 位 x86 还具有 64 位 MMX 寄存器和最多 512 位 AVX512 ZMM 寄存器。只有通用整数寄存器是 32 位的。 The connection between L1d cache and execution units is up to 512 bits wide(在 Skylake-AVX512 中)。
  • 更复杂的是,自 Pentium Pro 以来支持 PAE,它允许 36 位物理地址,但仍然是 32 位虚拟地址。
  • 对于简单的处理器,位宽是可以用一条指令计算和/或存储的最大数字的一般特征,但很少完美。处理器越复杂,这种表征就越不完善。正如@PeterCordes 指出的那样,对于现代通用处理器来说,位宽几乎没有意义:它的例外成为规则。因此,维基百科页面的模糊性。

标签: assembly memory x86 intel 32-bit


【解决方案1】:

x86-32(又名 IA-32)是 16 位 8086 的 32 位扩展,旨在将 asm 源从 8 位 8080 轻松移植到 8086。(Why are first four x86 GPRs named in such unintuitive order? 用于逆向计算)。

这段历史就是为什么现代 x86 有这么多部分寄存器的东西,直接支持 8 位和 16 位操作数大小。

大多数其他具有 32 位寄存器的架构仅允许窄加载/存储,而 ALU 操作仅是完整的寄存器宽度。 (但这同样重要,因为它们是 RISC 架构(MIPS、SPARC,甚至是稍微少一点 RISCy 的 ARM),而 x86 绝对是 CISC 架构。)

RISC 架构(如 MIPS)的 64 位扩展仍然支持 32 位操作,通常将 32 位结果隐式零扩展至“完整”寄存器the same way x86-64 does。 (特别是如果 64 位不是新模式,而只是同一模式中的新操作码,其语义设计使得现有机器代码在寻址模式使用完整寄存器但所有旧操作码仍然仅以相同方式运行时写入低 32 位。)

因此,您在 x86-32 上观察到的情况(支持对部分寄存器的窄操作)存在于作为旧架构的更广泛扩展存在的所有架构中,无论它以新模式运行(机器代码解码不同)与否。只是 x86 的祖先在 x86 中回到了 16 位,又回到 8 位作为对 8086 的影响。


Motorola 68000 有 32 位寄存器,根据维基百科“主要 ALU”只有 16 位。 (也许 32 位操作速度较慢或某些不支持,但绝对支持 32 位添加/和指令。我不知道为什么 Wikipedia 这么说背后的细节)。

最初 68000 设计用于 16 位外部总线,因此 16 位加载/存储在那些早期 CPU 上效率更高。我认为后来的 68k CPU 拓宽了数据总线,使 32 位加载/存储与 16 位一样快。无论如何,我认为 m68k 是另一个支持大量 16 位操作的 32 位架构示例。维基百科将其描述为“16/32 位 CISC 微处理器”。


添加缓存后,缓存行中可容纳的 16 位整数是 32 位整数的两倍,因此对于顺序访问,16 位的平均/持续内存只需一半带宽。 当有缓存时,“总线宽度”会变得更加复杂,因此在加载/存储单元和缓存之间以及缓存和内存之间存在总线或内部数据路径。 (并且在多级缓存中,不同级别的缓存之间)。


决定是否调用 8 / 16 / 32 / 64 位架构(或该架构的特定实现)是相当随意的。 营销部门可能会选择他们可以证明的最广泛的东西,并在 CPU 的描述中使用它。这可能是数据总线或寄存器宽度,或地址空间或其他任何东西。 (许多 8 位 CPU 在两个 8 位寄存器的串联中使用 16 位地址,尽管它们中的大多数不会尝试声称是 16 位。尽管它们可能被宣传为 8/16 位。)


32 位 x86 被认为是 32 位,因为这是指针或“通用”整数寄存器的最大宽度。 386 增加了几个主要的新内容:32 位整数寄存器 /操作数大小(可通过实模式的前缀访问)和具有虚拟内存分页的 32 位保护模式,其中默认地址和操作数大小为 32 位。


今天可以运行 IA-32 机器代码的物理 CPU比第一代 386SX CPU 具有更宽的总线和更好的内存带宽,但它们仍然支持相同的IA-32 架构(加上扩展)。

如今,基本上所有新的 x86 CPU 也可以在 x86-64 模式下运行。在 IA-32 模式下运行时,现代 x86 CPU 将仅使用其 64 位物理整数寄存器的低 32 位(例如在 32 位或 16 位模式下使用 32 位操作数大小的指令) .

但除整数寄存器外,还有 80 位 x87 寄存器(可用作 64 位整数-SIMD MMX 寄存器),以及 XMM / YMM / ZMM 寄存器(SSE / AVX / AVX512)。

SSE2 是 x86-64 的基准,现在可以在大多数 32 位代码中假定,因此至少有 128 位寄存器可用,并且可以用于 64 位整数加/减/移位,即使在32 位模式,带有 paddq 之类的指令。

现代 CPU 在向量加载/存储单元和缓存之间也具有至少 128 位的连接,因此当数据适合 L1d 缓存时,加载/存储/复制带宽不受外部双/三/四通道 DDR3 的限制/DDR4 DRAM 控制器(在 64 位外部总线上进行 8x 64 位的突发传输 = 一个 64 字节缓存线)。

相反,CPU 具有大型快速缓存,包括共享的 L3 缓存,因此如果数据在 L3 中仍然很热,则由一个内核写入并由另一个内核读取的数据通常不必经过内存。请参阅some details on how cache can be that fast for Intel IvyBridge,尽管它支持 256 位 AVX 指令,但它只有 128 位加载/存储路径。 Haswell 也将加载/存储路径扩大到 256 位。 Skylake-AVX512 将 L1d 缓存以及 L1d 和 L2 之间的连接的寄存器和数据路径扩大到 512 位。

但在纸面上,x86(自 P5 Pentium 及更高版本)仅保证 aligned loads/stores up to 64 bits are atomic,因此允许使用 SSE 的实现将 128 位 XMM 加载/存储分成两个 64 位半。 Pentium III 和 Pentium M 实际做到了这一点。但请注意,i586 Pentium 比 x86-64 早了十年,它可以加载/存储 64 位的唯一方法是使用 x87 fldfild。 Pentium MMX 可以进行 64 位 MMX movq 加载/存储。无论如何,这种原子性保证包括未缓存的存储(例如,对于 MMIO),这是可能的(很便宜,没有总线锁),因为 P5 微架构有一个 64 位外部总线,即使它是严格的 32 位而不是FPU

即使是纯整数代码也受益于宽数据路径,因为它增加了整数代码的带宽,加载/存储在 L3 或特别是 L2 缓存中命中,但不是 L1d 缓存。


所有这些对 x86 的 SIMD 扩展使其比纯 32 位整数架构强大得多。但是在32位模式下运行时,仍然是386引入的模式,我们称之为32位模式。这个名字和任何名字一样好,但不要试图过多地解读它。

事实上,除了整数/指针寄存器宽度之外,不要将任何东西读入其中。它运行的硬件通常具有 64 位整数寄存器和 48 位虚拟地址空间。以及各种巨大宽度的数据总线 + 缓存,以及复杂的乱序机制,给人一种在actually looking at a window of up to 224 uops to find instruction-level parallelism 时按顺序运行的错觉。 (Skylake / Kaby Lake / Coffee Lake ROB 大小)。

【讨论】:

  • 我认为将 32 位架构定义为 架构标量整数寄存器的全尺寸为 32 位 将涵盖所有“32 位架构”在历史上。不确定是否可以比这更精确。
  • @HadiBrais:是的,我想是的,但根据 Wiki,m68k 的“主 ALU”只有 16 位宽,它描述为 16/32 位架构。它肯定至少有 32 位寄存器和 32 位 ADD / AND 指令。但是,是的,我认为 8 位和 16 位更模糊(因为 8 位对于地址大小来说太小了,所以大多数 8 位 CPU 都有某种 16 位的东西)。
  • 但是无论如何,这个答案的 TL:DR 是纸上的 IA-32 指令集并没有告诉你任何关于可以运行它的 CPU 中的内存系统的信息,回答了问题标题。更重要的是,知道 CPU 是“32 位”并不能告诉您太多关于它的信息,除了 32 位整数的处理效率可能与 8 位或 16 位相同(加载和存储它们除外)。
  • 完全正确。这就是为什么我在我提出的定义中使用了术语架构。虽然 标量整数 部分可能看起来不是很精确。
  • 68k 是 32 位 设计,由于 1970 年代的芯片尺寸限制,必须使用 16 位 ALU 并通过它运行两轮数据。后来 68020 实现了相同的设计,到处都是 32 位总线。
【解决方案2】:

维基百科的解释有点模糊,但话说回来,这是一个很难得到准确定义的主题。以“乘用车”一词为例。你能准确定义吗?没有。

过去,32 位架构是具有 32 位数据总线的架构,但现在情况要复杂得多。

今天的一个工作定义是架构的位数往往与最大的可用通用寄存器的位数一致。

因此,可以预期 32 位系统具有 8 位、16 位和 32 位寄存器,但(通常)没有更大的寄存器。同样,一个 16 位系统可以预期有 8 位和 16 位寄存器,但(通常)没有更大的寄存器。

【讨论】:

  • 例如,386SX 有 16 位数据总线,但它是 32 位处理器。另一方面,当前的 x86 cpu 使用缓存线来访问主内存,这远远超过“位数”。
  • @Jester 至于缓存行,您可能是对的。现代 CPU 变得如此复杂。
  • 32 位 x86 还具有 64 位 MMX 寄存器和最多 512 位 AVX512 ZMM 寄存器。 只有通用整数寄存器是 32 位的。 (当然,在支持 64 位的 CPU 上,它们物理存储在 64 位物理寄存器的低半部分,就像在 64 位模式下使用 32 位操作数大小时一样。)The connection between L1d cache and execution units is up to 512 bits wide(在 Skylake 中-AVX512)。
  • 你的定义听起来并不比维基百科的好。
  • 伙计们,当然,这个答案有问题。但另一种选择是像 Peter Cordes 那样写一篇论文,这对于 OP 来说“信息太多”并且充满了未知单词,他只是想知道小于 32 位的寄存器是怎么回事。
猜你喜欢
  • 2012-02-25
  • 2023-03-29
  • 1970-01-01
  • 1970-01-01
  • 2019-08-02
  • 2012-03-28
  • 2013-08-11
  • 1970-01-01
  • 2014-04-02
相关资源
最近更新 更多