|
|
|
@@ -4,6 +4,9 @@
|
|
|
|
|
#define MAX_DATA_STACK 256
|
|
|
|
|
#define MAX_CALL_STACK 256
|
|
|
|
|
|
|
|
|
|
typedef unsigned char byte;
|
|
|
|
|
typedef unsigned short word;
|
|
|
|
|
|
|
|
|
|
enum OPS {
|
|
|
|
|
OP_NOP = 0,
|
|
|
|
|
OP_PUSH,
|
|
|
|
@@ -21,6 +24,8 @@ enum OPS {
|
|
|
|
|
OP_SETX,
|
|
|
|
|
OP_SETY,
|
|
|
|
|
OP_SETZ,
|
|
|
|
|
OP_GETY,
|
|
|
|
|
OP_GETZ,
|
|
|
|
|
OP_INCX,
|
|
|
|
|
OP_DECX,
|
|
|
|
|
OP_INCY,
|
|
|
|
@@ -62,6 +67,7 @@ enum OPS {
|
|
|
|
|
OP_NEG,
|
|
|
|
|
OP_INC,
|
|
|
|
|
OP_DEC,
|
|
|
|
|
OP_CONCAT,
|
|
|
|
|
|
|
|
|
|
OP_EQ,
|
|
|
|
|
OP_NEQ,
|
|
|
|
@@ -69,12 +75,20 @@ enum OPS {
|
|
|
|
|
OP_GT,
|
|
|
|
|
OP_LEQ,
|
|
|
|
|
OP_GEQ,
|
|
|
|
|
|
|
|
|
|
OP_IN,
|
|
|
|
|
OP_OUT,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
typedef void(*t_extcall)(t_stack&);
|
|
|
|
|
t_extcall external_calls[MAX_EXTERNAL_CALLS];
|
|
|
|
|
int numcallbacks = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef void(*t_out_port)(const byte&);
|
|
|
|
|
typedef byte(*t_in_port)();
|
|
|
|
|
t_out_port out_ports[256];
|
|
|
|
|
t_in_port in_ports[256];
|
|
|
|
|
|
|
|
|
|
const unsigned char* vm_program = nullptr;
|
|
|
|
|
int vm_pc = 0;
|
|
|
|
|
int vm_cycles = 0;
|
|
|
|
@@ -112,6 +126,8 @@ void vm_step() {
|
|
|
|
|
case OP_SETX: rX = WORD(); vm_cycles++; break;
|
|
|
|
|
case OP_SETY: rY = stack_pop(vm_datastack); vm_cycles++; break;
|
|
|
|
|
case OP_SETZ: rZ = stack_pop(vm_datastack); vm_cycles++; break;
|
|
|
|
|
case OP_GETY: stack_push(vm_datastack, rY); vm_cycles++; break;
|
|
|
|
|
case OP_GETZ: stack_push(vm_datastack, rZ); vm_cycles++; break;
|
|
|
|
|
case OP_INCX: rX++; vm_cycles++; break;
|
|
|
|
|
case OP_DECX: rX--; vm_cycles++; break;
|
|
|
|
|
case OP_INCY: rY++; vm_cycles++; break;
|
|
|
|
@@ -125,19 +141,19 @@ void vm_step() {
|
|
|
|
|
case OP_RET: rZ = stack_pop(vm_callstack); rY = stack_pop(vm_callstack); rX = (stack_pop(vm_callstack) << 8) + stack_pop(vm_callstack); 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_RJ: vm_pc += vm_program[vm_pc]; vm_cycles++; break;
|
|
|
|
|
case OP_RB: vm_pc -= vm_program[vm_pc]; vm_cycles++; break;
|
|
|
|
|
case OP_RB: vm_pc -= vm_program[vm_pc]+1; vm_cycles++; break;
|
|
|
|
|
case OP_RJZ: if (stack_pop(vm_datastack) == 0) vm_pc += vm_program[vm_pc]; vm_cycles++; break;
|
|
|
|
|
case OP_RJN: if (stack_pop(vm_datastack) != 0) vm_pc += vm_program[vm_pc]; vm_cycles++; break;
|
|
|
|
|
case OP_RBZ: if (stack_pop(vm_datastack) == 0) vm_pc -= vm_program[vm_pc]; vm_cycles++; break;
|
|
|
|
|
case OP_RBN: if (stack_pop(vm_datastack) != 0) vm_pc -= vm_program[vm_pc]; vm_cycles++; break;
|
|
|
|
|
case OP_RBZ: if (stack_pop(vm_datastack) == 0) vm_pc -= vm_program[vm_pc]+1; vm_cycles++; break;
|
|
|
|
|
case OP_RBN: if (stack_pop(vm_datastack) != 0) vm_pc -= vm_program[vm_pc]+1; vm_cycles++; break;
|
|
|
|
|
case OP_RJYZ: if (rY == 0) vm_pc += vm_program[vm_pc]; vm_cycles++; break;
|
|
|
|
|
case OP_RJYN: if (rY != 0) vm_pc += vm_program[vm_pc]; vm_cycles++; break;
|
|
|
|
|
case OP_RBYZ: if (rY == 0) vm_pc -= vm_program[vm_pc]; vm_cycles++; break;
|
|
|
|
|
case OP_RBYN: if (rY != 0) vm_pc -= vm_program[vm_pc]; vm_cycles++; break;
|
|
|
|
|
case OP_RBYZ: if (rY == 0) vm_pc -= vm_program[vm_pc]+1; vm_cycles++; break;
|
|
|
|
|
case OP_RBYN: if (rY != 0) vm_pc -= vm_program[vm_pc]+1; vm_cycles++; break;
|
|
|
|
|
case OP_RJZZ: if (rZ == 0) vm_pc += vm_program[vm_pc]; vm_cycles++; break;
|
|
|
|
|
case OP_RJZN: if (rZ != 0) vm_pc += vm_program[vm_pc]; vm_cycles++; break;
|
|
|
|
|
case OP_RBZZ: if (rZ == 0) vm_pc -= vm_program[vm_pc]; vm_cycles++; break;
|
|
|
|
|
case OP_RBZN: if (rZ != 0) vm_pc -= vm_program[vm_pc]; vm_cycles++; break;
|
|
|
|
|
case OP_RBZZ: if (rZ == 0) vm_pc -= vm_program[vm_pc]+1; vm_cycles++; break;
|
|
|
|
|
case OP_RBZN: if (rZ != 0) vm_pc -= vm_program[vm_pc]+1; 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;
|
|
|
|
@@ -149,15 +165,32 @@ void vm_step() {
|
|
|
|
|
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_DEC: stack_push(vm_datastack, stack_pop(vm_datastack) - 1); vm_cycles++; break;
|
|
|
|
|
case OP_CONCAT:
|
|
|
|
|
val = stack_pop(vm_datastack);
|
|
|
|
|
for (int i = 0; i < val; i++) stack_push(vm_callstack, stack_pop(vm_datastack));
|
|
|
|
|
val2 = stack_pop(vm_datastack);
|
|
|
|
|
for (int i = 0; i < val; i++) stack_push(vm_datastack, stack_pop(vm_callstack));
|
|
|
|
|
stack_push(vm_datastack, val + val2);
|
|
|
|
|
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;
|
|
|
|
|
case OP_LEQ: stack_push(vm_datastack, stack_pop(vm_datastack) <= stack_pop(vm_datastack)); vm_cycles++; break;
|
|
|
|
|
case OP_GEQ: stack_push(vm_datastack, stack_pop(vm_datastack) >= stack_pop(vm_datastack)); vm_cycles++; break;
|
|
|
|
|
case OP_IN: stack_push(vm_datastack, in_ports[vm_program[vm_pc++]]()); vm_cycles++; break;
|
|
|
|
|
case OP_OUT: out_ports[vm_program[vm_pc++]](stack_pop(vm_datastack)); vm_cycles++; break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void vm_register_call(void(*callback)(t_stack&)) {
|
|
|
|
|
external_calls[numcallbacks++] = callback;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void vm_register_in_port(const byte port, t_in_port callback) {
|
|
|
|
|
in_ports[port] = callback;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void vm_register_out_port(const byte port, t_out_port callback) {
|
|
|
|
|
out_ports[port] = callback;
|
|
|
|
|
}
|
|
|
|
|