Add wasm example, add paint example, ad neq opcodes, fix load/save VM,
This commit is contained in:
parent
71622c3133
commit
aea1dba6a2
27
Makefile
27
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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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, >);
|
||||
}
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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)))
|
Binary file not shown.
|
@ -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]
|
Binary file not shown.
Binary file not shown.
|
@ -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)
|
||||
|
|
Binary file not shown.
Loading…
Reference in New Issue