diff --git a/CCRH/U2x/README.md b/CCRH/U2x/README.md index 81ea1b813..429270532 100644 --- a/CCRH/U2x/README.md +++ b/CCRH/U2x/README.md @@ -18,11 +18,12 @@ This repository contains the port of FreeRTOS for Renesas RH850/U2x microcontrol ## Link to Test Project -The test project can be found in [RH850_U2Ax_CCRH](https://github.com/FreeRTOS/FreeRTOS-Partner-Supported-Demos/tree/main/RH850_U2Ax_CCRH) and [RH850_U2Bx_CCRH](https://github.com/FreeRTOS/FreeRTOS-Partner-Supported-Demos/tree/main/RH850_U2Bx_CCRH). These projects contain example tasks and configurations to help you get started with FreeRTOS on the RH850/U2Ax and U2Bx. +The test project can be found in [RH850_U2Ax_CCRH](https://github.com/FreeRTOS/FreeRTOS-Partner-Supported-Demos/tree/main/RH850_U2Ax_CCRH) and [RH850_U2Bx_CCRH](https://github.com/FreeRTOS/FreeRTOS-Partner-Supported-Demos/tree/main/RH850_U2Bx_CCRH). These projects contain example tasks and configurations to help you get started with FreeRTOS on the RH850/U2Ax and RH850/U2Bx. ## Note - 1. The minimal stack size (configMINIMAL_STACK_SIZE) must be included the reserved memory for nested interrupt. This formula can be referred: `(task_context_size) * (2 + configMAX_INT_NESTING) + Stack_depth_of_taskcode` - In which, `task_context_size` is calculated as `36*4bytes = 144bytes` (when FPU enabled) or `34*4bytes = 136` (when FPU disabled), configMAX_INT_NESTING is `02` as default (Note that a value of `0` is not allowed). + 1. The minimal stack size `configMINIMAL_STACK_SIZE` must be included the reserved memory for nested interrupt. This formula can be referred: `[(task_context_size) * 2] + Stack_depth_of_taskcode`. + In which, `task_context_size` is calculated as `36*4bytes = 144bytes`. + 2. Users need to create a memory section named `mev_address` in `CRAM` for Exclusive Control functionality. Users should initialize the `mev_address` section in the startup file. Example: @@ -32,13 +33,12 @@ Example: st.w r0, 0[r20] ``` 3. The `FXU unit` is only available on `core 0`. Users must ensure that FXU operations are restricted to `core 0` by using the `vTaskCoreAffinitySet` function provided by FreeRTOS SMP. - 4. FXU can be enabled by specific compiler option `-DconfigENABLE_FXU`. FPU can be enabled by specific compiler option `-DconfigENABLE_FPU` - 5. The macros `configENABLE_FXU` and `configENABLE_FPU` must be defined in `FreeRTOSConfig.h`. + 4. FXU can be enabled by specific compiler option `-DconfigDISABLE_FXU`. FPU can be enabled by specific compiler option `-DconfigDISABLE_FPU` + 5. The macros `configDISABLE_FXU` and `configDISABLE_FPU` must be defined in `FreeRTOSConfig.h`. 6. This port supports U2Ax and U2Bx devices. The user must configure `configDEVICE_NAME` with the value `U2Bx_DEVICES` or `U2Ax_DEVICES` to specify which device is being used. 7. The User can configure the interrupt priority of the OSTM Timer using `configTIMER_INT_PRIORITY`, with 16 levels available (0 being the highest priority and 15 the lowest). 8. This port also supports the configuration of contiguous CPU cores in FreeRTOS, allowing the user to set task affinity for execution on specific cores or subsets of cores. - ## Other Relevant Information - **Documentation:** diff --git a/CCRH/U2x/port.c b/CCRH/U2x/port.c index 8c4427391..f441ee50f 100644 --- a/CCRH/U2x/port.c +++ b/CCRH/U2x/port.c @@ -46,7 +46,7 @@ #define portFXSR_REGISTER_SEL ( 10 ) /* PSW.EBV and PSW.CUx bits are kept as current status */ -#define portINITIAL_PSW_MASK ( 0x00078000 ) +#define portINITIAL_PSW_MASK ( 0x00038000 ) #define portCURRENT_PSW_VALUE ( portSTSR( portPSW_REGISTER_ID, portREGISTER_SEL_0 ) ) #define portCURRENT_SR_ZERO_VALUE ( ( StackType_t ) 0x00000000 ) #define portCURRENT_FPSR_VALUE ( portSTSR( portFPSR_REGISTER_ID, portREGISTER_SEL_0 ) ) @@ -56,6 +56,8 @@ #define portINITIAL_FPSR_MASK ( 0x00ae0000 ) #define portINITIAL_FXSR_MASK ( 0x00ee0000 ) #define portPSW_ID_MASK ( 0x00000020 ) +#define portPSW_FPU_MASK ( 0x00010000 ) +#define portPSW_FXU_MASK ( 0x00020000 ) /* Define necessary hardware IO for OSTM timer. * - OSTM0 is used by default for device variant U2Bx. @@ -151,19 +153,6 @@ #define configSETUP_TICK_INTERRUPT() prvSetupTimerInterrupt() #endif /* configSETUP_TICK_INTERRUPT */ -#if ( !defined( configMAX_INT_NESTING ) || ( configMAX_INT_NESTING == 0 ) ) - -/* Set the default value for depth of nested interrupt. In theory, the - * microcontroller have mechanism to limit number of nested level of interrupt - * by priority (maximum 16 levels). However, the large stack memory should be - * prepared for each task to save resource in interrupt handler. Therefore, it - * is necessary to limit depth of nesting interrupt to optimize memory usage. - * In addition, the execution time of interrupt handler should be very short - * (typically not exceed 20us), this constraint does not impact to system. - */ - #define configMAX_INT_NESTING 2UL -#endif - /* * Used to catch tasks that attempt to return from their implementing function. */ @@ -191,7 +180,11 @@ volatile BaseType_t xPortScheduleStatus[ configNUMBER_OF_CORES ] = { 0 }; * It is necessary to control maximum stack depth. */ volatile UBaseType_t uxInterruptNesting[ configNUMBER_OF_CORES ] = { 0 }; -volatile const UBaseType_t uxPortMaxInterruptDepth = configMAX_INT_NESTING; + +#ifndef configPORT_ISR_STACK_TOPS +#error "Define configPORT_ISR_STACK_TOPS in FreeRTOSConfig.h" +#endif +const UBaseType_t uxInterruptStack[ configNUMBER_OF_CORES ] = configPORT_ISR_STACK_TOPS; /* Count number of nested locks by same cores. The lock is completely released * only if this count is decreased to 0, the lock is separated for task and isr */ @@ -381,46 +374,32 @@ StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack, pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R30; /* R30 (EP) */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R1; /* R1 */ + *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R1; /* R1 */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R2; /* R2 */ + *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R2; /* R2 */ pxTopOfStack--; + + /* if FPU is enabled, initialize the FPU registers in Stack */ + #if ( configDISABLE_FPU != 1 ) + { + *pxTopOfStack = ( StackType_t ) ( portCURRENT_FPSR_VALUE & portINITIAL_FPSR_MASK ); /* FPSR */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portCURRENT_SR_ZERO_VALUE; /* FPEPC */ + pxTopOfStack--; + } + #endif /* End of #if ( configDISABLE_FPU != 1 ) */ /* Keep System pre-configuration (HV, CUx, EBV) as current setting in PSW register */ *pxTopOfStack = ( StackType_t ) ( portCURRENT_PSW_VALUE & portINITIAL_PSW_MASK ); /* EIPSW */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* EIPC */ + *pxTopOfStack = ( StackType_t ) pxCode; /* EIPC */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) portCURRENT_SR_ZERO_VALUE; /* EIIC */ + *pxTopOfStack = ( StackType_t ) portCURRENT_SR_ZERO_VALUE; /* EIIC */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) ( portCURRENT_PSW_VALUE & portINITIAL_PSW_MASK ); /* CTPSW */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) portCURRENT_SR_ZERO_VALUE; /* CTPC */ - - /* if FPU is enabled, initialize the FPU registers in Stack */ - #if ( configENABLE_FPU == 1 ) - pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) ( portCURRENT_FPSR_VALUE & portINITIAL_FPSR_MASK ); /* FPSR */ - pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) portCURRENT_SR_ZERO_VALUE; /* FPEPC */ - #endif /* (configENABLE_FPU == 1) */ - - /* if FXU is enabled, initialize the FXU registers in Stack */ - #if ( configENABLE_FXU == 1 ) - /* FXU Unit is available in PE0 only */ - if( 0 == xPortGET_CORE_ID() ) - { - pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) ( portCURRENT_FXSR_VALUE & portINITIAL_FXSR_MASK ); /* FXSR */ - pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) portCURRENT_SR_ZERO_VALUE; /* FXXP */ - } - else - { - /* Do nothing */ - } - #endif /* (configENABLE_FXU == 1) */ + *pxTopOfStack = ( StackType_t ) portCURRENT_SR_ZERO_VALUE; /* CTPC */ return pxTopOfStack; } @@ -621,11 +600,11 @@ static void prvSetupTimerInterrupt( void ) /* Interrupt configuration for OSTM Timer*/ pulOSTMIntReg = ( volatile uint32_t * ) portOSTM_EIC_ADDR; - *pulOSTMIntReg = ( portINT_TABLE_VECTOR | configTIMER_INT_PRIORITY ); + *pulOSTMIntReg = ( portINT_DIRECT_VECTOR | configTIMER_INT_PRIORITY ); /* Set OSTM0 control setting */ *( ( volatile uint32_t * ) portOSTMCTL_ADDR ) = ( portOSTM_INTERRUPT_ENABLE | portOSTM_MODE_INTERVAL_TIMER | portOSTM_START_INTERRUPT_DISABLE ); - *( ( volatile uint32_t * ) portOSTMCMP_ADDR ) = ( ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) ) - 1; + *( ( volatile uint32_t * ) portOSTMCMP_ADDR ) = ( ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1 ); /* Enable OSTM0 operation */ *( ( volatile uint32_t * ) portOSTMTS_ADDR ) = portOSTM_COUNTER_START; @@ -646,12 +625,14 @@ static void prvSetupTimerInterrupt( void ) /* No problem with r20, CCRH does not required to restore same value * before and after function call. */ push r20 - mov # __s.mev_address.bss, r20 + mov # __s.mev_address.bss, r20 + /* r6 is xBitPosition */ Lock: set1 r6, [ r20 ] bz Lock_success snooze br Lock + Lock_success: pop r20 } @@ -662,7 +643,8 @@ Lock: set1 r6, [ r20 ] static void prvExclusiveRelease( BaseType_t xBitPosition ) { push r20 - mov # __s.mev_address.bss, r20 + mov # __s.mev_address.bss, r20 + /* r6 is xBitPosition */ clr1 r6, [ r20 ] pop r20 diff --git a/CCRH/U2x/portasm.s b/CCRH/U2x/portasm.s index 2b896d0d0..403029847 100644 --- a/CCRH/U2x/portasm.s +++ b/CCRH/U2x/portasm.s @@ -31,17 +31,16 @@ ; Extern symbols ;------------------------------------------------------------------------------ .extern _uxInterruptNesting -.extern _uxPortMaxInterruptDepth .extern _xPortScheduleStatus .extern _vTaskSwitchContext .extern _pvPortGetCurrentTCB -.extern _vCommonISRHandler .extern _xPortGET_CORE_ID .public _vIrq_Handler .public _vPortStartFirstTask .public _vPortYield .public _vTRAP0_Handler + ;------------------------------------------------------------------------------ ; Macro definitions ;------------------------------------------------------------------------------ @@ -56,6 +55,8 @@ EIIC .set 13 CTPC .set 16 CTPSW .set 17 EIIC_MSK .set 0x00000FFF +FPU_MSK .set 0x00010000 +FXU_MSK .set 0x00020000 ;------------------------------------------------------------------------------ ; portSAVE_CONTEXT @@ -71,31 +72,25 @@ portSAVE_CONTEXT .macro $warning stsr EIPSW, r15 - stsr EIPC, r16 - stsr EIIC, r17 - stsr CTPSW, r18 - stsr CTPC, r19 - pushsp r15, r19 ; Save FPU registers to stack if FPU is enabled - $ifdef configENABLE_FPU + ; If disable, skip next 2 instructions: stsr (4 bytes)*2 with dummy save. + $ifdef configDISABLE_FPU + mov FPU_MSK, r19 + tst r15, r19 + bz 10 + stsr FPSR, r18 stsr FPEPC, r19 - pushsp r18, r19 + pushsp r18, r19 ; Push dummy value if FPU disabled. $endif - ; Save FXU registers to stack if FXU is enabled - $ifdef configENABLE_FXU - mov r0, r20 - mov r0, r21 - stsr 0, r19, 2 ; Get PEID - cmp r19, r0 ; Confirm PEID value is PE0 - bne 8 ; Branch 2 instructions if is not PE0 - ; to avoid unprivileged access - stsr FXSR, r20, 10 ; If PE0, save FXU register - stsr FXXP, r21, 10 ; If PE0, save FXU register - pushsp r20, r21 - $endif + stsr EIPSW, r15 + stsr EIPC, r16 + stsr EIIC, r17 + stsr CTPSW, r18 + stsr CTPC, r19 + pushsp r15, r19 ; Get current TCB, the return value is stored in r10 (CCRH compiler) jarl _pvPortGetCurrentTCB, lp @@ -112,24 +107,6 @@ portRESTORE_CONTEXT .macro jarl _pvPortGetCurrentTCB, lp ld.w 0[r10], sp ; Restore the stack pointer from the TCB - ; Restore FXU registers if FXU is enabled - $ifdef configENABLE_FXU - popsp r20, r21 - stsr 0, r19, 2 ; Get PEID - cmp r19, r0 ; Confirm PEID value is PE0 - bne 8 ; Branch 2 instructions if is not PE0 - ; to avoid unprivileged access - ldsr r21, FXXP, 10 ; If PE0, restore FXU register - ldsr r20, FXSR, 10 ; If PE0, restore FXU register - $endif - - ; Restore FPU registers if FPU is enabled - $ifdef configENABLE_FPU - popsp r18, r19 - ldsr r19, FPEPC - ldsr r18, FPSR - $endif - ;Restore general-purpose registers and EIPSW, EIPC, EIIC, CTPSW, CTPC popsp r15, r19 ldsr r19, CTPC @@ -138,6 +115,16 @@ portRESTORE_CONTEXT .macro ldsr r16, EIPC ldsr r15, EIPSW + ; Restore FPU registers if FPU is enabled + $ifdef configDISABLE_FPU + popsp r18, r19 + mov FPU_MSK, r17 + tst r15, r17 + bz 10 + ldsr r19, FPEPC + ldsr r18, FPSR + $endif + $nowarning popsp r1, r2 $warning @@ -154,74 +141,76 @@ SAVE_REGISTER .macro ; Callee-Save registers (r20 to r30) are not used in interrupt handler and ; guaranteed no change after function call. So, do not need to save register ; to optimize the used stack memory. - pushsp r5, r21 + pushsp r5, r19 $nowarning pushsp r1, r2 $warning - stsr EIPSW, r19 - stsr EIPC, r18 - stsr EIIC, r17 - mov lp, r16 - mov ep, r15 - stsr CTPSW, r14 - stsr CTPC, r13 - pushsp r13, r19 + stsr EIPSW, r15 - $ifdef configENABLE_FPU + $ifdef configDISABLE_FPU + mov FPU_MSK, r19 + tst r15, r19 + bz 10 stsr FPSR, r18 stsr FPEPC, r19 - pushsp r18, r19 + pushsp r18, r19 ; Push dummy value if FPU disabled. $endif - ; Save FXU registers to stack if FXU is enabled - $ifdef configENABLE_FXU - mov r0, r20 - mov r0, r21 - stsr 0, r19, 2 ; Get PEID - cmp r19, r0 ; Confirm PEID value is PE0 - bne 8 ; Branch 2 instructions if is not PE0 - ; to avoid unprivileged access - stsr FXSR, r20, 10 ; If PE0, save FXU register - stsr FXXP, r21, 10 ; If PE0, save FXU register - pushsp r20, r21 + $ifdef configDISABLE_FXU + mov FXU_MSK, r19 + tst r15, r19 + bz 10 + stsr FXSR, r18, 10 + stsr FXXP, r19, 10 + pushsp r18, r19 ; Push dummy value if FXU disabled. $endif + mov ep, r13 + mov lp, r14 + stsr EIPSW, r15 + stsr EIPC, r16 + stsr EIIC, r17 + stsr CTPSW, r18 + stsr CTPC, r19 + pushsp r13, r19 + .endm ;------------------------------------------------------------------------------ ; Restore used registers ;------------------------------------------------------------------------------ RESTORE_REGISTER .macro - ; Restore FXU registers if FXU is enabled - $ifdef configENABLE_FXU - popsp r20, r21 - stsr 0, r19, 2 ; Get PEID - cmp r19, r0 ; Confirm PEID value is PE0 - bne 8 ; Branch 2 instructions if is not PE0 - ; to avoid unprivileged access - ldsr r21, FXXP, 10 ; If PE0, restore FXU register - ldsr r20, FXSR, 10 ; If PE0, restore FXU register + popsp r13, r19 + ldsr r19, CTPC + ldsr r18, CTPSW + ldsr r17, EIIC + ldsr r16, EIPC + ldsr r15, EIPSW + mov r14, lp + mov r13, ep + + $ifdef configDISABLE_FXU + popsp r18, r19 + mov FXU_MSK, r17 + tst r15, r17 + bz 10 + ldsr r19, FXXP, 10 + ldsr r18, FXSR, 10 $endif - $ifdef configENABLE_FPU + $ifdef configDISABLE_FPU popsp r18, r19 + mov FPU_MSK, r17 + tst r15, r17 + bz 10 ldsr r19, FPEPC ldsr r18, FPSR $endif - popsp r13, r19 - ldsr r13, CTPC - ldsr r14, CTPSW - mov r15, ep - mov r16, lp - ldsr r17, EIIC - ldsr r18, EIPC - ldsr r19, EIPSW - $nowarning popsp r1, r2 $warning - popsp r5, r21 + popsp r5, r19 .endm ;------------------------------------------------------------------------------ @@ -300,29 +289,43 @@ _vIrq_Handler: addi 0x1, r18, r16 st.w r16, 0[r19] - pushsp r17, r19 + ; Check and switch to interrupt stack if task stack is currently used. + cmp r0, r18 + bne _vIrq_Handler_Entry_End + mov #_uxInterruptStack, r14 + add r17, r14 + ld.w 0[r14], r14 + mov sp, r16 + mov r14, sp + +_vIrq_Handler_Entry_End: + pushsp r16, r19 - ;Call the interrupt handler. + ; Call the interrupt handler. stsr EIIC, r6 andi EIIC_MSK, r6, r6 - ; Do not enable interrupt for nesting. Stackover flow may occurs if the - ; depth of nesting interrupt is exceeded. - mov #_uxPortMaxInterruptDepth, r19 - ld.w 0[r19], r15 - cmp r15, r16 - bge 4 ; Jump over ei instruction + ; Enable nested interrupts, invoke ISR functions from reference table ei - jarl _vCommonISRHandler, lp + stsr 4, r16, 1 ; Load based address of Interrupt Reference Table + andi 0xfff, r6, r17 + shl 2, r17 + add r17, r16 + ld.w 0[r16], r16 + + ; Invoke registered ISR function + jarl [r16], lp + di synce - popsp r17, r19 + popsp r16, r19 st.w r18, 0[r19] ; Restore the old nesting count. ; A context switch if no nesting interrupt. cmp 0x0, r18 bne _vIrq_Handler_NotSwitchContext + mov r16, sp ; Restore to task stack. ; Check if context switch is requested. mov #_xPortScheduleStatus, r19 @@ -332,7 +335,7 @@ _vIrq_Handler: bne _vIrq_Handler_SwitchContext _vIrq_Handler_NotSwitchContext: - ; No context switch. Restore used registers + ; No context switch. Return to caller and exit interrupt RESTORE_REGISTER eiret @@ -353,7 +356,7 @@ _vIrq_Handler_SwitchContext: mov r10, r6 ; vPortYeild may be called to current core again at the end of vTaskSwitchContext. - ; This may case nested interrupt, however, it is not necessary to set + ; This may cause nested interrupt, however, it is not necessary to set ; uxInterruptNesting (currently 0) for trap0 exception. The user interrupt ; (EI level interrupt) is not accepted inside of trap0 exception. jarl _vTaskSwitchContext, lp @@ -361,6 +364,7 @@ _vIrq_Handler_SwitchContext: eiret _vIrq_Handler_StartFirstTask: + ; The stack is switch to task stack when starting the first task + ; Save address of interrupt stack RESTORE_REGISTER jr _vPortStartFirstTask - diff --git a/GHS/U2x/README.md b/GHS/U2x/README.md index 01a7a7cf9..ecf9b68e7 100644 --- a/GHS/U2x/README.md +++ b/GHS/U2x/README.md @@ -18,11 +18,12 @@ This repository contains the port of FreeRTOS for Renesas RH850/U2x microcontrol ## Link to Test Project -The test project can be found in [RH850_U2Ax_GHS](https://github.com/FreeRTOS/FreeRTOS-Partner-Supported-Demos/tree/main/RH850_U2Ax_GHS) and [RH850_U2Bx_GHS](https://github.com/FreeRTOS/FreeRTOS-Partner-Supported-Demos/tree/main/RH850_U2Bx_GHS). These projects contain example tasks and configurations to help you get started with FreeRTOS on the RH850/U2Ax and U2Bx. +The test project can be found in [RH850_U2Ax_GHS](https://github.com/FreeRTOS/FreeRTOS-Partner-Supported-Demos/tree/main/RH850_U2Ax_GHS) and [RH850_U2Bx_GHS](https://github.com/FreeRTOS/FreeRTOS-Partner-Supported-Demos/tree/main/RH850_U2Bx_GHS). These projects contain example tasks and configurations to help you get started with FreeRTOS on the RH850/U2Ax and RH850/U2Bx. ## Note - 1. The minimal stack size `configMINIMAL_STACK_SIZE` must be included the reserved memory for nested interrupt. This formula can be referred: `(task_context_size) * (2 + configMAX_INT_NESTING) + Stack_depth_of_taskcode` - In which, `task_context_size` is calculated as `36*4bytes = 144bytes` (when FPU enabled) or `34*4bytes = 136` (when FPU disabled), configMAX_INT_NESTING is `02` as default (Note that a value of `0` is not allowed). + 1. The minimal stack size `configMINIMAL_STACK_SIZE` must be included the reserved memory for nested interrupt. This formula can be referred: `[(task_context_size) * 2] + Stack_depth_of_taskcode`. + In which, `task_context_size` is calculated as `36*4bytes = 144bytes`. + 2. Users need to create a memory section named `mev_address` in `CRAM` for Exclusive Control functionality. Users should initialize the `mev_address` section in the startup file. Example: @@ -32,10 +33,11 @@ Example: st.w r0, 0[r20] ``` 3. The `FXU unit` is only available on `core 0`. Users must ensure that FXU operations are restricted to `core 0` by using the `vTaskCoreAffinitySet` function provided by FreeRTOS SMP. - 4. Set the macro `configENABLE_FXU` to `1` to enable the `FXU unit`; otherwise set `0` to disable `FXU unit`. - 5. This port supports both U2Ax and U2Bx devices. The user must configure `configDEVICE_NAME` with the value `U2Bx_DEVICES` or `U2Ax_DEVICES` to specify which device is being used. - 6. The User can configure the interrupt priority of the OSTM Timer using `configTIMER_INT_PRIORITY`, with 16 levels available (0 being the highest priority and 15 the lowest). - 7. This port also supports the configuration of contiguous CPU cores in FreeRTOS, allowing the user to set task affinity for execution on specific cores or subsets of cores. + 4. Set the macro `configDISABLE_FXU` to `1` to disable the `FXU unit`; otherwise set `0` to enable `FXU unit`. + 5. Set the macro `configDISABLE_FPU` to `1` to disable the `FPU unit`; otherwise set `0` to enable `FPU unit`. + 6. This port supports both U2Ax and U2Bx devices. The user must configure `configDEVICE_NAME` with the value `U2Bx_DEVICES` or `U2Ax_DEVICES` to specify which device is being used. + 7. The User can configure the interrupt priority of the OSTM Timer using `configTIMER_INT_PRIORITY`, with 16 levels available (0 being the highest priority and 15 the lowest). + 8. This port also supports the configuration of contiguous CPU cores in FreeRTOS, allowing the user to set task affinity for execution on specific cores or subsets of cores. ## Other Relevant Information diff --git a/GHS/U2x/port.c b/GHS/U2x/port.c index 9676b0acd..3d69a1f08 100644 --- a/GHS/U2x/port.c +++ b/GHS/U2x/port.c @@ -46,7 +46,7 @@ #define portFXSR_REGISTER_SEL ( 10 ) /* PSW.EBV and PSW.CUx bits are kept as current status */ -#define portINITIAL_PSW_MASK ( 0x00078000 ) +#define portINITIAL_PSW_MASK ( 0x00038000 ) #define portCURRENT_PSW_VALUE ( portSTSR( portPSW_REGISTER_ID, portREGISTER_SEL_0 ) ) #define portCURRENT_SR_ZERO_VALUE ( ( StackType_t ) 0x00000000 ) #define portCURRENT_FPSR_VALUE ( portSTSR( portFPSR_REGISTER_ID, portREGISTER_SEL_0 ) ) @@ -56,6 +56,8 @@ #define portINITIAL_FPSR_MASK ( 0x00ae0000 ) #define portINITIAL_FXSR_MASK ( 0x00ee0000 ) #define portPSW_ID_MASK ( 0x00000020 ) +#define portPSW_FPU_MASK ( 0x00010000 ) +#define portPSW_FXU_MASK ( 0x00020000 ) /* Define necessary hardware IO for OSTM timer. * - OSTM0 is used by default for device variant U2Bx. @@ -151,19 +153,6 @@ #define configSETUP_TICK_INTERRUPT() prvSetupTimerInterrupt() #endif /* configSETUP_TICK_INTERRUPT */ -#if ( !defined( configMAX_INT_NESTING ) || ( configMAX_INT_NESTING == 0 ) ) - -/* Set the default value for depth of nested interrupt. In theory, the - * microcontroller have mechanism to limit number of nested level of interrupt - * by priority (maximum 16 levels). However, the large stack memory should be - * prepared for each task to save resource in interrupt handler. Therefore, it - * is necessary to limit depth of nesting interrupt to optimize memory usage. - * In addition, the execution time of interrupt handler should be very short - * (typically not exceed 20us), this constraint does not impact to system. - */ - #define configMAX_INT_NESTING 2UL -#endif - /* * Used to catch tasks that attempt to return from their implementing function. */ @@ -191,7 +180,11 @@ volatile BaseType_t xPortScheduleStatus[ configNUMBER_OF_CORES ] = { 0 }; * It is necessary to control maximum stack depth. */ volatile UBaseType_t uxInterruptNesting[ configNUMBER_OF_CORES ] = { 0 }; -volatile const UBaseType_t uxPortMaxInterruptDepth = configMAX_INT_NESTING; + +#ifndef configPORT_ISR_STACK_TOPS +#error "Define configPORT_ISR_STACK_TOPS in FreeRTOSConfig.h" +#endif +const UBaseType_t uxInterruptStack[ configNUMBER_OF_CORES ] = configPORT_ISR_STACK_TOPS; /* Count number of nested locks by same cores. The lock is completely released * only if this count is decreased to 0, the lock is separated for task and isr */ @@ -381,46 +374,31 @@ StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack, pxTopOfStack--; *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R30; /* R30 (EP) */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R1; /* R1 */ + *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R1; /* R1 */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R2; /* R2 */ - + *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R2; /* R2 */ pxTopOfStack--; + /* if FPU is enabled, initialize the FPU registers in Stack */ + #if ( configDISABLE_FPU != 1 ) + { + *pxTopOfStack = ( StackType_t ) ( portCURRENT_FPSR_VALUE & portINITIAL_FPSR_MASK ); /* FPSR */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portCURRENT_SR_ZERO_VALUE; /* FPEPC */ + pxTopOfStack--; + } + #endif /* (configDISABLE_FPU != 1 ) */ + /* Keep System pre-configuration (HV, CUx, EBV) as current setting in PSW register */ *pxTopOfStack = ( StackType_t ) ( portCURRENT_PSW_VALUE & portINITIAL_PSW_MASK ); /* EIPSW */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* EIPC */ + *pxTopOfStack = ( StackType_t ) pxCode; /* EIPC */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) portCURRENT_SR_ZERO_VALUE; /* EIIC */ + *pxTopOfStack = ( StackType_t ) portCURRENT_SR_ZERO_VALUE; /* EIIC */ pxTopOfStack--; *pxTopOfStack = ( StackType_t ) ( portCURRENT_PSW_VALUE & portINITIAL_PSW_MASK ); /* CTPSW */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) portCURRENT_SR_ZERO_VALUE; /* CTPC */ - - /* if FPU is enabled, initialize the FPU registers in Stack */ - #if ( configENABLE_FPU == 1 ) - pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) ( portCURRENT_FPSR_VALUE & portINITIAL_FPSR_MASK ); /* FPSR */ - pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) portCURRENT_SR_ZERO_VALUE; /* FPEPC */ - #endif /* (configENABLE_FPU == 1) */ - - /* if FXU is enabled, initialize the FXU registers in Stack */ - #if ( configENABLE_FXU == 1 ) - /* FXU Unit is available in PE0 only */ - if( 0 == xPortGET_CORE_ID() ) - { - pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) ( portCURRENT_FXSR_VALUE & portINITIAL_FXSR_MASK ); /* FXSR */ - pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) portCURRENT_SR_ZERO_VALUE; /* FXXP */ - } - else - { - /* Do nothing */ - } - #endif /* (configENABLE_FXU == 1) */ + *pxTopOfStack = ( StackType_t ) portCURRENT_SR_ZERO_VALUE; /* CTPC */ return pxTopOfStack; } @@ -621,7 +599,7 @@ static void prvSetupTimerInterrupt( void ) /* Interrupt configuration for OSTM Timer*/ pulOSTMIntReg = ( volatile uint32_t * ) portOSTM_EIC_ADDR; - *pulOSTMIntReg = ( portINT_TABLE_VECTOR | configTIMER_INT_PRIORITY ); + *pulOSTMIntReg = ( portINT_DIRECT_VECTOR | configTIMER_INT_PRIORITY ); /* Set OSTM0 control setting */ *( ( volatile uint32_t * ) portOSTMCTL_ADDR ) = ( portOSTM_INTERRUPT_ENABLE | portOSTM_MODE_INTERVAL_TIMER | portOSTM_START_INTERRUPT_DISABLE ); diff --git a/GHS/U2x/portasm.850 b/GHS/U2x/portasm.850 index 0561ed0ef..9bbc3b0d3 100644 --- a/GHS/U2x/portasm.850 +++ b/GHS/U2x/portasm.850 @@ -32,17 +32,16 @@ -- Extern symbols ------------------------------------------------------------------------------- .extern _uxInterruptNesting -.extern _uxPortMaxInterruptDepth .extern _xPortScheduleStatus .extern _vTaskSwitchContext .extern _pvPortGetCurrentTCB -.extern _vCommonISRHandler .extern _xPortGET_CORE_ID .global _vIrq_Handler .global _vPortStartFirstTask .global _vPortYield .global _vTRAP0_Handler + -------------------------------------------------------------------------------- -- Macro definitions -------------------------------------------------------------------------------- @@ -57,6 +56,8 @@ .set CTPC, 16 .set CTPSW, 17 .set EIIC_MSK, 0x00000FFF +.set FPU_MSK 0x00010000 +.set FXU_MSK 0x00020000 -------------------------------------------------------------------------------- -- portSAVE_CONTEXT -- Context saving @@ -70,6 +71,18 @@ pushsp r1-r2 --$warning + stsr EIPSW, r15 + -- Save FPU registers to stack if they are enabled + -- If disable, skip next 2 instructions: stsr (4 bytes)*2 with dummy save. + #if (0 == configDISABLE_FPU) + mov FPU_MSK, r19 + tst r15, r19 + bz 10 + stsr FPSR, r18 + stsr FPEPC, r19 + pushsp r18-r19 -- Push dummy value if FPU disabled. + #endif + stsr EIPSW, r15 stsr EIPC, r16 stsr EIIC, r17 @@ -77,30 +90,9 @@ stsr CTPC, r19 pushsp r15-r19 - -- Save FPU registers to stack if FPU is enabled - #if (1 == configENABLE_FPU) - stsr FPSR, r18 - stsr FPEPC, r19 - pushsp r18-r19 - #endif - - -- Save FXU registers to stack if FXU is enabled - #if (1 == configENABLE_FXU) - mov r0, r20 - mov r0, r21 - stsr 0, r19, 2 -- Get PEID - cmp r19, r0 -- Confirm PEID value is PE0 - bne 8 -- branch 2 instructions if is not PE0 - -- to avoid unprivileged access - stsr FXSR, r20, 10 -- If PE0, save FXU register - stsr FXXP, r21, 10 -- If PE0, save FXU register - pushsp r20-r21 - #endif - -- Get current TCB, the return value is stored in r10 jarl _pvPortGetCurrentTCB, lp st.w sp, 0[r10] - .endm -------------------------------------------------------------------------------- @@ -112,25 +104,7 @@ jarl _pvPortGetCurrentTCB, lp ld.w 0[r10], sp -- Restore the stack pointer from the TCB - -- Restore FXU registers if FXU is enabled - #if (1 == configENABLE_FXU) - popsp r20-r21 - stsr 0, r19, 2 -- Get PEID - cmp r19, r0 -- Confirm PEID value is PE0 - bne 8 -- branch 2 instructions if is not PE0 - -- to avoid unprivileged access - ldsr r21, FXXP, 10 -- If PE0, restore FXU register - ldsr r20, FXSR, 10 -- If PE0, restore FXU register - #endif - - -- Restore FPU registers if FPU is enabled - #if (1 == configENABLE_FPU) - popsp r18-r19 - ldsr r19, FPEPC - ldsr r18, FPSR - #endif - - --Restore general-purpose registers and EIPSW, EIPC, EIIC, CTPSW, CTPC + -- Restore general-purpose registers and EIPSW, EIPC, EIIC, CTPSW, CTPC popsp r15-r19 ldsr r19, CTPC ldsr r18, CTPSW @@ -138,6 +112,16 @@ ldsr r16, EIPC ldsr r15, EIPSW + -- Restore FPU registers if FPU is enabled + #if (0 == configDISABLE_FPU) + popsp r18-r19 + mov FPU_MSK, r17 + tst r15, r17 + bz 10 + ldsr r19, FPEPC + ldsr r18, FPSR + #endif + --$nowarning popsp r1-r2 --$warning @@ -150,74 +134,79 @@ -- Save used registers -------------------------------------------------------------------------------- .macro SAVE_REGISTER - pushsp r5-r30 + pushsp r5-r19 --$nowarning pushsp r1-r2 --$warning - stsr EIPSW, r19 - stsr EIPC, r18 - stsr EIIC, r17 - mov lp, r16 - mov ep, r15 - stsr CTPSW, r14 - stsr CTPC, r13 - pushsp r13-r19 + stsr EIPSW, r15 - #if (1 == configENABLE_FPU) + #if (0 == configDISABLE_FPU) + mov FPU_MSK, r19 + tst r15, r19 + bz 10 stsr FPSR, r18 stsr FPEPC, r19 - pushsp r18-r19 + pushsp r18-r19 -- Push dummy value if FPU disabled. #endif -- Save FXU registers to stack if FXU is enabled - #if (1 == configENABLE_FXU) - mov r0, r20 - mov r0, r21 - stsr 0, r19, 2 -- Get PEID - cmp r19, r0 -- Confirm PEID value is PE0 - bne 8 -- Branch 2 instructions if is not PE0 - -- to avoid unprivileged access - stsr FXSR, r20, 10 -- If PE0, save FXU register - stsr FXXP, r21, 10 -- If PE0, save FXU register - pushsp r20-r21 + #if (0 == configDISABLE_FXU) + mov FXU_MSK, r19 + tst r15, r19 + bz 10 + stsr FXSR, r18, 10 + stsr FXXP, r19, 10 + pushsp r18-r19 -- Push dummy value if FXU disabled. #endif + mov ep, r13 + mov lp, r14 + stsr EIPSW, r15 + stsr EIPC, r16 + stsr EIIC, r17 + stsr CTPSW, r18 + stsr CTPC, r19 + pushsp r13-r19 + .endm -------------------------------------------------------------------------------- -- Restore used registers -------------------------------------------------------------------------------- .macro RESTORE_REGISTER + popsp r13-r19 + ldsr r19, CTPC + ldsr r18, CTPSW + ldsr r17, EIIC + ldsr r16, EIPC + ldsr r15, EIPSW + mov r14, lp + mov r13, ep + -- Restore FXU registers if FXU is enabled - #if (1 == configENABLE_FXU) - popsp r20-r21 - stsr 0, r19, 2 -- Get PEID - cmp r19, r0 -- Confirm PEID value is PE0 - bne 8 -- Branch 2 instructions if is not PE0 - -- to avoid unprivileged access - ldsr r21, FXXP, 10 -- If PE0, restore FXU register - ldsr r20, FXSR, 10 -- If PE0, restore FXU register + #if (0 == configDISABLE_FXU) + popsp r18-r19 + mov FXU_MSK, r17 + tst r15, r17 + bz 10 + ldsr r19, FXXP, 10 + ldsr r18, FXSR, 10 #endif - #if (1 == configENABLE_FPU) + -- Restore FPU registers if FPU is enabled + #if (0 == configDISABLE_FPU) popsp r18-r19 + mov FPU_MSK, r17 + tst r15, r17 + bz 10 ldsr r19, FPEPC ldsr r18, FPSR #endif - popsp r13-r19 - ldsr r13, CTPC - ldsr r14, CTPSW - mov r15, ep - mov r16, lp - ldsr r17, EIIC - ldsr r18, EIPC - ldsr r19, EIPSW - --$nowarning popsp r1-r2 --$warning - popsp r5-r30 + popsp r5-r19 .endm -------------------------------------------------------------------------------- @@ -238,7 +227,7 @@ _vPortYield: -- PortYield handler. This is installed as the TRAP exception handler. -------------------------------------------------------------------------------- _vTRAP0_Handler: - --Save the context of the current task. + -- Save the context of the current task. portSAVE_CONTEXT -- The use case that portYield() is called from interrupt context as nested interrupt. @@ -288,7 +277,7 @@ _vIrq_Handler: -- Then, increase nesting count for current core. jarl _xPortGET_CORE_ID, lp -- return value is contained in r10 mov r10, r17 - shl 2, r17 + shl 2, r17 mov _uxInterruptNesting, r19 add r17, r19 @@ -296,29 +285,43 @@ _vIrq_Handler: addi 0x1, r18, r16 st.w r16, 0[r19] - pushsp r17-r19 + -- Check and switch to interrupt stack if task stack is currently used. + cmp r0, r18 + bne _vIrq_Handler_Entry_End + mov _uxInterruptStack, r14 + add r17, r14 + ld.w 0[r14], r14 + mov sp, r16 + mov r14, sp + +_vIrq_Handler_Entry_End: + pushsp r16-r19 - --Call the interrupt handler. + -- Call the interrupt handler. stsr EIIC, r6 andi EIIC_MSK, r6, r6 - -- Do not enable interrupt for nesting. Stackover flow may occurs if the - -- depth of nesting interrupt is exceeded. - mov _uxPortMaxInterruptDepth, r19 - ld.w 0[r19], r15 - cmp r15, r16 - bge 4 -- Jump over ei instruction + -- Enable nested interrupts, invoke ISR functions from reference table ei - jarl _vCommonISRHandler, lp + stsr 4, r16, 1 -- Load based address of Interrupt Reference Table + andi 0xfff, r6, r17 + shl 2, r17 + add r17, r16 + ld.w 0[r16], r16 + + -- Invoke registered ISR function + jarl [r16], lp + di synce - popsp r17-r19 + popsp r16-r19 st.w r18, 0[r19] -- Restore the old nesting count. -- A context switch if no nesting interrupt. cmp 0x0, r18 bne _vIrq_Handler_NotSwitchContext + mov r16, sp -- Restore to task stack. -- Check if context switch is requested. mov _xPortScheduleStatus, r19 @@ -328,11 +331,11 @@ _vIrq_Handler: bne _vIrq_Handler_SwitchContext _vIrq_Handler_NotSwitchContext: - -- No context switch. Restore used registers + -- No context switch. Return to caller and exit interrupt RESTORE_REGISTER eiret ---This sequence is executed for primary core only to switch context +-- This sequence is executed for primary core only to switch context _vIrq_Handler_SwitchContext: -- Clear the context switch pending flag. st.w r0, 0[r19] @@ -349,7 +352,7 @@ _vIrq_Handler_SwitchContext: mov r10, r6 -- vPortYeild may be called to current core again at the end of vTaskSwitchContext. - -- This may case nested interrupt, however, it is not necessary to set + -- This may cause nested interrupt, however, it is not necessary to set -- uxInterruptNesting (currently 0) for trap0 exception. The user interrupt -- (EI level interrupt) is not accepted inside of trap0 exception. jarl _vTaskSwitchContext, lp @@ -357,6 +360,7 @@ _vIrq_Handler_SwitchContext: eiret _vIrq_Handler_StartFirstTask: + -- The stack is switch to task stack when starting the first task + -- Save address of interrupt stack RESTORE_REGISTER jr _vPortStartFirstTask -