196 lines
4.7 KiB
Zig
196 lines
4.7 KiB
Zig
// VOXIS FORGE // RUMPK L0
|
|
// libc_stubs.zig
|
|
// We are the standard library now.
|
|
//
|
|
// These C ABI functions are exported so Nim's generated C code
|
|
// can link against them. No glibc. No musl. Pure sovereignty.
|
|
|
|
// =========================================================
|
|
// Memory Operations (Nim needs these)
|
|
// =========================================================
|
|
|
|
export fn memcpy(dest: [*]u8, src: [*]const u8, len: usize) [*]u8 {
|
|
var i: usize = 0;
|
|
while (i < len) : (i += 1) {
|
|
dest[i] = src[i];
|
|
}
|
|
return dest;
|
|
}
|
|
|
|
export fn memset(dest: [*]u8, val: c_int, len: usize) [*]u8 {
|
|
const v: u8 = @intCast(val & 0xFF);
|
|
var i: usize = 0;
|
|
while (i < len) : (i += 1) {
|
|
dest[i] = v;
|
|
}
|
|
return dest;
|
|
}
|
|
|
|
export fn memmove(dest: [*]u8, src: [*]const u8, len: usize) [*]u8 {
|
|
if (@intFromPtr(dest) < @intFromPtr(src)) {
|
|
return memcpy(dest, src, len);
|
|
}
|
|
// Copy backwards for overlapping regions
|
|
var i: usize = len;
|
|
while (i > 0) {
|
|
i -= 1;
|
|
dest[i] = src[i];
|
|
}
|
|
return dest;
|
|
}
|
|
|
|
export fn memcmp(s1: [*]const u8, s2: [*]const u8, len: usize) c_int {
|
|
var i: usize = 0;
|
|
while (i < len) : (i += 1) {
|
|
if (s1[i] != s2[i]) {
|
|
return if (s1[i] < s2[i]) @as(c_int, -1) else @as(c_int, 1);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// =========================================================
|
|
// String Operations
|
|
// =========================================================
|
|
|
|
export fn strlen(s: [*]const u8) usize {
|
|
var len: usize = 0;
|
|
while (s[len] != 0) : (len += 1) {}
|
|
return len;
|
|
}
|
|
|
|
export fn strcpy(dest: [*]u8, src: [*]const u8) [*]u8 {
|
|
var i: usize = 0;
|
|
while (src[i] != 0) : (i += 1) {
|
|
dest[i] = src[i];
|
|
}
|
|
dest[i] = 0;
|
|
return dest;
|
|
}
|
|
|
|
export fn strcmp(s1: [*]const u8, s2: [*]const u8) c_int {
|
|
var i: usize = 0;
|
|
while (s1[i] != 0 and s1[i] == s2[i]) : (i += 1) {}
|
|
if (s1[i] == s2[i]) return 0;
|
|
return if (s1[i] < s2[i]) @as(c_int, -1) else @as(c_int, 1);
|
|
}
|
|
|
|
// =========================================================
|
|
// Heap Stubs (Bump Allocator)
|
|
// =========================================================
|
|
|
|
var heap_base: [64 * 1024]u8 = undefined;
|
|
var heap_offset: usize = 0;
|
|
|
|
export fn malloc(size: usize) ?*anyopaque {
|
|
if (heap_offset + size > heap_base.len) {
|
|
return null;
|
|
}
|
|
const ptr = &heap_base[heap_offset];
|
|
heap_offset += size;
|
|
// Align to 8 bytes
|
|
heap_offset = (heap_offset + 7) & ~@as(usize, 7);
|
|
return ptr;
|
|
}
|
|
|
|
export fn free(ptr: ?*anyopaque) void {
|
|
// Bump allocator - no deallocation
|
|
_ = ptr;
|
|
}
|
|
|
|
export fn realloc(ptr: ?*anyopaque, size: usize) ?*anyopaque {
|
|
// Simple realloc - just allocate new (wasteful but works for bootstrap)
|
|
_ = ptr;
|
|
return malloc(size);
|
|
}
|
|
|
|
export fn calloc(nmemb: usize, size: usize) ?*anyopaque {
|
|
const total = nmemb * size;
|
|
const ptr = malloc(total);
|
|
if (ptr) |p| {
|
|
_ = memset(@ptrCast(p), 0, total);
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
// =========================================================
|
|
// Stdio Stubs (Route to UART)
|
|
// =========================================================
|
|
|
|
const uart = @import("uart.zig");
|
|
|
|
export fn puts(s: [*]const u8) c_int {
|
|
const len = strlen(s);
|
|
uart.write_bytes(s[0..len]);
|
|
uart.putc('\n');
|
|
return 0;
|
|
}
|
|
|
|
export fn putchar(c: c_int) c_int {
|
|
uart.putc(@intCast(c & 0xFF));
|
|
return c;
|
|
}
|
|
|
|
export fn printf(fmt: [*]const u8, ...) c_int {
|
|
// Minimal printf - just output format string
|
|
const len = strlen(fmt);
|
|
uart.write_bytes(fmt[0..len]);
|
|
return @intCast(len);
|
|
}
|
|
|
|
export fn fprintf(stream: ?*anyopaque, fmt: [*]const u8, ...) c_int {
|
|
_ = stream;
|
|
return printf(fmt);
|
|
}
|
|
|
|
export fn fflush(stream: ?*anyopaque) c_int {
|
|
_ = stream;
|
|
return 0;
|
|
}
|
|
|
|
export fn fwrite(ptr: [*]const u8, size: usize, nmemb: usize, stream: ?*anyopaque) usize {
|
|
_ = stream;
|
|
uart.write_bytes(ptr[0 .. size * nmemb]);
|
|
return nmemb;
|
|
}
|
|
|
|
// =========================================================
|
|
// Signal Stubs (No signals in freestanding)
|
|
// =========================================================
|
|
|
|
export fn signal(signum: c_int, handler: ?*anyopaque) ?*anyopaque {
|
|
_ = signum;
|
|
_ = handler;
|
|
return null;
|
|
}
|
|
|
|
export fn raise(sig: c_int) c_int {
|
|
_ = sig;
|
|
return 0;
|
|
}
|
|
|
|
// =========================================================
|
|
// Exit Stubs
|
|
// =========================================================
|
|
|
|
fn halt() noreturn {
|
|
while (true) {
|
|
asm volatile ("wfi");
|
|
}
|
|
}
|
|
|
|
export fn exit(status: c_int) noreturn {
|
|
_ = status;
|
|
uart.puts("[RUMPK] exit() called - halt\n");
|
|
halt();
|
|
}
|
|
|
|
export fn abort() noreturn {
|
|
uart.puts("[RUMPK] abort() called - halt\n");
|
|
halt();
|
|
}
|
|
|
|
export fn _Exit(status: c_int) noreturn {
|
|
exit(status);
|
|
}
|