Skip to content

Instantly share code, notes, and snippets.

@mustooch
Created May 28, 2020 14:02
Show Gist options
  • Save mustooch/033fe2a8f471883ad5ed707abe4cb3f8 to your computer and use it in GitHub Desktop.
Save mustooch/033fe2a8f471883ad5ed707abe4cb3f8 to your computer and use it in GitHub Desktop.
basic virtual machine
#include <stdio.h>
#define STACK_MAX 256
#define PROGRAM_MAX 512
#define DEBUG 1
// define DEBUG 1 for all output, 0 for no output.
#define FINAL 1
// define FINAL 1 for final output, 0 for no output.
enum codes {
EXIT = 0,
ERROR = 1
};
enum instructions {
// TOS -> Top of stack
// X -> next instruction in program[] - hence a number is an instruction
HLT, // Halt, stop program
PSH, // Push X to TOS
POP, // Pop TOS
ADD, // pop and store TOS, add value to TOS-1 (now TOS)
SUB, // pop and store TOS, substitute value to TOS-1 (now TOS)
MUL, // pop and store TOS, multiply TOS-1
DIV, // pop and store TOS, divide TOS-1 by value
JNZ, // jump execution to program[X] if TOS not 0
JNP, // jump execution to program[X]
DUP, // duplicate TOS
SWP // swap TOS-1 and TOS
};
int ip = 0, sp = -1; // instruction pointer, stack pointer
int stack[STACK_MAX] = {0};
int program[PROGRAM_MAX] = {
// program to calculate 2*2 10 times (2^11)
PSH, 2, // [2]
PSH, 10, // [2,10]
SWP, // [10,2]
PSH, 2, // [10,2,2]
MUL, // [10,4]
SWP, // [4,10]
PSH, 1, // [4,10,1]
SUB, // [4,9]
JNZ, 4, // repeat 10 times
HLT
};
int main() {
// loop until HLT
for (;;) {
// read sp
int inst = program[ip];
// temporary registers
int reg1 = 0, reg2 = 0;
// execute
switch (inst) {
case HLT: {
if (FINAL || DEBUG) {
printf("Final stack values: \n");
for (int i=0; i<=sp; i++) printf("> %d : %d\n", i, stack[i]);
}
printf("Final stack height: %d\n", sp+1);
printf("TOS is: %d\n", stack[sp]);
printf("~~~~~~~~~~~~~\n");
printf("Exit with code %d\n", EXIT);
return EXIT;
} break;
case PSH: {
stack[++sp] = program[++ip];
if (DEBUG) printf(">> Pushed %d to TOS\n", stack[sp]);
} break;
case POP: {
stack[sp--] = 0;
if (DEBUG) printf(">> Poped TOS\n");
} break;
case ADD: {
reg1 = stack[sp];
stack[sp--] = 0;
stack[sp] += reg1;
if (DEBUG) printf(">> Added %d to TOS-1, poped TOS\n", reg1);
} break;
case SUB: {
reg1 = stack[sp];
stack[sp--] = 0;
reg2 = stack[sp];
stack[sp] -= reg1;
if (DEBUG) printf(">> Substituted %d from %d, poped TOS\n", reg1, reg2);
} break;
case MUL: {
reg1 = stack[sp];
stack[sp--] = 0;
reg2 = stack[sp];
stack[sp] *= reg1;
if (DEBUG) printf(">> Multiplied %d to %d, poped TOS\n", reg1, reg2);
} break;
case DIV: {
reg1 = stack[sp];
stack[sp--] = 0;
reg2 = stack[sp];
stack[sp] /= reg1;
if (DEBUG) printf(">> Substituted %d to %d, poped TOS\n", reg1, reg2);
} break;
case JNZ: {
if (stack[sp] != 0) {
ip = program[ip+1];
if (DEBUG) printf(">> TOS not zero, jumped execution to %d\n", ip);
continue; // skip ip++
} else {
ip++;
sp--;
if (DEBUG) printf(">> TOS is 0, continue execution\n");
}
} break;
case JNP: {
ip = program[ip+1];
if (DEBUG) printf(">> Jumped execution to %d\n", ip);
continue; // skip ip++
} break;
case DUP: {
reg1 = stack[sp++];
stack[sp] = reg1;
if (DEBUG) printf(">> Duplicated %d on TOS\n", reg1);
} break;
case SWP: {
reg1 = stack[sp];
stack[sp] = stack[sp-1];
stack[sp-1] = reg1;
if (DEBUG) printf(">> Swapped %d and %d\n", reg1, stack[sp]);
} break;
default: {
printf("Invalid instruction at ip: %d\n", ip);
}
}
if (DEBUG) printf("~~~~~~~~~~~~~\n");
ip++;
}
return EXIT;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment