92 lines
2.1 KiB
C++
92 lines
2.1 KiB
C++
#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_STORE,
|
|
|
|
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;
|
|
|
|
void vm_init(const unsigned char* program) {
|
|
vm_program = program;
|
|
vm_pc = 0;
|
|
vm_datastack = stack_new(MAX_DATA_STACK);
|
|
vm_callstack = stack_new(MAX_CALL_STACK);
|
|
}
|
|
|
|
|
|
void vm_step() {
|
|
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: vm_cycles++; break;
|
|
case OP_STORE: vm_cycles++; break;
|
|
case OP_JMP: vm_pc = vm_program[vm_pc] + (vm_program[vm_pc + 1] << 8); vm_cycles++; break;
|
|
case OP_JNT: vm_cycles++; break;
|
|
case OP_JTR: vm_cycles++; break;
|
|
case OP_JSR: vm_cycles++; break;
|
|
case OP_RET: vm_cycles++; break;
|
|
case OP_CALL: external_calls[vm_program[vm_pc++]](vm_datastack); vm_cycles++; break;
|
|
case OP_ADD: vm_cycles++; break;
|
|
case OP_SUB: vm_cycles++; break;
|
|
case OP_MUL: vm_cycles++; break;
|
|
case OP_DIV: vm_cycles++; break;
|
|
case OP_MOD: vm_cycles++; break;
|
|
case OP_AND: vm_cycles++; break;
|
|
case OP_OR: vm_cycles++; break;
|
|
case OP_NOT: vm_cycles++; break;
|
|
case OP_NEG: vm_cycles++; break;
|
|
case OP_INC: vm_cycles++; break;
|
|
case OP_EQ: vm_cycles++; break;
|
|
case OP_NEQ: vm_cycles++; break;
|
|
case OP_LT: vm_cycles++; break;
|
|
case OP_GT: vm_cycles++; break;
|
|
}
|
|
}
|
|
|
|
void vm_register_call(void(*callback)(t_stack&)) {
|
|
external_calls[numcallbacks++] = callback;
|
|
}
|