modVM 0.2.1

A framework for easily creating modular VMs.
Documentation
# ModVM-Rust

ModVM provides a simple framework for building Virtual Machines in Rust. VMs in ModVM are modular, and are to this end made up of two different types of components: Processors and Peripherals.

## Execution Model


The VM is initialized with a vector of Processors and a vector of Peripherals, and automatically constructs the communication channels between each of the processors and the peripherals. The processor then makes requests down these channels in its `exe_ins()` function, which is called in a loop. When any peripheral receives data down a channel, its `handle(request)` function is called, and this returns data for the processor to use.

After initialization, the VM returns a `MachineHandle` struct, which can be used to join to the threads of the VM.

## Useage

### The TwoWayChannel Struct


The `modVM` crate implements the `TwoWayChannel<I, O>` struct for easy communication between VM components.

`TwoWayChannel` is always instantiated in pairs, and each pair ('end') contains two channels for communicating in both directions down the channel. It accepts the following methods:

+ `send` - sends data down the channel.
+ `recv` - waits for next item, then returns it.
+ `try_recv` - tests to find an item in the channel's queue; if it finds it, it returns it.
+ `iter` - looped version of `recv`.
+ `try_iter` - looped version of `try_recv`.
+ `query` - sends data down the channel, then waits until it gets a reply, then returns it.

Internally, `Processor`s make requests with type `modVM::Query` and `Peripheral`s respond with `modVM::Response`.

### The Processor Trait


The `Processor<BASE>` trait requires the `exe_ins()` function to be implemented on the struct. This function must take in a Vector of `FrontEnd<BASE>` (a wrapper for `TwoWayChannel<Query<BASE>>`) and `&mut self`, and return `Result<(), BASE>`. The processor terminates if any of its functions return an `Err`.

A simple implementation would be:

```rust
impl Processor<u8> for ProcessorEightBit {
    fn exe_ins(&mut self, channels: &Vec<FrontEnd<u16>>) -> Result<(), u8> {
        // get instruction:
        let ins = channels[0].query(LoadRequest(self.counter)).unwrap();

        match ins {
            
            /* snip */

            // instruction didn't match:
            _ => Err(0),
        }
    }
}
```
### The Peripheral Trait


The `Peripheral<BASE>` trait works in a similar fashion to a webserver: its primary purpose is to send and receive requests for data. This is achived through the `handle()` function, which takes in a `Query` enum request and outputs a `Result<Response<BASE>, BASE>`, which, if `Ok` is unwrapped and sent back down the channel. This versatility gives ModVM amazing scope for quickly creating different components for VMs. The `handle()` function is called every time the peripheral receives a request.

A simple implementation would be:
```rust
impl Peripheral<u8> for MemEightBit {
    fn handle(&mut self, incoming: Query<u16>) -> Result<Response<u16>, u16> {
        Ok(match incoming {
            LoadRequest(x) => {
                match self.mem.get(x as usize) {
                    Some(y) => {
                        Data(*y)
                    },
                    None => Fail(0),
                }
            },
            SaveRequest(x, y) => {
                match self.mem.get_mut(x as usize) {
                    Some(z) => {
                        *z = y;
                        Good
                    },
                    None => Fail(0),
                }
            },
        })
    }
}
```

However `Peripheral`s are not only limited to memory. For example, you could configure one to act as a GPU, or handle I/O. To aid the user in this regard, the optional `cycle` function can be used to run processes that need to be active each cycle. This function can only mutate the component's state, however.

### Shared Functions


All the traits listed above share certain functions: `metadata`, `boot` and `halt`. Metada`metadata` specifies data about the VM, and returns a `Metadata` struct. This is used for identification of threads. `boot` and `halt` are fairly self-explanitory; They run on startup and after termination, and in a `Processor` the functions have access to the channels, so they can make requests for data. However, of these, only the `metadata` function is required for compilation.

Here is an implementation for all these functions on a `Processor`:
```rust
impl Processor<u8> for ProcessorEightBit {
    fn boot(&mut self, channels: &Vec<FrontEnd<u8>>) -> Result<(), BASE> {
        channels[0].query(SaveRequest(PRINT, self.bootcode)).unwrap(); // print the bootcode
        Ok(())
    }

    fn halt(&mut self, channels: &Vec<FrontEnd<u8>>) -> Result<(), BASE> {
        channels[0].query(SaveRequest(PRINT, self.error)).unwrap(); // print the error message

        for i in channels {
            i.send(LoadRequest(HALT)); // halt all peripherals
        }
    }
}
```

And for a peripheral:
```rust
impl Peripheral<u8> for MemEightBit {
    fn boot(&mut self) -> Result<(), BASE> {
        /* initialise things */
        Ok(())
    }

    fn halt(&mut self) -> Result<(), BASE> {
        /* halt processes */
        Ok(())
    }
}
```