RISC-V: Add support for RV32E extension in GCC port (#543)

Co-authored-by: Joseph Julicher <jjulicher@mac.com>
diff --git a/portable/GCC/RISC-V/portASM.S b/portable/GCC/RISC-V/portASM.S
index 58dfaf9..57e9820 100644
--- a/portable/GCC/RISC-V/portASM.S
+++ b/portable/GCC/RISC-V/portASM.S
@@ -98,35 +98,35 @@
 /*-----------------------------------------------------------*/
 
 .macro portUPDATE_MTIMER_COMPARE_REGISTER
-    load_x t0, pullMachineTimerCompareRegister  /* Load address of compare register into t0. */
-    load_x t1, pullNextTime                     /* Load the address of ullNextTime into t1. */
+    load_x a0, pullMachineTimerCompareRegister  /* Load address of compare register into a0. */
+    load_x a1, pullNextTime                     /* Load the address of ullNextTime into a1. */
 
     #if( __riscv_xlen == 32 )
 
         /* Update the 64-bit mtimer compare match value in two 32-bit writes. */
-        li t4, -1
-        lw t2, 0(t1)                /* Load the low word of ullNextTime into t2. */
-        lw t3, 4(t1)                /* Load the high word of ullNextTime into t3. */
-        sw t4, 0(t0)                /* Low word no smaller than old value to start with - will be overwritten below. */
-        sw t3, 4(t0)                /* Store high word of ullNextTime into compare register.  No smaller than new value. */
-        sw t2, 0(t0)                /* Store low word of ullNextTime into compare register. */
+        li a4, -1
+        lw a2, 0(a1)                /* Load the low word of ullNextTime into a2. */
+        lw a3, 4(a1)                /* Load the high word of ullNextTime into a3. */
+        sw a4, 0(a0)                /* Low word no smaller than old value to start with - will be overwritten below. */
+        sw a3, 4(a0)                /* Store high word of ullNextTime into compare register.  No smaller than new value. */
+        sw a2, 0(a0)                /* Store low word of ullNextTime into compare register. */
         lw t0, uxTimerIncrementsForOneTick  /* Load the value of ullTimerIncrementForOneTick into t0 (could this be optimized by storing in an array next to pullNextTime?). */
-        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). */
-        sltu t5, t4, t2             /* See if the sum of low words overflowed (what about the zero case?). */
-        add t6, t3, t5              /* Add overflow to high word of ullNextTime. */
-        sw t4, 0(t1)                /* Store new low word of ullNextTime. */
-        sw t6, 4(t1)                /* Store new high word of ullNextTime. */
+        add a4, t0, a2              /* Add the low word of ullNextTime to the timer increments for one tick (assumes timer increment for one tick fits in 32-bits). */
+        sltu t1, a4, a2             /* See if the sum of low words overflowed (what about the zero case?). */
+        add t2, a3, t1              /* Add overflow to high word of ullNextTime. */
+        sw a4, 0(a1)                /* Store new low word of ullNextTime. */
+        sw t2, 4(a1)                /* Store new high word of ullNextTime. */
 
     #endif /* __riscv_xlen == 32 */
 
     #if( __riscv_xlen == 64 )
 
         /* Update the 64-bit mtimer compare match value. */
-        ld t2, 0(t1)                /* Load ullNextTime into t2. */
-        sd t2, 0(t0)                /* Store ullNextTime into compare register. */
+        ld t2, 0(a1)                /* Load ullNextTime into t2. */
+        sd t2, 0(a0)                /* Store ullNextTime into compare register. */
         ld t0, uxTimerIncrementsForOneTick  /* Load the value of ullTimerIncrementForOneTick into t0 (could this be optimized by storing in an array next to pullNextTime?). */
         add t4, t0, t2              /* Add ullNextTime to the timer increments for one tick. */
-        sd t4, 0(t1)                /* Store ullNextTime. */
+        sd t4, 0(a1)                /* Store ullNextTime. */
 
     #endif /* __riscv_xlen == 64 */
     .endm
@@ -206,7 +206,12 @@
     store_x t0, 0(a0)                   /* mstatus onto the stack. */
     addi a0, a0, -portWORD_SIZE         /* Space for critical nesting count. */
     store_x x0, 0(a0)                   /* Critical nesting count starts at 0 for every task. */
+
+#ifdef __riscv_32e
+    addi a0, a0, -(6 * portWORD_SIZE)   /* Space for registers x11-x15. */
+#else
     addi a0, a0, -(22 * portWORD_SIZE)  /* Space for registers x11-x31. */
+#endif
     store_x a2, 0(a0)                   /* Task parameters (pvParameters parameter) goes into register X10/a0 on the stack. */
     addi a0, a0, -(6 * portWORD_SIZE)   /* Space for registers x5-x9. */
     load_x t0, xTaskReturnAddress
@@ -241,6 +246,7 @@
     load_x  x13, 10 * portWORD_SIZE( sp )   /* a3 */
     load_x  x14, 11 * portWORD_SIZE( sp )   /* a4 */
     load_x  x15, 12 * portWORD_SIZE( sp )   /* a5 */
+#ifndef __riscv_32e
     load_x  x16, 13 * portWORD_SIZE( sp )   /* a6 */
     load_x  x17, 14 * portWORD_SIZE( sp )   /* a7 */
     load_x  x18, 15 * portWORD_SIZE( sp )   /* s2 */
@@ -257,12 +263,13 @@
     load_x  x29, 26 * portWORD_SIZE( sp )   /* t4 */
     load_x  x30, 27 * portWORD_SIZE( sp )   /* t5 */
     load_x  x31, 28 * portWORD_SIZE( sp )   /* t6 */
+#endif
 
-    load_x  x5, 29 * portWORD_SIZE( sp )    /* Obtain xCriticalNesting value for this task from task's stack. */
+    load_x  x5, portCRITICAL_NESTING_OFFSET * portWORD_SIZE( sp )    /* Obtain xCriticalNesting value for this task from task's stack. */
     load_x  x6, pxCriticalNesting           /* Load the address of xCriticalNesting into x6. */
     store_x x5, 0( x6 )                     /* Restore the critical nesting value for this task. */
 
-    load_x  x5, 30 * portWORD_SIZE( sp )    /* Initial mstatus into x5 (t0). */
+    load_x  x5, portMSTATUS_OFFSET * portWORD_SIZE( sp )    /* Initial mstatus into x5 (t0). */
     addi    x5, x5, 0x08                    /* Set MIE bit so the first task starts with interrupts enabled - required as returns with ret not eret. */
     csrrw   x0, mstatus, x5                 /* Interrupts enabled from here! */
 
diff --git a/portable/GCC/RISC-V/portContext.h b/portable/GCC/RISC-V/portContext.h
index 757654b..c7eeeec 100644
--- a/portable/GCC/RISC-V/portContext.h
+++ b/portable/GCC/RISC-V/portContext.h
@@ -48,7 +48,16 @@
  * portasmRESTORE_ADDITIONAL_REGISTERS macros - which can be defined in a chip
  * specific version of freertos_risc_v_chip_specific_extensions.h.  See the
  * notes at the top of portASM.S file. */
-#define portCONTEXT_SIZE ( 31 * portWORD_SIZE )
+#ifdef __riscv_32e
+    #define portCONTEXT_SIZE ( 15 * portWORD_SIZE )
+    #define portCRITICAL_NESTING_OFFSET 13
+    #define portMSTATUS_OFFSET  14
+#else
+    #define portCONTEXT_SIZE ( 31 * portWORD_SIZE )
+    #define portCRITICAL_NESTING_OFFSET 29
+    #define portMSTATUS_OFFSET  30
+#endif
+
 /*-----------------------------------------------------------*/
 
 .extern pxCurrentTCB
@@ -71,6 +80,7 @@
     store_x x13, 10 * portWORD_SIZE( sp )
     store_x x14, 11 * portWORD_SIZE( sp )
     store_x x15, 12 * portWORD_SIZE( sp )
+#ifndef __riscv_32e
     store_x x16, 13 * portWORD_SIZE( sp )
     store_x x17, 14 * portWORD_SIZE( sp )
     store_x x18, 15 * portWORD_SIZE( sp )
@@ -87,12 +97,15 @@
     store_x x29, 26 * portWORD_SIZE( sp )
     store_x x30, 27 * portWORD_SIZE( sp )
     store_x x31, 28 * portWORD_SIZE( sp )
+#endif
 
     load_x  t0, xCriticalNesting         /* Load the value of xCriticalNesting into t0. */
-    store_x t0, 29 * portWORD_SIZE( sp ) /* Store the critical nesting value to the stack. */
+    store_x t0, portCRITICAL_NESTING_OFFSET * portWORD_SIZE( sp ) /* Store the critical nesting value to the stack. */
+
 
     csrr t0, mstatus                     /* Required for MPIE bit. */
-    store_x t0, 30 * portWORD_SIZE( sp )
+    store_x t0, portMSTATUS_OFFSET * portWORD_SIZE( sp )
+
 
     portasmSAVE_ADDITIONAL_REGISTERS     /* Defined in freertos_risc_v_chip_specific_extensions.h to save any registers unique to the RISC-V implementation. */
 
@@ -133,10 +146,10 @@
     portasmRESTORE_ADDITIONAL_REGISTERS
 
     /* Load mstatus with the interrupt enable bits used by the task. */
-    load_x  t0, 30 * portWORD_SIZE( sp )
+    load_x  t0, portMSTATUS_OFFSET * portWORD_SIZE( sp )
     csrw mstatus, t0                        /* Required for MPIE bit. */
 
-    load_x  t0, 29 * portWORD_SIZE( sp )    /* Obtain xCriticalNesting value for this task from task's stack. */
+    load_x  t0, portCRITICAL_NESTING_OFFSET * portWORD_SIZE( sp )    /* Obtain xCriticalNesting value for this task from task's stack. */
     load_x  t1, pxCriticalNesting           /* Load the address of xCriticalNesting into t1. */
     store_x t0, 0( t1 )                     /* Restore the critical nesting value for this task. */
 
@@ -152,6 +165,7 @@
     load_x  x13, 10 * portWORD_SIZE( sp )
     load_x  x14, 11 * portWORD_SIZE( sp )
     load_x  x15, 12 * portWORD_SIZE( sp )
+#ifndef __riscv_32e
     load_x  x16, 13 * portWORD_SIZE( sp )
     load_x  x17, 14 * portWORD_SIZE( sp )
     load_x  x18, 15 * portWORD_SIZE( sp )
@@ -168,6 +182,7 @@
     load_x  x29, 26 * portWORD_SIZE( sp )
     load_x  x30, 27 * portWORD_SIZE( sp )
     load_x  x31, 28 * portWORD_SIZE( sp )
+#endif
     addi sp, sp, portCONTEXT_SIZE
 
     mret
diff --git a/portable/GCC/RISC-V/portmacro.h b/portable/GCC/RISC-V/portmacro.h
index 8379782..76b7c92 100644
--- a/portable/GCC/RISC-V/portmacro.h
+++ b/portable/GCC/RISC-V/portmacro.h
@@ -80,7 +80,11 @@
 /* Architecture specifics. */

 #define portSTACK_GROWTH            ( -1 )

 #define portTICK_PERIOD_MS          ( ( TickType_t ) 1000 / configTICK_RATE_HZ )

-#define portBYTE_ALIGNMENT          16

+#ifdef __riscv_32e

+    #define portBYTE_ALIGNMENT      8   /* RV32E uses RISC-V EABI with reduced stack alignment requirements */

+#else

+    #define portBYTE_ALIGNMENT      16

+#endif

 /*-----------------------------------------------------------*/

 

 /* Scheduler utilities. */