libsidplayfp  1.4.1
mos656x.h
1 /*
2  * This file is part of libsidplayfp, a SID player engine.
3  *
4  * Copyright 2011-2013 Leandro Nini <drfiemost@users.sourceforge.net>
5  * Copyright 2007-2010 Antti Lankila
6  * Copyright 2001 Simon White
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 MOS656X_H
24 #define MOS656X_H
25 
26 #include <stdint.h>
27 
28 #include "sidplayfp/event.h"
29 #include "sidplayfp/component.h"
30 #include "sidplayfp/EventScheduler.h"
31 
32 
33 class MOS656X: public component, private Event
34 {
35 public:
36  typedef enum
37  {
38  MOS6567R56A = 0 /* OLD NTSC CHIP */
39  ,MOS6567R8 /* NTSC-M */
40  ,MOS6569 /* PAL-B */
41  ,MOS6572 /* PAL-N */
42  } model_t;
43 
44 private:
45  typedef struct
46  {
47  unsigned int rasterLines;
48  unsigned int cyclesPerLine;
49  event_clock_t (MOS656X::*clock)();
50  } model_data_t;
51 
52 private:
53  static const char *credit;
54 
55  static const model_data_t modelData[];
56 
57 private:
59  static const int IRQ_RASTER = 1 << 0;
60 
62  static const int IRQ_LIGHTPEN = 1 << 3;
63 
64 protected:
66  static const unsigned int FIRST_DMA_LINE = 0x30;
67 
69  static const unsigned int LAST_DMA_LINE = 0xf7;
70 
71 protected:
72  event_clock_t (MOS656X::*clock)();
73 
74  event_clock_t rasterClk;
75 
78 
80  unsigned int cyclesPerLine;
81 
82  unsigned int maxRasters;
83 
85  unsigned int lineCycle;
86 
88  unsigned int rasterY;
89 
91  unsigned int yscroll;
92 
95 
97  bool isBadLine;
98 
101 
103  bool vblanking;
104 
107 
109  uint8_t irqFlags;
110 
112  uint8_t irqMask;
113 
115  uint8_t lpx, lpy;
116 
120  uint8_t sprite_dma;
121  uint8_t sprite_mc_base[8];
122  uint8_t sprite_mc[8];
124 
126  uint8_t regs[0x40];
127 
128 private:
129  event_clock_t clockPAL();
130  event_clock_t clockNTSC();
131  event_clock_t clockOldNTSC();
132 
134  void handleIrqState();
135 
136  EventCallback<MOS656X> badLineStateChangeEvent;
137 
139  void badLineStateChange() { setBA(!isBadLine); }
140 
141  EventCallback<MOS656X> rasterYIRQEdgeDetectorEvent;
142 
144  void rasterYIRQEdgeDetector()
145  {
146  const bool oldRasterYIRQCondition = rasterYIRQCondition;
147  rasterYIRQCondition = rasterY == readRasterLineIRQ();
148  if (!oldRasterYIRQCondition && rasterYIRQCondition)
149  activateIRQFlag(IRQ_RASTER);
150  }
151 
156  void activateIRQFlag(int flag)
157  {
158  irqFlags |= flag;
159  handleIrqState();
160  }
161 
167  unsigned int readRasterLineIRQ() const
168  {
169  return (regs[0x12] & 0xff) + ((regs[0x11] & 0x80) << 1);
170  }
171 
177  bool readDEN() const { return (regs[0x11] & 0x10) != 0; }
178 
179  bool evaluateIsBadLine() const
180  {
181  return areBadLinesEnabled
182  && rasterY >= FIRST_DMA_LINE
183  && rasterY <= LAST_DMA_LINE
184  && (rasterY & 7) == yscroll;
185  }
186 
187  inline void sync()
188  {
189  event_context.cancel(*this);
190  event();
191  }
192 
193  inline void checkVblank()
194  {
195  // IRQ occurred (xraster != 0)
196  if (rasterY == (maxRasters - 1))
197  vblanking = true;
198  else
199  {
200  rasterY++;
201  rasterYIRQEdgeDetector();
202  }
203 
204  // In line $30, the DEN bit controls if Bad Lines can occur
205  if (rasterY == FIRST_DMA_LINE)
206  areBadLinesEnabled = readDEN();
207 
208  // Test for bad line condition
209  isBadLine = evaluateIsBadLine();
210  }
211 
212  inline void vblank()
213  {
214  // Vertical blank (line 0)
215  if (vblanking)
216  {
217  vblanking = lp_triggered = false;
218  rasterY = 0;
219  rasterYIRQEdgeDetector();
220  }
221  }
222 
223  inline void updateMc()
224  {
225  // Update mc values in one pass
226  // after the dma has been processed
227  uint8_t mask = 1;
228  for (unsigned int i=0; i<8; i++, mask<<=1)
229  {
230  if (sprite_dma & mask)
231  sprite_mc[i] = (sprite_mc[i] + 3) & 0x3f;
232  }
233  }
234 
235  inline void updateMcBase()
236  {
237  uint8_t mask = 1;
238  for (unsigned int i=0; i<8; i++, mask<<=1)
239  {
240  if (sprite_y_expansion & mask)
241  sprite_mc_base[i] = sprite_mc[i];
242  if (sprite_mc_base[i] == 0x3f)
243  sprite_dma &= ~mask;
244  }
245  }
246 
248  inline void checkSpriteDmaExp()
249  {
250  const uint8_t y = rasterY & 0xff;
251  uint8_t mask = 1;
252  for (unsigned int i=0; i<8; i++, mask<<=1)
253  {
254  if ((sprite_enable & mask) && (y == regs[(i << 1) + 1]))
255  {
256  sprite_dma |= mask;
257  sprite_mc_base[i] = 0;
258  sprite_y_expansion |= mask;
259  }
260  }
261  }
262 
264  inline void checkSpriteDma()
265  {
266  const uint8_t y = rasterY & 0xff;
267  uint8_t mask = 1;
268  for (unsigned int i=0; i<8; i++, mask<<=1)
269  {
270  if ((sprite_enable & mask) && (y == regs[(i << 1) + 1]) && !(sprite_dma & mask))
271  {
272  sprite_dma |= mask;
273  sprite_mc_base[i] = 0;
274  }
275  }
276  }
277 
278  inline void checkSpriteDisplay()
279  {
280  for (unsigned int i=0; i<8; i++)
281  {
282  sprite_mc[i] = sprite_mc_base[i];
283  }
284  }
285 
287  template<int n>
288  inline void startDma()
289  {
290  if (sprite_dma & (0x01 << n))
291  setBA(false);
292  }
293 
295  template<int n>
296  inline void endDma()
297  {
298  if (!(sprite_dma & (0x06 << n)))
299  setBA(true);
300  }
301 
303  inline void startBadline()
304  {
305  if (isBadLine)
306  setBA(false);
307  }
308 
309 protected:
310  MOS656X(EventContext *context);
311  ~MOS656X() {}
312 
313  // Environment Interface
314  virtual void interrupt (bool state) = 0;
315  virtual void setBA (bool state) = 0;
316 
323  uint8_t read(uint_least8_t addr);
324 
333  void write(uint_least8_t addr, uint8_t data);
334 
335 public:
336  void event();
337 
338  void chip(model_t model);
339  void lightpen();
340 
341  // Component Standard Calls
342  void reset();
343 
344  const char *credits() const { return credit; }
345 };
346 
347 // Template specializations
348 
350 template<>
351 inline void MOS656X::startDma<0>()
352 {
353  setBA(!(sprite_dma & 0x01));
354 }
355 
357 template<>
358 inline void MOS656X::endDma<7>()
359 {
360  setBA(true);
361 }
362 
363 #endif // MOS656X_H
uint8_t sprite_mc[8]
Definition: mos656x.h:122
bool vblanking
Definition: mos656x.h:103
bool areBadLinesEnabled
Definition: mos656x.h:94
bool rasterYIRQCondition
Definition: mos656x.h:100
Definition: mos656x.h:33
bool isBadLine
Definition: mos656x.h:97
void event()
Definition: mos656x.cpp:213
unsigned int yscroll
Definition: mos656x.h:91
Definition: event.h:101
unsigned int lineCycle
Definition: mos656x.h:85
unsigned int cyclesPerLine
Definition: mos656x.h:80
Definition: component.h:28
uint8_t & sprite_y_expansion
Definition: mos656x.h:119
static const unsigned int LAST_DMA_LINE
Definition: mos656x.h:69
uint8_t read(uint_least8_t addr)
Definition: mos656x.cpp:93
uint8_t sprite_mc_base[8]
Definition: mos656x.h:121
uint8_t lpx
Definition: mos656x.h:115
uint8_t irqMask
Definition: mos656x.h:112
uint8_t regs[0x40]
Definition: mos656x.h:126
void write(uint_least8_t addr, uint8_t data)
Definition: mos656x.cpp:129
static const unsigned int FIRST_DMA_LINE
Definition: mos656x.h:66
uint8_t irqFlags
Definition: mos656x.h:109
Definition: event.h:50
uint8_t sprite_dma
Definition: mos656x.h:120
EventContext & event_context
Definition: mos656x.h:77
unsigned int rasterY
Definition: mos656x.h:88
bool lp_triggered
Definition: mos656x.h:106
virtual void cancel(Event &event)=0
uint8_t & sprite_enable
Definition: mos656x.h:119