P4 - 单周期CPU设计文档
本文最后更新于:2024年4月22日 晚上
P4 单周期CPU设计文档
设计概述
- 设计的处理器为32位单周期处理器
- 处理器支持的指令集为
add, sub, ori, lw, sw, beq, lui, nop,j,jal,jr,lb,sb,lh,sh
等 nop
为空指令,其机器码为0x00000000
,不进行任何有效行为,如修改寄存器等add, sub
按无符号加减法处理,不考虑溢出
整体架构参考了《数字设计与计算机体系结构》图7-14,同时在P3的Logisim电路设计上进行了改动。
模块定义
宏定义
1 |
|
IFU
内部包括 PC(程序计数器)、IM(指令存储器)及相关逻辑。
PC 用寄存器实现,应具有同步复位功能,复位值为起始地址。
起始地址:0x00003000。
地址范围:0x00003000 ~ 0x00006FFF。
IM用ROM实现,容量为4096 × 32bit。
IM实际地址宽度仅为12位,需要使用恰当的方法将PC中储存的地址同IM联系起来。
PC的处理方法:
- PC的变化范围为0x00003000 ~ 0x00006FFF,考虑使用PC‘ = PC - 0x00003000,则PC‘的范围为0x00000000-0x00003FFF,不仅保证PC和PC‘在数值上一一对应,而且在设计处理时更加方便。
- 注意,输出是需要输出PC的值,而不是PC‘。
- IM的实际地址宽度为12位,而PC的有效位数(可能发生变化的位数)为低14位。因为ROM是按字寻址,在从IM读取指令时只需要用PC[13:2]作为地址,就可以正确读取数据。
端口定义
信号名 | 方向 | 描述 |
---|---|---|
clk | I | 时钟信号 |
reset | I | 同步复位信号,高电平有效,将PC置为0x0000_3000 |
PCSel[2:0] | I | 指定更新PC的方式 |
offset[15:0] | I | beq等branch指令的偏移量,即Instr[15:0] |
imm[25:0] | I | j指令和jal指令中的立即数,即Instr[25:0] |
jr_reg[31:0] | I | jr指令中指定寄存器所储存的数 |
PC[31:0] | O | 输出当前PC的值 |
PCa4[31:0] | O | 输出当前PC加上0x0000_0004的值 |
Instr[31:0] | O | 输出IM中PC地址上的指令 |
功能定义
序号 | 功能 | 描述 |
---|---|---|
1 | 同步复位 | reset置1,且时钟上升沿来临时,将PC置为0x0000_3000 |
2 | 更新PC的值 | 时钟上升沿来临时,根据PCSel的值更新PC的值 |
控制信号
PCSel | 操作 |
---|---|
PCSel_PCa4 | PC <- PC + 4 |
PCSel_branch | PC <- PC + 4 + sign_extend(offset||02>) |
PCSel_j | PC <- PC[31:28] || imm || 02 |
PCSel_jr | PC <- PC[31:28] || imm || 02 GPR[31] <- PC + 4 |
GRF
使用具有写使能功能的寄存器实现,寄存器总数为32个,具有异步复位功能。
其中,0号寄存器($zero)的值始终保持为0。其他的寄存器初始值(复位后)均为0,无需专门设置。
端口定义
信号名 | 方向 | 描述 |
---|---|---|
clk | I | 时钟信号 |
reset | I | 同步复位信号,高电平有效 |
WE | I | 写使能信号,高电平有效 |
A1[4:0] | I | 5位地址输入信号,指定32个寄存器中的一个,将其中存储的数据读出到RD1 |
A2[4:0] | I | 5位地址输入信号,指定32个寄存器中的一个,将其中存储的数据读出到RD2 |
A3[4:0] | I | 5位地址输入信号,指定32个寄存器中的一个将WD中的数据写入 |
WD[31:0] | I | 32为数据输入信号 |
WPC[31:0] | I | 写入寄存器时对应的指令PC值 |
RD1[31:0] | O | 输出A1指定的寄存器中的32位数据 |
RD2[31:0] | O | 输出A2指定的寄存器中的32位数据 |
功能定义
序号 | 功能 | 描述 |
---|---|---|
1 | 复位 | reset置1,且时钟上升沿来临时,所有寄存器存储的数值清零 |
2 | 读数据 | 读出A1,A2地址对应寄存器中所存储的数据到对应的RD1,RD2 |
3 | 写数据 | 当WE有效且时钟上升沿来临时,将WD写入A3所对应的寄存器中 |
控制信号
A3Sel | 操作 |
---|---|
A3Sel_rt | A3来自rt字段,对应I型指令 |
A3Sel_rd | A3来自rd字段,对应I型指令 |
A3Sel_ra | A3为$ra,对应jal指令 |
WDSel | 操作 |
---|---|
WDSel_aluans | WD来自ALU的运算结果 |
WDSel_dmrd | WD来自DM的输出RD |
WDSel_PCa4 | WD为PC + 4 |
ALU
提供 32 位加、减、或运算及大小比较功能。
加减法按无符号处理(不考虑溢出)。
端口定义
信号名 | 方向 | 描述 |
---|---|---|
A[31:0] | I | 32位运算数 |
B[31:0] | I | 32位运算数 |
ALUOp[2:0] | I | 指定ALU进行的计算 |
zero | O | 输出A - B的结果是否为0 |
result[31:0] | O | 32位运算结果 |
功能定义
序号 | 功能 | 描述 |
---|---|---|
1 | 运算 | 根据ALUOp指定的操作对A和B进行运算 |
控制信号
ALUOp | 操作 |
---|---|
ALU_add | result = A + B,不考虑溢出 |
ALU_sub | result = A + B,不考虑溢出 |
ALU_or | result = A | B |
ALU_lui | result = B | 1016 |
ALUBSel | 操作 |
---|---|
ALUBSel_grf | ALU的第二个运算数来自GRF |
ALUBSel_imm | ALU的第二个运算数来自立即数 |
DM
使用RAM实现,容量为3072 × 32bit,应具有同步复位功能,复位值为0x00000000。
起始地址:0x00000000。
地址范围:0x00000000 ~ 0x00002FFF。
端口定义
信号名 | 方向 | 描述 |
---|---|---|
clk | I | 时钟信号 |
reset | I | 同步复位信号,高电平有效 |
A[31:0] | I | 需要进行读/写操作的地址 |
WD[31:0] | I | 32位写入RAM的数据 |
WE | I | 写使能信号,高电平有效 |
DMOp[1:0] | I | 指定DM进行的读/写操作方式 |
WPC[31:0] | I | 写入DM时对应的指令PC值 |
RD[31:0] | O | 32位从RAM读出的输出数据 |
功能定义
序号 | 功能 | 描述 |
---|---|---|
1 | 复位 | reset置1,且时钟上升沿来临时,重置RAM内存为0 |
2 | 写数据 | 当WE有效且时钟上升沿到来时,将WD中的数据写入A对应的RAM地址中 |
3 | 读数据 | 读取A对应的RAM地址中存储的数据到RD |
控制信号
DMOp | 操作 |
---|---|
DM_word | 读/写整个字,对应lw和sw指令 |
DM_halfword | 读/写半个字,对应lh和sh指令 |
DM_byte | 读/写一个字节,对应lb和sb指令 |
EXT
端口定义
信号名 | 方向 | 描述 |
---|---|---|
num[15:0] | I | 16位需要扩展的立即数 |
EXTOp | I | 指定进行扩展的方式 |
result[31:0] | O | 32位完成扩展的立即数 |
功能定义
序号 | 功能 | 描述 |
---|---|---|
1 | 扩展 | 根据EXTOp指定的操作,对立即数进行扩展 |
控制信号
EXTOp | 操作 |
---|---|
EXT_zero | result = zero_extend(num) |
EXT_signed | result = sign_extend(num) |
Controller
使用与或门阵列构造控制信号。
和逻辑的功能是识别,将输入的机器码识别为相应的指令;或逻辑的功能是生成,根据输入的指令的不同,产生不同的控制信号。
端口定义
信号名 | 方向 | 描述 |
---|---|---|
opcode | I | 32位指令Instr[31:26] |
funct | I | 32位指令Instr[5:0] |
ALUflag_zero | I | ALU中两运算数相减是否为0,对应beq指令 |
A3Sel | O | 指定数据将写入GRF的寄存器序号,即A3 |
ALUOp | O | 指定ALU进行的运算操作 |
ALUBSel | O | 指定ALU第二个操作数是否为立即数 |
WDSel | O | 指定写入GRF的数据的来源 |
RegWrite | O | 是否可向GRF中写入数据 |
MemWrite | O | 是否可向DM中写入数据 |
PCSel | O | 指定更新PC的方式 |
EXTOp | O | 指定EXT进行立即数扩展的方式 |
DMOp | O | 指定DM操作的方式 |
功能定义
序号 | 功能 | 描述 |
---|---|---|
1 | 生成控制信号 | 生成控制信号 |
重要机制实现方法
生成控制信号
opcode | funct | A3Sel | ALUOp | ALUBSel | WDSel | RegWrite | MemWrite | PCSel | EXTOp | DMOp | |
---|---|---|---|---|---|---|---|---|---|---|---|
add | 000000 | 100000 | A3Sel_rd | ALU_add | ALUBSel_grf | WDSel_aluans | 1 | ||||
sub | 000000 | 100010 | A3Sel_rd | ALU_sub | ALUBSel_grf | WDSel_aluans | 1 | ||||
ori | 001101 | undefined | A3Sel_rt | ALU_or | ALUBSel_imm | WDSel_aluans | 1 | ||||
lw | 100011 | undefined | A3Sel_rt | ALU_add | ALUBSel_imm | WDSel_dmrd | 1 | 1 | DM_word | ||
sw | 101011 | undefined | ALU_add | ALUBSel_imm | 1 | 1 | DM_word | ||||
beq | 000100 | undefined | ALU_sub | ALUBSel_grf | PCSel_branch | ||||||
lui | 001111 | undefined | A3Sel_rt | ALU_lui | ALUBSel_imm | WDSel_aluans | 1 | ||||
j | 000010 | undefined | PCSel_j | ||||||||
jal | 000011 | undefined | A3Sel_ra | WDSel_PCa4 | 1 | PCSel_j | |||||
jr | 001000 | 001000 | PCSel_jr | ||||||||
lb | 100000 | undefined | A3Sel_rt | ALU_add | ALUBSel_imm | WDSel_dmrd | 1 | 1 | DM_byte | ||
sb | 101000 | undefined | ALU_add | ALUBSel_imm | 1 | 1 | DM_byte | ||||
lh | 100001 | undefined | A3Sel_rt | ALU_add | ALUBSel_imm | WDSel_dmrd | 1 | 1 | DM_halfword | ||
sh | 101001 | undefined | ALU_add | ALUBSel_imm | 1 | 1 | DM_halfword |
PCSel一列缺省值为PCSel_PCa4
当beq和ALUflag_zero同时为高电平时,PCSel为PCSel_branch
controller的verilog代码如下。
1 |
|
DM中对读写半字/字节的处理
1 |
|
测试方案
测试代码1
1 |
|
测试代码2
1 |
|
测试代码3
1 |
|
思考题
- 根据你的理解,在下面给出的DM的输入示例中,地址信号addr位数为什么是[11:2]而不是[9:0]?这个addr信号又是从哪里来的?
DM里的RAM按字节寻址,且该DM设计大小为4KB,所以应该使用addr[11:2]
addr来自ALU的计算输出,代表要读取的数据在RAM中的地址
思考上述两种控制器设计的译码方式,给出代码示例,并尝试对比各方式的优劣。
控制器设计的译码方式有三种。
三元运算符
1
2
3
4assign ALUOp = (lw || sw || add || lh || sh || lb || sb) ? `ALU_add :
(sub || beq) ? `ALU_sub :
ori ? `ALU_or :
lui ? `ALU_lui : 3'b000;case语句
1
2
3
4
5
6
7case(ALUOp)
`ALU_add: C = A + B;
`ALU_sub: C = A - B;
`ALU_or: C = A | B;
`ALU_lui: C = B << 16;
default: C = 32'h0000_0000;
endcaseif-else语句
1
2
3
4
5
6if (ALUOP == `ALU_add)
C = A + B;
else if (ALUOP == `ALU_sub)
C = A - B;
else
C = 32'h0000_0000;
assign语句配合三目运算符使用,可以不用再额外定义reg变量。
case语句,if-else语句配合宏定义使用可以增强代码的可读性。if-else语句写起来略显繁琐。
在相应的部件中,复位信号的设计都是同步复位,这与 P3 中的设计要求不同。请对比同步复位与异步复位这两种方式的 reset 信号与 clk 信号优先级的关系。
同步复位中,clk的优先级高于reset;异步复位中两者优先级相同。
C 语言是一种弱类型程序设计语言。C 语言中不对计算结果溢出进行处理,这意味着 C 语言要求程序员必须很清楚计算结果是否会导致溢出。因此,如果仅仅支持 C 语言,MIPS 指令的所有计算指令均可以忽略溢出。 请说明为什么在忽略溢出的前提下,addi 与 addiu 是等价的,add 与 addu 是等价的。提示:阅读《MIPS32® Architecture For Programmers Volume II: The MIPS32® Instruction Set》中相关指令的 Operation 部分。
addi与addiu的区别在于当出现溢出时,addiu忽略溢出,并将溢出的最高位舍弃;addi会报错SignalException(IntegerOverflow)。忽略溢出时,二者等价。