Compare commits
21 Commits
main
...
feature/sm
| Author | SHA1 | Date | |
|---|---|---|---|
| 2433b66dc0 | |||
| 2d0ec274ac | |||
| 58fc04bbb3 | |||
| 3ba7cdda9e | |||
| 239cd26a5c | |||
| ebe891dad6 | |||
| c390c4b8db | |||
| 1da9671197 | |||
| 28aaf8fd96 | |||
| 6d635345dd | |||
| 3fc721d6f2 | |||
| 5ebcce634a | |||
| cca56f89c6 | |||
| 1117527a02 | |||
| a75db78425 | |||
| 744773848c | |||
| f83e96fbcd | |||
| 2e955b9342 | |||
| 70bbde8502 | |||
| e5020b78de | |||
| f10fbbffab |
@@ -15,6 +15,9 @@ target_link_libraries(c PUBLIC gcc)
|
|||||||
set(THREADX_CUSTOM_PORT ${CMAKE_CURRENT_LIST_DIR}/port/threadx)
|
set(THREADX_CUSTOM_PORT ${CMAKE_CURRENT_LIST_DIR}/port/threadx)
|
||||||
add_subdirectory(third-party/threadx)
|
add_subdirectory(third-party/threadx)
|
||||||
target_link_libraries(threadx PUBLIC c)
|
target_link_libraries(threadx PUBLIC c)
|
||||||
|
#Adds threadx_smp
|
||||||
|
add_subdirectory(port/threadx_smp)
|
||||||
|
target_link_libraries(threadx_smp PUBLIC c)
|
||||||
# Adds netxduo
|
# Adds netxduo
|
||||||
set(NETXDUO_CUSTOM_PORT ${CMAKE_CURRENT_LIST_DIR}/port/threadx)
|
set(NETXDUO_CUSTOM_PORT ${CMAKE_CURRENT_LIST_DIR}/port/threadx)
|
||||||
set(NXD_ENABLE_FILE_SERVERS OFF)
|
set(NXD_ENABLE_FILE_SERVERS OFF)
|
||||||
@@ -80,7 +83,6 @@ function(setup_target TARGET)
|
|||||||
if(ST_LIBRARIES)
|
if(ST_LIBRARIES)
|
||||||
target_link_libraries(${TARGET} PRIVATE ${ST_LIBRARIES})
|
target_link_libraries(${TARGET} PRIVATE ${ST_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
target_link_libraries(${TARGET} PRIVATE threadx)
|
|
||||||
|
|
||||||
add_custom_command(TARGET ${TARGET} POST_BUILD
|
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
|
||||||
@@ -91,8 +93,6 @@ function(setup_target TARGET)
|
|||||||
)
|
)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
setup_target(thread_demo SOURCES src/thread_demo/main.c)
|
setup_target(thread_demo LIBRARIES threadx SOURCES src/thread_demo/main.c)
|
||||||
setup_target(tcp_demo
|
setup_target(tcp_demo LIBRARIES threadx netxduo SOURCES src/tcp_demo/main.c)
|
||||||
LIBRARIES netxduo
|
setup_target(smp_demo LIBRARIES threadx_smp SOURCES src/thread_demo/main.c)
|
||||||
SOURCES src/tcp_demo/main.c
|
|
||||||
)
|
|
||||||
|
|||||||
12
port/moonlight/aclint_ipi.h
Normal file
12
port/moonlight/aclint_ipi.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#ifndef _DEVICES_ACLINT_IPI
|
||||||
|
#define _DEVICES_ACLINT_IPI
|
||||||
|
|
||||||
|
#include "gen/aclint.h"
|
||||||
|
#include "platform.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
static void send_ipi(uint32_t target_core)
|
||||||
|
{
|
||||||
|
set_aclint_msip(aclint, target_core, 1);
|
||||||
|
}
|
||||||
|
#endif /* _DEVICES_ACLINT_IPI */
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <picotls.h>
|
#include <picotls.h>
|
||||||
|
#include <tx_port.h>
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
#define EXTERN_C extern "C"
|
#define EXTERN_C extern "C"
|
||||||
#else
|
#else
|
||||||
@@ -50,7 +50,6 @@ extern int main(void);
|
|||||||
|
|
||||||
// The linker script will place this in the reset entry point.
|
// The linker script will place this in the reset entry point.
|
||||||
// It will be 'called' with no stack or C runtime configuration.
|
// It will be 'called' with no stack or C runtime configuration.
|
||||||
// NOTE - this only supports a single hart.
|
|
||||||
// tp will not be initialized
|
// tp will not be initialized
|
||||||
void _start(void) {
|
void _start(void) {
|
||||||
// Setup SP and GP
|
// Setup SP and GP
|
||||||
@@ -64,6 +63,24 @@ void _start(void) {
|
|||||||
"la gp, __global_pointer$;"
|
"la gp, __global_pointer$;"
|
||||||
".option pop;"
|
".option pop;"
|
||||||
"la sp, _sp;"
|
"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;"
|
"jal zero, _initialize;"
|
||||||
: /* output: none %0 */
|
: /* output: none %0 */
|
||||||
: /* input: none */
|
: /* input: none */
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "hwtimer.h"
|
#include "hwtimer.h"
|
||||||
|
#include "platform.h"
|
||||||
#include "riscv-traps.h"
|
#include "riscv-traps.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -39,6 +40,11 @@ void trap_handler(uintptr_t mcause, uintptr_t mepc, uintptr_t mtval) {
|
|||||||
hwtimer_handler();
|
hwtimer_handler();
|
||||||
_tx_timer_interrupt();
|
_tx_timer_interrupt();
|
||||||
break;
|
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:
|
case RISCV_INT_MEI:
|
||||||
puts("[INTERRUPT]: handler ext irq error!\n");
|
puts("[INTERRUPT]: handler ext irq error!\n");
|
||||||
while(1)
|
while(1)
|
||||||
|
|||||||
@@ -72,11 +72,6 @@
|
|||||||
|
|
||||||
#else /*not __ASSEMBLER__ */
|
#else /*not __ASSEMBLER__ */
|
||||||
|
|
||||||
/* Include for memset. */
|
|
||||||
#include <string.h>
|
|
||||||
/* include for strtoul*/
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
/* Determine if the optional ThreadX user define file should be used. */
|
/* Determine if the optional ThreadX user define file should be used. */
|
||||||
|
|
||||||
#ifdef TX_INCLUDE_USER_DEFINE_FILE
|
#ifdef TX_INCLUDE_USER_DEFINE_FILE
|
||||||
@@ -90,6 +85,9 @@
|
|||||||
|
|
||||||
/* Define compiler library include files. */
|
/* Define compiler library include files. */
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
/* Define ThreadX basic types for this port. */
|
/* Define ThreadX basic types for this port. */
|
||||||
|
|
||||||
#define VOID void
|
#define VOID void
|
||||||
|
|||||||
60
port/threadx_smp/CMakeLists.txt
Normal file
60
port/threadx_smp/CMakeLists.txt
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.24)
|
||||||
|
project(smp_demo LANGUAGES C ASM)
|
||||||
|
|
||||||
|
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/ThreadXSmpOffsets.cmake)
|
||||||
|
|
||||||
|
set(THREADX_COMMON_SMP_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../third-party/threadx/common_smp)
|
||||||
|
if(NOT EXISTS "${THREADX_COMMON_SMP_DIR}")
|
||||||
|
message(FATAL_ERROR "could not find ThreadX SMP sources, is the submodule checked out?")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(THREADX_SMP_CUSTOM_INC
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/inc
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/../moonlight #needed for aclint (inter process interrupts)
|
||||||
|
)
|
||||||
|
set(THREADX_SMP_CUSTOM_SRC
|
||||||
|
src/tx_initialize_low_level.S
|
||||||
|
src/tx_thread_context_restore.S
|
||||||
|
src/tx_thread_context_save.S
|
||||||
|
src/tx_thread_schedule.S
|
||||||
|
src/tx_thread_smp_core_get.S
|
||||||
|
src/tx_thread_smp_core_preempt.c
|
||||||
|
src/tx_thread_smp_current_state_get.S
|
||||||
|
src/tx_thread_smp_current_thread_get.S
|
||||||
|
src/tx_thread_smp_initialize_wait.S
|
||||||
|
src/tx_thread_smp_low_level_initialize.S
|
||||||
|
src/tx_thread_smp_protect.S
|
||||||
|
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(
|
||||||
|
TARGET threadx_smp_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}
|
||||||
|
DEPENDS
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/inc/tx_port.h
|
||||||
|
${THREADX_COMMON_SMP_DIR}/inc/tx_api.h
|
||||||
|
OUT_INCLUDE_DIR THREADX_SMP_GENERATED_INC_DIR
|
||||||
|
)
|
||||||
|
|
||||||
|
file(GLOB THREADX_SMP_SOURCES ${THREADX_COMMON_SMP_DIR}/src/*.c)
|
||||||
|
add_library(threadx_smp STATIC)
|
||||||
|
target_sources(threadx_smp PRIVATE
|
||||||
|
${THREADX_SMP_SOURCES}
|
||||||
|
${THREADX_SMP_CUSTOM_SRC}
|
||||||
|
)
|
||||||
|
target_include_directories(threadx_smp PUBLIC
|
||||||
|
${THREADX_COMMON_SMP_DIR}/inc
|
||||||
|
${THREADX_SMP_CUSTOM_INC}
|
||||||
|
)
|
||||||
|
target_include_directories(threadx_smp PRIVATE
|
||||||
|
${THREADX_SMP_GENERATED_INC_DIR}
|
||||||
|
)
|
||||||
|
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)
|
||||||
41
port/threadx_smp/cmake/BuildAsmOffsets.cmake
Normal file
41
port/threadx_smp/cmake/BuildAsmOffsets.cmake
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
if(NOT DEFINED COMPILER)
|
||||||
|
message(FATAL_ERROR "COMPILER is required")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED SOURCE)
|
||||||
|
message(FATAL_ERROR "SOURCE is required")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED ASM_OUTPUT)
|
||||||
|
message(FATAL_ERROR "ASM_OUTPUT is required")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED HEADER_OUTPUT)
|
||||||
|
message(FATAL_ERROR "HEADER_OUTPUT is required")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED GENERATE_SCRIPT)
|
||||||
|
message(FATAL_ERROR "GENERATE_SCRIPT is required")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${COMPILER}" ${COMPILER_ARG1} ${CFLAG_ARGS} ${INCLUDE_ARGS} ${DEFINE_ARGS} -S -o "${ASM_OUTPUT}" "${SOURCE}"
|
||||||
|
RESULT_VARIABLE compile_result
|
||||||
|
OUTPUT_VARIABLE compile_stdout
|
||||||
|
ERROR_VARIABLE compile_stderr
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT compile_result EQUAL 0)
|
||||||
|
message(FATAL_ERROR "failed to compile asm offsets source\n${compile_stdout}${compile_stderr}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${CMAKE_COMMAND}" -DINPUT="${ASM_OUTPUT}" -DOUTPUT="${HEADER_OUTPUT}" -P "${GENERATE_SCRIPT}"
|
||||||
|
RESULT_VARIABLE generate_result
|
||||||
|
OUTPUT_VARIABLE generate_stdout
|
||||||
|
ERROR_VARIABLE generate_stderr
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT generate_result EQUAL 0)
|
||||||
|
message(FATAL_ERROR "failed to generate asm offsets header\n${generate_stdout}${generate_stderr}")
|
||||||
|
endif()
|
||||||
22
port/threadx_smp/cmake/GenerateAsmOffsets.cmake
Normal file
22
port/threadx_smp/cmake/GenerateAsmOffsets.cmake
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
if(NOT DEFINED INPUT)
|
||||||
|
message(FATAL_ERROR "INPUT is required")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED OUTPUT)
|
||||||
|
message(FATAL_ERROR "OUTPUT is required")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
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}")
|
||||||
|
if(NOT CMAKE_MATCH_1)
|
||||||
|
continue()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
string(APPEND OFFSET_CONTENT "#define ${CMAKE_MATCH_1} ${CMAKE_MATCH_2}\n")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
file(WRITE "${OUTPUT}" "${OFFSET_CONTENT}")
|
||||||
67
port/threadx_smp/cmake/ThreadXSmpOffsets.cmake
Normal file
67
port/threadx_smp/cmake/ThreadXSmpOffsets.cmake
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
function(threadx_smp_add_offsets)
|
||||||
|
set(options)
|
||||||
|
set(oneValueArgs TARGET OUTPUT_DIR SOURCE OUT_INCLUDE_DIR)
|
||||||
|
set(multiValueArgs INCLUDE_DIRS COMPILE_DEFINITIONS DEPENDS)
|
||||||
|
cmake_parse_arguments(THREADX_SMP_OFFSETS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
if(NOT THREADX_SMP_OFFSETS_TARGET)
|
||||||
|
message(FATAL_ERROR "threadx_smp_add_offsets requires TARGET")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT THREADX_SMP_OFFSETS_OUTPUT_DIR)
|
||||||
|
message(FATAL_ERROR "threadx_smp_add_offsets requires OUTPUT_DIR")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT THREADX_SMP_OFFSETS_SOURCE)
|
||||||
|
message(FATAL_ERROR "threadx_smp_add_offsets requires SOURCE")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT THREADX_SMP_OFFSETS_OUT_INCLUDE_DIR)
|
||||||
|
message(FATAL_ERROR "threadx_smp_add_offsets requires OUT_INCLUDE_DIR")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(threadx_smp_generate_script "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/GenerateAsmOffsets.cmake")
|
||||||
|
set(threadx_smp_offset_asm "${THREADX_SMP_OFFSETS_OUTPUT_DIR}/tx_asm_offsets.s")
|
||||||
|
set(threadx_smp_offset_inc "${THREADX_SMP_OFFSETS_OUTPUT_DIR}/tx_asm_offsets.inc")
|
||||||
|
|
||||||
|
set(threadx_smp_offset_include_args ${THREADX_SMP_OFFSETS_INCLUDE_DIRS})
|
||||||
|
list(TRANSFORM threadx_smp_offset_include_args PREPEND -I)
|
||||||
|
|
||||||
|
set(threadx_smp_offset_define_args ${THREADX_SMP_OFFSETS_COMPILE_DEFINITIONS})
|
||||||
|
list(TRANSFORM threadx_smp_offset_define_args PREPEND -D)
|
||||||
|
|
||||||
|
set(threadx_smp_offset_cflags ${CMAKE_C_FLAGS})
|
||||||
|
if(CMAKE_BUILD_TYPE)
|
||||||
|
string(TOUPPER "${CMAKE_BUILD_TYPE}" threadx_smp_build_type_upper)
|
||||||
|
list(APPEND threadx_smp_offset_cflags ${CMAKE_C_FLAGS_${threadx_smp_build_type_upper}})
|
||||||
|
endif()
|
||||||
|
separate_arguments(threadx_smp_offset_cflags)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${threadx_smp_offset_inc}
|
||||||
|
BYPRODUCTS ${threadx_smp_offset_asm}
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E make_directory ${THREADX_SMP_OFFSETS_OUTPUT_DIR}
|
||||||
|
COMMAND ${CMAKE_C_COMPILER}
|
||||||
|
${CMAKE_C_COMPILER_ARG1}
|
||||||
|
${threadx_smp_offset_cflags}
|
||||||
|
${threadx_smp_offset_include_args}
|
||||||
|
${threadx_smp_offset_define_args}
|
||||||
|
-S
|
||||||
|
-o ${threadx_smp_offset_asm}
|
||||||
|
${THREADX_SMP_OFFSETS_SOURCE}
|
||||||
|
COMMAND ${CMAKE_COMMAND}
|
||||||
|
-DINPUT=${threadx_smp_offset_asm}
|
||||||
|
-DOUTPUT=${threadx_smp_offset_inc}
|
||||||
|
-P ${threadx_smp_generate_script}
|
||||||
|
DEPENDS
|
||||||
|
${THREADX_SMP_OFFSETS_SOURCE}
|
||||||
|
${threadx_smp_generate_script}
|
||||||
|
${THREADX_SMP_OFFSETS_DEPENDS}
|
||||||
|
COMMAND_EXPAND_LISTS
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_target(${THREADX_SMP_OFFSETS_TARGET} DEPENDS ${threadx_smp_offset_inc})
|
||||||
|
|
||||||
|
set(${THREADX_SMP_OFFSETS_OUT_INCLUDE_DIR} ${THREADX_SMP_OFFSETS_OUTPUT_DIR} PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
371
port/threadx_smp/inc/csr.h
Normal file
371
port/threadx_smp/inc/csr.h
Normal file
@@ -0,0 +1,371 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* 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 CSR_H
|
||||||
|
#define CSR_H
|
||||||
|
|
||||||
|
// Machine Status Register, mstatus
|
||||||
|
#define MSTATUS_MPP_MASK (3L << 11) // previous mode.
|
||||||
|
#define MSTATUS_MPP_M (3L << 11)
|
||||||
|
#define MSTATUS_MPP_S (1L << 11)
|
||||||
|
#define MSTATUS_MPP_U (0L << 11)
|
||||||
|
#define MSTATUS_MIE (1L << 3) // machine-mode interrupt enable.
|
||||||
|
#define MSTATUS_MPIE (1L << 7)
|
||||||
|
#define MSTATUS_FS (1L << 13)
|
||||||
|
|
||||||
|
// Machine-mode Interrupt Enable
|
||||||
|
#define MIE_MTIE (1L << 7)
|
||||||
|
#define MIE_MSIE (1L << 3)
|
||||||
|
#define MIE_MEIE (1L << 11)
|
||||||
|
#define MIE_STIE (1L << 5) // supervisor timer
|
||||||
|
#define MIE_SSIE (1L << 1)
|
||||||
|
#define MIE_SEIE (1L << 9)
|
||||||
|
|
||||||
|
// Supervisor Status Register, sstatus
|
||||||
|
#define SSTATUS_SPP (1L << 8) // Previous mode, 1=Supervisor, 0=User
|
||||||
|
#define SSTATUS_SPIE (1L << 5) // Supervisor Previous Interrupt Enable
|
||||||
|
#define SSTATUS_UPIE (1L << 4) // User Previous Interrupt Enable
|
||||||
|
#define SSTATUS_SIE (1L << 1) // Supervisor Interrupt Enable
|
||||||
|
#define SSTATUS_UIE (1L << 0) // User Interrupt Enable
|
||||||
|
#define SSTATUS_SPIE (1L << 5)
|
||||||
|
#define SSTATUS_UPIE (1L << 4)
|
||||||
|
|
||||||
|
// Supervisor Interrupt Enable
|
||||||
|
#define SIE_SEIE (1L << 9) // external
|
||||||
|
#define SIE_STIE (1L << 5) // timer
|
||||||
|
#define SIE_SSIE (1L << 1) // software
|
||||||
|
|
||||||
|
#ifndef __ASSEMBLER__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
static inline uint64_t riscv_get_core()
|
||||||
|
{
|
||||||
|
uint64_t x;
|
||||||
|
asm volatile("csrr %0, mhartid" : "=r"(x));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t riscv_get_mstatus()
|
||||||
|
{
|
||||||
|
uint64_t x;
|
||||||
|
asm volatile("csrr %0, mstatus" : "=r"(x));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void riscv_writ_mstatus(uint64_t x)
|
||||||
|
{
|
||||||
|
asm volatile("csrw mstatus, %0" : : "r"(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
// machine exception program counter, holds the
|
||||||
|
// instruction address to which a return from
|
||||||
|
// exception will go.
|
||||||
|
static inline void riscv_writ_mepc(uint64_t x)
|
||||||
|
{
|
||||||
|
asm volatile("csrw mepc, %0" : : "r"(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t riscv_get_sstatus()
|
||||||
|
{
|
||||||
|
uint64_t x;
|
||||||
|
asm volatile("csrr %0, sstatus" : "=r"(x));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void riscv_writ_sstatus(uint64_t x)
|
||||||
|
{
|
||||||
|
asm volatile("csrw sstatus, %0" : : "r"(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Supervisor Interrupt Pending
|
||||||
|
static inline uint64_t riscv_get_sip()
|
||||||
|
{
|
||||||
|
uint64_t x;
|
||||||
|
asm volatile("csrr %0, sip" : "=r"(x));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void riscv_writ_sip(uint64_t x)
|
||||||
|
{
|
||||||
|
asm volatile("csrw sip, %0" : : "r"(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t riscv_get_sie()
|
||||||
|
{
|
||||||
|
uint64_t x;
|
||||||
|
asm volatile("csrr %0, sie" : "=r"(x));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void riscv_writ_sie(uint64_t x)
|
||||||
|
{
|
||||||
|
asm volatile("csrw sie, %0" : : "r"(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t riscv_get_mie()
|
||||||
|
{
|
||||||
|
uint64_t x;
|
||||||
|
asm volatile("csrr %0, mie" : "=r"(x));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void riscv_writ_mie(uint64_t x)
|
||||||
|
{
|
||||||
|
asm volatile("csrw mie, %0" : : "r"(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
// supervisor exception program counter, holds the
|
||||||
|
// instruction address to which a return from
|
||||||
|
// exception will go.
|
||||||
|
static inline void riscv_writ_sepc(uint64_t x)
|
||||||
|
{
|
||||||
|
asm volatile("csrw sepc, %0" : : "r"(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t riscv_get_sepc()
|
||||||
|
{
|
||||||
|
uint64_t x;
|
||||||
|
asm volatile("csrr %0, sepc" : "=r"(x));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Machine Exception Delegation
|
||||||
|
static inline uint64_t riscv_get_medeleg()
|
||||||
|
{
|
||||||
|
uint64_t x;
|
||||||
|
asm volatile("csrr %0, medeleg" : "=r"(x));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void riscv_writ_medeleg(uint64_t x)
|
||||||
|
{
|
||||||
|
asm volatile("csrw medeleg, %0" : : "r"(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Machine Interrupt Delegation
|
||||||
|
static inline uint64_t riscv_get_mideleg()
|
||||||
|
{
|
||||||
|
uint64_t x;
|
||||||
|
asm volatile("csrr %0, mideleg" : "=r"(x));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void riscv_writ_mideleg(uint64_t x)
|
||||||
|
{
|
||||||
|
asm volatile("csrw mideleg, %0" : : "r"(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Supervisor Trap-Vector Base Address
|
||||||
|
// low two bits are mode.
|
||||||
|
static inline void riscv_writ_stvec(uint64_t x)
|
||||||
|
{
|
||||||
|
asm volatile("csrw stvec, %0" : : "r"(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t riscv_get_stvec()
|
||||||
|
{
|
||||||
|
uint64_t x;
|
||||||
|
asm volatile("csrr %0, stvec" : "=r"(x));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Supervisor Timer Comparison Register
|
||||||
|
static inline uint64_t riscv_get_stimecmp()
|
||||||
|
{
|
||||||
|
uint64_t x;
|
||||||
|
// asm volatile("csrr %0, stimecmp" : "=r" (x) );
|
||||||
|
asm volatile("csrr %0, 0x14d" : "=r"(x));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void riscv_writ_stimecmp(uint64_t x)
|
||||||
|
{
|
||||||
|
// asm volatile("csrw stimecmp, %0" : : "r" (x));
|
||||||
|
asm volatile("csrw 0x14d, %0" : : "r"(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Machine Environment Configuration Register
|
||||||
|
static inline uint64_t riscv_get_menvcfg()
|
||||||
|
{
|
||||||
|
uint64_t x;
|
||||||
|
// asm volatile("csrr %0, menvcfg" : "=r" (x) );
|
||||||
|
asm volatile("csrr %0, 0x30a" : "=r"(x));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void riscv_writ_menvcfg(uint64_t x)
|
||||||
|
{
|
||||||
|
// asm volatile("csrw menvcfg, %0" : : "r" (x));
|
||||||
|
asm volatile("csrw 0x30a, %0" : : "r"(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Physical Memory Protection
|
||||||
|
static inline void riscv_writ_pmpcfg0(uint64_t x)
|
||||||
|
{
|
||||||
|
asm volatile("csrw pmpcfg0, %0" : : "r"(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void riscv_writ_pmpaddr0(uint64_t x)
|
||||||
|
{
|
||||||
|
asm volatile("csrw pmpaddr0, %0" : : "r"(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
// supervisor address translation and protection;
|
||||||
|
// holds the address of the page table.
|
||||||
|
static inline void riscv_writ_satp(uint64_t x)
|
||||||
|
{
|
||||||
|
asm volatile("csrw satp, %0" : : "r"(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t riscv_get_satp()
|
||||||
|
{
|
||||||
|
uint64_t x;
|
||||||
|
asm volatile("csrr %0, satp" : "=r"(x));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Supervisor Trap Cause
|
||||||
|
static inline uint64_t riscv_get_scause()
|
||||||
|
{
|
||||||
|
uint64_t x;
|
||||||
|
asm volatile("csrr %0, scause" : "=r"(x));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Supervisor Trap Value
|
||||||
|
static inline uint64_t riscv_get_stval()
|
||||||
|
{
|
||||||
|
uint64_t x;
|
||||||
|
asm volatile("csrr %0, stval" : "=r"(x));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Machine-mode Counter-Enable
|
||||||
|
static inline void riscv_writ_mcounteren(uint64_t x)
|
||||||
|
{
|
||||||
|
asm volatile("csrw mcounteren, %0" : : "r"(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t riscv_get_mcounteren()
|
||||||
|
{
|
||||||
|
uint64_t x;
|
||||||
|
asm volatile("csrr %0, mcounteren" : "=r"(x));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// machine-mode cycle counter
|
||||||
|
static inline uint64_t riscv_get_time()
|
||||||
|
{
|
||||||
|
uint64_t x;
|
||||||
|
asm volatile("csrr %0, time" : "=r"(x));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// enable device interrupts
|
||||||
|
static inline void riscv_sintr_on()
|
||||||
|
{
|
||||||
|
uint64_t sstatus = riscv_get_sstatus();
|
||||||
|
sstatus |= SSTATUS_SIE;
|
||||||
|
riscv_writ_sstatus(sstatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
// disable device interrupts
|
||||||
|
static inline void riscv_sintr_off()
|
||||||
|
{
|
||||||
|
uint64_t sstatus = riscv_get_sstatus();
|
||||||
|
sstatus &= (~SSTATUS_SIE);
|
||||||
|
riscv_writ_sstatus(sstatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
// are device interrupts enabled?
|
||||||
|
static inline int riscv_sintr_get()
|
||||||
|
{
|
||||||
|
uint64_t x = riscv_get_sstatus();
|
||||||
|
return (x & SSTATUS_SIE) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void riscv_sintr_restore(int x)
|
||||||
|
{
|
||||||
|
if (x)
|
||||||
|
riscv_sintr_on();
|
||||||
|
else
|
||||||
|
riscv_sintr_off();
|
||||||
|
}
|
||||||
|
|
||||||
|
// enable device interrupts
|
||||||
|
static inline void riscv_mintr_on()
|
||||||
|
{
|
||||||
|
uint64_t mstatus = riscv_get_mstatus();
|
||||||
|
mstatus |= MSTATUS_MIE;
|
||||||
|
riscv_writ_mstatus(mstatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
// disable device interrupts
|
||||||
|
static inline void riscv_mintr_off()
|
||||||
|
{
|
||||||
|
uint64_t mstatus = riscv_get_mstatus();
|
||||||
|
mstatus &= (~MSTATUS_MIE);
|
||||||
|
riscv_writ_mstatus(mstatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
// are device interrupts enabled?
|
||||||
|
static inline int riscv_mintr_get()
|
||||||
|
{
|
||||||
|
uint64_t x = riscv_get_mstatus();
|
||||||
|
return (x & MSTATUS_MIE) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void riscv_mintr_restore(int x)
|
||||||
|
{
|
||||||
|
if (x)
|
||||||
|
riscv_mintr_on();
|
||||||
|
else
|
||||||
|
riscv_mintr_off();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t riscv_get_sp()
|
||||||
|
{
|
||||||
|
uint64_t x;
|
||||||
|
asm volatile("mv %0, sp" : "=r"(x));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read and write tp, the thread pointer, which xv6 uses to hold
|
||||||
|
// this core's hartid (core number), the index into cpus[].
|
||||||
|
static inline uint64_t riscv_get_tp()
|
||||||
|
{
|
||||||
|
uint64_t x;
|
||||||
|
asm volatile("mv %0, tp" : "=r"(x));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void riscv_writ_tp(uint64_t x)
|
||||||
|
{
|
||||||
|
asm volatile("mv tp, %0" : : "r"(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t riscv_get_ra()
|
||||||
|
{
|
||||||
|
uint64_t x;
|
||||||
|
asm volatile("mv %0, ra" : "=r"(x));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// flush the TLB.
|
||||||
|
static inline void sfence_vma()
|
||||||
|
{
|
||||||
|
// the zero, zero means flush all TLB entries.
|
||||||
|
asm volatile("sfence.vma zero, zero");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __ASSEMBLER__
|
||||||
|
|
||||||
|
#endif
|
||||||
343
port/threadx_smp/inc/tx_port.h
Normal file
343
port/threadx_smp/inc/tx_port.h
Normal file
@@ -0,0 +1,343 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* 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 */
|
||||||
|
/** */
|
||||||
|
/** Port Specific */
|
||||||
|
/** */
|
||||||
|
/**************************************************************************/
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* PORT SPECIFIC C INFORMATION RELEASE */
|
||||||
|
/* */
|
||||||
|
/* tx_port.h ARMv8-A-SMP */
|
||||||
|
/* 6.1.10 */
|
||||||
|
/* */
|
||||||
|
/* AUTHOR */
|
||||||
|
/* */
|
||||||
|
/* William E. Lamie, Microsoft Corporation */
|
||||||
|
/* */
|
||||||
|
/* DESCRIPTION */
|
||||||
|
/* */
|
||||||
|
/* This file contains data type definitions that make the ThreadX */
|
||||||
|
/* real-time kernel function identically on a variety of different */
|
||||||
|
/* processor architectures. For example, the size or number of bits */
|
||||||
|
/* in an "int" data type vary between microprocessor architectures and */
|
||||||
|
/* even C compilers for the same microprocessor. ThreadX does not */
|
||||||
|
/* directly use native C data types. Instead, ThreadX creates its */
|
||||||
|
/* own special types that can be mapped to actual data types by this */
|
||||||
|
/* file to guarantee consistency in the interface and functionality. */
|
||||||
|
/* */
|
||||||
|
/* RELEASE HISTORY */
|
||||||
|
/* */
|
||||||
|
/* DATE NAME DESCRIPTION */
|
||||||
|
/* */
|
||||||
|
/* 09-30-2020 William E. Lamie Initial Version 6.1 */
|
||||||
|
/* 01-31-2022 Bhupendra Naphade Modified comment(s),updated */
|
||||||
|
/* macro definition, */
|
||||||
|
/* resulting in version 6.1.10 */
|
||||||
|
/* */
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TX_PORT_H
|
||||||
|
#define TX_PORT_H
|
||||||
|
|
||||||
|
#ifdef __ASSEMBLER__
|
||||||
|
|
||||||
|
#if __riscv_xlen == 64
|
||||||
|
#define SLL32 sllw
|
||||||
|
#define STORE sd
|
||||||
|
#define LOAD ld
|
||||||
|
#define LWU lwu
|
||||||
|
#define LOG_REGBYTES 3
|
||||||
|
#else
|
||||||
|
#define SLL32 sll
|
||||||
|
#define STORE sw
|
||||||
|
#define LOAD lw
|
||||||
|
#define LWU lw
|
||||||
|
#define LOG_REGBYTES 2
|
||||||
|
#endif
|
||||||
|
#define REGBYTES (1 << LOG_REGBYTES)
|
||||||
|
|
||||||
|
#include "tx_asm_offsets.inc"
|
||||||
|
|
||||||
|
#else /*not __ASSEMBLER__ */
|
||||||
|
|
||||||
|
/************* Define ThreadX SMP constants. *************/
|
||||||
|
|
||||||
|
/* Define the ThreadX SMP maximum number of cores. */
|
||||||
|
|
||||||
|
#ifndef TX_THREAD_SMP_MAX_CORES
|
||||||
|
#define TX_THREAD_SMP_MAX_CORES 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Define the ThreadX SMP core mask. */
|
||||||
|
|
||||||
|
#ifndef TX_THREAD_SMP_CORE_MASK
|
||||||
|
#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
|
||||||
|
|
||||||
|
/* Define ThreadX SMP initialization macro. */
|
||||||
|
|
||||||
|
#define TX_PORT_SPECIFIC_PRE_INITIALIZATION
|
||||||
|
|
||||||
|
/* Define ThreadX SMP pre-scheduler initialization. */
|
||||||
|
|
||||||
|
#define TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION
|
||||||
|
|
||||||
|
/* Enable the inter-core interrupt logic. */
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
|
/* Include customer-specific wakeup code. */
|
||||||
|
|
||||||
|
#include "tx_thread_smp_core_wakeup.h"
|
||||||
|
#else
|
||||||
|
|
||||||
|
#ifdef TX_THREAD_SMP_DEFAULT_WAKEUP_LOGIC
|
||||||
|
|
||||||
|
/* Default wakeup code. */
|
||||||
|
#define TX_THREAD_SMP_WAKEUP_LOGIC
|
||||||
|
#define TX_THREAD_SMP_WAKEUP(i) _tx_thread_smp_core_preempt(i)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Ensure that the in-line resume/suspend define is not allowed. */
|
||||||
|
|
||||||
|
#ifdef TX_INLINE_THREAD_RESUME_SUSPEND
|
||||||
|
#undef TX_INLINE_THREAD_RESUME_SUSPEND
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/************* End ThreadX SMP constants. *************/
|
||||||
|
|
||||||
|
/* Determine if the optional ThreadX user define file should be used. */
|
||||||
|
|
||||||
|
#ifdef TX_INCLUDE_USER_DEFINE_FILE
|
||||||
|
|
||||||
|
/* Yes, include the user defines in tx_user.h. The defines in this file may
|
||||||
|
alternately be defined on the command line. */
|
||||||
|
|
||||||
|
#include "tx_user.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Define compiler library include files. */
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* Define ThreadX basic types for this port. */
|
||||||
|
|
||||||
|
#define VOID void
|
||||||
|
typedef char CHAR;
|
||||||
|
typedef unsigned char UCHAR;
|
||||||
|
typedef int INT;
|
||||||
|
typedef unsigned int UINT;
|
||||||
|
typedef int LONG;
|
||||||
|
typedef unsigned int ULONG;
|
||||||
|
typedef unsigned long long ULONG64;
|
||||||
|
typedef short SHORT;
|
||||||
|
typedef unsigned short USHORT;
|
||||||
|
#define ULONG64_DEFINED
|
||||||
|
|
||||||
|
/* Define the priority levels for ThreadX. Legal values range
|
||||||
|
from 32 to 1024 and MUST be evenly divisible by 32. */
|
||||||
|
|
||||||
|
#ifndef TX_MAX_PRIORITIES
|
||||||
|
#define TX_MAX_PRIORITIES 32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Define the minimum stack for a ThreadX thread on this processor. If the size supplied during
|
||||||
|
thread creation is less than this value, the thread create call will return an error. */
|
||||||
|
|
||||||
|
#ifndef TX_MINIMUM_STACK
|
||||||
|
#define TX_MINIMUM_STACK 1024 /* Minimum stack size for this port */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Define the system timer thread's default stack size and priority. These are only applicable
|
||||||
|
if TX_TIMER_PROCESS_IN_ISR is not defined. */
|
||||||
|
|
||||||
|
#ifndef TX_TIMER_THREAD_STACK_SIZE
|
||||||
|
#define TX_TIMER_THREAD_STACK_SIZE 1024 /* Default timer thread stack size */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef TX_TIMER_THREAD_PRIORITY
|
||||||
|
#define TX_TIMER_THREAD_PRIORITY 0 /* Default timer thread priority */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Define various constants for the ThreadX RISC-V port. */
|
||||||
|
|
||||||
|
#define TX_INT_DISABLE 0x00000000 /* Disable interrupts value */
|
||||||
|
#define TX_INT_ENABLE 0x00000008 /* Enable interrupt value */
|
||||||
|
|
||||||
|
/* Define the clock source for trace event entry time stamp. The following two item are port specific.
|
||||||
|
For example, if the time source is at the address 0x0a800024 and is 16-bits in size, the clock
|
||||||
|
source constants would be:
|
||||||
|
|
||||||
|
#define TX_TRACE_TIME_SOURCE *((ULONG *) 0x0a800024)
|
||||||
|
#define TX_TRACE_TIME_MASK 0x0000FFFFUL
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TX_TRACE_TIME_SOURCE
|
||||||
|
#define TX_TRACE_TIME_SOURCE ++_tx_trace_simulated_time
|
||||||
|
#endif
|
||||||
|
#ifndef TX_TRACE_TIME_MASK
|
||||||
|
#define TX_TRACE_TIME_MASK 0xFFFFFFFFUL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Define the port specific options for the _tx_build_options variable. This variable indicates
|
||||||
|
how the ThreadX library was built. */
|
||||||
|
|
||||||
|
#define TX_PORT_SPECIFIC_BUILD_OPTIONS 0
|
||||||
|
|
||||||
|
/* Define the in-line initialization constant so that modules with in-line
|
||||||
|
initialization capabilities can prevent their initialization from being
|
||||||
|
a function call. */
|
||||||
|
|
||||||
|
#define TX_INLINE_INITIALIZATION
|
||||||
|
|
||||||
|
/* Determine whether or not stack checking is enabled. By default, ThreadX stack checking is
|
||||||
|
disabled. When the following is defined, ThreadX thread stack checking is enabled. If stack
|
||||||
|
checking is enabled (TX_ENABLE_STACK_CHECKING is defined), the TX_DISABLE_STACK_FILLING
|
||||||
|
define is negated, thereby forcing the stack fill which is necessary for the stack checking
|
||||||
|
logic. */
|
||||||
|
|
||||||
|
#ifdef TX_ENABLE_STACK_CHECKING
|
||||||
|
#undef TX_DISABLE_STACK_FILLING
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Define the TX_THREAD control block extensions for this port. The main reason
|
||||||
|
for the multiple macros is so that backward compatibility can be maintained with
|
||||||
|
existing ThreadX kernel awareness modules. */
|
||||||
|
|
||||||
|
#define TX_THREAD_EXTENSION_0
|
||||||
|
#define TX_THREAD_EXTENSION_1
|
||||||
|
#define TX_THREAD_EXTENSION_2
|
||||||
|
#define TX_THREAD_EXTENSION_3
|
||||||
|
|
||||||
|
/* Define the port extensions of the remaining ThreadX objects. */
|
||||||
|
|
||||||
|
#define TX_BLOCK_POOL_EXTENSION
|
||||||
|
#define TX_BYTE_POOL_EXTENSION
|
||||||
|
#define TX_EVENT_FLAGS_GROUP_EXTENSION
|
||||||
|
#define TX_MUTEX_EXTENSION
|
||||||
|
#define TX_QUEUE_EXTENSION
|
||||||
|
#define TX_SEMAPHORE_EXTENSION
|
||||||
|
#define TX_TIMER_EXTENSION
|
||||||
|
|
||||||
|
/* Define the user extension field of the thread control block. Nothing
|
||||||
|
additional is needed for this port so it is defined as white space. */
|
||||||
|
|
||||||
|
#ifndef TX_THREAD_USER_EXTENSION
|
||||||
|
#define TX_THREAD_USER_EXTENSION
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Define the macros for processing extensions in tx_thread_create, tx_thread_delete,
|
||||||
|
tx_thread_shell_entry, and tx_thread_terminate. */
|
||||||
|
|
||||||
|
#define TX_THREAD_CREATE_EXTENSION(thread_ptr)
|
||||||
|
#define TX_THREAD_DELETE_EXTENSION(thread_ptr)
|
||||||
|
#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr)
|
||||||
|
#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr)
|
||||||
|
|
||||||
|
/* Define the ThreadX object creation extensions for the remaining objects. */
|
||||||
|
|
||||||
|
#define TX_BLOCK_POOL_CREATE_EXTENSION(pool_ptr)
|
||||||
|
#define TX_BYTE_POOL_CREATE_EXTENSION(pool_ptr)
|
||||||
|
#define TX_EVENT_FLAGS_GROUP_CREATE_EXTENSION(group_ptr)
|
||||||
|
#define TX_MUTEX_CREATE_EXTENSION(mutex_ptr)
|
||||||
|
#define TX_QUEUE_CREATE_EXTENSION(queue_ptr)
|
||||||
|
#define TX_SEMAPHORE_CREATE_EXTENSION(semaphore_ptr)
|
||||||
|
#define TX_TIMER_CREATE_EXTENSION(timer_ptr)
|
||||||
|
|
||||||
|
/* Define the ThreadX object deletion extensions for the remaining objects. */
|
||||||
|
|
||||||
|
#define TX_BLOCK_POOL_DELETE_EXTENSION(pool_ptr)
|
||||||
|
#define TX_BYTE_POOL_DELETE_EXTENSION(pool_ptr)
|
||||||
|
#define TX_EVENT_FLAGS_GROUP_DELETE_EXTENSION(group_ptr)
|
||||||
|
#define TX_MUTEX_DELETE_EXTENSION(mutex_ptr)
|
||||||
|
#define TX_QUEUE_DELETE_EXTENSION(queue_ptr)
|
||||||
|
#define TX_SEMAPHORE_DELETE_EXTENSION(semaphore_ptr)
|
||||||
|
#define TX_TIMER_DELETE_EXTENSION(timer_ptr)
|
||||||
|
|
||||||
|
/************* Define ThreadX SMP data types and function prototypes. *************/
|
||||||
|
|
||||||
|
struct TX_THREAD_STRUCT;
|
||||||
|
|
||||||
|
/* Define the ThreadX SMP protection structure. */
|
||||||
|
|
||||||
|
typedef struct TX_THREAD_SMP_PROTECT_STRUCT
|
||||||
|
{
|
||||||
|
ULONG tx_thread_smp_protect_in_force;
|
||||||
|
ULONG tx_thread_smp_protect_core;
|
||||||
|
ULONG tx_thread_smp_protect_count;
|
||||||
|
ULONG tx_thread_smp_protect_pad_0;
|
||||||
|
ULONG tx_thread_smp_protect_pad_1;
|
||||||
|
ULONG tx_thread_smp_protect_pad_2;
|
||||||
|
ULONG tx_thread_smp_protect_pad_3;
|
||||||
|
} TX_THREAD_SMP_PROTECT;
|
||||||
|
|
||||||
|
/* Define ThreadX interrupt lockout and restore macros for protection on
|
||||||
|
access of critical kernel information. The restore interrupt macro must
|
||||||
|
restore the interrupt posture of the running thread prior to the value
|
||||||
|
present prior to the disable macro. In most cases, the save area macro
|
||||||
|
is used to define a local function save area for the disable and restore
|
||||||
|
macros. */
|
||||||
|
|
||||||
|
#define TX_INTERRUPT_SAVE_AREA ULONG64 interrupt_save;
|
||||||
|
|
||||||
|
#define TX_DISABLE interrupt_save = _tx_thread_smp_protect();
|
||||||
|
#define TX_RESTORE _tx_thread_smp_unprotect(interrupt_save);
|
||||||
|
|
||||||
|
/************* End ThreadX SMP data type and function prototype definitions. *************/
|
||||||
|
|
||||||
|
/* Define the interrupt lockout macros for each ThreadX object. */
|
||||||
|
|
||||||
|
#define TX_BLOCK_POOL_DISABLE TX_DISABLE
|
||||||
|
#define TX_BYTE_POOL_DISABLE TX_DISABLE
|
||||||
|
#define TX_EVENT_FLAGS_GROUP_DISABLE TX_DISABLE
|
||||||
|
#define TX_MUTEX_DISABLE TX_DISABLE
|
||||||
|
#define TX_QUEUE_DISABLE TX_DISABLE
|
||||||
|
#define TX_SEMAPHORE_DISABLE TX_DISABLE
|
||||||
|
|
||||||
|
/* Define the version ID of ThreadX. This may be utilized by the application. */
|
||||||
|
|
||||||
|
#ifdef TX_THREAD_INIT
|
||||||
|
CHAR _tx_version_id[] = "Copyright (c) 2024 Microsoft Corporation. * ThreadX RISC-V64/GNU Version 6.4.2 *";
|
||||||
|
#else
|
||||||
|
extern CHAR _tx_version_id[];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*not __ASSEMBLER__ */
|
||||||
|
#endif
|
||||||
12
port/threadx_smp/src/tx_asm_offsets.c
Normal file
12
port/threadx_smp/src/tx_asm_offsets.c
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "tx_api.h"
|
||||||
|
|
||||||
|
#define TX_ASM_OFFSET(symbol, value) __asm__ volatile("\n.ascii \"-->" #symbol " %c0\\n\"" : : "i"(value))
|
||||||
|
|
||||||
|
void tx_asm_offsets_generate(void)
|
||||||
|
{
|
||||||
|
TX_ASM_OFFSET(TX_THREAD_STACK_END_OFFSET, offsetof(TX_THREAD, tx_thread_stack_end));
|
||||||
|
TX_ASM_OFFSET(TX_THREAD_TIME_SLICE_OFFSET, offsetof(TX_THREAD, tx_thread_time_slice));
|
||||||
|
TX_ASM_OFFSET(TX_THREAD_SMP_LOCK_READY_BIT_OFFSET, offsetof(TX_THREAD, tx_thread_smp_lock_ready_bit));
|
||||||
|
}
|
||||||
163
port/threadx_smp/src/tx_initialize_low_level.S
Normal file
163
port/threadx_smp/src/tx_initialize_low_level.S
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* 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
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
#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
|
||||||
|
/**************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* FUNCTION RELEASE */
|
||||||
|
/* */
|
||||||
|
/* _tx_initialize_low_level RISC-V64/GNU */
|
||||||
|
/* 6.2.1 */
|
||||||
|
/* AUTHOR */
|
||||||
|
/* */
|
||||||
|
/* Scott Larson, Microsoft Corporation */
|
||||||
|
/* */
|
||||||
|
/* 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 */
|
||||||
|
/* */
|
||||||
|
/* 03-08-2023 Scott Larson Initial Version 6.2.1 */
|
||||||
|
/* */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* VOID _tx_initialize_low_level(VOID)
|
||||||
|
*/
|
||||||
|
.global _tx_initialize_low_level
|
||||||
|
.weak _tx_initialize_low_level
|
||||||
|
.extern __heap_start
|
||||||
|
.extern board_init
|
||||||
|
_tx_initialize_low_level:
|
||||||
|
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
|
||||||
|
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, -8
|
||||||
|
STORE ra, 0(sp)
|
||||||
|
call board_init
|
||||||
|
LOAD ra, 0(sp)
|
||||||
|
addi sp, sp, 8
|
||||||
|
la t0, trap_entry
|
||||||
|
csrw mtvec, t0
|
||||||
|
ret
|
||||||
402
port/threadx_smp/src/tx_thread_context_restore.S
Normal file
402
port/threadx_smp/src/tx_thread_context_restore.S
Normal file
@@ -0,0 +1,402 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* 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 */
|
||||||
|
/** */
|
||||||
|
/** Thread */
|
||||||
|
/** */
|
||||||
|
/**************************************************************************/
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#include "tx_port.h"
|
||||||
|
|
||||||
|
.section .text
|
||||||
|
/**************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* FUNCTION RELEASE */
|
||||||
|
/* */
|
||||||
|
/* _tx_thread_context_restore RISC-V64/GNU */
|
||||||
|
/* 6.2.1 */
|
||||||
|
/* AUTHOR */
|
||||||
|
/* */
|
||||||
|
/* Scott Larson, Microsoft Corporation */
|
||||||
|
/* */
|
||||||
|
/* DESCRIPTION */
|
||||||
|
/* */
|
||||||
|
/* This function restores the interrupt context if it is processing a */
|
||||||
|
/* nested interrupt. If not, it returns to the interrupt thread if no */
|
||||||
|
/* preemption is necessary. Otherwise, if preemption is necessary or */
|
||||||
|
/* if no thread was running, the function returns to the scheduler. */
|
||||||
|
/* */
|
||||||
|
/* INPUT */
|
||||||
|
/* */
|
||||||
|
/* None */
|
||||||
|
/* */
|
||||||
|
/* OUTPUT */
|
||||||
|
/* */
|
||||||
|
/* None */
|
||||||
|
/* */
|
||||||
|
/* CALLS */
|
||||||
|
/* */
|
||||||
|
/* _tx_thread_schedule Thread scheduling routine */
|
||||||
|
/* */
|
||||||
|
/* CALLED BY */
|
||||||
|
/* */
|
||||||
|
/* ISRs Interrupt Service Routines */
|
||||||
|
/* */
|
||||||
|
/* RELEASE HISTORY */
|
||||||
|
/* */
|
||||||
|
/* DATE NAME DESCRIPTION */
|
||||||
|
/* */
|
||||||
|
/* 03-08-2023 Scott Larson Initial Version 6.2.1 */
|
||||||
|
/* */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* VOID _tx_thread_context_restore(VOID)
|
||||||
|
{ */
|
||||||
|
.global _tx_thread_context_restore
|
||||||
|
_tx_thread_context_restore:
|
||||||
|
|
||||||
|
/* Lockout interrupts. */
|
||||||
|
|
||||||
|
csrci mstatus, 0x08 // Disable interrupts
|
||||||
|
|
||||||
|
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||||
|
call _tx_execution_isr_exit // Call the ISR execution exit function
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Determine if interrupts are nested. */
|
||||||
|
/* if (--_tx_thread_system_state)
|
||||||
|
{ */
|
||||||
|
|
||||||
|
csrr t3, mhartid // Pickup current hart ID
|
||||||
|
slli t4, t3, 2 // Build per-hart ULONG offset
|
||||||
|
slli t5, t3, LOG_REGBYTES // Build per-hart pointer offset
|
||||||
|
la t0, _tx_thread_system_state // Pickup base of system-state array
|
||||||
|
add t0, t0, t4 // Select this hart's system-state slot
|
||||||
|
lw t1, 0(t0) // Pickup nested interrupt count
|
||||||
|
addi t1, t1, -1 // Decrement the nested interrupt counter
|
||||||
|
sw t1, 0(t0) // Store new nested count
|
||||||
|
beqz t1, _tx_thread_not_nested_restore // If 0, not nested restore
|
||||||
|
|
||||||
|
/* Interrupts are nested. */
|
||||||
|
|
||||||
|
/* Just recover the saved registers and return to the point of
|
||||||
|
interrupt. */
|
||||||
|
|
||||||
|
/* Recover floating point registers. */
|
||||||
|
#if defined(__riscv_float_abi_single)
|
||||||
|
flw f0, 31*REGBYTES(sp) // Recover ft0
|
||||||
|
flw f1, 32*REGBYTES(sp) // Recover ft1
|
||||||
|
flw f2, 33*REGBYTES(sp) // Recover ft2
|
||||||
|
flw f3, 34*REGBYTES(sp) // Recover ft3
|
||||||
|
flw f4, 35*REGBYTES(sp) // Recover ft4
|
||||||
|
flw f5, 36*REGBYTES(sp) // Recover ft5
|
||||||
|
flw f6, 37*REGBYTES(sp) // Recover ft6
|
||||||
|
flw f7, 38*REGBYTES(sp) // Recover ft7
|
||||||
|
flw f10,41*REGBYTES(sp) // Recover fa0
|
||||||
|
flw f11,42*REGBYTES(sp) // Recover fa1
|
||||||
|
flw f12,43*REGBYTES(sp) // Recover fa2
|
||||||
|
flw f13,44*REGBYTES(sp) // Recover fa3
|
||||||
|
flw f14,45*REGBYTES(sp) // Recover fa4
|
||||||
|
flw f15,46*REGBYTES(sp) // Recover fa5
|
||||||
|
flw f16,47*REGBYTES(sp) // Recover fa6
|
||||||
|
flw f17,48*REGBYTES(sp) // Recover fa7
|
||||||
|
flw f28,59*REGBYTES(sp) // Recover ft8
|
||||||
|
flw f29,60*REGBYTES(sp) // Recover ft9
|
||||||
|
flw f30,61*REGBYTES(sp) // Recover ft10
|
||||||
|
flw f31,62*REGBYTES(sp) // Recover ft11
|
||||||
|
lw t0, 63*REGBYTES(sp) // Recover fcsr
|
||||||
|
csrw fcsr, t0 //
|
||||||
|
#elif defined(__riscv_float_abi_double)
|
||||||
|
fld f0, 31*REGBYTES(sp) // Recover ft0
|
||||||
|
fld f1, 32*REGBYTES(sp) // Recover ft1
|
||||||
|
fld f2, 33*REGBYTES(sp) // Recover ft2
|
||||||
|
fld f3, 34*REGBYTES(sp) // Recover ft3
|
||||||
|
fld f4, 35*REGBYTES(sp) // Recover ft4
|
||||||
|
fld f5, 36*REGBYTES(sp) // Recover ft5
|
||||||
|
fld f6, 37*REGBYTES(sp) // Recover ft6
|
||||||
|
fld f7, 38*REGBYTES(sp) // Recover ft7
|
||||||
|
fld f10,41*REGBYTES(sp) // Recover fa0
|
||||||
|
fld f11,42*REGBYTES(sp) // Recover fa1
|
||||||
|
fld f12,43*REGBYTES(sp) // Recover fa2
|
||||||
|
fld f13,44*REGBYTES(sp) // Recover fa3
|
||||||
|
fld f14,45*REGBYTES(sp) // Recover fa4
|
||||||
|
fld f15,46*REGBYTES(sp) // Recover fa5
|
||||||
|
fld f16,47*REGBYTES(sp) // Recover fa6
|
||||||
|
fld f17,48*REGBYTES(sp) // Recover fa7
|
||||||
|
fld f28,59*REGBYTES(sp) // Recover ft8
|
||||||
|
fld f29,60*REGBYTES(sp) // Recover ft9
|
||||||
|
fld f30,61*REGBYTES(sp) // Recover ft10
|
||||||
|
fld f31,62*REGBYTES(sp) // Recover ft11
|
||||||
|
LOAD t0, 63*REGBYTES(sp) // Recover fcsr
|
||||||
|
csrw fcsr, t0 //
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Recover standard registers. */
|
||||||
|
|
||||||
|
/* Restore registers,
|
||||||
|
Skip global pointer because that does not change.
|
||||||
|
Also skip the saved registers since they have been restored by any function we called,
|
||||||
|
except s0 since we use it ourselves. */
|
||||||
|
|
||||||
|
LOAD t0, 30*REGBYTES(sp) // Recover mepc
|
||||||
|
csrw mepc, t0 // Setup mepc
|
||||||
|
li t0, 0x1880 // Prepare MPIP
|
||||||
|
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
|
||||||
|
li t1, 1<<13
|
||||||
|
or t0, t1, t0
|
||||||
|
#endif
|
||||||
|
csrw mstatus, t0 // Enable MPIP
|
||||||
|
|
||||||
|
LOAD x1, 28*REGBYTES(sp) // Recover RA
|
||||||
|
LOAD x5, 19*REGBYTES(sp) // Recover t0
|
||||||
|
LOAD x6, 18*REGBYTES(sp) // Recover t1
|
||||||
|
LOAD x7, 17*REGBYTES(sp) // Recover t2
|
||||||
|
LOAD x8, 12*REGBYTES(sp) // Recover s0
|
||||||
|
LOAD x10, 27*REGBYTES(sp) // Recover a0
|
||||||
|
LOAD x11, 26*REGBYTES(sp) // Recover a1
|
||||||
|
LOAD x12, 25*REGBYTES(sp) // Recover a2
|
||||||
|
LOAD x13, 24*REGBYTES(sp) // Recover a3
|
||||||
|
LOAD x14, 23*REGBYTES(sp) // Recover a4
|
||||||
|
LOAD x15, 22*REGBYTES(sp) // Recover a5
|
||||||
|
LOAD x16, 21*REGBYTES(sp) // Recover a6
|
||||||
|
LOAD x17, 20*REGBYTES(sp) // Recover a7
|
||||||
|
LOAD x28, 16*REGBYTES(sp) // Recover t3
|
||||||
|
LOAD x29, 15*REGBYTES(sp) // Recover t4
|
||||||
|
LOAD x30, 14*REGBYTES(sp) // Recover t5
|
||||||
|
LOAD x31, 13*REGBYTES(sp) // Recover t6
|
||||||
|
|
||||||
|
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
|
||||||
|
addi sp, sp, 65*REGBYTES // Recover stack frame - with floating point enabled
|
||||||
|
#else
|
||||||
|
addi sp, sp, 32*REGBYTES // Recover stack frame - without floating point enabled
|
||||||
|
#endif
|
||||||
|
mret // Return to point of interrupt
|
||||||
|
|
||||||
|
/* } */
|
||||||
|
_tx_thread_not_nested_restore:
|
||||||
|
/* Determine if a thread was interrupted and no preemption is required. */
|
||||||
|
/* else if (((_tx_thread_current_ptr) && (_tx_thread_current_ptr == _tx_thread_execute_ptr)
|
||||||
|
|| (_tx_thread_preempt_disable))
|
||||||
|
{ */
|
||||||
|
|
||||||
|
la t0, _tx_thread_current_ptr // Pickup base of current-thread array
|
||||||
|
add t0, t0, t5 // Select this hart's current-thread slot
|
||||||
|
LOAD t1, 0(t0) // Pickup current thread pointer
|
||||||
|
beqz t1, _tx_thread_idle_system_restore // If NULL, idle system restore
|
||||||
|
|
||||||
|
la t0, _tx_thread_execute_ptr // Pickup base of execute-thread array
|
||||||
|
add t0, t0, t5 // Select this hart's execute-thread slot
|
||||||
|
LOAD t2, 0(t0) // Pickup thread execute pointer
|
||||||
|
beq t1, t2, _tx_thread_no_preempt_restore // Same thread selected, no preemption
|
||||||
|
|
||||||
|
la t0, _tx_thread_smp_protection // Pickup protection structure
|
||||||
|
lw t2, 4(t0) // Pickup owning hart
|
||||||
|
bne t2, t3, _tx_thread_preempt_restore // If owned by another hart, preempt
|
||||||
|
|
||||||
|
LOAD t2, _tx_thread_preempt_disable // Pickup preempt disable flag
|
||||||
|
bgtz t2, _tx_thread_no_preempt_restore // If set, restore interrupted thread
|
||||||
|
|
||||||
|
|
||||||
|
_tx_thread_no_preempt_restore:
|
||||||
|
/* Restore interrupted thread or ISR. */
|
||||||
|
|
||||||
|
/* Pickup the saved stack pointer. */
|
||||||
|
/* SP = _tx_thread_current_ptr -> tx_thread_stack_ptr; */
|
||||||
|
|
||||||
|
LOAD sp, 2*REGBYTES(t1) // Switch back to thread's stack
|
||||||
|
|
||||||
|
/* Recover floating point registers. */
|
||||||
|
#if defined(__riscv_float_abi_single)
|
||||||
|
flw f0, 31*REGBYTES(sp) // Recover ft0
|
||||||
|
flw f1, 32*REGBYTES(sp) // Recover ft1
|
||||||
|
flw f2, 33*REGBYTES(sp) // Recover ft2
|
||||||
|
flw f3, 34*REGBYTES(sp) // Recover ft3
|
||||||
|
flw f4, 35*REGBYTES(sp) // Recover ft4
|
||||||
|
flw f5, 36*REGBYTES(sp) // Recover ft5
|
||||||
|
flw f6, 37*REGBYTES(sp) // Recover ft6
|
||||||
|
flw f7, 38*REGBYTES(sp) // Recover ft7
|
||||||
|
flw f10,41*REGBYTES(sp) // Recover fa0
|
||||||
|
flw f11,42*REGBYTES(sp) // Recover fa1
|
||||||
|
flw f12,43*REGBYTES(sp) // Recover fa2
|
||||||
|
flw f13,44*REGBYTES(sp) // Recover fa3
|
||||||
|
flw f14,45*REGBYTES(sp) // Recover fa4
|
||||||
|
flw f15,46*REGBYTES(sp) // Recover fa5
|
||||||
|
flw f16,47*REGBYTES(sp) // Recover fa6
|
||||||
|
flw f17,48*REGBYTES(sp) // Recover fa7
|
||||||
|
flw f28,59*REGBYTES(sp) // Recover ft8
|
||||||
|
flw f29,60*REGBYTES(sp) // Recover ft9
|
||||||
|
flw f30,61*REGBYTES(sp) // Recover ft10
|
||||||
|
flw f31,62*REGBYTES(sp) // Recover ft11
|
||||||
|
lw t0, 63*REGBYTES(sp) // Recover fcsr
|
||||||
|
csrw fcsr, t0 //
|
||||||
|
#elif defined(__riscv_float_abi_double)
|
||||||
|
fld f0, 31*REGBYTES(sp) // Recover ft0
|
||||||
|
fld f1, 32*REGBYTES(sp) // Recover ft1
|
||||||
|
fld f2, 33*REGBYTES(sp) // Recover ft2
|
||||||
|
fld f3, 34*REGBYTES(sp) // Recover ft3
|
||||||
|
fld f4, 35*REGBYTES(sp) // Recover ft4
|
||||||
|
fld f5, 36*REGBYTES(sp) // Recover ft5
|
||||||
|
fld f6, 37*REGBYTES(sp) // Recover ft6
|
||||||
|
fld f7, 38*REGBYTES(sp) // Recover ft7
|
||||||
|
fld f10,41*REGBYTES(sp) // Recover fa0
|
||||||
|
fld f11,42*REGBYTES(sp) // Recover fa1
|
||||||
|
fld f12,43*REGBYTES(sp) // Recover fa2
|
||||||
|
fld f13,44*REGBYTES(sp) // Recover fa3
|
||||||
|
fld f14,45*REGBYTES(sp) // Recover fa4
|
||||||
|
fld f15,46*REGBYTES(sp) // Recover fa5
|
||||||
|
fld f16,47*REGBYTES(sp) // Recover fa6
|
||||||
|
fld f17,48*REGBYTES(sp) // Recover fa7
|
||||||
|
fld f28,59*REGBYTES(sp) // Recover ft8
|
||||||
|
fld f29,60*REGBYTES(sp) // Recover ft9
|
||||||
|
fld f30,61*REGBYTES(sp) // Recover ft10
|
||||||
|
fld f31,62*REGBYTES(sp) // Recover ft11
|
||||||
|
LOAD t0, 63*REGBYTES(sp) // Recover fcsr
|
||||||
|
csrw fcsr, t0 //
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Recover the saved context and return to the point of interrupt. */
|
||||||
|
|
||||||
|
/* Recover standard registers. */
|
||||||
|
/* Restore registers,
|
||||||
|
Skip global pointer because that does not change */
|
||||||
|
|
||||||
|
LOAD t0, 30*REGBYTES(sp) // Recover mepc
|
||||||
|
csrw mepc, t0 // Setup mepc
|
||||||
|
li t0, 0x1880 // Prepare MPIP
|
||||||
|
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
|
||||||
|
li t1, 1<<13
|
||||||
|
or t0, t1, t0
|
||||||
|
#endif
|
||||||
|
csrw mstatus, t0 // Enable MPIP
|
||||||
|
|
||||||
|
LOAD x1, 28*REGBYTES(sp) // Recover RA
|
||||||
|
LOAD x5, 19*REGBYTES(sp) // Recover t0
|
||||||
|
LOAD x6, 18*REGBYTES(sp) // Recover t1
|
||||||
|
LOAD x7, 17*REGBYTES(sp) // Recover t2
|
||||||
|
LOAD x8, 12*REGBYTES(sp) // Recover s0
|
||||||
|
LOAD x10, 27*REGBYTES(sp) // Recover a0
|
||||||
|
LOAD x11, 26*REGBYTES(sp) // Recover a1
|
||||||
|
LOAD x12, 25*REGBYTES(sp) // Recover a2
|
||||||
|
LOAD x13, 24*REGBYTES(sp) // Recover a3
|
||||||
|
LOAD x14, 23*REGBYTES(sp) // Recover a4
|
||||||
|
LOAD x15, 22*REGBYTES(sp) // Recover a5
|
||||||
|
LOAD x16, 21*REGBYTES(sp) // Recover a6
|
||||||
|
LOAD x17, 20*REGBYTES(sp) // Recover a7
|
||||||
|
LOAD x28, 16*REGBYTES(sp) // Recover t3
|
||||||
|
LOAD x29, 15*REGBYTES(sp) // Recover t4
|
||||||
|
LOAD x30, 14*REGBYTES(sp) // Recover t5
|
||||||
|
LOAD x31, 13*REGBYTES(sp) // Recover t6
|
||||||
|
|
||||||
|
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
|
||||||
|
addi sp, sp, 65*REGBYTES // Recover stack frame - with floating point enabled
|
||||||
|
#else
|
||||||
|
addi sp, sp, 32*REGBYTES // Recover stack frame - without floating point enabled
|
||||||
|
#endif
|
||||||
|
mret // Return to point of interrupt
|
||||||
|
|
||||||
|
/* }
|
||||||
|
else
|
||||||
|
{ */
|
||||||
|
_tx_thread_preempt_restore:
|
||||||
|
/* Instead of directly activating the thread again, ensure we save the
|
||||||
|
entire stack frame by saving the remaining registers. */
|
||||||
|
|
||||||
|
LOAD t0, 2*REGBYTES(t1) // Pickup thread's stack pointer
|
||||||
|
ori t3, x0, 1 // Build interrupt stack type
|
||||||
|
STORE t3, 0(t0) // Store stack type
|
||||||
|
|
||||||
|
/* Store floating point preserved registers. */
|
||||||
|
#ifdef __riscv_float_abi_single
|
||||||
|
fsw f8, 39*REGBYTES(t0) // Store fs0
|
||||||
|
fsw f9, 40*REGBYTES(t0) // Store fs1
|
||||||
|
fsw f18, 49*REGBYTES(t0) // Store fs2
|
||||||
|
fsw f19, 50*REGBYTES(t0) // Store fs3
|
||||||
|
fsw f20, 51*REGBYTES(t0) // Store fs4
|
||||||
|
fsw f21, 52*REGBYTES(t0) // Store fs5
|
||||||
|
fsw f22, 53*REGBYTES(t0) // Store fs6
|
||||||
|
fsw f23, 54*REGBYTES(t0) // Store fs7
|
||||||
|
fsw f24, 55*REGBYTES(t0) // Store fs8
|
||||||
|
fsw f25, 56*REGBYTES(t0) // Store fs9
|
||||||
|
fsw f26, 57*REGBYTES(t0) // Store fs10
|
||||||
|
fsw f27, 58*REGBYTES(t0) // Store fs11
|
||||||
|
#elif defined(__riscv_float_abi_double)
|
||||||
|
fsd f8, 39*REGBYTES(t0) // Store fs0
|
||||||
|
fsd f9, 40*REGBYTES(t0) // Store fs1
|
||||||
|
fsd f18, 49*REGBYTES(t0) // Store fs2
|
||||||
|
fsd f19, 50*REGBYTES(t0) // Store fs3
|
||||||
|
fsd f20, 51*REGBYTES(t0) // Store fs4
|
||||||
|
fsd f21, 52*REGBYTES(t0) // Store fs5
|
||||||
|
fsd f22, 53*REGBYTES(t0) // Store fs6
|
||||||
|
fsd f23, 54*REGBYTES(t0) // Store fs7
|
||||||
|
fsd f24, 55*REGBYTES(t0) // Store fs8
|
||||||
|
fsd f25, 56*REGBYTES(t0) // Store fs9
|
||||||
|
fsd f26, 57*REGBYTES(t0) // Store fs10
|
||||||
|
fsd f27, 58*REGBYTES(t0) // Store fs11
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Store standard preserved registers. */
|
||||||
|
|
||||||
|
STORE x9, 11*REGBYTES(t0) // Store s1
|
||||||
|
STORE x18, 10*REGBYTES(t0) // Store s2
|
||||||
|
STORE x19, 9*REGBYTES(t0) // Store s3
|
||||||
|
STORE x20, 8*REGBYTES(t0) // Store s4
|
||||||
|
STORE x21, 7*REGBYTES(t0) // Store s5
|
||||||
|
STORE x22, 6*REGBYTES(t0) // Store s6
|
||||||
|
STORE x23, 5*REGBYTES(t0) // Store s7
|
||||||
|
STORE x24, 4*REGBYTES(t0) // Store s8
|
||||||
|
STORE x25, 3*REGBYTES(t0) // Store s9
|
||||||
|
STORE x26, 2*REGBYTES(t0) // Store s10
|
||||||
|
STORE x27, 1*REGBYTES(t0) // Store s11
|
||||||
|
// Note: s0 is already stored!
|
||||||
|
|
||||||
|
/* Save the remaining time-slice and disable it. */
|
||||||
|
/* if (_tx_timer_time_slice)
|
||||||
|
{ */
|
||||||
|
|
||||||
|
la t0, _tx_timer_time_slice // Pickup base of time-slice array
|
||||||
|
add t0, t0, t4 // Select this hart's time-slice slot
|
||||||
|
lw t2, 0(t0) // Pickup time slice
|
||||||
|
beqz t2, _tx_thread_dont_save_ts // If 0, skip time slice processing
|
||||||
|
|
||||||
|
/* _tx_thread_current_ptr -> tx_thread_time_slice = _tx_timer_time_slice
|
||||||
|
_tx_timer_time_slice = 0; */
|
||||||
|
|
||||||
|
sw t2, TX_THREAD_TIME_SLICE_OFFSET(t1) // Save current time slice
|
||||||
|
sw x0, 0(t0) // Clear global time slice
|
||||||
|
|
||||||
|
|
||||||
|
/* } */
|
||||||
|
_tx_thread_dont_save_ts:
|
||||||
|
/* Clear the current task pointer. */
|
||||||
|
/* _tx_thread_current_ptr = TX_NULL; */
|
||||||
|
|
||||||
|
/* Return to the scheduler. */
|
||||||
|
/* _tx_thread_schedule(); */
|
||||||
|
|
||||||
|
la t0, _tx_thread_current_ptr // Pickup base of current-thread array
|
||||||
|
add t0, t0, t5 // Select this hart's current-thread slot
|
||||||
|
STORE x0, 0(t0) // Clear current thread pointer
|
||||||
|
|
||||||
|
fence rw, rw // Publish current-thread clear before ready token
|
||||||
|
addi t0, t1, TX_THREAD_SMP_LOCK_READY_BIT_OFFSET // Pickup lock/ready-bit address
|
||||||
|
li t2, 1 // Rebuild ready token
|
||||||
|
amoswap.w.rl x0, t2, (t0) // Set thread ready token for reschedule
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
_tx_thread_idle_system_restore:
|
||||||
|
/* Just return back to the scheduler! */
|
||||||
|
j _tx_thread_schedule // Return to scheduler
|
||||||
|
|
||||||
|
/* } */
|
||||||
289
port/threadx_smp/src/tx_thread_context_save.S
Normal file
289
port/threadx_smp/src/tx_thread_context_save.S
Normal file
@@ -0,0 +1,289 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* 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 */
|
||||||
|
/** */
|
||||||
|
/** Thread */
|
||||||
|
/** */
|
||||||
|
/**************************************************************************/
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#include "tx_port.h"
|
||||||
|
|
||||||
|
.section .text
|
||||||
|
/**************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* FUNCTION RELEASE */
|
||||||
|
/* */
|
||||||
|
/* _tx_thread_context_save RISC-V64/GNU */
|
||||||
|
/* 6.2.1 */
|
||||||
|
/* AUTHOR */
|
||||||
|
/* */
|
||||||
|
/* Scott Larson, Microsoft Corporation */
|
||||||
|
/* */
|
||||||
|
/* DESCRIPTION */
|
||||||
|
/* */
|
||||||
|
/* This function saves the context of an executing thread in the */
|
||||||
|
/* beginning of interrupt processing. The function also ensures that */
|
||||||
|
/* the system stack is used upon return to the calling ISR. */
|
||||||
|
/* */
|
||||||
|
/* INPUT */
|
||||||
|
/* */
|
||||||
|
/* None */
|
||||||
|
/* */
|
||||||
|
/* OUTPUT */
|
||||||
|
/* */
|
||||||
|
/* None */
|
||||||
|
/* */
|
||||||
|
/* CALLS */
|
||||||
|
/* */
|
||||||
|
/* None */
|
||||||
|
/* */
|
||||||
|
/* CALLED BY */
|
||||||
|
/* */
|
||||||
|
/* ISRs */
|
||||||
|
/* */
|
||||||
|
/* RELEASE HISTORY */
|
||||||
|
/* */
|
||||||
|
/* DATE NAME DESCRIPTION */
|
||||||
|
/* */
|
||||||
|
/* 03-08-2023 Scott Larson Initial Version 6.2.1 */
|
||||||
|
/* */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* VOID _tx_thread_context_save(VOID)
|
||||||
|
{ */
|
||||||
|
.global _tx_thread_context_save
|
||||||
|
_tx_thread_context_save:
|
||||||
|
|
||||||
|
/* Upon entry to this routine, it is assumed that interrupts are locked
|
||||||
|
out and the interrupt stack fame has been allocated and x1 (ra) has
|
||||||
|
been saved on the stack. */
|
||||||
|
|
||||||
|
STORE t0, 19*REGBYTES(sp) // Save t0
|
||||||
|
STORE t1, 18*REGBYTES(sp) // Save t1
|
||||||
|
STORE x7, 17*REGBYTES(sp) // Save t2 before reusing it
|
||||||
|
STORE x28, 16*REGBYTES(sp) // Save t3 before reusing it
|
||||||
|
STORE x29, 15*REGBYTES(sp) // Save t4 before reusing it
|
||||||
|
|
||||||
|
csrr t2, mhartid // Pickup current hart ID
|
||||||
|
slli t3, t2, 2 // Build per-hart ULONG offset
|
||||||
|
slli t4, t2, LOG_REGBYTES // Build per-hart pointer offset
|
||||||
|
la t1, _tx_thread_system_state // Pickup base of system state array
|
||||||
|
add t0, t1, t3 // Select this hart's system-state slot
|
||||||
|
lw t1, 0(t0) // Pickup system state
|
||||||
|
|
||||||
|
/* Check for a nested interrupt condition. */
|
||||||
|
/* if (_tx_thread_system_state++)
|
||||||
|
{ */
|
||||||
|
beqz t1, _tx_thread_not_nested_save // If 0, first interrupt condition
|
||||||
|
addi t1, t1, 1 // Increment the interrupt counter
|
||||||
|
sw t1, 0(t0) // Store the interrupt counter
|
||||||
|
|
||||||
|
/* Nested interrupt condition.
|
||||||
|
Save the reset of the scratch registers on the stack and return to the
|
||||||
|
calling ISR. */
|
||||||
|
|
||||||
|
STORE x8, 12*REGBYTES(sp) // Store s0
|
||||||
|
STORE x10, 27*REGBYTES(sp) // Store a0
|
||||||
|
STORE x11, 26*REGBYTES(sp) // Store a1
|
||||||
|
STORE x12, 25*REGBYTES(sp) // Store a2
|
||||||
|
STORE x13, 24*REGBYTES(sp) // Store a3
|
||||||
|
STORE x14, 23*REGBYTES(sp) // Store a4
|
||||||
|
STORE x15, 22*REGBYTES(sp) // Store a5
|
||||||
|
STORE x16, 21*REGBYTES(sp) // Store a6
|
||||||
|
STORE x17, 20*REGBYTES(sp) // Store a7
|
||||||
|
STORE x30, 14*REGBYTES(sp) // Store t5
|
||||||
|
STORE x31, 13*REGBYTES(sp) // Store t6
|
||||||
|
csrr t0, mepc // Load exception program counter
|
||||||
|
STORE t0, 30*REGBYTES(sp) // Save it on the stack
|
||||||
|
|
||||||
|
/* Save floating point scratch registers. */
|
||||||
|
#if defined(__riscv_float_abi_single)
|
||||||
|
fsw f0, 31*REGBYTES(sp) // Store ft0
|
||||||
|
fsw f1, 32*REGBYTES(sp) // Store ft1
|
||||||
|
fsw f2, 33*REGBYTES(sp) // Store ft2
|
||||||
|
fsw f3, 34*REGBYTES(sp) // Store ft3
|
||||||
|
fsw f4, 35*REGBYTES(sp) // Store ft4
|
||||||
|
fsw f5, 36*REGBYTES(sp) // Store ft5
|
||||||
|
fsw f6, 37*REGBYTES(sp) // Store ft6
|
||||||
|
fsw f7, 38*REGBYTES(sp) // Store ft7
|
||||||
|
fsw f10,41*REGBYTES(sp) // Store fa0
|
||||||
|
fsw f11,42*REGBYTES(sp) // Store fa1
|
||||||
|
fsw f12,43*REGBYTES(sp) // Store fa2
|
||||||
|
fsw f13,44*REGBYTES(sp) // Store fa3
|
||||||
|
fsw f14,45*REGBYTES(sp) // Store fa4
|
||||||
|
fsw f15,46*REGBYTES(sp) // Store fa5
|
||||||
|
fsw f16,47*REGBYTES(sp) // Store fa6
|
||||||
|
fsw f17,48*REGBYTES(sp) // Store fa7
|
||||||
|
fsw f28,59*REGBYTES(sp) // Store ft8
|
||||||
|
fsw f29,60*REGBYTES(sp) // Store ft9
|
||||||
|
fsw f30,61*REGBYTES(sp) // Store ft10
|
||||||
|
fsw f31,62*REGBYTES(sp) // Store ft11
|
||||||
|
csrr t0, fcsr
|
||||||
|
STORE t0, 63*REGBYTES(sp) // Store fcsr
|
||||||
|
#elif defined(__riscv_float_abi_double)
|
||||||
|
fsd f0, 31*REGBYTES(sp) // Store ft0
|
||||||
|
fsd f1, 32*REGBYTES(sp) // Store ft1
|
||||||
|
fsd f2, 33*REGBYTES(sp) // Store ft2
|
||||||
|
fsd f3, 34*REGBYTES(sp) // Store ft3
|
||||||
|
fsd f4, 35*REGBYTES(sp) // Store ft4
|
||||||
|
fsd f5, 36*REGBYTES(sp) // Store ft5
|
||||||
|
fsd f6, 37*REGBYTES(sp) // Store ft6
|
||||||
|
fsd f7, 38*REGBYTES(sp) // Store ft7
|
||||||
|
fsd f10,41*REGBYTES(sp) // Store fa0
|
||||||
|
fsd f11,42*REGBYTES(sp) // Store fa1
|
||||||
|
fsd f12,43*REGBYTES(sp) // Store fa2
|
||||||
|
fsd f13,44*REGBYTES(sp) // Store fa3
|
||||||
|
fsd f14,45*REGBYTES(sp) // Store fa4
|
||||||
|
fsd f15,46*REGBYTES(sp) // Store fa5
|
||||||
|
fsd f16,47*REGBYTES(sp) // Store fa6
|
||||||
|
fsd f17,48*REGBYTES(sp) // Store fa7
|
||||||
|
fsd f28,59*REGBYTES(sp) // Store ft8
|
||||||
|
fsd f29,60*REGBYTES(sp) // Store ft9
|
||||||
|
fsd f30,61*REGBYTES(sp) // Store ft10
|
||||||
|
fsd f31,62*REGBYTES(sp) // Store ft11
|
||||||
|
csrr t0, fcsr
|
||||||
|
STORE t0, 63*REGBYTES(sp) // Store fcsr
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||||
|
call _tx_execution_isr_enter // Call the ISR execution enter function
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ret // Return to calling ISR
|
||||||
|
|
||||||
|
_tx_thread_not_nested_save:
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* Otherwise, not nested, check to see if a thread was running. */
|
||||||
|
/* else if (_tx_thread_current_ptr)
|
||||||
|
{ */
|
||||||
|
addi t1, t1, 1 // Increment the interrupt counter
|
||||||
|
sw t1, 0(t0) // Store the interrupt counter
|
||||||
|
|
||||||
|
/* Not nested: Find the user thread that was running and load our SP */
|
||||||
|
|
||||||
|
la t1, _tx_thread_current_ptr // Pickup base of current-thread array
|
||||||
|
add t0, t1, t4 // Select this hart's current-thread slot
|
||||||
|
LOAD t0, 0(t0) // Pickup current thread pointer
|
||||||
|
beqz t0, _tx_thread_idle_system_save // If NULL, idle system was interrupted
|
||||||
|
|
||||||
|
/* Save the standard scratch registers. */
|
||||||
|
|
||||||
|
STORE x8, 12*REGBYTES(sp) // Store s0
|
||||||
|
STORE x10, 27*REGBYTES(sp) // Store a0
|
||||||
|
STORE x11, 26*REGBYTES(sp) // Store a1
|
||||||
|
STORE x12, 25*REGBYTES(sp) // Store a2
|
||||||
|
STORE x13, 24*REGBYTES(sp) // Store a3
|
||||||
|
STORE x14, 23*REGBYTES(sp) // Store a4
|
||||||
|
STORE x15, 22*REGBYTES(sp) // Store a5
|
||||||
|
STORE x16, 21*REGBYTES(sp) // Store a6
|
||||||
|
STORE x17, 20*REGBYTES(sp) // Store a7
|
||||||
|
STORE x30, 14*REGBYTES(sp) // Store t5
|
||||||
|
STORE x31, 13*REGBYTES(sp) // Store t6
|
||||||
|
|
||||||
|
csrr t0, mepc // Load exception program counter
|
||||||
|
STORE t0, 30*REGBYTES(sp) // Save it on the stack
|
||||||
|
|
||||||
|
/* Save floating point scratch registers. */
|
||||||
|
#if defined(__riscv_float_abi_single)
|
||||||
|
fsw f0, 31*REGBYTES(sp) // Store ft0
|
||||||
|
fsw f1, 32*REGBYTES(sp) // Store ft1
|
||||||
|
fsw f2, 33*REGBYTES(sp) // Store ft2
|
||||||
|
fsw f3, 34*REGBYTES(sp) // Store ft3
|
||||||
|
fsw f4, 35*REGBYTES(sp) // Store ft4
|
||||||
|
fsw f5, 36*REGBYTES(sp) // Store ft5
|
||||||
|
fsw f6, 37*REGBYTES(sp) // Store ft6
|
||||||
|
fsw f7, 38*REGBYTES(sp) // Store ft7
|
||||||
|
fsw f10,41*REGBYTES(sp) // Store fa0
|
||||||
|
fsw f11,42*REGBYTES(sp) // Store fa1
|
||||||
|
fsw f12,43*REGBYTES(sp) // Store fa2
|
||||||
|
fsw f13,44*REGBYTES(sp) // Store fa3
|
||||||
|
fsw f14,45*REGBYTES(sp) // Store fa4
|
||||||
|
fsw f15,46*REGBYTES(sp) // Store fa5
|
||||||
|
fsw f16,47*REGBYTES(sp) // Store fa6
|
||||||
|
fsw f17,48*REGBYTES(sp) // Store fa7
|
||||||
|
fsw f28,59*REGBYTES(sp) // Store ft8
|
||||||
|
fsw f29,60*REGBYTES(sp) // Store ft9
|
||||||
|
fsw f30,61*REGBYTES(sp) // Store ft10
|
||||||
|
fsw f31,62*REGBYTES(sp) // Store ft11
|
||||||
|
csrr t0, fcsr
|
||||||
|
STORE t0, 63*REGBYTES(sp) // Store fcsr
|
||||||
|
#elif defined(__riscv_float_abi_double)
|
||||||
|
fsd f0, 31*REGBYTES(sp) // Store ft0
|
||||||
|
fsd f1, 32*REGBYTES(sp) // Store ft1
|
||||||
|
fsd f2, 33*REGBYTES(sp) // Store ft2
|
||||||
|
fsd f3, 34*REGBYTES(sp) // Store ft3
|
||||||
|
fsd f4, 35*REGBYTES(sp) // Store ft4
|
||||||
|
fsd f5, 36*REGBYTES(sp) // Store ft5
|
||||||
|
fsd f6, 37*REGBYTES(sp) // Store ft6
|
||||||
|
fsd f7, 38*REGBYTES(sp) // Store ft7
|
||||||
|
fsd f10,41*REGBYTES(sp) // Store fa0
|
||||||
|
fsd f11,42*REGBYTES(sp) // Store fa1
|
||||||
|
fsd f12,43*REGBYTES(sp) // Store fa2
|
||||||
|
fsd f13,44*REGBYTES(sp) // Store fa3
|
||||||
|
fsd f14,45*REGBYTES(sp) // Store fa4
|
||||||
|
fsd f15,46*REGBYTES(sp) // Store fa5
|
||||||
|
fsd f16,47*REGBYTES(sp) // Store fa6
|
||||||
|
fsd f17,48*REGBYTES(sp) // Store fa7
|
||||||
|
fsd f28,59*REGBYTES(sp) // Store ft8
|
||||||
|
fsd f29,60*REGBYTES(sp) // Store ft9
|
||||||
|
fsd f30,61*REGBYTES(sp) // Store ft10
|
||||||
|
fsd f31,62*REGBYTES(sp) // Store ft11
|
||||||
|
csrr t0, fcsr
|
||||||
|
STORE t0, 63*REGBYTES(sp) // Store fcsr
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Save the current stack pointer in the thread's control block. */
|
||||||
|
/* _tx_thread_current_ptr -> tx_thread_stack_ptr = sp; */
|
||||||
|
|
||||||
|
/* Switch to the system stack. */
|
||||||
|
/* sp = _tx_thread_system_stack_ptr; */
|
||||||
|
|
||||||
|
la t0, _tx_thread_current_ptr // Pickup base of current-thread array
|
||||||
|
add t0, t0, t4 // Select this hart's current-thread slot
|
||||||
|
LOAD t1, 0(t0) // Pickup current thread pointer
|
||||||
|
STORE sp, 2*REGBYTES(t1) // Save stack pointer
|
||||||
|
|
||||||
|
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||||
|
/* _tx_execution_isr_enter is called with thread stack pointer */
|
||||||
|
call _tx_execution_isr_enter // Call the ISR execution enter function
|
||||||
|
#endif
|
||||||
|
|
||||||
|
la t0, _tx_thread_system_stack_ptr // Pickup base of system-stack array
|
||||||
|
add t0, t0, t4 // Select this hart's system-stack slot
|
||||||
|
LOAD sp, 0(t0) // Switch to system stack
|
||||||
|
ret // Return to calling ISR
|
||||||
|
|
||||||
|
/* }
|
||||||
|
else
|
||||||
|
{ */
|
||||||
|
|
||||||
|
_tx_thread_idle_system_save:
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||||
|
call _tx_execution_isr_enter // Call the ISR execution enter function
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Interrupt occurred in the scheduling loop. */
|
||||||
|
|
||||||
|
/* }
|
||||||
|
} */
|
||||||
|
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
|
||||||
|
addi sp, sp, 65*REGBYTES // Recover stack frame - with floating point enabled
|
||||||
|
#else
|
||||||
|
addi sp, sp, 32*REGBYTES // Recover the reserved stack space
|
||||||
|
#endif
|
||||||
|
ret // Return to calling ISR
|
||||||
337
port/threadx_smp/src/tx_thread_schedule.S
Normal file
337
port/threadx_smp/src/tx_thread_schedule.S
Normal file
@@ -0,0 +1,337 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* 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 */
|
||||||
|
/** */
|
||||||
|
/** Thread */
|
||||||
|
/** */
|
||||||
|
/**************************************************************************/
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#include "tx_port.h"
|
||||||
|
|
||||||
|
.section .text
|
||||||
|
/**************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* FUNCTION RELEASE */
|
||||||
|
/* */
|
||||||
|
/* _tx_thread_schedule RISC-V64/GNU */
|
||||||
|
/* 6.2.1 */
|
||||||
|
/* AUTHOR */
|
||||||
|
/* */
|
||||||
|
/* Scott Larson, Microsoft Corporation */
|
||||||
|
/* */
|
||||||
|
/* DESCRIPTION */
|
||||||
|
/* */
|
||||||
|
/* This function waits for a thread control block pointer to appear in */
|
||||||
|
/* the _tx_thread_execute_ptr variable. Once a thread pointer appears */
|
||||||
|
/* in the variable, the corresponding thread is resumed. */
|
||||||
|
/* */
|
||||||
|
/* INPUT */
|
||||||
|
/* */
|
||||||
|
/* None */
|
||||||
|
/* */
|
||||||
|
/* OUTPUT */
|
||||||
|
/* */
|
||||||
|
/* None */
|
||||||
|
/* */
|
||||||
|
/* CALLS */
|
||||||
|
/* */
|
||||||
|
/* None */
|
||||||
|
/* */
|
||||||
|
/* CALLED BY */
|
||||||
|
/* */
|
||||||
|
/* _tx_initialize_kernel_enter ThreadX entry function */
|
||||||
|
/* _tx_thread_system_return Return to system from thread */
|
||||||
|
/* _tx_thread_context_restore Restore thread's context */
|
||||||
|
/* */
|
||||||
|
/* RELEASE HISTORY */
|
||||||
|
/* */
|
||||||
|
/* DATE NAME DESCRIPTION */
|
||||||
|
/* */
|
||||||
|
/* 03-08-2023 Scott Larson Initial Version 6.2.1 */
|
||||||
|
/* */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* VOID _tx_thread_schedule(VOID)
|
||||||
|
{ */
|
||||||
|
.global _tx_thread_schedule
|
||||||
|
_tx_thread_schedule:
|
||||||
|
|
||||||
|
/* Enable interrupts. */
|
||||||
|
csrsi mstatus, 0x08 // Enable interrupts
|
||||||
|
csrr t4, mhartid // Pickup the current hart ID
|
||||||
|
slli t4, t4, LOG_REGBYTES // Build per-hart byte offset
|
||||||
|
|
||||||
|
/* Wait for a thread to execute. */
|
||||||
|
/* do
|
||||||
|
{ */
|
||||||
|
|
||||||
|
la t0, _tx_thread_execute_ptr // Pickup address of execute ptr
|
||||||
|
add t0, t0, t4 // Select this hart's execute slot
|
||||||
|
_tx_thread_schedule_loop:
|
||||||
|
#ifdef TX_ENABLE_WFI
|
||||||
|
csrci mstatus, 0x08 // Lockout interrupts
|
||||||
|
LOAD t1, 0(t0) // Pickup next thread to execute
|
||||||
|
bnez t1, _tx_thread_schedule_thread // If non-NULL, continue
|
||||||
|
csrsi mstatus, 0x08 // Enable interrupts
|
||||||
|
wfi // Wait for interrupt
|
||||||
|
j _tx_thread_schedule_loop // Keep looking for a thread
|
||||||
|
#else
|
||||||
|
csrci mstatus, 0x08 // Lockout interrupts
|
||||||
|
LOAD t1, 0(t0) // Pickup next thread to execute
|
||||||
|
bnez t1, _tx_thread_schedule_thread // If non-NULL, continue
|
||||||
|
csrsi mstatus, 0x08 // Enable interrupts
|
||||||
|
j _tx_thread_schedule_loop // Keep looking for a thread
|
||||||
|
#endif
|
||||||
|
_tx_thread_schedule_thread:
|
||||||
|
|
||||||
|
/* Atomically claim the thread's ready token so only one hart can
|
||||||
|
dispatch this TCB at a time. */
|
||||||
|
addi t2, t1, TX_THREAD_SMP_LOCK_READY_BIT_OFFSET // Pickup lock/ready-bit address
|
||||||
|
amoswap.w.aq t3, x0, (t2) // Clear it and fetch prior state
|
||||||
|
beqz t3, _tx_thread_schedule // If not ready, retry scheduling
|
||||||
|
|
||||||
|
/* }
|
||||||
|
while(_tx_thread_execute_ptr == TX_NULL); */
|
||||||
|
|
||||||
|
/* Publish the current thread pointer for this hart, then re-check the
|
||||||
|
execute slot to avoid missing a concurrent execute-pointer update. */
|
||||||
|
|
||||||
|
la t5, _tx_thread_current_ptr // Pickup current thread pointer address
|
||||||
|
add t5, t5, t4 // Select this hart's current slot
|
||||||
|
STORE t1, 0(t5) // Set current thread pointer
|
||||||
|
fence rw, rw // Publish current thread pointer before re-check
|
||||||
|
LOAD t6, 0(t0) // Reload execute pointer for this hart
|
||||||
|
beq t1, t6, _execute_pointer_did_not_change // If unchanged, continue
|
||||||
|
|
||||||
|
/* Another core changed the execute slot after this hart claimed the
|
||||||
|
thread but before current-thread publication completed. Roll back
|
||||||
|
and restart so the new selection is not missed. */
|
||||||
|
STORE x0, 0(t5) // Clear current thread pointer
|
||||||
|
li t3, 1 // Rebuild ready token
|
||||||
|
amoswap.w.rl x0, t3, (t2) // Restore ready token with release ordering
|
||||||
|
j _tx_thread_schedule_loop // Restart scheduling
|
||||||
|
|
||||||
|
_execute_pointer_did_not_change:
|
||||||
|
|
||||||
|
/* Increment the run count for this thread. */
|
||||||
|
/* _tx_thread_current_ptr -> tx_thread_run_count++; */
|
||||||
|
|
||||||
|
LOAD t2, 1*REGBYTES(t1) // Pickup run count
|
||||||
|
LOAD t3, 6*REGBYTES(t1) // Pickup time slice value
|
||||||
|
addi t2, t2, 1 // Increment run count
|
||||||
|
STORE t2, 1*REGBYTES(t1) // Store new run count
|
||||||
|
|
||||||
|
/* Setup time-slice for this hart, if present. */
|
||||||
|
|
||||||
|
la t2, _tx_timer_time_slice // Pickup time-slice variable address
|
||||||
|
add t2, t2, t4 // Select this hart's time-slice slot
|
||||||
|
|
||||||
|
/* Switch to the thread's stack. */
|
||||||
|
/* SP = _tx_thread_execute_ptr -> tx_thread_stack_ptr; */
|
||||||
|
|
||||||
|
LOAD sp, 2*REGBYTES(t1) // Switch to thread's stack
|
||||||
|
STORE t3, 0(t2) // Store new time-slice
|
||||||
|
|
||||||
|
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||||
|
|
||||||
|
call _tx_execution_thread_enter // Call the thread execution enter function
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Determine if an interrupt frame or a synchronous task suspension frame
|
||||||
|
is present. */
|
||||||
|
|
||||||
|
LOAD t2, 0(sp) // Pickup stack type
|
||||||
|
beqz t2, _tx_thread_synch_return // If 0, solicited thread return
|
||||||
|
|
||||||
|
/* Determine if floating point registers need to be recovered. */
|
||||||
|
|
||||||
|
#if defined(__riscv_float_abi_single)
|
||||||
|
flw f0, 31*REGBYTES(sp) // Recover ft0
|
||||||
|
flw f1, 32*REGBYTES(sp) // Recover ft1
|
||||||
|
flw f2, 33*REGBYTES(sp) // Recover ft2
|
||||||
|
flw f3, 34*REGBYTES(sp) // Recover ft3
|
||||||
|
flw f4, 35*REGBYTES(sp) // Recover ft4
|
||||||
|
flw f5, 36*REGBYTES(sp) // Recover ft5
|
||||||
|
flw f6, 37*REGBYTES(sp) // Recover ft6
|
||||||
|
flw f7, 38*REGBYTES(sp) // Recover ft7
|
||||||
|
flw f8, 39*REGBYTES(sp) // Recover fs0
|
||||||
|
flw f9, 40*REGBYTES(sp) // Recover fs1
|
||||||
|
flw f10,41*REGBYTES(sp) // Recover fa0
|
||||||
|
flw f11,42*REGBYTES(sp) // Recover fa1
|
||||||
|
flw f12,43*REGBYTES(sp) // Recover fa2
|
||||||
|
flw f13,44*REGBYTES(sp) // Recover fa3
|
||||||
|
flw f14,45*REGBYTES(sp) // Recover fa4
|
||||||
|
flw f15,46*REGBYTES(sp) // Recover fa5
|
||||||
|
flw f16,47*REGBYTES(sp) // Recover fa6
|
||||||
|
flw f17,48*REGBYTES(sp) // Recover fa7
|
||||||
|
flw f18,49*REGBYTES(sp) // Recover fs2
|
||||||
|
flw f19,50*REGBYTES(sp) // Recover fs3
|
||||||
|
flw f20,51*REGBYTES(sp) // Recover fs4
|
||||||
|
flw f21,52*REGBYTES(sp) // Recover fs5
|
||||||
|
flw f22,53*REGBYTES(sp) // Recover fs6
|
||||||
|
flw f23,54*REGBYTES(sp) // Recover fs7
|
||||||
|
flw f24,55*REGBYTES(sp) // Recover fs8
|
||||||
|
flw f25,56*REGBYTES(sp) // Recover fs9
|
||||||
|
flw f26,57*REGBYTES(sp) // Recover fs10
|
||||||
|
flw f27,58*REGBYTES(sp) // Recover fs11
|
||||||
|
flw f28,59*REGBYTES(sp) // Recover ft8
|
||||||
|
flw f29,60*REGBYTES(sp) // Recover ft9
|
||||||
|
flw f30,61*REGBYTES(sp) // Recover ft10
|
||||||
|
flw f31,62*REGBYTES(sp) // Recover ft11
|
||||||
|
LOAD t0, 63*REGBYTES(sp) // Recover fcsr
|
||||||
|
csrw fcsr, t0 //
|
||||||
|
#elif defined(__riscv_float_abi_double)
|
||||||
|
fld f0, 31*REGBYTES(sp) // Recover ft0
|
||||||
|
fld f1, 32*REGBYTES(sp) // Recover ft1
|
||||||
|
fld f2, 33*REGBYTES(sp) // Recover ft2
|
||||||
|
fld f3, 34*REGBYTES(sp) // Recover ft3
|
||||||
|
fld f4, 35*REGBYTES(sp) // Recover ft4
|
||||||
|
fld f5, 36*REGBYTES(sp) // Recover ft5
|
||||||
|
fld f6, 37*REGBYTES(sp) // Recover ft6
|
||||||
|
fld f7, 38*REGBYTES(sp) // Recover ft7
|
||||||
|
fld f8, 39*REGBYTES(sp) // Recover fs0
|
||||||
|
fld f9, 40*REGBYTES(sp) // Recover fs1
|
||||||
|
fld f10,41*REGBYTES(sp) // Recover fa0
|
||||||
|
fld f11,42*REGBYTES(sp) // Recover fa1
|
||||||
|
fld f12,43*REGBYTES(sp) // Recover fa2
|
||||||
|
fld f13,44*REGBYTES(sp) // Recover fa3
|
||||||
|
fld f14,45*REGBYTES(sp) // Recover fa4
|
||||||
|
fld f15,46*REGBYTES(sp) // Recover fa5
|
||||||
|
fld f16,47*REGBYTES(sp) // Recover fa6
|
||||||
|
fld f17,48*REGBYTES(sp) // Recover fa7
|
||||||
|
fld f18,49*REGBYTES(sp) // Recover fs2
|
||||||
|
fld f19,50*REGBYTES(sp) // Recover fs3
|
||||||
|
fld f20,51*REGBYTES(sp) // Recover fs4
|
||||||
|
fld f21,52*REGBYTES(sp) // Recover fs5
|
||||||
|
fld f22,53*REGBYTES(sp) // Recover fs6
|
||||||
|
fld f23,54*REGBYTES(sp) // Recover fs7
|
||||||
|
fld f24,55*REGBYTES(sp) // Recover fs8
|
||||||
|
fld f25,56*REGBYTES(sp) // Recover fs9
|
||||||
|
fld f26,57*REGBYTES(sp) // Recover fs10
|
||||||
|
fld f27,58*REGBYTES(sp) // Recover fs11
|
||||||
|
fld f28,59*REGBYTES(sp) // Recover ft8
|
||||||
|
fld f29,60*REGBYTES(sp) // Recover ft9
|
||||||
|
fld f30,61*REGBYTES(sp) // Recover ft10
|
||||||
|
fld f31,62*REGBYTES(sp) // Recover ft11
|
||||||
|
LOAD t0, 63*REGBYTES(sp) // Recover fcsr
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Recover standard registers. */
|
||||||
|
|
||||||
|
LOAD t0, 30*REGBYTES(sp) // Recover mepc
|
||||||
|
csrw mepc, t0 // Store mepc
|
||||||
|
li t0, 0x1880 // Prepare MPIP
|
||||||
|
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
|
||||||
|
li t1, 1<<13
|
||||||
|
or t0, t1, t0
|
||||||
|
#endif
|
||||||
|
csrw mstatus, t0 // Enable MPIP
|
||||||
|
|
||||||
|
LOAD x1, 28*REGBYTES(sp) // Recover RA
|
||||||
|
LOAD x5, 19*REGBYTES(sp) // Recover t0
|
||||||
|
LOAD x6, 18*REGBYTES(sp) // Recover t1
|
||||||
|
LOAD x7, 17*REGBYTES(sp) // Recover t2
|
||||||
|
LOAD x8, 12*REGBYTES(sp) // Recover s0
|
||||||
|
LOAD x9, 11*REGBYTES(sp) // Recover s1
|
||||||
|
LOAD x10, 27*REGBYTES(sp) // Recover a0
|
||||||
|
LOAD x11, 26*REGBYTES(sp) // Recover a1
|
||||||
|
LOAD x12, 25*REGBYTES(sp) // Recover a2
|
||||||
|
LOAD x13, 24*REGBYTES(sp) // Recover a3
|
||||||
|
LOAD x14, 23*REGBYTES(sp) // Recover a4
|
||||||
|
LOAD x15, 22*REGBYTES(sp) // Recover a5
|
||||||
|
LOAD x16, 21*REGBYTES(sp) // Recover a6
|
||||||
|
LOAD x17, 20*REGBYTES(sp) // Recover a7
|
||||||
|
LOAD x18, 10*REGBYTES(sp) // Recover s2
|
||||||
|
LOAD x19, 9*REGBYTES(sp) // Recover s3
|
||||||
|
LOAD x20, 8*REGBYTES(sp) // Recover s4
|
||||||
|
LOAD x21, 7*REGBYTES(sp) // Recover s5
|
||||||
|
LOAD x22, 6*REGBYTES(sp) // Recover s6
|
||||||
|
LOAD x23, 5*REGBYTES(sp) // Recover s7
|
||||||
|
LOAD x24, 4*REGBYTES(sp) // Recover s8
|
||||||
|
LOAD x25, 3*REGBYTES(sp) // Recover s9
|
||||||
|
LOAD x26, 2*REGBYTES(sp) // Recover s10
|
||||||
|
LOAD x27, 1*REGBYTES(sp) // Recover s11
|
||||||
|
LOAD x28, 16*REGBYTES(sp) // Recover t3
|
||||||
|
LOAD x29, 15*REGBYTES(sp) // Recover t4
|
||||||
|
LOAD x30, 14*REGBYTES(sp) // Recover t5
|
||||||
|
LOAD x31, 13*REGBYTES(sp) // Recover t6
|
||||||
|
|
||||||
|
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
|
||||||
|
addi sp, sp, 65*REGBYTES // Recover stack frame - with floating point registers
|
||||||
|
#else
|
||||||
|
addi sp, sp, 32*REGBYTES // Recover stack frame - without floating point registers
|
||||||
|
#endif
|
||||||
|
mret // Return to point of interrupt
|
||||||
|
|
||||||
|
_tx_thread_synch_return:
|
||||||
|
|
||||||
|
#if defined(__riscv_float_abi_single)
|
||||||
|
flw f8, 15*REGBYTES(sp) // Recover fs0
|
||||||
|
flw f9, 16*REGBYTES(sp) // Recover fs1
|
||||||
|
flw f18,17*REGBYTES(sp) // Recover fs2
|
||||||
|
flw f19,18*REGBYTES(sp) // Recover fs3
|
||||||
|
flw f20,19*REGBYTES(sp) // Recover fs4
|
||||||
|
flw f21,20*REGBYTES(sp) // Recover fs5
|
||||||
|
flw f22,21*REGBYTES(sp) // Recover fs6
|
||||||
|
flw f23,22*REGBYTES(sp) // Recover fs7
|
||||||
|
flw f24,23*REGBYTES(sp) // Recover fs8
|
||||||
|
flw f25,24*REGBYTES(sp) // Recover fs9
|
||||||
|
flw f26,25*REGBYTES(sp) // Recover fs10
|
||||||
|
flw f27,26*REGBYTES(sp) // Recover fs11
|
||||||
|
LOAD t0, 27*REGBYTES(sp) // Recover fcsr
|
||||||
|
csrw fcsr, t0 //
|
||||||
|
#elif defined(__riscv_float_abi_double)
|
||||||
|
fld f8, 15*REGBYTES(sp) // Recover fs0
|
||||||
|
fld f9, 16*REGBYTES(sp) // Recover fs1
|
||||||
|
fld f18,17*REGBYTES(sp) // Recover fs2
|
||||||
|
fld f19,18*REGBYTES(sp) // Recover fs3
|
||||||
|
fld f20,19*REGBYTES(sp) // Recover fs4
|
||||||
|
fld f21,20*REGBYTES(sp) // Recover fs5
|
||||||
|
fld f22,21*REGBYTES(sp) // Recover fs6
|
||||||
|
fld f23,22*REGBYTES(sp) // Recover fs7
|
||||||
|
fld f24,23*REGBYTES(sp) // Recover fs8
|
||||||
|
fld f25,24*REGBYTES(sp) // Recover fs9
|
||||||
|
fld f26,25*REGBYTES(sp) // Recover fs10
|
||||||
|
fld f27,26*REGBYTES(sp) // Recover fs11
|
||||||
|
LOAD t0, 27*REGBYTES(sp) // Recover fcsr
|
||||||
|
csrw fcsr, t0 //
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Recover standard preserved registers. */
|
||||||
|
/* Recover standard registers. */
|
||||||
|
|
||||||
|
LOAD x1, 13*REGBYTES(sp) // Recover RA
|
||||||
|
LOAD x8, 12*REGBYTES(sp) // Recover s0
|
||||||
|
LOAD x9, 11*REGBYTES(sp) // Recover s1
|
||||||
|
LOAD x18, 10*REGBYTES(sp) // Recover s2
|
||||||
|
LOAD x19, 9*REGBYTES(sp) // Recover s3
|
||||||
|
LOAD x20, 8*REGBYTES(sp) // Recover s4
|
||||||
|
LOAD x21, 7*REGBYTES(sp) // Recover s5
|
||||||
|
LOAD x22, 6*REGBYTES(sp) // Recover s6
|
||||||
|
LOAD x23, 5*REGBYTES(sp) // Recover s7
|
||||||
|
LOAD x24, 4*REGBYTES(sp) // Recover s8
|
||||||
|
LOAD x25, 3*REGBYTES(sp) // Recover s9
|
||||||
|
LOAD x26, 2*REGBYTES(sp) // Recover s10
|
||||||
|
LOAD x27, 1*REGBYTES(sp) // Recover s11
|
||||||
|
LOAD t0, 14*REGBYTES(sp) // Recover mstatus
|
||||||
|
csrw mstatus, t0 // Store mstatus, enables interrupt
|
||||||
|
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
|
||||||
|
addi sp, sp, 29*REGBYTES // Recover stack frame
|
||||||
|
#else
|
||||||
|
addi sp, sp, 16*REGBYTES // Recover stack frame
|
||||||
|
#endif
|
||||||
|
ret // Return to thread
|
||||||
|
|
||||||
|
/* } */
|
||||||
12
port/threadx_smp/src/tx_thread_smp_core_get.S
Normal file
12
port/threadx_smp/src/tx_thread_smp_core_get.S
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#include "tx_port.h"
|
||||||
|
|
||||||
|
.section .text
|
||||||
|
.align 2
|
||||||
|
|
||||||
|
.global _tx_thread_smp_core_get
|
||||||
|
.type _tx_thread_smp_core_get, @function
|
||||||
|
_tx_thread_smp_core_get:
|
||||||
|
csrr a0, mhartid // Pickup the current hart ID
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
6
port/threadx_smp/src/tx_thread_smp_core_preempt.c
Normal file
6
port/threadx_smp/src/tx_thread_smp_core_preempt.c
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#include <aclint_ipi.h>
|
||||||
|
#include <tx_port.h>
|
||||||
|
void _tx_thread_smp_core_preempt(UINT target_core)
|
||||||
|
{
|
||||||
|
send_ipi(target_core);
|
||||||
|
}
|
||||||
14
port/threadx_smp/src/tx_thread_smp_current_state_get.S
Normal file
14
port/threadx_smp/src/tx_thread_smp_current_state_get.S
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#include "tx_port.h"
|
||||||
|
|
||||||
|
.section .text
|
||||||
|
.align 2
|
||||||
|
|
||||||
|
.global _tx_thread_smp_current_state_get
|
||||||
|
.type _tx_thread_smp_current_state_get, @function
|
||||||
|
_tx_thread_smp_current_state_get:
|
||||||
|
csrr t0, mhartid // Pickup current hart ID
|
||||||
|
la t1, _tx_thread_system_state // Base of per-hart system-state array
|
||||||
|
slli t0, t0, 2 // Build offset into array
|
||||||
|
add t1, t1, t0 // Select this hart's slot
|
||||||
|
LWU a0, 0(t1) // Return current system state
|
||||||
|
ret
|
||||||
19
port/threadx_smp/src/tx_thread_smp_current_thread_get.S
Normal file
19
port/threadx_smp/src/tx_thread_smp_current_thread_get.S
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#include "tx_port.h"
|
||||||
|
|
||||||
|
.section .text
|
||||||
|
.align 2
|
||||||
|
|
||||||
|
.global _tx_thread_smp_current_thread_get
|
||||||
|
.type _tx_thread_smp_current_thread_get, @function
|
||||||
|
_tx_thread_smp_current_thread_get:
|
||||||
|
csrr t0, mstatus // Pickup current interrupt posture
|
||||||
|
csrci mstatus, 0x08 // Lockout interrupts
|
||||||
|
|
||||||
|
csrr t1, mhartid // Pickup current hart ID
|
||||||
|
la t2, _tx_thread_current_ptr // Base of current-thread pointer array
|
||||||
|
slli t1, t1, LOG_REGBYTES // Build per-hart byte offset
|
||||||
|
add t2, t2, t1 // Select this hart's slot
|
||||||
|
LOAD a0, 0(t2) // Pickup current thread pointer
|
||||||
|
|
||||||
|
csrw mstatus, t0 // Restore interrupt posture
|
||||||
|
ret
|
||||||
71
port/threadx_smp/src/tx_thread_smp_initialize_wait.S
Normal file
71
port/threadx_smp/src/tx_thread_smp_initialize_wait.S
Normal file
@@ -0,0 +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:
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
|
||||||
|
/* Build per-hart offsets for ULONG and pointer arrays. */
|
||||||
|
slli t1, t0, 2 // ULONG array offset
|
||||||
|
slli t2, t0, LOG_REGBYTES // Pointer array offset
|
||||||
|
|
||||||
|
/* 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
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#include "tx_port.h"
|
||||||
|
|
||||||
|
.section .text
|
||||||
|
.align 2
|
||||||
|
|
||||||
|
.global _tx_thread_smp_low_level_initialize
|
||||||
|
.type _tx_thread_smp_low_level_initialize, @function
|
||||||
|
_tx_thread_smp_low_level_initialize:
|
||||||
|
ret
|
||||||
50
port/threadx_smp/src/tx_thread_smp_protect.S
Normal file
50
port/threadx_smp/src/tx_thread_smp_protect.S
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
#include "tx_port.h"
|
||||||
|
|
||||||
|
.section .text
|
||||||
|
.align 2
|
||||||
|
|
||||||
|
.global _tx_thread_smp_protect
|
||||||
|
.type _tx_thread_smp_protect, @function
|
||||||
|
_tx_thread_smp_protect:
|
||||||
|
|
||||||
|
/* Disable interrupts so we don't get preempted. */
|
||||||
|
csrr a0, mstatus // Pickup current interrupt posture
|
||||||
|
csrci mstatus, 0x08 // Lockout interrupts
|
||||||
|
|
||||||
|
/* Pickup the hart ID. */
|
||||||
|
csrr t2, mhartid // Pickup the current hart ID
|
||||||
|
|
||||||
|
/* Build address to protection structure. */
|
||||||
|
la t1, _tx_thread_smp_protection
|
||||||
|
|
||||||
|
/* If this hart already owns protection, just nest the count. */
|
||||||
|
LWU t3, 4(t1) // Pickup owning hart
|
||||||
|
beq t3, t2, _owned // Already owned by this hart
|
||||||
|
|
||||||
|
/* Try to get the protection. */
|
||||||
|
LWU t4, 0(t1) // Pickup protection flag
|
||||||
|
beqz t4, _get_protection // If clear, try to claim it
|
||||||
|
|
||||||
|
/* Protection is busy. Restore interrupts and retry. */
|
||||||
|
csrw mstatus, a0 // Restore interrupts
|
||||||
|
j _tx_thread_smp_protect // Restart the protection attempt
|
||||||
|
|
||||||
|
_get_protection:
|
||||||
|
li t4, 1 // Build lock value
|
||||||
|
amoswap.w.aq t5, t4, (t1) // Attempt to get protection
|
||||||
|
bnez t5, _protection_busy // If old value != 0, retry
|
||||||
|
|
||||||
|
_got_protection:
|
||||||
|
fence rw, rw // Ensure lock acquisition is visible
|
||||||
|
sw t2, 4(t1) // Save owning hart
|
||||||
|
|
||||||
|
_owned:
|
||||||
|
LWU t5, 8(t1) // Pickup ownership count
|
||||||
|
addi t5, t5, 1 // Increment ownership count
|
||||||
|
sw t5, 8(t1) // Store ownership count
|
||||||
|
fence rw, rw // Publish owner/count before return
|
||||||
|
ret
|
||||||
|
|
||||||
|
_protection_busy:
|
||||||
|
csrw mstatus, a0 // Restore interrupts
|
||||||
|
j _tx_thread_smp_protect // Restart the protection attempt
|
||||||
43
port/threadx_smp/src/tx_thread_smp_unprotect.S
Normal file
43
port/threadx_smp/src/tx_thread_smp_unprotect.S
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#include "tx_port.h"
|
||||||
|
|
||||||
|
.section .text
|
||||||
|
.align 2
|
||||||
|
|
||||||
|
.global _tx_thread_smp_unprotect
|
||||||
|
.type _tx_thread_smp_unprotect, @function
|
||||||
|
_tx_thread_smp_unprotect:
|
||||||
|
|
||||||
|
/* Lockout interrupts while protection state is updated. */
|
||||||
|
csrci mstatus, 0x08 // Lockout interrupts
|
||||||
|
|
||||||
|
/* Pickup the current hart ID. */
|
||||||
|
csrr t1, mhartid // Pickup hart ID
|
||||||
|
|
||||||
|
/* Build address of protection structure. */
|
||||||
|
la t2, _tx_thread_smp_protection
|
||||||
|
|
||||||
|
/* Only the owning hart may release the protection. */
|
||||||
|
LWU t3, 4(t2) // Pickup owning hart
|
||||||
|
bne t1, t3, _still_protected // Not owner, skip release
|
||||||
|
|
||||||
|
/* Pickup and decrement the protection count. */
|
||||||
|
LWU t3, 8(t2) // Pickup protection count
|
||||||
|
beqz t3, _still_protected // Already cleared
|
||||||
|
addi t3, t3, -1 // Decrement protection count
|
||||||
|
sw t3, 8(t2) // Store new count
|
||||||
|
bnez t3, _still_protected // Still nested, stay protected
|
||||||
|
|
||||||
|
/* If preemption is disabled, keep protection in force. */
|
||||||
|
la t4, _tx_thread_preempt_disable
|
||||||
|
LWU t5, 0(t4) // Pickup preempt disable
|
||||||
|
bnez t5, _still_protected // Skip protection release
|
||||||
|
|
||||||
|
/* Release the protection. */
|
||||||
|
li t3, -1 // Invalid owner value
|
||||||
|
sw t3, 4(t2) // Mark owning hart invalid
|
||||||
|
fence rw, rw // Ensure shared accesses complete
|
||||||
|
amoswap.w.rl x0, x0, (t2) // Release protection flag
|
||||||
|
|
||||||
|
_still_protected:
|
||||||
|
csrw mstatus, a0 // Restore interrupt posture
|
||||||
|
ret
|
||||||
229
port/threadx_smp/src/tx_thread_stack_build.S
Normal file
229
port/threadx_smp/src/tx_thread_stack_build.S
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* 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 */
|
||||||
|
/** */
|
||||||
|
/** Thread */
|
||||||
|
/** */
|
||||||
|
/**************************************************************************/
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#include "tx_port.h"
|
||||||
|
|
||||||
|
.section .text
|
||||||
|
/**************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* FUNCTION RELEASE */
|
||||||
|
/* */
|
||||||
|
/* _tx_thread_stack_build RISC-V64/GNU */
|
||||||
|
/* 6.2.1 */
|
||||||
|
/* AUTHOR */
|
||||||
|
/* */
|
||||||
|
/* Scott Larson, Microsoft Corporation */
|
||||||
|
/* */
|
||||||
|
/* DESCRIPTION */
|
||||||
|
/* */
|
||||||
|
/* This function builds a stack frame on the supplied thread's stack. */
|
||||||
|
/* The stack frame results in a fake interrupt return to the supplied */
|
||||||
|
/* function pointer. */
|
||||||
|
/* */
|
||||||
|
/* INPUT */
|
||||||
|
/* */
|
||||||
|
/* thread_ptr Pointer to thread control blk */
|
||||||
|
/* function_ptr Pointer to return function */
|
||||||
|
/* */
|
||||||
|
/* OUTPUT */
|
||||||
|
/* */
|
||||||
|
/* None */
|
||||||
|
/* */
|
||||||
|
/* CALLS */
|
||||||
|
/* */
|
||||||
|
/* None */
|
||||||
|
/* */
|
||||||
|
/* CALLED BY */
|
||||||
|
/* */
|
||||||
|
/* _tx_thread_create Create thread service */
|
||||||
|
/* */
|
||||||
|
/* RELEASE HISTORY */
|
||||||
|
/* */
|
||||||
|
/* DATE NAME DESCRIPTION */
|
||||||
|
/* */
|
||||||
|
/* 03-08-2023 Scott Larson Initial Version 6.2.1 */
|
||||||
|
/* */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID))
|
||||||
|
{ */
|
||||||
|
.global _tx_thread_stack_build
|
||||||
|
_tx_thread_stack_build:
|
||||||
|
|
||||||
|
/* Build a fake interrupt frame. The form of the fake interrupt stack
|
||||||
|
on the RISC-V should look like the following after it is built:
|
||||||
|
Reg Index
|
||||||
|
Stack Top: 1 0 Interrupt stack frame type
|
||||||
|
x27 1 Initial s11
|
||||||
|
x26 2 Initial s10
|
||||||
|
x25 3 Initial s9
|
||||||
|
x24 4 Initial s8
|
||||||
|
x23 5 Initial s7
|
||||||
|
x22 6 Initial s6
|
||||||
|
x21 7 Initial s5
|
||||||
|
x20 8 Initial s4
|
||||||
|
x19 9 Initial s3
|
||||||
|
x18 10 Initial s2
|
||||||
|
x9 11 Initial s1
|
||||||
|
x8 12 Initial s0
|
||||||
|
x31 13 Initial t6
|
||||||
|
x30 14 Initial t5
|
||||||
|
x29 15 Initial t4
|
||||||
|
x28 16 Initial t3
|
||||||
|
x7 17 Initial t2
|
||||||
|
x6 18 Initial t1
|
||||||
|
x5 19 Initial t0
|
||||||
|
x17 20 Initial a7
|
||||||
|
x16 21 Initial a6
|
||||||
|
x15 22 Initial a5
|
||||||
|
x14 23 Initial a4
|
||||||
|
x13 24 Initial a3
|
||||||
|
x12 25 Initial a2
|
||||||
|
x11 26 Initial a1
|
||||||
|
x10 27 Initial a0
|
||||||
|
x1 28 Initial ra
|
||||||
|
-- 29 reserved
|
||||||
|
mepc 30 Initial mepc
|
||||||
|
If floating point support:
|
||||||
|
f0 31 Inital ft0
|
||||||
|
f1 32 Inital ft1
|
||||||
|
f2 33 Inital ft2
|
||||||
|
f3 34 Inital ft3
|
||||||
|
f4 35 Inital ft4
|
||||||
|
f5 36 Inital ft5
|
||||||
|
f6 37 Inital ft6
|
||||||
|
f7 38 Inital ft7
|
||||||
|
f8 39 Inital fs0
|
||||||
|
f9 40 Inital fs1
|
||||||
|
f10 41 Inital fa0
|
||||||
|
f11 42 Inital fa1
|
||||||
|
f12 43 Inital fa2
|
||||||
|
f13 44 Inital fa3
|
||||||
|
f14 45 Inital fa4
|
||||||
|
f15 46 Inital fa5
|
||||||
|
f16 47 Inital fa6
|
||||||
|
f17 48 Inital fa7
|
||||||
|
f18 49 Inital fs2
|
||||||
|
f19 50 Inital fs3
|
||||||
|
f20 51 Inital fs4
|
||||||
|
f21 52 Inital fs5
|
||||||
|
f22 53 Inital fs6
|
||||||
|
f23 54 Inital fs7
|
||||||
|
f24 55 Inital fs8
|
||||||
|
f25 56 Inital fs9
|
||||||
|
f26 57 Inital fs10
|
||||||
|
f27 58 Inital fs11
|
||||||
|
f28 59 Inital ft8
|
||||||
|
f29 60 Inital ft9
|
||||||
|
f30 61 Inital ft10
|
||||||
|
f31 62 Inital ft11
|
||||||
|
fscr 63 Inital fscr
|
||||||
|
|
||||||
|
Stack Bottom: (higher memory address) */
|
||||||
|
|
||||||
|
LOAD t0, TX_THREAD_STACK_END_OFFSET(a0) // Pickup end of stack area
|
||||||
|
andi t0, t0, -4*REGBYTES // Ensure alignment (16-byte for RV32 & 32-byte for RV64)
|
||||||
|
|
||||||
|
/* Actually build the stack frame. */
|
||||||
|
|
||||||
|
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
|
||||||
|
addi t0, t0, -65*REGBYTES
|
||||||
|
#else
|
||||||
|
addi t0, t0, -32*REGBYTES // Allocate space for the stack frame
|
||||||
|
#endif
|
||||||
|
li t1, 1 // Build stack type
|
||||||
|
STORE t1, 0*REGBYTES(t0) // Place stack type on the top
|
||||||
|
STORE x0, 1*REGBYTES(t0) // Initial s11
|
||||||
|
STORE x0, 2*REGBYTES(t0) // Initial s10
|
||||||
|
STORE x0, 3*REGBYTES(t0) // Initial s9
|
||||||
|
STORE x0, 4*REGBYTES(t0) // Initial s8
|
||||||
|
STORE x0, 5*REGBYTES(t0) // Initial s7
|
||||||
|
STORE x0, 6*REGBYTES(t0) // Initial s6
|
||||||
|
STORE x0, 7*REGBYTES(t0) // Initial s5
|
||||||
|
STORE x0, 8*REGBYTES(t0) // Initial s4
|
||||||
|
STORE x0, 9*REGBYTES(t0) // Initial s3
|
||||||
|
STORE x0, 10*REGBYTES(t0) // Initial s2
|
||||||
|
STORE x0, 11*REGBYTES(t0) // Initial s1
|
||||||
|
STORE x0, 12*REGBYTES(t0) // Initial s0
|
||||||
|
STORE x0, 13*REGBYTES(t0) // Initial t6
|
||||||
|
STORE x0, 14*REGBYTES(t0) // Initial t5
|
||||||
|
STORE x0, 15*REGBYTES(t0) // Initial t4
|
||||||
|
STORE x0, 16*REGBYTES(t0) // Initial t3
|
||||||
|
STORE x0, 17*REGBYTES(t0) // Initial t2
|
||||||
|
STORE x0, 18*REGBYTES(t0) // Initial t1
|
||||||
|
STORE x0, 19*REGBYTES(t0) // Initial t0
|
||||||
|
STORE x0, 20*REGBYTES(t0) // Initial a7
|
||||||
|
STORE x0, 21*REGBYTES(t0) // Initial a6
|
||||||
|
STORE x0, 22*REGBYTES(t0) // Initial a5
|
||||||
|
STORE x0, 23*REGBYTES(t0) // Initial a4
|
||||||
|
STORE x0, 24*REGBYTES(t0) // Initial a3
|
||||||
|
STORE x0, 25*REGBYTES(t0) // Initial a2
|
||||||
|
STORE x0, 26*REGBYTES(t0) // Initial a1
|
||||||
|
STORE x0, 27*REGBYTES(t0) // Initial a0
|
||||||
|
STORE x0, 28*REGBYTES(t0) // Initial ra
|
||||||
|
STORE a1, 30*REGBYTES(t0) // Initial mepc
|
||||||
|
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
|
||||||
|
STORE x0, 31*REGBYTES(t0) // Inital ft0
|
||||||
|
STORE x0, 32*REGBYTES(t0) // Inital ft1
|
||||||
|
STORE x0, 33*REGBYTES(t0) // Inital ft2
|
||||||
|
STORE x0, 34*REGBYTES(t0) // Inital ft3
|
||||||
|
STORE x0, 35*REGBYTES(t0) // Inital ft4
|
||||||
|
STORE x0, 36*REGBYTES(t0) // Inital ft5
|
||||||
|
STORE x0, 37*REGBYTES(t0) // Inital ft6
|
||||||
|
STORE x0, 38*REGBYTES(t0) // Inital ft7
|
||||||
|
STORE x0, 39*REGBYTES(t0) // Inital fs0
|
||||||
|
STORE x0, 40*REGBYTES(t0) // Inital fs1
|
||||||
|
STORE x0, 41*REGBYTES(t0) // Inital fa0
|
||||||
|
STORE x0, 42*REGBYTES(t0) // Inital fa1
|
||||||
|
STORE x0, 43*REGBYTES(t0) // Inital fa2
|
||||||
|
STORE x0, 44*REGBYTES(t0) // Inital fa3
|
||||||
|
STORE x0, 45*REGBYTES(t0) // Inital fa4
|
||||||
|
STORE x0, 46*REGBYTES(t0) // Inital fa5
|
||||||
|
STORE x0, 47*REGBYTES(t0) // Inital fa6
|
||||||
|
STORE x0, 48*REGBYTES(t0) // Inital fa7
|
||||||
|
STORE x0, 49*REGBYTES(t0) // Inital fs2
|
||||||
|
STORE x0, 50*REGBYTES(t0) // Inital fs3
|
||||||
|
STORE x0, 51*REGBYTES(t0) // Inital fs4
|
||||||
|
STORE x0, 52*REGBYTES(t0) // Inital fs5
|
||||||
|
STORE x0, 53*REGBYTES(t0) // Inital fs6
|
||||||
|
STORE x0, 54*REGBYTES(t0) // Inital fs7
|
||||||
|
STORE x0, 55*REGBYTES(t0) // Inital fs8
|
||||||
|
STORE x0, 56*REGBYTES(t0) // Inital fs9
|
||||||
|
STORE x0, 57*REGBYTES(t0) // Inital fs10
|
||||||
|
STORE x0, 58*REGBYTES(t0) // Inital fs11
|
||||||
|
STORE x0, 59*REGBYTES(t0) // Inital ft8
|
||||||
|
STORE x0, 60*REGBYTES(t0) // Inital ft9
|
||||||
|
STORE x0, 61*REGBYTES(t0) // Inital ft10
|
||||||
|
STORE x0, 62*REGBYTES(t0) // Inital ft11
|
||||||
|
csrr a1, fcsr // Read fcsr and use it for initial value for each thread
|
||||||
|
STORE a1, 63*REGBYTES(t0) // Initial fscr
|
||||||
|
STORE x0, 64*REGBYTES(t0) // Reserved word (0)
|
||||||
|
#else
|
||||||
|
STORE x0, 31*REGBYTES(t0) // Reserved word (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Setup stack pointer. */
|
||||||
|
/* thread_ptr -> tx_thread_stack_ptr = t0; */
|
||||||
|
|
||||||
|
STORE t0, 2*REGBYTES(a0) // Save stack pointer in thread's
|
||||||
|
addi t1, x0, 1 // Build ready flag
|
||||||
|
sw t1, TX_THREAD_SMP_LOCK_READY_BIT_OFFSET(a0) // Set ready flag
|
||||||
|
ret // control block and return
|
||||||
|
/* } */
|
||||||
198
port/threadx_smp/src/tx_thread_system_return.S
Normal file
198
port/threadx_smp/src/tx_thread_system_return.S
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* 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 */
|
||||||
|
/** */
|
||||||
|
/** Thread */
|
||||||
|
/** */
|
||||||
|
/**************************************************************************/
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#include "tx_port.h"
|
||||||
|
|
||||||
|
.section .text
|
||||||
|
/**************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* FUNCTION RELEASE */
|
||||||
|
/* */
|
||||||
|
/* _tx_thread_system_return RISC-V64/GNU */
|
||||||
|
/* 6.2.1 */
|
||||||
|
/* AUTHOR */
|
||||||
|
/* */
|
||||||
|
/* Scott Larson, Microsoft Corporation */
|
||||||
|
/* */
|
||||||
|
/* 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 */
|
||||||
|
/* */
|
||||||
|
/* 03-08-2023 Scott Larson Initial Version 6.2.1 */
|
||||||
|
/* */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* VOID _tx_thread_system_return(VOID)
|
||||||
|
{ */
|
||||||
|
.global _tx_thread_system_return
|
||||||
|
_tx_thread_system_return:
|
||||||
|
|
||||||
|
/* Save minimal context on the stack. */
|
||||||
|
|
||||||
|
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
|
||||||
|
addi sp, sp, -29*REGBYTES // Allocate space on the stack - with floating point enabled
|
||||||
|
#else
|
||||||
|
addi sp, sp, -16*REGBYTES // Allocate space on the stack - without floating point enabled
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Store floating point preserved registers. */
|
||||||
|
#if defined(__riscv_float_abi_single)
|
||||||
|
fsw f8, 15*REGBYTES(sp) // Store fs0
|
||||||
|
fsw f9, 16*REGBYTES(sp) // Store fs1
|
||||||
|
fsw f18, 17*REGBYTES(sp) // Store fs2
|
||||||
|
fsw f19, 18*REGBYTES(sp) // Store fs3
|
||||||
|
fsw f20, 19*REGBYTES(sp) // Store fs4
|
||||||
|
fsw f21, 20*REGBYTES(sp) // Store fs5
|
||||||
|
fsw f22, 21*REGBYTES(sp) // Store fs6
|
||||||
|
fsw f23, 22*REGBYTES(sp) // Store fs7
|
||||||
|
fsw f24, 23*REGBYTES(sp) // Store fs8
|
||||||
|
fsw f25, 24*REGBYTES(sp) // Store fs9
|
||||||
|
fsw f26, 25*REGBYTES(sp) // Store fs10
|
||||||
|
fsw f27, 26*REGBYTES(sp) // Store fs11
|
||||||
|
csrr t0, fcsr
|
||||||
|
STORE t0, 27*REGBYTES(sp) // Store fcsr
|
||||||
|
#elif defined(__riscv_float_abi_double)
|
||||||
|
fsd f8, 15*REGBYTES(sp) // Store fs0
|
||||||
|
fsd f9, 16*REGBYTES(sp) // Store fs1
|
||||||
|
fsd f18, 17*REGBYTES(sp) // Store fs2
|
||||||
|
fsd f19, 18*REGBYTES(sp) // Store fs3
|
||||||
|
fsd f20, 19*REGBYTES(sp) // Store fs4
|
||||||
|
fsd f21, 20*REGBYTES(sp) // Store fs5
|
||||||
|
fsd f22, 21*REGBYTES(sp) // Store fs6
|
||||||
|
fsd f23, 22*REGBYTES(sp) // Store fs7
|
||||||
|
fsd f24, 23*REGBYTES(sp) // Store fs8
|
||||||
|
fsd f25, 24*REGBYTES(sp) // Store fs9
|
||||||
|
fsd f26, 25*REGBYTES(sp) // Store fs10
|
||||||
|
fsd f27, 26*REGBYTES(sp) // Store fs11
|
||||||
|
csrr t0, fcsr
|
||||||
|
STORE t0, 27*REGBYTES(sp) // Store fcsr
|
||||||
|
#endif
|
||||||
|
|
||||||
|
STORE x0, 0(sp) // Solicited stack type
|
||||||
|
STORE x1, 13*REGBYTES(sp) // Save RA
|
||||||
|
STORE x8, 12*REGBYTES(sp) // Save s0
|
||||||
|
STORE x9, 11*REGBYTES(sp) // Save s1
|
||||||
|
STORE x18, 10*REGBYTES(sp) // Save s2
|
||||||
|
STORE x19, 9*REGBYTES(sp) // Save s3
|
||||||
|
STORE x20, 8*REGBYTES(sp) // Save s4
|
||||||
|
STORE x21, 7*REGBYTES(sp) // Save s5
|
||||||
|
STORE x22, 6*REGBYTES(sp) // Save s6
|
||||||
|
STORE x23, 5*REGBYTES(sp) // Save s7
|
||||||
|
STORE x24, 4*REGBYTES(sp) // Save s8
|
||||||
|
STORE x25, 3*REGBYTES(sp) // Save s9
|
||||||
|
STORE x26, 2*REGBYTES(sp) // Save s10
|
||||||
|
STORE x27, 1*REGBYTES(sp) // Save s11
|
||||||
|
csrr t0, mstatus // Pickup mstatus
|
||||||
|
STORE t0, 14*REGBYTES(sp) // Save mstatus
|
||||||
|
|
||||||
|
|
||||||
|
/* Lockout interrupts. - will be enabled in _tx_thread_schedule */
|
||||||
|
|
||||||
|
csrci mstatus, 0xF
|
||||||
|
|
||||||
|
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||||
|
|
||||||
|
call _tx_execution_thread_exit // Call the thread execution exit function
|
||||||
|
#endif
|
||||||
|
|
||||||
|
csrr t5, mhartid // Pickup current hart ID
|
||||||
|
slli t6, t5, 2 // Build per-hart ULONG offset
|
||||||
|
slli t5, t5, LOG_REGBYTES // Build per-hart pointer offset
|
||||||
|
|
||||||
|
la t0, _tx_thread_current_ptr // Pickup base of current-thread array
|
||||||
|
add t0, t0, t5 // Select this hart's current-thread slot
|
||||||
|
LOAD t1, 0(t0) // Pickup current thread pointer
|
||||||
|
la t2, _tx_thread_system_stack_ptr // Pickup base of system-stack array
|
||||||
|
|
||||||
|
/* Save current stack and switch to system stack. */
|
||||||
|
/* _tx_thread_current_ptr -> tx_thread_stack_ptr = SP;
|
||||||
|
SP = _tx_thread_system_stack_ptr; */
|
||||||
|
|
||||||
|
STORE sp, 2*REGBYTES(t1) // Save stack pointer
|
||||||
|
add t2, t2, t5 // Select this hart's system-stack slot
|
||||||
|
LOAD 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 base of time-slice array
|
||||||
|
add t4, t4, t6 // Select this hart's time-slice slot
|
||||||
|
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, TX_THREAD_TIME_SLICE_OFFSET(t1) // Save current time-slice for thread
|
||||||
|
sw x0, 0(t4) // Clear time-slice variable
|
||||||
|
|
||||||
|
/* } */
|
||||||
|
_tx_thread_dont_save_ts:
|
||||||
|
|
||||||
|
/* Clear the current thread pointer. */
|
||||||
|
/* _tx_thread_current_ptr = TX_NULL; */
|
||||||
|
|
||||||
|
STORE x0, 0(t0) // Clear current thread pointer
|
||||||
|
|
||||||
|
/* Make the thread runnable again before returning to the scheduler. */
|
||||||
|
fence rw, rw // Publish current-thread clear before ready token
|
||||||
|
addi t3, t1, TX_THREAD_SMP_LOCK_READY_BIT_OFFSET // Pickup lock/ready-bit address
|
||||||
|
li t4, 1 // Build ready token
|
||||||
|
amoswap.w.rl x0, t4, (t3) // Restore ready token
|
||||||
|
|
||||||
|
/* Clear protection state. */
|
||||||
|
la t3, _tx_thread_preempt_disable // Pickup preempt-disable address
|
||||||
|
sw x0, 0(t3) // Clear preempt disable flag
|
||||||
|
|
||||||
|
la t3, _tx_thread_smp_protection // Pickup protection structure
|
||||||
|
sw x0, 8(t3) // Clear protection count
|
||||||
|
li t4, -1 // Build invalid owner value
|
||||||
|
sw t4, 4(t3) // Invalidate owning hart
|
||||||
|
fence rw, rw // Ensure shared accesses complete before unlock
|
||||||
|
sw x0, 0(t3) // Clear protection in-force flag
|
||||||
|
jr t2 // Return to thread scheduler
|
||||||
|
|
||||||
|
/* } */
|
||||||
129
port/threadx_smp/src/tx_timer_interrupt.c
Normal file
129
port/threadx_smp/src/tx_timer_interrupt.c
Normal 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);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user