标签: MIPS汇编 汇编语言 编程语言 快速入门 转载翻译
原文
MIPS汇编快速入门
数据类型
使用定长指令,所有指令都是32位长的
2.1字节=8位,半字长=2个字节(32位),1字长=4个字节
3.一个字符空间=1个字节
4.一个整形=一个字长=4个字节
5.单个字符用单引号
6.字符串用双引号
寄存器
- MIPS下一共有32个通用寄存器
- 在汇编中,寄存器标志以$开头
- 寄存器表示可以有两种方式:
1.直接使用该寄存器对应的编号,例如:从$0到$31
2.使用对应的寄存器名称,例如 t1, t 1 , sp,详见下文
对于乘法和除法分别有对应的两个寄存器 lo, l o , hi - 对于以上两者,不存在直接寻址,必须通过mfhi(“move from hi”)和mflo(“move from lo”)分别来进行访问对应的内容。
- 栈的走向是从高地址向低地址
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( g p | ( G l o b a l P o i n t e r 简 写 ) 指 向 64 k ( 2^{16}$)大小的静态数据块的中间地址 | |
29 | $sp | (Stack Pointer简写)栈指针,指向栈顶 |
30 | $s8/$fp | (Save / Frame Pointer)帧指针 |
31 | $ra | 返回地址,目测不可用作其他用途 |
程序结构
本质就是数据声明+普通文本+程序编码(文件后缀为.s或.asm)
数据声明在代码段之后(在之前也没什么问题)
数据声明
- 数据段以.data为开始标志
- 声明变量后,即在主存中分配空间
代码
- 代码段以.text为开始标志
- 其实就是各项指令操作
- 程序入门为main:标志
- 程序结束标志(见下文)
注释
同C系语言
基本模板
# Comment giving name of program and description of function
# 说明下程序的目的和作用(其实和高级语言都差不多了)
#
#Bare-bones outline of MIPS assembly language program
.data # variable declarations follow this line
# 数据变量声明
# ...
.text # instructions follow this line
# 代码段部分
main: # indicates start of code (first instruction to execute)
# 主程序
# ...
# End of program, leave a blank line afterwards to make SPIM happy
# 必须多给你一行,你才欢?
数据声明
声明的格式:
变量名:(冒号不可缺少) 数据类型 变量值
通常给变量赋一个初始值,对于.space,需要指明需要多少大小空间(bytes)
加载/保存 指令集
- 如果要访问内存,只能够使用load/store指令
- 其他的只能是寄存器操作
load
lw
lw register_destination, RAM_source
从内存中复制RAM_source的内容到对应的寄存器中(w意味word,即该数据大小为4个字节)
lb
lb register_destination, RAM_source
同上,lb为load byte
store
sw
sw register_source, RAM_destination
指将指定寄存器中的数据写入到特定的内存中
sb
sb register_source, RAM_destination
同lb
load immediate
li
li register_destination, value
顾名思义,加载立即数
立即与间接寻址
la (load address 直接给地址)
例如la $to,var1
表示的是将var1中的内存地址塞入$to中
间接寻址
地址是寄存器的内容(也可以理解为指针) lw $t2,($t0)
load word at RAM address contained in $t0 into $t2 sw $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 $t0 sw $t2,-12($t0)
store word in register $t2 into RAM at address ($t0 - 12),negative offsets are fine
算术指令集
- 最多三个操作数
- 操作数只能是寄存器,不允许出现地址
- 所有指令统一是32位
add $t0,$t1,$t2 # $t0 = $t1 + $t2; add as signed (2's complement) integers
sub $t2,$t3,$t4 # $t2 = $t3 Ð $t4
addi $t2,$t3, 5 # $t2 = $t3 + 5; "add immediate" (no sub immediate)
addu $t1,$t6,$t7 # $t1 = $t6 + $t7; add as unsigned integers
subu $t1,$t6,$t7 # $t1 = $t6 + $t7; subtract as unsigned integers
mult $t3,$t4 # multiply 32-bit quantities in $t3 and $t4, and store 64-bit
# result in special registers Lo and Hi: (Hi,Lo) = $t3 * $t4
运算结果存储在hi,lo(hi高位数据, lo低位数据)
div $t5,$t6 # Lo = $t5 / $t6 (integer quotient)
# Hi = $t5 mod $t6 (remainder)
商数存放在 lo, 余数存放在 hi
mfhi $t0 # move quantity in special register Hi to $t0: $t0 = Hi
不能直接获取 hi 或 lo中的值, 需要mfhi, mflo指令传值给寄存器
mflo $t1 # move quantity in special register Lo to $t1: $t1 = Lo
# used to get at result of product or quotient
move $t2,$t3 # $t2 = $t3
控制流
分支(if else系列)
b target # unconditional branch to program label target
beq $t0,$t1,target # branch to target if $t0 = $t1
blt $t0,$t1,target # branch to target if $t0 < $t1
ble $t0,$t1,target # branch to target if $t0 <= $t1
bgt $t0,$t1,target # branch to target if $t0 > $t1
bge $t0,$t1,target # branch to target if $t0 >= $t1
bne $t0,$t1,target # branch to target if $t0 <> $t1
跳转(while,for,goto系列)
j target # unconditional jump to program label target
看到就跳, 不用考虑任何条件
jr $t3 # jump to address contained in $t3 ("jump register")
类似相对寻址,跳到该寄存器给出的地址处
子程序调用
jal sub_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.