srctree

Johan Norberg parent 04ee4406 8faf8fb9
Use register abstraction for ppu ctrl

core/include/nes/core/ppu_registers.h added: 32, removed: 20, total 12
@@ -130,6 +130,17 @@ public:
}
};
 
// Controll bits
// 0-1: nametable address (0 = $2000; 1 = $2400; 2 = $2800; 3 = $2C00)
// 2: VRAM address increment per CPU read/write of PPUDATA (0: add 1; 1: add 32)
// 3: Sprite pattern table address for 8x8 sprites
// (0: $0000; 1: $1000; ignored in 8x16 mode)
// 4: Background pattern table address (0: $0000; 1: $1000)
// 5: Sprite size (0: 8x8 pixels; 1: 8x16 pixels)
// 6: PPU master/slave select
// 7: Generate NMI at the start of the vertical blanking (0: off; 1: on)
using PpuCtrl = Register<uint8_t>;
 
// Mask bits
// 0: Greyscale (0: normal color, 1: produce a greyscale display)
// 1: Show background in leftmost 8 pixels of screen if set.
@@ -159,8 +170,8 @@ public:
struct PpuRegisters {
uint16_t scanline;
uint16_t cycle;
uint8_t ctrl;
 
PpuCtrl ctrl;
PpuMask mask;
uint8_t status;
uint8_t oamaddr;
 
core/src/ppu.cpp added: 32, removed: 20, total 12
@@ -73,13 +73,14 @@ uint8_t Ppu::read_byte(uint16_t addr) {
 
void Ppu::write_byte(uint16_t addr, uint8_t byte) {
if (addr == kPpuCtrl) {
const auto new_ctrl = PpuCtrl(byte);
// Trigger nmi if the nmi-enabled flag goes from 0 to 1 during vblank.
if (!(registers_->ctrl & (1u << 7u)) && byte & (1u << 7u) &&
if (!registers_->ctrl.is_set(7u) && new_ctrl.is_set(7u) &&
registers_->status & (1u << 7u)) {
on_nmi_();
}
 
registers_->ctrl = byte;
registers_->ctrl = new_ctrl;
registers_->temp_vram_addr.set_nametable(byte);
} else if (addr == kPpuMask) {
registers_->mask = PpuMask(byte);
@@ -200,10 +201,10 @@ bool Ppu::is_rendering_active() const {
}
 
uint8_t Ppu::get_vram_address_increment() const {
uint8_t addr_increment = 1;
uint8_t addr_increment = 1u;
 
if (registers_->ctrl & (1u << 2u)) {
addr_increment = 32;
if (registers_->ctrl.is_set(2u)) {
addr_increment = 32u;
}
 
return addr_increment;
@@ -234,7 +235,7 @@ void Ppu::execute_post_render_scanline() {
void Ppu::execute_vblank_scanline() {
if (scanline() == 241 && cycle() == 1) {
set_vblank_flag();
if (registers_->ctrl & (1u << 7u)) {
if (registers_->ctrl.is_set(7u)) {
on_nmi_();
}
}
@@ -297,7 +298,7 @@ void Ppu::fetch() {
(cycle() >= 321 && cycle() <= 336)) {
shift_registers();
const uint16_t background_pattern_table_base_address =
(registers_->ctrl & 0b0001'0000u) ? 0x1000u : 0x0000u;
registers_->ctrl.is_set(4u) ? 0x1000u : 0x0000u;
const uint8_t fine_scroll_y = registers_->vram_addr.fine_scroll_y();
 
switch ((cycle() - 1) % 8) {
 
core/test/src/ippu_helpers.cpp added: 32, removed: 20, total 12
@@ -18,7 +18,7 @@ void PrintTo(const PpuRegisters &r, std::ostream *os) {
"Attr: {:#06x}:{:#06x}[{:#04x}]\n",
r.cycle,
r.scanline,
r.ctrl,
r.ctrl.value(),
r.fine_x_scroll,
r.mask.value(),
r.oamaddr,
 
core/test/src/test_ppu.cpp added: 32, removed: 20, total 12
@@ -132,7 +132,7 @@ TEST_F(PpuTest, split_xy_scrolling_tests) {
 
TEST_F(PpuTest, nmi_is_triggered_when_it_should) {
bool triggered = false;
registers.ctrl = expected.ctrl = 0b1000'0000;
registers.ctrl = expected.ctrl = PpuCtrl(0b1000'0000u);
ppu->set_nmi_handler([&] { triggered = true; });
 
// Nmi shouldn't get triggered before the start of vblanking.
@@ -156,7 +156,7 @@ TEST_F(PpuTest, nmi_is_triggered_when_it_should) {
 
TEST_F(PpuTest, nmi_is_not_triggered_if_disabled) {
bool triggered = false;
registers.ctrl = expected.ctrl = 0x00;
registers.ctrl = expected.ctrl = PpuCtrl(0x00);
ppu->set_nmi_handler([&] { triggered = true; });
 
// Nmi shouldn't get triggered since bit 7 in ctrl is 0.
@@ -166,7 +166,7 @@ TEST_F(PpuTest, nmi_is_not_triggered_if_disabled) {
 
TEST_F(PpuTest, nmi_triggered_when_enabled_during_vblank) {
bool triggered = false;
expected.ctrl = 0b1000'0000;
expected.ctrl = PpuCtrl(0b1000'0000);
ppu->set_nmi_handler([&] { triggered = true; });
 
step_execution(kCyclesPerScanline * 241 + 1);
@@ -211,7 +211,7 @@ TEST_F(PpuTest, clear_vblank_flag_during_pre_render_line) {
}
 
TEST_F(PpuTest, write_to_ctrl_register) {
expected.ctrl = 0xBA;
expected.ctrl = PpuCtrl(0xBA);
expected.temp_vram_addr = PpuVram(0x800);
 
ppu->write_byte(0x2000, 0xBA);
@@ -329,7 +329,7 @@ TEST_F(PpuTest, write_ppu_scroll_two_times) {
}
 
TEST_F(PpuTest, write_ppu_scroll_nametable_bits_not_overwritten) {
expected.ctrl = 0b0000'0011;
expected.ctrl = PpuCtrl(0b0000'0011);
expected.temp_vram_addr = PpuVram(0b00'1100'0001'1111);
expected.write_toggle = true;
 
@@ -380,7 +380,7 @@ TEST_F(PpuTest, increment_vram_addr_by_1_after_writing) {
}
 
TEST_F(PpuTest, increment_vram_addr_by_32_after_writing) {
registers.ctrl = expected.ctrl = 0x04;
registers.ctrl = expected.ctrl = PpuCtrl(0x04);
expected.vram_addr = PpuVram(0x20);
 
ppu->write_byte(0x2007, 0x05);
@@ -435,7 +435,7 @@ TEST_F(PpuTest, increment_vram_addr_by_1_after_reading) {
}
 
TEST_F(PpuTest, increment_vram_addr_by_32_after_reading) {
registers.ctrl = expected.ctrl = 0x04;
registers.ctrl = expected.ctrl = PpuCtrl(0x04);
expected.vram_addr = PpuVram(0x0020);
 
ppu->read_byte(0x2007);