|
|
|
# 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
|