riscii

An emulator for the RISC II
Log | Files | Refs | LICENSE

commit 88683f9e8accc92605d708e195badaa0a68ce6d0
parent 8b07082e318e434a35779eef9cf66b844c0925da
Author: Ryan Jeffrey <ryan@ryanmj.xyz>
Date:   Thu, 13 Oct 2022 22:17:04 -0700

Move register data into the data path

Diffstat:
Msrc/cpu.rs | 501++++++++++++++++++++++++++++++++-----------------------------------------------
Msrc/main.rs | 4++--
Msrc/system.rs | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Rsrc/windows.rs -> src/window.rs | 0
4 files changed, 265 insertions(+), 326 deletions(-)

diff --git a/src/cpu.rs b/src/cpu.rs @@ -44,6 +44,26 @@ pub const TOTAL_NUM_REGISTERS: usize = NUM_SPECIAL_REGISTERS + NUM_GLOBALS + NUM pub const SIZEOF_REG_FILE: usize = TOTAL_NUM_REGISTERS * 4; /// The size of an instruction in bytes. Amount to increment the program counter registers by. pub const SIZEOF_INSTRUCTION: u32 = 4; +/// Location of the interrupt bit in the PSW. +pub const INTERRUPT_LOC: u16 = 1 << 6; +/// Location of the system mode bit bit in the PSW. +pub const SYSTEM_LOC: u16 = 1 << 5; +/// Location of the previous system mode bit bit in the PSW. +pub const PREV_SYSTEM_LOC: u16 = 1 << 4; +/// Location of the zero bit bit in the PSW. +pub const ZERO_LOC: u16 = 1 << 3; +/// Location of the negative bit bit in the PSW. +pub const NEG_LOC: u16 = 1 << 2; +/// Location of the overflow bit bit in the PSW. +pub const OVERFLOW_LOC: u16 = 1 << 1; +/// Location of the carry bit bit in the PSW. +pub const CARRY_LOC: u16 = 1; +/// Location of the saved window pointer bits in the PSW. +pub const SWP_LOC: u16 = 0x7 << 7; +/// Location of the current window pointer bits in the PSW. +pub const CWP_LOC: u16 = 0x7 << 10; +/// Location of the processor status word in the 16 bit uint it is stored in. +pub const PSW_LOC: u16 = 0x1fff; // Struct definitions. /// A RISC II 32bit register. @@ -51,46 +71,21 @@ type Register = u32; // TODO maybe convert this into a u16? /// PSW. Contains internal state that is usually opaque to the system. -#[derive(Debug, Copy, Clone, PartialEq)] -pub struct ProcessorStatusWord { - /// Current window pointer (MOD 8). - cwp: u32, - /// Saved window pointer (MOD 8). - swp: u32, - /// If interrupts are enabled. - interrupts_enabled: bool, - /// System bit, true if running in privileged state. - system_mode: bool, - /// The previous state of the `system_mode` bit the last time it was changed. - previous_system_mode: bool, - /// Condition codes zero (Z). - cc_zero: bool, - /// Condition code negative (N). - cc_neg: bool, - /// Condition code overflow (V). - cc_overflow: bool, - /// Condition code carry (C). - cc_carry: bool, -} +/// [12:10] -> Current window pointer (CWP). +/// [9:7] -> Saved window pointer (SWP). +/// [6] Interrupts enabled bit (I). +/// [5] System mode bit (S). +/// [4] Previous system mode bit (P). +/// [3] Zero bit (Z). +/// [2] Negative bit (N). +/// [1] Overflow bit (V). +/// [0] Carry bit (C). +#[derive(Copy, Clone, PartialEq)] +pub struct ProcessorStatusWord(u16); /// The CPU's register state. #[derive(Debug, Copy, Clone, PartialEq)] -pub struct RegisterFile { - /// Next program counter, holds the address of the instruction being - /// fetched for the next cycle. - pub nxtpc: Register, - /// Program counter, holds the address of current instruction being - /// executed. - pub pc: Register, - /// The lastpc, holds the address of the last executed instruction - /// (or last attempted to be executed). When running an interrupt `lstpc` - /// holds the address of the instruction that was aborted. - pub lstpc: Register, - /// Global registers. - globals: [Register; NUM_GLOBALS], - /// Register window stack. - window_regs: [Register; NUM_WINDOW_REGISTERS], // TODO test, there should be 138 regs. -} +pub struct RegisterFile([u32; NUM_GLOBALS + NUM_WINDOW_REGISTERS]); // Struct implementations. @@ -98,92 +93,94 @@ impl RegisterFile { /// Create a 0'd out register window. pub fn new() -> Self { Self { - nxtpc: 0, - pc: 0, - lstpc: 0, - globals: [0; NUM_GLOBALS], - window_regs: [0; NUM_WINDOW_REGISTERS], - } - } - - /// Create a register state from a buffer. - /// # Arguments - /// * `buf` - A byte buffer that is the size of the sum of of register::RegisterFile's - /// members (in bytes) (see `SIZEOF_REG_FILE`). - /// The registers should appear in the following order: - /// - NXTPC - /// - PC - /// - LSTPC - /// - Global registers - /// - Window registers - pub fn from_buf(buf: [u8; SIZEOF_REG_FILE]) -> Self { - // Offset used for gloabls and window_regs. - let mut cur_offset = NUM_SPECIAL_REGISTERS * 4; - Self { - nxtpc: u32::from_be_bytes(buf[..4].try_into().unwrap()), - pc: u32::from_be_bytes(buf[4..8].try_into().unwrap()), - lstpc: u32::from_be_bytes(buf[8..cur_offset].try_into().unwrap()), - globals: { - let mut result = [0u32; NUM_GLOBALS]; - for i in 0..result.len() { - result[i] = - u32::from_be_bytes(buf[cur_offset..cur_offset + 4].try_into().unwrap()); - cur_offset += 4; - } - // Ensure r0 is 0. - result[0] = 0; - result - }, - window_regs: { - let mut result = [0u32; NUM_WINDOW_REGISTERS]; - for i in 0..result.len() { - result[i] = - u32::from_be_bytes(buf[cur_offset..cur_offset + 4].try_into().unwrap()); - cur_offset += 4; - } - result - }, + 0: [0u32; NUM_GLOBALS + NUM_WINDOW_REGISTERS], } } - /// Convert self to a byte buffer of all of the register values. - pub fn to_buf(&self) -> [u8; SIZEOF_REG_FILE] { - let mut result = [0u8; SIZEOF_REG_FILE]; - // Offset of the special registers to the general purpose registers (bytes). - const SPECIAL_OFFSET: usize = NUM_SPECIAL_REGISTERS * 4; - result[..4].copy_from_slice(&self.nxtpc.to_be_bytes()); - result[4..8].copy_from_slice(&self.pc.to_be_bytes()); - result[8..SPECIAL_OFFSET].copy_from_slice(&self.lstpc.to_be_bytes()); - let globals = { - let mut tmp = [0u8; NUM_GLOBALS * 4]; - for i in 0..NUM_GLOBALS { - tmp[i * SPECIAL_OFFSET..i * SPECIAL_OFFSET + 4] - .copy_from_slice(&self.globals[i].to_be_bytes()); - } - tmp - }; - const GLOBAL_OFFSET: usize = NUM_SPECIAL_REGISTERS + NUM_GLOBALS * 4; - result[NUM_SPECIAL_REGISTERS..GLOBAL_OFFSET].copy_from_slice(&globals); - - let win_regs = { - let mut tmp = [0u8; NUM_WINDOW_REGISTERS * 4]; - for i in 0..NUM_WINDOW_REGISTERS { - tmp[i * SPECIAL_OFFSET..i * SPECIAL_OFFSET + 4] - .copy_from_slice(&self.window_regs[i].to_be_bytes()); - } - tmp - }; - - result[GLOBAL_OFFSET..].copy_from_slice(&win_regs); - result - } + // TODO refactor. + // /// Create a register state from a buffer. + // /// # Arguments + // /// * `buf` - A byte buffer that is the size of the sum of of register::RegisterFile's + // /// members (in bytes) (see `SIZEOF_REG_FILE`). + // /// The registers should appear in the following order: + // /// - NXTPC + // /// - PC + // /// - LSTPC + // /// - Global registers + // /// - Window registers + // pub fn from_buf(buf: [u8; SIZEOF_REG_FILE]) -> Self { + // // Offset used for gloabls and window_regs. + // let mut cur_offset = NUM_SPECIAL_REGISTERS * 4; + // Self { + // nxtpc: u32::from_be_bytes(buf[..4].try_into().unwrap()), + // pc: u32::from_be_bytes(buf[4..8].try_into().unwrap()), + // lstpc: u32::from_be_bytes(buf[8..cur_offset].try_into().unwrap()), + // globals: { + // let mut result = [0u32; NUM_GLOBALS]; + // for i in 0..result.len() { + // result[i] = + // u32::from_be_bytes(buf[cur_offset..cur_offset + 4].try_into().unwrap()); + // cur_offset += 4; + // } + // // Ensure r0 is 0. + // result[0] = 0; + // result + // }, + // window_regs: { + // let mut result = [0u32; NUM_WINDOW_REGISTERS]; + // for i in 0..result.len() { + // result[i] = + // u32::from_be_bytes(buf[cur_offset..cur_offset + 4].try_into().unwrap()); + // cur_offset += 4; + // } + // result + // }, + // } + // } + + //// Convert self to a byte buffer of all of the register values. + // TODO refactor + // pub fn to_buf(&self) -> [u8; SIZEOF_REG_FILE] { + // let mut result = [0u8; SIZEOF_REG_FILE]; + // // Offset of the special registers to the general purpose registers (bytes). + // const SPECIAL_OFFSET: usize = NUM_SPECIAL_REGISTERS * 4; + // result[..4].copy_from_slice(&self.nxtpc.to_be_bytes()); + // result[4..8].copy_from_slice(&self.pc.to_be_bytes()); + // result[8..SPECIAL_OFFSET].copy_from_slice(&self.lstpc.to_be_bytes()); + // let globals = { + // let mut tmp = [0u8; NUM_GLOBALS * 4]; + // for i in 0..NUM_GLOBALS { + // tmp[i * SPECIAL_OFFSET..i * SPECIAL_OFFSET + 4] + // .copy_from_slice(&self.globals[i].to_be_bytes()); + // } + // tmp + // }; + // const GLOBAL_OFFSET: usize = NUM_SPECIAL_REGISTERS + NUM_GLOBALS * 4; + // result[NUM_SPECIAL_REGISTERS..GLOBAL_OFFSET].copy_from_slice(&globals); + + // let win_regs = { + // let mut tmp = [0u8; NUM_WINDOW_REGISTERS * 4]; + // for i in 0..NUM_WINDOW_REGISTERS { + // tmp[i * SPECIAL_OFFSET..i * SPECIAL_OFFSET + 4] + // .copy_from_slice(&self.window_regs[i].to_be_bytes()); + // } + // tmp + // }; + + // result[GLOBAL_OFFSET..].copy_from_slice(&win_regs); + // result + // } /// Flush entire register window to memory. /// # Arguments /// * `mem` - Memory to flush to. /// * `addr` - Memory address to flush to. pub fn flush_to_mem(&self, mem: &mut Memory, addr: u32) { - mem.write_buf(addr, &self.to_buf()); + let mut address = addr; + for i in self.0.iter() { + mem.set_word(address, *i); + address += 4; + } } /// Get a register's value (unsigned). Return the register's value @@ -196,27 +193,14 @@ impl RegisterFile { /// # Arguments /// * `which` - Which register. [0-31] are the only valid values. /// * `psw` - Processor status object, contains window information. - pub fn ru(&self, which: u32, psw: &ProcessorStatusWord) -> Result<u32> { - let which = which as usize; - Ok(match which { - 0..=9 => self.globals[which], - 10..=31 => self.window_regs[NUM_ADDED_PER_WINDOW * psw.get_cwp() as usize + which], - _ => return berr!(format!("Register {} is out of range", which)), - }) - } - - /// Get a register's value (signed). Return the register's value - /// on success and a string message on error. - /// Register mapping: [0-9] -> Globals - /// [10-15] -> Outs - /// [16-25] -> Locals - /// [31-26] -> Ins - /// Anything outside this [0-31] range is an invalid argument. - /// # Arguments - /// * `which` - Which register. [0-31] are the only valid values. - /// * `psw` - Processor status object, contains window information. - pub fn rs(&self, which: u32, psw: &ProcessorStatusWord) -> Result<i32> { - Ok(self.ru(which, psw)? as i32) + pub fn read(&self, address: u32, cwp: u8) -> u32 { + let addr = address as usize; + let ptr = cwp as usize; + match addr { + 0..=9 => self.0[addr], + 10..=31 => self.0[NUM_ADDED_PER_WINDOW * ptr + addr + NUM_GLOBALS], + _ => 0, + } } /// Set a register's value (unsigned). Return the register's value on @@ -229,98 +213,36 @@ impl RegisterFile { /// # Arguments /// * `which` - Which register. [0-31] are the only valid values. /// * `psw` - Processor status object, contains window information. - pub fn rus(&mut self, which: u32, value: u32, psw: ProcessorStatusWord) -> Result<u32> { - let which = which as usize; - match which { - 0..=9 => self.globals[which] = value, - 10..=31 => { - self.window_regs[NUM_ADDED_PER_WINDOW * psw.get_cwp() as usize + which] = value - } - _ => return berr!(format!("Register {} is out of range", which)), + pub fn write(&mut self, address: u32, value: u32, cwp: u8) { + let addr = address as usize; + let ptr = cwp as usize; + match addr { + 0..=9 => self.0[addr] = value, + 10..=31 => self.0[NUM_ADDED_PER_WINDOW * ptr + addr + NUM_GLOBALS] = value, + _ => {} } - Ok(value) - } - - pub fn get_last_pc(&self) -> u32 { - self.lstpc - } - - pub fn get_pc(&self) -> u32 { - self.pc - } - - pub fn get_next_pc(&self) -> u32 { - self.nxtpc - } - - pub fn inc_pcs(&mut self) { - self.lstpc = self.pc; - self.pc = self.nxtpc; - self.nxtpc += SIZEOF_INSTRUCTION; - } - - pub fn branch_to(&mut self, to: u32) { - self.lstpc = self.pc; - self.pc = self.nxtpc; - self.nxtpc = to; - } - - pub fn get_ss_val(&self, ss: ShortSource, psw: &ProcessorStatusWord) -> Result<u32> { - type SS = ShortSource; - Ok(match ss { - SS::Reg(r) => self.ru(r as u32, psw)?, - SS::Imm13(u) => u, - }) } } impl fmt::Display for RegisterFile { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "Next PC: 0x{:x} -PC: 0x{:x} -Last PC: 0x{:x} -Globals: {:?} -Window: {:?}", - self.nxtpc, self.pc, self.lstpc, self.globals, self.window_regs - ) + write!(f, "{:?}", self.0) } } impl ProcessorStatusWord { /// Create a 0'd out PSW. pub fn new() -> Self { - Self { - cwp: 0, - swp: 0, - interrupts_enabled: false, - system_mode: false, - previous_system_mode: false, - cc_zero: false, - cc_neg: false, - cc_overflow: false, - cc_carry: false, - } + Self { 0: 0 } } - pub fn from_u32(v: u32) -> Self { - Self { - cwp: (v & (0x7 << 7)) >> 7, - swp: (v & (0x7 << 10)) >> 10, - interrupts_enabled: v & (0x1 << 6) != 0, - previous_system_mode: v & (0x1 << 5) != 0, - system_mode: v & (0x1 << 4) != 0, - cc_zero: v & (0x1 << 3) != 0, - cc_neg: v & (0x1 << 2) != 0, - cc_overflow: v & (0x1 << 1) != 0, - cc_carry: v & 0x1 != 0, - } + pub fn from_u16(v: u16) -> Self { + Self { 0: v } } pub fn init( - cwp: u32, - swp: u32, + cwp: u8, + swp: u8, interrupts_enabled: bool, previous_system_mode: bool, system_mode: bool, @@ -330,138 +252,125 @@ impl ProcessorStatusWord { cc_carry: bool, ) -> Self { Self { - cwp: cwp % 8, - swp: swp % 8, - interrupts_enabled: interrupts_enabled, - previous_system_mode: previous_system_mode, - system_mode: system_mode, - cc_zero: cc_zero, - cc_neg: cc_neg, - cc_overflow: cc_overflow, - cc_carry: cc_carry, + 0: (((cwp as u16) & 0x7) << 10) + | (((swp as u16) & 0x7) << 7) + | ((interrupts_enabled as u16) << 6) + | ((system_mode as u16) << 5) + | ((previous_system_mode as u16) << 4) + | ((cc_zero as u16) << 3) + | ((cc_neg as u16) << 2) + | ((cc_overflow as u16) << 1) + | (cc_carry as u16), } } - /// Get the 13 bit PSW value. PSW is the state of the system's special - /// registers and CC's. After the 13th bit PSW is 0 padded. - /// Format of PSW: - /// [0]: Carry bit - /// [1]: Overflow bit - /// [2]: Negative bit - /// [3]: Zero bit - /// [4]: Previous system mode bit. - /// [5]: System mode bit. - /// [6]: Interrupt enable bit. - /// [7-9]: SWP register mod 8. - /// [10-12]: CWP register mod 8. - pub fn to_u32(&self) -> u32 { - (self.cc_carry as u32 - | (self.cc_overflow as u32) << 1 - | (self.cc_neg as u32) << 2 - | (self.cc_zero as u32) << 3 - | (self.previous_system_mode as u32) << 4 - | (self.system_mode as u32) << 5 - | (self.interrupts_enabled as u32) << 6 - | (self.cwp) << 7 - | (self.swp) << 10) - & 0x1fff + pub fn get(&self) -> u16 { + self.0 } /// Push the register window stack. Set CWP to CWP-1 MOD 8. Push the top /// window to memory and increment SWP if necessary. - pub fn push_reg_window(&mut self) { - self.cwp = (self.cwp - 1) % NUM_REG_WINDOWS as u32; - if self.cwp == self.swp { + pub fn push(&mut self) { + let cwp = self.get_cwp() - 1; + let swp = self.get_swp(); + if cwp == swp { // TODO save windows to memory. - self.swp = (self.swp + 1) % NUM_REG_WINDOWS as u32; + self.set_swp(swp + 1); } } /// Pop the register window stack. Set CWP to CWP+1 MOD 8. Pull the bottom /// window from memory and decrement SWP if necessary. - pub fn pop_reg_window(&mut self) { - self.cwp = (self.cwp + 1) % NUM_REG_WINDOWS as u32; - if self.cwp == self.swp { - // TODO restore windows from memory. - self.swp = (self.swp - 1) % NUM_REG_WINDOWS as u32; + pub fn pop(&mut self) { + let cwp = self.get_cwp() + 1; + let swp = self.get_swp(); + if cwp == swp { + // TODO save windows to memory. + self.set_swp(swp - 1); } } - pub fn set_cwp(&mut self, v: u32) { - self.cwp = v % NUM_REG_WINDOWS as u32; + pub fn set_cwp(&mut self, v: u8) { + self.0 = ((self.0 & !CWP_LOC) | ((v % NUM_REG_WINDOWS as u8) << 10) as u16) & PSW_LOC; } - pub fn set_swp(&mut self, v: u32) { - self.swp = v % NUM_REG_WINDOWS as u32; + pub fn set_swp(&mut self, v: u8) { + self.0 = ((self.0 & !SWP_LOC) | ((v % NUM_REG_WINDOWS as u8) << 7) as u16) & PSW_LOC; } - pub fn get_cwp(&self) -> u32 { - self.cwp + pub fn set_cc_overflow(&mut self, value: bool) { + self.0 = (self.0 & !OVERFLOW_LOC) | ((value as u16) << OVERFLOW_LOC); } - pub fn get_swp(&self) -> u32 { - self.swp + pub fn set_cc_carry(&mut self, value: bool) { + self.0 = (self.0 & !CARRY_LOC) | ((value as u16) << CARRY_LOC); } - pub fn get_cc_overflow(&self) -> bool { - self.cc_overflow + pub fn set_cc_zero(&mut self, value: bool) { + self.0 = (self.0 & !ZERO_LOC) | ((value as u16) << ZERO_LOC); } - pub fn get_cc_carry(&self) -> bool { - self.cc_carry + pub fn set_cc_neg(&mut self, value: bool) { + self.0 = (self.0 & !NEG_LOC) | ((value as u16) << NEG_LOC); } - pub fn get_cc_zero(&self) -> bool { - self.cc_zero + pub fn set_system_mode(&mut self, value: bool) { + self.0 = (self.0 & !SYSTEM_LOC) | ((value as u16) << SYSTEM_LOC); } - pub fn get_cc_neg(&self) -> bool { - self.cc_neg + pub fn set_previous_system_mode(&mut self, value: bool) { + self.0 = (self.0 & !PREV_SYSTEM_LOC) | ((value as u16) << PREV_SYSTEM_LOC); } - pub fn set_cc_overflow(&mut self, value: bool) { - self.cc_overflow = value; + pub fn set_interrupt_enabled(&mut self, value: bool) { + self.0 = (self.0 & !INTERRUPT_LOC) | ((value as u16) << INTERRUPT_LOC); } - pub fn set_cc_carry(&mut self, value: bool) { - self.cc_carry = value; + pub fn get_cwp(&self) -> u8 { + ((self.0 & CWP_LOC) as u8) >> 10 } - pub fn set_cc_zero(&mut self, value: bool) { - self.cc_zero = value; + pub fn get_swp(&self) -> u8 { + ((self.0 & SWP_LOC) as u8) >> 7 } - pub fn set_cc_neg(&mut self, value: bool) { - self.cc_neg = value; + pub fn get_cc_overflow(&self) -> bool { + (self.0 & OVERFLOW_LOC) != 0 } - pub fn set_system_mode(&mut self, v: bool) { - self.system_mode = v; + pub fn get_cc_carry(&self) -> bool { + (self.0 & CARRY_LOC) != 0 } - pub fn set_previous_system_mode(&mut self, v: bool) { - self.previous_system_mode = v; + pub fn get_cc_zero(&self) -> bool { + (self.0 & ZERO_LOC) != 0 } - pub fn set_interrupt_enabled(&mut self, v: bool) { - self.interrupts_enabled = v; + pub fn get_cc_neg(&self) -> bool { + (self.0 & NEG_LOC) != 0 } - pub fn is_system_mode(&self) -> bool { - self.system_mode + pub fn get_system_mode(&self) -> bool { + (self.0 & SYSTEM_LOC) != 0 } - pub fn is_previous_system_mode(&self) -> bool { - self.previous_system_mode + pub fn get_previous_system_mode(&self) -> bool { + (self.0 & PREV_SYSTEM_LOC) != 0 } - pub fn is_interrupt_enabled(&self) -> bool { - self.interrupts_enabled + pub fn get_interrupt_enabled(&self) -> bool { + (self.0 & INTERRUPT_LOC) != 0 } } impl fmt::Display for ProcessorStatusWord { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "0x{:x}", self.0) + } +} + +impl fmt::Debug for ProcessorStatusWord { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, "Current window pointer: {} @@ -473,15 +382,15 @@ CC Zero: {} CC Negative: {} CC Overflow: {} CC Carry: {}", - self.cwp, - self.swp, - privilege_string(self.interrupts_enabled), - privilege_string(self.system_mode), - privilege_string(self.previous_system_mode), - bool_hl_string(self.cc_zero), - bool_hl_string(self.cc_neg), - bool_hl_string(self.cc_overflow), - bool_hl_string(self.cc_carry) + self.get_cwp(), + self.get_swp(), + bool_hl_string(self.get_interrupt_enabled()), + privilege_string(self.get_system_mode()), + privilege_string(self.get_previous_system_mode()), + bool_hl_string(self.get_cc_zero()), + bool_hl_string(self.get_cc_neg()), + bool_hl_string(self.get_cc_overflow()), + bool_hl_string(self.get_cc_carry()) ) } } diff --git a/src/main.rs b/src/main.rs @@ -34,7 +34,7 @@ pub mod memory; pub mod sdl; pub mod system; pub mod util; -pub mod windows; +pub mod window; use config::Config; use debug_window::DebugWindow; @@ -44,7 +44,7 @@ use sdl2::keyboard::Keycode; use std::boxed::Box; use std::error::Error; use system::System; -use windows::MainWindow; +use window::MainWindow; // Struct/enum declarations. diff --git a/src/system.rs b/src/system.rs @@ -15,13 +15,15 @@ // along with this program. If not, see <https://www.gnu.org/licenses/>. use config::Config; -use cpu::{ProcessorStatusWord, RegisterFile}; +use cpu::{ProcessorStatusWord, RegisterFile, SIZEOF_INSTRUCTION}; use instruction::noop; use memory::Memory; use std::fmt; use util::Result; -/// RISC II emulated system. +use crate::cpu; + +/// RISC II emulated data path. #[derive(Debug, Clone)] pub struct System { /// RISC II register file. @@ -31,9 +33,31 @@ pub struct System { /// Memory state. mem: Memory, /// Temporary latch for destination register. - tmp_latch: u32, + dst_latch: u32, + /// Source latch for the shifter and ALU. + src_latch: u32, /// Next instruction. next_instruction: u32, + /// Destination register address. + rd: u8, + /// Source register one. + ra: u8, + /// Source register two. + rb: u8, + /// Opcode register. + op: u8, + /// Immediate register. + imm: u32, + /// Next program counter, holds the address of the instruction being + /// fetched for the next cycle. + nxtpc: u32, + /// Program counter, holds the address of current instruction being + /// executed. + pc: u32, + /// The lastpc, holds the address of the last executed instruction + /// (or last attempted to be executed). When running an interrupt `lstpc` + /// holds the address of the instruction that was aborted. + lstpc: u32, } // Impls. @@ -48,11 +72,32 @@ impl System { regs: RegisterFile::new(), psw: ProcessorStatusWord::new(), mem: Memory::new(config), - tmp_latch: 0, + src_latch: 0, + dst_latch: 0, next_instruction: noop(), + rd: 0, + ra: 0, + rb: 0, + op: 0, + imm: 0, + nxtpc: 0, + pc: 0, + lstpc: 0, }) } + fn increment_pcs(&mut self) { + self.lstpc = self.pc; + self.pc = self.nxtpc; + self.nxtpc += cpu::SIZEOF_INSTRUCTION; + } + + fn branch_to(&mut self, address: u32) { + self.lstpc = self.pc; + self.pc = self.nxtpc; + self.nxtpc = address; + } + /// Get the 13 bit PSW value. PSW is the state of the system's special /// registers and CC's. After the 13th bit PSW is 0 padded. /// Format of PSW: @@ -66,15 +111,15 @@ impl System { /// [7-9]: SWP register mod 8. /// [10-12]: CWP register mod 8. pub fn get_psw_as_u32(&self) -> u32 { - self.psw.to_u32() + self.psw.get() as u32 } pub fn call(&mut self, addr: u32) { - self.psw.push_reg_window(); + self.psw.push(); } pub fn ret(&mut self) { - self.psw.pop_reg_window(); + self.psw.pop(); } pub fn get_register_file(&mut self) -> &mut RegisterFile { @@ -86,38 +131,23 @@ impl System { } pub fn get_last_pc(&self) -> u32 { - self.regs.get_last_pc() + self.lstpc } pub fn get_pc(&self) -> u32 { - self.regs.get_pc() + self.pc } pub fn get_next_pc(&self) -> u32 { - self.regs.get_next_pc() - } - - pub fn integrate_system_changes(&mut self, other: &System) { - self.regs = other.regs; - self.psw = other.psw; + self.nxtpc } pub fn get_psw(&self) -> ProcessorStatusWord { self.psw } - pub fn set_psw(&mut self, psw: u32) { - self.psw = ProcessorStatusWord::from_u32(psw); - } - - pub fn copy_no_mem(&self) -> Self { - System { - regs: self.regs, - psw: self.psw, - mem: Memory::from_size(0), - next_instruction: self.next_instruction, - tmp_latch: self.tmp_latch, - } + pub fn set_psw(&mut self, psw: u16) { + self.psw = ProcessorStatusWord::from_u16(psw); } pub fn get_mem_ref(&mut self) -> &mut Memory { @@ -132,7 +162,7 @@ impl System { } fn fetch(&mut self) -> Result<()> { - self.next_instruction = self.mem.get_word(self.regs.nxtpc)?; + self.next_instruction = self.mem.get_word(self.nxtpc)?; Ok(()) } diff --git a/src/windows.rs b/src/window.rs