首页 文章

x86寄存器:MBR / MDR和指令寄存器

提问于
浏览
0

根据我的阅读,IA-32架构有10个32位和6个16位寄存器 .

32位寄存器如下:

  • 数据寄存器 - EAX,EBX,ECX,EDX

  • 指针寄存器 - EIP,ESP,EBP

  • 索引寄存器 - ESI,EDI

  • 控制寄存器 - EFLAG(EIP也被归类为控制寄存器)

16位寄存器如下:

  • 代码段:它包含要执行的所有指令 .

  • 数据段:它包含数据,常量和工作区域 .

  • 堆栈段:它包含过程或子程序的数据和返回地址 .

  • 额外细分(ES) . 指向额外数据的指针 .

  • F段(FS) . 指向更多额外数据的指针 .

  • G段(GS) . 指向更多额外数据的指针 .

但是,我找不到有关当前指令寄存器(CIR)或存储器缓冲寄存器(MBR)/存储器数据寄存器(MBR)的任何信息 . 这些寄存器是否被称为其他东西?这些寄存器是32位吗?

我假设它们是32位的,并且在这种架构下最常用的指令长度不超过4个字节 . 从观察来看,许多指令似乎都在4个字节以下,例如:

  • 推动EBP(55)

  • MOV EBP,ESP(8B EC)

  • LEA(8D 44 38 02)

对于更长的指令,CPU将使用前缀代码和其他可选代码 . 较长的指令需要多个周期才能完成,这取决于指令长度 .

我是否正确,因为有问题的寄存器长度为32位? IA-32架构中是否还有其他寄存器,我也应该注意这些寄存器?

1 回答

  • 5

    不,您所谈论的寄存器是一个实现细节,在现代x86 CPU中不作为物理寄存器存在 .

    x86 doesn't specify any of those implementation details you find in toy / teaching CPU designs. The x86 manuals only specify things that are architecturally visible.

    英特尔和AMD _2906344都不像你的建议 . 现代x86 CPU将架构寄存器重命名为更大的物理寄存器文件,从而实现无序执行,而不会导致写入后写入或读后读取数据危险 . (有关寄存器重命名的更多详细信息,请参阅Why does mulss take only 3 cycles on Haswell, different from Agner's instruction tables?) . 有关无序执行程序的基本介绍,请参阅this answer,以及实际Haswell核心的框图 . (并记住物理芯片有多个核心) .


    与简单或玩具微体系结构不同,几乎所有高性能CPU都支持未命中和未命中的错过(多个未完成的缓存未命中,而不是完全阻止等待第一个完成的内存操作)


    您可以构建一个具有单个MBR / MDR的简单x86;如果原始的8086和386个微体系结构具有类似内部实现的一部分,我不会感到惊讶 .

    但是,例如Haswell或Skylake核心可以从/到L1d缓存每个周期执行2次加载和1次存储(参见How can cache be that fast?) . 显然他们不能只有一个MBR . 相反, Haswell has 72 load-buffer entries and 42 store-buffer entries, which all together are part of the Memory Order Buffer 支持无序执行加载/存储,同时保持只有StoreLoad重新排序发生/其他核心可见的错觉 .

    自从P5奔腾,naturally-aligned loads/stores up to 64 bits are guaranteed atomic,但在此之前只有32位访问是原子的 . 所以,是的,如果386/486有一个MDR,它可能是32位 . 但即便是那些早期的CPU也可以在CPU和RAM之间进行缓存 .

    我们知道Haswell and later have a 256-bit path between L1d cache and execution units,即32字节,而Skylake-AVX512具有用于ZMM加载/存储的64字节路径 . AMD CPU将宽矢量操作分成128位块,因此它们的加载/存储缓冲区条目大概只有16个字节宽 .

    英特尔CPU至少将相邻存储区合并到存储缓冲区内的同一缓存线,并且还有10个LFB(线填充缓冲区)用于L1d和L2之间(或从核到L3或DRAM)的挂起传输 .


    指令解码:x86是可变长度的

    x86是可变长度指令集;在前缀之后,最长的指令长于32位 . 即使对于8086也是如此 . 例如, add word [bx+disp16], imm16 长度为6个字节 . 但是8088只有一个4字节的预取队列来解码(相对于8086 's 6 byte queue), so it had to support decoding instructions without having loaded the whole thing from memory. 8088 / 8086 decoded prefixes 1 cycle at a time, and 4 bytes of opcode + modRM is definitely enough to identify the length of the rest of the instruction, so it could decode it and then fetch the disp16 and/or imm16 if they weren' t) . 现代x86可以有更长的指令,尤其是SSSE3 / SSE4需要许多强制性前缀作为操作码的一部分 .

    It's also a CISC ISA, so keeping around the actual instruction bytes internally isn't very useful; you can't use the instruction bits directly as internal control signals the way you can with a simple MIPS.

    在非流水线CPU中,是的,某处可能存在单个物理EIP寄存器 . 对于现代CPU,每条指令都有一个与之关联的EIP,但许多指令在CPU内部同时处于运行状态 . 有序流水线CPU可能会将EIP与每个阶段相关联,但是无序CPU必须在每指令基础 . (实际上每个uop,因为复杂的指令解码到超过1个内部uop . )

    现代x86采用16或32字节的块进行读取和解码,每个时钟周期解码多达5或6条指令,并将解码结果放入队列,以便前端发布到核心的无序部分 .

    另请参阅https://stackoverflow.com/tags/x86/info中的CPU内部链接,尤其是David Kanter 's write-ups and Agner Fog' s微型指南 .


    顺便说一句,你遗漏了x86的许多控制/调试寄存器 . CR0..4对于启用保护模式,分页和各种其他内容的386至关重要 . 您可以仅使用GP和段regs以及EFLAGS在实模式下使用CPU,但如果包含操作系统需要管理的非通用注册表,则x86具有更多架构寄存器 .

相关问题