libsidplayfp  2.3.0
mos656x.h
1 /*
2  * This file is part of libsidplayfp, a SID player engine.
3  *
4  * Copyright 2011-2020 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  EventCallback<MOS656X> lightpenTriggerEvent;
142 
143 private:
144  event_clock_t clockPAL();
145  event_clock_t clockNTSC();
146  event_clock_t clockOldNTSC();
147 
151  void handleIrqState();
152 
156  void badLineStateChange() { setBA(!isBadLine); }
157 
161  void rasterYIRQEdgeDetector()
162  {
163  const bool oldRasterYIRQCondition = rasterYIRQCondition;
164  rasterYIRQCondition = rasterY == readRasterLineIRQ();
165  if (!oldRasterYIRQCondition && rasterYIRQCondition)
166  activateIRQFlag(IRQ_RASTER);
167  }
168 
169  void lightpenTrigger()
170  {
171  // Synchronise simulation
172  sync();
173 
174  if (lp.trigger(lineCycle, rasterY))
175  {
176  activateIRQFlag(IRQ_LIGHTPEN);
177  }
178  }
179 
184  void activateIRQFlag(int flag)
185  {
186  irqFlags |= flag;
187  handleIrqState();
188  }
189 
195  unsigned int readRasterLineIRQ() const
196  {
197  return regs[0x12] + ((regs[0x11] & 0x80) << 1);
198  }
199 
205  bool readDEN() const { return (regs[0x11] & 0x10) != 0; }
206 
207  bool evaluateIsBadLine() const
208  {
209  return areBadLinesEnabled
210  && rasterY >= FIRST_DMA_LINE
211  && rasterY <= LAST_DMA_LINE
212  && (rasterY & 7) == yscroll;
213  }
214 
218  inline unsigned int oldRasterY() const
219  {
220  return (rasterY > 0 ? rasterY : maxRasters) - 1;
221  }
222 
223  inline void sync()
224  {
225  eventScheduler.cancel(*this);
226  event();
227  }
228 
232  inline void checkVblank()
233  {
234  // IRQ occurred (xraster != 0)
235  if (rasterY == (maxRasters - 1))
236  {
237  vblanking = true;
238  }
239 
240  // Check DEN bit on first cycle of the line following the first DMA line
241  if (rasterY == FIRST_DMA_LINE
242  && !areBadLinesEnabled
243  && readDEN())
244  {
245  areBadLinesEnabled = true;
246  }
247 
248  // Disallow bad lines after the last possible one has passed
249  if (rasterY == LAST_DMA_LINE)
250  {
251  areBadLinesEnabled = false;
252  }
253 
254  isBadLine = false;
255 
256  if (!vblanking)
257  {
258  rasterY++;
259  rasterYIRQEdgeDetector();
260  }
261 
262  if (evaluateIsBadLine())
263  isBadLine = true;
264  }
265 
269  inline void vblank()
270  {
271  if (vblanking)
272  {
273  vblanking = false;
274  rasterY = 0;
275  rasterYIRQEdgeDetector();
276  lp.untrigger();
277  if (lpAsserted && lp.retrigger())
278  {
279  activateIRQFlag(IRQ_LIGHTPEN);
280  }
281  }
282  }
283 
287  template<int n>
288  inline void startDma()
289  {
290  if (sprites.isDma(0x01 << n))
291  setBA(false);
292  }
293 
297  template<int n>
298  inline void endDma()
299  {
300  if (!sprites.isDma(0x06 << n))
301  setBA(true);
302  }
303 
307  inline void startBadline()
308  {
309  if (isBadLine)
310  setBA(false);
311  }
312 
313 protected:
314  MOS656X(EventScheduler &scheduler);
315  ~MOS656X() {}
316 
317  // Environment Interface
318  virtual void interrupt(bool state) = 0;
319  virtual void setBA(bool state) = 0;
320 
327  uint8_t read(uint_least8_t addr);
328 
337  void write(uint_least8_t addr, uint8_t data);
338 
339 public:
340  void event() override;
341 
345  void chip(model_t model);
346 
350  void triggerLightpen();
351 
355  void clearLightpen();
356 
360  void reset();
361 
362  static const char *credits();
363 };
364 
365 // Template specializations
366 
370 template<>
371 inline void MOS656X::startDma<0>()
372 {
373  setBA(!sprites.isDma(0x01));
374 }
375 
379 template<>
380 inline void MOS656X::endDma<7>()
381 {
382  setBA(true);
383 }
384 
385 }
386 
387 #endif // MOS656X_H
Definition: Event.h:39
Definition: mos656x.h:46
void write(uint_least8_t addr, uint8_t data)
Definition: mos656x.cpp:148
model_t
Definition: mos656x.h:49
@ MOS6573
PAL-M.
Definition: mos656x.h:54
@ MOS6567R56A
OLD NTSC CHIP.
Definition: mos656x.h:50
@ MOS6569
PAL-B.
Definition: mos656x.h:52
@ MOS6572
PAL-N.
Definition: mos656x.h:53
@ MOS6567R8
NTSC-M.
Definition: mos656x.h:51
void clearLightpen()
Definition: mos656x.cpp:692
void reset()
Definition: mos656x.cpp:77
void event() override
Definition: mos656x.cpp:259
void triggerLightpen()
Definition: mos656x.cpp:685
uint8_t read(uint_least8_t addr)
Definition: mos656x.cpp:111
void chip(model_t model)
Definition: mos656x.cpp:100