23 中断异常处理

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的状态

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值