From dd7cc62a3e15dea5617fa1f89c7c74df5348cca1 Mon Sep 17 00:00:00 2001 From: zongor Date: Wed, 17 Sep 2025 23:16:38 -0700 Subject: [PATCH] Refactor to varied length opcodes, update structure, fix Makefile, WIP: number toS --- .gitignore | 2 +- Makefile | 153 +++++++++ {test => bench}/add.lua | 0 {test => bench}/add.pl | 0 {test => bench}/add.py | 0 {test => bench}/add.ul | 0 {test => bench}/add.zl | 0 {test => bench}/fib.lua | 0 {test => bench}/fib.pl | 0 {test => bench}/fib.py | 0 {test => bench}/fib.ul | 0 {test => bench}/fib.zl | 0 {test => bench}/hello.ul | 0 {test => bench}/loop.lua | 2 +- {test => bench}/loop.pl | 2 +- {test => bench}/loop.py | 2 +- {test => bench}/loop.ul | 4 +- {test => bench}/loop.zl | 2 +- {test => bench}/run.sh | 0 {test => bench}/simple.ul | 0 src/Makefile | 91 ----- src/arch/linux/devices.c | 96 +++++- src/arch/linux/devices.h | 53 +-- src/arch/linux/main.c | 36 +- src/common.h | 23 +- src/device.c | 78 +++-- src/device.h | 4 +- src/gen/build.sh | 2 + src/gen/math_gen.c | 31 ++ src/opcodes.h | 136 ++++---- src/str.c | 44 +++ src/str.h | 10 + src/test.c | 263 ++++++--------- src/vm.c | 690 ++++++++++++++++++++------------------ src/vm.h | 5 +- test/loop.asm | 2 +- 36 files changed, 987 insertions(+), 744 deletions(-) create mode 100644 Makefile rename {test => bench}/add.lua (100%) rename {test => bench}/add.pl (100%) rename {test => bench}/add.py (100%) rename {test => bench}/add.ul (100%) rename {test => bench}/add.zl (100%) rename {test => bench}/fib.lua (100%) rename {test => bench}/fib.pl (100%) rename {test => bench}/fib.py (100%) rename {test => bench}/fib.ul (100%) rename {test => bench}/fib.zl (100%) rename {test => bench}/hello.ul (100%) rename {test => bench}/loop.lua (87%) rename {test => bench}/loop.pl (83%) rename {test => bench}/loop.py (78%) rename {test => bench}/loop.ul (69%) rename {test => bench}/loop.zl (77%) rename {test => bench}/run.sh (100%) rename {test => bench}/simple.ul (100%) delete mode 100644 src/Makefile create mode 100644 src/gen/build.sh create mode 100644 src/gen/math_gen.c create mode 100644 src/str.c create mode 100644 src/str.h diff --git a/.gitignore b/.gitignore index 6880352..789123e 100644 --- a/.gitignore +++ b/.gitignore @@ -104,6 +104,6 @@ dkms.conf zre zre.wasm memory_dump.bin -src/build/ +build/ .gdb_history .vscode \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a803ee3 --- /dev/null +++ b/Makefile @@ -0,0 +1,153 @@ +# --- CONFIGURABLE DEFAULTS --- +PLATFORM ?= linux +BUILD_MODE ?= debug # 'debug' or 'deploy' + +# --- DIRECTORIES --- +SRC_DIR := src +BUILD_DIR := build/$(PLATFORM) +ARCH_DIR := $(SRC_DIR)/arch/$(PLATFORM) + +# --- COMPILERS --- +ifeq ($(PLATFORM), emscripten) + CC := emcc +else + CC ?= gcc +endif + +# --- SHARED FLAGS --- +BASE_CFLAGS := -I$(SRC_DIR) -Wall -Wextra -Werror -pedantic + +# --- CORE-SPECIFIC FLAGS (freestanding, no stdlib) --- +CORE_CFLAGS := $(BASE_CFLAGS) -std=c89 -ffreestanding -nostdlib -fno-builtin + +# --- PLATFORM-SPECIFIC FLAGS --- +PLATFORM_CFLAGS := $(BASE_CFLAGS) + +# --- MODE & PLATFORM SPECIFIC FLAGS --- +ifeq ($(BUILD_MODE), deploy) + CORE_CFLAGS += -O2 -DNDEBUG + PLATFORM_CFLAGS += -O2 -DNDEBUG + LDFLAGS += -s + TARGET_SUFFIX := -release +else + CORE_CFLAGS += -g -DDEBUG + PLATFORM_CFLAGS += -g -DDEBUG + TARGET_SUFFIX := -debug +endif + +# --- LINUX-SPECIFIC (SDL, libc) --- +ifeq ($(PLATFORM), linux) + PLATFORM_CFLAGS += $(shell pkg-config --cflags sdl2 2>/dev/null) + LDFLAGS += $(shell pkg-config --libs sdl2 2>/dev/null) -lm + TARGET = $(BUILD_DIR)/zre-$(PLATFORM)$(TARGET_SUFFIX) +endif + +# --- EMSCRIPTEN-SPECIFIC --- +ifeq ($(PLATFORM), emscripten) + # Core still compiled freestanding (emcc supports this) + # Platform layer gets Emscripten/SDL flags + PLATFORM_CFLAGS += -s USE_SDL=2 -s WASM=1 + LDFLAGS += -s USE_SDL=2 -s WASM=1 + + # For deploy: optimize, strip debug, minimize size + ifeq ($(BUILD_MODE), deploy) + PLATFORM_CFLAGS += -O3 + LDFLAGS += -O3 --closure 1 + else + # For debug: preserve names, generate source maps + PLATFORM_CFLAGS += -gsource-map + LDFLAGS += -gsource-map --source-map-base . + endif + + # Output: HTML + JS + WASM + TARGET = $(BUILD_DIR)/zre.html +endif + +# --- FALLBACK TARGET (if no platform matched) --- +ifndef TARGET + TARGET = $(BUILD_DIR)/zre-$(PLATFORM)$(TARGET_SUFFIX) +endif + +# --- CORE SOURCES (flat in src/) --- +CORE_SOURCES := \ + $(SRC_DIR)/str.c \ + $(SRC_DIR)/vm.c \ + $(SRC_DIR)/device.c \ + $(SRC_DIR)/test.c + +# --- PLATFORM SOURCE --- +PLATFORM_SOURCE := $(ARCH_DIR)/main.c \ + $(ARCH_DIR)/devices.c + +# --- OBJECT FILES --- +CORE_OBJS := $(CORE_SOURCES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o) +PLATFORM_OBJ := $(PLATFORM_SOURCE:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o) + +# --- DEPENDENCIES --- +DEPS := $(CORE_OBJS:.o=.d) $(PLATFORM_OBJ:.o=.d) + +.PHONY: all debug deploy clean clean-all help + +# Default target +all: $(TARGET) + +# 'debug' target — just set BUILD_MODE and build +debug: BUILD_MODE = debug +debug: $(TARGET) + +# 'deploy' target — just set BUILD_MODE and build +deploy: BUILD_MODE = deploy +deploy: $(TARGET) + +# Main build rule +$(TARGET): $(CORE_OBJS) $(PLATFORM_OBJ) + @mkdir -p $(dir $@) + $(CC) $(PLATFORM_CFLAGS) $(LDFLAGS) -o $@ $^ + @echo "Built: $@" + @if [ "$(PLATFORM)" = "emscripten" ]; then \ + echo "Open in browser: file://$(shell pwd)/$@"; \ + fi + +# --- COMPILE CORE (freestanding) --- +$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c + @mkdir -p $(dir $@) + $(CC) $(CORE_CFLAGS) -MMD -MP -c $< -o $@ + +# --- COMPILE PLATFORM --- +$(BUILD_DIR)/arch/$(PLATFORM)/%.o: $(ARCH_DIR)/%.c + @mkdir -p $(dir $@) + $(CC) $(PLATFORM_CFLAGS) -MMD -MP -c $< -o $@ + +# --- AUTO-DEPENDENCIES --- +-include $(DEPS) + +# --- CLEAN --- +clean: + @echo "Cleaning build artifacts for $(PLATFORM)..." + @rm -rf $(BUILD_DIR) + @echo "Cleaned." + +clean-all: + @echo "Cleaning ALL build artifacts..." + @rm -rf build/ + @echo "All cleaned." + +# --- HELP --- +help: + @echo "Undar VM" + @echo "" + @echo "Targets:" + @echo " make -> debug build (default: linux)" + @echo " make debug -> same as above" + @echo " make deploy -> optimized, stripped build" + @echo " make clean -> clean current platform" + @echo " make clean-all→ clean all platforms" + @echo "" + @echo "Platforms:" + @echo " make PLATFORM=linux -> GCC + SDL2" + @echo " make PLATFORM=emscripten -> Emscripten + SDL2 for Web" + @echo " make PLATFORM=avr -> (example) AVR-GCC" + @echo "" + @echo "Output:" + @echo " Linux: build/linux/zre-linux-" + @echo " Web: build/emscripten/zre.html (+ .js, .wasm)" diff --git a/test/add.lua b/bench/add.lua similarity index 100% rename from test/add.lua rename to bench/add.lua diff --git a/test/add.pl b/bench/add.pl similarity index 100% rename from test/add.pl rename to bench/add.pl diff --git a/test/add.py b/bench/add.py similarity index 100% rename from test/add.py rename to bench/add.py diff --git a/test/add.ul b/bench/add.ul similarity index 100% rename from test/add.ul rename to bench/add.ul diff --git a/test/add.zl b/bench/add.zl similarity index 100% rename from test/add.zl rename to bench/add.zl diff --git a/test/fib.lua b/bench/fib.lua similarity index 100% rename from test/fib.lua rename to bench/fib.lua diff --git a/test/fib.pl b/bench/fib.pl similarity index 100% rename from test/fib.pl rename to bench/fib.pl diff --git a/test/fib.py b/bench/fib.py similarity index 100% rename from test/fib.py rename to bench/fib.py diff --git a/test/fib.ul b/bench/fib.ul similarity index 100% rename from test/fib.ul rename to bench/fib.ul diff --git a/test/fib.zl b/bench/fib.zl similarity index 100% rename from test/fib.zl rename to bench/fib.zl diff --git a/test/hello.ul b/bench/hello.ul similarity index 100% rename from test/hello.ul rename to bench/hello.ul diff --git a/test/loop.lua b/bench/loop.lua similarity index 87% rename from test/loop.lua rename to bench/loop.lua index b1a8854..69ed8be 100644 --- a/test/loop.lua +++ b/bench/loop.lua @@ -1,5 +1,5 @@ local a = 5.0 -for i = 50000, 0, -1 do +for i = 5000, 0, -1 do a = a + 5.0 end local b = math.floor(a) diff --git a/test/loop.pl b/bench/loop.pl similarity index 83% rename from test/loop.pl rename to bench/loop.pl index e2a2492..a28308d 100644 --- a/test/loop.pl +++ b/bench/loop.pl @@ -1,5 +1,5 @@ my $a = 5.0; -for (my $i = 50000; $i >= 0; $i--) { +for (my $i = 5000; $i >= 0; $i--) { $a += 5.0; } my $b = int($a); diff --git a/test/loop.py b/bench/loop.py similarity index 78% rename from test/loop.py rename to bench/loop.py index 11cc9ba..cc614b0 100644 --- a/test/loop.py +++ b/bench/loop.py @@ -1,5 +1,5 @@ a = 5.0 -for i in range(50000, -1, -1): +for i in range(5000, -1, -1): a += 5.0 b = int(a) user_string = input("Enter a string:") diff --git a/test/loop.ul b/bench/loop.ul similarity index 69% rename from test/loop.ul rename to bench/loop.ul index 2db9714..09bc993 100644 --- a/test/loop.ul +++ b/bench/loop.ul @@ -1,9 +1,9 @@ real a = 5.0; -do (int i = 50000, 0, -1) { +do (int i = 5000, 0, -1) { a = a + 5.0; } int b = a as nat; -print "Enter a string:"); +print("Enter a string:"); str user_string = read(); print a.str; print b.str; diff --git a/test/loop.zl b/bench/loop.zl similarity index 77% rename from test/loop.zl rename to bench/loop.zl index 9e75702..8b9f6d5 100644 --- a/test/loop.zl +++ b/bench/loop.zl @@ -1,5 +1,5 @@ let a = 5.0; -for (let i = 50000; i > 0; i = i - 1) { +for (let i = 5000; i > 0; i = i - 1) { a = a + 5.0; } let b = a; diff --git a/test/run.sh b/bench/run.sh similarity index 100% rename from test/run.sh rename to bench/run.sh diff --git a/test/simple.ul b/bench/simple.ul similarity index 100% rename from test/simple.ul rename to bench/simple.ul diff --git a/src/Makefile b/src/Makefile deleted file mode 100644 index dd69b4c..0000000 --- a/src/Makefile +++ /dev/null @@ -1,91 +0,0 @@ -# Compiler configurations -# ----------------------- -# Native build (gcc) -CC_NATIVE = gcc -CFLAGS_NATIVE = -g -std=c89 -Wall -Wextra -Werror -Wno-unused-parameter -I. #-O2 -LDFLAGS_NATIVE = -LDLIBS_NATIVE = -lSDL2 - -# WASM build (emscripten) -CC_WASM = emcc -CFLAGS_WASM = -g -std=c89 -Wall -Wextra -Werror -Wno-unused-parameter -I. -LDFLAGS_WASM = -s WASM=1 -g -s USE_SDL=2 -LDLIBS_WASM = - -# Source and build configuration -# ---------------------------- -COMMON_SRC = $(wildcard *.c) - -# Separate architecture sources -ARCH_SRC_LINUX = $(wildcard arch/linux/*.c) -ARCH_SRC_EMSCRIPTEN = $(wildcard arch/emscripten/*.c) - -# Object directories -OBJ_DIR_NATIVE = build/native/obj -OBJ_DIR_WASM = build/wasm/obj - -# Common objects from root -OBJ_NATIVE = $(addprefix $(OBJ_DIR_NATIVE)/,$(notdir $(COMMON_SRC:.c=.o))) -OBJ_WASM = $(addprefix $(OBJ_DIR_WASM)/,$(notdir $(COMMON_SRC:.c=.o))) - -# Architecture-specific objects -OBJ_ARCH_NATIVE = $(addprefix $(OBJ_DIR_NATIVE)/,$(notdir $(ARCH_SRC_LINUX:.c=.o))) -OBJ_ARCH_WASM = $(addprefix $(OBJ_DIR_WASM)/,$(notdir $(ARCH_SRC_EMSCRIPTEN:.c=.o))) - -# Executables -EXEC_NATIVE = zre -EXEC_WASM = zre.wasm - -# Phony targets -.PHONY: all clean install wasm native emscripten linux macos - -# Default target builds the native version -all: native - -# Native build rules -# ------------------ -native: linux - -linux: $(EXEC_NATIVE) - -$(EXEC_NATIVE): $(OBJ_NATIVE) $(OBJ_ARCH_NATIVE) - $(CC_NATIVE) $(LDFLAGS_NATIVE) $^ $(LDLIBS_NATIVE) -o $@ - -# WASM build rules -# ---------------- -wasm: emscripten - -emscripten: $(EXEC_WASM) - -$(EXEC_WASM): $(OBJ_WASM) $(OBJ_ARCH_WASM) - $(CC_WASM) $(LDFLAGS_WASM) $^ $(LDLIBS_WASM) -o $@ - -# Object file rules -# ----------------- -$(OBJ_DIR_NATIVE)/%.o: %.c - @mkdir -p $(dir $@) - $(CC_NATIVE) $(CFLAGS_NATIVE) -c $< -o $@ - -$(OBJ_DIR_WASM)/%.o: %.c - @mkdir -p $(dir $@) - $(CC_WASM) $(CFLAGS_WASM) -c $< -o $@ - -# Architecture-specific source rules -$(OBJ_DIR_NATIVE)/%.o: arch/linux/%.c - @mkdir -p $(dir $@) - $(CC_NATIVE) $(CFLAGS_NATIVE) -c $< -o $@ - -$(OBJ_DIR_WASM)/%.o: arch/emscripten/%.c - @mkdir -p $(dir $@) - $(CC_WASM) $(CFLAGS_WASM) -c $< -o $@ - -# Clean build artifacts -# --------------------- -clean: - rm -rf $(OBJ_DIR_NATIVE) $(OBJ_DIR_WASM) $(EXEC_NATIVE) $(EXEC_WASM) - -# Install target (example) -# ------------------------ -install: native - install -d $(DESTDIR)/usr/local/bin - install $(EXEC_NATIVE) $(DESTDIR)/usr/local/bin/ \ No newline at end of file diff --git a/src/arch/linux/devices.c b/src/arch/linux/devices.c index 585d129..0ac41ec 100644 --- a/src/arch/linux/devices.c +++ b/src/arch/linux/devices.c @@ -1,6 +1,43 @@ #include "devices.h" +#include +#include -int screen_open(void *data, uint32_t mode) { +i32 console_open(void *data, u32 mode) { + USED(mode); + USED(data); + /* Nothing to open — stdin/stdout are always available */ + return 0; /* Success */ +} + +i32 console_read(void *data, u8 *buffer, u32 size) { + USED(data); + ssize_t result = read(STDIN_FILENO, buffer, size); + if (result < 0) return -1; /* Error */ + return (i32)result; /* Bytes read */ +} + +i32 console_write(void *data, const u8 *buffer, u32 size) { + USED(data); + ssize_t result = write(STDOUT_FILENO, buffer, size); + if (result < 0) return -1; /* Error */ + return (i32)result; /* Bytes written */ +} + +i32 console_close(void *data) { + USED(data); + /* Nothing to close — stdin/stdout are process-owned */ + return 0; +} + +i32 console_ioctl(void *data, u32 cmd, void *args) { + USED(data); + USED(cmd); + USED(args); + return -1; /* Unsupported */ +} + +i32 screen_open(void *data, u32 mode) { + USED(mode); ScreenDeviceData *screen = (ScreenDeviceData *)data; @@ -27,12 +64,17 @@ int screen_open(void *data, uint32_t mode) { return 0; } -int screen_read(void *data, uint8_t *buffer, uint32_t size) { return -1; } +i32 screen_read(void *data, u8 *buffer, u32 size) { + USED(data); + USED(buffer); + USED(size); + return -1; +} -int screen_write(void *data, const uint8_t *buffer, uint32_t size) { +i32 screen_write(void *data, const u8 *buffer, u32 size) { ScreenDeviceData *screen = (ScreenDeviceData *)data; - if (size > screen->framebuffer_size * sizeof(uint8_t)) { + if (size > screen->framebuffer_size * sizeof(u8)) { return -1; } @@ -40,7 +82,7 @@ int screen_write(void *data, const uint8_t *buffer, uint32_t size) { return 0; } -int screen_close(void *data) { +i32 screen_close(void *data) { ScreenDeviceData *screen = (ScreenDeviceData *)data; if (screen->texture) { @@ -59,15 +101,19 @@ int screen_close(void *data) { } /* MOUSE */ -int mouse_open(void *data, uint32_t mode) { return 0; } +i32 mouse_open(void *data, u32 mode) { + USED(data); + USED(mode); + return 0; +} -int mouse_read(void *data, uint8_t *buffer, uint32_t size) { +i32 mouse_read(void *data, u8 *buffer, u32 size) { MouseDeviceData *mouse = (MouseDeviceData *)data; - if (size < 3 * sizeof(uint32_t)) + if (size < 3 * sizeof(u32)) return -1; - uint32_t *out = (uint32_t *)buffer; + u32 *out = (u32 *)buffer; out[0] = mouse->x; out[1] = mouse->y; out[2] = (mouse->btn1 | (mouse->btn2 << 1) | (mouse->btn3 << 2) | @@ -75,24 +121,42 @@ int mouse_read(void *data, uint8_t *buffer, uint32_t size) { return 0; } -int mouse_write(void *data, const uint8_t *buffer, uint32_t size) { return -1; } +i32 mouse_write(void *data, const u8 *buffer, u32 size) { + USED(data); + USED(buffer); + USED(size); + return -1; +} -int mouse_close(void *data) { return 0; } +i32 mouse_close(void *data) { + USED(data); + return 0; +} -int keyboard_open(void *data, uint32_t mode) { return 0; } +i32 keyboard_open(void *data, u32 mode) { + USED(data); + USED(mode); + return 0; +} -int keyboard_read(void *data, uint8_t *buffer, uint32_t size) { +i32 keyboard_read(void *data, u8 *buffer, u32 size) { KeyboardDeviceData *kbd = (KeyboardDeviceData *)data; - if (size < (uint32_t)kbd->key_count) + if (size < (u32)kbd->key_count) return -1; memcpy(buffer, kbd->keys, kbd->key_count); return 0; } -int keyboard_write(void *data, const uint8_t *buffer, uint32_t size) { +i32 keyboard_write(void *data, const u8 *buffer, u32 size) { + USED(data); + USED(buffer); + USED(size); return -1; /* not writable */ } -int keyboard_close(void *data) { return 0; } +i32 keyboard_close(void *data) { + USED(data); + return 0; +} diff --git a/src/arch/linux/devices.h b/src/arch/linux/devices.h index 6923777..845e6c0 100644 --- a/src/arch/linux/devices.h +++ b/src/arch/linux/devices.h @@ -4,10 +4,10 @@ /* Screen device data */ typedef struct screen_device_data_s { - uint32_t width; - uint32_t height; - uint32_t framebuffer_pos; - uint32_t framebuffer_size; + u32 width; + u32 height; + u32 framebuffer_pos; + u32 framebuffer_size; VM* vm; SDL_Window *window; SDL_Renderer *renderer; @@ -16,32 +16,37 @@ typedef struct screen_device_data_s { /* Mouse device data */ typedef struct mouse_device_data_s { - uint32_t x; - uint32_t y; - uint8_t btn1; - uint8_t btn2; - uint8_t btn3; - uint8_t btn4; + u32 x; + u32 y; + u8 btn1; + u8 btn2; + u8 btn3; + u8 btn4; } MouseDeviceData; /* Keyboard device data */ typedef struct keyboard_device_data_s { - const uint8_t *keys; - int32_t key_count; + const u8 *keys; + i32 key_count; } KeyboardDeviceData; -int screen_open(void *data, uint32_t mode); -int screen_read(void *data, uint8_t *buffer, uint32_t size); -int screen_write(void *data, const uint8_t *buffer, uint32_t size); -int screen_close(void *data); +i32 screen_open(void *data, u32 mode); +i32 screen_read(void *data, u8 *buffer, u32 size); +i32 screen_write(void *data, const u8 *buffer, u32 size); +i32 screen_close(void *data); -int mouse_open(void *data, uint32_t mode); -int mouse_read(void *data, uint8_t *buffer, uint32_t size); -int mouse_write(void *data, const uint8_t *buffer, uint32_t size); -int mouse_close(void *data); +i32 mouse_open(void *data, u32 mode); +i32 mouse_read(void *data, u8 *buffer, u32 size); +i32 mouse_write(void *data, const u8 *buffer, u32 size); +i32 mouse_close(void *data); -int keyboard_open(void *data, uint32_t mode); -int keyboard_read(void *data, uint8_t *buffer, uint32_t size); -int keyboard_write(void *data, const uint8_t *buffer, uint32_t size); -int keyboard_close(void *data); +i32 keyboard_open(void *data, u32 mode); +i32 keyboard_read(void *data, u8 *buffer, u32 size); +i32 keyboard_write(void *data, const u8 *buffer, u32 size); +i32 keyboard_close(void *data); +i32 console_open(void *data, u32 mode); +i32 console_read(void *data, u8 *buffer, u32 size); +i32 console_write(void *data, const u8 *buffer, u32 size); +i32 console_close(void *data); +i32 console_ioctl(void *data, u32 cmd, void *args); \ No newline at end of file diff --git a/src/arch/linux/main.c b/src/arch/linux/main.c index 5833794..97f87bf 100644 --- a/src/arch/linux/main.c +++ b/src/arch/linux/main.c @@ -26,11 +26,21 @@ static DeviceOps keyboard_ops = {.open = keyboard_open, .close = keyboard_close, .ioctl = NULL}; +static DeviceOps console_device_ops = { + .open = console_open, + .read = console_read, + .write = console_write, + .close = console_close, + .ioctl = console_ioctl, +}; + static ScreenDeviceData screen_data = {0}; static MouseDeviceData mouse_data = {0}; static KeyboardDeviceData keyboard_data = {0}; void compileFile(const char *path, VM *vm) { + USED(vm); + FILE *f = fopen(path, "rb"); if (!f) { perror("fopen"); @@ -84,13 +94,13 @@ enum FlagType { #define MAX_INPUT_FILES 16 /* Adjust based on your system's constraints */ struct CompilerConfig { - uint32_t flags; + u32 flags; char *input_files[MAX_INPUT_FILES]; - int input_file_count; + i32 input_file_count; }; -int parse_arguments(int argc, char *argv[], struct CompilerConfig *config) { - int i; +i32 parse_arguments(i32 argc, char *argv[], struct CompilerConfig *config) { + i32 i; /* Initialize config */ config->flags = 0; @@ -131,6 +141,9 @@ int parse_arguments(int argc, char *argv[], struct CompilerConfig *config) { return 0; } +/* + * This needs to be done dynamically eventually + */ void register_sdl_devices(VM *vm) { screen_data.vm = vm; screen_data.width = 640; @@ -156,7 +169,7 @@ void register_sdl_devices(VM *vm) { &keyboard_ops); } -int main(int argc, char *argv[]) { +i32 main(i32 argc, char *argv[]) { struct CompilerConfig config = {0}; if (parse_arguments(argc, argv, &config) != 0) { @@ -172,7 +185,7 @@ int main(int argc, char *argv[]) { if (config.flags & FLAG_TEST_MODE) { compile_internal_test(config.input_files[0], &vm); } else { - int j; + i32 j; for (j = 0; j < config.input_file_count; j++) { compileFile(config.input_files[j], &vm); } @@ -206,9 +219,10 @@ int main(int argc, char *argv[]) { } } bool running = true; + vm_register_device(&vm, "/dev/term/0", "terminal", nil, &console_device_ops); if (config.flags & FLAG_GUI_MODE) { - uint32_t i; + u32 i; register_sdl_devices(&vm); while (running) { for (i = 0; i < vm.dc; i++) { @@ -260,7 +274,7 @@ int main(int argc, char *argv[]) { if (screen->texture && screen->renderer) { SDL_UpdateTexture(screen->texture, NULL, &vm.memory[screen->framebuffer_pos], - screen->width * sizeof(uint32_t)); + screen->width * sizeof(u32)); SDL_RenderClear(screen->renderer); @@ -271,9 +285,9 @@ int main(int argc, char *argv[]) { float scale = SDL_min(scale_x, scale_y); SDL_Rect dstrect = { - (int)((output_rect.w - screen->width * scale) / 2), - (int)((output_rect.h - screen->height * scale) / 2), - (int)(screen->width * scale), (int)(screen->height * scale)}; + (i32)((output_rect.w - screen->width * scale) / 2), + (i32)((output_rect.h - screen->height * scale) / 2), + (i32)(screen->width * scale), (i32)(screen->height * scale)}; SDL_RenderCopy(screen->renderer, screen->texture, NULL, &dstrect); SDL_RenderPresent(screen->renderer); diff --git a/src/common.h b/src/common.h index 2d1036d..5abd9b8 100644 --- a/src/common.h +++ b/src/common.h @@ -1,22 +1,19 @@ #ifndef ZRE_COMMON_H #define ZRE_COMMON_H -#include -#include #include +#include #include -typedef unsigned char u8; -typedef signed char i8; -typedef unsigned short u16; -typedef signed short i16; -typedef unsigned long u32; -typedef signed long i32; +typedef uint8_t u8; +typedef int8_t i8; +typedef uint16_t u16; +typedef int16_t i16; +typedef uint32_t u32; +typedef int32_t i32; -/* For 64-bit, use compiler extensions or split into hi/lo u32 on pure C89 platforms */ -#if defined(__GNUC__) || defined(_MSC_VER) -typedef unsigned long long u64; -typedef signed long long i64; -#endif +#define nil NULL + +#define USED(x) ((void)(x)) #endif diff --git a/src/device.c b/src/device.c index b00cf6d..e6c3ebb 100644 --- a/src/device.c +++ b/src/device.c @@ -1,53 +1,57 @@ #include "device.h" +#include "str.h" -#include +i32 vm_register_device(VM *vm, const char *path, const char *type, void *data, + DeviceOps *ops) { + Device *dev; -int vm_register_device(VM *vm, const char *path, const char *type, void *data, DeviceOps *ops) { - if (vm->dc >= DEVICES_SIZE) return -1; - - Device *dev = &vm->devices[vm->dc++]; - - strncpy(dev->path, path, DEVICE_PATH_MAX_LENGTH); - dev->path[DEVICE_PATH_MAX_LENGTH - 1] = '\0'; - - strncpy(dev->type, type, DEVICE_TYPE_MAX_LENGTH); - dev->type[DEVICE_TYPE_MAX_LENGTH - 1] = '\0'; - - dev->data = data; - dev->ops = ops; - dev->flags = 0; - return 0; + if (vm->dc >= DEVICES_SIZE) + return -1; + + dev = &vm->devices[vm->dc++]; + + strcopy(dev->path, path, DEVICE_PATH_MAX_LENGTH); + dev->path[DEVICE_PATH_MAX_LENGTH - 1] = '\0'; + + strcopy(dev->type, type, DEVICE_TYPE_MAX_LENGTH); + dev->type[DEVICE_TYPE_MAX_LENGTH - 1] = '\0'; + + dev->data = data; + dev->ops = ops; + dev->flags = 0; + return 0; } /* Find device by path */ -Device* find_device_by_path(VM *vm, const char *path) { - uint32_t i; - for (i = 0; i < vm->dc; i++) { - if (strcmp(vm->devices[i].path, path) == 0) { - return &vm->devices[i]; - } +Device *find_device_by_path(VM *vm, const char *path) { + u32 i; + for (i = 0; i < vm->dc; i++) { + if (streq(vm->devices[i].path, path)) { + return &vm->devices[i]; } - return NULL; + } + return NULL; } /* Find device by type (useful for checking capabilities) */ -Device* find_device_by_type(VM *vm, const char *type) { - uint32_t i; - for (i = 0; i < vm->dc; i++) { - if (strcmp(vm->devices[i].type, type) == 0) { - return &vm->devices[i]; - } +Device *find_device_by_type(VM *vm, const char *type) { + u32 i; + for (i = 0; i < vm->dc; i++) { + if (streq(vm->devices[i].type, type)) { + return &vm->devices[i]; } - return NULL; + } + return NULL; } /* Find all devices of a type */ -int find_devices_by_type(VM *vm, const char *type, Device **results, uint32_t max_results) { - uint32_t i, count = 0; - for (i = 0; i < vm->dc && count < max_results; i++) { - if (strcmp(vm->devices[i].type, type) == 0) { - results[count++] = &vm->devices[i]; - } +i32 find_devices_by_type(VM *vm, const char *type, Device **results, + u32 max_results) { + u32 i, count = 0; + for (i = 0; i < vm->dc && count < max_results; i++) { + if (streq(vm->devices[i].type, type)) { + results[count++] = &vm->devices[i]; } - return count; + } + return count; } diff --git a/src/device.h b/src/device.h index 882694c..c6634be 100644 --- a/src/device.h +++ b/src/device.h @@ -3,9 +3,9 @@ #include "opcodes.h" -int vm_register_device(VM *vm, const char *path, const char *type, void *data, DeviceOps *ops); +i32 vm_register_device(VM *vm, const char *path, const char *type, void *data, DeviceOps *ops); Device* find_device_by_path(VM *vm, const char *path); Device* find_device_by_type(VM *vm, const char *type); -int find_devices_by_type(VM *vm, const char *type, Device **results, uint32_t max_results); +i32 find_devices_by_type(VM *vm, const char *type, Device **results, uint32_t max_results); #endif \ No newline at end of file diff --git a/src/gen/build.sh b/src/gen/build.sh new file mode 100644 index 0000000..bdf5a10 --- /dev/null +++ b/src/gen/build.sh @@ -0,0 +1,2 @@ +gcc math_gen.c -o math_gen -lm +./math_gen > ../math.h \ No newline at end of file diff --git a/src/gen/math_gen.c b/src/gen/math_gen.c new file mode 100644 index 0000000..089d78c --- /dev/null +++ b/src/gen/math_gen.c @@ -0,0 +1,31 @@ +#include +#include +#include + +int main() { + printf("#ifndef ZRE_TRIG_TABLES_H\n#define ZRE_TRIG_TABLES_H\n#include \n\n"); + + // Generate SINE table (256 entries, Q16.16 format) + printf("const int32_t sin_table[256] = {\n"); + for (int i = 0; i < 256; i++) { + double angle = i * 2 * M_PI / 256.0; // 0-360° in radians + double value = sin(angle) * 65536.0; // Scale to Q16.16 + int32_t fixed = (int32_t)(value + 0.5); // Round to nearest + printf(" %d,", fixed); + if (i % 8 == 7) printf("\n"); + } + printf("};\n\n"); + + // Generate COSINE table (256 entries, Q16.16 format) + printf("const int32_t cos_table[256] = {\n"); + for (int i = 0; i < 256; i++) { + double angle = i * 2 * M_PI / 256.0; // 0-360° in radians + double value = cos(angle) * 65536.0; // Scale to Q16.16 + int32_t fixed = (int32_t)(value + 0.5); // Round to nearest + printf(" %d,", fixed); + if (i % 8 == 7) printf("\n"); + } + printf("};\n"); + printf("#endif\n"); + return 0; +} \ No newline at end of file diff --git a/src/opcodes.h b/src/opcodes.h index 2915301..c76aec5 100644 --- a/src/opcodes.h +++ b/src/opcodes.h @@ -2,27 +2,18 @@ #define ZRE_OPCODES_H #include "common.h" -#include typedef enum { - OP_HALT, /* halt : terminate execution */ - OP_JMP, /* jump : jump to address dest unconditionally */ - OP_GET_PC, /* pc : dest = current program counter */ - OP_CALL, /* call : creates a new frame */ - OP_RETURN, /* retn : returns from a frame to the parent frame */ - OP_LOAD, /* load : dest = &[next memory location] */ - OP_STORE, /* stor : next memory location = src1 as float */ + OP_HALT, /* halt : terminate execution */ + OP_JMP, /* jump : jump to address dest unconditionally */ + OP_CALL, /* call : creates a new frame */ + OP_RETURN, /* retn : returns from a frame to the parent frame */ + OP_LOAD, /* load : dest = &[next memory location] */ + OP_LOAD_IMM, /* load : dest = &[next memory location] */ + OP_STORE, /* stor : next memory location = src1 as float */ OP_PUSH, /* push : push str ref from register onto the stack and copy str */ OP_POP, /* pop : pop int from stack onto the register */ OP_REG_MOV, /* rmov : dest = src1 */ - OP_REG_SWAP, /* rswp : dest = src1, src1 = dest */ - OP_GET_ACC, /* gacc : dest = accumulator */ - OP_MEM_SWAP, /* mswp : &dest = &src1, &src1 = &dest */ - OP_MEM_MOV, /* mmov : &dest = &src1 */ - OP_MEM_ALLOC, /* aloc : dest [next memory location as size] */ - OP_GET, /* get : dest = ptr : dest = memory[ptr] */ - OP_PUT, /* put : ptr = src1 : memory[ptr] = src */ - OP_OFFSET, /* offs : dest = ptr + src1 : dest = p + o */ OP_SYSCALL, /* sysc : */ OP_ADD_INT, /* addi : dest = src1 + src2 */ OP_SUB_INT, /* subi : dest = src1 - src2 */ @@ -58,36 +49,17 @@ typedef enum { OP_INT_TO_STRING, /* itos : dest = src1 as str */ OP_UINT_TO_STRING, /* utos : dest = src1 as str */ OP_REAL_TO_STRING, /* rtos : dest = src1 as str */ - OP_CMP_STRING, /* cmps : dest = (str == src2) as bool */ OP_STRING_TO_INT, /* stoi : dest = src1 as int */ OP_STRING_TO_UINT, /* stou : dest = src1 as uint */ - OP_STRING_TO_REAL, /* stor : dest = src1 as real */ - /* to remove (replace with device), just for testing for now */ - OP_DBG_PRINT_STRING, /* puts : write a string to stdout */ - OP_DBG_READ_STRING, /* gets : read a string from stdin */ + OP_STRING_TO_REAL /* stor : dest = src1 as real */ } Opcode; -/* defines a uint32 opcode */ -#define OP(opcode, dest, src1, src2) \ - ((opcode << 24) | (dest << 16) | (src1 << 8) | (src2)) - -typedef union value_u { - int32_t i; /* Integers */ - float f; /* Float */ - uint32_t u; /* Unsigned integers, also used for pointer address */ - char c[4]; /* 4 Byte char array for string packing */ -} Value; - -typedef struct slice_s { - uint32_t start; - uint32_t end; -} Slice; - #define MAX_REGS 32 typedef struct frame_s { - Value registers[MAX_REGS]; /* R0-R31 */ - uint32_t rp; /* register pointer (last unused) */ - Slice allocated; /* start and end of global allocated block */ + u32 registers[MAX_REGS]; /* R0-R31 */ + u32 rp; /* register pointer (last unused) */ + u32 start; /* start and end of global allocated block */ + u32 end; } Frame; typedef enum { @@ -96,16 +68,15 @@ typedef enum { SYSCALL_DEVICE_READ, SYSCALL_DEVICE_WRITE, SYSCALL_DEVICE_CLOSE, - SYSCALL_DEVICE_IOCTL, + SYSCALL_DEVICE_IOCTL } SyscallID; typedef struct device_ops_s { - int (*open)(void *device_data, uint32_t mode); - int (*read)(void *device_data, uint8_t *buffer, uint32_t size); - int (*write)(void *device_data, const uint8_t *buffer, uint32_t size); - int (*close)(void *device_data); - int (*ioctl)(void *device_data, uint32_t cmd, - void *args); /* optional control */ + i32 (*open)(void *device_data, u32 mode); + i32 (*read)(void *device_data, u8 *buffer, u32 size); + i32 (*write)(void *device_data, const u8 *buffer, u32 size); + i32 (*close)(void *device_data); + i32 (*ioctl)(void *device_data, u32 cmd, void *args); /* optional control */ } DeviceOps; #define DEVICE_TYPE_MAX_LENGTH 24 /* 23 chars + null terminator */ @@ -117,7 +88,7 @@ typedef struct device_s { etc. */ void *data; /* device-specific data */ DeviceOps *ops; /* operations vtable */ - uint32_t flags; /* permissions, status, etc. */ + u32 flags; /* permissions, status, etc. */ } Device; #define MEMORY_SIZE (640 * 480 + 65536) @@ -126,20 +97,61 @@ typedef struct device_s { #define STACK_SIZE 256 #define DEVICES_SIZE 8 typedef struct vm_s { - uint32_t pc; /* program counter */ - uint32_t cp; /* code pointer (last allocated opcode) */ - uint32_t fp; /* frame pointer (current frame) */ - uint32_t sp; /* stack pointer (top of stack) */ - uint32_t rp; /* return stack pointer (top of stack) */ - uint32_t mp; /* memory pointer (last allocated value) */ - uint32_t dc; /* device count */ - uint32_t acc; /* accumulator (temporary results like SYSCALL status) */ - Device devices[DEVICES_SIZE]; /* device definitions */ - Frame frames[FRAMES_SIZE]; /* function call frames */ - Value stack[STACK_SIZE]; /* main stack */ - Value return_stack[STACK_SIZE]; /* return stack (for call recursion) */ - Value code[CODE_SIZE]; /* code block */ - Value memory[MEMORY_SIZE]; /* memory block */ + u32 pc; /* program counter */ + u32 cp; /* code pointer (last allocated opcode) */ + u32 fp; /* frame pointer (current frame) */ + u32 sp; /* stack pointer (top of stack) */ + u32 rp; /* return stack pointer (top of stack) */ + u32 mp; /* memory pointer (last allocated value) */ + u32 dc; /* device count */ + u32 acc; /* accumulator (temporary results like SYSCALL status) */ + Frame frames[FRAMES_SIZE]; /* function call frames */ + u32 stack[STACK_SIZE]; /* main stack */ + u32 return_stack[STACK_SIZE]; /* return stack (for call recursion) */ + Device devices[DEVICES_SIZE]; /* device definitions */ + u8 code[CODE_SIZE]; /* code block */ + u8 memory[MEMORY_SIZE]; /* memory block */ } VM; +#define AS_INT(v) ((i32)(v)) +#define AS_UINT(v) ((u32)(v)) +#define AS_FIXED(v) ((float)(i32)(v) / 65536.0f) +#define TO_FIXED(f) ((u32)((i32)( \ + ((f) >= 0.0f) ? ((f) * 65536.0f + 0.5f) : ((f) * 65536.0f - 0.5f) \ +))) + +#define read_u8(vm, location, addr) ((vm)->location[addr]) +#define read_u16(vm, location, addr) \ + (((uint16_t)(vm)->location[(addr)] << 8) | \ + ((uint16_t)(vm)->location[(addr) + 1])) +#define read_u32(vm, location, addr) \ + (((u32)(vm)->location[(addr)] << 24) | \ + ((u32)(vm)->location[(addr) + 1] << 16) | \ + ((u32)(vm)->location[(addr) + 2] << 8) | ((u32)(vm)->location[(addr) + 3])) + +#define write_u8(vm, location, addr, value) \ + do { \ + if ((addr) < sizeof((vm)->location)) { \ + (vm)->location[(addr)] = (value); \ + } \ + } while (0) + +#define write_u16(vm, location, addr, value) \ + do { \ + if ((addr) + 1 < sizeof((vm)->location)) { \ + (vm)->location[(addr)] = ((value) >> 8) & 0xFF; \ + (vm)->location[(addr) + 1] = (value) & 0xFF; \ + } \ + } while (0) + +#define write_u32(vm, location, addr, value) \ + do { \ + if ((addr) + 3 < sizeof((vm)->location)) { \ + (vm)->location[(addr)] = ((value) >> 24) & 0xFF; \ + (vm)->location[(addr) + 1] = ((value) >> 16) & 0xFF; \ + (vm)->location[(addr) + 2] = ((value) >> 8) & 0xFF; \ + (vm)->location[(addr) + 3] = (value) & 0xFF; \ + } \ + } while (0) + #endif diff --git a/src/str.c b/src/str.c new file mode 100644 index 0000000..8db4401 --- /dev/null +++ b/src/str.c @@ -0,0 +1,44 @@ +#include "str.h" + +i32 strcopy(char *to, const char *from, u32 length) { + u32 i; + if (to == nil || from == nil) return -1; + if (length == 0) {return 0;} + for (i = 0; i < length - 1 && from[i] != '\0'; i++) { + to[i] = from[i]; + } + to[i] = '\0'; + return 0; +} + +bool streq(const char *s1, const char *s2) { + if (s1 == nil && s2 == nil) return true; + if (s1 == nil || s2 == nil) return false; + + while (*s1 && *s2) { + if (*s1 != *s2) return false; + s1++; + s2++; + } + + return (*s1 == '\0' && *s2 == '\0'); +} + + +u32 strlen(const char *str) { + u32 i; + if (str == nil) {return 0;} + for (i = 0; str[i] != '\0'; i++) { + ; /* twiddle thumbs, 'i' is doing all the work*/ + } + return i; +} + +u32 strnlen(const char *str, u32 max_len) { + u32 i; + if (str == nil) {return 0;} + for (i = 0; i < max_len && str[i] != '\0'; i++) { + ; /* twiddle thumbs, 'i' is doing all the work*/ + } + return i; +} \ No newline at end of file diff --git a/src/str.h b/src/str.h new file mode 100644 index 0000000..2756702 --- /dev/null +++ b/src/str.h @@ -0,0 +1,10 @@ +#ifndef ZRE_STR_H +#define ZRE_STR_H + +#include "common.h" + +i32 strcopy(char* to, const char *from, u32 length); +u32 strlen(const char* str); +bool streq(const char *s1, const char *s2); + +#endif diff --git a/src/test.c b/src/test.c index c86028e..1694e91 100644 --- a/src/test.c +++ b/src/test.c @@ -1,194 +1,135 @@ #include "test.h" +#include "opcodes.h" +#include "str.h" #include "vm.h" -#include -uint32_t real_alloc(VM *vm, float v) { - uint32_t addr = vm->mp; - vm->memory[vm->mp++].f = v; - vm->frames[vm->fp].allocated.end++; +u32 real_alloc(VM *vm, float v) { + i32 fixed = TO_FIXED(v); + u32 addr = vm->mp; + write_u32(vm, memory, vm->mp, fixed); + vm->mp += 4; + vm->frames[vm->fp].end += 4; return addr; } -uint32_t nat_alloc(VM *vm, uint32_t v) { - uint32_t addr = vm->mp; - vm->memory[vm->mp++].u = v; - vm->frames[vm->fp].allocated.end++; +u32 nat_alloc(VM *vm, u32 v) { + u32 addr = vm->mp; + write_u32(vm, memory, vm->mp, v); + vm->mp += 4; + vm->frames[vm->fp].end += 4; return addr; } -uint32_t int_alloc(VM *vm, int32_t v) { - uint32_t addr = vm->mp; - vm->memory[vm->mp++].i = v; - vm->frames[vm->fp].allocated.end++; +u32 int_alloc(VM *vm, i32 v) { + u32 addr = vm->mp; + write_u32(vm, memory, vm->mp, v); + vm->mp += 4; + vm->frames[vm->fp].end += 4; return addr; } /* Array of test mappings */ struct TestMapping internal_tests[] = { {"simple.ul", test_simple_compile}, - {"loop.ul", test_loop_compile}, - {"add.ul", test_add_function_compile}, - {"fib.ul", test_recursive_function_compile}, {"window.ul", test_window_click_compile}, - /* Add more test mappings here */ - {NULL, NULL} /* Sentinel to mark end of array */ + {NULL, NULL} /* Sentinel to mark end of array */ }; -bool compile_internal_test(const char* filename, VM* vm) { - int i; - for (i = 0; internal_tests[i].filename != NULL; i++) { - if (strcmp(internal_tests[i].filename, filename) == 0) { - return internal_tests[i].test_func(vm); - } +bool compile_internal_test(const char *filename, VM *vm) { + i32 i; + for (i = 0; internal_tests[i].filename != NULL; i++) { + if (streq(internal_tests[i].filename, filename)) { + return internal_tests[i].test_func(vm); } - return false; + } + return false; } bool test_simple_compile(VM *vm) { - vm->code[vm->cp++].u = OP(OP_LOAD, 0, 0, 0); - vm->code[vm->cp++].u = nat_alloc(vm, 1); - vm->code[vm->cp++].u = OP(OP_LOAD, 1, 0, 0); - vm->code[vm->cp++].u = nat_alloc(vm, 2); - vm->code[vm->cp++].u = OP(OP_ADD_UINT, 2, 1, 0); /* let sum = 1 + 2; */ - vm->code[vm->cp++].u = OP(OP_UINT_TO_STRING, 3, 2, 0); - vm->code[vm->cp++].u = OP(OP_DBG_PRINT_STRING, 0, 3, 0); /* print(sum.toS()); */ - vm->code[vm->cp++].u = OP(OP_HALT, 0, 0, 0); /* explicit halt */ - return true; -} + u32 ptr; + u32 terminal_path_addr = str_alloc(vm, "/dev/term/0", 12); + vm->code[vm->cp++] = OP_LOAD; + vm->code[vm->cp++] = 0; + ptr = real_alloc(vm, 1.0f); + write_u32(vm, code, vm->cp, ptr); vm->cp+=4; -bool test_loop_compile(VM *vm) { - vm->code[vm->cp++].u = OP(OP_LOAD, 0, 0, 0); /* let a = 5.0 */ - vm->code[vm->cp++].u = real_alloc(vm, 5.0f); - vm->code[vm->cp++].u = OP(OP_LOAD, 1, 0, 0); /* do (i = 50000, 0, -1) { */ - vm->code[vm->cp++].u = int_alloc(vm, 10000); - vm->code[vm->cp++].u = OP(OP_LOAD, 2, 0, 0); /* loop check value */ - vm->code[vm->cp++].u = int_alloc(vm, 0); - vm->code[vm->cp++].u = OP(OP_LOAD, 3, 0, 0); /* loop incriment value */ - vm->code[vm->cp++].u = int_alloc(vm, -1); - vm->code[vm->cp++].u = OP(OP_LOAD, 5, 0, 0); /* a */ - vm->code[vm->cp++].u = real_alloc(vm, 5.0f); - vm->code[vm->cp++].u = OP(OP_LOAD, 4, 0, 0); /* loop start */ - uint32_t addr = vm->cp + 1; - vm->code[vm->cp++].u = int_alloc(vm, addr); - vm->code[vm->cp++].u = OP(OP_ADD_REAL, 0, 0, 5); /* a += 5.0; */ - vm->code[vm->cp++].u = OP(OP_ADD_INT, 1, 1, 3); /* (implied by loop) i = i + (-1) */ - vm->code[vm->cp++].u = OP(OP_JGE_INT, 4, 1, 2); /* } */ - vm->code[vm->cp++].u = OP(OP_REAL_TO_UINT, 1, 0, 0); /* let b = a as nat; */ - vm->code[vm->cp++].u = OP(OP_LOAD, 6, 0, 0); - uint32_t str_addr = str_alloc(vm, "Enter a string:", 16); - vm->code[vm->cp++].u = nat_alloc(vm, str_addr); - vm->code[vm->cp++].u = OP(OP_DBG_PRINT_STRING, 0, 6, 0); /* print("Enter a string: "); */ - vm->code[vm->cp++].u = OP(OP_DBG_READ_STRING, 2, 0, 0); /* let user_string = gets(); */ - vm->code[vm->cp++].u = OP(OP_UINT_TO_STRING, 3, 1, 0); - vm->code[vm->cp++].u = OP(OP_DBG_PRINT_STRING, 0, 3, 0); /* print(a.toS()); */ - vm->code[vm->cp++].u = OP(OP_REAL_TO_STRING, 3, 0, 0); - vm->code[vm->cp++].u = OP(OP_DBG_PRINT_STRING, 0, 3, 0); /* print(b.toS()); */ - vm->code[vm->cp++].u = OP(OP_DBG_PRINT_STRING, 0, 2, 0); /* print(user_string); */ - vm->code[vm->cp++].u = OP(OP_HALT, 0, 0, 0); /* program done */ - return true; -} + vm->code[vm->cp++] = OP_LOAD; + vm->code[vm->cp++] = 1; + ptr = real_alloc(vm, 2.0f); + write_u32(vm, code, vm->cp, ptr); vm->cp+=4; -bool test_add_function_compile(VM *vm) { - /* fn main() */ - vm->code[vm->cp++].u = OP(OP_LOAD, 0, 0, 0); /* 1 */ - vm->code[vm->cp++].u = int_alloc(vm, 1); - vm->code[vm->cp++].u = OP(OP_PUSH, 0, 0, 0); - vm->code[vm->cp++].u = OP(OP_LOAD, 0, 0, 0); /* 1 */ - vm->code[vm->cp++].u = int_alloc(vm, 1); - vm->code[vm->cp++].u = OP(OP_PUSH, 0, 0, 0); - vm->code[vm->cp++].u = OP(OP_CALL, 0, 0, 0); /* ); */ - vm->code[vm->cp++].u = 12; - vm->code[vm->cp++].u = OP(OP_POP, 0, 0, 0); /* get return value */ - vm->code[vm->cp++].u = OP(OP_INT_TO_STRING, 1, 0, 0); - vm->code[vm->cp++].u = OP(OP_DBG_PRINT_STRING, 0, 1, 0); /* print(sum.toS()); */ - vm->code[vm->cp++].u = OP(OP_HALT, 0, 0, 0); - /* fn add() */ - vm->code[vm->cp++].u = OP(OP_POP, 0, 0, 0); /* a int */ - vm->code[vm->cp++].u = OP(OP_POP, 1, 0, 0); /* b int */ - vm->code[vm->cp++].u = OP(OP_ADD_INT, 2, 1, 0); /* a + b */ - vm->code[vm->cp++].u = OP(OP_PUSH, 2, 0, 0); /* push on stack */ - vm->code[vm->cp++].u = OP(OP_RETURN, 0, 0, 0); - return true; -} + vm->code[vm->cp++] = OP_ADD_UINT; + vm->code[vm->cp++] = 2; + vm->code[vm->cp++] = 1; + vm->code[vm->cp++] = 0; /* let sum = 1 + 2; */ -bool test_recursive_function_compile(VM *vm) { - /* fn main() */ - vm->code[vm->cp++].u = OP(OP_LOAD, 0, 0, 0); /* 35 */ - vm->code[vm->cp++].u = int_alloc(vm, 35); - vm->code[vm->cp++].u = OP(OP_PUSH, 0, 0, 0); - vm->code[vm->cp++].u = OP(OP_CALL, 0, 0, 0); /* ); */ - vm->code[vm->cp++].u = 9; - vm->code[vm->cp++].u = OP(OP_POP, 0, 0, 0); /* get return value */ - vm->code[vm->cp++].u = OP(OP_INT_TO_STRING, 1, 0, 0); - vm->code[vm->cp++].u = OP(OP_DBG_PRINT_STRING, 0, 1, 0); /* print(fib(35).toS()); */ - vm->code[vm->cp++].u = OP(OP_HALT, 0, 0, 0); - /* fn fib() */ - vm->code[vm->cp++].u = OP(OP_POP, 0, 0, 0); /* n int */ - vm->code[vm->cp++].u = OP(OP_LOAD, 1, 0, 0); /* 2 */ - vm->code[vm->cp++].u = int_alloc(vm, 2); - vm->code[vm->cp++].u = OP(OP_LOAD, 2, 0, 0); /* &fib */ - vm->code[vm->cp++].u = int_alloc(vm, 32); - vm->code[vm->cp++].u = OP(OP_JLT_INT, 2, 0, 1); - vm->code[vm->cp++].u = OP(OP_LOAD, 3, 0, 0); /* 2 */ - vm->code[vm->cp++].u = int_alloc(vm, 2); - vm->code[vm->cp++].u = OP(OP_SUB_INT, 4, 0, 3); - vm->code[vm->cp++].u = OP(OP_PUSH, 4, 0, 0); - vm->code[vm->cp++].u = OP(OP_CALL, 0, 0, 0); /* fib(n - 2) */ - vm->code[vm->cp++].u = 9; - vm->code[vm->cp++].u = OP(OP_LOAD, 3, 0, 0); /* 1 */ - vm->code[vm->cp++].u = int_alloc(vm, 1); - vm->code[vm->cp++].u = OP(OP_SUB_INT, 4, 0, 3); - vm->code[vm->cp++].u = OP(OP_PUSH, 4, 0, 0); - vm->code[vm->cp++].u = OP(OP_CALL, 0, 0, 0); /* fib(n - 1) */ - vm->code[vm->cp++].u = 9; - vm->code[vm->cp++].u = OP(OP_POP, 4, 0, 0); - vm->code[vm->cp++].u = OP(OP_POP, 5, 0, 0); - vm->code[vm->cp++].u = OP(OP_ADD_INT, 6, 5, 4); - vm->code[vm->cp++].u = OP(OP_PUSH, 6, 0, 0); - vm->code[vm->cp++].u = OP(OP_RETURN, 0, 0, 0); - vm->code[vm->cp++].u = OP(OP_PUSH, 0, 0, 0); - vm->code[vm->cp++].u = OP(OP_RETURN, 0, 0, 0); + vm->code[vm->cp++] = OP_REAL_TO_STRING; + vm->code[vm->cp++] = 4; + vm->code[vm->cp++] = 2; + + vm->code[vm->cp++] = OP_LOAD_IMM; + vm->code[vm->cp++] = 3; + write_u32(vm, code, vm->cp, terminal_path_addr); vm->cp+=4; + + vm->code[vm->cp++] = OP_SYSCALL; + write_u32(vm, code, vm->cp, AS_UINT(SYSCALL_DEVICE_WRITE)); vm->cp+=4; + write_u32(vm, code, vm->cp, AS_UINT(2)); vm->cp+=4; + vm->code[vm->cp++] = 3; + /* syscall_id=WRITE, arg_count=2, start_reg=3 ; print(sum.toS()); */ + vm->code[vm->cp++] = OP_HALT; /* explicit halt */ return true; } bool test_window_click_compile(VM *vm) { - uint32_t screen_path_addr = str_alloc(vm, "/dev/screen/0", 14); - /*uint32_t mouse_path_addr = str_alloc(vm, "/dev/mouse/0", 12);*/ - - /* Open screen device: R0=path, R1=mode */ - vm->code[vm->cp++].u = OP(OP_LOAD, 0, 0, 0); /* R0 = screen path */ - vm->code[vm->cp++].u = nat_alloc(vm, screen_path_addr); - vm->code[vm->cp++].u = OP(OP_LOAD, 1, 0, 0); /* R1 = mode (0) */ - vm->code[vm->cp++].u = int_alloc(vm, 0); - vm->code[vm->cp++].u = OP(OP_SYSCALL, SYSCALL_DEVICE_OPEN, 0, 2); /* syscall_id, first_reg=0, arg_count=2 */ - - /* Check if open succeeded (result in vm->acc) */ - vm->code[vm->cp++].u = OP(OP_GET_ACC, 2, 0, 0); /* Move result to R2 */ - - /* Create simple test pixel data */ - uint32_t test_pixel_addr = vm->mp; - vm->memory[vm->mp].c[0] = (char)((255 / 32) << 5) | ((0 / 32) << 2) | (0 / 64); - vm->memory[vm->mp].c[1] = (char)((255 / 32) << 5) | ((0 / 32) << 2) | (0 / 64); - vm->memory[vm->mp].c[2] = (char)((255 / 32) << 5) | ((0 / 32) << 2) | (0 / 64); - vm->memory[vm->mp++].c[3] = (char)((255 / 32) << 5) | ((0 / 32) << 2) | (0 / 64); - vm->frames[vm->fp].allocated.end++; + u32 test_pixel_addr, loop_start, screen_path_addr = str_alloc(vm, "/dev/screen/0", 14); - /* Main loop to check for mouse input */ - uint32_t loop_start = vm->cp; + vm->code[vm->cp++] = OP_LOAD; /* R0 = screen path */ + vm->code[vm->cp++] = 0; + vm->code[vm->cp++] = nat_alloc(vm, screen_path_addr); - /* Write to screen: R0=path, R1=buffer, R2=size */ - vm->code[vm->cp++].u = OP(OP_LOAD, 0, 0, 0); - vm->code[vm->cp++].u = nat_alloc(vm, screen_path_addr); - vm->code[vm->cp++].u = OP(OP_LOAD, 1, 0, 0); - vm->code[vm->cp++].u = nat_alloc(vm, test_pixel_addr); - vm->code[vm->cp++].u = OP(OP_LOAD, 2, 0, 0); - vm->code[vm->cp++].u = int_alloc(vm, 1); - vm->code[vm->cp++].u = OP(OP_SYSCALL, SYSCALL_DEVICE_WRITE, 0, 3); /* syscall_id, first_reg=0, arg_count=3 */ + vm->code[vm->cp++] = OP_LOAD; /* R1 = mode (0) */ + vm->code[vm->cp++] = 1; + vm->code[vm->cp++] = int_alloc(vm, 0); - vm->code[vm->cp++].u = OP(OP_LOAD, 3, 0, 0); - vm->code[vm->cp++].u = nat_alloc(vm, loop_start); - vm->code[vm->cp++].u = OP(OP_JMP, 3, 0, 0); /* Infinite loop for testing */ - vm->code[vm->cp++].u = OP(OP_HALT, 0, 0, 0); - - return true; + vm->code[vm->cp++] = OP_SYSCALL; + vm->code[vm->cp++] = SYSCALL_DEVICE_OPEN; + vm->code[vm->cp++] = 0; /* first_reg */ + vm->code[vm->cp++] = 2; /* arg_count */ + + test_pixel_addr = vm->mp; + vm->memory[vm->mp++] = (char)((255 / 32) << 5) | ((0 / 32) << 2) | (0 / 64); + vm->memory[vm->mp++] = (char)((255 / 32) << 5) | ((0 / 32) << 2) | (0 / 64); + vm->memory[vm->mp++] = (char)((255 / 32) << 5) | ((0 / 32) << 2) | (0 / 64); + vm->memory[vm->mp++] = (char)((255 / 32) << 5) | ((0 / 32) << 2) | (0 / 64); + vm->frames[vm->fp].end += 4; + + loop_start = vm->cp; + + vm->code[vm->cp++] = OP_LOAD; + vm->code[vm->cp++] = 0; + vm->code[vm->cp++] = nat_alloc(vm, screen_path_addr); + + vm->code[vm->cp++] = OP_LOAD; + vm->code[vm->cp++] = 1; + vm->code[vm->cp++] = nat_alloc(vm, test_pixel_addr); + + vm->code[vm->cp++] = OP_LOAD; + vm->code[vm->cp++] = 2; + vm->code[vm->cp++] = int_alloc(vm, 1); + + vm->code[vm->cp++] = OP_SYSCALL; + vm->code[vm->cp++] = SYSCALL_DEVICE_WRITE; + vm->code[vm->cp++] = 0; /* first_reg */ + vm->code[vm->cp++] = 3; /* arg_count */ + + vm->code[vm->cp++] = OP_LOAD; + vm->code[vm->cp++] = 3; + vm->code[vm->cp++] = nat_alloc(vm, loop_start); + + vm->code[vm->cp++] = OP_JMP; + vm->code[vm->cp++] = 3; + + vm->code[vm->cp++] = OP_HALT; + + return true; } \ No newline at end of file diff --git a/src/vm.c b/src/vm.c index a70ccae..92e73ce 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1,56 +1,50 @@ #include "vm.h" #include "device.h" #include "opcodes.h" -#include +#include "str.h" /* no inline fn in ANSI C :( */ -#define COMPARE_AND_JUMP(type, accessor, op) \ +#define COMPARE_AND_JUMP(type, op) \ do { \ - type value = vm->frames[vm->fp].registers[src1].accessor; \ - type value2 = vm->frames[vm->fp].registers[src2].accessor; \ - vm->pc = \ - (value op value2) ? vm->frames[vm->fp].registers[dest].u : vm->pc; \ + type value, value2; \ + dest = read_u8(vm, code, vm->pc); \ + vm->pc++; \ + src1 = read_u8(vm, code, vm->pc); \ + vm->pc++; \ + src2 = read_u8(vm, code, vm->pc); \ + vm->pc++; \ + value = vm->frames[vm->fp].registers[src1]; \ + value2 = vm->frames[vm->fp].registers[src2]; \ + vm->pc = (value op value2) ? vm->frames[vm->fp].registers[dest] : vm->pc; \ return true; \ } while (0) -#define MATH_OP(accessor, op) \ +#define MATH_OP(type, op) \ do { \ - vm->frames[vm->fp].registers[dest].accessor = \ - vm->frames[vm->fp] \ - .registers[src1] \ - .accessor op vm->frames[vm->fp] \ - .registers[src2] \ - .accessor; \ + dest = read_u8(vm, code, vm->pc); \ + vm->pc++; \ + src1 = read_u8(vm, code, vm->pc); \ + vm->pc++; \ + src2 = read_u8(vm, code, vm->pc); \ + vm->pc++; \ + vm->frames[vm->fp].registers[dest] = (type)vm->frames[vm->fp] \ + .registers[src1] op(type) \ + vm->frames[vm->fp] \ + .registers[src2]; \ return true; \ } while (0) -/** - * Embeds a string into the VM - */ -uint32_t str_alloc(VM *vm, const char *str, uint32_t length) { - uint32_t str_addr = vm->mp++; - uint32_t temp = 0; - - while (temp < length) { - uint32_t idx = temp % 4; - vm->memory[vm->mp].c[idx] = str[temp]; - temp++; - - if (idx == 3) - vm->mp++; +u32 str_alloc(VM *vm, const char *str, u32 length) { + u32 str_addr = vm->mp; + u32 i = 0; + vm->mp += 4; + while (i < length) { + vm->memory[vm->mp++] = str[i++]; } + vm->memory[vm->mp++] = '\0'; - uint32_t i, rem = temp % 4; - if (rem != 0) { - for (i = rem; i < 4; i++) { - vm->memory[vm->mp].c[i] = '\0'; - } - vm->mp++; - } - - vm->memory[str_addr].u = length; - vm->frames[vm->fp].allocated.end = vm->mp; - + write_u32(vm, memory, str_addr, length); + vm->frames[vm->fp].end = vm->mp; return str_addr; } @@ -58,143 +52,112 @@ uint32_t str_alloc(VM *vm, const char *str, uint32_t length) { * Step to the next opcode in the vm. */ bool step_vm(VM *vm) { - /* Get current instruction & Advance to next instruction */ - uint32_t instruction = vm->code[vm->pc++].u; + u8 opcode, dest, src1, src2; + u32 v, ptr; + i32 value; - uint8_t opcode = (instruction >> 24) & 0xFF; - uint8_t dest = (instruction >> 16) & 0xFF; - uint8_t src1 = (instruction >> 8) & 0xFF; - uint8_t src2 = instruction & 0xFF; + /* Get current instruction & Advance to next instruction */ + opcode = vm->code[vm->pc++]; switch (opcode) { case OP_HALT: { return false; } case OP_CALL: { - uint32_t jmp = vm->code[vm->pc++].u; /* location of function in code */ - vm->return_stack[vm->rp++].u = vm->pc; /* set return address */ - vm->fp++; /* increment to the next free frame */ - vm->frames[vm->fp].allocated.start = - vm->mp; /* set start of new memory block */ + u32 jmp = read_u32(vm, code, vm->pc); /* location of function in code */ + vm->pc += 4; + vm->return_stack[vm->rp++] = vm->pc; /* set return address */ + vm->fp++; /* increment to the next free frame */ + vm->frames[vm->fp].start = vm->mp; /* set start of new memory block */ vm->pc = jmp; return true; } case OP_RETURN: { - vm->frames[vm->fp].rp = 0; /* reset register ptr */ - vm->pc = vm->return_stack[--vm->rp].u; /* set pc to return address */ + vm->frames[vm->fp].rp = 0; /* reset register ptr */ + vm->pc = vm->return_stack[--vm->rp]; /* set pc to return address */ vm->mp = - vm->frames[vm->fp--].allocated.start; /* reset memory pointer to start + vm->frames[vm->fp--].start; /* reset memory pointer to start of old slice, pop the frame */ return true; } + case OP_LOAD_IMM: { + dest = read_u8(vm, code, vm->pc); + vm->pc++; + v = read_u32(vm, code, vm->pc); + vm->pc += 4; + vm->frames[vm->fp].registers[dest] = v; + return true; + } case OP_LOAD: { - uint32_t ptr = vm->code[vm->pc++].u; - Value v = vm->memory[ptr]; + dest = read_u8(vm, code, vm->pc); + vm->pc++; + ptr = read_u32(vm, code, vm->pc); + vm->pc += 4; + v = read_u32(vm, memory, ptr); vm->frames[vm->fp].registers[dest] = v; return true; } case OP_STORE: { - uint32_t ptr = vm->code[vm->pc++].u; - vm->memory[ptr] = vm->frames[vm->fp].registers[src1]; - return true; - } - case OP_PUT: { - uint32_t addr = vm->frames[vm->fp].registers[dest].u; - vm->memory[addr] = vm->frames[vm->fp].registers[src1]; - return true; - } - case OP_GET: { - uint32_t addr = vm->frames[vm->fp].registers[src1].u; - vm->frames[vm->fp].registers[dest] = vm->memory[addr]; - return true; - } - case OP_OFFSET: { - uint32_t ptr = vm->frames[vm->fp].registers[src1].u; - uint32_t offset = vm->frames[vm->fp].registers[src2].u; - uint32_t result = ptr + offset; - vm->frames[vm->fp].registers[dest].u = result; + src1 = read_u8(vm, code, vm->pc); + vm->pc++; + ptr = read_u32(vm, code, vm->pc); + vm->pc += 4; + v = vm->frames[vm->fp].registers[src1]; + write_u32(vm, memory, ptr, v); return true; } case OP_PUSH: { + dest = read_u8(vm, code, vm->pc); + vm->pc++; vm->stack[++vm->sp] = vm->frames[vm->fp].registers[dest]; return true; } case OP_POP: { + dest = read_u8(vm, code, vm->pc); + vm->pc++; vm->frames[vm->fp].registers[dest] = vm->stack[vm->sp--]; return true; } - case OP_MEM_ALLOC: { - uint32_t mem_dest = (uint32_t)vm->frames[vm->fp] - .allocated.end; /* get start of unallocated */ - vm->frames[vm->fp].registers[dest].u = - mem_dest; /* store ptr of array to dest register */ - uint32_t size = (uint32_t)vm->frames[vm->fp].registers[src1].u; - vm->memory[mem_dest].u = size; - vm->frames[vm->fp].allocated.end += - size; /* increment to end of allocated */ - return true; - } - case OP_MEM_MOV: { - uint32_t dest_addr = (uint32_t)vm->frames[vm->fp].registers[dest].u; - uint32_t src_addr = (uint32_t)vm->frames[vm->fp].registers[src1].u; - vm->memory[dest_addr] = vm->memory[src_addr]; - return true; - } - case OP_MEM_SWAP: { - uint32_t dest_addr = (uint32_t)vm->frames[vm->fp].registers[dest].u; - uint32_t src_addr = (uint32_t)vm->frames[vm->fp].registers[src1].u; - vm->memory[dest_addr].u ^= vm->memory[src_addr].u; - vm->memory[src_addr].u ^= vm->memory[dest_addr].u; - vm->memory[dest_addr].u ^= vm->memory[src_addr].u; - return true; - } - case OP_REG_SWAP: { - vm->frames[vm->fp].registers[dest].u ^= - vm->frames[vm->fp].registers[src1].u; - vm->frames[vm->fp].registers[src1].u ^= - vm->frames[vm->fp].registers[dest].u; - vm->frames[vm->fp].registers[dest].u ^= - vm->frames[vm->fp].registers[src1].u; - return true; - } case OP_REG_MOV: { - vm->frames[vm->fp].registers[dest].i = vm->frames[vm->fp].registers[src1].i; - return true; - } - case OP_GET_ACC: { - vm->frames[vm->fp].registers[dest].u = vm->acc; - return true; - } - case OP_GET_PC: { - vm->frames[vm->fp].registers[dest].u = vm->pc; + dest = read_u8(vm, code, vm->pc); + vm->pc++; + src1 = read_u8(vm, code, vm->pc); + vm->pc++; + vm->frames[vm->fp].registers[dest] = vm->frames[vm->fp].registers[src1]; return true; } case OP_JMP: { - vm->pc = vm->frames[vm->fp].registers[dest].u; /* Jump to address */ + dest = read_u8(vm, code, vm->pc); + vm->pc++; + vm->pc = vm->frames[vm->fp].registers[dest]; /* Jump to address */ return true; - } + } case OP_SYSCALL: { - uint32_t syscall_id = dest; - uint32_t arg_count = src2; - uint32_t first_reg = src1; + u32 syscall_id, arg_count; + u8 first_reg; + + syscall_id = read_u32(vm, code, vm->pc); + vm->pc += 4; + arg_count = read_u32(vm, code, vm->pc); + vm->pc += 4; + first_reg = read_u8(vm, code, vm->pc); + vm->pc++; switch (syscall_id) { case SYSCALL_DEVICE_OPEN: { if (arg_count >= 2) { - uint32_t path_ptr = - vm->frames[vm->fp].registers[first_reg].u; /* R0: path pointer */ - uint32_t mode = - vm->frames[vm->fp].registers[first_reg + 1].u; /* R1: mode */ - /* uint32_t length = vm->memory[path_ptr].u; */ - uint32_t str_src = path_ptr + 1; - const char *path = (const char *)&vm->memory[str_src]; + Device *dev; + u32 path_ptr, mode, str_src; + path_ptr = + vm->frames[vm->fp].registers[first_reg]; /* R0: path pointer */ + mode = vm->frames[vm->fp].registers[first_reg + 1]; /* R1: mode */ + str_src = path_ptr + 1; - Device *dev = find_device_by_path(vm, path); + dev = find_device_by_path(vm, (const char *)&vm->memory[str_src]); if (dev) { if (dev->ops->open) { - int result = dev->ops->open(dev->data, mode); - vm->acc = result; + vm->acc = dev->ops->open(dev->data, mode); } else { vm->acc = 1; /* success, no open needed */ } @@ -209,23 +172,21 @@ bool step_vm(VM *vm) { case SYSCALL_DEVICE_READ: { if (arg_count >= 3) { - uint32_t path_ptr = - vm->frames[vm->fp].registers[first_reg].u; /* R0: path pointer */ - uint32_t buffer_ptr = vm->frames[vm->fp] - .registers[first_reg + 1] - .u; /* R1: buffer pointer */ - uint32_t size = - vm->frames[vm->fp].registers[first_reg + 2].u; /* R2: size */ - /* uint32_t length = vm->memory[path_ptr].u; */ - uint32_t str_src = path_ptr + 1; + Device *dev; + u32 path_ptr, buffer_ptr, size, str_src; - const char *path = (const char *)&vm->memory[str_src]; - Device *dev = find_device_by_path(vm, path); + path_ptr = + vm->frames[vm->fp].registers[first_reg]; /* R0: path pointer */ + buffer_ptr = vm->frames[vm->fp] + .registers[first_reg + 1]; /* R1: buffer pointer */ + size = vm->frames[vm->fp].registers[first_reg + 2]; /* R2: size */ + str_src = path_ptr + 1; + + dev = find_device_by_path(vm, (const char *)&vm->memory[str_src]); if (dev && dev->ops->read) { - int result = dev->ops->read(dev->data, - (uint8_t *)&vm->memory[buffer_ptr], size); - vm->acc = result; + vm->acc = + dev->ops->read(dev->data, (u8 *)&vm->memory[buffer_ptr], size); } else { vm->acc = 0; } @@ -236,24 +197,20 @@ bool step_vm(VM *vm) { } case SYSCALL_DEVICE_WRITE: { - if (arg_count >= 3) { - uint32_t path_ptr = - vm->frames[vm->fp].registers[first_reg].u; /* R0: path pointer */ - uint32_t buffer_ptr = vm->frames[vm->fp] - .registers[first_reg + 1] - .u; /* R1: buffer pointer */ - uint32_t size = - vm->frames[vm->fp].registers[first_reg + 2].u; /* R2: size */ - /* uint32_t length = vm->memory[path_ptr].u; */ - uint32_t str_src = path_ptr + 1; - - const char *path = (const char *)&vm->memory[str_src]; - Device *dev = find_device_by_path(vm, path); + if (arg_count >= 2) { + Device *dev; + u32 path_ptr, buffer_ptr, size, str_src; + path_ptr = + vm->frames[vm->fp].registers[first_reg]; /* R0: path pointer */ + buffer_ptr = vm->frames[vm->fp] + .registers[first_reg + 1]; /* R1: buffer pointer */ + size = read_u32(vm, memory, buffer_ptr); /* R2: size */ + str_src = path_ptr += 4; + dev = find_device_by_path(vm, (const char *)&vm->memory[str_src]); if (dev && dev->ops->write) { - int result = dev->ops->write( - dev->data, (const uint8_t *)&vm->memory[buffer_ptr], size); - vm->acc = result; + vm->acc = dev->ops->write(dev->data, + (const u8 *)&vm->memory[buffer_ptr], size); } else { vm->acc = 0; } @@ -265,16 +222,16 @@ bool step_vm(VM *vm) { case SYSCALL_DEVICE_CLOSE: { if (arg_count >= 1) { - uint32_t path_ptr = - vm->frames[vm->fp].registers[first_reg].u; /* R0: path pointer */ - /* uint32_t length = vm->memory[path_ptr].u; */ - uint32_t str_src = path_ptr + 1; + Device *dev; + u32 path_ptr, str_src; + path_ptr = + vm->frames[vm->fp].registers[first_reg]; /* R0: path pointer */ + str_src = path_ptr + 1; - const char *path = (const char *)&vm->memory[str_src]; - Device *dev = find_device_by_path(vm, path); + dev = find_device_by_path(vm, (const char *)&vm->memory[str_src]); if (dev && dev->ops->close) { - int result = dev->ops->close(dev->data); + i32 result = dev->ops->close(dev->data); vm->acc = result; } else { vm->acc = 0; @@ -287,22 +244,20 @@ bool step_vm(VM *vm) { case SYSCALL_DEVICE_IOCTL: { if (arg_count >= 3) { - uint32_t path_ptr = - vm->frames[vm->fp].registers[first_reg].u; /* R0: device path */ - uint32_t cmd = vm->frames[vm->fp] - .registers[first_reg + 1] - .u; /* R1: ioctl command */ - uint32_t args_ptr = vm->frames[vm->fp] - .registers[first_reg + 2] - .u; /* R2: args pointer */ - /* uint32_t length = vm->memory[path_ptr].u; */ - uint32_t str_src = path_ptr + 1; + Device *dev; + u32 path_ptr, args_ptr, cmd, str_src; + path_ptr = + vm->frames[vm->fp].registers[first_reg]; /* R0: device path */ + cmd = + vm->frames[vm->fp].registers[first_reg + 1]; /* R1: ioctl command */ + args_ptr = + vm->frames[vm->fp].registers[first_reg + 2]; /* R2: args pointer */ + str_src = path_ptr + 1; - const char *path = (const char *)&vm->memory[str_src]; - Device *dev = find_device_by_path(vm, path); + dev = find_device_by_path(vm, (const char *)&vm->memory[str_src]); if (dev && dev->ops && dev->ops->ioctl) { - int result = dev->ops->ioctl(dev->data, cmd, &vm->memory[args_ptr]); + i32 result = dev->ops->ioctl(dev->data, cmd, &vm->memory[args_ptr]); vm->acc = result; } else { vm->acc = 0; /* error or no ioctl support */ @@ -325,210 +280,309 @@ bool step_vm(VM *vm) { return true; } case OP_ADD_INT: - MATH_OP(i, +); + MATH_OP(i32, +); case OP_SUB_INT: - MATH_OP(i, -); + MATH_OP(i32, -); case OP_MUL_INT: - MATH_OP(i, *); + MATH_OP(i32, *); case OP_DIV_INT: - MATH_OP(i, /); + MATH_OP(i32, /); case OP_ADD_UINT: - MATH_OP(u, +); + MATH_OP(u32, +); case OP_SUB_UINT: - MATH_OP(u, -); + MATH_OP(u32, -); case OP_MUL_UINT: - MATH_OP(u, *); + MATH_OP(u32, *); case OP_DIV_UINT: - MATH_OP(u, /); - case OP_ADD_REAL: - MATH_OP(f, +); - case OP_SUB_REAL: - MATH_OP(f, -); - case OP_MUL_REAL: - MATH_OP(f, *); - case OP_DIV_REAL: - MATH_OP(f, /); + MATH_OP(u32, /); + case OP_MUL_REAL: { + dest = read_u8(vm, code, vm->pc); + vm->pc++; + src1 = read_u8(vm, code, vm->pc); + vm->pc++; + src2 = read_u8(vm, code, vm->pc); + vm->pc++; + vm->frames[vm->fp].registers[dest] = (vm->frames[vm->fp].registers[src1] * + vm->frames[vm->fp].registers[src2]) >> + 16; + return true; + } + + case OP_DIV_REAL: { + dest = read_u8(vm, code, vm->pc); + vm->pc++; + src1 = read_u8(vm, code, vm->pc); + vm->pc++; + src2 = read_u8(vm, code, vm->pc); + vm->pc++; + vm->frames[vm->fp].registers[dest] = + (vm->frames[vm->fp].registers[src1] << 16) / + vm->frames[vm->fp].registers[src2]; + return true; + } + + case OP_ADD_REAL: { + dest = read_u8(vm, code, vm->pc); + vm->pc++; + src1 = read_u8(vm, code, vm->pc); + vm->pc++; + src2 = read_u8(vm, code, vm->pc); + vm->pc++; + vm->frames[vm->fp].registers[dest] = + vm->frames[vm->fp].registers[src1] + vm->frames[vm->fp].registers[src2]; + return true; + } + + case OP_SUB_REAL: { + dest = read_u8(vm, code, vm->pc); + vm->pc++; + src1 = read_u8(vm, code, vm->pc); + vm->pc++; + src2 = read_u8(vm, code, vm->pc); + vm->pc++; + vm->frames[vm->fp].registers[dest] = + vm->frames[vm->fp].registers[src1] - vm->frames[vm->fp].registers[src2]; + return true; + } case OP_REAL_TO_INT: { - vm->frames[vm->fp].registers[dest].i = - (int32_t)(vm->frames[vm->fp].registers[src1].f); + dest = read_u8(vm, code, vm->pc); + vm->pc++; + src1 = read_u8(vm, code, vm->pc); + vm->pc++; + value = vm->frames[vm->fp].registers[src1]; + + if (value >= 0) { + vm->frames[vm->fp].registers[dest] = value >> 16; + } else { + vm->frames[vm->fp].registers[dest] = -((-value) >> 16); + } + return true; } case OP_INT_TO_REAL: { - vm->frames[vm->fp].registers[dest].f = - (float)(vm->frames[vm->fp].registers[src1].i); + dest = read_u8(vm, code, vm->pc); + vm->pc++; + src1 = read_u8(vm, code, vm->pc); + vm->pc++; + vm->frames[vm->fp].registers[dest] = + (vm->frames[vm->fp].registers[src1] << 16); return true; } case OP_REAL_TO_UINT: { - vm->frames[vm->fp].registers[dest].u = - (uint32_t)(vm->frames[vm->fp].registers[src1].f); + dest = read_u8(vm, code, vm->pc); + vm->pc++; + src1 = read_u8(vm, code, vm->pc); + vm->pc++; + value = vm->frames[vm->fp].registers[src1]; + if (value < 0) { + vm->frames[vm->fp].registers[dest] = 0; + } else { + vm->frames[vm->fp].registers[dest] = AS_UINT(value >> 16); + } return true; } case OP_UINT_TO_REAL: { - vm->frames[vm->fp].registers[dest].f = - (float)(vm->frames[vm->fp].registers[src1].u); + dest = read_u8(vm, code, vm->pc); + vm->pc++; + src1 = read_u8(vm, code, vm->pc); + vm->pc++; + vm->frames[vm->fp].registers[dest] = + AS_INT(vm->frames[vm->fp].registers[src1] << 16); return true; } case OP_JEQ_UINT: { - COMPARE_AND_JUMP(uint32_t, u, ==); + COMPARE_AND_JUMP(u32, ==); } case OP_JGT_UINT: { - COMPARE_AND_JUMP(uint32_t, u, >); + COMPARE_AND_JUMP(u32, >); } case OP_JLT_UINT: { - COMPARE_AND_JUMP(uint32_t, u, <); + COMPARE_AND_JUMP(u32, <); } case OP_JLE_UINT: { - COMPARE_AND_JUMP(uint32_t, u, <=); + COMPARE_AND_JUMP(u32, <=); } case OP_JGE_UINT: { - COMPARE_AND_JUMP(uint32_t, u, >=); + COMPARE_AND_JUMP(u32, >=); } case OP_JEQ_INT: { - COMPARE_AND_JUMP(int32_t, i, ==); + COMPARE_AND_JUMP(i32, ==); } case OP_JGT_INT: { - COMPARE_AND_JUMP(int32_t, i, >); + COMPARE_AND_JUMP(i32, >); } case OP_JLT_INT: { - COMPARE_AND_JUMP(int32_t, i, <); + COMPARE_AND_JUMP(i32, <); } case OP_JLE_INT: { - COMPARE_AND_JUMP(int32_t, i, <=); + COMPARE_AND_JUMP(i32, <=); } case OP_JGE_INT: { - COMPARE_AND_JUMP(int32_t, i, >=); + COMPARE_AND_JUMP(i32, >=); } case OP_JEQ_REAL: { - COMPARE_AND_JUMP(int32_t, i, ==); + COMPARE_AND_JUMP(i32, ==); } case OP_JGT_REAL: { - COMPARE_AND_JUMP(float, u, >); + COMPARE_AND_JUMP(i32, >); } case OP_JLT_REAL: { - COMPARE_AND_JUMP(float, u, <); + COMPARE_AND_JUMP(i32, <); } case OP_JGE_REAL: { - COMPARE_AND_JUMP(float, u, >=); + COMPARE_AND_JUMP(i32, >=); } case OP_JLE_REAL: { - COMPARE_AND_JUMP(float, u, <=); + COMPARE_AND_JUMP(i32, <=); } case OP_INT_TO_STRING: { - int32_t a = (int32_t)vm->frames[vm->fp].registers[src1].i; /* get value */ char buffer[32]; - int len = sprintf(buffer, "%d", a); - uint32_t ptr = str_alloc(vm, buffer, len); /* copy buffer to dest */ - vm->frames[vm->fp].registers[dest].u = ptr; + dest = read_u8(vm, code, vm->pc); + vm->pc++; + src1 = read_u8(vm, code, vm->pc); + vm->pc++; + int_to_string(AS_INT(vm->frames[vm->fp].registers[src1]), buffer); + ptr = str_alloc(vm, buffer, strlen(buffer)); + vm->frames[vm->fp].registers[dest] = ptr; return true; } case OP_UINT_TO_STRING: { - uint32_t a = (uint32_t)vm->frames[vm->fp].registers[src1].u; /* get value */ char buffer[32]; - int len = sprintf(buffer, "%d", a); - uint32_t ptr = str_alloc(vm, buffer, len); /* copy buffer to dest */ - vm->frames[vm->fp].registers[dest].u = ptr; + dest = read_u8(vm, code, vm->pc); + vm->pc++; + src1 = read_u8(vm, code, vm->pc); + vm->pc++; + uint_to_string(vm->frames[vm->fp].registers[src1], buffer); + ptr = str_alloc(vm, buffer, strlen(buffer)); + vm->frames[vm->fp].registers[dest] = ptr; return true; } case OP_REAL_TO_STRING: { - float a = (float)vm->frames[vm->fp].registers[src1].f; /* get value */ char buffer[32]; - int len = sprintf(buffer, "%f", a); - uint32_t ptr = str_alloc(vm, buffer, len); /* copy buffer to dest */ - vm->frames[vm->fp].registers[dest].u = ptr; + dest = read_u8(vm, code, vm->pc); + vm->pc++; + src1 = read_u8(vm, code, vm->pc); + vm->pc++; + fixed_to_string(AS_INT(vm->frames[vm->fp].registers[src1]), buffer); + ptr = str_alloc(vm, buffer, strlen(buffer)); /* copy buffer to dest */ + vm->frames[vm->fp].registers[dest] = ptr; return true; } case OP_STRING_TO_INT: { - uint32_t src_addr = (uint32_t)vm->frames[vm->fp].registers[src1].u; - uint32_t dest_addr = (uint32_t)vm->frames[vm->fp].registers[dest].u; - char *endptr; - int32_t value = (int32_t)strtol((char*)&vm->memory[src_addr + 1], &endptr, 10); - vm->memory[dest_addr].i = value; - return true; + /* not implemented yet */ + return false; } case OP_STRING_TO_UINT: { - uint32_t src_addr = (uint32_t)vm->frames[vm->fp].registers[src1].u; - uint32_t dest_addr = (uint32_t)vm->frames[vm->fp].registers[dest].u; - long value = atol((char*)&vm->memory[src_addr + 1]); - vm->memory[dest_addr].u = value; - return true; + /* not implemented yet */ + return false; } case OP_STRING_TO_REAL: { - uint32_t src_addr = (uint32_t)vm->frames[vm->fp].registers[src1].u; - uint32_t dest_addr = (uint32_t)vm->frames[vm->fp].registers[dest].u; - float value = atof((char*)&vm->memory[src_addr + 1]); - vm->memory[dest_addr].u = value; - return true; - } - case OP_DBG_READ_STRING: { - uint32_t str_addr = vm->mp++; - uint32_t length = 0; - int ch; - - while ((ch = getchar()) != '\n' && ch != EOF) { - uint32_t idx = length % 4; - vm->memory[vm->mp].c[idx] = (char)ch; - length++; - - if (idx == 3) - vm->mp++; - } - - uint32_t i, rem = length % 4; - if (rem != 0) { - for (i = rem; i < 4; i++) { - vm->memory[vm->mp].c[i] = '\0'; - } - vm->mp++; - } - - vm->memory[str_addr].u = length; - vm->frames[vm->fp].allocated.end = vm->mp; - vm->frames[vm->fp].registers[dest].u = str_addr; - - return true; - } - case OP_DBG_PRINT_STRING: { - uint32_t ptr = (uint32_t)vm->frames[vm->fp].registers[src1].u; - uint32_t length = vm->memory[ptr].u; - uint32_t str_src = ptr + 1; - uint32_t i; - for (i = 0; i < length; i++) { - uint8_t ch = vm->memory[str_src + (i / 4)].c[i % 4]; - if (ch == '\0') - break; - putchar(ch); - } - putchar('\n'); - return true; - } - case OP_CMP_STRING: { - uint32_t addr1 = (uint32_t)vm->frames[vm->fp].registers[src1].u; - uint32_t addr2 = (uint32_t)vm->frames[vm->fp].registers[src2].u; - uint32_t length1 = vm->memory[addr1 - 1].u; - uint32_t length2 = vm->memory[addr2 - 1].u; - uint32_t equal = - 1; /* we dont have a native boolean type so we use uint32_t */ - - if (length1 != length2) { - equal = 0; - } else { - uint32_t i = 0; - while (i < length1) { - uint32_t char1 = vm->memory[addr1 + i].u; - uint32_t char2 = vm->memory[addr2 + i].u; - if (char1 != char2) { - equal = 0; - break; - } - if ((char1 & 0xFF) == '\0' && (char2 & 0xFF) == '\0') { - equal = 1; - break; - } - } - } - vm->memory[dest].u = equal; - return true; + /* not implemented yet */ + return false; } } return false; /* something bad happened */ } + +/* Static digit lookup table (0-9) */ +const char digits[10] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; + +/* Writes decimal digits of 'value' backwards into 'buf_end' (inclusive), + stopping at 'buf_start'. Returns pointer to first written digit. */ +char *write_digits_backwards(u32 value, char *buf_end, char *buf_start) { + char *p = buf_end; + if (value == 0) { + *--p = '0'; + } else { + u32 num = value; + while (num && p > buf_start) { + *--p = digits[num % 10]; + num /= 10; + } + } + return p; +} + +void uint_to_string(u32 value, char *buffer) { + char temp[16]; + char *start; + char *end = temp + sizeof(temp) - 1; + *end = '\0'; + start = write_digits_backwards(value, end, temp); + strcopy(buffer, start, end - start + 1); /* +1 for null terminator */ +} + +void int_to_string(i32 value, char *buffer) { + char temp[17]; /* Extra space for '-' */ + i32 negative = 0; + u32 abs_value; + char *end = temp + sizeof(temp) - 1; + *end = '\0'; + + if (value == (-2147483647 - 1)) { /* INT32_MIN */ + strcopy(buffer, "-2147483648", 12); + return; + } + + if (value == 0) { + *--end = '0'; + } else { + if (value < 0) { + negative = 1; + abs_value = (u32)(-value); + } else { + abs_value = (u32)value; + } + + end = write_digits_backwards(abs_value, end, temp); + + if (negative) { + *--end = '-'; + } + } + + strcopy(buffer, end, temp + sizeof(temp) - end); +} + +void fixed_to_string(i32 value, char *buffer) { + char temp[32]; + i32 negative; + u32 int_part; + u32 frac_part, frac_digits; + char *end = temp + sizeof(temp) - 1; + *end = '\0'; + + negative = 0; + if (value < 0) { + negative = 1; + value = -value; + } + + int_part = AS_UINT(value >> 16); + frac_part = AS_UINT(value & 0xFFFF); + + /* Convert fractional part to 5 decimal digits */ + frac_digits = (frac_part * 100000U) / 65536U; + + /* Trim trailing zeros */ + while (frac_digits > 0 && frac_digits % 10 == 0) { + frac_digits /= 10; + } + + if (frac_digits > 0) { + end = write_digits_backwards(frac_digits, end, temp); + *--end = '.'; + } + + if (int_part == 0 && frac_digits == 0) { + *--end = '0'; + } else { + end = write_digits_backwards(int_part, end, temp); + } + + if (negative) { + *--end = '-'; + } + + strcopy(buffer, end, temp + sizeof(temp) - end); +} diff --git a/src/vm.h b/src/vm.h index 6e96586..0e3dade 100644 --- a/src/vm.h +++ b/src/vm.h @@ -4,6 +4,9 @@ #include "opcodes.h" bool step_vm(VM *vm); -uint32_t str_alloc(VM *vm, const char *str, uint32_t length); +u32 str_alloc(VM *vm, const char *str, u32 length); +void fixed_to_string(i32 value, char *buffer); +void int_to_string(i32 value, char *buffer); +void uint_to_string(u32 value, char *buffer); #endif diff --git a/test/loop.asm b/test/loop.asm index f76753a..9868b76 100644 --- a/test/loop.asm +++ b/test/loop.asm @@ -1,6 +1,6 @@ main: lodr $0 5.0 - lodi $1 50000 + lodi $1 5000 lodi $2 0 lodi $3 -1 loop_body: