From c88a6a993dc04fdac076bebac801b03af253a325 Mon Sep 17 00:00:00 2001 From: SpookyDervish <78246495+SpookyDervish@users.noreply.github.com> Date: Sat, 20 Dec 2025 13:29:49 +1100 Subject: [PATCH] save and load compiled vmbl files --- fib.vmbl | Bin 0 -> 1792 bytes src/exception.c | 9 ++++ src/exception.h | 4 +- src/main.c | 19 ++++--- src/vmbl.c | 137 +++++++++++++++++++++++++++++++++++++++++++++++- src/vmbl.h | 39 ++++++++++---- 6 files changed, 186 insertions(+), 22 deletions(-) create mode 100644 fib.vmbl diff --git a/fib.vmbl b/fib.vmbl new file mode 100644 index 0000000000000000000000000000000000000000..ec100392c8ad5bc36a8f471420a66ac3abbefd9e GIT binary patch literal 1792 zcmZQzzz!Ip!c0&a7at}LGld1lfYQuR8fFffG{b|G>SJ2<=%S +#include +#include VMBL_Exception VBML_ExecuteInstruction(VMBL_State *vmblState, VMBL_Instruction instruction) { switch (instruction.type) @@ -21,8 +23,34 @@ VMBL_Exception VBML_ExecuteInstruction(VMBL_State *vmblState, VMBL_Instruction i vmblState->stackSize--; break; - default: + case INSTRUCTION_DUPLICATE: + if (vmblState->stackSize - instruction.opperand <= 0) { + return (VMBL_Exception){ EXCEPTION_STACK_UNDERFLOW }; + } + if (vmblState->stackSize >= VMBL_STACK_SIZE) { + return (VMBL_Exception){ EXCEPTION_STACK_OVERFLOW }; + } + + if (instruction.opperand < 0) { + return (VMBL_Exception) { EXCEPTION_INVALID_OPPERAND }; + } + + vmblState->stack[vmblState->stackSize++] = vmblState->stack[vmblState->stackSize - 1 - instruction.opperand]; + + break; + + case INSTRUCTION_JUMP: + + vmblState->ip = instruction.opperand; + + break; + + case INSTRUCTION_HALT: + vmblState->halted = true; + break; + + default: return (VMBL_Exception) { EXCEPTION_INVALID_OPCODE }; break; } @@ -36,10 +64,115 @@ void VMBL_Dump(VMBL_State vmblState, VMBL_Exception exception) { if (vmblState.stackSize > 0) { for (size_t i = 0; i < vmblState.stackSize; i++) { - fprintf(stderr, " 0x%lX: %ld\n", i, vmblState.stack[i]); + fprintf(stderr, " 0x%lX: 0x%ld\n", i, vmblState.stack[i]); } } else { fprintf(stderr, " [empty]\n"); } +} + +void VMBL_StartVM(VMBL_State *vmblState) { + for (;;) + { + // fetch next instruction + if (vmblState->ip >= VMBL_PROGRAM_SIZE) { + VMBL_Dump(*vmblState, (VMBL_Exception){ EXCEPTION_INVALID_INSTRUCTION_ACCESS}); + return; + } + + + VMBL_Instruction instruction = vmblState->program[vmblState->ip++]; + printf("%s 0x%lx\n", instructionTypeToCStr(instruction.type), instruction.opperand); + + VMBL_Exception exception = VBML_ExecuteInstruction(vmblState, instruction); + + if (exception.type != EXCEPTION_NONE) { + VMBL_Dump(*vmblState, exception); + return; + } + + if (vmblState->halted) { + return; + } + + } + +} + + +// executable operations +void VMBL_LoadExecutable(VMBL_State *vmblState, VMBL_Instruction *program, size_t programSize) { + if (programSize > VMBL_PROGRAM_SIZE) { + fprintf(stderr, "VMBL: failed to load program from memory because it is %ld words in size, while the max size is %d.", programSize, VMBL_PROGRAM_SIZE); + exit(1); + } + + memcpy(vmblState->program, program, sizeof(program[0]) * programSize); + + vmblState->programSize = programSize; +} + +void VMBL_LoadExecutableFromFile(VMBL_State *vmblState, const char* filePath) { + FILE *file = fopen(filePath, "rb"); + + if (file == NULL) { + perror("VMBL: Failed to open file"); + exit(1); + } + + fseek(file, 0, SEEK_END); + long size = ftell(file); + rewind(file); + + size_t programSize = size / sizeof(vmblState->program[0]); + VMBL_Instruction program[programSize]; + fread(program, sizeof(program[0]), programSize, file); + + VMBL_LoadExecutable(vmblState, program, programSize); + + fclose(file); + +} + +void VMBL_SaveExecutable(const char* filePath, VMBL_Instruction *program, size_t programSize) { + FILE *file = fopen(filePath, "wb"); + + if (file == NULL) { + perror("VMBL: Failed to open file"); + exit(1); + } + + fwrite(program, sizeof(program[0]), programSize, file); + fclose(file); +} + +char *instructionTypeToCStr(InstructionType type) { + switch (type) + { + + case INSTRUCTION_PUSH: + return "PUSH"; + break; + + case INSTRUCTION_ADD: + return "ADD "; + break; + + case INSTRUCTION_DUPLICATE: + return "DUP "; + break; + + case INSTRUCTION_JUMP: + return "JMP "; + break; + + case INSTRUCTION_HALT: + return "HALT"; + break; + + default: + return "??? "; + break; + } } \ No newline at end of file diff --git a/src/vmbl.h b/src/vmbl.h index c4fb320..5b337c1 100644 --- a/src/vmbl.h +++ b/src/vmbl.h @@ -4,34 +4,55 @@ #include #include #include +#include #include "exception.h" #define VMBL_STACK_SIZE 1024 +#define VMBL_PROGRAM_SIZE 1024 typedef int64_t Word; typedef enum { INSTRUCTION_PUSH, - INSTRUCTION_ADD + INSTRUCTION_ADD, + INSTRUCTION_DUPLICATE, + INSTRUCTION_JUMP, + INSTRUCTION_HALT } InstructionType; -typedef struct -{ - Word stack[VMBL_STACK_SIZE]; - size_t stackSize; -} VMBL_State; - typedef struct { InstructionType type; Word opperand; } VMBL_Instruction; -#define MAKE_INST_PUSH(value) (VMBL_Instruction) { .type = INSTRUCTION_PUSH, .opperand = (value) } -#define MAKE_INST_ADD (VMBL_Instruction) { .type = INSTRUCTION_ADD } +typedef struct +{ + Word stack[VMBL_STACK_SIZE]; + size_t stackSize; + + VMBL_Instruction program[VMBL_PROGRAM_SIZE]; + size_t programSize; + + long ip; + bool halted; +} VMBL_State; + +#define MAKE_INST_PUSH(value) (VMBL_Instruction) { .type = INSTRUCTION_PUSH, .opperand = (value) } +#define MAKE_INST_ADD (VMBL_Instruction) { .type = INSTRUCTION_ADD, } +#define MAKE_INST_DUP(value) (VMBL_Instruction) { .type = INSTRUCTION_DUPLICATE, .opperand = (value) } +#define MAKE_INST_JMP(value) (VMBL_Instruction) { .type = INSTRUCTION_JUMP , .opperand = (value) } +#define MAKE_INST_HALT (VMBL_Instruction) { .type = INSTRUCTION_HALT } VMBL_Exception VBML_ExecuteInstruction(VMBL_State *vmblState, VMBL_Instruction instruction); void VMBL_Dump(VMBL_State vmblState, VMBL_Exception exception); +void VMBL_StartVM(VMBL_State *vmblState); + +void VMBL_LoadExecutable(VMBL_State *vmblState, VMBL_Instruction *program, size_t programSize); +void VMBL_LoadExecutableFromFile(VMBL_State *vmblState, const char* filePath); +void VMBL_SaveExecutable(const char* filePath, VMBL_Instruction *program, size_t programSize); + +char *instructionTypeToCStr(InstructionType type); #endif // !VMBL_H