[TOC]

原文

MIPS汇编快速入门

数据类型

1.MIPS使用定长指令,所有指令都是32位长的 2.1字节=8位,半字长=2个字节(32位),1字长=4个字节 3.一个字符空间=1个字节 4.一个整形=一个字长=4个字节 5.单个字符用单引号 6.字符串用双引号

寄存器

  • MIPS下一共有32个通用寄存器
  • 在汇编中,寄存器标志以$开头
  • 寄存器表示可以有两种方式: 1.直接使用该寄存器对应的编号,例如:从\$0到\$31 2.使用对应的寄存器名称,例如$t1,$sp,详见下文 对于乘法和除法分别有对应的两个寄存器$lo,$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 (Global Pointer简写)指向64k($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
# 说明下程序的目的和作用(其实和高级语言都差不多了)
# Template.s
#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.