libsidplayfp 2.15.0
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#include "pla.h"
31
32#include "Event.h"
33
34#include "sidcxx11.h"
35
36namespace libsidplayfp
37{
38
54template <int Bit>
56{
57private:
80 static constexpr event_clock_t C64_CPU6510_DATA_PORT_FALL_OFF_CYCLES = 350000;
81 static constexpr event_clock_t C64_CPU8500_DATA_PORT_FALL_OFF_CYCLES = 1500000; // Curently unused
83
84private:
86 event_clock_t dataSetClk;
87
89 bool isFallingOff;
90
92 uint8_t dataSet;
93
94public:
95 void reset()
96 {
97 isFallingOff = false;
98 dataSet = 0;
99 }
100
101 uint8_t readBit(event_clock_t phi2time)
102 {
103 if (isFallingOff && (dataSetClk < phi2time))
104 {
105 // discharge the "capacitor"
106 reset();
107 }
108 return dataSet;
109 }
110
111 void writeBit(event_clock_t phi2time, uint8_t value)
112 {
113 dataSetClk = phi2time + C64_CPU6510_DATA_PORT_FALL_OFF_CYCLES;
114 dataSet = value & (1 << Bit);
115 isFallingOff = true;
116 }
117};
118
131class ZeroRAMBank final : public Bank
132{
133private:
134 // not emulated
135 static bool const tape_sense = false;
136
137private:
138 PLA &pla;
139
141 SystemRAMBank &ramBank;
142
144
145 dataBit<6> dataBit6;
146 dataBit<7> dataBit7;
148
150
151 uint8_t dir;
152 uint8_t data;
154
156 uint8_t dataRead;
157
159 uint8_t procPortPins;
160
161private:
162 void updateCpuPort()
163 {
164 // Update data pins for which direction is OUTPUT
165 procPortPins = (procPortPins & ~dir) | (data & dir);
166
167 dataRead = (data | ~dir) & (procPortPins | 0x17);
168
169 pla.setCpuPort((data | ~dir) & 0x07);
170
171 if ((dir & 0x20) == 0)
172 {
173 dataRead &= ~0x20;
174 }
175 if (tape_sense && (dir & 0x10) == 0)
176 {
177 dataRead &= ~0x10;
178 }
179 }
180
181public:
182 ZeroRAMBank(PLA &pla, SystemRAMBank &ramBank) :
183 pla(pla),
184 ramBank(ramBank)
185 {}
186
187 void reset()
188 {
189 dataBit6.reset();
190 dataBit7.reset();
191
192 dir = 0;
193 data = 0x3f;
194 dataRead = 0x3f;
195 procPortPins = 0x3f;
196
197 updateCpuPort();
198 }
199
200 uint8_t peek(uint_least16_t address) override
201 {
202 switch (address)
203 {
204 case 0:
205 return dir;
206 case 1:
207 {
208 uint8_t retval = dataRead;
209
210 // for unused bits in input mode, the value comes from the "capacitor"
211
212 // set real value of bit 6
213 if (!(dir & 0x40))
214 {
215 retval &= ~0x40;
216 retval |= dataBit6.readBit(pla.getPhi2Time());
217 }
218
219 // set real value of bit 7
220 if (!(dir & 0x80))
221 {
222 retval &= ~0x80;
223 retval |= dataBit7.readBit(pla.getPhi2Time());
224 }
225
226 return retval;
227 }
228 default:
229 return ramBank.peek(address);
230 }
231 }
232
233 void poke(uint_least16_t address, uint8_t value) override
234 {
235 switch (address)
236 {
237 case 0:
238 // when switching an unused bit from output (where it contained a
239 // stable value) to input mode (where the input is floating), some
240 // of the charge is transferred to the floating input
241
242 if (dir != value)
243 {
244 // check if bit 6 has flipped from 1 to 0
245 if ((dir & 0x40) && !(value & 0x40))
246 dataBit6.writeBit(pla.getPhi2Time(), data);
247
248 // check if bit 7 has flipped from 1 to 0
249 if ((dir & 0x80) && !(value & 0x80))
250 dataBit7.writeBit(pla.getPhi2Time(), data);
251
252 dir = value;
253 updateCpuPort();
254 }
255
256 value = pla.getLastReadByte();
257 break;
258 case 1:
259 // when writing to an unused bit that is output, charge the "capacitor",
260 // otherwise don't touch it
261
262 if (dir & 0x40)
263 dataBit6.writeBit(pla.getPhi2Time(), value);
264
265 if (dir & 0x80)
266 dataBit7.writeBit(pla.getPhi2Time(), value);
267
268 if (data != value)
269 {
270 data = value;
271 updateCpuPort();
272 }
273
274 value = pla.getLastReadByte();
275 break;
276 default:
277 break;
278 }
279
280 ramBank.poke(address, value);
281 }
282};
283
284}
285
286#endif
Definition Bank.h:36
Definition pla.h:35
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:132
void poke(uint_least16_t address, uint8_t value) override
Definition ZeroRAMBank.h:233
uint8_t peek(uint_least16_t address) override
Definition ZeroRAMBank.h:200
Definition ZeroRAMBank.h:56