Splitter模块

Sig Type Descript
Instr[31:0] Output 当前指令
opcode Output Instr[31:26]
rs Output Instr[25:21]
rt Output Instr[20:16]
rd Output Instr[13:11]
Output Instr[10:6]
func Output Instr[5:0]
offset/imm Output Instr[15:0]
base Output Instr[25:21]
  • 美化电路用,Logisim自带Splitter太丑了

Controller模块

Sig Type Descript
opcode[5:0] Input
func[5:0] Input
RegWrite Output GRF写使能
RegDst Output 选择寄存器rt(0)/rd(1)
ALUsrc Output ALU选择寄存器(0)/立即数(1)
Branch Output 跳转指令信号
MemWrite Output 内存写使能
MemtoReg Output 选择输出
EXTOp[1:0] Output 位拓展模式信号
ALUOp[2:0] Output ALU模式信号

opcode与func解析真值表

func 100000 100010 null null null null null
op 000000 000000 001101 100011 101011 000100 001111
Command add sub ori lw sw beq lui
RegWrite 1 1 1 1 0 0 1
RegDst 1 1 0 0 0 0 0
ALUsrc 0 0 1 1 1 0 1
Branch 0 0 0 0 0 1 0
MemWrite 0 0 0 0 1 0 0
MemtoReg 0 0 0 1 0 0 0
EXTOp[1:0] 00 00 00 01 01 01 10
ALUOp[2:0] 000 001 010 000 000 001 010
  • Controller模块可分为and-logic模块(真值表前三行,用于将opcode与func和指令联系)与or-logic模块(真值表其余部分,用于将指令和控制信号联系)

ALU模块

ALU模式 ALUOp[2:0]
加法 000
减法 001
010
011
左移 100
101
110
111
  • 使用3bit选择MUX选择ALU运算结果,为便于日后拓展功能,将ALUOp设置为3位

EXT模块

EXT模式 EXTOp[1:0]
零扩展 00
符号扩展 01
移位至高16位 10
11
  • 零扩展用于在lw/sw/beq指令中将立即数扩展为32位
  • 移位至高16位用于lui指令

IFU模块

Sig Type Descript
clk Input 时钟信号
reset Input 异步复位信号
Branch Input 跳转指令信号
equal Input 相等信号
imm[31:0] Input 输入立即数
PC Output 记录当前指令地址
Instr Output 从ROM中Addr处提取指令
  • beq = Branch && equal

    • beq == 0时,PC = PC + 4
    • beq == 1时,Addr = Addr + 4 + (imm<<2)
  • 既然ROM中0地址对应PC中的0x00003000,且只需要用到12位,只需用分线器提取PC中的[11:2]即可作为ROM的取地信号

    • 不取[31:12]原因:指令地址只可能存在于0x000030000x00003FFF之间
    • 不取[1:0]原因:一行指令占据空间为4字节

DM模块

Sig Type Descript
Addr[31:0] Input
Data[31:0] Input
WE Input RAM写使能信号
clk Input 时钟信号
RE Input RAM读使能信号
reset Input 异步复位信号
MemtoReg Input 输出选择
RegData Output RAM数据
  • MemtoReg == 0时,将ALU结果写入寄存器
  • MemtoReg == 1时,将内存中数据写入寄存器

测试方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
.text
main:
lui $t0, 0x1234
ori $t0, $t0, 0x5678
lui $t1, 0x0001
ori $t1, $t1, 0xffff
ori $t2, $0, 0x00ff
ori $t3, $0, 0
ori $t4, $0, 5
ori $t5, $0, 10
lui $t6, 0xffff
ori $t6, $t6, 0xfff0
lui $t7, 0xffff
ori $t7, $t7, 0xfff8

add $s0, $t3, $t4
add $s1, $t4, $t5
add $s2, $t6, $t7
add $s3, $t1, $t2
add $s4, $t0, $t2
add $0, $t4, $t5

sub $s5, $t3, $t4
sub $s6, $t5, $t6
sub $s7, $t1, $t2
sub $t3, $t2, $t2
sub $0, $t5, $t4

sw $s1, -4($sp)
lw $t1, -4($sp)
sw $s6, -8($sp)
lw $t2, -8($sp)

sw $s5, -12($sp)
lw $t4, -12($sp)

sw $s7, -16($sp)
lw $0, -16($sp)

beq $s0, $t4, eq1
nop
eq1:
beq $s1, $t1, eq2
nop
eq2:
beq $0, $0, forward
nop
forward:
ori $t6, $0, 10
loop:
ori $t8, $0, 1
sub $t6, $t6, $t8
beq $t6, $t3, exit
nop
beq $0, $0, loop
nop
exit:
nop

思考题

  • 请大家指出单周期 CPU 所用到的模块中,哪些发挥状态存储功能,哪些发挥状态转移功能。
    • 状态存储:IFU,DM,GRF
    • 状态转移:ALU,CU,EXT
  • 现在我们的模块中 IM 使用 ROM, DM 使用 RAM, GRF 使用 Register,这种做法合理吗? 请给出分析,若有改进意见也请一并给出。
    • 合理,IM中只需要读取外部导入指令;DM中需要随时在内存中存取数据;GRF中只需在每个寄存器中临时存取一个32位数据。
    • 能否设计更加高速的存储模块以进一步提高效率?
  • 你是否在实际实现时设计了其他的模块?如果是的话,请给出介绍和设计的思路。
    • 还设计了Splitter模块,用于将IM输出的指令分离成各个模块所需的部分,使顶层设计看上去更简洁
  • 实现 nop 空指令,我们并不需要将它加入控制信号真值表,为什么?
    • nop等价于sll $zero,$zero,0,没有使处理器中任何一个寄存器产生变化,但是需要让 ALU 的 0 码有对应操作,否则含 x 结果无法运行
  • 阅读 Pre 的 “MIPS 指令集及汇编语言” 一节中给出的测试样例,评价其强度(可从各个指令的覆盖情况,单一指令各种行为的覆盖情况等方面分析),并指出具体的不足之处。
    • 总体:缺少sub指令的测试
    • 单一指令覆盖情况:
      • add缺少最大值
      • ori缺少随机值
      • lui缺少0
      • lw/sw偏移量未考虑负数
      • lw没有尝试向$0赋值
      • beq没有跳转至当前指令或之前指令