ALL: Huge upstream synch + PerRom DelaySI & CountPerOp parameters
[mupen64plus-pandora.git] / source / mupen64plus-core / src / main / main.c
CommitLineData
451ab91e 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 *
8 * *
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. *
13 * *
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. *
18 * *
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 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
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
29 */
30
31#include <string.h>
32#include <stdlib.h>
33
34#include <SDL.h>
35
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"
43
44#include "main.h"
45#include "eventloop.h"
46#include "rom.h"
47#include "savestates.h"
48#include "util.h"
49
50#include "memory/memory.h"
51#include "osal/files.h"
52#include "osal/preproc.h"
53#include "osd/osd.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"
59
60#ifdef DBG
61#include "debugger/dbg_types.h"
62#include "debugger/debugger.h"
63#endif
64
65#ifdef WITH_LIRC
66#include "lirc.h"
67#endif //WITH_LIRC
68
69/* version number for Core config section */
70#define CONFIG_PARAM_VERSION 1.01
71
72/** globals **/
73m64p_handle g_CoreConfig = NULL;
74
75m64p_frame_callback g_FrameCallback = NULL;
76
77int g_MemHasBeenBSwapped = 0; // store byte-swapped flag so we don't swap twice when re-playing game
78int g_EmulatorRunning = 0; // need separate boolean to tell if emulator is running, since --nogui doesn't use a thread
79
80/** static (local) variables **/
81static int l_CurrentFrame = 0; // frame counter
82static int l_TakeScreenshot = 0; // Tell OSD Rendering callback to take a screenshot just before drawing the OSD
83static int l_SpeedFactor = 100; // percentage of nominal game speed at which emulator is running
84static int l_FrameAdvance = 0; // variable to check if we pause on next frame
85static int l_MainSpeedLimit = 1; // insert delay during vi_interrupt to keep speed at real-time
86
87static osd_message_t *l_msgVol = NULL;
88static osd_message_t *l_msgFF = NULL;
89static osd_message_t *l_msgPause = NULL;
90
91/*********************************************************************************************************
92* static functions
93*/
94
95static const char *get_savepathdefault(const char *configpath)
96{
97 static char path[1024];
98
99 if (!configpath || (strlen(configpath) == 0)) {
100 snprintf(path, 1024, "%ssave%c", ConfigGetUserDataPath(), OSAL_DIR_SEPARATORS[0]);
101 path[1023] = 0;
102 } else {
103 snprintf(path, 1024, "%s%c", configpath, OSAL_DIR_SEPARATORS[0]);
104 path[1023] = 0;
105 }
106
107 /* create directory if it doesn't exist */
108 osal_mkdirp(path, 0700);
109
110 return path;
111}
112
113
114/*********************************************************************************************************
115* helper functions
116*/
117
118
119const char *get_savestatepath(void)
120{
121 /* try to get the SaveStatePath string variable in the Core configuration section */
122 return get_savepathdefault(ConfigGetParamString(g_CoreConfig, "SaveStatePath"));
123}
124
125const char *get_savesrampath(void)
126{
127 /* try to get the SaveSRAMPath string variable in the Core configuration section */
128 return get_savepathdefault(ConfigGetParamString(g_CoreConfig, "SaveSRAMPath"));
129}
130
131void main_message(m64p_msg_level level, unsigned int corner, const char *format, ...)
132{
133 va_list ap;
134 char buffer[2049];
135 va_start(ap, format);
136 vsnprintf(buffer, 2047, format, ap);
137 buffer[2048]='\0';
138 va_end(ap);
139
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);
145}
146
147
148/*********************************************************************************************************
149* global functions, for adjusting the core emulator behavior
150*/
151
152int main_set_core_defaults(void)
153{
154 float fConfigParamsVersion;
155 int bSaveConfig = 0, bUpgrade = 0;
156
157 if (ConfigGetParameter(g_CoreConfig, "Version", M64TYPE_FLOAT, &fConfigParamsVersion, sizeof(float)) != M64ERR_SUCCESS)
158 {
159 DebugMessage(M64MSG_WARNING, "No version number in 'Core' config section. Setting defaults.");
160 ConfigDeleteSection("Core");
161 ConfigOpenSection("Core", &g_CoreConfig);
162 bSaveConfig = 1;
163 }
164 else if (((int) fConfigParamsVersion) != ((int) CONFIG_PARAM_VERSION))
165 {
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);
169 bSaveConfig = 1;
170 }
171 else if ((CONFIG_PARAM_VERSION - fConfigParamsVersion) >= 0.0001f)
172 {
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);
176 bUpgrade = 1;
177 bSaveConfig = 1;
178 }
179
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");
183#if defined(DYNAREC)
184 ConfigSetDefaultInt(g_CoreConfig, "R4300Emulator", 2, "Use Pure Interpreter if 0, Cached Interpreter if 1, or Dynamic Recompiler if 2 or more");
185#else
186 ConfigSetDefaultInt(g_CoreConfig, "R4300Emulator", 1, "Use Pure Interpreter if 0, Cached Interpreter if 1, or Dynamic Recompiler if 2 or more");
187#endif
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");
2d262872 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");
451ab91e 199
200 /* handle upgrades */
201 if (bUpgrade)
202 {
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);
208 }
209 }
210
211 if (bSaveConfig)
212 ConfigSaveSection("Core");
213
214 /* set config parameters for keyboard and joystick commands */
215 return event_set_core_defaults();
216}
217
218void main_speeddown(int percent)
219{
220 if (l_SpeedFactor - percent > 10) /* 10% minimum speed */
221 {
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);
226 }
227}
228
229void main_speedup(int percent)
230{
231 if (l_SpeedFactor + percent < 300) /* 300% maximum speed */
232 {
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);
237 }
238}
239
240static void main_speedset(int percent)
241{
242 if (percent < 1 || percent > 1000)
243 {
244 DebugMessage(M64MSG_WARNING, "Invalid speed setting %i percent", percent);
245 return;
246 }
247 // disable fast-forward if it's enabled
248 main_set_fastforward(0);
249 // set speed
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);
254}
255
256void main_set_fastforward(int enable)
257{
258 static int ff_state = 0;
259 static int SavedSpeedFactor = 100;
260
261 if (enable && !ff_state)
262 {
263 ff_state = 1; /* activate fast-forward */
264 SavedSpeedFactor = l_SpeedFactor;
265 l_SpeedFactor = 250;
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);
272 }
273 else if (!enable && ff_state)
274 {
275 ff_state = 0; /* de-activate fast-forward */
276 l_SpeedFactor = SavedSpeedFactor;
277 audio.setSpeedFactor(l_SpeedFactor);
278 StateChanged(M64CORE_SPEED_FACTOR, l_SpeedFactor);
279 // remove message
280 osd_delete_message(l_msgFF);
281 l_msgFF = NULL;
282 }
283
284}
285
286static void main_set_speedlimiter(int enable)
287{
288 l_MainSpeedLimit = enable ? 1 : 0;
289}
290
291static int main_is_paused(void)
292{
293 return (g_EmulatorRunning && rompause);
294}
295
296void main_toggle_pause(void)
297{
298 if (!g_EmulatorRunning)
299 return;
300
301 if (rompause)
302 {
303 DebugMessage(M64MSG_STATUS, "Emulation continued.");
304 if(l_msgPause)
305 {
306 osd_delete_message(l_msgPause);
307 l_msgPause = NULL;
308 }
309 StateChanged(M64CORE_EMU_STATE, M64EMU_RUNNING);
310 }
311 else
312 {
313 if(l_msgPause)
314 osd_delete_message(l_msgPause);
315
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);
321 }
322
323 rompause = !rompause;
324 l_FrameAdvance = 0;
325}
326
327void main_advance_one(void)
328{
329 l_FrameAdvance = 1;
330 rompause = 0;
331 StateChanged(M64CORE_EMU_STATE, M64EMU_RUNNING);
332}
333
334static void main_draw_volume_osd(void)
335{
336 char msgString[64];
337 const char *volString;
338
339 // this calls into the audio plugin
340 volString = audio.volumeGetString();
341 if (volString == NULL)
342 {
343 strcpy(msgString, "Volume Not Supported.");
344 }
345 else
346 {
347 sprintf(msgString, "%s: %s", "Volume", volString);
348 }
349
350 // create a new message or update an existing one
351 if (l_msgVol != NULL)
352 osd_update_message(l_msgVol, "%s", msgString);
353 else {
354 l_msgVol = osd_new_message(OSD_MIDDLE_CENTER, "%s", msgString);
355 osd_message_set_user_managed(l_msgVol);
356 }
357}
358
359/* this function could be called as a result of a keypress, joystick/button movement,
360 LIRC command, or 'testshots' command-line option timer */
361void main_take_next_screenshot(void)
362{
363 l_TakeScreenshot = l_CurrentFrame + 1;
364}
365
366void main_state_set_slot(int slot)
367{
368 if (slot < 0 || slot > 9)
369 {
370 DebugMessage(M64MSG_WARNING, "Invalid savestate slot '%i' in main_state_set_slot(). Using 0", slot);
371 slot = 0;
372 }
373
374 savestates_select_slot(slot);
375 StateChanged(M64CORE_SAVESTATE_SLOT, slot);
376}
377
378void main_state_inc_slot(void)
379{
380 savestates_inc_slot();
381}
382
383static 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};
388
389void main_state_load(const char *filename)
390{
391 input.controllerCommand(0, StopRumble);
392 input.controllerCommand(1, StopRumble);
393 input.controllerCommand(2, StopRumble);
394 input.controllerCommand(3, StopRumble);
395
396 if (filename == NULL) // Save to slot
397 savestates_set_job(savestates_job_load, savestates_type_m64p, NULL);
398 else
399 savestates_set_job(savestates_job_load, savestates_type_unknown, filename);
400}
401
402void main_state_save(int format, const char *filename)
403{
404 if (filename == NULL) // Save to slot
405 savestates_set_job(savestates_job_save, savestates_type_m64p, NULL);
406 else // Save to file
407 savestates_set_job(savestates_job_save, (savestates_type)format, filename);
408}
409
410m64p_error main_core_state_query(m64p_core_param param, int *rval)
411{
412 switch (param)
413 {
414 case M64CORE_EMU_STATE:
415 if (!g_EmulatorRunning)
416 *rval = M64EMU_STOPPED;
417 else if (rompause)
418 *rval = M64EMU_PAUSED;
419 else
420 *rval = M64EMU_RUNNING;
421 break;
422 case M64CORE_VIDEO_MODE:
423 if (!VidExt_VideoRunning())
424 *rval = M64VIDEO_NONE;
425 else if (VidExt_InFullscreenMode())
426 *rval = M64VIDEO_FULLSCREEN;
427 else
428 *rval = M64VIDEO_WINDOWED;
429 break;
430 case M64CORE_SAVESTATE_SLOT:
431 *rval = savestates_get_slot();
432 break;
433 case M64CORE_SPEED_FACTOR:
434 *rval = l_SpeedFactor;
435 break;
436 case M64CORE_SPEED_LIMITER:
437 *rval = l_MainSpeedLimit;
438 break;
439 case M64CORE_VIDEO_SIZE:
440 {
441 int width, height;
442 if (!g_EmulatorRunning)
443 return M64ERR_INVALID_STATE;
444 main_get_screen_size(&width, &height);
445 *rval = (width << 16) + height;
446 break;
447 }
448 case M64CORE_AUDIO_VOLUME:
449 {
450 if (!g_EmulatorRunning)
451 return M64ERR_INVALID_STATE;
452 return main_volume_get_level(rval);
453 }
454 case M64CORE_AUDIO_MUTE:
455 *rval = main_volume_get_muted();
456 break;
457 case M64CORE_INPUT_GAMESHARK:
458 *rval = event_gameshark_active();
459 break;
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;
464 default:
465 return M64ERR_INPUT_INVALID;
466 }
467
468 return M64ERR_SUCCESS;
469}
470
471m64p_error main_core_state_set(m64p_core_param param, int val)
472{
473 switch (param)
474 {
475 case M64CORE_EMU_STATE:
476 if (!g_EmulatorRunning)
477 return M64ERR_INVALID_STATE;
478 if (val == M64EMU_STOPPED)
479 {
480 /* this stop function is asynchronous. The emulator may not terminate until later */
481 main_stop();
482 return M64ERR_SUCCESS;
483 }
484 else if (val == M64EMU_RUNNING)
485 {
486 if (main_is_paused())
487 main_toggle_pause();
488 return M64ERR_SUCCESS;
489 }
490 else if (val == M64EMU_PAUSED)
491 {
492 if (!main_is_paused())
493 main_toggle_pause();
494 return M64ERR_SUCCESS;
495 }
496 return M64ERR_INPUT_INVALID;
497 case M64CORE_VIDEO_MODE:
498 if (!g_EmulatorRunning)
499 return M64ERR_INVALID_STATE;
500 if (val == M64VIDEO_WINDOWED)
501 {
502 if (VidExt_InFullscreenMode())
503 gfx.changeWindow();
504 return M64ERR_SUCCESS;
505 }
506 else if (val == M64VIDEO_FULLSCREEN)
507 {
508 if (!VidExt_InFullscreenMode())
509 gfx.changeWindow();
510 return M64ERR_SUCCESS;
511 }
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;
521 main_speedset(val);
522 return M64ERR_SUCCESS;
523 case M64CORE_SPEED_LIMITER:
524 main_set_speedlimiter(val);
525 return M64ERR_SUCCESS;
526 case M64CORE_VIDEO_SIZE:
527 {
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
530 int width, height;
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;
539 }
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;
559 default:
560 return M64ERR_INPUT_INVALID;
561 }
562}
563
564m64p_error main_get_screen_size(int *width, int *height)
565{
566 gfx.readScreen(NULL, width, height, 0);
567 return M64ERR_SUCCESS;
568}
569
570m64p_error main_read_screen(void *pixels, int bFront)
571{
572 int width_trash, height_trash;
573 gfx.readScreen(pixels, &width_trash, &height_trash, bFront);
574 return M64ERR_SUCCESS;
575}
576
577m64p_error main_volume_up(void)
578{
579 int level = 0;
580 audio.volumeUp();
581 main_draw_volume_osd();
582 main_volume_get_level(&level);
583 StateChanged(M64CORE_AUDIO_VOLUME, level);
584 return M64ERR_SUCCESS;
585}
586
587m64p_error main_volume_down(void)
588{
589 int level = 0;
590 audio.volumeDown();
591 main_draw_volume_osd();
592 main_volume_get_level(&level);
593 StateChanged(M64CORE_AUDIO_VOLUME, level);
594 return M64ERR_SUCCESS;
595}
596
597m64p_error main_volume_get_level(int *level)
598{
599 *level = audio.volumeGetLevel();
600 return M64ERR_SUCCESS;
601}
602
603m64p_error main_volume_set_level(int level)
604{
605 audio.volumeSetLevel(level);
606 main_draw_volume_osd();
607 level = audio.volumeGetLevel();
608 StateChanged(M64CORE_AUDIO_VOLUME, level);
609 return M64ERR_SUCCESS;
610}
611
612m64p_error main_volume_mute(void)
613{
614 audio.volumeMute();
615 main_draw_volume_osd();
616 StateChanged(M64CORE_AUDIO_MUTE, main_volume_get_muted());
617 return M64ERR_SUCCESS;
618}
619
620int main_volume_get_muted(void)
621{
622 return (audio.volumeGetLevel() == 0);
623}
624
625m64p_error main_reset(int do_hard_reset)
626{
627 if (do_hard_reset)
628 reset_hard_job |= 1;
629 else
630 reset_soft();
631 return M64ERR_SUCCESS;
632}
633
634/*********************************************************************************************************
635* global functions, callbacks from the r4300 core or from other plugins
636*/
637
638static void video_plugin_render_callback(int bScreenRedrawn)
639{
640 int bOSD = ConfigGetParamBool(g_CoreConfig, "OnScreenDisplay");
641
642 // if the flag is set to take a screenshot, then grab it now
643 if (l_TakeScreenshot != 0)
644 {
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)
648 {
649 TakeScreenshot(l_TakeScreenshot - 1); // current frame number +1 is in l_TakeScreenshot
650 l_TakeScreenshot = 0; // reset flag
651 }
652 }
653
654 // if the OSD is enabled, then draw it now
655 if (bOSD)
656 {
657 osd_render();
658 }
659}
660
661void new_frame(void)
662{
663 if (g_FrameCallback != NULL)
664 (*g_FrameCallback)(l_CurrentFrame);
665
666 /* advance the current frame */
667 l_CurrentFrame++;
668
669 if (l_FrameAdvance) {
670 rompause = 1;
671 l_FrameAdvance = 0;
672 StateChanged(M64CORE_EMU_STATE, M64EMU_PAUSED);
673 }
674}
675
676void new_vi(void)
677{
678 int Dif;
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;
684
685 double VILimitMilliseconds = 1000.0 / ROM_PARAMS.vilimit;
686 double AdjustedLimit = VILimitMilliseconds * 100.0 / l_SpeedFactor; // adjust for selected emulator speed
687 int time;
688
689 start_section(IDLE_SECTION);
690 VI_Counter++;
691
692#ifdef DBG
693 if(g_DebuggerActive) DebuggerCallback(DEBUG_UI_VI, 0);
694#endif
695
696 if(LastFPSTime == 0)
697 {
698 LastFPSTime = CounterTime = SDL_GetTicks();
699 return;
700 }
701 CurrentFPSTime = SDL_GetTicks();
702
703 Dif = CurrentFPSTime - LastFPSTime;
704
705 if (Dif < AdjustedLimit)
706 {
707 CalculatedTime = (unsigned int) (CounterTime + AdjustedLimit * VI_Counter);
708 time = (int)(CalculatedTime - CurrentFPSTime);
709 if (time > 0 && l_MainSpeedLimit)
710 {
711 DebugMessage(M64MSG_VERBOSE, " new_vi(): Waiting %ims", time);
712 SDL_Delay(time);
713 }
714 CurrentFPSTime = CurrentFPSTime + time;
715 }
716
717 if (CurrentFPSTime - CounterTime >= 1000.0 )
718 {
719 CounterTime = SDL_GetTicks();
720 VI_Counter = 0 ;
721 }
722
723 LastFPSTime = CurrentFPSTime ;
724 end_section(IDLE_SECTION);
725}
726
727/*********************************************************************************************************
728* emulation thread - runs the core
729*/
730m64p_error main_run(void)
731{
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");
734
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");
2d262872 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)
742 count_per_op = 2;
451ab91e 743
2d262872 744 // initialize memory, and do byte-swapping if it's not been done yet
451ab91e 745 if (g_MemHasBeenBSwapped == 0)
746 {
747 init_memory(1);
748 g_MemHasBeenBSwapped = 1;
749 }
750 else
751 {
752 init_memory(0);
753 }
754 // Attach rom to plugins
755 if (!gfx.romOpen())
756 {
757 free_memory(); return M64ERR_PLUGIN_FAIL;
758 }
759 if (!audio.romOpen())
760 {
761 gfx.romClosed(); free_memory(); return M64ERR_PLUGIN_FAIL;
762 }
763 if (!input.romOpen())
764 {
765 audio.romClosed(); gfx.romClosed(); free_memory(); return M64ERR_PLUGIN_FAIL;
766 }
767
768
769 /* set up the SDL key repeat and event filter to catch keyboard/joystick commands for the core */
770 event_initialize();
771
772 /* initialize the on-screen display */
773 if (ConfigGetParamBool(g_CoreConfig, "OnScreenDisplay"))
774 {
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);
779 }
780
781 // setup rendering callback from video plugin to the core, for screenshots and On-Screen-Display
782 gfx.setRenderingCallback(video_plugin_render_callback);
783
784#ifdef WITH_LIRC
785 lircStart();
786#endif // WITH_LIRC
787
788#ifdef DBG
789 if (ConfigGetParamBool(g_CoreConfig, "EnableDebugger"))
790 init_debugger();
791#endif
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 */
797 r4300_reset_hard();
798 r4300_reset_soft();
799 r4300_execute();
800
801 /* now begin to shut down */
802#ifdef WITH_LIRC
803 lircStop();
804#endif // WITH_LIRC
805
806#ifdef DBG
807 if (g_DebuggerActive)
808 destroy_debugger();
809#endif
810
811 if (ConfigGetParamBool(g_CoreConfig, "OnScreenDisplay"))
812 {
813 osd_exit();
814 }
815
816 rsp.romClosed();
817 input.romClosed();
818 audio.romClosed();
819 gfx.romClosed();
820 free_memory();
821
822 // clean up
823 g_EmulatorRunning = 0;
824 StateChanged(M64CORE_EMU_STATE, M64EMU_STOPPED);
825
826 return M64ERR_SUCCESS;
827}
828
829void main_stop(void)
830{
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)
834 return;
835
836 DebugMessage(M64MSG_STATUS, "Stopping emulation.");
837 if(l_msgPause)
838 {
839 osd_delete_message(l_msgPause);
840 l_msgPause = NULL;
841 }
842 if(l_msgFF)
843 {
844 osd_delete_message(l_msgFF);
845 l_msgFF = NULL;
846 }
847 if(l_msgVol)
848 {
849 osd_delete_message(l_msgVol);
850 l_msgVol = NULL;
851 }
852 if (rompause)
853 {
854 rompause = 0;
855 StateChanged(M64CORE_EMU_STATE, M64EMU_RUNNING);
856 }
857 stop = 1;
858#ifdef DBG
859 if(g_DebuggerActive)
860 {
861 debugger_step();
862 }
863#endif
864}