Created
November 14, 2022 03:31
-
-
Save Killaship/927951649bbf2f2399565c5f4b47c621 to your computer and use it in GitHub Desktop.
mac-vm
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
/* | |
Killaship | |
2022 | |
November 13th, ~10:30 PM EST | |
This took like an hour or two to make, WITH a tutorial and previous experience! | |
A VM following the specifications of the 'mac' architecture, as outlined in this blog: | |
https://felix.engineer/blogs/virtual-machine-in-c/ | |
I was pretty tired while writing this, so the code might suck. | |
Hell, I typed & instead of % twice and was wondering for minutes about it! | |
I started work on this at ~ 9:15, I recorded the progress. | |
Notes: | |
- In loops, stack overflows only happen if your program is "unbalanced," | |
i.e., end up pushing more than there's space for. If a program is balanced, it'll run forever. | |
It might be hard to get a ^C in, so beware. | |
- There's a very limited instruction set, either add to it on your own, | |
or wait for me to, if I ever do. You'd be better off following the original creator of mac, | |
found at this Github link: https://github.com/felixangell/mac | |
I only did the bare minimum to make what's outlined in the blog work. | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdbool.h> | |
#include <string.h> | |
int ip = 0; | |
int sp = -1; | |
bool run = true; | |
typedef enum { // this gives us reference names for the opcodes. | |
PSH, | |
ADD, | |
POP, | |
SET, | |
STKRESET, | |
JMP, | |
HLT | |
} ISA; | |
typedef enum { | |
A, B, C, D, E, F, SP, IP, // I spent longer trying to copy paste this than to actually type it :/ | |
NUM_OF_REGISTERS | |
} REG; | |
int registers[NUM_OF_REGISTERS]; // what's funny is that you can use the NUM_OF_REGISTERS register as a register if you tried to in code | |
#define sp (registers[SP]) | |
#define ip (registers[IP]) | |
// ^^ quick lil' hack | |
int program[] = { // unsigned char instead of int since we don't need billions of opcodes | |
STKRESET, // wow, looks like we do need this. | |
PSH, 5, // well, fuck it, I just realized we need to add or subtract large numbers | |
PSH, 6, // I mean, we could go all harvard arch, but that would kinda suck ass | |
ADD, | |
POP, | |
JMP, 0, | |
HLT | |
}; | |
int stack[256]; // stack array | |
int fetch() { | |
return program[ip]; // FFS, this doesn't need a function | |
} | |
void eval(int instr) { | |
// what kind of crack was that guy's compiler smoking? | |
// maybe it was llvm | |
int a = 69; // debug values | |
int b = 69; | |
int result = 69; | |
int val_popped = 69; | |
int pushval = 69; | |
switch(instr) { | |
case POP: | |
val_popped = stack[sp--]; // MAKE SURE THE INC/DEC IS ON THE RIGHT GODDAMN SIDE | |
printf("popped %d!\n", val_popped); | |
break; | |
case ADD: | |
a = stack[sp--]; | |
printf("a is %d!\n", a); // I really would be better off using GDB but who cares | |
b = stack[sp--]; | |
printf("b is %d!\n", b); // I really would be better off using GDB but who cares | |
result = b + a; | |
printf("a plus b is %d!\n", result); // I really would be better off using GDB but who cares | |
sp++; // increment stack pointer **before** | |
stack[sp] = result; // set the value to the top of the stack | |
printf("I just pushed %d!\n", stack[sp]); | |
break; | |
case PSH: | |
sp++; | |
stack[sp] = program[++ip]; | |
pushval = stack[sp]; | |
printf("pushed %d!\n", pushval); // grammar laws request that the comma is included inside the quotation mark | |
stack[sp] = pushval; // this uses something I didn't know about before I first read the blog | |
break; // it uses the ++ lvalue to increment the ip at the same time as reading it | |
case SET: // nevermind | |
registers[program[ip++]] = registers[program[ip++]]; // zoo wee mama this is weird | |
// it increments the IP and then in the same line increments it again | |
break; | |
case STKRESET: // stack reset | |
memset(&stack, 0, 256); // should really unhardcode this later | |
sp = -1; | |
break; | |
case JMP: | |
printf("before: %d. ", ip); // I should get sleep, I mistyped something really obvious | |
ip = program[++ip]; // brain farted here | |
printf("after %d.\n", ip); | |
break; | |
case HLT: | |
run = false; | |
break; | |
} | |
} | |
int main() { | |
int instr = program[ip]; | |
while(run == true) { | |
instr = fetch(); | |
eval(instr); | |
ip++; | |
} | |
printf("done!\n"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
or my bash history, I guess