汇编语言是计算机机器语言的人类可阅读表示。每条汇编语言指令都指明了需要完成的操作和操作所处理的操作数。
1. 指令
常见的加法计算操作代码示例如下。
将两个变量b和c相加并将结果写入a中。左边是高级语言(C、C++或Java),右边使用MIPS汇编语言。
汇编指令的第一部分add是助记符( mnemonic),它指明需要执行的操作。该操作基于源操作数( source operand) b和 c,将结果写入目的操作数( destination operand ) a。
减法指令类似于加法,除了操作码sub 以外,指令格式完全与加法指令相同。这种一致的指令格式很好地证明了第一个设计准则:
设计准则1:简单设计有助于规整化。
指令中包含固定数目的操作数(在本例中,有2个源操作数和一个目的操作数)将易于编码和硬件处理。更复杂的高级语言代码可以转化为多条MIPS 指令,如下面代码示例所示。
代码示例中的汇编语言程序需要一个临时变量t来存储中间结果。使用多条汇编指令执行复杂的操作体现了计算机体系结构的第二个设计准则:
设计准则2:加快常见功能。
MIPS 指令集通过仅仅包含简单、常用指令使常见的情况能较快执行。指令数比较少,这使得用于指令操作和操作数译码的硬件比较简单、精练和快捷。更复杂但不常见的操作由多条简单指令序列执行。因此,MIPS 属于精简指令集计算机(Reduced Instruction Set Computer ,RISC)体系结构。具有复杂指令的体系结构,例如 Intel x86,称为复杂指令集计算机(ComplexInstruction Set Computer,CISC)。
2. 操作数:寄存器、存储器和常数
一条指今的操作需要基于操作数。代码示例中变量a、b、c都是操作数,但是计算机只能处理二进制,而不能处理变量名,指令需要从一个物理位置中取出二进制数据。操作数可以存放在寄存器或存储器中,也可以作为常数存储在指令自身中。
计算机使用不同的位置存放操作数以便优化性能和存储容量。访问存放在指令中的常数或者寄存器中的操作数非常快,但是它们只能包含少量数据。更多的数据需要访问存储器得到。存储器虽然容量大,但是访问速度比较慢。
2.1 寄存器
2.1.1 寄存器集
大多数体系结构定义了几个寄存器用于存放常用的操作数。MIPS体系结构有32个寄存器,称为寄存器集( register set) 或寄存器文件( register file)。寄存器越少访问速度越快,这正验证了第三个设计准则:
设计准则3:越小的设计越快
下面代码示例显示了具有寄存器操作数的add指令。MIPS寄存器名由$
符号开始。变量a、b和c存放在$s0
、$s1
和$s2
中。( $s1
读作"Register sl"或“dollar s1")。指令将对$s1 (b)
和 $s2(c)
中存储的32位数据相加,并将32位结果写入$s0(a)
。
MIPS有32个寄存器,寄存器的名字、编号和用途如下:
2.1.2 保存寄存器(saved register)
其中使用18个寄存器存储变量$s0 ~ $s7
和 $t0 ~ $t9
。由$s
开头的寄存器称为保存寄存器(saved register)。根据MIPS的惯例,这些寄存器存储诸如a、b、c等变量。保存寄存器的一个特殊用途是用于函数调用。
2.1.3 临时寄存器( temporary resister)
以$t
开头的寄存器称为临时寄存器( temporary resister),用于存储临时变量。上述代码示例中MIPS汇编代码使用临时寄存器$t0
来存储c~d的中间结果。
例:
2.2 存储器
MIPS采用字节寻址存储器,存储器中的每一字节都有一个单独的地址。
2.2.1 字寻址存储器
字寻址( word-addressable)存储器阵列如下:
每32位数据字对应一个唯一的32位地址,其中32位地址和32位数据值用16进制表示。例如,数据OXF2F1ACO7存储在存储器地址1中。
MIPS使用装入字(load word)指令lw将存储器中读出的数据装入寄存器中:lw指令指定内存有效地址( effective address)为基地址(base address)与偏移量( offset)的和。
内存有效地址( effective address)=基地址(base address)+偏移量( offset)
基地址为寄存器,写在括号内。偏移量是一个常数,写在括号前面。
基地址$0
为0,偏移量是1,所以lw指令从存储器中读出的地址为($0
+1)=1。在lw指令执行之后,$s3
中的值为OXF2F1ACO7,就是字寻址存储器阵列图中1所存储的值。
类似地,MIPS使用存储字( store word)指令sw从寄存器向存储器写数据字。将寄存器$s7
中的内容写入存储器5的代码示例如下:
2.2.2 MIPS 存储器
上述两个代码示例描述了字寻址存储器的计算机体系结构。然而MIPS存储器模型是字节寻址而不是字寻址。 每一个数据字节都有一个唯一的地址,一个32位的字包含4个8位字节,所以每一个字地址都是4的倍数,32位字地址和数据值都是用16进制表示的,如图所示:
下面代码示例描述了如何在MIPS字节寻址存储器中读/写一字。字地址是字号的4倍,MIPS汇编代码读取第0、2和3号字,写人第1、8和100号字。偏移量可用10进制和16进制表示。
2.3 常数/立即数
常数的值可以被指令立即访问,而不需要通过访问寄存器或存储器来得到,所以这些常数叫作立即数( immediate)。
加立即数(addi)指令是一个以立即数为操作数的常见MIPS 指令。addi将指令指定的立即数与某一寄存器中的值相加,如下代码示例所示:
指令中指定的立即数采用16位补码表示,范围在[-32768,32767]。减法相当于加一个负数,因此,为了简单起见,MIPS体系结构中没有subi指令。
前面提到的add和 sub指令使用三个寄存器操作数。但是,lw、sw和 addi指令用两个寄存器操作数和一个常数。因为指令格式的不同,所以lw和 sw指令违反了设计原则1:简单设计有助于规整化。因此,引入最后一个设计准则:
设计准则4:好的设计需要好的折中。
单条指令格式可能简洁但缺乏弹性。MIPS指令集支持三种指令格式:
- 第一种格式有三个寄存器操作数,如add和sub指令;
- 第二种格式有两个寄存器操作数和一个16位的立即数,如lw和addi指令;
- 第三种格式有一个26位的立即数,但没有寄存器操作数(如后续的[[体系架构(二) 机器语言#3. J型指令——跳转类型(jump-type)|跳转J型指令]])。