mirror of
https://github.com/mupen64plus/mupen64plus-oldsvn.git
synced 2025-04-02 10:52:35 -04:00
345 lines
11 KiB
C
345 lines
11 KiB
C
/**
|
|
* Mupen64 - main.c
|
|
* Copyright (C) 2002 Hacktarux
|
|
*
|
|
* Mupen64 homepage: http://mupen64.emulation64.com
|
|
* email address: hacktarux@yahoo.fr
|
|
*
|
|
* If you want to contribute to the project please contact
|
|
* me first (maybe someone is already making what you are
|
|
* planning to do).
|
|
*
|
|
*
|
|
* This program is free software; you can redistribute it and/
|
|
* or modify it under the terms of the GNU General Public Li-
|
|
* cence as published by the Free Software Foundation; either
|
|
* version 2 of the Licence, or any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be use-
|
|
* ful, but WITHOUT ANY WARRANTY; without even the implied war-
|
|
* ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
* See the GNU General Public Licence for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public
|
|
* Licence along with this program; if not, write to the Free
|
|
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
|
|
* USA.
|
|
*
|
|
**/
|
|
|
|
/* This is MUPEN64's main entry point. It contains code that is common
|
|
* to both the gui and non-gui versions of mupen64. See
|
|
* gui subdirectories for the gui-specific code.
|
|
* if you want to implement an interface, you should look here
|
|
*/
|
|
|
|
/** function prototypes **/
|
|
static void *emulationThread( void *_arg );
|
|
static void sighandler( int signal, siginfo_t *info, void *context ); // signal handler
|
|
|
|
/** globals **/
|
|
pthread_t g_EmulationThread = 0; // core thread handle
|
|
|
|
|
|
/** emulation **/
|
|
/* startEmulation
|
|
* Begins emulation thread
|
|
*/
|
|
void startEmulation(void)
|
|
{
|
|
const char *gfx_plugin = NULL,
|
|
*audio_plugin = NULL,
|
|
*input_plugin = NULL,
|
|
*RSP_plugin = NULL;
|
|
|
|
// make sure rom is loaded before running
|
|
if(!rom)
|
|
{
|
|
alert_message(tr("There is no Rom loaded."));
|
|
return;
|
|
}
|
|
|
|
// make sure all plugins are specified before running
|
|
if(g_GfxPlugin)
|
|
gfx_plugin = plugin_name_by_filename(g_GfxPlugin);
|
|
else
|
|
gfx_plugin = plugin_name_by_filename(config_get_string("Gfx Plugin", ""));
|
|
|
|
if(!gfx_plugin)
|
|
{
|
|
alert_message(tr("No graphics plugin specified."));
|
|
return;
|
|
}
|
|
|
|
if(g_AudioPlugin)
|
|
audio_plugin = plugin_name_by_filename(g_AudioPlugin);
|
|
else
|
|
audio_plugin = plugin_name_by_filename(config_get_string("Audio Plugin", ""));
|
|
|
|
if(!audio_plugin)
|
|
{
|
|
alert_message(tr("No audio plugin specified."));
|
|
return;
|
|
}
|
|
|
|
if(g_InputPlugin)
|
|
input_plugin = plugin_name_by_filename(g_InputPlugin);
|
|
else
|
|
input_plugin = plugin_name_by_filename(config_get_string("Input Plugin", ""));
|
|
|
|
if(!input_plugin)
|
|
{
|
|
alert_message(tr("No input plugin specified."));
|
|
return;
|
|
}
|
|
|
|
if(g_RspPlugin)
|
|
RSP_plugin = plugin_name_by_filename(g_RspPlugin);
|
|
else
|
|
RSP_plugin = plugin_name_by_filename(config_get_string("RSP Plugin", ""));
|
|
|
|
if(!RSP_plugin)
|
|
{
|
|
alert_message(tr("No RSP plugin specified."));
|
|
return;
|
|
}
|
|
|
|
// in nogui mode, just start the emulator in the main thread
|
|
if(!g_GuiEnabled)
|
|
{
|
|
emulationThread(NULL);
|
|
}
|
|
else if(!g_EmulationThread)
|
|
{
|
|
// spawn emulation thread
|
|
if(pthread_create(&g_EmulationThread, NULL, emulationThread, NULL) != 0)
|
|
{
|
|
g_EmulationThread = 0;
|
|
alert_message(tr("Couldn't spawn core thread!"));
|
|
return;
|
|
}
|
|
pthread_detach(g_EmulationThread);
|
|
info_message(tr("Emulation started (PID: %d)"), g_EmulationThread);
|
|
}
|
|
|
|
}
|
|
|
|
void stopEmulation(void)
|
|
{
|
|
if(g_EmulationThread || g_EmulatorRunning)
|
|
{
|
|
info_message(tr("Stopping emulation."));
|
|
rompause = 0;
|
|
stop_it();
|
|
|
|
// wait until emulation thread is done before continuing
|
|
if(g_EmulationThread)
|
|
pthread_join(g_EmulationThread, NULL);
|
|
|
|
g_EmulatorRunning = 0;
|
|
|
|
info_message(tr("Emulation stopped."));
|
|
}
|
|
}
|
|
|
|
|
|
/*********************************************************************************************************
|
|
* emulation thread - runs the core
|
|
*/
|
|
static void * emulationThread( void *_arg )
|
|
{
|
|
const char *gfx_plugin = NULL,
|
|
*audio_plugin = NULL,
|
|
*input_plugin = NULL,
|
|
*RSP_plugin = NULL;
|
|
struct sigaction sa;
|
|
|
|
// install signal handler
|
|
memset( &sa, 0, sizeof( struct sigaction ) );
|
|
sa.sa_sigaction = sighandler;
|
|
sa.sa_flags = SA_SIGINFO;
|
|
sigaction( SIGSEGV, &sa, NULL );
|
|
sigaction( SIGILL, &sa, NULL );
|
|
sigaction( SIGFPE, &sa, NULL );
|
|
sigaction( SIGCHLD, &sa, NULL );
|
|
|
|
g_EmulatorRunning = 1;
|
|
g_LimitFPS = config_get_bool("LimitFPS", TRUE);
|
|
|
|
// if emu mode wasn't specified at the commandline, set from config file
|
|
if(!g_EmuMode)
|
|
dynacore = config_get_number( "Core", CORE_DYNAREC );
|
|
|
|
no_audio_delay = config_get_bool("NoAudioDelay", FALSE);
|
|
no_compiled_jump = config_get_bool("NoCompiledJump", FALSE);
|
|
|
|
// init sdl
|
|
SDL_Init(SDL_INIT_VIDEO);
|
|
SDL_ShowCursor(0);
|
|
SDL_EnableKeyRepeat(0, 0);
|
|
|
|
SDL_SetEventFilter(sdl_event_filter);
|
|
SDL_EnableUNICODE(1);
|
|
|
|
/* Determine which plugins to use:
|
|
* -If valid plugin was specified at the commandline, use it
|
|
* -Else, get plugin from config. NOTE: gui code must change config if user switches plugin in the gui)
|
|
*/
|
|
if(g_GfxPlugin)
|
|
gfx_plugin = plugin_name_by_filename(g_GfxPlugin);
|
|
else
|
|
gfx_plugin = plugin_name_by_filename(config_get_string("Gfx Plugin", ""));
|
|
|
|
if(g_AudioPlugin)
|
|
audio_plugin = plugin_name_by_filename(g_AudioPlugin);
|
|
else
|
|
audio_plugin = plugin_name_by_filename(config_get_string("Audio Plugin", ""));
|
|
|
|
if(g_InputPlugin)
|
|
input_plugin = plugin_name_by_filename(g_InputPlugin);
|
|
else
|
|
input_plugin = plugin_name_by_filename(config_get_string("Input Plugin", ""));
|
|
|
|
if(g_RspPlugin)
|
|
RSP_plugin = plugin_name_by_filename(g_RspPlugin);
|
|
else
|
|
RSP_plugin = plugin_name_by_filename(config_get_string("RSP Plugin", ""));
|
|
|
|
// initialize memory, and do byte-swapping if it's not been done yet
|
|
if (g_MemHasBeenBSwapped == 0)
|
|
{
|
|
init_memory(1);
|
|
g_MemHasBeenBSwapped = 1;
|
|
}
|
|
else
|
|
{
|
|
init_memory(0);
|
|
}
|
|
|
|
// load the plugins and attach the ROM to them
|
|
plugin_load_plugins(gfx_plugin, audio_plugin, input_plugin, RSP_plugin);
|
|
romOpen_gfx();
|
|
romOpen_audio();
|
|
romOpen_input();
|
|
|
|
if (g_Fullscreen)
|
|
changeWindow();
|
|
|
|
#ifdef WITH_LIRC
|
|
lircStart();
|
|
#endif // WITH_LIRC
|
|
|
|
#ifdef DBG
|
|
if( g_DebuggerEnabled )
|
|
init_debugger();
|
|
#endif
|
|
// load cheats for the current rom
|
|
cheat_load_current_rom();
|
|
|
|
go(); /* core func */
|
|
|
|
#ifdef WITH_LIRC
|
|
lircStop();
|
|
#endif // WITH_LIRC
|
|
|
|
romClosed_RSP();
|
|
romClosed_input();
|
|
romClosed_audio();
|
|
romClosed_gfx();
|
|
closeDLL_RSP();
|
|
closeDLL_input();
|
|
closeDLL_audio();
|
|
closeDLL_gfx();
|
|
free_memory();
|
|
|
|
// clean up
|
|
g_EmulationThread = 0;
|
|
|
|
SDL_Quit();
|
|
|
|
if (g_Filename != 0)
|
|
{
|
|
// the following doesn't work - it wouldn't exit immediately but when the next event is
|
|
// recieved (i.e. mouse movement)
|
|
/* gdk_threads_enter();
|
|
gtk_main_quit();
|
|
gdk_threads_leave();*/
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*********************************************************************************************************
|
|
* signal handler
|
|
*/
|
|
static void sighandler(int signal, siginfo_t *info, void *context)
|
|
{
|
|
if( info->si_pid == g_EmulationThread )
|
|
{
|
|
switch( signal )
|
|
{
|
|
case SIGSEGV:
|
|
alert_message(tr("The core thread recieved a SIGSEGV signal.\n"
|
|
"This means it tried to access protected memory.\n"
|
|
"Maybe you have set a wrong ucode for one of the plugins!"));
|
|
printf( "SIGSEGV in core thread caught:\n" );
|
|
printf( "\terrno = %d (%s)\n", info->si_errno, strerror( info->si_errno ) );
|
|
printf( "\taddress = 0x%08lX\n", (unsigned long) info->si_addr );
|
|
#ifdef SEGV_MAPERR
|
|
switch( info->si_code )
|
|
{
|
|
case SEGV_MAPERR: printf( " address not mapped to object\n" ); break;
|
|
case SEGV_ACCERR: printf( " invalid permissions for mapped object\n" ); break;
|
|
}
|
|
#endif
|
|
break;
|
|
case SIGILL:
|
|
printf( "SIGILL in core thread caught:\n" );
|
|
printf( "\terrno = %d (%s)\n", info->si_errno, strerror( info->si_errno ) );
|
|
printf( "\taddress = 0x%08lX\n", (unsigned long) info->si_addr );
|
|
#ifdef ILL_ILLOPC
|
|
switch( info->si_code )
|
|
{
|
|
case ILL_ILLOPC: printf( "\tillegal opcode\n" ); break;
|
|
case ILL_ILLOPN: printf( "\tillegal operand\n" ); break;
|
|
case ILL_ILLADR: printf( "\tillegal addressing mode\n" ); break;
|
|
case ILL_ILLTRP: printf( "\tillegal trap\n" ); break;
|
|
case ILL_PRVOPC: printf( "\tprivileged opcode\n" ); break;
|
|
case ILL_PRVREG: printf( "\tprivileged register\n" ); break;
|
|
case ILL_COPROC: printf( "\tcoprocessor error\n" ); break;
|
|
case ILL_BADSTK: printf( "\tinternal stack error\n" ); break;
|
|
}
|
|
#endif
|
|
break;
|
|
case SIGFPE:
|
|
printf( "SIGFPE in core thread caught:\n" );
|
|
printf( "\terrno = %d (%s)\n", info->si_errno, strerror( info->si_errno ) );
|
|
printf( "\taddress = 0x%08lX\n", (unsigned long) info->si_addr );
|
|
switch( info->si_code )
|
|
{
|
|
case FPE_INTDIV: printf( "\tinteger divide by zero\n" ); break;
|
|
case FPE_INTOVF: printf( "\tinteger overflow\n" ); break;
|
|
case FPE_FLTDIV: printf( "\tfloating point divide by zero\n" ); break;
|
|
case FPE_FLTOVF: printf( "\tfloating point overflow\n" ); break;
|
|
case FPE_FLTUND: printf( "\tfloating point underflow\n" ); break;
|
|
case FPE_FLTRES: printf( "\tfloating point inexact result\n" ); break;
|
|
case FPE_FLTINV: printf( "\tfloating point invalid operation\n" ); break;
|
|
case FPE_FLTSUB: printf( "\tsubscript out of range\n" ); break;
|
|
}
|
|
break;
|
|
default:
|
|
printf( "Signal number %d in core thread caught:\n", signal );
|
|
printf( "\terrno = %d (%s)\n", info->si_errno, strerror( info->si_errno ) );
|
|
}
|
|
pthread_cancel(g_EmulationThread);
|
|
g_EmulationThread = 0;
|
|
g_EmulatorRunning = 0;
|
|
}
|
|
else
|
|
{
|
|
printf( "Signal number %d caught:\n", signal );
|
|
printf( "\terrno = %d (%s)\n", info->si_errno, strerror( info->si_errno ) );
|
|
exit( EXIT_FAILURE );
|
|
}
|
|
}
|
|
|