207 lines
6.2 KiB
C
207 lines
6.2 KiB
C
#include "VM/VM.h"
|
|
#include "instructions/instructions.h"
|
|
#include "collections/List.h"
|
|
#include "compiler/Compiler.h"
|
|
#include "VM/Display/Display.h"
|
|
#include <SDL3/SDL.h>
|
|
|
|
#define arg_is(STR) (strcmp(argv[argi], STR) == 0)
|
|
|
|
i32 compileSources(cstr source_file, cstr out_file, bool debug_log);
|
|
i32 bootFromImage(cstr image_file);
|
|
|
|
#define assert_sdl(EXPR) if(!(EXPR)) { printf("assert failed: %s\nSDL_Error: %s\n", #EXPR, SDL_GetError()); return false; }
|
|
|
|
bool test_display(){
|
|
Display* display = Display_create(STR("le display"), 1600, 900, DisplayFlags_Default);
|
|
assert_sdl(display != NULL);
|
|
|
|
i64 fps = 60;
|
|
i64 nsec_per_frame = 1e9 / fps;
|
|
for(u32 i = 0; i < 600; i++){
|
|
static i64 last_frame_time = 0;
|
|
i64 current_frame_time = SDL_GetTicksNS();
|
|
i64 delta_time = current_frame_time - last_frame_time;
|
|
last_frame_time = current_frame_time;
|
|
|
|
SDL_Event event;
|
|
while(SDL_PollEvent(&event)) {
|
|
if(event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED){
|
|
printfe("event WINDOW_CLOSE");
|
|
return 0;
|
|
}
|
|
if(event.type == SDL_EVENT_QUIT){
|
|
printfe("event QUIT");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
assert_sdl(Display_setDrawingColor(display, ColorRGBA_create(200, 200, 200, 255)));
|
|
assert_sdl(Display_clear(display));
|
|
assert_sdl(Display_setDrawingColor(display, ColorRGBA_create(240, 40, 40, 255)));
|
|
assert_sdl(Display_fillRect(display, Rect_create(i, i, 64, 64)));
|
|
assert_sdl(Display_swapBuffers(display));
|
|
|
|
i64 time_ellapsed = SDL_GetTicksNS() - last_frame_time;
|
|
i64 delay = nsec_per_frame - time_ellapsed;
|
|
if (delay > 0) {
|
|
SDL_DelayNS(delay);
|
|
}
|
|
}
|
|
|
|
Display_destroy(display);
|
|
return true;
|
|
}
|
|
|
|
i32 main(const i32 argc, cstr* argv){
|
|
test_display();
|
|
return 0;
|
|
|
|
if(argc < 2){
|
|
printfe("ERROR: no arguments provided. Use --help to know more.\n");
|
|
return 1;
|
|
}
|
|
|
|
bool boot = false;
|
|
cstr NULLABLE(image_file) = NULL;
|
|
|
|
bool compile = false;
|
|
cstr NULLABLE(out_file) = NULL;
|
|
cstr NULLABLE(source_file) = NULL;
|
|
|
|
bool debug_log = false;
|
|
|
|
for(i32 argi = 1; argi < argc; argi++){
|
|
if(arg_is("-h") || arg_is("--help")){
|
|
printf(
|
|
"-h, --help Show this message.\n"
|
|
"-op, --opcodes Show list of all instructions.\n"
|
|
"-i, --image [FILE] Boot VM using image file.\n"
|
|
"-c, --compile [SOURCE_FILE] [OUT_FILE] Compile assembly source files to machine code.\n"
|
|
"-d, --debug Enable debug log.\n"
|
|
);
|
|
return 0;
|
|
}
|
|
else if(arg_is("-op") || arg_is("--opcodes")){
|
|
for(u8 opcode = 0; opcode < 255; opcode++){
|
|
const Instruction* instr = Instruction_getByOpcode(opcode);
|
|
if(instr != NULL){
|
|
printf("%02X %s\n", opcode, instr->name.data);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
else if(arg_is("-i") || arg_is("--image")){
|
|
if(boot){
|
|
printfe("--image flag is set already\n");
|
|
return 1;
|
|
}
|
|
|
|
boot = true;
|
|
if(++argi >= argc){
|
|
printfe("ERROR: no image file specified\n");
|
|
return 1;
|
|
}
|
|
image_file = argv[argi];
|
|
}
|
|
else if(arg_is("-c") || arg_is("--compile")){
|
|
if(compile){
|
|
printfe("--compile flag is set already\n");
|
|
return 1;
|
|
}
|
|
|
|
compile = true;
|
|
if(++argi >= argc){
|
|
printfe("ERROR: no source file file specified\n");
|
|
return 1;
|
|
}
|
|
source_file = argv[argi];
|
|
|
|
if(++argi >= argc){
|
|
printfe("ERROR: no output file file specified\n");
|
|
return 1;
|
|
}
|
|
out_file = argv[argi];
|
|
}
|
|
else if(arg_is("-d") || arg_is("--debug")){
|
|
debug_log = true;
|
|
}
|
|
else {
|
|
printfe("ERROR: unknown argument '%s'\n", argv[argi]);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
i32 exit_code = 0;
|
|
if(compile){
|
|
exit_code = compileSources(source_file, out_file, debug_log);
|
|
}
|
|
if(exit_code == 0 && boot){
|
|
exit_code = bootFromImage(image_file);
|
|
}
|
|
|
|
// frees global variables to supress valgrind memory leak errors
|
|
Instruction_freeSearchStructs();
|
|
return exit_code;
|
|
}
|
|
|
|
i32 bootFromImage(cstr image_file){
|
|
FILE* file = fopen(image_file, "rb");
|
|
if(file == NULL){
|
|
printfe("ERROR: can't open file '%s'\n", image_file);
|
|
return 1;
|
|
}
|
|
|
|
const size_t buffer_size = 1024*1024;
|
|
u8* vm_memory = malloc(buffer_size);
|
|
memset(vm_memory, 0, buffer_size);
|
|
|
|
size_t bytes_read = fread(vm_memory, 1, buffer_size, file);
|
|
fclose(file);
|
|
if(bytes_read == (size_t)EOF){
|
|
printfe("ERROR: can't read file '%s'\n", image_file);
|
|
free(vm_memory);
|
|
return 1;
|
|
}
|
|
|
|
VM vm;
|
|
VM_init(&vm);
|
|
|
|
i32 exit_code = 1;
|
|
if(VM_setMemory(&vm, vm_memory, bytes_read)){
|
|
exit_code = VM_boot(&vm);
|
|
}
|
|
if(vm.state == VMState_InternalError){
|
|
if(vm.error_message){
|
|
printfe("VM ERROR: %s\n", vm.error_message);
|
|
free(vm.error_message);
|
|
}
|
|
else printfe("VM ERROR: unknown (error_message is null)\n");
|
|
}
|
|
|
|
if(exit_code != 0){
|
|
printfe("program exited with code %i\n", exit_code);
|
|
}
|
|
|
|
free(vm_memory);
|
|
return exit_code;
|
|
}
|
|
|
|
i32 compileSources(cstr source_file, cstr out_file, bool debug_log){
|
|
Compiler cmp;
|
|
Compiler_init(&cmp);
|
|
bool success = Compiler_compile(&cmp, source_file, out_file, debug_log);
|
|
if(!success){
|
|
if(cmp.error_message){
|
|
printfe("COMPILER ERROR: %s\n", cmp.error_message);
|
|
free(cmp.error_message);
|
|
}
|
|
else printfe("COMPILER ERROR: unknown (error_message is null)\n");
|
|
Compiler_free(&cmp);
|
|
return 111;
|
|
}
|
|
|
|
Compiler_free(&cmp);
|
|
return 0;
|
|
}
|