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()
44 This file contains all code for coordinating the mapping in of the
45 address space external to the NES.
46 It's also (ab)used by the NSF code.
49 uint8 *Page[32],*VPage[8];
52 uint8 *MMC5SPRVPage[8];
53 uint8 *MMC5BGVPage[8];
55 static uint8 PRGIsRAM[32]; /* This page is/is not PRG RAM. */
57 /* 16 are (sort of) reserved for UNIF/iNES and 16 to map other stuff. */
58 static int CHRram[32];
59 static int PRGram[32];
87 static INLINE void setpageptr(int s, uint32 A, uint8 *p, int ram)
93 for(x=(s>>1)-1;x>=0;x--)
99 for(x=(s>>1)-1;x>=0;x--)
106 static uint8 nothing[8192];
107 void ResetCartMapping(void)
113 Page[x]=nothing-x*2048;
114 PRGptr[x]=CHRptr[x]=0;
115 PRGsize[x]=CHRsize[x]=0;
119 MMC5SPRVPage[x]=MMC5BGVPage[x]=VPageR[x]=nothing-0x400*x;
124 void SetupCartPRGMapping(int chip, uint8 *p, uint32 size, int ram)
129 PRGmask2[chip]=(size>>11)-1;
130 PRGmask4[chip]=(size>>12)-1;
131 PRGmask8[chip]=(size>>13)-1;
132 PRGmask16[chip]=(size>>14)-1;
133 PRGmask32[chip]=(size>>15)-1;
135 PRGram[chip]=ram?1:0;
138 void SetupCartCHRMapping(int chip, uint8 *p, uint32 size, int ram)
143 CHRmask1[chip]=(size>>10)-1;
144 CHRmask2[chip]=(size>>11)-1;
145 CHRmask4[chip]=(size>>12)-1;
146 CHRmask8[chip]=(size>>13)-1;
153 return Page[A>>11][A];
158 //printf("Ok: %04x:%02x, %d\n",A,V,PRGIsRAM[A>>11]);
159 if(PRGIsRAM[A>>11] && Page[A>>11])
165 if(!Page[A>>11]) return(X.DB);
166 return Page[A>>11][A];
169 void FASTAPASS(3) setprg2r(int r, unsigned int A, unsigned int V)
172 setpageptr(2,A,PRGptr[r]?(&PRGptr[r][V<<11]):0,PRGram[r]);
176 void FASTAPASS(2) setprg2(uint32 A, uint32 V)
181 void FASTAPASS(3) setprg4r(int r, unsigned int A, unsigned int V)
184 setpageptr(4,A,PRGptr[r]?(&PRGptr[r][V<<12]):0,PRGram[r]);
188 void FASTAPASS(2) setprg4(uint32 A, uint32 V)
193 void FASTAPASS(3) setprg8r(int r, unsigned int A, unsigned int V)
198 setpageptr(8,A,PRGptr[r]?(&PRGptr[r][V<<13]):0,PRGram[r]);
205 setpageptr(2,A+(x<<11),PRGptr[r]?(&PRGptr[r][((VA+x)&PRGmask2[r])<<11]):0,PRGram[r]);
210 void FASTAPASS(2) setprg8(uint32 A, uint32 V)
215 void FASTAPASS(3) setprg16r(int r, unsigned int A, unsigned int V)
217 if(PRGsize[r]>=16384)
220 setpageptr(16,A,PRGptr[r]?(&PRGptr[r][V<<14]):0,PRGram[r]);
228 setpageptr(2,A+(x<<11),PRGptr[r]?(&PRGptr[r][((VA+x)&PRGmask2[r])<<11]):0,PRGram[r]);
233 void FASTAPASS(2) setprg16(uint32 A, uint32 V)
238 void FASTAPASS(3) setprg32r(int r,unsigned int A, unsigned int V)
240 if(PRGsize[r]>=32768)
243 setpageptr(32,A,PRGptr[r]?(&PRGptr[r][V<<15]):0,PRGram[r]);
251 setpageptr(2,A+(x<<11),PRGptr[r]?(&PRGptr[r][((VA+x)&PRGmask2[r])<<11]):0,PRGram[r]);
256 void FASTAPASS(2) setprg32(uint32 A, uint32 V)
261 void FASTAPASS(3) setchr1r(int r, unsigned int A, unsigned int V)
263 if(!CHRptr[r]) return;
264 FCEUPPU_LineUpdate();
267 PPUCHRRAM|=(1<<(A>>10));
269 PPUCHRRAM&=~(1<<(A>>10));
270 VPageR[(A)>>10]=&CHRptr[r][(V)<<10]-(A);
273 void FASTAPASS(3) setchr2r(int r, unsigned int A, unsigned int V)
275 if(!CHRptr[r]) return;
276 FCEUPPU_LineUpdate();
278 VPageR[(A)>>10]=VPageR[((A)>>10)+1]=&CHRptr[r][(V)<<11]-(A);
280 PPUCHRRAM|=(3<<(A>>10));
282 PPUCHRRAM&=~(3<<(A>>10));
285 void FASTAPASS(3) setchr4r(int r, unsigned int A, unsigned int V)
287 if(!CHRptr[r]) return;
288 FCEUPPU_LineUpdate();
290 VPageR[(A)>>10]=VPageR[((A)>>10)+1]=
291 VPageR[((A)>>10)+2]=VPageR[((A)>>10)+3]=&CHRptr[r][(V)<<12]-(A);
293 PPUCHRRAM|=(15<<(A>>10));
295 PPUCHRRAM&=~(15<<(A>>10));
298 void FASTAPASS(2) setchr8r(int r, unsigned int V)
302 if(!CHRptr[r]) return;
303 FCEUPPU_LineUpdate();
306 VPageR[x]=&CHRptr[r][V<<13];
313 void FASTAPASS(2) setchr1(unsigned int A, unsigned int V)
318 void FASTAPASS(2) setchr2(unsigned int A, unsigned int V)
323 void FASTAPASS(2) setchr4(unsigned int A, unsigned int V)
328 void FASTAPASS(1) setchr8(unsigned int V)
333 void FASTAPASS(1) setvram8(uint8 *p)
341 void FASTAPASS(2) setvram4(uint32 A, uint8 *p)
345 VPageR[(A>>10)+x]=p-A;
346 PPUCHRRAM|=(15<<(A>>10));
349 void FASTAPASS(3) setvramb1(uint8 *p, uint32 A, uint32 b)
351 FCEUPPU_LineUpdate();
352 VPageR[A>>10]=p-A+(b<<10);
353 PPUCHRRAM|=(1<<(A>>10));
356 void FASTAPASS(3) setvramb2(uint8 *p, uint32 A, uint32 b)
358 FCEUPPU_LineUpdate();
359 VPageR[(A>>10)]=VPageR[(A>>10)+1]=p-A+(b<<11);
360 PPUCHRRAM|=(3<<(A>>10));
363 void FASTAPASS(3) setvramb4(uint8 *p, uint32 A, uint32 b)
367 FCEUPPU_LineUpdate();
369 VPageR[(A>>10)+x]=p-A+(b<<12);
370 PPUCHRRAM|=(15<<(A>>10));
373 void FASTAPASS(2) setvramb8(uint8 *p, uint32 b)
377 FCEUPPU_LineUpdate();
383 /* This function can be called without calling SetupCartMirroring(). */
385 void FASTAPASS(3) setntamem(uint8 *p, int ram, uint32 b)
387 FCEUPPU_LineUpdate();
394 static int mirrorhard=0;
395 void setmirrorw(int a, int b, int c, int d)
397 FCEUPPU_LineUpdate();
398 vnapage[0]=NTARAM+a*0x400;
399 vnapage[1]=NTARAM+b*0x400;
400 vnapage[2]=NTARAM+c*0x400;
401 vnapage[3]=NTARAM+d*0x400;
404 void FASTAPASS(1) setmirror(int t)
406 FCEUPPU_LineUpdate();
412 vnapage[0]=vnapage[1]=NTARAM;vnapage[2]=vnapage[3]=NTARAM+0x400;
415 vnapage[0]=vnapage[2]=NTARAM;vnapage[1]=vnapage[3]=NTARAM+0x400;
418 vnapage[0]=vnapage[1]=vnapage[2]=vnapage[3]=NTARAM;
421 vnapage[0]=vnapage[1]=vnapage[2]=vnapage[3]=NTARAM+0x400;
428 void SetupCartMirroring(int m, int hard, uint8 *extra)
438 vnapage[1]=NTARAM+0x400;
440 vnapage[3]=extra+0x400;
446 static uint8 *GENIEROM=0;
448 void FixGenieMap(void);
450 /* Called when a game(file) is opened successfully. */
460 if(!(GENIEROM=(uint8 *)FCEU_malloc(4096+1024))) return;
462 fn=FCEU_MakeFName(FCEUMKF_GGROM,0,0);
467 FCEU_PrintError("Error opening Game Genie ROM image!");
472 if(fread(GENIEROM,1,16,fp)!=16)
475 FCEU_PrintError("Error reading from Game Genie ROM image!");
481 if(GENIEROM[0]==0x4E) /* iNES ROM image */
483 if(fread(GENIEROM,1,4096,fp)!=4096)
485 if(fseek(fp,16384-4096,SEEK_CUR))
487 if(fread(GENIEROM+4096,1,256,fp)!=256)
492 if(fread(GENIEROM+16,1,4352-16,fp)!=(4352-16))
497 /* Workaround for the FCE Ultra CHR page size only being 1KB */
499 memcpy(GENIEROM+4096+(x<<8),GENIEROM+4096,256);
505 /* Called when a game is closed. */
506 void CloseGenie(void)
508 /* No good reason to free() the Game Genie ROM image data. */
514 void FCEU_KillGenie(void)
523 static DECLFR(GenieRead)
525 return GENIEROM[A&4095];
528 static DECLFW(GenieWrite)
534 case 0x8004:genieval[((A-4)&0xF)>>2]=V;break;
538 case 0x8003:geniech[((A-3)&0xF)>>2]=V;break;
542 case 0x8002:genieaddr[((A-2)&0xF)>>2]&=0xFF00;genieaddr[((A-2)&0xF)>>2]|=V;break;
546 case 0x8001:genieaddr[((A-1)&0xF)>>2]&=0xFF;genieaddr[((A-1)&0xF)>>2]|=(V|0x80)<<8;break;
560 static readfunc GenieBackup[3];
562 static DECLFR(GenieFix1)
564 uint8 r=GenieBackup[0](A);
566 if((modcon>>1)&1) // No check
568 else if(r==geniech[0])
574 static DECLFR(GenieFix2)
576 uint8 r=GenieBackup[1](A);
578 if((modcon>>2)&1) // No check
580 else if(r==geniech[1])
586 static DECLFR(GenieFix3)
588 uint8 r=GenieBackup[2](A);
590 if((modcon>>3)&1) // No check
592 else if(r==geniech[2])
599 void FixGenieMap(void)
610 //printf("Rightyo\n");
612 if((modcon>>(4+x))&1)
614 readfunc tmp[3]={GenieFix1,GenieFix2,GenieFix3};
615 GenieBackup[x]=GetReadHandler(genieaddr[x]);
616 SetReadHandler(genieaddr[x],genieaddr[x],tmp[x]);
620 void GeniePower(void)
636 SetWriteHandler(0x8000,0xFFFF,GenieWrite);
637 SetReadHandler(0x8000,0xFFFF,GenieRead);
640 VPage[x]=GENIEROM+4096-0x400*x;
648 static uint8 *real_pages[16];
650 void GenieSetPages(int restore)
655 for (page=16; page<32; page++)
656 Page[page] = real_pages[page-16];
660 for (page=16; page<32; page++) {
661 real_pages[page-16] = Page[page];
662 Page[page]=GENIEROM - (page<<11) + ((page&1)<<11);
667 void FCEU_SaveGameSave(CartInfo *LocalHWInfo)
669 if(LocalHWInfo->battery && LocalHWInfo->SaveGame[0])
674 soot=FCEU_MakeFName(FCEUMKF_SAV,0,"sav");
675 if((sp=FCEUD_UTF8fopen(soot,"wb"))==NULL)
677 FCEU_PrintError("WRAM file \"%s\" cannot be written to.\n",soot);
684 if(LocalHWInfo->SaveGame[x])
686 fwrite(LocalHWInfo->SaveGame[x],1,
687 LocalHWInfo->SaveGameLen[x],sp);
698 // hack, movie.c has to communicate with this function somehow
699 int disableBatteryLoading=0;
701 void FCEU_LoadGameSave(CartInfo *LocalHWInfo)
703 if(LocalHWInfo->battery && LocalHWInfo->SaveGame[0] && !disableBatteryLoading)
708 soot=FCEU_MakeFName(FCEUMKF_SAV,0,"sav");
709 sp=FCEUD_UTF8fopen(soot,"rb");
714 if(LocalHWInfo->SaveGame[x])
715 fread(LocalHWInfo->SaveGame[x],1,LocalHWInfo->SaveGameLen[x],sp);
722 void DumpEmptyCartMapping(void)
728 if (Page[x] == (nothing-x*2048) || Page[x] == 0)
734 printf("DumpEmptyCartMapping: %04x-%04x\n", st*2048, end*2048-1);
737 printf("DumpEmptyCartMapping: %04x-%04x\n", st*2048, end*2048-1);