#include "task.h"\r
#include "portmacro.h"\r
\r
+#ifndef configCLINT_BASE_ADDRESS\r
+ #warning configCLINT_BASE_ADDRESS must be defined in FreeRTOSConfig.h. If the target chip includes a Core Local Interrupter (CLINT) then set configCLINT_BASE_ADDRESS to the CLINT base address. Otherwise set configCLINT_BASE_ADDRESS to 0.\r
+#endif\r
+\r
+/* Let the user override the pre-loading of the initial LR with the address of\r
+prvTaskExitError() in case it messes up unwinding of the stack in the\r
+debugger. */\r
+#ifdef configTASK_RETURN_ADDRESS\r
+ #define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS\r
+#else\r
+ #define portTASK_RETURN_ADDRESS prvTaskExitError\r
+#endif\r
+\r
+/* The stack used by interrupt service routines. Set configISR_STACK_SIZE_WORDS\r
+to use a statically allocated array as the interrupt stack. Alternative leave\r
+configISR_STACK_SIZE_WORDS undefined and update the linker script so that a\r
+linker variable names __freertos_irq_stack_top has the same value as the top\r
+of the stack used by main. Using the linker script method will repurpose the\r
+stack that was used by main before the scheduler was started for use as the\r
+interrupt stack after the scheduler has started. */\r
+#ifdef configISR_STACK_SIZE_WORDS\r
+ static __attribute__ ((aligned(16))) StackType_t xISRStack[ configISR_STACK_SIZE_WORDS ] = { 0 };\r
+ const StackType_t xISRStackTop = ( StackType_t ) &( xISRStack[ ( configISR_STACK_SIZE_WORDS & ~portBYTE_ALIGNMENT_MASK ) - 1 ] );\r
+#else\r
+ extern const uint32_t __freertos_irq_stack_top[];\r
+ const StackType_t xISRStackTop = ( StackType_t ) __freertos_irq_stack_top;\r
+#endif\r
+\r
/*\r
* Setup the timer to generate the tick interrupts. The implementation in this\r
* file is weak to allow application writers to change the timer used to\r
/*-----------------------------------------------------------*/\r
\r
/* Used to program the machine timer compare register. */\r
-static uint64_t ullNextTime = 0ULL;\r
-static volatile uint64_t * const pullMachineTimerCompareRegister = ( volatile uint64_t * const ) ( configCTRL_BASE + 0x4000 );\r
+uint64_t ullNextTime = 0ULL;\r
+const uint64_t *pullNextTime = &ullNextTime;\r
+const uint32_t ulTimerIncrementsForOneTick = ( uint32_t ) ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ); /* Assumes increment won't go over 32-bits. */\r
+volatile uint64_t * const pullMachineTimerCompareRegister = ( volatile uint64_t * const ) ( configCLINT_BASE_ADDRESS + 0x4000 );\r
+\r
+/* Set configCHECK_FOR_STACK_OVERFLOW to 3 to add ISR stack checking to task\r
+stack checking. A problem in the ISR stack will trigger an assert, not call the\r
+stack overflow hook function (because the stack overflow hook is specific to a\r
+task stack, not the ISR stack). */\r
+#if( configCHECK_FOR_STACK_OVERFLOW > 2 )\r
+ #warning This path not tested, or even compiled yet.\r
+ /* Don't use 0xa5 as the stack fill bytes as that is used by the kernerl for\r
+ the task stacks, and so will legitimately appear in many positions within\r
+ the ISR stack. */\r
+ #define portISR_STACK_FILL_BYTE 0xee\r
+\r
+ static const uint8_t ucExpectedStackBytes[] = {\r
+ portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \\r
+ portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \\r
+ portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \\r
+ portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \\r
+ portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE }; \\r
+\r
+ #define portCHECK_ISR_STACK() configASSERT( ( memcmp( ( void * ) xISRStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) == 0 ) )\r
+#else\r
+ /* Define the function away. */\r
+ #define portCHECK_ISR_STACK()\r
+#endif /* configCHECK_FOR_STACK_OVERFLOW > 2 */\r
\r
/*-----------------------------------------------------------*/\r
\r
-void prvTaskExitError( void )\r
+static void prvTaskExitError( void )\r
{\r
volatile uint32_t ulx = 0;\r
-\r
+#warning Not currently used\r
/* A function that implements a task must not exit or attempt to return to\r
its caller as there is nothing to return to. If a task wants to exit it\r
should instead call vTaskDelete( NULL ).\r
}\r
/*-----------------------------------------------------------*/\r
\r
-/*\r
- * See header file for description.\r
- */\r
-StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )\r
-{\r
- /*\r
- X1 to X31 integer registers for the 'I' profile, X1 to X15 for the 'E' profile.\r
-\r
- Register ABI Name Description Saver\r
- x0 zero Hard-wired zero -\r
- x1 ra Return address Caller\r
- x2 sp Stack pointer Callee\r
- x3 gp Global pointer -\r
- x4 tp Thread pointer -\r
- x5-7 t0-2 Temporaries Caller\r
- x8 s0/fp Saved register/Frame pointer Callee\r
- x9 s1 Saved register Callee\r
- x10-11 a0-1 Function Arguments/return values Caller\r
- x12-17 a2-7 Function arguments Caller\r
- x18-27 s2-11 Saved registers Callee\r
- x28-31 t3-6 Temporaries Caller\r
- */\r
-\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( StackType_t ) 31;\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( StackType_t ) 30;\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( StackType_t ) 29;\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( StackType_t ) 28;\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( StackType_t ) 27;\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( StackType_t ) 26;\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( StackType_t ) 25;\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( StackType_t ) 24;\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( StackType_t ) 23;\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( StackType_t ) 22;\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( StackType_t ) 21;\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( StackType_t ) 20;\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( StackType_t ) 19;\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( StackType_t ) 18;\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( StackType_t ) 17;\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( StackType_t ) 16;\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( StackType_t ) 15;\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( StackType_t ) 14;\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( StackType_t ) 13;\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( StackType_t ) 12;\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( StackType_t ) 11;\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( StackType_t ) pvParameters;\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( StackType_t ) 9;\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( StackType_t ) 8;\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( StackType_t ) 7;\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( StackType_t ) 6;\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( StackType_t ) 5;\r
- pxTopOfStack--;\r
-// *pxTopOfStack = ( StackType_t ) 4; /* Thread pointer. */\r
-// pxTopOfStack--;\r
-// *pxTopOfStack = ( StackType_t ) 3; /* Global pointer. */\r
-// pxTopOfStack--;\r
-// *pxTopOfStack = ( StackType_t ) 2; /* Stack pointer. */\r
-// pxTopOfStack--;\r
- *pxTopOfStack = ( StackType_t ) prvTaskExitError;\r
- pxTopOfStack--;\r
- *pxTopOfStack = ( StackType_t ) pxCode;\r
-\r
- return pxTopOfStack;\r
-}\r
+#if( configCLINT_BASE_ADDRESS != 0 )\r
+\r
+ void vPortSetupTimerInterrupt( void )\r
+ {\r
+ uint32_t ulCurrentTimeHigh, ulCurrentTimeLow;\r
+ volatile uint32_t * const pulTimeHigh = ( volatile uint32_t * const ) ( configCLINT_BASE_ADDRESS + 0xBFFC );\r
+ volatile uint32_t * const pulTimeLow = ( volatile uint32_t * const ) ( configCLINT_BASE_ADDRESS + 0xBFF8 );\r
+\r
+ do\r
+ {\r
+ ulCurrentTimeHigh = *pulTimeHigh;\r
+ ulCurrentTimeLow = *pulTimeLow;\r
+ } while( ulCurrentTimeHigh != *pulTimeHigh );\r
+\r
+ ullNextTime = ( uint64_t ) ulCurrentTimeHigh;\r
+ ullNextTime <<= 32ULL;\r
+ ullNextTime |= ( uint64_t ) ulCurrentTimeLow;\r
+ ullNextTime += ( uint64_t ) ulTimerIncrementsForOneTick;\r
+ *pullMachineTimerCompareRegister = ullNextTime;\r
+\r
+ /* Prepare the time to use after the next tick interrupt. */\r
+ ullNextTime += ( uint64_t ) ulTimerIncrementsForOneTick;\r
+ }\r
+\r
+#endif /* ( configCLINT_BASE_ADDRESS != 0 ) */\r
/*-----------------------------------------------------------*/\r
\r
-void vPortSetupTimerInterrupt( void )\r
+BaseType_t xPortStartScheduler( void )\r
{\r
-uint32_t ulCurrentTimeHigh, ulCurrentTimeLow;\r
-volatile uint32_t * const pulTimeHigh = ( volatile uint32_t * const ) ( configCTRL_BASE + 0xBFF8 );\r
-volatile uint32_t * const pulTimeLow = ( volatile uint32_t * const ) ( configCTRL_BASE + 0xBFFc );\r
+extern void xPortStartFirstTask( void );\r
\r
- do\r
+ #if( configASSERT_DEFINED == 1 )\r
+ {\r
+ volatile uint32_t mtvec = 0;\r
+\r
+ /* Check the least significant two bits of mtvec are 00 - indicating\r
+ single vector mode. */\r
+ __asm volatile( "csrr %0, mtvec" : "=r"( mtvec ) );\r
+ configASSERT( ( mtvec & 0x03UL ) == 0 );\r
+\r
+ /* Check alignment of the interrupt stack - which is the same as the\r
+ stack that was being used by main() prior to the scheduler being\r
+ started. */\r
+ configASSERT( ( xISRStackTop & portBYTE_ALIGNMENT_MASK ) == 0 );\r
+ }\r
+ #endif /* configASSERT_DEFINED */\r
+\r
+ /* If there is a CLINT then it is ok to use the default implementation\r
+ in this file, otherwise vPortSetupTimerInterrupt() must be implemented to\r
+ configure whichever clock is to be used to generate the tick interrupt. */\r
+ vPortSetupTimerInterrupt();\r
+\r
+ #if( configCLINT_BASE_ADDRESS != 0 )\r
{\r
- ulCurrentTimeHigh = *pulTimeHigh;\r
- ulCurrentTimeLow = *pulTimeLow;\r
- } while( ulCurrentTimeHigh != *pulTimeHigh );\r
-\r
- ullNextTime = ( uint64_t ) ulCurrentTimeHigh;\r
- ullNextTime <<= 32ULL;\r
- ullNextTime |= ( uint64_t ) ulCurrentTimeLow;\r
- ullNextTime += ( configCPU_CLOCK_HZ / configTICK_RATE_HZ );\r
- *pullMachineTimerCompareRegister = ullNextTime;\r
-\r
- /* Enable timer interrupt */\r
- __asm volatile( "csrs mie, %0" :: "r"(0x80) );\r
+ /* Enable mtime and external interrupts. 1<<7 for timer interrupt, 1<<11\r
+ for external interrupt. _RB_ What happens here when mtime is not present as\r
+ with pulpino? */\r
+ __asm volatile( "csrs mie, %0" :: "r"(0x880) );\r
+ }\r
+ #else\r
+ {\r
+ /* Enable external interrupts. */\r
+ __asm volatile( "csrs mie, %0" :: "r"(0x800) );\r
+ }\r
+ #endif /* configCLINT_BASE_ADDRESS */\r
+\r
+ xPortStartFirstTask();\r
+\r
+ /* Should not get here as after calling xPortStartFirstTask() only tasks\r
+ should be executing. */\r
+ return pdFAIL;\r
}\r
/*-----------------------------------------------------------*/\r
\r
-void Software_IRQHandler( void )\r
+void vPortEndScheduler( void )\r
{\r
-volatile uint32_t * const ulSoftInterrupt = ( uint32_t * ) configCTRL_BASE;\r
+ /* Not implemented. */\r
+ for( ;; );\r
+}\r
+\r
\r
- vTaskSwitchContext();\r
\r
- /* Clear software interrupt. */\r
- *ulSoftInterrupt = 0UL;\r
-}\r
-/*-----------------------------------------------------------*/\r
\r
\r