我们大家都知道, CPU 访问内存时,需要知道访问内存的具体地址,内存单元是内存的基本单位,每一个内存单元在内存中都有唯一的地址,这个地址即是 物理地址。而 CPU 和内存之间的交互有三条总线,即数据总线、控制总线和地址总线。
CPU 通过地址总线将物理地址送入存储器,那么 CPU 是如何形成的物理地址呢?这将是我们接下来的讨论重点。
现在,我们先来讨论一下和 8086 CPU 有关的结构问题。
cxuan 和你聊了这么久,你应该知道 8086 CPU 是 16 位的 CPU 了,那么,什么是 16 位的 CPU 呢?
你可能大致听过这个回答,16 位 CPU 指的是 CPU 一次能处理的数据是 16 位的,能回答这个问题代表你的底层还不错,但是不够全面,其实,16 位的 CPU 指的是
CPU 内部的运算器一次最多能处理 16 位的数据
运算器其实就是 ALU,运算控制单元,它是 CPU 内部的三大核心器件之一,主要负责数据的运算。
寄存器的最大宽度为 16 位
这个寄存器的最大宽度值得就是通用寄存器能处理的二进制数的最大位数
寄存器和运算器之间的通路为 16 位
这个指的是寄存器和运算器之间的总线,一次能传输 16 位的数据
好了,现在你应该知道为什么叫做 16 位 CPU 了吧。
在你知道上面这个问题的答案之后,我们下面就来聊一聊如何计算物理地址。
8086 CPU 有 20 位地址总线,每一条总线都可以传输一位的地址,所以 8086 CPU 可以传送 20 位地址,也就是说,8086 CPU 可以达到 2^20 次幂的寻址能力,也就是 1MB。8086 CPU 又是 16 位的结构,从 8086 CPU 的结构看,它只能传输 16 位的地址,也就是 2^16 次幂也就是 64 KB,那么它如何达到 1MB 的寻址能力呢?
原来,8086 CPU 的内部采用两个 16 位地址合成的方式来传输一个 20 位的物理地址,如下图所示
叙述一下上图描述的过程
CPU 中相关组件提供两个地址:段地址和偏移地址,这两个地址都是 16 位的,他们经由地址加法器变为 20 位的物理地址,这个地址即是输入输出控制电路传递给内存的物理地址,由此完成物理地址的转换。
地址加法器采用 物理地址 = 段地址 * 16 + 偏移地址 的方法用段地址和偏移地址合成物理地址。
下面是地址加法器的工作流程
其实段地址 * 16 ,就是左移 4 位。在上面的叙述中,物理地址 = 段地址 * 16 + 偏移地址,其实就是基础地址 + 偏移地址 = 物理地址 寻址模式的一种具体实现方案。基础地址其实就等于段地址 * 16。
你可能不太清楚 段 的概念,下面我们就来探讨一下。
什么是段段这个概念经常出现在操作系统中,比如在内存管理中,操作系统会把不同的数据分成 段来存储,比如 代码段、数据段、bss 段、rodata 段 等。
但是这些的划分并不是内存干的,cxuan 告诉你是谁干的,这其实是幕后 Boss CPU 搞的,内存当作了声讨的对象。
其实,内存没有进行分段,分段完全是由 CPU 搞的,上面聊过的通过基础地址 + 偏移地址 = 物理地址的方式给出内存单元的物理地址,使得我们可以分段管理 CPU。
如图所示
这是两个 16 KB 的程序分别被装载进内存的示意图,可以看到,这两个程序的段地址的大小都是 16380。
这里需要注意一点, 8086 CPU 段地址的计算方式是段地址 * 16,所以,16 位的寻址能力是 2^16 次方,所以一个段的长度是 64 KB。
段寄存器