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
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
141 EventCallback<MOS656X> lightpenTriggerEvent;
142
143private:
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
313protected:
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
339public:
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
370template<>
371inline void MOS656X::startDma<0>()
372{
373 setBA(!sprites.isDma(0x01));
374}
375
379template<>
380inline 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