* base set of RISC-V registers. There are additional\r
* freertos_risc_v_port_specific_extensions.h files for RISC-V implementations\r
* that do not include a standard CLINT or do add to the base set of RISC-V\r
- * regiters.\r
+ * registers.\r
*\r
* CARE MUST BE TAKEN TO INCLDUE THE CORRECT\r
* freertos_risc_v_port_specific_extensions.h HEADER FILE FOR THE CHIP\r
\r
#define portasmHAS_CLINT 0\r
\r
+/* Constants to define the additional registers found on the Pulpino RI5KY. */\r
+#define lpstart0 0x7b0\r
+#define lpend0 0x7b1\r
+#define lpcount0 0x7b2\r
+#define lpstart1 0x7b4\r
+#define lpend1 0x7b5\r
+#define lpcount1 0x7b6\r
+\r
+/* Six additional registers to save and restore, as per the #defines above. */\r
+#define portasmADDITIONAL_CONTEXT_SIZE 6 /* Must be even number on 32-bit cores. */\r
+\r
+/* Save additional registers found on the Pulpino. */\r
.macro portasmSAVE_ADDITIONAL_REGISTERS\r
+ addi sp, sp, -portasmADDITIONAL_CONTEXT_SIZE /* Make room for the additional registers. */\r
+ csrr t0, lpstart0 /* Load additional registers into accessable temporary registers. */\r
+ csrr t1, lpend0\r
+ csrr t2, lpcount0\r
+ csrr t3, lpstart1\r
+ csrr t4, lpend1\r
+ csrr t5, lpcount1\r
+ sw t0, 1 * portWORD_SIZE( sp )\r
+ sw t1, 2 * portWORD_SIZE( sp )\r
+ sw t2, 3 * portWORD_SIZE( sp )\r
+ sw t3, 4 * portWORD_SIZE( sp )\r
+ sw t4, 5 * portWORD_SIZE( sp )\r
+ sw t5, 6 * portWORD_SIZE( sp )\r
.endm\r
\r
+/* Restore the additional registers found on the Pulpino. */\r
.macro portasmRESTORE_ADDITIONAL_REGISTERS\r
- /* This file is for use with chips that do not add to the standard RISC-V\r
- * register set, so there is nothing to do here. */\r
+ lw t0, 1 * portWORD_SIZE( sp ) /* Load additional registers into accessable temporary registers. */\r
+ lw t1, 2 * portWORD_SIZE( sp )\r
+ lw t2, 3 * portWORD_SIZE( sp )\r
+ lw t3, 4 * portWORD_SIZE( sp )\r
+ lw t4, 5 * portWORD_SIZE( sp )\r
+ lw t5, 6 * portWORD_SIZE( sp )\r
+ csrw lpstart0, t0\r
+ csrw lpend0, t1\r
+ csrw lpcount0, t2\r
+ csrw lpstart1, t3\r
+ csrw lpend1, t4\r
+ csrw lpcount1, t5\r
+ addi sp, sp, -portasmADDITIONAL_CONTEXT_SIZE /* Remove space added for additional registers. */\r
.endm\r
\r
#endif /* __FREERTOS_RISC_V_EXTENSIONS_H__ */\r
#include "task.h"\r
#include "portmacro.h"\r
\r
-#ifdef configISR_STACK_SIZE\r
- /* The stack used by interrupt service routines. */\r
- static __attribute__ ((aligned(16))) StackType_t xISRStack[ configISR_STACK_SIZE ] = { 0 };\r
- const StackType_t * const xISRStackTop = &( xISRStack[ ( configISR_STACK_SIZE & ~portBYTE_ALIGNMENT_MASK ) - 1 ] );\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 uint32_t xISRStackTop = ( uint32_t ) __freertos_irq_stack_top;\r
+ const StackType_t xISRStackTop = ( StackType_t ) __freertos_irq_stack_top;\r
#endif\r
\r
/*\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
-uint32_t mstatus;\r
-const uint32_t ulMPIE_Bit = 0x80, ulMPP_Bits = 0x1800;\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
- /* Start task with interrupt enabled. */\r
- __asm volatile ("csrr %0, mstatus" : "=r"(mstatus));\r
- mstatus |= ulMPIE_Bit | ulMPP_Bits;\r
- pxTopOfStack--;\r
- *pxTopOfStack = mstatus;\r
-\r
- /* Numbers correspond to the x register number. */\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
-/*-----------------------------------------------------------*/\r
-\r
#if( configCLINT_BASE_ADDRESS != 0 )\r
\r
void vPortSetupTimerInterrupt( void )\r
* 1 tab == 4 spaces!\r
*/\r
\r
+#if __riscv_xlen == 64\r
+ #error Not implemented yet - change lw to ld, and sw to sd.\r
+ #define portWORD_SIZE 8\r
+#elif __riscv_xlen == 32\r
+ #define portWORD_SIZE 4\r
+#else\r
+ #error Assembler did not define __riscv_xlen\r
+#endif\r
+\r
/*\r
* The FreeRTOS kernel's RISC-V port is split between the the code that is\r
* common across all currently supported RISC-V chips (implementations of the\r
* base set of RISC-V registers. There are additional\r
* freertos_risc_v_port_specific_extensions.h files for RISC-V implementations\r
* that do not include a standard CLINT or do add to the base set of RISC-V\r
- * regiters.\r
+ * registers.\r
*\r
* CARE MUST BE TAKEN TO INCLDUE THE CORRECT\r
* freertos_risc_v_port_specific_extensions.h HEADER FILE FOR THE CHIP\r
#error portasmHANDLE_INTERRUPT must be defined to the function to be called to handle external/peripheral interrupts. portasmHANDLE_INTERRUPT can be defined on the assmbler command line or in the appropriate freertos_risc_v_port_specific_extensions.h header file.\r
#endif\r
\r
-#ifndef portasmSAVE_ADDITIONAL_REGISTERS\r
- /* portasmSAVE_ADDITIONAL_REGISTERS is not defined so assume no additional\r
- registers need to be saved. */\r
- #define portasmSAVE_ADDITIONAL_REGISTERS\r
-#endif\r
-\r
-#ifndef portasmRESTORE_ADDITIONAL_REGISTERS\r
- /* portasmRESTORE_ADDITIONAL_REGISTERS is not defined so assume no\r
- additional registers need to be restored. */\r
- #define portasmRESTORE_ADDITIONAL_REGISTERS\r
-#endif\r
-\r
-#if __riscv_xlen == 64\r
- #error Not implemented yet - change lw to ld, and sw to sd.\r
- #define portWORD_SIZE 8\r
-#elif __riscv_xlen == 32\r
- #define portWORD_SIZE 4\r
-#else\r
- #error Assembler did not define __riscv_xlen\r
-#endif\r
-\r
/* Only the standard core registers are stored by default. Any additional\r
registers must be saved by the portasmSAVE_ADDITIONAL_REGISTERS and\r
portasmRESTORE_ADDITIONAL_REGISTERS macros - which can be defined in a chip\r
\r
.global xPortStartFirstTask\r
.global vFreeRTOSPortTrapHandler\r
+.global pxPortInitialiseStack\r
.extern pxCurrentTCB\r
.extern ulPortTrapHandler\r
.extern vTaskSwitchContext\r
.extern pullNextTime\r
.extern ulTimerIncrementsForOneTick\r
.extern xISRStackTop\r
-.extern vPortHandleInterrupt\r
\r
/*-----------------------------------------------------------*/\r
\r
-.align 16\r
+.align 8\r
+.func\r
vFreeRTOSPortTrapHandler:\r
addi sp, sp, -portCONTEXT_SIZE\r
sw x1, 1 * portWORD_SIZE( sp )\r
sw x30, 27 * portWORD_SIZE( sp )\r
sw x31, 28 * portWORD_SIZE( sp )\r
\r
- portasmSAVE_ADDITIONAL_REGISTERS /* Defined in freertos_risc_v_port_specific_extensions.h to save any registers unique to the RISC-V implementation. */\r
-\r
csrr t0, mstatus /* Required for MPIE bit. */\r
sw t0, 29 * portWORD_SIZE( sp )\r
\r
+ portasmSAVE_ADDITIONAL_REGISTERS /* Defined in freertos_risc_v_port_specific_extensions.h to save any registers unique to the RISC-V implementation. */\r
+\r
lw t0, pxCurrentTCB /* Load pxCurrentTCB. */\r
sw sp, 0( t0 ) /* Write sp to first TCB member. */\r
\r
lw sp, pxCurrentTCB /* Load pxCurrentTCB. */\r
lw sp, 0( sp ) /* Read sp from first TCB member. */\r
\r
- /* Load mret with the address of the next task. */\r
+ /* Load mret with the address of the next instruction in the task to run next. */\r
lw t0, 0( sp )\r
csrw mepc, t0\r
\r
+ portasmRESTORE_ADDITIONAL_REGISTERS /* Defined in freertos_risc_v_port_specific_extensions.h to restore any registers unique to the RISC-V implementation. */\r
+\r
/* Load mstatus with the interrupt enable bits used by the task. */\r
lw t0, 29 * portWORD_SIZE( sp )\r
csrw mstatus, t0 /* Required for MPIE bit. */\r
\r
- portasmRESTORE_ADDITIONAL_REGISTERS /* Defined in freertos_risc_v_port_specific_extensions.h to restore any registers unique to the RISC-V implementation. */\r
-\r
lw x1, 1 * portWORD_SIZE( sp )\r
lw x5, 2 * portWORD_SIZE( sp ) /* t0 */\r
lw x6, 3 * portWORD_SIZE( sp ) /* t1 */\r
lw x29, 26 * portWORD_SIZE( sp ) /* t4 */\r
lw x30, 27 * portWORD_SIZE( sp ) /* t5 */\r
lw x31, 28 * portWORD_SIZE( sp ) /* t6 */\r
- addi sp, sp, portCONTEXT_SIZE\r
+ addi sp, sp, portCONTEXT_SIZE\r
\r
mret\r
+ .endfunc\r
/*-----------------------------------------------------------*/\r
\r
-.align 16\r
+.align 8\r
+.func\r
xPortStartFirstTask:\r
\r
#if( portasmHAS_CLINT != 0 )\r
lw sp, 0( sp ) /* Read sp from first TCB member. */\r
\r
lw x1, 0( sp ) /* Note for starting the scheduler the exception return address is used as the function return address. */\r
+\r
+ portasmRESTORE_ADDITIONAL_REGISTERS /* Defined in freertos_risc_v_port_specific_extensions.h to restore any registers unique to the RISC-V implementation. */\r
+\r
+ lw t0, 29 * portWORD_SIZE( sp ) /* mstatus */\r
+ csrrw x0, mstatus, t0 /* Interrupts enabled from here! */\r
+\r
lw x5, 2 * portWORD_SIZE( sp ) /* t0 */\r
lw x6, 3 * portWORD_SIZE( sp ) /* t1 */\r
lw x7, 4 * portWORD_SIZE( sp ) /* t2 */\r
lw x30, 27 * portWORD_SIZE( sp ) /* t5 */\r
lw x31, 28 * portWORD_SIZE( sp ) /* t6 */\r
addi sp, sp, portCONTEXT_SIZE\r
- csrs mstatus, 8 /* Enable machine interrupts. */\r
ret\r
-\r
+ .endfunc\r
/*-----------------------------------------------------------*/\r
\r
+/*\r
+ * Unlike other ports pxPortInitialiseStack() is written in assembly code as it\r
+ * needs access to the portasmADDITIONAL_CONTEXT_SIZE constant. The prototype\r
+ * for the function is as per the other ports:\r
+ * StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters );\r
+ *\r
+ * As per the standard RISC-V ABI pxTopcOfStack is passed in in a0, pxCode in\r
+ * a1, and pvParameters in a2. The new top of stack is passed out in a0.\r
+ *\r
+ * RISC-V maps registers to ABI names as follows (X1 to X31 integer registers\r
+ * for the 'I' profile, X1 to X15 for the 'E' profile, currently I assumed).\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
+ * The RISC-V context is saved t FreeRTOS tasks in the following stack frame,\r
+ * where the global and thread pointers are currently assumed to be constant so\r
+ * are not saved:\r
+ *\r
+ * mstatus\r
+ * x31\r
+ * x30\r
+ * x29\r
+ * x28\r
+ * x27\r
+ * x26\r
+ * x25\r
+ * x24\r
+ * x23\r
+ * x22\r
+ * x21\r
+ * x20\r
+ * x19\r
+ * x18\r
+ * x17\r
+ * x16\r
+ * x15\r
+ * x14\r
+ * x13\r
+ * x12\r
+ * x11\r
+ * pvParameters\r
+ * x9\r
+ * x8\r
+ * x7\r
+ * x6\r
+ * x5\r
+ * portTASK_RETURN_ADDRESS\r
+ * pxCode\r
+ */\r
+.align 8\r
+.func\r
+pxPortInitialiseStack:\r
+\r
+ addi t0, x0, portasmADDITIONAL_CONTEXT_SIZE /* The number of chip specific additional registers. */\r
+\r
+chip_specific_stack_frame: /* First add any chip specific registers to the stack frame being created. */\r
+ beq t0, x0, standard_stack_frame /* No more chip specific registers to save. */\r
+ addi a0, a0, -portWORD_SIZE /* Make space for chip specific register. */\r
+ sw x0, 0(a0) /* Give the chip specific register an initial value of zero. */\r
+ addi t0, t0, -1 /* Decrement the count of chip specific registers remaining. */\r
+ j chip_specific_stack_frame /* Until no more chip specific registers. */\r
+\r
+standard_stack_frame: /* Now create the stack frame for the standard registers. */\r
+ csrr t0, mstatus /* Obtain current mstatus value. */\r
+ addi t1, x0, 0x188 /* Generate the value 0x1880, which are the MPIE and MPP bits to set in mstatus. */\r
+ slli t1, t1, 4\r
+ or t0, t0, t1 /* Set MPIE and MPP bits in mstatus value. */\r
+\r
+ addi a0, a0, -portWORD_SIZE\r
+ sw t0, 0(a0) /* mstatus onto the stack. */\r
+ addi a0, a0, -(22 * portWORD_SIZE) /* Space for registers x11-x31. */\r
+ sw a2, 0(a0) /* Task parameters (pvParameters parameter) goes into register X10/a0 on the stack. */\r
+ addi a0, a0, -(6 * portWORD_SIZE) /* Space for registers x5-x9. */\r
+ sw x0, 0(a0) /* Return address onto the stack, could be portTASK_RETURN_ADDRESS */\r
+ addi a0, a0, -portWORD_SIZE\r
+ sw a1, 0(a0) /* mret value (pxCode parameter) onto the stack. */\r
+ ret\r
+ .endfunc\r
+/*-----------------------------------------------------------*/\r