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