阴间指令集MIPS简介:汇编,IO,过程调⽤与冒泡排序
⽬录
前⾔
计系3第⼀个实验就是MIPS指令集写汇编。。。在计系1和2的折磨 下,我们对汇编语⾔有了⼀定的认知,但是还是难顶 。考虑到之后还有⼤量的实验,姑且记录⼀下MIPS的⼀些特性,操作等等,⽅便后续查阅。
MIPS指令集简介
MIPS的分类,也要按照基本法 ,按照寄存器的位数可以分为 MIPS-32 和 MIPS-64。其中本篇博客主要介绍 MIPS-64 指令集。
Mips指令集是⼀套精简指令集,所以使⽤起来⾮常 蛋疼 ⾼效快捷。
MIPS资源
在 MIPS 指令集中,有很多资源可供我们调⽤,⽐如寄存器资源,内存资源等等。
寄存器资源
⾸先介绍寄存器资源。相⽐于 这种只提供8个寄存器的拉跨的指令集,MIPS提供了32个寄存器,供程序员使⽤。
其中寄存器按照 R0 到 R31 划分。但是为了显式地区分他们的⽤途,我们⼈为地将寄存器按照⽤途进⾏划分:
名称别名⽤途被调⽤之前是否需要保存
$zero R0常数寄存器 表⽰0 $v0 ~ $v1R2 ~ R3函数调⽤ – 返回值×
$a0 ~ $a3R4 ~ R7函数调⽤ – 参数×
$t0 ~ $t7R8 ~ R15临时寄存器×
$s0 ~ $s7R16 ~ R23普通的寄存器√
$t8 ~ $t9R24 ~ R25临时寄存器×$gp R28Global Pointer 全局指针√
$sp R29Stack Pointer 栈指针√
$fp R30Frame Pointer 栈帧指针√
$ra R31Return Address 返回地址√
其中 R型指令使⽤三个寄存器,分别是 rs,rt,rd,分别表⽰ 源1,源2,⽬的寄存器。
值得注意的是,R型指令在⼆进制编码中,寄存器的顺序是 rs, rt, rd,⽽汇编代码中,我们通常使⽤ 指令⽬的寄存器源寄存器1 源寄存器2 这样的格式。这⾮常的反⼈类
再来看 I 型指令:I型指令使⽤两个寄存器,⼀个为源⼀个为⽬的寄存器。同样的,⼆进制编码和汇编代码的寄存器位置不统⼀ 多捞哦 要注意顺序。。。
下⾯给出所有的MIPS指令:
算数指令
数据传输指令
逻辑指令
分⽀跳转指令
MIPS模拟器
和 LC-3 类似,MIPS也有⼀套⾃⼰的模拟器。在可以下载到MIPS模拟器。
链接: pan.baidu/s/1yghDY2xp2AIuxbu1lcQMFw
提取码: vkid
复制这段内容后打开百度⽹盘⼿机App,操作更⽅便哦
下载完成,解压,打开,可以看到 7 个窗⼝,他们分别有不同的职能:
编译并且运⾏简单求和程序
新建⼀个 sum.s ,我们编写如下的内容,将 A,B地址处的数据载⼊ r4 和 r,然后将 r4 和 r5 相加,然后赋值给 r3 ,最后将 r3 存到 C 地址处:
.data
A: .word 10
B: .word 8
C: .word 0
.text
main:
ld r4,A(r0)
ld r5,B(r0)
dadd r3,r4,r5
sd r3,C(r0)
halt
然后在解压⽬录下,通过命令⾏运⾏ ⽂件,编译汇编代码:
最后在模拟器中载⼊代码:
按下 F4 运⾏,可以看到 C地址确实是 AB地址中数值的加和(⼗六进制)
MIPS模拟器中的汇编
MIPS模拟器中的汇编指令和之前介绍的有些许出⼊,⽐如 add 要改成 dadd,addi 要改成 daddi,否则⽆法通过编译。(捞的淌⼝⽔)下⾯给出模拟器⽀持的指令类型:
lb reg,imm(reg) - load byte
lbu reg,imm(reg) - load byte unsigned
sb reg,imm(reg) - store byte
lh reg,imm(reg) - load 16-bit half-word
lhu reg,imm(reg) - load 16-bit half word unsigned
sh reg,imm(reg) - store 16-bit half-word
lw reg,imm(reg) - load 32-bit word
lwu reg,imm(reg) - load 32-bit word unsigned
sw reg,imm(reg) - store 32-bit word
ld reg,imm(reg) - load 64-bit double-word
sd reg,imm(reg) - store 64-bit double-word
l.d freg,imm(reg) - load 64-bit floating-point
s.d freg,imm(reg) - store 64-bit floating-point
halt - stops the program
daddi reg,reg,imm - add immediate
daddui reg,reg,imm - add immediate unsigned
andi reg,reg,imm - logical and immediate
ori reg,reg,imm - logical or immediate
xori reg,reg,imm - exclusive or immediate
lui reg,imm - load upper half of register immediate
slti reg,reg,imm - set if less than immediate
sltiu reg,reg,imm - set if less than immediate unsigned
beq reg,reg,imm - branch if pair of registers are equal
bne reg,reg,imm - branch if pair of registers are not equal
beqz reg,imm - branch if register is equal to zero
bnez reg,imm - branch if register is not equal to zero
j imm - jump to address
jr reg - jump to address in register
jal imm - jump and link to address (call subroutine)
jalr reg - jump and link to address in register
dsll reg,reg,imm - shift left logical
dsrl reg,reg,imm - shift right logical
dsra reg,reg,imm - shift right arithmetic
dsllv reg,reg,reg - shift left logical by variable amount
dsrlv reg,reg,reg - shift right logical by variable amount
dsrav reg,reg,reg - shift right arithmetic by variable amount
movz reg,reg,reg - move if register equals zero
movn reg,reg,reg - move if register not equal to zero
nop - no operation
and reg,reg,reg - logical and
or reg,reg,reg - logical or
xor reg,reg,reg - logical xor
slt reg,reg,reg - set if less than
sltu reg,reg,reg - set if less than unsigned
dadd reg,reg,reg - add integers
daddu reg,reg,reg - add integers unsigned
dsub reg,reg,reg - subtract integers
dsubu reg,reg,reg - subtract integers unsigned
dmul reg,reg,reg - signed integer multiplication
dmulu reg,reg,reg - unsigned integer multiplication
ddiv reg,reg,reg - signed integer division
ddivu reg,reg,reg - unsigned integer division
add.d freg,freg,freg - add floating-point
sub.d freg,freg,freg - subtract floating-point
mul.d freg,freg,freg - multiply floating-point
div.d freg,freg,freg - divide floating-point
mov.d freg,freg - move floating-point
cvt.d.l freg,freg - convert 64-bit integer to a double FP format
cvt.l.d freg,freg - convert double FP to a 64-bit integer format
sort命令排序c.lt.d freg,freg - set FP flag if less than
c.le.d freg,freg - set FP flag if less than or equal to
c.eq.d freg,freg - set FP flag if equal to
bc1f imm - branch to address if FP flag is FALSE
bc1t imm - branch to address if FP flag is TRUE
mtc1 reg,freg - move data from integer register to FP register
mfc1 reg,freg - move data from FP register to integer register
此外,模拟器还和 LC-3 ⼀样,⽀持⼀些伪操作和伪指令:
.data - start of data segment
.text - start of code segment
.code - start of code segment (same as .text)
.org <n> - start address
.space <n> - leave n empty bytes
.asciiz <s> - enters zero terminated ascii string
.ascii <s> - enter ascii string
.align <n> - align to n-byte boundary
.
word <n1>,<n2>.. - enters word(s) of data (64-bits)
.byte <n1>,<n2>.. - enter bytes
.word32 <n1>,<n2>.. - enters 32 bit number(s)
.word16 <n1>,<n2>.. - enters 16 bit number(s)
.double <n1>,<n2>.. - enters floating-point number(s)
其中 n 表⽰数字,⽽ s 表⽰字符串。
MIPS IO操作
MIPS的IO操作和 lC-3 类似。两个内存地址 0x10000 和 0x10008,⼀个负责存储控制数据(即输出模式),⼀个负责存储输出数据。当控制模式 CONTROL 的值不同时,系统会按照不同的⽅式输出 DATA 中的数据。
于是我们输出的时候⼀般需要两个步骤:
1. 将输出数据放⼊ DATA 地址处
2. 将 CONTROL 地址处,赋值⼀个数字,表⽰我们的输出模式
⽽输⼊就反过来:
1. 将 CONTROL 地址处,赋值⼀个数字,表⽰我们的输⼊模式
2. 将输⼊数据从 DATA 地址处取出
下⾯给出输⼊输出的模式:
Addresses of CONTROL and DATA registers
CONTROL: .word32 0x10000
DATA: .word32 0x10008
Set CONTROL = 1, Set DATA to Unsigned Integer to be output
Set CONTROL = 2, Set DATA to Signed Integer to be output
Set CONTROL = 3, Set DATA to Floating Point to be output
Set CONTROL = 4, Set DATA to address of string to be output
Set CONTROL = 5, Set DATA+5 to x coordinate, DATA+4 to y coordinate, and DATA to RGB colour to be output
Set CONTROL = 6, Clears the terminal screen
Set CONTROL = 7, Clears the graphics screen
Set CONTROL = 8, read the DATA (either an integer or a floating-point) from the keyboard
Set CONTROL = 9, read one byte from DATA, no character echo.
其中常⽤的输出模式是 4 和 2,分别表⽰输出字符串和整数。
MIPS过程调⽤
和其他汇编指令集类似,MIPS的过程调⽤离不开栈指针 $sp 的改变。在调⽤前后,我们要做这么⼏件事情:
1. 保存 s 系列的寄存器
2. 保存返回地址寄存器 $ra
3. 如果是多层或者递归调⽤,还需要保存形参
其中 s 系列的寄存器需要存在栈中,此外,通过跳转指令 jal 可以⾃动保存返回地址到 $ra 寄存器。但是我们必须得⼿动将 $ra 的旧值保存在栈中。
下⾯给出⼀个函数调⽤的模板。我们因为使⽤的是 t 系列寄存器,就⽆需保存寄存器了,但是⾄少我们必须保存⼀次返回地址,否则跑飞了:
# @fucntion swap : 交换两个值
# @param a0 : 第⼀个数值的地址
# @param a1 : 第⼆个数值的地址
# @return : ----
swap:
daddi $sp, $sp, -4 # sp -= 4
sw $ra, ($sp) # save rteturn address
lw $t0, ($a0) # t0 = M[arg0]
lw $t1, ($a1) # t1 = M[arg1]
sw $t0, ($a1) # M[arg1] = t0
sw $t1, ($a0) # M[arg0] = t1
lw $ra, ($sp) # restore return address
daddi $sp, $sp, 4 # sp += 4
jr $ra # return
hello world程序
在了解了 MIPS 的 IO 机制之后,我们就可以编写 hello world 输出字符串程序了。
.data
CONTROL: .word 0x10000
DATA: .word 0x10008
STR: .asciiz "Hello World!"
.text
main:
daddi $t0, $zero, 4 # t0 = 4
daddi $t1, $zero, STR # t1 = STR
lwu $t2, DATA($zero) # t2 = M[DATA] = 0x10008
lwu $t3, CONTROL($zero) # t3 = M[CONTROL] = 0x10000
sd $t1, ($t2) # M[0x10008] = t1 = STR
sd $t0, ($t3) # M[0x10000] = t0 = 4
halt
加载并且运⾏:
冒泡排序
⾸先编写⼀些帮助函数,⽐如 printstr,swap,然后编写 sort 函数,最后调⽤即可。
值得注意的是栈空间的分配,即给栈指针分配初始空间,否则栈指针⼀开始是 0 ,然后我们开栈,即 $sp-4,栈指针变为负数,指的地⽅都不对了。。。
.data
CONTROL: .word 0x10000
DATA: .word 0x10008
LEN: .word 0xA
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论