]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS/Source/portable/GCC/RISC-V-RV32/portASM.S
Move the RISC-V pxPortInitialiseStack() implementation to the assembly port file...
[freertos] / FreeRTOS / Source / portable / GCC / RISC-V-RV32 / portASM.S
index 5f6c3a10ed8db94f5040a120426351f931e42e55..12cc49b4d06526d5379c951406b5c90657ea8c94 100644 (file)
@@ -6,9 +6,7 @@
  * 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