1
0
Fork 0
reality-engine/src/arch/emscripten/main.c

279 lines
10 KiB
C

#include "../../vm/device.h"
#include "../../vm/vm.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};
const char *opcode_to_string(Opcode op) {
static const char *names[] = {[OP_HALT] = "halt",
[OP_JMP] = "jump",
[OP_JMPF] = "jump-if-flag",
[OP_CALL] = "call",
[OP_RETURN] = "return",
[OP_LOAD_IMM] = "load-immediate",
[OP_GET_8] = "get-8",
[OP_GET_16] = "get-16",
[OP_GET_32] = "get",
[OP_LOAD_8] = "load-8",
[OP_LOAD_16] = "load-16",
[OP_LOAD_32] = "load",
[OP_STORE_8] = "store-8",
[OP_STORE_16] = "store-16",
[OP_STORE_32] = "store",
[OP_PUT_8] = "put-8",
[OP_PUT_16] = "put-16",
[OP_PUT_32] = "put",
[OP_MALLOC] = "malloc",
[OP_MEMSET_8] = "memset-8",
[OP_MEMSET_16] = "memset-16",
[OP_MEMSET_32] = "memset-32",
[OP_PUSH] = "push",
[OP_POP] = "pop",
[OP_REG_MOV] = "register-move",
[OP_SYSCALL] = "syscall",
[OP_SLL] = "bit-shift-left",
[OP_SRL] = "bit-shift-right",
[OP_SRE] = "bit-shift-re",
[OP_BAND] = "bit-and",
[OP_BOR] = "bit-or",
[OP_BXOR] = "bit-xor",
[OP_ADD_INT] = "add-int",
[OP_SUB_INT] = "sub-int",
[OP_MUL_INT] = "mul-int",
[OP_DIV_INT] = "div-int",
[OP_ADD_UINT] = "add-nat",
[OP_SUB_UINT] = "sub-nat",
[OP_MUL_UINT] = "mul-nat",
[OP_DIV_UINT] = "div-nat",
[OP_ADD_REAL] = "add-real",
[OP_SUB_REAL] = "sub-real",
[OP_MUL_REAL] = "mul-real",
[OP_DIV_REAL] = "div-real",
[OP_INT_TO_REAL] = "int-to-real",
[OP_UINT_TO_REAL] = "nat-to-real",
[OP_REAL_TO_INT] = "real-to-int",
[OP_REAL_TO_UINT] = "real-to-nat",
[OP_JEQ_INT] = "jump-eq-int",
[OP_JNEQ_INT] = "jump-neq-int",
[OP_JGT_INT] = "jump-gt-int",
[OP_JLT_INT] = "jump-lt-int",
[OP_JLE_INT] = "jump-le-int",
[OP_JGE_INT] = "jump-ge-int",
[OP_JEQ_UINT] = "jump-eq-nat",
[OP_JNEQ_UINT] = "jump-neq-nat",
[OP_JGT_UINT] = "jump-gt-nat",
[OP_JLT_UINT] = "jump-lt-nat",
[OP_JLE_UINT] = "jump-le-nat",
[OP_JGE_UINT] = "jump-ge-nat",
[OP_JEQ_REAL] = "jump-eq-real",
[OP_JNEQ_REAL] = "jump-neq-real",
[OP_JGE_REAL] = "jump-ge-real",
[OP_JGT_REAL] = "jump-gt-real",
[OP_JLT_REAL] = "jump-lt-real",
[OP_JLE_REAL] = "jump-le-real",
[OP_STRLEN] = "string-length",
[OP_STREQ] = "string-eq",
[OP_STRCAT] = "string-concat",
[OP_STR_GET_CHAR] = "string-get-char",
[OP_STR_FIND_CHAR] = "string-find-char",
[OP_STR_SLICE] = "string-slice",
[OP_INT_TO_STRING] = "int-to-string",
[OP_UINT_TO_STRING] = "nat-to-string",
[OP_REAL_TO_STRING] = "real-to-string",
[OP_STRING_TO_INT] = "string-to-int",
[OP_STRING_TO_UINT] = "string-to-nat",
[OP_STRING_TO_REAL] = "string-to-real"};
if (op < 0 || op >= (int)(sizeof(names) / sizeof(names[0]))) {
return "<invalid-opcode>";
}
const char *name = names[op];
return name ? name : "<unknown-opcode>";
}
void mainloop() {
SDL_Event event;
SDL_PumpEvents();
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;
}
}
}
// Run VM for a fixed number of cycles or a time slice
int cycles_this_frame = 0;
int max_cycles_per_frame = 1000; // Adjust this value
while (cycles_this_frame < max_cycles_per_frame) {
// printf("%s\n", opcode_to_string(vm.code[vm.pc])); // REMOVE THIS LINE
if (!step_vm(&vm)) {
emscripten_cancel_main_loop();
return;
}
cycles_this_frame++;
}
// Render only if the screen buffer was updated AND at a reasonable rate
if (screen_data.update) {
if (screen_data.renderer && screen_data.texture) {
SDL_RenderCopy(screen_data.renderer, screen_data.texture, NULL, NULL);
SDL_RenderPresent(screen_data.renderer);
}
screen_data.update = false; // Reset flag after rendering
}
}
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) {
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;
}