指令的编码与译码原理

       指令集是处理器体系架构的重要组成部分。指令集有两个发展方面,包含以X86为代表的CISC(复杂指令集)和以ARM、MIPS为代表的RISC(精简指令集)。CISC的目标是尽可能将经常使用的功能用最少甚至一条指令来实现,因此该指令相应的运行电路往往是复杂的,其側重的是硬件功能的实现;RISC则相反,其是将复杂的运行电路进行分解,即用尽可能简单的多指令去描写叙述该功能,以软件来减少硬件的复杂度,因此RISC对编译器的要求比較高。CISC的指令长度是可变的,运行周期也不固定,而RISC则是定长的、往往都是单周期运行。寄存器多也是RISC的特点。

        本文的重点不在于具体比較RISC和CISC,而是介绍CPU指令的编码和译码。我们都知道CPU的流水线运行过程有取指、译码、运行、訪存和回写(參看博文:CPU指令的流水线运行),但非常多人对于这些步骤的理解都只在概念层面上的,有必要对其进行具体阐述,理解CPU指令的设计和实现。

        我们都知道C语言是对现实问题的解决方法和过程的高度抽象,其语法主要包含数值、逻辑运算和分支控制转移。数值运算就是加减乘除(比較也是减法),逻辑运算就是与、或、非、异或等,分支控制转移包含if/else、for、while等语法。汇编语言是在机器层面上对C语言的理解和建构,其指令相同也包含数值、逻辑运算、分支控制转移,可是一行C语言可能须要多条汇编指令才干实现。同一时候因为指令在内存上,而CPU訪问寄存器要比訪问内存要快得多,所以CPU的运算一般都在寄存器中进行,因此汇编语言一般都须要添加内存和寄存器直接的数据载入/存储指令。CPU仅仅认识二进制输入,所以能够把汇编语言当次硬件层面上的伪代码,其便于开发者熟记,相同是低级语言。

指令的编码就是实现汇编语言到二进制机器码的过程,其是汇编器实现的(编译器是将C语言转为汇编语言)。         如今如果某种简单的CPU仅仅支持4种功能:包含

1)加法 ADD Rd,Rs,Rn , 结果是Rd=Rs+Rn

2)减法 SUB Rd,Rs,Rn , 结果是Rd=Rs-Rn

3)数据传送 MOV Rd,Rs,结果是Rd=Rs

        4)数据载入 LDR Rd,[Rs] ,结构是将内存中以Rs寄存器的值为地址取值赋给Rd

         怎样进行编码呢?

1)首先将指令分为操作码+操作数 两个部分,操作码即代表指令功能,如ADD、SUB等,其在CPU中就代表某种详细的电路,如ADD就代表加法电路,SUB代表减法电路;操作数即是代表功能的输入和输出,相应电路的输入和输出。

2)如今共同拥有4种功能,那至少须要2个比特来进行编码,如00代表ADD,01代表SUB,10代表MOV,11代表LDR;

        3)操作数的编码,如果寄存器共同拥有8个,Rd,Rs,Rn都是当中的一个,即d,s,n的范围是0到7,那至少须要3个比特来编码,如000代表R0,001代表R1,以此类推,111代表R7.

        那要实现以上四种功能指令,总共须要2+3+3+3=11个比特进行编码。如SUB R6,R1,R2,即R1减去R2的值赋给R7,那其编码就是01 110 001 010.

        理解完指令的编码,那指令的译码应该是比較好理解的。取指就是依据当前程序计数寄存器PC(如果硬件电路规定R7就是寄存器PC)的值从内存中取出机器码指令,该机器码的值是01 110 001 010。接下来的过程就是译码,即依据最先的两个比特01送入译码器,选择为减法电路;110即译码选择为R6,001译码选择R1,010译码选择R2. 再接着的就是指令的运行了,运行就是减法单元电路对两个输入(R1,R2)进行运算,将结果赋给R6.

取指和译码都是CPU的控制单元(CU)完毕的,运行是ALU(逻辑运算单元)完毕,能够将ALU看出是非常多种电路的集合。CPU指令的设计和指令编码息息相关。

        ARM和MIPS CPU都是32位字长,因此指令编码是32比特,可以支持和表达很多其它的功能(操作码)和寄存器(操作数)。如ARM体系是r0到r15,因此须要4个比特来表示,当然ARM的寄存器还有组的概念,即CPU在不同的工作模式时看到的寄存器可能是不同的,如r13,r14等。这些译码时不仅须要指令操作数作为输入,还须要当前状态寄存器的值作为输入。

        16位指令集是由于什么产生的呢?是由于相同的一段C语言代码,用16位指令进行编码比32位编码可以节省30%的代码量,代码量越少,那占用的内存就越少,自然成本越低。在MCU领域,一般都是成本敏感的,所以16为指令在MCU领域有很广泛的使用。

         ARM和MIPS的指令设计是以32位为基础进行设计,其运行也是32作为输入的,那怎样在32位指令集中实现16位呢?我们都知道二八原理,即20%的指令的使用率会达到80%,所以我们对这20%的指令(其是32位指令的一个子集)进行编码,自然能够用较少的比特数来进行编码,而在16位指令使用时,我们能够强制要求其仅仅使用一部分寄存器,那自然能够以更少的比特数来进行寄存器的编码。能够将16位指令集看成是32位指令集的一个子集,CPU在译码阶段先将16为指令转化为相应的32位指令,再进行译码、运行。

          ARM的16位指令集为thumb指令集,MIPS的16为指令集为MIPS16指令集。至于32位指令集和16位指令集之间的无缝切换,请參看还有一篇博文:32位和16位指令集模式自己主动切换机制

        







原文地址:https://www.cnblogs.com/lcchuguo/p/4064796.html