EightBit/M6502/inc/mos6502.h

660 lines
12 KiB
C
Raw Normal View History

#pragma once
#include <cstdint>
#include <string>
#include <array>
#include <functional>
#include "Memory.h"
#include "Processor.h"
#include "ProcessorType.h"
#include "AddressingMode.h"
#include "Signal.h"
namespace EightBit {
class MOS6502 : public Processor {
public:
enum StatusBits {
NF = 0x80, // Negative
VF = 0x40, // Overflow
RF = 0x20, // reserved
BF = 0x10, // Brk
DF = 0x08, // D (use BCD for arithmetic)
IF = 0x04, // I (IRQ disable)
ZF = 0x02, // Zero
CF = 0x01, // Carry
};
typedef std::function<void()> instruction_t;
struct Instruction {
instruction_t vector = nullptr;
int count = 0;
AddressingMode mode = AddressingMode::Illegal;
std::string display = "";
};
MOS6502(Memory& memory, ProcessorType level);
Signal<MOS6502> ExecutingInstruction;
Signal<MOS6502> ExecutedInstruction;
ProcessorType getLevel() const { return level; }
uint8_t& X() { return x; }
uint8_t& Y() { return y; }
uint8_t& A() { return a; }
uint8_t& S() { return s; }
uint8_t& P() { return p; }
const Instruction& getInstruction(uint8_t code) const {
return instructions[code];
}
virtual void initialise();
virtual int step();
virtual void Reset();
virtual void TriggerIRQ();
virtual void TriggerNMI();
void GetWord(register16_t& output);
void GetWord(uint16_t offset, register16_t& output);
uint8_t GetByte() { return m_memory.read(); }
uint8_t GetByte(uint16_t offset) { return m_memory.read(offset); }
void SetByte(uint8_t value) { m_memory.write(value); }
void SetByte(uint16_t offset, uint8_t value) { m_memory.write(offset, value); }
protected:
virtual void Interrupt(uint16_t vector);
virtual int Execute(uint8_t cell);
void ___();
private:
static Instruction INS(instruction_t method, int cycles, AddressingMode addressing, std::string display);
void Install6502Instructions();
void Install65sc02Instructions();
void Install65c02Instructions();
void InstallInstructionSet(const std::array<Instruction, 0x100>& basis);
void OverlayInstructionSet(const std::array<Instruction, 0x100>& overlay);
void OverlayInstructionSet(const std::array<Instruction, 0x100>& overlay, bool includeIllegal);
void UpdateZeroFlag(uint8_t datum) { clearFlag(P(), ZF, datum); }
void UpdateNegativeFlag(uint8_t datum) { setFlag(P(), NF, datum & NF); }
void UpdateZeroNegativeFlags(uint8_t datum) {
UpdateZeroFlag(datum);
UpdateNegativeFlag(datum);
}
void PushByte(uint8_t value);
uint8_t PopByte();
void PushWord(register16_t value);
void PopWord(register16_t& output);
uint8_t FetchByte();
void FetchWord(register16_t& output);
#pragma region 6502 addressing modes
#pragma region Addresses
void Address_Absolute() {
FetchWord(m_memptr);
}
void Address_ZeroPage() {
m_memptr.low = FetchByte();
m_memptr.high = 0;
}
void Address_ZeroPageIndirect() {
Address_ZeroPage();
m_memory.ADDRESS() = m_memptr;
GetWord(m_memptr);
}
void Address_Indirect() {
Address_Absolute();
m_memory.ADDRESS() = m_memptr;
GetWord(m_memptr);
}
void Address_IndirectX() {
Address_Absolute();
m_memory.ADDRESS().word = m_memptr.word + X();
GetWord(m_memptr);
}
void Address_ZeroPageX() {
Address_ZeroPage();
m_memptr.low += X();
}
void Address_ZeroPageY() {
Address_ZeroPage();
m_memptr.low += Y();
}
void Address_AbsoluteX() {
Address_Absolute();
m_memptr.word += X();
}
void Address_AbsoluteY() {
Address_Absolute();
m_memptr.word += Y();
}
void Address_IndexedIndirectX() {
Address_ZeroPageX();
m_memory.ADDRESS() = m_memptr;
GetWord(m_memptr);
}
void Address_IndirectIndexedY() {
Address_ZeroPageIndirect();
m_memptr.word += Y();
}
#pragma endregion Addresses
#pragma region References
uint8_t& AM_A() {
return A();
}
uint8_t& AM_X() {
return X();
}
uint8_t& AM_Y() {
return Y();
}
uint8_t& AM_Immediate() {
FetchByte();
return m_memory.reference();
}
uint8_t& AM_Absolute() {
Address_Absolute();
m_memory.ADDRESS() = m_memptr;
return m_memory.reference();
}
uint8_t& AM_ZeroPage() {
Address_ZeroPage();
m_memory.ADDRESS() = m_memptr;
return m_memory.reference();
}
uint8_t& AM_ZeroPageIndirect() {
Address_ZeroPageIndirect();
m_memory.ADDRESS() = m_memptr;
return m_memory.reference();
}
uint8_t& AM_AbsoluteX() {
Address_AbsoluteX();
m_memory.ADDRESS() = m_memptr;
return m_memory.reference();
}
uint8_t& AM_AbsoluteY() {
Address_AbsoluteY();
m_memory.ADDRESS() = m_memptr;
return m_memory.reference();
}
uint8_t& AM_ZeroPageX() {
Address_ZeroPageX();
m_memory.ADDRESS() = m_memptr;
return m_memory.reference();
}
uint8_t& AM_ZeroPageY() {
Address_ZeroPageY();
m_memory.ADDRESS() = m_memptr;
return m_memory.reference();
}
uint8_t& AM_IndexedIndirectX() {
Address_IndexedIndirectX();
m_memory.ADDRESS() = m_memptr;
return m_memory.reference();
}
uint8_t& AM_IndirectIndexedY() {
Address_IndirectIndexedY();
m_memory.ADDRESS() = m_memptr;
return m_memory.reference();
}
#pragma endregion References
#pragma region 6502 addressing mode switching
uint8_t& AM_00(int bbb) {
switch (bbb) {
case 0b000:
return AM_Immediate();
case 0b001:
return AM_ZeroPage();
case 0b011:
return AM_Absolute();
case 0b101:
return AM_ZeroPageX();
case 0b111:
return AM_AbsoluteX();
case 0b010:
case 0b100:
case 0b110:
throw std::domain_error("Illegal addressing mode");
default:
__assume(0);
}
}
uint8_t& AM_01(int bbb) {
switch (bbb) {
case 0b000:
return AM_IndexedIndirectX();
case 0b001:
return AM_ZeroPage();
case 0b010:
return AM_Immediate();
case 0b011:
return AM_Absolute();
case 0b100:
return AM_IndirectIndexedY();
case 0b101:
return AM_ZeroPageX();
case 0b110:
return AM_AbsoluteY();
case 0b111:
return AM_AbsoluteX();
default:
__assume(0);
}
}
uint8_t& AM_10(int bbb) {
switch (bbb) {
case 0b000:
return AM_Immediate();
case 0b001:
return AM_ZeroPage();
case 0b010:
return AM_A();
case 0b011:
return AM_Absolute();
case 0b101:
return AM_ZeroPageX();
case 0b111:
return AM_AbsoluteX();
case 0b100:
case 0b110:
throw std::domain_error("Illegal addressing mode");
default:
__assume(0);
}
}
uint8_t& AM_10_x(int bbb, bool x = false) {
switch (bbb) {
case 0b000:
return AM_Immediate();
case 0b001:
return AM_ZeroPage();
case 0b010:
return AM_A();
case 0b011:
return AM_Absolute();
case 0b101:
return AM_ZeroPageY();
case 0b111:
return AM_AbsoluteY();
case 0b100:
case 0b110:
throw std::domain_error("Illegal addressing mode");
default:
__assume(0);
}
}
#pragma endregion 6502 addressing mode switching
#pragma endregion 6502 addressing modes
void DEC(uint8_t& output);
void ROR(uint8_t& output);
void LSR(uint8_t& output);
void BIT(uint8_t data);
void TSB(uint8_t& output);
void TRB(uint8_t& output);
void INC(uint8_t& output);
void ROL(uint8_t& output);
void ASL(uint8_t& output);
void ORA(uint8_t data);
void AND(uint8_t data);
void SBC(uint8_t data);
void SBC_b(uint8_t data);
void SBC_d(uint8_t data);
void EOR(uint8_t data);
void CPX(uint8_t data);
void CPY(uint8_t data);
void CMP(uint8_t data);
void CMP(uint8_t first, uint8_t second);
void LDA(uint8_t data);
void LDY(uint8_t data);
void LDX(uint8_t data);
void ADC(uint8_t data);
void ADC_b(uint8_t data);
void ADC_d(uint8_t data);
void RMB(uint8_t& output, uint8_t flag);
void SMB(uint8_t& output, uint8_t flag);
void Branch(int8_t displacement);
void Branch();
void Branch(bool flag);
void BitBranch_Clear(uint8_t check);
void BitBranch_Set(uint8_t check);
void NOP_imp();
void NOP2_imp();
void NOP3_imp();
void ORA_xind();
void ORA_zp();
void ORA_imm();
void ORA_abs();
void ORA_absx();
void ORA_absy();
void ORA_zpx();
void ORA_indy();
void ORA_zpind();
void AND_zpx();
void AND_indy();
void AND_zp();
void AND_absx();
void AND_absy();
void AND_imm();
void AND_xind();
void AND_abs();
void AND_zpind();
void EOR_absx();
void EOR_absy();
void EOR_zpx();
void EOR_indy();
void EOR_abs();
void EOR_imm();
void EOR_zp();
void EOR_xind();
void EOR_zpind();
void LDA_absx();
void LDA_absy();
void LDA_zpx();
void LDA_indy();
void LDA_abs();
void LDA_imm();
void LDA_zp();
void LDA_xind();
void LDA_zpind();
void LDX_imm();
void LDX_zp();
void LDX_abs();
void LDX_zpy();
void LDX_absy();
void LDY_imm();
void LDY_zp();
void LDY_abs();
void LDY_zpx();
void LDY_absx();
void CMP_absx();
void CMP_absy();
void CMP_zpx();
void CMP_indy();
void CMP_abs();
void CMP_imm();
void CMP_zp();
void CMP_xind();
void CMP_zpind();
void CPX_abs();
void CPX_zp();
void CPX_imm();
void CPY_imm();
void CPY_zp();
void CPY_abs();
void ADC_zp();
void ADC_xind();
void ADC_imm();
void ADC_abs();
void ADC_zpx();
void ADC_indy();
void ADC_absx();
void ADC_absy();
void ADC_zpind();
void SBC_xind();
void SBC_zp();
void SBC_imm();
void SBC_abs();
void SBC_zpx();
void SBC_indy();
void SBC_absx();
void SBC_absy();
void SBC_zpind();
void BIT_imm();
void BIT_zp();
void BIT_zpx();
void BIT_abs();
void BIT_absx();
void DEC_a();
void DEC_absx();
void DEC_zpx();
void DEC_abs();
void DEC_zp();
void DEX_imp();
void DEY_imp();
void INC_a();
void INC_zp();
void INC_absx();
void INC_zpx();
void INC_abs();
void INX_imp();
void INY_imp();
void STX_zpy();
void STX_abs();
void STX_zp();
void STY_zpx();
void STY_abs();
void STY_zp();
void STA_absx();
void STA_absy();
void STA_zpx();
void STA_indy();
void STA_abs();
void STA_zp();
void STA_xind();
void STA_zpind();
void STZ_zp();
void STZ_zpx();
void STZ_abs();
void STZ_absx();
void TSX_imp();
void TAX_imp();
void TAY_imp();
void TXS_imp();
void TYA_imp();
void TXA_imp();
void PHP_imp();
void PLP_imp();
void PLA_imp();
void PHA_imp();
void PHX_imp();
void PHY_imp();
void PLX_imp();
void PLY_imp();
void ASL_a();
void ASL_zp();
void ASL_abs();
void ASL_absx();
void ASL_zpx();
void LSR_absx();
void LSR_zpx();
void LSR_abs();
void LSR_a();
void LSR_zp();
void ROL_absx();
void ROL_zpx();
void ROL_abs();
void ROL_a();
void ROL_zp();
void ROR_absx();
void ROR_zpx();
void ROR_abs();
void ROR_a();
void ROR_zp();
void TSB_zp();
void TSB_abs();
void TRB_zp();
void TRB_abs();
void RMB0_zp();
void RMB1_zp();
void RMB2_zp();
void RMB3_zp();
void RMB4_zp();
void RMB5_zp();
void RMB6_zp();
void RMB7_zp();
void SMB0_zp();
void SMB1_zp();
void SMB2_zp();
void SMB3_zp();
void SMB4_zp();
void SMB5_zp();
void SMB6_zp();
void SMB7_zp();
void JSR_abs();
void RTI_imp();
void RTS_imp();
void JMP_abs();
void JMP_ind();
void JMP_absxind();
void BRK_imp();
void WAI_imp();
void STP_imp();
void SED_imp();
void CLD_imp();
void CLV_imp();
void SEI_imp();
void CLI_imp();
void CLC_imp();
void SEC_imp();
void BMI_rel();
void BPL_rel();
void BVC_rel();
void BVS_rel();
void BCC_rel();
void BCS_rel();
void BNE_rel();
void BEQ_rel();
void BRA_rel();
void BBR0_zprel();
void BBR1_zprel();
void BBR2_zprel();
void BBR3_zprel();
void BBR4_zprel();
void BBR5_zprel();
void BBR6_zprel();
void BBR7_zprel();
void BBS0_zprel();
void BBS1_zprel();
void BBS2_zprel();
void BBS3_zprel();
void BBS4_zprel();
void BBS5_zprel();
void BBS6_zprel();
void BBS7_zprel();
const uint16_t PageOne = 0x100;
const uint16_t IRQvector = 0xfffe;
const uint16_t RSTvector = 0xfffc;
const uint16_t NMIvector = 0xfffa;
uint8_t x; // index register X
uint8_t y; // index register Y
uint8_t a; // accumulator
uint8_t s; // stack pointer
uint8_t p; // processor status
register16_t m_memptr;
std::array<Instruction, 0x100> instructions;
ProcessorType level;
std::array<Instruction, 0x100> overlay6502;
std::array<Instruction, 0x100> overlay65sc02;
std::array<Instruction, 0x100> overlay65c02;
};
}