73e884535139aae631bb7d13e456d7bfdf1aa1f1
[fceu.git] / fce.c
1 /* FCE Ultra - NES/Famicom Emulator
2  *
3  * Copyright notice for this file:
4  *  Copyright (C) 1998 BERO
5  *  Copyright (C) 2002 Ben Parnell
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include        <string.h>
23 #include        <stdio.h>
24 #include        <stdlib.h>
25
26 #include        "types.h"
27 #include        "x6502.h"
28 #include        "fce.h"
29 #include        "fceu098.h"
30 #include        "sound.h"
31 #include        "sound098.h"
32 #include        "svga.h"
33 #include        "netplay.h"
34 #include        "general.h"
35 #include        "endian.h"
36 #include        "version.h"
37 #include        "memory.h"
38
39 #include        "cart.h"
40 #include        "nsf.h"
41 #include        "fds.h"
42 #include        "ines.h"
43 #include        "unif.h"
44 #include        "vsuni.h"
45 #include        "cheat.h"
46
47 #include        "state.h"
48 #include        "video.h"
49 #include        "input.h"
50 #include        "file.h"
51 #include        "crc32.h"
52 #include        "ppu.h"
53
54 #include        "palette.h"
55 #include        "movie.h"
56
57 #include        "dprintf.h"
58
59 #ifdef GP2X
60 #include        "drivers/gp2x/asmutils.h"
61 #endif
62
63 #define Pal     (PALRAM)
64
65
66 static void (*RefreshLine)(uint8 *P, uint32 vofs) = NULL;
67 static void PRefreshLine(void);
68
69 static void ResetPPU(void);
70 static void PowerPPU(void);
71
72 uint64 timestampbase=0;
73
74 int ppudead=1;
75 int kook=0;
76
77 int MMC5Hack;
78 uint32 MMC5HackVROMMask;
79 uint8 *MMC5HackExNTARAMPtr;
80 uint8 *MMC5HackVROMPTR;
81 uint8 MMC5HackCHRMode=0;
82 uint8 MMC5HackSPMode;
83 uint8 MMC5HackSPScroll;
84 uint8 MMC5HackSPPage;
85
86 uint8 *MMC5SPRVPage[8];
87 uint8 *MMC5BGVPage[8];
88
89
90 uint8 VRAMBuffer,PPUGenLatch;
91
92 uint8 *vnapage[4];
93 uint8 PPUNTARAM;
94 uint8 PPUCHRRAM;
95
96 /* Color deemphasis emulation.  Joy... */
97 static uint8 deemp=0;
98 static int deempcnt[8];
99
100 FCEUGI FCEUGameInfo;
101 void (*GameInterface)(int h, void *param);
102
103 void FP_FASTAPASS(1) (*PPU_hook)(uint32 A);
104
105 void (*GameStateRestore)(int version);
106 void (*GameHBIRQHook)(void), (*GameHBIRQHook2)(void);
107
108 readfunc ARead[0x10000];
109 writefunc BWrite[0x10000];
110 static readfunc *AReadG;
111 static writefunc *BWriteG;
112 static int RWWrap=0;
113
114 #ifdef ASM_6502
115 static void asmcpu_update(int32 cycles)
116 {
117  // some code from x6502.c
118  fhcnt-=cycles;
119  if(fhcnt<=0)
120  {
121   FrameSoundUpdate();
122   fhcnt+=fhinc;
123  }
124
125  if(PCMIRQCount>0)
126  {
127   PCMIRQCount-=cycles;
128   if(PCMIRQCount<=0)
129   {
130    vdis=1;
131    if((PSG[0x10]&0x80) && !(PSG[0x10]&0x40))
132    {
133     extern uint8 SIRQStat;
134     SIRQStat|=0x80;
135     X6502_IRQBegin(FCEU_IQDPCM);
136    }
137   }
138  }
139 }
140
141 void asmcpu_unpack(void)
142 {
143         nes_registers[0] = X.A << 24;
144         nes_registers[1] = X.X;
145         nes_registers[2] = X.Y;
146         pc_base = 0;
147         nes_registers[3] = X.PC;
148         X6502_Rebase_a();
149         nes_registers[4] = X.S << 24;
150         nes_registers[4]|= X.IRQlow << 8;
151         if (MapIRQHook)
152                 nes_registers[4] |= 1<<16; // MapIRQHook set bit
153         nes_registers[7] = (uint32)X.count << 16;
154
155         // NVUB DIZC
156         nes_registers[4]|= X.P & 0x5d;
157         nes_registers[5] = X.P << 24; // N
158         if (!(X.P&0x02)) nes_registers[5] |= 1; // Z
159 }
160
161 void asmcpu_pack(void)
162 {
163         X.A = nes_registers[0] >> 24;
164         X.X = nes_registers[1];
165         X.Y = nes_registers[2];
166         X.PC= nes_registers[3] - pc_base;
167         X.S = nes_registers[4] >> 24;
168         X.IRQlow = nes_registers[4] >> 8;
169         X.count = (int32) nes_registers[7] >> 16;
170
171         // NVUB DIZC
172         X.P = nes_registers[4] & 0x5d;
173         if (  nes_registers[5]&0x80000000)  X.P |= 0x80; // N
174         if (!(nes_registers[5]&0x000000ff)) X.P |= 0x02; // Z
175 }
176 #endif
177
178 DECLFW(BNull)
179 {
180
181 }
182
183 DECLFR(ANull)
184 {
185  return(X.DB);
186 }
187
188 int AllocGenieRW(void)
189 {
190  if(!(AReadG=FCEU_malloc(0x8000*sizeof(readfunc))))
191   return 0;
192  if(!(BWriteG=FCEU_malloc(0x8000*sizeof(writefunc))))
193   return 0;
194  RWWrap=1;
195  return 1;
196 }
197
198 void FlushGenieRW(void)
199 {
200  int32 x;
201
202  if(RWWrap)
203  {
204   for(x=0;x<0x8000;x++)
205   {
206    ARead[x+0x8000]=AReadG[x];
207    BWrite[x+0x8000]=BWriteG[x];
208   }
209 #ifdef ASM_6502
210   GenieSetPages(1);
211 #endif
212   free(AReadG);
213   free(BWriteG);
214   AReadG=0;
215   BWriteG=0;
216   RWWrap=0;
217  }
218 }
219
220 readfunc FASTAPASS(1) GetReadHandler(int32 a)
221 {
222   if(a>=0x8000 && RWWrap)
223    return AReadG[a-0x8000];
224   else
225    return ARead[a];
226 }
227
228 void FASTAPASS(3) SetReadHandler(int32 start, int32 end, readfunc func)
229 {
230   int32 x;
231
232   if(!func)
233    func=ANull;
234
235   if(RWWrap)
236    for(x=end;x>=start;x--)
237    {
238     if(x>=0x8000)
239      AReadG[x-0x8000]=func;
240     else
241      ARead[x]=func;
242    }
243   else
244
245    for(x=end;x>=start;x--)
246     ARead[x]=func;
247 }
248
249 writefunc FASTAPASS(1) GetWriteHandler(int32 a)
250 {
251   if(RWWrap && a>=0x8000)
252    return BWriteG[a-0x8000];
253   else
254    return BWrite[a];
255 }
256
257 void FASTAPASS(3) SetWriteHandler(int32 start, int32 end, writefunc func)
258 {
259   int32 x;
260
261   if(!func)
262    func=BNull;
263
264   if(RWWrap)
265    for(x=end;x>=start;x--)
266    {
267     if(x>=0x8000)
268      BWriteG[x-0x8000]=func;
269     else
270      BWrite[x]=func;
271    }
272   else
273    for(x=end;x>=start;x--)
274     BWrite[x]=func;
275 }
276
277 uint8 vtoggle=0;
278 uint8 XOffset=0;
279
280 uint32 TempAddr,RefreshAddr;
281
282
283 /* scanline is equal to the current visible scanline we're on. */
284
285 int scanline;
286
287 uint8 GameMemBlock[131072] __attribute__ ((aligned (4)));
288 uint8 NTARAM[0x800] __attribute__ ((aligned (4)));
289 uint8 PALRAM[0x20] __attribute__ ((aligned (4)));
290 #if !defined(ASM_6502) || defined(DEBUG_ASM_6502)
291 uint8 RAM[0x800] __attribute__ ((aligned (4)));
292 #endif
293
294 uint8 PPU[4];
295 uint8 PPUSPL;
296
297 uint8 PAL=0;
298
299
300 #define MMC5BGVRAMADR(V)      &MMC5BGVPage[(V)>>10][(V)]
301 #define VRAMADR(V)      &VPage[(V)>>10][(V)]
302
303 static int linestartts;
304 static int tofix=0;
305
306 static uint8 *Plinef;
307
308 extern uint8 sprlinebuf[256+8];
309 extern int32 sphitx;
310 extern uint8 sphitdata;
311
312 extern int spork;       /* spork the world.  Any sprites on this line?
313                            Then this will be set to 1.  Needed for zapper
314                            emulation and *gasp* sprite emulation.
315                         */
316
317 static void ResetRL(uint8 *target)
318 {
319  if(InputScanlineHook)
320   InputScanlineHook(0,0,0,0);
321  Plinef=target;
322  linestartts=timestamp*48+X6502_GetCycleCount();
323  tofix=1;
324 }
325
326 static INLINE void Fixit1(void);
327
328 /* faking FCEUPPU_LineUpdate() from later versions of the emu */
329 static void FakedLineUpdate(void)
330 {
331  #define TOFIXNUM (272-0x4)
332  int lastpixel;
333
334  if (scanline >= 240) return;
335
336  if (tofix || sphitx != 0x100)
337  {
338   lastpixel = (timestamp*48-linestartts)>>4;
339   if (PAL) lastpixel += lastpixel>>4;
340   //printf("lastpixel: %i\n", lastpixel);
341  }
342
343  if (tofix && lastpixel>=TOFIXNUM)
344  {
345   Fixit1();
346   tofix=0;
347  }
348
349  // CheckSpriteHit()
350  if(sphitx!=0x100)
351  {
352   int l=lastpixel-16;
353   int x;
354
355   for(x=sphitx;x<(sphitx+8) && x<l;x++)
356   {
357    if((sphitdata&(0x80>>(x-sphitx))) && !(Plinef[x]&64))
358    {
359     PPU_status|=0x40;
360     sphitx=0x100;
361     break;
362    }
363   }
364  }
365 }
366
367
368 static DECLFW(BRAML)
369 {
370         RAM[A]=V;
371 }
372
373 static DECLFW(BRAMH)
374 {
375         RAM[A&0x7FF]=V;
376 }
377
378 static DECLFR(ARAML)
379 {
380         return RAM[A];
381 }
382
383 static DECLFR(ARAMH)
384 {
385         return RAM[A&0x7FF];
386 }
387
388
389 static DECLFR(A2002)
390 {
391         /* merged */
392                         uint8 ret;
393
394                         FakedLineUpdate();
395                         ret = PPU_status;
396                         ret|=PPUGenLatch&0x1F;
397                         vtoggle=0;
398                         PPU_status&=0x7F;
399                          PPUGenLatch=ret;
400                         //dprintf("r [2002] %02x",ret);
401                         return ret;
402 }
403
404 static DECLFR(A200x)
405 {
406         /* merged */
407                         FakedLineUpdate();
408                         return PPUGenLatch;
409 }
410
411 static DECLFR(A2007)
412 {
413         /* merged */
414                         uint8 ret;
415                         uint32 tmp=RefreshAddr&0x3FFF;
416
417                         FakedLineUpdate();
418
419                         ret=VRAMBuffer;
420
421                         if(PPU_hook) PPU_hook(tmp);
422                         PPUGenLatch=VRAMBuffer;
423                         if(tmp<0x2000)
424                         {
425                          VRAMBuffer=VPage[tmp>>10][tmp];
426                         }
427                         else
428                         {
429                          VRAMBuffer=vnapage[(tmp>>10)&0x3][tmp&0x3FF];
430                         }
431
432                         if (INC32) RefreshAddr+=32;
433                         else RefreshAddr++;
434                         if(PPU_hook) PPU_hook(RefreshAddr&0x3fff);
435                         dprintf("r [2007] %02x",ret);
436                         return ret;
437 }
438
439 static DECLFW(B2000)
440 {
441         /* NMI2? */
442                 FakedLineUpdate();
443                 PPUGenLatch=V;
444                 PPU[0]=V;
445                 TempAddr&=0xF3FF;
446                 TempAddr|=(V&3)<<10;
447 }
448
449 static DECLFW(B2001)
450 {
451         /* merged */
452                   FakedLineUpdate();
453                   PPUGenLatch=V;
454                   PPU[1]=V;
455                   if(V&0xE0)
456                    deemp=V>>5;
457                   //printf("$%04x:$%02x, %d\n",X.PC,V,scanline);
458 }
459
460 static DECLFW(B2002)
461 {
462         /* merged */
463                  PPUGenLatch=V;
464 }
465
466 static DECLFW(B2003)
467 {
468         /* merged */
469                 PPUGenLatch=V;
470                 PPU[3]=V;
471                 PPUSPL=V&0x7;
472 }
473
474 static DECLFW(B2004)
475 {
476         /* merged */
477                 PPUGenLatch=V;
478                 if(PPUSPL>=8)
479                 {
480                  if(PPU[3]>=8)
481                   SPRAM[PPU[3]]=V;
482                 }
483                 else
484                 {
485                  //printf("$%02x:$%02x\n",PPUSPL,V);
486                  SPRAM[PPUSPL]=V;
487                 }
488                 PPU[3]++;
489                 PPUSPL++;
490
491 }
492
493 static DECLFW(B2005)
494 {
495         /* merged */
496                 uint32 tmp=TempAddr;
497                 FakedLineUpdate();
498                 PPUGenLatch=V;
499                 if (!vtoggle)
500                 {
501                  tmp&=0xFFE0;
502                  tmp|=V>>3;
503                  XOffset=V&7;
504                 }
505                 else
506                 {
507                  tmp&=0x8C1F;
508                  tmp|=((V&~0x7)<<2);
509                  tmp|=(V&7)<<12;
510                 }
511
512                 TempAddr=tmp;
513                 vtoggle^=1;
514 }
515
516 static DECLFW(B2006)
517 {
518         /* merged */
519                        FakedLineUpdate();
520
521                        PPUGenLatch=V;
522                        if(!vtoggle)
523                        {
524                         TempAddr&=0x00FF;
525                         TempAddr|=(V&0x3f)<<8;
526                        }
527                        else
528                        {
529                         TempAddr&=0xFF00;
530                         TempAddr|=V;
531
532                         RefreshAddr=TempAddr;
533                         if(PPU_hook)
534                          PPU_hook(RefreshAddr);
535                        }
536                       vtoggle^=1;
537 }
538
539 static DECLFW(B2007)
540 {
541         /* merged */
542                         uint32 tmp=RefreshAddr&0x3FFF;
543                         PPUGenLatch=V;
544                         if(tmp>=0x3F00)
545                         {
546                          // hmmm....
547                          if(!(tmp&0xf))
548                           PALRAM[0x00]=PALRAM[0x04]=PALRAM[0x08]=PALRAM[0x0C]=V&0x3f;
549                          else if(tmp&3) PALRAM[(tmp&0x1f)]=V&0x3f;
550                         }
551                         else if(tmp<0x2000)
552                         {
553                           if(PPUCHRRAM&(1<<(tmp>>10)))
554                             VPage[tmp>>10][tmp]=V;
555                         }
556                         else
557                         {
558                          if(PPUNTARAM&(1<<((tmp&0xF00)>>10)))
559                           vnapage[((tmp&0xF00)>>10)][tmp&0x3FF]=V;
560                         }
561                         if (INC32) RefreshAddr+=32;
562                         else RefreshAddr++;
563                         if(PPU_hook) PPU_hook(RefreshAddr&0x3fff);
564 }
565
566 static DECLFW(B4014)
567 {
568         uint32 t=V<<8;
569         int x;
570
571         for(x=0;x<256;x++)
572          B2004(0x2004,X.DB=ARead[t+x](t+x));
573         X6502_AddCycles(512);
574 }
575
576 void BGRender(uint8 *target)
577 {
578         uint32 tem, vofs;
579         vofs=((PPU[0]&0x10)<<8) | ((RefreshAddr>>12)&7);
580
581         Pal[0]|=64;
582         Pal[4]|=64;
583         Pal[8]|=64;
584         Pal[0xC]|=64;
585         RefreshLine(target-XOffset, vofs);
586         Pal[0]&=63;
587         Pal[4]&=63;
588         Pal[8]&=63;
589         Pal[0xC]&=63;
590
591         if(!(PPU[1]&2))
592         {
593          tem=Pal[0]|0x40;
594          tem|=tem<<8;
595          tem|=tem<<16;
596          *(uint32 *)target=*(uint32 *)(target+4)=tem;
597         }
598 }
599
600 #ifdef FRAMESKIP
601 int FSkip=0;
602 void FCEUI_FrameSkip(int x)
603 {
604  FSkip=x;
605 }
606 #endif
607
608 /*      This is called at the beginning of each visible scanline */
609 static void LineUpdate(uint8 *target)
610 {
611         uint32 tem;
612         int y;
613
614         /* PRefreshLine() will not get called on skipped frames.  This
615          * could cause a problem, but the solution would be rather complex,
616          * due to the current sprite 0 hit code.
617          */
618         if(FSkip)
619         {
620          y=(int)SPRAM[0] + 1;
621          if(scanline==y && SpriteON) PPU_status|=0x40; // hack
622          return;
623         }
624
625         if(scanline < FSettings.FirstSLine || scanline > FSettings.LastSLine)
626         {
627            if(PPU_hook)
628             PRefreshLine();
629            y=(int)SPRAM[0] + 1;
630            if(scanline==y && SpriteON) PPU_status|=0x40;
631         }
632         else
633         {
634          if(ScreenON)
635          {
636            BGRender(target);
637          }
638          else
639          {
640            tem=Pal[0]|0x40;
641            tem|=tem << 8;
642            tem|=tem << 16;
643            FCEU_dwmemset(target,tem,256);
644          }
645         }
646
647         if(InputScanlineHook)
648          InputScanlineHook(target,spork?sprlinebuf:0,linestartts,256);
649 }
650
651
652 static void LineUpdateEnd(uint8 *target)
653 {
654 #ifdef GP2X
655  if(ScreenON || SpriteON)  // Yes, very el-cheapo.
656  {
657   if(PPU[1]&0x01)
658    block_and(target, 256, 0x30);
659  }
660  if((PPU[1]>>5)==0x7)
661   block_or(target, 256, 0xc0);
662  else if(PPU[1]&0xE0)
663   block_or(target, 256, 0x40);
664  else
665   block_andor(target, 256, 0x3f, 0x80);
666 #else
667  int x;
668
669  if(ScreenON || SpriteON)  // Yes, very el-cheapo.
670  {
671   if(PPU[1]&0x01)
672   {
673    for(x=63;x>=0;x--)
674    *(uint32 *)&target[x<<2]=(*(uint32*)&target[x<<2])&0x30303030;
675   }
676  }
677  if((PPU[1]>>5)==0x7)
678  {
679   for(x=63;x>=0;x--)
680    *(uint32 *)&target[x<<2]=((*(uint32*)&target[x<<2])&0x3f3f3f3f)|0xc0c0c0c0;
681  }
682  else if(PPU[1]&0xE0)
683   for(x=63;x>=0;x--)
684    *(uint32 *)&target[x<<2]=(*(uint32*)&target[x<<2])|0x40404040;
685  else
686   for(x=63;x>=0;x--)
687    *(uint32 *)&target[x<<2]=((*(uint32*)&target[x<<2])&0x3f3f3f3f)|0x80808080;
688 #endif
689
690  // black borders
691  ((uint32 *)target)[-2]=((uint32 *)target)[-1]=0;
692  ((uint32 *)target)[64]=((uint32 *)target)[65]=0;
693 }
694
695 #define PAL(c)  ((c)+cc)
696
697
698 static void PRefreshLine(void)
699 {
700          uint32 vofs;
701          int X1;
702          vofs=((PPU[0]&0x10)<<8) | ((RefreshAddr>>12)&7);
703          void (*PPU_hook_)(uint32 A) = PPU_hook;
704
705
706          for(X1=33;X1;X1--)
707          {
708                 uint32 zz2;
709                 uint32 vadr;
710
711                 zz2=(RefreshAddr>>10)&3;
712                 PPU_hook_(0x2000|(RefreshAddr&0xFFF));
713
714                 vadr=(vnapage[zz2][RefreshAddr&0x3ff]<<4)+vofs;
715
716                 PPU_hook_(vadr);
717
718                 if((RefreshAddr&0x1f)==0x1f)
719                  RefreshAddr^=0x41F;
720                 else
721                  RefreshAddr++;
722          }
723 }
724
725 /* This high-level graphics MMC5 emulation code was written
726    for MMC5 carts in "CL" mode.  It's probably not totally
727    correct for carts in "SL" mode.
728    */
729 static void RefreshLine_MMC5Hack1(uint8 *P, uint32 vofs)
730 {
731           int8 tochange, X1;
732
733           tochange=MMC5HackSPMode&0x1F;
734
735           for(X1=33;X1;X1--,P+=8)
736           {
737                 uint8 *C;
738                 uint8 cc,zz,zz2;
739                 uint32 vadr;
740
741                 if((tochange<=0 && MMC5HackSPMode&0x40) ||
742                    (tochange>0 && !(MMC5HackSPMode&0x40)))
743                 {
744                  uint8 xs,ys;
745
746                  xs=33-X1;
747                  ys=((scanline>>3)+MMC5HackSPScroll)&0x1F;
748                  if(ys>=0x1E) ys-=0x1E;
749                  vadr=(MMC5HackExNTARAMPtr[xs|(ys<<5)]<<4)+(vofs&7);
750
751                  C = MMC5HackVROMPTR+vadr;
752                  C += ((MMC5HackSPPage & 0x3f & MMC5HackVROMMask) << 12);
753
754                  cc=MMC5HackExNTARAMPtr[0x3c0+(xs>>2)+((ys&0x1C)<<1)];
755                  cc=((cc >> ((xs&2) + ((ys&0x2)<<1))) &3) <<2;
756                 }
757                 else
758                 {
759                  zz=RefreshAddr&0x1F;
760                  zz2=(RefreshAddr>>10)&3;
761                  vadr=(vnapage[zz2][RefreshAddr&0x3ff]<<4)+vofs;
762                  C = MMC5BGVRAMADR(vadr);
763                  cc=vnapage[zz2][0x3c0+(zz>>2)+((RefreshAddr&0x380)>>4)];
764                  cc=((cc >> ((zz&2) + ((RefreshAddr&0x40)>>4))) &3) <<2;
765                 }
766                 #include "fceline.h"
767
768                 if((RefreshAddr&0x1f)==0x1f)
769                  RefreshAddr^=0x41F;
770                 else
771                  RefreshAddr++;
772                 tochange--;
773           }
774 }
775
776 static void RefreshLine_MMC5Hack2(uint8 *P, uint32 vofs)
777 {
778           int8 tochange, X1;
779
780           tochange=MMC5HackSPMode&0x1F;
781
782           for(X1=33;X1;X1--,P+=8)
783           {
784                 uint8 *C;
785                 uint8 cc;
786                 uint8 zz2;
787                 uint32 vadr;
788
789                 if((tochange<=0 && MMC5HackSPMode&0x40) ||
790                    (tochange>0 && !(MMC5HackSPMode&0x40)))
791                 {
792                  uint8 xs,ys;
793
794                  xs=33-X1;
795                  ys=((scanline>>3)+MMC5HackSPScroll)&0x1F;
796                  if(ys>=0x1E) ys-=0x1E;
797                  vadr=(MMC5HackExNTARAMPtr[xs|(ys<<5)]<<4)+(vofs&7);
798
799                  C = MMC5HackVROMPTR+vadr;
800                  C += ((MMC5HackSPPage & 0x3f & MMC5HackVROMMask) << 12);
801
802                  cc=MMC5HackExNTARAMPtr[0x3c0+(xs>>2)+((ys&0x1C)<<1)];
803                  cc=((cc >> ((xs&2) + ((ys&0x2)<<1))) &3) <<2;
804                 }
805                 else
806                 {
807                  C=MMC5HackVROMPTR;
808                  zz2=(RefreshAddr>>10)&3;
809                  vadr = (vnapage[zz2][RefreshAddr & 0x3ff] << 4) + vofs;
810                  C += (((MMC5HackExNTARAMPtr[RefreshAddr & 0x3ff]) & 0x3f &
811                          MMC5HackVROMMask) << 12) + (vadr & 0xfff);
812                  vadr = (MMC5HackExNTARAMPtr[RefreshAddr & 0x3ff] & 0xC0)>> 4;
813                  cc = vadr;
814                 }
815                 #include "fceline.h"
816                 if((RefreshAddr&0x1f)==0x1f)
817                  RefreshAddr^=0x41F;
818                 else
819                  RefreshAddr++;
820                 tochange--;
821           }
822 }
823
824 static void RefreshLine_MMC5Hack3(uint8 *P, uint32 vofs)
825 {
826           int8 X1;
827
828           for(X1=33;X1;X1--,P+=8)
829           {
830                 uint8 *C;
831                 uint8 cc;
832                 uint8 zz2;
833                 uint32 vadr;
834
835                 C=MMC5HackVROMPTR;
836                 zz2=(RefreshAddr>>10)&3;
837                 vadr = (vnapage[zz2][RefreshAddr & 0x3ff] << 4) + vofs;
838                 C += (((MMC5HackExNTARAMPtr[RefreshAddr & 0x3ff]) & 0x3f &
839                         MMC5HackVROMMask) << 12) + (vadr & 0xfff);
840                 vadr = (MMC5HackExNTARAMPtr[RefreshAddr & 0x3ff] & 0xC0)>> 4;
841                 cc = vadr;
842
843                 #include "fceline.h"
844                 if((RefreshAddr&0x1f)==0x1f)
845                  RefreshAddr^=0x41F;
846                 else
847                  RefreshAddr++;
848           }
849 }
850
851 static void RefreshLine_MMC5Hack4(uint8 *P, uint32 vofs)
852 {
853           int8 X1;
854
855           for(X1=33;X1;X1--,P+=8)
856           {
857                 uint8 *C;
858                 uint8 cc,zz,zz2;
859                 uint32 vadr;
860
861                 zz=RefreshAddr&0x1F;
862                 zz2=(RefreshAddr>>10)&3;
863                 vadr=(vnapage[zz2][RefreshAddr&0x3ff]<<4)+vofs;
864                 C = MMC5BGVRAMADR(vadr);
865                 cc=vnapage[zz2][0x3c0+(zz>>2)+((RefreshAddr&0x380)>>4)];
866                 cc=((cc >> ((zz&2) + ((RefreshAddr&0x40)>>4))) &3) <<2;
867
868                 #include "fceline.h"
869
870                 if((RefreshAddr&0x1f)==0x1f)
871                  RefreshAddr^=0x41F;
872                 else
873                  RefreshAddr++;
874           }
875 }
876
877 static void RefreshLine_PPU_hook(uint8 *P, uint32 vofs)
878 {
879          int8 X1;
880          void (*PPU_hook_)(uint32 A) = PPU_hook;
881          uint32 rfraddr = RefreshAddr;
882          uint8 *page = vnapage[(rfraddr>>10)&3];
883
884          for(X1=33;X1;X1--,P+=8)
885          {
886                 uint8 *C;
887                 uint8 cc,zz;
888                 uint32 vadr;
889
890                 zz=rfraddr&0x1F;
891                 PPU_hook_(0x2000|(rfraddr&0xFFF));
892                 cc=page[0x3c0+(zz>>2)+((rfraddr&0x380)>>4)];
893                 cc=((cc >> ((zz&2) + ((rfraddr&0x40)>>4))) &3) <<2;
894                 vadr=(page[rfraddr&0x3ff]<<4)+vofs;
895                 C = VRAMADR(vadr);
896
897                 #include "fceline.h"
898
899                 PPU_hook_(vadr);
900
901                 if((rfraddr&0x1f)==0x1f) {
902                  rfraddr^=0x41F;
903                  page = vnapage[(rfraddr>>10)&3];
904                 } else
905                  rfraddr++;
906          }
907          RefreshAddr = rfraddr;
908 }
909
910 static void RefreshLine_normal(uint8 *P, uint32 vofs) // vofs is 0x107 max
911 {
912          int8 X1;
913          uint32 rfraddr = RefreshAddr;
914          uint8 *page = vnapage[(rfraddr>>10)&3];
915          uint32 cc2=0;
916
917          if ((rfraddr&0xc)!=0)
918           cc2=*(uint32 *) (page + ((rfraddr&0x380)>>4) + ((rfraddr&0x10)>>2) + 0x3c0);
919
920          for (X1=33;X1;X1--,P+=8)
921          {
922                 uint8 cc,*C;
923                 uint32 vadr;
924
925                 vadr=(page[rfraddr&0x3ff]<<4)+vofs;
926                 C = VRAMADR(vadr);
927                 if ((rfraddr&0xc)==0)
928                  cc2=*(uint32 *) (page + ((rfraddr&0x380)>>4) + ((rfraddr&0x10)>>2) + 0x3c0);
929                 cc=((cc2 >> ((rfraddr&2) + ((rfraddr&0x40)>>4) + ((rfraddr&0xc)<<1))) & 3) << 2;
930
931                 #include "fceline.h"
932
933                 if((rfraddr&0x1f)==0x1f) {
934                  rfraddr^=0x41F;
935                  page = vnapage[(rfraddr>>10)&3];
936                 } else
937                  rfraddr++;
938          }
939          RefreshAddr = rfraddr;
940 }
941
942 static void SetRefreshLine(void)
943 {
944         if(MMC5Hack && geniestage!=1)
945         {
946          if(MMC5HackCHRMode==0 && (MMC5HackSPMode&0x80))
947          {
948                  if (RefreshLine != RefreshLine_MMC5Hack1) printf("set refr RefreshLine_MMC5Hack1\n");
949                  RefreshLine = RefreshLine_MMC5Hack1;
950          }
951          else if(MMC5HackCHRMode==1 && (MMC5HackSPMode&0x80))
952          {
953                 if (RefreshLine != RefreshLine_MMC5Hack2) printf("set refr RefreshLine_MMC5Hack2\n");
954                  RefreshLine = RefreshLine_MMC5Hack2;
955          }
956          else if(MMC5HackCHRMode==1)
957          {
958                 if (RefreshLine != RefreshLine_MMC5Hack3) printf("set refr RefreshLine_MMC5Hack3\n");
959                  RefreshLine = RefreshLine_MMC5Hack3;
960          }
961          else
962          {
963                 if (RefreshLine != RefreshLine_MMC5Hack4) printf("set refr RefreshLine_MMC5Hack4\n");
964                  RefreshLine = RefreshLine_MMC5Hack4;
965          }
966         }       // End if(MMC5Hack)
967         else if(PPU_hook)
968         {
969                 if (RefreshLine != RefreshLine_PPU_hook) printf("set refr RefreshLine_PPU_hook\n");
970                 RefreshLine = RefreshLine_PPU_hook;
971         }
972         else
973         {
974                 if (RefreshLine != RefreshLine_normal) printf("set refr RefreshLine_normal\n");
975                 RefreshLine = RefreshLine_normal;
976         }
977 }
978
979 static INLINE
980 void Fixit2(void)
981 {
982    if(ScreenON || SpriteON)
983    {
984     uint32 rad=RefreshAddr;
985     rad&=0xFBE0;
986     rad|=TempAddr&0x041f;
987     RefreshAddr=rad;
988     //PPU_hook(RefreshAddr,-1);
989    }
990 }
991
992 static INLINE
993 void Fixit1(void)
994 {
995    if(ScreenON || SpriteON)
996    {
997     uint32 rad=RefreshAddr;
998
999     if((rad&0x7000)==0x7000)
1000     {
1001      rad^=0x7000;
1002      if((rad&0x3E0)==0x3A0)
1003      {
1004       rad^=0x3A0;
1005       rad^=0x800;
1006      }
1007      else
1008      {
1009       if((rad&0x3E0)==0x3e0)
1010        rad^=0x3e0;
1011       else rad+=0x20;
1012      }
1013     }
1014     else
1015      rad+=0x1000;
1016     RefreshAddr=rad;
1017     //PPU_hook(RefreshAddr,-1);
1018    }
1019 }
1020
1021
1022 // ============================//
1023 // end of new code
1024 // ===========================//
1025
1026 void ResetMapping(void)
1027 {
1028         int x;
1029
1030         SetReadHandler(0x0000,0xFFFF,ANull);
1031         SetWriteHandler(0x0000,0xFFFF,BNull);
1032
1033         SetReadHandler(0,0x7FF,ARAML);
1034         SetWriteHandler(0,0x7FF,BRAML);
1035
1036         SetReadHandler(0x800,0x1FFF,ARAMH);  /* Part of a little */
1037         SetWriteHandler(0x800,0x1FFF,BRAMH); /* hack for a small speed boost. */
1038
1039         for(x=0x2000;x<0x4000;x+=8)
1040         {
1041          ARead[x]=A200x;
1042          BWrite[x]=B2000;
1043          ARead[x+1]=A200x;
1044          BWrite[x+1]=B2001;
1045          ARead[x+2]=A2002;
1046          BWrite[x+2]=B2002;
1047          ARead[x+3]=A200x;
1048          BWrite[x+3]=B2003;
1049          ARead[x+4]=A200x;
1050          BWrite[x+4]=B2004;
1051          ARead[x+5]=A200x;
1052          BWrite[x+5]=B2005;
1053          ARead[x+6]=A200x;
1054          BWrite[x+6]=B2006;
1055          ARead[x+7]=A2007;
1056          BWrite[x+7]=B2007;
1057         }
1058
1059         BWrite[0x4014]=B4014;
1060         SetNESSoundMap();
1061         InitializeInput();
1062 }
1063
1064 int GameLoaded=0;
1065 void CloseGame(void)
1066 {
1067  FCEUI_StopMovie();
1068  if(GameLoaded)
1069  {
1070   if(FCEUGameInfo.type!=GIT_NSF)
1071    FCEU_FlushGameCheats(0,0);
1072   #ifdef NETWORK
1073   if(FSettings.NetworkPlay) KillNetplay();
1074   #endif
1075   GameInterface(GI_CLOSE, 0);
1076   CloseGenie();
1077   GameLoaded=0;
1078  }
1079 }
1080
1081 void ResetGameLoaded(void)
1082 {
1083         if(GameLoaded) CloseGame();
1084         GameStateRestore=0;
1085         PPU_hook=0;
1086         GameHBIRQHook=GameHBIRQHook2=0;
1087         GameExpSound.Fill=0;
1088         GameExpSound.RChange=0;
1089         if(GameExpSound.Kill)
1090          GameExpSound.Kill();
1091         GameExpSound.Kill=0;
1092         MapIRQHook=0;
1093         MMC5Hack=0;
1094         PAL&=1;
1095         pale=0;
1096
1097         FCEUGameInfo.name=0;
1098         FCEUGameInfo.type=GIT_CART;
1099         FCEUGameInfo.vidsys=GIV_USER;
1100         FCEUGameInfo.input[0]=FCEUGameInfo.input[1]=-1;
1101         FCEUGameInfo.inputfc=-1;
1102
1103         FCEUGameInfo.soundchan=0;
1104         FCEUGameInfo.soundrate=0;
1105         FCEUGameInfo.cspecial=0;
1106 }
1107
1108 char lastLoadedGameName [2048];
1109 int LoadGameLastError = 0;
1110 int UNIFLoad(const char *name, int fp);
1111 int iNESLoad(const char *name, int fp);
1112 int FDSLoad(const char *name, int fp);
1113 int NSFLoad(int fp);
1114
1115 FCEUGI *FCEUI_LoadGame(char *name)
1116 {
1117         char name2[512];
1118         int have_movie = 0, have_ips = 0;
1119         int fp;
1120
1121         //Exit=1;
1122         LoadGameLastError = 0;
1123         ResetGameLoaded();
1124
1125         strncpy(name2, name, sizeof(name2));
1126         name2[sizeof(name2)-1] = 0;
1127
1128         fp=FCEU_fopen(name2,"rb");
1129         if(!fp)
1130         {
1131          FCEU_PrintError("Error opening \"%s\"!",name);
1132          LoadGameLastError = 1;
1133          return 0;
1134         }
1135
1136         {
1137          char *p = name2 + strlen(name2) - 4;
1138          if (strcasecmp(p, ".fcm") == 0) printf("movie detected\n"), have_movie = 1;
1139          if (strcasecmp(p, ".ips") == 0) printf("ips detected\n"), have_ips = 1;
1140          if (have_movie || have_ips)
1141          {
1142           // movie detected
1143           FCEU_fclose(fp);
1144           *p = 0;
1145           fp=FCEU_fopen(name2,"rb");
1146           if (!fp && p - name2 > 2)
1147           {
1148            for (p--; p > name2 && *p != '.'; p--);
1149            *p = 0;
1150            fp=FCEU_fopen(name2,"rb");
1151           }
1152           if (!fp) {
1153            printf("no ROM for ips/movie\n");
1154            LoadGameLastError = 2;
1155            return 0;
1156           }
1157          }
1158         }
1159
1160         // do IPS patch
1161         if (have_ips)
1162         {
1163          FCEU_fclose(fp);
1164          FILE *ips = fopen(name, "rb");
1165          if (!ips) return 0;
1166          fp=FCEU_fopen_forcemem(name2);
1167          if (!fp) { fclose(ips); return 0; }
1168          ApplyIPS(ips, fp); // closes ips
1169         }
1170
1171         GetFileBase(name2);
1172         if(iNESLoad(name2,fp))
1173          goto endlseq;
1174         if(NSFLoad(fp))
1175          goto endlseq;
1176         if(FDSLoad(name2,fp))
1177          goto endlseq;
1178         if(UNIFLoad(name2,fp))
1179          goto endlseq;
1180
1181         FCEU_PrintError("An error occurred while loading the file.");
1182         FCEU_fclose(fp);
1183         // format handlers may set LoadGameLastError themselves.
1184         if (LoadGameLastError == 0) LoadGameLastError = 3;
1185         return 0;
1186
1187         endlseq:
1188         FCEU_fclose(fp);
1189         GameLoaded=1;
1190
1191         FCEU_ResetVidSys();
1192         if(FCEUGameInfo.type!=GIT_NSF)
1193          if(FSettings.GameGenie)
1194           OpenGenie();
1195
1196         PowerNES();
1197         #ifdef NETWORK
1198         if(FSettings.NetworkPlay) InitNetplay();
1199         #endif
1200         SaveStateRefresh();
1201         if(FCEUGameInfo.type!=GIT_NSF)
1202         {
1203          FCEU_LoadGamePalette();
1204          FCEU_LoadGameCheats(0);
1205         }
1206
1207         FCEU_ResetPalette();
1208         Exit=0;
1209
1210         if (have_movie)
1211                 FCEUI_LoadMovie(name, 1);
1212
1213         strcpy(lastLoadedGameName, name2);
1214
1215         return(&FCEUGameInfo);
1216 }
1217
1218
1219 void FCEU_ResetVidSys(void)
1220 {
1221  int w;
1222
1223  if(FCEUGameInfo.vidsys==GIV_NTSC)
1224   w=0;
1225  else if(FCEUGameInfo.vidsys==GIV_PAL)
1226   w=1;
1227  else
1228   w=FSettings.PAL;
1229
1230  if(w)
1231  {
1232   PAL=1;
1233   FSettings.FirstSLine=FSettings.UsrFirstSLine[1];
1234   FSettings.LastSLine=FSettings.UsrLastSLine[1];
1235  }
1236  else
1237  {
1238   PAL=0;
1239   FSettings.FirstSLine=FSettings.UsrFirstSLine[0];
1240   FSettings.LastSLine=FSettings.UsrLastSLine[0];
1241  }
1242  printf("ResetVidSys: PAL = %i\n", PAL);
1243  SetSoundVariables();
1244 }
1245
1246 int FCEUI_Initialize(void)
1247 {
1248         if(!InitVirtualVideo())
1249          return 0;
1250         memset(&FSettings,0,sizeof(FSettings));
1251         FSettings.UsrFirstSLine[0]=8;
1252         FSettings.UsrFirstSLine[1]=0;
1253         FSettings.UsrLastSLine[0]=FSettings.UsrLastSLine[1]=239;
1254         FSettings.SoundVolume=100;
1255
1256         FCEUI_Initialize098();
1257         FCEUI_SetEmuMode(0);
1258
1259         return 1;
1260 }
1261
1262 void FCEUI_Kill(void)
1263 {
1264  FCEU_KillGenie();
1265 }
1266
1267 static void EmLoop(void);
1268
1269 int use098code = 0;
1270 void (*ResetNES)(void) = 0;
1271 void (*PowerNES)(void) = 0;
1272 void (*FCEUI_Emulate)(void) = 0;
1273
1274 void FCEUI_SetEmuMode(int is_new)
1275 {
1276    use098code = is_new;
1277    if (is_new)
1278    {
1279     ResetNES=ResetNES098;
1280     PowerNES=PowerNES098;
1281     SetSoundVariables=SetSoundVariables098;
1282     FCEUI_Emulate=FCEUI_Emulate098;
1283    }
1284    else
1285    {
1286     ResetNES=ResetNES081;
1287     PowerNES=PowerNES081;
1288     SetSoundVariables=SetSoundVariables081;
1289     FCEUI_Emulate=EmLoop;
1290    }
1291 }
1292
1293 void MMC5_hb(int);     /* Ugh ugh ugh. */
1294 static void DoLine(void)
1295 {
1296    uint8 *target=XBuf+scanline*320+32;
1297
1298    LineUpdate(target);
1299
1300    if(MMC5Hack && (ScreenON || SpriteON)) MMC5_hb(scanline);
1301
1302    X6502_Run(256);
1303
1304    // check: Battletoads & Double Dragon, Addams Family
1305    // sky glitches in SMB1 if done wrong
1306    FakedLineUpdate();
1307
1308 #ifdef FRAMESKIP
1309    if(!FSkip)
1310 #endif
1311    if(scanline>=FSettings.FirstSLine && scanline<=FSettings.LastSLine)
1312    {
1313     if(SpriteON && spork)
1314      CopySprites(target);
1315
1316     LineUpdateEnd(target);
1317    }
1318    sphitx=0x100;
1319
1320    if(ScreenON || SpriteON)
1321     FetchSpriteData();
1322
1323    // DoHBlank();
1324    if(GameHBIRQHook && (ScreenON || SpriteON) && ((PPU[0]&0x38)!=0x18))
1325    {
1326     X6502_Run(6);
1327     Fixit2();
1328     X6502_Run(4);
1329     GameHBIRQHook();
1330     X6502_Run(85-10-16);
1331    }
1332    else
1333    {
1334     X6502_Run(6);  // Tried 65, caused problems with Slalom(maybe others)
1335     Fixit2();
1336     X6502_Run(85-6-16);
1337    }
1338
1339    if(SpriteON)
1340     RefreshSprites();
1341    if(GameHBIRQHook2 && (ScreenON || SpriteON))
1342     GameHBIRQHook2();
1343    scanline++;
1344    if (scanline<240)
1345     ResetRL(XBuf+scanline*320+32);
1346    X6502_Run(16);
1347 }
1348
1349
1350 static void EmLoop(void)
1351 {
1352  for(;;)
1353  {
1354   int x;
1355   uint32 scanlines_per_frame = PAL ? 312 : 262;
1356   UpdateInput();
1357   FCEU_ApplyPeriodicCheats();
1358
1359   // FCEUPPU_Loop:
1360   if(ppudead) /* Needed for Knight Rider, possibly others. */
1361   {
1362    //memset(XBuf, 0, 320*240);
1363    //X6502_Run(scanlines_per_frame*(256+85));
1364    int lines;
1365    for (lines=scanlines_per_frame;lines;lines--)
1366      X6502_Run(256+85);
1367    ppudead--;
1368    goto update;
1369   }
1370
1371   X6502_Run(256+85);
1372
1373   PPU[2]|=0x80;
1374   PPU[3]=PPUSPL=0;             /* Not sure if this is correct.  According
1375                                   to Matt Conte and my own tests, it is.  Timing is probably
1376                                   off, though.  NOTE:  Not having this here
1377                                   breaks a Super Donkey Kong game. */
1378
1379   X6502_Run(12);                /* I need to figure out the true nature and length
1380                                    of this delay.
1381                                 */
1382   if(FCEUGameInfo.type==GIT_NSF)
1383    DoNSFFrame();
1384   else if(VBlankON)
1385    TriggerNMI();
1386
1387   // Note: this is needed for asm core
1388   // Warning: using 'scanline' var here breaks Castlevania III
1389   {
1390    int lines;
1391    X6502_Run(256+85-12);
1392    for (lines=scanlines_per_frame-242-1;lines;lines--)
1393      X6502_Run(256+85);
1394   }
1395   // X6502_Run((scanlines_per_frame-242)*(256+85)-12);
1396   PPU_status&=0x1f;
1397   X6502_Run(256);
1398
1399   {
1400    if(ScreenON || SpriteON)
1401    {
1402     if(GameHBIRQHook)
1403      GameHBIRQHook();
1404      if(PPU_hook)
1405       for(x=0;x<42;x++) {PPU_hook(0x2000); PPU_hook(0);} // ugh
1406     if(GameHBIRQHook2)
1407      GameHBIRQHook2();
1408    }
1409
1410    X6502_Run(85-16);
1411
1412    if(ScreenON || SpriteON)
1413    {
1414     RefreshAddr=TempAddr;
1415     if(PPU_hook) PPU_hook(RefreshAddr&0x3fff);
1416    }
1417    spork=0;
1418    ResetRL(XBuf+32);
1419
1420    X6502_Run(16-kook);
1421    kook ^= 1;
1422   }
1423
1424   if(FCEUGameInfo.type==GIT_NSF)
1425   {
1426    // run scanlines for asm core to fuction
1427    for(scanline=0;scanline<240;scanline++)
1428     X6502_Run(256+85);
1429   }
1430   else
1431   {
1432    int x,max,maxref;
1433
1434    deemp=PPU[1]>>5;
1435    SetRefreshLine();
1436    for(scanline=0;scanline<240;)       // scanline is incremented in  DoLine.  Evil. :/
1437    {
1438     deempcnt[deemp]++;
1439     DoLine();
1440    }
1441    if(MMC5Hack && (ScreenON || SpriteON)) MMC5_hb(scanline);
1442    for(x=1,max=0,maxref=0;x<7;x++)
1443    {
1444     if(deempcnt[x]>max)
1445     {
1446      max=deempcnt[x];
1447      maxref=x;
1448     }
1449     deempcnt[x]=0;
1450    }
1451    SetNESDeemph(maxref,0);
1452   }
1453
1454 update:
1455   if(Exit)
1456   {
1457    //CloseGame();
1458    break;
1459   }
1460
1461   {
1462    int ssize;
1463
1464    ssize=FlushEmulateSound();
1465
1466    timestampbase += timestamp;
1467    timestamp = 0;
1468
1469    #ifdef FRAMESKIP
1470    if(FSkip)
1471    {
1472     FCEU_PutImageDummy();
1473     FSkip--;
1474     FCEUD_Update(0,WaveFinalMono,ssize);
1475    }
1476    else
1477    #endif
1478    {
1479     FCEU_PutImage();
1480     FCEUD_Update(XBuf+8,WaveFinalMono,ssize);
1481    }
1482   }
1483
1484  } // for
1485 }
1486
1487 void FCEUI_CloseGame(void)
1488 {
1489         Exit=1;
1490 }
1491
1492 static void ResetPPU(void)
1493 {
1494         VRAMBuffer=PPU[0]=PPU[1]=PPU[2]=PPU[3]=0;
1495         PPUSPL=0;
1496         PPUGenLatch=0;
1497         RefreshAddr=TempAddr=0;
1498         vtoggle = 0;
1499         ppudead = 2;
1500         kook = 0;
1501 }
1502
1503 static void PowerPPU(void)
1504 {
1505         memset(NTARAM,0x00,0x800);
1506         memset(PALRAM,0x00,0x20);
1507         memset(SPRAM,0x00,0x100);
1508         ResetPPU();
1509 }
1510
1511 void ResetNES081(void)
1512 {
1513         if(!GameLoaded) return;
1514         GameInterface(GI_RESETM2, 0);
1515         ResetSound();
1516         ResetPPU();
1517         X6502_Reset();
1518 }
1519
1520 static void FCEU_MemoryRand(uint8 *ptr, uint32 size)
1521 {
1522  int x=0;
1523  while(size)
1524  {
1525   *ptr=(x&4)?0xFF:0x00;
1526   x++;
1527   size--;
1528   ptr++;
1529  }
1530 }
1531
1532 void PowerNES081(void)
1533 {
1534         if(!GameLoaded) return;
1535
1536         FCEU_CheatResetRAM();
1537         FCEU_CheatAddRAM(2,0,RAM);
1538
1539         GeniePower();
1540
1541 #ifndef DEBUG_ASM_6502
1542         FCEU_MemoryRand(RAM,0x800);
1543 #else
1544         memset(RAM,0x00,0x800);
1545 #endif
1546         ResetMapping();
1547         PowerSound();
1548         PowerPPU();
1549         GameInterface(GI_POWER, 0);
1550         if(FCEUGameInfo.type==GIT_VSUNI)
1551          FCEU_VSUniPower();
1552 #ifdef ASM_6502
1553         if (geniestage)
1554          GenieSetPages(0);
1555 #endif
1556         timestampbase=0;
1557         X6502_Power();
1558         FCEU_PowerCheats();
1559 }
1560
1561
1562 /* savestate stuff */
1563 uint16 TempAddrT,RefreshAddrT;
1564
1565 SFORMAT FCEUPPU_STATEINFO[]={
1566  { NTARAM, 0x800, "NTAR"},
1567  { PALRAM, 0x20, "PRAM"},
1568  { SPRAM, 0x100, "SPRA"},
1569  { PPU, 0x4, "PPUR"},
1570  { &XOffset, 1, "XOFF"},
1571  { &vtoggle, 1, "VTOG"},
1572  { &RefreshAddrT, 2|RLSB, "RADD"},
1573  { &TempAddrT, 2|RLSB, "TADD"},
1574  { &VRAMBuffer, 1, "VBUF"},
1575  { &PPUGenLatch, 1, "PGEN"},
1576  // from 0.98.15
1577  { &kook, 1, "KOOK"},
1578  { &ppudead, 1, "DEAD"},
1579  { &PPUSPL, 1, "PSPL"},
1580  { 0 }
1581  };
1582
1583