Merge pull request #496 from akifejaz/rv64-gnu-port

Improved RV64/GNU port robustness, portability, and CSR handling
This commit is contained in:
Frédéric Desbiens
2026-02-05 09:50:08 -05:00
committed by GitHub
12 changed files with 1458 additions and 844 deletions
+1 -1
View File
@@ -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}}
)
+27 -44
View File
@@ -1,10 +1,10 @@
/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
*
* 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
**************************************************************************/
@@ -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,34 @@ typedef unsigned short USHORT;
is used to define a local function save area for the disable and restore
macros. */
/* 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);
#ifdef TX_DISABLE_INLINE
ULONG64 _tx_thread_interrupt_control(unsigned int new_posture);
#define TX_INTERRUPT_SAVE_AREA register UINT interrupt_save;
#define TX_INTERRUPT_SAVE_AREA register ULONG64 interrupt_save;
#define TX_DISABLE __asm__ volatile("csrrci %0, mstatus, 8" : "=r" (interrupt_save) :: "memory");
#define TX_RESTORE { \
unsigned long _temp_mstatus; \
__asm__ volatile( \
"csrc mstatus, 8\n" \
"andi %0, %1, 8\n" \
"csrs mstatus, %0" \
: "=&r" (_temp_mstatus) \
: "r" (interrupt_save) \
: "memory"); \
}
#else
#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) : );};
#endif
#endif /* TX_DISABLE_INLINE */
/* Define the interrupt lockout macros for each ThreadX object. */
@@ -291,7 +275,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 */
+430
View File
@@ -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
@@ -1,10 +1,10 @@
/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
*
* 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
**************************************************************************/
@@ -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
/* Timer Interrupt Handler Note:
Platform-specific implementations must provide their own timer ISR.
The timer interrupt handler should follow this execution flow:
/* Define the actual timer interrupt/exception handler. */
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)
.global timer1_plic_IRQHandler
//.global __minterrupt_000007
//EXTWEAK __require_minterrupt_vector_table
timer1_plic_IRQHandler:
//__minterrupt_000007:
//REQUIRE __require_minterrupt_vector_table
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
/* 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!
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. */
File diff suppressed because it is too large Load Diff
+220 -142
View File
@@ -1,10 +1,10 @@
/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
*
* 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 +19,6 @@
/**************************************************************************/
/**************************************************************************/
#include "tx_port.h"
.section .text
/**************************************************************************/
/* */
@@ -67,90 +65,90 @@
_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
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
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
/* 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
@@ -165,81 +163,82 @@ _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 t0, mepc // Load exception program counter
STORE t0, 30*REGBYTES(sp) // Save it on the stack
csrr t1, mepc // Load exception program counter
sd t1, 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
/* Save the current stack pointer in the thread's control block. */
@@ -248,8 +247,86 @@ _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 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
sd t0, 30*8(sp) // Save it on the stack
/* Save floating point scratch registers. */
#if defined(__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 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 +334,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 +354,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
@@ -1,10 +1,10 @@
/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
*
* 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 +19,6 @@
/**************************************************************************/
/**************************************************************************/
RETURN_MASK = 0x000000000000000F
SET_SR_MASK = 0xFFFFFFFFFFFFFFF0
.section .text
/**************************************************************************/
@@ -66,16 +64,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
/* Apply the new interrupt posture. */
/* 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, SET_SR_MASK // Build set SR mask
and t0, t0, t2 // Isolate interrupt lockout bits
or t0, t0, a0 // Put new lockout bits in
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
/* } */
+174 -159
View File
@@ -1,10 +1,10 @@
/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
*
* 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 +19,6 @@
/**************************************************************************/
/**************************************************************************/
#include "tx_port.h"
.section .text
/**************************************************************************/
/* */
@@ -69,7 +67,7 @@
_tx_thread_schedule:
/* Enable interrupts. */
csrsi mstatus, 0x08 // Enable interrupts
csrsi mstatus, 0x08 // Enable interrupts (MIE bit 3)
/* Wait for a thread to execute. */
/* do
@@ -77,11 +75,27 @@ _tx_thread_schedule:
la t0, _tx_thread_execute_ptr // Pickup address of execute ptr
_tx_thread_schedule_loop:
LOAD t1, 0(t0) // Pickup next 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. */
@@ -91,15 +105,15 @@ _tx_thread_schedule_loop:
/* _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
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
ld t2, 8(t1) // Pickup run count
ld t3, 48(t1) // Pickup time slice value
addi t2, t2, 1 // Increment run count
STORE t2, 1*REGBYTES(t1) // Store new 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; */
@@ -109,8 +123,8 @@ _tx_thread_schedule_loop:
/* 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
@@ -120,185 +134,186 @@ _tx_thread_schedule_loop:
/* Determine if an interrupt frame or a synchronous task suspension frame
is present. */
LOAD t2, 0(sp) // Pickup stack type
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 // Restore fcsr
#endif
/* Recover standard registers. */
LOAD t0, 30*REGBYTES(sp) // Recover mepc
ld t0, 30*8(sp) // Recover mepc
csrw mepc, t0 // Store mepc
li t0, 0x1880 // Prepare MPIP
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
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
+74 -76
View File
@@ -1,10 +1,10 @@
/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
*
* 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 +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
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
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
sd t0, 16(a0) // Save stack pointer in thread's
ret // control block and return
/* } */
@@ -1,10 +1,10 @@
/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
*
* 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 +19,6 @@
/**************************************************************************/
/**************************************************************************/
#include "tx_port.h"
.section .text
/**************************************************************************/
/* */
@@ -68,67 +66,68 @@
_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
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
STORE t0, 14*REGBYTES(sp) // Save 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
@@ -136,22 +135,22 @@ _tx_thread_system_return:
#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
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
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
@@ -159,8 +158,8 @@ _tx_thread_system_return:
/* _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
/* } */
+210
View File
@@ -0,0 +1,210 @@
/***************************************************************************
* Copyright (c) 2026 10xEngineers
*
* 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 */
/* */
/* Akif Ejaz, 10xEngineers */
/* */
/* 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 */
/* */
/* 01-20-2023 Akif Ejaz 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
/* } */
-134
View File
@@ -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();
}
}
}