From 3b3421dc1b09def9a9eed665ff1d8364bb975793 Mon Sep 17 00:00:00 2001 From: vik <> Date: Wed, 1 Jan 2025 19:42:52 -0600 Subject: [PATCH] implement get opcode from instr --- src/isa.rs | 71 +++++++++++++++++++++++ src/lib.rs | 3 + src/main.rs | 164 +++------------------------------------------------- src/mem.rs | 2 - src/vm.rs | 111 +++++++++++++++++++++++++++++++++++ 5 files changed, 193 insertions(+), 158 deletions(-) create mode 100644 src/isa.rs create mode 100644 src/lib.rs create mode 100644 src/vm.rs diff --git a/src/isa.rs b/src/isa.rs new file mode 100644 index 0000000..a5a73c6 --- /dev/null +++ b/src/isa.rs @@ -0,0 +1,71 @@ +#[allow(dead_code)] + +use crate::vm::VM; + +enum Opcode { + BR = 0, + ADD, + LD, + ST, + JSR, + AND, + LDR, + STR, + RTI, + NOT, + LDI, + STI, + JMP, + RES, + LEA, + TRAP, + NOOP, +} + +fn get_opcode(instr: u16) -> Opcode { + match instr >> 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_opcode(vm: &mut VM) { + let instr = vm.memory.get(vm.registers.pc); + let opcode = get_opcode(instr); + match opcode { + Opcode::ADD => noop(instr, vm), + Opcode::AND => noop(instr, vm), + Opcode::NOT => noop(instr, vm), + Opcode::BR => noop(instr, vm), + Opcode::JMP => noop(instr, vm), + Opcode::JSR => noop(instr, vm), + Opcode::LD => noop(instr, vm), + Opcode::LDI => noop(instr, vm), + Opcode::LDR => noop(instr, vm), + Opcode::LEA => noop(instr, vm), + Opcode::ST => noop(instr, vm), + Opcode::STI => noop(instr, vm), + Opcode::STR => noop(instr, vm), + Opcode::TRAP => noop(instr, vm), + _ => {} + } +} + +fn noop(instr: u16, vm: &mut VM) {} + + diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..2e0cbc5 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,3 @@ +pub mod mem; +pub mod isa; +pub mod vm; diff --git a/src/main.rs b/src/main.rs index fceed45..0fa9fda 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,161 +1,13 @@ #![allow(dead_code)] -mod mem; -use core::panic; -// use std::env; -// use std::fs; -// use std::io; -// use std::io::Read; -use std::{env, u16}; -use mem::Memory; - -const PC_START: u16 = 0x300; - -enum Opcodes { - BR = 0, - ADD, - LD, - ST, - JSR, - AND, - LDR, - STR, - RTI, - NOT, - LDI, - STI, - JMP, - RES, - LEA, - TRAP, -} - -struct Registers { - r0: u16, - r1: u16, - r2: u16, - r3: u16, - r4: u16, - r5: u16, - r6: u16, - r7: u16, - pc: u16, - cond: u16, -} - -enum ConditionFlags { - // condition flags can only be set as nzp with a 1 in each position - POS = 1 << 0, - ZERO = 1 << 1, - NEG = 1 << 2, -} - -impl Registers { - fn new() -> Registers { - Registers { - r0: 0, - r1: 0, - r2: 0, - r3: 0, - r4: 0, - r5: 0, - r6: 0, - r7: 0, - pc: PC_START, - cond: 0, - } - } - - // s/o dogeystamp for this cool register return logic - // most other vms just updated it with a &mut self - - fn return_register(&mut self, num: u16) -> &mut u16 { - match num { - 0 => &mut self.r0, - 1 => &mut self.r1, - 2 => &mut self.r2, - 3 => &mut self.r3, - 4 => &mut self.r4, - 5 => &mut self.r5, - 6 => &mut self.r6, - 7 => &mut self.r7, - 8 => &mut self.pc, - 9 => &mut self.cond, - _ => panic!("not a register!"), - } - } - - fn get_register(&mut self, num: u16) -> u16 { - *self.return_register(num) - } - - fn set_registers(&mut self, num : u16, value: u16) { - *self.return_register(num) = value; - } - - fn update_cond(&mut self, num : u16) { - if *self.return_register(num) > 0 { - self.cond = ConditionFlags::POS as u16; - } else if *self.return_register(num) == 0 { - self.cond = ConditionFlags::ZERO as u16; - } else { - self.cond = ConditionFlags::NEG as u16 - } - } - - fn update_reg_and_cond(&mut self, num : u16, value: u16) { - self.set_registers(num, value); - self.update_cond(num); - } -} - - -struct VM { - memory: Memory, - registers: Registers, -} - -impl VM { - fn new() -> VM { - VM{ - memory: Memory::new(), - registers: Registers::new(), - } - } - - fn execute(&mut self) { - while self.registers.pc < 0x3010 { - let instruction = self.memory.get(self.registers.pc); - match instruction >> 12 { - 0 => println!("opcode BR at address {:#x}", self.registers.pc), - 1 => println!("opcode ADD at address {:#x}", self.registers.pc), - 2 => println!("opcode LD at address {:#x}", self.registers.pc), - 3 => println!("opcode ST at address {:#x}", self.registers.pc), - 4 => println!("opcode JSR/JSRR at address {:#x}", self.registers.pc), - 5 => println!("opcode AND at address {:#x}", self.registers.pc), - 6 => println!("opcode LDR at address {:#x}", self.registers.pc), - 7 => println!("opcode STR at address {:#x}", self.registers.pc), - 8 => println!("opcode RTI at address {:#x}", self.registers.pc), - 9 => println!("opcode NOT at address {:#x}", self.registers.pc), - 10 => println!("opcode LDI at address {:#x}", self.registers.pc), - 11 => println!("opcode STI at address {:#x}", self.registers.pc), - 12 => println!("opcode RET at address {:#x}", self.registers.pc), - 13 => println!("reserved opcode at address {:#x}", self.registers.pc), - 14 => println!("opcode LEA at address {:#x}", self.registers.pc), - 15 => println!("opcode TRAP at address {:#x}", self.registers.pc), - _ => println!("this is a no op at address {:#x}", self.registers.pc), - } - self.registers.pc += 1; - } - } -} - - +mod vm; +use mem; fn main() { - let mut lc3 = VM::new(); - let args: Vec = env::args().collect(); - let path = args.get(1).expect("a file must be specified"); - lc3.memory.read(path.to_string()); - lc3.execute(); + let lc3 = vm::VM::new(); + // let mut lc3 = VM::new(); + // let args: Vec = env::args().collect(); + // let path = args.get(1).expect("a file must be specified"); + // lc3.memory.read(path.to_string()); + // lc3.execute(); } diff --git a/src/mem.rs b/src/mem.rs index e0d9ded..d977a27 100644 --- a/src/mem.rs +++ b/src/mem.rs @@ -1,5 +1,3 @@ -#![allow(dead_code)] - use std::{fs, io::{self, Read}}; pub const MEM_SIZE: usize = u16::MAX as usize; diff --git a/src/vm.rs b/src/vm.rs new file mode 100644 index 0000000..ee43ba2 --- /dev/null +++ b/src/vm.rs @@ -0,0 +1,111 @@ +#[allow(dead_code)] + +use crate::mem::Memory; + +const PC_START: u16 = 0x300; + +pub struct Registers { + pub r0: u16, + pub r1: u16, + pub r2: u16, + pub r3: u16, + pub r4: u16, + pub r5: u16, + pub r6: u16, + pub r7: u16, + pub pc: u16, + pub cond: u16, +} + +enum ConditionFlags { + // condition flags can only be set as nzp with a 1 in each position + POS = 1 << 0, + ZERO = 1 << 1, + NEG = 1 << 2, +} + +impl Registers { + fn new() -> Registers { + Registers { + r0: 0, + r1: 0, + r2: 0, + r3: 0, + r4: 0, + r5: 0, + r6: 0, + r7: 0, + pc: PC_START, + cond: 0, + } + } + + // s/o dogeystamp for this cool register return logic + // most other vms just updated it with a &mut self + + fn return_register(&mut self, num: u16) -> &mut u16 { + match num { + 0 => &mut self.r0, + 1 => &mut self.r1, + 2 => &mut self.r2, + 3 => &mut self.r3, + 4 => &mut self.r4, + 5 => &mut self.r5, + 6 => &mut self.r6, + 7 => &mut self.r7, + 8 => &mut self.pc, + 9 => &mut self.cond, + _ => panic!("not a register!"), + } + } + + fn get_register(&mut self, num: u16) -> u16 { + *self.return_register(num) + } + + fn set_registers(&mut self, num : u16, value: u16) { + *self.return_register(num) = value; + } + + fn update_cond(&mut self, num : u16) { + if *self.return_register(num) > 0 { + self.cond = ConditionFlags::POS as u16; + } else if *self.return_register(num) == 0 { + self.cond = ConditionFlags::ZERO as u16; + } else { + self.cond = ConditionFlags::NEG as u16 + } + } + + fn update_reg_and_cond(&mut self, num : u16, value: u16) { + self.set_registers(num, value); + self.update_cond(num); + } +} + + +pub struct VM { + pub memory: Memory, + pub registers: Registers, +} + +impl VM { + pub fn new() -> VM { + VM{ + memory: Memory::new(), + registers: Registers::new(), + } + } +} + +// pub fn execute(&mut self) { +// while self.registers.pc < 0x3010 { +// let instruction = self.memory.get(self.registers.pc); +// match instruction >> 12 { +// _ => todo!(), +// } +// self.registers.pc += 1; +// } +// } +// } +