4.1指令基本格式

一、前言

大家好,从这个小节开始 我们会进入这门课的第四章 指令系统 那通过之前的学习 我们知道现代计算机的结构大致上可以分为这样的几个板块
在这里插入图片描述
通过第二章的学习,我们已经知道了运算器是如何实现加减乘除移位运算这些操作的 ,而通过第三章的学习 我们又知道了我们的数据是如何存放在各种各样的存储器里边,然后cpu又是如何从存储器当中取走数据的 。这一章开始 我们要学习cpu的控制大致上有什么样的功能,还有各种功能的一个基本原理 。那之前我们说过控制器有两个很重要的功能 ,第一个功能就是解析各种各样的指令 ,然后根据不同的指令去指挥其他部件来协调这工作,所以 这一章也就是第四章 我们会重点探讨控制器需要支持的指令应该怎么设计。然后下一章 也就是第五章 我们再来具体的探讨控制器是如何控制 如何协调各种各样的部件 让他们配合工作的。

那在第一章的第四个视频当中 我们介绍了计算机的一个工作原理 我们用高级语言写的这样一串代码被编译之后 可以形成一系列与之对等的机器指令
在这里插入图片描述
那除了指令之外 还会有一些数据同时被放到储存里 那我们程序执行的过程 其实就是CPU来执行这些一条一条的机器指令的过程。

那么我们可以看到 任何一条指令会有两个部分组成 一个是操作码 一个是地址码,操作码就是指明了我们此时需要做什么, 然后地址码就是指明了我们做的这个操作 这个运算的对象到底是谁
在这里插入图片描述
比如对于这儿的第二条指令来说操作吗000100表示的是我们需要进行的是一个乘法操作,那参与这个运算的乘数是存在了这个地址码所指向的存储单元当中,也就是b这个变量 那每一条指令都是由操作码和地址码来组成的

不过 这个地方的最后一条指令会比较特殊 也就是这一条停机指令 当cpu检测到这条指令的操作码为000110的时候 就意味着当前执行的这些程序应该运行结束了
在这里插入图片描述
所以其实最后这条指令 ,它的地址码是没有意义的 我们可以不要地址码 只要操作码就可以,因此可以看到 前边这些指令都需要一个操作数 也就是 需要一个动作的对象,而最后这个指令 其实我们只需要保留操作码就可以 因此可以看到 即便是对于同一台计算机 那么这台计算机 他所支持的指令类别也是千差万别的,那么各种各样的指令应该如何设计 这就是我们这一章需要探讨的问题 那在这个小节当中 我们会先着重探讨指令的相关格式

二、指令相关格式

在这里插入图片描述

刚才我们其实已经回顾了操作码和地址码相关的概念 ,并且我们能够体会到 不同的指令有可能它的地址码的数目是不一样的, 因此 我们首先会根据地址码的数目不同对指令进行一个分类 接下来我们又会根据指令的总长度不同对指令的格式进行分类,再往后 又会根据操作码的长度还有操作类型来依次对指令进行一个分类,

首先我们来看一下指令的定义 其实这个已经没有必要看了 只不过为了保持这个知识体系的完整度 所以我们还是把这些东西给念一遍
在这里插入图片描述

指令呢 又称作机器指令 就是用来指示计算机执行某种操作的命令,是计算机运行的最小功能单位, 一台计算机的所有指令的集合 ,称为这台计算机的指令系统,也可以称为指令级。

那需要注意的是不同体系结构的计算机,所能支持的指令级是不一样的 ,大家应该都听过这两个名词 一个叫x86,一 个叫ARM,那英特尔系列的cpu就是X86架构的 ,然后现在我们使用的智能手机基本上都是arm架构,那这两种架构所能支持的指令类型,指令集是不一样的,所以这才导致了我们在个人电脑pc上运行的各种各样的软件 ,不可能直接的运行在手机上面, 因为电脑里面运行的软件,其实是基于x86 架构的指令来实现的 而手机里运行的那些软件是基于m架构所支持的另一种指令集来实现的,那前段时间苹果的开发者大会上,苹果公司宣布说接下来苹果自己的电脑会逐渐的抛弃英特尔的 ,这个芯片转而会使用他们自己设计的基于arm架构的cpu 那这样的转换就意味着在未来苹果电脑上很有可能会支持苹果的手机上的各种各样的应用, 可以直接在他们家的电脑上运行。因为手机里的各种软件使用的就是arm架构下的 各种各样的指令级 cpu所能支持的指令级应该怎么设计,这个问题我们会在计算机体系结构内门课里着重来探讨 ,那在计算机组成原理这门课里,我们只会简要的了解关于指令设计所需要考虑的一些问题 好 那这是指令的定义 注意指令级和指令系统这个概念.

好 那经过之前的复习 我们可以知道 一条指令在逻辑上可以被划分为操作码和地址码这样的两个部分
在这里插入图片描述

根据地址码数目分类

操作码指明了用户想要让cpu干什么 ,而地址码又指明了这个操作是要对谁进行的,那像刚才我们提到的 ,停机指令是不需要地址码的, 而比如说求加减乘除,这一类的指令需要指明两个操作对象, 因为有加数被加数 减数被减数。
因此, 由于各种各样的指令所需要执行的操作不一样 ,那么地址码的数目也有可能会出现变化,那么根据一条指令到底包含了几个地址吗 我们可以给指令进行一个分类:零地址指令,一地址指令, 二地址指令, 还有三地址、四地址指令,接下我们来依次看下这几种指令

零地址指令

首先看零地址指令,顾名思义就是只需要给出一个操作吗 而不需要给出地址码的指令。
在这里插入图片描述
那通常有两种情况 我们可以用到零地址指令。

(1) 第一种情况就是不需要操作数的一些操作

比如说我们之前提到的停机操作 ,另外学过操作系统的同学应该听过关中断指令 ,当然 关中断指令相关的内容我们还会在计组这门课后续章节学习。然后还有就是空操作指令, 执行这个指令就是什么也不干,总之,有的类型的指令是不需要指明操作数的。

(2)第二种情况有可能遇到零地址指令的是某些堆栈型的计算机当中有可能会把操作数隐含在栈顶和次栈顶, 然后计算的结果会被我们压回栈顶。也就说 ,对于这种情况, 我们并不是不需要操作数, 而是操作数会固定的隐含在某一个特定的位置。那关于这个问题 ,如果大家之前已经学过数据结构 ,那么我们在数据结构那门课里讲过一个东西叫做后缀表达式。堆栈型的计算机进行算术运算的时候,通常就是基于后缀表达式来进行运算的。

这个地方简要的提一下 ,这是我们平时熟悉的中缀表达式 那我们可以把中缀表达式转化为与之相对等的后缀表达式
在这里插入图片描述
那对于一个后缀表达式来说 我们会从左往右扫描各种各样的操作数 还有操作符
在这里插入图片描述

那站在计算机硬件的角度来看 ,大家可以理解为每一个操作数存放在一个主存单元当中。每一个操作服其实就是对应了一条零地址的指令,同样也是被存放在主存里边。那么 当cpu读入的是一个操作数的时候 ,这个操作数会被压到栈顶
在这里插入图片描述
而当cpu扫到一个操作符,也就是扫描到一个零地值指令的时候 他就会把栈顶的两个元素执行相应的算数运算,再把运算的结果压回栈顶, 然后再继续往后扫描 ,扫描到操作数就把它压到栈顶。
在这里插入图片描述

扫描到操作符也就相当于扫描到了一个零地址的指令, 这个时候就会把两个栈顶元素弹出,把他们运算的结果再压回栈顶, 总之用这样的方式就可以得到后缀表达式的一个运算结果
在这里插入图片描述

那这就是堆栈型计算机通过零地址指令来进行算数运算的一个基本原理。就是说,我们的操作数是隐含在这个栈里边的 而不会显式的在这个指令当中指明,那这是零地址指令, 接下来看一地址指令

一地址指令

有这样的几种情况 可能会遇到一地址指令:
在这里插入图片描述
(1)第一种情况
当我们需要进行的这个操作只需要一个操作数, 比如说某一个数的加一减一,或者求他的反码 、补码这些运算, 就是说只需要一个操作数就可以完成, 那么对于这一类的指令来说 ,他的含义是这样的:

cpu首先会从A1 所指向的主存单元当中取出相应的数据,然后对这个数据执行OP也就是操作符所指明的相对应的操作,(就是求反码 、补码之类的操作) 然后得到运算结果之后再把运算结果放回A1所指向的这个主存单元。
在这里插入图片描述

对于上面这种记录方式,A1表示的是一个主存地址,而A1的外面打了一个括号 ,指的是我们把A1所指向的地址当中的内容给取出来了。有点类似于c语言里的指针 ,还有指针所指向的内容,这样的一个关系 。

那经过刚才的分析 ,我们知道执行这样的一条指令,需要进行三次仿存 :
①第一次仿存就是从主存当中取出这一条一地址指令;
②第二次仿存就是根据A1所指的这个内容(地址), 去读出A1这个地址所对应的主存单元存的数据;
③第三次仿存就是得到了运算结果之后把运算结果再给写回A1

所以整个过程进行了三次仿存,这是第一种有可能会使用到一地址指令的地方。
在这里插入图片描述

(2)第二种情况 ,有时候我们的一地址指令, 也许这个操作他也需要两个操作数。但是其中的某一个操作数会隐含在某个寄存器当中 ,就比如我们在开头提到的 我们之前学习过的那个例子,其中一个操作数会由地址码显式的指明, 然后另一个操作数会隐含在acc累加寄存器当中,那大家也可以回顾一下之前这张ppt 比如说乘法操作, 他就是把乘数b用地址码(0000000110=6)显式的指明它是存放在主存地址6这个地方, 然后另一个被乘数已经默认存放在acc累加寄存器里面了
在这里插入图片描述
这一类的指令所需要做的事情就是把acc累加寄存器里存放的数据,还有A1所指明的地址当中存放的数据进行相应的操作运算 ,然后把运算的结果再给存回acc累加寄存器当中,所以 ,整个过程完成这样的一条指令只需要两次仿存:
(1) 第一次仿存就是从主存当中取出指令;
(2)第二次仿存就是根据A1所指向的这个地址去主存当中读出这个操作数

由于最后是把运算结果存回了这个acc累加寄存器当中 ,所以存结果这个过程不需要仿存。

这就是一地指指令。 接下来再看二地址指令。

二地址指令

二地指指令通常会用于需要两个操作数的某些与算术运算或者逻辑运算相关的指令。
在这里插入图片描述
就是说 a一和a二这两个地址码会分别指明我们需要进行运算的两个操作数分别存放在哪个位置,然后把这两个操作数取出之后 ,运算的结果会被存回a一,因此执行这样的一条指令需要四次访存。
(1)第一次就是取出指令;(取指)
(2) 第二次是去访问a1所指向的地址;
(3) 第三次是去访问a2所指向的地址;
(4)之后得到运算结果 ,再把运算结果写回a1。

三地址指令

在这里插入图片描述
三地址指令和二地址指令非常类似, 二地址指令当中我们会把最终的运算结果默认存回a1所指向的那个地址, 而三地址指令当中, 我们会显式的给出最终的运算结果要存放到什么位置。
所以一条三地址指令的执行是这样的:
(1)首先 ,我们会取出这条指令;
(2)接下来, 读出a1和a2所指向的两个存储单元内容, 这里进行了两次仿存;
(3)然后把这两个操作数进行相应的算数逻辑运算 ,之后得到的结果会被我们写回a3所指向的主存单元当中.
一共四次访存。

四地址指令

在这里插入图片描述

接下来再看最后一种四地址指令, 一条四地址指令的执行 总共需要进行四次的仿存:
(1)第一次仿存是取出这条四地址指令;
(2) 第二次仿存取出a1所指向的那个操作数;
(3)第三次会取出a2所指向的那个数 ;
(4)然后进行相应的运算 ,之后会把运算结果写回a3所指明的主存单元当中.

那可以看到 前边这些步骤其实和三地址指令是一模一样的, 只不过在最后还会进行这样的一步操作:
正常的普通情况,cpu在每一次取完一条指令之后, 都会让程序计数器pc的值加一,让它不断的指向下一条指令, 而对于四地值指令来说, 执行完这一条指令之后,我们会把程序计数器pc的值修改为a4所指向的那个地址。也就是说a4所指明的, 是下一条我们应该执行的指令的地址。

同样的结合之前我们这个例子并不难理解 之前我们介绍的这个例子当中 ,每一次cpu取出一条指令 取出一条指令之后 都会让pc程序计数器的值加一,指向下一条指令的地址。

而对于刚才提到的四地址指令来说 ,cpu执行完一条指令之后 ,并不是让这个pc的值简单的加一,而是会让pc的值修改为a4所指向的位置。这样的话 ,我们就可以让指令跳着执行, 而不是顺序的执行。

在这里插入图片描述
那接下思考这样的一个问题 ,地址码的位数对我们的指令执行会有什么影响呢?通过之前那个例子, 可以看到 ,我们的地址码是指明了某一个主存单元的地址,也就是说 ,如果地址码只有n位的话, 那么n位地址码可以指明的地址范围就应该是二的n次方这么多个储存单元。所以, 地址码的位数越长, 就意味着我们的这个指令 ,它的寻址能力、寻址范围也会越强。因此, 如果我们规定指令的总长度固定不变,那么地址码的数量越多,就意味着每一个地址码的位数n就越短, 就会导致指令的寻址能力变差。

好的, 目前为止, 我们按照地址码的数目对指令进行了一个分类 ,分别是零地址 一直到四地址这么多种指令。
在这里插入图片描述

大家可以在结合这个ppt来回顾一下。 接下我们再来按照指令的长度对指令的格式进行一个分类

根据指令长度分类

首先引入一个术语, 指令字长, 指令字长其实就是指令的总长度。
在这里插入图片描述

我们到目前为止学习了什么叫机器字长, 什么叫存储字长,然后这儿我们又接触了一个很相似的概念,叫做指令字长 ,那值得一提的是, 机器字长通常是和cpu有关,一台计算机的机器字长是固定不变的,而存储字长通常和主存有关 ,一台计算机的存储字长也是固定不变的,但是一台计算机的指令字长是有可能会发生改变的, 比如大家可能会遇到这样的一些描述,半字长指令 ,单字长指令, 双字长指令, 那这种描述方式指的是一条指令长度是机器字长的多少倍。

显然指令字长会直接影响到我们取指令所需要的时间,比如说一台计算机, 它的机器字长和存储字长都是16bit,也就意味着,每一次从主存当中读或者写的字节数就是16个bit, 那么在这种条件下,我们要取一条双字长的指令 也就是总长度32bit的指令 ,那么我们就需要进行两次访存,所以这就直接影响到我们取指令所需要的时间 。这就是指令字长的概念。不同指令的指令字长有可能是不一样的,那大家需要注意这三个概念之间的区别和联系。

有的计算机当中指令系统里边所有的指令长度,都是相等的,如果采用这种策略, 我们可以称这个计算机采用了定长指令字结构,而如果说某一台计算机它所支持的各种指令长度可以不相等的话 ,那么我们就称这种计算机它是变长指令字结构,这就是按指令的总长度对指令格式的一个分类。

根据操作码长度分类

在这里插入图片描述
一条指令由操作码和若干个地址码组成,操作码的长度有可能是不一样的,如果说整个指令系统当中所有的指令操作码的长度都相同 ,那么我们就称这一类的指令系统是定长操作码的指令系统,而如果说不同的指令操作码的长度比特位不一样的话 ,那么这种指令系统就称为可变长操作码的指令系统,显然 ,操作码的位数可以直接反映这个系统当中最多可以支持多少条指令,比如, 对于一个定长操作码系统来说, 如果它的操作码固定是n位 ,那么这就意味着这个系统最多只能支持二的n次方这么多条指令,这个应该很好理解。

那这种操作码的长度固定不变的这种指令系统的控制器,其译码电路设计起来会更简单一些 ,但是指令的设计灵活性会比较低,而可变长操作码刚好相反。 可能会导致控制器的译码电路设计会更复杂,但是指令设计的灵活性又会比较高 。

那在下一小节当中 ,我们会学习一种定长指令字结构, 也就是说指令的总长度固定不变, 但是操作码的位数可以改变的一种指令系统的设计方式, 也就是所谓的扩展操作码指令格式 ,这是我们下一小节会学习的内容,以上就是按照操作码的长度是否可变对指令格式进行的一个分类。

根据操作类型分类

我们再看指令的最后一种分类,按照操作类型分类。

数据传送类

第一种就是数据传送这种类型 ,进行主存与CPU之间的数据传送,比如说我们在之前例子当中遇到过的取数指令,LOAD这一指令就是把存储器主存当中的某个数据加载到某一个寄存器当中,也就这个地方,零这条指令
在这里插入图片描述
这条指令实现了数据从主存到寄存器的一个一个传送。
而三这条指令又实现了我们把寄存器里存的内容传送到某一个主存单元:
在这里插入图片描述
所以这就是实现数据传送这种操作的指令。

运算类

实现了算术运算、逻辑运算、移位运算。

算术、逻辑操作

第二类的操作指的是我们可能会用到算术运算或者逻辑运算,那算术运算就是加减乘除, 逻辑运算就是与或非异或这些运算, 这类的操作大家比较熟悉。

移位操作

第三类的操作就是移位操作, 其实移位操作也可以把它归为逻辑操作的一种 关于移位操作如何实现 ,我们在第二章里面也具体的探讨过,包括算数移位、 逻辑移位、 循环移位。 如果不记得可以再回去复习一下第二章内容。

程序控制类

第四种类型程序控制类,这类指令会改变程序执行的顺序。(转移操作)比如无条件转移指令jump ,还有就是某一些有条件的转移指令,另外还有函数调用,函数返回 ,还有陷入指令trap指令, 这些指令实现的都是转移类的操作,本质上这一类的指令实现的就是程序执行流的一个变化, 正常来说 ,我们的程序是一条一条指令顺序的执行的,但是我们写程序的时候 ,难免会遇到if else或者说某一些函数调用之类的情况,那么 ,在这种情况下程序的执行流就不是顺序的, 有可能会发生跳转, 所以转移类的指令就是用来实现程序执行流的改变 。

执行这一类的指令最终会导致程序计数器pc的值发生改变,因为程序计数器指明的是下一条指令的一个存放地址, 所以要改变程序的直行流, 那么本质上其实就是改变pc的一个值 。

输入输出操作

最后一类的操作叫输入输出操作,就是进行cpu寄存器和i o端口之间的一个数据传送,所谓端口就是IO里的寄存器,这个问题具体会在最后一章进行学习。 总之这一类的操作就是实现了cpu和lO之间的一个数据交换,。

三、总结

在这里插入图片描述
这个小节当中, 我们介绍指令的基本格式, 一条指令可以由一个操作码还有若干个地址码组成,地址码的数量有可能有0-4个 ,我们可以按地址码的数目不同对指令的类型进行一个分类,也可以根据指令系统当中所有的这些指令总长度是否相同把指令系统分为定长指令字结构还有变长指令字结构这样的两种,接下我们还可以根据操作码的长度是否可变 ,把指令系统分为定长操作码,可变长操作码两种指令系统,最后我们还可以根据指令的操作类型不同,对指令进行一个分类 ,分为数据传送类 ,运算类还有程序控制类和输入输出类 ,那下写节当中我们会基于定长指令字结构 还有可变长操作码,基于这两个条件来设计一个简单的指令系统,以上就是这一小节的全部内容。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值