Add wasm example, add paint example, ad neq opcodes, fix load/save VM,

This commit is contained in:
zongor 2025-10-05 22:54:34 -07:00
parent 71622c3133
commit aea1dba6a2
21 changed files with 849 additions and 101 deletions

View File

@ -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

View File

@ -0,0 +1,308 @@
#include "devices.h"
#include <stdio.h>
#include <string.h>
#include <emscripten.h>
#include <emscripten/html5.h>
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;
}

View File

@ -0,0 +1,56 @@
#include "../../vm/vm.h"
#include <SDL2/SDL.h>
#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);

View File

@ -1,18 +1,118 @@
#include "../../test.h"
#include "../../vm.h"
#include "../../vm/vm.h"
#include "../../vm/device.h"
#include "devices.h"
#include <SDL2/SDL.h>
#include <emscripten.h>
#include <emscripten/html5.h>
#include <stdio.h>
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;
}

View File

@ -1,4 +1,5 @@
#include "devices.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
@ -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,26 +74,29 @@ 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;
}
@ -111,14 +104,6 @@ i32 screen_write(void *data, const u8 *buffer, u32 size) {
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;
@ -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;
@ -168,40 +153,57 @@ i32 mouse_read(void *data, u8 *buffer, u32 size) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
// Mouse events
case SDL_MOUSEMOTION:
mouse->x = event.motion.x;
mouse->y = event.motion.y;
mouse_data->x = event.motion.x;
mouse_data->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;
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->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;
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;
}

View File

@ -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 */

View File

@ -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,7 +411,12 @@ 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

View File

@ -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 ||
@ -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);

View File

@ -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 */

View File

@ -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, >);
}

BIN
test/add.rom Normal file

Binary file not shown.

BIN
test/fib.rom Normal file

Binary file not shown.

BIN
test/hello.rom Normal file

Binary file not shown.

BIN
test/loop.rom Normal file

Binary file not shown.

226
test/paint-bw.asm.lisp Normal file
View File

@ -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)))

BIN
test/paint-bw.rom Normal file

Binary file not shown.

View File

@ -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]

BIN
test/paint.rom Normal file

Binary file not shown.

BIN
test/simple.rom Normal file

Binary file not shown.

View File

@ -21,6 +21,10 @@
(load-immediate $3 12) ; malloc sizeof mouse data
(malloc $4 $3)
(nat-to-string $5 $4)
(push $5)
(call &println)
(label draw-loop
; load mouse click data
(syscall READ $16 $2 $3 $4)

BIN
test/window.rom Normal file

Binary file not shown.