系列文章目录
1.《带你深挖计算机底层逻辑,打通你计算机基础知识的任督二脉》
2.《深度学习计算机底层原理,深度剖析存储器》
3.《基于内存全面理解高速缓冲存储器》
4.《深度学习计算机指令系统,彻底搞懂指令十大寻址方式》
文章目录
前言
我在之前的文章专栏已经系统地为大家讲解了计算机最基本的组成框架、存储器、高速缓冲存储器,计算机的下一个重要部分就是CPU了,可是再介绍CPU之前,我们不得不先介绍一下计算机指令系统,因为这个可以说是使得计算机正常运转的核心,我们也可以借助指令系统对于之前的给大家讲解的内容也是一种巩固。
但是在这里还是要提醒各位老铁一下,计算机底层原理进行到这里的时候,我们对于计算机底层原理就应该有了一个很清晰的认识了,也就是说要想把指令系统学会对于计算机最基本的框架应该构建起来了,我们应该已经达到了对于计算机的每一个部件,他们的功能,以及在主机当中的位置结构有了一个非常清晰的认识了,如果还没有的话,建议各位老铁先到我之前的文章去看看,对于计算机系统的组成有了一个初步的了解之后,再来学习指令系统,否则将很难学懂指令,因为今天的这篇文章要涉及到大量的与主存、寄存去的相关知识,如果对于这些不了解的话,则很难理解,今天的内容。
一、指令格式
概述:指令也就是机器指令,或者说是一种命令,他是用来指挥计算机完成某称操作的命令,一台计算机上的所有指令构成计算机的指令系统,也称指令集,指令系统是计算机的主要属性,位于软件和硬件的交界处。
1.指令的基本格式
注意:每一条指令都有其相应的运算形式,并不是每一条指令都适用于每一种情形的运算,这个一定要很清楚,比如说我们平常所见的算术运算指令和逻辑运算指令都是用而地址指令来运算的,那么其他指令是用来干什么的呢?接下来为大家讲解。
操作码字段****地址码字段
一条指令就是计算机语言的一个语句,他是一组有意义的二进制代码,一条指令通常包括操作码字段和地址码字段两个部分,其中操作码是用来指出指令应该执行什么样性质的指令一句指令具有何种功能,通俗的来讲,你是想要执行加法指令还是减法指令还是要返回一个数,这些最基本的信息必须告诉CPU,而这些信息就是操作码携带的。
地址码给出操作数的地址、运算结果的地址,程序的转移地址等等。
指令的长度是指指令所含二进制代码的位数,而指令字长取决于操作码的长度、地址码的长度以及地址码的个数。
注意:这里的地址码时代表操作数的地址,也就是要进行运算所需的数据的地址,而并非操作数本身。
**1.零地址指令:**
OP(操作码、但没有地址码)
之所以存在零地址指令是因为,有些操作他本身就是不需要操作数的,例如空操作指令、停机指令、关中断指令等等。
还有另外一种情况,因为零地址指令的运算尽在堆栈当中进行,通常参与运算的两个操作数隐含地从栈顶和次栈顶的位置弹出,送到运算器进行运算完成以后,运算的结果还会放回到对堆栈当中。所以操作码的地址就是默认的——堆栈当中的栈顶和次栈顶两个位置,所以就不需要给出地址码。
**2.一地址指令:**
OP(操作码)****A1(地址码)
1):第一种情况时按照A1地址从内存当中读取操作数,进行OP操作以后,结果还会存放会原来的地址当中去,相当于把原来的数据给破坏了(OP操作数代表着指令的类型,这里不说明具体指令的类型统一用OP操作来代替诸如加法指令、减法指令等多条指令) 。
OP(A1)->A1;
**详解: **
2):隐含了目的地址的双操作数指令,也就是说指令的操作需要两个操作数,但是指令当中只提供了一个地址码,显然还有一个操作数不由指令来提供,那怎么办呢?这个时候就需要用到CPU当中ALU(算术逻辑单元)中的ACC累加寄存器,一个隐含操作数地址会放到ACC当中,由ALU进行运算之后的结果,仍然会放到ACC当中。
(ACC)OP(A1)->A1;
指令含义: 可能有小伙伴对于上面所描述的指令(ACC)OP->A1的含义不太明白,现在就为大家进行进一步的说明,你要相信我,这些内容真的特别简单,学不会你打我。
- 首先我来解释一下‘()’的含义(有些计算机指令集用(),而有些则用[ ]来表示,至于他们的区别是什么我们随会介绍),首先他们的含义都是解引用,提到解引用大家都不陌生吧,只要是了解过指针的小伙伴我相信对于解引用这个东西都不会陌生,所以(ACC)的意思就是根据数据存放在ACC里面相应的地址把存放在ACC寄存器里面相应的地址里面的内容给取出来,就是这么简单。
- OP的含义我们刚才其实也提到过了,它用来代表指令的操作类型,这里不具体指明指令要进行哪些操作,所以统一用OP操作来表示。
- 那么这里的(A1)是什么意思呢?A1这里代表一个地址,(A1)就是根据这个地址,把存放在这个地址里面的内容给取出来,说白了他就是一个指针,它的功能就和*A1的功能是一样的。
- 所以(ACC)OP(A1)->A1的含义就是把第一个操作数从ACC当中取出,第二个操作数从A1这个地址取出,然后两数进行OP操作,结果存放到A1这个地址里面去,'->'是赋值的意思。
- OP(A1)->A1这条指令的意思也很简单,就是把A1地址存放的数据取出来进行OP操作以后再存放到A1地址里面去。
- 这些指令的基本根式一定要非常清晰,首先你一定要知道‘()’是解引用,->是赋值的意思,因为我们马上就要学习指令的寻址方式,如果这些没有搞懂的话,后面很难有进展。
** 3.二地址指令:**
OP(操作码)A1(地址码)A2(地址码)
特别提醒: 给大家补充一个非常重要的知识点,就是指令字长为四个字节,32位比特位(1byte==4bit),而操作码要占用一个字节,所以剩余的其他位数就是地址码字段,地址码字段所占的位数就代表着他的寻址范围例如但地址指令,地址码占24位,所以寻址范围就是2^24。
1)常用来算数运算指令和逻辑运算指令 往往要求使用两个操作数,分为源操作数和目的操作数,目的操作数就是运算结束以后的结果存放在目的操作数,但是原来的目的操作数里面存放的数据就会被覆盖。
(A1) OP (A2)->A1;
指令含义:相信大家到这里的时候就已经都能够明白这条指令的含义了吧,把目的操作数从A1地址出取出来,把源操作数从地址A2出取出来进行OP操作运算以后把运算的结果再放回到A1当中,这里的A1、A2都代表地址,(A1/A2)就代表着对这两个地址解引用,把存放在此处的地址的值取出来。
当然往后还有三地址指令、四地址指令不过这些都是大同小异,就不在此处做过多的说明了。
2.指令的操作类型
注释:这些指令都是汇编常见指令,需要大家掌握理解并且记忆,记忆的时候要根据他们的英文含义去记忆,不要死记硬背。
- 数据传送:MOV()寄存器之间的操作、LOAD(从内存单元读取数据存放到相应的寄存器)、STORE(从CPU的寄存器将数据写到内存单元)。
- 算术和逻辑运算:ADD(加法指令)、SUB(减法指令)、CMP(比较指令)、MUL(乘法指令)、DIV(除法指令)、AND(逻辑与)、OR(逻辑或)、XOR(逻辑异或)、INC(加一操作)、DEC(减一操作)。
- 移位操作:算术移位、逻辑移位、循环移位等。
- 转移操作:JMP(无条件跳转指令)、CALL(调用指令)。
- 输入输出操作:用于完成CPU与外部设备交换数据或传送命令及控制信息。
操作码扩展技术:
有些时候我们在指令字长有限的前提下要保证指令的多样性,这个时候就需要对指令进行扩展操作码,操作码扩展那么地址码就会随之减少。
不过对于程序员来说,这些我们并不需要掌握,只需要理解其基本原理即可,如果又想要考研的小伙伴,可以自行学习。面试的过程当中是肯定不会涉及到的。
二、指令的寻址方式
温馨提示:指令的寻址方式是整个指令当中最重要也是最难的一个环节,这对于我们后续《深度理解CPU》的学习至关重要。不过大家放心,既然我敢拿出来讲,那说明我有信心用最浅显易懂的方式保证大家能学会,废话不多说接下来我们进入正题。
序言:
寻址方式是寻找指令或者操作数的有效地址,也就是确定本条指令的数据地址以及下一条指令的地址。 还有特别要注意的一点是,指令当中的地址码字段并不代表操作数的真实的地址,这种地址成为形式地址A,形式地址的意思就是不是操作数本身的地址,而是操作数所在位置的地址,我这么说大家能够理解吗?如果还是不能够理解的话,我可以这么说,比如你坐在公交车上那么公交车的地址就是你的形式地址,那么你在公交车上的作为就是你的真实地址,要是这么说的话,我表述清楚了吗? 形式地址结合寻址方式,才能够计算出操作数在寄存器中的真实地址,这种地址成为有效地址EA(effectively address),他仅仅只是一个英文单词的缩写而已,没有什么其他的含义了。 还要特别注意(A)是地址A这个存储单元里面的数值,当然这个数值仍然还有可能是一个地址,这就好比一个二级指针,那么A既可以某个寄存器、也可以是内存地址,那么对应的(A)就是寄存器当中存放的数值或地址,还可以是相应的存储单元的数值。 EA=(A)的意思就是有效地址是A当中的数值,那么如果EA=A呢?那么代表着指令当中的地址码字段就是有效地址。
1.指令寻址和数据寻址
**1.指令寻址:**
1)顺序寻址:通过程序计数器PC+1(这里的1代表一个指令字长,一个指令字长为4个字节,所以有些时候看到有些教材上面写着PC+4的时候,也不要感到奇怪)。
2)跳跃寻址:很好理解就是不按照顺序来进行寻址,在计算完当前指令以后,会有当前指令自动计算下一条指令的位置,PC+A(偏移量),跳跃寻址的地址分为相对地址和绝对地址。
补充:相对地址、绝对地址
** 绝对地址:**绝对地址其实就是数据准确的地址,比如说山西省太原市尖草坪区学院路三号中北大学这就是绝对地址。
** 相对地址:**相对地址就是以某地址为参照进行寻址,比如说同样是中北大学,我可以这么说上兰村对面,以上兰村为基址进行寻址。
** 2.数据寻址:**
** *数据寻址就是在指令中表示一个操作数地址,由于数据寻址的方式有很多,为了区别这几种方式,通常在指令当中设计一个字段,由此来指明属于哪种寻址方式,由此可得指令的格式如下。
操作码寻址特征*形式地址A
那么数据寻址的方式到底有多少种呢?接下来我们就来谈一谈这个问题。
2.常见的数据寻址方式
** 1.隐含寻址:**这种类型的指令不会直接给出操作数的地址,而是在指令当中隐含操作数的地址,可能这样理解比较抽象,比如说我们之前介绍过的但地址指令就属于隐含寻址,他只给出了一个操作数的地址,而由ACC累加寄存器作为第二个操作数的地址,所以ACC对于但地址指令的格式来说就属于隐含寻址。
详解:以ACC累加器的隐含寻址为例,我们来讲述一下隐含寻址的具体原理和形式到底是怎样的,具体过程如下图:
**具体流程: **
- 首先CPU根据指令当中的地址码字段,找到主存当中的相应的存储单元,从存储单元取出操作数,那么这个时候还缺少一个操作数,由ACC完成。
- 主存通过数据总线将第二个操作数存放到CPU当中的ACC里面,再由ACC提供第二个操作数。
- 这个时候由主存当中的操作数和ACC当中提供的操作数同时提供给ALU,注意必须是同时提供给ALU,ALU才可以对两个操作数做运算(至于为什么是同时提供给ALU,这个我们会在后续的文章里面《深度理解CPU》当中为大家细心讲解)。
- 这个时候ALU计算出结果以后将结果放到暂存器当中(可能又会有小伙伴会问为什么要放到暂存器,这个同样在后续的文章当中《深度理解CPU》当中为大家讲解)。
- 这个时候运算结果从暂存器当中取出以后会再次放到ACC当中。,这个时候就完成了隐含寻址的全部过程。
** 2.立即(数)寻址:**这种类型的寻址的指令当中的地址码字段不在存放操作数的形式地址,而是直接存放操作数的本身,这种数就叫做立即数,他在计算机当中采用补码表示(至于为什么要用补码来表示,小伙伴们可以去了解一下原反补和数据的大小端,就很清晰了),这种指令的运算就很简单了,也不用访存,直接从地址吗字段的位置把操作数给取出来,然后在放到ALU当中,算完以后再放回来。
** 3.直接寻址:**直接寻址其实就是,指令的地址码字段存放的不再是形式地址了,而是操作数的真实地址,即EA=A。
**详解: **
- 根据指令当中的地址码字段存放的操作数的真实地址(主存当中的存储单元的地址)把操作数取出来以后送往ACC累加器,注意这里送往累加器并不是一定的,只有单地址指令并且是ADD运算的时候才需要,从主存当中取出来以后至于具体要送到哪里,还要看指令的类型。
- 但是这样的寻址方式有一定的缺点,就是直接将有效地址放入地址码字段是很难修改的,万一想要变换操作数,这是一件很麻烦的事情。
** 4.间接寻址:**
间接寻址是相对于直接寻址的,间接寻址给出的地址码字段并不是有效地址,而是形式地址,也就是操作数所在的存储单元的地址,也就是操作数地址的地址(二级指针)。间接寻址可以一次间接寻址,也可以多次间接寻址。
**详解: **
- CPU根据操作数的形式地址,去主存当中找到存储单元的地址也就是有效地址,这个时候再根据有效地址取出操作数本身即可。
- 他的缺点就在于需要多次访存,对系统的损耗很大。
** 5.寄存器寻址:**寄存器寻址和之前的一个区别就在于操作数不在内存当中而是在寄存器当中,所以指令的地址码字段存放的并不是形式地址,而是寄存器的编号即EA=Ri(register是寄存器的意思)。操作数直接从寄存器当中取出操作数以后进行运算,运算结束以后在放回到寄存器当中去即可。
**6.寄存器间接寻址:**这种寻址方式对应的是前一种寄存器寻址,他唯一的变化就是,寄存器当中不在是存放操作数了,而是操作数在内从当中的地址了,这肯定比普通的间接寻址要快,但是指令的执行阶段仍然需要访问主存,毕竟操作数还在主存当中。
**7.相对寻址:**相对寻址就是相对于当前的指令,给当前的指令一个偏移量,即EA=(PC)+A,(PC)是指PC(程序计数器、用于存放当前指令的有效地址)当中当中的存放的有效地址加上一个偏移量就是操作数的有效地址。
** 8.基址寻址:**EA=(BR)+A,它是由基址寄存器当中存放的内容再加上指令当中的形式地址A共同作用下形成操作数的有效地址,在这里还是要强调一下,这里的有效地址是经过基址寄存器和形式地址经过ALU算术逻辑单元运算出来的有效地址,并不是凭空产生的,具体实现原理如下图所示。
**详解: **
- 在程序的执行过程当中基址寄存器当中的内容是不会发生变化的,这也就是基址寻址的名称的含义,但是形式地址A确实是可以发生变化的,这里的A作为偏移量,通过对A的改变以此来查找有效地址。
- 基址寄存器是面向操作系统的,他又操作系统或管理程序来确定,它的主要功能就是用来解决逻辑地址和物理地址的无关性的,简单地说就是把逻辑地址转换为物理地址,要知道在虚拟存储器当中操作系统会给我们提供一个比真实地址内存空间大得多的内存空间,所以也会给我们提供一系列的逻辑地址,二基址寄存器就是专门解决逻辑地址和物理地址的无关性的,通过逻辑地址依然可以找到操作数的真是物理地址。
- 他的一个最大的优点就是可以扩大寻址范围,用户不必考虑自己的程序存在于主存当中的哪块空间,有利于多道程序设计,但是他的偏移量的位数比较短。
**9.变址寻址:**变址寻址是基于变址寄存器和指令字当中的形式地址的内容之和即EA=(IX)+A,IX是变址寄存器,当然也可以用通用寄存器来作为变址寄存器(要不怎么叫通用寄存器呢)。
** 详解: **
- 基址寻址是面向用户的,在程序执行过程当中变址寄存器当中的值是可以改变的(作为偏移量),反倒是指令字当中的形式地址A不可变(作为基址)。
- 他的一个巨大的优势就在于可以扩大寻址范围,就比如在数组的处理过程当中可设定A为数组的首地址,不断地改变变址寄存器的值,便很容易地形成数组当中任一数据的地址,而且IX的位数足以表示整个存储空间的地址。
- 其实我讲到这里大家也能够发现,基址寻址和变址寻址的区别在哪里,前者的寄存器当中的内容是由操作系统来确定的,不可变但是形式地址A可变,而后者的寄存器确实有用户程序员来确定的,寄存器当中的内容可变,但是形式地址A不可变。
** 10.堆栈寻址:**堆栈其实就是存储器(或者专用寄存器)中一块特定的,按照后进先出的原则管理的存储区,该存储区当中的读/写单元的地址是用一个特定的寄存器给出的,该寄存器成为堆栈指针(SP),其实就是起到一个类似于指针的作用,按照一定的次序先后存取内从当中的数据,并且保存当前正在访问的内存区域,可以把它比喻成一个指针。SP通常都是从栈区的顶层向下访问的,所以当出栈的时候SP+1,这个和我们平时所理解的操作正好是相反的。
三、CISC和RISC的基本概念
- 指令系统朝着两个截然不同的方向发展,一是增强原有的指令功能,设置更为复杂的新指令实现软件的硬化,这类机器成为复杂指令系统计算机(CISC),最典型的X86架构的计算机,二是减少指令的类型简化指令的功能,提高指令的执行速度,这类指令成为精简指令系计算机(RISC)典型的ARM、MIPS架构的计算机。
- 但是在使用复杂指令集的时候问题便凸现出来了,指令集在被使用的时候符合二八定律,就是20%的指令约占整个程序的80%。而剩下的多数指令则很少会被系统调用,这才有了后来的精简指令集。
- 对于将来不打算考研的小伙伴来说我们了解这些就已经足够了,如果有老铁想要更细致的了解,可以在《计算机组成原理》这本书上自己去寻觅答案。
总结
今天的内容就到此结束了,到目前为止关于计算机底层逻辑的内容就已经为大家介绍了一半了,说实在话我自己的收获真的很大,通过写博客分享的形式,真的对自己的知识是一个很大的提升,和一个很大的挑战,因为有时候自己学会了知识自己的一个主观感受,在为大家进行讲解的时候曾多次发现自己的知识体系有着很大的漏洞,这个时候通过写博客就是对自己的知识的一种巩固。
下一次将为大家介绍有关CPU的详细知识,这个是整个计算机组成远离当中最难的一部分,也是内容最多的一部分,指令流水、中断屏蔽、微指令等重难点都会在这里有所体现,这对于我来说也是一个重大的挑战,我写博客需要两个小时,但是光整理学习整理这些知识可能就要20个小时不止。本期内容到这里就结束了,我们下次再见。
你的支持就是我最大的动力,请问你学会了吗?
版权归原作者 刘洋邑 所有, 如有侵权,请联系我们删除。