MIPS入门

Instructions are all 32 bits
byte(8 bits), halfword (2 bytes), word (4 bytes)
a character requires 1 byte of storage
an integer requires 1 word (4 bytes) of storage

本质是数据声明+普通文本+程序编码
数据声明:
- 数据段以 .data为开始标志
- 声明变量后,即在主存中分配空间。
代码:
- 代码段以 .text为开始标志
- 各项指令操作
- 程序入口为main:标志
- 程序结束标志(详见下文)
注释:
- 使用#

数据声明

1
name:  storage_type	 value(s)

通常给变量赋一个初始值;对于**.space**,需要指明需要多少大小空间(bytes)

读取/写入 指令集

  • 要访问内存只能用 load 或者 store 指令
  • 其他的只能都一律是寄存器操作
load
1
lw	register_destination, RAM_source

从内存中 复制 RAM_source 的内容到 register_destination 中
(lw中的’w’意为’word’,即该数据大小为4个字节)

1
lb	register_destination, RAM_source

同上, lb 意为 load byte

store
1
sw	register_source, RAM_destination

将指定寄存器中的数据 写入 到指定的内存中

1
sb	register_source, RAM_destination
load immediate
1
li	register_destination, value

将 immediate value 载入 register_destination 中

1
2
3
4
5
6
7
8
9
10
11
12
example: 
.data
var1: .word 23 # declare storage for var1; initial value is 23
.text
__start:
lw $t0, var1
# load contents of RAM location into register $t0: $t0 = var1
li $t1, 5
# $t1 = 5 ("load immediate")
sw $t1, var1
# store contents of register $t1 into RAM: var1 = $t1
done
load address

直接给地址

1
la	$t0, var1
  • copy RAM address of var1 (presumably a label defined in the program) into register $t0
indirect addressing
1
lw	$t2, ($t0)
  • load word at RAM address contained in $t0 into $t2
    1
    sw	$t2, ($t0)
  • store word in register $t2 into RAM at address contained in $t0
based or indexed addressing
1
lw $t2, 4($t0)

• load word at RAM address ($t0+4) into register $t2
• “4” gives offset from address in register $t0

1
sw $t2, -12($t0)

• store word in register $t2 into RAM at address ($t0 - 12)
• negative offsets are fine

Note: based addressing is especially useful for:
• arrays; access elements as offset from base address
• stacks; easy to access elements at offset from stack pointer or frame pointer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
	.data
array1: .space 12
# declare 12 bytes of storage to hold array of 3 integers
.text
__start:
la $t0, array1
li $t1, 5
sw $t1, ($t0)
# first array element set to 5; indirect addressing
li $t1, 13
sw $t1, 4($t0)
# second array element set to 13
li $t1, -1
sw $t1, 8($t0)
# third array element set to -7
done

算术指令集

  • 最多3个操作数
  • 操作数只能是寄存器,绝对不允许出现地址
  • 所有指令统一是32位 = 4*8 bit = 4bytes = 1 word
add
1
add $t0,$t1,$t2

$t0 = $t1 + $t2 add as signed (2’s complement) integers

1
addi $t2,$t3, 5

$t2 = $t3 + 5 “add immediate” (no sub immediate)

1
addu $t1,$t6,$t7

$t1 = $t6 + $t7 add as unsigned integers

sub
1
sub $t2,$t3,$t4

$t2 = $t3 - $t4

1
subu $t1,$t6,$t7

$t1 = $t6 - $t7 subtract as unsigned integers

mult
1
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

div
1
div $t5,$t6

Lo = $t5 / $t6 (integer quotient)
Hi = $t5 mod $t6 (remainder)

mfhi/mflo
1
mfhi $t0

move quantity in special register Hi to $t0: $t0 = Hi

1
mflo $t1

move quantity in special register Lo to $t1: $t1 = Lo

used to get at result of product or quotient

1
move $t2,$t3

$t2 = $t3

控制流

Branches
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
Jumps
1
2
j  target  
# unconditional jump to program label target

看到就跳, 不用考虑任何条件

1
2
jr  $t3  
# jump to address contained in $t3 ("jump register")

类似相对寻址,跳到该寄存器给出的地址处

Subroutine Calls
1
2
jal sub_label 
# "jump and link"

• copy program counter (return address) to register $ra (return address register)
• jump to program statement at sub_label

1
jr $ra # "jump register"

• jump to return address in $ra (stored by jal instruction)
Note :
return address stored in register $ra; if subroutine will call other subroutines, or is recursive, return address should be copied from $ra onto stack to preserve it, since jal always places return address in this register and hence will overwrite previous value
如果说调用的子程序中有调用了其他子程序,如此往复, 则返回地址的标记就用 栈(stack) 来存储, 毕竟 $ra 只有一个

System Calls and I/O

  • 通过系统调用实现终端的输入输出,以及声明程序结束
  • 学会使用 syscall
  • 参数所使用的寄存器:$v0, $a0,  $a1
  • 返回值使用: $v0
Service Code in $v0 Arguments Results
print_int $v0 = 1 $a0 = integer to be printed
print_float $v0 = 2 $f12 = float to be printed
print_double $v0 = 3 $f12 = double to be printed
print_string $v0 = 4 $a0 = address of string in memory
read_int $v0 = 5 integer returned in $v0
read_float $v0 = 6 float returned in $v0
read_double $v0 = 7 double returned in $v0
read_string $v0 = 8 $a0 = memory address of string input buffer
$a1 = length of string buffer (n)
sbrk $v0 = 9 $a0 = amount address in $v0
exit $v0 =10
  • .ascii 与 .asciiz唯一区别就是 后者会在字符串最后自动加上一个终止符 ‘\0’
    • 对于读取整型, 浮点型,双精度的数据操作, 系统会读取一整行(也就是说以换行符为标志 ‘\n’)
  • sbrk服务将地址返回到包含n个额外字节的内存块。用于动态内存分配。
    1
    2
    3
    4
    5
    6
    打印一个存储在寄存器 $2 里的整型
    li $v0, 1
    #声明需要调用的操作代码为 1 (print_int) 并赋值给 $v0
    move $a0, $t2
    #将要打印的整型赋值给 $a0
    syscall
    1
    2
    3
    4
    5
    6
    读取一个数,并且存储到内存中的 int_value 变量中
    li $v0, 5
    syscall
    #从键盘输入的值返回寄存器$v0
    sw $v0, int_value
    #通过写入(store_word)指令将$v0的值(5)存入内存中
    1
    2
    3
    4
    5
    6
    7
    8
    9
    打印一个字符串
    .data
    string1 .asciiz "Print this.\n"
    .text
    main:
    li $v0, 4
    la $a0, string1
    #将要打印的字符串地址赋值 $a0 = address(string1)
    syscall
    1
    2
    3
    4
    执行到这里, 程序结束
    li $v0, 10
    # system call code for exit = 10
    syscall