标签:
MIPS 是一种汇编语言
汇编语言不像 C 、Java, 其没有 variables,它的 operands 只有 registers
MIPS 一共有 32 个 registers (每个 register 都是 32 bits)
先介绍几个 register
$16 - $ 23 一般命名为 $s0 - $s7
$8 - $15 一般命名为 $t0 - $t7
MIPS 加减操作
add $s0, $1, $s2 # MIPS a = b + c # C sub $s3, $s4, $s5 # MIPS d = e - f # C
由于 一条指令的操作数有限, 一条C语句可能会分成好几条 MIPS 语句
a = b + c + d - e # C add $t0, $s1, $s2 # temp = b + c add $t0, $t0, $s3 # temp = temp + d sub $s0, $t0, $s4 # a = temp - e
由于常数经常出现, 所有常数可以直接表示(叫做 Immediate)
addi $s0, $s1, 10; # 注意为 addi a = b + 10;
由于 0 的使用更加频繁(比如 a = b, 其实就是 a = b + 0), 所以有一个 register 特别的被设定为 0
add $s0, $s1, $zero
在 MIPS 中, 有符号数运算(add, addi, sub)会检测是否溢出,而无符号数运算(addu, addiu, subu)则不会检测
内存操作
从内存读取数据到寄存器
int A[100]; g = h + A[3]; lw $t0, 12($s3) add $1, $2, $t0
将寄存器数据写入内存
int A[100]; A[10] = h + A[3]; lw $to, 12($s3); # temp reg $t0 gets A[3] add $t0, $s2, $t0; # temp reg $t0 gets h + A[3] sw $t0, 40($s3); # send data in reg to A[10]
Note: $s3 为 base register(pointer); 12, 40 是 byte 的偏移量
$s3+12, $s3+40 必须是4的整数倍(因为是以 word(总线长度) 为单位读写内存的)
ps: 还有读取一个 byte 的指令(lb, sb), 格式类似
MIPS 逻辑运算指令
and 、or 、not 、sll 、srl ... (自己查表)
Instructions for Making Decisions
条件跳转
if - statement: 指令为:
beq reg1, reg2, L1
如果 reg1 的值与 reg2 的值相等, 就跳转到 Label 为 L1的语句, 否则就执行下一条语句
bne 与 beq 类似, 不过条件是 reg1 的值与 reg2 的值不等
无条件跳转
j L1
e.g
if (i==j) f = g + h; else f = g - h; bne $s3, $4, Else add $s0, $s1, $s2 j Exit Else: sub $s0, $s1, $s2 Exit:
还有一个 slt 指令
slt reg1, reg2, reg3
相当于如果 reg2 < reg3, 则reg1 = 1, 否则 reg1 = 0
这条指令配合前面的 beq、bne 指令, 就可以实现小于时跳转
if(g<h) Less; slt $t0, $s0, $s1 bne $t0, $zero, Less
对应的,针对无符号数有 sltu, Immediates 有 slti
MIPS Function
convention:
$a0 - $a3 : 参数的寄存器
$v0-$v1 : 返回值的寄存器
$ra : 返回调用前下一条指令的地址
要有这样一个概念, 写的一条条指令存储在内存的 text 段(每条指令占4个byte)
sum(a, b); // 调用 sum 函数 ... int sum(int x, int y) { // 定义在他处, 所以调用指令和定义指令的地址往往不连续 return x+y; } # 前面的数字是假设的内存地址 1000 add $a0, $s0, $zero 1004 add $a1, $s1, $zero 1008 addi $ra, $zero, 1016 # 因为调用结束后应该执行1016处的指令 1002 j sum # 跳转到 sum 1016 ... ... 2000 sum: add $v0, $a0, $a1 2004 jr $ra # 返回到 ra 指令处
现实中很难知道那条指令在内存何处, 所以上面 addi $ra, $zero, 1016 不现实, MIPS 有 一条 jump and link 指令 (jal)
before: 1008 addi $ra, $zero, 1016 1012 j sum; After: 1008 jal sum # 相当于 $ra=1012, 跳转到sum
还有一个问题, 函数调用时要设定一些寄存器的值为参数值, 如果之前那些寄存器已经有值且有意义时,该怎么办? A:将这些值压入stack,调用结束后再弹出 (MIPS中 $sp 寄存器 表示栈指针)
int sumSquare(intx, int y) { return mult(x, x) + y; } sumSquare: addi $sp, $sp, -8; // 改变栈指针 sw $ra, 4($sp) // 将 返回地址压入栈 sw $al, 0($sp) // 将 y 压入栈 add $al, a0, $zero jal mult lw $al, 0($sp) # 取出 y add $v0, $v0, $al lw $ra, 4($sp) # 取出返回地址 addi $sp, $sp, 8 # 恢复栈指针 jr $ra ... mult : ...
标签:
原文地址:http://www.cnblogs.com/whuyt/p/4808053.html