libsidplayfp 2.15.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 enum class model_t
49 {
50 MOS6567R56A = 0
51 ,MOS6567R8
52 ,MOS6569
53 ,MOS6572
54 ,MOS6573
55 };
56
57private:
58 using ClockFunc = event_clock_t (MOS656X::*)();
59
60 using model_data_t = struct
61 {
62 unsigned int rasterLines;
63 unsigned int cyclesPerLine;
64 ClockFunc clock;
65 };
66
67private:
68 static const model_data_t modelData[];
69
71 static constexpr int IRQ_RASTER = 1 << 0;
72
74 static constexpr int IRQ_LIGHTPEN = 1 << 3;
75
77 static constexpr unsigned int FIRST_DMA_LINE = 0x30;
78
80 static constexpr 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 uint8_t regs[0x40] = {0};
130
132 Lightpen lp;
133
135 Sprites sprites;
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 if ((rasterY == FIRST_DMA_LINE) && !areBadLinesEnabled)
261 areBadLinesEnabled = readDEN();
262 }
263
264 if (evaluateIsBadLine())
265 isBadLine = true;
266 }
267
271 inline void vblank()
272 {
273 if (vblanking)
274 {
275 vblanking = false;
276 rasterY = 0;
277 rasterYIRQEdgeDetector();
278 lp.untrigger();
279 if (lpAsserted && lp.retrigger())
280 {
281 activateIRQFlag(IRQ_LIGHTPEN);
282 }
283 }
284 }
285
289 template<int n>
290 inline void startDma()
291 {
292 if (sprites.isDma(0x01 << n))
293 setBA(false);
294 }
295
299 template<int n>
300 inline void endDma()
301 {
302 if (!sprites.isDma(0x06 << n))
303 setBA(true);
304 }
305
309 inline void startBadline()
310 {
311 if (isBadLine)
312 setBA(false);
313 }
314
315protected:
316 MOS656X(EventScheduler &scheduler);
317 ~MOS656X() = default;
318
319 // Environment Interface
320 virtual void interrupt(bool state) = 0;
321 virtual void setBA(bool state) = 0;
322
329 uint8_t read(uint_least8_t addr);
330
339 void write(uint_least8_t addr, uint8_t data);
340
341public:
342 void event() override;
343
347 void chip(model_t model);
348
352 void triggerLightpen();
353
357 void clearLightpen();
358
362 void reset();
363
364 static const char *credits();
365};
366
367// Template specializations
368
372template<>
373inline void MOS656X::startDma<0>()
374{
375 setBA(!sprites.isDma(0x01));
376}
377
381template<>
382inline void MOS656X::endDma<7>()
383{
384 setBA(true);
385}
386
387}
388
389#endif // MOS656X_H
Definition Event.h:39
Definition mos656x.h:46
void write(uint_least8_t addr, uint8_t data)
Definition mos656x.cpp:156
model_t
Definition mos656x.h:49
void clearLightpen()
Definition mos656x.cpp:700
void reset()
Definition mos656x.cpp:79
void event() override
Definition mos656x.cpp:267
void triggerLightpen()
Definition mos656x.cpp:693
uint8_t read(uint_least8_t addr)
Definition mos656x.cpp:119
void chip(model_t model)
Definition mos656x.cpp:102