mirror of
https://github.com/FranLMSP/snes.git
synced 2026-08-03 08:30:01 -04:00
cgram read and write logic
This commit is contained in:
@@ -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 {
|
pub struct PPURegisters {
|
||||||
data: [u8; 64],
|
data: [u8; 64],
|
||||||
vram: [u16; 0x8000],
|
vram: [u16; 0x8000],
|
||||||
@@ -154,6 +161,7 @@ pub struct PPURegisters {
|
|||||||
pub vblank_nmi: bool,
|
pub vblank_nmi: bool,
|
||||||
pub h_count: u16,
|
pub h_count: u16,
|
||||||
pub v_count: u16,
|
pub v_count: u16,
|
||||||
|
cgram_data_read_flipflop: CGRamDataReadFlipflop
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PPURegisters {
|
impl PPURegisters {
|
||||||
@@ -165,6 +173,7 @@ impl PPURegisters {
|
|||||||
vblank_nmi: false,
|
vblank_nmi: false,
|
||||||
h_count: 0,
|
h_count: 0,
|
||||||
v_count: 0,
|
v_count: 0,
|
||||||
|
cgram_data_read_flipflop: CGRamDataReadFlipflop::FirstAccess,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,6 +211,10 @@ impl PPURegisters {
|
|||||||
match address {
|
match address {
|
||||||
VMDATAH => self.handle_vram_addr_auto_increment(Some(result), None),
|
VMDATAH => self.handle_vram_addr_auto_increment(Some(result), None),
|
||||||
VMDATAL => self.handle_vram_addr_auto_increment(None, Some(result)),
|
VMDATAL => self.handle_vram_addr_auto_increment(None, Some(result)),
|
||||||
|
RDCGRAM => {
|
||||||
|
let value = self.get_rdcgram();
|
||||||
|
self._write(RDCGRAM, value);
|
||||||
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
};
|
};
|
||||||
self._read(address)
|
self._read(address)
|
||||||
@@ -218,6 +231,11 @@ impl PPURegisters {
|
|||||||
self.handle_write_vram(None, Some(value));
|
self.handle_write_vram(None, Some(value));
|
||||||
},
|
},
|
||||||
RDVRAML | RDVRAMH => {},
|
RDVRAML | RDVRAMH => {},
|
||||||
|
CGADD => {
|
||||||
|
self._write(address, value);
|
||||||
|
self.cgram_data_read_flipflop = CGRamDataReadFlipflop::FirstAccess;
|
||||||
|
},
|
||||||
|
CGDATA => self.write_cgram(value),
|
||||||
_ => self._write(address, value),
|
_ => self._write(address, value),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -402,6 +420,48 @@ impl PPURegisters {
|
|||||||
let current_bg_mode = self._read(BGMODE);
|
let current_bg_mode = self._read(BGMODE);
|
||||||
current_bg_mode == 5 || current_bg_mode == 6
|
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 {
|
impl Default for PPURegisters {
|
||||||
@@ -678,4 +738,94 @@ mod ppu_registers_test {
|
|||||||
registers._write(SETINI, 0x01);
|
registers._write(SETINI, 0x01);
|
||||||
assert_eq!(registers.get_current_res(), (512, 448));
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user