refixed "simpsons" and "rattlenroll" broblems after fixing "youngindiana jones" ;)

This commit is contained in:
CaH4e3 2010-06-13 04:19:46 +00:00
parent a7bb263e13
commit 742322bfc1
1 changed files with 188 additions and 172 deletions

View File

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