CPU体系架构-RISC和CISC

《CPU体系架构-ARM/MIPS/X86》第一部分,从程序员的角度(也就主要是指令集体系架构ISA),对ARM、MIPS、X86的处理器架构做一个行向的比较,尽量把一些基本概念夯实,常用知识点捋顺。

本节是CISC和RISC的基本区别,先从整体上把握X86(CISC)和ARM、MIPS(RISC)的区别。 Take a look from the height of thousand meters.

很长一段时间,我关于处理器的相关知识,都是大学课程《微机系统原理》中的8086,甚至不涉及到x86处理器。在实际项目或者工作中,更多的却是ARM/MIPS等处理器。所以工作过程中,难免疑惑不解,张冠李戴。为什么很多基本知识在面对ARM和MIPS时不再适用,主要是因为X86属于复杂指令集系统(CISC),而ARM,MIPS属于精简指令集系统(RISC)。

load-store体系结构

RISC使用的是load-store结构。load-store结构的本质,在于RISC技术的CPU只处理(指逻辑,算术运算处理)寄存器中的数据。相反,X86却能够直接处理存储器中的数据。

RISC体系架构的CPU,存储器和寄存器之间的数据交互,由专门的load和store指令负责。存储器是指内存或者Flash(NOR Flash)等可以被CPU直接寻址的存储单元。CPU要将某个地址的数据放入寄存器中,只能够使用load指令;要将寄存器中的值存放到存储器中,只能够使用store指令。

CISC体系架构的CPU对存储器数据操作则要复杂得多。在X86下,数据的传送都是使用MOV指令。MOV指令既负责寄存器和寄存器之间数据的交互,又负责寄存器和存储器之间的数据交互。X86能够直接处理存储器中的数据,而这一点在RISC体系的CPU中是无法做到的。

将存储器单元0x00000020中的数加上8,结果存放到该存储单元中。假设存储单元的地址0x00000020已经存放在寄存器reg中,即reg=0x00000020,下文中,(reg)表示reg地址处的值,即存储单元中的值。下面我们看看在X86下和ARM/MIPS下分别是如何操作的。

X86能够直接处理存储器中的数据, 所以X86直接寻址到存储器地址,将存储器中的值和立即数相加,结果存放到存储器单元中。整个过程使用下面一条指令就可以完成:

add (reg) 0x08 //直接将存储器单元(reg)中的值加0x08,结果仍然存放在该存储器单元中

ARM/MIPS只能够处理寄存器中的数据,所以需要将该存储器中的值用load命令加载到寄存器中,然后对寄存器中的值进行算术运算,最后使用store命令将运算结果送回存储单元中:

ld reg2 (reg) //将存储器单元(reg)中的值加载到寄存器reg2中 add reg2 0x08 //将寄存器reg2中的值加0x08,结果存到在寄存器reg2中 store (reg) reg2 //将寄存器reg2中的值放回存储器单元(reg)中

指令集

RISC指令长度固定。例如对于32位的ARM或者MIPS处理器,所有的指令长度都是32位。对于X86,不同指令的长度却不同。8086的指令编码长度就在1~6个字节范围内。显然,RISC处理器的平均代码长度要比CISC大。这样设计,RISC程序不是更占存储空间吗?确实是这样的,但是RISC指令固定长度,可以实现流水线(pipeline)。

另外,RISC的指令更加简单,简洁。CISC处理器可能为某个特定的操作专门设计一条指令,而RISC处理器却需要多条指令组合来完成这个操作。最明显的例子就是x86拥有专门的进栈,出栈指令PUSH和POP,而MIPS却没有这个指令,而是使用load/store以及add等多条命令组合完成这个操作。

流水线

RISC拥有流水线。每条指令的处理过程被拆分成几个更小、更能够被流水线并行执行的单元。而CISC处理器指令的执行需要调用微代码的一个微程序。

RISC使用固定长度的指令集也是为了实现指令的流水线执行。有关流水线的相关知识,参考《大话处理器》第4章、微架构-处理器的内心世界。

寄存器

RISC拥有更多的通用寄存器,而CISC则都是用于特定目的的专用寄存器。下面简单的说明一下ARM,MIPS,X86的寄存器的情况,建立一个整体了解。

X86处理器,以最基础的,也是现在很多大学课程中学习的8086为例:

  1. 8086的通用寄存器分为通用数据寄存器和通用地址寄存器。
  2. 通用数据寄存器为AX,BX,CX,DX。这4个寄存器都是16位寄存器,每个寄存器可以分为高低8位寄存器使用,例如AX可以分为AH和AL两个8位寄存器。
  3. 通用地址指针寄存器为SP,BP,SI,DI。通用地址指针寄存器只能够使用16位,用于存放存储器段内16位偏移地址值。
  4. 和通用地址指针寄存器相对应,8086还有4个16位的段寄存器,分别为CS,DS,SS,ES。4个16位的段寄存器和4个地址指针寄存器产生20位的地址,用于存储器寻址。
  5. 然后就是状态标志寄存器FR,也是16位。
  6. 最后,就是16位的指令指针寄存器IP,用于存放当前将要执行指令的16位偏移地址。相当于RISC处理器中的程序计数器PC寄存器。

ARM处理器,以经典的ARM7处理器为例:

  1. ARM的通用寄存器分为数据寄存器和程序状态寄存器,在ARM模式下,一共有16个数据寄存器r0~r15,1个程序状态寄存器cpsr。这些寄存器都是32位。
  2. 16个数据寄存器中,r13用作堆栈指针寄存器(sp),r14用作链接返回寄存器(lr),r15用作程序计数寄存器(pc)。

当然,ARM处理器还可能切换到其它的运行模式,寄存器的数目,使用略有不同。

MIPS处理器,以MIPS32指令集的处理器为例,这也是最为成功和经典的MIPS指令集:

  1. MIPS32拥有32个通用寄存器\(0~\)31,都是32位。下面就一些特殊用途的,和X86以及ARM处理器有对比关系的寄存器列举出来。
  2. \(31被用作返回地址寄存器(ra,return address),\)30被用作帧指针寄存器(s8/fp),$29被用作堆栈指针寄存器(sp)。

由上面的对比可以看出,最纯粹的RISC结构处理器MIPS拥有最多的通用寄存器,并且没有程序状态寄存器,也没有程序计数寄存器。作为吸收了RISC和CISC各自优势的ARM处理器,则拥有了程序状态寄存器cpsr,并且把通用寄存器r15当做程序计数寄存器pc。而作为CISC的8086,则除了4个通用数据寄存器外,其它的寄存器基本上都是用作专门用途的。最明显的就是SP寄存器,在ARM和MIPS中,都是使用的通用寄存器当做SP寄存器,而8086则专门设置了一个堆栈指针寄存器。

有关这三个处理器寄存器的详细说明和重要区别,请参考CPU体系架构-寄存器

以上的4点基本上能够概括CISC和RISC的区别。但如果你想要理解以上的区别,你是需要继续大量的学习和思考。如果说现在是从几千米的高空看到了一片森林,那么下面的章节,就带你到森林的各个地方转一转。