This commit is contained in:
2026-02-20 22:10:29 -05:00
parent 2db4acd493
commit fd132c6efc
4 changed files with 201 additions and 186 deletions

View File

@@ -6,6 +6,7 @@ DO NOT EVER make a shell script unless told to. DO NOT EVER make a readme or a f
The user will often screenshot various aspects of the development with ShareX, which will be available in the current months directory: 'C:\Users\Ed\scoop\apps\sharex\current\ShareX\Screenshots\2026-02'
You may read fromt his and the user will let you know (by last modified) which of the last screenshots are the most relevant. Otherwise they manually paste relevant content in the './gallery' directory.
Do not use the .gitignore as a reference for WHAT YOU SHOULD IGNORE. THAT IS STRICT FOR THE GIT REPO, NOT FOR INFERENCING FILE RELEVANCE.
If a task is very heavy, use sub-agents (such as a codebase/docs/references investiagor, code editor, specifc pattern or nuance analyzer, etc).
## Coding Conventions

View File

@@ -36,8 +36,11 @@ The application presents a visual grid of 32-bit tokens and allows the user to n
## What's Missing (TODO)
* **Saving/Loading:** The tape and annotation arenas are purely in-memory and are lost when the program closes.
* **Expanded Instruction Set:** The JIT only knows a handful of primitives (`SWAP`, `MULT`, `ADD`, `FETCH`, `STORE`, `DEC`, `RET_IF_ZERO`, `PRINT`). It has no support for floating point, stack manipulation for C FFI, or more complex branches.
* **Robust Dictionary:** The current dictionary is a simple array that is rebuilt on every compile. It doesn't handle collisions, scoping, or namespaces.
* **Expanded Instruction Set:** The JIT only knows a handful of primitives (`SWAP`, `MULT`, `ADD`, `FETCH`, `STORE`, `DEC`, `RET_IF_ZERO`, `PRINT`). It has no support for floating point or more complex branches.
* **The FFI Bridge:** The system needs a macro (like Onat's `CCALL`) to align the `RSP` stack to 16 bytes and map the 2-register data stack/globals into the Windows C-ABI (`RCX`, `RDX`, `R8`, `R9`) to call WinAPI safely from the JIT.
* **Implicit Definition Boundaries (Magenta Pipe):** Definitions should not need explicit `begin`/`end`. A definition token should implicitly cause the JIT to emit a `RET` to close the prior block, and an `xchg rax, rdx` to rotate the stack for the new block.
* **x68 Instruction Padding:** The JIT currently emits variable-length instructions (`emit8`). It needs to pad every logical block/instruction to exact 32-bit multiples using ignored prefixes or NOPs to perfectly align with the visual token grid.
* **O(1) Dictionary & Visual Linking:** The current dictionary is a simple string-matched array rebuilt on compile. It needs to transition to a true "visual linker" where visual tokens store the absolute source memory indices, resolving locations instantly at edit-time.
* **Annotation Editing:** Typing into an annotation just appends characters. A proper text-editing cursor within the token is needed.
## References Utilized

View File

@@ -1,16 +1,13 @@
#include "duffle.amd64.win32.h"
// --- Semantic Tags (Using X-Macros & Enum_) ---
// Colors translated from Cozy-and-WIndy:
// 0x00bbggrr Win32 format
#define Tag_Entries() \
X(Define, "Define", 0x0018AEFF, ":") /* Orange-ish (Language.Type) */ \
X(Call, "Call", 0x00D6A454, "~") /* Soft Blue (Language.Class) */ \
X(Data, "Data", 0x0094BAA1, "$") /* Muted Green (Language.Number) */ \
X(Imm, "Imm", 0x004AA4C2, "^") /* Sand/Yellow (Language.Keyword) */ \
X(Comment, "Comment", 0x00AAAAAA, ".") /* Grey (Language.Comment) */ \
X(Format, "Format", 0x003A2F3B, " ") /* Current Line BG for invisibles */
X(Define, "Define", 0x0018AEFF, ":") \
X(Call, "Call", 0x00D6A454, "~") \
X(Data, "Data", 0x0094BAA1, "$") \
X(Imm, "Imm", 0x004AA4C2, "^") \
X(Comment, "Comment", 0x00AAAAAA, ".") \
X(Format, "Format", 0x003A2F3B, " ")
typedef Enum_(U4, STag) {
#define X(n, s, c, p) tmpl(STag, n),
@@ -34,55 +31,61 @@ global const char* tag_names[] = {
#undef X
};
// Token Packing: 28 bits payload | 4 bits tag
#define pack_token(tag, val) ((u4_(tag) << 28) | (u4_(val) & 0x0FFFFFFF))
#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
#define MODE_NAV 0
#define MODE_EDIT 1
// The Tape Drive (Using FArena from duffle)
global FArena tape_arena;
global FArena anno_arena;
global U8 cursor_idx = 0;
global U4 editor_mode = MODE_NAV;
global U4 mode_switch_now = false;
// Executable Code Arena (The JIT)
global FArena code_arena;
// VM State: 2-Reg Stack + Global Memory
global U8 vm_rax = 0; // Top
global U8 vm_rdx = 0; // Next
global U8 vm_rax = 0;
global U8 vm_rdx = 0;
global U8 vm_globals[16] = {0};
// Execution Mode & Logging
global B4 run_full = false;
global U8 log_buffer[16] = {0};
global U4 log_count = 0;
// UI State
global S4 scroll_y_offset = 0;
void ms_builtin_print(U8 val) {
if (log_count < 16) {
log_buffer[log_count++] = val;
}
if (log_count < 16) log_buffer[log_count++] = val;
}
// Dictionary
typedef struct {
U4 val;
U4 offset;
} DictEntry;
global DictEntry dict[256];
global U8 dict_count = 0;
// Visual Linker & O(1) Dictionary
global U4 tape_to_code_offset[65536] = {0};
#define PRIM_SWAP 1
#define PRIM_MULT 2
#define PRIM_ADD 3
#define PRIM_FETCH 4
#define PRIM_DEC 5
#define PRIM_STORE 6
#define PRIM_RET_Z 7
#define PRIM_RET 8
#define PRIM_PRINT 9
global const char* prim_names[] = {
"",
"SWAP ",
"MULT ",
"ADD ",
"FETCH ",
"DEC ",
"STORE ",
"RET_IF_Z",
"RETURN ",
"PRINT "
};
IA_ void scatter(U4 token, const char* anno_str) {
if (tape_arena.used + sizeof(U4) <= tape_arena.capacity && anno_arena.used + sizeof(U8) <= anno_arena.capacity) {
@@ -93,96 +96,138 @@ IA_ void scatter(U4 token, const char* anno_str) {
aptr[0] = 0;
if (anno_str) {
char* dest = (char*)aptr;
int i = 0; while(i < 8 && anno_str[i]) {
dest[i] = anno_str[i];
i ++;
}
int i = 0; while(i < 8 && anno_str[i]) { dest[i] = anno_str[i]; i ++; }
}
anno_arena.used += sizeof(U8);
}
}
// --- Minimal x86-64 Emitter ---
internal void emit8(U1 b) {
if (code_arena.used + 1 <= code_arena.capacity) {
U1*r ptr = u1_r(code_arena.start + code_arena.used);
ptr[0] = b;
u1_r(code_arena.start + code_arena.used)[0] = b;
code_arena.used += 1;
}
}
internal void emit32(U4 val) {
if (code_arena.used + 4 <= code_arena.capacity) {
U4*r ptr = u4_r(code_arena.start + code_arena.used);
ptr[0] = val;
u4_r(code_arena.start + code_arena.used)[0] = val;
code_arena.used += 4;
}
}
internal void pad32(void) {
while ((code_arena.used % 4) != 0) emit8(0x90);
}
internal void relink_tape(void) {
U8 tape_count = tape_arena.used / sizeof(U4);
U4*r tape_ptr = u4_r(tape_arena.start);
U8*r anno_ptr = u8_r(anno_arena.start);
for (U8 i = 0; i < tape_count; i++) {
U4 t = tape_ptr[i];
U4 tag = unpack_tag(t);
if (tag == STag_Call || tag == STag_Imm) {
char* ref_name = (char*)&anno_ptr[i];
U4 new_val = 0;
for (int p = 1; p <= 9; p++) {
int match = 1;
for (int c = 0; c < 8; c++) {
char c1 = ref_name[c] ? ref_name[c] : ' ';
char c2 = prim_names[p][c] ? prim_names[p][c] : ' ';
if (c1 != c2) { match = 0; break; }
}
if (match) { new_val = p; break; }
}
if (new_val == 0) {
for (U8 j = 0; j < tape_count; j++) {
if (unpack_tag(tape_ptr[j]) == STag_Define) {
char* def_name = (char*)&anno_ptr[j];
int match = 1;
for (int c = 0; c < 8; c++) {
char c1 = ref_name[c] ? ref_name[c] : ' ';
char c2 = def_name[c] ? def_name[c] : ' ';
if (c1 != c2) { match = 0; break; }
}
if (match) { new_val = j; break; }
}
}
}
tape_ptr[i] = pack_token(tag, new_val);
}
}
}
internal void compile_action(U4 val)
{
if (val == id2('S','W')) { // SWAP: xchg rax, rdx
if (val == PRIM_SWAP) {
emit8(0x48); emit8(0x87); emit8(0xC2);
pad32();
return;
} else if (val == id2('M','*')) { // MULT: imul rax, rdx
} else if (val == PRIM_MULT) {
emit8(0x48); emit8(0x0F); emit8(0xAF); emit8(0xC2);
pad32();
return;
} else if (val == id2('+',' ')) { // ADD: add rax, rdx
} else if (val == PRIM_ADD) {
emit8(0x48); emit8(0x01); emit8(0xD0);
pad32();
return;
} else if (val == id2('@',' ')) { // FETCH: mov rax, QWORD PTR [rcx + rax*8]
} else if (val == PRIM_FETCH) {
emit8(0x48); emit8(0x8B); emit8(0x04); emit8(0xC1);
pad32();
return;
} else if (val == id2('-','1')) { // DEC: dec rax
} else if (val == PRIM_DEC) {
emit8(0x48); emit8(0xFF); emit8(0xC8);
pad32();
return;
} else if (val == id2('!',' ')) { // STORE: mov QWORD PTR [rcx + rax*8], rdx
} else if (val == PRIM_STORE) {
emit8(0x48); emit8(0x89); emit8(0x14); emit8(0xC1);
pad32();
return;
} 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(0x75); emit8(0x01); // jnz skip_ret (+1 byte)
emit8(0xC3); // ret
} else if (val == PRIM_RET_Z) {
emit8(0x48); emit8(0x85); emit8(0xC0);
emit8(0x75); emit8(0x01);
emit8(0xC3);
pad32();
return;
} else if (val == id2('R','E')) { // RET
} else if (val == PRIM_RET) {
emit8(0xC3);
pad32();
return;
} else if (val == id2('P','R')) { // PRINT: call ms_builtin_print
emit8(0x51); // push rcx
emit8(0x52); // push rdx
emit8(0x48); emit8(0x83); emit8(0xEC); emit8(0x20); // sub rsp, 32
emit8(0x48); emit8(0x89); emit8(0xC1); // mov rcx, rax
emit8(0x49); emit8(0xB8); // mov r8, imm64
} else if (val == PRIM_PRINT) {
emit8(0x51); emit8(0x52);
emit8(0x48); emit8(0x83); emit8(0xEC); emit8(0x20);
emit8(0x48); emit8(0x89); emit8(0xC1);
emit8(0x49); emit8(0xB8);
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(0x59); // pop rcx
emit8(0x41); emit8(0xFF); emit8(0xD0);
emit8(0x48); emit8(0x83); emit8(0xC4); emit8(0x20);
emit8(0x5A); emit8(0x59);
pad32();
return;
}
// Dictionary Resolver (Call User Word)
for (U8 entry = 0; entry < dict_count; entry++) {
if (dict[entry].val == val) {
U4 target = dict[entry].offset;
U4 current = code_arena.used;
S4 rel32 = s4_(target) - s4_(current + 5);
emit8(0xE8); // CALL rel32
emit32(u4_(rel32));
return;
}
if (val > 0) {
U4 target = tape_to_code_offset[val];
pad32();
S4 rel32 = s4_(target) - s4_(code_arena.used + 5);
emit8(0xE8);
emit32(u4_(rel32));
pad32();
}
}
IA_ void compile_and_run_tape(void)
{
farena_reset(& code_arena);
dict_count = 0;
log_count = 0;
// 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(0x51); emit8(0x78); // mov rdx, [rcx+120]
emit8(0x48); emit8(0x8B); emit8(0x41); emit8(0x70);
emit8(0x48); emit8(0x8B); emit8(0x51); emit8(0x78);
U4*r tape_ptr = u4_r(tape_arena.start);
B4 in_def = false;
@@ -195,35 +240,36 @@ IA_ void compile_and_run_tape(void)
if (tag == STag_Define)
{
if (in_def == false) {
emit8(0xE9); // JMP rel32 (Skip over definition body)
pad32();
emit8(0xE9);
def_jmp_offset = code_arena.used;
emit32(0);
pad32();
in_def = true;
} else {
emit8(0xC3);
pad32();
}
if (dict_count < 256) {
dict[dict_count].val = val;
dict[dict_count].offset = code_arena.used;
dict_count++;
}
tape_to_code_offset[i] = code_arena.used;
emit8(0x48); emit8(0x87); emit8(0xC2);
pad32();
}
else if (tag == 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_r(code_arena.start + def_jmp_offset)[0] = current - (def_jmp_offset + 4);
in_def = false;
}
}
else if (tag == STag_Data) {
emit8(0x48); emit8(0x89); emit8(0xC2); // mov rdx, rax
emit8(0x48); emit8(0xC7); emit8(0xC0); emit32(val); // mov rax, imm32
emit8(0x48); emit8(0x89); emit8(0xC2);
emit8(0x48); emit8(0xC7); emit8(0xC0); emit32(val);
pad32();
}
else if (tag == STag_Imm)
{
if (in_def) {
// If we execute something, we jump out of def block first
emit8(0xC3);
pad32();
U4 current = code_arena.used;
u4_r(code_arena.start + def_jmp_offset)[0] = current - (def_jmp_offset + 4);
in_def = false;
@@ -233,27 +279,24 @@ IA_ void compile_and_run_tape(void)
}
if (in_def) {
// If we hit cursor inside a definition, patch jump so it doesn't crash on execution
emit8(0xC3);
pad32();
U4 current = code_arena.used;
u4_r(code_arena.start + def_jmp_offset)[0] = current - (def_jmp_offset + 4);
}
// Epilogue: Save VM state back to globals
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
emit8(0x48); emit8(0x89); emit8(0x41); emit8(0x70);
emit8(0x48); emit8(0x89); emit8(0x51); emit8(0x78);
emit8(0xC3);
// Cast code arena to function pointer and CALL it!
typedef void JIT_Func(U8* globals_ptr);
JIT_Func* func = (JIT_Func*)code_arena.start;
func(vm_globals);
// Read state for UI
vm_rax = vm_globals[14];
vm_rdx = vm_globals[15];
}
// --- Window Procedure ---
S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
{
U8 tape_count = tape_arena.used / sizeof(U4);
@@ -267,12 +310,10 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
U4 val = unpack_val(t);
U1 c = u1_(wparam);
// Skip control characters and the 'E' that triggered the mode
bool should_skip = c < 32 || (c == 'e' && mode_switch_now);
if (should_skip) { mode_switch_now = false; return 0; }
if (tag == STag_Data) {
// Hex input
U4 digit = 16;
if (c >= '0' && c <= '9') digit = c - '0';
if (c >= 'a' && c <= 'f') digit = c - 'a' + 10;
@@ -290,28 +331,22 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
if (len < 8) {
anno_str[len] = (char)c;
for (int i = len + 1; i < 8; i++) anno_str[i] = '\0';
// Update the 2-char token ID from the first 2 chars
char c1 = anno_str[0] ? anno_str[0] : ' ';
char c2 = anno_str[1] ? anno_str[1] : ' ';
val = id2(c1, c2);
tape_ptr[cursor_idx] = pack_token(tag, val);
}
}
vm_rax = 0; vm_rdx = 0; mem_zero(u8_(vm_globals), sizeof(vm_globals));
relink_tape();
compile_and_run_tape();
ms_invalidate_rect(hwnd, nullptr, true);
return 0;
}
case MS_WM_KEYDOWN: {
if (wparam == 0x45 && editor_mode == MODE_NAV) { // 'E'
if (wparam == 0x45 && editor_mode == MODE_NAV) {
editor_mode = MODE_EDIT;
mode_switch_now = true;
ms_invalidate_rect(hwnd, nullptr, true);
return 0;
// ~~Consume the keypress so it doesn't trigger WM_CHAR~~
// NOTE(Ed): Still triggers WM_CHAR we need to track when we just entered edit mode and that must be consumed.
}
if (wparam == 0x1B && editor_mode == MODE_EDIT) { // ESC
if (wparam == 0x1B && editor_mode == MODE_EDIT) {
editor_mode = MODE_NAV;
ms_invalidate_rect(hwnd, nullptr, true);
return 0;
@@ -332,16 +367,14 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
while (len < 8 && anno_str[len] != '\0' && anno_str[len] != ' ') len ++;
if (len > 0) {
anno_str[len - 1] = '\0';
char c1 = anno_str[0] ? anno_str[0] : ' ';
char c2 = anno_str[1] ? anno_str[1] : ' ';
tape_ptr[cursor_idx] = pack_token(tag, id2(c1, c2));
}
}
vm_rax = 0; vm_rdx = 0; mem_zero(u8_(vm_globals), sizeof(vm_globals));
relink_tape();
compile_and_run_tape();
ms_invalidate_rect(hwnd, nullptr, true);
}
return 0; // Block navigation keys in Edit Mode
return 0;
}
if (wparam == MS_VK_RIGHT && cursor_idx < tape_count - 1) cursor_idx ++;
@@ -365,7 +398,7 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
U8 next_line_start = cursor_idx;
while (next_line_start < tape_count && unpack_tag(tape_ptr[next_line_start]) != STag_Format) next_line_start ++;
if (next_line_start < tape_count) {
next_line_start ++; // Skip the newline
next_line_start ++;
U8 next_line_end = next_line_start;
while (next_line_end < tape_count && unpack_tag(tape_ptr[next_line_end]) != STag_Format) next_line_end ++;
U8 next_line_len = next_line_end - next_line_start;
@@ -378,15 +411,12 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
if (wparam == MS_VK_F5) { run_full = !run_full; }
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
// Shift: delete AT cursor | Regular: delete TO THE LEFT
U8 delete_idx = cursor_idx;
B4 is_shift = (ms_get_async_key_state(MS_VK_SHIFT) & 0x8000) != 0;
if (is_shift == false) {
@@ -407,8 +437,6 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
}
}
else if (wparam == MS_VK_SPACE || wparam == MS_VK_RETURN) {
// Insert New Token
// Shift: insert AFTER cursor | Regular: insert BEFORE cursor
B4 is_shift = (ms_get_async_key_state(MS_VK_SHIFT) & 0x8000) != 0;
U8 insert_idx = cursor_idx;
if (is_shift) insert_idx ++;
@@ -423,7 +451,7 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
tape_ptr[insert_idx] = pack_token(STag_Format, 0xA);
anno_ptr[insert_idx] = 0;
} else {
tape_ptr[insert_idx] = pack_token(STag_Comment, id2(' ',' '));
tape_ptr[insert_idx] = pack_token(STag_Comment, 0);
anno_ptr[insert_idx] = 0;
}
if (is_shift) cursor_idx ++;
@@ -432,10 +460,10 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
}
}
// Interaction: Reset VM and compile
vm_rax = 0; vm_rdx = 0;
mem_zero(u8_(vm_globals), sizeof(vm_globals));
relink_tape();
compile_and_run_tape();
ms_invalidate_rect(hwnd, nullptr, true);
@@ -447,7 +475,7 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
void* hFont = ms_create_font_a(20, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, "Consolas");
void* hOldFont = ms_select_object(hdc, hFont);
ms_set_bk_mode(hdc, 1); // TRANSPARENT text background
ms_set_bk_mode(hdc, 1);
void* hBgBrush = ms_create_solid_brush(0x00222222);
ms_select_object(hdc, hBgBrush);
@@ -462,7 +490,6 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
U4*r tape_ptr = u4_r(tape_arena.start);
U8*r anno_ptr = u8_r(anno_arena.start);
// Render Tokens
for (U8 i = 0; i < tape_count; i++)
{
if (x >= start_x + (TOKENS_PER_ROW * spacing_x)) {
@@ -492,7 +519,6 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
ms_set_text_color(hdc, color);
if (editor_mode == MODE_EDIT && i == cursor_idx) {
// Better visibility in Edit Mode: White text on White-ish cursor
ms_set_text_color(hdc, 0x001E1E1E);
}
@@ -503,19 +529,11 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
}
else
{
// Extract annotation string
char* a_str = (char*) & anno;
if (a_str[0] == '\0') {
// Fallback to 2-character 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';
}
else {
mem_copy(u8_(val_str), u8_(a_str), 8);
val_str[8] = '\0';
for(int c=0; c<8; c++) {
val_str[c] = a_str[c] ? a_str[c] : ' ';
}
val_str[8] = '\0';
}
char out_buf[12];
out_buf[0] = prefix[0];
@@ -536,7 +554,6 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
}
}
// Draw a solid background behind the HUD to cover scrolling text
void* hHudBrush = ms_create_solid_brush(0x00141E23);
ms_select_object(hdc, hHudBrush);
ms_rectangle(hdc, -1, 500, 3000, 3000);
@@ -545,7 +562,6 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
ms_set_text_color(hdc, 0x00AAAAAA);
ms_text_out_a(hdc, 40, 10, "x86-64 Machine Code Emitter | 2-Reg Stack | [F5] Toggle Run Mode | [PgUp/PgDn] Scroll", 85);
// Render VM State
ms_set_text_color(hdc, 0x00FFFFFF);
char jit_str[64] = "Mode: Incremental | JIT Size: 0x000 bytes";
if (run_full) mem_copy(u8_(jit_str + 6), u8_("Full "), 11);
@@ -555,10 +571,9 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
char state_str[64] = "RAX: 00000000 | RDX: 00000000";
u64_to_hex(vm_rax, state_str + 5, 8);
u64_to_hex(vm_rdx, state_str + 21, 8);
ms_set_text_color(hdc, 0x0094BAA1); // Number green
ms_set_text_color(hdc, 0x0094BAA1);
ms_text_out_a(hdc, 40, 550, state_str, 29);
// HUD: Display Current Token Meaning
if (tape_count > 0 && cursor_idx < tape_count) {
U4 cur_tag = unpack_tag(tape_ptr[cursor_idx]);
const char* tag_name = tag_names [cur_tag];
@@ -580,11 +595,10 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
char glob_str[32] = "[0]: 00000000";
glob_str[1] = '0' + i;
u64_to_hex(vm_globals[i], glob_str + 5, 8);
ms_set_text_color(hdc, 0x00D6A454); // Soft blue
ms_set_text_color(hdc, 0x00D6A454);
ms_text_out_a(hdc, 400, 550 + (i * 25), glob_str, 13);
}
// Print Log
ms_set_text_color(hdc, 0x00C8C8C8);
ms_text_out_a(hdc, 750, 520, "Print Log:", 10);
for (int i = 0; i<log_count && i < 4; i ++) {
@@ -607,7 +621,6 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
}
int main(void) {
// 1. Initialize Memory Arenas using WinAPI + FArena
Slice tape_mem = slice_ut_(u8_(ms_virtual_alloc(nullptr, 64 * 1024, MS_MEM_COMMIT | MS_MEM_RESERVE, MS_PAGE_READWRITE)), 64 * 1024);
Slice anno_mem = slice_ut_(u8_(ms_virtual_alloc(nullptr, 64 * 1024, MS_MEM_COMMIT | MS_MEM_RESERVE, MS_PAGE_READWRITE)), 64 * 1024);
Slice code_mem = slice_ut_(u8_(ms_virtual_alloc(nullptr, 64 * 1024, MS_MEM_COMMIT | MS_MEM_RESERVE, MS_PAGE_EXECUTE_READWRITE)), 64 * 1024);
@@ -617,54 +630,51 @@ int main(void) {
farena_init(& anno_arena, anno_mem);
farena_init(& code_arena, code_mem);
// Bootstrap Robust Sample: Factorial State Machine
scatter(pack_token(STag_Comment, id2('I','N')), "INIT "); // .IN
scatter(pack_token(STag_Data, 5), 0); // $5
scatter(pack_token(STag_Data, 0), 0); // $0 (Addr)
scatter(pack_token(STag_Imm, id2('!',' ')), "STORE "); // ^!
scatter(pack_token(STag_Comment, 0), "INIT ");
scatter(pack_token(STag_Data, 5), 0);
scatter(pack_token(STag_Data, 0), 0);
scatter(pack_token(STag_Imm, 0), "STORE ");
scatter(pack_token(STag_Data, 1), 0); // $1
scatter(pack_token(STag_Data, 1), 0); // $1 (Addr)
scatter(pack_token(STag_Imm, id2('!',' ')), "STORE "); // ^!
scatter(pack_token(STag_Data, 1), 0);
scatter(pack_token(STag_Data, 1), 0);
scatter(pack_token(STag_Imm, 0), "STORE ");
scatter(pack_token(STag_Format, 0xA), 0); // Newline
scatter(pack_token(STag_Format, 0xA), 0);
// Define the FS (Factorial Step) word in memory
scatter(pack_token(STag_Define, id2('F','S')), "F_STEP ");
scatter(pack_token(STag_Data, 0), 0);
scatter(pack_token(STag_Call, id2('@',' ')), "FETCH ");
scatter(pack_token(STag_Call, id2('R','0')), "RET_IF_Z");
scatter(pack_token(STag_Format, 0xA), 0); // Newline
scatter(pack_token(STag_Define, 0), "F_STEP ");
scatter(pack_token(STag_Data, 0), 0);
scatter(pack_token(STag_Call, 0), "FETCH ");
scatter(pack_token(STag_Call, 0), "RET_IF_Z");
scatter(pack_token(STag_Format, 0xA), 0);
scatter(pack_token(STag_Data, 1), 0);
scatter(pack_token(STag_Call, id2('@',' ')), "FETCH ");
scatter(pack_token(STag_Data, 0), 0);
scatter(pack_token(STag_Call, id2('@',' ')), "FETCH ");
scatter(pack_token(STag_Call, id2('M','*')), "MULT ");
scatter(pack_token(STag_Data, 1), 0);
scatter(pack_token(STag_Call, id2('!',' ')), "STORE ");
scatter(pack_token(STag_Format, 0xA), 0); // Newline
scatter(pack_token(STag_Data, 1), 0);
scatter(pack_token(STag_Call, 0), "FETCH ");
scatter(pack_token(STag_Data, 0), 0);
scatter(pack_token(STag_Call, 0), "FETCH ");
scatter(pack_token(STag_Call, 0), "MULT ");
scatter(pack_token(STag_Data, 1), 0);
scatter(pack_token(STag_Call, 0), "STORE ");
scatter(pack_token(STag_Format, 0xA), 0);
scatter(pack_token(STag_Data, 0), 0);
scatter(pack_token(STag_Call, id2('@',' ')), "FETCH ");
scatter(pack_token(STag_Call, id2('-','1')), "DEC ");
scatter(pack_token(STag_Data, 0), 0);
scatter(pack_token(STag_Call, id2('!',' ')), "STORE ");
scatter(pack_token(STag_Data, 0), 0);
scatter(pack_token(STag_Call, 0), "FETCH ");
scatter(pack_token(STag_Call, 0), "DEC ");
scatter(pack_token(STag_Data, 0), 0);
scatter(pack_token(STag_Call, 0), "STORE ");
scatter(pack_token(STag_Data, 1), 0);
scatter(pack_token(STag_Call, id2('@',' ')), "FETCH ");
scatter(pack_token(STag_Call, id2('P','R')), "PRINT "); // Print Accumulator!
scatter(pack_token(STag_Data, 1), 0);
scatter(pack_token(STag_Call, 0), "FETCH ");
scatter(pack_token(STag_Call, 0), "PRINT ");
scatter(pack_token(STag_Call, id2('R','E')), "RETURN "); // Return!
scatter(pack_token(STag_Format, 0xA), 0);
scatter(pack_token(STag_Format, 0xA), 0); // Newline
// Call it
scatter(pack_token(STag_Imm, id2('F','S')), "F_STEP "); // ^FS
scatter(pack_token(STag_Imm, id2('F','S')), "F_STEP ");
scatter(pack_token(STag_Imm, id2('F','S')), "F_STEP ");
scatter(pack_token(STag_Imm, id2('F','S')), "F_STEP ");
scatter(pack_token(STag_Imm, id2('F','S')), "F_STEP ");
scatter(pack_token(STag_Imm, 0), "F_STEP ");
scatter(pack_token(STag_Imm, 0), "F_STEP ");
scatter(pack_token(STag_Imm, 0), "F_STEP ");
scatter(pack_token(STag_Imm, 0), "F_STEP ");
scatter(pack_token(STag_Imm, 0), "F_STEP ");
relink_tape();
MS_WNDCLASSA wc;
mem_fill(u8_(& wc), 0, sizeof(wc));
@@ -679,4 +689,4 @@ int main(void) {
while (ms_get_message_a(& msg, nullptr, 0, 0)) { ms_translate_message(& msg); ms_dispatch_message_a(& msg); }
ms_exit_process(0);
return 0;
}
}

View File

@@ -19,10 +19,11 @@ This document serves as the master blueprint for the research and curation phase
## 3. Onat's VAMP/KYRA Architecture (The Runtime/Codegen)
* **2-Item Register Stack:** Uses `RAX` and `RDX` as a tiny, hardware-resident stack.
* **The Swap:** `xchg rax, rdx` (1-byte: `48 87 C2`) is emitted to rotate the "top of stack".
* **The Swap / Magenta Pipe:** A definition boundary implicitly emits `RET` (to close the last block) followed by `xchg rax, rdx` (1-byte: `48 87 C2` or `48 92`) to rotate the "top of stack" for the new block.
* **Aliased Global Namespace:** The CPU register file is treated as a shared, aliased memory space for functions.
* **Functions as Blocks:** Words are "free of arguments and returns" in the traditional sense.
* **Preemptive Scatter ("Tape Drive"):** Arguments are pre-placed into fixed, contiguous memory slots ("the tape") by the compiler/loader before execution. This eliminates "argument gathering" during function calls.
* **The FFI Dance (C-ABI Integration):** To call OS APIs (like WinAPI or Vulkan), the hardware stack pointer (`RSP`) must be strictly 16-byte aligned. Custom macros (like `CCALL`) must save state, align `RSP`, map the 2-register stack into C-ABI registers (`RCX`, `RDX`, `R8`, `R9`), execute the `CALL`, and restore `RSP`.
## 4. Implementation Components
* **Emitter:** **Zydis Encoder API**. Zero-allocation, sub-5ms instruction generation.