libsidplayfp  1.1.0
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 "sidplayfp/component.h"
27 #include "sidplayfp/EventScheduler.h"
28 
29 
30 class MOS656X: public component, private Event
31 {
32 public:
33  typedef enum
34  {
35  MOS6567R56A = 0 /* OLD NTSC CHIP */
36  ,MOS6567R8 /* NTSC-M */
37  ,MOS6569 /* PAL-B */
38  ,MOS6572 /* PAL-N */
39  } model_t;
40 
41 private:
42  typedef struct
43  {
44  unsigned int cyclesPerLine;
45  unsigned int rasterLines;
46  event_clock_t (MOS656X::*clock)();
47  } model_data_t;
48 
49 private:
50  static const char *credit;
51 
52  static const model_data_t modelData[];
53 
54 private:
56  static const int IRQ_RASTER = 1 << 0;
57 
59  static const int IRQ_LIGHTPEN = 1 << 3;
60 
61 protected:
63  static const int FIRST_DMA_LINE = 0x30;
64 
66  static const int LAST_DMA_LINE = 0xf7;
67 
68 protected:
69  event_clock_t (MOS656X::*clock)();
70 
71  event_clock_t rasterClk;
72 
75 
77  uint_least16_t cyclesPerLine;
78 
79  uint_least16_t maxRasters;
80 
81  uint_least16_t raster_irq;
82 
84  uint_least16_t lineCycle;
85 
87  uint_least16_t rasterY;
88 
90  uint_least16_t yscroll;
91 
94 
96  bool isBadLine;
97 
99  bool vblanking;
100 
103 
105  uint8_t irqFlags;
106 
108  uint8_t irqMask;
109 
111  uint8_t lpx, lpy;
112 
116  uint8_t sprite_dma;
117  uint8_t sprite_mc_base[8];
118  uint8_t sprite_mc[8];
120 
122  uint8_t regs[0x40];
123 
124 private:
125  event_clock_t clockPAL();
126  event_clock_t clockNTSC();
127  event_clock_t clockOldNTSC();
128 
130  void handleIrqState();
131 
132  EventCallback<MOS656X> badLineStateChangeEvent;
133 
135  void badLineStateChange() { setBA(!isBadLine); }
136 
141  void activateIRQFlag(int flag)
142  {
143  irqFlags |= flag;
144  handleIrqState();
145  }
146 
152  bool readDEN() const { return (regs[0x11] & 0x10) != 0; }
153 
154  bool evaluateIsBadLine() const
155  {
156  return areBadLinesEnabled
157  && rasterY >= FIRST_DMA_LINE
158  && rasterY <= LAST_DMA_LINE
159  && (rasterY & 7) == yscroll;
160  }
161 
162  inline void sync()
163  {
164  event_context.cancel(*this);
165  event();
166  }
167 
168  inline void checkVblank()
169  {
170  // IRQ occurred (xraster != 0)
171  if (rasterY == (maxRasters - 1))
172  vblanking = true;
173  else
174  {
175  rasterY++;
176  // Trigger raster IRQ if IRQ line reached
177  if (rasterY == raster_irq)
178  activateIRQFlag(IRQ_RASTER);
179  }
180 
181  // In line $30, the DEN bit controls if Bad Lines can occur
182  if (rasterY == FIRST_DMA_LINE)
183  areBadLinesEnabled = readDEN();
184 
185  // Test for bad line condition
186  isBadLine = evaluateIsBadLine();
187  }
188 
189  inline void vblank()
190  {
191  // Vertical blank (line 0)
192  if (vblanking)
193  {
194  vblanking = lp_triggered = false;
195  rasterY = 0;
196  // Trigger raster IRQ if IRQ in line 0
197  if (raster_irq == 0)
198  activateIRQFlag(IRQ_RASTER);
199  }
200  }
201 
202  inline void updateMc()
203  {
204  // Update mc values in one pass
205  // after the dma has been processed
206  uint8_t mask = 1;
207  for (unsigned int i=0; i<8; i++, mask<<=1)
208  {
209  if (sprite_enable & mask)
210  sprite_mc[i] = (sprite_mc[i] + 3) & 0x3f;
211  }
212  }
213 
214  inline void updateMcBase()
215  {
216  uint8_t mask = 1;
217  for (unsigned int i=0; i<8; i++, mask<<=1)
218  {
219  if (sprite_y_expansion & mask)
220  sprite_mc_base[i] = sprite_mc[i];
221  if (sprite_mc_base[i] == 0x3f)
222  sprite_dma &= ~mask;
223  }
224  }
225 
227  inline void checkSpriteDmaExp()
228  {
229  const uint8_t y = rasterY & 0xff;
230  uint8_t mask = 1;
231  for (unsigned int i=0; i<8; i++, mask<<=1)
232  {
233  if ((sprite_enable & mask) && (y == regs[i << 1]))
234  {
235  sprite_dma |= mask;
236  sprite_mc_base[i] = 0;
237  sprite_y_expansion |= mask;
238  }
239  }
240  }
241 
243  inline void checkSpriteDma()
244  {
245  const uint8_t y = rasterY & 0xff;
246  uint8_t mask = 1;
247  for (unsigned int i=0; i<8; i++, mask<<=1)
248  {
249  if ((sprite_enable & mask) && (y == regs[i << 1]))
250  {
251  sprite_dma |= mask;
252  sprite_mc_base[i] = 0;
253  }
254  }
255  }
256 
257  inline void checkSpriteDisplay()
258  {
259  for (unsigned int i=0; i<8; i++)
260  {
261  sprite_mc[i] = sprite_mc_base[i];
262  }
263  }
264 
266  template<int n>
267  inline void startDma()
268  {
269  if (sprite_dma & (0x01 << n))
270  setBA(false);
271  }
272 
274  template<int n>
275  inline void endDma()
276  {
277  if (!(sprite_dma & (0x06 << n)))
278  setBA(true);
279  }
280 
282  inline void startBadline()
283  {
284  if (isBadLine)
285  setBA(false);
286  }
287 
288 protected:
289  MOS656X(EventContext *context);
290  ~MOS656X() {}
291 
292  // Environment Interface
293  virtual void interrupt (bool state) = 0;
294  virtual void setBA (bool state) = 0;
295 
302  uint8_t read(uint_least8_t addr);
303 
312  void write(uint_least8_t addr, uint8_t data);
313 
314 public:
315  void event();
316 
317  void chip(model_t model);
318  void lightpen();
319 
320  // Component Standard Calls
321  void reset();
322 
323  const char *credits() const { return credit; }
324 
325  uint_least16_t getCyclesPerLine() const { return cyclesPerLine; }
326 
327  uint_least16_t getRasterLines() const { return maxRasters; }
328 };
329 
330 // Template specializations
331 
333 template<>
334 inline void MOS656X::startDma<0>()
335 {
336  setBA(!(sprite_dma & 0x01));
337 }
338 
340 template<>
341 inline void MOS656X::endDma<7>()
342 {
343  setBA(true);
344 }
345 
346 #endif // MOS656X_H
uint8_t sprite_mc[8]
Definition: mos656x.h:118
bool vblanking
Definition: mos656x.h:99
bool areBadLinesEnabled
Definition: mos656x.h:93
Definition: mos656x.h:30
bool isBadLine
Definition: mos656x.h:96
void event()
Definition: mos656x.cpp:214
uint_least16_t rasterY
Definition: mos656x.h:87
Definition: event.h:101
Definition: component.h:28
uint8_t & sprite_y_expansion
Definition: mos656x.h:115
uint8_t read(uint_least8_t addr)
Definition: mos656x.cpp:91
uint8_t sprite_mc_base[8]
Definition: mos656x.h:117
uint_least16_t yscroll
Definition: mos656x.h:90
uint8_t lpx
Definition: mos656x.h:111
uint8_t irqMask
Definition: mos656x.h:108
uint8_t regs[0x40]
Definition: mos656x.h:122
void write(uint_least8_t addr, uint8_t data)
Definition: mos656x.cpp:127
uint8_t irqFlags
Definition: mos656x.h:105
Definition: event.h:50
static const int LAST_DMA_LINE
Definition: mos656x.h:66
uint_least16_t cyclesPerLine
Definition: mos656x.h:77
uint8_t sprite_dma
Definition: mos656x.h:116
static const int FIRST_DMA_LINE
Definition: mos656x.h:63
uint_least16_t lineCycle
Definition: mos656x.h:84
EventContext & event_context
Definition: mos656x.h:74
bool lp_triggered
Definition: mos656x.h:102
virtual void cancel(Event &event)=0
uint8_t & sprite_enable
Definition: mos656x.h:115