PolarFire® SoC 异常中断的两种模式 和 trap_from_machine_mode 中断服务函数分析
一、 PolarFire® SoC 两种中断模式,是 MTVEC 寄存器,BIT[1:0] 决定的,
0: (Direct) All exceptions set PC to BASE 直接中断模式
1: (Vectored) Asynchronous interrupts set PC to BASE + 4 × cause 向量模式
≥2: Reserved
直接中断模式,异常和中断产生时,会跳到 MTVEC 存的地址里执行代码,在这个代码里 读取 MCAUSE , 判断中断号,然后跳转对应函数执行 ,正如 trap_from_machine_mode 函数
向量模式 :中断触发后,会跳转到 以 MTVEC 地址开始,查询 mcause 得到中断号后,中断号*4 或者 中断号*8 + MTVEC 的地址 ,对应 函数 里执行 , 例如 FreeRTOS 移植时, vector_table.S 表;
这两种模式 ,建议看 RISC-V手册 或者 risc-v 体系结构编程与实践 第二版 笨叔
注意: 向量模式下, 发生的<异常> ,还是要读取 MCAUSE, 根据中断号 处理;
二、如何区分 异常 还是 中断, mcause 寄存器 最高位 63位 确定
1 if the trap was caused by an interrupt; 0 otherwise.
三、mpfs-mmuart-interrupt 中断例程是直接中断模式 代码分析:/mpfs-mmuart-interrupt/src/platform/mpfs_hal/startup_gcc/mss_entry.S 文件中
1、mss_entry.S 文件中 将 trap_vector 地址 更新到 mtvec 寄存器中
_start_non_bootloader_amp_image:
/* Setup trap handler */
la a4, trap_vector
csrw mtvec, a4 # initalise machine trap vector address
2、trap_vector 函数 会 跳转到 trap_from_machine_mode 函数执行 ;
学习新知识:汇编跳转函数时,传递形参的方式, trap_from_machine_mode 三个 形参 对应 寄存器 A0 A1 A2;
总结:直接中断模式:产生中断时, 先判断是 异常 还是中断 ,然后再读取 中断号, 跳到 不同 的 中断服务函数执行
四、trap_from_machine_mode 函数分析
void trap_from_machine_mode(uintptr_t * regs, uintptr_t dummy, uintptr_t mepc) { volatile uintptr_t mcause = read_csr(mcause); if (((mcause & MCAUSE_INT) == MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) >=\ IRQ_M_LOCAL_MIN)&& ((mcause & MCAUSE_CAUSE) <= IRQ_M_LOCAL_MAX)) { // 中断类型 // 中断号 >= 16 中断号 <= 63 本地中断处理 handle_local_interrupt((uint8_t)(mcause & MCAUSE_CAUSE)); } else if (((mcause & MCAUSE_INT) == MCAUSE_INT) && ((mcause & MCAUSE_CAUSE)\ == IRQ_M_EXT)) { // 中断类型 // 中断号 = 11 Machine Global interrupt handle_m_ext_interrupt(); } else if (((mcause & MCAUSE_INT) == MCAUSE_INT) && ((mcause & MCAUSE_CAUSE)\ == IRQ_M_SOFT)) { // 中断类型 // 中断号 = 3 Machine software interrupt handle_m_soft_interrupt(); } else if (((mcause & MCAUSE_INT) == MCAUSE_INT) && ((mcause & MCAUSE_CAUSE)\ == IRQ_M_TIMER)) { // 中断类型 // 中断号 = 7 Machine timer interrupt // 这个 移植 FreeRTOS 时, 中断采用直接中断模式,应该跳转到 // freertos_risc_v_mtimer_interrupt_handler // 需要测试 2025年9月17日 11点46分 handle_m_timer_interrupt(); } else if (((mcause & MCAUSE_INT) == MCAUSE_INT) && ((mcause & MCAUSE_CAUSE)\ == IRQ_M_BEU )) { // 中断类型 // 中断号 0x80 beu 中断,暂时没有研究 handle_local_beu_interrupt(); } else { // 没有 对异常 进行处理 // 无语…… uint32_t i = 0U; while(1U) { /* wait for watchdog */ i++; if(i == 0x1000U) { i = (uint32_t)mcause; /* so mcause is not optimised out */ } } switch(mcause) { case CAUSE_LOAD_PAGE_FAULT: break; case CAUSE_STORE_PAGE_FAULT: break; case CAUSE_FETCH_ACCESS: break; case CAUSE_LOAD_ACCESS: break; case CAUSE_STORE_ACCESS: break; default: bad_trap(regs, dummy, mepc); break; } } }
浙公网安备 33010602011771号