cpu.rs: Reference chaining mutable functions
This commit is contained in:
parent
49a6fc0377
commit
5159afa3fd
57
src/cpu.rs
57
src/cpu.rs
@ -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) {
|
||||||
|
Loading…
Reference in New Issue
Block a user