diff --git a/src/ppu.cpp b/src/ppu.cpp index 28f312d2..12e673a1 100644 --- a/src/ppu.cpp +++ b/src/ppu.cpp @@ -1,19 +1,19 @@ /* FCE Ultra - NES/Famicom Emulator -* +* * Copyright notice for this file: * Copyright (C) 1998 BERO * Copyright (C) 2003 Xodnizel -* +* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or +* the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. -* +* * This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. -* +* * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -42,7 +42,7 @@ #define VBlankON (PPU[0]&0x80) //Generate VBlank NMI -#define Sprite16 (PPU[0]&0x20) //Sprites 8x16/8x8 +#define Sprite16 (PPU[0]&0x20) //Sprites 8x16/8x8 #define BGAdrHI (PPU[0]&0x10) //BG pattern adr $0000/$1000 #define SpAdrHI (PPU[0]&0x08) //Sprite pattern adr $0000/$1000 #define INC32 (PPU[0]&0x04) //auto increment 1/32 @@ -57,7 +57,7 @@ #define PPU_status (PPU[2]) -#define Pal (PALRAM) +#define Pal (PALRAM) static void FetchSpriteData(void); static void RefreshLine(int lastpixel); @@ -155,7 +155,7 @@ struct PPUREGS { //temp unlatched regs (need savestating, can be written to at any time) uint32 _fv, _v, _h, _vt, _ht; - + //other regs that need savestating uint32 fh;//3 (horz scroll) uint32 s;//1 ($2000 bit 4: "Background pattern table address (0: $0000; 1: $1000)") @@ -172,11 +172,11 @@ struct PPUREGS { fv = v = h = vt = ht = 0; fh = par = s = 0; _fv = _v = _h = _vt = _ht = 0; - status.cycle = 0; + status.cycle = 0; status.end_cycle = 341; - status.sl = 241; + status.sl = 241; } - + void install_latches() { fv = _fv; v = _v; @@ -196,8 +196,8 @@ struct PPUREGS { } void increment_hsc() { - //The first one, the horizontal scroll counter, consists of 6 bits, and is - //made up by daisy-chaining the HT counter to the H counter. The HT counter is + //The first one, the horizontal scroll counter, consists of 6 bits, and is + //made up by daisy-chaining the HT counter to the H counter. The HT counter is //then clocked every 8 pixel dot clocks (or every 8/3 CPU clock cycles). ht++; h += (ht>>5); @@ -222,12 +222,12 @@ struct PPUREGS { uint32 get_2007access() { return ((fv&3)<<0xC) | (v<<0xB) | (h<<0xA) | (vt<<5) | ht; } - - //The PPU has an internal 4-position, 2-bit shifter, which it uses for - //obtaining the 2-bit palette select data during an attribute table byte - //fetch. To represent how this data is shifted in the diagram, letters a..c - //are used in the diagram to represent the right-shift position amount to - //apply to the data read from the attribute data (a is always 0). This is why + + //The PPU has an internal 4-position, 2-bit shifter, which it uses for + //obtaining the 2-bit palette select data during an attribute table byte + //fetch. To represent how this data is shifted in the diagram, letters a..c + //are used in the diagram to represent the right-shift position amount to + //apply to the data read from the attribute data (a is always 0). This is why //you only see bits 0 and 1 used off the read attribute data in the diagram. uint32 get_atread() { return 0x2000 | (v<<0xB) | (h<<0xA) | 0x3C0 | ((vt&0x1C)<<1) | ((ht&0x1C)>>2); @@ -239,15 +239,15 @@ struct PPUREGS { } void increment2007(bool by32) { - - //If the VRAM address increment bit (2000.2) is clear (inc. amt. = 1), all the - //scroll counters are daisy-chained (in the order of HT, VT, H, V, FV) so that - //the carry out of each counter controls the next counter's clock rate. The - //result is that all 5 counters function as a single 15-bit one. Any access to + + //If the VRAM address increment bit (2000.2) is clear (inc. amt. = 1), all the + //scroll counters are daisy-chained (in the order of HT, VT, H, V, FV) so that + //the carry out of each counter controls the next counter's clock rate. The + //result is that all 5 counters function as a single 15-bit one. Any access to //2007 clocks the HT counter here. // - //If the VRAM address increment bit is set (inc. amt. = 32), the only - //difference is that the HT counter is no longer being clocked, and the VT + //If the VRAM address increment bit is set (inc. amt. = 32), the only + //difference is that the HT counter is no longer being clocked, and the VT //counter is now being clocked by access to 2007. if(by32) { vt++; @@ -302,7 +302,7 @@ static void makeppulut(void) // printf("%08x\n",ppulut3[xo|(cc<<3)]); } } -} +} static int ppudead=1; static int kook=0; @@ -318,16 +318,16 @@ uint32 MMC5HackVROMMask=0; uint8 *MMC5HackExNTARAMPtr=0; uint8 *MMC5HackVROMPTR=0; uint8 MMC5HackCHRMode=0; -uint8 MMC5HackSPMode=0; +uint8 MMC5HackSPMode=0; uint8 MMC50x5130=0; -uint8 MMC5HackSPScroll=0; +uint8 MMC5HackSPScroll=0; uint8 MMC5HackSPPage=0; uint8 VRAMBuffer=0,PPUGenLatch=0; uint8 *vnapage[4]; -uint8 PPUNTARAM=0; -uint8 PPUCHRRAM=0; +uint8 PPUNTARAM=0; +uint8 PPUCHRRAM=0; //Color deemphasis emulation. Joy... static uint8 deemp=0; @@ -341,7 +341,7 @@ uint8 XOffset=0; uint32 TempAddr=0,RefreshAddr=0; -static int maxsprites=8; +static int maxsprites=8; //scanline is equal to the current visible scanline we're on. int scanline; @@ -365,7 +365,7 @@ uint8 * MMC5BGVRAMADR(uint32 V) { extern uint8 mmc5ABMode; /* A=0, B=1 */ if(mmc5ABMode==0) return MMC5SPRVRAMADR(V); - else + else return &MMC5BGVPage[(V)>>10][(V)]; } else return &MMC5BGVPage[(V)>>10][(V)]; } @@ -409,7 +409,7 @@ inline void FFCEUX_PPUWrite_Default(uint32 A, uint8 V) { { if(PPUCHRRAM&(1<<(tmp>>10))) VPage[tmp>>10][tmp]=V; - } + } else if (tmp<0x3F00) { if(PPUNTARAM&(1<<((tmp&0xF00)>>10))) @@ -420,7 +420,7 @@ inline void FFCEUX_PPUWrite_Default(uint32 A, uint8 V) { if (!(tmp & 3)) { if (!(tmp & 0xC)) - PALRAM[0x00] = PALRAM[0x04] = + PALRAM[0x00] = PALRAM[0x04] = PALRAM[0x08] = PALRAM[0x0C] = V & 0x3F; else UPALRAM[((tmp & 0xC) >> 2) - 1] = V & 0x3F; @@ -440,7 +440,7 @@ uint8 FASTCALL FFCEUX_PPURead_Default(uint32 A) { return VPage[tmp>>10][tmp]; } else if (tmp < 0x3F00) - { + { return vnapage[(tmp>>10)&0x3][tmp&0x3FF]; } else @@ -455,7 +455,7 @@ uint8 FASTCALL FFCEUX_PPURead_Default(uint32 A) { } else ret = PALRAM[tmp & 0x1F]; - + if (GRAYSCALE) ret &= 0x30; return ret; @@ -484,7 +484,7 @@ void ppu_getScroll(int &xpos, int &ypos) { xpos = ((RefreshAddr & 0x400) >> 2) | ((RefreshAddr & 0x1F) << 3) | XOffset; - ypos = ((RefreshAddr & 0x3E0) >> 2) | ((RefreshAddr & 0x7000) >> 12); + ypos = ((RefreshAddr & 0x3E0) >> 2) | ((RefreshAddr & 0x7000) >> 12); if(RefreshAddr & 0x800) ypos += 240; } } @@ -498,7 +498,7 @@ static DECLFR(A2002) //i think we should only reset the state machine for 2005/2006 //ppur.clear_latches(); } - + uint8 ret; FCEUPPU_LineUpdate(); @@ -528,9 +528,9 @@ static DECLFR(A2004) * to 0xFF */ if (ppur.status.cycle < 64) return spr_read.ret = 0xFF; - else + else { - for (int i = spr_read.last; + for (int i = spr_read.last; i != ppur.status.cycle; ++i) { if (i < 256) @@ -539,11 +539,11 @@ static DECLFR(A2004) { case 0: if (spr_read.count < 2) - spr_read.ret = (PPU[3] & 0xF8) + spr_read.ret = (PPU[3] & 0xF8) + (spr_read.count << 2); else spr_read.ret = spr_read.count << 2; - spr_read.found_pos[spr_read.found] = + spr_read.found_pos[spr_read.found] = spr_read.ret; spr_read.ret = SPRAM[spr_read.ret]; @@ -551,8 +551,8 @@ static DECLFR(A2004) if (i & 1) //odd cycle { //see if in range - if ( !((ppur.status.sl - 1 - - spr_read.ret) + if ( !((ppur.status.sl - 1 - + spr_read.ret) & ~(Sprite16 ? 0xF : 0x7)) ) { @@ -560,7 +560,7 @@ static DECLFR(A2004) spr_read.fetch = 1; spr_read.mode = 1; } - else + else { if (++spr_read.count == 64) { @@ -598,23 +598,23 @@ static DECLFR(A2004) } if (spr_read.count < 2) - spr_read.ret = (PPU[3] & 0xF8) + spr_read.ret = (PPU[3] & 0xF8) + (spr_read.count << 2); else spr_read.ret = spr_read.count << 2; - spr_read.ret = SPRAM[spr_read.ret | + spr_read.ret = SPRAM[spr_read.ret | spr_read.fetch]; break; - case 2: //8th sprite fetched - spr_read.ret = SPRAM[(spr_read.count << 2) + case 2: //8th sprite fetched + spr_read.ret = SPRAM[(spr_read.count << 2) | spr_read.fetch]; if (i & 1) { - if ( !((ppur.status.sl - 1 - + if ( !((ppur.status.sl - 1 - SPRAM[((spr_read.count << 2) - | spr_read.fetch)]) - & ~((Sprite16) ? 0xF : 0x7)) ) + | spr_read.fetch)]) + & ~((Sprite16) ? 0xF : 0x7)) ) { spr_read.fetch = 1; spr_read.mode = 3; @@ -626,20 +626,20 @@ static DECLFR(A2004) spr_read.count = 0; spr_read.mode = 4; } - spr_read.fetch = + spr_read.fetch = (spr_read.fetch + 1) & 3; } } spr_read.ret = spr_read.count; break; case 3: //9th sprite overflow detected - spr_read.ret = SPRAM[spr_read.count + spr_read.ret = SPRAM[spr_read.count | spr_read.fetch]; if (i & 1) { if (++spr_read.fetch == 4) { - spr_read.count = (spr_read.count + spr_read.count = (spr_read.count + 1) & 63; spr_read.mode = 4; } @@ -647,7 +647,7 @@ static DECLFR(A2004) break; case 4: //read OAM[n][0] until hblank if (i & 1) - spr_read.count = + spr_read.count = (spr_read.count + 1) & 63; spr_read.fetch = 0; spr_read.ret = SPRAM[spr_read.count << 2]; @@ -664,13 +664,13 @@ static DECLFR(A2004) spr_read.ret = SPRAM[252]; spr_read.num = 0; } - else + else spr_read.ret = 0xFF; } else if ((i & 7) < 4) - { - spr_read.ret = - SPRAM[spr_read.found_pos[spr_read.ret] + { + spr_read.ret = + SPRAM[spr_read.found_pos[spr_read.ret] | spr_read.fetch++]; if (spr_read.fetch == 4) spr_read.fetch = 0; @@ -679,7 +679,7 @@ static DECLFR(A2004) spr_read.ret = SPRAM[spr_read.found_pos [spr_read.ret | 3]]; } - else + else { if (!spr_read.found) spr_read.ret = SPRAM[252]; @@ -716,7 +716,7 @@ uint8 ret; FCEUPPU_LineUpdate(); ret = SPRAM[PPU[3]]; -if(PPUSPL>=8) +if(PPUSPL>=8) { if(PPU[3]>=8) ret = SPRAM[PPU[3]]; @@ -743,7 +743,7 @@ static DECLFR(A2007) RefreshAddr = ppur.get_2007access() & 0x3FFF; if ((RefreshAddr & 0x3F00) == 0x3F00) { - //if it is in the palette range bypass the + //if it is in the palette range bypass the //delayed read, and what gets filled in the temp //buffer is the address - 0x1000, also //if grayscale is set then the return is AND with 0x30 @@ -782,7 +782,7 @@ static DECLFR(A2007) VRAMBuffer=VPage[tmp>>10][tmp]; } else if (tmp < 0x3F00) - { + { VRAMBuffer=vnapage[(tmp>>10)&0x3][tmp&0x3FF]; } } @@ -790,8 +790,24 @@ static DECLFR(A2007) if(!fceuindbg) #endif { - if(scanline<240) - Fixit1(); + if((ScreenON || SpriteON) && (scanline < 240)) + { + uint32 rad=RefreshAddr; + + if((rad&0x7000)==0x7000) + { + rad^=0x7000; + if((rad&0x3E0)==0x3A0) + rad^=0xBA0; + else if((rad&0x3E0)==0x3e0) + rad^=0x3e0; + else + rad+=0x20; + } + else + rad+=0x1000; + RefreshAddr=rad; + } else { if (INC32) @@ -861,17 +877,17 @@ static DECLFW(B2004) if ((PPU[3] & 3) == 2) V &= 0xE3; SPRAM[PPU[3]] = V; - PPU[3] = (PPU[3] + 1) & 0xFF; - } + PPU[3] = (PPU[3] + 1) & 0xFF; + } else { - if(PPUSPL>=8) + if(PPUSPL>=8) { if(PPU[3]>=8) SPRAM[PPU[3]]=V; } else - { + { //printf("$%02x:$%02x\n",PPUSPL,V); SPRAM[PPUSPL]=V; } @@ -888,13 +904,13 @@ static DECLFW(B2005) if(!vtoggle) { tmp&=0xFFE0; - tmp|=V>>3; + tmp|=V>>3; XOffset=V&7; ppur._ht = V>>3; ppur.fh = V&7; } else - { + { tmp&=0x8C1F; tmp|=((V&~0x7)<<2); tmp|=(V&7)<<12; @@ -902,7 +918,7 @@ static DECLFW(B2005) ppur._fv = V&7; } TempAddr=tmp; - vtoggle^=1; + vtoggle^=1; } @@ -913,11 +929,11 @@ static DECLFW(B2006) PPUGenLatch=V; - if(!vtoggle) + if(!vtoggle) { TempAddr&=0x00FF; TempAddr|=(V&0x3f)<<8; - + ppur._vt &= 0x07; ppur._vt |= (V&0x3)<<3; ppur._h = (V>>2)&1; @@ -925,7 +941,7 @@ static DECLFW(B2006) ppur._fv = (V>>4)&3; } else - { + { TempAddr&=0xFF00; TempAddr|=V; @@ -954,7 +970,7 @@ static DECLFW(B2007) //printf("%04x ",RefreshAddr); ppur.increment2007(INC32!=0); RefreshAddr = ppur.get_2007access(); - } + } else { //printf("%04x ",tmp); @@ -970,7 +986,7 @@ static DECLFW(B2007) { if(PPUCHRRAM&(1<<(tmp>>10))) VPage[tmp>>10][tmp]=V; - } + } else { if(PPUNTARAM&(1<<((tmp&0xF00)>>10))) @@ -997,7 +1013,7 @@ static DECLFW(B4014) #define GETLASTPIXEL (PAL?((timestamp*48-linestartts)/15) : ((timestamp*48-linestartts)>>4) ) static uint8 *Pline,*Plinef; -static int firsttile; +static int firsttile; int linestartts; //no longer static so the debugger can see it static int tofix=0; @@ -1006,12 +1022,12 @@ static void ResetRL(uint8 *target) memset(target,0xFF,256); InputScanlineHook(0,0,0,0); Plinef=target; - Pline=target; + Pline=target; firsttile=0; linestartts=timestamp*48+X.count; tofix=0; FCEUPPU_LineUpdate(); - tofix=1; + tofix=1; } static uint8 sprlinebuf[256+8]; @@ -1026,7 +1042,7 @@ void FCEUPPU_LineUpdate(void) int l=GETLASTPIXEL; RefreshLine(l); } -} +} static bool rendersprites=true, renderbg=true; @@ -1055,10 +1071,10 @@ void FCEUI_GetRenderPlanes(bool& sprites, bool& bg) //{ // uint8 *P=XBuf+16*256; // int bgh; -// int y; -// int X1; +// int y; +// int X1; // for(bgh=0;bgh<2;bgh++) -// for(y=0;y<16*8;y++) +// for(y=0;y<16*8;y++) // for(P=XBuf+bgh*128+(16+y)*256,X1=16;X1;X1--,P+=8) // { // uint8 *C; @@ -1073,7 +1089,7 @@ void FCEUI_GetRenderPlanes(bool& sprites, bool& bg) // cc=0; // //#include "pputile.inc" // } -//} +//} static void CheckSpriteHit(int p); @@ -1099,7 +1115,7 @@ static void CheckSpriteHit(int p) for(x=sphitx;x<(sphitx+8) && x>(x-sphitx))) && !(Plinef[x]&64) && x < 255) + if((sphitdata&(0x80>>(x-sphitx))) && !(Plinef[x]&64) && x < 255) { PPU_status|=0x40; //printf("Ha: %d, %d, Hita: %d, %d, %d, %d, %d\n",p,p&~7,scanline,GETLASTPIXEL-16,&Plinef[x],Pline,Pline-Plinef); @@ -1110,12 +1126,12 @@ static void CheckSpriteHit(int p) break; } } -} +} -//spork the world. Any sprites on this line? Then this will be set to 1. +//spork the world. Any sprites on this line? Then this will be set to 1. //Needed for zapper emulation and *gasp* sprite emulation. -static int spork=0; - +static int spork=0; + // lasttile is really "second to last tile." static void RefreshLine(int lastpixel) { @@ -1176,7 +1192,7 @@ static void RefreshLine(int lastpixel) tofix=0; } - if((lastpixel-16)>=0) + if((lastpixel-16)>=0) { InputScanlineHook(Plinef,spork?sprlinebuf:0,linestartts,lasttile*8-16); } @@ -1184,12 +1200,12 @@ static void RefreshLine(int lastpixel) } //Priority bits, needed for sprite emulation. - Pal[0]|=64; + Pal[0]|=64; Pal[4]|=64; Pal[8]|=64; Pal[0xC]|=64; - //This high-level graphics MMC5 emulation code was written for MMC5 carts in "CL" mode. + //This high-level graphics MMC5 emulation code was written for MMC5 carts in "CL" mode. //It's probably not totally correct for carts in "SL" mode. #define PPUT_MMC5 @@ -1209,7 +1225,7 @@ static void RefreshLine(int lastpixel) } else { -#include "pputile.inc" +#include "pputile.inc" } tochange--; } @@ -1269,16 +1285,16 @@ static void RefreshLine(int lastpixel) #undef RefreshAddr //Reverse changes made before. - Pal[0]&=63; + Pal[0]&=63; Pal[4]&=63; Pal[8]&=63; Pal[0xC]&=63; RefreshAddr=smorkus; - if(firsttile<=2 && 2=0) { InputScanlineHook(Plinef,spork?sprlinebuf:0,linestartts,lasttile*8-16); @@ -1592,9 +1608,9 @@ static void FetchSpriteData(void) } //if(ns>=7) //printf("%d %d\n",scanline,ns); - - //Handle case when >8 sprites per scanline option is enabled. - if(ns>8) PPU_status|=0x20; + + //Handle case when >8 sprites per scanline option is enabled. + if(ns>8) PPU_status|=0x20; else if(PPU_hook) { for(n=0;n<(8-ns);n++) @@ -1646,13 +1662,13 @@ static void RefreshSprites(void) ((J>>1)&0x08) | ((J>>3)&0x04) | ((J>>5)&0x02) | - ((J>>7)&0x01); + ((J>>7)&0x01); } C = sprlinebuf+x; VB = (PALRAM+0x10)+((atr&3)<<2); - if(atr&SP_BACK) + if(atr&SP_BACK) { if(atr&H_FLIP) { @@ -1672,9 +1688,9 @@ static void RefreshSprites(void) pixdata>>=4; if(J&0x01) C[0]=VB[pixdata]|0x40; } else { - if(J&0x80) C[0]=VB[pixdata&3]|0x40; + if(J&0x80) C[0]=VB[pixdata&3]|0x40; pixdata>>=4; - if(J&0x40) C[1]=VB[pixdata&3]|0x40; + if(J&0x40) C[1]=VB[pixdata&3]|0x40; pixdata>>=4; if(J&0x20) C[2]=VB[pixdata&3]|0x40; pixdata>>=4; @@ -1691,9 +1707,9 @@ static void RefreshSprites(void) } else { if(atr&H_FLIP) { - if(J&0x80) C[7]=VB[pixdata&3]; + if(J&0x80) C[7]=VB[pixdata&3]; pixdata>>=4; - if(J&0x40) C[6]=VB[pixdata&3]; + if(J&0x40) C[6]=VB[pixdata&3]; pixdata>>=4; if(J&0x20) C[5]=VB[pixdata&3]; pixdata>>=4; @@ -1706,10 +1722,10 @@ static void RefreshSprites(void) if(J&0x02) C[1]=VB[pixdata&3]; pixdata>>=4; if(J&0x01) C[0]=VB[pixdata]; - }else{ - if(J&0x80) C[0]=VB[pixdata&3]; + }else{ + if(J&0x80) C[0]=VB[pixdata&3]; pixdata>>=4; - if(J&0x40) C[1]=VB[pixdata&3]; + if(J&0x40) C[1]=VB[pixdata&3]; pixdata>>=4; if(J&0x20) C[2]=VB[pixdata&3]; pixdata>>=4; @@ -1839,7 +1855,7 @@ void PPU_ResetHooks() void FCEUPPU_Reset(void) { - VRAMBuffer=PPU[0]=PPU[1]=PPU_status=PPU[3]=0; + VRAMBuffer=PPU[0]=PPU[1]=PPU_status=PPU[3]=0; PPUSPL=0; PPUGenLatch=0; RefreshAddr=TempAddr=0; @@ -1860,7 +1876,7 @@ void FCEUPPU_Power(void) memset(NTARAM,0x00,0x800); memset(PALRAM,0x00,0x20); memset(UPALRAM,0x00,0x03); - memset(SPRAM,0x00,0x100); + memset(SPRAM,0x00,0x100); FCEUPPU_Reset(); for(x=0x2000;x<0x4000;x+=8) @@ -1903,12 +1919,12 @@ int FCEUPPU_Loop(int skip) { X6502_Run(256+85); PPU_status |= 0x80; - + //Not sure if this is correct. According to Matt Conte and my own tests, it is. - //Timing is probably off, though. - //NOTE: Not having this here breaks a Super Donkey Kong game. - PPU[3]=PPUSPL=0; - + //Timing is probably off, though. + //NOTE: Not having this here breaks a Super Donkey Kong game. + PPU[3]=PPUSPL=0; + //I need to figure out the true nature and length of this delay. X6502_Run(12); if(GameInfo->type==GIT_NSF) @@ -1918,7 +1934,7 @@ int FCEUPPU_Loop(int skip) if(VBlankON) TriggerNMI(); } - X6502_Run((scanlines_per_frame-242)*(256+85)-12); //-12); + X6502_Run((scanlines_per_frame-242)*(256+85)-12); //-12); PPU_status&=0x1f; X6502_Run(256); @@ -1936,9 +1952,9 @@ int FCEUPPU_Loop(int skip) } X6502_Run(85-16); if(ScreenON || SpriteON) - { - RefreshAddr=TempAddr; - if(PPU_hook) PPU_hook(RefreshAddr&0x3fff); + { + RefreshAddr=TempAddr; + if(PPU_hook) PPU_hook(RefreshAddr&0x3fff); } //Clean this stuff up later. @@ -1968,7 +1984,7 @@ int FCEUPPU_Loop(int skip) GameHBIRQHook(); if(scanline==y && SpriteON) PPU_status|=0x40; X6502_Run((scanline==239)?85:(256+85)); - } + } } else if(y<240) { @@ -1991,11 +2007,11 @@ int FCEUPPU_Loop(int skip) DEBUG(FCEUD_UpdatePPUView(scanline, 1)); DoLine(); } - + if(MMC5Hack && (ScreenON || SpriteON)) MMC5_hb(scanline); for(x=1,max=0,maxref=0;x<7;x++) { - + if(deempcnt[x]>max) { max=deempcnt[x]; @@ -2009,7 +2025,7 @@ int FCEUPPU_Loop(int skip) } } //else... to if(ppudead) -#ifdef FRAMESKIP +#ifdef FRAMESKIP if(skip) { FCEU_PutImageDummy(); @@ -2020,9 +2036,9 @@ int FCEUPPU_Loop(int skip) { //mbg 6/21/08 - tileview is being ripped out since i dont know how long its been since it worked //if(tileview) TileView(); - FCEU_PutImage(); + FCEU_PutImage(); return(1); - } + } } int (*PPU_MASTER)(int skip) = FCEUPPU_Loop; @@ -2089,7 +2105,7 @@ SFORMAT FCEU_NEWPPU_STATEINFO[] = { void FCEUPPU_SaveState(void) { - TempAddrT=TempAddr; + TempAddrT=TempAddr; RefreshAddrT=RefreshAddr; } @@ -2104,7 +2120,7 @@ void runppu(int x) { //pputime+=x; //if(cputodo<200) return; - ppur.status.cycle = (ppur.status.cycle + x) % + ppur.status.cycle = (ppur.status.cycle + x) % ppur.status.end_cycle; X6502_Run(x); @@ -2123,7 +2139,7 @@ struct BGData { RefreshAddr = ppur.get_atread(); at = CALL_PPUREAD(RefreshAddr); - + //modify at to get appropriate palette shift if(ppur.vt&2) at >>= 4; if(ppur.ht&2) at >>= 2; @@ -2135,11 +2151,11 @@ struct BGData { if (PPUON) { ppur.increment_hsc(); - if (ppur.status.cycle == 251) + if (ppur.status.cycle == 251) ppur.increment_vs(); } runppu(1); - + ppur.par = nt; RefreshAddr = ppur.get_ptread(); pt[0] = CALL_PPUREAD(RefreshAddr); @@ -2174,35 +2190,35 @@ int FCEUX_PPU_Loop(int skip) { --ppudead; goto finish; } - + { PPU_status |= 0x80; ppuphase = PPUPHASE_VBL; - + //Not sure if this is correct. According to Matt Conte and my own tests, it is. - //Timing is probably off, though. - //NOTE: Not having this here breaks a Super Donkey Kong game. - PPU[3]=PPUSPL=0; + //Timing is probably off, though. + //NOTE: Not having this here breaks a Super Donkey Kong game. + PPU[3]=PPUSPL=0; const int delay = 20; //fceu used 12 here but I couldnt get it to work in marble madness and pirates. - + ppur.status.sl = 241; //for sprite reads - + runppu(delay); //X6502_Run(12); if(VBlankON) TriggerNMI(); if (PAL) runppu(70*(kLineTime)-delay); else runppu(20*(kLineTime)-delay); - + //this seems to run just before the dummy scanline begins PPU_status = 0; //this early out caused metroid to fail to boot. I am leaving it here as a reminder of what not to do //if(!PPUON) { runppu(kLineTime*242); goto finish; } - //There are 2 conditions that update all 5 PPU scroll counters with the - //contents of the latches adjacent to them. The first is after a write to - //2006/2. The second, is at the beginning of scanline 20, when the PPU starts - //rendering data for the first time in a frame (this update won't happen if + //There are 2 conditions that update all 5 PPU scroll counters with the + //contents of the latches adjacent to them. The first is after a write to + //2006/2. The second, is at the beginning of scanline 20, when the PPU starts + //rendering data for the first time in a frame (this update won't happen if //all rendering is disabled via 2001.3 and 2001.4). //if(PPUON) @@ -2230,7 +2246,7 @@ int FCEUX_PPU_Loop(int skip) { } if(sl != 0) if(MMC5Hack && PPUON) MMC5_hb(yp); - + //twiddle the oam buffers const int scanslot = oamslot^1; @@ -2238,7 +2254,7 @@ int FCEUX_PPU_Loop(int skip) { oamslot ^= 1; oamcount = oamcounts[renderslot]; - + //the main scanline rendering loop: //32 times, we will fetch a tile and then render 8 pixels. //two of those tiles were read in the last scanline. @@ -2265,7 +2281,7 @@ int FCEUX_PPU_Loop(int skip) { const int bgpos = rasterpos + ppur.fh; const int bgpx = bgpos&7; const int bgtile = bgpos>>3; - + uint8 pixel=0, pixelcolor; //generate the BG data @@ -2280,7 +2296,7 @@ int FCEUX_PPU_Loop(int skip) { bool havepixel = false; for(int s=0;s=x && rasterpos=8) + if(s==oamcount && s>=8) break; //if this is a real sprite sprite, then it is not above the 8 sprite limit. @@ -2430,7 +2446,7 @@ int FCEUX_PPU_Loop(int skip) { else runppu(kFetchTime); } - //Dragon's Lair (Europe version mapper 4) + //Dragon's Lair (Europe version mapper 4) //does not set SpriteON in the beginning but it does //set the bg on so if using the conditional SpriteON the MMC3 counter //the counter will never count and no IRQs will be fired so use PPUON @@ -2471,12 +2487,12 @@ int FCEUX_PPU_Loop(int skip) { for(int xt=0;xt<2;xt++) bgdata.main[xt].Read(); - //I'm unclear of the reason why this particular access to memory is made. - //The nametable address that is accessed 2 times in a row here, is also the - //same nametable address that points to the 3rd tile to be rendered on the - //screen (or basically, the first nametable address that will be accessed when + //I'm unclear of the reason why this particular access to memory is made. + //The nametable address that is accessed 2 times in a row here, is also the + //same nametable address that points to the 3rd tile to be rendered on the + //screen (or basically, the first nametable address that will be accessed when //the PPU is fetching background data on the next scanline). - //(not implemented yet) + //(not implemented yet) runppu(kFetchTime); if (sl == 0) { @@ -2490,9 +2506,9 @@ int FCEUX_PPU_Loop(int skip) { ppur.status.end_cycle = 341; runppu(kFetchTime); - //After memory access 170, the PPU simply rests for 4 cycles (or the - //equivelant of half a memory access cycle) before repeating the whole - //pixel/scanline rendering process. If the scanline being rendered is the very + //After memory access 170, the PPU simply rests for 4 cycles (or the + //equivelant of half a memory access cycle) before repeating the whole + //pixel/scanline rendering process. If the scanline being rendered is the very //first one on every second frame, then this delay simply doesn't exist. if (ppur.status.end_cycle == 341) runppu(1);