Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RISC-V Nested Interrupt Support #366

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions portable/GCC/RISC-V/port.c
Expand Up @@ -95,6 +95,10 @@ const size_t uxTimerIncrementsForOneTick = ( size_t ) ( ( configCPU_CLOCK_HZ ) /
uint32_t const ullMachineTimerCompareRegisterBase = configMTIMECMP_BASE_ADDRESS;
volatile uint64_t * pullMachineTimerCompareRegister = NULL;

/* Counts the number of times the interrupt service routine was entered, but not
exited. Used for interrupt nesting and xPortIsInsideInterrupt(). */
uint32_t ulIsrEnterCount = 0;

/* Set configCHECK_FOR_STACK_OVERFLOW to 3 to add ISR stack checking to task
stack checking. A problem in the ISR stack will trigger an assert, not call the
stack overflow hook function (because the stack overflow hook is specific to a
Expand Down
36 changes: 24 additions & 12 deletions portable/GCC/RISC-V/portASM.S
Expand Up @@ -114,6 +114,7 @@ at the top of this file. */
.extern uxTimerIncrementsForOneTick /* size_t type so 32-bit on 32-bit core and 64-bits on 64-bit core. */
.extern xISRStackTop
.extern portasmHANDLE_INTERRUPT
.extern ulIsrEnterCount

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

Expand Down Expand Up @@ -155,17 +156,28 @@ freertos_risc_v_trap_handler:

portasmSAVE_ADDITIONAL_REGISTERS /* Defined in freertos_risc_v_chip_specific_extensions.h to save any registers unique to the RISC-V implementation. */

load_x t0, pxCurrentTCB /* Load pxCurrentTCB. */
store_x sp, 0( t0 ) /* Write sp to first TCB member. */

csrr a0, mcause
csrr a1, mepc

test_if_asynchronous:
srli a2, a0, __riscv_xlen - 1 /* MSB of mcause is 1 if handing an asynchronous interrupt - shift to LSB to clear other bits. */
beq a2, x0, handle_synchronous /* Branch past interrupt handing if not asynchronous. */
bltz a0, 1f /* MSB is set for async, i.e. it is negative. */
addi a1, a1, 4 /* Synchronous so updated exception return address to the instruction after the instruction that generated the exeption. */
1:
store_x a1, 0( sp ) /* Asynch so save unmodified exception return address. */

/* ulIsrEnterCount++: */
la t0, ulIsrEnterCount /* t0 = &ulIsrEnterCount */
lw t1, 0(t0) /* t1 = *t0 */
addi t2, t1, 1 /* t2 = t1 + 1 */
sw t2, 0(t0) /* *t0 = t2 */
bnez t1, 2f /* If the interrupt is not nesting: */
load_x t0, pxCurrentTCB /* Load pxCurrentTCB. */
store_x sp, 0( t0 ) /* Write sp to first TCB member. */
load_x sp, xISRStackTop /* Switch to ISR stack before function call. */
2:
bgez a0, handle_synchronous /* Branch past interrupt handing if not asynchronous. */


handle_asynchronous:

#if( portasmHAS_MTIME != 0 )
Expand Down Expand Up @@ -210,7 +222,6 @@ handle_asynchronous:

#endif /* __riscv_xlen == 64 */

load_x sp, xISRStackTop /* Switch to ISR stack before function call. */
jal xTaskIncrementTick
beqz a0, processed_source /* Don't switch context if incrementing tick didn't unblock a task. */
jal vTaskSwitchContext
Expand All @@ -222,18 +233,13 @@ handle_asynchronous:

#endif /* portasmHAS_MTIME */

load_x sp, xISRStackTop /* Switch to ISR stack before function call. */
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. */
j processed_source

handle_synchronous:
addi a1, a1, 4 /* Synchronous so updated exception return address to the instruction after the instruction that generated the exeption. */
store_x a1, 0( sp ) /* Save updated exception return address. */

test_if_environment_call:
li t0, 11 /* 11 == environment call. */
bne a0, t0, is_exception /* Not an M environment call, so some other exception. */
load_x sp, xISRStackTop /* Switch to ISR stack before function call. */
jal vTaskSwitchContext
j processed_source

Expand All @@ -248,9 +254,15 @@ as_yet_unhandled:
j as_yet_unhandled

processed_source:
/* ulIsrEnterCount--: */
la t0, ulIsrEnterCount /* t0 = &ulIsrEnterCount */
lw t1, 0(t0) /* t1 = *t0 */
addi t1, t1, -1 /* t1-- */
sw t1, 0(t0) /* *t0 = t1 */
bnez t1, 1f /* If we are going to exit from ISR on the last (or only) nesting level: */
load_x t1, pxCurrentTCB /* Load pxCurrentTCB. */
load_x sp, 0( t1 ) /* Read sp from first TCB member. */

1:
/* Load mret with the address of the next instruction in the task to run next. */
load_x t0, 0( sp )
csrw mepc, t0
Expand Down
5 changes: 5 additions & 0 deletions portable/GCC/RISC-V/portmacro.h
Expand Up @@ -34,6 +34,8 @@
extern "C" {
#endif

#include <stdint.h>

/*-----------------------------------------------------------
* Port specific definitions.
*
Expand Down Expand Up @@ -95,6 +97,9 @@ extern void vTaskSwitchContext( void );
#define portYIELD() __asm volatile( "ecall" );
#define portEND_SWITCHING_ISR( xSwitchRequired ) do { if( xSwitchRequired ) vTaskSwitchContext(); } while( 0 )
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )

extern uint32_t ulIsrEnterCount;
#define xPortIsInsideInterrupt() (ulIsrEnterCount > 0)
/*-----------------------------------------------------------*/


Expand Down