P4
P4_Study
1 单周期CPU设计方案(Verilog实现)
1.1 设计概述
本文所呈现的是利用Verilog实现的MIPS架构CPU,可以支持10条指令,含有PC、NPC、IM、GRF、ALU、DM、Controller、EXT、Branch模块。整体采用自下而上的设计思路。
1.2 实现指令说明
1.2.1 R型指令
算术指令:add(暂视为不做溢出检查),sub(暂视为不做溢出检查)
跳转指令:jr
1.2.2 I型指令
B类指令:beq
算术指令:lui,ori
访存指令:lw,sw
1.2.3 J型指令
跳转指令:jal
1.2.4 其他
nop
1.3 数据通路模块定义
1.3.1 PC
该模块包含一个32位寄存器用于存储当前执行的指令地址,考虑到可综合性,不用添加initial模块,通过tb里的reset来实现initial。
注意: 指令地址从0x0000_3000开始
- 端口定义
信号名 方向 位宽 描述 clk I 1 时钟信号 reset I 1 同步复位信号 NPC I 32 下一条指令地址 PC O 32 当前指令地址 - 功能定义
序号 功能名称 功能描述 1 同步复位 时钟上升沿到来时,如果reset信号有效,地址置为0x0000_3000 2 写入NPC 将下一条指令地址NPC写入寄存器
1.3.2 NPC
该模块为逻辑运算,通过选择信号和当前指令计算出下一条指令地址
- 端口定义
信号名 方向 位宽 描述 pc I 32 当前指令地址 imm16 I 16 instr[15:0] imm26 I 26 instr[25:0] ra I 32 GPR[ra] (也可以是其他寄存器的内容) PCCtrl I 1 0 :选择pc+4
1 :选择beq所对应的npcJump I 1 0:不是jr/jal指令
1:是jr/jal指令jr I 1 0:不是jr指令
1:是jr指令 - B类与J类指令实现机制
通过mux实现对npc的输出选择
注意:
弄清楚mux的0、1对应
1.3.3 IM
该模块为指令存储单元,大小为4096*32 bits
注意:
- ROM为只读存储器,reset时其中数据不清零
- pc默认是从0x0000_3000开始,故使用pc在ROM中索引相应指令时应为
temp = pc - 32'h0000_3000
- ROM容量为2^12,故
addr = temp[13:2]
- 利用系统调用函数读取指令信息
1
2
3initial begin
$readmemh("code.txt",rom);
end
- 端口定义
信号名 方向 位宽 描述 clk I 1 时钟信号 reset I 1 同步复位信号 pc I 32 当前指令地址 opcode O 6 instr[31:26] func O 6 instr[5:0] rs O 6 instr[25:21] rt O 6 instr[20:16] rd O 6 instr[15:11] imm16 O 16 imm16[15:0] imm26 O 26 imm26[25:0] - 功能定义
序号 功能名称 功能描述 1 取指令 根据pc在ROM中取出相应指令 2 取数据 splitter行为,取出instr不同位所拥有的信息
1.3.4 GRF
该模块包含32个32位寄存器,对应MIPS架构中$0~$31通用寄存器,可以通过输入的5位地址访存寄存器,其中,$0寄存器设置写入信息为const0。
- 端口定义
信号名 方向 位宽 描述 clk I 1 时钟信号 reset I 1 同步复位信号 A1 I 5 需要读取的第一个寄存器编号 A2 I 5 需要读取的第二个寄存器编号 A3 I 5 需要写入的寄存器编号 pc I 32 当前指令的地址 Data I 32 需要写入的数据 RegWrite I 1 写使能信号 RD1 O 32 读取的第一个寄存器数据 RD2 O 32 读取的第二个寄存器数据 - 功能定义
序号 功能名称 功能描述 1 同步复位 当时钟上升沿到来,若reset信号有效,寄存器全部置0 2 读取寄存器 根据寄存器编号读取寄存器内容 3 写寄存器 根据寄存器编号、写使能信号、写入数据,向相应寄存器写入数据
1.3.5 ALU
该模块通过计算控制信号aluCtrl实现计算
- 端口说明
信号名 方向 位宽 描述 SourceA I 32 第一个操作数 SourceB I 32 第二个操作数 aluCtrl I 3 计算控制信号
000:与 001:或
010:加 110:减ALUResult O 32 计算结果
1.3.6 DM
该模块为数据存储单元,大小为3072*32 bits
- 端口说明
信号名 方向 位宽 描述 clk I 1 时钟信号 reset I 1 同步复位信号 pc I 32 当前指令地址 Addr I 32 需要读取/写入的地址 WD I 32 需要写入的数据 ReadData O 32 从相应地址读取的数据
1.3.7 EXT
该模块通过位扩展信号对imm16进行位扩展
注意:位拼接符的使用{{16{imm16[15]}},imm16}
,16外也有大括号,大括号的对应不要出错
- 端口说明
信号名 方向 位宽 描述 imm16 I 16 instr[15:0] EXTControl I 2 控制以何种方式位扩展 immExtend O 32 扩展后的结果
1.3.8 Branch
该模块输出控制信号PCSource,决定是否实现B类指令的跳转
- 端口说明
信号名 方向 位宽 描述 If_branch I 1 当前是否是B类指令 ALUResult I 32 ALU的计算结果 PCSource O 1 是否实现B类指令跳转
1.4 控制模块定义
1.4.1 Controller
该模块通过解码opcode和func来输出数据通路中的控制信号,主要分为and逻辑与or逻辑
拓展:在and逻辑中增加相应的指令信号,在or逻辑中将需要置1的信号或上该指令信号。
- 端口说明
信号名 方向 位宽 描述 opcode I 6 instr[31:26] func I 6 instr[5:0] Jump O 1 是否J型指令 jr O 1 是否为jr指令 RegDst O 1 0:rt
1: rdraLink O 1 0: rt/rd
1: ra(31)aluSource O 1 0: RD2
1: immExtendBranch O 1 当前是否为B类指令 MemtoReg O 1 0:ALUResult
1:ReadDataAddrTrans O 1 0: A/R
1:pc+4RegWrite O 1 GRF写使能信号 MemWrite O 1 DM写使能信号 EXTCtrl O 2 位扩展控制信号 aluCtrl O 3 ALU控制信号
1.4.2 MUX
多个MUX模块放在同一个mux.v文件中。其实可以不写mux.v文件,遇到多路选择器可以直接用三目语句而不用示例化一个MUX。
注意: 0,1一定要对应好!!!
mux_mforn
- 端口说明
信号名 方向 位宽 描述 A I n 选择数据1 B I n 选择数据2 sel I 1 选择信号 result O n 输出结果
2 测试方案
2.1 测试数据
通过比较大的测试数据和与同学对拍进行测试。
1 | lui $1,0x64a1 |
机器码
1 | 3c0164a1 |
3 可能的拓展
3.1 draft
1 | // lw/lh/lhu/lb/lbu |
3.2 其他拓展思考
- 主要修改ALU模块和Controller模块
- 对于半字/字节读取等,在DM模块做出相应修改
- 读好RTL,列出信号的0,1情况,认真
4 思考题解答
- 阅读下面给出的 DM 的输入示例中(示例 DM 容量为 4KB,即 32bit × 1024字),根据你的理解回答,这个 addr 信号又是从哪里来的?地址信号 addr 位数为什么是 [11:2] 而不是 [9:0] ?
答:addr信号是上一个模块ALU计算出的ALUResult(当然根据每条指令RTL的不同,也可能是其他模块的输出结果)。因为DM是以字(32bits)为单位存储,而addr是以字节(8bits)为单位计数,因此2^12(Byte)/2^2 = 2^10,去掉addr的最低两位(表示字节),取addr[11:2]。 - 思考上述两种控制器设计的译码方式,给出代码示例,并尝试对比各方式的优劣。第一种译码方式方便清楚每一个指令对应的控制信号,但书写代码量较大。第二种译码方式代码书写量较小,但需要注意的是,增加新的指令时,各种控制信号的增改勿重勿漏。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17//指令对应的控制信号如何取值
always @(*)
begin
if (add) begin
RegDst = 1;
RegWrite = 1;
ALUCtrl = 3'b010;
end
else if (sub) begin
//......
end
//......
end
//控制信号所对应的指令
assign Jump = jal | jr;
assign RegDst = add | sub;
//...... - 在相应的部件中,复位信号的设计都是同步复位,这与 P3 中的设计要求不同。请对比同步复位与异步复位这两种方式的 reset 信号与 clk 信号优先级的关系。
答:同步复位clk信号优先级更高,异步复位reset信号优先级更高。
祝P4上机一切顺利!
P4_review
写在前面:Verilog就是很容易出小问题
- 是否有符号数,注意
$signed
- 多加括号,勤加括号
- 判断条件写成
temp32 != temp32
,我是笨蛋 - 不要慌乱,把子模块的信号什么都加好
- 祝流水线顺利!
- Post title:P4
- Post author:Coooookie
- Create time:2023-01-02 20:29:59
- Post link:https://coooookie0913.github.io/2023/01/02/P4/
- Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.