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