Micro Virtual Machine - A weekend project to build a virtual machine
Taylor Bockman ec7ddca7ec Create LICENSE 2 years ago
include Initial Pass at the Virtual Machine 2 years ago
src Initial Pass at the Virtual Machine 2 years ago
.gitignore Initial Pass at the Virtual Machine 2 years ago
CMakeLists.txt Initial Pass at the Virtual Machine 2 years ago
LICENSE Create LICENSE 2 years ago
README.md Update README.md 2 years ago

README.md

uVM - Micro Virtual Machine

uVM is simply an experiment in developing a working virtual machine with it's own bytecode.

Contributing

I am taking any and all contributions! This is a fun project for me and I'd like to see other people throw their ideas into this.

Requirements

  • CMake version 3.8 or higher
  • Clang and Clang++
  • Boost (because im lazy)

Building

  1. git clone the repository
  2. cmake .
  3. make

Usage

NOTE: This is unimplemented - Looking for contributors

uvm [-v] [-h] [-d <stack_depth>] -f <your_file_of_bytecode>.uc

  • -v: Enable verbose logging mode
  • -h: Show usage
  • -f <file_name>.uc: Load the uvm bytecode file for processing
  • -d <stack_depth>: The maximum stack depth in words

Testing

CMake tests are used to confirm a handful of sample programs will run successfully in the VM

  1. cmake .
  2. make test

Architecture

uVM is a stack machine. That is, it gets all of it's arguments from the stack, and returns the result of the computation back to the stack when it's done.

There are some exceptions to this. In particular the current version of uvm supports registers.

uVM Instruction Set

uVM possesses the standard issue instruction set you might expect in a simple VM:

Instruction Opcode Action
ipush X 0 Pushes integer X onto the stack
isave0 1 Takes the top of the stack and stores it in t0
isave1 2 Takes the top of the stack and stores it in t1
isave2 3 Takes the top of the stack and stores it in t2
iload0 4 Puts the value in t0 onto the top of the stack
iload1 5 Puts the value in t1 onto the top of the stack
iload2 6 Puts the value in t2 onto the top of the stack
icmp 7 Compares the top two items on the stack together and returns a boolean result
iadd 8 Adds the top two integer arguments of the stack together
isub 9 Subtracts the top two integer arguments of the stack from each other
jmp BYTE A Unconditional jump to BYTE
jc BYTE B Jump to BYTE if the top of the stack is a 1
halt C Halts the VM
print D Prints the current top of the stack as an integer
imul E Multiples the top two integers on the stack
call F TBD
idiv 10 Takes the top two values on the stack and performs integer division on them
irem 11 Takes the integer remainder of the division of the top two integer values on the stack

Additionally some registers exist to ease computation:

Register Use
t0 Temporary integer register 0
t1 Temporary integer register 1
t2 Temporary integer register 2
cf Comparison flag register

As I learn more about VM development this instruction set will likely become much more robust.

uVM Calling Convention

uVM borrows heavily from past work - so a CDECL convention modified to work with stack machines (result is store on the top of the stack instead of EAX) is used.

TODO

  • [ ] Tests for good paths for all instructions
  • [ ] Come up with a clever way to support floating point operations
  • [ ] Tests for uncompilable code
  • [ ] Tests for maximum stack size reached
  • [ ] Tests to make sure the maximum stack depth is always greater than 0
  • [ ] Test to make sure that run doesn't run when the byte code array is empty
  • [ ] Logging out current stack position, etc when verbose mode is enabled
  • [ ] If verbose mode isn't enabled it shows the ascii loading while processing
  • [ ] It would be cool to eventually write a high level language compiler that compiles down to the uvm