summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAkif Ejaz <[email protected]>2026-01-26 15:48:46 +0500
committerAkif Ejaz <[email protected]>2026-01-26 15:48:46 +0500
commit6c25effb405cc694578dec664a798fc8af3107e1 (patch)
tree36987ae1933ee659014c74942b318e2ca473c7e7
parent12dac1d67d0dfe1c06f839ee285e190c759865a7 (diff)
improve port robustness, portability, and CSR handling
- removed tx_port.h dependency from .S files - replaced tx_timer_interrupt.c with tx_timer_interrupt.S - made some cleanups, formatting to better readability - removed macros (LOAD/STORE/REGBYTES) changed register nomenclature to use RISC-V ABI names (ra, sp, t0, etc.) - added readme_threadx.txt Signed-off-by: Akif Ejaz <[email protected]>
-rw-r--r--ports/risc-v64/gnu/CMakeLists.txt2
-rw-r--r--ports/risc-v64/gnu/inc/tx_port.h52
-rw-r--r--ports/risc-v64/gnu/readme_threadx.txt430
-rw-r--r--ports/risc-v64/gnu/src/tx_initialize_low_level.S66
-rw-r--r--ports/risc-v64/gnu/src/tx_thread_context_restore.S425
-rw-r--r--ports/risc-v64/gnu/src/tx_thread_context_save.S367
-rw-r--r--ports/risc-v64/gnu/src/tx_thread_interrupt_control.S22
-rw-r--r--ports/risc-v64/gnu/src/tx_thread_schedule.S348
-rw-r--r--ports/risc-v64/gnu/src/tx_thread_stack_build.S152
-rw-r--r--ports/risc-v64/gnu/src/tx_thread_system_return.S121
-rw-r--r--ports/risc-v64/gnu/src/tx_timer_interrupt.S210
-rw-r--r--ports/risc-v64/gnu/src/tx_timer_interrupt.c134
12 files changed, 1463 insertions, 866 deletions
diff --git a/ports/risc-v64/gnu/CMakeLists.txt b/ports/risc-v64/gnu/CMakeLists.txt
index b217065d..9357c697 100644
--- a/ports/risc-v64/gnu/CMakeLists.txt
+++ b/ports/risc-v64/gnu/CMakeLists.txt
@@ -9,7 +9,7 @@ target_sources(${PROJECT_NAME}
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_schedule.S
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_stack_build.S
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_system_return.S
- ${CMAKE_CURRENT_LIST_DIR}/src/tx_timer_interrupt.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/tx_timer_interrupt.S
# {{END_TARGET_SOURCES}}
)
diff --git a/ports/risc-v64/gnu/inc/tx_port.h b/ports/risc-v64/gnu/inc/tx_port.h
index 855ecf82..346083e5 100644
--- a/ports/risc-v64/gnu/inc/tx_port.h
+++ b/ports/risc-v64/gnu/inc/tx_port.h
@@ -53,26 +53,6 @@
#ifndef TX_PORT_H
#define TX_PORT_H
-#ifdef __ASSEMBLER__
-
-
-#if __riscv_xlen == 64
-# define SLL32 sllw
-# define STORE sd
-# define LOAD ld
-# define LWU lwu
-# define LOG_REGBYTES 3
-#else
-# define SLL32 sll
-# define STORE sw
-# define LOAD lw
-# define LWU lw
-# define LOG_REGBYTES 2
-#endif
-#define REGBYTES (1 << LOG_REGBYTES)
-
-#else /*not __ASSEMBLER__ */
-
/* Include for memset. */
#include <string.h>
@@ -86,10 +66,7 @@
alternately be defined on the command line. */
#include "tx_user.h"
-#endif
-
-
-/* Define compiler library include files. */
+#endif /* TX_INCLUDE_USER_DEFINE_FILE */
/* Define ThreadX basic types for this port. */
@@ -105,8 +82,6 @@ typedef unsigned long long ULONG64;
typedef short SHORT;
typedef unsigned short USHORT;
#define ULONG64_DEFINED
-#define ALIGN_TYPE_DEFINED
-#define ALIGN_TYPE ULONG64
@@ -253,25 +228,25 @@ typedef unsigned short USHORT;
is used to define a local function save area for the disable and restore
macros. */
-#ifdef TX_DISABLE_INLINE
+/* Expose helper used to perform an atomic read/modify/write of mstatus.
+ The helper composes and returns the posture per ThreadX contract. */
+UINT _tx_thread_interrupt_control(UINT new_posture);
-ULONG64 _tx_thread_interrupt_control(unsigned int new_posture);
+#ifdef TX_DISABLE_INLINE
-#define TX_INTERRUPT_SAVE_AREA register ULONG64 interrupt_save;
+#define TX_INTERRUPT_SAVE_AREA register UINT interrupt_save;
#define TX_DISABLE interrupt_save = _tx_thread_interrupt_control(TX_INT_DISABLE);
#define TX_RESTORE _tx_thread_interrupt_control(interrupt_save);
#else
-#define TX_INTERRUPT_SAVE_AREA ULONG64 interrupt_save;
-/* Atomically read mstatus into interrupt_save and clear bit 3 of mstatus. */
-#define TX_DISABLE {__asm__ ("csrrci %0, mstatus, 0x08" : "=r" (interrupt_save) : );};
-/* We only care about mstatus.mie (bit 3), so mask interrupt_save and write to mstatus. */
-#define TX_RESTORE {register ULONG64 __tempmask = interrupt_save & 0x08; \
- __asm__ ("csrrs x0, mstatus, %0 \n\t" : : "r" (__tempmask) : );};
+#define TX_INTERRUPT_SAVE_AREA register UINT interrupt_save;
-#endif
+#define TX_DISABLE interrupt_save = _tx_thread_interrupt_control(TX_INT_DISABLE);
+#define TX_RESTORE _tx_thread_interrupt_control(interrupt_save);
+
+#endif /* TX_DISABLE_INLINE */
/* Define the interrupt lockout macros for each ThreadX object. */
@@ -291,7 +266,6 @@ CHAR _tx_version_id[] =
"Copyright (c) 2024 Microsoft Corporation. * ThreadX RISC-V64/GNU Version 6.4.2 *";
#else
extern CHAR _tx_version_id[];
-#endif
+#endif /* TX_THREAD_INIT */
-#endif /*not __ASSEMBLER__ */
-#endif
+#endif /* TX_PORT_H */
diff --git a/ports/risc-v64/gnu/readme_threadx.txt b/ports/risc-v64/gnu/readme_threadx.txt
new file mode 100644
index 00000000..60854ecd
--- /dev/null
+++ b/ports/risc-v64/gnu/readme_threadx.txt
@@ -0,0 +1,430 @@
+ Eclipse Foundation's RTOS, ThreadX for RISC-V64
+
+ Using the GNU Tools
+
+
+1. Building the ThreadX run-time Library
+
+Prerequisites
+- Install a RISC-V64 bare-metal GNU toolchain with riscv64-unknown-elf prefix
+- Common source: https://github.com/riscv-collab/riscv-gnu-toolchain
+
+Verify the toolchain:
+ riscv64-unknown-elf-gcc --version
+ riscv64-unknown-elf-objdump --version
+
+CMake-based build (recommended)
+
+From the ThreadX top-level directory:
+
+ cmake -Bbuild -GNinja -DCMAKE_TOOLCHAIN_FILE=cmake/riscv64_gnu.cmake .
+ cmake --build ./build/
+
+This uses cmake/riscv64_gnu.cmake and ports/risc-v64/gnu/CMakeLists.txt to
+configure the cross-compiler flags and produce the ThreadX run-time library
+and example binaries.
+
+Example build script
+
+The example demonstration contains a build script. See:
+
+ ports/risc-v64/gnu/example_build/qemu_virt/build_libthreadx.sh
+
+This script builds the library and the demo application kernel.elf.
+
+
+2. Demonstration System (QEMU)
+
+The provided example is targeted at QEMU's virt platform. After building the
+example, the produced kernel.elf can be executed in QEMU:
+
+ qemu-system-riscv64 -nographic -smp 1 -bios none -m 128M -machine virt -kernel kernel.elf
+
+Typical QEMU features used:
+- Single-core CPU
+- UART serial console
+- PLIC (Platform-Level Interrupt Controller)
+- CLINT (Core-Local Interruptor) for timer
+
+
+3. System Initialization
+
+Entry Point
+
+The example startup code begins at the _start label in entry.s. This startup
+code performs hardware initialization including:
+- Check hart ID (only hart 0 continues; others enter WFI loop)
+- Zero general-purpose registers
+- Set up initial stack pointer
+- Clear BSS section
+- Jump to main()
+
+Low-Level Port Initialization (tx_initialize_low_level.S)
+
+The _tx_initialize_low_level function:
+- Saves the system stack pointer to _tx_thread_system_stack_ptr
+- Records first free RAM address from __tx_free_memory_start symbol
+- Initializes floating-point control/status register (FCSR) if floating point enabled
+
+Board Initialization (board.c)
+
+After tx_initialize_low_level returns, main() calls board_init() to:
+- Initialize PLIC (Platform-Level Interrupt Controller)
+- Initialize UART
+- Initialize hardware timer (CLINT)
+- Set trap vector (mtvec) to point to trap handler
+
+
+4. Register Usage and Stack Frames
+
+The RISC-V64 ABI defines t0-t6 and a0-a7 as caller-saved (scratch) registers.
+All other registers used by a function must be preserved by the function.
+
+ThreadX takes advantage of this: when a context switch happens during a
+function call, only the non-scratch registers need to be saved.
+
+Stack Frame Types
+
+Two types of stack frames exist:
+
+A. Interrupt Frame (stack type = 1)
+ Created when an interrupt occurs during thread execution.
+ Saves all registers including caller-saved registers.
+ Size: 65*8 = 520 bytes (with FP), or 32*8 = 256 bytes (without FP)
+
+B. Solicited Frame (stack type = 0)
+ Created when a thread voluntarily yields via ThreadX service calls.
+ Saves only callee-saved registers (s0-s11) and mstatus.
+ Size: 29*8 = 232 bytes (with FP), or 16*8 = 128 bytes (without FP)
+
+
+Stack Layout for Interrupt Frame (with FP enabled):
+
+ Index Offset Register Description
+ ─────────────────────────────────────────────────
+ 0 0x00 -- Stack type (1 = interrupt)
+ 1 0x08 s11 Preserved register
+ 2 0x10 s10 Preserved register
+ 3 0x18 s9 Preserved register
+ 4 0x20 s8 Preserved register
+ 5 0x28 s7 Preserved register
+ 6 0x30 s6 Preserved register
+ 7 0x38 s5 Preserved register
+ 8 0x40 s4 Preserved register
+ 9 0x48 s3 Preserved register
+ 10 0x50 s2 Preserved register
+ 11 0x58 s1 Preserved register
+ 12 0x60 s0 Preserved register
+ 13 0x68 t6 Scratch register
+ 14 0x70 t5 Scratch register
+ 15 0x78 t4 Scratch register
+ 16 0x80 t3 Scratch register
+ 17 0x88 t2 Scratch register
+ 18 0x90 t1 Scratch register
+ 19 0x98 t0 Scratch register
+ 20 0xA0 a7 Argument register
+ 21 0xA8 a6 Argument register
+ 22 0xB0 a5 Argument register
+ 23 0xB8 a4 Argument register
+ 24 0xC0 a3 Argument register
+ 25 0xC8 a2 Argument register
+ 26 0xD0 a1 Argument register
+ 27 0xD8 a0 Argument register
+ 28 0xE0 ra Return address
+ 29 0xE8 -- Reserved
+ 30 0xF0 mepc Machine exception PC
+ 31-46 0xF8-0x168 fs0-fs7 Preserved FP registers
+ 47-62 0x170-0x210 ft0-ft11 Scratch FP registers
+ 63 0x218 fcsr FP control/status register
+ ─────────────────────────────────────────────────
+
+
+5. Interrupt Handling
+
+Machine Mode Operation
+
+ThreadX operates in machine mode (M-mode), the highest privilege level.
+All interrupts and exceptions trap to machine mode.
+
+Interrupt Sources
+
+1. Machine Timer Interrupt (MTI):
+ - Triggered by CLINT when mtime >= mtimecmp
+ - Handled by _tx_timer_interrupt (src/tx_timer_interrupt.S)
+ - Called from trap handler in trap.c
+
+2. External Interrupts (MEI):
+ - Routed through PLIC
+ - Handler in trap.c calls registered ISR callbacks
+
+3. Software Interrupts (MSI):
+ - Supported but not actively used in this port
+
+Interrupt Flow
+
+1. Hardware trap entry (automatic):
+ - mepc <- PC (address of interrupted instruction)
+ - mcause <- exception/interrupt code
+ - mstatus.MPIE <- mstatus.MIE (save interrupt-enable state)
+ - mstatus.MIE <- 0 (disable interrupts)
+ - mstatus.MPP <- Machine mode
+ - PC <- mtvec (points to trap_entry in entry.s)
+
+2. Trap entry (entry.s):
+ - Allocates interrupt stack frame (32*8 or 65*8 bytes depending on FP)
+ - Saves RA (x1) on stack
+ - Calls _tx_thread_context_save
+
+3. Context save (_tx_thread_context_save.S):
+ - Increments _tx_thread_system_state (nested interrupt counter)
+ - If nested interrupt: saves remaining registers and returns to ISR
+ - If first interrupt: saves full context, switches to system stack
+
+4. Trap handler (trap.c):
+ - Examines mcause to determine interrupt type
+ - Dispatches to appropriate handler (_tx_timer_interrupt or PLIC handler)
+ - Returns to context restore
+
+5. Context restore (_tx_thread_context_restore.S):
+ - Decrements _tx_thread_system_state
+ - Checks if preemption needed
+ - Restores thread context or switches to next ready thread via scheduler
+ - Returns to interrupted thread or executes new thread
+
+
+Interrupt Control Macros
+
+TX_DISABLE and TX_RESTORE macros atomically manage the MIE bit in mstatus:
+
+ TX_DISABLE: Saves and clears MIE bit via csrrci (CSR read-clear immediate)
+ TX_RESTORE: Restores only MIE bit via csrrs (CSR read-set)
+ Other mstatus bits remain unchanged
+
+These are defined in ports/risc-v64/gnu/inc/tx_port.h and use the
+_tx_thread_interrupt_control() function.
+
+
+6. Thread Scheduling and Context Switching
+
+Thread Scheduler (src/tx_thread_schedule.S)
+
+The scheduler:
+1. Enables interrupts while waiting for next thread
+2. Spins until _tx_thread_execute_ptr becomes non-NULL
+3. Disables interrupts (critical section)
+4. Sets _tx_thread_current_ptr = _tx_thread_execute_ptr
+5. Increments thread's run count
+6. Switches to thread's stack
+7. Determines stack frame type and restores context:
+ - Interrupt frame: full context restored, returns via mret
+ - Solicited frame: minimal context restored, returns via ret
+
+Initial Thread Stack Frame (src/tx_thread_stack_build.S)
+
+New threads start with a fake interrupt frame containing:
+- All registers initialized to 0
+- ra (x1) = 0
+- mepc = entry function pointer
+- Stack type = 1 (interrupt frame)
+- Floating-point registers initialized based on ABI
+
+
+7. Port Configuration and Macros
+
+Default Configurations (in ports/risc-v64/gnu/inc/tx_port.h):
+
+ TX_MINIMUM_STACK 1024 /* Minimum thread stack size */
+ TX_TIMER_THREAD_STACK_SIZE 1024 /* Timer thread stack size */
+ TX_TIMER_THREAD_PRIORITY 0 /* Timer thread priority */
+ TX_MAX_PRIORITIES 32 /* Must be multiple of 32 */
+
+These can be overridden in tx_user.h or on the compiler command line.
+
+
+8. Build Configuration
+
+CMake Toolchain File: cmake/riscv64_gnu.cmake
+
+Compiler Flags:
+ -march=rv64gc RV64 with IMAFD+C extensions
+ -mabi=lp64d 64-bit integers/pointers, double-precision FP in registers
+ -mcmodel=medany ±2GB addressability
+ -D__ASSEMBLER__ For assembly files
+
+ABI Selection
+
+The port uses lp64d ABI which includes:
+- 64-bit integers and pointers
+- Double-precision floating-point arguments in registers
+- Floating-point registers f0-f31
+
+When building with floating-point ABI:
+- FP registers and FCSR are saved/restored in context switches
+- Stack frames expand from 32*REGBYTES to 65*REGBYTES
+- Conditional compilation uses __riscv_float_abi_double
+
+
+9. File Organization
+
+Port-specific files (ports/risc-v64/gnu/):
+
+Core assembly files (src/):
+ - tx_initialize_low_level.S Initial setup and system state
+ - tx_thread_context_save.S Save context on interrupt entry
+ - tx_thread_context_restore.S Restore context on interrupt exit
+ - tx_thread_schedule.S Thread scheduler
+ - tx_thread_system_return.S Solicited context save for voluntary yield
+ - tx_thread_stack_build.S Build initial stack frame for new thread
+ - tx_thread_interrupt_control.S Interrupt enable/disable control
+ - tx_timer_interrupt.S Timer interrupt handler
+
+Header file (inc/):
+ - tx_port.h Port-specific defines and macros
+
+Example files (example_build/qemu_virt/):
+ - entry.s Startup code, trap entry point
+ - board.c, uart.c, hwtimer.c Platform-specific initialization
+ - plic.c PLIC interrupt controller driver
+ - trap.c Trap/exception dispatcher
+ - link.lds Linker script for QEMU virt
+ - build_libthreadx.sh Build script
+
+
+10. Linker Script Requirements
+
+The linker script must provide:
+
+1. Entry point:
+ ENTRY(_start)
+
+2. Memory layout:
+ - .text section (code)
+ - .rodata section (read-only data)
+ - .data section (initialized data)
+ - .bss section (uninitialized data)
+
+3. Symbols:
+ - _end: First free memory address (used by ThreadX allocation)
+ - _bss_start, _bss_end: For zero initialization
+ - Initial stack space (example: 4KB)
+
+4. Alignment:
+ - 16-byte alignment throughout (RISC-V64 requirement)
+
+Example from QEMU virt build:
+
+ SECTIONS
+ {
+ . = 0x80000000; /* QEMU virt base address */
+
+ .text : { *(.text .text.*) }
+ .rodata : { *(.rodata .rodata.*) }
+ .data : { *(.data .data.*) }
+ .bss : { *(.bss .bss.*) }
+
+ .stack : {
+ . = ALIGN(4096);
+ _sysstack_start = .;
+ . += 0x1000; /* 4KB initial stack */
+ _sysstack_end = .;
+ }
+
+ PROVIDE(_end = .);
+ }
+
+
+11. Floating-Point Support
+
+When building with lp64d ABI and FP enabled:
+
+- FP registers f0-f31 and FCSR are saved/restored during context switches
+- Stack frames increase from 32*REGBYTES to 65*REGBYTES (256 to 520 bytes)
+- MSTATUS.FS (floating-point state) field is set to indicate dirty FP state
+
+Stack frame differences:
+- Without FP: 32*8 = 256 bytes (interrupt), 16*8 = 128 bytes (solicited)
+- With FP: 65*8 = 520 bytes (interrupt), 29*8 = 232 bytes (solicited)
+
+
+12. Performance and Debugging
+
+Performance Optimization
+
+Build optimizations:
+- Use -O2 or -O3 for production (example uses -O0 for debugging)
+- Enable -Wl,--gc-sections to remove unused code
+- Define TX_DISABLE_ERROR_CHECKING to remove parameter checks
+- Consider -flto for link-time optimization
+
+Debugging with QEMU and GDB
+
+Start QEMU in debug mode:
+ qemu-system-riscv64 -nographic -smp 1 -bios none -m 128M \
+ -machine virt -kernel kernel.elf -s -S
+
+ -s: Enable GDB server on TCP port 1234
+ -S: Pause at startup waiting for GDB
+
+Connect GDB:
+ riscv64-unknown-elf-gdb kernel.elf
+ (gdb) target remote :1234
+ (gdb) break main
+ (gdb) continue
+
+Useful GDB commands:
+ (gdb) info registers # View general registers
+ (gdb) info all-registers # Include CSR and FP registers
+ (gdb) p/x $mstatus # View machine status register
+ (gdb) x/32gx $sp # Examine stack memory
+ (gdb) p *_tx_thread_current_ptr # View current thread control block
+
+
+13. Platform-Specific Notes (QEMU virt)
+
+PLIC Configuration
+
+The PLIC (Platform-Level Interrupt Controller) is memory-mapped at 0x0C000000:
+
+- Enables up to 1024 interrupt sources
+- Supports priority levels 0-7 (0 = disabled)
+- Requires per-hart priority threshold and enable register configuration
+
+Example PLIC usage (from plic.c):
+ plic_irq_enable(irq_number); # Enable specific interrupt
+ plic_prio_set(irq_number, priority);# Set priority level
+
+CLINT Configuration
+
+The CLINT (Core-Local Interruptor) is memory-mapped at 0x02000000:
+
+- CLINT_MSIP(hartid): 0x0000 + 4*hartid (software interrupt)
+- CLINT_MTIMECMP(hartid): 0x4000 + 8*hartid (timer compare)
+- CLINT_MTIME: 0xBFF8 (timer value, read-only)
+
+Timer frequency is platform-dependent (example uses 10MHz).
+
+Multi-Core Considerations
+
+The current port is single-core focused:
+- Only hart 0 continues from reset; others enter WFI loop
+- _tx_thread_system_state is a global variable
+- No per-hart data structures
+
+
+14. Revision History
+
+For generic code revision information, refer to readme_threadx_generic.txt.
+
+The following details the revision history for this RISC-V64 GNU port:
+
+01-26-2026 Akif Ejaz Comprehensive rewrite with accurate
+ technical details matching implementation,
+ register naming per RISC-V ABI, and
+ complete interrupt flow documentation
+
+03-08-2023 Scott Larson Initial Version 6.2.1
+
+
+Copyright (c) 1996-2026 Microsoft Corporation
+
+https://azure.com/rtos
diff --git a/ports/risc-v64/gnu/src/tx_initialize_low_level.S b/ports/risc-v64/gnu/src/tx_initialize_low_level.S
index ccafd5e2..68150c18 100644
--- a/ports/risc-v64/gnu/src/tx_initialize_low_level.S
+++ b/ports/risc-v64/gnu/src/tx_initialize_low_level.S
@@ -71,41 +71,45 @@ __tx_free_memory_start:
.global _tx_initialize_low_level
.weak _tx_initialize_low_level
_tx_initialize_low_level:
- sd sp, _tx_thread_system_stack_ptr, t0 // Save system stack pointer
+ /* Save the system stack pointer. */
+ /* _tx_thread_system_stack_ptr = sp; */
+ la t0, _tx_thread_system_stack_ptr
+ sd sp, 0(t0) /* Save system stack pointer */
- la t0, __tx_free_memory_start // Pickup first free address
- sd t0, _tx_initialize_unused_memory, t1 // Save unused memory address
+ /* Pickup first free address. */
+ /* _tx_initialize_unused_memory(__tx_free_memory_start); */
+ la t0, __tx_free_memory_start /* Pickup first free address */
+ la t1, _tx_initialize_unused_memory
+ sd t0, 0(t1) /* Save unused memory address */
+ /* Initialize floating point control/status register if floating point is enabled. */
#ifdef __riscv_flen
- fscsr x0
+ li t0, 0
+ csrw fcsr, t0 /* Clear FP control/status register */
#endif
ret
-
- /* Define the actual timer interrupt/exception handler. */
-
- .global timer1_plic_IRQHandler
- //.global __minterrupt_000007
- //EXTWEAK __require_minterrupt_vector_table
-timer1_plic_IRQHandler:
-//__minterrupt_000007:
- //REQUIRE __require_minterrupt_vector_table
-
-
- /* Before calling _tx_thread_context_save, we have to allocate an interrupt
- stack frame and save the current value of x1 (ra). */
-//#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
-// addi sp, sp, -520 // Allocate space for all registers - with floating point enabled
-//#else
-// addi sp, sp, -256 // Allocate space for all registers - without floating point enabled
-//#endif
-// sd x1, 224(sp) // Store RA
-// call _tx_thread_context_save // Call ThreadX context save
-
- /* Call the ThreadX timer routine. */
- call _tx_timer_interrupt // Call timer interrupt handler
- call timer1_interrupt
- ret
- /* Timer interrupt processing is done, jump to ThreadX context restore. */
-// j _tx_thread_context_restore // Jump to ThreadX context restore function. Note: this does not return!
+/* Timer Interrupt Handler Note:
+ Platform-specific implementations must provide their own timer ISR.
+ The timer interrupt handler should follow this execution flow:
+
+ 1. Disable interrupts (if not done by hardware exception entry)
+ 2. Allocate interrupt stack frame (65*8 bytes with FP, 32*8 bytes without)
+ 3. Save RA (x1) on the stack at offset 28*8
+ 4. Call _tx_thread_context_save to save thread context
+ 5. Call _tx_timer_interrupt to process the timer tick
+ 6. Call _tx_thread_context_restore to resume execution (does not return)
+
+ Example (for CLINT timer):
+
+ _tx_timer_interrupt_handler:
+ addi sp, sp, -32*8
+ sd ra, 28*8(sp)
+ call _tx_thread_context_save
+ call _tx_timer_interrupt
+ j _tx_thread_context_restore
+
+ The port assumes Machine mode (M-mode) execution.
+ For Supervisor mode (S-mode), use sstatus and SIE/SPIE instead of mstatus.
+ See the RISC-V Privileged Specification for more details. */
diff --git a/ports/risc-v64/gnu/src/tx_thread_context_restore.S b/ports/risc-v64/gnu/src/tx_thread_context_restore.S
index d805a59c..edacb8b6 100644
--- a/ports/risc-v64/gnu/src/tx_thread_context_restore.S
+++ b/ports/risc-v64/gnu/src/tx_thread_context_restore.S
@@ -19,7 +19,6 @@
/**************************************************************************/
/**************************************************************************/
-#include "tx_port.h"
.section .text
/**************************************************************************/
@@ -69,21 +68,21 @@ _tx_thread_context_restore:
/* Lockout interrupts. */
- csrci mstatus, 0x08 // Disable interrupts
+ csrci mstatus, 0x08 /* Disable interrupts (MIE bit 3) */
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
- call _tx_execution_isr_exit // Call the ISR execution exit function
+ call _tx_execution_isr_exit /* Call the ISR execution exit function */
#endif
/* Determine if interrupts are nested. */
/* if (--_tx_thread_system_state)
{ */
- la t0, _tx_thread_system_state // Pickup addr of nested interrupt count
- LOAD t1, 0(t0) // Pickup nested interrupt count
- addi t1, t1, -1 // Decrement the nested interrupt counter
- STORE t1, 0(t0) // Store new nested count
- beqz t1, _tx_thread_not_nested_restore // If 0, not nested restore
+ la t0, _tx_thread_system_state /* Pickup addr of nested interrupt count */
+ ld t1, 0(t0) /* Pickup nested interrupt count */
+ addi t1, t1, -1 /* Decrement the nested interrupt counter */
+ sd t1, 0(t0) /* Store new nested count */
+ beqz t1, _tx_thread_not_nested_restore /* If 0, not nested restore */
/* Interrupts are nested. */
@@ -92,51 +91,51 @@ _tx_thread_context_restore:
/* Recover floating point registers. */
#if defined(__riscv_float_abi_single)
- flw f0, 31*REGBYTES(sp) // Recover ft0
- flw f1, 32*REGBYTES(sp) // Recover ft1
- flw f2, 33*REGBYTES(sp) // Recover ft2
- flw f3, 34*REGBYTES(sp) // Recover ft3
- flw f4, 35*REGBYTES(sp) // Recover ft4
- flw f5, 36*REGBYTES(sp) // Recover ft5
- flw f6, 37*REGBYTES(sp) // Recover ft6
- flw f7, 38*REGBYTES(sp) // Recover ft7
- flw f10,41*REGBYTES(sp) // Recover fa0
- flw f11,42*REGBYTES(sp) // Recover fa1
- flw f12,43*REGBYTES(sp) // Recover fa2
- flw f13,44*REGBYTES(sp) // Recover fa3
- flw f14,45*REGBYTES(sp) // Recover fa4
- flw f15,46*REGBYTES(sp) // Recover fa5
- flw f16,47*REGBYTES(sp) // Recover fa6
- flw f17,48*REGBYTES(sp) // Recover fa7
- flw f28,59*REGBYTES(sp) // Recover ft8
- flw f29,60*REGBYTES(sp) // Recover ft9
- flw f30,61*REGBYTES(sp) // Recover ft10
- flw f31,62*REGBYTES(sp) // Recover ft11
- lw t0, 63*REGBYTES(sp) // Recover fcsr
- csrw fcsr, t0 //
+ flw f0, 31*8(sp) /* Recover ft0 */
+ flw f1, 32*8(sp) /* Recover ft1 */
+ flw f2, 33*8(sp) /* Recover ft2 */
+ flw f3, 34*8(sp) /* Recover ft3 */
+ flw f4, 35*8(sp) /* Recover ft4 */
+ flw f5, 36*8(sp) /* Recover ft5 */
+ flw f6, 37*8(sp) /* Recover ft6 */
+ flw f7, 38*8(sp) /* Recover ft7 */
+ flw f10,41*8(sp) /* Recover fa0 */
+ flw f11,42*8(sp) /* Recover fa1 */
+ flw f12,43*8(sp) /* Recover fa2 */
+ flw f13,44*8(sp) /* Recover fa3 */
+ flw f14,45*8(sp) /* Recover fa4 */
+ flw f15,46*8(sp) /* Recover fa5 */
+ flw f16,47*8(sp) /* Recover fa6 */
+ flw f17,48*8(sp) /* Recover fa7 */
+ flw f28,59*8(sp) /* Recover ft8 */
+ flw f29,60*8(sp) /* Recover ft9 */
+ flw f30,61*8(sp) /* Recover ft10 */
+ flw f31,62*8(sp) /* Recover ft11 */
+ ld t0, 63*8(sp) /* Recover fcsr */
+ csrw fcsr, t0 /* Restore fcsr */
#elif defined(__riscv_float_abi_double)
- fld f0, 31*REGBYTES(sp) // Recover ft0
- fld f1, 32*REGBYTES(sp) // Recover ft1
- fld f2, 33*REGBYTES(sp) // Recover ft2
- fld f3, 34*REGBYTES(sp) // Recover ft3
- fld f4, 35*REGBYTES(sp) // Recover ft4
- fld f5, 36*REGBYTES(sp) // Recover ft5
- fld f6, 37*REGBYTES(sp) // Recover ft6
- fld f7, 38*REGBYTES(sp) // Recover ft7
- fld f10,41*REGBYTES(sp) // Recover fa0
- fld f11,42*REGBYTES(sp) // Recover fa1
- fld f12,43*REGBYTES(sp) // Recover fa2
- fld f13,44*REGBYTES(sp) // Recover fa3
- fld f14,45*REGBYTES(sp) // Recover fa4
- fld f15,46*REGBYTES(sp) // Recover fa5
- fld f16,47*REGBYTES(sp) // Recover fa6
- fld f17,48*REGBYTES(sp) // Recover fa7
- fld f28,59*REGBYTES(sp) // Recover ft8
- fld f29,60*REGBYTES(sp) // Recover ft9
- fld f30,61*REGBYTES(sp) // Recover ft10
- fld f31,62*REGBYTES(sp) // Recover ft11
- LOAD t0, 63*REGBYTES(sp) // Recover fcsr
- csrw fcsr, t0 //
+ fld f0, 31*8(sp) /* Recover ft0 */
+ fld f1, 32*8(sp) /* Recover ft1 */
+ fld f2, 33*8(sp) /* Recover ft2 */
+ fld f3, 34*8(sp) /* Recover ft3 */
+ fld f4, 35*8(sp) /* Recover ft4 */
+ fld f5, 36*8(sp) /* Recover ft5 */
+ fld f6, 37*8(sp) /* Recover ft6 */
+ fld f7, 38*8(sp) /* Recover ft7 */
+ fld f10,41*8(sp) /* Recover fa0 */
+ fld f11,42*8(sp) /* Recover fa1 */
+ fld f12,43*8(sp) /* Recover fa2 */
+ fld f13,44*8(sp) /* Recover fa3 */
+ fld f14,45*8(sp) /* Recover fa4 */
+ fld f15,46*8(sp) /* Recover fa5 */
+ fld f16,47*8(sp) /* Recover fa6 */
+ fld f17,48*8(sp) /* Recover fa7 */
+ fld f28,59*8(sp) /* Recover ft8 */
+ fld f29,60*8(sp) /* Recover ft9 */
+ fld f30,61*8(sp) /* Recover ft10 */
+ fld f31,62*8(sp) /* Recover ft11 */
+ ld t0, 63*8(sp) /* Recover fcsr */
+ csrw fcsr, t0
#endif
/* Recover standard registers. */
@@ -146,39 +145,56 @@ _tx_thread_context_restore:
Also skip the saved registers since they have been restored by any function we called,
except s0 since we use it ourselves. */
- LOAD t0, 30*REGBYTES(sp) // Recover mepc
- csrw mepc, t0 // Setup mepc
- li t0, 0x1880 // Prepare MPIP
+ ld t0, 30*8(sp) /* Recover mepc */
+ csrw mepc, t0 /* Setup mepc */
+
+ /* Compose mstatus via read/modify/write to avoid clobbering unrelated bits.
+ Set MPIE and restore MPP to Machine, preserve other fields. */
+
+ csrr t1, mstatus
+
+ /* Clear MPP/MPIE/MIE bits in t1 then set desired values. */
+
+ li t2, 0x1888 /* MPP(0x1800) | MPIE(0x80) | MIE(0x08) */
+ li t3, 0x1800 /* Set MPP to Machine mode (bits 12:11) */
+
+ /* Construct new mstatus in t1: clear mask bits, set MPP/MPIE and optionally FP bit,
+ preserve everything except the bits we will modify. */
+
+ li t4, ~0x1888 /* Clear mask for MPP/MPIE/MIE */
+ and t1, t1, t4
+ or t1, t1, t3
+
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
- li t1, 1<<13
- or t0, t1, t0
+ li t0, 0x2000 /* Set FS bits (bits 14:13 to 01) for FP state */
+ or t1, t1, t0
#endif
- csrw mstatus, t0 // Enable MPIP
+ csrw mstatus, t1 /* Update mstatus safely */
- LOAD x1, 28*REGBYTES(sp) // Recover RA
- LOAD x5, 19*REGBYTES(sp) // Recover t0
- LOAD x6, 18*REGBYTES(sp) // Recover t1
- LOAD x7, 17*REGBYTES(sp) // Recover t2
- LOAD x8, 12*REGBYTES(sp) // Recover s0
- LOAD x10, 27*REGBYTES(sp) // Recover a0
- LOAD x11, 26*REGBYTES(sp) // Recover a1
- LOAD x12, 25*REGBYTES(sp) // Recover a2
- LOAD x13, 24*REGBYTES(sp) // Recover a3
- LOAD x14, 23*REGBYTES(sp) // Recover a4
- LOAD x15, 22*REGBYTES(sp) // Recover a5
- LOAD x16, 21*REGBYTES(sp) // Recover a6
- LOAD x17, 20*REGBYTES(sp) // Recover a7
- LOAD x28, 16*REGBYTES(sp) // Recover t3
- LOAD x29, 15*REGBYTES(sp) // Recover t4
- LOAD x30, 14*REGBYTES(sp) // Recover t5
- LOAD x31, 13*REGBYTES(sp) // Recover t6
+ ld ra, 28*8(sp) /* Recover return address */
+ ld t0, 19*8(sp) /* Recover t0 */
+ ld t1, 18*8(sp) /* Recover t1 */
+ ld t2, 17*8(sp) /* Recover t2 */
+ ld s0, 12*8(sp) /* Recover s0 */
+ ld a0, 27*8(sp) /* Recover a0 */
+ ld a1, 26*8(sp) /* Recover a1 */
+ ld a2, 25*8(sp) /* Recover a2 */
+ ld a3, 24*8(sp) /* Recover a3 */
+ ld a4, 23*8(sp) /* Recover a4 */
+ ld a5, 22*8(sp) /* Recover a5 */
+ ld a6, 21*8(sp) /* Recover a6 */
+ ld a7, 20*8(sp) /* Recover a7 */
+ ld t3, 16*8(sp) /* Recover t3 */
+ ld t4, 15*8(sp) /* Recover t4 */
+ ld t5, 14*8(sp) /* Recover t5 */
+ ld t6, 13*8(sp) /* Recover t6 */
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
- addi sp, sp, 65*REGBYTES // Recover stack frame - with floating point enabled
+ addi sp, sp, 65*8 /* Recover stack frame - with floating point enabled */
#else
- addi sp, sp, 32*REGBYTES // Recover stack frame - without floating point enabled
+ addi sp, sp, 32*8 /* Recover stack frame - without floating point enabled */
#endif
- mret // Return to point of interrupt
+ mret /* Return to point of interrupt */
/* } */
_tx_thread_not_nested_restore:
@@ -187,71 +203,74 @@ _tx_thread_not_nested_restore:
|| (_tx_thread_preempt_disable))
{ */
- LOAD t1, _tx_thread_current_ptr // Pickup current thread pointer
- beqz t1, _tx_thread_idle_system_restore // If NULL, idle system restore
+ la t0, _tx_thread_current_ptr /* Pickup current thread pointer address */
+ ld t1, 0(t0) /* Pickup current thread pointer */
+ beqz t1, _tx_thread_idle_system_restore /* If NULL, idle system restore */
- LOAD t2, _tx_thread_preempt_disable // Pickup preempt disable flag
- bgtz t2, _tx_thread_no_preempt_restore // If set, restore interrupted thread
+ la t0, _tx_thread_preempt_disable /* Pickup preempt disable flag address */
+ lw t2, 0(t0) /* Pickup preempt disable flag (UINT) */
+ bgtz t2, _tx_thread_no_preempt_restore /* If set, restore interrupted thread */
- LOAD t2, _tx_thread_execute_ptr // Pickup thread execute pointer
- bne t1, t2, _tx_thread_preempt_restore // If higher-priority thread is ready, preempt
+ la t0, _tx_thread_execute_ptr /* Pickup thread execute pointer address */
+ ld t2, 0(t0) /* Pickup thread execute pointer */
+ bne t1, t2, _tx_thread_preempt_restore /* If higher-priority thread is ready, preempt */
_tx_thread_no_preempt_restore:
/* Restore interrupted thread or ISR. */
/* Pickup the saved stack pointer. */
- /* SP = _tx_thread_current_ptr -> tx_thread_stack_ptr; */
+ /* sp = _tx_thread_current_ptr -> tx_thread_stack_ptr; */
- LOAD sp, 2*REGBYTES(t1) // Switch back to thread's stack
+ ld sp, 16(t1) /* Switch back to thread's stack */
/* Recover floating point registers. */
#if defined(__riscv_float_abi_single)
- flw f0, 31*REGBYTES(sp) // Recover ft0
- flw f1, 32*REGBYTES(sp) // Recover ft1
- flw f2, 33*REGBYTES(sp) // Recover ft2
- flw f3, 34*REGBYTES(sp) // Recover ft3
- flw f4, 35*REGBYTES(sp) // Recover ft4
- flw f5, 36*REGBYTES(sp) // Recover ft5
- flw f6, 37*REGBYTES(sp) // Recover ft6
- flw f7, 38*REGBYTES(sp) // Recover ft7
- flw f10,41*REGBYTES(sp) // Recover fa0
- flw f11,42*REGBYTES(sp) // Recover fa1
- flw f12,43*REGBYTES(sp) // Recover fa2
- flw f13,44*REGBYTES(sp) // Recover fa3
- flw f14,45*REGBYTES(sp) // Recover fa4
- flw f15,46*REGBYTES(sp) // Recover fa5
- flw f16,47*REGBYTES(sp) // Recover fa6
- flw f17,48*REGBYTES(sp) // Recover fa7
- flw f28,59*REGBYTES(sp) // Recover ft8
- flw f29,60*REGBYTES(sp) // Recover ft9
- flw f30,61*REGBYTES(sp) // Recover ft10
- flw f31,62*REGBYTES(sp) // Recover ft11
- lw t0, 63*REGBYTES(sp) // Recover fcsr
- csrw fcsr, t0 //
+ flw f0, 31*8(sp) /* Recover ft0 */
+ flw f1, 32*8(sp) /* Recover ft1 */
+ flw f2, 33*8(sp) /* Recover ft2 */
+ flw f3, 34*8(sp) /* Recover ft3 */
+ flw f4, 35*8(sp) /* Recover ft4 */
+ flw f5, 36*8(sp) /* Recover ft5 */
+ flw f6, 37*8(sp) /* Recover ft6 */
+ flw f7, 38*8(sp) /* Recover ft7 */
+ flw f10,41*8(sp) /* Recover fa0 */
+ flw f11,42*8(sp) /* Recover fa1 */
+ flw f12,43*8(sp) /* Recover fa2 */
+ flw f13,44*8(sp) /* Recover fa3 */
+ flw f14,45*8(sp) /* Recover fa4 */
+ flw f15,46*8(sp) /* Recover fa5 */
+ flw f16,47*8(sp) /* Recover fa6 */
+ flw f17,48*8(sp) /* Recover fa7 */
+ flw f28,59*8(sp) /* Recover ft8 */
+ flw f29,60*8(sp) /* Recover ft9 */
+ flw f30,61*8(sp) /* Recover ft10 */
+ flw f31,62*8(sp) /* Recover ft11 */
+ ld t0, 63*8(sp) /* Recover fcsr */
+ csrw fcsr, t0 /* Restore fcsr */
#elif defined(__riscv_float_abi_double)
- fld f0, 31*REGBYTES(sp) // Recover ft0
- fld f1, 32*REGBYTES(sp) // Recover ft1
- fld f2, 33*REGBYTES(sp) // Recover ft2
- fld f3, 34*REGBYTES(sp) // Recover ft3
- fld f4, 35*REGBYTES(sp) // Recover ft4
- fld f5, 36*REGBYTES(sp) // Recover ft5
- fld f6, 37*REGBYTES(sp) // Recover ft6
- fld f7, 38*REGBYTES(sp) // Recover ft7
- fld f10,41*REGBYTES(sp) // Recover fa0
- fld f11,42*REGBYTES(sp) // Recover fa1
- fld f12,43*REGBYTES(sp) // Recover fa2
- fld f13,44*REGBYTES(sp) // Recover fa3
- fld f14,45*REGBYTES(sp) // Recover fa4
- fld f15,46*REGBYTES(sp) // Recover fa5
- fld f16,47*REGBYTES(sp) // Recover fa6
- fld f17,48*REGBYTES(sp) // Recover fa7
- fld f28,59*REGBYTES(sp) // Recover ft8
- fld f29,60*REGBYTES(sp) // Recover ft9
- fld f30,61*REGBYTES(sp) // Recover ft10
- fld f31,62*REGBYTES(sp) // Recover ft11
- LOAD t0, 63*REGBYTES(sp) // Recover fcsr
- csrw fcsr, t0 //
+ fld f0, 31*8(sp) /* Recover ft0 */
+ fld f1, 32*8(sp) /* Recover ft1 */
+ fld f2, 33*8(sp) /* Recover ft2 */
+ fld f3, 34*8(sp) /* Recover ft3 */
+ fld f4, 35*8(sp) /* Recover ft4 */
+ fld f5, 36*8(sp) /* Recover ft5 */
+ fld f6, 37*8(sp) /* Recover ft6 */
+ fld f7, 38*8(sp) /* Recover ft7 */
+ fld f10,41*8(sp) /* Recover fa0 */
+ fld f11,42*8(sp) /* Recover fa1 */
+ fld f12,43*8(sp) /* Recover fa2 */
+ fld f13,44*8(sp) /* Recover fa3 */
+ fld f14,45*8(sp) /* Recover fa4 */
+ fld f15,46*8(sp) /* Recover fa5 */
+ fld f16,47*8(sp) /* Recover fa6 */
+ fld f17,48*8(sp) /* Recover fa7 */
+ fld f28,59*8(sp) /* Recover ft8 */
+ fld f29,60*8(sp) /* Recover ft9 */
+ fld f30,61*8(sp) /* Recover ft10 */
+ fld f31,62*8(sp) /* Recover ft11 */
+ ld t0, 63*8(sp) /* Recover fcsr */
+ csrw fcsr, t0 /* Restore fcsr */
#endif
/* Recover the saved context and return to the point of interrupt. */
@@ -260,39 +279,48 @@ _tx_thread_no_preempt_restore:
/* Restore registers,
Skip global pointer because that does not change */
- LOAD t0, 240(sp) // Recover mepc
- csrw mepc, t0 // Setup mepc
- li t0, 0x1880 // Prepare MPIP
+ ld t0, 30*8(sp) /* Recover mepc */
+ csrw mepc, t0 /* Setup mepc */
+
+ /* Compose mstatus via read/modify/write to avoid clobbering unrelated bits. */
+
+ csrr t1, mstatus
+ li t2, 0x1888 /* MPP(0x1800) | MPIE(0x80) | MIE(0x08) */
+ li t3, 0x1800 /* Set MPP to Machine mode */
+ li t4, ~0x1888 /* Clear mask for MPP/MPIE/MIE */
+ and t1, t1, t4
+ or t1, t1, t3
+
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
- li t1, 1<<13
- or t0, t1, t0
+ li t0, 0x2000 /* Set FS bits for FP state */
+ or t1, t1, t0
#endif
- csrw mstatus, t0 // Enable MPIP
+ csrw mstatus, t1 /* Update mstatus safely */
- LOAD x1, 28*REGBYTES(sp) // Recover RA
- LOAD x5, 19*REGBYTES(sp) // Recover t0
- LOAD x6, 18*REGBYTES(sp) // Recover t1
- LOAD x7, 17*REGBYTES(sp) // Recover t2
- LOAD x8, 12*REGBYTES(sp) // Recover s0
- LOAD x10, 27*REGBYTES(sp) // Recover a0
- LOAD x11, 26*REGBYTES(sp) // Recover a1
- LOAD x12, 25*REGBYTES(sp) // Recover a2
- LOAD x13, 24*REGBYTES(sp) // Recover a3
- LOAD x14, 23*REGBYTES(sp) // Recover a4
- LOAD x15, 22*REGBYTES(sp) // Recover a5
- LOAD x16, 21*REGBYTES(sp) // Recover a6
- LOAD x17, 20*REGBYTES(sp) // Recover a7
- LOAD x28, 16*REGBYTES(sp) // Recover t3
- LOAD x29, 15*REGBYTES(sp) // Recover t4
- LOAD x30, 14*REGBYTES(sp) // Recover t5
- LOAD x31, 13*REGBYTES(sp) // Recover t6
+ ld ra, 28*8(sp) /* Recover return address */
+ ld t0, 19*8(sp) /* Recover t0 */
+ ld t1, 18*8(sp) /* Recover t1 */
+ ld t2, 17*8(sp) /* Recover t2 */
+ ld s0, 12*8(sp) /* Recover s0 */
+ ld a0, 27*8(sp) /* Recover a0 */
+ ld a1, 26*8(sp) /* Recover a1 */
+ ld a2, 25*8(sp) /* Recover a2 */
+ ld a3, 24*8(sp) /* Recover a3 */
+ ld a4, 23*8(sp) /* Recover a4 */
+ ld a5, 22*8(sp) /* Recover a5 */
+ ld a6, 21*8(sp) /* Recover a6 */
+ ld a7, 20*8(sp) /* Recover a7 */
+ ld t3, 16*8(sp) /* Recover t3 */
+ ld t4, 15*8(sp) /* Recover t4 */
+ ld t5, 14*8(sp) /* Recover t5 */
+ ld t6, 13*8(sp) /* Recover t6 */
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
- addi sp, sp, 65*REGBYTES // Recover stack frame - with floating point enabled
+ addi sp, sp, 65*8 /* Recover stack frame - with floating point enabled */
#else
- addi sp, sp, 32*REGBYTES // Recover stack frame - without floating point enabled
+ addi sp, sp, 32*8 /* Recover stack frame - without floating point enabled */
#endif
- mret // Return to point of interrupt
+ mret /* Return to point of interrupt */
/* }
else
@@ -301,52 +329,52 @@ _tx_thread_preempt_restore:
/* Instead of directly activating the thread again, ensure we save the
entire stack frame by saving the remaining registers. */
- LOAD t0, 2*REGBYTES(t1) // Pickup thread's stack pointer
- ori t3, x0, 1 // Build interrupt stack type
- STORE t3, 0(t0) // Store stack type
+ ld t0, 16(t1) /* Pickup thread's stack pointer */
+ ori t3, zero, 1 /* Build interrupt stack type */
+ sd t3, 0(t0) /* Store stack type */
/* Store floating point preserved registers. */
#ifdef __riscv_float_abi_single
- fsw f8, 39*REGBYTES(t0) // Store fs0
- fsw f9, 40*REGBYTES(t0) // Store fs1
- fsw f18, 49*REGBYTES(t0) // Store fs2
- fsw f19, 50*REGBYTES(t0) // Store fs3
- fsw f20, 51*REGBYTES(t0) // Store fs4
- fsw f21, 52*REGBYTES(t0) // Store fs5
- fsw f22, 53*REGBYTES(t0) // Store fs6
- fsw f23, 54*REGBYTES(t0) // Store fs7
- fsw f24, 55*REGBYTES(t0) // Store fs8
- fsw f25, 56*REGBYTES(t0) // Store fs9
- fsw f26, 57*REGBYTES(t0) // Store fs10
- fsw f27, 58*REGBYTES(t0) // Store fs11
+ fsw f8, 39*8(t0) /* Store fs0 */
+ fsw f9, 40*8(t0) /* Store fs1 */
+ fsw f18, 49*8(t0) /* Store fs2 */
+ fsw f19, 50*8(t0) // Store fs3
+ fsw f20, 51*8(t0) // Store fs4
+ fsw f21, 52*8(t0) // Store fs5
+ fsw f22, 53*8(t0) // Store fs6
+ fsw f23, 54*8(t0) // Store fs7
+ fsw f24, 55*8(t0) // Store fs8
+ fsw f25, 56*8(t0) // Store fs9
+ fsw f26, 57*8(t0) // Store fs10
+ fsw f27, 58*8(t0) // Store fs11
#elif defined(__riscv_float_abi_double)
- fsd f8, 39*REGBYTES(t0) // Store fs0
- fsd f9, 40*REGBYTES(t0) // Store fs1
- fsd f18, 49*REGBYTES(t0) // Store fs2
- fsd f19, 50*REGBYTES(t0) // Store fs3
- fsd f20, 51*REGBYTES(t0) // Store fs4
- fsd f21, 52*REGBYTES(t0) // Store fs5
- fsd f22, 53*REGBYTES(t0) // Store fs6
- fsd f23, 54*REGBYTES(t0) // Store fs7
- fsd f24, 55*REGBYTES(t0) // Store fs8
- fsd f25, 56*REGBYTES(t0) // Store fs9
- fsd f26, 57*REGBYTES(t0) // Store fs10
- fsd f27, 58*REGBYTES(t0) // Store fs11
+ fsd f8, 39*8(t0) // Store fs0
+ fsd f9, 40*8(t0) // Store fs1
+ fsd f18, 49*8(t0) // Store fs2
+ fsd f19, 50*8(t0) // Store fs3
+ fsd f20, 51*8(t0) // Store fs4
+ fsd f21, 52*8(t0) // Store fs5
+ fsd f22, 53*8(t0) // Store fs6
+ fsd f23, 54*8(t0) // Store fs7
+ fsd f24, 55*8(t0) // Store fs8
+ fsd f25, 56*8(t0) // Store fs9
+ fsd f26, 57*8(t0) // Store fs10
+ fsd f27, 58*8(t0) // Store fs11
#endif
/* Store standard preserved registers. */
- STORE x9, 11*REGBYTES(t0) // Store s1
- STORE x18, 10*REGBYTES(t0) // Store s2
- STORE x19, 9*REGBYTES(t0) // Store s3
- STORE x20, 8*REGBYTES(t0) // Store s4
- STORE x21, 7*REGBYTES(t0) // Store s5
- STORE x22, 6*REGBYTES(t0) // Store s6
- STORE x23, 5*REGBYTES(t0) // Store s7
- STORE x24, 4*REGBYTES(t0) // Store s8
- STORE x25, 3*REGBYTES(t0) // Store s9
- STORE x26, 2*REGBYTES(t0) // Store s10
- STORE x27, 1*REGBYTES(t0) // Store s11
+ sd x9, 11*8(t0) // Store s1
+ sd x18, 10*8(t0) // Store s2
+ sd x19, 9*8(t0) // Store s3
+ sd x20, 8*8(t0) // Store s4
+ sd x21, 7*8(t0) // Store s5
+ sd x22, 6*8(t0) // Store s6
+ sd x23, 5*8(t0) // Store s7
+ sd x24, 4*8(t0) // Store s8
+ sd x25, 3*8(t0) // Store s9
+ sd x26, 2*8(t0) // Store s10
+ sd x27, 1*8(t0) // Store s11
// Note: s0 is already stored!
/* Save the remaining time-slice and disable it. */
@@ -354,14 +382,14 @@ _tx_thread_preempt_restore:
{ */
la t0, _tx_timer_time_slice // Pickup time slice variable address
- LOAD t2, 0(t0) // Pickup time slice
+ ld t2, 0(t0) // Pickup time slice
beqz t2, _tx_thread_dont_save_ts // If 0, skip time slice processing
/* _tx_thread_current_ptr -> tx_thread_time_slice = _tx_timer_time_slice
_tx_timer_time_slice = 0; */
- STORE t2, 6*REGBYTES(t1) // Save current time slice
- STORE x0, 0(t0) // Clear global time slice
+ sd t2, 48(t1) // Save current time slice
+ sd x0, 0(t0) // Clear global time slice
/* } */
@@ -372,7 +400,8 @@ _tx_thread_dont_save_ts:
/* Return to the scheduler. */
/* _tx_thread_schedule(); */
- STORE x0, _tx_thread_current_ptr, t0 // Clear current thread pointer*/
+ la t0, _tx_thread_current_ptr // Pickup current thread pointer address
+ sd x0, 0(t0) // Clear current thread pointer*/
/* } */
_tx_thread_idle_system_restore:
diff --git a/ports/risc-v64/gnu/src/tx_thread_context_save.S b/ports/risc-v64/gnu/src/tx_thread_context_save.S
index a1f2a9b6..30704850 100644
--- a/ports/risc-v64/gnu/src/tx_thread_context_save.S
+++ b/ports/risc-v64/gnu/src/tx_thread_context_save.S
@@ -1,14 +1,3 @@
-/***************************************************************************
- * Copyright (c) 2024 Microsoft Corporation
- *
- * This program and the accompanying materials are made available under the
- * terms of the MIT License which is available at
- * https://opensource.org/licenses/MIT.
- *
- * SPDX-License-Identifier: MIT
- **************************************************************************/
-
-
/**************************************************************************/
/**************************************************************************/
/** */
@@ -19,8 +8,6 @@
/**************************************************************************/
/**************************************************************************/
-#include "tx_port.h"
-
.section .text
/**************************************************************************/
/* */
@@ -67,97 +54,97 @@
_tx_thread_context_save:
/* Upon entry to this routine, it is assumed that interrupts are locked
- out and the interrupt stack fame has been allocated and x1 (ra) has
+ out and the interrupt stack frame has been allocated and ra has
been saved on the stack. */
- STORE x5, 19*REGBYTES(sp) // First store t0 and t1
- STORE x6, 18*REGBYTES(sp)
+ sd t0, 19*8(sp) /* First store t0 and t1 */
+ sd t1, 18*8(sp)
- la x5, _tx_thread_system_state // Pickup address of system state
- LOAD x6, 0(x5) // Pickup system state
+ la t0, _tx_thread_system_state /* Pickup address of system state */
+ ld t1, 0(t0) /* Pickup system state */
/* Check for a nested interrupt condition. */
/* if (_tx_thread_system_state++)
{ */
- beqz x6, _tx_thread_not_nested_save // If 0, first interrupt condition
- addi x6, x6, 1 // Increment the interrupt counter
- STORE x6, 0(x5) // Store the interrupt counter
+ beqz t1, _tx_thread_not_nested_save /* If 0, first interrupt condition */
+ addi t1, t1, 1 /* Increment the interrupt counter */
+ sd t1, 0(t0) /* Store the interrupt counter */
/* Nested interrupt condition.
- Save the reset of the scratch registers on the stack and return to the
+ Save the rest of the scratch registers on the stack and return to the
calling ISR. */
- STORE x7, 17*REGBYTES(sp) // Store t2
- STORE x8, 12*REGBYTES(sp) // Store s0
- STORE x10, 27*REGBYTES(sp) // Store a0
- STORE x11, 26*REGBYTES(sp) // Store a1
- STORE x12, 25*REGBYTES(sp) // Store a2
- STORE x13, 24*REGBYTES(sp) // Store a3
- STORE x14, 23*REGBYTES(sp) // Store a4
- STORE x15, 22*REGBYTES(sp) // Store a5
- STORE x16, 21*REGBYTES(sp) // Store a6
- STORE x17, 20*REGBYTES(sp) // Store a7
- STORE x28, 16*REGBYTES(sp) // Store t3
- STORE x29, 15*REGBYTES(sp) // Store t4
- STORE x30, 14*REGBYTES(sp) // Store t5
- STORE x31, 13*REGBYTES(sp) // Store t6
- csrr t0, mepc // Load exception program counter
- STORE t0, 30*REGBYTES(sp) // Save it on the stack
+ sd t2, 17*8(sp) /* Store t2 */
+ sd s0, 12*8(sp) /* Store s0 */
+ sd a0, 27*8(sp) /* Store a0 */
+ sd a1, 26*8(sp) /* Store a1 */
+ sd a2, 25*8(sp) /* Store a2 */
+ sd a3, 24*8(sp) /* Store a3 */
+ sd a4, 23*8(sp) /* Store a4 */
+ sd a5, 22*8(sp) /* Store a5 */
+ sd a6, 21*8(sp) /* Store a6 */
+ sd a7, 20*8(sp) /* Store a7 */
+ sd t3, 16*8(sp) /* Store t3 */
+ sd t4, 15*8(sp) /* Store t4 */
+ sd t5, 14*8(sp) /* Store t5 */
+ sd t6, 13*8(sp) /* Store t6 */
+ csrr t0, mepc /* Load exception program counter */
+ sd t0, 30*8(sp) /* Save it on the stack */
- /* Save floating point scratch registers. */
-#if defined(__riscv_float_abi_single)
- fsw f0, 31*REGBYTES(sp) // Store ft0
- fsw f1, 32*REGBYTES(sp) // Store ft1
- fsw f2, 33*REGBYTES(sp) // Store ft2
- fsw f3, 34*REGBYTES(sp) // Store ft3
- fsw f4, 35*REGBYTES(sp) // Store ft4
- fsw f5, 36*REGBYTES(sp) // Store ft5
- fsw f6, 37*REGBYTES(sp) // Store ft6
- fsw f7, 38*REGBYTES(sp) // Store ft7
- fsw f10,41*REGBYTES(sp) // Store fa0
- fsw f11,42*REGBYTES(sp) // Store fa1
- fsw f12,43*REGBYTES(sp) // Store fa2
- fsw f13,44*REGBYTES(sp) // Store fa3
- fsw f14,45*REGBYTES(sp) // Store fa4
- fsw f15,46*REGBYTES(sp) // Store fa5
- fsw f16,47*REGBYTES(sp) // Store fa6
- fsw f17,48*REGBYTES(sp) // Store fa7
- fsw f28,59*REGBYTES(sp) // Store ft8
- fsw f29,60*REGBYTES(sp) // Store ft9
- fsw f30,61*REGBYTES(sp) // Store ft10
- fsw f31,62*REGBYTES(sp) // Store ft11
+ /* Save floating point scratch registers if floating point is enabled. */
+#ifdef __riscv_float_abi_single
+ fsw f0, 31*8(sp) /* Store ft0 */
+ fsw f1, 32*8(sp) /* Store ft1 */
+ fsw f2, 33*8(sp) /* Store ft2 */
+ fsw f3, 34*8(sp) /* Store ft3 */
+ fsw f4, 35*8(sp) /* Store ft4 */
+ fsw f5, 36*8(sp) /* Store ft5 */
+ fsw f6, 37*8(sp) /* Store ft6 */
+ fsw f7, 38*8(sp) /* Store ft7 */
+ fsw f10,41*8(sp) /* Store fa0 */
+ fsw f11,42*8(sp) /* Store fa1 */
+ fsw f12,43*8(sp) /* Store fa2 */
+ fsw f13,44*8(sp) /* Store fa3 */
+ fsw f14,45*8(sp) /* Store fa4 */
+ fsw f15,46*8(sp) /* Store fa5 */
+ fsw f16,47*8(sp) /* Store fa6 */
+ fsw f17,48*8(sp) /* Store fa7 */
+ fsw f28,59*8(sp) /* Store ft8 */
+ fsw f29,60*8(sp) /* Store ft9 */
+ fsw f30,61*8(sp) /* Store ft10 */
+ fsw f31,62*8(sp) /* Store ft11 */
csrr t0, fcsr
- STORE t0, 63*REGBYTES(sp) // Store fcsr
+ sd t0, 63*8(sp) /* Store fcsr */
#elif defined(__riscv_float_abi_double)
- fsd f0, 31*REGBYTES(sp) // Store ft0
- fsd f1, 32*REGBYTES(sp) // Store ft1
- fsd f2, 33*REGBYTES(sp) // Store ft2
- fsd f3, 34*REGBYTES(sp) // Store ft3
- fsd f4, 35*REGBYTES(sp) // Store ft4
- fsd f5, 36*REGBYTES(sp) // Store ft5
- fsd f6, 37*REGBYTES(sp) // Store ft6
- fsd f7, 38*REGBYTES(sp) // Store ft7
- fsd f10,41*REGBYTES(sp) // Store fa0
- fsd f11,42*REGBYTES(sp) // Store fa1
- fsd f12,43*REGBYTES(sp) // Store fa2
- fsd f13,44*REGBYTES(sp) // Store fa3
- fsd f14,45*REGBYTES(sp) // Store fa4
- fsd f15,46*REGBYTES(sp) // Store fa5
- fsd f16,47*REGBYTES(sp) // Store fa6
- fsd f17,48*REGBYTES(sp) // Store fa7
- fsd f28,59*REGBYTES(sp) // Store ft8
- fsd f29,60*REGBYTES(sp) // Store ft9
- fsd f30,61*REGBYTES(sp) // Store ft10
- fsd f31,62*REGBYTES(sp) // Store ft11
+ fsd f0, 31*8(sp) /* Store ft0 */
+ fsd f1, 32*8(sp) /* Store ft1 */
+ fsd f2, 33*8(sp) /* Store ft2 */
+ fsd f3, 34*8(sp) /* Store ft3 */
+ fsd f4, 35*8(sp) /* Store ft4 */
+ fsd f5, 36*8(sp) /* Store ft5 */
+ fsd f6, 37*8(sp) /* Store ft6 */
+ fsd f7, 38*8(sp) /* Store ft7 */
+ fsd f10,41*8(sp) /* Store fa0 */
+ fsd f11,42*8(sp) /* Store fa1 */
+ fsd f12,43*8(sp) /* Store fa2 */
+ fsd f13,44*8(sp) /* Store fa3 */
+ fsd f14,45*8(sp) /* Store fa4 */
+ fsd f15,46*8(sp) /* Store fa5 */
+ fsd f16,47*8(sp) /* Store fa6 */
+ fsd f17,48*8(sp) /* Store fa7 */
+ fsd f28,59*8(sp) /* Store ft8 */
+ fsd f29,60*8(sp) /* Store ft9 */
+ fsd f30,61*8(sp) /* Store ft10 */
+ fsd f31,62*8(sp) /* Store ft11 */
csrr t0, fcsr
- STORE t0, 63*REGBYTES(sp) // Store fcsr
+ sd t0, 63*8(sp) /* Store fcsr */
#endif
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
- call _tx_execution_isr_enter // Call the ISR execution enter function
+ call _tx_execution_isr_enter /* Call the ISR execution enter function */
#endif
- ret // Return to calling ISR
+ ret /* Return to calling ISR */
_tx_thread_not_nested_save:
/* } */
@@ -165,81 +152,159 @@ _tx_thread_not_nested_save:
/* Otherwise, not nested, check to see if a thread was running. */
/* else if (_tx_thread_current_ptr)
{ */
- addi x6, x6, 1 // Increment the interrupt counter
- STORE x6, 0(x5) // Store the interrupt counter
+ addi t1, t1, 1 /* Increment the interrupt counter */
+ sd t1, 0(t0) /* Store the interrupt counter */
/* Not nested: Find the user thread that was running and load our SP */
- LOAD x5, _tx_thread_current_ptr // Pickup current thread pointer
- beqz x5, _tx_thread_idle_system_save // If NULL, idle system was interrupted
+ la t0, _tx_thread_current_ptr /* Pickup current thread pointer address */
+ ld t0, 0(t0) /* Pickup current thread pointer */
+ beqz t0, _tx_thread_idle_system_save /* If NULL, idle system was interrupted */
/* Save the standard scratch registers. */
- STORE x7, 17*REGBYTES(sp) // Store t2
- STORE x8, 12*REGBYTES(sp) // Store s0
- STORE x10, 27*REGBYTES(sp) // Store a0
- STORE x11, 26*REGBYTES(sp) // Store a1
- STORE x12, 25*REGBYTES(sp) // Store a2
- STORE x13, 24*REGBYTES(sp) // Store a3
- STORE x14, 23*REGBYTES(sp) // Store a4
- STORE x15, 22*REGBYTES(sp) // Store a5
- STORE x16, 21*REGBYTES(sp) // Store a6
- STORE x17, 20*REGBYTES(sp) // Store a7
- STORE x28, 16*REGBYTES(sp) // Store t3
- STORE x29, 15*REGBYTES(sp) // Store t4
- STORE x30, 14*REGBYTES(sp) // Store t5
- STORE x31, 13*REGBYTES(sp) // Store t6
+ sd t2, 17*8(sp) /* Store t2 */
+ sd s0, 12*8(sp) /* Store s0 */
+ sd a0, 27*8(sp) /* Store a0 */
+ sd a1, 26*8(sp) /* Store a1 */
+ sd a2, 25*8(sp) /* Store a2 */
+ sd a3, 24*8(sp) /* Store a3 */
+ sd a4, 23*8(sp) /* Store a4 */
+ sd a5, 22*8(sp) /* Store a5 */
+ sd a6, 21*8(sp) /* Store a6 */
+ sd a7, 20*8(sp) /* Store a7 */
+ sd t3, 16*8(sp) /* Store t3 */
+ sd t4, 15*8(sp) /* Store t4 */
+ sd t5, 14*8(sp) /* Store t5 */
+ sd t6, 13*8(sp) /* Store t6 */
+
+ csrr t1, mepc /* Load exception program counter */
+ sd t1, 30*8(sp) /* Save it on the stack */
+
+ /* Save floating point scratch registers if floating point is enabled. */
+#ifdef __riscv_float_abi_single
+ fsw f0, 31*8(sp) /* Store ft0 */
+ fsw f1, 32*8(sp) /* Store ft1 */
+ fsw f2, 33*8(sp) /* Store ft2 */
+ fsw f3, 34*8(sp) /* Store ft3 */
+ fsw f4, 35*8(sp) /* Store ft4 */
+ fsw f5, 36*8(sp) /* Store ft5 */
+ fsw f6, 37*8(sp) /* Store ft6 */
+ fsw f7, 38*8(sp) /* Store ft7 */
+ fsw f10,41*8(sp) /* Store fa0 */
+ fsw f11,42*8(sp) /* Store fa1 */
+ fsw f12,43*8(sp) /* Store fa2 */
+ fsw f13,44*8(sp) /* Store fa3 */
+ fsw f14,45*8(sp) /* Store fa4 */
+ fsw f15,46*8(sp) /* Store fa5 */
+ fsw f16,47*8(sp) /* Store fa6 */
+ fsw f17,48*8(sp) /* Store fa7 */
+ fsw f28,59*8(sp) /* Store ft8 */
+ fsw f29,60*8(sp) /* Store ft9 */
+ fsw f30,61*8(sp) /* Store ft10 */
+ fsw f31,62*8(sp) /* Store ft11 */
+ csrr t0, fcsr
+ sd t0, 63*8(sp) /* Store fcsr */
+#elif defined(__riscv_float_abi_double)
+ fsd f0, 31*8(sp) /* Store ft0 */
+ fsd f1, 32*8(sp) /* Store ft1 */
+ fsd f2, 33*8(sp) /* Store ft2 */
+ fsd f3, 34*8(sp) /* Store ft3 */
+ fsd f4, 35*8(sp) /* Store ft4 */
+ fsd f5, 36*8(sp) /* Store ft5 */
+ fsd f6, 37*8(sp) /* Store ft6 */
+ fsd f7, 38*8(sp) /* Store ft7 */
+ fsd f10,41*8(sp) /* Store fa0 */
+ fsd f11,42*8(sp) /* Store fa1 */
+ fsd f12,43*8(sp) /* Store fa2 */
+ fsd f13,44*8(sp) /* Store fa3 */
+ fsd f14,45*8(sp) /* Store fa4 */
+ fsd f15,46*8(sp) /* Store fa5 */
+ fsd f16,47*8(sp) /* Store fa6 */
+ fsd f17,48*8(sp) /* Store fa7 */
+ fsd f28,59*8(sp) /* Store ft8 */
+ fsd f29,60*8(sp) /* Store ft9 */
+ fsd f30,61*8(sp) /* Store ft10 */
+ fsd f31,62*8(sp) /* Store ft11 */
+ csrr t0, fcsr
+ sd t0, 63*8(sp) /* Store fcsr */
+#endif
+
+ /* Save the current stack pointer in the thread's control block. */
+ /* _tx_thread_current_ptr -> tx_thread_stack_ptr = sp; */
+
+ /* Switch to the system stack. */
+ /* sp = _tx_thread_system_stack_ptr; */
+
+ la t1, _tx_thread_current_ptr /* Pickup current thread pointer address */
+ ld t1, 0(t1) /* Pickup current thread pointer */
+ sd sp, 16(t1) /* Save stack pointer */
+
+#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
+ /* _tx_execution_isr_enter is called with thread stack pointer */
+ call _tx_execution_isr_enter /* Call the ISR execution enter function */
+#endif
+
+ la t0, _tx_thread_system_stack_ptr /* Pickup system stack pointer address */
+ ld sp, 0(t0) /* Switch to system stack */
+ ret /* Return to calling ISR */
+
+ sd x17, 20*8(sp) // Store a7
+ sd x28, 16*8(sp) // Store t3
+ sd x29, 15*8(sp) // Store t4
+ sd x30, 14*8(sp) // Store t5
+ sd x31, 13*8(sp) // Store t6
csrr t0, mepc // Load exception program counter
- STORE t0, 30*REGBYTES(sp) // Save it on the stack
+ sd t0, 30*8(sp) // Save it on the stack
/* Save floating point scratch registers. */
#if defined(__riscv_float_abi_single)
- fsw f0, 31*REGBYTES(sp) // Store ft0
- fsw f1, 32*REGBYTES(sp) // Store ft1
- fsw f2, 33*REGBYTES(sp) // Store ft2
- fsw f3, 34*REGBYTES(sp) // Store ft3
- fsw f4, 35*REGBYTES(sp) // Store ft4
- fsw f5, 36*REGBYTES(sp) // Store ft5
- fsw f6, 37*REGBYTES(sp) // Store ft6
- fsw f7, 38*REGBYTES(sp) // Store ft7
- fsw f10,41*REGBYTES(sp) // Store fa0
- fsw f11,42*REGBYTES(sp) // Store fa1
- fsw f12,43*REGBYTES(sp) // Store fa2
- fsw f13,44*REGBYTES(sp) // Store fa3
- fsw f14,45*REGBYTES(sp) // Store fa4
- fsw f15,46*REGBYTES(sp) // Store fa5
- fsw f16,47*REGBYTES(sp) // Store fa6
- fsw f17,48*REGBYTES(sp) // Store fa7
- fsw f28,59*REGBYTES(sp) // Store ft8
- fsw f29,60*REGBYTES(sp) // Store ft9
- fsw f30,61*REGBYTES(sp) // Store ft10
- fsw f31,62*REGBYTES(sp) // Store ft11
+ fsw f0, 31*8(sp) // Store ft0
+ fsw f1, 32*8(sp) // Store ft1
+ fsw f2, 33*8(sp) // Store ft2
+ fsw f3, 34*8(sp) // Store ft3
+ fsw f4, 35*8(sp) // Store ft4
+ fsw f5, 36*8(sp) // Store ft5
+ fsw f6, 37*8(sp) // Store ft6
+ fsw f7, 38*8(sp) // Store ft7
+ fsw f10,41*8(sp) // Store fa0
+ fsw f11,42*8(sp) // Store fa1
+ fsw f12,43*8(sp) // Store fa2
+ fsw f13,44*8(sp) // Store fa3
+ fsw f14,45*8(sp) // Store fa4
+ fsw f15,46*8(sp) // Store fa5
+ fsw f16,47*8(sp) // Store fa6
+ fsw f17,48*8(sp) // Store fa7
+ fsw f28,59*8(sp) // Store ft8
+ fsw f29,60*8(sp) // Store ft9
+ fsw f30,61*8(sp) // Store ft10
+ fsw f31,62*8(sp) // Store ft11
csrr t0, fcsr
- STORE t0, 63*REGBYTES(sp) // Store fcsr
+ sd t0, 63*8(sp) // Store fcsr
#elif defined(__riscv_float_abi_double)
- fsd f0, 31*REGBYTES(sp) // Store ft0
- fsd f1, 32*REGBYTES(sp) // Store ft1
- fsd f2, 33*REGBYTES(sp) // Store ft2
- fsd f3, 34*REGBYTES(sp) // Store ft3
- fsd f4, 35*REGBYTES(sp) // Store ft4
- fsd f5, 36*REGBYTES(sp) // Store ft5
- fsd f6, 37*REGBYTES(sp) // Store ft6
- fsd f7, 38*REGBYTES(sp) // Store ft7
- fsd f10,41*REGBYTES(sp) // Store fa0
- fsd f11,42*REGBYTES(sp) // Store fa1
- fsd f12,43*REGBYTES(sp) // Store fa2
- fsd f13,44*REGBYTES(sp) // Store fa3
- fsd f14,45*REGBYTES(sp) // Store fa4
- fsd f15,46*REGBYTES(sp) // Store fa5
- fsd f16,47*REGBYTES(sp) // Store fa6
- fsd f17,48*REGBYTES(sp) // Store fa7
- fsd f28,59*REGBYTES(sp) // Store ft8
- fsd f29,60*REGBYTES(sp) // Store ft9
- fsd f30,61*REGBYTES(sp) // Store ft10
- fsd f31,62*REGBYTES(sp) // Store ft11
+ fsd f0, 31*8(sp) // Store ft0
+ fsd f1, 32*8(sp) // Store ft1
+ fsd f2, 33*8(sp) // Store ft2
+ fsd f3, 34*8(sp) // Store ft3
+ fsd f4, 35*8(sp) // Store ft4
+ fsd f5, 36*8(sp) // Store ft5
+ fsd f6, 37*8(sp) // Store ft6
+ fsd f7, 38*8(sp) // Store ft7
+ fsd f10,41*8(sp) // Store fa0
+ fsd f11,42*8(sp) // Store fa1
+ fsd f12,43*8(sp) // Store fa2
+ fsd f13,44*8(sp) // Store fa3
+ fsd f14,45*8(sp) // Store fa4
+ fsd f15,46*8(sp) // Store fa5
+ fsd f16,47*8(sp) // Store fa6
+ fsd f17,48*8(sp) // Store fa7
+ fsd f28,59*8(sp) // Store ft8
+ fsd f29,60*8(sp) // Store ft9
+ fsd f30,61*8(sp) // Store ft10
+ fsd f31,62*8(sp) // Store ft11
csrr t0, fcsr
- STORE t0, 63*REGBYTES(sp) // Store fcsr
+ sd t0, 63*8(sp) // Store fcsr
#endif
/* Save the current stack pointer in the thread's control block. */
@@ -248,8 +313,9 @@ _tx_thread_not_nested_save:
/* Switch to the system stack. */
/* sp = _tx_thread_system_stack_ptr; */
- LOAD t1, _tx_thread_current_ptr // Pickup current thread pointer
- STORE sp, 2*REGBYTES(t1) // Save stack pointer
+ la x5, _tx_thread_current_ptr // Pickup current thread pointer address
+ ld t1, 0(x5) // Pickup current thread pointer
+ sd sp, 16(t1) // Save stack pointer
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
/* _tx_execution_isr_enter is called with thread stack pointer */
@@ -257,7 +323,8 @@ _tx_thread_not_nested_save:
#endif
- LOAD sp, _tx_thread_system_stack_ptr // Switch to system stack
+ la x5, _tx_thread_system_stack_ptr // Pickup system stack pointer address
+ ld sp, 0(x5) // Switch to system stack
ret // Return to calling ISR
/* }
@@ -276,8 +343,8 @@ _tx_thread_idle_system_save:
/* }
} */
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
- addi sp, sp, 65*REGBYTES // Recover stack frame - with floating point enabled
+ addi sp, sp, 65*8 // Recover stack frame - with floating point enabled
#else
- addi sp, sp, 32*REGBYTES // Recover the reserved stack space
+ addi sp, sp, 32*8 // Recover the reserved stack space
#endif
ret // Return to calling ISR
diff --git a/ports/risc-v64/gnu/src/tx_thread_interrupt_control.S b/ports/risc-v64/gnu/src/tx_thread_interrupt_control.S
index c75c7c47..57b25a52 100644
--- a/ports/risc-v64/gnu/src/tx_thread_interrupt_control.S
+++ b/ports/risc-v64/gnu/src/tx_thread_interrupt_control.S
@@ -19,8 +19,8 @@
/**************************************************************************/
/**************************************************************************/
- RETURN_MASK = 0x000000000000000F
- SET_SR_MASK = 0xFFFFFFFFFFFFFFF0
+ /* Define which mstatus bits this function will modify/return. */
+ /* MSTATUS_MIE bit 3 = Machine Interrupt Enable */
.section .text
/**************************************************************************/
@@ -66,16 +66,20 @@
.global _tx_thread_interrupt_control
_tx_thread_interrupt_control:
/* Pickup current interrupt lockout posture. */
+ /* old_mstatus = mstatus; */
csrr t0, mstatus
- mv t1, t0 // Save original mstatus for return
+ mv t1, t0 /* Save original mstatus for return */
- /* Apply the new interrupt posture. */
-
- li t2, SET_SR_MASK // Build set SR mask
- and t0, t0, t2 // Isolate interrupt lockout bits
- or t0, t0, a0 // Put new lockout bits in
+ /* Apply the new interrupt posture while preserving unrelated mstatus bits. */
+ /* Only modify the MIE bit (bit 3) */
+ /* mstatus = (mstatus & ~MIE) | (new_posture & MIE); */
+
+ li t2, ~0x08 /* Build mask to clear MIE */
+ and t0, t0, t2 /* Clear MIE bit */
+ and a0, a0, 0x08 /* Mask incoming to only MIE bit */
+ or t0, t0, a0 /* Set requested MIE state */
csrw mstatus, t0
- andi a0, t1, RETURN_MASK // Return original mstatus.
+ andi a0, t1, 0x08 /* Return original MIE bit */
ret
/* } */
diff --git a/ports/risc-v64/gnu/src/tx_thread_schedule.S b/ports/risc-v64/gnu/src/tx_thread_schedule.S
index c9be4c6f..4da4c244 100644
--- a/ports/risc-v64/gnu/src/tx_thread_schedule.S
+++ b/ports/risc-v64/gnu/src/tx_thread_schedule.S
@@ -19,8 +19,6 @@
/**************************************************************************/
/**************************************************************************/
-#include "tx_port.h"
-
.section .text
/**************************************************************************/
/* */
@@ -69,236 +67,254 @@
_tx_thread_schedule:
/* Enable interrupts. */
- csrsi mstatus, 0x08 // Enable interrupts
+ /* mstatus |= MIE; */
+ csrsi mstatus, 0x08 /* Enable interrupts (MIE bit 3) */
/* Wait for a thread to execute. */
/* do
{ */
- la t0, _tx_thread_execute_ptr // Pickup address of execute ptr
+ la t0, _tx_thread_execute_ptr /* Pickup address of execute ptr */
_tx_thread_schedule_loop:
- LOAD t1, 0(t0) // Pickup next thread to execute
- beqz t1, _tx_thread_schedule_loop // If NULL, wait for thread to execute
+ ld t1, 0(t0) /* Pickup next thread to execute */
+
+/* TX_USE_WFI_IDLE Configuration:
+ When defined, the scheduler enters WFI (Wait-For-Interrupt) mode when
+ no threads are ready, reducing power consumption. The core will wake
+ on any enabled interrupt. This is recommended for battery-powered or
+ low-power applications. Define TX_USE_WFI_IDLE in tx_user.h or via
+ compiler flags to enable this feature. */
+#ifdef TX_USE_WFI_IDLE
+ beqz t1, 1f
+ j 2f
+1: wfi
+ j _tx_thread_schedule_loop
+2:
+ beqz t1, _tx_thread_schedule_loop /* Fallback: If still NULL, loop */
+#else
+ beqz t1, _tx_thread_schedule_loop /* If NULL, wait for thread to execute */
+#endif
/* }
- while(_tx_thread_execute_ptr == TX_NULL); */
+ while(_tx_thread_execute_ptr == NULL); */
/* Yes! We have a thread to execute. Lockout interrupts and
transfer control to it. */
- csrci mstatus, 0x08 // Lockout interrupts
+ csrci mstatus, 0x08 /* Lockout interrupts */
/* Setup the current thread pointer. */
/* _tx_thread_current_ptr = _tx_thread_execute_ptr; */
- la t0, _tx_thread_current_ptr // Pickup current thread pointer address
- STORE t1, 0(t0) // Set current thread pointer
+ la t0, _tx_thread_current_ptr /* Pickup current thread pointer address */
+ sd t1, 0(t0) /* Set current thread pointer */
/* Increment the run count for this thread. */
/* _tx_thread_current_ptr -> tx_thread_run_count++; */
- LOAD t2, 1*REGBYTES(t1) // Pickup run count
- LOAD t3, 6*REGBYTES(t1) // Pickup time slice value
- addi t2, t2, 1 // Increment run count
- STORE t2, 1*REGBYTES(t1) // Store new run count
+ ld t2, 8(t1) /* Pickup run count */
+ ld t3, 48(t1) /* Pickup time slice value */
+ addi t2, t2, 1 /* Increment run count */
+ sd t2, 8(t1) /* Store new run count */
/* Setup time-slice, if present. */
/* _tx_timer_time_slice = _tx_thread_current_ptr -> tx_thread_time_slice; */
- la t2, _tx_timer_time_slice // Pickup time-slice variable address
+ la t2, _tx_timer_time_slice /* Pickup time-slice variable address */
/* Switch to the thread's stack. */
/* SP = _tx_thread_execute_ptr -> tx_thread_stack_ptr; */
- LOAD sp, 2*REGBYTES(t1) // Switch to thread's stack
- STORE t3, 0(t2) // Store new time-slice*/
+ ld sp, 16(t1) /* Switch to thread's stack */
+ sd t3, 0(t2) /* Store new time-slice*/
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
- call _tx_execution_thread_enter // Call the thread execution enter function
+ call _tx_execution_thread_enter /* Call the thread execution enter function */
#endif
/* Determine if an interrupt frame or a synchronous task suspension frame
is present. */
- LOAD t2, 0(sp) // Pickup stack type
- beqz t2, _tx_thread_synch_return // If 0, solicited thread return
+ ld t2, 0(sp) /* Pickup stack type */
+ beqz t2, _tx_thread_synch_return /* If 0, solicited thread return */
/* Determine if floating point registers need to be recovered. */
#if defined(__riscv_float_abi_single)
- flw f0, 31*REGBYTES(sp) // Recover ft0
- flw f1, 32*REGBYTES(sp) // Recover ft1
- flw f2, 33*REGBYTES(sp) // Recover ft2
- flw f3, 34*REGBYTES(sp) // Recover ft3
- flw f4, 35*REGBYTES(sp) // Recover ft4
- flw f5, 36*REGBYTES(sp) // Recover ft5
- flw f6, 37*REGBYTES(sp) // Recover ft6
- flw f7, 38*REGBYTES(sp) // Recover ft7
- flw f8, 39*REGBYTES(sp) // Recover fs0
- flw f9, 40*REGBYTES(sp) // Recover fs1
- flw f10,41*REGBYTES(sp) // Recover fa0
- flw f11,42*REGBYTES(sp) // Recover fa1
- flw f12,43*REGBYTES(sp) // Recover fa2
- flw f13,44*REGBYTES(sp) // Recover fa3
- flw f14,45*REGBYTES(sp) // Recover fa4
- flw f15,46*REGBYTES(sp) // Recover fa5
- flw f16,47*REGBYTES(sp) // Recover fa6
- flw f17,48*REGBYTES(sp) // Recover fa7
- flw f18,49*REGBYTES(sp) // Recover fs2
- flw f19,50*REGBYTES(sp) // Recover fs3
- flw f20,51*REGBYTES(sp) // Recover fs4
- flw f21,52*REGBYTES(sp) // Recover fs5
- flw f22,53*REGBYTES(sp) // Recover fs6
- flw f23,54*REGBYTES(sp) // Recover fs7
- flw f24,55*REGBYTES(sp) // Recover fs8
- flw f25,56*REGBYTES(sp) // Recover fs9
- flw f26,57*REGBYTES(sp) // Recover fs10
- flw f27,58*REGBYTES(sp) // Recover fs11
- flw f28,59*REGBYTES(sp) // Recover ft8
- flw f29,60*REGBYTES(sp) // Recover ft9
- flw f30,61*REGBYTES(sp) // Recover ft10
- flw f31,62*REGBYTES(sp) // Recover ft11
- LOAD t0, 63*REGBYTES(sp) // Recover fcsr
- csrw fcsr, t0 //
+ flw f0, 31*8(sp) /* Recover ft0 */
+ flw f1, 32*8(sp) /* Recover ft1 */
+ flw f2, 33*8(sp) /* Recover ft2 */
+ flw f3, 34*8(sp) /* Recover ft3 */
+ flw f4, 35*8(sp) /* Recover ft4 */
+ flw f5, 36*8(sp) /* Recover ft5 */
+ flw f6, 37*8(sp) /* Recover ft6 */
+ flw f7, 38*8(sp) /* Recover ft7 */
+ flw f8, 39*8(sp) /* Recover fs0 */
+ flw f9, 40*8(sp) /* Recover fs1 */
+ flw f10,41*8(sp) /* Recover fa0 */
+ flw f11,42*8(sp) /* Recover fa1 */
+ flw f12,43*8(sp) /* Recover fa2 */
+ flw f13,44*8(sp) /* Recover fa3 */
+ flw f14,45*8(sp) /* Recover fa4 */
+ flw f15,46*8(sp) /* Recover fa5 */
+ flw f16,47*8(sp) /* Recover fa6 */
+ flw f17,48*8(sp) /* Recover fa7 */
+ flw f18,49*8(sp) /* Recover fs2 */
+ flw f19,50*8(sp) /* Recover fs3 */
+ flw f20,51*8(sp) /* Recover fs4 */
+ flw f21,52*8(sp) /* Recover fs5 */
+ flw f22,53*8(sp) /* Recover fs6 */
+ flw f23,54*8(sp) /* Recover fs7 */
+ flw f24,55*8(sp) /* Recover fs8 */
+ flw f25,56*8(sp) /* Recover fs9 */
+ flw f26,57*8(sp) /* Recover fs10 */
+ flw f27,58*8(sp) /* Recover fs11 */
+ flw f28,59*8(sp) /* Recover ft8 */
+ flw f29,60*8(sp) /* Recover ft9 */
+ flw f30,61*8(sp) /* Recover ft10 */
+ flw f31,62*8(sp) /* Recover ft11 */
+ ld t0, 63*8(sp) /* Recover fcsr */
+ csrw fcsr, t0 /* Restore fcsr */
#elif defined(__riscv_float_abi_double)
- fld f0, 31*REGBYTES(sp) // Recover ft0
- fld f1, 32*REGBYTES(sp) // Recover ft1
- fld f2, 33*REGBYTES(sp) // Recover ft2
- fld f3, 34*REGBYTES(sp) // Recover ft3
- fld f4, 35*REGBYTES(sp) // Recover ft4
- fld f5, 36*REGBYTES(sp) // Recover ft5
- fld f6, 37*REGBYTES(sp) // Recover ft6
- fld f7, 38*REGBYTES(sp) // Recover ft7
- fld f8, 39*REGBYTES(sp) // Recover fs0
- fld f9, 40*REGBYTES(sp) // Recover fs1
- fld f10,41*REGBYTES(sp) // Recover fa0
- fld f11,42*REGBYTES(sp) // Recover fa1
- fld f12,43*REGBYTES(sp) // Recover fa2
- fld f13,44*REGBYTES(sp) // Recover fa3
- fld f14,45*REGBYTES(sp) // Recover fa4
- fld f15,46*REGBYTES(sp) // Recover fa5
- fld f16,47*REGBYTES(sp) // Recover fa6
- fld f17,48*REGBYTES(sp) // Recover fa7
- fld f18,49*REGBYTES(sp) // Recover fs2
- fld f19,50*REGBYTES(sp) // Recover fs3
- fld f20,51*REGBYTES(sp) // Recover fs4
- fld f21,52*REGBYTES(sp) // Recover fs5
- fld f22,53*REGBYTES(sp) // Recover fs6
- fld f23,54*REGBYTES(sp) // Recover fs7
- fld f24,55*REGBYTES(sp) // Recover fs8
- fld f25,56*REGBYTES(sp) // Recover fs9
- fld f26,57*REGBYTES(sp) // Recover fs10
- fld f27,58*REGBYTES(sp) // Recover fs11
- fld f28,59*REGBYTES(sp) // Recover ft8
- fld f29,60*REGBYTES(sp) // Recover ft9
- fld f30,61*REGBYTES(sp) // Recover ft10
- fld f31,62*REGBYTES(sp) // Recover ft11
- LOAD t0, 63*REGBYTES(sp) // Recover fcsr
+ fld f0, 31*8(sp) // Recover ft0
+ fld f1, 32*8(sp) // Recover ft1
+ fld f2, 33*8(sp) // Recover ft2
+ fld f3, 34*8(sp) // Recover ft3
+ fld f4, 35*8(sp) // Recover ft4
+ fld f5, 36*8(sp) // Recover ft5
+ fld f6, 37*8(sp) // Recover ft6
+ fld f7, 38*8(sp) // Recover ft7
+ fld f8, 39*8(sp) // Recover fs0
+ fld f9, 40*8(sp) // Recover fs1
+ fld f10,41*8(sp) // Recover fa0
+ fld f11,42*8(sp) // Recover fa1
+ fld f12,43*8(sp) // Recover fa2
+ fld f13,44*8(sp) // Recover fa3
+ fld f14,45*8(sp) // Recover fa4
+ fld f15,46*8(sp) // Recover fa5
+ fld f16,47*8(sp) // Recover fa6
+ fld f17,48*8(sp) // Recover fa7
+ fld f18,49*8(sp) // Recover fs2
+ fld f19,50*8(sp) // Recover fs3
+ fld f20,51*8(sp) // Recover fs4
+ fld f21,52*8(sp) // Recover fs5
+ fld f22,53*8(sp) // Recover fs6
+ fld f23,54*8(sp) // Recover fs7
+ fld f24,55*8(sp) // Recover fs8
+ fld f25,56*8(sp) // Recover fs9
+ fld f26,57*8(sp) // Recover fs10
+ fld f27,58*8(sp) // Recover fs11
+ fld f28,59*8(sp) // Recover ft8
+ fld f29,60*8(sp) // Recover ft9
+ fld f30,61*8(sp) // Recover ft10
+ fld f31,62*8(sp) // Recover ft11
+ ld t0, 63*8(sp) // Recover fcsr
+ csrw fcsr, t0 //
#endif
/* Recover standard registers. */
- LOAD t0, 30*REGBYTES(sp) // Recover mepc
- csrw mepc, t0 // Store mepc
- li t0, 0x1880 // Prepare MPIP
+ ld t0, 30*8(sp) /* Recover mepc */
+ csrw mepc, t0 /* Store mepc */
+ li t0, 0x1880 /* Prepare mstatus: MPP=Machine(0x1800) | MPIE(0x80) */
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
- li t1, 1<<13
- or t0, t1, t0
+ li t1, 0x2000 /* Set FS bits for FP state */
+ or t0, t0, t1
#endif
- csrw mstatus, t0 // Enable MPIP
+ csrw mstatus, t0 /* Set mstatus */
- LOAD x1, 28*REGBYTES(sp) // Recover RA
- LOAD x5, 19*REGBYTES(sp) // Recover t0
- LOAD x6, 18*REGBYTES(sp) // Recover t1
- LOAD x7, 17*REGBYTES(sp) // Recover t2
- LOAD x8, 12*REGBYTES(sp) // Recover s0
- LOAD x9, 11*REGBYTES(sp) // Recover s1
- LOAD x10, 27*REGBYTES(sp) // Recover a0
- LOAD x11, 26*REGBYTES(sp) // Recover a1
- LOAD x12, 25*REGBYTES(sp) // Recover a2
- LOAD x13, 24*REGBYTES(sp) // Recover a3
- LOAD x14, 23*REGBYTES(sp) // Recover a4
- LOAD x15, 22*REGBYTES(sp) // Recover a5
- LOAD x16, 21*REGBYTES(sp) // Recover a6
- LOAD x17, 20*REGBYTES(sp) // Recover a7
- LOAD x18, 10*REGBYTES(sp) // Recover s2
- LOAD x19, 9*REGBYTES(sp) // Recover s3
- LOAD x20, 8*REGBYTES(sp) // Recover s4
- LOAD x21, 7*REGBYTES(sp) // Recover s5
- LOAD x22, 6*REGBYTES(sp) // Recover s6
- LOAD x23, 5*REGBYTES(sp) // Recover s7
- LOAD x24, 4*REGBYTES(sp) // Recover s8
- LOAD x25, 3*REGBYTES(sp) // Recover s9
- LOAD x26, 2*REGBYTES(sp) // Recover s10
- LOAD x27, 1*REGBYTES(sp) // Recover s11
- LOAD x28, 16*REGBYTES(sp) // Recover t3
- LOAD x29, 15*REGBYTES(sp) // Recover t4
- LOAD x30, 14*REGBYTES(sp) // Recover t5
- LOAD x31, 13*REGBYTES(sp) // Recover t6
+ ld ra, 28*8(sp) /* Recover return address */
+ ld t0, 19*8(sp) /* Recover t0 */
+ ld t1, 18*8(sp) /* Recover t1 */
+ ld t2, 17*8(sp) /* Recover t2 */
+ ld s0, 12*8(sp) /* Recover s0 */
+ ld s1, 11*8(sp) /* Recover s1 */
+ ld a0, 27*8(sp) /* Recover a0 */
+ ld a1, 26*8(sp) /* Recover a1 */
+ ld a2, 25*8(sp) /* Recover a2 */
+ ld a3, 24*8(sp) /* Recover a3 */
+ ld a4, 23*8(sp) /* Recover a4 */
+ ld a5, 22*8(sp) /* Recover a5 */
+ ld a6, 21*8(sp) /* Recover a6 */
+ ld a7, 20*8(sp) /* Recover a7 */
+ ld s2, 10*8(sp) /* Recover s2 */
+ ld s3, 9*8(sp) /* Recover s3 */
+ ld s4, 8*8(sp) /* Recover s4 */
+ ld s5, 7*8(sp) /* Recover s5 */
+ ld s6, 6*8(sp) /* Recover s6 */
+ ld s7, 5*8(sp) /* Recover s7 */
+ ld s8, 4*8(sp) /* Recover s8 */
+ ld s9, 3*8(sp) /* Recover s9 */
+ ld s10, 2*8(sp) /* Recover s10 */
+ ld s11, 1*8(sp) /* Recover s11 */
+ ld t3, 16*8(sp) /* Recover t3 */
+ ld t4, 15*8(sp) /* Recover t4 */
+ ld t5, 14*8(sp) /* Recover t5 */
+ ld t6, 13*8(sp) /* Recover t6 */
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
- addi sp, sp, 65*REGBYTES // Recover stack frame - with floating point registers
+ addi sp, sp, 65*8 // Recover stack frame - with floating point registers
#else
- addi sp, sp, 32*REGBYTES // Recover stack frame - without floating point registers
+ addi sp, sp, 32*8 // Recover stack frame - without floating point registers
#endif
mret // Return to point of interrupt
_tx_thread_synch_return:
#if defined(__riscv_float_abi_single)
- flw f8, 15*REGBYTES(sp) // Recover fs0
- flw f9, 16*REGBYTES(sp) // Recover fs1
- flw f18,17*REGBYTES(sp) // Recover fs2
- flw f19,18*REGBYTES(sp) // Recover fs3
- flw f20,19*REGBYTES(sp) // Recover fs4
- flw f21,20*REGBYTES(sp) // Recover fs5
- flw f22,21*REGBYTES(sp) // Recover fs6
- flw f23,22*REGBYTES(sp) // Recover fs7
- flw f24,23*REGBYTES(sp) // Recover fs8
- flw f25,24*REGBYTES(sp) // Recover fs9
- flw f26,25*REGBYTES(sp) // Recover fs10
- flw f27,26*REGBYTES(sp) // Recover fs11
- LOAD t0, 27*REGBYTES(sp) // Recover fcsr
+ flw f8, 15*8(sp) // Recover fs0
+ flw f9, 16*8(sp) // Recover fs1
+ flw f18,17*8(sp) // Recover fs2
+ flw f19,18*8(sp) // Recover fs3
+ flw f20,19*8(sp) // Recover fs4
+ flw f21,20*8(sp) // Recover fs5
+ flw f22,21*8(sp) // Recover fs6
+ flw f23,22*8(sp) // Recover fs7
+ flw f24,23*8(sp) // Recover fs8
+ flw f25,24*8(sp) // Recover fs9
+ flw f26,25*8(sp) // Recover fs10
+ flw f27,26*8(sp) // Recover fs11
+ ld t0, 27*8(sp) // Recover fcsr
csrw fcsr, t0 //
#elif defined(__riscv_float_abi_double)
- fld f8, 15*REGBYTES(sp) // Recover fs0
- fld f9, 16*REGBYTES(sp) // Recover fs1
- fld f18,17*REGBYTES(sp) // Recover fs2
- fld f19,18*REGBYTES(sp) // Recover fs3
- fld f20,19*REGBYTES(sp) // Recover fs4
- fld f21,20*REGBYTES(sp) // Recover fs5
- fld f22,21*REGBYTES(sp) // Recover fs6
- fld f23,22*REGBYTES(sp) // Recover fs7
- fld f24,23*REGBYTES(sp) // Recover fs8
- fld f25,24*REGBYTES(sp) // Recover fs9
- fld f26,25*REGBYTES(sp) // Recover fs10
- fld f27,26*REGBYTES(sp) // Recover fs11
- LOAD t0, 27*REGBYTES(sp) // Recover fcsr
+ fld f8, 15*8(sp) // Recover fs0
+ fld f9, 16*8(sp) // Recover fs1
+ fld f18,17*8(sp) // Recover fs2
+ fld f19,18*8(sp) // Recover fs3
+ fld f20,19*8(sp) // Recover fs4
+ fld f21,20*8(sp) // Recover fs5
+ fld f22,21*8(sp) // Recover fs6
+ fld f23,22*8(sp) // Recover fs7
+ fld f24,23*8(sp) // Recover fs8
+ fld f25,24*8(sp) // Recover fs9
+ fld f26,25*8(sp) // Recover fs10
+ fld f27,26*8(sp) // Recover fs11
+ ld t0, 27*8(sp) // Recover fcsr
csrw fcsr, t0 //
#endif
/* Recover standard preserved registers. */
/* Recover standard registers. */
- LOAD x1, 13*REGBYTES(sp) // Recover RA
- LOAD x8, 12*REGBYTES(sp) // Recover s0
- LOAD x9, 11*REGBYTES(sp) // Recover s1
- LOAD x18, 10*REGBYTES(sp) // Recover s2
- LOAD x19, 9*REGBYTES(sp) // Recover s3
- LOAD x20, 8*REGBYTES(sp) // Recover s4
- LOAD x21, 7*REGBYTES(sp) // Recover s5
- LOAD x22, 6*REGBYTES(sp) // Recover s6
- LOAD x23, 5*REGBYTES(sp) // Recover s7
- LOAD x24, 4*REGBYTES(sp) // Recover s8
- LOAD x25, 3*REGBYTES(sp) // Recover s9
- LOAD x26, 2*REGBYTES(sp) // Recover s10
- LOAD x27, 1*REGBYTES(sp) // Recover s11
- LOAD t0, 14*REGBYTES(sp) // Recover mstatus
- csrw mstatus, t0 // Store mstatus, enables interrupt
+ ld ra, 13*8(sp) /* Recover RA */
+ ld s0, 12*8(sp) /* Recover s0 */
+ ld s1, 11*8(sp) /* Recover s1 */
+ ld s2, 10*8(sp) /* Recover s2 */
+ ld s3, 9*8(sp) /* Recover s3 */
+ ld s4, 8*8(sp) /* Recover s4 */
+ ld s5, 7*8(sp) /* Recover s5 */
+ ld s6, 6*8(sp) /* Recover s6 */
+ ld s7, 5*8(sp) /* Recover s7 */
+ ld s8, 4*8(sp) /* Recover s8 */
+ ld s9, 3*8(sp) /* Recover s9 */
+ ld s10, 2*8(sp) /* Recover s10 */
+ ld s11, 1*8(sp) /* Recover s11 */
+ ld t0, 14*8(sp) /* Recover mstatus */
+ csrw mstatus, t0 /* Store mstatus, enables interrupt */
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
- addi sp, sp, 29*REGBYTES // Recover stack frame
+ addi sp, sp, 29*8 // Recover stack frame
#else
- addi sp, sp, 16*REGBYTES // Recover stack frame
+ addi sp, sp, 16*8 // Recover stack frame
#endif
ret // Return to thread
diff --git a/ports/risc-v64/gnu/src/tx_thread_stack_build.S b/ports/risc-v64/gnu/src/tx_thread_stack_build.S
index 34d807ee..a8b32a91 100644
--- a/ports/risc-v64/gnu/src/tx_thread_stack_build.S
+++ b/ports/risc-v64/gnu/src/tx_thread_stack_build.S
@@ -19,8 +19,6 @@
/**************************************************************************/
/**************************************************************************/
-#include "tx_port.h"
-
.section .text
/**************************************************************************/
/* */
@@ -43,7 +41,7 @@
/* thread_ptr Pointer to thread control blk */
/* function_ptr Pointer to return function */
/* */
-/* OUTPUT */
+/* OUTPUT */
/* */
/* None */
/* */
@@ -138,91 +136,91 @@ If floating point support:
Stack Bottom: (higher memory address) */
- LOAD t0, 4*REGBYTES(a0) // Pickup end of stack area
- li t1, ~15 // Build 16-byte alignment mask
- and t0, t0, t1 // Make sure 16-byte alignment
+ ld t0, 32(a0) /* Pickup end of stack area */
+ li t1, ~15 /* Build 16-byte alignment mask */
+ and t0, t0, t1 /* Make sure 16-byte alignment */
/* Actually build the stack frame. */
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
- addi t0, t0, -65*REGBYTES
+ addi t0, t0, -65*8
#else
- addi t0, t0, -32*REGBYTES // Allocate space for the stack frame
+ addi t0, t0, -32*8 /* Allocate space for the stack frame */
#endif
- li t1, 1 // Build stack type
- STORE t1, 0*REGBYTES(t0) // Place stack type on the top
- STORE x0, 1*REGBYTES(t0) // Initial s11
- STORE x0, 2*REGBYTES(t0) // Initial s10
- STORE x0, 3*REGBYTES(t0) // Initial s9
- STORE x0, 4*REGBYTES(t0) // Initial s8
- STORE x0, 5*REGBYTES(t0) // Initial s7
- STORE x0, 6*REGBYTES(t0) // Initial s6
- STORE x0, 7*REGBYTES(t0) // Initial s5
- STORE x0, 8*REGBYTES(t0) // Initial s4
- STORE x0, 9*REGBYTES(t0) // Initial s3
- STORE x0, 10*REGBYTES(t0) // Initial s2
- STORE x0, 11*REGBYTES(t0) // Initial s1
- STORE x0, 12*REGBYTES(t0) // Initial s0
- STORE x0, 13*REGBYTES(t0) // Initial t6
- STORE x0, 14*REGBYTES(t0) // Initial t5
- STORE x0, 15*REGBYTES(t0) // Initial t4
- STORE x0, 16*REGBYTES(t0) // Initial t3
- STORE x0, 17*REGBYTES(t0) // Initial t2
- STORE x0, 18*REGBYTES(t0) // Initial t1
- STORE x0, 19*REGBYTES(t0) // Initial t0
- STORE x0, 20*REGBYTES(t0) // Initial a7
- STORE x0, 21*REGBYTES(t0) // Initial a6
- STORE x0, 22*REGBYTES(t0) // Initial a5
- STORE x0, 23*REGBYTES(t0) // Initial a4
- STORE x0, 24*REGBYTES(t0) // Initial a3
- STORE x0, 25*REGBYTES(t0) // Initial a2
- STORE x0, 26*REGBYTES(t0) // Initial a1
- STORE x0, 27*REGBYTES(t0) // Initial a0
- STORE x0, 28*REGBYTES(t0) // Initial ra
- STORE a1, 30*REGBYTES(t0) // Initial mepc
+ li t1, 1 /* Build stack type */
+ sd t1, 0*8(t0) /* Place stack type on the top */
+ sd zero, 1*8(t0) /* Initial s11 */
+ sd zero, 2*8(t0) /* Initial s10 */
+ sd zero, 3*8(t0) /* Initial s9 */
+ sd zero, 4*8(t0) /* Initial s8 */
+ sd zero, 5*8(t0) /* Initial s7 */
+ sd zero, 6*8(t0) /* Initial s6 */
+ sd zero, 7*8(t0) /* Initial s5 */
+ sd zero, 8*8(t0) /* Initial s4 */
+ sd zero, 9*8(t0) /* Initial s3 */
+ sd zero, 10*8(t0) /* Initial s2 */
+ sd zero, 11*8(t0) /* Initial s1 */
+ sd zero, 12*8(t0) /* Initial s0 */
+ sd zero, 13*8(t0) /* Initial t6 */
+ sd zero, 14*8(t0) /* Initial t5 */
+ sd zero, 15*8(t0) /* Initial t4 */
+ sd zero, 16*8(t0) /* Initial t3 */
+ sd zero, 17*8(t0) /* Initial t2 */
+ sd zero, 18*8(t0) /* Initial t1 */
+ sd zero, 19*8(t0) /* Initial t0 */
+ sd zero, 20*8(t0) /* Initial a7 */
+ sd zero, 21*8(t0) /* Initial a6 */
+ sd zero, 22*8(t0) /* Initial a5 */
+ sd zero, 23*8(t0) /* Initial a4 */
+ sd zero, 24*8(t0) /* Initial a3 */
+ sd zero, 25*8(t0) /* Initial a2 */
+ sd zero, 26*8(t0) /* Initial a1 */
+ sd zero, 27*8(t0) /* Initial a0 */
+ sd zero, 28*8(t0) /* Initial ra */
+ sd a1, 30*8(t0) /* Initial mepc (thread entry point) */
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
- STORE x0, 31*REGBYTES(t0) // Inital ft0
- STORE x0, 32*REGBYTES(t0) // Inital ft1
- STORE x0, 33*REGBYTES(t0) // Inital ft2
- STORE x0, 34*REGBYTES(t0) // Inital ft3
- STORE x0, 35*REGBYTES(t0) // Inital ft4
- STORE x0, 36*REGBYTES(t0) // Inital ft5
- STORE x0, 37*REGBYTES(t0) // Inital ft6
- STORE x0, 38*REGBYTES(t0) // Inital ft7
- STORE x0, 39*REGBYTES(t0) // Inital fs0
- STORE x0, 40*REGBYTES(t0) // Inital fs1
- STORE x0, 41*REGBYTES(t0) // Inital fa0
- STORE x0, 42*REGBYTES(t0) // Inital fa1
- STORE x0, 43*REGBYTES(t0) // Inital fa2
- STORE x0, 44*REGBYTES(t0) // Inital fa3
- STORE x0, 45*REGBYTES(t0) // Inital fa4
- STORE x0, 46*REGBYTES(t0) // Inital fa5
- STORE x0, 47*REGBYTES(t0) // Inital fa6
- STORE x0, 48*REGBYTES(t0) // Inital fa7
- STORE x0, 49*REGBYTES(t0) // Inital fs2
- STORE x0, 50*REGBYTES(t0) // Inital fs3
- STORE x0, 51*REGBYTES(t0) // Inital fs4
- STORE x0, 52*REGBYTES(t0) // Inital fs5
- STORE x0, 53*REGBYTES(t0) // Inital fs6
- STORE x0, 54*REGBYTES(t0) // Inital fs7
- STORE x0, 55*REGBYTES(t0) // Inital fs8
- STORE x0, 56*REGBYTES(t0) // Inital fs9
- STORE x0, 57*REGBYTES(t0) // Inital fs10
- STORE x0, 58*REGBYTES(t0) // Inital fs11
- STORE x0, 59*REGBYTES(t0) // Inital ft8
- STORE x0, 60*REGBYTES(t0) // Inital ft9
- STORE x0, 61*REGBYTES(t0) // Inital ft10
- STORE x0, 62*REGBYTES(t0) // Inital ft11
- csrr a1, fcsr // Read fcsr and use it for initial value for each thread
- STORE a1, 63*REGBYTES(t0) // Initial fscr
- STORE x0, 64*REGBYTES(t0) // Reserved word (0)
+ sd zero, 31*8(t0) /* Initial ft0 */
+ sd zero, 32*8(t0) /* Initial ft1 */
+ sd zero, 33*8(t0) /* Initial ft2 */
+ sd zero, 34*8(t0) /* Initial ft3 */
+ sd zero, 35*8(t0) /* Initial ft4 */
+ sd zero, 36*8(t0) /* Initial ft5 */
+ sd zero, 37*8(t0) /* Initial ft6 */
+ sd zero, 38*8(t0) /* Initial ft7 */
+ sd zero, 39*8(t0) /* Initial fs0 */
+ sd zero, 40*8(t0) /* Initial fs1 */
+ sd zero, 41*8(t0) /* Initial fa0 */
+ sd zero, 42*8(t0) /* Initial fa1 */
+ sd zero, 43*8(t0) /* Initial fa2 */
+ sd zero, 44*8(t0) /* Initial fa3 */
+ sd zero, 45*8(t0) /* Initial fa4 */
+ sd zero, 46*8(t0) /* Initial fa5 */
+ sd zero, 47*8(t0) /* Initial fa6 */
+ sd zero, 48*8(t0) /* Initial fa7 */
+ sd zero, 49*8(t0) /* Initial fs2 */
+ sd zero, 50*8(t0) /* Initial fs3 */
+ sd zero, 51*8(t0) /* Initial fs4 */
+ sd zero, 52*8(t0) /* Initial fs5 */
+ sd zero, 53*8(t0) /* Initial fs6 */
+ sd zero, 54*8(t0) /* Initial fs7 */
+ sd zero, 55*8(t0) /* Initial fs8 */
+ sd zero, 56*8(t0) /* Initial fs9 */
+ sd zero, 57*8(t0) /* Initial fs10 */
+ sd zero, 58*8(t0) /* Initial fs11 */
+ sd zero, 59*8(t0) /* Initial ft8 */
+ sd zero, 60*8(t0) /* Initial ft9 */
+ sd zero, 61*8(t0) /* Initial ft10 */
+ sd zero, 62*8(t0) /* Initial ft11 */
+ csrr a1, fcsr /* Read fcsr for initial value */
+ sd a1, 63*8(t0) /* Initial fcsr */
+ sd zero, 64*8(t0) /* Reserved word (0) */
#else
- STORE x0, 31*REGBYTES(t0) // Reserved word (0)
+ sd zero, 31*8(t0) /* Reserved word (0) */
#endif
/* Setup stack pointer. */
/* thread_ptr -> tx_thread_stack_ptr = t0; */
- STORE t0, 2*REGBYTES(a0) // Save stack pointer in thread's
- ret // control block and return
+ sd t0, 16(a0) /* Save stack pointer in thread's */
+ ret /* control block and return */
/* } */
diff --git a/ports/risc-v64/gnu/src/tx_thread_system_return.S b/ports/risc-v64/gnu/src/tx_thread_system_return.S
index 3da67ffb..2e698a62 100644
--- a/ports/risc-v64/gnu/src/tx_thread_system_return.S
+++ b/ports/risc-v64/gnu/src/tx_thread_system_return.S
@@ -19,8 +19,6 @@
/**************************************************************************/
/**************************************************************************/
-#include "tx_port.h"
-
.section .text
/**************************************************************************/
/* */
@@ -68,99 +66,100 @@
_tx_thread_system_return:
/* Save minimal context on the stack. */
+ /* sp -= sizeof(stack_frame); */
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
- addi sp, sp, -29*REGBYTES // Allocate space on the stack - with floating point enabled
+ addi sp, sp, -29*8 /* Allocate space on the stack - with floating point enabled */
#else
- addi sp, sp, -16*REGBYTES // Allocate space on the stack - without floating point enabled
+ addi sp, sp, -16*8 /* Allocate space on the stack - without floating point enabled */
#endif
/* Store floating point preserved registers. */
#if defined(__riscv_float_abi_single)
- fsw f8, 15*REGBYTES(sp) // Store fs0
- fsw f9, 16*REGBYTES(sp) // Store fs1
- fsw f18, 17*REGBYTES(sp) // Store fs2
- fsw f19, 18*REGBYTES(sp) // Store fs3
- fsw f20, 19*REGBYTES(sp) // Store fs4
- fsw f21, 20*REGBYTES(sp) // Store fs5
- fsw f22, 21*REGBYTES(sp) // Store fs6
- fsw f23, 22*REGBYTES(sp) // Store fs7
- fsw f24, 23*REGBYTES(sp) // Store fs8
- fsw f25, 24*REGBYTES(sp) // Store fs9
- fsw f26, 25*REGBYTES(sp) // Store fs10
- fsw f27, 26*REGBYTES(sp) // Store fs11
+ fsw f8, 15*8(sp) /* Store fs0 */
+ fsw f9, 16*8(sp) /* Store fs1 */
+ fsw f18, 17*8(sp) /* Store fs2 */
+ fsw f19, 18*8(sp) /* Store fs3 */
+ fsw f20, 19*8(sp) /* Store fs4 */
+ fsw f21, 20*8(sp) /* Store fs5 */
+ fsw f22, 21*8(sp) /* Store fs6 */
+ fsw f23, 22*8(sp) /* Store fs7 */
+ fsw f24, 23*8(sp) /* Store fs8 */
+ fsw f25, 24*8(sp) /* Store fs9 */
+ fsw f26, 25*8(sp) /* Store fs10 */
+ fsw f27, 26*8(sp) /* Store fs11 */
csrr t0, fcsr
- STORE t0, 27*REGBYTES(sp) // Store fcsr
+ sd t0, 27*8(sp) /* Store fcsr */
#elif defined(__riscv_float_abi_double)
- fsd f8, 15*REGBYTES(sp) // Store fs0
- fsd f9, 16*REGBYTES(sp) // Store fs1
- fsd f18, 17*REGBYTES(sp) // Store fs2
- fsd f19, 18*REGBYTES(sp) // Store fs3
- fsd f20, 19*REGBYTES(sp) // Store fs4
- fsd f21, 20*REGBYTES(sp) // Store fs5
- fsd f22, 21*REGBYTES(sp) // Store fs6
- fsd f23, 22*REGBYTES(sp) // Store fs7
- fsd f24, 23*REGBYTES(sp) // Store fs8
- fsd f25, 24*REGBYTES(sp) // Store fs9
- fsd f26, 25*REGBYTES(sp) // Store fs10
- fsd f27, 26*REGBYTES(sp) // Store fs11
+ fsd f8, 15*8(sp) /* Store fs0 */
+ fsd f9, 16*8(sp) /* Store fs1 */
+ fsd f18, 17*8(sp) /* Store fs2 */
+ fsd f19, 18*8(sp) /* Store fs3 */
+ fsd f20, 19*8(sp) /* Store fs4 */
+ fsd f21, 20*8(sp) /* Store fs5 */
+ fsd f22, 21*8(sp) /* Store fs6 */
+ fsd f23, 22*8(sp) /* Store fs7 */
+ fsd f24, 23*8(sp) /* Store fs8 */
+ fsd f25, 24*8(sp) /* Store fs9 */
+ fsd f26, 25*8(sp) /* Store fs10 */
+ fsd f27, 26*8(sp) /* Store fs11 */
csrr t0, fcsr
- STORE t0, 27*REGBYTES(sp) // Store fcsr
+ sd t0, 27*8(sp) /* Store fcsr */
#endif
- STORE x0, 0(sp) // Solicited stack type
- STORE x1, 13*REGBYTES(sp) // Save RA
- STORE x8, 12*REGBYTES(sp) // Save s0
- STORE x9, 11*REGBYTES(sp) // Save s1
- STORE x18, 10*REGBYTES(sp) // Save s2
- STORE x19, 9*REGBYTES(sp) // Save s3
- STORE x20, 8*REGBYTES(sp) // Save s4
- STORE x21, 7*REGBYTES(sp) // Save s5
- STORE x22, 6*REGBYTES(sp) // Save s6
- STORE x23, 5*REGBYTES(sp) // Save s7
- STORE x24, 4*REGBYTES(sp) // Save s8
- STORE x25, 3*REGBYTES(sp) // Save s9
- STORE x26, 2*REGBYTES(sp) // Save s10
- STORE x27, 1*REGBYTES(sp) // Save s11
- csrr t0, mstatus // Pickup mstatus
- STORE t0, 14*REGBYTES(sp) // Save mstatus
+ sd zero, 0(sp) /* Solicited stack type */
+ sd ra, 13*8(sp) /* Save return address */
+ sd s0, 12*8(sp) /* Save s0 */
+ sd s1, 11*8(sp) /* Save s1 */
+ sd s2, 10*8(sp) /* Save s2 */
+ sd s3, 9*8(sp) /* Save s3 */
+ sd s4, 8*8(sp) /* Save s4 */
+ sd s5, 7*8(sp) /* Save s5 */
+ sd s6, 6*8(sp) /* Save s6 */
+ sd s7, 5*8(sp) /* Save s7 */
+ sd s8, 4*8(sp) /* Save s8 */
+ sd s9, 3*8(sp) /* Save s9 */
+ sd s10, 2*8(sp) /* Save s10 */
+ sd s11, 1*8(sp) /* Save s11 */
+ csrr t0, mstatus /* Pickup mstatus */
+ sd t0, 14*8(sp) /* Save mstatus */
- /* Lockout interrupts. - will be enabled in _tx_thread_schedule */
+ /* Lockout interrupts. will be enabled in _tx_thread_schedule */
- csrci mstatus, 0xF
+ csrci mstatus, 0x08 /* Disable interrupts (MIE bit 3) */
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
- call _tx_execution_thread_exit // Call the thread execution exit function
+ call _tx_execution_thread_exit /* Call the thread execution exit function */
#endif
- la t0, _tx_thread_current_ptr // Pickup address of pointer
- LOAD t1, 0(t0) // Pickup current thread pointer
- la t2,_tx_thread_system_stack_ptr // Pickup stack pointer address
+ la t0, _tx_thread_current_ptr /* Pickup address of pointer */
+ ld t1, 0(t0) /* Pickup current thread pointer */
+ la t2, _tx_thread_system_stack_ptr /* Pickup stack pointer address */
/* Save current stack and switch to system stack. */
/* _tx_thread_current_ptr -> tx_thread_stack_ptr = SP;
SP = _tx_thread_system_stack_ptr; */
- STORE sp, 2*REGBYTES(t1) // Save stack pointer
- LOAD sp, 0(t2) // Switch to system stack
+ sd sp, 16(t1) /* Save stack pointer */
+ ld sp, 0(t2) /* Switch to system stack */
/* Determine if the time-slice is active. */
/* if (_tx_timer_time_slice)
{ */
- la t4, _tx_timer_time_slice // Pickup time slice variable addr
- LOAD t3, 0(t4) // Pickup time slice value
- la t2, _tx_thread_schedule // Pickup address of scheduling loop
- beqz t3, _tx_thread_dont_save_ts // If no time-slice, don't save it
+ la t4, _tx_timer_time_slice /* Pickup time slice variable addr */
+ ld t3, 0(t4) /* Pickup time slice value */
+ la t2, _tx_thread_schedule /* Pickup address of scheduling loop */
+ beqz t3, _tx_thread_dont_save_ts /* If no time-slice, don't save it */
/* Save time-slice for the thread and clear the current time-slice. */
/* _tx_thread_current_ptr -> tx_thread_time_slice = _tx_timer_time_slice;
_tx_timer_time_slice = 0; */
- STORE t3, 6*REGBYTES(t1) // Save current time-slice for thread
- STORE x0, 0(t4) // Clear time-slice variable
+ sd t3, 48(t1) /* Save current time-slice for thread */
+ sd zero, 0(t4) /* Clear time-slice variable */
/* } */
_tx_thread_dont_save_ts:
@@ -168,7 +167,7 @@ _tx_thread_dont_save_ts:
/* Clear the current thread pointer. */
/* _tx_thread_current_ptr = TX_NULL; */
- STORE x0, 0(t0) // Clear current thread pointer
+ sd x0, 0(t0) // Clear current thread pointer
jr t2 // Return to thread scheduler
/* } */
diff --git a/ports/risc-v64/gnu/src/tx_timer_interrupt.S b/ports/risc-v64/gnu/src/tx_timer_interrupt.S
new file mode 100644
index 00000000..4b2acf61
--- /dev/null
+++ b/ports/risc-v64/gnu/src/tx_timer_interrupt.S
@@ -0,0 +1,210 @@
+/***************************************************************************
+ * Copyright (c) 2024 Microsoft Corporation
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the MIT License which is available at
+ * https://opensource.org/licenses/MIT.
+ *
+ * SPDX-License-Identifier: MIT
+ **************************************************************************/
+
+
+/**************************************************************************/
+/**************************************************************************/
+/** */
+/** ThreadX Component */
+/** */
+/** Timer */
+/** */
+/**************************************************************************/
+/**************************************************************************/
+
+ .section .text
+ .align 4
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _tx_timer_interrupt RISC-V64/GNU */
+/* 6.2.1 */
+/* AUTHOR */
+/* */
+/* Scott Larson, Microsoft Corporation */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function processes the hardware timer interrupt. This */
+/* processing includes incrementing the system clock and checking for */
+/* time slice and/or timer expiration. If either is found, the */
+/* interrupt context save/restore functions are called along with the */
+/* expiration functions. */
+/* */
+/* INPUT */
+/* */
+/* None */
+/* */
+/* OUTPUT */
+/* */
+/* None */
+/* */
+/* CALLS */
+/* */
+/* _tx_timer_expiration_process Timer expiration processing */
+/* _tx_thread_time_slice Time slice interrupted thread */
+/* */
+/* CALLED BY */
+/* */
+/* interrupt vector */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/* 03-08-2023 Scott Larson Initial Version 6.2.1 */
+/* */
+/**************************************************************************/
+/* VOID _tx_timer_interrupt(VOID)
+{ */
+ .global _tx_timer_interrupt
+_tx_timer_interrupt:
+
+ /* Increment the system clock. */
+ /* _tx_timer_system_clock++; */
+
+ la t0, _tx_timer_system_clock /* Pickup address of system clock */
+ ld t1, 0(t0) /* Pickup system clock */
+ la t2, _tx_timer_time_slice /* Pickup address of time slice */
+ ld t3, 0(t2) /* Pickup time slice */
+ addi t1, t1, 1 /* Increment system clock */
+ sd t1, 0(t0) /* Store new system clock */
+ li t6, 0 /* Clear local expired flag */
+
+ /* Test for time-slice expiration. */
+ /* if (_tx_timer_time_slice)
+ { */
+
+ beqz t3, _tx_timer_no_time_slice /* If 0, skip time slice processing */
+ addi t3, t3, -1 /* Decrement the time slice */
+
+ /* Decrement the time_slice. */
+ /* _tx_timer_time_slice--; */
+
+ sd t3, 0(t2) /* Store new time slice */
+
+ /* Check for expiration. */
+ /* if (_tx_timer_time_slice == 0) */
+
+ bgtz t3, _tx_timer_no_time_slice /* If not 0, has not expired yet */
+ li t1, 1 /* Build expired flag */
+
+ /* Set the time-slice expired flag. */
+ /* _tx_timer_expired_time_slice = TX_TRUE; */
+
+ la t4, _tx_timer_expired_time_slice /* Get address of expired flag */
+ sw t1, 0(t4) /* Set expired flag (UINT) */
+ ori t6, t6, 1 /* Set local expired flag */
+
+ /* } */
+
+_tx_timer_no_time_slice:
+
+ /* Test for timer expiration. */
+ /* if (*_tx_timer_current_ptr)
+ { */
+
+ la t0, _tx_timer_current_ptr /* Pickup address of current ptr */
+ ld t1, 0(t0) /* Pickup current pointer (double word) */
+ ld t3, 0(t1) /* Pickup the current timer entry (double word) */
+ la t2, _tx_timer_expired /* Pickup address of timer expired flag */
+ li t4, 1 /* Build TX_TRUE flag */
+ beqz t3, _tx_timer_no_timer /* If NULL, no timer has expired */
+
+ /* Set expiration flag. */
+ /* _tx_timer_expired = TX_TRUE; */
+
+ ori t6, t6, 2 /* Set local expired flag */
+ sw t4, 0(t2) /* Set expired flag in memory (UINT) */
+ j _tx_timer_done /* Finished timer processing */
+
+
+ /* }
+ else
+ { */
+_tx_timer_no_timer:
+
+ /* No timer expired, increment the timer pointer. */
+ /* _tx_timer_current_ptr++; */
+
+ /* Check for wrap-around. */
+ /* if (_tx_timer_current_ptr == _tx_timer_list_end) */
+
+ la t2, _tx_timer_list_end /* Pickup address of list end pointer */
+ ld t3, 0(t2) /* Pickup actual list end */
+ addi t1, t1, 8 /* Point to next timer entry */
+ sd t1, 0(t0) /* Store new timer pointer */
+ bne t1, t3, _tx_timer_skip_wrap /* If not same, good pointer */
+
+ /* Wrap to beginning of list. */
+ /* _tx_timer_current_ptr = _tx_timer_list_start; */
+
+ la t2, _tx_timer_list_start /* Pickup address of list start pointer */
+ ld t4, 0(t2) /* Pickup start of the list */
+ sd t4, 0(t0) /* Store new timer pointer */
+
+
+_tx_timer_skip_wrap:
+ /* } */
+
+_tx_timer_done:
+
+
+ /* See if anything has expired. */
+ /* if ((_tx_timer_expired_time_slice) || (_tx_timer_expired))
+ { */
+
+ beqz t6, _tx_timer_nothing_expired /* If nothing expired skip the rest */
+ addi sp, sp, -16 /* Allocate some storage on the stack */
+ sd t6, 0(sp) /* Save local expired flag */
+ sd ra, 8(sp) /* Save ra (8-byte aligned) */
+
+ /* Did a timer expire? */
+ /* if (_tx_timer_expired)
+ { */
+
+ andi t2, t6, 2 /* Isolate the timer expired bit */
+ beqz t2, _tx_timer_dont_activate /* No, timer not expired */
+
+ /* Call the timer expiration processing. */
+ /* _tx_timer_expiration_process(void); */
+
+ call _tx_timer_expiration_process /* Call _tx_timer_expiration_process */
+ ld t6, 0(sp) /* Recover local expired flag */
+
+ /* } */
+_tx_timer_dont_activate:
+
+ /* Did time slice expire? */
+ /* if (_tx_timer_expired_time_slice)
+ { */
+
+ andi t2, t6, 1 /* Is the timer expired bit set? */
+ beqz t2, _tx_timer_not_ts_expiration /* If not, skip time slice processing */
+
+ /* Time slice interrupted thread. */
+ /* _tx_thread_time_slice(); */
+
+ call _tx_thread_time_slice /* Call time slice */
+
+ /* } */
+
+_tx_timer_not_ts_expiration:
+
+ ld ra, 8(sp) /* Recover ra */
+ addi sp, sp, 16 /* Recover stack space */
+ /* } */
+
+_tx_timer_nothing_expired:
+
+ ret
+
+/* } */
diff --git a/ports/risc-v64/gnu/src/tx_timer_interrupt.c b/ports/risc-v64/gnu/src/tx_timer_interrupt.c
deleted file mode 100644
index 3c90d0a6..00000000
--- a/ports/risc-v64/gnu/src/tx_timer_interrupt.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/***************************************************************************
- * Copyright (c) 2024 Microsoft Corporation
- *
- * This program and the accompanying materials are made available under the
- * terms of the MIT License which is available at
- * https://opensource.org/licenses/MIT.
- *
- * SPDX-License-Identifier: MIT
- **************************************************************************/
-
-
-/**************************************************************************/
-/**************************************************************************/
-/** */
-/** ThreadX Component */
-/** */
-/** Timer */
-/** */
-/**************************************************************************/
-/**************************************************************************/
-
-#define TX_SOURCE_CODE
-
-/* Include necessary system files. */
-
-#include "tx_api.h"
-#include "tx_timer.h"
-#include "tx_thread.h"
-
-/**************************************************************************/
-/* */
-/* FUNCTION RELEASE */
-/* */
-/* _tx_timer_interrupt RISC-V64/GNU */
-/* 6.2.1 */
-/* AUTHOR */
-/* */
-/* Scott Larson, Microsoft Corporation */
-/* */
-/* DESCRIPTION */
-/* */
-/* This function processes the hardware timer interrupt. This */
-/* processing includes incrementing the system clock and checking for */
-/* time slice and/or timer expiration. If either is found, the */
-/* interrupt context save/restore functions are called along with the */
-/* expiration functions. */
-/* */
-/* INPUT */
-/* */
-/* None */
-/* */
-/* OUTPUT */
-/* */
-/* None */
-/* */
-/* CALLS */
-/* */
-/* _tx_timer_expiration_process Timer expiration processing */
-/* _tx_thread_time_slice Time slice interrupted thread */
-/* */
-/* CALLED BY */
-/* */
-/* interrupt vector */
-/* */
-/* RELEASE HISTORY */
-/* */
-/* DATE NAME DESCRIPTION */
-/* */
-/* 03-08-2023 Scott Larson Initial Version 6.2.1 */
-/* */
-/**************************************************************************/
-VOID _tx_timer_interrupt(VOID)
-{
- /* Increment system clock. */
- _tx_timer_system_clock++;
-
- /* Test for time-slice expiration. */
- if (_tx_timer_time_slice)
- {
- /* Decrement the time_slice. */
- _tx_timer_time_slice--;
-
- /* Check for expiration. */
- if (_tx_timer_time_slice == 0)
- {
-
- /* Set the time-slice expired flag. */
- _tx_timer_expired_time_slice = TX_TRUE;
- }
- }
-
- /* Test for timer expiration. */
- if (*_tx_timer_current_ptr)
- {
-
- /* Set expiration flag. */
- _tx_timer_expired = TX_TRUE;
- }
- else
- {
-
- /* No timer expired, increment the timer pointer. */
- _tx_timer_current_ptr++;
-
- /* Check for wrap-around. */
- if (_tx_timer_current_ptr == _tx_timer_list_end)
- {
-
- /* Wrap to beginning of list. */
- _tx_timer_current_ptr = _tx_timer_list_start;
- }
- }
-
- /* See if anything has expired. */
- if ((_tx_timer_expired_time_slice) || (_tx_timer_expired))
- {
-
- /* Did a timer expire? */
- if (_tx_timer_expired)
- {
-
- /* Process timer expiration. */
- _tx_timer_expiration_process();
- }
-
- /* Did time slice expire? */
- if (_tx_timer_expired_time_slice)
- {
-
- /* Time slice interrupted thread. */
- _tx_thread_time_slice();
- }
- }
-}