1 /* FCE Ultra - NES/Famicom Emulator
3 * Copyright notice for this file:
4 * Copyright (C) 2002 Xodnizel
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.
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.
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
26 #include <unistd.h> // for sync()
42 #define FCEUPPU_LineUpdate(...)
45 This file contains all code for coordinating the mapping in of the
46 address space external to the NES.
47 It's also (ab)used by the NSF code.
50 uint8 *Page[32],*VPage[8];
53 uint8 *MMC5SPRVPage[8];
54 uint8 *MMC5BGVPage[8];
56 static uint8 PRGIsRAM[32]; /* This page is/is not PRG RAM. */
58 /* 16 are (sort of) reserved for UNIF/iNES and 16 to map other stuff. */
59 static int CHRram[32];
60 static int PRGram[32];
88 static INLINE void setpageptr(int s, uint32 A, uint8 *p, int ram)
94 for(x=(s>>1)-1;x>=0;x--)
100 for(x=(s>>1)-1;x>=0;x--)
107 static uint8 nothing[8192];
108 void ResetCartMapping(void)
114 Page[x]=nothing-x*2048;
115 PRGptr[x]=CHRptr[x]=0;
116 PRGsize[x]=CHRsize[x]=0;
120 MMC5SPRVPage[x]=MMC5BGVPage[x]=VPageR[x]=nothing-0x400*x;
125 void SetupCartPRGMapping(int chip, uint8 *p, uint32 size, int ram)
130 PRGmask2[chip]=(size>>11)-1;
131 PRGmask4[chip]=(size>>12)-1;
132 PRGmask8[chip]=(size>>13)-1;
133 PRGmask16[chip]=(size>>14)-1;
134 PRGmask32[chip]=(size>>15)-1;
136 PRGram[chip]=ram?1:0;
139 void SetupCartCHRMapping(int chip, uint8 *p, uint32 size, int ram)
144 CHRmask1[chip]=(size>>10)-1;
145 CHRmask2[chip]=(size>>11)-1;
146 CHRmask4[chip]=(size>>12)-1;
147 CHRmask8[chip]=(size>>13)-1;
154 return Page[A>>11][A];
159 //printf("Ok: %04x:%02x, %d\n",A,V,PRGIsRAM[A>>11]);
160 if(PRGIsRAM[A>>11] && Page[A>>11])
166 if(!Page[A>>11]) return(X.DB);
167 return Page[A>>11][A];
170 void FASTAPASS(3) setprg2r(int r, unsigned int A, unsigned int V)
173 setpageptr(2,A,PRGptr[r]?(&PRGptr[r][V<<11]):0,PRGram[r]);
177 void FASTAPASS(2) setprg2(uint32 A, uint32 V)
182 void FASTAPASS(3) setprg4r(int r, unsigned int A, unsigned int V)
185 setpageptr(4,A,PRGptr[r]?(&PRGptr[r][V<<12]):0,PRGram[r]);
189 void FASTAPASS(2) setprg4(uint32 A, uint32 V)
194 void FASTAPASS(3) setprg8r(int r, unsigned int A, unsigned int V)
199 setpageptr(8,A,PRGptr[r]?(&PRGptr[r][V<<13]):0,PRGram[r]);
206 setpageptr(2,A+(x<<11),PRGptr[r]?(&PRGptr[r][((VA+x)&PRGmask2[r])<<11]):0,PRGram[r]);
211 void FASTAPASS(2) setprg8(uint32 A, uint32 V)
216 void FASTAPASS(3) setprg16r(int r, unsigned int A, unsigned int V)
218 if(PRGsize[r]>=16384)
221 setpageptr(16,A,PRGptr[r]?(&PRGptr[r][V<<14]):0,PRGram[r]);
229 setpageptr(2,A+(x<<11),PRGptr[r]?(&PRGptr[r][((VA+x)&PRGmask2[r])<<11]):0,PRGram[r]);
234 void FASTAPASS(2) setprg16(uint32 A, uint32 V)
239 void FASTAPASS(3) setprg32r(int r,unsigned int A, unsigned int V)
241 if(PRGsize[r]>=32768)
244 setpageptr(32,A,PRGptr[r]?(&PRGptr[r][V<<15]):0,PRGram[r]);
252 setpageptr(2,A+(x<<11),PRGptr[r]?(&PRGptr[r][((VA+x)&PRGmask2[r])<<11]):0,PRGram[r]);
257 void FASTAPASS(2) setprg32(uint32 A, uint32 V)
262 void FASTAPASS(3) setchr1r(int r, unsigned int A, unsigned int V)
264 if(!CHRptr[r]) return;
265 FCEUPPU_LineUpdate();
268 PPUCHRRAM|=(1<<(A>>10));
270 PPUCHRRAM&=~(1<<(A>>10));
271 VPageR[(A)>>10]=&CHRptr[r][(V)<<10]-(A);
274 void FASTAPASS(3) setchr2r(int r, unsigned int A, unsigned int V)
276 if(!CHRptr[r]) return;
277 FCEUPPU_LineUpdate();
279 VPageR[(A)>>10]=VPageR[((A)>>10)+1]=&CHRptr[r][(V)<<11]-(A);
281 PPUCHRRAM|=(3<<(A>>10));
283 PPUCHRRAM&=~(3<<(A>>10));
286 void FASTAPASS(3) setchr4r(int r, unsigned int A, unsigned int V)
288 if(!CHRptr[r]) return;
289 FCEUPPU_LineUpdate();
291 VPageR[(A)>>10]=VPageR[((A)>>10)+1]=
292 VPageR[((A)>>10)+2]=VPageR[((A)>>10)+3]=&CHRptr[r][(V)<<12]-(A);
294 PPUCHRRAM|=(15<<(A>>10));
296 PPUCHRRAM&=~(15<<(A>>10));
299 void FASTAPASS(2) setchr8r(int r, unsigned int V)
303 if(!CHRptr[r]) return;
304 FCEUPPU_LineUpdate();
307 VPageR[x]=&CHRptr[r][V<<13];
314 void FASTAPASS(2) setchr1(unsigned int A, unsigned int V)
319 void FASTAPASS(2) setchr2(unsigned int A, unsigned int V)
324 void FASTAPASS(2) setchr4(unsigned int A, unsigned int V)
329 void FASTAPASS(1) setchr8(unsigned int V)
334 void FASTAPASS(1) setvram8(uint8 *p)
342 void FASTAPASS(2) setvram4(uint32 A, uint8 *p)
346 VPageR[(A>>10)+x]=p-A;
347 PPUCHRRAM|=(15<<(A>>10));
350 void FASTAPASS(3) setvramb1(uint8 *p, uint32 A, uint32 b)
352 FCEUPPU_LineUpdate();
353 VPageR[A>>10]=p-A+(b<<10);
354 PPUCHRRAM|=(1<<(A>>10));
357 void FASTAPASS(3) setvramb2(uint8 *p, uint32 A, uint32 b)
359 FCEUPPU_LineUpdate();
360 VPageR[(A>>10)]=VPageR[(A>>10)+1]=p-A+(b<<11);
361 PPUCHRRAM|=(3<<(A>>10));
364 void FASTAPASS(3) setvramb4(uint8 *p, uint32 A, uint32 b)
368 FCEUPPU_LineUpdate();
370 VPageR[(A>>10)+x]=p-A+(b<<12);
371 PPUCHRRAM|=(15<<(A>>10));
374 void FASTAPASS(2) setvramb8(uint8 *p, uint32 b)
378 FCEUPPU_LineUpdate();
384 /* This function can be called without calling SetupCartMirroring(). */
386 void FASTAPASS(3) setntamem(uint8 *p, int ram, uint32 b)
388 FCEUPPU_LineUpdate();
395 static int mirrorhard=0;
396 void setmirrorw(int a, int b, int c, int d)
398 FCEUPPU_LineUpdate();
399 vnapage[0]=NTARAM+a*0x400;
400 vnapage[1]=NTARAM+b*0x400;
401 vnapage[2]=NTARAM+c*0x400;
402 vnapage[3]=NTARAM+d*0x400;
405 void FASTAPASS(1) setmirror(int t)
407 FCEUPPU_LineUpdate();
413 vnapage[0]=vnapage[1]=NTARAM;vnapage[2]=vnapage[3]=NTARAM+0x400;
416 vnapage[0]=vnapage[2]=NTARAM;vnapage[1]=vnapage[3]=NTARAM+0x400;
419 vnapage[0]=vnapage[1]=vnapage[2]=vnapage[3]=NTARAM;
422 vnapage[0]=vnapage[1]=vnapage[2]=vnapage[3]=NTARAM+0x400;
429 void SetupCartMirroring(int m, int hard, uint8 *extra)
439 vnapage[1]=NTARAM+0x400;
441 vnapage[3]=extra+0x400;
447 static uint8 *GENIEROM=0;
449 void FixGenieMap(void);
451 /* Called when a game(file) is opened successfully. */
461 if(!(GENIEROM=(uint8 *)FCEU_malloc(4096+1024))) return;
463 fn=FCEU_MakeFName(FCEUMKF_GGROM,0,0);
468 FCEU_PrintError("Error opening Game Genie ROM image!");
473 if(fread(GENIEROM,1,16,fp)!=16)
476 FCEU_PrintError("Error reading from Game Genie ROM image!");
482 if(GENIEROM[0]==0x4E) /* iNES ROM image */
484 if(fread(GENIEROM,1,4096,fp)!=4096)
486 if(fseek(fp,16384-4096,SEEK_CUR))
488 if(fread(GENIEROM+4096,1,256,fp)!=256)
493 if(fread(GENIEROM+16,1,4352-16,fp)!=(4352-16))
498 /* Workaround for the FCE Ultra CHR page size only being 1KB */
500 memcpy(GENIEROM+4096+(x<<8),GENIEROM+4096,256);
506 /* Called when a game is closed. */
507 void CloseGenie(void)
509 /* No good reason to free() the Game Genie ROM image data. */
515 void FCEU_KillGenie(void)
524 static DECLFR(GenieRead)
526 return GENIEROM[A&4095];
529 static DECLFW(GenieWrite)
535 case 0x8004:genieval[((A-4)&0xF)>>2]=V;break;
539 case 0x8003:geniech[((A-3)&0xF)>>2]=V;break;
543 case 0x8002:genieaddr[((A-2)&0xF)>>2]&=0xFF00;genieaddr[((A-2)&0xF)>>2]|=V;break;
547 case 0x8001:genieaddr[((A-1)&0xF)>>2]&=0xFF;genieaddr[((A-1)&0xF)>>2]|=(V|0x80)<<8;break;
561 static readfunc GenieBackup[3];
563 static DECLFR(GenieFix1)
565 uint8 r=GenieBackup[0](A);
567 if((modcon>>1)&1) // No check
569 else if(r==geniech[0])
575 static DECLFR(GenieFix2)
577 uint8 r=GenieBackup[1](A);
579 if((modcon>>2)&1) // No check
581 else if(r==geniech[1])
587 static DECLFR(GenieFix3)
589 uint8 r=GenieBackup[2](A);
591 if((modcon>>3)&1) // No check
593 else if(r==geniech[2])
600 void FixGenieMap(void)
611 //printf("Rightyo\n");
613 if((modcon>>(4+x))&1)
615 readfunc tmp[3]={GenieFix1,GenieFix2,GenieFix3};
616 GenieBackup[x]=GetReadHandler(genieaddr[x]);
617 SetReadHandler(genieaddr[x],genieaddr[x],tmp[x]);
621 void GeniePower(void)
637 SetWriteHandler(0x8000,0xFFFF,GenieWrite);
638 SetReadHandler(0x8000,0xFFFF,GenieRead);
641 VPage[x]=GENIEROM+4096-0x400*x;
649 static uint8 *real_pages[16];
651 void GenieSetPages(int restore)
656 for (page=16; page<32; page++)
657 Page[page] = real_pages[page-16];
661 for (page=16; page<32; page++) {
662 real_pages[page-16] = Page[page];
663 Page[page]=GENIEROM - (page<<11) + ((page&1)<<11);
668 void FCEU_SaveGameSave(CartInfo *LocalHWInfo)
670 if(LocalHWInfo->battery && LocalHWInfo->SaveGame[0])
675 soot=FCEU_MakeFName(FCEUMKF_SAV,0,"sav");
676 if((sp=FCEUD_UTF8fopen(soot,"wb"))==NULL)
678 FCEU_PrintError("WRAM file \"%s\" cannot be written to.\n",soot);
685 if(LocalHWInfo->SaveGame[x])
687 fwrite(LocalHWInfo->SaveGame[x],1,
688 LocalHWInfo->SaveGameLen[x],sp);
699 // hack, movie.c has to communicate with this function somehow
700 int disableBatteryLoading=0;
702 void FCEU_LoadGameSave(CartInfo *LocalHWInfo)
704 if(LocalHWInfo->battery && LocalHWInfo->SaveGame[0] && !disableBatteryLoading)
709 soot=FCEU_MakeFName(FCEUMKF_SAV,0,"sav");
710 sp=FCEUD_UTF8fopen(soot,"rb");
715 if(LocalHWInfo->SaveGame[x])
716 fread(LocalHWInfo->SaveGame[x],1,LocalHWInfo->SaveGameLen[x],sp);
723 void DumpEmptyCartMapping(void)
729 if (Page[x] == (nothing-x*2048) || Page[x] == 0)
735 printf("DumpEmptyCartMapping: %04x-%04x\n", st*2048, end*2048-1);
738 printf("DumpEmptyCartMapping: %04x-%04x\n", st*2048, end*2048-1);