#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.data); 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 bytes_read; 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.ex; } 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; } void* addr = vm->data + pos; memcpy(dst, addr, size); return true; } void VM_registerRead(VM* vm, void* dst, RegisterCode code) { u8 index = code / 0x10; u8 part = code & 0xf; u8 offset = part / 8; u8 size = 8 / part; void* addr = (u8*)(&vm->registers.array[index]) + offset; memcpy(dst, addr, size); } void VM_registerWrite(VM* vm, void* src, RegisterCode code){ u8 index = code / 0x10; u8 part = code & 0xf; u8 offset = part / 8; u8 size = 8 / part; void* addr = (u8*)(&vm->registers.array[index]) + offset; memcpy(addr, src, size); }