load binary file
This commit is contained in:
parent
3c9603adea
commit
7a42429cf2
|
@ -40,6 +40,10 @@ print_section "zlc ($FILENAME.zl)"
|
||||||
print_section "zre ($FILENAME.t.ul)"
|
print_section "zre ($FILENAME.t.ul)"
|
||||||
echo "test input" | time ../build/old/zre -t "$FILENAME.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)"
|
print_section "undar ($FILENAME.asm.lisp)"
|
||||||
echo "test input" | time ../build/linux/undar-linux-release "../test/$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"
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define MAX_SRC_SIZE 16384
|
#define MAX_SRC_SIZE 16384
|
||||||
|
@ -39,11 +40,91 @@ static ScreenDeviceData screen_data = {0};
|
||||||
static MouseDeviceData mouse_data = {0};
|
static MouseDeviceData mouse_data = {0};
|
||||||
static KeyboardDeviceData keyboard_data = {0};
|
static KeyboardDeviceData keyboard_data = {0};
|
||||||
|
|
||||||
void compileFile(const char *path, VM *vm) {
|
// Function to save VM state to ROM file
|
||||||
FILE *f = fopen(path, "rb");
|
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) {
|
if (!f) {
|
||||||
perror("fopen");
|
perror("fopen");
|
||||||
exit(1);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char source[MAX_SRC_SIZE + 1];
|
static char source[MAX_SRC_SIZE + 1];
|
||||||
|
@ -52,18 +133,31 @@ void compileFile(const char *path, VM *vm) {
|
||||||
long len = ftell(f);
|
long len = ftell(f);
|
||||||
fseek(f, 0, SEEK_SET);
|
fseek(f, 0, SEEK_SET);
|
||||||
if (len >= MAX_SRC_SIZE) {
|
if (len >= MAX_SRC_SIZE) {
|
||||||
perror("source is larget than buffer");
|
fprintf(stderr, "Source is larger than buffer\n");
|
||||||
exit(1);
|
fclose(f);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
size_t read = fread(source, 1, len, f);
|
size_t read = fread(source, 1, len, f);
|
||||||
source[read] = '\0';
|
source[read] = '\0';
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
ExprNode *ast = expr_parse(source, strlen(source));
|
ExprNode *ast = expr_parse(source, strlen(source));
|
||||||
if (!ast) {
|
if (!ast) {
|
||||||
printf("Parse failed.\n");
|
printf("Parse failed.\n");
|
||||||
|
return false;
|
||||||
} else {
|
} else {
|
||||||
assemble(vm, ast);
|
assemble(vm, ast);
|
||||||
expr_free(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 (;;) {
|
for (;;) {
|
||||||
// Count current parentheses balance
|
// Count current parentheses balance
|
||||||
int paren_balance = 0;
|
i32 paren_balance = 0;
|
||||||
for (int i = 0; buffer[i]; i++) {
|
for (i32 i = 0; buffer[i]; i++) {
|
||||||
if (buffer[i] == '(')
|
if (buffer[i] == '(')
|
||||||
paren_balance++;
|
paren_balance++;
|
||||||
else if (buffer[i] == ')')
|
else if (buffer[i] == ')')
|
||||||
|
@ -101,7 +195,7 @@ void repl(VM *vm) {
|
||||||
|
|
||||||
// Recalculate balance after adding new line
|
// Recalculate balance after adding new line
|
||||||
paren_balance = 0;
|
paren_balance = 0;
|
||||||
for (int i = 0; buffer[i]; i++) {
|
for (i32 i = 0; buffer[i]; i++) {
|
||||||
if (buffer[i] == '(')
|
if (buffer[i] == '(')
|
||||||
paren_balance++;
|
paren_balance++;
|
||||||
else if (buffer[i] == ')')
|
else if (buffer[i] == ')')
|
||||||
|
@ -111,8 +205,8 @@ void repl(VM *vm) {
|
||||||
// Only parse when parentheses are balanced
|
// Only parse when parentheses are balanced
|
||||||
if (paren_balance == 0) {
|
if (paren_balance == 0) {
|
||||||
// Check if buffer has actual content (not just whitespace)
|
// Check if buffer has actual content (not just whitespace)
|
||||||
int has_content = 0;
|
i32 has_content = 0;
|
||||||
for (int i = 0; buffer[i]; i++) {
|
for (i32 i = 0; buffer[i]; i++) {
|
||||||
if (!isspace(buffer[i])) {
|
if (!isspace(buffer[i])) {
|
||||||
has_content = 1;
|
has_content = 1;
|
||||||
break;
|
break;
|
||||||
|
@ -139,66 +233,6 @@ void repl(VM *vm) {
|
||||||
exit(0);
|
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
|
* This needs to be done dynamically eventually
|
||||||
*/
|
*/
|
||||||
|
@ -228,58 +262,79 @@ void register_sdl_devices(VM *vm) {
|
||||||
}
|
}
|
||||||
|
|
||||||
i32 main(i32 argc, char *argv[]) {
|
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) {
|
// Parse command line arguments
|
||||||
fprintf(stderr, "Usage: %s [-d] [-g] [-o] <file1.ul> [file2.ul] ...\n",
|
for (i32 i = 1; i < argc; i++) {
|
||||||
argv[0]);
|
if (strcmp(argv[i], "-g") == 0 || strcmp(argv[i], "--gui") == 0) {
|
||||||
return 64;
|
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};
|
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) {
|
// Register terminal device first
|
||||||
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;
|
|
||||||
vm_register_device(&vm, "/dev/term/0", "terminal", nil, &console_device_ops);
|
vm_register_device(&vm, "/dev/term/0", "terminal", nil, &console_device_ops);
|
||||||
|
|
||||||
if (config.flags & FLAG_GUI_MODE) {
|
bool compilation_success = true;
|
||||||
u32 i;
|
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);
|
register_sdl_devices(&vm);
|
||||||
|
|
||||||
while (running) {
|
while (running) {
|
||||||
for (i = 0; i < vm.dc; i++) {
|
for (u32 i = 0; i < vm.dc; i++) {
|
||||||
Device *dev = &vm.devices[i];
|
Device *dev = &vm.devices[i];
|
||||||
if (strcmp(dev->type, "mouse") == 0) {
|
if (strcmp(dev->type, "mouse") == 0) {
|
||||||
MouseDeviceData *mouse = (MouseDeviceData *)dev->data;
|
MouseDeviceData *mouse = (MouseDeviceData *)dev->data;
|
||||||
|
@ -321,12 +376,12 @@ i32 main(i32 argc, char *argv[]) {
|
||||||
|
|
||||||
step_vm(&vm);
|
step_vm(&vm);
|
||||||
|
|
||||||
for (i = 0; i < vm.dc; i++) {
|
for (u32 i = 0; i < vm.dc; i++) {
|
||||||
Device *dev = &vm.devices[i];
|
Device *dev = &vm.devices[i];
|
||||||
if (strcmp(dev->type, "screen") == 0) {
|
if (strcmp(dev->type, "screen") == 0) {
|
||||||
ScreenDeviceData *screen = (ScreenDeviceData *)dev->data;
|
ScreenDeviceData *screen = (ScreenDeviceData *)dev->data;
|
||||||
if (screen->texture && screen->renderer) {
|
if (screen->texture && screen->renderer) {
|
||||||
SDL_UpdateTexture(screen->texture, NULL,
|
SDL_UpdateTexture(screen->texture, nil,
|
||||||
&vm.memory[screen->framebuffer_pos],
|
&vm.memory[screen->framebuffer_pos],
|
||||||
screen->width * sizeof(u32));
|
screen->width * sizeof(u32));
|
||||||
|
|
||||||
|
@ -343,7 +398,7 @@ i32 main(i32 argc, char *argv[]) {
|
||||||
(i32)((output_rect.h - screen->height * scale) / 2),
|
(i32)((output_rect.h - screen->height * scale) / 2),
|
||||||
(i32)(screen->width * scale), (i32)(screen->height * scale)};
|
(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);
|
SDL_RenderPresent(screen->renderer);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -356,5 +411,5 @@ i32 main(i32 argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -282,7 +282,7 @@ bool step_vm(VM *vm) {
|
||||||
case SYSCALL_DEVICE_WRITE: {
|
case SYSCALL_DEVICE_WRITE: {
|
||||||
Device *dev;
|
Device *dev;
|
||||||
u32 path_ptr, buffer_ptr, size;
|
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);
|
path_reg = read_u8(vm, code, vm->pc);
|
||||||
vm->pc++;
|
vm->pc++;
|
||||||
buffer_reg = read_u8(vm, code, vm->pc);
|
buffer_reg = read_u8(vm, code, vm->pc);
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue