从零到单周期CPU

从零到单周期 CPU

CPU 的设计就是从一套指令系统规范到一个数字逻辑电路的过程。这个数字逻辑电路包括组合逻辑电路和数字逻辑电路,数据在这个电路上流转,我们称这些逻辑电路为数据通路。为了控制数据通路的流向,我们必须要有这些通路的“交通信号”,这个“交通信号”被称为“控制逻辑”。一个 CPU 从宏观上来说由数据通路和控制逻辑组成。本文使用的指令系统是 MIPS32 指令系统的一个子集。

单周期 CPU 的数据通路设计

我们以一些指令作为例子描述数据通路应该怎样组成:

ADDU 指令

汇编格式:ADDU rd, rs, rt

功能描述:将寄存器 rs 的值与寄存器 rt 的值相加,结果写入 rd 寄存器中。

操作定义:GPR[rd] ← GPR[rs] + GPR[rt]

取指

将 pc(程序计数器,控制指令的位置)进行虚实地址转换,得到指令在内存的物理地址。

PC

PC 将送到虚实地址转换部件

MIPS32 指令中指令的宽度为 32bit,因此我们用一组 32 位的触发器来存放 PC。

PC 的输入有两个,一个是复位值 0xBFC00000(MIPS 指令系统规范定义的),另一个是执行完一条指令后的下一条指令:PC+4(4 的来源是因为按字存取,一字(word)为四字节(byte))。32 位 CPU 的指令长度是 32,所以理解成按一条指令的长度存取也可以。也可以理解成 PC+1(字)。

虚实地址转换部件

被送到虚实地址转换部件上的 PC 进行地址转换。

任何时候 CPU 上运行的程序中出现的地址都是虚地址,而 CPU 本身访问内存、I/O 所用的地址都是物理地址。

在实现TLB MMU之前,我们的 CPU 都将采用 固定映射 的地址映射机制,即将虚地址 kseg0 和 kesg1 (分别是 0x80000000 ~ 0x9FFFFFFF 与 0x00000000 ~ 0x1FFFFFFF) 映射至 物理地址 (0x00000000 ~ 1FFFFFFF)。其余三个段的虚地址等于物理地址。

指令 RAM

得到 PC 的物理地址后将该地址送往内存(即指令 RAM)。

在单周期 CPU 中,我们只能使用异步读 RAM(当拍请求当拍得到数据)、同步写 RAM(第一拍请求下一拍得到数据)来实现指令 RAM(和数据 RAM)。

译码

分析指令,得到指令的行为。

执行

寄存器堆

根据指令的行为,我们需要一个寄存器组,根据 MIPS32 规范定义,这个寄存器组有 32 项,每项 32 位。

从 ADDU 指令的操作定义中我们知道,为了在一个周期内能完成 ADDU 指令,这个寄存器至少需要两个读端口和一个写端口。

加法器

为了实现运算,这个操作需要一个加法器,这个加法器接受两个 32 位的输入 src1、src2,输出一个 32 位的结果 result。

ADDIU 指令

汇编格式:ADDIU rd, rs,imm

功能描述:将寄存器 rs 的值与符号扩展至 32 位的立即数(imm,在指令码中被直接给出)相加,结果写入 rd 寄存器中。

操作定义:GPR[rd] ← GPR[rs] + sign_extend(imm)

ADDIU 和 ADDU 指令高度相似,因此我们需要改变的只有:

加法器

第二个输入前引入 二选一 部件,输入 寄存器堆读端口 2 和 指令码的一部分,选择后输出到加法器的第二个输入 src2。这个 二选一 部件还需要一个选择信号,这一部分交给我们的 控制逻辑 来管理。

SUBU 指令

汇编格式:SUBU rd, rs, rt

功能描述:将寄存器 rs 的值与寄存器 rt 的值相减,结果写入 rd 寄存器中。

操作定义:GPR[rd] ← GPR[rs] - GPR[rt]

SUBU 和 ADDU 指令同样高度相似。

加法器

第二个输入前再引入一个 二选一 部件,选择减法。

LW 指令

汇编格式:LW rt, offset(base)

功能描述:将 base 寄存器的值加上符号扩展后的立即数 offset 得到访存(访问内存)的虚地址。(每次存取一个字,因此地址必须是 4 的倍数,否则触发例外)

操作定义:vAddr ← GPR[base] + sign_extend(offset)

(pAddr, CCA) ← AddressTranslation(vAddr, DATA, LOAD)

memword ← LoadMemory(CCA, WORD, pAddr, vAddr, DATA)

  1. 得到虚地址:ADDIU vAddr, base, offset
  2. 得到物理地址
  3. 访存

值得注意的是,此处转换后的访存物理地址需要和指令分开,因此用的是一个单独的虚实地址转换部件。

数据 RAM 和指令 RAM 设计上大致相同。

寄存器堆

之前接收加法器的结果,现在又要接收数据 RAM 的输出,因此又需要一个 二选一 部件。

SW 指令

汇编格式:SW rt, offset(base)

功能描述:将 base 寄存器的值加上符号扩展后的立即数 offset 得到访存(访问内存)的虚地址。(每次存取一个字,因此地址必须是 4 的倍数,否则触发例外)

操作定义:vAddr ← GPR[base] + sign_extend(offset)

(pAddr, CCA) ← AddressTranslation(vAddr, DATA, LOAD)

dataword ← GPR[rt]

StoreMemory(CCA, WORD, dataword, pAddr, vAddr, DATA)

LW 读 RAM 写寄存器,SW 读寄存器写 RAM

寄存器堆

之前接收加法器的结果,数据 RAM 的输出,现在又加一个 RAM 的写端口。

BEQ 和 BNE 指令

汇编格式:BEQ rs, rt, offset

功能描述:如果 rs == rt 则转移,否则顺序执行。转移目标由立即数 offset 左移两位并进行符号拓展的值加上该分支指令对应的延迟槽指令的 PC 计算得到。
操作定义:

I. condition ← GPR[rs] = GPR[rt]

​ target_offset ← sign_extend(offset||00)

I+1. if condition then

​ PC ← PC + target_offset

​ endif

汇编格式:BNE rs, rt, offset

功能描述:如果 rs ≠ rt 则转移,否则顺序执行。转移目标由立即数 offset 左移两位并进行符号拓展的值加上该分支指令对应的延迟槽指令的 PC 计算得到。

操作定义:

I. condition ← GPR[rs] ≠ GPR[rt]

​ target_offset ← sign_extend(offset||00)

I+1. if condition then

​ PC ← PC + target_offset

​ endif

在加入了两条跳转指令后,PC 的更新也有了两种情况:PC+4 与 PC + target_offset。

PC

PC 前加入一个二选一部件。

JAL 指令

汇编格式:JAL target

功能描述:无条件跳转,跳转目标为分支指令对应的延迟槽指令的 PC 的最高四位与立即数 instr_index 左移两位后的值拼接得到。同时将 PC+4 + 4 给 31 号寄存器中。

操作定义:

I. FPR[31] ← PC +8

I+1: PC ← PC[31:28] || instr_index || 00

JAL 指令与函数调用有关,跳转到函数对应的地址时为了不丢失当前的 PC 信息,因此需要存储下一条 PC 的地址。为了实现 PC + 8:

PC

PC 改为 三选一 ,新增的 in2 输入为拼接后的结果。

ALU

in0 由原来的只接入寄存器堆改为 二选一寄存器堆PC

in1 有原来的 二选一 改为 三选一:加入一个常数 8

JR 指令

汇编格式:JR rs

功能描述:无条件跳转,跳转目标为寄存器 rs 中的值。

操作定义:

I. temp ← GPR[rs]

I+1: PC ← temp

分成两步是因为 I 操作在一个周期的后半部分,而 I+1 这个操作需要在一个周期的前半部分。

很显然,这条指令是用来和 JAL 指令配合来完成函数调用的。

PC

PC 改为 四选一 in3 来自通用寄存器

SLT 和 SLTU 指令

汇编格式:SLT rd, rs, rt

功能描述:将寄存器 rs 的值和寄存器 rt 中的值进行有符号数比较,如果 rs 中的值小,则寄存器 rd 置 1,否则置 0

操作定义:

if GPR[rs] < GPR[rt] then

​ GPR[rd] ← 1

else

​ GPR[rd] ← 0

endif

汇编格式:SLTU rd, rs, rt

功能描述:将寄存器 rs 的值和寄存器 rt 中的值进行无符号数比较,如果 rs 中的值小,则寄存器 rd 置 1,否则置 0

操作定义:

if (signed)GPR[rs] < (signed)GPR[rt] then

​ GPR[rd] ← 1

else

​ GPR[rd] ← 0

endif

ALU

ALU 中加入比较器功能。

SLL、SRL 和 SRA 指令

ALU

ALU 中加入移位功能。

LUI、AND、OR、XOR 和 NOR 指令

ALU

ALU 中进行加入位运算。

单周期 CPU 的控制信号生成

多选一部件:

nextPC 的四选一:PC+4, PC+(offset), PC+(instr_index), 寄存器堆

指令 RAM 的片选信号:暂时恒为 1

指令 RAM 的写使能信号:暂时恒为 0

ALU 的源操作数 src1 的三选一:寄存器堆、PC、指令码

ALU 的源操作数 src2 的三选一:寄存器堆、指令码、常值 8

ALU 内部的多路选择器:对应指令

数据 RAM 的片选信号:暂时恒为 1

数据 RAM 的写使能信号:暂时恒为 1

通用寄存器堆写地址的三选一:rd, rt, 常值 31

通用寄存器堆写数据的二选一:ALU 的结果,load 指令的返回值(待添加)

单周期 CPU 的复位

复位就是初始化。复位信号包括同步复位和异步复位,本文中只讨论同步复位的情况。

复位信号有效期间不对外发起第一条指令的取值请求。

参考资料