多周期CPU
多周期数据通路
R | lw or sw | beq | J | |
---|---|---|---|---|
IF | PC<=PC+4; IR <=MemInst[PC]; | * | * | * |
ID | opcode<=IR[31:26]; A<=Reg[IR[25:21]]; B<=Reg[IR[20:16]]; ALUOut<=PC+(signext(IR[15:0]«2)) | * | * | * |
EX | ALUOut <= A op B | ALUOut<=A+sign-ext(IR[15:0]) | if (A=B)PC<=ALUOut | PC <= {PC[31:28],IR[25:0],2’b00} |
MEM | Reg[IR[15:11]]<=ALUOut | Lw:MDR<=MemData[ALUOut];Sw:MemData[ALUout] <=B | ||
WB | Reg[IR[20:16]]<=MDR |
重点控制信号的周期:
- IRWrite:在Instruction fench阶段被置为1,但在lw的Memory access阶段被置为0,因为在lw的Register writeback阶段,Instruction Register不能再更新,如果更新的话,会被读出的数据覆盖。
- MemRead:在Instruction fench阶段被置为1(用于读取指令),在Instruction decode阶段为0,在lw的Memory access阶段被置为1。
- MemWrite:默认0,在sw的Memory access阶段被置为1。
- ALUSrc1:在Instruction fench阶段为00(PC),在Execution阶段根据实际情况修改。
- ALUSrc2:在Instruction fench阶段为01(4),在Instruction decode阶段为11(imm«2),在Execution阶段根据实际情况修改。
- PCWrite:在Instruction fench阶段为1(PC<=PC+4),在Instruction decode阶段为0,此后若执行跳转类指令则被置为1。
- PCSource:默认为00(PC<=PC+4),在Execution阶段视情况改变。
- IorD:默认0(取指令),在Memory access阶段被置为1。
- PCWriteCond:在beq的Execution阶段被置为1。
- MemtoReg:默认00。
- RegDst:默认00。
- RegWrite:默认0,在jal和jalr以及Register writeback中被置为1。
- ExtOp:在Instruction decode阶段被置为1,因为需要算跳转地址。
- ALUOp:在Instruction fench和Instruction decode均为00,因为需要执行加法操作;R type被置为10,beq被置为01。
多周期异常和中断处理
异常指内部不可预知事件(溢出,同步),中断指外部不可预知事件(I/O,异步)。
简单起见,假设我们需要处理两种异常:1)未定义指令的执行 2)算术溢出,异常处理程序的入口为0x80000180。
我们需要添加2个寄存器:
- EPC Register:保存受影响的指令的地址。注意写入EPC的地址应该为PC-4。
- Cause Register:记录产生异常事件原因。此处0为未定义指令,1为算术溢出。
4个控制信号:
- EPCWrite:EPC写入使能,在触发异常/中断时被置为1。
- CauseWrite:Cause写入使能。
- PCSource:增加0x80000180。
- IntCause:异常原因选择信号。
异常处理的步骤大致如下:
-
异常检测。通过检测 ALU 的溢出信号,判断是否发生溢出异常。
-
保存现场。在异常程序计数器(Exception Program Counter,EPC)中保存出错的指令地址。
-
跳转到异常处理程序。通过修改程序计数器(PC)的值,使得处理器进入异常处理程序。
-
异常/中断处理程序采取操作,比如可以执行对溢出情况实现定义的一些操作,或者终止程序运行并报告。在异常处理完成后,异常处理程序可以选择终止程序,也可以根据 EPC 存储的指令地址恢复并继续执行程序。