|
|
|
# uVM - Micro Virtual Machine
|
|
|
|
|
|
|
|
uVM is simply an experiment in developing a working virtual machine with it's own bytecode.
|
|
|
|
|
|
|
|
## Requirements
|
|
|
|
|
|
|
|
* CMake version 3.8 or higher
|
|
|
|
* Clang and Clang++
|
|
|
|
|
|
|
|
## Building
|
|
|
|
|
|
|
|
1. `git clone` the repository
|
|
|
|
2. `cmake .`
|
|
|
|
3. `make`
|
|
|
|
|
|
|
|
## Usage
|
|
|
|
|
|
|
|
`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 a single variable,
|
|
|
|
called `0`, that can be written to using `xpop0` where x is the datatype of the thing getting taken off
|
|
|
|
the stack.
|
|
|
|
|
|
|
|
Additionally `0` can be placed on the top of the stack using `xpush0`.
|
|
|
|
|
|
|
|
## 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 |
|
|
|
|
| ipush0 | 1 | Pushes the _integer_ in `0` onto the stack |
|
|
|
|
| ipop0 | 2 | Pops the top _integer_ of the stack off and into variable 0 |
|
|
|
|
| icmp | 3 | Compares the top two items on the stack together and returns a boolean result |
|
|
|
|
| iadd | 4 | Adds the top two _integer_ arguments of the stack together |
|
|
|
|
| isub | 5 | Subtracts the top two _integer_ arguments of the stack from each other |
|
|
|
|
| jmp _LABEL_ | 6 | Unconditional jump to _label_ |
|
|
|
|
| jc _LABEL_ | 7 | Jump if the top of the stack is a 1 |
|
|
|
|
| halt | 8 | Halts the VM |
|
|
|
|
|
|
|
|
|
|
|
|
As I learn more about VM development this instruction set will likely become much more robust.
|
|
|
|
|
|
|
|
## TODO
|
|
|
|
|
|
|
|
- [] Tests for good paths for all instructions
|
|
|
|
- [] Tests for uncompilable code
|
|
|
|
- [] Tests for maximum stack size reached
|
|
|
|
- [] Tests to make sure the maximum stack depth is always greater than 0
|
|
|
|
- [] Logging out current stack position, etc when verbose mode is enabled
|
|
|
|
- [] If verbose mode isn't enabled it shows the ascii loading while processing
|
|
|
|
- [] Come up with a way to allow the user to echo to the screen
|
|
|
|
- [] It would be cool to eventually write a high level language compiler that compiles down to the uvm
|