diff --git a/.gitignore b/.gitignore index 40481d0..735fc9a 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .env references/processed_visuals build +bootslop.proj diff --git a/attempt_1/main.c b/attempt_1/main.c index 1562208..62764b4 100644 --- a/attempt_1/main.c +++ b/attempt_1/main.c @@ -39,6 +39,9 @@ global const char* tag_prefixes[] = { #define UNPACK_TAG(token) (((token) >> 28) & 0x0F) #define UNPACK_VAL(token) ((token) & 0x0FFFFFFF) +// 2-Character Mapped Dictionary Helper +#define ID2(a, b) (((U4)(a) << 8) | (U4)(b)) + #define TOKENS_PER_ROW 8 // The Tape Drive (Using FArena from duffle) @@ -53,16 +56,20 @@ global U8 vm_rax = 0; // Top global U8 vm_rdx = 0; // Next global U8 vm_globals[16] = {0}; -// Provide memset/memcpy for the compiler's implicit struct zeroing (-nostdlib) +#pragma clang optimize off void* memset(void* dest, int c, U8 count) { - mem_fill(u8_(dest), c, count); + U1* bytes = (U1*)dest; + while (count--) *bytes++ = (U1)c; return dest; } void* memcpy(void* dest, const void* src, U8 count) { - mem_copy(u8_(dest), u8_(src), count); + U1* d = (U1*)dest; + const U1* s = (const U1*)src; + while (count--) *d++ = *s++; return dest; } +#pragma clang optimize on IA_ void scatter(U4 token) { U4*r ptr = farena_push_type(&tape_arena, U4); @@ -75,57 +82,70 @@ IA_ void u64_to_hex(U8 val, char* buf, S4 chars) { } // --- Minimal x86-64 Emitter --- -IA_ void emit8(U1 b) { U1*r p = farena_push_type(&code_arena, U1); if(p) p[0] = b; } -IA_ void emit32(U4 val){ U4*r p = farena_push_type(&code_arena, U4); if(p) p[0] = val; } +internal void emit8(U1 b) { + if (code_arena.used + 1 <= code_arena.capacity) { + U1* ptr = (U1*)(code_arena.start + code_arena.used); + *ptr = b; + code_arena.used += 1; + } +} -IA_ void compile_word(U4 tag, U4 val) { +internal void emit32(U4 val) { + if (code_arena.used + 4 <= code_arena.capacity) { + U4* ptr = (U4*)(code_arena.start + code_arena.used); + *ptr = val; + code_arena.used += 4; + } +} + +internal void compile_word(U4 tag, U4 val) { if (tag == tmpl(STag, Data)) { // mov rdx, rax emit8(0x48); emit8(0x89); emit8(0xC2); // mov rax, imm32 emit8(0x48); emit8(0xC7); emit8(0xC0); emit32(val); } else if (tag == tmpl(STag, Imm) || tag == tmpl(STag, Call)) { - if (val == 0x1) { // SWAP: xchg rax, rdx + if (val == ID2('S','W')) { // SWAP: xchg rax, rdx emit8(0x48); emit8(0x87); emit8(0xC2); - } else if (val == 0x2) { // MULT: imul rax, rdx + } else if (val == ID2('M','*')) { // MULT: imul rax, rdx emit8(0x48); emit8(0x0F); emit8(0xAF); emit8(0xC2); - } else if (val == 0x3) { // ADD: add rax, rdx + } else if (val == ID2('+',' ')) { // ADD: add rax, rdx emit8(0x48); emit8(0x01); emit8(0xD0); - } else if (val == 0x4) { // FETCH: mov rax, QWORD PTR [rcx + rax*8] + } else if (val == ID2('@',' ')) { // FETCH: mov rax, QWORD PTR [rcx + rax*8] emit8(0x48); emit8(0x8B); emit8(0x04); emit8(0xC1); - } else if (val == 0x5) { // DEC: dec rax + } else if (val == ID2('-','1')) { // DEC: dec rax emit8(0x48); emit8(0xFF); emit8(0xC8); - } else if (val == 0x6) { // STORE: mov QWORD PTR [rcx + rax*8], rdx + } else if (val == ID2('!',' ')) { // STORE: mov QWORD PTR [rcx + rax*8], rdx emit8(0x48); emit8(0x89); emit8(0x14); emit8(0xC1); - } else if (val == 0x7) { // RET_IF_ZERO: test rax, rax; jnz +9; epilogue; ret + } else if (val == ID2('R','0')) { // RET_IF_ZERO: test rax, rax; jnz +9; epilogue; ret emit8(0x48); emit8(0x85); emit8(0xC0); // test rax, rax emit8(0x75); emit8(0x09); // jnz skip_ret (+9 bytes) emit8(0x48); emit8(0x89); emit8(0x41); emit8(0x70); // mov [rcx+112], rax emit8(0x48); emit8(0x89); emit8(0x51); emit8(0x78); // mov [rcx+120], rdx emit8(0xC3); // ret - } else if (val == 0xFA) { // F_STEP (Inlined Compiler Macro) + } else if (val == ID2('F','S')) { // F_STEP (Inlined Compiler Macro) compile_word(tmpl(STag, Data), 0); - compile_word(tmpl(STag, Imm), 0x4); - compile_word(tmpl(STag, Imm), 0x7); + compile_word(tmpl(STag, Imm), ID2('@',' ')); + compile_word(tmpl(STag, Imm), ID2('R','0')); compile_word(tmpl(STag, Data), 1); - compile_word(tmpl(STag, Imm), 0x4); + compile_word(tmpl(STag, Imm), ID2('@',' ')); compile_word(tmpl(STag, Data), 0); - compile_word(tmpl(STag, Imm), 0x4); - compile_word(tmpl(STag, Imm), 0x2); + compile_word(tmpl(STag, Imm), ID2('@',' ')); + compile_word(tmpl(STag, Imm), ID2('M','*')); compile_word(tmpl(STag, Data), 1); - compile_word(tmpl(STag, Imm), 0x6); + compile_word(tmpl(STag, Imm), ID2('!',' ')); compile_word(tmpl(STag, Data), 0); - compile_word(tmpl(STag, Imm), 0x4); - compile_word(tmpl(STag, Imm), 0x5); + compile_word(tmpl(STag, Imm), ID2('@',' ')); + compile_word(tmpl(STag, Imm), ID2('-','1')); compile_word(tmpl(STag, Data), 0); - compile_word(tmpl(STag, Imm), 0x6); + compile_word(tmpl(STag, Imm), ID2('!',' ')); } } } -IA_ void compile_and_run_tape(void) { +internal void compile_and_run_tape(void) { farena_reset(&code_arena); // Prologue: Load VM state from globals[14] and [15] @@ -153,17 +173,80 @@ IA_ void compile_and_run_tape(void) { vm_rdx = vm_globals[15]; } +#define MS_WM_CHAR 0x0102 +#define MS_VK_RETURN 0x0D +#define MS_VK_BACK 0x08 +#define MS_VK_TAB 0x09 +#define MS_VK_SPACE 0x20 + // --- Window Procedure --- S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam) { U8 tape_count = tape_arena.used / sizeof(U4); + U4*r tape_ptr = C_(U4*r, tape_arena.start); switch (msg) { + case MS_WM_CHAR: { + U4 t = tape_ptr[cursor_idx]; + U4 tag = UNPACK_TAG(t); + U4 val = UNPACK_VAL(t); + U1 c = (U1)wparam; + + // Skip control characters in WM_CHAR (handled in KEYDOWN) + if (c < 32) break; + + if (tag == tmpl(STag, Data)) { + // Hex input + U4 digit = 16; + if (c >= '0' && c <= '9') digit = c - '0'; + if (c >= 'a' && c <= 'f') digit = c - 'a' + 10; + if (c >= 'A' && c <= 'F') digit = c - 'A' + 10; + if (digit < 16) { + val = ((val << 4) | digit) & 0x0FFFFFFF; + tape_ptr[cursor_idx] = PACK_TOKEN(tag, val); + } + } else { + // 2-Char String input (Shift left and insert new char) + val = ((val << 8) | c) & 0xFFFF; + tape_ptr[cursor_idx] = PACK_TOKEN(tag, val); + } + + vm_rax = 0; vm_rdx = 0; mem_zero(u8_(vm_globals), sizeof(vm_globals)); + compile_and_run_tape(); + ms_invalidate_rect(hwnd, NULL, true); + return 0; + } case MS_WM_KEYDOWN: { if (wparam == MS_VK_RIGHT && cursor_idx < tape_count - 1) cursor_idx++; if (wparam == MS_VK_LEFT && cursor_idx > 0) cursor_idx--; if (wparam == MS_VK_DOWN && cursor_idx + TOKENS_PER_ROW < tape_count) cursor_idx += TOKENS_PER_ROW; if (wparam == MS_VK_UP && cursor_idx >= TOKENS_PER_ROW) cursor_idx -= TOKENS_PER_ROW; + if (wparam == MS_VK_TAB) { + // Cycle Color Tag + U4 t = tape_ptr[cursor_idx]; + U4 tag = (UNPACK_TAG(t) + 1) % STag_Count; + tape_ptr[cursor_idx] = PACK_TOKEN(tag, UNPACK_VAL(t)); + } else if (wparam == MS_VK_BACK) { + // Delete Token + if (tape_count > 1) { + for (U8 i = cursor_idx; i < tape_count - 1; i++) { + tape_ptr[i] = tape_ptr[i+1]; + } + tape_arena.used -= sizeof(U4); + if (cursor_idx >= tape_count - 1 && cursor_idx > 0) cursor_idx--; + } + } else if (wparam == MS_VK_SPACE || wparam == MS_VK_RETURN) { + // Insert New Token (Default to Comment) + if (tape_arena.used + sizeof(U4) <= tape_arena.capacity) { + for (U8 i = tape_count; i > cursor_idx + 1; i--) { + tape_ptr[i] = tape_ptr[i-1]; + } + cursor_idx++; + tape_ptr[cursor_idx] = PACK_TOKEN(tmpl(STag, Comment), ID2(' ',' ')); + tape_arena.used += sizeof(U4); + } + } + // Interaction: Reset VM and compile up to cursor vm_rax = 0; vm_rdx = 0; mem_zero(u8_(vm_globals), sizeof(vm_globals)); @@ -207,19 +290,18 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam) { ms_set_text_color(hdc, color); char val_str[9]; - u64_to_hex(val, val_str, 6); - val_str[6] = '\0'; - - // Friendly names for our primitives - if (tag == tmpl(STag, Imm) || tag == tmpl(STag, Call)) { - if (val == 0x1) mem_copy(u8_(val_str), u8_("SWAP "), 6); - if (val == 0x2) mem_copy(u8_(val_str), u8_("MULT "), 6); - if (val == 0x3) mem_copy(u8_(val_str), u8_("ADD "), 6); - if (val == 0x4) mem_copy(u8_(val_str), u8_("FETCH "), 6); - if (val == 0x5) mem_copy(u8_(val_str), u8_("DEC "), 6); - if (val == 0x6) mem_copy(u8_(val_str), u8_("STORE "), 6); - if (val == 0x7) mem_copy(u8_(val_str), u8_("RET_IF"), 6); - if (val == 0xFA) mem_copy(u8_(val_str), u8_("F_STEP"), 6); + if (tag == tmpl(STag, Data)) { + u64_to_hex(val, val_str, 6); + val_str[6] = '\0'; + } else { + // Decode 2-character dictionary ID + val_str[0] = (char)((val >> 8) & 0xFF); + val_str[1] = (char)(val & 0xFF); + val_str[2] = ' '; + val_str[3] = ' '; + val_str[4] = ' '; + val_str[5] = ' '; + val_str[6] = '\0'; } char out_buf[10]; @@ -275,22 +357,25 @@ int main(void) { farena_init(&code_arena, code_mem); // Bootstrap Robust Sample: Factorial State Machine - scatter(PACK_TOKEN(tmpl(STag, Comment), 0x1111)); // .INIT + scatter(PACK_TOKEN(tmpl(STag, Comment), ID2('I','N'))); // .IN scatter(PACK_TOKEN(tmpl(STag, Data), 5)); // $5 scatter(PACK_TOKEN(tmpl(STag, Data), 0)); // $0 (Addr) - scatter(PACK_TOKEN(tmpl(STag, Imm), 0x6)); // ^STORE + scatter(PACK_TOKEN(tmpl(STag, Imm), ID2('!',' '))); // ^! + scatter(PACK_TOKEN(tmpl(STag, Data), 1)); // $1 scatter(PACK_TOKEN(tmpl(STag, Data), 1)); // $1 (Addr) - scatter(PACK_TOKEN(tmpl(STag, Imm), 0x6)); // ^STORE - scatter(PACK_TOKEN(tmpl(STag, Comment), 0xFAFA)); // .FAFA - scatter(PACK_TOKEN(tmpl(STag, Imm), 0xFA)); // ^F_STEP - scatter(PACK_TOKEN(tmpl(STag, Imm), 0xFA)); - scatter(PACK_TOKEN(tmpl(STag, Imm), 0xFA)); - scatter(PACK_TOKEN(tmpl(STag, Imm), 0xFA)); - scatter(PACK_TOKEN(tmpl(STag, Imm), 0xFA)); + scatter(PACK_TOKEN(tmpl(STag, Imm), ID2('!',' '))); // ^! + + scatter(PACK_TOKEN(tmpl(STag, Comment), ID2('-','-'))); // .-- + + scatter(PACK_TOKEN(tmpl(STag, Imm), ID2('F','S'))); // ^FS + scatter(PACK_TOKEN(tmpl(STag, Imm), ID2('F','S'))); + scatter(PACK_TOKEN(tmpl(STag, Imm), ID2('F','S'))); + scatter(PACK_TOKEN(tmpl(STag, Imm), ID2('F','S'))); + scatter(PACK_TOKEN(tmpl(STag, Imm), ID2('F','S'))); MS_WNDCLASSA wc; - memset(&wc, 0, sizeof(wc)); + mem_fill(u8_(& wc), 0, sizeof(wc)); wc.lpfnWndProc = win_proc; wc.hInstance = ms_get_stock_object(0); wc.lpszClassName = "ColorForthWindow"; diff --git a/image.png b/image.png deleted file mode 100644 index 2646efc..0000000 Binary files a/image.png and /dev/null differ diff --git a/old_debugger_null_address.png b/old_debugger_null_address.png new file mode 100644 index 0000000..612a672 Binary files /dev/null and b/old_debugger_null_address.png differ diff --git a/sourceless_snapshot.png b/sourceless_snapshot.png new file mode 100644 index 0000000..6d6c578 Binary files /dev/null and b/sourceless_snapshot.png differ