1. 汇编文件组成
在模拟器Mars中,MIPS汇编代码(以.asm格式存储)分为两部分
- 以.data开头后的若干行,存储.data数据,格式如下
.data
name1: .word 0x1,0x02...
name2: .word ...
.text
# 之后才是指令区
其中.word标明了格式,可选的还有.double、.ascii、.dwrd等格式分别对应浮点数存储,字符串存储和长整型存储。
在Mars中,默认的.data的起始位置是0x10010000,而默认的外部存储是从0x10000000(这也意味着.data定义的变量是可以被覆写的),而0x00400000 - 0x0ffffffc这一段存储的是指令字符集。要注意到这些地址的长度单位是byte,所以一般的以word为单位的数据(包括寄存器的大小)都是四个字节,所以无论读还是写,地址都应当是4的倍数。
.text之后可以编写指令,因为它们处于lw/sw不可达的区域,所以不会被轻易修改
2. 寄存器知识
基本寄存器介绍
MIPS有32个寄存器:
名称 | 寄存器号 | 用途 |
---|---|---|
$zero | 0 | 始终为0 |
$at | 1 | 为汇编保留,主要用于伪指令扩展 |
$v0-$v1 | 2-3 | 子程序的返回值 |
$a0-$a3 | 4-7 | 子程序调用参数 |
$t0-$t7 | 8-15 | 临时变量寄存器 |
$s0-$s7 | 16-23 | 变量寄存器(会保留一段时间) |
$t8-$t9 | 24-25 | 更多临时变量 |
$k0-$k1 | 26-27 | 操作系统核预留&错误返回 |
$gp | 28 | 全局指针 |
$sp | 29 | 栈指针 |
$fp | 30 | 帧指针 |
$ra | 31 | 返回地址寄存器 |
$t:主调保存寄存器,由主程序负责寄存器的数据安全,即在子程序中可以随便使用,如果寄存器内容的改变可能影响程序运行,由主程序负责将寄存器内容存入堆栈,在子程序返回时恢复。
$s:被调保存寄存器,有子程序负责寄存器数据安全,如果要修改,应由子程序存入堆栈,并在返回前恢复
$a:子程序调用参数,按顺序放置在其中供子程序调用,也作为syscall的参数,a系列寄存器应当是被调保存的
$v:子程序返回参数寄存器
调用子程序时,参数的保留与否决策:
保留 | 不保留 |
---|---|
保存寄存器$s | 临时寄存器$t |
栈指针寄存器$sp | 参数寄存器$a |
返回地址寄存器$ra | 返回值寄存器$v |
栈指针以上的栈 | 栈指针以下的栈 |
协处理器0
3. 指令系统
MIPS为等长指令,所有指令均为32位
rs,rt,rd为通用寄存器名,分别对应指令的25-21,20-16,15-11位
3.1 指令类型
- R类型
- I类型:注意观察立即数的表示确定立即数的含义
- J类型
- C类型:操作协处理器
其中协处理器9用于配合CPU工作,协处理器1为浮点处理器,mips中有4个处理器,因此用前六位的低两位表示协处理器号
3.2 指令格式
之后是可选的浮点数乘法:
若干注解:
- R类型指令与I类型指令中有些查了一个字母i,它代表着参与的数据从寄存器变成了立即数
- 后缀u代表了原指令基础上的无符号数值运算
- 后缀x代表了原指令基础上的小头模式运算与操作(默认为大头模式)
- srl/srlv与sra/srav的区别是前者是逻辑右移,始终补0,后者是算术右移,根据补码条件选择补0或补1
拾遗与杂记
- J指令操作的立即数的单位是字(因为指令的单位永远是字),而其中的立即数总共有26位,因而其可以表示28位长的绝对地址,当使用J指令时,如果使用绝对寻址方式,就将高4位设为PC的高4位,后28位由J指令提供的立即数决定。
- jr指令虽然也用于转移,但它是r类型,因为它提供的是一个寄存器(并且时常是$ra寄存器),从而让程序返回调用子程序处的正确位置,由于寄存器中存储的就是32位的数据,所以jr指令无需进行j指令那样的取位操作
- jal与j指令的唯一区别是在跳转之前,将下一条指令的PC地址赋值给$ra寄存器,j是一种无条件跳转的指令,而jal则是以比较明显的方法声明子程序调用的结构。
- j/jr与jal/jalr关系类似,左右两边都分别代表使用立即数或寄存器,同样地,jalr也是R类型的指令
- 所有为寄存器赋值的指令都存在一个问题:能够表示的立即数(一般是16位,更高者类似)可能小于需要的立即数(例如为32位寄存器赋值时,如果最高非零位大于16,1条i类型指令就无法满足要求)。此时使用lui+ori的组合:
# 要达到 li $t0,0x11112222的效果
lui $t0,0x1111
ori $t0,0x2222
特殊的协处理器(C)类型指令
- mfc0:从协处理器0的寄存器中读取数据(move from coprocessor0)
其中传入的最后一个参数必须是EPC,STATUS和PAUSE三个协处理器寄存器中的一个 - mtc0:向协处理器0的寄存器中写数据(move to coprocessor0)
与协处理器对应的R类型的指令
-
eret:中断返回(在Mars中解释为return with error)
程序将以非正常模式返回,会进行一次STATUS &= ~INTmsk
的操作,大概是更正状态码 -
syscall:中断调用
根据功能号($v0)对输入参数($a0)进行相应操作,对应表格如下
可以看到,syscall是系统调用标准/文件I/O的接口。
4. 伪指令
伪指令功能比较简单,是若干条简单指令形成的一条扩展功能的指令。下表提供的伪指令与Mars模拟器能够实现的伪指令有部分偏差
其中,push,pop,shi,shix,inc,dec,swap,beqi,bnei在Mars当中不支持