2017-06-04 20:38:34 +00:00
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <cstdint>
|
2018-10-31 23:29:13 +00:00
|
|
|
|
#include <utility>
|
2017-06-04 20:38:34 +00:00
|
|
|
|
|
2018-10-31 23:29:13 +00:00
|
|
|
|
#include <EightBitCompilerDefinitions.h>
|
2018-08-17 20:53:49 +00:00
|
|
|
|
#include <LittleEndianProcessor.h>
|
2018-10-31 23:29:13 +00:00
|
|
|
|
#include <Register.h>
|
2017-09-06 23:58:56 +00:00
|
|
|
|
#include <Signal.h>
|
2019-01-14 02:10:17 +00:00
|
|
|
|
#include <EventArgs.h>
|
2017-06-04 20:38:34 +00:00
|
|
|
|
|
2017-07-02 21:03:33 +00:00
|
|
|
|
namespace EightBit {
|
2018-10-31 23:29:13 +00:00
|
|
|
|
|
|
|
|
|
class Bus;
|
|
|
|
|
|
2018-08-17 20:53:49 +00:00
|
|
|
|
class MOS6502 : public LittleEndianProcessor {
|
2017-07-02 21:03:33 +00:00
|
|
|
|
public:
|
2017-07-10 14:51:33 +00:00
|
|
|
|
enum StatusBits {
|
2017-07-17 12:46:06 +00:00
|
|
|
|
NF = Bit7, // Negative
|
|
|
|
|
VF = Bit6, // Overflow
|
|
|
|
|
RF = Bit5, // reserved
|
|
|
|
|
BF = Bit4, // Brk
|
|
|
|
|
DF = Bit3, // D (use BCD for arithmetic)
|
|
|
|
|
IF = Bit2, // I (IRQ disable)
|
|
|
|
|
ZF = Bit1, // Zero
|
|
|
|
|
CF = Bit0, // Carry
|
2017-07-10 14:51:33 +00:00
|
|
|
|
};
|
|
|
|
|
|
2021-10-24 10:12:23 +00:00
|
|
|
|
MOS6502(Bus& bus) noexcept;
|
2017-07-02 21:03:33 +00:00
|
|
|
|
|
|
|
|
|
Signal<MOS6502> ExecutingInstruction;
|
2017-07-05 16:46:02 +00:00
|
|
|
|
Signal<MOS6502> ExecutedInstruction;
|
2017-06-04 20:38:34 +00:00
|
|
|
|
|
2019-01-14 02:10:17 +00:00
|
|
|
|
int execute() final;
|
2021-04-07 20:36:09 +00:00
|
|
|
|
[[nodiscard]] int step() final;
|
2019-01-14 02:10:17 +00:00
|
|
|
|
|
2021-07-18 13:28:40 +00:00
|
|
|
|
[[nodiscard]] constexpr auto& X() noexcept { return x; }
|
|
|
|
|
[[nodiscard]] constexpr auto& Y() noexcept { return y; }
|
|
|
|
|
[[nodiscard]] constexpr auto& A() noexcept { return a; }
|
|
|
|
|
[[nodiscard]] constexpr auto& S() noexcept { return s; }
|
2017-07-02 21:03:33 +00:00
|
|
|
|
|
2021-07-18 13:28:40 +00:00
|
|
|
|
[[nodiscard]] constexpr auto& P() noexcept { return p; }
|
|
|
|
|
[[nodiscard]] constexpr const auto& P() const noexcept { return p; }
|
2018-10-31 23:29:13 +00:00
|
|
|
|
|
2019-01-14 23:17:54 +00:00
|
|
|
|
DECLARE_PIN_INPUT(NMI)
|
|
|
|
|
DECLARE_PIN_INPUT(SO)
|
|
|
|
|
DECLARE_PIN_OUTPUT(SYNC)
|
|
|
|
|
DECLARE_PIN_INPUT(RDY)
|
2019-09-15 11:49:32 +00:00
|
|
|
|
DECLARE_PIN_OUTPUT(RW)
|
2018-01-12 20:13:35 +00:00
|
|
|
|
|
2017-12-10 21:41:48 +00:00
|
|
|
|
protected:
|
2021-04-07 20:36:09 +00:00
|
|
|
|
void handleRESET() final;
|
|
|
|
|
void handleINT() final;
|
2017-06-04 20:38:34 +00:00
|
|
|
|
|
2021-04-07 20:36:09 +00:00
|
|
|
|
void busWrite() final;
|
|
|
|
|
[[nodiscard]] uint8_t busRead() final;
|
2018-12-29 22:18:01 +00:00
|
|
|
|
|
2021-07-18 13:28:40 +00:00
|
|
|
|
[[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) noexcept;
|
|
|
|
|
[[nodiscard]] uint8_t sub_d(uint8_t operand, uint8_t data, int borrow) noexcept;
|
2017-12-25 23:34:56 +00:00
|
|
|
|
|
2021-07-18 13:28:40 +00:00
|
|
|
|
[[nodiscard]] virtual uint8_t add(uint8_t operand, uint8_t data, int carry = 0) noexcept;
|
|
|
|
|
[[nodiscard]] uint8_t adc(uint8_t operand, uint8_t data) 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;
|
2017-12-25 23:34:56 +00:00
|
|
|
|
|
2017-07-02 21:03:33 +00:00
|
|
|
|
private:
|
2018-10-31 23:29:13 +00:00
|
|
|
|
const uint8_t IRQvector = 0xfe; // IRQ vector
|
|
|
|
|
const uint8_t RSTvector = 0xfc; // RST vector
|
|
|
|
|
const uint8_t NMIvector = 0xfa; // NMI vector
|
|
|
|
|
|
2018-08-25 11:09:26 +00:00
|
|
|
|
void handleNMI();
|
|
|
|
|
void handleSO();
|
|
|
|
|
|
2019-01-07 01:06:07 +00:00
|
|
|
|
void interrupt();
|
2017-12-10 21:41:48 +00:00
|
|
|
|
|
2021-04-07 20:36:09 +00:00
|
|
|
|
void push(uint8_t value) final;
|
|
|
|
|
[[nodiscard]] uint8_t pop() final;
|
2017-06-04 20:38:34 +00:00
|
|
|
|
|
2019-01-08 23:09:52 +00:00
|
|
|
|
// Dummy stack push, used during RESET
|
|
|
|
|
void dummyPush(uint8_t value);
|
|
|
|
|
|
2018-10-31 23:29:13 +00:00
|
|
|
|
// Addressing modes
|
2017-07-11 20:34:01 +00:00
|
|
|
|
|
2021-04-07 20:36:09 +00:00
|
|
|
|
[[nodiscard]] register16_t Address_Absolute();
|
|
|
|
|
[[nodiscard]] uint8_t Address_ZeroPage();
|
|
|
|
|
[[nodiscard]] register16_t Address_ZeroPageIndirect();
|
|
|
|
|
[[nodiscard]] register16_t Address_Indirect();
|
|
|
|
|
[[nodiscard]] uint8_t Address_ZeroPageX();
|
|
|
|
|
[[nodiscard]] uint8_t Address_ZeroPageY();
|
|
|
|
|
[[nodiscard]] std::pair<register16_t, uint8_t> Address_AbsoluteX();
|
|
|
|
|
[[nodiscard]] std::pair<register16_t, uint8_t> Address_AbsoluteY();
|
|
|
|
|
[[nodiscard]] register16_t Address_IndexedIndirectX();
|
|
|
|
|
[[nodiscard]] std::pair<register16_t, uint8_t> Address_IndirectIndexedY();
|
|
|
|
|
[[nodiscard]] register16_t Address_relative_byte();
|
2017-07-11 20:34:01 +00:00
|
|
|
|
|
2017-12-30 15:22:27 +00:00
|
|
|
|
// Addressing modes, read
|
2017-07-11 20:34:01 +00:00
|
|
|
|
|
2019-11-09 18:58:23 +00:00
|
|
|
|
enum class PageCrossingBehavior { AlwaysReadTwice, MaybeReadTwice };
|
2019-01-06 12:58:13 +00:00
|
|
|
|
|
2018-10-31 23:29:13 +00:00
|
|
|
|
uint8_t AM_Immediate();
|
|
|
|
|
uint8_t AM_Absolute();
|
|
|
|
|
uint8_t AM_ZeroPage();
|
2019-11-09 18:58:23 +00:00
|
|
|
|
uint8_t AM_AbsoluteX(PageCrossingBehavior behaviour = PageCrossingBehavior::MaybeReadTwice);
|
2018-10-31 23:29:13 +00:00
|
|
|
|
uint8_t AM_AbsoluteY();
|
|
|
|
|
uint8_t AM_ZeroPageX();
|
|
|
|
|
uint8_t AM_ZeroPageY();
|
|
|
|
|
uint8_t AM_IndexedIndirectX();
|
|
|
|
|
uint8_t AM_IndirectIndexedY();
|
2017-07-11 20:34:01 +00:00
|
|
|
|
|
2018-10-31 23:29:13 +00:00
|
|
|
|
// Flag adjustment
|
2017-07-11 20:34:01 +00:00
|
|
|
|
|
2021-10-24 10:12:23 +00:00
|
|
|
|
constexpr void adjustZero(const uint8_t datum) noexcept { P() = clearBit(P(), ZF, datum); }
|
|
|
|
|
constexpr void adjustNegative(const uint8_t datum) noexcept { P() = setBit(P(), NF, datum & NF); }
|
2018-10-31 23:29:13 +00:00
|
|
|
|
|
2021-10-24 10:12:23 +00:00
|
|
|
|
constexpr void adjustNZ(const uint8_t datum) noexcept {
|
2018-10-31 23:29:13 +00:00
|
|
|
|
adjustZero(datum);
|
|
|
|
|
adjustNegative(datum);
|
2017-07-11 20:34:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-10-31 23:29:13 +00:00
|
|
|
|
// Flag checking
|
2017-07-11 20:34:01 +00:00
|
|
|
|
|
2021-10-24 10:12:23 +00:00
|
|
|
|
[[nodiscard]] constexpr auto interruptMasked() const noexcept { return P() & IF; }
|
|
|
|
|
[[nodiscard]] constexpr auto decimal() const noexcept { return P() & DF; }
|
2017-07-11 20:34:01 +00:00
|
|
|
|
|
2021-10-24 10:12:23 +00:00
|
|
|
|
[[nodiscard]] constexpr auto negative() const noexcept { return P() & NF; }
|
|
|
|
|
[[nodiscard]] constexpr auto zero() const noexcept { return P() & ZF; }
|
|
|
|
|
[[nodiscard]] constexpr auto overflow() const noexcept { return P() & VF; }
|
|
|
|
|
[[nodiscard]] constexpr auto carry() const noexcept { return P() & CF; }
|
2017-07-11 20:34:01 +00:00
|
|
|
|
|
2018-10-31 23:29:13 +00:00
|
|
|
|
// Miscellaneous
|
|
|
|
|
|
2019-01-05 17:23:50 +00:00
|
|
|
|
void branch(int condition);
|
|
|
|
|
|
2021-10-24 10:12:23 +00:00
|
|
|
|
[[nodiscard]] constexpr auto through(const uint8_t data) noexcept {
|
2018-10-31 23:29:13 +00:00
|
|
|
|
adjustNZ(data);
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 16:44:09 +00:00
|
|
|
|
void memoryReadModifyWrite(const uint8_t data) {
|
2019-01-03 01:04:12 +00:00
|
|
|
|
// The read will have already taken place...
|
2020-02-09 11:51:58 +00:00
|
|
|
|
memoryWrite();
|
|
|
|
|
memoryWrite(data);
|
2019-01-03 01:04:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-10-31 23:29:13 +00:00
|
|
|
|
// Instruction implementations
|
|
|
|
|
|
2021-07-18 13:28:40 +00:00
|
|
|
|
[[nodiscard]] uint8_t andr(uint8_t operand, uint8_t data) noexcept;
|
|
|
|
|
[[nodiscard]] uint8_t asl(uint8_t value) noexcept;
|
|
|
|
|
void bit(uint8_t operand, uint8_t data) noexcept;
|
|
|
|
|
void cmp(uint8_t first, uint8_t second) noexcept;
|
|
|
|
|
[[nodiscard]] uint8_t dec(uint8_t value) noexcept;
|
|
|
|
|
[[nodiscard]] uint8_t eorr(uint8_t operand, uint8_t data) noexcept;
|
|
|
|
|
[[nodiscard]] uint8_t inc(uint8_t value) noexcept;
|
2019-01-05 23:21:43 +00:00
|
|
|
|
void jsr();
|
2021-07-18 13:28:40 +00:00
|
|
|
|
[[nodiscard]] uint8_t lsr(uint8_t value) noexcept;
|
|
|
|
|
[[nodiscard]] uint8_t orr(uint8_t operand, uint8_t data) noexcept;
|
2018-10-31 23:29:13 +00:00
|
|
|
|
void php();
|
|
|
|
|
void plp();
|
2021-07-18 13:28:40 +00:00
|
|
|
|
[[nodiscard]] uint8_t rol(uint8_t operand) noexcept;
|
|
|
|
|
[[nodiscard]] uint8_t ror(uint8_t operand) noexcept;
|
2018-10-31 23:29:13 +00:00
|
|
|
|
void rti();
|
|
|
|
|
void rts();
|
2017-07-02 21:03:33 +00:00
|
|
|
|
|
2018-12-29 22:22:31 +00:00
|
|
|
|
// Undocumented compound instructions
|
|
|
|
|
|
2021-07-18 13:28:40 +00:00
|
|
|
|
void anc(uint8_t value) noexcept;
|
|
|
|
|
void arr(uint8_t value) noexcept;
|
|
|
|
|
void asr(uint8_t value) noexcept;
|
|
|
|
|
void axs(uint8_t value) noexcept;
|
2018-12-29 22:22:31 +00:00
|
|
|
|
void dcp(uint8_t value);
|
|
|
|
|
void isb(uint8_t value);
|
|
|
|
|
void rla(uint8_t value);
|
|
|
|
|
void rra(uint8_t value);
|
|
|
|
|
void slo(uint8_t value);
|
|
|
|
|
void sre(uint8_t value);
|
|
|
|
|
|
2019-01-06 20:39:37 +00:00
|
|
|
|
// Complicated addressing mode implementations
|
|
|
|
|
|
|
|
|
|
void sta_AbsoluteX();
|
|
|
|
|
void sta_AbsoluteY();
|
|
|
|
|
|
2018-01-18 17:50:15 +00:00
|
|
|
|
uint8_t x = 0; // index register X
|
|
|
|
|
uint8_t y = 0; // index register Y
|
|
|
|
|
uint8_t a = 0; // accumulator
|
|
|
|
|
uint8_t s = 0; // stack pointer
|
|
|
|
|
uint8_t p = 0; // processor status
|
2017-07-02 21:03:33 +00:00
|
|
|
|
|
2018-06-15 23:55:32 +00:00
|
|
|
|
register16_t m_intermediate;
|
2019-01-08 01:32:43 +00:00
|
|
|
|
|
|
|
|
|
bool m_handlingRESET = false;
|
|
|
|
|
bool m_handlingNMI = false;
|
2019-01-14 02:10:17 +00:00
|
|
|
|
bool m_handlingINT = false;
|
2017-07-02 21:03:33 +00:00
|
|
|
|
};
|
|
|
|
|
}
|