From 55c59e6164ee88983cb53bd3278dbe256d2e7db0 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 28 Oct 2025 12:55:52 -0400 Subject: [PATCH 1/8] Start hiding Flags implementation. --- .../Mac/Clock SignalTests/6502Mk2Tests.mm | 2 +- Processors/6502Mk2/Implementation/6502.hpp | 3 +- Processors/6502Mk2/Perform.hpp | 84 ++++++++-------- Processors/6502Mk2/Registers.hpp | 96 ++++++++++++++----- 4 files changed, 118 insertions(+), 67 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/6502Mk2Tests.mm b/OSBindings/Mac/Clock SignalTests/6502Mk2Tests.mm index acbc0004d..1b5ccfebd 100644 --- a/OSBindings/Mac/Clock SignalTests/6502Mk2Tests.mm +++ b/OSBindings/Mac/Clock SignalTests/6502Mk2Tests.mm @@ -169,7 +169,7 @@ void testExecution(NSDictionary *test, BusHandler &handler) { auto repeat_processor = make_processor(test, handler); const bool should_interrupt = instruction.operation != CPU::MOS6502Mk2::Operation::BRK && - repeat_processor.registers().flags.inverse_interrupt; + !repeat_processor.registers().flags.template get(); try { repeat_processor.run_for(Cycles(last_length - 1)); diff --git a/Processors/6502Mk2/Implementation/6502.hpp b/Processors/6502Mk2/Implementation/6502.hpp index 19e35053e..a60b349ac 100644 --- a/Processors/6502Mk2/Implementation/6502.hpp +++ b/Processors/6502Mk2/Implementation/6502.hpp @@ -42,8 +42,7 @@ void Processor::run_for(const Cycles cycles) { }; const auto check_interrupt = [&] { Storage::captured_interrupt_requests_ = - Storage::inputs_.interrupt_requests & - (Storage::registers_.flags.inverse_interrupt | ~InterruptRequest::IRQ); + Storage::inputs_.interrupt_requests & Storage::registers_.flags.interrupt_mask(); }; #define restore_point() (__COUNTER__ + int(ResumePoint::Max) + int(AddressingMode::Max)) diff --git a/Processors/6502Mk2/Perform.hpp b/Processors/6502Mk2/Perform.hpp index f1349608e..a6855798f 100644 --- a/Processors/6502Mk2/Perform.hpp +++ b/Processors/6502Mk2/Perform.hpp @@ -21,13 +21,13 @@ namespace Operations { template void ane(RegistersT ®isters, const uint8_t operand) { registers.a = (registers.a | 0xee) & operand & registers.x; - registers.flags.set_nz(registers.a); + registers.flags.template set(registers.a); } template void anc(RegistersT ®isters, const uint8_t operand) { registers.a &= operand; - registers.flags.set_nz(registers.a); + registers.flags.template set(registers.a); registers.flags.carry = registers.a >> 7; } @@ -37,8 +37,8 @@ void adc(RegistersT ®isters, const uint8_t operand) { registers.flags.carry = result < registers.a + registers.flags.carry; if(!has_decimal_mode(model) || !registers.flags.decimal) { - registers.flags.set_v(result, registers.a, operand); - registers.flags.set_nz(registers.a = result); + registers.flags.set_overflow(result, registers.a, operand); + registers.flags.template set(registers.a = result); return; } @@ -69,7 +69,7 @@ void adc(RegistersT ®isters, const uint8_t operand) { if constexpr (!is_65c02(model)) { registers.flags.negative_result = result; } - registers.flags.set_v(result, registers.a, operand); + registers.flags.set_overflow(result, registers.a, operand); // i.e. fix high nibble if there was carry out of bit 7 already, or if the // top nibble is too large (in which case there will be carry after the fix-up). @@ -80,7 +80,7 @@ void adc(RegistersT ®isters, const uint8_t operand) { registers.a = result; if constexpr (is_65c02(model)) { - registers.flags.set_nz(registers.a); + registers.flags.template set(registers.a); } } @@ -97,9 +97,9 @@ void sbc(RegistersT ®isters, const uint8_t operand) { // All flags are set based only on the decimal result. registers.flags.carry = result < registers.a + registers.flags.carry; if constexpr (!is_65c02(model)) { - registers.flags.set_nz(result); + registers.flags.template set(result); } - registers.flags.set_v(result, registers.a, operand_complement); + registers.flags.set_overflow(result, registers.a, operand_complement); // General SBC logic: // @@ -128,7 +128,7 @@ void sbc(RegistersT ®isters, const uint8_t operand) { registers.a = result; if constexpr (is_65c02(model)) { - registers.flags.set_nz(registers.a); + registers.flags.template set(registers.a); } } @@ -137,7 +137,7 @@ void arr(RegistersT ®isters, const uint8_t operand) { registers.a &= operand; const uint8_t unshifted_a = registers.a; registers.a = uint8_t((registers.a >> 1) | (registers.flags.carry << 7)); - registers.flags.set_nz(registers.a); + registers.flags.template set(registers.a); registers.flags.overflow = (registers.a^(registers.a << 1))&Flag::Overflow; if(registers.flags.decimal && has_decimal_mode(model)) { @@ -154,14 +154,14 @@ void sbx(RegistersT ®isters, const uint8_t operand) { registers.x &= registers.a; registers.flags.carry = operand <= registers.x; registers.x -= operand; - registers.flags.set_nz(registers.x); + registers.flags.template set(registers.x); } template void asl(RegistersT ®isters, uint8_t &operand) { registers.flags.carry = operand >> 7; operand <<= 1; - registers.flags.set_nz(operand); + registers.flags.template set(operand); } template @@ -169,14 +169,14 @@ void aso(RegistersT ®isters, uint8_t &operand) { registers.flags.carry = operand >> 7; operand <<= 1; registers.a |= operand; - registers.flags.set_nz(registers.a); + registers.flags.template set(registers.a); } template void rol(RegistersT ®isters, uint8_t &operand) { const uint8_t temp8 = uint8_t((operand << 1) | registers.flags.carry); registers.flags.carry = operand >> 7; - registers.flags.set_nz(operand = temp8); + registers.flags.template set(operand = temp8); } template @@ -185,14 +185,14 @@ void rla(RegistersT ®isters, uint8_t &operand) { registers.flags.carry = operand >> 7; operand = temp8; registers.a &= operand; - registers.flags.set_nz(registers.a); + registers.flags.template set(registers.a); } template void lsr(RegistersT ®isters, uint8_t &operand) { registers.flags.carry = operand & 1; operand >>= 1; - registers.flags.set_nz(operand); + registers.flags.template set(operand); } template @@ -200,7 +200,7 @@ void lse(RegistersT ®isters, uint8_t &operand) { registers.flags.carry = operand & 1; operand >>= 1; registers.a ^= operand; - registers.flags.set_nz(registers.a); + registers.flags.template set(registers.a); } template @@ -208,14 +208,14 @@ void asr(RegistersT ®isters, uint8_t &operand) { registers.a &= operand; registers.flags.carry = registers.a & 1; registers.a >>= 1; - registers.flags.set_nz(registers.a); + registers.flags.template set(registers.a); } template void ror(RegistersT ®isters, uint8_t &operand) { const uint8_t temp8 = uint8_t((operand >> 1) | (registers.flags.carry << 7)); registers.flags.carry = operand & 1; - registers.flags.set_nz(operand = temp8); + registers.flags.template set(operand = temp8); } template @@ -229,7 +229,7 @@ void rra(RegistersT ®isters, uint8_t &operand) { template void compare(RegistersT ®isters, const uint8_t lhs, const uint8_t rhs) { registers.flags.carry = rhs <= lhs; - registers.flags.set_nz(lhs - rhs); + registers.flags.template set(lhs - rhs); } template @@ -342,19 +342,19 @@ void perform( // MARK: - Bitwise logic. - case Operation::ORA: registers.flags.set_nz(registers.a |= operand); break; - case Operation::AND: registers.flags.set_nz(registers.a &= operand); break; - case Operation::EOR: registers.flags.set_nz(registers.a ^= operand); break; + case Operation::ORA: registers.flags.template set(registers.a |= operand); break; + case Operation::AND: registers.flags.template set(registers.a &= operand); break; + case Operation::EOR: registers.flags.template set(registers.a ^= operand); break; // MARK: - Loads and stores. - case Operation::LDA: registers.flags.set_nz(registers.a = operand); break; - case Operation::LDX: registers.flags.set_nz(registers.x = operand); break; - case Operation::LDY: registers.flags.set_nz(registers.y = operand); break; - case Operation::LAX: registers.flags.set_nz(registers.a = registers.x = operand); break; + case Operation::LDA: registers.flags.template set(registers.a = operand); break; + case Operation::LDX: registers.flags.template set(registers.x = operand); break; + case Operation::LDY: registers.flags.template set(registers.y = operand); break; + case Operation::LAX: registers.flags.template set(registers.a = registers.x = operand); break; case Operation::LXA: registers.a = registers.x = (registers.a | 0xee) & operand; - registers.flags.set_nz(registers.a); + registers.flags.template set(registers.a); break; case Operation::PLP: registers.flags = Flags(operand); break; @@ -377,28 +377,28 @@ void perform( case Operation::ANC: Operations::anc(registers, operand); break; case Operation::LAS: registers.a = registers.x = registers.s = registers.s & operand; - registers.flags.set_nz(registers.a); + registers.flags.template set(registers.a); break; // MARK: - Transfers. - case Operation::TXA: registers.flags.set_nz(registers.a = registers.x); break; - case Operation::TYA: registers.flags.set_nz(registers.a = registers.y); break; + case Operation::TXA: registers.flags.template set(registers.a = registers.x); break; + case Operation::TYA: registers.flags.template set(registers.a = registers.y); break; case Operation::TXS: registers.s = registers.x; break; - case Operation::TAY: registers.flags.set_nz(registers.y = registers.a); break; - case Operation::TAX: registers.flags.set_nz(registers.x = registers.a); break; - case Operation::TSX: registers.flags.set_nz(registers.x = registers.s); break; + case Operation::TAY: registers.flags.template set(registers.y = registers.a); break; + case Operation::TAX: registers.flags.template set(registers.x = registers.a); break; + case Operation::TSX: registers.flags.template set(registers.x = registers.s); break; // MARK: - Increments and decrements. - case Operation::INC: registers.flags.set_nz(++operand); break; - case Operation::DEC: registers.flags.set_nz(--operand); break; - case Operation::INA: registers.flags.set_nz(++registers.a); break; - case Operation::DEA: registers.flags.set_nz(--registers.a); break; - case Operation::INX: registers.flags.set_nz(++registers.x); break; - case Operation::DEX: registers.flags.set_nz(--registers.x); break; - case Operation::INY: registers.flags.set_nz(++registers.y); break; - case Operation::DEY: registers.flags.set_nz(--registers.y); break; + case Operation::INC: registers.flags.template set(++operand); break; + case Operation::DEC: registers.flags.template set(--operand); break; + case Operation::INA: registers.flags.template set(++registers.a); break; + case Operation::DEA: registers.flags.template set(--registers.a); break; + case Operation::INX: registers.flags.template set(++registers.x); break; + case Operation::DEX: registers.flags.template set(--registers.x); break; + case Operation::INY: registers.flags.template set(++registers.y); break; + case Operation::DEY: registers.flags.template set(--registers.y); break; // MARK: - Shifts and rolls. diff --git a/Processors/6502Mk2/Registers.hpp b/Processors/6502Mk2/Registers.hpp index 58c02e6a6..53da28193 100644 --- a/Processors/6502Mk2/Registers.hpp +++ b/Processors/6502Mk2/Registers.hpp @@ -37,7 +37,7 @@ enum class Register { the corresponding set. */ enum Flag: uint8_t { - Sign = 0b1000'0000, + Negative = 0b1000'0000, Overflow = 0b0100'0000, Always = 0b0010'0000, Break = 0b0001'0000, @@ -46,6 +46,12 @@ enum Flag: uint8_t { Zero = 0b0000'0010, Carry = 0b0000'0001, + // + // Psuedo-flags, for convenience setting and getting. + // + NegativeZero = 0b00, + InverseInterrupt = 0b11, + // // 65816 only. // @@ -53,36 +59,80 @@ enum Flag: uint8_t { IndexSize = Break, }; +constexpr bool is_stored(const Flag flag) { + switch(flag) { + case Flag::Negative: + case Flag::Overflow: + case Flag::Decimal: + case Flag::Interrupt: + case Flag::InverseInterrupt: + case Flag::Zero: + case Flag::Carry: + return true; + + default: + return false; + } +} + +constexpr bool is_settable(const Flag flag) { + switch(flag) { + case Flag::NegativeZero: return true; + default: return is_stored(flag); + } +} + struct Flags { - /// Sets N and Z flags per the 8-bit value @c value. - void set_nz(const uint8_t value) { - zero_result = negative_result = value; + template + requires(is_stored(flag)) + bool get() const { + switch(flag) { + default: __builtin_unreachable(); + case Flag::Negative: return negative_result & Flag::Negative; + case Flag::Overflow: return overflow; + case Flag::Decimal: return decimal; + case Flag::Interrupt: return !(inverse_interrupt & Flag::Interrupt); + case Flag::InverseInterrupt: return inverse_interrupt & Flag::Interrupt; + case Flag::Zero: return !zero_result; + case Flag::Carry: return carry & Flag::Carry; + } + return false; } - /// Sets N and Z flags per the 8- or 16-bit value @c value; @c shift should be 0 to indicate an 8-bit value or 8 to indicate a 16-bit value. - void set_nz(const uint16_t value, const int shift) { - negative_result = uint8_t(value >> shift); - zero_result = uint8_t(value | (value >> shift)); + /// Sets a flag based on an 8-bit ALU result. + template + requires(is_settable(flag)) + void set(const uint8_t result) { + switch(flag) { + default: __builtin_unreachable(); + + case Flag::Negative: negative_result = result; break; + case Flag::Overflow: overflow = result & Flag::Overflow; break; + case Flag::Decimal: decimal = result & Flag::Decimal; break; + case Flag::Interrupt: inverse_interrupt = uint8_t(~Flag::Interrupt) | uint8_t(~result); break; + case Flag::InverseInterrupt: inverse_interrupt = uint8_t(~Flag::Interrupt) | result; break; + case Flag::Zero: zero_result = result; break; + case Flag::Carry: carry = result & Flag::Carry; break; + case Flag::NegativeZero: zero_result = negative_result = result; break; + } } - /// Sets the Z flag per the 8- or 16-bit value @c value; @c shift should be 0 to indicate an 8-bit value or 8 to indicate a 16-bit value. - void set_z(const uint16_t value, const int shift) { - zero_result = uint8_t(value | (value >> shift)); + uint8_t carry_value() const { + return carry; } - /// Sets the N flag per the 8- or 16-bit value @c value; @c shift should be 0 to indicate an 8-bit value or 8 to indicate a 16-bit value. - void set_n(const uint16_t value, const int shift) { - negative_result = uint8_t(value >> shift); + uint8_t interrupt_mask() const { + return inverse_interrupt; } - void set_v(const uint8_t result, const uint8_t lhs, const uint8_t rhs) { + void set_overflow(const uint8_t result, const uint8_t lhs, const uint8_t rhs) { // TODO: can this be done lazily? overflow = (( (result^lhs) & (result^rhs) ) & 0x80) >> 1; } explicit operator uint8_t() const { return - carry | overflow | (inverse_interrupt ^ Flag::Interrupt) | (negative_result & 0x80) | + carry | overflow | ((~inverse_interrupt) & Flag::Interrupt) | (negative_result & 0x80) | (zero_result ? 0 : Flag::Zero) | Flag::Always | Flag::Break | decimal; } @@ -95,12 +145,14 @@ struct Flags { } Flags(const uint8_t flags) { - carry = flags & Flag::Carry; - negative_result = flags & Flag::Sign; - zero_result = (~flags) & Flag::Zero; - overflow = flags & Flag::Overflow; - inverse_interrupt = (~flags) & Flag::Interrupt; - decimal = flags & Flag::Decimal; + set(flags); + set(flags); + set((~flags) & Flag::Zero); + set(flags); + set(flags); + set(flags); + + assert((flags | Flag::Always | Flag::Break) == static_cast(*this)); } auto operator <=> (const Flags &rhs) const { From 5332bcd6b4a4f1ff47c0e7b5c3ab5434b6a19cf1 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 28 Oct 2025 17:32:10 -0400 Subject: [PATCH 2/8] Clarify set/get difference; make interrupt flag storage private. --- Processors/6502Mk2/Implementation/6502.hpp | 2 +- Processors/6502Mk2/Perform.hpp | 92 +++++++++++----------- Processors/6502Mk2/Registers.hpp | 21 +++-- 3 files changed, 61 insertions(+), 54 deletions(-) diff --git a/Processors/6502Mk2/Implementation/6502.hpp b/Processors/6502Mk2/Implementation/6502.hpp index a60b349ac..666a18617 100644 --- a/Processors/6502Mk2/Implementation/6502.hpp +++ b/Processors/6502Mk2/Implementation/6502.hpp @@ -111,7 +111,7 @@ void Processor::run_for(const Cycles cycles) { ) && registers.flags.decimal; }; const auto set_interrupt_flag = [&] { - registers.flags.inverse_interrupt = 0; + registers.flags.template set_per(0); if constexpr (is_65c02(model)) { registers.flags.decimal = 0; } diff --git a/Processors/6502Mk2/Perform.hpp b/Processors/6502Mk2/Perform.hpp index a6855798f..3c24b52f5 100644 --- a/Processors/6502Mk2/Perform.hpp +++ b/Processors/6502Mk2/Perform.hpp @@ -21,13 +21,13 @@ namespace Operations { template void ane(RegistersT ®isters, const uint8_t operand) { registers.a = (registers.a | 0xee) & operand & registers.x; - registers.flags.template set(registers.a); + registers.flags.template set_per(registers.a); } template void anc(RegistersT ®isters, const uint8_t operand) { registers.a &= operand; - registers.flags.template set(registers.a); + registers.flags.template set_per(registers.a); registers.flags.carry = registers.a >> 7; } @@ -38,7 +38,7 @@ void adc(RegistersT ®isters, const uint8_t operand) { if(!has_decimal_mode(model) || !registers.flags.decimal) { registers.flags.set_overflow(result, registers.a, operand); - registers.flags.template set(registers.a = result); + registers.flags.template set_per(registers.a = result); return; } @@ -80,7 +80,7 @@ void adc(RegistersT ®isters, const uint8_t operand) { registers.a = result; if constexpr (is_65c02(model)) { - registers.flags.template set(registers.a); + registers.flags.template set_per(registers.a); } } @@ -97,7 +97,7 @@ void sbc(RegistersT ®isters, const uint8_t operand) { // All flags are set based only on the decimal result. registers.flags.carry = result < registers.a + registers.flags.carry; if constexpr (!is_65c02(model)) { - registers.flags.template set(result); + registers.flags.template set_per(result); } registers.flags.set_overflow(result, registers.a, operand_complement); @@ -128,7 +128,7 @@ void sbc(RegistersT ®isters, const uint8_t operand) { registers.a = result; if constexpr (is_65c02(model)) { - registers.flags.template set(registers.a); + registers.flags.template set_per(registers.a); } } @@ -137,7 +137,7 @@ void arr(RegistersT ®isters, const uint8_t operand) { registers.a &= operand; const uint8_t unshifted_a = registers.a; registers.a = uint8_t((registers.a >> 1) | (registers.flags.carry << 7)); - registers.flags.template set(registers.a); + registers.flags.template set_per(registers.a); registers.flags.overflow = (registers.a^(registers.a << 1))&Flag::Overflow; if(registers.flags.decimal && has_decimal_mode(model)) { @@ -154,14 +154,14 @@ void sbx(RegistersT ®isters, const uint8_t operand) { registers.x &= registers.a; registers.flags.carry = operand <= registers.x; registers.x -= operand; - registers.flags.template set(registers.x); + registers.flags.template set_per(registers.x); } template void asl(RegistersT ®isters, uint8_t &operand) { registers.flags.carry = operand >> 7; operand <<= 1; - registers.flags.template set(operand); + registers.flags.template set_per(operand); } template @@ -169,14 +169,14 @@ void aso(RegistersT ®isters, uint8_t &operand) { registers.flags.carry = operand >> 7; operand <<= 1; registers.a |= operand; - registers.flags.template set(registers.a); + registers.flags.template set_per(registers.a); } template void rol(RegistersT ®isters, uint8_t &operand) { const uint8_t temp8 = uint8_t((operand << 1) | registers.flags.carry); registers.flags.carry = operand >> 7; - registers.flags.template set(operand = temp8); + registers.flags.template set_per(operand = temp8); } template @@ -185,14 +185,14 @@ void rla(RegistersT ®isters, uint8_t &operand) { registers.flags.carry = operand >> 7; operand = temp8; registers.a &= operand; - registers.flags.template set(registers.a); + registers.flags.template set_per(registers.a); } template void lsr(RegistersT ®isters, uint8_t &operand) { registers.flags.carry = operand & 1; operand >>= 1; - registers.flags.template set(operand); + registers.flags.template set_per(operand); } template @@ -200,7 +200,7 @@ void lse(RegistersT ®isters, uint8_t &operand) { registers.flags.carry = operand & 1; operand >>= 1; registers.a ^= operand; - registers.flags.template set(registers.a); + registers.flags.template set_per(registers.a); } template @@ -208,14 +208,14 @@ void asr(RegistersT ®isters, uint8_t &operand) { registers.a &= operand; registers.flags.carry = registers.a & 1; registers.a >>= 1; - registers.flags.template set(registers.a); + registers.flags.template set_per(registers.a); } template void ror(RegistersT ®isters, uint8_t &operand) { const uint8_t temp8 = uint8_t((operand >> 1) | (registers.flags.carry << 7)); registers.flags.carry = operand & 1; - registers.flags.template set(operand = temp8); + registers.flags.template set_per(operand = temp8); } template @@ -229,7 +229,7 @@ void rra(RegistersT ®isters, uint8_t &operand) { template void compare(RegistersT ®isters, const uint8_t lhs, const uint8_t rhs) { registers.flags.carry = rhs <= lhs; - registers.flags.template set(lhs - rhs); + registers.flags.template set_per(lhs - rhs); } template @@ -342,19 +342,19 @@ void perform( // MARK: - Bitwise logic. - case Operation::ORA: registers.flags.template set(registers.a |= operand); break; - case Operation::AND: registers.flags.template set(registers.a &= operand); break; - case Operation::EOR: registers.flags.template set(registers.a ^= operand); break; + case Operation::ORA: registers.flags.template set_per(registers.a |= operand); break; + case Operation::AND: registers.flags.template set_per(registers.a &= operand); break; + case Operation::EOR: registers.flags.template set_per(registers.a ^= operand); break; // MARK: - Loads and stores. - case Operation::LDA: registers.flags.template set(registers.a = operand); break; - case Operation::LDX: registers.flags.template set(registers.x = operand); break; - case Operation::LDY: registers.flags.template set(registers.y = operand); break; - case Operation::LAX: registers.flags.template set(registers.a = registers.x = operand); break; + case Operation::LDA: registers.flags.template set_per(registers.a = operand); break; + case Operation::LDX: registers.flags.template set_per(registers.x = operand); break; + case Operation::LDY: registers.flags.template set_per(registers.y = operand); break; + case Operation::LAX: registers.flags.template set_per(registers.a = registers.x = operand); break; case Operation::LXA: registers.a = registers.x = (registers.a | 0xee) & operand; - registers.flags.template set(registers.a); + registers.flags.template set_per(registers.a); break; case Operation::PLP: registers.flags = Flags(operand); break; @@ -365,40 +365,40 @@ void perform( case Operation::SAX: operand = registers.a & registers.x; break; case Operation::PHP: operand = static_cast(registers.flags) | Flag::Break; break; - case Operation::CLC: registers.flags.carry = 0; break; - case Operation::CLI: registers.flags.inverse_interrupt = Flag::Interrupt; break; - case Operation::CLV: registers.flags.overflow = 0; break; - case Operation::CLD: registers.flags.decimal = 0; break; - case Operation::SEC: registers.flags.carry = Flag::Carry; break; - case Operation::SEI: registers.flags.inverse_interrupt = 0; break; - case Operation::SED: registers.flags.decimal = Flag::Decimal; break; + case Operation::CLC: registers.flags.carry = 0; break; + case Operation::CLI: registers.flags.template set_per(0); break; + case Operation::CLV: registers.flags.overflow = 0; break; + case Operation::CLD: registers.flags.decimal = 0; break; + case Operation::SEC: registers.flags.carry = Flag::Carry; break; + case Operation::SEI: registers.flags.template set_per(Flag::Interrupt); break; + case Operation::SED: registers.flags.decimal = Flag::Decimal; break; case Operation::ANE: Operations::ane(registers, operand); break; case Operation::ANC: Operations::anc(registers, operand); break; case Operation::LAS: registers.a = registers.x = registers.s = registers.s & operand; - registers.flags.template set(registers.a); + registers.flags.template set_per(registers.a); break; // MARK: - Transfers. - case Operation::TXA: registers.flags.template set(registers.a = registers.x); break; - case Operation::TYA: registers.flags.template set(registers.a = registers.y); break; + case Operation::TXA: registers.flags.template set_per(registers.a = registers.x); break; + case Operation::TYA: registers.flags.template set_per(registers.a = registers.y); break; case Operation::TXS: registers.s = registers.x; break; - case Operation::TAY: registers.flags.template set(registers.y = registers.a); break; - case Operation::TAX: registers.flags.template set(registers.x = registers.a); break; - case Operation::TSX: registers.flags.template set(registers.x = registers.s); break; + case Operation::TAY: registers.flags.template set_per(registers.y = registers.a); break; + case Operation::TAX: registers.flags.template set_per(registers.x = registers.a); break; + case Operation::TSX: registers.flags.template set_per(registers.x = registers.s); break; // MARK: - Increments and decrements. - case Operation::INC: registers.flags.template set(++operand); break; - case Operation::DEC: registers.flags.template set(--operand); break; - case Operation::INA: registers.flags.template set(++registers.a); break; - case Operation::DEA: registers.flags.template set(--registers.a); break; - case Operation::INX: registers.flags.template set(++registers.x); break; - case Operation::DEX: registers.flags.template set(--registers.x); break; - case Operation::INY: registers.flags.template set(++registers.y); break; - case Operation::DEY: registers.flags.template set(--registers.y); break; + case Operation::INC: registers.flags.template set_per(++operand); break; + case Operation::DEC: registers.flags.template set_per(--operand); break; + case Operation::INA: registers.flags.template set_per(++registers.a); break; + case Operation::DEA: registers.flags.template set_per(--registers.a); break; + case Operation::INX: registers.flags.template set_per(++registers.x); break; + case Operation::DEX: registers.flags.template set_per(--registers.x); break; + case Operation::INY: registers.flags.template set_per(++registers.y); break; + case Operation::DEY: registers.flags.template set_per(--registers.y); break; // MARK: - Shifts and rolls. diff --git a/Processors/6502Mk2/Registers.hpp b/Processors/6502Mk2/Registers.hpp index 53da28193..a1acfe99a 100644 --- a/Processors/6502Mk2/Registers.hpp +++ b/Processors/6502Mk2/Registers.hpp @@ -102,7 +102,7 @@ struct Flags { /// Sets a flag based on an 8-bit ALU result. template requires(is_settable(flag)) - void set(const uint8_t result) { + void set_per(const uint8_t result) { switch(flag) { default: __builtin_unreachable(); @@ -117,6 +117,12 @@ struct Flags { } } + template + requires(is_settable(flag)) + void set(const bool result) { + set_per(result ? 0xff : 0x00); + } + uint8_t carry_value() const { return carry; } @@ -145,12 +151,12 @@ struct Flags { } Flags(const uint8_t flags) { - set(flags); - set(flags); - set((~flags) & Flag::Zero); - set(flags); - set(flags); - set(flags); + set_per(flags); + set_per(flags); + set_per((~flags) & Flag::Zero); + set_per(flags); + set_per(flags); + set_per(flags); assert((flags | Flag::Always | Flag::Break) == static_cast(*this)); } @@ -164,6 +170,7 @@ struct Flags { uint8_t carry = 0; /// Contains Flag::Carry. uint8_t decimal = 0; /// Contains Flag::Decimal. uint8_t overflow = 0; /// Contains Flag::Overflow. +private: uint8_t inverse_interrupt = 0; /// Contains Flag::Interrupt, complemented. }; From 332fb2f384d483d8280b373b9cfae9de4f9d3dbb Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 28 Oct 2025 17:34:31 -0400 Subject: [PATCH 3/8] Make decimal flag private. --- Processors/6502Mk2/Implementation/6502.hpp | 2 +- Processors/6502Mk2/Perform.hpp | 10 +++++----- Processors/6502Mk2/Registers.hpp | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Processors/6502Mk2/Implementation/6502.hpp b/Processors/6502Mk2/Implementation/6502.hpp index 666a18617..593f8e89c 100644 --- a/Processors/6502Mk2/Implementation/6502.hpp +++ b/Processors/6502Mk2/Implementation/6502.hpp @@ -108,7 +108,7 @@ void Processor::run_for(const Cycles cycles) { ( Storage::decoded_.operation == Operation::ADC || Storage::decoded_.operation == Operation::SBC - ) && registers.flags.decimal; + ) && registers.flags.template get(); }; const auto set_interrupt_flag = [&] { registers.flags.template set_per(0); diff --git a/Processors/6502Mk2/Perform.hpp b/Processors/6502Mk2/Perform.hpp index 3c24b52f5..634eefc03 100644 --- a/Processors/6502Mk2/Perform.hpp +++ b/Processors/6502Mk2/Perform.hpp @@ -36,7 +36,7 @@ void adc(RegistersT ®isters, const uint8_t operand) { uint8_t result = registers.a + operand + registers.flags.carry; registers.flags.carry = result < registers.a + registers.flags.carry; - if(!has_decimal_mode(model) || !registers.flags.decimal) { + if(!has_decimal_mode(model) || !registers.flags.template get()) { registers.flags.set_overflow(result, registers.a, operand); registers.flags.template set_per(registers.a = result); return; @@ -86,7 +86,7 @@ void adc(RegistersT ®isters, const uint8_t operand) { template void sbc(RegistersT ®isters, const uint8_t operand) { - if(!has_decimal_mode(model) || !registers.flags.decimal) { + if(!has_decimal_mode(model) || !registers.flags.template get()) { adc(registers, ~operand); // Lie about the model to carry forward the fact of not-decimal. return; } @@ -140,7 +140,7 @@ void arr(RegistersT ®isters, const uint8_t operand) { registers.flags.template set_per(registers.a); registers.flags.overflow = (registers.a^(registers.a << 1))&Flag::Overflow; - if(registers.flags.decimal && has_decimal_mode(model)) { + if(registers.flags.template get() && has_decimal_mode(model)) { if((unshifted_a&0xf) + (unshifted_a&0x1) > 5) registers.a = ((registers.a + 6)&0xf) | (registers.a & 0xf0); registers.flags.carry = ((unshifted_a&0xf0) + (unshifted_a&0x10) > 0x50) ? 1 : 0; if(registers.flags.carry) registers.a += 0x60; @@ -368,10 +368,10 @@ void perform( case Operation::CLC: registers.flags.carry = 0; break; case Operation::CLI: registers.flags.template set_per(0); break; case Operation::CLV: registers.flags.overflow = 0; break; - case Operation::CLD: registers.flags.decimal = 0; break; + case Operation::CLD: registers.flags.template set_per(0); break; case Operation::SEC: registers.flags.carry = Flag::Carry; break; case Operation::SEI: registers.flags.template set_per(Flag::Interrupt); break; - case Operation::SED: registers.flags.decimal = Flag::Decimal; break; + case Operation::SED: registers.flags.template set_per(Flag::Decimal); break; case Operation::ANE: Operations::ane(registers, operand); break; case Operation::ANC: Operations::anc(registers, operand); break; diff --git a/Processors/6502Mk2/Registers.hpp b/Processors/6502Mk2/Registers.hpp index a1acfe99a..ad84c216d 100644 --- a/Processors/6502Mk2/Registers.hpp +++ b/Processors/6502Mk2/Registers.hpp @@ -168,9 +168,9 @@ struct Flags { uint8_t negative_result = 0; /// Bit 7 = the negative flag. uint8_t zero_result = 0; /// Non-zero if the zero flag is clear, zero if it is set. uint8_t carry = 0; /// Contains Flag::Carry. - uint8_t decimal = 0; /// Contains Flag::Decimal. uint8_t overflow = 0; /// Contains Flag::Overflow. private: + uint8_t decimal = 0; /// Contains Flag::Decimal. uint8_t inverse_interrupt = 0; /// Contains Flag::Interrupt, complemented. }; From e688d87c22e01dfcec49b44f065f6243ccd9f9b7 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 28 Oct 2025 18:23:16 -0400 Subject: [PATCH 4/8] Move negative and zero into private storage. --- .../Mac/Clock SignalTests/6502Mk2Tests.mm | 2 +- Processors/6502Mk2/Implementation/6502.hpp | 2 +- Processors/6502Mk2/Perform.hpp | 22 +++++++++---------- Processors/6502Mk2/Registers.hpp | 4 ++-- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/6502Mk2Tests.mm b/OSBindings/Mac/Clock SignalTests/6502Mk2Tests.mm index 1b5ccfebd..67c0deaa9 100644 --- a/OSBindings/Mac/Clock SignalTests/6502Mk2Tests.mm +++ b/OSBindings/Mac/Clock SignalTests/6502Mk2Tests.mm @@ -120,7 +120,7 @@ void testExecution(NSDictionary *test, BusHandler &handler) { instruction.operation == CPU::MOS6502Mk2::Operation::SBC ) && instruction.mode == CPU::MOS6502Mk2::AddressingMode::Immediate && - processor.registers().flags.decimal; + processor.registers().flags.template get(); ignore_addresses[3] = instruction.mode == CPU::MOS6502Mk2::AddressingMode::JMPAbsoluteIndexedIndirect; } diff --git a/Processors/6502Mk2/Implementation/6502.hpp b/Processors/6502Mk2/Implementation/6502.hpp index 593f8e89c..5c4b96243 100644 --- a/Processors/6502Mk2/Implementation/6502.hpp +++ b/Processors/6502Mk2/Implementation/6502.hpp @@ -113,7 +113,7 @@ void Processor::run_for(const Cycles cycles) { const auto set_interrupt_flag = [&] { registers.flags.template set_per(0); if constexpr (is_65c02(model)) { - registers.flags.decimal = 0; + registers.flags.template set_per(0); } }; diff --git a/Processors/6502Mk2/Perform.hpp b/Processors/6502Mk2/Perform.hpp index 634eefc03..bbd87626e 100644 --- a/Processors/6502Mk2/Perform.hpp +++ b/Processors/6502Mk2/Perform.hpp @@ -43,7 +43,7 @@ void adc(RegistersT ®isters, const uint8_t operand) { } if constexpr (!is_65c02(model)) { - registers.flags.zero_result = result; + registers.flags.template set_per(result); } // General ADC logic: @@ -67,7 +67,7 @@ void adc(RegistersT ®isters, const uint8_t operand) { // 6502 quirk: N and V are set before the full result is computed but // after the low nibble has been corrected. if constexpr (!is_65c02(model)) { - registers.flags.negative_result = result; + registers.flags.template set_per(result); } registers.flags.set_overflow(result, registers.a, operand); @@ -234,25 +234,25 @@ void compare(RegistersT ®isters, const uint8_t lhs, const uint8_t rhs) { template void bit(RegistersT ®isters, const uint8_t operand) { - registers.flags.zero_result = operand & registers.a; - registers.flags.negative_result = operand; + registers.flags.template set_per(operand & registers.a); + registers.flags.template set_per(operand); registers.flags.overflow = operand & Flag::Overflow; } template void bit_no_nv(RegistersT ®isters, const uint8_t operand) { - registers.flags.zero_result = operand & registers.a; + registers.flags.template set_per(operand & registers.a); } template void trb(RegistersT ®isters, uint8_t &operand) { - registers.flags.zero_result = operand & registers.a; + registers.flags.template set_per(operand & registers.a); operand &= ~registers.a; } template void tsb(RegistersT ®isters, uint8_t &operand) { - registers.flags.zero_result = operand & registers.a; + registers.flags.template set_per(operand & registers.a); operand |= registers.a; } @@ -309,14 +309,14 @@ bool test(const Operation operation, RegistersT ®isters) { default: __builtin_unreachable(); - case Operation::BPL: return !(registers.flags.negative_result & 0x80); - case Operation::BMI: return registers.flags.negative_result & 0x80; + case Operation::BPL: return !registers.flags.template get(); + case Operation::BMI: return registers.flags.template get(); case Operation::BVC: return !registers.flags.overflow; case Operation::BVS: return registers.flags.overflow; case Operation::BCC: return !registers.flags.carry; case Operation::BCS: return registers.flags.carry; - case Operation::BNE: return registers.flags.zero_result; - case Operation::BEQ: return !registers.flags.zero_result; + case Operation::BNE: return !registers.flags.template get(); + case Operation::BEQ: return registers.flags.template get(); case Operation::BRA: return true; } } diff --git a/Processors/6502Mk2/Registers.hpp b/Processors/6502Mk2/Registers.hpp index ad84c216d..61a843920 100644 --- a/Processors/6502Mk2/Registers.hpp +++ b/Processors/6502Mk2/Registers.hpp @@ -165,11 +165,11 @@ struct Flags { return static_cast(*this) <=> static_cast(rhs); } - uint8_t negative_result = 0; /// Bit 7 = the negative flag. - uint8_t zero_result = 0; /// Non-zero if the zero flag is clear, zero if it is set. uint8_t carry = 0; /// Contains Flag::Carry. uint8_t overflow = 0; /// Contains Flag::Overflow. private: + uint8_t negative_result = 0; /// Bit 7 = the negative flag. + uint8_t zero_result = 0; /// Non-zero if the zero flag is clear, zero if it is set. uint8_t decimal = 0; /// Contains Flag::Decimal. uint8_t inverse_interrupt = 0; /// Contains Flag::Interrupt, complemented. }; From b3f01fe31490ddaf03ee9f929cd9e8ae054a6844 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 28 Oct 2025 20:43:57 -0400 Subject: [PATCH 5/8] Move carry into private storage. --- Processors/6502Mk2/Perform.hpp | 68 +++++++++++++++++--------------- Processors/6502Mk2/Registers.hpp | 12 ++++-- 2 files changed, 44 insertions(+), 36 deletions(-) diff --git a/Processors/6502Mk2/Perform.hpp b/Processors/6502Mk2/Perform.hpp index bbd87626e..02d415a20 100644 --- a/Processors/6502Mk2/Perform.hpp +++ b/Processors/6502Mk2/Perform.hpp @@ -28,17 +28,18 @@ template void anc(RegistersT ®isters, const uint8_t operand) { registers.a &= operand; registers.flags.template set_per(registers.a); - registers.flags.carry = registers.a >> 7; + registers.flags.template set_per(registers.a >> 7); } template void adc(RegistersT ®isters, const uint8_t operand) { - uint8_t result = registers.a + operand + registers.flags.carry; - registers.flags.carry = result < registers.a + registers.flags.carry; + uint8_t result = registers.a + operand + registers.flags.carry_value(); + uint8_t carry = result < registers.a + registers.flags.carry_value(); if(!has_decimal_mode(model) || !registers.flags.template get()) { registers.flags.set_overflow(result, registers.a, operand); registers.flags.template set_per(registers.a = result); + registers.flags.template set_per(carry); return; } @@ -60,7 +61,7 @@ void adc(RegistersT ®isters, const uint8_t operand) { if(Numeric::carried_in<4>(registers.a, operand, result)) { result = (result & 0xf0) | ((result + 0x06) & 0x0f); } else if((result & 0xf) > 0x9) { - registers.flags.carry |= result >= 0x100 - 0x6; + carry |= result >= 0x100 - 0x6; result += 0x06; } @@ -73,12 +74,13 @@ void adc(RegistersT ®isters, const uint8_t operand) { // i.e. fix high nibble if there was carry out of bit 7 already, or if the // top nibble is too large (in which case there will be carry after the fix-up). - registers.flags.carry |= result >= 0xa0; - if(registers.flags.carry) { + carry |= result >= 0xa0; + if(carry) { result += 0x60; } registers.a = result; + registers.flags.template set_per(carry); if constexpr (is_65c02(model)) { registers.flags.template set_per(registers.a); } @@ -92,10 +94,10 @@ void sbc(RegistersT ®isters, const uint8_t operand) { } const uint8_t operand_complement = ~operand; - uint8_t result = registers.a + operand_complement + registers.flags.carry; + uint8_t result = registers.a + operand_complement + registers.flags.carry_value(); // All flags are set based only on the decimal result. - registers.flags.carry = result < registers.a + registers.flags.carry; + uint8_t carry = result < registers.a + registers.flags.carry_value(); if constexpr (!is_65c02(model)) { registers.flags.template set_per(result); } @@ -122,11 +124,12 @@ void sbc(RegistersT ®isters, const uint8_t operand) { } // The top nibble is adjusted only if there was borrow out of the whole byte. - if(!registers.flags.carry) { + if(!carry) { result += 0xa0; } registers.a = result; + registers.flags.template set_per(carry); if constexpr (is_65c02(model)) { registers.flags.template set_per(registers.a); } @@ -136,37 +139,38 @@ template void arr(RegistersT ®isters, const uint8_t operand) { registers.a &= operand; const uint8_t unshifted_a = registers.a; - registers.a = uint8_t((registers.a >> 1) | (registers.flags.carry << 7)); + registers.a = uint8_t((registers.a >> 1) | (registers.flags.carry_value() << 7)); registers.flags.template set_per(registers.a); registers.flags.overflow = (registers.a^(registers.a << 1))&Flag::Overflow; if(registers.flags.template get() && has_decimal_mode(model)) { if((unshifted_a&0xf) + (unshifted_a&0x1) > 5) registers.a = ((registers.a + 6)&0xf) | (registers.a & 0xf0); - registers.flags.carry = ((unshifted_a&0xf0) + (unshifted_a&0x10) > 0x50) ? 1 : 0; - if(registers.flags.carry) registers.a += 0x60; + const uint8_t carry = ((unshifted_a&0xf0) + (unshifted_a&0x10) > 0x50) ? 1 : 0; + if(carry) registers.a += 0x60; + registers.flags.template set_per(carry); } else { - registers.flags.carry = (registers.a >> 6)&1; + registers.flags.template set_per((registers.a >> 6)&1); } } template void sbx(RegistersT ®isters, const uint8_t operand) { registers.x &= registers.a; - registers.flags.carry = operand <= registers.x; + registers.flags.template set_per(operand <= registers.x); registers.x -= operand; registers.flags.template set_per(registers.x); } template void asl(RegistersT ®isters, uint8_t &operand) { - registers.flags.carry = operand >> 7; + registers.flags.template set_per(operand >> 7); operand <<= 1; registers.flags.template set_per(operand); } template void aso(RegistersT ®isters, uint8_t &operand) { - registers.flags.carry = operand >> 7; + registers.flags.template set_per(operand >> 7); operand <<= 1; registers.a |= operand; registers.flags.template set_per(registers.a); @@ -174,15 +178,15 @@ void aso(RegistersT ®isters, uint8_t &operand) { template void rol(RegistersT ®isters, uint8_t &operand) { - const uint8_t temp8 = uint8_t((operand << 1) | registers.flags.carry); - registers.flags.carry = operand >> 7; + const uint8_t temp8 = uint8_t((operand << 1) | registers.flags.carry_value()); + registers.flags.template set_per(operand >> 7); registers.flags.template set_per(operand = temp8); } template void rla(RegistersT ®isters, uint8_t &operand) { - const uint8_t temp8 = uint8_t((operand << 1) | registers.flags.carry); - registers.flags.carry = operand >> 7; + const uint8_t temp8 = uint8_t((operand << 1) | registers.flags.carry_value()); + registers.flags.template set_per(operand >> 7); operand = temp8; registers.a &= operand; registers.flags.template set_per(registers.a); @@ -190,14 +194,14 @@ void rla(RegistersT ®isters, uint8_t &operand) { template void lsr(RegistersT ®isters, uint8_t &operand) { - registers.flags.carry = operand & 1; + registers.flags.template set_per(operand & 1); operand >>= 1; registers.flags.template set_per(operand); } template void lse(RegistersT ®isters, uint8_t &operand) { - registers.flags.carry = operand & 1; + registers.flags.template set_per(operand & 1); operand >>= 1; registers.a ^= operand; registers.flags.template set_per(registers.a); @@ -206,29 +210,29 @@ void lse(RegistersT ®isters, uint8_t &operand) { template void asr(RegistersT ®isters, uint8_t &operand) { registers.a &= operand; - registers.flags.carry = registers.a & 1; + registers.flags.template set_per(registers.a & 1); registers.a >>= 1; registers.flags.template set_per(registers.a); } template void ror(RegistersT ®isters, uint8_t &operand) { - const uint8_t temp8 = uint8_t((operand >> 1) | (registers.flags.carry << 7)); - registers.flags.carry = operand & 1; + const uint8_t temp8 = uint8_t((operand >> 1) | (registers.flags.carry_value() << 7)); + registers.flags.template set_per(operand & 1); registers.flags.template set_per(operand = temp8); } template void rra(RegistersT ®isters, uint8_t &operand) { - const uint8_t temp8 = uint8_t((operand >> 1) | (registers.flags.carry << 7)); - registers.flags.carry = operand & 1; + const uint8_t temp8 = uint8_t((operand >> 1) | (registers.flags.carry_value() << 7)); + registers.flags.template set_per(operand & 1); Operations::adc(registers, temp8); operand = temp8; } template void compare(RegistersT ®isters, const uint8_t lhs, const uint8_t rhs) { - registers.flags.carry = rhs <= lhs; + registers.flags.template set_per(rhs <= lhs); registers.flags.template set_per(lhs - rhs); } @@ -313,8 +317,8 @@ bool test(const Operation operation, RegistersT ®isters) { case Operation::BMI: return registers.flags.template get(); case Operation::BVC: return !registers.flags.overflow; case Operation::BVS: return registers.flags.overflow; - case Operation::BCC: return !registers.flags.carry; - case Operation::BCS: return registers.flags.carry; + case Operation::BCC: return !registers.flags.template get(); + case Operation::BCS: return registers.flags.template get(); case Operation::BNE: return !registers.flags.template get(); case Operation::BEQ: return registers.flags.template get(); case Operation::BRA: return true; @@ -365,11 +369,11 @@ void perform( case Operation::SAX: operand = registers.a & registers.x; break; case Operation::PHP: operand = static_cast(registers.flags) | Flag::Break; break; - case Operation::CLC: registers.flags.carry = 0; break; + case Operation::CLC: registers.flags.template set_per(0); break; case Operation::CLI: registers.flags.template set_per(0); break; case Operation::CLV: registers.flags.overflow = 0; break; case Operation::CLD: registers.flags.template set_per(0); break; - case Operation::SEC: registers.flags.carry = Flag::Carry; break; + case Operation::SEC: registers.flags.template set_per(Flag::Carry); break; case Operation::SEI: registers.flags.template set_per(Flag::Interrupt); break; case Operation::SED: registers.flags.template set_per(Flag::Decimal); break; diff --git a/Processors/6502Mk2/Registers.hpp b/Processors/6502Mk2/Registers.hpp index 61a843920..2af0a4d92 100644 --- a/Processors/6502Mk2/Registers.hpp +++ b/Processors/6502Mk2/Registers.hpp @@ -8,6 +8,7 @@ #include "Numeric/RegisterSizes.hpp" +#include #include #pragma once @@ -112,7 +113,10 @@ struct Flags { case Flag::Interrupt: inverse_interrupt = uint8_t(~Flag::Interrupt) | uint8_t(~result); break; case Flag::InverseInterrupt: inverse_interrupt = uint8_t(~Flag::Interrupt) | result; break; case Flag::Zero: zero_result = result; break; - case Flag::Carry: carry = result & Flag::Carry; break; + case Flag::Carry: + assert(!(result & ~Flag::Carry)); + carry = result; + break; case Flag::NegativeZero: zero_result = negative_result = result; break; } } @@ -120,7 +124,7 @@ struct Flags { template requires(is_settable(flag)) void set(const bool result) { - set_per(result ? 0xff : 0x00); + set_per(result ? flag : 0x00); } uint8_t carry_value() const { @@ -151,7 +155,7 @@ struct Flags { } Flags(const uint8_t flags) { - set_per(flags); + set_per(flags & Flag::Carry); set_per(flags); set_per((~flags) & Flag::Zero); set_per(flags); @@ -165,9 +169,9 @@ struct Flags { return static_cast(*this) <=> static_cast(rhs); } - uint8_t carry = 0; /// Contains Flag::Carry. uint8_t overflow = 0; /// Contains Flag::Overflow. private: + uint8_t carry = 0; /// Contains Flag::Carry. uint8_t negative_result = 0; /// Bit 7 = the negative flag. uint8_t zero_result = 0; /// Non-zero if the zero flag is clear, zero if it is set. uint8_t decimal = 0; /// Contains Flag::Decimal. From 5aa9168dd681bed75c4c58a9d64eb325f970f85e Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 28 Oct 2025 20:49:59 -0400 Subject: [PATCH 6/8] Make overflow private. --- Processors/6502Mk2/Perform.hpp | 10 +++++----- Processors/6502Mk2/Registers.hpp | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Processors/6502Mk2/Perform.hpp b/Processors/6502Mk2/Perform.hpp index 02d415a20..f573b24cc 100644 --- a/Processors/6502Mk2/Perform.hpp +++ b/Processors/6502Mk2/Perform.hpp @@ -141,7 +141,7 @@ void arr(RegistersT ®isters, const uint8_t operand) { const uint8_t unshifted_a = registers.a; registers.a = uint8_t((registers.a >> 1) | (registers.flags.carry_value() << 7)); registers.flags.template set_per(registers.a); - registers.flags.overflow = (registers.a^(registers.a << 1))&Flag::Overflow; + registers.flags.template set_per(registers.a ^ (registers.a << 1)); if(registers.flags.template get() && has_decimal_mode(model)) { if((unshifted_a&0xf) + (unshifted_a&0x1) > 5) registers.a = ((registers.a + 6)&0xf) | (registers.a & 0xf0); @@ -240,7 +240,7 @@ template void bit(RegistersT ®isters, const uint8_t operand) { registers.flags.template set_per(operand & registers.a); registers.flags.template set_per(operand); - registers.flags.overflow = operand & Flag::Overflow; + registers.flags.template set_per(operand); } template @@ -315,8 +315,8 @@ bool test(const Operation operation, RegistersT ®isters) { case Operation::BPL: return !registers.flags.template get(); case Operation::BMI: return registers.flags.template get(); - case Operation::BVC: return !registers.flags.overflow; - case Operation::BVS: return registers.flags.overflow; + case Operation::BVC: return !registers.flags.template get(); + case Operation::BVS: return registers.flags.template get(); case Operation::BCC: return !registers.flags.template get(); case Operation::BCS: return registers.flags.template get(); case Operation::BNE: return !registers.flags.template get(); @@ -371,7 +371,7 @@ void perform( case Operation::CLC: registers.flags.template set_per(0); break; case Operation::CLI: registers.flags.template set_per(0); break; - case Operation::CLV: registers.flags.overflow = 0; break; + case Operation::CLV: registers.flags.template set_per(0); break; case Operation::CLD: registers.flags.template set_per(0); break; case Operation::SEC: registers.flags.template set_per(Flag::Carry); break; case Operation::SEI: registers.flags.template set_per(Flag::Interrupt); break; diff --git a/Processors/6502Mk2/Registers.hpp b/Processors/6502Mk2/Registers.hpp index 2af0a4d92..c48ba3987 100644 --- a/Processors/6502Mk2/Registers.hpp +++ b/Processors/6502Mk2/Registers.hpp @@ -169,8 +169,8 @@ struct Flags { return static_cast(*this) <=> static_cast(rhs); } - uint8_t overflow = 0; /// Contains Flag::Overflow. private: + uint8_t overflow = 0; /// Contains Flag::Overflow. uint8_t carry = 0; /// Contains Flag::Carry. uint8_t negative_result = 0; /// Bit 7 = the negative flag. uint8_t zero_result = 0; /// Non-zero if the zero flag is clear, zero if it is set. From 80a503f317bd93f461d4763c3cb33d2cfe6b8cd1 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 28 Oct 2025 20:54:05 -0400 Subject: [PATCH 7/8] Adjust formatting. --- Processors/6502Mk2/Perform.hpp | 134 +++++++++++++++++---------------- 1 file changed, 69 insertions(+), 65 deletions(-) diff --git a/Processors/6502Mk2/Perform.hpp b/Processors/6502Mk2/Perform.hpp index f573b24cc..686d49d63 100644 --- a/Processors/6502Mk2/Perform.hpp +++ b/Processors/6502Mk2/Perform.hpp @@ -141,7 +141,7 @@ void arr(RegistersT ®isters, const uint8_t operand) { const uint8_t unshifted_a = registers.a; registers.a = uint8_t((registers.a >> 1) | (registers.flags.carry_value() << 7)); registers.flags.template set_per(registers.a); - registers.flags.template set_per(registers.a ^ (registers.a << 1)); + registers.flags.template set_per(uint8_t(registers.a ^ (registers.a << 1))); if(registers.flags.template get() && has_decimal_mode(model)) { if((unshifted_a&0xf) + (unshifted_a&0x1) > 5) registers.a = ((registers.a + 6)&0xf) | (registers.a & 0xf0); @@ -339,112 +339,116 @@ void perform( const uint8_t opcode ) { switch(operation) { + using enum Operation; + default: __builtin_unreachable(); - case Operation::NOP: break; + case NOP: break; // MARK: - Bitwise logic. - case Operation::ORA: registers.flags.template set_per(registers.a |= operand); break; - case Operation::AND: registers.flags.template set_per(registers.a &= operand); break; - case Operation::EOR: registers.flags.template set_per(registers.a ^= operand); break; + case ORA: registers.flags.template set_per(registers.a |= operand); break; + case AND: registers.flags.template set_per(registers.a &= operand); break; + case EOR: registers.flags.template set_per(registers.a ^= operand); break; // MARK: - Loads and stores. - case Operation::LDA: registers.flags.template set_per(registers.a = operand); break; - case Operation::LDX: registers.flags.template set_per(registers.x = operand); break; - case Operation::LDY: registers.flags.template set_per(registers.y = operand); break; - case Operation::LAX: registers.flags.template set_per(registers.a = registers.x = operand); break; - case Operation::LXA: + case LDA: registers.flags.template set_per(registers.a = operand); break; + case LDX: registers.flags.template set_per(registers.x = operand); break; + case LDY: registers.flags.template set_per(registers.y = operand); break; + case LAX: + registers.flags.template set_per(registers.a = registers.x = operand); + break; + case LXA: registers.a = registers.x = (registers.a | 0xee) & operand; registers.flags.template set_per(registers.a); break; - case Operation::PLP: registers.flags = Flags(operand); break; + case PLP: registers.flags = Flags(operand); break; - case Operation::STA: operand = registers.a; break; - case Operation::STX: operand = registers.x; break; - case Operation::STY: operand = registers.y; break; - case Operation::STZ: operand = 0; break; - case Operation::SAX: operand = registers.a & registers.x; break; - case Operation::PHP: operand = static_cast(registers.flags) | Flag::Break; break; + case STA: operand = registers.a; break; + case STX: operand = registers.x; break; + case STY: operand = registers.y; break; + case STZ: operand = 0; break; + case SAX: operand = registers.a & registers.x; break; + case PHP: operand = static_cast(registers.flags) | Flag::Break; break; - case Operation::CLC: registers.flags.template set_per(0); break; - case Operation::CLI: registers.flags.template set_per(0); break; - case Operation::CLV: registers.flags.template set_per(0); break; - case Operation::CLD: registers.flags.template set_per(0); break; - case Operation::SEC: registers.flags.template set_per(Flag::Carry); break; - case Operation::SEI: registers.flags.template set_per(Flag::Interrupt); break; - case Operation::SED: registers.flags.template set_per(Flag::Decimal); break; + case CLC: registers.flags.template set_per(0); break; + case CLI: registers.flags.template set_per(0); break; + case CLV: registers.flags.template set_per(0); break; + case CLD: registers.flags.template set_per(0); break; + case SEC: registers.flags.template set_per(Flag::Carry); break; + case SEI: registers.flags.template set_per(Flag::Interrupt); break; + case SED: registers.flags.template set_per(Flag::Decimal); break; - case Operation::ANE: Operations::ane(registers, operand); break; - case Operation::ANC: Operations::anc(registers, operand); break; - case Operation::LAS: + case ANE: Operations::ane(registers, operand); break; + case ANC: Operations::anc(registers, operand); break; + case LAS: registers.a = registers.x = registers.s = registers.s & operand; registers.flags.template set_per(registers.a); break; // MARK: - Transfers. - case Operation::TXA: registers.flags.template set_per(registers.a = registers.x); break; - case Operation::TYA: registers.flags.template set_per(registers.a = registers.y); break; - case Operation::TXS: registers.s = registers.x; break; - case Operation::TAY: registers.flags.template set_per(registers.y = registers.a); break; - case Operation::TAX: registers.flags.template set_per(registers.x = registers.a); break; - case Operation::TSX: registers.flags.template set_per(registers.x = registers.s); break; + case TXA: registers.flags.template set_per(registers.a = registers.x); break; + case TYA: registers.flags.template set_per(registers.a = registers.y); break; + case TXS: registers.s = registers.x; break; + case TAY: registers.flags.template set_per(registers.y = registers.a); break; + case TAX: registers.flags.template set_per(registers.x = registers.a); break; + case TSX: registers.flags.template set_per(registers.x = registers.s); break; // MARK: - Increments and decrements. - case Operation::INC: registers.flags.template set_per(++operand); break; - case Operation::DEC: registers.flags.template set_per(--operand); break; - case Operation::INA: registers.flags.template set_per(++registers.a); break; - case Operation::DEA: registers.flags.template set_per(--registers.a); break; - case Operation::INX: registers.flags.template set_per(++registers.x); break; - case Operation::DEX: registers.flags.template set_per(--registers.x); break; - case Operation::INY: registers.flags.template set_per(++registers.y); break; - case Operation::DEY: registers.flags.template set_per(--registers.y); break; + case INC: registers.flags.template set_per(++operand); break; + case DEC: registers.flags.template set_per(--operand); break; + case INA: registers.flags.template set_per(++registers.a); break; + case DEA: registers.flags.template set_per(--registers.a); break; + case INX: registers.flags.template set_per(++registers.x); break; + case DEX: registers.flags.template set_per(--registers.x); break; + case INY: registers.flags.template set_per(++registers.y); break; + case DEY: registers.flags.template set_per(--registers.y); break; // MARK: - Shifts and rolls. - case Operation::ASL: Operations::asl(registers, operand); break; - case Operation::ASO: Operations::aso(registers, operand); break; - case Operation::ROL: Operations::rol(registers, operand); break; - case Operation::RLA: Operations::rla(registers, operand); break; - case Operation::LSR: Operations::lsr(registers, operand); break; - case Operation::LSE: Operations::lse(registers, operand); break; - case Operation::ASR: Operations::asr(registers, operand); break; - case Operation::ROR: Operations::ror(registers, operand); break; - case Operation::RRA: Operations::rra(registers, operand); break; + case ASL: Operations::asl(registers, operand); break; + case ASO: Operations::aso(registers, operand); break; + case ROL: Operations::rol(registers, operand); break; + case RLA: Operations::rla(registers, operand); break; + case LSR: Operations::lsr(registers, operand); break; + case LSE: Operations::lse(registers, operand); break; + case ASR: Operations::asr(registers, operand); break; + case ROR: Operations::ror(registers, operand); break; + case RRA: Operations::rra(registers, operand); break; // MARK: - Bit logic. - case Operation::BIT: Operations::bit(registers, operand); break; - case Operation::BITNoNV: Operations::bit_no_nv(registers, operand); break; - case Operation::TRB: Operations::trb(registers, operand); break; - case Operation::TSB: Operations::tsb(registers, operand); break; - case Operation::RMB: Operations::rmb(operand, opcode); break; - case Operation::SMB: Operations::smb(operand, opcode); break; + case BIT: Operations::bit(registers, operand); break; + case BITNoNV: Operations::bit_no_nv(registers, operand); break; + case TRB: Operations::trb(registers, operand); break; + case TSB: Operations::tsb(registers, operand); break; + case RMB: Operations::rmb(operand, opcode); break; + case SMB: Operations::smb(operand, opcode); break; // MARK: - Compare - case Operation::DCP: + case DCP: --operand; Operations::compare(registers, registers.a, operand); break; - case Operation::CMP: Operations::compare(registers, registers.a, operand); break; - case Operation::CPX: Operations::compare(registers, registers.x, operand); break; - case Operation::CPY: Operations::compare(registers, registers.y, operand); break; + case CMP: Operations::compare(registers, registers.a, operand); break; + case CPX: Operations::compare(registers, registers.x, operand); break; + case CPY: Operations::compare(registers, registers.y, operand); break; // MARK: - Arithmetic. - case Operation::INS: + case INS: ++operand; Operations::sbc(registers, operand); break; - case Operation::SBC: Operations::sbc(registers, operand); break; - case Operation::ADC: Operations::adc(registers, operand); break; - case Operation::ARR: Operations::arr(registers, operand); break; - case Operation::SBX: Operations::sbx(registers, operand); break; + case SBC: Operations::sbc(registers, operand); break; + case ADC: Operations::adc(registers, operand); break; + case ARR: Operations::arr(registers, operand); break; + case SBX: Operations::sbx(registers, operand); break; } } From dd25d387fe9a631a4fc051e2ab986caba6635f7e Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 28 Oct 2025 21:07:03 -0400 Subject: [PATCH 8/8] Allow for __COUNTER__ potentially not starting at 0. --- Processors/6502Mk2/Implementation/6502.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Processors/6502Mk2/Implementation/6502.hpp b/Processors/6502Mk2/Implementation/6502.hpp index 5c4b96243..96bc3bd6e 100644 --- a/Processors/6502Mk2/Implementation/6502.hpp +++ b/Processors/6502Mk2/Implementation/6502.hpp @@ -45,7 +45,9 @@ void Processor::run_for(const Cycles cycles) { Storage::inputs_.interrupt_requests & Storage::registers_.flags.interrupt_mask(); }; - #define restore_point() (__COUNTER__ + int(ResumePoint::Max) + int(AddressingMode::Max)) + // This is a header file, so exclusive use of the counter can't be guaranteed; adjust for that via FirstCounter. + static constexpr auto FirstCounter = __COUNTER__; + #define restore_point() (__COUNTER__ - FirstCounter + int(ResumePoint::Max) + int(AddressingMode::Max)) #define join(a, b) a##b #define attach(a, b) join(a, b)