progress.
This commit is contained in:
166
attempt_1/main.c
166
attempt_1/main.c
@@ -64,6 +64,14 @@ global U8 vm_rax = 0; // Top
|
|||||||
global U8 vm_rdx = 0; // Next
|
global U8 vm_rdx = 0; // Next
|
||||||
global U8 vm_globals[16] = {0};
|
global U8 vm_globals[16] = {0};
|
||||||
|
|
||||||
|
// Dictionary
|
||||||
|
typedef struct {
|
||||||
|
U4 val;
|
||||||
|
U4 offset;
|
||||||
|
} DictEntry;
|
||||||
|
global DictEntry dict[256];
|
||||||
|
global U8 dict_count = 0;
|
||||||
|
|
||||||
#pragma clang optimize off
|
#pragma clang optimize off
|
||||||
void* memset(void* dest, int c, U8 count) {
|
void* memset(void* dest, int c, U8 count) {
|
||||||
U1* bytes = (U1*)dest;
|
U1* bytes = (U1*)dest;
|
||||||
@@ -109,64 +117,102 @@ internal void emit32(U4 val) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void compile_word(U4 tag, U4 val) {
|
internal void compile_action(U4 val) {
|
||||||
if (tag == tmpl(STag, Data)) {
|
if (val == ID2('S','W')) { // SWAP: xchg rax, rdx
|
||||||
// mov rdx, rax
|
emit8(0x48); emit8(0x87); emit8(0xC2);
|
||||||
emit8(0x48); emit8(0x89); emit8(0xC2);
|
return;
|
||||||
// mov rax, imm32
|
} else if (val == ID2('M','*')) { // MULT: imul rax, rdx
|
||||||
emit8(0x48); emit8(0xC7); emit8(0xC0); emit32(val);
|
emit8(0x48); emit8(0x0F); emit8(0xAF); emit8(0xC2);
|
||||||
} else if (tag == tmpl(STag, Imm) || tag == tmpl(STag, Call)) {
|
return;
|
||||||
if (val == ID2('S','W')) { // SWAP: xchg rax, rdx
|
} else if (val == ID2('+',' ')) { // ADD: add rax, rdx
|
||||||
emit8(0x48); emit8(0x87); emit8(0xC2);
|
emit8(0x48); emit8(0x01); emit8(0xD0);
|
||||||
} else if (val == ID2('M','*')) { // MULT: imul rax, rdx
|
return;
|
||||||
emit8(0x48); emit8(0x0F); emit8(0xAF); emit8(0xC2);
|
} else if (val == ID2('@',' ')) { // FETCH: mov rax, QWORD PTR [rcx + rax*8]
|
||||||
} else if (val == ID2('+',' ')) { // ADD: add rax, rdx
|
emit8(0x48); emit8(0x8B); emit8(0x04); emit8(0xC1);
|
||||||
emit8(0x48); emit8(0x01); emit8(0xD0);
|
return;
|
||||||
} else if (val == ID2('@',' ')) { // FETCH: mov rax, QWORD PTR [rcx + rax*8]
|
} else if (val == ID2('-','1')) { // DEC: dec rax
|
||||||
emit8(0x48); emit8(0x8B); emit8(0x04); emit8(0xC1);
|
emit8(0x48); emit8(0xFF); emit8(0xC8);
|
||||||
} else if (val == ID2('-','1')) { // DEC: dec rax
|
return;
|
||||||
emit8(0x48); emit8(0xFF); emit8(0xC8);
|
} else if (val == ID2('!',' ')) { // 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);
|
||||||
emit8(0x48); emit8(0x89); emit8(0x14); emit8(0xC1);
|
return;
|
||||||
} else if (val == ID2('R','0')) { // RET_IF_ZERO: test rax, rax; jnz +9; epilogue; ret
|
} else if (val == ID2('R','0')) { // RET_IF_ZERO: test rax, rax; jnz +1; ret
|
||||||
emit8(0x48); emit8(0x85); emit8(0xC0); // test rax, rax
|
emit8(0x48); emit8(0x85); emit8(0xC0); // test rax, rax
|
||||||
emit8(0x75); emit8(0x09); // jnz skip_ret (+9 bytes)
|
emit8(0x75); emit8(0x01); // jnz skip_ret (+1 byte)
|
||||||
emit8(0x48); emit8(0x89); emit8(0x41); emit8(0x70); // mov [rcx+112], rax
|
emit8(0xC3); // ret
|
||||||
emit8(0x48); emit8(0x89); emit8(0x51); emit8(0x78); // mov [rcx+120], rdx
|
return;
|
||||||
emit8(0xC3); // ret
|
} else if (val == ID2('R','E')) { // RET
|
||||||
} else if (val == ID2('F','S')) { // F_STEP (Inlined Compiler Macro)
|
emit8(0xC3);
|
||||||
compile_word(tmpl(STag, Data), 0);
|
return;
|
||||||
compile_word(tmpl(STag, Imm), ID2('@',' '));
|
}
|
||||||
compile_word(tmpl(STag, Imm), ID2('R','0'));
|
|
||||||
|
// Dictionary Resolver (Call User Word)
|
||||||
compile_word(tmpl(STag, Data), 1);
|
for (U8 i = 0; i < dict_count; i++) {
|
||||||
compile_word(tmpl(STag, Imm), ID2('@',' '));
|
if (dict[i].val == val) {
|
||||||
compile_word(tmpl(STag, Data), 0);
|
U4 target = dict[i].offset;
|
||||||
compile_word(tmpl(STag, Imm), ID2('@',' '));
|
U4 current = code_arena.used;
|
||||||
compile_word(tmpl(STag, Imm), ID2('M','*'));
|
S4 rel32 = (S4)target - (S4)(current + 5);
|
||||||
compile_word(tmpl(STag, Data), 1);
|
emit8(0xE8); // CALL rel32
|
||||||
compile_word(tmpl(STag, Imm), ID2('!',' '));
|
emit32((U4)rel32);
|
||||||
|
return;
|
||||||
compile_word(tmpl(STag, Data), 0);
|
|
||||||
compile_word(tmpl(STag, Imm), ID2('@',' '));
|
|
||||||
compile_word(tmpl(STag, Imm), ID2('-','1'));
|
|
||||||
compile_word(tmpl(STag, Data), 0);
|
|
||||||
compile_word(tmpl(STag, Imm), ID2('!',' '));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void compile_and_run_tape(void) {
|
IA_ void compile_and_run_tape(void) {
|
||||||
farena_reset(&code_arena);
|
farena_reset(&code_arena);
|
||||||
|
dict_count = 0;
|
||||||
|
|
||||||
// Prologue: Load VM state from globals[14] and [15]
|
// Prologue: Load VM state from globals[14] and [15]
|
||||||
emit8(0x48); emit8(0x8B); emit8(0x41); emit8(0x70); // mov rax, [rcx+112]
|
emit8(0x48); emit8(0x8B); emit8(0x41); emit8(0x70); // mov rax, [rcx+112]
|
||||||
emit8(0x48); emit8(0x8B); emit8(0x51); emit8(0x78); // mov rdx, [rcx+120]
|
emit8(0x48); emit8(0x8B); emit8(0x51); emit8(0x78); // mov rdx, [rcx+120]
|
||||||
|
|
||||||
// Compile the selected tokens
|
|
||||||
U4*r tape_ptr = C_(U4*r, tape_arena.start);
|
U4*r tape_ptr = C_(U4*r, tape_arena.start);
|
||||||
|
B4 in_def = false;
|
||||||
|
U4 def_jmp_offset = 0;
|
||||||
|
|
||||||
for (U8 i = 0; i <= cursor_idx; i++) {
|
for (U8 i = 0; i <= cursor_idx; i++) {
|
||||||
compile_word(UNPACK_TAG(tape_ptr[i]), UNPACK_VAL(tape_ptr[i]));
|
U4 tag = UNPACK_TAG(tape_ptr[i]);
|
||||||
|
U4 val = UNPACK_VAL(tape_ptr[i]);
|
||||||
|
|
||||||
|
if (tag == tmpl(STag, Define)) {
|
||||||
|
if (!in_def) {
|
||||||
|
emit8(0xE9); // JMP rel32 (Skip over definition body)
|
||||||
|
def_jmp_offset = code_arena.used;
|
||||||
|
emit32(0);
|
||||||
|
in_def = true;
|
||||||
|
}
|
||||||
|
if (dict_count < 256) {
|
||||||
|
dict[dict_count].val = val;
|
||||||
|
dict[dict_count].offset = code_arena.used;
|
||||||
|
dict_count++;
|
||||||
|
}
|
||||||
|
} else if (tag == tmpl(STag, Call)) {
|
||||||
|
compile_action(val);
|
||||||
|
if (val == ID2('R','E') && in_def) {
|
||||||
|
// End of definition block, patch the jump
|
||||||
|
U4 current = code_arena.used;
|
||||||
|
*(U4*)(code_arena.start + def_jmp_offset) = current - (def_jmp_offset + 4);
|
||||||
|
in_def = false;
|
||||||
|
}
|
||||||
|
} else if (tag == tmpl(STag, Data)) {
|
||||||
|
emit8(0x48); emit8(0x89); emit8(0xC2); // mov rdx, rax
|
||||||
|
emit8(0x48); emit8(0xC7); emit8(0xC0); emit32(val); // mov rax, imm32
|
||||||
|
} else if (tag == tmpl(STag, Imm)) {
|
||||||
|
if (in_def) {
|
||||||
|
// If we execute something, we jump out of def block first
|
||||||
|
U4 current = code_arena.used;
|
||||||
|
*(U4*)(code_arena.start + def_jmp_offset) = current - (def_jmp_offset + 4);
|
||||||
|
in_def = false;
|
||||||
|
}
|
||||||
|
compile_action(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_def) {
|
||||||
|
// If we hit cursor inside a definition, patch jump so it doesn't crash on execution
|
||||||
|
U4 current = code_arena.used;
|
||||||
|
*(U4*)(code_arena.start + def_jmp_offset) = current - (def_jmp_offset + 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Epilogue: Save VM state back to globals
|
// Epilogue: Save VM state back to globals
|
||||||
@@ -432,11 +478,37 @@ int main(void) {
|
|||||||
|
|
||||||
scatter(PACK_TOKEN(tmpl(STag, Format), 0xA)); // Newline
|
scatter(PACK_TOKEN(tmpl(STag, Format), 0xA)); // Newline
|
||||||
|
|
||||||
|
// Define the FS (Factorial Step) word in memory
|
||||||
|
scatter(PACK_TOKEN(tmpl(STag, Define), ID2('F','S')));
|
||||||
|
scatter(PACK_TOKEN(tmpl(STag, Data), 0));
|
||||||
|
scatter(PACK_TOKEN(tmpl(STag, Call), ID2('@',' ')));
|
||||||
|
scatter(PACK_TOKEN(tmpl(STag, Call), ID2('R','0')));
|
||||||
|
scatter(PACK_TOKEN(tmpl(STag, Format), 0xA)); // Newline
|
||||||
|
|
||||||
|
scatter(PACK_TOKEN(tmpl(STag, Data), 1));
|
||||||
|
scatter(PACK_TOKEN(tmpl(STag, Call), ID2('@',' ')));
|
||||||
|
scatter(PACK_TOKEN(tmpl(STag, Data), 0));
|
||||||
|
scatter(PACK_TOKEN(tmpl(STag, Call), ID2('@',' ')));
|
||||||
|
scatter(PACK_TOKEN(tmpl(STag, Call), ID2('M','*')));
|
||||||
|
scatter(PACK_TOKEN(tmpl(STag, Data), 1));
|
||||||
|
scatter(PACK_TOKEN(tmpl(STag, Call), ID2('!',' ')));
|
||||||
|
scatter(PACK_TOKEN(tmpl(STag, Format), 0xA)); // Newline
|
||||||
|
|
||||||
|
scatter(PACK_TOKEN(tmpl(STag, Data), 0));
|
||||||
|
scatter(PACK_TOKEN(tmpl(STag, Call), ID2('@',' ')));
|
||||||
|
scatter(PACK_TOKEN(tmpl(STag, Call), ID2('-','1')));
|
||||||
|
scatter(PACK_TOKEN(tmpl(STag, Data), 0));
|
||||||
|
scatter(PACK_TOKEN(tmpl(STag, Call), ID2('!',' ')));
|
||||||
|
scatter(PACK_TOKEN(tmpl(STag, Call), ID2('R','E'))); // Return!
|
||||||
|
|
||||||
|
scatter(PACK_TOKEN(tmpl(STag, Format), 0xA)); // Newline
|
||||||
|
|
||||||
|
// Call it
|
||||||
scatter(PACK_TOKEN(tmpl(STag, Imm), ID2('F','S'))); // ^FS
|
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')));
|
||||||
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;
|
MS_WNDCLASSA wc;
|
||||||
mem_fill(u8_(& wc), 0, sizeof(wc));
|
mem_fill(u8_(& wc), 0, sizeof(wc));
|
||||||
|
|||||||
Reference in New Issue
Block a user