# MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI) # RUMPK CORE // FIBER # The atom of execution. {.push stackTrace: off, lineTrace: off.} type FiberState* = object sp*: uint64 # The Stack Pointer (Must be first field!) entry*: proc() {.cdecl.} # Entry point for this fiber Fiber* = ptr FiberObject FiberObject* = object id*: uint64 name*: cstring state*: FiberState stack*: ptr UncheckedArray[uint8] stack_size*: int # Import the Assembly Magic proc cpu_switch_to(prev_sp_ptr: ptr uint64, next_sp: uint64) {.importc, cdecl.} # Import console for debugging proc console_write(p: pointer, len: csize_t) {.importc, cdecl.} proc debug(s: string) = if s.len > 0: console_write(unsafeAddr s[0], csize_t(s.len)) # Context Frame Size: 6 pairs * 16 bytes = 96 bytes (16-byte aligned!) const CONTEXT_SIZE = 96 # Stack Helper (Simple 4KB aligned stack) const STACK_SIZE* = 4096 # We need a "Main" fiber to represent the boot thread var main_fiber: FiberObject var current_fiber*: Fiber = addr main_fiber # Trampoline that calls the fiber's entry point proc fiber_trampoline() {.cdecl, exportc, noreturn.} = let f = current_fiber if f.state.entry != nil: f.state.entry() # If the fiber returns, halt while true: {.emit: "asm volatile(\"wfi\");".} proc init_fiber*(f: Fiber, entry: proc() {.cdecl.}, stack_base: pointer) = f.state.entry = entry # Start at top of stack var sp = cast[uint64](stack_base) + STACK_SIZE # 1. Align to 16 bytes (Strict requirement) sp = sp and not 15'u64 # 2. Reserve space for the context frame (96 bytes) sp = sp - CONTEXT_SIZE # 3. Setup the Context var stack_ptr = cast[ptr UncheckedArray[uint64]](sp) # Zero out registers x19-x28 (indices 0-9) for i in 0..<10: stack_ptr[i] = 0 # Set x29 (FP) to 0 - Offset 80 / 8 = index 10 stack_ptr[10] = 0 # Set x30 (LR) to trampoline - Offset 88 / 8 = index 11 stack_ptr[11] = cast[uint64](fiber_trampoline) f.state.sp = sp proc switch*(next: Fiber) = let prev = current_fiber current_fiber = next cpu_switch_to(addr prev.state.sp, next.state.sp) {.pop.}