1 /* Mednafen - Multi-system Emulator
2  *
3  * Copyright notice for this file:
4  *  Copyright (C) 2002 Xodnizel
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 
21 #include "nes.h"
22 #include "ppu/ppu.h"
23 #include "cart.h"
24 #include "x6502.h"
25 
26 #include <mednafen/mempatcher.h>
27 #include <mednafen/FileStream.h>
28 
29 /*
30    This file contains all code for coordinating the mapping in of the
31    address space external to the NES.
32    It's also (ab)used by the NSF code.
33 */
34 namespace MDFN_IEN_NES
35 {
36 uint8 *Page[32],*VPage[8];
37 uint8 **VPageR=VPage;
38 static uint8 *VPageG[8];
39 uint8 *MMC5SPRVPage[8];
40 uint8 *MMC5BGVPage[8];
41 
42 static uint8 PRGIsRAM[32];	/* This page is/is not PRG RAM. */
43 
44 /* 16 are (sort of) reserved for UNIF/iNES and 16 to map other stuff. */
45 static int CHRram[32];
46 static int PRGram[32];
47 
48 uint8 *PRGptr[32];
49 uint8 *CHRptr[32];
50 
51 uint32 PRGsize[32];
52 uint32 CHRsize[32];
53 
54 uint32 PRGmask2[32];
55 uint32 PRGmask4[32];
56 uint32 PRGmask8[32];
57 uint32 PRGmask16[32];
58 uint32 PRGmask32[32];
59 
60 uint32 CHRmask1[32];
61 uint32 CHRmask2[32];
62 uint32 CHRmask4[32];
63 uint32 CHRmask8[32];
64 
65 //
66 //
67 //
68 //
69 
70 /*
71 enum
72 {
73  GENIESTAGE_UNUSED = 0,
74  GENIESTAGE_ENTRY = 1,
75  GENIESTAGE_GAME = 2
76 };
77 */
78 
79 uint8 geniestage = 0;
80 static uint8 modcon;
81 static std::array<uint8, 3> genieval;
82 static std::array<uint8, 3> geniech;
83 static std::array<uint16, 3> genieaddr;
84 
85 static DECLFR(GenieFix1);
86 static DECLFR(GenieFix2);
87 static DECLFR(GenieFix3);
88 static readfunc const GenieFix[3] = { GenieFix1, GenieFix2, GenieFix3 };
89 
90 //
91 //
92 //
93 //
94 
setpageptr(int s,uint32 A,uint8 * p,int ram)95 static INLINE void setpageptr(int s, uint32 A, uint8 *p, int ram)
96 {
97  uint32 AB=A>>11;
98  int x;
99 
100  if(p)
101   for(x=(s>>1)-1;x>=0;x--)
102   {
103    PRGIsRAM[AB+x]=ram;
104    Page[AB+x]=p-A;
105   }
106  else
107   for(x=(s>>1)-1;x>=0;x--)
108   {
109    PRGIsRAM[AB+x]=0;
110    Page[AB+x]=0;
111   }
112 }
113 
114 static uint8 nothing[8192];
115 
GetCartPagePtr(uint16 A)116 uint8 *GetCartPagePtr(uint16 A)
117 {
118  int n = A >> 11;
119 
120  if(Page[n] == (nothing - (n << 11)))
121  {
122   return(0);
123  }
124  else
125   return(Page[n]);
126 }
127 
ResetCartMapping(void)128 void ResetCartMapping(void)
129 {
130  int x;
131 
132  for(x=0;x<32;x++)
133  {
134   Page[x]=nothing-x*2048;
135   PRGptr[x]=CHRptr[x]=0;
136   PRGsize[x]=CHRsize[x]=0;
137  }
138  for(x=0;x<8;x++)
139  {
140   MMC5SPRVPage[x]=MMC5BGVPage[x]=VPageR[x]=nothing-0x400*x;
141  }
142 
143 }
144 
SetupCartPRGMapping(int chip,uint8 * p,uint32 size,int ram)145 void SetupCartPRGMapping(int chip, uint8 *p, uint32 size, int ram)
146 {
147  PRGptr[chip]=p;
148  PRGsize[chip]=size;
149 
150  PRGmask2[chip]=(size>>11)-1;
151  PRGmask4[chip]=(size>>12)-1;
152  PRGmask8[chip]=(size>>13)-1;
153  PRGmask16[chip]=(size>>14)-1;
154  PRGmask32[chip]=(size>>15)-1;
155 
156  PRGram[chip]=ram?1:0;
157 }
158 
SetupCartCHRMapping(int chip,uint8 * p,uint32 size,int ram)159 void SetupCartCHRMapping(int chip, uint8 *p, uint32 size, int ram)
160 {
161  CHRptr[chip]=p;
162  CHRsize[chip]=size;
163 
164  CHRmask1[chip]=(size>>10)-1;
165  CHRmask2[chip]=(size>>11)-1;
166  CHRmask4[chip]=(size>>12)-1;
167  CHRmask8[chip]=(size>>13)-1;
168 
169  CHRram[chip]=ram;
170 }
171 
DECLFR(CartBR)172 DECLFR(CartBR)
173 {
174  return Page[A>>11][A];
175 }
176 
DECLFW(CartBW)177 DECLFW(CartBW)
178 {
179  //printf("Ok: %04x:%02x, %d\n",A,V,PRGIsRAM[A>>11]);
180  if(PRGIsRAM[A>>11] && Page[A>>11])
181   Page[A>>11][A]=V;
182 }
183 
DECLFR(CartBROB)184 DECLFR(CartBROB)
185 {
186  if(!Page[A>>11]) return(X.DB);
187  return Page[A>>11][A];
188 }
189 
setprg2r(int r,unsigned int A,unsigned int V)190 void setprg2r(int r, unsigned int A, unsigned int V)
191 {
192   V&=PRGmask2[r];
193 
194   setpageptr(2,A,PRGptr[r]?(&PRGptr[r][V<<11]):0,PRGram[r]);
195 }
196 
setprg2(uint32 A,uint32 V)197 void setprg2(uint32 A, uint32 V)
198 {
199  setprg2r(0,A,V);
200 }
201 
setprg4r(int r,unsigned int A,unsigned int V)202 void setprg4r(int r, unsigned int A, unsigned int V)
203 {
204   V&=PRGmask4[r];
205   setpageptr(4,A,PRGptr[r]?(&PRGptr[r][V<<12]):0,PRGram[r]);
206 }
207 
setprg4(uint32 A,uint32 V)208 void setprg4(uint32 A, uint32 V)
209 {
210  setprg4r(0,A,V);
211 }
212 
setprg8r(int r,unsigned int A,unsigned int V)213 void setprg8r(int r, unsigned int A, unsigned int V)
214 {
215   if(PRGsize[r]>=8192)
216   {
217    V&=PRGmask8[r];
218    setpageptr(8,A,PRGptr[r]?(&PRGptr[r][V<<13]):0,PRGram[r]);
219   }
220   else
221   {
222    uint32 VA=V<<2;
223    int x;
224    for(x=0;x<4;x++)
225     setpageptr(2,A+(x<<11),PRGptr[r]?(&PRGptr[r][((VA+x)&PRGmask2[r])<<11]):0,PRGram[r]);
226   }
227 }
228 
setprg8(uint32 A,uint32 V)229 void setprg8(uint32 A, uint32 V)
230 {
231  setprg8r(0,A,V);
232 }
233 
setprg16r(int r,unsigned int A,unsigned int V)234 void setprg16r(int r, unsigned int A, unsigned int V)
235 {
236   if(PRGsize[r]>=16384)
237   {
238    V&=PRGmask16[r];
239    setpageptr(16,A,PRGptr[r]?(&PRGptr[r][V<<14]):0,PRGram[r]);
240   }
241   else
242   {
243    uint32 VA=V<<3;
244    int x;
245 
246    for(x=0;x<8;x++)
247     setpageptr(2,A+(x<<11),PRGptr[r]?(&PRGptr[r][((VA+x)&PRGmask2[r])<<11]):0,PRGram[r]);
248   }
249 }
250 
setprg16(uint32 A,uint32 V)251 void setprg16(uint32 A, uint32 V)
252 {
253  setprg16r(0,A,V);
254 }
255 
setprg32r(int r,unsigned int A,unsigned int V)256 void setprg32r(int r,unsigned int A, unsigned int V)
257 {
258   if(PRGsize[r]>=32768)
259   {
260    V&=PRGmask32[r];
261    setpageptr(32,A,PRGptr[r]?(&PRGptr[r][V<<15]):0,PRGram[r]);
262   }
263   else
264   {
265    uint32 VA=V<<4;
266    int x;
267 
268    for(x=0;x<16;x++)
269     setpageptr(2,A+(x<<11),PRGptr[r]?(&PRGptr[r][((VA+x)&PRGmask2[r])<<11]):0,PRGram[r]);
270   }
271 }
272 
setprg32(uint32 A,uint32 V)273 void setprg32(uint32 A, uint32 V)
274 {
275  setprg32r(0,A,V);
276 }
277 
setchr1r(int r,unsigned int A,unsigned int V)278 void setchr1r(int r, unsigned int A, unsigned int V)
279 {
280   if(!CHRptr[r]) return;
281   MDFNPPU_LineUpdate();
282   V&=CHRmask1[r];
283   if(CHRram[r])
284    PPUCHRRAM|=(1<<(A>>10));
285   else
286    PPUCHRRAM&=~(1<<(A>>10));
287   VPageR[(A)>>10]=&CHRptr[r][(V)<<10]-(A);
288 }
289 
setchr2r(int r,unsigned int A,unsigned int V)290 void setchr2r(int r, unsigned int A, unsigned int V)
291 {
292   if(!CHRptr[r]) return;
293   MDFNPPU_LineUpdate();
294   V&=CHRmask2[r];
295   VPageR[(A)>>10]=VPageR[((A)>>10)+1]=&CHRptr[r][(V)<<11]-(A);
296   if(CHRram[r])
297    PPUCHRRAM|=(3<<(A>>10));
298   else
299    PPUCHRRAM&=~(3<<(A>>10));
300 }
301 
setchr4r(int r,unsigned int A,unsigned int V)302 void setchr4r(int r, unsigned int A, unsigned int V)
303 {
304   if(!CHRptr[r]) return;
305   MDFNPPU_LineUpdate();
306   V&=CHRmask4[r];
307   VPageR[(A)>>10]=VPageR[((A)>>10)+1]=
308   VPageR[((A)>>10)+2]=VPageR[((A)>>10)+3]=&CHRptr[r][(V)<<12]-(A);
309 
310   if(CHRram[r])
311    PPUCHRRAM |= (15<<(A>>10));
312   else
313    PPUCHRRAM&=~(15<<(A>>10));
314 }
315 
setchr8r(int r,unsigned int V)316 void setchr8r(int r, unsigned int V)
317 {
318   int x;
319 
320   if(!CHRptr[r]) return;
321   MDFNPPU_LineUpdate();
322   V&=CHRmask8[r];
323   for(x=7;x>=0;x--)
324    VPageR[x]=&CHRptr[r][V<<13];
325 
326   if(CHRram[r])
327    PPUCHRRAM = 0xFF;
328   else
329    PPUCHRRAM = 0;
330 }
331 
setchr1(unsigned int A,unsigned int V)332 void setchr1(unsigned int A, unsigned int V)
333 {
334  setchr1r(0,A,V);
335 }
336 
setchr2(unsigned int A,unsigned int V)337 void setchr2(unsigned int A, unsigned int V)
338 {
339  setchr2r(0,A,V);
340 }
341 
setchr4(unsigned int A,unsigned int V)342 void setchr4(unsigned int A, unsigned int V)
343 {
344  setchr4r(0,A,V);
345 }
346 
setchr8(unsigned int V)347 void setchr8(unsigned int V)
348 {
349  setchr8r(0,V);
350 }
351 
setvram8(uint8 * p)352 void setvram8(uint8 *p)
353 {
354   int x;
355 
356   MDFNPPU_LineUpdate();
357 
358   for(x=7;x>=0;x--)
359    VPageR[x]=p;
360   PPUCHRRAM|=255;
361 }
362 
setvram4(uint32 A,uint8 * p)363 void setvram4(uint32 A, uint8 *p)
364 {
365   int x;
366 
367   MDFNPPU_LineUpdate();
368 
369   for(x=3;x>=0;x--)
370    VPageR[(A>>10)+x]=p-A;
371   PPUCHRRAM|=(15<<(A>>10));
372 }
373 
setvramb1(uint8 * p,uint32 A,uint32 b)374 void setvramb1(uint8 *p, uint32 A, uint32 b)
375 {
376   MDFNPPU_LineUpdate();
377   VPageR[A>>10]=p-A+(b<<10);
378   PPUCHRRAM|=(1<<(A>>10));
379 }
380 
setvramb2(uint8 * p,uint32 A,uint32 b)381 void setvramb2(uint8 *p, uint32 A, uint32 b)
382 {
383   MDFNPPU_LineUpdate();
384   VPageR[(A>>10)]=VPageR[(A>>10)+1]=p-A+(b<<11);
385   PPUCHRRAM|=(3<<(A>>10));
386 }
387 
setvramb4(uint8 * p,uint32 A,uint32 b)388 void setvramb4(uint8 *p, uint32 A, uint32 b)
389 {
390   int x;
391 
392   MDFNPPU_LineUpdate();
393   for(x=3;x>=0;x--)
394    VPageR[(A>>10)+x]=p-A+(b<<12);
395   PPUCHRRAM|=(15<<(A>>10));
396 }
397 
setvramb8(uint8 * p,uint32 b)398 void setvramb8(uint8 *p, uint32 b)
399 {
400   int x;
401 
402   MDFNPPU_LineUpdate();
403   for(x=7;x>=0;x--)
404    VPageR[x]=p+(b<<13);
405   PPUCHRRAM|=255;
406 }
407 
408 /* This function can be called without calling SetupCartMirroring(). */
409 
setntamem(uint8 * p,int ram,uint32 b)410 void setntamem(uint8 *p, int ram, uint32 b)
411 {
412  MDFNPPU_LineUpdate();
413  vnapage[b]=p;
414  PPUNTARAM&=~(1<<b);
415  if(ram)
416   PPUNTARAM|=1<<b;
417 }
418 
419 static bool mirrorhard = false;
420 
setmirrorw(int a,int b,int c,int d)421 void setmirrorw(int a, int b, int c, int d)
422 {
423  MDFNPPU_LineUpdate();
424  vnapage[0]=NTARAM+a*0x400;
425  vnapage[1]=NTARAM+b*0x400;
426  vnapage[2]=NTARAM+c*0x400;
427  vnapage[3]=NTARAM+d*0x400;
428 }
429 
setmirror(int t)430 void setmirror(int t)
431 {
432   MDFNPPU_LineUpdate();
433   if(!mirrorhard)
434   {
435    switch(t)
436    {
437     case MI_H:
438      vnapage[0]=vnapage[1]=NTARAM;vnapage[2]=vnapage[3]=NTARAM+0x400;
439      break;
440     case MI_V:
441      vnapage[0]=vnapage[2]=NTARAM;vnapage[1]=vnapage[3]=NTARAM+0x400;
442      break;
443     case MI_0:
444      vnapage[0]=vnapage[1]=vnapage[2]=vnapage[3]=NTARAM;
445      break;
446     case MI_1:
447      vnapage[0]=vnapage[1]=vnapage[2]=vnapage[3]=NTARAM+0x400;
448      break;
449    }
450   PPUNTARAM=0xF;
451  }
452 }
453 
SetupCartMirroring(int m,int hard,uint8 * extra)454 void SetupCartMirroring(int m, int hard, uint8 *extra)
455 {
456  if(m < 4)
457  {
458   mirrorhard = false;
459   setmirror(m);
460  }
461  else
462  {
463   vnapage[0]=NTARAM;
464   vnapage[1]=NTARAM+0x400;
465   vnapage[2]=extra;
466   vnapage[3]=extra+0x400;
467   PPUNTARAM=0xF;
468  }
469  mirrorhard = hard;
470 }
471 
CartHasHardMirroring(void)472 bool CartHasHardMirroring(void)
473 {
474  return(mirrorhard);
475 }
476 
477 static uint8 *GENIEROM = NULL;
478 static readfunc GenieBackup[3] = { NULL, NULL, NULL };
479 static void FixGenieMap(void);
480 
481 static DECLFW(GenieWrite);
482 static DECLFR(GenieRead);
483 static bool GenieBIOSHooksInstalled = false;
484 static readfunc *AReadGG = NULL;
485 static writefunc *BWriteGG = NULL;
486 
Genie_BIOSInstalled(void)487 bool Genie_BIOSInstalled(void)
488 {
489  return(GenieBIOSHooksInstalled);
490 }
491 
InstallGenieBIOSHooks(void)492 static void InstallGenieBIOSHooks(void)
493 {
494  if(GenieBIOSHooksInstalled)
495   return;
496 
497  for(int i = 0; i < 0x8000; i++)
498  {
499   //assert(AReadGG[i] == NULL);
500   //assert(BWriteGG[i] == NULL);
501 
502   AReadGG[i] = GetReadHandler(i + 0x8000);
503   BWriteGG[i] = GetWriteHandler(i + 0x8000);
504  }
505 
506  SetWriteHandler(0x8000, 0xFFFF, GenieWrite);
507  SetReadHandler(0x8000, 0xFFFF, GenieRead);
508 
509  for(int x = 0; x < 8; x++)
510   VPage[x]=GENIEROM+4096-0x400*x;
511 
512  VPageR = VPageG;
513 
514  GenieBIOSHooksInstalled = true;
515 }
516 
RemoveGenieBIOSHooks(void)517 static void RemoveGenieBIOSHooks(void)
518 {
519  if(!GenieBIOSHooksInstalled)
520   return;
521 
522  for(int x = 0; x < 8; x++)
523   VPage[x] = VPageG[x];
524 
525  VPageR = VPage;
526 
527  for(int i = 0; i < 0x8000; i++)
528  {
529   //assert(GetReadHandler(i + 0x8000) == GenieRead);
530   //assert(GetWriteHandler(i + 0x8000) == GenieWrite);
531 
532   SetReadHandler(i + 0x8000, i + 0x8000, AReadGG[i]);
533   SetWriteHandler(i + 0x8000, i + 0x8000, BWriteGG[i]);
534 
535   AReadGG[i] = NULL;
536   BWriteGG[i] = NULL;
537  }
538 
539  GenieBIOSHooksInstalled = false;
540 }
541 
InstallGenieReadPatches(void)542 static void InstallGenieReadPatches(void)
543 {
544  for(int x = 0; x <= 2; x++)
545  {
546   if((modcon >> (4 + x)) & 1)
547   {
548    //assert(!GenieBackup[x]);
549 
550    GenieBackup[x] = GetReadHandler(genieaddr[x]);
551    SetReadHandler(genieaddr[x], genieaddr[x], GenieFix[x]);
552   }
553  }
554 }
555 
RemoveGenieReadPatches(void)556 static void RemoveGenieReadPatches(void)
557 {
558  // Remove in reverse order to install in case addrs are the same(corrupted save states could trigger this possibly).
559  for(int x = 2; x >= 0; x--)
560  {
561   if(GenieBackup[x])
562   {
563    SetReadHandler(genieaddr[x], genieaddr[x], GenieBackup[x]);
564    GenieBackup[x] = NULL;
565   }
566  }
567 }
568 
569 /* Called when a game(file) is opened successfully. */
Genie_Init(void)570 void Genie_Init(void)
571 {
572  try
573  {
574   if(!GENIEROM)
575   {
576    GENIEROM = new uint8[4096 + 1024];
577 
578    std::string fn = MDFN_MakeFName(MDFNMKF_FIRMWARE, 0, MDFN_GetSettingS("nes.ggrom"));
579    static const std::vector<FileExtensionSpecStruct> KnownExtensions
580    {
581     { ".nes", 0, "iNES Format ROM Image" },
582    };
583    MDFNFILE fp(&NVFS, fn.c_str(), KnownExtensions, _("Game Genie ROM Image"));
584 
585    fp.read(GENIEROM, 16);
586 
587    if(!memcmp(GENIEROM, "NES\x1A", 4))	/* iNES ROM image */
588    {
589     fp.read(GENIEROM, 4096);
590     fp.seek(16384 - 4096, SEEK_CUR);
591     fp.read(GENIEROM + 4096, 256);
592    }
593    else
594    {
595     fp.read(GENIEROM + 16, 4352-16);
596    }
597    fp.Close();
598 
599    /* Workaround for the Mednafen CHR page size only being 1KB */
600    for(int x = 0; x < 4; x++)
601     memcpy(GENIEROM + 4096 + (x<<8), GENIEROM + 4096, 256);
602   }
603 
604   AReadGG = new readfunc[32768]; // Game Genie Read Map Backup
605   BWriteGG = new writefunc[32768]; // Game Genie Write Map Backup
606 
607   for(unsigned i = 0; i < 32768; i++)
608   {
609    AReadGG[i] = NULL;
610    BWriteGG[i] = NULL;
611   }
612 
613   GenieBIOSHooksInstalled = false;
614 
615   for(int x = 0; x < 3; x++)
616   {
617    GenieBackup[x] = NULL;
618 
619    genieval[x] = 0xFF;
620    geniech[x] = 0xFF;
621    genieaddr[x] = 0xFFFF;
622   }
623 
624   geniestage=1;
625  }
626  catch(...)
627  {
628   if(GENIEROM)
629   {
630    delete[] GENIEROM;
631    GENIEROM = NULL;
632   }
633 
634   if(AReadGG)
635   {
636    delete[] AReadGG;
637    AReadGG = NULL;
638   }
639 
640   if(BWriteGG)
641   {
642    delete[] BWriteGG;
643    BWriteGG = NULL;
644   }
645 
646   throw;
647  }
648 }
649 
Genie_Kill(void)650 void Genie_Kill(void)
651 {
652  geniestage = 0;
653  //FlushGenieRW();
654  VPageR = VPage;
655 
656  if(GENIEROM)
657  {
658   delete[] GENIEROM;
659   GENIEROM = NULL;
660  }
661 
662  if(AReadGG)
663  {
664   delete[] AReadGG;
665   AReadGG = NULL;
666  }
667 
668  if(BWriteGG)
669  {
670   delete[] BWriteGG;
671   BWriteGG = NULL;
672  }
673 
674  memset(&GenieBackup, 0, sizeof(GenieBackup));
675 }
676 
DECLFR(GenieRead)677 static DECLFR(GenieRead)
678 {
679  return GENIEROM[A&4095];
680 }
681 
DECLFW(GenieWrite)682 static DECLFW(GenieWrite)
683 {
684  switch(A)
685  {
686   case 0x800c:
687   case 0x8008:
688   case 0x8004:
689 	      genieval[((A-4)&0xF)>>2]=V;
690 	      break;
691 
692   case 0x800b:
693   case 0x8007:
694   case 0x8003:
695 	      geniech[((A-3)&0xF)>>2]=V;
696 	      break;
697 
698   case 0x800a:
699   case 0x8006:
700   case 0x8002:genieaddr[((A-2)&0xF)>>2] &= 0xFF00;
701 	      genieaddr[((A-2)&0xF)>>2] |= V;
702 	      break;
703 
704   case 0x8009:
705   case 0x8005:
706   case 0x8001:genieaddr[((A-1)&0xF)>>2] &= 0x00FF;
707 	      genieaddr[((A-1)&0xF)>>2] |= (V | 0x80) << 8;
708 	      break;
709 
710   case 0x8000:if(!V)
711                FixGenieMap();
712               else
713               {
714                modcon = V ^ 0xFF;
715                if(V == 0x71)
716 		modcon=0;
717               }
718               break;
719  }
720 }
721 
722 
DECLFR(GenieFix1)723 static DECLFR(GenieFix1)
724 {
725  uint8 r=GenieBackup[0](A);
726 
727  if((modcon>>1)&1)		// No check
728   return genieval[0];
729  else if(r==geniech[0])
730   return genieval[0];
731 
732  return r;
733 }
734 
DECLFR(GenieFix2)735 static DECLFR(GenieFix2)
736 {
737  uint8 r=GenieBackup[1](A);
738 
739  if((modcon>>2)&1)              // No check
740   return genieval[1];
741  else if(r==geniech[1])
742   return genieval[1];
743 
744  return r;
745 }
746 
DECLFR(GenieFix3)747 static DECLFR(GenieFix3)
748 {
749  uint8 r=GenieBackup[2](A);
750 
751  if((modcon>>3)&1)              // No check
752   return genieval[2];
753  else if(r==geniech[2])
754   return genieval[2];
755 
756  return r;
757 }
758 
FixGenieMap(void)759 static void FixGenieMap(void)
760 {
761  geniestage = 2;
762 
763  if(!GenieBIOSHooksInstalled)
764   return;
765 
766  RemoveGenieBIOSHooks();
767 
768  InstallGenieReadPatches();
769 
770  // Call this last, after GenieBIOSHooksInstalled = false and our read cheat hooks are installed.  Yay spaghetti code.
771  MDFNMP_InstallReadPatches();
772 }
773 
Genie_Power(void)774 void Genie_Power(void)
775 {
776  if(!geniestage)
777   return;
778 
779  RemoveGenieReadPatches();
780 
781  for(unsigned x = 0; x < 3; x++)
782  {
783   genieval[x] = 0xFF;
784   geniech[x] = 0xFF;
785   genieaddr[x] = 0xFFFF;
786  }
787 
788  geniestage = 1;
789  modcon = 0;
790 
791  if(!GenieBIOSHooksInstalled)
792   InstallGenieBIOSHooks();
793 }
794 
Genie_StateAction(StateMem * sm,const unsigned load,const bool data_only)795 void Genie_StateAction(StateMem *sm, const unsigned load, const bool data_only)
796 {
797  auto tmp_modcon = modcon;
798  auto tmp_geniestage = geniestage;
799  auto tmp_genieval = genieval;
800  auto tmp_geniech = geniech;
801  auto tmp_genieaddr = genieaddr;
802 
803  SFORMAT StateRegs[] =
804  {
805   SFVAR(tmp_geniestage),
806   SFVAR(tmp_modcon),
807 
808   SFPTR8(tmp_genieval.data(), tmp_genieval.size()),
809   SFPTR8(tmp_geniech.data(), tmp_geniech.size()),
810   SFPTR16(tmp_genieaddr.data(), tmp_genieaddr.size()),
811 
812   SFEND
813  };
814 
815  bool lsv = MDFNSS_StateAction(sm, load, data_only, StateRegs, "GENIE", load < 0x937);
816 
817  if(load)
818  {
819   if(!lsv || !GENIEROM)
820   {
821    if(lsv && tmp_geniestage == 1)
822     throw MDFN_Error(0, _("State saved in Game Genie screen, but GG emulation is currently disabled!"));
823 
824    tmp_geniestage = (GENIEROM ? 2 : 0);
825    tmp_modcon = 0;
826 
827    for(unsigned x = 0; x < 3; x++)
828    {
829     tmp_genieval[x] = 0xFF;
830     tmp_geniech[x] = 0xFF;
831     tmp_genieaddr[x] = 0xFFFF;
832    }
833   }
834 
835   for(unsigned x = 0; x < 3; x++)
836    tmp_genieaddr[x] |= 0x8000;
837 
838   MDFNMP_RemoveReadPatches();
839   RemoveGenieReadPatches();
840   RemoveGenieBIOSHooks();
841 
842   modcon = tmp_modcon;
843   geniestage = tmp_geniestage;
844   genieval = tmp_genieval;
845   geniech = tmp_geniech;
846   genieaddr = tmp_genieaddr;
847 
848   switch(geniestage)
849   {
850    default:
851 	geniestage = 0;
852 	MDFNMP_InstallReadPatches();
853 	break;
854 
855    case 1:
856 	InstallGenieBIOSHooks();
857 	break;
858 
859    case 2:
860 	InstallGenieReadPatches();
861 	MDFNMP_InstallReadPatches();
862 	break;
863   }
864  }
865 }
866 
MDFN_SaveGameSave(CartInfo * LocalHWInfo)867 void MDFN_SaveGameSave(CartInfo *LocalHWInfo)
868 {
869  if(LocalHWInfo->battery && LocalHWInfo->SaveGame[0])
870  {
871   try
872   {
873    FileStream sp(MDFN_MakeFName(MDFNMKF_SAV, 0, "sav"), FileStream::MODE_WRITE_INPLACE);
874 
875    for(unsigned x = 0; x < 4; x++)
876     if(LocalHWInfo->SaveGame[x])
877      sp.write(LocalHWInfo->SaveGame[x], LocalHWInfo->SaveGameLen[x]);
878 
879    sp.close();
880   }
881   catch(std::exception &e)
882   {
883    throw MDFN_Error(0, _("Error saving save game file: %s\n"), e.what());
884   }
885  }
886 }
887 
MDFN_LoadGameSave(CartInfo * LocalHWInfo)888 void MDFN_LoadGameSave(CartInfo *LocalHWInfo)
889 {
890  if(LocalHWInfo->battery && LocalHWInfo->SaveGame[0])
891  {
892   try
893   {
894    FileStream sp(MDFN_MakeFName(MDFNMKF_SAV, 0, "sav"), FileStream::MODE_READ);
895 
896    for(unsigned x = 0; x < 4; x++)
897     if(LocalHWInfo->SaveGame[x])
898      sp.read(LocalHWInfo->SaveGame[x], LocalHWInfo->SaveGameLen[x]);
899   }
900   catch(MDFN_Error &e)
901   {
902    if(e.GetErrno() != ENOENT)
903     throw MDFN_Error(0, _("Error loading save game file: %s\n"), e.what());
904   }
905   catch(std::exception &e)
906   {
907    throw MDFN_Error(0, _("Error loading save game file: %s\n"), e.what());
908   }
909  }
910 }
911 
912 }
913