本章目标
2.3 指令和指令序列
一个计算机程序所执行的任务是由一系列小的执行步骤构成的,比如像两个数相加、测 试特定的条件、从键盘上读一个字符或是发送一个字符到显示屏上去显示等。一台计算机必须 具备能够执行以下四种类型操作的指令:
存储器和处理器寄存器之间的数据传送
●
数据的算术和逻辑运算
●
程序序列化和控制执行
●
输入/ 输出传送
●
我们首先讨论前两种类型的指令。为了便于讨论,需要先介绍一些标记符号。
2.3.1 寄存器传送标记
我们需要描述信息在计算机中从一个单元传送到另一个单元。在这种传送中涉及的单元 可以是存储器中的单元、处理器寄存器或是I/O 子系统中的寄存器。大多数情况下,我们用方 便的符号名来识别这些单元的位置。例如,代表存储单元地址的名字可能是LOC、PLACE、A 或者VAR2。处理器寄存器的预定义名可能是 R0 或者 R5,而 I/O 子系统中的寄存器可能由像 DATAIN 或者 OUTSTATUS 这样的名字来识别。为了描述信息的传送,任何一个单元中的内容 用它的名字外加方括号来表示。因此表达式
R2 ← [LOC]
表示存储器单元LOC 中的内容被传送到处理器寄存器 R2 中。
另一个例子是将寄存器R2 和 R3 的内容相加,并将它们的和放到寄存器 R4 中。这个动 作表示为:
R4 ← [R2] + [R3]
这种标记方式就是所谓的寄存器传送标记(Register Transfer Notation,RTN)。要注意的是,在 32
RTN 表达式的右边总是表示一个值,而左边是存放这个值的单元名,将用这个值覆盖该单元 中的原有内容。
在计算机术语中,“传送”和“移动”常用于表示“复制”的意思。从源(source)单元 A 传输数据到目的(destination)单元 B 意味着读取单元 A 的内容,然后将其写到单元 B 中。
在这个操作中,只有目的单元的内容被改变,源单元的内容将保持不变。
2.3.2 汇编语言符号
我们需要用另一种标记符号来表示机器指令和程序。为此,我们使用汇编语言(assembly language)。例如,将存储单元 LOC 的内容传送到处理器寄存器 R2 中,产生这种传送操作的 通用指令将使用下面的语句来说明:
Load R2, LOC
执行这条指令后LOC 的内容不改变,但寄存器 R2 中原有的内容被覆盖了。名字 Load 对于这 条指令是恰当的,因为从存储单元中读取的内容被装载(load)到处理器的寄存器中。
第二个例子是将处理器寄存器R2 和 R3 中的两个数相加并将得到的和放到 R4 中,该例 子可以用汇编语言的语句描述为:
Add R4, R2, R3
在本例中,寄存器R2 和 R3 保存着源操作数,而 R4 则为目的寄存器。
一条指令(instruction)指定了一个将要执行的操作及其包含的操作数。在上面的例子中,
我们用英语单词Load 和 Add 表示所需的操作。在实际的(商用)处理器的汇编语言指令中,
这样的操作是用助记符(mnemonic)来定义的,助记符通常是描述这些操作的单词的缩写。
例如,Load 操作可能写成 LD,而将一个字从处理器寄存器传送到存储器的 Store 操作,则可 能被写成STR 或 ST。对于给定的操作,不同处理器的汇编语言通常使用不同的助记符。为了 避免在这个较早的阶段了解特定汇编语言的细节,在本章中我们将会继续使用英语单词来描 述,而不使用特定处理器的助记符。
2.3.3 RISC 和 CISC 指令集
区分不同计算机的一个最重要的特征是其指令的本质。在现代计算机的指令集设计中,
有两种根本不同的方法。其中一种流行的方法所依据的前提是,如果每条指令恰好占据存储器 中的一个字,则可以获得更高的性能,并且执行指令指定的算术或逻辑运算所需要的所有操作 数都已经在处理器的寄存器中。这种方法有利于处理单元的实现,其中处理指令序列所需要的 各种操作可以用流水线的方式重叠执行,从而减少程序的总执行时间,这将在第6 章中讨论。
每条指令必须刚好放入一个单字中的限制降低了这些指令的复杂度,减少了计算机指令集中所 包含的不同指令类型的数目。这样的计算机被称为精简指令集计算机(Reduced Instruction Set Computer,RISC)。
相对于RISC 方法的另一种方法是使用更复杂的指令,这些指令可能跨越多个存储器字,
但可以指定更复杂的操作。这种方法在20 世纪 70 年代 RISC 方法推出之前是很盛行的。尽管 复杂指令的使用最初没有确定任何特定的称呼,但是基于这个思想的计算机后来被称为复杂指 令集计算机(Complex Instruction Computer,CISC)。
由于RISC 风格的指令集比较简单,并且易于理解,所以我们将首先介绍 RISC 风格的指 令集,然后再讨论CISC 风格的指令集并说明这两种方法之间的主要区别。
33
2.3.4 RISC 指令集介绍
RISC 指令集的两个关键特性是:
每条指令为一个字长
●
● 使用load/store 体系结构(load/store architecture),其中 只能通过Load 和 Store 指令来访问存储器操作数。
■
算术或逻辑运算中涉及的所有操作数都必须在处理器寄存器中,或者其中一个操作
■
数在指令字中被明确地给出。
在程序运行之初,程序中用到的所有指令和数据都存储在计算机的存储器中。此时,处理器寄 存器中并没有包含有效的操作数。如果希望操作数在指令使用之前就已经在处理器的寄存器 中,那么就有必要先把这些操作数放到寄存器中。这个任务由Load 指令完成,Load 指令会将 存储单元中的内容复制到处理器寄存器中。Load 指令的格式为:
Load 目的操作数,源操作数 或者更具体一点:
Load 处理器寄存器,存储单元
存储单元可以用若干种方法指定。寻址方式(addressing mode)就是指能够实现这一目的的不 同方式,我们将在2.4 节中讨论。
现在我们来考虑一个典型的算术运算。两个数相加的操作是任何一台计算机的基本功能。
高级语言程序中的语句
C = A + B
指示计算机将变量A 和 B 中的当前值相加,并将得到的和赋值给第三个变量 C。当包含这个 语句的程序被编译时,三个变量A、B、C 被分配到了存储器的不同单元中。为简单起见,我 们将这些单元的地址分别称作A、B 和 C。这些单元的内容表示这三个变量的值。因此,上述 高级语言语句需要在计算机中完成的动作是:
C ← [A] + [B]
为了执行这个动作,从存储器中取出存储单元A 和 B 中的内容并将其传送到处理器中,在那 里对它们进行求和计算。然后将计算结果传送回存储器并存储在单元C 中。
上述语句所需的动作可以通过一系列简单的机器指令来完成。我们选择使用寄存器R2、
R3、R4 以及四条指令来执行这个任务。
Load R2, A Load R3, B Add R4, R2, R3 Store R4, C
我们称Add 为三操作数(three-operand)指令或三地址(three-address)指令且具有以下格式:
Add 目的操作数,源操作数 1,源操作数 2 Store 指令具有以下格式:
Store 源操作数,目的操作数
其中源操作数为处理器寄存器,目的操作数为存储单元。需要注意的是,Store 指令中源操作 数和目的操作数的定义顺序与Load 指令相反,这是一般的使用惯例。
注意,如果其中一个源操作数寄存器也同时用作存放结果的目的寄存器,那么只需要使 用两个寄存器R2 和 R3 就可以完成所需的加法。在这种情况下加法可以按如下方式执行:
Add R3, R2, R3
34
35
最后一条指令将变为
Store R3, C 2.3.5 指令执行和线性序列
在前面的小节中,我们使用任务C = A + B 作为例子,C = A + B 实现为 C ← [A] + [B]。
图2-4 给出了完成这个任务的程序段存放在计算机存储器中的情况。假定计算机的字长为 32 位并且存储器是按字节寻址的。程序中的四条指令放在连续的字单元中,起始单元是 i。由于 每条指令是4 字节长,所以第二、第三和第四条指令的起始地址分别为 i + 4、i + 8 和 i + 12。
为了简单起见,假定所需的存储器地址都能够在Load 和 Store 指令中直接说明,虽然这在包 含一个完整的32 位地址时是不可能的。我们将在 2.4 节中解决这个问题。
R4, R2, R3 R3, B R2, A
i + 8 Add i Load
C B A i + 4 Load
R4, C Store i + 12
地址 内容
从这里开始执行
4 条指令的程序段
该程序的数据
图2-4 一个完成 C ← [A] + [B] 的程序
我们来考虑这个程序将如何执行。处理器中包含一个称为程序计数器(program counter,
PC)的寄存器,它保存着将要执行的下一条指令的地址。当开始执行一个程序时,它的第一 条指令地址(在本例中为 i)必须被放入PC 中。然后,处理器的控制电路利用 PC 中的这个 信息,按照地址递增的顺序一次一条地取出并执行指令。这种执行方式叫做线性序列(straight-line sequencing)。在每条指令执行时,PC 每次递增 4 以指向下一条指令。这样当 i + 12 单元中 的Store 指令被执行后,PC 中包含的值是 i + 16,它是下一个程序段的第一条指令的地址。
执行一条给定的指令可以分成两个阶段。第一个阶段叫做取指令(instruction fetch)阶段,
在该阶段中,根据PC 中的地址从存储单元中取出该指令。这条指令被放入处理器的指令寄存 器(instruction register,IR)中。第二个阶段叫做指令执行(instruction execute)阶段,在该阶 段开始时,对IR 中的指令进行检查以确定将要执行哪种操作。然后处理器执行这个指定的操 作。这个执行过程涉及少量步骤,如从存储器或处理器寄存器中提取操作数,执行一个算术或 逻辑运算,然后将结果存放到目的单元中。在这个两阶段过程中的某个点上,PC 的内容被递 增以指向下一条指令。当一条指令的执行阶段完成时,PC 中包含着下一条指令的地址,并且 一条新指令的读取阶段又可以开始了。
2.3.6 转移 R3, NUMn R2, R2, R3 R3, NUM3 R2, R2, R3
R2, NUM1 Load
R3, NUM2 Load
Subtract R2, R2, #1
就对R2 的内容减 1(我们将在 2.4.1 节中解释符号“#”的意义)。只要 R2 的内容大于 0,就 重复执行这个循环。