mirror of
https://github.com/MoleskiCoder/EightBit.git
synced 2024-06-01 07:41:51 +00:00
Compare commits
6 Commits
c15f7f836e
...
69a845e2f4
Author | SHA1 | Date | |
---|---|---|---|
|
69a845e2f4 | ||
|
9334f6ee93 | ||
|
bd289ed8fb | ||
|
bc37fd4e30 | ||
|
48369f0e98 | ||
|
349bada9cc |
|
@ -84,7 +84,7 @@ public:
|
||||||
[[nodiscard]] constexpr auto cycles() const noexcept { return m_cycles; }
|
[[nodiscard]] constexpr auto cycles() const noexcept { return m_cycles; }
|
||||||
[[nodiscard]] constexpr auto valid() const noexcept { return m_valid; }
|
[[nodiscard]] constexpr auto valid() const noexcept { return m_valid; }
|
||||||
[[nodiscard]] constexpr auto invalid() const noexcept { return !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 auto implemented() const noexcept { return !unimplemented(); }
|
||||||
|
|
||||||
[[nodiscard]] constexpr const auto& messages() const noexcept { return m_messages; }
|
[[nodiscard]] constexpr const auto& messages() const noexcept { return m_messages; }
|
||||||
|
|
|
@ -10,5 +10,5 @@ class cycle_t final : public byte_t {
|
||||||
public:
|
public:
|
||||||
cycle_t(simdjson::dom::array input) noexcept;
|
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();
|
opcode.load();
|
||||||
|
|
||||||
auto test_generator = opcode.generator();
|
auto test_generator = opcode.generator();
|
||||||
|
std::vector<std::string> test_names;
|
||||||
while (test_generator) {
|
while (test_generator) {
|
||||||
|
|
||||||
const auto test = test_generator();
|
const auto test = test_generator();
|
||||||
checker.check(test);
|
checker.check(test);
|
||||||
|
|
||||||
if (checker.invalid()) {
|
if (checker.invalid()) {
|
||||||
|
|
||||||
|
std::cout << "** Failed: " << test.name() << "\n";
|
||||||
|
|
||||||
++invalid_opcode_count;
|
++invalid_opcode_count;
|
||||||
|
|
||||||
|
// Was it just unimplemented?
|
||||||
if (checker.unimplemented())
|
if (checker.unimplemented())
|
||||||
++unimplemented_opcode_count;
|
++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())
|
for (const auto& message : checker.messages())
|
||||||
std::cout << "**** " << message << "\n";
|
std::cout << "**** " << message << "\n";
|
||||||
|
|
||||||
|
// I'm not really interested in the remaining tests for this opcode
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test_names.push_back(std::string(std::string_view(test.name())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,8 @@ namespace EightBit {
|
||||||
void busWrite() noexcept final;
|
void busWrite() noexcept final;
|
||||||
[[nodiscard]] uint8_t busRead() 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]] 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 sbc(uint8_t operand, uint8_t data) noexcept;
|
||||||
[[nodiscard]] uint8_t sub_b(uint8_t operand, uint8_t data, int borrow = 0) 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_b(uint8_t operand, uint8_t data, int carry) noexcept;
|
||||||
[[nodiscard]] uint8_t add_d(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:
|
private:
|
||||||
const uint8_t IRQvector = 0xfe; // IRQ vector
|
const uint8_t IRQvector = 0xfe; // IRQ vector
|
||||||
const uint8_t RSTvector = 0xfc; // RST vector
|
const uint8_t RSTvector = 0xfc; // RST vector
|
||||||
|
@ -174,7 +182,6 @@ namespace EightBit {
|
||||||
// Undocumented compound instructions
|
// Undocumented compound instructions
|
||||||
|
|
||||||
void anc(uint8_t value) noexcept;
|
void anc(uint8_t value) noexcept;
|
||||||
void arr(uint8_t value) noexcept;
|
|
||||||
void asr(uint8_t value) noexcept;
|
void asr(uint8_t value) noexcept;
|
||||||
void axs(uint8_t value) noexcept;
|
void axs(uint8_t value) noexcept;
|
||||||
void dcp(uint8_t value) noexcept;
|
void dcp(uint8_t value) noexcept;
|
||||||
|
@ -257,6 +264,12 @@ namespace EightBit {
|
||||||
sre(memoryRead());
|
sre(memoryRead());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SYA
|
||||||
|
void sya_AbsoluteX() noexcept;
|
||||||
|
|
||||||
|
// SXA
|
||||||
|
void sxa_AbsoluteY() noexcept;
|
||||||
|
|
||||||
// NOP
|
// NOP
|
||||||
void nop_AbsoluteX() noexcept;
|
void nop_AbsoluteX() noexcept;
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#include "../inc/mos6502.h"
|
#include "../inc/mos6502.h"
|
||||||
|
|
||||||
EightBit::MOS6502::MOS6502(Bus& bus) noexcept
|
EightBit::MOS6502::MOS6502(Bus& bus) noexcept
|
||||||
: LittleEndianProcessor(bus) {
|
: LittleEndianProcessor(bus) {
|
||||||
RaisedPOWER.connect([this](EventArgs) {
|
RaisedPOWER.connect([this](EventArgs) {
|
||||||
X() = Bit7;
|
X() = Bit7;
|
||||||
Y() = 0;
|
Y() = 0;
|
||||||
|
@ -24,7 +24,6 @@ int EightBit::MOS6502::step() noexcept {
|
||||||
resetCycles();
|
resetCycles();
|
||||||
ExecutingInstruction.fire(*this);
|
ExecutingInstruction.fire(*this);
|
||||||
if (LIKELY(powered())) {
|
if (LIKELY(powered())) {
|
||||||
tick();
|
|
||||||
if (UNLIKELY(lowered(SO())))
|
if (UNLIKELY(lowered(SO())))
|
||||||
handleSO();
|
handleSO();
|
||||||
if (LIKELY(raised(RDY()))) {
|
if (LIKELY(raised(RDY()))) {
|
||||||
|
@ -277,9 +276,9 @@ int EightBit::MOS6502::execute() noexcept {
|
||||||
case 0x99: sta_AbsoluteY(); break; // STA (absolute, Y)
|
case 0x99: sta_AbsoluteY(); break; // STA (absolute, Y)
|
||||||
case 0x9a: memoryRead(PC()); S() = X(); break; // TXS (implied)
|
case 0x9a: memoryRead(PC()); S() = X(); break; // TXS (implied)
|
||||||
case 0x9b: break;
|
case 0x9b: break;
|
||||||
case 0x9c: break;
|
case 0x9c: sya_AbsoluteX(); break; // *SYA (absolute, X)
|
||||||
case 0x9d: sta_AbsoluteX(); break; // STA (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 0x9f: break;
|
||||||
|
|
||||||
case 0xa0: Y() = through(AM_Immediate()); break; // LDY (immediate)
|
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 0xa8: memoryRead(PC()); Y() = through(A()); break; // TAY (implied)
|
||||||
case 0xa9: A() = through(AM_Immediate()); break; // LDA (immediate)
|
case 0xa9: A() = through(AM_Immediate()); break; // LDA (immediate)
|
||||||
case 0xaa: memoryRead(PC()); X() = through(A()); break; // TAX (implied)
|
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 0xac: Y() = through(AM_Absolute()); break; // LDY (absolute)
|
||||||
case 0xad: A() = through(AM_Absolute()); break; // LDA (absolute)
|
case 0xad: A() = through(AM_Absolute()); break; // LDA (absolute)
|
||||||
case 0xae: X() = through(AM_Absolute()); break; // LDX (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 {
|
void EightBit::MOS6502::arr(const uint8_t value) noexcept {
|
||||||
A() = andr(A(), value);
|
decimal() ? arr_d(value) : arr_b(value);
|
||||||
A() = ror(A());
|
}
|
||||||
|
|
||||||
|
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(), 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 {
|
void EightBit::MOS6502::asr(const uint8_t value) noexcept {
|
||||||
|
@ -853,6 +875,18 @@ void EightBit::MOS6502::sre_IndirectIndexedY() noexcept {
|
||||||
sre_with_fixup(address, page);
|
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 {
|
void EightBit::MOS6502::nop_AbsoluteX() noexcept {
|
||||||
const auto [address, page] = Address_AbsoluteX();
|
const auto [address, page] = Address_AbsoluteX();
|
||||||
fixup(address, page);
|
fixup(address, page);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user