Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libsnes/bsnes/snes/alt/ppu-compatibility/ppu.cpp
2 views
1
#include <snes/snes.hpp>
2
3
#define PPU_CPP
4
namespace SNES {
5
6
PPU ppu;
7
8
#include "memory/memory.cpp"
9
#include "mmio/mmio.cpp"
10
#include "render/render.cpp"
11
#include "serialization.cpp"
12
13
void PPU::step(unsigned clocks) {
14
clock += clocks;
15
}
16
17
void PPU::synchronize_cpu() {
18
if(CPU::Threaded == true) {
19
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All)
20
co_switch(cpu.thread);
21
else if(clock >= 0 && scheduler.sync == Scheduler::SynchronizeMode::All)
22
interface()->message("PPU had to advance nondeterministically!");
23
} else {
24
while(clock >= 0) cpu.enter();
25
}
26
}
27
28
void PPU::Enter() { ppu.enter(); }
29
30
void PPU::enter() {
31
while(true) {
32
if(scheduler.sync == Scheduler::SynchronizeMode::CPU) {
33
synchronize_cpu(); // when in CPU sync mode, always switch back to CPU as soon as possible
34
}
35
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
36
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
37
}
38
39
switch(uindex)
40
{
41
case 0: enter1(); break;
42
case 1: enter2(); break;
43
case 2: enter3(); break;
44
case 3: enter4(); break;
45
}
46
uindex++;
47
uindex &= 3;
48
}
49
}
50
51
void PPU::enter1() {
52
//H = 0 (initialize)
53
scanline();
54
add_clocks(10);
55
}
56
57
void PPU::enter2() {
58
//H = 10 (cache mode7 registers + OAM address reset)
59
cache.m7_hofs = regs.m7_hofs;
60
cache.m7_vofs = regs.m7_vofs;
61
cache.m7a = regs.m7a;
62
cache.m7b = regs.m7b;
63
cache.m7c = regs.m7c;
64
cache.m7d = regs.m7d;
65
cache.m7x = regs.m7x;
66
cache.m7y = regs.m7y;
67
if(vcounter() == (!overscan() ? 225 : 240)) {
68
if(regs.display_disabled == false) {
69
regs.oam_addr = regs.oam_baseaddr << 1;
70
regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127;
71
}
72
}
73
add_clocks(502);
74
}
75
76
void PPU::enter3() {
77
//H = 512 (render)
78
render_scanline();
79
add_clocks(640);
80
}
81
82
void PPU::enter4() {
83
//H = 1152 (cache OBSEL)
84
if(cache.oam_basesize != regs.oam_basesize) {
85
cache.oam_basesize = regs.oam_basesize;
86
sprite_list_valid = false;
87
}
88
cache.oam_nameselect = regs.oam_nameselect;
89
cache.oam_tdaddr = regs.oam_tdaddr;
90
add_clocks(lineclocks() - 1152); //seek to start of next scanline
91
}
92
93
void PPU::add_clocks(unsigned clocks) {
94
tick(clocks);
95
step(clocks);
96
synchronize_cpu();
97
}
98
99
void PPU::scanline() {
100
line = vcounter();
101
102
if(line == 0) {
103
frame();
104
105
//RTO flag reset
106
regs.time_over = false;
107
regs.range_over = false;
108
}
109
110
interface()->scanlineStart(line);
111
112
if(line == 1) {
113
//mosaic reset
114
for(int bg = BG1; bg <= BG4; bg++) regs.bg_y[bg] = 1;
115
regs.mosaic_countdown = regs.mosaic_size + 1;
116
regs.mosaic_countdown--;
117
} else {
118
for(int bg = BG1; bg <= BG4; bg++) {
119
if(!regs.mosaic_enabled[bg] || !regs.mosaic_countdown) regs.bg_y[bg] = line;
120
}
121
if(!regs.mosaic_countdown) regs.mosaic_countdown = regs.mosaic_size + 1;
122
regs.mosaic_countdown--;
123
}
124
}
125
126
void PPU::render_scanline() {
127
if(line >= 1 && line < (!overscan() ? 225 : 240)) {
128
if(framecounter) return;
129
render_line_oam_rto();
130
render_line();
131
}
132
}
133
134
void PPU::frame() {
135
system.frame();
136
137
if(field() == 0) {
138
display.interlace = regs.interlace;
139
regs.scanlines = (regs.overscan == false) ? 224 : 239;
140
}
141
142
framecounter = (frameskip == 0 ? 0 : (framecounter + 1) % frameskip);
143
}
144
145
void PPU::enable() {
146
function<uint8 (unsigned)> read = { &PPU::mmio_read, (PPU*)&ppu };
147
function<void (unsigned, uint8)> write = { &PPU::mmio_write, (PPU*)&ppu };
148
149
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2100, 0x213f, read, write);
150
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2100, 0x213f, read, write);
151
}
152
153
void PPU::power() {
154
ppu1_version = config.ppu1.version;
155
ppu2_version = config.ppu2.version;
156
157
for(int i=0;i<128*1024;i++) vram[i] = 0;
158
for(int i=0;i<544;i++) oam[i] = 0;
159
for(int i=0;i<512;i++) cgram[i] = 0;
160
flush_tiledata_cache();
161
162
region = (system.region() == System::Region::NTSC ? 0 : 1); //0 = NTSC, 1 = PAL
163
164
regs.ioamaddr = 0x0000;
165
regs.icgramaddr = 0x01ff;
166
167
//$2100
168
regs.display_disabled = true;
169
regs.display_brightness = 15;
170
171
//$2101
172
regs.oam_basesize = 0;
173
regs.oam_nameselect = 0;
174
regs.oam_tdaddr = 0x0000;
175
176
cache.oam_basesize = 0;
177
cache.oam_nameselect = 0;
178
cache.oam_tdaddr = 0x0000;
179
180
//$2102-$2103
181
regs.oam_baseaddr = 0x0000;
182
regs.oam_addr = 0x0000;
183
regs.oam_priority = false;
184
regs.oam_firstsprite = 0;
185
186
//$2104
187
regs.oam_latchdata = 0x00;
188
189
//$2105
190
regs.bg_tilesize[BG1] = 0;
191
regs.bg_tilesize[BG2] = 0;
192
regs.bg_tilesize[BG3] = 0;
193
regs.bg_tilesize[BG4] = 0;
194
regs.bg3_priority = 0;
195
regs.bg_mode = 0;
196
197
//$2106
198
regs.mosaic_size = 0;
199
regs.mosaic_enabled[BG1] = false;
200
regs.mosaic_enabled[BG2] = false;
201
regs.mosaic_enabled[BG3] = false;
202
regs.mosaic_enabled[BG4] = false;
203
regs.mosaic_countdown = 0;
204
205
//$2107-$210a
206
regs.bg_scaddr[BG1] = 0x0000;
207
regs.bg_scaddr[BG2] = 0x0000;
208
regs.bg_scaddr[BG3] = 0x0000;
209
regs.bg_scaddr[BG4] = 0x0000;
210
regs.bg_scsize[BG1] = SC_32x32;
211
regs.bg_scsize[BG2] = SC_32x32;
212
regs.bg_scsize[BG3] = SC_32x32;
213
regs.bg_scsize[BG4] = SC_32x32;
214
215
//$210b-$210c
216
regs.bg_tdaddr[BG1] = 0x0000;
217
regs.bg_tdaddr[BG2] = 0x0000;
218
regs.bg_tdaddr[BG3] = 0x0000;
219
regs.bg_tdaddr[BG4] = 0x0000;
220
221
//$210d-$2114
222
regs.bg_ofslatch = 0x00;
223
regs.m7_hofs = regs.m7_vofs = 0x0000;
224
regs.bg_hofs[BG1] = regs.bg_vofs[BG1] = 0x0000;
225
regs.bg_hofs[BG2] = regs.bg_vofs[BG2] = 0x0000;
226
regs.bg_hofs[BG3] = regs.bg_vofs[BG3] = 0x0000;
227
regs.bg_hofs[BG4] = regs.bg_vofs[BG4] = 0x0000;
228
229
//$2115
230
regs.vram_incmode = 1;
231
regs.vram_mapping = 0;
232
regs.vram_incsize = 1;
233
234
//$2116-$2117
235
regs.vram_addr = 0x0000;
236
237
//$211a
238
regs.mode7_repeat = 0;
239
regs.mode7_vflip = false;
240
regs.mode7_hflip = false;
241
242
//$211b-$2120
243
regs.m7_latch = 0x00;
244
regs.m7a = 0x0000;
245
regs.m7b = 0x0000;
246
regs.m7c = 0x0000;
247
regs.m7d = 0x0000;
248
regs.m7x = 0x0000;
249
regs.m7y = 0x0000;
250
251
//$2121
252
regs.cgram_addr = 0x0000;
253
254
//$2122
255
regs.cgram_latchdata = 0x00;
256
257
//$2123-$2125
258
regs.window1_enabled[BG1] = false;
259
regs.window1_enabled[BG2] = false;
260
regs.window1_enabled[BG3] = false;
261
regs.window1_enabled[BG4] = false;
262
regs.window1_enabled[OAM] = false;
263
regs.window1_enabled[COL] = false;
264
265
regs.window1_invert [BG1] = false;
266
regs.window1_invert [BG2] = false;
267
regs.window1_invert [BG3] = false;
268
regs.window1_invert [BG4] = false;
269
regs.window1_invert [OAM] = false;
270
regs.window1_invert [COL] = false;
271
272
regs.window2_enabled[BG1] = false;
273
regs.window2_enabled[BG2] = false;
274
regs.window2_enabled[BG3] = false;
275
regs.window2_enabled[BG4] = false;
276
regs.window2_enabled[OAM] = false;
277
regs.window2_enabled[COL] = false;
278
279
regs.window2_invert [BG1] = false;
280
regs.window2_invert [BG2] = false;
281
regs.window2_invert [BG3] = false;
282
regs.window2_invert [BG4] = false;
283
regs.window2_invert [OAM] = false;
284
regs.window2_invert [COL] = false;
285
286
//$2126-$2129
287
regs.window1_left = 0x00;
288
regs.window1_right = 0x00;
289
regs.window2_left = 0x00;
290
regs.window2_right = 0x00;
291
292
//$212a-$212b
293
regs.window_mask[BG1] = 0;
294
regs.window_mask[BG2] = 0;
295
regs.window_mask[BG3] = 0;
296
regs.window_mask[BG4] = 0;
297
regs.window_mask[OAM] = 0;
298
regs.window_mask[COL] = 0;
299
300
//$212c-$212d
301
regs.bg_enabled[BG1] = false;
302
regs.bg_enabled[BG2] = false;
303
regs.bg_enabled[BG3] = false;
304
regs.bg_enabled[BG4] = false;
305
regs.bg_enabled[OAM] = false;
306
regs.bgsub_enabled[BG1] = false;
307
regs.bgsub_enabled[BG2] = false;
308
regs.bgsub_enabled[BG3] = false;
309
regs.bgsub_enabled[BG4] = false;
310
regs.bgsub_enabled[OAM] = false;
311
312
//$212e-$212f
313
regs.window_enabled[BG1] = false;
314
regs.window_enabled[BG2] = false;
315
regs.window_enabled[BG3] = false;
316
regs.window_enabled[BG4] = false;
317
regs.window_enabled[OAM] = false;
318
regs.sub_window_enabled[BG1] = false;
319
regs.sub_window_enabled[BG2] = false;
320
regs.sub_window_enabled[BG3] = false;
321
regs.sub_window_enabled[BG4] = false;
322
regs.sub_window_enabled[OAM] = false;
323
324
//$2130
325
regs.color_mask = 0;
326
regs.colorsub_mask = 0;
327
regs.addsub_mode = false;
328
regs.direct_color = false;
329
330
//$2131
331
regs.color_mode = 0;
332
regs.color_halve = false;
333
regs.color_enabled[BACK] = false;
334
regs.color_enabled[OAM] = false;
335
regs.color_enabled[BG4] = false;
336
regs.color_enabled[BG3] = false;
337
regs.color_enabled[BG2] = false;
338
regs.color_enabled[BG1] = false;
339
340
//$2132
341
regs.color_r = 0x00;
342
regs.color_g = 0x00;
343
regs.color_b = 0x00;
344
regs.color_rgb = 0x0000;
345
346
//$2133
347
regs.mode7_extbg = false;
348
regs.pseudo_hires = false;
349
regs.overscan = false;
350
regs.scanlines = 224;
351
regs.oam_interlace = false;
352
regs.interlace = false;
353
354
//$2137
355
regs.hcounter = 0;
356
regs.vcounter = 0;
357
regs.latch_hcounter = 0;
358
regs.latch_vcounter = 0;
359
regs.counters_latched = false;
360
361
//$2139-$213a
362
regs.vram_readbuffer = 0x0000;
363
364
//$213e
365
regs.time_over = false;
366
regs.range_over = false;
367
368
reset();
369
}
370
371
void PPU::reset() {
372
create(Enter, system.cpu_frequency());
373
PPUcounter::reset();
374
memset(surface, 0, 512 * 512 * sizeof(uint32));
375
376
uindex = 0;
377
378
//zero 01-dec-2012 - gotta reset these sometime, somewhere
379
memset(oam_itemlist, 0, sizeof(oam_itemlist));
380
memset(oam_tilelist, 0, sizeof(oam_tilelist));
381
memset(oam_line_pal, 0, sizeof(oam_line_pal));
382
memset(oam_line_pri, 0, sizeof(oam_line_pri));
383
active_sprite = sprite_list_valid = 0;
384
memset(bg_info, 0, sizeof(bg_info));
385
memset(window, 0, sizeof(window));
386
memset(pixel_cache, 0, sizeof(pixel_cache));
387
regs.oam_tilecount = regs.oam_itemcount = 0;
388
389
frame();
390
391
//$2100
392
regs.display_disabled = true;
393
394
display.interlace = false;
395
display.overscan = false;
396
regs.scanlines = 224;
397
398
memset(sprite_list, 0, sizeof(sprite_list));
399
sprite_list_valid = false;
400
401
//open bus support
402
regs.ppu1_mdr = 0xff;
403
regs.ppu2_mdr = 0xff;
404
405
//bg line counters
406
regs.bg_y[0] = 0;
407
regs.bg_y[1] = 0;
408
regs.bg_y[2] = 0;
409
regs.bg_y[3] = 0;
410
}
411
412
void PPU::layer_enable(unsigned layer, unsigned priority, bool enable) {
413
switch(layer * 4 + priority) {
414
case 0: layer_enabled[BG1][0] = enable; break;
415
case 1: layer_enabled[BG1][1] = enable; break;
416
case 4: layer_enabled[BG2][0] = enable; break;
417
case 5: layer_enabled[BG2][1] = enable; break;
418
case 8: layer_enabled[BG3][0] = enable; break;
419
case 9: layer_enabled[BG3][1] = enable; break;
420
case 12: layer_enabled[BG4][0] = enable; break;
421
case 13: layer_enabled[BG4][1] = enable; break;
422
case 16: layer_enabled[OAM][0] = enable; break;
423
case 17: layer_enabled[OAM][1] = enable; break;
424
case 18: layer_enabled[OAM][2] = enable; break;
425
case 19: layer_enabled[OAM][3] = enable; break;
426
}
427
}
428
429
void PPU::set_frameskip(unsigned frameskip_) {
430
frameskip = frameskip_;
431
framecounter = 0;
432
}
433
434
PPU::PPU()
435
: vram(nullptr)
436
, oam(nullptr)
437
, cgram(nullptr)
438
{
439
440
}
441
442
void PPU::initialize()
443
{
444
vram = (uint8*)interface()->allocSharedMemory("VRAM",128 * 1024);
445
oam = (uint8*)interface()->allocSharedMemory("OAM",544);
446
cgram = (uint8*)interface()->allocSharedMemory("CGRAM",512);
447
448
surface = new uint32[512 * 512];
449
output = surface + 16 * 512;
450
451
alloc_tiledata_cache();
452
453
for(unsigned l = 0; l < 16; l++) {
454
for(unsigned i = 0; i < 4096; i++) {
455
mosaic_table[l][i] = (i / (l + 1)) * (l + 1);
456
}
457
}
458
459
layer_enabled[BG1][0] = true;
460
layer_enabled[BG1][1] = true;
461
layer_enabled[BG2][0] = true;
462
layer_enabled[BG2][1] = true;
463
layer_enabled[BG3][0] = true;
464
layer_enabled[BG3][1] = true;
465
layer_enabled[BG4][0] = true;
466
layer_enabled[BG4][1] = true;
467
layer_enabled[OAM][0] = true;
468
layer_enabled[OAM][1] = true;
469
layer_enabled[OAM][2] = true;
470
layer_enabled[OAM][3] = true;
471
frameskip = 0;
472
framecounter = 0;
473
}
474
475
PPU::~PPU() {
476
delete[] surface;
477
free_tiledata_cache();
478
interface()->freeSharedMemory(vram);
479
interface()->freeSharedMemory(oam);
480
interface()->freeSharedMemory(cgram);
481
}
482
483
}
484
485