progress
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,3 +2,4 @@
|
||||
.env
|
||||
references/processed_visuals
|
||||
build
|
||||
bootslop.proj
|
||||
|
||||
175
attempt_1/main.c
175
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];
|
||||
if (tag == tmpl(STag, Data)) {
|
||||
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);
|
||||
} 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";
|
||||
|
||||
BIN
old_debugger_null_address.png
Normal file
BIN
old_debugger_null_address.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 428 KiB |
BIN
sourceless_snapshot.png
Normal file
BIN
sourceless_snapshot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
Reference in New Issue
Block a user