srctree

Johan Norberg parent b6cb5499 d4e460b3
Fix ppu address register writes

* Temporary vram address was not updated correctly and addresses larger than the upper address limit were not mirrored down. * Added test from the summary here: https://wiki.nesdev.org/w/index.php/PPU_scrolling#Summary
core/src/ppu.cpp added: 57, removed: 5, total 52
@@ -168,12 +168,16 @@ void Ppu::write_byte(uint16_t addr, uint8_t byte) {
}
} else if (addr == kPpuAddr) {
if (registers_->write_toggle) { // Second write, lower address byte
registers_->temp_vram_addr |= byte;
registers_->temp_vram_addr =
(registers_->temp_vram_addr & 0xFF00u) | byte;
registers_->vram_addr = registers_->temp_vram_addr;
registers_->write_toggle = false;
} else { // First write, upper address byte
uint16_t upper_addr_byte = byte;
registers_->temp_vram_addr = (upper_addr_byte << 8u);
// Valid addresses are $0000-$3FFF; higher addresses will be
// mirrored down.
const uint16_t upper_byte = (byte & 0x3Fu) << 8u;
const uint16_t lower_byte = registers_->temp_vram_addr & 0x00FFu;
registers_->temp_vram_addr = upper_byte | lower_byte;
registers_->write_toggle = true;
}
} else if (addr == kPpuData) {
 
core/test/src/test_ppu.cpp added: 57, removed: 5, total 52
@@ -65,6 +65,43 @@ TEST_F(PpuTest, clear_status_when_reading_status) {
EXPECT_EQ(expected, registers);
}
 
// Test from the example show at:
// https://wiki.nesdev.org/w/index.php/PPU_scrolling#Summary
TEST_F(PpuTest, scrolling_tests) {
registers.temp_vram_addr = 0b00001100'00000000u;
registers.vram_addr = 0b00000000'00000000u;
expected.temp_vram_addr = 0b00000000'00000000u;
registers.write_toggle = expected.write_toggle = true;
 
ppu->write_byte(0x2000, 0x00);
EXPECT_EQ(expected, registers);
 
expected.write_toggle = false;
ppu->read_byte(0x2002);
EXPECT_EQ(expected, registers);
 
expected.temp_vram_addr = 0b00000000'00001111u;
expected.fine_x_scroll = 0b101u;
expected.write_toggle = true;
ppu->write_byte(0x2005, 0b01111101u);
EXPECT_EQ(expected, registers);
 
expected.temp_vram_addr = 0b01100001'01101111u;
expected.write_toggle = false;
ppu->write_byte(0x2005, 0b01011110u);
EXPECT_EQ(expected, registers);
 
expected.temp_vram_addr = 0b00111101'01101111u;
expected.write_toggle = true;
ppu->write_byte(0x2006, 0b00111101u);
EXPECT_EQ(expected, registers);
 
expected.vram_addr = expected.temp_vram_addr = 0b00111101'11110000u;
expected.write_toggle = false;
ppu->write_byte(0x2006, 0b11110000u);
EXPECT_EQ(expected, registers);
}
 
TEST_F(PpuTest, nmi_is_triggered_when_it_should) {
bool triggered = false;
registers.ctrl = expected.ctrl = 0b1000'0000;
@@ -271,6 +308,7 @@ TEST_F(PpuTest, write_ppu_scroll_nametable_bits_not_overwritten) {
}
 
TEST_F(PpuTest, write_ppu_addr_one_time) {
registers.temp_vram_addr = 0b0011'1111'0000'0000;
expected.temp_vram_addr = 0b0010'1101'0000'0000;
expected.write_toggle = true;
 
@@ -280,6 +318,7 @@ TEST_F(PpuTest, write_ppu_addr_one_time) {
}
 
TEST_F(PpuTest, write_ppu_addr_two_times) {
registers.temp_vram_addr = 0b0010'1101'1111'1111;
expected.temp_vram_addr = 0b0010'1101'0110'0001;
expected.vram_addr = expected.temp_vram_addr;
expected.write_toggle = false;
@@ -290,6 +329,15 @@ TEST_F(PpuTest, write_ppu_addr_two_times) {
EXPECT_EQ(expected, registers);
}
 
TEST_F(PpuTest, write_ppu_addr_ignores_highest_bits) {
expected.temp_vram_addr = 0b0010'1101'0000'0000;
expected.write_toggle = true;
 
ppu->write_byte(0x2006, 0b1110'1101);
 
EXPECT_EQ(expected, registers);
}
 
TEST_F(PpuTest, increment_vram_addr_by_1_after_writing) {
expected.vram_addr = 0x01;