/* * This file is part of libsidplayfp, a SID player engine. * * Copyright 2011-2014 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 C64_H #define C64_H #include #include #include #include "Banks/IOBank.h" #include "Banks/ColorRAMBank.h" #include "Banks/DisconnectedBusBank.h" #include "Banks/SidBank.h" #include "Banks/ExtraSidBank.h" #include "EventScheduler.h" #include "c64/c64env.h" #include "c64/c64cpu.h" #include "c64/c64cia.h" #include "c64/c64vic.h" #include "c64/mmu.h" #include "sidcxx11.h" #ifdef HAVE_CONFIG_H # include "config.h" #endif class sidmemory; namespace libsidplayfp { class c64sid; #ifdef PC64_TESTSUITE class testEnv { public: virtual ~testEnv() {} virtual void load(const char *) =0; }; #endif /** * Commodore 64 emulation core. * * It consists of the following chips: * - CPU 6510 * - VIC-II 6567/6569/6572 * - CIA 6526 * - SID 6581/8580 * - PLA 7700/82S100 * - Color RAM 2114 * - System RAM 4164-20/50464-150 * - Character ROM 2332 * - Basic ROM 2364 * - Kernal ROM 2364 */ class c64: private c64env { public: typedef enum { PAL_B = 0 ///< PAL C64 ,NTSC_M ///< NTSC C64 ,OLD_NTSC_M ///< Old NTSC C64 ,PAL_N ///< C64 Drean } model_t; private: typedef std::map sidBankMap_t; private: /// System clock frequency double m_cpuFreq; /// Number of sources asserting IRQ int irqCount; /// BA state bool oldBAState; /// System event context EventScheduler m_scheduler; /// CPU c64cpu cpu; /// CIA1 c64cia1 cia1; /// CIA2 c64cia2 cia2; /// VIC c64vic vic; /// Color RAM ColorRAMBank colorRAMBank; /// SID SidBank sidBank; /// Extra SIDs sidBankMap_t extraSidBanks; /// I/O Area #1 and #2 DisconnectedBusBank disconnectedBusBank; /// I/O Area IOBank ioBank; /// MMU chip MMU mmu; private: static double getCpuFreq(model_t model); private: /** * Access memory as seen by CPU. * * @param addr the address where to read from * @return value at address */ uint8_t cpuRead(uint_least16_t addr) override { return mmu.cpuRead(addr); } /** * Access memory as seen by CPU. * * @param addr the address where to write to * @param data the value to write */ void cpuWrite(uint_least16_t addr, uint8_t data) override { mmu.cpuWrite(addr, data); } /** * IRQ trigger signal. * * Calls permitted any time, but normally originated by chips at PHI1. * * @param state */ inline void interruptIRQ(bool state) override; /** * NMI trigger signal. * * Calls permitted any time, but normally originated by chips at PHI1. */ inline void interruptNMI() override { cpu.triggerNMI(); } /** * Reset signal. */ inline void interruptRST() override { cpu.triggerRST(); } /** * BA signal. * * Calls permitted during PHI1. * * @param state */ inline void setBA(bool state) override; inline void lightpen(bool state) override; #ifdef PC64_TESTSUITE testEnv *m_env; void loadFile(const char *file) override { m_env->load(file); } #endif void resetIoBank(); public: c64(); ~c64() {} #ifdef PC64_TESTSUITE void setTestEnv(testEnv *env) { m_env = env; } #endif /** * Get C64's event scheduler * * @return the scheduler */ //@{ EventScheduler *getEventScheduler() { return &m_scheduler; } const EventScheduler &getEventScheduler() const { return m_scheduler; } //@} void debug(bool enable, FILE *out) { cpu.debug(enable, out); } void reset(); void resetCpu() { cpu.reset(); } /** * Set the c64 model. */ void setModel(model_t model); void setRoms(const uint8_t* kernal, const uint8_t* basic, const uint8_t* character) { mmu.setRoms(kernal, basic, character); } /** * Get the CPU clock speed. * * @return the speed in Hertz */ double getMainCpuSpeed() const { return m_cpuFreq; } /** * Set the base SID. * * @param s the sid emu to set */ void setBaseSid(c64sid *s); /** * Add an extra SID. * * @param s the sid emu to set * @param sidAddress * base address (e.g. 0xd420) * * @return false if address is unsupported */ bool addExtraSid(c64sid *s, int address); /** * Remove all the SIDs. */ void clearSids(); /** * Get the components credits */ //@{ const char* cpuCredits() const { return cpu.credits(); } const char* ciaCredits() const { return cia1.credits(); } const char* vicCredits() const { return vic.credits(); } //@} sidmemory *getMemInterface() { return &mmu; } uint_least16_t getCia1TimerA() const { return cia1.getTimerA(); } }; void c64::interruptIRQ(bool state) { if (state) { if (irqCount == 0) cpu.triggerIRQ(); irqCount ++; } else { irqCount --; if (irqCount == 0) cpu.clearIRQ(); } } void c64::setBA(bool state) { // only react to changes in state if (state == oldBAState) return; oldBAState = state; // Signal changes in BA to interested parties cpu.setRDY(state); } void c64::lightpen(bool state) { if (state) vic.triggerLightpen(); else vic.clearLightpen(); } } #endif // C64_H