-
Notifications
You must be signed in to change notification settings - Fork 0
/
VirtualMachine.c
185 lines (163 loc) · 5.14 KB
/
VirtualMachine.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define fetch program[registers[PC]]
#define MAX_PROGRAM_SIZE 512
//all instructions
typedef enum {
PSH, //Pushes a value onto the stack ex: PSH, 12
POP, //Pops a value from the stack ex: POP, B
ADD, //Adds a value to the A register ex: ADD, 2
SUB, //Subtracts a value from the A register ex: SUB, 3
SET, //Sets value of any register ex: SET, B, 23
MOV, //Copies first register value into second register ex: MOV, A, PC
JSR, //Jumps to a subroutine ex: JSR, 23
RTS, //Returns from a subroutine ex: RTS
JZ, //Branch to adress if 0 is in A register ex: BEQ, 12
HLT, //Halts the machine ex: HLT
IOT, //Outputs contents of a register ex: OUT, A
COT //Outputs contents of a register as char ex: OUT, B
} InstructionSet;
//registers
typedef enum {
A, B, C, D, PC, SP,
NUM_REGISTERS
} Registers;
//global variables
int* program;
int stack[256];
int registers[NUM_REGISTERS];
bool running = true;
void execute(int instruction) {
switch(instruction) {
case PSH: {
//pushes next value onto the stack
stack[++registers[SP]] = program[registers[PC]++];
break;
}
case POP: {
//check if stack has value
if(registers[SP] < 0) printf("\nBVM Error: Tried to pop empty stack");
//gets value and decrements sp
int popped_value = stack[registers[SP]--];
//stores value in register
registers[program[registers[PC]++]] = popped_value;
break;
}
case ADD: {
//gets number to the A register
int reg = program[registers[PC]++];
int result = registers[reg] + registers[A];
if((registers[reg] > 0 && registers[A] > 0 && result < 0) || (registers[reg] < 0 && registers[A] < 0 && result > 0)) {
//overflow
printf("BVM Error: Sum Overflow\n");
}
//puts result back into the A register
registers[A] = result;
break;
}
case SUB: {
//gets number to subtract from A register
int x = program[registers[PC]++];
//puts result back into the A register
registers[A] -= x;
break;
}
case SET: {
//get the register to change from program
int reg = program[registers[PC]++];
//change the register with the next value in program
registers[reg] = program[registers[PC]++];
break;
}
case MOV: {
//get source and dest
int source = program[registers[PC]++];
int dest = program[registers[PC]++];
//copy
registers[dest] = registers[source];
break;
}
case JSR: {
//get adress to jump to and push current onto stack
int jump_adress = program[registers[PC]++];
stack[++registers[SP]] = registers[PC];
//jump
registers[PC] = jump_adress;
break;
}
case RTS: {
//pull adress from stack and jump
int jump_adress = stack[registers[SP]--];
registers[PC] = jump_adress;
break;
}
case JZ: {
//gets adress
int adress = program[registers[PC]++];
//branch if zero
if(registers[A] == 0) {
registers[PC] = adress;
}
break;
}
case HLT: {
//stops the machine
running = false;
break;
}
case IOT: {
//prints int value stored in register
printf("%d", registers[program[registers[PC]++]]);
break;
}
case COT: {
//prints char value stored in the register
printf("%c", registers[program[registers[PC]++]]);
break;
}
}
}
int* read_program(char file_name[]) {
//create and open file
FILE *file;
int *program = malloc(sizeof(int) * MAX_PROGRAM_SIZE);
file = fopen(file_name, "r");
//check if file opened properly
if(file == NULL) {
printf("BVM Fatal Error: could not open file \n");
running = false;
return 0;
}
//read file
for(int i = 0; i < MAX_PROGRAM_SIZE; i++) {
fscanf(file, "%d", &program[i]);
}
//close file
fclose(file);
return program;
}
int main(int argc, char* argv[]) {
//init SP and PC
registers[PC] = 0;
registers[SP] = -1;
//read program from file
if(argc == 2) {
printf("BVM: Reading File \n");
program = read_program(argv[1]);
} else {
printf("BVM Fatal Error: no file specified \n");
return 0;
}
//system clock
while(running) {
//fetch
int current_instruction = fetch;
registers[PC]++;
//decode and execute
execute(current_instruction);
}
//free program from heap
free(program);
return 0;
}