mirror of
https://github.com/MoleskiCoder/EightBit.git
synced 2024-11-17 04:09:14 +00:00
4dc0becb74
Signed-off-by: Adrian Conlon <Adrian.conlon@gmail.com>
177 lines
4.3 KiB
C++
177 lines
4.3 KiB
C++
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <utility>
|
|
|
|
#include <EightBitCompilerDefinitions.h>
|
|
#include <LittleEndianProcessor.h>
|
|
#include <Register.h>
|
|
#include <Signal.h>
|
|
|
|
namespace EightBit {
|
|
|
|
class Bus;
|
|
|
|
class MOS6502 : public LittleEndianProcessor {
|
|
public:
|
|
enum StatusBits {
|
|
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
|
|
};
|
|
|
|
MOS6502(Bus& bus);
|
|
|
|
Signal<MOS6502> ExecutingInstruction;
|
|
Signal<MOS6502> ExecutedInstruction;
|
|
|
|
virtual int execute(uint8_t opcode) final;
|
|
virtual int step() final;
|
|
virtual void powerOn() final;
|
|
|
|
auto& X() { return x; }
|
|
auto& Y() { return y; }
|
|
auto& A() { return a; }
|
|
auto& S() { return s; }
|
|
|
|
auto& P() { return p; }
|
|
const auto& P() const { return p; }
|
|
|
|
auto& NMI() { return m_nmiLine; } // In
|
|
auto& SO() { return m_soLine; } // In
|
|
|
|
protected:
|
|
virtual void handleRESET() final;
|
|
virtual void handleIRQ() final;
|
|
|
|
virtual uint8_t sub(uint8_t operand, uint8_t data, int borrow = 0);
|
|
uint8_t sbc(uint8_t operand, uint8_t data);
|
|
uint8_t sub_b(uint8_t operand, uint8_t data, int borrow);
|
|
uint8_t sub_d(uint8_t operand, uint8_t data, int borrow);
|
|
|
|
virtual uint8_t add(uint8_t operand, uint8_t data, int carry = 0);
|
|
uint8_t adc(uint8_t operand, uint8_t data);
|
|
uint8_t add_b(uint8_t operand, uint8_t data, int carry);
|
|
uint8_t add_d(uint8_t operand, uint8_t data, int carry);
|
|
|
|
private:
|
|
const uint8_t IRQvector = 0xfe; // IRQ vector
|
|
const uint8_t RSTvector = 0xfc; // RST vector
|
|
const uint8_t NMIvector = 0xfa; // NMI vector
|
|
|
|
void handleNMI();
|
|
void handleSO();
|
|
void handleHALT();
|
|
|
|
void interrupt(uint8_t vector);
|
|
|
|
virtual void push(uint8_t value) final;
|
|
virtual uint8_t pop() final;
|
|
|
|
// Addressing modes
|
|
|
|
register16_t Address_Absolute();
|
|
uint8_t Address_ZeroPage();
|
|
register16_t Address_ZeroPageIndirect();
|
|
register16_t Address_Indirect();
|
|
uint8_t Address_ZeroPageX();
|
|
uint8_t Address_ZeroPageY();
|
|
std::pair<register16_t, bool> Address_AbsoluteX();
|
|
std::pair<register16_t, bool> Address_AbsoluteY();
|
|
register16_t Address_IndexedIndirectX();
|
|
std::pair<register16_t, bool> Address_IndirectIndexedY();
|
|
register16_t Address_relative_byte();
|
|
|
|
// Addressing modes, read
|
|
|
|
uint8_t AM_Immediate();
|
|
uint8_t AM_Absolute();
|
|
uint8_t AM_ZeroPage();
|
|
uint8_t AM_AbsoluteX();
|
|
uint8_t AM_AbsoluteY();
|
|
uint8_t AM_ZeroPageX();
|
|
uint8_t AM_ZeroPageY();
|
|
uint8_t AM_IndexedIndirectX();
|
|
uint8_t AM_IndirectIndexedY();
|
|
|
|
// Flag adjustment
|
|
|
|
void adjustZero(const uint8_t datum) { clearFlag(P(), ZF, datum); }
|
|
void adjustNegative(const uint8_t datum) { setFlag(P(), NF, datum & NF); }
|
|
|
|
void adjustNZ(const uint8_t datum) {
|
|
adjustZero(datum);
|
|
adjustNegative(datum);
|
|
}
|
|
|
|
// Flag checking
|
|
|
|
auto interruptMasked() const { return P() & IF; }
|
|
auto decimal() const { return P() & DF; }
|
|
|
|
auto negative() const { return P() & NF; }
|
|
auto zero() const { return P() & ZF; }
|
|
auto overflow() const { return P() & VF; }
|
|
auto carry() const { return P() & CF; }
|
|
|
|
// Branching
|
|
|
|
auto branch(const register16_t destination, const int condition) {
|
|
const auto page = PC().high;
|
|
if (condition) {
|
|
jump(destination);
|
|
if (UNLIKELY(PC().high != page))
|
|
addCycle();
|
|
}
|
|
return !!condition;
|
|
}
|
|
|
|
void branch(const int condition) {
|
|
if (branch(Address_relative_byte(), condition))
|
|
addCycle();
|
|
}
|
|
|
|
// Miscellaneous
|
|
|
|
auto through(const uint8_t data) {
|
|
adjustNZ(data);
|
|
return data;
|
|
}
|
|
|
|
// Instruction implementations
|
|
|
|
uint8_t andr(uint8_t operand, uint8_t data);
|
|
uint8_t asl(uint8_t value);
|
|
void bit(uint8_t operand, uint8_t data);
|
|
void brk();
|
|
void cmp(uint8_t first, uint8_t second);
|
|
uint8_t dec(uint8_t value);
|
|
uint8_t eorr(uint8_t operand, uint8_t data);
|
|
uint8_t inc(uint8_t value);
|
|
void jsr(register16_t destination);
|
|
uint8_t lsr(uint8_t value);
|
|
uint8_t orr(uint8_t operand, uint8_t data);
|
|
void php();
|
|
void plp();
|
|
uint8_t rol(uint8_t operand);
|
|
uint8_t ror(uint8_t operand);
|
|
void rti();
|
|
void rts();
|
|
|
|
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
|
|
|
|
PinLevel m_nmiLine = Low;
|
|
PinLevel m_soLine = Low;
|
|
|
|
register16_t m_intermediate;
|
|
};
|
|
} |