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