mirror of
https://github.com/eclipse-threadx/threadx.git
synced 2026-10-06 06:59:08 +08:00
Implemented lazy FPU, GP relaxation, and QEMU automation for GNU port in arch/risc-v32 (#513)
This PR adds three functional improvements to the RISC-V 32-bit GNU port. Lazy FPU stacking (tx_thread_context_save.S, tx_thread_context_restore.S, tx_thread_schedule.S): FP register save/restore is now skipped whenmstatus.FS is Off, reducing context switch overhead for threads that do not use floating point. GP relaxation (cmake/riscv32_gnu.cmake, entry.s, link.lds): Enables the -mrelax compiler flag and defines __global_pointer$ in the linker script.The entry stub initializes gp at startup. gp is not saved or restored during context switches. WFI in idle loop (tx_thread_schedule.S): The scheduler issues wfi when no thread is ready, replacing busy-waiting with a low-power sleep. A Python/QEMU/GDB functional test runner is added under ports/risc-v32/gnu/example_build/qemu_virt/test/. It validates context switching, FPUcontext preservation, timer interrupts, and preemption. To run: cd ports/risc-v32/gnu/example_build/qemu_virt make check-functional-riscv32 Tested on QEMU virt machine (rv32gc). Co-authored-by: Wei-Chen Lai Winstonllllai@users.noreply.github.com Co-authored-by: Frédéric Desbiens frederic.desbiens@eclipse-foundation.org Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com
This commit is contained in:
co-authored by
Wei-Chen Lai Winstonllllai@users.noreply.github.com
Frédéric Desbiens frederic.desbiens@eclipse-foundation.org
Copilot 223556219+Copilot@users.noreply.github.com
parent
5b1b740a66
commit
e031a3d506
@@ -4,6 +4,7 @@
|
||||
.tmp/
|
||||
_deps/
|
||||
build/
|
||||
build_qemu/
|
||||
Debug/
|
||||
CMakeFiles/
|
||||
CMakeScripts/
|
||||
|
||||
@@ -7,7 +7,7 @@ if(DEFINED SOFT_FLOAT)
|
||||
set(ARCH_FLAGS "-g -march=rv32ima_zicsr -mabi=ilp32 -mcmodel=medany")
|
||||
set(CACHE{SOFT_FLOAT} FORCE 1)
|
||||
else()
|
||||
set(ARCH_FLAGS "-g -march=rv32gc -mabi=ilp32d -mcmodel=medany")
|
||||
set(ARCH_FLAGS "-g -march=rv32gc -mabi=ilp32d -mcmodel=medany -mrelax")
|
||||
endif()
|
||||
set(CFLAGS "${ARCH_FLAGS}")
|
||||
set(ASFLAGS "${ARCH_FLAGS}")
|
||||
|
||||
@@ -17,3 +17,7 @@ target_include_directories(${PROJECT_NAME}
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_LIST_DIR}/inc
|
||||
)
|
||||
|
||||
if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/example_build/qemu_virt/CMakeLists.txt)
|
||||
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/example_build/qemu_virt)
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
set(QEMU_DEMO_DIR ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
add_executable(kernel.elf EXCLUDE_FROM_ALL
|
||||
${QEMU_DEMO_DIR}/demo_threadx.c
|
||||
${QEMU_DEMO_DIR}/entry.s
|
||||
${QEMU_DEMO_DIR}/uart.c
|
||||
${QEMU_DEMO_DIR}/plic.c
|
||||
${QEMU_DEMO_DIR}/hwtimer.c
|
||||
${QEMU_DEMO_DIR}/trap.c
|
||||
${QEMU_DEMO_DIR}/board.c
|
||||
${QEMU_DEMO_DIR}/tx_initialize_low_level.S
|
||||
)
|
||||
|
||||
target_link_libraries(kernel.elf PRIVATE threadx)
|
||||
|
||||
target_include_directories(kernel.elf PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/common/inc
|
||||
${CMAKE_SOURCE_DIR}/ports/${THREADX_ARCH}/${THREADX_TOOLCHAIN}/inc
|
||||
${QEMU_DEMO_DIR}
|
||||
)
|
||||
|
||||
target_link_options(kernel.elf PRIVATE
|
||||
-T${QEMU_DEMO_DIR}/link.lds
|
||||
-nostartfiles
|
||||
-Wl,-Map=kernel.map
|
||||
)
|
||||
|
||||
# QEMU/GDB functional test runner. Optional: skipped silently if the
|
||||
# host has no Python 3 interpreter on PATH.
|
||||
find_package(Python3 COMPONENTS Interpreter)
|
||||
if(Python3_FOUND)
|
||||
add_custom_target(check-functional-riscv32
|
||||
COMMAND ${Python3_EXECUTABLE}
|
||||
${QEMU_DEMO_DIR}/test/azrtos_test_tx_gnu_riscv32_qemu.py
|
||||
--elf $<TARGET_FILE:kernel.elf>
|
||||
--qemu qemu-system-riscv32
|
||||
--gdb gdb
|
||||
DEPENDS kernel.elf
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMENT "Running RISC-V32 QEMU/GDB functional test runner..."
|
||||
)
|
||||
else()
|
||||
message(STATUS
|
||||
"Python3 not found; check-functional-riscv32 target unavailable.")
|
||||
endif()
|
||||
@@ -9,6 +9,7 @@
|
||||
#define DEMO_BYTE_POOL_SIZE 9120
|
||||
#define DEMO_BLOCK_POOL_SIZE 100
|
||||
#define DEMO_QUEUE_SIZE 100
|
||||
float fpu_test_val = 0.0f;
|
||||
|
||||
char *_to_str(ULONG val)
|
||||
{
|
||||
@@ -201,7 +202,7 @@ UINT status;
|
||||
thread_0_counter++;
|
||||
|
||||
/* Sleep for 10 ticks. */
|
||||
tx_thread_sleep(10);
|
||||
tx_thread_sleep(1);
|
||||
|
||||
/* Set event flag 0 to wakeup thread 5. */
|
||||
status = tx_event_flags_set(&event_flags_0, 0x1, TX_OR);
|
||||
@@ -363,6 +364,8 @@ UINT status;
|
||||
if (status != TX_SUCCESS)
|
||||
break;
|
||||
|
||||
/* FPU Test */
|
||||
fpu_test_val += 1.1f;
|
||||
/* Get the mutex again with suspension. This shows
|
||||
that an owning thread may retrieve the mutex it
|
||||
owns multiple times. */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
.section .text
|
||||
.section .text.boot, "ax"
|
||||
.align 4
|
||||
.global _start
|
||||
.extern main
|
||||
@@ -11,7 +11,10 @@ _start:
|
||||
bne t0, zero, 1f
|
||||
li x1, 0
|
||||
li x2, 0
|
||||
li x3, 0
|
||||
.option push
|
||||
.option norelax
|
||||
la gp, __global_pointer$ /* x3 = gp; norelax keeps this load absolute */
|
||||
.option pop
|
||||
li x4, 0
|
||||
li x5, 0
|
||||
li x6, 0
|
||||
|
||||
@@ -10,6 +10,7 @@ SECTIONS
|
||||
. = 0x80000000;
|
||||
|
||||
.text : {
|
||||
KEEP(*(.text.boot)) /* entry.s _start — must be first at 0x80000000 */
|
||||
*(.text .text.*)
|
||||
. = ALIGN(0x1000);
|
||||
PROVIDE(etext = .);
|
||||
@@ -24,6 +25,9 @@ SECTIONS
|
||||
|
||||
.data : {
|
||||
. = ALIGN(16);
|
||||
/* Centre __global_pointer$ in the small-data window so the +/-2 KiB
|
||||
reach of GP-relative addressing covers the .sdata/.sbss area. */
|
||||
PROVIDE( __global_pointer$ = . + 0x800 );
|
||||
*(.sdata .sdata.*) /* do not need to distinguish this from .data */
|
||||
. = ALIGN(16);
|
||||
*(.data .data.*)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -29,6 +29,7 @@
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* Akif Ejaz, 10xEngineers */
|
||||
/* Wei-Chen Lai, National Cheng Kung University */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
@@ -82,7 +83,13 @@ _tx_thread_context_restore:
|
||||
/* Just recover the saved registers and return to the point of
|
||||
interrupt. */
|
||||
|
||||
/* Recover floating point registers. */
|
||||
/* Recover floating point registers only if saved mstatus.FS was not Off. */
|
||||
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
|
||||
lw t1, 29*4(sp) // Pickup saved mstatus
|
||||
srli t1, t1, 13
|
||||
andi t1, t1, 0x3
|
||||
beqz t1, _tx_thread_skip_fp_restore // Skip if FS was Off
|
||||
#endif
|
||||
#if defined(__riscv_float_abi_single)
|
||||
flw f0, 31*4(sp) // Recover ft0
|
||||
flw f1, 32*4(sp) // Recover ft1
|
||||
@@ -130,6 +137,7 @@ _tx_thread_context_restore:
|
||||
lw t0, 63*4(sp) // Recover fcsr
|
||||
csrw fcsr, t0 // Restore fcsr
|
||||
#endif
|
||||
_tx_thread_skip_fp_restore:
|
||||
|
||||
/* Recover standard registers. */
|
||||
|
||||
@@ -222,7 +230,13 @@ _tx_thread_no_preempt_restore:
|
||||
|
||||
lw sp, 8(t1) // Switch back to thread's stack
|
||||
|
||||
/* Recover floating point registers. */
|
||||
/* Recover floating point registers only if saved mstatus.FS was not Off. */
|
||||
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
|
||||
lw t3, 29*4(sp) // Pickup saved mstatus
|
||||
srli t3, t3, 13
|
||||
andi t3, t3, 0x3
|
||||
beqz t3, _tx_thread_no_preempt_skip_fp_restore // Skip if FS was Off
|
||||
#endif
|
||||
#if defined(__riscv_float_abi_single)
|
||||
flw f0, 31*4(sp) // Recover ft0
|
||||
flw f1, 32*4(sp) // Recover ft1
|
||||
@@ -270,6 +284,7 @@ _tx_thread_no_preempt_restore:
|
||||
lw t0, 63*4(sp) // Recover fcsr
|
||||
csrw fcsr, t0 // Restore fcsr
|
||||
#endif
|
||||
_tx_thread_no_preempt_skip_fp_restore:
|
||||
|
||||
/* Recover the saved context and return to the point of interrupt. */
|
||||
|
||||
@@ -331,7 +346,13 @@ _tx_thread_preempt_restore:
|
||||
ori t3, zero, 1 // Build interrupt stack type
|
||||
sw t3, 0(t0) // Store stack type
|
||||
|
||||
/* Store floating point preserved registers. */
|
||||
/* Store floating point preserved registers only if saved mstatus.FS was not Off. */
|
||||
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
|
||||
lw t3, 29*4(t0) // Pickup saved mstatus
|
||||
srli t3, t3, 13
|
||||
andi t3, t3, 0x3
|
||||
beqz t3, _tx_thread_preempt_skip_fp_restore // Skip if FS was Off
|
||||
#endif
|
||||
#ifdef __riscv_float_abi_single
|
||||
fsw f8, 39*4(t0) // Store fs0
|
||||
fsw f9, 40*4(t0) // Store fs1
|
||||
@@ -359,6 +380,7 @@ _tx_thread_preempt_restore:
|
||||
fsd f26, 57*4(t0) // Store fs10
|
||||
fsd f27, 58*4(t0) // Store fs11
|
||||
#endif
|
||||
_tx_thread_preempt_skip_fp_restore:
|
||||
|
||||
/* Store standard preserved registers. */
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* Akif Ejaz, 10xEngineers */
|
||||
/* Wei-Chen Lai, National Cheng Kung University */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
@@ -96,6 +97,15 @@ _tx_thread_context_save:
|
||||
sw t5, 14*4(sp) // Store t5
|
||||
sw t6, 13*4(sp) // Store t6
|
||||
|
||||
/* Save mstatus and skip FP state if FS is Off. */
|
||||
csrr t0, mstatus
|
||||
sw t0, 29*4(sp)
|
||||
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
|
||||
srli t1, t0, 13
|
||||
andi t1, t1, 0x3
|
||||
beqz t1, _tx_thread_skip_fpu_save
|
||||
#endif
|
||||
|
||||
/* Save floating point registers. */
|
||||
#if defined(__riscv_float_abi_single)
|
||||
fsw f0, 31*4(sp) // Store ft0
|
||||
@@ -144,14 +154,11 @@ _tx_thread_context_save:
|
||||
csrr t0, fcsr
|
||||
sw t0, 63*4(sp) // Store fcsr
|
||||
#endif
|
||||
_tx_thread_skip_fpu_save:
|
||||
|
||||
csrr t0, mepc
|
||||
sw t0, 30*4(sp) // Save it on the stack
|
||||
|
||||
/* Save mstatus. */
|
||||
csrr t0, mstatus
|
||||
sw t0, 29*4(sp)
|
||||
|
||||
la t1, _tx_thread_current_ptr // Pickup address of current thread ptr
|
||||
lw t2, 0(t1) // Pickup current thread pointer
|
||||
beqz t2, _tx_thread_idle_system_save // If NULL, idle system was interrupted
|
||||
@@ -190,6 +197,15 @@ _tx_thread_nested_save:
|
||||
sw t5, 14*4(sp) // Store t5
|
||||
sw t6, 13*4(sp) // Store t6
|
||||
|
||||
/* Save mstatus and skip FP state if FS is Off. */
|
||||
csrr t0, mstatus
|
||||
sw t0, 29*4(sp)
|
||||
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
|
||||
srli t1, t0, 13
|
||||
andi t1, t1, 0x3
|
||||
beqz t1, _tx_thread_skip_nested_fpu_save
|
||||
#endif
|
||||
|
||||
/* Save floating point registers. */
|
||||
#if defined(__riscv_float_abi_single)
|
||||
fsw f0, 31*4(sp) // Store ft0
|
||||
@@ -238,13 +254,11 @@ _tx_thread_nested_save:
|
||||
csrr t0, fcsr
|
||||
sw t0, 63*4(sp) // Store fcsr
|
||||
#endif
|
||||
_tx_thread_skip_nested_fpu_save:
|
||||
|
||||
csrr t0, mepc
|
||||
sw t0, 30*4(sp) // Save it on stack
|
||||
|
||||
csrr t0, mstatus
|
||||
sw t0, 29*4(sp)
|
||||
|
||||
/* Call the ISR execution exit function if enabled. */
|
||||
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||
call _tx_execution_isr_enter // Call the ISR execution enter function
|
||||
|
||||
@@ -133,7 +133,12 @@ _tx_thread_ready_to_run:
|
||||
lw t0, 0(sp) // Pickup stack type
|
||||
beqz t0, _tx_thread_solicited_return // If 0, solicited return
|
||||
|
||||
/* Recover floating point registers. */
|
||||
/* Recover floating point registers only if saved mstatus.FS was not Off. */
|
||||
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
|
||||
lw t1, 29*4(sp) // Pickup saved mstatus
|
||||
srli t1, t1, 13
|
||||
andi t1, t1, 0x3
|
||||
beqz t1, _tx_thread_schedule_skip_fp_restore // Skip if FS was Off
|
||||
#if defined(__riscv_float_abi_single)
|
||||
flw f0, 31*4(sp) // Recover ft0
|
||||
flw f1, 32*4(sp) // Recover ft1
|
||||
@@ -204,11 +209,11 @@ _tx_thread_ready_to_run:
|
||||
fld f31, 62*4(sp) // Recover ft11
|
||||
lw t0, 63*4(sp) // Recover fcsr
|
||||
csrw fcsr, t0 // Restore fcsr
|
||||
#endif
|
||||
_tx_thread_schedule_skip_fp_restore:
|
||||
#endif
|
||||
|
||||
/* Recover standard registers. */
|
||||
|
||||
lw t0, 30*4(sp) // Recover mepc
|
||||
csrw mepc, t0 // Setup mepc
|
||||
|
||||
li t0, 0x1880 // Prepare mstatus: MPP=Machine(0x1800) | MPIE(0x80)
|
||||
@@ -256,7 +261,12 @@ _tx_thread_ready_to_run:
|
||||
|
||||
_tx_thread_solicited_return:
|
||||
|
||||
/* Recover floating point registers. */
|
||||
/* Recover floating point registers only if saved mstatus.FS was not Off. */
|
||||
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
|
||||
lw t1, 14*4(sp) // Pickup saved mstatus
|
||||
srli t1, t1, 13
|
||||
andi t1, t1, 0x3
|
||||
beqz t1, _tx_thread_schedule_solicited_skip_fp_restore // Skip if FS was Off
|
||||
#if defined(__riscv_float_abi_single)
|
||||
flw f8, 15*4(sp) // Recover fs0
|
||||
flw f9, 16*4(sp) // Recover fs1
|
||||
@@ -287,11 +297,11 @@ _tx_thread_solicited_return:
|
||||
fld f27, 26*4(sp) // Recover fs11
|
||||
lw t0, 27*4(sp) // Recover fcsr
|
||||
csrw fcsr, t0 // Restore fcsr
|
||||
#endif
|
||||
_tx_thread_schedule_solicited_skip_fp_restore:
|
||||
#endif
|
||||
|
||||
/* Recover standard registers. */
|
||||
|
||||
lw t0, 14*4(sp) // Recover mstatus
|
||||
csrw mstatus, t0 // Restore mstatus
|
||||
|
||||
lw ra, 13*4(sp) // Recover return address
|
||||
|
||||
Reference in New Issue
Block a user