前言
本文为博主在学习mips时的一些基本笔记(苦于计组实验需要用到mips,而全网对mips小白的基础教程是在太少,有也不全面),因为是全英文课程,所以索性笔记也用了英文来记(当然都是很通俗易懂初中英语水平就差不多能看懂了嗷),是油管博主Amell录制的mips基础视频(可以说是全网最最基础的mips教程了,各种变量、代码结构、循环、分支、数组、栈使用、递归都有涉及)
注意:本文知识点很全,但是比较适合已经理解mips基本常识的童鞋学习(因为是学习笔记嘛,博主也不可能事无巨细的把所有东西都记录一遍,纯小白可以直接看下面的mips学习视频,把我的笔记当做对照来用就行)
没有vpn的童鞋可以看下面这个,不过哔哩哔哩上少了最后一课时(二维数组的应用)
关于算法实现部分,之后会更新一些相关实例
让我康康有多少Buaaer👀
反汇编
这里提供一个反汇编的网站,可以把你的高级语言程序直接反汇编为mips,对理解mips中的栈思想非常有帮助,
也可以更好的理解变量等等在mips中是怎么传递的,理解$s0-$s7为什么被定义为需要恢复为原值的寄存器
反汇编
.data
存放在内存中的数据类型声明
frequent use syscall arguments
Code in $v0 | Service | notes(注意点) |
---|---|---|
1 | print integer in $a0 | - |
2 | print float in $f12 | - |
3 | print double in $f12 | - |
4 | print string(across address) in $a0 | - |
5 | read integer into $v0 | - |
6 | read float into $f0 | - |
7 | read double into $f0(exactly saved in $f0 and in $f1) | - |
8 | $a0 = address of input buffer,$a1 = maximum number of characters to read | if $a0==n,so the max number input is n-1,because the final character is ‘\0’,and if n==1,input is ignored and null byte placed at buffer address. If n<1, input is ignored and nothing is written to the buffer. (what’s more,’\n’ will be read) |
10 | exit the whole programm | - |
type
char
.data # 数据声明区域
# name: .type values
char: .byte 'M' # 将一个字符保存在一个字节的存储空间里
endline: .byte '\n' # 常用,换行符
# 记得字符要使用单引号声明
.text # 代码区域
main:
li $v0 4 # 表示输出$a0中char类型的内容
la $a0 char # 将char常量的地址保存在$a0中
syscall
string
.data
string1: .ascii "12345" # 将字符串存储在存储空间里,根据字符串长度自动分配空间
string2: .asciiz "12345" # 与ascii的区别是会自动在末尾添加'\0',避免了字符串的连接
.text
main:
li $v0 4 # byte和ascii都是字符类型,参数为4
la $a0 string2 # 将string2的地址传入
syscall
int
.data
age: .word 23 # 将一个整数保存在一个4字节的存储空间里
.text
main:
li $v0 1
lw $a0 age # 可能是因为int的原因,只能传入int的值,无法传入地址
syscall
float
关于float的保存位置(下图为Mars中的Coproc1)
.data
PI: .float 3.1415926 # 同样将浮点数保存在存储空间中
.text
main:
li $v0 2 # float的syscall参数
# 就像计算机组成原理说的那样,对于浮点型的数据并不是保存在通用寄存器里,所以不能使用lw指令导入
# 浮点数保存在Coproc1中,register的右侧,所以需要使用指令lwcl
lwc1 $f12 PI # 以$f12作为输出寄存器
syscall
double
.data
mydouble: .double 7.202
zerodouble: .double 1.303
# 随便在内存中分配的两个double数据,注意这里分别分配的是64位内存
.text
main:
ldc1 $f2 mydouble # 因为是64位存储,所以需要占用$f2,$f3两个寄存器
ldc1 $f0 zerodouble # load double into Coproc1
# 注意double的存储有特殊的指令:ldc1
li $v0 3 # attention
add.d $f12 $f0 $f2 # 将$f0,$f2中的两个数据相加存入$f12,与add指令类似
.text
calculate
add
add $a0 $t1 $t2 # 整数加法
add.d # double加法
add.s # float加法
addi # 立即数加法
addu # 无符号数加法
addiu # 无符号立即数加法
sub
减法同上(与加法几乎相同)
mul
.data
data1: .word 12
data2: .word 34
.text
init:
lw $t0 data1
lw $t1 data2
mul:
# 总共有三种方式来实现乘法操作1.mul 2.mult 3.sll
mul $a0 $t0 $t1 # $a0=$t0*$t1
# 这种方法有一个问题就是最大的结果分为依旧是32位
mult:
li $v0 1
mult $t0 $t1 # 将两个寄存器中的内容相乘并且存放在32位乘寄存器Hi、Lo中,这样就可以吧乘法范围拓展到64位
# 注意是高32位存储在Hi,低32位存储在Lo
mflo $a0 # 将低位寄存器中的值转移入$a0寄存器中
syscall
# mfhi $a1 同理,只不过是高位寄存器
# 虽然可以做更大数的乘法,但是貌似还不知道如何输出这个更大数的值
# 猜测1:存储在浮点数寄存器里???
sll:
# 就是逻辑左移乘2
div
.data
data1: .word 4
data2: .word 10
.text
main:
li $v0 1
lw $t0 data1
lw $t1 data2
div $a0 $t1 $t0
div $t1 $t0 # Hi寄存器存储余数,Lo寄存器存储商
# 同理 利用mflo和mflh来使用Hi和Lo寄存器
syscall
input
int、float、double都肥肠简单嗷,感觉记一下syscall的参数就行了
稍微讲解一下字符串的读取即可
.data
message: .asciiz "Hello,"
userInput: .space 20 # variable:allow the user to input 20 characters
.text
main:
li $v0 8
la $a0 userInput
li $a1 20 # input max 19 characters
syscall
li $v0 4
la $a0 message
syscall
li $v0 4
la $a0 userInput
syscall
# the end of the programm
li $v0 10
syscall
function
basic function
we could see these functions as modules or components of a programme
which is reu