P7-CPU设计文档
本文最后更新于 2024年12月2日 晚上
P7-CPU设计文档
流水线架构
1 | |
IF
顶层
Instruction Fetch阶段,从指令寄存器中读取指令
| 端口 | In/Out? | 位宽 | 功能 |
|---|---|---|---|
| clk | in | 时钟信号 | |
| reset | in | 重置信号 | |
| req | in | 中断请求信号 | |
| enablePC | in | 使能信号 | |
| NPC | in | [31:0] | PC地址输入 |
| ID_OP | in | [3:0] | ID区处理指令分支类型 |
| IF_PC | out | [31:0] | 输出PC地址 |
| IF_BD | out | IF区当前指令是否为延迟槽指令 | |
| IF_ExcCode | out | [4:0] | IF区异常码 |
PC部件
| 端口 | In/Out? | 位宽 | 功能 |
|---|---|---|---|
| clk | in | 时钟信号 | |
| reset | in | 重置信号 | |
| req | in | 中断请求信号 | |
| enable | in | 使能信号 | |
| NPC | in | [31:0] | PC地址输入 |
| PC | out | [31:0] | 输出PC地址 |
PC部件处理逻辑说明
信号优先级:reset > req > enable
1 | |
IF区IF_BD信号逻辑说明
IF_BD信号用于指定当前IF区指令是否为延迟槽指令;根据
ID_OP信号决定:
1assign IF_BD = (ID_OP != `ID_NOJUMP) ? 1 : 0;
- 若ID区指令为跳转指令(branch, jal, jr, beq, bne, ...),IF_BD置1
- 反之,IF_BD置0
依次经过
IF_ID,ID_EX,EX_MEM间流水寄存器,直到PC0,PC0根据该信号决定eret跳转地址(即EPC)
1EPC <= (BD_in == 1) ? VPC - 32'D4 : VPC;
- 若VPC(受害PC)为延迟槽指令,则EPC设置为该指令的上一条指令地址
- 若VPC(受害PC)不是延迟槽指令,则EPC设置为该指令地址
注:若在4180H处理异常逻辑代码中不修改EPC,直接使用
eret指令会导致死循环
IF_ID
在时钟上升沿将IF_PC,IF_instr的值传递给ID_PC,ID_instr
| 端口 | In/Out? | 位宽 | 功能 |
|---|---|---|---|
| clk | in | 时钟信号 | |
| reset | in | 重置信号 | |
| req | in | 中断请求信号 | |
| flush | in | 冲洗信号 | |
| enable | in | 使能信号 | |
| IF_PC | in | [31:0] | IF传入PC地址 |
| IF_instr | in | [31:0] | IF传入指令 |
| IF_ExcCode | in | [4:0] | IF区异常码 |
| IF_BD | in | IF区延迟槽指令信号 | |
| ID_PC | out | [31:0] | ID接收PC地址 |
| ID_instr | out | [31:0] | ID接收指令 |
| ID_ExcCode | out | [4:0] | ID接收异常码 |
| ID_BD | ID接收延迟槽指令信号 |
优先级:
reset > req > enable/flush
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26if (reset)begin
ID_PC <= 32'h3000;
ID_instr <= 32'h0;
ID_ExcCode = 5'b0;
ID_BD = 1'b0;
end
else if (req)begin
ID_PC <= 32'h4180; // 异常处理程序入口地址
ID_instr <= 32'b0; // nop
ID_ExcCode <= 5'b0;
ID_BD <= 1'b0;
end
else if (enable)begin
if (flush)begin
ID_PC <= 32'h3000;
ID_instr <= 32'h0;
ID_ExcCode <= 5'b0;
ID_BD <= 1'b0;
end
else begin
ID_PC <= IF_PC;
ID_instr <= IF_instr;
ID_ExcCode <= IF_ExcCode;
ID_BD <= IF_BD;
end
end
ID
Instruction Decode阶段
顶层
| 端口 | In/Out? | 位宽 | 功能 |
|---|---|---|---|
| clk | in | ||
| reset | in | ||
| IF/ID输入 | |||
| IF_PC | in | [31:0] | IF区的PC,用于正常的地址+4操作 |
| ID_PC | in | [31:0] | ID区的PC |
| ID_instr | in | [31:0] | ID区的指令 |
| ID_RD1_forward | in | [31:0] | 转发的Data1 |
| ID_RD2_forward | in | [31:0] | 转发的Data2 |
| ID_ExcCode | in | [4:0] | ID区的异常码 |
| WB输入 | |||
| WB_WD | in | [31:0] | 写入数据,来自于WB阶段 |
| WB_A3 | in | [31:0] | 写入寄存器地址,来自于WB阶段 |
| WB_PC | in | [31:0] | 写入数据对应PC地址,传递给\(display语句,作为显示,来自于WB阶段 | | **ID输出** | | | | | ID_RD1 | out | [31:0] | ID输出rs寄存器读出值 | | ID_RD2 | out | [31:0] | ID输出rt寄存器读出值 | | ID_IMM32 | out | [31:0] | ID输出经过位扩展的立即数 | | ID_A3 | out | [4:0] | ID阶段的A3,向后传递用 | | ID_WD | out | [31:0] | ID阶段的写入数据,向后传递 | | NPC | out | [31:0] | ID阶段(内部NPC模块)计算的下一个地址 | | ID_A1_USE | out | [1:0] | ID阶段rs寄存器的\)T_{USE}$ |
| ID_A2_USE | out | [1:0] | ID阶段rt寄存器的\(T_{USE}\) |
| ID_MD | out | ID区当前是否在处理乘除相关指令 | |
| ID_EX_ExcCode | out | [4:0] | ID区处理后的异常码 |
| ID_OP | out | ID区指令的分支类型 | |
| IF_ID_FLUSH | out | 对IF_ID间流水寄存器的冲洗信号 |
EXT部件
立即数扩展
| 端口 | In/Out? | 位宽 | 功能 |
|---|---|---|---|
| imm16 | in | [15:0] | 输入的16位立即数 |
| ExtControl | in | 决定零扩展还是符号扩展 | |
| imm32 | out | [31:0] | 输出的为扩展后的32位立即数 |
CMP部件
判断两个输入(从寄存器取出来的两个值)是否相等,输出zero,用于处理beq信号通路
| 端口 | In/Out? | 位宽 | 功能 |
|---|---|---|---|
| A | in | [31:0] | 输入数据,接收的是转发的Data1(RD1_forward) |
| B | in | [31:0] | 输入数据,接收的是转发的Data2(RD2_forward) |
| CMPControl | in | [3:0] | CMP部件控制信号(选择比较方式) |
| zero | out | 若相等则输出1,否则输出0 |
CMPControl信号表
| 指令 | CMPControl |
|---|---|
| cmpBeq | 4'b0000 |
| cmpBgez | 4'b0001 |
| cmpBgtz | 4'b0010 |
| cmpBlez | 4'b0011 |
| cmpBltz | 4'b0100 |
| cmpBne | 4'b0101 |
| bnumeq | 4'b1000 |
NPC部件
计算下一个PC地址
| 端口 | In/Out? | 位宽 | 功能 |
|---|---|---|---|
| IF_PC | in | [31:0] | IF输出的PC |
| ID_PC | in | [31:0] | |
| ID_imm26 | in | [25:0] | Jal指令中[25:0]位,指定跳转的绝对地址 |
| imm32 | in | [31:0] | 经过EXT扩展的立即数 |
| Jr_Reg_Data | in | [31:0] | Jr指定的寄存器的值 |
| EPC_out | in | [31:0] | CP0传递的跳转指令 |
| Branch | in | Branch信号(beq激活) | |
| Jal | in | Jal信号(jal激活) | |
| Jr | in | Jr信号(jr激活) | |
| Eret | in | Eret信号(eret激活) | |
| NPC | out | [31:0] | 下一个PC地址 |
跳转地址表
| 指令 | 跳转地址 |
|---|---|
| Branch类(beq,bne) | \(ID\_PC+4+signed(imm32 << 2)\) |
| Jal | \((ID\_PC+4)_{31:28}||ID_imm26||2'b0\) |
| Jr | \(Jr\_Reg\_Data\) |
| Eret | \(EPC\_out\) |
| default | \(IF_PC+4\) |
Control部件(共用)
控制信号生成部件,这里我们采用的是分布式译码,这里展示的共用Control部件在ID阶段被使用的端口
| 端口 | In/Out? | 位宽 | 功能 |
|---|---|---|---|
| instr | in | [31:0] | 输入的指令 |
| zero | in | ID_RD1_forward与ID_RD2_forward是否相等 | |
| Branch | out | Branch信号(beq激活) | |
| Jal | out | Jal信号(jal激活) | |
| Jr | out | Jr信号(jr激活) | |
| Eret | out | Eret信号(eret激活) | |
| ExtControl | out | 控制ext部件的信号 | |
| Sel_ID_WD | out | 与jal相关,若执行jal指令则为1,该信号为1时将Write Data(写入寄存器)指定为ID_PC+8 | |
| ID_A3 | out | [4:0] | 解码阶段输出的写入寄存器地址 |
| ID_A1_USE | out | [1:0] | rs的\(T_{USE}\) |
| ID_A2_USE | out | [1:0] | rt的\(T_{USE}\) |
| CMPControl | out | [3:0] | CMP部件控制信号(选择比较方式) |
| ID_MD | out | ID区当前是否在处理乘除相关指令 | |
| ID_OP | out | [3:0] | ID区当前指令分支类型 |
| ri | out | 未知指令异常信号 | |
| SYSCALL | out | 系统调用指令信号 |
ID控制信号表
| 指令/信号 | ExtControl | ID_A3 |
|---|---|---|
| ori | 1(立即数零扩展) | rt |
| add | \ | rd |
| sub | \ | rd |
| lw | 0(立即数符号扩展) | rt |
| sw | 0(立即数符号扩展) | $0 |
| beq | 0(立即数符号扩展) | $0 |
| lui | 0(立即数符号扩展)(其实随意) | rt |
| jal | \ | $31 |
| jr | \ | \ |
| swc | \ | rd |
| bonall | 0(立即数符号扩展) | 31 |
| lh | 0 | rt |
| sh | 0 | \ |
| lb | 0 | rt |
| sb | 0 | \ |
| and | \ | rd |
| or | \ | rd |
| slt | \ | rd |
| sltu | \ | rd |
| addi | 0 | rt |
| andi | 0 | rt |
| mult | \ | $0 |
| multu | \ | $0 |
| div | \ | $0 |
| divu | \ | $0 |
| mflo | \ | rd |
| mfhi | \ | rd |
| mtlo | \ | $0 |
| mthi | \ | $0 |
| mfc0 | \ | rt |
其余信号:
\(beq/bne\rightarrow Branch\)
\(jal\rightarrow Sel\_ID\_WD\)
\(jal\rightarrow Jal\)
\(jr\rightarrow Jr\)
\(eret\rightarrow Eret\)
\(mult/multu/div/divu/mfhi/mflo/mthi/mtlo(8)\rightarrow ID\_MD\)
\(branch/jal/jr\rightarrow ID\_OP=JUMP,else\rightarrow NOJUMP\)
\(syscall\rightarrow SYSCALL\)
\(T_{USE}\)表
| ID_A1_USE | ID_A2_USE | |
|---|---|---|
| cal_r | 1 | 1 |
| cal_i | 1 | 3 |
| load | 1 | 3 |
| store | 1 | 2 |
| cal_md | 1 | 1 |
| load_md | 3 | 3 |
| store_md | 1 | 3 |
| branch | 0 | 0 |
| cal_jal | 3 | 3 |
| cal_jr | 0 | 3 |
| P7新增指令(未分类) | ||
| eret | 3 | 3 |
| mfc0 | 3 | 3 |
| mtc0 | 3 | 2 |
| syscall | 3 | 3 |
GRF部件
32个32bit寄存器组成的寄存器堆
| 端口 | In/Out? | 位宽 | 功能 |
|---|---|---|---|
| clk | in | ||
| reset | in | ||
| A1 | in | [4:0] | A1读出寄存器地址 |
| A2 | in | [4:0] | A2读出寄存器地址 |
| A3 | in | [4:0] | A3写入寄存器地址 |
| WD | in | [31:0] | 写入数据 |
| PC | in | [31:0] | 当前PC($display用) |
| RD1 | out | [31:0] | A1寄存器读出值 |
| RD2 | out | [31:0] | A2寄存器读出值 |
ID_EX
| 端口 | In/Out? | 位宽 | 功能 |
|---|---|---|---|
| clk | in | ||
| reset | in | ||
| enable | in | 使能信号 | |
| flush | in | 冲洗信号,和reset作用相同 | |
| ID_PC | in | [31:0] | |
| ID_instr | in | [31:0] | |
| ID_RD1 | in | [31:0] | |
| ID_RD2 | in | [31:0] | |
| ID_imm32 | in | [31:0] | |
| ID_A3 | in | [4:0] | |
| ID_WD | in | [31:0] | |
| ID_BD | in | ID区branch delay信号 | |
| ID_EX_ExcCode | in | [4:0] | ID区异常码 |
| EX_PC | out | [31:0] | |
| EX_instr | out | [31:0] | |
| EX_RD1 | out | [31:0] | |
| EX_RD2 | out | [31:0] | |
| EX_imm32 | out | [31:0] | |
| EX_A3 | out | [4:0] | |
| EX_WD | out | [31:0] | |
| EX_BD | out | EX区接收branch delay信号 | |
| EX_ExcCode | out | [4:0] | EX区接收异常码 |
EX
顶层
| 端口 | In/Out? | 位宽 | 功能 |
|---|---|---|---|
| clk | in | ||
| reset | in | ||
| EX_instr | in | [31:0] | EX阶段的指令 |
| EX_imm32 | in | [31:0] | 32位扩展的立即数 |
| EX_WD | in | [31:0] | EX阶段接收的写入寄存器堆的数据 |
| EX_RD1_forward | in | [31:0] | 接收hazard ctrl部件向EX阶段传递的转发数据寄存器A1值 |
| EX_RD2_forward | in | [31:0] | 接收hazard ctrl部件向EX阶段传递的转发数据寄存器A2值 |
| EX_ExcCode | in | [4:0] | EX接收区异常码 |
| EX_MEM_RES | out | [31:0] | 传递ALU计算结果 |
| EX_MEM_WD | out | [31:0] | 传递给EX_MEM流水寄存器的Write Data |
| EX_MEM_RD2 | out | [31:0] | 传递给EX_MEM流水寄存器的Read Data2 |
| EX_NEW | out | [1:0] | EX阶段的\(T_{NEW}\) |
| MULT_DIV_BUSY | out | ||
| MULT_DIV_START | out | ||
| EX_MEM_ExcCode | out | [4:0] |
MULT_DIV部件
| 端口 | In/Out? | 位宽 | 功能 |
|---|---|---|---|
| clk | in | 时钟信号 | |
| reset | in | 重制信号 | |
| A | in | [31:0] | 计算数A |
| B | in | [31:0] | 计算数B |
| start | in | 有效一个时钟周期,启动信号 | |
| MULT_DIV_OP | in | [2:0] | 乘除模块计算方式 |
| MFHI | in | mfhi信号 | |
| MFLO | in | mflo信号 | |
| busy | out | 输出延迟信号 | |
| HI | out | [31:0] | $hi值 |
| LO | out | [31:0] | $lo值 |
乘除槽相关信号表
| 指令/信号 | MULT_DIV_OP | MULT_DIV_START |
|---|---|---|
| mult | mult | 1 | | multu |multu |
1 |
| div | div | 1 | | divu |divu |
1 |
ALU部件
| 端口 | In/Out? | 位宽 | 功能 |
|---|---|---|---|
| SrcA | in | [31:0] | 操作数A |
| SrcB | in | [31:0] | 操作数B |
| ALUOp | in | [3:0] | 计算方式 |
| ALURes | out | [31:0] | ALU计算结果 |
| overflow | out | 是否溢出 |
Control部件(共用)
| 端口 | In/Out? | 位宽 | 功能 |
|---|---|---|---|
| instr | in | [31:0] | |
| ALUOp | out | [3:0] | 选择ALU操作方式 |
| out | |||
| ALU_B_Sel | out | 选择32位立即数或者寄存器rt的值 | |
| WD_Sel | out | 选择Write Data来源(1:ID阶段的PC+8,0:ALURes) | |
| EX_NEW | out | 当前EX阶段\(T_{USE}\) | |
| MULT_DIV_OP | out | 乘除模块计算方式 | |
| MULT_DIV _START | out | 乘除模块开始信号 | |
| MTHI | out | mthi信号,下同理 | |
| MTLO | out | ||
| MFHI | out | ||
| MFLO | out | ||
| MTC0 | out | ||
| LOAD | out | ||
| STORE | out |
EX控制信号表
| 指令/信号 | ALUOp | ALU_B_Sel | WD_Sel |
|---|---|---|---|
| ori | aluOr | 1(选择立即数) | 0(Write Data选择aluRes) | | add |aluAdd |
0(选择rt寄存器) | 0 |
| sub | aluSub | 0(选择rt寄存器) | 0 | | beq | \ | \ | \ | | lw |aluAdd |
1(选择立即数) | 0 |
| sw | aluAdd | 1(选择立即数) | 0 | | lh |aluAdd |
1 | 0 |
| sh | aluAdd | 1 | 0 | | lb |aluAdd |
1 | 0 |
| sb | aluAdd | 1 | 0 | | lui |aluLui |
1(选择立即数) | 0 |
| jal | \ | \ | 1(Write Data选择ID传递值) |
| jr | \ | \ | \ |
| and | aluAnd | 0(选择rt寄存器) | 0 | | or |aluOr |
0(选择rt寄存器) | 0 |
| slt | aluSlt | 0 | 0 | | sltu |aluSltu |
0 | 0 |
| addi | aluAdd | 1 | 0 | | andi |aluAnd |
1 | 0 |
| mult | \ | \ | 0 |
| mflo | \ | \ | \ |
| mfhi | \ | \ | \ |
EX\(T_{NEW}\)表
| EX_NEW | |
|---|---|
| cal_r | 1 |
| cal_i | 1 |
| load | 2 |
| store | 0 |
| cal_md | 0 |
| load_md | 1 |
| store_md | 0 |
| cal_jal | 0 |
| cal_jr | 0 |
| branch | 0 |
| P7新增指令(未分类) | |
| mfc0 | 2 |
| mtc0 | 0 |
| eret | 0 |
| syscall | 0 |
EX_MEM
| 端口 | In/Out? | 位宽 | 功能 |
|---|---|---|---|
| clk | in | ||
| reset | in | ||
| flush | in | ||
| req | in | ||
| EX_PC | in | [31:0] | EX阶段PC地址 |
| EX_instr | in | [31:0] | EX阶段指令 |
| EX_A3 | out | [4:0] | EX阶段传递的A3 |
| EX_WD | out | [31:0] | EX阶段Write Data |
| EX_RES | out | [31:0] | EX阶段ALURes |
| EX_RD2 | out | [31:0] | EX阶段Read Data2 |
| EX_BD | |||
| MEM_PC | out | [31:0] | MEM阶段PC地址 |
| MEM_instr | out | [31:0] | MEM阶段指令 |
| MEM_A3 | out | [4:0] | |
| MEM_WD | out | [31:0] | |
| MEM_RES | out | [31:0] | |
| MEM_RD2 | out | [31:0] | |
| MEM_BD | out | ||
| MEM_ExcCode | out | [4:0] |
MEM
顶层
| 端口 | In/Out? | 位宽 | 功能 |
|---|---|---|---|
| clk | in | ||
| reset | in | ||
| req | in | ||
| MEM_PC | in | [31:0] | |
| MEM_instr | in | [31:0] | |
| MEM_WD | in | [31:0] | |
| MEM_RES | in | [31:0] | |
| MEM_RD2_forward | in | [31:0] | WB转发的Read Data2 |
| MEM_A3 | in | [4:0] | MEM传递的A3寄存器地址 |
| RD | in | [31:0] | 从Memory中读出的数据 |
| MEM_ExcCode | in | [4:0] | |
| CP0_out | in | [31:0] | CP0读出数据 |
| MEM_WB_A3 | out | [4:0] | MEM区传递接收写入数据的A3寄存器,传递至WB区 |
| MEM_WB_WD | out | [31:0] | |
| MEM_A2_NEW | out | [1:0] | MEM\(T_{NEW}\) |
| MEM_BYTE_EN | out | [3:0] | 写入MEM数据的按字节使能信号 |
| MEM_WRITE_DATA | out | [31:0] | 写入MEM,按字节重新排序的数据 |
| MEM_DATA_ADDR | out | [31:0] | 写入或读出的Memory地址 |
| MEM_INST_ADDR | out | [31:0] | 当load/store指令对应的PC地址 |
| MEM_WB_ExcCode | out | [4:0] | |
| CP0_enable | out | CP0写入数据信号 | |
| mfc0_rd | out | [4:0] | mfc0/mtc0指定的寄存器rd |
| EXL_clr | out | EXL清空信号,由eret指令发出 |
MEMControl部件(共用)
| 端口 | In/Out? | 位宽 | 功能 |
|---|---|---|---|
| instr | in | ||
| MEM_WE | out | 选择是否写入Memory | |
| MEM_Sel | out | 选择是否将Memory读出值向后传递(1:yes) | |
| MEM_A2_NEW | out | MEM区\(T_{NEW}\) | |
| MEM_PART | out | [1:0] | 选择存入/读取Word,Half或者Byte |
| MEM_EXT_Control | out | [2:0] | MEM_EXT部件控制信号 |
| CP0_Sel | out | 读出数据来源选择CP0(由mfc0发出) | |
| mfc0_rd | out | [4:0] | mfc0/mtc0指定,输出指令对应的rd |
| EXL_clr | out | EXL清空信号,由eret指令发出 |
MEM信号及\(T_{NEW}\)表
| 指令/信号 | MEM_WE | MEM_Sel | MEM_A2_NEW | MEM_PART | MEM_EXT_Control |
|---|---|---|---|---|---|
| sw | 1 | 0 | 0 | memWord |
3'bz |
| sh | 1 | 0 | 0 | memHalf |
3'bz |
| sb | 1 | 0 | 0 | memByte |
3'bz |
| lw | 0 | 1 | 1 | memWord |nonExt |
|
| lh | 0 | 1 | 1 | memHalf |signedHalfExt |
|
| lb | 0 | 1 | 1 | memByte |signedByteExt |
|
| else | 0 | 0 | 0 | none |
3'bz |
MEM_WB
| 端口 | In/Out? | 位宽 | 功能 |
|---|---|---|---|
| clk | in | ||
| reset | in | ||
| req | in | ||
| MEM_PC | in | [31;0] | |
| MEM_instr | in | [31:0] | |
| MEM_A3 | in | [4:0] | |
| MEM_WD | in | [31:0] | |
| WB_PC | out | [31:0] | |
| WB_instr | out | [31:0] | |
| WB_A3 | out | [4:0] | |
| WB_WD | out | [31:0] |
HAZARD_CTRL
| 端口 | In/Out? | 位宽 | 功能 |
|---|---|---|---|
| clk | in | ||
| reset | in | ||
| ID阶段 | |||
| ID_A1 | in | [4:0] | ID阶段正在使用的A1寄存器 |
| ID_A2 | in | [4:0] | ID阶段正在使用的A2寄存器 |
| ID_RD1 | in | [31:0] | ID阶段寄存器堆读出的A1对应值 |
| ID_RD2 | in | [31:0] | ID阶段寄存器堆读出的A2对应值 |
| ID_A1_USE | in | [1:0] | \(T_{USE}\) |
| ID_A2_USE | in | [1:0] | \(T_{USE}\) |
| ID_MD | in | ID区处理指令是否与乘除相关 | |
| EX阶段 | |||
| EX_A1 | in | [4:0] | |
| EX_A2 | in | [4:0] | |
| EX_RD1 | in | [31:0] | IE阶段A2对应值,由ID区的转发值得来 |
| EX_RD2 | in | [31:0] | IE阶段A2对应值,由ID区的转发值得来 |
| EX_A1_USE | in | [1:0] | \(T_{USE}\) |
| EX_A2_USE | in | [1:0] | \(T_{USE}\) |
| EX_A3 | in | [4:0] | EX传递的A3寄存器(rd) |
| EX_WD | in | [31:0] | EX传递的Write Data |
| MULT_DIV_BUSY | in | 乘除模块忙碌信号 | |
| MULT_DIV_START | in | 乘除模块开始信号 | |
| MEM阶段 | |||
| MEM_A2 | in | [4:0] | MEM正在使用的A2 |
| MEM_RD2 | in | [31:0] | MEM的Read Data2,由EX传递而来 |
| MEM_A2_NEW | in | [1:0] | MEM的\(T_{NEW}\) |
| MEM_A3 | in | [4:0] | MEM传递A3 |
| MEM_WD | in | [31:0] | MEM传递的Write Data |
| WB | |||
| WB_A3 | in | [4:0] | |
| WB_WD | in | [31:0] | |
| 转发FORWARD | |||
| ID_RD1_forward | out | [31:0] | |
| ID_RD2_forward | out | [31:0] | |
| EX_RD1_forward | out | [31:0] | |
| EX_RD2_forward | out | [31:0] | |
| MEM_RD2_forward | out | [31:0] | |
| 暂停信号STALL | |||
| Enable_PC | out | PC使能信号 | |
| Enable_IF_ID | out | IF_ID流水寄存器使能信号 | |
| Enable_ID_EX | out | ID_EX流水寄存器使能信号 | |
| Flush_ID_EX | out | ID_EX流水寄存器刷新信号 | |
| Flush_EX_MEM | out | EX_MEM流水寄存器刷新信号 |
CPU
端口
| 端口 | In/Out? | 位宽 | 功能 |
|---|---|---|---|
| clk | in | 时钟信号 | |
| reset | in | 同步复位信号 | |
| HW_Int | in | [5:0] | 用于传递来自计时器和外部的中断信号 |
| F区 | |||
| i_inst_addr | out | [31:0] | 需要进行取指操作的流水级 PC(一般为 F 级) |
| i_inst_rdata | in | [31:0] | i_inst_addr 对应的 32 位指令 |
| BRIDGE | |||
| m_data_addr | out | [31:0] | BRIDGE待写入地址 |
| m_data_rdata | in | [31:0] | CPU_addr 对应的 32 位数据 |
| m_data_wdata | out | [31:0] | BRIDGE待写入数据 |
| m_data_byteen | out | [3:0] | BRIDGE字节使能信号 |
| MEM区 | |||
| m_inst_addr | out | [31:0] | M 级 PC |
| WB区 | |||
| w_grf_we | out | GRF 写使能信号 | |
| w_grf_addr | out | [31:0] | GRF 中待写入寄存器编号 |
| w_grf_wdata | out | [31:0] | GRF 中待写入数据 |
| w_inst_addr | out | [31:0] | W 级 PC |
| macroscopic_pc | out | [31:0] | 宏观PC |
BRIDGE
端口
| 端口 | In/Out? | 位宽 | 功能 |
|---|---|---|---|
| CPU内部传出数据 | |||
| PR_addr | in | [31:0] | 寄存器内部EX_MEM流水寄存器输出的store地址 |
| PR_WD | in | [31:0] | 寄存器内部EX_MEM流水寄存器输出的store数据 |
| PR_byteen | in | [31:0] | 寄存器字节使能信号 |
| 根据DEV_addr 从各部件获取数据 |
|||
| DEV_addr | out | [31:0] | 将PR_addr[X:2]直接输出即可,X由N个设备中地址空间需求最大者决定 |
| DM_RD | in | [31:0] | MEM区DM的读出数据 |
| TC0_RD | in | [31:0] | 计数器0的读出数据 |
| TC1_RD | in | [31:0] | 计数器1的读出数据 |
| 对DEV_addr写入 (字节)数据使能信号 |
|||
| DM_byteen | out | [3:0] | 字节使能信号 |
| TC0_enable | out | TC0写入使能信号 | |
| TC1_enable | out | TC1写入使能信号 | |
| INT_byteen | out | [31:0] | 中断发生器字节使能信号 |
| load相关,将写入 寄存器的值传回CPU |
|||
| PR_RD | out | [31:0] | 输出到WB阶段,写入GRF的数据 |
地址图
| 条目 | 地址或地址范围 | 备注 |
|---|---|---|
| 数据存储器 | 0x0000_0000∼0x0000_2FFF | |
| 指令存储器 | 0x0000_3000∼0x0000_6FFF | |
| PC 初始值 | 0x0000_30000x0000_3000 | |
| 异常处理程序入口地址 | 0x0000_41800x0000_4180 | |
| 计时器 0 寄存器地址 | 0x0000_7F00∼0x0000_7F0B | 计时器 0 的 3 个寄存器 |
| 计时器 1 寄存器地址 | 0x0000_7F10∼0x0000_7F1B | 计时器 1 的 3 个寄存器 |
| 中断发生器响应地址 | 0x0000_7F20∼0x0000_7F23 |
地址匹配方式
- 设备基地址:分为高位和低位
- 基地址低位:位数由设备占用空间大小决定,也就是偏移地址的位数
- 基地址高位:
Bridge用于译码选择设备
CP0
寄存器
| 寄存器 | 编号 | 功能 | |
|---|---|---|---|
| SR | 12 | 配置异常的功能。 | |
| Cause | 13 | 记录异常发生的原因和情况。 | |
| EPC | 14 | 记录异常处理结束后需要返回的 PC。 |
| 寄存器 | 功能域 | 位域 | 解释 |
|---|---|---|---|
| SR(State Register) | IM(Interrupt Mask) | 15:10 | 分别对应六个外部中断,相应位置 1 表示允许中断,置 0
表示禁止中断。这是一个被动的功能,只能通过 mtc0
这个指令修改,通过修改这个功能域,我们可以屏蔽一些中断。 |
| SR(State Register) | EXL(Exception Level) | 1 | 任何异常发生时置位,这会强制进入核心态(也就是进入异常处理程序)并禁止中断。 |
| SR(State Register) | IE(Interrupt Enable) | 0 | 全局中断使能,该位置 1 表示允许中断,置 0 表示禁止中断。 |
| Cause | BD(Branch Delay) | 31 | 当该位置 1 的时候,EPC 指向当前指令的前一条指令(一定为跳转),否则指向当前指令。 |
| Cause | IP(Interrupt Pending) | 15:10 | 为 6 位待决的中断位,分别对应 6 个外部中断,相应位置 1 表示有中断,置 0 表示无中断,将会每个周期被修改一次,修改的内容来自计时器和外部中断。 |
| Cause | ExcCode | 6:2 | 异常编码,记录当前发生的是什么异常。 |
| EPC | - | - | 记录异常处理结束后需要返回的 PC。 |
模块接口
| 端口 | 方向 | 位数 | 解释 |
|---|---|---|---|
| clk | IN | 1 | 时钟信号。 |
| reset | IN | 1 | 复位信号。 |
| enable | IN | 1 | 写使能信号。 |
| CP0_addr | IN | 5 | 寄存器地址。执行MTC0/MFCO指令时产生 |
| CP0_in | IN | 32 | CP0 写入数据。执行MTC0指令时产生 |
| CP0_out | OUT | 32 | CP0 读出数据。执行MFC0指令时产生,输出数据至 GPR |
| VPC | IN | 32 | 受害 PC。 |
| BD_in | IN | 1 | 是否是延迟槽指令。 |
| ExcCode_in | IN | 5 | 记录异常类型。 |
| HW_int | IN | 6 | 输入中断信号。 |
| EXL_clr | IN | 1 | 用来复位 EXL。 |
| EPC_out | OUT | 32 | EPC 的值。 |
| Req | OUT | 1 | 进入处理程序请求。 |
| macroscopic_pc | OUT | [31:0] | 宏观PC |
异常编码
| 异常与中断码 | 助记符与名称 | 指令与指令类型 | 描述 | 检测模块 |
|---|---|---|---|---|
| 0 | Int (外部中断) |
所有指令 | 中断请求,来源于计时器与外部中断。 | \ |
| 4 | AdEL (取指异常) |
所有指令 | PC 地址未字对齐。 | IF |
PC 地址超过 0x3000 ~ 0x6ffc。 |
IF | |||
AdEL (取数异常) |
lw |
取数地址未与 4 字节对齐。 | MEM | |
lh |
取数地址未与 2 字节对齐。 | MEM | ||
lh, lb |
取 Timer 寄存器的值。 | MEM | ||
| load 型指令 | 计算地址时加法溢出。 | EX | ||
| load 型指令 | 取数地址超出 DM、Timer0、Timer1、中断发生器的范围。 | MEM | ||
| 5 | AdES (存数异常) |
sw |
存数地址未 4 字节对齐。 | MEM |
sh |
存数地址未 2 字节对齐。 | MEM | ||
sh, sb |
存 Timer 寄存器的值。 | MEM | ||
| store 型指令 | 计算地址加法溢出。 | EX | ||
| store 型指令 | 向计时器的 Count 寄存器存值。 | MEM | ||
| store 型指令 | 存数地址超出 DM、Timer0、Timer1、中断发生器的范围。 | MEM | ||
| 8 | Syscall (系统调用) |
syscall |
系统调用。 | ID |
| 10 | RI(未知指令) |
- | 未知的指令码。 | ID |
| 12 | Ov(溢出异常) |
add, addi, sub |
算术溢出。 | EX |
阻塞矩阵
| IF/ID当前指令 | ID/EX | EX/MEM | MEM/WB | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| 指令类型 | 源寄存器 | \(T_{use}\) | cal_r 1/rd) |
cal_i (1/rt) |
load (2/rt) |
cal_r (0/rd) |
cal_i (0/rt) |
load (1/rt) |
cal_r (0/rd) |
cal_i (0/rt) |
load (0/rt) |
| beq | rs/rt | 0 | X | X | X | X | |||||
| cal_r | rs_rt | 1 | X | ||||||||
| cal_i | rs | 1 | X | ||||||||
| load | rs(base) | 1 | X | ||||||||
| store | rs(base) | 1 | X | ||||||||
| store | rt | 2 |
暂停实现
使用课程讲解的AT法,在流水线运行期间,ID区提供\(T_{USE}\),EX,MEM区提供\(T_{NEW}\),在冒险控制模块中采用以下判断逻辑:
1
2
3
4assign STALL = (ID_A1 == EX_A3 && ID_A1_USE < EX_NEW && EX_A3 != 0)
|| (ID_A2 == EX_A3 && ID_A2_USE < EX_NEW && EX_A3 != 0)
|| (ID_A1 == MEM_A3 && ID_A1_USE < MEM_A2_NEW && MEM_A3 != 0)
|| (ID_A2 == MEM_A3 && ID_A2_USE < MEM_A2_NEW && MEM_A3 != 0);STALL信号会控制三个行为:
- 暂停IF区的PC模块
- 暂停IF_ID间流水寄存器
- 刷新ID_EX间流水寄存器(等同于reset)
1
2
3assign Enable_PC = !STALL;
assign Enable_IF_ID = !STALL;
assign Flush_ID_EX = STALL;
转发实现
转发有五条可能的数据通路:
- \(EX\_MEM\rightarrow ID\)
- \(MEM\_WB\rightarrow ID\)
- \(EX\_MEM\rightarrow EX\)
- \(MEM\_WB\rightarrow EX\)
- \(MEM\_WB\rightarrow MEM\)
这里以ID区的RD1转发数据逻辑为例:
1
2
3
4assign ID_RD1_forward = (ID_A1 == 5'b0) ? 0 :
(ID_A1 == MEM_A3) ? MEM_WD :
(ID_A1 == WB_A3) ? WB_WD :
ID_RD1;
寄存器内部转发实现
1 | |
测试方案
Python自动生成测试mips文件Mars运行mips文件,生成正确结果和机器码iverilog运行CPU文件,生成测试结果Python比较两份答案
思考题
1、请查阅相关资料,说明鼠标和键盘的输入信号是如何被 CPU 知晓的?
当键盘或者鼠标按下按键时,设备会发出一个中断信号,中断信号经过中断控制器传到CPU,CPU根据不同的中断号执行不同的中断响应程序,然后进行相应的IO操作
2、请思考为什么我们的 CPU 处理中断异常必须是已经指定好的地址?如果你的 CPU 支持用户自定义入口地址,即处理中断异常的程序由用户提供,其还能提供我们所希望的功能吗?如果可以,请说明这样可能会出现什么问题?否则举例说明。(假设用户提供的中断处理程序合法)
统一的CPU处理中断异常地址能够实现软件的兼容.
会影响CPU的处理逻辑
3、为何与外设通信需要 Bridge?
让CPU访问不同外设只需要通过对应的地址,这种操作遵循了"高内聚,低耦合"的原则
4、请阅读官方提供的定时器源代码,阐述两种中断模式的异同,并分别针对每一种模式绘制状态移图。
当计数器倒计数为0时,计数器停止计数,Ctrl寄存器的计数使能自动变为0,并且中断信号时钟保持有效,直到屏蔽中断或重新开始计数

计数器模式1:
当计数器倒计数为0,自动读取PRESENT寄存器的值,然后重新开始倒计数,这种模式下中断信号只会产生一个中断周期

5、倘若中断信号流入的时候,在检测宏观 PC 的一级如果是一条空泡(你的 CPU 该级所有信息均为空)指令,此时会发生什么问题?在此例基础上请思考:在 P7 中,清空流水线产生的空泡指令应该保留原指令的哪些信息?
宏观PC突然变为0x0000_0000
保留原指令的PC信息
6、为什么 jalr 指令为什么不能写成
jalr $31, $31?
若
jalr $31, $31指令的延迟槽内发生异常或者需要响应中断,那么在处理异常结束后会再次执行jalr $31, $31指令,这时的$31值已经被修改,会跳转到不正确的PC地址