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 <akif.ejaz@10xengineers.ai>
This commit is contained in:
Akif Ejaz
2026-01-26 15:48:46 +05:00
parent 12dac1d67d
commit 6c25effb40
12 changed files with 1466 additions and 869 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}}
)
+13 -39
View File
@@ -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. */
/* 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 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 */
+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
@@ -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. */
File diff suppressed because it is too large Load Diff
+220 -153
View File
@@ -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,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 +236,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 +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
@@ -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
/* } */
+182 -166
View File
@@ -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
+75 -77
View File
@@ -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 */
/* } */
@@ -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
/* } */
+210
View File
@@ -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
/* } */
-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();
}
}
}