处理器的体系结构,理解处理器是如何工作的,能够帮助我们理解整个计算机系统的工作原理。我们研究一个硬件系统是如何执行某种ISA(处理器支持的指令和指令的字节型编码称为处理器的指令集体系结构,Instruction-Set Architecture)指令的。
我们自己定义一个简单的指令集,然后基于指令集设计一个处理器。我们设计出的处理器是基于顺序操作的,每个时钟周期处理一条完整的指令,虽然不实用,但是对于我们理解处理器的体系结构已经足够了!
一. 指令集体系结构
我们自己定义一个指令体系结构,包括可见状态,指令集,指令编码以及异常事件处理。
1.可见状态
可见状态。这里的可见指的是对写汇编代码的人和产生机器代码的编译器可见。
8个程序寄存器,每个程序寄存器存储一个字;
条件码(CC),ZF,CF和OF,它们保存最近的算术和逻辑指令所造成的影响的有关信息;
程序计数器(PC)存放当前正在执行的指令的地址;
存储器保存程序和数据;状态码(Stat)表明程序执行的总体状态,表明是正常运行,还是出现了异常。
2.指令集
指令集中各个指令的简单描述,后面我们将要用处理器来实现这些指令。
4个数据传送指令:irmovl、rrmovl、mrmovl、rmmovl。指明了源操作数和目的操作数,源操作数可以是立即数、寄存器和存储器;目的操作数可以是寄存器和存储器。
4个整数操作指令:addl、subl、andl、xorl。这些指令对寄存器数据进行操作,会对条件码进行设置;
7个跳转指令:jmp、jle、jl、je、jne、jge、jg。根据分支指令的的类型和条件码来选择分支;
6个条件传送指令:cmovle、cmovl、cmove、cmovne、cmovge、cmovg。当条件码满足约束时,更新目的寄存器的值;
此外,call指令将返回的地址入栈,然后跳转到目的地址,call 指令调用一个过程,指挥处理器从新的内存地址开始执行;过程使用 ret(从过程返回)指令将处理器转回到该过程被调用的程序点上;pushl和popl指令实现入栈和出栈;halt指令停止指令的执行;nop为空指令。
3.指令编码
指令的字节编码,每条指令需要用1~6个字节编码。
如图所示,每个格子表示一个四位的二进制数,两个格子表示一个字节,图中的数值为十六进制的数。
指令指示符(icode,ifun),其中,每条指令的第一个字节表示指令的类型,高四位(代码值-icode)是代码部分,低四位(功能值-ifun)是功能部分。当一组指令共用一个代码(代码值相同)时,功能值才起作用。
寄存器指示符(A,B,F),用于指定一个或两个寄存器,对于只需要一个寄存器操作数的指令,将另一个寄存器的指示符设为0xF。8个寄存器都有相应的0~7的标识符(ID),当ID=0xF时,表示,没有寄存器操作数。
常数(valC),该常数可以作为立即数数据(V),地址指示符的偏移量(D)和目的地址(Dest)。
4.异常事件处理
当Stat的值分别为1、2、3和4时,分别对应AOK(正常操作)、HLT(处理器执行halt指令)、ADR(遇到非法地址)和INS(遇到非法指令)。
当我们遇到上述异常时,就让处理器停止执行指令,而在实际过程中,处理器会调用一个异常处理程序。
二. 数字硬件设计
逻辑门是数字电路的基本组成部分,包括与门,或门和非门。将逻辑门组合成一个网,称为组合电路(如多路复用器MUX,算术\逻辑单元ALU等)。组合电路只是简单的响应输入信号,产生相应的输出,不存储任何信息。时序电路,是由最基本的逻辑门电路加上反馈逻辑回路(输出到输入)或器件组合而成的电路,与组合电路最本质的区别在于时序电路具有记忆功能。
时钟寄存器(寄存器)和随机访问存储器(存储器)。
数据输出(数据输出值),scrA和scrB分别为寄存器两个读端口RA和RB的地址输入(表明选择哪一个程序寄存器);valW和dstW分别为寄存器写端口的数据输入(程序寄存器的写入值)和地址输入。write、read和Clock分别为存储器的读写控制信号和时钟输入信号,address和data_in分别为存储器的地址输入和数据输入,data_out为存储器的数据输出。
三. 设计处理器
SEQ处理器为例,在每个时钟周期上,SEQ执行处理一条完整的指令所需的所有步骤,也就是说,一个时钟周期处理一条指令,这需要很长的时钟周期,效率极低。不过,在掌握了SEQ的基本原理的基础上,我们可以实现一个高效的、流水线化的处理器。有兴趣的朋友可以参考《深入理解计算机系统》第二版4.4,4.5节。
我们将处理一条指令组织成以下6个阶段,可以参考上图进行理解。
取指:将程序计数器(PC)的值作为地址,从存储器中读取指令字节icode、ifun、A、B和valC;同时PC增加器计算当前指令的下一条指令的地址valP(等于PC的值加上已经取出的指令的长度)
译码:根据A和B字段指明的寄存器,读取相应寄存器的值valA和valB。
执行:对于整数操作,算术\逻辑单元(ALU)根据ifun的值,执行指令指明的操作,计算存储器的有效地址;对于其他指令,算术\逻辑单元(ALU)增加或减小栈指针。最终得到值valW。同时,也可能会设置条件码(CC)。
访存:将数据写入存储器或者从存储器中读出数据。读出的值为valW。
写回:将算术\逻辑单元(ALU)计算出来的值和从数据存储器中读出来的值写入寄存器
更新:将程序计数器的值设置为下一条指令的地址。
可以看到,我们将执行不同的指令所需要的步骤,组织成一个统一的流程,然后用各种硬件单元和时钟信号来控制计算顺序,从而实现整个处理器。
参考书籍:Randal E.Bryant David R.O'Hallaron 著,龚奕利 雷迎春 译,《深入理解计算机系统》,机械工业出版社