Skip to content

Commit 888f7a4

Browse files
Added a RISC-V32 architecture port layer for Clang.
1 parent 8f126ee commit 888f7a4

29 files changed

+4167
-0
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Toolchain settings
2+
set(CMAKE_C_COMPILER clang-18)
3+
set(CMAKE_CXX_COMPILER clang++-18)
4+
#set(AS llvm-as)
5+
#set(AR llvm-ar)
6+
#set(OBJCOPY llvm-objcopy)
7+
#set(OBJDUMP llvm-objdump-18)
8+
#set(SIZE llvm-size)
9+
10+
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
11+
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
12+
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
13+
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
14+
15+
# this makes the test compiles use static library option so that we don't need to pre-set linker flags and scripts
16+
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
17+
18+
set(CMAKE_C_FLAGS "${CFLAGS}" CACHE INTERNAL "c compiler flags")
19+
set(CMAKE_CXX_FLAGS "${CXXFLAGS}" CACHE INTERNAL "cxx compiler flags")
20+
set(CMAKE_ASM_FLAGS "${ASFLAGS} -D__ASSEMBLER__" CACHE INTERNAL "asm compiler flags")
21+
set(CMAKE_EXE_LINKER_FLAGS "${LDFLAGS}" CACHE INTERNAL "exe link flags")
22+
23+
SET(CMAKE_C_FLAGS_DEBUG "--target=riscv32 -march=rv32im_zicsr_zicntr -mabi=ilp32 -g" CACHE INTERNAL "c debug compiler flags")
24+
SET(CMAKE_CXX_FLAGS_DEBUG "--target=riscv32 -march=rv32im_zicsr_zicntr -mabi=ilp32 -g" CACHE INTERNAL "cxx debug compiler flags")
25+
SET(CMAKE_ASM_FLAGS_DEBUG "--target=riscv32 -march=rv32im_zicsr_zicntr -mabi=ilp32 -g" CACHE INTERNAL "asm debug compiler flags")
26+
27+
SET(CMAKE_C_FLAGS_RELEASE "--target=riscv32 -march=rv32im_zicsr_zicntr -mabi=ilp32 -O3" CACHE INTERNAL "c release compiler flags")
28+
SET(CMAKE_CXX_FLAGS_RELEASE "--target=riscv32 -march=rv32im_zicsr_zicntr -mabi=ilp32 -O3" CACHE INTERNAL "cxx release compiler flags")
29+
SET(CMAKE_ASM_FLAGS_RELEASE "--target=riscv32 -march=rv32im_zicsr_zicntr -mabi=ilp32" CACHE INTERNAL "asm release compiler flags")

cmake/riscv32_clang.cmake

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Name of the target
2+
set(CMAKE_SYSTEM_NAME Generic)
3+
set(CMAKE_SYSTEM_PROCESSOR risc-v32)
4+
5+
IF(DEFINED $ENV{GCC_INSTALL_PREFIX})
6+
SET(GCC_INSTALL_PREFIX "$ENV{GCC_INSTALL_PREFIX}" CACHE INTERNAL "" FORCE)
7+
ELSE()
8+
SET(GCC_INSTALL_PREFIX "/opt/riscv_rv32ima" CACHE INTERNAL "" FORCE)
9+
ENDIF()
10+
11+
set(THREADX_ARCH "risc-v32")
12+
set(THREADX_TOOLCHAIN "clang")
13+
set(ARCH_FLAGS "--sysroot=${GCC_INSTALL_PREFIX}/riscv32-unknown-elf --target=riscv32 -g -march=rv32ima_zicsr -mabi=ilp32")
14+
set(CFLAGS "${ARCH_FLAGS}")
15+
set(ASFLAGS "${ARCH_FLAGS}")
16+
set(LDFLAGS "--no-dynamic-linker -m elf32lriscv -static -nostdlib")
17+
18+
include(${CMAKE_CURRENT_LIST_DIR}/riscv32-clang-unknown-elf.cmake)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
2+
target_sources(${PROJECT_NAME}
3+
PRIVATE
4+
# {{BEGIN_TARGET_SOURCES}}
5+
${CMAKE_CURRENT_LIST_DIR}/src/tx_initialize_low_level.S
6+
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_restore.S
7+
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_save.S
8+
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_interrupt_control.S
9+
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_schedule.S
10+
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_stack_build.S
11+
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_system_return.S
12+
${CMAKE_CURRENT_LIST_DIR}/src/tx_timer_interrupt.S
13+
# {{END_TARGET_SOURCES}}
14+
)
15+
16+
target_include_directories(${PROJECT_NAME}
17+
PUBLIC
18+
${CMAKE_CURRENT_LIST_DIR}/inc
19+
)

ports/risc-v32/clang/README.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# RISCV32 clang port
2+
3+
This is basically a copy of the RISC64 gnu port.
4+
The only major modification was changing the load double word (ld)
5+
and store double double (sd) word with load word (ld) and store word (sd).
6+
7+
I also added support for semihosting so the example can be executed on QEMU.
8+
9+
## How to build
10+
11+
cd to the folder where this repo is cloned and run the following commands:
12+
13+
```
14+
cd /threadx/ports/risc-v32/clang/example_build/qemu_virt
15+
./build_libthreadx.sh
16+
./build_threadx_sample.sh
17+
```
18+
19+
The first script will build the ThreadX libraries.
20+
You can find the library in <threadx repo>/build/libthreadx.a.
21+
22+
The second script will build the demo application.
23+
You can find the demo application in <threadx repo>/ports/risc-v32/clang/example_build/qemu_virt/build/demo_threadx.elf
24+
25+
## How to run using QEMU
26+
27+
cd to the folder where this repo is cloned and run the following command:
28+
29+
```
30+
docker run --rm -it -p 1234:1234 -v $(pwd):/threadx -w /threadx ghcr.io/quintauris-tech/qemu-system-riscv32-v10:latest bash
31+
```
32+
33+
The commands assumes that this repo is clone into a folder named "threadx"
34+
35+
```
36+
cd /threadx/ports/risc-v32/clang/example_build/qemu_virt
37+
38+
qemu-system-riscv32 -machine virt -m 16M -bios ./build/demo_threadx.elf -display none -chardev stdio,id=stdio0 -semihosting-config enable=on,userspace=on,chardev=stdio0 -gdb tcp::1234
39+
```
40+
41+
This should print output from different threads. In the QEMU output you should see output like the following:
42+
43+
```
44+
[Thread] : thread_xxxx_entry is here!
45+
```
46+
47+
You can use option -S with qemu-system-riscv32 to debug.
48+
49+
In this case run debugger as /opt/riscv_rv32ima_zicsr/bin/riscv32-unknown-elf-gdb <repo>/ports/risc-v32/gnu/example_build/qemu_virt/build/demo_threadx.elf
50+
51+
```
52+
target remote :1234
53+
```
54+
55+
to connect to the target. Enter 'c' to continue execution.
56+
57+
58+
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/***************************************************************************
2+
* Copyright (c) 2026 Quintauris
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the MIT License which is available at
6+
* https://opensource.org/licenses/MIT.
7+
*
8+
* SPDX-License-Identifier: MIT
9+
**************************************************************************/
10+
11+
#include "plic.h"
12+
#include "hwtimer.h"
13+
#include "uart.h"
14+
#include <stdint.h>
15+
#include <stddef.h>
16+
17+
void *memset(void *des, int c,size_t n)
18+
{
19+
if((des == NULL) || n <=0)
20+
return (void*)des;
21+
char* t = (char*)des;
22+
int i;
23+
for(i=0;i<n;i++)
24+
t[i]=c;
25+
return t;
26+
}
27+
28+
29+
int board_init(void)
30+
{
31+
int ret;
32+
ret = plic_init();
33+
if(ret)
34+
return ret;
35+
ret = uart_init();
36+
if(ret)
37+
return ret;
38+
ret = hwtimer_init();
39+
if(ret)
40+
return ret;
41+
return 0;
42+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/bin/bash
2+
3+
pushd ../../../../../
4+
#cmake -Bbuild -GNinja -DCMAKE_TOOLCHAIN_FILE=cmake/riscv32_clang.cmake .
5+
cmake -Bbuild -DCMAKE_TOOLCHAIN_FILE=cmake/riscv32_clang.cmake .
6+
cmake --build ./build/
7+
popd
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#!/bin/bash
2+
3+
DIRNAME=$(dirname "$0")
4+
BASEDIR=$DIRNAME/../../../../..
5+
6+
mkdir -p build
7+
8+
CC=clang-18
9+
LD=ld.lld-18
10+
11+
$CC -I $BASEDIR/ports/risc-v32/clang/inc -I $BASEDIR/build/custom_inc -g --sysroot=/opt/riscv_rv32ima/riscv32-unknown-elf --target=riscv32 -march=rv32ima_zicsr -mabi=ilp32 -o build/entry.obj -c entry.s
12+
$CC -DTX_INCLUDE_USER_DEFINE_FILE -I $BASEDIR/ports/risc-v32/clang/inc -I $BASEDIR/build/custom_inc -isystem $BASEDIR/common/inc -g --sysroot=/opt/riscv_rv32ima/riscv32-unknown-elf --target=riscv32 -march=rv32ima_zicsr -mabi=ilp32 -D__ASSEMBLER__ -o build/tx_initialize_low_level.obj -c tx_initialize_low_level.S
13+
$CC -DTX_INCLUDE_USER_DEFINE_FILE -I $BASEDIR/ports/risc-v32/clang/inc -I $BASEDIR/build/custom_inc -isystem $BASEDIR/common/inc -g --sysroot=/opt/riscv_rv32ima/riscv32-unknown-elf --target=riscv32 -march=rv32ima_zicsr -mabi=ilp32 -o build/board.obj -c board.c
14+
$CC -DTX_INCLUDE_USER_DEFINE_FILE -I $BASEDIR/ports/risc-v32/clang/inc -I $BASEDIR/build/custom_inc -isystem $BASEDIR/common/inc -g --sysroot=/opt/riscv_rv32ima/riscv32-unknown-elf --target=riscv32 -march=rv32ima_zicsr -mabi=ilp32 -o build/hwtimer.obj -c hwtimer.c
15+
$CC -DTX_INCLUDE_USER_DEFINE_FILE -I $BASEDIR/ports/risc-v32/clang/inc -I $BASEDIR/build/custom_inc -isystem $BASEDIR/common/inc -g --sysroot=/opt/riscv_rv32ima/riscv32-unknown-elf --target=riscv32 -march=rv32ima_zicsr -mabi=ilp32 -o build/plic.obj -c plic.c
16+
$CC -DTX_INCLUDE_USER_DEFINE_FILE -I $BASEDIR/ports/risc-v32/clang/inc -I $BASEDIR/build/custom_inc -isystem $BASEDIR/common/inc -g --sysroot=/opt/riscv_rv32ima/riscv32-unknown-elf --target=riscv32 -march=rv32ima_zicsr -mabi=ilp32 -o build/trap.obj -c trap.c
17+
$CC -DTX_INCLUDE_USER_DEFINE_FILE -I $BASEDIR/ports/risc-v32/clang/inc -I $BASEDIR/build/custom_inc -isystem $BASEDIR/common/inc -g --sysroot=/opt/riscv_rv32ima/riscv32-unknown-elf --target=riscv32 -march=rv32ima_zicsr -mabi=ilp32 -o build/uart.obj -c uart.c
18+
$CC -DTX_INCLUDE_USER_DEFINE_FILE -I $BASEDIR/ports/risc-v32/clang/inc -I $BASEDIR/build/custom_inc -isystem $BASEDIR/common/inc -g --sysroot=/opt/riscv_rv32ima/riscv32-unknown-elf --target=riscv32 -march=rv32ima_zicsr -mabi=ilp32 -o build/demo_threadx.obj -c demo_threadx.c
19+
$LD -Tlink.lds --no-dynamic-linker -m elf32lriscv -static -nostdlib -o build/demo_threadx.elf --Map=build/demo_threadx.map build/entry.obj build/tx_initialize_low_level.obj build/board.obj build/hwtimer.obj build/plic.obj build/trap.obj build/uart.obj build/demo_threadx.obj $BASEDIR/build/libthreadx.a

0 commit comments

Comments
 (0)