From d5a52cc491a222f1b7d33fa6789bed617ec6638b Mon Sep 17 00:00:00 2001 From: Hannes Schulze Date: Sat, 18 Jan 2025 00:05:53 +0100 Subject: cpu: bugfixes --- src/CMakeLists.txt | 3 +++ src/main.mm | 1 - src/nes/cpu.cc | 35 ++++++++++++++++++++++++------- src/nes/cpu.hh | 9 +++++--- src/nes/mapper.cc | 12 +++++++++-- src/nes/nes.cc | 16 +++++++++++++- src/nes/nes.hh | 4 ++++ src/nes/ppu.cc | 10 +++++++++ src/nes/ppu.hh | 12 ++++++++++- src/nes/util/address.hh | 2 +- src/status.hh | 55 +++++++++++++++++++++++++++++++++++++++++++++++++ src/test/CMakeLists.txt | 0 src/test/main.cc | 3 +++ 13 files changed, 145 insertions(+), 17 deletions(-) create mode 100644 src/status.hh create mode 100644 src/test/CMakeLists.txt create mode 100644 src/test/main.cc (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 68ba329..b997a1d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,9 +1,12 @@ add_subdirectory(nes) +#add_subdirectory(ref) +#add_subdirectory(test) target_sources( nes PRIVATE main.mm + status.hh scene.hh scene.mm) diff --git a/src/main.mm b/src/main.mm index 7543e0c..5ca7c5c 100644 --- a/src/main.mm +++ b/src/main.mm @@ -13,7 +13,6 @@ int main(int argc, char** argv) } auto filePath = [NSString stringWithUTF8String:argv[1]]; - //auto filePath = @"/Users/hannes/Documents/temp/nes-test-roms/nes_instr_test/rom_singles/01-implied.nes"; auto app = [NSApplication sharedApplication]; [app setActivationPolicy:NSApplicationActivationPolicyRegular]; diff --git a/src/nes/cpu.cc b/src/nes/cpu.cc index 277c05d..2a079cc 100644 --- a/src/nes/cpu.cc +++ b/src/nes/cpu.cc @@ -14,6 +14,25 @@ namespace nes registers_.pc = read16(address{ 0xFFFC }); } + auto cpu::snapshot(test::status& snapshot) -> void + { + snapshot.cpu_cycle = current_cycles_; + snapshot.ram = std::vector(std::begin(ram_), std::end(ram_)); + snapshot.registers.pc = registers_.pc; + snapshot.registers.sp = registers_.sp; + snapshot.registers.a = registers_.a; + snapshot.registers.x = registers_.x; + snapshot.registers.y = registers_.y; + snapshot.registers.p = registers_.p; + snapshot.registers.c = registers_.c; + snapshot.registers.z = registers_.z; + snapshot.registers.i = registers_.i; + snapshot.registers.d = registers_.d; + snapshot.registers.b = registers_.b; + snapshot.registers.v = registers_.v; + snapshot.registers.n = registers_.n; + } + auto cpu::step_to(cycle_count const target) -> void { while (current_cycles_ < target) @@ -71,7 +90,7 @@ namespace nes case 0x27: run_rla(); break; case 0x28: run_plp(); break; case 0x29: run_and(); break; - case 0x2A: run_rol(); break; + case 0x2A: run_rol(); break; case 0x2B: run_anc(); break; case 0x2C: run_bit(); break; case 0x2D: run_and(); break; @@ -352,7 +371,7 @@ namespace nes { // ASL: Arithmetic Shift Left auto operand = fetch_operand(); - eval_asl(operand.read()); + operand.write(eval_asl(operand.read())); current_cycles_ += shift_cycle_count(); } @@ -613,7 +632,7 @@ namespace nes template auto cpu::run_ahx() -> void { - // AHX: AND A X H + // AHX: ??? // TODO std::abort(); } @@ -694,7 +713,7 @@ namespace nes template auto cpu::run_tas() -> void { - // TAS: S = A & X + AND S H + // TAS: ??? // TODO std::abort(); } @@ -702,7 +721,7 @@ namespace nes template auto cpu::run_shy() -> void { - // SHY: AND Y H + // SHY: ??? // TODO std::abort(); } @@ -710,7 +729,7 @@ namespace nes template auto cpu::run_shx() -> void { - // SHY: AND X H + // SHY: ??? // TODO std::abort(); } @@ -796,7 +815,7 @@ namespace nes template auto cpu::run_las() -> void { - // LAS: AND S, store into A, X, S + // LAS: ??? // TODO std::abort(); } @@ -1055,7 +1074,7 @@ namespace nes registers_.a = new_val; registers_.c = tmp > 0xFF; - registers_.v = ((old_val ^ arg) & 0x80) == 0 && ((old_val ^ new_val) & 0x80) == 0; + registers_.v = ((old_val ^ arg) & 0x80) == 0 && ((old_val ^ new_val) & 0x80) != 0; update_alu_flags(registers_.a); } diff --git a/src/nes/cpu.hh b/src/nes/cpu.hh index 59f2db4..3587fd6 100644 --- a/src/nes/cpu.hh +++ b/src/nes/cpu.hh @@ -2,6 +2,7 @@ #include "nes/util/cycle_count.hh" #include "nes/util/address.hh" +#include "status.hh" namespace nes { @@ -114,7 +115,7 @@ namespace nes bool i : 1; // interrupt inhibit bool d : 1; // decimal bool b : 1; // break - bool _ : 1; // (unused, always true) + bool : 1; // (unused, always true) bool v : 1; // overflow bool n : 1; // negative }; @@ -130,6 +131,8 @@ namespace nes auto operator=(cpu const&) -> cpu& = delete; auto operator=(cpu&&) -> cpu& = delete; + auto snapshot(test::status&) -> void; + auto step_to(cycle_count) -> void; private: @@ -251,8 +254,8 @@ namespace nes template<> auto name##_cycle_count() -> cycle_count { return cycle_count::from_cpu(value); } DEFINE_CYCLE_COUNT(jump) - DEFINE_CYCLE_COUNT_INSTANCE(jump, absolute, 2) - DEFINE_CYCLE_COUNT_INSTANCE(jump, indirect, 2) + DEFINE_CYCLE_COUNT_INSTANCE(jump, absolute, 3) + DEFINE_CYCLE_COUNT_INSTANCE(jump, indirect, 5) DEFINE_CYCLE_COUNT(shift) DEFINE_CYCLE_COUNT_INSTANCE(shift, accumulator, 2) diff --git a/src/nes/mapper.cc b/src/nes/mapper.cc index a540dbf..a451e3a 100644 --- a/src/nes/mapper.cc +++ b/src/nes/mapper.cc @@ -27,9 +27,13 @@ namespace nes auto mapper::nrom_read(address const addr) -> std::uint8_t { + if (addr <= address{ 0x5FFF }) + { + return 0x0; + } if (addr <= address{ 0x7FFF }) { - return cartridge_.get_ram()[addr.get_absolute() % 0x2000]; + return cartridge_.get_ram()[addr.get_absolute() - 0x6000]; } if (addr <= address{ 0xBFFF }) { @@ -52,9 +56,13 @@ namespace nes auto mapper::nrom_write(address const addr, std::uint8_t const value) -> void { + if (addr <= address{ 0x5FFF }) + { + return; + } if (addr <= address{ 0x7FFF }) { - cartridge_.get_ram_mut()[addr.get_absolute() % 0x2000] = value; + cartridge_.get_ram_mut()[addr.get_absolute() - 0x6000] = value; } } diff --git a/src/nes/nes.cc b/src/nes/nes.cc index 0579735..84f3309 100644 --- a/src/nes/nes.cc +++ b/src/nes/nes.cc @@ -10,6 +10,7 @@ namespace nes : cartridge_{ std::move(cartridge) } , display_{ display } , mapper_{ mapper::select(cartridge_) } + , ppu_{ cpu_, mapper_ } , cpu_{ ppu_, mapper_, controller_1_, controller_2_ } { if (!cartridge_.is_valid()) @@ -24,7 +25,12 @@ namespace nes auto nes::step(std::chrono::microseconds const delta) -> void { - current_cycles_ += cycle_count::from_duration(delta); + step(cycle_count::from_duration(delta)); + } + + auto nes::step(cycle_count const delta) -> void + { + current_cycles_ += delta; cpu_.step_to(current_cycles_); ppu_.step_to(current_cycles_); @@ -32,4 +38,12 @@ namespace nes display_.clear(rgb{ animation_progress_, animation_progress_, animation_progress_ }); display_.switch_buffers(); } + + auto nes::snapshot() -> test::status + { + auto res = test::status{}; + res.sram = std::vector(cartridge_.get_ram(), cartridge_.get_ram() + cartridge_.get_ram_length()); + cpu_.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 be50bbb..2701f4b 100644 --- a/src/nes/nes.hh +++ b/src/nes/nes.hh @@ -6,6 +6,7 @@ #include "nes/cpu.hh" #include "nes/ppu.hh" #include "nes/mapper.hh" +#include "status.hh" namespace nes { @@ -38,5 +39,8 @@ namespace nes auto get_controller_2() -> controller& { return controller_2_; } auto step(std::chrono::microseconds delta) -> void; + auto step(cycle_count delta) -> void; + + auto snapshot() -> test::status; }; } // namespace nes \ No newline at end of file diff --git a/src/nes/ppu.cc b/src/nes/ppu.cc index c2ec439..302b395 100644 --- a/src/nes/ppu.cc +++ b/src/nes/ppu.cc @@ -2,7 +2,17 @@ namespace nes { + ppu::ppu(cpu& cpu, mapper& mapper) + : cpu_{ cpu } + , mapper_{ mapper } + { + } + auto ppu::step_to(cycle_count const cycle) -> void { + while (current_cycles_ < cycle) + { + current_cycles_ += cycle_count::from_ppu(1); + } } } // namespace nes \ No newline at end of file diff --git a/src/nes/ppu.hh b/src/nes/ppu.hh index edb7aba..8f116c7 100644 --- a/src/nes/ppu.hh +++ b/src/nes/ppu.hh @@ -4,10 +4,20 @@ namespace nes { + class cpu; + class mapper; + class ppu { + static constexpr auto vram_size = std::size_t{ 0x800 }; + + cycle_count current_cycles_; + cpu& cpu_; + mapper& mapper_; + std::uint8_t vram_[vram_size]{}; + public: - explicit ppu() = default; + explicit ppu(cpu& cpu, mapper& mapper); ppu(ppu const&) = delete; ppu(ppu&&) = delete; diff --git a/src/nes/util/address.hh b/src/nes/util/address.hh index 0161998..77ee76a 100644 --- a/src/nes/util/address.hh +++ b/src/nes/util/address.hh @@ -21,7 +21,7 @@ namespace nes /// Create an address from its page and offset combination. constexpr explicit address(std::uint8_t const page, std::uint8_t const offset) - : address{ static_cast((page << 8) | (offset < 0)) } + : address{ static_cast((page << 8) | (offset << 0)) } { } diff --git a/src/status.hh b/src/status.hh new file mode 100644 index 0000000..705ae6e --- /dev/null +++ b/src/status.hh @@ -0,0 +1,55 @@ +#pragma once + +#include "nes/util/cycle_count.hh" +#include +#include + +namespace test +{ + /// System status used for comparison. + struct status + { + explicit status() = default; + + nes::cycle_count cpu_cycle; + std::vector ram; + std::vector sram; + struct + { + std::uint16_t pc{}; + std::uint8_t sp{}; + std::uint8_t a{}; + std::uint8_t x{}; + std::uint8_t y{}; + std::uint8_t p{}; + bool c{}; + bool z{}; + bool i{}; + bool d{}; + bool b{}; + bool v{}; + bool n{}; + } registers{}; + + static auto equal(status const& a, status const& b) -> bool + { + if (a.cpu_cycle != b.cpu_cycle) { return false; } + if (a.ram != b.ram) { return false; } + if (a.sram != b.sram) { return false; } + if (a.registers.pc != b.registers.pc) { return false; } + if (a.registers.sp != b.registers.sp) { return false; } + if (a.registers.a != b.registers.a) { return false; } + if (a.registers.x != b.registers.x) { return false; } + if (a.registers.y != b.registers.y) { return false; } + if (a.registers.p != b.registers.p) { return false; } + if (a.registers.c != b.registers.c) { return false; } + if (a.registers.z != b.registers.z) { return false; } + if (a.registers.i != b.registers.i) { return false; } + if (a.registers.d != b.registers.d) { return false; } + if (a.registers.b != b.registers.b) { return false; } + if (a.registers.v != b.registers.v) { return false; } + if (a.registers.n != b.registers.n) { return false; } + return true; + } + }; +} // namespace test \ No newline at end of file diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/test/main.cc b/src/test/main.cc new file mode 100644 index 0000000..58e618d --- /dev/null +++ b/src/test/main.cc @@ -0,0 +1,3 @@ +// +// Created by Hannes Schulze on 17.01.25. +// -- cgit v1.3.1