cgram read and write logic

This commit is contained in:
2024-11-04 15:34:46 -05:00
parent 2ceb51fc9d
commit e6c57e8046
+150
View File
@@ -147,6 +147,13 @@ pub enum Background {
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum CGRamDataReadFlipflop{
FirstAccess, // Lower 8 bits
SecondAccess, // Upper 8 bits
}
pub struct PPURegisters {
data: [u8; 64],
vram: [u16; 0x8000],
@@ -154,6 +161,7 @@ pub struct PPURegisters {
pub vblank_nmi: bool,
pub h_count: u16,
pub v_count: u16,
cgram_data_read_flipflop: CGRamDataReadFlipflop
}
impl PPURegisters {
@@ -165,6 +173,7 @@ impl PPURegisters {
vblank_nmi: false,
h_count: 0,
v_count: 0,
cgram_data_read_flipflop: CGRamDataReadFlipflop::FirstAccess,
}
}
@@ -202,6 +211,10 @@ impl PPURegisters {
match address {
VMDATAH => self.handle_vram_addr_auto_increment(Some(result), None),
VMDATAL => self.handle_vram_addr_auto_increment(None, Some(result)),
RDCGRAM => {
let value = self.get_rdcgram();
self._write(RDCGRAM, value);
},
_ => {},
};
self._read(address)
@@ -218,6 +231,11 @@ impl PPURegisters {
self.handle_write_vram(None, Some(value));
},
RDVRAML | RDVRAMH => {},
CGADD => {
self._write(address, value);
self.cgram_data_read_flipflop = CGRamDataReadFlipflop::FirstAccess;
},
CGDATA => self.write_cgram(value),
_ => self._write(address, value),
};
}
@@ -402,6 +420,48 @@ impl PPURegisters {
let current_bg_mode = self._read(BGMODE);
current_bg_mode == 5 || current_bg_mode == 6
}
fn get_cgram_index(&self) -> u8 {
self._read(CGADD)
}
fn handle_cgram_flipflop(&mut self) {
match self.cgram_data_read_flipflop {
CGRamDataReadFlipflop::FirstAccess => {
self.cgram_data_read_flipflop = CGRamDataReadFlipflop::SecondAccess;
},
CGRamDataReadFlipflop::SecondAccess => {
let current_index = self._read(CGADD);
self._write(CGADD, current_index.wrapping_add(1));
self.cgram_data_read_flipflop = CGRamDataReadFlipflop::FirstAccess;
},
};
}
fn get_rdcgram(&mut self) -> u8 {
let cgram_index = self.get_cgram_index() as usize;
let value = match self.cgram_data_read_flipflop {
CGRamDataReadFlipflop::FirstAccess => self.cgram[cgram_index] as u8,
CGRamDataReadFlipflop::SecondAccess => (self.cgram[cgram_index] >> 8) as u8,
};
self.handle_cgram_flipflop();
value
}
fn write_cgram(&mut self, data: u8) {
let cgram_index = self.get_cgram_index() as usize;
match self.cgram_data_read_flipflop {
CGRamDataReadFlipflop::FirstAccess => {
let current_value = self.cgram[cgram_index];
self.cgram[cgram_index] = (current_value & 0xFF00) | (data as u16);
},
CGRamDataReadFlipflop::SecondAccess => {
let current_value = self.cgram[cgram_index];
self.cgram[cgram_index] = (current_value & 0x00FF) | ((data as u16) << 8);
},
};
self.handle_cgram_flipflop();
}
}
impl Default for PPURegisters {
@@ -678,4 +738,94 @@ mod ppu_registers_test {
registers._write(SETINI, 0x01);
assert_eq!(registers.get_current_res(), (512, 448));
}
#[test]
fn test_get_cgram_index() {
let mut registers = PPURegisters::new();
registers._write(CGADD, 0x00);
assert_eq!(registers.get_cgram_index(), 0x00);
registers._write(CGADD, 0x10);
assert_eq!(registers.get_cgram_index(), 0x10);
registers._write(CGADD, 0xFF);
assert_eq!(registers.get_cgram_index(), 0xFF);
registers._write(CGADD, 0xAB);
assert_eq!(registers.get_cgram_index(), 0xAB);
}
#[test]
fn test_handle_cgram_flipflop() {
let mut registers = PPURegisters::new();
registers.cgram_data_read_flipflop = CGRamDataReadFlipflop::FirstAccess;
registers.handle_cgram_flipflop();
assert_eq!(
registers.cgram_data_read_flipflop,
CGRamDataReadFlipflop::SecondAccess,
);
registers.cgram_data_read_flipflop = CGRamDataReadFlipflop::SecondAccess;
registers.handle_cgram_flipflop();
assert_eq!(
registers.cgram_data_read_flipflop,
CGRamDataReadFlipflop::FirstAccess,
);
// When CGADD is written to, the flipflop is reset to first access
registers.cgram_data_read_flipflop = CGRamDataReadFlipflop::FirstAccess;
registers.write(CGADD, 0x00);
assert_eq!(
registers.cgram_data_read_flipflop,
CGRamDataReadFlipflop::FirstAccess,
);
registers.cgram_data_read_flipflop = CGRamDataReadFlipflop::SecondAccess;
registers.write(CGADD, 0x00);
assert_eq!(
registers.cgram_data_read_flipflop,
CGRamDataReadFlipflop::FirstAccess,
);
}
#[test]
fn test_rdcgram_registers() {
let mut registers = PPURegisters::new();
registers.cgram_data_read_flipflop = CGRamDataReadFlipflop::FirstAccess;
registers.cgram[0x10] = 0x1234;
registers._write(CGADD, 0x10);
let first_access_value = registers.read(RDCGRAM);
assert_eq!(first_access_value, 0x34);
assert_eq!(
registers.cgram_data_read_flipflop,
CGRamDataReadFlipflop::SecondAccess,
);
let second_access_value = registers.read(RDCGRAM);
assert_eq!(registers._read(CGADD), 0x11);
assert_eq!(second_access_value, 0x12);
assert_eq!(
registers.cgram_data_read_flipflop,
CGRamDataReadFlipflop::FirstAccess,
);
}
#[test]
fn test_cgdata_registers() {
let mut registers = PPURegisters::new();
registers.cgram_data_read_flipflop = CGRamDataReadFlipflop::FirstAccess;
registers.cgram[0x10] = 0x0000;
registers._write(CGADD, 0x10);
registers.write(CGDATA, 0x34);
assert_eq!(registers.cgram[0x10], 0x0034);
assert_eq!(
registers.cgram_data_read_flipflop,
CGRamDataReadFlipflop::SecondAccess,
);
registers.write(CGDATA, 0x12);
assert_eq!(registers._read(CGADD), 0x11);
assert_eq!(registers.cgram[0x10], 0x1234);
assert_eq!(
registers.cgram_data_read_flipflop,
CGRamDataReadFlipflop::FirstAccess,
);
}
}