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