MIPS汇编语言编程
MIPS下各个寄存器编号及描述
寄存器编号 | 寄存器名 | 寄存器用途 | ||
---|---|---|---|---|
0 | zero | 永远返回0 | ||
1 | $at | 汇编保留寄存器(不可用作其他用途) | ||
2-3 | $v0-$v1 | (value的简写)存储表达式或者函数的返回值 | ||
4-7 | $a0-$a3 | (Argument简写)存储子程序的前4个参数,在子程序调用过程中释放 | ||
8-15 | $t0-$t7 | (temp简写)临时变量,同上调用时不保存 | ||
16-23 | $s0-$s7 | (Save or Static简写?)静态变量?调用时保存 | ||
24-25 | $t8-$t9 | (Temp简写)算是前面$0-$7的继续,属性同$t0-$t7 | ||
26-27 | $k0-$k1 | (break off简写?)中断函数返回值,不可做其他用途 | ||
28 | gp\ | (GlobalPointer简写)指向64k(gp\ | (GlobalPointer简写)指向64k(2^{16}$)大小的静态数据块的中间地址 | |
29 | $sp | (Stack Pointer简写)栈指针,指向栈顶 | ||
30 | $s8/$fp | (Save / Frame Pointer)帧指针 | ||
31 | $ra | 返回地址,目测不可用作其他用途 |
程序结构
数据声明 + 普通文本 + 程序编码(文件后缀是 .s 或 .asm)
数据声明在代码段之后(在之前也没什么问题)
数据
- 数据段以
.data
为开始标志 - 声明变量后,即在主存中分配空间
代码
- 代码段以
.text
为开始标志 - 各项指令操作
- 程序入口标志:
main:
- 程序结束标志
注释
同C系语言。
基本模板:
1 | # Comment giving name of program and description of function |
数据声明
声明的格式:
1 | 变量名: 数据类型 变量值 |
冒号不可缺少。
通常给变量赋一个初始值,对于 .space
,要指明需要多少大小的空间(bytes)。
加载/保存 指令集
- 如果要访问内存,只能使用
load/store
指令 - 其他的只能是寄存器操作
load
lw
lw register_dest, RAM_src
从内存中复制RAM_src的内容到对应的寄存器中(w即word,一个字长,4个字节,因此该数据大小为4个字节)
lb
lb register_dest, RAM_src
同上,lb为load byte.
store
sw
sw register_src, RAM_dest
指将指定寄存器中的数据写入到特定的内存中。
sb
sb register_src, RAM_dest
同上,但数据大小为1字节。
load imm
li
li register_dest, value
加载立即数。
立即与间接寻址
la
Load address 直接给地址
例如,la $t0, var1
将 var1 (表示的是内存地址)放到 $t0 中。
如果变量var1不是内存地址,就成 li
指令了。
间接寻址
lw
: 寄存器中存储的是内存地址,需要访问该内存地址得到数据再放到目的寄存器中。
lw $t2,($t0)
load word at RAM address contained in $t0 into $t2sw $t2,($t0)
store word in register $t2 into RAM at address contained in $t0
加偏移量
lw $t2,4($t0)
load word at RAM address ($t0+4) into register $t2, ”4” gives offset from address in register $t0sw $t2,-12($t0)
store word in register $t2 into RAM at address ($t0 - 12),negative offsets are fine
算术指令集
- 最多3个操作数
- 操作数只能是寄存器,不允许出现地址
- 所有指令统一是32位
1 | add $t0,$t1,$t2 # $t0 = $t1 + $t2; add as signed (2's complement) integers |
控制流
分支(if else系列)
1 | b target # unconditional branch to program label target |
跳转(while, for, goto系列)
1 | j target # unconditional jump to program label target |
子程序调用
1 | jal sun_label # "jump and link" |
将当前程序计数器保存在 $ra
中,通过上面保存在 $ra
中的计数器返回到调用前。
如果调用的子程序中有调用了其他的子程序,如此往复,则返回地址的标记就用栈来存储。
系统调用与输入/输出(主要针对SPIM模拟器)
- 使用syscall,以下指令应该是通用的。
- 参数使用的寄存器:
$v0, $a0, $a1
. - 返回值使用:
$v0
.
Service | Code in $v0 对应功能的调用码 | Arguemnts 所需参数 | Results 返回值 |
---|---|---|---|
打印一个整型 | $v0=1 | 将要打印的整型赋值给$a0 | |
打印一个浮点数 | $v0=2 | 将要打印的浮点数赋值给$f12 | |
打印双精度浮点数 | $v0=3 | 将要打印的双精度浮点数赋值给$f12 | |
打印字符串 | $v0=4 | 将要打印的字符串的地址赋值给$a0 | |
读取一个整型 | $v0=5 | 将读取的整型赋值给$v0 | |
读取浮点数 | $v0=6 | 将读取的浮点数赋值给$v0 | |
读取双精度浮点数 | $v0=7 | 将读取的双精度浮点数赋值给$v0 | |
读取字符串 | $v0=8 | 将读取字符串地址赋值给$a0,将读取字符串的长度赋值给$a1 | |
sbrk(应该同C中的sbrk()函数一样) 动态分配内存 | $v0=9 | $a0=amount 需要分配的空间大小,单位目测是字节 | 将分配好的空间首地址给$a0 |
退出 | \v0=10 | 退出 |
- 打印的字符串应该有一个终止符(‘\0’),声明字符串为
.asciiz
类型即可。 - 对于读取整型,浮点数,双精度浮点数等数据操作,系统会读取一整行(以’\n’为结束)
- 读取字符串时,输入过长就截短,短了不补,最后会加上终止符
- The sbrk service returns the address to a block of memory containing n additional bytes. This would be used for dynamic memory allocation.
在MIPS程序中,指令一般从地址0x00400000开始存储。MIPS存储器地址是字节寻址,所以32位(4字节)指令地址每次增加4字节而不是1字节。
机器代码就是指令。汇编代码是汇编代码。
处理器从存储器中顺序地取出指令。数字电路硬件解码和执行这些指令。当前指令的地址存储在程序计数器(一个32位寄存器)中。
操作系统将PC的值设为地址0x00400000。处理器将位于这个地址的指令读出并执行机器代码。然后,处理器将PC增加4,变为0x00400000,接着取出该地址的指令并执行,以此类推。
微处理器的体系结构状态(architectural state)保存程序的状态。对于MIPS,体系结构状态由寄存器文件和PC组成。
分支
为了顺序执行指令,程序计数器执行一条指令后增4。分支(branch)指令改变程序计数器的值,跳过某段代码或返回到执行先前的代码。
本文作者 : preccrep
原文链接 : https://preccrep.github.io/2021/06/13/MIPS%E6%B1%87%E7%BC%96%E8%AF%AD%E8%A8%80%E7%BC%96%E7%A8%8B/
版权声明 : 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!