Bweh/boy-debug/src/bus.rs

120 lines
3.3 KiB
Rust

//! 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<Self>;
fn ascii(&mut self) -> AsciiSerial<Self>;
fn read_file(&mut self, path: impl AsRef<Path>) -> IoResult<&mut Self>
where
Self: Sized;
}
impl<T: BusIO> BusIOTools for T {
fn trace(&mut self) -> TracingBus<Self> {
TracingBus { bus: self }
}
fn ascii(&mut self) -> AsciiSerial<Self> {
AsciiSerial {
data: 0,
buf: vec![],
bus: self,
}
}
fn read_file(&mut self, path: impl AsRef<Path>) -> 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<u8> {
// 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<u8>,
bus: &'t mut T,
}
impl<'t, T: BusIO + ?Sized> AsciiSerial<'t, T> {
/// Gets the contents of the data buffer
pub fn string(&self) -> Cow<str> {
String::from_utf8_lossy(&self.buf)
}
}
impl<'t, T: BusIO + ?Sized> BusIO for AsciiSerial<'t, T> {
fn read(&self, addr: usize) -> Option<u8> {
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)
}
}