/vm.c
Last active
April 9, 2023 16:25
Simple Stack Virtual Machine in C
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
/* | |
Simple stack Virtual Machine | |
Version 1.0 | |
by DreamVB | |
This is a simple example of how to code a simple VM in C | |
At the moment this vm only supports a small amount of instruction I hope to add more as I learn more. | |
This version has some hard coded example that you can test in the vm. Next version I plan to load the examples from files. | |
If you like this code, or if you have some improvements I can make drop me a message below: | |
dreamvb@outlook.com | |
Happy-Coding | |
15/7/2019 | |
+ Added NEG, NOT , LT (Less Than),JF (Jump False) | |
+ Added simple IF example | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#define MAX_PROG 65535 | |
#define MAX_STACK 256 | |
#define MAX_GLOBALS 8 | |
typedef enum { | |
PUSH = 0, | |
PRTI, | |
PRTC, | |
ADD, | |
SUB, | |
MUL, | |
DIV, | |
AND, | |
OR, | |
XOR, | |
NEG, | |
NOT, | |
MOD, | |
GSTORE, | |
GLOAD, | |
JMP, | |
LT, | |
GT, | |
JT, | |
JF, | |
HLT, | |
}OP_CODES; | |
//Program code to execute | |
int pcode[MAX_PROG]; | |
//Stack | |
int STACK[MAX_STACK]; | |
//Global variables pool | |
int Globals[MAX_GLOBALS]; | |
//Stack pointer | |
int sp = -1; | |
//Program counter | |
int pc = 0; | |
//Length of the current program to execute | |
int p_len = 0; | |
//Examples are shown below. | |
int Adder[] = { | |
PUSH, | |
150, | |
PUSH, | |
150, | |
ADD, | |
PRTI, | |
PUSH, | |
128, | |
PUSH, | |
4, | |
DIV, | |
PRTI, | |
HLT | |
}; | |
int Neg[] = { | |
PUSH, | |
124, | |
NEG, | |
PRTI, | |
PUSH, | |
-120, | |
NEG, | |
PRTI, | |
HLT | |
}; | |
int Not[] = { | |
PUSH, | |
1, | |
NOT, | |
PRTI, | |
HLT | |
}; | |
int JumpTrue[] = { | |
PUSH,8, | |
PUSH, 6, | |
LT, | |
//True | |
JF,10, | |
PUSH,'T', | |
PRTC, | |
HLT, | |
//False | |
PUSH,'F', | |
PRTC, | |
HLT | |
}; | |
int Hello[] = { | |
PUSH, | |
1234, | |
PRTI, | |
HLT | |
}; | |
int Logic[] = { | |
PUSH, | |
5, | |
PUSH, | |
14, | |
XOR, | |
PRTI, | |
HLT | |
}; | |
int BasicVar[] = { | |
PUSH, | |
150, | |
PUSH, | |
120, | |
ADD, | |
GSTORE, | |
1, | |
PUSH, | |
15, | |
PRTI, | |
GLOAD, | |
1, | |
PRTI, | |
HLT | |
}; | |
int Beep[] = { | |
PUSH, | |
0x7, | |
PRTC, | |
HLT | |
}; | |
int Jump[] = { | |
JMP, | |
4, | |
PUSH, | |
20, | |
PRTI, | |
//Don't output the above | |
PUSH, | |
141, | |
PRTI, | |
HLT | |
}; | |
int ModTest[] = { | |
PUSH, | |
14, | |
PUSH, | |
3, | |
MOD, | |
PRTI, | |
HLT | |
}; | |
void vm_init(const int *code,int code_len){ | |
int x = 0; | |
p_len = code_len; | |
//Load code into program code array. | |
while(x < code_len){ | |
pcode[x] = code[x]; | |
//INC counter | |
x++; | |
} | |
//Reset default variables values. | |
x = 0; | |
while(x < MAX_GLOBALS){ | |
Globals[x] = 0; | |
x++; | |
} | |
} | |
void vm_execute(){ | |
int op = 0; | |
int r = 0; | |
int l = 0; | |
int r_idx = 0; | |
//Loop while we still have code to execute | |
while(pc < p_len){ | |
//Read Instruction | |
op = pcode[pc]; | |
//See what Instruction we are dealing with | |
switch(op){ | |
//Push a value to the top of the stack | |
case PUSH: | |
pc++; | |
STACK[++sp] = pcode[pc]; | |
break; | |
//Print the top of the stack as an integer | |
case PRTI: | |
printf("%d\n",STACK[sp--]); | |
break; | |
//Print the top of the stack as a char | |
case PRTC: | |
printf("%c",STACK[sp--]); | |
break; | |
//Add the two top items on the stack and push back onto the stack. | |
case ADD: | |
r = STACK[sp--]; | |
l = STACK[sp--]; | |
STACK[++sp] = (r + l); | |
break; | |
//Subtract the two top items on the stack and push back onto the stack. | |
case SUB: | |
r = STACK[sp--]; | |
l = STACK[sp--]; | |
STACK[++sp] = (l - r); | |
break; | |
//Multiply the two top items on the stack and push back onto the stack. | |
case MUL: | |
r = STACK[sp--]; | |
l = STACK[sp--]; | |
STACK[++sp] = (r * l); | |
break; | |
//Divide the two top items on the stack and push back onto the stack. | |
case DIV: | |
r = STACK[sp--]; | |
l = STACK[sp--]; | |
//Check for division by zero error. | |
if(r == 0){ | |
printf("Division by zero"); | |
//Set program counter to the end of the program code length. | |
pc = p_len; | |
}else{ | |
STACK[++sp] = (l / r); | |
} | |
break; | |
case MOD: | |
r = STACK[sp--]; | |
l = STACK[sp--]; | |
STACK[++sp] = (l % r); | |
break; | |
case HLT: | |
pc = p_len; | |
break; | |
case AND: | |
r = STACK[sp--]; | |
l = STACK[sp--]; | |
STACK[++sp] = (r & l); | |
break; | |
case OR: | |
r = STACK[sp--]; | |
l = STACK[sp--]; | |
STACK[++sp] = (r | l); | |
break; | |
case XOR: | |
r = STACK[sp--]; | |
l = STACK[sp--]; | |
STACK[++sp] = (r ^ l); | |
break; | |
case NEG: | |
r = -STACK[sp--]; | |
STACK[++sp] = r; | |
break; | |
case NOT: | |
r = !STACK[sp--]; | |
STACK[++sp] = r; | |
break; | |
//Save the top of the stack into a global variable address. | |
case LT: | |
r = STACK[sp--]; | |
l = STACK[sp--]; | |
//test the two values on the stack | |
if(l < r){ | |
//Flag is true | |
STACK[++sp] = 1; | |
}else{ | |
//Flag is false | |
STACK[++sp] = 0; | |
} | |
break; | |
//Jump False | |
case JF: | |
pc++; | |
//Get the top of the stack | |
r = STACK[sp--]; | |
//Check for zero flag | |
if(r == 0){ | |
//Jump to code address. | |
pc = pcode[pc]; | |
} | |
break; | |
case GSTORE: | |
pc++; | |
//Get reg address. | |
r_idx = pcode[pc]; | |
//Get the tack value and put into reg | |
Globals[r_idx] = STACK[sp--]; | |
//Get what is on the stack. | |
break; | |
//Load a global variable and place on the stack | |
case GLOAD: | |
pc++; | |
//Get reg index | |
r_idx = pcode[pc]; | |
STACK[++sp] = Globals[r_idx]; | |
break; | |
case JMP: | |
pc++; | |
//Jump to address | |
pc = pcode[pc]; | |
break; | |
} | |
//INC program counter | |
pc++; | |
} | |
} | |
void vm_free(){ | |
memset(pcode,0,sizeof(pcode)); | |
} | |
int main() | |
{ | |
//Add code to VM | |
vm_init(JumpTrue,sizeof(JumpTrue) / sizeof(int)); | |
//Execute code | |
vm_execute(); | |
//Free the program code. | |
vm_free(); | |
//Return back to the operating system. | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment