273 lines
6.4 KiB
Plaintext
273 lines
6.4 KiB
Plaintext
// Moved from docs/src/platform-integration/PLATFORM_ABSTRACTION.adoc to docs/working/scratch/src/platform-integration/PLATFORM_ABSTRACTION.adoc on 2026-06-16 (docs reorg Phase 2)
|
|
== StarForth Platform Abstraction Layer
|
|
:toc: left
|
|
:toc-title: Contents
|
|
:toclevels: 3
|
|
xref:../README.adoc[← Back to Documentation Index]
|
|
|
|
|
|
|
|
StarForth now includes a clean platform abstraction layer that allows
|
|
building for multiple platforms with a simple Makefile switch.
|
|
|
|
=== Overview
|
|
|
|
The platform abstraction provides portable timing/clock functionality
|
|
across:
|
|
|
|
* *POSIX* systems (Linux, macOS, BSD, etc.)
|
|
* *L4Re/StarshipOS* microkernel
|
|
|
|
=== Architecture
|
|
|
|
Similar to the `+blkio+` subsystem, the platform layer uses a *vtable
|
|
pattern* for zero runtime overhead while maintaining clean separation
|
|
between core VM logic and platform-specific code.
|
|
|
|
....
|
|
StarForth Core (platform-agnostic)
|
|
↓
|
|
include/platform_time.h (abstraction API)
|
|
↓
|
|
Runtime platform selection (compile-time)
|
|
├── src/platform/time_posix.c (POSIX: clock_gettime)
|
|
└── src/platform/time_l4re.c (L4Re: RTC server + KIP clock)
|
|
....
|
|
|
|
=== Usage
|
|
|
|
==== Building for Different Platforms
|
|
|
|
[source,bash]
|
|
----
|
|
# POSIX build (default - Linux/macOS/BSD)
|
|
make
|
|
|
|
# L4Re/StarshipOS build
|
|
make L4RE=1
|
|
|
|
# Minimal embedded build (no platform layer)
|
|
make MINIMAL=1
|
|
----
|
|
|
|
==== API Reference
|
|
|
|
All timing functions are accessed through `+include/platform_time.h+`:
|
|
|
|
[source,c]
|
|
----
|
|
#include "platform_time.h"
|
|
|
|
// Initialize platform (call once at startup)
|
|
sf_time_init();
|
|
|
|
// Get monotonic time (for performance measurement)
|
|
sf_time_ns_t uptime = sf_monotonic_ns(); // nanoseconds since boot
|
|
|
|
// Get wall-clock time (Unix epoch)
|
|
sf_time_ns_t now = sf_realtime_ns(); // nanoseconds since 1970-01-01
|
|
|
|
// Set system time (requires privileges on most platforms)
|
|
sf_set_realtime_ns(new_time_ns);
|
|
|
|
// Format timestamp as human-readable string
|
|
char buf[SF_TIME_STAMP_SIZE];
|
|
sf_format_timestamp(now, buf, 1); // 1 = 24-hour format
|
|
printf("Current time: %s\n", buf);
|
|
|
|
// Check if RTC is available
|
|
if (sf_has_rtc()) {
|
|
printf("RTC available\n");
|
|
}
|
|
----
|
|
|
|
==== Helper Functions
|
|
|
|
[source,c]
|
|
----
|
|
// Time conversion helpers
|
|
uint64_t seconds = 1234567890;
|
|
sf_time_ns_t ns = sf_seconds_to_ns(seconds);
|
|
|
|
uint64_t secs = sf_ns_to_seconds(ns);
|
|
uint64_t ms = sf_ns_to_ms(ns);
|
|
uint64_t us = sf_ns_to_us(ns);
|
|
----
|
|
|
|
=== Implementation Details
|
|
|
|
==== POSIX Backend (`+time_posix.c+`)
|
|
|
|
* Uses `+clock_gettime(CLOCK_MONOTONIC)+` for high-precision monotonic
|
|
time
|
|
* Uses `+clock_gettime(CLOCK_REALTIME)+` for wall-clock time
|
|
* Provides `+localtime()+` and `+strftime()+` for timestamp formatting
|
|
* Always reports RTC as available (standard POSIX behavior)
|
|
|
|
==== L4Re Backend (`+time_l4re.c+`)
|
|
|
|
* *Monotonic time*: L4Re KIP (Kernel Info Page) clock - microsecond
|
|
counter since boot
|
|
+
|
|
[source,c]
|
|
----
|
|
l4_kip_clock_ns(l4re_kip()) // Direct CPU timestamp counter access
|
|
----
|
|
* *Real time*: RTC server offset + KIP clock
|
|
+
|
|
[source,c]
|
|
----
|
|
rtc_offset + l4_kip_clock_ns(l4re_kip())
|
|
----
|
|
* *RTC server integration*:
|
|
** Attempts to get `+"rtc"+` capability from L4Re environment
|
|
** Queries offset via `+get_timer_offset()+` RPC
|
|
** Falls back gracefully if RTC server unavailable (reports epoch time)
|
|
* *Time setting*: Updates RTC offset via `+set_timer_offset()+` RPC
|
|
(requires write capability)
|
|
|
|
==== Platform Selection (`+platform_init.c+`)
|
|
|
|
Compile-time platform selection based on `+__l4__+` define:
|
|
|
|
[source,c]
|
|
----
|
|
void sf_time_init(void) {
|
|
#ifdef __l4__
|
|
sf_time_init_l4re(); // L4Re-specific init
|
|
sf_time_backend = &sf_time_backend_l4re;
|
|
#else
|
|
sf_time_backend = &sf_time_backend_posix;
|
|
#endif
|
|
}
|
|
----
|
|
|
|
=== Porting to L4Re/StarshipOS
|
|
|
|
When copying StarForth to `+StarshipOS/l4/pkg/starforth+`, the build
|
|
system automatically uses the L4Re backend:
|
|
|
|
==== StarshipOS Makefile Integration
|
|
|
|
[source,makefile]
|
|
----
|
|
# In StarshipOS/l4/pkg/starforth/server/src/Makefile
|
|
SRC_C = main.c vm.c log.c profiler.c \
|
|
platform/time_l4re.c platform/platform_init.c
|
|
|
|
REQUIRES_LIBS = libc_be_l4re libc l4re l4re_c l4sys librtc
|
|
|
|
CPPFLAGS += -D__l4__=1
|
|
----
|
|
|
|
==== Loader Configuration
|
|
|
|
[source,lua]
|
|
----
|
|
-- Start RTC server first
|
|
ld:start({
|
|
caps = {
|
|
vbus = vbus_l4re,
|
|
},
|
|
}, "rom/rtc");
|
|
|
|
-- StarForth with RTC capability
|
|
ld:start({
|
|
caps = {
|
|
rtc = ld:wait("rtc", 1000), -- Wait for RTC server
|
|
},
|
|
}, "rom/starforth");
|
|
----
|
|
|
|
=== Migration from Old Code
|
|
|
|
The platform abstraction *replaces* direct POSIX calls:
|
|
|
|
==== Before (POSIX-only):
|
|
|
|
[source,c]
|
|
----
|
|
// profiler.c
|
|
static uint64_t get_time_ns(void) {
|
|
struct timespec ts;
|
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
|
|
}
|
|
|
|
// log.c
|
|
static void get_timestamp(char *buffer, size_t size) {
|
|
time_t now = time(NULL);
|
|
struct tm *tm_info = localtime(&now);
|
|
strftime(buffer, size, "%H:%M:%S", tm_info);
|
|
}
|
|
----
|
|
|
|
==== After (Platform-agnostic):
|
|
|
|
[source,c]
|
|
----
|
|
// profiler.c
|
|
#include "platform_time.h"
|
|
|
|
static uint64_t get_time_ns(void) {
|
|
return sf_monotonic_ns(); // Works on both POSIX and L4Re
|
|
}
|
|
|
|
// log.c
|
|
#include "platform_time.h"
|
|
|
|
static void get_timestamp(char *buffer, size_t size) {
|
|
sf_time_ns_t now = sf_realtime_ns();
|
|
sf_format_timestamp(now, buffer, 1);
|
|
}
|
|
----
|
|
|
|
=== Benefits
|
|
|
|
[arabic]
|
|
. *Single codebase*: No more `+#ifdef+` spaghetti in core files
|
|
. *Zero overhead*: Inline functions compile to direct calls
|
|
. *Type safety*: Strong typing via vtable pattern
|
|
. *Extensibility*: Easy to add new platforms (WASM, baremetal, etc.)
|
|
. *Testability*: Mock implementations possible via vtable swapping
|
|
|
|
=== Future Platforms
|
|
|
|
The abstraction is designed to support:
|
|
|
|
* *Baremetal* (direct hardware timer access)
|
|
* *WASM* (performance.now() emulation)
|
|
* *RTOS* (FreeRTOS, Zephyr, etc.)
|
|
* *Custom microkernels* (seL4, etc.)
|
|
|
|
Adding a new platform requires:
|
|
|
|
[arabic]
|
|
. Create `+src/platform/time_<platform>.c+`
|
|
. Implement `+sf_time_backend_<platform>+` vtable
|
|
. Add platform detection to `+platform_init.c+`
|
|
. Update Makefile with new platform flag
|
|
|
|
=== Testing
|
|
|
|
[source,bash]
|
|
----
|
|
# Test POSIX build
|
|
make clean && make
|
|
./build/starforth --run-tests
|
|
|
|
# Test profiler timing
|
|
./build/starforth --profile 2 --run-tests --profile-report
|
|
|
|
# Test logging timestamps
|
|
./build/starforth --log-debug
|
|
----
|
|
|
|
=== See Also
|
|
|
|
* `+include/platform_time.h+` - Platform API documentation
|
|
* `+src/platform/time_posix.c+` - POSIX implementation
|
|
* `+src/platform/time_l4re.c+` - L4Re implementation
|
|
* `+src/platform/platform_init.c+` - Platform selector
|
|
* StarshipOS CLAUDE.md - L4Re RTC architecture details
|