104 lines
4.5 KiB
Rust
104 lines
4.5 KiB
Rust
use crate::cartridge::Mirror;
|
|
|
|
impl super::Ppu {
|
|
pub fn read(&mut self, address: usize) -> u8 {
|
|
match address {
|
|
0x0000..=0x1FFF => self.mapper.borrow().read(address),
|
|
0x2000..=0x3EFF => self.read_nametable(address),
|
|
0x3F00..=0x3FFF => {
|
|
let a = address % 0x0020;
|
|
let value = self.palette_ram[a];
|
|
value
|
|
}
|
|
_ => 0,
|
|
}
|
|
}
|
|
|
|
pub fn write(&mut self, address: usize, value: u8) {
|
|
// let address = addr % 0x4000;
|
|
match address {
|
|
0x0000..=0x1FFF => self.mapper.borrow_mut().write(address, value),
|
|
0x2000..=0x3EFF => self.write_nametable(address, value),
|
|
0x3F00..=0x3FFF => {
|
|
// I did not read this closely enough for a long time.
|
|
// Addresses $3F10/$3F14/$3F18/$3F1C are mirrors of $3F00/$3F04/$3F08/$3F0C.
|
|
// Note that this goes for writing as well as reading.
|
|
// A symptom of not having implemented this correctly in an emulator is the sky being black in Super Mario Bros.,
|
|
// which writes the backdrop color through $3F10.
|
|
match address % 0x10 {
|
|
0x00 => {
|
|
self.palette_ram[0] = value;
|
|
self.palette_ram[0x10] = value;
|
|
}
|
|
0x04 => {
|
|
self.palette_ram[0x04] = value;
|
|
self.palette_ram[0x14] = value;
|
|
}
|
|
0x08 => {
|
|
self.palette_ram[0x08] = value;
|
|
self.palette_ram[0x18] = value;
|
|
}
|
|
0x0C => {
|
|
self.palette_ram[0x0C] = value;
|
|
self.palette_ram[0x1C] = value;
|
|
}
|
|
_ => self.palette_ram[address % 0x0020] = value,
|
|
}
|
|
}
|
|
_ => (),
|
|
}
|
|
}
|
|
|
|
fn read_nametable(&mut self, address: usize) -> u8 {
|
|
let base = address % 0x1000;
|
|
let offset = base % 0x0400;
|
|
match self.mapper.borrow().get_mirroring() {
|
|
Mirror::LowBank => self.nametable_a[offset],
|
|
Mirror::HighBank => self.nametable_b[offset],
|
|
Mirror::Horizontal => match base {
|
|
0x0000..=0x07FF => self.nametable_a[offset],
|
|
0x0800..=0x0FFF => self.nametable_b[offset],
|
|
_ => panic!("panicked reading nametable base: {}", base),
|
|
},
|
|
Mirror::Vertical => match base {
|
|
0x0000..=0x03FF | 0x0800..=0x0BFF => self.nametable_a[offset],
|
|
0x0400..=0x07FF | 0x0C00..=0x0FFF => self.nametable_b[offset],
|
|
_ => panic!("panicked reading nametable base: {}", base),
|
|
},
|
|
Mirror::FourScreen => match base {
|
|
0x0000..=0x03FF => self.nametable_a[offset],
|
|
0x0400..=0x07FF => self.nametable_b[offset],
|
|
0x0800..=0x0BFF => self.nametable_c[offset],
|
|
0x0C00..=0x0FFF => self.nametable_d[offset],
|
|
_ => panic!("panicked reading nametable base: {}", base),
|
|
},
|
|
}
|
|
}
|
|
|
|
fn write_nametable(&mut self, address: usize, value: u8) {
|
|
let base = address % 0x1000;
|
|
let offset = base % 0x0400;
|
|
match self.mapper.borrow().get_mirroring() {
|
|
Mirror::LowBank => self.nametable_a[offset] = value,
|
|
Mirror::HighBank => self.nametable_b[offset] = value,
|
|
Mirror::Horizontal => match base {
|
|
0x0000..=0x07FF => self.nametable_a[offset] = value,
|
|
0x0800..=0x0FFF => self.nametable_b[offset] = value,
|
|
_ => panic!("panicked writing nametable base: {}", base),
|
|
},
|
|
Mirror::Vertical => match base {
|
|
0x0000..=0x03FF | 0x0800..=0x0BFF => self.nametable_a[offset] = value,
|
|
0x0400..=0x07FF | 0x0C00..=0x0FFF => self.nametable_b[offset] = value,
|
|
_ => panic!("panicked writing nametable base: {}", base),
|
|
},
|
|
Mirror::FourScreen => match base {
|
|
0x0000..=0x03FF => self.nametable_a[offset] = value,
|
|
0x0400..=0x07FF => self.nametable_b[offset] = value,
|
|
0x0800..=0x0BFF => self.nametable_c[offset] = value,
|
|
0x0C00..=0x0FFF => self.nametable_d[offset] = value,
|
|
_ => panic!("panicked writing nametable base: {}", base),
|
|
},
|
|
}
|
|
}
|
|
}
|