Files
vm-test/main.c

136 lines
3.4 KiB
C

#include <stdint.h>
#include <stdio.h>
#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;
}