summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHannes Schulze <haschu0103@outlook.de>2025-01-18 00:05:53 +0100
committerHannes Schulze <haschu0103@outlook.de>2025-01-18 00:05:53 +0100
commitd5a52cc491a222f1b7d33fa6789bed617ec6638b (patch)
treea1c849e94620eb2c132fbd1a61898ef51ce167ba
parent9d80b5b8a61bd8c2336f5032de8b84fea15d685f (diff)
cpu: bugfixes
-rw-r--r--src/CMakeLists.txt3
-rw-r--r--src/main.mm1
-rw-r--r--src/nes/cpu.cc35
-rw-r--r--src/nes/cpu.hh9
-rw-r--r--src/nes/mapper.cc12
-rw-r--r--src/nes/nes.cc16
-rw-r--r--src/nes/nes.hh4
-rw-r--r--src/nes/ppu.cc10
-rw-r--r--src/nes/ppu.hh12
-rw-r--r--src/nes/util/address.hh2
-rw-r--r--src/status.hh55
-rw-r--r--src/test/CMakeLists.txt0
-rw-r--r--src/test/main.cc3
13 files changed, 145 insertions, 17 deletions
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<addressing_mode::zero_page>(); break;
case 0x28: run_plp(); break;
case 0x29: run_and<addressing_mode::immediate>(); break;
- case 0x2A: run_rol<addressing_mode::absolute>(); break;
+ case 0x2A: run_rol<addressing_mode::accumulator>(); break;
case 0x2B: run_anc<addressing_mode::immediate>(); break;
case 0x2C: run_bit<addressing_mode::absolute>(); break;
case 0x2D: run_and<addressing_mode::absolute>(); break;
@@ -352,7 +371,7 @@ namespace nes
{
// ASL: Arithmetic Shift Left
auto operand = fetch_operand<Mode>();
- eval_asl(operand.read());
+ operand.write(eval_asl(operand.read()));
current_cycles_ += shift_cycle_count<Mode>();
}
@@ -613,7 +632,7 @@ namespace nes
template<cpu::addressing_mode Mode>
auto cpu::run_ahx() -> void
{
- // AHX: AND A X H
+ // AHX: ???
// TODO
std::abort();
}
@@ -694,7 +713,7 @@ namespace nes
template<cpu::addressing_mode Mode>
auto cpu::run_tas() -> void
{
- // TAS: S = A & X + AND S H
+ // TAS: ???
// TODO
std::abort();
}
@@ -702,7 +721,7 @@ namespace nes
template<cpu::addressing_mode Mode>
auto cpu::run_shy() -> void
{
- // SHY: AND Y H
+ // SHY: ???
// TODO
std::abort();
}
@@ -710,7 +729,7 @@ namespace nes
template<cpu::addressing_mode Mode>
auto cpu::run_shx() -> void
{
- // SHY: AND X H
+ // SHY: ???
// TODO
std::abort();
}
@@ -796,7 +815,7 @@ namespace nes
template<cpu::addressing_mode Mode>
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<addressing_mode::mode>() -> 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<std::uint16_t>((page << 8) | (offset < 0)) }
+ : address{ static_cast<std::uint16_t>((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 <vector>
+#include <cstdint>
+
+namespace test
+{
+ /// System status used for comparison.
+ struct status
+ {
+ explicit status() = default;
+
+ nes::cycle_count cpu_cycle;
+ std::vector<std::uint8_t> ram;
+ std::vector<std::uint8_t> 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
--- /dev/null
+++ b/src/test/CMakeLists.txt
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.
+//