libsidplayfp  2.4.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 
36 namespace libsidplayfp
37 {
38 
54 template <int Bit>
55 class dataBit
56 {
57 private:
80  static event_clock_t const C64_CPU6510_DATA_PORT_FALL_OFF_CYCLES = 350000;
81  static event_clock_t const C64_CPU8500_DATA_PORT_FALL_OFF_CYCLES = 1500000; // Curently unused
83 
84 private:
86  event_clock_t dataSetClk;
87 
89  bool isFallingOff;
90 
92  uint8_t dataSet;
93 
94 public:
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 
131 class ZeroRAMBank final : public Bank
132 {
133 private:
134  // not emulated
135  static bool const tape_sense = false;
136 
137 private:
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 
161 private:
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 
181 public:
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