MIPS指令集(一)基本操作

目录

计算机硬件的操作数

存储器操作数

常数或立即数操作数

有符号数和无符号数

指令的格式

逻辑操作

决策指令

循环


计算机硬件的操作数

先从一条C语句入手

cpp 复制代码
a = b + c;

将其翻译为MIPS

cpp 复制代码
add a, b, c

其中a,b,c就是这条指令的操作数。表示将b与c的和放入a中。

加法指令只有三个操作数,也就是说只能一次完成两个数相加,下面的指令序列会完成四个数相加

cpp 复制代码
add a, b, c
add a, a, d
add a, a, e

只能一次完成两个数相加体现了硬件简单性的设计原则。下面会知道,使用指令实际上不会写诸如a,b,c之类的字符,而是使用寄存器。

与高级语言不同,MIPS的算术运算被要求操作数只能来自寄存器。寄存器是构成计算机的基本单元。在MIPS体系结构中寄存器大小为32位,同时拥有32个寄存器。在MIPS体系结构中也常把32位称作一个(word)。

MIPS在使用寄存器时,用''后跟两个字符表示寄存器。用s0,s1...表示类似C语言中的变量所对应的寄存器,用t0,$t1...表示临时变量对应的寄存器。

cpp 复制代码
a = (b + c) - (d + e)

以该C赋值语句为例,将其翻译为MIPS指令,假设s0,...s4分别对应存储了a,..e

cpp 复制代码
add $t0, $s1, $s2 #b+c的结果存在临时变量寄存器t0中
add $t1, $s3, $s4 #同上
add $s0, $t0, $t1

MIPS中#后是注释,注意这种语言一行只有一条指令,且注释是在一行的末尾结束

存储器操作数

高级语言中常有数组和结构体,而且往往大小不止一个字,这种数据结构就会存储在内存中,而内存就是存储器,磁盘更习惯叫做io设备。

由于MIPS算术指令只能操作寄存器,因此必须有一种手段,能将内存中的数据加载到寄存器中。

这些指令叫做数据传输指令

为了访问内存中的字,必须给出地址。内存中的地址是按字节编排的,也就是说每个相邻的地址相差1

图中每一块大小一个字节。

将数据从内存加载到寄存器通常称为取数(load)指令,实际MIPS取数指令助记符是lw,操作数有三个,第一个表示要把数据存到哪个寄存器,第二个是地址偏移量 (单位为字节,要求是常数),第三个是基址寄存器

cpp 复制代码
a = b + A[8];

假设a存在s0,b存在s1,A地址存在s2。

cpp 复制代码
lw $t0, 32($s2) #一个字大小为32位,也就是4字节,8个字就得偏移32字节
add $s0, $s1, $t0

MIPS字的起始地址是4的倍数,这叫做对齐限制。字在内存中如图存储。

MIPS还有一类指令是将寄存器中的数据复制到存储器中,叫做存数(store)指令。MIPS记作sw,用法与lw类似,只是第一个操作数代表要从哪个寄存器中得到数据。

常数或立即数操作数

仅仅从已经介绍的指令来看,要使用常数,只能从存储器取出(lw),如要将a+4

cpp 复制代码
lw $t0, AddrConstant($s1)#AddrConstant为某一常数偏移量,将4加载到t0
add $s0, $s0, $t0

如果要避免使用取数指令,可使用addi指令

cpp 复制代码
addi $s0, $s0, 4

像这种加法叫加立即数(add immediate),常数操作数出现频率高,像这种带立即数的指令,比从存储器种取值快很多,能耗也较低。

常数0可简化指令集。例如,数据传输指令可视为操作数为0的加法。MIPS将$zero恒置为0,编号也为0

有符号数和无符号数

有符号数在MIPS中用补码表示。需要注意的是,当不满32位的数被存储时,高位会补上符号位。

像0100,存在寄存器中

cpp 复制代码
00000000 00000000 00000000 00000100

1100,存在寄存器中

cpp 复制代码
11111111 11111111 11111111 11111100

MIPS有一些末尾为u的指令操作无符号数,具体后面可以见到。

指令的格式

指令以二进制的形式存储,现在我们可以把指令翻译成二进制。

所有的寄存器会被映射为数字,s0\~s7映射到16~23, t0\~t7映射到8~15。

cpp 复制代码
add $t0, $s1, $s2

以该指令为例,先将其翻译为十进制,再转为二进制。

机器指令分为多个字段,本例第一个和最后一个告诉MIPS计算机要执行加法操作,第二个和第三个表示源操作数寄存器,第四个字段表示存放结果的寄存器,第五个字段没有用到,故置为0。

截取《计算机组成与设计 硬件/软件接口》中相关说明

这种指令格式在某些场景可能不适用,如lw指令需要传入偏移量,5位是不够用的,这时,想要增加位数,但是MIPS的设计是,所有指令的长度都相同,这样,就会采取折中方案:所有指令长度相同,但不同类型指令采用不同指令格式。如上述指令就是R型。另一种是I型,用于传输立即数。

在这种I型格式中,立即数大小仍然有限制。可以看到这种格式下,很难增加寄存器的数量,因为寄存器序号会使得rs,rt字段增加位。

逻辑操作

一张图即可解决,用法也与其他指令类似。

决策指令

计算机的运算能力强大,但计算机与计算器的差别在于计算机能执行决策指令,也就是条件分支指令。MIPS有两条类似C语言 if和 go to的指令

cpp 复制代码
beq regsiter1, register2, L1

表示若寄存器register1 和register2的值相等,跳转到L1标签。beq(branch if equal),相等则分支。

cpp 复制代码
bne regsiter1, register2, L1

表示若寄存器register1 和register2的值不等,跳转到L1标签。bne(branch if not equal),不等则分支。

还需介绍另一种分支指令------无条件分支

cpp 复制代码
j L1

j为jump的缩写

cpp 复制代码
if (i == j) 
    f = g + h;
else
    f = g - h;

现在将该C语句编译为MIPS指令。

假设i存在s0,j存在s1,f,g,h分别存在s2,s3,s4

cpp 复制代码
bne $s0, $s1, Else
add $s2, $s3, $s4
j Exit
Else: sub $s2, $s3, $s4
Exit:

循环

条件分支指令可以实现循环

cpp 复制代码
while (save[i] == k)
    i += 1;

假设i和k存在s3和s5中,save的基址存在s6中。

cpp 复制代码
Loop: sll $t1, $s3, 2 #需要将i×4
add $t1, $s6, $t1
lw $t0, 0($t1)        #要求偏移量为常数
bne $t0, $s5, Exit
addi $s3, $s3, 1
j Loop
Exit:
相关推荐
ok0606 小时前
各种开源汇编、反汇编引擎的非专业比较
汇编·开源
Crossoads14 小时前
【汇编语言】内中断(三) —— 中断探险:从do0到特殊响应的奇妙旅程
android·开发语言·javascript·网络·汇编·单片机·机器学习
染指11101 天前
49.第二阶段x86游戏实战2-鼠标点击call深追二叉树
汇编·c++·windows·游戏安全·反游戏外挂·游戏逆向
程序leo源3 天前
深入理解指针
android·c语言·开发语言·汇编·c++·青少年编程·c#
skywalk81634 天前
好玩的汇编编译器NASM:一款基于x86架构的汇编与反汇编软件
汇编
Coding~6 天前
逆向攻防世界CTF系列56-easy_Maze
c语言·汇编·算法·安全·网络安全
二进制怪兽7 天前
[笔记] 编译LetMeowIn(C++汇编联编程序)过程
汇编·c++·笔记
Reeeeeeeeeee-8 天前
x64dbg 安装使用教程
开发语言·汇编·c++
YuCaiH10 天前
【汇编】逻辑指令
汇编·笔记