我对计算机科学领域的一切事物都怀着一颗好奇的心。而CPU(Central Processing Unit,中央处理器),作为计算机的核心,更是让我着迷。我很幸运,在毕设的时候选了一个设计并实现MIPS CPU的题目,让我与CPU有了一个交集。

FAQ

当我们谈到CPU的设计与实现,可能有些人会有各种各样的疑问,在正式开始之前,让我们先回答一些问题。

我们到底能做出一个什么东西?

在硬件层面上,我们可以做出一个CPU,它采用特定的指令集(本文采用MIPS指令集),它能读写存储器,可以响应外部中断。 在软件层面上,可以为设计出来的CPU写一个汇编器,用来将汇编程序翻译成机器码,可以移植操作系统。

我们需要哪些知识?

关于理论知识的话,主要是数字电子技术(简称数电),其实单纯是设计的话,数电方面的知识就差不多够了,如果要实现的话,还得使用专门的技术,比如HDL(硬件描述语言)来具体描绘出CPU的逻辑结构。

RISC & CISC ?

CPU按其指令系统,可以分为两类:RISC CPU和RISC CPU。 RISC(Reduced Instruction Set Computer,精简指令集计算机),其特点是指令较少,指令字定长,格式规整,寻址方式单一,指令功能原子化。 CISC(Complex Instruction Set Computer,复杂指令集计算机),其特点是指令复杂,指令字不定长,寻址方式多样化,单条指令功能强大。

目标

  1. 兼容MIPS32 Release 1指令集架构。
  2. 单周期执行指令,即不使用流水线技术。
  3. 采用哈佛结构,使用分开的指令和数据接口。
  4. 数据宽度为32位,采用大端序。

详细指令列表,可以参考InstructionList.xlsx文件。

分析

CPU黑盒模型

对于一个简单的CPU,从功能上来看,可以抽象成下面的黑盒模型。CPU从存储器获取指令,以及读写数据。除了存储器,CPU也可以从IO设备读写数据:比如从键盘获取输入,将数据输出到显示器。 CPU黑盒模型 CPU主要通过三总线与外部设备通信:数据总线(Data Bus)地址总线(Address Bus)控制总线(Control Bus)

一条指令的处理流程

让我们分析一下一条指令的处理流程。

  1. 区别于普林斯顿结构(又称冯·诺依曼结构),对于采用哈佛结构的CPU,其指令一般是储存在专门的指令存储器中。取指令模块会输出一个指令地址,然后从指令存储器获取一条指令,并且将获取到的指令传送到解码模块
  2. 解码模块会对指令进行分解分析,分解出的一部分会被发送到控制器模块用以对整个CPU实施控制,另一部分可能会被发送到寄存器文件模块用来获取指令要操作的数据,还有一部分可能会被发送到ALU(Arithmetic Logic Unit,算术逻辑运算单元)模块来指明对数据进行的操作。对于某些指令,比如直接跳转指令,其指令解码的结果可能会被送到指令获取模块作为下一条指令的地址。
  3. 寄存器文件模块读出的数据可以送到ALU模块进行计算,也可以作为间接跳转指令输出的地址。对于写存储器指令,从寄存器文件读出的数据可以直接写入存储器。
  4. 一般情况下,ALU模块计算出来的结果会被写回到寄存器文件模块。但是对于存储器读写指令,其计算结果会作为数据存储器的地址来指明数据读写的位置。 综上,可以用下图来表示上面分析出来的CPU的结构。 CPU模块结构

模块接口

上面给出的CPU结构只包括了数据总线和地址总线,对于每个模块来说,还必须有控制总线,以及一些类似时钟这样的基本驱动信号。

存储器

CPU直接读取的存储器包括数据存储器和指令存储器。对于指令存储器来说,CPU一般只读不写,但是CPU可以通过施加一些控制信号,将指令加载到指令存储器。而对于数据存储器,CPU则会直接执行读写操作。 首先,CPU可以通过一个使能信号enable来控制指令存储器的使能,当CPU禁用指令存储器时,指令存储器不会产生任何有效输出。当CPU启用指令存储器时,指令获取模块会为指令存储器提供一个地址,指令存储器根据这个地址,找到对应的指令,输出给指令获取模块。在有些情况下,指令存储器无法在预定的时间内输出指令,在这种情况下,指令存储器会输出一个“就绪ready”信号,告诉CPU当前输出的指令是否有效。 数据存储器与指令存储器的接口类似,但是因为CPU可以直接将寄存器文件中的数据写入数据存储器,所以会有一条数据总线指向数据存储器,为数据存储器提供数据。当然,配套的还必须有一个数据写入控制信号。当数据写入信号writeEnable有效时,数据存储器会将CPU提供的数据写入由CPU指定的地址中。 存储器接口