Skip to content

Commit

Permalink
Add CPU <-> APU communication ports
Browse files Browse the repository at this point in the history
  • Loading branch information
twvd committed Nov 26, 2023
1 parent eadd734 commit 87242b8
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 22 deletions.
41 changes: 40 additions & 1 deletion src/snes/apu/apubus.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,43 @@
use std::cell::RefCell;
use std::rc::Rc;

use anyhow::Result;

use crate::snes::bus::{Bus, BusMember};
use crate::snes::cpu_spc700::cpu::{SpcAddress, SPC_ADDRESS_MASK};
use crate::tickable::{Tickable, Ticks};

use super::ApuPorts;

const APU_RAM_SIZE: usize = 64 * 1024;
const APU_ROM_SIZE: usize = 64;

/// APU peripherals as they face the SPC700 audio CPU
pub struct Apubus {
ram: [u8; APU_RAM_SIZE],
rom: [u8; APU_ROM_SIZE],
ports: Rc<RefCell<ApuPorts>>,
}

impl Apubus {
pub fn new(rom: &[u8]) -> Self {
pub fn new(rom: &[u8], ports: Rc<RefCell<ApuPorts>>) -> Self {
Self {
ram: [0; APU_RAM_SIZE],
rom: rom.try_into().unwrap(),
ports,
}
}
}

impl Bus<SpcAddress> for Apubus {
fn read(&self, addr: SpcAddress) -> u8 {
match addr {
// Ports
0x00F4..=0x00F7 => {
let ports = self.ports.borrow();
ports.apu[addr as usize - 0x00F4]
}

// ROM (IPL)
// TODO mask setting!
0xFFC0..=0xFFFF => self.rom[addr as usize - 0xFFC0],
Expand All @@ -33,6 +46,32 @@ impl Bus<SpcAddress> for Apubus {
}

fn write(&mut self, addr: SpcAddress, val: u8) {
match addr {
0x00F1 => {
println!("APU control: {:02X}", val);

if val & (1 << 4) != 0 {
let mut ports = self.ports.borrow_mut();
println!("Clear input 0, 1");
ports.apu[0] = 0;
ports.apu[1] = 0;
}
if val & (1 << 5) != 0 {
let mut ports = self.ports.borrow_mut();
println!("Clear input 2, 3");
ports.apu[2] = 0;
ports.apu[3] = 0;
}
}
// Ports
0x00F4..=0x00F7 => {
let mut ports = self.ports.borrow_mut();
println!("APU port {:04X} to {:02X}", addr, val);
ports.cpu[addr as usize - 0x00F4] = val;
}
_ => (),
}

// Writes ALWAYS go through to RAM
self.ram[addr as usize] = val;
}
Expand Down
37 changes: 33 additions & 4 deletions src/snes/apu/mod.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,27 @@
pub mod apubus;

use std::cell::RefCell;
use std::rc::Rc;

use anyhow::Result;
use colored::*;

use crate::snes::bus::{Address, BusMember};
use crate::snes::cpu_spc700::cpu::{CpuSpc700, SpcAddress};
use crate::snes::cpu_spc700::regs::Register;
use crate::tickable::{Tickable, Ticks};

use apubus::Apubus;

/// Type for the CPU <-> APU communication ports
pub struct ApuPorts {
/// APU -> CPU
pub cpu: [u8; 4],

/// CPU -> APU
pub apu: [u8; 4],
}

/// The SNES Audio Processing Unit
pub struct Apu {
/// SPC700 CPU core
Expand All @@ -22,11 +35,14 @@ pub struct Apu {

/// Print instructions
verbose: bool,

/// Main CPU communication ports
ports: Rc<RefCell<ApuPorts>>,
}

impl Apu {
/// One SPC cycle = 25 master cycles
const SPC_MASTER_FACTOR: Ticks = 25;
const SPC_MASTER_FACTOR: Ticks = 1;

const IPL_ENTRYPOINT: SpcAddress = 0xFFC0;
const IPL_SIZE: usize = 64;
Expand All @@ -40,13 +56,26 @@ impl Apu {
];

pub fn new(verbose: bool) -> Self {
let ports = Rc::new(RefCell::new(ApuPorts {
cpu: [0; 4],
apu: [0; 4],
}));
Self {
cpu: CpuSpc700::<Apubus>::new(Apubus::new(&Self::IPL_BIN), Self::IPL_ENTRYPOINT),
cpu: CpuSpc700::<Apubus>::new(
Apubus::new(&Self::IPL_BIN, Rc::clone(&ports)),
Self::IPL_ENTRYPOINT,
),
spc_cycles_taken: 0,
spc_master_credit: 0,
verbose,
ports,
}
}

/// Get a (reference counted) copy of the communication ports
pub fn get_ports(&self) -> Rc<RefCell<ApuPorts>> {
Rc::clone(&self.ports)
}
}

impl Tickable for Apu {
Expand All @@ -57,8 +86,8 @@ impl Tickable for Apu {
self.spc_master_credit += ticks;

while self.spc_master_credit >= Self::SPC_MASTER_FACTOR {
if self.spc_cycles_taken == 0 {
if self.verbose {
if true || self.spc_cycles_taken == 0 {
if self.verbose && self.cpu.regs.read(Register::PC) < Self::IPL_ENTRYPOINT {
println!("{}", self.cpu.dump_state().red());
}
self.spc_cycles_taken += self.cpu.step()?;
Expand Down
34 changes: 18 additions & 16 deletions src/snes/bus/mainbus.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use std::cell::{Cell, RefCell};
use std::rc::Rc;

use anyhow::Result;
use dbg_hex::dbg_hex;

use crate::frontend::Renderer;
use crate::snes::apu::Apu;
use crate::snes::apu::{Apu, ApuPorts};
use crate::snes::bus::{Address, Bus, BusMember, ADDRESS_MASK};
use crate::snes::cartridge::Cartridge;
use crate::snes::joypad::{Joypad, JOYPAD_COUNT};
Expand Down Expand Up @@ -37,8 +38,12 @@ where
/// Controllers
joypads: [Joypad; JOYPAD_COUNT],

/// Audio Processing Unit
pub apu: Apu,

/// APU communication ports
apu_ports: Rc<RefCell<ApuPorts>>,

/// Picture Processing Unit
pub ppu: PPU<TRenderer>,

Expand Down Expand Up @@ -66,8 +71,6 @@ where
/// NMITIMEN register
nmitimen: u8,

apumock: RefCell<[u8; 4]>,

/// Multiplication/division unit registers
wrmpya: u8,
wrdiv: u16,
Expand Down Expand Up @@ -230,6 +233,9 @@ where
joypads: [Joypad; JOYPAD_COUNT],
apu_verbose: bool,
) -> Self {
let apu = Apu::new(apu_verbose);
let apu_ports = apu.get_ports();

Self {
cartridge,
wram: vec![0; WRAM_SIZE],
Expand All @@ -239,7 +245,8 @@ where
joypads,

ppu: PPU::<TRenderer>::new(renderer),
apu: Apu::new(apu_verbose),
apu,
apu_ports,

memsel: 0,
wmadd: Cell::new(0),
Expand All @@ -249,8 +256,6 @@ where
intreq_int: false,
nmitimen: 0,

apumock: RefCell::new([0xAA, 0, 0, 0]),

wrmpya: 0,
wrdiv: 0,
rddiv: 0,
Expand Down Expand Up @@ -439,14 +444,9 @@ where
// APU comms
0x2140..=0x217F => {
let ch = (addr - 0x2140) % 4;
let mut apumock = self.apumock.borrow_mut();
let value = apumock[ch];
apumock[ch] = match ch {
0 => 0xAA,
1 => 0xBB,
_ => 0,
};
Some(value)

let ports = self.apu_ports.borrow();
Some(ports.cpu[ch])
}
// WMDATA - WRAM Data Read/Write (R/W)
0x2180 => {
Expand Down Expand Up @@ -586,8 +586,9 @@ where
// APU comms
0x2140..=0x217F => {
let ch = (addr - 0x2140) % 4;
let mut apumock = self.apumock.borrow_mut();
apumock[ch] = val;
let mut ports = self.apu_ports.borrow_mut();
println!("CPU APU port {} to {:02X}", ch, val);
ports.apu[ch] = val;
Some(())
}
// WMDATA - WRAM Data Read/Write
Expand Down Expand Up @@ -812,6 +813,7 @@ mod tests {
BusTrace::All,
NullRenderer::new(0, 0).unwrap(),
joypads,
false,
)
}

Expand Down
2 changes: 1 addition & 1 deletion src/test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ fn test_display(rom: &[u8], pass_hash: &[u8], time_limit: u128, stable: bool) {
let (display, dispstatus) = TestRenderer::new_test(SCREEN_WIDTH, SCREEN_HEIGHT);
let (joypads, _) = Joypad::new_channel_all();
let cart = Cartridge::load_nohdr(rom, false);
let bus = Mainbus::<TestRenderer>::new(cart, BusTrace::None, display, joypads);
let bus = Mainbus::<TestRenderer>::new(cart, BusTrace::None, display, joypads, false);
let reset = bus.read16(0xFFFC);
let mut cpu = Cpu65816::<Mainbus<TestRenderer>>::new(bus, reset);

Expand Down

0 comments on commit 87242b8

Please sign in to comment.