2009-07-17 19:27:04 +02:00
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file :
* 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
* ( 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
* 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
*/
# include <string>
# include <string.h>
# include <stdio.h>
# include <stdlib.h>
# include <stdarg.h>
# include <time.h>
# include "types.h"
# include "x6502.h"
# include "fceu.h"
# include "ppu.h"
# include "sound.h"
# include "netplay.h"
# include "file.h"
# include "utils/endian.h"
# include "utils/memory.h"
# include "utils/crc32.h"
# include "cart.h"
# include "nsf.h"
# include "fds.h"
# include "ines.h"
# include "unif.h"
# include "cheat.h"
# include "palette.h"
# include "state.h"
# include "movie.h"
# include "video.h"
# include "input.h"
# include "file.h"
# include "vsuni.h"
# include "ines.h"
2009-10-07 06:40:55 +02:00
# ifdef WIN32
# include "drivers/win/pref.h"
2012-01-09 02:59:06 +01:00
# include "drivers/win/taseditlib/greenzone.h"
extern GREENZONE greenzone ;
2009-10-07 06:40:55 +02:00
# endif
2009-07-17 19:27:04 +02:00
# include <fstream>
# include <sstream>
# ifdef _S9XLUA_H
# include "fceulua.h"
# endif
//TODO - we really need some kind of global platform-specific options api
# ifdef WIN32
# include "drivers/win/main.h"
# include "drivers/win/cheat.h"
# include "drivers/win/texthook.h"
2009-11-03 09:16:57 +01:00
# include "drivers/win/ram_search.h"
# include "drivers/win/ramwatch.h"
2009-07-17 19:27:04 +02:00
# include "drivers/win/memwatch.h"
# include "drivers/win/tracer.h"
# else
2009-07-17 20:01:31 +02:00
# ifdef GEKKO
# include "driver.h"
# else
2009-07-17 19:27:04 +02:00
# include "drivers/sdl/sdl.h"
# endif
2009-07-17 20:01:31 +02:00
# endif
2009-07-17 19:27:04 +02:00
using namespace std ;
int AFon = 1 , AFoff = 1 , AutoFireOffset = 0 ; //For keeping track of autofire settings
bool justLagged = false ;
bool frameAdvanceLagSkip = false ; //If this is true, frame advance will skip over lag frame (i.e. it will emulate 2 frames instead of 1)
bool AutoSS = false ; //Flagged true when the first auto-savestate is made while a game is loaded, flagged false on game close
bool movieSubtitles = true ; //Toggle for displaying movie subtitles
2010-08-29 23:15:42 +02:00
bool DebuggerWasUpdated = false ; //To prevent the debugger from updating things without being updated.
2009-07-17 19:27:04 +02:00
FCEUGI : : FCEUGI ( )
: filename ( 0 )
, archiveFilename ( 0 )
{
printf ( " %08x " , opsize ) ;
}
FCEUGI : : ~ FCEUGI ( )
{
if ( filename ) delete filename ;
if ( archiveFilename ) delete archiveFilename ;
}
2010-08-29 23:15:42 +02:00
bool CheckFileExists ( const char * filename )
{
//This function simply checks to see if the given filename exists
if ( ! filename ) return false ;
fstream test ;
test . open ( filename , fstream : : in ) ;
if ( test . fail ( ) )
{
test . close ( ) ;
return false ;
}
else
{
test . close ( ) ;
return true ;
}
}
void FCEU_TogglePPU ( void )
{
newppu ^ = 1 ;
if ( newppu )
{
FCEU_DispMessage ( " New PPU loaded " , 0 ) ;
FCEUI_printf ( " New PPU loaded " ) ;
}
else
{
FCEU_DispMessage ( " Old PPU loaded " , 0 ) ;
FCEUI_printf ( " Old PPU loaded " ) ;
}
}
2009-12-14 07:56:29 +01:00
static void FCEU_CloseGame ( void )
2009-07-17 19:27:04 +02:00
{
if ( GameInfo )
{
2009-10-07 06:40:55 +02:00
# ifdef WIN32
2010-08-29 23:15:42 +02:00
//SP CODE
2009-10-07 06:40:55 +02:00
extern char LoadedRomFName [ 2048 ] ;
if ( storePreferences ( LoadedRomFName ) )
{
FCEUD_PrintError ( " Couldn't store debugging data " ) ;
}
# endif
2009-07-17 19:27:04 +02:00
if ( FCEUnetplay )
{
FCEUD_NetworkClose ( ) ;
}
if ( GameInfo - > name )
{
free ( GameInfo - > name ) ;
GameInfo - > name = 0 ;
}
if ( GameInfo - > type ! = GIT_NSF )
{
FCEU_FlushGameCheats ( 0 , 0 ) ;
}
GameInterface ( GI_CLOSE ) ;
FCEUI_StopMovie ( ) ;
ResetExState ( 0 , 0 ) ;
2010-08-29 23:15:42 +02:00
//clear screen when game is closed
2009-07-17 19:27:04 +02:00
extern uint8 * XBuf ;
if ( XBuf )
memset ( XBuf , 0 , 256 * 256 ) ;
CloseGenie ( ) ;
delete GameInfo ;
GameInfo = 0 ;
2010-08-29 23:15:42 +02:00
2009-07-17 19:27:04 +02:00
currFrameCounter = 0 ;
2010-08-29 23:15:42 +02:00
//Reset flags for Undo/Redo/Auto Savestating //adelikat: TODO: maybe this stuff would be cleaner as a struct or class
2009-07-17 19:27:04 +02:00
lastSavestateMade [ 0 ] = 0 ;
undoSS = false ;
redoSS = false ;
lastLoadstateMade [ 0 ] = 0 ;
undoLS = false ;
redoLS = false ;
AutoSS = false ;
}
}
uint64 timestampbase ;
FCEUGI * GameInfo = 0 ;
void ( * GameInterface ) ( GI h ) ;
void ( * GameStateRestore ) ( int version ) ;
readfunc ARead [ 0x10000 ] ;
writefunc BWrite [ 0x10000 ] ;
static readfunc * AReadG ;
static writefunc * BWriteG ;
static int RWWrap = 0 ;
//mbg merge 7/18/06 docs
//bit0 indicates whether emulation is paused
//bit1 indicates whether emulation is in frame step mode
int EmulationPaused = 0 ;
bool frameAdvanceRequested = false ;
int frameAdvanceDelay ;
//indicates that the emulation core just frame advanced (consumed the frame advance state and paused)
bool JustFrameAdvanced = false ;
2009-11-27 09:53:39 +01:00
static int * AutosaveStatus ; //is it safe to load Auto-savestate
2009-07-17 19:27:04 +02:00
static int AutosaveIndex = 0 ; //which Auto-savestate we're on
2009-11-27 09:53:39 +01:00
int AutosaveQty = 4 ; // Number of Autosaves to store
int AutosaveFrequency = 256 ; // Number of frames between autosaves
2009-07-17 19:27:04 +02:00
// Flag that indicates whether the Auto-save option is enabled or not
int EnableAutosave = 0 ;
///a wrapper for unzip.c
extern " C " FILE * FCEUI_UTF8fopen_C ( const char * n , const char * m ) { return : : FCEUD_UTF8fopen ( n , m ) ; }
static DECLFW ( BNull )
{
}
static DECLFR ( ANull )
{
return ( X . DB ) ;
}
int AllocGenieRW ( void )
{
if ( ! ( AReadG = ( readfunc * ) FCEU_malloc ( 0x8000 * sizeof ( readfunc ) ) ) )
return 0 ;
if ( ! ( BWriteG = ( writefunc * ) FCEU_malloc ( 0x8000 * sizeof ( writefunc ) ) ) )
return 0 ;
RWWrap = 1 ;
return 1 ;
}
void FlushGenieRW ( void )
{
int32 x ;
if ( RWWrap )
{
for ( x = 0 ; x < 0x8000 ; x + + )
{
ARead [ x + 0x8000 ] = AReadG [ x ] ;
BWrite [ x + 0x8000 ] = BWriteG [ x ] ;
}
free ( AReadG ) ;
free ( BWriteG ) ;
AReadG = 0 ;
BWriteG = 0 ;
RWWrap = 0 ;
}
}
readfunc GetReadHandler ( int32 a )
{
if ( a > = 0x8000 & & RWWrap )
return AReadG [ a - 0x8000 ] ;
else
return ARead [ a ] ;
}
void SetReadHandler ( int32 start , int32 end , readfunc func )
{
int32 x ;
if ( ! func )
func = ANull ;
if ( RWWrap )
for ( x = end ; x > = start ; x - - )
{
if ( x > = 0x8000 )
AReadG [ x - 0x8000 ] = func ;
else
ARead [ x ] = func ;
}
else
for ( x = end ; x > = start ; x - - )
ARead [ x ] = func ;
}
writefunc GetWriteHandler ( int32 a )
{
if ( RWWrap & & a > = 0x8000 )
return BWriteG [ a - 0x8000 ] ;
else
return BWrite [ a ] ;
}
void SetWriteHandler ( int32 start , int32 end , writefunc func )
{
int32 x ;
if ( ! func )
func = BNull ;
if ( RWWrap )
for ( x = end ; x > = start ; x - - )
{
if ( x > = 0x8000 )
BWriteG [ x - 0x8000 ] = func ;
else
BWrite [ x ] = func ;
}
else
for ( x = end ; x > = start ; x - - )
BWrite [ x ] = func ;
}
uint8 * GameMemBlock ;
uint8 * RAM ;
//---------
//windows might need to allocate these differently, so we have some special code
static void AllocBuffers ( )
{
2009-11-10 23:13:41 +01:00
GameMemBlock = ( uint8 * ) FCEU_gmalloc ( GAME_MEM_BLOCK_SIZE ) ;
2009-07-17 19:27:04 +02:00
RAM = ( uint8 * ) FCEU_gmalloc ( 0x800 ) ;
}
2010-08-29 23:15:42 +02:00
static void FreeBuffers ( )
{
2009-07-17 19:27:04 +02:00
FCEU_free ( GameMemBlock ) ;
FCEU_free ( RAM ) ;
}
//------
uint8 PAL = 0 ;
static DECLFW ( BRAML )
2009-11-10 23:13:41 +01:00
{
2009-07-17 19:27:04 +02:00
RAM [ A ] = V ;
# ifdef _S9XLUA_H
2009-11-03 09:16:57 +01:00
CallRegisteredLuaMemHook ( A , 1 , V , LUAMEMHOOK_WRITE ) ;
2009-07-17 19:27:04 +02:00
# endif
}
static DECLFW ( BRAMH )
{
RAM [ A & 0x7FF ] = V ;
# ifdef _S9XLUA_H
2009-11-03 09:16:57 +01:00
CallRegisteredLuaMemHook ( A & 0x7FF , 1 , V , LUAMEMHOOK_WRITE ) ;
2009-07-17 19:27:04 +02:00
# endif
}
static DECLFR ( ARAML )
{
return RAM [ A ] ;
}
static DECLFR ( ARAMH )
{
return RAM [ A & 0x7FF ] ;
}
void ResetGameLoaded ( void )
{
2009-12-14 07:56:29 +01:00
if ( GameInfo ) FCEU_CloseGame ( ) ;
2009-07-17 19:27:04 +02:00
EmulationPaused = 0 ; //mbg 5/8/08 - loading games while paused was bad news. maybe this fixes it
GameStateRestore = 0 ;
PPU_hook = 0 ;
GameHBIRQHook = 0 ;
FFCEUX_PPURead = 0 ;
FFCEUX_PPUWrite = 0 ;
if ( GameExpSound . Kill )
GameExpSound . Kill ( ) ;
memset ( & GameExpSound , 0 , sizeof ( GameExpSound ) ) ;
MapIRQHook = 0 ;
MMC5Hack = 0 ;
PAL & = 1 ;
pale = 0 ;
}
int UNIFLoad ( const char * name , FCEUFILE * fp ) ;
int iNESLoad ( const char * name , FCEUFILE * fp , int OverwriteVidMode ) ;
int FDSLoad ( const char * name , FCEUFILE * fp ) ;
2009-09-15 10:20:48 +02:00
int NSFLoad ( const char * name , FCEUFILE * fp ) ;
2009-07-17 19:27:04 +02:00
//char lastLoadedGameName [2048] = {0,}; // hack for movie WRAM clearing on record from poweron
FCEUGI * FCEUI_LoadGameVirtual ( const char * name , int OverwriteVidMode )
{
//mbg merge 7/17/07 - why is this here
//#ifdef WIN32
// StopSound();
//#endif
//----------
//attempt to open the files
FCEUFILE * fp ;
FCEU_printf ( " Loading %s... \n \n " , name ) ;
const char * romextensions [ ] = { " nes " , " fds " , 0 } ;
fp = FCEU_fopen ( name , 0 , " rb " , 0 , - 1 , romextensions ) ;
if ( ! fp ) {
FCEU_PrintError ( " Error opening \" %s \" ! " , name ) ;
return 0 ;
}
2012-01-09 02:59:06 +01:00
GetFileBase ( fp - > filename . c_str ( ) ) ;
2009-07-17 19:27:04 +02:00
//---------
//file opened ok. start loading.
ResetGameLoaded ( ) ;
2009-11-27 09:53:39 +01:00
if ( ! AutosaveStatus )
2010-10-06 05:57:22 +02:00
AutosaveStatus = ( int * ) FCEU_dmalloc ( sizeof ( int ) * AutosaveQty ) ;
2009-11-27 09:53:39 +01:00
for ( AutosaveIndex = 0 ; AutosaveIndex < AutosaveQty ; + + AutosaveIndex )
AutosaveStatus [ AutosaveIndex ] = 0 ;
2009-07-17 19:27:04 +02:00
2009-12-14 07:56:29 +01:00
FCEU_CloseGame ( ) ;
2009-07-17 19:27:04 +02:00
GameInfo = new FCEUGI ( ) ;
memset ( GameInfo , 0 , sizeof ( FCEUGI ) ) ;
GameInfo - > filename = strdup ( fp - > filename . c_str ( ) ) ;
if ( fp - > archiveFilename ! = " " ) GameInfo - > archiveFilename = strdup ( fp - > archiveFilename . c_str ( ) ) ;
GameInfo - > archiveCount = fp - > archiveCount ;
GameInfo - > soundchan = 0 ;
GameInfo - > soundrate = 0 ;
GameInfo - > name = 0 ;
GameInfo - > type = GIT_CART ;
GameInfo - > vidsys = GIV_USER ;
GameInfo - > input [ 0 ] = GameInfo - > input [ 1 ] = SI_UNSET ;
GameInfo - > inputfc = SIFC_UNSET ;
GameInfo - > cspecial = SIS_NONE ;
//try to load each different format
bool FCEUXLoad ( const char * name , FCEUFILE * fp ) ;
/*if(FCEUXLoad(name,fp))
goto endlseq ; */
if ( iNESLoad ( name , fp , OverwriteVidMode ) )
goto endlseq ;
2009-09-15 10:20:48 +02:00
if ( NSFLoad ( name , fp ) )
2009-07-17 19:27:04 +02:00
goto endlseq ;
if ( UNIFLoad ( name , fp ) )
goto endlseq ;
if ( FDSLoad ( name , fp ) )
goto endlseq ;
FCEU_PrintError ( " An error occurred while loading the file. " ) ;
FCEU_fclose ( fp ) ;
delete GameInfo ;
GameInfo = 0 ;
return 0 ;
endlseq :
FCEU_fclose ( fp ) ;
2009-10-07 06:40:55 +02:00
# ifdef WIN32
// ################################## Start of SP CODE ###########################
extern char LoadedRomFName [ 2048 ] ;
extern int loadDebugDataFailed ;
if ( ( loadDebugDataFailed = loadPreferences ( LoadedRomFName ) ) )
{
FCEUD_PrintError ( " Couldn't load debugging data " ) ;
}
// ################################## End of SP CODE ###########################
# endif
2009-07-17 19:27:04 +02:00
FCEU_ResetVidSys ( ) ;
if ( GameInfo - > type ! = GIT_NSF )
if ( FSettings . GameGenie )
OpenGenie ( ) ;
PowerNES ( ) ;
if ( GameInfo - > type ! = GIT_NSF )
FCEU_LoadGamePalette ( ) ;
FCEU_ResetPalette ( ) ;
FCEU_ResetMessages ( ) ; // Save state, status messages, etc.
if ( GameInfo - > type ! = GIT_NSF )
FCEU_LoadGameCheats ( 0 ) ;
2009-11-03 09:16:57 +01:00
# if defined (WIN32) || defined (WIN64)
2010-08-29 23:15:42 +02:00
DoDebuggerDataReload ( ) ; // Reloads data without reopening window
2009-11-03 09:16:57 +01:00
# endif
2009-07-17 19:27:04 +02:00
return GameInfo ;
}
FCEUGI * FCEUI_LoadGame ( const char * name , int OverwriteVidMode )
{
return FCEUI_LoadGameVirtual ( name , OverwriteVidMode ) ;
}
//Return: Flag that indicates whether the function was succesful or not.
bool FCEUI_Initialize ( )
{
srand ( time ( 0 ) ) ;
if ( ! FCEU_InitVirtualVideo ( ) )
{
return false ;
}
AllocBuffers ( ) ;
// Initialize some parts of the settings structure
//mbg 5/7/08 - I changed the ntsc settings to match pal.
//this is more for precision emulation, instead of entertainment, which is what fceux is all about nowadays
memset ( & FSettings , 0 , sizeof ( FSettings ) ) ;
//FSettings.UsrFirstSLine[0]=8;
FSettings . UsrFirstSLine [ 0 ] = 0 ;
FSettings . UsrFirstSLine [ 1 ] = 0 ;
//FSettings.UsrLastSLine[0]=231;
FSettings . UsrLastSLine [ 0 ] = 239 ;
FSettings . UsrLastSLine [ 1 ] = 239 ;
FSettings . SoundVolume = 150 ; //0-150 scale
FSettings . TriangleVolume = 256 ; //0-256 scale (256 is max volume)
FSettings . Square1Volume = 256 ; //0-256 scale (256 is max volume)
FSettings . Square2Volume = 256 ; //0-256 scale (256 is max volume)
FSettings . NoiseVolume = 256 ; //0-256 scale (256 is max volume)
FSettings . PCMVolume = 256 ; //0-256 scale (256 is max volume)
FCEUPPU_Init ( ) ;
X6502_Init ( ) ;
return true ;
}
void FCEUI_Kill ( void )
{
# ifdef _S9XLUA_H
FCEU_LuaStop ( ) ;
# endif
FCEU_KillVirtualVideo ( ) ;
FCEU_KillGenie ( ) ;
FreeBuffers ( ) ;
}
int rapidAlternator = 0 ;
int AutoFirePattern [ 8 ] = { 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
int AutoFirePatternLength = 2 ;
void SetAutoFirePattern ( int onframes , int offframes )
{
int i ;
for ( i = 0 ; i < onframes & & i < 8 ; i + + )
{
AutoFirePattern [ i ] = 1 ;
}
for ( ; i < 8 ; i + + )
{
AutoFirePattern [ i ] = 0 ;
}
if ( onframes + offframes < 2 )
{
AutoFirePatternLength = 2 ;
}
else if ( onframes + offframes > 8 )
{
AutoFirePatternLength = 8 ;
}
else
{
AutoFirePatternLength = onframes + offframes ;
}
AFon = onframes ; AFoff = offframes ;
}
void SetAutoFireOffset ( int offset )
{
if ( offset < 0 | | offset > 8 ) return ;
AutoFireOffset = offset ;
}
void AutoFire ( void )
{
static int counter = 0 ;
2010-08-29 23:15:42 +02:00
if ( justLagged = = false )
counter = ( counter + 1 ) % ( 8 * 7 * 5 * 3 ) ;
2009-07-17 19:27:04 +02:00
//If recording a movie, use the frame # for the autofire so the offset
//doesn't get screwed up when loading.
if ( FCEUMOV_Mode ( MOVIEMODE_RECORD | MOVIEMODE_PLAY ) )
{
2010-08-29 23:15:42 +02:00
rapidAlternator = AutoFirePattern [ ( AutoFireOffset + FCEUMOV_GetFrame ( ) ) % AutoFirePatternLength ] ; //adelikat: TODO: Think through this, MOVIEMODE_FINISHED should not use movie data for auto-fire?
2009-07-17 19:27:04 +02:00
}
else
{
rapidAlternator = AutoFirePattern [ ( AutoFireOffset + counter ) % AutoFirePatternLength ] ;
}
}
void UpdateAutosave ( void ) ;
///Emulates a single frame.
///Skip may be passed in, if FRAMESKIP is #defined, to cause this to emulate more than one frame
void FCEUI_Emulate ( uint8 * * pXBuf , int32 * * SoundBuf , int32 * SoundBufSize , int skip )
{
//skip initiates frame skip if 1, or frame skip and sound skip if 2
int r , ssize ;
JustFrameAdvanced = false ;
if ( frameAdvanceRequested )
{
if ( frameAdvanceDelay = = 0 | | frameAdvanceDelay > = 10 )
EmulationPaused = 3 ;
if ( frameAdvanceDelay = = 0 | | frameAdvanceDelay < 10 )
frameAdvanceDelay + + ;
}
if ( EmulationPaused & 2 )
EmulationPaused & = ~ 1 ; // clear paused flag temporarily (frame advance)
else if ( ( EmulationPaused & 1 ) )
{
memcpy ( XBuf , XBackBuf , 256 * 256 ) ;
FCEU_PutImage ( ) ;
* pXBuf = XBuf ;
* SoundBuf = WaveFinal ;
* SoundBufSize = 0 ;
return ;
}
AutoFire ( ) ;
UpdateAutosave ( ) ;
# ifdef _S9XLUA_H
FCEU_LuaFrameBoundary ( ) ;
# endif
FCEU_UpdateInput ( ) ;
lagFlag = 1 ;
2009-11-03 09:16:57 +01:00
# ifdef _S9XLUA_H
CallRegisteredLuaFunctions ( LUACALL_BEFOREEMULATION ) ;
# endif
2009-07-17 19:27:04 +02:00
if ( geniestage ! = 1 ) FCEU_ApplyPeriodicCheats ( ) ;
r = FCEUPPU_Loop ( skip ) ;
if ( skip ! = 2 ) ssize = FlushEmulateSound ( ) ; //If skip = 2 we are skipping sound processing
2009-11-03 09:16:57 +01:00
# ifdef _S9XLUA_H
CallRegisteredLuaFunctions ( LUACALL_AFTEREMULATION ) ;
# endif
2009-07-17 19:27:04 +02:00
# ifdef WIN32
//These Windows only dialogs need to be updated only once per frame so they are included here
2010-08-29 23:15:42 +02:00
UpdateCheatList ( ) ; // CaH4e3: can't see why, this is only cause problems with selection - adelikat: selection is only a problem when not paused, it shoudl be paused to select, we want to see the values update
2009-07-17 19:27:04 +02:00
UpdateTextHooker ( ) ;
2009-11-03 09:16:57 +01:00
Update_RAM_Search ( ) ; // Update_RAM_Watch() is also called.
2009-07-17 19:27:04 +02:00
RamChange ( ) ;
UpdateLogWindow ( ) ;
//FCEUI_AviVideoUpdate(XBuf);
2010-08-29 23:15:42 +02:00
extern int KillFCEUXonFrame ;
if ( KillFCEUXonFrame & & ( FCEUMOV_GetFrame ( ) > = KillFCEUXonFrame ) )
DoFCEUExit ( ) ;
2009-07-17 19:27:04 +02:00
# endif
timestampbase + = timestamp ;
timestamp = 0 ;
* pXBuf = skip ? 0 : XBuf ;
if ( skip = = 2 ) //If skip = 2, then bypass sound
{
* SoundBuf = 0 ;
* SoundBufSize = 0 ;
}
2009-11-10 23:13:41 +01:00
else
2009-07-17 19:27:04 +02:00
{
* SoundBuf = WaveFinal ;
* SoundBufSize = ssize ;
}
2009-11-10 23:13:41 +01:00
2009-07-17 19:27:04 +02:00
if ( EmulationPaused & 2 & & ( ! frameAdvanceLagSkip | | ! lagFlag ) )
//Lots of conditions here. EmulationPaused&2 must be true. In addition frameAdvanceLagSkip or lagFlag must be false
{
EmulationPaused = 1 ; // restore paused flag
JustFrameAdvanced = true ;
# ifdef WIN32
if ( soundoptions & SO_MUTEFA ) //mute the frame advance if the user requested it
* SoundBufSize = 0 ; //keep sound muted
# endif
2009-11-10 23:13:41 +01:00
2009-07-17 19:27:04 +02:00
}
2009-11-10 23:13:41 +01:00
if ( lagFlag )
2009-07-17 19:27:04 +02:00
{
lagCounter + + ;
justLagged = true ;
}
else justLagged = false ;
if ( movieSubtitles )
ProcessSubtitles ( ) ;
2012-01-09 02:59:06 +01:00
# ifdef WIN32
if ( FCEUMOV_Mode ( MOVIEMODE_TASEDIT ) )
greenzone . TryDumpIncremental ( lagFlag ! = 0 ) ;
# endif
2009-07-17 19:27:04 +02:00
}
void FCEUI_CloseGame ( void )
2009-11-10 23:13:41 +01:00
{
if ( ! FCEU_IsValidUI ( FCEUI_CLOSEGAME ) )
2009-07-17 19:27:04 +02:00
return ;
2009-10-07 06:40:55 +02:00
2009-12-14 07:56:29 +01:00
FCEU_CloseGame ( ) ;
2009-07-17 19:27:04 +02:00
}
void ResetNES ( void )
{
FCEUMOV_AddCommand ( FCEUNPCMD_RESET ) ;
if ( ! GameInfo ) return ;
GameInterface ( GI_RESETM2 ) ;
FCEUSND_Reset ( ) ;
FCEUPPU_Reset ( ) ;
X6502_Reset ( ) ;
// clear back baffer
extern uint8 * XBackBuf ;
memset ( XBackBuf , 0 , 256 * 256 ) ;
}
void FCEU_MemoryRand ( uint8 * ptr , uint32 size )
{
int x = 0 ;
while ( size )
{
* ptr = ( x & 4 ) ? 0xFF : 0x00 ;
x + + ;
size - - ;
ptr + + ;
}
}
void hand ( X6502 * X , int type , unsigned int A )
{
}
int suppressAddPowerCommand = 0 ; // hack... yeah, I know...
2009-11-10 23:13:41 +01:00
void PowerNES ( void )
2009-07-17 19:27:04 +02:00
{
//void MapperInit();
//MapperInit();
if ( ! suppressAddPowerCommand )
FCEUMOV_AddCommand ( FCEUNPCMD_POWER ) ;
if ( ! GameInfo ) return ;
FCEU_CheatResetRAM ( ) ;
FCEU_CheatAddRAM ( 2 , 0 , RAM ) ;
GeniePower ( ) ;
FCEU_MemoryRand ( RAM , 0x800 ) ;
//memset(RAM,0xFF,0x800);
SetReadHandler ( 0x0000 , 0xFFFF , ANull ) ;
SetWriteHandler ( 0x0000 , 0xFFFF , BNull ) ;
SetReadHandler ( 0 , 0x7FF , ARAML ) ;
SetWriteHandler ( 0 , 0x7FF , BRAML ) ;
SetReadHandler ( 0x800 , 0x1FFF , ARAMH ) ; // Part of a little
SetWriteHandler ( 0x800 , 0x1FFF , BRAMH ) ; //hack for a small speed boost.
InitializeInput ( ) ;
FCEUSND_Power ( ) ;
FCEUPPU_Power ( ) ;
//Have the external game hardware "powered" after the internal NES stuff. Needed for the NSF code and VS System code.
GameInterface ( GI_POWER ) ;
if ( GameInfo - > type = = GIT_VSUNI )
FCEU_VSUniPower ( ) ;
//if we are in a movie, then reset the saveram
extern int disableBatteryLoading ;
if ( disableBatteryLoading )
GameInterface ( GI_RESETSAVE ) ;
2009-11-10 23:13:41 +01:00
2009-07-17 19:27:04 +02:00
timestampbase = 0 ;
LagCounterReset ( ) ;
X6502_Power ( ) ;
FCEU_PowerCheats ( ) ;
// clear back baffer
extern uint8 * XBackBuf ;
memset ( XBackBuf , 0 , 256 * 256 ) ;
2012-01-09 02:59:06 +01:00
# ifdef WIN32
Update_RAM_Search ( ) ; // Update_RAM_Watch() is also called.
# endif
2009-07-17 19:27:04 +02:00
}
void FCEU_ResetVidSys ( void )
{
int w ;
if ( GameInfo - > vidsys = = GIV_NTSC )
2009-11-10 23:13:41 +01:00
w = 0 ;
2009-07-17 19:27:04 +02:00
else if ( GameInfo - > vidsys = = GIV_PAL )
2009-11-10 23:13:41 +01:00
w = 1 ;
2009-07-17 19:27:04 +02:00
else
w = FSettings . PAL ;
PAL = w ? 1 : 0 ;
FCEUPPU_SetVideoSystem ( w ) ;
SetSoundVariables ( ) ;
}
FCEUS FSettings ;
void FCEU_printf ( char * format , . . . )
{
char temp [ 2048 ] ;
va_list ap ;
va_start ( ap , format ) ;
vsnprintf ( temp , sizeof ( temp ) , format , ap ) ;
FCEUD_Message ( temp ) ;
va_end ( ap ) ;
}
void FCEU_PrintError ( char * format , . . . )
{
char temp [ 2048 ] ;
va_list ap ;
va_start ( ap , format ) ;
vsnprintf ( temp , sizeof ( temp ) , format , ap ) ;
FCEUD_PrintError ( temp ) ;
va_end ( ap ) ;
}
void FCEUI_SetRenderedLines ( int ntscf , int ntscl , int palf , int pall )
{
FSettings . UsrFirstSLine [ 0 ] = ntscf ;
FSettings . UsrLastSLine [ 0 ] = ntscl ;
FSettings . UsrFirstSLine [ 1 ] = palf ;
FSettings . UsrLastSLine [ 1 ] = pall ;
if ( PAL )
{
FSettings . FirstSLine = FSettings . UsrFirstSLine [ 1 ] ;
FSettings . LastSLine = FSettings . UsrLastSLine [ 1 ] ;
}
else
{
FSettings . FirstSLine = FSettings . UsrFirstSLine [ 0 ] ;
FSettings . LastSLine = FSettings . UsrLastSLine [ 0 ] ;
}
}
void FCEUI_SetVidSystem ( int a )
{
FSettings . PAL = a ? 1 : 0 ;
if ( GameInfo )
{
FCEU_ResetVidSys ( ) ;
FCEU_ResetPalette ( ) ;
FCEUD_VideoChanged ( ) ;
}
}
int FCEUI_GetCurrentVidSystem ( int * slstart , int * slend )
{
if ( slstart )
* slstart = FSettings . FirstSLine ;
if ( slend )
* slend = FSettings . LastSLine ;
return ( PAL ) ;
}
//Enable or disable Game Genie option.
void FCEUI_SetGameGenie ( bool a )
{
FSettings . GameGenie = a ;
}
//this variable isn't used at all, snap is always name-based
//void FCEUI_SetSnapName(bool a)
//{
// FSettings.SnapName = a;
//}
int32 FCEUI_GetDesiredFPS ( void )
{
if ( PAL )
return ( 838977920 ) ; // ~50.007
else
return ( 1008307711 ) ; // ~60.1
}
int FCEUI_EmulationPaused ( void )
{
return ( EmulationPaused & 1 ) ;
}
int FCEUI_EmulationFrameStepped ( )
{
return ( EmulationPaused & 2 ) ;
}
void FCEUI_ClearEmulationFrameStepped ( )
{
EmulationPaused & = ~ 2 ;
}
//mbg merge 7/18/06 added
//ideally maybe we shouldnt be using this, but i need it for quick merging
void FCEUI_SetEmulationPaused ( int val )
{
EmulationPaused = val ;
}
void FCEUI_ToggleEmulationPause ( void )
{
EmulationPaused = ( EmulationPaused & 1 ) ^ 1 ;
2010-08-29 23:15:42 +02:00
DebuggerWasUpdated = false ;
2009-07-17 19:27:04 +02:00
}
void FCEUI_FrameAdvanceEnd ( void )
{
frameAdvanceRequested = false ;
}
void FCEUI_FrameAdvance ( void )
{
frameAdvanceRequested = true ;
frameAdvanceDelay = 0 ;
}
static int AutosaveCounter = 0 ;
void UpdateAutosave ( void )
{
2010-08-29 23:15:42 +02:00
if ( ! EnableAutosave | | turbo )
2009-07-17 19:27:04 +02:00
return ;
2009-11-10 23:13:41 +01:00
2009-07-17 19:27:04 +02:00
char * f ;
2009-11-27 09:53:39 +01:00
if ( + + AutosaveCounter > = AutosaveFrequency )
2009-07-17 19:27:04 +02:00
{
2009-11-27 09:53:39 +01:00
AutosaveCounter = 0 ;
AutosaveIndex = ( AutosaveIndex + 1 ) % AutosaveQty ;
2009-07-17 19:27:04 +02:00
f = strdup ( FCEU_MakeFName ( FCEUMKF_AUTOSTATE , AutosaveIndex , 0 ) . c_str ( ) ) ;
FCEUSS_Save ( f ) ;
AutoSS = true ; //Flag that an auto-savestate was made
free ( f ) ;
AutosaveStatus [ AutosaveIndex ] = 1 ;
}
}
void FCEUI_Autosave ( void )
{
2010-08-29 23:15:42 +02:00
if ( ! EnableAutosave | | ! AutoSS | | FCEUMOV_Mode ( MOVIEMODE_TASEDIT ) )
2009-07-17 19:27:04 +02:00
return ;
if ( AutosaveStatus [ AutosaveIndex ] = = 1 )
{
char * f ;
f = strdup ( FCEU_MakeFName ( FCEUMKF_AUTOSTATE , AutosaveIndex , 0 ) . c_str ( ) ) ;
FCEUSS_Load ( f ) ;
free ( f ) ;
//Set pointer to previous available slot
2009-11-27 09:53:39 +01:00
if ( AutosaveStatus [ ( AutosaveIndex + AutosaveQty - 1 ) % AutosaveQty ] = = 1 )
2009-07-17 19:27:04 +02:00
{
2009-11-27 09:53:39 +01:00
AutosaveIndex = ( AutosaveIndex + AutosaveQty - 1 ) % AutosaveQty ;
2009-07-17 19:27:04 +02:00
}
//Reset time to next Auto-save
AutosaveCounter = 0 ;
}
}
int FCEU_TextScanlineOffset ( int y )
{
return FSettings . FirstSLine * 256 ;
}
int FCEU_TextScanlineOffsetFromBottom ( int y )
{
return ( FSettings . LastSLine - y ) * 256 ;
}
bool FCEU_IsValidUI ( EFCEUI ui )
{
switch ( ui )
{
case FCEUI_OPENGAME :
case FCEUI_CLOSEGAME :
if ( FCEUMOV_Mode ( MOVIEMODE_TASEDIT ) ) return false ;
break ;
case FCEUI_RECORDMOVIE :
case FCEUI_PLAYMOVIE :
case FCEUI_QUICKSAVE :
case FCEUI_QUICKLOAD :
case FCEUI_SAVESTATE :
case FCEUI_LOADSTATE :
case FCEUI_NEXTSAVESTATE :
case FCEUI_PREVIOUSSAVESTATE :
case FCEUI_VIEWSLOTS :
if ( ! GameInfo ) return false ;
if ( FCEUMOV_Mode ( MOVIEMODE_TASEDIT ) ) return false ;
break ;
case FCEUI_STOPMOVIE :
case FCEUI_PLAYFROMBEGINNING :
2010-08-29 23:15:42 +02:00
return ( FCEUMOV_Mode ( MOVIEMODE_PLAY | MOVIEMODE_RECORD | MOVIEMODE_FINISHED ) ) ;
2009-07-17 19:27:04 +02:00
case FCEUI_STOPAVI :
return FCEUI_AviIsRecording ( ) ;
case FCEUI_TASEDIT :
if ( ! GameInfo ) return false ;
2012-01-09 02:59:06 +01:00
if ( FCEUMOV_Mode ( MOVIEMODE_TASEDIT ) ) return false ;
2009-07-17 19:27:04 +02:00
break ;
case FCEUI_RESET :
if ( ! GameInfo ) return false ;
2010-08-29 23:15:42 +02:00
if ( FCEUMOV_Mode ( MOVIEMODE_FINISHED | MOVIEMODE_TASEDIT | MOVIEMODE_PLAY ) ) return false ;
2009-07-17 19:27:04 +02:00
break ;
case FCEUI_POWER :
if ( ! GameInfo ) return false ;
if ( FCEUMOV_Mode ( MOVIEMODE_RECORD ) ) return true ;
if ( ! FCEUMOV_Mode ( MOVIEMODE_INACTIVE ) ) return false ;
break ;
}
return true ;
}
//---------------------
//experimental new mapper and ppu system follows
class FCEUXCart {
public :
int mirroring ;
int chrPages , prgPages ;
uint32 chrSize , prgSize ;
char * CHR , * PRG ;
FCEUXCart ( )
: CHR ( 0 )
, PRG ( 0 )
{ }
~ FCEUXCart ( ) {
if ( CHR ) delete [ ] CHR ;
if ( PRG ) delete [ ] PRG ;
}
virtual void Power ( ) {
}
protected :
//void SetReadHandler(int32 start, int32 end, readfunc func) {
} ;
FCEUXCart * cart = 0 ;
//uint8 Read_ByteFromRom(uint32 A) {
// if(A>=cart->prgSize) return 0xFF;
// return cart->PRG[A];
//}
//
//uint8 Read_Unmapped(uint32 A) {
// return 0xFF;
//}
class NROM : FCEUXCart {
public :
virtual void Power ( ) {
SetReadHandler ( 0x8000 , 0xFFFF , CartBR ) ;
setprg16 ( 0x8000 , 0 ) ;
setprg16 ( 0xC000 , ~ 0 ) ;
setchr8 ( 0 ) ;
vnapage [ 0 ] = NTARAM ;
vnapage [ 2 ] = NTARAM ;
vnapage [ 1 ] = NTARAM + 0x400 ;
vnapage [ 3 ] = NTARAM + 0x400 ;
PPUNTARAM = 0xF ;
}
} ;
void FCEUXGameInterface ( GI command ) {
switch ( command ) {
case GI_POWER :
cart - > Power ( ) ;
}
}
bool FCEUXLoad ( const char * name , FCEUFILE * fp )
{
//read ines header
iNES_HEADER head ;
if ( FCEU_fread ( & head , 1 , 16 , fp ) ! = 16 )
return false ;
//validate header
if ( memcmp ( & head , " NES \x1a " , 4 ) )
return 0 ;
int mapper = ( head . ROM_type > > 4 ) ;
mapper | = ( head . ROM_type2 & 0xF0 ) ;
//choose what kind of cart to use.
cart = ( FCEUXCart * ) new NROM ( ) ;
//fceu ines loading code uses 256 here when the romsize is 0.
cart - > prgPages = head . ROM_size ;
if ( cart - > prgPages = = 0 ) {
printf ( " FCEUX: received zero prgpages \n " ) ;
cart - > prgPages = 256 ;
}
cart - > chrPages = head . VROM_size ;
2009-11-10 23:13:41 +01:00
cart - > mirroring = ( head . ROM_type & 1 ) ;
2009-07-17 19:27:04 +02:00
if ( head . ROM_type & 8 ) cart - > mirroring = 2 ;
//skip trainer
bool hasTrainer = ( head . ROM_type & 4 ) ! = 0 ;
if ( hasTrainer ) {
FCEU_fseek ( fp , 512 , SEEK_CUR ) ;
}
//load data
cart - > prgSize = cart - > prgPages * 16 * 1024 ;
cart - > chrSize = cart - > chrPages * 8 * 1024 ;
cart - > PRG = new char [ cart - > prgSize ] ;
cart - > CHR = new char [ cart - > chrSize ] ;
FCEU_fread ( cart - > PRG , 1 , cart - > prgSize , fp ) ;
FCEU_fread ( cart - > CHR , 1 , cart - > chrSize , fp ) ;
//setup the emulator
GameInterface = FCEUXGameInterface ;
ResetCartMapping ( ) ;
SetupCartPRGMapping ( 0 , ( uint8 * ) cart - > PRG , cart - > prgSize , 0 ) ;
SetupCartCHRMapping ( 0 , ( uint8 * ) cart - > CHR , cart - > chrSize , 0 ) ;
2009-11-10 23:13:41 +01:00
2009-07-17 19:27:04 +02:00
return true ;
}
uint8 FCEU_ReadRomByte ( uint32 i ) {
extern iNES_HEADER head ;
if ( i < 16 ) return * ( ( unsigned char * ) & head + i ) ;
if ( i < 16 + PRGsize [ 0 ] ) return PRGptr [ 0 ] [ i - 16 ] ;
if ( i < 16 + PRGsize [ 0 ] + CHRsize [ 0 ] ) return CHRptr [ 0 ] [ i - 16 - PRGsize [ 0 ] ] ;
return 0 ;
2009-11-03 09:16:57 +01:00
}