Compare commits

...

10 Commits

12 changed files with 334 additions and 79 deletions

View File

@@ -15,6 +15,9 @@ target_link_libraries(c PUBLIC gcc)
set(THREADX_CUSTOM_PORT ${CMAKE_CURRENT_LIST_DIR}/port/threadx)
add_subdirectory(third-party/threadx)
target_link_libraries(threadx PUBLIC c)
#Adds threadx_smp
add_subdirectory(port/threadx_smp)
target_link_libraries(threadx_smp PUBLIC c)
# Adds netxduo
set(NETXDUO_CUSTOM_PORT ${CMAKE_CURRENT_LIST_DIR}/port/threadx)
set(NXD_ENABLE_FILE_SERVERS OFF)
@@ -30,12 +33,12 @@ endif()
###############################################################################
project(threadx_demo C ASM)
option(NX_DEBUG "compile netxduo debug output in" OFF)
set(TARGET_MEM "ram" CACHE STRING "memory map to use" )
set(TARGET_MEM "ram" CACHE STRING "memory map to use")
set(CMAKE_EXECUTABLE_SUFFIX_C ".elf")
function(setup_target TARGET)
set(options)
set(oneValueArgs) # none for now
set(oneValueArgs) # none for now
set(multiValueArgs LIBRARIES SOURCES)
cmake_parse_arguments(ST "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(ST_UNPARSED_ARGUMENTS)
@@ -43,13 +46,13 @@ function(setup_target TARGET)
endif()
add_executable(${TARGET})
target_sources(${TARGET} PRIVATE
port/picolibc/port.c
port/moonlight/bootup.c
port/moonlight/board.c
port/moonlight/trap_non_vectored.c
port/moonlight/exception.c
port/moonlight/vector_table.c
target_sources(${TARGET} PRIVATE
port/picolibc/port.c
port/moonlight/bootup.c
port/moonlight/board.c
port/moonlight/trap_non_vectored.c
port/moonlight/exception.c
port/moonlight/vector_table.c
)
if("netxduo" IN_LIST ST_LIBRARIES)
target_sources(${TARGET} PRIVATE port/moonlight/mnrs_network_driver.c)
@@ -67,7 +70,7 @@ function(setup_target TARGET)
-ffunction-sections
)
if(NX_DEBUG)
target_compile_definitions(${TARGET} PRIVATE NX_DEBUG NX_DEBUG_PACKET)
target_compile_definitions(${TARGET} PRIVATE NX_DEBUG NX_DEBUG_PACKET)
endif()
target_link_directories(${TARGET} PRIVATE src) # needed for linker script includes
target_link_options(${TARGET} PRIVATE
@@ -80,19 +83,16 @@ function(setup_target TARGET)
if(ST_LIBRARIES)
target_link_libraries(${TARGET} PRIVATE ${ST_LIBRARIES})
endif()
target_link_libraries(${TARGET} PRIVATE threadx)
add_custom_command(TARGET ${TARGET} POST_BUILD
COMMAND ${OBJCOPY} -O ihex $<TARGET_FILE:${TARGET}> ${CMAKE_BINARY_DIR}/${TARGET}.hex
COMMAND ${OBJCOPY} -O ihex $<TARGET_FILE:${TARGET}> ${CMAKE_BINARY_DIR}/${TARGET}.hex
COMMAND ${OBJCOPY} -O binary $<TARGET_FILE:${TARGET}> ${CMAKE_BINARY_DIR}/${TARGET}.bin
COMMAND ${SIZE} $<TARGET_FILE:${TARGET}>
COMMAND ${OBJDUMP} -S $<TARGET_FILE:${TARGET}> > ${TARGET}.dis
COMMAND ${OBJDUMP} -S $<TARGET_FILE:${TARGET}> > ${TARGET}.dis
COMMENT "Creating collateral for ${TARGET}"
)
endfunction()
setup_target(thread_demo SOURCES src/thread_demo/main.c)
setup_target(tcp_demo
LIBRARIES netxduo
SOURCES src/tcp_demo/main.c
)
setup_target(thread_demo LIBRARIES threadx SOURCES src/thread_demo/main.c)
setup_target(tcp_demo LIBRARIES threadx netxduo SOURCES src/tcp_demo/main.c)
setup_target(smp_demo LIBRARIES threadx_smp SOURCES src/thread_demo/main.c)

View File

@@ -9,7 +9,7 @@
#include <stdint.h>
#include <string.h>
#include <picotls.h>
#include <tx_port.h>
#ifdef __cplusplus
#define EXTERN_C extern "C"
#else
@@ -50,7 +50,6 @@ extern int main(void);
// The linker script will place this in the reset entry point.
// It will be 'called' with no stack or C runtime configuration.
// NOTE - this only supports a single hart.
// tp will not be initialized
void _start(void) {
// Setup SP and GP
@@ -64,6 +63,24 @@ void _start(void) {
"la gp, __global_pointer$;"
".option pop;"
"la sp, _sp;"
#if defined(__riscv_zicsr)
"csrr t0, mhartid;"
#else
"li t0, 0;"
#endif
"la t1, __stack_size;"
"la t1, __stack_size;"
"la sp, _sp;"
// Loop incase M extension is not present
"1:;"
"beqz t0, 2f;"
"sub sp, sp, t1;"
"addi t0, t0, -1;"
"j 1b;"
"2:;"
#ifdef TX_THREAD_SMP_MAX_CORES
"call _tx_thread_smp_initialize_wait;"
#endif
"jal zero, _initialize;"
: /* output: none %0 */
: /* input: none */

View File

@@ -1,4 +1,5 @@
#include "hwtimer.h"
#include "platform.h"
#include "riscv-traps.h"
#include <stdint.h>
#include <stdio.h>
@@ -39,6 +40,11 @@ void trap_handler(uintptr_t mcause, uintptr_t mepc, uintptr_t mtval) {
hwtimer_handler();
_tx_timer_interrupt();
break;
#ifdef TX_THREAD_SMP_INTER_CORE_INTERRUPT
case RISCV_INT_MSI:
set_aclint_msip(aclint, csr_read_mhartid(), 0);
break;
#endif
case RISCV_INT_MEI:
puts("[INTERRUPT]: handler ext irq error!\n");
while(1)

View File

@@ -138,19 +138,19 @@ trap_handler:
.extern __heap_start
.extern board_init
_tx_initialize_low_level:
STORE sp, _tx_thread_system_stack_ptr, t0 // Save system stack pointer
STORE sp, _tx_thread_system_stack_ptr, t0 // Save system stack pointer
la t0, __heap_start // Pickup first free address
STORE t0, _tx_initialize_unused_memory, t1 // Save unused memory address
la t0, __heap_start // Pickup first free address
STORE t0, _tx_initialize_unused_memory, t1 // Save unused memory address
li t0, MSTATUS_MIE
csrrc zero, mstatus, t0 // clear MSTATUS_MIE bit
csrrc zero, mstatus, t0 // clear MSTATUS_MIE bit
li t0, (MSTATUS_MPP_M | MSTATUS_MPIE )
csrrs zero, mstatus, t0 // set MSTATUS_MPP, MPIE bit
csrrs zero, mstatus, t0 // set MSTATUS_MPP, MPIE bit
li t0, (MIE_MTIE | MIE_MSIE | MIE_MEIE)
csrrs zero, mie, t0 // set mie
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
csrrs zero, mstatus, t0 // set MSTATUS_FS bit to open f/d isa in riscv
fscsr x0
#endif
addi sp, sp, -8

View File

@@ -27,6 +27,7 @@ set(THREADX_SMP_CUSTOM_SRC
src/tx_thread_smp_unprotect.S
src/tx_thread_stack_build.S
src/tx_thread_system_return.S
src/tx_timer_interrupt.c
)
threadx_smp_add_offsets(
@@ -34,13 +35,11 @@ threadx_smp_add_offsets(
OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/generated
SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/src/tx_asm_offsets.c
INCLUDE_DIRS
${THREADX_COMMON_SMP_DIR}/inc
${THREADX_SMP_CUSTOM_INC}
COMPILE_DEFINITIONS
TX_QUEUE_MESSAGE_MAX_SIZE=16
${THREADX_COMMON_SMP_DIR}/inc
${THREADX_SMP_CUSTOM_INC}
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/inc/tx_port.h
${THREADX_COMMON_SMP_DIR}/inc/tx_api.h
${CMAKE_CURRENT_SOURCE_DIR}/inc/tx_port.h
${THREADX_COMMON_SMP_DIR}/inc/tx_api.h
OUT_INCLUDE_DIR THREADX_SMP_GENERATED_INC_DIR
)
@@ -59,13 +58,3 @@ target_include_directories(threadx_smp PRIVATE
)
target_compile_definitions(threadx_smp PRIVATE TX_QUEUE_MESSAGE_MAX_SIZE=16) #This is addressed in PR #503
add_dependencies(threadx_smp threadx_smp_offsets)
add_executable(smp_demo)
target_include_directories(smp_demo PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/../moonlight
)
target_link_libraries(smp_demo PRIVATE threadx_smp)
target_sources(smp_demo PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../src/thread_demo/main.c)
#cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=$PWD/../../cmake/rv32gc_gnu.cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=YES

View File

@@ -11,7 +11,7 @@ file(STRINGS "${INPUT}" OFFSET_LINES REGEX "->")
set(OFFSET_CONTENT "/* Generated by GenerateAsmOffsets.cmake. */\n")
foreach(LINE IN LISTS OFFSET_LINES)
string(REGEX MATCH "->([A-Za-z0-9_]+)[^0-9-]*(-?[0-9]+)" _ "${LINE}")
string(REGEX MATCH "-->([A-Za-z0-9_]+)[^0-9-]*(-?[0-9]+)" _ "${LINE}")
if(NOT CMAKE_MATCH_1)
continue()
endif()

View File

@@ -69,7 +69,7 @@
#define LWU lw
#define LOG_REGBYTES 2
#endif
#define REGBYTES (1 << LOG_REGBYTES)
#define REGBYTES (1 << LOG_REGBYTES)
#include "tx_asm_offsets.inc"
@@ -89,6 +89,13 @@
#define TX_THREAD_SMP_CORE_MASK 0xF /* Where bit 0 represents Core 0, bit 1 represents Core 1, etc. */
#endif
/* Declare ThreadX to discover the cores dynamically. The ceiling is given by TX_THREAD_SMP_MAX_CORES */
/*
The current implementation does not support dynamic discovery, but simply set the runtime determined number to
TX_THREAD_SMP_MAX_CORES. See tx_thread_smp_low_level_initialize.S
#define TX_THREAD_SMP_DYNAMIC_CORE_MAX
*/
/* Define INLINE_DECLARE */
#define INLINE_DECLARE inline
@@ -105,6 +112,10 @@
#define TX_THREAD_SMP_INTER_CORE_INTERRUPT
/* Use default wakeup logic*/
#define TX_THREAD_SMP_DEFAULT_WAKEUP_LOGIC
/* Determine if there is customer-specific wakeup logic needed. */
#ifdef TX_THREAD_SMP_WAKEUP_LOGIC

View File

@@ -2,9 +2,7 @@
#include "tx_api.h"
#define TX_ASM_OFFSET(symbol, value) __asm__ volatile("\n.ascii \"->" #symbol " %c0\\n\"" : : "i" (value))
#define TX_ASM_OFFSET(symbol, value) __asm__ volatile("\n.ascii \"-->" #symbol " %c0\\n\"" : : "i"(value))
void tx_asm_offsets_generate(void)
{

View File

@@ -10,6 +10,85 @@
#include "csr.h"
#include "tx_port.h"
.section .text
.align 4
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* trap_entry RISC-V64/GNU */
/* 6.2.1 */
/* AUTHOR */
/* */
/* Jer6y , luojun@oerv.isrc.iscas.ac.cn */
/* */
/* 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 */
/* */
/* 10-25-2024 Jerry Luo */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Initialize */
/** */
/**************************************************************************/
/**************************************************************************/
.global trap_entry
.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, -8
STORE ra, 0(sp)
call trap_handler
LOAD ra, 0(sp)
addi sp, sp, 8
call _tx_thread_context_restore
// it will nerver return
.weak trap_handler
trap_handler:
1:
j 1b
.section .text
/**************************************************************************/
/* */
@@ -81,4 +160,4 @@ _tx_initialize_low_level:
addi sp, sp, 8
la t0, trap_entry
csrw mtvec, t0
ret
ret

View File

@@ -1,23 +1,71 @@
#include "tx_port.h"
#include "csr.h"
.section .text
.align 2
.global _tx_thread_smp_initialize_wait
.type _tx_thread_smp_initialize_wait, @function
.extern _tx_thread_schedule
_tx_thread_smp_initialize_wait:
/* Core 0 continues initialization. All other harts wait until the
release flag is set by the low-level SMP initialization path. */
/* Lockout interrupts while startup synchronization is in progress. */
csrci mstatus, 0x08 // Lockout interrupts
/* Pickup current hart ID. */
csrr t0, mhartid // Pickup current hart ID
beqz t0, _tx_thread_smp_initialize_done // Core 0 does not wait
la t1, _tx_thread_smp_release_cores_flag // Release flag address
/* Build per-hart offsets for ULONG and pointer arrays. */
slli t1, t0, 2 // ULONG array offset
slli t2, t0, LOG_REGBYTES // Pointer array offset
_tx_thread_smp_initialize_wait_loop:
LWU t2, 0(t1) // Pickup release flag
bnez t2, _tx_thread_smp_initialize_done // Exit once core 0 releases secondaries
j _tx_thread_smp_initialize_wait_loop // Keep waiting
/* Wait until ThreadX has acknowledged this hart by setting its
system state to TX_INITIALIZE_IN_PROGRESS. */
li t3, 0xF0F0F0F0 // TX_INITIALIZE_IN_PROGRESS
la t4, _tx_thread_system_state // Base of system state array
add t5, t4, t1 // This hart's system state slot
_tx_thread_smp_wait_for_initialize:
LWU t6, 0(t5) // Pickup current hart's system state
bne t6, t3, _tx_thread_smp_wait_for_initialize
/* Save the system stack pointer for this hart. */
la t3, _tx_thread_system_stack_ptr // Base of system stack pointer array
add t3, t3, t2 // Select this hart's slot
STORE sp, 0(t3) // Save system stack pointer
/* Wait for core 0 to release the secondary harts. */
la t3, _tx_thread_smp_release_cores_flag // Release flag address
_tx_thread_smp_wait_for_release:
LWU t6, 0(t3) // Pickup release flag
beqz t6, _tx_thread_smp_wait_for_release
/* Acknowledge the release by clearing this hart's system state. */
sw x0, 0(t5) // Set this hart's system state to zero
/* Wait for core 0 to finish initialization. */
_tx_thread_smp_wait_for_core0:
LWU t6, 0(t4) // Pickup core 0 system state
bnez t6, _tx_thread_smp_wait_for_core0
/* Prepare interrupt state */
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
la t0, trap_entry
csrw mtvec, t0
/* Initialization is complete for this hart, enter the scheduler. */
j _tx_thread_schedule
_tx_thread_smp_initialize_done:
ret

View File

@@ -6,26 +6,4 @@
.global _tx_thread_smp_low_level_initialize
.type _tx_thread_smp_low_level_initialize, @function
_tx_thread_smp_low_level_initialize:
/* Only hart 0 performs low-level SMP initialization. */
csrr t0, mhartid // Pickup current hart ID
bnez t0, _tx_thread_smp_low_level_initialize_done
/* Keep secondary harts parked until kernel-enter releases them. */
la t1, _tx_thread_smp_release_cores_flag
sw x0, 0(t1) // Clear release flag
#ifdef TX_THREAD_SMP_DYNAMIC_CORE_MAX
/* Record the detected core count supplied by the caller. */
la t1, _tx_thread_smp_detected_cores
sw a0, 0(t1)
#endif
/* Platform-specific secondary-hart startup can go here.
This is where core 0 would program boot addresses, send startup IPIs,
or otherwise bring the other harts online. */
fence rw, rw // Publish startup state
_tx_thread_smp_low_level_initialize_done:
ret

View File

@@ -0,0 +1,129 @@
/***************************************************************************
* 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
**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Timer */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
#define TX_THREAD_SMP_SOURCE_CODE
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_thread.h"
#include "tx_timer.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_timer_interrupt RISC-V64/GNU */
/* 6.2.1 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function processes the hardware timer interrupt. This */
/* processing includes incrementing the system clock and checking for */
/* time slice and/or timer expiration. If either is found, the */
/* interrupt context save/restore functions are called along with the */
/* expiration functions. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _tx_timer_expiration_process Timer expiration processing */
/* _tx_thread_time_slice Time slice interrupted thread */
/* */
/* CALLED BY */
/* */
/* interrupt vector */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 03-08-2023 Scott Larson Initial Version 6.2.1 */
/* */
/**************************************************************************/
VOID _tx_timer_interrupt(VOID)
{
UINT saved_posture;
/* Only core 0 advances the global timer wheel. */
if (TX_SMP_CORE_ID != ((UINT) 0))
{
return;
}
/* Get the protection. */
saved_posture = _tx_thread_smp_protect();
/* Indicate timer interrupt processing is active. */
_tx_timer_interrupt_active++;
/* Increment system clock. */
_tx_timer_system_clock++;
/* Test for timer expiration. */
if (*_tx_timer_current_ptr)
{
/* Set expiration flag. */
_tx_timer_expired = TX_TRUE;
}
else
{
/* No timer expired, increment the timer pointer. */
_tx_timer_current_ptr++;
/* Check for wrap-around. */
if (_tx_timer_current_ptr == _tx_timer_list_end)
{
/* Wrap to beginning of list. */
_tx_timer_current_ptr = _tx_timer_list_start;
}
}
/* Did a timer expire? */
if (_tx_timer_expired)
{
/* Process timer expiration. */
_tx_timer_expiration_process();
}
/* Process time-slice expiration for all cores. */
_tx_thread_time_slice();
/* Timer interrupt processing is no longer active. */
_tx_timer_interrupt_active--;
/* Release the protection. */
_tx_thread_smp_unprotect(saved_posture);
}