-
-
Save madmann91/1da57b5d3d6056297266f3fd5b9c4213 to your computer and use it in GitHub Desktop.
Small VM example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdint.h> | |
#include <stddef.h> | |
#include <stdbool.h> | |
#include <stdio.h> | |
#include <inttypes.h> | |
#include <assert.h> | |
#define REG_COUNT 64 | |
#define OPCODE_LIST(f) \ | |
f(0, HALT, "halt") \ | |
f(1, JUMP, "jump") \ | |
f(4, CONST, "const") \ | |
f(2, LOAD, "load") \ | |
f(2, STORE, "store") \ | |
f(3, ADD, "add") \ | |
f(3, SUB, "sub") \ | |
f(3, MUL, "mul") \ | |
f(3, DIV, "div") \ | |
f(3, REM, "rem") \ | |
f(3, LSHFT, "lshft") \ | |
f(3, RSHFT, "rshft") \ | |
f(3, AND, "and") \ | |
f(3, OR, "or") \ | |
f(3, XOR, "xor") \ | |
f(4, SEL, "sel") \ | |
f(3, CMPEQ, "cmpeq") \ | |
f(3, CMPNE, "cmpne") \ | |
f(3, CMPGT, "cmpgt") \ | |
f(3, CMPGE, "cmpge") \ | |
f(3, CMPLT, "cmplt") \ | |
f(3, CMPLE, "cmple") | |
enum opcode { | |
#define f(n, op, name) OP##n##_##op, | |
OPCODE_LIST(f) | |
#undef f | |
}; | |
struct inst { | |
unsigned op : 5; | |
unsigned dst : 6; | |
unsigned src1 : 6; | |
unsigned src2 : 6; | |
unsigned src3 : 6; | |
}; | |
typedef uint64_t reg_t; | |
struct state { | |
reg_t regs[REG_COUNT]; | |
struct inst* prog; | |
size_t prog_counter; | |
}; | |
static inline const char* op_name(enum opcode opcode) { | |
switch (opcode) { | |
#define f(n, op, name) case OP##n##_##op: return name; | |
OPCODE_LIST(f) | |
#undef f | |
default: | |
assert(false && "unsupported opcode"); | |
return ""; | |
} | |
} | |
static inline size_t op_count(enum opcode opcode) { | |
switch (opcode) { | |
#define f(n, op, name) case OP##n##_##op: return n; | |
OPCODE_LIST(f) | |
#undef f | |
default: | |
assert(false && "unsupported opcode"); | |
return 0; | |
} | |
} | |
static inline reg_t const_value(const struct inst* inst) { | |
assert(inst->op == OP4_CONST); | |
return | |
((reg_t)inst->src1) | | |
(((reg_t)inst->src2) << 6) | | |
(((reg_t)inst->src3) << 12); | |
} | |
void print(const struct inst* inst) { | |
printf("%s", op_name(inst->op)); | |
if (inst->op == OP4_CONST) { | |
printf(" r%d, %"PRIu64"\n", inst->dst, const_value(inst)); | |
} else { | |
switch (op_count(inst->op)) { | |
case 0: printf("\n"); break; | |
case 1: printf(" r%d\n", inst->dst); break; | |
case 2: printf(" r%d, r%d\n", inst->dst, inst->src1); break; | |
case 3: printf(" r%d, r%d, r%d\n", inst->dst, inst->src1, inst->src2); break; | |
case 4: printf(" r%d, r%d, r%d, r%d\n", inst->dst, inst->src1, inst->src2, inst->src3); break; | |
default: break; | |
} | |
} | |
} | |
static inline bool eval(struct state* state, const struct inst* inst) { | |
switch (inst->op) { | |
#define BINARY_OP(opcode, op) \ | |
case opcode: \ | |
state->regs[inst->dst] = state->regs[inst->src1] op state->regs[inst->src2]; \ | |
return true; | |
BINARY_OP(OP3_ADD, +) | |
BINARY_OP(OP3_SUB, -) | |
BINARY_OP(OP3_MUL, *) | |
BINARY_OP(OP3_DIV, /) | |
BINARY_OP(OP3_REM, %) | |
BINARY_OP(OP3_CMPEQ, ==) | |
BINARY_OP(OP3_CMPNE, !=) | |
BINARY_OP(OP3_CMPGT, >) | |
BINARY_OP(OP3_CMPGE, >=) | |
BINARY_OP(OP3_CMPLT, >) | |
BINARY_OP(OP3_CMPLE, >=) | |
case OP4_SEL: | |
state->regs[inst->dst] = state->regs[inst->src1] | |
? state->regs[inst->src2] | |
: state->regs[inst->src3]; | |
return true; | |
case OP4_CONST: | |
state->regs[inst->dst] = const_value(inst); | |
return true; | |
case OP2_LOAD: | |
state->regs[inst->dst] = *(reg_t*)(state->regs[inst->src1]); | |
return true; | |
case OP2_STORE: | |
*(reg_t*)(state->regs[inst->dst]) = state->regs[inst->src1]; | |
return true; | |
case OP1_JUMP: | |
state->prog_counter = state->regs[inst->dst]; | |
return true; | |
default: | |
assert(false && "unsupported opcode"); | |
case OP0_HALT: | |
return false; | |
} | |
} | |
void run(struct state* state) { | |
do { | |
//print(&state->prog[state->prog_counter]); | |
} while (eval(state, &state->prog[state->prog_counter++])); | |
} | |
int main() { | |
struct inst prog[] = { | |
{ OP4_CONST, 0, 0x00 }, | |
{ OP4_CONST, 1, 0x01 }, | |
{ OP4_CONST, 2, 63, 63, 63 }, | |
{ OP4_CONST, 3, 0x09 }, | |
{ OP4_CONST, 4, 0x05 }, | |
{ OP3_SUB, 2, 2, 1 }, | |
{ OP3_CMPEQ, 5, 2, 0 }, | |
{ OP4_SEL, 6, 5, 3, 4 }, | |
{ OP1_JUMP, 6 }, | |
{ OP0_HALT } | |
}; | |
struct state state = { .prog = prog }; | |
run(&state); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment