入门篇
入门篇
MIPS 的指令非常多,指导书当中也只会列举出完成实验常用的指令。
在课件下载区新增了《MIPS32-Quick Reference》,是常用 MIPS 指令的快速查询手册。

MIPS 汇编编写的主要的一个难点就是,一次只能做一个运算,但是会用到好几个寄存器,稍微复杂一点就乱了。我的建议是对每一个使用到的寄存器,都做上注释防止出现混乱。
另外,希望大家在写 MIPS 汇编的时候,多多参考 MARS Help 当中的内容。

赋值
在 C 语言中,我们最先用到的便是给变量赋值,这个在 MIPS 中该如何实现呢?
下面这条指令的意思,就是将 t1 寄存器的值赋值为 100,其实际含义是给 $t1 赋值为 100 和 0 进行按位或运算后得到的结果。
ori $t1, 100
当然了,我们也可以使用扩展指令(伪指令)li(load immediate),下面这条指令的意思,便是直接将 $t1 寄存器赋值为 100,该指令与上一条指令的效果完全一致。
li $t1, 100
是不是很简单呢?
传值
学过 C 语言的同学马上想到,在我给变量 a 赋值后,想把 a 的值传给变量 b,我们常用 b = a 的方法进行传值,那么在 MIPS 中该如何实现呢?
move $t1, $t2
这条指令的意思,就是将 $t2 寄存器的值传给 $t1 寄存器,同时 $t2 寄存器中的值不变,与 C 语言中 b = a 的含义基本一致。
加减运算
在 MIPS 中,加减便更为简单,如下公式的含义为 $t1 寄存器的值为 $t2 寄存器的值加上 $t3 寄存器的值。
add $t1, $t2, $t3
而如果需要在公式中包含数字,我们一般使用如下公式,含义为 $t1 寄存器的值为 $t2 寄存器的值加上 100。
addi 表示 add immediate(其实直接 add 也可以做到)。
addi $t1, $t2, 100
减法的使用方法相似,可以查看 MIPS 指令集进行学习,这里不再赘述。
乘法运算
在 MIPS 中,所有的寄存器都是 32 位的,所以两个 32 位的数相乘,显然就会乘出 64 位的结果,不可避免的就会出现溢出的情况。
如果不考虑溢出,那么乘法与上面的加减运算是完全一致的。(不过我们的实验不考虑乘法溢出的情况)
如果考虑溢出怎么做呢?
所以 MIPS 使用了两个寄存器 $hi(即 high)和 $lo(即 low)来存储乘法得到的结果。
mult $t1, $t2
上面这条指令执行之后,乘积的高 32 位就会被放到 $hi 寄存器,低 32 位就会被放到 $lo 寄存器。
需要使用 mfhi 指令 获得 $hi 寄存器里的内容, mflo 指令 获得 $lo 寄存器里的内容。
除法运算和模运算
对于除法运算,在 C 语言中,两个整数的除法是整除,例如 5 / 2 = 2。
而在 MIPS 中,除法是带有余数的,我们来看 MIPS 指令集中对于除法的描述:
商存放在 $lo 寄存器,而余数存放在 $hi 寄存器,我们需要使用 mfhi 指令 获得 $hi 寄存器里的内容, mflo 指令 获得 $lo 寄存器里的内容。
完整代码如下所示:
li $t1,5 # 被除数为 5
li $t2,2 # 除数为 2
div $t1, $t2 # 计算 5 / 2,其中商存放在 lo 寄存器,而余数存放在 hi 寄存器
mfhi $t3 # 将 hi 寄存器中的值取出放到 t3 寄存器(余数,值为 1)
mflo $t4 # 将 lo 寄存器中的值取出放到 t4 寄存器(商,值为 2)
输入输出
学习了最简单的几种指令后,我们来学习输入输出(scanf 和 printf)的方式,这一块是很重要的内容,也是一个小小的难点
众所周知,MIPS 中有很多的的寄存器,虽然大部分寄存器可以乱用(不是),但是有一些寄存器是有着自己独特的含义的,比如接下来要学习的 $v0 寄存器。
$v0 寄存器的值与 syscall(系统调用)是紧密联系在一起的,如果用非常非常非常大白话的方式来讲,就是 $v0 寄存器里的值决定了 syscall 是输入还是输出,输入(输出)的是数字还是字符/字符串,如下代码
li $v0, 5
syscall
这个代码的表面含义是,把 $v0 寄存器的值赋值为 5,然后进行系统调用,而其实际含义是读入一个整数,该整数的值被存储在 $v0寄存器中。或者你可以这么理解:$v0 寄存器为 5 决定了 syscall 为读入一个整数,并将读入的值存储在 $v0 寄存器中。
有同学会问,那我怎么知道 $v0 的值与 syscall 的值的对应关系呢?可以查询 MARS help。

点击 syscall,其中就有 $v0 值对应 syscall 的表格,比如第一排我可以这么理解:$v0 是 1,对应 syscall 是输出整数(print integer),输出的值是 $a0 寄存器内的值。是不是很简单?

终止程序
终止程序代码如下所示:
li $v0, 10
syscall
只要执行到上面的代码,程序就会停止运行。
第一个程序
学会了这些,我们就可以写一个最最简单的程序。
输入一个整数 n,输出 n + 1 的值。
MIPS 汇编代码如下:
li $v0, 5
syscall # 读入一个整数
addi $v0, $v0, 1 # 加 1
move $a0, $v0 # 把 v0 寄存器的值移到 a0
li $v0, 1
syscall # 输出 a0 寄存器的值
在保存后,我们点击 run-assemble

点击最大的绿色按钮

随便输入一个数 20,系统自动输出 21,是不是和我们预计的结果一样?

恭喜你,你已经学会了 MIPS 的基本使用方法了。