libsidplayfp  1.0.3
SystemROMBanks.h
00001 /*
00002  * This file is part of libsidplayfp, a SID player engine.
00003  *
00004  * Copyright 2012-2013 Leandro Nini <drfiemost@users.sourceforge.net>
00005  * Copyright 2010 Antti Lankila
00006  *
00007  * This program is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2 of the License, or
00010  * (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00020  */
00021 
00022 #ifndef SYSTEMROMBANKS_H
00023 #define SYSTEMROMBANKS_H
00024 
00025 #include <string.h>
00026 #include <stdint.h>
00027 
00028 #include "Bank.h"
00029 #include "sidplayfp/c64/CPU/opcodes.h"
00030 
00035 template <int N>
00036 class romBank : public Bank
00037 {
00038 protected:
00040     uint8_t rom[N];
00041 
00042 protected:
00044     void setVal(uint_least16_t address, uint8_t val) { rom[address & (N-1)]=val; }
00045 
00047     uint8_t getVal(uint_least16_t address) const { return rom[address & (N-1)]; }
00048 
00050     void* getPtr(uint_least16_t address) const { return (void*)&rom[address & (N-1)]; }
00051 
00052 public:
00054     void set(const uint8_t* source) { if (source) memcpy(rom, source, N); }
00055 
00057     void poke(uint_least16_t address SID_UNUSED, uint8_t value SID_UNUSED) {}
00058 
00059     uint8_t peek(uint_least16_t address) { return rom[address & (N-1)]; }
00060 };
00061 
00065 class KernalRomBank : public romBank<0x2000>
00066 {
00067 private:
00068     uint8_t resetVectorLo;  // 0xfffc
00069     uint8_t resetVectorHi;  // 0xfffd
00070 
00071 public:
00072     void set(const uint8_t* kernal)
00073     {
00074         romBank<0x2000>::set(kernal);
00075 
00076         if (kernal)
00077         {
00078             // Apply Kernal hacks
00079             setVal(0xfd69, 0x9f); // Bypass memory check
00080             setVal(0xe55f, 0x00); // Bypass screen clear
00081             setVal(0xfdc4, 0xea); // Ignore sid volume reset to avoid DC
00082             setVal(0xfdc5, 0xea); //   click (potentially incompatibility)!!
00083             setVal(0xfdc6, 0xea);
00084         }
00085         else
00086         {
00087             // Normal IRQ interrupt
00088             setVal(0xea31, LDAa); // Ack IRQs
00089             setVal(0xea32, 0x0D);
00090             setVal(0xea33, 0xDC);
00091             setVal(0xea34, PLAn); // Restore regs
00092             setVal(0xea35, TAYn);
00093             setVal(0xea36, PLAn);
00094             setVal(0xea37, TAXn);
00095             setVal(0xea38, PLAn);
00096             setVal(0xea39, RTIn); // Return
00097 
00098             // Hardware setup routine
00099             setVal(0xff84, LDAa); // Set CIA 1 Timer A
00100             setVal(0xff85, 0xa6);
00101             setVal(0xff86, 0x02);
00102             setVal(0xff87, BEQr);
00103             setVal(0xff88, 0x06);
00104             setVal(0xff89, LDAb); // PAL
00105             setVal(0xff8a, 0x25);
00106             setVal(0xff8b, LDXb);
00107             setVal(0xff8c, 0x40);
00108             setVal(0xff8d, BNEr);
00109             setVal(0xff8e, 0x04);
00110             setVal(0xff8f, LDAb); // NTSC
00111             setVal(0xff90, 0x95);
00112             setVal(0xff91, LDXb);
00113             setVal(0xff92, 0x42);
00114             setVal(0xff93, STAa);
00115             setVal(0xff94, 0x04);
00116             setVal(0xff95, 0xdc);
00117             setVal(0xff96, STXa);
00118             setVal(0xff97, 0x05);
00119             setVal(0xff98, 0xdc);
00120             setVal(0xff99, LDAb); // Set SID to maximum volume
00121             setVal(0xff9a, 0x0f);
00122             setVal(0xff9b, STAa);
00123             setVal(0xff9c, 0x18);
00124             setVal(0xff9d, 0xd4);
00125             setVal(0xff9e, RTSn);
00126 
00127             // IRQ entry point
00128             setVal(0xffa0, PHAn); // Save regs
00129             setVal(0xffa1, TXAn);
00130             setVal(0xffa2, PHAn);
00131             setVal(0xffa3, TYAn);
00132             setVal(0xffa4, PHAn);
00133             setVal(0xffa5, JMPi); // Jump to IRQ routine
00134             setVal(0xffa6, 0x14);
00135             setVal(0xffa7, 0x03);
00136 
00137             // Hardware vectors
00138             setVal(0xfffa, 0x39); // NMI vector
00139             setVal(0xfffb, 0xea);
00140             setVal(0xfffc, 0x39); // RESET vector
00141             setVal(0xfffd, 0xea);
00142             setVal(0xfffe, 0xa0); // IRQ/BRK vector
00143             setVal(0xffff, 0xff);
00144         }
00145 
00146         // Backup Reset Vector
00147         resetVectorLo = getVal(0xfffc);
00148         resetVectorHi = getVal(0xfffd);
00149     }
00150 
00151     void reset()
00152     {
00153         // Restore original Reset Vector
00154         setVal(0xfffc, resetVectorLo);
00155         setVal(0xfffd, resetVectorHi);
00156     }
00157 
00163     void installResetHook(uint_least16_t addr)
00164     {
00165         setVal(0xfffc, endian_16lo8(addr));
00166         setVal(0xfffd, endian_16hi8(addr));
00167     }
00168 };
00169 
00173 class BasicRomBank : public romBank<0x2000>
00174 {
00175 private:
00176     uint8_t trap[3];
00177     uint8_t subTune[11];
00178 
00179 public:
00180     void set(const uint8_t* basic)
00181     {
00182         romBank<0x2000>::set(basic);
00183 
00184         // Backup BASIC Warm Start
00185         memcpy(trap, getPtr(0xa7ae), 3);
00186 
00187         memcpy(subTune, getPtr(0xbf53), 11);
00188     }
00189 
00190     void reset()
00191     {
00192         // Restore original BASIC Warm Start
00193         memcpy(getPtr(0xa7ae), trap, 3);
00194 
00195         memcpy(getPtr(0xbf53), subTune, 11);
00196     }
00197 
00203     void installTrap(uint_least16_t addr)
00204     {
00205         setVal(0xa7ae, JMPw);
00206         setVal(0xa7af, endian_16lo8(addr));
00207         setVal(0xa7b0, endian_16hi8(addr));
00208     }
00209 
00210     void setSubtune(uint8_t tune)
00211     {
00212         setVal(0xbf53, LDAb);
00213         setVal(0xbf54, tune);
00214         setVal(0xbf55, STAa);
00215         setVal(0xbf56, 0x0c);
00216         setVal(0xbf57, 0x03);
00217         setVal(0xbf58, JSRw);
00218         setVal(0xbf59, 0x2c);
00219         setVal(0xbf5a, 0xa8);
00220         setVal(0xbf5b, JMPw);
00221         setVal(0xbf5c, 0xb1);
00222         setVal(0xbf5d, 0xa7);
00223     }
00224 };
00225 
00229 class CharacterRomBank : public romBank<0x1000> {};
00230 
00231 #endif