F5 支持数列求和的简单处理器

用数字电路实现一个简单的cpu,约定一些寄存器的位宽:

  • PC位宽为8位, 初值为0
  • GPR有4个, 位宽均为8位
  • 支持如下3条指令
     7  6 5  4 3   2 1   0
    +----+----+-----+-----+
    | 00 | rd | rs1 | rs2 | R[rd]=R[rs1]+R[rs2]       add指令, 寄存器相加
    +----+----+-----+-----+
    | 10 | rd |    imm    | R[rd]=imm                 li指令, 装入立即数, 高位补0
    +----+----+-----+-----+
    | 11 |   addr   | rs2 | if (R[0]!=R[rs2]) PC=addr bner0指令, 若不等于R[0]则跳转
    +----+----------+-----+
    

只有一条指令的sCPU

从最简单的li指令开始考虑, 也即, 先实现一个只支持li指令的sCPU。

“指令周期”为:取指-译码-执行-更新PC

  1. 取指(fetch): 根据当前PC, 在存储器中找到一条指令
  2. 译码(decode): 看这条指令具体是什么指令, 操作数是哪些
    • li指令为例, 操作数需要看立即数是多少, 需要写入哪个目的寄存器
  3. 执行(execute): 对操作数进行处理, 必要时更新指定的目的寄存器
  4. 更新PC: 让PC指向下一条指令

接下来分步实现上述四步骤。

取指

在P3我们已经实现了寄存器,现在需要根据PC在存储器中找到一条指令。存储器和寄存器都可以存储信息,区别是存储器支持殉职操作,即存储器中内容按照顺序排布,给一个地址存储器可以读取其中内容。

例如, 一个2x3的存储器排布如下, 其中$b_{(x,y)}$表示第x行第y列所存储的比特:

地址 存储字
0 $b_{(0,2)}b_{(0,1)}b_{(0,0)}$
1 $b_{(1,2)}b_{(1,1)}b_{(1,0)}$

地址数量称为存储器的深度,存储字位宽称为存储器深度。

功能上可以分为ROM(只读存储器)和RAM(随机访问存储器,支持写入),我们这里不需要写入数据,故只用ROM。下图为一个2*3的ROM。电路在功能上构成了一个3位的2选1多路选择器,addr为选择端。1789975339200

与左上角地址译码器相连的两条线(红)是字线(word line),每条代表一个存储字,和或门输出相连的(绿)是位线(bit line),每条线对应存储字的一个位。

实现取指功能

通过多路选择器实现一个ROM, 并在其中存放数列求和的指令序列, 然后通过PC寄存器取出指令. 你需要根据你的理解来确定ROM的规格.

“PC位宽为8”,故深度为$2^8$;存储字位宽为8位。但是这里只是为了演示,PC位宽设置为4。1789994493042

counter_4bit内部结构见F3笔记(超链接定位),有一个4位寄存器和加法器组成。

译码

译码的目的是根据指令的编码识别指令的功能。进一步分为操作码译码和操作数译码, 前者是根据指令的操作码来识别指令的功能, 后者是从指令的编码中识别出相应的操作数. 对于操作码译码, 由于目前只需要实现一条li指令, 因此我们可以认为取到的指令就是li, 不存在其他情况. 对于操作数译码, 我们解析出li指令中的rdimm字段即可。

执行

li指令的功能是将立即数imm写入rd寄存器中, 因此我们需要考虑如何实现ISA的GPR。

GPR通常包含多个寄存器, 一次访问通常只访问其中的几个寄存器, 因此GPR也应该支持寻址. 可以看到, GPR的电路本质也是一个存储器. 不过GPR需要作为目的寄存器被指令写入, 因此GPR是一个支持写入的存储器, 即RAM