libsidplayfp  1.2.2
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 
93  uint16_t raster_irq;
94 
97 
99  bool isBadLine;
100 
102  bool vblanking;
103 
106 
108  uint8_t irqFlags;
109 
111  uint8_t irqMask;
112 
114  uint8_t lpx, lpy;
115 
119  uint8_t sprite_dma;
120  uint8_t sprite_mc_base[8];
121  uint8_t sprite_mc[8];
123 
125  uint8_t regs[0x40];
126 
127 private:
128  event_clock_t clockPAL();
129  event_clock_t clockNTSC();
130  event_clock_t clockOldNTSC();
131 
133  void handleIrqState();
134 
135  EventCallback<MOS656X> badLineStateChangeEvent;
136 
138  void badLineStateChange() { setBA(!isBadLine); }
139 
144  void activateIRQFlag(int flag)
145  {
146  irqFlags |= flag;
147  handleIrqState();
148  }
149 
155  bool readDEN() const { return (regs[0x11] & 0x10) != 0; }
156 
157  bool evaluateIsBadLine() const
158  {
159  return areBadLinesEnabled
160  && rasterY >= FIRST_DMA_LINE
161  && rasterY <= LAST_DMA_LINE
162  && (rasterY & 7) == yscroll;
163  }
164 
165  inline void sync()
166  {
167  event_context.cancel(*this);
168  event();
169  }
170 
171  inline void checkVblank()
172  {
173  // IRQ occurred (xraster != 0)
174  if (rasterY == (maxRasters - 1))
175  vblanking = true;
176  else
177  {
178  rasterY++;
179  // Trigger raster IRQ if IRQ line reached
180  if (rasterY == raster_irq)
181  activateIRQFlag(IRQ_RASTER);
182  }
183 
184  // In line $30, the DEN bit controls if Bad Lines can occur
185  if (rasterY == FIRST_DMA_LINE)
186  areBadLinesEnabled = readDEN();
187 
188  // Test for bad line condition
189  isBadLine = evaluateIsBadLine();
190  }
191 
192  inline void vblank()
193  {
194  // Vertical blank (line 0)
195  if (vblanking)
196  {
197  vblanking = lp_triggered = false;
198  rasterY = 0;
199  // Trigger raster IRQ if IRQ in line 0
200  if (raster_irq == 0)
201  activateIRQFlag(IRQ_RASTER);
202  }
203  }
204 
205  inline void updateMc()
206  {
207  // Update mc values in one pass
208  // after the dma has been processed
209  uint8_t mask = 1;
210  for (unsigned int i=0; i<8; i++, mask<<=1)
211  {
212  if (sprite_enable & mask)
213  sprite_mc[i] = (sprite_mc[i] + 3) & 0x3f;
214  }
215  }
216 
217  inline void updateMcBase()
218  {
219  uint8_t mask = 1;
220  for (unsigned int i=0; i<8; i++, mask<<=1)
221  {
222  if (sprite_y_expansion & mask)
223  sprite_mc_base[i] = sprite_mc[i];
224  if (sprite_mc_base[i] == 0x3f)
225  sprite_dma &= ~mask;
226  }
227  }
228 
230  inline void checkSpriteDmaExp()
231  {
232  const uint8_t y = rasterY & 0xff;
233  uint8_t mask = 1;
234  for (unsigned int i=0; i<8; i++, mask<<=1)
235  {
236  if ((sprite_enable & mask) && (y == regs[i << 1]))
237  {
238  sprite_dma |= mask;
239  sprite_mc_base[i] = 0;
240  sprite_y_expansion |= mask;
241  }
242  }
243  }
244 
246  inline void checkSpriteDma()
247  {
248  const uint8_t y = rasterY & 0xff;
249  uint8_t mask = 1;
250  for (unsigned int i=0; i<8; i++, mask<<=1)
251  {
252  if ((sprite_enable & mask) && (y == regs[i << 1]))
253  {
254  sprite_dma |= mask;
255  sprite_mc_base[i] = 0;
256  }
257  }
258  }
259 
260  inline void checkSpriteDisplay()
261  {
262  for (unsigned int i=0; i<8; i++)
263  {
264  sprite_mc[i] = sprite_mc_base[i];
265  }
266  }
267 
269  template<int n>
270  inline void startDma()
271  {
272  if (sprite_dma & (0x01 << n))
273  setBA(false);
274  }
275 
277  template<int n>
278  inline void endDma()
279  {
280  if (!(sprite_dma & (0x06 << n)))
281  setBA(true);
282  }
283 
285  inline void startBadline()
286  {
287  if (isBadLine)
288  setBA(false);
289  }
290 
291 protected:
292  MOS656X(EventContext *context);
293  ~MOS656X() {}
294 
295  // Environment Interface
296  virtual void interrupt (bool state) = 0;
297  virtual void setBA (bool state) = 0;
298 
305  uint8_t read(uint_least8_t addr);
306 
315  void write(uint_least8_t addr, uint8_t data);
316 
317 public:
318  void event();
319 
320  void chip(model_t model);
321  void lightpen();
322 
323  // Component Standard Calls
324  void reset();
325 
326  const char *credits() const { return credit; }
327 
328  int getCyclesPerLine() const { return cyclesPerLine; }
329 
330  int getRasterLines() const { return maxRasters; }
331 };
332 
333 // Template specializations
334 
336 template<>
337 inline void MOS656X::startDma<0>()
338 {
339  setBA(!(sprite_dma & 0x01));
340 }
341 
343 template<>
344 inline void MOS656X::endDma<7>()
345 {
346  setBA(true);
347 }
348 
349 #endif // MOS656X_H
uint8_t sprite_mc[8]
Definition: mos656x.h:121
bool vblanking
Definition: mos656x.h:102
bool areBadLinesEnabled
Definition: mos656x.h:96
Definition: mos656x.h:33
bool isBadLine
Definition: mos656x.h:99
void event()
Definition: mos656x.cpp:214
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:118
static const unsigned int LAST_DMA_LINE
Definition: mos656x.h:69
uint8_t read(uint_least8_t addr)
Definition: mos656x.cpp:91
uint8_t sprite_mc_base[8]
Definition: mos656x.h:120
uint8_t lpx
Definition: mos656x.h:114
uint8_t irqMask
Definition: mos656x.h:111
uint8_t regs[0x40]
Definition: mos656x.h:125
void write(uint_least8_t addr, uint8_t data)
Definition: mos656x.cpp:127
static const unsigned int FIRST_DMA_LINE
Definition: mos656x.h:66
uint8_t irqFlags
Definition: mos656x.h:108
Definition: event.h:50
uint8_t sprite_dma
Definition: mos656x.h:119
EventContext & event_context
Definition: mos656x.h:77
unsigned int rasterY
Definition: mos656x.h:88
bool lp_triggered
Definition: mos656x.h:105
virtual void cancel(Event &event)=0
uint8_t & sprite_enable
Definition: mos656x.h:118