MIPS小总结

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表示读入的首地址, a0a1表示读入的字符数n,与fget类似,会在读入的字符串最后加'\n',因此实际上最多读入n-1个字符

syscall($v0=12)

读入一个字符,将读入的字符存在$v0中。

.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中

输出

使用syscall( v 0 = 1 ) , 将 v0=1),将 v0=1)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语言差不多的写法(老菜鸡行为)。

	#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 t 0 = i , t0=i, t0=i,t1=j,$t2为保存slt结果的寄存器)

初始条件 slt $t2所代表的含义 beq/bne
i 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

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

更多层的就把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)
	
	

你可能感兴趣的:(计算机组成原理,MIPS,java,正则表达式,字符串)