Reorganize source tree: kernel/, v3/, v4/ split and board infrastructure

Source tree reorganization:
- Move StarForth v3 engine to v3/ (src/, include/, Makefile)
- Move kernel to kernel/ (src/, include/, linker/, Makefile)
- Create v4/ skeleton for F18-ISA golden model (DECOMPOSITION.md, JUSTIFICATION.md)
- Move FABRIC-0..4.md to docs/fabric/
- Move ONTOLOGY.md and ROADMAP.md to docs/

Board infrastructure:
- Add boards/ser5/, boards/raspi/, boards/milkv/, boards/zynq7020/
- Each board has board.mk (ISA, CPU flags, boot recipe) and README.md
- Root Makefile becomes thin dispatcher: boot_image, all, clean, docs take TARGET
- make boot_image TARGET=SER5|RASPI|MILKV builds one GPT/MBR image per board
- ZYNQ7020 target exists but stops with clear error (ARMv7 port not built yet)
- scripts/mkdiskimage.sh builds disk images for all boards

Docs pipeline:
- docs/book/ with LaTeX master (main.tex) and Makefile
- pandoc converts Markdown to LaTeX at build time
- Two Lua filters: table-widths.lua (wide tables wrap), code-breaks.lua (inline code breaks)
- make docs builds single PDF (754 pages, 0 missing characters)
- make docs TARGET=<board> adds board appendix
- build/docs/<book|board>/meta.tex stamps git commit into PDF

Bug fixes:
- 42 include paths that only worked by accident now use correct relative paths
- clang-18 hardcode replaced with configurable CC variable (fixed aarch64 build)
- Pi 5: kernel_2712.img linked at 0x80000, .bss zeroed, memory reserved
- Doxyfile, .clang-tidy, README.md, Kconfig paths updated

Verified:
- Hosted v3 build passes 1012 tests, 0 failures
- SER5 image boots in QEMU (OVMF), POST passes, K exact (65536 = Q48_ONE)
- Milk-V image boots in QEMU (OpenSBI + U-Boot + bootefi), POST passes
- make clean TARGET=<board> removes only that board and its ISA objects
- make all builds all boards, hosted v3, and docs in one run

Co-authored-by: Junie <junie@jetbrains.com>
This commit is contained in:
rajames
2026-10-01 15:40:09 -04:00
co-authored by Junie
parent 3c709c115b
commit a8b70e88d3
630 changed files with 2646 additions and 2036 deletions
+643
View File
@@ -0,0 +1,643 @@
/*
StarForth — Steady-State Virtual Machine Runtime
Copyright (c) 2023–2025 Robert A. James
All rights reserved.
This file is part of the StarForth project.
Licensed under the StarForth License, Version 1.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
https://github.com/star.4th@proton.me/StarForth/LICENSE.txt
This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND,
express or implied, including but not limited to the warranties of
merchantability, fitness for a particular purpose, and noninfringement.
See the License for the specific language governing permissions and
limitations under the License.
StarForth — Steady-State Virtual Machine Runtime
Copyright (c) 2023–2025 Robert A. James
All rights reserved.
This file is part of the StarForth project.
Licensed under the StarForth License, Version 1.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
https://github.com/star.4th@proton.me/StarForth/LICENSE.txt
This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND,
express or implied, including but not limited to the warranties of
merchantability, fitness for a particular purpose, and noninfringement.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
*** StarForth ***
vm_inner_interp_asm.h - Optimized Inner Interpreter using Direct Threading
Compatible with: Linux, bare metal x86_64
HISTORICAL: the "L4Re Compatibility"/"L4RE INTEGRATION NOTES" throughout
this file describe a target that was supported through mid-2026. L4Re
support has since been removed as an active target; these notes are
retained as historical design rationale.
This work is released under license terms in LICENSE file.
No warranty. Use at your own risk.
*/
#ifndef VM_INNER_INTERP_ASM_H
#define VM_INNER_INTERP_ASM_H
#include "vm.h"
/*
* INNER INTERPRETER OPTIMIZATION
* ===============================
*
* This is the MOST CRITICAL optimization for Forth performance.
*
* Background:
* -----------
* Forth uses "threaded code" where compiled words are sequences of pointers
* to other words. The inner interpreter's job is to:
* 1. Fetch the next word pointer (IP)
* 2. Execute that word
* 3. Increment IP
* 4. Repeat
*
* Traditional C implementation has massive overhead:
* - Function call/return for each word (push/pop return address)
* - Register spilling
* - No tail-call optimization in most C compilers
*
* This optimization uses:
* - Direct threading: Each word ends with a jump to NEXT
* - Register allocation: Keep IP, SP, RP in registers
* - Tail calls: Use jmp instead of call/ret
* - Computed goto: Fast dispatch using indirect jump
*
* Performance Impact:
* ------------------
* Can improve interpreter speed by 2-5x for threaded code execution
*
* L4Re Compatibility: YES
* All operations are unprivileged and pure computation
*/
#ifndef USE_DIRECT_THREADING
#define USE_DIRECT_THREADING 0
#endif
#if USE_DIRECT_THREADING
/**
* @brief Register allocation strategy for optimized execution
*
* Register usage:
* @arg r12 VM pointer (callee-saved, preserved across calls)
* @arg r13 Instruction Pointer (IP) - points to current cell
* @arg r14 Data Stack Pointer (DSP) - points to vm->data_stack[vm->dsp]
* @arg r15 Return Stack Pointer (RSP) - points to vm->return_stack[vm->rsp]
*
* Callee-saved registers are used because:
* - They're preserved across function calls
* - Allows mixing C and assembly code
* - No need to save/restore on each word execution
*/
/**
* @brief Core inner interpreter macro - executes next word
* @details Fetches next word pointer from IP, increments IP, and jumps to word
*/
#define NEXT_ASM() \
__asm__ __volatile__ ( \
"movq (%%r13), %%rax\n\t" /* Load word pointer from [IP] */ \
"addq $8, %%r13\n\t" /* IP++ */ \
"jmpq *%%rax\n\t" /* Jump to word's code */ \
::: "rax", "memory" \
)
/**
* @brief Enter a colon definition (DOCOL)
* @param vm Pointer to VM instance
* @details Called when executing a user-defined word
*/
static inline void vm_docol_asm(VM *vm) {
__asm__ __volatile__(
/* Save current IP on return stack */
"movq %%r13, (%%r15)\n\t" /* *RSP = IP */
"addq $8, %%r15\n\t" /* RSP++ */
/* IP = address of colon definition body (from DictEntry) */
"movq %[entry], %%rax\n\t"
"movq (%%rax), %%r13\n\t" /* IP = entry->code_field */
/* Continue with NEXT */
"movq (%%r13), %%rax\n\t"
"addq $8, %%r13\n\t"
"jmpq *%%rax\n\t"
:
: [entry]"r"(vm->current_executing_entry)
: "rax", "r13", "r15", "memory"
);
}
/**
* @brief Return from a colon definition (EXIT)
* @details Pops IP from return stack and continues execution
*/
static inline void vm_exit_asm(void) {
__asm__ __volatile__(
/* Restore IP from return stack */
"subq $8, %%r15\n\t" /* RSP-- */
"movq (%%r15), %%r13\n\t" /* IP = *RSP */
/* Continue with NEXT */
"movq (%%r13), %%rax\n\t"
"addq $8, %%r13\n\t"
"jmpq *%%rax\n\t"
::: "rax", "r13", "r15", "memory"
);
}
/**
* @brief Main interpreter loop implementation
* @details Replaces execute_colon_word function with optimized assembly
*
* Usage example:
* @code
* vm_setup_registers(vm);
* VM_INNER_LOOP();
* @endcode
*/
/* Setup registers before entering inner loop */
static inline void vm_setup_registers(VM *vm) {
__asm__ __volatile__(
"movq %[vm], %%r12\n\t" /* R12 = VM pointer */
"movq %[ip], %%r13\n\t" /* R13 = IP */
/* Calculate actual stack pointers */
"movl %[dsp], %%eax\n\t"
"leaq (%[dstack], %%rax, 8), %%r14\n\t" /* R14 = &data_stack[dsp] */
"movl %[rsp], %%eax\n\t"
"leaq (%[rstack], %%rax, 8), %%r15\n\t" /* R15 = &return_stack[rsp] */
:
: [vm]"r"(vm),
[ip]"r"(vm->ip),
[dsp]"m"(vm->dsp),
[rsp]"m"(vm->rsp),
[dstack]"r"(vm->data_stack),
[rstack]"r"(vm->return_stack)
: "r12", "r13", "r14", "r15", "rax", "memory"
);
}
/* Save registers back to VM structure */
static inline void vm_save_registers(VM *vm) {
__asm__ __volatile__(
"movq %%r13, %[ip]\n\t" /* Save IP */
/* Calculate dsp from R14 */
"movq %%r14, %%rax\n\t"
"subq %[dstack], %%rax\n\t"
"shrq $3, %%rax\n\t" /* / 8 */
"movl %%eax, %[dsp]\n\t"
/* Calculate rsp from R15 */
"movq %%r15, %%rax\n\t"
"subq %[rstack], %%rax\n\t"
"shrq $3, %%rax\n\t"
"movl %%eax, %[rsp]\n\t"
: [ip]"=m"(vm->ip),
[dsp]"=m"(vm->dsp),
[rsp]"=m"(vm->rsp)
: [dstack]"r"(vm->data_stack),
[rstack]"r"(vm->return_stack)
: "rax", "memory"
);
}
/*
* Fast primitive word implementations using register-based stacks
*
* These use the register-allocated stack pointers (R14/R15) directly
* without going through memory or function calls
*/
/* DUP - duplicate top of stack */
#define PRIM_DUP() \
__asm__ __volatile__ ( \
"movq (%%r14), %%rax\n\t" /* Load TOS */ \
"addq $8, %%r14\n\t" /* DSP++ */ \
"movq %%rax, (%%r14)\n\t" /* Store duplicate */ \
::: "rax", "r14", "memory" \
)
/* DROP - remove top of stack */
#define PRIM_DROP() \
__asm__ __volatile__ ( \
"subq $8, %%r14\n\t" /* DSP-- */ \
::: "r14" \
)
/* SWAP - swap top two stack items */
#define PRIM_SWAP() \
__asm__ __volatile__ ( \
"movq (%%r14), %%rax\n\t" /* Load TOS */ \
"movq -8(%%r14), %%rcx\n\t" /* Load NOS */ \
"movq %%rcx, (%%r14)\n\t" /* Store NOS to TOS */ \
"movq %%rax, -8(%%r14)\n\t" /* Store TOS to NOS */ \
::: "rax", "rcx", "memory" \
)
/* + - add top two stack items */
#define PRIM_PLUS() \
__asm__ __volatile__ ( \
"movq (%%r14), %%rax\n\t" /* Load TOS */ \
"addq %%rax, -8(%%r14)\n\t" /* Add to NOS */ \
"subq $8, %%r14\n\t" /* DSP-- */ \
::: "rax", "r14", "cc", "memory" \
)
/* - - subtract top from second */
#define PRIM_MINUS() \
__asm__ __volatile__ ( \
"movq (%%r14), %%rax\n\t" /* Load TOS */ \
"subq %%rax, -8(%%r14)\n\t" /* Subtract from NOS */ \
"subq $8, %%r14\n\t" /* DSP-- */ \
::: "rax", "r14", "cc", "memory" \
)
/* * - multiply top two stack items */
#define PRIM_STAR() \
__asm__ __volatile__ ( \
"movq (%%r14), %%rax\n\t" /* Load TOS */ \
"imulq -8(%%r14), %%rax\n\t" /* Multiply with NOS */ \
"movq %%rax, -8(%%r14)\n\t" /* Store result */ \
"subq $8, %%r14\n\t" /* DSP-- */ \
::: "rax", "rdx", "r14", "cc", "memory" \
)
/* @ - fetch cell from memory */
#define PRIM_FETCH() \
__asm__ __volatile__ ( \
"movq (%%r14), %%rax\n\t" /* Load address from TOS */ \
"movq (%%r12), %%rcx\n\t" /* Load VM->memory */ \
"movq (%%rcx, %%rax, 1), %%rax\n\t" /* Load cell from memory */ \
"movq %%rax, (%%r14)\n\t" /* Store to TOS */ \
::: "rax", "rcx", "memory" \
)
/* ! - store cell to memory */
#define PRIM_STORE() \
__asm__ __volatile__ ( \
"movq (%%r14), %%rax\n\t" /* Load address from TOS */ \
"movq -8(%%r14), %%rcx\n\t" /* Load value from NOS */ \
"movq (%%r12), %%rdx\n\t" /* Load VM->memory */ \
"movq %%rcx, (%%rdx, %%rax, 1)\n\t" /* Store to memory */ \
"subq $16, %%r14\n\t" /* DSP -= 2 */ \
::: "rax", "rcx", "rdx", "r14", "memory" \
)
/* >R - push to return stack */
#define PRIM_TO_R() \
__asm__ __volatile__ ( \
"movq (%%r14), %%rax\n\t" /* Load from TOS */ \
"subq $8, %%r14\n\t" /* DSP-- */ \
"movq %%rax, (%%r15)\n\t" /* Store to return stack */ \
"addq $8, %%r15\n\t" /* RSP++ */ \
::: "rax", "r14", "r15", "memory" \
)
/* R> - pop from return stack */
#define PRIM_R_FROM() \
__asm__ __volatile__ ( \
"subq $8, %%r15\n\t" /* RSP-- */ \
"movq (%%r15), %%rax\n\t" /* Load from return stack */ \
"addq $8, %%r14\n\t" /* DSP++ */ \
"movq %%rax, (%%r14)\n\t" /* Store to TOS */ \
::: "rax", "r14", "r15", "memory" \
)
/* R@ - copy top of return stack to data stack */
#define PRIM_R_FETCH() \
__asm__ __volatile__ ( \
"movq -8(%%r15), %%rax\n\t" /* Load from top of return stack */ \
"addq $8, %%r14\n\t" /* DSP++ */ \
"movq %%rax, (%%r14)\n\t" /* Store to TOS */ \
::: "rax", "r14", "memory" \
)
/*
* BRANCH and 0BRANCH - Control flow primitives
* These modify IP based on conditions
*/
/* BRANCH - unconditional branch */
#define PRIM_BRANCH() \
__asm__ __volatile__ ( \
"movq (%%r13), %%rax\n\t" /* Load offset from IP */ \
"addq %%rax, %%r13\n\t" /* IP += offset */ \
::: "rax", "r13", "memory" \
)
/* 0BRANCH - branch if TOS is zero */
#define PRIM_ZBRANCH() \
__asm__ __volatile__ ( \
"movq (%%r14), %%rax\n\t" /* Load TOS */ \
"subq $8, %%r14\n\t" /* DSP-- */ \
"testq %%rax, %%rax\n\t" /* Test if zero */ \
"jnz 1f\n\t" /* Skip if non-zero */ \
"movq (%%r13), %%rax\n\t" /* Load offset */ \
"addq %%rax, %%r13\n\t" /* IP += offset */ \
"jmp 2f\n\t" \
"1:\n\t" \
"addq $8, %%r13\n\t" /* Skip offset */ \
"2:\n\t" \
::: "rax", "r13", "r14", "cc", "memory" \
)
/* OVER - copy second item to top of stack */
#define PRIM_OVER() \
__asm__ __volatile__ ( \
"movq -8(%%r14), %%rax\n\t" /* Load NOS */ \
"addq $8, %%r14\n\t" /* DSP++ */ \
"movq %%rax, (%%r14)\n\t" /* Store NOS as new TOS */ \
::: "rax", "r14", "memory" \
)
/* ROT - rotate top three items ( a b c -- b c a ) */
#define PRIM_ROT() \
__asm__ __volatile__ ( \
"movq (%%r14), %%rax\n\t" /* c = TOS */ \
"movq -8(%%r14), %%rcx\n\t" /* b = NOS */ \
"movq -16(%%r14), %%rdx\n\t" /* a = third */ \
"movq %%rdx, -8(%%r14)\n\t" /* a -> NOS */ \
"movq %%rax, -16(%%r14)\n\t" /* c -> third */ \
"movq %%rcx, (%%r14)\n\t" /* b -> TOS */ \
::: "rax", "rcx", "rdx", "memory" \
)
/* / - signed divide second by top */
#define PRIM_SLASH() \
__asm__ __volatile__ ( \
"movq -8(%%r14), %%rax\n\t" /* Load dividend (NOS) */ \
"cqo\n\t" /* Sign-extend rax to rdx:rax */ \
"idivq (%%r14)\n\t" /* Divide by TOS */ \
"movq %%rax, -8(%%r14)\n\t" /* Store quotient to NOS slot */ \
"subq $8, %%r14\n\t" /* DSP-- */ \
::: "rax", "rdx", "r14", "cc", "memory" \
)
/* MOD - signed modulo */
#define PRIM_MOD() \
__asm__ __volatile__ ( \
"movq -8(%%r14), %%rax\n\t" /* Load dividend (NOS) */ \
"cqo\n\t" /* Sign-extend */ \
"idivq (%%r14)\n\t" /* rdx = remainder */ \
"movq %%rdx, -8(%%r14)\n\t" /* Store remainder to NOS slot */ \
"subq $8, %%r14\n\t" /* DSP-- */ \
::: "rax", "rdx", "r14", "cc", "memory" \
)
/* AND - bitwise and */
#define PRIM_AND() \
__asm__ __volatile__ ( \
"movq (%%r14), %%rax\n\t" /* Load TOS */ \
"andq %%rax, -8(%%r14)\n\t" /* NOS &= TOS */ \
"subq $8, %%r14\n\t" /* DSP-- */ \
::: "rax", "r14", "cc", "memory" \
)
/* OR - bitwise or */
#define PRIM_OR() \
__asm__ __volatile__ ( \
"movq (%%r14), %%rax\n\t" /* Load TOS */ \
"orq %%rax, -8(%%r14)\n\t" /* NOS |= TOS */ \
"subq $8, %%r14\n\t" /* DSP-- */ \
::: "rax", "r14", "cc", "memory" \
)
/* XOR - bitwise xor */
#define PRIM_XOR() \
__asm__ __volatile__ ( \
"movq (%%r14), %%rax\n\t" /* Load TOS */ \
"xorq %%rax, -8(%%r14)\n\t" /* NOS ^= TOS */ \
"subq $8, %%r14\n\t" /* DSP-- */ \
::: "rax", "r14", "cc", "memory" \
)
/* INVERT - bitwise complement */
#define PRIM_INVERT() \
__asm__ __volatile__ ( \
"notq (%%r14)\n\t" /* TOS = ~TOS */ \
::: "memory" \
)
/* NEGATE - two's complement negation */
#define PRIM_NEGATE() \
__asm__ __volatile__ ( \
"negq (%%r14)\n\t" /* TOS = -TOS */ \
::: "cc", "memory" \
)
/* C@ - fetch byte from memory */
#define PRIM_C_FETCH() \
__asm__ __volatile__ ( \
"movq (%%r14), %%rax\n\t" /* Load address from TOS */ \
"movq (%%r12), %%rcx\n\t" /* Load VM->memory */ \
"movzbq (%%rcx, %%rax, 1), %%rax\n\t" /* Load byte, zero-extend */ \
"movq %%rax, (%%r14)\n\t" /* Store byte value to TOS */ \
::: "rax", "rcx", "memory" \
)
/* C! - store byte to memory */
#define PRIM_C_STORE() \
__asm__ __volatile__ ( \
"movq (%%r14), %%rax\n\t" /* Load address from TOS */ \
"movq -8(%%r14), %%rcx\n\t" /* Load byte value from NOS */ \
"movq (%%r12), %%rdx\n\t" /* Load VM->memory */ \
"movb %%cl, (%%rdx, %%rax, 1)\n\t" /* Store byte */ \
"subq $16, %%r14\n\t" /* DSP -= 2 */ \
::: "rax", "rcx", "rdx", "r14", "memory" \
)
/* 2DUP - duplicate top two items ( a b -- a b a b ) */
#define PRIM_2DUP() \
__asm__ __volatile__ ( \
"movq -8(%%r14), %%rax\n\t" /* Load NOS (a) */ \
"movq (%%r14), %%rcx\n\t" /* Load TOS (b) */ \
"movq %%rax, 8(%%r14)\n\t" /* Store a above TOS */ \
"movq %%rcx, 16(%%r14)\n\t" /* Store b above that */ \
"addq $16, %%r14\n\t" /* DSP += 2 */ \
::: "rax", "rcx", "r14", "memory" \
)
/* 2DROP - drop top two items */
#define PRIM_2DROP() \
__asm__ __volatile__ ( \
"subq $16, %%r14\n\t" /* DSP -= 2 */ \
::: "r14" \
)
/* 0= - true (-1) if TOS is zero, false (0) otherwise */
#define PRIM_ZERO_EQUALS() \
__asm__ __volatile__ ( \
"movq (%%r14), %%rax\n\t" /* Load TOS */ \
"testq %%rax, %%rax\n\t" /* Test for zero */ \
"sete %%al\n\t" /* AL = 1 if zero */ \
"movzbq %%al, %%rax\n\t" /* Zero-extend */ \
"negq %%rax\n\t" /* -1 if true, 0 if false */ \
"movq %%rax, (%%r14)\n\t" /* Store result */ \
::: "rax", "cc", "memory" \
)
/* 0< - true (-1) if TOS is negative, false (0) otherwise */
#define PRIM_ZERO_LESS() \
__asm__ __volatile__ ( \
"movq (%%r14), %%rax\n\t" /* Load TOS */ \
"sarq $63, %%rax\n\t" /* Arithmetic shift: -1 if negative, 0 otherwise */ \
"movq %%rax, (%%r14)\n\t" /* Store result */ \
::: "rax", "cc", "memory" \
)
/* = - true (-1) if top two items are equal, false (0) otherwise */
#define PRIM_EQUALS() \
__asm__ __volatile__ ( \
"movq (%%r14), %%rax\n\t" /* Load TOS (b) */ \
"cmpq %%rax, -8(%%r14)\n\t" /* Compare NOS (a) with TOS (b) */ \
"sete %%al\n\t" /* AL = 1 if equal */ \
"movzbq %%al, %%rax\n\t" /* Zero-extend */ \
"negq %%rax\n\t" /* -1 if true, 0 if false */ \
"movq %%rax, -8(%%r14)\n\t" /* Store result to NOS slot */ \
"subq $8, %%r14\n\t" /* DSP-- */ \
::: "rax", "r14", "cc", "memory" \
)
/* < - true (-1) if NOS < TOS (signed), false (0) otherwise */
#define PRIM_LESS() \
__asm__ __volatile__ ( \
"movq (%%r14), %%rcx\n\t" /* Load TOS (b) */ \
"movq -8(%%r14), %%rax\n\t" /* Load NOS (a) */ \
"cmpq %%rcx, %%rax\n\t" /* rax - rcx: signed compare a vs b */ \
"setl %%al\n\t" /* AL = 1 if a < b */ \
"movzbq %%al, %%rax\n\t" /* Zero-extend */ \
"negq %%rax\n\t" /* -1 if true, 0 if false */ \
"movq %%rax, -8(%%r14)\n\t" /* Store result to NOS slot */ \
"subq $8, %%r14\n\t" /* DSP-- */ \
::: "rax", "rcx", "r14", "cc", "memory" \
)
/* > - true (-1) if NOS > TOS (signed), false (0) otherwise */
#define PRIM_GREATER() \
__asm__ __volatile__ ( \
"movq (%%r14), %%rcx\n\t" /* Load TOS (b) */ \
"movq -8(%%r14), %%rax\n\t" /* Load NOS (a) */ \
"cmpq %%rcx, %%rax\n\t" /* rax - rcx: signed compare a vs b */ \
"setg %%al\n\t" /* AL = 1 if a > b */ \
"movzbq %%al, %%rax\n\t" /* Zero-extend */ \
"negq %%rax\n\t" /* -1 if true, 0 if false */ \
"movq %%rax, -8(%%r14)\n\t" /* Store result to NOS slot */ \
"subq $8, %%r14\n\t" /* DSP-- */ \
::: "rax", "rcx", "r14", "cc", "memory" \
)
/* EXECUTE - execute word whose execution token is on stack */
#define PRIM_EXECUTE() \
__asm__ __volatile__ ( \
"movq (%%r14), %%rax\n\t" /* Load xt from TOS */ \
"subq $8, %%r14\n\t" /* DSP-- */ \
"jmpq *%%rax\n\t" /* Jump to execution token */ \
::: "rax", "r14", "memory" \
)
#else /* !USE_DIRECT_THREADING */
/* Fallback definitions when direct threading is disabled */
#define NEXT_ASM() do {} while(0)
#define vm_setup_registers(vm) do {} while(0)
#define vm_save_registers(vm) do {} while(0)
#endif /* USE_DIRECT_THREADING */
/*
* ============================================================================
* INTEGRATION GUIDE
* ============================================================================
*
* To integrate these optimizations:
*
* 1. Enable in your build:
* -DUSE_DIRECT_THREADING=1 -DUSE_ASM_OPT=1
*
* 2. Modify your inner interpreter in vm.c:
*
* void execute_threaded_code(VM *vm) {
* vm_setup_registers(vm);
*
* // Execute words...
* // Each primitive word should use PRIM_* macros
* // and end with NEXT_ASM()
*
* vm_save_registers(vm);
* }
*
* 3. For each primitive word, replace function with macro:
*
* Instead of:
* void word_dup(VM *vm) { vm_push(vm, vm->data_stack[vm->dsp]); }
*
* Use:
* PRIM_DUP(); NEXT_ASM();
*
* 4. Benchmark before and after!
*
* ============================================================================
* PERFORMANCE NOTES
* ============================================================================
*
* Expected speedup: 2-5x for threaded code execution
*
* Why so fast?
* - No function call overhead (10+ cycles saved per word)
* - Register allocation eliminates memory traffic
* - Direct jumps instead of call/return (better branch prediction)
* - Cache-friendly: hot path stays in I-cache
*
* Trade-offs:
* - More complex code
* - Harder to debug (use regular C version for debugging)
* - Platform-specific (x86_64 only)
* - Requires more careful register management
*
* ============================================================================
* L4RE INTEGRATION NOTES
* ============================================================================
*
* All safe for L4Re because:
* - No privileged instructions
* - No system calls
* - Preserved ABI (callee-saved registers)
* - Can be used in both user and kernel contexts
*
* For StarshipOS:
* - These optimizations work in L4Re tasks
* - Safe for real-time contexts (deterministic timing)
* - No FPU usage (kernel-safe)
* - Stack usage is minimal
*
* ============================================================================
*/
#endif /* VM_INNER_INTERP_ASM_H */