1 /*
2  * This file is part of libsidplayfp, a SID player engine.
3  *
4  * Copyright 2011-2021 Leandro Nini <drfiemost@users.sourceforge.net>
5  * Copyright 2007-2010 Antti Lankila
6  * Copyright 2000 Simon White
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21  */
22 
23 #include "c64.h"
24 
25 #include <algorithm>
26 
27 #include "c64/CIA/mos652x.h"
28 #include "c64/VIC_II/mos656x.h"
29 
30 namespace libsidplayfp
31 {
32 
33 typedef struct
34 {
35     double colorBurst;         ///< Colorburst frequency in Herz
36     double divider;            ///< Clock frequency divider
37     double powerFreq;          ///< Power line frequency in Herz
38     MOS656X::model_t vicModel; ///< Video chip model
39 } model_data_t;
40 
41 typedef struct
42 {
43     MOS652X::model_t ciaModel; ///< CIA chip model
44 } cia_model_data_t;
45 
46 /*
47  * Color burst frequencies:
48  *
49  * NTSC  - 3.579545455 MHz = 315/88 MHz
50  * PAL-B - 4.43361875 MHz = 283.75 * 15625 Hz + 25 Hz.
51  * PAL-M - 3.57561149 MHz
52  * PAL-N - 3.58205625 MHz
53  */
54 
55 const model_data_t modelData[] =
56 {
57     {4433618.75,  18., 50., MOS656X::MOS6569},      // PAL-B
58     {3579545.455, 14., 60., MOS656X::MOS6567R8},    // NTSC-M
59     {3579545.455, 14., 60., MOS656X::MOS6567R56A},  // Old NTSC-M
60     {3582056.25,  14., 50., MOS656X::MOS6572},      // PAL-N
61     {3575611.49,  14., 50., MOS656X::MOS6573},      // PAL-M
62 };
63 
64 const cia_model_data_t ciaModelData[] =
65 {
66     {MOS652X::MOS6526},      // Old
67     {MOS652X::MOS8521},      // New
68     {MOS652X::MOS6526W4485}, // Old week 4485
69 };
70 
getCpuFreq(model_t model)71 double c64::getCpuFreq(model_t model)
72 {
73     // The crystal clock that drives the VIC II chip is four times
74     // the color burst frequency
75     const double crystalFreq = modelData[model].colorBurst * 4.;
76 
77     // The VIC II produces the two-phase system clock
78     // by running the input clock through a divider
79     return crystalFreq / modelData[model].divider;
80 }
81 
c64()82 c64::c64() :
83     c64env(eventScheduler),
84     cpuFrequency(getCpuFreq(PAL_B)),
85     cpu(*this),
86     cia1(*this),
87     cia2(*this),
88     vic(*this),
89     disconnectedBusBank(mmu),
90     mmu(eventScheduler, &ioBank)
91 {
92     resetIoBank();
93 }
94 
95 
resetIoBank()96 void c64::resetIoBank()
97 {
98     ioBank.setBank(0x0, &vic);
99     ioBank.setBank(0x1, &vic);
100     ioBank.setBank(0x2, &vic);
101     ioBank.setBank(0x3, &vic);
102     ioBank.setBank(0x4, &sidBank);
103     ioBank.setBank(0x5, &sidBank);
104     ioBank.setBank(0x6, &sidBank);
105     ioBank.setBank(0x7, &sidBank);
106     ioBank.setBank(0x8, &colorRAMBank);
107     ioBank.setBank(0x9, &colorRAMBank);
108     ioBank.setBank(0xa, &colorRAMBank);
109     ioBank.setBank(0xb, &colorRAMBank);
110     ioBank.setBank(0xc, &cia1);
111     ioBank.setBank(0xd, &cia2);
112     ioBank.setBank(0xe, &disconnectedBusBank);
113     ioBank.setBank(0xf, &disconnectedBusBank);
114 }
115 
116 template<typename T>
resetSID(T & e)117 void resetSID(T &e) { e.second->reset(); }
118 
reset()119 void c64::reset()
120 {
121     eventScheduler.reset();
122 
123     //cpu.reset();
124     cia1.reset();
125     cia2.reset();
126     vic.reset();
127     sidBank.reset();
128     colorRAMBank.reset();
129     mmu.reset();
130 
131     std::for_each(extraSidBanks.begin(), extraSidBanks.end(), resetSID<sidBankMap_t::value_type>);
132 
133     irqCount = 0;
134     oldBAState = true;
135 }
136 
setModel(model_t model)137 void c64::setModel(model_t model)
138 {
139     cpuFrequency = getCpuFreq(model);
140     vic.chip(modelData[model].vicModel);
141 
142     const unsigned int rate = cpuFrequency / modelData[model].powerFreq;
143     cia1.setDayOfTimeRate(rate);
144     cia2.setDayOfTimeRate(rate);
145 }
146 
setCiaModel(cia_model_t model)147 void c64::setCiaModel(cia_model_t model)
148 {
149     cia1.setModel(ciaModelData[model].ciaModel);
150     cia2.setModel(ciaModelData[model].ciaModel);
151 }
152 
setBaseSid(c64sid * s)153 void c64::setBaseSid(c64sid *s)
154 {
155     sidBank.setSID(s);
156 }
157 
addExtraSid(c64sid * s,int address)158 bool c64::addExtraSid(c64sid *s, int address)
159 {
160     // Check for valid address in the IO area range ($dxxx)
161     if ((address & 0xf000) != 0xd000)
162         return false;
163 
164     const int idx = (address >> 8) & 0xf;
165 
166     // Only allow second SID chip in SID area ($d400-$d7ff)
167     // or IO Area ($de00-$dfff)
168     if ((idx < 0x4) || ((idx > 0x7) && (idx < 0xe)))
169         return false;
170 
171     // Add new SID bank
172     sidBankMap_t::iterator it = extraSidBanks.find(idx);
173     if (it != extraSidBanks.end())
174     {
175          ExtraSidBank *extraSidBank = it->second;
176          extraSidBank->addSID(s, address);
177     }
178     else
179     {
180         ExtraSidBank *extraSidBank = extraSidBanks.insert(it, sidBankMap_t::value_type(idx, new ExtraSidBank()))->second;
181         extraSidBank->resetSIDMapper(ioBank.getBank(idx));
182         ioBank.setBank(idx, extraSidBank);
183         extraSidBank->addSID(s, address);
184     }
185 
186     return true;
187 }
188 
189 template<class T>
Delete(T & s)190 void Delete(T &s) { delete s.second; }
191 
clearSids()192 void c64::clearSids()
193 {
194     sidBank.setSID(nullptr);
195 
196     resetIoBank();
197 
198     std::for_each(extraSidBanks.begin(), extraSidBanks.end(), Delete<sidBankMap_t::value_type>);
199 
200     extraSidBanks.clear();
201 }
202 
203 }
204