服务器怎么看cpu数(算机是如何读懂0和1的)

本文为《BUT HOW DO IT KNOW – The Basic Principles of Computer for everyone 》笔记,文章绝大部分图片来自于这本书,用visio重新绘制,并增加不同的颜色,更便于阅读。

这一篇主要介绍CPU中Control Section的构建。我们先来回忆一下计算机的组成:

服务器怎么看cpu数(算机是如何读懂0和1的)(1)

根据前面所述,计算机有两大部分组成:CPU和RAM。CPU又包含Control section和ALU以及若干个寄存器等。

上一篇文章说了,对于CPU来说,我们把具体干活的部分称之为ALU,把起调度功能的部分称之为“Control section”,即控制单元。Control section调度过程又分为两部分:指令解析数据准备


一、Control Section基本架构

Control section的基本功能很明确,就是通过解析指令,获得各个寄存器的“读”和“写”使能端,大概样子如下图所示:

服务器怎么看cpu数(算机是如何读懂0和1的)(2)

左侧为生成的“”使能信号;

右侧为生成的“”使能信号;

“读”使能对象为6个寄存器:RAM、ACC、R0、R1、R2、R3。

“写”使能对象为8个寄存器,除RAM、ACC、R0、R1、R2、R3之外,还包括MAR、TMP。因为TMP只有“写”使能端,“读”一直使能,而MAR则不要“读”使能。

下面我们就以“加法”、“存入”以及“取指令”的过程来看一下这些使能信号是如何产生的。

1.1、如何实现加法

服务器怎么看cpu数(算机是如何读懂0和1的)(3)

前面我们介绍了stepper的实现方式,总共分成7步,其中step 7的作用是使stepper跳回至step 1,也就是说,我们能够利用的是step 1到step 6。在每一步,都会产生clk e“读”使能信号和clk s “写”使能信号,其先后关系及持续时间为:

服务器怎么看cpu数(算机是如何读懂0和1的)(4)

可见,“读”信号先使能,尔后“写”信号使能,尔后“读”信号使能结束。这样就能保证“写”操作进行时所用的数据为当前step“读”到的信号。

我们先来看一下step 4到step 6。实现逻辑如上图所示,还记得我们前面说过的吗?——左侧为“读”使能,右侧为“写”使能,我们整理一下上图的逻辑,可以得到:

服务器怎么看cpu数(算机是如何读懂0和1的)(5)

Step 4:寄存器R1中的数在“读”使能时,传输到BUS,在“写”使能时,写入到TMP里;

Step 5:寄存器R0中的数在“读”使能时传输到BUS,ALU开始工作,此时TMP在上一步已经准备好,两个输入TMP和R0都就位,ALU计算两者的;在“写”使能时,ALU计算的结果存储到ACC,注意,此时不经过BUS。

Step 6:寄存器ACC中的数在“读”使能时,传输到BUS,在“写”使能时,写入到R0里;

总的效果就是:将R0中的数加上R1中的数,存储到R0中


1.2、如何存入数据

前面将计算结果存储到了寄存器R0中, R0是CPU内部寄存器,大多数时候我们想要存到RAM里面,是否可实现呢?请看下图:

服务器怎么看cpu数(算机是如何读懂0和1的)(6)

在时钟的作用下,数据流向为:

服务器怎么看cpu数(算机是如何读懂0和1的)(7)

Step 4:寄存器R2中的数在“读”使能时,传输到BUS,在“写”使能时,写入到MAR里;

Step 5:寄存器R0中的数在“读”使能时传输到BUS,在“写”使能时,开始往RAM里写数据,数值为R0,此时RAM中地位MAR存的数据是R2。

总的效果就是:将R0中的数据存到RAM中,存储地址是R2中存的数据。


1.3、如何实现“取指令”

前面我们说了两个例子,分别是将寄存器中的数相加,以及将寄存器中的数存到RAM指定的地址中去。

这是两种完全不同的操作,怎么来区分呢?——在step 1到step 3中实现。为此,我们要再增加两个寄存器:IAR和IR,分别存储指令地址和指令内容。此时,计算机的继续丰满,如下所示:

服务器怎么看cpu数(算机是如何读懂0和1的)(8)

其中IAR有“读”和“写”两个使能端,也就是地址寄存器中内容可以有“读”和“写”两个操作;IR只有“写”使能端,也就是指令寄存器只能从总线拿数据。

接下来,我们就看一下取指令的过程是如何实现的,如下图:

服务器怎么看cpu数(算机是如何读懂0和1的)(9)

数据流向如下:

服务器怎么看cpu数(算机是如何读懂0和1的)(10)

具体过程为:

Step 1:地址寄存器IAR在“读”使能的时候,将数据传输到BUS,在“写”使能的时候,存入MAR,即RAM中地址寄存器;Step 1还有一个动作,后面再说。

Step 2:RAM中地址为MAR的数据,在“读”使能的时候,将数据传输到BUS,在“写”使能的时候,存入指令寄存器IR;

Step 3:为了能让程序自动执行,我们还需要更新IAR,一个最简单的方式就是将IAR加1,这样就对应RAM中IAR下一条指令。加法很容易实现,ALU中就有加法器,具体实现我们先不管,假设现在ALU的计算结果已经保存在ACC中,我们怎么能让程序自动运转起来?——很简单,寄存器ACC在“读”使能的时候,将数据传输到BUS,在“写”使能的时候,存入IAR,对应RAM中下一条指令;

怎么实现ALU中IAR加1的功能呢?我们知道,ALU有两个输入,一个是TMP,一个来自总线BUS,BUS由于连接的东西很多,我们最好不要动他,剩下的就只能在TMP上做做手脚。——解决方案就是在TMP和ALU中间增加一个模块,这个模块要实现的功能是要么传输TMP里面的数据,要么传输1,具体实现方式如下:

服务器怎么看cpu数(算机是如何读懂0和1的)(11)

不难分析,这个电路的实现的功能很简单,如下:

服务器怎么看cpu数(算机是如何读懂0和1的)(12)

那IAR加1的这个动作在哪一步实现呢?——step 1。我们知道在step 1的时候,IAR已经在BUS中,这时候我们bus 1=1,我们再将ACC使能,这样IAR 1就存入到了ACC中。


二、ALU指令编码及解析

对于一个8位CPU来说,指令可以分为两大类,一类为ALU相关指令,主要包括需要ALU参与完成的相关指令,比如加法、移位、比较等;另一类是非ALU相关指令,比如加载数据,存储数据,跳转等。

无论哪种指令,都可以分为前4位和后4位,前四位和动作有关,后四位和数据有关

我们先说ALU相关指令,其基本定义如下:

服务器怎么看cpu数(算机是如何读懂0和1的)(13)

最高位为1表示该条指令为ALU指令,接下来三位为操作码,表示ALU要干的具体工作;后四位的前两位和后两位表示ALU运算所需要的数据所在寄存器的编码,具体定义如上图所示。

比如,有一条ALU(1)指令执行加法(000)运算,被加的内容是Resister 2(10)里的数据与Resister 3(11)的数据,结果存放在Resister 3(11)里面,那么它对应的指令就是:

服务器怎么看cpu数(算机是如何读懂0和1的)(14)

如果把这条指令(1000 1011)存入RAM中,地址为10,那么当IAR设为10时,开启计算机,它就会从IAR为10的RAM中读取该条指令,通过总线传输至IR,然后在Control Section的控制下,去计算R2和R3之和。

如果ALU指令是单输入指令,比如SHL,SHR或者NOT,数据内容将来自Reg A,经过ALU运算,结果会被存在Reg B中。可以选在从一个寄存器取数,结果存到另外一个寄存器,比如R1→R3;可以选在从一个寄存器取数,结果存到同一个寄存器,比如R2→R2。

如果ALU指令是双输入指令,Reg A和Reg B将会被送到ALU,运算结果送到Reg B,Reg A和Reg B可以是同一个寄存器。

通过以上分析我们知道,ALU面对的是两个输入:Reg A和Reg B。Reg A和Reg B的逻辑相对是比较明确的,那就是Reg A (ALU) Reg B→Reg B,Reg A和Reg B进过ALU运算,结果存在Reg B里面,具体实现方式如下:

服务器怎么看cpu数(算机是如何读懂0和1的)(15)

数据流总结如下:

服务器怎么看cpu数(算机是如何读懂0和1的)(16)

Step 4:“读”和“写”使能端有两个条件:指令寄存器IR最高位为1,Stepper 4的clk信号为高;通过控制“读”“写”两个信号,实现Reg B的内容加载到TMP里面;

Step 5:“读”和“写”使能端有两个条件:指令寄存器IR最高位为1,Stepper 5的clk信号为高,实现Reg B的内容加上TMP里面存的Reg A,结果传输至Reg B;Stepper 5的clk信号还作为ALU操作码产生信号的控制,也就是说,只有在step 5才产生非000的ALU操作码。

Step 6:只要不是比较运算(操作码111),都要将ACC的计算计算结果存储至Reg B。

可见,对于ALU指令操作,就是Reg A和Reg B两个寄存器的数据运算和存储。但是呢,我们手上有4个寄存器:R0、R1、R2、R3,每一个Reg A或Reg B可以是R0、R1、R2、R3中的任意一个,因此,我们需要对R0、R1、R2、R3编码,这样,就可以实现对任何一个寄存器的操作,如下图所示:

服务器怎么看cpu数(算机是如何读懂0和1的)(17)

这样就可以通过指令后四位的寄存器编码,实现对寄存器里面数据的操作。

服务器怎么看cpu数(算机是如何读懂0和1的)(18)

助记符如下:

服务器怎么看cpu数(算机是如何读懂0和1的)(19)


三、非ALU指令编码及解析3.1、如何实现“load”和“store”指令

前面说了,当指令的第一位为1时,是ALU相关指令。接下来我们就看看当第一位不为1时的指令情况,见下图:

服务器怎么看cpu数(算机是如何读懂0和1的)(20)

最高位0表示非ALU指令,接下来三位为000表示加载数据,001表示存储数据。指令后四位和ALU指令一致,表示寄存器的编码。实现逻辑为:

服务器怎么看cpu数(算机是如何读懂0和1的)(21)

当前四位为0000时:

Step 4:Reg A的数据存储到RAM中(地址为MAR);

Step 5: RAM中地址为MAR的数据存储到Reg A;

当前四位为0001时:

Step 4:Reg A的数据存储到MAR;

Step 5: Reg B中的数据存储到RAM中(地址为MAR);

助记符如下:

服务器怎么看cpu数(算机是如何读懂0和1的)(22)


3.2、如何实现“data”指令

当指令前四位为0010时,代表的是数据指令。与之前不同的是,这个指令有2个字节,后面紧跟的字节为要写入寄存器的数据,如下图所示:

服务器怎么看cpu数(算机是如何读懂0和1的)(23)

实现方式为:

服务器怎么看cpu数(算机是如何读懂0和1的)(24)

Step 4:读取IAR中的数据,存储到MAR中;bus 1使能,将IAR 1的结果存到ACC中;

Step 5:读取RAM中的数据(地址为IAR),存储到Reg B中;

Step 6:读取ACC中的数据(此时为IAR 1),更新到IAR中;

注意:由于IAR在step 1的时候已经 1了,在step 4又 1,因此,下一条指令将跳过仅邻的后一条指令(为需要载入的数据),从而实现将后一条紧邻的输入读入的功能。

助记符如下:

服务器怎么看cpu数(算机是如何读懂0和1的)(25)


3.3、如何实现“jump”指令

当指令前四位为0011时,代表的是跳转指令,如下图所示:

服务器怎么看cpu数(算机是如何读懂0和1的)(26)

实现方式为:

服务器怎么看cpu数(算机是如何读懂0和1的)(27)

Step 4:Reg B中的数据存储到IAR中,意味着下一次的指令将从IAR(目前为Reg B寄存器中存储的数据),从而实现跳转功能。

助记符如下:

服务器怎么看cpu数(算机是如何读懂0和1的)(28)


3.4、如何实现“jump to”指令

当指令前四位为0100时,代表的是跳转到指令,注意,这也是一条2字节指令,紧邻的后1字节代表要跳转到的地址,如下图所示:

服务器怎么看cpu数(算机是如何读懂0和1的)(29)

实现方式为:

服务器怎么看cpu数(算机是如何读懂0和1的)(30)

Step 4:将IAR中的数据存储到MAR;

Step 5:将RAM中地址为IAR的数据存储到IAR;

也就是IAR中的内容变成了RAM[IAR 1],实现到“跳转到”功能。

助记符如下:

服务器怎么看cpu数(算机是如何读懂0和1的)(31)


3.5、如何实现“jump if”指令

当然还可以实现更复杂的跳转指令,比如说有条件跳转,如下图所示:

服务器怎么看cpu数(算机是如何读懂0和1的)(32)

前面我们说了,ALU计算会输出四个标志位,分别为:carry out、a larger、equal和zero。如下图所示:

服务器怎么看cpu数(算机是如何读懂0和1的)(33)

我们可以把这四个标志位作为判断条件,实现有条件跳转,实现方式如下:

服务器怎么看cpu数(算机是如何读懂0和1的)(34)

Step 4:IAR传输至MAR,IAR 1传输至ACC;

Step 5:ACC传输至IAR;

Step 6:若carry out、a larger、equal或zero其中之一为真,则RAM [IAR] 传输至IAR。

也就是说,新的IAR有两种情况,正常情况下,程序将顺序执行(跳过紧邻的“地址”字节);当carry out、a larger、equal或zero之一为真时,程序跳转到紧邻字节所存储的地址。

助记符如下:

服务器怎么看cpu数(算机是如何读懂0和1的)(35)

如果我们把指令某个位置1,这样就可以进行组合标志条件跳转,因为我们有4个标志位,共计有16种组合,当然,4个标志位都off时,就不需要跳转,所以我们只对剩下的15个标志位组合感兴趣,其机器语言如下:

两个标志位组合:

服务器怎么看cpu数(算机是如何读懂0和1的)(36)

三个或四个标志位组合:

服务器怎么看cpu数(算机是如何读懂0和1的)(37)


3.6、如何实现“clear flags”指令

当我们去做加法或者移位运算时,可能会用到carry进位标志位,比如在有条件跳转时,就会用到这个标志位。

服务器怎么看cpu数(算机是如何读懂0和1的)(38)

Carry标志位还会作为加法和移位运算的输入,这就带来一个问题:Carry标志位是存在寄存器里面的,会一直保存之前的记录,当我们的运算不需要这个进位的时候,也会被ALU使用,这就可能会出现2 2=5的情况。

有很多种方式可以处理这个问题,现在我们采用一种比较简单的方式来清除标志位,如下图所示:

服务器怎么看cpu数(算机是如何读懂0和1的)(39)

看着很简洁,但是还是很有技巧的。首先,并没有使能任何寄存器往BUS写数据,这样ALU的输入A就是0000 0000。在Step 4的时候,使能Bus 1,所以此时ALU的输入B为0000 0001。这是并没有任何操作码发送至ALU,因为默认的是ADD操作,这时ALU就会执行0000 0000 0000 0001=0000 0001,此时还可能有进位carry in,所以总的结果可能是0000 0001,也可能是0000 0010,但是肯定不会产生进位carry out。注意此时carry 标志位为off;结果不是零,所以zero标志位也为off;B比A大,所以“‘A larger”和“equal”也为off。也就是说,所有标志位都清零了。

助记符如下:

服务器怎么看cpu数(算机是如何读懂0和1的)(40)


3.7、如何实现“I/O”指令

当然,我们还需要相关的指令实现CPU和RAM与外部的数据交换,如下图所示:

服务器怎么看cpu数(算机是如何读懂0和1的)(41)

I/O总线包括数据总线和一些关键的内部信号,包括输入/输出标志位、数据/地址标志位、“读”使能标志位、“写”使能标志位,具体如下:

服务器怎么看cpu数(算机是如何读懂0和1的)(42)

其指令格式如下,前四位为0111就表示该指令为I/O指令。后四位第一位表示是输入/输出标志,第二位表示数据/地址标志位,最后两位表示地址/数据的内容(存在Reg B中)。

服务器怎么看cpu数(算机是如何读懂0和1的)(43)

具体实现方式如下:

服务器怎么看cpu数(算机是如何读懂0和1的)(44)

Step 4:input/output标志位为1,指令前4位为0111时,Reg B寄存器“读”使能,Reg B寄存器内容传输至BUS;I/O clk s标志位为on;

Step 5:input/output标志位为0,指令前4位为0111时,Reg B寄存器“写”使能,BUS数据传输至Reg B寄存器;I/O clk e标志位为on;

助记符如下:

服务器怎么看cpu数(算机是如何读懂0和1的)(45)


四、控制单元集成

把前面所有介绍的指令用或门全部封装在一起,就可以得到CPU的Control Section了。其实现的功能为:

服务器怎么看cpu数(算机是如何读懂0和1的)(46)

具体实现方式如下:

把前面所列的所有ALU指令封装在一起,可以得到ALU相关指令的Control Section部分如下:

服务器怎么看cpu数(算机是如何读懂0和1的)(47)

继续把所有非ALU指令封装在一起,如下:

服务器怎么看cpu数(算机是如何读懂0和1的)(48)

把所有指令封装在一起,如下图所示:

服务器怎么看cpu数(算机是如何读懂0和1的)(49)

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页