#include "VM.h" #include "../instructions/instructions.h" void VM_init(VM* vm){ memset(vm, 0, sizeof(VM)); vm->state = VMState_Initialized; } void _VM_setError(VM* vm, cstr context, cstr format, ...){ va_list argv; char position_str[32]; sprintf(position_str, "[at 0x%x][", (u32)vm->current_pos); char* real_format = strcat_malloc(position_str, context, "] ", format); va_start(argv, format); char* NULLABLE(buf) = vsprintf_malloc(256, real_format, argv); va_end(argv); free(real_format); if(buf == NULL){ buf = malloc(16); strcpy(buf, "SPRINTF FAILED"); } vm->error_message = buf; vm->state = VMState_InternalError; } bool VM_setMemory(VM* vm, u8* data, size_t size){ if(data == NULL){ VM_setError(vm, "data == NULL"); return false; } if(size == 0){ VM_setError(vm, "size == 0"); return false; } vm->data = data; vm->data_size = size; return true; } i32 VM_boot(VM* vm){ if(vm->data == NULL){ VM_setError(vm, "data == null"); return -1; } vm->state = VMState_Executing; vm->current_pos = 0; while (vm->current_pos < vm->data_size){ u8 opcode = vm->data[vm->current_pos]; const Instruction* instr = Instruction_getByOpcode(opcode); // printfe("[at 0x%x] %02X %s\n", (u32)vm->current_pos, opcode, instr->name); if(instr == NULL){ VM_setError(vm, "unknown opcode %02X", opcode); return -1; } vm->current_pos++; i32 bytes_read = instr->implementation(vm); // internal error occured if(bytes_read < 0) return -1; if(vm->state == VMState_Exited) break; } if(vm->state != VMState_Exited){ VM_setError(vm, "unexpected end of the program"); return -1; } // exit code of the program should be in ax register return vm->registers.a.u32v0; } bool VM_dataRead(VM* vm, void* dst, size_t pos, size_t size){ if(pos + size >= vm->data_size){ VM_setError(vm, "can't read " IFWIN("%lli", "%li") " bytes from 0x%x, because only " IFWIN("%lli", "%li") " are avaliable", size, (u32)pos, vm->data_size - size); return false; } memcpy(dst, vm->data + pos, size); return true; }