梁说:8086最头疼的问题在于段式结构,1MB的内存被它的段偏移所限制。至今我也不明白Intel当初为什何要设计成这么复杂的内存机制,也许是为了与8080兼容的需要。这套笨拙的体系一直延续到IA64为止。
以下文字参考Linux内核源代码情景分析一书。
当我们说一个CPU是”16位”或”32”位时,指的是处理器中”算术逻辑单元”[ALU]的宽度。系统总线中的数据线部分,称为数据总线,它通常与ALU有相同的宽度。另外,还有一条地址总线来访问内存,它的宽度应该与数据总线一致,这是因为从程序设计的角度来说,一个地址是一个指针,最好与CPU所处理的一个整数的宽度一致,但实际情况是不可能这样的。8位CPU如果让地址总线也是8位,那只能寻址256个不同的地址单元,太小了。所以8位的CPU的地址总线通常是16位的,但这样,在8位的指令系统中常存在着一些16位的操作。后来CPU发展到了16位,本来地址总线和数据总线的宽度应该可以一致了,但当时人们又觉得16位的地址总线可以寻址的空间还是太小啊,还要加大。那加到多大?Intel结合当时人们所能看到的微型计算机的应用前景以及存储器芯片的价格,决定用1MB。由此可见,CPU的地址总线不是你觉得多少位好就采用多少位的宽度了,它要对当时存储器的价位进行衡量才可以确定要多少位的地址总线,假如当时人们不是普遍觉得1MB内存足够用的话,那么CPU发展到我们今天就有可能不是现在这样了,可能32位的地址总线就在8086中出现了。就这样,8086决定要用1MB的内存时,那么地址总线就必须是20位的宽度,但CPU的ALU的宽度只有16位,也就是说在内存寻址时参与计算的地址指针也只能是16位的。该如何解决这个问题,这应该是当时很困扰Intel的设计人员的问题,如果像8位计算机所做的那样,在CPU的指令集中添加一些20位的指令来进行内存寻址,这样会导致CPU内部结构的不均匀性(想一想就知道了,CPU内部的电路系统又要处理16位的指令,又要处理20位的指令,麻烦不麻烦?)。Intel设计人员后来选择了分段机制,这在当时看来应该是很巧妙的方法了。当时PDP-II小型机也是16位的,但它可以通过内存管理机制将16位的地址映射到24位的地址空间,intel应该是借鉴了它的思路。
Intel在8086CPU中设置了四个”段寄存器”,每个段寄存器都是16位的,对应于地址总线的高16位。每条访问内存的指令中的内部地址也都是16位的,但是在将地址传到地址总线上之前,要使用CPU内部的加法器对内部地址和某个段寄存器中的地址相加,形成一个20位的地址。由于段寄存器中的内容对应于20位地址总线中的高16位,所以在相加时是拿内部地址的高12位与段寄存器中的16位相加,而内部地址中的低四位保持不变。这个方法与操作系统理论中的”段式内存管理”相似,但并不完全一样,主要是没有地址空间的保护机制,对每一个由段寄存器的内容确定的”基地址”,一个进程总是能够访问从此开始的64K字节的连续空间,而无法加以限制。同时,可以用来改变段寄存器内容的指令也不是什么”特权指令”,也就是说通过改变段寄存器的内容,一个进程可以随心所欲地访问内存中的任何一个单元,而丝毫不受到限制,能对一个进程的内存访问加以限制,也就谈不上对其他进程以及系统本身的保护。与此相应,一个CPU如果缺乏对内存访问的限制,就谈不上什么内存管理,也就谈不上是现代意义上的中央处理器。由此,而生出”保护模式”的概念。
本文地址:http://com.8s8s.com/it/it23175.htm