北京大学 Computer Organization 学习笔记(一)

计算机起初只是方便数学家进行算数运算。

冯诺依曼参与到了第一台通用计算机ENIAC计算机的研发中。 并从中提出自己心中计算机的物理结构预想。第一份草案

冯诺依曼体系结构

关于《EDVAC》的报告草案,其中内容是冯诺依曼和负责设计ENIAC的其他小组人员共同商讨的结果,针对ENIAC可以改进的点,不过冯诺依曼后来发表出来只署名了自己。并未完稿,101页。

论述了两个重要思想:

  1. 存储程序:控制计算及运行的程序应该存储在存储器中,而不是通过开关连线,会大大降低计算机的执行效率
  2. 计算机应该采用二进制而不是十进制,十进制会使计算机内部执行逻辑变得异常复杂。

明确了计算机的五个组成部分:运算器,控制器,存储器,输入设备,输出设备。

71F743F0-9426-4A29-B1C0-4257F4A81D60.png

4者构成芯片组

  • 4001: 断电数据不会丢失
  • 4002:可以方便读写,断电数据会丢失
  • 4003:用来进行数据的输入输出

CPU和主存储器通过系统总线进行连接。

036C8138-C280-42E3-BCE6-7ED4FA24C5CD.png

现代主存一般一个内存内容是一个字节。

5E4C5D00-6099-4BD8-913E-4F3FACFB7C85.png

冯诺依曼结构的计算机就好比这个餐馆, CPU就是厨房, 而主存就是仓库, 仓库里的货架就好比主存当中的存储单元, 我们为货架的每一格都编上了一个序号,相当于主存当中的地址,货架上存放的物品相当于存储单元当中的内容,主存中会存放着计算机的指令,还有数据,对于这个餐馆来说就是厨师需要执行的任务和做菜所用的原料,那厨房当中承担主要控制任务的就是这位大厨了, 它也是控制器,而运算器则是厨具。那我们还需要一些附加的设备。这个厨师记性很不好,他必须要在身边 有一张纸,上面写着下一张任务单的位置,这里这张纸上写了1,厨师就知道我下一张任务单放在仓库的第一格, 那么如果把任务单取回来以后还需要放在身边随时的查看所以他还可以有一个放置当天任务单的位置。如果取来了任务单就放在这。 那厨师做菜,做完了菜放哪呢,不能直接端着锅冲到仓库去吧。所以他身边操作台上总得放几个盘子,相当于CPU当中我们就称这些盘子为通用寄存器。用于临时存放计算器的运算结果或者要送到运算器的操作数。我们有可能从主存当中事先会取来一些操作数,当然也需要执行指令去取来一些操作数,先放到通用寄存器当中。

计算机执行一条指令的主要步骤包括如下四步

  1. 取址
  2. 译码
  3. 执行
  4. 回写

现在我们假设这个餐馆处在这样一个状态,厨师第一步要做的事情就是查看下一张任务单的位置在哪,我要去取这张任务单了,我一查,发现是1, 我向主存发送了请求我需要第一格的物品,他并不知道第一格存放的是什么,他只是根据这里的编号向主存 发出申请,哎,主存并不简单是一些货架,他还是要有一些控制逻辑,那么这类控制逻辑就会响应控制器的请求, 需要第一格的物品,他就找到了第一格的物品,把第一格的物品给送回去了,厨师收到了任务单了,就把他放在身边存放当前任务单的位置, 这就完成了第一步,取任务单的工作。而实际上这一步呢还需要有一项任务。就是更新下一张任务单的位置。第一格取完了等这件事做完之后下一次再去取任务单的时候再去取下一格,就把它更新为2,那现在不会取第二格了,只是先更新, 等一会去执行下一条指令的时候再根据这个位置去向主存发出请求,好,那这样的话取任务单的这一步就算真正的完成了。

第二步,在计算机当中称之为译码,对于这个厨师来说,就是分析刚才拿到的任务单。这个任务单上写了这么几条。第一呢说明了这项任务所需要用的方法。第二呢说明了这项任务所需要的原料。看来这个原料有两个位置,一个在仓库,一个在他身边的盘子里。最后这项任务完成了以后,看起来是炒一盘菜,那么炒完之后呢还得把成果存放在某个地方,这个任务单上也指定了,存放在A号的盘子里。好,这个任务就分析完了。控制器就把他转换成若干组的控制信号一一完成,这样译码这个阶段就算完成了。

第三步,对计算机执行指令是其核心的步骤,就叫做执行。对程序来说一样,执行这个已经分析完的任务,这个任务一共有4步,你先完成第一步,第一步是要去取第六格的物品。好,与刚才一样,向主存发出请求说我需要第六格的物品,主存会响应,把第六格的物品送过来。由于这次是取运算要用的操作数,所以返回的物品控制器就会把它放在运算器的其中一个入口,然后第二部是取这个运算的第二个操作数。其实这是放在A号盘子里的,就在厨师身边,很快,马上就可以拿到。那么第三步是执行这项运算,那么控制器会给出对应的信号给运算器,让它执行对应的运算,经过短暂的时间之后呢运算就完成了,运算结果也产生了。 执行阶段就到此结束了。

但是现在运算结果还放在运算器的这个输出端口上。我们必须要把它转移到另外的地方,根据这条指令的要求,运算的结果应该是存放在A号的通用计算器里。那我们在最后一步回写也就是保存结果的时候呢,用控制器把这个运算结果存放在A号的通用器当中, 这样我们就完成了执行指令的全部过程。做完了这条指令,控制器也不会闲着,接着来执行下一条指令。它就会去查看下一张任务单的位置,跟刚才执行前一条指令的第一步是一样的,先去查看下一张任务单的位置,发现是2,那么就向主存发出所需要第二格的物品,然后主存就会把第二格的任务单返回来,注意我们取回来以后呢要自动更新成下一张任务单的位置,之后再做13,这个更新完以后我们就像刚才一样,继续分析当前取回来这张任务单并完成它所指定的任务,最后保存结果, 然后再去取下一条指令。不断的重复,计算机就会自动的运转起来了。

FA102A9F-ED1D-4388-841B-510612544AC7.png

CPU和存储器通过系统总线相连,系统总线分为

  • 控制总线
  • 地址总线
  • 数据总线
656A9D07-78EB-49AC-9F6F-C2894A4634D1.png
49E0AFCC-BD23-42B8-9ED7-989DF686B86F.png
8C1DA4DC-37C0-4FED-8383-B8D5A0E2E740.png
EE76D817-29F6-415F-88FF-D7482ED06122.png
26C9E198-D384-470B-87DD-BEFEE142E066.png

Tips: 在通用寄存器和ALU以及控制器当中的若干寄存器之间要传递数据的话, 就必须要经过CPU的内部总线

8BD052E2-D1B1-4BDE-B964-48E3DF48E6D0.png
742DE42A-FB22-4D32-B194-555AC2FB2FCB.png
1246735C-CD21-4049-8D9D-04E875AEE1BC.png

假设模型机的当前状态已经有了一些初始值,我们需要注意的是CPU中的R0所保存的值是00000011,这等于10进制的3。 而存储单元地址为6的存储单元的内容是00000010,相当于10进制的2。那么我们所要做的,就是把这个存储单元的数和R0当中的数相加,最后再放到R0中。我们还看到PC寄存器也就是指向下一条指令地址的寄存器,保存的值是0001,那么,他所指向的内层单元,这里,所以这个内层单元中其实是保存了当前所需要执行的那条指令。 我就用10101010这么一个值来指代, 这仅仅是指代而已。

指令执行的第一步,取指。控制器将指令的地址送往存储器,存储器按给定的地址读出指令内容,送回控制器。具体的操作步骤:

  1. 首先请注意控制器会发出控制信号将PC寄存器中的内容通过内部总线传送到MAR中。现在MAR寄存器中也保存了0001。
  2. MAR将会把这个地址送到地址总线上,与此同时,控制电路会在控制总线上发出相应的控制信号,代表这次访问存储器的操作是要读数据。
  3. 存储器的MAR寄存器就会收到地址总线上传送来的地址并把它保存下来。存储器中的控制逻辑,也会受到控制总线中传送来的控制信号 得知这次仿真操作是一次读操作。

这样存储器通过地址译码器就可以查找到对应地址001的存储单元的内容;并将该存储单元的内容送到MDR寄存器中。然后存储器的控制逻辑,会通过控制总线向CPU反馈当前的传输已经准备好了,同时,MDR之中的内容也会送数据总线上。

随后,CPU中的控制电路检测到来自控制总线的准备好的ready信号,就知道当前数据总线上已经准备好了数据。 因此 MDR寄存器就会将当前数据总线上传送来的数值保存下来,这就获得了我们所要取的指令。当然,仅到如此是不够的。MDR中的内容还不需要传送到指令寄存器中,也就是IR寄存器。当指令的编码已经保存到IR寄存器中时,还需要再做一件事,就是把PC寄存器更新为下一条指令所需要访问的地址。 刚才是0001,现在变成0010,也就是10进制的2。更新完以后我们才可以做效益不的工作。那么,取指阶段到此正式完成。

第二部是译码。 在一步控制器会分析指令的操作性质并向相关的部件发出指令所需的控制信号。当前的指令计算器IR中指令编码会送到指令译码部件。指令译码部件根据指令编码很快会发现这是一条加法指令。而且,是要把R0和存储器中地址为6的单元的内容相加,并把结果存放到R0中。然後,控制电路就据此产生对应的控制信号,发到相关部件中将译码阶段就到此完成了。第三步是执行。控制器会从通用寄存器或者存储器中取出操作数,并命令运算器对操作数进行指令规定的运算。首先,根据这条指令我们会发现,还是需要去取操作数,其中一个操作数在存储器里中。因此,这一步会在MAR中放置要访问的存储器的地址,0110。就是10进制的6。那么,随后的过程类似于取指阶段的操作。MAR将地址发到地址总线, 同时,控制电路在控制总线发出读操作的控制信号。存储器的MAR控制逻辑会接收到相应的信号,然后查找到对应的地址,这次要查找的地址是0110,对应的内容会送到MDR这个存储器。然後,控制逻辑会向CPU反馈当前数据已经准备好了的信号。 然後,MDR的内容也会被放置到数据总线上,CPU会接收数据并保存在MDR寄存器中。

由于这个数据要进行加法运算,所以控制器会进一步将MDR中的数据传送到ALU的输入目前会暂存到Y寄存器中。这一个操作数现在就准备好了, 那么另一个操作数是放在R0中;因此,控制器还会将R0中的数据传送到ALU的另一个输入端,也就是x寄存器。

现在,两个操作数都准备好了,在控制电路的控制下ALU就会进行运算再将x、y中的内容执行加法并计算出结果。结果就是00000101也就是10进制的5。 到此,执行阶段就完成了。

第四步是回写。也就是将运算结果写入到通用寄存器或者储存器。现在,运算结果还在ALU的输出端,也就是Z寄存器中, 控制电路会给出相应的控制信号将Z寄存器当中的内容传送到R0中。R0目前的内容是之前的原操作数, 也就是00000011。随后,会被新的结果所覆盖。这样,我们这个加法运算的结果就已经保存到了R0寄存器中, 回写阶段到此完成。这条指令你就执行完毕了。然後,CPU就会自动执行下一条指令。它们是和刚才一样,先将PC中的内容传送到MAR寄存器当中,然後MAR会将这个地址传送到地址总线上依次的执行下一条指令。

6EC4C536-264E-4BEA-AD84-B11AA227FC02.png
AD12F6DD-ADC0-49BD-9323-A8A33571F039.png

那CPU是如何获取指令,开始执行的呢。 这块主板上采用的是个人计算机上长期占据主导地位的南北桥结构。 所以CPU对外会连接的一块芯片,叫做北桥。 这是在主板上非常明显的一块芯片,CPU想要访问主存, 就得通过北桥芯片。

但是我们还要注意,计算机刚启动的时候,主存里面是没有信息的,因为当计算机断电之后,主存的信息都会丢失。那在系统启动之后,CPU从哪里获得指令呢?我们也可以看到北桥下方,还有一块比较大的芯片。它就是南桥。我们已经知道南桥内部,集成了很多输入输出设备的控制器,其中就包括硬盘的控制器。 所以硬盘实际上是和南桥芯片相连的。 而硬盘,我们也已经知道了,它是属于外部记录介质, 它内部保存着计算机系统所需的程序和数据。 那CPU所需要的指令是否就直接从硬盘取得呢。 其实也不是。因为要从硬盘中访问数据,相对比较复杂。 对硬盘进行配置和访问,本身还需要程序来控制。 这也就是所谓的硬盘驱动程序。 所以在计算机刚启动时,CPU是无法从硬盘中, 获得自己想要的第一条指令的

那第一条指令在哪呢? 实际上在主板上,还会有一个很小的芯片,它会与南桥相连。一般我们称之为BIOS芯片,这个芯片存储容量很小,** 会保存的一段比较简单但十分重要的程序,包括检查主板上都有哪些设备,这些设备工作是否正常。这个芯片实际上是一颗只读存储器。当系统断电之后,只读存储器中保存的信息是不会丢失的。所以当计算器启动后,CPU可以依次通过北桥, 南桥,访问到BIOS芯片,从里面取得指令。** 所以这颗BIOS芯片,虽然是一颗只读存储器,但是从冯·诺依曼结构原理上来看,它并不属于存储器的范畴,而是和硬盘一样,属于外部记录介质, 它和早年计算机的穿孔纸带也属于同一类别。严格地说,BIOS是指这颗只读存储器当中存储的软件。 它是基本输入输出系统的缩写。 那通常我们把保存了BIOS这个软件的只读存储器 成为BIOS芯片。

现在计算机主板上的BIOS芯片,有很多种封装形式,位置也有不同。但大多会在芯片旁边的主板上,标出BIOS的字样CPU从BIOS中取出指令后,会依次地检查主板上的各个设备,包括有显卡,通过显卡点亮显示器,检查键盘的存在,之后我们就可以通过键盘进行输入。 这些都是与I/O设备。此外,现在的显卡功能越来越复杂,性能也越来越强大,尤其是其中的图形处理单元。 我们也常称为GPU。GPU往往支持很多复杂的数学运算,拥有很强的运算能力。所以有时候,也会让GPU承担一些运算的工作。 实际上在现在高性能的超级计算机中, 经常会采用大量的GPU来进行运算。所以从这个意义上讲, GPU也承担了运算器和控制器的一些功能。

1AFFACB5-4510-47A5-8941-1741D8E72B6B.png

那在这个结构当中,只有北桥芯片的特征比较特殊一些。实际上,它提供了各个芯片之间互相访问的通道。当然,我们也不用太纠结,北桥到底对应着哪个结构。因为整个南北桥的结构也在迅速地发生着变化。这还是刚才那块主板,最上方是CPU。 这颗芯片中,往往包含着多个CPU核。 往下,它连接着北桥。 北桥中,主要会有主存控制器,对外连接着主存,那 现在的显卡,一般采用PCIE接口,所以在北桥中,会集成PCIE控制器,对外通过PCIE的插槽,连接PCIE的显卡。当然如果你对显示的性能要求不高, 也可以通过北桥内部自带的集成显卡,直接连接显示器。那北桥还连接着南桥,南桥中,集中了大多数 I/O设备的控制器,如右图。CPU对外的访问都需要通过北桥, 而其中对传输的性能要求最高的就是与主存的这条 通道。主存通道的性能也成为了整个计算机性能的关键瓶颈。 除此之外,另一条对性能影响很大的通道就是显示通道。那么这就是PCIE的插槽,这上面可以插上PCIE显卡。再有一条重要的通道, 就是北桥与南桥的连接,通过这条通道,外部的输入输出设备可以对主存进行访问。那在这里,红颜色的箭头表示传输压力很大的通道,而南北桥之间的绿色箭头表示这条通道传输压力相对较小。那在这种情况下,首先要解决对性能影响最大的关键问题。 这就是CPU访问主存的通道。

142CC084-482A-4762-BC1C-A47D1196DF19.png

所以在南北桥架构上,发生的第一个重要的变化,就是北桥中的主存控制器被移到了CPU芯片当中。通过上图可以看出来, CPU的插槽与主存的插槽变得更近了,这就是因为现在CPU是直接访问主存,而不需要再通过北桥了。这样可以大大地提高数据的传输率,进而提升系统的性能。现在,显示的这条通道,就成为了下一个要解决的问题。而南桥中连接的这些设备,暂时还不关键。 因此,在最新的个人计算机的CPU设计中,不仅包括了主存控制器,还包含了PCIE控制器,在外部可以直接连接显卡。 这样北桥当中最重要的一些部件,都被集成到了CPU芯片当中,那北桥就没有存在的必要了。

于是将北桥中剩余的一些功能,和南桥芯片整合到一起之后,所谓南北桥的架构,其实已经消失了。整个个人计算机的主板由三片式的架构缩减成了两片式。由于没有了北桥,南桥这个名字也显得有些奇怪了。所以它现在往往有一些不同的名字。如上图现在CPU直接连接着主存,还直接连接着显卡,还与原先的南桥直接相连,这样就将原先通过主板的复杂的通路,大多移到了芯片的内部。 而芯片内部的数据传输率,是远远高于主板的。 这样就大大地提升了系统的性能。 那既然从三片缩减成了两片,我们可不可以进一步缩减呢? 其实已经有人这么做了,这就是系统芯片的概念。 系统芯片, 可以认为是将计算机系统,或其它电子系统集成到一个单一的芯片上。如现在的消费电子设备就是一块大的系统芯片

C6369D39-9662-4C98-8659-F79C6216887C.png

这是一颗硬币大小的芯片,这个框图就是这颗芯片中所包含的功能模块。这部分是一个四核的CPU。这一部分是显卡的功能模块, 而这些是南桥中数量繁多的 各种接口的控制器,而且这个芯片还采用了一些特殊的方法,把主存也集中在了一起。 这样,就在这一颗芯片内部,集中了iii结构当中的所有组件。所以我们可以用这样的芯片制造出非常小巧的计算机。你看这个计算机的主板大约只有手掌大小,却拥有非常丰富的外部接口,与一个普通的计算机并没有什么差别。那这样高集成度的优势就让系统芯片的技术 广泛应用于智能手机,平板电脑等移动计算设备上

指令系统体系结构

x86 复杂指令集 CISC

84E91E5D-42CD-4F5B-BABE-B6C1B2A2B276.png
F844668D-0489-4CF5-8CC3-AEA21FE203D9.png
A115301F-A26E-492C-B23B-25FDE4FC7742.png
740522B8-63B1-4D1D-A688-6C23B5C96A67.png

为什么PC寄存器当中的地址是这个呢? 其实这是不一定的,这也是我们进行指令系统体系结构设计时。必须要约定的一个内容。 就是CPU在启动时,或者说在复位完成之后,第一条指令从哪里开始取出。 这也是最开始,软硬件双方必须商量好的事情。 至于这个地址到底应该是什么,并没有明确的规则。 但通常情况下,我们会约定为这个体系结构所能访问的存储单元 的最小地址,也就是0,或者是接近最高地址的地方。

E693577B-3210-4653-8821-4D5772CA27E0.png
23F455CE-F6E8-4904-8A41-2310C9FE38B1.png

最早推出来的8086是一款16位的CPU,所谓16位CPU,主要是指CPU当中的运算部件可以支持16位数据的运算。因为运算当中所需要的数据,一般会放在通用寄存器中。所以通用寄存器的位宽通常和运算单元的位宽是相同的。而运算单元产生的数据又经常会用做访问存储器的地址。 所以CPU访问存储器地址的宽度,也常常和运算单元的位宽相同。

对于8086来说,它是一个16位的CPU,它内部的通用寄存器也是16位的。 但是它连接存储器的地址线的宽度却是20位的。 那么它生成访问存储器的地址就需要采用一些特殊的方式。这就是8086体系结构所规定的寄存器。都是16位宽的,主要可分为这几类:通用寄存器、 指令指针寄存器、标志寄存器,还有段寄存器。 我们首先来看通用寄存器,结合我们之前说过的模型机的例子, 通用寄存器就在这里,CPU从存储器当中取回一个数, 很可能就会放在某一个通用寄存器当中。 而CPU执行运算指令,其操作数的来源也往往会在寄存器中。 对于8086来说,这些用于存储数据的通用寄存器, 主要有这四个:AX、BX、CX和DX。 这四个寄存器都是16位寄存器。 但是这些16位寄存器还可以被分为两个8位的寄存器来使用。

574C5BFF-B978-4753-BB27-2395208B024B.png

大多数的算术运算和逻辑运算的指令,都可以使用这些数据寄存器。 那么这些寄存器除了可以一般性的存放数据之外, 还会有一些专门的用途。除了这四个寄存器还有SP、BP、SI、DI这四个通用寄存器。 它们在早期都有一些特殊的用途。 而随着X86体系结构的不断更新,它们也大多成为了可以用于保存普通数据的寄存器。

86205DCC-E08A-4393-AA97-9A1AB3366D15.png

标志寄存器:之前分析模型机时提到,当执行运算指令时,ALU会将X和Y两个寄存器当中的内容相加,并将运算结果放在Z这个寄存器中。 同时将运算结果的一些特性保持在标志寄存器中。例如这个加法运算如果产生了进位,那就可以将这个进位保持在标志寄存器中, 以免丢失,后续的运算也可以知道之前的运算产生了这样一个进位。

6C72404D-1BA1-4889-B7A4-CCC4D6F74C4A.png

8086中,也有这样一个标志寄存器。称为FLAGS,这个寄存器当中,包含了若干个标志位。主要可以分为两大类,一类称为状态标志,它反映的是CPU的工作状态。另一大类称为控制标志。这是对CPU的运行起到特定的控制的作用。那8086的这个标志寄存器也是16位的。但实际只有其中一部分有具体的含义。在图中标为红色的都是状态标志,标为紫色的这三个是控制标志。 例如我们刚才提到的加法的进位标志。 当CPU执行完一条加法指令, 而这次加法运算的结果产生了一个进位, 那CPU内部除了将加法的运算结果保存到对应的寄存器之外, 还同时会将这个CF标志置为1, 这个动作是由硬件自动完成的,不需要由编程人员来设置。

B6B1718C-E212-44BA-AC27-D314665AE608.png

在模型机上,CPU要去取下一条指令之前,都会先从PC寄存器当中,取出下一条指令的地址,将这个地址发到存储器中,才能取回下一条指令的编码。 那在8086当中,这个寄存器称为IP寄存器。IP是指令指针的缩写。编程人员是不能直接修改IP寄存器的, 除了顺序取出指令,IP寄存器会自动增加以外,如果遇到了转移指令,这些会改变程序流向的指令,那CPU会自动修改IP寄存器的内容。 这里我们还需要注意一个问题,因为IP寄存器是16位宽的,所以它能够指向的内存单元的数量是2的16次方。 也就是64K个字节单元,那么即使在那个时代,64K的内存也是太小了, 无法满足当时大多数程序的需求。 因此,实际上8086在外部连接的是一个1兆字节的内存。这样就需要8086对外有20位的地址线。那多出来的这4位地址线,从哪里来呢? 那8086采用的是一个很巧妙,也很繁琐的解决方案。这就是用段寄存器的方式,段寄存器是用来和其它寄存器一起联合生成存储器地址的, 8086当中有4个段寄存器。 CS是代码段寄存器,DS是数据段寄存器。ES是附加段寄存器,SS是堆栈段寄存器。

D9DF70D8-DC11-4870-88DF-73B6E1EE3544.png
2A1BBE35-5546-4CF3-9871-46E4ED94B4BA.png

以代码段寄存器为例,来看一看地址生成的方式。假设8086CPU要从这个1M的内存中取出一条指令,那就需要现在段寄存器当中保存这个地址的一部分。然后地址的另一部分根据这个程序的本身来产生。这样的组合,就称为逻辑地址。 我们假设已经在这个代码段寄存器当中存放了一个16位数,那用16进制来表示,就是2000H,而根据程序运行的状况,当前IP寄存器当中的值是3000H, 那下一条指令的地址是怎么产生的呢? 那在CPU内部就会有一个硬件单元,负责移位, 先将段寄存器当中的16位数向左移4位。 那新产生的这个数用16进制来表示就是20000H, 然后再将这个移位后的数与IP寄存器当中的内容相加, 这又需要用到一个加法器。 相加之后就得到一个20位的地址, 在这里就是23000H,这时CPU才 可以将这个地址发送到存储器去,从而取回下一条指令的编码。 而这个地址则被称为物理地址,从逻辑地址到物理地址,就是用段寄存器当中的内容乘以16再加上程序中产生的偏移地址。

9B494A1D-40C7-4F2A-9DDD-61FD28D24E76.png

假设这时CPU已经把下一条指令的编码取回了,放在IR寄存器当中,那这条指令是要将3000H所指向的内存地址当中的数取出来,放在AX寄存器当中。 那如果是在我们之前讲过的模型机上运行,CPU就会将3000H这个数,放到MIR寄存器当中去,然后再传送到地址总线上。 但是对于8086来说,它要发出的是一个20位的地址,必须先要用段加偏移的方式进行计算。那我们假设之前已经在DS寄存器当中保存了2000H这个数,那CPU的硬件就会将DS当中的数取出来。送到一个移位的部件,向左移4位。 然后再和3000H相加。 这样就得到了一个20位的地址,23000H,然后才能把这个生成的地址放在MIR寄存器当中,再传送到地址总线上。 然后存储器则会返回23000H这个地址所对应的内容,并放到数据总线上,进一步保存到了MDR寄存器中,最后CPU的硬件 会将MDR当中的内容,再传送到AX计算器当中,从而完成了这条指令所执行的操作。

那么结合上一页我们所介绍的内容,我们会发现,对于8086来说,它在取指令的时候,就要执行一次段加偏移的这样的计算。 那么在执行指令的时候,还要执行这样一次计算,那它执行一条指令的过程就要复杂得多了。 当然,虽然很繁琐, 但在那个时期,确实在一定程度上解决了16位地址空间太小的问题。但是想要提供更高的性能,以满足当时蓬勃发展的个人计算机的需要, 还是要从体系结构上做大的改进。

而1985年推出的80386就是这样一款跨时代的作品。80386是x86系列当中第一款32位的微处理器,也就是说它的运算部件可以支持32位数据的运算, 同时也提供32位的通用寄存器,那么自然它也可以产生32位的地址,从而可以指向2的32次方,也就是4G字节的内存空间。 这样大容量的内存空间在之后相当长的时间里,都让编程几乎不受内存空间的限制。而英特尔也凭借80386确立了它在个人计算机CPU领域的优势地位。此外,80386还对运行模式进行了改进,以便更好和更稳定地支持操作系统,以及越来越丰富的软件。32位x86的体系结构也被称为IA-32,它所提供的32位寄存器是在8086的16位寄存器的基础上扩展而来的。 例如8086中的AX寄存器在为它增加了16位之后就变成了32位的EAX寄存器。在指令中如果使用EAX,就是指这个32位的寄存器,但与此同时,指令中还可以继续使用AX来指定其中的低16位。同样,也可以继续使用AH和AL这两个8位的寄存器编号, 那这样IA-32中就有了8个32位的通用寄存器,还有一个32位的标志寄存器。指令指针寄存器也扩展到了32位, 用这个寄存器就可以指向2的32次方,也就是4G字节的内存空间。从这里看来,386只要使用这个EIP寄存器就足够了, 但实际上386不但保留了原先的4个段寄存器,还增加了2个段寄存器。而运行在保护模式下,这些段寄存器的使用方法是不一样的

3DDCFD1D-09B1-4DB6-A9AB-B5F7C0239580.png
CB354163-60E4-4CDA-993C-56A28876CF9E.png

那到了上世纪90年代后期,即使在个人计算机领域,32位CPU也逐渐出现了难以满足性能需求的情况,尤其是4G内存的空间限制了大规模程序的应用, 那在这时,一贯主导x86体系结构改进的英特尔,它提出了名为IA-64的体系结构。这个64位的体系结构和之前的x86体系结构并不兼容,那由于种种原因,这个新的结构并未获得成功。那趁着这个机会,AMD后来居上, 提出了与原先兼容的64位的x86的方案, 从而在64位的时代占据了先机, 当然后来英特尔也转回来支持这个兼容的方案。 那这个方案有很多不同的名字, 比如说AMD64,Intel64, 通常我们更多地把它称为x86-64。 那x86-64的寄存器模型 则是在IA-32的32位寄存器模型的基础上进行了扩展。那与之前类似,在原先32位的EAX寄存器的基础上再增加32位,形成了64位的RAX寄存器。 而指令指针寄存器也被扩展到了64位,因此理论上我们就可以访问2的64次方个字节这么大的内存空间。 此外,因为把常用的操作数放在寄存器当中比放在存储器当中性能要好得多。因此有更多的寄存器,编程就会更加地方便。 那么在x86-64当中,另外还新增了8个64位的通用寄存器, 这8个新增的寄存器的名称依次为R8,R9,一直到R15。 因为之前我们就已经有了8个通用寄存器, 如果要给它们编号的话,就正好是从R0到R7, 所以新增的寄存器就从R8开始编号, 这就是x86体系结构从16位直到64位的大致情况。

7AB9CEA6-0DF0-4707-AD4B-F85CC646AF5F.png

MIPS 精简指令集 RISC

RISC是精简指令系统计算机的简称,与之相对,之前的计算机上的指令系统就被称为复杂指令系统,X86就是其中的代表。现在MIPS处理器已经不再应用在计算机产品中了,但是在广义的计算设备包括数字电视,游戏机,网络设备等领域仍然有广泛的应用。

MIPS全称的含义是一个流水线不会互锁的微处理器,流水线是现代微处理器为提高性能而采用的一项技术,而流水线中的互锁则是导致流水线性能降低的一个非常重要的因素。从这个名称也可以看出,MIPS的指导思想是希望其指令的设计能让微处理器运行的更快,性能更好。 所以它主要的关注点是减少指令的类型,并且降低指令的复杂度,所以在MIPS指令系统当中, 指令的总数是很少的。 而且每条指令都比较简单

它的主要目的就是希望可以用一个非常简单的CPU来支持这样的指令系统。而CPU越简单 就可以运行的更快。假设要编写程序完成同样的任务,用MIPS指令编写,其指令数量是X-86指令的5倍, 但是如果MIPS的CPU能够做到比X86 CPU快10倍,那它仍然获得了明显的性能优势。

这就是MIPS,同时也是RISC的设计思想。 那MIPS的指令是怎么体现它这样的设计思想的呢?

  1. MIPS固定了指令的长度,都是32个比特,也就说MIPS中的一个WORD,我们要注意这和X86中一个WORD是16位是不同的。固定的指令长度,大大简化了CPU从存储器中取指令的工作。 不用像X86CPU那样需要判断每条指令的长度。
  2. MIPS采用了非常简单的寻址模式,相比于X86提供的复杂多样的寻址模式,虽然给编程带来了不变,但是大大简化了CPU访问存储器的控制逻辑。
  3. MIPS指令的数量比较少,每条指令的工作也很简单,基本上一条指令只完成一个操作,不像X86的指令,一条指令往往完成丰富的功能, 这样可以简化指令的执行过程。不但简化了CPU的控制逻辑,而且可以方便的实现各种让指令并行执行的技术,从而提高CPU的性能
  4. 在MIPS指令系统中只允许LOAD和STALL这两种指令访问存储器,而不支持X86指令中这些让算术指令访问存储器的操作。 因为访存是一个相对复杂的工作, 这种限制就可以让运算指令的实现变得非常的简单,但是我们要注意,MIPS 的这些特点让直接使用MIPS指令进行编程变得非常的困难,因此,想要有高效率的MIPS程序,必须要有优秀的编译器的支持。

MIPS指令的基本格式就分为这三种,R型,I型和J型。R型指的是寄存器型, I型指的是立即数型,J型指的是转移型

BC6ABB58-7877-4DFD-9CAB-0326E423D07F.png
93E57DDF-4C77-4DE2-9581-CA709926F3B1.png
78786D62-F069-44B8-9D12-D814E851F16B.png
327867B9-9A68-42E4-B2E7-2151EF3EB8F7.png
C20E5C96-B7CA-4825-8E91-DE5588094BAF.png

算术逻辑单元

8E569D05-5D79-4A40-B9D8-EE764BB28722.png

现代集成电路中通常使用MOS晶体管。

29033145-724B-4C6F-956D-06334EAF8F2B.png

在CPU当中用来存放信息的非常重要的部件就是通用寄存器, 比如说0号通用寄存器,在mips的体系结构中,它就是一个32位的寄存器, 从电路实现上来说这32个比特都是同样的。它就可以用这样一个结构来实现。 这个结构就是我们将要介绍的D触发器。

触发器是具有存储信息能力的基本单元, 它有很多种类型,d触发器是其中一种。 仅就D触发器而言,也有很多的实现方式

8C5430A6-579C-4285-8AA1-4C774F7C5A6B.png

这个D触发器主要有这三个接孔,一个数据输入, 一个数据输出和一个时钟输入。 它的功能表现是这样的,在时钟clock的上升沿,也就是clock从低电平变为高电平, 也可以说是从0变到1的时候,这是一个很短的时间, 在这时D触发器会采样输入端口D的值, 经过一段很短的时间会将这个值传送到输出端口Q, 在其它的时候也就是不在时钟信号的上升沿的时候, 无论输入端口D如何变化,其输出端口Q的值都是保持不变的。

DD188DB9-3122-45C9-ACA0-029EAFD8E807.png

第一行是时钟信号,它是有规律的进行变化,两个上升沿之间的间隔时间就称为时钟周期,输入信号D则可能在任何时候发生变化, 比如在图示这个时候它由0变到了1,但是因为时钟上升沿没有到来,所以输出端Q并没有发生变化,直到时钟上升沿到来的时候,D触发器会采样输入端的信号, 并经过很短的clock to Q的时间在输出端体现出来,因为这时候输入端是1,所以输出端也变成了1,然后时间再继续,在这个时钟周期内,输入D又发生了变化,由1变成了0, 但是同样输出端Q没有发生变化,直到下一个时钟上升沿到来,采样到了新的输入端的指令,再经过Clock to Q输出端也变成了0这就是一个D触发器的基本工作行为。

那我们如果把很多个D触发器 组合起来,比如就是这32个D触发器,那就可以构成一个32位的寄存器,当然这只是一个很简单的原理性实现。 用这样一个32位的寄存器就可以做成CPU当中的一个通用寄存器,用同样的方法可以作出其它的通用寄存器以及PC,IR这样的寄存器,再将这些寄存器于其它的由逻辑门构成的电路相连, 就构成了我们这个复杂的CPU了

BC33CA6C-32AD-4215-8E00-3E68DBE37DA1.png

就好比我们平常使用的照相机,我们把镜头比作d触发器的输入端D,拍照的快门比作时钟端clock,这台相机内部带有无线传输的模块,可以将其拍摄的照片传送到一个显示器上,这个显示器就好比D触发器的输出端Q,那这样我们就把D触发器比作这个照相机和这个显示器。 当按下照相机的快门后,照相机会拍一张照片,过一秒钟后显示器上显示出这张照片,对于D触发器来说,这就叫做clock to Q的时间,也就是从时钟的上升沿到来开始直到数据出现在输出端为止,这个时间是属于D触发器自身的特性,那对于这个D触发器所在的整个芯片还有一个重要的特性就是时钟频率,在这里就好比我们约定每十秒钟会来按一次快门,那这个系统的时钟频率就是零点一赫兹。

需要注意的是就和现实中的照相一样,在按动快门的前后很短的时间内通过镜头看到的画面不应该发生变动,否则就可能造成拍出的照片是模糊的。 对于D触发器来说,在时钟上升沿前后很短的时间内,输入端的信号也不能发生变化,否则就可能造成无法正确的采样。 那么这也是D触发器的一个重要的特性,要求输入信号在时钟上升沿之前有一段很短的稳- 定时间, 很短的稳定时间,称为set up时间,在时钟上升沿之后也需要有一段很短的稳定时间,称为hold时间。

逻辑运算的实现

A1B399BB-885B-4DBA-8CBC-7E02669A44EA.png

在ALU当中,实际上是包含了多钟不同的功能部件。包括32位的与运算,32位的或运算,还会有其它的逻辑运算以及算术运算单元。 那它们是怎样合成一个整体的呢?对于这个整体的运算单元,它需要有一个32位的输入,然后在运算单元的内部, 分别连接到各个不同的运算功能部件的A输入端口,然后将另一个32位的输入也在运算单元的内部分别连接到各个不同功能单元的B输入端口。 这样每个功能部件都按照各自的功能完成对应的与操作,或操作,以及其他的操作,并产生对应的运算结果。 那现在的问题是,我们到底需要哪个运算结果作为输出呢?

这就还需要增加一个部件就是多选器。这里我们假定这个运算单元当中包含四种功能,所以我们会有四个运算的结果,要经过一个四选一的多选器。 那样从四个选择当中选出一个来,我们就需要一个两位的选择信号,当这个选择信号为00时, 在这个图中就会选择与运算功能部件输出的结果。

如果它是01时,就会选择这个或运算功能部件输出的结果。这个多选器实际上也是由若干个门组成的。当然如果这个运算单元中包含着更多数量功能单元,比如说8个,那么就要使用一个8选1的多选器, 而运算类型的选择信号也要扩大为3个bit。 那好经过这个多选器之后,我们就可以产生一个32位的输出。那对于这一个完整运算单元来说,当我们通过这个选择信号选择了对应的运算类型之后, 从运算单元的输出端口,我们就可以看到经过指定运算之后产生的输出

实际上是在控制电路的控制下 将9号和10号寄存器的内容分别连接到ALU的两个输入端,这里我们需要进行的与运算。如果按照上一页给出的例子, 这时候控制电路给出的选择信号应该是00。最后控制电路还会将ALU的输出与8号寄存器的输入相连, 这就相当于左边这张图所显示的电路的连接。最上面是由32个D触发器组成的8号寄存器,中间是9号寄存器,然后是10号寄存器。9号,10号寄存器的Q端的输出会被链接到ALU的两个输入,同时ALU的功能选择信号输入了与运算所对应的编码。 然后ALU的输出会被连接到8号寄存器的输入D端,所以在某一个时钟周期内,ALU会按照输入的要求完成相关的运算,并将运算结果送到输出信号上。 输入结果经过连线的传送, 会送到8号寄存器的输入端, 等到下一个时钟上升沿来临的时候, 8号寄存器就会将输入端的信号采样,存入到寄存器内部,并会在输出端表现出来。之后的运算如果使用8号寄存器作为输入的话,就会使用这个新的值。

E27F8CF9-4DF7-4CC0-B87A-4143CE8742BE.png

半加器缺陷:它不能将第一位产生的进位作为输入参与运算

3A31D277-FFB0-4336-9583-0DA15B7E186B.png

全加器实际上是两个半加器加一个或门组合而成。可以很好的弥补半加器的缺点

305543E2-5745-44AF-A4D2-AB04FC4576CE.png

和这个四位的加法器一样,我们可以很容易的构建出32位的 加法器。也就是用32个全加器串联而成

79B8F5B8-9F41-4250-A7FF-2E9F9E9C12AC.png

它的输入是两个32位数A和B在加法器的内部,会分别连接到了32个全加器的A输入端口和B输入端口。输入全加器的输出成为一个32位的加法器的输出。 整个加法器的进位输入连接到了最低位的全加器。而最高位全加器的进位输出作为整个加法器的进位输出。 这样的加法器就可以满足加法运算指令的需求,对于这道指令我们只需要将rs所指向的寄存器和rt所指向的寄存器的内容分贝连接到A端口和B端口并将S送到RD所指向的寄存器这就完成了对应的加法运算。那么ui的指令类似 addu的指令也完成了同样的运算功能,这两条指令的区别就在于对溢出的处理不同。溢出是指运算结果超出了正常的表示范围。 由于在计算机中我们总是用有限的二进制位来表示一个数,因此加法运算的结果有可能或超出这个有限的位数所能表示的范围。 溢出这种情况仅是针对有符号运算数来说的。 具体表现就是如果两个正数相加,结果变成了一个负数; 或者两个负数相加结果变成了一个正数这显然是不正确的 进位必然正负性取反。

进位是很容易判断的,加法器本身就提供了这样的机制。最高位的全加器的进位输出就是整个加法器的进位。溢出就是当最高位的全加器的进位输入不等于它的进位输出的时候,这就是发生溢出了。像如下示例逻辑也很清晰,可以根据最高数值位是否产生进位,以及符号位是否产生进位来判断是否有溢出发生,即如果最高位的进位输入和最高位的进位输出不相等的话,就表示发生了溢出。

两个有符号数相加产生溢出的条件:

  • 正数+正数:如果结果为负数,则产生了溢出;
  • 负数+负数:如果结果为正数,则产生了溢出;
  • 正数-负数:如果结果为负数,则产生了溢出;
  • 负数-正数:如果结果为正数,则产生了溢出;
A7D5D58A-E4CE-43FA-9C22-95970066DA51.png

这是刚才的全加器,这个c31就是最高位的全加器的进位输入。C(out),就是最高位全加器的进位输出。把这两个信号连出来,判断它们是否不相等。用一个异或门就可以了。当它们不相等时,异或门的输出为1。当他们两个都为0或者都为1时,异或门的输出为0。因此,就可以用这个信号来表示是否发生了溢出。

对于 一个加法器的硬件实现,它并不关心这两个输入数是有符号数还是无符号数。或者说,它对于有符号数和无符号数的处理都是一样的。 全都是通过这套同样的硬件逻辑,进行运算,产生相同的结果。至于参与运算的数到底是有符号数还是无符号数,取决于编程人员如何去看待它。因此,是不是要处理溢出以及如何处理溢出,就不能只交给硬件来做。不同体系结构有不同的方法。

我们先来看MIPS处理溢出的方式。它提供了两种不同的指令。如果编程人员想将操作数看作有符号数,需要处理溢出,则需要使用add和addi这样的指令。 当这样的运算发生溢出时,会产生异常。就是说,控制电路会检查加法器产生的overflow的信号。 如果overflow信号有效,控制电路就会当做一个异常的情况进行处理。如果编程人员希望将操作数看作无符号数也就是不对溢出进行处理。 那就需要使用这两条指令,addu和addiu。它们分别和上面这两条指令是对应的。唯一的区别就是,在执行这两条指令时,控制电路不会检查加法器输出的overflo-w信号。所以说,MIPS处理溢出的方式是提前做准备。按照是否要处理溢出,采用不同的指令进行运算。

而x86则采用了另一种方式。它并没有根据是否处理溢出分为两种运算指令,x86的运算指令,如果产生了溢出,并不会直接由控制电路检查到并进行处理。 而是将加法器产生的溢出信号传送到了标志寄存器。 如果发生溢出,则会致标志寄存器当中的OF位为1.如果没有发生溢出,则致OF位为0。这就是x86的标志寄存器,其中第十一位是OF位,这就是溢出标志。则在后续的指令中,需要检查标志寄存器的OF位是否为1并进行相应的操作。

E68E7EA3-D43C-4BFF-A6DD-473F52BE15B0.png

补码表示二进制数取相反数,有这样一个转换的规则。 叫做按位取反,末位加一。

原理:例如我们有一个数X,那么所谓按位取反,就是将X中的每一位由0变成1,由1变成0,那么得到了X按位取反以后的值。如果我们把这两个值相加, 那么它们的和,显而易见,每一位都是1. 在补码表示中,全1的这个二进制数,就代表着-1 。那么由这个运算我们可以得到,如果将X和它按位取反后的值相加, 就等于-1,我们把这个等式进行一些变换, 就可以得到,X相反数,就等于对X进行按位取反。然后再加上1。那么我们在加法器的基础上,用这样的方式,就可以很容易的实现减法器。

那么我们应该对加法器进行怎样的改造就能实现这样的操作呢?我们来看,这就是刚才的那个加法器。原来的输入A和B都不变,我们增加了一个新的输入,sub-mode只有一个比特,称为减法模式。它首先控制了一个二选一的多选器,如果这个信号为0代表是执行加法操作,那么会将多选器会将B传送的下面的这些全加器。这就跟刚才的加法运算是一样的。而且我们还注意到这个选择信号还连接到了最低位全加-器的进位输入,但是因为它现在是0,所以仍然和刚才的加法操作是一样的,这时候就该执行一个加法的运算。如果这个信号为1,代表要执行一个减法的运算。那这个二选一的多选器会将B这个信号的输入每一位都接上一个非门,相当于按位取反,将按位取反的B送到每一个全加器与A相加,我们还要注意,因为这个选择信号为1,所以最低位的全加器的进位输入也是1。这样就实现了对B进行按位取反,末位加一的操作,于是这个加法器也就变成了减法器。这样我们通过这个改动,这个功能部件又能实现加法,又能实现减法,通过这个选择信号来进行选择。

CBACACD0-F971-48BF-A82B-B043076843F4.png
59BD16F6-D368-4955-A19B-91207E0EF726.png

由于电路中An和Bn都是一开始可以确定的。且电路中C0的值一开始也是确定的,所以电路中所有值都可以通过这三个值进行确立。

3978D9BD-1E65-4B5A-A72E-D20F9BF727AA.png
DE6DA306-4B46-4E6F-9739-E54E2C637791.png

乘法器和除法器

乘法器

ECF4339D-566A-4ABA-8F44-939AE24B398E.png
CA8A45EC-48D6-4105-88F4-84B3CE7A6FFA.png
F83CA6E2-89FF-4093-AFCC-E445A57C1CC1.png
41A56711-B97A-4EF8-B3A0-3197C07A79AD.png

要实现一个四位的乘法器, 首先我们需要一个寄存器来保存被乘数,被乘数寄存器是一个八位的寄存器。而且带有左移的功能。 它有一个左移的控制信号输入,当外部的控制逻辑将这个信号视为有效时,在下一个时钟顺延到来的时候,被乘数寄存器当中的内容就会向左移动一位。

第二个寄存器是乘积寄存器,这也是一个八位的寄存器。 用来保存运算的结果。 被乘数寄存器当中的内容和乘积寄存器当中的内容需要进行加法运算, 这里我们就需要进行一个八位的加法器。 它会将被乘数寄存器当中的内容和乘积寄存器当中的内容进行相加,并将结果再送到乘积寄存- 器当中。

另外,我们还需要一个寄存器来 保存乘数。 这个寄存器只要四位就可以了。但有一点比较特殊,乘数寄存器的最低位被连到了控制逻辑, 也就说控制逻辑可以观察当前乘数寄存器的最低位,并据此来生成相关的控制信号, 这些控制信号就包括是否要让加法器进行 加法运算,以及是否要让乘积寄存器保存当前的运算结果。 另外,这个乘数寄存器还需要有向右移位的功能, 同样也是由控制逻辑发出的信号来进行控制的。 现在我们就有了一个完整的乘法器。

步骤如下:

  1. 首先是检查乘数寄存器的最低位,看是否为1,现在发现它是1,那么就需要将被乘数寄存器当中的内容和当前乘积寄存器当中的内容进行相加, 我们把这一步命名为第一步之后的一个小的步骤,称为1A, 在这一步控制逻辑会控制加法器,将 加法器的两个输入,也就是被乘数寄存器的内容和乘积寄存器当中的内容进行加法运算,然后将加法器的运算结果送入乘积寄存器,在下一个时钟上来临的时候,因为乘积寄存器的写入信号是有效的,所以它就会采样输入端的数据,饼保存到寄存器当中。 这样在这个时钟上升元之后,乘积寄存器当中的内容 就变成了00001000
  2. 对被乘数进行左移,以便为下一次运算进行准备。所以控制逻辑会给出左移的信号,那么在下一个iii来临的时候,被乘数寄存器就会完成一次左移, 最左端的0被丢弃了,在最右端补入一个0
  3. 乘数寄存器是有右移功能的,控制逻辑会给出右移的控制信号,当下一个时钟上升来临的时候,乘数寄存器就会向右移动一位。所以在做完加法运算之后的 第二步和第三步,实际上是在为下一轮的工作做准备。
  4. 进行一个判断。那就是到底有没有下一轮。由控制逻辑进行判断,现在是否已经完成了运算,对这个四位的乘法器来说, 一共要产生四个中间结果并将他们相加,所以与刚才类似这样的工作一共要执行四轮,简单的计数对硬件来说是非常容易的, 所以控制逻辑可以很容易的判断出当前是否已经是第四次循环了。

这种结构的乘法器工作时,每执行一轮,都需要3个时钟周期那如果是一个32位的乘法器,那就大约需要100个时钟周期。上述4步,虽然我们在介绍流程时这些步骤是一步一步进行的,这样只是便于我们理解。在实际的实现上,它们并不需要一定有一个先后的顺序。需要清楚的知道的是寄存器的内容只会在时钟上升沿来临的时候发生变化而在其他时候,无论输入端如何变化,寄存器的内容都不会发生变化

假设现在时钟上升沿还没有来临,那“被乘数寄存器”的输出就是它当前所保存的内容00001000,这八位信号会被送到加法器的输入端,而加法器的另一个输入端连接的是“乘积寄存器”的输出端,因此,现在的信号值是全0。而当前“乘积寄存器”的最低位为1,控制逻辑会据此 产生相关的控制信号,包括让加法器进行加法运算这样加法器就会产生对应的运算结果。与此同时,控制逻辑还会给出写输入信号但是现在时钟上升沿还没有来,所以“乘积寄存器”其实什么也不会做。那在这个时候,控制逻辑实际上可以同时给出“被乘数寄存器”的移位信号还可以给出“乘数寄存器”的移位信号。那现在,控制逻辑就将刚才流程图当中的第1a步第2步和第3步所对应的控制信号都置为有效了。但是因为时钟上升沿还没有来,所以这些寄存器的内容都不会发生变化。 那么当时钟上升沿到来的时候,这些寄存器就会根据输入改变其内容。“乘积寄存器”会将输入端的数保存起来,“被乘数寄存器”会向左移动一位,“乘数寄存器“会向右移动一位。而这些操作都是在同一个时钟上升沿到来的时候完成的,又因为在时钟上升沿之后很短的一个时间寄存器所改变的内容就会传送到输出端。因此我们可以注意到,”被乘数寄存器“的内容现在已经改变,因此很快,它的输出也会变成00010000,并传递到加法器。

但是我们可以放心的是,即使这个信号经过了加法器,并产生了新的运算结果这个运算结果也不会改变”乘积寄存器“的内容。 因为等这个信号传递到了”乘积寄存器“的输入端时已经过去了一段时间,这时候”乘积寄存器“对输入端的采样工作已经完成其输入端信号的改变不会影响这个寄存器的内容了。这样我们就在同一个时刻完成了所有的加法和移位的操作。那我们再回到刚才的那个流程图。在这个流程图当中,这3个顺序执行的操作就可以进行优化而我们这32位的乘法,也就不应该再需要100个时钟周期了。经过优化以后的工作流程,在最开始的第1步,和最后的第4步,还是跟原来一样的而中间的这3步,我们可以把它并排地放在一起。当第1步检查”乘数寄存器“的最低位,如果最低位是1的时候第1a步、第2步和第3步将同时进行 如果最低位为0,则通过控制信号的不同,不执行第1a步,而同时执行第2步和第3步完成之后,就直接进入第4步。这样我们每一次循环只需要一个周期 我们用这个很简单的优化,就把性能提升为了之前的3倍。

对于CPU这样的集成电路芯片来说, 它的价格的一个重要因素就是其中晶体管的数量。 或者说是芯片的面积。

乘法器最终优化结果:

  1. 被乘数寄存器,位数等于实际位数,不需要左移操作
  2. 乘机寄存器,位数等于被乘数位数加乘数位数。初始值放在半高位,为了弥补被乘数无法左移对其运算,增加右移功能
  3. 加法器,被乘数寄存器的这几位和乘积寄存器的半高位进行运算
  4. 乘数寄存器移除,内容放在乘机寄存器的半低位。有效位随着每轮乘机寄存器右移而改变。

乘积寄存器初始值的放置位置也发生了一点变化,我们把它放置在高四位的地方,并在这个寄存器中间加一条虚拟的线来标志高四位和第四位的分界。

乘积寄存器的最低位连接到控制逻辑,这也就是我们当前所需要观察的乘数的对应位,如果发现这位为1,控制逻辑就需要向加法运算的控制信号,并向乘积寄存器发出写入的控-制信号,并向乘积寄存器发出写入的控制信号,但这个写入只发生在 但这个写入只发生在这个寄存器的高四位,然后每个周期会发出右移的控制信号,那么随着乘积寄存器的右移,原先存放在第四位的乘数就在逐渐的被移出,而原先只在高四位的乘积则逐渐占满了乘积寄存器。而在这个过程中,控制逻辑每一轮都可以观察到 乘数的对应位,从而产生对应的控制信号,因此这个结构可以完成刚才我们所介绍的那个乘法运算流程的所有工作。

E58F90A2-8599-4999-8073-B8AB3C852AE3.png

除法器

对于除法操作,本质上你被除数是在不断的和除数进行减法的操作,最后产生了余数。如果我们将每次减法运算的结果都放回到被除数的寄存器当中, 那么这个寄存器又可以被称为余数寄存器。现在我们就有了第一个部件,就是一个8位宽的余数寄存器。 然后我们还需要一个部件来保存除数,还需要一个部件来保存商。除法中这个位宽和乘法运算正好是相反的,在乘法当中,我们一般会约定乘数和被乘数的宽度是一样的,如果两个都是4位宽的,则乘积最多为8位宽,所以在除法当中,我们也用了类似的约定。 如果被除数是8位宽,则除数和商都约定为4位宽。

4D1CEDD9-661E-4783-9E5B-9078F911F379.png
2EE85422-4AB3-415D-BDCF-67634EB8577A.png
除法器初始化流程
除法器面积优化

处理器的设计步骤

指令系统,是在处理器设计之前,就由软件和硬件的设计人员共同协商决定的

609C162E-E41F-4D39-A103-87B6799C2B3A.png

在现代计算机当中,内存就是这样一个指令和数据统一存放的存储器但是在处理器内部,现代的设计往往会设置高速缓存, 也就是Cache这样的部件,用来保存内存当中的一部分数据。高速缓存这个结构,是会被分成指令和数据两个部分

45681FB5-C5CD-47C8-A983-F4B70EC4FAC2.png
6E889F3B-1F47-4BC5-8A50-0905D4D20DD4.png
3550E72C-F558-4CE5-89C3-6A30A6162A87.png
A7E680EB-D2E9-4130-A222-F50E2BFC0A6C.png

如上图,这个RegWr信号等于1的时候,寄存器堆就会采样busW信号上的内容,并将其存入到Rb这个信号所指定的寄存器当中去。然后我们将busA和busB连到ALU的输入端,并且我们根据指令编码当中的操作码和功能位域,就可以知道当前是加法还是减法指令, 我们要通过一个控制信号,来选择当前ALU提供的运算的类型也就是ALUCtr指令。

05D7D9B5-3234-491B-AE2A-59C6B887F1BA.png

同一功能部件扩展而来

  • RegDst:1/2选择器
  • ALUsrc:1/2选择器
  • ZeroExt:0高位扩展器
32C1F202-BC49-425C-B7EB-51164197C270.png

Store指令是将rt所指定的寄存器当中的内容存放到数据存储器当中去。rt所指定的寄存器的内容会从busB信号上出来,那我们就需要将这个信号连接到数据存储器的数据输入端,但是对于除了Store之外的其他指令,我们都不希望将busB上的信号写入到数据存储- 器当中, 所以我们还需要给数据存储器连接一个控制信号,只有在这控制信号有效的时候,才会进行写入的操作,这个信号就是图中MemWr,这样我们就满足了Store指令的需求。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,393评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,790评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,391评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,703评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,613评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,003评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,507评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,158评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,300评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,256评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,274评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,984评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,569评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,662评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,899评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,268评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,840评论 2 339