srctree

Johan Norberg parent 37265498 88eada29
Implement memory accesses for visible scanline in ppu

* Pixel rendering is not added yet.
core/src/ppu.cpp added: 143, removed: 5, total 138
@@ -275,7 +275,11 @@ void Ppu::execute_pre_render_scanline() {
}
}
 
void Ppu::execute_visible_scanline() {}
void Ppu::execute_visible_scanline() {
fetch();
shift_registers();
increase_scroll_counters();
}
 
void Ppu::execute_post_render_scanline() {
// The ppu is idle this scanline
 
core/src/ppu.h added: 143, removed: 5, total 138
@@ -58,7 +58,7 @@ private:
void increment_vram_address();
 
void execute_pre_render_scanline();
static void execute_visible_scanline();
void execute_visible_scanline();
void execute_post_render_scanline();
void execute_vblank_scanline();
 
 
core/test/src/test_ppu.cpp added: 143, removed: 5, total 138
@@ -364,6 +364,140 @@ TEST_F(PpuTest, increment_vram_addr_by_32_after_reading) {
EXPECT_EQ(expected, registers);
}
 
TEST_F(PpuTest, visible_two_sub_cycles) {
registers.scanline = expected.scanline = 0;
registers.mask = expected.mask = 0b000'1000; // Enable background rendering
 
expected.cycle = 17;
// Vram should be increased at cycle 8 and 16
expected.vram_addr = 0x0002;
 
// Clear scrolling
ppu->write_byte(0x2005, 0);
ppu->write_byte(0x2005, 0);
 
{
testing::InSequence seq;
// Nametable on cycle 1 set to index 2
EXPECT_CALL(mmu, read_byte(0x2000)).WillOnce(Return(0x02));
 
// Attribute on cycle 3.
// Second tile has the same attribute byte as the first.
EXPECT_CALL(mmu, read_byte(0x23C0)).WillRepeatedly(Return(0xAB));
 
// Pattern table low byte on cycle 5.
// Each tile uses 16 bytes. So tile with index 2 starts at address 16*2.
EXPECT_CALL(mmu, read_byte(0x02 * 16u)).WillOnce(Return(0x80));
// High byte on cycle 7
// Second bit plane address is 8 bytes after the first bit plane.
EXPECT_CALL(mmu, read_byte(0x02 * 16u + 8u)).WillOnce(Return(0x99));
 
// Nametable on cycle 9 set to index 3
EXPECT_CALL(mmu, read_byte(0x2001)).WillOnce(Return(0x03));
 
// Attribute on cycle 11.
// Second tile has the same attribute byte as the first.
EXPECT_CALL(mmu, read_byte(0x23C0)).WillRepeatedly(Return(0xAB));
 
// Pattern table low byte on cycle 13.
EXPECT_CALL(mmu, read_byte(0x03 * 16u)).WillOnce(Return(0x80));
// Pattern table high byte on cycle 15
EXPECT_CALL(mmu, read_byte(0x03 * 16u + 8u)).WillOnce(Return(0x99));
}
 
for (int i = 0; i < 17; ++i) {
ppu->execute();
}
 
EXPECT_EQ(expected, registers);
}
 
TEST_F(PpuTest, visible_scanline) {
registers.scanline = 0u; // Start at visible scanline
registers.mask = expected.mask = 0b000'1000; // Enable background rendering
 
expected.cycle = 257;
expected.scanline = 0u;
// vram addr: yyy NN YYYYY XXXXX
// Fine scroll should be increase once, and coarse x for each tile except
// the last (31x).
expected.vram_addr = 0b001'00'00000'11111;
 
// Clear scrolling
ppu->write_byte(0x2005, 0);
ppu->write_byte(0x2005, 0);
 
// Nametables
for (int i = 0; i < 32; ++i) {
EXPECT_CALL(mmu, read_byte(0x2000 + i)).WillOnce(Return(i));
}
 
// Attributes. Each address should be fetched four times since each byte
// controlls 4x4 tiles.
for (int i = 0; i < 8; ++i) {
EXPECT_CALL(mmu, read_byte(0x23C0 + i))
.Times(4)
.WillRepeatedly(Return(i));
}
 
// Background
for (int i = 0; i < 32; ++i) {
EXPECT_CALL(mmu, read_byte(i * 16u)).WillOnce(Return(i));
EXPECT_CALL(mmu, read_byte(i * 16u + 8u)).WillOnce(Return(i + 0xF0));
}
 
for (int i = 0; i <= 256; ++i) {
ppu->execute();
}
EXPECT_EQ(expected, registers);
 
// During cycle 257 the horizontal bits should be reloaded.
expected.vram_addr = 0b001'00'00000'00000;
expected.cycle = 258;
 
ppu->execute(); // Cycle 257
EXPECT_EQ(expected, registers);
 
// Cycle 258-320
// During cycle 280-304 the ppu is idle
expected.cycle = 321;
for (int i = 258; i <= 320; ++i) {
ppu->execute();
}
EXPECT_EQ(expected, registers);
 
// Cycle 321-336.
// Fetch first two tiles for next scanline (fine scroll y=1)
expected.vram_addr = 0b001'00'00000'00010;
expected.cycle = 337;
// Nametables
EXPECT_CALL(mmu, read_byte(0x2000)).WillOnce(Return(0x02));
EXPECT_CALL(mmu, read_byte(0x2001)).WillOnce(Return(0x03));
 
// Attributes
EXPECT_CALL(mmu, read_byte(0x23C0)).Times(2).WillRepeatedly(Return(0xAB));
 
// Background for next scanline (+1 for address)
EXPECT_CALL(mmu, read_byte(0x02 * 16u + 1u)).WillOnce(Return(0x80));
EXPECT_CALL(mmu, read_byte(0x02 * 16u + 8u + 1u)).WillOnce(Return(0x99));
EXPECT_CALL(mmu, read_byte(0x03 * 16u + 1u)).WillOnce(Return(0x80));
EXPECT_CALL(mmu, read_byte(0x03 * 16u + 8u + 1u)).WillOnce(Return(0x99));
 
for (int i = 321; i <= 336; ++i) {
ppu->execute();
}
EXPECT_EQ(expected, registers);
 
// Finally cycle 337-340.
// Two nametable fetches (TODO: not implemented).
expected.scanline = 1;
expected.cycle = 0;
for (int i = 337; i <= 340; ++i) {
ppu->execute();
}
EXPECT_EQ(expected, registers);
}
 
TEST_F(PpuTest, pre_render_two_sub_cycles) {
registers.scanline = expected.scanline = 261; // Start at pre-render
registers.mask = expected.mask = 0b000'1000; // Enable background rendering