implement fetch-execute loop
This commit is contained in:
parent
fb7b17a7fe
commit
60ad020d14
@ -9,4 +9,5 @@ fn main() {
|
||||
let mut vm = VM::new();
|
||||
|
||||
vm.read_program(&"programs/hello-world.obj".to_string());
|
||||
vm.execute();
|
||||
}
|
||||
|
@ -2,7 +2,9 @@
|
||||
////// instruction execution
|
||||
//////////////////////////////
|
||||
|
||||
enum OpCodes {
|
||||
use crate::vm::VM;
|
||||
|
||||
enum OpCode {
|
||||
// branch
|
||||
BR = 0,
|
||||
// add
|
||||
@ -35,6 +37,56 @@ enum OpCodes {
|
||||
LEA,
|
||||
// trap
|
||||
TRAP,
|
||||
// no-operation (not a real opcode)
|
||||
NOOP,
|
||||
}
|
||||
|
||||
fn get_opcode(instruction: u16) -> OpCode {
|
||||
// the opcode is stored in the left 4 bits
|
||||
match instruction >> 12 {
|
||||
0 => OpCode::BR,
|
||||
1 => OpCode::ADD,
|
||||
2 => OpCode::LD,
|
||||
3 => OpCode::ST,
|
||||
4 => OpCode::JSR,
|
||||
5 => OpCode::AND,
|
||||
6 => OpCode::LDR,
|
||||
7 => OpCode::STR,
|
||||
8 => OpCode::RTI,
|
||||
9 => OpCode::NOT,
|
||||
10 => OpCode::LDI,
|
||||
11 => OpCode::STI,
|
||||
12 => OpCode::JMP,
|
||||
13 => OpCode::RES,
|
||||
14 => OpCode::LEA,
|
||||
15 => OpCode::TRAP,
|
||||
_ => OpCode::NOOP,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn execute_instruction(vm: &mut VM) {
|
||||
let instruction: u16 = vm.mem.get_mem(vm.registers.pc);
|
||||
let opcode = get_opcode(instruction);
|
||||
|
||||
match opcode {
|
||||
OpCode::BR => no_op(vm),
|
||||
OpCode::ADD => no_op(vm),
|
||||
OpCode::LD => no_op(vm),
|
||||
OpCode::ST => no_op(vm),
|
||||
OpCode::JSR => no_op(vm),
|
||||
OpCode::AND => no_op(vm),
|
||||
OpCode::LDR => no_op(vm),
|
||||
OpCode::STR => no_op(vm),
|
||||
OpCode::RTI => no_op(vm),
|
||||
OpCode::NOT => no_op(vm),
|
||||
OpCode::LDI => no_op(vm),
|
||||
OpCode::STI => no_op(vm),
|
||||
OpCode::JMP => no_op(vm),
|
||||
OpCode::RES => no_op(vm),
|
||||
OpCode::LEA => no_op(vm),
|
||||
OpCode::TRAP => no_op(vm),
|
||||
OpCode::NOOP => no_op(vm),
|
||||
}
|
||||
}
|
||||
|
||||
fn no_op(vm: &mut VM) {}
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
use byteorder::{BigEndian, ReadBytesExt};
|
||||
use std::{fs::File, io::BufReader};
|
||||
|
||||
mod instruction;
|
||||
|
||||
////////////////
|
||||
@ -59,6 +60,7 @@ impl Registers {
|
||||
}
|
||||
}
|
||||
|
||||
/// Map an integer index to its register
|
||||
fn register_reference(&mut self, idx: u16) -> &mut u16 {
|
||||
match idx {
|
||||
0 => &mut self.r0,
|
||||
@ -75,11 +77,11 @@ impl Registers {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_reg(&mut self, idx: u16, val: u16) {
|
||||
fn set_reg(&mut self, idx: u16, val: u16) {
|
||||
*self.register_reference(idx) = val;
|
||||
}
|
||||
|
||||
pub fn get_reg(&mut self, idx: u16) -> u16 {
|
||||
fn get_reg(&mut self, idx: u16) -> u16 {
|
||||
let reg = &*self.register_reference(idx);
|
||||
*reg
|
||||
}
|
||||
@ -97,7 +99,7 @@ impl Registers {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_reg_with_cond(&mut self, idx: u16, val: u16) {
|
||||
fn set_reg_with_cond(&mut self, idx: u16, val: u16) {
|
||||
self.set_reg(idx, val);
|
||||
self.set_cond(idx);
|
||||
}
|
||||
@ -120,11 +122,11 @@ impl Memory {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_mem(&mut self, addr: u16, val: u16) {
|
||||
fn set_mem(&mut self, addr: u16, val: u16) {
|
||||
self.data[addr as usize] = val;
|
||||
}
|
||||
|
||||
pub fn get_mem(&self, addr: u16) -> u16 {
|
||||
fn get_mem(&self, addr: u16) -> u16 {
|
||||
return self.data[addr as usize];
|
||||
}
|
||||
}
|
||||
@ -185,8 +187,17 @@ impl VM {
|
||||
}
|
||||
|
||||
pub fn execute(&mut self) {
|
||||
loop {
|
||||
self.registers.pc += 1;
|
||||
let mut running: bool = true;
|
||||
|
||||
while running {
|
||||
instruction::execute_instruction(self);
|
||||
|
||||
// disallow reading past memory bounds
|
||||
if self.registers.pc as usize == MEM_SIZE - 1 {
|
||||
running = false
|
||||
} else {
|
||||
self.registers.pc += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user