//! A dummied out implementation of a Bus, which is filled entirely with RAM use std::{borrow::Cow, io::Result as IoResult, path::Path}; use boy::memory::io::BusIO; pub trait BusIOTools: BusIO { /// Prints all successful reads and writes fn trace(&mut self) -> TracingBus; fn ascii(&mut self) -> AsciiSerial; fn read_file(&mut self, path: impl AsRef) -> IoResult<&mut Self> where Self: Sized; } impl BusIOTools for T { fn trace(&mut self) -> TracingBus { TracingBus { bus: self } } fn ascii(&mut self) -> AsciiSerial { AsciiSerial { data: 0, buf: vec![], bus: self, } } fn read_file(&mut self, path: impl AsRef) -> IoResult<&mut Self> { let data = std::fs::read(path)?; eprintln!("Read {} bytes.", data.len()); for (addr, data) in data.into_iter().enumerate() { self.write(addr, data); } Ok(self) } } /// A [BusIO] wrapper which prints every read and write operation #[repr(transparent)] pub struct TracingBus<'t, T: BusIO + ?Sized> { bus: &'t mut T, } impl<'t, T: BusIO> BusIO for TracingBus<'t, T> { fn read(&self, addr: usize) -> Option { // print!("bus[{addr:04x}] -> "); // match out { // Some(v) => println!("{v:02x}"), // None => println!("None"), // } self.bus.read(addr) } fn write(&mut self, addr: usize, data: u8) -> Option<()> { eprintln!("set [{addr:04x}], {data:02x}"); self.bus.write(addr, data) } } impl<'t, T: BusIO> From<&'t mut T> for TracingBus<'t, T> { fn from(value: &'t mut T) -> Self { Self { bus: value } } } impl<'t, T: BusIO + AsRef<[u8]>> AsRef<[u8]> for TracingBus<'t, T> { fn as_ref(&self) -> &[u8] { self.bus.as_ref() } } impl<'t, T: BusIO + AsMut<[u8]>> AsMut<[u8]> for TracingBus<'t, T> { fn as_mut(&mut self) -> &mut [u8] { self.bus.as_mut() } } /// Implements a hacky serial port for extracting data pub struct AsciiSerial<'t, T: BusIO + ?Sized> { data: u8, buf: Vec, bus: &'t mut T, } impl<'t, T: BusIO + ?Sized> AsciiSerial<'t, T> { /// Gets the contents of the data buffer pub fn string(&self) -> Cow { String::from_utf8_lossy(&self.buf) } } impl<'t, T: BusIO + ?Sized> BusIO for AsciiSerial<'t, T> { fn read(&self, addr: usize) -> Option { match addr { 0xff01 => Some(self.data), 0xff02 => Some(0x7f), _ => self.bus.read(addr), } } fn write(&mut self, addr: usize, data: u8) -> Option<()> { match addr { 0xff01 => { // eprintln!("'{data:02x}'"); self.buf.push(data); } 0xff02 => { if data & 0x80 != 0 { // eprintln!("SERIAL => {:02x}", self.data); eprintln!("tx: {data:02x}, buf: {:02x?}", self.buf); let interrupt = self.bus.read(0xff0f)? | (1 << 3); self.bus.write(0xff0f, interrupt)?; } } _ => {} } self.bus.write(addr, data) } fn diag(&mut self, param: usize) { println!("debug: '{}'", self.string()); self.buf.clear(); self.bus.diag(param) } }