1 #ifdef BPPU_CPP
2 
3 //INIDISP
mmio_w2100(uint8 value)4 void bPPU::mmio_w2100(uint8 value) {
5   if(regs.display_disabled == true && cpu.vcounter() == (!overscan() ? 225 : 240)) {
6     regs.oam_addr = regs.oam_baseaddr << 1;
7     regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127;
8   }
9 
10   regs.display_disabled   = !!(value & 0x80);
11   regs.display_brightness = value & 15;
12 }
13 
14 //OBSEL
mmio_w2101(uint8 value)15 void bPPU::mmio_w2101(uint8 value) {
16   regs.oam_basesize   = (value >> 5) & 7;
17   regs.oam_nameselect = (value >> 3) & 3;
18   regs.oam_tdaddr     = (value & 3) << 14;
19 }
20 
21 //OAMADDL
mmio_w2102(uint8 data)22 void bPPU::mmio_w2102(uint8 data) {
23   regs.oam_baseaddr    = (regs.oam_baseaddr & ~0xff) | (data << 0);
24   regs.oam_baseaddr   &= 0x01ff;
25   regs.oam_addr        = regs.oam_baseaddr << 1;
26   regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127;
27 }
28 
29 //OAMADDH
mmio_w2103(uint8 data)30 void bPPU::mmio_w2103(uint8 data) {
31   regs.oam_priority    = !!(data & 0x80);
32   regs.oam_baseaddr    = (regs.oam_baseaddr &  0xff) | (data << 8);
33   regs.oam_baseaddr   &= 0x01ff;
34   regs.oam_addr        = regs.oam_baseaddr << 1;
35   regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127;
36 }
37 
38 //OAMDATA
mmio_w2104(uint8 data)39 void bPPU::mmio_w2104(uint8 data) {
40   if(regs.oam_addr & 0x0200) {
41     oam_mmio_write(regs.oam_addr, data);
42   } else if((regs.oam_addr & 1) == 0) {
43     regs.oam_latchdata = data;
44   } else {
45     oam_mmio_write((regs.oam_addr & ~1) + 0, regs.oam_latchdata);
46     oam_mmio_write((regs.oam_addr & ~1) + 1, data);
47   }
48 
49   regs.oam_addr++;
50   regs.oam_addr &= 0x03ff;
51   regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127;
52 }
53 
54 //BGMODE
mmio_w2105(uint8 value)55 void bPPU::mmio_w2105(uint8 value) {
56   regs.bg_tilesize[BG4] = !!(value & 0x80);
57   regs.bg_tilesize[BG3] = !!(value & 0x40);
58   regs.bg_tilesize[BG2] = !!(value & 0x20);
59   regs.bg_tilesize[BG1] = !!(value & 0x10);
60   regs.bg3_priority     = !!(value & 0x08);
61   regs.bg_mode          = (value & 7);
62 }
63 
64 //MOSAIC
mmio_w2106(uint8 value)65 void bPPU::mmio_w2106(uint8 value) {
66   regs.mosaic_size         = (value >> 4) & 15;
67   regs.mosaic_enabled[BG4] = !!(value & 0x08);
68   regs.mosaic_enabled[BG3] = !!(value & 0x04);
69   regs.mosaic_enabled[BG2] = !!(value & 0x02);
70   regs.mosaic_enabled[BG1] = !!(value & 0x01);
71 }
72 
73 //BG1SC
mmio_w2107(uint8 value)74 void bPPU::mmio_w2107(uint8 value) {
75   regs.bg_scaddr[BG1] = (value & 0x7c) << 9;
76   regs.bg_scsize[BG1] = value & 3;
77 }
78 
79 //BG2SC
mmio_w2108(uint8 value)80 void bPPU::mmio_w2108(uint8 value) {
81   regs.bg_scaddr[BG2] = (value & 0x7c) << 9;
82   regs.bg_scsize[BG2] = value & 3;
83 }
84 
85 //BG3SC
mmio_w2109(uint8 value)86 void bPPU::mmio_w2109(uint8 value) {
87   regs.bg_scaddr[BG3] = (value & 0x7c) << 9;
88   regs.bg_scsize[BG3] = value & 3;
89 }
90 
91 //BG4SC
mmio_w210a(uint8 value)92 void bPPU::mmio_w210a(uint8 value) {
93   regs.bg_scaddr[BG4] = (value & 0x7c) << 9;
94   regs.bg_scsize[BG4] = value & 3;
95 }
96 
97 //BG12NBA
mmio_w210b(uint8 value)98 void bPPU::mmio_w210b(uint8 value) {
99   regs.bg_tdaddr[BG1] = (value & 0x07) << 13;
100   regs.bg_tdaddr[BG2] = (value & 0x70) <<  9;
101 }
102 
103 //BG34NBA
mmio_w210c(uint8 value)104 void bPPU::mmio_w210c(uint8 value) {
105   regs.bg_tdaddr[BG3] = (value & 0x07) << 13;
106   regs.bg_tdaddr[BG4] = (value & 0x70) <<  9;
107 }
108 
109 //BG1HOFS
mmio_w210d(uint8 value)110 void bPPU::mmio_w210d(uint8 value) {
111   regs.m7_hofs  = (value << 8) | regs.m7_latch;
112   regs.m7_latch = value;
113 
114   regs.bg_hofs[BG1] = (value << 8) | (regs.bg_ofslatch & ~7) | ((regs.bg_hofs[BG1] >> 8) & 7);
115   regs.bg_ofslatch  = value;
116 }
117 
118 //BG1VOFS
mmio_w210e(uint8 value)119 void bPPU::mmio_w210e(uint8 value) {
120   regs.m7_vofs  = (value << 8) | regs.m7_latch;
121   regs.m7_latch = value;
122 
123   regs.bg_vofs[BG1] = (value << 8) | (regs.bg_ofslatch);
124   regs.bg_ofslatch  = value;
125 }
126 
127 //BG2HOFS
mmio_w210f(uint8 value)128 void bPPU::mmio_w210f(uint8 value) {
129   regs.bg_hofs[BG2] = (value << 8) | (regs.bg_ofslatch & ~7) | ((regs.bg_hofs[BG2] >> 8) & 7);
130   regs.bg_ofslatch  = value;
131 }
132 
133 //BG2VOFS
mmio_w2110(uint8 value)134 void bPPU::mmio_w2110(uint8 value) {
135   regs.bg_vofs[BG2] = (value << 8) | (regs.bg_ofslatch);
136   regs.bg_ofslatch  = value;
137 }
138 
139 //BG3HOFS
mmio_w2111(uint8 value)140 void bPPU::mmio_w2111(uint8 value) {
141   regs.bg_hofs[BG3] = (value << 8) | (regs.bg_ofslatch & ~7) | ((regs.bg_hofs[BG3] >> 8) & 7);
142   regs.bg_ofslatch  = value;
143 }
144 
145 //BG3VOFS
mmio_w2112(uint8 value)146 void bPPU::mmio_w2112(uint8 value) {
147   regs.bg_vofs[BG3] = (value << 8) | (regs.bg_ofslatch);
148   regs.bg_ofslatch  = value;
149 }
150 
151 //BG4HOFS
mmio_w2113(uint8 value)152 void bPPU::mmio_w2113(uint8 value) {
153   regs.bg_hofs[BG4] = (value << 8) | (regs.bg_ofslatch & ~7) | ((regs.bg_hofs[BG4] >> 8) & 7);
154   regs.bg_ofslatch  = value;
155 }
156 
157 //BG4VOFS
mmio_w2114(uint8 value)158 void bPPU::mmio_w2114(uint8 value) {
159   regs.bg_vofs[BG4] = (value << 8) | (regs.bg_ofslatch);
160   regs.bg_ofslatch  = value;
161 }
162 
163 //VMAIN
mmio_w2115(uint8 value)164 void bPPU::mmio_w2115(uint8 value) {
165   regs.vram_incmode = !!(value & 0x80);
166   regs.vram_mapping = (value >> 2) & 3;
167   switch(value & 3) {
168     case 0: regs.vram_incsize =   1; break;
169     case 1: regs.vram_incsize =  32; break;
170     case 2: regs.vram_incsize = 128; break;
171     case 3: regs.vram_incsize = 128; break;
172   }
173 }
174 
175 //VMADDL
mmio_w2116(uint8 value)176 void bPPU::mmio_w2116(uint8 value) {
177   regs.vram_addr = (regs.vram_addr & 0xff00) | value;
178   uint16 addr = get_vram_address();
179   regs.vram_readbuffer  = vram_mmio_read(addr + 0);
180   regs.vram_readbuffer |= vram_mmio_read(addr + 1) << 8;
181 }
182 
183 //VMADDH
mmio_w2117(uint8 value)184 void bPPU::mmio_w2117(uint8 value) {
185   regs.vram_addr = (value << 8) | (regs.vram_addr & 0x00ff);
186   uint16 addr = get_vram_address();
187   regs.vram_readbuffer  = vram_mmio_read(addr + 0);
188   regs.vram_readbuffer |= vram_mmio_read(addr + 1) << 8;
189 }
190 
191 //VMDATAL
mmio_w2118(uint8 value)192 void bPPU::mmio_w2118(uint8 value) {
193 uint16 addr = get_vram_address();
194   vram_mmio_write(addr, value);
195   bg_tiledata_state[TILE_2BIT][(addr >> 4)] = 1;
196   bg_tiledata_state[TILE_4BIT][(addr >> 5)] = 1;
197   bg_tiledata_state[TILE_8BIT][(addr >> 6)] = 1;
198 
199   if(regs.vram_incmode == 0) {
200     regs.vram_addr += regs.vram_incsize;
201   }
202 }
203 
204 //VMDATAH
mmio_w2119(uint8 value)205 void bPPU::mmio_w2119(uint8 value) {
206 uint16 addr = get_vram_address() + 1;
207   vram_mmio_write(addr, value);
208   bg_tiledata_state[TILE_2BIT][(addr >> 4)] = 1;
209   bg_tiledata_state[TILE_4BIT][(addr >> 5)] = 1;
210   bg_tiledata_state[TILE_8BIT][(addr >> 6)] = 1;
211 
212   if(regs.vram_incmode == 1) {
213     regs.vram_addr += regs.vram_incsize;
214   }
215 }
216 
217 //M7SEL
mmio_w211a(uint8 value)218 void bPPU::mmio_w211a(uint8 value) {
219   regs.mode7_repeat = (value >> 6) & 3;
220   regs.mode7_vflip  = !!(value & 0x02);
221   regs.mode7_hflip  = !!(value & 0x01);
222 }
223 
224 //M7A
mmio_w211b(uint8 value)225 void bPPU::mmio_w211b(uint8 value) {
226   regs.m7a      = (value << 8) | regs.m7_latch;
227   regs.m7_latch = value;
228 }
229 
230 //M7B
mmio_w211c(uint8 value)231 void bPPU::mmio_w211c(uint8 value) {
232   regs.m7b      = (value << 8) | regs.m7_latch;
233   regs.m7_latch = value;
234 }
235 
236 //M7C
mmio_w211d(uint8 value)237 void bPPU::mmio_w211d(uint8 value) {
238   regs.m7c      = (value << 8) | regs.m7_latch;
239   regs.m7_latch = value;
240 }
241 
242 //M7D
mmio_w211e(uint8 value)243 void bPPU::mmio_w211e(uint8 value) {
244   regs.m7d      = (value << 8) | regs.m7_latch;
245   regs.m7_latch = value;
246 }
247 
248 //M7X
mmio_w211f(uint8 value)249 void bPPU::mmio_w211f(uint8 value) {
250   regs.m7x      = (value << 8) | regs.m7_latch;
251   regs.m7_latch = value;
252 }
253 
254 //M7Y
mmio_w2120(uint8 value)255 void bPPU::mmio_w2120(uint8 value) {
256   regs.m7y      = (value << 8) | regs.m7_latch;
257   regs.m7_latch = value;
258 }
259 
260 //CGADD
mmio_w2121(uint8 value)261 void bPPU::mmio_w2121(uint8 value) {
262   regs.cgram_addr = value << 1;
263 }
264 
265 //CGDATA
266 //note: CGRAM palette data format is 15-bits
267 //(0,bbbbb,ggggg,rrrrr). Highest bit is ignored,
268 //as evidenced by $213b CGRAM data reads.
269 //
270 //anomie indicates writes to CGDATA work the same
271 //as writes to OAMDATA's low table. need to verify
272 //this on hardware.
mmio_w2122(uint8 value)273 void bPPU::mmio_w2122(uint8 value) {
274   if(!(regs.cgram_addr & 1)) {
275     regs.cgram_latchdata = value;
276   } else {
277     cgram_mmio_write((regs.cgram_addr & 0x01fe),     regs.cgram_latchdata);
278     cgram_mmio_write((regs.cgram_addr & 0x01fe) + 1, value & 0x7f);
279   }
280   regs.cgram_addr++;
281   regs.cgram_addr &= 0x01ff;
282 }
283 
284 //W12SEL
mmio_w2123(uint8 value)285 void bPPU::mmio_w2123(uint8 value) {
286   regs.window2_enabled[BG2] = !!(value & 0x80);
287   regs.window2_invert [BG2] = !!(value & 0x40);
288   regs.window1_enabled[BG2] = !!(value & 0x20);
289   regs.window1_invert [BG2] = !!(value & 0x10);
290   regs.window2_enabled[BG1] = !!(value & 0x08);
291   regs.window2_invert [BG1] = !!(value & 0x04);
292   regs.window1_enabled[BG1] = !!(value & 0x02);
293   regs.window1_invert [BG1] = !!(value & 0x01);
294 }
295 
296 //W34SEL
mmio_w2124(uint8 value)297 void bPPU::mmio_w2124(uint8 value) {
298   regs.window2_enabled[BG4] = !!(value & 0x80);
299   regs.window2_invert [BG4] = !!(value & 0x40);
300   regs.window1_enabled[BG4] = !!(value & 0x20);
301   regs.window1_invert [BG4] = !!(value & 0x10);
302   regs.window2_enabled[BG3] = !!(value & 0x08);
303   regs.window2_invert [BG3] = !!(value & 0x04);
304   regs.window1_enabled[BG3] = !!(value & 0x02);
305   regs.window1_invert [BG3] = !!(value & 0x01);
306 }
307 
308 //WOBJSEL
mmio_w2125(uint8 value)309 void bPPU::mmio_w2125(uint8 value) {
310   regs.window2_enabled[COL] = !!(value & 0x80);
311   regs.window2_invert [COL] = !!(value & 0x40);
312   regs.window1_enabled[COL] = !!(value & 0x20);
313   regs.window1_invert [COL] = !!(value & 0x10);
314   regs.window2_enabled[OAM] = !!(value & 0x08);
315   regs.window2_invert [OAM] = !!(value & 0x04);
316   regs.window1_enabled[OAM] = !!(value & 0x02);
317   regs.window1_invert [OAM] = !!(value & 0x01);
318 }
319 
320 //WH0
mmio_w2126(uint8 value)321 void bPPU::mmio_w2126(uint8 value) {
322   regs.window1_left = value;
323 }
324 
325 //WH1
mmio_w2127(uint8 value)326 void bPPU::mmio_w2127(uint8 value) {
327   regs.window1_right = value;
328 }
329 
330 //WH2
mmio_w2128(uint8 value)331 void bPPU::mmio_w2128(uint8 value) {
332   regs.window2_left = value;
333 }
334 
335 //WH3
mmio_w2129(uint8 value)336 void bPPU::mmio_w2129(uint8 value) {
337   regs.window2_right = value;
338 }
339 
340 //WBGLOG
mmio_w212a(uint8 value)341 void bPPU::mmio_w212a(uint8 value) {
342   regs.window_mask[BG4] = (value >> 6) & 3;
343   regs.window_mask[BG3] = (value >> 4) & 3;
344   regs.window_mask[BG2] = (value >> 2) & 3;
345   regs.window_mask[BG1] = (value     ) & 3;
346 }
347 
348 //WOBJLOG
mmio_w212b(uint8 value)349 void bPPU::mmio_w212b(uint8 value) {
350   regs.window_mask[COL] = (value >> 2) & 3;
351   regs.window_mask[OAM] = (value     ) & 3;
352 }
353 
354 //TM
mmio_w212c(uint8 value)355 void bPPU::mmio_w212c(uint8 value) {
356   regs.bg_enabled[OAM] = !!(value & 0x10);
357   regs.bg_enabled[BG4] = !!(value & 0x08);
358   regs.bg_enabled[BG3] = !!(value & 0x04);
359   regs.bg_enabled[BG2] = !!(value & 0x02);
360   regs.bg_enabled[BG1] = !!(value & 0x01);
361 }
362 
363 //TS
mmio_w212d(uint8 value)364 void bPPU::mmio_w212d(uint8 value) {
365   regs.bgsub_enabled[OAM] = !!(value & 0x10);
366   regs.bgsub_enabled[BG4] = !!(value & 0x08);
367   regs.bgsub_enabled[BG3] = !!(value & 0x04);
368   regs.bgsub_enabled[BG2] = !!(value & 0x02);
369   regs.bgsub_enabled[BG1] = !!(value & 0x01);
370 }
371 
372 //TMW
mmio_w212e(uint8 value)373 void bPPU::mmio_w212e(uint8 value) {
374   regs.window_enabled[OAM] = !!(value & 0x10);
375   regs.window_enabled[BG4] = !!(value & 0x08);
376   regs.window_enabled[BG3] = !!(value & 0x04);
377   regs.window_enabled[BG2] = !!(value & 0x02);
378   regs.window_enabled[BG1] = !!(value & 0x01);
379 }
380 
381 //TSW
mmio_w212f(uint8 value)382 void bPPU::mmio_w212f(uint8 value) {
383   regs.sub_window_enabled[OAM] = !!(value & 0x10);
384   regs.sub_window_enabled[BG4] = !!(value & 0x08);
385   regs.sub_window_enabled[BG3] = !!(value & 0x04);
386   regs.sub_window_enabled[BG2] = !!(value & 0x02);
387   regs.sub_window_enabled[BG1] = !!(value & 0x01);
388 }
389 
390 //CGWSEL
mmio_w2130(uint8 value)391 void bPPU::mmio_w2130(uint8 value) {
392   regs.color_mask    = (value >> 6) & 3;
393   regs.colorsub_mask = (value >> 4) & 3;
394   regs.addsub_mode   = !!(value & 0x02);
395   regs.direct_color  = !!(value & 0x01);
396 }
397 
398 //CGADDSUB
mmio_w2131(uint8 value)399 void bPPU::mmio_w2131(uint8 value) {
400   regs.color_mode          = !!(value & 0x80);
401   regs.color_halve         = !!(value & 0x40);
402   regs.color_enabled[BACK] = !!(value & 0x20);
403   regs.color_enabled[OAM]  = !!(value & 0x10);
404   regs.color_enabled[BG4]  = !!(value & 0x08);
405   regs.color_enabled[BG3]  = !!(value & 0x04);
406   regs.color_enabled[BG2]  = !!(value & 0x02);
407   regs.color_enabled[BG1]  = !!(value & 0x01);
408 }
409 
410 //COLDATA
mmio_w2132(uint8 value)411 void bPPU::mmio_w2132(uint8 value) {
412   if(value & 0x80) regs.color_b = value & 0x1f;
413   if(value & 0x40) regs.color_g = value & 0x1f;
414   if(value & 0x20) regs.color_r = value & 0x1f;
415 
416   regs.color_rgb = (regs.color_r)
417                  | (regs.color_g << 5)
418                  | (regs.color_b << 10);
419 }
420 
421 //SETINI
mmio_w2133(uint8 value)422 void bPPU::mmio_w2133(uint8 value) {
423   regs.mode7_extbg   = !!(value & 0x40);
424   regs.pseudo_hires  = !!(value & 0x08);
425   regs.overscan      = !!(value & 0x04);
426   regs.oam_interlace = !!(value & 0x02);
427   regs.interlace     = !!(value & 0x01);
428 
429   display.overscan = regs.overscan;
430   sprite_list_valid = false;
431 }
432 
433 //MPYL
mmio_r2134()434 uint8 bPPU::mmio_r2134() {
435 uint32 r;
436   r = ((int16)regs.m7a * (int8)(regs.m7b >> 8));
437   regs.ppu1_mdr = r;
438   return regs.ppu1_mdr;
439 }
440 
441 //MPYM
mmio_r2135()442 uint8 bPPU::mmio_r2135() {
443 uint32 r;
444   r = ((int16)regs.m7a * (int8)(regs.m7b >> 8));
445   regs.ppu1_mdr = r >> 8;
446   return regs.ppu1_mdr;
447 }
448 
449 //MPYH
mmio_r2136()450 uint8 bPPU::mmio_r2136() {
451 uint32 r;
452   r = ((int16)regs.m7a * (int8)(regs.m7b >> 8));
453   regs.ppu1_mdr = r >> 16;
454   return regs.ppu1_mdr;
455 }
456 
457 //SLHV
mmio_r2137()458 uint8 bPPU::mmio_r2137() {
459   if(cpu.pio() & 0x80) {
460     latch_counters();
461   }
462   return cpu.regs.mdr;
463 }
464 
465 //OAMDATAREAD
mmio_r2138()466 uint8 bPPU::mmio_r2138() {
467   regs.ppu1_mdr = oam_mmio_read(regs.oam_addr);
468 
469   regs.oam_addr++;
470   regs.oam_addr &= 0x03ff;
471   regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127;
472 
473   return regs.ppu1_mdr;
474 }
475 
476 //VMDATALREAD
mmio_r2139()477 uint8 bPPU::mmio_r2139() {
478 uint16 addr = get_vram_address();
479   regs.ppu1_mdr = regs.vram_readbuffer;
480   if(regs.vram_incmode == 0) {
481     addr &= 0xfffe;
482     regs.vram_readbuffer  = vram_mmio_read(addr + 0);
483     regs.vram_readbuffer |= vram_mmio_read(addr + 1) << 8;
484     regs.vram_addr += regs.vram_incsize;
485   }
486   return regs.ppu1_mdr;
487 }
488 
489 //VMDATAHREAD
mmio_r213a()490 uint8 bPPU::mmio_r213a() {
491 uint16 addr = get_vram_address() + 1;
492   regs.ppu1_mdr = regs.vram_readbuffer >> 8;
493   if(regs.vram_incmode == 1) {
494     addr &= 0xfffe;
495     regs.vram_readbuffer  = vram_mmio_read(addr + 0);
496     regs.vram_readbuffer |= vram_mmio_read(addr + 1) << 8;
497     regs.vram_addr += regs.vram_incsize;
498   }
499   return regs.ppu1_mdr;
500 }
501 
502 //CGDATAREAD
503 //note: CGRAM palette data is 15-bits (0,bbbbb,ggggg,rrrrr)
504 //therefore, the high byte read from each color does not
505 //update bit 7 of the PPU2 MDR.
mmio_r213b()506 uint8 bPPU::mmio_r213b() {
507   if(!(regs.cgram_addr & 1)) {
508     regs.ppu2_mdr  = cgram_mmio_read(regs.cgram_addr) & 0xff;
509   } else {
510     regs.ppu2_mdr &= 0x80;
511     regs.ppu2_mdr |= cgram_mmio_read(regs.cgram_addr) & 0x7f;
512   }
513   regs.cgram_addr++;
514   regs.cgram_addr &= 0x01ff;
515   return regs.ppu2_mdr;
516 }
517 
518 //OPHCT
mmio_r213c()519 uint8 bPPU::mmio_r213c() {
520   if(!regs.latch_hcounter) {
521     regs.ppu2_mdr  = regs.hcounter & 0xff;
522   } else {
523     regs.ppu2_mdr &= 0xfe;
524     regs.ppu2_mdr |= (regs.hcounter >> 8) & 1;
525   }
526   regs.latch_hcounter ^= 1;
527   return regs.ppu2_mdr;
528 }
529 
530 //OPVCT
mmio_r213d()531 uint8 bPPU::mmio_r213d() {
532   if(!regs.latch_vcounter) {
533     regs.ppu2_mdr  = regs.vcounter & 0xff;
534   } else {
535     regs.ppu2_mdr &= 0xfe;
536     regs.ppu2_mdr |= (regs.vcounter >> 8) & 1;
537   }
538   regs.latch_vcounter ^= 1;
539   return regs.ppu2_mdr;
540 }
541 
542 //STAT77
mmio_r213e()543 uint8 bPPU::mmio_r213e() {
544 uint8 r = 0x00;
545   r |= (regs.time_over)  ? 0x80 : 0x00;
546   r |= (regs.range_over) ? 0x40 : 0x00;
547   r |= (regs.ppu1_mdr & 0x10);
548   r |= (ppu1_version & 0x0f);
549   regs.ppu1_mdr = r;
550   return regs.ppu1_mdr;
551 }
552 
553 //STAT78
mmio_r213f()554 uint8 bPPU::mmio_r213f() {
555 uint8 r = 0x00;
556   regs.latch_hcounter = 0;
557   regs.latch_vcounter = 0;
558 
559   r |= cpu.field() << 7;
560   if(!(cpu.pio() & 0x80)) {
561     r |= 0x40;
562   } else if(regs.counters_latched == true) {
563     r |= 0x40;
564     regs.counters_latched = false;
565   }
566   r |= (regs.ppu2_mdr & 0x20);
567   r |= (region << 4); //0 = NTSC, 1 = PAL
568   r |= (ppu2_version & 0x0f);
569   regs.ppu2_mdr = r;
570   return regs.ppu2_mdr;
571 }
572 
mmio_read(unsigned addr)573 uint8 bPPU::mmio_read(unsigned addr) {
574   scheduler.sync_cpuppu();
575 
576   switch(addr & 0xffff) {
577     case 0x2104:
578     case 0x2105:
579     case 0x2106:
580     case 0x2108:
581     case 0x2109:
582     case 0x210a:
583     case 0x2114:
584     case 0x2115:
585     case 0x2116:
586     case 0x2118:
587     case 0x2119:
588     case 0x211a:
589     case 0x2124:
590     case 0x2125:
591     case 0x2126:
592     case 0x2128:
593     case 0x2129:
594     case 0x212a: return regs.ppu1_mdr;
595     case 0x2134: return mmio_r2134();  //MPYL
596     case 0x2135: return mmio_r2135();  //MPYM
597     case 0x2136: return mmio_r2136();  //MPYH
598     case 0x2137: return mmio_r2137();  //SLHV
599     case 0x2138: return mmio_r2138();  //OAMDATAREAD
600     case 0x2139: return mmio_r2139();  //VMDATALREAD
601     case 0x213a: return mmio_r213a();  //VMDATAHREAD
602     case 0x213b: return mmio_r213b();  //CGDATAREAD
603     case 0x213c: return mmio_r213c();  //OPHCT
604     case 0x213d: return mmio_r213d();  //OPVCT
605     case 0x213e: return mmio_r213e();  //STAT77
606     case 0x213f: return mmio_r213f();  //STAT78
607   }
608 
609   return cpu.regs.mdr;
610 }
611 
mmio_write(unsigned addr,uint8 data)612 void bPPU::mmio_write(unsigned addr, uint8 data) {
613   scheduler.sync_cpuppu();
614 
615   switch(addr & 0xffff) {
616     case 0x2100: return mmio_w2100(data);  //INIDISP
617     case 0x2101: return mmio_w2101(data);  //OBSEL
618     case 0x2102: return mmio_w2102(data);  //OAMADDL
619     case 0x2103: return mmio_w2103(data);  //OAMADDH
620     case 0x2104: return mmio_w2104(data);  //OAMDATA
621     case 0x2105: return mmio_w2105(data);  //BGMODE
622     case 0x2106: return mmio_w2106(data);  //MOSAIC
623     case 0x2107: return mmio_w2107(data);  //BG1SC
624     case 0x2108: return mmio_w2108(data);  //BG2SC
625     case 0x2109: return mmio_w2109(data);  //BG3SC
626     case 0x210a: return mmio_w210a(data);  //BG4SC
627     case 0x210b: return mmio_w210b(data);  //BG12NBA
628     case 0x210c: return mmio_w210c(data);  //BG34NBA
629     case 0x210d: return mmio_w210d(data);  //BG1HOFS
630     case 0x210e: return mmio_w210e(data);  //BG1VOFS
631     case 0x210f: return mmio_w210f(data);  //BG2HOFS
632     case 0x2110: return mmio_w2110(data);  //BG2VOFS
633     case 0x2111: return mmio_w2111(data);  //BG3HOFS
634     case 0x2112: return mmio_w2112(data);  //BG3VOFS
635     case 0x2113: return mmio_w2113(data);  //BG4HOFS
636     case 0x2114: return mmio_w2114(data);  //BG4VOFS
637     case 0x2115: return mmio_w2115(data);  //VMAIN
638     case 0x2116: return mmio_w2116(data);  //VMADDL
639     case 0x2117: return mmio_w2117(data);  //VMADDH
640     case 0x2118: return mmio_w2118(data);  //VMDATAL
641     case 0x2119: return mmio_w2119(data);  //VMDATAH
642     case 0x211a: return mmio_w211a(data);  //M7SEL
643     case 0x211b: return mmio_w211b(data);  //M7A
644     case 0x211c: return mmio_w211c(data);  //M7B
645     case 0x211d: return mmio_w211d(data);  //M7C
646     case 0x211e: return mmio_w211e(data);  //M7D
647     case 0x211f: return mmio_w211f(data);  //M7X
648     case 0x2120: return mmio_w2120(data);  //M7Y
649     case 0x2121: return mmio_w2121(data);  //CGADD
650     case 0x2122: return mmio_w2122(data);  //CGDATA
651     case 0x2123: return mmio_w2123(data);  //W12SEL
652     case 0x2124: return mmio_w2124(data);  //W34SEL
653     case 0x2125: return mmio_w2125(data);  //WOBJSEL
654     case 0x2126: return mmio_w2126(data);  //WH0
655     case 0x2127: return mmio_w2127(data);  //WH1
656     case 0x2128: return mmio_w2128(data);  //WH2
657     case 0x2129: return mmio_w2129(data);  //WH3
658     case 0x212a: return mmio_w212a(data);  //WBGLOG
659     case 0x212b: return mmio_w212b(data);  //WOBJLOG
660     case 0x212c: return mmio_w212c(data);  //TM
661     case 0x212d: return mmio_w212d(data);  //TS
662     case 0x212e: return mmio_w212e(data);  //TMW
663     case 0x212f: return mmio_w212f(data);  //TSW
664     case 0x2130: return mmio_w2130(data);  //CGWSEL
665     case 0x2131: return mmio_w2131(data);  //CGADDSUB
666     case 0x2132: return mmio_w2132(data);  //COLDATA
667     case 0x2133: return mmio_w2133(data);  //SETINI
668   }
669 }
670 
671 #endif
672