Add RISC-V32 arch. port layer

This update adapts the ThreadX low-level kernel routines
for RV32, including:
  - startup and initialization logic
  - context save/restore implementations
  - interrupt control and scheduler entry
  - thread stack build and system return paths
  - timer interrupt handling
  - made it complient as per new risc-v64/gnu
      & threadx style
  - added reademe for risc-v32/gnu port

These changes provide full low-level support needed to run
ThreadX on RISC-V32 targets.

Signed-off-by: Akif Ejaz <akif.ejaz@10xengineers.ai>
This commit is contained in:
Akif Ejaz
2026-02-25 09:06:02 +08:00
committed by shuta.lst
parent ede5aa2867
commit 1d796d5fde
13 changed files with 2623 additions and 0 deletions
+29
View File
@@ -0,0 +1,29 @@
# Toolchain settings
set(CMAKE_C_COMPILER riscv32-unknown-elf-gcc)
set(CMAKE_CXX_COMPILER riscv32-unknown-elf-g++)
set(AS riscv32-unknown-elf-as)
set(AR riscv32-unknown-elf-ar)
set(OBJCOPY riscv32-unknown-elf-objcopy)
set(OBJDUMP riscv32-unknown-elf-objdump)
set(SIZE riscv32-unknown-elf-size)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
# this makes the test compiles use static library option so that we don't need to pre-set linker flags and scripts
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
set(CMAKE_C_FLAGS "${CFLAGS}" CACHE INTERNAL "c compiler flags")
set(CMAKE_CXX_FLAGS "${CXXFLAGS}" CACHE INTERNAL "cxx compiler flags")
set(CMAKE_ASM_FLAGS "${ASFLAGS} -D__ASSEMBLER__ -D__riscv_float_abi_single" CACHE INTERNAL "asm compiler flags")
set(CMAKE_EXE_LINKER_FLAGS "${LDFLAGS}" CACHE INTERNAL "exe link flags")
SET(CMAKE_C_FLAGS_DEBUG "-Og -g -ggdb3" CACHE INTERNAL "c debug compiler flags")
SET(CMAKE_CXX_FLAGS_DEBUG "-Og -g -ggdb3" CACHE INTERNAL "cxx debug compiler flags")
SET(CMAKE_ASM_FLAGS_DEBUG "-g -ggdb3" CACHE INTERNAL "asm debug compiler flags")
SET(CMAKE_C_FLAGS_RELEASE "-O3" CACHE INTERNAL "c release compiler flags")
SET(CMAKE_CXX_FLAGS_RELEASE "-O3" CACHE INTERNAL "cxx release compiler flags")
SET(CMAKE_ASM_FLAGS_RELEASE "" CACHE INTERNAL "asm release compiler flags")
+12
View File
@@ -0,0 +1,12 @@
# Name of the target
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR risc-v32)
set(THREADX_ARCH "risc-v32")
set(THREADX_TOOLCHAIN "gnu")
set(ARCH_FLAGS "-g -march=rv32gc -mabi=ilp32d -mcmodel=medany")
set(CFLAGS "${ARCH_FLAGS}")
set(ASFLAGS "${ARCH_FLAGS}")
set(LDFLAGS "${ARCH_FLAGS}")
include(${CMAKE_CURRENT_LIST_DIR}/riscv32-unknown-elf.cmake)
+19
View File
@@ -0,0 +1,19 @@
target_sources(${PROJECT_NAME}
PRIVATE
# {{BEGIN_TARGET_SOURCES}}
${CMAKE_CURRENT_LIST_DIR}/src/tx_initialize_low_level.S
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_restore.S
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_save.S
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_interrupt_control.S
${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.S
# {{END_TARGET_SOURCES}}
)
target_include_directories(${PROJECT_NAME}
PUBLIC
${CMAKE_CURRENT_LIST_DIR}/inc
)
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,118 @@
/***************************************************************************
* Copyright (c) 2025 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 */
/** */
/** Initialize */
/** */
/**************************************************************************/
/**************************************************************************/
.section .data
.global __tx_free_memory_start
__tx_free_memory_start:
.section .text
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_initialize_low_level RISC-V32/GNU */
/* 6.4.x */
/* AUTHOR */
/* */
/* Akif Ejaz, 10xEngineers */
/* */
/* DESCRIPTION */
/* */
/* This function is responsible for any low-level processor */
/* initialization, including setting up interrupt vectors, setting */
/* up a periodic timer interrupt source, saving the system stack */
/* pointer for use in ISR processing later, and finding the first */
/* available RAM memory address for tx_application_define. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _tx_initialize_kernel_enter ThreadX entry function */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 23-12-2025 Akif Ejaz Initial Version 6.4.x */
/* */
/**************************************************************************/
/* VOID _tx_initialize_low_level(VOID)
{ */
.global _tx_initialize_low_level
.weak _tx_initialize_low_level
_tx_initialize_low_level:
/* Save the system stack pointer. */
/* _tx_thread_system_stack_ptr = sp; */
la t0, _tx_thread_system_stack_ptr // Pickup address of system stack ptr
sw sp, 0(t0) // Save system stack pointer
/* 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 // Pickup address of unused memory
sw t0, 0(t1) // Save unused memory address
/* Initialize floating point control/status register if floating point is enabled. */
#ifdef __riscv_flen
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:
1. Disable interrupts (if not done by hardware exception entry)
2. Allocate interrupt stack frame (65*4 bytes with FP, 32*4 bytes without)
3. Save RA (x1) on the stack at offset 28*4
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*4
sw ra, 28*4(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
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,94 @@
/***************************************************************************
* Copyright (c) 2025 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 */
/** */
/** Thread */
/** */
/**************************************************************************/
/**************************************************************************/
.section .text
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_interrupt_control RISC-V32/GNU */
/* 6.4.x */
/* AUTHOR */
/* */
/* Akif Ejaz, 10xEngineers */
/* */
/* DESCRIPTION */
/* */
/* This function is responsible for changing the interrupt lockout */
/* posture of the system. */
/* */
/* INPUT */
/* */
/* new_posture New interrupt lockout posture */
/* */
/* OUTPUT */
/* */
/* old_posture Old interrupt lockout posture */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 23-12-2025 Akif Ejaz Initial Version 6.4.x */
/* */
/**************************************************************************/
/* UINT _tx_thread_interrupt_control(UINT new_posture)
{ */
.global _tx_thread_interrupt_control
_tx_thread_interrupt_control:
/* Pickup current interrupt posture. */
csrr a1, mstatus // Pickup mstatus
andi a1, a1, 0x08 // Mask out all but MIE
/* Check for the new posture. */
beqz a0, _tx_thread_interrupt_disable // If 0, disable interrupts
/* Enable interrupts. */
csrsi mstatus, 0x08 // Enable interrupts (MIE bit 3)
j _tx_thread_interrupt_control_exit // Return to caller
_tx_thread_interrupt_disable:
/* Disable interrupts. */
csrci mstatus, 0x08 // Disable interrupts (MIE bit 3)
_tx_thread_interrupt_control_exit:
/* Return the old interrupt posture. */
mv a0, a1 // Setup return value
ret // Return to caller
/* } */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,174 @@
/***************************************************************************
* Copyright (c) 2025 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 */
/** */
/** Thread */
/** */
/**************************************************************************/
/**************************************************************************/
.section .text
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_system_return RISC-V32/GNU */
/* 6.4.x */
/* AUTHOR */
/* */
/* Akif Ejaz, 10xEngineers */
/* */
/* DESCRIPTION */
/* */
/* This function is target processor specific. It is used to transfer */
/* control from a thread back to the system. Only a minimal context */
/* is saved since the compiler assumes temp registers are going to get */
/* slicked by a function call anyway. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _tx_thread_schedule Thread scheduling loop */
/* */
/* CALLED BY */
/* */
/* ThreadX components */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 23-12-2025 Akif Ejaz Initial Version 6.4.x */
/* */
/**************************************************************************/
/* VOID _tx_thread_system_return(VOID)
{ */
.global _tx_thread_system_return
_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*4 // Allocate space on the stack - with floating point enabled
#else
addi sp, sp, -16*4 // Allocate space on the stack - without floating point enabled
#endif
/* Store floating point preserved registers. */
#if defined(__riscv_float_abi_single)
fsw f8, 15*4(sp) // Store fs0
fsw f9, 16*4(sp) // Store fs1
fsw f18, 17*4(sp) // Store fs2
fsw f19, 18*4(sp) // Store fs3
fsw f20, 19*4(sp) // Store fs4
fsw f21, 20*4(sp) // Store fs5
fsw f22, 21*4(sp) // Store fs6
fsw f23, 22*4(sp) // Store fs7
fsw f24, 23*4(sp) // Store fs8
fsw f25, 24*4(sp) // Store fs9
fsw f26, 25*4(sp) // Store fs10
fsw f27, 26*4(sp) // Store fs11
csrr t0, fcsr
sw t0, 27*4(sp) // Store fcsr
#elif defined(__riscv_float_abi_double)
fsd f8, 15*4(sp) // Store fs0
fsd f9, 16*4(sp) // Store fs1
fsd f18, 17*4(sp) // Store fs2
fsd f19, 18*4(sp) // Store fs3
fsd f20, 19*4(sp) // Store fs4
fsd f21, 20*4(sp) // Store fs5
fsd f22, 21*4(sp) // Store fs6
fsd f23, 22*4(sp) // Store fs7
fsd f24, 23*4(sp) // Store fs8
fsd f25, 24*4(sp) // Store fs9
fsd f26, 25*4(sp) // Store fs10
fsd f27, 26*4(sp) // Store fs11
csrr t0, fcsr
sw t0, 27*4(sp) // Store fcsr
#endif
sw zero, 0(sp) // Solicited stack type
sw ra, 13*4(sp) // Save return address
sw s0, 12*4(sp) // Save s0
sw s1, 11*4(sp) // Save s1
sw s2, 10*4(sp) // Save s2
sw s3, 9*4(sp) // Save s3
sw s4, 8*4(sp) // Save s4
sw s5, 7*4(sp) // Save s5
sw s6, 6*4(sp) // Save s6
sw s7, 5*4(sp) // Save s7
sw s8, 4*4(sp) // Save s8
sw s9, 3*4(sp) // Save s9
sw s10, 2*4(sp) // Save s10
sw s11, 1*4(sp) // Save s11
csrr t0, mstatus // Pickup mstatus
sw t0, 14*4(sp) // Save mstatus
/* Lockout interrupts. will be enabled in _tx_thread_schedule */
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
#endif
la t0, _tx_thread_current_ptr // Pickup address of pointer
lw 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; */
sw sp, 8(t1) // Save stack pointer
lw 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
lw 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; */
sw t3, 24(t1) // Save current time-slice for thread
sw zero, 0(t4) // Clear time-slice variable
/* } */
_tx_thread_dont_save_ts:
/* Clear the current thread pointer. */
/* _tx_thread_current_ptr = TX_NULL; */
sw x0, 0(t0) // Clear current thread pointer
jr t2 // Return to thread scheduler
/* } */
File diff suppressed because it is too large Load Diff