Compare commits
6 Commits
c15f7f836e
...
69a845e2f4
Author | SHA1 | Date |
---|---|---|
Adrian Conlon | 69a845e2f4 | |
Adrian Conlon | 9334f6ee93 | |
Adrian Conlon | bd289ed8fb | |
Adrian Conlon | bc37fd4e30 | |
Adrian Conlon | 48369f0e98 | |
Adrian Conlon | 349bada9cc |
|
@ -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; }
|
||||
|
|
|
@ -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))); }
|
||||
};
|
||||
|
|
|
@ -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())));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue