1 // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
2 // Copyright (C) 1999-2003 Forgotten
3 // Copyright (C) 2004 Forgotten and the VBA development team
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 as published by
7 // the Free Software Foundation; either version 2, or(at your option)
8 // any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 #include <mednafen/mednafen.h>
20 #include <mednafen/file.h>
21 #include <mednafen/general.h>
22 #include <mednafen/state.h>
23 #include <mednafen/mempatcher.h>
24 #include <mednafen/hash/md5.h>
25 #include <mednafen/FileStream.h>
26 #include <mednafen/Time.h>
27 #include <mednafen/cheat_formats/gb.h>
28
29 #include <zlib.h>
30
31 #include "gbGlobals.h"
32 #include "gb.h"
33 #include "memory.h"
34 #include "sound.h"
35 #include "z80.h"
36
37 namespace MDFN_IEN_GB
38 {
39
40 static void Cleanup(void) MDFN_COLD;
41
42 static uint32 *gbColorFilter = NULL;
43 static uint32 gbMonoColorMap[12 + 1]; // Mono color map(+1 = LCD off color)!
44
45 static void LoadROM(Stream* s);
46 static int32 SoundTS = 0;
47 //extern uint16 gbLineMix[160];
48 extern union __gblmt
49 {
50 uint16 cgb[160];
51 uint8 dmg[160];
52 uint32 dmg_32[40];
53 } gbLineMix;
54
55 // mappers
56 void (*mapper)(uint16,uint8) = NULL;
57 void (*mapperRAM)(uint16,uint8) = NULL;
58 uint8 (*mapperReadRAM)(uint16) = NULL;
59
60 static uint8 HRAM[0x80];
61 uint8 gbOAM[0xA0];
62
63 // 0xff00
64 static uint8 register_P1 = 0;
65
66 // 0xff01
67 static uint8 register_SB = 0;
68 // 0xff02
69 uint8 register_SC = 0;
70 // 0xff04
71 uint8 register_DIV = 0;
72 // 0xff05
73 static uint8 register_TIMA = 0;
74 // 0xff06
75 static uint8 register_TMA = 0;
76 // 0xff07
77 static uint8 register_TAC = 0;
78 // 0xff0f
79 uint8 register_IF = 0;
80 // 0xff40
81 uint8 register_LCDC = 0;
82 // 0xff41
83 static uint8 register_STAT = 0;
84 // 0xff42
85 uint8 register_SCY = 0;
86 // 0xff43
87 uint8 register_SCX = 0;
88 // 0xff44
89 uint8 register_LY = 0;
90 // 0xff45
91 uint8 register_LYC = 0;
92 // 0xff46
93 uint8 register_DMA = 0;
94 // 0xff4a
95 uint8 register_WY = 0;
96 // 0xff4b
97 uint8 register_WX = 0;
98 // 0xff4d
99 uint8 register_KEY1 = 0;
100 // 0xff4f
101 uint8 register_VBK = 0;
102 // 0xff51
103 static uint8 register_HDMA1 = 0;
104 // 0xff52
105 static uint8 register_HDMA2 = 0;
106 // 0xff53
107 static uint8 register_HDMA3 = 0;
108 // 0xff54
109 static uint8 register_HDMA4 = 0;
110 // 0xff55
111 static uint8 register_HDMA5 = 0;
112
113 // 0xff56
114 static uint8 register_RP = 0;
115
116 // 0xff68
117 static uint8 register_BCPS = 0;
118 // 0xff69
119 static uint8 register_BCPD = 0;
120 // 0xff6a
121 static uint8 register_OCPS = 0;
122 // 0xff6b
123 static uint8 register_OCPD = 0;
124
125 // 0xff6c
126 static uint8 register_FF6C = 0;
127 // 0xff72
128 static uint8 register_FF72 = 0;
129 // 0xff73
130 static uint8 register_FF73 = 0;
131 // 0xff74
132 static uint8 register_FF74 = 0;
133 // 0xff75
134 static uint8 register_FF75 = 0;
135
136 // 0xff70
137 static uint8 register_SVBK = 0;
138 // 0xffff
139 uint8 register_IE = 0;
140
141 // ticks definition
142 static int GBDIV_CLOCK_TICKS = 64;
143 static int GBLCD_MODE_0_CLOCK_TICKS = 51;
144 static int GBLCD_MODE_1_CLOCK_TICKS = 1140;
145 static int GBLCD_MODE_2_CLOCK_TICKS = 20;
146 static int GBLCD_MODE_3_CLOCK_TICKS = 43;
147 static int GBLY_INCREMENT_CLOCK_TICKS = 114;
148 static int GBTIMER_MODE_0_CLOCK_TICKS = 256;
149 static int GBTIMER_MODE_1_CLOCK_TICKS = 4;
150 static int GBTIMER_MODE_2_CLOCK_TICKS = 16;
151 static int GBTIMER_MODE_3_CLOCK_TICKS = 64;
152 static int GBSERIAL_CLOCK_TICKS = 128;
153 static int GBSYNCHRONIZE_CLOCK_TICKS = 52920;
154
155 // state variables
156 static int32 snooze;
157 static int32 PadInterruptDelay;
158
159 // serial
160 static int gbSerialOn;
161 static int gbSerialTicks;
162 static int gbSerialBits;
163 // timer
164 static int gbTimerOn;
165 static int gbTimerTicks;
166 static int gbTimerClockTicks;
167 static int gbTimerMode;
168
169
170 enum
171 {
172 GBLCDM_HBLANK = 0,
173 GBLCDM_VBLANK = 1,
174 GBLCDM_OAM = 2,
175 GBLCDM_OAM_VRAM = 3,
176 };
177
178 // lcd
179 int gbLcdMode = GBLCDM_OAM;
180 int gbLcdTicks = GBLCD_MODE_2_CLOCK_TICKS;
181 int gbLcdLYIncrementTicks = 0;
182 // div
183 int gbDivTicks = GBDIV_CLOCK_TICKS;
184 // cgb
185 int gbWramBank = 1;
186 int gbHdmaSource = 0x0000;
187 int gbHdmaDestination = 0x8000;
188 int gbHdmaBytes = 0x0000;
189 int gbHdmaOn = 0;
190 int gbSpeed = 0;
191
192 // timing
193 int gbSynchronizeTicks = GBSYNCHRONIZE_CLOCK_TICKS;
194
195 // emulator features
196 int gbBattery = 0;
197
198 static uint8 gbJoymask;
199
200 static const int gbRomSizes[] = { 0x00008000, // 32K
201 0x00010000, // 64K
202 0x00020000, // 128K
203 0x00040000, // 256K
204 0x00080000, // 512K
205 0x00100000, // 1024K
206 0x00200000, // 2048K
207 0x00400000, // 4096K
208 0x00800000 // 8192K
209 };
210
211 static const int gbRomSizesMasks[] = { 0x00007fff,
212 0x0000ffff,
213 0x0001ffff,
214 0x0003ffff,
215 0x0007ffff,
216 0x000fffff,
217 0x001fffff,
218 0x003fffff,
219 0x007fffff
220 };
221
222 static const int gbRamSizes[6] = { 0x00000000, // 0K
223 0x00000800, // 2K
224 0x00002000, // 8K
225 0x00008000, // 32K
226 0x00020000, // 128K
227 0x00010000 // 64K
228 };
229
230 static const int gbRamSizesMasks[6] = { 0x00000000,
231 0x000007ff,
232 0x00001fff,
233 0x00007fff,
234 0x0001ffff,
235 0x0000ffff
236 };
237
238 static MDFN_PaletteEntry PalTest[256];
239
MatchExists(MDFN_PaletteEntry * pt,unsigned n,const MDFN_PaletteEntry & pe)240 static bool MatchExists(MDFN_PaletteEntry *pt, unsigned n, const MDFN_PaletteEntry& pe)
241 {
242 for(unsigned x = 0; x < n; x++)
243 {
244 if(pt[x].r == pe.r && pt[x].g == pe.g && pt[x].b == pe.b)
245 return(true);
246 }
247 return(false);
248 }
249
250 class MDFN_PaletteMapper8
251 {
252 public:
253
254 MDFN_PaletteMapper8(MDFN_PaletteEntry *pal);
255
256 uint8 FindClose(const MDFN_PaletteEntry& pe);
257
258 private:
259
260 int rcl[256];
261 int gcl[256];
262 int bcl[256];
263 int ccp_to_ccl[256];
264 };
265
MDFN_PaletteMapper8(MDFN_PaletteEntry * pal)266 MDFN_PaletteMapper8::MDFN_PaletteMapper8(MDFN_PaletteEntry *pal)
267 {
268 for(unsigned i = 0; i < 256; i++)
269 {
270 ccp_to_ccl[i] = 65536U * pow((double)i / 255, 2.2 / 1.0);
271 }
272
273 for(unsigned i = 0; i < 256; i++)
274 {
275 rcl[i] = ccp_to_ccl[pal[i].r];
276 gcl[i] = ccp_to_ccl[pal[i].g];
277 bcl[i] = ccp_to_ccl[pal[i].b];
278 }
279 }
280
FindClose(const MDFN_PaletteEntry & pe)281 uint8 MDFN_PaletteMapper8::FindClose(const MDFN_PaletteEntry& pe)
282 {
283 int rl, gl, bl;
284 int closest = -1;
285 int closest_cs = 0x7FFFFFFF;
286
287 rl = ccp_to_ccl[pe.r];
288 gl = ccp_to_ccl[pe.g];
289 bl = ccp_to_ccl[pe.b];
290
291 for(unsigned x = 0; x < 256; x++)
292 {
293 int cs;
294
295 cs = abs(rcl[x] - rl) * 2126 + abs(gcl[x] - gl) * 7152 + abs(bcl[x] - bl) * 722;
296 if(cs < closest_cs)
297 {
298 closest_cs = cs;
299 closest = x;
300 }
301 }
302
303 return(closest);
304 }
305
306
307 static void SetPixelFormat(const MDFN_PixelFormat &format, bool cgb_mode, const uint8* CustomColorMap, const uint32 CustomColorMapNE) MDFN_COLD;
SetPixelFormat(const MDFN_PixelFormat & format,bool cgb_mode,const uint8 * CustomColorMap,const uint32 CustomColorMapNE)308 static void SetPixelFormat(const MDFN_PixelFormat &format, bool cgb_mode, const uint8* CustomColorMap, const uint32 CustomColorMapNE)
309 {
310 if(cgb_mode)
311 {
312 if(format.bpp == 8)
313 {
314 unsigned pti = 0;
315
316 memset(PalTest, 0, sizeof(PalTest));
317
318 for(int i = 0; i < 8; i++)
319 {
320 PalTest[pti++] = format.MakePColor(i * 36, i * 36, i * 36);
321
322 if(i)
323 {
324 PalTest[pti++] = format.MakePColor(i * 36, 0, 0);
325 PalTest[pti++] = format.MakePColor(0, i * 36, 0);
326 PalTest[pti++] = format.MakePColor(0, 0, i * 36);
327 PalTest[pti++] = format.MakePColor(i * 36, i * 36, 0);
328 PalTest[pti++] = format.MakePColor(i * 36, 0, i * 36);
329 PalTest[pti++] = format.MakePColor(0, i * 36, i * 36);
330 }
331 }
332
333 for(int r = 0; r < 8; r++)
334 {
335 for(int g = 0; g < 8; g++)
336 {
337 for(int b = 0; b < 8; b++)
338 {
339 if(MatchExists(PalTest, 256, format.MakePColor(r * 36, g * 36, b * 36)))
340 continue;
341
342 if(g == 6 && b == 6 && r == 5)
343 goto SkipStuff;
344
345 if(g == 6 && b == 3 && r == 5)
346 goto SkipStuff;
347
348 if(g == 4 && b == 5 && r == 3)
349 goto SkipStuff;
350
351 if(!(b & 1))
352 continue;
353
354 if(g == (r + 1))
355 continue;
356
357 //if(g == 7 && r >= 4 && b < 4)
358 // continue;
359
360 if(g == (r + 3) && b >= 5)
361 continue;
362
363 SkipStuff:;
364
365 PalTest[pti++] = format.MakePColor(r * 36, g * 36, b * 36);
366
367 if(pti == 256) goto EndThingy;
368 }
369 }
370 }
371 EndThingy:;
372 //printf("ZOOMBA: %u\n", pti);
373 //exit(1);
374 }
375
376 MDFN_PaletteMapper8 pm8(PalTest);
377
378 for(int r = 0; r < 32; r++)
379 {
380 for(int g = 0; g < 32; g++)
381 {
382 for(int b = 0; b < 32; b++)
383 {
384 int nr = r * 226 + g * 29 + b * 0;
385 int ng = r * 29 + g * 197 + b * 29;
386 int nb = r * 30 + g * 73 + b * 152;
387
388 nr /= 31;
389 ng /= 31;
390 nb /= 31;
391
392 if(CustomColorMap)
393 {
394 nr = CustomColorMap[((b << 10) | (g << 5) | r) * 3 + 0];
395 ng = CustomColorMap[((b << 10) | (g << 5) | r) * 3 + 1];
396 nb = CustomColorMap[((b << 10) | (g << 5) | r) * 3 + 2];
397 }
398
399 if(format.bpp == 8)
400 gbColorFilter[(b << 10) | (g << 5) | r] = pm8.FindClose(format.MakePColor(nr, ng, nb));
401 else
402 gbColorFilter[(b << 10) | (g << 5) | r] = format.MakeColor(nr, ng, nb);
403 }
404 }
405 }
406 }
407 else
408 {
409 for(int i = 0; i < 12; i++)
410 {
411 int r, g, b;
412
413 r = (3 - (i & 3)) * 48 + 32;
414 g = (3 - (i & 3)) * 48 + 32;
415 b = (3 - (i & 3)) * 48 + 32;
416
417 if(CustomColorMap)
418 {
419 unsigned ci = i;
420
421 if(CustomColorMapNE == 4)
422 ci %= 4;
423 else if(CustomColorMapNE == 8)
424 ci = (ci & 0x7) | ((ci & 0x8) >> 1);
425
426 r = CustomColorMap[ci * 3 + 0];
427 g = CustomColorMap[ci * 3 + 1];
428 b = CustomColorMap[ci * 3 + 2];
429 }
430
431 gbMonoColorMap[i] = format.MakeColor(r, g, b);
432 PalTest[i] = format.MakePColor(r, g, b);
433 }
434
435 gbMonoColorMap[12] = gbMonoColorMap[0];
436 PalTest[12] = PalTest[0];
437 }
438 }
439
440 #if 0
441 if(num_read == 4 * 3)
442 {
443 for(unsigned i = 4 * 3; i < 12 * 3; i++)
444 {
445 (*ptr)[i] = (*ptr)[i % (4 * 3)];
446 }
447 }
448 else if(num_read == 8 * 3)
449 {
450 for(unsigned i = 8 * 3; i < 12 * 3; i++)
451 (*ptr)[i] = (*ptr)[(4 * 3) + (i % (4 * 3))];
452 }
453 #endif
454
gbCopyMemory(uint16 d,uint16 s,int count)455 static void gbCopyMemory(uint16 d, uint16 s, int count)
456 {
457 while(count)
458 {
459 gbWriteMemory(d, gbReadMemory(s));
460 s++;
461 d++;
462 count--;
463 }
464 }
465
gbDoHdma()466 static void gbDoHdma()
467 {
468 gbCopyMemory(gbHdmaDestination,
469 gbHdmaSource,
470 0x10);
471
472 gbHdmaDestination += 0x10;
473 gbHdmaSource += 0x10;
474
475 register_HDMA2 += 0x10;
476 if(register_HDMA2 == 0x00)
477 register_HDMA1++;
478
479 register_HDMA4 += 0x10;
480 if(register_HDMA4 == 0x00)
481 register_HDMA3++;
482
483 gbHdmaBytes -= 0x10;
484 register_HDMA5--;
485 if(register_HDMA5 == 0xff)
486 gbHdmaOn = 0;
487 }
488
489 // fix for Harley and Lego Racers
gbCompareLYToLYC()490 static void gbCompareLYToLYC()
491 {
492 if(register_LY == register_LYC)
493 {
494 // mark that we have a match
495 register_STAT |= 4;
496
497 // check if we need an interrupt
498 if(register_STAT & 0x40)
499 register_IF |= 2;
500 }
501 else // no match
502 register_STAT &= 0xfb;
503 }
504
ClockTIMA(void)505 static void ClockTIMA(void)
506 {
507 register_TIMA++;
508
509 if(register_TIMA == 0)
510 {
511 // timer overflow!
512
513 // reload timer modulo
514 register_TIMA = register_TMA;
515
516 // flag interrupt
517 register_IF |= 4;
518 }
519 }
520
gbWriteMemory(uint16 address,uint8 value)521 void gbWriteMemory(uint16 address, uint8 value)
522 {
523 if(address < 0x8000) {
524 if(mapper)
525 (*mapper)(address, value);
526 return;
527 }
528
529 if(address < 0xa000) {
530 gbMemoryMap[address>>12][address&0x0fff] = value;
531 return;
532 }
533
534 if(address < 0xc000)
535 {
536 if(mapper)
537 (*mapperRAM)(address, value);
538 return;
539 }
540
541 if(address < 0xfe00) {
542 unsigned int page = (address >> 12);
543 if(page >= 0xE) page -= 2;
544 gbMemoryMap[page][address & 0x0fff] = value;
545 return;
546 }
547
548 if(address < 0xff00) {
549 if(address < 0xFEA0)
550 gbOAM[address & 0xFF] = value;
551 return;
552 }
553 //printf("Write: %04x %02x, %d\n", address, value, register_LY);
554 switch(address & 0x00ff)
555 {
556 case 0x00:
557 register_P1 = ((register_P1 & 0xcf) | (value & 0x30));
558 return;
559
560 case 0x01: {
561 register_SB = value;
562 return;
563 }
564
565 // serial control
566 case 0x02: {
567 gbSerialOn = (value & 0x80);
568 register_SC = value;
569 if(gbSerialOn) {
570 gbSerialTicks = GBSERIAL_CLOCK_TICKS;
571 #ifdef LINK_EMULATION
572 if(linkConnected) {
573 if(value & 1) {
574 linkSendByte(0x100|register_SB);
575 Sleep(5);
576 }
577 }
578 #endif
579 }
580
581 gbSerialBits = 0;
582 return;
583 }
584
585 // DIV register resets on any write
586 case 0x04: {
587 register_DIV = 0;
588 gbDivTicks = GBDIV_CLOCK_TICKS;
589 // Another weird timer 'bug' :
590 // Writing to DIV register resets the internal timer,
591 // and can also increase TIMA/trigger an interrupt
592 // in some cases...
593 //if (gbTimerOn && !(gbInternalTimer & (gbTimerClockTicks>>1)))
594 //{
595 // ClockTIMA();
596 //}
597 return;
598 }
599 case 0x05:
600 register_TIMA = value;
601 return;
602
603 case 0x06:
604 register_TMA = value;
605 return;
606
607 // TIMER control
608 case 0x07: {
609 register_TAC = value;
610 gbTimerOn = (value & 4);
611 gbTimerMode = value & 3;
612 // register_TIMA = register_TMA;
613 switch(gbTimerMode) {
614 case 0:
615 gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_0_CLOCK_TICKS;
616 break;
617 case 1:
618 gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_1_CLOCK_TICKS;
619 break;
620 case 2:
621 gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_2_CLOCK_TICKS;
622 break;
623 case 3:
624 gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_3_CLOCK_TICKS;
625 break;
626 }
627 return;
628 }
629
630 case 0x0f:
631 {
632 register_IF = value;
633 return;
634 }
635
636
637 case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
638 case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
639 case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
640 case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
641 case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
642 case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
643 {
644 SOUND_Write(SoundTS, address, value);
645 return;
646 }
647 case 0x40: {
648 int lcdChange = (register_LCDC & 0x80) ^ (value & 0x80);
649
650 if(lcdChange) {
651 if(value & 0x80) {
652 gbLcdTicks = GBLCD_MODE_1_CLOCK_TICKS;
653 gbLcdMode = GBLCDM_HBLANK;
654 register_STAT &= 0xfc;
655 register_LY = 0x00;
656 } else {
657 gbLcdTicks = 0;
658 gbLcdMode = GBLCDM_HBLANK;
659 register_STAT &= 0xfc;
660 register_LY = 0x00;
661 }
662 // compareLYToLYC();
663 }
664 // don't draw the window if it was not enabled and not being drawn before
665 if(!(register_LCDC & 0x20) && (value & 0x20) && gbWindowLine == -1 &&
666 register_LY > register_WY)
667 gbWindowLine = 144;
668
669 register_LCDC = value;
670
671 return;
672 }
673
674 // STAT
675 case 0x41: {
676 //register_STAT = (register_STAT & 0x87) |
677 // (value & 0x7c);
678 register_STAT = (value & 0xf8) | (register_STAT & 0x07); // fix ?
679 // GB bug from Devrs FAQ
680 if(!gbCgbMode && (register_LCDC & 0x80) && gbLcdMode < 2)
681 register_IF |= 2;
682 return;
683 }
684
685 // SCY
686 case 0x42: {
687 register_SCY = value;
688 return;
689 }
690
691 // SCX
692 case 0x43: {
693 register_SCX = value;
694 return;
695 }
696
697 // LY
698 case 0x44: {
699 // read only
700 return;
701 }
702
703 // LYC
704 case 0x45: {
705 register_LYC = value;
706 if((register_LCDC & 0x80)) {
707 gbCompareLYToLYC();
708 }
709 return;
710 }
711
712 // DMA!
713 case 0x46: {
714 int source = value * 0x0100;
715
716 gbCopyMemory(0xfe00,
717 source,
718 0xa0);
719 register_DMA = value;
720 return;
721 }
722
723 // BGP
724 case 0x47: {
725 gbBgp[0] = value & 0x03;
726 gbBgp[1] = (value & 0x0c)>>2;
727 gbBgp[2] = (value & 0x30)>>4;
728 gbBgp[3] = (value & 0xc0)>>6;
729 return;
730 }
731
732 // OBP0
733 case 0x48: {
734 gbObp0[0] = 4 | (value & 0x03);
735 gbObp0[1] = 4 | ((value & 0x0c)>>2);
736 gbObp0[2] = 4 | ((value & 0x30)>>4);
737 gbObp0[3] = 4 | ((value & 0xc0)>>6);
738 return;
739 }
740
741 // OBP1
742 case 0x49: {
743 gbObp1[0] = 8 | (value & 0x03);
744 gbObp1[1] = 8 | ((value & 0x0c)>>2);
745 gbObp1[2] = 8 | ((value & 0x30)>>4);
746 gbObp1[3] = 8 | ((value & 0xc0)>>6);
747 return;
748 }
749
750 case 0x4a:
751 register_WY = value;
752 return;
753
754 case 0x4b:
755 register_WX = value;
756 return;
757
758 // KEY1
759 case 0x4d: {
760 if(gbCgbMode) {
761 register_KEY1 = (register_KEY1 & 0x80) | (value & 1);
762 return;
763 }
764 }
765 break;
766
767 // VBK
768 case 0x4f: {
769 if(gbCgbMode) {
770 value = value & 1;
771
772 unsigned vramAddress = value * 0x2000;
773 gbMemoryMap[0x08] = &gbVram[vramAddress];
774 gbMemoryMap[0x09] = &gbVram[vramAddress + 0x1000];
775
776 register_VBK = value;
777 }
778 return;
779 }
780 break;
781
782 // HDMA1
783 case 0x51: {
784 if(gbCgbMode) {
785 if(value > 0x7f && value < 0xa0)
786 value = 0;
787
788 gbHdmaSource = (value << 8) | (register_HDMA2 & 0xf0);
789
790 register_HDMA1 = value;
791 return;
792 }
793 }
794 break;
795
796 // HDMA2
797 case 0x52: {
798 if(gbCgbMode) {
799 value = value & 0xf0;
800
801 gbHdmaSource = (register_HDMA1 << 8) | (value);
802
803 register_HDMA2 = value;
804 return;
805 }
806 }
807 break;
808
809 // HDMA3
810 case 0x53: {
811 if(gbCgbMode) {
812 value = value & 0x1f;
813 gbHdmaDestination = (value << 8) | (register_HDMA4 & 0xf0);
814 gbHdmaDestination += 0x8000;
815 register_HDMA3 = value;
816 return;
817 }
818 }
819 break;
820
821 // HDMA4
822 case 0x54: {
823 if(gbCgbMode) {
824 value = value & 0xf0;
825 gbHdmaDestination = ((register_HDMA3 & 0x1f) << 8) | value;
826 gbHdmaDestination += 0x8000;
827 register_HDMA4 = value;
828 return;
829 }
830 }
831 break;
832
833 // HDMA5
834 case 0x55: {
835 if(gbCgbMode) {
836 gbHdmaBytes = 16 + (value & 0x7f) * 16;
837 if(gbHdmaOn) {
838 if(value & 0x80) {
839 register_HDMA5 = (value & 0x7f);
840 } else {
841 register_HDMA5 = 0xff;
842 gbHdmaOn = 0;
843 }
844 } else {
845 if(value & 0x80) {
846 gbHdmaOn = 1;
847 register_HDMA5 = value & 0x7f;
848 if(gbLcdMode == GBLCDM_HBLANK)
849 gbDoHdma();
850 } else {
851 // we need to take the time it takes to complete the transfer into
852 // account... according to GB DEV FAQs, the setup time is the same
853 // for single and double speed, but the actual transfer takes the
854 // same time
855 //if(gbSpeed)
856 // gbDmaTicks = 231 + 16 * (value & 0x7f);
857 //else
858 // gbDmaTicks = 231 + 8 * (value & 0x7f);
859 gbDmaTicks = 231;
860 gbCopyMemory(gbHdmaDestination,
861 gbHdmaSource,
862 gbHdmaBytes);
863 gbHdmaDestination += gbHdmaBytes;
864 gbHdmaSource += gbHdmaBytes;
865
866 register_HDMA3 = ((gbHdmaDestination - 0x8000) >> 8) & 0x1f;
867 register_HDMA4 = gbHdmaDestination & 0xf0;
868 register_HDMA1 = (gbHdmaSource >> 8) & 0xff;
869 register_HDMA2 = gbHdmaSource & 0xf0;
870 }
871 }
872 return;
873 }
874 }
875 break;
876
877
878 case 0x56:
879 register_RP = value & 0xC1;
880 break;
881
882 // BCPS
883 case 0x68: {
884 if(gbCgbMode) {
885 int paletteIndex = (value & 0x3f) >> 1;
886 int paletteHiLo = (value & 0x01);
887
888 register_BCPS = value;
889 register_BCPD = (paletteHiLo ?
890 (gbPalette[paletteIndex] >> 8) :
891 (gbPalette[paletteIndex] & 0x00ff));
892 return;
893 }
894 }
895 break;
896
897 // BCPD
898 case 0x69: {
899 if(gbCgbMode) {
900 int v = register_BCPS;
901 int paletteIndex = (v & 0x3f) >> 1;
902 int paletteHiLo = (v & 0x01);
903 register_BCPD = value;
904 gbPalette[paletteIndex] = (paletteHiLo ?
905 ((value << 8) | (gbPalette[paletteIndex] & 0xff)) :
906 ((gbPalette[paletteIndex] & 0xff00) | (value))) & 0x7fff;
907
908 if(register_BCPS & 0x80) {
909 int index = ((register_BCPS & 0x3f) + 1) & 0x3f;
910
911 register_BCPS = (register_BCPS & 0x80) | index;
912
913 register_BCPD = (index & 1 ?
914 (gbPalette[index>>1] >> 8) :
915 (gbPalette[index>>1] & 0x00ff));
916
917 }
918 return;
919 }
920 }
921 break;
922
923 // OCPS
924 case 0x6a: {
925 if(gbCgbMode) {
926 int paletteIndex = (value & 0x3f) >> 1;
927 int paletteHiLo = (value & 0x01);
928
929 paletteIndex += 32;
930
931 register_OCPS = value;
932 register_OCPD = (paletteHiLo ?
933 (gbPalette[paletteIndex] >> 8) :
934 (gbPalette[paletteIndex] & 0x00ff));
935 return;
936 }
937 }
938 break;
939
940 // OCPD
941 case 0x6b: {
942 if(gbCgbMode) {
943 int v = register_OCPS;
944 int paletteIndex = (v & 0x3f) >> 1;
945 int paletteHiLo = (v & 0x01);
946
947 paletteIndex += 32;
948
949 register_OCPD = value;
950 gbPalette[paletteIndex] = (paletteHiLo ?
951 ((value << 8) | (gbPalette[paletteIndex] & 0xff)) :
952 ((gbPalette[paletteIndex] & 0xff00) | (value))) & 0x7fff;
953 if(register_OCPS & 0x80) {
954 int index = ((register_OCPS & 0x3f) + 1) & 0x3f;
955
956 register_OCPS = (register_OCPS & 0x80) | index;
957
958 register_OCPD = (index & 1 ?
959 (gbPalette[(index>>1) + 32] >> 8) :
960 (gbPalette[(index>>1) + 32] & 0x00ff));
961
962 }
963 return;
964 }
965 }
966 break;
967
968 case 0x6c:
969 register_FF6C = value & 1;
970 break;
971
972 // SVBK
973 case 0x70: {
974 if(gbCgbMode) {
975 value = value & 7;
976
977 int bank = value;
978 if(value == 0)
979 bank = 1;
980
981 if(bank == gbWramBank)
982 return;
983
984 int wramAddress = bank * 0x1000;
985 gbMemoryMap[0x0d] = &gbWram[wramAddress];
986
987 MDFNMP_AddRAM(0x1000, 0xD000, &gbWram[wramAddress]);
988
989 gbWramBank = bank;
990 register_SVBK = value;
991 return;
992 }
993 }
994 break;
995
996 case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
997 case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f:
998 case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:
999 case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f:
1000 case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7:
1001 case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
1002 case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
1003 case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf:
1004 case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7:
1005 case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf:
1006 case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7:
1007 case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf:
1008 case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7:
1009 case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef:
1010 case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
1011 case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe:
1012 HRAM[address & 0x7F] = value;
1013 return;
1014
1015 case 0xff:
1016 register_IE = value;
1017 return;
1018 }
1019
1020 //printf("%04x\n", address);
1021 //gbMemory[address - 0x8000] = value;
1022 }
1023
gbReadMemory(uint16 address)1024 uint8 gbReadMemory(uint16 address)
1025 {
1026 uint8 retval = 0xFF;
1027
1028 if(address < 0xa000)
1029 retval = gbMemoryMap[address>>12][address&0x0fff];
1030 else if(address < 0xc000)
1031 {
1032 if(mapperReadRAM)
1033 retval = mapperReadRAM(address);
1034 else if(mapper && gbMemoryMap[address >> 12])
1035 {
1036 //printf("%04x %d\n", address, gbRamSizeMask);
1037 retval = gbMemoryMap[address >> 12][address & 0x0fff & gbRamSizeMask];
1038 }
1039 }
1040 else if(address < 0xfe00)
1041 {
1042 unsigned int page = (address >> 12);
1043 if(page >= 0xE) page -= 2;
1044 retval = gbMemoryMap[page][address & 0x0fff];
1045 }
1046 else if(address < 0xfea0)
1047 retval = gbOAM[address & 0xFF];
1048 else if(address >= 0xff00)
1049 {
1050 switch(address & 0x00ff)
1051 {
1052 case 0x00:
1053 {
1054 int b = register_P1;
1055
1056 if((b & 0x30) == 0x20) {
1057 b &= 0xf0;
1058
1059 b |= ((gbJoymask >> 4) & 0xF) ^ 0xF;
1060
1061 register_P1 = b;
1062 } else if((b & 0x30) == 0x10) {
1063 b &= 0xf0;
1064
1065 b |= ((gbJoymask >> 0) & 0xF) ^ 0xF;
1066
1067 register_P1 = b;
1068 } else {
1069 register_P1 = 0xff;
1070 }
1071 }
1072 retval = register_P1;
1073 break;
1074 case 0x01:
1075 retval = register_SB;
1076 break;
1077 case 0x02:
1078 retval = register_SC;
1079 break;
1080 case 0x04:
1081 retval = register_DIV;
1082 break;
1083 case 0x05:
1084 retval = register_TIMA;
1085 break;
1086 case 0x06:
1087 retval = register_TMA;
1088 break;
1089 case 0x07:
1090 retval = 0xf8 | register_TAC;
1091 break;
1092 case 0x0f:
1093 retval = 0xe0 | register_IF;
1094 break;
1095 case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
1096 case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
1097 case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
1098 case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
1099 case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
1100 case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
1101 retval = SOUND_Read(SoundTS, address);
1102 break;
1103 case 0x40:
1104 retval = register_LCDC;
1105 break;
1106 case 0x41:
1107 retval = 0x80 | register_STAT;
1108 break;
1109 case 0x42:
1110 retval = register_SCY;
1111 break;
1112 case 0x43:
1113 retval = register_SCX;
1114 break;
1115 case 0x44:
1116 retval = register_LY;
1117 break;
1118 case 0x45:
1119 retval = register_LYC;
1120 break;
1121 case 0x46:
1122 retval = register_DMA;
1123 break;
1124 case 0x47:
1125 retval = gbBgp[0] | (gbBgp[1] << 2) | (gbBgp[2] << 4) | (gbBgp[3] << 6);
1126 break;
1127 case 0x48:
1128 retval = (gbObp0[0] & 3) | ((gbObp0[1] & 3) << 2) | ((gbObp0[2] & 3) << 4) | ((gbObp0[3] & 3) << 6);
1129 break;
1130 case 0x49:
1131 retval = (gbObp1[0] & 3) | ((gbObp1[1] & 3) << 2) | ((gbObp1[2] & 3) << 4) | ((gbObp1[3] & 3) << 6);
1132 break;
1133 case 0x4a:
1134 retval = register_WY;
1135 break;
1136 case 0x4b:
1137 retval = register_WX;
1138 break;
1139 case 0x4d:
1140 retval = register_KEY1;
1141 break;
1142 case 0x4f:
1143 retval = 0xfe | register_VBK;
1144 break;
1145 case 0x51:
1146 retval = register_HDMA1;
1147 break;
1148 case 0x52:
1149 retval = register_HDMA2;
1150 break;
1151 case 0x53:
1152 retval = register_HDMA3;
1153 break;
1154 case 0x54:
1155 retval = register_HDMA4;
1156 break;
1157 case 0x55:
1158 retval = register_HDMA5;
1159 break;
1160 case 0x56:
1161 retval = register_RP;
1162 break;
1163 case 0x68:
1164 retval = register_BCPS;
1165 break;
1166 case 0x69:
1167 retval = register_BCPD;
1168 break;
1169 case 0x6a:
1170 retval = register_OCPS;
1171 break;
1172 case 0x6b:
1173 retval = register_OCPD;
1174 break;
1175 case 0x6c:
1176 retval = (register_FF6C & 1) | 0xFE;
1177 break;
1178 case 0x70:
1179 retval = (0xf8 | register_SVBK);
1180 break;
1181 case 0x72:
1182 retval = gbCgbMode ? register_FF72 : 0xFF;
1183 break;
1184 case 0x73:
1185 retval = gbCgbMode ? register_FF73 : 0xFF;
1186 break;
1187 case 0x74:
1188 retval = gbCgbMode ? register_FF74 : 0xFF;
1189 break;
1190 case 0x75:
1191 retval = gbCgbMode ? ((register_FF75 &~0x8F) | 0x8F) : 0xFF;
1192 break;
1193 case 0x76:
1194 retval = gbCgbMode ? 0x00 : 0xFF;
1195 break;
1196 case 0x77:
1197 retval = gbCgbMode ? 0x00 : 0xFF;
1198 break;
1199
1200 case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
1201 case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f:
1202 case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:
1203 case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f:
1204 case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7:
1205 case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
1206 case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
1207 case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf:
1208 case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7:
1209 case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf:
1210 case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7:
1211 case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf:
1212 case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7:
1213 case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef:
1214 case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
1215 case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe:
1216 retval = HRAM[address & 0x7F];
1217 break;
1218 case 0xff:
1219 retval = register_IE;
1220 break;
1221 }
1222 }
1223
1224 if(SubCheatsOn)
1225 {
1226 std::vector<SUBCHEAT>::iterator chit;
1227
1228 for(chit = SubCheats[address & 0x7].begin(); chit != SubCheats[address & 0x7].end(); chit++)
1229 {
1230 if(address == chit->addr)
1231 {
1232 //printf("%02x %02x %02x\n", retval, chit->value, chit->compare);
1233 if(chit->compare == -1 || chit->compare == retval)
1234 {
1235 retval = chit->value;
1236 }
1237 }
1238 }
1239 }
1240
1241 return(retval);
1242 //printf("Unknown read: %04x\n", address);
1243 //return(0xFF);
1244 //return gbMemoryMap[address>>12][address & 0x0fff];
1245 }
1246
gbSpeedSwitch()1247 void gbSpeedSwitch()
1248 {
1249 if(gbSpeed == 0) {
1250 gbSpeed = 1;
1251 GBLCD_MODE_0_CLOCK_TICKS = 51 * 2; //127; //51 * 2;
1252 GBLCD_MODE_1_CLOCK_TICKS = 1140 * 2;
1253 GBLCD_MODE_2_CLOCK_TICKS = 20 * 2; //52; //20 * 2;
1254 GBLCD_MODE_3_CLOCK_TICKS = 43 * 2; //99; //43 * 2;
1255 GBDIV_CLOCK_TICKS = 64 * 2;
1256 GBLY_INCREMENT_CLOCK_TICKS = 114 * 2;
1257 GBTIMER_MODE_0_CLOCK_TICKS = 256; //256*2;
1258 GBTIMER_MODE_1_CLOCK_TICKS = 4; //4*2;
1259 GBTIMER_MODE_2_CLOCK_TICKS = 16; //16*2;
1260 GBTIMER_MODE_3_CLOCK_TICKS = 64; //64*2;
1261 GBSERIAL_CLOCK_TICKS = 128 * 2;
1262 gbDivTicks *= 2;
1263 gbLcdTicks *= 2;
1264 gbLcdLYIncrementTicks *= 2;
1265 // timerTicks *= 2;
1266 // timerClockTicks *= 2;
1267 gbSerialTicks *= 2;
1268 // synchronizeTicks *= 2;
1269 // SYNCHRONIZE_CLOCK_TICKS *= 2;
1270 } else {
1271 gbSpeed = 0;
1272 GBLCD_MODE_0_CLOCK_TICKS = 51;
1273 GBLCD_MODE_1_CLOCK_TICKS = 1140;
1274 GBLCD_MODE_2_CLOCK_TICKS = 20;
1275 GBLCD_MODE_3_CLOCK_TICKS = 43;
1276 GBDIV_CLOCK_TICKS = 64;
1277 GBLY_INCREMENT_CLOCK_TICKS = 114;
1278 GBTIMER_MODE_0_CLOCK_TICKS = 256;
1279 GBTIMER_MODE_1_CLOCK_TICKS = 4;
1280 GBTIMER_MODE_2_CLOCK_TICKS = 16;
1281 GBTIMER_MODE_3_CLOCK_TICKS = 64;
1282 GBSERIAL_CLOCK_TICKS = 128;
1283 gbDivTicks /= 2;
1284 gbLcdTicks /= 2;
1285 gbLcdLYIncrementTicks /= 2;
1286 // timerTicks /= 2;
1287 // timerClockTicks /= 2;
1288 gbSerialTicks /= 2;
1289 // synchronizeTicks /= 2;
1290 // SYNCHRONIZE_CLOCK_TICKS /= 2;
1291 }
1292 }
1293
gbReset()1294 void gbReset()
1295 {
1296 GBZ80_Reset();
1297
1298 register_DIV = 0;
1299 register_TIMA = 0;
1300 register_TMA = 0;
1301 register_TAC = 0;
1302 register_IF = 1;
1303 register_LCDC = 0x91;
1304 register_STAT = 0;
1305 register_SCY = 0;
1306 register_SCX = 0;
1307 register_LY = 0;
1308 register_LYC = 0;
1309 register_DMA = 0;
1310 register_WY = 0;
1311 register_WX = 0;
1312 register_VBK = 0;
1313 register_HDMA1 = 0;
1314 register_HDMA2 = 0;
1315 register_HDMA3 = 0;
1316 register_HDMA4 = 0;
1317 register_HDMA5 = 0;
1318 register_SVBK = 0;
1319 register_IE = 0;
1320
1321 if(gbCgbMode)
1322 {
1323 register_HDMA5 = 0xff;
1324 register_BCPS = 0xc0;
1325 register_OCPS = 0xc0;
1326 }
1327 else
1328 {
1329 for(int i = 0; i < 8; i++)
1330 {
1331 int fun = 3 - (i & 3);
1332 fun *= 6;
1333 fun += 4;
1334 gbPalette[i] = fun | (fun << 5) | (fun << 10);
1335 }
1336 }
1337
1338 if(gbSpeed) {
1339 gbSpeedSwitch();
1340 register_KEY1 = 0;
1341 }
1342
1343 gbDivTicks = GBDIV_CLOCK_TICKS;
1344 gbLcdMode = GBLCDM_OAM;
1345 gbLcdTicks = GBLCD_MODE_2_CLOCK_TICKS;
1346 gbLcdLYIncrementTicks = 0;
1347 gbTimerTicks = 0;
1348 gbTimerClockTicks = 0;
1349 gbSerialTicks = 0;
1350 gbSerialBits = 0;
1351 gbSerialOn = 0;
1352 gbWindowLine = -1;
1353 gbTimerOn = 0;
1354 gbTimerMode = 0;
1355 // gbSynchronizeTicks = GBSYNCHRONIZE_CLOCK_TICKS;
1356 gbSpeed = 0;
1357 gbJoymask = 0;
1358
1359 if(gbCgbMode) {
1360 gbSpeed = 0;
1361 gbHdmaOn = 0;
1362 gbHdmaSource = 0x0000;
1363 gbHdmaDestination = 0x8000;
1364 gbWramBank = 1;
1365 register_LY = 0x90;
1366 gbLcdMode = GBLCDM_VBLANK;
1367 for(int i = 0; i < 64; i++)
1368 gbPalette[i] = 0x7fff;
1369 }
1370
1371 for(int i = 0; i < 4; i++)
1372 {
1373 gbBgp[i] = i;
1374 gbObp0[i] = 4 | i;
1375 gbObp1[i] = 8 | i;
1376 }
1377
1378 memset(&gbDataMBC1,0, sizeof(gbDataMBC1));
1379 gbDataMBC1.mapperROMBank = 1;
1380
1381 gbDataMBC2.mapperRAMEnable = 0;
1382 gbDataMBC2.mapperROMBank = 1;
1383
1384 memset(&gbDataMBC3,0, 6 * sizeof(int));
1385 gbDataMBC3.mapperROMBank = 1;
1386
1387 memset(&gbDataMBC5, 0, sizeof(gbDataMBC5));
1388 gbDataMBC5.mapperROMBank = 1;
1389
1390 memset(&gbDataHuC1, 0, sizeof(gbDataHuC1));
1391 gbDataHuC1.mapperROMBank = 1;
1392
1393 memset(&gbDataHuC3, 0, sizeof(gbDataHuC3));
1394 gbDataHuC3.mapperROMBank = 1;
1395
1396 gbMemoryMap[0x00] = &gbRom[0x0000];
1397 gbMemoryMap[0x01] = &gbRom[0x1000];
1398 gbMemoryMap[0x02] = &gbRom[0x2000];
1399 gbMemoryMap[0x03] = &gbRom[0x3000];
1400 gbMemoryMap[0x04] = &gbRom[0x4000];
1401 gbMemoryMap[0x05] = &gbRom[0x5000];
1402 gbMemoryMap[0x06] = &gbRom[0x6000];
1403 gbMemoryMap[0x07] = &gbRom[0x7000];
1404 gbMemoryMap[0x08] = &gbVram[0x0000];
1405 gbMemoryMap[0x09] = &gbVram[0x1000];
1406 gbMemoryMap[0x0a] = NULL;
1407 gbMemoryMap[0x0b] = NULL;
1408 gbMemoryMap[0x0c] = &gbWram[0x0000];
1409 gbMemoryMap[0x0d] = &gbWram[0x1000];
1410 gbMemoryMap[0x0e] = NULL;
1411 gbMemoryMap[0x0f] = NULL;
1412
1413 if(gbRam)
1414 {
1415 gbMemoryMap[0x0a] = &gbRam[0x0000];
1416
1417 if(gbRamSize > 0x1000)
1418 gbMemoryMap[0x0b] = &gbRam[0x1000];
1419 else
1420 gbMemoryMap[0x0b] = gbMemoryMap[0x0a];
1421 }
1422
1423 SOUND_Reset();
1424
1425 // BIOS simulate
1426 SOUND_Write(0, 0xFF26, 0x80);
1427 SOUND_Write(0, 0xFF11, 0x80);
1428 SOUND_Write(0, 0xFF12, 0xF3);
1429 SOUND_Write(0, 0xFF25, 0xF3);
1430 SOUND_Write(0, 0xFF24, 0x77);
1431 }
1432
gbPower(void)1433 static void gbPower(void)
1434 {
1435 snooze = 0;
1436 PadInterruptDelay = 0;
1437
1438 if(gbCgbMode)
1439 {
1440 memset(gbWram,0,0x8000);
1441 memset(gbVram, 0, 0x4000);
1442 }
1443 else
1444 {
1445 memset(gbWram, 0x00, 0x2000);
1446 memset(gbVram, 0x00, 0x2000);
1447 }
1448 memset(gbOAM, 0x00, 0xA0);
1449 memset(HRAM, 0x00, 0x80);
1450
1451 if(gbRam && !gbBattery)
1452 memset(gbRam, 0xFF, gbRamSize);
1453
1454 gbReset();
1455 }
1456
gbWriteSaveMBC1(const std::string & path)1457 static void gbWriteSaveMBC1(const std::string& path)
1458 {
1459 MDFN_DumpToFile(path, gbRam, gbRamSize, true);
1460 }
1461
gbWriteSaveMBC2(const std::string & path)1462 static void gbWriteSaveMBC2(const std::string& path)
1463 {
1464 MDFN_DumpToFile(path, gbRam, 256 * 2, true);
1465 }
1466
gbWriteSaveMBC3(const std::string & path,bool extendedSave)1467 static void gbWriteSaveMBC3(const std::string& path, bool extendedSave)
1468 {
1469 std::vector<PtrLengthPair> EvilRams;
1470 uint8 time_buffer[10 * 4 + 8]; // 10 uint32, 1 uint64
1471
1472 EvilRams.push_back(PtrLengthPair(gbRam, gbRamSize));
1473
1474 if(extendedSave)
1475 {
1476 MDFN_en32lsb(time_buffer + 0, gbDataMBC3.mapperSeconds);
1477 MDFN_en32lsb(time_buffer + 4, gbDataMBC3.mapperMinutes);
1478 MDFN_en32lsb(time_buffer + 8, gbDataMBC3.mapperHours);
1479 MDFN_en32lsb(time_buffer + 12, gbDataMBC3.mapperDays);
1480 MDFN_en32lsb(time_buffer + 16, gbDataMBC3.mapperControl);
1481 MDFN_en32lsb(time_buffer + 20, gbDataMBC3.mapperLSeconds);
1482 MDFN_en32lsb(time_buffer + 24, gbDataMBC3.mapperLMinutes);
1483 MDFN_en32lsb(time_buffer + 28, gbDataMBC3.mapperLHours);
1484 MDFN_en32lsb(time_buffer + 32, gbDataMBC3.mapperLDays);
1485 MDFN_en32lsb(time_buffer + 36, gbDataMBC3.mapperLControl);
1486 MDFN_en64lsb(time_buffer + 40, gbDataMBC3.mapperLastTime);
1487
1488 EvilRams.push_back(PtrLengthPair(time_buffer, sizeof(time_buffer)));
1489 }
1490
1491 MDFN_DumpToFile(path, EvilRams, true);
1492 }
1493
gbWriteSaveMBC5(const std::string & path)1494 static void gbWriteSaveMBC5(const std::string& path)
1495 {
1496 MDFN_DumpToFile(path, gbRam, gbRamSize, true);
1497 }
1498
gbWriteSaveMBC7(const std::string & path)1499 static void gbWriteSaveMBC7(const std::string& path)
1500 {
1501 MDFN_DumpToFile(path, gbRam, 256, true);
1502 }
1503
gbReadSaveMBC1(const std::string & path)1504 static void gbReadSaveMBC1(const std::string& path)
1505 {
1506 std::unique_ptr<Stream> file = MDFN_AmbigGZOpenHelper(path, std::vector<size_t>({ (unsigned)gbRamSize }));
1507
1508 file->read(gbRam, gbRamSize);
1509 }
1510
gbReadSaveMBC2(const std::string & path)1511 static void gbReadSaveMBC2(const std::string& path)
1512 {
1513 std::unique_ptr<Stream> file = MDFN_AmbigGZOpenHelper(path, std::vector<size_t>({ 256 * 2 }));
1514
1515 file->read(gbRam, 256 * 2);
1516 }
1517
gbReadSaveMBC3(const std::string & path)1518 static void gbReadSaveMBC3(const std::string& path)
1519 {
1520 uint8 time_buffer[10 * 4 + 8]; // 10 uint32, 1 uint64
1521 std::unique_ptr<Stream> file = MDFN_AmbigGZOpenHelper(path, std::vector<size_t>({ (unsigned)gbRamSize, (unsigned)gbRamSize + sizeof(time_buffer) }));
1522
1523 file->read(gbRam, gbRamSize);
1524
1525 if(file->read(&time_buffer[0], 1, false) == 1)
1526 {
1527 file->read(&time_buffer[1], sizeof(time_buffer) - 1);
1528
1529 gbDataMBC3.mapperSeconds = MDFN_de32lsb(time_buffer + 0);
1530 gbDataMBC3.mapperMinutes = MDFN_de32lsb(time_buffer + 4);
1531 gbDataMBC3.mapperHours = MDFN_de32lsb(time_buffer + 8);
1532 gbDataMBC3.mapperDays = MDFN_de32lsb(time_buffer + 12);
1533 gbDataMBC3.mapperControl = MDFN_de32lsb(time_buffer + 16);
1534 gbDataMBC3.mapperLSeconds = MDFN_de32lsb(time_buffer + 20);
1535 gbDataMBC3.mapperLMinutes = MDFN_de32lsb(time_buffer + 24);
1536 gbDataMBC3.mapperLHours = MDFN_de32lsb(time_buffer + 28);
1537 gbDataMBC3.mapperLDays = MDFN_de32lsb(time_buffer + 32);
1538 gbDataMBC3.mapperLControl = MDFN_de32lsb(time_buffer + 36);
1539 gbDataMBC3.mapperLastTime = MDFN_de64lsb(time_buffer + 40);
1540 }
1541 }
1542
gbReadSaveMBC5(const std::string & path)1543 static void gbReadSaveMBC5(const std::string& path)
1544 {
1545 std::unique_ptr<Stream> file = MDFN_AmbigGZOpenHelper(path, std::vector<size_t>({ (unsigned)gbRamSize }));
1546
1547 file->read(gbRam, gbRamSize);
1548 }
1549
gbReadSaveMBC7(const std::string & path)1550 static void gbReadSaveMBC7(const std::string& path)
1551 {
1552 std::unique_ptr<Stream> file = MDFN_AmbigGZOpenHelper(path, std::vector<size_t>({ 256 }));
1553
1554 file->read(gbRam, 256);
1555 }
1556
gbWriteBatteryFile(const std::string & path,bool extendedSave)1557 static void gbWriteBatteryFile(const std::string& path, bool extendedSave)
1558 {
1559 if(gbBattery)
1560 {
1561 int type = gbRom[0x147];
1562
1563 switch(type)
1564 {
1565 case 0x03:
1566 gbWriteSaveMBC1(path);
1567 break;
1568 case 0x06:
1569 gbWriteSaveMBC2(path);
1570 break;
1571 case 0x0f:
1572 case 0x10:
1573 case 0x13:
1574 gbWriteSaveMBC3(path, extendedSave);
1575 break;
1576 case 0x1b:
1577 case 0x1e:
1578 gbWriteSaveMBC5(path);
1579 break;
1580 case 0x22:
1581 gbWriteSaveMBC7(path);
1582 break;
1583 case 0xff:
1584 gbWriteSaveMBC1(path);
1585 break;
1586 }
1587 }
1588 }
1589
gbReadBatteryFile(const std::string & path)1590 static void gbReadBatteryFile(const std::string& path)
1591 {
1592 if(gbBattery)
1593 {
1594 int type = gbRom[0x147];
1595
1596 switch(type)
1597 {
1598 case 0x03:
1599 gbReadSaveMBC1(path);
1600 break;
1601
1602 case 0x06:
1603 gbReadSaveMBC2(path);
1604 break;
1605
1606 case 0x0f:
1607 case 0x10:
1608 case 0x13:
1609 //
1610 // Initialize time data before loading from save file, in case save file doesn't exist(or doesn't contain the time data) and throws an exception.
1611 //
1612 {
1613 int64 tmp = Time::EpochTime();
1614
1615 gbDataMBC3.mapperLastTime = tmp;
1616 struct tm lt;
1617 lt = Time::LocalTime(tmp);
1618 gbDataMBC3.mapperSeconds = lt.tm_sec;
1619 gbDataMBC3.mapperMinutes = lt.tm_min;
1620 gbDataMBC3.mapperHours = lt.tm_hour;
1621 gbDataMBC3.mapperDays = lt.tm_yday & 255;
1622 gbDataMBC3.mapperControl = (gbDataMBC3.mapperControl & 0xfe) |
1623 (lt.tm_yday > 255 ? 1: 0);
1624 }
1625 gbReadSaveMBC3(path);
1626 break;
1627
1628 case 0x1b:
1629 case 0x1e:
1630 gbReadSaveMBC5(path);
1631 break;
1632
1633 case 0x22:
1634 gbReadSaveMBC7(path);
1635 break;
1636
1637 case 0xff:
1638 gbReadSaveMBC1(path);
1639 break;
1640 }
1641 }
1642 }
1643
1644 static const SFORMAT Joy_StateRegs[] =
1645 {
1646 SFVAR(gbJoymask),
1647 SFEND
1648 };
1649
1650 static const SFORMAT MBC1_StateRegs[] =
1651 {
1652 SFVARN(gbDataMBC1.mapperRAMEnable, "RAME"),
1653 SFVARN(gbDataMBC1.mapperROMBank, "ROMB"),
1654 SFVARN(gbDataMBC1.mapperRAMBank,"RAMB"),
1655 SFVARN(gbDataMBC1.mapperMemoryModel, "MEMM"),
1656 SFEND
1657 };
1658
1659 static const SFORMAT MBC2_StateRegs[] =
1660 {
1661 SFVARN(gbDataMBC2.mapperRAMEnable, "RAME"),
1662 SFVARN(gbDataMBC2.mapperROMBank, "ROMB"),
1663 SFEND
1664 };
1665
1666 static const SFORMAT MBC3_StateRegs[] =
1667 {
1668 SFVARN(gbDataMBC3.mapperRAMEnable, "RAME"),
1669 SFVARN(gbDataMBC3.mapperROMBank, "ROMB"),
1670 SFVARN(gbDataMBC3.mapperRAMBank, "RAMB"),
1671 SFVARN(gbDataMBC3.mapperClockLatch, "CLKL"),
1672 SFVARN(gbDataMBC3.mapperClockRegister, "CLKR"),
1673 SFVARN(gbDataMBC3.mapperSeconds, "SEC"),
1674 SFVARN(gbDataMBC3.mapperMinutes, "MIN"),
1675 SFVARN(gbDataMBC3.mapperHours, "HOUR"),
1676 SFVARN(gbDataMBC3.mapperDays, "DAY"),
1677 SFVARN(gbDataMBC3.mapperControl, "CTRL"),
1678
1679 SFVARN(gbDataMBC3.mapperLSeconds, "LSEC"),
1680 SFVARN(gbDataMBC3.mapperLMinutes, "LMIN"),
1681 SFVARN(gbDataMBC3.mapperLHours, "LHUR"),
1682 SFVARN(gbDataMBC3.mapperLDays, "LDAY"),
1683 SFVARN(gbDataMBC3.mapperLControl, "LCTR"),
1684 SFVARN(gbDataMBC3.mapperLastTime, "LTIM"),
1685
1686 SFEND
1687 };
1688
1689 static const SFORMAT MBC5_StateRegs[] =
1690 {
1691 SFVAR(gbDataMBC5.mapperRAMEnable),
1692 SFVAR(gbDataMBC5.mapperROMBank),
1693 SFVAR(gbDataMBC5.mapperRAMBank),
1694 SFVAR(gbDataMBC5.mapperROMHighAddress),
1695 SFVAR(gbDataMBC5.isRumbleCartridge),
1696 SFEND
1697 };
1698
1699 static const SFORMAT MBC7_StateRegs[] =
1700 {
1701 SFVARN(gbDataMBC7.mapperROMBank, "ROMB"),
1702 SFVARN(gbDataMBC7.cs, "CS"),
1703 SFVARN(gbDataMBC7.sk, "SK"),
1704 SFVARN(gbDataMBC7.state, "STTE"),
1705 SFVARN(gbDataMBC7.buffer, "BUF"),
1706 SFVARN(gbDataMBC7.idle, "IDLE"),
1707 SFVARN(gbDataMBC7.count, "CONT"),
1708 SFVARN(gbDataMBC7.code, "CODE"),
1709 SFVARN(gbDataMBC7.address, "ADDR"),
1710 SFVARN(gbDataMBC7.writeEnable, "WRE"),
1711 SFVARN(gbDataMBC7.value, "VALU"),
1712
1713 SFVARN(gbDataMBC7.curtiltx, "TILTX"),
1714 SFVARN(gbDataMBC7.curtilty, "TILTY"),
1715
1716 SFEND
1717 };
1718
1719 static const SFORMAT HuC1_StateRegs[] =
1720 {
1721 SFVARN(gbDataHuC1.mapperRAMEnable, "RAME"),
1722 SFVARN(gbDataHuC1.mapperROMBank, "ROMB"),
1723 SFVARN(gbDataHuC1.mapperRAMBank, "RAMB"),
1724 SFVARN(gbDataHuC1.mapperMemoryModel, "MEMM"),
1725 SFVARN(gbDataHuC1.mapperROMHighAddress, "ROMH"),
1726 SFEND
1727 };
1728
1729 static const SFORMAT HuC3_StateRegs[] =
1730 {
1731 SFVARN(gbDataHuC3.mapperRAMEnable, "RAME"),
1732 SFVARN(gbDataHuC3.mapperROMBank, "ROMB"),
1733 SFVARN(gbDataHuC3.mapperRAMBank, "RAMB"),
1734 SFVARN(gbDataHuC3.mapperAddress, "ADDR"),
1735 SFVARN(gbDataHuC3.mapperRAMFlag, "RAMF"),
1736 SFVARN(gbDataHuC3.mapperRAMValue, "RAMV"),
1737 SFVARN(gbDataHuC3.mapperRegister1, "REG1"),
1738 SFVARN(gbDataHuC3.mapperRegister2, "REG2"),
1739 SFVARN(gbDataHuC3.mapperRegister3, "REG3"),
1740 SFVARN(gbDataHuC3.mapperRegister4, "REG4"),
1741 SFVARN(gbDataHuC3.mapperRegister5, "REG5"),
1742 SFVARN(gbDataHuC3.mapperRegister6, "REG6"),
1743 SFVARN(gbDataHuC3.mapperRegister7, "REG7"),
1744 SFVARN(gbDataHuC3.mapperRegister8, "REG8"),
1745
1746 SFEND
1747 };
1748
1749
1750 static const SFORMAT gbSaveGameStruct[] =
1751 {
1752 SFVAR(GBLCD_MODE_0_CLOCK_TICKS),
1753 SFVAR(GBLCD_MODE_1_CLOCK_TICKS),
1754 SFVAR(GBLCD_MODE_2_CLOCK_TICKS),
1755 SFVAR(GBLCD_MODE_3_CLOCK_TICKS),
1756 SFVAR(GBDIV_CLOCK_TICKS),
1757 SFVAR(GBLY_INCREMENT_CLOCK_TICKS),
1758 SFVAR(GBTIMER_MODE_0_CLOCK_TICKS),
1759 SFVAR(GBTIMER_MODE_1_CLOCK_TICKS),
1760 SFVAR(GBTIMER_MODE_2_CLOCK_TICKS),
1761 SFVAR(GBTIMER_MODE_3_CLOCK_TICKS),
1762 SFVAR(GBSERIAL_CLOCK_TICKS),
1763 SFVAR(GBSYNCHRONIZE_CLOCK_TICKS),
1764
1765 SFVAR(snooze),
1766 SFVAR(PadInterruptDelay),
1767
1768 SFVAR(gbDivTicks),
1769 SFVAR(gbLcdMode),
1770 SFVAR(gbLcdTicks),
1771 SFVAR(gbLcdLYIncrementTicks),
1772 SFVAR(gbTimerTicks),
1773 SFVAR(gbTimerClockTicks),
1774 SFVAR(gbSerialTicks),
1775 SFVAR(gbSerialBits),
1776 SFVAR(gbSynchronizeTicks),
1777 SFVAR(gbTimerOn),
1778 SFVAR(gbTimerMode),
1779 SFVAR(gbSerialOn),
1780 SFVAR(gbWindowLine),
1781 //SFVAR(gbCgbMode),
1782 SFVAR(gbWramBank),
1783 SFVAR(gbHdmaSource),
1784 SFVAR(gbHdmaDestination),
1785 SFVAR(gbHdmaBytes),
1786 SFVAR(gbHdmaOn),
1787 SFVAR(gbSpeed),
1788 SFVAR(gbDmaTicks),
1789 SFVAR(register_P1),
1790 SFVAR(register_SB),
1791 SFVAR(register_SC),
1792 SFVAR(register_DIV),
1793 SFVAR(register_TIMA),
1794 SFVAR(register_TMA),
1795 SFVAR(register_TAC),
1796 SFVAR(register_IF),
1797 SFVAR(register_LCDC),
1798 SFVAR(register_STAT),
1799 SFVAR(register_SCY),
1800 SFVAR(register_SCX),
1801 SFVAR(register_LY),
1802 SFVAR(register_LYC),
1803 SFVAR(register_DMA),
1804 SFVAR(register_WY),
1805 SFVAR(register_WX),
1806 SFVAR(register_VBK),
1807 SFVAR(register_HDMA1),
1808 SFVAR(register_HDMA2),
1809 SFVAR(register_HDMA3),
1810 SFVAR(register_HDMA4),
1811 SFVAR(register_HDMA5),
1812 SFVAR(register_RP),
1813 SFVAR(register_FF6C),
1814 SFVAR(register_SVBK),
1815 SFVAR(register_FF72),
1816 SFVAR(register_FF73),
1817 SFVAR(register_FF74),
1818 SFVAR(register_FF75),
1819 SFVAR(register_IE),
1820 SFVARN(gbBgp, "BGP"),
1821 SFVARN(gbObp0, "OBP0"),
1822 SFVARN(gbObp1, "OBP1"),
1823 SFEND
1824 };
1825
1826 static void CloseGame(void) MDFN_COLD;
CloseGame(void)1827 static void CloseGame(void)
1828 {
1829 try
1830 {
1831 gbWriteBatteryFile(MDFN_MakeFName(MDFNMKF_SAV, 0, "sav"), true);
1832 }
1833 catch(std::exception &e)
1834 {
1835 MDFND_OutputNotice(MDFN_NOTICE_ERROR, e.what());
1836 }
1837
1838 Cleanup();
1839 }
1840
StateRest(int version)1841 static void StateRest(int version)
1842 {
1843 register_SVBK &= 7;
1844 register_VBK &= 1;
1845
1846 for(unsigned i = 0; i < 4; i++)
1847 {
1848 gbBgp[i] = gbBgp[i] & 0x3;
1849 gbObp0[i] = (gbObp0[i] & 0x3) | 4;
1850 gbObp1[i] = (gbObp1[i] & 0x3) | 8;
1851 }
1852
1853 gbMemoryMap[0x00] = &gbRom[0x0000];
1854 gbMemoryMap[0x01] = &gbRom[0x1000];
1855 gbMemoryMap[0x02] = &gbRom[0x2000];
1856 gbMemoryMap[0x03] = &gbRom[0x3000];
1857 gbMemoryMap[0x04] = &gbRom[0x4000];
1858 gbMemoryMap[0x05] = &gbRom[0x5000];
1859 gbMemoryMap[0x06] = &gbRom[0x6000];
1860 gbMemoryMap[0x07] = &gbRom[0x7000];
1861 gbMemoryMap[0x08] = &gbVram[0x0000];
1862 gbMemoryMap[0x09] = &gbVram[0x1000];
1863 gbMemoryMap[0x0a] = NULL;
1864 gbMemoryMap[0x0b] = NULL;
1865 gbMemoryMap[0x0c] = &gbWram[0x0000];
1866 gbMemoryMap[0x0d] = &gbWram[0x1000];
1867 gbMemoryMap[0x0e] = NULL;
1868 gbMemoryMap[0x0f] = NULL;
1869
1870 if(gbRam)
1871 {
1872 gbMemoryMap[0x0a] = &gbRam[0x0000];
1873
1874 if(gbRamSize > 0x1000)
1875 gbMemoryMap[0x0b] = &gbRam[0x1000];
1876 else
1877 gbMemoryMap[0x0b] = gbMemoryMap[0x0a];
1878 }
1879
1880 int type = gbRom[0x147];
1881
1882 switch(type) {
1883 case 0x00:
1884 case 0x01:
1885 case 0x02:
1886 case 0x03:
1887 // MBC 1
1888 memoryUpdateMapMBC1();
1889 break;
1890 case 0x05:
1891 case 0x06:
1892 // MBC2
1893 memoryUpdateMapMBC2();
1894 break;
1895 case 0x0f:
1896 case 0x10:
1897 case 0x11:
1898 case 0x12:
1899 case 0x13:
1900 // MBC 3
1901 memoryUpdateMapMBC3();
1902 break;
1903 case 0x19:
1904 case 0x1a:
1905 case 0x1b:
1906 // MBC5
1907 memoryUpdateMapMBC5();
1908 break;
1909 case 0x1c:
1910 case 0x1d:
1911 case 0x1e:
1912 // MBC 5 Rumble
1913 memoryUpdateMapMBC5();
1914 break;
1915 case 0x22:
1916 // MBC 7
1917 memoryUpdateMapMBC7();
1918 break;
1919 case 0xfe:
1920 // HuC3
1921 memoryUpdateMapHuC3();
1922 break;
1923 case 0xff:
1924 // HuC1
1925 memoryUpdateMapHuC1();
1926 break;
1927 }
1928
1929 if(gbCgbMode)
1930 {
1931 int value = register_SVBK;
1932 if(value == 0)
1933 value = 1;
1934
1935 gbMemoryMap[0x08] = &gbVram[register_VBK * 0x2000];
1936 gbMemoryMap[0x09] = &gbVram[register_VBK * 0x2000 + 0x1000];
1937 gbMemoryMap[0x0d] = &gbWram[value * 0x1000];
1938
1939 gbWramBank = value;
1940 }
1941
1942 }
1943
1944 uint32 gblayerSettings;
1945
GetGBRAMSizeString(uint8 t)1946 static const char *GetGBRAMSizeString(uint8 t)
1947 {
1948 const char *type = _("Unknown");
1949
1950 switch(t)
1951 {
1952 case 0:
1953 type = _("None");
1954 break;
1955 case 1:
1956 type = "2K";
1957 break;
1958 case 2:
1959 type = "8K";
1960 break;
1961 case 3:
1962 type = "32K";
1963 break;
1964 case 4:
1965 type = "128K";
1966 break;
1967 case 5:
1968 type = "64K";
1969 break;
1970 }
1971
1972 return(type);
1973 }
1974
1975
GetGBTypeString(uint8 t)1976 static const char *GetGBTypeString(uint8 t)
1977 {
1978 const char *type = _("Unknown");
1979
1980 switch(t)
1981 {
1982 case 0x00:
1983 type = "ROM";
1984 break;
1985 case 0x01:
1986 type = "ROM+MBC1";
1987 break;
1988 case 0x02:
1989 type = "ROM+MBC1+RAM";
1990 break;
1991 case 0x03:
1992 type = "ROM+MBC1+RAM+BATT";
1993 break;
1994 case 0x05:
1995 type = "ROM+MBC2";
1996 break;
1997 case 0x06:
1998 type = "ROM+MBC2+BATT";
1999 break;
2000 case 0x0f:
2001 type = "ROM+MBC3+TIMER+BATT";
2002 break;
2003 case 0x10:
2004 type = "ROM+MBC3+TIMER+RAM+BATT";
2005 break;
2006 case 0x11:
2007 type = "ROM+MBC3";
2008 break;
2009 case 0x12:
2010 type = "ROM+MBC3+RAM";
2011 break;
2012 case 0x13:
2013 type = "ROM+MBC3+RAM+BATT";
2014 break;
2015 case 0x19:
2016 type = "ROM+MBC5";
2017 break;
2018 case 0x1a:
2019 type = "ROM+MBC5+RAM";
2020 break;
2021 case 0x1b:
2022 type = "ROM+MBC5+RAM+BATT";
2023 break;
2024 case 0x1c:
2025 type = "ROM+MBC5+RUMBLE";
2026 break;
2027 case 0x1d:
2028 type = "ROM+MBC5+RUMBLE+RAM";
2029 break;
2030 case 0x1e:
2031 type = "ROM+MBC5+RUMBLE+RAM+BATT";
2032 break;
2033 case 0x22:
2034 type = "ROM+MBC7+BATT";
2035 break;
2036 case 0xfe:
2037 type = "ROM+HuC-3";
2038 break;
2039 case 0xff:
2040 type = "ROM+HuC-1";
2041 break;
2042 }
2043
2044 return(type);
2045 }
2046
TestMagic(GameFile * gf)2047 static bool TestMagic(GameFile* gf)
2048 {
2049 static const uint8 GBMagic[8] = { 0xCE, 0xED, 0x66, 0x66, 0xCC, 0x0D, 0x00, 0x0B };
2050 uint8 data[0x200];
2051
2052 if(gf->stream->read(data, 0x200, false) != 0x200 || memcmp(data + 0x104, GBMagic, 8))
2053 return false;
2054
2055 return true;
2056 }
2057
Cleanup(void)2058 static void Cleanup(void)
2059 {
2060 SOUND_Kill();
2061
2062 if(gbRam != NULL)
2063 {
2064 delete[] gbRam;
2065 gbRam = NULL;
2066 }
2067
2068 if(gbRom != NULL)
2069 {
2070 delete[] gbRom;
2071 gbRom = NULL;
2072 }
2073
2074 if(gbVram != NULL)
2075 {
2076 delete[] gbVram;
2077 gbVram = NULL;
2078 }
2079
2080 if(gbWram != NULL)
2081 {
2082 delete[] gbWram;
2083 gbWram = NULL;
2084 }
2085
2086 if(gbColorFilter)
2087 {
2088 delete[] gbColorFilter;
2089 gbColorFilter = NULL;
2090 }
2091 }
2092
2093 static void Load(GameFile* gf) MDFN_COLD;
Load(GameFile * gf)2094 static void Load(GameFile* gf)
2095 {
2096 try
2097 {
2098 gbColorFilter = new uint32[32768];
2099
2100 gbEmulatorType = MDFN_GetSettingI("gb.system_type");
2101
2102 MDFNMP_Init(128, (65536 + 32768) / 128); // + 32768 for GBC WRAM for supported GameShark cheats with RAM page numbers
2103
2104 SOUND_Init();
2105
2106 LoadROM(gf->stream);
2107
2108 md5_context md5;
2109 md5.starts();
2110 md5.update(gbRom, gbRomSize);
2111 md5.finish(MDFNGameInfo->MD5);
2112
2113 MDFN_printf(_("ROM: %dKiB\n"), (gbRomSize + 1023) / 1024);
2114 MDFN_printf(_("ROM CRC32: 0x%08x\n"), (unsigned int)crc32(0, gbRom, gbRomSize));
2115 MDFN_printf(_("ROM MD5: 0x%s\n"), md5_context::asciistr(MDFNGameInfo->MD5, 0).c_str());
2116 MDFN_printf(_("Type: 0x%02x(%s)\n"), gbRom[0x147], GetGBTypeString(gbRom[0x147]));
2117 MDFN_printf(_("RAM Size: 0x%02x(%s)\n"), gbRom[0x149], GetGBRAMSizeString(gbRom[0x149]));
2118 MDFN_printf(_("Version: 0x%02x\n"), gbRom[0x14C]);
2119
2120 //
2121 //
2122 //
2123
2124 try
2125 {
2126 gbReadBatteryFile(MDFN_MakeFName(MDFNMKF_SAV, 0, "sav"));
2127 }
2128 catch(MDFN_Error &e)
2129 {
2130 if(e.GetErrno() != ENOENT)
2131 throw;
2132 }
2133 gblayerSettings = 0xFF;
2134
2135
2136 MDFNGameInfo->CPInfoActiveBF = 1 << (bool)gbCgbMode;
2137 }
2138 catch(std::exception &e)
2139 {
2140 Cleanup();
2141 throw;
2142 }
2143 }
2144
LoadROM(Stream * s)2145 static void LoadROM(Stream* s)
2146 {
2147 uint8 header[0x200];
2148
2149 s->read(header, 0x200);
2150
2151 if(header[0x148] > 8)
2152 throw MDFN_Error(0, _("Unsupported ROM size specified in GB header."));
2153
2154 gbRomSize = gbRomSizes[header[0x148]];
2155 gbRomSizeMask = gbRomSizesMasks[header[0x148]];
2156
2157 gbRom = new uint8[gbRomSize];
2158 memset(gbRom, 0xFF, gbRomSize);
2159 memcpy(gbRom, header, std::min<uint64>(0x200, gbRomSize));
2160
2161 if(gbRomSize > 0x200) // && in_rom_size > 0x200)
2162 s->read(gbRom + 0x200, gbRomSize - 0x200); // std::min<uint64>(in_rom_size, gbRomSize) - 0x200);
2163
2164 if(header[0x149] > 5)
2165 throw MDFN_Error(0, _("Unsupported RAM size specified in GB header."));
2166
2167 gbRamSize = gbRamSizes[header[0x149]];
2168 gbRamSizeMask = gbRamSizesMasks[header[0x149]];
2169
2170 int type = header[0x147];
2171
2172 mapperReadRAM = NULL;
2173
2174 switch(type) {
2175 case 0x00:
2176 case 0x01:
2177 case 0x02:
2178 case 0x03:
2179 // MBC 1
2180 mapper = mapperMBC1ROM;
2181 mapperRAM = mapperMBC1RAM;
2182 break;
2183 case 0x05:
2184 case 0x06:
2185 // MBC2
2186 mapper = mapperMBC2ROM;
2187 mapperRAM = mapperMBC2RAM;
2188 gbRamSize = 0x200;
2189 gbRamSizeMask = 0x1ff;
2190 break;
2191 case 0x0f:
2192 case 0x10:
2193 case 0x11:
2194 case 0x12:
2195 case 0x13:
2196 // MBC 3
2197 mapper = mapperMBC3ROM;
2198 mapperRAM = mapperMBC3RAM;
2199 mapperReadRAM = mapperMBC3ReadRAM;
2200 break;
2201 case 0x19:
2202 case 0x1a:
2203 case 0x1b:
2204 // MBC5
2205 mapper = mapperMBC5ROM;
2206 mapperRAM = mapperMBC5RAM;
2207 break;
2208 case 0x1c:
2209 case 0x1d:
2210 case 0x1e:
2211 // MBC 5 Rumble
2212 mapper = mapperMBC5ROM;
2213 mapperRAM = mapperMBC5RAM;
2214 break;
2215 case 0x22:
2216 // MBC 7
2217 mapper = mapperMBC7ROM;
2218 mapperRAM = mapperMBC7RAM;
2219 mapperReadRAM = mapperMBC7ReadRAM;
2220 gbRamSize = 0x200;
2221 gbRamSizeMask = 0x1ff;
2222 break;
2223 case 0xfe:
2224 // HuC3
2225 mapper = mapperHuC3ROM;
2226 mapperRAM = mapperHuC3RAM;
2227 mapperReadRAM = mapperHuC3ReadRAM;
2228 break;
2229 case 0xff:
2230 // HuC1
2231 mapper = mapperHuC1ROM;
2232 mapperRAM = mapperHuC1RAM;
2233 break;
2234 default:
2235 throw MDFN_Error(0, _("Unsupported mapper type specified in GB header."));
2236 }
2237
2238 switch(type) {
2239 case 0x03:
2240 case 0x06:
2241 case 0x0f:
2242 case 0x10:
2243 case 0x13:
2244 case 0x1b:
2245 case 0x1d:
2246 case 0x1e:
2247 case 0x22:
2248 case 0xff:
2249 gbBattery = 1;
2250 break;
2251 }
2252
2253 if(gbRamSize) {
2254 gbRam = new uint8[gbRamSize];
2255 memset(gbRam, 0xFF, gbRamSize);
2256 }
2257
2258 // CGB bit
2259 if(header[0x143] & 0x80)
2260 {
2261 if(gbEmulatorType == 0 ||
2262 gbEmulatorType == 1 ||
2263 gbEmulatorType == 4 ||
2264 gbEmulatorType == 5) {
2265 gbCgbMode = 1;
2266 memset(gbPalette,0, 2*128);
2267 } else {
2268 gbCgbMode = 0;
2269 }
2270 }
2271 else
2272 gbCgbMode = 0;
2273
2274 if(gbCgbMode)
2275 {
2276 gbWram = new uint8[0x8000];
2277 memset(gbWram, 0, 0x8000);
2278 MDFNMP_AddRAM(0x8000, 0x10000, gbWram);
2279
2280 gbVram = new uint8[0x4000];
2281 memset(gbVram, 0, 0x4000);
2282 }
2283 else
2284 {
2285 gbWram = new uint8[0x2000];
2286 memset(gbWram,0,0x2000);
2287
2288 for(unsigned x = 0; x < 32768; x += 8192)
2289 MDFNMP_AddRAM(0x2000, 0x10000 | x, &gbWram[0]);
2290
2291 gbVram = new uint8[0x2000];
2292 memset(gbVram, 0, 0x2000);
2293 }
2294
2295 MDFNMP_AddRAM(0x80, 0xFF80, HRAM);
2296 MDFNMP_AddRAM(0x2000, 0xC000, gbWram);
2297
2298 if(gbRam)
2299 MDFNMP_AddRAM(gbRamSize > 8192 ? 8192 : gbRamSize, 0xA000, gbRam);
2300
2301 switch(type) {
2302 case 0x1c:
2303 case 0x1d:
2304 case 0x1e:
2305 gbDataMBC5.isRumbleCartridge = 1;
2306 }
2307
2308 gbPower();
2309 }
2310
2311
2312 template<typename T>
CopyLineSurface(MDFN_Surface * surface)2313 static void CopyLineSurface(MDFN_Surface *surface)
2314 {
2315 T *dest = surface->pix<T>() + register_LY * surface->pitchinpix;
2316
2317 if(gbCgbMode)
2318 {
2319 for(int x = 0; x < 160;)
2320 {
2321 *dest++ = gbColorFilter[gbLineMix.cgb[x++]];
2322 *dest++ = gbColorFilter[gbLineMix.cgb[x++]];
2323 *dest++ = gbColorFilter[gbLineMix.cgb[x++]];
2324 *dest++ = gbColorFilter[gbLineMix.cgb[x++]];
2325
2326 *dest++ = gbColorFilter[gbLineMix.cgb[x++]];
2327 *dest++ = gbColorFilter[gbLineMix.cgb[x++]];
2328 *dest++ = gbColorFilter[gbLineMix.cgb[x++]];
2329 *dest++ = gbColorFilter[gbLineMix.cgb[x++]];
2330
2331 *dest++ = gbColorFilter[gbLineMix.cgb[x++]];
2332 *dest++ = gbColorFilter[gbLineMix.cgb[x++]];
2333 *dest++ = gbColorFilter[gbLineMix.cgb[x++]];
2334 *dest++ = gbColorFilter[gbLineMix.cgb[x++]];
2335
2336 *dest++ = gbColorFilter[gbLineMix.cgb[x++]];
2337 *dest++ = gbColorFilter[gbLineMix.cgb[x++]];
2338 *dest++ = gbColorFilter[gbLineMix.cgb[x++]];
2339 *dest++ = gbColorFilter[gbLineMix.cgb[x++]];
2340 }
2341 }
2342 else // to if(gbCgbMode)
2343 {
2344 if(sizeof(T) == 1)
2345 {
2346 for(int x = 0; x < 160; x++)
2347 dest[x] = gbLineMix.dmg[x];
2348 }
2349 else
2350 {
2351 for(int x = 0; x < 160; x++)
2352 dest[x] = gbMonoColorMap[gbLineMix.dmg[x]];
2353 }
2354 }
2355 }
2356
2357 template<typename T>
FillLineSurface(MDFN_Surface * surface,int y)2358 static void FillLineSurface(MDFN_Surface *surface, int y)
2359 {
2360 T* dest = surface->pix<T>() + y * surface->pitchinpix;
2361 uint32 fill_color = gbCgbMode ? gbColorFilter[gbPalette[0]] : ((sizeof(T) == 1) ? 12 : gbMonoColorMap[12]);
2362
2363 for(int x = 0; x < 160; x++)
2364 dest[x] = fill_color;
2365 }
2366
2367 static uint8 *paddie, *tilt_paddie;
2368
MDFNGB_SetInput(unsigned port,const char * type,uint8 * ptr)2369 static void MDFNGB_SetInput(unsigned port, const char *type, uint8 *ptr)
2370 {
2371 if(port)
2372 tilt_paddie = (uint8*)ptr;
2373 else
2374 paddie = (uint8*)ptr;
2375 }
2376
Emulate(EmulateSpecStruct * espec)2377 static void Emulate(EmulateSpecStruct *espec)
2378 {
2379 bool linedrawn[144];
2380
2381 #if 0
2382 {
2383 static bool firstcat = true;
2384 MDFN_PixelFormat nf;
2385
2386 nf.bpp = 8;
2387 nf.colorspace = MDFN_COLORSPACE_RGB;
2388 nf.Rshift = 0;
2389 nf.Gshift = 0;
2390 nf.Bshift = 0;
2391 nf.Ashift = 8;
2392
2393 nf.Rprec = 6;
2394 nf.Gprec = 6;
2395 nf.Bprec = 6;
2396 nf.Aprec = 0;
2397
2398 espec->surface->SetFormat(nf, false);
2399 espec->VideoFormatChanged = firstcat;
2400 firstcat = false;
2401 }
2402 #endif
2403
2404 if(espec->VideoFormatChanged)
2405 SetPixelFormat(espec->surface->format, gbCgbMode, espec->CustomPalette, espec->CustomPaletteNumEntries);
2406
2407 if(espec->SoundFormatChanged)
2408 MDFNGB_SetSoundRate(espec->SoundRate);
2409
2410
2411
2412 espec->DisplayRect.x = 0;
2413 espec->DisplayRect.y = 0;
2414 espec->DisplayRect.w = 160;
2415 espec->DisplayRect.h = 144;
2416
2417 memset(linedrawn, 0, sizeof(linedrawn));
2418
2419 if(!espec->skip && espec->surface->palette)
2420 memcpy(espec->surface->palette, PalTest, sizeof(PalTest));
2421
2422 if(gbRom[0x147] == 0x22)
2423 {
2424 gbDataMBC7.curtiltx = 2048 + ((int32)MDFN_de16lsb(&tilt_paddie[0x0]) - 32768) / 200;
2425 gbDataMBC7.curtilty = 2048 + ((int32)MDFN_de16lsb(&tilt_paddie[0x2]) - 32768) / 200;
2426 }
2427
2428 if(*paddie != gbJoymask)
2429 {
2430 PadInterruptDelay = 20;
2431 }
2432
2433 MDFNMP_ApplyPeriodicCheats();
2434 int clockTicks = 0;
2435 int doret = 0;
2436
2437 while(!doret && SoundTS < 72000)
2438 {
2439 if(gbDmaTicks)
2440 {
2441 clockTicks = 4;
2442 gbDmaTicks -= 4;
2443 if(gbDmaTicks < 0) { clockTicks += gbDmaTicks; gbDmaTicks = 0; }
2444 }
2445 else
2446 clockTicks = GBZ80_RunOp();
2447
2448 SoundTS += clockTicks << (2 - gbSpeed);
2449
2450 gbDivTicks -= clockTicks;
2451 while(gbDivTicks <= 0)
2452 {
2453 register_DIV++;
2454 gbDivTicks += GBDIV_CLOCK_TICKS;
2455 }
2456
2457 if(PadInterruptDelay > 0)
2458 {
2459 PadInterruptDelay -= clockTicks;
2460 if(PadInterruptDelay <= 0)
2461 {
2462 gbJoymask = *paddie;
2463 register_IF |= 0x10;
2464 }
2465 }
2466
2467 if(snooze > 0)
2468 {
2469 snooze -= clockTicks;
2470 if(snooze <= 0)
2471 {
2472 register_IF |= 1; // V-Blank interrupt
2473 if(register_STAT & 0x10)
2474 register_IF |= 2;
2475 }
2476 }
2477
2478
2479 if(register_LCDC & 0x80)
2480 {
2481 // LCD stuff
2482 gbLcdTicks -= clockTicks;
2483 if(gbLcdMode == GBLCDM_VBLANK)
2484 {
2485 // during V-BLANK,we need to increment LY at the same rate!
2486 gbLcdLYIncrementTicks -= clockTicks;
2487 while(gbLcdLYIncrementTicks <= 0)
2488 {
2489 gbLcdLYIncrementTicks += GBLY_INCREMENT_CLOCK_TICKS;
2490
2491 if(register_LY < 153)
2492 {
2493 register_LY++;
2494 gbCompareLYToLYC();
2495
2496 if(register_LY >= 153)
2497 gbLcdLYIncrementTicks = 6;
2498 }
2499 else
2500 {
2501 register_LY = 0x00;
2502 // reset the window line
2503 gbWindowLine = -1;
2504 gbLcdLYIncrementTicks = GBLY_INCREMENT_CLOCK_TICKS * 2;
2505 gbCompareLYToLYC();
2506 }
2507 }
2508 }
2509
2510 // our counter is off, see what we need to do
2511 while(gbLcdTicks <= 0)
2512 {
2513 switch(gbLcdMode)
2514 {
2515 case GBLCDM_HBLANK:
2516 // H-Blank
2517 register_LY++;
2518 gbCompareLYToLYC();
2519
2520 // check if we reached the V-Blank period
2521 if(register_LY == 144)
2522 {
2523 doret = 1;
2524 // Yes, V-Blank
2525 // set the LY increment counter
2526 gbLcdLYIncrementTicks = gbLcdTicks + GBLY_INCREMENT_CLOCK_TICKS;
2527 gbLcdTicks += GBLCD_MODE_1_CLOCK_TICKS;
2528 gbLcdMode = 1;
2529
2530 if(register_LCDC & 0x80)
2531 {
2532 snooze = 6;
2533 //register_IF |= 1; // V-Blank interrupt
2534 //if(register_STAT & 0x10)
2535 // register_IF |= 2;
2536 }
2537 } else {
2538 // go the the OAM being accessed mode
2539 gbLcdTicks += GBLCD_MODE_2_CLOCK_TICKS;
2540 gbLcdMode = 2;
2541
2542 // only one LCD interrupt per line. may need to generalize...
2543 if(!(register_STAT & 0x40) ||
2544 (register_LY != register_LYC)) {
2545 if((register_STAT & 0x28) == 0x20)
2546 register_IF |= 2;
2547 }
2548 }
2549 break;
2550
2551 case GBLCDM_VBLANK:
2552 // V-Blank
2553 // next mode is OAM being accessed mode
2554 gbLcdTicks += GBLCD_MODE_2_CLOCK_TICKS;
2555 gbLcdMode = GBLCDM_OAM;
2556 if(!(register_STAT & 0x40) ||
2557 (register_LY != register_LYC)) {
2558 if((register_STAT & 0x28) == 0x20)
2559 register_IF |= 2;
2560 }
2561 break;
2562
2563 case GBLCDM_OAM:
2564 // OAM being accessed mode
2565
2566 // next mode is OAM and VRAM in use
2567 gbLcdTicks += GBLCD_MODE_3_CLOCK_TICKS;
2568 gbLcdMode = GBLCDM_OAM_VRAM;
2569 break;
2570
2571 case GBLCDM_OAM_VRAM:
2572 // OAM and VRAM in use
2573 // next mode is H-Blank
2574 if(register_LY < 144)
2575 {
2576 linedrawn[register_LY] = 1;
2577 gbRenderLine();
2578
2579 switch(espec->surface->format.bpp)
2580 {
2581 case 8:
2582 CopyLineSurface<uint8>(espec->surface);
2583 break;
2584
2585 case 16:
2586 CopyLineSurface<uint16>(espec->surface);
2587 break;
2588
2589 case 32:
2590 CopyLineSurface<uint32>(espec->surface);
2591 break;
2592 }
2593 MDFN_MidLineUpdate(espec, register_LY);
2594 }
2595 gbLcdMode = GBLCDM_HBLANK;
2596 // only one LCD interrupt per line. may need to generalize...
2597 if(!(register_STAT & 0x40) || (register_LY != register_LYC))
2598 {
2599 if(register_STAT & 0x08)
2600 register_IF |= 2;
2601 }
2602 if(gbHdmaOn)
2603 {
2604 gbDoHdma();
2605 //gbDmaTicks += GBLCD_MODE_0_CLOCK_TICKS - 4;
2606 }
2607
2608 gbLcdTicks += GBLCD_MODE_0_CLOCK_TICKS;
2609 break;
2610 }
2611 // mark the correct lcd mode on STAT register
2612 register_STAT = (register_STAT & 0xfc) | gbLcdMode;
2613 }
2614 }
2615
2616 // serial emulation
2617 if(gbSerialOn) {
2618 #ifdef LINK_EMULATION
2619 if(linkConnected) {
2620 gbSerialTicks -= clockTicks;
2621
2622 while(gbSerialTicks <= 0) {
2623 // increment number of shifted bits
2624 gbSerialBits++;
2625 linkProc();
2626 if(gbSerialOn && (register_SC & 1)) {
2627 if(gbSerialBits == 8) {
2628 gbSerialBits = 0;
2629 register_SB = 0xff;
2630 register_SC &= 0x7f;
2631 gbSerialOn = 0;
2632 register_IF |= 8;
2633 gbSerialTicks = 0;
2634 }
2635 }
2636 gbSerialTicks += GBSERIAL_CLOCK_TICKS;
2637 }
2638 } else {
2639 #endif
2640 if(register_SC & 1) {
2641 gbSerialTicks -= clockTicks;
2642
2643 // overflow
2644 while(gbSerialTicks <= 0) {
2645 // shift serial byte to right and put a 1 bit in its place
2646 // register_SB = 0x80 | (register_SB>>1);
2647 // increment number of shifted bits
2648 gbSerialBits++;
2649 if(gbSerialBits == 8) {
2650 // end of transmission
2651 if(gbSerialFunction) // external device
2652 register_SB = gbSerialFunction(register_SB);
2653 else
2654 register_SB = 0xff;
2655 gbSerialTicks = 0;
2656 register_SC &= 0x7f;
2657 gbSerialOn = 0;
2658 register_IF |= 8;
2659 gbSerialBits = 0;
2660 } else
2661 gbSerialTicks += GBSERIAL_CLOCK_TICKS;
2662 }
2663 }
2664 #ifdef LINK_EMULATION
2665 }
2666 #endif
2667 }
2668
2669 // timer emulation
2670 if(gbTimerOn) {
2671 gbTimerTicks -= clockTicks;
2672 while(gbTimerTicks <= 0) {
2673 ClockTIMA();
2674 gbTimerTicks += gbTimerClockTicks;
2675 }
2676 }
2677 }
2678
2679 //printf("%d %d\n", register_LY, SoundTS);
2680 for(int y = 0; y < 144; y++)
2681 {
2682 if(!linedrawn[y])
2683 {
2684 switch(espec->surface->format.bpp)
2685 {
2686 case 8:
2687 FillLineSurface<uint8>(espec->surface, y);
2688 break;
2689
2690 case 16:
2691 FillLineSurface<uint16>(espec->surface, y);
2692 break;
2693
2694 case 32:
2695 FillLineSurface<uint32>(espec->surface, y);
2696 break;
2697 }
2698 MDFN_MidLineUpdate(espec, y);
2699 }
2700 }
2701
2702 espec->MasterCycles = SoundTS;
2703
2704 espec->SoundBufSize = SOUND_Flush(SoundTS, espec->SoundBuf, espec->SoundBufMaxSize);
2705 SoundTS = 0;
2706 }
2707
StateAction(StateMem * sm,const unsigned load,const bool data_only)2708 static void StateAction(StateMem *sm, const unsigned load, const bool data_only)
2709 {
2710 SFORMAT RAMDesc[] =
2711 {
2712 SFPTR8N(gbOAM, 0xA0, "OAM"),
2713 SFPTR8N(HRAM, 0x80, "HRAM"),
2714 SFPTR8N(gbRam, gbRamSize, "RAM"),
2715 SFPTR8N(gbVram, gbCgbMode ? 0x4000 : 0x2000, "VRAM"),
2716 SFPTR8N(gbWram, gbCgbMode ? 0x8000 : 0x2000, "WRAM"),
2717 SFPTR16(gbPalette, (gbCgbMode ? 128 : 0)),
2718 SFEND
2719 };
2720
2721 MDFNSS_StateAction(sm, load, data_only, gbSaveGameStruct, "MAIN");
2722 MDFNSS_StateAction(sm, load, data_only, Joy_StateRegs, "JOY");
2723 MDFNSS_StateAction(sm, load, data_only, MBC1_StateRegs, "MBC1");
2724 MDFNSS_StateAction(sm, load, data_only, MBC2_StateRegs, "MBC2");
2725 MDFNSS_StateAction(sm, load, data_only, MBC3_StateRegs, "MBC3");
2726 MDFNSS_StateAction(sm, load, data_only, MBC5_StateRegs, "MBC5");
2727 MDFNSS_StateAction(sm, load, data_only, MBC7_StateRegs, "MBC7");
2728 MDFNSS_StateAction(sm, load, data_only, HuC1_StateRegs, "HuC1");
2729 MDFNSS_StateAction(sm, load, data_only, HuC3_StateRegs, "HuC3");
2730 MDFNSS_StateAction(sm, load, data_only, RAMDesc, "RAM");
2731
2732 GBZ80_StateAction(sm, load, data_only);
2733
2734 if(load)
2735 StateRest(load);
2736
2737 SOUND_StateAction(sm, load, data_only);
2738 }
2739
SetLayerEnableMask(uint64 mask)2740 static void SetLayerEnableMask(uint64 mask)
2741 {
2742 gblayerSettings = mask;
2743 }
2744
DoSimpleCommand(int cmd)2745 static void DoSimpleCommand(int cmd)
2746 {
2747 if(cmd == MDFN_MSC_POWER || cmd == MDFN_MSC_RESET)
2748 {
2749 gbPower();
2750 }
2751 }
2752
2753 static const MDFNSetting_EnumList SystemType_List[] =
2754 {
2755 { "auto", 0, gettext_noop("Auto"), gettext_noop("Automatic detection based on headers.") },
2756 { "dmg", 3, gettext_noop("DMG"), gettext_noop("Original GameBoy Monochrome.") },
2757 { "cgb", 1, gettext_noop("CGB"), gettext_noop("GameBoy Color.\n\nThis option is not fully implemented in regards to handling of DMG games.") },
2758 { "agb", 4, gettext_noop("AGB"), gettext_noop("GameBoy Advance.\n\nThis option is not fully implemented in regards to handling of DMG games.") },
2759 { NULL, 0 },
2760 };
2761
2762 static const MDFNSetting GBSettings[] =
2763 {
2764 { "gb.system_type", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Emulated GB type."), NULL, MDFNST_ENUM, "auto", NULL, NULL, NULL, NULL, SystemType_List },
2765 { NULL }
2766 };
2767
2768 static const IDIISG IDII =
2769 {
2770 IDIIS_ButtonCR("a", "A", /*VIRTB_1,*/ 7, NULL),
2771
2772 IDIIS_ButtonCR("b", "B", /*VIRTB_0,*/ 6, NULL),
2773
2774 IDIIS_Button("select", "SELECT", /*VIRTB_SELECT,*/ 4, NULL),
2775
2776 IDIIS_Button("start", "START", /*VIRTB_START,*/ 5, NULL),
2777
2778 IDIIS_Button("right", "RIGHT →", /*VIRTB_DP0_R,*/ 3, "left"),
2779
2780 IDIIS_Button("left", "LEFT ←", /*VIRTB_DP0_L,*/ 2, "right"),
2781
2782 IDIIS_Button("up", "UP ↑", /*VIRTB_DP0_U,*/ 0, "down"),
2783
2784 IDIIS_Button("down", "DOWN ↓", /*VIRTB_DP0_D,*/ 1, "up"),
2785 };
2786
2787 static const std::vector<InputDeviceInfoStruct> InputDeviceInfo =
2788 {
2789 {
2790 "gamepad",
2791 "Gamepad",
2792 NULL,
2793 IDII,
2794 }
2795 };
2796
2797 static const IDIISG Tilt_IDII =
2798 {
2799 IDIIS_Axis("", "", "right", "RIGHT →", "left", "LEFT ←", 1, true),
2800 IDIIS_Axis("", "", "down", "DOWN ↓", "up", "UP ↑", 0, true),
2801 };
2802
2803
2804 static const std::vector<InputDeviceInfoStruct> Tilt_InputDeviceInfo =
2805 {
2806 {
2807 "tilt",
2808 "Tilt",
2809 NULL,
2810 Tilt_IDII,
2811 }
2812 };
2813
2814 static const std::vector<InputPortInfoStruct> PortInfo =
2815 {
2816 { "builtin", "Built-In", InputDeviceInfo, "gamepad" },
2817 { "tilt", "Tilt", Tilt_InputDeviceInfo, "tilt" }
2818 };
2819
InstallReadPatch(uint32 address,uint8 value,int compare)2820 static void InstallReadPatch(uint32 address, uint8 value, int compare)
2821 {
2822
2823 }
2824
RemoveReadPatches(void)2825 static void RemoveReadPatches(void)
2826 {
2827
2828 }
2829
2830
2831 static const FileExtensionSpecStruct KnownExtensions[] =
2832 {
2833 { ".gb", 0, gettext_noop("GameBoy ROM Image") },
2834 { ".gbc", 0, gettext_noop("GameBoy Color ROM Image") },
2835 { ".cgb", 0, gettext_noop("GameBoy Color ROM Image") },
2836 { NULL, 0, NULL }
2837 };
2838
2839 static const CustomPalette_Spec CPInfo[] =
2840 {
2841 { gettext_noop("GameBoy(mono)"), NULL, { 4, 8, 12, 0 } },
2842 { gettext_noop("GameBoy Color 15-bit BGR"), "gbc", { 32768, 0 } },
2843 { NULL, NULL }
2844 };
2845
2846 static const CheatInfoStruct CheatInfo =
2847 {
2848 InstallReadPatch,
2849 RemoveReadPatches,
2850 NULL,
2851 NULL,
2852 CheatFormats_GB,
2853 };
2854
2855 }
2856
2857 using namespace MDFN_IEN_GB;
2858
2859 MDFNGI EmulatedGB =
2860 {
2861 "gb",
2862 "GameBoy (Color)",
2863 KnownExtensions,
2864 MODPRIO_INTERNAL_HIGH,
2865 NULL,
2866 PortInfo,
2867 NULL,
2868 Load,
2869 TestMagic,
2870 NULL,
2871 NULL,
2872 CloseGame,
2873
2874 SetLayerEnableMask,
2875 "Background\0Window\0Sprites\0",
2876
2877 NULL,
2878 NULL,
2879
2880 CPInfo,
2881 0,
2882
2883 CheatInfo,
2884
2885 false,
2886 StateAction,
2887 Emulate,
2888 NULL,
2889 MDFNGB_SetInput,
2890 NULL,
2891 DoSimpleCommand,
2892 NULL,
2893 GBSettings,
2894 MDFN_MASTERCLOCK_FIXED(4194304),
2895 (uint32)((double)4194304 / 70224 * 65536 * 256),
2896 false, // Multires possible?
2897
2898 160, // lcm_width
2899 144, // lcm_height
2900 NULL, // Dummy
2901
2902 160, // Nominal width
2903 144, // Nominal height
2904
2905 160, // Framebuffer width
2906 144, // Framebuffer height
2907
2908 2, // Number of output sound channels
2909 };
2910