use crate::cartridge::{Cartridge, ChrRomContentStatus};
use crate::input::{ConnectedSocket, HostInput, InputRegisters};
use crate::nes::dma::Dma;
use crate::nes::ppu_cart_memory::PpuCartMemory;
use cpu6502::MemorySpace;
use devices6502::size_const::*;
use devices6502::Device;
type Ram = devices6502::Mirror<devices6502::Ram<SIZE_2K>, 4>;
pub struct NesMemorySpace<'a, THostInput> {
internal_ram: &'a mut Ram,
cartridge: &'a mut dyn Cartridge,
ppu: &'a mut crate::ppu::Ppu,
input_registers: &'a mut InputRegisters,
host_input: &'a mut THostInput,
ppu_dma: &'a mut Dma,
chr_rom_changed: bool,
}
impl<'a, THostInput> MemorySpace for NesMemorySpace<'a, THostInput>
where
THostInput: HostInput,
{
fn read(&mut self, addr: u16) -> u8 {
match addr {
0x0000..=0x1FFF => self.internal_ram.read(addr),
0x2000..=0x3FFF => {
let mut ppu_memory = PpuCartMemory::new(self.cartridge);
self.ppu.read_ppu_register_by_addr(addr, &mut ppu_memory)
}
0x4000..=0x4013 => 0, 0x4014 => 0, 0x4015 => 0, 0x4016 => self
.input_registers
.read_register(self.host_input, ConnectedSocket::Player1),
0x4017 => self
.input_registers
.read_register(self.host_input, ConnectedSocket::Player2),
0x4018..=0x401F => 0, 0x4020..=0xFFFF => self.cartridge.read_cpu_mapped(addr - 0x4020),
}
}
fn write(&mut self, data: u8, addr: u16) {
let mut chr_rom_status = ChrRomContentStatus::Unchanged;
match addr {
0x0000..=0x1FFF => self.internal_ram.write(data, addr),
0x2000..=0x3FFF => {
let mut ppu_memory = PpuCartMemory::new(self.cartridge);
self.ppu
.write_ppu_register_by_addr(data, addr, &mut ppu_memory);
}
0x4000..=0x4013 => (), 0x4014 => self.ppu_dma.initiate_dma(data),
0x4015 => (), 0x4016 => {
if (data & 1) != 0 {
self.input_registers.set_strobe_mode_on();
} else {
self.input_registers.set_strobe_mode_off(self.host_input);
}
}
0x4017 => (), 0x4018..=0x401F => (), 0x4020..=0xFFFF => {
chr_rom_status = self.cartridge.write_cpu_mapped(data, addr - 0x4020)
}
};
self.chr_rom_changed = chr_rom_status == ChrRomContentStatus::Changed;
}
}
impl<'a, THostInput> NesMemorySpace<'a, THostInput>
where
THostInput: HostInput,
{
pub fn new(
internal_ram: &'a mut Ram,
cartridge: &'a mut dyn Cartridge,
ppu: &'a mut crate::ppu::Ppu,
input_registers: &'a mut InputRegisters,
host_input: &'a mut THostInput,
ppu_dma: &'a mut Dma,
) -> Self {
Self {
internal_ram,
cartridge,
ppu,
input_registers,
host_input,
ppu_dma,
chr_rom_changed: false,
}
}
pub fn chr_rom_changed(&self) -> bool {
self.chr_rom_changed
}
}