目录
计算机硬件的操作数
先从一条C语句入手
cpp
a = b + c;
将其翻译为MIPS
cpp
add a, b, c
其中a,b,c就是这条指令的操作数。表示将b与c的和放入a中。
加法指令只有三个操作数,也就是说只能一次完成两个数相加,下面的指令序列会完成四个数相加
cpp
add a, b, c
add a, a, d
add a, a, e
只能一次完成两个数相加体现了硬件简单性的设计原则。下面会知道,使用指令实际上不会写诸如a,b,c之类的字符,而是使用寄存器。
与高级语言不同,MIPS的算术运算被要求操作数只能来自寄存器。寄存器是构成计算机的基本单元。在MIPS体系结构中寄存器大小为32位,同时拥有32个寄存器。在MIPS体系结构中也常把32位称作一个字(word)。
MIPS在使用寄存器时,用''后跟两个字符表示寄存器。用s0,s1...表示类似C语言中的变量所对应的寄存器,用t0,$t1...表示临时变量对应的寄存器。
cpp
a = (b + c) - (d + e)
以该C赋值语句为例,将其翻译为MIPS指令,假设s0,...s4分别对应存储了a,..e
cpp
add $t0, $s1, $s2 #b+c的结果存在临时变量寄存器t0中
add $t1, $s3, $s4 #同上
add $s0, $t0, $t1
MIPS中#后是注释,注意这种语言一行只有一条指令,且注释是在一行的末尾结束
存储器操作数
高级语言中常有数组和结构体,而且往往大小不止一个字,这种数据结构就会存储在内存中,而内存就是存储器,磁盘更习惯叫做io设备。
由于MIPS算术指令只能操作寄存器,因此必须有一种手段,能将内存中的数据加载到寄存器中。
这些指令叫做数据传输指令。
为了访问内存中的字,必须给出地址。内存中的地址是按字节编排的,也就是说每个相邻的地址相差1
图中每一块大小一个字节。
将数据从内存加载到寄存器通常称为取数(load)指令,实际MIPS取数指令助记符是lw,操作数有三个,第一个表示要把数据存到哪个寄存器,第二个是地址偏移量 (单位为字节,要求是常数),第三个是基址寄存器。
cpp
a = b + A[8];
假设a存在s0,b存在s1,A地址存在s2。
cpp
lw $t0, 32($s2) #一个字大小为32位,也就是4字节,8个字就得偏移32字节
add $s0, $s1, $t0
MIPS字的起始地址是4的倍数,这叫做对齐限制。字在内存中如图存储。
MIPS还有一类指令是将寄存器中的数据复制到存储器中,叫做存数(store)指令。MIPS记作sw,用法与lw类似,只是第一个操作数代表要从哪个寄存器中得到数据。
常数或立即数操作数
仅仅从已经介绍的指令来看,要使用常数,只能从存储器取出(lw),如要将a+4
cpp
lw $t0, AddrConstant($s1)#AddrConstant为某一常数偏移量,将4加载到t0
add $s0, $s0, $t0
如果要避免使用取数指令,可使用addi指令
cpp
addi $s0, $s0, 4
像这种加法叫加立即数(add immediate),常数操作数出现频率高,像这种带立即数的指令,比从存储器种取值快很多,能耗也较低。
常数0可简化指令集。例如,数据传输指令可视为操作数为0的加法。MIPS将$zero恒置为0,编号也为0
有符号数和无符号数
有符号数在MIPS中用补码表示。需要注意的是,当不满32位的数被存储时,高位会补上符号位。
像0100,存在寄存器中
cpp
00000000 00000000 00000000 00000100
1100,存在寄存器中
cpp
11111111 11111111 11111111 11111100
MIPS有一些末尾为u的指令操作无符号数,具体后面可以见到。
指令的格式
指令以二进制的形式存储,现在我们可以把指令翻译成二进制。
所有的寄存器会被映射为数字,s0\~s7映射到16~23, t0\~t7映射到8~15。
cpp
add $t0, $s1, $s2
以该指令为例,先将其翻译为十进制,再转为二进制。
机器指令分为多个字段,本例第一个和最后一个告诉MIPS计算机要执行加法操作,第二个和第三个表示源操作数寄存器,第四个字段表示存放结果的寄存器,第五个字段没有用到,故置为0。
截取《计算机组成与设计 硬件/软件接口》中相关说明
这种指令格式在某些场景可能不适用,如lw指令需要传入偏移量,5位是不够用的,这时,想要增加位数,但是MIPS的设计是,所有指令的长度都相同,这样,就会采取折中方案:所有指令长度相同,但不同类型指令采用不同指令格式。如上述指令就是R型。另一种是I型,用于传输立即数。
在这种I型格式中,立即数大小仍然有限制。可以看到这种格式下,很难增加寄存器的数量,因为寄存器序号会使得rs,rt字段增加位。
逻辑操作
一张图即可解决,用法也与其他指令类似。
决策指令
计算机的运算能力强大,但计算机与计算器的差别在于计算机能执行决策指令,也就是条件分支指令。MIPS有两条类似C语言 if和 go to的指令
cpp
beq regsiter1, register2, L1
表示若寄存器register1 和register2的值相等,跳转到L1标签。beq(branch if equal),相等则分支。
cpp
bne regsiter1, register2, L1
表示若寄存器register1 和register2的值不等,跳转到L1标签。bne(branch if not equal),不等则分支。
还需介绍另一种分支指令------无条件分支
cpp
j L1
j为jump的缩写
cpp
if (i == j)
f = g + h;
else
f = g - h;
现在将该C语句编译为MIPS指令。
假设i存在s0,j存在s1,f,g,h分别存在s2,s3,s4
cpp
bne $s0, $s1, Else
add $s2, $s3, $s4
j Exit
Else: sub $s2, $s3, $s4
Exit:
循环
条件分支指令可以实现循环
cpp
while (save[i] == k)
i += 1;
假设i和k存在s3和s5中,save的基址存在s6中。
cpp
Loop: sll $t1, $s3, 2 #需要将i×4
add $t1, $s6, $t1
lw $t0, 0($t1) #要求偏移量为常数
bne $t0, $s5, Exit
addi $s3, $s3, 1
j Loop
Exit: