Compare commits

...

6 Commits

Author SHA1 Message Date
Adrian Conlon 69a845e2f4 How did that "secret" tick in the M6502 implementation get there??? 2024-01-06 20:53:50 +00:00
Adrian Conlon 9334f6ee93 Fix the ATX implementation in the M6502 core 2024-01-06 13:10:51 +00:00
Adrian Conlon bd289ed8fb Add a working M6502 ARR implementation 2024-01-06 12:19:02 +00:00
Adrian Conlon bc37fd4e30 Better information in the event of failing tests 2024-01-06 12:17:45 +00:00
Adrian Conlon 48369f0e98 Remove warning about temporary values being used 2024-01-06 12:17:15 +00:00
Adrian Conlon 349bada9cc Add undocumented instructions SYA and SXA to M6502 implementation 2024-01-06 09:52:17 +00:00
5 changed files with 77 additions and 13 deletions

View File

@ -84,7 +84,7 @@ public:
[[nodiscard]] constexpr auto cycles() const noexcept { return m_cycles; }
[[nodiscard]] constexpr auto valid() const noexcept { return m_valid; }
[[nodiscard]] constexpr auto invalid() const noexcept { return !valid(); }
[[nodiscard]] constexpr auto unimplemented() const noexcept { return invalid() && m_cycle_count_mismatch && (cycles() == 1); }
[[nodiscard]] constexpr auto unimplemented() const noexcept { return invalid() && m_cycle_count_mismatch && (cycles() == 0); }
[[nodiscard]] constexpr auto implemented() const noexcept { return !unimplemented(); }
[[nodiscard]] constexpr const auto& messages() const noexcept { return m_messages; }

View File

@ -10,5 +10,5 @@ class cycle_t final : public byte_t {
public:
cycle_t(simdjson::dom::array input) noexcept;
[[nodiscard]] auto action() const noexcept { return std::string_view(at(2)); }
[[nodiscard]] auto action() const noexcept { return std::string(std::string_view(at(2))); }
};

View File

@ -36,20 +36,37 @@ int main() {
opcode.load();
auto test_generator = opcode.generator();
std::vector<std::string> test_names;
while (test_generator) {
const auto test = test_generator();
checker.check(test);
if (checker.invalid()) {
std::cout << "** Failed: " << test.name() << "\n";
++invalid_opcode_count;
// Was it just unimplemented?
if (checker.unimplemented())
++unimplemented_opcode_count;
std::cout << "** Failed: " << test.name() << "\n";
// Let's see if we had any successes!
if (!test_names.empty()) {
std::cout << "**** The follow test variations succeeeded\n";
for (const auto& test_name : test_names)
std::cout << "****** " << test_name << "\n";
}
// OK, we've attempted an implementation, how did it fail?
for (const auto& message : checker.messages())
std::cout << "**** " << message << "\n";
// I'm not really interested in the remaining tests for this opcode
break;
}
test_names.push_back(std::string(std::string_view(test.name())));
}
}

View File

@ -56,6 +56,8 @@ namespace EightBit {
void busWrite() noexcept final;
[[nodiscard]] uint8_t busRead() noexcept final;
// Instructions with BCD effects
[[nodiscard]] virtual uint8_t sub(uint8_t operand, uint8_t data, int borrow = 0) noexcept;
[[nodiscard]] uint8_t sbc(uint8_t operand, uint8_t data) noexcept;
[[nodiscard]] uint8_t sub_b(uint8_t operand, uint8_t data, int borrow = 0) noexcept;
@ -66,6 +68,12 @@ namespace EightBit {
[[nodiscard]] uint8_t add_b(uint8_t operand, uint8_t data, int carry) noexcept;
[[nodiscard]] uint8_t add_d(uint8_t operand, uint8_t data, int carry) noexcept;
// Undocumented compound instructions (with BCD effects)
virtual void arr(uint8_t value) noexcept;
virtual void arr_b(uint8_t value) noexcept;
virtual void arr_d(uint8_t value) noexcept;
private:
const uint8_t IRQvector = 0xfe; // IRQ vector
const uint8_t RSTvector = 0xfc; // RST vector
@ -174,7 +182,6 @@ namespace EightBit {
// Undocumented compound instructions
void anc(uint8_t value) noexcept;
void arr(uint8_t value) noexcept;
void asr(uint8_t value) noexcept;
void axs(uint8_t value) noexcept;
void dcp(uint8_t value) noexcept;
@ -257,6 +264,12 @@ namespace EightBit {
sre(memoryRead());
}
// SYA
void sya_AbsoluteX() noexcept;
// SXA
void sxa_AbsoluteY() noexcept;
// NOP
void nop_AbsoluteX() noexcept;

View File

@ -2,7 +2,7 @@
#include "../inc/mos6502.h"
EightBit::MOS6502::MOS6502(Bus& bus) noexcept
: LittleEndianProcessor(bus) {
: LittleEndianProcessor(bus) {
RaisedPOWER.connect([this](EventArgs) {
X() = Bit7;
Y() = 0;
@ -24,7 +24,6 @@ int EightBit::MOS6502::step() noexcept {
resetCycles();
ExecutingInstruction.fire(*this);
if (LIKELY(powered())) {
tick();
if (UNLIKELY(lowered(SO())))
handleSO();
if (LIKELY(raised(RDY()))) {
@ -277,9 +276,9 @@ int EightBit::MOS6502::execute() noexcept {
case 0x99: sta_AbsoluteY(); break; // STA (absolute, Y)
case 0x9a: memoryRead(PC()); S() = X(); break; // TXS (implied)
case 0x9b: break;
case 0x9c: break;
case 0x9c: sya_AbsoluteX(); break; // *SYA (absolute, X)
case 0x9d: sta_AbsoluteX(); break; // STA (absolute, X)
case 0x9e: break;
case 0x9e: sxa_AbsoluteY(); break; // *SXA (absolute, Y)
case 0x9f: break;
case 0xa0: Y() = through(AM_Immediate()); break; // LDY (immediate)
@ -293,7 +292,7 @@ int EightBit::MOS6502::execute() noexcept {
case 0xa8: memoryRead(PC()); Y() = through(A()); break; // TAY (implied)
case 0xa9: A() = through(AM_Immediate()); break; // LDA (immediate)
case 0xaa: memoryRead(PC()); X() = through(A()); break; // TAX (implied)
case 0xab: A() = X() = through(AM_Immediate()); break; // *ATX (immediate)
case 0xab: A() = X() = through((A() | 0xee) & AM_Immediate()); break; // *ATX (immediate)
case 0xac: Y() = through(AM_Absolute()); break; // LDY (absolute)
case 0xad: A() = through(AM_Absolute()); break; // LDA (absolute)
case 0xae: X() = through(AM_Absolute()); break; // LDX (absolute)
@ -698,10 +697,33 @@ void EightBit::MOS6502::anc(const uint8_t value) noexcept {
}
void EightBit::MOS6502::arr(const uint8_t value) noexcept {
A() = andr(A(), value);
A() = ror(A());
decimal() ? arr_d(value) : arr_b(value);
}
void EightBit::MOS6502::arr_d(const uint8_t value) noexcept {
// With thanks to https://github.com/TomHarte/CLK
// What a very strange instruction ARR is...
A() &= value;
auto unshiftedA = A();
A() = through((A() >> 1) | (carry() << 7));
P() = setBit(P(), VF, (A() ^ (A() << 1)) & VF);
if (lowerNibble(unshiftedA) + (unshiftedA & 0x1) > 5)
A() = lowerNibble(A() + 6) | higherNibble(A());
P() = setBit(P(), CF, higherNibble(unshiftedA) + (unshiftedA & 0x10) > 0x50);
if (carry())
A() += 0x60;
}
void EightBit::MOS6502::arr_b(const uint8_t value) noexcept {
A() &= value;
A() = through((A() >> 1) | (carry() << 7));
P() = setBit(P(), CF, A() & Bit6);
P() = setBit(P(), VF, ((A() & Bit6) >> 6) ^((A() & Bit5) >> 5));
P() = setBit(P(), VF, (A() ^ (A() << 1)) & VF);
}
void EightBit::MOS6502::asr(const uint8_t value) noexcept {
@ -853,6 +875,18 @@ void EightBit::MOS6502::sre_IndirectIndexedY() noexcept {
sre_with_fixup(address, page);
}
void EightBit::MOS6502::sya_AbsoluteX() noexcept {
const auto [address, page] = Address_AbsoluteX();
fixup(address, page);
memoryWrite(Y() & (address.high + 1));
}
void EightBit::MOS6502::sxa_AbsoluteY() noexcept {
const auto [address, page] = Address_AbsoluteY();
fixup(address, page);
memoryWrite(X() & (address.high + 1));
}
void EightBit::MOS6502::nop_AbsoluteX() noexcept {
const auto [address, page] = Address_AbsoluteX();
fixup(address, page);