1. 分析指令集

  • 经过分类,指令共包含R型指令和I型指令
  • 列出其对应的32位机器码,寻找共性差异

R型指令:

Type Op Rs Rt Rd Shamt Func 解释
add 000000 (5) (5) (5) 00000 100000 相加(rs+rt->rd)
sub 000000 (5) (5) (5) 00000 100010 相减(rs-rt->rd)

I型指令:

Type Op Rs Rt Immediate 解释
ori 001101 (5) (5) (16) 或运算(rs|immediate->rt)
lui 001111 00000 (5) (16) 立即数加载至高16位({immediate||{16{1’b0}}}->rt)
Type Op Rs Rt Offset 解释
lw 100011 (5) (5) (16) 加载字(rs+offset在memory中data->rt)
sw 101011 (5) (5) (16) 保存字(rt->rs+offset在memory中的data)
beq 000100 (5) (5) (16) rs与rt相等则PC偏移offset*4
  • 可以分析得到,通过Op能够区分R型指令和I型指令
  • R型指令中通过Func再具体区别运算类型

2. 分析Controller

端口 作用(0) 作用(1)
RegDst GRF写入端地址选择Rt GRF写入端地址选择Rd
ALUSrc ALU输入端B选择R[rt] ALU输入端B选择Signext
MemtoReg GRF写入端数据来自ALU输出 GRF写入端数据来自DM输出
RegWrite 把数据写入GRF中对应寄存器
MemWrite 数据存储器DM写输入
nPC_Sel PC=PC+4 PC=PC+4+移位
ExtOp 选择扩展类型
ALU_Op 选择计算类型

3.设计PC状态转移模块

  • 经过分析,PC只会转移到两个状态:1. PC+4 2. PC+4+移位
  • 1.状态是除beq以外其他指令的转移
  • 2.状态时beq成立时的转移
  • PC是保存的状态
  • Moore状态机,输出是PC所对应的ROM中的地址
  • reset异步复位
type name 位宽
input PCop 1
input PC [15:0]
input beq [15:0]
output instruction [31:0]

因此可设计如下PC状态机:

alt text

其中PCshift模块为:

alt text

需要注意,因为PC实际是从0x00003000开始的,而ROM是从0x00000000开始的,因此二者有插值。在获取PC值的时候,需要加上初始地址0x00003000

4. 设计splitter

  • 根据不同指令从对应位数拆分出相关信息,用于后续操作。

alt text

5. 设计ALU

ALU端口设计:

type name 位宽
input num1 [31:0]
input num2 [31:0]
input ALUop [3:0]
output ans [31:0]

ALUop解释:

ALUop 解释
0000 加法
0001 减法
0010 或运算
0011 相等
0100 小于
0101 大于

ALU实现电路:

alt text

6. CU

端口设计:

type name 位宽 解释
input op [5:0] 机器码高6位
input func [5:0] 机器码低6位
output RegDst 1 GRF被写入寄存器是rt还是rd。0是rt,1是rd
output ALUSrc 1 ALU第二个运算值是rt还是立即数。0是rt,1是立即数
output mentoReg 1 GRF写入值是ALUans还是DMans。0是ALUans,1是DMans
output Regwrite 1 是否写入GRF
output Menwrite 1 是否写入RAM
output PCsel 1 当前指令是否是beq
output Extop [1:0] 扩展操作类型类型,详见Extender
output ALUop [3:0] ALU运算类型,详见ALU
  • 内部电路采用最小项表达式判断法,先判断Op,再判断Func
    alt text
  • 之后根据每种指令对应的输出来用或逻辑接线。
    alt text
  • 对于ALUop的判断,再次采用最小项表达式的方法。
    alt text

7. Extender

端口类型:

type name 位宽
input num [15:0]
input Extop [1:0]
output ans [31:0]

Extop类型解释:

Extop 解释
00 zero扩展
01 sign扩展
10 低16位移至高16位,补0
11 sign扩展,左移2位,补0
实现过程:
alt text

8. 控制信号操作电路

  • 凭借splitter提供的寄存器信息、立即数信息,和CU提供的控制信号,我们可以组合连接GRF与RAM,以达到完成指令操作的效果。
    alt text
  • 通过CU的控制信号来决定MUX的输出是什么,从而特性化处理不同指令的要求。

9. 输出

alt text
通过tunnel获取相应输出的结果,并从端口输出。(PC要加上初始地址)

10. 测试方案

  1. 理论检验。一个个指令单独检测,从CU产生的控制信号,到这些控制信号实际所控制的内容,分别进行检查核对,确保指令正确执行。
  2. 数据检验。利用教程平台提供的机器码,导入ROM中运行CPU,通过翻译机器码获取MIPS指令,并利用MARS计算出正确结果,与CPU中的GRF和RAM核对信息。

11. 思考题

  1. CPU中有两个FSM。一个是由PC和PCop组成的FSM,是一个Moore状态机,输出是当前PC所对应的指令机器码;另一个是GRF和RAM与Splitter和CU组成的FSM,是一个Mealy状态机,输出是众多信号。PC、GRF、RAM起到状态存储功能,PCshifter、ALU、Extender实现状态转移功能(即计算出下一状态)。
  2. 我认为比较合理。ROM是只读寄存器,不可修改,其存储的是指令的机器码,而程序指令一经写好就是固定的,因此可以应用。GRF是寄存器堆,用来对应32个寄存器,能起到数据存储的作用,我认为也比较合理。RAM是随机访存寄存器,且读出和写入操作分离,满足内存中访问和存储的操作,因此也合理。但也有一些问题,比如 $sp寄存器是栈指针,其初始值并不是0,而是一个地址。进行入栈操作时会先 $sp自减4字节,之后再在内存中 $sp的位置存储数据。而寄存器默认初始值是0,因此需要注意特殊寄存器赋初值的问题。
  3. 除了教程中提及的模块,我还设计了PCshifter模块,其作用是根据PC和PCop来计算出下一周期的PC。利用PCop当MUX的sel信号,根据PCop的不同,决定不同的PC输出alt text
  4. nop的作用是让当前电路不发生任何改变。当CU中不设计nop指令时,出现nop指令后CU所有控制信号都是0,包括Regwrite和Menwrite,此时不会对GRF和RAM进行任何改变,满足nop指令的作用,因此不需要设计。
  5. 该测试样例的覆盖率和强度都较高,但是对于特定样例、边界情况的测试还有些不足。
    ori指令:应该增加立即数的符号位是1的测试样例,以判断是否是无符号扩展。
    lui指令:测试较为全面
    add指令:应增加溢出情况测试
    sw指令:应增加对某一地址重复赋值的测试,应变换寄存器中的值测试偏移量
    lw指令:应变换寄存器中的值测试偏移量
    beq指令:应增加label是beq指令的下一条指令的跳转,测试跳转情况下PC是否+4再偏移。