progress
This commit is contained in:
@@ -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'
|
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.
|
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.
|
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
|
## Coding Conventions
|
||||||
|
|
||||||
|
|||||||
@@ -36,8 +36,11 @@ The application presents a visual grid of 32-bit tokens and allows the user to n
|
|||||||
## What's Missing (TODO)
|
## What's Missing (TODO)
|
||||||
|
|
||||||
* **Saving/Loading:** The tape and annotation arenas are purely in-memory and are lost when the program closes.
|
* **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.
|
* **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.
|
||||||
* **Robust Dictionary:** The current dictionary is a simple array that is rebuilt on every compile. It doesn't handle collisions, scoping, or namespaces.
|
* **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.
|
* **Annotation Editing:** Typing into an annotation just appends characters. A proper text-editing cursor within the token is needed.
|
||||||
|
|
||||||
## References Utilized
|
## References Utilized
|
||||||
|
|||||||
376
attempt_1/main.c
376
attempt_1/main.c
@@ -1,16 +1,13 @@
|
|||||||
#include "duffle.amd64.win32.h"
|
#include "duffle.amd64.win32.h"
|
||||||
|
|
||||||
// --- Semantic Tags (Using X-Macros & Enum_) ---
|
// --- Semantic Tags (Using X-Macros & Enum_) ---
|
||||||
// Colors translated from Cozy-and-WIndy:
|
|
||||||
// 0x00bbggrr Win32 format
|
|
||||||
|
|
||||||
#define Tag_Entries() \
|
#define Tag_Entries() \
|
||||||
X(Define, "Define", 0x0018AEFF, ":") /* Orange-ish (Language.Type) */ \
|
X(Define, "Define", 0x0018AEFF, ":") \
|
||||||
X(Call, "Call", 0x00D6A454, "~") /* Soft Blue (Language.Class) */ \
|
X(Call, "Call", 0x00D6A454, "~") \
|
||||||
X(Data, "Data", 0x0094BAA1, "$") /* Muted Green (Language.Number) */ \
|
X(Data, "Data", 0x0094BAA1, "$") \
|
||||||
X(Imm, "Imm", 0x004AA4C2, "^") /* Sand/Yellow (Language.Keyword) */ \
|
X(Imm, "Imm", 0x004AA4C2, "^") \
|
||||||
X(Comment, "Comment", 0x00AAAAAA, ".") /* Grey (Language.Comment) */ \
|
X(Comment, "Comment", 0x00AAAAAA, ".") \
|
||||||
X(Format, "Format", 0x003A2F3B, " ") /* Current Line BG for invisibles */
|
X(Format, "Format", 0x003A2F3B, " ")
|
||||||
|
|
||||||
typedef Enum_(U4, STag) {
|
typedef Enum_(U4, STag) {
|
||||||
#define X(n, s, c, p) tmpl(STag, n),
|
#define X(n, s, c, p) tmpl(STag, n),
|
||||||
@@ -34,55 +31,61 @@ global const char* tag_names[] = {
|
|||||||
#undef X
|
#undef X
|
||||||
};
|
};
|
||||||
|
|
||||||
// Token Packing: 28 bits payload | 4 bits tag
|
|
||||||
#define pack_token(tag, val) ((u4_(tag) << 28) | (u4_(val) & 0x0FFFFFFF))
|
#define pack_token(tag, val) ((u4_(tag) << 28) | (u4_(val) & 0x0FFFFFFF))
|
||||||
#define unpack_tag(token) ( ((token) >> 28) & 0x0F)
|
#define unpack_tag(token) ( ((token) >> 28) & 0x0F)
|
||||||
#define unpack_val(token) ( (token) & 0x0FFFFFFF)
|
#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 TOKENS_PER_ROW 8
|
||||||
|
|
||||||
#define MODE_NAV 0
|
#define MODE_NAV 0
|
||||||
#define MODE_EDIT 1
|
#define MODE_EDIT 1
|
||||||
|
|
||||||
// The Tape Drive (Using FArena from duffle)
|
|
||||||
global FArena tape_arena;
|
global FArena tape_arena;
|
||||||
global FArena anno_arena;
|
global FArena anno_arena;
|
||||||
global U8 cursor_idx = 0;
|
global U8 cursor_idx = 0;
|
||||||
global U4 editor_mode = MODE_NAV;
|
global U4 editor_mode = MODE_NAV;
|
||||||
global U4 mode_switch_now = false;
|
global U4 mode_switch_now = false;
|
||||||
|
|
||||||
// Executable Code Arena (The JIT)
|
|
||||||
global FArena code_arena;
|
global FArena code_arena;
|
||||||
|
|
||||||
// VM State: 2-Reg Stack + Global Memory
|
global U8 vm_rax = 0;
|
||||||
global U8 vm_rax = 0; // Top
|
global U8 vm_rdx = 0;
|
||||||
global U8 vm_rdx = 0; // Next
|
|
||||||
global U8 vm_globals[16] = {0};
|
global U8 vm_globals[16] = {0};
|
||||||
|
|
||||||
// Execution Mode & Logging
|
|
||||||
global B4 run_full = false;
|
global B4 run_full = false;
|
||||||
global U8 log_buffer[16] = {0};
|
global U8 log_buffer[16] = {0};
|
||||||
global U4 log_count = 0;
|
global U4 log_count = 0;
|
||||||
|
|
||||||
// UI State
|
|
||||||
global S4 scroll_y_offset = 0;
|
global S4 scroll_y_offset = 0;
|
||||||
|
|
||||||
void ms_builtin_print(U8 val) {
|
void ms_builtin_print(U8 val) {
|
||||||
if (log_count < 16) {
|
if (log_count < 16) log_buffer[log_count++] = val;
|
||||||
log_buffer[log_count++] = val;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dictionary
|
// Visual Linker & O(1) Dictionary
|
||||||
typedef struct {
|
global U4 tape_to_code_offset[65536] = {0};
|
||||||
U4 val;
|
|
||||||
U4 offset;
|
#define PRIM_SWAP 1
|
||||||
} DictEntry;
|
#define PRIM_MULT 2
|
||||||
global DictEntry dict[256];
|
#define PRIM_ADD 3
|
||||||
global U8 dict_count = 0;
|
#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) {
|
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) {
|
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;
|
aptr[0] = 0;
|
||||||
if (anno_str) {
|
if (anno_str) {
|
||||||
char* dest = (char*)aptr;
|
char* dest = (char*)aptr;
|
||||||
int i = 0; while(i < 8 && anno_str[i]) {
|
int i = 0; while(i < 8 && anno_str[i]) { dest[i] = anno_str[i]; i ++; }
|
||||||
dest[i] = anno_str[i];
|
|
||||||
i ++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
anno_arena.used += sizeof(U8);
|
anno_arena.used += sizeof(U8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Minimal x86-64 Emitter ---
|
|
||||||
internal void emit8(U1 b) {
|
internal void emit8(U1 b) {
|
||||||
if (code_arena.used + 1 <= code_arena.capacity) {
|
if (code_arena.used + 1 <= code_arena.capacity) {
|
||||||
U1*r ptr = u1_r(code_arena.start + code_arena.used);
|
u1_r(code_arena.start + code_arena.used)[0] = b;
|
||||||
ptr[0] = b;
|
|
||||||
code_arena.used += 1;
|
code_arena.used += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal void emit32(U4 val) {
|
internal void emit32(U4 val) {
|
||||||
if (code_arena.used + 4 <= code_arena.capacity) {
|
if (code_arena.used + 4 <= code_arena.capacity) {
|
||||||
U4*r ptr = u4_r(code_arena.start + code_arena.used);
|
u4_r(code_arena.start + code_arena.used)[0] = val;
|
||||||
ptr[0] = val;
|
|
||||||
code_arena.used += 4;
|
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)
|
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);
|
emit8(0x48); emit8(0x87); emit8(0xC2);
|
||||||
|
pad32();
|
||||||
return;
|
return;
|
||||||
} else if (val == id2('M','*')) { // MULT: imul rax, rdx
|
} else if (val == PRIM_MULT) {
|
||||||
emit8(0x48); emit8(0x0F); emit8(0xAF); emit8(0xC2);
|
emit8(0x48); emit8(0x0F); emit8(0xAF); emit8(0xC2);
|
||||||
|
pad32();
|
||||||
return;
|
return;
|
||||||
} else if (val == id2('+',' ')) { // ADD: add rax, rdx
|
} else if (val == PRIM_ADD) {
|
||||||
emit8(0x48); emit8(0x01); emit8(0xD0);
|
emit8(0x48); emit8(0x01); emit8(0xD0);
|
||||||
|
pad32();
|
||||||
return;
|
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);
|
emit8(0x48); emit8(0x8B); emit8(0x04); emit8(0xC1);
|
||||||
|
pad32();
|
||||||
return;
|
return;
|
||||||
} else if (val == id2('-','1')) { // DEC: dec rax
|
} else if (val == PRIM_DEC) {
|
||||||
emit8(0x48); emit8(0xFF); emit8(0xC8);
|
emit8(0x48); emit8(0xFF); emit8(0xC8);
|
||||||
|
pad32();
|
||||||
return;
|
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);
|
emit8(0x48); emit8(0x89); emit8(0x14); emit8(0xC1);
|
||||||
|
pad32();
|
||||||
return;
|
return;
|
||||||
} else if (val == id2('R','0')) { // RET_IF_ZERO: test rax, rax; jnz +1; ret
|
} else if (val == PRIM_RET_Z) {
|
||||||
emit8(0x48); emit8(0x85); emit8(0xC0); // test rax, rax
|
emit8(0x48); emit8(0x85); emit8(0xC0);
|
||||||
emit8(0x75); emit8(0x01); // jnz skip_ret (+1 byte)
|
emit8(0x75); emit8(0x01);
|
||||||
emit8(0xC3); // ret
|
emit8(0xC3);
|
||||||
|
pad32();
|
||||||
return;
|
return;
|
||||||
} else if (val == id2('R','E')) { // RET
|
} else if (val == PRIM_RET) {
|
||||||
emit8(0xC3);
|
emit8(0xC3);
|
||||||
|
pad32();
|
||||||
return;
|
return;
|
||||||
} else if (val == id2('P','R')) { // PRINT: call ms_builtin_print
|
} else if (val == PRIM_PRINT) {
|
||||||
emit8(0x51); // push rcx
|
emit8(0x51); emit8(0x52);
|
||||||
emit8(0x52); // push rdx
|
emit8(0x48); emit8(0x83); emit8(0xEC); emit8(0x20);
|
||||||
emit8(0x48); emit8(0x83); emit8(0xEC); emit8(0x20); // sub rsp, 32
|
emit8(0x48); emit8(0x89); emit8(0xC1);
|
||||||
emit8(0x48); emit8(0x89); emit8(0xC1); // mov rcx, rax
|
emit8(0x49); emit8(0xB8);
|
||||||
emit8(0x49); emit8(0xB8); // mov r8, imm64
|
|
||||||
U8 addr = u8_(& ms_builtin_print);
|
U8 addr = u8_(& ms_builtin_print);
|
||||||
emit32(u4_(addr & 0xFFFFFFFF));
|
emit32(u4_(addr & 0xFFFFFFFF));
|
||||||
emit32(u4_(addr >> 32));
|
emit32(u4_(addr >> 32));
|
||||||
emit8(0x41); emit8(0xFF); emit8(0xD0); // call r8
|
emit8(0x41); emit8(0xFF); emit8(0xD0);
|
||||||
emit8(0x48); emit8(0x83); emit8(0xC4); emit8(0x20); // add rsp, 32
|
emit8(0x48); emit8(0x83); emit8(0xC4); emit8(0x20);
|
||||||
emit8(0x5A); // pop rdx
|
emit8(0x5A); emit8(0x59);
|
||||||
emit8(0x59); // pop rcx
|
pad32();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Dictionary Resolver (Call User Word)
|
|
||||||
for (U8 entry = 0; entry < dict_count; entry++) {
|
if (val > 0) {
|
||||||
if (dict[entry].val == val) {
|
U4 target = tape_to_code_offset[val];
|
||||||
U4 target = dict[entry].offset;
|
pad32();
|
||||||
U4 current = code_arena.used;
|
S4 rel32 = s4_(target) - s4_(code_arena.used + 5);
|
||||||
S4 rel32 = s4_(target) - s4_(current + 5);
|
emit8(0xE8);
|
||||||
emit8(0xE8); // CALL rel32
|
emit32(u4_(rel32));
|
||||||
emit32(u4_(rel32));
|
pad32();
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IA_ void compile_and_run_tape(void)
|
IA_ void compile_and_run_tape(void)
|
||||||
{
|
{
|
||||||
farena_reset(& code_arena);
|
farena_reset(& code_arena);
|
||||||
dict_count = 0;
|
|
||||||
log_count = 0;
|
log_count = 0;
|
||||||
|
|
||||||
// Prologue: Load VM state from globals[14] and [15]
|
emit8(0x48); emit8(0x8B); emit8(0x41); emit8(0x70);
|
||||||
emit8(0x48); emit8(0x8B); emit8(0x41); emit8(0x70); // mov rax, [rcx+112]
|
emit8(0x48); emit8(0x8B); emit8(0x51); emit8(0x78);
|
||||||
emit8(0x48); emit8(0x8B); emit8(0x51); emit8(0x78); // mov rdx, [rcx+120]
|
|
||||||
|
|
||||||
U4*r tape_ptr = u4_r(tape_arena.start);
|
U4*r tape_ptr = u4_r(tape_arena.start);
|
||||||
B4 in_def = false;
|
B4 in_def = false;
|
||||||
@@ -195,35 +240,36 @@ IA_ void compile_and_run_tape(void)
|
|||||||
if (tag == STag_Define)
|
if (tag == STag_Define)
|
||||||
{
|
{
|
||||||
if (in_def == false) {
|
if (in_def == false) {
|
||||||
emit8(0xE9); // JMP rel32 (Skip over definition body)
|
pad32();
|
||||||
|
emit8(0xE9);
|
||||||
def_jmp_offset = code_arena.used;
|
def_jmp_offset = code_arena.used;
|
||||||
emit32(0);
|
emit32(0);
|
||||||
|
pad32();
|
||||||
in_def = true;
|
in_def = true;
|
||||||
|
} else {
|
||||||
|
emit8(0xC3);
|
||||||
|
pad32();
|
||||||
}
|
}
|
||||||
if (dict_count < 256) {
|
|
||||||
dict[dict_count].val = val;
|
tape_to_code_offset[i] = code_arena.used;
|
||||||
dict[dict_count].offset = code_arena.used;
|
|
||||||
dict_count++;
|
emit8(0x48); emit8(0x87); emit8(0xC2);
|
||||||
}
|
pad32();
|
||||||
}
|
}
|
||||||
else if (tag == STag_Call)
|
else if (tag == STag_Call)
|
||||||
{
|
{
|
||||||
compile_action(val);
|
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) {
|
else if (tag == STag_Data) {
|
||||||
emit8(0x48); emit8(0x89); emit8(0xC2); // mov rdx, rax
|
emit8(0x48); emit8(0x89); emit8(0xC2);
|
||||||
emit8(0x48); emit8(0xC7); emit8(0xC0); emit32(val); // mov rax, imm32
|
emit8(0x48); emit8(0xC7); emit8(0xC0); emit32(val);
|
||||||
|
pad32();
|
||||||
}
|
}
|
||||||
else if (tag == STag_Imm)
|
else if (tag == STag_Imm)
|
||||||
{
|
{
|
||||||
if (in_def) {
|
if (in_def) {
|
||||||
// If we execute something, we jump out of def block first
|
emit8(0xC3);
|
||||||
|
pad32();
|
||||||
U4 current = code_arena.used;
|
U4 current = code_arena.used;
|
||||||
u4_r(code_arena.start + def_jmp_offset)[0] = current - (def_jmp_offset + 4);
|
u4_r(code_arena.start + def_jmp_offset)[0] = current - (def_jmp_offset + 4);
|
||||||
in_def = false;
|
in_def = false;
|
||||||
@@ -233,27 +279,24 @@ IA_ void compile_and_run_tape(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (in_def) {
|
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 current = code_arena.used;
|
||||||
u4_r(code_arena.start + def_jmp_offset)[0] = current - (def_jmp_offset + 4);
|
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);
|
||||||
emit8(0x48); emit8(0x89); emit8(0x41); emit8(0x70); // mov [rcx+112], rax
|
emit8(0x48); emit8(0x89); emit8(0x51); emit8(0x78);
|
||||||
emit8(0x48); emit8(0x89); emit8(0x51); emit8(0x78); // mov [rcx+120], rdx
|
emit8(0xC3);
|
||||||
emit8(0xC3); // ret
|
|
||||||
|
|
||||||
// Cast code arena to function pointer and CALL it!
|
|
||||||
typedef void JIT_Func(U8* globals_ptr);
|
typedef void JIT_Func(U8* globals_ptr);
|
||||||
JIT_Func* func = (JIT_Func*)code_arena.start;
|
JIT_Func* func = (JIT_Func*)code_arena.start;
|
||||||
func(vm_globals);
|
func(vm_globals);
|
||||||
|
|
||||||
// Read state for UI
|
|
||||||
vm_rax = vm_globals[14];
|
vm_rax = vm_globals[14];
|
||||||
vm_rdx = vm_globals[15];
|
vm_rdx = vm_globals[15];
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Window Procedure ---
|
|
||||||
S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
|
S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
|
||||||
{
|
{
|
||||||
U8 tape_count = tape_arena.used / sizeof(U4);
|
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);
|
U4 val = unpack_val(t);
|
||||||
U1 c = u1_(wparam);
|
U1 c = u1_(wparam);
|
||||||
|
|
||||||
// Skip control characters and the 'E' that triggered the mode
|
|
||||||
bool should_skip = c < 32 || (c == 'e' && mode_switch_now);
|
bool should_skip = c < 32 || (c == 'e' && mode_switch_now);
|
||||||
if (should_skip) { mode_switch_now = false; return 0; }
|
if (should_skip) { mode_switch_now = false; return 0; }
|
||||||
|
|
||||||
if (tag == STag_Data) {
|
if (tag == STag_Data) {
|
||||||
// Hex input
|
|
||||||
U4 digit = 16;
|
U4 digit = 16;
|
||||||
if (c >= '0' && c <= '9') digit = c - '0';
|
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;
|
||||||
@@ -290,28 +331,22 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
|
|||||||
if (len < 8) {
|
if (len < 8) {
|
||||||
anno_str[len] = (char)c;
|
anno_str[len] = (char)c;
|
||||||
for (int i = len + 1; i < 8; i++) anno_str[i] = '\0';
|
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));
|
vm_rax = 0; vm_rdx = 0; mem_zero(u8_(vm_globals), sizeof(vm_globals));
|
||||||
|
relink_tape();
|
||||||
compile_and_run_tape();
|
compile_and_run_tape();
|
||||||
ms_invalidate_rect(hwnd, nullptr, true);
|
ms_invalidate_rect(hwnd, nullptr, true);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case MS_WM_KEYDOWN: {
|
case MS_WM_KEYDOWN: {
|
||||||
if (wparam == 0x45 && editor_mode == MODE_NAV) { // 'E'
|
if (wparam == 0x45 && editor_mode == MODE_NAV) {
|
||||||
editor_mode = MODE_EDIT;
|
editor_mode = MODE_EDIT;
|
||||||
mode_switch_now = true;
|
mode_switch_now = true;
|
||||||
ms_invalidate_rect(hwnd, nullptr, true);
|
ms_invalidate_rect(hwnd, nullptr, true);
|
||||||
return 0;
|
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;
|
editor_mode = MODE_NAV;
|
||||||
ms_invalidate_rect(hwnd, nullptr, true);
|
ms_invalidate_rect(hwnd, nullptr, true);
|
||||||
return 0;
|
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 ++;
|
while (len < 8 && anno_str[len] != '\0' && anno_str[len] != ' ') len ++;
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
anno_str[len - 1] = '\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));
|
vm_rax = 0; vm_rdx = 0; mem_zero(u8_(vm_globals), sizeof(vm_globals));
|
||||||
|
relink_tape();
|
||||||
compile_and_run_tape();
|
compile_and_run_tape();
|
||||||
ms_invalidate_rect(hwnd, nullptr, true);
|
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 ++;
|
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;
|
U8 next_line_start = cursor_idx;
|
||||||
while (next_line_start < tape_count && unpack_tag(tape_ptr[next_line_start]) != STag_Format) next_line_start ++;
|
while (next_line_start < tape_count && unpack_tag(tape_ptr[next_line_start]) != STag_Format) next_line_start ++;
|
||||||
if (next_line_start < tape_count) {
|
if (next_line_start < tape_count) {
|
||||||
next_line_start ++; // Skip the newline
|
next_line_start ++;
|
||||||
U8 next_line_end = 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 ++;
|
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;
|
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_F5) { run_full = !run_full; }
|
||||||
|
|
||||||
if (wparam == MS_VK_TAB) {
|
if (wparam == MS_VK_TAB) {
|
||||||
// Cycle Color Tag
|
|
||||||
U4 t = tape_ptr[cursor_idx];
|
U4 t = tape_ptr[cursor_idx];
|
||||||
U4 tag = (unpack_tag(t) + 1) % STag_Count;
|
U4 tag = (unpack_tag(t) + 1) % STag_Count;
|
||||||
tape_ptr[cursor_idx] = pack_token(tag, unpack_val(t));
|
tape_ptr[cursor_idx] = pack_token(tag, unpack_val(t));
|
||||||
}
|
}
|
||||||
else if (wparam == MS_VK_BACK)
|
else if (wparam == MS_VK_BACK)
|
||||||
{
|
{
|
||||||
// Delete Token
|
|
||||||
// Shift: delete AT cursor | Regular: delete TO THE LEFT
|
|
||||||
U8 delete_idx = cursor_idx;
|
U8 delete_idx = cursor_idx;
|
||||||
B4 is_shift = (ms_get_async_key_state(MS_VK_SHIFT) & 0x8000) != 0;
|
B4 is_shift = (ms_get_async_key_state(MS_VK_SHIFT) & 0x8000) != 0;
|
||||||
if (is_shift == false) {
|
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) {
|
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;
|
B4 is_shift = (ms_get_async_key_state(MS_VK_SHIFT) & 0x8000) != 0;
|
||||||
U8 insert_idx = cursor_idx;
|
U8 insert_idx = cursor_idx;
|
||||||
if (is_shift) insert_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);
|
tape_ptr[insert_idx] = pack_token(STag_Format, 0xA);
|
||||||
anno_ptr[insert_idx] = 0;
|
anno_ptr[insert_idx] = 0;
|
||||||
} else {
|
} else {
|
||||||
tape_ptr[insert_idx] = pack_token(STag_Comment, id2(' ',' '));
|
tape_ptr[insert_idx] = pack_token(STag_Comment, 0);
|
||||||
anno_ptr[insert_idx] = 0;
|
anno_ptr[insert_idx] = 0;
|
||||||
}
|
}
|
||||||
if (is_shift) cursor_idx ++;
|
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;
|
vm_rax = 0; vm_rdx = 0;
|
||||||
mem_zero(u8_(vm_globals), sizeof(vm_globals));
|
mem_zero(u8_(vm_globals), sizeof(vm_globals));
|
||||||
|
|
||||||
|
relink_tape();
|
||||||
compile_and_run_tape();
|
compile_and_run_tape();
|
||||||
|
|
||||||
ms_invalidate_rect(hwnd, nullptr, true);
|
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* 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);
|
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);
|
void* hBgBrush = ms_create_solid_brush(0x00222222);
|
||||||
ms_select_object(hdc, hBgBrush);
|
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);
|
U4*r tape_ptr = u4_r(tape_arena.start);
|
||||||
U8*r anno_ptr = u8_r(anno_arena.start);
|
U8*r anno_ptr = u8_r(anno_arena.start);
|
||||||
|
|
||||||
// Render Tokens
|
|
||||||
for (U8 i = 0; i < tape_count; i++)
|
for (U8 i = 0; i < tape_count; i++)
|
||||||
{
|
{
|
||||||
if (x >= start_x + (TOKENS_PER_ROW * spacing_x)) {
|
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);
|
ms_set_text_color(hdc, color);
|
||||||
if (editor_mode == MODE_EDIT && i == cursor_idx) {
|
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);
|
ms_set_text_color(hdc, 0x001E1E1E);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -503,19 +529,11 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Extract annotation string
|
|
||||||
char* a_str = (char*) & anno;
|
char* a_str = (char*) & anno;
|
||||||
if (a_str[0] == '\0') {
|
for(int c=0; c<8; c++) {
|
||||||
// Fallback to 2-character ID
|
val_str[c] = a_str[c] ? a_str[c] : ' ';
|
||||||
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';
|
|
||||||
}
|
}
|
||||||
|
val_str[8] = '\0';
|
||||||
}
|
}
|
||||||
char out_buf[12];
|
char out_buf[12];
|
||||||
out_buf[0] = prefix[0];
|
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);
|
void* hHudBrush = ms_create_solid_brush(0x00141E23);
|
||||||
ms_select_object(hdc, hHudBrush);
|
ms_select_object(hdc, hHudBrush);
|
||||||
ms_rectangle(hdc, -1, 500, 3000, 3000);
|
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_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);
|
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);
|
ms_set_text_color(hdc, 0x00FFFFFF);
|
||||||
char jit_str[64] = "Mode: Incremental | JIT Size: 0x000 bytes";
|
char jit_str[64] = "Mode: Incremental | JIT Size: 0x000 bytes";
|
||||||
if (run_full) mem_copy(u8_(jit_str + 6), u8_("Full "), 11);
|
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";
|
char state_str[64] = "RAX: 00000000 | RDX: 00000000";
|
||||||
u64_to_hex(vm_rax, state_str + 5, 8);
|
u64_to_hex(vm_rax, state_str + 5, 8);
|
||||||
u64_to_hex(vm_rdx, state_str + 21, 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);
|
ms_text_out_a(hdc, 40, 550, state_str, 29);
|
||||||
|
|
||||||
// HUD: Display Current Token Meaning
|
|
||||||
if (tape_count > 0 && cursor_idx < tape_count) {
|
if (tape_count > 0 && cursor_idx < tape_count) {
|
||||||
U4 cur_tag = unpack_tag(tape_ptr[cursor_idx]);
|
U4 cur_tag = unpack_tag(tape_ptr[cursor_idx]);
|
||||||
const char* tag_name = tag_names [cur_tag];
|
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";
|
char glob_str[32] = "[0]: 00000000";
|
||||||
glob_str[1] = '0' + i;
|
glob_str[1] = '0' + i;
|
||||||
u64_to_hex(vm_globals[i], glob_str + 5, 8);
|
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);
|
ms_text_out_a(hdc, 400, 550 + (i * 25), glob_str, 13);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print Log
|
|
||||||
ms_set_text_color(hdc, 0x00C8C8C8);
|
ms_set_text_color(hdc, 0x00C8C8C8);
|
||||||
ms_text_out_a(hdc, 750, 520, "Print Log:", 10);
|
ms_text_out_a(hdc, 750, 520, "Print Log:", 10);
|
||||||
for (int i = 0; i<log_count && i < 4; i ++) {
|
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) {
|
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 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 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);
|
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(& anno_arena, anno_mem);
|
||||||
farena_init(& code_arena, code_mem);
|
farena_init(& code_arena, code_mem);
|
||||||
|
|
||||||
// Bootstrap Robust Sample: Factorial State Machine
|
scatter(pack_token(STag_Comment, 0), "INIT ");
|
||||||
scatter(pack_token(STag_Comment, id2('I','N')), "INIT "); // .IN
|
scatter(pack_token(STag_Data, 5), 0);
|
||||||
scatter(pack_token(STag_Data, 5), 0); // $5
|
scatter(pack_token(STag_Data, 0), 0);
|
||||||
scatter(pack_token(STag_Data, 0), 0); // $0 (Addr)
|
scatter(pack_token(STag_Imm, 0), "STORE ");
|
||||||
scatter(pack_token(STag_Imm, id2('!',' ')), "STORE "); // ^!
|
|
||||||
|
|
||||||
scatter(pack_token(STag_Data, 1), 0); // $1
|
scatter(pack_token(STag_Data, 1), 0);
|
||||||
scatter(pack_token(STag_Data, 1), 0); // $1 (Addr)
|
scatter(pack_token(STag_Data, 1), 0);
|
||||||
scatter(pack_token(STag_Imm, id2('!',' ')), "STORE "); // ^!
|
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, 0), "F_STEP ");
|
||||||
scatter(pack_token(STag_Define, id2('F','S')), "F_STEP ");
|
scatter(pack_token(STag_Data, 0), 0);
|
||||||
scatter(pack_token(STag_Data, 0), 0);
|
scatter(pack_token(STag_Call, 0), "FETCH ");
|
||||||
scatter(pack_token(STag_Call, id2('@',' ')), "FETCH ");
|
scatter(pack_token(STag_Call, 0), "RET_IF_Z");
|
||||||
scatter(pack_token(STag_Call, id2('R','0')), "RET_IF_Z");
|
scatter(pack_token(STag_Format, 0xA), 0);
|
||||||
scatter(pack_token(STag_Format, 0xA), 0); // Newline
|
|
||||||
|
|
||||||
scatter(pack_token(STag_Data, 1), 0);
|
scatter(pack_token(STag_Data, 1), 0);
|
||||||
scatter(pack_token(STag_Call, id2('@',' ')), "FETCH ");
|
scatter(pack_token(STag_Call, 0), "FETCH ");
|
||||||
scatter(pack_token(STag_Data, 0), 0);
|
scatter(pack_token(STag_Data, 0), 0);
|
||||||
scatter(pack_token(STag_Call, id2('@',' ')), "FETCH ");
|
scatter(pack_token(STag_Call, 0), "FETCH ");
|
||||||
scatter(pack_token(STag_Call, id2('M','*')), "MULT ");
|
scatter(pack_token(STag_Call, 0), "MULT ");
|
||||||
scatter(pack_token(STag_Data, 1), 0);
|
scatter(pack_token(STag_Data, 1), 0);
|
||||||
scatter(pack_token(STag_Call, id2('!',' ')), "STORE ");
|
scatter(pack_token(STag_Call, 0), "STORE ");
|
||||||
scatter(pack_token(STag_Format, 0xA), 0); // Newline
|
scatter(pack_token(STag_Format, 0xA), 0);
|
||||||
|
|
||||||
scatter(pack_token(STag_Data, 0), 0);
|
scatter(pack_token(STag_Data, 0), 0);
|
||||||
scatter(pack_token(STag_Call, id2('@',' ')), "FETCH ");
|
scatter(pack_token(STag_Call, 0), "FETCH ");
|
||||||
scatter(pack_token(STag_Call, id2('-','1')), "DEC ");
|
scatter(pack_token(STag_Call, 0), "DEC ");
|
||||||
scatter(pack_token(STag_Data, 0), 0);
|
scatter(pack_token(STag_Data, 0), 0);
|
||||||
scatter(pack_token(STag_Call, id2('!',' ')), "STORE ");
|
scatter(pack_token(STag_Call, 0), "STORE ");
|
||||||
|
|
||||||
scatter(pack_token(STag_Data, 1), 0);
|
scatter(pack_token(STag_Data, 1), 0);
|
||||||
scatter(pack_token(STag_Call, id2('@',' ')), "FETCH ");
|
scatter(pack_token(STag_Call, 0), "FETCH ");
|
||||||
scatter(pack_token(STag_Call, id2('P','R')), "PRINT "); // Print Accumulator!
|
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
|
scatter(pack_token(STag_Imm, 0), "F_STEP ");
|
||||||
|
scatter(pack_token(STag_Imm, 0), "F_STEP ");
|
||||||
// Call it
|
scatter(pack_token(STag_Imm, 0), "F_STEP ");
|
||||||
scatter(pack_token(STag_Imm, id2('F','S')), "F_STEP "); // ^FS
|
scatter(pack_token(STag_Imm, 0), "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, id2('F','S')), "F_STEP ");
|
|
||||||
scatter(pack_token(STag_Imm, id2('F','S')), "F_STEP ");
|
relink_tape();
|
||||||
scatter(pack_token(STag_Imm, id2('F','S')), "F_STEP ");
|
|
||||||
|
|
||||||
MS_WNDCLASSA wc;
|
MS_WNDCLASSA wc;
|
||||||
mem_fill(u8_(& wc), 0, sizeof(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); }
|
while (ms_get_message_a(& msg, nullptr, 0, 0)) { ms_translate_message(& msg); ms_dispatch_message_a(& msg); }
|
||||||
ms_exit_process(0);
|
ms_exit_process(0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -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)
|
## 3. Onat's VAMP/KYRA Architecture (The Runtime/Codegen)
|
||||||
* **2-Item Register Stack:** Uses `RAX` and `RDX` as a tiny, hardware-resident stack.
|
* **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.
|
* **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.
|
* **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.
|
* **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
|
## 4. Implementation Components
|
||||||
* **Emitter:** **Zydis Encoder API**. Zero-allocation, sub-5ms instruction generation.
|
* **Emitter:** **Zydis Encoder API**. Zero-allocation, sub-5ms instruction generation.
|
||||||
|
|||||||
Reference in New Issue
Block a user