098 renderer added
[fceu.git] / cart.c
CommitLineData
c62d2810 1/* FCE Ultra - NES/Famicom Emulator
2 *
3 * Copyright notice for this file:
d97315ac 4 * Copyright (C) 2002 Xodnizel
c62d2810 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 <string.h>
22#include <stdlib.h>
d97315ac 23#include <stdio.h>
c62d2810 24
2a6855a3 25#ifdef GP2X
26#include <unistd.h> // for sync()
27#endif
28
c62d2810 29#include "types.h"
c62d2810 30#include "fce.h"
d97315ac 31#include "ppu.h"
6244011f 32#include "ppu098.h"
d97315ac 33
c62d2810 34#include "cart.h"
35#include "memory.h"
d97315ac 36#include "x6502.h"
c62d2810 37
38#include "general.h"
d97315ac 39
c62d2810 40#include "svga.h"
d97315ac 41#include "file.h"
42
937bf65b 43/*
c62d2810 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.
47*/
48
49uint8 *Page[32],*VPage[8];
50uint8 **VPageR=VPage;
51uint8 *VPageG[8];
52uint8 *MMC5SPRVPage[8];
53uint8 *MMC5BGVPage[8];
54
d97315ac 55static uint8 PRGIsRAM[32]; /* This page is/is not PRG RAM. */
c62d2810 56
d97315ac 57/* 16 are (sort of) reserved for UNIF/iNES and 16 to map other stuff. */
c62d2810 58static int CHRram[32];
59static int PRGram[32];
60
61uint8 *PRGptr[32];
62uint8 *CHRptr[32];
63
64uint32 PRGsize[32];
65uint32 CHRsize[32];
66
67uint32 PRGmask2[32];
68uint32 PRGmask4[32];
69uint32 PRGmask8[32];
70uint32 PRGmask16[32];
71uint32 PRGmask32[32];
72
73uint32 CHRmask1[32];
74uint32 CHRmask2[32];
75uint32 CHRmask4[32];
76uint32 CHRmask8[32];
77
78int geniestage=0;
79
80int modcon;
81
82uint8 genieval[3];
83uint8 geniech[3];
84
85uint32 genieaddr[3];
86
d97315ac 87static INLINE void setpageptr(int s, uint32 A, uint8 *p, int ram)
c62d2810 88{
89 uint32 AB=A>>11;
90 int x;
91
d97315ac 92 if(p)
93 for(x=(s>>1)-1;x>=0;x--)
94 {
95 PRGIsRAM[AB+x]=ram;
96 Page[AB+x]=p-A;
97 }
98 else
99 for(x=(s>>1)-1;x>=0;x--)
100 {
101 PRGIsRAM[AB+x]=0;
102 Page[AB+x]=0;
103 }
c62d2810 104}
105
d97315ac 106static uint8 nothing[8192];
c62d2810 107void ResetCartMapping(void)
108{
109 int x;
110
111 for(x=0;x<32;x++)
112 {
d97315ac 113 Page[x]=nothing-x*2048;
c62d2810 114 PRGptr[x]=CHRptr[x]=0;
115 PRGsize[x]=CHRsize[x]=0;
116 }
117 for(x=0;x<8;x++)
118 {
d97315ac 119 MMC5SPRVPage[x]=MMC5BGVPage[x]=VPageR[x]=nothing-0x400*x;
c62d2810 120 }
121
122}
123
124void SetupCartPRGMapping(int chip, uint8 *p, uint32 size, int ram)
125{
126 PRGptr[chip]=p;
127 PRGsize[chip]=size;
128
129 PRGmask2[chip]=(size>>11)-1;
130 PRGmask4[chip]=(size>>12)-1;
131 PRGmask8[chip]=(size>>13)-1;
132 PRGmask16[chip]=(size>>14)-1;
937bf65b 133 PRGmask32[chip]=(size>>15)-1;
c62d2810 134
135 PRGram[chip]=ram?1:0;
136}
137
138void SetupCartCHRMapping(int chip, uint8 *p, uint32 size, int ram)
139{
140 CHRptr[chip]=p;
141 CHRsize[chip]=size;
142
143 CHRmask1[chip]=(size>>10)-1;
144 CHRmask2[chip]=(size>>11)-1;
145 CHRmask4[chip]=(size>>12)-1;
146 CHRmask8[chip]=(size>>13)-1;
147
148 CHRram[chip]=ram;
149}
150
151DECLFR(CartBR)
152{
153 return Page[A>>11][A];
154}
155
d97315ac 156DECLFW(CartBW)
c62d2810 157{
d97315ac 158 //printf("Ok: %04x:%02x, %d\n",A,V,PRGIsRAM[A>>11]);
159 if(PRGIsRAM[A>>11] && Page[A>>11])
160 Page[A>>11][A]=V;
161}
162
163DECLFR(CartBROB)
164{
165 if(!Page[A>>11]) return(X.DB);
166 return Page[A>>11][A];
167}
c62d2810 168
d97315ac 169void FASTAPASS(3) setprg2r(int r, unsigned int A, unsigned int V)
170{
171 V&=PRGmask2[r];
172 setpageptr(2,A,PRGptr[r]?(&PRGptr[r][V<<11]):0,PRGram[r]);
13624c8f 173 X6502_Rebase();
c62d2810 174}
175
176void FASTAPASS(2) setprg2(uint32 A, uint32 V)
177{
178 setprg2r(0,A,V);
179}
180
d97315ac 181void FASTAPASS(3) setprg4r(int r, unsigned int A, unsigned int V)
c62d2810 182{
c62d2810 183 V&=PRGmask4[r];
d97315ac 184 setpageptr(4,A,PRGptr[r]?(&PRGptr[r][V<<12]):0,PRGram[r]);
13624c8f 185 X6502_Rebase();
c62d2810 186}
187
188void FASTAPASS(2) setprg4(uint32 A, uint32 V)
189{
190 setprg4r(0,A,V);
191}
192
d97315ac 193void FASTAPASS(3) setprg8r(int r, unsigned int A, unsigned int V)
c62d2810 194{
c62d2810 195 if(PRGsize[r]>=8192)
196 {
197 V&=PRGmask8[r];
d97315ac 198 setpageptr(8,A,PRGptr[r]?(&PRGptr[r][V<<13]):0,PRGram[r]);
c62d2810 199 }
200 else
201 {
202 uint32 VA=V<<2;
203 int x;
204 for(x=0;x<4;x++)
d97315ac 205 setpageptr(2,A+(x<<11),PRGptr[r]?(&PRGptr[r][((VA+x)&PRGmask2[r])<<11]):0,PRGram[r]);
c62d2810 206 }
13624c8f 207 X6502_Rebase();
c62d2810 208}
209
210void FASTAPASS(2) setprg8(uint32 A, uint32 V)
211{
212 setprg8r(0,A,V);
213}
214
d97315ac 215void FASTAPASS(3) setprg16r(int r, unsigned int A, unsigned int V)
c62d2810 216{
c62d2810 217 if(PRGsize[r]>=16384)
218 {
219 V&=PRGmask16[r];
d97315ac 220 setpageptr(16,A,PRGptr[r]?(&PRGptr[r][V<<14]):0,PRGram[r]);
c62d2810 221 }
222 else
223 {
224 uint32 VA=V<<3;
225 int x;
226
227 for(x=0;x<8;x++)
d97315ac 228 setpageptr(2,A+(x<<11),PRGptr[r]?(&PRGptr[r][((VA+x)&PRGmask2[r])<<11]):0,PRGram[r]);
c62d2810 229 }
13624c8f 230 X6502_Rebase();
c62d2810 231}
232
233void FASTAPASS(2) setprg16(uint32 A, uint32 V)
234{
235 setprg16r(0,A,V);
236}
237
d97315ac 238void FASTAPASS(3) setprg32r(int r,unsigned int A, unsigned int V)
c62d2810 239{
c62d2810 240 if(PRGsize[r]>=32768)
241 {
242 V&=PRGmask32[r];
d97315ac 243 setpageptr(32,A,PRGptr[r]?(&PRGptr[r][V<<15]):0,PRGram[r]);
c62d2810 244 }
245 else
246 {
247 uint32 VA=V<<4;
248 int x;
249
250 for(x=0;x<16;x++)
d97315ac 251 setpageptr(2,A+(x<<11),PRGptr[r]?(&PRGptr[r][((VA+x)&PRGmask2[r])<<11]):0,PRGram[r]);
c62d2810 252 }
13624c8f 253 X6502_Rebase();
c62d2810 254}
255
256void FASTAPASS(2) setprg32(uint32 A, uint32 V)
257{
258 setprg32r(0,A,V);
259}
260
d97315ac 261void FASTAPASS(3) setchr1r(int r, unsigned int A, unsigned int V)
c62d2810 262{
263 if(!CHRptr[r]) return;
d97315ac 264 FCEUPPU_LineUpdate();
c62d2810 265 V&=CHRmask1[r];
266 if(CHRram[r])
267 PPUCHRRAM|=(1<<(A>>10));
268 else
269 PPUCHRRAM&=~(1<<(A>>10));
270 VPageR[(A)>>10]=&CHRptr[r][(V)<<10]-(A);
271}
272
d97315ac 273void FASTAPASS(3) setchr2r(int r, unsigned int A, unsigned int V)
c62d2810 274{
275 if(!CHRptr[r]) return;
d97315ac 276 FCEUPPU_LineUpdate();
c62d2810 277 V&=CHRmask2[r];
278 VPageR[(A)>>10]=VPageR[((A)>>10)+1]=&CHRptr[r][(V)<<11]-(A);
279 if(CHRram[r])
280 PPUCHRRAM|=(3<<(A>>10));
281 else
282 PPUCHRRAM&=~(3<<(A>>10));
283}
284
d97315ac 285void FASTAPASS(3) setchr4r(int r, unsigned int A, unsigned int V)
c62d2810 286{
287 if(!CHRptr[r]) return;
d97315ac 288 FCEUPPU_LineUpdate();
c62d2810 289 V&=CHRmask4[r];
290 VPageR[(A)>>10]=VPageR[((A)>>10)+1]=
291 VPageR[((A)>>10)+2]=VPageR[((A)>>10)+3]=&CHRptr[r][(V)<<12]-(A);
292 if(CHRram[r])
293 PPUCHRRAM|=(15<<(A>>10));
294 else
295 PPUCHRRAM&=~(15<<(A>>10));
296}
297
d97315ac 298void FASTAPASS(2) setchr8r(int r, unsigned int V)
c62d2810 299{
300 int x;
301
302 if(!CHRptr[r]) return;
d97315ac 303 FCEUPPU_LineUpdate();
c62d2810 304 V&=CHRmask8[r];
305 for(x=7;x>=0;x--)
306 VPageR[x]=&CHRptr[r][V<<13];
307 if(CHRram[r])
308 PPUCHRRAM|=(255);
309 else
310 PPUCHRRAM&=~(255);
311}
312
313void FASTAPASS(2) setchr1(unsigned int A, unsigned int V)
314{
315 setchr1r(0,A,V);
316}
317
318void FASTAPASS(2) setchr2(unsigned int A, unsigned int V)
319{
320 setchr2r(0,A,V);
321}
322
323void FASTAPASS(2) setchr4(unsigned int A, unsigned int V)
324{
325 setchr4r(0,A,V);
326}
327
d97315ac 328void FASTAPASS(1) setchr8(unsigned int V)
c62d2810 329{
330 setchr8r(0,V);
331}
332
333void FASTAPASS(1) setvram8(uint8 *p)
334{
335 int x;
336 for(x=7;x>=0;x--)
337 VPageR[x]=p;
338 PPUCHRRAM|=255;
339}
340
341void FASTAPASS(2) setvram4(uint32 A, uint8 *p)
342{
343 int x;
344 for(x=3;x>=0;x--)
345 VPageR[(A>>10)+x]=p-A;
346 PPUCHRRAM|=(15<<(A>>10));
347}
348
349void FASTAPASS(3) setvramb1(uint8 *p, uint32 A, uint32 b)
350{
d97315ac 351 FCEUPPU_LineUpdate();
c62d2810 352 VPageR[A>>10]=p-A+(b<<10);
353 PPUCHRRAM|=(1<<(A>>10));
354}
355
356void FASTAPASS(3) setvramb2(uint8 *p, uint32 A, uint32 b)
357{
d97315ac 358 FCEUPPU_LineUpdate();
c62d2810 359 VPageR[(A>>10)]=VPageR[(A>>10)+1]=p-A+(b<<11);
360 PPUCHRRAM|=(3<<(A>>10));
361}
362
363void FASTAPASS(3) setvramb4(uint8 *p, uint32 A, uint32 b)
364{
365 int x;
366
d97315ac 367 FCEUPPU_LineUpdate();
c62d2810 368 for(x=3;x>=0;x--)
369 VPageR[(A>>10)+x]=p-A+(b<<12);
370 PPUCHRRAM|=(15<<(A>>10));
371}
372
373void FASTAPASS(2) setvramb8(uint8 *p, uint32 b)
374{
375 int x;
376
d97315ac 377 FCEUPPU_LineUpdate();
c62d2810 378 for(x=7;x>=0;x--)
379 VPageR[x]=p+(b<<13);
380 PPUCHRRAM|=255;
381}
382
383/* This function can be called without calling SetupCartMirroring(). */
384
385void FASTAPASS(3) setntamem(uint8 *p, int ram, uint32 b)
386{
d97315ac 387 FCEUPPU_LineUpdate();
c62d2810 388 vnapage[b]=p;
389 PPUNTARAM&=~(1<<b);
390 if(ram)
391 PPUNTARAM|=1<<b;
392}
393
394static int mirrorhard=0;
395void setmirrorw(int a, int b, int c, int d)
396{
d97315ac 397 FCEUPPU_LineUpdate();
c62d2810 398 vnapage[0]=NTARAM+a*0x400;
399 vnapage[1]=NTARAM+b*0x400;
400 vnapage[2]=NTARAM+c*0x400;
401 vnapage[3]=NTARAM+d*0x400;
402}
403
404void FASTAPASS(1) setmirror(int t)
405{
d97315ac 406 FCEUPPU_LineUpdate();
c62d2810 407 if(!mirrorhard)
408 {
409 switch(t)
410 {
411 case MI_H:
412 vnapage[0]=vnapage[1]=NTARAM;vnapage[2]=vnapage[3]=NTARAM+0x400;
413 break;
414 case MI_V:
415 vnapage[0]=vnapage[2]=NTARAM;vnapage[1]=vnapage[3]=NTARAM+0x400;
416 break;
417 case MI_0:
418 vnapage[0]=vnapage[1]=vnapage[2]=vnapage[3]=NTARAM;
419 break;
420 case MI_1:
421 vnapage[0]=vnapage[1]=vnapage[2]=vnapage[3]=NTARAM+0x400;
422 break;
423 }
424 PPUNTARAM=0xF;
425 }
426}
427
428void SetupCartMirroring(int m, int hard, uint8 *extra)
429{
430 if(m<4)
d97315ac 431 {
432 mirrorhard = 0;
c62d2810 433 setmirror(m);
d97315ac 434 }
c62d2810 435 else
436 {
437 vnapage[0]=NTARAM;
438 vnapage[1]=NTARAM+0x400;
439 vnapage[2]=extra;
440 vnapage[3]=extra+0x400;
441 PPUNTARAM=0xF;
442 }
443 mirrorhard=hard;
444}
445
446static uint8 *GENIEROM=0;
447
448void FixGenieMap(void);
449
450/* Called when a game(file) is opened successfully. */
451void OpenGenie(void)
452{
453 FILE *fp;
454 int x;
455
456 if(!GENIEROM)
457 {
d97315ac 458 char *fn;
459
460 if(!(GENIEROM=(uint8 *)FCEU_malloc(4096+1024))) return;
c62d2810 461
d97315ac 462 fn=FCEU_MakeFName(FCEUMKF_GGROM,0,0);
463 fp=fopen(fn,"rb");
92764e62 464 free(fn);
d97315ac 465 if(!fp)
c62d2810 466 {
467 FCEU_PrintError("Error opening Game Genie ROM image!");
468 free(GENIEROM);
469 GENIEROM=0;
470 return;
471 }
472 if(fread(GENIEROM,1,16,fp)!=16)
473 {
474 grerr:
475 FCEU_PrintError("Error reading from Game Genie ROM image!");
476 free(GENIEROM);
477 GENIEROM=0;
478 fclose(fp);
479 return;
480 }
d97315ac 481 if(GENIEROM[0]==0x4E) /* iNES ROM image */
c62d2810 482 {
483 if(fread(GENIEROM,1,4096,fp)!=4096)
484 goto grerr;
485 if(fseek(fp,16384-4096,SEEK_CUR))
486 goto grerr;
487 if(fread(GENIEROM+4096,1,256,fp)!=256)
488 goto grerr;
489 }
490 else
491 {
492 if(fread(GENIEROM+16,1,4352-16,fp)!=(4352-16))
493 goto grerr;
494 }
495 fclose(fp);
937bf65b 496
c62d2810 497 /* Workaround for the FCE Ultra CHR page size only being 1KB */
498 for(x=0;x<4;x++)
499 memcpy(GENIEROM+4096+(x<<8),GENIEROM+4096,256);
500 }
501
502 geniestage=1;
503}
504
505/* Called when a game is closed. */
506void CloseGenie(void)
507{
508 /* No good reason to free() the Game Genie ROM image data. */
509 geniestage=0;
510 FlushGenieRW();
511 VPageR=VPage;
512}
513
d97315ac 514void FCEU_KillGenie(void)
515{
516 if(GENIEROM)
517 {
518 free(GENIEROM);
519 GENIEROM=0;
520 }
521}
522
c62d2810 523static DECLFR(GenieRead)
524{
525 return GENIEROM[A&4095];
526}
527
528static DECLFW(GenieWrite)
529{
530 switch(A)
531 {
532 case 0x800c:
533 case 0x8008:
534 case 0x8004:genieval[((A-4)&0xF)>>2]=V;break;
535
536 case 0x800b:
537 case 0x8007:
538 case 0x8003:geniech[((A-3)&0xF)>>2]=V;break;
539
540 case 0x800a:
541 case 0x8006:
542 case 0x8002:genieaddr[((A-2)&0xF)>>2]&=0xFF00;genieaddr[((A-2)&0xF)>>2]|=V;break;
543
544 case 0x8009:
545 case 0x8005:
546 case 0x8001:genieaddr[((A-1)&0xF)>>2]&=0xFF;genieaddr[((A-1)&0xF)>>2]|=(V|0x80)<<8;break;
547
548 case 0x8000:if(!V)
d97315ac 549 FixGenieMap();
550 else
551 {
552 modcon=V^0xFF;
553 if(V==0x71)
554 modcon=0;
555 }
556 break;
c62d2810 557 }
558}
559
560static readfunc GenieBackup[3];
561
562static DECLFR(GenieFix1)
563{
564 uint8 r=GenieBackup[0](A);
565
d97315ac 566 if((modcon>>1)&1) // No check
c62d2810 567 return genieval[0];
568 else if(r==geniech[0])
569 return genieval[0];
570
571 return r;
572}
573
574static DECLFR(GenieFix2)
575{
576 uint8 r=GenieBackup[1](A);
577
d97315ac 578 if((modcon>>2)&1) // No check
c62d2810 579 return genieval[1];
580 else if(r==geniech[1])
581 return genieval[1];
582
583 return r;
584}
585
586static DECLFR(GenieFix3)
587{
588 uint8 r=GenieBackup[2](A);
589
d97315ac 590 if((modcon>>3)&1) // No check
c62d2810 591 return genieval[2];
592 else if(r==geniech[2])
593 return genieval[2];
594
595 return r;
596}
597
598
599void FixGenieMap(void)
600{
601 int x;
602
603 geniestage=2;
604
605 for(x=0;x<8;x++)
606 VPage[x]=VPageG[x];
607
608 VPageR=VPage;
609 FlushGenieRW();
d97315ac 610 //printf("Rightyo\n");
c62d2810 611 for(x=0;x<3;x++)
612 if((modcon>>(4+x))&1)
613 {
614 readfunc tmp[3]={GenieFix1,GenieFix2,GenieFix3};
615 GenieBackup[x]=GetReadHandler(genieaddr[x]);
616 SetReadHandler(genieaddr[x],genieaddr[x],tmp[x]);
617 }
618}
619
620void GeniePower(void)
621{
622 uint32 x;
623
624 if(!geniestage)
625 return;
626
627 geniestage=1;
628 for(x=0;x<3;x++)
629 {
630 genieval[x]=0xFF;
631 geniech[x]=0xFF;
632 genieaddr[x]=0xFFFF;
633 }
634 modcon=0;
635
636 SetWriteHandler(0x8000,0xFFFF,GenieWrite);
637 SetReadHandler(0x8000,0xFFFF,GenieRead);
638
639 for(x=0;x<8;x++)
640 VPage[x]=GENIEROM+4096-0x400*x;
641
642 if(AllocGenieRW())
643 VPageR=VPageG;
644 else
645 geniestage=2;
646}
647
b8da43fb 648static uint8 *real_pages[16];
649
650void GenieSetPages(int restore)
651{
652 int page;
653 if (restore)
654 {
655 for (page=16; page<32; page++)
656 Page[page] = real_pages[page-16];
657 }
658 else
659 {
660 for (page=16; page<32; page++) {
661 real_pages[page-16] = Page[page];
662 Page[page]=GENIEROM - (page<<11) + ((page&1)<<11);
663 }
664 }
665}
c62d2810 666
d97315ac 667void FCEU_SaveGameSave(CartInfo *LocalHWInfo)
668{
669 if(LocalHWInfo->battery && LocalHWInfo->SaveGame[0])
670 {
671 FILE *sp;
672 char *soot;
673
674 soot=FCEU_MakeFName(FCEUMKF_SAV,0,"sav");
675 if((sp=FCEUD_UTF8fopen(soot,"wb"))==NULL)
676 {
677 FCEU_PrintError("WRAM file \"%s\" cannot be written to.\n",soot);
678 }
679 else
680 {
681 int x;
682
683 for(x=0;x<4;x++)
684 if(LocalHWInfo->SaveGame[x])
685 {
686 fwrite(LocalHWInfo->SaveGame[x],1,
687 LocalHWInfo->SaveGameLen[x],sp);
688 }
2a6855a3 689 fclose(sp);
690#ifdef GP2X
691 sync();
692#endif
d97315ac 693 }
694 free(soot);
695 }
696}
697
698// hack, movie.c has to communicate with this function somehow
699int disableBatteryLoading=0;
700
701void FCEU_LoadGameSave(CartInfo *LocalHWInfo)
702{
703 if(LocalHWInfo->battery && LocalHWInfo->SaveGame[0] && !disableBatteryLoading)
704 {
705 FILE *sp;
706 char *soot;
707
708 soot=FCEU_MakeFName(FCEUMKF_SAV,0,"sav");
709 sp=FCEUD_UTF8fopen(soot,"rb");
710 if(sp!=NULL)
711 {
712 int x;
713 for(x=0;x<4;x++)
714 if(LocalHWInfo->SaveGame[x])
715 fread(LocalHWInfo->SaveGame[x],1,LocalHWInfo->SaveGameLen[x],sp);
2a6855a3 716 fclose(sp);
d97315ac 717 }
718 free(soot);
719 }
720}
721
e7f52878 722void DumpEmptyCartMapping(void)
723{
724 int x, st=0, end=-1;
725
726 for(x=8;x<32;x++)
727 {
728 if (Page[x] == (nothing-x*2048) || Page[x] == 0)
729 {
730 if (end != x) st=x;
731 end=x+1;
732 }
733 if (end == x)
734 printf("DumpEmptyCartMapping: %04x-%04x\n", st*2048, end*2048-1);
735 }
736 if (end==32)
737 printf("DumpEmptyCartMapping: %04x-%04x\n", st*2048, end*2048-1);
738}
739
d97315ac 740