implement fetch-execute loop
This commit is contained in:
parent
fb7b17a7fe
commit
60ad020d14
@ -9,4 +9,5 @@ fn main() {
|
|||||||
let mut vm = VM::new();
|
let mut vm = VM::new();
|
||||||
|
|
||||||
vm.read_program(&"programs/hello-world.obj".to_string());
|
vm.read_program(&"programs/hello-world.obj".to_string());
|
||||||
|
vm.execute();
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,9 @@
|
|||||||
////// instruction execution
|
////// instruction execution
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
|
|
||||||
enum OpCodes {
|
use crate::vm::VM;
|
||||||
|
|
||||||
|
enum OpCode {
|
||||||
// branch
|
// branch
|
||||||
BR = 0,
|
BR = 0,
|
||||||
// add
|
// add
|
||||||
@ -35,6 +37,56 @@ enum OpCodes {
|
|||||||
LEA,
|
LEA,
|
||||||
// trap
|
// trap
|
||||||
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 byteorder::{BigEndian, ReadBytesExt};
|
||||||
use std::{fs::File, io::BufReader};
|
use std::{fs::File, io::BufReader};
|
||||||
|
|
||||||
mod instruction;
|
mod instruction;
|
||||||
|
|
||||||
////////////////
|
////////////////
|
||||||
@ -59,6 +60,7 @@ impl Registers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Map an integer index to its register
|
||||||
fn register_reference(&mut self, idx: u16) -> &mut u16 {
|
fn register_reference(&mut self, idx: u16) -> &mut u16 {
|
||||||
match idx {
|
match idx {
|
||||||
0 => &mut self.r0,
|
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;
|
*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);
|
let reg = &*self.register_reference(idx);
|
||||||
*reg
|
*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_reg(idx, val);
|
||||||
self.set_cond(idx);
|
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;
|
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];
|
return self.data[addr as usize];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -185,8 +187,17 @@ impl VM {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute(&mut self) {
|
pub fn execute(&mut self) {
|
||||||
loop {
|
let mut running: bool = true;
|
||||||
self.registers.pc += 1;
|
|
||||||
|
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