SuperTinyKernel™ RTOS 1.06.x
Lightweight, high-performance, deterministic, bare-metal C++ RTOS for resource-constrained embedded systems. MIT Open Source License.
Loading...
Searching...
No Matches
stk::hw Namespace Reference

Hardware Abstraction Layer (HAL) for architecture-specific operations. More...

Classes

class  CriticalSection
 Nestable, SMP-safe critical section that combines local interrupt masking with a global cross-core spinlock. More...
class  SpinLock
 Atomic busy-wait lock used as the global cross-core synchronisation primitive inside CriticalSection. More...
class  HiResClock
 High-resolution clock for high-precision measurements. More...

Functions

template<typename T>
static constexpr Word PtrToWord (T *const ptr) noexcept
 Cast a pointer to a CPU register-width integer.
template<typename T>
static constexpr T * WordToPtr (Word value) noexcept
 Cast a CPU register-width integer back to a pointer.
bool IsInsideISR ()
 Check whether the CPU is currently executing inside a hardware interrupt service routine (ISR).
template<typename T>
static __stk_forceinlineReadVolatile64 (volatile const T *addr)
 Atomically read a 64-bit volatile value.
template<typename T>
static __stk_forceinline void WriteVolatile64 (volatile T *addr, T value)
 Atomically write a 64-bit volatile value.

Detailed Description

Hardware Abstraction Layer (HAL) for architecture-specific operations.

This namespace contains low-level functions that interface directly with the CPU registers and hardware state. Implementations live in the architecture back-end headers included above and are typically written in assembly or using compiler intrinsics for maximum performance and minimum latency.

See also
IsInsideISR, GetTlsPtr, SetTlsPtr, CriticalSection, SpinLock, ReadVolatile64, WriteVolatile64

Function Documentation

◆ IsInsideISR()

bool stk::hw::IsInsideISR ( )

Check whether the CPU is currently executing inside a hardware interrupt service routine (ISR).

Returns
true if called from an ISR context; false if called from a normal task/thread context.
Note
Used as a guard in all ISR-unsafe kernel functions (Sleep, Delay, Yield, GetTid, etc.) to catch accidental calls from interrupt context that would deadlock the scheduler.
ISR-safe itself: may be called from any context.

References __stk_forceinline.

Referenced by stk::Kernel< TMode, TSize, TStrategy, TPlatform >::KernelService::Delay(), IsIrqContext(), IsIrqContext(), stk::Kernel< TMode, TSize, TStrategy, TPlatform >::KernelService::Sleep(), stk::Kernel< TMode, TSize, TStrategy, TPlatform >::KernelService::SleepUntil(), stk_blockpool_alloc(), stk::Kernel< TMode, TSize, TStrategy, TPlatform >::KernelService::SwitchToNext(), stk::memory::BlockMemoryPool::TimedAlloc(), stk::sync::Mutex::TimedLock(), stk::sync::SpinLock::Unlock(), stk::sync::ConditionVariable::Wait(), stk::sync::Event::Wait(), stk::sync::EventFlags::Wait(), and stk::sync::Semaphore::Wait().

Here is the caller graph for this function:

◆ PtrToWord()

template<typename T>
constexpr Word stk::hw::PtrToWord ( T *const ptr)
staticconstexprnoexcept

Cast a pointer to a CPU register-width integer.

Template Parameters
TThe type of the object pointed to.
Parameters
[in]ptrThe pointer to be converted.
Returns
The numeric value of the pointer as a Word.
Note
This operation is used to store pointers within task context structures or stack frames where raw register values are required.
MISRA deviation: [STK-DEV-001] Rule 5-2-7 (reinterpret_cast). This is a mechanical necessity for low-level kernel operations where the hardware requires integral values for address registers.
See also
WordToPtr

Definition at line 106 of file stk_arch.h.

107{
108 STK_STATIC_ASSERT(sizeof(Word) == sizeof(T *));
109 return reinterpret_cast<Word>(ptr);
110}
#define STK_STATIC_ASSERT(X)
Compile-time assertion. Produces a compilation error if X is false.
Definition stk_defs.h:446
uintptr_t Word
Native processor word type.
Definition stk_common.h:115

References STK_STATIC_ASSERT.

Referenced by stk::memory::MemoryAllocator::AllocateArrayT(), stk::memory::BlockMemoryPool::BuildFreeList(), stk::memory::BlockMemoryPool::Free(), stk::memory::MemoryAllocator::FreeArrayT(), stk::GetTidFromUserTask(), stk::PlatformContext::InitStackMemory(), stk::Kernel< TMode, TSize, TStrategy, TPlatform >::KernelTask::IsMemoryOfSP(), ReadVolatile64(), STK_MEMCPY(), and WriteVolatile64().

Here is the caller graph for this function:

◆ ReadVolatile64()

template<typename T>
__stk_forceinline T stk::hw::ReadVolatile64 ( volatile const T * addr)
static

Atomically read a 64-bit volatile value.

Template Parameters
TMust be exactly 8 bytes wide and at least 4-byte aligned (enforced by static assertions).
Parameters
[in]addrPointer to the volatile 64-bit memory location.
Returns
Consistent 64-bit snapshot of the value at addr.
Note
On 64-bit architectures a single aligned load is inherently atomic, the value is read directly with no additional protocol.
On 32-bit architectures uses a lock-free hi-lo retry protocol compatible with WriteVolatile64: reads the high half, then the low half, then re-reads the high half. If the high half changed between the first and second read, a tick occurred between the two 32-bit loads and the pair is retried until a consistent snapshot is obtained. Requires that WriteVolatile64 writes hi before lo (which it does).
Requires a single writer that uses WriteVolatile64. Safe with multiple concurrent readers. Not C++ memory-model compliant, intended for bare-metal embedded use only.
MISRA deviation: [STK-DEV-002] Rule 5-2-7, 5-0-15. Required for lock-free 64-bit I/O on 32-bit architectures using a Hi-Lo retry protocol.
Warning
Not safe for read-modify-write operations. Use only for polling a value written atomically by a single producer.
See also
WriteVolatile64

Definition at line 379 of file stk_arch.h.

380{
381 STK_STATIC_ASSERT_N(sz, sizeof(T) == 8U); // only 64-bit types permitted
382 STK_STATIC_ASSERT_N(al, alignof(T) >= 4U); // type must be at least 4-byte aligned
385
386 if __stk_constexpr_cpp17 (sizeof(void *) == 8U) // 64-bit arch: aligned 64-bit load is inherently atomic
387 {
388 return (*addr);
389 }
390 else
391 {
392 // 32-bit arch: split the 64-bit address into two 32-bit halves;
393 // writer always updates hi before lo (see WriteVolatile64), so if hi is
394 // the same before and after reading lo, no write straddled the two reads.
395 #if STK_STRICT_COMPLIANCY
396 const Word p_base = hw::PtrToWord(addr);
397 volatile const uint32_t *const plo = hw::WordToPtr<uint32_t>(p_base + (STK_ENDIAN_IDX_LO * sizeof(uint32_t)));
398 volatile const uint32_t *const phi = hw::WordToPtr<uint32_t>(p_base + (STK_ENDIAN_IDX_HI * sizeof(uint32_t)));
399 #else
400 volatile const uint32_t *const p_base = reinterpret_cast<volatile const uint32_t *>(addr);
401 volatile const uint32_t *const plo = &p_base[STK_ENDIAN_IDX_LO];
402 volatile const uint32_t *const phi = &p_base[STK_ENDIAN_IDX_HI];
403 #endif
404
405 uint32_t hi, lo;
406 do
407 {
408 hi = (*phi);
409 __stk_full_memfence();
410
411 lo = (*plo);
412 __stk_full_memfence();
413 }
414 while (hi != (*phi)); // hi changed: a write occurred during the read; retry
415
416 const uint64_t result = (static_cast<uint64_t>(hi) << 32U) | static_cast<uint64_t>(lo);
417
418 return static_cast<T>(result);
419 }
420}
#define STK_STATIC_ASSERT_N(NAME, X)
Compile-time assertion with a user-defined name suffix.
Definition stk_defs.h:438
#define STK_ENDIAN_IDX_LO
Array index of the low 32-bit word when a 64-bit value is viewed as uint32_t[2].
Definition stk_defs.h:587
#define STK_ENDIAN_IDX_HI
Array index of the high 32-bit word when a 64-bit value is viewed as uint32_t[2].
Definition stk_defs.h:586
#define __stk_constexpr_cpp17
constexpr definition for C++17 and above.
Definition stk_defs.h:382
static constexpr T * WordToPtr(Word value) noexcept
Cast a CPU register-width integer back to a pointer.
Definition stk_arch.h:123
static constexpr Word PtrToWord(T *const ptr) noexcept
Cast a pointer to a CPU register-width integer.
Definition stk_arch.h:106

References __stk_constexpr_cpp17, __stk_forceinline, PtrToWord(), STK_ENDIAN_IDX_HI, STK_ENDIAN_IDX_LO, STK_STATIC_ASSERT_N, and WordToPtr().

Referenced by stk::Kernel< TMode, TSize, TStrategy, TPlatform >::KernelService::GetTicks(), and stk::time::TimerHost::GetTimeNow().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ WordToPtr()

template<typename T>
constexpr T * stk::hw::WordToPtr ( Word value)
staticconstexprnoexcept

Cast a CPU register-width integer back to a pointer.

Template Parameters
TThe type of the object the resulting pointer will address.
Parameters
[in]valueThe register-width integer (Word) to be converted.
Returns
A pointer of type T* addressing the memory location specified by the value.
Note
This is the inverse of PtrToWord and is primarily used when restoring a task's context from a saved stack frame.
MISRA deviation: [STK-DEV-001] Rule 5-2-7 (reinterpret_cast). Required for restoring pointer types from numeric CPU context structures.
See also
PtrToWord

Definition at line 123 of file stk_arch.h.

124{
125 STK_STATIC_ASSERT(sizeof(Word) == sizeof(T *));
126 return reinterpret_cast<T *>(value);
127}

References STK_STATIC_ASSERT.

Referenced by stk::memory::BlockMemoryPool::BuildFreeList(), stk::GetUserTaskFromTid(), ReadVolatile64(), and WriteVolatile64().

Here is the caller graph for this function:

◆ WriteVolatile64()

template<typename T>
__stk_forceinline void stk::hw::WriteVolatile64 ( volatile T * addr,
T value )
static

Atomically write a 64-bit volatile value.

Template Parameters
TMust be exactly 8 bytes wide and at least 4-byte aligned (enforced by static assertions).
Parameters
[in]addrPointer to the volatile 64-bit memory location.
[in]valueValue to write.
Note
On 64-bit architectures a single aligned store is inherently atomic.
On 32-bit architectures the value is split into two 32-bit half-writes. The high half is always written before the low half. This ordering is the contractual invariant that ReadVolatile64 depends on to detect a mid-write tear: if a reader observes a changed high half, it knows a write occurred and retries. Breaking this order (writing lo before hi) will corrupt concurrent reads.
A full memory fence is emitted between the two half-writes to prevent the CPU from reordering the stores.
ISR-safe: does not use a critical section.
MISRA deviation: [STK-DEV-002] Rule 5-2-7, 5-0-15. Required for lock-free 64-bit I/O on 32-bit architectures using a Hi-Lo retry protocol.
Warning
Supports only a single writer at a time. Concurrent writers on the same address will corrupt the value. Not safe for read-modify-write operations (e.g. increment); the caller must ensure exclusive write access by other means.
Not C++ memory-model compliant; intended for bare-metal embedded use only.
See also
ReadVolatile64

Definition at line 444 of file stk_arch.h.

445{
446 STK_STATIC_ASSERT_N(sz, sizeof(T) == 8U); // only 64-bit types permitted
447 STK_STATIC_ASSERT_N(al, alignof(T) >= 4U); // type must be at least 4-byte aligned
450
451 if __stk_constexpr_cpp17 (sizeof(void *) == 8U) // 64-bit arch: aligned 64-bit store is inherently atomic
452 {
453 (*addr) = value;
454 }
455 else
456 {
457 #if STK_STRICT_COMPLIANCY
458 const Word p_base = hw::PtrToWord(addr);
459 volatile uint32_t *const plo = hw::WordToPtr<uint32_t>(p_base + (STK_ENDIAN_IDX_LO * sizeof(uint32_t)));
460 volatile uint32_t *const phi = hw::WordToPtr<uint32_t>(p_base + (STK_ENDIAN_IDX_HI * sizeof(uint32_t)));
461 #else
462 volatile uint32_t *const p_base = reinterpret_cast<volatile uint32_t *>(addr);
463 volatile uint32_t *const plo = &p_base[STK_ENDIAN_IDX_LO];
464 volatile uint32_t *const phi = &p_base[STK_ENDIAN_IDX_HI];
465 #endif
466
467 // write hi first: ReadVolatile64 reads hi twice and retries if it changed,
468 // so writing hi before lo ensures readers can detect a torn write.
469 (*phi) = static_cast<uint32_t>(static_cast<uint64_t>(value) >> 32U);
470 __stk_full_memfence();
471
472 (*plo) = static_cast<uint32_t>(value);
473 }
474}

References __stk_constexpr_cpp17, __stk_forceinline, PtrToWord(), STK_ENDIAN_IDX_HI, STK_ENDIAN_IDX_LO, STK_STATIC_ASSERT_N, and WordToPtr().

Referenced by stk::Kernel< TMode, TSize, TStrategy, TPlatform >::KernelService::IncrementTicks(), and stk::time::TimerHost::UpdateTime().

Here is the call graph for this function:
Here is the caller graph for this function: