* this software and associated documentation files (the "Software"), to deal in\r
* the Software without restriction, including without limitation the rights to\r
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
- * the Software, and t\r
-\r
- o permit persons to whom the Software is furnished to do so,\r
+ * the Software, and to permit persons to whom the Software is furnished to do so,\r
* subject to the following conditions:\r
*\r
* The above copyright notice and this permission notice shall be included in all\r
\r
#if __riscv_xlen == 64\r
#error Not implemented yet - change lw to ld, and sw to sd.\r
- #define WORD_SIZE 8\r
+ #define portWORD_SIZE 8\r
#elif __riscv_xlen == 32\r
- #define WORD_SIZE 4\r
+ #define portWORD_SIZE 4\r
#else\r
- #error Assembler has not defined __riscv_xlen\r
+ #error Assembler did not define __riscv_xlen\r
#endif\r
\r
-#define CONTEXT_SIZE ( 30 * WORD_SIZE )\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
+ * RISC-V ISA), and code which tailors the port to a specific RISC-V chip:\r
+ *\r
+ * + The code that is common to all RISC-V chips is implemented in\r
+ * FreeRTOS\Source\portable\GCC\RISC-V-RV32\portASM.S. There is only one\r
+ * portASM.S file because the same file is used no matter which RISC-V chip is\r
+ * in use.\r
+ *\r
+ * + The code that tailors the kernel's RISC-V port to a specific RISC-V\r
+ * chip is implemented in freertos_risc_v_port_specific_extensions.h. There\r
+ * is one freertos_risc_v_port_specific_extensions.h that can be used with any\r
+ * RISC-V chip that both includes a standard CLINT and does not add to 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
+ * 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
+ * IN USE. To include the correct freertos_risc_v_port_specific_extensions.h\r
+ * header file ensure the path to the correct header file is in the assembler's\r
+ * include path.\r
+ *\r
+ * This freertos_risc_v_port_specific_extensions.h is for use on RISC-V chips\r
+ * that include a standard CLINT and do not add to the base set of RISC-V\r
+ * registers.\r
+ *\r
+ */\r
+#include "freertos_risc_v_port_specific_extensions.h"\r
+\r
+/* Check the freertos_risc_v_port_specific_extensions.h and/or command line\r
+definitions. */\r
+#ifndef portasmHAS_CLINT\r
+ #error freertos_risc_v_port_specific_extensions.h must define portasmHAS_CLINT to either 1 (CLINT present) or 0 (clint not present).\r
+#endif\r
+\r
+#ifndef portasmHANDLE_INTERRUPT\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
+/* 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
+specific version of freertos_risc_v_port_specific_extensions.h. See the notes\r
+at the top of this file. */\r
+#define portCONTEXT_SIZE ( 30 * portWORD_SIZE )\r
\r
.global xPortStartFirstTask\r
-.global vPortTrapHandler\r
+.global vFreeRTOSPortTrapHandler\r
+.global pxPortInitialiseStack\r
.extern pxCurrentTCB\r
.extern ulPortTrapHandler\r
.extern vTaskSwitchContext\r
.extern Timer_IRQHandler\r
-\r
-\r
.extern pullMachineTimerCompareRegister\r
.extern pullNextTime\r
.extern ulTimerIncrementsForOneTick\r
-\r
+.extern xISRStackTop\r
\r
/*-----------------------------------------------------------*/\r
\r
.align 8\r
-xPortStartFirstTask:\r
+.func\r
+vFreeRTOSPortTrapHandler:\r
+ addi sp, sp, -portCONTEXT_SIZE\r
+ sw x1, 1 * portWORD_SIZE( sp )\r
+ sw x5, 2 * portWORD_SIZE( sp )\r
+ sw x6, 3 * portWORD_SIZE( sp )\r
+ sw x7, 4 * portWORD_SIZE( sp )\r
+ sw x8, 5 * portWORD_SIZE( sp )\r
+ sw x9, 6 * portWORD_SIZE( sp )\r
+ sw x10, 7 * portWORD_SIZE( sp )\r
+ sw x11, 8 * portWORD_SIZE( sp )\r
+ sw x12, 9 * portWORD_SIZE( sp )\r
+ sw x13, 10 * portWORD_SIZE( sp )\r
+ sw x14, 11 * portWORD_SIZE( sp )\r
+ sw x15, 12 * portWORD_SIZE( sp )\r
+ sw x16, 13 * portWORD_SIZE( sp )\r
+ sw x17, 14 * portWORD_SIZE( sp )\r
+ sw x18, 15 * portWORD_SIZE( sp )\r
+ sw x19, 16 * portWORD_SIZE( sp )\r
+ sw x20, 17 * portWORD_SIZE( sp )\r
+ sw x21, 18 * portWORD_SIZE( sp )\r
+ sw x22, 19 * portWORD_SIZE( sp )\r
+ sw x23, 20 * portWORD_SIZE( sp )\r
+ sw x24, 21 * portWORD_SIZE( sp )\r
+ sw x25, 22 * portWORD_SIZE( sp )\r
+ sw x26, 23 * portWORD_SIZE( sp )\r
+ sw x27, 24 * portWORD_SIZE( sp )\r
+ sw x28, 25 * portWORD_SIZE( sp )\r
+ sw x29, 26 * portWORD_SIZE( sp )\r
+ sw x30, 27 * portWORD_SIZE( sp )\r
+ sw x31, 28 * portWORD_SIZE( sp )\r
\r
- la t0, vPortTrapHandler\r
- csrw mtvec, t0\r
+ csrr t0, mstatus /* Required for MPIE bit. */\r
+ sw t0, 29 * portWORD_SIZE( sp )\r
\r
- lw sp, pxCurrentTCB /* Load pxCurrentTCB. */\r
- lw sp, 0( sp ) /* Read sp from first TCB member. */\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 x1, 0( sp ) /* Note for starting the scheduler the exception return address is used as the function return address. */\r
- lw x5, 2 * WORD_SIZE( sp ) /* t0 */\r
- lw x6, 3 * WORD_SIZE( sp ) /* t1 */\r
- lw x7, 4 * WORD_SIZE( sp ) /* t2 */\r
- lw x8, 5 * WORD_SIZE( sp ) /* s0/fp */\r
- lw x9, 6 * WORD_SIZE( sp ) /* s1 */\r
- lw x10, 7 * WORD_SIZE( sp ) /* a0 */\r
- lw x11, 8 * WORD_SIZE( sp ) /* a1 */\r
- lw x12, 9 * WORD_SIZE( sp ) /* a2 */\r
- lw x13, 10 * WORD_SIZE( sp ) /* a3 */\r
- lw x14, 11 * WORD_SIZE( sp ) /* a4 */\r
- lw x15, 12 * WORD_SIZE( sp ) /* a5 */\r
- lw x16, 13 * WORD_SIZE( sp ) /* a6 */\r
- lw x17, 14 * WORD_SIZE( sp ) /* a7 */\r
- lw x18, 15 * WORD_SIZE( sp ) /* s2 */\r
- lw x19, 16 * WORD_SIZE( sp ) /* s3 */\r
- lw x20, 17 * WORD_SIZE( sp ) /* s4 */\r
- lw x21, 18 * WORD_SIZE( sp ) /* s5 */\r
- lw x22, 19 * WORD_SIZE( sp ) /* s6 */\r
- lw x23, 20 * WORD_SIZE( sp ) /* s7 */\r
- lw x24, 21 * WORD_SIZE( sp ) /* s8 */\r
- lw x25, 22 * WORD_SIZE( sp ) /* s9 */\r
- lw x26, 23 * WORD_SIZE( sp ) /* s10 */\r
- lw x27, 24 * WORD_SIZE( sp ) /* s11 */\r
- lw x28, 25 * WORD_SIZE( sp ) /* t3 */\r
- lw x29, 26 * WORD_SIZE( sp ) /* t4 */\r
- lw x30, 27 * WORD_SIZE( sp ) /* t5 */\r
- lw x31, 28 * WORD_SIZE( sp ) /* t6 */\r
- addi sp, sp, CONTEXT_SIZE\r
- csrs mstatus, 8 /* Enable machine interrupts. */\r
- ret\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-.align 8\r
-vPortTrapHandler:\r
- addi sp, sp, -CONTEXT_SIZE\r
- sw x1, 1 * WORD_SIZE( sp )\r
- sw x5, 2 * WORD_SIZE( sp )\r
- sw x6, 3 * WORD_SIZE( sp )\r
- sw x7, 4 * WORD_SIZE( sp )\r
- sw x8, 5 * WORD_SIZE( sp )\r
- sw x9, 6 * WORD_SIZE( sp )\r
- sw x10, 7 * WORD_SIZE( sp )\r
- sw x11, 8 * WORD_SIZE( sp )\r
- sw x12, 9 * WORD_SIZE( sp )\r
- sw x13, 10 * WORD_SIZE( sp )\r
- sw x14, 11 * WORD_SIZE( sp )\r
- sw x15, 12 * WORD_SIZE( sp )\r
- sw x16, 13 * WORD_SIZE( sp )\r
- sw x17, 14 * WORD_SIZE( sp )\r
- sw x18, 15 * WORD_SIZE( sp )\r
- sw x19, 16 * WORD_SIZE( sp )\r
- sw x20, 17 * WORD_SIZE( sp )\r
- sw x21, 18 * WORD_SIZE( sp )\r
- sw x22, 19 * WORD_SIZE( sp )\r
- sw x23, 20 * WORD_SIZE( sp )\r
- sw x24, 21 * WORD_SIZE( sp )\r
- sw x25, 22 * WORD_SIZE( sp )\r
- sw x26, 23 * WORD_SIZE( sp )\r
- sw x27, 24 * WORD_SIZE( sp )\r
- sw x28, 25 * WORD_SIZE( sp )\r
- sw x29, 26 * WORD_SIZE( sp )\r
- sw x30, 27 * WORD_SIZE( sp )\r
- sw x31, 28 * WORD_SIZE( sp )\r
-\r
- csrr t0, mstatus /* Required for MPIE bit. */\r
- sw t0, 29 * WORD_SIZE( sp )\r
-\r
- lw t0, pxCurrentTCB /* Load pxCurrentTCB. */\r
- sw sp, 0( t0 ) /* Write sp to first TCB member. */\r
+ lw t0, pxCurrentTCB /* Load pxCurrentTCB. */\r
+ sw sp, 0( t0 ) /* Write sp to first TCB member. */\r
\r
csrr a0, mcause\r
csrr a1, mepc\r
- mv a2, sp\r
\r
-test_if_environment_call:\r
- li t0, 11 /* 11 == environment call when using qemu. */\r
- bne a0, t0, test_if_timer\r
- addi a1, a1, 4 /* Synchronous so return to the instruction after the environment call. */\r
- sw a1, 0( sp ) /* Save updated exception return address. */\r
-/*_RB_ Does stack need aligning here? */\r
- jal vTaskSwitchContext\r
+test_if_asynchronous:\r
+ srli a2, a0, 0x1f /* MSB of mcause is 1 if handing an asynchronous interrupt - shift to LSB to clear other bits. */\r
+ beq a2, x0, handle_synchronous /* Branch past interrupt handing if not asynchronous. */\r
+ sw a1, 0( sp ) /* Asynch so save unmodified exception return address. */\r
+\r
+handle_asynchronous:\r
+\r
+#if( portasmHAS_CLINT != 0 )\r
+\r
+ test_if_mtimer: /* If there is a CLINT then the mtimer is used to generate the tick interrupt. */\r
+ lui t0, 0x80000\r
+ addi t1, t0, 7 /* 0x80000007 == machine timer interrupt. */\r
+ bne a0, t1, test_if_external_interrupt\r
+\r
+ lw t0, pullMachineTimerCompareRegister /* Load address of compare register into t0. */\r
+ lw t1, pullNextTime /* Load the address of ullNextTime into t1. */\r
+ lw t2, 0(t1) /* Load the low word of ullNextTime into t2. */\r
+ lw t3, 4(t1) /* Load the high word of ullNextTime into t3. */\r
+ sw t2, 0(t0) /* Store low word of ullNextTime into compare register. */\r
+ sw t3, 4(t0) /* Store high word of ullNextTime into compare register. */\r
+ lw t0, ulTimerIncrementsForOneTick /* Load the value of ullTimerIncrementForOneTick into t0 (could this be optimized by storing in an array next to pullNextTime?). */\r
+ add t4, t0, t2 /* Add the low word of ullNextTime to the timer increments for one tick (assumes timer increment for one tick fits in 32-bits. */\r
+ sltu t5, t4, t2 /* See if the sum of low words overflowed (what about the zero case?). */\r
+ add t6, t3, t5 /* Add overflow to high word of ullNextTime. */\r
+ sw t4, 0(t1) /* Store new low word of ullNextTime. */\r
+ sw t6, 4(t1) /* Store new high word of ullNextTime. */\r
+ lw sp, xISRStackTop /* Switch to ISR stack before function call. */\r
+ jal xTaskIncrementTick\r
+ beqz a0, processed_source /* Don't switch context if incrementing tick didn't unblock a task. */\r
+ jal vTaskSwitchContext\r
+ j processed_source\r
+\r
+ test_if_external_interrupt: /* If there is a CLINT and the mtimer interrupt is not pending then check to see if an external interrupt is pending. */\r
+ addi t1, t1, 4 /* 0x80000007 + 4 = 0x8000000b == Machine external interrupt. */\r
+ bne a0, t1, as_yet_unhandled /* Something as yet unhandled. */\r
+\r
+#endif /* portasmHAS_CLINT */\r
+\r
+ lw sp, xISRStackTop /* Switch to ISR stack before function call. */\r
+ jal portasmHANDLE_INTERRUPT /* Jump to the interrupt handler if there is no CLINT or if there is a CLINT and it has been determined that an external interrupt is pending. */\r
j processed_source\r
\r
+handle_synchronous:\r
+ addi a1, a1, 4 /* Synchronous so updated exception return address to the instruction after the instruction that generated the exeption. */\r
+ sw a1, 0( sp ) /* Save updated exception return address. */\r
\r
-test_if_timer:\r
- sw a1, 0( sp ) /* Asynch so save unmodified exception return address. */\r
-\r
- lui t0, 0x80000\r
- addi t1,t0, 7 /* 0x80000007 == machine timer interrupt. */\r
- bne a0, t1, as_yet_unhandled\r
-\r
- lw t0, pullMachineTimerCompareRegister /* Load address of compare register into t0. */\r
- lw t1, pullNextTime /* Load the address of ullNextTime into t1. */\r
- lw t2, 0(t1) /* Load the low word of ullNextTime into t2. */\r
- lw t3, 4(t1) /* Load the high word of ullNextTime into t3. */\r
- sw t2, 0(t0) /* Store low word of ullNextTime into compare register. */\r
- sw t3, 4(t0) /* Store high word of ullNextTime into compare register. */\r
- lw t0, ulTimerIncrementsForOneTick /* Load the value of ullTimerIncrementForOneTick into t0 (could this be optimized by storing in an array next to pullNextTime?). */\r
- add t4, t0, t2 /* Add the low word of ullNextTime to the timer increments for one tick (assumes timer increment for one tick fits in 32-bits. */\r
- sltu t5, t4, t2 /* See if the sum of low words overflowed (what about the zero case?). */\r
- add t6, t3, t5 /* Add overflow to high word of ullNextTime. */\r
- sw t4, 0(t1) /* Store new low word of ullNextTime. */\r
- sw t6, 4(t1) /* Store new high word of ullNextTime. */\r
- jal xTaskIncrementTick\r
- beqz a0, processed_source /* Don't switch context if incrementing tick didn't unblock a task. */\r
+test_if_environment_call:\r
+ li t0, 11 /* 11 == environment call. */\r
+ bne a0, t0, is_exception /* Not an M environment call, so some other exception. */\r
+ lw sp, xISRStackTop /* Switch to ISR stack before function call. */\r
jal vTaskSwitchContext\r
j processed_source\r
\r
+is_exception:\r
+ ebreak\r
+ j is_exception\r
+\r
as_yet_unhandled:\r
- j as_yet_unhandled /* External interrupt? */\r
+ ebreak\r
+ j as_yet_unhandled\r
\r
processed_source:\r
- lw sp, pxCurrentTCB /* Load pxCurrentTCB. */\r
- lw sp, 0( sp ) /* Read sp from first TCB member. */\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 * WORD_SIZE( sp )\r
- csrw mstatus, t0 /* Required for MPIE bit. */\r
-\r
- lw x1, 1 * WORD_SIZE( sp )\r
- lw x5, 2 * WORD_SIZE( sp ) /* t0 */\r
- lw x6, 3 * WORD_SIZE( sp ) /* t1 */\r
- lw x7, 4 * WORD_SIZE( sp ) /* t2 */\r
- lw x8, 5 * WORD_SIZE( sp ) /* s0/fp */\r
- lw x9, 6 * WORD_SIZE( sp ) /* s1 */\r
- lw x10, 7 * WORD_SIZE( sp ) /* a0 */\r
- lw x11, 8 * WORD_SIZE( sp ) /* a1 */\r
- lw x12, 9 * WORD_SIZE( sp ) /* a2 */\r
- lw x13, 10 * WORD_SIZE( sp ) /* a3 */\r
- lw x14, 11 * WORD_SIZE( sp ) /* a4 */\r
- lw x15, 12 * WORD_SIZE( sp ) /* a5 */\r
- lw x16, 13 * WORD_SIZE( sp ) /* a6 */\r
- lw x17, 14 * WORD_SIZE( sp ) /* a7 */\r
- lw x18, 15 * WORD_SIZE( sp ) /* s2 */\r
- lw x19, 16 * WORD_SIZE( sp ) /* s3 */\r
- lw x20, 17 * WORD_SIZE( sp ) /* s4 */\r
- lw x21, 18 * WORD_SIZE( sp ) /* s5 */\r
- lw x22, 19 * WORD_SIZE( sp ) /* s6 */\r
- lw x23, 20 * WORD_SIZE( sp ) /* s7 */\r
- lw x24, 21 * WORD_SIZE( sp ) /* s8 */\r
- lw x25, 22 * WORD_SIZE( sp ) /* s9 */\r
- lw x26, 23 * WORD_SIZE( sp ) /* s10 */\r
- lw x27, 24 * WORD_SIZE( sp ) /* s11 */\r
- lw x28, 25 * WORD_SIZE( sp ) /* t3 */\r
- lw x29, 26 * WORD_SIZE( sp ) /* t4 */\r
- lw x30, 27 * WORD_SIZE( sp ) /* t5 */\r
- lw x31, 28 * WORD_SIZE( sp ) /* t6 */\r
- addi sp, sp, CONTEXT_SIZE\r
+ lw t0, 29 * portWORD_SIZE( sp )\r
+ csrw mstatus, t0 /* Required for MPIE bit. */\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 x7, 4 * portWORD_SIZE( sp ) /* t2 */\r
+ lw x8, 5 * portWORD_SIZE( sp ) /* s0/fp */\r
+ lw x9, 6 * portWORD_SIZE( sp ) /* s1 */\r
+ lw x10, 7 * portWORD_SIZE( sp ) /* a0 */\r
+ lw x11, 8 * portWORD_SIZE( sp ) /* a1 */\r
+ lw x12, 9 * portWORD_SIZE( sp ) /* a2 */\r
+ lw x13, 10 * portWORD_SIZE( sp ) /* a3 */\r
+ lw x14, 11 * portWORD_SIZE( sp ) /* a4 */\r
+ lw x15, 12 * portWORD_SIZE( sp ) /* a5 */\r
+ lw x16, 13 * portWORD_SIZE( sp ) /* a6 */\r
+ lw x17, 14 * portWORD_SIZE( sp ) /* a7 */\r
+ lw x18, 15 * portWORD_SIZE( sp ) /* s2 */\r
+ lw x19, 16 * portWORD_SIZE( sp ) /* s3 */\r
+ lw x20, 17 * portWORD_SIZE( sp ) /* s4 */\r
+ lw x21, 18 * portWORD_SIZE( sp ) /* s5 */\r
+ lw x22, 19 * portWORD_SIZE( sp ) /* s6 */\r
+ lw x23, 20 * portWORD_SIZE( sp ) /* s7 */\r
+ lw x24, 21 * portWORD_SIZE( sp ) /* s8 */\r
+ lw x25, 22 * portWORD_SIZE( sp ) /* s9 */\r
+ lw x26, 23 * portWORD_SIZE( sp ) /* s10 */\r
+ lw x27, 24 * portWORD_SIZE( sp ) /* s11 */\r
+ lw x28, 25 * portWORD_SIZE( sp ) /* t3 */\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
\r
mret\r
+ .endfunc\r
+/*-----------------------------------------------------------*/\r
+\r
+.align 8\r
+.func\r
+xPortStartFirstTask:\r
+\r
+#if( portasmHAS_CLINT != 0 )\r
+ /* If there is a clint then interrupts can branch directly to the FreeRTOS\r
+ trap handler. Otherwise the interrupt controller will need to be configured\r
+ outside of this file. */\r
+ la t0, vFreeRTOSPortTrapHandler\r
+ csrw mtvec, t0\r
+#endif /* portasmHAS_CLILNT */\r
+\r
+ lw sp, pxCurrentTCB /* Load pxCurrentTCB. */\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 x8, 5 * portWORD_SIZE( sp ) /* s0/fp */\r
+ lw x9, 6 * portWORD_SIZE( sp ) /* s1 */\r
+ lw x10, 7 * portWORD_SIZE( sp ) /* a0 */\r
+ lw x11, 8 * portWORD_SIZE( sp ) /* a1 */\r
+ lw x12, 9 * portWORD_SIZE( sp ) /* a2 */\r
+ lw x13, 10 * portWORD_SIZE( sp ) /* a3 */\r
+ lw x14, 11 * portWORD_SIZE( sp ) /* a4 */\r
+ lw x15, 12 * portWORD_SIZE( sp ) /* a5 */\r
+ lw x16, 13 * portWORD_SIZE( sp ) /* a6 */\r
+ lw x17, 14 * portWORD_SIZE( sp ) /* a7 */\r
+ lw x18, 15 * portWORD_SIZE( sp ) /* s2 */\r
+ lw x19, 16 * portWORD_SIZE( sp ) /* s3 */\r
+ lw x20, 17 * portWORD_SIZE( sp ) /* s4 */\r
+ lw x21, 18 * portWORD_SIZE( sp ) /* s5 */\r
+ lw x22, 19 * portWORD_SIZE( sp ) /* s6 */\r
+ lw x23, 20 * portWORD_SIZE( sp ) /* s7 */\r
+ lw x24, 21 * portWORD_SIZE( sp ) /* s8 */\r
+ lw x25, 22 * portWORD_SIZE( sp ) /* s9 */\r
+ lw x26, 23 * portWORD_SIZE( sp ) /* s10 */\r
+ lw x27, 24 * portWORD_SIZE( sp ) /* s11 */\r
+ lw x28, 25 * portWORD_SIZE( sp ) /* t3 */\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
+ ret\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