libsidplayfp  2.0.2
mos656x.h
1 /*
2  * This file is part of libsidplayfp, a SID player engine.
3  *
4  * Copyright 2011-2019 Leandro Nini <drfiemost@users.sourceforge.net>
5  * Copyright 2009-2014 VICE Project
6  * Copyright 2007-2010 Antti Lankila
7  * Copyright 2001 Simon White
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22  */
23 
24 #ifndef MOS656X_H
25 #define MOS656X_H
26 
27 #include <stdint.h>
28 
29 
30 #include "lightpen.h"
31 #include "sprites.h"
32 #include "Event.h"
33 #include "EventCallback.h"
34 #include "EventScheduler.h"
35 
36 #include "sidcxx11.h"
37 
38 namespace libsidplayfp
39 {
40 
45 class MOS656X : private Event
46 {
47 public:
48  typedef enum
49  {
50  MOS6567R56A = 0
56 
57 private:
58  typedef event_clock_t (MOS656X::*ClockFunc)();
59 
60  typedef struct
61  {
62  unsigned int rasterLines;
63  unsigned int cyclesPerLine;
64  ClockFunc clock;
65  } model_data_t;
66 
67 private:
68  static const model_data_t modelData[];
69 
71  static const int IRQ_RASTER = 1 << 0;
72 
74  static const int IRQ_LIGHTPEN = 1 << 3;
75 
77  static const unsigned int FIRST_DMA_LINE = 0x30;
78 
80  static const unsigned int LAST_DMA_LINE = 0xf7;
81 
82 private:
84  ClockFunc clock;
85 
87  event_clock_t rasterClk;
88 
90  EventScheduler &eventScheduler;
91 
93  unsigned int cyclesPerLine;
94 
96  unsigned int maxRasters;
97 
99  unsigned int lineCycle;
100 
102  unsigned int rasterY;
103 
105  unsigned int yscroll;
106 
108  bool areBadLinesEnabled;
109 
111  bool isBadLine;
112 
114  bool rasterYIRQCondition;
115 
117  bool vblanking;
118 
120  bool lpAsserted;
121 
123  uint8_t irqFlags;
124 
126  uint8_t irqMask;
127 
129  Lightpen lp;
130 
132  Sprites sprites;
133 
135  uint8_t regs[0x40];
136 
137  EventCallback<MOS656X> badLineStateChangeEvent;
138 
139  EventCallback<MOS656X> rasterYIRQEdgeDetectorEvent;
140 
141 private:
142  event_clock_t clockPAL();
143  event_clock_t clockNTSC();
144  event_clock_t clockOldNTSC();
145 
149  void handleIrqState();
150 
154  void badLineStateChange() { setBA(!isBadLine); }
155 
159  void rasterYIRQEdgeDetector()
160  {
161  const bool oldRasterYIRQCondition = rasterYIRQCondition;
162  rasterYIRQCondition = rasterY == readRasterLineIRQ();
163  if (!oldRasterYIRQCondition && rasterYIRQCondition)
164  activateIRQFlag(IRQ_RASTER);
165  }
166 
171  void activateIRQFlag(int flag)
172  {
173  irqFlags |= flag;
174  handleIrqState();
175  }
176 
182  unsigned int readRasterLineIRQ() const
183  {
184  return (regs[0x12] & 0xff) + ((regs[0x11] & 0x80) << 1);
185  }
186 
192  bool readDEN() const { return (regs[0x11] & 0x10) != 0; }
193 
194  bool evaluateIsBadLine() const
195  {
196  return areBadLinesEnabled
197  && rasterY >= FIRST_DMA_LINE
198  && rasterY <= LAST_DMA_LINE
199  && (rasterY & 7) == yscroll;
200  }
201 
205  inline unsigned int oldRasterY() const
206  {
207  return (rasterY > 0 ? rasterY : maxRasters) - 1;
208  }
209 
210  inline void sync()
211  {
212  eventScheduler.cancel(*this);
213  event();
214  }
215 
219  inline void checkVblank()
220  {
221  // IRQ occurred (xraster != 0)
222  if (rasterY == (maxRasters - 1))
223  {
224  vblanking = true;
225  }
226 
227  // Check DEN bit on first cycle of the line following the first DMA line
228  if (rasterY == FIRST_DMA_LINE
229  && !areBadLinesEnabled
230  && readDEN())
231  {
232  areBadLinesEnabled = true;
233  }
234 
235  // Disallow bad lines after the last possible one has passed
236  if (rasterY == LAST_DMA_LINE)
237  {
238  areBadLinesEnabled = false;
239  }
240 
241  isBadLine = false;
242 
243  if (!vblanking)
244  {
245  rasterY++;
246  rasterYIRQEdgeDetector();
247  }
248 
249  if (evaluateIsBadLine())
250  isBadLine = true;
251  }
252 
256  inline void vblank()
257  {
258  if (vblanking)
259  {
260  vblanking = false;
261  rasterY = 0;
262  rasterYIRQEdgeDetector();
263  lp.untrigger();
264  if (lpAsserted && lp.retrigger(lineCycle, rasterY))
265  {
266  activateIRQFlag(IRQ_LIGHTPEN);
267  }
268  }
269  }
270 
274  template<int n>
275  inline void startDma()
276  {
277  if (sprites.isDma(0x01 << n))
278  setBA(false);
279  }
280 
284  template<int n>
285  inline void endDma()
286  {
287  if (!sprites.isDma(0x06 << n))
288  setBA(true);
289  }
290 
294  inline void startBadline()
295  {
296  if (isBadLine)
297  setBA(false);
298  }
299 
300 protected:
301  MOS656X(EventScheduler &scheduler);
302  ~MOS656X() {}
303 
304  // Environment Interface
305  virtual void interrupt(bool state) = 0;
306  virtual void setBA(bool state) = 0;
307 
314  uint8_t read(uint_least8_t addr);
315 
324  void write(uint_least8_t addr, uint8_t data);
325 
326 public:
327  void event() override;
328 
332  void chip(model_t model);
333 
337  void triggerLightpen();
338 
342  void clearLightpen();
343 
347  void reset();
348 
349  static const char *credits();
350 };
351 
352 // Template specializations
353 
357 template<>
358 inline void MOS656X::startDma<0>()
359 {
360  setBA(!sprites.isDma(0x01));
361 }
362 
366 template<>
367 inline void MOS656X::endDma<7>()
368 {
369  setBA(true);
370 }
371 
372 }
373 
374 #endif // MOS656X_H
libsidplayfp::MOS656X::reset
void reset()
Definition: mos656x.cpp:76
libsidplayfp::MOS656X::read
uint8_t read(uint_least8_t addr)
Definition: mos656x.cpp:110
libsidplayfp::MOS656X::MOS6567R8
@ MOS6567R8
NTSC-M.
Definition: mos656x.h:51
libsidplayfp::MOS656X::MOS6567R56A
@ MOS6567R56A
OLD NTSC CHIP.
Definition: mos656x.h:50
libsidplayfp::MOS656X::clearLightpen
void clearLightpen()
Definition: mos656x.cpp:689
libsidplayfp::MOS656X::chip
void chip(model_t model)
Definition: mos656x.cpp:99
libsidplayfp::MOS656X::MOS6572
@ MOS6572
PAL-N.
Definition: mos656x.h:53
libsidplayfp::MOS656X::triggerLightpen
void triggerLightpen()
Definition: mos656x.cpp:676
libsidplayfp::MOS656X
Definition: mos656x.h:46
libsidplayfp::MOS656X::MOS6569
@ MOS6569
PAL-B.
Definition: mos656x.h:52
libsidplayfp::MOS656X::MOS6573
@ MOS6573
PAL-M.
Definition: mos656x.h:54
libsidplayfp::MOS656X::write
void write(uint_least8_t addr, uint8_t data)
Definition: mos656x.cpp:147
libsidplayfp::MOS656X::event
void event() override
Definition: mos656x.cpp:258
libsidplayfp::MOS656X::model_t
model_t
Definition: mos656x.h:49
libsidplayfp::Event
Definition: Event.h:39