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
信号决定:
1
assign 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
)
1
EPC <= (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
26
if (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
4
assign 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
3
assign 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
4
assign 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地址