Skip to content

Instantly share code, notes, and snippets.

@DreamVB
Last active April 9, 2023 16:25
Show Gist options
  • Save DreamVB/dbd69bde0bee6013d955492b25d1fe05 to your computer and use it in GitHub Desktop.
Save DreamVB/dbd69bde0bee6013d955492b25d1fe05 to your computer and use it in GitHub Desktop.
Simple Stack Virtual Machine in C
/*
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