4.10 中断 中断(中断返回)本质上也是一种跳转,只不过还需要附加一些读写CSR寄存器的操作。 RISC-V中断分为两种类型,一种是同步中断,即ECALL、EBREAK等指令所产生的中断,另一种是异步中断,即GPIO、UART等外设产生的中断。 对于中断模块设计,一种简单的方法就是当检测到中断(中断返回)信号时,先暂停整条流水线,设置跳转地址为中断入口地址,然后读、写必要的CSR寄存器(mstatus、mepc、mcause等),等读写完这些CSR寄存器后取消流水线暂停,这样处理器就可以从中断入口地址开始取指,进入中断服务程序。 下面看tinyriscv的中断是如何设计的。中断模块所在文件:rtl/core/clint.v 输入输出信号列表如下:
先看中断模块是怎样判断有中断信号产生的,如下代码:
第3~4行,复位后的状态,默认没有中断要处理。 第6~7行,判断当前指令是否是ECALL或者EBREAK指令,如果是则设置中断状态为S_INT_SYNC_ASSERT,表示有同步中断要处理。 第8~9行,判断是否有外设中断信号产生,如果是则设置中断状态为S_INT_ASYNC_ASSERT,表示有异步中断要处理。 第10~11行,判断当前指令是否是MRET指令,MRET指令是中断返回指令。如果是,则设置中断状态为S_INT_MRET。 下面就根据当前的中断状态做不同处理(读写不同的CSR寄存器),代码如下:
第1023行,当CSR处于S_CSR_IDLE时,如果中断状态为S_INT_SYNC_ASSERT,则在第11行将CSR状态设置为S_CSR_MEPC,在第12行将当前指令地址保存下来。 在第1323行,根据不同的指令类型,设置不同的中断码(Exception Code),这样在中断服务程序里就可以知道当前中断发生的原因了。 第24~28行,目前tinyriscv只支持定时器这个外设中断。 第30~31行,如果是中断返回指令,则设置CSR状态为S_CSR_MSTATUS_MRET。 第34~48行,一个时钟切换一下CSR状态。 接下来就是写CSR寄存器操作,需要根据上面的CSR状态来写。
第11~15行,写mepc寄存器。 第17~21行,写mcause寄存器。 第23~27行,关闭全局异步中断。 第29~33行,写mstatus寄存器。 最后就是发出中断信号,中断信号会进入到执行阶段。
有两种情况需要发出中断信号,一种是进入中断,另一种是退出中断。 9~12行,写完mstatus寄存器后发出中断进入信号,中断入口地址就是mtvec寄存器的值。 第13~15行,发出中断退出信号,中断退出地址就是mepc寄存器的值。
|