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;
        }
    }
}

 

posted on 2025-09-17 11:01  所长  阅读(20)  评论(0)    收藏  举报

导航