1.5 存储程序的概念
本节介绍存储程序计算机其中会精确地描述直到20世纪70年代许多计算机还在采用的运行过程。今天的计算机已经偏离了这个简单的模型,因为它们能够并行地(甚至是乱序地)而不是串行地完成内部操作。下面的伪码描述了存储程序计算机的基本操作。
这段伪码表明,从存储器中取出每条指令都需要进行一次访存操作(即读存储器)。可以用下面的伪码描述“执行指令”这一动作:
在这台机器上执行一条指令需要至少两次访存。第一次访存是读取指令。第二次访存要么从存储器中读出指令需要的数据,要么将它之前的指令产生的或修改过的数据写回存储器。有时候也称存储程序计算机是按照读取/执行(fetch/execution)周期的两阶段模式工作的。
因为每条指令必须两次访问存储器,人们用“冯·诺依曼瓶颈”一词表明CPU与存储器之间的通路是存储程序计算机的制约因素之一。人们设计了不同体系结构的机器来解决这一问题,后续章节将会介绍这些内容。
下面简要介绍一下存储程序计算机上执行的指令的格式。存储程序计算机的一种直观合理的指令格式可以用下面的形式表示
这里Operation表示要执行的指令的动作,Address1、Address2和Address3分别是3个操作数在存储器中的位置。在这条一般性的指令中,操作数为数据的地址,而不是数据本身。
本书用粗体字表示地址是数据的目的地址而不是源地址。ADD P,Q,R是一条典型的三操作数指令,这里P、Q、R是三个存储单元地址的符号名。操作数的书写顺序没有严格标准。有些计算机使用destination, source1, source2的形式,另一些则使用source1, source2, destination的形式。
Address2和Address3所指定的存储单元的内容由指令所指定的二元操作(例如,加、减、乘,等等)处理。操作的结果保存在Address1所指的存储单元中。图1-13描述了这样一条指令的执行过程,它一共需要4次访存(即一次取指令,两次取两个源操作数,一次保存结果)。指令与操作数P、Q、R可存放在存储器中的任何位置。
图1-14描述了指令的4个字段与CPU、存储器以及指令的执行方式之间的关系。这台计算机只能执行4条指令并仅有8个可能的存储单元(图1-14中仅显示了4个单元)。当前指令为ADD P,Q,R,它将存储单元Q的内容与R的相加,并将结果保存在P中。该指令的二进制编码为10011010001,存储单元P、Q和R分别为011、010和001(二进制)或3、2和1(十进制)。
图1-14描述了如何用操作码选择一个操作(四选一),用源地址选择两个存储单元,以及用目的地址选择写回操作数的存储单元。该图还说明了加法指令执行期间所产生的信息流。后面我们还会看到操作码如何被转换为实现目标指令的动作序列。
这里Address2为源操作数,Address1既是源操作数也是目的操作数。这种指令格式意味着从存储器中读出源操作数,对其进行操作,并将结果写回存储器中第一个源操作数的位置。指令ADD P,Q的RTL定义为
两地址指令会破坏它的一个操作数。也就是说,它会用结果替换源操作数P。本书绝大部分章节都约定两地址指令的格式为:
而在实际的计算机中,一般都不会允许同一条指令中使用两个存储地址。绝大多数计算机(如Pentium或更现代一些的Core i7处理器)都规定一个地址是存储器地址,另一个地址是寄存器。寄存器是计算机内的存储单元,其名如r0,r1,r2,...,r31,用来保存计算过程中生成的临时数据。本书在介绍计算机的结构时会用大量篇幅介绍寄存器。
2.单地址指令
将指令数量减到最少的压力使得第一代计算机没能实现两操作数指令。它们一般都实现了单地址指令,形如
由于指令中只提供了一个操作数地址而指令却需要至少两个地址,处理器不得不使用一个不需要显式地址的第二操作数。也就是说,第二个操作数来自CPU内一个叫作累加器(accumulator)的寄存器。术语累加器今天已经很少使用了,因为现在绝大多数微处理器中都带有几个片上寄存器。图1-15描述了一条单操作数指令执行过程中的信息流。操作结果将一直保存在寄存器中,直到另一条指令将它送入存储器。这样一台计算机很难称得上简洁,如下面实现P = Q + R的序列所示。
在这个例子里,我们必须将第一个操作数Q载入累加器,与第二个操作数R相加,并将结果保存在第三个操作数P中。请注意累加器是怎样成为瓶颈的,因为所有操作数都要流过它。
寻址方式是计算机指令集的一个重要特征,它是确定操作数位置的方法。例如,可以直接(即它的地址为1234)或间接(即寄存器5的内容是我们所需要的操作数的地址)给出操作数的位置。第3章和第4章将详细介绍寻址方式。不过,在讨论计算机体系结构时,有时我们并不希望指定实际的寻址方式,因此我们使用有效地址这种更一般的形式。例如,我们会说将有效地址处的数据载入寄存器r1中。之所以使用有效地址,因为它代表了生成操作数地址的所有不同方式,因而可以避免指定某个特定的寻址方式。
3.计算机的分类
前面已经指出,计算机中既拥有能够存储大量数据的主存,也拥有CPU内临时保存中间结果的寄存器。第一代微处理器中大约有6个寄存器,而典型的现代微处理器可能有16个、32个或64个寄存器。我们可以按照计算机的指令处理数据的方式对计算机分类。如果一条指令能够从存储器中读出源操作数,对数据完成某个操作,并将结果保存在存储器中,那么这台计算机就叫作是存储器–存储器型的。使用了Intel IA32 CPU(8086、Pentium、Core i7)的计算机具有寄存器–存储器型体系结构,它们能够处理两个数据,其中一个位于存储器中,另一个位于寄存器中(结果要么被写回存储器,要么被写回寄存器)。
某些使用了ARM和MIPS CPU的计算机只能对寄存器中的内容进行操作,称作是寄存器–寄存器型的。这些计算机必须通过LOAD指令将数据读入寄存器并使用STORE指令将数据从寄存器送回存储器。由于LOAD和STORE操作是仅有的存储器访问指令,这些计算机也经常被称作load/store型计算机。后面我们还会看到寄存器–存储器型计算机被归为CISC机器一类,而load-store型计算机被归为RISC机器一类。
当讨论计算机体系结构的问题时,我们通常会用不同的微处理器作为例子。然而,由于希望学生们能够理解程序是如何构造和执行的,我们一开始会将注意力集中在ARM处理器上。