计算机组成学习笔记(二)
目录
摘要
计算机组成学习笔记(二)。
3 算术逻辑单元
3.1 算术运算和逻辑运算
- 这条指令的操作数,全都是寄存器,所以它是一条R型指令。
- 首先我们查指令编码表,知道i的指令的
opcode
应该是0,function
是16进制的20,也就是10进制的32, 因为它不是一条移位指令,所以移位的域应该为0。 - 根据这条指令当中的操作数,我们可以知道,它的目的操作数,是8号寄存器, 所以rd对应是8, 第一个源操作数是9号寄存器,第二个源操作数是10号寄存器,所以这两个对应的域分别应该是9和10,根据这样的分析,我们就可以知道, 这条指令的具体编码。
- CPU通过取址,就会把这条指令,从内存中取回来。并放到IR寄存器中,也就是存放指令编码的寄存器。
- 指令译码电路,看到了这条指令的编码之后,根据
opcode
域为全0,知道了这是一条R形的指令,再根据function
域的值,分析出这是一条add
指令。 - 因此,控制电路会向ALU,也就是运算器,发出对应的控制信号,指明接下来要进行加法运算。
- 同时,指令译码部件分析出,第一个源操作数rs是9号寄存器,第二个源操作数rt是10号寄存器。控制电路会选通对应的源操作数寄存器,将其内容传送到ALU的输入,同时指令译码部件还会分析出目的操作数rd,为8号寄存器,因此控制电路还会将ALU的输出,连通到8号寄存器的输入。
- ALU会根据控制电路给出的信号,将两个输入的源操作数,进行加法运算,并送出运算的结果,会被保存在8号寄存器中,这就完成了一次加法运算。
- R型指令,它的源操作数都是在寄存器当中的。
- 不含有
u
的指令,在加法运算产生溢出时,会向控制器报告异常,由控制器进行相关的处理,而含有u
指令,在发生溢出时不会报出异常。
- 如果有一个源操作数是立即数的话,就需要采用I型指令。
- 通过指令编码表我们可以得到,这批指令的
opcode
是8,然后根据这条指令当中的参数,可以知道,源操作数的寄存器编号rs是8,等于22,目的操作数的寄存器编号rt,也等于21, 而立即数这个域,应该是-50,将这些数都转换成二进制,填入对应的区域,我们就可以知道这条指令的编码。
- CPU将这条指令的编码,取回放入IR寄存器当中后, 指令译码部件会根据
opcode
域发现这是一条立即数的加法指令,因此控制电路, 会将ALU发出控制信号,只是接下来要进行加法运算。 - 同时,指令译码部件分析也会发现,其中一个源操作数来自于22号寄存器,22号寄存器的内容 会在控制电路的控制下,通过内部走线走到ALU的一个入口。
- 这个运算的另一个操作数是一个立即数, 这个立即数是存放在指令编码中的, 因此,控制电路会从指令编码中提取出这个立即数, 并将其传送到ALU的另一个入口。
- 这条运算指令指示的目的操作数rt,是第21号寄存器, 因此ALU的输出会被传送到21号寄存器,这就是这条立即数加法指令的运算过程。
- 要注意的一点是,这个立即数,是16位的。而另一个源操作数以及目的寄存器,都是32位的,那如何将一个16位数和32位数进行相加呢,我们就需要进行一些转换。
- 在指令说明中,指出将rs寄存器的内容,加上这个立即数的符号扩展,然后再将结果存放在r寄存器当中。
- 这条指令会在加法发生溢出时,向控制器报出异常,交由控制器来处理。
- 对立即数的扩展的方法,立即数是16位的,那它如何被扩展到32位呢?是让它的高16位是由这低16位当中的最高位,复制了16次,填充到高16位当中。 也就是说这32位当中的高16位,都和低16位当中的最高位,完全一样。 这样的扩展方法我们称为符号扩展。
- 符号扩展不会改变原有的有符号数的数值。
- 含有
u
指令,在发生溢出时不会报出异常。
-
在R型当中,有
and
指令,就两个寄存器当中的数,进行与操作,并将结果放在第三个寄存器中。还有o
r指令, 是对两个寄存器当中的数,进行或操作。nor
指令,是进行或非操作,也就是先进行或,然后再取反。 -
I型指令当中,有
andi
指令,也是进行与操作,但其中一个操作数是立即数, 这与算术运算指令类似,但其不同点在于,这16位立即数的扩展方式,它不是采用符号扩展,而是采用0扩展。同样还有
ori
指令。 -
0扩展操作是这样的, 扩展后的高16位全都是0,而不是低16位当中最高位的复制,这种扩展方式,就称为0扩展。
-
因为算术运算指令会考虑将操作数看做是一个有符号的数,在运算时要考虑正数和负数的这个性质,而逻辑运算指令,是将操作数,视为一组二进制的01串,这就不存在正数或着负数这样的概念,因此它采用了0扩展,而不是符号扩展。
- 通过查指令编码表,我们可以得到
opcode
域是0,function
域是16进制的24,移位域同样还是0,然后根据这条指令的 三个操作数得到,rd域,也就是目的操作数是8。第一个源操作数是9,第二个源操作数是10,我们在将这些数都转换成二进制,就可以得到这条指令的编码。
- CPU将这条编码从内存中取回,并放回IR寄存器中,那控制电路这一次就会发出要进行与操作的控制信号。
- 在这样的控制下ALU就会将9号10号寄存器当中内容,进行与运算,并将结果送回到了8号寄存器当中。
3.2 门电路的基本原理
- NMOS对外有三个连接,一个是源,一个漏, 一个是门。
- MOS晶体管其工作原理其实很像这个水龙头,电路中的电流就好比水管中的水流,水流的来源也就是源,而水流出的地方就称为漏,控制水流的开关就是门。 如果把门打开,水流就会从源流到漏, 也就相当于晶体管导通,电流可以从源到漏。
- 对于NMOS来说,其导通的条件是gate端连接了高电平,而当gate端连接低电平时这个晶体管是不导通的。于NMOS相对还有另一种类型叫做PMOS,它和NMOS的区别就在于当gate端连接低电平时,这个晶体管导通,而连接高电平时这个晶体管不导通。 这就好比我们有两种类型的水龙头,一种是把这个把手向上拉才会出水,另一种是将这个把手向下压才会出水。
- 用这两种功能相对应的晶体管就构成了互补型的MOS集成电路,也简称为CMOS。
- 有空心圆圈的符号为PMOS,无空心圆圈的符号为NMOS。
3.3 寄存器的基本原理
- 0号通用寄存器,在MIPS的体系结构中,它就是一个32位的寄存器, 从电路实现上来说这32个比特都是同样的,这样一个结构就是D触发器。
- 触发器是具有存储信息能力的基本单元。
- D触发器主要有这三个接孔,一个数据输入, 一个数据输出和一个时钟输入。
- 在时钟clock的上升沿,也就是clock从低电平变为高电平,也可以说是从0变到1的时候,这是一个很短的时间, 在这时D触发器会采样输入端口D的值,经过一段很短的时间会将这个值传送到输出端口Q。
- 在其它的时候也就是不在时钟信号的上升沿的时候,无论输入端口D如何变化,其输出端口Q的值都是保持不变的。
- 我们把镜头比作D触发器的输入端D,拍照的快门比作时钟端clock,这台相机内部带有无线传输的模块,可以将其拍摄的照片传送到一个显示器上,这个显示器就好比D触发器的输出端Q。
- 当按下照相机的快门后,照相机会拍一张照片,过一秒钟后显示器上显示出这张照片,对于D触发器来说,这就叫做clock to Q的时间,也就是从时钟的上升沿到来开始直到数据出现在输出端为止,这个时间是属于D触发器自身的特性。
- 对于这个D触发器所在的整个芯片还有一个重要的特性就是时钟频率,在这里就好比我们约定每10秒钟会来按一次快门,那这个系统的时钟频率就是0.1Hz。
- 假设十秒钟到了,我们会按动一次快门, 按动快门后照相机会拍摄下左边这台显示器上的画面,并在一秒钟后将拍摄的照片传送到右边这台显示器上,这个过程就体现了在时钟的上升沿D触发器采用输入端的信号,并在时钟上升沿之后clock to Q的时间 将采样的信号从输出端口送出来。
- 之后输入端 也就是左边这台显示器上的画面可能会发生变化,但是只要不按动快门,右边显示器上的内容是不会发生变化的。也就是在下一个时钟上升沿来临之前无论输入怎么变化,输出都不会发生变化。
- 在按动快门的前后很短的时间内通过镜头看到的画面不应该发生变动,否则就可能造成拍出的照片是模糊的。对于D触发器来说,在时钟上升沿前后很短的时间内,输入端的信号也不能发生变化,否则就可能造成无法正确的采样。那么这也是D触发器的一个重要的特性,要求输入信号在时钟上升沿之前有一段很短的稳- 定时间,很短的稳定时间,称为set up时间,在时钟上升沿之后也需要有一段很短的稳定时间,称为hold时间。
- 要注意的是a相机拍摄下来的这个绿叶,是经过了clock to Q时间才传送到了它的输出,而在此之前b相机已经拍摄到了a相机此前的输出,也就是现在显示在最右边的显示器上的这个红色的叶子。所以我们要注意的是这两个相连的相机虽然是同时按动了快门,但并不意味着最左边的画面会一直传递到最右边的显示器上,而是将左边的相机之前存储的画面依次向右传递。
- 同样在时钟上升沿没有到来的时候,无论输入发生什么样的变化都不会影响到后面触发器的输出。
- 第一行是时钟信号,它是有规律的进行变化, 两个上升沿之间的间隔时间就称为时钟周期。
- 输入信号D则可能在任何时候发生变化, 比如在这个时候它由0变到了1,但是因为时钟上升沿没有到来,所以输出端Q 并没有发生变化。
- 直到时钟上升沿到来的时候,D触发器会采样输入端的信号, 并经过很短的clock to Q的时间在输出端体现出来, 因为这时候输入端是1,所以输出端也变成了1。
- 然后时间再继续,在这个时钟周期内,输入D又发生了变化,由1变成了0,但是同样输出端Q没有发生变化。
- 直到下一个时钟上升沿到来,采样到了新的输入端的指令, 再经过Clock to Q输出端也变成了0。
- 如果把很多个D触发器组合起来,比如就是这32个D触发器,那就可以构成一个32位的寄存器。
- 用这样一个32位的寄存器就可以做成CPU当中的一个通用寄存器,用同样的方法可以作出其它的通用寄存器以及PC,IR这样的寄存器。
3.4 逻辑运算的实现
- 32个与门并排连起来,将32位的输入分别连接到这32个与门上。可以标记为A0,A1一直到A31,这代表第一个操作数,而从B0,B1一直到B31,这代表第二个操作数。这32个 与门的输出,分别记为Y0,Y1直到Y31。它们就组成了一个32位的数。
- 在这条与运算的指令控制下,rs所指定的寄存器的内容会被传送到这个端口。而rt所指向的内容会被传送到另一个端口。经过这些与门之后,得到的运算结果,会被传送到rd所指定的寄存器当中。这样就完成了这条指令所要求的与运算。
- 与之类似,如果我们要完成这条或运算指令,则需要32个或门,这样就构成一个可以完成32位或运算的单元。
- 在ALU当中,实际上是包含了多钟不同的功能部件。包括我们刚才提到的32位的与运算, 32位的或运算,还会有其它的逻辑运算以及算术运算单元。
- 对于这个整体的运算单元,它需要有一个32位的输入,然后在运算单元的内部,分别连接到各个不同的运算功能部件的A输入端口,然后将另一个32位的输入也在运算单元的内部分别连接到各个不同功能单元的B输入端口。这样每个功能部件都按照各自的功能完成对应的与操作,或操作,以及其他的操作,并产生对应的运算结果。
- 那现在的问题是,我们到底需要哪个运算结果作为输出呢?这就还需要增加一个部件就是多选器。这里我们假定这个运算单元当中包含四种功能,所以我们会有四个运算的结果,要经过一个四选一的多选器。那样从四个选择当中选出一个来, 我们就需要一个两位的选择信号,当这个选择信号为00时,在这个图中就会选择与运算功能部件输出的结果。如果它是01时,就会选择这个或运算功能部件输出的结果。这个多选器实际上也是由若干个门组成的。
- 那对于这一个完整运算单元来说, 当我们通过这个选择信号选择了对应的运算类型之后,从运算单元的输出端口,我们就可以看到经过指定运算之后产生的输出。
- 最上面是由32个D触发器组成的8号寄存器,中间是9号寄存器,然后是10号寄存器。
- 9号,10号寄存器的Q端的输出会被链接到ALU的两个输入,同时ALU的功能选择信号输入了与运算所对应的编码。
- 然后ALU的输出会被连接到8号寄存器的输入D端。
- 在某一个时钟周期内,ALU会按照输入的要求完成相关的运算,并将运算结果送到输出信号上。输入结果经过连线的传送, 会送到8号寄存器的输入端,等到下一个时钟上升沿来临的时候,8号寄存器就会将输入端的信号采样,存入到寄存器内部,并会在输出端表现出来。之后的运算如果使用8号寄存器作为输入的话,就会使用这个新的值。
3.5 加法和减法的实现
- 半加器,由一个异或门和与门组成。
- 它由两个输入端口 A和B,就是我们要相加的两个一位二进制数。两个输出端口其中一个是S,相当于这两个一位二进制数相加对应产生的(和),而C则是它们产生的进位; 有进位就是1,没有进位就是0。
- 全加器是由两个半加器构成的。
- 这个图中这两个绿色的异或门和与门就是一个半加器,而这两个橙色的异或门和与门是另一个半加器,最后再添加一个或门就构成了全加器。
- 将四个全加器串联起来,前一个全加器的进位输出,连到后一个全加器的进位输入,这样就构成了一个四位的加法器。
- 当最高位的全加器的进位输入不等于它的进位输出的时候,这就是发生溢出了。
- 那么用什么方法来判断不相等呢?其实非常简单,就连接一个异或门就可以了。
- 对于一个加法器的硬件实现,它并不关心这两个输入数是有符号数还是无符号数。或者说,它对于有符号数和无符号数的处理都是一样的。全都是通过这套同样的硬件逻辑,进行运算,产生相同的结果。
- 如果编程人员想将操作数看作有符号数,需要处理溢出,则需要使用
add
和addi
这样的指令。当这样的运算发生溢出时,会产生异常。就是说,控制电路会检查加法器产生的overflow
的信号。如果overflow
信号有效,控制电路就会当做一个异常的情况进行处理。 - 如果编程人员希望将操作数看作无符号数,也就是不对溢出进行处理。那就需要使用这两条指令,
addu
和addiu
。它们分别和上面这两条指令是对应的。唯一的区别就是,在执行这两条指令时,控制电路不会检查加法器输出的overflow
信号。 - 所以说,MIPS处理溢出的方式是提前做准备。按照是否要处理溢出,采用不同的指令进行运算。
- 86的运算指令,如果产生了溢出, 并不会直接由控制电路检查到并进行处理。而是将加法器产生的溢出信号传送到了标志寄存器。
- 如果发生溢出,则会致标志寄存器当中的OF位为1。如果没有发生溢出,则致OF位为0。x86的标志寄存器,其中第11位是OF位,这就是溢出标志。
- 在后续的指令中,需要检查标志寄存器的OF位是否为1并进行相应的操作。
- B转换为负B,按位取反,末位加1。
- 将X中的每一位由0变成1,由1变成0,那么得到了X按位取反以后的值。如果我们把这两个值相加,那么它们的和,显而易见,每一位都是1。在补码表示中,全1的这个二进制数,就代表着-1。
- 如果将X和它按位取反后的值相加,就等于-1,我们把这个等式进行一些变换,就可以得到,X相反数,就等于对X进行按位取反。然后再加上1。
- 在加法器的基础上,用这样的方式,就可以很容易的实现减法器。也就是A减B,相当于A加上负B, 实际上就等于A加上B的按位取反然后再加1。
- 刚才的那个加法器,原来的输入A和B都不变,我们增加了一个新的输入, 只有一个比特,称为减法模式。
- 它首先控制了一个二选一的多选器,如果这个信号为0,代表是执行加法操作,那么会将多选器的这一条通路选通, 也就是直接将B传送的下面的这些全加器。这就跟刚才的加法运算是一样的。而且我们还注意到这个选择信号还连接到了最低位全加器的进位输入,但是因为它现在是0,所以仍然和刚才的加法 操作是一样的,这时候就该执行一个加法的运算。
- 如果这个信号为1,代表要执行一个减法的运算。那这个二选一的多选器会选择这条通路。这条通路是将B这个信号的输入每一位都接上一个非门, 相当于按位取反,将按位取反的B送到每一个全加器与A相加,我们还要注意,因为这个选择信号为1, 所以最低位的全加器的进位输入也是1。这样就实现了对B进行按位取反,末位加一的操作,于是这个加法器也就变成了减法器。
3.6 加法器的优化
- 要对一个电路的性能进行分析,我们就要找出其中的最长路径。也就是找出所有的从输入到输出的电路连接中,经过的门数最多的那一条,经过分析,我们可以发现,实际上红色标明的这条路径,就是这个加法器延迟最长的路径,也被称为关键路径。
- 在这个进位输出产生时,所有的全加器的S都已经产生了。即使最晚产生的这个S,也比这个Cout早了一级门。
- N位的形波进位加法器,那就一共是2N+1个门延迟。
- 著名的智能手机,它内部的CPU,采用着28nm的制造工艺,主频是1.3GHz,也就是时钟周期0.66ns,这就是最近的两个时钟上升延之间的时间长度。
- 因为加法器的输入是来自寄存器,而且加法器的输出,包括运算的和,和进位输出, 都是要传递到寄存器保存起来。所以说这些信号从前一级的寄存器,经过加法器的所有逻辑,一直到下一级寄存器的输入,不能超过0.66ns。
- 对于一个32位的形波进位加法器, 如果采用28nm的制造工艺,没延迟大约为0.02ns,因为总共需要65个门的延迟,所以一共需要1.3ns, 这远远超过了我们所要求的0.66ns,采用这样的加法器,它的主时钟频率,最多也只能达到769MHz。
- 进位输出信号记为Ci+1,Ci+1可以通过这样的逻辑表达式计算出来,它的意思就是,如果这个全加器的三个输入, Ai,Bi或着Ci,只要任义其中两个为一,则进位就是1,这是很自然的,三个一位的二进制数相加,有两个或着两个以上的1,则自然会产生进位。
- 再将这个算式当中的Ci提取出来,就可以得到这样一个表达式。在这个表达式当中,Ai和Bi都是在运算之初就是确定的。
- 所以为了表达的简便,我们再设定两个信号,一个称为Gi,它就等于Ai和Bi的与,另一个是Pi,它就等于Ai和Bi的或,这样将Gi和Pi,代入到这个算式当中,就得到了一个更为简化的算式。
- 我们只需要记住的是,Pi和Gi是由Ai和Bi产生的,他们都是在运算之初,就可以确定了的信号。
- C1是通过G0、P0和C0计算出来的,那么在运算之初,G0和P0都是已知的,C0也是已知的。所以C1不用进行任何的等待,直接就可以计算出来。
- 而Ci,是由G1、P1和C1运算而得的。在这里G和P都是已知的, 但是C1不是这个加法器的直接输入,但如果我们想提前计算出C2,我们可以将上一个算式,代入到这个算式当中。也就是C1转换成上一个算式,我们再将这个算式展开,除了G和P之外,只有C0,所有的信号都是在运算之初就可以确定的,这样,我们就不用等待最低位的全加器产生C1,而是通过整个加法器的输入,直接计算出C2。
- 通过这样的转换, 我们就有了提前计算所有的进位输出信号的方法。
- 最外层一共有五组元素进行 或运算,对应了最后的这个五数字的或门。
- 而其中第一个元素是G3,G3就是A3和B3的与, 所以在这里我们可以看到,A3和B3经过了一个与门,与门的输出直接连到了最后的这个或门上。
- 第二个元素是P3和G2的与, 它就对应了这个与门,其中一个输入是P3,而P3是A3和B3的或。另一个输入是G2, G2是A2和B2的与。
- 第三组元素对应了这个3输入的与门。第一个输入是P3,来自于这里。第二个输入是P2,来自这里。第三个输入是G1,来自这里。
- 这样我们就可以发现C4只需要通过A,B和C0就可以计算出来,而且计算C4的延迟只需要三级门。
- 由此类推,计算任意一级的进位输出都只需要三级门延迟,与加法器的位数无关。但只是如果进一步拓宽加法器的位数,像这样最后的算式 会变得越来越长,对应的电路就会变得越来越复杂。
- 这就是一个四位的超前进位加法器。它仍然由四个全加器构成,但是每个全加器的进位输入并不来自于前一级的全加器,而是来自一个统一的逻辑,这就是刚才我们展示的超前进位的逻辑。
- 对于每一个进位,其实都只需要三级门延迟就可以计算出来。然后进入到全加器当中,还需要经过一级门延迟才可以计算出对应的S信号。因此,对于超前进位加法器总的延迟时间为4级的门延迟。
- 32位的加法器如果采用行波进位的方式,我们已经分析过需要65级的门延迟,那如果采用超前进位的方式,理想情况下也只需要四级的门延迟,但可惜的是,这也只是一个理想。因为要实现32位的完全的超前进位,电路就会变得非常的复杂。
- 因此通常的实现方法,是采用多个小规模的超前进位加法器拼接而成一个较大的加法器,比如说,要生成一个32位的加法器,我们可以先做一个8位的超前进位加法器,然后将四个八位的超前进位加法器用行波进位的方式连接起来,从而构成一个32位的加法器。