23 中断异常处理
在中断异常中我们需要使用到csr相关的寄存器,首先对csr处理时需要的信号进行解析:
module execute_csr (
input [ `IMM_LEN-1:0] imm_CSR_i,
input isNeedimmCSR_i, // 是否是立即数指令
input [ `XLEN-1:0] rs1_data_i, // rs1 data
input [ `XLEN-1:0] csr_data_i, // 读取的 CSR 数据
input [`CSROP_LEN-1:0] csr_op_i, // csr 操作码
output [ `XLEN-1:0] csr_exe_result,
output csr_exe_valid
);
imm_csr_i:为csr类的寄存器
isNeedimmCSR_i : 表示是否需要立即数
rs1_data_i = rs1寄存器的数据
csr_data : csr寄存器的数据
csr_op : csr的操作码
csr_exe_result : csr的执行结果
csr_exe_valid : csr写控制信号
csr常用寄存器指令解析
INSTPAT("??????? ????? ????? 001 ????? 11100 11", csrrw, I, word_t t = csr(imm); csr(imm) = src1; R(rd) = t);
INSTPAT("??????? ????? ????? 010 ????? 11100 11", csrrs, I, word_t t = csr(imm); csr(imm) = t | src1; R(rd) = t);
INSTPAT("??????? ????? ????? 011 ????? 11100 11", csrrc, I, word_t t = csr(imm); csr(imm) = t & (~src1); R(rd) = t);
指令分析
wire _csr_write = (csr_op_i == `CSROP_WRITE);
wire _csr_set = (csr_op_i == `CSROP_SET);
wire _csr_clear = (csr_op_i == `CSROP_CLEAR);
wire _csr_read = (csr_op_i == `CSROP_READ);
wire _csr_none = (csr_op_i == `CSROP_NONE);
计算结果得到不同指令的值
wire [`XLEN-1:0] _csr_exe_result= ({`XLEN{_csr_write}}&_csr_write_result)|
({`XLEN{_csr_set}}&_csr_set_result)|
({`XLEN{_csr_clear}}&_csr_clear_result)|
({`XLEN{_csr_read}}&_csr_read_result);
assign csr_exe_result = _csr_exe_result;
assign csr_exe_valid = ~(_csr_none | _csr_read); // 读取不写回
csr 中断自陷指令的实现
INSTPAT("0000000 00000 00000 000 00000 11100 11", ecall, I, s->dnpc = isa_raise_intr(11, s->pc)); // trap 操作
INSTPAT("??????? ????? ????? 001 ????? 11100 11", csrrw, I, word_t t = csr(imm); csr(imm) = src1; R(rd) = t);
INSTPAT("??????? ????? ????? 010 ????? 11100 11", csrrs, I, word_t t = csr(imm); csr(imm) = t | src1; R(rd) = t);
INSTPAT("??????? ????? ????? 011 ????? 11100 11", csrrc, I, word_t t = csr(imm); csr(imm) = t & (~src1); R(rd) = t);
INSTPAT("0011000 00010 00000 000 00000 11100 11", mret, R, s->dnpc = csr(0x341));
当发生ecall会发生如下的过程
1. 保存当前的异常pc值
2. 读出跳转的异常处理的地址
3. 保存异常处理cause
当发生mret时
跳转到异常地址pc+4或不加(暂时不知道什么情况)
csr Regfile 存数据
// mstatus
wire [`XLEN-1:0] _mstatus_d = (csr_mstatus_i_en) ? csr_mstatus_i : csr_writedata;
reg [`XLEN-1:0] _mstatus_q;
reg _mstatus_en;
// mepc
wire [`XLEN-1:0] _mepc_d = (csr_mepc_i_en) ? csr_mepc_i : csr_writedata;
reg [`XLEN-1:0] _mepc_q;
reg _mepc_en;
// mcause
wire [`XLEN-1:0] _mcause_d = (csr_mcause_i_en) ? csr_mcause_i : csr_writedata;
reg [`XLEN-1:0] _mcause_q;
reg _mcause_en;
// mtval
wire [`XLEN-1:0] _mtval_d = (csr_mtval_i_en) ? csr_mtval_i : csr_writedata;
reg [`XLEN-1:0] _mtval_q;
reg _mtval_en;
// mtvec
wire [`XLEN-1:0] _mtvec_d = (csr_mtvec_i_en) ? csr_mtvec_i : csr_writedata;
reg [`XLEN-1:0] _mtvec_q;
reg _mtvec_en;
上述代码的作用就是,得到最新的目的数据,如果在ecall是能的情况下
/* 写使能 */
always @(*) begin
//需要赋初值防止生成 latch
_mstatus_en = csr_mstatus_i_en;
_mepc_en = csr_mepc_i_en;
_mcause_en = csr_mcause_i_en;
_mtval_en = csr_mtval_i_en;
_mtvec_en = csr_mtvec_i_en;
case (csr_writeaddr)
`CSR_MSTATUS: _mstatus_en = write_enable;
`CSR_MEPC: _mepc_en = write_enable;
`CSR_MCAUSE: _mcause_en = write_enable;
`CSR_MTVAL: _mtval_en = write_enable;
`CSR_MTVEC: _mtvec_en = write_enable;
default: ;
endcase
end
得到五个寄存器的写使能的状态,
regTemplate #(
.WIDTH (`XLEN),
.RESET_VAL(`CSR_MSTATUS_DEFAULT) // 为了 difftest
) u_csr_mstatus (
.clk (clk),
.rst (rst),
.din (_mstatus_d),
.dout(_mstatus_q),
.wen (_mstatus_en)
);
更新 mstatus的状态