libsidplayfp 3.0.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 <cstdint>
28
29#include "lightpen.h"
30#include "sprites.h"
31#include "Event.h"
32#include "EventCallback.h"
33#include "EventScheduler.h"
34
35#include "sidcxx11.h"
36
37namespace libsidplayfp
38{
39
44class MOS656X : private Event
45{
46public:
55
56private:
57 using ClockFunc = event_clock_t (MOS656X::*)();
58
59 using model_data_t = struct
60 {
61 unsigned int rasterLines;
62 unsigned int cyclesPerLine;
63 ClockFunc clock;
64 };
65
66private:
67 static const model_data_t modelData[];
68
70 static constexpr int IRQ_RASTER = 1 << 0;
71
73 static constexpr int IRQ_LIGHTPEN = 1 << 3;
74
76 static constexpr unsigned int FIRST_DMA_LINE = 0x30;
77
79 static constexpr unsigned int LAST_DMA_LINE = 0xf7;
80
81private:
83 ClockFunc clock;
84
86 event_clock_t rasterClk;
87
89 EventScheduler &eventScheduler;
90
92 unsigned int cyclesPerLine;
93
95 unsigned int maxRasters;
96
98 unsigned int lineCycle;
99
101 unsigned int rasterY;
102
104 unsigned int yscroll;
105
107 bool areBadLinesEnabled;
108
110 bool isBadLine;
111
113 bool rasterYIRQCondition;
114
116 bool vblanking;
117
119 bool lpAsserted;
120
122 uint8_t irqFlags;
123
125 uint8_t irqMask;
126
128 uint8_t regs[0x40] = {0};
129
131 Lightpen lp;
132
134 Sprites sprites;
135
136 EventCallback<MOS656X> badLineStateChangeEvent;
137
138 EventCallback<MOS656X> rasterYIRQEdgeDetectorEvent;
139
140 EventCallback<MOS656X> lightpenTriggerEvent;
141
142private:
143 event_clock_t clockPAL();
144 event_clock_t clockNTSC();
145 event_clock_t clockOldNTSC();
146
150 void handleIrqState();
151
155 void badLineStateChange() { setBA(!isBadLine); }
156
160 void rasterYIRQEdgeDetector()
161 {
162 const bool oldRasterYIRQCondition = rasterYIRQCondition;
163 rasterYIRQCondition = rasterY == readRasterLineIRQ();
164 if (!oldRasterYIRQCondition && rasterYIRQCondition)
165 activateIRQFlag(IRQ_RASTER);
166 }
167
168 void lightpenTrigger()
169 {
170 // Synchronise simulation
171 sync();
172
173 if (lp.trigger(lineCycle, rasterY))
174 {
175 activateIRQFlag(IRQ_LIGHTPEN);
176 }
177 }
178
183 void activateIRQFlag(int flag)
184 {
185 irqFlags |= flag;
186 handleIrqState();
187 }
188
194 inline unsigned int readRasterLineIRQ() const
195 {
196 return regs[0x12] + ((regs[0x11] & 0x80) << 1);
197 }
198
204 inline bool readDEN() const { return (regs[0x11] & 0x10) != 0; }
205
206 inline bool evaluateIsBadLine() const
207 {
208 return areBadLinesEnabled
209 && rasterY >= FIRST_DMA_LINE
210 && rasterY <= LAST_DMA_LINE
211 && (rasterY & 7) == yscroll;
212 }
213
217 inline unsigned int oldRasterY() const
218 {
219 return (rasterY > 0 ? rasterY : maxRasters) - 1;
220 }
221
222 inline void sync()
223 {
224 eventScheduler.cancel(*this);
225 event();
226 }
227
231 inline void checkVblank()
232 {
233 // IRQ occurred (xraster != 0)
234 if (rasterY == (maxRasters - 1))
235 {
236 vblanking = true;
237 }
238
239 // Check DEN bit on first cycle of the line following the first DMA line
240 if (rasterY == FIRST_DMA_LINE
241 && !areBadLinesEnabled
242 && readDEN())
243 {
244 areBadLinesEnabled = true;
245 }
246
247 // Disallow bad lines after the last possible one has passed
248 if (rasterY == LAST_DMA_LINE)
249 {
250 areBadLinesEnabled = false;
251 }
252
253 isBadLine = false;
254
255 if (!vblanking)
256 {
257 rasterY++;
258 rasterYIRQEdgeDetector();
259 if ((rasterY == FIRST_DMA_LINE) && !areBadLinesEnabled)
260 areBadLinesEnabled = readDEN();
261 }
262
263 if (evaluateIsBadLine())
264 isBadLine = true;
265 }
266
270 inline void vblank()
271 {
272 if (vblanking)
273 {
274 vblanking = false;
275 rasterY = 0;
276 rasterYIRQEdgeDetector();
277 lp.untrigger();
278 if (lpAsserted && lp.retrigger())
279 {
280 activateIRQFlag(IRQ_LIGHTPEN);
281 }
282 }
283 }
284
288 template<int n>
289 inline void startDma()
290 {
291 if (sprites.isDma(0x01 << n))
292 setBA(false);
293 }
294
298 template<int n>
299 inline void endDma()
300 {
301 if (!sprites.isDma(0x06 << n))
302 setBA(true);
303 }
304
308 inline void startBadline()
309 {
310 if (isBadLine)
311 setBA(false);
312 }
313
314protected:
315 MOS656X(EventScheduler &scheduler);
316 ~MOS656X() = default;
317
318 // Environment Interface
319 virtual void interrupt(bool state) = 0;
320 virtual void setBA(bool state) = 0;
321
328 uint8_t read(uint_least8_t addr);
329
338 void write(uint_least8_t addr, uint8_t data);
339
340public:
341 void event() override;
342
346 void chip(model_t model);
347
351 void triggerLightpen();
352
356 void clearLightpen();
357
361 void reset();
362
363 static const char *credits();
364};
365
366// Template specializations
367
371template<>
372inline void MOS656X::startDma<0>()
373{
374 setBA(!sprites.isDma(0x01));
375}
376
380template<>
381inline void MOS656X::endDma<7>()
382{
383 setBA(true);
384}
385
386}
387
388#endif // MOS656X_H
Event(const char *const name)
Definition Event.h:58
Definition mos656x.h:45
void write(uint_least8_t addr, uint8_t data)
Definition mos656x.cpp:163
model_t
Definition mos656x.h:48
@ MOS6567R8
NTSC-M.
Definition mos656x.h:50
@ MOS6572
PAL-N.
Definition mos656x.h:52
@ MOS6569
PAL-B.
Definition mos656x.h:51
@ MOS6573
PAL-M.
Definition mos656x.h:53
@ MOS6567R56A
OLD NTSC CHIP.
Definition mos656x.h:49
void clearLightpen()
Definition mos656x.cpp:707
void reset()
Definition mos656x.cpp:84
void event() override
Definition mos656x.cpp:274
void triggerLightpen()
Definition mos656x.cpp:700
uint8_t read(uint_least8_t addr)
Definition mos656x.cpp:126
void chip(model_t model)
Definition mos656x.cpp:107