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