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:
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