Change small heuristics, add newlines between items

This commit is contained in:
John 2024-07-09 01:22:32 -05:00
parent 9106d9727f
commit 060a6b068b
9 changed files with 178 additions and 41 deletions

View File

@ -7,7 +7,9 @@ use boy::memory::io::BusIO;
pub trait BusIOTools: BusIO { pub trait BusIOTools: BusIO {
/// Prints all successful reads and writes /// Prints all successful reads and writes
fn trace(&mut self) -> TracingBus<Self>; fn trace(&mut self) -> TracingBus<Self>;
fn ascii(&mut self) -> AsciiSerial<Self>; fn ascii(&mut self) -> AsciiSerial<Self>;
fn read_file(&mut self, path: impl AsRef<Path>) -> IoResult<&mut Self> fn read_file(&mut self, path: impl AsRef<Path>) -> IoResult<&mut Self>
where where
Self: Sized; Self: Sized;
@ -17,6 +19,7 @@ impl<T: BusIO> BusIOTools for T {
fn trace(&mut self) -> TracingBus<Self> { fn trace(&mut self) -> TracingBus<Self> {
TracingBus { bus: self } TracingBus { bus: self }
} }
fn ascii(&mut self) -> AsciiSerial<Self> { fn ascii(&mut self) -> AsciiSerial<Self> {
AsciiSerial { AsciiSerial {
data: 0, data: 0,
@ -24,6 +27,7 @@ impl<T: BusIO> BusIOTools for T {
bus: self, bus: self,
} }
} }
fn read_file(&mut self, path: impl AsRef<Path>) -> IoResult<&mut Self> { fn read_file(&mut self, path: impl AsRef<Path>) -> IoResult<&mut Self> {
let data = std::fs::read(path)?; let data = std::fs::read(path)?;
eprintln!("Read {} bytes.", data.len()); eprintln!("Read {} bytes.", data.len());
@ -49,6 +53,7 @@ impl<'t, T: BusIO> BusIO for TracingBus<'t, T> {
// } // }
self.bus.read(addr) self.bus.read(addr)
} }
fn write(&mut self, addr: usize, data: u8) -> Option<()> { fn write(&mut self, addr: usize, data: u8) -> Option<()> {
eprintln!("set [{addr:04x}], {data:02x}"); eprintln!("set [{addr:04x}], {data:02x}");
self.bus.write(addr, data) self.bus.write(addr, data)
@ -60,11 +65,13 @@ impl<'t, T: BusIO> From<&'t mut T> for TracingBus<'t, T> {
Self { bus: value } Self { bus: value }
} }
} }
impl<'t, T: BusIO + AsRef<[u8]>> AsRef<[u8]> for TracingBus<'t, T> { impl<'t, T: BusIO + AsRef<[u8]>> AsRef<[u8]> for TracingBus<'t, T> {
fn as_ref(&self) -> &[u8] { fn as_ref(&self) -> &[u8] {
self.bus.as_ref() self.bus.as_ref()
} }
} }
impl<'t, T: BusIO + AsMut<[u8]>> AsMut<[u8]> for TracingBus<'t, T> { impl<'t, T: BusIO + AsMut<[u8]>> AsMut<[u8]> for TracingBus<'t, T> {
fn as_mut(&mut self) -> &mut [u8] { fn as_mut(&mut self) -> &mut [u8] {
self.bus.as_mut() self.bus.as_mut()
@ -93,6 +100,7 @@ impl<'t, T: BusIO + ?Sized> BusIO for AsciiSerial<'t, T> {
_ => self.bus.read(addr), _ => self.bus.read(addr),
} }
} }
fn write(&mut self, addr: usize, data: u8) -> Option<()> { fn write(&mut self, addr: usize, data: u8) -> Option<()> {
match addr { match addr {
0xff01 => { 0xff01 => {
@ -111,6 +119,7 @@ impl<'t, T: BusIO + ?Sized> BusIO for AsciiSerial<'t, T> {
} }
self.bus.write(addr, data) self.bus.write(addr, data)
} }
fn diag(&mut self, param: usize) { fn diag(&mut self, param: usize) {
println!("debug: '{}'", self.string()); println!("debug: '{}'", self.string());
self.buf.clear(); self.buf.clear();

View File

@ -6,6 +6,7 @@ use std::iter::{Enumerate, Peekable};
pub trait Disassemble: Iterator<Item = u8> + Sized { pub trait Disassemble: Iterator<Item = u8> + Sized {
fn disassemble(self) -> Disassembler<Self>; fn disassemble(self) -> Disassembler<Self>;
} }
impl<T: Iterator<Item = u8> + Sized> Disassemble for T { impl<T: Iterator<Item = u8> + Sized> Disassemble for T {
fn disassemble(self) -> Disassembler<Self> { fn disassemble(self) -> Disassembler<Self> {
Disassembler::new(self) Disassembler::new(self)
@ -29,27 +30,31 @@ impl<I: Iterator<Item = u8>> Iterator for Disassembler<I> {
impl<I: Iterator<Item = u8>> Disassembler<I> { impl<I: Iterator<Item = u8>> Disassembler<I> {
pub fn new(bytes: I) -> Self { pub fn new(bytes: I) -> Self {
Disassembler { Disassembler { bytes: bytes.enumerate().peekable() }
bytes: bytes.enumerate().peekable(),
}
} }
pub fn index(&mut self) -> Option<usize> { pub fn index(&mut self) -> Option<usize> {
self.bytes.peek().map(|v| v.0) self.bytes.peek().map(|v| v.0)
} }
pub fn imm8(&mut self) -> Option<u8> { pub fn imm8(&mut self) -> Option<u8> {
self.bytes.next().map(|v| v.1) self.bytes.next().map(|v| v.1)
} }
pub fn smm8(&mut self) -> Option<i8> { pub fn smm8(&mut self) -> Option<i8> {
self.imm8().map(|b| b as i8) self.imm8().map(|b| b as i8)
} }
pub fn imm16(&mut self) -> Option<u16> { pub fn imm16(&mut self) -> Option<u16> {
let low = self.imm8()? as u16; let low = self.imm8()? as u16;
let high = self.imm8()? as u16; let high = self.imm8()? as u16;
Some(high << 8 | low) Some(high << 8 | low)
} }
pub fn smm16(&mut self) -> Option<i16> { pub fn smm16(&mut self) -> Option<i16> {
self.imm16().map(|w| w as i16) self.imm16().map(|w| w as i16)
} }
pub fn print(&mut self, insn: Insn) -> Option<String> { pub fn print(&mut self, insn: Insn) -> Option<String> {
Some(match insn { Some(match insn {
Insn::LdImm(reg) => format!("ld\t{reg}, {:02x}", self.imm8()?), Insn::LdImm(reg) => format!("ld\t{reg}, {:02x}", self.imm8()?),
@ -79,6 +84,7 @@ impl<I: Iterator<Item = u8>> Disassembler<I> {
_ => format!("{insn}"), _ => format!("{insn}"),
}) })
} }
pub fn print_prefix_cb(&mut self) -> Option<String> { pub fn print_prefix_cb(&mut self) -> Option<String> {
let prefixed: Prefixed = self.imm8()?.into(); let prefixed: Prefixed = self.imm8()?.into();
Some(format!("{prefixed}")) Some(format!("{prefixed}"))

View File

@ -77,6 +77,7 @@ pub mod cli {
/// `=`: Equals Sign /// `=`: Equals Sign
Eq, Eq,
} }
impl Display for Op { impl Display for Op {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
@ -180,16 +181,20 @@ pub mod cli {
} }
self self
} }
fn peek(&mut self) -> Option<&char> { fn peek(&mut self) -> Option<&char> {
self.text.peek() self.text.peek()
} }
fn take(&mut self) -> &mut Self { fn take(&mut self) -> &mut Self {
self.text.next(); self.text.next();
self self
} }
fn emit(&mut self, kind: Token) -> Option<Token> { fn emit(&mut self, kind: Token) -> Option<Token> {
Some(kind) Some(kind)
} }
fn digits<const B: u32>(&mut self) -> Option<Token> { fn digits<const B: u32>(&mut self) -> Option<Token> {
let mut out = 0; let mut out = 0;
while let Some(Some(next)) = self.peek().map(|c| c.to_digit(B)) { while let Some(Some(next)) = self.peek().map(|c| c.to_digit(B)) {
@ -198,6 +203,7 @@ pub mod cli {
} }
Some(Num(out)) Some(Num(out))
} }
fn base(&mut self) -> Option<Token> { fn base(&mut self) -> Option<Token> {
match self.peek() { match self.peek() {
Some('b') => self.take().digits::<2>(), Some('b') => self.take().digits::<2>(),
@ -207,6 +213,7 @@ pub mod cli {
_ => self.digits::<16>(), _ => self.digits::<16>(),
} }
} }
fn ident(&mut self) -> Option<Token> { fn ident(&mut self) -> Option<Token> {
let mut out = String::new(); let mut out = String::new();
while let Some(&c) = self.peek().filter(|&&c| c.is_alphanumeric() || c == '_') { while let Some(&c) = self.peek().filter(|&&c| c.is_alphanumeric() || c == '_') {
@ -239,6 +246,7 @@ pub mod cli {
}, },
}) })
} }
/// Checks the following character, producing the provided [Token] /// Checks the following character, producing the provided [Token]
/// if it matches the expected [char]. Otherwise, prodices [Token::Other]. /// if it matches the expected [char]. Otherwise, prodices [Token::Other].
fn chain(&mut self, expect: char, becomes: Token) -> Option<Token> { fn chain(&mut self, expect: char, becomes: Token) -> Option<Token> {
@ -264,8 +272,10 @@ pub mod cli {
self.take().emit(Token::Ident(value)) self.take().emit(Token::Ident(value))
} }
} }
impl<I: Iterator<Item = char>> Iterator for Lexer<I> { impl<I: Iterator<Item = char>> Iterator for Lexer<I> {
type Item = Token; type Item = Token;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
match self.sync().peek()? { match self.sync().peek()? {
'[' => self.take().emit(Op(BrackOpen)), '[' => self.take().emit(Op(BrackOpen)),
@ -310,6 +320,7 @@ pub mod cli {
pub trait Parsible: Iterator<Item = Token> + Sized { pub trait Parsible: Iterator<Item = Token> + Sized {
fn parse(self) -> Parser<Self>; fn parse(self) -> Parser<Self>;
} }
impl<T: Iterator<Item = Token> + Sized> Parsible for T { impl<T: Iterator<Item = Token> + Sized> Parsible for T {
fn parse(self) -> Parser<Self> { fn parse(self) -> Parser<Self> {
Parser::new(self) Parser::new(self)
@ -330,9 +341,11 @@ pub mod cli {
fn peek(&mut self) -> Option<&Token> { fn peek(&mut self) -> Option<&Token> {
self.lexer.peek() self.lexer.peek()
} }
fn take(&mut self) -> Option<Token> { fn take(&mut self) -> Option<Token> {
self.lexer.next() self.lexer.next()
} }
#[must_use] #[must_use]
fn then(&mut self, tok: Token) -> Option<&mut Self> { fn then(&mut self, tok: Token) -> Option<&mut Self> {
(*self.peek()? == tok).then(|| { (*self.peek()? == tok).then(|| {
@ -472,6 +485,7 @@ pub mod cli {
}; };
continue; continue;
} }
if let Some(prec) = op.infix() { if let Some(prec) = op.infix() {
if prec.before() < level { if prec.before() < level {
break; break;
@ -501,13 +515,16 @@ pub mod cli {
Term, Term,
Sign, Sign,
} }
impl Level { impl Level {
fn level(self) -> u8 { fn level(self) -> u8 {
(self as u8) << 1 (self as u8) << 1
} }
pub fn before(self) -> u8 { pub fn before(self) -> u8 {
self.level() self.level()
} }
pub fn after(self) -> u8 { pub fn after(self) -> u8 {
self.level() + 1 self.level() + 1
} }

1
rustfmt.toml Normal file
View File

@ -0,0 +1 @@
use_small_heuristics = "Max"

View File

@ -35,6 +35,7 @@ pub struct Flags {
fn half_carry_add(a: u8, b: u8) -> bool { fn half_carry_add(a: u8, b: u8) -> bool {
(a & 0xf) + (b & 0xf) > 0xf (a & 0xf) + (b & 0xf) > 0xf
} }
/// Performs the half-carry calculation for subtraction /// Performs the half-carry calculation for subtraction
fn half_carry_sub(a: u8, b: u8) -> bool { fn half_carry_sub(a: u8, b: u8) -> bool {
(a & 0xf) < (b & 0xf) (a & 0xf) < (b & 0xf)
@ -145,18 +146,22 @@ impl CPU {
pub fn pc(&self) -> u16 { pub fn pc(&self) -> u16 {
self.pc.0 self.pc.0
} }
/// Sets the address of the next instruction /// Sets the address of the next instruction
pub fn set_pc(&mut self, addr: u16) { pub fn set_pc(&mut self, addr: u16) {
self.pc.0 = addr self.pc.0 = addr
} }
/// Gets the current instruction /// Gets the current instruction
pub fn ir(&self) -> Insn { pub fn ir(&self) -> Insn {
self.ir self.ir
} }
/// Sets a breakpoint. Returns true if the breakpoint was not already set. /// Sets a breakpoint. Returns true if the breakpoint was not already set.
pub fn set_break(&mut self, addr: u16) -> bool { pub fn set_break(&mut self, addr: u16) -> bool {
self.breakpoints.insert(addr) self.breakpoints.insert(addr)
} }
/// Removes a breakpoint. Returns true if the breakpoint was set. /// Removes a breakpoint. Returns true if the breakpoint was set.
pub fn unset_break(&mut self, addr: u16) -> bool { pub fn unset_break(&mut self, addr: u16) -> bool {
self.breakpoints.remove(&addr) self.breakpoints.remove(&addr)
@ -171,18 +176,21 @@ impl CPU {
self.pc += 1; self.pc += 1;
Ok(out) Ok(out)
} }
/// Read a 16-bit immediate at the program counter, post-incrementing it twice (adds two cycles) /// Read a 16-bit immediate at the program counter, post-incrementing it twice (adds two cycles)
pub fn imm16(&mut self, bus: &impl BusIO) -> Result<u16, Error> { pub fn imm16(&mut self, bus: &impl BusIO) -> Result<u16, Error> {
let out = self.read16(self.pc.0, bus)?; let out = self.read16(self.pc.0, bus)?;
self.pc += 2; self.pc += 2;
Ok(out) Ok(out)
} }
/// Read an 8-bit value at address `addr` on the `bus` (adds one cycle) /// Read an 8-bit value at address `addr` on the `bus` (adds one cycle)
pub fn read(&mut self, addr: u16, bus: &impl BusIO) -> Result<u8, Error> { pub fn read(&mut self, addr: u16, bus: &impl BusIO) -> Result<u8, Error> {
// Reading a byte takes one cycle // Reading a byte takes one cycle
self.wait(); self.wait();
bus.read(addr as usize).ok_or(InvalidAddress(addr).into()) bus.read(addr as usize).ok_or(InvalidAddress(addr).into())
} }
/// Read a 16-bit LE value at address `addr` on the `bus` (adds two cycles) /// Read a 16-bit LE value at address `addr` on the `bus` (adds two cycles)
pub fn read16(&mut self, addr: u16, bus: &impl BusIO) -> Result<u16, Error> { pub fn read16(&mut self, addr: u16, bus: &impl BusIO) -> Result<u16, Error> {
let out = self.read(addr, bus)? as u16; let out = self.read(addr, bus)? as u16;
@ -193,9 +201,9 @@ impl CPU {
pub fn write(&mut self, addr: u16, data: u8, bus: &mut impl BusIO) -> Result<(), Error> { pub fn write(&mut self, addr: u16, data: u8, bus: &mut impl BusIO) -> Result<(), Error> {
// Writing a byte takes one cycle // Writing a byte takes one cycle
self.wait(); self.wait();
bus.write(addr as usize, data) bus.write(addr as usize, data).ok_or(InvalidAddress(addr).into())
.ok_or(InvalidAddress(addr).into())
} }
/// Write a 16-bit LE value to address `addr..=addr+1` on the `bus` (adds two cycles) /// Write a 16-bit LE value to address `addr..=addr+1` on the `bus` (adds two cycles)
pub fn write16(&mut self, addr: u16, data: u16, bus: &mut impl BusIO) -> Result<(), Error> { pub fn write16(&mut self, addr: u16, data: u16, bus: &mut impl BusIO) -> Result<(), Error> {
let data = data.to_le_bytes(); let data = data.to_le_bytes();
@ -208,18 +216,21 @@ impl CPU {
self.sp -= 1; self.sp -= 1;
self.write(self.sp.0, data, bus) self.write(self.sp.0, data, bus)
} }
/// Push a 16-bit value onto the stack (adds two cycles) /// Push a 16-bit value onto the stack (adds two cycles)
pub fn push16(&mut self, data: u16, bus: &mut impl BusIO) -> Result<(), Error> { pub fn push16(&mut self, data: u16, bus: &mut impl BusIO) -> Result<(), Error> {
let data = data.to_le_bytes(); let data = data.to_le_bytes();
self.push(data[0], bus)?; self.push(data[0], bus)?;
self.push(data[1], bus) self.push(data[1], bus)
} }
/// Pop a byte off the stack (adds one cycle) /// Pop a byte off the stack (adds one cycle)
pub fn pop(&mut self, bus: &mut impl BusIO) -> Result<u8, Error> { pub fn pop(&mut self, bus: &mut impl BusIO) -> Result<u8, Error> {
let out = self.read(self.sp.0, bus); let out = self.read(self.sp.0, bus);
self.sp += 1; self.sp += 1;
out out
} }
/// Pop a double word off the stack (adds two cycles) /// Pop a double word off the stack (adds two cycles)
pub fn pop16(&mut self, bus: &mut impl BusIO) -> Result<u16, Error> { pub fn pop16(&mut self, bus: &mut impl BusIO) -> Result<u16, Error> {
// pushes LH, pops HL // pushes LH, pops HL
@ -268,23 +279,28 @@ mod instructions {
pub fn nop(&mut self) -> IResult { pub fn nop(&mut self) -> IResult {
Ok(()) Ok(())
} }
pub fn stop(&mut self) -> IResult { pub fn stop(&mut self) -> IResult {
println!("Stop requested.\n{self}"); println!("Stop requested.\n{self}");
Ok(()) Ok(())
} }
pub fn halt(&mut self) -> IResult { pub fn halt(&mut self) -> IResult {
Ok(()) Ok(())
} }
pub fn di(&mut self) -> IResult { pub fn di(&mut self) -> IResult {
self.ime = Ime::Disabled; self.ime = Ime::Disabled;
Ok(()) Ok(())
} }
pub fn ei(&mut self) -> IResult { pub fn ei(&mut self) -> IResult {
// TODO: this is incorrect // TODO: this is incorrect
self.ime = Ime::ShouldEnable; self.ime = Ime::ShouldEnable;
Ok(()) Ok(())
} }
} }
/// Loads and stores /// Loads and stores
impl CPU { impl CPU {
pub fn ld(&mut self, dst: R8, src: R8, bus: &mut impl BusIO) -> IResult { pub fn ld(&mut self, dst: R8, src: R8, bus: &mut impl BusIO) -> IResult {
@ -292,70 +308,84 @@ mod instructions {
self.set_r8(dst, src, bus); self.set_r8(dst, src, bus);
Ok(()) Ok(())
} }
pub fn ld_imm(&mut self, dst: R8, bus: &mut impl BusIO) -> IResult { pub fn ld_imm(&mut self, dst: R8, bus: &mut impl BusIO) -> IResult {
// TODO: open bus behavior // TODO: open bus behavior
let src = self.imm8(bus)?; let src = self.imm8(bus)?;
self.set_r8(dst, src, bus); self.set_r8(dst, src, bus);
Ok(()) Ok(())
} }
pub fn ld_imm16(&mut self, dst: R16, bus: &mut impl BusIO) -> IResult { pub fn ld_imm16(&mut self, dst: R16, bus: &mut impl BusIO) -> IResult {
let imm16 = self.imm16(bus)?; let imm16 = self.imm16(bus)?;
self[dst].0 = imm16; self[dst].0 = imm16;
Ok(()) Ok(())
} }
pub fn ld_ind(&mut self, src: R16Indirect, bus: &mut impl BusIO) -> IResult { pub fn ld_ind(&mut self, src: R16Indirect, bus: &mut impl BusIO) -> IResult {
self[R8::A].0 = self.read_r16ind(src, bus)?; self[R8::A].0 = self.read_r16ind(src, bus)?;
Ok(()) Ok(())
} }
pub fn st_ind(&mut self, dst: R16Indirect, bus: &mut impl BusIO) -> IResult { pub fn st_ind(&mut self, dst: R16Indirect, bus: &mut impl BusIO) -> IResult {
self.write_r16ind(dst, self[R8::A].0, bus); self.write_r16ind(dst, self[R8::A].0, bus);
Ok(()) Ok(())
} }
pub fn ldc(&mut self, bus: &mut impl BusIO) -> IResult { pub fn ldc(&mut self, bus: &mut impl BusIO) -> IResult {
let addr = self[R8::C].0 as u16 | 0xff00; let addr = self[R8::C].0 as u16 | 0xff00;
self[R8::A].0 = self.read(addr, bus)?; self[R8::A].0 = self.read(addr, bus)?;
Ok(()) Ok(())
} }
pub fn stc(&mut self, bus: &mut impl BusIO) -> IResult { pub fn stc(&mut self, bus: &mut impl BusIO) -> IResult {
let addr = self[R8::C].0 as u16 | 0xff00; let addr = self[R8::C].0 as u16 | 0xff00;
self.write(addr, self[R8::A].0, bus)?; self.write(addr, self[R8::A].0, bus)?;
Ok(()) Ok(())
} }
pub fn ld_abs(&mut self, bus: &mut impl BusIO) -> IResult { pub fn ld_abs(&mut self, bus: &mut impl BusIO) -> IResult {
let addr = self.imm16(bus)?; let addr = self.imm16(bus)?;
self[R8::A].0 = self.read(addr, bus)?; self[R8::A].0 = self.read(addr, bus)?;
Ok(()) Ok(())
} }
pub fn st_abs(&mut self, bus: &mut impl BusIO) -> IResult { pub fn st_abs(&mut self, bus: &mut impl BusIO) -> IResult {
let addr = self.imm16(bus)?; let addr = self.imm16(bus)?;
self.write(addr, self[R8::A].0, bus)?; self.write(addr, self[R8::A].0, bus)?;
Ok(()) Ok(())
} }
pub fn st_sp_abs(&mut self, bus: &mut impl BusIO) -> IResult { pub fn st_sp_abs(&mut self, bus: &mut impl BusIO) -> IResult {
let addr = self.imm16(bus)?; let addr = self.imm16(bus)?;
self.write16(addr, self[R16::SP].0, bus)?; self.write16(addr, self[R16::SP].0, bus)?;
Ok(()) Ok(())
} }
pub fn ld_sp_hl(&mut self) -> IResult { pub fn ld_sp_hl(&mut self) -> IResult {
self[R16::HL].0 = self[R16::SP].0; self[R16::HL].0 = self[R16::SP].0;
Ok(()) Ok(())
} }
pub fn ld_hl_sp_rel(&mut self, bus: &mut impl BusIO) -> IResult { pub fn ld_hl_sp_rel(&mut self, bus: &mut impl BusIO) -> IResult {
let offset = self.imm8(bus)? as i8 as i16 as u16; let offset = self.imm8(bus)? as i8 as i16 as u16;
self[R16::HL].0 = self.sp.0.wrapping_add(offset); self[R16::HL].0 = self.sp.0.wrapping_add(offset);
Ok(()) Ok(())
} }
pub fn ldh(&mut self, bus: &mut impl BusIO) -> IResult { pub fn ldh(&mut self, bus: &mut impl BusIO) -> IResult {
let addr = self.imm8(bus)? as u16 | 0xff00; let addr = self.imm8(bus)? as u16 | 0xff00;
self[R8::A].0 = self.read(addr, bus)?; self[R8::A].0 = self.read(addr, bus)?;
Ok(()) Ok(())
} }
pub fn sth(&mut self, bus: &mut impl BusIO) -> IResult { pub fn sth(&mut self, bus: &mut impl BusIO) -> IResult {
let addr = self.imm8(bus)? as u16 | 0xff00; let addr = self.imm8(bus)? as u16 | 0xff00;
self.write(addr, self[R8::A].0, bus)?; self.write(addr, self[R8::A].0, bus)?;
Ok(()) Ok(())
} }
} }
/// Inc and Dec /// Inc and Dec
impl CPU { impl CPU {
pub fn inc(&mut self, reg: R8, bus: &mut impl BusIO) -> IResult { pub fn inc(&mut self, reg: R8, bus: &mut impl BusIO) -> IResult {
@ -364,21 +394,25 @@ mod instructions {
*self.flags_mut() = Flags::new().with_z(data == 0).with_c(carry); *self.flags_mut() = Flags::new().with_z(data == 0).with_c(carry);
Ok(()) Ok(())
} }
pub fn dec(&mut self, reg: R8, bus: &mut impl BusIO) -> IResult { pub fn dec(&mut self, reg: R8, bus: &mut impl BusIO) -> IResult {
let (data, carry) = self.get_r8(reg, bus).overflowing_sub(1); let (data, carry) = self.get_r8(reg, bus).overflowing_sub(1);
self.set_r8(reg, data, bus); self.set_r8(reg, data, bus);
*self.flags_mut() = Flags::new().with_z(data == 0).with_c(carry); *self.flags_mut() = Flags::new().with_z(data == 0).with_c(carry);
Ok(()) Ok(())
} }
pub fn inc16(&mut self, reg: R16) -> IResult { pub fn inc16(&mut self, reg: R16) -> IResult {
self[reg] += 1; self[reg] += 1;
Ok(()) Ok(())
} }
pub fn dec16(&mut self, reg: R16) -> IResult { pub fn dec16(&mut self, reg: R16) -> IResult {
self[reg] -= 1; self[reg] -= 1;
Ok(()) Ok(())
} }
} }
/// Rotates and shifts /// Rotates and shifts
impl CPU { impl CPU {
pub fn rlnca(&mut self) -> IResult { pub fn rlnca(&mut self) -> IResult {
@ -387,12 +421,14 @@ mod instructions {
self.set_z(false).set_n(false).set_h(false).set_c(carry); self.set_z(false).set_n(false).set_h(false).set_c(carry);
Ok(()) Ok(())
} }
pub fn rrnca(&mut self) -> IResult { pub fn rrnca(&mut self) -> IResult {
let carry = self[R8::A].0 & 1 != 0; let carry = self[R8::A].0 & 1 != 0;
self[R8::A].0 = self[R8::A].0.rotate_right(1); self[R8::A].0 = self[R8::A].0.rotate_right(1);
self.set_z(false).set_n(false).set_h(false).set_c(carry); self.set_z(false).set_n(false).set_h(false).set_c(carry);
Ok(()) Ok(())
} }
pub fn rla(&mut self) -> IResult { pub fn rla(&mut self) -> IResult {
// TODO: optimize RLA/RRA // TODO: optimize RLA/RRA
let carry = self[R8::A].0 & 0x80 != 0; let carry = self[R8::A].0 & 0x80 != 0;
@ -402,6 +438,7 @@ mod instructions {
self.set_z(false).set_n(false).set_h(false).set_c(carry); self.set_z(false).set_n(false).set_h(false).set_c(carry);
Ok(()) Ok(())
} }
pub fn rra(&mut self) -> IResult { pub fn rra(&mut self) -> IResult {
let carry = self[R8::A].0 & 1 != 0; let carry = self[R8::A].0 & 1 != 0;
self[R8::A] >>= 1; self[R8::A] >>= 1;
@ -411,6 +448,7 @@ mod instructions {
Ok(()) Ok(())
} }
} }
/// Funky instructions /// Funky instructions
impl CPU { impl CPU {
pub fn daa(&mut self) -> IResult { pub fn daa(&mut self) -> IResult {
@ -435,22 +473,26 @@ mod instructions {
Ok(()) Ok(())
} }
pub fn cpl(&mut self) -> IResult { pub fn cpl(&mut self) -> IResult {
self[R8::A] ^= 0xff; self[R8::A] ^= 0xff;
self.set_n(false).set_h(false); self.set_n(false).set_h(false);
Ok(()) Ok(())
} }
pub fn scf(&mut self) -> IResult { pub fn scf(&mut self) -> IResult {
let flags = self.flags_mut(); let flags = self.flags_mut();
*flags = flags.with_n(false).with_h(false).with_c(true); *flags = flags.with_n(false).with_h(false).with_c(true);
Ok(()) Ok(())
} }
pub fn ccf(&mut self) -> IResult { pub fn ccf(&mut self) -> IResult {
let flags = self.flags_mut(); let flags = self.flags_mut();
*flags = flags.with_n(false).with_h(false).with_c(!flags.c()); *flags = flags.with_n(false).with_h(false).with_c(!flags.c());
Ok(()) Ok(())
} }
} }
/// Addition /// Addition
impl CPU { impl CPU {
fn add_impl(&mut self, value: u8) -> IResult { fn add_impl(&mut self, value: u8) -> IResult {
@ -469,6 +511,7 @@ mod instructions {
self.add_impl(src)?; self.add_impl(src)?;
Ok(()) Ok(())
} }
pub fn add16(&mut self, reg: R16) -> IResult { pub fn add16(&mut self, reg: R16) -> IResult {
let (value, h) = (self[reg], self[R8::H].0); let (value, h) = (self[reg], self[R8::H].0);
let value_h = (value.0 >> 8) as u8; let value_h = (value.0 >> 8) as u8;
@ -479,13 +522,14 @@ mod instructions {
*self.hl.wide_mut() += value; *self.hl.wide_mut() += value;
Ok(()) Ok(())
} }
#[allow(unused)] #[allow(unused)]
pub fn add16_spi(&mut self, bus: &mut impl BusIO) -> IResult { pub fn add16_spi(&mut self, bus: &mut impl BusIO) -> IResult {
let offset = self.imm8(bus)? as i8 as i16; // sign extend let offset = self.imm8(bus)? as i8 as i16; // sign extend
Err(UnimplementedInsn(self.ir).into()) Err(UnimplementedInsn(self.ir).into())
} }
} }
/// Addition with carry /// Addition with carry
impl CPU { impl CPU {
fn addc_impl(&mut self, value: u8) -> IResult { fn addc_impl(&mut self, value: u8) -> IResult {
@ -493,10 +537,7 @@ mod instructions {
let hc = half_carry_add(self[R8::A].0, src); let hc = half_carry_add(self[R8::A].0, src);
let (out, carry) = self[R8::A].0.overflowing_add(src); let (out, carry) = self[R8::A].0.overflowing_add(src);
self[R8::A].0 = out; self[R8::A].0 = out;
self.set_z(out == 0) self.set_z(out == 0).set_n(false).set_h(hc).set_c(carry | carry_in);
.set_n(false)
.set_h(hc)
.set_c(carry | carry_in);
Ok(()) Ok(())
} }
pub fn adc(&mut self, reg: R8, bus: &mut impl BusIO) -> IResult { pub fn adc(&mut self, reg: R8, bus: &mut impl BusIO) -> IResult {
@ -508,6 +549,7 @@ mod instructions {
self.addc_impl(src) self.addc_impl(src)
} }
} }
/// Subtraction /// Subtraction
impl CPU { impl CPU {
fn sub_impl(&mut self, value: u8) -> IResult { fn sub_impl(&mut self, value: u8) -> IResult {
@ -526,6 +568,7 @@ mod instructions {
self.sub_impl(value) self.sub_impl(value)
} }
} }
/// Subtraction with carry /// Subtraction with carry
impl CPU { impl CPU {
#[inline] #[inline]
@ -534,10 +577,7 @@ mod instructions {
let (out, carry) = self[R8::A].0.overflowing_sub(src); let (out, carry) = self[R8::A].0.overflowing_sub(src);
let hc = half_carry_sub(self[R8::A].0, src); let hc = half_carry_sub(self[R8::A].0, src);
self[R8::A].0 = out; self[R8::A].0 = out;
self.set_z(out == 0) self.set_z(out == 0).set_n(true).set_h(hc).set_c(carry | cin);
.set_n(true)
.set_h(hc)
.set_c(carry | cin);
Ok(()) Ok(())
} }
pub fn sbc(&mut self, reg: R8, bus: &mut impl BusIO) -> IResult { pub fn sbc(&mut self, reg: R8, bus: &mut impl BusIO) -> IResult {
@ -549,14 +589,12 @@ mod instructions {
self.subc_impl(value) self.subc_impl(value)
} }
} }
/// Bitwise AND /// Bitwise AND
impl CPU { impl CPU {
fn and_impl(&mut self, value: u8) -> IResult { fn and_impl(&mut self, value: u8) -> IResult {
self[R8::A] &= value; self[R8::A] &= value;
self.set_z(self[R8::A].0 == 0) self.set_z(self[R8::A].0 == 0).set_n(false).set_h(true).set_c(false);
.set_n(false)
.set_h(true)
.set_c(false);
Ok(()) Ok(())
} }
pub fn and(&mut self, reg: R8, bus: &mut impl BusIO) -> IResult { pub fn and(&mut self, reg: R8, bus: &mut impl BusIO) -> IResult {
@ -568,6 +606,7 @@ mod instructions {
self.and_impl(value) self.and_impl(value)
} }
} }
/// Bitwise XOR /// Bitwise XOR
impl CPU { impl CPU {
fn xor_impl(&mut self, value: u8) -> IResult { fn xor_impl(&mut self, value: u8) -> IResult {
@ -584,6 +623,7 @@ mod instructions {
self.xor_impl(value) self.xor_impl(value)
} }
} }
/// Bitwise OR /// Bitwise OR
impl CPU { impl CPU {
fn or_impl(&mut self, value: u8) -> IResult { fn or_impl(&mut self, value: u8) -> IResult {
@ -600,6 +640,7 @@ mod instructions {
self.or_impl(value) self.or_impl(value)
} }
} }
/// Comparison /// Comparison
impl CPU { impl CPU {
fn cmp_impl(&mut self, src: u8) -> IResult { fn cmp_impl(&mut self, src: u8) -> IResult {
@ -617,11 +658,13 @@ mod instructions {
self.cmp_impl(src) self.cmp_impl(src)
} }
} }
/// Stack ops /// Stack ops
impl CPU { impl CPU {
pub fn insn_push(&mut self, reg: R16Stack, bus: &mut impl BusIO) -> IResult { pub fn insn_push(&mut self, reg: R16Stack, bus: &mut impl BusIO) -> IResult {
self.push16(self[reg].0, bus) self.push16(self[reg].0, bus)
} }
pub fn insn_pop(&mut self, reg: R16Stack, bus: &mut impl BusIO) -> IResult { pub fn insn_pop(&mut self, reg: R16Stack, bus: &mut impl BusIO) -> IResult {
self[reg].0 = self.pop16(bus)?; self[reg].0 = self.pop16(bus)?;
if let R16Stack::AF = reg { if let R16Stack::AF = reg {
@ -630,6 +673,7 @@ mod instructions {
Ok(()) Ok(())
} }
} }
/// Jumps, branches, calls, and returns /// Jumps, branches, calls, and returns
impl CPU { impl CPU {
pub fn jr(&mut self, bus: &mut impl BusIO) -> IResult { pub fn jr(&mut self, bus: &mut impl BusIO) -> IResult {
@ -680,6 +724,7 @@ mod instructions {
false => Ok(()), false => Ok(()),
} }
} }
pub fn ret(&mut self, bus: &mut impl BusIO) -> IResult { pub fn ret(&mut self, bus: &mut impl BusIO) -> IResult {
let addr = self.pop16(bus)?; let addr = self.pop16(bus)?;
self.jumpto(addr); self.jumpto(addr);
@ -696,10 +741,12 @@ mod instructions {
self.ime = Ime::Enabled; // Technically this should go after ret's pop self.ime = Ime::Enabled; // Technically this should go after ret's pop
self.ret(bus) self.ret(bus)
} }
pub fn reset(&mut self, addr: u8, bus: &mut impl BusIO) -> IResult { pub fn reset(&mut self, addr: u8, bus: &mut impl BusIO) -> IResult {
self.call_addr(addr as u16 * 8, bus) self.call_addr(addr as u16 * 8, bus)
} }
} }
/// Prefixed instructions /// Prefixed instructions
impl CPU { impl CPU {
/// Rotates left, setting the carry flag to the highest bit /// Rotates left, setting the carry flag to the highest bit
@ -786,7 +833,7 @@ impl CPU {
pub fn run(&mut self, bus: &mut impl BusIO) -> Result<usize, Error> { pub fn run(&mut self, bus: &mut impl BusIO) -> Result<usize, Error> {
self.m_cycles = 0; self.m_cycles = 0;
// Run the current instruction // Run the current instruction
self.execute(bus)?; let out = self.execute(bus);
let prefetch_pc = self.pc.0; let prefetch_pc = self.pc.0;
// Handle interrupts // Handle interrupts
@ -802,9 +849,10 @@ impl CPU {
if self.breakpoints.contains(&prefetch_pc) { if self.breakpoints.contains(&prefetch_pc) {
Err(HitBreak(prefetch_pc, self.m_cycles).into()) Err(HitBreak(prefetch_pc, self.m_cycles).into())
} else { } else {
Ok(self.m_cycles as usize) out.map(|_| self.m_cycles as usize)
} }
} }
pub fn fetch(&mut self, bus: &mut impl BusIO) -> Result<(), Error> { pub fn fetch(&mut self, bus: &mut impl BusIO) -> Result<(), Error> {
self.ir = match self.ir { self.ir = match self.ir {
// HALT fetches the current instruction, rather than the next // HALT fetches the current instruction, rather than the next
@ -815,6 +863,7 @@ impl CPU {
}; };
Ok(()) Ok(())
} }
pub fn execute(&mut self, bus: &mut impl BusIO) -> Result<(), Error> { pub fn execute(&mut self, bus: &mut impl BusIO) -> Result<(), Error> {
#[allow(unused_variables)] #[allow(unused_variables)]
match self.ir { match self.ir {
@ -874,6 +923,7 @@ impl CPU {
Insn::OrI => self.ori(bus), Insn::OrI => self.ori(bus),
Insn::Cp(reg) => self.cmp(reg, bus), Insn::Cp(reg) => self.cmp(reg, bus),
Insn::CpI => self.cmpi(bus), Insn::CpI => self.cmpi(bus),
Insn::Push(reg) => self.insn_push(reg, bus), Insn::Push(reg) => self.insn_push(reg, bus),
Insn::Pop(reg) => self.insn_pop(reg, bus), Insn::Pop(reg) => self.insn_pop(reg, bus),
// Jumps // Jumps
@ -894,6 +944,7 @@ impl CPU {
Insn::Invalid(b) => Err(InvalidInstruction(b).into()), Insn::Invalid(b) => Err(InvalidInstruction(b).into()),
} }
} }
pub fn prefixed(&mut self, bus: &mut impl BusIO) -> Result<(), Error> { pub fn prefixed(&mut self, bus: &mut impl BusIO) -> Result<(), Error> {
match Prefixed::from(self.imm8(bus)?) { match Prefixed::from(self.imm8(bus)?) {
Prefixed::Rlc(reg) => self.rlc(reg, bus), Prefixed::Rlc(reg) => self.rlc(reg, bus),
@ -919,6 +970,7 @@ impl CPU {
_ => self[r8].0, _ => self[r8].0,
} }
} }
/// Sets an 8-bit register. This requires bus access, since `[HL]` is a valid location /// Sets an 8-bit register. This requires bus access, since `[HL]` is a valid location
/// ///
/// Panic-free alternative to [IndexMut] /// Panic-free alternative to [IndexMut]
@ -947,21 +999,26 @@ impl CPU {
} }
} }
} }
/// Reads data at an R16-indirect address /// Reads data at an R16-indirect address
pub fn read_r16ind(&mut self, r16: R16Indirect, bus: &impl BusIO) -> Result<u8, Error> { pub fn read_r16ind(&mut self, r16: R16Indirect, bus: &impl BusIO) -> Result<u8, Error> {
let addr = self.get_r16ind_addr(r16); let addr = self.get_r16ind_addr(r16);
self.read(addr, bus) self.read(addr, bus)
} }
pub fn write_r16ind(&mut self, r16: R16Indirect, data: u8, bus: &mut impl BusIO) { pub fn write_r16ind(&mut self, r16: R16Indirect, data: u8, bus: &mut impl BusIO) {
let addr = self.get_r16ind_addr(r16); let addr = self.get_r16ind_addr(r16);
let _ = self.write(addr, data, bus); let _ = self.write(addr, data, bus);
} }
pub fn flags_mut(&mut self) -> &mut Flags { pub fn flags_mut(&mut self) -> &mut Flags {
self.af.flags_mut() self.af.flags_mut()
} }
pub fn flags(&self) -> Flags { pub fn flags(&self) -> Flags {
self.af.flags().to_owned() self.af.flags().to_owned()
} }
flags_getters_setters! { flags_getters_setters! {
/// the `Zero` Flag /// the `Zero` Flag
z, set_z; z, set_z;
@ -972,6 +1029,7 @@ impl CPU {
/// the `Carry` Flag /// the `Carry` Flag
c, set_c; c, set_c;
} }
/// Compares the given [Cond] to the CPU's condition flags /// Compares the given [Cond] to the CPU's condition flags
pub fn cond(&self, cond: Cond) -> bool { pub fn cond(&self, cond: Cond) -> bool {
match cond { match cond {
@ -1018,6 +1076,7 @@ impl Index<R8> for CPU {
} }
} }
} }
impl IndexMut<R8> for CPU { impl IndexMut<R8> for CPU {
/// Performs the mutable indexing (`container[index]`) operation. /// Performs the mutable indexing (`container[index]`) operation.
/// # Panics /// # Panics
@ -1035,6 +1094,7 @@ impl IndexMut<R8> for CPU {
} }
} }
} }
impl Index<R16> for CPU { impl Index<R16> for CPU {
type Output = Wrapping<u16>; type Output = Wrapping<u16>;
/// Performs the indexing (`container[index]`) operation. /// Performs the indexing (`container[index]`) operation.
@ -1047,6 +1107,7 @@ impl Index<R16> for CPU {
} }
} }
} }
impl IndexMut<R16> for CPU { impl IndexMut<R16> for CPU {
/// Performs the mutable indexing (`container[index]`) operation. /// Performs the mutable indexing (`container[index]`) operation.
fn index_mut(&mut self, index: R16) -> &mut Self::Output { fn index_mut(&mut self, index: R16) -> &mut Self::Output {
@ -1070,6 +1131,7 @@ impl Index<R16Stack> for CPU {
} }
} }
} }
impl IndexMut<R16Stack> for CPU { impl IndexMut<R16Stack> for CPU {
fn index_mut(&mut self, index: R16Stack) -> &mut Self::Output { fn index_mut(&mut self, index: R16Stack) -> &mut Self::Output {
match index { match index {

View File

@ -20,6 +20,7 @@ use super::Flags;
/// The low-byte index constant /// The low-byte index constant
const LO: usize = if 1u16.to_be() != 1u16 { 0 } else { 1 }; const LO: usize = if 1u16.to_be() != 1u16 { 0 } else { 1 };
/// The high-byte index constant /// The high-byte index constant
const HI: usize = 1 - LO; const HI: usize = 1 - LO;
@ -30,22 +31,26 @@ pub union SplitRegister {
af: [Flags; 2], af: [Flags; 2],
r16: Wrapping<u16>, r16: Wrapping<u16>,
} }
impl SplitRegister { impl SplitRegister {
/// Read the low byte of the register /// Read the low byte of the register
pub fn lo(&self) -> &Wrapping<u8> { pub fn lo(&self) -> &Wrapping<u8> {
// SAFETY: The GB's registers store POD types, so it's safe to transmute // SAFETY: The GB's registers store POD types, so it's safe to transmute
unsafe { &self.lh[LO] } unsafe { &self.lh[LO] }
} }
/// Read the high byte of the register /// Read the high byte of the register
pub fn hi(&self) -> &Wrapping<u8> { pub fn hi(&self) -> &Wrapping<u8> {
// SAFETY: See [SplitRegister::lo] // SAFETY: See [SplitRegister::lo]
unsafe { &self.lh[HI] } unsafe { &self.lh[HI] }
} }
/// Read the [flags byte](Flags) of the register /// Read the [flags byte](Flags) of the register
pub fn flags(&self) -> &Flags { pub fn flags(&self) -> &Flags {
// SAFETY: See [SplitRegister::lo] // SAFETY: See [SplitRegister::lo]
unsafe { &self.af[LO] } unsafe { &self.af[LO] }
} }
/// Read the contents of the combined register /// Read the contents of the combined register
pub fn wide(&self) -> &Wrapping<u16> { pub fn wide(&self) -> &Wrapping<u16> {
// SAFETY: See [SplitRegister::lo] // SAFETY: See [SplitRegister::lo]
@ -57,16 +62,19 @@ impl SplitRegister {
// SAFETY: See [SplitRegister::lo] // SAFETY: See [SplitRegister::lo]
unsafe { &mut self.lh[LO] } unsafe { &mut self.lh[LO] }
} }
/// Gets a mutable reference to the high byte of the register /// Gets a mutable reference to the high byte of the register
pub fn hi_mut(&mut self) -> &mut Wrapping<u8> { pub fn hi_mut(&mut self) -> &mut Wrapping<u8> {
// SAFETY: See [SplitRegister::lo] // SAFETY: See [SplitRegister::lo]
unsafe { &mut self.lh[HI] } unsafe { &mut self.lh[HI] }
} }
/// Gets a mutable reference to the [flags byte](Flags) of the register /// Gets a mutable reference to the [flags byte](Flags) of the register
pub fn flags_mut(&mut self) -> &mut Flags { pub fn flags_mut(&mut self) -> &mut Flags {
// SAFETY: See [SplitRegister::lo] // SAFETY: See [SplitRegister::lo]
unsafe { &mut self.af[LO] } unsafe { &mut self.af[LO] }
} }
/// Gets a mutable reference to the combined register /// Gets a mutable reference to the combined register
pub fn wide_mut(&mut self) -> &mut Wrapping<u16> { pub fn wide_mut(&mut self) -> &mut Wrapping<u16> {
// SAFETY: See [SplitRegister::lo] // SAFETY: See [SplitRegister::lo]
@ -75,61 +83,64 @@ impl SplitRegister {
/// Constructs a SplitRegister from an array of big-endian bytes. /// Constructs a SplitRegister from an array of big-endian bytes.
pub fn from_be_bytes(value: [u8; 2]) -> Self { pub fn from_be_bytes(value: [u8; 2]) -> Self {
Self { Self { lh: [Wrapping(value[HI]), Wrapping(value[LO])] }
lh: [Wrapping(value[HI]), Wrapping(value[LO])],
}
} }
/// Constructs a SplitRegister from an array of little-endian bytes. /// Constructs a SplitRegister from an array of little-endian bytes.
pub fn from_le_bytes(value: [u8; 2]) -> Self { pub fn from_le_bytes(value: [u8; 2]) -> Self {
Self { Self { lh: [Wrapping(value[LO]), Wrapping(value[HI])] }
lh: [Wrapping(value[LO]), Wrapping(value[HI])],
}
} }
/// Constructs a SplitRegister from an array of host-endian bytes. /// Constructs a SplitRegister from an array of host-endian bytes.
pub fn from_ne_bytes(value: [u8; 2]) -> Self { pub fn from_ne_bytes(value: [u8; 2]) -> Self {
Self { Self { lh: [Wrapping(value[0]), Wrapping(value[1])] }
lh: [Wrapping(value[0]), Wrapping(value[1])],
}
} }
} }
impl Debug for SplitRegister { impl Debug for SplitRegister {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "[{:02x}, {:02x}]", self.lo(), self.hi()) write!(f, "[{:02x}, {:02x}]", self.lo(), self.hi())
} }
} }
impl Default for SplitRegister { impl Default for SplitRegister {
fn default() -> Self { fn default() -> Self {
Self { r16: Wrapping(0) } Self { r16: Wrapping(0) }
} }
} }
impl PartialEq for SplitRegister { impl PartialEq for SplitRegister {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.wide().eq(other.wide()) self.wide().eq(other.wide())
} }
} }
impl Eq for SplitRegister {} impl Eq for SplitRegister {}
impl PartialOrd for SplitRegister { impl PartialOrd for SplitRegister {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other)) Some(self.cmp(other))
} }
} }
impl Ord for SplitRegister { impl Ord for SplitRegister {
fn cmp(&self, other: &Self) -> std::cmp::Ordering { fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.wide().cmp(other.wide()) self.wide().cmp(other.wide())
} }
} }
impl Hash for SplitRegister { impl Hash for SplitRegister {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) { fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.wide().hash(state) self.wide().hash(state)
} }
} }
impl From<u16> for SplitRegister { impl From<u16> for SplitRegister {
fn from(value: u16) -> Self { fn from(value: u16) -> Self {
Self { Self { r16: Wrapping(value) }
r16: Wrapping(value),
}
} }
} }
impl From<Wrapping<u16>> for SplitRegister { impl From<Wrapping<u16>> for SplitRegister {
fn from(value: Wrapping<u16>) -> Self { fn from(value: Wrapping<u16>) -> Self {
Self { r16: value } Self { r16: value }
@ -158,6 +169,7 @@ macro impl_ops(for $base:ident {$($trait:ident<$($ty:ty),*$(,)?> $func:ident()),
})* })*
)* )*
} }
impl_ops!(for SplitRegister { impl_ops!(for SplitRegister {
Mul<u8, u16> mul(), Mul<u8, u16> mul(),
Div<u8, u16> div(), Div<u8, u16> div(),
@ -171,18 +183,16 @@ impl_ops!(for SplitRegister {
#[test] #[test]
fn low_is_low() { fn low_is_low() {
let reg = SplitRegister { let reg = SplitRegister { r16: Wrapping(0x00ff) };
r16: Wrapping(0x00ff),
};
assert_eq!(*reg.lo(), Wrapping(0xff)) assert_eq!(*reg.lo(), Wrapping(0xff))
} }
#[test] #[test]
fn hi_is_hi() { fn hi_is_hi() {
let reg = SplitRegister { let reg = SplitRegister { r16: Wrapping(0xff00) };
r16: Wrapping(0xff00),
};
assert_eq!(*reg.hi(), Wrapping(0xff)) assert_eq!(*reg.hi(), Wrapping(0xff))
} }
#[test] #[test]
fn from_bytes() { fn from_bytes() {
let be = SplitRegister::from_be_bytes([0xc5, 0x77]); let be = SplitRegister::from_be_bytes([0xc5, 0x77]);

View File

@ -30,6 +30,7 @@ pub enum Mode {
DMG, DMG,
CGB, CGB,
} }
impl Mode { impl Mode {
pub fn from_bits(value: u8) -> Self { pub fn from_bits(value: u8) -> Self {
match value & 0x40 { match value & 0x40 {
@ -37,6 +38,7 @@ impl Mode {
_ => Self::CGB, _ => Self::CGB,
} }
} }
pub fn to_bits(self) -> u8 { pub fn to_bits(self) -> u8 {
(self as u8) << 7 (self as u8) << 7
} }
@ -124,6 +126,7 @@ impl Bus {
hram: [0; 128], hram: [0; 128],
} }
} }
pub fn mmio_read(&self, addr: usize) -> Option<u8> { pub fn mmio_read(&self, addr: usize) -> Option<u8> {
match addr { match addr {
// Joypad I/O // Joypad I/O
@ -306,6 +309,7 @@ mod cart {
Self::new(value) Self::new(value)
} }
} }
impl From<&[u8]> for Cart { impl From<&[u8]> for Cart {
fn from(value: &[u8]) -> Self { fn from(value: &[u8]) -> Self {
Self::new(Vec::from(value)) Self::new(Vec::from(value))
@ -366,8 +370,10 @@ pub mod mapper {
pub mod no_mbc { pub mod no_mbc {
use super::*; use super::*;
#[derive(Clone, Copy, Debug, Default)] #[derive(Clone, Copy, Debug, Default)]
pub struct NoMBC; pub struct NoMBC;
impl Mapper for NoMBC { impl Mapper for NoMBC {
fn read(&self, addr: usize) -> Response { fn read(&self, addr: usize) -> Response {
match addr { match addr {

View File

@ -13,10 +13,12 @@ impl<const BASE: usize, const LEN: usize, const BANKS: usize> Banked<BASE, LEN,
pub fn new() -> Self { pub fn new() -> Self {
Self::default() Self::default()
} }
/// Selects a bank between 0 and `LEN` - 1, saturating /// Selects a bank between 0 and `LEN` - 1, saturating
pub fn select(&mut self, bank: usize) { pub fn select(&mut self, bank: usize) {
self.selected = bank.min(BANKS - 1) self.selected = bank.min(BANKS - 1)
} }
pub fn selected(&self) -> usize { pub fn selected(&self) -> usize {
self.selected self.selected
} }
@ -79,10 +81,12 @@ impl<const BASE: usize, const LEN: usize, const BANKS: usize> UpperBanked<BASE,
pub fn new() -> Self { pub fn new() -> Self {
Self::default() Self::default()
} }
/// Selects a bank between 1 and `LEN` - 1, saturating to `LEN` - 1 /// Selects a bank between 1 and `LEN` - 1, saturating to `LEN` - 1
pub fn select(&mut self, bank: usize) { pub fn select(&mut self, bank: usize) {
self.selected = bank.clamp(1, BANKS - 1) self.selected = bank.clamp(1, BANKS - 1)
} }
/// Gets the currently selected upper bank /// Gets the currently selected upper bank
pub fn selected(&self) -> usize { pub fn selected(&self) -> usize {
self.selected self.selected
@ -159,6 +163,7 @@ mod test {
assert_eq!(idx, *data as usize) assert_eq!(idx, *data as usize)
} }
} }
#[test] #[test]
fn upper_banked_bounds() { fn upper_banked_bounds() {
let ub = UpperBanked::<0, 8, 32>::new(); let ub = UpperBanked::<0, 8, 32>::new();

View File

@ -8,6 +8,7 @@ pub mod iter {
start: usize, start: usize,
bus: &'a dyn BusIO, bus: &'a dyn BusIO,
} }
impl<'a> Iter<'a> { impl<'a> Iter<'a> {
pub fn new(bus: &'a dyn BusIO) -> Self { pub fn new(bus: &'a dyn BusIO) -> Self {
Self { start: 0, bus } Self { start: 0, bus }
@ -16,8 +17,10 @@ pub mod iter {
Self { start, bus } Self { start, bus }
} }
} }
impl<'a> Iterator for Iter<'a> { impl<'a> Iterator for Iter<'a> {
type Item = u8; type Item = u8;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
let Self { start, bus } = self; let Self { start, bus } = self;
let out = bus.read(*start); let out = bus.read(*start);
@ -34,6 +37,7 @@ pub trait BusIO {
// required functions // required functions
/// Attempts to read a byte from self, returning None if the operation failed. /// Attempts to read a byte from self, returning None if the operation failed.
fn read(&self, addr: usize) -> Option<u8>; fn read(&self, addr: usize) -> Option<u8>;
/// Attempts to write a byte to self, returning None if the operation failed. /// Attempts to write a byte to self, returning None if the operation failed.
fn write(&mut self, addr: usize, data: u8) -> Option<()>; fn write(&mut self, addr: usize, data: u8) -> Option<()>;
@ -47,6 +51,7 @@ pub trait BusIO {
{ {
iter::Iter::new(self) iter::Iter::new(self)
} }
/// Gets an iterator which reads bytes in an exclusive range /// Gets an iterator which reads bytes in an exclusive range
fn read_iter_from(&self, start: usize) -> iter::Iter fn read_iter_from(&self, start: usize) -> iter::Iter
where where
@ -60,6 +65,7 @@ impl<const N: usize> BusIO for [u8; N] {
fn read(&self, addr: usize) -> Option<u8> { fn read(&self, addr: usize) -> Option<u8> {
self.get(addr).copied() self.get(addr).copied()
} }
fn write(&mut self, addr: usize, data: u8) -> Option<()> { fn write(&mut self, addr: usize, data: u8) -> Option<()> {
self.get_mut(addr).map(|v| *v = data) self.get_mut(addr).map(|v| *v = data)
} }
@ -69,6 +75,7 @@ impl BusIO for [u8] {
fn read(&self, addr: usize) -> Option<u8> { fn read(&self, addr: usize) -> Option<u8> {
self.get(addr).copied() self.get(addr).copied()
} }
fn write(&mut self, addr: usize, data: u8) -> Option<()> { fn write(&mut self, addr: usize, data: u8) -> Option<()> {
self.get_mut(addr).map(|v| *v = data) self.get_mut(addr).map(|v| *v = data)
} }
@ -78,6 +85,7 @@ impl BusIO for Vec<u8> {
fn read(&self, addr: usize) -> Option<u8> { fn read(&self, addr: usize) -> Option<u8> {
self.get(addr).copied() self.get(addr).copied()
} }
fn write(&mut self, addr: usize, data: u8) -> Option<()> { fn write(&mut self, addr: usize, data: u8) -> Option<()> {
self.get_mut(addr).map(|v| *v = data) self.get_mut(addr).map(|v| *v = data)
} }
@ -97,14 +105,17 @@ pub trait BusAux: BusIO {
} }
Ok(out) Ok(out)
} }
/// Gets the cart entrypoint bytes (machine code starting at 0x100) /// Gets the cart entrypoint bytes (machine code starting at 0x100)
fn entry(&self) -> Result<[u8; 4], [u8; 4]> { fn entry(&self) -> Result<[u8; 4], [u8; 4]> {
self.read_arr(0x100) self.read_arr(0x100)
} }
/// Gets the logo bytes (0x104..0x134) /// Gets the logo bytes (0x104..0x134)
fn logo(&self) -> Result<[u8; 0x30], [u8; 0x30]> { fn logo(&self) -> Result<[u8; 0x30], [u8; 0x30]> {
self.read_arr(0x104) self.read_arr(0x104)
} }
/// Gets the title bytes as a String /// Gets the title bytes as a String
/// # Note /// # Note
/// The title area was repartitioned for other purposes during the Game Boy's life. /// The title area was repartitioned for other purposes during the Game Boy's life.
@ -119,31 +130,36 @@ pub trait BusAux: BusIO {
.map(|c| unsafe { char::from_u32_unchecked(c as u32) }) .map(|c| unsafe { char::from_u32_unchecked(c as u32) })
.collect()) .collect())
} }
/// Gets the manufacturer code bytes /// Gets the manufacturer code bytes
fn mfcode(&self) -> Result<[u8; 4], [u8; 4]> { fn mfcode(&self) -> Result<[u8; 4], [u8; 4]> {
self.read_arr(0x13f) self.read_arr(0x13f)
} }
/// Gets the CGB Flag byte /// Gets the CGB Flag byte
fn cgbflag(&self) -> Option<u8> { fn cgbflag(&self) -> Option<u8> {
self.read(0x143) self.read(0x143)
} }
/// Gets the New Licensee bytes /// Gets the New Licensee bytes
fn newlicensee(&self) -> Result<[u8; 2], [u8; 2]> { fn newlicensee(&self) -> Result<[u8; 2], [u8; 2]> {
self.read_arr(0x144) self.read_arr(0x144)
} }
/// Gets the SGB Flag byte /// Gets the SGB Flag byte
fn sgbflag(&self) -> Option<u8> { fn sgbflag(&self) -> Option<u8> {
self.read(0x146) self.read(0x146)
} }
/// Gets the Cartridge Type byte /// Gets the Cartridge Type byte
fn carttype(&self) -> Option<u8> { fn carttype(&self) -> Option<u8> {
self.read(0x147) self.read(0x147)
} }
/// Gets the size of the cartridge ROM (in 0x8000 byte banks)
fn romsize(&self) -> Option<usize> { fn romsize(&self) -> Option<usize> {
self.read(0x148).map(|s| 1usize.wrapping_shl(s as u32 + 1)) self.read(0x148).map(|s| 1usize.wrapping_shl(s as u32 + 1))
} }
/// Gets the size of the cartridge RAM (in 0x8000 byte banks)
fn ramsize(&self) -> Option<usize> { fn ramsize(&self) -> Option<usize> {
self.read(0x149).map(|s| match s { self.read(0x149).map(|s| match s {
0x02 => 1, 0x02 => 1,
@ -153,22 +169,27 @@ pub trait BusAux: BusIO {
_ => 0, _ => 0,
}) })
} }
/// Gets the destination region code /// Gets the destination region code
fn destcode(&self) -> Option<u8> { fn destcode(&self) -> Option<u8> {
self.read(0x14a) self.read(0x14a)
} }
/// Gets the old licensee byte /// Gets the old licensee byte
fn oldlicencee(&self) -> Option<u8> { fn oldlicencee(&self) -> Option<u8> {
self.read(0x14b) self.read(0x14b)
} }
/// Gets the Maskrom Version byte. Usually 0 /// Gets the Maskrom Version byte. Usually 0
fn maskromver(&self) -> Option<u8> { fn maskromver(&self) -> Option<u8> {
self.read(0x14c) self.read(0x14c)
} }
/// Gets the header checksum /// Gets the header checksum
fn headercksum(&self) -> Option<u8> { fn headercksum(&self) -> Option<u8> {
self.read(0x14d) self.read(0x14d)
} }
/// Gets the checksum of all bytes in ROM /// Gets the checksum of all bytes in ROM
fn globalcksum(&self) -> Option<u16> { fn globalcksum(&self) -> Option<u16> {
self.read_arr(0x14e).ok().map(u16::from_be_bytes) self.read_arr(0x14e).ok().map(u16::from_be_bytes)