293 lines
8.3 KiB
C
293 lines
8.3 KiB
C
#include "../../test.h"
|
|
#include "../../vm.h"
|
|
#include "devices.h"
|
|
#include <SDL2/SDL.h>
|
|
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#define MAX_SRC_SIZE 16384
|
|
|
|
static DeviceOps screen_ops = {.open = screen_open,
|
|
.read = screen_read,
|
|
.write = screen_write,
|
|
.close = screen_close,
|
|
.ioctl = NULL};
|
|
|
|
static DeviceOps mouse_ops = {.open = mouse_open,
|
|
.read = mouse_read,
|
|
.write = mouse_write,
|
|
.close = mouse_close,
|
|
.ioctl = NULL};
|
|
|
|
static DeviceOps keyboard_ops = {.open = keyboard_open,
|
|
.read = keyboard_read,
|
|
.write = keyboard_write,
|
|
.close = keyboard_close,
|
|
.ioctl = NULL};
|
|
|
|
static ScreenDeviceData screen_data = {0};
|
|
static MouseDeviceData mouse_data = {0};
|
|
static KeyboardDeviceData keyboard_data = {0};
|
|
|
|
void compileFile(const char *path, VM *vm) {
|
|
FILE *f = fopen(path, "rb");
|
|
if (!f) {
|
|
perror("fopen");
|
|
exit(1);
|
|
}
|
|
|
|
static char source[MAX_SRC_SIZE + 1];
|
|
|
|
fseek(f, 0, SEEK_END);
|
|
long len = ftell(f);
|
|
fseek(f, 0, SEEK_SET);
|
|
if (len >= MAX_SRC_SIZE) {
|
|
perror("source is larget than buffer");
|
|
exit(1);
|
|
}
|
|
size_t read = fread(source, 1, len, f);
|
|
source[read] = '\0';
|
|
fclose(f);
|
|
}
|
|
|
|
void repl(VM *vm) {
|
|
char line[1024];
|
|
for (;;) {
|
|
printf("> ");
|
|
|
|
if (!fgets(line, sizeof(line), stdin)) {
|
|
printf("\n");
|
|
break;
|
|
}
|
|
/* reset the code counter to 0 */
|
|
vm->cp = 0;
|
|
vm->sp = 0;
|
|
vm->pc = 0;
|
|
vm->mp = 0;
|
|
|
|
/* assemble(line, vm); */
|
|
while (step_vm(vm))
|
|
;
|
|
}
|
|
exit(0);
|
|
}
|
|
|
|
enum FlagType {
|
|
FLAG_NONE = 0,
|
|
FLAG_DEV_MODE = 1,
|
|
FLAG_TEST_MODE = 2,
|
|
FLAG_DUMP_ROM = 4,
|
|
FLAG_GUI_MODE = 8,
|
|
};
|
|
|
|
#define MAX_INPUT_FILES 16 /* Adjust based on your system's constraints */
|
|
|
|
struct CompilerConfig {
|
|
uint32_t flags;
|
|
char *input_files[MAX_INPUT_FILES];
|
|
int input_file_count;
|
|
};
|
|
|
|
int parse_arguments(int argc, char *argv[], struct CompilerConfig *config) {
|
|
int i;
|
|
|
|
/* Initialize config */
|
|
config->flags = 0;
|
|
config->input_file_count = 0;
|
|
|
|
/* Zero out input files array for safety */
|
|
for (i = 0; i < MAX_INPUT_FILES; i++) {
|
|
config->input_files[i] = NULL;
|
|
}
|
|
|
|
for (i = 1; i < argc; i++) {
|
|
if (argv[i][0] == '-') {
|
|
/* Long and short flag handling */
|
|
if (strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "--dev") == 0) {
|
|
config->flags |= FLAG_DEV_MODE;
|
|
} else if (strcmp(argv[i], "-g") == 0 || strcmp(argv[i], "--gui") == 0) {
|
|
config->flags |= FLAG_GUI_MODE;
|
|
} else if (strcmp(argv[i], "-t") == 0 || strcmp(argv[i], "--test") == 0) {
|
|
config->flags |= FLAG_TEST_MODE;
|
|
} else if (strcmp(argv[i], "-o") == 0 ||
|
|
strcmp(argv[i], "--dump-rom") == 0) {
|
|
config->flags |= FLAG_DUMP_ROM;
|
|
} else {
|
|
fprintf(stderr, "Unknown flag: %s\n", argv[i]);
|
|
return -1;
|
|
}
|
|
} else if (strstr(argv[i], ".ul") != NULL) {
|
|
/* Collect input files */
|
|
if (config->input_file_count >= MAX_INPUT_FILES) {
|
|
fprintf(stderr, "Too many input files. Maximum is %d\n",
|
|
MAX_INPUT_FILES);
|
|
return -1;
|
|
}
|
|
config->input_files[config->input_file_count++] = argv[i];
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void register_sdl_devices(VM *vm) {
|
|
screen_data.vm = vm;
|
|
screen_data.width = 640;
|
|
screen_data.height = 480;
|
|
screen_data.framebuffer_size = 640 * 480;
|
|
screen_data.framebuffer_pos = vm->mp;
|
|
vm->mp += screen_data.framebuffer_size / 4; /* advance memory pointer */
|
|
|
|
vm_register_device(vm, "/dev/screen/0", "screen", &screen_data, &screen_ops);
|
|
|
|
mouse_data.x = 0;
|
|
mouse_data.y = 0;
|
|
mouse_data.btn1 = 0;
|
|
mouse_data.btn2 = 0;
|
|
mouse_data.btn3 = 0;
|
|
mouse_data.btn4 = 0;
|
|
|
|
vm_register_device(vm, "/dev/mouse/0", "mouse", &mouse_data, &mouse_ops);
|
|
|
|
keyboard_data.keys = SDL_GetKeyboardState(&keyboard_data.key_count);
|
|
|
|
vm_register_device(vm, "/dev/keyboard/0", "keyboard", &keyboard_data,
|
|
&keyboard_ops);
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
struct CompilerConfig config = {0};
|
|
|
|
if (parse_arguments(argc, argv, &config) != 0) {
|
|
fprintf(stderr, "Usage: %s [-d] [-t] [-g] [-o] <file1.ul> [file2.ul] ...\n",
|
|
argv[0]);
|
|
return 64;
|
|
}
|
|
|
|
VM vm = {0};
|
|
if (config.input_file_count == 0) {
|
|
repl(&vm);
|
|
} else {
|
|
if (config.flags & FLAG_TEST_MODE) {
|
|
compile_internal_test(config.input_files[0], &vm);
|
|
} else {
|
|
int j;
|
|
for (j = 0; j < config.input_file_count; j++) {
|
|
compileFile(config.input_files[j], &vm);
|
|
}
|
|
}
|
|
|
|
if (config.flags & FLAG_DUMP_ROM) {
|
|
FILE *file = fopen("memory_dump.bin", "wb");
|
|
if (!file) {
|
|
perror("Failed to open file");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
size_t code_written = fwrite(vm.code, 1, CODE_SIZE, file);
|
|
if (code_written != CODE_SIZE) {
|
|
fprintf(stderr, "Incomplete code write: %zu bytes written out of %u\n",
|
|
code_written, CODE_SIZE);
|
|
fclose(file);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
size_t memory_written = fwrite(vm.memory, 1, MEMORY_SIZE, file);
|
|
if (memory_written != MEMORY_SIZE) {
|
|
fprintf(stderr,
|
|
"Incomplete memory write: %zu bytes written out of %u\n",
|
|
memory_written, MEMORY_SIZE);
|
|
fclose(file);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
fclose(file);
|
|
}
|
|
}
|
|
bool running = true;
|
|
|
|
if (config.flags & FLAG_GUI_MODE) {
|
|
uint32_t i;
|
|
register_sdl_devices(&vm);
|
|
while (running) {
|
|
for (i = 0; i < vm.dc; i++) {
|
|
Device *dev = &vm.devices[i];
|
|
if (strcmp(dev->type, "mouse") == 0) {
|
|
MouseDeviceData *mouse = (MouseDeviceData *)dev->data;
|
|
SDL_PumpEvents();
|
|
SDL_Event event;
|
|
while (SDL_PollEvent(&event)) {
|
|
switch (event.type) {
|
|
case SDL_QUIT:
|
|
running = false;
|
|
break;
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
step_vm(&vm);
|
|
|
|
for (i = 0; i < vm.dc; i++) {
|
|
Device *dev = &vm.devices[i];
|
|
if (strcmp(dev->type, "screen") == 0) {
|
|
ScreenDeviceData *screen = (ScreenDeviceData *)dev->data;
|
|
if (screen->texture && screen->renderer) {
|
|
SDL_UpdateTexture(screen->texture, NULL,
|
|
&vm.memory[screen->framebuffer_pos],
|
|
screen->width * sizeof(uint32_t));
|
|
|
|
SDL_RenderClear(screen->renderer);
|
|
|
|
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 = {
|
|
(int)((output_rect.w - screen->width * scale) / 2),
|
|
(int)((output_rect.h - screen->height * scale) / 2),
|
|
(int)(screen->width * scale), (int)(screen->height * scale)};
|
|
|
|
SDL_RenderCopy(screen->renderer, screen->texture, NULL, &dstrect);
|
|
SDL_RenderPresent(screen->renderer);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
while (running) {
|
|
running = step_vm(&vm);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|