# CPU 设计文档及思考题
# 设计草稿
# 思路
- 在 P5 草稿基础上进行修订,加入了乘除模块和存储器外置,先画出流水线 CPU 的设计示意图如下。其中正三角表示转发的供给者,倒三角表示转发的需求者。部分控制信号连线省略了。
# 工程化设计
- 先对需要实现的指令进行分类,对每个类别设计数据通路。分成以下几类:Cal,immCal,irCal,Load,Store,Branch,jWrite,jUse,mdCal,mdSet,mdGet, 大多数沿用之前的通路。
数据通路的设计如下,其中标记橙色部分为转发的需求者,需要替换为转发需求者多路选择器的输出: - 控制信号的设计基本延续了之前的指令,添加了少量信号。
- 暂停转发的设计如下 (延续 P5):
- 暂停 / 转发的策略信号:rs-Tuse,rt-Tuse 是从存到 D 级开始,过多少周期用到。Tnew 是从存入当前寄存器开始,过多少周期更新数据。
- 暂停信号例如 (rs-Tuse < Tnew_E && rs == A3@E && RegWrite@E && rs != 0)。其他同理,将两个子公式析取起来得到 rs_Stall,将 rs_Stall 和 rt_Stall 析取得到 Stall。
- 转发信号的条件则是信号已经产生并且读写同一个寄存器、寄存器不为零号、写使能。由于采用集中式译码,因此 “信号已经产生” 的条件不是查看后面流水级寄存器得到的 T_new 为零,而是等到将要转发的那个周期中 T_new 为零。即 T_new_2D 为零,T_new_2E 小于等于一,T_new_2M 小于等于 2。
- 添加 Stall_md 信号,当乘除模块 start 或 busy 时 D 级为乘除指令时暂停
- 添加 E 级的转发选择信号,如果是 mfhi/mflo 指令应该转发 MDR.Out
# 模块设计
PC
信号名 方向 描述 Clk Input 时钟 Reset Input 同步复位到 0x00003000 In Input[31:0] npc Out Output[31:0] pc IM
信号名 方向 描述 A[31:0] Input 指令的字节地址 Out[31:0] Output 指令 GRF
信号名 方向 描述 Clk Input 时钟 Reset Input 同步复位 WE Input 写使能 A1[4:0] Input 操作数 1 地址 A2[4:0] Input 操作数 2 地址 A3[4:0] Input 操作数 3 地址 WD[31:0] Input 写入数据 D1[31:0] Output 读出数据 1 D2[31:0] Output 读出数据 2 NPC
信号名 方向 描述 BLOCK_NPC Input 冻结信号 NPCMode[2:0] Input 运算模式 PC_Out[31:0] Input F 级 PC PC_D[31;0] Input D 级 PC Imm Input[25:0] 25 位立即数 ra Input[31:0] ra beq Input beq 两数是否相等 pc8 Output[31:0] PC_D+8(PC_Out+4) npc Output[31:0] NPC EXT
信号名 方向 描述 EXTMode[1:0] Input 模式 Imm16 Input 待扩展立即数 ext[31:0] Output 结果 Controller
信号名 方向 描述 Opcode[5:0] Input Funct[5:0] Input rs[4:0] Input rt[4:0] Input T_new_E[2:0] Input T_new_D[2:0] Input T_new_M[2:0] Input RegWrite_E Input RegWrite_D Input RegWrite_M Input NPCMode Output[2:0] NPC 模式 EXTMode Output EXT 使能和模式 A3Src[1:0] Output ALU/DM 回写 ALUSrc[1:0] Output B 为寄存器 / 立即数 ALUMode[3:0] Output ALU 模式 MemoryWrite Output DM 写使能 WDSrc[1:0] Ouput DM 选择 RegWrite Output GRF 写使能 Stall Output 暂停 DFV1_DSrc[2:0] Output 转发 DFV2_DSrc[2:0] Output 转发 DFV1_ESrc[1:0] Output 转发 DFV2_ESrc[1:0] Output 转发 DFData_MSrc[1:0] Output 转发 T_new_D[2:0] Output 产生结果时间 ALU
信号名 方向 描述 A[31:0] Input 操作数 1 B[31:0] Input 操作数 2 ALUMode[3:0] Input 模式 C[31:0] Output 运算结果 D
信号名 方向 描述 CLK Input 时钟信号 Reset Input 同步复位 BLOCK_D Input 冻结信号 PC[31:0] Input pc IR[31:0] Input 指令 PC_D Output IR_()_D Ouput 指令的各个域
# 测试方案
- 进行一定的手动测试。其中可以先进行单条指令的测试。这里使用了部分 P5 的测试点,并构造了一些其他点测试新指令,如:
.data
.text
ori $1,$0,12
sw $1,0($0)
ori $2,$0,15
sb $2,1($0)
ori $3,$0,1376
sh $3,2($0)
ori $4,$0,0xffff
sh $4,4($0)
lui $5,0xffff
sb $5,7($0)
slt $10,$5,$4
sh $10,6($0)
slt $11,$1,$2
sb $11,8($0)
slt $10,$3,$1
slt $11,$1,$4
sltu $10,$5,$4
sltu $11,$1,$2
sltu $10,$3,$1
sltu $11,$1,$4
and $1,$2,$1
sb $1,10($0)
and $2,$3,$3
sh $2,14($0)
and $5,$5,$3
lw $4,0($0)
and $4,$5,$4
lh $3,0($0)
or $1,$2,$1
lb $3,3($0)
or $2,$3,$3
lh $5,4($0)
or $5,$5,$3
lb $4,5($0)
or $4,$5,$4
- 多条指令之间的暂停转发的测试。为了进行充分覆盖,将指令分成不同的类型,类型内和类型之间进行测试。包括前一条指令与后一条指令数据相关,隔一条指令数据相关,隔两条指令数据相关。测试样例如下 (算数指令和立即数指令内和之间):
.data
.text
ori $1,$0,12
addi $2,$0,15
ori $3,$0,16
addi $4,$0,17
add $1,$2,$3
sub $2,$3,$1
add $1,$2,$3
sub $3,$1,$2
add $1,$2,$3
nop
or $3,$1,$2
add $1,$2,$3
nop
sub $3,$2,$1
and $1,$2,$3
nop
nop
slt $3,$1,$2
add $1,$2,$3
nop
nop
sltu $3,$2,$1
add $1,$2,$3
andi $3,$1,15
add $1,$2,$3
nop
ori $3,$1,13
add $1,$2,$3
nop
nop
ori $3,$1,15
and $1,$2,$3
ori $3,$1,15
or $1,$3,$2
ori $3,$1,15
nop
add $1,$3,$2
ori $3,$1,15
nop
add $1,$2,$3
ori $3,$1,15
nop
nop
or $1,$3,$2
ori $3,$1,15
nop
nop
or $1,$2,$3
lui $1,0xff
add $1,$2,$1
lui $1,0xff
add $1,$1,$1
lui $1,0xff
nop
add $1,$2,$1
lui $1,0x1
nop
add $2,$1,$2
lui $1,0x11
nop
nop
add $2,$1,$2
lui $1,0x1
nop
nop
add $2,$2,$1
# 思考题
- 思考题 1:
- 乘除法需要较长的计算时间,独立出来进行计算,与不用到乘除模块的指令并行进行能够显著提高效率;并且部件用到了大量的加法器,规模较大,无法简单复用 ALU 模块。
- 为了保证乘除模块的独立性,不至于和其他的指令产生数据相关和冒险,设置专用寄存器 hi/lo。
- 思考题 2:
- 流水线乘法器(除法器)可以采用横向进位的方式,然后在每一级(若干位)插入一个流水线寄存器,将整个组合电路分成 N 个流水级,N 个周期算出结果。
- 思考题 3:
- 将 busy 和 start 信号传入 D 级中,如果 start || busy 且 D 级的指令使用到了乘除模块,则 D 级指令暂停,否则继续执行。
- 思考题 4:
- 按字节使能的方式来处理数据,要存入哪几个字节一目了然,相比于使用其它控制信号,代码易读且易修改,将来有其它的写入方式也容易添加。
- 通过字节使能信号的标记,能清晰地看出要将待写入的有效字节放在哪几位上,和 Mem 中写入的位统一。
- 思考题 5:
- 实际读写时写入和读出的数据都是一个字而不是一个字节。
- 如果数据是按照字节存储的,例如 char,那么按照字节读取的效率高于按字读取的效率。
- 思考题 6:
- 延续和扩展了之前使用的一些规范手段,例如采用宏定义标记多路选择器的选择信号;合理命名指令译码信号、控制信号和选择器等等。
- 采用了一些抽象手段,例如给指令进行分类,将若干个信号析取合成一个指令类信号,例如 等。释放相应控制信号尽可能采用抽象类信号。
- 如上所述,在译码过程中采用的是控制信号驱动的译码。在记录相应指令信号时采用指令类的信号使得代码量减小且易读。
- 处理数据冲突时先记录 T_use_rs 和 T_use_rt T_new,再根据大小关系判断暂停和转发信号,在此次设计中同样将 T_use_rs 和 T_use_rt T_new 信号的记录换成指令类,其他信号几乎无修改即可实现冲突处理。
- 思考题 7:
- 在本分类当中,产生冲突的组合有
以及Cal Cal immCal irCal irCal Load Load + Store jWrite Branch mdGet jUse mdCal
- 解决方案为记录相应的 T-use-rs 和 T-use-rt T-new,通过比较判断暂停和转发情况。特别的,乘除模块的冲突使用 busy/start 信号判断是否需要暂停,始终无需转发
- 对每个类型构造相邻 / 相隔一条指令 / 相隔两条指令来测试暂停和转发的正确性,样例同测试方案样例 (展示了 Cal 内部测试):
.data
.text
ori $1,$0,12
addi $2,$0,15
ori $3,$0,16
addi $4,$0,17
add $1,$2,$3
sub $2,$3,$1
add $1,$2,$3
sub $3,$1,$2
add $1,$2,$3
nop
or $3,$1,$2
add $1,$2,$3
nop
sub $3,$2,$1
and $1,$2,$3
nop
nop
slt $3,$1,$2
add $1,$2,$3
nop
nop
sltu $3,$2,$1
add $1,$2,$3
andi $3,$1,15
add $1,$2,$3
nop
ori $3,$1,13
add $1,$2,$3
nop
nop
ori $3,$1,15
and $1,$2,$3
ori $3,$1,15
or $1,$3,$2
ori $3,$1,15
nop
add $1,$3,$2
ori $3,$1,15
nop
add $1,$2,$3
ori $3,$1,15
nop
nop
or $1,$3,$2
ori $3,$1,15
nop
nop
or $1,$2,$3
lui $1,0xff
add $1,$2,$1
lui $1,0xff
add $1,$1,$1
lui $1,0xff
nop
add $1,$2,$1
lui $1,0x1
nop
add $2,$1,$2
lui $1,0x11
nop
nop
add $2,$1,$2
lui $1,0x1
nop
nop
add $2,$2,$1
- 思考题 8:
- 对于单条指令的测试,与 P3/P4 基本相同,即构造不同类别、不同大小、边界条件的数据,以保证测试的覆盖性。
- 对于冲突和冒险的测试,根据上面思考题 7 提到的方案进行构造。对于寄存器冲突的测试,只需要测试相邻 / 相隔一个周期 / 相隔两个周期即可,因为相隔三个周期及以上已存入通用寄存器下一个周期才读取并存入流水线寄存器,不会产生数据冒险。对于乘除模块,则需要测试相隔高达 5/10 个周期。