Files
ComSquare/sources/CPU/CPU.hpp
Anonymus Raccoon 26ea447f24 Implementing the XBA
2020-04-08 17:13:00 +02:00

720 lines
34 KiB
C++

//
// Created by anonymus-raccoon on 1/24/20.
//
#ifndef COMSQUARE_CPU_HPP
#define COMSQUARE_CPU_HPP
#include "../Memory/AMemory.hpp"
#include "../Memory/MemoryBus.hpp"
#include "../Models/Int24.hpp"
#include "../Cartridge/Cartridge.hpp"
#include "../Memory/AMemory.hpp"
#include "Instruction.hpp"
namespace ComSquare::CPU
{
//! @brief Struct containing registers for the main CPU.
struct Registers {
//! @brief The Accumulator
union {
struct {
uint8_t al;
uint8_t ah;
};
uint16_t a;
};
//! @brief The Data Bank Register;
uint8_t dbr;
//! @brief The Direct Page register;
union {
struct {
uint8_t dl;
uint8_t dh;
};
uint16_t d;
};
union {
struct {
//! @brief The Program Counter;
union {
struct {
uint8_t pcl;
uint8_t pch;
};
uint16_t pc;
};
//! @brief The Program Bank Register;
uint8_t pbr;
};
//! @brief The current Program Address Counter (does not exist in a snes but is useful here).
uint24_t pac;
};
//! @brief The Stack pointer
union {
struct {
uint8_t sl;
uint8_t sh;
};
uint16_t s;
};
//! @brief The X index register
union {
struct {
uint8_t xl;
uint8_t xh;
};
uint16_t x;
};
//! @brief The Y index register
union {
struct {
uint8_t yl;
uint8_t yh;
};
uint16_t y;
};
//! @brief The Processor status register;
union {
struct {
//! @brief The Carry flag
bool c : 1;
//! @brief The Zero flag
bool z : 1;
//! @brief The Interrupt request disable flag
bool i : 1;
//! @brief The Decimal mode flag
bool d : 1;
//! @brief The indeX register width flag (in native mode only) - 0 = 16 bits mode, 1 = 8 bits mode OR the Break flag (in emulation mode only)
bool x_b : 1;
//! @brief The accumulator and Memory width flag (in native mode only) - 0 = 16 bits mode, 1 = 8 bits mode.
bool m : 1;
//! @brief The oVerflow flag
bool v : 1;
//! @brief The Negative flag
bool n : 1;
};
uint8_t flags;
} p;
};
//! @brief Struct containing internal registers of the CPU.
struct InternalRegisters
{
//! @brief Interrupt Enable Register
uint8_t nmitimen;
//! @brief IO Port Write Register
uint8_t wrio;
//! @brief Multiplicand Register A
uint8_t wrmpya;
//! @brief Multiplicand Register B
uint8_t wrmpyb;
//! @brief Divisor & Dividend Registers (A - Low)
uint8_t wrdivl;
//! @brief Divisor & Dividend Registers (A - High)
uint8_t wrdivh;
//! @brief Divisor & Dividend Registers (B)
uint8_t wrdivb;
//! @brief IRQ Timer Registers (Horizontal - Low)
uint8_t htimel;
//! @brief IRQ Timer Registers (Horizontal - High)
uint8_t htimeh;
//! @brief IRQ Timer Registers (Vertical - Low)
uint8_t vtimel;
//! @brief IRQ Timer Registers (Vertical - High)
uint8_t vtimeh;
//! @brief DMA Enable Register
uint8_t mdmaen;
//! @brief HDMA Enable Register
uint8_t hdmaen;
//! @brief ROM Speed Register
uint8_t memsel;
//! @brief Interrupt Flag Registers
uint8_t rdnmi;
//! @brief Interrupt Flag Registers - TimeUp
uint8_t timeup;
//! @brief PPU Status Register
uint8_t hvbjoy;
//! @brief IO Port Read Register
uint8_t rdio;
//! @brief Divide Result Registers (can sometimes be used as multiplication result register) - LOW
uint8_t rddivl;
//! @brief Divide Result Registers (can sometimes be used as multiplication result register) - HIGH
uint8_t rddivh;
//! @brief Multiplication Result Registers (can sometimes be used as divide result register) - LOW
uint8_t rdmpyl;
//! @brief Multiplication Result Registers (can sometimes be used as divide result register) - HIGH
uint8_t rdmpyh;
//! @brief Controller Port Data Registers (Pad 1 - Low)
uint8_t joy1l;
//! @brief Controller Port Data Registers (Pad 1 - High)
uint8_t joy1h;
//! @brief Controller Port Data Registers (Pad 2 - Low)
uint8_t joy2l;
//! @brief Controller Port Data Registers (Pad 2 - High)
uint8_t joy2h;
//! @brief Controller Port Data Registers (Pad 3 - Low)
uint8_t joy3l;
//! @brief Controller Port Data Registers (Pad 3 - High)
uint8_t joy3h;
//! @brief Controller Port Data Registers (Pad 4 - Low)
uint8_t joy4l;
//! @brief Controller Port Data Registers (Pad 4 - High)
uint8_t joy4h;
};
//! @brief The main CPU
class CPU : public Memory::AMemory {
protected:
//! @brief All the registers of the CPU
Registers _registers{};
//! @brief Is the CPU running in emulation mode (in 8bits)
bool _isEmulationMode = true;
//! @brief Internal registers of the CPU (accessible from the bus via addr $4200 to $421F).
InternalRegisters _internalRegisters{};
//! @brief The memory bus to use for read/write.
std::shared_ptr<Memory::MemoryBus> _bus;
//! @brief The cartridge header (stored for interrupt vectors..
Cartridge::Header &_cartridgeHeader;
//! @brief True if an addressing mode with an iterator (x, y) has crossed the page. (Used because crossing the page boundary take one more cycle to run certain instructions).
bool _hasIndexCrossedPageBoundary = false;
//! @brief Immediate address mode is specified with a value in 8. (This functions returns the 24bit space address of the value).
uint24_t _getImmediateAddr8Bits();
//! @brief Immediate address mode is specified with a value in 8 or 16 bits. The value is 16 bits if the m flag is unset. (This functions returns the 24bit space address of the value).
uint24_t _getImmediateAddrForA();
//! @brief Immediate address mode is specified with a value in 8 or 16 bits. The value is 16 bits if the x flag is unset. (This functions returns the 24bit space address of the value).
uint24_t _getImmediateAddrForX();
//! @brief The destination is formed by adding the direct page register with the 8-bit address to form an effective address. (This functions returns the 24bit space address of the value).
uint24_t _getDirectAddr();
//! @brief The effective address is formed by DBR:<16-bit exp>. (This functions returns the 24bit space address of the value).
uint24_t _getAbsoluteAddr();
//! @brief The effective address is the expression. (This functions returns the 24bit space address of the value).
uint24_t _getAbsoluteLongAddr();
//! @brief The address is DBR:$(read($($Value + D)) + Y). (This functions returns the 24bit space address of the value).
uint24_t _getDirectIndirectIndexedYAddr();
//! @brief This mode is like the previous addressing mode, but the difference is that rather than pulling 2 bytes from the DP address, it pulls 3 bytes to form the effective address.
uint24_t _getDirectIndirectIndexedYLongAddr();
//! @brief The direct page address is calculated and added with x. 2 bytes from the dp address combined with DBR will form the effective address.
uint24_t _getDirectIndirectIndexedXAddr();
//! @brief The DP address is added to X to form the effective address. The effective address is always in bank 0.
uint24_t _getDirectIndexedByXAddr();
//! @brief The DP address is added to Y to form the effective address. The effective address is always in bank 0.
uint24_t _getDirectIndexedByYAddr();
//! @brief The absolute expression is added with X and combined with DBR to form the effective address.
uint24_t _getAbsoluteIndexedByXAddr();
//! @brief The absolute expression is added with Y and combined with DBR to form the effective address.
uint24_t _getAbsoluteIndexedByYAddr();
//! @brief The effective address is formed by adding the <long exp> with X.
uint24_t _getAbsoluteIndexedByXLongAddr();
//! @brief 2 bytes are pulled from the <abs exp> to form the effective address.
uint24_t _getAbsoluteIndirectAddr();
//! @brief 3 bytes are pulled from the <abs exp> to form the effective address.
uint24_t _getAbsoluteIndirectLongAddr();
//! @brief The <abs exp> is added with X, then 2 bytes are pulled from that address to form the new location.
uint24_t _getAbsoluteIndirectIndexedByXAddr();
//! @brief 2 bytes are pulled from the direct page address to form the 16-bit address. It is combined with DBR to form a 24-bit effective address.
uint24_t _getDirectIndirectAddr();
//! @brief 3 bytes are pulled from the direct page address to form an effective address.
uint24_t _getDirectIndirectLongAddr();
//! @brief The stack register is added to the <8-bit exp> to form the effective address.
uint24_t _getStackRelativeAddr();
//! @brief The <8-bit exp> is added to S and combined with DBR to form the base address. Y is added to the base address to form the effective address.
uint24_t _getStackRelativeIndirectIndexedYAddr();
//! @brief Push 8 bits of data to the stack.
void _push(uint8_t data);
//! @brief Push 16 bits of data to the stack.
void _push(uint16_t data);
//! @brief Pop 8 bits of data from the stack.
uint8_t _pop();
//! @brief Pop 16 bits of data from the stack.
uint16_t _pop16();
//! @brief Return the data at the program bank concatenated with the program counter. It also increment the program counter (the program bank is not incremented on overflows).
uint8_t readPC();
//! @brief Execute a single instruction.
//! @return The number of CPU cycles that the instruction took.
virtual unsigned _executeInstruction(uint8_t opcode);
//! @brief Get the parameter address of an instruction from it's addressing mode.
//! @info The current program counter should point to the instruction's opcode + 1.
//! @return The address of the data to read on the instruction.
uint24_t _getValueAddr(Instruction &instruction);
//! @brief Break instruction - Causes a software break. The PC is loaded from a vector table.
int BRK(uint24_t, AddressingMode);
//! @brief Co-Processor Enable instruction - Causes a software break. The PC is loaded from a vector table.
int COP(uint24_t, AddressingMode);
//! @brief Return from Interrupt - Used to return from a interrupt handler.
int RTI(uint24_t, AddressingMode);
//! @brief Add with carry - Adds operand to the Accumulator; adds an additional 1 if carry is set.
int ADC(uint24_t valueAddr, AddressingMode);
//! @brief Store the accumulator to memory.
int STA(uint24_t addr, AddressingMode);
//! @brief Store the index register X to memory.
int STX(uint24_t addr, AddressingMode);
//! @brief Store the index register Y to memory.
int STY(uint24_t addr, AddressingMode);
//! @brief Store zero to the memory.
int STZ(uint24_t addr, AddressingMode);
//! @brief Load the accumulator from memory.
int LDA(uint24_t addr, AddressingMode);
//! @brief Load the X index register from memory.
int LDX(uint24_t addr, AddressingMode);
//! @brief Load the Y index register from memory.
int LDY(uint24_t addr, AddressingMode);
//! @brief Set status bits.
int SEP(uint24_t valueAddr, AddressingMode);
//! @brief Reset status bits.
int REP(uint24_t valueAddr, AddressingMode);
//! @brief Jump to subroutine
int JSR(uint24_t addr, AddressingMode);
//! @brief Jump to subroutine (long)
int JSL(uint24_t addr, AddressingMode);
//! @brief Push the accumulator to the stack.
int PHA(uint24_t, AddressingMode);
//! @brief Push the data bank register to the stack.
int PHB(uint24_t, AddressingMode);
//! @brief Push the direct page register to the stack.
int PHD(uint24_t, AddressingMode);
//! @brief Push the program bank register to the stack.
int PHK(uint24_t, AddressingMode);
//! @brief Push the processor status register to the stack.
int PHP(uint24_t, AddressingMode);
//! @brief Push the x index register to the stack.
int PHX(uint24_t, AddressingMode);
//! @brief Push the y index register to the stack.
int PHY(uint24_t, AddressingMode);
//! @brief Pull the accumulator to the stack.
int PLA(uint24_t, AddressingMode);
//! @brief Pull the data bank register to the stack.
int PLB(uint24_t, AddressingMode);
//! @brief Pull the direct page register to the stack.
int PLD(uint24_t, AddressingMode);
//! @brief Pull the processor status register to the stack.
int PLP(uint24_t, AddressingMode);
//! @brief Pull the x index register to the stack.
int PLX(uint24_t, AddressingMode);
//! @brief Pull the y index register to the stack.
int PLY(uint24_t, AddressingMode);
//! @brief Clear the carry flag.
int CLC(uint24_t, AddressingMode);
//! @brief Clear the Interrupt Disable flag.
int CLI(uint24_t, AddressingMode);
//! @brief Clear the decimal flag.
int CLD(uint24_t, AddressingMode);
//! @brief Clear the overflow flag.
int CLV(uint24_t, AddressingMode);
//! @brief Set the carry Flag.
int SEC(uint24_t, AddressingMode);
//! @brief Set the decimal flag.
int SED(uint24_t, AddressingMode);
//! @brief Set the Interrupt Disable flag.
int SEI(uint24_t, AddressingMode);
//! @brief Exchange Carry and Emulation Flags
int XCE(uint24_t, AddressingMode);
//! @brief And accumulator with memory.
int AND(uint24_t valueAddr, AddressingMode);
//! @brief Subtract with Borrow from Accumulator.
int SBC(uint24_t valueAddr, AddressingMode);
//! @brief Transfer A to X
int TAX(uint24_t, AddressingMode);
//! @brief Transfer A to Y
int TAY(uint24_t, AddressingMode);
//! @brief Transfer X to SP
int TXS(uint24_t, AddressingMode);
//! @brief Increment the X register
int INX(uint24_t, AddressingMode);
//! @brief Increment the Y register
int INY(uint24_t, AddressingMode);
//! @brief Compare the X register with the memory
int CPX(uint24_t valueAddr, AddressingMode);
//! @brief Compare the Y register with the memory
int CPY(uint24_t valueAddr, AddressingMode);
//! @brief Branch if carry clear
int BCC(uint24_t valueAddr, AddressingMode);
//! @brief Branch if carry set
int BCS(uint24_t valueAddr, AddressingMode);
//! @brief Branch if equal
int BEQ(uint24_t valueAddr, AddressingMode);
//! @brief Branch if not equal
int BNE(uint24_t valueAddr, AddressingMode);
//! @brief Branch if minus
int BMI(uint24_t valueAddr, AddressingMode);
//! @brief Branch if plus
int BPL(uint24_t valueAddr, AddressingMode);
//! @brief Branch if Overflow Clear
int BVC(uint24_t valueAddr, AddressingMode);
//! @brief Branch if Overflow Set
int BVS(uint24_t valueAddr, AddressingMode);
//! @brief Branch always
int BRA(uint24_t valueAddr, AddressingMode);
//! @brief Branch always long
int BRL(uint24_t valueAddr, AddressingMode);
//! @brief Jump.
int JMP(uint24_t valueAddr, AddressingMode);
//! @brief Long jump.
int JML(uint24_t valueAddr, AddressingMode);
//! @brief No OP.
int NOP(uint24_t, AddressingMode);
//! @brief Decrement the X register.
int DEX(uint24_t, AddressingMode);
//! @brief Decrement the Y register.
int DEY(uint24_t, AddressingMode);
//! @brief Or accumulator with memory.
int ORA(uint24_t valueAddr, AddressingMode mode);
//! @brief Return from subroutine.
int RTS(uint24_t, AddressingMode);
//! @brief Return from subroutine long.
int RTL(uint24_t, AddressingMode);
//! @brief Compare Accumulator with Memory.
int CMP(uint24_t, AddressingMode);
//! @brief Increment
int INC(uint24_t, AddressingMode);
//! @brief Decrement
int DEC(uint24_t, AddressingMode);
//! @brief XOR, Exclusive OR accumulator with memory.
int EOR(uint24_t, AddressingMode);
//! @brief Transfer 16 bit A to DP
int TCD(uint24_t, AddressingMode);
//! @brief Transfer 16 bit A to SP
int TCS(uint24_t, AddressingMode);
//! @brief Transfer DP to 16 bit A
int TDC(uint24_t, AddressingMode);
//! @brief Transfer DP to 16 bit A
int TSC(uint24_t, AddressingMode);
//! @brief Transfer SP to X
int TSX(uint24_t, AddressingMode);
//! @brief Transfer X to A
int TXA(uint24_t, AddressingMode);
//! @brief Transfer Y to A
int TYA(uint24_t, AddressingMode);
//! @brief Transfer X to Y
int TXY(uint24_t, AddressingMode);
//! @brief Transfer Y to X
int TYX(uint24_t, AddressingMode);
//! @brief Test and Set Memory Bits Against Accumulator
int TSB(uint24_t, AddressingMode);
//! @brief Exchange the B and A Accumulators
int XBA(uint24_t, AddressingMode);
//! @brief All the instructions of the CPU.
//! @info Instructions are indexed by their opcode
Instruction _instructions[0x100] = {
{&CPU::BRK, 7, "brk", AddressingMode::Immediate8bits, 2}, // 00
{&CPU::ORA, 6, "ora", AddressingMode::DirectPageIndirectIndexedByX, 2}, // 01
{&CPU::COP, 7, "cop", AddressingMode::Immediate8bits, 2}, // 02
{&CPU::ORA, 4, "ora", AddressingMode::StackRelative, 2}, // 03
{&CPU::TSB, 5, "tsb", AddressingMode::DirectPage, 2}, // 04
{&CPU::ORA, 3, "ora", AddressingMode::DirectPage, 2}, // 05
{&CPU::BRK, 7, "asl #-#", AddressingMode::Implied, 2}, // 06
{&CPU::ORA, 6, "ora", AddressingMode::DirectPageIndirectLong, 2}, // 07
{&CPU::PHP, 3, "php", AddressingMode::Implied, 3}, // 08
{&CPU::ORA, 2, "ora", AddressingMode::ImmediateForA, 2}, // 09
{&CPU::BRK, 7, "asl #-#", AddressingMode::Implied, 2}, // 0A
{&CPU::PHD, 4, "phd", AddressingMode::Implied, 1}, // 0B
{&CPU::TSB, 6, "tsb", AddressingMode::Absolute, 3}, // 0C
{&CPU::ORA, 3, "ora", AddressingMode::Absolute, 4}, // 0D
{&CPU::BRK, 7, "asl #-#", AddressingMode::Implied, 2}, // 0E
{&CPU::ORA, 5, "ora", AddressingMode::AbsoluteLong, 5}, // 0F
{&CPU::BPL, 7, "bpl", AddressingMode::Immediate8bits, 2}, // 10
{&CPU::ORA, 5, "ora", AddressingMode::DirectPageIndirectIndexedByY, 2}, // 11
{&CPU::ORA, 5, "ora", AddressingMode::DirectPageIndirect, 2}, // 12
{&CPU::ORA, 7, "ora", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // 13
{&CPU::BRK, 7, "trb #-#", AddressingMode::Implied, 2}, // 14
{&CPU::ORA, 4, "ora", AddressingMode::DirectPageIndexedByX, 2}, // 15
{&CPU::BRK, 7, "asl #-#", AddressingMode::Implied, 2}, // 16
{&CPU::ORA, 6, "ora", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // 17
{&CPU::CLC, 2, "clc", AddressingMode::Implied, 1}, // 18
{&CPU::ORA, 4, "ora", AddressingMode::AbsoluteIndexedByY, 3}, // 19
{&CPU::INC, 2, "inc", AddressingMode::Implied, 1}, // 1A
{&CPU::TCS, 2, "tcs", AddressingMode::Implied, 1}, // 1B
{&CPU::BRK, 7, "trb #-#", AddressingMode::Implied, 2}, // 1C
{&CPU::ORA, 4, "ora", AddressingMode::AbsoluteIndexedByX, 3}, // 1D
{&CPU::BRK, 7, "asl #-#", AddressingMode::Implied, 2}, // 1E
{&CPU::ORA, 5, "ora", AddressingMode::AbsoluteIndexedByXLong, 4}, // 1F
{&CPU::JSR, 6, "jsr", AddressingMode::Absolute, 3}, // 20
{&CPU::AND, 6, "and", AddressingMode::DirectPageIndirectIndexedByX, 2}, // 21
{&CPU::JSL, 8, "jsl", AddressingMode::AbsoluteLong, 4}, // 22
{&CPU::AND, 4, "and", AddressingMode::StackRelative, 2}, // 23
{&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 24
{&CPU::AND, 3, "and", AddressingMode::DirectPage, 2}, // 25
{&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 26
{&CPU::AND, 6, "and", AddressingMode::DirectPageIndirectLong, 2}, // 27
{&CPU::PLP, 4, "plp", AddressingMode::Implied, 1}, // 28
{&CPU::AND, 2, "and", AddressingMode::ImmediateForA, 2}, // 29
{&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 2A
{&CPU::PLD, 5, "pld", AddressingMode::Implied, 1}, // 2B
{&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 2C
{&CPU::AND, 4, "and", AddressingMode::Absolute, 3}, // 2D
{&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 2E
{&CPU::AND, 5, "and", AddressingMode::AbsoluteLong, 4}, // 2F
{&CPU::BMI, 2, "bmi", AddressingMode::Immediate8bits, 2}, // 30
{&CPU::AND, 5, "and", AddressingMode::DirectPageIndirectIndexedByY, 2}, // 31
{&CPU::AND, 5, "and", AddressingMode::DirectPageIndirect, 2}, // 32
{&CPU::AND, 7, "and", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // 33
{&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 34
{&CPU::AND, 4, "and", AddressingMode::DirectPageIndexedByX, 2}, // 35
{&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 36
{&CPU::AND, 6, "and", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // 37
{&CPU::SEC, 2, "sec", AddressingMode::Implied, 1}, // 38
{&CPU::AND, 4, "and", AddressingMode::AbsoluteIndexedByY, 3}, // 39
{&CPU::DEC, 2, "dec", AddressingMode::Implied, 1}, // 3A
{&CPU::TSC, 2, "tsc", AddressingMode::Implied, 1}, // 3B
{&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 3C
{&CPU::AND, 4, "and", AddressingMode::AbsoluteIndexedByX, 3}, // 3D
{&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 3E
{&CPU::AND, 5, "and", AddressingMode::AbsoluteIndexedByXLong, 4}, // 3F
{&CPU::RTI, 6, "rti", AddressingMode::Implied, 1}, // 40
{&CPU::EOR, 6, "eor", AddressingMode::DirectPageIndirectIndexedByX, 2}, // 41
{&CPU::BRK, 7, "wdm #-#", AddressingMode::Implied, 2}, // 42
{&CPU::EOR, 4, "eor", AddressingMode::StackRelative, 2}, // 43
{&CPU::BRK, 7, "mvp #-#", AddressingMode::Implied, 2}, // 44
{&CPU::EOR, 3, "eor", AddressingMode::DirectPage, 2}, // 45
{&CPU::BRK, 7, "lsr #-#", AddressingMode::Implied, 2}, // 46
{&CPU::EOR, 6, "eor", AddressingMode::DirectPageIndirectLong, 2}, // 47
{&CPU::PHA, 3, "pha", AddressingMode::Implied, 1}, // 48
{&CPU::EOR, 2, "eor", AddressingMode::ImmediateForA, 2}, // 49
{&CPU::BRK, 7, "lsr #-#", AddressingMode::Implied, 2}, // 4A
{&CPU::PHK, 3, "phk", AddressingMode::Implied, 1}, // 4B
{&CPU::JMP, 3, "jmp", AddressingMode::Absolute, 3}, // 4C
{&CPU::EOR, 4, "eor", AddressingMode::Absolute, 3}, // 4D
{&CPU::BRK, 7, "lsr #-#", AddressingMode::Implied, 2}, // 4E
{&CPU::EOR, 5, "eor", AddressingMode::AbsoluteLong, 4}, // 4F
{&CPU::BVC, 2, "bvc", AddressingMode::Immediate8bits, 2}, // 50
{&CPU::EOR, 5, "eor", AddressingMode::DirectPageIndirectIndexedByY, 2}, // 51
{&CPU::EOR, 5, "eor", AddressingMode::DirectPageIndirect, 2}, // 52
{&CPU::EOR, 4, "eor", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // 53
{&CPU::BRK, 7, "mvn #-#", AddressingMode::Implied, 2}, // 54
{&CPU::EOR, 4, "eor", AddressingMode::DirectPageIndexedByX, 2}, // 55
{&CPU::BRK, 7, "lsr #-#", AddressingMode::Implied, 2}, // 56
{&CPU::EOR, 6, "eor", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // 57
{&CPU::CLI, 2, "cli", AddressingMode::Implied, 1}, // 58
{&CPU::EOR, 4, "eor", AddressingMode::AbsoluteIndexedByY, 3}, // 59
{&CPU::PHY, 3, "phy", AddressingMode::Implied, 1}, // 5A
{&CPU::TCD, 2, "tcd", AddressingMode::Implied, 1}, // 5B
{&CPU::JML, 4, "jml", AddressingMode::Implied, 4}, // 5C
{&CPU::EOR, 4, "eor", AddressingMode::AbsoluteIndexedByX, 3}, // 5D
{&CPU::BRK, 7, "lsr #-#", AddressingMode::Implied, 2}, // 5E
{&CPU::EOR, 5, "eor", AddressingMode::AbsoluteIndexedByXLong, 4}, // 5F
{&CPU::RTL, 6, "rtl", AddressingMode::Implied, 1}, // 60
{&CPU::ADC, 6, "adc", AddressingMode::DirectPageIndirectIndexedByX, 2}, // 61
{&CPU::BRK, 7, "per #-#", AddressingMode::Implied, 2}, // 62
{&CPU::ADC, 4, "adc", AddressingMode::StackRelative, 2}, // 63
{&CPU::STZ, 3, "stz", AddressingMode::DirectPage, 2}, // 64
{&CPU::ADC, 3, "adc", AddressingMode::DirectPage, 2}, // 65
{&CPU::BRK, 7, "ror #-#", AddressingMode::Implied, 2}, // 66
{&CPU::ADC, 6, "adc", AddressingMode::DirectPageIndirectLong, 2}, // 67
{&CPU::PLA, 4, "pla", AddressingMode::Implied, 1}, // 68
{&CPU::ADC, 2, "adc", AddressingMode::ImmediateForA, 2}, // 69
{&CPU::BRK, 7, "ror #-#", AddressingMode::Implied, 2}, // 6A
{&CPU::RTS, 6, "rts", AddressingMode::Implied, 1}, // 6B
{&CPU::JMP, 5, "jmp", AddressingMode::AbsoluteIndirect, 3}, // 6C
{&CPU::ADC, 4, "adc", AddressingMode::Absolute, 3}, // 6D
{&CPU::BRK, 7, "ror #-#", AddressingMode::Implied, 2}, // 6E
{&CPU::ADC, 5, "adc", AddressingMode::AbsoluteLong, 4}, // 6F
{&CPU::BVS, 2, "bvs", AddressingMode::Immediate8bits, 2}, // 70
{&CPU::ADC, 5, "adc", AddressingMode::DirectPageIndirectIndexedByY, 2}, // 71
{&CPU::ADC, 5, "adc", AddressingMode::DirectPageIndirect, 2}, // 72
{&CPU::ADC, 7, "adc", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // 73
{&CPU::STZ, 4, "stz", AddressingMode::DirectPageIndexedByX, 2}, // 74
{&CPU::ADC, 4, "adc", AddressingMode::DirectPageIndexedByX, 2}, // 75
{&CPU::BRK, 7, "ror #-#", AddressingMode::Implied, 2}, // 76
{&CPU::ADC, 6, "adc", AddressingMode::DirectPageIndirectIndexedByY, 2}, // 77
{&CPU::SEI, 2, "sei", AddressingMode::Implied, 1}, // 78
{&CPU::ADC, 4, "adc", AddressingMode::AbsoluteIndexedByY, 2}, // 79
{&CPU::PLY, 4, "ply", AddressingMode::Implied, 1}, // 7A
{&CPU::TDC, 2, "tdc", AddressingMode::Implied, 1}, // 7B
{&CPU::JMP, 6, "jmp", AddressingMode::AbsoluteIndirectIndexedByX, 3}, // 7C
{&CPU::ADC, 4, "adc", AddressingMode::AbsoluteIndexedByX, 3}, // 7D
{&CPU::BRK, 7, "ror #-#", AddressingMode::Implied, 2}, // 7E
{&CPU::ADC, 5, "adc", AddressingMode::AbsoluteIndexedByXLong, 4}, // 7F
{&CPU::BRA, 3, "bra", AddressingMode::Immediate8bits, 2}, // 80
{&CPU::STA, 6, "sta", AddressingMode::DirectPageIndexedByX, 2}, // 81
{&CPU::BRL, 4, "brl", AddressingMode::Absolute, 3}, // 82
{&CPU::STA, 4, "sta", AddressingMode::StackRelative, 2}, // 83
{&CPU::STY, 3, "sty", AddressingMode::DirectPage, 2}, // 84
{&CPU::STA, 3, "sta", AddressingMode::DirectPage, 2}, // 85
{&CPU::STX, 3, "stx", AddressingMode::DirectPage, 2}, // 86
{&CPU::STA, 6, "sta", AddressingMode::DirectPageIndirectLong, 2}, // 87
{&CPU::DEY, 2, "dey", AddressingMode::Implied, 1}, // 88
{&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 89
{&CPU::TXA, 2, "txa", AddressingMode::Implied, 2}, // 8A
{&CPU::PHB, 3, "phb", AddressingMode::Implied, 1}, // 8B
{&CPU::STY, 4, "sty", AddressingMode::Absolute, 3}, // 8C
{&CPU::STA, 4, "sta", AddressingMode::Absolute, 3}, // 8D
{&CPU::STX, 4, "stx", AddressingMode::Absolute, 3}, // 8E
{&CPU::STA, 5, "sta", AddressingMode::AbsoluteLong, 4}, // 8F
{&CPU::BCC, 2, "bcc", AddressingMode::Immediate8bits, 2}, // 90
{&CPU::STA, 6, "sta", AddressingMode::DirectPageIndirectIndexedByY, 2}, // 91
{&CPU::STA, 5, "sta", AddressingMode::DirectPageIndirect, 2}, // 92
{&CPU::STA, 7, "sta", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // 93
{&CPU::STY, 4, "sty", AddressingMode::DirectPageIndirectIndexedByX, 2}, // 94
{&CPU::STA, 4, "sta", AddressingMode::DirectPageIndexedByX, 2}, // 95
{&CPU::STX, 4, "stx", AddressingMode::DirectPageIndexedByY, 2}, // 96
{&CPU::STA, 6, "sta", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // 97
{&CPU::TYA, 2, "tya", AddressingMode::Implied, 1}, // 98
{&CPU::STA, 5, "sta", AddressingMode::AbsoluteIndexedByY, 3}, // 99
{&CPU::TXS, 2, "txs", AddressingMode::Implied, 1}, // 9A
{&CPU::TXY, 2, "txy", AddressingMode::Implied, 1}, // 9B
{&CPU::STZ, 4, "stz", AddressingMode::Absolute, 3}, // 9C
{&CPU::STA, 5, "sta", AddressingMode::AbsoluteIndexedByX, 3}, // 9D
{&CPU::STZ, 5, "stz", AddressingMode::AbsoluteIndexedByX, 3}, // 9E
{&CPU::STA, 5, "sta", AddressingMode::AbsoluteIndexedByXLong, 4}, // 9F
{&CPU::LDY, 2, "ldy", AddressingMode::ImmediateForX, 2}, // A0
{&CPU::LDA, 6, "lda", AddressingMode::DirectPageIndirectIndexedByX, 2}, // A1
{&CPU::LDX, 2, "ldx", AddressingMode::ImmediateForX, 2}, // A2
{&CPU::LDA, 4, "lda", AddressingMode::StackRelative, 2}, // A3
{&CPU::LDY, 3, "ldy", AddressingMode::DirectPage, 2}, // A4
{&CPU::LDA, 3, "lda", AddressingMode::DirectPage, 2}, // A5
{&CPU::LDX, 3, "ldx", AddressingMode::DirectPage, 2}, // A6
{&CPU::LDA, 6, "lda", AddressingMode::DirectPageIndirectLong, 2}, // A7
{&CPU::TAY, 2, "tay", AddressingMode::Implied, 1}, // A8
{&CPU::LDA, 2, "lda", AddressingMode::ImmediateForA, 2}, // A9
{&CPU::TAX, 2, "tax", AddressingMode::Implied, 1}, // AA
{&CPU::BRK, 7, "trb #-#", AddressingMode::Implied, 2}, // AB
{&CPU::LDY, 4, "ldy", AddressingMode::Absolute, 4}, // AC
{&CPU::LDA, 4, "lda", AddressingMode::Absolute, 3}, // AD
{&CPU::LDX, 4, "ldx", AddressingMode::Absolute, 3}, // AE
{&CPU::LDA, 5, "lda", AddressingMode::AbsoluteLong, 4}, // AF
{&CPU::BCS, 2, "bcs", AddressingMode::Immediate8bits, 2}, // B0
{&CPU::LDA, 5, "lda", AddressingMode::DirectPageIndirectIndexedByY, 2}, // B1
{&CPU::LDA, 5, "lda", AddressingMode::DirectPageIndirect, 2}, // B2
{&CPU::LDA, 7, "lda", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // B3
{&CPU::LDY, 4, "ldy", AddressingMode::DirectPageIndexedByX, 2}, // B4
{&CPU::LDA, 4, "lda", AddressingMode::DirectPageIndexedByX, 2}, // B5
{&CPU::LDX, 4, "ldx", AddressingMode::DirectPageIndexedByY, 2}, // B6
{&CPU::LDA, 6, "lda", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // B7
{&CPU::CLV, 7, "clv", AddressingMode::Implied, 1}, // B8
{&CPU::LDA, 4, "lda", AddressingMode::AbsoluteIndexedByY, 3}, // B9
{&CPU::TSX, 2, "tsx", AddressingMode::Implied, 1}, // BA
{&CPU::TYX, 2, "tyx", AddressingMode::Implied, 1}, // BB
{&CPU::LDY, 4, "ldy", AddressingMode::AbsoluteIndexedByX, 3}, // BC
{&CPU::LDA, 4, "lda", AddressingMode::AbsoluteIndexedByX, 3}, // BD
{&CPU::LDX, 4, "ldx", AddressingMode::AbsoluteIndexedByY, 3}, // BE
{&CPU::LDA, 5, "lda", AddressingMode::AbsoluteIndexedByXLong, 4}, // BF
{&CPU::CPY, 2, "cpy", AddressingMode::ImmediateForX, 2}, // C0
{&CPU::CMP, 6, "cmp", AddressingMode::DirectPageIndirectIndexedByX, 2}, // C1
{&CPU::REP, 3, "rep", AddressingMode::Immediate8bits, 2}, // C2
{&CPU::CMP, 4, "cmp", AddressingMode::StackRelative, 2}, // C3
{&CPU::CPY, 3, "cpy", AddressingMode::DirectPage, 2}, // C4
{&CPU::CMP, 3, "cmp", AddressingMode::DirectPage, 2}, // C5
{&CPU::DEC, 5, "dec", AddressingMode::DirectPage, 2}, // C6
{&CPU::CMP, 6, "cmp", AddressingMode::DirectPageIndirectLong, 2}, // C7
{&CPU::INY, 2, "iny", AddressingMode::Implied, 1}, // C8
{&CPU::CMP, 2, "cmp", AddressingMode::ImmediateForA, 2}, // C9
{&CPU::DEX, 2, "dex", AddressingMode::Implied, 1}, // CA
{&CPU::BRK, 7, "wai #-#", AddressingMode::Implied, 2}, // CB
{&CPU::CPY, 4, "cpy", AddressingMode::Absolute, 3}, // CC
{&CPU::CMP, 4, "cmp", AddressingMode::Absolute, 3}, // CD
{&CPU::DEC, 6, "dec", AddressingMode::Absolute, 3}, // CE
{&CPU::CMP, 6, "cmp", AddressingMode::AbsoluteLong, 4}, // CF
{&CPU::BNE, 2, "bne", AddressingMode::Immediate8bits, 2}, // D0
{&CPU::CMP, 5, "cmp", AddressingMode::DirectPageIndirectIndexedByY, 2}, // D1
{&CPU::CMP, 5, "cmp", AddressingMode::DirectPageIndirect, 2}, // D2
{&CPU::CMP, 7, "cmp", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // D3
{&CPU::BRK, 7, "pei #-#", AddressingMode::Implied, 2}, // D4
{&CPU::CMP, 4, "cmp", AddressingMode::DirectPageIndexedByX, 2}, // D5
{&CPU::DEC, 6, "dec", AddressingMode::DirectPageIndexedByX, 2}, // D6
{&CPU::CMP, 6, "cmp", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // D7
{&CPU::CLD, 2, "cld", AddressingMode::Implied, 2}, // D8
{&CPU::CMP, 4, "cmp", AddressingMode::AbsoluteIndexedByY, 3}, // D9
{&CPU::PHX, 3, "phx", AddressingMode::Implied, 1}, // DA
{&CPU::BRK, 7, "stp #-#", AddressingMode::Implied, 2}, // DB
{&CPU::JML, 7, "jml", AddressingMode::AbsoluteIndirectLong, 2}, // DC
{&CPU::CMP, 4, "cmp", AddressingMode::AbsoluteIndexedByX, 3}, // DD
{&CPU::DEC, 7, "dec", AddressingMode::AbsoluteIndexedByX, 3}, // DE
{&CPU::CMP, 5, "cmp", AddressingMode::AbsoluteIndexedByXLong, 4}, // DF
{&CPU::CPX, 2, "cpx", AddressingMode::ImmediateForX, 2}, // E0
{&CPU::SBC, 6, "sbc", AddressingMode::DirectPageIndirectIndexedByX, 2}, // E1
{&CPU::SEP, 3, "sep", AddressingMode::Immediate8bits, 2}, // E2
{&CPU::SBC, 4, "sbc", AddressingMode::StackRelative, 2}, // E3
{&CPU::CPX, 3, "cpx", AddressingMode::DirectPage, 2}, // E4
{&CPU::SBC, 3, "sbc", AddressingMode::DirectPage, 2}, // E5
{&CPU::INC, 5, "inc", AddressingMode::DirectPage, 2}, // E6
{&CPU::SBC, 6, "sbc", AddressingMode::DirectPageIndirectLong, 2}, // E7
{&CPU::INX, 2, "inx", AddressingMode::Implied, 1}, // E8
{&CPU::SBC, 2, "sbc", AddressingMode::ImmediateForA, 2}, // E9
{&CPU::NOP, 2, "nop", AddressingMode::Implied, 1}, // EA
{&CPU::XBA, 3, "xba", AddressingMode::Implied, 1}, // EB
{&CPU::CPX, 4, "cpx", AddressingMode::Absolute, 3}, // EC
{&CPU::SBC, 4, "sbc", AddressingMode::Absolute, 3}, // ED
{&CPU::INC, 6, "inc", AddressingMode::Absolute, 3}, // EE
{&CPU::SBC, 5, "sbc", AddressingMode::AbsoluteLong, 4}, // EF
{&CPU::BEQ, 2, "beq", AddressingMode::Immediate8bits, 2}, // F0
{&CPU::SBC, 5, "sbc", AddressingMode::DirectPageIndirectIndexedByY, 2}, // F1
{&CPU::SBC, 5, "sbc", AddressingMode::DirectPageIndirect, 2}, // F2
{&CPU::SBC, 7, "sbc", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // F3
{&CPU::BRK, 7, "pea #-#", AddressingMode::Implied, 2}, // F4
{&CPU::SBC, 4, "sbc", AddressingMode::DirectPageIndexedByX, 2}, // F5
{&CPU::INC, 6, "inc", AddressingMode::DirectPageIndexedByX, 2}, // F6
{&CPU::SBC, 6, "sbc", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // F7
{&CPU::SED, 2, "sed", AddressingMode::Implied, 1}, // F8
{&CPU::SBC, 4, "sbc", AddressingMode::AbsoluteIndexedByY, 3}, // F9
{&CPU::PLX, 4, "plx", AddressingMode::Implied, 1}, // FA
{&CPU::XCE, 2, "xce", AddressingMode::Implied, 1}, // FB
{&CPU::JSR, 8, "jsr", AddressingMode::AbsoluteIndirectIndexedByX, 3}, // FC
{&CPU::SBC, 4, "sbc", AddressingMode::AbsoluteIndexedByX, 3}, // FD
{&CPU::INC, 7, "inc", AddressingMode::AbsoluteIndexedByX, 3}, // FE
{&CPU::SBC, 5, "sbc", AddressingMode::AbsoluteIndexedByXLong, 4}, // FF
};
public:
explicit CPU(std::shared_ptr<Memory::MemoryBus> bus, Cartridge::Header &cartridgeHeader);
CPU(const CPU &) = default;
CPU &operator=(const CPU &) = delete;
~CPU() override = default;
//! @brief This function continue to execute the Cartridge code.
//! @return The number of CPU cycles that elapsed
virtual unsigned update();
//! @brief Read from the internal CPU register.
//! @param addr The address to read from. The address 0x0 should refer to the first byte of the register.
//! @throw InvalidAddress will be thrown if the address is more than $1F (the number of register).
//! @return Return the value of the register.
uint8_t read(uint24_t addr) override;
//! @brief Write data to the internal CPU register.
//! @param addr The address to write to. The address 0x0 should refer to the first byte of register.
//! @param data The new value of the register.
//! @throw InvalidAddress will be thrown if the address is more than $1F (the number of register).
void write(uint24_t addr, uint8_t data) override;
//! @brief Get the name of this accessor (used for debug purpose)
std::string getName() override;
//! @brief Get the component of this accessor (used for debug purpose)
Component getComponent() override;
//! @brief Reset interrupt - Called on boot and when the reset button is pressed.
virtual int RESB();
//! @brief Return true if the CPU is overloaded with debugging features.
virtual bool isDebugger();
//! @brief Change the memory bus used by the CPU.
void setMemoryBus(std::shared_ptr<Memory::MemoryBus> bus);
};
}
#endif //COMSQUARE_CPU_HPP