https://mp.weixin.qq.com/s/-FmAFPptdUCibzOGO_yCnQ
简单介绍ID阶段异常的处理。
本文目录:
1. id_xcpt
2. alu
以下正文:
1. id_xcpt
id_xcpt表示ID阶段发生的异常和检测到的中断:
2. ex_reg_xcpt
id_xcpt在ctrl_killd的过滤下向ex_reg_xcpt传递:
因为csr.io.interrupt会触发ctrl_killd导致id_xcpt无法向ex_reg_xcpt传递,所以只有当没有发生中断时,id_xcpt才会向ex_reg_xcpt传递。也就是说:
a. 如果ID阶段同时发生异常和检测到中断,那么中断优先得到处理;待中断处理完成后重新执行该指令时,同样会触发异常;
b. ex_reg_xcpt中只记录了id阶段传递过来的异常,而没有中断的情形;
3. alu
id_xcpt同样会对ex阶段的alu产生影响:
1) !ctrl_killd && id_xcpt
首先,!ctrl_killd && id_xcpt表示仅发生异常的情况。
其次,在这种情况下,需要记录发生异常的指令的地址,这个地址使用alu进行计算。
2) alu
ID阶段发生异常的指令的地址,通过alu进行计算:
其中:
a. 需要alu执行加法操作;
b. 计算结果alu.io.out辗转存入mtval寄存器;
c. 如果是rvc的情况,且4字节2指令中的第二条指令发生异常,那么第一个运算数为pc,第二个运算数为指令大小即2,即addr(inst) = pc + 2;
d. bpu.io.xcpt_if表示断点触发,只需要记录指令地址即可;
e. id_xcpt0的两种错误皆为取指异常,记录指令地址(同c):
f. bpu.io.debug_if暂不考虑;
g. 现在只剩下id_illegal_insn的情况,非法指令异常的处理是记录指令的内容。这里使用的第一个运算数是A1_RS1,第二个运算数是0。
所以alu的第一个运算数的值要组装成指令内容:
指令的内容装入ex_reg_rs_msb/lsb之后,经过bypass逻辑,进入到ex_op1:
3) alu.io.out
alu.io.out是如何进入mtval寄存器的呢?
A. alu.io.out的值存入mem_reg_wdata寄存器中:
这里受到开关ex_pc_valid的影响,因为只有异常而没有中断,所以ex_reg_valid = ex_pc_valid = 1:
B. mem_reg_wdata存入mem_int_wdata:
C. mem_int_data存入wb_reg_wdata寄存器中:
D. wb_reg_data写入到csr.io.tval:
这里需要经过tval_valid的过滤,其包括两个条件:
a. wb_xcpt = 1:这里发生了异常,可以满足;
b. wb_cause列举的情况,包含了ID阶段异常中除CSR.debugTriggerCause之外的全部情况;
E. tval写入到reg_mtval寄存器中: