diff --git a/GEMINI.md b/GEMINI.md index 712a593..539c863 100644 --- a/GEMINI.md +++ b/GEMINI.md @@ -48,7 +48,7 @@ The prototype currently implements a functional WinAPI modal editor, a 2-registe Here is a breakdown of the next steps to advance the `attempt_1` implementation towards a complete ColorForth derivative: -1. **Refine the FFI / Tape Drive Argument Scatter:** +1. ~~**Refine the FFI / Tape Drive Argument Scatter:**~~ (Completed via `PRIM_PRINT` updating to load R8/R9 from `vm_globals`) * Currently, the FFI bridge only maps `RAX` and `RDX` to the C-ABI `RCX` and `RDX`. * Implement "Preemptive Scatter" logic so the FFI bridge correctly reads subsequent arguments (e.g., `R8`, `R9`) directly from pre-defined offsets in the `vm_globals` tape drive instead of just zeroing them out. @@ -56,7 +56,7 @@ Here is a breakdown of the next steps to advance the `attempt_1` implementation * The current `anno_arena` strictly allocates 8 bytes (a `U8`) per token. * Refactor the visual editor and annotation memory management to allow for arbitrarily long text blocks (comments) to be attached to specific tokens without disrupting the `O(1)` compilation mapping. -3. **Implement the Self-Modifying Cartridge (Persistence):** +3. ~~**Implement the Self-Modifying Cartridge (Persistence):**~~ (Completed via F1/F2 save/load) * The tape and annotations are currently lost when the program closes. * Move away from purely transient `VirtualAlloc` buffers to a memory-mapped file approach (or a manual Save/Load equivalent in WinAPI) to allow the "executable as source" to persist between sessions. diff --git a/attempt_1/main.c b/attempt_1/main.c index 1dd85aa..18b5ed3 100644 --- a/attempt_1/main.c +++ b/attempt_1/main.c @@ -89,15 +89,22 @@ internal void debug_log(Str8 fmt, KTL_Str8 table) { ms_write_console(stdout_handle, (UTF8 const*r)"\n", 1, nullptr, 0); } -void ms_builtin_print(U8 val) { - char val_hex[9]; - u64_to_hex(val, val_hex, 8); - val_hex[8] = '\0'; +U8 ms_builtin_print(U8 val, U8 rdx_val, U8 r8_val, U8 r9_val) { + char hex1[9], hex2[9], hex3[9], hex4[9]; + u64_to_hex(val, hex1, 8); hex1[8] = '\0'; + u64_to_hex(rdx_val, hex2, 8); hex2[8] = '\0'; + u64_to_hex(r8_val, hex3, 8); hex3[8] = '\0'; + u64_to_hex(r9_val, hex4, 8); hex4[8] = '\0'; + KTL_Slot_Str8 log_table[] = { - { ktl_str8_key("val"), str8(val_hex) }, + { ktl_str8_key("v1"), str8(hex1) }, + { ktl_str8_key("v2"), str8(hex2) }, + { ktl_str8_key("v3"), str8(hex3) }, + { ktl_str8_key("v4"), str8(hex4) }, }; - debug_log(str8("ms_builtin_print called with: "), ktl_str8_from_arr(log_table)); + debug_log(str8("FFI PRINT -> RCX: RDX: R8: R9:"), ktl_str8_from_arr(log_table)); if (log_count < 16) log_buffer[log_count++] = val; + return val; } // Visual Linker & O(1) Dictionary @@ -324,16 +331,25 @@ internal void compile_action(U4 val) pad32(); return; } else if (p == PRIM_PRINT) { - emit8(0x52); // push rdx - emit8(0x48); emit8(0x83); emit8(0xEC); emit8(0x20); // sub rsp, 32 (shadow space) - emit8(0x48); emit8(0x89); emit8(0xC1); // mov rcx, rax - emit8(0x49); emit8(0xB8); // mov r8, ... + // FFI Dance: Save RDX, Align RSP (32 shadow + 8 align = 40) + emit8(0x52); // push rdx + emit8(0x48); emit8(0x83); emit8(0xEC); emit8(0x28); // sub rsp, 40 + + // Map arguments: RCX=RAX, RDX=RDX(already loaded), R8=Globals[0], R9=Globals[1] + emit8(0x48); emit8(0x89); emit8(0xC1); // mov rcx, rax + emit8(0x4C); emit8(0x8B); emit8(0x03); // mov r8, [rbx] + emit8(0x4C); emit8(0x8B); emit8(0x4B); emit8(0x08); // mov r9, [rbx+8] + + // Load func ptr and call + emit8(0x49); emit8(0xBA); // mov r10, ... U8 addr = u8_(& ms_builtin_print); emit32(u4_(addr & 0xFFFFFFFF)); emit32(u4_(addr >> 32)); - emit8(0x41); emit8(0xFF); emit8(0xD0); // call r8 - emit8(0x48); emit8(0x83); emit8(0xC4); emit8(0x20); // add rsp, 32 - emit8(0x5A); // pop rdx + emit8(0x41); emit8(0xFF); emit8(0xD2); // call r10 + + // Restore + emit8(0x48); emit8(0x83); emit8(0xC4); emit8(0x28); // add rsp, 40 + emit8(0x5A); // pop rdx pad32(); return; }