define all ppu registers

This commit is contained in:
2023-07-09 14:03:59 -05:00
parent 85f41b872d
commit ea7fb8ce65
3 changed files with 140 additions and 103 deletions

View File

@@ -1,10 +1,10 @@
use crate::ppu::registers::PPURegisters;
use crate::ppu::registers::{
RDNMI
};
pub const INTERNAL_REGISTERS_ADDRESS: u16 = 0x4200;
// PPU Interrupts
pub const RDNMI: u16 = 0x4210; // V-Blank NMI Flag
pub struct InternalRegisters {
registers: [u8; 32],
}

View File

@@ -1,24 +1,23 @@
// PPU Control
pub const INIDISP: u16 = 0x2100; // Display Control 1 (W)
pub const TM: u16 = 0x212C; // Main Screen Designation (W)
pub const TS: u16 = 0x212D; // Sub Screen Designation (W)
// PPU Sprites
pub const OBSEL: u16 = 0x2101; // Object Size and Object Base (W)
pub const SETINI: u16 = 0x2133; // Display Control 2 (W)
// OAM Read/Write
pub const OAMADDL: u16 = 0x2102; // OAM Address (L)
pub const OAMADDH: u16 = 0x2103; // OAM Address (H)
pub const OAMDATA: u16 = 0x2104; // OAM Data Write
// PPU BG Control
pub const BGMODE: u16 = 0x2105; // BG Mode and BG Character Size (W)
pub const MOSAIC: u16 = 0x2106; // Mosaic Size and Mosaic Enable (W)
pub const BG1SC: u16 = 0x2107; // BG1 Screen Base and Screen Size (W)
pub const BG2SC: u16 = 0x2108; // BG2 Screen Base and Screen Size (W)
pub const BG3SC: u16 = 0x2109; // BG3 Screen Base and Screen Size (W)
pub const BG4SC: u16 = 0x210A; // BG4 Screen Base and Screen Size (W)
pub const BG12NBA: u16 = 0x210B; // BG Character Data Area Designation (W)
pub const BG34NBA: u16 = 0x210C; // BG Character Data Area Designation (W)
pub const BG1HOFS: u16 = 0x210D; // BG1 Horizontal Scroll (X) (W) and M7HOFS
pub const BG1VOFS: u16 = 0x210E; // BG1 Vertical Scroll (Y) (W) and M7VOFS
pub const BG2HOFS: u16 = 0x210F; // BG2 Horizontal Scroll (X) (W)
@@ -28,58 +27,68 @@ pub const BG3VOFS: u16 = 0x2112; // BG3 Vertical Scroll (Y) (W)
pub const BG4HOFS: u16 = 0x2113; // BG4 Horizontal Scroll (X) (W)
pub const BG4VOFS: u16 = 0x2114; // BG4 Horizontal Scroll (X) (W)
// PPU Rotating/Scaling
pub const M7SEL: u16 = 0x211A; // Rotation/Scaling Mode Settings (W)
pub const M7A: u16 = 0x211B; // Rotation/Scaling Parameter A (and Maths 16bit operand) (W)
pub const M7B: u16 = 0x211C; // Rotation/Scaling Parameter B (and Maths 8bit operand) (W)
pub const M7C: u16 = 0x211D; // Rotation/Scaling Parameter C (W)
pub const M7D: u16 = 0x211E; // Rotation/Scaling Parameter D (W)
pub const M7X: u16 = 0x211F; // Rotation/Scaling Center Coordinate X (W)
pub const M7Y: u16 = 0x2120; // Rotation/Scaling Center Coordinate Y (W)
// PPU Sprites
pub const OBSEL: u16 = 0x2101; // Object Size and Object Base (W)
// PPU Window
pub const WH0: u16 = 0x2126; // Window 1 Left Position (X1) (W)
pub const WH1: u16 = 0x2127; // Window 1 Right Position (X2) (W)
pub const WH2: u16 = 0x2128; // Window 2 Left Position (X1) (W)
pub const WH3: u16 = 0x2129; // Window 2 Right Position (X2) (W)
pub const W12SEL: u16 = 0x2123; // Window BG1/BG2 Mask Settings (W)
pub const W34SEL: u16 = 0x2124; // Window BG3/BG4 Mask Settings (W)
pub const WOBJSEL: u16 = 0x2125; // Window OBJ/MATH Mask Settings (W)
pub const WBGLOG: u16 = 0x212A; // Window 1 Mask Logic (W)
pub const WOBJLOG: u16 = 0x212B; // Window 2 Mask Logic (W)
pub const TMW: u16 = 0x212E; // Window Area Main Screen Disable (W)
pub const TSW: u16 = 0x212F; // Window Area Sub Screen Disable (W)
// PPU Interrupts
pub const RDNMI: u16 = 0x4210; // V-Blank NMI Flag
// PPU VRAM Access
pub const VMAIN: u16 = 0x2115; // VRAM Address Increment
pub const VMAINC: u16 = VMAIN; // VRAM Address Increment
pub const VMADDL: u16 = 0x2116; // VRAM Address Low
pub const VMADDH: u16 = 0x2117; // VRAM Address High
pub const VMDATAL: u16 = 0x2118; // VRAM Write Low
pub const VMDATAH: u16 = 0x2119; // VRAM Write High
pub const VMDATALW: u16 = VMDATAL;
pub const VMDATAHW: u16 = VMDATAH;
// PPU Rotating/Scaling
pub const M7SEL: u16 = 0x211A; // Rotation/Scaling Mode Settings (W)
pub const M7A: u16 = 0x211B; // Rotation/Scaling Parameter A (and Maths 16bit operand) (W)
pub const M7B: u16 = 0x211C; // Rotation/Scaling Parameter B (and Maths 8bit operand) (W)
pub const M7C: u16 = 0x211D; // Rotation/Scaling Parameter C (W)
pub const M7D: u16 = 0x211E; // Rotation/Scaling Parameter D (W)
pub const M7X: u16 = 0x211F; // Rotation/Scaling Center Coordinate X (W)
pub const M7Y: u16 = 0x2120; // Rotation/Scaling Center Coordinate Y (W)
// PPU CGRAM
pub const CGADD: u16 = 0x2121; // Palette CGRAM Address
pub const CGDATA: u16 = 0x2122; // Palette CGRAM Address
// PPU Window
pub const W12SEL: u16 = 0x2123; // Window BG1/BG2 Mask Settings (W)
pub const W34SEL: u16 = 0x2124; // Window BG3/BG4 Mask Settings (W)
pub const WOBJSEL: u16 = 0x2125; // Window OBJ/MATH Mask Settings (W)
pub const WH0: u16 = 0x2126; // Window 1 Left Position (X1) (W)
pub const WH1: u16 = 0x2127; // Window 1 Right Position (X2) (W)
pub const WH2: u16 = 0x2128; // Window 2 Left Position (X1) (W)
pub const WH3: u16 = 0x2129; // Window 2 Right Position (X2) (W)
pub const WBGLOG: u16 = 0x212A; // Window 1 Mask Logic (W)
pub const WOBJLOG: u16 = 0x212B; // Window 2 Mask Logic (W)
pub const TM: u16 = 0x212C; // Main Screen Designation (W)
pub const TS: u16 = 0x212D; // Sub Screen Designation (W)
pub const TMW: u16 = 0x212E; // Window Area Main Screen Disable (W)
pub const TSW: u16 = 0x212F; // Window Area Sub Screen Disable (W)
// PPU Color Math
pub const CGWSEL: u16 = 0x2130; // Color Math Control Register A
pub const CGADSUB: u16 = 0x2131; // Color Math Control Register B
pub const COLDATA: u16 = 0x2132; // Color Math Sub Screen Backdrop Color
// Display Control
pub const SETINI: u16 = 0x2133; // Display Control 2 (W)
// PPU Read-only ports
pub const MPYL: u16 = 0x2134; // Signed Multiply Result (lower 8bit)
pub const MPYM: u16 = 0x2135; // Signed Multiply Result (middle 8bit)
pub const MPYH: u16 = 0x2136; // Signed Multiply Result (upper 8bit)
pub const SLHV: u16 = 0x2137; // Latch H/V-Counter by Software (Read=Strobe)
pub const RDOAM: u16 = 0x2138; // OAM Data Read (read-twice)
pub const RDVRAML: u16 = 0x2139; // VRAM Read Low
pub const RDVRAMH: u16 = 0x213A; // VRAM Read High
pub const VMDATALR: u16 = RDVRAML;
pub const VMDATAHR: u16 = RDVRAMH;
pub const RDCGRAM: u16 = 0x213B; // CGRAM Data Read (Palette)(read-twice)
pub const OPHCT: u16 = 0x213C; // Horizontal Counter Latch (read-twice)
pub const OPVCT: u16 = 0x213D; // Vertical Counter Latch (read-twice)
pub const STAT77: u16 = 0x213E; // PPU1 Status and PPU1 Version Number
pub const STAT78: u16 = 0x213F; // PPU1 Status and PPU1 Version Number
pub const MAX_BG_WIDTH: usize = 16 * 64;
pub const MAX_BG_HEIGHT: usize = 16 * 64;
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum TileSize {
P8x8,
@@ -136,7 +145,7 @@ pub enum Background {
pub struct PPURegisters {
data: [u8; 256],
data: [u8; 64],
vram: [u8; 0x10000],
pub vblank_nmi: bool,
pub h_count: u16,
@@ -146,7 +155,7 @@ pub struct PPURegisters {
impl PPURegisters {
pub fn new() -> Self {
Self {
data: [0x00; 256],
data: [0x00; 64],
vram: [0; 0x10000],
vblank_nmi: false,
h_count: 0,
@@ -163,11 +172,17 @@ impl PPURegisters {
}
fn _read(&self, address: u16) -> u8 {
self.data[(address as usize) - 0x2100]
match address {
0x2100..=0x213F => self.data[(address as usize) - 0x2100],
_ => 0xFF,
}
}
pub fn _write(&mut self, address: u16, value: u8) {
self.data[(address as usize) - 0x2100] = value;
match address {
0x2100..=0x213F => self.data[(address as usize) - 0x2100] = value,
_ => {},
};
}
pub fn read_external(&self, address: u16) -> u8 {
@@ -177,8 +192,8 @@ impl PPURegisters {
pub fn read(&mut self, address: u16) -> u8 {
let result = self._read(address);
match address {
VMDATALR => self.handle_vram_addr_auto_increment(Some(result), None),
VMDATAHR => self.handle_vram_addr_auto_increment(None, Some(result)),
VMDATAL => self.handle_vram_addr_auto_increment(Some(result), None),
VMDATAH => self.handle_vram_addr_auto_increment(None, Some(result)),
_ => {},
};
self._read(address)
@@ -186,15 +201,15 @@ impl PPURegisters {
pub fn write(&mut self, address: u16, value: u8) {
match address {
VMDATALW => {
VMDATAL => {
self._write(address, value);
self.handle_write_vram(Some(value), None);
},
VMDATAHW => {
VMDATAH => {
self._write(address, value);
self.handle_write_vram(None, Some(value));
},
VMDATALR | VMDATAHR => {},
RDVRAML | RDVRAMH => {},
_ => self._write(address, value),
};
}
@@ -204,17 +219,17 @@ impl PPURegisters {
let effective_address = (address & 0x7FFF) * 2;
if let Some(byte) = byte_lo {
self.vram[effective_address.wrapping_add(1) as usize] = byte;
self._write(VMDATALR, byte);
self._write(RDVRAML, byte);
}
if let Some(byte) = byte_hi {
self.vram[effective_address as usize] = byte;
self._write(VMDATAHR, byte);
self._write(RDVRAMH, byte);
}
self.handle_vram_addr_auto_increment(byte_lo, byte_hi);
}
fn handle_vram_addr_auto_increment(&mut self, byte_lo: Option<u8>, byte_hi: Option<u8>) {
let register = self._read(VMAINC);
let register = self._read(VMAIN);
let amount_to_increment = match register & 0b11 {
0b00 => 1,
0b01 => 32,
@@ -467,28 +482,28 @@ mod ppu_registers_test {
let mut registers = PPURegisters::new();
registers.write(VMADDL, 0x00);
registers.write(VMADDH, 0x00);
registers.write(VMDATAHW, 0xAB);
registers.write(VMDATALW, 0xCD);
registers.write(VMDATAH, 0xAB);
registers.write(VMDATAL, 0xCD);
assert_eq!(registers.vram[0x0000], 0xAB);
assert_eq!(registers.vram[0x0001], 0xCD);
registers.write(VMADDH, 0x12);
registers.write(VMADDL, 0x34);
registers.write(VMDATAHW, 0xAB);
registers.write(VMDATALW, 0xCD);
registers.write(VMDATAH, 0xAB);
registers.write(VMDATAL, 0xCD);
assert_eq!(registers.vram[0x2468], 0xAB);
assert_eq!(registers.vram[0x2469], 0xCD);
assert_eq!(registers.read(VMDATAHR), 0xAB);
assert_eq!(registers.read(VMDATALR), 0xCD);
assert_eq!(registers.read(RDVRAMH), 0xAB);
assert_eq!(registers.read(RDVRAML), 0xCD);
registers.write(VMADDH, 0xFF);
registers.write(VMADDL, 0xFF);
registers.write(VMDATAHW, 0xAB);
registers.write(VMDATALW, 0xCD);
registers.write(VMDATAH, 0xAB);
registers.write(VMDATAL, 0xCD);
assert_eq!(registers.vram[0xFFFE], 0xAB);
assert_eq!(registers.vram[0xFFFF], 0xCD);
assert_eq!(registers.read(VMDATAHR), 0xAB);
assert_eq!(registers.read(VMDATALR), 0xCD);
assert_eq!(registers.read(RDVRAMH), 0xAB);
assert_eq!(registers.read(RDVRAML), 0xCD);
}
#[test]
@@ -499,18 +514,18 @@ mod ppu_registers_test {
registers.write(VMADDH, 0x00);
// Increment when low bit is written to
registers.write(VMAINC, 0x00);
registers.write(VMAIN, 0x00);
registers.write(VMDATAHW, 0xAA);
registers.write(VMDATAH, 0xAA);
assert_eq!(registers.get_current_vram_address(), 0x0000);
registers.write(VMDATALW, 0xAA);
registers.write(VMDATAL, 0xAA);
assert_eq!(registers.get_current_vram_address(), 0x0001);
// Increment when hi bit is written to
registers.write(VMAINC, 0b1000_0000);
registers.write(VMDATAHW, 0xAA);
registers.write(VMAIN, 0b1000_0000);
registers.write(VMDATAH, 0xAA);
assert_eq!(registers.get_current_vram_address(), 0x0002);
registers.write(VMDATALW, 0xAA);
registers.write(VMDATAL, 0xAA);
assert_eq!(registers.get_current_vram_address(), 0x0002);
@@ -519,43 +534,43 @@ mod ppu_registers_test {
registers.write(VMADDH, 0x00);
// Increment when low bit is read from
registers.write(VMAINC, 0x00);
registers.write(VMAIN, 0x00);
registers.read(VMDATAHR);
registers.read(VMDATAH);
assert_eq!(registers.get_current_vram_address(), 0x0000);
registers.read(VMDATALR);
registers.read(VMDATAL);
assert_eq!(registers.get_current_vram_address(), 0x0001);
// Increment when hi bit is read from
registers.write(VMAINC, 0b1000_0000);
registers.read(VMDATAHR);
registers.write(VMAIN, 0b1000_0000);
registers.read(VMDATAH);
assert_eq!(registers.get_current_vram_address(), 0x0002);
registers.read(VMDATALR);
registers.read(VMDATAL);
assert_eq!(registers.get_current_vram_address(), 0x0002);
// Increment amounts
registers.write(VMAINC, 0b1000_0000);
registers.write(VMAIN, 0b1000_0000);
registers.write(VMADDL, 0x00);
registers.write(VMADDH, 0x00);
registers.write(VMDATAHW, 0xAA);
registers.write(VMDATAH, 0xAA);
assert_eq!(registers.get_current_vram_address(), 1);
registers.write(VMAINC, 0b1000_0001);
registers.write(VMAIN, 0b1000_0001);
registers.write(VMADDL, 0x00);
registers.write(VMADDH, 0x00);
registers.write(VMDATAHW, 0xAA);
registers.write(VMDATAH, 0xAA);
assert_eq!(registers.get_current_vram_address(), 32);
registers.write(VMAINC, 0b1000_0010);
registers.write(VMAIN, 0b1000_0010);
registers.write(VMADDL, 0x00);
registers.write(VMADDH, 0x00);
registers.write(VMDATAHW, 0xAA);
registers.write(VMDATAH, 0xAA);
assert_eq!(registers.get_current_vram_address(), 128);
registers.write(VMAINC, 0b1000_0011);
registers.write(VMAIN, 0b1000_0011);
registers.write(VMADDL, 0x00);
registers.write(VMADDH, 0x00);
registers.write(VMDATAHW, 0xAA);
registers.write(VMDATAH, 0xAA);
assert_eq!(registers.get_current_vram_address(), 128);
}

View File

@@ -77,9 +77,10 @@ pub fn background_window(bgdebug: &mut BgDebug, registers: &PPURegisters, ui: &i
fn get_register_name(register: u16) -> &'static str {
match register {
snes_core::ppu::registers::INIDISP => "INIDISP",
snes_core::ppu::registers::TM => "TM ",
snes_core::ppu::registers::TS => "TS ",
snes_core::ppu::registers::SETINI => "SETINI ",
snes_core::ppu::registers::OBSEL => "OBSEL ",
snes_core::ppu::registers::OAMADDL => "OAMADDL",
snes_core::ppu::registers::OAMADDH => "OAMADDH",
snes_core::ppu::registers::OAMDATA => "OAMDATA",
snes_core::ppu::registers::BGMODE => "BGMODE ",
snes_core::ppu::registers::MOSAIC => "MOSAIC ",
snes_core::ppu::registers::BG1SC => "BG1SC ",
@@ -89,9 +90,18 @@ fn get_register_name(register: u16) -> &'static str {
snes_core::ppu::registers::BG12NBA => "BG12NBA",
snes_core::ppu::registers::BG34NBA => "BG34NBA",
snes_core::ppu::registers::BG1HOFS => "BG1HOFS",
snes_core::ppu::registers::BG1VOFS => "BG1VOFS",
snes_core::ppu::registers::BG2HOFS => "BG2HOFS",
snes_core::ppu::registers::BG2VOFS => "BG2VOFS",
snes_core::ppu::registers::BG3HOFS => "BG3HOFS",
snes_core::ppu::registers::BG3VOFS => "BG3VOFS",
snes_core::ppu::registers::BG4HOFS => "BG4HOFS",
snes_core::ppu::registers::BG4VOFS => "BG4VOFS",
snes_core::ppu::registers::VMAIN => "VMAIN ",
snes_core::ppu::registers::VMADDL => "VMADDL ",
snes_core::ppu::registers::VMADDH => "VMADDH ",
snes_core::ppu::registers::VMDATAL => "VMDATAL",
snes_core::ppu::registers::VMDATAH => "VMDATAH",
snes_core::ppu::registers::M7SEL => "M7SEL ",
snes_core::ppu::registers::M7A => "M7A ",
snes_core::ppu::registers::M7B => "M7B ",
@@ -99,25 +109,37 @@ fn get_register_name(register: u16) -> &'static str {
snes_core::ppu::registers::M7D => "M7D ",
snes_core::ppu::registers::M7X => "M7X ",
snes_core::ppu::registers::M7Y => "M7Y ",
snes_core::ppu::registers::OBSEL => "OBSEL ",
snes_core::ppu::registers::CGADD => "CGADD ",
snes_core::ppu::registers::CGDATA => "CGDATA ",
snes_core::ppu::registers::W12SEL => "W12SEL ",
snes_core::ppu::registers::W34SEL => "W34SEL ",
snes_core::ppu::registers::WOBJSEL => "WOBJSEL",
snes_core::ppu::registers::WH0 => "WH0 ",
snes_core::ppu::registers::WH1 => "WH1 ",
snes_core::ppu::registers::WH2 => "WH2 ",
snes_core::ppu::registers::WH3 => "WH3 ",
snes_core::ppu::registers::W12SEL => "W12SEL ",
snes_core::ppu::registers::W34SEL => "W34SEL ",
snes_core::ppu::registers::WOBJSEL => "WOBJSEL",
snes_core::ppu::registers::WBGLOG => "WBGLOG ",
snes_core::ppu::registers::WOBJLOG => "WOBJLOG",
snes_core::ppu::registers::TM => "TM ",
snes_core::ppu::registers::TS => "TS ",
snes_core::ppu::registers::TMW => "TMW ",
snes_core::ppu::registers::TSW => "TSW ",
snes_core::ppu::registers::RDNMI => "RDNMI ",
snes_core::ppu::registers::VMAIN => "VMAIN ",
snes_core::ppu::registers::VMADDH => "VMADDH ",
snes_core::ppu::registers::VMDATAL => "VMDATAL",
snes_core::ppu::registers::VMDATAH => "VMDATAH",
snes_core::ppu::registers::CGWSEL => "CGWSEL ",
snes_core::ppu::registers::CGADSUB => "CGADSUB",
snes_core::ppu::registers::COLDATA => "COLDATA",
snes_core::ppu::registers::SETINI => "SETINI ",
snes_core::ppu::registers::MPYL => "MPYL ",
snes_core::ppu::registers::MPYM => "MPYM ",
snes_core::ppu::registers::MPYH => "MPYH ",
snes_core::ppu::registers::SLHV => "SLHV ",
snes_core::ppu::registers::RDOAM => "RDOAM ",
snes_core::ppu::registers::RDVRAML => "RDVRAML",
snes_core::ppu::registers::RDVRAMH => "RDVRAMH",
snes_core::ppu::registers::RDCGRAM => "RDCGRAM",
snes_core::ppu::registers::OPHCT => "OPHCT ",
snes_core::ppu::registers::OPVCT => "OPVCT ",
snes_core::ppu::registers::STAT77 => "STAT77 ",
snes_core::ppu::registers::STAT78 => "STAT78 ",
_ => "N/A ",
}
}