P4-CPU设计文档[BUAA-CO]
P4单周期CPU设计文档
设计整体概述
- 预计实现指令集:add、sub、ori、Lui、lw、sw、beq、nop、j、jr、jal、jalr
- R型指令:add、sub、ori、jr、jalr
| opcode | rs | rt | rd | shamt | funct |
|---|---|---|---|---|---|
| 6 | 5 | 5 | 5 | 5 | 6 |
- I型指令:lui、lw、sw、beq
| opcode | rs | rt | offset |
|---|---|---|---|
| 6 | 5 | 5 | 16 |
- J型指令:j、jal
| opcode | instr_index |
|---|---|
| 6 | 26 |
其中,nop指令为空指令,不执行任何操作,add、sub不考虑溢出,故实际执行addu和subu
- 实现功能:实现单周期CPU,能够执行上述指令集,采用模块化设计,顶层模块包含控制器
CU和数据通路模块ALU、IFU、NPC、GRF、DM、Ext共七个子模块 - 顶层设计图:

数据通路模块设计
IFU 指令单元
- 定义:模块内部包含
PC程序计数器、IM指令存储器实现,负责根据PC的值从指令存储器中读取指令输出。 - 端口定义
| 信号名 | 方向 | 位宽 | 说明 |
|---|---|---|---|
| Next_PC | I | 32 | NPC模块输出的下一条指令地址 |
| clk | I | 1 | 时钟信号 |
| reset | I | 1 | 复位信号 |
| stop | I | 1 | 停机信号 |
| RD | O | 32 | IM取得的指令 |
| PC | O | 32 | PC模块输出地址,传入NPC模块用于得到下一条指令地址 |

1 | reg [31:0] IM_Reg [0:4095]; |
实现从文件中读取指令的功能
2. 实现功能
| 序号 | 功能 | 描述 |
|---|---|---|
| 1 | 同步复位 | 当reset信号为1且处于时钟上升沿时,PC置0x00003000 |
| 2 | 停机 | 当stop信号为1时,PC保持不变 |
| 3 | 取指 | 当stop信号为0时,根据PC在clk上升沿得到的下一条指令地址,从IM读取指令 |

PC初始化为0x00003000
IM取PC[13:2]作为地址,减去0x00003000后读取指令
NPC 指令地址生成单元
- 定义:根据当前PC地址和控制信号,生成下一条指令地址。
- 端口定义
| 信号名 | 方向 | 位宽 | 说明 |
|---|---|---|---|
| PC | I | 32 | 当前指令地址 |
| instr_index | I | 32 | J型指令的立即数 |
| offset | I | 16 | I型指令的立即数 |
| rs | I | 32 | jr指令的寄存器 |
| branch | I | 1 | 是否执行I型指令跳转 |
| jump | I | 1 | 是否执行J型指令跳转 |
| jr | I | 1 | 是否执行jr指令跳转,读取rs寄存器中的值 |
| Next_PC | O | 32 | 下一条指令地址 |
| PC_plus_4 | O | 32 | 当前指令地址+4,可用于Jal指令将地址存入$ra |

1 | PC_Branch = PC + 32'h00000004 + {{14{offset[15]}}, offset, 2'b00}; |
- 实现功能
| 序号 | 功能 | 描述 |
|---|---|---|
| 1 | PC+4 | Next_PC输出PC+4 |
| 2 | I型跳转 | beq时,Next_PC输出PC_Branch |
| 3 | JR型跳转 | jr时Next_PC输出rs |
| 4 | J型跳转 | j、jal、jalr时,Next_PC输出PC_Jump |
GRF 寄存器堆
- 定义:根据读写信号,对寄存器堆进行读写操作。
- 端口定义
| 信号名 | 方向 | 位宽 | 说明 |
|---|---|---|---|
| A1 | I | 5 | 读寄存器1地址 |
| A2 | I | 5 | 读寄存器2地址 |
| RegAddr | I | 5 | 写寄存器地址 |
| RegData | I | 32 | 写数据 |
| clk | I | 1 | 时钟信号 |
| reset | I | 1 | 复位信号 |
| RegWrite | I | 1 | 写使能信号 |
| PC | I | 32 | 当前PC地址,用于输出 |
| RD1 | O | 32 | 读寄存器1数据 |
| RD2 | O | 32 | 读寄存器2数据 |

1 | if (RegWrite) begin |
实现输出寄存器堆中寄存器改变的信息
3. 实现功能
| 序号 | 功能 | 描述 |
|---|---|---|
| 1 | 复位 | 当reset为1时,将所有寄存器置为0 |
| 2 | 读 | 当RegWrite为0时,将A1、A2对应的寄存器数据输出到RD1、RD2 |
| 3 | 写 | 当RegWrite为1时,当RegAddr不为0时,在时钟上升沿将RegAddr对应的寄存器写入RegData |
A1、A2分别读取Rs、Rt寄存器,RegAddress根据RegDst选择Rt或R),RegData根据MemRead选择ALU的运算结果或I型指令的立即数
ALU 算术逻辑单元
- 定义:根据控制信号,对输入的两个数进行算术或逻辑运算。
- 端口定义
| 信号名 | 方向 | 位宽 | 说明 |
|---|---|---|---|
| A | I | 32 | 操作数1 |
| B | I | 32 | 操作数2 |
| ALU_Op | I | 4 | ALU控制信号 |
| ALU_Res | O | 32 | ALU运算结果 |
| cmp | O | 2 | A、B比较结果 |

1 | parameter ADD = 4'b0000, |
- 实现功能
| 序号 | 功能 | 描述 |
|---|---|---|
| 1 | 加法 | 当ALU_Op为3’b000时,ALU_Res输出A+B |
| 2 | 减法 | 当ALU_Op为3’b001时,ALU_Res输出A-B |
| 3 | 与 | 当ALU_Op为3’b010时,ALU_Res输出A&B |
| 4 | 或 | 当ALU_Op为3’b011时,ALU_Res输出A丨B |
| 5 | 异或 | 当ALU_Op为3’b100时,ALU_Res输出A^B |
| 6 | 低位补0 | 当ALU_Op为3’b101时,ALU_Res输出B[15:0] + 016(实现lui指令) |
| 7 | 相等 | cmp输出A、B比较结果 |
Ext 指令扩展单元
- 定义:根据控制信号,对输入的16位立即数进行零扩展或符号扩展。
- 端口定义
| 信号名 | 方向 | 位宽 | 说明 |
|---|---|---|---|
| offset | I | 16 | 16位立即数 |
| sel | I | 1 | 扩展选择信号,0为零扩展,1为符号扩展 |
| extend | O | 32 | 扩展后的32位立即数 |
- 实现功能
| 序号 | 功能 | 描述 |
|---|---|---|
| 1 | 零扩展 | 当sel为0时,extend输出 016 + offset[15:0] |
| 2 | 符号扩展 | 当sel为1时,extend输出 offset[15] ? 116 + offset[15:0] : 016 + offset[15:0] |
DM 数据存储器
- 定义:使用RAM实现,根据控制信号,对输入的地址和数据进行读写操作。
- 端口定义
| 信号名 | 方向 | 位宽 | 说明 |
|---|---|---|---|
| MemAddr | I | 32 | 32位地址 |
| WD | I | 32 | 32位数据 |
| WE | I | 1 | 读/写控制信号,0为读,1为写 |
| clk | I | 1 | 时钟信号 |
| reset | I | 1 | 同步复位信号 |
| PC | I | 32 | PC地址 |
| DM_RD | O | 32 | 32位数据 |

- 实现功能
| 序号 | 功能 | 描述 |
|---|---|---|
| 1 | 复位 | 当reset为1时,将所有数据存储单元置零 |
| 2 | 读 | 当WE为0时,输出地址对应的32位数据DM_RD |
| 3 | 写 | 当WE为1时,将MemAddr对应地址写入32位数据WD |
CU 控制单元
-
定义:利用
ANDLogic和ORLogic生成控制信号,控制其他模块的行为。 -
端口定义
控制单元需要读取指令的Op字段和Func字段,识别生成对应指令的控制信号。
| 信号名 | 方向 | 位宽 | 说明 |
|---|---|---|---|
| Op | I | 6 | instr[31:26] |
| Func | I | 6 | instr[5:0] |
| RegDst | O | 1 | GRF写地址选择信号,0为Rt,1为Rd |
| ALUSrc | O | 1 | ALU源选择信号,0为RD2,1为拓展后的offset |
| RegWrite | O | 1 | GRF写使能信号 |
| MemWrite | O | 1 | DM写使能信号 |
| is_Branch | O | 1 | I型跳转指令 |
| is_Jump | O | 1 | J型跳转指令 |
| is_Jr | O | 1 | JR跳转指令 |
| ExtOp | O | 1 | 扩展操作选择信号, 0为零拓展,1为符号拓展 |
| ALU_Op | O | 4 | 四位ALU操作码 |

1 | parameter ADDFunc = 6'b100000, // |
- 实现功能
-
ANDLogic模块- 定义:根据输入信号,识别对应指令。
- 端口定义
信号名 方向 位宽 说明 OP I 6 instr[31:26] FUNC I 6 instr[5:0] ADD O 1 add指令 SUB O 1 sub指令 ORI O 1 ori指令 LW O 1 lw指令 SW O 1 sw指令 BEQ O 1 beq指令 LUI O 1 lui指令 J O 1 j指令 JR O 1 jr指令 JAL O 1 jal指令 JALR O 1 jalr指令
-
ORLogic模块-
定义:根据输入的对应指令,生成其他模块的操作信号。
-
端口定义
信号名 方向 位宽 说明 RegDst O 1 GRF写地址选择信号,0为Rt,1为RdALUSrc O 1 ALU源选择信号,0为RD2,1为拓展后的offsetMemRead O 1 GRF数据选择信号,0为ALU_Res,1为内存读取数据RegWrite O 1 GRF写使能信号MemWrite O 1 DM写使能信号is_Branch O 1 I型跳转指令 is_Jump O 1 J型跳转指令 is_JR O 1 JR指令 ExtOp O 1 扩展操作选择信号, 0为零拓展,1为符号拓展 ALU_Op O 3 三位ALU操作码,由真值表生成 -
功能实现:根据每种指令的对应操作,在输出前将指令信号进行或运算,得到其他模块的操作信号。
-
1 | assign RegDst = ADD || SUB || JALR; |
顶层模块
- 定义:顶层模块,将所有模块连接起来,实现整个CPU的功能。
- 端口定义
信号名 方向 位宽 说明 clk I 1 时钟信号 reset I 1 复位信号 - 功能实现:将所有模块连接起来,实现整个CPU的功能。
1 | wire [31:0] PC; |
通过assign语句与三目运算符实现多路选择
1 | assign rs = RD1; |
测试方案
第四次思考题
- 阅读下面给出的 DM 的输入示例中(示例 DM 容量为 4KB,即 32bit × 1024字),根据你的理解回答,这个 addr 信号又是从哪里来的?地址信号 addr 位数为什么是 [11:2] 而不是 [9:0] ?

addr信号来自于ALU的输出端口,因为DM的容量为4KB,即32bit×1024字,是按字引索,故低2位没有作用,地址信号addr的位数应该是[11:2]而不是[9:0]。
- 思考上述两种控制器设计的译码方式(可以记录下指令对应的控制信号如何取值,也可以记录下控制信号每种取值所对应的指令),给出代码示例,并尝试对比各方式的优劣。
第一种(记录指令对应的控制信号如何取值)
1 | always @(*) begin |
第二种(控制信号每种取值所对应的指令)
1 | always @(*) begin |
记录指令的所有控制信号怎么取值,能够较方便地追踪每一条指令对应的控制信号,从而方便调试和增加新的指令,但如果添加了一个新的控制信号,需要修改所有指令对应的控制信号取值,比较麻烦。
记录控制信号取值对应的指令,可以很快找到控制信号取值的构成,方便增加新的控制信号,但增加新的指令需要修改多处,可能因为遗漏导致bug。
- 在相应的部件中,复位信号的设计都是同步复位,这与 P3 中的设计要求不同。请对比同步复位与异步复位这两种方式的 reset 信号与 clk 信号优先级的关系。
同步复位:clk信号优先级高于reset信号,复位信号只在时钟上升沿有效。
异步复位:reset信号优先级高于或相等于clk信号,复位信号在任何时刻都可以有效。应当与clk一样用一个always块来描述。
- C 语言是一种弱类型程序设计语言。C 语言中不对计算结果溢出进行处理,这意味着 C 语言要求程序员必须很清楚计算结果是否会导致溢出。因此,如果仅仅支持 C 语言,MIPS 指令的所有计算指令均可以忽略溢出。 请说明为什么在忽略溢出的前提下,addi 与 addiu 是等价的,add 与 addu 是等价的。提示:阅读《MIPS32® Architecture For Programmers Volume II: The MIPS32® Instruction Set》中相关指令的 Operation 部分。
检查addi与addiu、add与addu的对应的Operation部分,发现addi与addiu、add与addu的区别在于addi和add会在溢出时报
Integer Overflow异常,而addiu和addu不会,因此当只支持C语言时,MIPS指令可以忽略溢出,addi与addiu等价,add与addu等价。










![VLA模型技术代码调研学习 [VLA]](https://gitee.com/TheUHO/blog/raw/master/images/202409111007683.jpg)
![OpenVLA,pi_0,pi_0-fast论文精读 [VLA]](https://gitee.com/TheUHO/blog/raw/master/images/202407212255294.jpg)
![北航2025机器学习期末复习[BUAA-ML]](https://gitee.com/TheUHO/blog/raw/master/images/202407212255288.jpg)
![lab6 实验报告 [BUAA-OS]](https://gitee.com/TheUHO/blog/raw/master/images/202409111007685.jpg)