/* * This file is part of libsidplayfp, a SID player engine. * * Copyright 2011-2013 Leandro Nini * Copyright 2007-2010 Antti Lankila * Copyright 2000 Simon White * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef MOS6510_H #define MOS6510_H #include #include #include "flags.h" #include "EventScheduler.h" #ifdef HAVE_CONFIG_H # include "config.h" #endif class EventContext; namespace libsidplayfp { #ifdef DEBUG class MOS6510; namespace MOS6510Debug { void DumpState(event_clock_t time, MOS6510 &cpu); } #endif /** * Cycle-exact 6502/6510 emulation core. * * Code is based on work by Simon A. White . * Original Java port by Ken Händel. Later on, it has been hacked to * improve compatibility with Lorenz suite on VICE's test suite. * * @author alankila */ class MOS6510 { #ifdef DEBUG friend void MOS6510Debug::DumpState(event_clock_t time, MOS6510 &cpu); #endif private: static const char *credit; private: /** * IRQ/NMI magic limit values. * Need to be larger than about 0x103 << 3, * but can't be min/max for Integer type. */ static const int MAX = 65536; /// Stack page location static const uint8_t SP_PAGE = 0x01; public: /// Status register interrupt bit. static const int SR_INTERRUPT = 2; private: struct ProcessorCycle { void (MOS6510::*func)(); bool nosteal; ProcessorCycle() : func(0), nosteal(false) {} }; private: /// Our event context copy. */ EventContext &eventContext; /// Current instruction and subcycle within instruction int cycleCount; /// When IRQ was triggered. -MAX means "during some previous instruction", MAX means "no IRQ" int interruptCycle; /// IRQ asserted on CPU bool irqAssertedOnPin; /// NMI requested? bool nmiFlag; /// RST requested? bool rstFlag; /// RDY pin state (stop CPU on read) bool rdy; /// Status register Flags flags; // Data regarding current instruction uint_least16_t Register_ProgramCounter; uint_least16_t Cycle_EffectiveAddress; uint_least16_t Cycle_HighByteWrongEffectiveAddress; uint_least16_t Cycle_Pointer; uint8_t Cycle_Data; uint8_t Register_StackPointer; uint8_t Register_Accumulator; uint8_t Register_X; uint8_t Register_Y; #ifdef DEBUG // Debug info uint_least16_t instrStartPC; uint_least16_t instrOperand; FILE *m_fdbg; bool dodump; #endif /// Table of CPU opcode implementations struct ProcessorCycle instrTable[0x101 << 3]; private: /// Represents an instruction subcycle that writes EventCallback m_nosteal; /// Represents an instruction subcycle that reads EventCallback m_steal; void eventWithoutSteals(); void eventWithSteals(); void Initialise(); // Declare Interrupt Routines inline void IRQLoRequest(); inline void IRQHiRequest(); inline void interruptsAndNextOpcode(); inline void calculateInterruptTriggerCycle(); // Declare Instruction Routines inline void fetchNextOpcode(); inline void throwAwayFetch(); inline void throwAwayRead(); inline void FetchDataByte(); inline void FetchLowAddr(); inline void FetchLowAddrX(); inline void FetchLowAddrY(); inline void FetchHighAddr(); inline void FetchHighAddrX(); inline void FetchHighAddrX2(); inline void FetchHighAddrY(); inline void FetchHighAddrY2(); inline void FetchLowEffAddr(); inline void FetchHighEffAddr(); inline void FetchHighEffAddrY(); inline void FetchHighEffAddrY2(); inline void FetchLowPointer(); inline void FetchLowPointerX(); inline void FetchHighPointer(); inline void FetchEffAddrDataByte(); inline void PutEffAddrDataByte(); inline void PushLowPC(); inline void PushHighPC(); inline void PushSR(); inline void PopLowPC(); inline void PopHighPC(); inline void PopSR(); inline void brkPushLowPC(); inline void WasteCycle(); // Delcare Instruction Operation Routines inline void adc_instr(); inline void alr_instr(); inline void anc_instr(); inline void and_instr(); inline void ane_instr(); inline void arr_instr(); inline void asl_instr(); inline void asla_instr(); inline void aso_instr(); inline void axa_instr(); inline void axs_instr(); inline void bcc_instr(); inline void bcs_instr(); inline void beq_instr(); inline void bit_instr(); inline void bmi_instr(); inline void bne_instr(); inline void branch_instr(bool condition); inline void bpl_instr(); inline void brk_instr(); inline void bvc_instr(); inline void bvs_instr(); inline void clc_instr(); inline void cld_instr(); inline void cli_instr(); inline void clv_instr(); inline void cmp_instr(); inline void cpx_instr(); inline void cpy_instr(); inline void dcm_instr(); inline void dec_instr(); inline void dex_instr(); inline void dey_instr(); inline void eor_instr(); inline void inc_instr(); inline void ins_instr(); inline void inx_instr(); inline void iny_instr(); inline void jmp_instr(); inline void las_instr(); inline void lax_instr(); inline void lda_instr(); inline void ldx_instr(); inline void ldy_instr(); inline void lse_instr(); inline void lsr_instr(); inline void lsra_instr(); inline void oal_instr(); inline void ora_instr(); inline void pha_instr(); inline void pla_instr(); inline void plp_instr(); inline void rla_instr(); inline void rol_instr(); inline void rola_instr(); inline void ror_instr(); inline void rora_instr(); inline void rra_instr(); inline void rti_instr(); inline void rts_instr(); inline void sbx_instr(); inline void say_instr(); inline void sbc_instr(); inline void sec_instr(); inline void sed_instr(); inline void sei_instr(); inline void shs_instr(); inline void sta_instr(); inline void stx_instr(); inline void sty_instr(); inline void tax_instr(); inline void tay_instr(); inline void tsx_instr(); inline void txa_instr(); inline void txs_instr(); inline void tya_instr(); inline void xas_instr(); void illegal_instr(); // Declare Arithmetic Operations inline void doADC(); inline void doSBC(); inline void doJSR(); protected: MOS6510(EventContext *context); ~MOS6510() {} public: /** * Get data from system environment. * * @param address * @return data byte CPU requested */ virtual uint8_t cpuRead(uint_least16_t addr) =0; /** * Write data to system environment. * * @param address * @param data */ virtual void cpuWrite(uint_least16_t addr, uint8_t data) =0; #ifdef PC64_TESTSUITE virtual void loadFile(const char *file) =0; #endif void reset(); static const char *credits() { return credit; } void debug(bool enable, FILE *out); void setRDY(bool newRDY); // Non-standard functions void triggerRST(); void triggerNMI(); void triggerIRQ(); void clearIRQ(); }; } #endif // MOS6510_H