MIPS
读入输出
字符串
输出
.ascii
与.asciiz
.ascii
不会在字符串后加上'\0'
,而.asciiz
会在字符串加'\0'
。二者均以字节为单位存储数据,这会对咱们带来一些小麻烦,.asciiz
以后分配的空间首地址有可能没法字对齐,所以咱们在定义.ascii
与.asciiz
时尽可能写在最后面数组
#正确写法 .data array_int: .space 28 space: .asciiz " " #错误示范 .data space: .asciiz " " array_int: .space 28 #因为.data后面的变量声明在内存中是紧密有序存储的,因此后面获取array的地址时会报错“fetch address not aligned on word boundary 0x00000002”
syscall($v0=4)
以$a0寄存器所存地址为首地址输出,直到赶上'\0'
中止函数
#输出一个空格并换行 .data space: .asciiz " " enter: .asciiz "\n" .text la $a0,space #将space的首地址传给$a0 li $v0,4 syscall la $a0,enter #将enter的首地址传给$a0 li $v0,4 syscall
读入
syscall($v0=8)
读入一个字符串,其中 a 0 表 示 读 入 的 首 地 址 , a0表示读入的首地址, a0表示读入的首地址,a1表示读入的字符数n,与fget相似,会在读入的字符串最后加'\n'
,所以实际上最多读入n-1个字符oop
syscall($v0=12)
读入一个字符,将读入的字符存在$v0中。fetch
.data str: .space 20 .text #$t0 = i li $v0,12 syscall sb $v0,str($t0) # 将读入的字符存在str[i]中(sb指令仅将寄存器的低8位保存)
整数
读入
使用syscall( v 0 = 5 ) , 将 读 入 的 整 数 存 在 v0=5),将读入的整数存在 v0=5),将读入的整数存在v0中spa
输出
使用syscall( v 0 = 5 ) , 将 v0=5),将 v0=5),将a0中的整数输出翻译
条件语句
单条件
相等条件if-else
if(i==j){ THEN语句块 }else{ ELSE语句块 }
- 用beq
#t0=i,t1=j beq $t0,$t1,then #若i==j,那么跳到THEN语句块,不相等则进行运行下一条语句,即ELSE语句块 ELSE语句块 j end #不跳转到end的话将继续运行THEN语句块 then: THEN语句块 end:
- 用bne
该写法与C的THEN与ELSE块顺序同样,因此我通常都是将if中的条件取反后用转移指令,这样就保持了与c语言差很少的写法(老菜鸡行为)。code
#t0=i,t1=j bne $t0,$t1,else #若i!=j,那么跳到ELSE语句块,相等则进行运行下一条语句,即THEN语句块 THEN语句块 j end #不跳转到end的话将继续运行ELSE语句块 else: ELSE语句块 end:
与0比较的if-else
使用bxxx rs,label。(同理我为了保持与c语言同样的写法,将条件取反后再找指令)递归
if(a<=0){ THEN块 }else{ ELSE块 }
#$t0=a bgtz $t0,else #当a>0时跳转 THEN块 j end else: ELSE块 end:
非0值比较的if-else
使用slt使其转化为与0比较的if-else,若条件中含=号,则将条件取反(如条件为i<=j,那么slt判断的为j<i)。下面列表表示( t 0 = i , t0=i, t0=i,t1=j,$t2为保存slt结果的寄存器)内存
初始条件 | slt | $t2所表明的含义 | beq/bne |
---|---|---|---|
i<j | slt t 2 , t2, t2,t0,$t1 | 0:初始条件为假 1:初始条件为真 | beq $t2,$0,else |
i>j | slt t 2 , t2, t2,t1,$t0 | 0:初始条件为假 1:初始条件为真 | beq $t2,$0,else |
i<=j | slt t 2 , t2, t2,t1,$t0 | 0:初始条件为真 1:初始条件为假 | bne $t2,$0,else |
i>=j | slt t 2 , t2, t2,t0,$t1 | 0:初始条件为真 1:初始条件为假 | bne $t2,$0,else |
(注:均为了保持与c语言顺序一致,只写了该写法的beq/bne,事实上i<j的beq/bne也能够写为bne $t2,$0,then,可是这种写法的THEN块与ELSE块与c语言的顺序相反)ci
eg:i<=j,将上表格的对应的slt和beq/bne复制便可
if(i<=j){ THEN块 }else{ ELSE块 }
#$t0=i,$t1=j slt $t2,$t1,$t0 bne $t2,$0,else THEN块 j end else: ELSE块 end:
多条件
&&
能够先判断第一个条件,若不成立直接跳至else,不然判断第2个条件。
if(a<b&&i<j){ THEN块 }else{ ELSE块 }
# $t0=a,$t1=b,$t2=i,$t3=j slt $t4,$t0,$t1 beq $t4,$0,else#判断条件1 slt $t4,$t3,$t2 beq $t4,$0,else#判断条件2 THEN块 j end else: ELSE块 end:
||
不能判断了第1个条件就跳转,应该将两个条件得出的结果作一次或运算,再判断是否跳转。
循环语句
c语言: MIPS: for(i=0;i<n;i++) li $t0,0 # 赋值i=0 { for_loop: beq $t0,$s0,end_loop # $s0=n loop语句块 loop语句块 addi $t0,$t0,1 } j for_loop end_loop:
更多层的就把loop语句块换成下一层的循环便可。
for(i=0;i<n;i++) { for(j=0;j<m;j++) { loop块 } }
# 为了把层次看的更清楚,这里采用了不一样的缩进表明不一样的循环 li $t0,0 #i=0 for_loopi: beq $t0,$s0,end_loopi li $t1,0 #j=0 for_loopj: beq $t1,$s1,end_loopj loop语句块 addi $t1,$t1,1 j for_loopj end_loopj: addi $t0,$t0,1 j for_loopi end_loopi:
一维数组的使用
字符数组
声明
[name]: .space [n]
eg:str: .space 20
使用
- set
li $v0,12 syscall sb $v0,str($t0) # 读入一个字符并存到str[i]
- get
lb $t2,str($t0) #将str[i]读入寄存器$t2
整型数组
声明
[name]: .space [n]
其中n应为4*数组大小
eg:a .space 200
至关于int a[50]
使用
- set
sll $t1,$t0,2 #必定记得地址是i*4 sw $v0,a($t1) # 读入一个字符并存到a[i]
- get
sll $t1,$t0,2 lb $t2,a($t1) #将a[i]读入寄存器$t2
二维数组的使用
声明
.data a: .space 256 # int a[8][8]
使用
#使用宏来简化 .macro getindex(%ans,%i,%j) sll %ans,%i,3 # %ans=%i*8,若不是8*8的二维数组,如是10*10的,那么这条指令应改成mul %ans,%i,10 add %ans,%ans,%j # %ans=%ans+%j sll %ans,%ans,2 # %ans=%ans*4 .end_macro .text #$t0=i,$t1=j #存数组操做: li $v0,5 syscall getindex($t2,$t0,$t1) sw $v0,a($t2) #将读入的整数存入a[i][j] #读数组操做: getindex($t2,$t0,$t1) lw $s0,a($t2) #将a[i][j]的值存至$s0
递归函数
按c语言一步一步翻译就能够,递归调用的时候把$ra和函数的参数压栈便可。如c语言中func_name(n+1);
这一条语句就对应MIPS里的
sw $ra,0($sp) #存$ra subi $sp,$sp,4 sw $t0,0($sp) #存这一层函数的参数 subi $sp,$sp,4 addi $t1,$t0,1 #将n+1存入$t1 move $a0,$t1 #传值 jal factorial #下一层函数的参数即是n+1了,当下一层函数运行到return(jr $31)时将回到这一层 addi $sp,$sp,4 lw $t0,0($sp) #读回这一层的参数 addi $sp,$sp,4 lw $ra,0($sp) #读回这一层的$ra
下面看一个求阶乘的递归问题。
int factorial(int n) { if(n==1) return 1; else return n*factorial(n-1); } int main() { int n; scanf("%d",&n); printf("%d",factorial(n)); return 0; }
main: #int main() li $v0, 5 syscall move $s0,$v0 #scanf("%d",&n); move $a0,$s0 #让$a0=n,传入参数 jal factorial #factorial(n); move $a0,$v0 li $v0,1 syscall #printf(); li $v0,10 syscall #return 0; factorial: #int factorial (int n) bne $a0,1,else #if(n==1){ li $v0,1 #return 1; jr $31 #} else: #else{ move $t0,$a0 ########### sw $ra,0($sp) subi $sp,$sp,4 sw $t0,0($sp) subi $sp,$sp,4 #要压入栈的东西:$ra和递归函数的参数 subi $t1,$t0,1 move $a0,$t1 #这一大段等价于factorial(n-1) jal factorial addi $sp,$sp,4 lw $t0,0($sp) addi $sp,$sp,4 lw $ra,0($sp) #将$ra和这层的参数读回 ############ mult $t0,$v0 mflo $v0 jr $31 #return n*factorial(n-1)