计算机的工作模式
![](https://s1.51cto.com/images/blog/201904/11/80cbdd82448b3ec59dbd90ce0b8efeed.jpeg?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)
对于计算机来说,CPU(central processing Unit,中央处理器)肯定是最核心的,程序执行全都要依赖于它。
CPU和其他设备连接,要靠一种叫总线(bus)的东西,其实就是主板上密密麻麻的集成电路,这些东西组成了CPU和其他设备的高速通道。
在这些设备中,最重要的是内存(memory),因为单靠CPU是没法完成计算任务的,很多复杂的计算任务需要把中间结果保存下来,然后基于中间结果进行进一步计算,CPU本身是没有办法保存这些结果的,这就需要依赖内存了。
当然总线上也会有一些其他设备,例如显卡会连接显示器,磁盘控制器会连接硬盘,USB控制器会连接鼠标和键盘等等。
CPU和内存是完成计算任务的核心组件,CPU其实也不是单独一块,它包括三个部分,运算单元 ,数据单元和控制单元。
* 运算单元只管算,例如做加法,做位移等等。但是它不知道应该算哪些数据,运算结果应该放在哪里。运算单元计算的数据如果每次都要经过总线,到内存中去现拿,这样就太慢了,
* 所以有了数据单元。数据单元包括CPU内部的缓存和寄存器组,空间很小,但是速度飞快,可以暂时存放数据和运算结果。
* 有了放数据的地方,也有了算的地方,还需要有个指挥到底做什么运算的地方,这就是控制单元。控制单元是一个统一的指挥中心,它可以获得下一条指令,然后执行这条指令,这个指令会指定运算单元取出数据单元的某几个数据,计算出结果,然后放在数据单元的某个地方。
![](https://s1.51cto.com/images/blog/201904/11/c3f950117cef1b3188aa72c182f9b9a4.jpeg?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)‘’
CPU的控制单元中,有一个指令指针寄存器,执行的是下一条指令执行的地址,控制单元会不停的将代码段的指令拿出来,先放进指令寄存器,当前的指令分为俩部分,一部分是做什么操作,是加法还是位移;一部分是操作哪些数据,要执行这些指令,就需要把就需要把第一部分交给运算单元,第二部分交给数据单元,数据单元根据数据的地址,从数据段里读到数据寄存器里,就可以参与运算了。运算单元做完运算,产生的结果会暂存在数据单元的数据寄存器里,最终会有指令将数据写回内存中的数据段。CPU有俩个寄存器,专门保存当前处理进程的代码段的起始地址,以及数据段的起始地址,这里面写的都是进程A,那当前执行的就是进程A的指令,等切换成进程B,就会执行B的指令了,这个过程叫做进程切换(process switch)。这是一个多任务系统的必备操作。
CPU和内存传输数据都是依靠总线,总线上主要有俩类数据,一个是地址数据,也就是我想拿内存中哪个位置的数据,这类总线叫做地址总线(Address bus);另一类是真正的数据,这类总线叫数据总线(data bus).总线有点像连接CPU和内存的高速公路,说总线到底有多少位,就类似说高速公路有几个车道,地址总线的位数,决定了能访问的地址范围到底有多广,例如只有俩位,那CPU就只能认00,01,10,11四个位置,超过这四个位置,就区分不出来了,位数越多,能够访问的位置就越多,能管理的内存范围就越广。而数据总线的位数,决定了一次能拿多少数据进来,例如只有俩位,那CPU一次只能从内存拿俩位数,要想拿八位就需要拿四次,位数越多,一次拿的数据就越多,访问速度也就越快。
英特尔技术成为行业的开放事实标准,这个系列开端于8086,因此称为X86架构,后来英特尔的数据总线和位置总线越来越宽,处理能力越来越强,但是一直不能忘记三点,一个是标准,二是开放,三是兼容。
![](https://s1.51cto.com/images/blog/201904/11/7d96daa2264a510e55fd5d54a194ef50.jpeg?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)
* 先来看数据单元,为了暂存数据,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就是出栈。凡是与函数调用相关的操作,都与栈紧密相关
如果运算中需要加载内存中的数据,需垚通过DS找到内存中的数据,加载到通用寄存器中,对于一个段,有一个起始的地址,而段内的具体位置,我们称为偏移量(Offset),在CS和DS中都存着一个段的起始地址。代码段的偏移量在IP寄存器中,数据段的偏移量会放到通用寄存器中。CS和DS都是16位的,起始地址都是16位的,IP寄存器和通用寄存器也都是16位的,偏移量也是16位的,但是8086的地址总线地址是20位,方法就是起始地址16+偏移量,也就是把CS和DS中的值左移4位,变成20位,加上16位的偏移量,这样就可以得到20位的数据地址。从这个计算方式可以算出,无论真正的内存多么大,对于只有20位地址总现的8086来讲,能够分出的地址也就2^20=1M,超过这个空间就访问不到了。如果你想访问1M+X的地方,这个位置已经超出20位了,由于地址总线只有20位,在总线上超过20位的部分是发不出去的,所以发出去的还是X,最后还是会访问1M内的X的位置。那么一个段最大是多大,因为偏移量只能是16位的,所以一个段最大的大小为2^16=64K。对于8086CPU,最多只能访问1M的内存空间,还要分成多个段,每个段最多64k,不过在当时已经足够使用了。
* 32位处理器
在32位处理器中有32根地址总线,可以访问2^32=4G的内存。既然是开放的就需要保持兼容,首先,通用寄存器有扩展,可以将8个16位的扩展到8个32位的,但是依然可以保留16位的和8位的使用方式,其中指向下一条指令的指令指针寄存器IP,就会扩展成32位的,同样也兼容16位的。
![](https://s1.51cto.com/images/blog/201904/12/1bf5a03019ef1ef0539a1d0b81e531ef.jpeg?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)
而改动比较大,有点不兼容的就是段寄存器(segment register),因为原来的模式其实有一点不伦不类,因为他没有把16位当成一个段的起始位置,也没有按8位或者16位扩展的形式,而是根据当时的硬件,弄了一个不上不下的20位的地址,这样每次都要左移4位,也就意味着段的起始位置不能是任何一个地方,只是能整除16的地方。那么我们索性重新定义,CS,SS,DS,ES仍然是16位的,但是不再是段的起始地址,段的起始地址放在内存的某个地方,这个地方是一个表格,表格的一项一项是段描述符(segment descriptor),这里面才是段的真正起始地址,而段寄存器保存的是在这个表格的哪一项,称为选择子(selector),这样,将一个段寄存器直接拿到的段起始地址,就变成了先间接地从段寄存器找到表格中的一项,再从表格的一项中拿到段起始地址。这样段起始地址就会很灵活,为了快速拿到段起始地址,段寄存器会从内存中拿到CPU的描述符高速缓存器中。这样就会不兼容,好在后面这种模式灵活度非常高,可以保持将来一直兼容下去,前面的模式出现的时候,没想到自己能够成为一个标准,所以设计就没有这么灵活,因而到了32位的系统架构下,我们将前一种模式称为实模式(Real Pattern),后一种模式称为保护模式(Protected Pattern).当系统刚启动的时候,CPU是处于实模式的,这个时候和原来的模式是兼容的,当需要更多内存的时候,你可以遵循一定的规则,进行一系列的操作,然后切换到保护模式,就能用到32位CPU更强大的能力。也就是说,不能无缝兼容,但是通过切换模式兼容,也是可以接受的。
![](https://s1.51cto.com/images/blog/201904/12/3e6c148db0f8cfa1016ef597cbdaf8f8.jpeg?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)