Monday, February 19, 2024

NIOS V OS porting

 First Interrupt Execution Flow:

C:\intelFPGA_pro\23.2\ip\altera\soft_processor\intel_niosv_common\HAL\src\machine_trap.S is copied to bsp generated in project folders:

C:\test\top_project\sw\bsp_freertos\HAL\src\machine_trap.S

C:\test\top_project\sw\bsp_ucosii\HAL\src\machine_trap.S

trap_vector:

        :

save_registers:
    /* Save caller-saved registers on the stack */
#if ALT_CPU_NUM_GPR == 32
    addi sp, sp, -16 * 4
    sw a6, 10 * 4(sp)
    sw a7, 11 * 4(sp)
    sw t3, 12 * 4(sp)
    sw t4, 13 * 4(sp)
    sw t5, 14 * 4(sp)
    sw t6, 15 * 4(sp)
#else // 16 (RV32E)
    addi sp, sp, -10 * 4
#endif
    sw ra,  0 * 4(sp)
    sw t0,  1 * 4(sp)
    sw t1,  2 * 4(sp)
    sw t2,  3 * 4(sp)
    sw a0,  4 * 4(sp)
    sw a1,  5 * 4(sp)
    sw a2,  6 * 4(sp)
    sw a3,  7 * 4(sp)
    sw a4,  8 * 4(sp)
    sw a5,  9 * 4(sp)
   
    /* Call handle_trap to dispatch the correct handler, if available */
    csrr a0, mcause
    csrr a1, mepc
    csrr a2, mtval
    jal handle_trap
    csrw mepc, a0
        :

top_project\sw\bsp_ucosii\HAL\src\alt_irq_handler.c
top_project\sw\bsp_freertos\HAL\src\alt_irq_handler.c
alt_u32 handle_trap(alt_u32 cause, alt_u32 epc, alt_u32 tval)

{

    alt_u32 is_irq, exception_code;

    is_irq = (cause & NIOSV_MCAUSE_INTERRUPT_MASK);
    exception_code = (cause & ~NIOSV_MCAUSE_INTERRUPT_MASK);

    if (is_irq) {
        switch (exception_code) {
            case NIOSV_TIMER_IRQ:
            {
                if (alt_niosv_timer_interrupt_handler) {
                    ALT_OS_INT_ENTER();
                    alt_niosv_timer_interrupt_handler(cause, epc, tval);
                    ALT_OS_INT_EXIT();
                }
                break;
            }
            case NIOSV_SOFTWARE_IRQ:
            {
                if (alt_niosv_software_interrupt_handler) {
                    ALT_OS_INT_ENTER();
                    alt_niosv_software_interrupt_handler(cause, epc, tval);
                    ALT_OS_INT_EXIT();
                }
                break;
            default:
            {
                if (exception_code >= 16) {
                    alt_irq_handler();
                } else {
                    ALT_LOG_PRINTF("invalid exception code: %d, epc = %d, tval = %d\n", exception_code, epc, tval);
                }
                break;
            }
                    :
/*
 * A table describing each interrupt handler. The index into the array is the
 * interrupt id associated with the handler. 
 *
 * When an interrupt occurs, the associated handler is called with
 * the argument stored in the context member.
 */
struct ALT_IRQ_HANDLER
{
  void (*handler)(void*);
  void *context;
} alt_irq[ALT_NIRQ];

/*
 * alt_irq_handler() is called by the interrupt exception handler in order to 
 * process any outstanding interrupts. 
 *
 * It is defined here since it is linked in using weak linkage. 
 * This means that if there is never a call to alt_irq_register() then
 * this function will not get linked in to the executable. This is acceptable
 * since if no handler is ever registered, then an interrupt can never occur.
 */
void alt_irq_handler (void)
{
    alt_u32 active;
    alt_u32 mask;
    alt_u32 i;

    /*
     * Notify the operating system that we are at interrupt level.
     */  
    ALT_OS_INT_ENTER();
                        :
                alt_irq[i].handler(alt_irq[i].context); 
                        :
    /*
     * Notify the operating system that interrupt processing is complete.
     */ 

    ALT_OS_INT_EXIT();
}

There seems to be a major difference between FreeRTOS and uCOS II in interrupt handling that FreeRTOS seems to be calling BSP's handle_trap() from its own trap_vector instead of you provide the ALT_OS_INT_ENTER/ALT_OS_INT_EXIT() for the BSP's trap_vector() and handle_trap(). Check that as it would be better for you.

top_project\sw\bsp_freertos\HAL\src\os_cpu_c.c

/* handle_trap() and alt_tick() are Intel HAL function. */
extern alt_u32 handle_trap( alt_u32 cause, alt_u32 epc, alt_u32 tval );
extern void alt_tick( void );

#define HAL_HANDLE_TRAP();  alt_u32 ulMCAUSE = 0, ulMEPC = 0, ulMTVAL = 0;           \
                          __asm volatile( "csrr %0, mcause" : "=r"( ulMCAUSE ) );  \
                            __asm volatile( "csrr %0, mepc" : "=r"( ulMEPC ) );      \
                            __asm volatile( "csrr %0, mtval" : "=r"( ulMTVAL ) );    \
                            ulHalNestedInterruptCounter++;                           \
                            handle_trap(ulMCAUSE, ulMEPC, ulMTVAL);                  \
                            ulHalNestedInterruptCounter--;                           \

/* Hook for tick. To use this, configUSE_TICK_HOOK must set to 1 */
void vApplicationTickHook( void )
{
    /* ALT_LOG - see altera_hal/HAL/inc/sys/alt_log_printf.h */
    ALT_LOG_SYS_CLK_HEARTBEAT();

    ulHalNestedInterruptCounter++;
    alt_tick();
    ulHalNestedInterruptCounter--;
}
                        :
/* Override weak function defined in portASM.S */
void freertos_risc_v_application_interrupt_handler( void )
{
   HAL_HANDLE_TRAP();
}

/* Override weak function defined in portASM.S */
void freertos_risc_v_application_exception_handler( void )
{
   HAL_HANDLE_TRAP();
}

freertos_risc_v_trap_handler  is assigned as Vector Base Address in mtvec register.

│Installing the FreeRTOS trap handler

│The FreeRTOS trap handler is called freertos_risc_v_trap_handler() and is the central
entry point for all interrupts and exceptions.


top_project\sw\bsp_freertos\FREERTOS\inc\os\alt_hooks.h
#define ALT_OS_INIT()           alt_envsem = xSemaphoreCreateCounting(1, 1);                                \
                                alt_heapsem = xSemaphoreCreateCounting(1, 1);                               \
                                extern void freertos_risc_v_trap_handler( void );                           \
                                __asm__ volatile( "csrw mtvec, %0" :: "r"( freertos_risc_v_trap_handler ) )