Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libgambatte/src/video.h
2 views
1
/***************************************************************************
2
* Copyright (C) 2007 by Sindre AamÄs *
3
* [email protected] *
4
* *
5
* This program is free software; you can redistribute it and/or modify *
6
* it under the terms of the GNU General Public License version 2 as *
7
* published by the Free Software Foundation. *
8
* *
9
* This program is distributed in the hope that it will be useful, *
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12
* GNU General Public License version 2 for more details. *
13
* *
14
* You should have received a copy of the GNU General Public License *
15
* version 2 along with this program; if not, write to the *
16
* Free Software Foundation, Inc., *
17
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
18
***************************************************************************/
19
#ifndef VIDEO_H
20
#define VIDEO_H
21
22
#include "video/ppu.h"
23
#include "video/lyc_irq.h"
24
#include "video/next_m0_time.h"
25
#include "interruptrequester.h"
26
#include "minkeeper.h"
27
#include <memory>
28
#include "newstate.h"
29
30
namespace gambatte {
31
32
class VideoInterruptRequester {
33
InterruptRequester * intreq;
34
35
public:
36
explicit VideoInterruptRequester(InterruptRequester * intreq) : intreq(intreq) {}
37
void flagHdmaReq() const { gambatte::flagHdmaReq(intreq); }
38
void flagIrq(const unsigned bit) const { intreq->flagIrq(bit); }
39
void setNextEventTime(const unsigned long time) const { intreq->setEventTime<VIDEO>(time); }
40
};
41
42
class M0Irq {
43
unsigned char statReg_;
44
unsigned char lycReg_;
45
46
public:
47
M0Irq() : statReg_(0), lycReg_(0) {}
48
49
void lcdReset(const unsigned statReg, const unsigned lycReg) {
50
statReg_ = statReg;
51
lycReg_ = lycReg;
52
}
53
54
void statRegChange(const unsigned statReg,
55
const unsigned long nextM0IrqTime, const unsigned long cc, const bool cgb) {
56
if (nextM0IrqTime - cc > cgb * 2U)
57
statReg_ = statReg;
58
}
59
60
void lycRegChange(const unsigned lycReg,
61
const unsigned long nextM0IrqTime, const unsigned long cc, const bool ds, const bool cgb) {
62
if (nextM0IrqTime - cc > cgb * 5 + 1U - ds)
63
lycReg_ = lycReg;
64
}
65
66
void doEvent(unsigned char *const ifreg, const unsigned ly, const unsigned statReg, const unsigned lycReg) {
67
if (((statReg_ | statReg) & 0x08) && (!(statReg_ & 0x40) || ly != lycReg_))
68
*ifreg |= 2;
69
70
statReg_ = statReg;
71
lycReg_ = lycReg;
72
}
73
74
void loadState(const SaveState &state) {
75
lycReg_ = state.ppu.m0lyc;
76
statReg_ = state.mem.ioamhram.get()[0x141];
77
}
78
79
unsigned statReg() const { return statReg_; }
80
81
template<bool isReader>
82
void SyncState(NewState *ns)
83
{
84
NSS(statReg_);
85
NSS(lycReg_);
86
}
87
};
88
89
class LCD {
90
enum Event { MEM_EVENT, LY_COUNT }; enum { NUM_EVENTS = LY_COUNT + 1 };
91
enum MemEvent { ONESHOT_LCDSTATIRQ, ONESHOT_UPDATEWY2, MODE1_IRQ, LYC_IRQ, SPRITE_MAP,
92
HDMA_REQ, MODE2_IRQ, MODE0_IRQ }; enum { NUM_MEM_EVENTS = MODE0_IRQ + 1 };
93
94
class EventTimes {
95
MinKeeper<NUM_EVENTS> eventMin_;
96
MinKeeper<NUM_MEM_EVENTS> memEventMin_;
97
VideoInterruptRequester memEventRequester_;
98
99
void setMemEvent() {
100
const unsigned long nmet = nextMemEventTime();
101
eventMin_.setValue<MEM_EVENT>(nmet);
102
memEventRequester_.setNextEventTime(nmet);
103
}
104
105
public:
106
explicit EventTimes(const VideoInterruptRequester memEventRequester) : memEventRequester_(memEventRequester) {}
107
108
Event nextEvent() const { return static_cast<Event>(eventMin_.min()); }
109
unsigned long nextEventTime() const { return eventMin_.minValue(); }
110
unsigned long operator()(const Event e) const { return eventMin_.value(e); }
111
template<Event e> void set(const unsigned long time) { eventMin_.setValue<e>(time); }
112
void set(const Event e, const unsigned long time) { eventMin_.setValue(e, time); }
113
114
MemEvent nextMemEvent() const { return static_cast<MemEvent>(memEventMin_.min()); }
115
unsigned long nextMemEventTime() const { return memEventMin_.minValue(); }
116
unsigned long operator()(const MemEvent e) const { return memEventMin_.value(e); }
117
template<MemEvent e> void setm(const unsigned long time) { memEventMin_.setValue<e>(time); setMemEvent(); }
118
void set(const MemEvent e, const unsigned long time) { memEventMin_.setValue(e, time); setMemEvent(); }
119
120
void flagIrq(const unsigned bit) { memEventRequester_.flagIrq(bit); }
121
void flagHdmaReq() { memEventRequester_.flagHdmaReq(); }
122
123
template<bool isReader>
124
void SyncState(NewState *ns)
125
{
126
SSS(eventMin_);
127
SSS(memEventMin_);
128
//SSS(memEventRequester_); // not needed
129
}
130
};
131
132
PPU ppu;
133
unsigned long dmgColorsRgb32[3 * 4];
134
unsigned long cgbColorsRgb32[32768];
135
unsigned char bgpData[8 * 8];
136
unsigned char objpData[8 * 8];
137
138
EventTimes eventTimes_;
139
M0Irq m0Irq_;
140
LycIrq lycIrq;
141
NextM0Time nextM0Time_;
142
143
unsigned char statReg;
144
unsigned char m2IrqStatReg_;
145
unsigned char m1IrqStatReg_;
146
147
static void setDmgPalette(unsigned long *palette, const unsigned long *dmgColors, unsigned data);
148
void setDmgPaletteColor(unsigned index, unsigned long rgb32);
149
150
unsigned long gbcToRgb32(const unsigned bgr15);
151
void doCgbColorChange(unsigned char *const pdata, unsigned long *const palette, unsigned index, const unsigned data);
152
153
void refreshPalettes();
154
void setDBuffer();
155
156
void doMode2IrqEvent();
157
void event();
158
159
unsigned long m0TimeOfCurrentLine(unsigned long cc);
160
bool cgbpAccessible(unsigned long cycleCounter);
161
162
void mode3CyclesChange();
163
void doCgbBgColorChange(unsigned index, unsigned data, unsigned long cycleCounter);
164
void doCgbSpColorChange(unsigned index, unsigned data, unsigned long cycleCounter);
165
166
void (*scanlinecallback)();
167
int scanlinecallbacksl;
168
169
public:
170
LCD(const unsigned char *oamram, const unsigned char *vram_in, VideoInterruptRequester memEventRequester);
171
void reset(const unsigned char *oamram, const unsigned char *vram, bool cgb);
172
void setStatePtrs(SaveState &state);
173
void loadState(const SaveState &state, const unsigned char *oamram);
174
void setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned long rgb32);
175
void setCgbPalette(unsigned *lut);
176
void setVideoBuffer(uint_least32_t *videoBuf, int pitch);
177
void setLayers(unsigned mask) { ppu.setLayers(mask); }
178
179
int debugGetLY() const { return ppu.lyCounter().ly(); }
180
181
void dmgBgPaletteChange(const unsigned data, const unsigned long cycleCounter) {
182
update(cycleCounter);
183
bgpData[0] = data;
184
setDmgPalette(ppu.bgPalette(), dmgColorsRgb32, data);
185
}
186
187
void dmgSpPalette1Change(const unsigned data, const unsigned long cycleCounter) {
188
update(cycleCounter);
189
objpData[0] = data;
190
setDmgPalette(ppu.spPalette(), dmgColorsRgb32 + 4, data);
191
}
192
193
void dmgSpPalette2Change(const unsigned data, const unsigned long cycleCounter) {
194
update(cycleCounter);
195
objpData[1] = data;
196
setDmgPalette(ppu.spPalette() + 4, dmgColorsRgb32 + 8, data);
197
}
198
199
void cgbBgColorChange(unsigned index, const unsigned data, const unsigned long cycleCounter) {
200
if (bgpData[index] != data)
201
doCgbBgColorChange(index, data, cycleCounter);
202
}
203
204
void cgbSpColorChange(unsigned index, const unsigned data, const unsigned long cycleCounter) {
205
if (objpData[index] != data)
206
doCgbSpColorChange(index, data, cycleCounter);
207
}
208
209
unsigned cgbBgColorRead(const unsigned index, const unsigned long cycleCounter) {
210
return ppu.cgb() & cgbpAccessible(cycleCounter) ? bgpData[index] : 0xFF;
211
}
212
213
unsigned cgbSpColorRead(const unsigned index, const unsigned long cycleCounter) {
214
return ppu.cgb() & cgbpAccessible(cycleCounter) ? objpData[index] : 0xFF;
215
}
216
217
void updateScreen(bool blanklcd, unsigned long cc);
218
void resetCc(unsigned long oldCC, unsigned long newCc);
219
void speedChange(unsigned long cycleCounter);
220
bool vramAccessible(unsigned long cycleCounter);
221
bool oamReadable(unsigned long cycleCounter);
222
bool oamWritable(unsigned long cycleCounter);
223
void wxChange(unsigned newValue, unsigned long cycleCounter);
224
void wyChange(unsigned newValue, unsigned long cycleCounter);
225
void oamChange(unsigned long cycleCounter);
226
void oamChange(const unsigned char *oamram, unsigned long cycleCounter);
227
void scxChange(unsigned newScx, unsigned long cycleCounter);
228
void scyChange(unsigned newValue, unsigned long cycleCounter);
229
230
void vramChange(const unsigned long cycleCounter) { update(cycleCounter); }
231
232
unsigned getStat(unsigned lycReg, unsigned long cycleCounter);
233
234
unsigned getLyReg(const unsigned long cycleCounter) {
235
unsigned lyReg = 0;
236
237
if (ppu.lcdc() & 0x80) {
238
if (cycleCounter >= ppu.lyCounter().time())
239
update(cycleCounter);
240
241
lyReg = ppu.lyCounter().ly();
242
243
if (lyReg == 153) {
244
if (isDoubleSpeed()) {
245
if (ppu.lyCounter().time() - cycleCounter <= 456 * 2 - 8)
246
lyReg = 0;
247
} else
248
lyReg = 0;
249
} else if (ppu.lyCounter().time() - cycleCounter <= 4)
250
++lyReg;
251
}
252
253
return lyReg;
254
}
255
256
unsigned long nextMode1IrqTime() const { return eventTimes_(MODE1_IRQ); }
257
258
void lcdcChange(unsigned data, unsigned long cycleCounter);
259
void lcdstatChange(unsigned data, unsigned long cycleCounter);
260
void lycRegChange(unsigned data, unsigned long cycleCounter);
261
262
void enableHdma(unsigned long cycleCounter);
263
void disableHdma(unsigned long cycleCounter);
264
bool hdmaIsEnabled() const { return eventTimes_(HDMA_REQ) != DISABLED_TIME; }
265
266
void update(unsigned long cycleCounter);
267
268
bool isCgb() const { return ppu.cgb(); }
269
bool isDoubleSpeed() const { return ppu.lyCounter().isDoubleSpeed(); }
270
271
unsigned long *bgPalette() { return ppu.bgPalette(); }
272
unsigned long *spPalette() { return ppu.spPalette(); }
273
274
void setScanlineCallback(void (*callback)(), int sl) { scanlinecallback = callback; scanlinecallbacksl = sl; }
275
276
template<bool isReader>void SyncState(NewState *ns);
277
};
278
279
}
280
281
#endif
282
283