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 (15 + (STK_RISCV_FPU != 0 ? 31 : 0))
160 #define STK_RISCV_REGISTER_COUNT (31 + (STK_RISCV_FPU != 0 ? 31 : 0))
163#define STK_SERVICE_SLOTS 2
165#if (__riscv_32e == 1)
166 #define FOFFSET XSTR(68)
167 #if (STK_RISCV_FPU == 0)
168 #define REGSIZE XSTR(((15 + STK_SERVICE_SLOTS) * 4))
170 #if (STK_RISCV_FPU == 32)
171 #define REGSIZE XSTR((((15 + STK_SERVICE_SLOTS) * 4) + (31 * 4)))
172 #elif (STK_RISCV_FPU == 64)
173 #define REGSIZE XSTR((((15 + STK_SERVICE_SLOTS) * 4) + (31 * 8)))
176#elif (__riscv_xlen == 32)
177 #define FOFFSET XSTR(132)
178 #if (STK_RISCV_FPU == 0)
179 #define REGSIZE XSTR(((31 + STK_SERVICE_SLOTS) * 4))
181 #if (STK_RISCV_FPU == 32)
182 #define REGSIZE XSTR((((31 + STK_SERVICE_SLOTS) * 4) + (31 * 4)))
183 #elif (STK_RISCV_FPU == 64)
184 #define REGSIZE XSTR((((31 + STK_SERVICE_SLOTS) * 4) + (31 * 8)))
187#elif (__riscv_xlen == 64)
188 #define FOFFSET XSTR(264)
189 #if (STK_RISCV_FPU == 0)
190 #define REGSIZE XSTR(((31 + STK_SERVICE_SLOTS) * 8))
192 #if (STK_RISCV_FPU == 32)
193 #define REGSIZE XSTR((((31 + STK_SERVICE_SLOTS) * 8) + (31 * 4)))
194 #elif (STK_RISCV_FPU == 64)
195 #define REGSIZE XSTR((((31 + STK_SERVICE_SLOTS) * 8) + (31 * 8)))
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"
397 clear_csr(mie, MIP_MTIP);
404#ifdef _STK_RISCV_USE_PENDSV
405 clear_csr(mie, MIP_MSIP);
423 return STK_TIMER_CLOCK_FREQUENCY;
433#if ( __riscv_xlen > 32)
434 return *((
volatile uint64_t *)STK_RISCV_CLINT_MTIME_ADDR);
436 volatile uint32_t *mtime_hi = ((uint32_t *)STK_RISCV_CLINT_MTIME_ADDR) + 1;
437 volatile uint32_t *mtime_lo = ((uint32_t *)STK_RISCV_CLINT_MTIME_ADDR);
445 while (hi != (*mtime_hi));
447 return ((uint64_t)hi << 32) | lo;
456#if STK_RISCV_CLINT_MTIMECMP_PER_HART
457 const uint8_t hart = HW_GetHartId();
459 const uint8_t hart = 0;
462#if (__riscv_xlen == 64)
463 ((
volatile uint64_t *)STK_RISCV_CLINT_MTIMECMP_ADDR)[hart] = next;
465 volatile uint32_t *mtime_lo = (uint32_t *)((uint64_t *)STK_RISCV_CLINT_MTIMECMP_ADDR + hart);
466 volatile uint32_t *mtime_hi = mtime_lo + 1;
469 STK_ASSERT(((uintptr_t)mtime_lo & (4 - 1)) == 0);
470 STK_ASSERT(((uintptr_t)mtime_hi & (4 - 1)) == 0);
476 (*mtime_lo) = (uint32_t)(time_next & 0xFFFFFFFF);
477 (*mtime_hi) = (uint32_t)(time_next >> 32);
488 return HW_GetMtime() - since;
495 __asm
volatile(
"csrci mcountinhibit, 0x1");
503 uint32_t high, low, check;
506 __asm
volatile(
"csrr %0, mcycleh" :
"=r"(high));
507 __asm
volatile(
"csrr %0, mcycle" :
"=r"(low));
508 __asm
volatile(
"csrr %0, mcycleh" :
"=r"(check));
510 while (high != check);
512 return (
static_cast<Cycles>(high) << 32) | low;
520 __asm
volatile(
"mv %0, sp"
532 ses = HW_EnterCriticalSection();
546 HW_ExitCriticalSection(ses);
568 return !__atomic_test_and_set(&lock, __ATOMIC_ACQUIRE);
589 uint32_t timeout = 0xFFFFFF;
590 while (!HW_SpinLockTryLock(lock))
626 __asm
volatile(
"fence rw, w" :::
"memory");
628 __atomic_clear(&lock, __ATOMIC_RELEASE);
635#ifdef _STK_RISCV_USE_PENDSV
637 volatile uint32_t *msip = (
volatile uint32_t *)(STK_RISCV_CLINT_BASE_ADDR);
646#ifndef _STK_SYSTEM_CORE_CLOCK_EXTERNAL
652static volatile bool s_StkRiscvCsuLock =
false;
665#ifdef _STK_RISCV_USE_PENDSV
733#if (STK_RISCV_FPU != 0)
752__attribute__((naked))
753int32_t SaveJmp(JmpFrame &)
757 SREG
" ra, 0*" REGBYTES
"(a0) \n"
758 SREG
" sp, 1*" REGBYTES
"(a0) \n"
759 SREG
" s0, 2*" REGBYTES
"(a0) \n"
760 SREG
" s1, 3*" REGBYTES
"(a0) \n"
761 SREG
" s2, 4*" REGBYTES
"(a0) \n"
762 SREG
" s3, 5*" REGBYTES
"(a0) \n"
763 SREG
" s4, 6*" REGBYTES
"(a0) \n"
764 SREG
" s5, 7*" REGBYTES
"(a0) \n"
765 SREG
" s6, 8*" REGBYTES
"(a0) \n"
766 SREG
" s7, 9*" REGBYTES
"(a0) \n"
767 SREG
" s8, 10*" REGBYTES
"(a0) \n"
768 SREG
" s9, 11*" REGBYTES
"(a0) \n"
769 SREG
" s10, 12*" REGBYTES
"(a0) \n"
770 SREG
" s11, 13*" REGBYTES
"(a0) \n"
771#if (STK_RISCV_FPU != 0)
773 SREG
" t0, 14*" REGBYTES
"(a0) \n"
797__attribute__((naked, noreturn))
798void RestoreJmp(JmpFrame &, int32_t )
802 LREG
" ra, 0*" REGBYTES
"(a0) \n"
803 LREG
" sp, 1*" REGBYTES
"(a0) \n"
804 LREG
" s0, 2*" REGBYTES
"(a0) \n"
805 LREG
" s1, 3*" REGBYTES
"(a0) \n"
806 LREG
" s2, 4*" REGBYTES
"(a0) \n"
807 LREG
" s3, 5*" REGBYTES
"(a0) \n"
808 LREG
" s4, 6*" REGBYTES
"(a0) \n"
809 LREG
" s5, 7*" REGBYTES
"(a0) \n"
810 LREG
" s6, 8*" REGBYTES
"(a0) \n"
811 LREG
" s7, 9*" REGBYTES
"(a0) \n"
812 LREG
" s8, 10*" REGBYTES
"(a0) \n"
813 LREG
" s9, 11*" REGBYTES
"(a0) \n"
814 LREG
" s10, 12*" REGBYTES
"(a0) \n"
815 LREG
" s11, 13*" REGBYTES
"(a0) \n"
816#if (STK_RISCV_FPU != 0)
817 LREG
" t0, 14*" REGBYTES
"(a0) \n"
828#if STK_SUBMICORSECOND_PRECISION_TIMER
832 static HiResClockCYCLE *GetInstance()
836 static HiResClockCYCLE clock;
842 return HW_GetCycleCounter();
845 uint32_t GetFrequency()
847 return HW_CoreClockFrequency();
850typedef HiResClockCYCLE HiResClockImpl;
855 static HiResClockMTIME *GetInstance()
859 static HiResClockMTIME clock;
865 return HW_GetMtime();
868 uint32_t GetFrequency()
870 return HW_MtimeClockFrequency();
873typedef HiResClockMTIME HiResClockImpl;
879 Context() : PlatformContext(), m_stack_main(), m_stack_isr(), m_stack_isr_mem(),
880 m_exit_buf(), m_overrider(nullptr), m_specific(nullptr), m_tick_period(0), m_last_mtime(0ULL),
884 m_csu(0), m_csu_nesting(0),
885 m_starting(false), m_started(false), m_exiting(false)
895 void Initialize(IPlatform::IEventHandler *handler, IKernelService *service, Stack *exit_trap, int32_t resolution_us)
897 PlatformContext::Initialize(handler, service, exit_trap, resolution_us);
901 StackMemoryWrapper<STK_RISCV_ISR_STACK_SIZE> stack_isr_mem(&m_stack_isr_mem);
902 m_stack_isr.SP = hw::PtrToWord(InitStackMemory(&stack_isr_mem));
916 m_tick_period = ConvertTimeUsToClockCycles(STK_TIMER_CLOCK_FREQUENCY, resolution_us);
923 #if STK_SUBMICORSECOND_PRECISION_TIMER
924 HW_EnableCycleCounter();
932 HW_CriticalSectionStart(cs);
934 #if STK_TICKLESS_IDLE
938 if (m_handler->OnTick(m_stack_idle, m_stack_active
950 const uint8_t hart = HW_GetHartId();
951 s_StkRiscvStackActive[hart] = m_stack_active;
952 #ifdef _STK_RISCV_USE_PENDSV
953 s_StkRiscvStackIdle[hart] = m_stack_idle;
956 HW_ScheduleContextSwitch(hart);
959 #if STK_TICKLESS_IDLE
960 m_sleep_ticks = ticks;
963 HW_CriticalSectionEnd(cs);
970 HW_CriticalSectionStart(current_ses);
972 if (m_csu_nesting == 0)
975 HW_SpinLockLock(s_StkRiscvCsuLock);
994 if (m_csu_nesting == 0)
997 Word ses_to_restore = m_csu;
1000 HW_SpinLockUnlock(s_StkRiscvCsuLock);
1003 HW_CriticalSectionEnd(ses_to_restore);
1007 uint64_t GetSleepTicksPrev()
1009 #if STK_TICKLESS_IDLE
1010 uint64_t ticks = (
static_cast<uint64_t
>(m_sleep_ticks) *
static_cast<uint64_t
>(m_tick_period));
1012 uint64_t ticks = (1U *
static_cast<uint64_t
>(m_tick_period));
1017 uint64_t GetTimeNow(uint64_t &error)
1019 uint64_t mtime_now = HW_GetMtime();
1020 error = (mtime_now - m_last_mtime) - GetSleepTicksPrev();
1024 void RearmTimer(
const uint64_t mtime_now,
const uint64_t error)
1026 #if STK_TICKLESS_IDLE
1028 STK_ASSERT((
static_cast<uint64_t
>(m_sleep_ticks) *
static_cast<uint64_t
>(m_tick_period)) <= (UINT64_MAX - mtime_now));
1029 const uint64_t next_time = (
static_cast<uint64_t
>(m_sleep_ticks) *
static_cast<uint64_t
>(m_tick_period));
1031 const uint64_t next_time = (1U *
static_cast<uint64_t
>(m_tick_period));
1033 HW_SetMtimecmp(mtime_now + next_time - error);
1034 m_last_mtime = mtime_now;
1043 uint64_t mtime_now = GetTimeNow(error);
1044 __stk_compiler_barrier();
1055 RearmTimer(mtime_now, error);
1058 void StartTickTimer(Timeout elapsed_ticks)
1060 #if STK_TICKLESS_IDLE
1062 m_sleep_ticks = elapsed_ticks;
1066 m_last_mtime = HW_GetMtime();
1067 HW_SetMtimecmp(m_last_mtime + m_tick_period);
1070 set_csr(mie, MIP_MTIP);
1076#if STK_TICKLESS_IDLE
1078 void Resume(Timeout elapsed_ticks);
1081 typedef IPlatform::IEventOverrider eovrd_t;
1082 typedef PlatformRiscV::ISpecificEventHandler sehndl_t;
1083 typedef StackMemoryWrapper<STK_RISCV_ISR_STACK_SIZE>::MemoryType isrmem_t;
1087 isrmem_t m_stack_isr_mem;
1088 JmpFrame m_exit_buf;
1089 eovrd_t *m_overrider;
1090 sehndl_t *m_specific;
1091 uint32_t m_tick_period;
1092 uint64_t m_last_mtime;
1093#if STK_TICKLESS_IDLE
1097 uint8_t m_csu_nesting;
1100 volatile bool m_exiting;
1106#ifdef _STK_RISCV_USE_PENDSV
1108 HW_CriticalSectionStart(cs);
1112 HW_CriticalSectionEnd(cs);
1129 HW_DisableInterrupts();
1139#define STK_ASM_SAVE_CONTEXT_BASE\
1140 SREG " x1, 2*" REGBYTES "(sp) \n"\
1143 SREG " x4, 5*" REGBYTES "(sp) \n"\
1144 SREG " x5, 6*" REGBYTES "(sp) \n"\
1145 SREG " x6, 7*" REGBYTES "(sp) \n"\
1146 SREG " x7, 8*" REGBYTES "(sp) \n"\
1147 SREG " x8, 9*" REGBYTES "(sp) \n"\
1148 SREG " x9, 10*" REGBYTES "(sp) \n"\
1149 SREG " x10, 11*" REGBYTES "(sp) \n"\
1150 SREG " x11, 12*" REGBYTES "(sp) \n"\
1151 SREG " x12, 13*" REGBYTES "(sp) \n"\
1152 SREG " x13, 14*" REGBYTES "(sp) \n"\
1153 SREG " x14, 15*" REGBYTES "(sp) \n"\
1154 SREG " x15, 16*" REGBYTES "(sp) \n"
1156#if (__riscv_32e != 1)
1157#define STK_ASM_SAVE_CONTEXT_RV32I_EXT\
1158 SREG " x16, 17*" REGBYTES "(sp) \n"\
1159 SREG " x17, 18*" REGBYTES "(sp) \n"\
1160 SREG " x18, 19*" REGBYTES "(sp) \n"\
1161 SREG " x19, 20*" REGBYTES "(sp) \n"\
1162 SREG " x20, 21*" REGBYTES "(sp) \n"\
1163 SREG " x21, 22*" REGBYTES "(sp) \n"\
1164 SREG " x22, 23*" REGBYTES "(sp) \n"\
1165 SREG " x23, 24*" REGBYTES "(sp) \n"\
1166 SREG " x24, 25*" REGBYTES "(sp) \n"\
1167 SREG " x25, 26*" REGBYTES "(sp) \n"\
1168 SREG " x26, 27*" REGBYTES "(sp) \n"\
1169 SREG " x27, 28*" REGBYTES "(sp) \n"\
1170 SREG " x28, 29*" REGBYTES "(sp) \n"\
1171 SREG " x29, 30*" REGBYTES "(sp) \n"\
1172 SREG " x30, 31*" REGBYTES "(sp) \n"\
1173 SREG " x31, 32*" REGBYTES "(sp) \n"
1175#define STK_ASM_SAVE_CONTEXT_RV32I_EXT
1178#if (STK_RISCV_FPU != 0)
1179#define STK_ASM_SAVE_CONTEXT_FP\
1180 FSREG " f0, " FOFFSET "+0*" FREGBYTES "(sp) \n"\
1181 FSREG " f1, " FOFFSET "+1*" FREGBYTES "(sp) \n"\
1182 FSREG " f2, " FOFFSET "+2*" FREGBYTES "(sp) \n"\
1183 FSREG " f3, " FOFFSET "+3*" FREGBYTES "(sp) \n"\
1184 FSREG " f4, " FOFFSET "+4*" FREGBYTES "(sp) \n"\
1185 FSREG " f5, " FOFFSET "+5*" FREGBYTES "(sp) \n"\
1186 FSREG " f6, " FOFFSET "+6*" FREGBYTES "(sp) \n"\
1187 FSREG " f7, " FOFFSET "+7*" FREGBYTES "(sp) \n"\
1188 FSREG " f8, " FOFFSET "+8*" FREGBYTES "(sp) \n"\
1189 FSREG " f9, " FOFFSET "+9*" FREGBYTES "(sp) \n"\
1190 FSREG " f10, " FOFFSET "+10*" FREGBYTES "(sp) \n"\
1191 FSREG " f11, " FOFFSET "+11*" FREGBYTES "(sp) \n"\
1192 FSREG " f12, " FOFFSET "+12*" FREGBYTES "(sp) \n"\
1193 FSREG " f13, " FOFFSET "+13*" FREGBYTES "(sp) \n"\
1194 FSREG " f14, " FOFFSET "+14*" FREGBYTES "(sp) \n"\
1195 FSREG " f15, " FOFFSET "+15*" FREGBYTES "(sp) \n"\
1196 FSREG " f16, " FOFFSET "+16*" FREGBYTES "(sp) \n"\
1197 FSREG " f17, " FOFFSET "+17*" FREGBYTES "(sp) \n"\
1198 FSREG " f18, " FOFFSET "+18*" FREGBYTES "(sp) \n"\
1199 FSREG " f19, " FOFFSET "+19*" FREGBYTES "(sp) \n"\
1200 FSREG " f20, " FOFFSET "+20*" FREGBYTES "(sp) \n"\
1201 FSREG " f21, " FOFFSET "+21*" FREGBYTES "(sp) \n"\
1202 FSREG " f22, " FOFFSET "+22*" FREGBYTES "(sp) \n"\
1203 FSREG " f23, " FOFFSET "+23*" FREGBYTES "(sp) \n"\
1204 FSREG " f24, " FOFFSET "+24*" FREGBYTES "(sp) \n"\
1205 FSREG " f25, " FOFFSET "+25*" FREGBYTES "(sp) \n"\
1206 FSREG " f26, " FOFFSET "+26*" FREGBYTES "(sp) \n"\
1207 FSREG " f27, " FOFFSET "+27*" FREGBYTES "(sp) \n"\
1208 FSREG " f28, " FOFFSET "+28*" FREGBYTES "(sp) \n"\
1209 FSREG " f29, " FOFFSET "+29*" FREGBYTES "(sp) \n"\
1210 FSREG " f30, " FOFFSET "+30*" FREGBYTES "(sp) \n"\
1211 FSREG " f31, " FOFFSET "+31*" FREGBYTES "(sp) \n"
1213#define STK_ASM_SAVE_CONTEXT_FP
1216#define STK_ASM_SAVE_CONTEXT_PC_STATUS\
1218 "csrr t1, mstatus \n"\
1219 SREG " t0, 0*" REGBYTES "(sp) \n"\
1220 SREG " t1, 1*" REGBYTES "(sp) \n"
1222#if (STK_RISCV_FPU != 0)
1223#define STK_ASM_SAVE_CONTEXT_FRCSR\
1225 SREG " t0, 4*" REGBYTES "(sp) \n"
1227#define STK_ASM_SAVE_CONTEXT_FRCSR
1230#define STK_ASM_SAVE_CONTEXT\
1231 "addi sp, sp, -" REGSIZE " \n" \
1232 STK_ASM_SAVE_CONTEXT_BASE\
1233 STK_ASM_SAVE_CONTEXT_RV32I_EXT\
1234 STK_ASM_SAVE_CONTEXT_FP\
1235 STK_ASM_SAVE_CONTEXT_PC_STATUS\
1236 STK_ASM_SAVE_CONTEXT_FRCSR
1238#define STK_ASM_LOAD_CONTEXT_BASE\
1239 LREG " x1, 2*" REGBYTES "(sp) \n"\
1242 LREG " x4, 5*" REGBYTES "(sp) \n"\
1243 LREG " x5, 6*" REGBYTES "(sp) \n"\
1244 LREG " x6, 7*" REGBYTES "(sp) \n"\
1245 LREG " x7, 8*" REGBYTES "(sp) \n"\
1246 LREG " x8, 9*" REGBYTES "(sp) \n"\
1247 LREG " x9, 10*" REGBYTES "(sp) \n"\
1248 LREG " x10, 11*" REGBYTES "(sp) \n"\
1249 LREG " x11, 12*" REGBYTES "(sp) \n"\
1250 LREG " x12, 13*" REGBYTES "(sp) \n"\
1251 LREG " x13, 14*" REGBYTES "(sp) \n"\
1252 LREG " x14, 15*" REGBYTES "(sp) \n"\
1253 LREG " x15, 16*" REGBYTES "(sp) \n"
1255#if (__riscv_32e != 1)
1256#define STK_ASM_LOAD_CONTEXT_RV32I_EXT\
1257 LREG " x16, 17*" REGBYTES "(sp) \n"\
1258 LREG " x17, 18*" REGBYTES "(sp) \n"\
1259 LREG " x18, 19*" REGBYTES "(sp) \n"\
1260 LREG " x19, 20*" REGBYTES "(sp) \n"\
1261 LREG " x20, 21*" REGBYTES "(sp) \n"\
1262 LREG " x21, 22*" REGBYTES "(sp) \n"\
1263 LREG " x22, 23*" REGBYTES "(sp) \n"\
1264 LREG " x23, 24*" REGBYTES "(sp) \n"\
1265 LREG " x24, 25*" REGBYTES "(sp) \n"\
1266 LREG " x25, 26*" REGBYTES "(sp) \n"\
1267 LREG " x26, 27*" REGBYTES "(sp) \n"\
1268 LREG " x27, 28*" REGBYTES "(sp) \n"\
1269 LREG " x28, 29*" REGBYTES "(sp) \n"\
1270 LREG " x29, 30*" REGBYTES "(sp) \n"\
1271 LREG " x30, 31*" REGBYTES "(sp) \n"\
1272 LREG " x31, 32*" REGBYTES "(sp) \n"
1274#define STK_ASM_LOAD_CONTEXT_RV32I_EXT
1277#if (STK_RISCV_FPU != 0)
1278#define STK_ASM_LOAD_CONTEXT_FP\
1279 FLREG " f0, " FOFFSET "+0*" FREGBYTES "(sp) \n"\
1280 FLREG " f1, " FOFFSET "+1*" FREGBYTES "(sp) \n"\
1281 FLREG " f2, " FOFFSET "+2*" FREGBYTES "(sp) \n"\
1282 FLREG " f3, " FOFFSET "+3*" FREGBYTES "(sp) \n"\
1283 FLREG " f4, " FOFFSET "+4*" FREGBYTES "(sp) \n"\
1284 FLREG " f5, " FOFFSET "+5*" FREGBYTES "(sp) \n"\
1285 FLREG " f6, " FOFFSET "+6*" FREGBYTES "(sp) \n"\
1286 FLREG " f7, " FOFFSET "+7*" FREGBYTES "(sp) \n"\
1287 FLREG " f8, " FOFFSET "+8*" FREGBYTES "(sp) \n"\
1288 FLREG " f9, " FOFFSET "+9*" FREGBYTES "(sp) \n"\
1289 FLREG " f10, " FOFFSET "+10*" FREGBYTES "(sp) \n"\
1290 FLREG " f11, " FOFFSET "+11*" FREGBYTES "(sp) \n"\
1291 FLREG " f12, " FOFFSET "+12*" FREGBYTES "(sp) \n"\
1292 FLREG " f13, " FOFFSET "+13*" FREGBYTES "(sp) \n"\
1293 FLREG " f14, " FOFFSET "+14*" FREGBYTES "(sp) \n"\
1294 FLREG " f15, " FOFFSET "+15*" FREGBYTES "(sp) \n"\
1295 FLREG " f16, " FOFFSET "+16*" FREGBYTES "(sp) \n"\
1296 FLREG " f17, " FOFFSET "+17*" FREGBYTES "(sp) \n"\
1297 FLREG " f18, " FOFFSET "+18*" FREGBYTES "(sp) \n"\
1298 FLREG " f19, " FOFFSET "+19*" FREGBYTES "(sp) \n"\
1299 FLREG " f20, " FOFFSET "+20*" FREGBYTES "(sp) \n"\
1300 FLREG " f21, " FOFFSET "+21*" FREGBYTES "(sp) \n"\
1301 FLREG " f22, " FOFFSET "+22*" FREGBYTES "(sp) \n"\
1302 FLREG " f23, " FOFFSET "+23*" FREGBYTES "(sp) \n"\
1303 FLREG " f24, " FOFFSET "+24*" FREGBYTES "(sp) \n"\
1304 FLREG " f25, " FOFFSET "+25*" FREGBYTES "(sp) \n"\
1305 FLREG " f26, " FOFFSET "+26*" FREGBYTES "(sp) \n"\
1306 FLREG " f27, " FOFFSET "+27*" FREGBYTES "(sp) \n"\
1307 FLREG " f28, " FOFFSET "+28*" FREGBYTES "(sp) \n"\
1308 FLREG " f29, " FOFFSET "+29*" FREGBYTES "(sp) \n"\
1309 FLREG " f30, " FOFFSET "+30*" FREGBYTES "(sp) \n"\
1310 FLREG " f31, " FOFFSET "+31*" FREGBYTES "(sp) \n"
1312#define STK_ASM_LOAD_CONTEXT_FP
1315#define STK_ASM_LOAD_CONTEXT_PC_STATUS\
1316 LREG " t0, 0*" REGBYTES "(sp) \n"\
1317 LREG " t1, 1*" REGBYTES "(sp) \n"\
1319 "csrw mstatus, t1 \n"
1321#if (STK_RISCV_FPU != 0)
1322#define STK_ASM_LOAD_CONTEXT_FRCSR\
1323 LREG " t0, 4*" REGBYTES "(sp) \n" \
1326#define STK_ASM_LOAD_CONTEXT_FRCSR
1329#define STK_ASM_LOAD_CONTEXT\
1330 STK_ASM_LOAD_CONTEXT_PC_STATUS\
1331 STK_ASM_LOAD_CONTEXT_FRCSR\
1332 STK_ASM_LOAD_CONTEXT_BASE\
1333 STK_ASM_LOAD_CONTEXT_RV32I_EXT\
1334 STK_ASM_LOAD_CONTEXT_FP\
1335 "addi sp, sp, " REGSIZE " \n"
1341 LREG
" sp, 0(t0) \n"
1343 STK_ASM_LOAD_CONTEXT
1344 STK_ASM_EXIT_FROM_HANDLER
" \n"
1348 :
"t0",
"t1",
"a2",
"a3",
"a4",
"a5",
"gp",
"memory");
1353#if (STK_RISCV_FPU != 0)
1357 :
"r"(MSTATUS_FS | MSTATUS_XS)
1364#if (STK_RISCV_FPU != 0)
1403 __asm
volatile(
"csrr %0, mcause" :
"=r"(mcause));
1409 Word current_sp = HW_GetCallerSP();
1414 const Word isr_stack_top = isr_stack_base + STK_RISCV_ISR_STACK_SIZE;
1416 return ((current_sp >= isr_stack_base) && (current_sp < isr_stack_top));
1421 HW_LoadContextAndExit();
1425extern "C" STK_RISCV_ISR_SECTION
__stk_attr_used void TrySwitchContext()
1430#ifdef _STK_RISCV_USE_PENDSV
1431extern "C" STK_RISCV_ISR_SECTION
__stk_attr_naked void STK_SYSTICK_HANDLER()
1435 STK_ASM_SAVE_CONTEXT
1438#if (STK_ARCH_CPU_COUNT > 1)
1439 "csrr t0, mhartid \n"
1440 "la t1, s_StkRiscvSpIsrInt \n"
1441 "slli t0, t0, " REGBYTES_LOG2
" \n"
1443 SREG
" sp, 0(t1) \n"
1445 "la t1, s_StkRiscvSpIsrInt \n"
1446 SREG
" sp, 0(t1) \n"
1450#if (STK_ARCH_CPU_COUNT > 1)
1451 "csrr t0, mhartid \n"
1452 "la t1, s_StkRiscvStackIsr \n"
1453 "slli t0, t0, " REGBYTES_LOG2
" \n"
1455 LREG
" t1, 0(t1) \n"
1457 "la t1, s_StkRiscvStackIsr \n"
1458 LREG
" t1, 0(t1) \n"
1460 LREG
" sp, 0(t1) \n"
1463 "jal ra, TrySwitchContext \n"
1466#if (STK_ARCH_CPU_COUNT > 1)
1467 "csrr t0, mhartid \n"
1468 "la t1, s_StkRiscvSpIsrInt \n"
1469 "slli t0, t0, " REGBYTES_LOG2
" \n"
1471 LREG
" sp, 0(t1) \n"
1473 "la t1, s_StkRiscvSpIsrInt \n"
1474 LREG
" sp, 0(t1) \n"
1478 STK_ASM_LOAD_CONTEXT
1481 STK_ASM_EXIT_FROM_HANDLER
" \n"
1491 STK_ASM_SAVE_CONTEXT
1497#if (STK_ARCH_CPU_COUNT > 1)
1498 "csrr t0, mhartid \n"
1499 "la t1, s_StkRiscvStackIdle \n"
1500 "slli t0, t0, " REGBYTES_LOG2
" \n"
1502 LREG
" t1, 0(t1) \n"
1504 "la t1, s_StkRiscvStackIdle \n"
1505 LREG
" t1, 0(t1) \n"
1507 SREG
" sp, 0(t1) \n"
1510#if (STK_ARCH_CPU_COUNT > 1)
1511 "csrr t0, mhartid \n"
1513 "li t1, %[clint_msip_base] \n"
1516 "li t0, %[clint_msip_base] \n"
1522#if (STK_ARCH_CPU_COUNT > 1)
1523 "csrr t0, mhartid \n"
1524 "la t1, s_StkRiscvStackActive \n"
1525 "slli t0, t0, " REGBYTES_LOG2
" \n"
1527 LREG
" t1, 0(t1) \n"
1529 "la t1, s_StkRiscvStackActive \n"
1530 LREG
" t1, 0(t1) \n"
1532 LREG
" sp, 0(t1) \n"
1535 STK_ASM_LOAD_CONTEXT
1538 STK_ASM_EXIT_FROM_HANDLER
" \n"
1541 : [clint_msip_base]
"i" (STK_RISCV_CLINT_BASE_ADDR)
1585extern "C" STK_RISCV_ISR_SECTION
__stk_attr_naked void STK_SYSTICK_HANDLER()
1589 STK_ASM_SAVE_CONTEXT
1595#if (STK_ARCH_CPU_COUNT > 1)
1596 "csrr t0, mhartid \n"
1597 "la t1, s_StkRiscvStackActive \n"
1598 "slli t0, t0, " REGBYTES_LOG2
" \n"
1600 LREG
" t1, 0(t1) \n"
1602 "la t1, s_StkRiscvStackActive \n"
1603 LREG
" t1, 0(t1) \n"
1605 SREG
" sp, 0(t1) \n"
1608#if (STK_ARCH_CPU_COUNT > 1)
1609 "csrr t0, mhartid \n"
1610 "la t1, s_StkRiscvStackIsr \n"
1611 "slli t0, t0, " REGBYTES_LOG2
" \n"
1613 LREG
" t1, 0(t1) \n"
1615 "la t1, s_StkRiscvStackIsr \n"
1616 LREG
" t1, 0(t1) \n"
1618 LREG
" sp, 0(t1) \n"
1625 "jal ra, TrySwitchContext \n"
1630#if (STK_ARCH_CPU_COUNT > 1)
1631 "csrr t0, mhartid \n"
1632 "la t1, s_StkRiscvStackActive \n"
1633 "slli t0, t0, " REGBYTES_LOG2
" \n"
1635 LREG
" t1, 0(t1) \n"
1637 "la t1, s_StkRiscvStackActive \n"
1638 LREG
" t1, 0(t1) \n"
1640 LREG
" sp, 0(t1) \n"
1643 STK_ASM_LOAD_CONTEXT
1646 STK_ASM_EXIT_FROM_HANDLER
" \n"
1655void Context::OnStart()
1657 const uint8_t hart = HW_GetHartId();
1663 HW_EnableFullFpuAccess();
1669 m_handler->OnStart(m_stack_active);
1672 s_StkRiscvStackIsr[hart] = &m_stack_isr;
1673 s_StkRiscvStackActive[hart] = m_stack_active;
1674#ifdef _STK_RISCV_USE_PENDSV
1675 s_StkRiscvStackIdle[hart] = m_stack_idle;
1686#ifdef _STK_RISCV_USE_PENDSV
1687 set_csr(mie, MIP_MSIP);
1691STK_RISCV_ISR
void STK_SVC_HANDLER()
1693 Word cause = HW_GetCurrentException();
1705 if (cause == IRQ_M_EXT)
1715 write_csr(mepc, read_csr(mepc) +
sizeof(
Word));
1720 HW_DisableInterrupts();
1746static void OnTaskRun(
ITask *task)
1751static void OnTaskExit()
1754 HW_CriticalSectionStart(cs);
1758 HW_CriticalSectionEnd(cs);
1767static STK_RISCV_ISR_SECTION
void OnSchedulerSleep()
1769#if STK_SEGGER_SYSVIEW
1770 SEGGER_SYSVIEW_OnIdle();
1780static STK_RISCV_ISR_SECTION
void OnSchedulerSleepOverride()
1786static void OnSchedulerExit()
1797 GetContext().Initialize(event_handler, service, exit_trap, resolution_us);
1800void Context::Start()
1805 SaveJmp(m_exit_buf);
1809 m_handler->OnStop();
1814 HW_EnableFullFpuAccess();
1818 HW_StartScheduler();
1821#if STK_TICKLESS_IDLE
1827 HW_DisableInterrupts();
1833 HW_ClearPendingSwitch();
1837 const uint32_t elapsed = HW_GetMtime() - m_last_mtime;
1841 Timeout elapsed_ticks =
static_cast<Timeout>(elapsed / resolution);
1842 Timeout sleep_ticks =
Max(m_sleep_ticks - elapsed_ticks,
static_cast<Timeout>(0));
1845 m_handler->OnSuspend(
true);
1847 HW_EnableInterrupts();
1853#if STK_TICKLESS_IDLE
1854void Context::Resume(
Timeout elapsed_ticks)
1856 HW_DisableInterrupts();
1859 m_handler->OnSuspend(
false);
1862 StartTickTimer(elapsed_ticks + 1);
1864 HW_EnableInterrupts();
1877 "TaskFrame size must match REGSIZE: (REGISTER_COUNT + SERVICE_SLOTS) * REGBYTES");
1885 stack->
SP =
hw::PtrToWord(stack_top - (STK_RISCV_REGISTER_COUNT + STK_SERVICE_SLOTS));
1888 TaskFrame *
const task_frame =
reinterpret_cast<TaskFrame *
>(stack->
SP);
1900 task_frame->MEPC =
hw::PtrToWord(
GetContext().m_overrider != NULL ? &OnSchedulerSleepOverride : &OnSchedulerSleep);
1915 task_frame->MSTATUS = MSTATUS_MPP | MSTATUS_MPIE | (STK_RISCV_FPU != 0 ? (MSTATUS_FS | MSTATUS_XS) : 0);
1917#if (STK_RISCV_FPU != 0)
1918 task_frame->X3_FSR = 0;
1924void Context::OnStop()
1930 HW_ClearPendingSwitch();
1945 HW_DisableInterrupts();
1956 return static_cast<Cycles>(HW_GetMtime());
1961 return HW_MtimeClockFrequency();
1966 GetContext().m_handler->OnTaskSwitch(HW_GetCallerSP());
1971 GetContext().m_handler->OnTaskSleep(HW_GetCallerSP(), ticks);
1976 GetContext().m_handler->OnTaskSleepUntil(HW_GetCallerSP(), timestamp);
1981 return GetContext().m_handler->OnTaskWait(HW_GetCallerSP(), sync_obj, mutex, timeout);
1986 if (HW_IsHandlerMode())
1990 const Word exc = HW_GetCurrentException();
1992 Word num = (exc & 0x7FFU);
1994 #if (__riscv_xlen > 32)
1995 Word interrupt_bit = ((exc & (1ULL << (__riscv_xlen - 1))) ? 0x800U : 0);
1997 Word interrupt_bit = ((exc & (1U << (__riscv_xlen - 1))) ? 0x800U : 0);
2005 return GetContext().m_handler->OnGetTid(HW_GetCallerSP());
2010#if STK_TICKLESS_IDLE
2019#if STK_TICKLESS_IDLE
2042 return HW_GetCallerSP();
2068 HW_SpinLockLock(m_lock);
2073 HW_SpinLockUnlock(m_lock);
2078 return HW_SpinLockTryLock(m_lock);
2083 return HW_IsHandlerMode();
2088 return HiResClockImpl::GetInstance()->GetCycles();
2093 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_KERNEL_PANIC(id)
Called when the kernel detects an unrecoverable internal fault.
#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_TICKLESS_IDLE
Enables tickless (dynamic-tick) low-power operation during idle periods.
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
#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).
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.
static __stk_forceinline Cycles ConvertTimeUsToClockCycles(Cycles clock_freq, Ticks time_us)
Convert time (microseconds) to core clock cycles.
static bool IsIsrTid(TId tid)
Test whether a task identifier represents an ISR context.
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.
uint64_t Cycles
Cycles value.
@ ACCESS_PRIVILEGED
Privileged access mode (access to hardware is fully unrestricted).
EKernelPanicId
Identifies the source of a kernel panic.
@ 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.
__stk_forceinline Word PtrToWord(T *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).
uint32_t GetSysTimerFrequency() const
Get system timer frequency.
void SetEventOverrider(IEventOverrider *overrider)
Set platform event overrider.
void Initialize(IEventHandler *event_handler, IKernelService *service, uint32_t resolution_us, Stack *exit_trap)
Initialize scheduler's context.
void SleepUntil(Ticks timestamp)
Put calling process into a sleep state until the specified timestamp.
Timeout Suspend()
Suspend scheduling.
void SetSpecificEventHandler(ISpecificEventHandler *handler)
void Stop()
Stop scheduling.
void Sleep(Timeout ticks)
Put calling process into a sleep state.
void SwitchToNext()
Switch to a next task.
void ProcessTick()
Process one tick.
uint32_t GetTickResolution() const
Get resolution of the system tick timer in microseconds. Resolution means a number of microseconds be...
bool InitStack(EStackType stack_type, Stack *stack, IStackMemory *stack_memory, ITask *user_task)
Initialize stack memory of the user task.
void ProcessHardFault()
Cause a hard fault of the system.
void Resume(Timeout elapsed_ticks)
Resume scheduling after a prior Suspend() call.
IWaitObject * Wait(ISyncObject *sync_obj, IMutex *mutex, Timeout timeout)
Word GetCallerSP() const
Get caller's Stack Pointer (SP).
TId GetTid() const
Get thread Id.
void Start()
Start scheduling.
Cycles GetSysTimerCount() const
Get system timer count value.
Base platform context for all platform implementations.
static Word * InitStackMemory(IStackMemory *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.