libsidplayfp 2.2.2
ZeroRAMBank.h
1/*
2 * This file is part of libsidplayfp, a SID player engine.
3 *
4 * Copyright 2012-2015 Leandro Nini <drfiemost@users.sourceforge.net>
5 * Copyright 2009-2014 VICE Project
6 * Copyright 2010 Antti Lankila
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#ifndef ZERORAMBANK_H
24#define ZERORAMBANK_H
25
26#include <stdint.h>
27
28#include "Bank.h"
29#include "SystemRAMBank.h"
30
31#include "Event.h"
32
33#include "sidcxx11.h"
34
35namespace libsidplayfp
36{
37
41class PLA
42{
43public:
44 virtual void setCpuPort(uint8_t state) =0;
45 virtual uint8_t getLastReadByte() const =0;
46 virtual event_clock_t getPhi2Time() const =0;
47
48protected:
49 ~PLA() {}
50};
51
67template <int Bit>
69{
70private:
93 static event_clock_t const C64_CPU6510_DATA_PORT_FALL_OFF_CYCLES = 350000;
94 static event_clock_t const C64_CPU8500_DATA_PORT_FALL_OFF_CYCLES = 1500000; // Curently unused
96
97private:
99 event_clock_t dataSetClk;
100
102 bool isFallingOff;
103
105 uint8_t dataSet;
106
107public:
108 void reset()
109 {
110 isFallingOff = false;
111 dataSet = 0;
112 }
113
114 uint8_t readBit(event_clock_t phi2time)
115 {
116 if (isFallingOff && (dataSetClk < phi2time))
117 {
118 // discharge the "capacitor"
119 reset();
120 }
121 return dataSet;
122 }
123
124 void writeBit(event_clock_t phi2time, uint8_t value)
125 {
126 dataSetClk = phi2time + C64_CPU6510_DATA_PORT_FALL_OFF_CYCLES;
127 dataSet = value & (1 << Bit);
128 isFallingOff = true;
129 }
130};
131
144class ZeroRAMBank final : public Bank
145{
146private:
147 // not emulated
148 static bool const tape_sense = false;
149
150private:
151 PLA &pla;
152
154 SystemRAMBank &ramBank;
155
157
158 dataBit<6> dataBit6;
159 dataBit<7> dataBit7;
161
163
164 uint8_t dir;
165 uint8_t data;
167
169 uint8_t dataRead;
170
172 uint8_t procPortPins;
173
174private:
175 void updateCpuPort()
176 {
177 // Update data pins for which direction is OUTPUT
178 procPortPins = (procPortPins & ~dir) | (data & dir);
179
180 dataRead = (data | ~dir) & (procPortPins | 0x17);
181
182 pla.setCpuPort((data | ~dir) & 0x07);
183
184 if ((dir & 0x20) == 0)
185 {
186 dataRead &= ~0x20;
187 }
188 if (tape_sense && (dir & 0x10) == 0)
189 {
190 dataRead &= ~0x10;
191 }
192 }
193
194public:
195 ZeroRAMBank(PLA &pla, SystemRAMBank &ramBank) :
196 pla(pla),
197 ramBank(ramBank)
198 {}
199
200 void reset()
201 {
202 dataBit6.reset();
203 dataBit7.reset();
204
205 dir = 0;
206 data = 0x3f;
207 dataRead = 0x3f;
208 procPortPins = 0x3f;
209
210 updateCpuPort();
211 }
212
213 uint8_t peek(uint_least16_t address) override
214 {
215 switch (address)
216 {
217 case 0:
218 return dir;
219 case 1:
220 {
221 uint8_t retval = dataRead;
222
223 // for unused bits in input mode, the value comes from the "capacitor"
224
225 // set real value of bit 6
226 if (!(dir & 0x40))
227 {
228 retval &= ~0x40;
229 retval |= dataBit6.readBit(pla.getPhi2Time());
230 }
231
232 // set real value of bit 7
233 if (!(dir & 0x80))
234 {
235 retval &= ~0x80;
236 retval |= dataBit7.readBit(pla.getPhi2Time());
237 }
238
239 return retval;
240 }
241 default:
242 return ramBank.peek(address);
243 }
244 }
245
246 void poke(uint_least16_t address, uint8_t value) override
247 {
248 switch (address)
249 {
250 case 0:
251 // when switching an unused bit from output (where it contained a
252 // stable value) to input mode (where the input is floating), some
253 // of the charge is transferred to the floating input
254
255 if (dir != value)
256 {
257 // check if bit 6 has flipped from 1 to 0
258 if ((dir & 0x40) && !(value & 0x40))
259 dataBit6.writeBit(pla.getPhi2Time(), data);
260
261 // check if bit 7 has flipped from 1 to 0
262 if ((dir & 0x80) && !(value & 0x80))
263 dataBit7.writeBit(pla.getPhi2Time(), data);
264
265 dir = value;
266 updateCpuPort();
267 }
268
269 value = pla.getLastReadByte();
270 break;
271 case 1:
272 // when writing to an unused bit that is output, charge the "capacitor",
273 // otherwise don't touch it
274
275 if (dir & 0x40)
276 dataBit6.writeBit(pla.getPhi2Time(), value);
277
278 if (dir & 0x80)
279 dataBit7.writeBit(pla.getPhi2Time(), value);
280
281 if (data != value)
282 {
283 data = value;
284 updateCpuPort();
285 }
286
287 value = pla.getLastReadByte();
288 break;
289 default:
290 break;
291 }
292
293 ramBank.poke(address, value);
294 }
295};
296
297}
298
299#endif
Definition: Bank.h:36
Definition: ZeroRAMBank.h:42
Definition: SystemRAMBank.h:39
uint8_t peek(uint_least16_t address) override
Definition: SystemRAMBank.h:72
void poke(uint_least16_t address, uint8_t value) override
Definition: SystemRAMBank.h:77
Definition: ZeroRAMBank.h:145
void poke(uint_least16_t address, uint8_t value) override
Definition: ZeroRAMBank.h:246
uint8_t peek(uint_least16_t address) override
Definition: ZeroRAMBank.h:213
Definition: ZeroRAMBank.h:69