summaryrefslogtreecommitdiff
path: root/src/nes
diff options
context:
space:
mode:
Diffstat (limited to 'src/nes')
-rw-r--r--src/nes/cpu.cc20
-rw-r--r--src/nes/cpu.hh6
-rw-r--r--src/nes/mapper.cc21
-rw-r--r--src/nes/mapper.hh3
-rw-r--r--src/nes/nes.cc32
-rw-r--r--src/nes/nes.hh2
-rw-r--r--src/nes/ppu.cc206
-rw-r--r--src/nes/ppu.hh19
-rw-r--r--src/nes/util/address.hh2
-rw-r--r--src/nes/util/cycle_count.hh2
10 files changed, 190 insertions, 123 deletions
diff --git a/src/nes/cpu.cc b/src/nes/cpu.cc
index b488a08..9060e72 100644
--- a/src/nes/cpu.cc
+++ b/src/nes/cpu.cc
@@ -45,14 +45,6 @@ namespace nes
nmi_pending_ = true;
}
- auto cpu::step_to(cycle_count const target) -> void
- {
- while (current_cycles_ < target)
- {
- step();
- }
- }
-
auto cpu::step() -> void
{
// See https://www.nesdev.org/wiki/CPU_unofficial_opcodes
@@ -400,8 +392,10 @@ namespace nes
auto cpu::run_anc() -> void
{
// ANC: AND #i + copy N to C
- // TODO
- std::abort();
+ auto operand = fetch_operand<Mode>();
+ eval_and(operand.read());
+ registers_.c = registers_.n;
+ current_cycles_ += operand.get_cycles();
}
template<cpu::addressing_mode Mode>
@@ -539,8 +533,10 @@ namespace nes
auto cpu::run_alr() -> void
{
// ALR: AND #i + LSR A
- // TODO
- std::abort();
+ auto operand = fetch_operand<Mode>();
+ eval_and(operand.read());
+ registers_.a = eval_lsr(registers_.a);
+ current_cycles_ += operand.get_cycles();
}
auto cpu::run_pha() -> void
diff --git a/src/nes/cpu.hh b/src/nes/cpu.hh
index 0614f76..fc3ef5b 100644
--- a/src/nes/cpu.hh
+++ b/src/nes/cpu.hh
@@ -134,9 +134,11 @@ namespace nes
auto snapshot(test::status&) -> void;
+ auto get_cycles() const -> cycle_count { return current_cycles_; }
auto stall_cycles(cycle_count) -> void;
auto trigger_nmi() -> void;
- auto step_to(cycle_count) -> void;
+ auto step() -> void;
+ auto is_nmi_pending() const -> bool { return nmi_pending_; } // XXX: Debugging
// Memory access
@@ -146,8 +148,6 @@ namespace nes
auto write16(address, std::uint16_t) -> void;
private:
- auto step() -> void;
-
// Instructions
#define DEFINE_SIMPLE_INSTRUCTION(name) \
diff --git a/src/nes/mapper.cc b/src/nes/mapper.cc
index aa9618e..5392d87 100644
--- a/src/nes/mapper.cc
+++ b/src/nes/mapper.cc
@@ -16,6 +16,11 @@ namespace nes
{
}
+ auto mapper::snapshot(test::status& snapshot) const -> void
+ {
+ snapshot.chrrom = std::vector(cartridge_.get_chr_rom(), cartridge_.get_chr_rom() + cartridge_.get_chr_rom_length());
+ }
+
auto mapper::select(cartridge& cartridge) -> mapper
{
switch (cartridge.get_mapper_number())
@@ -115,17 +120,17 @@ namespace nes
{
case name_table_arrangement::horizontal:
// $2000 = $2400, $2800 = $2c00
- if (rel <= 0x23FF) { return 0x000 + (rel % 0x400); }
- if (rel <= 0x27FF) { return 0x000 + (rel % 0x400); }
- if (rel <= 0x2BFF) { return 0x400 + (rel % 0x400); }
- if (rel <= 0x2FFF) { return 0x400 + (rel % 0x400); }
+ if (rel <= 0x3FF) { return 0x000 + (rel % 0x400); }
+ if (rel <= 0x7FF) { return 0x000 + (rel % 0x400); }
+ if (rel <= 0xBFF) { return 0x400 + (rel % 0x400); }
+ if (rel <= 0xFFF) { return 0x400 + (rel % 0x400); }
break;
case name_table_arrangement::vertical:
// $2000 = $2800, $2400 = $2c00
- if (rel <= 0x23FF) { return 0x000 + (rel % 0x400); }
- if (rel <= 0x27FF) { return 0x400 + (rel % 0x400); }
- if (rel <= 0x2BFF) { return 0x000 + (rel % 0x400); }
- if (rel <= 0x2FFF) { return 0x400 + (rel % 0x400); }
+ if (rel <= 0x3FF) { return 0x000 + (rel % 0x400); }
+ if (rel <= 0x7FF) { return 0x400 + (rel % 0x400); }
+ if (rel <= 0xBFF) { return 0x000 + (rel % 0x400); }
+ if (rel <= 0xFFF) { return 0x400 + (rel % 0x400); }
break;
}
diff --git a/src/nes/mapper.hh b/src/nes/mapper.hh
index f2873a6..12ad804 100644
--- a/src/nes/mapper.hh
+++ b/src/nes/mapper.hh
@@ -1,6 +1,7 @@
#pragma once
#include "nes/util/address.hh"
+#include "status.hh"
namespace nes
{
@@ -27,6 +28,8 @@ namespace nes
auto operator=(mapper const&) -> mapper& = delete;
auto operator=(mapper&&) -> mapper& = delete;
+ auto snapshot(test::status&) const -> void;
+
auto read_cpu(address const addr) -> std::uint8_t
{
return (this->*read_cpu_)(addr);
diff --git a/src/nes/nes.cc b/src/nes/nes.cc
index 3ed7a22..7ac1887 100644
--- a/src/nes/nes.cc
+++ b/src/nes/nes.cc
@@ -32,8 +32,34 @@ namespace nes
auto nes::step(cycle_count const delta) -> void
{
current_cycles_ += delta;
- cpu_.step_to(current_cycles_);
- ppu_.step_to(current_cycles_);
+ while (cpu_.get_cycles() < current_cycles_)
+ {
+ cpu_.step();
+ while (ppu_.get_cycles() < cpu_.get_cycles())
+ {
+ ppu_.step();
+ }
+ }
+ }
+
+ auto nes::step_to_nmi() -> void
+ {
+ while (cpu_.is_nmi_pending())
+ {
+ cpu_.step();
+ while (ppu_.get_cycles() < cpu_.get_cycles())
+ {
+ ppu_.step();
+ }
+ }
+ while (!cpu_.is_nmi_pending())
+ {
+ cpu_.step();
+ while (ppu_.get_cycles() < cpu_.get_cycles())
+ {
+ ppu_.step();
+ }
+ }
}
auto nes::snapshot() -> test::status
@@ -41,6 +67,8 @@ namespace nes
auto res = test::status{};
res.sram = std::vector(cartridge_.get_ram(), cartridge_.get_ram() + cartridge_.get_ram_length());
cpu_.snapshot(res);
+ ppu_.snapshot(res);
+ mapper_.snapshot(res);
return res;
}
} // namespace nes \ No newline at end of file
diff --git a/src/nes/nes.hh b/src/nes/nes.hh
index 16e645a..76c29ab 100644
--- a/src/nes/nes.hh
+++ b/src/nes/nes.hh
@@ -36,9 +36,11 @@ namespace nes
auto get_controller_1() -> controller& { return controller_1_; }
auto get_controller_2() const -> controller const& { return controller_2_; }
auto get_controller_2() -> controller& { return controller_2_; }
+ auto ref_operations() -> std::vector<test::memory_operation>& { return ppu_.memory_operations; }
auto step(std::chrono::microseconds delta) -> void;
auto step(cycle_count delta) -> void;
+ auto step_to_nmi() -> void; // XXX: Debugging
auto snapshot() -> test::status;
};
diff --git a/src/nes/ppu.cc b/src/nes/ppu.cc
index 29a5643..87c7f8d 100644
--- a/src/nes/ppu.cc
+++ b/src/nes/ppu.cc
@@ -4,6 +4,9 @@
#include "nes/mapper.hh"
#include "nes/util/address.hh"
#include "nes/util/rgb.hh"
+#include <iostream>
+
+// #define ENABLE_TRACES
namespace nes
{
@@ -14,12 +17,10 @@ namespace nes
{
}
- auto ppu::step_to(cycle_count const cycle) -> void
+ auto ppu::snapshot(test::status& snapshot) -> void
{
- while (current_cycles_ < cycle)
- {
- step();
- }
+ snapshot.vram = std::vector(std::begin(vram_), std::end(vram_));
+ snapshot.oam = std::vector(std::begin(oam_), std::end(oam_));
}
auto ppu::step() -> void
@@ -27,15 +28,6 @@ namespace nes
// See https://www.nesdev.org/wiki/PPU_rendering
// Based on: https://github.com/fogleman/nes/blob/master/nes/ppu.go
- if (nmi_delay_ > 0)
- {
- nmi_delay_ -= 1;
- if (nmi_delay_ == 0 && control_.vblank_nmi && status_.vblank)
- {
- cpu_.trigger_nmi();
- }
- }
-
auto const enable_rendering = mask_.enable_background || mask_.enable_sprites;
current_cycles_ += cycle_count::from_ppu(1);
@@ -160,24 +152,27 @@ namespace nes
if (mask_.enable_background)
{
auto const tile_data = static_cast<std::uint32_t>(tile_data_ >> 32);
- background_color = color_index{ (tile_data >> ((7 - internal_.x) * 4)) & 0xF };
+ background_color = color_index{ static_cast<std::uint8_t>((tile_data >> ((7 - internal_.x) * 4)) & 0xF) };
background_color.role = role::background;
}
auto foreground = sprite{};
auto foreground_color = color_index{ 0 };
- for (auto i = unsigned{ 0 }; i < sprite_count_; ++i)
+ if (mask_.enable_sprites)
{
- auto const s = sprites_[i];
- auto const offset = static_cast<int>(x) - static_cast<int>(s.position);
- if (offset < 0 || offset > 7) { continue; }
- auto const color = color_index{ (s.pattern >> ((7 - offset) * 4)) & 0xF };
- if (color.color == 0) { continue; }
+ for (auto i = unsigned{ 0 }; i < sprite_count_; ++i)
+ {
+ auto const s = sprites_[i];
+ auto const offset = static_cast<int>(x) - static_cast<int>(s.position);
+ if (offset < 0 || offset > 7) { continue; }
+ auto const color = color_index{ static_cast<std::uint8_t>((s.pattern >> ((7 - offset) * 4)) & 0xF) };
+ if (color.color == 0) { continue; }
- foreground = s;
- foreground_color = color;
- foreground_color.role = role::sprite;
- break;
+ foreground = s;
+ foreground_color = color;
+ foreground_color.role = role::sprite;
+ break;
+ }
}
auto has_background = background_color.color != 0;
@@ -341,7 +336,7 @@ namespace nes
sprites_[sprite_count_].position = x;
// TODO: Check
// sprites_[sprite_count_].is_in_front = a & 0b00100000;
- sprites_[sprite_count_].is_in_front = (a >> 5) & 1;
+ sprites_[sprite_count_].is_in_front = ((a >> 5) & 1) == 0;
sprites_[sprite_count_].is_sprite_zero = i == 0;
sprite_count_ += 1;
}
@@ -425,7 +420,7 @@ namespace nes
if (addr <= address{ 0x3EFF }) { return mapper_.read_ppu(addr, vram_); }
if (addr <= address{ 0x3FFF })
{
- auto const index = color_index{ addr.get_absolute() };
+ auto const index = color_index{ static_cast<std::uint8_t>(addr.get_absolute() % 0x20) };
auto const color = get_color(index);
return static_cast<std::uint8_t>(color);
}
@@ -443,7 +438,7 @@ namespace nes
}
if (addr <= address{ 0x3FFF })
{
- auto const index = color_index{ addr.get_absolute() };
+ auto const index = color_index{ static_cast<std::uint8_t>(addr.get_absolute() % 0x20) };
get_color(index) = color{ value };
return;
}
@@ -466,12 +461,15 @@ namespace nes
{
auto const base = latch_ & ~status_mask;
auto const res = base | (status_.value & status_mask);
+#ifdef ENABLE_TRACES
+ memory_operations.emplace_back(test::memory_operation::type::read_ppustatus, res, current_cycles_);
+#endif
status_.vblank = false;
internal_.w = false;
nmi_change();
- //write_latch(res);
+ write_latch(res);
return res;
}
@@ -482,6 +480,9 @@ namespace nes
{
res &= 0xE3;
}
+#ifdef ENABLE_TRACES
+ memory_operations.emplace_back(test::memory_operation::type::read_oamdata, res, current_cycles_);
+#endif
write_latch(res);
return res;
}
@@ -490,8 +491,9 @@ namespace nes
{
auto const addr = address{ internal_.v };
auto res = read8(addr);
+ write_latch(ppudata_read_buffer_);
- if (addr % 0x4000 <= address{ 0x3F00 })
+ if (addr % 0x4000 <= address{ 0x3EFF })
{
std::swap(res, ppudata_read_buffer_);
}
@@ -501,7 +503,9 @@ namespace nes
ppudata_read_buffer_ = read8(addr - 0x1000);
}
- write_latch(res);
+#ifdef ENABLE_TRACES
+ memory_operations.emplace_back(test::memory_operation::type::read_ppudata, res, current_cycles_);
+#endif
increment_vram();
return res;
}
@@ -513,20 +517,26 @@ namespace nes
auto ppu::write_ppuctrl(std::uint8_t const value) -> void
{
- write_latch(value);
if (current_cycles_ > boot_up_cycles)
{
+ write_latch(value);
control_.value = value;
internal_.t = (internal_.t & 0xF3FF) | ((value & 0x03) << 10);
+#ifdef ENABLE_TRACES
+ memory_operations.emplace_back(test::memory_operation::type::write_ppuctrl, value, current_cycles_);
+#endif
nmi_change();
}
}
auto ppu::write_ppuscroll(std::uint8_t const value) -> void
{
- write_latch(value);
if (current_cycles_ > boot_up_cycles)
{
+ write_latch(value);
+#ifdef ENABLE_TRACES
+ memory_operations.emplace_back(test::memory_operation::type::write_ppuscroll, value, current_cycles_);
+#endif
if (!internal_.w)
{
// First write -> x value.
@@ -546,18 +556,24 @@ namespace nes
auto ppu::write_ppumask(std::uint8_t const value) -> void
{
- write_latch(value);
if (current_cycles_ > boot_up_cycles)
{
+ write_latch(value);
+#ifdef ENABLE_TRACES
+ memory_operations.emplace_back(test::memory_operation::type::write_ppumask, value, current_cycles_);
+#endif
mask_.value = value;
}
}
auto ppu::write_ppuaddr(std::uint8_t const value) -> void
{
- write_latch(value);
if (current_cycles_ > boot_up_cycles)
{
+ write_latch(value);
+#ifdef ENABLE_TRACES
+ memory_operations.emplace_back(test::memory_operation::type::write_ppuaddr, value, current_cycles_);
+#endif
if (!internal_.w)
{
// First write.
@@ -576,6 +592,9 @@ namespace nes
auto ppu::write_ppudata(std::uint8_t const value) -> void
{
+#ifdef ENABLE_TRACES
+ memory_operations.emplace_back(test::memory_operation::type::write_ppudata, value, current_cycles_);
+#endif
write_latch(value);
write8(address{ internal_.v }, value);
increment_vram();
@@ -583,12 +602,18 @@ namespace nes
auto ppu::write_oamaddr(std::uint8_t const value) -> void
{
+#ifdef ENABLE_TRACES
+ memory_operations.emplace_back(test::memory_operation::type::write_oamaddr, value, current_cycles_);
+#endif
write_latch(value);
oamaddr_ = value;
}
auto ppu::write_oamdata(std::uint8_t const value) -> void
{
+#ifdef ENABLE_TRACES
+ memory_operations.emplace_back(test::memory_operation::type::write_oamdata, value, current_cycles_);
+#endif
write_latch(value);
oam_[oamaddr_] = value;
oamaddr_ += 1;
@@ -597,13 +622,18 @@ namespace nes
auto ppu::write_oamdma(std::uint8_t const value) -> void
{
// TODO: Do this in CPU::step instead in case there's an NMI?
- for (auto i = std::uint8_t{ 0x00 }; i < 0xff; ++i)
+#ifdef ENABLE_TRACES
+ memory_operations.emplace_back(test::memory_operation::type::write_oamdma, value, current_cycles_);
+#endif
+ auto addr = address{ value, 0x00 };
+ for (auto i = unsigned{ 0 }; i < 256; ++i)
{
- oam_[oamaddr_] = cpu_.read8(address{ value, i });
+ oam_[oamaddr_] = cpu_.read8(addr);
oamaddr_ += 1;
+ addr = addr + 1;
}
- auto const stalled_cycles = cycle_count::from_cpu((current_cycles_.to_ppu() % 2 == 0) ? 513 : 514);
+ auto const stalled_cycles = cycle_count::from_cpu((cpu_.get_cycles().to_cpu() % 2 == 0) ? 513 : 514);
cpu_.stall_cycles(stalled_cycles);
}
@@ -614,12 +644,10 @@ namespace nes
auto ppu::nmi_change() -> void
{
auto const should_trigger = control_.vblank_nmi && status_.vblank;
- if (!nmi_requested_ && should_trigger)
+ if (should_trigger)
{
- // TODO: HACK
- nmi_delay_ = 15;
+ cpu_.trigger_nmi();
}
- nmi_requested_ = should_trigger;
}
auto ppu::sprite_height() -> unsigned
@@ -666,66 +694,66 @@ namespace nes
switch (index & 0x3F)
{
case 0x00: return rgb::from_hex(0x666666);
- case 0x01: return rgb::from_hex(0x882A00);
- case 0x02: return rgb::from_hex(0xA71214);
- case 0x03: return rgb::from_hex(0xA4003B);
- case 0x04: return rgb::from_hex(0x7E005C);
- case 0x05: return rgb::from_hex(0x40006E);
- case 0x06: return rgb::from_hex(0x00066C);
- case 0x07: return rgb::from_hex(0x001D56);
- case 0x08: return rgb::from_hex(0x003533);
- case 0x09: return rgb::from_hex(0x00480B);
+ case 0x01: return rgb::from_hex(0x002A88);
+ case 0x02: return rgb::from_hex(0x1412A7);
+ case 0x03: return rgb::from_hex(0x3B00A4);
+ case 0x04: return rgb::from_hex(0x5C007E);
+ case 0x05: return rgb::from_hex(0x6E0040);
+ case 0x06: return rgb::from_hex(0x6C0600);
+ case 0x07: return rgb::from_hex(0x561D00);
+ case 0x08: return rgb::from_hex(0x333500);
+ case 0x09: return rgb::from_hex(0x0B4800);
case 0x0A: return rgb::from_hex(0x005200);
- case 0x0B: return rgb::from_hex(0x084F00);
- case 0x0C: return rgb::from_hex(0x4D4000);
+ case 0x0B: return rgb::from_hex(0x004F08);
+ case 0x0C: return rgb::from_hex(0x00404D);
case 0x0D: return rgb::from_hex(0x000000);
case 0x0E: return rgb::from_hex(0x000000);
case 0x0F: return rgb::from_hex(0x000000);
case 0x10: return rgb::from_hex(0xADADAD);
- case 0x11: return rgb::from_hex(0xD95F15);
- case 0x12: return rgb::from_hex(0xFF4042);
- case 0x13: return rgb::from_hex(0xFE2775);
- case 0x14: return rgb::from_hex(0xCC1AA0);
- case 0x15: return rgb::from_hex(0x7B1EB7);
- case 0x16: return rgb::from_hex(0x2031B5);
- case 0x17: return rgb::from_hex(0x004E99);
- case 0x18: return rgb::from_hex(0x006D6B);
- case 0x19: return rgb::from_hex(0x008738);
- case 0x1A: return rgb::from_hex(0x00930C);
- case 0x1B: return rgb::from_hex(0x328F00);
- case 0x1C: return rgb::from_hex(0x8D7C00);
+ case 0x11: return rgb::from_hex(0x155FD9);
+ case 0x12: return rgb::from_hex(0x4240FF);
+ case 0x13: return rgb::from_hex(0x7527FE);
+ case 0x14: return rgb::from_hex(0xA01ACC);
+ case 0x15: return rgb::from_hex(0xB71E7B);
+ case 0x16: return rgb::from_hex(0xB53120);
+ case 0x17: return rgb::from_hex(0x994E00);
+ case 0x18: return rgb::from_hex(0x6B6D00);
+ case 0x19: return rgb::from_hex(0x388700);
+ case 0x1A: return rgb::from_hex(0x0C9300);
+ case 0x1B: return rgb::from_hex(0x008F32);
+ case 0x1C: return rgb::from_hex(0x007C8D);
case 0x1D: return rgb::from_hex(0x000000);
case 0x1E: return rgb::from_hex(0x000000);
case 0x1F: return rgb::from_hex(0x000000);
case 0x20: return rgb::from_hex(0xFFFEFF);
- case 0x21: return rgb::from_hex(0xFFB064);
- case 0x22: return rgb::from_hex(0xFF9092);
- case 0x23: return rgb::from_hex(0xFF76C6);
- case 0x24: return rgb::from_hex(0xFF6AF3);
- case 0x25: return rgb::from_hex(0xCC6EFE);
- case 0x26: return rgb::from_hex(0x7081FE);
- case 0x27: return rgb::from_hex(0x229EEA);
- case 0x28: return rgb::from_hex(0x00BEBC);
- case 0x29: return rgb::from_hex(0x00D888);
- case 0x2A: return rgb::from_hex(0x30E45C);
- case 0x2B: return rgb::from_hex(0x82E045);
- case 0x2C: return rgb::from_hex(0xDECD48);
+ case 0x21: return rgb::from_hex(0x64B0FF);
+ case 0x22: return rgb::from_hex(0x9290FF);
+ case 0x23: return rgb::from_hex(0xC676FF);
+ case 0x24: return rgb::from_hex(0xF36AFF);
+ case 0x25: return rgb::from_hex(0xFE6ECC);
+ case 0x26: return rgb::from_hex(0xFE8170);
+ case 0x27: return rgb::from_hex(0xEA9E22);
+ case 0x28: return rgb::from_hex(0xBCBE00);
+ case 0x29: return rgb::from_hex(0x88D800);
+ case 0x2A: return rgb::from_hex(0x5CE430);
+ case 0x2B: return rgb::from_hex(0x45E082);
+ case 0x2C: return rgb::from_hex(0x48CDDE);
case 0x2D: return rgb::from_hex(0x4F4F4F);
case 0x2E: return rgb::from_hex(0x000000);
case 0x2F: return rgb::from_hex(0x000000);
case 0x30: return rgb::from_hex(0xFFFEFF);
- case 0x31: return rgb::from_hex(0xFFDFC0);
- case 0x32: return rgb::from_hex(0xFFD2D3);
- case 0x33: return rgb::from_hex(0xFFC8E8);
- case 0x34: return rgb::from_hex(0xFFC2FB);
- case 0x35: return rgb::from_hex(0xEAC4FE);
- case 0x36: return rgb::from_hex(0xC5CCFE);
- case 0x37: return rgb::from_hex(0xA5D8F7);
- case 0x38: return rgb::from_hex(0x94E5E4);
- case 0x39: return rgb::from_hex(0x96EFCF);
- case 0x3A: return rgb::from_hex(0xABF4BD);
- case 0x3B: return rgb::from_hex(0xCCF3B3);
- case 0x3C: return rgb::from_hex(0xF2EBB5);
+ case 0x31: return rgb::from_hex(0xC0DFFF);
+ case 0x32: return rgb::from_hex(0xD3D2FF);
+ case 0x33: return rgb::from_hex(0xE8C8FF);
+ case 0x34: return rgb::from_hex(0xFBC2FF);
+ case 0x35: return rgb::from_hex(0xFEC4EA);
+ case 0x36: return rgb::from_hex(0xFECCC5);
+ case 0x37: return rgb::from_hex(0xF7D8A5);
+ case 0x38: return rgb::from_hex(0xE4E594);
+ case 0x39: return rgb::from_hex(0xCFEF96);
+ case 0x3A: return rgb::from_hex(0xBDF4AB);
+ case 0x3B: return rgb::from_hex(0xB3F3CC);
+ case 0x3C: return rgb::from_hex(0xB5EBF2);
case 0x3D: return rgb::from_hex(0xB8B8B8);
case 0x3E: return rgb::from_hex(0x000000);
case 0x3F: return rgb::from_hex(0x000000);
diff --git a/src/nes/ppu.hh b/src/nes/ppu.hh
index 9bd6139..fff51de 100644
--- a/src/nes/ppu.hh
+++ b/src/nes/ppu.hh
@@ -1,6 +1,7 @@
#pragma once
#include "nes/util/cycle_count.hh"
+#include "status.hh"
namespace nes
{
@@ -19,19 +20,19 @@ namespace nes
// Writes to some registers are ignored until this clock cycle.
static constexpr auto boot_up_cycles = cycle_count::from_ppu(29658);
- enum class vram_increment
+ enum class vram_increment : unsigned
{
add_1_across = 0,
add_32_down = 1,
};
- enum class sprite_size
+ enum class sprite_size : unsigned
{
_8x8 = 0,
_8x16 = 1,
};
- enum class role
+ enum class role : unsigned
{
background = 0,
sprite = 1,
@@ -49,9 +50,9 @@ namespace nes
unsigned palette : 2;
role role : 1;
};
- unsigned value;
+ std::uint8_t value;
- explicit color_index(unsigned const value)
+ explicit color_index(std::uint8_t const value)
: value{ value }
{
}
@@ -147,7 +148,6 @@ namespace nes
std::uint8_t high_tile_byte_{ 0 };
sprite sprites_[8]{}; // Evaluated sprites.
unsigned sprite_count_{ 0 }; // Number of evaluated sprites in sprites_.
- unsigned nmi_delay_{ 0 }; // Delay until an NMI is requested if conditions still met.
bool nmi_requested_{ false };
public:
@@ -158,7 +158,11 @@ namespace nes
auto operator=(ppu const&) -> ppu& = delete;
auto operator=(ppu&&) -> ppu& = delete;
- auto step_to(cycle_count) -> void;
+ std::vector<test::memory_operation> memory_operations;
+
+ auto get_cycles() const -> cycle_count { return current_cycles_; }
+ auto snapshot(test::status&) -> void;
+ auto step() -> void;
// Memory access
@@ -183,7 +187,6 @@ namespace nes
auto write_oamdma(std::uint8_t) -> void;
private:
- auto step() -> void;
auto render_pixel() -> void;
auto fetch_name_table_byte() -> void;
auto fetch_attribute_table_byte() -> void;
diff --git a/src/nes/util/address.hh b/src/nes/util/address.hh
index 85a00ab..7987d07 100644
--- a/src/nes/util/address.hh
+++ b/src/nes/util/address.hh
@@ -66,7 +66,7 @@ namespace nes
return address{ static_cast<std::uint16_t>(a.get_absolute() - b) };
}
- constexpr auto operator%(address const a, std::uint16_t b) -> address
+ constexpr auto operator%(address const a, std::uint16_t const b) -> address
{
return address{ static_cast<std::uint16_t>(a.get_absolute() % b) };
}
diff --git a/src/nes/util/cycle_count.hh b/src/nes/util/cycle_count.hh
index f8039c2..8afd40a 100644
--- a/src/nes/util/cycle_count.hh
+++ b/src/nes/util/cycle_count.hh
@@ -11,6 +11,7 @@ namespace nes
class cycle_count
{
friend constexpr auto operator+(cycle_count, cycle_count) -> cycle_count;
+ friend constexpr auto operator-(cycle_count, cycle_count) -> cycle_count;
friend constexpr auto operator*(std::uint64_t, cycle_count) -> cycle_count;
friend constexpr auto operator*(cycle_count, std::uint64_t) -> cycle_count;
friend constexpr auto operator/(cycle_count, cycle_count) -> std::uint64_t;
@@ -79,6 +80,7 @@ namespace nes
constexpr auto operator<=(cycle_count const a, cycle_count const b) -> bool { return a.get_units() <= b.get_units(); }
constexpr auto operator>=(cycle_count const a, cycle_count const b) -> bool { return a.get_units() >= b.get_units(); }
constexpr auto operator+(cycle_count const a, cycle_count const b) -> cycle_count { return cycle_count{ a.get_units() + b.get_units() }; }
+ constexpr auto operator-(cycle_count const a, cycle_count const b) -> cycle_count { return cycle_count{ a.get_units() - b.get_units() }; }
constexpr auto operator*(std::uint64_t const a, cycle_count const b) -> cycle_count { return cycle_count{ a * b.get_units() }; }
constexpr auto operator*(cycle_count const a, std::uint64_t const b) -> cycle_count { return cycle_count{ a.get_units() * b }; }
constexpr auto operator/(cycle_count const a, cycle_count const b) -> std::uint64_t { return a.get_units() / b.get_units(); }