TCPU/src/VM/VM.c
2025-04-18 02:46:46 +05:00

109 lines
2.9 KiB
C

#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);
}