本篇主要介绍CPU的组成以及记录下其中关于寄存器的知识。以x86为例进行说明。

CPU的组成

我们知道现在的电脑组成一般包含CPU、内存、USB、硬盘、网卡、显卡、声卡等等,其中CPU和内存较为重要,CPU(Central Processing Unit,中央处理器)是一台电脑的核心,可以视作一个人的大脑,可以说所有设备都是围绕它来展开的(计算机的计算二字全都在CPU里了,你说它核心不核心)。

而这些设备之间的连接血管或者经络是一个叫做总线(Bus)的东西。其连接的逻辑图如下所示:

对于其他的设备而言,内存是相对来说最为重要的。CPU是拥有计算能力的,但是我们在计算的时候需要计算什么数据呢(也就是数据在哪儿)?计算的结果又存放在哪儿呢?由于CPU造价昂贵(各位可以对比下配置电脑的时候CPU和内存条的价格就心中有数了),并且其主要功能是“计算”二字,所以不可能将存储大量数据的功能也放置在CPU中(并不是说CPU中就没有一点儿数据了),这个时候就需要一个跟CPU进行“沟通”并且速度不能太慢的硬件–内存。

CPU是如何计算的?

CPU是负责计算的,那么一定可以想到CPU中是拥有一个计算能力的硬件组成,一般我们把其成为计算单元,它的责任就只有这一个单调的能力,比如做加法、位移等。但是这依旧存在一个问题,它计算的数据是从哪儿来的?结果需要放到哪儿?

上面介绍过内存解决了数据从哪儿来、存放在哪儿的问题,但是现在又有一个问题,若每次的计算数据都是通过总线去内存中拿,因为内存速度还远比不上CPU的计算速度,这就会导致计算的时间远小于取数据的时间,不能够“榨干”CPU性能,就像人只用了幼儿园的大脑,完全是浪费行为(浪费可耻)。所以,CPU中有了计算的硬件之后,还需要有一个能够跟得上计算能力的存储结构,我们把它叫做数据单元。数据单元其特点就是存取数据飞一般的感觉,用来暂时存放数据和运算结果,其包括了CPU缓存寄存器组

好了,现在有了计算能力的计算单元,也有了能跟上计算能力的存储结构数据单元,那么就可以进行计算了…然后怎么去计算呢?也就是说该计算什么不该计算什么呢?所以CPU光有计算单元、数据单元是不能够有效的进行目的性计算的,必须有一个能够控制计算的存在,去控制指挥计算,我们把这个硬件称为控制单元控制单元负责获取下一条指令并且去执行这条指令。这个指令会指导运算单元取出数据单元中的某些数据进行计算,之后放在数据单元中去。

所以,总的来说CPU分为计算单元(计算能力)、数据单元(存放数据)、控制单元(怎么去计算)三部分组成,并且依靠这三个部分相互合作协调去计算目的指令的值。

CPU与内存的合作

一个程序运行时,会有独立的内存空间,程序会被加载自己的内存中形成代码段,代码段中可以认为存放的是需要执行的指令、指令集,也就是CPU的控制单元需要执行的对象。

程序在运行时,还需要对一些数据进行操作并且会产生一些结果,这些数据都存放在内存的数据段中。

那么问题来了,CPU是如何执行这些指令、操作这些数据、写回结果到内存中呢?

首先指令怎么取?为了解决这个问题,CPU的控制单元中(为什么是控制单元呢?因为其职责就是控制呀)设置了一个指令指针寄存器,里面存放了下一条指令在内存中的地址。这样就可以去内存中将要执行的指令取过来。但是取过来之后放在哪儿呢(不可能是指令指针寄存器了)?CPU的控制单元又提供了一个指令寄存器,用来存放将要执行的指令。

现在有了指令了,那么计算单元怎么去计算呢?这得从这条指令结构说起:要执行的这条指令被分为了两部分,一部分是要做什么操作(计算需求),一部分是要操作什么(数据需求)。所以这条指令会把第一部分交给计算单元去进行计算,将第二部分交给数据单元。

对于一个进程现在已经可以进行CPU运算了,但是当存在多个进程的时候呢?为此,CPU在控制单元中设置了两个寄存器:一个保存当前处理进程的代码段的起始地址,一个保存进程的数据段起始地址。这两个寄存器中写的是A进程的地址就运行的是A进程指令,是B进程的地址就运行的是B进程指令,而这个切换执行指令的行为就是进程切换

到此,我们发现内存跟CPU之间交互数据都是靠的总线。但是总线传输的数据也可以分为两类:一类是地址数据,也就是想获取内存中哪个位置的数据,这类总线被称为地址总线;一类是内存的真正的数据,这类叫做数据总线

地址总线确定了CPU可以访问内存的范围有多大,比如地址总线为两位,那么可以访问的地址只有00 01 10 11这四个位置,超过这四个位置的就无法区分了。

数据总线确定了一次能够拿多少个数据进来。比如是两位数据总线,那么一次只能拿两位数进来,若想获取更多的数,必须要更多次数来拿取。

控制单元、计算单元、数据单元的组成

作为一个假装求知若渴的人,我就在想上面介绍的数据单元、控制单元、计算单元到底是什么组成的呢?当然是二极管啊…是直接由二极管组成的吗?还是说由其他寄存器组成?这样想了就去看看⑧

以早期8086处理器为模型. …

首先看看数据单元:

上面说过CPU需要暂存数据,为了达到这个目的芯片设计师在8086处理器中有8个16位的通用寄存器,也就是上上图的CPU中的数据单元,分别是AX、BX、CX、DX、SP、BP、SI、DI。这些寄存器主要就是为了暂存数据。

想想当时计算机CPU的资源多珍贵,而我们的存储的数据不光有16位的,还有一些小数据4位、8位等,因此为了更加充分压榨CPU,就将其中的四个寄存器AX、BX、CX、DX分别分成两个八位寄存器来使用,分别是上面的AH、AL、BH、BL、CH、CL、DH、DL,其中H表示高位high,L表示地位low。这样长数据端数据都能够暂存了。

接下来是控制单元:

首先是其他寄存器。over

其次,我们主要关注IP(Instruction Pointer)寄存器,它就是上上上(CPU运行图)个图中的控制单元的指令指针寄存器,其指向代码段下一条指令的位置。CPU能够不断的从内存中找到指令就是靠它了,找到之后会加载到CPU的指令队列中(有没有类似的熟悉味道?OS接收缓冲、kafka接收缓冲消息?思想有点儿类似哈),之后交给运算单元去计算执行。这样就保证了一个进程在CPU中的执行,那么多个进程存在的时候怎么办呢?怎么切换呢?

首先,我们知道每个进程都分为代码段和数据段,那么肯定有两个寄存器指向代码段和数据段,也就是CS(代码段寄存器)和DS(数据段寄存器),通过CS可以找到代码在内存中的位置,通过DS可以找到数据在内存中的位置。从上图可知,还有两个寄存器SS、ES。这两个也是段寄存器,带着存在即合理的说法去找找它们“合理的理由”。由于我们程序中存在一种特殊的数据结构—栈,其数据的存取只能从一端进行,为了适应这种特殊的数据存取也就除了相应的寄存器SS(stack register,栈寄存器)。凡是与函数相关的操作,都与栈紧密相关(所以我认为这可能是存在栈寄存器的一个重要原因,未考证求认证)。

从上面知道可以通过DS找到内存中的数据并加载到通用寄存器中,那么是怎么加载的呢?对于一个段(从段寄存器中加载)都有一个段的起始地址,而段的具体位置是一个数据量称之为偏移量(offset)。在DS、CS中都存放着段的起始地址,代码段的偏移量存放在IP寄存器中(所以说IP存放着指令地址),数据段的偏移量放在通用寄存器中。

这里注意有一个问题存在:IP寄存器和通用寄存器都是16位的,但是8086的总线是20位的,那么这里就会“差4位”了,需要怎么凑齐呢?其方法就是“起始地址*16+偏移量”,也就是把CS、DS中的值左移4位变成20位了,再加上16位的偏移量就可以得到20位的数据地址了。所以我们可以知道8086的最大的内存(能区分的地址大小)为2^20=1M,超过这个空间就不能识别了。而一个段因为只有16位,所以一个段的最大地址为2^16=64kb。LOL直接卡死,pass。

32位处理器

计算机发展日新月异,原来的8086处理器早已不能满足各大玩家的需求,相应出来了32位、64位处理器,以32位处理器为例进行说明。

32位的地址总线,可以识别的内存大小为2^32=4G。所以原来的架构是远远不够的了,但是又不能丢弃原来的架构(丢弃了就不兼容,顾客不满意,顾客就是上帝,上帝抛弃你,GG),因此就需要让其兼容原来的20位的地址总线的架构。

首先是8个通用寄存器,可以直接将这八个通用寄存器扩展到32位,但是还是要保留16位、8位的使用方式;而指向下一条指令地址的指令指针寄存器IP也扩展为32位,同样也可以兼容16位的。

而改动比较大的就是段寄存器了。为原来的段寄存器位数,并不是一个段的起始地址,也不是按照8位或16位这样来进行扩展的,而是为了满足地址总线弄了一个20位地址,这样每次都需要左移四位。为了解决这个问题,只能重新进行定义了。首先为了尽可能的兼容,CS、DS、DS、ES仍然是16位的,但是其不再是段的起始地址(左移4位后),其映射的是内存中的一个地址,这个内存中内容称为选择子。段的起始地址就保存在内存这个地方,这个地方是一个表格,表格中的一项是段描述符,也就是真正的段起始地址。这样就是先从段寄存器中拿到一个内存中的表格的一项,再从表格中的一项拿到段起始地址(是不是又是中间层解决问题的思想)。但是这样确实还是不兼容。

我们将前面一种模式(20位地址)称为实模式,后面这种称为保护模式。当32位系统刚刚启动的时候CPU是处于实模式的,这个时候是和原来的20位是兼容的。当需要更多的内存的时候,可以进行模式的切换到32位的保护模式下运行。这样通过切换模式来实现了兼容。

参考:《计算机组成原理》《趣谈Linux操作系统》《UINX高级环境编程》

说明:本文主要是记录自己学习笔记,加深自己理解,有些比喻不太恰当的地方请轻喷。错误的知识请使劲儿。因此本文只做参考与理解