Skip to content

Refactored, consolidated, and cleaned up RV32/RV64 ports#536

Merged
fdesbiens merged 12 commits into
eclipse-threadx:devfrom
fdesbiens:risc-v-refactoring
May 27, 2026
Merged

Refactored, consolidated, and cleaned up RV32/RV64 ports#536
fdesbiens merged 12 commits into
eclipse-threadx:devfrom
fdesbiens:risc-v-refactoring

Conversation

@fdesbiens
Copy link
Copy Markdown
Contributor

Phase 1a — Clang port: use GNU assembly sources

  • Delete ports/risc-v32/clang/src/ (all 8 .S files had no Clang-specific directives; diverged only due to missing bug fixes)
  • Update clang/CMakeLists.txt to compile from ../gnu/src/
  • Change .global -> .weak for _tx_initialize_low_level in gnu/src/ (allows BSP override without linker conflicts; adopted from Clang port)

Phase 2a — tx_port.h consolidation

  • Create ports/risc-v32/common/tx_port_riscv32_common.h with all definitions shared between GNU and Clang ports
  • Reduce risc-v32/gnu/inc/tx_port.h to a thin wrapper (adds regression test extension block + version string)
  • Reduce risc-v32/clang/inc/tx_port.h to a thin wrapper (version string only, no regression test block)

Phase 2b — RV64 LONG/ULONG documentation

  • Add prominent comment in risc-v64/gnu/inc/tx_port.h explaining why LONG/ULONG are intentionally 32-bit on RV64 (ThreadX ABI requirement)

Phase 3a — Shared CMake helper

  • Create cmake/threadx_riscv_port.cmake with threadx_add_riscv_port()
  • Reduce all three port CMakeLists.txt to ~8 lines each

Phase 4a/b/c/d — Shared example-build drivers

  • Create canonical files in ports/risc-v_common/:
    inc/csr.h (uintptr_t, works RV32+RV64)
    example_build/plic/ (plic.c, plic.h)
    example_build/uart/ (uart_qemu_ns16550.c/h; static inline putc_nolock)
    example_build/trap/ (trap_qemu.c; XLEN-portable mcause constants)
  • Replace per-example copies with symlinks in all qemu_virt dirs and cva6_ariane
  • Fix OS_IS_INTERRUPT typo (was OS_IS_INTERUPT) in shared trap_qemu.c
  • Gate print_hex() behind TX_RISCV_TRAP_DEBUG

Phase 5a — RV64 QEMU CI test

  • Add ports/risc-v64/gnu/example_build/qemu_virt/test/ threadx_test_tx_gnu_riscv64_qemu.py

Phase 6a — entry.s → entry.S rename

  • Normalize case on all 4 example entry point files

Housekeeping

  • Rename azrtos_test_* → threadx_test_* (eliminate Azure RTOS branding)
  • Update CMakeLists.txt reference to match renamed test script

…85 GNU (eclipse-threadx#452) (eclipse-threadx#514)

The Cortex-M33, M55, and M85 GNU ports incorrectly include tx_initialize_low_level.S as a library source in CMakeLists.txt. This file is board-specific initialization code that users must
customize for their hardware, and including it in the library causes linker conflicts when users provide their own implementation (e.g., via CMake FetchContent).

This change aligns these ports with the established pattern used by
Cortex-M0/M3/M4/M7 GNU ports:
- Move tx_initialize_low_level.S from src/ to example_build/
- Remove it from CMakeLists.txt target_sources
- Add sample_threadx.c to example_build/ for consistency

Signed-off-by: An Dao <webmaster@taktflow-systems.com>
@fdesbiens fdesbiens requested a review from akifejaz May 26, 2026 14:31
@fdesbiens fdesbiens changed the title Reefactored, consolidated, and cleaned up RV32/RV64 ports Refactored, consolidated, and cleaned up RV32/RV64 ports May 26, 2026
@fdesbiens fdesbiens self-assigned this May 26, 2026
@fdesbiens fdesbiens moved this to In review in ThreadX Roadmap May 26, 2026
fdesbiens and others added 7 commits May 26, 2026 17:21
Phase 1a — Clang port: use GNU assembly sources
- Delete ports/risc-v32/clang/src/ (all 8 .S files had no Clang-specific
  directives; diverged only due to missing bug fixes)
- Update clang/CMakeLists.txt to compile from ../gnu/src/
- Change .global -> .weak for _tx_initialize_low_level in gnu/src/
  (allows BSP override without linker conflicts; adopted from Clang port)

Phase 2a — tx_port.h consolidation
- Create ports/risc-v32/common/tx_port_riscv32_common.h with all
  definitions shared between GNU and Clang ports
- Reduce risc-v32/gnu/inc/tx_port.h to a thin wrapper (adds regression
  test extension block + version string)
- Reduce risc-v32/clang/inc/tx_port.h to a thin wrapper (version string
  only, no regression test block)

Phase 2b — RV64 LONG/ULONG documentation
- Add prominent comment in risc-v64/gnu/inc/tx_port.h explaining why
  LONG/ULONG are intentionally 32-bit on RV64 (ThreadX ABI requirement)

Phase 3a — Shared CMake helper
- Create cmake/threadx_riscv_port.cmake with threadx_add_riscv_port()
- Reduce all three port CMakeLists.txt to ~8 lines each

Phase 4a/b/c/d — Shared example-build drivers
- Create canonical files in ports/risc-v_common/:
    inc/csr.h               (uintptr_t, works RV32+RV64)
    example_build/plic/     (plic.c, plic.h)
    example_build/uart/     (uart_qemu_ns16550.c/h; static inline putc_nolock)
    example_build/trap/     (trap_qemu.c; XLEN-portable mcause constants)
- Replace per-example copies with symlinks in all qemu_virt dirs and cva6_ariane
- Fix OS_IS_INTERRUPT typo (was OS_IS_INTERUPT) in shared trap_qemu.c
- Gate print_hex() behind TX_RISCV_TRAP_DEBUG

Phase 5a — RV64 QEMU CI test
- Add ports/risc-v64/gnu/example_build/qemu_virt/test/
    threadx_test_tx_gnu_riscv64_qemu.py

Phase 6a — entry.s → entry.S rename
- Normalize case on all 4 example entry point files

Housekeeping
- Rename azrtos_test_* → threadx_test_* (eliminate Azure RTOS branding)
- Update CMakeLists.txt reference to match renamed test script

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fix two pre-existing bugs in the RV32 GNU port assembly:

1. tx_thread_schedule.S: Solicited return path restores mstatus from slot
   14 before csrw to avoid clobbering mstatus with the fcsr value that t0
   held after the FP register restore block.

2. tx_thread_system_return.S: FP callee-saved registers were saved
   unconditionally before checking mstatus.FS, causing an illegal
   instruction trap (mcause=0x2) when a thread with FS=Off (lazy FPU,
   thread has never used FP) voluntarily yielded. Apply the same
   mstatus.FS guard pattern used in tx_thread_context_save.S: read
   mstatus first, isolate FS[1:0] bits, and skip fsw/fsd instructions
   if FS == Off.

Also fix cmake include path in all three port CMakeLists.txt files
(risc-v32/gnu, risc-v32/clang, risc-v64/gnu) to use a path relative to
CMAKE_CURRENT_LIST_DIR so the shared threadx_riscv_port.cmake helper is
found correctly whether ports are built standalone or as a subdirectory
of the test framework.

Disable -Wconversion for the RV64 test configuration: ULONG = unsigned
int (32-bit) is intentional for ThreadX ABI compatibility, but causes
spurious conversion warnings when sizeof() (size_t, 8 bytes on RV64) is
used in arithmetic with ULONG throughout common/src/.

Verified: 95/95 RV32 regression tests pass with QEMU virt.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment out the riscv job in the regression workflow and remove it from
the deploy job's needs list. The job definition is preserved in-place
for easy re-enablement.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…64 merge

ports/risc-v64/gnu/inc/tx_port.h:
- Add TX_TIMER_INTERNAL_EXTENSION, TX_THREAD_CREATE_TIMEOUT_SETUP, and
  TX_THREAD_TIMEOUT_POINTER_SETUP to store the thread timeout pointer in a
  VOID * extension field rather than truncating it into a 32-bit ULONG.
  Mirrors the win64 port pattern.  Also silences -Wunused-parameter in
  _tx_thread_timeout via TX_PARAMETER_NOT_USED.
- Define TX_TIMER_EXTENSION_PTR_DEFINED as a portable sentinel so test
  code can detect this mechanism without checking _WIN64.

test/tx/regression/threadx_thread_basic_execution_test.c:
- Replace #if defined(_WIN64) guard with the portable
  #if defined(_WIN64) || defined(TX_TIMER_EXTENSION_PTR_DEFINED) so the
  extension-pointer path is taken on RV64 as well.

test/tx/cmake/riscv/regression/CMakeLists.txt:
- Include testcontrol_weak_defaults.c (added by the win64 merge) as an
  OBJECT library so the weak symbol definitions are always linked into
  every test binary, avoiding link failures against the new weak symbols
  in testcontrol.c (abort_all_threads_suspended_on_mutex, etc.).

Verified: 95/95 tests pass for both RV32 and RV64 with QEMU virt.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@fdesbiens fdesbiens force-pushed the risc-v-refactoring branch from 052333b to a8b2656 Compare May 27, 2026 11:56
fdesbiens and others added 4 commits May 27, 2026 08:23
…ssion builds

testcontrol_weak_defaults.c provides __attribute__((weak)) definitions
for abort_all_threads_suspended_on_mutex, suspend_lowest_priority, and
abort_and_resume_byte_allocating_thread. These are called from libthreadx
when TX_REGRESSION_TEST is defined.

GNU ld does not extract objects from a static archive to satisfy
undefined strong references using weak symbols, so bundling
testcontrol_weak_defaults.c in the test_utility OBJECT library was not
sufficient for the standalone threadx_initialize_kernel_setup_test (which
doesn't link test_utility).

Fix: build testcontrol_weak_defaults.c as a separate OBJECT library
(test_weak_defaults) and include it via $<TARGET_OBJECTS:test_weak_defaults>
in every test executable, including the standalone one. Applied the same
fix to both test/tx and test/smp regression cmake.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The riscv-collab riscv64-unknown-elf toolchain (installed to /opt/riscv
by install_riscv.sh) is built without multilib and does not ship an
rv32im/ilp32 libgcc.  When -nodefaultlibs is used, -lgcc resolves to
the rv64 libgcc.a which does not define rv32-only helpers such as
__clzsi2, causing linker errors in fll.c.

The Ubuntu gcc-riscv64-unknown-elf package is built with full multilib
support and correctly resolves -lgcc to rv32im/ilp32/libgcc.a for
-march=rv32imc_zicsr -mabi=ilp32 targets.

Fix: hard-code /usr/bin/riscv64-unknown-elf-{gcc,g++,...} in the
toolchain file so the multilib Ubuntu compiler is always used regardless
of PATH order, and update the comment to document the requirement.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…olchain

The riscv-collab toolchain (/opt/riscv) is built without rv32 multilib,
so its libgcc does not define __clzsi2 — the helper GCC emits for
__builtin_clz() on targets lacking a hardware CLZ instruction (fll.c).

Add bsp/clz.c with a weak __attribute__((weak)) __clzsi2 implementation
so the build is self-contained regardless of which riscv64-unknown-elf
toolchain is in use.  The weak attribute ensures a libgcc-provided strong
symbol (e.g. from the Ubuntu gcc-riscv64-unknown-elf multilib) takes
precedence when available.

Also update cmake/riscv64-gcc-rv32imc.cmake to resolve riscv64-unknown-elf-gcc
via PATH (dropping the hard-coded /usr/bin prefix), so the riscv-collab
toolchain in /opt/riscv/bin is picked up when it appears first in PATH.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CMake consumes CMAKE_TOOLCHAIN_FILE internally before the project runs,
so it never appears in any CMakeLists.txt read() call, triggering the
"Manually-specified variables were not used by the project" warning.

Reference the variable explicitly via message(STATUS ...) to suppress
the warning and provide useful diagnostic output during configuration.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@fdesbiens fdesbiens merged commit 7486de0 into eclipse-threadx:dev May 27, 2026
1 check passed
@github-project-automation github-project-automation Bot moved this from In review to Done in ThreadX Roadmap May 27, 2026
@fdesbiens fdesbiens deleted the risc-v-refactoring branch May 27, 2026 15:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants