1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Mupen64plus - main.c *
3 * Mupen64Plus homepage: https://mupen64plus.org/ *
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 <SDL.h>
32#include <assert.h>
33#include <stdarg.h>
34#include <stddef.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38
39#define M64P_CORE_PROTOTYPES 1
40#include "api/callbacks.h"
41#include "api/config.h"
42#include "api/debugger.h"
43#include "api/m64p_config.h"
44#include "api/m64p_types.h"
45#include "api/m64p_vidext.h"
46#include "api/vidext.h"
47#include "backends/api/audio_out_backend.h"
48#include "backends/api/clock_backend.h"
49#include "backends/api/controller_input_backend.h"
50#include "backends/api/joybus.h"
51#include "backends/api/rumble_backend.h"
52#include "backends/api/storage_backend.h"
53#include "backends/api/video_capture_backend.h"
54#include "backends/plugins_compat/plugins_compat.h"
55#include "backends/clock_ctime_plus_delta.h"
56#include "backends/file_storage.h"
57#include "cheat.h"
58#include "device/device.h"
59#include "device/controllers/paks/biopak.h"
60#include "device/controllers/paks/mempak.h"
61#include "device/controllers/paks/rumblepak.h"
62#include "device/controllers/paks/transferpak.h"
63#include "device/gb/gb_cart.h"
64#include "device/pif/bootrom_hle.h"
65#include "eventloop.h"
66#include "main.h"
67#include "cheat.h"
68#include "osal/files.h"
69#include "osal/preproc.h"
70#include "osd/osd.h"
71#include "plugin/plugin.h"
72#if defined(PROFILE)
73#include "profile.h"
74#endif
75#include "rom.h"
76#include "savestates.h"
77#include "screenshot.h"
78#include "util.h"
79
80#ifdef DBG
81#include "debugger/dbg_debugger.h"
82#endif
83
84#ifdef WITH_LIRC
85#include "lirc.h"
86#endif //WITH_LIRC
87
88/* version number for Core config section */
89#define CONFIG_PARAM_VERSION 1.01
90
91/** globals **/
92m64p_handle g_CoreConfig = NULL;
93
94m64p_frame_callback g_FrameCallback = NULL;
95
96int g_RomWordsLittleEndian = 0; // after loading, ROM words are in native N64 byte order (big endian). We will swap them on x86
97int g_EmulatorRunning = 0; // need separate boolean to tell if emulator is running, since --nogui doesn't use a thread
98
99
100int g_rom_pause;
101
102struct cheat_ctx g_cheat_ctx;
103
104/* g_mem_base is global to allow plugins early access (before device is initialized).
105 * Do not use this variable directly in emulation code.
106 * Initialization and DeInitialization of this variable is done at CoreStartup and CoreShutdown.
107 */
108void* g_mem_base = NULL;
109
110struct device g_dev;
111
112m64p_media_loader g_media_loader;
113
114int g_gs_vi_counter = 0;
115
116/** static (local) variables **/
117static int l_CurrentFrame = 0; // frame counter
118static int l_TakeScreenshot = 0; // Tell OSD Rendering callback to take a screenshot just before drawing the OSD
119static int l_SpeedFactor = 100; // percentage of nominal game speed at which emulator is running
120static int l_FrameAdvance = 0; // variable to check if we pause on next frame
121static int l_MainSpeedLimit = 1; // insert delay during vi_interrupt to keep speed at real-time
122
123static osd_message_t *l_msgVol = NULL;
124static osd_message_t *l_msgFF = NULL;
125static osd_message_t *l_msgPause = NULL;
126
127/* compatible paks */
128enum { PAK_MAX_SIZE = 5 };
129static size_t l_paks_idx[GAME_CONTROLLERS_COUNT];
130static void* l_paks[GAME_CONTROLLERS_COUNT][PAK_MAX_SIZE];
131static const struct pak_interface* l_ipaks[PAK_MAX_SIZE];
132static size_t l_pak_type_idx[6];
133
134/*********************************************************************************************************
135* static functions
136*/
137
138static const char *get_savepathdefault(const char *configpath)
139{
140 static char path[1024];
141
142 if (!configpath || (strlen(configpath) == 0)) {
143 snprintf(path, 1024, "%ssave%c", ConfigGetUserDataPath(), OSAL_DIR_SEPARATORS[0]);
144 path[1023] = 0;
145 } else {
146 snprintf(path, 1024, "%s%c", configpath, OSAL_DIR_SEPARATORS[0]);
147 path[1023] = 0;
148 }
149
150 /* create directory if it doesn't exist */
151 osal_mkdirp(path, 0700);
152
153 return path;
154}
155
156static char *get_mempaks_path(void)
157{
158 return formatstr("%s%s.mpk", get_savesrampath(), ROM_SETTINGS.goodname);
159}
160
161static char *get_eeprom_path(void)
162{
163 return formatstr("%s%s.eep", get_savesrampath(), ROM_SETTINGS.goodname);
164}
165
166static char *get_sram_path(void)
167{
168 return formatstr("%s%s.sra", get_savesrampath(), ROM_SETTINGS.goodname);
169}
170
171static char *get_flashram_path(void)
172{
173 return formatstr("%s%s.fla", get_savesrampath(), ROM_SETTINGS.goodname);
174}
175
176static char *get_gb_ram_path(const char* gbrom, unsigned int control_id)
177{
178 return formatstr("%s%s.%u.sav", get_savesrampath(), gbrom, control_id);
179}
180
181static m64p_error init_video_capture_backend(const struct video_capture_backend_interface** ivcap, void** vcap, m64p_handle config, const char* key)
182{
183 m64p_error err;
184
185 const char* name = ConfigGetParamString(config, key);
186 if (name == NULL) {
187 DebugMessage(M64MSG_WARNING, "Couldn't get %s value. Using NULL value instead.", key);
188 }
189
190 /* try to find desired backend (by name) */
191 *ivcap = get_video_capture_backend(name);
192
193 /* handle not found case */
194 if (*ivcap == NULL) {
195 /* default to dummy backend */
196 *ivcap = get_video_capture_backend(NULL);
197
198 DebugMessage(M64MSG_WARNING, "Could not find %s video_capture_backend_interface. Using %s instead.",
199 name, (*ivcap)->name);
200 }
201
202 /* build section name */
203 char* section = formatstr("%s:%s", key, (*ivcap)->name);
204
205 /* init backend */
206 err = (*ivcap)->init(vcap, section);
207
208 if (err == M64ERR_SUCCESS) {
209 DebugMessage(M64MSG_INFO, "Using video capture backend: %s", (*ivcap)->name);
210 }
211 else {
212 DebugMessage(M64MSG_ERROR, "Failed to initialize video capture backend %s: %s", (*ivcap)->name, CoreErrorMessage(err));
213 *ivcap = NULL;
214 }
215
216 free(section);
217
218 return err;
219}
220
221/*********************************************************************************************************
222* helper functions
223*/
224
225
226const char *get_savestatepath(void)
227{
228 /* try to get the SaveStatePath string variable in the Core configuration section */
229 return get_savepathdefault(ConfigGetParamString(g_CoreConfig, "SaveStatePath"));
230}
231
232const char *get_savesrampath(void)
233{
234 /* try to get the SaveSRAMPath string variable in the Core configuration section */
235 return get_savepathdefault(ConfigGetParamString(g_CoreConfig, "SaveSRAMPath"));
236}
237
238void main_message(m64p_msg_level level, unsigned int corner, const char *format, ...)
239{
240 va_list ap;
241 char buffer[2049];
242 va_start(ap, format);
243 vsnprintf(buffer, 2047, format, ap);
244 buffer[2048]='\0';
245 va_end(ap);
246
247 /* send message to on-screen-display if enabled */
248 if (ConfigGetParamBool(g_CoreConfig, "OnScreenDisplay"))
249 osd_new_message((enum osd_corner) corner, "%s", buffer);
250 /* send message to front-end */
251 DebugMessage(level, "%s", buffer);
252}
253
254static void main_check_inputs(void)
255{
256#ifdef WITH_LIRC
257 lircCheckInput();
258#endif
259}
260
261/*********************************************************************************************************
262* global functions, for adjusting the core emulator behavior
263*/
264
265int main_set_core_defaults(void)
266{
267 float fConfigParamsVersion;
268 int bUpgrade = 0;
269
270 if (ConfigGetParameter(g_CoreConfig, "Version", M64TYPE_FLOAT, &fConfigParamsVersion, sizeof(float)) != M64ERR_SUCCESS)
271 {
272 DebugMessage(M64MSG_WARNING, "No version number in 'Core' config section. Setting defaults.");
273 ConfigDeleteSection("Core");
274 ConfigOpenSection("Core", &g_CoreConfig);
275 }
276 else if (((int) fConfigParamsVersion) != ((int) CONFIG_PARAM_VERSION))
277 {
278 DebugMessage(M64MSG_WARNING, "Incompatible version %.2f in 'Core' config section: current is %.2f. Setting defaults.", fConfigParamsVersion, (float) CONFIG_PARAM_VERSION);
279 ConfigDeleteSection("Core");
280 ConfigOpenSection("Core", &g_CoreConfig);
281 }
282 else if ((CONFIG_PARAM_VERSION - fConfigParamsVersion) >= 0.0001f)
283 {
284 float fVersion = (float) CONFIG_PARAM_VERSION;
285 ConfigSetParameter(g_CoreConfig, "Version", M64TYPE_FLOAT, &fVersion);
286 DebugMessage(M64MSG_INFO, "Updating parameter set version in 'Core' config section to %.2f", fVersion);
287 bUpgrade = 1;
288 }
289
290 /* parameters controlling the operation of the core */
291 ConfigSetDefaultFloat(g_CoreConfig, "Version", (float) CONFIG_PARAM_VERSION, "Mupen64Plus Core config parameter set version number. Please don't change this version number.");
292 ConfigSetDefaultBool(g_CoreConfig, "OnScreenDisplay", 1, "Draw on-screen display if True, otherwise don't draw OSD");
293#if defined(DYNAREC)
294 ConfigSetDefaultInt(g_CoreConfig, "R4300Emulator", 2, "Use Pure Interpreter if 0, Cached Interpreter if 1, or Dynamic Recompiler if 2 or more");
295#else
296 ConfigSetDefaultInt(g_CoreConfig, "R4300Emulator", 1, "Use Pure Interpreter if 0, Cached Interpreter if 1, or Dynamic Recompiler if 2 or more");
297#endif
298 ConfigSetDefaultBool(g_CoreConfig, "NoCompiledJump", 0, "Disable compiled jump commands in dynamic recompiler (should be set to False) ");
299 ConfigSetDefaultBool(g_CoreConfig, "DisableExtraMem", 0, "Disable 4MB expansion RAM pack. May be necessary for some games");
300 ConfigSetDefaultBool(g_CoreConfig, "AutoStateSlotIncrement", 0, "Increment the save state slot after each save operation");
301 ConfigSetDefaultBool(g_CoreConfig, "EnableDebugger", 0, "Activate the R4300 debugger when ROM execution begins, if core was built with Debugger support");
302 ConfigSetDefaultInt(g_CoreConfig, "CurrentStateSlot", 0, "Save state slot (0-9) to use when saving/loading the emulator state");
303 ConfigSetDefaultString(g_CoreConfig, "ScreenshotPath", "", "Path to directory where screenshots are saved. If this is blank, the default value of ${UserDataPath}/screenshot will be used");
304 ConfigSetDefaultString(g_CoreConfig, "SaveStatePath", "", "Path to directory where emulator save states (snapshots) are saved. If this is blank, the default value of ${UserDataPath}/save will be used");
305 ConfigSetDefaultString(g_CoreConfig, "SaveSRAMPath", "", "Path to directory where SRAM/EEPROM data (in-game saves) are stored. If this is blank, the default value of ${UserDataPath}/save will be used");
306 ConfigSetDefaultString(g_CoreConfig, "SharedDataPath", "", "Path to a directory to search when looking for shared data files");
307 ConfigSetDefaultInt(g_CoreConfig, "CountPerOp", 0, "Force number of cycles per emulated instruction");
308 ConfigSetDefaultBool(g_CoreConfig, "RandomizeInterrupt", 1, "Randomize PI/SI Interrupt Timing");
309 ConfigSetDefaultInt(g_CoreConfig, "SiDmaDuration", -1, "Duration of SI DMA (-1: use per game settings)");
310 ConfigSetDefaultString(g_CoreConfig, "GbCameraVideoCaptureBackend1", DEFAULT_VIDEO_CAPTURE_BACKEND, "Gameboy Camera Video Capture backend");
311
312 /* handle upgrades */
313 if (bUpgrade)
314 {
315 if (fConfigParamsVersion < 1.01f)
316 { // added separate SaveSRAMPath parameter in v1.01
317 const char *pccSaveStatePath = ConfigGetParamString(g_CoreConfig, "SaveStatePath");
318 if (pccSaveStatePath != NULL)
319 ConfigSetParameter(g_CoreConfig, "SaveSRAMPath", M64TYPE_STRING, pccSaveStatePath);
320 }
321 }
322
323 /* set config parameters for keyboard and joystick commands */
324 return event_set_core_defaults();
325}
326
327void main_speeddown(int percent)
328{
329 if (l_SpeedFactor - percent > 10) /* 10% minimum speed */
330 {
331 l_SpeedFactor -= percent;
332 main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "%s %d%%", "Playback speed:", l_SpeedFactor);
333 audio.setSpeedFactor(l_SpeedFactor);
334 StateChanged(M64CORE_SPEED_FACTOR, l_SpeedFactor);
335 }
336}
337
338void main_speedup(int percent)
339{
340 if (l_SpeedFactor + percent < 300) /* 300% maximum speed */
341 {
342 l_SpeedFactor += percent;
343 main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "%s %d%%", "Playback speed:", l_SpeedFactor);
344 audio.setSpeedFactor(l_SpeedFactor);
345 StateChanged(M64CORE_SPEED_FACTOR, l_SpeedFactor);
346 }
347}
348
349static void main_speedset(int percent)
350{
351 if (percent < 1 || percent > 1000)
352 {
353 DebugMessage(M64MSG_WARNING, "Invalid speed setting %i percent", percent);
354 return;
355 }
356 // disable fast-forward if it's enabled
357 main_set_fastforward(0);
358 // set speed
359 l_SpeedFactor = percent;
360 main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "%s %d%%", "Playback speed:", l_SpeedFactor);
361 audio.setSpeedFactor(l_SpeedFactor);
362 StateChanged(M64CORE_SPEED_FACTOR, l_SpeedFactor);
363}
364
365void main_set_fastforward(int enable)
366{
367 static int ff_state = 0;
368 static int SavedSpeedFactor = 100;
369
370 if (enable && !ff_state)
371 {
372 ff_state = 1; /* activate fast-forward */
373 SavedSpeedFactor = l_SpeedFactor;
374 l_SpeedFactor = 250;
375 audio.setSpeedFactor(l_SpeedFactor);
376 StateChanged(M64CORE_SPEED_FACTOR, l_SpeedFactor);
377 // set fast-forward indicator
378 l_msgFF = osd_new_message(OSD_TOP_RIGHT, "Fast Forward");
379 osd_message_set_static(l_msgFF);
380 osd_message_set_user_managed(l_msgFF);
381 }
382 else if (!enable && ff_state)
383 {
384 ff_state = 0; /* de-activate fast-forward */
385 l_SpeedFactor = SavedSpeedFactor;
386 audio.setSpeedFactor(l_SpeedFactor);
387 StateChanged(M64CORE_SPEED_FACTOR, l_SpeedFactor);
388 // remove message
389 osd_delete_message(l_msgFF);
390 l_msgFF = NULL;
391 }
392
393}
394
395static void main_set_speedlimiter(int enable)
396{
397 l_MainSpeedLimit = enable ? 1 : 0;
398}
399
400static int main_is_paused(void)
401{
402 return (g_EmulatorRunning && g_rom_pause);
403}
404
405void main_toggle_pause(void)
406{
407 if (!g_EmulatorRunning)
408 return;
409
410 if (g_rom_pause)
411 {
412 DebugMessage(M64MSG_STATUS, "Emulation continued.");
413 if(l_msgPause)
414 {
415 osd_delete_message(l_msgPause);
416 l_msgPause = NULL;
417 }
418 StateChanged(M64CORE_EMU_STATE, M64EMU_RUNNING);
419 }
420 else
421 {
422 if(l_msgPause)
423 osd_delete_message(l_msgPause);
424
425 DebugMessage(M64MSG_STATUS, "Emulation paused.");
426 l_msgPause = osd_new_message(OSD_MIDDLE_CENTER, "Paused");
427 osd_message_set_static(l_msgPause);
428 osd_message_set_user_managed(l_msgPause);
429 StateChanged(M64CORE_EMU_STATE, M64EMU_PAUSED);
430 }
431
432 g_rom_pause = !g_rom_pause;
433 l_FrameAdvance = 0;
434}
435
436void main_advance_one(void)
437{
438 l_FrameAdvance = 1;
439 g_rom_pause = 0;
440 StateChanged(M64CORE_EMU_STATE, M64EMU_RUNNING);
441}
442
443static void main_draw_volume_osd(void)
444{
445 char msgString[64];
446 const char *volString;
447
448 // this calls into the audio plugin
449 volString = audio.volumeGetString();
450 if (volString == NULL)
451 {
452 strcpy(msgString, "Volume Not Supported.");
453 }
454 else
455 {
456 sprintf(msgString, "%s: %s", "Volume", volString);
457 }
458
459 // create a new message or update an existing one
460 if (l_msgVol != NULL)
461 osd_update_message(l_msgVol, "%s", msgString);
462 else {
463 l_msgVol = osd_new_message(OSD_MIDDLE_CENTER, "%s", msgString);
464 osd_message_set_user_managed(l_msgVol);
465 }
466}
467
468/* this function could be called as a result of a keypress, joystick/button movement,
469 LIRC command, or 'testshots' command-line option timer */
470void main_take_next_screenshot(void)
471{
472 l_TakeScreenshot = l_CurrentFrame + 1;
473}
474
475void main_state_set_slot(int slot)
476{
477 if (slot < 0 || slot > 9)
478 {
479 DebugMessage(M64MSG_WARNING, "Invalid savestate slot '%i' in main_state_set_slot(). Using 0", slot);
480 slot = 0;
481 }
482
483 savestates_select_slot(slot);
484}
485
486void main_state_inc_slot(void)
487{
488 savestates_inc_slot();
489}
490
491void main_state_load(const char *filename)
492{
493 if (filename == NULL) // Save to slot
494 savestates_set_job(savestates_job_load, savestates_type_m64p, NULL);
495 else
496 savestates_set_job(savestates_job_load, savestates_type_unknown, filename);
497}
498
499void main_state_save(int format, const char *filename)
500{
501 if (filename == NULL) // Save to slot
502 savestates_set_job(savestates_job_save, savestates_type_m64p, NULL);
503 else // Save to file
504 savestates_set_job(savestates_job_save, (savestates_type)format, filename);
505}
506
507m64p_error main_core_state_query(m64p_core_param param, int *rval)
508{
509 switch (param)
510 {
511 case M64CORE_EMU_STATE:
512 if (!g_EmulatorRunning)
513 *rval = M64EMU_STOPPED;
514 else if (g_rom_pause)
515 *rval = M64EMU_PAUSED;
516 else
517 *rval = M64EMU_RUNNING;
518 break;
519 case M64CORE_VIDEO_MODE:
520 if (!VidExt_VideoRunning())
521 *rval = M64VIDEO_NONE;
522 else if (VidExt_InFullscreenMode())
523 *rval = M64VIDEO_FULLSCREEN;
524 else
525 *rval = M64VIDEO_WINDOWED;
526 break;
527 case M64CORE_SAVESTATE_SLOT:
528 *rval = savestates_get_slot();
529 break;
530 case M64CORE_SPEED_FACTOR:
531 *rval = l_SpeedFactor;
532 break;
533 case M64CORE_SPEED_LIMITER:
534 *rval = l_MainSpeedLimit;
535 break;
536 case M64CORE_VIDEO_SIZE:
537 {
538 int width, height;
539 if (!g_EmulatorRunning)
540 return M64ERR_INVALID_STATE;
541 main_get_screen_size(&width, &height);
542 *rval = (width << 16) + height;
543 break;
544 }
545 case M64CORE_AUDIO_VOLUME:
546 {
547 if (!g_EmulatorRunning)
548 return M64ERR_INVALID_STATE;
549 return main_volume_get_level(rval);
550 }
551 case M64CORE_AUDIO_MUTE:
552 *rval = main_volume_get_muted();
553 break;
554 case M64CORE_INPUT_GAMESHARK:
555 *rval = event_gameshark_active();
556 break;
557 // these are only used for callbacks; they cannot be queried or set
558 case M64CORE_STATE_LOADCOMPLETE:
559 case M64CORE_STATE_SAVECOMPLETE:
560 return M64ERR_INPUT_INVALID;
561 default:
562 return M64ERR_INPUT_INVALID;
563 }
564
565 return M64ERR_SUCCESS;
566}
567
568m64p_error main_core_state_set(m64p_core_param param, int val)
569{
570 switch (param)
571 {
572 case M64CORE_EMU_STATE:
573 if (!g_EmulatorRunning)
574 return M64ERR_INVALID_STATE;
575 if (val == M64EMU_STOPPED)
576 {
577 /* this stop function is asynchronous. The emulator may not terminate until later */
578 main_stop();
579 return M64ERR_SUCCESS;
580 }
581 else if (val == M64EMU_RUNNING)
582 {
583 if (main_is_paused())
584 main_toggle_pause();
585 return M64ERR_SUCCESS;
586 }
587 else if (val == M64EMU_PAUSED)
588 {
589 if (!main_is_paused())
590 main_toggle_pause();
591 return M64ERR_SUCCESS;
592 }
593 return M64ERR_INPUT_INVALID;
594 case M64CORE_VIDEO_MODE:
595 if (!g_EmulatorRunning)
596 return M64ERR_INVALID_STATE;
597 if (val == M64VIDEO_WINDOWED)
598 {
599 if (VidExt_InFullscreenMode())
600 gfx.changeWindow();
601 return M64ERR_SUCCESS;
602 }
603 else if (val == M64VIDEO_FULLSCREEN)
604 {
605 if (!VidExt_InFullscreenMode())
606 gfx.changeWindow();
607 return M64ERR_SUCCESS;
608 }
609 return M64ERR_INPUT_INVALID;
610 case M64CORE_SAVESTATE_SLOT:
611 if (val < 0 || val > 9)
612 return M64ERR_INPUT_INVALID;
613 savestates_select_slot(val);
614 return M64ERR_SUCCESS;
615 case M64CORE_SPEED_FACTOR:
616 if (!g_EmulatorRunning)
617 return M64ERR_INVALID_STATE;
618 main_speedset(val);
619 return M64ERR_SUCCESS;
620 case M64CORE_SPEED_LIMITER:
621 main_set_speedlimiter(val);
622 return M64ERR_SUCCESS;
623 case M64CORE_VIDEO_SIZE:
624 {
625 // the front-end app is telling us that the user has resized the video output frame, and so
626 // we should try to update the video plugin accordingly. First, check state
627 int width, height;
628 if (!g_EmulatorRunning)
629 return M64ERR_INVALID_STATE;
630 width = (val >> 16) & 0xffff;
631 height = val & 0xffff;
632 // then call the video plugin. if the video plugin supports resizing, it will resize its viewport and call
633 // VidExt_ResizeWindow to update the window manager handling our opengl output window
634 gfx.resizeVideoOutput(width, height);
635 return M64ERR_SUCCESS;
636 }
637 case M64CORE_AUDIO_VOLUME:
638 if (!g_EmulatorRunning)
639 return M64ERR_INVALID_STATE;
640 if (val < 0 || val > 100)
641 return M64ERR_INPUT_INVALID;
642 return main_volume_set_level(val);
643 case M64CORE_AUDIO_MUTE:
644 if ((main_volume_get_muted() && !val) || (!main_volume_get_muted() && val))
645 return main_volume_mute();
646 return M64ERR_SUCCESS;
647 case M64CORE_INPUT_GAMESHARK:
648 if (!g_EmulatorRunning)
649 return M64ERR_INVALID_STATE;
650 event_set_gameshark(val);
651 return M64ERR_SUCCESS;
652 // these are only used for callbacks; they cannot be queried or set
653 case M64CORE_STATE_LOADCOMPLETE:
654 case M64CORE_STATE_SAVECOMPLETE:
655 return M64ERR_INPUT_INVALID;
656 default:
657 return M64ERR_INPUT_INVALID;
658 }
659}
660
661m64p_error main_get_screen_size(int *width, int *height)
662{
663 gfx.readScreen(NULL, width, height, 0);
664 return M64ERR_SUCCESS;
665}
666
667m64p_error main_read_screen(void *pixels, int bFront)
668{
669 int width_trash, height_trash;
670 gfx.readScreen(pixels, &width_trash, &height_trash, bFront);
671 return M64ERR_SUCCESS;
672}
673
674m64p_error main_volume_up(void)
675{
676 int level = 0;
677 audio.volumeUp();
678 main_draw_volume_osd();
679 main_volume_get_level(&level);
680 StateChanged(M64CORE_AUDIO_VOLUME, level);
681 return M64ERR_SUCCESS;
682}
683
684m64p_error main_volume_down(void)
685{
686 int level = 0;
687 audio.volumeDown();
688 main_draw_volume_osd();
689 main_volume_get_level(&level);
690 StateChanged(M64CORE_AUDIO_VOLUME, level);
691 return M64ERR_SUCCESS;
692}
693
694m64p_error main_volume_get_level(int *level)
695{
696 *level = audio.volumeGetLevel();
697 return M64ERR_SUCCESS;
698}
699
700m64p_error main_volume_set_level(int level)
701{
702 audio.volumeSetLevel(level);
703 main_draw_volume_osd();
704 level = audio.volumeGetLevel();
705 StateChanged(M64CORE_AUDIO_VOLUME, level);
706 return M64ERR_SUCCESS;
707}
708
709m64p_error main_volume_mute(void)
710{
711 audio.volumeMute();
712 main_draw_volume_osd();
713 StateChanged(M64CORE_AUDIO_MUTE, main_volume_get_muted());
714 return M64ERR_SUCCESS;
715}
716
717int main_volume_get_muted(void)
718{
719 return (audio.volumeGetLevel() == 0);
720}
721
722m64p_error main_reset(int do_hard_reset)
723{
724 if (do_hard_reset) {
725 hard_reset_device(&g_dev);
726 }
727 else {
728 soft_reset_device(&g_dev);
729 }
730
731 return M64ERR_SUCCESS;
732}
733
734/*********************************************************************************************************
735* global functions, callbacks from the r4300 core or from other plugins
736*/
737
738static void video_plugin_render_callback(int bScreenRedrawn)
739{
740 int bOSD = ConfigGetParamBool(g_CoreConfig, "OnScreenDisplay");
741
742 // if the flag is set to take a screenshot, then grab it now
743 if (l_TakeScreenshot != 0)
744 {
745 // if the OSD is enabled, and the screen has not been recently redrawn, then we cannot take a screenshot now because
746 // it contains the OSD text. Wait until the next redraw
747 if (!bOSD || bScreenRedrawn)
748 {
749 TakeScreenshot(l_TakeScreenshot - 1); // current frame number +1 is in l_TakeScreenshot
750 l_TakeScreenshot = 0; // reset flag
751 }
752 }
753
754 // if the OSD is enabled, then draw it now
755 if (bOSD)
756 {
757 osd_render();
758 }
759
760 // if the input plugin specified a render callback, call it now
761 if(input.renderCallback)
762 {
763 input.renderCallback();
764 }
765}
766
767void new_frame(void)
768{
769 if (g_FrameCallback != NULL)
770 (*g_FrameCallback)(l_CurrentFrame);
771
772 /* advance the current frame */
773 l_CurrentFrame++;
774
775 if (l_FrameAdvance) {
776 g_rom_pause = 1;
777 l_FrameAdvance = 0;
778 StateChanged(M64CORE_EMU_STATE, M64EMU_PAUSED);
779 }
780}
781
782#define SAMPLE_COUNT 3
783static void apply_speed_limiter(void)
784{
785 static unsigned long totalVIs = 0;
786 static int resetOnce = 0;
787 static int lastSpeedFactor = 100;
788 static unsigned int StartFPSTime = 0;
789 static const double defaultSpeedFactor = 100.0;
790 unsigned int CurrentFPSTime = SDL_GetTicks();
791 static double sleepTimes[SAMPLE_COUNT];
792 static unsigned int sleepTimesIndex = 0;
793
794 // calculate frame duration based upon ROM setting (50/60hz) and mupen64plus speed adjustment
795 const double VILimitMilliseconds = 1000.0 / g_dev.vi.expected_refresh_rate;
796 const double SpeedFactorMultiple = defaultSpeedFactor/l_SpeedFactor;
797 const double AdjustedLimit = VILimitMilliseconds * SpeedFactorMultiple;
798
799 //if this is the first time or we are resuming from pause
800 if(StartFPSTime == 0 || !resetOnce || lastSpeedFactor != l_SpeedFactor)
801 {
802 StartFPSTime = CurrentFPSTime;
803 totalVIs = 0;
804 resetOnce = 1;
805 }
806 else
807 {
808 ++totalVIs;
809 }
810
811 lastSpeedFactor = l_SpeedFactor;
812
813#if defined(PROFILE)
814 timed_section_start(TIMED_SECTION_IDLE);
815#endif
816
817#ifdef DBG
818 if(g_DebuggerActive) DebuggerCallback(DEBUG_UI_VI, 0);
819#endif
820
821 double totalElapsedGameTime = AdjustedLimit*totalVIs;
822 double elapsedRealTime = CurrentFPSTime - StartFPSTime;
823 double sleepTime = totalElapsedGameTime - elapsedRealTime;
824
825 //Reset if the sleep needed is an unreasonable value
826 static const double minSleepNeeded = -50;
827 static const double maxSleepNeeded = 50;
828 if(sleepTime < minSleepNeeded || sleepTime > (maxSleepNeeded*SpeedFactorMultiple))
829 {
830 resetOnce = 0;
831 }
832
833 sleepTimes[sleepTimesIndex%SAMPLE_COUNT] = sleepTime;
834 sleepTimesIndex++;
835
836 unsigned int elementsForAverage = sleepTimesIndex > SAMPLE_COUNT ? SAMPLE_COUNT : sleepTimesIndex;
837
838 // compute the average sleepTime
839 double sum = 0;
840 unsigned int index;
841 for(index = 0; index < elementsForAverage; index++)
842 {
843 sum += sleepTimes[index];
844 }
845
846 double averageSleep = sum/elementsForAverage;
847
848 int sleepMs = (int)averageSleep;
849
850 if(sleepMs > 0 && sleepMs < maxSleepNeeded*SpeedFactorMultiple && l_MainSpeedLimit)
851 {
852 DebugMessage(M64MSG_VERBOSE, " apply_speed_limiter(): Waiting %ims", sleepMs);
853
854 SDL_Delay(sleepMs);
855 }
856
857
858#if defined(PROFILE)
859 timed_section_end(TIMED_SECTION_IDLE);
860#endif
861}
862
863/* TODO: make a GameShark module and move that there */
864static void gs_apply_cheats(struct cheat_ctx* ctx)
865{
866 struct r4300_core* r4300 = &g_dev.r4300;
867
868 if (g_gs_vi_counter < 60)
869 {
870 if (g_gs_vi_counter == 0)
871 cheat_apply_cheats(ctx, r4300, ENTRY_BOOT);
872 g_gs_vi_counter++;
873 }
874 else
875 {
876 cheat_apply_cheats(ctx, r4300, ENTRY_VI);
877 }
878}
879
880static void pause_loop(void)
881{
882 if(g_rom_pause)
883 {
884 osd_render(); // draw Paused message in case gfx.updateScreen didn't do it
885 VidExt_GL_SwapBuffers();
886 while(g_rom_pause)
887 {
888 SDL_Delay(10);
889 main_check_inputs();
890 }
891 }
892}
893
894/* called on vertical interrupt.
895 * Allow the core to perform various things */
896void new_vi(void)
897{
898#if defined(PROFILE)
899 timed_sections_refresh();
900#endif
901
902 gs_apply_cheats(&g_cheat_ctx);
903
904 apply_speed_limiter();
905 main_check_inputs();
906
907 pause_loop();
908}
909
910static void main_switch_pak(int control_id)
911{
912 struct game_controller* cont = &g_dev.controllers[control_id];
913
914 change_pak(cont, l_paks[control_id][l_paks_idx[control_id]], l_ipaks[l_paks_idx[control_id]]);
915
916 if (cont->ipak != NULL) {
917 DebugMessage(M64MSG_INFO, "Controller %u pak changed to %s", control_id, cont->ipak->name);
918 }
919 else {
920 DebugMessage(M64MSG_INFO, "Removing pak from controller %u", control_id);
921 }
922}
923
924void main_switch_next_pak(int control_id)
925{
926 if (l_ipaks[l_paks_idx[control_id]] == NULL ||
927 ++l_paks_idx[control_id] >= PAK_MAX_SIZE) {
928 l_paks_idx[control_id] = 0;
929 }
930
931 main_switch_pak(control_id);
932}
933
934void main_switch_plugin_pak(int control_id)
935{
936 //Don't switch to the selected pak if it's not available for the game
937 if (l_ipaks[l_pak_type_idx[Controls[control_id].Plugin]] == NULL) {
938 Controls[control_id].Plugin = PLUGIN_NONE;
939 }
940
941 l_paks_idx[control_id] = l_pak_type_idx[Controls[control_id].Plugin];
942
943 main_switch_pak(control_id);
944}
945
946static void open_mpk_file(struct file_storage* fstorage)
947{
948 unsigned int i;
949 int ret = open_file_storage(fstorage, GAME_CONTROLLERS_COUNT*MEMPAK_SIZE, get_mempaks_path());
950
951 if (ret == (int)file_open_error) {
952 /* if file doesn't exists provide default content */
953 for(i = 0; i < GAME_CONTROLLERS_COUNT; ++i) {
954 format_mempak(fstorage->data + i * MEMPAK_SIZE);
955 }
956 }
957}
958
959static void open_fla_file(struct file_storage* fstorage)
960{
961 int ret = open_file_storage(fstorage, FLASHRAM_SIZE, get_flashram_path());
962
963 if (ret == (int)file_open_error) {
964 /* if file doesn't exists provide default content */
965 format_flashram(fstorage->data);
966 }
967}
968
969static void open_sra_file(struct file_storage* fstorage)
970{
971 int ret = open_file_storage(fstorage, SRAM_SIZE, get_sram_path());
972
973 if (ret == (int)file_open_error) {
974 /* if file doesn't exists provide default content */
975 format_sram(fstorage->data);
976 }
977}
978
979static void open_eep_file(struct file_storage* fstorage)
980{
981 /* Note: EEP files are all EEPROM_MAX_SIZE bytes long,
982 * whatever the real EEPROM size is.
983 */
984 enum { EEPROM_MAX_SIZE = 0x800 };
985
986 int ret = open_file_storage(fstorage, EEPROM_MAX_SIZE, get_eeprom_path());
987
988 if (ret == (int)file_open_error) {
989 /* if file doesn't exists provide default content */
990 format_eeprom(fstorage->data, EEPROM_MAX_SIZE);
991 }
992
993 /* Truncate to 4k bit if necessary */
994 if (ROM_SETTINGS.savetype != EEPROM_16KB) {
995 fstorage->size = 0x200;
996 }
997}
998
999static void load_dd_rom(uint8_t* rom, size_t* rom_size)
1000{
1001 /* ask the core loader for DD disk filename */
1002 char* dd_ipl_rom_filename = (g_media_loader.get_dd_rom == NULL)
1003 ? NULL
1004 : g_media_loader.get_dd_rom(g_media_loader.cb_data);
1005
1006 if ((dd_ipl_rom_filename == NULL) || (strlen(dd_ipl_rom_filename) == 0)) {
1007 goto no_dd;
1008 }
1009
1010 struct file_storage dd_rom;
1011 memset(&dd_rom, 0, sizeof(dd_rom));
1012
1013 if (open_rom_file_storage(&dd_rom, dd_ipl_rom_filename) != file_ok) {
1014 DebugMessage(M64MSG_ERROR, "Failed to load DD IPL ROM: %s. Disabling 64DD", dd_ipl_rom_filename);
1015 goto no_dd;
1016 }
1017
1018 DebugMessage(M64MSG_INFO, "DD IPL ROM: %s", dd_ipl_rom_filename);
1019
1020 /* load and swap DD IPL ROM */
1021 *rom_size = g_ifile_storage_ro.size(&dd_rom);
1022 memcpy(rom, g_ifile_storage_ro.data(&dd_rom), *rom_size);
1023 close_file_storage(&dd_rom);
1024
1025 /* fetch 1st word to identify IPL ROM format */
1026 /* FIXME: use more robust ROM detection heuristic - do the same for regular ROMs */
1027 uint32_t pi_bsd_dom1_config = 0
1028 | ((uint32_t)rom[0] << 24)
1029 | ((uint32_t)rom[1] << 16)
1030 | ((uint32_t)rom[2] << 8)
1031 | ((uint32_t)rom[3] << 0);
1032
1033 switch (pi_bsd_dom1_config)
1034 {
1035 case 0x80270740: /* Z64 - big endian */
1036 to_big_endian_buffer(rom, 4, *rom_size/4);
1037 break;
1038
1039 case 0x40072780: /* N64 - little endian */
1040 to_little_endian_buffer(rom, 4, *rom_size/4);
1041 break;
1042
1043 case 0x27804007: /* V64 - bi-endian */
1044 swap_buffer(rom, 2, *rom_size/2);
1045 break;
1046
1047 default: /* unknown */
1048 DebugMessage(M64MSG_ERROR, "Invalid DD IPL ROM: Disabling 64DD.");
1049 *rom_size = 0;
1050 return;
1051 }
1052
1053 return;
1054
1055no_dd:
1056 free(dd_ipl_rom_filename);
1057 *rom_size = 0;
1058}
1059
1060static void load_dd_disk(struct file_storage* dd_disk, const struct storage_backend_interface** dd_idisk)
1061{
1062 const char* format_desc;
1063 /* ask the core loader for DD disk filename */
1064 char* dd_disk_filename = (g_media_loader.get_dd_disk == NULL)
1065 ? NULL
1066 : g_media_loader.get_dd_disk(g_media_loader.cb_data);
1067
1068 /* handle the no disk case */
1069 if (dd_disk_filename == NULL || strlen(dd_disk_filename) == 0) {
1070 goto no_disk;
1071 }
1072
1073 /* open file */
1074 if (open_rom_file_storage(dd_disk, dd_disk_filename) != file_ok) {
1075 DebugMessage(M64MSG_ERROR, "Failed to load DD Disk: %s.", dd_disk_filename);
1076 goto no_disk;
1077 }
1078
1079 /* FIXME: handle byte swapping */
1080
1081
1082 switch (dd_disk->size)
1083 {
1084 case MAME_FORMAT_DUMP_SIZE:
1085 /* already in a compatible format */
1086 *dd_idisk = &g_ifile_storage;
1087 format_desc = "MAME";
1088 break;
1089
1090 case SDK_FORMAT_DUMP_SIZE: {
1091 /* convert to mame format */
1092 uint8_t* buffer = malloc(MAME_FORMAT_DUMP_SIZE);
1093 if (buffer == NULL) {
1094 DebugMessage(M64MSG_ERROR, "Failed to allocate memory for MAME disk dump");
1095 close_file_storage(dd_disk);
1096 goto no_disk;
1097 }
1098
1099 dd_convert_to_mame(buffer, dd_disk->data);
1100 free(dd_disk->data);
1101 dd_disk->data = buffer;
1102 dd_disk->size = MAME_FORMAT_DUMP_SIZE;
1103 *dd_idisk = &g_ifile_storage_dd_sdk_dump;
1104 format_desc = "SDK";
1105 } break;
1106
1107 default:
1108 DebugMessage(M64MSG_ERROR, "Invalid DD Disk size %u.", (uint32_t) dd_disk->size);
1109 close_file_storage(dd_disk);
1110 goto no_disk;
1111 }
1112
1113 DebugMessage(M64MSG_INFO, "DD Disk: %s - %zu - %s",
1114 dd_disk->filename,
1115 dd_disk->size,
1116 format_desc);
1117
1118 uint32_t w = *(uint32_t*)dd_disk->data;
1119 if (w == DD_REGION_JP || w == DD_REGION_US) {
1120 DebugMessage(M64MSG_WARNING, "Loading a saved disk ");
1121 }
1122
1123 return;
1124
1125no_disk:
1126 free(dd_disk_filename);
1127 *dd_idisk = NULL;
1128}
1129
1130
1131struct gb_cart_data
1132{
1133 int control_id;
1134 struct file_storage rom_fstorage;
1135 struct file_storage ram_fstorage;
1136 void* gbcam_backend;
1137 const struct video_capture_backend_interface* igbcam_backend;
1138};
1139
1140static struct gb_cart_data l_gb_carts_data[GAME_CONTROLLERS_COUNT];
1141
1142static void init_gb_rom(void* opaque, void** storage, const struct storage_backend_interface** istorage)
1143{
1144 struct gb_cart_data* data = (struct gb_cart_data*)opaque;
1145
1146 /* Ask the core loader for rom filename */
1147 char* rom_filename = (g_media_loader.get_gb_cart_rom == NULL)
1148 ? NULL
1149 : g_media_loader.get_gb_cart_rom(g_media_loader.cb_data, data->control_id);
1150
1151 /* Handle the no cart case */
1152 if (rom_filename == NULL || strlen(rom_filename) == 0) {
1153 goto no_cart;
1154 }
1155
1156 /* Open ROM file */
1157 if (open_rom_file_storage(&data->rom_fstorage, rom_filename) != file_ok) {
1158 DebugMessage(M64MSG_ERROR, "Failed to load ROM file: %s", rom_filename);
1159 goto no_cart;
1160 }
1161
1162 DebugMessage(M64MSG_INFO, "GB Loader ROM: %s - %zu",
1163 data->rom_fstorage.filename,
1164 data->rom_fstorage.size);
1165
1166 /* init GB ROM storage */
1167 *storage = &data->rom_fstorage;
1168 *istorage = &g_ifile_storage_ro;
1169 return;
1170
1171no_cart:
1172 free(rom_filename);
1173 *storage = NULL;
1174 *istorage = NULL;
1175}
1176
1177static void release_gb_rom(void* opaque)
1178{
1179 struct gb_cart_data* data = (struct gb_cart_data*)opaque;
1180
1181 close_file_storage(&data->rom_fstorage);
1182
1183 memset(&data->rom_fstorage, 0, sizeof(data->rom_fstorage));
1184}
1185
1186static void init_gb_ram(void* opaque, size_t ram_size, void** storage, const struct storage_backend_interface** istorage)
1187{
1188 struct gb_cart_data* data = (struct gb_cart_data*)opaque;
1189
1190 /* Ask the core loader for ram filename */
1191 char* ram_filename = (g_media_loader.get_gb_cart_ram == NULL)
1192 ? NULL
1193 : g_media_loader.get_gb_cart_ram(g_media_loader.cb_data, data->control_id);
1194
1195 /* Handle the no RAM case
1196 * if NULL or empty string generate a filename
1197 */
1198 if (ram_filename == NULL || strlen(ram_filename) == 0) {
1199 free(ram_filename);
1200 ram_filename = get_gb_ram_path(namefrompath(data->rom_fstorage.filename), data->control_id+1);
1201 }
1202
1203 /* Open RAM file
1204 * if file doesn't exists provide default content */
1205 int err = open_file_storage(&data->ram_fstorage, ram_size, ram_filename);
1206 if (err == file_open_error) {
1207 memset(data->ram_fstorage.data, 0, data->ram_fstorage.size);
1208 DebugMessage(M64MSG_INFO, "Providing default RAM content");
1209 }
1210 else if (err == file_read_error) {
1211 DebugMessage(M64MSG_WARNING, "Size mismatch between expected RAM size and effective file size");
1212 }
1213
1214 DebugMessage(M64MSG_INFO, "GB Loader RAM: %s - %zu",
1215 data->ram_fstorage.filename,
1216 data->ram_fstorage.size);
1217
1218 /* init GB RAM storage */
1219 *storage = &data->ram_fstorage;
1220 *istorage = &g_ifile_storage;
1221}
1222
1223static void release_gb_ram(void* opaque)
1224{
1225 struct gb_cart_data* data = (struct gb_cart_data*)opaque;
1226
1227 close_file_storage(&data->ram_fstorage);
1228
1229 memset(&data->ram_fstorage, 0, sizeof(data->ram_fstorage));
1230}
1231
1232void main_change_gb_cart(int control_id)
1233{
1234 struct transferpak* tpk = &g_dev.transferpaks[control_id];
1235 struct gb_cart* gb_cart = &g_dev.gb_carts[control_id];
1236 struct gb_cart_data* data = &l_gb_carts_data[control_id];
1237
1238 /* reset gb_cart_data */
1239 memset(data, 0, sizeof(*data));
1240 data->control_id = control_id;
1241
1242 init_gb_cart(gb_cart,
1243 data, init_gb_rom, release_gb_rom,
1244 data, init_gb_ram, release_gb_ram,
1245 NULL, &g_iclock_ctime_plus_delta,
1246 &data->control_id, &g_irumble_backend_plugin_compat,
1247 data->gbcam_backend, data->igbcam_backend);
1248
1249 if (gb_cart->read_gb_cart == NULL) {
1250 gb_cart = NULL;
1251 }
1252
1253 change_gb_cart(tpk, gb_cart);
1254
1255 if (tpk->gb_cart != NULL) {
1256 const uint8_t* rom_data = gb_cart->irom_storage->data(gb_cart->rom_storage);
1257 DebugMessage(M64MSG_INFO, "Inserting GB cart %s into transferpak %u", rom_data + 0x134, control_id);
1258 }
1259 else {
1260 DebugMessage(M64MSG_INFO, "Removing GB cart from transferpak %u", control_id);
1261 }
1262}
1263
1264
1265/*********************************************************************************************************
1266* emulation thread - runs the core
1267*/
1268
1269
1270m64p_error main_run(void)
1271{
1272 size_t i, k;
1273 size_t rdram_size;
1274 unsigned int count_per_op;
1275 unsigned int emumode;
1276 unsigned int disable_extra_mem;
1277 int si_dma_duration;
1278 int no_compiled_jump;
1279 int randomize_interrupt;
1280 struct file_storage eep;
1281 struct file_storage fla;
1282 struct file_storage sra;
1283 size_t dd_rom_size;
1284 struct file_storage dd_disk;
1285
1286 int control_ids[GAME_CONTROLLERS_COUNT];
1287 struct controller_input_compat cin_compats[GAME_CONTROLLERS_COUNT];
1288
1289 struct file_storage mpk_storages[GAME_CONTROLLERS_COUNT];
1290 struct file_storage mpk;
1291
1292 void* gbcam_backend;
1293 const struct video_capture_backend_interface* igbcam_backend;
1294
1295 /* XXX: select type of flashram from db */
1296 uint32_t flashram_type = MX29L1100_ID;
1297
1298
1299 /* take the r4300 emulator mode from the config file at this point and cache it in a global variable */
1300 emumode = ConfigGetParamInt(g_CoreConfig, "R4300Emulator");
1301
1302 /* set some other core parameters based on the config file values */
1303 savestates_set_autoinc_slot(ConfigGetParamBool(g_CoreConfig, "AutoStateSlotIncrement"));
1304 savestates_select_slot(ConfigGetParamInt(g_CoreConfig, "CurrentStateSlot"));
1305 no_compiled_jump = ConfigGetParamBool(g_CoreConfig, "NoCompiledJump");
1306 randomize_interrupt = ConfigGetParamBool(g_CoreConfig, "RandomizeInterrupt");
1307 count_per_op = ConfigGetParamInt(g_CoreConfig, "CountPerOp");
1308
1309 if (ROM_PARAMS.disableextramem)
1310 disable_extra_mem = ROM_PARAMS.disableextramem;
1311 else
1312 disable_extra_mem = ConfigGetParamInt(g_CoreConfig, "DisableExtraMem");
1313
1314
1315 rdram_size = (disable_extra_mem == 0) ? 0x800000 : 0x400000;
1316
1317 if (count_per_op <= 0)
1318 count_per_op = ROM_PARAMS.countperop;
1319
1320 si_dma_duration = ConfigGetParamInt(g_CoreConfig, "SiDmaDuration");
1321 if (si_dma_duration < 0)
1322 si_dma_duration = ROM_PARAMS.sidmaduration;
1323
1324 cheat_add_hacks(&g_cheat_ctx, ROM_PARAMS.cheats);
1325
1326 /* do byte-swapping if it hasn't been done yet */
1327#if !defined(M64P_BIG_ENDIAN)
1328 if (g_RomWordsLittleEndian == 0)
1329 {
1330 swap_buffer((uint8_t*)mem_base_u32(g_mem_base, MM_CART_ROM), 4, g_rom_size/4);
1331 g_RomWordsLittleEndian = 1;
1332 }
1333#endif
1334
1335 /* Fill-in l_pak_type_idx and l_ipaks according to game compatibility */
1336 k = 0;
1337 if (ROM_SETTINGS.biopak) {
1338 l_ipaks[k++] = &g_ibiopak;
1339 }
1340 if (ROM_SETTINGS.mempak) {
1341 l_pak_type_idx[PLUGIN_MEMPAK] = k;
1342 l_ipaks[k] = &g_imempak;
1343 ++k;
1344 }
1345 if (ROM_SETTINGS.rumble) {
1346 l_pak_type_idx[PLUGIN_RUMBLE_PAK] = k;
1347 l_pak_type_idx[PLUGIN_RAW] = k;
1348 l_ipaks[k] = &g_irumblepak;
1349 ++k;
1350 }
1351 if (ROM_SETTINGS.transferpak) {
1352 l_pak_type_idx[PLUGIN_TRANSFER_PAK] = k;
1353 l_ipaks[k] = &g_itransferpak;
1354 ++k;
1355 }
1356 l_pak_type_idx[PLUGIN_NONE] = k;
1357 l_ipaks[k] = NULL;
1358
1359 if (!ROM_SETTINGS.mempak) {
1360 l_pak_type_idx[PLUGIN_MEMPAK] = k;
1361 }
1362 if (!ROM_SETTINGS.rumble) {
1363 l_pak_type_idx[PLUGIN_RUMBLE_PAK] = k;
1364 l_pak_type_idx[PLUGIN_RAW] = k;
1365 }
1366 if (!ROM_SETTINGS.transferpak) {
1367 l_pak_type_idx[PLUGIN_TRANSFER_PAK] = k;
1368 }
1369
1370 /* init GbCamera backend specified in the configuration file */
1371 init_video_capture_backend(&igbcam_backend, &gbcam_backend,
1372 g_CoreConfig, "GbCameraVideoCaptureBackend1");
1373
1374 /* open GB cam video device */
1375 igbcam_backend->open(gbcam_backend, M64282FP_SENSOR_W, M64282FP_SENSOR_H);
1376
1377 /* open storage files, provide default content if not present */
1378 open_mpk_file(&mpk);
1379 open_eep_file(&eep);
1380 open_fla_file(&fla);
1381 open_sra_file(&sra);
1382
1383 /* Load 64DD IPL ROM and Disk */
1384 const struct clock_backend_interface* dd_rtc_iclock = NULL;
1385 const struct storage_backend_interface* dd_idisk = NULL;
1386 memset(&dd_disk, 0, sizeof(dd_disk));
1387
1388 load_dd_rom((uint8_t*)mem_base_u32(g_mem_base, MM_DD_ROM), &dd_rom_size);
1389 if (dd_rom_size > 0) {
1390 dd_rtc_iclock = &g_iclock_ctime_plus_delta;
1391 load_dd_disk(&dd_disk, &dd_idisk);
1392 }
1393
1394 /* setup pif channel devices */
1395 void* joybus_devices[PIF_CHANNELS_COUNT];
1396 const struct joybus_device_interface* ijoybus_devices[PIF_CHANNELS_COUNT];
1397
1398 memset(&g_dev.gb_carts, 0, GAME_CONTROLLERS_COUNT*sizeof(*g_dev.gb_carts));
1399 memset(&l_gb_carts_data, 0, GAME_CONTROLLERS_COUNT*sizeof(*l_gb_carts_data));
1400 memset(cin_compats, 0, GAME_CONTROLLERS_COUNT*sizeof(*cin_compats));
1401
1402 for (i = 0; i < GAME_CONTROLLERS_COUNT; ++i) {
1403
1404 control_ids[i] = (int)i;
1405
1406 /* if input plugin requests RawData let the input plugin do the channel device processing */
1407 if (Controls[i].RawData) {
1408 joybus_devices[i] = &control_ids[i];
1409 ijoybus_devices[i] = &g_ijoybus_device_plugin_compat;
1410 }
1411 /* otherwise let the core do the processing */
1412 else {
1413 /* select appropriate controller
1414 * FIXME: assume for now that only standard controller is compatible
1415 * Use the rom db to know if other peripherals are compatibles (VRU, mouse, train, ...)
1416 */
1417 const struct game_controller_flavor* cont_flavor =
1418 &g_standard_controller_flavor;
1419
1420 joybus_devices[i] = &g_dev.controllers[i];
1421 ijoybus_devices[i] = &g_ijoybus_device_controller;
1422
1423 cin_compats[i].control_id = (int)i;
1424 cin_compats[i].cont = &g_dev.controllers[i];
1425 cin_compats[i].tpk = &g_dev.transferpaks[i];
1426 cin_compats[i].last_pak_type = Controls[i].Plugin;
1427
1428 l_gb_carts_data[i].control_id = (int)i;
1429
1430 l_gb_carts_data[i].gbcam_backend = gbcam_backend;
1431 l_gb_carts_data[i].igbcam_backend = igbcam_backend;
1432
1433 l_paks_idx[i] = 0;
1434
1435 //Don't use the selected pak if it's not available for the game, instead use NONE
1436 if (l_ipaks[l_pak_type_idx[Controls[i].Plugin]] == NULL) {
1437 Controls[i].Plugin = PLUGIN_NONE;
1438 }
1439
1440 /* init all compatibles paks */
1441 for(k = 0; k < PAK_MAX_SIZE; ++k) {
1442 /* Bio Pak */
1443 if (l_ipaks[k] == &g_ibiopak) {
1444 init_biopak(&g_dev.biopaks[i], 64);
1445 l_paks[i][k] = &g_dev.biopaks[i];
1446
1447 if (Controls[i].Plugin == PLUGIN_BIO_PAK) {
1448 l_paks_idx[i] = k;
1449 }
1450 }
1451 /* Memory Pak */
1452 else if (l_ipaks[k] == &g_imempak) {
1453 mpk_storages[i].data = mpk.data + i * MEMPAK_SIZE;
1454 mpk_storages[i].size = MEMPAK_SIZE;
1455 mpk_storages[i].filename = (void*)&mpk; /* OK for isubfile_storage */
1456
1457 init_mempak(&g_dev.mempaks[i], &mpk_storages[i], &g_isubfile_storage);
1458 l_paks[i][k] = &g_dev.mempaks[i];
1459
1460 if (Controls[i].Plugin == PLUGIN_MEMPAK) {
1461 l_paks_idx[i] = k;
1462 }
1463 }
1464 /* Rumble Pak */
1465 else if (l_ipaks[k] == &g_irumblepak) {
1466 init_rumblepak(&g_dev.rumblepaks[i], &control_ids[i], &g_irumble_backend_plugin_compat);
1467 l_paks[i][k] = &g_dev.rumblepaks[i];
1468
1469 if (Controls[i].Plugin == PLUGIN_RUMBLE_PAK
1470 || Controls[i].Plugin == PLUGIN_RAW) {
1471 l_paks_idx[i] = k;
1472 }
1473 }
1474 /* Transfer Pak */
1475 else if (l_ipaks[k] == &g_itransferpak) {
1476
1477 /* init GB cart */
1478 init_gb_cart(&g_dev.gb_carts[i],
1479 &l_gb_carts_data[i], init_gb_rom, release_gb_rom,
1480 &l_gb_carts_data[i], init_gb_ram, release_gb_ram,
1481 NULL, &g_iclock_ctime_plus_delta,
1482 &l_gb_carts_data[i].control_id, &g_irumble_backend_plugin_compat,
1483 l_gb_carts_data[i].gbcam_backend, l_gb_carts_data[i].igbcam_backend);
1484
1485 init_transferpak(&g_dev.transferpaks[i], (g_dev.gb_carts[i].read_gb_cart == NULL) ? NULL : &g_dev.gb_carts[i]);
1486 l_paks[i][k] = &g_dev.transferpaks[i];
1487
1488 if (Controls[i].Plugin == PLUGIN_TRANSFER_PAK) {
1489 l_paks_idx[i] = k;
1490 }
1491
1492 /* enable GB cart switch */
1493 cin_compats[i].gb_cart_switch_enabled = 1;
1494 }
1495 /* No Pak */
1496 else {
1497 l_ipaks[k] = NULL;
1498 l_paks[i][k] = NULL;
1499
1500 if (Controls[i].Plugin == PLUGIN_NONE) {
1501 l_paks_idx[i] = k;
1502 }
1503
1504 break;
1505 }
1506 }
1507
1508 /* init game_controller */
1509 init_game_controller(&g_dev.controllers[i],
1510 cont_flavor,
1511 &cin_compats[i], &g_icontroller_input_backend_plugin_compat,
1512 l_paks[i][l_paks_idx[i]], l_ipaks[l_paks_idx[i]]);
1513
1514 if (l_ipaks[l_paks_idx[i]] != NULL) {
1515 DebugMessage(M64MSG_INFO, "Game controller %u (%s) has a %s plugged in",
1516 (uint32_t) i, cont_flavor->name, l_ipaks[l_paks_idx[i]]->name);
1517 } else {
1518 DebugMessage(M64MSG_INFO, "Game controller %u (%s) has nothing plugged in",
1519 (uint32_t) i, cont_flavor->name);
1520 }
1521 }
1522 }
1523 for (i = GAME_CONTROLLERS_COUNT; i < PIF_CHANNELS_COUNT; ++i) {
1524 joybus_devices[i] = &g_dev.cart;
1525 ijoybus_devices[i] = &g_ijoybus_device_cart;
1526 }
1527
1528
1529 init_device(&g_dev,
1530 g_mem_base,
1531 emumode,
1532 count_per_op,
1533 no_compiled_jump,
1534 randomize_interrupt,
1535 &g_dev.ai, &g_iaudio_out_backend_plugin_compat,
1536 si_dma_duration,
1537 rdram_size,
1538 joybus_devices, ijoybus_devices,
1539 vi_clock_from_tv_standard(ROM_PARAMS.systemtype), vi_expected_refresh_rate_from_tv_standard(ROM_PARAMS.systemtype),
1540 NULL, &g_iclock_ctime_plus_delta,
1541 g_rom_size,
1542 (ROM_SETTINGS.savetype != EEPROM_16KB) ? JDT_EEPROM_4K : JDT_EEPROM_16K,
1543 &eep, &g_ifile_storage,
1544 flashram_type,
1545 &fla, &g_ifile_storage,
1546 &sra, &g_ifile_storage,
1547 NULL, dd_rtc_iclock,
1548 dd_rom_size,
1549 &dd_disk, dd_idisk);
1550
1551 // Attach rom to plugins
1552 if (!gfx.romOpen())
1553 {
1554 goto on_gfx_open_failure;
1555 }
1556 if (!audio.romOpen())
1557 {
1558 goto on_audio_open_failure;
1559 }
1560 if (!input.romOpen())
1561 {
1562 goto on_input_open_failure;
1563 }
1564
1565 /* set up the SDL key repeat and event filter to catch keyboard/joystick commands for the core */
1566 event_initialize();
1567
1568 /* initialize the on-screen display */
1569 if (ConfigGetParamBool(g_CoreConfig, "OnScreenDisplay"))
1570 {
1571 // init on-screen display
1572 int width = 640, height = 480;
1573 gfx.readScreen(NULL, &width, &height, 0); // read screen to get width and height
1574 osd_init(width, height);
1575 }
1576
1577 // setup rendering callback from video plugin to the core, for screenshots and On-Screen-Display
1578 gfx.setRenderingCallback(video_plugin_render_callback);
1579
1580#ifdef WITH_LIRC
1581 lircStart();
1582#endif // WITH_LIRC
1583
1584#ifdef DBG
1585 if (ConfigGetParamBool(g_CoreConfig, "EnableDebugger"))
1586 init_debugger();
1587#endif
1588
1589 /* Startup message on the OSD */
1590 osd_new_message(OSD_MIDDLE_CENTER, "Mupen64Plus Started...");
1591
1592 g_EmulatorRunning = 1;
1593 StateChanged(M64CORE_EMU_STATE, M64EMU_RUNNING);
1594
1595 poweron_device(&g_dev);
1596 pif_bootrom_hle_execute(&g_dev.r4300);
1597 run_device(&g_dev);
1598
1599 /* now begin to shut down */
1600#ifdef WITH_LIRC
1601 lircStop();
1602#endif // WITH_LIRC
1603
1604#ifdef DBG
1605 if (g_DebuggerActive)
1606 destroy_debugger();
1607#endif
1608 /* release gb_carts */
1609 for(i = 0; i < GAME_CONTROLLERS_COUNT; ++i) {
1610 if (!Controls[i].RawData && g_dev.gb_carts[i].read_gb_cart != NULL) {
1611 release_gb_rom(&l_gb_carts_data[i]);
1612 release_gb_ram(&l_gb_carts_data[i]);
1613 }
1614 }
1615
1616 igbcam_backend->close(gbcam_backend);
1617 igbcam_backend->release(gbcam_backend);
1618
1619 close_file_storage(&sra);
1620 close_file_storage(&fla);
1621 close_file_storage(&eep);
1622 close_file_storage(&mpk);
1623 close_file_storage(&dd_disk);
1624
1625 if (ConfigGetParamBool(g_CoreConfig, "OnScreenDisplay"))
1626 {
1627 osd_exit();
1628 }
1629
1630 rsp.romClosed();
1631 input.romClosed();
1632 audio.romClosed();
1633 gfx.romClosed();
1634
1635 // clean up
1636 g_EmulatorRunning = 0;
1637 StateChanged(M64CORE_EMU_STATE, M64EMU_STOPPED);
1638
1639 return M64ERR_SUCCESS;
1640
1641on_input_open_failure:
1642 audio.romClosed();
1643on_audio_open_failure:
1644 gfx.romClosed();
1645on_gfx_open_failure:
1646 /* release gb_carts */
1647 for(i = 0; i < GAME_CONTROLLERS_COUNT; ++i) {
1648 if (!Controls[i].RawData && g_dev.gb_carts[i].read_gb_cart != NULL) {
1649 release_gb_rom(&l_gb_carts_data[i]);
1650 release_gb_ram(&l_gb_carts_data[i]);
1651 }
1652 }
1653
1654 igbcam_backend->close(gbcam_backend);
1655 igbcam_backend->release(gbcam_backend);
1656
1657 /* release storage files */
1658 close_file_storage(&sra);
1659 close_file_storage(&fla);
1660 close_file_storage(&eep);
1661 close_file_storage(&mpk);
1662 close_file_storage(&dd_disk);
1663
1664 return M64ERR_PLUGIN_FAIL;
1665}
1666
1667void main_stop(void)
1668{
1669 /* note: this operation is asynchronous. It may be called from a thread other than the
1670 main emulator thread, and may return before the emulator is completely stopped */
1671 if (!g_EmulatorRunning)
1672 return;
1673
1674 DebugMessage(M64MSG_STATUS, "Stopping emulation.");
1675 if(l_msgPause)
1676 {
1677 osd_delete_message(l_msgPause);
1678 l_msgPause = NULL;
1679 }
1680 if(l_msgFF)
1681 {
1682 osd_delete_message(l_msgFF);
1683 l_msgFF = NULL;
1684 }
1685 if(l_msgVol)
1686 {
1687 osd_delete_message(l_msgVol);
1688 l_msgVol = NULL;
1689 }
1690 if (g_rom_pause)
1691 {
1692 g_rom_pause = 0;
1693 StateChanged(M64CORE_EMU_STATE, M64EMU_RUNNING);
1694 }
1695
1696 stop_device(&g_dev);
1697
1698#ifdef DBG
1699 if(g_DebuggerActive)
1700 {
1701 debugger_step();
1702 }
1703#endif
1704}
1705