Skip to content

Instantly share code, notes, and snippets.

@pauldub
Created September 4, 2014 07:22
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 pauldub/e4445f2dfd868e30b67b to your computer and use it in GitHub Desktop.
Save pauldub/e4445f2dfd868e30b67b to your computer and use it in GitHub Desktop.
#include <stdlib.h>
#include <stdio.h>
#include <u/libu.h>
int facility = LOG_LOCAL0;
typedef struct stack {
void *mem;
int p;
int len;
size_t val_sz;
} stack;
stack *stack_new(int len, size_t val_sz);
void stack_destroy(stack *s);
int stack_push(stack *s, void *v);
void *stack_pop(stack *s);
stack *stack_new(int len, size_t val_sz)
{
stack *s = NULL;
void *mem = NULL;
dbg_err_sif((s = u_malloc(sizeof(stack))) == NULL);
dbg_err_sif((mem = u_malloc(sizeof(val_sz) * len)) == NULL);
s->len = len;
s->val_sz = val_sz;
s->mem = mem;
s->p = 1;
return s;
err:
if(mem) {
u_free(mem);
}
if(s) {
u_free(s);
}
printf("Failed to allocate memory for (stack *)s or (void *)mem.");
return NULL;
}
void stack_destroy(stack *s)
{
if(s) {
if(s->mem) {
u_free(s->mem);
}
u_free(s);
}
}
int stack_push(stack *s, void *v)
{
dbg_err_sif(s->p > s->len);
memcpy(s->mem + ((s->p - 1) * s->val_sz), v, s->val_sz);
s->p += 1;
return 0;
err:
return ~0;
}
void *stack_pop(stack *s)
{
void *v = NULL;
if(s->p > 0) {
v = s->mem + ((s->p - 2) * s->val_sz);
if(s->p > 1) {
s->p -= 1;
}
}
return v;
}
#define VM_REGISTERS_SZ 16
#define VM_INSTRUCTIONS_SZ 65536
#define VM_STACK_SZ 256
#define NOP 0x00
#define PUSH 0x01
#define POP 0x02
#define LOAD 0x03
#define STORE 0x04
#define JMP 0x05
#define JZ 0x06
#define JNZ 0x07
#define ADD 0x08
#define SUB 0x09
#define MUL 0x0a
#define DIV 0x0b
#define PRINT 0x0c
#define STOP 0x0d
typedef struct vm {
stack *s; // stack
unsigned short r[VM_REGISTERS_SZ]; // registers
unsigned char i[VM_INSTRUCTIONS_SZ]; // instructions
unsigned short ip; // current instruction
} vm;
vm *vm_new();
void vm_destroy(vm *v);
int vm_run(vm *v);
int vm_readn(vm *v, int n);
void vm_push(vm *v, int n);
int vm_pop(vm *v);
void vm_load(vm *v, int n);
void vm_store(vm *v, int n);
void vm_jmp(vm *v, int n);
void vm_jz(vm *v, int n);
void vm_jnz(vm *v, int n);
void vm_add(vm *v);
void vm_sub(vm *v);
void vm_mul(vm *v);
void vm_div(vm *v);
void vm_print(vm *v);
void vm_print_op(int op)
{
char *op_str = NULL;
switch(op) {
case NOP:
op_str = "NOP";
break;
case PUSH:
op_str = "PUSH";
break;
case POP:
op_str = "POP";
break;
case LOAD:
op_str = "LOAD";
break;
case STORE:
op_str = "STORE";
break;
case JMP:
op_str = "JMP";
break;
case JZ:
op_str = "JZ";
break;
case JNZ:
op_str = "JNZ";
break;
case ADD:
op_str = "ADD";
break;
case SUB:
op_str = "SUB";
break;
case MUL:
op_str = "MUL";
break;
case DIV:
op_str = "DIV";
break;
case PRINT:
op_str = "PRINT";
break;
case STOP:
op_str = "STOP";
break;
default:
u_con("Unknown: 0x%x", op);
}
if(op_str) {
printf("%s", op_str);
}
}
vm *vm_new(char *i, int i_sz)
{
vm *v = NULL;
stack *s = NULL;
dbg_err_sif(i_sz > VM_INSTRUCTIONS_SZ);
dbg_err_sif((v = u_malloc(sizeof(vm))) == NULL);
dbg_err_sif((s = stack_new(VM_STACK_SZ, sizeof(int))) == NULL);
v->s = s;
memcpy(&v->i, i, i_sz);
return v;
err:
if(s) {
stack_destroy(s);
}
if(v) {
vm_destroy(v);
}
return NULL;
}
void vm_destroy(vm *v)
{
if(v) {
if(v->s) {
stack_destroy(v->s);
}
u_free(v);
}
}
int vm_run(vm *v)
{
int val;
v->ip = 0;
v->s->p = 0;
int ni = 0;
for(int i = 0; i < 50; i++) {
printf("0x%x ", i);
vm_print_op(v->i[i]);
printf(" \n");
}
while(1) {
ni++;
if(ni - 1 > 25) {
break;
}
switch(v->i[v->ip]) {
case NOP:
v->ip++;
break;
case PUSH:
v->ip++;
val = vm_readn(v, 4);
vm_push(v, val);
break;
case POP:
v->ip++;
vm_pop(v);
break;
case LOAD:
v->ip++;
val = vm_readn(v, 1);
vm_load(v, val);
break;
case STORE:
v->ip++;
val = vm_readn(v, 1);
vm_store(v, val);
break;
case JMP:
v->ip++;
val = vm_readn(v, 2);
vm_jmp(v, val);
break;
case JZ:
v->ip++;
val = vm_readn(v, 2);
vm_jz(v, val);
break;
case JNZ:
v->ip++;
val = vm_readn(v, 2);
vm_jnz(v, val);
break;
case ADD:
v->ip++;
vm_add(v);
break;
case SUB:
v->ip++;
vm_sub(v);
break;
case MUL:
v->ip++;
vm_mul(v);
break;
case DIV:
v->ip++;
vm_div(v);
break;
case PRINT:
v->ip++;
vm_print(v);
break;
case STOP:
v->ip ++;
break;
default:
u_err("invalid instruction: %x", v->i[v->ip]);
return ~0;
}
}
return 0;
}
void vm_push(vm *v, int n)
{
u_con("push: 0x%x", n);
stack_push(v->s, &n);
}
int vm_pop(vm *v)
{
int *val = (int *)stack_pop(v->s);
u_con("pop: 0x%x", *val);
return *val;
}
void vm_load(vm *v, int n)
{
int val = v->r[n];
u_con("load: %d %d", n, val);
vm_push(v, val);
}
void vm_store(vm *v, int n)
{
int val = vm_pop(v);
u_con("store: %d %d", n, val);
v->r[n] = val;
}
int vm_assert_jmp(vm *v, int n)
{
return v->ip + n < VM_INSTRUCTIONS_SZ;
}
void vm_jmp(vm *v, int n)
{
if(!vm_assert_jmp(v, n)) {
u_con("can't jump to 0x%x", n);
return;
}
u_con("jmp: 0x%x", n);
v->ip = n;
}
void vm_jz(vm *v, int n)
{
if(!vm_assert_jmp(v, n)) {
u_con("can't jump to 0x%x", n);
return;
}
int val = vm_pop(v);
u_con("jz: 0x%x z: %d", n, val);
if(val == 0) {
v->ip = n;
} else {
v->ip++;
}
}
void vm_jnz(vm *v, int n)
{
if(!vm_assert_jmp(v, n)) {
u_con("can't jump to 0x%x", n);
return;
}
int val = vm_pop(v);
u_con("jnz: 0x%x z: %d", n, val);
if(val != 0) {
v->ip = n;
} else {
v->ip++;
}
}
void vm_add(vm *v)
{
int a = vm_pop(v);
int b = vm_pop(v);
u_con("sub: 0x%x - 0x%x = 0x%d", b, a, b + a);
vm_push(v, b + a);
}
void vm_sub(vm *v)
{
int a = vm_pop(v);
int b = vm_pop(v);
u_con("sub: 0x%x - 0x%x = 0x%d", b, a, b - a);
vm_push(v, b - a);
}
void vm_mul(vm *v)
{
int a = vm_pop(v);
int b = vm_pop(v);
u_con("sub: 0x%x - 0x%x = 0x%d", b, a, b * a);
vm_push(v, b * a);
}
void vm_div(vm *v)
{
int a = vm_pop(v);
int b = vm_pop(v);
u_con("sub: 0x%x - 0x%x = 0x%d", b, a, b / a);
if(a == 0) {
u_con("can't divide by 0!");
exit(1);
}
vm_push(v, b / a);
}
void vm_print(vm *v)
{
int a = vm_pop(v);
u_con("print: %d", a);
}
// reads n bytes from the current instruction.
int vm_readn(vm *v, int n)
{
int i = 0;
unsigned char *val_p = NULL;
int val = 0;
dbg_err_sif((n != 1) && (n != 2) && (n != 4));
val_p = (unsigned char *)(&val);
for(i = 0; i < n; i++) {
*val_p = v->i[v->ip];
val_p++;
v->ip++;
}
err: // fallthrough
return val;
}
int main(int argc, char **argv) {
stack *s = NULL;
vm *v = NULL;
FILE *fp = NULL;
dbg_err_sif((s = stack_new(5, sizeof(int))) == NULL);
int val = 10;
int res = stack_push(s, &val);
u_con("res: %d", res);
int val2 = 20;
res = stack_push(s, &val2);
u_con("res: %d", res);
u_con("val: %d", *(int *)stack_pop(s));
u_con("val: %d", *(int *)stack_pop(s));
dbg_err_sif((v = vm_new(NULL, 0)) == NULL);
u_con("v(@%p)", v);
dbg_err_sif(argc < 2);
dbg_err_sif((fp = fopen(argv[1], "r")) == NULL);
int nread = 0;
int i = 0;
unsigned char *ip = v->i;
do {
if(i + 1 > VM_INSTRUCTIONS_SZ) {
break;
}
nread = fread(ip, 1, 1, fp);
ip++;
i++;
} while(nread > 0);
u_con("program %s loaded in vm", argv[1]);
vm_run(v);
u_con("vm ran");
err: // fallthrough
if(fp) {
fclose(fp);
}
if(s) {
stack_destroy(s);
}
if(v) {
vm_destroy(v);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment