This repository has been archived on 2025-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
corten/src/vm.rs
2020-02-06 17:40:43 -05:00

117 lines
3.1 KiB
Rust

use crate::instruction::Opcode;
pub struct VM {
registers: [i32; 32],
pc: usize,
program: Vec<u8>,
remainder: u32,
}
impl VM {
pub fn new() -> Self {
VM {
registers: [0; 32],
pc: 0,
program: vec![],
remainder: 0,
}
}
fn decode_opcode(&mut self) -> Opcode {
let opcode = Opcode::from(self.program[self.pc]);
self.pc += 1;
opcode
}
fn next_8_bits(&mut self) -> u8 {
let result = self.program[self.pc];
self.pc += 1;
result
}
fn next_16_bits(&mut self) -> u16 {
let result = ((self.program[self.pc] as u16) << 8) | self.program[self.pc + 1] as u16;
self.pc += 2;
result
}
pub fn run(&mut self) {
let mut is_done = false;
while !is_done {
is_done = self.execute_instruction()
}
}
pub fn run_once(&mut self) {
self.execute_instruction();
}
fn execute_instruction(&mut self) -> bool {
if self.pc >= self.program.len() {
return false;
}
match self.decode_opcode() {
Opcode::LOAD => {
let reg = self.next_8_bits() as usize;
let num = self.next_16_bits() as u32;
self.registers[reg] = num as i32;
}
Opcode::HLT => {
println!("HLT encountered");
return false;
}
Opcode::IGL => {
println!("Unrecognized opcode found! Terminating!");
}
Opcode::ADD => {
let reg1 = self.registers[self.next_8_bits() as usize];
let reg2 = self.registers[self.next_8_bits() as usize];
self.registers[self.next_8_bits() as usize] = reg1 + reg2;
}
Opcode::MUL => {
let reg1 = self.registers[self.next_8_bits() as usize];
let reg2 = self.registers[self.next_8_bits() as usize];
self.registers[self.next_8_bits() as usize] = reg1 * reg2;
}
Opcode::DIV => {
let reg1 = self.registers[self.next_8_bits() as usize];
let reg2 = self.registers[self.next_8_bits() as usize];
self.registers[self.next_8_bits() as usize] = reg1 / reg2;
self.remainder = (reg1 % reg2) as u32;
}
}
true
}
}
#[cfg(test)]
mod vm_tests {
use crate::vm::*;
#[test]
fn test_crate_vm() {
let test_vm = VM::new();
assert_eq!(test_vm.registers[0], 0);
}
#[test]
fn test_opcode_hlt() {
let mut test_vm = VM::new();
let test_bytes = vec![0, 0, 0, 0];
test_vm.program = test_bytes;
test_vm.run_once();
assert_eq!(test_vm.pc, 1);
}
#[test]
fn test_opcode_igl() {
let mut test_vm = VM::new();
let test_bytes = vec![200, 0, 0, 0];
test_vm.program = test_bytes;
test_vm.run_once();
assert_eq!(test_vm.pc, 1);
}
#[test]
fn test_load_opcode() {}
}