I usually use c++ so it may not be best practice for c.  

This is a stack based toy vm and as a result it is very primitive, and it has no bitwise
instructions  

64k might be a bit overkill for a toy vm.  

coding is hard

```
#include <stdio.h>
#include "vm.h"

int main() {
    Vm *vm = new_vm();
    i32 buffer[] = {
        0x00000A01, /* push 0x0A(\n) */
        0x00004301, /* push 0x43(C)  */
        0x00004201, /* push 0x42(B)  */
        0x00004101, /* push 0x41(A)  */
        0x00000009, /* output */
        0x00000002, /* pop */
        0x00000009,
        0x00000002,
        0x00000009,
        0x00000002,
        0x00000009,
        0x00000000  /* halt */
    };
    for (int i = 0; i < sizeof(buffer); i++) {
        vm->mem[vm->pc+i] = buffer[i];
    }
    run_vm(vm);
    free_vm(vm);
    return 0;
}

```

vm.h

```
#ifndef VM_H_
#define VM_H_

#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>

typedef uint32_t i32; /* other numbers */
typedef int32_t si32; /* stack pointer */
typedef unsigned char byte;

typedef struct {
    i32 mem[0xffff]; /* approx. 64k */
    si32 sp;
    i32 pc;

    i32 raw;
    byte opc;
    i32 param;

    bool running;
} Vm;

Vm *new_vm();
void reset_vm(Vm *vm);
void free_vm(Vm *vm);
void run_vm(Vm *vm);

#endif

```

vm.c

```
#include <stdio.h>
#include "vm.h"

Vm *new_vm() {
    Vm *ret = (Vm*)malloc(sizeof(Vm));
    ret->pc = 1024; /* add space for the stack */
    ret->sp = -1;
    ret->running = true;
    return ret;
}

void reset_vm(Vm *vm) {
    vm->running = true;
    for (int i = 0; i < 0xffff; i++) {
        vm->mem[i] = 0;
    }
    vm->sp = -1;
    vm->pc = 1024;
}
void free_vm(Vm *vm) {
    free(vm);
    vm = NULL;
}

static void fetch(Vm *vm) {
    vm->raw = vm->mem[vm->pc++];
}

static void decode(Vm *vm) {
    /* style of opcode
     * 24 bits for parameter
     * a byte for the opcode 
    */
    vm->opc = vm->raw & 0xff;
    vm->param = (vm->raw & 0xffffff00) >> 8;
}

static void execute(Vm *vm) {
    switch(vm->opc) {
        case 0x00: /* halt */
            vm->running = false;
            printf("Halt\n");
        break;
        case 0x01: /* push */
            vm->mem[++vm->sp] = vm->param;
        break;
        case 0x02: /* pop */
            vm->mem[vm->sp--] = 0;
        break;
        case 0x03: /* store */
            vm->mem[ vm->mem[vm->sp - 1] ] = vm->mem[vm->sp];
        break;
        case 0x04: /* load */
            vm->mem[vm->sp + 1] = vm->mem[ vm->mem[vm->sp] ];
            ++vm->sp;
        break;
        case 0x05: /* add */
            vm->mem[vm->sp + 1] = vm->mem[vm->sp] + vm->mem[vm->sp - 1];
            ++vm->sp;
        break;
        case 0x06: /* sub */
            vm->mem[vm->sp + 1] = vm->mem[vm->sp - 1] - vm->mem[vm->sp];
            ++vm->sp;
        break;
        case 0x07: /* mul */
            vm->mem[vm->sp + 1] = vm->mem[vm->sp] * vm->mem[vm->sp - 1];
            ++vm->sp;
        break;
        case 0x08: /* div */
            vm->mem[vm->sp + 1] = vm->mem[vm->sp - 1] / vm->mem[vm->sp];
            ++vm->sp;
        break;
        case 0x09: /* outc */
            printf("%c", vm->mem[vm->sp]);
        break;
        case 0x0A: /* inpc */
            vm->mem[++vm->sp] = getchar();
        break;
    }
}

void run_vm(Vm *vm) {
    while(vm->running) {
        fetch(vm);
        decode(vm);
        execute(vm);
    }
}

```