120 lines
3.3 KiB
Rust
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)
|
|
}
|
|
}
|