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)