Overclocking CPU NES (FCEUMM)

Hello again.

There is few games (hacks) which is need overclocked cpu for nes.

I did tried decrease cycles in fceux cpu. But now graphics is broken for most games. Probably its need to sync ppu with cpu?

How I can remove a graphic bugs? Also some games does not starts. (ex. battletoads)

ps this bug repeated on other cores.

This isn’t a bug. Overclocking consoles isn’t something that’s commonly supported in emulators because it’s prone to problems. These consoles were designed for each component to function in rock-solid sync with each other, so you can’t just crank up the speed on one component and expect everything to still work.

I have an overclocked Fceux SourceCode, but I cant adapt a source code to retroarch core. Because It is c++ files, not C. (different versions I guess) You can see it below (main difference):

x6502.cpp (new cycletable and copy RUN function:

[B]//the opsize table is used to quickly grab the instruction sizes (in bytes)
const uint8 opsize[256] = {
/*0x00*/	1,2,0,0,0,2,2,0,1,2,1,0,0,3,3,0,
/*0x10*/	2,2,0,0,0,2,2,0,1,3,0,0,0,3,3,0,
/*0x20*/	3,2,0,0,2,2,2,0,1,2,1,0,3,3,3,0,
/*0x30*/	2,2,0,0,0,2,2,0,1,3,0,0,0,3,3,0,
/*0x40*/	1,2,0,0,0,2,2,0,1,2,1,0,3,3,3,0,
/*0x50*/	2,2,0,0,0,2,2,0,1,3,0,0,0,3,3,0,
/*0x60*/	1,2,0,0,0,2,2,0,1,2,1,0,3,3,3,0,
/*0x70*/	2,2,0,0,0,2,2,0,1,3,0,0,0,3,3,0,
/*0x80*/	0,2,0,0,2,2,2,0,1,0,1,0,3,3,3,0,
/*0x90*/	2,2,0,0,2,2,2,0,1,3,1,0,0,3,0,0,
/*0xA0*/	2,2,2,0,2,2,2,0,1,2,1,0,3,3,3,0,
/*0xB0*/	2,2,0,0,2,2,2,0,1,3,1,0,3,3,3,0,
/*0xC0*/	2,2,0,0,2,2,2,0,1,2,1,0,3,3,3,0,
/*0xD0*/	2,2,0,0,0,2,2,0,1,3,0,0,0,3,3,0,
/*0xE0*/	2,2,0,0,2,2,2,0,1,2,1,0,3,3,3,0,
/*0xF0*/	2,2,0,0,0,2,2,0,1,3,0,0,0,3,3,0
};


//the optype table is a quick way to grab the addressing mode for any 6502 opcode
//
//  0 = Implied\Accumulator\Immediate\Branch\NULL
//  1 = (Indirect,X)
//  2 = Zero Page
//  3 = Absolute
//  4 = (Indirect),Y
//  5 = Zero Page,X
//  6 = Absolute,Y
//  7 = Absolute,X
//  8 = Zero Page,Y
//
const uint8 optype[256] = {
/*0x00*/	0,1,0,0,0,2,2,0,0,0,0,0,0,3,3,0,
/*0x10*/	0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0,
/*0x20*/	0,1,0,0,2,2,2,0,0,0,0,0,3,3,3,0,
/*0x30*/	0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0,
/*0x40*/	0,1,0,0,0,2,2,0,0,0,0,0,0,3,3,0,
/*0x50*/	0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0,
/*0x60*/	0,1,0,0,0,2,2,0,0,0,0,0,3,3,3,0,
/*0x70*/	0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0,
/*0x80*/	0,1,0,0,2,2,2,0,0,0,0,0,3,3,3,0,
/*0x90*/	0,4,0,0,5,5,8,0,0,6,0,0,0,7,0,0,
/*0xA0*/	0,1,0,0,2,2,2,0,0,0,0,0,3,3,3,0,
/*0xB0*/	0,4,0,0,5,5,8,0,0,6,0,0,7,7,6,0,
/*0xC0*/	0,1,0,0,2,2,2,0,0,0,0,0,3,3,3,0,
/*0xD0*/	0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0,
/*0xE0*/	0,1,0,0,2,2,2,0,0,0,0,0,3,3,3,0,
/*0xF0*/	0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0
};

static uint8 CycTableHACK[256] =
{
/*0x00*/ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
/*0x10*/ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
/*0x20*/ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
/*0x30*/ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
/*0x40*/ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
/*0x50*/ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
/*0x60*/ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
/*0x70*/ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
/*0x80*/ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
/*0x90*/ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
/*0xA0*/ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
/*0xB0*/ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
/*0xC0*/ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
/*0xD0*/ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
/*0xE0*/ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
/*0xF0*/ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
};
[/B]


void [B]X6502_RunHACK[/B](int32 cycles)
{
  if(PAL)
   cycles*=15;    // 15*4=60
  else
   cycles*=16;    // 16*4=64

  _count+=cycles;
extern int test; test++;
  while(_count>0)
  {
   int32 temp;
   uint8 b1;

   if(_IRQlow)
   {
    if(_IRQlow&FCEU_IQRESET)
    {
	 DEBUG( if(debug_loggingCD) LogCDVectors(0xFFFC); )
     _PC=RdMem(0xFFFC);
     _PC|=RdMem(0xFFFD)<<8;
     _jammed=0;
     _PI=_P=I_FLAG;
     _IRQlow&=~FCEU_IQRESET;
    }
    else if(_IRQlow&FCEU_IQNMI2)
     {
     _IRQlow&=~FCEU_IQNMI2;
     _IRQlow|=FCEU_IQNMI;
    }
    else if(_IRQlow&FCEU_IQNMI)
    {
     if(!_jammed)
     {
      ADDCYC(7);
      PUSH(_PC>>8);
      PUSH(_PC);
      PUSH((_P&~B_FLAG)|(U_FLAG));
      _P|=I_FLAG;
	  DEBUG( if(debug_loggingCD) LogCDVectors(0xFFFA) );
      _PC=RdMem(0xFFFA);
      _PC|=RdMem(0xFFFB)<<8;
      _IRQlow&=~FCEU_IQNMI;
     }
    }
    else
    {
     if(!(_PI&I_FLAG) && !_jammed)
     {
      ADDCYC(7);
      PUSH(_PC>>8);
      PUSH(_PC);
      PUSH((_P&~B_FLAG)|(U_FLAG));
      _P|=I_FLAG;
	  DEBUG( if(debug_loggingCD) LogCDVectors(0xFFFE) );
      _PC=RdMem(0xFFFE);
      _PC|=RdMem(0xFFFF)<<8;
     }
    }
    _IRQlow&=~(FCEU_IQTEMP);
    if(_count<=0)
    {
     _PI=_P;
     return;
     } //Should increase accuracy without a
              //major speed hit.
   }

	//will probably cause a major speed decrease on low-end systems
   DEBUG( DebugCycle() );

   _PI=_P;
   b1=RdMem(_PC);

   ADDCYC[B](CycTableHACK[b1])[/B];

   temp=_tcount;
   _tcount=0;
   if(MapIRQHook) MapIRQHook(temp);
   FCEU_SoundCPUHook(temp);
   #ifdef _S9XLUA_H
   CallRegisteredLuaMemHook(_PC, 1, 0, LUAMEMHOOK_EXEC);
   #endif
   _PC++;
   switch(b1)
   {
    #include "ops.inc"
   }
  }
}

So and ppu.cpp, which have reference to new RUN function:

static void [B]DoLineHACK[/B](void)
{
	int x;
	uint8 *target=XBuf+(scanline<<8);

	if(MMC5Hack && (ScreenON || SpriteON)) MMC5_hb(scanline);

	[B]X6502_RunHACK[/B](256);
	EndRL();

	if(!renderbg)  // User asked to not display background data.
	{
		uint32 tem;
		uint8 col;
		if(gNoBGFillColor == 0xFF)
			col = Pal[0];
		else col = gNoBGFillColor;
		tem=col|(col<<8)|(col<<16)|(col<<24);
		tem|=0x40404040;
		FCEU_dwmemset(target,tem,256);
	}

	if(SpriteON)
		CopySprites(target);

	if(ScreenON || SpriteON)  // Yes, very el-cheapo.
	{
		if(PPU[1]&0x01)
		{
			for(x=63;x>=0;x--)
				*(uint32 *)&target[x<<2]=(*(uint32*)&target[x<<2])&0x30303030;
		}
	}
	if((PPU[1]>>5)==0x7)
	{
		for(x=63;x>=0;x--)
			*(uint32 *)&target[x<<2]=((*(uint32*)&target[x<<2])&0x3f3f3f3f)|0xc0c0c0c0;
	}
	else if(PPU[1]&0xE0)
		for(x=63;x>=0;x--)
			*(uint32 *)&target[x<<2]=(*(uint32*)&target[x<<2])|0x40404040;
	else
		for(x=63;x>=0;x--)
			*(uint32 *)&target[x<<2]=((*(uint32*)&target[x<<2])&0x3f3f3f3f)|0x80808080;

	sphitx=0x100;

	if(ScreenON || SpriteON)
		FetchSpriteData();

	if(GameHBIRQHook && (ScreenON || SpriteON) && ((PPU[0]&0x38)!=0x18))
	{
		X6502_Run(6);
		Fixit2();
		X6502_Run(4);
		GameHBIRQHook();
		X6502_Run(85-16-10);
	}
	else
	{
		X6502_Run(6);  // Tried 65, caused problems with Slalom(maybe others)
		Fixit2();
		X6502_Run(85-6-16);

		// A semi-hack for Star Trek: 25th Anniversary
		if(GameHBIRQHook && (ScreenON || SpriteON) && ((PPU[0]&0x38)!=0x18))
			GameHBIRQHook();
	}

	DEBUG(FCEUD_UpdateNTView(scanline,0));

	if(SpriteON)
		RefreshSprites();
	if(GameHBIRQHook2 && (ScreenON || SpriteON))
		GameHBIRQHook2();
	scanline++;
	if(scanline<240)
	{
		ResetRL(XBuf+(scanline<<8));
	}
	X6502_Run(16);
}

Duplicated function again:


#ifdef FRAMESKIP
		else if(skip)
		{
			int y;

			y=SPRAM[0];
			y++;

			PPU_status|=0x20;       // Fixes "Bee 52".  Does it break anything?
			if(GameHBIRQHook)
			{
				X6502_Run(256);
				for(scanline=0;scanline<240;scanline++)
				{
					if(ScreenON || SpriteON)
						GameHBIRQHook();
					if(scanline==y && SpriteON) PPU_status|=0x40;
					X6502_Run((scanline==239)?85:(256+85));
				}
			}
			else if(y<240)
			{
				X6502_Run((256+85)*y);
				if(SpriteON) PPU_status|=0x40; // Quick and very dirty hack.
				X6502_Run((256+85)*(240-y));
			}
			else
				X6502_Run((256+85)*240);
		}
#endif
		else
		{
			int x,max,maxref;

			deemp=PPU[1]>>5;
			for(scanline=0;scanline<200;)       //scanline is incremented in  DoLine.  Evil. :/
			{
				deempcnt[deemp]++;
				DEBUG(FCEUD_UpdatePPUView(scanline, 1));
				DoLine();
			}
			[B]	for(scanline=200;scanline<239;)       //scanline is incremented in  DoLine.  Evil. :/
			{
				deempcnt[deemp]++;
				DEBUG(FCEUD_UpdatePPUView(scanline, 1));
				DoLineHACK();
			}
[/B]
				for(scanline=239;scanline<240;)       //scanline is incremented in  DoLine.  Evil. :/
			{
				deempcnt[deemp]++;
				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];
					maxref=x;
				}
				deempcnt[x]=0;
			}
			//FCEU_DispMessage("%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x %d",0,deempcnt[0],deempcnt[1],deempcnt[2],deempcnt[3],deempcnt[4],deempcnt[5],deempcnt[6],deempcnt[7],maxref);
			//memset(deempcnt,0,sizeof(deempcnt));
			SetNESDeemph(maxref,0);
		}
	} //else... to if(ppudead)

PS I marked main differences PSS When I duplicated this functions in core, then graphics is broken (just emulator starts a chaotic work)

I did it. If someone is interested, I can upload the changed files.

wow, nice. Sure, if you’d like to upload them somewhere, Squarepusher may want to add it as a toggleable core option.