MIPS简易流水线CPU

MIPS简易流水线CPU
shiki设计思路
基本结构
流水线寄存器,GRF等模块与P6相同,新增timer模块,bridge模块,cp0模块,形成如下图所示的结构。
其中timer模块采用课程组设计,bridge模块负责将cpu传出的数据与外界,timer模块相连,cp0模块负责响应异常和终端,并记录相关信息。
## 模块设计 ### bridge +
主要用于传输数据,将数据发送至相应接口,部分代码示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15assign cpuReadData = (cpuDataAddr>=0&&cpuDataAddr<=32'h2fff)?memReadData:
(cpuDataAddr>=32'h7f00&&cpuDataAddr<=32'h7f0b)?timer1ReadData:
(cpuDataAddr>=32'h7f10&&cpuDataAddr<=32'h7f1b)?timer2ReadData:
0;
assign timer1DataAddr = cpuDataAddr;
assign timer1We = (cpuDataAddr>=32'h7f00&&cpuDataAddr<=32'h7f0b&&cpuDataByteen==4'b1111);
assign timer1WriteData = cpuWriteData;
assign timer2DataAddr = cpuDataAddr;
assign timer2We = (cpuDataAddr>=32'h7f10&&cpuDataAddr<=32'h7f1b&&cpuDataByteen==4'b1111);
assign timer2WriteData = cpuWriteData;
assign memDataAddr = cpuDataAddr;
assign memWriteData = cpuWriteData;
assign memDataByteen = (cpuDataAddr>=0&&cpuDataAddr<=32'h2fff)?cpuDataByteen:0;
assign intAddr = cpuDataAddr;
assign intByteen = (cpuDataAddr>=32'h7f20&&cpuDataAddr<=32'h7f23)?cpuDataByteen:0;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15module CP0 (
input clk, // 时钟信号
input reset, // 复位信号
input en, // mtc0指令写使能信号
input [4:0] CP0Add, // cp0寄存器地址(仅用于mtc0指令)
input [31:0] CP0In, // cp0寄存器输入数据(仅y用于mtc0指令)
output [31:0] CP0Out, // cp0寄存器输出数据 (仅用于mfc0指令)
input [31:0] VPC, // 发生异常或传入中断时的PC值
input BDIn, // 是否为延迟槽指令
input [4:0] ExcCodeIn, // 异常类型
input [5:0] HWInt, // 外部中断类型
input EXLClr, // 异常中断处理结束信号
output [31:0] EPCOut, // EPC输出值
output reg Req // 异常中断处理开始信号
);
+ 异常和中断处理逻辑(CP0部分): 1.
发生中断或异常时如果此时不在处理中断和异常,则将Req信号置为1,即中断和异常处理的开始信号,如果此时正在处理中断和异常则置为0。
2.
在下一个时钟上升沿到来时,如果Req为1,将EXL置为1,表示正在进行中断和异常处理,并将相应的输入信号存入对应寄存器。
3. EXLClr为1时,表示异常中断处理结束,EXL置为0。 +
ps:由于EPC可能产生数据冒险,为其输出端口EPCOut设计内部转发。 ### mips
顶层模块,连接cpu,bridge,timer1,timer2。
### 冒险处理模块
大体上与P6相同,由于新增了mfc0,mtc0,eret,指令,故需考虑以下情况:
1. mtc0写入EPC寄存器,下一条指令为eret指令,此时需要阻塞一个周期。 2.
mfc0,mtc0冒险处理与乘除模块的mfhi,mthi等类似(除tUse,tNew以及写寄存器地址可能不同)。
## 异常判断以及相应信号的产生
涉及到的异常情况及其编码ExcCode如下表:
异常中断码 | 助记符与名称 | 指令或指令类型 | 描述 |
---|---|---|---|
0 | Int(外部中断) | 所有指令 | 中断请求,来源于计时器与外部中断。 |
4 | AdEl(取指异常) | 所有指令 | PC地址未字对齐 | PC地址超出0x3000 ~ 0x6ffc |
AdEl(取数异常) | lw | 地址未4字节对齐 | |
lh | 地址未2字节对齐 | ||
lh,lb | 取timer寄存器的值 | ||
load型指令 | 地址计算加法溢出 | ||
load型指令 | 取数地址超出DM,timer1,timer2,中断发生器地址 | ||
5 | AdEs(存数异常) | sw | 地址未4字节对齐 |
sh | 地址未2字节对齐 | ||
sh,sb | 存timer寄存器的值 | ||
store型指令 | 地址计算加法溢出 | ||
store型指令 | 向计时器的Count寄存器存值 | ||
store型指令 | 取数地址超出DM,timer1,timer2,中断发生器地址 | ||
8 | syscall(系统调用) | syscall | 系统调用 |
10 | RI(未知指令) | - | 未知指令码 |
12 | Ov(溢出异常) | add,addi,sub | 算数溢出 |
- I极判断pc值是否产生异常同时判断是否为延迟槽指令,注意如果此时正在进行阻塞,异常判断码和延迟槽判断信号应当保持不变。
1
2
3assign ExcCodeI = (freezD==1)?ExcCodeD:
(pcI[1:0]!=0||!(pcI>=32'h3000&&pcI<=32'h6ffc))?4:0;
assign BDInI = (freezD==1)?BDInD:((codeD[31:26]==0&&codeD[5:0]==`jrfun)||codeD[31:26]==`beq||codeD[31:26]==`jal||codeD[31:26]==`bne); - D极判断是否为未知指令或系统调用,注意如果此时正在进行阻塞,异常判断码应当置为0,延迟槽判断信号保持不变,同时注意异常优先级。
1
2
3
4
5assign ExcCodeDIn = (freezD==1)?0:
(ExcCodeD!=0)?ExcCodeD:
(syscall==1)?8:
(RI==1)?10:
ExcCodeD; - E极判断是否有溢出现象,注意异常优先级。
1
2
3
4
5assign ExcCodeEIn = (ExcCodeE!=0)?ExcCodeE:
(Ov==1&&(ALUop==0||ALUop==1))?((MemWriteE==1)?5:
(MemtoRegE==1)?4:
12):
ExcCodeE; - M极判断存取指令地址是否有异常,注意异常优先级。
1
2
3
4
5
6
7
8
9
10
11
12
13assign ExcCodeMIn = (HWInt!=0)?0:
(ExcCodeM!=0)?ExcCodeM:((MemtoRegM==1)?((extMemWordOp==0&&m_data_addr[1:0]!=0)?4:
(extMemWordOp==4&&m_data_addr[0]!=0)?4:
((extMemWordOp==2||extMemWordOp==4)&&((m_data_addr>=32'h7f00&&m_data_addr<=32'h7f0b)||(m_data_addr>=32'h7f10&&m_data_addr<=32'h7f1b)))?4:
(!((m_data_addr>=0&&m_data_addr<=32'h2fff)||(m_data_addr>=32'h7f00&&m_data_addr<=32'h7f0b)||(m_data_addr>=32'h7f10&&m_data_addr<=32'h7f1b)||(m_data_addr>=32'h7f20&&m_data_addr<=32'h7f23)))?4:
ExcCodeM):
((MemWrite==1)?((mDataByteen==3&&m_data_addr[1:0]!=0)?5:
(mDataByteen==2&&m_data_addr[0]!=0)?5:
((mDataByteen==2||mDataByteen==1)&&((m_data_addr>=32'h7f00&&m_data_addr<=32'h7f0b)||(m_data_addr>=32'h7f10&&m_data_addr<=32'h7f1b)))?5:
(m_data_addr[3:0]==8&&((m_data_addr>=32'h7f00&&m_data_addr<=32'h7f0b)||(m_data_addr>=32'h7f10&&m_data_addr<=32'h7f1b)))?5:
(!((m_data_addr>=0&&m_data_addr<=32'h2fff)||(m_data_addr>=32'h7f00&&m_data_addr<=32'h7f0b)||(m_data_addr>=32'h7f10&&m_data_addr<=32'h7f1b)||(m_data_addr>=32'h7f20&&m_data_addr<=32'h7f23)))?5:
ExcCodeM):
ExcCodeM)); - 异常和中断处理开始时,清空除W极以外的所有极指令同时将这些值pc置为32'h4180。
- 异常和中断开始时,如果乘除模块正在进行乘除运算,此时不需要处理,如果异常和中断刚刚开始时(即M极为异常指令或产生中断,E极为乘除模块相关指令),则需要取消其运算。
- 异常和中断开始时,跳转至地址为32'h4180的指令,从而进行异常和中断的处理。
- 异常优先级:最早发生的异常优先级最高。
## 备注
- 由于中断可能发生于任意时刻,此时流水线cpu并不能明确地说其在进行哪一条指令,因此引入宏观pc的概念,即宏观地将流水线cpu看作单周期cpu,此时的pc值应当为CP0寄存器所在流水极的pc值(此处为M极pc)。
- EPC负责保存发生异常或中断时的pc值,即为宏观pc,然而当此时正在进行延迟槽指令时,应当存入pc+4(避免重复执行延迟槽指令)。