use std::{fs::File, io::prelude::*,};
pub struct Bus {
address_space: Vec<u8>,
rom_space: Option<ROMSpace>,
}
pub struct ROMSpace {
pub start: u16,
pub end: u16,
}
impl Bus {
#[doc(hidden)]
pub fn new() -> Bus {
Bus {
address_space: vec![0; 65536],
rom_space: None,
}
}
pub fn set_romspace(&mut self, start: u16, end: u16) {
self.rom_space = Some(ROMSpace{start, end});
}
pub fn read_byte(&self, address: u16) -> u8 {
self.address_space[usize::from(address)]
}
pub fn write_byte(&mut self, address: u16, data: u8) {
if self.rom_space.is_some() && address >= self.rom_space.as_ref().unwrap().start && address <= self.rom_space.as_ref().unwrap().end { return };
self.address_space[usize::from(address)] = data;
}
pub fn read_word(&self, address: u16) -> u16 {
u16::from(self.address_space[usize::from(address)]) | (u16::from(self.address_space[usize::from(address + 1)]) << 8)
}
pub fn read_le_word(&self, address: u16) -> u16 {
u16::from(self.address_space[usize::from(address)]) << 8 | (u16::from(self.address_space[usize::from(address + 1)]))
}
pub fn write_word(&mut self, address: u16, data: u16) {
if self.rom_space.is_some() && address >= self.rom_space.as_ref().unwrap().start && address <= self.rom_space.as_ref().unwrap().end { return };
self.address_space[usize::from(address)] = (data & 0xFF) as u8;
self.address_space[usize::from(address + 1)] = (data >> 8) as u8;
}
pub fn load_bin(&mut self, file: &str, org: u16) -> Result<(), std::io::Error> {
let mut f = File::open(file)?;
let mut buf = Vec::new();
f.read_to_end(&mut buf)?;
self.address_space[org as usize..(buf.len() + org as usize)].clone_from_slice(&buf[..]);
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn rw_byte() {
let mut b = Bus::new();
b.write_byte(0x0000, 0xFF);
assert_eq!(b.read_byte(0x0000), 0xFF);
}
#[test]
fn rw_word() {
let mut b = Bus::new();
b.write_word(0x0000, 0x1be3);
assert_eq!(b.read_word(0x0000), 0x1be3);
}
#[test]
fn rw_le_word() {
let mut b = Bus::new();
b.write_word(0x0000, 0x1be3);
assert_eq!(b.read_le_word(0x0000), 0xe31b);
}
}