mirror of
https://github.com/eclipse-threadx/threadx.git
synced 2026-10-06 06:59:08 +08:00
Added a RISC-V32 architecture port layer for Clang.
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
# Toolchain settings
|
||||
set(CMAKE_C_COMPILER clang-18)
|
||||
set(CMAKE_CXX_COMPILER clang++-18)
|
||||
#set(AS llvm-as)
|
||||
#set(AR llvm-ar)
|
||||
#set(OBJCOPY llvm-objcopy)
|
||||
#set(OBJDUMP llvm-objdump-18)
|
||||
#set(SIZE llvm-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__" CACHE INTERNAL "asm compiler flags")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${LDFLAGS}" CACHE INTERNAL "exe link flags")
|
||||
|
||||
SET(CMAKE_C_FLAGS_DEBUG "--target=riscv32 -march=rv32im_zicsr_zicntr -mabi=ilp32 -g" CACHE INTERNAL "c debug compiler flags")
|
||||
SET(CMAKE_CXX_FLAGS_DEBUG "--target=riscv32 -march=rv32im_zicsr_zicntr -mabi=ilp32 -g" CACHE INTERNAL "cxx debug compiler flags")
|
||||
SET(CMAKE_ASM_FLAGS_DEBUG "--target=riscv32 -march=rv32im_zicsr_zicntr -mabi=ilp32 -g" CACHE INTERNAL "asm debug compiler flags")
|
||||
|
||||
SET(CMAKE_C_FLAGS_RELEASE "--target=riscv32 -march=rv32im_zicsr_zicntr -mabi=ilp32 -O3" CACHE INTERNAL "c release compiler flags")
|
||||
SET(CMAKE_CXX_FLAGS_RELEASE "--target=riscv32 -march=rv32im_zicsr_zicntr -mabi=ilp32 -O3" CACHE INTERNAL "cxx release compiler flags")
|
||||
SET(CMAKE_ASM_FLAGS_RELEASE "--target=riscv32 -march=rv32im_zicsr_zicntr -mabi=ilp32" CACHE INTERNAL "asm release compiler flags")
|
||||
@@ -0,0 +1,18 @@
|
||||
# Name of the target
|
||||
set(CMAKE_SYSTEM_NAME Generic)
|
||||
set(CMAKE_SYSTEM_PROCESSOR risc-v32)
|
||||
|
||||
IF(DEFINED $ENV{GCC_INSTALL_PREFIX})
|
||||
SET(GCC_INSTALL_PREFIX "$ENV{GCC_INSTALL_PREFIX}" CACHE INTERNAL "" FORCE)
|
||||
ELSE()
|
||||
SET(GCC_INSTALL_PREFIX "/opt/riscv_rv32ima" CACHE INTERNAL "" FORCE)
|
||||
ENDIF()
|
||||
|
||||
set(THREADX_ARCH "risc-v32")
|
||||
set(THREADX_TOOLCHAIN "clang")
|
||||
set(ARCH_FLAGS "--sysroot=${GCC_INSTALL_PREFIX}/riscv32-unknown-elf --target=riscv32 -g -march=rv32ima_zicsr -mabi=ilp32")
|
||||
set(CFLAGS "${ARCH_FLAGS}")
|
||||
set(ASFLAGS "${ARCH_FLAGS}")
|
||||
set(LDFLAGS "--no-dynamic-linker -m elf32lriscv -static -nostdlib")
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/riscv32-clang-unknown-elf.cmake)
|
||||
@@ -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
|
||||
)
|
||||
@@ -0,0 +1,58 @@
|
||||
# RISCV32 clang port
|
||||
|
||||
This is basically a copy of the RISC64 gnu port.
|
||||
The only major modification was changing the load double word (ld)
|
||||
and store double double (sd) word with load word (ld) and store word (sd).
|
||||
|
||||
I also added support for semihosting so the example can be executed on QEMU.
|
||||
|
||||
## How to build
|
||||
|
||||
cd to the folder where this repo is cloned and run the following commands:
|
||||
|
||||
```
|
||||
cd /threadx/ports/risc-v32/clang/example_build/qemu_virt
|
||||
./build_libthreadx.sh
|
||||
./build_threadx_sample.sh
|
||||
```
|
||||
|
||||
The first script will build the ThreadX libraries.
|
||||
You can find the library in <threadx repo>/build/libthreadx.a.
|
||||
|
||||
The second script will build the demo application.
|
||||
You can find the demo application in <threadx repo>/ports/risc-v32/clang/example_build/qemu_virt/build/demo_threadx.elf
|
||||
|
||||
## How to run using QEMU
|
||||
|
||||
cd to the folder where this repo is cloned and run the following command:
|
||||
|
||||
```
|
||||
docker run --rm -it -p 1234:1234 -v $(pwd):/threadx -w /threadx ghcr.io/quintauris-tech/qemu-system-riscv32-v10:latest bash
|
||||
```
|
||||
|
||||
The commands assumes that this repo is clone into a folder named "threadx"
|
||||
|
||||
```
|
||||
cd /threadx/ports/risc-v32/clang/example_build/qemu_virt
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
This should print output from different threads. In the QEMU output you should see output like the following:
|
||||
|
||||
```
|
||||
[Thread] : thread_xxxx_entry is here!
|
||||
```
|
||||
|
||||
You can use option -S with qemu-system-riscv32 to debug.
|
||||
|
||||
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
|
||||
|
||||
```
|
||||
target remote :1234
|
||||
```
|
||||
|
||||
to connect to the target. Enter 'c' to continue execution.
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2026 Quintauris
|
||||
*
|
||||
* 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
|
||||
**************************************************************************/
|
||||
|
||||
#include "plic.h"
|
||||
#include "hwtimer.h"
|
||||
#include "uart.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
void *memset(void *des, int c,size_t n)
|
||||
{
|
||||
if((des == NULL) || n <=0)
|
||||
return (void*)des;
|
||||
char* t = (char*)des;
|
||||
int i;
|
||||
for(i=0;i<n;i++)
|
||||
t[i]=c;
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
int board_init(void)
|
||||
{
|
||||
int ret;
|
||||
ret = plic_init();
|
||||
if(ret)
|
||||
return ret;
|
||||
ret = uart_init();
|
||||
if(ret)
|
||||
return ret;
|
||||
ret = hwtimer_init();
|
||||
if(ret)
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
pushd ../../../../../
|
||||
#cmake -Bbuild -GNinja -DCMAKE_TOOLCHAIN_FILE=cmake/riscv32_clang.cmake .
|
||||
cmake -Bbuild -DCMAKE_TOOLCHAIN_FILE=cmake/riscv32_clang.cmake .
|
||||
cmake --build ./build/
|
||||
popd
|
||||
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
DIRNAME=$(dirname "$0")
|
||||
BASEDIR=$DIRNAME/../../../../..
|
||||
|
||||
mkdir -p build
|
||||
|
||||
CC=clang-18
|
||||
LD=ld.lld-18
|
||||
|
||||
$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
|
||||
$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
|
||||
$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
|
||||
$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
|
||||
$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
|
||||
$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
|
||||
$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
|
||||
$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
|
||||
$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
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,58 @@
|
||||
|
||||
.section .text
|
||||
.align 4
|
||||
.global _start
|
||||
.extern main
|
||||
.extern _sysstack_start
|
||||
.extern _bss_start
|
||||
.extern _bss_end
|
||||
_start:
|
||||
csrr t0, mhartid
|
||||
bne t0, zero, 1f
|
||||
li x1, 0
|
||||
li x2, 0
|
||||
li x3, 0
|
||||
li x4, 0
|
||||
li x5, 0
|
||||
li x6, 0
|
||||
li x7, 0
|
||||
li x8, 0
|
||||
li x9, 0
|
||||
li x10, 0
|
||||
li x11, 0
|
||||
li x12, 0
|
||||
li x13, 0
|
||||
li x14, 0
|
||||
li x15, 0
|
||||
li x16, 0
|
||||
li x17, 0
|
||||
li x18, 0
|
||||
li x19, 0
|
||||
li x20, 0
|
||||
li x21, 0
|
||||
li x22, 0
|
||||
li x23, 0
|
||||
li x24, 0
|
||||
li x25, 0
|
||||
li x26, 0
|
||||
li x27, 0
|
||||
li x28, 0
|
||||
li x29, 0
|
||||
li x30, 0
|
||||
li x31, 0
|
||||
la t0, _sysstack_start
|
||||
li t1, 0x1000
|
||||
add sp, t0, t1
|
||||
la t0, _bss_start
|
||||
la t1, _bss_end
|
||||
_bss_clean_start:
|
||||
bgeu t0, t1, _bss_clean_end
|
||||
sb zero, 0(t0)
|
||||
addi t0, t0, 1
|
||||
j _bss_clean_start
|
||||
_bss_clean_end:
|
||||
call main
|
||||
1:
|
||||
/* todo smp */
|
||||
wfi
|
||||
j 1b
|
||||
@@ -0,0 +1,35 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2026 Quintauris
|
||||
*
|
||||
* 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
|
||||
**************************************************************************/
|
||||
|
||||
#include "tx_port.h"
|
||||
#include "csr.h"
|
||||
#include "hwtimer.h"
|
||||
|
||||
#define CLINT (0x02000000L)
|
||||
#define CLINT_TIME (CLINT+0xBFF8)
|
||||
#define CLINT_TIMECMP(hart_id) (CLINT+0x4000+8*(hart_id))
|
||||
|
||||
|
||||
int hwtimer_init(void)
|
||||
{
|
||||
int hart = riscv_get_core();
|
||||
uint64_t time = *((uint64_t*)CLINT_TIME);
|
||||
*((uint64_t*)CLINT_TIMECMP(hart)) = time + TICKNUM_PER_TIMER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hwtimer_handler(void)
|
||||
{
|
||||
int hart = riscv_get_core();
|
||||
uint64_t time = *((uint64_t*)CLINT_TIME);
|
||||
*((uint64_t*)CLINT_TIMECMP(hart)) = time + TICKNUM_PER_TIMER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2026 Quintauris
|
||||
*
|
||||
* 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
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef RISCV_HWTIMER_H
|
||||
#define RISCV_HWTIMER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define TICKNUM_PER_SECOND 10000000
|
||||
#define TICKNUM_PER_TIMER (TICKNUM_PER_SECOND / 10)
|
||||
|
||||
int hwtimer_init(void);
|
||||
int hwtimer_handler(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,49 @@
|
||||
OUTPUT_ARCH( "riscv" )
|
||||
ENTRY( _start )
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/*
|
||||
* ensure that entry.S / _entry is at 0x80000000,
|
||||
* where qemu's -kernel jumps.
|
||||
*/
|
||||
. = 0x80000000;
|
||||
|
||||
.text : {
|
||||
*(.text .text.*)
|
||||
. = ALIGN(0x1000);
|
||||
PROVIDE(etext = .);
|
||||
}
|
||||
|
||||
.rodata : {
|
||||
. = ALIGN(16);
|
||||
*(.srodata .srodata.*) /* do not need to distinguish this from .rodata */
|
||||
. = ALIGN(16);
|
||||
*(.rodata .rodata.*)
|
||||
}
|
||||
|
||||
.data : {
|
||||
. = ALIGN(16);
|
||||
*(.sdata .sdata.*) /* do not need to distinguish this from .data */
|
||||
. = ALIGN(16);
|
||||
*(.data .data.*)
|
||||
}
|
||||
|
||||
.bss : {
|
||||
. = ALIGN(16);
|
||||
_bss_start = .;
|
||||
*(.sbss .sbss.*) /* do not need to distinguish this from .bss */
|
||||
. = ALIGN(16);
|
||||
*(.bss .bss.*)
|
||||
_bss_end = .;
|
||||
}
|
||||
|
||||
.stack : {
|
||||
. = ALIGN(4096);
|
||||
_sysstack_start = .;
|
||||
. += 0x1000;
|
||||
_sysstack_end = .;
|
||||
}
|
||||
|
||||
PROVIDE(_end = .);
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
#include "plic.h"
|
||||
#include <stddef.h>
|
||||
irq_callback callbacks[MAX_CALLBACK_NUM];
|
||||
|
||||
void plic_irq_enable(int irqno)
|
||||
{
|
||||
int hart = riscv_get_core();
|
||||
*(uint32_t*)PLIC_MENABLE(hart) = (*(uint32_t*)PLIC_MENABLE(hart) | (1 << irqno));
|
||||
return;
|
||||
}
|
||||
|
||||
void plic_irq_disable(int irqno)
|
||||
{
|
||||
int hart = riscv_get_core();
|
||||
*(uint32_t*)PLIC_MENABLE(hart) = (*(uint32_t*)PLIC_MENABLE(hart) & (~(1 << irqno)));
|
||||
return;
|
||||
}
|
||||
|
||||
void plic_prio_set(int irqno, int prio)
|
||||
{
|
||||
PLIC_SET_PRIO(irqno, prio);
|
||||
}
|
||||
|
||||
int plic_prio_get(int irqno)
|
||||
{
|
||||
return PLIC_GET_PRIO(irqno);
|
||||
}
|
||||
|
||||
int plic_register_callback(int irqno, irq_callback callback)
|
||||
{
|
||||
if(!(irqno >=0 && irqno < MAX_CALLBACK_NUM))
|
||||
return -1;
|
||||
callbacks[irqno] = callback;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int plic_unregister_callback(int irqno)
|
||||
{
|
||||
return plic_register_callback(irqno, NULL);
|
||||
}
|
||||
|
||||
int plic_init(void)
|
||||
{
|
||||
for(int i=0;i<MAX_CALLBACK_NUM;i++)
|
||||
{
|
||||
callbacks[i] = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int plic_claim(void)
|
||||
{
|
||||
int hart = riscv_get_core();
|
||||
return (*(uint32_t*)PLIC_MCLAIM(hart));
|
||||
}
|
||||
|
||||
void plic_complete(int irqno)
|
||||
{
|
||||
int hart = riscv_get_core();
|
||||
*(uint32_t*)(PLIC_MCOMPLETE(hart)) = (uint32_t)irqno;
|
||||
return;
|
||||
}
|
||||
|
||||
int plic_irq_intr(void)
|
||||
{
|
||||
int ret = -1;
|
||||
int irqno = plic_claim();
|
||||
if(callbacks[irqno] != NULL)
|
||||
ret = (callbacks[irqno])(irqno);
|
||||
plic_complete(irqno);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2026 Quintauris
|
||||
*
|
||||
* 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
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef RISCV_PLIC_H
|
||||
#define RISCV_PLIC_H
|
||||
|
||||
#include "csr.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#define PLIC 0x0c000000L
|
||||
#define PLIC_PRIORITY (PLIC + 0x0)
|
||||
#define PLIC_PENDING (PLIC + 0x1000)
|
||||
#define PLIC_MENABLE(hart) (PLIC + 0x2000 + (hart)*0x100)
|
||||
#define PLIC_SENABLE(hart) (PLIC + 0x2080 + (hart)*0x100)
|
||||
#define PLIC_MPRIORITY(hart) (PLIC + 0x200000 + (hart)*0x2000)
|
||||
#define PLIC_SPRIORITY(hart) (PLIC + 0x201000 + (hart)*0x2000)
|
||||
#define PLIC_MCLAIM(hart) (PLIC + 0x200004 + (hart)*0x2000)
|
||||
#define PLIC_SCLAIM(hart) (PLIC + 0x201004 + (hart)*0x2000)
|
||||
#define PLIC_MCOMPLETE(hart) (PLIC + 0x200004 + (hart)*0x2000)
|
||||
#define PLIC_SCOMPLETE(hart) (PLIC + 0x201004 + (hart)*0x2000)
|
||||
|
||||
|
||||
#define PLIC_GET_PRIO(irqno) (*(uint32_t *)(PLIC_PRIORITY + (irqno)*4))
|
||||
#define PLIC_SET_PRIO(irqno, prio) (*(uint32_t *)(PLIC_PRIORITY + (irqno)*4) = (prio))
|
||||
|
||||
#define MAX_CALLBACK_NUM 128
|
||||
typedef int (*irq_callback)(int irqno);
|
||||
|
||||
void plic_irq_enable(int irqno);
|
||||
void plic_irq_disable(int irqno);
|
||||
int plic_prio_get(int irqno);
|
||||
void plic_prio_set(int irqno, int prio);
|
||||
int plic_register_callback(int irqno, irq_callback callback);
|
||||
int plic_unregister_callback(int irqno);
|
||||
int plic_init(void);
|
||||
int plic_claim(void);
|
||||
void plic_complete(int irqno);
|
||||
|
||||
int plic_irq_intr(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
#include "csr.h"
|
||||
#include <stdint.h>
|
||||
#include "uart.h"
|
||||
#include "hwtimer.h"
|
||||
#include "plic.h"
|
||||
#include <tx_port.h>
|
||||
#include <tx_api.h>
|
||||
|
||||
#define OS_IS_INTERUPT(mcause) (mcause & 0x80000000u)
|
||||
#define OS_IS_EXCEPTION(mcause) (~(OS_IS_INTERUPT))
|
||||
#define OS_IS_TICK_INT(mcause) (mcause == 0x80000007u)
|
||||
#define OS_IS_SOFT_INT(mcause) (mcause == 0x80000003u)
|
||||
#define OS_IS_EXT_INT(mcause) (mcause == 0x8000000bu)
|
||||
#define OS_IS_TRAP_USER(mcause) (mcause == 0x0000000bu)
|
||||
extern void _tx_timer_interrupt(void);
|
||||
|
||||
extern int uart_putc(int ch);
|
||||
|
||||
static void print_hex(uintptr_t val)
|
||||
{
|
||||
char digits[] = "0123456789ABCDEF";
|
||||
uart_putc('0');
|
||||
uart_putc('x');
|
||||
for(int i = (sizeof(uintptr_t)*2) - 1; i >= 0; i--) {
|
||||
int d = (val >> (i*4)) & 0xF;
|
||||
uart_putc(digits[d]);
|
||||
}
|
||||
uart_putc('\n');
|
||||
}
|
||||
|
||||
void trap_handler(uintptr_t mcause, uintptr_t mepc, uintptr_t mtval)
|
||||
{
|
||||
// uart_puts("DEBUG : threadx/ports/risc-v32/gnu/example_build/qemu_virt/trap.c, trap_handler\n");
|
||||
if(OS_IS_INTERUPT(mcause))
|
||||
{
|
||||
if(OS_IS_TICK_INT(mcause))
|
||||
{
|
||||
hwtimer_handler();
|
||||
_tx_timer_interrupt();
|
||||
}
|
||||
else if(OS_IS_EXT_INT(mcause))
|
||||
{
|
||||
int ret = plic_irq_intr();
|
||||
if(ret)
|
||||
{
|
||||
puts("[INTERRUPT]: handler irq error!");
|
||||
while(1) ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
puts("[INTERRUPT]: now can't deal with the interrupt!");
|
||||
while(1) ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
puts("[EXCEPTION] : Unkown Error!!");
|
||||
puts("mcause:");
|
||||
print_hex(mcause);
|
||||
puts("mepc:");
|
||||
print_hex(mepc);
|
||||
puts("mtval:");
|
||||
print_hex(mtval);
|
||||
while(1) ;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2026 Quintauris
|
||||
*
|
||||
* 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
|
||||
**************************************************************************/
|
||||
|
||||
#include "csr.h"
|
||||
#include "tx_port.h"
|
||||
|
||||
.section .text
|
||||
.align 4
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* trap_entry RISC-V32/GNU */
|
||||
/* 6.4.x */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* Francisco Merino, Quintauris */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function is responsible for riscv processor trap handle */
|
||||
/* It will do the contex save and call c trap_handler and do contex */
|
||||
/* load */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* trap_handler */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* hardware exception */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 02-02-2026 Francisco Merino Adapted for RV32 Clang */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Initialize */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
.global trap_entry
|
||||
.extern trap_handler
|
||||
.extern _tx_thread_context_restore
|
||||
trap_entry:
|
||||
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
|
||||
addi sp, sp, -65*REGBYTES // Allocate space for all registers - with floating point enabled
|
||||
#else
|
||||
addi sp, sp, -32*REGBYTES // Allocate space for all registers - without floating point enabled
|
||||
#endif
|
||||
|
||||
STORE x1, 28*REGBYTES(sp) // Store RA, 28*REGBYTES(because call will override ra [ra is a calle register in riscv])
|
||||
|
||||
call _tx_thread_context_save
|
||||
|
||||
csrr a0, mcause
|
||||
csrr a1, mepc
|
||||
csrr a2, mtval
|
||||
addi sp, sp, -4
|
||||
sw ra, 0(sp)
|
||||
call trap_handler
|
||||
lw ra, 0(sp)
|
||||
addi sp, sp, 4
|
||||
call _tx_thread_context_restore
|
||||
// it will nerver return
|
||||
_err:
|
||||
wfi
|
||||
j _err
|
||||
.section .text
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_initialize_low_level RISC-V32/GNU */
|
||||
/* 6.4.x */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* Francisco Merino, Quintauris */
|
||||
/* */
|
||||
/* 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 */
|
||||
/* */
|
||||
/* 26-02-2026 Francisco Merino Adapted for RV32 Clang */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
/* VOID _tx_initialize_low_level(VOID)
|
||||
{ */
|
||||
// .global _tx_initialize_low_level
|
||||
.weak _tx_initialize_low_level
|
||||
.extern _end
|
||||
.extern board_init
|
||||
_tx_initialize_low_level:
|
||||
|
||||
/* debug print
|
||||
.section .rodata
|
||||
debug_str_init:
|
||||
.string "DEBUG : threadx/ports/risc-v32/gnu/example_build/qemu_virt/tx_initialize_low_level.S, _tx_initialize_low_level\n"
|
||||
*/
|
||||
.section .text
|
||||
|
||||
la t0, _tx_thread_system_stack_ptr
|
||||
sw sp, 0(t0) // Save system stack pointer
|
||||
|
||||
la t0, _end // Pickup first free address
|
||||
la t1, _tx_initialize_unused_memory
|
||||
sw t0, 0(t1) // Save unused memory address
|
||||
li t0, MSTATUS_MIE
|
||||
csrrc zero, mstatus, t0 // clear MSTATUS_MIE bit
|
||||
li t0, (MSTATUS_MPP_M | MSTATUS_MPIE )
|
||||
csrrs zero, mstatus, t0 // set MSTATUS_MPP, MPIE bit
|
||||
li t0, (MIE_MTIE | MIE_MSIE | MIE_MEIE)
|
||||
csrrs zero, mie, t0 // set mie
|
||||
#ifdef __riscv_flen
|
||||
li t0, MSTATUS_FS
|
||||
csrrs zero, mstatus, t0 // set MSTATUS_FS bit to open f/d isa in riscv
|
||||
fscsr x0
|
||||
#endif
|
||||
addi sp, sp, -4
|
||||
sw ra, 0(sp)
|
||||
call board_init
|
||||
/* debug print
|
||||
la a0, debug_str_init
|
||||
call uart_puts
|
||||
*/
|
||||
lw ra, 0(sp)
|
||||
addi sp, sp, 4
|
||||
la t0, trap_entry
|
||||
csrw mtvec, t0
|
||||
ret
|
||||
@@ -0,0 +1,102 @@
|
||||
#include "uart.h"
|
||||
#include "csr.h"
|
||||
#include "plic.h"
|
||||
#include <stdint.h>
|
||||
|
||||
// the UART control registers are memory-mapped
|
||||
// at address UART0. this macro returns the
|
||||
// address of one of the registers.
|
||||
#define Reg(reg) ((volatile unsigned char *)(UART0 + (reg)))
|
||||
|
||||
// the UART control registers.
|
||||
// some have different meanings for
|
||||
// read vs write.
|
||||
// see http://byterunner.com/16550.html
|
||||
#define RHR 0 // receive holding register (for input bytes)
|
||||
#define THR 0 // transmit holding register (for output bytes)
|
||||
#define IER 1 // interrupt enable register
|
||||
#define IER_RX_ENABLE (1<<0)
|
||||
#define IER_TX_ENABLE (1<<1)
|
||||
#define FCR 2 // FIFO control register
|
||||
#define FCR_FIFO_ENABLE (1<<0)
|
||||
#define FCR_FIFO_CLEAR (3<<1) // clear the content of the two FIFOs
|
||||
#define ISR 2 // interrupt status register
|
||||
#define LCR 3 // line control register
|
||||
#define LCR_EIGHT_BITS (3<<0)
|
||||
#define LCR_BAUD_LATCH (1<<7) // special mode to set baud rate
|
||||
#define LSR 5 // line status register
|
||||
#define LSR_RX_READY (1<<0) // input is waiting to be read from RHR
|
||||
#define LSR_TX_IDLE (1<<5) // THR can accept another character to send
|
||||
|
||||
#define ReadReg(reg) (*(Reg(reg)))
|
||||
#define WriteReg(reg, v) (*(Reg(reg)) = (v))
|
||||
|
||||
int uart_init(void)
|
||||
{
|
||||
// disable interrupts.
|
||||
WriteReg(IER, 0x00);
|
||||
|
||||
// special mode to set baud rate.
|
||||
WriteReg(LCR, LCR_BAUD_LATCH);
|
||||
|
||||
// LSB for baud rate of 38.4K.
|
||||
WriteReg(0, 0x03);
|
||||
|
||||
// MSB for baud rate of 38.4K.
|
||||
WriteReg(1, 0x00);
|
||||
|
||||
// leave set-baud mode,
|
||||
// and set word length to 8 bits, no parity.
|
||||
WriteReg(LCR, LCR_EIGHT_BITS);
|
||||
|
||||
// reset and enable FIFOs.
|
||||
WriteReg(FCR, FCR_FIFO_ENABLE | FCR_FIFO_CLEAR);
|
||||
|
||||
// enable transmit and receive interrupts.
|
||||
// WriteReg(IER, IER_TX_ENABLE | IER_RX_ENABLE);
|
||||
|
||||
//enable UART0 in PLIC
|
||||
plic_irq_enable(UART0_IRQ);
|
||||
|
||||
//set UART0 priority in PLIC
|
||||
plic_prio_set(UART0_IRQ, 1);
|
||||
|
||||
//register callback for UART0
|
||||
//plic_register_callback(UART0_IRQ, uart_intr);
|
||||
puts("[UART0] : Uart Init Done, this is Test output!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uart_putc_nolock(int ch)
|
||||
{
|
||||
// wait for Transmit Holding Empty to be set in LSR.
|
||||
while((ReadReg(LSR) & LSR_TX_IDLE) == 0)
|
||||
;
|
||||
WriteReg(THR, ch);
|
||||
return;
|
||||
}
|
||||
|
||||
int uart_putc(int ch)
|
||||
{
|
||||
int intr_enable = riscv_mintr_get();
|
||||
riscv_mintr_off();
|
||||
uart_putc_nolock(ch);
|
||||
riscv_mintr_restore(intr_enable);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int uart_puts(const char* str)
|
||||
{
|
||||
int i;
|
||||
int intr_enable = riscv_mintr_get();
|
||||
riscv_mintr_off();
|
||||
for(i=0;str[i]!=0;i++)
|
||||
{
|
||||
uart_putc_nolock(str[i]);
|
||||
}
|
||||
uart_putc_nolock('\n');
|
||||
riscv_mintr_restore(intr_enable);
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/***************************************************************************
|
||||
* 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
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef RISCV_UART_H
|
||||
#define RISCV_UART_H
|
||||
|
||||
#define UART0 0x10000000L
|
||||
#define UART0_IRQ 10
|
||||
|
||||
#define puts uart_puts
|
||||
int uart_init(void);
|
||||
int uart_putc(int ch);
|
||||
void uart_putc_nolock(int ch);
|
||||
int uart_puts(const char* str);
|
||||
#endif
|
||||
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) 2026 Quintauris
|
||||
*
|
||||
* 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 */
|
||||
/* */
|
||||
/* Francisco Merino, Quintauris */
|
||||
/* */
|
||||
/* 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 */
|
||||
/* */
|
||||
/* 26-02-2026 Francisco Merino 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) 2026 Quintauris
|
||||
*
|
||||
* 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 */
|
||||
/* */
|
||||
/* Francisco Merino, Quintauris */
|
||||
/* */
|
||||
/* 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 */
|
||||
/* */
|
||||
/* 26-02-2026 Francisco Merino 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) 2026 Quintauris
|
||||
*
|
||||
* 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 */
|
||||
/* */
|
||||
/* Francisco Merino, Quintauris */
|
||||
/* */
|
||||
/* 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 */
|
||||
/* */
|
||||
/* 26-02-2026 Francisco Merino 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
Reference in New Issue
Block a user