srctree

Johan parent 6e85e388 cefba851 94b6daa5
Merge pull request #346 from johnor/move-cycle-scanline

Move cycle scanline
core/CMakeLists.txt added: 100, removed: 51, total 49
@@ -5,8 +5,8 @@ add_library(${PROJECT_NAME}
include/nes/core/icpu.h
include/nes/core/imembank.h
include/nes/core/immu.h
include/nes/core/ines_controller.h
include/nes/core/imos6502.h
include/nes/core/ines_controller.h
include/nes/core/ines_header.h
include/nes/core/invalid_address.h
include/nes/core/ippu.h
@@ -16,6 +16,7 @@ add_library(${PROJECT_NAME}
include/nes/core/nes_controller_factory.h
include/nes/core/opcode.h
include/nes/core/ppu_factory.h
include/nes/core/ppu_registers.h
include/nes/core/rom_factory.h
src/cpu_factory.cpp
src/invalid_address.cpp
@@ -27,10 +28,10 @@ add_library(${PROJECT_NAME}
src/mmu.cpp
src/mmu.h
src/mmu_factory.cpp
src/nes_controller.h
src/nes_controller_factory.cpp
src/mos6502.cpp
src/mos6502.h
src/nes_controller.h
src/nes_controller_factory.cpp
src/opcode.cpp
src/pipeline.cpp
src/pipeline.h
 
core/include/nes/core/ippu.h added: 100, removed: 51, total 49
@@ -3,18 +3,9 @@
#include <cstdint>
#include <functional>
 
namespace n_e_s::core {
#include "ppu_registers.h"
 
struct PpuRegisters {
uint8_t ctrl;
uint8_t mask;
uint8_t status;
uint8_t oamaddr;
uint8_t fine_x_scroll;
uint16_t vram_addr;
uint16_t temp_vram_addr;
bool write_toggle;
};
namespace n_e_s::core {
 
class IPpu {
public:
 
filename was Deleted added: 100, removed: 51, total 49
@@ -0,0 +1,24 @@
#pragma once
 
#include <cstdint>
 
namespace n_e_s::core {
 
struct PpuRegisters {
uint16_t scanline;
uint16_t cycle;
uint8_t ctrl;
uint8_t mask;
uint8_t status;
uint8_t oamaddr;
uint8_t fine_x_scroll;
uint16_t vram_addr;
uint16_t temp_vram_addr;
bool write_toggle;
 
[[nodiscard]] constexpr bool is_rendering_enabled() const {
return (mask & (1u << 3u)) || (mask & (1u << 4u));
}
};
 
} // namespace n_e_s::core
 
core/src/ppu.cpp added: 100, removed: 51, total 49
@@ -131,49 +131,53 @@ void Ppu::set_nmi_handler(const std::function<void()> &on_nmi) {
on_nmi_ = on_nmi;
}
uint16_t Ppu::scanline() const {
return scanline_;
return registers_->scanline;
}
 
uint16_t Ppu::cycle() const {
return cycle_;
return registers_->cycle;
}
uint16_t &Ppu::scanline() {
return registers_->scanline;
}
 
uint16_t &Ppu::cycle() {
return registers_->cycle;
}
 
void Ppu::update_counters() {
if (cycle_ == kLastCycleInScanline) {
cycle_ = 0;
if (scanline_ == kLastScanlineInFrame) {
scanline_ = 0;
if (cycle() == kLastCycleInScanline) {
cycle() = 0;
if (scanline() == kLastScanlineInFrame) {
scanline() = 0;
} else {
++scanline_;
++scanline();
}
} else {
++cycle_;
++cycle();
}
}
 
bool Ppu::is_pre_render_scanline() const {
return scanline_ == kPreRenderScanline;
return scanline() == kPreRenderScanline;
}
 
bool Ppu::is_visible_scanline() const {
// Visible scanlines starts at 0
return scanline_ <= kVisibleScanlineEnd;
return scanline() <= kVisibleScanlineEnd;
}
 
bool Ppu::is_post_render_scanline() const {
return scanline_ == kPostRenderScanline;
return scanline() == kPostRenderScanline;
}
 
bool Ppu::is_vblank_scanline() const {
return scanline_ >= kVBlankScanlineStart && scanline_ <= kVBlankScanlineEnd;
}
 
bool Ppu::is_rendering_enabled() const {
return (registers_->mask & (1u << 3u)) || (registers_->mask & (1u << 4u));
return scanline() >= kVBlankScanlineStart &&
scanline() <= kVBlankScanlineEnd;
}
 
bool Ppu::is_rendering_active() const {
return is_rendering_enabled() &&
return registers_->is_rendering_enabled() &&
(is_pre_render_scanline() || is_visible_scanline());
}
 
@@ -192,7 +196,7 @@ void Ppu::increment_vram_address() {
}
 
void Ppu::execute_pre_render_scanline() {
if (cycle_ == 1) {
if (cycle() == 1) {
clear_vblank_flag();
}
}
@@ -202,7 +206,7 @@ void Ppu::execute_visible_scanline() {}
void Ppu::execute_post_render_scanline() {}
 
void Ppu::execute_vblank_scanline() {
if (scanline_ == 241 && cycle_ == 1) {
if (scanline() == 241 && cycle() == 1) {
set_vblank_flag();
if (registers_->ctrl & (1u << 7u)) {
on_nmi_();
 
core/src/ppu.h added: 100, removed: 51, total 49
@@ -22,13 +22,14 @@ public:
uint16_t cycle() const override;
 
private:
uint16_t &scanline();
uint16_t &cycle();
 
PpuRegisters *const registers_;
IMmu *const mmu_;
 
std::function<void()> on_nmi_{[] {}};
 
uint16_t scanline_{0};
uint16_t cycle_{0};
uint8_t read_buffer_{0};
 
// Object Atribute Memory
@@ -43,9 +44,6 @@ private:
bool is_post_render_scanline() const;
bool is_vblank_scanline() const;
 
// Rendering is enabled if bit 3 or bit 4 is enabled in the mask register.
bool is_rendering_enabled() const;
 
// Rendering is active if rendering is enabled and the PPU is currently
// in pre render scanline or a visible scanline.
bool is_rendering_active() const;
 
core/test/CMakeLists.txt added: 100, removed: 51, total 49
@@ -32,6 +32,7 @@ add_executable(${PROJECT_NAME}
src/test_opcode.cpp
src/test_ppu.cpp
src/test_ppu_membank.cpp
src/test_ppu_registers.cpp
src/test_rom.cpp
)
 
 
core/test/src/ippu_helpers.cpp added: 100, removed: 51, total 49
@@ -6,9 +6,10 @@
namespace n_e_s::core {
 
bool operator==(const PpuRegisters &a, const PpuRegisters &b) {
return a.ctrl == b.ctrl && a.mask == b.mask && a.status == b.status &&
a.oamaddr == b.oamaddr && a.fine_x_scroll == b.fine_x_scroll &&
a.vram_addr == b.vram_addr && a.temp_vram_addr == b.temp_vram_addr &&
return a.scanline == b.scanline && a.cycle == b.cycle && a.ctrl == b.ctrl &&
a.mask == b.mask && a.status == b.status && a.oamaddr == b.oamaddr &&
a.fine_x_scroll == b.fine_x_scroll && a.vram_addr == b.vram_addr &&
a.temp_vram_addr == b.temp_vram_addr &&
a.write_toggle == b.write_toggle;
}
 
@@ -16,9 +17,12 @@ bool operator==(const PpuRegisters &a, const PpuRegisters &b) {
// NOLINTNEXTLINE(readability-identifier-naming)
void PrintTo(const PpuRegisters &r, std::ostream *os) {
*os << fmt::format(
"Ctrl: {:#04x} ScrollX: {:#04x} Mask: {:#04x} OamAddr: {:#04x} "
"Cycle: {} Scanline: {} Ctrl: {:#04x} ScrollX: {:#04x} Mask: "
"{:#04x} OamAddr: {:#04x} "
"Status: {:#04x} VramAddr: {:#06x} TmpVramAddr: {:#06x} "
"WriteToggle: {}\n",
r.cycle,
r.scanline,
r.ctrl,
r.fine_x_scroll,
r.mask,
 
core/test/src/test_ppu.cpp added: 100, removed: 51, total 49
@@ -122,6 +122,8 @@ TEST_F(PpuTest, nmi_triggered_when_enabled_during_vblank) {
TEST_F(PpuTest, set_vblank_flag_during_vertical_blanking) {
registers.status = 0x00;
expected.status = 0x80;
expected.cycle = 2;
expected.scanline = 241;
 
// The VBlank flag is set at the second cycle of scanline 241
step_execution(kCyclesPerScanline * 241 + 2);
@@ -132,6 +134,8 @@ TEST_F(PpuTest, set_vblank_flag_during_vertical_blanking) {
TEST_F(PpuTest, clear_vblank_flag_during_pre_render_line) {
registers.status = 0x00;
expected.status = 0x00;
expected.cycle = 2;
expected.scanline = 261;
 
// The VBlank flag is cleared at the second cycle of scanline 261
step_execution(kCyclesPerScanline * 261 + 2);
@@ -192,6 +196,7 @@ TEST_F(PpuTest, ignore_oamdata_during_pre_render_scanline) {
expected.status = 0x80;
expected.mask = registers.mask;
expected.oamaddr = registers.oamaddr;
expected.scanline = 261;
 
step_execution(kCyclesPerScanline * 261);
 
@@ -211,6 +216,7 @@ TEST_F(PpuTest, write_to_oamdata_register_rendering_disabled) {
TEST_F(PpuTest, write_to_oamdata_register_during_vertical_blanking) {
expected.status = 0x80;
expected.oamaddr = 0x01;
expected.scanline = 250;
 
step_execution(kCyclesPerScanline * 250);
 
 
filename was Deleted added: 100, removed: 51, total 49
@@ -0,0 +1,20 @@
#include "nes/core/ppu_registers.h"
 
#include <gtest/gtest.h>
 
using namespace n_e_s::core;
 
namespace {
 
TEST(PpuRegisters, is_rendering_enabled_returns_true_for_bit_three_and_four) {
PpuRegisters r{};
EXPECT_FALSE(r.is_rendering_enabled());
 
r.mask = 0b0000'1000;
EXPECT_TRUE(r.is_rendering_enabled());
 
r.mask = 0b0001'0000;
EXPECT_TRUE(r.is_rendering_enabled());
}
 
} // namespace