16位微处理器
8086寄存器组成
8086/8088包括:4个16位的数据寄存器,2个16位的指针寄存器,2个16位变址寄存器,分成四组。
通用寄存器中,这些寄存器除完成规定的专门用途外,均可用于传送和暂存数据,可以保存算术逻辑运算的操作和运算结果。
段寄存器能在8086 中实现1M物理空间寻址,并可与8080 CPU进行兼容。段寄存器都是16位的,分别称为代码段(Code Segment)寄存器CS、数据段(Data Segment)寄存器DS、堆栈段(Stack Segment)寄存器SS,附加段寄存器。
标志寄存器在8086中有一个16位用于反映处理器的状态和运算结果的某些特征。(其中只有9位有定义)
这些标志位分为两类:
其一是运算结果标志,主要用于反映处理器的状态和运算结果特征。(例如:进位标志、零标志、符号标志、溢出标志等)
其二是状态控制标志,它控制着处理器的操作。要通过专门的指令才能使状态控制标志发生变化。(例如:方向标志、中断允许标志、追踪标志)
内存的寻址(实模式)
8086 CPU有20根地址线,可直接寻址的物理地址空间为1M。尽管8086/8088内部的ALU每次最多进行16位运算,但存放存储单元地址偏移的指针寄存器都是16位的,所以8080/8086通过内存分段和使用段寄存器的方法来有效地实现寻址1M的空间。
存储单元的逻辑地址由段值和偏移两部分组成,用如下形式表示:
段值:偏移
所以根据逻辑地址可以方便地得到存储单元的物理地址,计算公式如下:
物理地址(20位) = 段值*16+偏移
段值通过段寄存器的值来取得,偏移可由指令指针的IP或其他可作为内存指针使用的寄存器给出。偏移还可以直接用16位数给出。
指令中不使用物理地址,而使用逻辑地址,由总线接口单元BIU按需要根据段值和偏移自动形成20位物理地址。
32位微处理器
1985年,真正的32位微处理器80386DX诞生,为32位软件的开发提供了广阔的舞台。
80386寄存器的宽度大多是32位,可分为如下几组:
通用寄存器、段寄存器、指令指针
及标志寄存器、系统地址寄存器、调试寄存器、控制寄存器和测试寄存器。
应用程序主要使用前面三组寄存器,只有系统才会使用其他寄存器。
[图片上传中。。。(2)]
[说明]
由于在实模式下,段的最大范围是64KB,所以EIP的高16位必须全是0,仍相当于16位的IP作用。
注意,在32位模式下,段寄存器仍然是16位。
80836中,标志寄存器也扩展到了32位,记为EFLAG。
其中,增加了
IO特权级IOPL:当前运行程序或任务的CPL必须小于或等于这个IOPL才能访问I/O地址空间。
嵌套任务标志NT(Nest Task)
重启动标志RF(Reset Flag)
虚拟8086标志VM:当设置该标志时,就开启虚拟8086方式,当复位该标志时,则回到保护模式。
控制寄存器
控制寄存器(CR0~CR3)用于控制和确定处理器的操作模式以及当前执行任务的特性。4个控制寄存器都是32位的。
[图片上传中。。。(3)]
CR0:含有控制CPU操作模式和状态的标识
CR1:保留不用
CR2:存储导致页错误的线性地址
CR3:含有页目录表的物理内存基址
CR0中的保护控制位:
PE:CR0的位0是启用保护(Protection Enable)标志。(CR0的最低位)
当设置该位时即开启了保护模式,当复位时即进入实地址模式。这个标志仅开启段级保护,而没有启用分页机制。若要启用分页机制,那么PE和PG都要置位。
PG:CR0的位31是分页(Paging)标志。(CR0的最高位)
当设置该位时即开启了分页机制,当复位时则禁止分页机制,此时所有线性地址等同于物理地址。
注意,在开启这个标志之前必须已经开启PE标志,否则CPU会产生一个一般保护性异常。
改变PG位的代码必须在线性地址空间和物理地址空间中具有相同地址,这部分具有相同地址的代码在分页和未分页世界之间起着桥梁的作用。
如果PE=0、PG=0,处理器工作在实地址模式下。(兼容早期的实模式操作系统)
如果PE=1、PG=0,处理器工作在无分页机制的段保护模式下(兼容段式管理的操作系统)
如果PE=1、PG=1,处理器工作在段页式保护模式下
在系统刚上电时,处理器被复位成PE=0和PG=0(即实模式状态),以允许引导代码在启用分段和分页机制之前能够初始化这些寄存器和数据结构。
【程序原理】
CPU是如何处理物理地址的?
在实模式下用段寄存器左移4位与偏移量相加。在保护模式下用段描述符中的基址加偏移量。这两者其实是一样的。
当Intel把80286推出时,其地址空间变成了24位,则从8086的20位到24位,十分自然地要加大段寄存器才行。实际上,段寄存器和指针都被加大了,只是由于保护的原因,加大的部分没有被程序看见,到了80386之后,地址又从24位加大到32位。
在8086中,CPU只有“看得见部分”,但在80286之后,在“看不见部分”中已经包含了地址值。“看得见部分”就退化为只是一个标号,再也不用参与地址形成运算了。地址的形成总是从“不可看见部分”取出基址值与偏移相加形成地址。
也就是说,在实模式下,当一个段寄存器被装入一个值时,“看不见部分”的段限界被设成FFFFH,基址部分将装入值左移4位,段属性部分设成16位0特权级。这个过程与保护模式时装入一个段寄存器是同理的,只是保护模式的“不可见部分”是从描述表中取值,而实模式是一套固定的过程。
对于CPU在翻译地址时,是没有实模式与保护模式之分的,它只管用基址(“不可见部分”)去加上偏移量。
实模式下的段寄存器装入有固定的形成办法,从而也就不需要保护模式的“描述符”了,因此,保持了与8086/8088的兼容性。而“描述符”也只是为了装入段寄存器的“不可见部分”而设的。(保护模式。还为了存储段属性等实现保护机制的数据结构)
CPU的地址形成与“看得见部分”的当前值毫无关系。这也就解释了为什么刚进入保护模式时,后面的代码依然被正确地运行,而这时代码段寄存器CS的值还是进入保护模式前的实模式值,或者从保护模式回到实模式时,代码段CS被改变之前程序是正常地工作,而不会“突变”到CS左移4位的地址上去。
比如:在保护模式时,CS是08H的选择子,到了实模式时,CS还是08H,但地址不会突然变成80H加上偏移量。因为地址的形成不理会段寄存器“看得见部分”的当前值,这一值只是在被装入时对CPU有用。(实模式与保护模式只是在向段寄存器加载值时处理不同,之后的处理是相同的)
地址的形成与CPU的工作模式无关,也就是说,实模式与0特权级保护模式不分页时是一模一样的。明白了这一机理后,在实模式下一样可以处理通常被认为只有在保护模式才能做的事,比如访问整个机器的内存。不必理会保护模式下的众多术语或许会更易于理解,如选择子就是“看得见部分”,描述符是为了装入“不可见部分”而设的。
【后记】
内存管理,实际上是CPU制造厂家提出的内存管理方案,并提供了硬件机制来帮助操作系统来实现。操作系统做的工作就是维护相关的数据结构,并做具体的操作。
CPU提供了各种段寄存器用于查询段表中的段,还提供了控制寄存器用于实现段页式内存管理,而段表和页表等数据结构是要由操作系统来实现并维护的。