tests: Update tests to match current behavior.

This commit is contained in:
John 2023-04-01 02:31:51 -05:00
parent a4c548d0ec
commit f27537b3b8
3 changed files with 61 additions and 8 deletions

View File

@ -522,6 +522,11 @@ impl CPU {
} }
/// Executes a single instruction /// Executes a single instruction
///
/// Returns [Error::BreakpointHit] if a breakpoint was hit after the instruction executed.
/// This result contains information about the breakpoint, but can be safely ignored.
///
/// Returns [Error::UnimplementedInstruction] if the instruction at `pc` is unimplemented.
/// # Examples /// # Examples
/// ```rust /// ```rust
/// # use chirp::*; /// # use chirp::*;
@ -552,11 +557,8 @@ impl CPU {
/// ], /// ],
/// Screen [0x0f00..0x1000], /// Screen [0x0f00..0x1000],
/// }; /// };
/// match cpu.tick(&mut bus) { /// dbg!(cpu.tick(&mut bus))
/// Err(Error::UnimplementedInstruction {word}) /// .expect_err("Should return Error::InvalidInstruction { 0xffff }");
/// => assert_eq!(0xffff, word),
/// _ => panic!(),
/// }
/// ``` /// ```
pub fn tick(&mut self, bus: &mut Bus) -> Result<&mut Self> { pub fn tick(&mut self, bus: &mut Bus) -> Result<&mut Self> {
// Do nothing if paused // Do nothing if paused
@ -571,7 +573,9 @@ impl CPU {
// fetch opcode // fetch opcode
let opcode: &[u8; 2] = if let Some(slice) = bus.get(self.pc as usize..self.pc as usize + 2) let opcode: &[u8; 2] = if let Some(slice) = bus.get(self.pc as usize..self.pc as usize + 2)
{ {
slice.try_into()? slice
.try_into()
.expect("`slice` should be exactly 2 bytes.")
} else { } else {
return Err(Error::InvalidBusRange { return Err(Error::InvalidBusRange {
range: self.pc as usize..self.pc as usize + 2, range: self.pc as usize..self.pc as usize + 2,
@ -603,6 +607,10 @@ impl CPU {
// process breakpoints // process breakpoints
if !self.breakpoints.is_empty() && self.breakpoints.contains(&self.pc) { if !self.breakpoints.is_empty() && self.breakpoints.contains(&self.pc) {
self.flags.pause = true; self.flags.pause = true;
return Err(Error::BreakpointHit {
addr: self.pc,
next: bus.read(self.pc),
});
} }
Ok(self) Ok(self)
} }

View File

@ -939,6 +939,7 @@ mod io {
output: &'static [u8], output: &'static [u8],
} }
/// Verify the character sprite addresses with the data they should return
#[rustfmt::skip] #[rustfmt::skip]
const TESTS: [SpriteTest; 16] = [ const TESTS: [SpriteTest; 16] = [
SpriteTest { input: 0x0, output: &[0xf0, 0x90, 0x90, 0x90, 0xf0] }, SpriteTest { input: 0x0, output: &[0xf0, 0x90, 0x90, 0x90, 0xf0] },
@ -1121,15 +1122,51 @@ mod behavior {
} }
} }
mod breakpoint { mod breakpoint {
use super::*; use super::*;
#[test] #[test]
#[cfg_attr(feature = "unstable", no_coverage)]
fn hit_break() { fn hit_break() {
let (mut cpu, mut bus) = setup_environment(); let (mut cpu, mut bus) = setup_environment();
cpu.set_break(0x202); cpu.set_break(0x202);
cpu.multistep(&mut bus, 10) match cpu.multistep(&mut bus, 10) {
.expect("Running valid instructions should always succeed"); Err(crate::error::Error::BreakpointHit { addr, next }) => {
assert_eq!(0x202, addr); // current address is 202
assert_eq!(0x1204, next); // next insn is `jmp 204`
}
other => unreachable!("{:?}", other),
}
assert!(cpu.flags.pause);
assert_eq!(0x202, cpu.pc);
}
#[test]
#[cfg_attr(feature = "unstable", no_coverage)]
fn hit_break_singlestep() {
let (mut cpu, mut bus) = setup_environment();
cpu.set_break(0x202);
match cpu.singlestep(&mut bus) {
Err(crate::error::Error::BreakpointHit { addr, next }) => {
assert_eq!(0x202, addr); // current address is 202
assert_eq!(0x1204, next); // next insn is `jmp 204`
}
other => unreachable!("{:?}", other),
}
assert!(cpu.flags.pause); assert!(cpu.flags.pause);
assert_eq!(0x202, cpu.pc); assert_eq!(0x202, cpu.pc);
} }
} }
#[test]
#[cfg_attr(feature = "unstable", no_coverage)]
fn invalid_pc() {
let (mut cpu, mut bus) = setup_environment();
// The bus extends from 0x0..0x1000
cpu.pc = 0xfff;
match cpu.tick(&mut bus) {
Err(Error::InvalidBusRange { range }) => {
eprintln!("InvalidBusRange {{ {range:04x?} }}")
}
other => unreachable!("{other:04x?}"),
}
}
} }

View File

@ -14,6 +14,14 @@ pub type Result<T> = std::result::Result<T, Error>;
/// Error type for Chirp. /// Error type for Chirp.
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum Error { pub enum Error {
/// Represents a breakpoint being hit
#[error("Breakpoint hit: {addr:03x} ({next:04x})")]
BreakpointHit {
/// The address of the breakpoint
addr: u16,
/// The instruction after the breakpoint
next: u16,
},
/// Represents an unimplemented operation /// Represents an unimplemented operation
#[error("Unrecognized opcode: {word:04x}")] #[error("Unrecognized opcode: {word:04x}")]
UnimplementedInstruction { UnimplementedInstruction {