From aea1dba6a2dc8c7421b96ab3bc93a67bc461b4a6 Mon Sep 17 00:00:00 2001 From: zongor Date: Sun, 5 Oct 2025 22:54:34 -0700 Subject: [PATCH] Add wasm example, add paint example, ad neq opcodes, fix load/save VM, --- Makefile | 27 ++- src/arch/emscripten/devices.c | 308 ++++++++++++++++++++++++++ src/arch/emscripten/devices.h | 56 +++++ src/arch/emscripten/main.c | 112 +++++++++- src/arch/linux/devices.c | 142 ++++++------ src/arch/linux/devices.h | 3 +- src/arch/linux/main.c | 17 +- src/tools/assembler.c | 29 ++- src/vm/opcodes.h | 13 +- src/vm/vm.c | 9 + test/add.rom | Bin 0 -> 136 bytes test/fib.rom | Bin 0 -> 180 bytes test/hello.rom | Bin 0 -> 89 bytes test/loop.rom | Bin 0 -> 229 bytes test/paint-bw.asm.lisp | 226 +++++++++++++++++++ test/paint-bw.rom | Bin 0 -> 685 bytes test/{box.asm.lisp => paint.asm.lisp} | 4 +- test/paint.rom | Bin 0 -> 1344 bytes test/simple.rom | Bin 0 -> 126 bytes test/window.asm.lisp | 4 + test/window.rom | Bin 0 -> 353 bytes 21 files changed, 849 insertions(+), 101 deletions(-) create mode 100644 src/arch/emscripten/devices.c create mode 100644 src/arch/emscripten/devices.h create mode 100644 test/add.rom create mode 100644 test/fib.rom create mode 100644 test/hello.rom create mode 100644 test/loop.rom create mode 100644 test/paint-bw.asm.lisp create mode 100644 test/paint-bw.rom rename test/{box.asm.lisp => paint.asm.lisp} (98%) create mode 100644 test/paint.rom create mode 100644 test/simple.rom create mode 100644 test/window.rom diff --git a/Makefile b/Makefile index e54a567..b2d6058 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,16 @@ else CC ?= gcc endif +ifeq ($(PLATFORM), emscripten) +# --- SHARED FLAGS --- +BASE_CFLAGS := -I$(SRC_DIR) + +# --- CORE-SPECIFIC FLAGS (freestanding, no stdlib) --- +CORE_CFLAGS := $(BASE_CFLAGS) + +# --- PLATFORM-SPECIFIC FLAGS --- +PLATFORM_CFLAGS := $(BASE_CFLAGS) +else # --- SHARED FLAGS --- BASE_CFLAGS := -I$(SRC_DIR) -Wall -Wextra -Werror -pedantic @@ -22,6 +32,7 @@ CORE_CFLAGS := $(BASE_CFLAGS) -std=c89 -ffreestanding -nostdlib -fno-builtin # --- PLATFORM-SPECIFIC FLAGS --- PLATFORM_CFLAGS := $(BASE_CFLAGS) +endif # --- MODE & PLATFORM SPECIFIC FLAGS --- ifeq ($(BUILD_MODE), release) @@ -44,19 +55,15 @@ 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 + LDFLAGS += -s USE_SDL=2 -s WASM=1 \ + -s MAX_WEBGL_VERSION=2 \ + --preload-file test/window.rom@paint.rom \ + -s INITIAL_MEMORY=16MB # For release: optimize, strip debug, minimize size ifeq ($(BUILD_MODE), release) - PLATFORM_CFLAGS += -O2 - LDFLAGS += -O2 --closure 1 - else - # For debug: preserve names, generate source maps - PLATFORM_CFLAGS += -gsource-map - LDFLAGS += -gsource-map --source-map-base . + PLATFORM_CFLAGS += -O2 -flto + LDFLAGS += -O2 -flto endif # Output: HTML + JS + WASM diff --git a/src/arch/emscripten/devices.c b/src/arch/emscripten/devices.c new file mode 100644 index 0000000..844ed0e --- /dev/null +++ b/src/arch/emscripten/devices.c @@ -0,0 +1,308 @@ +#include "devices.h" +#include +#include +#include +#include + + +i32 console_open(void *data, u32 mode) { + USED(mode); + USED(data); + return 0; +} + +i32 console_read(void *data, u8 *buffer, u32 size) { + USED(data); + for (u32 i = 0; i < size; i++) { + u8 ch = getchar(); + if (ch == '\0' || ch == '\n') break; + buffer[i] = ch; + } + return 0; +} + +i32 console_write(void *data, const u8 *buffer, u32 size) { + USED(data); + for (u32 i = 0; i < size; i++) { + putchar(buffer[i]); + } + return 0; +} + +i32 console_close(void *data) { + USED(data); + return 0; +} + +i32 console_ioctl(void *data, u32 cmd, const u8 *buffer) { + USED(data); + USED(cmd); + USED(buffer); + return -1; +} + +i32 screen_open(void *data, u32 mode) { + USED(mode); + ScreenDeviceData *screen = (ScreenDeviceData *)data; + + // Initialize with proper values + screen->width = 640; + screen->height = 480; + screen->size = 640 * 480; + screen->window = NULL; + screen->renderer = NULL; + screen->texture = NULL; + + #ifdef __EMSCRIPTEN__ + emscripten_set_canvas_element_size("#canvas", screen->width, screen->height); + #endif + + screen->window = SDL_CreateWindow( + "Reality Engine VM", + SDL_WINDOWPOS_CENTERED, + SDL_WINDOWPOS_CENTERED, + screen->width, + screen->height, + SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI + ); + + if (!screen->window) { + fprintf(stderr, "Failed to create SDL window: %s\n", SDL_GetError()); + return -1; + } + + // Create renderer with hardware acceleration + screen->renderer = SDL_CreateRenderer( + screen->window, -1, + SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC + ); + + if (!screen->renderer) { + fprintf(stderr, "Failed to create SDL renderer: %s\n", SDL_GetError()); + return -1; + } + + // Create the texture with RGB332 format + screen->texture = SDL_CreateTexture( + screen->renderer, + SDL_PIXELFORMAT_RGB332, + SDL_TEXTUREACCESS_STREAMING, + screen->width, + screen->height + ); + + if (!screen->texture) { + // If RGB332 isn't supported, try RGB888 + screen->texture = SDL_CreateTexture( + screen->renderer, + SDL_PIXELFORMAT_RGB888, + SDL_TEXTUREACCESS_STREAMING, + screen->width, + screen->height + ); + + if (!screen->texture) { + fprintf(stderr, "Failed to create SDL texture: %s\n", SDL_GetError()); + return -1; + } + printf("Using RGB888 format (conversion needed)\n"); + } else { + printf("Using direct RGB332 format\n"); + } + + return 0; +} + +i32 screen_write(void *data, const u8 *buffer, u32 size) { + ScreenDeviceData *screen = (ScreenDeviceData *)data; + + if (size > screen->size) { + printf("Screen write size mismatch: %d > %d\n", size, screen->size); + return -1; + } + + // Update texture with new frame data + SDL_UpdateTexture(screen->texture, NULL, buffer, screen->width); + + // Clear and render + SDL_RenderClear(screen->renderer); + + SDL_Rect output_rect; + SDL_RenderGetViewport(screen->renderer, &output_rect); + + // Calculate aspect ratio preserving scaling + float scale_x = (float)output_rect.w / screen->width; + float scale_y = (float)output_rect.h / screen->height; + float scale = SDL_min(scale_x, scale_y); + + SDL_Rect dstrect = { + (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); + + return 0; +} + +i32 screen_close(void *data) { + ScreenDeviceData *screen = (ScreenDeviceData *)data; + + if (screen->texture) { + SDL_DestroyTexture(screen->texture); + screen->texture = NULL; + } + + if (screen->renderer) { + SDL_DestroyRenderer(screen->renderer); + screen->renderer = NULL; + } + + if (screen->window) { + SDL_DestroyWindow(screen->window); + screen->window = NULL; + } + + return 0; +} + +i32 screen_read(void *data, u8 *buffer, u32 size) { + USED(data); + USED(buffer); + USED(size); + return -1; +} + +i32 screen_ioctl(void *data, u32 cmd, const u8 *buffer) { + ScreenDeviceData *screen = (ScreenDeviceData *)data; + + switch (cmd) { + case IOCTL_GET_INFO: { + u8 *info = (u8 *)buffer; + u32 size; + memcpy(&size, &info[0], sizeof(u32)); + + if (size < 16) { + return -1; + } + + memcpy(&info[4], &screen->pos, sizeof(u32)); + memcpy(&info[8], &screen->size, sizeof(u32)); + memcpy(&info[12], &screen->width, sizeof(u32)); + memcpy(&info[16], &screen->height, sizeof(u32)); + return 0; + } + default: + return -1; + } +} + +i32 mouse_open(void *data, u32 mode) { + USED(mode); + return 0; +} + +i32 mouse_read(void *data, u8 *buffer, u32 size) { + MouseDeviceData *mouse_data = (MouseDeviceData *)data; + + if (size < 12) return -1; + + SDL_PumpEvents(); + SDL_Event event; + while (SDL_PollEvent(&event)) { + switch (event.type) { + // Mouse events + case SDL_MOUSEMOTION: + mouse_data->x = event.motion.x; + mouse_data->y = event.motion.y; + break; + + case SDL_MOUSEBUTTONDOWN: + if (event.button.button == SDL_BUTTON_LEFT) mouse_data->btn1 = 1; + if (event.button.button == SDL_BUTTON_RIGHT) mouse_data->btn2 = 1; + if (event.button.button == SDL_BUTTON_MIDDLE) mouse_data->btn3 = 1; + if (event.button.button == SDL_BUTTON_X1) mouse_data->btn4 = 1; + break; + + case SDL_MOUSEBUTTONUP: + if (event.button.button == SDL_BUTTON_LEFT) mouse_data->btn1 = 0; + if (event.button.button == SDL_BUTTON_RIGHT) mouse_data->btn2 = 0; + if (event.button.button == SDL_BUTTON_MIDDLE) mouse_data->btn3 = 0; + if (event.button.button == SDL_BUTTON_X1) mouse_data->btn4 = 0; + break; + + // Touch events (map to mouse_data as left-click equivalent) + case SDL_FINGERMOTION: + case SDL_FINGERDOWN: + case SDL_FINGERUP: { + + float x = event.tfinger.x * 640; + float y = event.tfinger.y * 480; + + mouse_data->x = (int)x; + mouse_data->y = (int)y; + + // Only treat the first finger as mouse input (ignore multi-touch beyond 1 finger) + if (event.tfinger.fingerId == 0) { + if (event.type == SDL_FINGERDOWN || event.type == SDL_FINGERMOTION) { + mouse_data->btn1 = 1; + } else if (event.type == SDL_FINGERUP) { + mouse_data->btn1 = 0; + } + } + break; + } + } + } + + u8 *info = (u8 *)buffer; + memcpy(&info[0], &mouse_data->x, sizeof(u32)); + memcpy(&info[4], &mouse_data->y, sizeof(u32)); + memcpy(&info[8], &mouse_data->btn1, sizeof(u8)); + memcpy(&info[9], &mouse_data->btn2, sizeof(u8)); + memcpy(&info[10], &mouse_data->btn3, sizeof(u8)); + memcpy(&info[11], &mouse_data->btn4, sizeof(u8)); + return 0; +} + +i32 mouse_write(void *data, const u8 *buffer, u32 size) { + USED(data); + USED(buffer); + USED(size); + return -1; +} + +i32 mouse_close(void *data) { + USED(data); + return 0; +} + +i32 keyboard_open(void *data, u32 mode) { + USED(data); + USED(mode); + return 0; +} + +i32 keyboard_read(void *data, u8 *buffer, u32 size) { + KeyboardDeviceData *kbd = (KeyboardDeviceData *)data; + + if (size < (u32)kbd->key_count) return -1; + + memcpy(buffer, kbd->keys, kbd->key_count); + return 0; +} + +i32 keyboard_write(void *data, const u8 *buffer, u32 size) { + USED(data); + USED(buffer); + USED(size); + return -1; +} + +i32 keyboard_close(void *data) { + USED(data); + return 0; +} \ No newline at end of file diff --git a/src/arch/emscripten/devices.h b/src/arch/emscripten/devices.h new file mode 100644 index 0000000..64308b3 --- /dev/null +++ b/src/arch/emscripten/devices.h @@ -0,0 +1,56 @@ +#include "../../vm/vm.h" +#include + +#define IOCTL_GET_INFO 0x01 + +typedef struct screen_device_data_s { + u32 width; + u32 height; + u32 pos; + u32 size; + SDL_Window *window; + SDL_Renderer *renderer; + SDL_Texture *texture; +} ScreenDeviceData; + +/* Mouse device data */ +typedef struct mouse_device_data_s { + u32 x; + u32 y; + u8 btn1; + u8 btn2; + u8 btn3; + u8 btn4; + u32 pos; + u32 size; +} MouseDeviceData; + +/* Keyboard device data */ +typedef struct keyboard_device_data_s { + const u8 *keys; + i32 key_count; + u32 pos; + u32 size; +} KeyboardDeviceData; + +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); +i32 screen_ioctl(void *data, u32 cmd, const u8 *buffer); + +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); + +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, const u8 *buffer); \ No newline at end of file diff --git a/src/arch/emscripten/main.c b/src/arch/emscripten/main.c index f5e2bb9..4f97ee9 100644 --- a/src/arch/emscripten/main.c +++ b/src/arch/emscripten/main.c @@ -1,18 +1,118 @@ -#include "../../test.h" -#include "../../vm.h" +#include "../../vm/vm.h" +#include "../../vm/device.h" +#include "devices.h" +#include #include +#include +#include VM vm = {0}; +static DeviceOps screen_ops = {.open = screen_open, + .read = screen_read, + .write = screen_write, + .close = screen_close, + .ioctl = screen_ioctl}; + +static DeviceOps mouse_ops = {.open = mouse_open, + .read = mouse_read, + .write = mouse_write, + .close = mouse_close, + .ioctl = nil}; + +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}; + void mainloop() { if (!step_vm(&vm)) { - emscripten_cancel_main_loop(); /* this should "kill" the app. */ + emscripten_cancel_main_loop(); + printf("VM execution completed\n"); } } +bool loadVM(const char *filename, VM *vm) { + FILE *file = fopen(filename, "rb"); + if (!file) { + printf("Failed to open ROM file: %s\n", filename); + return false; + } + + // Read VM state + if (fread(&vm->pc, sizeof(u32), 1, file) != 1 || + fread(&vm->cp, sizeof(u32), 1, file) != 1 || + fread(&vm->fp, sizeof(u32), 1, file) != 1 || + fread(&vm->sp, sizeof(u32), 1, file) != 1 || + fread(&vm->rp, sizeof(u32), 1, file) != 1 || + fread(&vm->mp, sizeof(u32), 1, file) != 1 || + fread(&vm->dc, sizeof(u32), 1, file) != 1 || + fread(&vm->flag, sizeof(i32), 1, file) != 1) { + printf("Failed to read VM state\n"); + fclose(file); + return false; + } + + // Read code section + if (fread(vm->code, 1, vm->cp, file) != vm->cp) { + printf("Failed to read code section\n"); + fclose(file); + return false; + } + + // Read memory section + if (fread(vm->memory, 1, vm->mp, file) != vm->mp) { + printf("Failed to read memory section\n"); + fclose(file); + return false; + } + + fclose(file); + return true; +} + int main(int argc, char **argv) { - test_add_function_compile(vm.memory); - /* test_recursive_function_compile(vm.memory); */ + if (SDL_Init(SDL_INIT_VIDEO) < 0) { + printf("SDL initialization failed: %s\n", SDL_GetError()); + return 1; + } + SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0"); + + #ifdef __EMSCRIPTEN__ + emscripten_set_canvas_element_size("#canvas", 640, 480); + #endif + + loadVM("paint.rom", &vm); + printf("VM loaded successfully\n"); + + // Initialize device data + screen_data.width = 640; + screen_data.height = 480; + screen_data.size = 640 * 480; + screen_data.window = NULL; + screen_data.renderer = NULL; + screen_data.texture = NULL; + + mouse_data.x = 0; + mouse_data.y = 0; + mouse_data.btn1 = 0; + mouse_data.btn2 = 0; + mouse_data.btn3 = 0; + mouse_data.btn4 = 0; + mouse_data.size = 12; + + // Register devices + vm_register_device(&vm, "/dev/screen/0", "screen", &screen_data, &screen_ops); + vm_register_device(&vm, "/dev/mouse/0", "mouse", &mouse_data, &mouse_ops); + vm_register_device(&vm, "/dev/term/0", "terminal", NULL, &console_device_ops); + + // Set up main loop emscripten_set_main_loop(mainloop, 0, 1); return 0; -} +} \ No newline at end of file diff --git a/src/arch/linux/devices.c b/src/arch/linux/devices.c index 8e9e7d0..1c0eb6f 100644 --- a/src/arch/linux/devices.c +++ b/src/arch/linux/devices.c @@ -1,4 +1,5 @@ #include "devices.h" +#include #include #include @@ -55,17 +56,6 @@ i32 screen_open(void *data, u32 mode) { if (!screen->window) return -1; - screen->renderer = SDL_CreateRenderer( - screen->window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); - if (!screen->renderer) - return -1; - - screen->texture = SDL_CreateTexture(screen->renderer, SDL_PIXELFORMAT_RGB332, - SDL_TEXTUREACCESS_STREAMING, - screen->width, screen->height); - if (!screen->texture) - return -1; - SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); return 0; } @@ -84,41 +74,36 @@ i32 screen_write(void *data, const u8 *buffer, u32 size) { return -1; } - if (screen->texture && screen->renderer) { - SDL_UpdateTexture(screen->texture, nil, buffer, - screen->width); + if (!screen->surface && screen->window) { + const u8 *pixel_buffer = buffer; + int pitch = screen->width; // bytes per row - SDL_RenderClear(screen->renderer); + screen->surface = SDL_CreateRGBSurfaceFrom((void *)pixel_buffer, + screen->width, screen->height, + 8, // bits per pixel + pitch, + 0xE0, // R mask (RGB332) + 0x1C, // G mask + 0x03, // B mask + 0x00 // no alpha + ); - SDL_Rect output_rect; - SDL_RenderGetViewport(screen->renderer, &output_rect); - float scale_x = (float)output_rect.w / screen->width; - float scale_y = (float)output_rect.h / screen->height; - float scale = SDL_min(scale_x, scale_y); - - SDL_Rect dstrect = {(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, nil, &dstrect); - SDL_RenderPresent(screen->renderer); + if (!screen->surface) { + fprintf(stderr, "SDL_CreateRGBSurfaceFrom failed: %s\n", SDL_GetError()); + return -1; + } } + SDL_BlitScaled(screen->surface, NULL, + SDL_GetWindowSurface(screen->window), NULL); + SDL_UpdateWindowSurface(screen->window); + return 0; } i32 screen_close(void *data) { ScreenDeviceData *screen = (ScreenDeviceData *)data; - if (screen->texture) { - SDL_DestroyTexture(screen->texture); - screen->texture = NULL; - } - if (screen->renderer) { - SDL_DestroyRenderer(screen->renderer); - screen->renderer = NULL; - } if (screen->window) { SDL_DestroyWindow(screen->window); screen->window = NULL; @@ -138,7 +123,7 @@ i32 screen_ioctl(void *data, u32 cmd, const u8 *buffer) { if (size < 16) { return -1; } - + memcpy(&info[4], &screen->pos, sizeof(u32)); memcpy(&info[8], &screen->size, sizeof(u32)); memcpy(&info[12], &screen->width, sizeof(u32)); @@ -159,7 +144,7 @@ i32 mouse_open(void *data, u32 mode) { } i32 mouse_read(void *data, u8 *buffer, u32 size) { - MouseDeviceData *mouse = (MouseDeviceData *)data; + MouseDeviceData *mouse_data = (MouseDeviceData *)data; if (size < 12) return -1; @@ -167,41 +152,58 @@ i32 mouse_read(void *data, u8 *buffer, u32 size) { SDL_PumpEvents(); SDL_Event event; while (SDL_PollEvent(&event)) { - switch (event.type) { - case SDL_MOUSEMOTION: - mouse->x = event.motion.x; - mouse->y = event.motion.y; - break; - case SDL_MOUSEBUTTONDOWN: - if (event.button.button == SDL_BUTTON_LEFT) - mouse->btn1 = 1; - if (event.button.button == SDL_BUTTON_RIGHT) - mouse->btn2 = 1; - if (event.button.button == SDL_BUTTON_MIDDLE) - mouse->btn3 = 1; - if (event.button.button == SDL_BUTTON_X1) - mouse->btn4 = 1; - break; - case SDL_MOUSEBUTTONUP: - if (event.button.button == SDL_BUTTON_LEFT) - mouse->btn1 = 0; - if (event.button.button == SDL_BUTTON_RIGHT) - mouse->btn2 = 0; - if (event.button.button == SDL_BUTTON_MIDDLE) - mouse->btn3 = 0; - if (event.button.button == SDL_BUTTON_X1) - mouse->btn4 = 0; - break; - } + switch (event.type) { + // Mouse events + case SDL_MOUSEMOTION: + mouse_data->x = event.motion.x; + mouse_data->y = event.motion.y; + break; + + case SDL_MOUSEBUTTONDOWN: + if (event.button.button == SDL_BUTTON_LEFT) mouse_data->btn1 = 1; + if (event.button.button == SDL_BUTTON_RIGHT) mouse_data->btn2 = 1; + if (event.button.button == SDL_BUTTON_MIDDLE) mouse_data->btn3 = 1; + if (event.button.button == SDL_BUTTON_X1) mouse_data->btn4 = 1; + break; + + case SDL_MOUSEBUTTONUP: + if (event.button.button == SDL_BUTTON_LEFT) mouse_data->btn1 = 0; + if (event.button.button == SDL_BUTTON_RIGHT) mouse_data->btn2 = 0; + if (event.button.button == SDL_BUTTON_MIDDLE) mouse_data->btn3 = 0; + if (event.button.button == SDL_BUTTON_X1) mouse_data->btn4 = 0; + break; + + // Touch events (map to mouse_data as left-click equivalent) + case SDL_FINGERMOTION: + case SDL_FINGERDOWN: + case SDL_FINGERUP: { + + float x = event.tfinger.x * 640; + float y = event.tfinger.y * 480; + + mouse_data->x = (int)x; + mouse_data->y = (int)y; + + // Only treat the first finger as mouse input (ignore multi-touch beyond 1 finger) + if (event.tfinger.fingerId == 0) { + if (event.type == SDL_FINGERDOWN || event.type == SDL_FINGERMOTION) { + mouse_data->btn1 = 1; + } else if (event.type == SDL_FINGERUP) { + mouse_data->btn1 = 0; + } + } + break; + } + } } u8 *info = (u8 *)buffer; - memcpy(&info[0], &mouse->x, sizeof(u32)); - memcpy(&info[4], &mouse->y, sizeof(u32)); - memcpy(&info[8], &mouse->btn1, sizeof(u8)); - memcpy(&info[9], &mouse->btn2, sizeof(u8)); - memcpy(&info[10], &mouse->btn3, sizeof(u8)); - memcpy(&info[11], &mouse->btn4, sizeof(u8)); + memcpy(&info[0], &mouse_data->x, sizeof(u32)); + memcpy(&info[4], &mouse_data->y, sizeof(u32)); + memcpy(&info[8], &mouse_data->btn1, sizeof(u8)); + memcpy(&info[9], &mouse_data->btn2, sizeof(u8)); + memcpy(&info[10], &mouse_data->btn3, sizeof(u8)); + memcpy(&info[11], &mouse_data->btn4, sizeof(u8)); return 0; } diff --git a/src/arch/linux/devices.h b/src/arch/linux/devices.h index 6c00fcb..8cd9910 100644 --- a/src/arch/linux/devices.h +++ b/src/arch/linux/devices.h @@ -11,8 +11,7 @@ typedef struct screen_device_data_s { u32 pos; u32 size; SDL_Window *window; - SDL_Renderer *renderer; - SDL_Texture *texture; + SDL_Surface *surface; } ScreenDeviceData; /* Mouse device data */ diff --git a/src/arch/linux/main.c b/src/arch/linux/main.c index b61dc56..a4cdd1c 100644 --- a/src/arch/linux/main.c +++ b/src/arch/linux/main.c @@ -62,14 +62,14 @@ bool saveVM(const char *filename, VM *vm) { return false; } // Write code section - if (fwrite(vm->code, 1, CODE_SIZE, file) != CODE_SIZE) { + if (fwrite(vm->code, 1, vm->cp, file) != vm->cp) { fprintf(stderr, "Failed to write code section\n"); fclose(file); return false; } // Write memory section - if (fwrite(vm->memory, 1, MEMORY_SIZE, file) != MEMORY_SIZE) { + if (fwrite(vm->memory, 1, vm->mp, file) != vm->mp) { fprintf(stderr, "Failed to write memory section\n"); fclose(file); return false; @@ -102,14 +102,14 @@ bool loadVM(const char *filename, VM *vm) { } // Read code section - if (fread(vm->code, 1, CODE_SIZE, file) != CODE_SIZE) { + if (fread(vm->code, 1, vm->cp, file) != vm->cp) { fprintf(stderr, "Failed to read code section\n"); fclose(file); return false; } // Read memory section - if (fread(vm->memory, 1, MEMORY_SIZE, file) != MEMORY_SIZE) { + if (fread(vm->memory, 1, vm->mp, file) != vm->mp) { fprintf(stderr, "Failed to read memory section\n"); fclose(file); return false; @@ -411,18 +411,23 @@ i32 main(i32 argc, char *argv[]) { vm_register_device(&vm, "/dev/term/0", "terminal", nil, &console_device_ops); if (gui_mode) { + if (SDL_Init(SDL_INIT_VIDEO) < 0) { + printf("SDL initialization failed: %s\n", SDL_GetError()); + return 1; + } register_sdl_devices(&vm); + SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0"); while (running) { #ifdef ASM_DEBUG - printf("| %s %d\n", opcode_to_string(vm.code[vm.pc]),vm.pc); + printf("| %s %d\n", opcode_to_string(vm.code[vm.pc]), vm.pc); #endif running = step_vm(&vm); } } else { while (running) { #ifdef ASM_DEBUG - printf("| %s %d\n", opcode_to_string(vm.code[vm.pc]),vm.pc); + printf("| %s %d\n", opcode_to_string(vm.code[vm.pc]), vm.pc); #endif running = step_vm(&vm); } diff --git a/src/tools/assembler.c b/src/tools/assembler.c index 1950d93..1e3fff5 100644 --- a/src/tools/assembler.c +++ b/src/tools/assembler.c @@ -122,16 +122,19 @@ int get_instruction_byte_size(ExprNode *node) { // jump compare (7 bytes: 1 + 4 + 1 + 1) if (strcmp(opname, "jump-eq-int") == 0 || + strcmp(opname, "jump-neq-int") == 0 || strcmp(opname, "jump-gt-int") == 0 || strcmp(opname, "jump-lt-int") == 0 || strcmp(opname, "jump-le-int") == 0 || strcmp(opname, "jump-ge-int") == 0 || strcmp(opname, "jump-eq-nat") == 0 || + strcmp(opname, "jump-neq-nat") == 0 || strcmp(opname, "jump-gt-nat") == 0 || strcmp(opname, "jump-lt-nat") == 0 || strcmp(opname, "jump-le-nat") == 0 || strcmp(opname, "jump-ge-nat") == 0 || strcmp(opname, "jump-eq-real") == 0 || + strcmp(opname, "jump-neq-real") == 0 || strcmp(opname, "jump-gt-real") == 0 || strcmp(opname, "jump-lt-real") == 0 || strcmp(opname, "jump-le-real") == 0 || @@ -708,7 +711,7 @@ void process_code_expr(VM *vm, SymbolTable *table, ExprNode *node) { int dest = parse_register(node->children[0]->token); int src = parse_register(node->children[1]->token); emit_byte(vm, dest); - emit_byte(vm, src); + emit_byte(vm, src); } else if (strcmp(opname, "jump-eq-int") == 0) { emit_opcode(vm, OP_JEQ_INT); u32 addr = resolve_symbol(table, node->children[0]->token); @@ -717,6 +720,14 @@ void process_code_expr(VM *vm, SymbolTable *table, ExprNode *node) { emit_u32(vm, addr); emit_byte(vm, src1); emit_byte(vm, src2); + } else if (strcmp(opname, "jump-neq-int") == 0 ) { + emit_opcode(vm, OP_JNEQ_INT); + u32 addr = resolve_symbol(table, node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_u32(vm, addr); + emit_byte(vm, src1); + emit_byte(vm, src2); } else if (strcmp(opname, "jump-gt-int") == 0) { emit_opcode(vm, OP_JGT_INT); u32 addr = resolve_symbol(table, node->children[0]->token); @@ -757,6 +768,14 @@ void process_code_expr(VM *vm, SymbolTable *table, ExprNode *node) { emit_u32(vm, addr); emit_byte(vm, src1); emit_byte(vm, src2); + } else if (strcmp(opname, "jump-neq-nat") == 0 ) { + emit_opcode(vm, OP_JNEQ_UINT); + u32 addr = resolve_symbol(table, node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_u32(vm, addr); + emit_byte(vm, src1); + emit_byte(vm, src2); } else if (strcmp(opname, "jump-gt-nat") == 0) { emit_opcode(vm, OP_JGT_UINT); u32 addr = resolve_symbol(table, node->children[0]->token); @@ -797,6 +816,14 @@ void process_code_expr(VM *vm, SymbolTable *table, ExprNode *node) { emit_u32(vm, addr); emit_byte(vm, src1); emit_byte(vm, src2); + } else if (strcmp(opname, "jump-neq-real") == 0 ) { + emit_opcode(vm, OP_JNEQ_REAL); + u32 addr = resolve_symbol(table, node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_u32(vm, addr); + emit_byte(vm, src1); + emit_byte(vm, src2); } else if (strcmp(opname, "jump-gt-real") == 0) { emit_opcode(vm, OP_JGT_REAL); u32 addr = resolve_symbol(table, node->children[0]->token); diff --git a/src/vm/opcodes.h b/src/vm/opcodes.h index 8b88714..0a90168 100644 --- a/src/vm/opcodes.h +++ b/src/vm/opcodes.h @@ -48,16 +48,19 @@ typedef enum { OP_REAL_TO_INT, /* real-to-int : dest = src1 as int */ OP_REAL_TO_UINT, /* real-to-nat : dest = src1 as uint */ OP_JEQ_INT, /* jump-eq-int : jump to address dest if src1 as int == src2 as int */ + OP_JNEQ_INT, /* jump-neq-int : jump to address dest if src1 as int != src2 as int */ OP_JGT_INT, /* jump-gt-int : jump to address dest if src1 as int > src2 as int */ OP_JLT_INT, /* jump-lt-int : jump to address dest if src1 as int < src2 as int */ OP_JLE_INT, /* jump-le-int : jump to address dest if src1 as int <= src2 as int */ OP_JGE_INT, /* jump-ge-int : jump to address dest if src1 as int >= src2 as int */ - OP_JEQ_UINT, /* jump-eq-nat : jump to address dest if src1 as int == src2 as uint */ - OP_JGT_UINT, /* jump-gt-nat : jump to address dest if src1 as int > src2 as uint */ - OP_JLT_UINT, /* jump-lt-nat : jump to address dest if src1 as int < src2 as uint */ - OP_JLE_UINT, /* jump-le-nat : jump to address dest if src1 as int <= src2 as uint */ - OP_JGE_UINT, /* jump-ge-nat : jump to address dest if src1 as int >= src2 as uint */ + OP_JEQ_UINT, /* jump-eq-nat : jump to address dest if src1 as uint == src2 as uint */ + OP_JNEQ_UINT, /* jump-neq-nat : jump to address dest if src1 as uint != src2 as uint */ + OP_JGT_UINT, /* jump-gt-nat : jump to address dest if src1 as uint > src2 as uint */ + OP_JLT_UINT, /* jump-lt-nat : jump to address dest if src1 as uint < src2 as uint */ + OP_JLE_UINT, /* jump-le-nat : jump to address dest if src1 as uint <= src2 as uint */ + OP_JGE_UINT, /* jump-ge-nat : jump to address dest if src1 as uint >= src2 as uint */ OP_JEQ_REAL, /* jump-eq-real : jump to address dest if src1 as real == src2 as real */ + OP_JNEQ_REAL, /* jump-neq-real : jump to address dest if src1 as real != src2 as real */ OP_JGE_REAL, /* jump-ge-real : jump to address dest if src1 as real >= src2 as real */ OP_JGT_REAL, /* jump-gt-real : jump to address dest if src1 as real > src2 as real */ OP_JLT_REAL, /* jump-lt-real : jump to address dest if src1 as real < src2 as real */ diff --git a/src/vm/vm.c b/src/vm/vm.c index e73f7c9..eaba728 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -517,6 +517,9 @@ bool step_vm(VM *vm) { case OP_JEQ_UINT: { COMPARE_AND_JUMP(u32, ==); } + case OP_JNEQ_UINT: { + COMPARE_AND_JUMP(u32, !=); + } case OP_JGT_UINT: { COMPARE_AND_JUMP(u32, >); } @@ -532,6 +535,9 @@ bool step_vm(VM *vm) { case OP_JEQ_INT: { COMPARE_AND_JUMP(i32, ==); } + case OP_JNEQ_INT: { + COMPARE_AND_JUMP(i32, !=); + } case OP_JGT_INT: { COMPARE_AND_JUMP(i32, >); } @@ -547,6 +553,9 @@ bool step_vm(VM *vm) { case OP_JEQ_REAL: { COMPARE_AND_JUMP(i32, ==); } + case OP_JNEQ_REAL: { + COMPARE_AND_JUMP(i32, !=); + } case OP_JGT_REAL: { COMPARE_AND_JUMP(i32, >); } diff --git a/test/add.rom b/test/add.rom new file mode 100644 index 0000000000000000000000000000000000000000..3a769ffb9da37129ff8f2151982febf36c7c4908 GIT binary patch literal 136 zcmZQzU|k)`~$iub_O0=`B>(^b literal 0 HcmV?d00001 diff --git a/test/loop.rom b/test/loop.rom new file mode 100644 index 0000000000000000000000000000000000000000..70e8b578ee33cd49ae801f4fa6710132ff10fae5 GIT binary patch literal 229 zcmYj~u?oUK42F}-l^$&bPrC_nATBywXQ7*Y5TQjJ>`<%E;4}ELnw(1mNxnY``2hev zlJhvu1Pf=t_+A6B(FN02f-{}(q-+qW-pT?E7kY3&;Cw02xV$3iMef)Ifko*m{ZSZK zdP7gavqf(cwFI6Lftsq(Ug`=PgXxVJG?xBI*6LC0`d6I#@g8gNqT4}4xP-?v-iGTb HKyrg09w8KE literal 0 HcmV?d00001 diff --git a/test/paint-bw.asm.lisp b/test/paint-bw.asm.lisp new file mode 100644 index 0000000..08272ce --- /dev/null +++ b/test/paint-bw.asm.lisp @@ -0,0 +1,226 @@ +((code + (label main + (load-immediate $30 4) ; fat ptr size + + ; Open screen + ; use load immediate because it is a pointer to a string, not a value + (load-immediate $0 &screen-namespace) + (load-immediate $11 0) + (syscall OPEN $0 $11) + + (load-immediate $16 1) ; device info call + (load-immediate $17 16) ; sizeof screen device info + (malloc $18 $17) + (syscall IOCTL $0 $16 $18) + + (load-immediate $1 12) ; offset for width + (add-nat $19 $18 $1) + (load-r $20 $19) ; load width + + (load-immediate $1 8) ; offset for size + (add-nat $19 $18 $1) + (load-r $22 $19) ; load size + + (malloc $21 $22) ; malloc frame buffer + + (load-immediate $16 &mouse-namespace) + (load-immediate $3 12) ; malloc sizeof mouse data + (malloc $4 $3) + + (load-immediate $14 20) ; box size + + (label draw-loop + ; load mouse click data + (syscall READ $16 $2 $3 $4) + + (load-immediate $5 4) ; offset for x + (add-nat $6 $5 $2) + (load-r $7 $6) ; load x + + (load-immediate $5 8) ; offset for y + (add-nat $6 $5 $2) + (load-r $8 $6) ; load y + + (load-immediate $5 12) ; offset for btn1 + (add-nat $6 $5 $2) + (load-r8 $9 $6) ; load btn1 pressed + + (load-immediate $5 13) ; offset for btn2 + (add-nat $6 $5 $2) + (load-r8 $10 $6) ; load btn2 pressed + + ; first row + (push $21) + (push $20) + (load $1 &BLACK) + (push $1) + (load-immediate $12 1) + (push $12) + (load-immediate $13 1) + (push $13) + (call &draw-outlined-swatch) + (syscall WRITE $0 $21 $22) + + (push $14) ; box_size (20) + (push $13) ; box_y + (push $12) ; box_x + (push $8) ; click_y + (push $7) ; click_x + (push $1) ; color + (push $9) ; is btn1 clicked? + (call &set-color-if-clicked) + + (push $21) + (push $20) + (load $1 &WHITE) + (push $1) + (load-immediate $12 21) + (push $12) + (load-immediate $13 1) + (push $13) + (call &draw-outlined-swatch) + + (push $14) ; box_size (20) + (push $13) ; box_y + (push $12) ; box_x + (push $8) ; click_y + (push $7) ; click_x + (push $1) ; color + (push $9) ; is btn1 clicked? + (call &set-color-if-clicked) + + (syscall WRITE $0 $21 $22) + + (jump-eq-nat &draw-loop $9 $11) + + (mul-nat $15 $8 $20) ; $15 = y * width + (add-nat $15 $15 $7) ; $15 += x + (add-nat $15 $21 $15) ; $15 = base + pixel_offset + (add-nat $15 $15 $30) + (load $22 &SELECTED-COLOR) ; color + (store-8 $15 $22) ; draw color at screen [x,y] + + (jump-eq-nat &draw-loop $10 $11)) + + ; Flush and halt + (halt)) + + (label set-color-if-clicked + ; Pop inputs from stack (in reverse order of pushing) + (pop $12) ; $12 = btn1 down? + (pop $11) ; $11 = color + (pop $0) ; $0 = click_x + (pop $1) ; $1 = click_y + (pop $2) ; $2 = box_x + (pop $3) ; $3 = box_y + (pop $5) ; $5 = box_size + + ; Compute right = box_x + box_size + (add-int $6 $2 $5) ; $6 = right edge + + ; Compute bottom = box_y + box_size + (add-int $7 $3 $5) ; $7 = bottom edge + + ; Bounds check: x in [box_x, right] and y in [box_y, bottom] + (jump-lt-int &fail $0 $2) + (jump-gt-int &fail $0 $6) + (jump-lt-int &fail $1 $3) + (jump-gt-int &fail $1 $7) + ; If btn1 is pressed (==1), set color + (jump-eq-int &fail $12 1) + (load-immediate $10 &SELECTED-COLOR) + (store-8 $10 $11) + + (label fail) + (return)) + + (label draw-outlined-swatch + (pop $3) ; y + (pop $2) ; x + (pop $1) ; color + (pop $20) + (pop $21) + + ; Constants + (load $4 &GRAY) + (load $10 &SELECTED-COLOR) + (jump-eq-int &set-selected $10 $1) + (jump-eq-int &end-set-selected $4 $4) + (label set-selected) + (load $4 &DARK-GRAY) + (label end-set-selected) + + (load-immediate $5 20) ; outline size + (load-immediate $6 17) ; fill size + (load-immediate $7 2) ; offset + + (push $21) ; base + (push $20) ; width + (push $4) ; color (gray) + (push $2) ; x + (push $3) ; y + (push $5) ; width (20) + (push $5) ; height (20) + (call &draw-box) + + (add-int $8 $2 $7) ; x + 2 + (add-int $9 $3 $7) ; y + 2 + + (push $21) ; base + (push $20) ; width + (push $1) ; color (original) + (push $8) ; x + 2 + (push $9) ; y + 2 + (push $6) ; width (17) + (push $6) ; height (17) + (call &draw-box) + + (return)) + + ; draw-box(color, x, y) + ; Pops: y, x, color + (label draw-box + ; Pop arguments (reverse order) + (pop $14) ; height + (pop $12) ; width + (pop $13) ; y_start + (pop $11) ; x_start + (pop $3) ; color + (pop $2) ; width + (pop $21) ; base + + ; Constants + (load-immediate $1 1) ; increment + + ; Compute start address: base + y*640 + x + (mul-int $15 $13 $2) ; $15 = y * 640 + (add-int $15 $15 $11) ; $15 += x + (add-nat $15 $21 $15) ; $15 = base + pixel_offset + (load-immediate $25 4) + (add-nat $15 $15 $25) ; need to add offset for fat pointer size + (register-move $4 $15) + + ; Outer loop: height times + (register-move $5 $14) ; $5 = row counter + + (label draw-box-outer + (add-int $6 $4 $12) ; $6 = row end = current + width + (register-move $7 $4) ; $7 = pixel pointer + + (label draw-box-inner + (store-8 $7 $3) ; write color + (add-int $7 $7 $1) ; next pixel + (jump-lt-int &draw-box-inner $7 $6)) + + (add-int $4 $4 $2) ; next row (+= 640) + (sub-int $5 $5 $1) ; decrement row count + (jump-gt-int &draw-box-outer $5 0)) + (return))) +(data + (label screen-namespace "/dev/screen/0") + (label mouse-namespace "/dev/mouse/0") + (label SELECTED-COLOR 255) + (label BLACK 0) + (label WHITE 255) + (label DARK-GRAY 73) + (label GRAY 146))) diff --git a/test/paint-bw.rom b/test/paint-bw.rom new file mode 100644 index 0000000000000000000000000000000000000000..00c9cee163ff4ac962a4261ce7ca475e90979db5 GIT binary patch literal 685 zcmZuuOKub~5cRL@{*>EY?vE5T$tWVbQ8FNwERe`5$}Ix31SBHZlOyC1S>+Lb_55CaT~xjnk$nPY}U!B$|@Vq5G5k$Sc<(+HyW8MVZ&hOGTKpso&N z9^y1(pP8eTkmxLSBVR`8-W%%>q}9rU@xddMR3R0UQj|%knZ$iqXgp2aS+7|jjVKcl zVk{W#1LJ5}Q`1ZxMMA15kfz#xV%NXi5BuEdb?$$14&~n8ad_RHr)pfK6jo_UjAt;v zWj&?2_?uQ`%xzX#XOnG)#T!_Hg{wa@p}8#J3)8kR9o8b^4x3V`X&omTE->Z^+%=~` z@vNUXtkLUd2Is(iWDkPu6FrFyvQ~K_IWlAk2<%@DUMdro+J@rNypWna`Qmc9<9Q=b zEG;M09Ij4NG)qdYJP}XI52bW6xHLewc!xu9DcB_heRaVtgI}C8Zvgb=DO1?Fj*D!* kZhvp?zx>>8zi-|t`M;uk`|<03%fgO@<8$CQd+~9PFMD+>P5=M^ literal 0 HcmV?d00001 diff --git a/test/box.asm.lisp b/test/paint.asm.lisp similarity index 98% rename from test/box.asm.lisp rename to test/paint.asm.lisp index 96ed57c..dc4e390 100644 --- a/test/box.asm.lisp +++ b/test/paint.asm.lisp @@ -51,7 +51,7 @@ (load-immediate $13 1) (push $13) (call &draw-outlined-swatch) - + (syscall WRITE $0 $21 $22) (push $14) ; box_size (20) (push $13) ; box_y (push $12) ; box_x @@ -243,6 +243,8 @@ (mul-nat $15 $8 $20) ; $15 = y * width (add-nat $15 $15 $7) ; $15 += x (add-nat $15 $21 $15) ; $15 = base + pixel_offset + (load-immediate $1 4) ; need to add offset for fat pointer size + (add-nat $15 $15 $1) (load $22 &SELECTED-COLOR) ; color (store-8 $15 $22) ; draw color at screen [x,y] diff --git a/test/paint.rom b/test/paint.rom new file mode 100644 index 0000000000000000000000000000000000000000..5a166e0b83304dc690cb280469a460472175615b GIT binary patch literal 1344 zcma)+zl+pB6vs1}Uz_A*XJ?Wu9JynWvyq^?B35E`jbdeKqs6(U3NBjvqp=Z0{{a0T z1pf(}>uf~}Ye75Vd~foCN91&;$S3d3`_6YJc}bEa$xn%w6QdJ<0*JRz5bBsOU`7N# z!)qCQt!Zu+Kv3!5xT>?gRks%mb8>rM!%`gSDUf(u1FP>xIwcH?;1xmss2U ztvyw9W#kvNz2B*tgOSfRn!}OLIg0<|Q{mz1Sq$gdMzb0DT;0Ow4QmFUZ8YykJ~y}U z`8e|Vw`O?V7jL61E6%t{y>QMhT;o8*CUZ{c`997%H;+|$kpu`uNP-AykU_U5)vc9! zrLljKR4q%QQL6?iq+0F~t?K)%>o9^+LB3Cm=7qvFQe3MJjaD}>r{hd_3+r;x-9ad& z)d9|crXB|4>1yd~pq})~r(SyPwS0%g?Ig8rCT*M&*uj}M-oz;trnvPIH&2!g2x|O2 zSEj9VMLhEkpLwTJuF})iD5$J*R<_oP3!iX#Yg(n!U9H9WBMkMin&KkMyX(ix&EdoK z`u=j2&}SDj_Z~djtTAzniIZc9&vNoQ^ELAW^9l1a^A+J(NzF>*S&!r^^C|NS^BVId^9A!e^N9I_`5UXPQN92G literal 0 HcmV?d00001 diff --git a/test/simple.rom b/test/simple.rom new file mode 100644 index 0000000000000000000000000000000000000000..775f8d9e76c50969fd70cfbdc299741811c703a0 GIT binary patch literal 126 zcmZQzU|?_nVq_qP#NlBO1M+wnrGTU|6C;BwGm{`QvouHr4~SskVHNq>IaYjqt{P@8SPh z>}~;7a}8};UhRoRf>*|<*G6C6+N|yEB3S#ths#$!Er-v2&b#GVNm5a^-^W8{LH=8W PpS<7lESogy!YK6%#g`ZU literal 0 HcmV?d00001