#include "vm.h" #define MAX_EXTERNAL_CALLS 256 #define MAX_DATA_STACK 256 #define MAX_CALL_STACK 256 enum OPS { OP_NOP = 0, OP_PUSH, OP_POP, OP_DUP, OP_LOAD, OP_LOADI, OP_STORE, OP_STOREI, OP_JMP, OP_JNT, OP_JTR, OP_JSR, OP_RET, OP_CALL, OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD, OP_AND, OP_OR, OP_NOT, OP_NEG, OP_INC, OP_EQ, OP_NEQ, OP_LT, OP_GT }; typedef void(*t_extcall)(t_stack&); t_extcall external_calls[MAX_EXTERNAL_CALLS]; int numcallbacks = 0; const unsigned char* vm_program = nullptr; int vm_pc = 0; int vm_cycles = 0; t_stack vm_datastack; t_stack vm_callstack; unsigned char mem[65536]; void vm_init(const unsigned char* program) { vm_program = program; vm_pc = 0; stack_init(vm_datastack, MAX_DATA_STACK); stack_init(vm_callstack, MAX_CALL_STACK); } inline unsigned short WORD() { vm_pc += 2; return vm_program[vm_pc - 2] + (vm_program[vm_pc - 1] << 8); } void vm_step() { char val; switch (vm_program[vm_pc++]) { case OP_NOP: vm_cycles++; break; case OP_PUSH: stack_push(vm_datastack, vm_program[vm_pc++]); vm_cycles++; break; case OP_POP: stack_pop(vm_datastack); vm_cycles++; break; case OP_DUP: stack_push(vm_datastack, stack_peek(vm_datastack)); vm_cycles++; break; case OP_LOAD: stack_push(vm_datastack, mem[WORD()]); vm_cycles++; break; case OP_LOADI: stack_push(vm_datastack, mem[WORD() + stack_pop(vm_datastack)]); vm_cycles++; break; case OP_STORE: mem[WORD()] = stack_pop(vm_datastack); vm_cycles++; break; case OP_STOREI: val = stack_pop(vm_datastack); mem[WORD() + stack_pop(vm_datastack)] = val; vm_cycles++; break; case OP_JMP: vm_pc = WORD(); vm_cycles++; break; case OP_JNT: if (stack_pop(vm_datastack) == 0) { vm_pc = WORD(); } vm_cycles++; break; case OP_JTR: if (stack_pop(vm_datastack) != 0) { vm_pc = WORD(); } vm_cycles++; break; case OP_JSR: stack_push(vm_callstack, vm_pc+2); vm_pc = WORD(); vm_cycles++; break; case OP_RET: vm_pc = stack_pop(vm_callstack); vm_cycles++; break; case OP_CALL: external_calls[vm_program[vm_pc++]](vm_datastack); vm_cycles++; break; case OP_ADD: stack_push(vm_datastack, stack_pop(vm_datastack) + stack_pop(vm_datastack)); vm_cycles++; break; case OP_SUB: stack_push(vm_datastack, stack_pop(vm_datastack) - stack_pop(vm_datastack)); vm_cycles++; break; case OP_MUL: stack_push(vm_datastack, stack_pop(vm_datastack) * stack_pop(vm_datastack)); vm_cycles++; break; case OP_DIV: stack_push(vm_datastack, stack_pop(vm_datastack) / stack_pop(vm_datastack)); vm_cycles++; break; case OP_MOD: stack_push(vm_datastack, stack_pop(vm_datastack) % stack_pop(vm_datastack)); vm_cycles++; break; case OP_AND: stack_push(vm_datastack, stack_pop(vm_datastack) & stack_pop(vm_datastack)); vm_cycles++; break; case OP_OR: stack_push(vm_datastack, stack_pop(vm_datastack) | stack_pop(vm_datastack)); vm_cycles++; break; case OP_NOT: stack_push(vm_datastack, !stack_pop(vm_datastack)); vm_cycles++; break; case OP_NEG: stack_push(vm_datastack, -stack_pop(vm_datastack)); vm_cycles++; break; case OP_INC: stack_push(vm_datastack, stack_pop(vm_datastack)+1); vm_cycles++; break; case OP_EQ: stack_push(vm_datastack, stack_pop(vm_datastack) == stack_pop(vm_datastack)); vm_cycles++; break; case OP_NEQ: stack_push(vm_datastack, stack_pop(vm_datastack) != stack_pop(vm_datastack)); vm_cycles++; break; case OP_LT: stack_push(vm_datastack, stack_pop(vm_datastack) < stack_pop(vm_datastack)); vm_cycles++; break; case OP_GT: stack_push(vm_datastack, stack_pop(vm_datastack) > stack_pop(vm_datastack)); vm_cycles++; break; } } void vm_register_call(void(*callback)(t_stack&)) { external_calls[numcallbacks++] = callback; }