-
-
Save mustooch/033fe2a8f471883ad5ed707abe4cb3f8 to your computer and use it in GitHub Desktop.
basic virtual machine
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
#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