Skip to content

Commit

Permalink
Refactor Bus/BusMember to take a generic address type
Browse files Browse the repository at this point in the history
  • Loading branch information
twvd committed Nov 19, 2023
1 parent 84c1fd6 commit 9412d7d
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 54 deletions.
8 changes: 6 additions & 2 deletions src/snes/bus/mainbus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use anyhow::Result;
use dbg_hex::dbg_hex;

use crate::frontend::Renderer;
use crate::snes::bus::{Address, Bus, BusMember};
use crate::snes::bus::{Address, Bus, BusMember, ADDRESS_MASK};
use crate::snes::cartridge::Cartridge;
use crate::snes::joypad::{Joypad, JOYPAD_COUNT};
use crate::snes::ppu::PPU;
Expand Down Expand Up @@ -413,10 +413,14 @@ where
}
}

impl<TRenderer> Bus for Mainbus<TRenderer>
impl<TRenderer> Bus<Address> for Mainbus<TRenderer>
where
TRenderer: Renderer,
{
fn get_mask(&self) -> Address {
ADDRESS_MASK
}

fn read(&self, fulladdr: Address) -> u8 {
let (bank, addr) = ((fulladdr >> 16) as usize, (fulladdr & 0xFFFF) as usize);

Expand Down
79 changes: 32 additions & 47 deletions src/snes/bus/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,99 +3,84 @@ pub mod testbus;

use crate::tickable::Tickable;

/// Address data type (actually 24-bit)
use num_traits::{PrimInt, WrappingAdd};

/// Main CPU address data type (actually 24-bit)
pub type Address = u32;

/// Address mask
/// Main CPU address mask
pub const ADDRESS_MASK: Address = 0x00FFFFFF;

/// Total address space
/// Main CPU total address space
pub const ADDRESS_SPACE_SIZE: usize = 16 * 1024 * 1024;
pub const ADDRESS_SPACE: u32 = 16 * 1024 * 1024;

pub trait BusMember {
fn read(&self, addr: Address) -> Option<u8>;
fn write(&mut self, addr: Address, val: u8) -> Option<()>;
pub trait BusMember<T: PrimInt> {
fn read(&self, addr: T) -> Option<u8>;
fn write(&mut self, addr: T, val: u8) -> Option<()>;
}

pub trait Bus: Tickable {
fn read(&self, addr: Address) -> u8;
fn write(&mut self, addr: Address, val: u8);
pub trait Bus<T: PrimInt + WrappingAdd>: Tickable {
fn read(&self, addr: T) -> u8;
fn write(&mut self, addr: T, val: u8);
fn get_clr_nmi(&mut self) -> bool;
fn get_clr_int(&mut self) -> bool;

/// Writes an entire u8 slice to the bus from a specified
/// address offset.
fn write_slice(&mut self, from: &[u8], offset: Address) {
for (i, b) in from.into_iter().enumerate() {
self.write(offset.wrapping_add(i as Address) & ADDRESS_MASK, *b);
}
}

/// Reads the specified size from the specified address
/// into a u8 vec.
fn read_vec(&self, addr: Address, size: usize) -> Vec<u8> {
let mut addr = addr;
let mut ret: Vec<u8> = vec![];
for _ in 0..size {
ret.push(self.read(addr));
addr = addr.wrapping_add(1) & ADDRESS_MASK;
}
ret
}
// TODO this is pretty awful
fn get_mask(&self) -> T;

/// Write 16-bits to addr + 1 and addr (specific access order),
/// in little endian.
fn write16(&mut self, addr: Address, val: u16) {
self.write(addr.wrapping_add(1), (val >> 8) as u8);
fn write16(&mut self, addr: T, val: u16) {
self.write(addr.wrapping_add(&T::one()), (val >> 8) as u8);
self.write(addr, val as u8);
}

/// Write 16-bits to addr and addr + 1 (specific access order),
/// in little endian.
/// This access order is inverted, for operations that
/// require that..
fn write16_acc_low(&mut self, addr: Address, val: u16) {
fn write16_acc_low(&mut self, addr: T, val: u16) {
self.write(addr, val as u8);
self.write(addr.wrapping_add(1), (val >> 8) as u8);
self.write(addr.wrapping_add(&T::one()), (val >> 8) as u8);
}

/// Read 16-bits from addr and addr + 1,
/// from little endian.
fn read16(&self, addr: Address) -> u16 {
fn read16(&self, addr: T) -> u16 {
let l = self.read(addr);
let h = self.read(addr.wrapping_add(1));
let h = self.read(addr.wrapping_add(&T::one()));
l as u16 | (h as u16) << 8
}
}

impl core::fmt::Debug for dyn Bus {
impl<T> core::fmt::Debug for dyn Bus<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "Bus")
}
}

pub struct BusIterator<'a> {
bus: &'a dyn Bus,
next: Address,
pub struct BusIterator<'a, T: PrimInt + WrappingAdd> {
bus: &'a dyn Bus<T>,
next: T,
}

impl<'a> BusIterator<'a> {
pub fn new_from(bus: &'a dyn Bus, offset: Address) -> BusIterator {
BusIterator { bus, next: offset }
impl<'a, T: PrimInt + WrappingAdd> BusIterator<'a, T> {
pub fn new_from(bus: &'a dyn Bus<T>, offset: T) -> Self {
Self { bus, next: offset }
}

pub fn new(bus: &'a dyn Bus) -> BusIterator {
Self::new_from(bus, 0)
pub fn new(bus: &'a dyn Bus<T>) -> Self {
Self::new_from(bus, T::zero())
}
}

impl<'a> Iterator for BusIterator<'a> {
impl<'a, T: PrimInt + WrappingAdd> Iterator for BusIterator<'a, T> {
type Item = u8;

fn next(&mut self) -> Option<Self::Item> {
let curr = self.next;
self.next = self.next.wrapping_add(1) & ADDRESS_MASK;
self.next = self.next.wrapping_add(&T::one()) & self.bus.get_mask();

Some(self.bus.read(curr))
}
Expand Down Expand Up @@ -140,15 +125,15 @@ mod tests {

#[test]
fn bus_write16() {
let mut b: Box<dyn Bus> = Box::new(testbus());
let mut b = testbus();
b.write16(0x1000, 0x55AA);
assert_eq!(b.read(0x1000), 0xAA);
assert_eq!(b.read(0x1001), 0x55);
}

#[test]
fn bus_read16() {
let mut b: Box<dyn Bus> = Box::new(testbus());
let mut b = testbus();
b.write(0x1000, 0xAA);
b.write(0x1001, 0x55);
assert_eq!(b.read16(0x1000), 0x55AA);
Expand Down
6 changes: 5 additions & 1 deletion src/snes/bus/testbus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,11 @@ impl Testbus {
}
}

impl Bus for Testbus {
impl Bus<Address> for Testbus {
fn get_mask(&self) -> Address {
ADDRESS_MASK
}

fn read(&self, addr: Address) -> u8 {
assert_eq!(addr & ADDRESS_MASK, addr);

Expand Down
2 changes: 1 addition & 1 deletion src/snes/cartridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ impl fmt::Display for Cartridge {
}
}

impl BusMember for Cartridge {
impl BusMember<Address> for Cartridge {
fn read(&self, fulladdr: Address) -> Option<u8> {
let (bank, addr) = ((fulladdr >> 16) as usize, (fulladdr & 0xFFFF) as usize);

Expand Down
4 changes: 2 additions & 2 deletions src/snes/cpu_65816/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ use super::instruction::{AddressingMode, Instruction, InstructionType};
use super::regs::{Flag, Register, RegisterFile, RegisterWidth};

/// Main SNES CPU (65816)
pub struct Cpu65816<TBus: Bus> {
pub struct Cpu65816<TBus: Bus<Address>> {
pub bus: TBus,
pub regs: RegisterFile,
pub cycles: Ticks,
}

impl<TBus> Cpu65816<TBus>
where
TBus: Bus,
TBus: Bus<Address>,
{
const INTVEC_COP: Address = 0x00FFE4;
const INTVEC_BRK: Address = 0x00FFE6;
Expand Down
2 changes: 1 addition & 1 deletion src/snes/ppu/bus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use super::*;
use crate::frontend::Renderer;
use crate::snes::bus::{Address, BusMember};

impl<TRenderer> BusMember for PPU<TRenderer>
impl<TRenderer> BusMember<Address> for PPU<TRenderer>
where
TRenderer: Renderer,
{
Expand Down

0 comments on commit 9412d7d

Please sign in to comment.