About
I'm trying to implement a simple virtual machine. Now it supports only three operations:
ADD(reg0, reg1, reg2) -> reg0 = reg1 + reg2
LOAD(reg, value) -> reg = value
EXIT -> finish process
It has 8 registers and no memory (for now).
Source code
main.rs:
use std::process;
mod opcodes;
mod utils;
const REGISTERS_COUNT: usize = 8;
#[derive(Copy, Clone)]
struct Program<'a> {
code: &'a Vec<u8>,
pos: usize
}
impl<'a> Program<'a> {
pub fn new(code: &'a Vec<u8>) -> Program<'a> {
Program { code: code, pos: 0 }
}
pub fn fetch(&mut self) -> u8 {
self.pos += 1;
if self.pos > self.code.len() {
process::exit(0);
}
return self.code[self.pos - 1];
}
}
fn eval(mut program: Program, mut registers: [u64; REGISTERS_COUNT]) {
loop {
let operator = program.fetch();
let operands = (
program.fetch(),
vec![
program.fetch(), program.fetch(),
program.fetch(), program.fetch(),
program.fetch(), program.fetch(),
program.fetch(), program.fetch()
]
);
match operator {
opcodes::EXIT => {
process::exit(0);
}
opcodes::LOAD => {
registers[operands.0 as usize] = utils::concat_bytes(&operands.1);
}
opcodes::ADD => {
registers[operands.0 as usize] = registers[utils::concat_bytes(&operands.1[..4]) as usize]
+ registers[utils::concat_bytes(&operands.1[4..]) as usize];
}
_ => {
println!("error: invalid instruction code");
process::exit(1);
}
}
println!("{:?}", registers);
}
}
fn main() {
let registers: [u64; REGISTERS_COUNT] = [0; REGISTERS_COUNT];
let code = vec![
opcodes::LOAD,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64,
opcodes::LOAD,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC8,
opcodes::ADD,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
opcodes::EXIT,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
];
let program = Program::new(&code);
eval(program, registers);
}
utils.rs:
pub fn concat_bytes(bytes: &[u8]) -> u64 {
let mut result = bytes[0] as u64;
for i in 1..bytes.len() {
result = (result << 8) | (bytes[i] as u64)
}
return result;
}
opcodes.rs:
pub const EXIT: u8 = 0x00;
pub const LOAD: u8 = 0x01;
pub const ADD: u8 = 0x02;
Output
[100, 0, 0, 0, 0, 0, 0, 0]
[100, 200, 0, 0, 0, 0, 0, 0]
[100, 200, 300, 0, 0, 0, 0, 0]
Disadvantages:
- No memory
- Only integers
- All operators require the same number of arguments (even if they don't need any, like
EXIT
)
Anything else?