diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..8896099 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "cSpell.words": [ + "VMOP" + ] +} \ No newline at end of file diff --git a/main.c b/main.c new file mode 100644 index 0000000..ba80169 --- /dev/null +++ b/main.c @@ -0,0 +1,136 @@ +#include +#include + +#define REGISTER_SIZE (1 << 6) // 64 register , overkill IK + +/* +the types are defined using the X macro patter in this order +(enum name, actual c type, the value used in the union) +*/ +#define VM_TYPES \ + X(UINT8, uint8_t, _uint8_val) \ + X(UINT16, uint16_t, _uint16_val) \ + X(UINT32, uint32_t, _uint32_val) \ + X(UINT64, uint64_t, _uint64_val) \ + X(PTR, uintptr_t, _uintptr_val) + +#define VM_OPCODES \ + X(OP_ADD, vm_add) \ + X(OP_SET_REG, vm_set_reg) \ + X(OP_PRINT, vm_print) \ + X(OP_END, vm_end) + +// given context pointer perform operations on the register +#define GET_REGISTER(CTX_P, IDX) (CTX_P)->registers[(IDX)] + +#define SET_REGISTER(CTX_P, IDX, TYPE, VALUE) ((CTX_P)->registers[(IDX)].type = (TYPE), vm_set_value((CTX_P), (IDX), (TYPE), (VALUE))) + +// clang-format off +typedef enum { + #define X(name, ctype, field) name, + VM_TYPES + #undef X +} VMTypes; + +typedef enum { + #define X(op_name, op_func) op_name, + VM_OPCODES + #undef X +} VMOPCodes; + +typedef struct { + VMTypes type; + + union { + #define X(name, ctype, field) ctype field; + VM_TYPES + #undef X + } value; +} VMType; + +typedef struct { + VMType registers[REGISTER_SIZE]; +} VMCtx; + +typedef void (*vm_op_func_t)(VMCtx *, uint8_t *, size_t *); +// clang-format on + +void vm_set_value(VMCtx *ctx, size_t idx, VMTypes type, uintptr_t value) { + // clang-format off + switch(type) { + #define X(name, ctype, field) \ + case name: { \ + ctx->registers[idx].value.field = value; \ + break; \ + } \ + + VM_TYPES + #undef X + } + // clang-format on +} + +void vm_add(VMCtx *ctx, uint8_t *program, size_t *pc) { + (*pc)++; + size_t op1_idx = program[(*pc)++]; + size_t op2_idx = program[(*pc)++]; + size_t dest_idx = program[(*pc)++]; + + vm_set_value(ctx, dest_idx, UINT8, GET_REGISTER(ctx, op1_idx).value._uint8_val + GET_REGISTER(ctx, op2_idx).value._uint8_val); +} + +void vm_set_reg(VMCtx *ctx, uint8_t *program, size_t *pc) { + (*pc)++; + size_t idx = program[(*pc)++]; + VMTypes type = (VMTypes)program[(*pc)++]; + vm_set_value(ctx, idx, type, program[(*pc)++]); +} + +void vm_print(VMCtx *ctx, uint8_t *program, size_t *pc) { + (*pc)++; + printf("vm_print %d\n", GET_REGISTER(ctx, program[(*pc)++]).value._uint8_val); +} +void vm_end(VMCtx *ctx, uint8_t *program, size_t *pc) { + (*pc)++; +} +// clang-format off +vm_op_func_t vm_funcs[] = { + #define X(op_name, op_func) [op_name] = op_func, + VM_OPCODES + #undef X +}; + +// clang-format on + +void vm_eval(VMCtx *ctx, uint8_t *program) { + size_t pc = 0; + + while (program[pc] != OP_END) { + // pc++; + vm_funcs[program[pc]](ctx, program, &pc); + } +} + +int main() { + + VMCtx ctx = {0}; + + // clang-format off + uint8_t program[] = { + OP_SET_REG, 0, UINT8, 35, + OP_SET_REG, 1, UINT8, 34, + OP_ADD, 0, 1, 2, + OP_PRINT, 2, + OP_END + }; + // clang-format on + + // SET_REGISTER(&ctx, 0, UINT8, 12); + // SET_REGISTER(&ctx, 1, UINT8, 15); + + // printf("Add = %d\n", ctx.registers[0].value._uint8_val + ctx.registers[1].value._uint8_val); + + vm_eval(&ctx, program); + + return 0; +} \ No newline at end of file