From fe7243fdd14f6ef57033f9e70141aba970dba7ea Mon Sep 17 00:00:00 2001 From: Hannes Schulze Date: Sat, 18 Jan 2025 00:20:54 +0100 Subject: clean up cpu --- src/nes/cpu.cc | 88 ++++++++++++++++++++++++++++++++-------------------------- src/nes/cpu.hh | 76 ++++++++++++++++++++++++++------------------------ 2 files changed, 88 insertions(+), 76 deletions(-) (limited to 'src/nes') diff --git a/src/nes/cpu.cc b/src/nes/cpu.cc index 2a079cc..3e3c6b8 100644 --- a/src/nes/cpu.cc +++ b/src/nes/cpu.cc @@ -1,7 +1,6 @@ #include "nes/cpu.hh" #include "nes/controller.hh" #include "nes/mapper.hh" -#include namespace nes { @@ -510,7 +509,7 @@ namespace nes auto const new_val = static_cast(old_val >> 1); operand.write(new_val); registers_.c = (old_val & 0x1) != 0; - update_alu_flags(new_val); + update_zn(new_val); current_cycles_ += shift_cycle_count(); } @@ -602,7 +601,7 @@ namespace nes { // PLA: Pull Accumulator registers_.a = pop_stack8(); - update_alu_flags(registers_.a); + update_zn(registers_.a); current_cycles_ += cycle_count::from_cpu(4); } @@ -669,7 +668,7 @@ namespace nes { // DEY: Decrement Y Register registers_.y -= 1; - update_alu_flags(registers_.y); + update_zn(registers_.y); current_cycles_ += cycle_count::from_cpu(2); } @@ -677,7 +676,7 @@ namespace nes { // TXA: Transfer X to Accumulator registers_.a = registers_.x; - update_alu_flags(registers_.a); + update_zn(registers_.a); current_cycles_ += cycle_count::from_cpu(2); } @@ -699,7 +698,7 @@ namespace nes { // TYA: Transfer Y to Accumulator registers_.a = registers_.y; - update_alu_flags(registers_.a); + update_zn(registers_.a); current_cycles_ += cycle_count::from_cpu(2); } @@ -740,7 +739,7 @@ namespace nes // LDY: Load Y Register auto operand = fetch_operand(); registers_.y = operand.read(); - update_alu_flags(registers_.y); + update_zn(registers_.y); current_cycles_ += operand.get_cycles(); } @@ -750,7 +749,7 @@ namespace nes // LDA: Load Accumulator auto operand = fetch_operand(); registers_.a = operand.read(); - update_alu_flags(registers_.a); + update_zn(registers_.a); current_cycles_ += operand.get_cycles(); } @@ -760,7 +759,7 @@ namespace nes // LDX: Load X Register auto operand = fetch_operand(); registers_.x = operand.read(); - update_alu_flags(registers_.x); + update_zn(registers_.x); current_cycles_ += operand.get_cycles(); } @@ -770,7 +769,7 @@ namespace nes // LAX: LDA + TAX auto operand = fetch_operand(); registers_.x = registers_.a = operand.read(); - update_alu_flags(registers_.a); + update_zn(registers_.a); current_cycles_ += operand.get_cycles(); } @@ -778,7 +777,7 @@ namespace nes { // TAY: Transfer Accumulator to Y registers_.y = registers_.a; - update_alu_flags(registers_.y); + update_zn(registers_.y); current_cycles_ += cycle_count::from_cpu(2); } @@ -786,7 +785,7 @@ namespace nes { // TAX: Transfer Accumulator to X registers_.x = registers_.a; - update_alu_flags(registers_.x); + update_zn(registers_.x); current_cycles_ += cycle_count::from_cpu(2); } @@ -808,7 +807,7 @@ namespace nes { // TSX: Transfer Stack Pointer to X registers_.x = registers_.sp; - update_alu_flags(registers_.x); + update_zn(registers_.x); current_cycles_ += cycle_count::from_cpu(2); } @@ -865,7 +864,7 @@ namespace nes auto const old_val = read8(operand.get_address()); auto const new_val = static_cast(old_val - 1); write8(operand.get_address(), new_val); - update_alu_flags(new_val); + update_zn(new_val); current_cycles_ += inc_dec_cycle_count(); } @@ -873,7 +872,7 @@ namespace nes { // INY: Increment Y registers_.y += 1; - update_alu_flags(registers_.y); + update_zn(registers_.y); current_cycles_ += cycle_count::from_cpu(2); } @@ -881,7 +880,7 @@ namespace nes { // DEX: Decrement X Register registers_.x -= 1; - update_alu_flags(registers_.x); + update_zn(registers_.x); current_cycles_ += cycle_count::from_cpu(2); } @@ -936,7 +935,7 @@ namespace nes auto const old_val = read8(operand.get_address()); auto const new_val = static_cast(old_val + 1); write8(operand.get_address(), new_val); - update_alu_flags(new_val); + update_zn(new_val); current_cycles_ += inc_dec_cycle_count(); } @@ -944,7 +943,7 @@ namespace nes { // INX: Increment X registers_.x += 1; - update_alu_flags(registers_.x); + update_zn(registers_.x); current_cycles_ += cycle_count::from_cpu(2); } @@ -963,13 +962,9 @@ namespace nes } // ----------------------------------------------------------------------------------------------------------------- - // Operands + // Helpers // ----------------------------------------------------------------------------------------------------------------- - // - // See: https://www.nesdev.org/wiki/CPU_addressing_modes - // - auto cpu::advance_pc8() -> std::uint8_t { auto const val = read8(address{ registers_.pc }); @@ -1011,7 +1006,7 @@ namespace nes return static_cast((high << 8) | (low << 0)); } - auto cpu::update_alu_flags(std::uint8_t const value) -> void + auto cpu::update_zn(std::uint8_t const value) -> void { registers_.z = value == 0; registers_.n = (value & 0x80) != 0; @@ -1038,7 +1033,7 @@ namespace nes { auto const res = static_cast((registers_.c << 7) | (arg >> 1)); registers_.c = (arg & 0x1) != 0; - update_alu_flags(res); + update_zn(res); return res; } @@ -1046,7 +1041,7 @@ namespace nes { auto const res = static_cast((arg << 1) | (registers_.c ? 1 : 0)); registers_.c = (arg & 0x80) != 0; - update_alu_flags(res); + update_zn(res); return res; } @@ -1054,7 +1049,7 @@ namespace nes { auto const new_val = static_cast(arg << 1); registers_.c = (arg & 0x80) != 0; - update_alu_flags(new_val); + update_zn(new_val); return new_val; } @@ -1062,7 +1057,7 @@ namespace nes { auto const new_val = static_cast(arg >> 1); registers_.c = (arg & 0x01) != 0; - update_alu_flags(new_val); + update_zn(new_val); return new_val; } @@ -1075,30 +1070,30 @@ namespace nes registers_.a = new_val; registers_.c = tmp > 0xFF; registers_.v = ((old_val ^ arg) & 0x80) == 0 && ((old_val ^ new_val) & 0x80) != 0; - update_alu_flags(registers_.a); + update_zn(registers_.a); } auto cpu::eval_and(std::uint8_t const arg) -> void { registers_.a &= arg; - update_alu_flags(registers_.a); + update_zn(registers_.a); } auto cpu::eval_ora(std::uint8_t const arg) -> void { registers_.a |= arg; - update_alu_flags(registers_.a); + update_zn(registers_.a); } auto cpu::eval_eor(std::uint8_t const arg) -> void { registers_.a ^= arg; - update_alu_flags(registers_.a); + update_zn(registers_.a); } auto cpu::eval_cmp(std::uint8_t const a, std::uint8_t const b) -> void { - update_alu_flags(a - b); + update_zn(a - b); registers_.c = a >= b; } @@ -1110,6 +1105,15 @@ namespace nes (registers_.p & 0b00110000); } + + // ----------------------------------------------------------------------------------------------------------------- + // Operands + // ----------------------------------------------------------------------------------------------------------------- + + // + // See: https://www.nesdev.org/wiki/CPU_addressing_modes + // + template auto cpu::fetch_operand(force_page_crossing const force_page_crossing) -> operand { @@ -1135,7 +1139,8 @@ namespace nes auto const offset = static_cast(advance_pc8()); auto const base = address{ registers_.pc }; addr = address{ static_cast(registers_.pc + offset) }; - auto const page_crossing = base.get_page() != addr.get_page() || force_page_crossing == force_page_crossing::yes; + auto const page_crossing = + base.get_page() != addr.get_page() || force_page_crossing == force_page_crossing::yes; cycles = cycle_count::from_cpu(page_crossing ? 4 : 3); break; } @@ -1168,7 +1173,8 @@ namespace nes // PEEK(arg + X) auto const arg = address{ advance_pc16() }; addr = arg + registers_.x; - auto const page_crossing = addr.get_page() != arg.get_page() || force_page_crossing == force_page_crossing::yes; + auto const page_crossing = + addr.get_page() != arg.get_page() || force_page_crossing == force_page_crossing::yes; cycles = cycle_count::from_cpu(page_crossing ? 5 : 4); break; } @@ -1177,7 +1183,8 @@ namespace nes // PEEK(arg + Y) auto const arg = address{ advance_pc16() }; addr = arg + registers_.y; - auto const page_crossing = addr.get_page() != arg.get_page() || force_page_crossing == force_page_crossing::yes; + auto const page_crossing = + addr.get_page() != arg.get_page() || force_page_crossing == force_page_crossing::yes; cycles = cycle_count::from_cpu(page_crossing ? 5 : 4); break; } @@ -1199,7 +1206,8 @@ namespace nes auto const offset = read8(address{ 0x00, static_cast(arg) }); auto const base = address{ page, offset }; addr = base + registers_.y; - auto const page_crossing = addr.get_page() != base.get_page() || force_page_crossing == force_page_crossing::yes; + auto const page_crossing = + addr.get_page() != base.get_page() || force_page_crossing == force_page_crossing::yes; cycles = cycle_count::from_cpu(page_crossing ? 6 : 5); break; } @@ -1209,13 +1217,15 @@ namespace nes } template<> - auto cpu::fetch_operand(force_page_crossing) -> operand + auto cpu::fetch_operand(force_page_crossing) + -> operand { return operand{ *this }; } template<> - auto cpu::fetch_operand(force_page_crossing) -> operand + auto cpu::fetch_operand(force_page_crossing) + -> operand { return operand{ *this, advance_pc8() }; } diff --git a/src/nes/cpu.hh b/src/nes/cpu.hh index 3587fd6..28ac0d6 100644 --- a/src/nes/cpu.hh +++ b/src/nes/cpu.hh @@ -15,6 +15,38 @@ namespace nes static constexpr auto ram_size = std::size_t{ 0x800 }; static constexpr auto stack_offset = address{ 0x100 }; + cycle_count current_cycles_; + ppu& ppu_; + mapper& mapper_; + controller& controller_1_; + controller& controller_2_; + std::uint8_t ram_[ram_size]{}; + + // Registers + struct + { + std::uint16_t pc{ 0 }; + std::uint8_t sp{ 0xFD }; + std::uint8_t a{ 0 }; + std::uint8_t x{ 0 }; + std::uint8_t y{ 0 }; + union + { + struct + { + bool c : 1; // carry + bool z : 1; // zero + bool i : 1; // interrupt inhibit + bool d : 1; // decimal + bool b : 1; // break + bool : 1; // (unused, always true) + bool v : 1; // overflow + bool n : 1; // negative + }; + std::uint8_t p{ 0b00100100 }; // initially, set i = true + }; + } registers_{}; + enum class addressing_mode { accumulator, // A @@ -47,8 +79,8 @@ namespace nes public: explicit operand(cpu& cpu, address const address, cycle_count const cycles) : cpu_{ cpu } - , address_{ address } - , cycles_{ cycles } + , address_{ address } + , cycles_{ cycles } { } @@ -83,7 +115,7 @@ namespace nes public: explicit operand(cpu& cpu, std::uint8_t const value) : cpu_{ cpu } - , value_{ value } + , value_{ value } { } @@ -91,38 +123,6 @@ namespace nes auto get_cycles() -> cycle_count { return cycle_count::from_cpu(2); } }; - cycle_count current_cycles_; - ppu& ppu_; - mapper& mapper_; - controller& controller_1_; - controller& controller_2_; - std::uint8_t ram_[ram_size]{}; - - // Registers - struct - { - std::uint16_t pc{ 0 }; - std::uint8_t sp{ 0xFD }; - std::uint8_t a{ 0 }; - std::uint8_t x{ 0 }; - std::uint8_t y{ 0 }; - union - { - struct - { - bool c : 1; // carry - bool z : 1; // zero - bool i : 1; // interrupt inhibit - bool d : 1; // decimal - bool b : 1; // break - bool : 1; // (unused, always true) - bool v : 1; // overflow - bool n : 1; // negative - }; - std::uint8_t p{ 0b00100100 }; // initially, set i = true - }; - } registers_{}; - public: explicit cpu(ppu& ppu, mapper& mapper, controller& controller_1, controller& controller_2); @@ -225,7 +225,7 @@ namespace nes #undef DEFINE_SIMPLE_INSTRUCTION #undef DEFINE_OPERAND_INSTRUCTION - // Operands + // Helpers auto advance_pc8() -> std::uint8_t; auto advance_pc16() -> std::uint16_t; @@ -233,7 +233,7 @@ namespace nes auto push_stack16(std::uint16_t) -> void; auto pop_stack8() -> std::uint8_t; auto pop_stack16() -> std::uint16_t; - auto update_alu_flags(std::uint8_t value) -> void; + auto update_zn(std::uint8_t value) -> void; template auto branch(bool condition) -> void; @@ -248,6 +248,8 @@ namespace nes auto eval_cmp(std::uint8_t a, std::uint8_t b) -> void; auto eval_plp() -> void; + // Operands + #define DEFINE_CYCLE_COUNT(name) \ template static auto name##_cycle_count() -> cycle_count; #define DEFINE_CYCLE_COUNT_INSTANCE(name, mode, value) \ -- cgit v1.3.1