diff --git a/src/bin/disasm/main.rs b/src/bin/disasm/main.rs index a78ba71..8a27dec 100644 --- a/src/bin/disasm/main.rs +++ b/src/bin/disasm/main.rs @@ -3,7 +3,7 @@ use std::fs; use anyhow::{bail, Result}; -use siena::snes::cpu_65816::instruction::Instruction; +use siena::cpu_65816::instruction::Instruction; fn main() -> Result<()> { let args: Vec = env::args().collect(); diff --git a/src/bin/siena/main.rs b/src/bin/siena/main.rs index 26cf0f2..3a5b116 100644 --- a/src/bin/siena/main.rs +++ b/src/bin/siena/main.rs @@ -11,14 +11,14 @@ use sdl2::keyboard::Keycode; use serde::Deserialize; use serde_json::Deserializer; +use siena::bus::Bus; +use siena::cpu_65816::cpu::Cpu65816; use siena::frontend::channel::ChannelRenderer; use siena::frontend::gif::Gif; use siena::frontend::sdl::{SDLAudioSink, SDLEventPump, SDLRenderer}; use siena::frontend::Renderer; use siena::snes::bus::mainbus::{BusTrace, Mainbus}; -use siena::snes::bus::Bus; use siena::snes::cartridge::{Cartridge, VideoFormat}; -use siena::snes::cpu_65816::cpu::Cpu65816; use siena::snes::joypad::{Button, Joypad, JoypadEvent}; use siena::snes::ppu::ppu::{SCREEN_HEIGHT, SCREEN_WIDTH}; diff --git a/src/bin/spcdisasm/main.rs b/src/bin/spcdisasm/main.rs index 3de7f2d..e12f07f 100644 --- a/src/bin/spcdisasm/main.rs +++ b/src/bin/spcdisasm/main.rs @@ -3,7 +3,7 @@ use std::fs; use anyhow::{bail, Result}; -use siena::snes::cpu_spc700::instruction::Instruction; +use siena::cpu_spc700::instruction::Instruction; fn main() -> Result<()> { let args: Vec = env::args().collect(); diff --git a/src/bin/upddisasm/main.rs b/src/bin/upddisasm/main.rs index 25cdd7e..448e7ff 100644 --- a/src/bin/upddisasm/main.rs +++ b/src/bin/upddisasm/main.rs @@ -3,7 +3,7 @@ use std::fs; use anyhow::{bail, Result}; -use siena::snes::cpu_upd77c25::instruction::Instruction; +use siena::cpu_upd77c25::instruction::Instruction; fn main() -> Result<()> { let args: Vec = env::args().collect(); diff --git a/src/bus/mod.rs b/src/bus/mod.rs new file mode 100644 index 0000000..ce059cc --- /dev/null +++ b/src/bus/mod.rs @@ -0,0 +1,140 @@ +pub mod testbus; + +use crate::tickable::Tickable; + +use num_traits::{PrimInt, WrappingAdd}; + +/// Main CPU address data type (actually 24-bit) +pub type Address = u32; + +/// Main CPU address mask +pub const ADDRESS_MASK: Address = 0x00FFFFFF; + +/// 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: T) -> Option; + fn write(&mut self, addr: T, val: u8) -> Option<()>; +} + +pub trait Bus: 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; + + // 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: 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: T, val: u16) { + self.write(addr, val 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: T) -> u16 { + let l = self.read(addr); + let h = self.read(addr.wrapping_add(&T::one())); + l as u16 | (h as u16) << 8 + } +} + +impl core::fmt::Debug for dyn Bus { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "Bus") + } +} + +pub struct BusIterator<'a, T: PrimInt + WrappingAdd> { + bus: &'a dyn Bus, + next: T, +} + +impl<'a, T: PrimInt + WrappingAdd> BusIterator<'a, T> { + pub fn new_from(bus: &'a dyn Bus, offset: T) -> Self { + Self { bus, next: offset } + } + + pub fn new(bus: &'a dyn Bus) -> Self { + Self::new_from(bus, T::zero()) + } +} + +impl<'a, T: PrimInt + WrappingAdd> Iterator for BusIterator<'a, T> { + type Item = u8; + + fn next(&mut self) -> Option { + let curr = self.next; + self.next = self.next.wrapping_add(&T::one()) & self.bus.get_mask(); + + Some(self.bus.read(curr)) + } +} + +#[cfg(test)] +mod tests { + use super::testbus::Testbus; + use super::*; + + fn testbus() -> Testbus
{ + let mut b = Testbus::
::new(ADDRESS_MASK); + for a in 0..ADDRESS_SPACE { + b.write(a, a as u8); + } + b + } + + #[test] + fn busiterator_new() { + let b = testbus(); + let mut i = BusIterator::new(&b); + + for a in 0..=ADDRESS_MASK { + assert_eq!(i.next(), Some(a as u8)); + } + // Should wrap around at the end + assert_eq!(i.next(), Some(0)); + } + + #[test] + fn busiterator_new_from() { + let b = testbus(); + let mut i = BusIterator::new_from(&b, 5); + + for a in 5..=ADDRESS_MASK { + assert_eq!(i.next(), Some(a as u8)); + } + // Should wrap around at the end + assert_eq!(i.next(), Some(0)); + } + + #[test] + fn bus_write16() { + 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 = testbus(); + b.write(0x1000, 0xAA); + b.write(0x1001, 0x55); + assert_eq!(b.read16(0x1000), 0x55AA); + } +} diff --git a/src/snes/bus/testbus.rs b/src/bus/testbus.rs similarity index 100% rename from src/snes/bus/testbus.rs rename to src/bus/testbus.rs diff --git a/src/snes/cpu_65816/alu.rs b/src/cpu_65816/alu.rs similarity index 100% rename from src/snes/cpu_65816/alu.rs rename to src/cpu_65816/alu.rs diff --git a/src/snes/cpu_65816/cpu.rs b/src/cpu_65816/cpu.rs similarity index 99% rename from src/snes/cpu_65816/cpu.rs rename to src/cpu_65816/cpu.rs index c0c9b87..74c236c 100644 --- a/src/snes/cpu_65816/cpu.rs +++ b/src/cpu_65816/cpu.rs @@ -4,7 +4,7 @@ use lrumap::LruBTreeMap; use num_traits::ToPrimitive; use serde::{Deserialize, Serialize}; -use crate::snes::bus::{Address, Bus, BusIterator, ADDRESS_MASK}; +use crate::bus::{Address, Bus, BusIterator, ADDRESS_MASK}; use crate::tickable::Ticks; use super::alu; diff --git a/src/snes/cpu_65816/instruction.rs b/src/cpu_65816/instruction.rs similarity index 100% rename from src/snes/cpu_65816/instruction.rs rename to src/cpu_65816/instruction.rs diff --git a/src/snes/cpu_65816/instruction_table.rs b/src/cpu_65816/instruction_table.rs similarity index 100% rename from src/snes/cpu_65816/instruction_table.rs rename to src/cpu_65816/instruction_table.rs diff --git a/src/snes/cpu_65816/mod.rs b/src/cpu_65816/mod.rs similarity index 100% rename from src/snes/cpu_65816/mod.rs rename to src/cpu_65816/mod.rs diff --git a/src/snes/cpu_65816/regs.rs b/src/cpu_65816/regs.rs similarity index 100% rename from src/snes/cpu_65816/regs.rs rename to src/cpu_65816/regs.rs diff --git a/src/snes/cpu_spc700/cpu.rs b/src/cpu_spc700/cpu.rs similarity index 99% rename from src/snes/cpu_spc700/cpu.rs rename to src/cpu_spc700/cpu.rs index d1a7a43..8d3d372 100644 --- a/src/snes/cpu_spc700/cpu.rs +++ b/src/cpu_spc700/cpu.rs @@ -2,7 +2,7 @@ use anyhow::Result; use arrayvec::ArrayVec; use serde::{Deserialize, Serialize}; -use crate::snes::bus::{Bus, BusIterator}; +use crate::bus::{Bus, BusIterator}; use crate::tickable::Ticks; use super::instruction::{Instruction, InstructionType, Operand, MAX_INSTRUCTION_LEN}; diff --git a/src/snes/cpu_spc700/instruction.rs b/src/cpu_spc700/instruction.rs similarity index 100% rename from src/snes/cpu_spc700/instruction.rs rename to src/cpu_spc700/instruction.rs diff --git a/src/snes/cpu_spc700/instruction_table.rs b/src/cpu_spc700/instruction_table.rs similarity index 100% rename from src/snes/cpu_spc700/instruction_table.rs rename to src/cpu_spc700/instruction_table.rs diff --git a/src/snes/cpu_spc700/mod.rs b/src/cpu_spc700/mod.rs similarity index 100% rename from src/snes/cpu_spc700/mod.rs rename to src/cpu_spc700/mod.rs diff --git a/src/snes/cpu_spc700/regs.rs b/src/cpu_spc700/regs.rs similarity index 100% rename from src/snes/cpu_spc700/regs.rs rename to src/cpu_spc700/regs.rs diff --git a/src/snes/cpu_upd77c25/cpu.rs b/src/cpu_upd77c25/cpu.rs similarity index 100% rename from src/snes/cpu_upd77c25/cpu.rs rename to src/cpu_upd77c25/cpu.rs diff --git a/src/snes/cpu_upd77c25/instruction.rs b/src/cpu_upd77c25/instruction.rs similarity index 100% rename from src/snes/cpu_upd77c25/instruction.rs rename to src/cpu_upd77c25/instruction.rs diff --git a/src/snes/cpu_upd77c25/mod.rs b/src/cpu_upd77c25/mod.rs similarity index 100% rename from src/snes/cpu_upd77c25/mod.rs rename to src/cpu_upd77c25/mod.rs diff --git a/src/snes/cpu_upd77c25/regs.rs b/src/cpu_upd77c25/regs.rs similarity index 100% rename from src/snes/cpu_upd77c25/regs.rs rename to src/cpu_upd77c25/regs.rs diff --git a/src/lib.rs b/src/lib.rs index 5c37863..a395c4e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,7 @@ +pub mod bus; +pub mod cpu_65816; +pub mod cpu_spc700; +pub mod cpu_upd77c25; pub mod frontend; pub mod snes; pub mod tickable; diff --git a/src/snes/apu/apu.rs b/src/snes/apu/apu.rs index cd71240..1cfdbd4 100644 --- a/src/snes/apu/apu.rs +++ b/src/snes/apu/apu.rs @@ -4,9 +4,9 @@ use anyhow::Result; use colored::*; use serde::{Deserialize, Serialize}; -use crate::snes::bus::{Address, BusMember}; -use crate::snes::cpu_spc700::cpu::{CpuSpc700, SpcAddress}; -use crate::snes::cpu_spc700::regs::Register; +use crate::bus::{Address, BusMember}; +use crate::cpu_spc700::cpu::{CpuSpc700, SpcAddress}; +use crate::cpu_spc700::regs::Register; use crate::tickable::{Tickable, Ticks}; use super::apubus::Apubus; diff --git a/src/snes/apu/apubus.rs b/src/snes/apu/apubus.rs index 0bd9e17..317bc59 100644 --- a/src/snes/apu/apubus.rs +++ b/src/snes/apu/apubus.rs @@ -3,8 +3,8 @@ use colored::*; use serbia::serbia; use serde::{Deserialize, Serialize}; -use crate::snes::bus::Bus; -use crate::snes::cpu_spc700::cpu::{SpcAddress, SPC_ADDRESS_MASK}; +use crate::bus::Bus; +use crate::cpu_spc700::cpu::{SpcAddress, SPC_ADDRESS_MASK}; use crate::tickable::{Tickable, Ticks}; use super::apu::ApuPorts; diff --git a/src/snes/bus/mainbus.rs b/src/snes/bus/mainbus.rs index 9a2dfe7..d0a0ef7 100644 --- a/src/snes/bus/mainbus.rs +++ b/src/snes/bus/mainbus.rs @@ -5,8 +5,8 @@ use anyhow::Result; use dbg_hex::dbg_hex; use serde::{Deserialize, Serialize}; +use crate::bus::{Address, Bus, BusMember, ADDRESS_MASK}; use crate::frontend::Renderer; -use crate::snes::bus::{Address, Bus, BusMember, ADDRESS_MASK}; use crate::snes::cartridge::{Cartridge, VideoFormat}; use crate::snes::joypad::{Joypad, JOYPAD_COUNT}; use crate::snes::ppu::ppu::PPU; diff --git a/src/snes/bus/mod.rs b/src/snes/bus/mod.rs index b97b074..cf51179 100644 --- a/src/snes/bus/mod.rs +++ b/src/snes/bus/mod.rs @@ -1,141 +1 @@ pub mod mainbus; -pub mod testbus; - -use crate::tickable::Tickable; - -use num_traits::{PrimInt, WrappingAdd}; - -/// Main CPU address data type (actually 24-bit) -pub type Address = u32; - -/// Main CPU address mask -pub const ADDRESS_MASK: Address = 0x00FFFFFF; - -/// 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: T) -> Option; - fn write(&mut self, addr: T, val: u8) -> Option<()>; -} - -pub trait Bus: 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; - - // 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: 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: T, val: u16) { - self.write(addr, val 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: T) -> u16 { - let l = self.read(addr); - let h = self.read(addr.wrapping_add(&T::one())); - l as u16 | (h as u16) << 8 - } -} - -impl core::fmt::Debug for dyn Bus { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "Bus") - } -} - -pub struct BusIterator<'a, T: PrimInt + WrappingAdd> { - bus: &'a dyn Bus, - next: T, -} - -impl<'a, T: PrimInt + WrappingAdd> BusIterator<'a, T> { - pub fn new_from(bus: &'a dyn Bus, offset: T) -> Self { - Self { bus, next: offset } - } - - pub fn new(bus: &'a dyn Bus) -> Self { - Self::new_from(bus, T::zero()) - } -} - -impl<'a, T: PrimInt + WrappingAdd> Iterator for BusIterator<'a, T> { - type Item = u8; - - fn next(&mut self) -> Option { - let curr = self.next; - self.next = self.next.wrapping_add(&T::one()) & self.bus.get_mask(); - - Some(self.bus.read(curr)) - } -} - -#[cfg(test)] -mod tests { - use super::testbus::Testbus; - use super::*; - - fn testbus() -> Testbus
{ - let mut b = Testbus::
::new(ADDRESS_MASK); - for a in 0..ADDRESS_SPACE { - b.write(a, a as u8); - } - b - } - - #[test] - fn busiterator_new() { - let b = testbus(); - let mut i = BusIterator::new(&b); - - for a in 0..=ADDRESS_MASK { - assert_eq!(i.next(), Some(a as u8)); - } - // Should wrap around at the end - assert_eq!(i.next(), Some(0)); - } - - #[test] - fn busiterator_new_from() { - let b = testbus(); - let mut i = BusIterator::new_from(&b, 5); - - for a in 5..=ADDRESS_MASK { - assert_eq!(i.next(), Some(a as u8)); - } - // Should wrap around at the end - assert_eq!(i.next(), Some(0)); - } - - #[test] - fn bus_write16() { - 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 = testbus(); - b.write(0x1000, 0xAA); - b.write(0x1001, 0x55); - assert_eq!(b.read16(0x1000), 0x55AA); - } -} diff --git a/src/snes/cartridge.rs b/src/snes/cartridge.rs index 8634ec0..d065b1c 100644 --- a/src/snes/cartridge.rs +++ b/src/snes/cartridge.rs @@ -6,8 +6,9 @@ use num_traits::FromPrimitive; use serde::{Deserialize, Serialize}; use strum::Display; -use super::bus::{Address, BusMember}; use super::coprocessor::dsp1::DSP1; + +use crate::bus::{Address, BusMember}; use crate::tickable::{Tickable, Ticks}; const HDR_TITLE_OFFSET: usize = 0x00; diff --git a/src/snes/coprocessor/dsp1.rs b/src/snes/coprocessor/dsp1.rs index 8fdc406..32cfc2d 100644 --- a/src/snes/coprocessor/dsp1.rs +++ b/src/snes/coprocessor/dsp1.rs @@ -3,8 +3,8 @@ use std::cell::{Cell, RefCell}; use anyhow::Result; use serde::{Deserialize, Serialize}; -use crate::snes::cpu_upd77c25::cpu::CpuUpd77c25; -use crate::snes::cpu_upd77c25::regs::{Register, SR}; +use crate::cpu_upd77c25::cpu::CpuUpd77c25; +use crate::cpu_upd77c25::regs::{Register, SR}; use crate::tickable::{Tickable, Ticks}; /// DSP-1 co-processor diff --git a/src/snes/mod.rs b/src/snes/mod.rs index 5f001b5..d6202a8 100644 --- a/src/snes/mod.rs +++ b/src/snes/mod.rs @@ -6,8 +6,5 @@ pub mod apu_blargg; pub mod bus; pub mod cartridge; pub mod coprocessor; -pub mod cpu_65816; -pub mod cpu_spc700; -pub mod cpu_upd77c25; pub mod joypad; pub mod ppu; diff --git a/src/snes/ppu/bus.rs b/src/snes/ppu/bus.rs index f25bd10..bc31fde 100644 --- a/src/snes/ppu/bus.rs +++ b/src/snes/ppu/bus.rs @@ -1,6 +1,6 @@ use super::state::*; -use crate::snes::bus::{Address, BusMember}; +use crate::bus::{Address, BusMember}; use crate::util::sign_extend; macro_rules! write_m7x { diff --git a/src/snes/ppu/ppu.rs b/src/snes/ppu/ppu.rs index c167bd5..41aa729 100644 --- a/src/snes/ppu/ppu.rs +++ b/src/snes/ppu/ppu.rs @@ -4,8 +4,8 @@ use anyhow::Result; use rusty_pool::ThreadPool; use serde::{Deserialize, Serialize}; +use crate::bus::{Address, BusMember}; use crate::frontend::Renderer; -use crate::snes::bus::{Address, BusMember}; use crate::snes::cartridge::VideoFormat; use crate::tickable::{Tickable, Ticks}; diff --git a/src/snes/ppu/tests.rs b/src/snes/ppu/tests.rs index b08c6bc..6045e3b 100644 --- a/src/snes/ppu/tests.rs +++ b/src/snes/ppu/tests.rs @@ -1,5 +1,5 @@ +use crate::bus::BusMember; use crate::frontend::NullRenderer; -use crate::snes::bus::BusMember; use crate::snes::cartridge::VideoFormat; use super::ppu::PPU; diff --git a/src/test/mod.rs b/src/test/mod.rs index e03b590..06f1eca 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -7,11 +7,11 @@ pub mod processortests_spc700; use itertools::Itertools; use std::time::Instant; +use crate::bus::Bus; +use crate::cpu_65816::cpu::Cpu65816; use crate::frontend::test::TestRenderer; use crate::snes::bus::mainbus::{BusTrace, Mainbus}; -use crate::snes::bus::Bus; use crate::snes::cartridge::{Cartridge, VideoFormat}; -use crate::snes::cpu_65816::cpu::Cpu65816; use crate::snes::joypad::Joypad; use crate::snes::ppu::ppu::{SCREEN_HEIGHT, SCREEN_WIDTH}; diff --git a/src/test/processortests_65816.rs b/src/test/processortests_65816.rs index 3733eb6..3712e53 100644 --- a/src/test/processortests_65816.rs +++ b/src/test/processortests_65816.rs @@ -3,10 +3,10 @@ use serde_json::Value; use std::collections::HashMap; use std::fs; -use crate::snes::bus::testbus::{Access, Testbus}; -use crate::snes::bus::{Address, Bus, ADDRESS_MASK}; -use crate::snes::cpu_65816::cpu::Cpu65816; -use crate::snes::cpu_65816::regs::RegisterFile; +use crate::bus::testbus::{Access, Testbus}; +use crate::bus::{Address, Bus, ADDRESS_MASK}; +use crate::cpu_65816::cpu::Cpu65816; +use crate::cpu_65816::regs::RegisterFile; macro_rules! _cpu_test { ($testfn:ident, $instr:expr, $trace:expr, $steps:expr) => { diff --git a/src/test/processortests_spc700.rs b/src/test/processortests_spc700.rs index 929aa2e..59d3a48 100644 --- a/src/test/processortests_spc700.rs +++ b/src/test/processortests_spc700.rs @@ -3,10 +3,10 @@ use serde_json::Value; use std::collections::HashMap; use std::fs; -use crate::snes::bus::testbus::{Access, Testbus}; -use crate::snes::bus::Bus; -use crate::snes::cpu_spc700::cpu::{CpuSpc700, SpcAddress, SPC_ADDRESS_MASK}; -use crate::snes::cpu_spc700::regs::RegisterFile; +use crate::bus::testbus::{Access, Testbus}; +use crate::bus::Bus; +use crate::cpu_spc700::cpu::{CpuSpc700, SpcAddress, SPC_ADDRESS_MASK}; +use crate::cpu_spc700::regs::RegisterFile; macro_rules! _cpu_test { ($testfn:ident, $instr:expr, $trace:expr, $steps:expr) => {