8086 是 Intel 公司第一款 16 位处理器,诞生于 1978 年,所以说它很古老。
一.8086 的通用寄存器
8086 处理器内部共有 8 个 16 位的通用处理器,分别被命名为 AX、 BX、 CX、 DX、 SI、 DI、 BP、 SP。如下图所示。
“通用”的意思是,它们之中的大部分都可以根据需要用于多种目的。
二.程序的重定位难题
2.1 代码段和数据段
处理器是自动化的器件,在给出了起始地址之后,它将从这个地址开始,自动地取出每条指令并加以执行。
只要每条指令都正确无误,它就能准确地知道下一条指令的地址。
这就意味着:
(1)完成某个工作的所有指令,必须集中在一起,处于内存的某个位置,形成一个段,叫做代码段。
若指令中间夹杂了其它非指令的数据,处理器将因为不能识别而出错。
(2)程序总要操作大量的数据,这些数据也应该集中在一起,位于内存中的某个地方,形成一个段,叫做数据段。
我们并没有改变内存的物理性质,并不是真的把它分成几块。段的划分是逻辑上的,从本质上来说,是如何看待和组织内存中的数据。
2.2 单任务
段在内存中的位置并不重要,因为处理器是可控的,我们可以让它从内存的任何位置开始取指令并加以执行。
如下图,整个程序(包括代码段和数据段)在内存中的位置, 是由我们自己决定的。我们把数据段定在 0100H,把代码段定在 0120H。
2.3 多任务
大多数时候,整个程序(包括代码段和数据段)在内存中的位置并不是我们能够决定的。
程序在 Windows 里启动之前,内存已经被塞了很多东西。在这种情况下,你所运行的程序,在内存中被加载的位置完全是随机的,哪里有空闲的地方,它就会被加载到哪里,并从那里开始被处理器执行。
如下图所示,因为程序现在从内存地址 1000H 处被加载的,所以,数据段的起始地址为 1000H。代码段依然紧挨着数据段之后,起始地址相应地是 1020H。
只要所有的指令都是连续存放的,代码段位于内存中的什么地方都可以正常执行。但指令中包含的数据地址是绝对地址(物理地址),这样的程序是无法重定位的。
为了让你写的程序在卖给别人之后,可以在内存中的任何地方正确执行,就只能在编写程序的时候使用相对地址或者逻辑地址了,而不是使用真实的物理地址。当程序加载时,这些相对地址还要根据程序实际被加载的位置重新计算。
2.4 解决-分段机制
在任何时候,程序的重定位都是非常棘手的事情。当然,也有好几种解决的办法。在 8086 处理器上,这个问题特别容易解决,因为该处理器在访问内存时使用了分段机制。
三.内存分段机制
3.1 概述
采用分段策略之后,一个内存单元的地址实际上就可以用“段:偏移”或者“段地址:偏移地址”来表示,这就是通常所说的逻辑地址。
为了在硬件一级提供对“段地址:偏移地址”内存访问模式的支持,处理器至少要提供两个段寄存器,分别是代码段寄存器(CS)和数据段寄存器(DS)。
对 CS 内容的改变将导致处理器从新的代码段开始执行。同样,在开始访问内存中的数据之前,也必须首先设置好 DS 寄存器,使之指向数据段。
除此之外,最重要的是, 当处理器访问内存时,它把指令中指定的内存地址看成是段内的偏移地址,而不是物理地址。 这样,一旦处理器遇到一条访问内存的指令,它将把 DS 中的数据段起始地址和指令中提供的段内偏移相加,来得到访问内存所需要的物理地址。
3.2 8086 的内存分段机制
3.2.1 段寄存器
3.2.2 指令指针寄存器
它只和 CS 一起使用,而且只有处理器才能直接改变它的内容。
当一段代码开始执行时, CS 指向代码段的起始地址, IP 则指向段内偏移。这样,由 CS 和 IP 共同形成逻辑地址,并由总线接口部件变换成物理地址来取得指令。
然后,处理器会自动根据当前指令的长度来改变 IP 的值,使它指向下一条指令。
3.2.3 地址线 20 根
8086 的段寄存器和 IP 寄存器都是 16 位的,而地址线却有 20 根。
为解决这个问题, 8086 处理器在形成物理地址时,先将段寄存器的内容左移 4 位,形成 20 位的段地址,然后再同 16 位的偏移地址相加,得到 20 位的物理地址。