Add IAR RISC-V 32 Embedded Extension Support (#588)
Adds RV32E support to the IAR port. This is done by
reducing our register usage to the first 16 registers
only.
Influenced by changes in https://github.com/FreeRTOS/FreeRTOS-Kernel/pull/543
Signed-off-by: Gaurav Aggarwal <aggarg@amazon.com>
Co-authored-by: Gaurav Aggarwal <aggarg@amazon.com>
diff --git a/portable/GCC/RISC-V/portASM.S b/portable/GCC/RISC-V/portASM.S
index 57e9820..9dde71f 100644
--- a/portable/GCC/RISC-V/portASM.S
+++ b/portable/GCC/RISC-V/portASM.S
@@ -208,12 +208,12 @@
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. */
+ addi a0, a0, -(6 * portWORD_SIZE) /* Space for registers x10-x15. */
#else
- addi a0, a0, -(22 * portWORD_SIZE) /* Space for registers x11-x31. */
+ addi a0, a0, -(22 * portWORD_SIZE) /* Space for registers x10-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. */
+ addi a0, a0, -(6 * portWORD_SIZE) /* Space for registers x5-x9 + taskReturnAddress. */
load_x t0, xTaskReturnAddress
store_x t0, 0(a0) /* Return address onto the stack. */
addi t0, x0, portasmADDITIONAL_CONTEXT_SIZE /* The number of chip specific additional registers. */
diff --git a/portable/IAR/RISC-V/portASM.s b/portable/IAR/RISC-V/portASM.s
index 1364644..1a7d1c4 100644
--- a/portable/IAR/RISC-V/portASM.s
+++ b/portable/IAR/RISC-V/portASM.s
@@ -107,35 +107,35 @@
CODE
portUPDATE_MTIMER_COMPARE_REGISTER MACRO
- 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
@@ -205,7 +205,7 @@
* pxCode
*/
pxPortInitialiseStack:
- csrr t0, CSR_MSTATUS /* Obtain current mstatus value. */
+ csrr t0, CSR_MSTATUS /* Obtain current mstatus value. */
andi t0, t0, ~0x8 /* Ensure interrupts are disabled when the stack is restored within an ISR. Required when a task is created after the schedulre has been started, otherwise interrupts would be disabled anyway. */
addi t1, x0, 0x188 /* Generate the value 0x1880, which are the MPIE and MPP bits to set in mstatus. */
slli t1, t1, 4
@@ -215,9 +215,13 @@
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. */
- addi a0, a0, -(22 * portWORD_SIZE) /* Space for registers x11-x31. */
+#ifdef __riscv_32e
+ addi a0, a0, -(6 * portWORD_SIZE) /* Space for registers x10-15. */
+#else
+ addi a0, a0, -(22 * portWORD_SIZE) /* Space for registers x10-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. */
+ addi a0, a0, -(6 * portWORD_SIZE) /* Space for registers x5-x9 + taskReturnAddress. */
load_x t0, xTaskReturnAddress
store_x t0, 0(a0) /* Return address onto the stack. */
addi t0, x0, portasmADDITIONAL_CONTEXT_SIZE /* The number of chip specific additional registers. */
@@ -250,6 +254,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 */
@@ -266,12 +271,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, CSR_MSTATUS, x5 /* Interrupts enabled from here! */
diff --git a/portable/IAR/RISC-V/portContext.h b/portable/IAR/RISC-V/portContext.h
index 8b883c8..b8f8958 100644
--- a/portable/IAR/RISC-V/portContext.h
+++ b/portable/IAR/RISC-V/portContext.h
@@ -48,7 +48,15 @@
* 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
EXTERN xISRStackTop
@@ -71,6 +79,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 +96,13 @@
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. */
@@ -123,7 +133,7 @@
portcontextRESTORE_CONTEXT MACRO
load_x t1, pxCurrentTCB /* Load pxCurrentTCB. */
- load_x sp, 0( t1 ) /* Read sp from first TCB member. */
+ load_x sp, 0( t1 ) /* Read sp from first TCB member. */
/* Load mepc with the address of the instruction in the task to run next. */
load_x t0, 0( sp )
@@ -133,10 +143,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 +162,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 +179,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/IAR/RISC-V/portmacro.h b/portable/IAR/RISC-V/portmacro.h
index 50e03e2..7aab094 100644
--- a/portable/IAR/RISC-V/portmacro.h
+++ b/portable/IAR/RISC-V/portmacro.h
@@ -82,7 +82,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. */