Skip to content

Instantly share code, notes, and snippets.

@OrangeTide
Created April 21, 2017 00:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save OrangeTide/016a6af3b6d45120ffbd1e4f83d0da19 to your computer and use it in GitHub Desktop.
Save OrangeTide/016a6af3b6d45120ffbd1e4f83d0da19 to your computer and use it in GitHub Desktop.
virtual machine in one header file
/* 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