我们使用术语自陷(trap)来指当被一个异常条件引起的事件发生在一个 RISC-V 的线程里的时候,同步地把控制权传输给管理员环境
`include "defines.v"
module pc_reg(
input wire clk,
input wire rst,
//来自控制模块的信息
input wire[5:0] stall,
input wire flush, //流水线清除信号
input wire[`RegBus] new_pc, //异常处理例程入口地址
//来自译码阶段的信息
input wire branch_flag_i,
input wire[`RegBus] branch_target_address_i,
output reg [`InstAddrBus] pc, //InstAddrBus为宏定义 31:0 代表ROM的地址总线宽度 输出给ROM的addr
output reg ce //给到ROM的使能
);
//如果复位,则使能信号ce拉0,否则置1
always @ (posedge clk) begin
if (rst == `RstEnable) begin //复位信号有效 1'b1
ce <= `ChipDisable;
end
else begin
ce <= `ChipEnable;
end
end
//如果使能信号为低,则指令地址拉0;使能有效,则指令地址自加4'h4
always @ (posedge clk) begin
if (ce == `ChipDisable) begin //芯片禁止宏定义 1'b0
pc <= 32'h00000000;
end
else begin
if(flush == 1'b1) begin //输入信号为1表示异常发生,将从CTRL模块给出的异常
pc <= new_pc; //处理例程入口地址new_pc处取值执行
end
else if(stall[0] == `NoStop)begin
if(branch_flag_i == `Branch) begin
pc <= branch_target_address_i;
end
else
pc <= pc + 4'h4; //自加4 字节寻址
end
end
end
endmodule
`include "defines.v"
module if_id(
input wire clk,
input wire rst,
input wire [`InstBus] if_inst, //InstBus为ROM数据宽度,同样为31:0
input wire[`InstAddrBus] if_pc , //ROM地址总线宽度 31:0
//来自控制模块的信息
input wire[5:0] stall,
input wire flush,
output reg [`InstBus] id_inst,
output reg[`InstAddrBus] id_pc
);
//复位有效 输出为32位的0;否则则寄存传递来的取指指令地址和指令
//1.当stall[1]为stop,stall[2]为nostop,表示取指阶段暂停,译码阶段继续
// 使用空指令作为下一个周期进入译码阶段的指令
//2.当stall[1]为nostop,取指阶段继续,取得的指令进入译码阶段
//3.其余情况,保持不变
always @ (posedge clk) begin
if (rst == `RstEnable) begin
id_pc <= `ZeroWord;
id_inst <= `ZeroWord;
end
else if(flush == 1'b1 ) begin //发生异常 清除流水线
id_pc <= `ZeroWord;
id_inst <= `ZeroWord;
end
else if(stall[1] == `Stop && stall[2] == `NoStop) begin
id_pc <= `ZeroWord;
id_inst <= `ZeroWord;
end
else if(stall[1] == `NoStop) begin
id_pc <= if_pc;
id_inst <= if_inst;
end
end
endmodule
`include "defines.v"
module id_ex(
input wire clk,
input wire rst,
input wire flush, //流水线消除信号
//从译码阶段传递的信息
input wire[`AluOpBus] id_aluop, //[7:0]
input wire[`AluSelBus] id_alusel, //[2:0]
input wire[`RegBus] id_reg1,
input wire[`RegBus] id_reg2,
input wire[`RegAddrBus] id_wd,
input wire id_wreg,
input wire[`RegBus] id_link_address, //处于译码阶段的转移指令要保存的返回地址
input wire id_is_in_delayslot, //当前处于译码阶段的指令是否位于延迟槽
input wire next_inst_in_delayslot_i, //下一条进入译码阶段的指令是否位于延迟槽
input wire[`RegBus] id_current_inst_address, //译码阶段指令地址
input wire[31:0] id_excepttype, //译码阶段异常信息
//当前处于译码阶段的指令
input wire[`RegBus] id_inst,
//来自控制模块的
input wire[5:0] stall,
//传递到执行阶段的
output reg[`AluOpBus] ex_aluop,
output reg[`AluSelBus] ex_alusel,
output reg[`RegBus] ex_reg1,
output reg[`RegBus] ex_reg2,
output reg[`RegAddrBus] ex_wd,
output reg ex_wreg,
output reg[`RegBus] ex_link_address, //处于执行阶段的转移指令要保存的返回地址
output reg ex_is_in_delayslot, //当前处于执行阶段的指令是否位于延迟槽
output reg is_in_delayslot_o, //当前译码阶段的指令是否位于延迟槽
output reg[31:0] ex_excepttype, //译码阶段收集到的异常信息
output reg[`RegBus] ex_current_inst_address,//执行阶段指令地址
//当前处于执行阶段的指令
output reg[`RegBus] ex_inst
);
//打一拍传过去
//1.当stall[2]为stop,stall[3]为nostop,表示译码阶段暂停,执行阶段继续
// 使用空指令作为下一个周期进入执行阶段的指令
//2.当stall[2]为nostop,译码阶段继续,译码后的指令进入执行阶段
//3.其余情况,保持不变
always @ (posedge clk) begin
if (rst == `RstEnable) begin
ex_aluop <= `EXE_NOP_OP;
ex_alusel <= `EXE_RES_NOP;
ex_reg1 <= `ZeroWord;
ex_reg2 <= `ZeroWord;
ex_wd <= `NOPRegAddr;
ex_wreg <= `WriteDisable;
ex_link_address <= `ZeroWord;
ex_is_in_delayslot <= `NotInDelaySlot;
is_in_delayslot_o <= `NotInDelaySlot;
ex_inst <= `ZeroWord;
ex_excepttype <= `ZeroWord;
ex_current_inst_address <= `ZeroWord;
end
else if(flush == 1'b1 ) begin //清除流水线
ex_aluop <= `EXE_NOP_OP;
ex_alusel <= `EXE_RES_NOP;
ex_reg1 <= `ZeroWord;
ex_reg2 <= `ZeroWord;
ex_wd <= `NOPRegAddr;
ex_wreg <= `WriteDisable;
ex_excepttype <= `ZeroWord;
ex_link_address <= `ZeroWord;
ex_inst <= `ZeroWord;
ex_is_in_delayslot <= `NotInDelaySlot;
ex_current_inst_address <= `ZeroWord;
is_in_delayslot_o <= `NotInDelaySlot;
end
else if(stall[2] == `Stop && stall[3] == `NoStop) begin
ex_aluop <= `EXE_NOP_OP;
ex_alusel <= `EXE_RES_NOP;
ex_reg1 <= `ZeroWord;
ex_reg2 <= `ZeroWord;
ex_wd <= `NOPRegAddr;
ex_wreg <= `WriteDisable;
ex_link_address <= `ZeroWord;
ex_is_in_delayslot <= `NotInDelaySlot;
ex_inst <= `ZeroWord;
ex_excepttype <= `ZeroWord;
ex_current_inst_address <= `ZeroWord;
end
else if(stall[2] == `NoStop) begin
ex_aluop <= id_aluop;
ex_alusel <= id_alusel;
ex_reg1 <= id_reg1;
ex_reg2 <= id_reg2;
ex_wd <= id_wd;
ex_wreg <= id_wreg;
ex_link_address <= id_link_address;
ex_is_in_delayslot <= id_is_in_delayslot;
is_in_delayslot_o <= next_inst_in_delayslot_i;
ex_inst <= id_inst;
ex_excepttype <= id_excepttype;
ex_current_inst_address <= id_current_inst_address;
end
end
endmodule
`include "defines.v"
module ex_mem(
input wire clk,
input wire rst,
//来自控制模块的信息
input wire[5:0] stall,
input wire flush,
//为实现加载、访存指令而添加
input wire[`AluOpBus] ex_aluop, //执行阶段的指令要进行的运算的子类型
input wire[`RegBus] ex_mem_addr, //执行阶段的加载、存储指令对应的存储器地址
input wire[`RegBus] ex_reg2, //执行阶段的存储指令要存储的数据或lwl/lwr要加载到的目的段寄存器原始值
//来自执行阶段的信息
input wire[`RegAddrBus] ex_wd,
input wire ex_wreg,
input wire[`RegBus] ex_wdata,
input wire[`RegBus] ex_hi,
input wire[`RegBus] ex_lo,
input wire ex_whilo,
//协处理器
input wire ex_cp0_reg_we,
input wire[4:0] ex_cp0_reg_write_addr,
input wire[`RegBus] ex_cp0_reg_data,
//乘累
input wire[`DoubleRegBus] hilo_i,
input wire[1:0] cnt_i,
input wire[31:0] ex_excepttype, //译码执行收集的异常信息
input wire ex_is_in_delayslot,
input wire[`RegBus] ex_current_inst_address,
//送到访存阶段的信息
output reg[`RegAddrBus] mem_wd,
output reg mem_wreg,
output reg[`RegBus] mem_wdata,
output reg[`RegBus] mem_hi,
output reg[`RegBus] mem_lo,
output reg mem_whilo,
//为实现加载、访存指令而添加
output reg[`AluOpBus] mem_aluop, //访存阶段的指令要进行的运算的子类型
output reg[`RegBus] mem_mem_addr,//访存阶段的加载、存储指令对应的存储器地址
output reg[`RegBus] mem_reg2, //访存阶段的存储指令要存储的数据或lwl/lwr要加载到的目的段寄存器原始值
output reg mem_cp0_reg_we,
output reg[4:0] mem_cp0_reg_write_addr,
output reg[`RegBus] mem_cp0_reg_data,
output reg[31:0] mem_excepttype,
output reg mem_is_in_delayslot,
output reg[`RegBus] mem_current_inst_address,
//乘累
output reg[`DoubleRegBus] hilo_o,
output reg[1:0] cnt_o
);
//1.当stall[3]为stop,stall[4]为nostop,表示执行阶段暂停,访存阶段继续
// 使用空指令作为下一个周期进入访存阶段的指令
//2.当stall[3]为nostop,执行阶段继续,执行后的指令进入访存阶段
//3.其余情况,保持不变
always @ (posedge clk) begin
if(rst == `RstEnable) begin
mem_wd <= `NOPRegAddr;
mem_wreg <= `WriteDisable;
mem_wdata <= `ZeroWord;
mem_hi <= `ZeroWord;
mem_lo <= `ZeroWord;
mem_whilo <= `WriteDisable;
hilo_o <= {`ZeroWord, `ZeroWord};
cnt_o <= 2'b00;
mem_aluop <= `EXE_NOP_OP;
mem_mem_addr <= `ZeroWord;
mem_reg2 <= `ZeroWord;
mem_cp0_reg_we <= `WriteDisable;
mem_cp0_reg_write_addr <= 5'b00000;
mem_cp0_reg_data <= `ZeroWord;
mem_excepttype <= `ZeroWord;
mem_is_in_delayslot <= `NotInDelaySlot;
mem_current_inst_address <= `ZeroWord;
end
else if(flush == 1'b1 ) begin
mem_wd <= `NOPRegAddr;
mem_wreg <= `WriteDisable;
mem_wdata <= `ZeroWord;
mem_hi <= `ZeroWord;
mem_lo <= `ZeroWord;
mem_whilo <= `WriteDisable;
mem_aluop <= `EXE_NOP_OP;
mem_mem_addr <= `ZeroWord;
mem_reg2 <= `ZeroWord;
mem_cp0_reg_we <= `WriteDisable;
mem_cp0_reg_write_addr <= 5'b00000;
mem_cp0_reg_data <= `ZeroWord;
mem_excepttype <= `ZeroWord;
mem_is_in_delayslot <= `NotInDelaySlot;
mem_current_inst_address <= `ZeroWord;
hilo_o <= {`ZeroWord, `ZeroWord};
cnt_o <= 2'b00;
end
else if(stall[3] == `Stop && stall[4] == `NoStop) begin
mem_wd <= `NOPRegAddr;
mem_wreg <= `WriteDisable;
mem_wdata <= `ZeroWord;
mem_hi <= `ZeroWord;
mem_lo <= `ZeroWord;
mem_whilo <= `WriteDisable;
hilo_o <= hilo_i;
cnt_o <= cnt_i;
mem_aluop <= `EXE_NOP_OP;
mem_mem_addr <= `ZeroWord;
mem_reg2 <= `ZeroWord;
mem_cp0_reg_we <= `WriteDisable;
mem_cp0_reg_write_addr <= 5'b00000;
mem_cp0_reg_data <= `ZeroWord;
mem_excepttype <= `ZeroWord;
mem_is_in_delayslot <= `NotInDelaySlot;
mem_current_inst_address <= `ZeroWord;
end
else if(stall[3] == `NoStop) begin
mem_wd <= ex_wd;
mem_wreg <= ex_wreg;
mem_wdata <= ex_wdata;
mem_hi <= ex_hi;
mem_lo <= ex_lo;
mem_whilo <= ex_whilo;
hilo_o <= {`ZeroWord, `ZeroWord};
cnt_o <= 2'b00;
mem_aluop <= ex_aluop;
mem_mem_addr <= ex_mem_addr;
mem_reg2 <= ex_reg2;
mem_cp0_reg_we <= ex_cp0_reg_we;
mem_cp0_reg_write_addr <= ex_cp0_reg_write_addr;
mem_cp0_reg_data <= ex_cp0_reg_data;
mem_excepttype <= ex_excepttype;
mem_is_in_delayslot <= ex_is_in_delayslot;
mem_current_inst_address <= ex_current_inst_address;
end
else begin
hilo_o <= hilo_i;
cnt_o <= cnt_i;
end
end
endmodule
`include "defines.v"
module mem_wb(
input wire clk,
input wire rst,
//来自控制模块的信息
input wire[5:0] stall,
input wire flush,
//来自访存阶段的信息
input wire[`RegAddrBus] mem_wd,
input wire mem_wreg,
input wire[`RegBus] mem_wdata,
input wire[`RegBus] mem_hi,
input wire[`RegBus] mem_lo,
input wire mem_whilo,
input wire mem_LLbit_we, //访存阶段指令是否要写LLbit
input wire mem_LLbit_value, //值
input wire mem_cp0_reg_we,
input wire[4:0] mem_cp0_reg_write_addr,
input wire[`RegBus] mem_cp0_reg_data,
//送到回写阶段的信息
output reg[`RegAddrBus] wb_wd,
output reg wb_wreg,
output reg[`RegBus] wb_wdata,
output reg[`RegBus] wb_hi,
output reg[`RegBus] wb_lo,
output reg wb_whilo,
output reg wb_LLbit_we, //回写阶段的指令是否要写LLbit
output reg wb_LLbit_value, //值
output reg wb_cp0_reg_we,
output reg[4:0] wb_cp0_reg_write_addr,
output reg[`RegBus] wb_cp0_reg_data
);
//1.当stall[4]为stop,stall[5]为nostop,表示访存阶段暂停,回写阶段继续
// 使用空指令作为下一个周期进入回写阶段的指令
//2.当stall[4]为nostop,访存阶段继续,访存后的指令进入回写阶段
//3.其余情况,保持不变
always @ (posedge clk) begin
if(rst == `RstEnable) begin
wb_wd <= `NOPRegAddr;
wb_wreg <= `WriteDisable;
wb_wdata <= `ZeroWord;
wb_hi <= `ZeroWord;
wb_lo <= `ZeroWord;
wb_whilo <= `WriteDisable;
wb_LLbit_we <= 1'b0;
wb_LLbit_value <= 1'b0;
wb_cp0_reg_we <= `WriteDisable;
wb_cp0_reg_write_addr <= 5'b00000;
wb_cp0_reg_data <= `ZeroWord;
end
else if(flush == 1'b1 ) begin
wb_wd <= `NOPRegAddr;
wb_wreg <= `WriteDisable;
wb_wdata <= `ZeroWord;
wb_hi <= `ZeroWord;
wb_lo <= `ZeroWord;
wb_whilo <= `WriteDisable;
wb_LLbit_we <= 1'b0;
wb_LLbit_value <= 1'b0;
wb_cp0_reg_we <= `WriteDisable;
wb_cp0_reg_write_addr <= 5'b00000;
wb_cp0_reg_data <= `ZeroWord;
end
else if(stall[4] == `Stop && stall[5] == `NoStop) begin
wb_wd <= `NOPRegAddr;
wb_wreg <= `WriteDisable;
wb_wdata <= `ZeroWord;
wb_hi <= `ZeroWord;
wb_lo <= `ZeroWord;
wb_whilo <= `WriteDisable;
wb_LLbit_we <= 1'b0;
wb_LLbit_value <= 1'b0;
wb_cp0_reg_we <= `WriteDisable;
wb_cp0_reg_write_addr <= 5'b00000;
wb_cp0_reg_data <= `ZeroWord;
end
else if(stall[4] == `NoStop) begin //判断访存阶段是否暂停
wb_wd <= mem_wd;
wb_wreg <= mem_wreg;
wb_wdata <= mem_wdata;
wb_hi <= mem_hi;
wb_lo <= mem_lo;
wb_whilo <= mem_whilo;
wb_LLbit_we <= mem_LLbit_we;
wb_LLbit_value <= mem_LLbit_value;
wb_cp0_reg_we <= mem_cp0_reg_we;
wb_cp0_reg_write_addr <= mem_cp0_reg_write_addr;
wb_cp0_reg_data <= mem_cp0_reg_data;
end
end
endmodule
`include "defines.v"
module cp0_reg(
input wire clk,
input wire rst,
input wire we_i, //是否要写CP0的寄存器
input wire[4:0] waddr_i, //要写寄存器的地址
input wire[4:0] raddr_i, //要读取寄存器的地址
input wire[`RegBus] data_i, //要写入的数据
input wire[31:0] excepttype_i,
input wire[5:0] int_i, //6个外部硬件中断的输入
input wire[`RegBus] current_inst_addr_i,
input wire is_in_delayslot_i,
//相关寄存器的值
output reg[`RegBus] data_o, //读出的值
output reg[`RegBus] count_o,
output reg[`RegBus] compare_o,
output reg[`RegBus] status_o,
output reg[`RegBus] cause_o,
output reg[`RegBus] epc_o,
output reg[`RegBus] config_o,
output reg[`RegBus] prid_o,
//是否有定时中断发生
output reg timer_int_o
);
//第一段:对CP0中寄存器的写操作
always @ (posedge clk) begin
if(rst == `RstEnable) begin
count_o <= `ZeroWord;
compare_o <= `ZeroWord;
//status寄存器的CU为0001,表示协处理器CP0存在
status_o <= 32'b00010000000000000000000000000000;
cause_o <= `ZeroWord;
epc_o <= `ZeroWord;
//config寄存器的BE为1,表示Big-Endian;MT为00,表示没有MMU
config_o <= 32'b00000000000000001000000000000000;
//制作者是L,对应的是0x48,类型是0x1,基本类型,版本号是1.0
prid_o <= 32'b00000000010011000000000100000010;
timer_int_o <= `InterruptNotAssert;
end
else begin
count_o <= count_o + 1 ; //每个时钟周期自加1
cause_o[15:10] <= int_i; //cause[15:11]保存外部中断声明
//当comepare不为0且count值为compare时
//将输出信号timer_int_o置为1,表示时钟中断发生
if(compare_o != `ZeroWord && count_o == compare_o) begin
timer_int_o <= `InterruptAssert;
end
if(we_i == `WriteEnable) begin
case (waddr_i)
`CP0_REG_COUNT: begin //写count寄存器
count_o <= data_i;
end
`CP0_REG_COMPARE: begin //写compare寄存器
compare_o <= data_i;
timer_int_o <= `InterruptNotAssert;
end
`CP0_REG_STATUS: begin //写state寄存器
status_o <= data_i;
end
`CP0_REG_EPC: begin //写EPC寄存器
epc_o <= data_i;
end
`CP0_REG_CAUSE: begin //写cause寄存器
//cause寄存器只有IP[1:0]、IV、WP字段是可写的
cause_o[9:8] <= data_i[9:8];
cause_o[23] <= data_i[23];
cause_o[22] <= data_i[22];
end
endcase
end
case (excepttype_i)
32'h00000001: begin //外部中断
if(is_in_delayslot_i == `InDelaySlot ) begin
epc_o <= current_inst_addr_i - 4 ;
cause_o[31] <= 1'b1;
end else begin
epc_o <= current_inst_addr_i;
cause_o[31] <= 1'b0;
end
status_o[1] <= 1'b1;
cause_o[6:2] <= 5'b00000;
end
32'h00000008: begin //syscall
if(status_o[1] == 1'b0) begin
if(is_in_delayslot_i == `InDelaySlot ) begin
epc_o <= current_inst_addr_i - 4 ;
cause_o[31] <= 1'b1;
end else begin
epc_o <= current_inst_addr_i;
cause_o[31] <= 1'b0;
end
end
status_o[1] <= 1'b1;
cause_o[6:2] <= 5'b01000;
end
32'h0000000a: begin //无效指令
if(status_o[1] == 1'b0) begin
if(is_in_delayslot_i == `InDelaySlot ) begin
epc_o <= current_inst_addr_i - 4 ;
cause_o[31] <= 1'b1;
end else begin
epc_o <= current_inst_addr_i;
cause_o[31] <= 1'b0;
end
end
status_o[1] <= 1'b1;
cause_o[6:2] <= 5'b01010;
end
32'h0000000d: begin //自陷异常
if(status_o[1] == 1'b0) begin
if(is_in_delayslot_i == `InDelaySlot ) begin
epc_o <= current_inst_addr_i - 4 ;
cause_o[31] <= 1'b1;
end else begin
epc_o <= current_inst_addr_i;
cause_o[31] <= 1'b0;
end
end
status_o[1] <= 1'b1;
cause_o[6:2] <= 5'b01101;
end
32'h0000000c: begin //溢出异常
if(status_o[1] == 1'b0) begin
if(is_in_delayslot_i == `InDelaySlot ) begin
epc_o <= current_inst_addr_i - 4 ;
cause_o[31] <= 1'b1;
end else begin
epc_o <= current_inst_addr_i;
cause_o[31] <= 1'b0;
end
end
status_o[1] <= 1'b1;
cause_o[6:2] <= 5'b01100;
end
32'h0000000e: begin //eret
status_o[1] <= 1'b0;
end
default: begin
end
endcase
end
end
//第二段:对cp0寄存器的读操作
always @ (*) begin
if(rst == `RstEnable) begin
data_o <= `ZeroWord;
end
else begin
case (raddr_i)
`CP0_REG_COUNT: begin
data_o <= count_o ;
end
`CP0_REG_COMPARE: begin
data_o <= compare_o ;
end
`CP0_REG_STATUS: begin
data_o <= status_o ;
end
`CP0_REG_CAUSE: begin
data_o <= cause_o ;
end
`CP0_REG_EPC: begin
data_o <= epc_o ;
end
`CP0_REG_PrId: begin
data_o <= prid_o ;
end
`CP0_REG_CONFIG: begin
data_o <= config_o ;
end
default: begin
end
endcase
end
end
endmodule
`include "defines.v"
module ctrl(
input wire rst,
input wire[31:0] excepttype_i,
input wire[`RegBus] cp0_epc_i, //epc最新值
input wire stallreq_from_id,
input wire stallreq_from_ex,
output reg[`RegBus] new_pc,
output reg flush,
output reg[5:0] stall
);
always @ (*) begin
if(rst == `RstEnable) begin
stall <= 6'b000000;
flush <= 1'b0;
new_pc <= `ZeroWord;
end
else if(excepttype_i != `ZeroWord) begin //不为0 表示发生异常
flush <= 1'b1;
stall <= 6'b000000;
case (excepttype_i)
32'h00000001: begin //interrupt
new_pc <= 32'h00000020;
end
32'h00000008: begin //syscall
new_pc <= 32'h00000040;
end
32'h0000000a: begin //inst_invalid
new_pc <= 32'h00000040;
end
32'h0000000d: begin //trap
new_pc <= 32'h00000040;
end
32'h0000000c: begin //ov
new_pc <= 32'h00000040;
end
32'h0000000e: begin //eret
new_pc <= cp0_epc_i;
end
default : begin
end
endcase
end
else if(stallreq_from_ex == `Stop) begin
stall <= 6'b001111;
flush <= 1'b0;
end
else if(stallreq_from_id == `Stop) begin
stall <= 6'b000111;
flush <= 1'b0;
end
else begin
stall <= 6'b000000;
flush <= 1'b0;
new_pc <= `ZeroWord;
end
end
endmodule