1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Mupen64plus - main.c *
3 * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
4 * Copyright (C) 2012 CasualJames *
5 * Copyright (C) 2008-2009 Richard Goedeken *
6 * Copyright (C) 2008 Ebenblues Nmn Okaygo Tillin9 *
7 * Copyright (C) 2002 Hacktarux *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
14 * This program is distributed in the hope that it will be useful, *
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17 * GNU General Public License for more details. *
19 * You should have received a copy of the GNU General Public License *
20 * along with this program; if not, write to the *
21 * Free Software Foundation, Inc., *
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
23 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
25 /* This is MUPEN64's main entry point. It contains code that is common
26 * to both the gui and non-gui versions of mupen64. See
27 * gui subdirectories for the gui-specific code.
28 * if you want to implement an interface, you should look here
36 #define M64P_CORE_PROTOTYPES 1
37 #include "api/m64p_types.h"
38 #include "api/callbacks.h"
39 #include "api/config.h"
40 #include "api/m64p_config.h"
41 #include "api/debugger.h"
42 #include "api/vidext.h"
45 #include "eventloop.h"
47 #include "savestates.h"
50 #include "memory/memory.h"
51 #include "osal/files.h"
52 #include "osal/preproc.h"
54 #include "osd/screenshot.h"
55 #include "plugin/plugin.h"
56 #include "r4300/r4300.h"
57 #include "r4300/interupt.h"
58 #include "r4300/reset.h"
61 #include "debugger/dbg_types.h"
62 #include "debugger/debugger.h"
69 /* version number for Core config section */
70 #define CONFIG_PARAM_VERSION 1.01
73 m64p_handle g_CoreConfig = NULL;
75 m64p_frame_callback g_FrameCallback = NULL;
77 int g_MemHasBeenBSwapped = 0; // store byte-swapped flag so we don't swap twice when re-playing game
78 int g_EmulatorRunning = 0; // need separate boolean to tell if emulator is running, since --nogui doesn't use a thread
80 /** static (local) variables **/
81 static int l_CurrentFrame = 0; // frame counter
82 static int l_TakeScreenshot = 0; // Tell OSD Rendering callback to take a screenshot just before drawing the OSD
83 static int l_SpeedFactor = 100; // percentage of nominal game speed at which emulator is running
84 static int l_FrameAdvance = 0; // variable to check if we pause on next frame
85 static int l_MainSpeedLimit = 1; // insert delay during vi_interrupt to keep speed at real-time
87 static osd_message_t *l_msgVol = NULL;
88 static osd_message_t *l_msgFF = NULL;
89 static osd_message_t *l_msgPause = NULL;
91 /*********************************************************************************************************
95 static const char *get_savepathdefault(const char *configpath)
97 static char path[1024];
99 if (!configpath || (strlen(configpath) == 0)) {
100 snprintf(path, 1024, "%ssave%c", ConfigGetUserDataPath(), OSAL_DIR_SEPARATORS[0]);
103 snprintf(path, 1024, "%s%c", configpath, OSAL_DIR_SEPARATORS[0]);
107 /* create directory if it doesn't exist */
108 osal_mkdirp(path, 0700);
114 /*********************************************************************************************************
119 const char *get_savestatepath(void)
121 /* try to get the SaveStatePath string variable in the Core configuration section */
122 return get_savepathdefault(ConfigGetParamString(g_CoreConfig, "SaveStatePath"));
125 const char *get_savesrampath(void)
127 /* try to get the SaveSRAMPath string variable in the Core configuration section */
128 return get_savepathdefault(ConfigGetParamString(g_CoreConfig, "SaveSRAMPath"));
131 void main_message(m64p_msg_level level, unsigned int corner, const char *format, ...)
135 va_start(ap, format);
136 vsnprintf(buffer, 2047, format, ap);
140 /* send message to on-screen-display if enabled */
141 if (ConfigGetParamBool(g_CoreConfig, "OnScreenDisplay"))
142 osd_new_message((enum osd_corner) corner, "%s", buffer);
143 /* send message to front-end */
144 DebugMessage(level, "%s", buffer);
148 /*********************************************************************************************************
149 * global functions, for adjusting the core emulator behavior
152 int main_set_core_defaults(void)
154 float fConfigParamsVersion;
155 int bSaveConfig = 0, bUpgrade = 0;
157 if (ConfigGetParameter(g_CoreConfig, "Version", M64TYPE_FLOAT, &fConfigParamsVersion, sizeof(float)) != M64ERR_SUCCESS)
159 DebugMessage(M64MSG_WARNING, "No version number in 'Core' config section. Setting defaults.");
160 ConfigDeleteSection("Core");
161 ConfigOpenSection("Core", &g_CoreConfig);
164 else if (((int) fConfigParamsVersion) != ((int) CONFIG_PARAM_VERSION))
166 DebugMessage(M64MSG_WARNING, "Incompatible version %.2f in 'Core' config section: current is %.2f. Setting defaults.", fConfigParamsVersion, (float) CONFIG_PARAM_VERSION);
167 ConfigDeleteSection("Core");
168 ConfigOpenSection("Core", &g_CoreConfig);
171 else if ((CONFIG_PARAM_VERSION - fConfigParamsVersion) >= 0.0001f)
173 float fVersion = (float) CONFIG_PARAM_VERSION;
174 ConfigSetParameter(g_CoreConfig, "Version", M64TYPE_FLOAT, &fVersion);
175 DebugMessage(M64MSG_INFO, "Updating parameter set version in 'Core' config section to %.2f", fVersion);
180 /* parameters controlling the operation of the core */
181 ConfigSetDefaultFloat(g_CoreConfig, "Version", (float) CONFIG_PARAM_VERSION, "Mupen64Plus Core config parameter set version number. Please don't change this version number.");
182 ConfigSetDefaultBool(g_CoreConfig, "OnScreenDisplay", 1, "Draw on-screen display if True, otherwise don't draw OSD");
184 ConfigSetDefaultInt(g_CoreConfig, "R4300Emulator", 2, "Use Pure Interpreter if 0, Cached Interpreter if 1, or Dynamic Recompiler if 2 or more");
186 ConfigSetDefaultInt(g_CoreConfig, "R4300Emulator", 1, "Use Pure Interpreter if 0, Cached Interpreter if 1, or Dynamic Recompiler if 2 or more");
188 ConfigSetDefaultBool(g_CoreConfig, "NoCompiledJump", 0, "Disable compiled jump commands in dynamic recompiler (should be set to False) ");
189 ConfigSetDefaultBool(g_CoreConfig, "DisableExtraMem", 0, "Disable 4MB expansion RAM pack. May be necessary for some games");
190 ConfigSetDefaultBool(g_CoreConfig, "AutoStateSlotIncrement", 0, "Increment the save state slot after each save operation");
191 ConfigSetDefaultBool(g_CoreConfig, "EnableDebugger", 0, "Activate the R4300 debugger when ROM execution begins, if core was built with Debugger support");
192 ConfigSetDefaultInt(g_CoreConfig, "CurrentStateSlot", 0, "Save state slot (0-9) to use when saving/loading the emulator state");
193 ConfigSetDefaultString(g_CoreConfig, "ScreenshotPath", "", "Path to directory where screenshots are saved. If this is blank, the default value of ${UserConfigPath}/screenshot will be used");
194 ConfigSetDefaultString(g_CoreConfig, "SaveStatePath", "", "Path to directory where emulator save states (snapshots) are saved. If this is blank, the default value of ${UserConfigPath}/save will be used");
195 ConfigSetDefaultString(g_CoreConfig, "SaveSRAMPath", "", "Path to directory where SRAM/EEPROM data (in-game saves) are stored. If this is blank, the default value of ${UserConfigPath}/save will be used");
196 ConfigSetDefaultString(g_CoreConfig, "SharedDataPath", "", "Path to a directory to search when looking for shared data files");
197 ConfigSetDefaultBool(g_CoreConfig, "DelaySI", 0, "Delay interrupt after DMA SI read/write");
198 ConfigSetDefaultInt(g_CoreConfig, "CountPerOp", 2, "Force number of cycles per emulated instruction");
200 /* handle upgrades */
203 if (fConfigParamsVersion < 1.01f)
204 { // added separate SaveSRAMPath parameter in v1.01
205 const char *pccSaveStatePath = ConfigGetParamString(g_CoreConfig, "SaveStatePath");
206 if (pccSaveStatePath != NULL)
207 ConfigSetParameter(g_CoreConfig, "SaveSRAMPath", M64TYPE_STRING, pccSaveStatePath);
212 ConfigSaveSection("Core");
214 /* set config parameters for keyboard and joystick commands */
215 return event_set_core_defaults();
218 void main_speeddown(int percent)
220 if (l_SpeedFactor - percent > 10) /* 10% minimum speed */
222 l_SpeedFactor -= percent;
223 main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "%s %d%%", "Playback speed:", l_SpeedFactor);
224 audio.setSpeedFactor(l_SpeedFactor);
225 StateChanged(M64CORE_SPEED_FACTOR, l_SpeedFactor);
229 void main_speedup(int percent)
231 if (l_SpeedFactor + percent < 300) /* 300% maximum speed */
233 l_SpeedFactor += percent;
234 main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "%s %d%%", "Playback speed:", l_SpeedFactor);
235 audio.setSpeedFactor(l_SpeedFactor);
236 StateChanged(M64CORE_SPEED_FACTOR, l_SpeedFactor);
240 static void main_speedset(int percent)
242 if (percent < 1 || percent > 1000)
244 DebugMessage(M64MSG_WARNING, "Invalid speed setting %i percent", percent);
247 // disable fast-forward if it's enabled
248 main_set_fastforward(0);
250 l_SpeedFactor = percent;
251 main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "%s %d%%", "Playback speed:", l_SpeedFactor);
252 audio.setSpeedFactor(l_SpeedFactor);
253 StateChanged(M64CORE_SPEED_FACTOR, l_SpeedFactor);
256 void main_set_fastforward(int enable)
258 static int ff_state = 0;
259 static int SavedSpeedFactor = 100;
261 if (enable && !ff_state)
263 ff_state = 1; /* activate fast-forward */
264 SavedSpeedFactor = l_SpeedFactor;
266 audio.setSpeedFactor(l_SpeedFactor);
267 StateChanged(M64CORE_SPEED_FACTOR, l_SpeedFactor);
268 // set fast-forward indicator
269 l_msgFF = osd_new_message(OSD_TOP_RIGHT, "Fast Forward");
270 osd_message_set_static(l_msgFF);
271 osd_message_set_user_managed(l_msgFF);
273 else if (!enable && ff_state)
275 ff_state = 0; /* de-activate fast-forward */
276 l_SpeedFactor = SavedSpeedFactor;
277 audio.setSpeedFactor(l_SpeedFactor);
278 StateChanged(M64CORE_SPEED_FACTOR, l_SpeedFactor);
280 osd_delete_message(l_msgFF);
286 static void main_set_speedlimiter(int enable)
288 l_MainSpeedLimit = enable ? 1 : 0;
291 static int main_is_paused(void)
293 return (g_EmulatorRunning && rompause);
296 void main_toggle_pause(void)
298 if (!g_EmulatorRunning)
303 DebugMessage(M64MSG_STATUS, "Emulation continued.");
306 osd_delete_message(l_msgPause);
309 StateChanged(M64CORE_EMU_STATE, M64EMU_RUNNING);
314 osd_delete_message(l_msgPause);
316 DebugMessage(M64MSG_STATUS, "Emulation paused.");
317 l_msgPause = osd_new_message(OSD_MIDDLE_CENTER, "Paused");
318 osd_message_set_static(l_msgPause);
319 osd_message_set_user_managed(l_msgPause);
320 StateChanged(M64CORE_EMU_STATE, M64EMU_PAUSED);
323 rompause = !rompause;
327 void main_advance_one(void)
331 StateChanged(M64CORE_EMU_STATE, M64EMU_RUNNING);
334 static void main_draw_volume_osd(void)
337 const char *volString;
339 // this calls into the audio plugin
340 volString = audio.volumeGetString();
341 if (volString == NULL)
343 strcpy(msgString, "Volume Not Supported.");
347 sprintf(msgString, "%s: %s", "Volume", volString);
350 // create a new message or update an existing one
351 if (l_msgVol != NULL)
352 osd_update_message(l_msgVol, "%s", msgString);
354 l_msgVol = osd_new_message(OSD_MIDDLE_CENTER, "%s", msgString);
355 osd_message_set_user_managed(l_msgVol);
359 /* this function could be called as a result of a keypress, joystick/button movement,
360 LIRC command, or 'testshots' command-line option timer */
361 void main_take_next_screenshot(void)
363 l_TakeScreenshot = l_CurrentFrame + 1;
366 void main_state_set_slot(int slot)
368 if (slot < 0 || slot > 9)
370 DebugMessage(M64MSG_WARNING, "Invalid savestate slot '%i' in main_state_set_slot(). Using 0", slot);
374 savestates_select_slot(slot);
375 StateChanged(M64CORE_SAVESTATE_SLOT, slot);
378 void main_state_inc_slot(void)
380 savestates_inc_slot();
383 static unsigned char StopRumble[64] = {0x23, 0x01, 0x03, 0xc0, 0x1b, 0x00, 0x00, 0x00,
384 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
385 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
386 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
387 0, 0, 0, 0, 0, 0, 0, 0};
389 void main_state_load(const char *filename)
391 input.controllerCommand(0, StopRumble);
392 input.controllerCommand(1, StopRumble);
393 input.controllerCommand(2, StopRumble);
394 input.controllerCommand(3, StopRumble);
396 if (filename == NULL) // Save to slot
397 savestates_set_job(savestates_job_load, savestates_type_m64p, NULL);
399 savestates_set_job(savestates_job_load, savestates_type_unknown, filename);
402 void main_state_save(int format, const char *filename)
404 if (filename == NULL) // Save to slot
405 savestates_set_job(savestates_job_save, savestates_type_m64p, NULL);
407 savestates_set_job(savestates_job_save, (savestates_type)format, filename);
410 m64p_error main_core_state_query(m64p_core_param param, int *rval)
414 case M64CORE_EMU_STATE:
415 if (!g_EmulatorRunning)
416 *rval = M64EMU_STOPPED;
418 *rval = M64EMU_PAUSED;
420 *rval = M64EMU_RUNNING;
422 case M64CORE_VIDEO_MODE:
423 if (!VidExt_VideoRunning())
424 *rval = M64VIDEO_NONE;
425 else if (VidExt_InFullscreenMode())
426 *rval = M64VIDEO_FULLSCREEN;
428 *rval = M64VIDEO_WINDOWED;
430 case M64CORE_SAVESTATE_SLOT:
431 *rval = savestates_get_slot();
433 case M64CORE_SPEED_FACTOR:
434 *rval = l_SpeedFactor;
436 case M64CORE_SPEED_LIMITER:
437 *rval = l_MainSpeedLimit;
439 case M64CORE_VIDEO_SIZE:
442 if (!g_EmulatorRunning)
443 return M64ERR_INVALID_STATE;
444 main_get_screen_size(&width, &height);
445 *rval = (width << 16) + height;
448 case M64CORE_AUDIO_VOLUME:
450 if (!g_EmulatorRunning)
451 return M64ERR_INVALID_STATE;
452 return main_volume_get_level(rval);
454 case M64CORE_AUDIO_MUTE:
455 *rval = main_volume_get_muted();
457 case M64CORE_INPUT_GAMESHARK:
458 *rval = event_gameshark_active();
460 // these are only used for callbacks; they cannot be queried or set
461 case M64CORE_STATE_LOADCOMPLETE:
462 case M64CORE_STATE_SAVECOMPLETE:
463 return M64ERR_INPUT_INVALID;
465 return M64ERR_INPUT_INVALID;
468 return M64ERR_SUCCESS;
471 m64p_error main_core_state_set(m64p_core_param param, int val)
475 case M64CORE_EMU_STATE:
476 if (!g_EmulatorRunning)
477 return M64ERR_INVALID_STATE;
478 if (val == M64EMU_STOPPED)
480 /* this stop function is asynchronous. The emulator may not terminate until later */
482 return M64ERR_SUCCESS;
484 else if (val == M64EMU_RUNNING)
486 if (main_is_paused())
488 return M64ERR_SUCCESS;
490 else if (val == M64EMU_PAUSED)
492 if (!main_is_paused())
494 return M64ERR_SUCCESS;
496 return M64ERR_INPUT_INVALID;
497 case M64CORE_VIDEO_MODE:
498 if (!g_EmulatorRunning)
499 return M64ERR_INVALID_STATE;
500 if (val == M64VIDEO_WINDOWED)
502 if (VidExt_InFullscreenMode())
504 return M64ERR_SUCCESS;
506 else if (val == M64VIDEO_FULLSCREEN)
508 if (!VidExt_InFullscreenMode())
510 return M64ERR_SUCCESS;
512 return M64ERR_INPUT_INVALID;
513 case M64CORE_SAVESTATE_SLOT:
514 if (val < 0 || val > 9)
515 return M64ERR_INPUT_INVALID;
516 savestates_select_slot(val);
517 return M64ERR_SUCCESS;
518 case M64CORE_SPEED_FACTOR:
519 if (!g_EmulatorRunning)
520 return M64ERR_INVALID_STATE;
522 return M64ERR_SUCCESS;
523 case M64CORE_SPEED_LIMITER:
524 main_set_speedlimiter(val);
525 return M64ERR_SUCCESS;
526 case M64CORE_VIDEO_SIZE:
528 // the front-end app is telling us that the user has resized the video output frame, and so
529 // we should try to update the video plugin accordingly. First, check state
531 if (!g_EmulatorRunning)
532 return M64ERR_INVALID_STATE;
533 width = (val >> 16) & 0xffff;
534 height = val & 0xffff;
535 // then call the video plugin. if the video plugin supports resizing, it will resize its viewport and call
536 // VidExt_ResizeWindow to update the window manager handling our opengl output window
537 gfx.resizeVideoOutput(width, height);
538 return M64ERR_SUCCESS;
540 case M64CORE_AUDIO_VOLUME:
541 if (!g_EmulatorRunning)
542 return M64ERR_INVALID_STATE;
543 if (val < 0 || val > 100)
544 return M64ERR_INPUT_INVALID;
545 return main_volume_set_level(val);
546 case M64CORE_AUDIO_MUTE:
547 if ((main_volume_get_muted() && !val) || (!main_volume_get_muted() && val))
548 return main_volume_mute();
549 return M64ERR_SUCCESS;
550 case M64CORE_INPUT_GAMESHARK:
551 if (!g_EmulatorRunning)
552 return M64ERR_INVALID_STATE;
553 event_set_gameshark(val);
554 return M64ERR_SUCCESS;
555 // these are only used for callbacks; they cannot be queried or set
556 case M64CORE_STATE_LOADCOMPLETE:
557 case M64CORE_STATE_SAVECOMPLETE:
558 return M64ERR_INPUT_INVALID;
560 return M64ERR_INPUT_INVALID;
564 m64p_error main_get_screen_size(int *width, int *height)
566 gfx.readScreen(NULL, width, height, 0);
567 return M64ERR_SUCCESS;
570 m64p_error main_read_screen(void *pixels, int bFront)
572 int width_trash, height_trash;
573 gfx.readScreen(pixels, &width_trash, &height_trash, bFront);
574 return M64ERR_SUCCESS;
577 m64p_error main_volume_up(void)
581 main_draw_volume_osd();
582 main_volume_get_level(&level);
583 StateChanged(M64CORE_AUDIO_VOLUME, level);
584 return M64ERR_SUCCESS;
587 m64p_error main_volume_down(void)
591 main_draw_volume_osd();
592 main_volume_get_level(&level);
593 StateChanged(M64CORE_AUDIO_VOLUME, level);
594 return M64ERR_SUCCESS;
597 m64p_error main_volume_get_level(int *level)
599 *level = audio.volumeGetLevel();
600 return M64ERR_SUCCESS;
603 m64p_error main_volume_set_level(int level)
605 audio.volumeSetLevel(level);
606 main_draw_volume_osd();
607 level = audio.volumeGetLevel();
608 StateChanged(M64CORE_AUDIO_VOLUME, level);
609 return M64ERR_SUCCESS;
612 m64p_error main_volume_mute(void)
615 main_draw_volume_osd();
616 StateChanged(M64CORE_AUDIO_MUTE, main_volume_get_muted());
617 return M64ERR_SUCCESS;
620 int main_volume_get_muted(void)
622 return (audio.volumeGetLevel() == 0);
625 m64p_error main_reset(int do_hard_reset)
631 return M64ERR_SUCCESS;
634 /*********************************************************************************************************
635 * global functions, callbacks from the r4300 core or from other plugins
638 static void video_plugin_render_callback(int bScreenRedrawn)
640 int bOSD = ConfigGetParamBool(g_CoreConfig, "OnScreenDisplay");
642 // if the flag is set to take a screenshot, then grab it now
643 if (l_TakeScreenshot != 0)
645 // if the OSD is enabled, and the screen has not been recently redrawn, then we cannot take a screenshot now because
646 // it contains the OSD text. Wait until the next redraw
647 if (!bOSD || bScreenRedrawn)
649 TakeScreenshot(l_TakeScreenshot - 1); // current frame number +1 is in l_TakeScreenshot
650 l_TakeScreenshot = 0; // reset flag
654 // if the OSD is enabled, then draw it now
663 if (g_FrameCallback != NULL)
664 (*g_FrameCallback)(l_CurrentFrame);
666 /* advance the current frame */
669 if (l_FrameAdvance) {
672 StateChanged(M64CORE_EMU_STATE, M64EMU_PAUSED);
679 unsigned int CurrentFPSTime;
680 static unsigned int LastFPSTime = 0;
681 static unsigned int CounterTime = 0;
682 static unsigned int CalculatedTime ;
683 static int VI_Counter = 0;
685 double VILimitMilliseconds = 1000.0 / ROM_PARAMS.vilimit;
686 double AdjustedLimit = VILimitMilliseconds * 100.0 / l_SpeedFactor; // adjust for selected emulator speed
689 start_section(IDLE_SECTION);
693 if(g_DebuggerActive) DebuggerCallback(DEBUG_UI_VI, 0);
698 LastFPSTime = CounterTime = SDL_GetTicks();
701 CurrentFPSTime = SDL_GetTicks();
703 Dif = CurrentFPSTime - LastFPSTime;
705 if (Dif < AdjustedLimit)
707 CalculatedTime = (unsigned int) (CounterTime + AdjustedLimit * VI_Counter);
708 time = (int)(CalculatedTime - CurrentFPSTime);
709 if (time > 0 && l_MainSpeedLimit)
711 DebugMessage(M64MSG_VERBOSE, " new_vi(): Waiting %ims", time);
714 CurrentFPSTime = CurrentFPSTime + time;
717 if (CurrentFPSTime - CounterTime >= 1000.0 )
719 CounterTime = SDL_GetTicks();
723 LastFPSTime = CurrentFPSTime ;
724 end_section(IDLE_SECTION);
727 /*********************************************************************************************************
728 * emulation thread - runs the core
730 m64p_error main_run(void)
732 /* take the r4300 emulator mode from the config file at this point and cache it in a global variable */
733 r4300emu = ConfigGetParamInt(g_CoreConfig, "R4300Emulator");
735 /* set some other core parameters based on the config file values */
736 savestates_set_autoinc_slot(ConfigGetParamBool(g_CoreConfig, "AutoStateSlotIncrement"));
737 savestates_select_slot(ConfigGetParamInt(g_CoreConfig, "CurrentStateSlot"));
738 no_compiled_jump = ConfigGetParamBool(g_CoreConfig, "NoCompiledJump");
739 if (delay_si==-1) delay_si = ConfigGetParamBool(g_CoreConfig, "DelaySI");
740 if (count_per_op==-1) count_per_op = ConfigGetParamInt(g_CoreConfig, "CountPerOp");
741 if (count_per_op <= 0)
744 // initialize memory, and do byte-swapping if it's not been done yet
745 if (g_MemHasBeenBSwapped == 0)
748 g_MemHasBeenBSwapped = 1;
754 // Attach rom to plugins
757 free_memory(); return M64ERR_PLUGIN_FAIL;
759 if (!audio.romOpen())
761 gfx.romClosed(); free_memory(); return M64ERR_PLUGIN_FAIL;
763 if (!input.romOpen())
765 audio.romClosed(); gfx.romClosed(); free_memory(); return M64ERR_PLUGIN_FAIL;
769 /* set up the SDL key repeat and event filter to catch keyboard/joystick commands for the core */
772 /* initialize the on-screen display */
773 if (ConfigGetParamBool(g_CoreConfig, "OnScreenDisplay"))
775 // init on-screen display
776 int width = 640, height = 480;
777 gfx.readScreen(NULL, &width, &height, 0); // read screen to get width and height
778 osd_init(width, height);
781 // setup rendering callback from video plugin to the core, for screenshots and On-Screen-Display
782 gfx.setRenderingCallback(video_plugin_render_callback);
789 if (ConfigGetParamBool(g_CoreConfig, "EnableDebugger"))
792 /* Startup message on the OSD */
793 osd_new_message(OSD_MIDDLE_CENTER, "Mupen64Plus Started...");
794 g_EmulatorRunning = 1;
795 StateChanged(M64CORE_EMU_STATE, M64EMU_RUNNING);
796 /* call r4300 CPU core and run the game */
801 /* now begin to shut down */
807 if (g_DebuggerActive)
811 if (ConfigGetParamBool(g_CoreConfig, "OnScreenDisplay"))
823 g_EmulatorRunning = 0;
824 StateChanged(M64CORE_EMU_STATE, M64EMU_STOPPED);
826 return M64ERR_SUCCESS;
831 /* note: this operation is asynchronous. It may be called from a thread other than the
832 main emulator thread, and may return before the emulator is completely stopped */
833 if (!g_EmulatorRunning)
836 DebugMessage(M64MSG_STATUS, "Stopping emulation.");
839 osd_delete_message(l_msgPause);
844 osd_delete_message(l_msgFF);
849 osd_delete_message(l_msgVol);
855 StateChanged(M64CORE_EMU_STATE, M64EMU_RUNNING);