// MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI)
// RUMPK HAL // RISC-V ENTRY - SOVEREIGN TRAP ARCHITECTURE
const std = @import("std");
const uart = @import("uart.zig");
const virtio_net = @import("virtio_net.zig");

// =========================================================
// Entry Point (Naked)
// =========================================================

export fn _start() callconv(.naked) noreturn {
    asm volatile (
    // 1. Disable Interrupts
        \\ csrw sie, zero
        \\ csrw satp, zero
        // 1.1 Enable FPU (sstatus.FS = Initial [01])
        \\ li t0, 0x2000
        \\ csrs sstatus, t0

        // 1.2 Initialize Global Pointer
        \\ .option push
        \\ .option norelax
        \\ la gp, __global_pointer$
        \\ .option pop

        // 2. Set up Stack
        \\ la sp, stack_bytes
        \\ li t0, 65536
        \\ add sp, sp, t0

        // 2.1 Install Trap Handler (Direct Mode)
        \\ la t0, trap_entry
        \\ csrw stvec, t0

        // 3. Jump to Zig Entry
        \\ call zig_entry
        \\ 1: wfi
        \\ j 1b
    );
    unreachable;
}

// Trap Frame Layout (Packed on stack)
const TrapFrame = extern struct {
    ra: usize,
    gp: usize,
    tp: usize,
    t0: usize,
    t1: usize,
    t2: usize,
    s0: usize,
    s1: usize,
    a0: usize,
    a1: usize,
    a2: usize,
    a3: usize,
    a4: usize,
    a5: usize,
    a6: usize,
    a7: usize,
    s2: usize,
    s3: usize,
    s4: usize,
    s5: usize,
    s6: usize,
    s7: usize,
    s8: usize,
    s9: usize,
    s10: usize,
    s11: usize,
    t3: usize,
    t4: usize,
    t5: usize,
    t6: usize,
    sepc: usize,
    sstatus: usize,
    scause: usize,
    stval: usize,
};

// Full Context Save Trap Entry
export fn trap_entry() callconv(.naked) void {
    asm volatile (
    // LOUD HARDWARE TRACE: Write '!' to UART
        \\ li t0, 0x10000000
        \\ li t1, 33
        \\ sb t1, 0(t0)

        // Allocate stack (36 words * 8 bytes = 288 bytes)
        \\ addi sp, sp, -288

        // Save GPRs
        \\ sd ra, 0(sp)
        \\ sd gp, 8(sp)
        \\ sd tp, 16(sp)
        \\ sd t0, 24(sp)
        \\ sd t1, 32(sp)
        \\ sd t2, 40(sp)
        \\ sd s0, 48(sp)
        \\ sd s1, 56(sp)
        \\ sd a0, 64(sp)
        \\ sd a1, 72(sp)
        \\ sd a2, 80(sp)
        \\ sd a3, 88(sp)
        \\ sd a4, 96(sp)
        \\ sd a5, 104(sp)
        \\ sd a6, 112(sp)
        \\ sd a7, 120(sp)
        \\ sd s2, 128(sp)
        \\ sd s3, 136(sp)
        \\ sd s4, 144(sp)
        \\ sd s5, 152(sp)
        \\ sd s6, 160(sp)
        \\ sd s7, 168(sp)
        \\ sd s8, 176(sp)
        \\ sd s9, 184(sp)
        \\ sd s10, 192(sp)
        \\ sd s11, 200(sp)
        \\ sd t3, 208(sp)
        \\ sd t4, 216(sp)
        \\ sd t5, 224(sp)
        \\ sd t6, 232(sp)

        // RELOAD KERNEL GLOBAL POINTER (Critical for globals access)
        \\ .option push
        \\ .option norelax
        \\ la gp, __global_pointer$
        \\ .option pop

        // Save CSRs
        \\ csrr t0, sepc
        \\ sd t0, 240(sp)
        \\ csrr t1, sstatus
        \\ sd t1, 248(sp)
        \\ csrr t2, scause
        \\ sd t2, 256(sp)
        \\ csrr t3, stval
        \\ sd t3, 264(sp)

        // Call Handler (Arg0 = Frame Pointer)
        \\ mv a0, sp
        \\ call rss_trap_handler

        // Restore CSRs (sepc might be modified by syscall handler to skip ecall)
        \\ ld t0, 240(sp)
        \\ csrw sepc, t0
        // We restore sstatus to preserve interrupt state if needed, though usually fixed in kernel
        \\ ld t1, 248(sp)
        \\ csrw sstatus, t1

        // Restore GPRs
        \\ ld ra, 0(sp)
        \\ ld gp, 8(sp)
        \\ ld tp, 16(sp)
        \\ ld t0, 24(sp)
        \\ ld t1, 32(sp)
        \\ ld t2, 40(sp)
        \\ ld s0, 48(sp)
        \\ ld s1, 56(sp)
        \\ ld a0, 64(sp)
        \\ ld a1, 72(sp)
        \\ ld a2, 80(sp)
        \\ ld a3, 88(sp)
        \\ ld a4, 96(sp)
        \\ ld a5, 104(sp)
        \\ ld a6, 112(sp)
        \\ ld a7, 120(sp)
        \\ ld s2, 128(sp)
        \\ ld s3, 136(sp)
        \\ ld s4, 144(sp)
        \\ ld s5, 152(sp)
        \\ ld s6, 160(sp)
        \\ ld s7, 168(sp)
        \\ ld s8, 176(sp)
        \\ ld s9, 184(sp)
        \\ ld s10, 192(sp)
        \\ ld s11, 200(sp)
        \\ ld t3, 208(sp)
        \\ ld t4, 216(sp)
        \\ ld t5, 224(sp)
        \\ ld t6, 232(sp)

        // Deallocate stack
        \\ addi sp, sp, 288
        \\ sret
    );
}

// L1 Kernel Logic
extern fn k_handle_syscall(nr: usize, a0: usize, a1: usize, a2: usize) usize;

extern fn k_handle_exception(scause: usize, sepc: usize, stval: usize) void;
extern fn k_check_deferred_yield() void;

export fn rss_trap_handler(frame: *TrapFrame) void {
    const scause = frame.scause;

    // 8: ECALL from U-mode
    // 9: ECALL from S-mode
    if (scause == 8 or scause == 9) {
        // Advance PC to skip 'ecall' instruction (4 bytes)
        frame.sepc += 4;

        // Dispatch Syscall
        const res = k_handle_syscall(frame.a7, frame.a0, frame.a1, frame.a2);

        // Write result back to a0
        frame.a0 = res;

        // uart.puts("[Trap] Checking deferred yield\n");
        // Check for deferred yield
        k_check_deferred_yield();
        return;
    }

    // Delegate all other exceptions to the Kernel Immune System
    // It will decide whether to segregate (worker) or halt (system)
    // Note: k_handle_exception handles flow control (yield/halt) and does not return
    k_handle_exception(scause, frame.sepc, frame.stval);

    // Safety halt if kernel returns (should be unreachable)
    while (true) {}
}

export var stack_bytes: [64 * 1024]u8 align(16) = undefined;

const hud = @import("hud.zig");
extern fn kmain() void;
extern fn NimMain() void;

export fn zig_entry() void {
    uart.init_riscv();
    uart.print("[Rumpk L0] zig_entry reached\n");
    uart.print("[Rumpk RISC-V] Handing off to Nim L1...\n");
    _ = virtio_net;
    NimMain();
    kmain();
    rumpk_halt();
}

export fn console_write(ptr: [*]const u8, len: usize) void {
    uart.write_bytes(ptr[0..len]);
}

export fn console_read() c_int {
    if (uart.read_byte()) |b| {
        return @as(c_int, b);
    }
    return -1;
}

const virtio_block = @import("virtio_block.zig");

extern fn hal_surface_init() void;

export fn hal_io_init() void {
    uart.init();
    hal_surface_init();
    virtio_net.init();
    virtio_block.init();
}

export fn rumpk_halt() noreturn {
    uart.print("[Rumpk RISC-V] Halting.\n");
    while (true) {
        asm volatile ("wfi");
    }
}

export fn rumpk_timer_now_ns() u64 {
    var ticks: u64 = 0;
    asm volatile ("rdtime %[ticks]"
        : [ticks] "=r" (ticks),
    );
    // QEMU Virt machine is 10MHz -> 1 tick = 100ns
    return ticks * 100;
}
