-
-
Save OrangeTide/016a6af3b6d45120ffbd1e4f83d0da19 to your computer and use it in GitHub Desktop.
virtual machine in one header file
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
/* vm.h - virtual machine */ | |
#ifndef VM_H | |
#define VM_H | |
/* Goals: | |
* - no allocations in library | |
* - multithread safe | |
* - easy opcode extensions | |
* - single file | |
*/ | |
#include <stddef.h> | |
#include <stdint.h> | |
#include <errno.h> | |
#include <string.h> | |
/* Instruction Formats: | |
* | |
* MSB ................ LSB | |
* +----+-----+-----+-----+ | |
* | OP | C | B | A | Type I : Three 8-bit arguments | |
* +----+-----+-----+-----+ | |
* | OP | C | AB | Type II : 16-bit argument and 8-bit argument | |
* +----+-----+-----------+ | |
* | OP | ABC | Type III : One 24-bit argument | |
* +----+-----------------+ | |
*/ | |
/* OP : operation #0 to #255 */ | |
#define VM_DECODE_OP(i) ((i >> 24) & 255) | |
/* A (first argument) : 8-bit value */ | |
#define VM_DECODE_A(i) (i & 255) | |
/* B (second argument) : 8-bit value */ | |
#define VM_DECODE_B(i) ((i >> 8) & 255) | |
/* C (third argument) : 8-bit value */ | |
#define VM_DECODE_C(i) ((i >> 16) & 255) | |
/* AB : 16-bit value */ | |
#define VM_DECODE_AB(i) (i & 65535) | |
/* ABC : 24-bit value */ | |
#define VM_DECODE_ABC(i) (i & 16777215) | |
#define VM_CELL_MAX 0x7fffffffl | |
#define VM_CELL_MIN -0x80000000l | |
typedef struct vm_state vm_state_t; | |
typedef uint32_t vm_instr_t; | |
typedef int32_t vm_cell_t; | |
typedef struct vm_reg { | |
// enum vm_datatype type; | |
vm_cell_t v; /* value */ | |
} vm_data_t; | |
/* return 0 on success, -1 and set errno on error */ | |
typedef int (*vm_fun_t)(vm_state_t *ctx, vm_instr_t i); | |
struct vm_state { | |
uint32_t pc; | |
vm_data_t reg[256]; | |
vm_fun_t fun[256]; | |
const vm_instr_t *code; | |
size_t code_len; | |
vm_cell_t *data; | |
size_t data_len; | |
}; | |
static inline void | |
vm_init(vm_state_t *ctx, | |
const vm_instr_t *code, | |
size_t code_len, | |
vm_cell_t *data, | |
size_t data_len) | |
{ | |
ctx->code = code; | |
ctx->code_len = code_len; | |
ctx->data = data; | |
ctx->data_len = data_len; | |
ctx->pc = 0; | |
memset(ctx->reg, 0, sizeof(ctx->reg)); | |
memset(ctx->fun, 0, sizeof(ctx->fun)); | |
} | |
static inline int | |
vm_step(vm_state_t *ctx) | |
{ | |
#ifndef NDEBUG | |
if (ctx->pc >= ctx->code_len) { | |
errno = EFAULT; | |
return -1; | |
} | |
#endif | |
vm_instr_t instr = ctx->code[ctx->pc++]; | |
unsigned op = VM_DECODE_OP(instr); | |
vm_fun_t f = ctx->fun[op]; | |
if (f) | |
return f(ctx, instr); | |
errno = EINVAL; | |
return -1; | |
} | |
#endif /* VM_H */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment