第5章 中断处理流程
在前面的start.S的启动流程分析中,有提及到将MCU的异常处理地址设置为了0x1c001000,由于ls1c102的硬件设计,其启动地址为0x1c000000,所以中断处理的入口地址就在start.S内的.org 0x1000处,内容如下:
#该宏定义了将中断现场保存进指定内存空间的操作
#define SAVE_REGS_FAST(BASE) \
#这里由于所有寄存器都存放了中断现场的值,不能进行破坏,所以使用了csr寄存器去临时作为保存空间,可以空出一个寄存器以便使用
csrwr tp, CSR_KScratch1; \
#这里设置保存中断现场的基地址并将寄存器数据全部写入内存空间进行保存
li.w tp, BASE;\
st.w t0, tp, -0x4 ;\
st.w t1, tp, -0x8 ;\
st.w t2, tp, -0xc ;\
st.w t3, tp, -0x10;\
st.w t4, tp, -0x14;\
st.w t5, tp, -0x18;\
st.w t6, tp, -0x1c;\
st.w t7, tp, -0x20;\
st.w t8, tp, -0x24;\
/*st.w s0, tp, -0x28;*/\
/*st.w s1, tp, -0x2c;*/\
/*st.w s2, tp, -0x30;*/\
/*st.w s3, tp, -0x34;*/\
/*st.w s4, tp, -0x38;*/\
/*st.w s5, tp, -0x3c;*/\
/*st.w s6, tp, -0x40;*/\
/*st.w s7, tp, -0x44;*/\
/*st.w s8, tp, -0x48;*/\
st.w a0, tp, -0x4c;\
st.w a1, tp, -0x50;\
st.w a2, tp, -0x54;\
st.w a3, tp, -0x58;\
st.w a4, tp, -0x5c;\
st.w a5, tp, -0x60;\
st.w a6, tp, -0x64;\
st.w a7, tp, -0x68;\
st.w ra, tp, -0x6c;\
st.w sp, tp, -0x70;\
/*st.w gp, tp, -0x74;*/\
/*st.w fp, tp, -0x78;*/\
#该宏定义了将保存的中断现场进行恢复的操作
#define RESTORE_REGS_FAST(BASE) \
#获取保存地址并逐一恢复保存的寄存器值
li.w tp, BASE;\
ld.w t0, tp, -0x4 ;\
ld.w t1, tp, -0x8 ;\
ld.w t2, tp, -0xc ;\
ld.w t3, tp, -0x10;\
ld.w t4, tp, -0x14;\
ld.w t5, tp, -0x18;\
ld.w t6, tp, -0x1c;\
ld.w t7, tp, -0x20;\
ld.w t8, tp, -0x24;\
/*ld.w s0, tp, -0x28;*/\
/*ld.w s1, tp, -0x2c;*/\
/*ld.w s2, tp, -0x30;*/\
/*ld.w s3, tp, -0x34;*/\
/*ld.w s4, tp, -0x38;*/\
/*ld.w s5, tp, -0x3c;*/\
/*ld.w s6, tp, -0x40;*/\
/*ld.w s7, tp, -0x44;*/\
/*ld.w s8, tp, -0x48;*/\
ld.w a0, tp, -0x4c;\
ld.w a1, tp, -0x50;\
ld.w a2, tp, -0x54;\
ld.w a3, tp, -0x58;\
ld.w a4, tp, -0x5c;\
ld.w a5, tp, -0x60;\
ld.w a6, tp, -0x64;\
ld.w a7, tp, -0x68;\
ld.w ra, tp, -0x6c;\
ld.w sp, tp, -0x70;\
/*ld.w gp, tp, -0x74;*/\
/*ld.w fp, tp, -0x78;*/\
csrrd tp, CSR_KScratch1;
.org 0x1000
DEFAULT_INT_HANDLER:
#此处在处理中断前先对中断现场进行了保存,即保存各寄存器的至,该宏定义的展开在上面,这里的REGS_MEM为0x80002000,结合上面设置栈寄存器时的地址,可以理解为此空间是在栈底高地址区域特地留下来用于保存中断现场的空间
SAVE_REGS_FAST(REGS_MEM)
csrrd t0, CSR_ExStatus
andi t1, t0, INT_VECTOR
beqz t1, exception_core_check
exception_pmu:
andi t1,t0,0x1
bnez t1,sw0_label
andi t1,t0,0x2
bnez t1,sw1_label
andi t1,t0,0x4
bnez t1,wake_label
andi t1,t0,0x8
bnez t1,touch_label
andi t1,t0,0x10
bnez t1,uart2_label
andi t1,t0,0x20
bnez t1,bcc_label
andi t1,t0,0x80
bnez t1,exint_label
andi t1,t0,0x800
bnez t1,timer_label
sw0_label:
bl Software0_HANDLER
b exception_exit
sw1_label:
bl Software1_HANDLER
b exception_exit
wake_label:
bl TIMER_WAKE_INT
b exception_exit
touch_label:
bl TOUCH
b exception_exit
uart2_label:
bl UART2_INT
b exception_exit
bcc_label:
bl BAT_FAIL
b exception_exit
exint_label:
bl ext_handler
b exception_exit
timer_label:
bl TIMER_HANDLER
b exception_exit
exception_core_check:
andi t1, t0, INTC_VECTOR
beqz t1, exception_exit
bl intc_handler
b exception_exit
exception_exit:
RESTORE_REGS_FAST(REGS_MEM)
ertn
根据龙芯架构32位精简版参考手册的解释我们可知
在中断触发时:
- 将 CSR.CRMD 的 PLV、IE 分别存到 CSR.PRMD 的 PPLV、PIE 中,然后将CSR.CRMD的PLV置为 0,IE 置为 0
- 将触发例外指令的 PC 值记录到 CSR.ERA 中
- 跳转到例外入口处取指
当软件执行 ertn 指令从例外执行返回时:
- 将 CSR.PRMD 中的 PPLV、PIE 值恢复到 CSR.CRMD 的 PLV、IE 中
- 跳转到 CSR.ERA 所记录的地址处取指。