diff --git a/bench/run.sh b/bench/run.sh index 999d536..ab75bcd 100755 --- a/bench/run.sh +++ b/bench/run.sh @@ -40,6 +40,10 @@ print_section "zlc ($FILENAME.zl)" print_section "zre ($FILENAME.t.ul)" echo "test input" | time ../build/old/zre -t "$FILENAME.ul" -# Undâr Implementation +# Undâr Implementation (inline assembled) print_section "undar ($FILENAME.asm.lisp)" echo "test input" | time ../build/linux/undar-linux-release "../test/$FILENAME.asm.lisp" + +# Undâr Implementation (binary) +print_section "undar ($FILENAME.rom)" +echo "test input" | time ../build/linux/undar-linux-release "../test/$FILENAME.rom" diff --git a/src/arch/linux/main.c b/src/arch/linux/main.c index 8fd0574..3e3bfe4 100644 --- a/src/arch/linux/main.c +++ b/src/arch/linux/main.c @@ -5,6 +5,7 @@ #include #include +#include #include #define MAX_SRC_SIZE 16384 @@ -39,11 +40,91 @@ 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"); +// Function to save VM state to ROM file +bool saveVM(const char *filename, VM *vm) { + FILE *file = fopen(filename, "wb"); + if (!file) { + perror("Failed to open file for writing"); + return false; + } + + // Write VM state (registers and pointers) + if (fwrite(&vm->pc, sizeof(u32), 1, file) != 1 || + fwrite(&vm->cp, sizeof(u32), 1, file) != 1 || + fwrite(&vm->fp, sizeof(u32), 1, file) != 1 || + fwrite(&vm->sp, sizeof(u32), 1, file) != 1 || + fwrite(&vm->rp, sizeof(u32), 1, file) != 1 || + fwrite(&vm->mp, sizeof(u32), 1, file) != 1 || + fwrite(&vm->dc, sizeof(u32), 1, file) != 1 || + fwrite(&vm->flag, sizeof(i32), 1, file) != 1) { + fprintf(stderr, "Failed to write VM state\n"); + fclose(file); + return false; + } + // Write code section + if (fwrite(vm->code, 1, CODE_SIZE, file) != CODE_SIZE) { + 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) { + fprintf(stderr, "Failed to write memory section\n"); + fclose(file); + return false; + } + + fclose(file); + return true; +} + +// Function to load VM state from ROM file +bool loadVM(const char *filename, VM *vm) { + FILE *file = fopen(filename, "rb"); + if (!file) { + perror("Failed to open ROM file"); + return false; + } + + // Read VM state (registers and pointers) + 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) { + fprintf(stderr, "Failed to read VM state\n"); + fclose(file); + return false; + } + + // Read code section + if (fread(vm->code, 1, CODE_SIZE, file) != CODE_SIZE) { + 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) { + fprintf(stderr, "Failed to read memory section\n"); + fclose(file); + return false; + } + + fclose(file); + return true; +} + +// Function to compile and optionally save +bool compileAndSave(const char *source_file, const char *output_file, VM *vm) { + FILE *f = fopen(source_file, "rb"); if (!f) { perror("fopen"); - exit(1); + return false; } static char source[MAX_SRC_SIZE + 1]; @@ -52,18 +133,31 @@ void compileFile(const char *path, VM *vm) { long len = ftell(f); fseek(f, 0, SEEK_SET); if (len >= MAX_SRC_SIZE) { - perror("source is larget than buffer"); - exit(1); + fprintf(stderr, "Source is larger than buffer\n"); + fclose(f); + return false; } size_t read = fread(source, 1, len, f); source[read] = '\0'; fclose(f); + ExprNode *ast = expr_parse(source, strlen(source)); if (!ast) { printf("Parse failed.\n"); + return false; } else { assemble(vm, ast); expr_free(ast); + + // If output file specified, save the VM + if (output_file) { + if (!saveVM(output_file, vm)) { + printf("Failed to save VM to %s\n", output_file); + return false; + } + printf("VM saved to %s\n", output_file); + } + return true; } } @@ -75,8 +169,8 @@ void repl(VM *vm) { for (;;) { // Count current parentheses balance - int paren_balance = 0; - for (int i = 0; buffer[i]; i++) { + i32 paren_balance = 0; + for (i32 i = 0; buffer[i]; i++) { if (buffer[i] == '(') paren_balance++; else if (buffer[i] == ')') @@ -101,7 +195,7 @@ void repl(VM *vm) { // Recalculate balance after adding new line paren_balance = 0; - for (int i = 0; buffer[i]; i++) { + for (i32 i = 0; buffer[i]; i++) { if (buffer[i] == '(') paren_balance++; else if (buffer[i] == ')') @@ -111,8 +205,8 @@ void repl(VM *vm) { // Only parse when parentheses are balanced if (paren_balance == 0) { // Check if buffer has actual content (not just whitespace) - int has_content = 0; - for (int i = 0; buffer[i]; i++) { + i32 has_content = 0; + for (i32 i = 0; buffer[i]; i++) { if (!isspace(buffer[i])) { has_content = 1; break; @@ -139,66 +233,6 @@ void repl(VM *vm) { exit(0); } -enum FlagType { - FLAG_NONE = 0, - FLAG_DUMP_ROM = 1, - FLAG_GUI_MODE = 2, -}; - -#define MAX_INPUT_FILES 16 /* Adjust based on your system's constraints */ - -struct CompilerConfig { - u32 flags; - char *input_files[MAX_INPUT_FILES]; - i32 input_file_count; -}; - -i32 parse_arguments(i32 argc, char *argv[], struct CompilerConfig *config) { - i32 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], "-g") == 0 || strcmp(argv[i], "--gui") == 0) { - config->flags |= FLAG_GUI_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]; - } else if (strstr(argv[i], ".lisp") != 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; -} - /* * This needs to be done dynamically eventually */ @@ -228,58 +262,79 @@ void register_sdl_devices(VM *vm) { } i32 main(i32 argc, char *argv[]) { - struct CompilerConfig config = {0}; + bool gui_mode = false; + bool dump_rom = false; + char *input_file = nil; + char *output_file = nil; + bool is_rom = false; - if (parse_arguments(argc, argv, &config) != 0) { - fprintf(stderr, "Usage: %s [-d] [-g] [-o] [file2.ul] ...\n", - argv[0]); - return 64; + // Parse command line arguments + for (i32 i = 1; i < argc; i++) { + if (strcmp(argv[i], "-g") == 0 || strcmp(argv[i], "--gui") == 0) { + gui_mode = true; + } else if (strcmp(argv[i], "-o") == 0 || + strcmp(argv[i], "--dump-rom") == 0) { + dump_rom = true; + } else if (input_file == nil) { + // This is the input file + input_file = argv[i]; + + // Check if it's a ROM file + const char *ext = strrchr(argv[i], '.'); + if (ext && (strcmp(ext, ".rom") == 0)) { + is_rom = true; + } + } else if (output_file == nil && dump_rom) { + // This is the output file for -o flag + output_file = argv[i]; + } } VM vm = {0}; - if (config.input_file_count == 0) { - repl(&vm); - } else { - i32 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; + // Register terminal device first vm_register_device(&vm, "/dev/term/0", "terminal", nil, &console_device_ops); - if (config.flags & FLAG_GUI_MODE) { - u32 i; + bool compilation_success = true; + if (input_file) { + if (is_rom) { + // Load ROM file directly + compilation_success = loadVM(input_file, &vm); + } else { + // Compile Lisp file + if (dump_rom && output_file) { + compilation_success = compileAndSave(input_file, output_file, &vm); + } else { + compilation_success = compileAndSave(input_file, nil, &vm); + } + } + } else { + // No input file - enter REPL mode + repl(&vm); + return 0; + } + + if (dump_rom) { + return (compilation_success) ? EXIT_SUCCESS : EXIT_FAILURE; + } + + // If dump_rom flag was set without specifying output file, use default + if (dump_rom && !is_rom && !output_file) { + if (!saveVM("memory_dump.bin", &vm)) { + printf("Failed to save VM to memory_dump.bin\n"); + return EXIT_FAILURE; + } + printf("VM saved to memory_dump.bin\n"); + return EXIT_SUCCESS; + } + + bool running = true; + + if (gui_mode) { register_sdl_devices(&vm); + while (running) { - for (i = 0; i < vm.dc; i++) { + for (u32 i = 0; i < vm.dc; i++) { Device *dev = &vm.devices[i]; if (strcmp(dev->type, "mouse") == 0) { MouseDeviceData *mouse = (MouseDeviceData *)dev->data; @@ -321,12 +376,12 @@ i32 main(i32 argc, char *argv[]) { step_vm(&vm); - for (i = 0; i < vm.dc; i++) { + for (u32 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, + SDL_UpdateTexture(screen->texture, nil, &vm.memory[screen->framebuffer_pos], screen->width * sizeof(u32)); @@ -343,7 +398,7 @@ i32 main(i32 argc, char *argv[]) { (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_RenderCopy(screen->renderer, screen->texture, nil, &dstrect); SDL_RenderPresent(screen->renderer); } break; @@ -356,5 +411,5 @@ i32 main(i32 argc, char *argv[]) { } } - return 0; + return EXIT_SUCCESS; } diff --git a/src/vm/vm.c b/src/vm/vm.c index be2d58c..d4b2636 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -282,7 +282,7 @@ bool step_vm(VM *vm) { case SYSCALL_DEVICE_WRITE: { Device *dev; u32 path_ptr, buffer_ptr, size; - u8 path_reg, buffer_reg, size_reg; + u16 path_reg, buffer_reg, size_reg; path_reg = read_u8(vm, code, vm->pc); vm->pc++; buffer_reg = read_u8(vm, code, vm->pc); diff --git a/test/add.rom b/test/add.rom new file mode 100644 index 0000000..9db41ef Binary files /dev/null and b/test/add.rom differ diff --git a/test/fib.rom b/test/fib.rom new file mode 100644 index 0000000..6206833 Binary files /dev/null and b/test/fib.rom differ diff --git a/test/hello.rom b/test/hello.rom new file mode 100644 index 0000000..8cebff6 Binary files /dev/null and b/test/hello.rom differ diff --git a/test/loop.rom b/test/loop.rom new file mode 100644 index 0000000..4d4576b Binary files /dev/null and b/test/loop.rom differ diff --git a/test/simple.rom b/test/simple.rom new file mode 100644 index 0000000..3ee1d8d Binary files /dev/null and b/test/simple.rom differ