14 KiB
HAL Migration Plan
Overview
This document provides a step-by-step plan for refactoring StarForth to use the Hardware Abstraction Layer (HAL). The migration preserves all existing functionality while preparing the codebase for StarKernel.
HISTORICAL — L4Re/Fiasco.OC: L4Re references below describe a target that was a supported platform through mid-2026. L4Re support has since been removed as an active target —
src/platform/l4re/time.cand related#ifdef __l4__code are retained for reference but no longer wired into any build.
Goal: Zero functional regressions, all 936+ tests pass, 0% algorithmic variance maintained.
Migration Strategy
Principles
- Incremental refactoring - One subsystem at a time
- Test after each step - Build + test suite must pass
- Platform parity - Linux and L4Re work throughout migration
- No big bang - HAL interfaces defined first, then adopted gradually
Phases
Phase 1: Define HAL Interfaces (headers only)
↓
Phase 2: Implement HAL for Linux (refactor existing code)
↓
Phase 3: Migrate VM Core to use HAL
↓
Phase 4: Migrate Physics Subsystems to use HAL
↓
Phase 5: Migrate REPL and Word Implementations
↓
Phase 6: Implement HAL for L4Re (optional validation)
↓
Phase 7: Validate Deterministic Behavior
Phase 1: Define HAL Interfaces
Duration: 1-2 days Risk: Low (no code changes, only headers)
Tasks
-
Create HAL header directory
mkdir -p include/hal -
Write HAL interface headers
include/hal/hal_time.hinclude/hal/hal_interrupt.hinclude/hal/hal_memory.hinclude/hal/hal_console.hinclude/hal/hal_cpu.hinclude/hal/hal_panic.h
See
interfaces.mdfor full specifications. -
Update Makefile to include HAL headers
INCLUDES += -Iinclude/hal -
Compile check (headers only)
make clean && make PLATFORM=linuxShould compile without errors (HAL functions not yet called).
Success Criteria
✅ All HAL headers compile without errors ✅ No changes to VM code yet ✅ Documentation reviewed and approved
Phase 2: Implement HAL for Linux
Duration: 3-5 days Risk: Medium (refactoring existing platform code)
Current Platform Code Locations
Audit existing platform-specific code:
# Find POSIX-specific calls
grep -r "clock_gettime\|pthread\|signal\|malloc\|printf" src/
Expected locations:
- Timing:
src/platform/linux/time.c(already exists) - Memory: Direct
malloc()calls in VM code (needs refactoring) - Console: Direct
printf()calls in REPL (needs refactoring)
Tasks
-
Create Linux HAL directory
mkdir -p src/platform/linux/hal -
Implement Linux HAL subsystems
2a.
hal_time.c- Refactorsrc/platform/linux/time.c/* Before: */ uint64_t platform_time_ns(void) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return ...; } /* After: */ uint64_t hal_time_now_ns(void) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return (uint64_t)ts.tv_sec * 1000000000ULL + ts.tv_nsec; }2b.
hal_memory.c- Wrap malloc/freevoid *hal_mem_alloc(size_t size) { if (size == 0) return NULL; void *ptr = malloc(size); if (ptr) memset(ptr, 0, size); return ptr; } void hal_mem_free(void *ptr) { free(ptr); }2c.
hal_console.c- Wrap stdiovoid hal_console_putc(char c) { putchar(c); fflush(stdout); } int hal_console_getc(void) { return getchar(); }2d.
hal_interrupt.c- Signal-based interrupts Seeplatform-implementations.mdfor full implementation.2e.
hal_cpu.c- CPU infounsigned int hal_cpu_id(void) { return 0; /* Single-threaded */ } void hal_cpu_relax(void) { sched_yield(); }2f.
hal_panic.c- Error handlingvoid hal_panic(const char *msg) { fprintf(stderr, "PANIC: %s\n", msg ? msg : "unknown"); abort(); } -
Update Makefile
ifeq ($(PLATFORM),linux) PLATFORM_SOURCES = \ src/platform/linux/hal_time.c \ src/platform/linux/hal_interrupt.c \ src/platform/linux/hal_memory.c \ src/platform/linux/hal_console.c \ src/platform/linux/hal_cpu.c \ src/platform/linux/hal_panic.c endif -
Build test (HAL code compiles)
make clean && make PLATFORM=linux
Success Criteria
✅ Linux HAL compiles without errors ✅ Existing VM code still builds (not yet using HAL) ✅ No functional changes yet
Phase 3: Migrate VM Core to use HAL
Duration: 2-3 days Risk: High (core VM changes)
Files to Modify
src/vm.c- Core interpreter loopsrc/vm_api.c- External APIsrc/memory_management.c- Dictionary allocatorinclude/vm.h- VM struct
Tasks
-
Replace direct malloc/free in VM core
Before:
/* src/memory_management.c */ void *mem = malloc(size);After:
#include "hal/hal_memory.h" void *mem = hal_mem_alloc(size); -
Replace timing calls in heartbeat
Before:
/* src/vm.c */ #include <time.h> struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); uint64_t now = ts.tv_sec * 1000000000ULL + ts.tv_nsec;After:
#include "hal/hal_time.h" uint64_t now = hal_time_now_ns(); -
Add HAL initialization to VM startup
In
src/main.c:int main(int argc, char **argv) { /* Initialize HAL subsystems */ hal_time_init(); hal_interrupt_init(); hal_mem_init(); hal_console_init(); hal_cpu_init(); /* Continue with existing VM initialization */ VM *vm = vm_create(); ... } -
Remove platform-specific #ifdefs
Before:
#ifdef PLATFORM_LINUX clock_gettime(CLOCK_MONOTONIC, &ts); #elif PLATFORM_L4RE l4re_kip_clock(kip); #endifAfter:
uint64_t now = hal_time_now_ns(); /* Works on all platforms */ -
Build and test
make clean && make PLATFORM=linux make test
Expected Failures
- Compilation errors: Missing
#include "hal/hal_*.h" - Link errors: HAL functions not implemented
- Runtime errors: HAL not initialized before VM
Fix incrementally: Add includes, implement missing HAL functions, ensure init order.
Success Criteria
✅ VM builds using HAL interfaces
✅ All 936+ tests pass
✅ No platform-specific code in src/vm.c
Phase 4: Migrate Physics Subsystems to use HAL
Duration: 2-3 days Risk: Medium (determinism must be preserved)
Files to Modify
src/dictionary_heat_optimization.csrc/rolling_window_of_truth.csrc/physics_hotwords_cache.csrc/physics_pipelining_metrics.csrc/inference_engine.csrc/heartbeat.c
Tasks
-
Audit timing calls in physics subsystems
grep -n "clock_gettime\|time\.h" src/*physics*.c src/heartbeat.c src/inference*.c -
Replace timing calls
Example:
src/rolling_window_of_truth.c/* Before: */ #include <time.h> struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); uint64_t timestamp = ...; /* After: */ #include "hal/hal_time.h" uint64_t timestamp = hal_time_now_ns(); -
Migrate heartbeat to HAL timer
Before:
src/heartbeat.cuses pthread + sleepvoid *heartbeat_thread(void *arg) { while (running) { usleep(period_us); vm_tick(vm); } }After: Use HAL periodic timer
static VM *heartbeat_vm = NULL; static void heartbeat_isr(void *ctx) { (void)ctx; if (heartbeat_vm) { vm_tick_isr(heartbeat_vm); /* ISR-safe VM tick */ } } void heartbeat_start(VM *vm, uint64_t rate_hz) { heartbeat_vm = vm; uint64_t period_ns = 1000000000ULL / rate_hz; hal_timer_periodic(period_ns, heartbeat_isr, NULL); }Critical:
vm_tick_isr()must be ISR-safe:- No malloc/free
- No blocking I/O
- Only lock-free ring buffer updates
-
Test deterministic behavior
make fastest PLATFORM=linux ./build/amd64/fastest/starforth --doe > results_after_hal.csvCompare with baseline (before HAL migration):
diff results_before_hal.csv results_after_hal.csvExpected: Identical results (0% algorithmic variance).
Success Criteria
✅ Physics subsystems use HAL for all timing ✅ Heartbeat runs via HAL periodic timer ✅ 0% algorithmic variance maintained ✅ All tests pass
Phase 5: Migrate REPL and Word Implementations
Duration: 1-2 days Risk: Low (mostly console I/O)
Files to Modify
src/repl.c- Read-eval-print loopsrc/word_source/*_words.c- Words that do I/O (emit, key, etc.)
Tasks
-
Replace stdio in REPL
Before:
src/repl.c#include <stdio.h> char c = getchar(); printf("ok\n");After:
#include "hal/hal_console.h" char c = hal_console_getc(); hal_console_puts("ok\n"); -
Update I/O words
src/word_source/io_words.c:/* EMIT ( c -- ) */ static void word_emit(VM *vm) { int c = vm_pop(vm); hal_console_putc((char)c); } /* KEY ( -- c ) */ static void word_key(VM *vm) { int c = hal_console_getc(); vm_push(vm, c); } -
Test REPL interactively
./build/amd64/standard/starforth > 1 2 + . 3 ok > BYE
Success Criteria
✅ REPL works identically to before ✅ All I/O words use HAL ✅ No direct stdio calls in VM code
Phase 6: Implement HAL for L4Re (Optional)
Duration: 3-5 days Risk: Low (validates HAL portability)
This phase is optional but highly recommended to validate that the HAL abstraction actually works across platforms.
Tasks
-
Create L4Re HAL directory
mkdir -p src/platform/l4re/hal -
Implement L4Re HAL subsystems
hal_time.c→ L4Re clock APIhal_memory.c→ L4Re dataspaceshal_console.c→ L4Re console servicehal_interrupt.c→ L4Re IRQ objects
See L4Re documentation for API details.
-
Build for L4Re
make PLATFORM=l4re -
Run tests on L4Re
make PLATFORM=l4re test
Success Criteria
✅ L4Re HAL compiles ✅ VM runs on L4Re without source changes ✅ Tests pass on L4Re
Phase 7: Validate Deterministic Behavior
Duration: 1 day Risk: High (final validation)
Tasks
-
Run DoE on Linux (HAL)
make fastest PLATFORM=linux for i in {1..10}; do ./build/amd64/fastest/starforth --doe > results_linux_$i.csv done -
Verify 0% variance across runs
# All CSV files should be identical md5sum results_linux_*.csv -
Compare with pre-HAL baseline
diff results_before_hal.csv results_linux_1.csvExpected: Identical (HAL added zero overhead).
-
Run full test suite
make test PLATFORM=linuxExpected: All 936+ tests pass.
-
Benchmark performance
make bench PLATFORM=linuxExpected: < 5% performance delta from pre-HAL baseline.
Success Criteria
✅ 0% algorithmic variance maintained ✅ All tests pass ✅ < 5% performance regression ✅ HAL abstraction validated
Rollback Strategy
If migration fails at any phase:
-
Git branch strategy
git checkout -b hal-migration # Work on branch, test each phase git commit -m "Phase N complete" # If phase fails, revert: git reset --hard HEAD~1 -
Incremental commits
- Commit after each phase passes tests
- Never commit broken code
- Each commit should build and pass tests
-
Feature flag (if needed)
#ifdef ENABLE_HAL uint64_t now = hal_time_now_ns(); #else struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); uint64_t now = ...; #endifEnable HAL incrementally, fall back if issues arise.
Post-Migration Cleanup
After successful migration:
-
Remove old platform code
# If src/platform/linux/time.c was fully replaced by hal_time.c git rm src/platform/linux/time.c -
Update documentation
docs/CLAUDE.md- Mention HAL architectureREADME.md- Update build instructionsdocs/DEVELOPER.md- Add HAL section
-
Update .gitignore
# Build artifacts for all platforms build/linux/ build/l4re/ build/kernel/
Timeline Estimate
| Phase | Duration | Cumulative |
|---|---|---|
| 1. Define HAL Interfaces | 1-2 days | 1-2 days |
| 2. Implement Linux HAL | 3-5 days | 4-7 days |
| 3. Migrate VM Core | 2-3 days | 6-10 days |
| 4. Migrate Physics | 2-3 days | 8-13 days |
| 5. Migrate REPL | 1-2 days | 9-15 days |
| 6. L4Re HAL (optional) | 3-5 days | 12-20 days |
| 7. Validation | 1 day | 13-21 days |
Total: 2-4 weeks (depending on L4Re inclusion)
Success Metrics
The HAL migration is successful if:
- ✅ All tests pass - 936+ tests on Linux (and L4Re if implemented)
- ✅ 0% variance - DoE results identical pre/post migration
- ✅ No regressions - Performance < 5% slower
- ✅ Zero platform code in VM - No #ifdef PLATFORM_X in core
- ✅ Clean abstractions - HAL interfaces well-documented
- ✅ Ready for StarKernel - Platform layer can be replaced
Next Steps
After successful HAL migration:
- Implement StarKernel platform (
src/platform/kernel/) - UEFI boot loader (
src/platform/kernel/boot/uefi_loader.c) - Boot to
okprompt on QEMU/OVMF - Validate physics on bare metal (determinism on real hardware)
See starkernel-integration.md for StarKernel-specific implementation details.