3.6 MIPS指令简介
计算机组成
3 指令系统体系结构
3.6 MIPS指令简介

MIPS秉承着指令数量少,指令功能简单的设计理念。那这样的设计理念是如何实现的呢?在这一节,我们就将来分析MIPS指令的特点。

相比于X86指令所提供的动辄上千页的指令说明,MIPS指令只用这两页纸就可以说清楚了。

MIPS指令的基本格式就分为这三种:R型,I型和J型。
R型指的是寄存器型;
I型指的是立即数型;
J型指的是转移型。

我们用这张表对MIPS的指令进行不同纬度的分类,横轴是按照指令的格式分为R型、I型和J型,纵轴则是根据指令的功能类型分为运算指令、访存指令和分支指令。
首先,我们来看指令格式为R型的运算指令。

R型指令总共包含六个域。其中最高位的opcode域是六个比特,最低位的funct域也是六个比特,中间的四个域均为五个比特。我们分别来看各个域的用途:
opcode域,用于指定指令的类型。对于所有的R型指令,这个域的值均为零。但这并不是说明R型指令只有一种,它还需要用funct域来更为精确的指定指令的类型。所以说,对于R型指令,实际上一共有12个比特操作码。那大家可以思考一下,为什么不将opcode域和funct域合并成一个12比特的域呢?那样岂不是更直观明了吗?

我们再来看这些5比特的域。rs 域,这个域通常用来指定第一个源操作数所在的寄存器编号;rt 域,通常用来指定第二个源操作数所在的寄存器的编号;rd 域,通常用来指定目的操作数的寄存器编号,也就是保存运算结果的地方。
5个比特的域可以表示0-31的数,正好对应MIPS的体系结构中的32个通用寄存器。

还剩下最后一个域 shamt,它指示的是移位操作的位数。因为对于32比特的数,5比特的域正好可以表示0-31的移位位数。那这个域只是对于移位指令有用,对于非移位指令,这个域被设为0。

我们来看一个例子,这是将9号寄存器和10号寄存器中的数相加,把运算结果保存在8号寄存器中。那我们通过这条汇编指令的描述,如何得到MIPS指令的二进制编码呢?这其实很容易。首先,我们查询MIPS指令编码表,就可以得到加法指令的opcode域应该是0(十进制),funct域应该是32。因为它不是移位指令,所以移位的域shamt被设为0。然后我们根据这条指令的操作数,可以得到目的操作数也就说rd这个域等于8,第一个源操作数应该是9,第二个源操作数应该是10。这样我们把各个域的数值转换成二进制数,填写到对应的位置,就可以得到这条指令的二进制编码了。
MIPS指令系统简洁明了的规则可以让我们非常容易的对指令进行这样的手工编码转换,同样也说明了CPU对这样的指令进行硬件的译码也会非常的方便。

如果指令中需要用到立即数,那么就要用到I型指令。

因为R型指令当中只有一个5比特的域,也就是shamt移位这个域可以用来表示立即数,那能表示的数的范围为0-31。在程序中常用的立即数远大于这个范围,所以R型指令并不适用,我们需要新的指令格式。这就是I型指令,I型指令的大部分域与R型指令是相同的。

I型指令的第一个域,也是opcode域,用于指定指令的类型。但它没有funct域,所以不同的I型指令,其opcode域是不一样的。
第二个域rs,指定了第一个源操作数所在的寄存器编号;
第三个域rt,用于指定目的操作数。
I型指令与R型指令不同,它只有两个寄存器数域。

剩下的16位被整合成了一个完整的域,可以存放16位的立即数,可以表示2的十六次方个不同的数值。对一般的访存指令,我们需要用一个寄存器加上一个立即数来指示一个内存单元。那么这个立即数就是访存地址的偏移量,16位的立即数,可以访问正负32K(\(2^{16-1}=32K\),1位符号位)的空间,对于一般的访存指令来说,就可以满足了。而对于运算指令,虽然无法满足全部的需求,但是大多数情况下,16位也可以使用了。在这一点上,就可以体现出X86这样的CISC指令系统的优势,对于X86指令来说,如果它想使用更大宽度的立即数,它可以很容易的扩展,因为它的指令本来就没有限制长度。但是,MIPS指令就不行,它的指令总长度就是32位的,再加上各个寄存器位域的使用,所以I型指令最多只能使用十六位的立即数。

我们来看一个例子。对于加法,如果我们想让其中的源操作数是一个立即数的话,就可以用 addi 这个指令, 注意它和 add 指令是不一样的。add 指令的操作数必须都是寄存器。我们再来练习一下手工转换指令的编码。我们通过查指令编码表,可以发现 addi 指令的opcode域是8,从这一点我们也可以看出 addi 和 add 虽然只有一个字母的差别,但是他们指令格式是完全不一样的。剩下的域我们通过分析这条指令的操作数就可以得到,rs域等于22,rt域等于21,立即数域等于 -50。我们将这些数转换成二进制,就可以得到这条指令的编码了。

然后我们来看所有的分支指令。

分支指令是用于改变控制流的指令,其实就相当于X86当中的转移指令。在MIPS中,分支指令也分为条件分支和非条件分支两种。对于条件分支有两条指令,beq和bne;对于非条件分支,只有一条指令,j。

我们先来看条件分支指令,条件分支指令实际上是i型指令。这就是两条条件分支指令,他们的opcode域分别是4和5。我们以beq指令为例,它共有三个操作数,前两个是寄存器操作数,第三个操作数是存储器地址,也就说一个立即数。CPU会判断第一个寄存器当中的数和第二个寄存器当中的数是否相等。如果相等就跳转到L1所指向的寄存器单元取出下一条指令,否则,顺序执行beq之后的那条指令。我们需要注意,这里和X86的条件转移指令有很大的不同,MIPS没有标志寄存器,它就在一条指令当中既进行了比较,又完成了转移。
我们还记得MIPS的全称,就是为了减少指令流水线的互锁。也就说要尽量避免不同指令之间相互的影响。而标志位这件事,很明显就是前一条指令运行的结果可能会对后面的某一条指令产生影响,这是MIPS指令设计时要尽量避免的。所以beq指令也很好的体现了MIPS的这一设计理念。

我们来看一个例子。这段C语言代码是我们经常会写的。如果把它转换为MIPS指令,是这样的,第一条beq指令,如果S3寄存器和S4寄存器内容相同,则转移到True所对应的这行指令。那么S3和S4中保存了I和J这两个变量,如果他们内容相同,会转移到True这里,执行加法指令,也就对应于F=G+H;如果他们不等,则会顺序的执行下一条指令,也就一条减法指令sub对应于F=G-H。执行完之后,会跳过 add $s0, $s1, $s2 这条加法指令,然后进入后面的代码。

从条件分支指令的格式可以看出,目标地址只能使用16位的位移量,这是一个很大的局限,但是我们还得考虑如何充分发挥这16位的作用。如果以当前的PC寄存器为基准,在MIPS中,指向下一条指令地址的寄存器称为PC,类似于X86中的IP寄存器。PC这个寄存器,是指向32位地址的,如果以它为基准,16位位移量可以表示出当前指令前后2的15次方字节这么一个范围。但是我们要注意一点,MIPS的指令长度固定位32个比特,因此每条指令的位置,一定会在四个字节对齐的地方,这样地址最低两位肯定为0。所以我们实际上可以用十六位的位移量去指示每四个字节为一个单位的地址,这样就可以把目标地址的范围扩大四倍,可以达到前后128KB。
在这样的条件下,目标地址应该这么计算:
当分支条件不成立时,下一条指令的地址就等于当前的pc+4;
如果分支条件成立,那下一条指令的地址就等于已经加了4的pc, 再加上这个立即数乘以4。

然后我们来看非条件分支指令。相比于条件分支指令,有两个寄存器域用于比较条件,那如果我们不需要判断条件,我们就可以想办法扩大目标地址的范围。当然理想情况下是直接使用32位的地址,但还是因为MIPS的指令长度固定为32位。而每条指令至少需要有opcode域,指示它指令类型,这就占用了6个bit。那我们把剩下的26个bit全都用于目标地址,这就是J型指令。在考虑到MIPS指令是四字节对齐的这个情况,对于J型指令,下一条指令的地址的计算方法可以是将当前的pc加4之后,取最高的四位,再加上J型指令编码中的26位,然后在末尾填上两个0。
虽然目标地址的范围还不能达到整个4G的空间,但比之前的条件分支指令已经扩大了很多。

我们用一个例子来进行进一步的说明。假设我们在高级语言中用的若干变量与寄存器的对应关系是这样的。那我们就可以用这样一种方式来实现这段C语言的代码,第一条指令 bne 是判断i和j是否相等,如果不相等,则转移到 Else 这个标号所对应的位置,也就是执行一条减法指令对应于 f = g - h;如果判断条件不成立,也就是 i = j 的时候,顺序地执行下一条加法指令,也就对应于 f = g + h。然后用无条件分支指令跳到 Else 条件之后继续执行后面的程序。

我们现在已经知道这个J型指令的目标地址可以是当前指令前后256MB(\(2^{26+2}\)字节)的范围,那如果我们还想跳转到更远的地址,应该怎么办呢?有一个很简单的方法就是两次调用J指令。第一条J指令尽可能跳到最远的地方,然后在那个目标地址再放一条J指令,像接力一样再跳一次。这个方法很简单,但是用起来不算太方便。那么还可以用什么方法呢?大家还记得我们曾说过间接转移指令吗?MIPS中也可以用同样的方法,这就是jr指令。jr指令有一个寄存器操作数,可以把要转移的目标地址放到寄存器当中,这样就可以使用32位的目标地址了,但是这样的指令显然无法用J型指令来实现。那么需要新增一种指令类型吗?其实也不需要,我们就用原来的R型指令就可以很好的实现。只用占用其中的一个寄存器位域,然后新增一种funct的编码就可以了。

这就是MIPS指令系统的核心内容,我们只用熟悉这两页的内容就可以轻松的掌握MIPS的指令了。

我们已经介绍完了MIPS指令系统体系结构。它不愧为精简指令系统(RISC)的经典设计,指令简洁而且精巧。
3.6 MIPS指令简介的更多相关文章
- QtSpim实现MIPS指令的编写
QtSpim实现MIPS指令的编写 由于各种对齐问题,cnblogs的格式难以控制,故贴图片,谅解.
- angularjs学习第六天笔记(指令简介学习)
您好,由于周末有事情,没哟学习angularjs,几天晚上开始继续学习angularjs,坚持加油每一天.谢谢 接着上周五学习了表单验证以后,今天开始学习angularjs中一个非常重要的模块:指令 ...
- MIPS指令学习二
1.MIPS寻址方式 MIPS架构的寻址模式有寄存器寻址.立即数寻址.寄存器相对寻址和PC相对寻址4种,其中寄存器相对寻址.PC相对寻址介绍如下: 1.1.寄存器相对寻址 这种寻址模式主要被加载/存储 ...
- 3.3 x86指令简介
计算机组成 3 指令系统体系结构 3.3 x86指令简介 x86指令种类繁多,数量庞大.在这一节我们将会学习x86指令的分类,并分析其中最为基础的一部分指令. 通常一个指令系统主要包括这几类指令.运算 ...
- MIPS指令 MIPS架构
华中科技大学 - 计算机组成原理 华中科技大学 - 计算机硬件系统设计 Microprocessor without Interlocked Pipleline Stages 无内部互锁流水级的微处理 ...
- 8086cpu-intel汇编指令简介
jcxz 有条件跳转指令,cx为跳转条件.如果(cx)==0则跳转到指定标号处.跳转地址在机器码中已相对位置(-128~127)给出. 相当于 if((cx)==0) ...
- [zt]系统中常用MIPS指令
指令 功能 应用实例 LB 从存储器中读取一个字节的数据到寄存器中 LB R1, 0(R2) LH 从存储器中读取半个字的数据到寄存器中 LH R1, 0(R2) LW 从存储器中读取一个字的数据到寄 ...
- Redis系统管理相关指令简介
常用命令列表 DBSIZE 返回当前数据库 Key 的数量 INFO ...
- javaee学习-JSP指令简介
JSP指令(directive)是为JSP引擎而设计的,它们并不直接产生任何可见输出,而只是告诉引擎如何处理JSP页面中的其余部分. 在JSP 2.0规范中共定义了三个指令: page指令 Inclu ...
随机推荐
- cf249D
这题说的是给了一个n*m的网格,然后每个格子的点事黑色的或者是白色的然后每个点如图所示 然后只能用白点和图中给出的边建立三角形然后询问三角形的个数有多少个,这样说每个三角形的边必须是图中有的边, ...
- NOSQL学习之一:Memcached, Redis, MongoDB区别
Redis是一个开源(BSD许可),内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理. Memcached是一个自由开源的,高性能,分布式内存对象缓存系统. MongoDB是一个基于分布 ...
- mysql设置环境变量
临时修改环境变量 我们可以使用set语法在运行时修改环境变量,修改global变量后,对修改之前的session没有影响,对修修改之后的session生效:修改session变量后,修改后,对于该se ...
- Linux基础命令---bzcat
bzcat 解压缩被bzip2压缩过的文件,将文件解压到标准输出,此命令只有一个选项-s.该指令对压缩过的二进制文件没有意义,因为二进制文件没有可读性. 此命令的适用范围:RedHat.RHEL.Ub ...
- Python之路----递归函数
1.小练一下 用map来处理字符串列表,把列表中所有人都变成sb,比方alex_sb name=['alex','wupeiqi','yuanhao','nezha'] # def func(item ...
- php多进程结合Linux利器split命令实现把大文件分批高效处理
有时候会遇到这样的需求,比如log日志文件,这个文件很大,甚至上百M,需要把所有的日志拿来做统计,这时候我们如果用单进程来处理,效率会很慢.如果我们想要快速完成这项需求,我们可以利用Linux的一个利 ...
- 20145104张家明 《Java程序设计》第8周学习总结
20145104张家明 <Java程序设计>第8周学习总结 教材学习内容总结 第15章 -java.util.logging包提供了日志功能相关类与接口,不必额外配置日志组件,就可以在标准 ...
- Ubuntu18.04安装Openssl-1.1.1
1.查看版本 Ubuntu的版本是18.04.使用openssl version命令查看openssl版本,可以看到Ubuntu自带了openssl-1.1.0版本,因此安装新版本需要替换旧版本. 2 ...
- 《Python程序设计(第3版)》[美] 约翰·策勒(John Zelle) 第 3 章 答案
判断对错 1.由计算机存储和操作的信息称为数据.2.由于浮点数是非常准确的,所以通常应该使用它们,而不是int.3.像加法和减法这样的操作在mAth库中定义.4.n 项的可能排列的数目等于 n!.5. ...
- bootstrap5
列表组的使用 ul.list-group > li.list-group-item *5... 列表组中可以放置徽标: 在li中放置 span.badge. bootstrap中的情景类: 实际 ...