2009-07-17 17:27:04 +00:00
/* FCE Ultra - NES/Famicom Emulator
2012-12-14 17:18:20 +00:00
*
* 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 . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
2009-07-17 17:27:04 +00:00
# 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 04:40:55 +00:00
# ifdef WIN32
# include "drivers/win/pref.h"
2016-09-17 20:43:24 -07:00
# include "utils/xstring.h"
2012-01-09 01:59:06 +00:00
2016-09-17 20:43:24 -07:00
extern void CDLoggerROMClosed ( ) ;
extern void CDLoggerROMChanged ( ) ;
2012-12-14 17:18:20 +00:00
extern void ResetDebugStatisticsCounters ( ) ;
extern void SetMainWindowText ( ) ;
2016-09-17 20:43:24 -07:00
extern bool isTaseditorRecording ( ) ;
2012-12-14 17:43:51 +00:00
extern int32 fps_scale ;
extern int32 fps_scale_unpaused ;
extern int32 fps_scale_frameadvance ;
2009-10-07 04:40:55 +00:00
# endif
2018-08-13 09:04:20 -06:00
extern void RefreshThrottleFPS ( ) ;
2009-07-17 17:27:04 +00:00
# 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"
2016-09-17 20:43:24 -07:00
# include "drivers/win/memview.h"
2009-07-17 17:27:04 +00:00
# include "drivers/win/cheat.h"
# include "drivers/win/texthook.h"
2009-11-03 08:16:57 +00:00
# include "drivers/win/ram_search.h"
# include "drivers/win/ramwatch.h"
2009-07-17 17:27:04 +00:00
# include "drivers/win/memwatch.h"
# include "drivers/win/tracer.h"
# else
2009-07-17 18:01:31 +00:00
# ifdef GEKKO
# include "driver.h"
# else
2009-07-17 17:27:04 +00:00
# include "drivers/sdl/sdl.h"
# endif
2009-07-17 18:01:31 +00:00
# endif
2009-07-17 17:27:04 +00:00
2016-09-17 20:43:24 -07:00
# include <fstream>
# include <sstream>
# include <string>
# include <cstring>
# include <cstdio>
# include <cstdlib>
# include <cstdarg>
# include <ctime>
2009-07-17 17:27:04 +00:00
using namespace std ;
2018-08-13 09:04:20 -06:00
//-----------
//overclocking-related
// overclock the console by adding dummy scanlines to PPU loop or to vblank
// disables DMC DMA, WaveHi filling and image rendering for these dummies
// doesn't work with new PPU
bool overclock_enabled = 0 ;
bool overclocking = 0 ;
bool skip_7bit_overclocking = 1 ; // 7-bit samples have priority over overclocking
int normalscanlines ;
int totalscanlines ;
int postrenderscanlines = 0 ;
int vblankscanlines = 0 ;
//------------
2009-07-17 17:27:04 +00:00
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)
2012-12-14 17:43:51 +00:00
bool AutoSS = false ; //Flagged true when the first auto-savestate is made while a game is loaded, flagged false on game close
2009-07-17 17:27:04 +00:00
bool movieSubtitles = true ; //Toggle for displaying movie subtitles
2010-08-29 21:15:42 +00:00
bool DebuggerWasUpdated = false ; //To prevent the debugger from updating things without being updated.
2013-01-01 23:27:33 +00:00
bool AutoResumePlay = false ;
2016-09-17 20:43:24 -07:00
char romNameWhenClosingEmulator [ 2048 ] = { 0 } ;
2009-07-17 17:27:04 +00:00
FCEUGI : : FCEUGI ( )
2016-09-17 20:43:24 -07:00
: filename ( 0 ) ,
archiveFilename ( 0 ) {
2012-06-26 23:14:39 +00:00
//printf("%08x",opsize); // WTF?!
2009-07-17 17:27:04 +00:00
}
2012-12-14 17:43:51 +00:00
FCEUGI : : ~ FCEUGI ( ) {
2016-09-17 20:43:24 -07:00
if ( filename ) {
free ( filename ) ;
filename = NULL ;
}
if ( archiveFilename ) {
delete archiveFilename ;
archiveFilename = NULL ;
}
2009-07-17 17:27:04 +00:00
}
2012-12-14 17:43:51 +00:00
bool CheckFileExists ( const char * filename ) {
2010-08-29 21:15:42 +00:00
//This function simply checks to see if the given filename exists
if ( ! filename ) return false ;
fstream test ;
2012-12-14 17:43:51 +00:00
test . open ( filename , fstream : : in ) ;
2012-12-14 17:18:20 +00:00
2012-12-14 17:43:51 +00:00
if ( test . fail ( ) ) {
2010-08-29 21:15:42 +00:00
test . close ( ) ;
2012-12-14 17:18:20 +00:00
return false ;
2012-12-14 17:43:51 +00:00
} else {
2010-08-29 21:15:42 +00:00
test . close ( ) ;
2012-12-14 17:18:20 +00:00
return true ;
2010-08-29 21:15:42 +00:00
}
}
2012-12-14 17:43:51 +00:00
void FCEU_TogglePPU ( void ) {
2010-08-29 21:15:42 +00:00
newppu ^ = 1 ;
2012-12-14 17:43:51 +00:00
if ( newppu ) {
2010-08-29 21:15:42 +00:00
FCEU_DispMessage ( " New PPU loaded " , 0 ) ;
FCEUI_printf ( " New PPU loaded " ) ;
2018-08-13 09:04:20 -06:00
overclock_enabled = 0 ;
2012-12-14 17:43:51 +00:00
} else {
2010-08-29 21:15:42 +00:00
FCEU_DispMessage ( " Old PPU loaded " , 0 ) ;
FCEUI_printf ( " Old PPU loaded " ) ;
}
2018-08-13 09:04:20 -06:00
normalscanlines = ( dendy ? 290 : 240 ) + newppu ; // use flag as number!
2012-12-14 17:18:20 +00:00
# ifdef WIN32
SetMainWindowText ( ) ;
# endif
2010-08-29 21:15:42 +00:00
}
2013-01-01 23:27:33 +00:00
static void FCEU_CloseGame ( void )
{
if ( GameInfo )
{
2016-09-17 20:43:24 -07:00
if ( AutoResumePlay )
2013-01-01 23:27:33 +00:00
{
// save "-resume" savestate
2016-09-17 20:43:24 -07:00
FCEUSS_Save ( FCEU_MakeFName ( FCEUMKF_RESUMESTATE , 0 , 0 ) . c_str ( ) , false ) ;
2013-01-01 23:27:33 +00:00
}
2009-10-07 04:40:55 +00:00
# ifdef WIN32
2012-12-14 17:43:51 +00:00
extern char LoadedRomFName [ 2048 ] ;
2016-09-17 20:43:24 -07:00
if ( storePreferences ( mass_replace ( LoadedRomFName , " | " , " . " ) . c_str ( ) ) )
2012-12-14 17:43:51 +00:00
FCEUD_PrintError ( " Couldn't store debugging data " ) ;
2016-09-17 20:43:24 -07:00
CDLoggerROMClosed ( ) ;
2009-10-07 04:40:55 +00:00
# endif
2012-12-14 17:43:51 +00:00
if ( FCEUnetplay ) {
2009-07-17 17:27:04 +00:00
FCEUD_NetworkClose ( ) ;
}
2012-12-14 17:43:51 +00:00
if ( GameInfo - > name ) {
2009-07-17 17:27:04 +00:00
free ( GameInfo - > name ) ;
2016-09-17 20:43:24 -07:00
GameInfo - > name = NULL ;
2009-07-17 17:27:04 +00:00
}
2012-12-14 17:43:51 +00:00
if ( GameInfo - > type ! = GIT_NSF ) {
FCEU_FlushGameCheats ( 0 , 0 ) ;
2009-07-17 17:27:04 +00:00
}
GameInterface ( GI_CLOSE ) ;
FCEUI_StopMovie ( ) ;
2012-12-14 17:43:51 +00:00
ResetExState ( 0 , 0 ) ;
2009-07-17 17:27:04 +00:00
2010-08-29 21:15:42 +00:00
//clear screen when game is closed
2009-07-17 17:27:04 +00:00
extern uint8 * XBuf ;
2012-12-14 17:43:51 +00:00
if ( XBuf )
memset ( XBuf , 0 , 256 * 256 ) ;
2009-07-17 17:27:04 +00:00
2012-12-14 17:43:51 +00:00
FCEU_CloseGenie ( ) ;
2009-07-17 17:27:04 +00:00
delete GameInfo ;
2012-06-26 23:14:39 +00:00
GameInfo = NULL ;
2012-12-14 17:18:20 +00:00
2009-07-17 17:27:04 +00:00
currFrameCounter = 0 ;
2010-08-29 21:15:42 +00:00
//Reset flags for Undo/Redo/Auto Savestating //adelikat: TODO: maybe this stuff would be cleaner as a struct or class
2009-07-17 17:27:04 +00:00
lastSavestateMade [ 0 ] = 0 ;
undoSS = false ;
redoSS = false ;
lastLoadstateMade [ 0 ] = 0 ;
undoLS = false ;
redoLS = false ;
AutoSS = false ;
}
}
uint64 timestampbase ;
2012-06-26 23:14:39 +00:00
FCEUGI * GameInfo = NULL ;
2009-07-17 17:27:04 +00:00
void ( * GameInterface ) ( GI h ) ;
void ( * GameStateRestore ) ( int version ) ;
readfunc ARead [ 0x10000 ] ;
writefunc BWrite [ 0x10000 ] ;
static readfunc * AReadG ;
static writefunc * BWriteG ;
2012-12-14 17:43:51 +00:00
static int RWWrap = 0 ;
2009-07-17 17:27:04 +00:00
//mbg merge 7/18/06 docs
//bit0 indicates whether emulation is paused
//bit1 indicates whether emulation is in frame step mode
2012-12-14 17:43:51 +00:00
int EmulationPaused = 0 ;
2009-07-17 17:27:04 +00:00
bool frameAdvanceRequested = false ;
2012-12-14 17:43:51 +00:00
int frameAdvance_Delay_count = 0 ;
int frameAdvance_Delay = FRAMEADVANCE_DELAY_DEFAULT ;
2009-07-17 17:27:04 +00:00
//indicates that the emulation core just frame advanced (consumed the frame advance state and paused)
2012-12-14 17:18:20 +00:00
bool JustFrameAdvanced = false ;
2009-07-17 17:27:04 +00:00
2009-11-27 08:53:39 +00:00
static int * AutosaveStatus ; //is it safe to load Auto-savestate
2009-07-17 17:27:04 +00:00
static int AutosaveIndex = 0 ; //which Auto-savestate we're on
2009-11-27 08:53:39 +00:00
int AutosaveQty = 4 ; // Number of Autosaves to store
int AutosaveFrequency = 256 ; // Number of frames between autosaves
2009-07-17 17:27:04 +00:00
// Flag that indicates whether the Auto-save option is enabled or not
int EnableAutosave = 0 ;
///a wrapper for unzip.c
2012-12-14 17:43:51 +00:00
extern " C " FILE * FCEUI_UTF8fopen_C ( const char * n , const char * m ) {
return : : FCEUD_UTF8fopen ( n , m ) ;
}
2009-07-17 17:27:04 +00:00
2012-12-14 17:43:51 +00:00
static DECLFW ( BNull ) {
2009-07-17 17:27:04 +00:00
}
2012-12-14 17:43:51 +00:00
static DECLFR ( ANull ) {
2009-07-17 17:27:04 +00:00
return ( X . DB ) ;
}
2012-12-14 17:43:51 +00:00
int AllocGenieRW ( void ) {
if ( ! ( AReadG = ( readfunc * ) FCEU_malloc ( 0x8000 * sizeof ( readfunc ) ) ) )
2009-07-17 17:27:04 +00:00
return 0 ;
2012-12-14 17:43:51 +00:00
if ( ! ( BWriteG = ( writefunc * ) FCEU_malloc ( 0x8000 * sizeof ( writefunc ) ) ) )
2009-07-17 17:27:04 +00:00
return 0 ;
2012-12-14 17:43:51 +00:00
RWWrap = 1 ;
2009-07-17 17:27:04 +00:00
return 1 ;
}
2012-12-14 17:43:51 +00:00
void FlushGenieRW ( void ) {
2009-07-17 17:27:04 +00:00
int32 x ;
2012-12-14 17:43:51 +00:00
if ( RWWrap ) {
for ( x = 0 ; x < 0x8000 ; x + + ) {
ARead [ x + 0x8000 ] = AReadG [ x ] ;
BWrite [ x + 0x8000 ] = BWriteG [ x ] ;
2009-07-17 17:27:04 +00:00
}
free ( AReadG ) ;
free ( BWriteG ) ;
2016-09-17 20:43:24 -07:00
AReadG = NULL ;
BWriteG = NULL ;
2012-12-14 17:43:51 +00:00
RWWrap = 0 ;
2009-07-17 17:27:04 +00:00
}
}
2012-12-14 17:43:51 +00:00
readfunc GetReadHandler ( int32 a ) {
if ( a > = 0x8000 & & RWWrap )
return AReadG [ a - 0x8000 ] ;
2009-07-17 17:27:04 +00:00
else
return ARead [ a ] ;
}
2016-09-17 20:43:24 -07:00
2012-12-14 17:43:51 +00:00
void SetReadHandler ( int32 start , int32 end , readfunc func ) {
2009-07-17 17:27:04 +00:00
int32 x ;
2016-09-17 20:43:24 -07:00
2012-12-14 17:43:51 +00:00
if ( ! func )
func = ANull ;
2009-07-17 17:27:04 +00:00
2012-12-14 17:43:51 +00:00
if ( RWWrap )
for ( x = end ; x > = start ; x - - ) {
if ( x > = 0x8000 )
AReadG [ x - 0x8000 ] = func ;
2009-07-17 17:27:04 +00:00
else
2012-12-14 17:43:51 +00:00
ARead [ x ] = func ;
2009-07-17 17:27:04 +00:00
}
else
2012-12-14 17:43:51 +00:00
for ( x = end ; x > = start ; x - - )
ARead [ x ] = func ;
2009-07-17 17:27:04 +00:00
}
2012-12-14 17:43:51 +00:00
writefunc GetWriteHandler ( int32 a ) {
if ( RWWrap & & a > = 0x8000 )
return BWriteG [ a - 0x8000 ] ;
2009-07-17 17:27:04 +00:00
else
return BWrite [ a ] ;
}
2012-12-14 17:43:51 +00:00
void SetWriteHandler ( int32 start , int32 end , writefunc func ) {
2009-07-17 17:27:04 +00:00
int32 x ;
2012-12-14 17:43:51 +00:00
if ( ! func )
func = BNull ;
2009-07-17 17:27:04 +00:00
2012-12-14 17:43:51 +00:00
if ( RWWrap )
for ( x = end ; x > = start ; x - - ) {
if ( x > = 0x8000 )
BWriteG [ x - 0x8000 ] = func ;
2009-07-17 17:27:04 +00:00
else
2012-12-14 17:43:51 +00:00
BWrite [ x ] = func ;
2009-07-17 17:27:04 +00:00
}
else
2012-12-14 17:43:51 +00:00
for ( x = end ; x > = start ; x - - )
BWrite [ x ] = func ;
2009-07-17 17:27:04 +00:00
}
uint8 * RAM ;
//---------
//windows might need to allocate these differently, so we have some special code
2012-12-14 17:43:51 +00:00
static void AllocBuffers ( ) {
2009-07-17 17:27:04 +00:00
RAM = ( uint8 * ) FCEU_gmalloc ( 0x800 ) ;
}
2012-12-14 17:43:51 +00:00
static void FreeBuffers ( ) {
2009-07-17 17:27:04 +00:00
FCEU_free ( RAM ) ;
2016-09-17 20:43:24 -07:00
RAM = NULL ;
2009-07-17 17:27:04 +00:00
}
//------
2012-12-14 17:43:51 +00:00
uint8 PAL = 0 ;
2009-07-17 17:27:04 +00:00
2012-12-14 17:43:51 +00:00
static DECLFW ( BRAML ) {
RAM [ A ] = V ;
2009-07-17 17:27:04 +00:00
}
2012-12-14 17:43:51 +00:00
static DECLFW ( BRAMH ) {
RAM [ A & 0x7FF ] = V ;
2009-07-17 17:27:04 +00:00
}
2012-12-14 17:43:51 +00:00
static DECLFR ( ARAML ) {
2009-07-17 17:27:04 +00:00
return RAM [ A ] ;
}
2012-12-14 17:43:51 +00:00
static DECLFR ( ARAMH ) {
return RAM [ A & 0x7FF ] ;
2009-07-17 17:27:04 +00:00
}
2012-12-14 17:43:51 +00:00
void ResetGameLoaded ( void ) {
if ( GameInfo ) FCEU_CloseGame ( ) ;
2009-07-17 17:27:04 +00:00
EmulationPaused = 0 ; //mbg 5/8/08 - loading games while paused was bad news. maybe this fixes it
2012-12-14 17:43:51 +00:00
GameStateRestore = 0 ;
2016-09-17 20:43:24 -07:00
PPU_hook = NULL ;
GameHBIRQHook = NULL ;
FFCEUX_PPURead = NULL ;
FFCEUX_PPUWrite = NULL ;
2012-12-14 17:43:51 +00:00
if ( GameExpSound . Kill )
2009-07-17 17:27:04 +00:00
GameExpSound . Kill ( ) ;
2012-12-14 17:43:51 +00:00
memset ( & GameExpSound , 0 , sizeof ( GameExpSound ) ) ;
2016-09-17 20:43:24 -07:00
MapIRQHook = NULL ;
2012-12-14 17:43:51 +00:00
MMC5Hack = 0 ;
2016-09-17 20:43:24 -07:00
PEC586Hack = 0 ;
2012-12-14 17:43:51 +00:00
PAL & = 1 ;
2018-08-13 09:04:20 -06:00
default_palette_selection = 0 ;
2009-07-17 17:27:04 +00:00
}
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 08:20:48 +00:00
int NSFLoad ( const char * name , FCEUFILE * fp ) ;
2009-07-17 17:27:04 +00:00
//char lastLoadedGameName [2048] = {0,}; // hack for movie WRAM clearing on record from poweron
2012-12-14 17:18:20 +00:00
//name should be UTF-8, hopefully, or else there may be trouble
2013-01-01 23:27:33 +00:00
FCEUGI * FCEUI_LoadGameVirtual ( const char * name , int OverwriteVidMode , bool silent )
{
2009-07-17 17:27:04 +00:00
//----------
//attempt to open the files
FCEUFILE * fp ;
2016-09-17 20:43:24 -07:00
char fullname [ 2048 ] ; // this name contains both archive name and ROM file name
2018-08-13 09:04:20 -06:00
int lastpal = PAL ;
int lastdendy = dendy ;
2009-07-17 17:27:04 +00:00
2012-12-14 17:43:51 +00:00
const char * romextensions [ ] = { " nes " , " fds " , 0 } ;
fp = FCEU_fopen ( name , 0 , " rb " , 0 , - 1 , romextensions ) ;
2009-07-17 17:27:04 +00:00
2013-01-01 23:27:33 +00:00
if ( ! fp )
{
if ( ! silent )
FCEU_PrintError ( " Error opening \" %s \" ! " , name ) ;
2009-07-17 17:27:04 +00:00
return 0 ;
2016-09-17 20:43:24 -07:00
} else if ( fp - > archiveFilename ! = " " )
{
strcpy ( fullname , fp - > archiveFilename . c_str ( ) ) ;
strcat ( fullname , " | " ) ;
strcat ( fullname , fp - > filename . c_str ( ) ) ;
} else
{
strcpy ( fullname , name ) ;
2009-07-17 17:27:04 +00:00
}
2012-01-09 01:59:06 +00:00
2009-07-17 17:27:04 +00:00
//file opened ok. start loading.
2016-09-17 20:43:24 -07:00
FCEU_printf ( " Loading %s... \n \n " , fullname ) ;
GetFileBase ( fp - > filename . c_str ( ) ) ;
2009-07-17 17:27:04 +00:00
ResetGameLoaded ( ) ;
2016-09-17 20:43:24 -07:00
//reset parameters so they're cleared just in case a format's loader doesn't know to do the clearing
2012-12-14 17:18:20 +00:00
MasterRomInfoParams = TMasterRomInfoParams ( ) ;
2009-11-27 08:53:39 +00:00
if ( ! AutosaveStatus )
2012-12-14 17:43:51 +00:00
AutosaveStatus = ( int * ) FCEU_dmalloc ( sizeof ( int ) * AutosaveQty ) ;
for ( AutosaveIndex = 0 ; AutosaveIndex < AutosaveQty ; + + AutosaveIndex )
2009-11-27 08:53:39 +00:00
AutosaveStatus [ AutosaveIndex ] = 0 ;
2009-07-17 17:27:04 +00:00
2009-12-14 06:56:29 +00:00
FCEU_CloseGame ( ) ;
2009-07-17 17:27:04 +00:00
GameInfo = new FCEUGI ( ) ;
memset ( GameInfo , 0 , sizeof ( FCEUGI ) ) ;
GameInfo - > filename = strdup ( fp - > filename . c_str ( ) ) ;
2016-09-17 20:43:24 -07:00
if ( fp - > archiveFilename ! = " " )
GameInfo - > archiveFilename = strdup ( fp - > archiveFilename . c_str ( ) ) ;
2009-07-17 17:27:04 +00:00
GameInfo - > archiveCount = fp - > archiveCount ;
GameInfo - > soundchan = 0 ;
GameInfo - > soundrate = 0 ;
2012-12-14 17:43:51 +00:00
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 ;
2009-07-17 17:27:04 +00:00
//try to load each different format
2012-12-14 17:43:51 +00:00
bool FCEUXLoad ( const char * name , FCEUFILE * fp ) ;
2009-07-17 17:27:04 +00:00
/*if(FCEUXLoad(name,fp))
2012-12-14 17:43:51 +00:00
goto endlseq ; */
2016-09-17 20:43:24 -07:00
if ( iNESLoad ( fullname , fp , OverwriteVidMode ) )
2009-07-17 17:27:04 +00:00
goto endlseq ;
2016-09-17 20:43:24 -07:00
if ( NSFLoad ( fullname , fp ) )
2009-07-17 17:27:04 +00:00
goto endlseq ;
2016-09-17 20:43:24 -07:00
if ( UNIFLoad ( fullname , fp ) )
2009-07-17 17:27:04 +00:00
goto endlseq ;
2016-09-17 20:43:24 -07:00
if ( FDSLoad ( fullname , fp ) )
2009-07-17 17:27:04 +00:00
goto endlseq ;
2013-01-01 23:27:33 +00:00
if ( ! silent )
FCEU_PrintError ( " An error occurred while loading the file. " ) ;
2009-07-17 17:27:04 +00:00
FCEU_fclose ( fp ) ;
delete GameInfo ;
GameInfo = 0 ;
return 0 ;
2012-12-14 17:43:51 +00:00
endlseq :
2009-07-17 17:27:04 +00:00
FCEU_fclose ( fp ) ;
2009-10-07 04:40:55 +00:00
# ifdef WIN32
// ################################## Start of SP CODE ###########################
2012-12-14 17:43:51 +00:00
extern char LoadedRomFName [ 2048 ] ;
extern int loadDebugDataFailed ;
2009-10-07 04:40:55 +00:00
2016-09-17 20:43:24 -07:00
if ( ( loadDebugDataFailed = loadPreferences ( mass_replace ( LoadedRomFName , " | " , " . " ) . c_str ( ) ) ) )
2013-01-01 23:27:33 +00:00
if ( ! silent )
FCEU_printf ( " Couldn't load debugging data. \n " ) ;
2009-10-07 04:40:55 +00:00
// ################################## End of SP CODE ###########################
# endif
2018-08-13 09:04:20 -06:00
if ( OverwriteVidMode )
FCEU_ResetVidSys ( ) ;
2009-07-17 17:27:04 +00:00
2012-12-14 17:43:51 +00:00
if ( GameInfo - > type ! = GIT_NSF )
2016-09-17 20:43:24 -07:00
{
2012-12-14 17:43:51 +00:00
if ( FSettings . GameGenie )
2016-09-17 20:43:24 -07:00
{
if ( FCEU_OpenGenie ( ) )
{
FCEUI_SetGameGenie ( false ) ;
# ifdef WIN32
genie = 0 ;
# endif
}
}
}
2009-07-17 17:27:04 +00:00
PowerNES ( ) ;
2012-12-14 17:43:51 +00:00
if ( GameInfo - > type ! = GIT_NSF )
2009-07-17 17:27:04 +00:00
FCEU_LoadGamePalette ( ) ;
FCEU_ResetPalette ( ) ;
2012-12-14 17:43:51 +00:00
FCEU_ResetMessages ( ) ; // Save state, status messages, etc.
2009-07-17 17:27:04 +00:00
2018-08-13 09:04:20 -06:00
if ( ! lastpal & & PAL ) {
FCEU_DispMessage ( " PAL mode set " , 0 ) ;
FCEUI_printf ( " PAL mode set " ) ;
} else if ( ! lastdendy & & dendy ) {
// this won't happen, since we don't autodetect dendy, but maybe someday we will?
FCEU_DispMessage ( " Dendy mode set " , 0 ) ;
FCEUI_printf ( " Dendy mode set " ) ;
} else if ( ( lastpal | | lastdendy ) & & ! ( PAL | | dendy ) ) {
FCEU_DispMessage ( " NTSC mode set " , 0 ) ;
FCEUI_printf ( " NTSC mode set " ) ;
}
2012-12-14 17:43:51 +00:00
if ( GameInfo - > type ! = GIT_NSF )
2009-07-17 17:27:04 +00:00
FCEU_LoadGameCheats ( 0 ) ;
2016-09-17 20:43:24 -07:00
if ( AutoResumePlay )
2013-01-01 23:27:33 +00:00
{
// load "-resume" savestate
2016-09-17 20:43:24 -07:00
if ( FCEUSS_Load ( FCEU_MakeFName ( FCEUMKF_RESUMESTATE , 0 , 0 ) . c_str ( ) , false ) )
2013-01-01 23:27:33 +00:00
FCEU_DispMessage ( " Old play session resumed. " , 0 ) ;
}
2012-12-14 17:18:20 +00:00
ResetScreenshotsCounter ( ) ;
2016-09-17 20:43:24 -07:00
# if defined (WIN32) || defined (WIN64)
DoDebuggerDataReload ( ) ; // Reloads data without reopening window
CDLoggerROMChanged ( ) ;
if ( hMemView ) UpdateColorTable ( ) ;
if ( hCheat ) UpdateCheatsAdded ( ) ;
if ( FrozenAddressCount )
FCEU_DispMessage ( " %d cheats active " , 0 , FrozenAddressCount ) ;
# endif
2009-07-17 17:27:04 +00:00
return GameInfo ;
}
2013-01-01 23:27:33 +00:00
FCEUGI * FCEUI_LoadGame ( const char * name , int OverwriteVidMode , bool silent )
{
return FCEUI_LoadGameVirtual ( name , OverwriteVidMode , silent ) ;
2009-07-17 17:27:04 +00:00
}
//Return: Flag that indicates whether the function was succesful or not.
2012-12-14 17:43:51 +00:00
bool FCEUI_Initialize ( ) {
2009-07-17 17:27:04 +00:00
srand ( time ( 0 ) ) ;
2012-12-14 17:43:51 +00:00
if ( ! FCEU_InitVirtualVideo ( ) ) {
2009-07-17 17:27:04 +00:00
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
2012-12-14 17:43:51 +00:00
memset ( & FSettings , 0 , sizeof ( FSettings ) ) ;
2009-07-17 17:27:04 +00:00
//FSettings.UsrFirstSLine[0]=8;
2012-12-14 17:43:51 +00:00
FSettings . UsrFirstSLine [ 0 ] = 0 ;
FSettings . UsrFirstSLine [ 1 ] = 0 ;
2009-07-17 17:27:04 +00:00
//FSettings.UsrLastSLine[0]=231;
2012-12-14 17:43:51 +00:00
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)
2009-07-17 17:27:04 +00:00
FCEUPPU_Init ( ) ;
X6502_Init ( ) ;
return true ;
}
2012-12-14 17:43:51 +00:00
void FCEUI_Kill ( void ) {
2009-07-17 17:27:04 +00:00
# ifdef _S9XLUA_H
FCEU_LuaStop ( ) ;
# endif
FCEU_KillVirtualVideo ( ) ;
FCEU_KillGenie ( ) ;
FreeBuffers ( ) ;
}
int rapidAlternator = 0 ;
2012-12-14 17:43:51 +00:00
int AutoFirePattern [ 8 ] = { 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
2009-07-17 17:27:04 +00:00
int AutoFirePatternLength = 2 ;
2012-12-14 17:43:51 +00:00
void SetAutoFirePattern ( int onframes , int offframes ) {
2009-07-17 17:27:04 +00:00
int i ;
2012-12-14 17:43:51 +00:00
for ( i = 0 ; i < onframes & & i < 8 ; i + + ) {
2009-07-17 17:27:04 +00:00
AutoFirePattern [ i ] = 1 ;
}
2012-12-14 17:43:51 +00:00
for ( ; i < 8 ; i + + ) {
2009-07-17 17:27:04 +00:00
AutoFirePattern [ i ] = 0 ;
}
2012-12-14 17:43:51 +00:00
if ( onframes + offframes < 2 ) {
2009-07-17 17:27:04 +00:00
AutoFirePatternLength = 2 ;
2012-12-14 17:43:51 +00:00
} else if ( onframes + offframes > 8 ) {
2009-07-17 17:27:04 +00:00
AutoFirePatternLength = 8 ;
2012-12-14 17:43:51 +00:00
} else {
2009-07-17 17:27:04 +00:00
AutoFirePatternLength = onframes + offframes ;
}
AFon = onframes ; AFoff = offframes ;
}
2012-12-14 17:43:51 +00:00
void SetAutoFireOffset ( int offset ) {
if ( offset < 0 | | offset > 8 ) return ;
2009-07-17 17:27:04 +00:00
AutoFireOffset = offset ;
}
2012-12-14 17:43:51 +00:00
void AutoFire ( void ) {
2009-07-17 17:27:04 +00:00
static int counter = 0 ;
2012-12-14 17:18:20 +00:00
if ( justLagged = = false )
2012-12-14 17:43:51 +00:00
counter = ( counter + 1 ) % ( 8 * 7 * 5 * 3 ) ;
2009-07-17 17:27:04 +00:00
//If recording a movie, use the frame # for the autofire so the offset
//doesn't get screwed up when loading.
2012-12-14 17:43:51 +00:00
if ( FCEUMOV_Mode ( MOVIEMODE_RECORD | MOVIEMODE_PLAY ) ) {
rapidAlternator = AutoFirePattern [ ( AutoFireOffset + FCEUMOV_GetFrame ( ) ) % AutoFirePatternLength ] ; //adelikat: TODO: Think through this, MOVIEMODE_FINISHED should not use movie data for auto-fire?
} else {
rapidAlternator = AutoFirePattern [ ( AutoFireOffset + counter ) % AutoFirePatternLength ] ;
2009-07-17 17:27:04 +00:00
}
}
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
2012-12-14 17:43:51 +00:00
void FCEUI_Emulate ( uint8 * * pXBuf , int32 * * SoundBuf , int32 * SoundBufSize , int skip ) {
2009-07-17 17:27:04 +00:00
//skip initiates frame skip if 1, or frame skip and sound skip if 2
2012-12-14 17:43:51 +00:00
int r , ssize ;
2009-07-17 17:27:04 +00:00
JustFrameAdvanced = false ;
if ( frameAdvanceRequested )
{
2012-12-14 17:43:51 +00:00
if ( frameAdvance_Delay_count = = 0 | | frameAdvance_Delay_count > = frameAdvance_Delay )
EmulationPaused = EMULATIONPAUSED_FA ;
if ( frameAdvance_Delay_count < frameAdvance_Delay )
frameAdvance_Delay_count + + ;
2009-07-17 17:27:04 +00:00
}
2012-12-14 17:43:51 +00:00
if ( EmulationPaused & EMULATIONPAUSED_FA )
2009-07-17 17:27:04 +00:00
{
2012-12-14 17:43:51 +00:00
// the user is holding Frame Advance key
// clear paused flag temporarily
EmulationPaused & = ~ EMULATIONPAUSED_PAUSED ;
# ifdef WIN32
// different emulation speed when holding Frame Advance
if ( fps_scale_frameadvance > 0 )
{
fps_scale = fps_scale_frameadvance ;
RefreshThrottleFPS ( ) ;
}
# endif
} else
{
# ifdef WIN32
if ( fps_scale_frameadvance > 0 )
{
// restore emulation speed when Frame Advance is not held
fps_scale = fps_scale_unpaused ;
RefreshThrottleFPS ( ) ;
}
# endif
if ( EmulationPaused & EMULATIONPAUSED_PAUSED )
{
// emulator is paused
memcpy ( XBuf , XBackBuf , 256 * 256 ) ;
FCEU_PutImage ( ) ;
* pXBuf = XBuf ;
* SoundBuf = WaveFinal ;
* SoundBufSize = 0 ;
return ;
}
2009-07-17 17:27:04 +00:00
}
AutoFire ( ) ;
UpdateAutosave ( ) ;
# ifdef _S9XLUA_H
FCEU_LuaFrameBoundary ( ) ;
# endif
FCEU_UpdateInput ( ) ;
lagFlag = 1 ;
2009-11-03 08:16:57 +00:00
# ifdef _S9XLUA_H
CallRegisteredLuaFunctions ( LUACALL_BEFOREEMULATION ) ;
# endif
2012-12-14 17:43:51 +00:00
if ( geniestage ! = 1 ) FCEU_ApplyPeriodicCheats ( ) ;
2009-07-17 17:27:04 +00:00
r = FCEUPPU_Loop ( skip ) ;
2012-12-14 17:43:51 +00:00
if ( skip ! = 2 ) ssize = FlushEmulateSound ( ) ; //If skip = 2 we are skipping sound processing
2009-11-03 08:16:57 +00:00
# ifdef _S9XLUA_H
CallRegisteredLuaFunctions ( LUACALL_AFTEREMULATION ) ;
# endif
2009-07-17 17:27:04 +00:00
# ifdef WIN32
//These Windows only dialogs need to be updated only once per frame so they are included here
2010-08-29 21:15:42 +00: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 17:27:04 +00:00
UpdateTextHooker ( ) ;
2009-11-03 08:16:57 +00:00
Update_RAM_Search ( ) ; // Update_RAM_Watch() is also called.
2009-07-17 17:27:04 +00:00
RamChange ( ) ;
//FCEUI_AviVideoUpdate(XBuf);
2013-01-01 23:27:33 +00:00
2010-08-29 21:15:42 +00:00
extern int KillFCEUXonFrame ;
if ( KillFCEUXonFrame & & ( FCEUMOV_GetFrame ( ) > = KillFCEUXonFrame ) )
DoFCEUExit ( ) ;
2018-08-13 09:04:20 -06:00
# else
extern int KillFCEUXonFrame ;
if ( KillFCEUXonFrame & & ( FCEUMOV_GetFrame ( ) > = KillFCEUXonFrame ) )
exit ( 0 ) ;
2009-07-17 17:27:04 +00:00
# endif
timestampbase + = timestamp ;
timestamp = 0 ;
2018-08-13 09:04:20 -06:00
soundtimestamp = 0 ;
2009-07-17 17:27:04 +00:00
2012-12-14 17:43:51 +00:00
* pXBuf = skip ? 0 : XBuf ;
if ( skip = = 2 ) { //If skip = 2, then bypass sound
* SoundBuf = 0 ;
* SoundBufSize = 0 ;
} else {
* SoundBuf = WaveFinal ;
* SoundBufSize = ssize ;
2009-07-17 17:27:04 +00:00
}
2009-11-10 22:13:41 +00:00
2012-12-14 17:43:51 +00:00
if ( ( EmulationPaused & EMULATIONPAUSED_FA ) & & ( ! frameAdvanceLagSkip | | ! lagFlag ) )
//Lots of conditions here. EmulationPaused & EMULATIONPAUSED_FA must be true. In addition frameAdvanceLagSkip or lagFlag must be false
// When Frame Advance is held, emulator is automatically paused after emulating one frame (or several lag frames)
2009-07-17 17:27:04 +00:00
{
2012-12-14 17:43:51 +00:00
EmulationPaused = EMULATIONPAUSED_PAUSED ; // restore EMULATIONPAUSED_PAUSED flag and clear EMULATIONPAUSED_FA flag
2009-07-17 17:27:04 +00:00
JustFrameAdvanced = true ;
# ifdef WIN32
2012-12-14 17:43:51 +00:00
if ( soundoptions & SO_MUTEFA ) //mute the frame advance if the user requested it
* SoundBufSize = 0 ; //keep sound muted
2009-07-17 17:27:04 +00:00
# endif
}
2009-11-10 22:13:41 +00:00
2012-12-14 17:43:51 +00:00
if ( lagFlag ) {
2009-07-17 17:27:04 +00:00
lagCounter + + ;
justLagged = true ;
2012-12-14 17:43:51 +00:00
} else justLagged = false ;
2009-07-17 17:27:04 +00:00
if ( movieSubtitles )
ProcessSubtitles ( ) ;
}
2012-12-14 17:43:51 +00:00
void FCEUI_CloseGame ( void ) {
if ( ! FCEU_IsValidUI ( FCEUI_CLOSEGAME ) )
2009-07-17 17:27:04 +00:00
return ;
2009-10-07 04:40:55 +00:00
2009-12-14 06:56:29 +00:00
FCEU_CloseGame ( ) ;
2009-07-17 17:27:04 +00:00
}
2012-12-14 17:43:51 +00:00
void ResetNES ( void ) {
2009-07-17 17:27:04 +00:00
FCEUMOV_AddCommand ( FCEUNPCMD_RESET ) ;
2012-12-14 17:43:51 +00:00
if ( ! GameInfo ) return ;
2009-07-17 17:27:04 +00:00
GameInterface ( GI_RESETM2 ) ;
FCEUSND_Reset ( ) ;
FCEUPPU_Reset ( ) ;
X6502_Reset ( ) ;
// clear back baffer
extern uint8 * XBackBuf ;
2012-12-14 17:43:51 +00:00
memset ( XBackBuf , 0 , 256 * 256 ) ;
2012-06-26 23:14:39 +00:00
2016-09-17 20:43:24 -07:00
//FCEU_DispMessage("Reset", 0);
2009-07-17 17:27:04 +00:00
}
2018-08-13 09:04:20 -06:00
int RAMInitSeed = 0 ;
int RAMInitOption = 0 ;
u64 splitmix64 ( u32 input ) {
u64 z = ( input + 0x9e3779b97f4a7c15 ) ;
z = ( z ^ ( z > > 30 ) ) * 0xbf58476d1ce4e5b9 ;
z = ( z ^ ( z > > 27 ) ) * 0x94d049bb133111eb ;
return z ^ ( z > > 31 ) ;
}
static inline u64 xoroshiro128plus_rotl ( const u64 x , int k ) {
return ( x < < k ) | ( x > > ( 64 - k ) ) ;
}
u64 xoroshiro128plus_s [ 2 ] ;
void xoroshiro128plus_seed ( u32 input )
{
//http://xoroshiro.di.unimi.it/splitmix64.c
u64 x = input ;
u64 z = ( x + = 0x9e3779b97f4a7c15 ) ;
z = ( z ^ ( z > > 30 ) ) * 0xbf58476d1ce4e5b9 ;
z = ( z ^ ( z > > 27 ) ) * 0x94d049bb133111eb ;
xoroshiro128plus_s [ 0 ] = z ^ ( z > > 31 ) ;
z = ( x + = 0x9e3779b97f4a7c15 ) ;
z = ( z ^ ( z > > 30 ) ) * 0xbf58476d1ce4e5b9 ;
z = ( z ^ ( z > > 27 ) ) * 0x94d049bb133111eb ;
xoroshiro128plus_s [ 1 ] = z ^ ( z > > 31 ) ;
}
//http://vigna.di.unimi.it/xorshift/xoroshiro128plus.c
u64 xoroshiro128plus_next ( ) {
const u64 s0 = xoroshiro128plus_s [ 0 ] ;
u64 s1 = xoroshiro128plus_s [ 1 ] ;
const u64 result = s0 + s1 ;
s1 ^ = s0 ;
xoroshiro128plus_s [ 0 ] = xoroshiro128plus_rotl ( s0 , 55 ) ^ s1 ^ ( s1 < < 14 ) ; // a, b
xoroshiro128plus_s [ 1 ] = xoroshiro128plus_rotl ( s1 , 36 ) ; // c
return result ;
}
void FCEU_MemoryRand ( uint8 * ptr , uint32 size , bool default_zero ) {
2012-12-14 17:43:51 +00:00
int x = 0 ;
2018-08-13 09:04:20 -06:00
2012-12-14 17:43:51 +00:00
while ( size ) {
2018-08-13 09:04:20 -06:00
uint8 v = 0 ;
switch ( RAMInitOption )
{
default :
case 0 :
if ( ! default_zero ) v = ( x & 4 ) ? 0xFF : 0x00 ;
else v = 0x00 ;
break ;
case 1 : v = 0xFF ; break ;
case 2 : v = 0x00 ; break ;
case 3 : v = ( u8 ) ( xoroshiro128plus_next ( ) ) ; break ;
// the default is this 8 byte pattern: 00 00 00 00 FF FF FF FF
// it has been used in FCEUX since time immemorial
// Some games to examine uninitialied RAM problems with:
// * Cybernoid - music option starts turned off with default pattern
// * Huang Di - debug mode is enabled with default pattern
// * Minna no Taabou no Nakayoshi Daisakusen - fails to boot with some patterns
// * F-15 City War - high score table
// * 1942 - high score table
// * Cheetahmen II - may start in different levels with different RAM startup
}
* ptr = v ;
2009-07-17 17:27:04 +00:00
x + + ;
size - - ;
ptr + + ;
}
}
2012-12-14 17:43:51 +00:00
void hand ( X6502 * X , int type , uint32 A ) {
2009-07-17 17:27:04 +00:00
}
2012-12-14 17:43:51 +00:00
void PowerNES ( void ) {
FCEUMOV_AddCommand ( FCEUNPCMD_POWER ) ;
if ( ! GameInfo ) return ;
2009-07-17 17:27:04 +00:00
2018-08-13 09:04:20 -06:00
//reseed random, unless we're in a movie
extern int disableBatteryLoading ;
if ( FCEUMOV_Mode ( MOVIEMODE_INACTIVE ) & & ! disableBatteryLoading )
{
RAMInitSeed = rand ( ) ^ ( u32 ) xoroshiro128plus_next ( ) ;
}
//always reseed the PRNG with the current seed, for deterministic results (for that seed)
xoroshiro128plus_seed ( RAMInitSeed ) ;
2009-07-17 17:27:04 +00:00
FCEU_CheatResetRAM ( ) ;
2012-12-14 17:43:51 +00:00
FCEU_CheatAddRAM ( 2 , 0 , RAM ) ;
2009-07-17 17:27:04 +00:00
2012-12-14 17:43:51 +00:00
FCEU_GeniePower ( ) ;
2009-07-17 17:27:04 +00:00
2012-12-14 17:43:51 +00:00
FCEU_MemoryRand ( RAM , 0x800 ) ;
2009-07-17 17:27:04 +00:00
2012-12-14 17:43:51 +00:00
SetReadHandler ( 0x0000 , 0xFFFF , ANull ) ;
SetWriteHandler ( 0x0000 , 0xFFFF , BNull ) ;
2009-07-17 17:27:04 +00:00
2012-12-14 17:43:51 +00:00
SetReadHandler ( 0 , 0x7FF , ARAML ) ;
SetWriteHandler ( 0 , 0x7FF , BRAML ) ;
2009-07-17 17:27:04 +00:00
2016-09-17 20:43:24 -07:00
SetReadHandler ( 0x800 , 0x1FFF , ARAMH ) ; // Part of a little
SetWriteHandler ( 0x800 , 0x1FFF , BRAMH ) ; //hack for a small speed boost.
2009-07-17 17:27:04 +00:00
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 ) ;
2012-12-14 17:43:51 +00:00
if ( GameInfo - > type = = GIT_VSUNI )
2009-07-17 17:27:04 +00:00
FCEU_VSUniPower ( ) ;
//if we are in a movie, then reset the saveram
extern int disableBatteryLoading ;
2012-12-14 17:43:51 +00:00
if ( disableBatteryLoading )
2009-07-17 17:27:04 +00:00
GameInterface ( GI_RESETSAVE ) ;
2009-11-10 22:13:41 +00:00
2012-12-14 17:18:20 +00:00
timestampbase = 0 ;
2009-07-17 17:27:04 +00:00
X6502_Power ( ) ;
2012-12-14 17:18:20 +00:00
# ifdef WIN32
ResetDebugStatisticsCounters ( ) ;
# endif
2009-07-17 17:27:04 +00:00
FCEU_PowerCheats ( ) ;
2012-12-14 17:18:20 +00:00
LagCounterReset ( ) ;
2016-09-17 20:43:24 -07:00
// clear back buffer
2009-07-17 17:27:04 +00:00
extern uint8 * XBackBuf ;
2012-12-14 17:43:51 +00:00
memset ( XBackBuf , 0 , 256 * 256 ) ;
2012-01-09 01:59:06 +00:00
# ifdef WIN32
Update_RAM_Search ( ) ; // Update_RAM_Watch() is also called.
# endif
2012-12-14 17:18:20 +00:00
2018-08-13 09:04:20 -06:00
FCEU_DispMessage ( " Power on " , 0 ) ;
2009-07-17 17:27:04 +00:00
}
2012-12-14 17:43:51 +00:00
void FCEU_ResetVidSys ( void ) {
2009-07-17 17:27:04 +00:00
int w ;
2012-12-14 17:43:51 +00:00
if ( GameInfo - > vidsys = = GIV_NTSC )
w = 0 ;
2016-09-17 20:43:24 -07:00
else if ( GameInfo - > vidsys = = GIV_PAL ) {
2012-12-14 17:43:51 +00:00
w = 1 ;
2016-09-17 20:43:24 -07:00
dendy = 0 ;
} else
2012-12-14 17:43:51 +00:00
w = FSettings . PAL ;
2009-07-17 17:27:04 +00:00
2012-12-14 17:43:51 +00:00
PAL = w ? 1 : 0 ;
2016-09-17 20:43:24 -07:00
2018-08-13 09:04:20 -06:00
if ( PAL )
dendy = 0 ;
if ( newppu )
overclock_enabled = 0 ;
normalscanlines = ( dendy ? 290 : 240 ) + newppu ; // use flag as number!
totalscanlines = normalscanlines + ( overclock_enabled ? postrenderscanlines : 0 ) ;
2016-09-17 20:43:24 -07:00
FCEUPPU_SetVideoSystem ( w | | dendy ) ;
2009-07-17 17:27:04 +00:00
SetSoundVariables ( ) ;
}
FCEUS FSettings ;
2012-12-14 17:43:51 +00:00
void FCEU_printf ( char * format , . . . ) {
2012-01-24 03:22:17 +00:00
# ifndef GEKKO
2009-07-17 17:27:04 +00:00
char temp [ 2048 ] ;
va_list ap ;
2012-12-14 17:43:51 +00:00
va_start ( ap , format ) ;
vsnprintf ( temp , sizeof ( temp ) , format , ap ) ;
2009-07-17 17:27:04 +00:00
FCEUD_Message ( temp ) ;
2018-08-13 09:04:20 -06:00
#if 0
FILE * ofile ;
ofile = fopen ( " stdout.txt " , " ab " ) ;
fwrite ( temp , 1 , strlen ( temp ) , ofile ) ;
fclose ( ofile ) ;
# endif
2009-07-17 17:27:04 +00:00
va_end ( ap ) ;
2012-01-24 03:22:17 +00:00
# endif
2009-07-17 17:27:04 +00:00
}
2012-12-14 17:43:51 +00:00
void FCEU_PrintError ( char * format , . . . ) {
2012-01-24 03:22:17 +00:00
# ifndef GEKKO
2009-07-17 17:27:04 +00:00
char temp [ 2048 ] ;
va_list ap ;
2012-12-14 17:43:51 +00:00
va_start ( ap , format ) ;
vsnprintf ( temp , sizeof ( temp ) , format , ap ) ;
2009-07-17 17:27:04 +00:00
FCEUD_PrintError ( temp ) ;
va_end ( ap ) ;
2012-01-24 03:22:17 +00:00
# endif
2009-07-17 17:27:04 +00:00
}
2012-12-14 17:43:51 +00:00
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 ;
2016-09-17 20:43:24 -07:00
if ( PAL | | dendy ) {
2012-12-14 17:43:51 +00:00
FSettings . FirstSLine = FSettings . UsrFirstSLine [ 1 ] ;
FSettings . LastSLine = FSettings . UsrLastSLine [ 1 ] ;
} else {
FSettings . FirstSLine = FSettings . UsrFirstSLine [ 0 ] ;
FSettings . LastSLine = FSettings . UsrLastSLine [ 0 ] ;
2009-07-17 17:27:04 +00:00
}
}
2012-12-14 17:43:51 +00:00
void FCEUI_SetVidSystem ( int a ) {
FSettings . PAL = a ? 1 : 0 ;
if ( GameInfo ) {
2009-07-17 17:27:04 +00:00
FCEU_ResetVidSys ( ) ;
FCEU_ResetPalette ( ) ;
FCEUD_VideoChanged ( ) ;
}
}
2012-12-14 17:43:51 +00:00
int FCEUI_GetCurrentVidSystem ( int * slstart , int * slend ) {
if ( slstart )
* slstart = FSettings . FirstSLine ;
if ( slend )
* slend = FSettings . LastSLine ;
2009-07-17 17:27:04 +00:00
return ( PAL ) ;
}
2018-08-13 09:04:20 -06:00
# ifndef GEKKO
void FCEUI_SetRegion ( int region , int notify ) {
2016-09-17 20:43:24 -07:00
switch ( region ) {
case 0 : // NTSC
2018-08-13 09:04:20 -06:00
normalscanlines = 240 ;
2016-09-17 20:43:24 -07:00
pal_emulation = 0 ;
dendy = 0 ;
2018-08-13 09:04:20 -06:00
// until it's fixed on sdl. see issue #740
# ifdef WIN32
if ( notify )
{
FCEU_DispMessage ( " NTSC mode set " , 0 ) ;
FCEUI_printf ( " NTSC mode set " ) ;
}
# endif
2016-09-17 20:43:24 -07:00
break ;
case 1 : // PAL
2018-08-13 09:04:20 -06:00
normalscanlines = 240 ;
2016-09-17 20:43:24 -07:00
pal_emulation = 1 ;
dendy = 0 ;
2018-08-13 09:04:20 -06:00
# ifdef WIN32
if ( notify )
{
FCEU_DispMessage ( " PAL mode set " , 0 ) ;
FCEUI_printf ( " PAL mode set " ) ;
}
# endif
2016-09-17 20:43:24 -07:00
break ;
case 2 : // Dendy
2018-08-13 09:04:20 -06:00
normalscanlines = 290 ;
2016-09-17 20:43:24 -07:00
pal_emulation = 0 ;
dendy = 1 ;
2018-08-13 09:04:20 -06:00
# ifdef WIN32
if ( notify )
{
FCEU_DispMessage ( " Dendy mode set " , 0 ) ;
FCEUI_printf ( " Dendy mode set " ) ;
}
# endif
2016-09-17 20:43:24 -07:00
break ;
}
2018-08-13 09:04:20 -06:00
normalscanlines + = newppu ;
totalscanlines = normalscanlines + ( overclock_enabled ? postrenderscanlines : 0 ) ;
2016-09-17 20:43:24 -07:00
FCEUI_SetVidSystem ( pal_emulation ) ;
RefreshThrottleFPS ( ) ;
# ifdef WIN32
UpdateCheckedMenuItems ( ) ;
PushCurrentVideoSettings ( ) ;
# endif
2018-08-13 09:04:20 -06:00
}
# endif
2009-07-17 17:27:04 +00:00
//Enable or disable Game Genie option.
2012-12-14 17:43:51 +00:00
void FCEUI_SetGameGenie ( bool a ) {
2009-07-17 17:27:04 +00:00
FSettings . GameGenie = a ;
}
//this variable isn't used at all, snap is always name-based
//void FCEUI_SetSnapName(bool a)
//{
// FSettings.SnapName = a;
//}
2012-12-14 17:43:51 +00:00
int32 FCEUI_GetDesiredFPS ( void ) {
2016-09-17 20:43:24 -07:00
if ( PAL | | dendy )
2012-12-14 17:43:51 +00:00
return ( 838977920 ) ; // ~50.007
2009-07-17 17:27:04 +00:00
else
2012-12-14 17:43:51 +00:00
return ( 1008307711 ) ; // ~60.1
2009-07-17 17:27:04 +00:00
}
int FCEUI_EmulationPaused ( void )
{
2012-12-14 17:43:51 +00:00
return ( EmulationPaused & EMULATIONPAUSED_PAUSED ) ;
2009-07-17 17:27:04 +00:00
}
int FCEUI_EmulationFrameStepped ( )
{
2012-12-14 17:43:51 +00:00
return ( EmulationPaused & EMULATIONPAUSED_FA ) ;
2009-07-17 17:27:04 +00:00
}
void FCEUI_ClearEmulationFrameStepped ( )
{
2012-12-14 17:43:51 +00:00
EmulationPaused & = ~ EMULATIONPAUSED_FA ;
2009-07-17 17:27:04 +00:00
}
//mbg merge 7/18/06 added
//ideally maybe we shouldnt be using this, but i need it for quick merging
2012-12-14 17:43:51 +00:00
void FCEUI_SetEmulationPaused ( int val ) {
2009-07-17 17:27:04 +00:00
EmulationPaused = val ;
}
void FCEUI_ToggleEmulationPause ( void )
{
2012-12-14 17:43:51 +00:00
EmulationPaused = ( EmulationPaused & EMULATIONPAUSED_PAUSED ) ^ EMULATIONPAUSED_PAUSED ;
2010-08-29 21:15:42 +00:00
DebuggerWasUpdated = false ;
2009-07-17 17:27:04 +00:00
}
2012-12-14 17:43:51 +00:00
void FCEUI_FrameAdvanceEnd ( void ) {
2009-07-17 17:27:04 +00:00
frameAdvanceRequested = false ;
}
2012-12-14 17:43:51 +00:00
void FCEUI_FrameAdvance ( void ) {
2009-07-17 17:27:04 +00:00
frameAdvanceRequested = true ;
2012-12-14 17:43:51 +00:00
frameAdvance_Delay_count = 0 ;
2009-07-17 17:27:04 +00:00
}
static int AutosaveCounter = 0 ;
2012-12-14 17:43:51 +00:00
void UpdateAutosave ( void ) {
if ( ! EnableAutosave | | turbo )
2009-07-17 17:27:04 +00:00
return ;
2009-11-10 22:13:41 +00:00
2009-07-17 17:27:04 +00:00
char * f ;
2012-12-14 17:43:51 +00:00
if ( + + AutosaveCounter > = AutosaveFrequency ) {
2009-11-27 08:53:39 +00:00
AutosaveCounter = 0 ;
AutosaveIndex = ( AutosaveIndex + 1 ) % AutosaveQty ;
2012-12-14 17:43:51 +00:00
f = strdup ( FCEU_MakeFName ( FCEUMKF_AUTOSTATE , AutosaveIndex , 0 ) . c_str ( ) ) ;
2016-09-17 20:43:24 -07:00
FCEUSS_Save ( f , false ) ;
2012-12-14 17:43:51 +00:00
AutoSS = true ; //Flag that an auto-savestate was made
2009-07-17 17:27:04 +00:00
free ( f ) ;
2016-09-17 20:43:24 -07:00
f = NULL ;
2009-07-17 17:27:04 +00:00
AutosaveStatus [ AutosaveIndex ] = 1 ;
}
}
2016-09-17 20:43:24 -07:00
void FCEUI_RewindToLastAutosave ( void ) {
2012-12-14 17:43:51 +00:00
if ( ! EnableAutosave | | ! AutoSS )
2009-07-17 17:27:04 +00:00
return ;
2012-12-14 17:43:51 +00:00
if ( AutosaveStatus [ AutosaveIndex ] = = 1 ) {
2009-07-17 17:27:04 +00:00
char * f ;
2012-12-14 17:43:51 +00:00
f = strdup ( FCEU_MakeFName ( FCEUMKF_AUTOSTATE , AutosaveIndex , 0 ) . c_str ( ) ) ;
2009-07-17 17:27:04 +00:00
FCEUSS_Load ( f ) ;
free ( f ) ;
2016-09-17 20:43:24 -07:00
f = NULL ;
2009-07-17 17:27:04 +00:00
//Set pointer to previous available slot
2012-12-14 17:43:51 +00:00
if ( AutosaveStatus [ ( AutosaveIndex + AutosaveQty - 1 ) % AutosaveQty ] = = 1 ) {
AutosaveIndex = ( AutosaveIndex + AutosaveQty - 1 ) % AutosaveQty ;
2009-07-17 17:27:04 +00:00
}
//Reset time to next Auto-save
AutosaveCounter = 0 ;
}
}
2012-12-14 17:43:51 +00:00
int FCEU_TextScanlineOffset ( int y ) {
return FSettings . FirstSLine * 256 ;
2009-07-17 17:27:04 +00:00
}
2012-12-14 17:43:51 +00:00
int FCEU_TextScanlineOffsetFromBottom ( int y ) {
return ( FSettings . LastSLine - y ) * 256 ;
2009-07-17 17:27:04 +00:00
}
2012-12-14 17:43:51 +00:00
bool FCEU_IsValidUI ( EFCEUI ui ) {
2018-08-13 09:04:20 -06:00
# ifndef GEKKO
2012-12-14 17:43:51 +00:00
switch ( ui ) {
2009-07-17 17:27:04 +00:00
case FCEUI_OPENGAME :
case FCEUI_CLOSEGAME :
2012-12-14 17:43:51 +00:00
if ( FCEUMOV_Mode ( MOVIEMODE_TASEDITOR ) ) return false ;
2009-07-17 17:27:04 +00:00
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 :
2012-12-14 17:43:51 +00:00
if ( ! GameInfo ) return false ;
if ( FCEUMOV_Mode ( MOVIEMODE_TASEDITOR ) ) return false ;
2009-07-17 17:27:04 +00:00
break ;
case FCEUI_STOPMOVIE :
2012-12-14 17:43:51 +00:00
return ( FCEUMOV_Mode ( MOVIEMODE_PLAY | MOVIEMODE_RECORD | MOVIEMODE_FINISHED ) ) ;
2009-07-17 17:27:04 +00:00
2012-06-26 23:14:39 +00:00
case FCEUI_PLAYFROMBEGINNING :
2012-12-14 17:43:51 +00:00
return ( FCEUMOV_Mode ( MOVIEMODE_PLAY | MOVIEMODE_RECORD | MOVIEMODE_TASEDITOR | MOVIEMODE_FINISHED ) ) ;
2012-06-26 23:14:39 +00:00
2009-07-17 17:27:04 +00:00
case FCEUI_STOPAVI :
return FCEUI_AviIsRecording ( ) ;
2012-01-14 22:35:51 +00:00
case FCEUI_TASEDITOR :
2012-12-14 17:43:51 +00:00
if ( ! GameInfo ) return false ;
2009-07-17 17:27:04 +00:00
break ;
case FCEUI_RESET :
case FCEUI_POWER :
2012-06-26 23:14:39 +00:00
case FCEUI_EJECT_DISK :
case FCEUI_SWITCH_DISK :
2016-09-17 20:43:24 -07:00
case FCEUI_INSERT_COIN :
2012-12-14 17:43:51 +00:00
if ( ! GameInfo ) return false ;
if ( FCEUMOV_Mode ( MOVIEMODE_RECORD ) ) return true ;
2012-06-26 23:14:39 +00:00
# ifdef WIN32
2016-09-17 20:43:24 -07:00
if ( FCEUMOV_Mode ( MOVIEMODE_TASEDITOR ) & & isTaseditorRecording ( ) ) return true ;
2012-06-26 23:14:39 +00:00
# endif
2012-12-14 17:43:51 +00:00
if ( ! FCEUMOV_Mode ( MOVIEMODE_INACTIVE ) ) return false ;
2009-07-17 17:27:04 +00:00
break ;
}
2018-08-13 09:04:20 -06:00
# endif
2009-07-17 17:27:04 +00:00
return true ;
}
//---------------------
//experimental new mapper and ppu system follows
class FCEUXCart {
public :
2012-12-14 17:43:51 +00:00
int mirroring ;
int chrPages , prgPages ;
uint32 chrSize , prgSize ;
char * CHR , * PRG ;
FCEUXCart ( )
: CHR ( 0 )
, PRG ( 0 ) {
}
2009-07-17 17:27:04 +00:00
2012-12-14 17:43:51 +00:00
~ FCEUXCart ( ) {
if ( CHR ) delete [ ] CHR ;
if ( PRG ) delete [ ] PRG ;
}
virtual void Power ( ) {
}
2009-07-17 17:27:04 +00:00
protected :
2012-12-14 17:43:51 +00:00
//void SetReadHandler(int32 start, int32 end, readfunc func) {
2009-07-17 17:27:04 +00:00
} ;
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 :
2012-12-14 17:43:51 +00:00
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 ;
}
2009-07-17 17:27:04 +00:00
} ;
void FCEUXGameInterface ( GI command ) {
2012-12-14 17:43:51 +00:00
switch ( command ) {
case GI_POWER :
cart - > Power ( ) ;
2009-07-17 17:27:04 +00:00
}
}
2012-12-14 17:43:51 +00:00
bool FCEUXLoad ( const char * name , FCEUFILE * fp ) {
2009-07-17 17:27:04 +00:00
//read ines header
iNES_HEADER head ;
2012-12-14 17:43:51 +00:00
if ( FCEU_fread ( & head , 1 , 16 , fp ) ! = 16 )
2009-07-17 17:27:04 +00:00
return false ;
//validate header
2012-12-14 17:43:51 +00:00
if ( memcmp ( & head , " NES \x1a " , 4 ) )
2009-07-17 17:27:04 +00:00
return 0 ;
2012-12-14 17:43:51 +00:00
int mapper = ( head . ROM_type > > 4 ) ;
mapper | = ( head . ROM_type2 & 0xF0 ) ;
2009-07-17 17:27:04 +00:00
//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 ;
2012-12-14 17:43:51 +00:00
if ( cart - > prgPages = = 0 ) {
2009-07-17 17:27:04 +00:00
printf ( " FCEUX: received zero prgpages \n " ) ;
cart - > prgPages = 256 ;
}
cart - > chrPages = head . VROM_size ;
2012-12-14 17:43:51 +00:00
cart - > mirroring = ( head . ROM_type & 1 ) ;
if ( head . ROM_type & 8 ) cart - > mirroring = 2 ;
2009-07-17 17:27:04 +00:00
//skip trainer
2012-12-14 17:43:51 +00:00
bool hasTrainer = ( head . ROM_type & 4 ) ! = 0 ;
if ( hasTrainer ) {
FCEU_fseek ( fp , 512 , SEEK_CUR ) ;
2009-07-17 17:27:04 +00:00
}
//load data
2012-12-14 17:43:51 +00:00
cart - > prgSize = cart - > prgPages * 16 * 1024 ;
cart - > chrSize = cart - > chrPages * 8 * 1024 ;
2009-07-17 17:27:04 +00:00
cart - > PRG = new char [ cart - > prgSize ] ;
cart - > CHR = new char [ cart - > chrSize ] ;
2012-12-14 17:43:51 +00:00
FCEU_fread ( cart - > PRG , 1 , cart - > prgSize , fp ) ;
FCEU_fread ( cart - > CHR , 1 , cart - > chrSize , fp ) ;
2009-07-17 17:27:04 +00:00
//setup the emulator
2012-12-14 17:43:51 +00:00
GameInterface = FCEUXGameInterface ;
2009-07-17 17:27:04 +00:00
ResetCartMapping ( ) ;
2012-12-14 17:43:51 +00:00
SetupCartPRGMapping ( 0 , ( uint8 * ) cart - > PRG , cart - > prgSize , 0 ) ;
SetupCartCHRMapping ( 0 , ( uint8 * ) cart - > CHR , cart - > chrSize , 0 ) ;
2009-11-10 22:13:41 +00:00
2009-07-17 17:27:04 +00:00
return true ;
}
uint8 FCEU_ReadRomByte ( uint32 i ) {
extern iNES_HEADER head ;
2018-08-13 09:04:20 -06:00
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 ] ] ;
2009-07-17 17:27:04 +00:00
return 0 ;
2009-11-03 08:16:57 +00:00
}
2018-08-13 09:04:20 -06:00
void FCEU_WriteRomByte ( uint32 i , uint8 value ) {
if ( i < 16 )
# ifdef WIN32
MessageBox ( hMemView , " Sorry " , " You can't edit the ROM header. " , MB_OK ) ;
# else
printf ( " Sorry, you can't edit the ROM header. \n " ) ;
# endif
if ( i < 16 + PRGsize [ 0 ] )
PRGptr [ 0 ] [ i - 16 ] = value ;
else if ( i < 16 + PRGsize [ 0 ] + CHRsize [ 0 ] )
CHRptr [ 0 ] [ i - 16 - PRGsize [ 0 ] ] = value ;
}