cpu.rs: Reference chaining mutable functions

This commit is contained in:
John 2023-03-25 18:09:41 -05:00
parent 49a6fc0377
commit 5159afa3fd

View File

@ -1,4 +1,4 @@
//! The CPU decodes and runs instructions //! Decodes and runs instructions
pub mod disassemble; pub mod disassemble;
@ -74,10 +74,10 @@ impl CPU {
/// Set a general purpose register in the CPU /// Set a general purpose register in the CPU
/// # Examples /// # Examples
/// ```rust /// ```rust
/// # use chumpulator::prelude::*; /// # use chirp::prelude::*;
/// // Create a new CPU, and set v4 to 0x41 /// // Create a new CPU, and set v4 to 0x41
/// let cpu = CPU::default() /// let mut cpu = CPU::default();
/// .set_gpr(0x4, 0x41); /// cpu.set_gpr(0x4, 0x41);
/// // Dump the CPU registers /// // Dump the CPU registers
/// cpu.dump(); /// cpu.dump();
/// ``` /// ```
@ -87,21 +87,21 @@ impl CPU {
} }
} }
/// Constructs a new CPU with sane defaults /// Constructs a new CPU, taking all configurable parameters
///
/// | value | default | description
/// |--------|---------|------------
/// | screen | 0x0f00 | Location of screen memory.
/// | font | 0x0050 | Location of font memory.
/// | pc | 0x0200 | Start location. Generally 0x200 or 0x600.
/// | sp | 0x0efe | Initial top of stack.
/// # Examples /// # Examples
/// ```rust /// ```rust
/// # use chumpulator::prelude::*; /// # use chirp::prelude::*;
/// let mut cpu = CPU::new(0xf00, 0x50, 0x200, 0xefe, Disassemble::default());
/// let mut cpu = CPU::new(0xf00, 0x50, 0x200, 0xefe, Disassemble::default(), vec![], ControlFlags::default()); /// let mut cpu = CPU::new(0xf00, 0x50, 0x200, 0xefe, Disassemble::default(), vec![], ControlFlags::default());
/// ``` /// ```
pub fn new(screen: Adr, font: Adr, pc: Adr, sp: Adr, disassembler: Disassemble) -> Self { pub fn new(
screen: Adr,
font: Adr,
pc: Adr,
sp: Adr,
disassembler: Disassemble,
breakpoints: Vec<Adr>,
flags: ControlFlags,
) -> Self {
CPU { CPU {
disassembler, disassembler,
screen, screen,
@ -114,11 +114,8 @@ impl CPU {
sound: 0, sound: 0,
cycle: 0, cycle: 0,
keys: [false; 16], keys: [false; 16],
breakpoints: vec![], breakpoints,
flags: ControlFlags { flags,
debug: true,
..Default::default()
},
} }
} }
@ -134,14 +131,15 @@ impl CPU {
} }
/// Set a breakpoint /// Set a breakpoint
pub fn set_break(&mut self, point: Adr) { pub fn set_break(&mut self, point: Adr) -> &mut Self {
if !self.breakpoints.contains(&point) { if !self.breakpoints.contains(&point) {
self.breakpoints.push(point) self.breakpoints.push(point)
} }
self
} }
/// Unset a breakpoint /// Unset a breakpoint
pub fn unset_break(&mut self, point: Adr) { pub fn unset_break(&mut self, point: Adr) -> &mut Self {
fn linear_find(needle: Adr, haystack: &Vec<Adr>) -> Option<usize> { fn linear_find(needle: Adr, haystack: &Vec<Adr>) -> Option<usize> {
for (i, v) in haystack.iter().enumerate() { for (i, v) in haystack.iter().enumerate() {
if *v == needle { if *v == needle {
@ -153,30 +151,32 @@ impl CPU {
if let Some(idx) = linear_find(point, &self.breakpoints) { if let Some(idx) = linear_find(point, &self.breakpoints) {
assert_eq!(point, self.breakpoints.swap_remove(idx)); assert_eq!(point, self.breakpoints.swap_remove(idx));
} }
self
} }
/// Unpauses the emulator for a single tick /// Unpauses the emulator for a single tick
/// NOTE: does not synchronize with delay timers /// NOTE: does not synchronize with delay timers
pub fn singlestep(&mut self, bus: &mut Bus) { pub fn singlestep(&mut self, bus: &mut Bus) -> &mut Self {
self.flags.pause = false; self.flags.pause = false;
self.tick(bus); self.tick(bus);
self.flags.pause = true; self
} }
/// Ticks the delay and sound timers /// Ticks the delay and sound timers
pub fn tick_timer(&mut self) { pub fn tick_timer(&mut self) -> &mut Self {
if self.flags.pause { if self.flags.pause {
return; return self;
} }
self.delay = self.delay.saturating_sub(1); self.delay = self.delay.saturating_sub(1);
self.sound = self.sound.saturating_sub(1); self.sound = self.sound.saturating_sub(1);
self
} }
/// Runs a single instruction /// Runs a single instruction
pub fn tick(&mut self, bus: &mut Bus) { pub fn tick(&mut self, bus: &mut Bus) -> &mut Self {
// Do nothing if paused // Do nothing if paused
if self.flags.pause || self.flags.keypause { if self.flags.pause || self.flags.keypause {
return; return self;
} }
let time = Instant::now(); let time = Instant::now();
// fetch opcode // fetch opcode
@ -322,6 +322,7 @@ impl CPU {
if self.breakpoints.contains(&self.pc) { if self.breakpoints.contains(&self.pc) {
self.flags.pause = true; self.flags.pause = true;
} }
self
} }
pub fn dump(&self) { pub fn dump(&self) {