From 5d2aa1ad222d62ee13803a12f9514739753d5d55 Mon Sep 17 00:00:00 2001 From: zongor Date: Tue, 4 Nov 2025 17:09:55 -0800 Subject: [PATCH] wip compiler stuff --- Makefile | 9 +- README.org | 41 +++---- bench/fib.lisp | 2 +- bench/fib.lua | 2 +- bench/fib.pl | 2 +- bench/fib.py | 2 +- bench/fib.zl | 2 +- src/arch/emscripten/devices.c | 13 ++- src/arch/emscripten/devices.h | 6 +- src/arch/emscripten/main.c | 6 +- src/arch/linux/main.c | 171 ++++++++++++++--------------- src/tools/compiler.c | 200 ++++++++++++++++++++++++++++++++++ src/tools/compiler.h | 38 +++++++ src/vm/common.h | 1 + src/vm/fixed.c | 181 ++++++++++++++++++++++++++++++ src/vm/fixed.h | 53 +++++++++ src/vm/vm.c | 80 ++++++-------- test/add.rom | Bin 139 -> 143 bytes test/fib.rom | Bin 183 -> 187 bytes test/hello.rom | Bin 131 -> 135 bytes test/loop.rom | Bin 254 -> 258 bytes test/malloc.rom | Bin 163 -> 167 bytes test/paint-bw.rom | Bin 594 -> 574 bytes test/paint.rom | Bin 1394 -> 1266 bytes test/simple.rom | Bin 136 -> 140 bytes test/window.rom | Bin 326 -> 326 bytes 26 files changed, 633 insertions(+), 176 deletions(-) create mode 100644 src/tools/compiler.c create mode 100644 src/tools/compiler.h create mode 100644 src/vm/fixed.c create mode 100644 src/vm/fixed.h diff --git a/Makefile b/Makefile index 716919e..2327006 100644 --- a/Makefile +++ b/Makefile @@ -80,6 +80,7 @@ endif VM_SOURCES := \ $(SRC_DIR)/vm/vm.c \ $(SRC_DIR)/vm/device.c \ + $(SRC_DIR)/vm/fixed.c \ $(SRC_DIR)/vm/libc.c ifeq ($(BUILD_MODE), release) @@ -87,13 +88,15 @@ ifeq ($(BUILD_MODE), release) $(ARCH_DIR)/devices.c\ $(SRC_DIR)/tools/parser.c \ $(SRC_DIR)/tools/lexer.c \ - $(SRC_DIR)/tools/assembler.c + $(SRC_DIR)/tools/assembler.c\ + $(SRC_DIR)/tools/compiler.c else PLATFORM_SOURCE := $(ARCH_DIR)/main.c \ $(ARCH_DIR)/devices.c \ $(SRC_DIR)/tools/parser.c \ $(SRC_DIR)/tools/lexer.c \ - $(SRC_DIR)/tools/assembler.c + $(SRC_DIR)/tools/assembler.c\ + $(SRC_DIR)/tools/compiler.c endif # --- OBJECT FILES --- @@ -184,4 +187,4 @@ help: @echo "" @echo "Output:" @echo " Linux: build/linux/undar-linux-" - @echo " Web: build/emscripten/undar.html (+ .js, .wasm)" \ No newline at end of file + @echo " Web: build/emscripten/undar.html (+ .js, .wasm)" diff --git a/README.org b/README.org index c6495c4..0df876a 100644 --- a/README.org +++ b/README.org @@ -58,23 +58,16 @@ The Undâr compiler will be written in Sċieppan, as well as core VM tests. #+BEGIN_SRC lisp ((code (label main - (load-immediate $1 &hello-str) ; load hello string ptr - (call &pln ($1) nil) - (halt)) ; done - (label pln - (load-immediate $1 &terminal-namespace) ; get terminal device - (load-immediate $11 0) - (syscall OPEN $1 $1 $11) - (load-immediate $3 &new-line) - (string-length $2 $0) - (syscall WRITE $1 $0 $2) - (string-length $4 $3) - (syscall WRITE $1 $3 $4) - (return nil))) + (ldi $0 &terminal-namespace) ; get terminal device + (ldi $1 0) + (syscall OPEN $0 $0 $1) + (ldi $1 &hello-str) ; load hello string ptr + (strlen $2 $1) + (syscall WRITE $0 $1 $2) + (halt 0))) (data (label terminal-namespace "/dev/term/0") - (label new-line "\n") - (label hello-str "nuqneH 'u'?"))) + (label hello-str "nuqneH 'u'?\n"))) #+END_SRC #+BEGIN_SRC sh @@ -92,24 +85,24 @@ heap allocations using the internal malloc opcode push pointers within this fram #+BEGIN_SRC lisp ((code (label main - (load-immediate $0 &terminal-namespace) ; get terminal device - (load-immediate $11 0) + (ldi $0 &terminal-namespace) ; get terminal device + (ldi $11 0) (syscall OPEN $0 $0 $11) - (load-immediate $1 &help) ; print help message - (call &pln ($0 $1) nil) + (ldi $1 &help) ; print help message + (fcall &pln ($0 $1) nil) - (load-immediate $1 32) ; read in a string of max 32 char length + (ldi $1 32) ; read in a string of max 32 char length (malloc $4 $1) ; allocate memory for the string (syscall READ $0 $4 $1) ; read the string - (call &pln ($0 $4) nil) ; print the string + (fcall &pln ($0 $4) nil) ; print the string (halt)) (label pln - (load-immediate $3 &new-line) - (string-length $2 $1) + (ldi $3 &new-line) + (strlen $2 $1) (syscall WRITE $0 $1 $2) - (string-length $4 $3) + (strlen $4 $3) (syscall WRITE $0 $3 $4) (return nil))) (data diff --git a/bench/fib.lisp b/bench/fib.lisp index 19174ae..f73186a 100644 --- a/bench/fib.lisp +++ b/bench/fib.lisp @@ -3,4 +3,4 @@ (return n)) (return (+ (fib (- n 2)) (fib (- n 1))))) -(print (fib 35)) \ No newline at end of file +(print (fib 36)) \ No newline at end of file diff --git a/bench/fib.lua b/bench/fib.lua index d7ce19a..be357e9 100644 --- a/bench/fib.lua +++ b/bench/fib.lua @@ -3,6 +3,6 @@ function fib(n) return fib(n-1) + fib(n-2) end -local result = fib(35) +local result = fib(36) print(result) diff --git a/bench/fib.pl b/bench/fib.pl index e246993..776351e 100644 --- a/bench/fib.pl +++ b/bench/fib.pl @@ -7,6 +7,6 @@ sub fib { return fib($n-1) + fib($n-2); } -my $result = fib(35); +my $result = fib(36); print "$result\n"; diff --git a/bench/fib.py b/bench/fib.py index c4ea615..4ab00e6 100644 --- a/bench/fib.py +++ b/bench/fib.py @@ -3,5 +3,5 @@ def fib(n): return n return fib(n-1) + fib(n-2) -result = fib(35) +result = fib(36) print(result) diff --git a/bench/fib.zl b/bench/fib.zl index 1b95c65..dd93fc8 100644 --- a/bench/fib.zl +++ b/bench/fib.zl @@ -3,5 +3,5 @@ fn fib(n) { return fib(n - 2) + fib(n - 1); } -let result = fib(35); +let result = fib(36); print result; diff --git a/src/arch/emscripten/devices.c b/src/arch/emscripten/devices.c index 2d58703..4d667b1 100644 --- a/src/arch/emscripten/devices.c +++ b/src/arch/emscripten/devices.c @@ -1,8 +1,7 @@ #include "devices.h" #include #include -#include -#include +#include i32 console_open(void *data, u32 mode, u32 handle, u8 *buffer, u32 size) { USED(mode); @@ -141,10 +140,14 @@ i32 mouse_open(void *data, u32 mode, u32 handle, u8 *buffer, u32 size) { } i32 mouse_read(void *data, u8 *buffer, u32 size) { - MouseDeviceData *mouse_data = (MouseDeviceData *)data; + USED(data); + USED(buffer); + USED(size); + return -1; +} - if (size < 12) - return -1; +i32 mouse_refresh(void *data, u8 *buffer) { + MouseDeviceData *mouse_data = (MouseDeviceData *)data; u8 *info = (u8 *)buffer; memcpy(&info[4], &mouse_data->x, sizeof(u32)); diff --git a/src/arch/emscripten/devices.h b/src/arch/emscripten/devices.h index b252c03..946ed28 100644 --- a/src/arch/emscripten/devices.h +++ b/src/arch/emscripten/devices.h @@ -26,16 +26,13 @@ typedef struct mouse_device_data_s { u8 btn2; u8 btn3; u8 btn4; - u32 size; } MouseDeviceData; /* Keyboard device data */ typedef struct keyboard_device_data_s { u32 handle; - const u8 *keys; i32 key_count; - u32 pos; - u32 size; + const u8 *keys; } KeyboardDeviceData; /* Console device data */ @@ -52,6 +49,7 @@ i32 screen_ioctl(void *data, u32 cmd, const u8 *buffer); i32 mouse_open(void *data, u32 mode, u32 handle, u8 *buffer, u32 size); i32 mouse_read(void *data, u8 *buffer, u32 size); +i32 mouse_refresh(void *data, u8 *buffer); i32 mouse_write(void *data, const u8 *buffer, u32 size); i32 mouse_close(void *data); diff --git a/src/arch/emscripten/main.c b/src/arch/emscripten/main.c index 8d454c9..1a98d0e 100644 --- a/src/arch/emscripten/main.c +++ b/src/arch/emscripten/main.c @@ -18,7 +18,8 @@ static DeviceOps mouse_ops = {.open = mouse_open, .read = mouse_read, .write = mouse_write, .close = mouse_close, - .ioctl = nil}; + .ioctl = nil, + .refresh = mouse_refresh}; static DeviceOps console_device_ops = { .open = console_open, @@ -177,13 +178,12 @@ int main(int argc, char **argv) { mouse_data.btn2 = 0; mouse_data.btn3 = 0; mouse_data.btn4 = 0; - mouse_data.size = 16; // Register devices vm_register_device(&vm, "/dev/screen/0", "screen", &screen_data, &screen_ops, 16 + screen_data.buffer_size); vm_register_device(&vm, "/dev/mouse/0", "mouse", &mouse_data, &mouse_ops, - mouse_data.size); + 16); vm_register_device(&vm, "/dev/term/0", "terminal", &console_data, &console_device_ops, 4); diff --git a/src/arch/linux/main.c b/src/arch/linux/main.c index cad07d3..3626374 100644 --- a/src/arch/linux/main.c +++ b/src/arch/linux/main.c @@ -1,11 +1,12 @@ #include "../../tools/assembler.h" -#include "../../tools/lexer.h" +#include "../../tools/compiler.h" #include "../../tools/parser.h" #include "../../vm/vm.h" #include "devices.h" #include #include +#include #include #include @@ -280,130 +281,130 @@ const char *opcode_to_string(Opcode op) { static const char *names[] = { [OP_HALT] = "halt", [OP_JMP] = "jump", - [OP_JMPF] = "jump-if-flag", - [OP_CALL] = "call", - [OP_RETURN] = "return", + [OP_JMPF] = "jmpf", + [OP_FCALL] = "fcall", + [OP_FRETURN] = "return", /* Immediate loads (only 32-bit variant needed) */ - [OP_LOAD_IMM] = "load-immediate", + [OP_LOAD_IMM] = "ldi", /* Register-indirect loads */ - [OP_LOAD_IND_8] = "load-indirect-8", - [OP_LOAD_IND_16] = "load-indirect-16", - [OP_LOAD_IND_32] = "load-indirect-32", + [OP_LOAD_IND_8] = "ld8", + [OP_LOAD_IND_16] = "ld16", + [OP_LOAD_IND_32] = "ld32", /* Absolute address loads */ - [OP_LOAD_ABS_8] = "load-absolute-8", - [OP_LOAD_ABS_16] = "load-absolute-16", - [OP_LOAD_ABS_32] = "load-absolute-32", + [OP_LOAD_ABS_8] = "lda8", + [OP_LOAD_ABS_16] = "lda16", + [OP_LOAD_ABS_32] = "lda32", /* Base+offset loads */ - [OP_LOAD_OFF_8] = "load-offset-8", - [OP_LOAD_OFF_16] = "load-offset-16", - [OP_LOAD_OFF_32] = "load-offset-32", + [OP_LOAD_OFF_8] = "ldo8", + [OP_LOAD_OFF_16] = "ldo16", + [OP_LOAD_OFF_32] = "ldo32", /* Absolute address stores */ - [OP_STORE_ABS_8] = "store-absolute-8", - [OP_STORE_ABS_16] = "store-absolute-16", - [OP_STORE_ABS_32] = "store-absolute-32", + [OP_STORE_ABS_8] = "sta8", + [OP_STORE_ABS_16] = "sta16", + [OP_STORE_ABS_32] = "sta32", /* Register-indirect stores */ - [OP_STORE_IND_8] = "store-indirect-8", - [OP_STORE_IND_16] = "store-indirect-16", - [OP_STORE_IND_32] = "store-indirect-32", + [OP_STORE_IND_8] = "sti8", + [OP_STORE_IND_16] = "sti16", + [OP_STORE_IND_32] = "sti32", /* Base+offset stores */ - [OP_STORE_OFF_8] = "store-offset-8", - [OP_STORE_OFF_16] = "store-offset-16", - [OP_STORE_OFF_32] = "store-offset-32", + [OP_STORE_OFF_8] = "sto8", + [OP_STORE_OFF_16] = "sto16", + [OP_STORE_OFF_32] = "sto32", /* Memory operations */ [OP_MALLOC] = "malloc", - [OP_MEMSET_8] = "memset-8", - [OP_MEMSET_16] = "memset-16", - [OP_MEMSET_32] = "memset-32", + [OP_MEMSET_8] = "set8", + [OP_MEMSET_16] = "set16", + [OP_MEMSET_32] = "set32", /* Register operations */ - [OP_REG_MOV] = "register-move", + [OP_REG_MOV] = "mov", [OP_SYSCALL] = "syscall", /* Bit operations */ - [OP_BIT_SHIFT_LEFT] = "bit-shift-left", - [OP_BIT_SHIFT_RIGHT] = "bit-shift-right", - [OP_BIT_SHIFT_R_EXT] = "bit-shift-r-ext", - [OP_BAND] = "bit-and", - [OP_BOR] = "bit-or", - [OP_BXOR] = "bit-xor", + [OP_BIT_SHIFT_LEFT] = "sll", + [OP_BIT_SHIFT_RIGHT] = "srl", + [OP_BIT_SHIFT_R_EXT] = "sre", + [OP_BAND] = "and", + [OP_BOR] = "or", + [OP_BXOR] = "xor", /* Integer arithmetic */ - [OP_ADD_INT] = "add-int", - [OP_SUB_INT] = "sub-int", - [OP_MUL_INT] = "mul-int", - [OP_DIV_INT] = "div-int", - [OP_ABS_INT] = "abs-int", // ← NEW - [OP_NEG_INT] = "neg-int", // ← NEW + [OP_ADD_INT] = "addi", + [OP_SUB_INT] = "subi", + [OP_MUL_INT] = "muli", + [OP_DIV_INT] = "divi", + [OP_ABS_INT] = "absi", // ← NEW + [OP_NEG_INT] = "negi", // ← NEW /* Natural number arithmetic */ - [OP_ADD_NAT] = "add-nat", - [OP_SUB_NAT] = "sub-nat", - [OP_MUL_NAT] = "mul-nat", - [OP_DIV_NAT] = "div-nat", - [OP_ABS_NAT] = "abs-nat", // ← NEW - [OP_NEG_NAT] = "neg-nat", // ← NEW + [OP_ADD_NAT] = "addn", + [OP_SUB_NAT] = "subn", + [OP_MUL_NAT] = "muln", + [OP_DIV_NAT] = "divn", + [OP_ABS_NAT] = "absn", // ← NEW + [OP_NEG_NAT] = "negn", // ← NEW /* Floating point operations */ - [OP_ADD_REAL] = "add-real", - [OP_SUB_REAL] = "sub-real", - [OP_MUL_REAL] = "mul-real", - [OP_DIV_REAL] = "div-real", - [OP_ABS_REAL] = "abs-real", // ← NEW - [OP_NEG_REAL] = "neg-real", // ← NEW + [OP_ADD_REAL] = "addr", + [OP_SUB_REAL] = "subr", + [OP_MUL_REAL] = "mulr", + [OP_DIV_REAL] = "divr", + [OP_ABS_REAL] = "absr", // ← NEW + [OP_NEG_REAL] = "negr", // ← NEW /* Type conversions */ - [OP_INT_TO_REAL] = "int-to-real", - [OP_NAT_TO_REAL] = "nat-to-real", - [OP_REAL_TO_INT] = "real-to-int", - [OP_REAL_TO_NAT] = "real-to-nat", + [OP_INT_TO_REAL] = "itor", + [OP_NAT_TO_REAL] = "ntor", + [OP_REAL_TO_INT] = "rtoi", + [OP_REAL_TO_NAT] = "rton", /* Integer comparisons */ - [OP_JEQ_INT] = "jump-eq-int", - [OP_JNEQ_INT] = "jump-neq-int", - [OP_JGT_INT] = "jump-gt-int", - [OP_JLT_INT] = "jump-lt-int", - [OP_JLE_INT] = "jump-le-int", - [OP_JGE_INT] = "jump-ge-int", + [OP_JEQ_INT] = "jeqi", + [OP_JNEQ_INT] = "jneqi", + [OP_JGT_INT] = "jgti", + [OP_JLT_INT] = "jlti", + [OP_JLE_INT] = "jlei", + [OP_JGE_INT] = "jgei", /* Natural number comparisons */ - [OP_JEQ_NAT] = "jump-eq-nat", - [OP_JNEQ_NAT] = "jump-neq-nat", - [OP_JGT_NAT] = "jump-gt-nat", - [OP_JLT_NAT] = "jump-lt-nat", - [OP_JLE_NAT] = "jump-le-nat", - [OP_JGE_NAT] = "jump-ge-nat", + [OP_JEQ_NAT] = "jeqn", + [OP_JNEQ_NAT] = "jneqn", + [OP_JGT_NAT] = "jgtn", + [OP_JLT_NAT] = "jltn", + [OP_JLE_NAT] = "jlen", + [OP_JGE_NAT] = "jgen", /* Floating point comparisons */ - [OP_JEQ_REAL] = "jump-eq-real", - [OP_JNEQ_REAL] = "jump-neq-real", - [OP_JGE_REAL] = "jump-ge-real", - [OP_JGT_REAL] = "jump-gt-real", - [OP_JLT_REAL] = "jump-lt-real", - [OP_JLE_REAL] = "jump-le-real", + [OP_JEQ_REAL] = "jeqr", + [OP_JNEQ_REAL] = "jneqr", + [OP_JGE_REAL] = "jger", + [OP_JGT_REAL] = "jgtr", + [OP_JLT_REAL] = "jltr", + [OP_JLE_REAL] = "jler", /* String operations */ - [OP_STRLEN] = "string-length", - [OP_STREQ] = "string-eq", - [OP_STRCAT] = "string-concat", - [OP_STR_GET_CHAR] = "string-get-char", - [OP_STR_FIND_CHAR] = "string-find-char", - [OP_STR_SLICE] = "string-slice", + [OP_STRLEN] = "strlen", + [OP_STREQ] = "streq", + [OP_STRCAT] = "strcat", + [OP_STR_GET_CHAR] = "getch", + [OP_STR_FIND_CHAR] = "findch", + [OP_STR_SLICE] = "strcut", /* String conversions */ - [OP_INT_TO_STRING] = "int-to-string", - [OP_NAT_TO_STRING] = "nat-to-string", - [OP_REAL_TO_STRING] = "real-to-string", - [OP_STRING_TO_INT] = "string-to-int", - [OP_STRING_TO_NAT] = "string-to-nat", - [OP_STRING_TO_REAL] = "string-to-real"}; + [OP_INT_TO_STRING] = "itos", + [OP_NAT_TO_STRING] = "ntos", + [OP_REAL_TO_STRING] = "rtos", + [OP_STRING_TO_INT] = "stoi", + [OP_STRING_TO_NAT] = "ston", + [OP_STRING_TO_REAL] = "stor"}; if (op < 0 || op >= (int)(sizeof(names) / sizeof(names[0]))) { return ""; diff --git a/src/tools/compiler.c b/src/tools/compiler.c new file mode 100644 index 0000000..d531caf --- /dev/null +++ b/src/tools/compiler.c @@ -0,0 +1,200 @@ +#include "compiler.h" +#include "lexer.h" +#include +#include + +//typedef struct { +// Token current; +// Token previous; +// bool hadError; +// bool panicMode; +//} Parser; +// +//typedef enum { +// PREC_NONE, +// PREC_ASSIGNMENT, /* = */ +// PREC_OR, /* or */ +// PREC_AND, /* and */ +// PREC_EQUALITY, /* == != */ +// PREC_COMPARISON, /* < > <= >= */ +// PREC_TERM, /* + - */ +// PREC_FACTOR, /* * / */ +// PREC_UNARY, /* not */ +// PREC_CALL, /* . () */ +// PREC_PRIMARY +//} Precedence; +// +//typedef void (*ParseFn)(char *program); +// +//typedef struct { +// ParseFn prefix; +// ParseFn infix; +// Precedence precedence; +//} ParseRule; +// +//typedef struct { +// i8 rp; // Next free register +//} Compiler; +// +//Parser parser; +// +//const char *internalErrorMsg = +// "FLAGRANT COMPILER ERROR\n\nCompiler over.\nBug = Very Yes."; +// +//void errorAt(Token *token, const char *message) { +// if (parser.panicMode) +// return; +// parser.panicMode = true; +// fprintf(stderr, "[line %d] Error", token->line); +// +// if (token->type == TOKEN_EOF) { +// fprintf(stderr, " at end"); +// } else if (token->type == TOKEN_ERROR) { +// } else { +// fprintf(stderr, " at '%.*s'", token->length, token->start); +// } +// +// fprintf(stderr, ": %s\n", message); +// parser.hadError = true; +//} +// +//void error(const char *message) { errorAt(&parser.previous, message); } +// +//void errorAtCurrent(const char *message) { errorAt(&parser.current, message); } +// +//void advance() { +// parser.previous = parser.current; +// +// for (;;) { +// parser.current = nextToken(); +// if (parser.current.type != TOKEN_ERROR) +// break; +// +// errorAtCurrent(parser.current.start); +// } +//} +// +//void consume(TokenType type, const char *message) { +// if (parser.current.type == type) { +// advance(); +// return; +// } +// +// errorAtCurrent(message); +//} +// +//static int allocateRegister(Compiler *c) { +// char buffer[38]; +// if (c->rp > 28) { +// sprintf(buffer, "Out of registers (used %d, max 28)", c->rp); +// error(buffer); +// return -1; +// } +// +// return c->rp++; +//} + +//static void freeRegister(Compiler *c, u8 reg) { +// if (reg == c->rp - 1) { +// c->rp--; +// } +//} + +//void emit_byte(VM *vm, u8 byte) { vm->code[vm->cp++] = byte; } +// +//void emit_u32(VM *vm, u32 value) { +// write_u32(vm, code, vm->cp, value); +// vm->cp += 4; +//} +// +//void emit_opcode(VM *vm, Opcode op) { emit_byte(vm, op); } +// +//static bool check(TokenType type) { return parser.current.type == type; } +// +//static bool match(TokenType type) { +// if (!check(type)) +// return false; +// advance(); +// return true; +//} +// +//static void expression(Compiler *c, VM *vm) { +// USED(c); +// USED(vm); +//} +// +//void number(Compiler *c, VM *vm) { +// emit_opcode(vm, OP_LOAD_IMM); +// int reg = allocateRegister(c); +// if (reg < 0) +// return; +// emit_byte(vm, reg); +// +// switch (parser.previous.type) { +// case TOKEN_INT_LITERAL: { +// char *endptr; +// i32 value = (i32)strtol(parser.previous.start, &endptr, 10); +// emit_u32(vm, value); +// return; +// } +// case TOKEN_UINT_LITERAL: { +// long value = atol(parser.previous.start); +// emit_u32(vm, value); +// return; +// } +// case TOKEN_FLOAT_LITERAL: { +// float value = atof(parser.previous.start); +// fixed_t fvalue = float_to_fixed(value); +// emit_u32(vm, fvalue); +// return; +// } +// default: +// return; // Unreachable. +// } +// +// errorAtCurrent("Invalid number format"); +//} +// +//static void unary(Compiler *c, VM *vm) { +// TokenType operatorType = parser.previous.type; +// +// // Compile the operand. +// expression(c, vm); +// +// // Emit the operator instruction. +// switch (operatorType) { +// default: +// return; // Unreachable. +// } +//} +// +//static void emitHalt(Compiler *c, VM *vm) { +// emit_opcode(vm, OP_HALT); +// advance(); +// number(c, vm); +//} +// +//static void endCompiler(Compiler *c, VM *vm) { emitHalt(c, vm); } +// +//static void grouping(Compiler *c, VM *vm) { +// expression(c, vm); +// consume(TOKEN_RPAREN, "Expect ')' after expression."); +//} + +bool compile(const char *source, VM *vm) { + USED(source); + USED(vm); + //initLexer(source); +// + //parser.hadError = false; + //parser.panicMode = false; +// + //Compiler compiler; + //advance(); + //expression(&compiler, vm); + //consume(TOKEN_EOF, "Expect end of expression."); + //endCompiler(&compiler, vm); +// + //return parser.hadError; + return false; +} diff --git a/src/tools/compiler.h b/src/tools/compiler.h new file mode 100644 index 0000000..c657898 --- /dev/null +++ b/src/tools/compiler.h @@ -0,0 +1,38 @@ +#ifndef UNDAR_COMPILER_H +#define UNDAR_COMPILER_H + +#include "../vm/common.h" +#include "../vm/vm.h" +#include "../vm/fixed.h" +#include "lexer.h" + +#include +#include +#include +#include + +typedef struct field_s { + char* name; // "handle" + TokenType type; // TOKEN_TYPE_NAT + u32 offset; // 4 (for first field in heap object) + u32 size; // 4 (bytes for nat) +} Field; + +typedef struct plex_def_s { + char* name; + u32 field_count; + u32 logical_size; // Data size (e.g., 12 for Vec3) + u32 physical_size; // Total allocation (logical + 4) + Field *fields; // All offsets are PHYSICAL +} PlexDef; + +typedef struct array_def_s { + TokenType type; + u32 length; + u32 logical_size; // length * element_size + u32 physical_size; // logical_size + 4 +} ArrayDef; + +bool compile(const char *source, VM *vm); + +#endif diff --git a/src/vm/common.h b/src/vm/common.h index 4691709..18d0d28 100644 --- a/src/vm/common.h +++ b/src/vm/common.h @@ -10,6 +10,7 @@ typedef uint16_t u16; typedef int16_t i16; typedef uint32_t u32; typedef int32_t i32; +typedef float f32; #define true 1 #define false 0 diff --git a/src/vm/fixed.c b/src/vm/fixed.c new file mode 100644 index 0000000..bbbdbc2 --- /dev/null +++ b/src/vm/fixed.c @@ -0,0 +1,181 @@ +/* fixed.c - Q16.16 Fixed-Point Math Implementation */ + +#include "fixed.h" + +/* Conversion functions */ +fixed_t int_to_fixed(i32 i) { return i << 16; } + +i32 fixed_to_int(fixed_t f) { return f >> 16; } + +fixed_t float_to_fixed(f32 f) { return (fixed_t)(f * 65536.0f); } + +f32 fixed_to_float(fixed_t f) { return (f32)f / 65536.0f; } + +fixed_t fixed_add(fixed_t a, fixed_t b) { return a + b; } + +fixed_t fixed_sub(fixed_t a, fixed_t b) { return a - b; } + +fixed_t fixed_mul(fixed_t a, fixed_t b) { + /* Extract high and low parts */ + i32 a_hi = a >> 16; + u32 a_lo = (u32)a & 0xFFFFU; + i32 b_hi = b >> 16; + u32 b_lo = (u32)b & 0xFFFFU; + + /* Compute partial products */ + i32 p0 = (i32)(a_lo * b_lo) >> 16; /* Low * Low */ + i32 p1 = a_hi * (i32)b_lo; /* High * Low */ + i32 p2 = (i32)a_lo * b_hi; /* Low * High */ + i32 p3 = (a_hi * b_hi) << 16; /* High * High */ + + /* Combine results */ + return p0 + p1 + p2 + p3; +} + +fixed_t fixed_div(fixed_t a, fixed_t b) { + int negative; + u32 ua, ub, quotient, remainder; + int i; + + if (b == 0) + return 0; /* Handle division by zero */ + + /* Determine sign */ + negative = ((a < 0) ^ (b < 0)); + + /* Work with absolute values */ + ua = (a < 0) ? -a : a; + ub = (b < 0) ? -b : b; + + /* Perform division using long division in base 2^16 */ + quotient = 0; + remainder = 0; + + for (i = 0; i < 32; i++) { + remainder <<= 1; + if (ua & 0x80000000U) { + remainder |= 1; + } + ua <<= 1; + + if (remainder >= ub) { + remainder -= ub; + quotient |= 1; + } + + if (i < 31) { + quotient <<= 1; + } + } + + return negative ? -(i32)quotient : (i32)quotient; +} + +int fixed_eq(fixed_t a, fixed_t b) { return a == b; } + +int fixed_ne(fixed_t a, fixed_t b) { return a != b; } + +int fixed_lt(fixed_t a, fixed_t b) { return a < b; } + +int fixed_le(fixed_t a, fixed_t b) { return a <= b; } + +int fixed_gt(fixed_t a, fixed_t b) { return a > b; } + +int fixed_ge(fixed_t a, fixed_t b) { return a >= b; } + +/* Unary operations */ +fixed_t fixed_neg(fixed_t f) { return -f; } + +fixed_t fixed_abs(fixed_t f) { return (f < 0) ? -f : f; } + +/* Square root using Newton-Raphson method */ +fixed_t fixed_sqrt(fixed_t f) { + fixed_t x, prev; + + if (f <= 0) + return 0; + + x = f; + /* Newton-Raphson iteration: x = (x + f/x) / 2 */ + do { + prev = x; + x = fixed_div(fixed_add(x, fixed_div(f, x)), int_to_fixed(2)); + } while ( + fixed_gt(fixed_abs(fixed_sub(x, prev)), 1)); /* Precision to 1/65536 */ + + return x; +} + +/* Sine function using Taylor series */ +fixed_t fixed_sin(fixed_t f) { + fixed_t result, term, f_squared; + int i; + /* Normalize angle to [-π, π] */ + fixed_t pi2 = fixed_mul(FIXED_PI, int_to_fixed(2)); + while (fixed_gt(f, FIXED_PI)) + f = fixed_sub(f, pi2); + while (fixed_lt(f, fixed_neg(FIXED_PI))) + f = fixed_add(f, pi2); + + /* Taylor series: sin(x) = x - x³/3! + x⁵/5! - x⁷/7! + ... */ + result = f; + term = f; + f_squared = fixed_mul(f, f); + + /* Calculate first few terms for reasonable precision */ + for (i = 3; i <= 11; i += 2) { + term = fixed_mul(term, f_squared); + term = fixed_div(term, int_to_fixed(i * (i - 1))); + + if ((i / 2) % 2 == 0) { + result = fixed_add(result, term); + } else { + result = fixed_sub(result, term); + } + } + + return result; +} + +/* Cosine function using Taylor series */ +fixed_t fixed_cos(fixed_t f) { + /* cos(x) = 1 - x²/2! + x⁴/4! - x⁶/6! + ... */ + fixed_t result = FIXED_ONE; + fixed_t term = FIXED_ONE; + fixed_t f_squared = fixed_mul(f, f); + + int i; + for (i = 2; i <= 12; i += 2) { + term = fixed_mul(term, f_squared); + term = fixed_div(term, int_to_fixed(i * (i - 1))); + + if ((i / 2) % 2 == 0) { + result = fixed_add(result, term); + } else { + result = fixed_sub(result, term); + } + } + + return result; +} + +/* Tangent function */ +fixed_t fixed_tan(fixed_t f) { + fixed_t cos_val = fixed_cos(f); + if (cos_val == 0) + return 0; /* Handle undefined case */ + return fixed_div(fixed_sin(f), cos_val); +} + +/* Utility functions */ +fixed_t fixed_min(fixed_t a, fixed_t b) { return (a < b) ? a : b; } + +fixed_t fixed_max(fixed_t a, fixed_t b) { return (a > b) ? a : b; } + +fixed_t fixed_clamp(fixed_t f, fixed_t min_val, fixed_t max_val) { + if (f < min_val) + return min_val; + if (f > max_val) + return max_val; + return f; +} diff --git a/src/vm/fixed.h b/src/vm/fixed.h new file mode 100644 index 0000000..717705c --- /dev/null +++ b/src/vm/fixed.h @@ -0,0 +1,53 @@ +#ifndef FIXED_H +#define FIXED_H + +#include "common.h" + +/* Q16.16 fixed-point type */ +typedef i32 fixed_t; + +/* Constants */ +#define FIXED_ONE 0x00010000L /* 1.0 in Q16.16 */ +#define FIXED_ZERO 0x00000000L /* 0.0 in Q16.16 */ +#define FIXED_HALF 0x00008000L /* 0.5 in Q16.16 */ +#define FIXED_PI 0x0003243FL /* π ≈ 3.14159 */ +#define FIXED_E 0x0002B7E1L /* e ≈ 2.71828 */ +#define FIXED_MAX 0x7FFFFFFFL /* Maximum positive value */ +#define FIXED_MIN 0x80000000L /* Minimum negative value */ + +/* Conversion functions */ +fixed_t int_to_fixed(i32 i); +i32 fixed_to_int(fixed_t f); +fixed_t float_to_fixed(f32 f); +f32 fixed_to_float(fixed_t f); + +/* Basic arithmetic operations */ +fixed_t fixed_add(fixed_t a, fixed_t b); +fixed_t fixed_sub(fixed_t a, fixed_t b); +fixed_t fixed_mul(fixed_t a, fixed_t b); +fixed_t fixed_div(fixed_t a, fixed_t b); + +/* Comparison functions */ +int fixed_eq(fixed_t a, fixed_t b); +int fixed_ne(fixed_t a, fixed_t b); +int fixed_lt(fixed_t a, fixed_t b); +int fixed_le(fixed_t a, fixed_t b); +int fixed_gt(fixed_t a, fixed_t b); +int fixed_ge(fixed_t a, fixed_t b); + +/* Unary operations */ +fixed_t fixed_neg(fixed_t f); +fixed_t fixed_abs(fixed_t f); + +/* Advanced math functions */ +fixed_t fixed_sqrt(fixed_t f); +fixed_t fixed_sin(fixed_t f); /* f in radians */ +fixed_t fixed_cos(fixed_t f); /* f in radians */ +fixed_t fixed_tan(fixed_t f); /* f in radians */ + +/* Utility functions */ +fixed_t fixed_min(fixed_t a, fixed_t b); +fixed_t fixed_max(fixed_t a, fixed_t b); +fixed_t fixed_clamp(fixed_t f, fixed_t min, fixed_t max); + +#endif /* FIXED_H */ diff --git a/src/vm/vm.c b/src/vm/vm.c index 84bf11f..ba92c73 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -1,7 +1,8 @@ #include "vm.h" #include "device.h" -#include "opcodes.h" +#include "fixed.h" #include "libc.h" +#include "opcodes.h" #define COMPARE_AND_JUMP(type, op) \ do { \ @@ -101,12 +102,10 @@ bool step_vm(VM *vm) { Frame *child; u32 jmp, heap_mask, i; - /* Read call parameters */ jmp = read_u32(vm, code, vm->pc); vm->pc += 4; N = vm->code[vm->pc++]; - /* Read arguments */ for (i = 0; i < N; i++) { args[i] = vm->code[vm->pc++]; } @@ -114,7 +113,6 @@ bool step_vm(VM *vm) { return_reg = vm->code[vm->pc++]; frame->return_reg = return_reg; - /* Stack and frame checks */ if (vm->sp >= STACK_SIZE) return false; vm->stack[vm->sp++] = vm->pc; @@ -123,14 +121,12 @@ bool step_vm(VM *vm) { return false; vm->fp++; - /* Setup child frame */ child = &vm->frames[vm->fp]; child->start = vm->mp; child->end = vm->mp; child->return_reg = 0; child->heap_mask = 0; - /* Optimized register copy with bitmask for heap status */ heap_mask = 0; for (i = 0; i < N; i++) { src_reg = args[i]; @@ -185,11 +181,9 @@ bool step_vm(VM *vm) { if (parent->end + size + 4 > MEMORY_SIZE) { return false; } - *(u32 *)(vm->memory + new_ptr) = size; memcopy(vm->memory + new_ptr + 4, vm->memory + ptr + 4, size); parent->end += size + 4; - parent->registers[parent->return_reg] = new_ptr; parent->heap_mask |= (1 << parent->return_reg); } else { @@ -198,7 +192,6 @@ bool step_vm(VM *vm) { } } - /* Always handle frame cleanup */ vm->pc = vm->stack[--vm->sp]; vm->mp = child->start; vm->fp--; @@ -603,7 +596,7 @@ bool step_vm(VM *vm) { device_ptr = frame->registers[device_reg]; /* device pointer */ buffer_ptr = frame->registers[buffer_reg]; - size = frame->registers[size_reg]; /* size */ + size = frame->registers[size_reg]; /* size */ handle = vm->memory[device_ptr + 4]; /* get device handle */ dev = &vm->devices[handle]; @@ -624,7 +617,7 @@ bool step_vm(VM *vm) { vm->pc++; device_ptr = frame->registers[device_reg]; /* device pointer */ - handle = vm->memory[device_ptr + 4]; /* get device handle */ + handle = vm->memory[device_ptr + 4]; /* get device handle */ dev = &vm->devices[handle]; if (dev && dev->ops->refresh) { vm->flag = dev->ops->refresh(dev->data, &vm->memory[device_ptr + 4]); @@ -635,7 +628,6 @@ bool step_vm(VM *vm) { return true; } - case SYSCALL_DEVICE_WRITE: { Device *dev; u32 handle, buffer_ptr, size, device_ptr; @@ -743,28 +735,28 @@ bool step_vm(VM *vm) { case OP_DIV_INT: MATH_OP(i32, /); case OP_ABS_INT: { - dest = read_u8(vm, code, vm->pc); - vm->pc++; - src1 = read_u8(vm, code, vm->pc); - vm->pc++; + dest = read_u8(vm, code, vm->pc); + vm->pc++; + src1 = read_u8(vm, code, vm->pc); + vm->pc++; - value = frame->registers[src1]; - if (value < 0) { - value = -value; - } - - frame->registers[dest] = value; - return true; - } + value = frame->registers[src1]; + if (value < 0) { + value = -value; + } + + frame->registers[dest] = value; + return true; + } case OP_NEG_INT: { - dest = read_u8(vm, code, vm->pc); - vm->pc++; - src1 = read_u8(vm, code, vm->pc); - vm->pc++; + dest = read_u8(vm, code, vm->pc); + vm->pc++; + src1 = read_u8(vm, code, vm->pc); + vm->pc++; - value = frame->registers[src1]; - frame->registers[dest] = -value; - return true; + value = frame->registers[src1]; + frame->registers[dest] = -value; + return true; } case OP_ADD_NAT: MATH_OP(u32, +); @@ -782,7 +774,7 @@ bool step_vm(VM *vm) { src2 = read_u8(vm, code, vm->pc); vm->pc++; frame->registers[dest] = - (frame->registers[src1] * frame->registers[src2]) >> 16; + fixed_mul(frame->registers[src1], frame->registers[src2]); return true; } @@ -794,7 +786,7 @@ bool step_vm(VM *vm) { src2 = read_u8(vm, code, vm->pc); vm->pc++; frame->registers[dest] = - (frame->registers[src1] << 16) / frame->registers[src2]; + fixed_div(frame->registers[src1], frame->registers[src2]); return true; } @@ -805,7 +797,8 @@ bool step_vm(VM *vm) { vm->pc++; src2 = read_u8(vm, code, vm->pc); vm->pc++; - frame->registers[dest] = frame->registers[src1] + frame->registers[src2]; + frame->registers[dest] = + fixed_add(frame->registers[src1], frame->registers[src2]); return true; } @@ -816,7 +809,8 @@ bool step_vm(VM *vm) { vm->pc++; src2 = read_u8(vm, code, vm->pc); vm->pc++; - frame->registers[dest] = frame->registers[src1] - frame->registers[src2]; + frame->registers[dest] = + fixed_sub(frame->registers[src1], frame->registers[src2]); return true; } case OP_REAL_TO_INT: { @@ -826,11 +820,7 @@ bool step_vm(VM *vm) { vm->pc++; value = frame->registers[src1]; - if (value >= 0) { - frame->registers[dest] = value >> 16; - } else { - frame->registers[dest] = -((-value) >> 16); - } + frame->registers[dest] = fixed_to_int(value); return true; } @@ -839,7 +829,7 @@ bool step_vm(VM *vm) { vm->pc++; src1 = read_u8(vm, code, vm->pc); vm->pc++; - frame->registers[dest] = (frame->registers[src1] << 16); + frame->registers[dest] = int_to_fixed(frame->registers[src1]); return true; } case OP_REAL_TO_NAT: { @@ -848,11 +838,7 @@ bool step_vm(VM *vm) { src1 = read_u8(vm, code, vm->pc); vm->pc++; value = frame->registers[src1]; - if (value < 0) { - frame->registers[dest] = 0; - } else { - frame->registers[dest] = AS_NAT(value >> 16); - } + frame->registers[dest] = fixed_to_int(value); return true; } case OP_NAT_TO_REAL: { @@ -860,7 +846,7 @@ bool step_vm(VM *vm) { vm->pc++; src1 = read_u8(vm, code, vm->pc); vm->pc++; - frame->registers[dest] = AS_INT(frame->registers[src1] << 16); + frame->registers[dest] = int_to_fixed(frame->registers[src1]); return true; } case OP_JEQ_NAT: { diff --git a/test/add.rom b/test/add.rom index 618c517c3d9328a670095dc647f4051d1e5bc7ed..0f1dd4cf7279a0013513ad42e030f59d47f9742f 100644 GIT binary patch delta 93 zcmeBX>}O7BU2DF6Qeee&B**8BsbAU+Qf&6fteX3#K6SDEC6Kq gurNaem|2+qa{~qRQ&P+HOHzw+^$mck7#O%10N>vVwg3PC delta 89 zcmeBY>}F(T0D{PgtSZ8aKn4>7Ba;s^6Qeqi&B*+JqJy*v3$p-_yk#5;IuoJvUiNnfYGGf4s9quSqT z7wUmt_w?}G*=Wq`AW{)adng5@VIJT`97i3M>5IeQxT?8&@$aY!l~@S<5)cb&d$J!8^tx UgFfwbEAReW#(wye8}io}1D!191@#Vn+*#di|Op4dmzj7XVmv%Zvr|3iX=QT2R(% tKdCL*n5Y)+6jldj6L72Wk1Q@X>cSr1aL4Ni6P)%6X47+~xDEdCGd_iw3g!R+ diff --git a/test/loop.rom b/test/loop.rom index 42eabd88f168876c9bcae5b8f1b74a8b51f35411..1ae871122caf2b3379b7de38bba2408806ef034d 100644 GIT binary patch literal 258 zcmYL@u?oUK42F|SN{_omaBva1MGzdStBaFcH+=y?5eGZe;xp(o`Eci-mSP~uclpDA zAtL%B$5@YmuE>Iv-&3$NK_w%!u=xsQ&Mf-{1a=zwg=ke6C4{(T(sBZ>eJNtI(yLE^ zS@dF#A$tCxbIeEO0X3h529yj9-OVnRUKiirZrvLx| literal 254 zcmYL?u?oUK42F|SN{>4S#lc172Aw+8Rd>7TI|!EIV24_K1Hm`)@y`ERih(3w@`pb} zL|^0-#RTYz%t-mO1e+wNM1*E(zeQOy%V7h7jk@8$rz(u%oG+L(pMxu#i=>H1EyVZ!8NT#0L<3pX0$H*2&j7lS)04ysU($uxvy@q+v|BtOe-tWaz?i9$=TN z1rO7qnjO;6UwM=+7uDy)-KlXRIoHxQoXzCAG^)vec#`72kC25=KA(w(^Dc+ N3m@h)vKO*9vQGwOFP{Ja literal 594 zcmah`OHRWu5cT*UC(e{AiKv=Zm0-uB2&y8%k`+tTBS4k~i3*k+f@`qn3LJ!kn6XJD zkPvwB-prdBzp>01V;?}!pUn^u%M{Bzl1M${+*iy}>Kj%NNf;3>Y6fyN9=dRpJ2;Bf zA`VF(5jKRXhQe3D!D*`2zgC4HnbnQZM3`q7EzX|_vfLX??iQ1KS&{m;7aWqWHn#9k z{$u>3b=bl+2jn3^5yC6oW$LOi79gC&l~}8}YK>55*YTBnok*t)M9RQO7w;&YA9#%=3_9aPAiF@c9UN@x+q0vXCl z{I~_;M9$+iK95ETYolg1kt6) zEPVsPm9O9F@ZkSs<>rRmoeDLZYmu zBFCzli4lUL3Fc)jNKH;+6;yswIy%eQ5t~%SGaX4GbWNjb+BrHOvh_c*ZOE>@tU2zz z*z*pvS9{)b1Mj<@cbL7=^X?D4w|d@T_HNI6bKrf_^Tt_;!U$2%q(Sgy;kl$&4)FR# zSy>;do%>Mj@f4|aZRr7SXKX&IX#Af-N77W)BWbDyku=qhNSbO+Bu#ZHlBU`gNmD(H zq^X7;lWw}}W~b3RMH(~xLXT`co!OkIyUeW)qcNFotknDOkr&xs2qs*S3|C~8&7Xz_2|P$HR`^;mLjVW!xhcjo)n){JccfTf~EVu{TaK%G`8XTmz4<`al% zn@=GlC>+zeC;-*?QloO?)Z&t>8JkqjD}D+Abb(nusVwgKYVnWiZC|authwktY&_FLpo9Wu=6`GwwO)LJQ8AZip8pVj!4IVX=CeURR>YE>_2El=c@jDFt4kKmx zjFDAAW%Yf!v_7%_l`IzbPY7CDeMl8$_*GHS7O!zYYkgBtItY!a$|Q(O8^%o*6B|WU zP|cmf(z$Tqz^NVn0W6%`QFH%@yH4-U+~pZPsdG3pW`5vEV#qflax*xn kTRyCCTliYYFAm468gM3jDf}tCD|{<_BRm&=7ycIh1uBAfcmMzZ diff --git a/test/simple.rom b/test/simple.rom index 13f146d7d77cfec10f670467ab81563d06737b5d..fd84bf941006f8de59fe213c33f07f662309d1a5 100644 GIT binary patch literal 140 zcmXwyF$#b%3`KwPJK4p_!9g6|>One*N3f%dh}W-)(m-Aw$%g>IX5DIPVza~Gl+n1T uV5iD#F04i%$j9iUyGRV|O|pXY1vCf#%AnPw=_pUS%XOyJ?*7GdfZ_#>D+nL} delta 87 zcmeBS>|kVN00O^>tjhcCAf{%xhXA zq7QbzcD+ECnHs}dXSR)r-%uQPX-)}L8|Qyg(j<_wC&C%PydZAl;tw;842dqY#=uZf zngN=#Bc~Jl6UxY@L#IciiPPL=mE`lP8e$j10s_TjvxS;grVrZaY*@kzbg^o}am-fC z8m@^b{LU0L@|$EMQJ3Odee|#TeziduC#fLqzmJ zhByR(uIEA&OP!l8CVm5PJY)qWKwVt?m5Qcbse+<8hp;G#ySV&|xmbEfn;WG-sI1fo z&6?E8#{P_wnrv+4M3z|bUDiplsOvGZ)U2TZ@kH%_X0-}N8`&kzE2&1XKgDdc+Jdza w`BA2*)xRxPIvQqpYfkRf+>bZsF3p;qUZ_23csga%ZJFCkVQ?EnA(