设计草稿

设计要求

  • 处理器为 32 位单周期处理器,应支持的指令集为:add, sub, ori, lw, sw, beq, lui, nop,其中:

    • nop 为空指令,机器码 0x00000000,不进行任何有效行为(修改寄存器等)。
    • add, sub 按无符号加减法处理(不考虑溢出)。
  • 需要采用模块化层次化设计。顶层有效的驱动信号要求包括且仅包括异步复位信号 reset(clk 请使用内置时钟模块)。

可以将微体系结构分为两个相互作用的部分:数据通路(datapath)控制(control)

先根据应实现的指令对功能部件进行设计与搭建,然后再对各个功能部件进行连接,形成完整的数据通路。

数据通路搭建完毕后,再构造控制器,以根据读取的指令产生相应的控制信号。

数据通路

1 数据通路模块定义

先从包含状态元件的硬件开始,然后在这些存储组件之间增加组合逻辑基于当前状态计算新的状态。

1.1 程序计数器(PC)

  • 32 位寄存器。输出 PC 指向当前指令,输入 PC’表示下一条指令的地址。

  • PC 用寄存器实现,应具有异步复位功能,复位值为起始地址(0x00003000)

  • 地址范围:0x00003000 ~ 0x00006FFF。

1.2 NPC

  • 计算下一个 PC 值。

1.3 指令存储器(IM)

  • 将 32 位指令地址输入 A,并在这个地址中读取 32 位数据(指令)并传送到读数据输出 RD 上。
  • 用 ROM 实现,容量为 4096 × 32bit。
  • ROM 内部的起始地址是从 0 开始的,即 ROM 的 0 位置存储的是 PC 为 0x00003000 的指令,每条指令是一个 32bit 常数。
  • 经过以上分析,不难发现 ROM 实际地址宽度仅需 12 位。又由于 PC 值一定为 4 的倍数,即 PC 的低 2 位始终为 0,故只需将 PC[13:2]同 IM 联系起来。

1.4 寄存器堆(GRF)

信号名 方向 描述
A1[4:0] I 指定 32 个寄存器中的一个作为源操作数
A2[4:0] I 指定 32 个寄存器中的一个作为源操作数
RD1[31:0] O 从指定的 32 位寄存器中读取的值
RD2[31:0] O 从指定的 32 位寄存器中读取的值
A3[4:0] I 需要写入的寄存器的地址
WD3[31:0] I 需要写入的数据
WE3 I 写使能信号
CLK I 时钟信号

注意 0 号寄存器值始终为 0

1.5 数据存储器(DM)

  • 若写使能 WE=1,则在时钟上升沿将数据 WD 写入地址 A;若写使能 WE=0,则从地址 A 将数据读到 RD。

  • 使用 RAM 实现,容量为 3072 × 32bit,应具有异步复位功能,复位值为 0x00000000。

  • 起始地址:0x00000000

  • 地址范围:0x00000000 ~ 0x00002FFF(一个地址 1 个字节,1 个字节 8 位)。

  • RAM 应使用双端口模式,即设置 RAM 的 Data Interface 属性为 Separate load and store ports

  • 由于只实现lw,sw,故 A 的值为 4 的倍数,即 A 的 32 位二进制低 2 位始终为 0,且 3072 个数据地址 12 位即可,所以只要 A[13:2]。

  • lb,sb怎么处理?数据地址位宽为 12,共有 4096 个地址,如何处理地址超出 3072 的情况?

1.6 算数逻辑单元(ALU)

  • 提供 32 位加、减、或运算、大小比较以及移位功能。

  • 加减法按无符号处理(不考虑溢出)。

  • 端口定义:

    信号名 方向 描述
    SrcA[31:0] I 第一个操作数
    SrcB[31:0] I 第二个操作数
    ALUOp[2:0] I 运算选择
    Result[31:0] O 运算结果
    Zero O SrcA == SrcB ? 1 : 0
    Shift[4:0] I 移位量
  • 功能定义:

    功能名 ALUOp 功能描述
    ADD 3’b000 SrcA + SrcB
    SUB 3’b001 SrcA - SrcB
    OR 3’b010 SrcA | SrcB
    SHIFT 3’b011 SrcB << Shift

1.7 扩展单元(EXT)

  • 对 16 位立即数进行符号扩展或无符号扩展。

2 构建数据通路

通过一次增加一个状态元件,逐步构成单周期的数据路径。

2.1 从指令存储器中读取指令

PC 将32 位指令地址传入 A,并从指令存储器中取出相应地址处的32 位指令输出到 RD,标记为Instr

由于处理器的动作取决于取出的具体指令,故先针对lw指令构造数据路径连接,然后再泛化处理该数据路径来处理其他指令。

2.2 从寄存器堆中读源操作数

lw指令的格式为 lw rt, offset(base),操作为

Addr GPR[base] + sign_ext(offset)

GPR[rt] memory[Addr]

故读包含基地址的源寄存器,该寄存器由 Instr[25:21]的 rs 字段指定。

Instr[25:21]连接到 GRF 的 A1 口,GRF 读出源寄存器的基地址值到 RD1 口。

2.3 符号扩展立即数

偏移量 offset 由 Instr[15:0]字段指定,且需要符号扩展,记为 SignImm。

2.4 计算存储器地址

基地址值还要再和偏移量 offset 相加,故 Instr[15:0]经符号扩展后与基地址相加。

基地址值连接到 ALU 的 SrcA,SignImm 连接到 ALU 的 SrcB。

Addr 由 ALU 计算结果得到,ALUResult 连接到 DM 的 A 口,以获取相应内存中的值。

2.5 向寄存器堆写入数据

将内存读取到的值写入 GPR。

DM 的 RD 口连接到 GRF 的 WD3 口,同时写入的寄存器由 Instr[20:16]字段指定,故 Instr[20:16]连接到 A3 口,同时 GRF 的写使能信号 RegWrite 连接到 WE3 口。

2.6 确定 PC 的下一个指令地址

操作执行完毕后,需要由 NPC 计算出下一个地址值。lw指令中,NPC = PC + 4。

就此完成了lw的数据通路。新增其它指令时仿照上述流程构建相应的数据通路。

控制

控制器的设计,从最基本的层面来说,是一个译码的过程,将每一条机器指令中包含的信息,转化为给 CPU 各部分的控制信号(RegDst, ALUSrc 等等)。我们把解码逻辑分解为和逻辑或逻辑两部分:和逻辑的功能是识别,将输入的机器码识别为相应的指令;或逻辑的功能是生成,根据输入的指令的不同,产生不同的控制信号。

而在设计这两套逻辑的过程中,和逻辑是非常自然的。而或逻辑则需要我们建立从指令到控制信号的映射,为了避免错误的产生,我们希望使用真值表来完成相应的设计任务,并希望通过真值表可以简化相应的逻辑。一个典型的真值表如下:

func 10 0000 10 0010 n/a
op 00 0000 00 0000 00 1101 10 0011 10 1011 00 0100 00 1111
add sub ori lw sw beq lui
RegDst 1 1 0 0 X X 0
ALUSrc 0 0 1 1 1 0 1
MemtoReg 0 0 0 1 X X 0
RegWrite 1 1 1 1 0 0 1
MemWrite 0 0 0 0 1 0 0
nPC_sel 0 0 0 0 0 1 0
ExtOp X X 0 1 1 1 0
ALUctr ADD SUB OR ADD ADD SUB SHIFT
ALUctr[0] 0 1 0 0 0 1 1
ALUctr[1] 0 0 1 0 0 0 1
ALUctr[2] 0 0 0 0 0 0 0
ShiftOp X X X X X X 1

控制单元端口定义如下:

端口名 方向 描述
Op[5:0] I 指令的操作类型
Funct[5:0] I R 型指令通过 funct 字段来决定 ALU 的操作
RegDst O GRF 的写入寄存器地址选择。
ALUSrc O ALU 的 SrcB 选择。0 为 GRF 的 RD2,1 为扩展立即数。
MemtoReg O GRF 的写入数据选择。0 为 ALU 运算结果,1 为 DM 读取的数据。
RegWrite O GRF 的写使能信号。
MemWrite O DM 的写使能信号。
nPC_sel O NPC 的值选择。0 为 PC+4,1 且 ALU 的 Zero 信号生效时为 PC+4+sign_extend(immediate || 02)。
ExtOp O 立即数扩展方式选择。0 为无符号扩展,1 为有符号扩展。
ShiftOp O 移位量选择。1 为 LUI 移位(左移 16 位)。
ALUctr[2:0] O ALU 运算类型选择。

总体预览

指令集

add

add rd, rs, rt

sub

sub rd, rs, rt

ori

ori rt, rs, immediate

操作:GPR[rt] GPR[rs] OR zero_extend(immediate)

lw

lw rt, offset(base)

sw

sw rt, offset(base)

beq

beq rs, rt ,offset

操作:

if (GPR[rs] == GPR[rt]) PC PC + 4 + sign_extend(offset || 02)

else PC PC + 4

lui

lui rt, immediate

操作:GPR [rt] immediate || 016

nop

测试方案

通过 asm 文件随机生成,以保证测试数据的任意性,然后与 MARS 或同学的结果对拍,以确定正确性。(随机生成程序与对拍程序均借助讨论区工具)。

同时,适当修改随机数,产生一些极端情况的数据以对电路进行压力测试。

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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
lw $17,692($0)
lw $27,7576($0)
label0:
ori $25,$27,55842
nop
sub $19,$12,$11
sw $2,4500($0)
ori $7,$10,16845
ori $12,$12,51698
beq $12,$15,label0
ori $14,$23,9736
ori $5,$5,54233
beq $5,$18,label0
nop
ori $15,$15,65535
beq $15,$14,label0
nop
ori $6,$7,34855
lw $18,4932($0)
nop
sub $24,$26,$14
ori $23,$7,33149
sub $13,$22,$5
sub $3,$14,$22
label1:
sw $14,10196($0)
ori $9,$17,21335
ori $8,$3,36832
sw $26,4068($0)
ori $2,$18,62203
ori $12,$12,5574
beq $12,$4,label1
ori $9,$9,9938
beq $9,$12,label0
add $21,$2,$4
lui $16,50966
lui $24,53930
nop
lui $23,38667
nop
add $6,$12,$19
nop
lui $27,6097
nop
lw $9,4356($0)
sw $4,1268($0)
sub $26,$22,$6
ori $19,$19,24032
beq $19,$23,label0
add $24,$3,$26
lui $27,42112
nop
ori $16,$16,10912
beq $16,$20,label0
label2:
ori $8,$24,17325
lw $22,9812($0)
add $19,$27,$11
lw $10,10156($0)
label3:
nop
nop
sw $11,9264($0)
ori $15,$15,30113
beq $15,$4,label3
lw $3,3264($0)
sw $4,100($0)
sw $16,6276($0)
nop
label4:
ori $12,$12,6712
beq $12,$14,label2
add $27,$20,$21
sw $17,8876($0)
ori $4,$4,27756
beq $4,$2,label2
ori $21,$4,47542
label5:
add $12,$27,$12
add $2,$8,$14
ori $3,$3,15240
beq $3,$7,label1
ori $24,$6,58591
ori $9,$9,17485
beq $9,$22,label1
lw $6,592($0)
lw $5,2084($0)
nop
nop
ori $19,$19,40028
beq $19,$17,label1
ori $14,$10,29720
ori $18,$18,8933
beq $18,$17,label0
ori $2,$2,57597
beq $2,$17,label0
ori $8,$8,54934
beq $8,$27,label0
nop
ori $23,$24,61720
label6:
ori $20,$20,41073
beq $20,$4,label0
add $27,$10,$23
ori $13,$7,44324
sw $12,11336($0)
ori $19,$19,22207
beq $19,$21,label2
sub $8,$14,$27
label7:
label8:
lw $15,4176($0)
lui $11,52027
label9:
lw $26,8572($0)
lw $25,4664($0)
ori $10,$10,42721
beq $10,$25,label7
ori $26,$19,26300

计算类指令功能测试

  • 寄存器数据方面,可以考虑以下情况:

    • 0 及附近的数:−2,−1,0,1,2
    • 32 位数边界附近的数: −2147483648,−2147483647,2147483646,2147483647
    • 32 位数范围内的一些随机数:−1000786109,1919156834,…
  • 无符号立即数方面,可以考虑以下情况:

    • 0 及附近的数:0,1,2,3
    • 16 位无符号数边界附近的数:65533,65534,65535
    • 16 位无符号数范围内的一些随机数:25779,42528,…
  • 符号立即数 (P3 不涉及) 方面,可以考虑以下情况:

    • 0 及附近的数:−2,−1,0,1,2
    • 16 位符号数边界附近的数:−32768,−32767,32766,32767
    • 16 位符号数范围内的一些随机数:−5329,25299,…
  • 特别的,可注意测试目标寄存器是 $0 的情况。

存取类指令功能测试

  • offset 方面,可以考虑以下情况:
    • offset 是正数
    • offset 是零
    • offset 是负数
  • $base寄存器方面,可以考虑以下情况:
    • $base 寄存器中的值是正数
    • $base 寄存器中的值是零
    • $base 寄存器中的值是负数
  • 特别的,对于 sw 指令,建议存入的 word 中,每个 byte 都不是零。
  • 特别的,对于 lw 指令,可注意测试目标寄存器是 $0 的情况。

跳转类指令功能测试

  • 对于非比较相关的部分,可以考虑以下情况:
    • 跳转,且目标在此跳转指令之前
    • 跳转,且目标是此跳转指令
    • 跳转,且目标在此跳转指令之后
    • 不跳转,且目标在此跳转指令之前
    • 不跳转,且目标是此跳转指令
    • 不跳转,且目标在此跳转指令之后
  • 对于比较相关的部分,本质上依旧是构造寄存器数据,处理类似 “计算类指令功能测试”。

思考题

1.上面我们介绍了通过 FSM 理解单周期 CPU 的基本方法。请大家指出单周期 CPU 所用到的模块中,哪些发挥状态存储功能,哪些发挥状态转移功能。

状态存储功能:PC,GRF,DM

状态转移功能:IM,Control Unit,EXT,ALU,NPC

2.现在我们的模块中 IM 使用 ROM, DM 使用 RAM, GRF 使用 Register,这种做法合理吗? 请给出分析,若有改进意见也请一并给出。

部分合理。IM 为 ROM 存在过度简化,因为在大多数实际存储器中,指令存储器必须可写,从而使操作系统可以载入一个新的程序到存储器中。DM 为 RAM 可读可写,满足 DM 对读写的要求;GRF 使用寄存器,满足寄存器堆较高读写速度的要求。

3.在上述提示的模块之外,你是否在实际实现时设计了其他的模块?如果是的话,请给出介绍和设计的思路。

是。NPC 用于计算下一个 PC 值。根据目前实现的指令,当指令为 beq 时,NPC = PC + 4 + sign_extend(offset || 02),其余情况 NPC = PC + 4;故使用一个 DMX 并通过信号控制 NPC 的取值。

4.事实上,实现 nop 空指令,我们并不需要将它加入控制信号真值表,为什么?

空指令机器码为 0x00000000,不需要执行任何操作。

5.阅读 Pre 的 “MIPS 指令集及汇编语言” 一节中给出的测试样例,评价其强度(可从各个指令的覆盖情况,单一指令各种行为的覆盖情况等方面分析),并指出具体的不足之处。

sw指令仅测试了$base$为 0 的情况。

beq指令仅考虑了跳转/不跳转,且目标在跳转指令之后的情况。