200字范文,内容丰富有趣,生活中的好帮手!
200字范文 > 阴间指令集MIPS简介:汇编 IO 过程调用与冒泡排序

阴间指令集MIPS简介:汇编 IO 过程调用与冒泡排序

时间:2021-10-09 08:20:44

相关推荐

阴间指令集MIPS简介:汇编 IO 过程调用与冒泡排序

目录

前言MIPS指令集简介MIPS资源寄存器资源内存资源MIPS指令算数指令数据传输指令逻辑指令分支跳转指令MIPS模拟器编译并且运行简单求和程序MIPS模拟器中的汇编MIPS IO操作MIPS过程调用hello world程序冒泡排序

前言

计系3第一个实验就是MIPS指令集写汇编。。。在计系1和2的折磨下,我们对汇编语言有了一定的认知,但是还是难顶。考虑到之后还有大量的实验,姑且记录一下MIPS的一些特性,操作等等,方便后续查阅。

MIPS指令集简介

MIPS的分类,也要按照基本法,按照寄存器的位数可以分为 MIPS-32 和 MIPS-64。其中本篇博客主要介绍 MIPS-64 指令集。

Mips指令集是一套精简指令集,所以使用起来非常蛋疼高效快捷。

MIPS资源

在 MIPS 指令集中,有很多资源可供我们调用,比如寄存器资源,内存资源等等。

寄存器资源

首先介绍寄存器资源。相比于 LC-3 这种只提供8个寄存器的拉跨的指令集,MIPS提供了32个寄存器,供程序员使用。

其中寄存器按照 R0 到 R31 划分。但是为了显式地区分他们的用途,我们人为地将寄存器按照用途进行划分:

注意其中 $zero 寄存器是不可写的。所以我们无需考虑其保存问题。。。此外,虽然帧指针 $fp 也是需要保存的,但是实际编程中似乎并不需要我们显式地保存它~~(快进到 Stack.Overflow)~~

内存资源

存储器只能通过数据传输指令访问。MIPS将使用字节编址,这意味着连续的地址之间相差8bit。此外,存储器用于保存数据结构,数组和溢出的寄存器(比如函数形参多于4个,那么寄存器不够用了)

MIPS指令

MIPS指令集的指令非常精简,数目非常少(迫真)。其中指令又根据操作寄存器的数目,分为 R型指令 和 I型指令。

其中 R型指令使用三个寄存器,分别是 rs,rt,rd,分别表示 源1,源2,目的寄存器。

值得注意的是,R型指令在二进制编码中,寄存器的顺序是 rs, rt, rd,而汇编代码中,我们通常使用指令 目的寄存器 源寄存器1 源寄存器2这样的格式。这非常的反人类

再来看 I 型指令:I型指令使用两个寄存器,一个为源一个为目的寄存器。同样的,二进制编码和汇编代码的寄存器位置不统一多捞哦要注意顺序。。。

下面给出所有的MIPS指令:

算数指令

数据传输指令

逻辑指令

分支跳转指令

MIPS模拟器

和 LC-3 类似,MIPS也有一套自己的模拟器。在这里可以下载到MIPS模拟器。

链接: /s/1yghDY2xp2AIuxbu1lcQMFw 提取码: vkid 复制这段内容后打开百度网盘手机App,操作更方便哦

下载完成,解压,打开,可以看到 7 个窗口,他们分别有不同的职能:

编译并且运行简单求和程序

新建一个 sum.s ,我们编写如下的内容,将 A,B地址处的数据载入 r4 和 r,然后将 r4 和 r5 相加,然后赋值给 r3 ,最后将 r3 存到 C 地址处:

.dataA: .word 10B: .word 8C: .word 0.textmain:ld r4,A(r0)ld r5,B(r0)dadd r3,r4,r5sd r3,C(r0)halt

然后在解压目录下,通过命令行运行 asm.exe 文件,编译汇编代码:

最后在模拟器中载入代码:

按下 F4 运行,可以看到 C地址确实是 AB地址中数值的加和(十六进制)

MIPS模拟器中的汇编

MIPS模拟器中的汇编指令和之前介绍的有些许出入,比如 add 要改成 dadd,addi 要改成 daddi,否则无法通过编译(捞的淌口水)

下面给出模拟器支持的指令类型:

lb reg,imm(reg)- load bytelbu reg,imm(reg) - load byte unsignedsb reg,imm(reg)- store bytelh reg,imm(reg)- load 16-bit half-wordlhu reg,imm(reg) - load 16-bit half word unsignedsh reg,imm(reg)- store 16-bit half-wordlw reg,imm(reg)- load 32-bit wordlwu reg,imm(reg) - load 32-bit word unsignedsw reg,imm(reg)- store 32-bit wordld reg,imm(reg)- load 64-bit double-wordsd reg,imm(reg)- store 64-bit double-wordl.d freg,imm(reg) - load 64-bit floating-points.d freg,imm(reg) - store 64-bit floating-pointhalt- stops the programdaddi reg,reg,imm - add immediatedaddui reg,reg,imm - add immediate unsignedandi reg,reg,imm - logical and immediateori reg,reg,imm- logical or immediatexori reg,reg,imm - exclusive or immediatelui reg,imm - load upper half of register immediateslti reg,reg,imm - set if less than immediatesltiu reg,reg,imm - set if less than immediate unsignedbeq reg,reg,imm- branch if pair of registers are equalbne reg,reg,imm- branch if pair of registers are not equalbeqz reg,imm - branch if register is equal to zerobnez reg,imm - branch if register is not equal to zeroj imm- jump to addressjr reg - jump to address in registerjal imm - jump and link to address (call subroutine)jalr reg - jump and link to address in registerdsll reg,reg,imm- shift left logicaldsrl reg,reg,imm- shift right logicaldsra reg,reg,imm- shift right arithmeticdsllv reg,reg,reg - shift left logical by variable amount dsrlv reg,reg,reg - shift right logical by variable amountdsrav reg,reg,reg - shift right arithmetic by variable amountmovz reg,reg,reg- move if register equals zeromovn reg,reg,reg- move if register not equal to zeronop - no operationand reg,reg,reg- logical andor reg,reg,reg - logical orxor reg,reg,reg- logical xorslt reg,reg,reg- set if less thansltu reg,reg,reg- set if less than unsigneddadd reg,reg,reg- add integersdaddu reg,reg,reg - add integers unsigneddsub reg,reg,reg- subtract integersdsubu reg,reg,reg - subtract integers unsigneddmul reg,reg,reg- signed integer multiplicationdmulu reg,reg,reg - unsigned integer multiplicationddiv reg,reg,reg- signed integer divisionddivu reg,reg,reg - unsigned integer divisionadd.d freg,freg,freg - add floating-pointsub.d freg,freg,freg - subtract floating-pointmul.d freg,freg,freg - multiply floating-pointdiv.d freg,freg,freg - divide floating-pointmov.d freg,freg- move floating-pointcvt.d.l freg,freg - convert 64-bit integer to a double FP formatcvt.l.d freg,freg - convert double FP to a 64-bit integer formatc.lt.d freg,freg- set FP flag if less thanc.le.d freg,freg- set FP flag if less than or equal toc.eq.d freg,freg- set FP flag if equal tobc1f imm - branch to address if FP flag is FALSEbc1t imm - branch to address if FP flag is TRUE mtc1 reg,freg - move data from integer register to FP registermfc1 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 中的数据。

于是我们输出的时候一般需要两个步骤:

将输出数据放入 DATA 地址处将 CONTROL 地址处,赋值一个数字,表示我们的输出模式

而输入就反过来:

将 CONTROL 地址处,赋值一个数字,表示我们的输入模式将输入数据从 DATA 地址处取出

下面给出输入输出的模式:

Addresses of CONTROL and DATA registersCONTROL: .word32 0x10000DATA: .word32 0x10008Set CONTROL = 1, Set DATA to Unsigned Integer to be outputSet CONTROL = 2, Set DATA to Signed Integer to be outputSet CONTROL = 3, Set DATA to Floating Point to be outputSet CONTROL = 4, Set DATA to address of string to be outputSet CONTROL = 5, Set DATA+5 to x coordinate, DATA+4 to y coordinate, and DATA to RGB colour to be outputSet CONTROL = 6, Clears the terminal screenSet CONTROL = 7, Clears the graphics screenSet CONTROL = 8, read the DATA (either an integer or a floating-point) from the keyboardSet CONTROL = 9, read one byte from DATA, no character echo.

其中常用的输出模式是 4 和 2,分别表示输出字符串和整数。

MIPS过程调用

和其他汇编指令集类似,MIPS的过程调用离不开栈指针 $sp 的改变。在调用前后,我们要做这么几件事情:

保存 s 系列的寄存器保存返回地址寄存器 $ra如果是多层或者递归调用,还需要保存形参

其中 s 系列的寄存器需要存在栈中,此外,通过跳转指令 jal 可以自动保存返回地址到 $ra 寄存器。但是我们必须得手动将 $ra 的旧值保存在栈中。

下面给出一个函数调用的模板。我们因为使用的是 t 系列寄存器,就无需保存寄存器了,但是至少我们必须保存一次返回地址,否则跑飞了

# @fucntion swap : 交换两个值# @param a0 : 第一个数值的地址# @param a1 : 第二个数值的地址# @return : ----swap:daddi $sp, $sp, -4 # sp -= 4sw $ra, ($sp) # save rteturn addresslw $t0, ($a0) # t0 = M[arg0]lw $t1, ($a1) # t1 = M[arg1]sw $t0, ($a1) # M[arg1] = t0sw $t1, ($a0) # M[arg0] = t1lw $ra, ($sp) # restore return addressdaddi $sp, $sp, 4 # sp += 4jr $ra # return

hello world程序

在了解了 MIPS 的 IO 机制之后,我们就可以编写 hello world 输出字符串程序了。

.dataCONTROL: .word 0x10000DATA: .word 0x10008STR: .asciiz "Hello World!".textmain: daddi $t0, $zero, 4# t0 = 4daddi $t1, $zero, STR # t1 = STRlwu $t2, DATA($zero) # t2 = M[DATA] = 0x10008lwu $t3, CONTROL($zero) # t3 = M[CONTROL] = 0x10000sd $t1, ($t2) # M[0x10008] = t1 = STRsd $t0, ($t3) # M[0x10000] = t0 = 4halt

加载并且运行:

冒泡排序

首先编写一些帮助函数,比如 printstr,swap,然后编写 sort 函数,最后调用即可。

值得注意的是栈空间的分配,即给栈指针分配初始空间,否则栈指针一开始是 0 ,然后我们开栈,即 $sp-4,栈指针变为负数,指的地方都不对了。。。

.dataCONTROL: .word 0x10000DATA: .word 0x10008LEN: .word 0xAARR: .word 8.word 6.word 3.word 7.word 1.word 0.word 9.word 4.word 5.word 2STR1: .asciiz "before sort the array is:\n" STR2: .asciiz "after sort the array is:\n"STACKBOTTOM: .space 80STACKTOP: .word 0.textmain: daddi $sp, $zero, STACKTOP # assign stackdaddi $a0, $zero, STR1# print str1jal printStrdaddi $a0, $zero, ARR # print arrayld $a1, LEN($zero)jal printArrdaddi $a0, $zero, STR2# print str2jal printStrdaddi $a0, $zero, ARR # sort arrayld $a1, LEN($zero)jal sortdaddi $a0, $zero, ARR # print arrayld $a1, LEN($zero)jal printArrhalt# @function printStr :# @param a0 : 字符串起始地址# @return : ----printStr:daddi $sp, $sp, -4# sp -= 4sw $ra, ($sp) # save return addressdaddi $t0, $zero, 4# t0 = 4dadd $t1, $zero, $a0 # t1 = arg0lwu $t2, DATA($zero) # t2 = M[DATA] = 0x10008lwu $t3, CONTROL($zero) # t3 = M[CONTROL] = 0x10000sd $t1, ($t2) # M[0x10008] = t1 = arg0sd $t0, ($t3) # M[0x10000] = t0 = 4lw $ra, ($sp) # restore return addressdaddi $sp, $sp, 4 # sp += 4jr $ra # return# @fucntion swap : 交换两个值# @param a0 : 第一个数值的地址# @param a1 : 第二个数值的地址# @return : ----swap:daddi $sp, $sp, -4 # sp -= 4sw $ra, ($sp) # save rteturn addresslw $t0, ($a0) # t0 = M[arg0]lw $t1, ($a1) # t1 = M[arg1]sw $t0, ($a1) # M[arg1] = t0sw $t1, ($a0) # M[arg0] = t1lw $ra, ($sp) # restore return addressdaddi $sp, $sp, 4 # sp += 4jr $ra # return# @fucntion sort : 排序# @param a0 : 数组首地址# @param a1 : 数组长度# @return : ----sort:daddi $sp, $sp, -20# sp -= 20sw $s3, 16($sp)sw $s2, 12($sp)sw $s1, 8($sp)sw $s0, 4($sp)sw $ra, ($sp) # save rteturn addressdadd $s0, $a0, $zero # s0 = ARRdadd $s1, $a1, $zero # s1 = LENdadd $s2, $zero, $zero # s2 = i = 0dadd $s3, $zero, $zero # s3 = j = 0loop1:beq $s1, $s2, end1# if i==LEN -> end1dadd $s3, $zero, $zero # j = 0loop2:daddi $t0, $s1, -1# t0 = s1-1 = LEN-1beq $t0, $s3, end2# if j==LEN-1 -> end2### inner loopdsll $t0, $s3, 3 # t0 = j*4dadd $a0, $t0, $s0# a0 = ARR + j*4daddi $a1, $a0, 8 # a1 = ARR + (j+1)*4ld $t0, ($a0) # t0 = ARR[j]ld $t1, ($a1) # t1 = ARR[j+1]slt $t2, $t1, $t0 # t1<t0 ? t2=1beq $zero, $t2, l1# t2==0 -> l1jal swap# swapl1:#daddi r15, r15, 1# debug### end of inner loopdaddi $s3, $s3, 1 # j++j loop2 # goto loop2end2:daddi $s2, $s2, 1 # i++j loop1 # goto loop1end1:lw $ra, ($sp) # restore return lw $s0, 4($sp)lw $s1, 8($sp)lw $s2, 12($sp)lw $s3, 16($sp)daddi $sp, $sp, 20# sp += 20jr $ra # return# @fucntion printArr : 打印数组# @param a0 : 数组首地址# @param a1 : 数组长度# @return : ----printArr:daddi $sp, $sp, -20# sp -= 20sw $s3, 16($sp)sw $s2, 12($sp)sw $s1, 8($sp)sw $s0, 4($sp)sw $ra, ($sp) # save rteturn addressdadd $s0, $a0, $zero # s0 = ARRdadd $s1, $a1, $zero # s1 = LENdadd $s2, $zero, $zero # s2 = i = 0loop3:beq $s1, $s2, end3# if i==LEN -> end3dsll $t0, $s2, 3 # t0 = i*8dadd $t0, $t0, $s0# t0 = ARR + i*8ld $t0, ($t0) # t0 = ARR[i]daddi $t1, $zero, 2# t1 = 2lwu $t2, DATA($zero) # t2 = M[DATA] = 0x10008lwu $t3, CONTROL($zero) # t3 = M[CONTROL] = 0x10000sd $t0, ($t2) # M[0x10008] = ARR[i]sd $t1, ($t3) # M[0x10000] = 2#daddi r15, r15, 1daddi $s2, $s2, 1 # i++j loop3 # goto loop3end3:lw $ra, ($sp) # restore return lw $s0, 4($sp)lw $s1, 8($sp)lw $s2, 12($sp)lw $s3, 16($sp)daddi $sp, $sp, 20# sp += 20jr $ra # return

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。