From ab5bc879083801bff29b83290b98541fc3e61780 Mon Sep 17 00:00:00 2001 From: zongor Date: Sun, 31 Aug 2025 12:56:59 -0700 Subject: [PATCH] add initial device implementation --- src/arch/linux-sdl/main.c | 9 ++- src/device.c | 53 ++++++++++++++++ src/device.h | 11 ++++ src/opcodes.h | 69 +++++++++------------ src/vm.c | 125 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 223 insertions(+), 44 deletions(-) create mode 100644 src/device.c create mode 100644 src/device.h diff --git a/src/arch/linux-sdl/main.c b/src/arch/linux-sdl/main.c index e818591..a97043b 100644 --- a/src/arch/linux-sdl/main.c +++ b/src/arch/linux-sdl/main.c @@ -66,6 +66,7 @@ int main(int argc, char **argv) { uint32_t buffer_size = 640 * 480 * sizeof(uint32_t); + /* Device screen; screen.type = SCREEN; screen.s = (Screen){.width = (uint8_t)480, @@ -86,7 +87,6 @@ int main(int argc, char **argv) { keyboard.k = (Keyboard){.length = SDL_NUM_SCANCODES, .keys = state}; vm.devices[vm.dp++] = keyboard; - /* Create window and renderer */ SDL_Window *window = SDL_CreateWindow("Reality Engine VM", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, screen.s.width, screen.s.height, @@ -95,13 +95,11 @@ int main(int argc, char **argv) { SDL_Renderer *renderer = SDL_CreateRenderer( window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); - /* Create texture for 640x480 buffer */ SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, screen.s.width, screen.s.height); - /* Enable nearest-neighbor scaling (preserves pixel art) */ - SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); /* "0" = nearest-neighbor */ + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); bool running = true; while (running) { @@ -138,7 +136,7 @@ int main(int argc, char **argv) { SDL_RenderClear(renderer); - /* (Scales to fit screen while preserving pixel grid) */ + SDL_Rect output_rect; SDL_RenderGetViewport(renderer, &output_rect); float scale_x = (float)output_rect.w / screen.s.width; @@ -153,5 +151,6 @@ int main(int argc, char **argv) { SDL_RenderCopy(renderer, texture, NULL, &dstrect); SDL_RenderPresent(renderer); } + */ return 0; } diff --git a/src/device.c b/src/device.c new file mode 100644 index 0000000..b00cf6d --- /dev/null +++ b/src/device.c @@ -0,0 +1,53 @@ +#include "device.h" + +#include + +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; +} + +/* 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]; + } + } + 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]; + } + } + 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]; + } + } + return count; +} diff --git a/src/device.h b/src/device.h new file mode 100644 index 0000000..cf62804 --- /dev/null +++ b/src/device.h @@ -0,0 +1,11 @@ +#ifndef ZRL_DEVICE_H +#define ZRL_DEVICE_H + +#include "opcodes.h" + +int 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); + +#endif \ No newline at end of file diff --git a/src/opcodes.h b/src/opcodes.h index 02ebd7d..5af6007 100644 --- a/src/opcodes.h +++ b/src/opcodes.h @@ -2,6 +2,7 @@ #define ZRL_OPCODES_H #include "common.h" +#include typedef enum { OP_HALT, /* halt : terminate execution */ @@ -12,11 +13,11 @@ typedef enum { OP_LOAD, /* 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_POP, /* pop : pop int from stack onto the register */ OP_REG_MOV, /* rmov : dest = src1 */ OP_REG_SWAP, /* rswp : dest = src1, src1 = dest */ OP_MEM_SWAP, /* mswp : &dest = &src1, &src1 = &dest */ - OP_MEM_MOV, /* mmov : &dest = &src1 */ + 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 */ @@ -60,7 +61,7 @@ typedef enum { 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, just for testing for now */ + /* to remove (replace with device), just for testing for now */ OP_DBG_PRINT_STRING, OP_DBG_READ_STRING, } Opcode; @@ -88,42 +89,32 @@ typedef struct frame_s { Slice allocated; /* start and end of global allocated block */ } Frame; -typedef struct screen_t { - uint8_t width; - uint8_t height; - Slice allocated; - Value *buffer; -} Screen; - -typedef struct mouse_t { - uint32_t x; - uint32_t y; - uint8_t btn1; - uint8_t btn2; - uint8_t btn3; -} Mouse; - -typedef struct keyboard_t { - uint32_t length; - const uint8_t *keys; -} Keyboard; - typedef enum { - SCREEN, - MOUSE, - KEYBOARD, - CONTROLLER, - AUDIO, - TUNNEL, -} Devicecode; + SYSCALL_EXIT = 0, + SYSCALL_DEVICE_OPEN, + SYSCALL_DEVICE_READ, + SYSCALL_DEVICE_WRITE, + SYSCALL_DEVICE_CLOSE, + SYSCALL_DEVICE_IOCTL, +} SyscallID; -typedef union device_u { - uint8_t type; - Screen s; - Mouse m; - Keyboard k; - /* Audio a; */ - /* Tunnel t; */ +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 */ +} DeviceOps; + +#define DEVICE_TYPE_MAX_LENGTH 24 /* 23 chars + null terminator */ +#define DEVICE_PATH_MAX_LENGTH 64 /* 63 chars + null terminator */ + +typedef struct device_s { + char type[DEVICE_TYPE_MAX_LENGTH]; /* e.g., "screen", "mouse", "gpio" */ + char path[DEVICE_PATH_MAX_LENGTH]; /* "/dev/screen", "/dev/input/mouse/0", etc. */ + void *data; /* device-specific data */ + DeviceOps *ops; /* operations vtable */ + uint32_t flags; /* permissions, status, etc. */ } Device; #define MEMORY_SIZE 65536 @@ -138,8 +129,8 @@ typedef struct vm_s { 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 dp; /* device pointer (last allocated device) */ - uint8_t devices_size; + uint32_t dc; /* device count */ + uint32_t device_size; Device devices[DEVICES_SIZE]; uint32_t frames_size; Frame frames[FRAMES_SIZE]; /* function call frames */ diff --git a/src/vm.c b/src/vm.c index fa2fa3b..62c7a33 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1,4 +1,5 @@ #include "vm.h" +#include "device.h" #include /* no inline fn in ANSI C :( */ @@ -158,6 +159,130 @@ bool step_vm(VM *vm) { return true; } case OP_SYSCALL: { + uint32_t syscall_id = dest; + uint32_t arg_ptr = src1; + uint32_t arg_count = src2; + + Frame *frame = &vm->frames[vm->fp]; + Value *regs = frame->registers; + + uint32_t memory_ptr = regs[arg_ptr].u; + + switch (syscall_id) { + case SYSCALL_DEVICE_OPEN: { + if (arg_count >= 2) { + uint32_t path_offset = vm->memory[memory_ptr].u; + uint32_t mode = vm->memory[memory_ptr + 1].u; + + const char *path = (const char *)&vm->memory[path_offset]; + Device *dev = find_device_by_path(vm, path); + + if (dev) { + if (dev->ops->open) { + int result = dev->ops->open(dev->data, mode); + vm->stack[++vm->sp].i = result; + } else { + vm->stack[++vm->sp].i = 1; /* success, no open needed */ + } + } else { + vm->stack[++vm->sp].i = 0; /* error */ + } + } + return true; + } + + case SYSCALL_DEVICE_READ: { + if (arg_count >= 3) { + uint32_t path_offset = + vm->memory[memory_ptr].u; /* offset 0: path pointer */ + uint32_t buffer_ptr = + vm->memory[memory_ptr + 1].u; /* offset 1: buffer pointer */ + uint32_t size = vm->memory[memory_ptr + 2].u; /* offset 2: size */ + + const char *path = (const char *)&vm->memory[path_offset]; + Device *dev = find_device_by_path(vm, path); + + if (dev && dev->ops->read) { + int result = dev->ops->read(dev->data, + (uint8_t *)&vm->memory[buffer_ptr], size); + vm->stack[++vm->sp].i = result; + } else { + vm->stack[++vm->sp].i = 0; + } + } + return true; + } + + case SYSCALL_DEVICE_WRITE: { + if (arg_count >= 3) { + uint32_t path_offset = + vm->memory[memory_ptr].u; /* offset 0: path pointer */ + uint32_t buffer_ptr = + vm->memory[memory_ptr + 1].u; /* offset 1: buffer pointer */ + uint32_t size = vm->memory[memory_ptr + 2].u; /* offset 2: size */ + + const char *path = (const char *)&vm->memory[path_offset]; + Device *dev = find_device_by_path(vm, path); + + if (dev && dev->ops->write) { + int result = dev->ops->write( + dev->data, (const uint8_t *)&vm->memory[buffer_ptr], size); + vm->stack[++vm->sp].i = result; + } else { + vm->stack[++vm->sp].i = 0; + } + } + return true; + } + + case SYSCALL_DEVICE_CLOSE: { + if (arg_count >= 1) { + uint32_t path_offset = + vm->memory[memory_ptr].u; /* offset 0: path pointer */ + + const char *path = (const char *)&vm->memory[path_offset]; + Device *dev = find_device_by_path(vm, path); + + if (dev && dev->ops->close) { + int result = dev->ops->close(dev->data); + vm->stack[++vm->sp].i = result; + } else { + vm->stack[++vm->sp].i = 0; + } + } + return true; + } + + case SYSCALL_DEVICE_IOCTL: { + if (arg_count >= 3) { + uint32_t path_offset = vm->memory[memory_ptr].u; /* device path */ + uint32_t cmd = vm->memory[memory_ptr + 1].u; /* ioctl command */ + uint32_t args_ptr = vm->memory[memory_ptr + 2].u; /* args pointer */ + + const char *path = (const char *)&vm->memory[path_offset]; + Device *dev = find_device_by_path(vm, path); + + if (dev && dev->ops && dev->ops->ioctl) { + int result = dev->ops->ioctl(dev->data, cmd, &vm->memory[args_ptr]); + vm->stack[++vm->sp].i = result; + } else { + vm->stack[++vm->sp].i = 0; /* error or no ioctl support */ + } + } + break; + } + + case SYSCALL_EXIT: { + return false; + break; + } + + default: { + regs[0].i = -1; + return true; + } + } + return true; } case OP_ADD_INT: MATH_OP(i, +);