12#include "stk_config.h"
14#ifdef _STK_ARCH_RISC_V
64#ifndef STK_RISCV_CLINT_BASE_ADDR
65 #define STK_RISCV_CLINT_BASE_ADDR (0x2000000U)
67#ifndef STK_RISCV_CLINT_MTIMECMP_ADDR
68 #define STK_RISCV_CLINT_MTIMECMP_ADDR (STK_RISCV_CLINT_BASE_ADDR + 0x4000U)
70#ifndef STK_RISCV_CLINT_MTIME_ADDR
71 #define STK_RISCV_CLINT_MTIME_ADDR (STK_RISCV_CLINT_BASE_ADDR + 0xBFF8U)
78#define STK_RISCV_ISR_STACK_SIZE 256U
83#ifndef STK_TIMER_CLOCK_FREQUENCY
84 #define STK_TIMER_CLOCK_FREQUENCY 1000000U
91#ifndef STK_RISCV_ISR_SECTION
92 #define STK_RISCV_ISR_SECTION
99#define STK_RISCV_ISR extern "C" STK_RISCV_ISR_SECTION __attribute__ ((interrupt("machine")))
102#define STK_ASM_EXIT_FROM_HANDLER "mret"
109#ifndef STK_RISCV_CLINT_MTIMECMP_PER_HART
110 #define STK_RISCV_CLINT_MTIMECMP_PER_HART 1
117#ifndef STK_ARCH_GET_CPU_ID
118 #define STK_ARCH_GET_CPU_ID() read_csr(mhartid)
122#if (__riscv_flen == 0)
123 #define STK_RISCV_FPU 0
125 #define STK_RISCV_FPU __riscv_flen
129#define XSTR(s) STR(s)
132#if (__riscv_xlen == 32)
133 #define REGBYTES XSTR(4)
134 #define LREG XSTR(lw)
135 #define SREG XSTR(sw)
136#elif (__riscv_xlen == 64)
137 #define REGBYTES XSTR(8)
138 #define LREG XSTR(ld)
139 #define SREG XSTR(sd)
141 #error Unsupported RISC-V platform!
144#if (STK_RISCV_FPU == 32)
145 #define FREGBYTES XSTR(4)
146 #define FLREG XSTR(flw)
147 #define FSREG XSTR(fsw)
148#elif (STK_RISCV_FPU == 64)
149 #define FREGBYTES XSTR(8)
150 #define FLREG XSTR(fld)
151 #define FSREG XSTR(fsd)
152#elif (STK_RISCV_FPU != 0)
153#error Unsupported FP register count!
157#if (__riscv_32e == 1)
158 #define STK_RISCV_REGISTER_COUNT (15U + (STK_RISCV_FPU != 0U ? 31U : 0U))
160 #define STK_RISCV_REGISTER_COUNT (31U + (STK_RISCV_FPU != 0U ? 31U : 0U))
163#define STK_SERVICE_SLOTS 2U
165#if (__riscv_32e == 1)
166 #define FOFFSET XSTR(68)
167 #if (STK_RISCV_FPU == 0)
168 #define REGSIZE XSTR(((15U + STK_SERVICE_SLOTS) * 4U))
170 #if (STK_RISCV_FPU == 32)
171 #define REGSIZE XSTR((((15U + STK_SERVICE_SLOTS) * 4U) + (31U * 4U)))
172 #elif (STK_RISCV_FPU == 64)
173 #define REGSIZE XSTR((((15U + STK_SERVICE_SLOTS) * 4U) + (31U * 8U)))
176#elif (__riscv_xlen == 32)
177 #define FOFFSET XSTR(132)
178 #if (STK_RISCV_FPU == 0)
179 #define REGSIZE XSTR(((31U + STK_SERVICE_SLOTS) * 4U))
181 #if (STK_RISCV_FPU == 32)
182 #define REGSIZE XSTR((((31U + STK_SERVICE_SLOTS) * 4U) + (31U * 4U)))
183 #elif (STK_RISCV_FPU == 64)
184 #define REGSIZE XSTR((((31U + STK_SERVICE_SLOTS) * 4U) + (31U * 8U)))
187#elif (__riscv_xlen == 64)
188 #define FOFFSET XSTR(264)
189 #if (STK_RISCV_FPU == 0)
190 #define REGSIZE XSTR(((31U + STK_SERVICE_SLOTS) * 8U))
192 #if (STK_RISCV_FPU == 32)
193 #define REGSIZE XSTR((((31U + STK_SERVICE_SLOTS) * 8U) + (31U * 4U)))
194 #elif (STK_RISCV_FPU == 64)
195 #define REGSIZE XSTR((((31U + STK_SERVICE_SLOTS) * 8U) + (31U * 8U)))
200#if (__riscv_xlen == 32)
201 #define REGBYTES_LOG2 "2"
202#elif (__riscv_xlen == 64)
203 #define REGBYTES_LOG2 "3"
212#ifndef STK_SYSTICK_HANDLER
213 #define STK_SYSTICK_HANDLER riscv_mtvec_mti
222#ifndef STK_SVC_HANDLER
223 #define STK_SVC_HANDLER riscv_mtvec_exception
233#ifndef STK_MSI_HANDLER
234 #define STK_MSI_HANDLER riscv_mtvec_msi
264#if (STK_RISCV_FPU != 0)
281#if (__riscv_32e != 1)
299#if (STK_RISCV_FPU != 0)
312 __asm
volatile(
"fence rw, rw" :::
"memory");
319#ifdef __riscv_zifencei
320 __asm
volatile(
"fence.i" :::
"memory");
322 __sync_synchronize();
330 __asm
volatile(
"wfi");
338 __asm
volatile(
"ecall");
352 __asm
volatile(
"csrrci zero, mstatus, %0"
362 __asm
volatile(
"csrrsi zero, mstatus, %0"
374 __asm
volatile(
"csrrci %0, mstatus, %1"
387 __asm
volatile(
"csrrs zero, mstatus, %0"
405 clear_csr(mie, MIP_MTIP);
412#ifdef _STK_RISCV_USE_PENDSV
413 clear_csr(mie, MIP_MSIP);
431 return STK_TIMER_CLOCK_FREQUENCY;
441#if ( __riscv_xlen > 32)
444 const Word mtime_base = STK_RISCV_CLINT_MTIME_ADDR;
454 while (hi != (*mtime_hi));
456 return (
static_cast<uint64_t
>(hi) << 32) | lo;
465#if STK_RISCV_CLINT_MTIMECMP_PER_HART
466 const uint8_t hart = HW_GetHartId();
468 const uint8_t hart = 0U;
471#if (__riscv_xlen == 64)
474 const Word mtimecmp_base = STK_RISCV_CLINT_MTIMECMP_ADDR + (hart *
sizeof(uint64_t));
479 STK_ASSERT(((uintptr_t)mtimecmp_lo & (4U - 1U)) == 0U);
480 STK_ASSERT(((uintptr_t)mtimecmp_hi & (4U - 1U)) == 0U);
484 (*mtimecmp_hi) = ~0U;
486 (*mtimecmp_lo) = (uint32_t)(time_next & 0xFFFFFFFFU);
487 (*mtimecmp_hi) = (uint32_t)(time_next >> 32);
498 return HW_GetMtime() - since;
505 __asm
volatile(
"csrci mcountinhibit, 0x1");
513 uint32_t high, low, check;
516 __asm
volatile(
"csrr %0, mcycleh" :
"=r"(high));
517 __asm
volatile(
"csrr %0, mcycle" :
"=r"(low));
518 __asm
volatile(
"csrr %0, mcycleh" :
"=r"(check));
520 while (high != check);
522 return (
static_cast<Cycles>(high) << 32) | low;
530 __asm
volatile(
"mv %0, sp"
542 ses = HW_EnterCriticalSection();
556 HW_ExitCriticalSection(ses);
578 return !__atomic_test_and_set(&lock, __ATOMIC_ACQUIRE);
599 uint32_t timeout = 0xFFFFFFU;
600 while (!HW_SpinLockTryLock(lock))
636 __asm
volatile(
"fence rw, w" :::
"memory");
638 __atomic_clear(&lock, __ATOMIC_RELEASE);
645#ifdef _STK_RISCV_USE_PENDSV
647 volatile uint32_t *msip = (
volatile uint32_t *)(STK_RISCV_CLINT_BASE_ADDR);
656#ifndef _STK_SYSTEM_CORE_CLOCK_EXTERNAL
662static volatile bool s_StkRiscvCsuLock =
false;
675#ifdef _STK_RISCV_USE_PENDSV
743#if (STK_RISCV_FPU != 0)
762__attribute__((naked))
763int32_t SaveJmp(JmpFrame &)
767 SREG
" ra, 0*" REGBYTES
"(a0) \n"
768 SREG
" sp, 1*" REGBYTES
"(a0) \n"
769 SREG
" s0, 2*" REGBYTES
"(a0) \n"
770 SREG
" s1, 3*" REGBYTES
"(a0) \n"
771 SREG
" s2, 4*" REGBYTES
"(a0) \n"
772 SREG
" s3, 5*" REGBYTES
"(a0) \n"
773 SREG
" s4, 6*" REGBYTES
"(a0) \n"
774 SREG
" s5, 7*" REGBYTES
"(a0) \n"
775 SREG
" s6, 8*" REGBYTES
"(a0) \n"
776 SREG
" s7, 9*" REGBYTES
"(a0) \n"
777 SREG
" s8, 10*" REGBYTES
"(a0) \n"
778 SREG
" s9, 11*" REGBYTES
"(a0) \n"
779 SREG
" s10, 12*" REGBYTES
"(a0) \n"
780 SREG
" s11, 13*" REGBYTES
"(a0) \n"
781#if (STK_RISCV_FPU != 0)
783 SREG
" t0, 14*" REGBYTES
"(a0) \n"
807__attribute__((naked, noreturn))
808void RestoreJmp(JmpFrame &, int32_t )
812 LREG
" ra, 0*" REGBYTES
"(a0) \n"
813 LREG
" sp, 1*" REGBYTES
"(a0) \n"
814 LREG
" s0, 2*" REGBYTES
"(a0) \n"
815 LREG
" s1, 3*" REGBYTES
"(a0) \n"
816 LREG
" s2, 4*" REGBYTES
"(a0) \n"
817 LREG
" s3, 5*" REGBYTES
"(a0) \n"
818 LREG
" s4, 6*" REGBYTES
"(a0) \n"
819 LREG
" s5, 7*" REGBYTES
"(a0) \n"
820 LREG
" s6, 8*" REGBYTES
"(a0) \n"
821 LREG
" s7, 9*" REGBYTES
"(a0) \n"
822 LREG
" s8, 10*" REGBYTES
"(a0) \n"
823 LREG
" s9, 11*" REGBYTES
"(a0) \n"
824 LREG
" s10, 12*" REGBYTES
"(a0) \n"
825 LREG
" s11, 13*" REGBYTES
"(a0) \n"
826#if (STK_RISCV_FPU != 0)
827 LREG
" t0, 14*" REGBYTES
"(a0) \n"
838#if STK_SUBMICORSECOND_PRECISION_TIMER
842 static HiResClockCYCLE *GetInstance()
846 static HiResClockCYCLE clock;
852 return HW_GetCycleCounter();
855 uint32_t GetFrequency()
857 return HW_CoreClockFrequency();
860typedef HiResClockCYCLE HiResClockImpl;
865 static HiResClockMTIME *GetInstance()
869 static HiResClockMTIME clock;
875 return HW_GetMtime();
878 uint32_t GetFrequency()
880 return HW_MtimeClockFrequency();
883typedef HiResClockMTIME HiResClockImpl;
889 explicit Context() : PlatformContext(), m_stack_main(), m_stack_isr(), m_stack_isr_mem(),
890 m_exit_buf(), m_overrider(nullptr), m_specific(nullptr), m_tick_period(0), m_last_mtime(0ULL),
891 #if STK_TICKLESS_IDLE
894 m_csu(0), m_csu_nesting(0),
895 m_starting(false), m_started(false), m_exiting(false)
904 void Initialize(IPlatform::IEventHandler *handler, IKernelService *service, Stack *exit_trap,
905 uint32_t resolution_us)
override
907 PlatformContext::Initialize(handler, service, exit_trap, resolution_us);
911 StackMemoryWrapper<STK_RISCV_ISR_STACK_SIZE> stack_isr_mem(&m_stack_isr_mem);
912 m_stack_isr.SP = InitStackMemory(&stack_isr_mem);
924 m_tick_period = ConvertTimeUsToClockCycles(STK_TIMER_CLOCK_FREQUENCY, resolution_us);
931 #if STK_SUBMICORSECOND_PRECISION_TIMER
932 HW_EnableCycleCounter();
940 HW_CriticalSectionStart(cs);
942 #if STK_TICKLESS_IDLE
946 if (m_handler->OnTick(m_stack_idle, m_stack_active
947 #
if STK_TICKLESS_IDLE
958 const uint8_t hart = HW_GetHartId();
959 s_StkRiscvStackActive[hart] = m_stack_active;
960 #ifdef _STK_RISCV_USE_PENDSV
961 s_StkRiscvStackIdle[hart] = m_stack_idle;
964 HW_ScheduleContextSwitch(hart);
967 #if STK_TICKLESS_IDLE
968 m_sleep_ticks = ticks;
971 HW_CriticalSectionEnd(cs);
978 HW_CriticalSectionStart(current_ses);
980 if (m_csu_nesting == 0U)
983 HW_SpinLockLock(s_StkRiscvCsuLock);
993 STK_KERNEL_PANIC(KERNEL_PANIC_CS_NESTING_OVERFLOW);
1002 if (m_csu_nesting == 0U)
1005 const Word ses_to_restore = m_csu;
1008 HW_SpinLockUnlock(s_StkRiscvCsuLock);
1011 HW_CriticalSectionEnd(ses_to_restore);
1015 uint64_t GetSleepTicksPrev()
1017 #if STK_TICKLESS_IDLE
1018 const uint64_t ticks = (
static_cast<uint64_t
>(m_sleep_ticks) *
static_cast<uint64_t
>(m_tick_period));
1020 const uint64_t ticks = (1U *
static_cast<uint64_t
>(m_tick_period));
1025 uint64_t GetTimeNow(uint64_t &error)
1027 const uint64_t mtime_now = HW_GetMtime();
1028 error = (mtime_now - m_last_mtime) - GetSleepTicksPrev();
1032 void RearmTimer(
const uint64_t mtime_now,
const uint64_t error)
1034 #if STK_TICKLESS_IDLE
1036 STK_ASSERT((
static_cast<uint64_t
>(m_sleep_ticks) *
static_cast<uint64_t
>(m_tick_period)) <= (UINT64_MAX - mtime_now));
1037 const uint64_t next_time = (
static_cast<uint64_t
>(m_sleep_ticks) *
static_cast<uint64_t
>(m_tick_period));
1039 const uint64_t next_time = (1U *
static_cast<uint64_t
>(m_tick_period));
1041 HW_SetMtimecmp(mtime_now + next_time - error);
1042 m_last_mtime = mtime_now;
1050 uint64_t error = 0U;
1051 const uint64_t mtime_now = GetTimeNow(error);
1052 __stk_compiler_barrier();
1063 RearmTimer(mtime_now, error);
1066 void StartTickTimer(Timeout elapsed_ticks)
1068 #if STK_TICKLESS_IDLE
1070 m_sleep_ticks = elapsed_ticks;
1076 m_last_mtime = HW_GetMtime();
1077 HW_SetMtimecmp(m_last_mtime + m_tick_period);
1080 set_csr(mie, MIP_MTIP);
1083 void OnSleepOverride()
1085 #if STK_TICKLESS_IDLE
1086 const Timeout sleep_ticks = m_sleep_ticks;
1088 const Timeout sleep_ticks = 1;
1091 if (!m_overrider->OnSleep(sleep_ticks))
1093 HW_EnterSleepMode();
1097#if STK_TLS && !STK_INLINE_TLS
1100 hw::CriticalSection::ScopedLock cs_;
1104 return m_stack_active->tls;
1107 void SetTls(Word tp)
1109 hw::CriticalSection::ScopedLock cs_;
1113 m_stack_active->tls = tp;
1120#if STK_TICKLESS_IDLE
1122 void Resume(Timeout elapsed_ticks);
1125 typedef IPlatform::IEventOverrider eovrd_t;
1126 typedef PlatformRiscV::ISpecificEventHandler sehndl_t;
1127 typedef StackMemoryWrapper<STK_RISCV_ISR_STACK_SIZE>::MemoryType isrmem_t;
1131 isrmem_t m_stack_isr_mem;
1132 JmpFrame m_exit_buf;
1133 eovrd_t *m_overrider;
1134 sehndl_t *m_specific;
1135 uint32_t m_tick_period;
1136 uint64_t m_last_mtime;
1137#if STK_TICKLESS_IDLE
1141 uint8_t m_csu_nesting;
1144 volatile bool m_exiting;
1150#ifdef _STK_RISCV_USE_PENDSV
1152 HW_CriticalSectionStart(cs);
1156 HW_CriticalSectionEnd(cs);
1173 HW_DisableInterrupts();
1183#define STK_ASM_SAVE_CONTEXT_BASE\
1184 SREG " x1, 2*" REGBYTES "(sp) \n"\
1187 SREG " x4, 5*" REGBYTES "(sp) \n"\
1188 SREG " x5, 6*" REGBYTES "(sp) \n"\
1189 SREG " x6, 7*" REGBYTES "(sp) \n"\
1190 SREG " x7, 8*" REGBYTES "(sp) \n"\
1191 SREG " x8, 9*" REGBYTES "(sp) \n"\
1192 SREG " x9, 10*" REGBYTES "(sp) \n"\
1193 SREG " x10, 11*" REGBYTES "(sp) \n"\
1194 SREG " x11, 12*" REGBYTES "(sp) \n"\
1195 SREG " x12, 13*" REGBYTES "(sp) \n"\
1196 SREG " x13, 14*" REGBYTES "(sp) \n"\
1197 SREG " x14, 15*" REGBYTES "(sp) \n"\
1198 SREG " x15, 16*" REGBYTES "(sp) \n"
1200#if (__riscv_32e != 1)
1201#define STK_ASM_SAVE_CONTEXT_RV32I_EXT\
1202 SREG " x16, 17*" REGBYTES "(sp) \n"\
1203 SREG " x17, 18*" REGBYTES "(sp) \n"\
1204 SREG " x18, 19*" REGBYTES "(sp) \n"\
1205 SREG " x19, 20*" REGBYTES "(sp) \n"\
1206 SREG " x20, 21*" REGBYTES "(sp) \n"\
1207 SREG " x21, 22*" REGBYTES "(sp) \n"\
1208 SREG " x22, 23*" REGBYTES "(sp) \n"\
1209 SREG " x23, 24*" REGBYTES "(sp) \n"\
1210 SREG " x24, 25*" REGBYTES "(sp) \n"\
1211 SREG " x25, 26*" REGBYTES "(sp) \n"\
1212 SREG " x26, 27*" REGBYTES "(sp) \n"\
1213 SREG " x27, 28*" REGBYTES "(sp) \n"\
1214 SREG " x28, 29*" REGBYTES "(sp) \n"\
1215 SREG " x29, 30*" REGBYTES "(sp) \n"\
1216 SREG " x30, 31*" REGBYTES "(sp) \n"\
1217 SREG " x31, 32*" REGBYTES "(sp) \n"
1219#define STK_ASM_SAVE_CONTEXT_RV32I_EXT
1222#if (STK_RISCV_FPU != 0)
1223#define STK_ASM_SAVE_CONTEXT_FP\
1224 FSREG " f0, " FOFFSET "+0*" FREGBYTES "(sp) \n"\
1225 FSREG " f1, " FOFFSET "+1*" FREGBYTES "(sp) \n"\
1226 FSREG " f2, " FOFFSET "+2*" FREGBYTES "(sp) \n"\
1227 FSREG " f3, " FOFFSET "+3*" FREGBYTES "(sp) \n"\
1228 FSREG " f4, " FOFFSET "+4*" FREGBYTES "(sp) \n"\
1229 FSREG " f5, " FOFFSET "+5*" FREGBYTES "(sp) \n"\
1230 FSREG " f6, " FOFFSET "+6*" FREGBYTES "(sp) \n"\
1231 FSREG " f7, " FOFFSET "+7*" FREGBYTES "(sp) \n"\
1232 FSREG " f8, " FOFFSET "+8*" FREGBYTES "(sp) \n"\
1233 FSREG " f9, " FOFFSET "+9*" FREGBYTES "(sp) \n"\
1234 FSREG " f10, " FOFFSET "+10*" FREGBYTES "(sp) \n"\
1235 FSREG " f11, " FOFFSET "+11*" FREGBYTES "(sp) \n"\
1236 FSREG " f12, " FOFFSET "+12*" FREGBYTES "(sp) \n"\
1237 FSREG " f13, " FOFFSET "+13*" FREGBYTES "(sp) \n"\
1238 FSREG " f14, " FOFFSET "+14*" FREGBYTES "(sp) \n"\
1239 FSREG " f15, " FOFFSET "+15*" FREGBYTES "(sp) \n"\
1240 FSREG " f16, " FOFFSET "+16*" FREGBYTES "(sp) \n"\
1241 FSREG " f17, " FOFFSET "+17*" FREGBYTES "(sp) \n"\
1242 FSREG " f18, " FOFFSET "+18*" FREGBYTES "(sp) \n"\
1243 FSREG " f19, " FOFFSET "+19*" FREGBYTES "(sp) \n"\
1244 FSREG " f20, " FOFFSET "+20*" FREGBYTES "(sp) \n"\
1245 FSREG " f21, " FOFFSET "+21*" FREGBYTES "(sp) \n"\
1246 FSREG " f22, " FOFFSET "+22*" FREGBYTES "(sp) \n"\
1247 FSREG " f23, " FOFFSET "+23*" FREGBYTES "(sp) \n"\
1248 FSREG " f24, " FOFFSET "+24*" FREGBYTES "(sp) \n"\
1249 FSREG " f25, " FOFFSET "+25*" FREGBYTES "(sp) \n"\
1250 FSREG " f26, " FOFFSET "+26*" FREGBYTES "(sp) \n"\
1251 FSREG " f27, " FOFFSET "+27*" FREGBYTES "(sp) \n"\
1252 FSREG " f28, " FOFFSET "+28*" FREGBYTES "(sp) \n"\
1253 FSREG " f29, " FOFFSET "+29*" FREGBYTES "(sp) \n"\
1254 FSREG " f30, " FOFFSET "+30*" FREGBYTES "(sp) \n"\
1255 FSREG " f31, " FOFFSET "+31*" FREGBYTES "(sp) \n"
1257#define STK_ASM_SAVE_CONTEXT_FP
1260#define STK_ASM_SAVE_CONTEXT_PC_STATUS\
1262 "csrr t1, mstatus \n"\
1263 SREG " t0, 0*" REGBYTES "(sp) \n"\
1264 SREG " t1, 1*" REGBYTES "(sp) \n"
1266#if (STK_RISCV_FPU != 0)
1267#define STK_ASM_SAVE_CONTEXT_FRCSR\
1269 SREG " t0, 4*" REGBYTES "(sp) \n"
1271#define STK_ASM_SAVE_CONTEXT_FRCSR
1274#define STK_ASM_SAVE_CONTEXT\
1275 "addi sp, sp, -" REGSIZE " \n" \
1276 STK_ASM_SAVE_CONTEXT_BASE\
1277 STK_ASM_SAVE_CONTEXT_RV32I_EXT\
1278 STK_ASM_SAVE_CONTEXT_FP\
1279 STK_ASM_SAVE_CONTEXT_PC_STATUS\
1280 STK_ASM_SAVE_CONTEXT_FRCSR
1282#define STK_ASM_LOAD_CONTEXT_BASE\
1283 LREG " x1, 2*" REGBYTES "(sp) \n"\
1286 LREG " x4, 5*" REGBYTES "(sp) \n"\
1287 LREG " x5, 6*" REGBYTES "(sp) \n"\
1288 LREG " x6, 7*" REGBYTES "(sp) \n"\
1289 LREG " x7, 8*" REGBYTES "(sp) \n"\
1290 LREG " x8, 9*" REGBYTES "(sp) \n"\
1291 LREG " x9, 10*" REGBYTES "(sp) \n"\
1292 LREG " x10, 11*" REGBYTES "(sp) \n"\
1293 LREG " x11, 12*" REGBYTES "(sp) \n"\
1294 LREG " x12, 13*" REGBYTES "(sp) \n"\
1295 LREG " x13, 14*" REGBYTES "(sp) \n"\
1296 LREG " x14, 15*" REGBYTES "(sp) \n"\
1297 LREG " x15, 16*" REGBYTES "(sp) \n"
1299#if (__riscv_32e != 1)
1300#define STK_ASM_LOAD_CONTEXT_RV32I_EXT\
1301 LREG " x16, 17*" REGBYTES "(sp) \n"\
1302 LREG " x17, 18*" REGBYTES "(sp) \n"\
1303 LREG " x18, 19*" REGBYTES "(sp) \n"\
1304 LREG " x19, 20*" REGBYTES "(sp) \n"\
1305 LREG " x20, 21*" REGBYTES "(sp) \n"\
1306 LREG " x21, 22*" REGBYTES "(sp) \n"\
1307 LREG " x22, 23*" REGBYTES "(sp) \n"\
1308 LREG " x23, 24*" REGBYTES "(sp) \n"\
1309 LREG " x24, 25*" REGBYTES "(sp) \n"\
1310 LREG " x25, 26*" REGBYTES "(sp) \n"\
1311 LREG " x26, 27*" REGBYTES "(sp) \n"\
1312 LREG " x27, 28*" REGBYTES "(sp) \n"\
1313 LREG " x28, 29*" REGBYTES "(sp) \n"\
1314 LREG " x29, 30*" REGBYTES "(sp) \n"\
1315 LREG " x30, 31*" REGBYTES "(sp) \n"\
1316 LREG " x31, 32*" REGBYTES "(sp) \n"
1318#define STK_ASM_LOAD_CONTEXT_RV32I_EXT
1321#if (STK_RISCV_FPU != 0)
1322#define STK_ASM_LOAD_CONTEXT_FP\
1323 FLREG " f0, " FOFFSET "+0*" FREGBYTES "(sp) \n"\
1324 FLREG " f1, " FOFFSET "+1*" FREGBYTES "(sp) \n"\
1325 FLREG " f2, " FOFFSET "+2*" FREGBYTES "(sp) \n"\
1326 FLREG " f3, " FOFFSET "+3*" FREGBYTES "(sp) \n"\
1327 FLREG " f4, " FOFFSET "+4*" FREGBYTES "(sp) \n"\
1328 FLREG " f5, " FOFFSET "+5*" FREGBYTES "(sp) \n"\
1329 FLREG " f6, " FOFFSET "+6*" FREGBYTES "(sp) \n"\
1330 FLREG " f7, " FOFFSET "+7*" FREGBYTES "(sp) \n"\
1331 FLREG " f8, " FOFFSET "+8*" FREGBYTES "(sp) \n"\
1332 FLREG " f9, " FOFFSET "+9*" FREGBYTES "(sp) \n"\
1333 FLREG " f10, " FOFFSET "+10*" FREGBYTES "(sp) \n"\
1334 FLREG " f11, " FOFFSET "+11*" FREGBYTES "(sp) \n"\
1335 FLREG " f12, " FOFFSET "+12*" FREGBYTES "(sp) \n"\
1336 FLREG " f13, " FOFFSET "+13*" FREGBYTES "(sp) \n"\
1337 FLREG " f14, " FOFFSET "+14*" FREGBYTES "(sp) \n"\
1338 FLREG " f15, " FOFFSET "+15*" FREGBYTES "(sp) \n"\
1339 FLREG " f16, " FOFFSET "+16*" FREGBYTES "(sp) \n"\
1340 FLREG " f17, " FOFFSET "+17*" FREGBYTES "(sp) \n"\
1341 FLREG " f18, " FOFFSET "+18*" FREGBYTES "(sp) \n"\
1342 FLREG " f19, " FOFFSET "+19*" FREGBYTES "(sp) \n"\
1343 FLREG " f20, " FOFFSET "+20*" FREGBYTES "(sp) \n"\
1344 FLREG " f21, " FOFFSET "+21*" FREGBYTES "(sp) \n"\
1345 FLREG " f22, " FOFFSET "+22*" FREGBYTES "(sp) \n"\
1346 FLREG " f23, " FOFFSET "+23*" FREGBYTES "(sp) \n"\
1347 FLREG " f24, " FOFFSET "+24*" FREGBYTES "(sp) \n"\
1348 FLREG " f25, " FOFFSET "+25*" FREGBYTES "(sp) \n"\
1349 FLREG " f26, " FOFFSET "+26*" FREGBYTES "(sp) \n"\
1350 FLREG " f27, " FOFFSET "+27*" FREGBYTES "(sp) \n"\
1351 FLREG " f28, " FOFFSET "+28*" FREGBYTES "(sp) \n"\
1352 FLREG " f29, " FOFFSET "+29*" FREGBYTES "(sp) \n"\
1353 FLREG " f30, " FOFFSET "+30*" FREGBYTES "(sp) \n"\
1354 FLREG " f31, " FOFFSET "+31*" FREGBYTES "(sp) \n"
1356#define STK_ASM_LOAD_CONTEXT_FP
1359#define STK_ASM_LOAD_CONTEXT_PC_STATUS\
1360 LREG " t0, 0*" REGBYTES "(sp) \n"\
1361 LREG " t1, 1*" REGBYTES "(sp) \n"\
1363 "csrw mstatus, t1 \n"
1365#if (STK_RISCV_FPU != 0)
1366#define STK_ASM_LOAD_CONTEXT_FRCSR\
1367 LREG " t0, 4*" REGBYTES "(sp) \n" \
1370#define STK_ASM_LOAD_CONTEXT_FRCSR
1373#define STK_ASM_LOAD_CONTEXT\
1374 STK_ASM_LOAD_CONTEXT_PC_STATUS\
1375 STK_ASM_LOAD_CONTEXT_FRCSR\
1376 STK_ASM_LOAD_CONTEXT_BASE\
1377 STK_ASM_LOAD_CONTEXT_RV32I_EXT\
1378 STK_ASM_LOAD_CONTEXT_FP\
1379 "addi sp, sp, " REGSIZE " \n"
1385 LREG
" sp, 0(t0) \n"
1387 STK_ASM_LOAD_CONTEXT
1388 STK_ASM_EXIT_FROM_HANDLER
" \n"
1392 :
"t0",
"t1",
"a2",
"a3",
"a4",
"a5",
"gp",
"memory");
1397#if (STK_RISCV_FPU != 0)
1401 :
"r"(MSTATUS_FS | MSTATUS_XS)
1408#if (STK_RISCV_FPU != 0)
1447 __asm
volatile(
"csrr %0, mcause" :
"=r"(mcause));
1453 const Word current_sp = HW_GetCallerSP();
1458 const Word isr_stack_top = isr_stack_base + (STK_RISCV_ISR_STACK_SIZE *
sizeof(
Word));
1460 return ((current_sp >= isr_stack_base) && (current_sp < isr_stack_top));
1465 HW_LoadContextAndExit();
1469extern "C" STK_RISCV_ISR_SECTION
__stk_attr_used void TrySwitchContext()
1474#ifdef _STK_RISCV_USE_PENDSV
1475extern "C" STK_RISCV_ISR_SECTION
__stk_attr_naked void STK_SYSTICK_HANDLER()
1479 STK_ASM_SAVE_CONTEXT
1482#if (STK_ARCH_CPU_COUNT > 1)
1483 "csrr t0, mhartid \n"
1484 "la t1, s_StkRiscvSpIsrInt \n"
1485 "slli t0, t0, " REGBYTES_LOG2
" \n"
1487 SREG
" sp, 0(t1) \n"
1489 "la t1, s_StkRiscvSpIsrInt \n"
1490 SREG
" sp, 0(t1) \n"
1494#if (STK_ARCH_CPU_COUNT > 1)
1495 "csrr t0, mhartid \n"
1496 "la t1, s_StkRiscvStackIsr \n"
1497 "slli t0, t0, " REGBYTES_LOG2
" \n"
1499 LREG
" t1, 0(t1) \n"
1501 "la t1, s_StkRiscvStackIsr \n"
1502 LREG
" t1, 0(t1) \n"
1504 LREG
" sp, 0(t1) \n"
1507 "jal ra, TrySwitchContext \n"
1510#if (STK_ARCH_CPU_COUNT > 1)
1511 "csrr t0, mhartid \n"
1512 "la t1, s_StkRiscvSpIsrInt \n"
1513 "slli t0, t0, " REGBYTES_LOG2
" \n"
1515 LREG
" sp, 0(t1) \n"
1517 "la t1, s_StkRiscvSpIsrInt \n"
1518 LREG
" sp, 0(t1) \n"
1522 STK_ASM_LOAD_CONTEXT
1525 STK_ASM_EXIT_FROM_HANDLER
" \n"
1535 STK_ASM_SAVE_CONTEXT
1541#if (STK_ARCH_CPU_COUNT > 1)
1542 "csrr t0, mhartid \n"
1543 "la t1, s_StkRiscvStackIdle \n"
1544 "slli t0, t0, " REGBYTES_LOG2
" \n"
1546 LREG
" t1, 0(t1) \n"
1548 "la t1, s_StkRiscvStackIdle \n"
1549 LREG
" t1, 0(t1) \n"
1551 SREG
" sp, 0(t1) \n"
1554#if (STK_ARCH_CPU_COUNT > 1)
1555 "csrr t0, mhartid \n"
1557 "li t1, %[clint_msip_base] \n"
1560 "li t0, %[clint_msip_base] \n"
1566#if (STK_ARCH_CPU_COUNT > 1)
1567 "csrr t0, mhartid \n"
1568 "la t1, s_StkRiscvStackActive \n"
1569 "slli t0, t0, " REGBYTES_LOG2
" \n"
1571 LREG
" t1, 0(t1) \n"
1573 "la t1, s_StkRiscvStackActive \n"
1574 LREG
" t1, 0(t1) \n"
1576 LREG
" sp, 0(t1) \n"
1579 STK_ASM_LOAD_CONTEXT
1582 STK_ASM_EXIT_FROM_HANDLER
" \n"
1585 : [clint_msip_base]
"i" (STK_RISCV_CLINT_BASE_ADDR)
1629extern "C" STK_RISCV_ISR_SECTION
__stk_attr_naked void STK_SYSTICK_HANDLER()
1633 STK_ASM_SAVE_CONTEXT
1639#if (STK_ARCH_CPU_COUNT > 1)
1640 "csrr t0, mhartid \n"
1641 "la t1, s_StkRiscvStackActive \n"
1642 "slli t0, t0, " REGBYTES_LOG2
" \n"
1644 LREG
" t1, 0(t1) \n"
1646 "la t1, s_StkRiscvStackActive \n"
1647 LREG
" t1, 0(t1) \n"
1649 SREG
" sp, 0(t1) \n"
1652#if (STK_ARCH_CPU_COUNT > 1)
1653 "csrr t0, mhartid \n"
1654 "la t1, s_StkRiscvStackIsr \n"
1655 "slli t0, t0, " REGBYTES_LOG2
" \n"
1657 LREG
" t1, 0(t1) \n"
1659 "la t1, s_StkRiscvStackIsr \n"
1660 LREG
" t1, 0(t1) \n"
1662 LREG
" sp, 0(t1) \n"
1669 "jal ra, TrySwitchContext \n"
1674#if (STK_ARCH_CPU_COUNT > 1)
1675 "csrr t0, mhartid \n"
1676 "la t1, s_StkRiscvStackActive \n"
1677 "slli t0, t0, " REGBYTES_LOG2
" \n"
1679 LREG
" t1, 0(t1) \n"
1681 "la t1, s_StkRiscvStackActive \n"
1682 LREG
" t1, 0(t1) \n"
1684 LREG
" sp, 0(t1) \n"
1687 STK_ASM_LOAD_CONTEXT
1690 STK_ASM_EXIT_FROM_HANDLER
" \n"
1699void Context::OnStart()
1701 const uint8_t hart = HW_GetHartId();
1707 HW_EnableFullFpuAccess();
1713 m_handler->OnStart(m_stack_active);
1716 s_StkRiscvStackIsr[hart] = &m_stack_isr;
1717 s_StkRiscvStackActive[hart] = m_stack_active;
1718#ifdef _STK_RISCV_USE_PENDSV
1719 s_StkRiscvStackIdle[hart] = m_stack_idle;
1730#ifdef _STK_RISCV_USE_PENDSV
1731 set_csr(mie, MIP_MSIP);
1735STK_RISCV_ISR
void STK_SVC_HANDLER()
1737 const Word cause = HW_GetCurrentException();
1749 if (cause == IRQ_M_EXT)
1759 write_csr(mepc, read_csr(mepc) +
sizeof(
Word));
1764 HW_DisableInterrupts();
1790static void OnTaskRun(
ITask *task)
1795static void OnTaskExit()
1798 HW_CriticalSectionStart(cs);
1802 HW_CriticalSectionEnd(cs);
1811static STK_RISCV_ISR_SECTION
void OnSchedulerSleep()
1816#if STK_SEGGER_SYSVIEW
1817 SEGGER_SYSVIEW_OnIdle();
1822 HW_EnterSleepMode();
1826static STK_RISCV_ISR_SECTION
void OnSchedulerSleepOverride()
1831#if STK_SEGGER_SYSVIEW
1832 SEGGER_SYSVIEW_OnIdle();
1841static void OnSchedulerExit()
1852 GetContext().Initialize(event_handler, service, exit_trap, resolution_us);
1855void Context::Start()
1860 SaveJmp(m_exit_buf);
1864 m_handler->OnStop();
1869 HW_EnableFullFpuAccess();
1873 HW_StartScheduler();
1877#if STK_TICKLESS_IDLE
1881 if (resolution == 0U)
1887 HW_DisableInterrupts();
1893 HW_ClearPendingSwitch();
1897 const uint32_t elapsed = HW_GetMtime() - m_last_mtime;
1901 const Timeout elapsed_ticks =
static_cast<Timeout>(elapsed / resolution);
1902 const Timeout sleep_ticks =
Max(m_sleep_ticks - elapsed_ticks,
static_cast<Timeout>(0));
1905 m_handler->OnSuspend(
true);
1907 HW_EnableInterrupts();
1913#if STK_TICKLESS_IDLE
1914void Context::Resume(
Timeout elapsed_ticks)
1916 HW_DisableInterrupts();
1919 m_handler->OnSuspend(
false);
1922 StartTickTimer(elapsed_ticks + 1);
1924 HW_EnableInterrupts();
1937 "TaskFrame size must match REGSIZE: (REGISTER_COUNT + SERVICE_SLOTS) * REGBYTES");
1945 stack->
SP = stack_top - ((STK_RISCV_REGISTER_COUNT + STK_SERVICE_SLOTS) *
sizeof(
Word));
1960 task_frame->MEPC =
hw::PtrToWord(
GetContext().m_overrider !=
nullptr ? &OnSchedulerSleepOverride : &OnSchedulerSleep);
1976 task_frame->MSTATUS = MSTATUS_MPP | MSTATUS_MPIE | (STK_RISCV_FPU != 0U ? (MSTATUS_FS | MSTATUS_XS) : 0U);
1978#if (STK_RISCV_FPU != 0)
1979 task_frame->X3_FSR = 0U;
1983void Context::OnStop()
1989 HW_ClearPendingSwitch();
2004 HW_DisableInterrupts();
2015 return static_cast<Cycles>(HW_GetMtime());
2020 return HW_MtimeClockFrequency();
2025 GetContext().m_handler->OnTaskSwitch(HW_GetCallerSP());
2030 GetContext().m_handler->OnTaskSleep(HW_GetCallerSP(), ticks);
2035 return GetContext().m_handler->OnTaskSleepUntil(HW_GetCallerSP(), timestamp);
2040 return GetContext().m_handler->OnTaskWait(HW_GetCallerSP(), sync_obj, mutex, timeout);
2047 if (HW_IsHandlerMode())
2051 const Word exc = HW_GetCurrentException();
2052 const Word num = (exc & 0x7FFU);
2053 #if (__riscv_xlen > 32)
2054 const Word interrupt_bit = ((exc & (1ULL << (__riscv_xlen - 1))) ? 0x800U : 0);
2056 const Word interrupt_bit = ((exc & (1U << (__riscv_xlen - 1))) ? 0x800U : 0);
2065 result =
GetContext().m_handler->OnGetTid(HW_GetCallerSP());
2073#if STK_TICKLESS_IDLE
2082#if STK_TICKLESS_IDLE
2091 bool is_handled =
false;
2095 is_handled =
GetContext().m_overrider->OnHardFault();
2112 return HW_GetCallerSP();
2141 HW_SpinLockLock(m_lock);
2146 HW_SpinLockUnlock(m_lock);
2151 return HW_SpinLockTryLock(m_lock);
2156 return HW_IsHandlerMode();
2167 return HiResClockImpl::GetInstance()->GetCycles();
2172 const uint32_t freq = HiResClockImpl::GetInstance()->GetFrequency();
2177#if STK_TLS && !STK_INLINE_TLS
2178Word stk::hw::GetTls()
2183void stk::hw::SetTls(
Word tp)
#define STK_SYSTEM_CORE_CLOCK_FREQUENCY
System clock frequency in Hz. Default: 150 MHz.
#define STK_SYSTEM_CORE_CLOCK_VAR
Definition of the system core clock variable holding frequency of the CPU in Hz.
volatile uint32_t SystemCoreClock
System clock frequency in Hz.
Contains common inventory for platform implementation.
#define STK_ARCH_GET_CPU_ID()
Get CPU core id of the caller, e.g. if called while running on core 0 then returned value must be 0.
#define GetContext()
Get platform's context.
Hardware Abstraction Layer (HAL) declarations for the stk::hw namespace.
void STK_PANIC_HANDLER_DEFAULT(stk::EKernelPanicId id)
Default panic handler: disable interrupts, record the id, and spin in a tight loop — a defined,...
#define STK_UNUSED(X)
Explicitly marks a variable as unused to suppress compiler warnings.
#define __stk_attr_used
Marks a symbol as used, preventing the linker from discarding it even if no references are visible (d...
#define __stk_forceinline
Forces compiler to always inline the decorated function, regardless of optimisation level.
#define STK_SLEEP_TRAP_STACK_SIZE
Stack size for the sleep trap in elements of Word (default: STK_STACK_SIZE_MIN).
#define STK_CS_NESTINGS_MAX
Maximum allowable recursion depth for critical section entry (default: 16).
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
#define STK_STACK_SIZE_MIN
Minimum stack size in elements of Word, shared by all stack allocation lower-bound checks.
#define __stk_attr_noinline
Prevents compiler from inlining the decorated function (function prefix).
#define STK_ARCH_CPU_COUNT
Number of physical CPU cores available to the scheduler (default: 1).
#define __stk_attr_naked
Suppresses compiler-generated function prologue and epilogue (function prefix).
#define STK_STATIC_ASSERT_DESC(X, DESC)
Compile-time assertion with a custom error description. Produces a compilation error if X is false.
#define STK_STACK_MEMORY_FILLER
Sentinel value written to the entire stack region at initialization (stack watermark pattern).
#define __stk_attr_noreturn
Declares that function never returns to its caller (function prefix).
#define STK_STATIC_ASSERT(X)
Compile-time assertion. Produces a compilation error if X is false.
#define STK_VIRT_DTOR
Makes destructors virtual and compliant to strict rules if STK_STRICT_COMPLIANCY=0.
Contains helper implementations which simplify user-side code.
Namespace of STK package.
uintptr_t Word
Native processor word type.
static constexpr TId TID_ISR_N
Bitmask sentinel for ISR-context task identifiers.
@ ACCESS_PRIVILEGED
Privileged access mode (access to hardware is fully unrestricted).
static constexpr Timeout NO_WAIT
Timeout value: return immediately if the synchronization object is not yet signaled (non-blocking pol...
EWaitResult
Wait result (see IKernelService::Wait).
static __stk_forceinline Cycles ConvertTimeUsToClockCycles(uint32_t clock_freq, Ticks time_us)
Convert time (microseconds) to core clock cycles.
int64_t Ticks
Ticks value.
int32_t Timeout
Timeout time (ticks).
static bool IsIsrTid(TId id)
Test whether a task identifier represents an ISR context.
static __stk_forceinline void STK_KERNEL_PANIC(stk::EKernelPanicId id)
Called when the kernel detects an unrecoverable internal fault.
static constexpr T Max(T a, T b) noexcept
Compile-time maximum of two values.
@ STACK_SLEEP_TRAP
Stack of the Sleep trap.
@ STACK_USER_TASK
Stack of the user task.
@ STACK_EXIT_TRAP
Stack of the Exit trap.
uint64_t Cycles
Cycles value.
Word TId
Task (thread) id.
EKernelPanicId
Identifies the source of a kernel panic.
@ KERNEL_PANIC_BAD_STACK_TYPE
Stack type is unknown.
@ KERNEL_PANIC_HRT_HARD_FAULT
Kernel running in KERNEL_HRT mode reported deadline failure of the task.
@ KERNEL_PANIC_NONE
Panic is absent (no fault).
@ KERNEL_PANIC_CPU_EXCEPTION
CPU reported an exception and halted execution.
@ KERNEL_PANIC_SPINLOCK_DEADLOCK
Spin-lock timeout expired: lock owner never released.
bool IsPrivilegedContext()
Check if caller context is Privileged.
static constexpr T * WordToPtr(Word value) noexcept
Cast a CPU register-width integer back to a pointer.
static constexpr Word PtrToWord(T *const ptr) noexcept
Cast a pointer to a CPU register-width integer.
bool IsInsideISR()
Check whether the CPU is currently executing inside a hardware interrupt service routine (ISR).
Cycles GetSysTimerCount() const override
Get system timer count value.
Word GetCallerSP() const override
Get caller's Stack Pointer (SP).
void Resume(Timeout elapsed_ticks) override
Resume scheduling after a prior Suspend() call.
void Start() override
Start scheduling.
uint32_t GetTickResolution() const override
Get resolution of the system tick timer in microseconds. Resolution means a number of microseconds be...
bool SleepUntil(Ticks timestamp) override
Put calling process into a sleep state until the specified timestamp.
uint32_t GetSysTimerFrequency() const override
Get system timer frequency.
void ProcessHardFault() override
Cause a hard fault of the system.
void InitStack(EStackType stack_type, Stack *stack, IStackMemory *stack_memory, ITask *user_task) override
Initialize stack memory of the user task.
void ProcessTick() override
Process one tick.
TId GetTid() const override
Get thread Id.
EWaitResult Wait(ISyncObject *sync_obj, IMutex *mutex, Timeout timeout) override
Put calling process into a waiting state until synchronization object is signaled or timeout occurs.
void SetSpecificEventHandler(ISpecificEventHandler *handler)
void SetEventOverrider(IEventOverrider *overrider) override
Set platform event overrider.
void Stop() override
Stop scheduling.
void SwitchToNext() override
Switch to a next task.
Timeout Suspend() override
Suspend scheduling.
void Sleep(Timeout ticks) override
Put calling process into a sleep state.
void Initialize(IEventHandler *event_handler, IKernelService *service, uint32_t resolution_us, Stack *exit_trap) override
Initialize scheduler's context.
Base platform context for all platform implementations.
static Word InitStackMemory(IStackMemory *const memory)
Initialize stack memory by filling it with STK_STACK_MEMORY_FILLER.
static constexpr Session DEFAULT_SESSION
Default session value passed to Enter()/Exit() when the caller does not need to force a specific hand...
static Session Enter(const Session ses=DEFAULT_SESSION)
Enter a critical section.
uint8_t Session
Opaque session token returned by Enter() and consumed by Exit().
static void Exit(const Session ses=DEFAULT_SESSION)
Exit a critical section.
bool TryLock()
Attempt to acquire SpinLock in a single non-blocking attempt.
void Lock()
Acquire SpinLock, blocking until it is available.
void Unlock()
Release SpinLock, allowing another thread or core to acquire it.
static uint32_t GetFrequency()
Get clock frequency.
static Cycles GetCycles()
Get number of clock cycles elapsed.
Word SP
Offset 0: Stack Pointer (SP) register.
Interface for a stack memory region.
virtual size_t GetStackSize() const =0
Get number of elements of the stack memory array.
Synchronization object interface.
Interface for mutex synchronization primitive.
Interface for a user task.
virtual void Run()=0
Entry point of the user task.
Interface for the kernel services exposed to the user processes during run-time when Kernel started s...
static IKernelService * GetInstance()
Get CPU-local instance of the kernel service.
RISC-V specific event handler.