8086结构

x86架构中经典的处理器8086的大体结构如下:

20220719183423

其寻址范围为1M

为了暂存数据,8086 处理器内部有 8 个 16 位的通用寄存器,也就是刚才说的 CPU 内部的数据单元,分别是 AX、BX、CX、DX、SP、BP、SI、DI。这些寄存器主要用于在计算过程中暂存数据。这些寄存器比较灵活,其中 AX、BX、CX、DX 可以分成两个 8 位的寄存器来使用,分别是 AH、AL、BH、BL、CH、CL、DH、DL,其中 H 就是 High(高位),L 就是 Low(低位)的意思。

控制单元:

IP 寄存器就是指令指针寄存器(Instruction Pointer Register),指向代码段中下一条指令的位置。CPU 会根据它来不断地将指令从内存的代码段中,加载到 CPU 的指令队列中,然后交给运算单元去执行。

如果需要切换进程,每个进程都分代码段和数据段,为了指向不同进程的地址空间,有四个 16 位的段寄存器,分别是 CS、DS、SS、ES。

其中,CS 就是代码段寄存器(Code Segment Register),通过它可以找到代码在内存中的位置;DS 是数据段的寄存器,通过它可以找到数据在内存中的位置。SS 是栈寄存器(Stack Register)。栈是程序运行中一个特殊的数据结构,数据的存取只能从一端进行,秉承后进先出的原则,push 就是入栈,pop 就是出栈。

存储起始地址的CS和DS都是16位的;存储偏移量的IP寄存器和通用寄存器都是16位的;但8086地址总线是20位的。如何从16位的寄存器寻址到20位的地址?

方法是:起始地址×16+偏移量,也就是把 CS 和 DS 中的值左移 4 位,变成 20 位的,加上 16 位的偏移量,这样就可以得到最终 20 位(1M)的数据地址。

32位处理器

32位处理器必须保持和原来处理器的兼容。

首先,通用寄存器有扩展,可以将 8 个 16 位的扩展到 8 个 32 位的,但是依然可以保留 16 位的和 8 位的使用方式。其中,指向下一条指令的指令指针寄存器 IP,就会扩展成 32 位的,同样也兼容 16 位的。

20220719184256

而段寄存器仍然是16位,但其含义不再是段的起始地址。段的起始地址放在内存的某个地方。这个地方是一个表格,表格中的一项一项是段描述符(Segment Descriptor)。这里面才是真正的段的起始地址。而段寄存器里面保存的是在这个表格中的哪一项,称为选择子(Selector)。

这样,将一个从段寄存器直接拿到的段起始地址,就变成了先间接地从段寄存器找到表格中的一项,再从表格中的一项中拿到段起始地址。这样段起始地址就会很灵活了。当然为了快速拿到段起始地址,段寄存器会从内存中拿到 CPU 的描述符高速缓存器中。

实模式和保护模式

段寄存器的含义改变后,就与原来的的模式不兼容了。处理这个问题的办法是为处理器定义两种模式,当系统刚刚启动时,CPU处于实模式,这时候和原来的模式是兼容的。当需要更多内存时,切换到保护模式,就能用32位CPU更强大的能力。

实模式直接获取到段的起始地址,保护模式先读取寄存器选择子,再从选择子中获取实际的段的起始地址

  • 切换到保护模式需要做以下三件事:
    • 启用分段, 辅助进程管理
    • 启动分页, 辅助内存管理
    • 打开其他地址线