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();
1100#if STK_TICKLESS_IDLE
1102 void Resume(Timeout elapsed_ticks);
1105 typedef IPlatform::IEventOverrider eovrd_t;
1106 typedef PlatformRiscV::ISpecificEventHandler sehndl_t;
1107 typedef StackMemoryWrapper<STK_RISCV_ISR_STACK_SIZE>::MemoryType isrmem_t;
1111 isrmem_t m_stack_isr_mem;
1112 JmpFrame m_exit_buf;
1113 eovrd_t *m_overrider;
1114 sehndl_t *m_specific;
1115 uint32_t m_tick_period;
1116 uint64_t m_last_mtime;
1117#if STK_TICKLESS_IDLE
1121 uint8_t m_csu_nesting;
1124 volatile bool m_exiting;
1130#ifdef _STK_RISCV_USE_PENDSV
1132 HW_CriticalSectionStart(cs);
1136 HW_CriticalSectionEnd(cs);
1153 HW_DisableInterrupts();
1163#define STK_ASM_SAVE_CONTEXT_BASE\
1164 SREG " x1, 2*" REGBYTES "(sp) \n"\
1167 SREG " x4, 5*" REGBYTES "(sp) \n"\
1168 SREG " x5, 6*" REGBYTES "(sp) \n"\
1169 SREG " x6, 7*" REGBYTES "(sp) \n"\
1170 SREG " x7, 8*" REGBYTES "(sp) \n"\
1171 SREG " x8, 9*" REGBYTES "(sp) \n"\
1172 SREG " x9, 10*" REGBYTES "(sp) \n"\
1173 SREG " x10, 11*" REGBYTES "(sp) \n"\
1174 SREG " x11, 12*" REGBYTES "(sp) \n"\
1175 SREG " x12, 13*" REGBYTES "(sp) \n"\
1176 SREG " x13, 14*" REGBYTES "(sp) \n"\
1177 SREG " x14, 15*" REGBYTES "(sp) \n"\
1178 SREG " x15, 16*" REGBYTES "(sp) \n"
1180#if (__riscv_32e != 1)
1181#define STK_ASM_SAVE_CONTEXT_RV32I_EXT\
1182 SREG " x16, 17*" REGBYTES "(sp) \n"\
1183 SREG " x17, 18*" REGBYTES "(sp) \n"\
1184 SREG " x18, 19*" REGBYTES "(sp) \n"\
1185 SREG " x19, 20*" REGBYTES "(sp) \n"\
1186 SREG " x20, 21*" REGBYTES "(sp) \n"\
1187 SREG " x21, 22*" REGBYTES "(sp) \n"\
1188 SREG " x22, 23*" REGBYTES "(sp) \n"\
1189 SREG " x23, 24*" REGBYTES "(sp) \n"\
1190 SREG " x24, 25*" REGBYTES "(sp) \n"\
1191 SREG " x25, 26*" REGBYTES "(sp) \n"\
1192 SREG " x26, 27*" REGBYTES "(sp) \n"\
1193 SREG " x27, 28*" REGBYTES "(sp) \n"\
1194 SREG " x28, 29*" REGBYTES "(sp) \n"\
1195 SREG " x29, 30*" REGBYTES "(sp) \n"\
1196 SREG " x30, 31*" REGBYTES "(sp) \n"\
1197 SREG " x31, 32*" REGBYTES "(sp) \n"
1199#define STK_ASM_SAVE_CONTEXT_RV32I_EXT
1202#if (STK_RISCV_FPU != 0)
1203#define STK_ASM_SAVE_CONTEXT_FP\
1204 FSREG " f0, " FOFFSET "+0*" FREGBYTES "(sp) \n"\
1205 FSREG " f1, " FOFFSET "+1*" FREGBYTES "(sp) \n"\
1206 FSREG " f2, " FOFFSET "+2*" FREGBYTES "(sp) \n"\
1207 FSREG " f3, " FOFFSET "+3*" FREGBYTES "(sp) \n"\
1208 FSREG " f4, " FOFFSET "+4*" FREGBYTES "(sp) \n"\
1209 FSREG " f5, " FOFFSET "+5*" FREGBYTES "(sp) \n"\
1210 FSREG " f6, " FOFFSET "+6*" FREGBYTES "(sp) \n"\
1211 FSREG " f7, " FOFFSET "+7*" FREGBYTES "(sp) \n"\
1212 FSREG " f8, " FOFFSET "+8*" FREGBYTES "(sp) \n"\
1213 FSREG " f9, " FOFFSET "+9*" FREGBYTES "(sp) \n"\
1214 FSREG " f10, " FOFFSET "+10*" FREGBYTES "(sp) \n"\
1215 FSREG " f11, " FOFFSET "+11*" FREGBYTES "(sp) \n"\
1216 FSREG " f12, " FOFFSET "+12*" FREGBYTES "(sp) \n"\
1217 FSREG " f13, " FOFFSET "+13*" FREGBYTES "(sp) \n"\
1218 FSREG " f14, " FOFFSET "+14*" FREGBYTES "(sp) \n"\
1219 FSREG " f15, " FOFFSET "+15*" FREGBYTES "(sp) \n"\
1220 FSREG " f16, " FOFFSET "+16*" FREGBYTES "(sp) \n"\
1221 FSREG " f17, " FOFFSET "+17*" FREGBYTES "(sp) \n"\
1222 FSREG " f18, " FOFFSET "+18*" FREGBYTES "(sp) \n"\
1223 FSREG " f19, " FOFFSET "+19*" FREGBYTES "(sp) \n"\
1224 FSREG " f20, " FOFFSET "+20*" FREGBYTES "(sp) \n"\
1225 FSREG " f21, " FOFFSET "+21*" FREGBYTES "(sp) \n"\
1226 FSREG " f22, " FOFFSET "+22*" FREGBYTES "(sp) \n"\
1227 FSREG " f23, " FOFFSET "+23*" FREGBYTES "(sp) \n"\
1228 FSREG " f24, " FOFFSET "+24*" FREGBYTES "(sp) \n"\
1229 FSREG " f25, " FOFFSET "+25*" FREGBYTES "(sp) \n"\
1230 FSREG " f26, " FOFFSET "+26*" FREGBYTES "(sp) \n"\
1231 FSREG " f27, " FOFFSET "+27*" FREGBYTES "(sp) \n"\
1232 FSREG " f28, " FOFFSET "+28*" FREGBYTES "(sp) \n"\
1233 FSREG " f29, " FOFFSET "+29*" FREGBYTES "(sp) \n"\
1234 FSREG " f30, " FOFFSET "+30*" FREGBYTES "(sp) \n"\
1235 FSREG " f31, " FOFFSET "+31*" FREGBYTES "(sp) \n"
1237#define STK_ASM_SAVE_CONTEXT_FP
1240#define STK_ASM_SAVE_CONTEXT_PC_STATUS\
1242 "csrr t1, mstatus \n"\
1243 SREG " t0, 0*" REGBYTES "(sp) \n"\
1244 SREG " t1, 1*" REGBYTES "(sp) \n"
1246#if (STK_RISCV_FPU != 0)
1247#define STK_ASM_SAVE_CONTEXT_FRCSR\
1249 SREG " t0, 4*" REGBYTES "(sp) \n"
1251#define STK_ASM_SAVE_CONTEXT_FRCSR
1254#define STK_ASM_SAVE_CONTEXT\
1255 "addi sp, sp, -" REGSIZE " \n" \
1256 STK_ASM_SAVE_CONTEXT_BASE\
1257 STK_ASM_SAVE_CONTEXT_RV32I_EXT\
1258 STK_ASM_SAVE_CONTEXT_FP\
1259 STK_ASM_SAVE_CONTEXT_PC_STATUS\
1260 STK_ASM_SAVE_CONTEXT_FRCSR
1262#define STK_ASM_LOAD_CONTEXT_BASE\
1263 LREG " x1, 2*" REGBYTES "(sp) \n"\
1266 LREG " x4, 5*" REGBYTES "(sp) \n"\
1267 LREG " x5, 6*" REGBYTES "(sp) \n"\
1268 LREG " x6, 7*" REGBYTES "(sp) \n"\
1269 LREG " x7, 8*" REGBYTES "(sp) \n"\
1270 LREG " x8, 9*" REGBYTES "(sp) \n"\
1271 LREG " x9, 10*" REGBYTES "(sp) \n"\
1272 LREG " x10, 11*" REGBYTES "(sp) \n"\
1273 LREG " x11, 12*" REGBYTES "(sp) \n"\
1274 LREG " x12, 13*" REGBYTES "(sp) \n"\
1275 LREG " x13, 14*" REGBYTES "(sp) \n"\
1276 LREG " x14, 15*" REGBYTES "(sp) \n"\
1277 LREG " x15, 16*" REGBYTES "(sp) \n"
1279#if (__riscv_32e != 1)
1280#define STK_ASM_LOAD_CONTEXT_RV32I_EXT\
1281 LREG " x16, 17*" REGBYTES "(sp) \n"\
1282 LREG " x17, 18*" REGBYTES "(sp) \n"\
1283 LREG " x18, 19*" REGBYTES "(sp) \n"\
1284 LREG " x19, 20*" REGBYTES "(sp) \n"\
1285 LREG " x20, 21*" REGBYTES "(sp) \n"\
1286 LREG " x21, 22*" REGBYTES "(sp) \n"\
1287 LREG " x22, 23*" REGBYTES "(sp) \n"\
1288 LREG " x23, 24*" REGBYTES "(sp) \n"\
1289 LREG " x24, 25*" REGBYTES "(sp) \n"\
1290 LREG " x25, 26*" REGBYTES "(sp) \n"\
1291 LREG " x26, 27*" REGBYTES "(sp) \n"\
1292 LREG " x27, 28*" REGBYTES "(sp) \n"\
1293 LREG " x28, 29*" REGBYTES "(sp) \n"\
1294 LREG " x29, 30*" REGBYTES "(sp) \n"\
1295 LREG " x30, 31*" REGBYTES "(sp) \n"\
1296 LREG " x31, 32*" REGBYTES "(sp) \n"
1298#define STK_ASM_LOAD_CONTEXT_RV32I_EXT
1301#if (STK_RISCV_FPU != 0)
1302#define STK_ASM_LOAD_CONTEXT_FP\
1303 FLREG " f0, " FOFFSET "+0*" FREGBYTES "(sp) \n"\
1304 FLREG " f1, " FOFFSET "+1*" FREGBYTES "(sp) \n"\
1305 FLREG " f2, " FOFFSET "+2*" FREGBYTES "(sp) \n"\
1306 FLREG " f3, " FOFFSET "+3*" FREGBYTES "(sp) \n"\
1307 FLREG " f4, " FOFFSET "+4*" FREGBYTES "(sp) \n"\
1308 FLREG " f5, " FOFFSET "+5*" FREGBYTES "(sp) \n"\
1309 FLREG " f6, " FOFFSET "+6*" FREGBYTES "(sp) \n"\
1310 FLREG " f7, " FOFFSET "+7*" FREGBYTES "(sp) \n"\
1311 FLREG " f8, " FOFFSET "+8*" FREGBYTES "(sp) \n"\
1312 FLREG " f9, " FOFFSET "+9*" FREGBYTES "(sp) \n"\
1313 FLREG " f10, " FOFFSET "+10*" FREGBYTES "(sp) \n"\
1314 FLREG " f11, " FOFFSET "+11*" FREGBYTES "(sp) \n"\
1315 FLREG " f12, " FOFFSET "+12*" FREGBYTES "(sp) \n"\
1316 FLREG " f13, " FOFFSET "+13*" FREGBYTES "(sp) \n"\
1317 FLREG " f14, " FOFFSET "+14*" FREGBYTES "(sp) \n"\
1318 FLREG " f15, " FOFFSET "+15*" FREGBYTES "(sp) \n"\
1319 FLREG " f16, " FOFFSET "+16*" FREGBYTES "(sp) \n"\
1320 FLREG " f17, " FOFFSET "+17*" FREGBYTES "(sp) \n"\
1321 FLREG " f18, " FOFFSET "+18*" FREGBYTES "(sp) \n"\
1322 FLREG " f19, " FOFFSET "+19*" FREGBYTES "(sp) \n"\
1323 FLREG " f20, " FOFFSET "+20*" FREGBYTES "(sp) \n"\
1324 FLREG " f21, " FOFFSET "+21*" FREGBYTES "(sp) \n"\
1325 FLREG " f22, " FOFFSET "+22*" FREGBYTES "(sp) \n"\
1326 FLREG " f23, " FOFFSET "+23*" FREGBYTES "(sp) \n"\
1327 FLREG " f24, " FOFFSET "+24*" FREGBYTES "(sp) \n"\
1328 FLREG " f25, " FOFFSET "+25*" FREGBYTES "(sp) \n"\
1329 FLREG " f26, " FOFFSET "+26*" FREGBYTES "(sp) \n"\
1330 FLREG " f27, " FOFFSET "+27*" FREGBYTES "(sp) \n"\
1331 FLREG " f28, " FOFFSET "+28*" FREGBYTES "(sp) \n"\
1332 FLREG " f29, " FOFFSET "+29*" FREGBYTES "(sp) \n"\
1333 FLREG " f30, " FOFFSET "+30*" FREGBYTES "(sp) \n"\
1334 FLREG " f31, " FOFFSET "+31*" FREGBYTES "(sp) \n"
1336#define STK_ASM_LOAD_CONTEXT_FP
1339#define STK_ASM_LOAD_CONTEXT_PC_STATUS\
1340 LREG " t0, 0*" REGBYTES "(sp) \n"\
1341 LREG " t1, 1*" REGBYTES "(sp) \n"\
1343 "csrw mstatus, t1 \n"
1345#if (STK_RISCV_FPU != 0)
1346#define STK_ASM_LOAD_CONTEXT_FRCSR\
1347 LREG " t0, 4*" REGBYTES "(sp) \n" \
1350#define STK_ASM_LOAD_CONTEXT_FRCSR
1353#define STK_ASM_LOAD_CONTEXT\
1354 STK_ASM_LOAD_CONTEXT_PC_STATUS\
1355 STK_ASM_LOAD_CONTEXT_FRCSR\
1356 STK_ASM_LOAD_CONTEXT_BASE\
1357 STK_ASM_LOAD_CONTEXT_RV32I_EXT\
1358 STK_ASM_LOAD_CONTEXT_FP\
1359 "addi sp, sp, " REGSIZE " \n"
1365 LREG
" sp, 0(t0) \n"
1367 STK_ASM_LOAD_CONTEXT
1368 STK_ASM_EXIT_FROM_HANDLER
" \n"
1372 :
"t0",
"t1",
"a2",
"a3",
"a4",
"a5",
"gp",
"memory");
1377#if (STK_RISCV_FPU != 0)
1381 :
"r"(MSTATUS_FS | MSTATUS_XS)
1388#if (STK_RISCV_FPU != 0)
1427 __asm
volatile(
"csrr %0, mcause" :
"=r"(mcause));
1433 const Word current_sp = HW_GetCallerSP();
1438 const Word isr_stack_top = isr_stack_base + (STK_RISCV_ISR_STACK_SIZE *
sizeof(
Word));
1440 return ((current_sp >= isr_stack_base) && (current_sp < isr_stack_top));
1445 HW_LoadContextAndExit();
1449extern "C" STK_RISCV_ISR_SECTION
__stk_attr_used void TrySwitchContext()
1454#ifdef _STK_RISCV_USE_PENDSV
1455extern "C" STK_RISCV_ISR_SECTION
__stk_attr_naked void STK_SYSTICK_HANDLER()
1459 STK_ASM_SAVE_CONTEXT
1462#if (STK_ARCH_CPU_COUNT > 1)
1463 "csrr t0, mhartid \n"
1464 "la t1, s_StkRiscvSpIsrInt \n"
1465 "slli t0, t0, " REGBYTES_LOG2
" \n"
1467 SREG
" sp, 0(t1) \n"
1469 "la t1, s_StkRiscvSpIsrInt \n"
1470 SREG
" sp, 0(t1) \n"
1474#if (STK_ARCH_CPU_COUNT > 1)
1475 "csrr t0, mhartid \n"
1476 "la t1, s_StkRiscvStackIsr \n"
1477 "slli t0, t0, " REGBYTES_LOG2
" \n"
1479 LREG
" t1, 0(t1) \n"
1481 "la t1, s_StkRiscvStackIsr \n"
1482 LREG
" t1, 0(t1) \n"
1484 LREG
" sp, 0(t1) \n"
1487 "jal ra, TrySwitchContext \n"
1490#if (STK_ARCH_CPU_COUNT > 1)
1491 "csrr t0, mhartid \n"
1492 "la t1, s_StkRiscvSpIsrInt \n"
1493 "slli t0, t0, " REGBYTES_LOG2
" \n"
1495 LREG
" sp, 0(t1) \n"
1497 "la t1, s_StkRiscvSpIsrInt \n"
1498 LREG
" sp, 0(t1) \n"
1502 STK_ASM_LOAD_CONTEXT
1505 STK_ASM_EXIT_FROM_HANDLER
" \n"
1515 STK_ASM_SAVE_CONTEXT
1521#if (STK_ARCH_CPU_COUNT > 1)
1522 "csrr t0, mhartid \n"
1523 "la t1, s_StkRiscvStackIdle \n"
1524 "slli t0, t0, " REGBYTES_LOG2
" \n"
1526 LREG
" t1, 0(t1) \n"
1528 "la t1, s_StkRiscvStackIdle \n"
1529 LREG
" t1, 0(t1) \n"
1531 SREG
" sp, 0(t1) \n"
1534#if (STK_ARCH_CPU_COUNT > 1)
1535 "csrr t0, mhartid \n"
1537 "li t1, %[clint_msip_base] \n"
1540 "li t0, %[clint_msip_base] \n"
1546#if (STK_ARCH_CPU_COUNT > 1)
1547 "csrr t0, mhartid \n"
1548 "la t1, s_StkRiscvStackActive \n"
1549 "slli t0, t0, " REGBYTES_LOG2
" \n"
1551 LREG
" t1, 0(t1) \n"
1553 "la t1, s_StkRiscvStackActive \n"
1554 LREG
" t1, 0(t1) \n"
1556 LREG
" sp, 0(t1) \n"
1559 STK_ASM_LOAD_CONTEXT
1562 STK_ASM_EXIT_FROM_HANDLER
" \n"
1565 : [clint_msip_base]
"i" (STK_RISCV_CLINT_BASE_ADDR)
1609extern "C" STK_RISCV_ISR_SECTION
__stk_attr_naked void STK_SYSTICK_HANDLER()
1613 STK_ASM_SAVE_CONTEXT
1619#if (STK_ARCH_CPU_COUNT > 1)
1620 "csrr t0, mhartid \n"
1621 "la t1, s_StkRiscvStackActive \n"
1622 "slli t0, t0, " REGBYTES_LOG2
" \n"
1624 LREG
" t1, 0(t1) \n"
1626 "la t1, s_StkRiscvStackActive \n"
1627 LREG
" t1, 0(t1) \n"
1629 SREG
" sp, 0(t1) \n"
1632#if (STK_ARCH_CPU_COUNT > 1)
1633 "csrr t0, mhartid \n"
1634 "la t1, s_StkRiscvStackIsr \n"
1635 "slli t0, t0, " REGBYTES_LOG2
" \n"
1637 LREG
" t1, 0(t1) \n"
1639 "la t1, s_StkRiscvStackIsr \n"
1640 LREG
" t1, 0(t1) \n"
1642 LREG
" sp, 0(t1) \n"
1649 "jal ra, TrySwitchContext \n"
1654#if (STK_ARCH_CPU_COUNT > 1)
1655 "csrr t0, mhartid \n"
1656 "la t1, s_StkRiscvStackActive \n"
1657 "slli t0, t0, " REGBYTES_LOG2
" \n"
1659 LREG
" t1, 0(t1) \n"
1661 "la t1, s_StkRiscvStackActive \n"
1662 LREG
" t1, 0(t1) \n"
1664 LREG
" sp, 0(t1) \n"
1667 STK_ASM_LOAD_CONTEXT
1670 STK_ASM_EXIT_FROM_HANDLER
" \n"
1679void Context::OnStart()
1681 const uint8_t hart = HW_GetHartId();
1687 HW_EnableFullFpuAccess();
1693 m_handler->OnStart(m_stack_active);
1696 s_StkRiscvStackIsr[hart] = &m_stack_isr;
1697 s_StkRiscvStackActive[hart] = m_stack_active;
1698#ifdef _STK_RISCV_USE_PENDSV
1699 s_StkRiscvStackIdle[hart] = m_stack_idle;
1710#ifdef _STK_RISCV_USE_PENDSV
1711 set_csr(mie, MIP_MSIP);
1715STK_RISCV_ISR
void STK_SVC_HANDLER()
1717 const Word cause = HW_GetCurrentException();
1729 if (cause == IRQ_M_EXT)
1739 write_csr(mepc, read_csr(mepc) +
sizeof(
Word));
1744 HW_DisableInterrupts();
1770static void OnTaskRun(
ITask *task)
1775static void OnTaskExit()
1778 HW_CriticalSectionStart(cs);
1782 HW_CriticalSectionEnd(cs);
1791static STK_RISCV_ISR_SECTION
void OnSchedulerSleep()
1796#if STK_SEGGER_SYSVIEW
1797 SEGGER_SYSVIEW_OnIdle();
1802 HW_EnterSleepMode();
1806static STK_RISCV_ISR_SECTION
void OnSchedulerSleepOverride()
1811#if STK_SEGGER_SYSVIEW
1812 SEGGER_SYSVIEW_OnIdle();
1821static void OnSchedulerExit()
1832 GetContext().Initialize(event_handler, service, exit_trap, resolution_us);
1835void Context::Start()
1840 SaveJmp(m_exit_buf);
1844 m_handler->OnStop();
1849 HW_EnableFullFpuAccess();
1853 HW_StartScheduler();
1857#if STK_TICKLESS_IDLE
1861 if (resolution == 0U)
1867 HW_DisableInterrupts();
1873 HW_ClearPendingSwitch();
1877 const uint32_t elapsed = HW_GetMtime() - m_last_mtime;
1881 const Timeout elapsed_ticks =
static_cast<Timeout>(elapsed / resolution);
1882 const Timeout sleep_ticks =
Max(m_sleep_ticks - elapsed_ticks,
static_cast<Timeout>(0));
1885 m_handler->OnSuspend(
true);
1887 HW_EnableInterrupts();
1893#if STK_TICKLESS_IDLE
1894void Context::Resume(
Timeout elapsed_ticks)
1896 HW_DisableInterrupts();
1899 m_handler->OnSuspend(
false);
1902 StartTickTimer(elapsed_ticks + 1);
1904 HW_EnableInterrupts();
1917 "TaskFrame size must match REGSIZE: (REGISTER_COUNT + SERVICE_SLOTS) * REGBYTES");
1925 stack->
SP = stack_top - ((STK_RISCV_REGISTER_COUNT + STK_SERVICE_SLOTS) *
sizeof(
Word));
1940 task_frame->MEPC =
hw::PtrToWord(
GetContext().m_overrider !=
nullptr ? &OnSchedulerSleepOverride : &OnSchedulerSleep);
1956 task_frame->MSTATUS = MSTATUS_MPP | MSTATUS_MPIE | (STK_RISCV_FPU != 0U ? (MSTATUS_FS | MSTATUS_XS) : 0U);
1958#if (STK_RISCV_FPU != 0)
1959 task_frame->X3_FSR = 0U;
1963void Context::OnStop()
1969 HW_ClearPendingSwitch();
1984 HW_DisableInterrupts();
1995 return static_cast<Cycles>(HW_GetMtime());
2000 return HW_MtimeClockFrequency();
2005 GetContext().m_handler->OnTaskSwitch(HW_GetCallerSP());
2010 GetContext().m_handler->OnTaskSleep(HW_GetCallerSP(), ticks);
2015 return GetContext().m_handler->OnTaskSleepUntil(HW_GetCallerSP(), timestamp);
2020 return GetContext().m_handler->OnTaskWait(HW_GetCallerSP(), sync_obj, mutex, timeout);
2027 if (HW_IsHandlerMode())
2031 const Word exc = HW_GetCurrentException();
2032 const Word num = (exc & 0x7FFU);
2033 #if (__riscv_xlen > 32)
2034 const Word interrupt_bit = ((exc & (1ULL << (__riscv_xlen - 1))) ? 0x800U : 0);
2036 const Word interrupt_bit = ((exc & (1U << (__riscv_xlen - 1))) ? 0x800U : 0);
2045 result =
GetContext().m_handler->OnGetTid(HW_GetCallerSP());
2053#if STK_TICKLESS_IDLE
2062#if STK_TICKLESS_IDLE
2071 bool is_handled =
false;
2075 is_handled =
GetContext().m_overrider->OnHardFault();
2092 return HW_GetCallerSP();
2118 HW_SpinLockLock(m_lock);
2123 HW_SpinLockUnlock(m_lock);
2128 return HW_SpinLockTryLock(m_lock);
2133 return HW_IsHandlerMode();
2144 return HiResClockImpl::GetInstance()->GetCycles();
2149 const uint32_t freq = HiResClockImpl::GetInstance()->GetFrequency();
#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_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_CRITICAL_SECTION_NESTINGS_MAX
Maximum allowable recursion depth for critical section entry (default: 16).
#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.
constexpr TId TID_ISR_N
Bitmask sentinel for ISR-context task identifiers.
@ ACCESS_PRIVILEGED
Privileged access mode (access to hardware is fully unrestricted).
constexpr Timeout NO_WAIT
Timeout value: return immediately if the synchronization object is not yet signaled (non-blocking pol...
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 constexpr T Max(T a, T b)
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.
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.
EWaitResult
Wait result (see IKernelService::Wait).
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.
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 IsContextPrivileged()
Check if caller is Privileged.
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 void Enter()
Enter a critical section.
static void Exit()
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
Stack Pointer (SP) register (note: must be the first entry in this struct).
Interface for a stack memory region.
virtual size_t GetStackSize() const =0
Get number of elements of the stack memory array.
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.