指令构成

指令是由指令集架构定义的单个的 CPU 操作,指令包括一个操作码和地址码,操作码用来指示这条指令执行什么任务,地址码用来表示这条指令作用的对象的所在位置。

下面是对于指令的基本分析:

定长操作码很简单,按照指令数量的最大长度编号即可,但是地址码不是定长的,所以这样的话虽然操作码定长了,但是整体的指令不会定长。

而变长操作码,下面的图就是规划变长操作码对应不同数量的地址指令的一种方式,通过让操作码变长来适应不同长度的地址码,从而让整个指令定长:

251.jpg

指令寻址

指令寻址指的是 CPU 去获取指令的方式,目前来说有两种寻址模式,分别为顺序寻址和跳跃寻址。

顺序寻址:借助于 PC (Programme Counter) 不断的地址 +1 实现的,实现也很简单,只需要将所有要执行的指令按照顺序在内存中放在一起即可。

跳跃寻址:当遇到跳跃指令的时候,往往会给出要 PC 跳到的指令的地址,就需要修改 PC 里面的内容,然后跳到对应的地址读取指令。

数据寻址

数据寻址方式就是指令在计算机中寻找要操作的对象的过程,有很多种:

大概的图:

立即寻址

立即寻址指形式地址 A 表示的就是操作数本身,也就是立即数,用补码表示,常用于常量的操作。

比如 C 语言里面写 X=2+5; 那么这条代码执行背后的指令一定是使用立即寻址的,不需要去内存中寻找数据,操作码后面就跟着数据 2 和 5 ,速度相当快,只需要访问一次主存即可。

但是这样就会导致数据可表示范围大大缩小,毕竟操作码占用了不少地方。

直接寻址

直接寻址:指的是地址码表示的就是数据在内存中的实际地址,直接按照地址码的标识去内存中找就可以拿到数据了。

间接寻址

间接寻址:指的是地址码表示并不是数据的地址,数据地址的地址。

需要先根据地址码表示的地址从内存中拿到另外一个地址,这个地址才是数据的真实地址,所以叫作间接寻址。当然间接寻址也分间接多少次,可以是一重间接寻址,二重间接寻址等等。

寄存器寻址

寄存器直接寻址

和直接寻址唯一不同的就是,它的地址表示的不是内存的地址,而是寄存器的地址,这样可以以最快的数据获取想要的数据。

寄存器间接寻址

和间接寻址唯一不同的就是,它的地址表示的不是内存的地址,而是寄存器的地址,这样可以以最快的数据获取想要的数据。

隐含寻址

就是可以通过操作码推断出来所需要的数据在什么地方,比如加法指令,相加是需要两个输入数的地址和结果写入的目的地址一共三个。但是因为加法器的设计就隐含了其中一个输入数就在 ACC 中,结果写入目的地址也在 ACC 中,所以因为隐含了两个的寻址,最终只需要一次寻址即可。

252.jpg

偏移寻址

偏移寻址指的是地址码里面表示的地址都需要进行加法运算才可以获取到真正的地址,优点就是可以扩大寻址范围,并且用户不需要关心自己的实际地址在哪里,只要有相对于某个地址的偏移量即可。

相对寻址

相对寻址,会直接在地址码的地方给出偏移量,这个偏移是相对于当前指令的下一条指令的地址做偏移的,因此会将偏移量和 PC 中的当前地址送入 ALU 中进行相加,获取真实地址。

之所以是下一条指令的地址的原因是 PC 在取出当前指令之后,会将自身的内容自动加一,所以实际上从 PC 中取出来的东西是当前执行的指令的下一条指令的地址。

254.jpg

基址寻址

首先先引入一个寄存器,基址寄存器(BR),里面存放的地址将作为基准地址。首先基址寻址的地址码表示一个偏移量,用补码表示,寻址的时候会将偏移量和基址寄存器一起放进 ALU 中执行加法运算。然后获取的结果作为一个内存地址去寻找操作数。

当然用通用寄存器代替基址寄存器也是可以的,那么就需要在地址码里面多加一个寄存器编号了,指明去哪个通用寄存器中寻找基本地址。

改变址寻址

首先引入一个寄存器,变址寄存器(IX),里面存放偏移量,而操作码里面的地址 A 表示基本地址,和 IX 里面的偏移量进行相加运算之后,获取真实地址。

253.jpg

这玩意和上面的基址寻址基本相反,里面的变址寄存器是用户可控的,常用于遍历数组,将 A 作为数组首地址,不断迭代基址寄存器,就可以快速遍历整个数组了。

堆栈寻址

属于隐含寻址的一部分,它隐含了地址为堆栈指针(StackPointer)的地址,没啥可讲的。

CISC 和 RISC

Complex Instruction Set Computer 复杂指令集:X86。

复杂指令集的设计思路就是让一条指令执行一个复杂的任务。因此有以下特点:复杂庞大,指令不定长,不太好实现指令流水线。

Reduced Instruction Set Computer 精简指令集:RISC。

精简指令集的设计思路就是让一个复杂任务被多条指令执行。因此有以下特点:简单精简,指令定长,必须实现指令流水线。