最近的MIPS感觉都是照猫画虎,写一篇做个笔记没准还能想明白点新东西,不知道咋用一定要经常打开指令集,这里MIPS指令集。
输入输出
重要的是这个syscall指令的用法,详见MIPS汇编语言syscall指令的用法。
因此在输入输出相应的类型时,要发出对应的指令,将常用的输入输出写在这备忘:
字符串
输出
.data
str: .asciiz"Hello Wolrd"
.text
la $a0,str
li $v0,4
syscall
参照上面的样例,我们就大致清楚了怎么对字符串进行输出,首先在.data区内开辟一个空间,在.text里面先需要把相应地址传送给寄存器$a0,然后通过调用$v0 = 4的指令将其输出。syscall($v0 = 4)指令:以$a0寄存器所存地址为首地址输出,直到遇上'\0'停止。
输入
.data
str: .space 1024
.text
li $t0,1
li $v0,12
syscall
sb $v0,str($t0) #存入str[1]
输入字符使用$v0 = 12,读入字符串则使用$v0 = 8。
TIPS:
- .asciiz.在读入字符串时会在最后加上'\0',而.ascii不会加'\0',两者都以字节为单位存储数据,data段进行变量声明是在内存中紧密有序存储的,所以.asciiz之后分配的空间首地址可能无法字对齐,因此定义.ascii与.asciiz时尽量写在最后面。
-
syscall($v0 = 8)指令代表:读入一个字符串,其中$a0表示读入的首地址,$a1表示读入的字符数n,与fget类似,会在读入的字符串最后加
'\n'
,因此实际上最多读入n-1个字符。
整数
输入使用syscall($v0 = 5),将读入的整数存在$v0中。输出使用syscall($v0 = 1),将寄存器$a0中的整数输出。
.text
li $v0,5
syscall
move $a0,$v0
li $v0,1
syscall
条件语句
单条件
if-else判断相等
if(i == j){
then do A;
}
else{
then do B;
}
MIPS使用beq实现
.text:
li $v0,5
syscall
move $t0,$v0
li $v0,5
syscall
move $t1,$v0
beq $t0,$t1,A
do B
j end
A:
do A
end:
li $v0,10
syscall
使用bne实现:
.text:
li $v0,5
syscall
move $t0,$v0
li $v0,5
syscall
move $t1,$v0
bne $t0,$t1,else
do A
j end
else:
do B
end:
li $v0,10
syscall
与0比较的if-else
if(a <= 0){
then do A;
}
else{
do B;
}
MIPS实现:
.text
li $v0,5
syscall
move $t0,$v0
bgtz $t0,else
do A
j end
else:
do B
end:
li $v0,10
syscall
非0值比较if-else
使用slt使其转化为与0比较的if-else,若条件中含=则按条件取反。
初始条件 | slt | $t2所代表含义 | beq/bne |
---|---|---|---|
i < j | slt $t2,$t0,$t1 | 0:初始条件为假 1:初始条件为真 | beq $t2,$0,else |
i > j | slt $t2,$t1,$t0 | 0:初始条件为假 1:初始条件为真 | beq $t2,$0,else |
i <= j | slt $t2,$t1,$t0 | 0:初始条件为真 1:初始条件为假 | beq $t2,$0,else |
i >= j | slt $t2,$t0,$t1 | 0:初始条件为真 1:初始条件为假 | beq $t2,$0,else |
.text
li $v0,5
syscall
move $t0,$v0
li $v0,5
syscall
move $t1,$v0
slt $t2,$t1,$t0
bne $t2,$0,else
do A
j end
else:
do B
end:
li $v0,10
syscall
多条件
&&
可以先判断第一个条件,若不成立直接跳转else,否则判断第二个条件。
.text
li $v0,5
syscall
move $t0,$v0
li $v0,5
syscall
move $t1,$v0
li $v0,5
syscall
move $t2,$v0
li $v0,5
syscall
move $t3,$v0
slt $t4,$t0,$t1
beq $t4,$0,beq
slt $t4,$t2,$t3
beq $t4,$0,beq
do A
j end
else:
do B
end:
li $v0,10
syscall
||
两个条件判断后进行一次或运算再判断是否跳转
.text
li $v0,5
syscall
move $t0,$v0
li $v0,5
syscall
move $t1,$v0
li $v0,5
syscall
move $t2,$v0
li $v0,5
syscall
move $t3,$v0
slt $t4,$t0,$t1
slt $t5,$t2,$t3
or $t4,$t4,$t5
beq $t4,$1,else
do A
j end
else:
do B
end:
li $v0,10
syscall
循环语句
.text
li $v0,5
syscall
move $s0,$v0
li $v0,5
syscall
move $s1,$v0
li $t0,0
for_loopi:
beq $t0,$s0,end_loopi
li $t1,0
for_loopj:
beq $t1,$s1,end_loopj
do loop
addi $t1,$t1,1
j forloopj
end_loopj:
addi $t0,$t0,1
j for_loopi
end_loopi:
li $v0,10
syscall
一维数组的使用
字符数组
.data
str: .space 1024
.text
#set
li $v0,12
syscall
sb $v0,str($t0)
#get
lb $t1,str($t0)
整型数组
.data
a: .space200 #a[50]
.text
#set
sll $t1,$t0,2
sw $v0,a($t1)
#get
sll $t1,$t0,2
lb $t2,a($t1)
二维数组的使用
#使用宏
.macro getindex(%ans,%i,%j)
sll %ans,%i,3
add %ans,%ans,%j
sll %ans,%ans,2
.end_macro
.data
a: .space 256 #int a[8][8]
.text
#save $t0 = i,$t1 = j
li $v0,5
syscall
getindex($t2,$t0,$t1)
sw $v0,a($t2)
#get
getindex($t2,$t0,$t1)
lw $s0,a($t2)
宏定义
.macro 函数名(参数)
.end_macro
#scanf函数示例
.macro scanf(%x)
li $v0,5
syscall
move %x,$v0
.end_macro
递归函数
按C语言一步一步翻译,递归的时候注意要把$ra和函数的参数压栈,如func_name(n + 1)对应:
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 #下一层函数运行都return(jr $31)时将回到这一层
addi $sp,$sp,4
lw $t0,0($sp) #读回这一层的参数
addi $sp,$sp,4
lw $ra,0($sp) #读回这一层的$ra
今天就复习到这里,这就去看刘老师的ppt做作业