序
麻了,P3 就挂了,出师不利啊 qwq
CPU 设计草稿
已实现:add sub ori sw sh sb lw lh lb and or j jal jalr beq bne addi lui sll (不考虑溢出)
IFU
IFU 由三部分构成,分别是存储当前 PC 的值,计算下一个 PC 的值,用 PC 值从 IM 中提取指令。整体是一个 Moore 型有限状态机。
PC
PC 用一个 32 位寄存器存储。由于指令段地址从 0x00003000 开始,因此需要初始化为该值。
| 端口名 | 位宽 | 方向 | 注释 | 
|---|---|---|---|
| clk | 1 | I | 时钟信号 | 
| reset | 1 | I | 异步复位信号 | 
| NPC | [31:0] | I | 下一个 PC 值 | 
| PC | [31:0] | O | 当前 PC 值 | 
NPC
NPC 用组合逻辑来计算下一个 PC 的值,回传给 PC。
- 
对于一般的算数指令
addi,ori等,PC = PC + 4。 - 
对于
j,jal,PC 直接变为外部输入的 26 位立即数instr_index。instr_index尾部补两个 0(Splitter 实现)后位扩展至 32 位。 - 
对于
bne,beq等,一方面要接受外界输入的寄存器值,一方面要接受外界输入的 16 位offset,offset尾部补两个 0 实现后位扩展至 32 位,加上寄存器值赋给 PC。 - 
对于
jr,jalr,PC 直接变为外部输入的寄存器值。 
由于有四种可能的 NPC 求取方式,必须根据读到的指令来判断 NPC 使用上面哪一条来计算。因此引入一个 NPCSel[1:0] 来选择。另外,对于 beq 等指令,若条件判断不成功,NPC 仍然是 PC + 4,引入一个 zero 输入来判断。
| 端口名 | 位宽 | 方向 | 注释 | 
|---|---|---|---|
| PC | [31:0] | I | 当前 PC 值 | 
| imm26 | [25:0] | I | 机器码低 26 位 | 
| GRF | [31:0] | I | 寄存器值 | 
| imm16 | [15:0] | I | 机器码低 16 位 | 
| NPCSel | [1:0] | I | NPC 计算方法选择信号 | 
| zero | 1 | I | 条件判断成功信号 | 
| PC+4 | [31:0] | O | PC + 4 值 | 
| NPC | [31:0] | O | 下一个 PC 值 | 
IM
程序运行时为保证安全性,不可篡改指令数据,按要求用一个 4096*32 bits 的 ROM 来存储。至多可存储 4096(2^12)条,因此 ROM 的地址输入位宽为 12,即 Addr[11:0]。先给 PC 减去 0x00003000,又因为 ROM 两行的地址差为 1 而非 4,故再除以 4(逻辑右移 2 位实现),取低 12 位,从而建立了 PC 到 ROM 的映射关系。
IM 输出端为指令机器码。分为 Opcode,rs,rt,rd,shamt,Funct,同时提取低 26 位和低 16 位。
| 端口名 | 位宽 | 方向 | 注释 | 
|---|---|---|---|
| Addr | [31:0] | I | 待取指令之地址 | 
| Instr | [31:0] | O | 指令内容 | 
Controller
Controller 接受 Opcode 和 Funct,判断收到的具体是什么指令,然后发出信号决定 NPC 如何计算,决定 GRF,ALU,DM 做的事。按照指令手册先比较 Opcode,再比较 Funct,用 Priority Encoder 把指令种类的独热编码换成对应的序号type[4:0]。对于未知的指令,序号统一为 0。根据对应的序号:
- 
输出
NewPCSel[1:0]给 NPC 决定 NPC 如何计算。 - 
输出
GRFEnable给 GRF 作为写使能信号。 - 
输出
EXTType给 EXT 决定输入的立即数是符号扩展或非符号扩展。 - 
type[4:0]可以作为选择信号给 ALU 选择相应的运算结果, - 
addi等涉及立即数的指令,需要让 ALU 的 inputB 为位扩展后的立即数,而add等的 ALU 的 inputB 是寄存器值,因此输出ALUIBSel供 inputB 选择输入是立即数或寄存器值。 - 
addi等涉及立即数的指令,最终结果存储在 rt 寄存器中,而add等存储在 rd 中,因此输出GRF A3Sel供 GRF 的 A3 端口(写入位置)选择 rt 或 rd。注意jalr的目的寄存器是 rd。 - 
输出
DMEnable给 DM 作为写使能信号。 - 
lw等指令需要从 DM 中提取数据到 GRF 中,而add等指令是 ALU 算出的结果回传给 GRF,因此输出DMtoGRFSel供 GRF 的 WD 选择输入是 ALU 结果还是 DM 数据。 - 
jalr,jal涉及将 PC + 4 保存到 GRF 中,因此输出PC+4toGRFSel选择 WD 是否是 PC + 4。注意,应当在DMtoGRFSel后选择。 - 
jal把 PC + 4 保存到$ra(31 号寄存器)中,这是不需要输入的。因此输出$raSel选择 A3 是 31 号。注意,应当在GRF A3Sel后选择。 
| 端口名 | 位宽 | 方向 | 注释 | 
|---|---|---|---|
| Opcode | [5:0] | I | 机器码高 6 位 | 
| funct | [5:0] | I | 机器码低 6 位 | 
| ALUSel | [4:0] | O | ALU 计算方法选择信号 | 
| NPCSel | [1:0] | O | NPC 计算方法选择信号 | 
| GRFEnable | 1 | O | GRF 写使能信号 | 
| EXTType | 1 | O | EXT 方法选择信号 | 
| ALUIBSel | 1 | O | ALU InputB 选择信号 | 
| GRF A3Sel | 1 | O | GRF A3 选择信号 | 
| DMEnable | 1 | O | DM 写使能信号 | 
| DMtoGRFSel | 1 | O | 允许将 DM 数据写入 GRF | 
| PC+4toGRFSel | 1 | O | 允许将 PC+4 写入 GRF | 
| $raSel | 1 | O | 选择 31 号寄存器为写入目标 | 
| StoreType | [1:0] | O | 向 DM 存入数据方法选择信号 | 
| LoadType | [1:0] | O | 从 DM 读取数据方法选择信号 | 
GRF
GRF 根据 A1[4:0] 从 32 个寄存器中读取数据到 RD1[31:0],根据 A2[4:0] 从 32 个寄存器中读取数据到 RD2[31:0],若 WE 为 1,则将 WD[31:0] 写入对应的寄存器。其中 0 号寄存器永远为 0。
| 端口名 | 位宽 | 方向 | 注释 | 
|---|---|---|---|
| clk | 1 | I | 时钟信号 | 
| reset | 1 | I | 异步复位信号 | 
| WriteEnable | 1 | I | GRF 写使能信号 | 
| A1 | [4:0] | I | 待读取的寄存器编号 1 | 
| A2 | [4:0] | I | 待读取的寄存器编号 2 | 
| A3 | [4:0] | I | 待写入的寄存器编号 | 
| WriteData | [31:0] | I | 待写入的内容 | 
| ReadData1 | [31:0] | O | 读取的寄存器内容 1 | 
| ReadData2 | [31:0] | O | 读取的寄存器内容 2 | 
ALU
根据 Controller 传来的 type[4:0] 决定如何对 inputA 和 inputB 进行运算。
- 
A + B (
add等) - 
A - B (
sub等) - 
A and B(
and等) - 
A or B(
or等) - 
A xor B(
xor等) - 
B 左移 16 位(
lui) - 
if (A == B) (
beq等) - 
B 左移
sll指定位数(来自shamt) 
if (A == B) 作为上述的 zero 传给 NewPC。
| 端口名 | 位宽 | 方向 | 注释 | 
|---|---|---|---|
| InputA | [31:0] | I | 输入 A | 
| InputB | [31:0] | I | 输入 B | 
| ALUSel | [4:0] | I | ALU 计算方法选择信号 | 
| sll | [4:0] | I | SLL 命令移动位数 | 
| Output | [31:0] | O | 计算结果 | 
| zero | 1 | O | 条件判断成功信号 | 
EXT
给 imm16 符号扩展和无符号扩展至 imm32。用 Controller 传来的 EXTType 判断如何扩展。
| 端口名 | 位宽 | 方向 | 注释 | 
|---|---|---|---|
| imm16 | [15:0] | I | 16 位立即数 | 
| EXTType | 1 | I | 位扩展方法选择信号 | 
| imm32 | [31:0] | O | 32 位立即数 | 
DM
DM 需要频繁进行读写操作,故用 3072*32 bits 的 RAM 存储。仍用 Addr[11:0] 覆盖所有范围。
| 端口名 | 位宽 | 方向 | 注释 | 
|---|---|---|---|
| clk | 1 | I | 时钟信号 | 
| reset | 1 | I | 异步复位信号 | 
| WriteEnable | 1 | I | DM 写使能信号 | 
| Addr | [31:0] | I | 地址 | 
| WriteData | [31:0] | I | 待写入数据 | 
| Data | [31:0] | O | 读取的数据 | 
思考题
- 
状态存储:PC,GRF。状态转移:NPC,ALU。
 - 
合理。IM 中保存的是设定好的指令,其内容和顺序都是固定好的,如果在运行过程中遭到篡改则会导致程序运行失败,为安全起见使用 ROM。DM 中数据需要频繁读写,如果用寄存器,管理过于麻烦,且寄存器无法存储大量数据,用 RAM 最合适。GRF 同样需要频繁读写,但数据量不大,可以用寄存器。
 - 
- StoreType:用以实现 
sb sh。首先用 ALU 算出的地址从 DM 中取出整个字,接受来自 GRF 的待存储数据,接受地址值并按照sb和sh的要求取出 byte。给原有数据按照 sb 和 sh 的要求拆分成多种,把待存储数据与这些拆分的所有可能性一一融合成新数据。从 Controller 引一个 2 位的选择信号选出最终的结果(默认为不对 DM 原数据做任何操作),传给 DM 重新存储。 - LoadType:用以实现 
lb lh。首先从 DM 中取出整个字,接受地址值并按照lb和lh的要求取出 byte。给原有数据按照lb和lh的要求拆分成多种,用不同的 byte 选出不同的部分,符号扩展至 32 位。从 Controller 引一个 2 位的选择信号选出最终的结果(默认为不对 DM 原数据做任何操作),传给 GRF 存储。 
 - StoreType:用以实现 
 - 
nop不激活任何信号,使得 GRF 和 DM 没有改变,ALU 不计算,不会改变状态,故不用考虑。 - 
- 没有测到 32 位边界处的数在寄存器中的表现。
 - 没有测 16 位边界处的立即数在立即数相关指令中的表现。
 - 没有测对 0 号寄存器读写的表现。
 
 
测试
1  | 
  |