1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2
* Mupen64plus - main.c *
3
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
4
* Copyright (C) 2008 Richard42 Ebenblues Nmn Okaygo Tillin9 *
5
* Copyright (C) 2002 Hacktarux *
7
* This program is free software; you can redistribute it and/or modify *
8
* it under the terms of the GNU General Public License as published by *
9
* the Free Software Foundation; either version 2 of the License, or *
10
* (at your option) any later version. *
12
* This program is distributed in the hope that it will be useful, *
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15
* GNU General Public License for more details. *
17
* You should have received a copy of the GNU General Public License *
18
* along with this program; if not, write to the *
19
* Free Software Foundation, Inc., *
20
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
21
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
23
/* This is MUPEN64's main entry point. It contains code that is common
24
* to both the gui and non-gui versions of mupen64. See
25
* gui subdirectories for the gui-specific code.
26
* if you want to implement an interface, you should look here
30
#include <CoreFoundation/CoreFoundation.h>
31
#define _7ZIP_UINT32_DEFINED // avoid stupid conflicts between native types and 7zip types
35
# include <ucontext.h> // extra signal types (for portability)
36
# include <libgen.h> // basename, dirname
40
#include <sys/stat.h> /* mkdir() */
44
#include <unistd.h> // POSIX macros and standard types.
45
#include <signal.h> // signals
46
#include <getopt.h> // getopt_long
49
#include <png.h> // for writing screenshot PNG files
52
#include <SDL_thread.h>
60
#include "savestates.h"
62
#include "translate.h"
65
#include "../r4300/r4300.h"
66
#include "../r4300/recomph.h"
67
#include "../r4300/interupt.h"
69
#include "../memory/memory.h"
71
#include "../opengl/osd.h"
72
#include "../opengl/screenshot.h"
80
#include "../debugger/debugger.h"
88
// dynamic data path detection onmac
89
bool macSetBundlePath(char* buffer)
91
printf("checking whether we are using an app bundle... ");
92
// the following code will enable mupen to find its plugins when placed in an app bundle on mac OS X.
93
// returns true if path is set, returns false if path was not set
95
CFBundleRef main_bundle = CFBundleGetMainBundle(); assert(main_bundle);
96
CFURLRef main_bundle_URL = CFBundleCopyBundleURL(main_bundle); assert(main_bundle_URL);
97
CFStringRef cf_string_ref = CFURLCopyFileSystemPath( main_bundle_URL, kCFURLPOSIXPathStyle); assert(cf_string_ref);
98
CFStringGetCString(cf_string_ref, path, 1024, kCFStringEncodingASCII);
99
CFRelease(main_bundle_URL);
100
CFRelease(cf_string_ref);
102
if(strstr( path, ".app" ) != 0)
105
// executable is inside an app bundle, use app bundle-relative paths
106
sprintf(buffer, "%s/Contents/Resources/", path);
117
/** function prototypes **/
118
static void parseCommandLine(int argc, char **argv);
119
static int emulationThread( void *_arg );
120
extern int rom_cache_system( void *_arg );
124
static void sighandler( int signal );
126
static void sighandler( int signal, siginfo_t *info, void *context );
130
SDL_Thread * g_EmulationThread; // core thread handle
131
SDL_Thread * g_RomCacheThread; // rom cache thread handle
134
int g_Noask = 0; // don't ask to force load on bad dumps
135
int g_NoaskParam = 0; // was --noask passed at the commandline?
136
int g_MemHasBeenBSwapped = 0; // store byte-swapped flag so we don't swap twice when re-playing game
137
int g_EmulatorRunning = 0; // need separate boolean to tell if emulator is running, since --nogui doesn't use a thread
138
int g_OsdEnabled = 1; // On Screen Display enabled?
139
int g_Fullscreen = 0; // fullscreen enabled?
140
int g_TakeScreenshot = 0; // Tell OSD Rendering callback to take a screenshot just before drawing the OSD
142
char *g_GfxPlugin = NULL; // pointer to graphics plugin specified at commandline (if any)
143
char *g_AudioPlugin = NULL; // pointer to audio plugin specified at commandline (if any)
144
char *g_InputPlugin = NULL; // pointer to input plugin specified at commandline (if any)
145
char *g_RspPlugin = NULL; // pointer to rsp plugin specified at commandline (if any)
147
/** static (local) variables **/
149
static int l_GuiEnabled = 0; // GUI enabled?
151
static int l_GuiEnabled = 1; // GUI enabled?
154
static char l_ConfigDir[PATH_MAX] = {'\0'};
155
static char l_InstallDir[PATH_MAX] = {'\0'};
157
static int l_EmuMode = 0; // emumode specified at commandline?
158
static int l_CurrentFrame = 0; // frame counter
159
static int *l_TestShotList = NULL; // list of screenshots to take for regression test support
160
static int l_TestShotIdx = 0; // index of next screenshot frame in list
161
static char *l_Filename = NULL; // filename to load & run at startup (if given at command line)
162
static int l_RomNumber = 0; // rom number in archive (if given at command line)
163
static int l_SpeedFactor = 100; // percentage of nominal game speed at which emulator is running
164
static int l_FrameAdvance = 0; // variable to check if we pause on next frame
166
static osd_message_t *l_volMsg = NULL;
168
/*********************************************************************************************************
171
char *get_configpath()
176
char *get_installpath()
181
char *get_savespath()
183
static char path[PATH_MAX];
184
strncpy(path, get_configpath(), PATH_MAX-5);
185
strcat(path, "save/");
189
char *get_iconspath()
191
static char path[PATH_MAX];
192
strncpy(path, get_installpath(), PATH_MAX-6);
193
strcat(path, "icons/");
197
char *get_iconpath(const char *iconfile)
199
static char path[PATH_MAX];
200
strncpy(path, get_iconspath(), PATH_MAX-strlen(iconfile));
201
strcat(path, iconfile);
205
int gui_enabled(void)
210
void main_message(unsigned int console, unsigned int statusbar, unsigned int osd, unsigned int osd_corner, const char *format, ...)
214
va_start(ap, format);
215
vsnprintf(buffer, 2047, format, ap);
219
if (g_OsdEnabled && osd)
220
osd_new_message(osd_corner, buffer);
222
if (l_GuiEnabled && statusbar)
223
gui_message(GUI_MESSAGE_INFO, buffer);
226
printf("%s\n", buffer);
229
void error_message(const char *format, ...)
233
va_start(ap, format);
234
vsnprintf(buffer, 2047, format, ap);
240
gui_message(GUI_MESSAGE_ERROR, buffer);
242
printf("%s: %s\n", tr("Error"), buffer);
246
/*********************************************************************************************************
249
static float VILimit = 60.0;
250
static double VILimitMilliseconds = 1000.0/60.0;
252
static int GetVILimit(void)
254
switch (ROM_HEADER->Country_code&0xFF)
276
// Fallback for unknown codes
282
static unsigned int gettimeofday_msec(void)
285
#if defined(__WIN32__)
287
unsigned __int64 tmpres = 0;
288
GetSystemTimeAsFileTime(&ft);
289
tmpres |= ft.dwHighDateTime;
291
tmpres |= ft.dwLowDateTime;
292
foo = (((tmpres / 1000000UL) % 1000000) * 1000) + (tmpres % 1000000UL / 1000);
296
gettimeofday(&tv, NULL);
297
foo = ((tv.tv_sec % 1000000) * 1000) + (tv.tv_usec / 1000);
302
/*********************************************************************************************************
303
* global functions, for adjusting the core emulator behavior
306
void main_speeddown(int percent)
308
if (l_SpeedFactor - percent > 10) /* 10% minimum speed */
310
l_SpeedFactor -= percent;
311
main_message(0, 1, 1, OSD_BOTTOM_LEFT, "%s %d%%", tr("Playback speed:"), l_SpeedFactor);
312
setSpeedFactor(l_SpeedFactor); // call to audio plugin
316
void main_speedup(int percent)
318
if (l_SpeedFactor + percent < 300) /* 300% maximum speed */
320
l_SpeedFactor += percent;
321
main_message(0, 1, 1, OSD_BOTTOM_LEFT, "%s %d%%", tr("Playback speed:"), l_SpeedFactor);
322
setSpeedFactor(l_SpeedFactor); // call to audio plugin
326
void main_pause(void)
328
pauseContinueEmulation();
332
void main_advance_one(void)
338
void main_draw_volume_osd(void)
341
const char *volString;
343
// if we had a volume message, make sure that it's still in the OSD list, or set it to NULL
344
if (l_volMsg != NULL && !osd_message_valid(l_volMsg))
347
// this calls into the audio plugin
348
volString = volumeGetString();
349
if (volString == NULL)
351
strcpy(msgString, tr("Volume Not Supported."));
355
sprintf(msgString, "%s: %s", tr("Volume"), volString);
356
if (msgString[strlen(msgString) - 1] == '%')
357
strcat(msgString, "%");
360
// create a new message or update an existing one
361
if (l_volMsg != NULL)
362
osd_update_message(l_volMsg, msgString);
364
l_volMsg = osd_new_message(OSD_MIDDLE_CENTER, msgString);
367
/* this function could be called as a result of a keypress, joystick/button movement,
368
LIRC command, or 'testshots' command-line option timer */
369
void take_next_screenshot(void)
371
g_TakeScreenshot = l_CurrentFrame + 1;
374
void startEmulation(void)
376
VILimit = GetVILimit();
377
VILimitMilliseconds = (double) 1000.0/VILimit;
378
printf("init timer!\n");
380
const char *gfx_plugin = NULL,
381
*audio_plugin = NULL,
382
*input_plugin = NULL,
385
// make sure rom is loaded before running
388
error_message(tr("There is no Rom loaded."));
392
/* Determine which plugins to use:
393
* -If valid plugin was specified at the commandline, use it
394
* -Else, get plugin from config. NOTE: gui code must change config if user switches plugin in the gui)
398
gfx_plugin = plugin_name_by_filename(g_GfxPlugin);
402
gfx_plugin = plugin_name_by_filename(config_get_string("Gfx Plugin", ""));
407
error_message(tr("No graphics plugin specified."));
412
audio_plugin = plugin_name_by_filename(g_AudioPlugin);
414
audio_plugin = plugin_name_by_filename(config_get_string("Audio Plugin", ""));
418
error_message(tr("No audio plugin specified."));
423
input_plugin = plugin_name_by_filename(g_InputPlugin);
425
input_plugin = plugin_name_by_filename(config_get_string("Input Plugin", ""));
429
error_message(tr("No input plugin specified."));
434
RSP_plugin = plugin_name_by_filename(g_RspPlugin);
436
RSP_plugin = plugin_name_by_filename(config_get_string("RSP Plugin", ""));
440
error_message(tr("No RSP plugin specified."));
444
// load the plugins. Do this outside the emulation thread for GUI
445
// related things which cannot be done outside the main thread.
446
// Examples: GTK Icon theme setup in Rice which otherwise hangs forever
447
// with the Qt4 interface.
448
plugin_load_plugins(gfx_plugin, audio_plugin, input_plugin, RSP_plugin);
450
// in nogui mode, just start the emulator in the main thread
453
emulationThread(NULL);
455
else if(!g_EmulatorRunning)
457
// spawn emulation thread
458
g_EmulationThread = SDL_CreateThread(emulationThread, NULL);
459
if(g_EmulationThread == NULL)
461
printf("Unable to create thread: %s\n", SDL_GetError());
462
error_message(tr("Couldn't spawn core thread!"));
466
main_message(0, 1, 0, OSD_BOTTOM_LEFT, tr("Emulation started (PID: %d)"), g_EmulationThread);
468
// if emulation is already running, but it's paused, unpause it
475
void stopEmulation(void)
477
if(g_EmulatorRunning)
479
main_message(0, 1, 0, OSD_BOTTOM_LEFT, tr("Stopping emulation.\n"));
490
// wait until emulation thread is done before continuing
491
if(g_EmulatorRunning)
492
SDL_WaitThread(g_EmulationThread, NULL);
495
plugin_close_plugins();
497
g_EmulatorRunning = 0;
498
g_EmulationThread = 0;
501
gui_set_state(GUI_STATE_STOPPED);
502
g_romcache.rcspause = 0;
505
main_message(0, 1, 0, OSD_BOTTOM_LEFT, tr("Emulation stopped.\n"));
509
int pauseContinueEmulation(void)
511
static osd_message_t *msg = NULL;
513
if (!g_EmulatorRunning)
519
gui_set_state(GUI_STATE_RUNNING);
520
g_romcache.rcspause = 1;
522
main_message(0, 1, 0, OSD_BOTTOM_LEFT, tr("Emulation continued.\n"));
525
osd_delete_message(msg);
532
gui_set_state(GUI_STATE_PAUSED);
533
g_romcache.rcspause = 0;
536
osd_delete_message(msg);
538
main_message(0, 1, 0, OSD_BOTTOM_LEFT, tr("Paused\n"));
539
msg = osd_new_message(OSD_MIDDLE_CENTER, tr("Paused\n"));
540
osd_message_set_static(msg);
543
rompause = !rompause;
547
/*********************************************************************************************************
548
* global functions, callbacks from the r4300 core or from other plugins
551
void video_plugin_render_callback(void)
553
// if the flag is set to take a screenshot, then grab it now
554
if (g_TakeScreenshot != 0)
556
TakeScreenshot(g_TakeScreenshot - 1); // current frame number +1 is in g_TakeScreenshot
557
g_TakeScreenshot = 0; // reset flag
560
// if the OSD is enabled, then draw it now
569
// take a screenshot if we need to
570
if (l_TestShotList != NULL)
572
int nextshot = l_TestShotList[l_TestShotIdx];
573
if (nextshot == l_CurrentFrame)
575
// set global variable so screenshot will be taken just before OSD is drawn at the end of frame rendering
576
take_next_screenshot();
577
// advance list index to next screenshot frame number. If it's 0, then quit
580
else if (nextshot == 0)
583
free(l_TestShotList);
584
l_TestShotList = NULL;
588
// advance the current frame
595
unsigned int CurrentFPSTime;
596
static unsigned int LastFPSTime = 0;
597
static unsigned int CounterTime = 0;
598
static unsigned int CalculatedTime ;
599
static int VI_Counter = 0;
601
double AdjustedLimit = VILimitMilliseconds * 100.0 / l_SpeedFactor; // adjust for selected emulator speed
604
start_section(IDLE_SECTION);
608
if(debugger_mode) debugger_frontend_vi();
613
LastFPSTime = gettimeofday_msec();
614
CounterTime = gettimeofday_msec();
617
CurrentFPSTime = gettimeofday_msec();
619
Dif = CurrentFPSTime - LastFPSTime;
621
if (Dif < AdjustedLimit)
623
CalculatedTime = CounterTime + AdjustedLimit * VI_Counter;
624
time = (int)(CalculatedTime - CurrentFPSTime);
633
CurrentFPSTime = CurrentFPSTime + time;
636
if (CurrentFPSTime - CounterTime >= 1000.0 )
638
CounterTime = gettimeofday_msec();
642
LastFPSTime = CurrentFPSTime ;
643
end_section(IDLE_SECTION);
644
if (l_FrameAdvance) {
650
/*********************************************************************************************************
653
static int sdl_event_filter( const SDL_Event *event )
655
static osd_message_t *msgFF = NULL;
656
static int SavedSpeedFactor = 100;
657
static BYTE StopRumble[6] = {0x23, 0x01, 0x03, 0xc0, 0x1b, 0x00};
658
char *event_str = NULL;
660
switch( event->type )
662
// user clicked on window close button
667
/* check for the only 2 hard-coded key commands: Alt-enter for fullscreen and 0-9 for save state slot */
668
if (event->key.keysym.sym == SDLK_RETURN && event->key.keysym.mod & (KMOD_LALT | KMOD_RALT))
672
else if (event->key.keysym.unicode >= '0' && event->key.keysym.unicode <= '9')
674
savestates_select_slot( event->key.keysym.unicode - '0' );
676
/* check all of the configurable commands */
677
else if (event->key.keysym.sym == config_get_number("Kbd Mapping Stop", SDLK_ESCAPE))
679
else if (event->key.keysym.sym == config_get_number("Kbd Mapping Fullscreen", 0))
681
else if (event->key.keysym.sym == config_get_number("Kbd Mapping Save State", SDLK_F5))
682
savestates_job |= SAVESTATE;
683
else if (event->key.keysym.sym == config_get_number("Kbd Mapping Load State", SDLK_F7))
685
savestates_job |= LOADSTATE;
686
controllerCommand(0, StopRumble);
687
controllerCommand(1, StopRumble);
688
controllerCommand(2, StopRumble);
689
controllerCommand(3, StopRumble);
691
else if (event->key.keysym.sym == config_get_number("Kbd Mapping Increment Slot", 0))
692
savestates_inc_slot();
693
else if (event->key.keysym.sym == config_get_number("Kbd Mapping Reset", SDLK_F9))
695
add_interupt_event(HW2_INT, 0); /* Hardware 2 Interrupt immediately */
696
add_interupt_event(NMI_INT, 50000000); /* Non maskable Interrupt after 1/2 second */
698
else if (event->key.keysym.sym == config_get_number("Kbd Mapping Speed Down", SDLK_F10))
700
else if (event->key.keysym.sym == config_get_number("Kbd Mapping Speed Up",SDLK_F11))
702
else if (event->key.keysym.sym == config_get_number("Kbd Mapping Screenshot", SDLK_F12))
703
// set flag so that screenshot will be taken at the end of frame rendering
704
take_next_screenshot();
705
else if (event->key.keysym.sym == config_get_number("Kbd Mapping Pause", SDLK_p))
707
else if (event->key.keysym.sym == config_get_number("Kbd Mapping Mute", SDLK_m))
710
main_draw_volume_osd();
712
else if (event->key.keysym.sym == config_get_number("Kbd Mapping Increase Volume", SDLK_RIGHTBRACKET))
715
main_draw_volume_osd();
717
else if (event->key.keysym.sym == config_get_number("Kbd Mapping Decrease Volume", SDLK_LEFTBRACKET))
720
main_draw_volume_osd();
722
else if (event->key.keysym.sym == config_get_number("Kbd Mapping Fast Forward", SDLK_f))
724
SavedSpeedFactor = l_SpeedFactor;
726
setSpeedFactor(l_SpeedFactor); // call to audio plugin
727
// set fast-forward indicator
728
msgFF = osd_new_message(OSD_TOP_RIGHT, tr("Fast Forward"));
729
osd_message_set_static(msgFF);
731
else if (event->key.keysym.sym == config_get_number("Kbd Mapping Frame Advance", SDLK_SLASH))
733
// pass all other keypresses to the input plugin
734
else keyDown( 0, event->key.keysym.sym );
739
if(event->key.keysym.sym == config_get_number("Kbd Mapping Stop", SDLK_ESCAPE))
743
else if(event->key.keysym.sym == config_get_number("Kbd Mapping Fast Forward", SDLK_f))
745
// cancel fast-forward
746
l_SpeedFactor = SavedSpeedFactor;
747
setSpeedFactor(l_SpeedFactor); // call to audio plugin
749
osd_delete_message(msgFF);
751
else keyUp( 0, event->key.keysym.sym );
755
// if joystick action is detected, check if it's mapped to a special function
756
case SDL_JOYAXISMOTION:
757
// axis events have to be above a certain threshold to be valid
758
if(event->jaxis.value > -15000 && event->jaxis.value < 15000)
760
case SDL_JOYBUTTONDOWN:
761
case SDL_JOYHATMOTION:
762
event_str = event_to_str(event);
764
if(!event_str) return 0;
766
if(strcmp(event_str, config_get_string("Joy Mapping Fullscreen", "")) == 0)
768
else if(strcmp(event_str, config_get_string("Joy Mapping Stop", "")) == 0)
770
else if(strcmp(event_str, config_get_string("Joy Mapping Pause", "")) == 0)
772
else if(strcmp(event_str, config_get_string("Joy Mapping Save State", "")) == 0)
773
savestates_job |= SAVESTATE;
774
else if(strcmp(event_str, config_get_string("Joy Mapping Load State", "")) == 0)
775
savestates_job |= LOADSTATE;
776
else if(strcmp(event_str, config_get_string("Joy Mapping Increment Slot", "")) == 0)
777
savestates_inc_slot();
778
else if(strcmp(event_str, config_get_string("Joy Mapping Screenshot", "")) == 0)
779
take_next_screenshot();
780
else if(strcmp(event_str, config_get_string("Joy Mapping Mute", "")) == 0)
783
main_draw_volume_osd();
785
else if(strcmp(event_str, config_get_string("Joy Mapping Decrease Volume", "")) == 0)
788
main_draw_volume_osd();
790
else if(strcmp(event_str, config_get_string("Joy Mapping Increase Volume", "")) == 0)
793
main_draw_volume_osd();
804
/*********************************************************************************************************
805
* emulation thread - runs the core
807
static int emulationThread( void *_arg )
809
#if !defined(__WIN32__)
812
const char *gfx_plugin = NULL,
813
*audio_plugin = NULL,
814
*input_plugin = NULL,
817
// install signal handler, but only if we're running in GUI mode
818
// in non-GUI mode, we don't need to catch exceptions (there's no GUI to take down)
821
#if defined(__WIN32__)
822
signal( SIGSEGV, sighandler );
823
signal( SIGILL, sighandler );
824
signal( SIGFPE, sighandler );
826
memset( &sa, 0, sizeof( struct sigaction ) );
827
sa.sa_sigaction = sighandler;
828
sa.sa_flags = SA_SIGINFO;
829
sigaction( SIGSEGV, &sa, NULL );
830
sigaction( SIGILL, &sa, NULL );
831
sigaction( SIGFPE, &sa, NULL );
832
sigaction( SIGCHLD, &sa, NULL );
836
g_EmulatorRunning = 1;
837
// if emu mode wasn't specified at the commandline, set from config file
839
dynacore = config_get_number( "Core", CORE_DYNAREC );
841
if(dynacore==CORE_DYNAREC)
842
dynacore = CORE_INTERPRETER;
845
no_compiled_jump = config_get_bool("NoCompiledJump", FALSE);
848
SDL_Init(SDL_INIT_VIDEO);
850
SDL_EnableKeyRepeat(0, 0);
852
SDL_SetEventFilter(sdl_event_filter);
853
SDL_EnableUNICODE(1);
855
// initialize memory, and do byte-swapping if it's not been done yet
856
if (g_MemHasBeenBSwapped == 0)
859
g_MemHasBeenBSwapped = 1;
866
// Attach rom to plugins
871
// switch to fullscreen if enabled
877
// init on-screen display
878
void *pvPixels = NULL;
879
int width = 640, height = 480;
880
readScreen(&pvPixels, &width, &height); // read screen to get width and height
881
if (pvPixels != NULL)
886
osd_init(width, height);
889
// setup rendering callback from video plugin to the core, for screenshots and On-Screen-Display
890
setRenderingCallback(video_plugin_render_callback);
893
gui_set_state(GUI_STATE_RUNNING);
894
g_romcache.rcspause = 1;
902
if (g_DebuggerEnabled)
906
/* load cheats for the current rom */
907
cheat_load_current_rom();
909
/* Startup message on the OSD */
910
osd_new_message(OSD_MIDDLE_CENTER, "Mupen64Plus Started...");
912
/* call r4300 CPU core and run the game */
942
g_EmulatorRunning = 0;
949
/*********************************************************************************************************
953
static void sighandler(int signal)
955
printf( "Signal number %d caught\n", signal );
958
static void sighandler(int signal, siginfo_t *info, void *context)
960
SDL_Thread *emuThread = g_EmulationThread;
965
error_message(tr("The core thread recieved a SIGSEGV signal.\n"
966
"This means it tried to access protected memory.\n"
967
"Maybe you have set a wrong ucode for one of the plugins!"));
968
printf( "SIGSEGV in core thread caught:\n" );
969
printf( "\terrno = %d (%s)\n", info->si_errno, strerror( info->si_errno ) );
970
printf( "\taddress = 0x%08lX\n", (unsigned long) info->si_addr );
972
switch( info->si_code )
974
case SEGV_MAPERR: printf( " address not mapped to object\n" ); break;
975
case SEGV_ACCERR: printf( " invalid permissions for mapped object\n" ); break;
980
printf( "SIGILL in core thread caught:\n" );
981
printf( "\terrno = %d (%s)\n", info->si_errno, strerror( info->si_errno ) );
982
printf( "\taddress = 0x%08lX\n", (unsigned long) info->si_addr );
984
switch( info->si_code )
986
case ILL_ILLOPC: printf( "\tillegal opcode\n" ); break;
987
case ILL_ILLOPN: printf( "\tillegal operand\n" ); break;
988
case ILL_ILLADR: printf( "\tillegal addressing mode\n" ); break;
989
case ILL_ILLTRP: printf( "\tillegal trap\n" ); break;
990
case ILL_PRVOPC: printf( "\tprivileged opcode\n" ); break;
991
case ILL_PRVREG: printf( "\tprivileged register\n" ); break;
992
case ILL_COPROC: printf( "\tcoprocessor error\n" ); break;
993
case ILL_BADSTK: printf( "\tinternal stack error\n" ); break;
998
printf( "SIGFPE in core thread caught:\n" );
999
printf( "\terrno = %d (%s)\n", info->si_errno, strerror( info->si_errno ) );
1000
printf( "\taddress = 0x%08lX\n", (unsigned long) info->si_addr );
1001
switch( info->si_code )
1003
case FPE_INTDIV: printf( "\tinteger divide by zero\n" ); break;
1004
case FPE_INTOVF: printf( "\tinteger overflow\n" ); break;
1005
case FPE_FLTDIV: printf( "\tfloating point divide by zero\n" ); break;
1006
case FPE_FLTOVF: printf( "\tfloating point overflow\n" ); break;
1007
case FPE_FLTUND: printf( "\tfloating point underflow\n" ); break;
1008
case FPE_FLTRES: printf( "\tfloating point inexact result\n" ); break;
1009
case FPE_FLTINV: printf( "\tfloating point invalid operation\n" ); break;
1010
case FPE_FLTSUB: printf( "\tsubscript out of range\n" ); break;
1014
printf( "Signal number %d in core thread caught:\n", signal );
1015
printf( "\terrno = %d (%s)\n", info->si_errno, strerror( info->si_errno ) );
1018
g_EmulationThread = 0;
1019
g_EmulatorRunning = 0;
1021
if (emuThread != NULL)
1022
SDL_KillThread(emuThread);
1024
#endif /* __WIN32__ */
1027
static void printUsage(const char *progname)
1029
char *str = strdup(progname);
1031
printf("Usage: %s [parameter(s)] [romfile]\n"
1034
" --nogui : do not display GUI.\n"
1035
" --noask : do not prompt user if rom file is hacked or a bad dump.\n"
1036
" --noosd : disable onscreen display.\n"
1037
" --fullscreen : turn fullscreen mode on.\n"
1038
" --romnumber (number) : specify which rom in romfile, if multirom archive.\n"
1039
" --gfx (plugin-file) : use gfx plugin given by (path)\n"
1040
" --audio (plugin-file) : use audio plugin given by (path)\n"
1041
" --input (plugin-file) : use input plugin given by (path)\n"
1042
" --rsp (plugin-file) : use rsp plugin given by (path)\n"
1043
" --emumode (mode) : set emu mode to: 0=Interpreter 1=DynaRec 2=Pure Interpreter\n"
1044
" --sshotdir (dir) : set screenshot directory to (dir)\n"
1045
" --configdir (dir) : force config dir (must contain mupen64plus.conf)\n"
1046
" --installdir (dir) : force install dir (place to look for plugins, icons, lang, etc)\n"
1047
" --testshots (list) : take screenshots at frames given in comma-separated (list), then quit\n"
1049
" --debugger : start with debugger enabled\n"
1051
" -h, --help : see this help message\n"
1060
* Parses commandline options and sets global variables accordingly
1062
void parseCommandLine(int argc, char **argv)
1067
// option parsing vars
1068
int opt, option_index;
1086
struct option long_options[] =
1088
{"nogui", no_argument, &l_GuiEnabled, FALSE},
1089
{"noosd", no_argument, &g_OsdEnabled, FALSE},
1090
{"fullscreen", no_argument, &g_Fullscreen, TRUE},
1091
{"romnumber", required_argument, NULL, OPT_ROMNUMBER},
1092
{"gfx", required_argument, NULL, OPT_GFX},
1093
{"audio", required_argument, NULL, OPT_AUDIO},
1094
{"input", required_argument, NULL, OPT_INPUT},
1095
{"rsp", required_argument, NULL, OPT_RSP},
1096
{"emumode", required_argument, NULL, OPT_EMUMODE},
1097
{"sshotdir", required_argument, NULL, OPT_SSHOTDIR},
1098
{"configdir", required_argument, NULL, OPT_CONFIGDIR},
1099
{"installdir", required_argument, NULL, OPT_INSTALLDIR},
1101
{"debugger", no_argument, NULL, OPT_DEBUGGER},
1103
{"noask", no_argument, NULL, OPT_NOASK},
1104
{"testshots", required_argument, NULL, OPT_TESTSHOTS},
1105
{"help", no_argument, NULL, 'h'},
1106
{0, 0, 0, 0} // last opt must be empty
1108
char opt_str[] = "h";
1110
/* parse commandline options */
1111
while((opt = getopt_long(argc, argv, opt_str,
1112
long_options, &option_index)) != -1)
1116
// if getopt_long returns 0, it already set the global for us, so do nothing
1120
if(plugin_scan_file(optarg, PLUGIN_TYPE_GFX))
1122
g_GfxPlugin = optarg;
1126
printf("***Warning: GFX Plugin '%s' couldn't be loaded!\n", optarg);
1130
if(plugin_scan_file(optarg, PLUGIN_TYPE_AUDIO))
1132
g_AudioPlugin = optarg;
1136
printf("***Warning: Audio Plugin '%s' couldn't be loaded!\n", optarg);
1140
if(plugin_scan_file(optarg, PLUGIN_TYPE_CONTROLLER))
1142
g_InputPlugin = optarg;
1146
printf("***Warning: Input Plugin '%s' couldn't be loaded!\n", optarg);
1150
if(plugin_scan_file(optarg, PLUGIN_TYPE_RSP))
1152
g_RspPlugin = optarg;
1156
printf("***Warning: RSP Plugin '%s' couldn't be loaded!\n", optarg);
1161
if(i >= CORE_INTERPRETER && i <= CORE_PURE_INTERPRETER)
1168
printf("***Warning: Invalid Emumode: %s\n", optarg);
1173
SetScreenshotDir(optarg);
1175
printf("***Warning: Screen shot directory '%s' is not accessible or not a directory.\n", optarg);
1179
strncpy(l_ConfigDir, optarg, PATH_MAX);
1181
printf("***Warning: Config directory '%s' is not accessible or not a directory.\n", optarg);
1183
case OPT_INSTALLDIR:
1185
strncpy(l_InstallDir, optarg, PATH_MAX);
1187
printf("***Warning: Install directory '%s' is not accessible or not a directory.\n", optarg);
1190
g_Noask = g_NoaskParam = TRUE;
1193
// count the number of integers in the list
1196
while ((str = strchr(str, ',')) != NULL)
1201
// create a list and populate it with the frame counter values at which to take screenshots
1202
if ((l_TestShotList = malloc(sizeof(int) * (shots + 1))) != NULL)
1208
l_TestShotList[idx++] = atoi(str);
1209
str = strchr(str, ',');
1210
if (str != NULL) str++;
1212
l_TestShotList[idx] = 0;
1217
g_DebuggerEnabled = TRUE;
1221
l_RomNumber = atoi(optarg);
1227
printUsage(argv[0]);
1233
// if there are still parameters left after option parsing, assume it's the rom filename
1236
l_Filename = argv[optind];
1239
// if executable name contains "_nogui", set l_GuiEnabled to FALSE.
1240
// This allows creation of a mupen64plus_nogui symlink to mupen64plus instead of passing --nogui
1241
// for backwards compatability with old mupen64_nogui program name.
1242
str = strdup(argv[0]);
1243
if(strstr(str, "_nogui") != NULL)
1245
l_GuiEnabled = FALSE;
1251
* setup paths to config/install/screenshot directories. The config dir is the dir where all
1252
* user config information is stored, e.g. mupen64plus.conf, save files, and plugin conf files.
1253
* The install dir is where mupen64plus looks for common files, e.g. plugins, icons, language
1254
* translation files.
1256
static void setPaths(void)
1259
strncpy(l_ConfigDir, "./", PATH_MAX);
1260
strncpy(l_InstallDir, "./", PATH_MAX);
1263
char buf[PATH_MAX], buf2[PATH_MAX];
1265
// if the config dir was not specified at the commandline, look for ~/.mupen64plus dir
1266
if (strlen(l_ConfigDir) == 0)
1268
strncpy(l_ConfigDir, getenv("HOME"), PATH_MAX);
1269
strncat(l_ConfigDir, "/.mupen64plus", PATH_MAX - strlen(l_ConfigDir));
1271
// if ~/.mupen64plus dir is not found, create it
1272
if(!isdir(l_ConfigDir))
1274
printf("Creating %s to store user data\n", l_ConfigDir);
1275
if(mkdir(l_ConfigDir, (mode_t)0755) != 0)
1277
printf("Error: Could not create %s: ", l_ConfigDir);
1282
// create save subdir
1283
strncpy(buf, l_ConfigDir, PATH_MAX);
1284
strncat(buf, "/save", PATH_MAX - strlen(buf));
1285
if(mkdir(buf, (mode_t)0755) != 0)
1287
// report error, but don't exit
1288
printf("Warning: Could not create %s: %s", buf, strerror(errno));
1291
// create screenshots subdir
1292
strncpy(buf, l_ConfigDir, PATH_MAX);
1293
strncat(buf, "/screenshots", PATH_MAX - strlen(buf));
1294
if(mkdir(buf, (mode_t)0755) != 0)
1296
// report error, but don't exit
1297
printf("Warning: Could not create %s: %s", buf, strerror(errno));
1302
// make sure config dir has a '/' on the end.
1303
if(l_ConfigDir[strlen(l_ConfigDir)-1] != '/')
1304
strncat(l_ConfigDir, "/", PATH_MAX - strlen(l_ConfigDir));
1306
// if install dir was not specified at the commandline, look for it in the executable's directory
1307
if (strlen(l_InstallDir) == 0)
1310
macSetBundlePath(buf);
1311
strncpy(l_InstallDir, buf, PATH_MAX);
1312
strncat(buf, "/config/mupen64plus.conf", PATH_MAX - strlen(buf));
1315
int n = readlink("/proc/self/exe", buf, PATH_MAX);
1320
strncpy(l_InstallDir, buf, PATH_MAX);
1321
strncat(buf, "/config/mupen64plus.conf", PATH_MAX - strlen(buf));
1324
// if it's not in the executable's directory, try a couple of default locations
1325
if (buf[0] == '\0' || !isfile(buf))
1327
strcpy(l_InstallDir, "/usr/local/share/mupen64plus");
1328
strcpy(buf, l_InstallDir);
1329
strcat(buf, "/config/mupen64plus.conf");
1332
strcpy(l_InstallDir, "/usr/share/mupen64plus");
1333
strcpy(buf, l_InstallDir);
1334
strcat(buf, "/config/mupen64plus.conf");
1335
// if install dir is not in the default locations, try the same dir as the binary
1338
// try cwd as last resort
1339
getcwd(l_InstallDir, PATH_MAX);
1345
// make sure install dir has a '/' on the end.
1346
if(l_InstallDir[strlen(l_InstallDir)-1] != '/')
1347
strncat(l_InstallDir, "/", PATH_MAX - strlen(l_InstallDir));
1349
// make sure install dir is valid
1350
strncpy(buf, l_InstallDir, PATH_MAX);
1351
strncat(buf, "config/mupen64plus.conf", PATH_MAX - strlen(buf));
1354
printf("Could not locate valid install directory\n");
1358
// check user config dir for mupen64plus.conf file. If it's not there, copy all
1359
// config files from install dir over to user dir.
1360
strncpy(buf, l_ConfigDir, PATH_MAX);
1361
strncat(buf, "mupen64plus.conf", PATH_MAX - strlen(buf));
1365
struct dirent *entry;
1367
strncpy(buf, l_InstallDir, PATH_MAX);
1368
strncat(buf, "config", PATH_MAX - strlen(buf));
1371
// should never hit this error because of previous checks
1378
while((entry = readdir(dir)) != NULL)
1380
strncpy(buf, l_InstallDir, PATH_MAX);
1381
strncat(buf, "config/", PATH_MAX - strlen(buf));
1382
strncat(buf, entry->d_name, PATH_MAX - strlen(buf));
1384
// only copy regular files
1387
strncpy(buf2, l_ConfigDir, PATH_MAX);
1388
strncat(buf2, entry->d_name, PATH_MAX - strlen(buf2));
1390
printf("Copying %s to %s\n", buf, l_ConfigDir);
1391
if(copyfile(buf, buf2) != 0)
1392
printf("Error copying file\n");
1399
// set screenshot dir if it wasn't specified by the user
1400
if (!ValidScreenshotDir())
1402
char chDefaultDir[PATH_MAX + 1];
1403
snprintf(chDefaultDir, PATH_MAX, "%sscreenshots/", l_ConfigDir);
1404
SetScreenshotDir(chDefaultDir);
1406
#endif /* __WIN32__ */
1409
/*********************************************************************************************************
1412
int main(int argc, char *argv[])
1414
char dirpath[PATH_MAX];
1416
int retval = EXIT_SUCCESS;
1417
printf(" __ __ __ _ _ ____ _ \n");
1418
printf("| \\/ |_ _ _ __ ___ _ __ / /_ | || | | _ \\| |_ _ ___ \n");
1419
printf("| |\\/| | | | | '_ \\ / _ \\ '_ \\| '_ \\| || |_| |_) | | | | / __| \n");
1420
printf("| | | | |_| | |_) | __/ | | | (_) |__ _| __/| | |_| \\__ \\ \n");
1421
printf("|_| |_|\\__,_| .__/ \\___|_| |_|\\___/ |_| |_| |_|\\__,_|___/ \n");
1422
printf(" |_| http://code.google.com/p/mupen64plus/ \n");
1423
printf("Version %s\n\n",MUPEN_VERSION);
1425
parseCommandLine(argc, argv);
1431
i = config_get_bool("OsdEnabled", 2);
1434
config_put_bool("OsdEnabled", 1);
1436
else if (g_OsdEnabled == 1)
1440
// check "GUI always start fullscreen" setting in config file
1441
i = config_get_bool("GuiStartFullscreen", 2);
1444
config_put_bool("GuiStartFullscreen", 0);
1446
else if (g_Fullscreen == 0)
1453
// init multi-language support
1456
// if --noask was not specified at the commandline, default to true in nogui mode,
1457
// otherwise check the config file.
1466
g_Noask = config_get_bool("No Ask", FALSE);
1470
cheat_read_config();
1472
// try to get plugin folder path from the mupen64plus config file (except on mac where app bundles may be used)
1473
strncpy(dirpath, config_get_string("PluginDirectory", ""), PATH_MAX-1);
1475
dirpath[PATH_MAX-1] = '\0';
1476
// if it's not set in the config file, use the /plugins/ sub-folder of the installation directory
1477
if (strlen(dirpath) < 2)
1479
strncpy(dirpath, "/usr/lib/mupen64plus/", PATH_MAX);
1480
dirpath[PATH_MAX-1] = '\0';
1482
// scan the plugin directory and set the config dir for the plugins
1483
plugin_scan_directory(dirpath);
1484
plugin_set_dirs(l_ConfigDir, l_InstallDir);
1488
gui_init(&argc, &argv);
1490
// must be called after building gui
1491
// look for plugins in the install dir and set plugin config dir
1492
savestates_set_autoinc_slot(config_get_bool("AutoIncSaveSlot", FALSE));
1494
if((i=config_get_number("CurrentSaveSlot",10))!=10)
1496
savestates_select_slot((unsigned int)i);
1500
config_put_number("CurrentSaveSlot",0);
1503
main_message(1, 0, 0, 0, tr("Config Dir: %s\nInstall Dir: %s\nPlugin Dir: %s\n"), l_ConfigDir, l_InstallDir, dirpath);
1504
main_message(0, 1, 0, 0, tr("Config Dir: \"%s\", Install Dir: \"%s\", Plugin Dir: \"%s\""), l_ConfigDir, l_InstallDir, dirpath);
1506
//The database needs to be opened regardless of GUI mode.
1509
// only create the ROM Cache Thread if GUI is enabled
1512
g_romcache.rcstask = RCS_INIT;
1513
g_RomCacheThread = SDL_CreateThread(rom_cache_system, NULL);
1515
if(g_RomCacheThread == NULL)
1517
error_message(tr("Couldn't spawn rom cache thread!"));
1521
// only display gui if user wants it
1526
// if rom file was specified, run it
1529
if (open_rom(l_Filename, l_RomNumber) >= 0)
1533
else if (!l_GuiEnabled)
1538
// Rom file must be specified in nogui mode
1539
else if (!l_GuiEnabled)
1541
error_message("Rom file must be specified in nogui mode.");
1542
printUsage(argv[0]);
1547
// give control of this thread to the gui
1555
// free allocated memory
1556
if (l_TestShotList != NULL)
1557
free(l_TestShotList);
1561
cheat_write_config();
1564
g_romcache.rcstask = RCS_SHUTDOWN;
1566
romdatabase_close();
1567
plugin_delete_list();
1568
tr_delete_languages();
1576
static const char* programName = "mupen64plus.exe";
1578
int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdParamarg, int cmdShow)
1580
list_t arguments = NULL;
1581
list_node_t* node = NULL;
1587
g_ProgramInstance = instance;
1589
wrk = malloc(strlen(programName) + 1);
1590
strcpy(wrk, programName);
1591
list_append(&arguments, wrk);
1593
for (arg = strtok(cmdParamarg, " ");
1595
arg = strtok(NULL, " "))
1597
wrk = malloc(strlen(arg) + 1);
1599
list_append(&arguments, arg);
1602
argv = malloc(list_length(arguments) + 1 * sizeof(char*));
1603
list_foreach(arguments, node)
1605
argv[i++] = node->data;
1608
return main(i, argv);