109 lines
2.9 KiB
C
109 lines
2.9 KiB
C
#include "VM.h"
|
|
#include "instructions/instructions.h"
|
|
|
|
void VM_construct(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);
|
|
}
|