libsidplayfp 2.2.2
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
38namespace libsidplayfp
39{
40
45class MOS656X : private Event
46{
47public:
48 typedef enum
49 {
50 MOS6567R56A = 0
56
57private:
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
67private:
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
82private:
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
141private:
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] + ((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
300protected:
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
326public:
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
357template<>
358inline void MOS656X::startDma<0>()
359{
360 setBA(!sprites.isDma(0x01));
361}
362
366template<>
367inline void MOS656X::endDma<7>()
368{
369 setBA(true);
370}
371
372}
373
374#endif // MOS656X_H
Definition: Event.h:39
Definition: mos656x.h:46
void write(uint_least8_t addr, uint8_t data)
Definition: mos656x.cpp:147
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:697
void reset()
Definition: mos656x.cpp:76
void event() override
Definition: mos656x.cpp:258
void triggerLightpen()
Definition: mos656x.cpp:684
uint8_t read(uint_least8_t addr)
Definition: mos656x.cpp:110
void chip(model_t model)
Definition: mos656x.cpp:99