mirror of
https://github.com/Rosalie241/RMG.git
synced 2026-07-11 09:34:00 +02:00
Compare commits
22 Commits
v0.8.1
...
n64-systemtest
| Author | SHA1 | Date | |
|---|---|---|---|
| cd89473f7e | |||
| b89fed20e8 | |||
| 28af6a436e | |||
| 9c53a846b8 | |||
| 816bb4c426 | |||
| c119e5f128 | |||
| d64b23bdfe | |||
| b03f118b04 | |||
| d18ac4076f | |||
| 4620c1beb8 | |||
| 55431be957 | |||
| 18946b1d92 | |||
| c517862b3c | |||
| e8d4d6341b | |||
| 2246b6f25b | |||
| cd754fafa9 | |||
| 8660ced35f | |||
| 1c7276b4f8 | |||
| 4b793c4ad4 | |||
| e9dc24d947 | |||
| 51b712a8c9 | |||
| 1ce70fba22 |
@@ -1,6 +1,6 @@
|
||||
# Maintainer: Rosalie Wanders <rosalie@mailbox.org>
|
||||
pkgname=rmg
|
||||
pkgver=0.8.1
|
||||
pkgver=0.8.3
|
||||
pkgrel=1
|
||||
pkgdesc="Rosalie's Mupen GUI"
|
||||
arch=('x86_64' 'aarch64')
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name: RMG
|
||||
Version: 0.8.1
|
||||
Version: 0.8.3
|
||||
Release: %autorelease
|
||||
Summary: Rosalie's Mupen GUI
|
||||
|
||||
|
||||
@@ -29,6 +29,30 @@
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<releases>
|
||||
<release version="v0.8.3" date="2025-09-28" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Fix supported 64DD games not having the transfer pak functionality enabled</li>
|
||||
<li>Fix crash in Mario Artist Talent Studio when using mupen64plus-rsp-hle since v0.8.2</li>
|
||||
<li>Fix frame count not increasing from 0 since v0.8.2</li>
|
||||
<li>Fix loading save states freezing since v0.8.2</li>
|
||||
<li>Add clear buttons to 64DD IPL settings in the settings dialog</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.8.2" date="2025-09-26" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Fix screenshot filename being incorrect when playing 64DD games</li>
|
||||
<li>Fix GameBoy tower functionality not working in Pokemon Stadium 1 and 2</li>
|
||||
<li>Add clear buttons to transfer pak settings in RMG-Input</li>
|
||||
<li>Add support for the GameBoy camera by implementing a SDL3 backend in mupen64plus-core</li>
|
||||
<li>Improve accuracy of RSP</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.8.1" date="2025-09-23" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
|
||||
+53
-14
@@ -6130,18 +6130,6 @@ RefMD5=70C525880240C1E838B8B1BE35666C3B
|
||||
GoodName=GoldenEye 007 Intro by SonCrap (PD)
|
||||
CRC=9303DD17 0813B398
|
||||
|
||||
[67F2E18ED18A5F0EA3FE2D913E3F1786]
|
||||
GoodName=GoldenEye X
|
||||
; Alternate Title=GoldenEye X (5e Clouds)
|
||||
CRC=FDF95D15 618546CA
|
||||
RefMD5=E03B088B6AC9E0080440EFED07C1E40F
|
||||
|
||||
[435D75D07878D305293EC4D591B86303]
|
||||
GoodName=GoldenEye X
|
||||
; Alternate Title=GoldenEye X (5e Cloudless)
|
||||
CRC=E8B3F63D E5A997B1
|
||||
RefMD5=E03B088B6AC9E0080440EFED07C1E40F
|
||||
|
||||
[EA0E3E6AEFA58738A12906298373218B]
|
||||
GoodName=GoldenEye 007 (UE) (Switch Online) [!]
|
||||
CRC=DCBC50D1 9FD1AA3
|
||||
@@ -12024,10 +12012,25 @@ Rumble=Yes
|
||||
Transferpak=Yes
|
||||
|
||||
[5D72155E00Bf2CAB41B0F4A2f2E09C61]
|
||||
GoodName=Perfect Dark Plus
|
||||
GoodName=Perfect Dark Plus [h1]
|
||||
CRC=FB453D58 AD565422
|
||||
RefMD5=E03B088B6AC9E0080440EFED07C1E40F
|
||||
|
||||
[67F2E18ED18A5F0EA3FE2D913E3F1786]
|
||||
GoodName=GoldenEye X [h2] (5e Clouds)
|
||||
CRC=FDF95D15 618546CA
|
||||
RefMD5=E03B088B6AC9E0080440EFED07C1E40F
|
||||
|
||||
[435D75D07878D305293EC4D591B86303]
|
||||
GoodName=GoldenEye X [h3] (5e Cloudless)
|
||||
CRC=E8B3F63D E5A997B1
|
||||
RefMD5=E03B088B6AC9E0080440EFED07C1E40F
|
||||
|
||||
[640923B68B9281044AC1B518612E979B]
|
||||
GoodName=GoldenEye X [h4] (6a)
|
||||
CRC=BE0052C3 2CA8CFB2
|
||||
RefMD5=E03B088B6AC9E0080440EFED07C1E40F
|
||||
|
||||
[E0BCB2758EDF0AC6AB7DB36D98E1E57C]
|
||||
GoodName=Pikachu Genki Dechu (J) [!]
|
||||
CRC=3F245305 FC0B74AA
|
||||
@@ -14372,6 +14375,11 @@ GoodName=Space Station Silicon Valley (E) (M7) [b1]
|
||||
CRC=FC70E272 08FFE7AA
|
||||
RefMD5=FCA7AFCADCF5E5545A62919BA94DAD18
|
||||
|
||||
[2E91FFB252AA28B99E82D8F74BCC3831]
|
||||
GoodName=Space Station Silicon Valley (E) (M7) [f1] (FBM Fix v1.2)
|
||||
CRC=FC70E272 08FFE7AA
|
||||
RefMD5=FCA7AFCADCF5E5545A62919BA94DAD18
|
||||
|
||||
[E66ED1CC4AB95D0872BB2EBC49B206C4]
|
||||
GoodName=Space Station Silicon Valley (J) [!]
|
||||
CRC=BFE23884 EF48EAAF
|
||||
@@ -14379,6 +14387,11 @@ Players=1
|
||||
SaveType=Eeprom 4KB
|
||||
Rumble=Yes
|
||||
|
||||
[042D1CBD3F4705642D12D004F0649558]
|
||||
GoodName=Space Station Silicon Valley (J) [f1] (ExpFBM Fix v1.2)
|
||||
CRC=7AB86C9B A6487448
|
||||
RefMD5=E66ED1CC4AB95D0872BB2EBC49B206C4
|
||||
|
||||
[868B37D1B66D1D994E2BAD4E218BF129]
|
||||
GoodName=Space Station Silicon Valley (U) [!]
|
||||
CRC=BFE23884 EF48EAAF
|
||||
@@ -14396,13 +14409,23 @@ GoodName=Space Station Silicon Valley (U) [f2] (PAL)
|
||||
CRC=BFE23884 EF48EAAF
|
||||
RefMD5=868B37D1B66D1D994E2BAD4E218BF129
|
||||
|
||||
[92EE9AF3DFEB19A1339F3C75BAED1E6B]
|
||||
GoodName=Space Station Silicon Valley (U) (M7) [f3] (ExpFBMLSelect Fix v1.2)
|
||||
CRC=7AB86C9D 37CD109C
|
||||
RefMD5=868B37D1B66D1D994E2BAD4E218BF129
|
||||
|
||||
[F1F1C5E2B895DB63348BC738C0CDC645]
|
||||
GoodName=Space Station Silicon Valley (U) (V1.1) [!]
|
||||
CRC=FC70E272 8FFE7AA
|
||||
CRC=FC70E272 08FFE7AA
|
||||
Players=1
|
||||
SaveType=Eeprom 4KB
|
||||
Rumble=Yes
|
||||
|
||||
[9325E39AF74FC9571B5F2EFFCC1676A9]
|
||||
GoodName=Space Station Silicon Valley (U) (V1.1) (M7) [f1] (FBMLSelect Fix v1.2)
|
||||
CRC=FC70E270 658EA161
|
||||
RefMD5=F1F1C5E2B895DB63348BC738C0CDC645
|
||||
|
||||
[630E4122B0743A29C246DA2C257F92DA]
|
||||
GoodName=Spacer by Memir (POM '99) (PD)
|
||||
CRC=A3A044B5 6DB1BF5E
|
||||
@@ -18329,9 +18352,19 @@ GoodName=64DD IPL (USA)
|
||||
|
||||
[8485643E5830CD67ED4C0A5FD49E2491]
|
||||
GoodName=Mario Artist Paint Studio (J)
|
||||
Transferpak=Yes
|
||||
|
||||
[B17771664DAF95D7E61D8549A8CEACC6]
|
||||
GoodName=Mario Artist Paint Studio (J) [English v2.1]
|
||||
Transferpak=Yes
|
||||
|
||||
[88228E990B58A94E9B3460BEFF632304]
|
||||
GoodName=Mario Artist Talent Studio (J)
|
||||
Transferpak=Yes
|
||||
|
||||
[F3767735B1610C2BCA3220B590D43232]
|
||||
GoodName=Mario Artist Talent Studio (J) [English v2.1]
|
||||
Transferpak=Yes
|
||||
|
||||
[114AF722029D6386C3BFEA4CC8FA603C]
|
||||
GoodName=Mario Artist Communication Kit (J)
|
||||
@@ -18339,9 +18372,15 @@ GoodName=Mario Artist Communication Kit (J)
|
||||
[DA23EE561578B7DAD77ED72728B46D30]
|
||||
GoodName=Mario Artist Polygon Studio (J)
|
||||
|
||||
[7B94CB9AF6FE351CA7B47F59594AF96C]
|
||||
GoodName=Mario Artist Polygon Studio (J) [English v3.0]
|
||||
|
||||
[EBBA03F20096FC2BC178FC3A1F4EC2B6]
|
||||
GoodName=Sim City 64 (J)
|
||||
|
||||
[4372F74477FE54CD363FE4F14984625A]
|
||||
GoodName=Sim City 64 (J) [English v0.6.38]
|
||||
|
||||
[9F797A9C704B5EBD04D6A2B036309AF2]
|
||||
GoodName=Nihon Pro Golf Tour 64 (J)
|
||||
|
||||
|
||||
+9
-1
@@ -253,7 +253,7 @@ ifeq ($(OS), OSX)
|
||||
endif
|
||||
ifeq ($(OS), MINGW)
|
||||
TARGET = mupen64plus$(POSTFIX).dll
|
||||
ifeq ($(CC), clang)
|
||||
ifeq (clang, $(word 1, $(shell $(CC) --version)))
|
||||
LDFLAGS += -shared -Wl,-export-all-symbols
|
||||
else
|
||||
LDFLAGS += -Wl,-Bsymbolic -shared -Wl,-export-all-symbols
|
||||
@@ -355,9 +355,13 @@ ifeq ($(origin SDL_CFLAGS) $(origin SDL_LDLIBS), undefined undefined)
|
||||
ifeq ($(shell $(PKG_CONFIG) --modversion sdl2 2>/dev/null),)
|
||||
$(error No SDL3 or SDL2 development libraries found!)
|
||||
endif
|
||||
ifeq ($(SDL3_CAMERA), 1)
|
||||
$(error SDL3_CAMERA requires SDL3!)
|
||||
endif
|
||||
SDL_CFLAGS += $(shell $(PKG_CONFIG) --cflags sdl2)
|
||||
SDL_LDLIBS += $(shell $(PKG_CONFIG) --libs sdl2)
|
||||
else
|
||||
SDL3_CAMERA := 1
|
||||
SDL_CFLAGS += -DUSE_SDL3
|
||||
SDL_CFLAGS += $(shell $(PKG_CONFIG) --cflags sdl3)
|
||||
SDL_LDLIBS += $(shell $(PKG_CONFIG) --libs sdl3)
|
||||
@@ -762,6 +766,10 @@ ifeq ($(OPENCV), 1)
|
||||
CFLAGS += -DM64P_OPENCV
|
||||
endif
|
||||
|
||||
ifeq ($(SDL3_CAMERA), 1)
|
||||
SOURCE += $(SRCDIR)/backends/sdl3_video_capture.cpp
|
||||
CFLAGS += -DSDL3_CAMERA
|
||||
endif
|
||||
|
||||
# generate a list of object files to build, make a temporary directory for them
|
||||
OBJECTS := $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o, $(filter $(SRCDIR)/%.c, $(SOURCE)))
|
||||
|
||||
@@ -28,12 +28,18 @@ extern const struct video_capture_backend_interface g_idummy_video_capture_backe
|
||||
#if defined(M64P_OPENCV)
|
||||
extern const struct video_capture_backend_interface g_iopencv_video_capture_backend;
|
||||
#endif
|
||||
#if defined(SDL3_CAMERA)
|
||||
extern const struct video_capture_backend_interface g_isdl3_video_capture_backend;
|
||||
#endif
|
||||
|
||||
|
||||
const struct video_capture_backend_interface* g_video_capture_backend_interfaces[] =
|
||||
{
|
||||
#if defined(M64P_OPENCV)
|
||||
&g_iopencv_video_capture_backend,
|
||||
#endif
|
||||
#if defined(SDL3_CAMERA)
|
||||
&g_isdl3_video_capture_backend,
|
||||
#endif
|
||||
&g_idummy_video_capture_backend,
|
||||
NULL /* sentinel - must be last element */
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
#if !defined(DEFAULT_VIDEO_CAPTURE_BACKEND)
|
||||
#if defined(M64P_OPENCV)
|
||||
#define DEFAULT_VIDEO_CAPTURE_BACKEND "opencv"
|
||||
#elif defined(SDL3_CAMERA)
|
||||
#define DEFAULT_VIDEO_CAPTURE_BACKEND "sdl3"
|
||||
#else
|
||||
#define DEFAULT_VIDEO_CAPTURE_BACKEND ""
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,282 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus - sdl3_video_capture.cpp *
|
||||
* Mupen64Plus homepage: https://mupen64plus.org/ *
|
||||
* Copyright (C) 2025 Rosalie Wanders *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
struct sdl3_video_capture
|
||||
{
|
||||
int init_sdl;
|
||||
|
||||
SDL_Camera* camera;
|
||||
SDL_CameraID camera_id;
|
||||
|
||||
char* target_camera_name;
|
||||
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
};
|
||||
|
||||
#include "backends/api/video_capture_backend.h"
|
||||
|
||||
#define M64P_CORE_PROTOTYPES 1
|
||||
#include "api/callbacks.h"
|
||||
#include "api/m64p_types.h"
|
||||
#include "api/m64p_config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
const struct video_capture_backend_interface g_isdl3_video_capture_backend;
|
||||
|
||||
static m64p_error sdl3_init(void** vcap, const char* section)
|
||||
{
|
||||
/* initialize data */
|
||||
*vcap = malloc(sizeof(struct sdl3_video_capture));
|
||||
if (*vcap == NULL)
|
||||
{
|
||||
return M64ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
memset(*vcap, 0, sizeof(struct sdl3_video_capture));
|
||||
struct sdl3_video_capture* sdl = (struct sdl3_video_capture*)(*vcap);
|
||||
|
||||
/* attempt to initialize SDL3 */
|
||||
if (!SDL_WasInit(SDL_INIT_CAMERA))
|
||||
{
|
||||
if (!SDL_Init(SDL_INIT_CAMERA))
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "Failed to initialize SDL camera subsystem: %s", SDL_GetError());
|
||||
free(sdl);
|
||||
return M64ERR_SYSTEM_FAIL;
|
||||
}
|
||||
|
||||
sdl->init_sdl = 1;
|
||||
}
|
||||
|
||||
/* default parameters */
|
||||
const char* device = NULL;
|
||||
|
||||
if (section && strlen(section) > 0)
|
||||
{
|
||||
m64p_handle config = NULL;
|
||||
|
||||
if (ConfigOpenSection(section, &config) != M64ERR_SUCCESS)
|
||||
{
|
||||
DebugMessage(M64MSG_WARNING, "Failed to open video configuration section: %s, falling back to default video device", section);
|
||||
return M64ERR_SUCCESS;
|
||||
}
|
||||
|
||||
/* set default parameters */
|
||||
ConfigSetDefaultString(config, "device", "", "Device name to use for capture or empty for default.");
|
||||
|
||||
/* get parameters */
|
||||
device = ConfigGetParamString(config, "device");
|
||||
}
|
||||
|
||||
/* store device name for later */
|
||||
if (device != NULL && strlen(device) > 0)
|
||||
{
|
||||
sdl->target_camera_name = strdup(device);
|
||||
}
|
||||
|
||||
return M64ERR_SUCCESS;
|
||||
}
|
||||
|
||||
static void sdl3_release(void* vcap)
|
||||
{
|
||||
struct sdl3_video_capture* sdl = (struct sdl3_video_capture*)(vcap);
|
||||
if (sdl != NULL)
|
||||
{
|
||||
if (sdl->init_sdl && SDL_WasInit(SDL_INIT_CAMERA))
|
||||
{
|
||||
SDL_QuitSubSystem(SDL_INIT_CAMERA);
|
||||
}
|
||||
|
||||
if (sdl->target_camera_name != NULL)
|
||||
{
|
||||
free(sdl->target_camera_name);
|
||||
}
|
||||
|
||||
free(sdl);
|
||||
}
|
||||
}
|
||||
|
||||
static m64p_error sdl3_open(void* vcap, unsigned int width, unsigned int height)
|
||||
{
|
||||
struct sdl3_video_capture* sdl = (struct sdl3_video_capture*)(vcap);
|
||||
if (sdl == NULL)
|
||||
{
|
||||
return M64ERR_NOT_INIT;
|
||||
}
|
||||
|
||||
sdl->width = width;
|
||||
sdl->height = height;
|
||||
|
||||
int cameras_count = 0;
|
||||
SDL_CameraID* cameras = SDL_GetCameras(&cameras_count);
|
||||
if (cameras == NULL)
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "Failed to retrieve list of video devices: %s", SDL_GetError());
|
||||
return M64ERR_SYSTEM_FAIL;
|
||||
}
|
||||
if (cameras_count == 0)
|
||||
{
|
||||
DebugMessage(M64MSG_WARNING, "Failed to find video devices");
|
||||
return M64ERR_INPUT_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* fallback to default camera */
|
||||
sdl->camera_id = cameras[0];
|
||||
|
||||
/* print name of every camera to user, and
|
||||
* attempt to find the camera that the user
|
||||
* specified in the config */
|
||||
int found_camera = 0;
|
||||
for (int i = 0; i < cameras_count; i++)
|
||||
{
|
||||
const char* name = SDL_GetCameraName(cameras[i]);
|
||||
if (name == NULL)
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "Failed to retrieve video device name: %s", SDL_GetError());
|
||||
continue;
|
||||
}
|
||||
|
||||
DebugMessage(M64MSG_INFO, "Found video device: \"%s\"", name);
|
||||
|
||||
if (sdl->target_camera_name != NULL &&
|
||||
strcmp(sdl->target_camera_name, name) == 0)
|
||||
{
|
||||
sdl->camera_id = cameras[i];
|
||||
found_camera = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* show warning when device was not found */
|
||||
if (sdl->target_camera_name != NULL && !found_camera)
|
||||
{
|
||||
DebugMessage(M64MSG_WARNING, "Failed to find video device with name \"%s\", falling back to default", sdl->target_camera_name);
|
||||
}
|
||||
|
||||
SDL_free(cameras);
|
||||
|
||||
/* attempt to open camera */
|
||||
sdl->camera = SDL_OpenCamera(sdl->camera_id, NULL);
|
||||
if (sdl->camera == NULL)
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "Failed to open video device: %s", SDL_GetError());
|
||||
return M64ERR_SYSTEM_FAIL;
|
||||
}
|
||||
|
||||
/* attempt to get permission for the camera */
|
||||
int permission_state = SDL_GetCameraPermissionState(sdl->camera);
|
||||
if (permission_state == 0)
|
||||
{
|
||||
DebugMessage(M64MSG_INFO, "Waiting until user has approved video access");
|
||||
do
|
||||
{
|
||||
SDL_Delay(250);
|
||||
permission_state = SDL_GetCameraPermissionState(sdl->camera);
|
||||
} while (permission_state == 0);
|
||||
}
|
||||
|
||||
if (permission_state == -1)
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "Failed to open video device: permission denied");
|
||||
return M64ERR_SYSTEM_FAIL;
|
||||
}
|
||||
|
||||
DebugMessage(M64MSG_INFO, "Video successfully opened: %s", SDL_GetCameraName(sdl->camera_id));
|
||||
return M64ERR_SUCCESS;
|
||||
}
|
||||
|
||||
static void sdl3_close(void* vcap)
|
||||
{
|
||||
struct sdl3_video_capture* sdl = (struct sdl3_video_capture*)(vcap);
|
||||
if (sdl == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (sdl->camera != NULL)
|
||||
{
|
||||
SDL_CloseCamera(sdl->camera);
|
||||
}
|
||||
|
||||
DebugMessage(M64MSG_INFO, "Video closed");
|
||||
}
|
||||
|
||||
static m64p_error sdl3_grab_image(void* vcap, void* data)
|
||||
{
|
||||
struct sdl3_video_capture* sdl = (struct sdl3_video_capture*)(vcap);
|
||||
if (sdl == NULL || sdl->camera == NULL)
|
||||
{
|
||||
return M64ERR_NOT_INIT;
|
||||
}
|
||||
|
||||
SDL_Surface* frame_surface = SDL_AcquireCameraFrame(sdl->camera, NULL);
|
||||
if (frame_surface == NULL)
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "Failed to grab video frame: %s", SDL_GetError());
|
||||
return M64ERR_SYSTEM_FAIL;
|
||||
}
|
||||
|
||||
SDL_Surface* target_surface = SDL_CreateSurface(sdl->width, sdl->height, SDL_PIXELFORMAT_BGR24);
|
||||
if (target_surface == NULL)
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "Failed to create target surface: %s\n", SDL_GetError());
|
||||
SDL_ReleaseCameraFrame(sdl->camera, frame_surface);
|
||||
return M64ERR_SYSTEM_FAIL;
|
||||
}
|
||||
|
||||
int frame_size = SDL_min(frame_surface->w, frame_surface->h);
|
||||
SDL_Rect frame_rect;
|
||||
frame_rect.x = (frame_surface->w / 2) - (frame_size / 2);
|
||||
frame_rect.y = 0;
|
||||
frame_rect.w = frame_size;
|
||||
frame_rect.h = frame_size;
|
||||
|
||||
if (!SDL_BlitSurfaceScaled(frame_surface, &frame_rect, target_surface, NULL, SDL_SCALEMODE_NEAREST))
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "Failed to blit surface: %s", SDL_GetError());
|
||||
SDL_ReleaseCameraFrame(sdl->camera, frame_surface);
|
||||
SDL_DestroySurface(target_surface);
|
||||
return M64ERR_SYSTEM_FAIL;
|
||||
}
|
||||
|
||||
memcpy(data, target_surface->pixels, target_surface->w * target_surface->h * 3);
|
||||
|
||||
SDL_ReleaseCameraFrame(sdl->camera, frame_surface);
|
||||
SDL_DestroySurface(target_surface);
|
||||
return M64ERR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const struct video_capture_backend_interface g_isdl3_video_capture_backend =
|
||||
{
|
||||
"sdl3",
|
||||
sdl3_init,
|
||||
sdl3_release,
|
||||
sdl3_open,
|
||||
sdl3_close,
|
||||
sdl3_grab_image
|
||||
};
|
||||
|
||||
+34
-30
@@ -35,9 +35,12 @@
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#define RESET_MODE_CART_ENABLE_BIT UINT32_C(0x00000001)
|
||||
#define RESET_MODE_PAK_ENABLE_BIT UINT32_C(0x00000080)
|
||||
|
||||
static uint16_t gb_cart_address(unsigned int bank, uint16_t address)
|
||||
{
|
||||
return (address & 0x3fff) | ((bank & 0x3) * 0x4000) ;
|
||||
return 0x4000 * bank + (address & 0x7fff) - 0x4000;
|
||||
}
|
||||
|
||||
void init_transferpak(struct transferpak* tpk, struct gb_cart* gb_cart)
|
||||
@@ -49,10 +52,8 @@ void poweron_transferpak(struct transferpak* tpk)
|
||||
{
|
||||
tpk->enabled = 0;
|
||||
tpk->bank = 0;
|
||||
tpk->access_mode = (tpk->gb_cart == NULL)
|
||||
? CART_NOT_INSERTED
|
||||
: CART_ACCESS_MODE_0;
|
||||
tpk->access_mode_changed = 0x44;
|
||||
tpk->cart_enabled = 0;
|
||||
tpk->reset_state = 3;
|
||||
|
||||
if (tpk->gb_cart != NULL) {
|
||||
poweron_gb_cart(tpk->gb_cart);
|
||||
@@ -62,16 +63,13 @@ void poweron_transferpak(struct transferpak* tpk)
|
||||
void change_gb_cart(struct transferpak* tpk, struct gb_cart* gb_cart)
|
||||
{
|
||||
tpk->enabled = 0;
|
||||
tpk->cart_enabled = 0;
|
||||
tpk->reset_state = 3;
|
||||
tpk->gb_cart = gb_cart;
|
||||
|
||||
if (gb_cart == NULL) {
|
||||
tpk->access_mode = CART_NOT_INSERTED;
|
||||
}
|
||||
else {
|
||||
tpk->access_mode = CART_ACCESS_MODE_0;
|
||||
if (gb_cart != NULL) {
|
||||
poweron_gb_cart(gb_cart);
|
||||
}
|
||||
|
||||
tpk->gb_cart = gb_cart;
|
||||
}
|
||||
|
||||
static void plug_transferpak(void* pak)
|
||||
@@ -87,7 +85,7 @@ static void unplug_transferpak(void* pak)
|
||||
static void read_transferpak(void* pak, uint16_t address, uint8_t* data, size_t size)
|
||||
{
|
||||
struct transferpak* tpk = (struct transferpak*)pak;
|
||||
uint8_t value;
|
||||
uint8_t value = 0;
|
||||
|
||||
DebugMessage(M64MSG_VERBOSE, "tpak read: %04x", address);
|
||||
|
||||
@@ -104,18 +102,29 @@ static void read_transferpak(void* pak, uint16_t address, uint8_t* data, size_t
|
||||
break;
|
||||
|
||||
case 0xb:
|
||||
/* get gb cart access mode */
|
||||
if (tpk->enabled)
|
||||
{
|
||||
DebugMessage(M64MSG_VERBOSE, "tpak get access mode: %02x", tpk->access_mode);
|
||||
memset(data, tpk->access_mode, size);
|
||||
if (tpk->access_mode != CART_NOT_INSERTED)
|
||||
{
|
||||
data[0] |= tpk->access_mode_changed;
|
||||
}
|
||||
tpk->access_mode_changed = 0;
|
||||
{
|
||||
if (tpk->gb_cart && tpk->cart_enabled) {
|
||||
value |= RESET_MODE_CART_ENABLE_BIT;
|
||||
}
|
||||
|
||||
value |= (uint8_t)((tpk->reset_state & 3) << 2);
|
||||
|
||||
if (tpk->enabled) {
|
||||
value |= RESET_MODE_PAK_ENABLE_BIT;
|
||||
}
|
||||
|
||||
if (tpk->cart_enabled && tpk->reset_state == 3) {
|
||||
tpk->reset_state = 2;
|
||||
} else if (!tpk->cart_enabled && tpk->reset_state == 2) {
|
||||
tpk->reset_state = 1;
|
||||
} else if (!tpk->cart_enabled && tpk->reset_state == 1) {
|
||||
tpk->reset_state = 0;
|
||||
}
|
||||
|
||||
DebugMessage(M64MSG_VERBOSE, "tpak read 0xB => %02x", value);
|
||||
memset(data, value, size);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xc:
|
||||
case 0xd:
|
||||
@@ -176,18 +185,13 @@ static void write_transferpak(void* pak, uint16_t address, const uint8_t* data,
|
||||
/* set gb cart access mode */
|
||||
if (tpk->enabled)
|
||||
{
|
||||
tpk->access_mode_changed = 0x04;
|
||||
|
||||
tpk->access_mode = ((value & 1) == 0)
|
||||
? CART_ACCESS_MODE_0
|
||||
: CART_ACCESS_MODE_1;
|
||||
tpk->reset_state = 3;
|
||||
tpk->cart_enabled = 1;
|
||||
|
||||
if ((value & 0xfe) != 0)
|
||||
{
|
||||
DebugMessage(M64MSG_WARNING, "Unknown tpak write: %04x <- %02x", address, value);
|
||||
}
|
||||
|
||||
DebugMessage(M64MSG_VERBOSE, "tpak set access mode %02x", tpk->access_mode);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -38,8 +38,9 @@ struct transferpak
|
||||
{
|
||||
unsigned int enabled;
|
||||
unsigned int bank;
|
||||
unsigned int access_mode;
|
||||
unsigned int access_mode_changed;
|
||||
|
||||
unsigned int cart_enabled;
|
||||
unsigned int reset_state;
|
||||
|
||||
struct gb_cart* gb_cart;
|
||||
};
|
||||
|
||||
@@ -129,6 +129,7 @@ void init_device(struct device* dev,
|
||||
{ &dev->dd, dd_mecha_int_handler }, /* DD MECHA */
|
||||
{ &dev->dd, dd_bm_int_handler }, /* DD BM */
|
||||
{ &dev->dd, dd_dv_int_handler }, /* DD DRIVE */
|
||||
{ &dev->sp, rsp_task_event },
|
||||
};
|
||||
|
||||
#define R(x) read_ ## x
|
||||
|
||||
@@ -54,7 +54,7 @@ enum gbcart_extra_devices
|
||||
/* various helper functions for ram, rom, or MBC uses */
|
||||
|
||||
|
||||
static void read_rom(const void* rom_storage, const struct storage_backend_interface* irom_storage, uint16_t address, uint8_t* data, size_t size)
|
||||
static void read_rom(const void* rom_storage, const struct storage_backend_interface* irom_storage, uint32_t address, uint8_t* data, size_t size)
|
||||
{
|
||||
assert(size > 0);
|
||||
|
||||
@@ -68,7 +68,7 @@ static void read_rom(const void* rom_storage, const struct storage_backend_inter
|
||||
}
|
||||
|
||||
|
||||
static void read_ram(const void* ram_storage, const struct storage_backend_interface* iram_storage, unsigned int enabled, uint16_t address, uint8_t* data, size_t size, uint8_t mask)
|
||||
static void read_ram(const void* ram_storage, const struct storage_backend_interface* iram_storage, unsigned int enabled, uint32_t address, uint8_t* data, size_t size, uint8_t mask)
|
||||
{
|
||||
size_t i;
|
||||
assert(size > 0);
|
||||
@@ -715,6 +715,9 @@ static void init_pocket_cam(struct pocket_cam* cam, uint8_t* ram, void* vcap, co
|
||||
|
||||
cam->vcap = vcap;
|
||||
cam->ivcap = ivcap;
|
||||
|
||||
/* open video device */
|
||||
cam->ivcap->open(cam->vcap, M64282FP_SENSOR_W, M64282FP_SENSOR_H);
|
||||
}
|
||||
|
||||
static void poweron_pocket_cam(struct pocket_cam* cam)
|
||||
|
||||
@@ -58,7 +58,7 @@ void pif_bootrom_hle_execute(struct r4300_core* r4300)
|
||||
unsigned int tv_type = get_tv_type(); /* 0:PAL, 1:NTSC, 2:MPAL */
|
||||
|
||||
int64_t* r4300_gpregs = r4300_regs(r4300);
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
|
||||
/* setup CP0 registers */
|
||||
cp0_regs[CP0_STATUS_REG] = 0x34000000;
|
||||
|
||||
@@ -136,7 +136,7 @@ void cached_interp_##name##_OUT(void) \
|
||||
void cached_interp_##name##_IDLE(void) \
|
||||
{ \
|
||||
DECLARE_R4300 \
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); \
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); \
|
||||
int* cp0_cycle_count = r4300_cp0_cycle_count(&r4300->cp0); \
|
||||
const int take_jump = (condition); \
|
||||
if (cop1 && check_cop1_unusable(r4300)) return; \
|
||||
|
||||
+11
-11
@@ -49,7 +49,7 @@ void init_cp0(struct cp0* cp0, unsigned int count_per_op, unsigned int count_per
|
||||
|
||||
void poweron_cp0(struct cp0* cp0)
|
||||
{
|
||||
uint32_t* cp0_regs;
|
||||
uint64_t* cp0_regs;
|
||||
unsigned int* cp0_next_interrupt;
|
||||
int* cp0_cycle_count;
|
||||
|
||||
@@ -65,7 +65,7 @@ void poweron_cp0(struct cp0* cp0)
|
||||
cp0_regs[CP0_COUNT_REG] = UINT32_C(0x5000);
|
||||
cp0_regs[CP0_CAUSE_REG] = UINT32_C(0x5c);
|
||||
cp0_regs[CP0_CONTEXT_REG] = UINT32_C(0x7ffff0);
|
||||
cp0_regs[CP0_EPC_REG] = UINT32_C(0xffffffff);
|
||||
cp0_regs[CP0_EPC_REG] = UINT64_C(0xffffffffffffffff);
|
||||
cp0_regs[CP0_BADVADDR_REG] = UINT32_C(0xffffffff);
|
||||
cp0_regs[CP0_ERROREPC_REG] = UINT32_C(0xffffffff);
|
||||
|
||||
@@ -81,7 +81,7 @@ void poweron_cp0(struct cp0* cp0)
|
||||
}
|
||||
|
||||
|
||||
uint32_t* r4300_cp0_regs(struct cp0* cp0)
|
||||
uint64_t* r4300_cp0_regs(struct cp0* cp0)
|
||||
{
|
||||
#ifndef NEW_DYNAREC
|
||||
return cp0->regs;
|
||||
@@ -124,7 +124,7 @@ int* r4300_cp0_cycle_count(struct cp0* cp0)
|
||||
|
||||
int check_cop1_unusable(struct r4300_core* r4300)
|
||||
{
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
|
||||
if (!(cp0_regs[CP0_STATUS_REG] & CP0_STATUS_CU1))
|
||||
{
|
||||
@@ -137,7 +137,7 @@ int check_cop1_unusable(struct r4300_core* r4300)
|
||||
|
||||
int check_cop2_unusable(struct r4300_core* r4300)
|
||||
{
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
|
||||
if (!(cp0_regs[CP0_STATUS_REG] & CP0_STATUS_CU2))
|
||||
{
|
||||
@@ -151,7 +151,7 @@ int check_cop2_unusable(struct r4300_core* r4300)
|
||||
void cp0_update_count(struct r4300_core* r4300)
|
||||
{
|
||||
struct cp0* cp0 = &r4300->cp0;
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(cp0);
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(cp0);
|
||||
|
||||
#ifdef NEW_DYNAREC
|
||||
if (r4300->emumode != EMUMODE_DYNAREC)
|
||||
@@ -213,7 +213,7 @@ static void exception_epilog(struct r4300_core* r4300)
|
||||
|
||||
void TLB_refill_exception(struct r4300_core* r4300, uint32_t address, int w)
|
||||
{
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
int usual_handler = 0, i;
|
||||
|
||||
if (r4300->emumode != EMUMODE_DYNAREC && w != 2) {
|
||||
@@ -246,8 +246,8 @@ void TLB_refill_exception(struct r4300_core* r4300, uint32_t address, int w)
|
||||
if (r4300->emumode != EMUMODE_PURE_INTERPRETER)
|
||||
{
|
||||
cp0_regs[CP0_EPC_REG] = (w != 2)
|
||||
? *r4300_pc(r4300)
|
||||
: address;
|
||||
? SE32(*r4300_pc(r4300))
|
||||
: SE32(address);
|
||||
}
|
||||
else {
|
||||
cp0_regs[CP0_EPC_REG] = *r4300_pc(r4300);
|
||||
@@ -297,12 +297,12 @@ void TLB_refill_exception(struct r4300_core* r4300, uint32_t address, int w)
|
||||
|
||||
void exception_general(struct r4300_core* r4300)
|
||||
{
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
|
||||
cp0_update_count(r4300);
|
||||
cp0_regs[CP0_STATUS_REG] |= CP0_STATUS_EXL;
|
||||
|
||||
cp0_regs[CP0_EPC_REG] = *r4300_pc(r4300);
|
||||
cp0_regs[CP0_EPC_REG] = SE32(*r4300_pc(r4300));
|
||||
|
||||
if (r4300->delay_slot == 1 || r4300->delay_slot == 3)
|
||||
{
|
||||
|
||||
+3
-3
@@ -173,7 +173,7 @@ struct interrupt_handler
|
||||
void (*callback)(void*);
|
||||
};
|
||||
|
||||
enum { CP0_INTERRUPT_HANDLERS_COUNT = 16 };
|
||||
enum { CP0_INTERRUPT_HANDLERS_COUNT = 17 };
|
||||
|
||||
enum {
|
||||
INTR_UNSAFE_R4300 = 0x01,
|
||||
@@ -184,7 +184,7 @@ struct cp0
|
||||
{
|
||||
#ifndef NEW_DYNAREC
|
||||
/* New dynarec uses a different memory layout */
|
||||
uint32_t regs[CP0_REGS_COUNT];
|
||||
uint64_t regs[CP0_REGS_COUNT];
|
||||
uint64_t latch;
|
||||
#endif
|
||||
|
||||
@@ -227,7 +227,7 @@ struct cp0
|
||||
void init_cp0(struct cp0* cp0, unsigned int count_per_op, unsigned int count_per_op_denom_pot, struct new_dynarec_hot_state* new_dynarec_hot_state, const struct interrupt_handler* interrupt_handlers);
|
||||
void poweron_cp0(struct cp0* cp0);
|
||||
|
||||
uint32_t* r4300_cp0_regs(struct cp0* cp0);
|
||||
uint64_t* r4300_cp0_regs(struct cp0* cp0);
|
||||
uint64_t* r4300_cp0_latch(struct cp0* cp0);
|
||||
uint32_t* r4300_cp0_last_addr(struct cp0* cp0);
|
||||
unsigned int* r4300_cp0_next_interrupt(struct cp0* cp0);
|
||||
|
||||
+20
-12
@@ -100,7 +100,7 @@ static void clear_queue(struct interrupt_queue* q)
|
||||
|
||||
static int before_event(const struct cp0* cp0, unsigned int evt1, unsigned int evt2, int type2)
|
||||
{
|
||||
const uint32_t* cp0_regs = r4300_cp0_regs((struct cp0*)cp0); /* OK to cast away const qualifier */
|
||||
const uint64_t* cp0_regs = r4300_cp0_regs((struct cp0*)cp0); /* OK to cast away const qualifier */
|
||||
uint32_t count = cp0_regs[CP0_COUNT_REG];
|
||||
int* cp0_cycle_count = r4300_cp0_cycle_count((struct cp0*)cp0);
|
||||
|
||||
@@ -128,7 +128,7 @@ unsigned int add_random_interrupt_time(struct r4300_core* r4300)
|
||||
|
||||
void add_interrupt_event(struct cp0* cp0, int type, unsigned int delay)
|
||||
{
|
||||
const uint32_t* cp0_regs = r4300_cp0_regs(cp0);
|
||||
const uint64_t* cp0_regs = r4300_cp0_regs(cp0);
|
||||
add_interrupt_event_count(cp0, type, cp0_regs[CP0_COUNT_REG] + delay);
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ void add_interrupt_event_count(struct cp0* cp0, int type, unsigned int count)
|
||||
{
|
||||
struct node* event;
|
||||
struct node* e;
|
||||
const uint32_t* cp0_regs = r4300_cp0_regs(cp0);
|
||||
const uint64_t* cp0_regs = r4300_cp0_regs(cp0);
|
||||
unsigned int* cp0_next_interrupt = r4300_cp0_next_interrupt(cp0);
|
||||
int* cp0_cycle_count = r4300_cp0_cycle_count(cp0);
|
||||
|
||||
@@ -191,7 +191,7 @@ void add_interrupt_event_count(struct cp0* cp0, int type, unsigned int count)
|
||||
void remove_interrupt_event(struct cp0* cp0)
|
||||
{
|
||||
struct node* e;
|
||||
const uint32_t* cp0_regs = r4300_cp0_regs(cp0);
|
||||
const uint64_t* cp0_regs = r4300_cp0_regs(cp0);
|
||||
unsigned int* cp0_next_interrupt = r4300_cp0_next_interrupt(cp0);
|
||||
int* cp0_cycle_count = r4300_cp0_cycle_count(cp0);
|
||||
|
||||
@@ -264,7 +264,7 @@ void remove_event(struct interrupt_queue* q, int type)
|
||||
void translate_event_queue(struct cp0* cp0, unsigned int base)
|
||||
{
|
||||
struct node* e;
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(cp0);
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(cp0);
|
||||
int* cp0_cycle_count = r4300_cp0_cycle_count(cp0);
|
||||
|
||||
remove_event(&cp0->q, COMPARE_INT);
|
||||
@@ -309,7 +309,7 @@ int save_eventqueue_infos(const struct cp0* cp0, char *buf)
|
||||
void load_eventqueue_infos(struct cp0* cp0, const char *buf)
|
||||
{
|
||||
int len = 0;
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(cp0);
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(cp0);
|
||||
|
||||
clear_queue(&cp0->q);
|
||||
|
||||
@@ -335,7 +335,7 @@ void init_interrupt(struct cp0* cp0)
|
||||
void r4300_check_interrupt(struct r4300_core* r4300, uint32_t cause_ip, int set_cause)
|
||||
{
|
||||
struct node* event;
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
unsigned int* cp0_next_interrupt = r4300_cp0_next_interrupt(&r4300->cp0);
|
||||
int* cp0_cycle_count = r4300_cp0_cycle_count(&r4300->cp0);
|
||||
|
||||
@@ -379,7 +379,7 @@ void r4300_check_interrupt(struct r4300_core* r4300, uint32_t cause_ip, int set_
|
||||
|
||||
void raise_maskable_interrupt(struct r4300_core* r4300, uint32_t cause_ip)
|
||||
{
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
cp0_regs[CP0_CAUSE_REG] = (cp0_regs[CP0_CAUSE_REG] | cause_ip) & ~CP0_CAUSE_EXCCODE_MASK;
|
||||
|
||||
if (!(cp0_regs[CP0_STATUS_REG] & cp0_regs[CP0_CAUSE_REG] & UINT32_C(0xff00))) {
|
||||
@@ -396,7 +396,7 @@ void raise_maskable_interrupt(struct r4300_core* r4300, uint32_t cause_ip)
|
||||
void compare_int_handler(void* opaque)
|
||||
{
|
||||
struct r4300_core* r4300 = (struct r4300_core*)opaque;
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
int* cp0_cycle_count = r4300_cp0_cycle_count(&r4300->cp0);
|
||||
|
||||
/* Add count_per_op to avoid wrong event order in case CP0_COUNT_REG == CP0_COMPARE_REG */
|
||||
@@ -422,7 +422,7 @@ void check_int_handler(void* opaque)
|
||||
void special_int_handler(void* opaque)
|
||||
{
|
||||
struct cp0* cp0 = (struct cp0*)opaque;
|
||||
const uint32_t* cp0_regs = r4300_cp0_regs(cp0);
|
||||
const uint64_t* cp0_regs = r4300_cp0_regs(cp0);
|
||||
|
||||
remove_interrupt_event(cp0);
|
||||
add_interrupt_event_count(cp0, SPECIAL_INT, ((cp0_regs[CP0_COUNT_REG] & UINT32_C(0x80000000)) ^ UINT32_C(0x80000000)));
|
||||
@@ -434,10 +434,13 @@ void nmi_int_handler(void* opaque)
|
||||
{
|
||||
struct device* dev = (struct device*)opaque;
|
||||
struct r4300_core* r4300 = &dev->r4300;
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
|
||||
reset_pif(&dev->pif, 1);
|
||||
|
||||
// HACK: reset rsp state
|
||||
poweron_rsp(&dev->sp);
|
||||
|
||||
// setup r4300 Status flags: reset TS and SR, set BEV, ERL, and SR
|
||||
cp0_regs[CP0_STATUS_REG] = (cp0_regs[CP0_STATUS_REG] & ~(CP0_STATUS_SR | CP0_STATUS_TS | UINT32_C(0x00080000))) | (CP0_STATUS_ERL | CP0_STATUS_BEV | CP0_STATUS_SR);
|
||||
cp0_regs[CP0_CAUSE_REG] = 0x00000000;
|
||||
@@ -534,7 +537,7 @@ static void call_interrupt_handler(const struct cp0* cp0, size_t index)
|
||||
|
||||
void gen_interrupt(struct r4300_core* r4300)
|
||||
{
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
unsigned int* cp0_next_interrupt = r4300_cp0_next_interrupt(&r4300->cp0);
|
||||
int* cp0_cycle_count = r4300_cp0_cycle_count(&r4300->cp0);
|
||||
|
||||
@@ -656,6 +659,11 @@ void gen_interrupt(struct r4300_core* r4300)
|
||||
call_interrupt_handler(&r4300->cp0, 15);
|
||||
break;
|
||||
|
||||
case RSP_TSK_EVT:
|
||||
remove_interrupt_event(&r4300->cp0);
|
||||
call_interrupt_handler(&r4300->cp0, 16);
|
||||
break;
|
||||
|
||||
default:
|
||||
DebugMessage(M64MSG_ERROR, "Unknown interrupt queue event type %.8X.", r4300->cp0.q.first->data.type);
|
||||
remove_interrupt_event(&r4300->cp0);
|
||||
|
||||
@@ -69,5 +69,6 @@ void nmi_int_handler(void* opaque);
|
||||
#define DD_MC_INT 0x1000
|
||||
#define DD_BM_INT 0x2000
|
||||
#define DD_DV_INT 0x4000
|
||||
#define RSP_TSK_EVT 0x8000
|
||||
|
||||
#endif /* M64P_DEVICE_R4300_INTERRUPT_H */
|
||||
|
||||
@@ -115,7 +115,7 @@ DECLARE_INSTRUCTION(RESERVED)
|
||||
{
|
||||
DECLARE_R4300
|
||||
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
|
||||
DebugMessage(M64MSG_ERROR, "reserved opcode: %" PRIX32 ":%" PRIX32, PCADDR, *fast_mem_access(r4300, PCADDR));
|
||||
|
||||
@@ -127,7 +127,7 @@ DECLARE_INSTRUCTION(RESERVED_COP2)
|
||||
{
|
||||
DECLARE_R4300
|
||||
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
|
||||
if (check_cop2_unusable(r4300)) { return; }
|
||||
|
||||
@@ -140,7 +140,7 @@ DECLARE_INSTRUCTION(RESERVED_COP2)
|
||||
DECLARE_INSTRUCTION(BREAK)
|
||||
{
|
||||
DECLARE_R4300
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
|
||||
cp0_regs[CP0_CAUSE_REG] = CP0_CAUSE_EXCCODE_BP;
|
||||
exception_general(r4300);
|
||||
@@ -221,11 +221,23 @@ DECLARE_INSTRUCTION(LL)
|
||||
DECLARE_INSTRUCTION(LW)
|
||||
{
|
||||
DECLARE_R4300
|
||||
const uint32_t lsaddr = (uint32_t) irs32 + (uint32_t) iimmediate;
|
||||
const uint64_t lsaddr = (int64_t) irs + (int16_t) iimmediate;
|
||||
int64_t *lsrtp = &irt;
|
||||
ADD_TO_PC(1);
|
||||
uint32_t value;
|
||||
|
||||
if (lsaddr & 3) {
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
//
|
||||
cp0_regs[CP0_CONTEXT_REG] = (cp0_regs[CP0_CONTEXT_REG] & 0xffffffffff800000) | (lsaddr >> 9 & 0x00000000007FFFF0);
|
||||
cp0_regs[CP0_XCONTEXT_REG] = (cp0_regs[CP0_CONTEXT_REG] & 0xffffffffff800000) | (lsaddr >> 9 & 0x7FFFFFF0) | (lsaddr >> 31 & 0x80000000) | ((int64_t)1 << 32);
|
||||
cp0_regs[CP0_BADVADDR_REG] = lsaddr;
|
||||
cp0_regs[CP0_CAUSE_REG] = CP0_CAUSE_EXCCODE_ADEL;
|
||||
exception_general(r4300);
|
||||
return;
|
||||
}
|
||||
|
||||
ADD_TO_PC(1);
|
||||
|
||||
if (r4300_read_aligned_word(r4300, lsaddr, &value)) {
|
||||
*lsrtp = SE32(value);
|
||||
}
|
||||
@@ -374,8 +386,19 @@ DECLARE_INSTRUCTION(SC)
|
||||
DECLARE_INSTRUCTION(SW)
|
||||
{
|
||||
DECLARE_R4300
|
||||
const uint32_t lsaddr = (uint32_t) irs32 + (uint32_t) iimmediate;
|
||||
const uint64_t lsaddr = (int64_t) irs + (int16_t) iimmediate;
|
||||
int64_t *lsrtp = &irt;
|
||||
|
||||
if (lsaddr & 3) {
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
cp0_regs[CP0_CONTEXT_REG] = (lsaddr >> 9 & 0x007FFFF0);
|
||||
cp0_regs[CP0_XCONTEXT_REG] = (lsaddr >> 9 & 0x7FFFFFF0) | (lsaddr >> 31 & 0x80000000) | ((int64_t)1 << 32);
|
||||
cp0_regs[CP0_BADVADDR_REG] = lsaddr;
|
||||
cp0_regs[CP0_CAUSE_REG] = CP0_CAUSE_EXCCODE_ADES;
|
||||
exception_general(r4300);
|
||||
return;
|
||||
}
|
||||
|
||||
ADD_TO_PC(1);
|
||||
|
||||
r4300_write_aligned_word(r4300, lsaddr, (uint32_t)*lsrtp, ~UINT32_C(0));
|
||||
@@ -993,7 +1016,7 @@ DECLARE_INSTRUCTION(CACHE)
|
||||
DECLARE_INSTRUCTION(ERET)
|
||||
{
|
||||
DECLARE_R4300
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
int* cp0_cycle_count = r4300_cp0_cycle_count(&r4300->cp0);
|
||||
|
||||
cp0_update_count(r4300);
|
||||
@@ -1022,7 +1045,7 @@ DECLARE_INSTRUCTION(SYNC)
|
||||
DECLARE_INSTRUCTION(SYSCALL)
|
||||
{
|
||||
DECLARE_R4300
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
|
||||
cp0_regs[CP0_CAUSE_REG] = CP0_CAUSE_EXCCODE_SYS;
|
||||
exception_general(r4300);
|
||||
@@ -1034,7 +1057,7 @@ DECLARE_INSTRUCTION(SYSCALL)
|
||||
DECLARE_INSTRUCTION(name) \
|
||||
{ \
|
||||
DECLARE_R4300 \
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); \
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); \
|
||||
if (cond) \
|
||||
{ \
|
||||
cp0_regs[CP0_CAUSE_REG] = CP0_CAUSE_EXCCODE_TR; \
|
||||
@@ -1067,7 +1090,7 @@ DECLARE_INSTRUCTION(TLBP)
|
||||
{
|
||||
DECLARE_R4300
|
||||
int i;
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
|
||||
cp0_regs[CP0_INDEX_REG] |= UINT32_C(0x80000000);
|
||||
for (i = 0; i < 32; ++i)
|
||||
@@ -1087,7 +1110,7 @@ DECLARE_INSTRUCTION(TLBP)
|
||||
DECLARE_INSTRUCTION(TLBR)
|
||||
{
|
||||
DECLARE_R4300
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
|
||||
int index;
|
||||
index = cp0_regs[CP0_INDEX_REG] & UINT32_C(0x1F);
|
||||
@@ -1104,7 +1127,7 @@ DECLARE_INSTRUCTION(TLBR)
|
||||
|
||||
static void TLBWrite(struct r4300_core* r4300, unsigned int idx)
|
||||
{
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
uint32_t pc_addr = *r4300_pc(r4300);
|
||||
|
||||
if (pc_addr >= r4300->cp0.tlb.entries[idx].start_even && pc_addr < r4300->cp0.tlb.entries[idx].end_even && r4300->cp0.tlb.entries[idx].v_even)
|
||||
@@ -1218,7 +1241,7 @@ static void TLBWrite(struct r4300_core* r4300, unsigned int idx)
|
||||
DECLARE_INSTRUCTION(TLBWR)
|
||||
{
|
||||
DECLARE_R4300
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
cp0_update_count(r4300);
|
||||
cp0_regs[CP0_RANDOM_REG] = (cp0_regs[CP0_COUNT_REG]/r4300->cp0.count_per_op % (32 - cp0_regs[CP0_WIRED_REG]))
|
||||
+ cp0_regs[CP0_WIRED_REG];
|
||||
@@ -1229,31 +1252,32 @@ DECLARE_INSTRUCTION(TLBWR)
|
||||
DECLARE_INSTRUCTION(TLBWI)
|
||||
{
|
||||
DECLARE_R4300
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
|
||||
TLBWrite(r4300, cp0_regs[CP0_INDEX_REG] & UINT32_C(0x3F));
|
||||
ADD_TO_PC(1);
|
||||
}
|
||||
|
||||
/* CP0 load/store instructions */
|
||||
#include <stdio.h>
|
||||
|
||||
DECLARE_INSTRUCTION(MFC0)
|
||||
static osal_inline uint64_t get_cp0_register(struct r4300_core* r4300, uint8_t reg)
|
||||
{
|
||||
DECLARE_R4300
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
uint64_t* cp0_latch = r4300_cp0_latch(&r4300->cp0);
|
||||
|
||||
switch(rfs)
|
||||
uint64_t data;
|
||||
switch (reg)
|
||||
{
|
||||
case CP0_RANDOM_REG:
|
||||
cp0_update_count(r4300);
|
||||
cp0_regs[CP0_RANDOM_REG] = (cp0_regs[CP0_COUNT_REG]/r4300->cp0.count_per_op % (32 - cp0_regs[CP0_WIRED_REG]))
|
||||
+ cp0_regs[CP0_WIRED_REG];
|
||||
rrt = SE32(cp0_regs[rfs]);
|
||||
data = cp0_regs[reg];
|
||||
break;
|
||||
case CP0_COUNT_REG:
|
||||
cp0_update_count(r4300);
|
||||
rrt = SE32(cp0_regs[rfs]);
|
||||
data = cp0_regs[reg];
|
||||
break;
|
||||
case CP0_UNUSED_7:
|
||||
case CP0_UNUSED_21:
|
||||
@@ -1262,90 +1286,53 @@ DECLARE_INSTRUCTION(MFC0)
|
||||
case CP0_UNUSED_24:
|
||||
case CP0_UNUSED_25:
|
||||
case CP0_UNUSED_31:
|
||||
rrt = (*cp0_latch);
|
||||
data = (*cp0_latch);
|
||||
break;
|
||||
default:
|
||||
rrt = SE32(cp0_regs[rfs]);
|
||||
data = cp0_regs[reg];
|
||||
break;
|
||||
}
|
||||
|
||||
ADD_TO_PC(1);
|
||||
return data;
|
||||
}
|
||||
|
||||
DECLARE_INSTRUCTION(DMFC0)
|
||||
static osal_inline void set_cp0_register(struct r4300_core* r4300, uint8_t reg, uint64_t value)
|
||||
{
|
||||
DECLARE_R4300
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
uint64_t* cp0_latch = r4300_cp0_latch(&r4300->cp0);
|
||||
|
||||
switch(rfs)
|
||||
{
|
||||
case CP0_RANDOM_REG:
|
||||
cp0_update_count(r4300);
|
||||
cp0_regs[CP0_RANDOM_REG] = (cp0_regs[CP0_COUNT_REG]/r4300->cp0.count_per_op % (32 - cp0_regs[CP0_WIRED_REG]))
|
||||
+ cp0_regs[CP0_WIRED_REG];
|
||||
rrt = cp0_regs[rfs];
|
||||
break;
|
||||
case CP0_COUNT_REG:
|
||||
cp0_update_count(r4300);
|
||||
rrt = cp0_regs[rfs];
|
||||
break;
|
||||
case CP0_EPC_REG:
|
||||
rrt = SE32(cp0_regs[rfs]);
|
||||
break;
|
||||
case CP0_UNUSED_7:
|
||||
case CP0_UNUSED_21:
|
||||
case CP0_UNUSED_22:
|
||||
case CP0_UNUSED_23:
|
||||
case CP0_UNUSED_24:
|
||||
case CP0_UNUSED_25:
|
||||
case CP0_UNUSED_31:
|
||||
rrt = (*cp0_latch);
|
||||
break;
|
||||
default:
|
||||
rrt = cp0_regs[rfs];
|
||||
break;
|
||||
}
|
||||
|
||||
ADD_TO_PC(1);
|
||||
}
|
||||
|
||||
DECLARE_INSTRUCTION(MTC0)
|
||||
{
|
||||
DECLARE_R4300
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
uint64_t* cp0_latch = r4300_cp0_latch(&r4300->cp0);
|
||||
int* cp0_cycle_count = r4300_cp0_cycle_count(&r4300->cp0);
|
||||
|
||||
(*cp0_latch) = rrt32;
|
||||
(*cp0_latch) = value;
|
||||
|
||||
switch(rfs)
|
||||
switch (reg)
|
||||
{
|
||||
case CP0_INDEX_REG:
|
||||
cp0_regs[CP0_INDEX_REG] = rrt32 & UINT32_C(0x8000003F);
|
||||
cp0_regs[CP0_INDEX_REG] = value & UINT32_C(0x8000003F);
|
||||
if ((cp0_regs[CP0_INDEX_REG] & UINT32_C(0x3F)) > UINT32_C(31))
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "MTC0 instruction writing Index register with TLB index > 31");
|
||||
*r4300_stop(r4300)=1;
|
||||
//DebugMessage(M64MSG_ERROR, "MTC0 instruction writing Index register with TLB index > 31");
|
||||
//*r4300_stop(r4300)=1;
|
||||
}
|
||||
break;
|
||||
case CP0_RANDOM_REG:
|
||||
break;
|
||||
case CP0_ENTRYLO0_REG:
|
||||
cp0_regs[CP0_ENTRYLO0_REG] = rrt32 & UINT32_C(0x3FFFFFFF);
|
||||
cp0_regs[CP0_ENTRYLO0_REG] = value & UINT32_C(0x3FFFFFFF);
|
||||
break;
|
||||
case CP0_ENTRYLO1_REG:
|
||||
cp0_regs[CP0_ENTRYLO1_REG] = rrt32 & UINT32_C(0x3FFFFFFF);
|
||||
cp0_regs[CP0_ENTRYLO1_REG] = value & UINT32_C(0x3FFFFFFF);
|
||||
break;
|
||||
case CP0_CONTEXT_REG:
|
||||
cp0_regs[CP0_CONTEXT_REG] = (rrt32 & UINT32_C(0xFF800000))
|
||||
| (cp0_regs[CP0_CONTEXT_REG] & UINT32_C(0x007FFFF0));
|
||||
// 0xffffffffff800000
|
||||
cp0_regs[CP0_CONTEXT_REG] = value & UINT64_C(0xffffffffff800000);
|
||||
break;
|
||||
case CP0_XCONTEXT_REG:
|
||||
//cp0_regs[CP0_XCONTEXT_REG] = value & UINT64_C(0xffffffffff800000);
|
||||
break;
|
||||
case CP0_PAGEMASK_REG:
|
||||
cp0_regs[CP0_PAGEMASK_REG] = rrt32 & UINT32_C(0x01FFE000);
|
||||
cp0_regs[CP0_PAGEMASK_REG] = value & UINT32_C(0x01FFE000);
|
||||
break;
|
||||
case CP0_WIRED_REG:
|
||||
cp0_regs[CP0_WIRED_REG] = rrt32 & UINT32_C(0x0000003F);
|
||||
cp0_regs[CP0_WIRED_REG] = value & UINT32_C(0x0000003F);
|
||||
cp0_regs[CP0_RANDOM_REG] = UINT32_C(31);
|
||||
break;
|
||||
case CP0_BADVADDR_REG:
|
||||
@@ -1355,10 +1342,10 @@ DECLARE_INSTRUCTION(MTC0)
|
||||
r4300->cp0.interrupt_unsafe_state |= INTR_UNSAFE_R4300;
|
||||
if (*cp0_cycle_count >= 0) { gen_interrupt(r4300); }
|
||||
r4300->cp0.interrupt_unsafe_state &= ~INTR_UNSAFE_R4300;
|
||||
translate_event_queue(&r4300->cp0, rrt32);
|
||||
translate_event_queue(&r4300->cp0, value);
|
||||
break;
|
||||
case CP0_ENTRYHI_REG:
|
||||
cp0_regs[CP0_ENTRYHI_REG] = rrt32 & UINT32_C(0xFFFFE0FF);
|
||||
cp0_regs[CP0_ENTRYHI_REG] = value & UINT32_C(0xFFFFE0FF);
|
||||
break;
|
||||
case CP0_COMPARE_REG:
|
||||
cp0_update_count(r4300);
|
||||
@@ -1367,21 +1354,21 @@ DECLARE_INSTRUCTION(MTC0)
|
||||
/* Add count_per_op to avoid wrong event order in case CP0_COUNT_REG == CP0_COMPARE_REG */
|
||||
cp0_regs[CP0_COUNT_REG] += r4300->cp0.count_per_op;
|
||||
*cp0_cycle_count += r4300->cp0.count_per_op;
|
||||
add_interrupt_event_count(&r4300->cp0, COMPARE_INT, rrt32);
|
||||
add_interrupt_event_count(&r4300->cp0, COMPARE_INT, value);
|
||||
cp0_regs[CP0_COUNT_REG] -= r4300->cp0.count_per_op;
|
||||
|
||||
/* Update next interrupt in case first event is COMPARE_INT */
|
||||
*cp0_cycle_count = cp0_regs[CP0_COUNT_REG] - r4300->cp0.q.first->data.count;
|
||||
cp0_regs[CP0_COMPARE_REG] = rrt32;
|
||||
cp0_regs[CP0_COMPARE_REG] = value;
|
||||
cp0_regs[CP0_CAUSE_REG] &= ~CP0_CAUSE_IP7;
|
||||
break;
|
||||
case CP0_STATUS_REG:
|
||||
rrt32 &= ~UINT32_C(0x080000); /* 19th bit isn't writable */
|
||||
value &= ~UINT32_C(0x080000); /* 19th bit isn't writable */
|
||||
|
||||
if((rrt32 & CP0_STATUS_FR) != (cp0_regs[CP0_STATUS_REG] & CP0_STATUS_FR))
|
||||
set_fpr_pointers(&r4300->cp1, rrt32);
|
||||
if((value & CP0_STATUS_FR) != (cp0_regs[CP0_STATUS_REG] & CP0_STATUS_FR))
|
||||
set_fpr_pointers(&r4300->cp1, value);
|
||||
|
||||
cp0_regs[CP0_STATUS_REG] = rrt32;
|
||||
cp0_regs[CP0_STATUS_REG] = value;
|
||||
ADD_TO_PC(1);
|
||||
cp0_update_count(r4300);
|
||||
r4300_check_interrupt(r4300, CP0_CAUSE_IP2, r4300->mi->regs[MI_INTR_REG] & r4300->mi->regs[MI_INTR_MASK_REG]); // ???
|
||||
@@ -1391,50 +1378,79 @@ DECLARE_INSTRUCTION(MTC0)
|
||||
return;
|
||||
case CP0_CAUSE_REG:
|
||||
cp0_regs[CP0_CAUSE_REG] &= ~(CP0_CAUSE_IP0 | CP0_CAUSE_IP1);
|
||||
cp0_regs[CP0_CAUSE_REG] |= rrt32 & (CP0_CAUSE_IP0 | CP0_CAUSE_IP1);
|
||||
cp0_regs[CP0_CAUSE_REG] |= value & (CP0_CAUSE_IP0 | CP0_CAUSE_IP1);
|
||||
break;
|
||||
case CP0_EPC_REG:
|
||||
cp0_regs[CP0_EPC_REG] = rrt32;
|
||||
cp0_regs[CP0_EPC_REG] = value;
|
||||
break;
|
||||
case CP0_PREVID_REG:
|
||||
break;
|
||||
case CP0_CONFIG_REG:
|
||||
cp0_regs[CP0_CONFIG_REG] = (rrt32 & UINT32_C(0x0000000F))
|
||||
cp0_regs[CP0_CONFIG_REG] = (value & UINT32_C(0x0000000F))
|
||||
| (cp0_regs[CP0_CONFIG_REG] & UINT32_C(0x00008000))
|
||||
| (cp0_regs[CP0_CONFIG_REG] & UINT32_C(0x7FFFFFFF));
|
||||
break;
|
||||
case CP0_LLADDR_REG:
|
||||
cp0_regs[CP0_LLADDR_REG] = rrt32;
|
||||
cp0_regs[CP0_LLADDR_REG] = value;
|
||||
break;
|
||||
case CP0_WATCHLO_REG:
|
||||
cp0_regs[CP0_WATCHLO_REG] = rrt32;
|
||||
cp0_regs[CP0_WATCHLO_REG] = value;
|
||||
break;
|
||||
case CP0_WATCHHI_REG:
|
||||
cp0_regs[CP0_WATCHHI_REG] = rrt32;
|
||||
break;
|
||||
case CP0_XCONTEXT_REG:
|
||||
cp0_regs[CP0_WATCHHI_REG] = value;
|
||||
break;
|
||||
case CP0_CACHEERR_REG:
|
||||
break;
|
||||
case CP0_PARITYERR_REG:
|
||||
cp0_regs[CP0_PARITYERR_REG] = rrt32 & UINT32_C(0x000000FF);
|
||||
cp0_regs[CP0_PARITYERR_REG] = value & UINT32_C(0x000000FF);
|
||||
break;
|
||||
case CP0_TAGLO_REG:
|
||||
cp0_regs[CP0_TAGLO_REG] = rrt32 & UINT32_C(0x0FFFFFC0);
|
||||
cp0_regs[CP0_TAGLO_REG] = value & UINT32_C(0x0FFFFFC0);
|
||||
break;
|
||||
case CP0_TAGHI_REG:
|
||||
cp0_regs[CP0_TAGHI_REG] = 0;
|
||||
break;
|
||||
case CP0_ERROREPC_REG:
|
||||
cp0_regs[CP0_ERROREPC_REG] = rrt32;
|
||||
cp0_regs[CP0_ERROREPC_REG] = value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_INSTRUCTION(MFC0)
|
||||
{
|
||||
DECLARE_R4300
|
||||
rrt32 = SE32(get_cp0_register(r4300, rfs));
|
||||
ADD_TO_PC(1);
|
||||
}
|
||||
|
||||
DECLARE_INSTRUCTION(DMFC0)
|
||||
{
|
||||
DECLARE_R4300
|
||||
rrt = get_cp0_register(r4300, rfs);
|
||||
ADD_TO_PC(1);
|
||||
}
|
||||
|
||||
DECLARE_INSTRUCTION(MTC0)
|
||||
{
|
||||
DECLARE_R4300
|
||||
set_cp0_register(r4300, rfs, rrt32);
|
||||
if (rfs == CP0_STATUS_REG)
|
||||
return;
|
||||
ADD_TO_PC(1);
|
||||
}
|
||||
|
||||
DECLARE_INSTRUCTION(DMTC0)
|
||||
{
|
||||
DECLARE_R4300
|
||||
set_cp0_register(r4300, rfs, rrt);
|
||||
if (rfs == CP0_STATUS_REG)
|
||||
return;
|
||||
ADD_TO_PC(1);
|
||||
}
|
||||
|
||||
|
||||
/* CP1 load/store instructions */
|
||||
|
||||
DECLARE_INSTRUCTION(LWC1)
|
||||
@@ -1517,7 +1533,7 @@ DECLARE_INSTRUCTION(DCFC1)
|
||||
DECLARE_R4300
|
||||
if (check_cop1_unusable(r4300)) { return; }
|
||||
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
|
||||
fpu_reset_cause(r4300_cp1_fcr31(&r4300->cp1));
|
||||
|
||||
@@ -1563,7 +1579,7 @@ DECLARE_INSTRUCTION(DCTC1)
|
||||
DECLARE_R4300
|
||||
if (check_cop1_unusable(r4300)) { return; }
|
||||
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
|
||||
fpu_reset_cause(r4300_cp1_fcr31(&r4300->cp1));
|
||||
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ struct new_dynarec_hot_state
|
||||
int64_t regs[32];
|
||||
int64_t hi;
|
||||
int64_t lo;
|
||||
uint32_t cp0_regs[32];
|
||||
uint64_t cp0_regs[32];
|
||||
uint64_t cp0_latch;
|
||||
float* cp1_regs_simple[32];
|
||||
double* cp1_regs_double[32];
|
||||
|
||||
@@ -76,7 +76,7 @@ static void InterpretOpcode(struct r4300_core* r4300);
|
||||
} \
|
||||
static void name##_IDLE(struct r4300_core* r4300, uint32_t op) \
|
||||
{ \
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); \
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); \
|
||||
int* cp0_cycle_count = r4300_cp0_cycle_count(&r4300->cp0); \
|
||||
const int take_jump = (condition); \
|
||||
if (cop1 && check_cop1_unusable(r4300)) return; \
|
||||
@@ -443,9 +443,11 @@ void InterpretOpcode(struct r4300_core* r4300)
|
||||
else NOP(r4300, 0);
|
||||
break;
|
||||
case 4: /* Coprocessor 0 opcode 4: MTC0 */
|
||||
case 5: /* Coprocessor 0 opcode 5: DMTC0 */
|
||||
MTC0(r4300, op);
|
||||
break;
|
||||
case 5: /* Coprocessor 0 opcode 5: DMTC0 */
|
||||
DMTC0(r4300, op);
|
||||
break;
|
||||
case 16: /* Coprocessor 0 opcode 16: TLB */
|
||||
switch (op & 0x3F) {
|
||||
case 1: TLBR(r4300, op); break;
|
||||
@@ -686,8 +688,7 @@ void InterpretOpcode(struct r4300_core* r4300)
|
||||
else NOP(r4300, 0);
|
||||
break;
|
||||
case 35: /* Major opcode 35: LW */
|
||||
if (RT_OF(op) != 0) LW(r4300, op);
|
||||
else NOP(r4300, 0);
|
||||
LW(r4300, op);
|
||||
break;
|
||||
case 36: /* Major opcode 36: LBU */
|
||||
if (RT_OF(op) != 0) LBU(r4300, op);
|
||||
|
||||
@@ -40,7 +40,7 @@ static uint32_t get_remaining_dma_length(struct ai_controller* ai)
|
||||
{
|
||||
unsigned int* next_ai_event;
|
||||
unsigned int remaining_dma_duration;
|
||||
const uint32_t* cp0_regs;
|
||||
const uint64_t* cp0_regs;
|
||||
|
||||
if (ai->fifo[0].duration == 0)
|
||||
return 0;
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "device/memory/memory.h"
|
||||
#include "device/rcp/mi/mi_controller.h"
|
||||
#include "device/rcp/rsp/rsp_core.h"
|
||||
#include "device/r4300/r4300_core.h"
|
||||
#include "plugin/plugin.h"
|
||||
|
||||
static void update_dpc_status(struct rdp_core* dp, uint32_t w)
|
||||
@@ -40,7 +41,11 @@ static void update_dpc_status(struct rdp_core* dp, uint32_t w)
|
||||
dp->dpc_regs[DPC_STATUS_REG] &= ~DPC_STATUS_FREEZE;
|
||||
|
||||
if (dp->do_on_unfreeze & DELAY_DP_INT)
|
||||
{
|
||||
signal_rcp_interrupt(dp->mi, MI_INTR_DP);
|
||||
|
||||
clear_rsp_wait(dp->sp, WAIT_PENDING_DP_SYNC);
|
||||
}
|
||||
if (dp->do_on_unfreeze & DELAY_UPDATESCREEN)
|
||||
gfx.updateScreen();
|
||||
dp->do_on_unfreeze = 0;
|
||||
@@ -51,6 +56,22 @@ static void update_dpc_status(struct rdp_core* dp, uint32_t w)
|
||||
if (w & DPC_CLR_FLUSH) dp->dpc_regs[DPC_STATUS_REG] &= ~DPC_STATUS_FLUSH;
|
||||
if (w & DPC_SET_FLUSH) dp->dpc_regs[DPC_STATUS_REG] |= DPC_STATUS_FLUSH;
|
||||
|
||||
if (w & DPC_CLR_TMEM_CTR)
|
||||
{
|
||||
dp->dpc_regs[DPC_STATUS_REG] &= ~DPC_STATUS_TMEM_BUSY;
|
||||
dp->dpc_regs[DPC_TMEM_REG] = 0;
|
||||
}
|
||||
if (w & DPC_CLR_PIPE_CTR)
|
||||
{
|
||||
dp->dpc_regs[DPC_STATUS_REG] &= ~DPC_STATUS_PIPE_BUSY;
|
||||
dp->dpc_regs[DPC_PIPEBUSY_REG] = 0;
|
||||
}
|
||||
if (w & DPC_CLR_CMD_CTR)
|
||||
{
|
||||
dp->dpc_regs[DPC_STATUS_REG] &= ~DPC_STATUS_CMD_BUSY;
|
||||
dp->dpc_regs[DPC_BUFBUSY_REG] = 0;
|
||||
}
|
||||
|
||||
/* clear clock counter */
|
||||
if (w & DPC_CLR_CLOCK_CTR) dp->dpc_regs[DPC_CLOCK_REG] = 0;
|
||||
}
|
||||
@@ -73,7 +94,7 @@ void poweron_rdp(struct rdp_core* dp)
|
||||
{
|
||||
memset(dp->dpc_regs, 0, DPC_REGS_COUNT*sizeof(uint32_t));
|
||||
memset(dp->dps_regs, 0, DPS_REGS_COUNT*sizeof(uint32_t));
|
||||
dp->dpc_regs[DPC_STATUS_REG] |= DPC_STATUS_START_GCLK;
|
||||
dp->dpc_regs[DPC_STATUS_REG] |= DPC_STATUS_START_GCLK | DPC_STATUS_PIPE_BUSY | DPC_STATUS_CBUF_READY;
|
||||
|
||||
dp->do_on_unfreeze = 0;
|
||||
|
||||
@@ -106,18 +127,37 @@ void write_dpc_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mas
|
||||
return;
|
||||
}
|
||||
|
||||
masked_write(&dp->dpc_regs[reg], value, mask);
|
||||
|
||||
switch(reg)
|
||||
{
|
||||
case DPC_START_REG:
|
||||
dp->dpc_regs[DPC_CURRENT_REG] = dp->dpc_regs[DPC_START_REG];
|
||||
if (!(dp->dpc_regs[DPC_STATUS_REG] & DPC_STATUS_START_VALID))
|
||||
{
|
||||
masked_write(&dp->dpc_regs[reg], value & UINT32_C(0xFFFFF8), mask);
|
||||
}
|
||||
dp->dpc_regs[DPC_STATUS_REG] |= DPC_STATUS_START_VALID;
|
||||
break;
|
||||
case DPC_END_REG:
|
||||
masked_write(&dp->dpc_regs[reg], value & UINT32_C(0xFFFFF8), mask);
|
||||
if (dp->dpc_regs[DPC_STATUS_REG] & DPC_STATUS_START_VALID)
|
||||
{
|
||||
dp->dpc_regs[DPC_CURRENT_REG] = dp->dpc_regs[DPC_START_REG];
|
||||
dp->dpc_regs[DPC_STATUS_REG] &= ~DPC_STATUS_START_VALID;
|
||||
}
|
||||
unprotect_framebuffers(&dp->fb);
|
||||
gfx.processRDPList();
|
||||
protect_framebuffers(&dp->fb);
|
||||
signal_rcp_interrupt(dp->mi, MI_INTR_DP);
|
||||
if (dp->mi->regs[MI_INTR_REG] & MI_INTR_DP)
|
||||
{
|
||||
dp->mi->regs[MI_INTR_REG] &= ~MI_INTR_DP;
|
||||
if (dp->dpc_regs[DPC_STATUS_REG] & DPC_STATUS_FREEZE) {
|
||||
dp->do_on_unfreeze |= DELAY_DP_INT;
|
||||
} else {
|
||||
add_interrupt_event(&dp->mi->r4300->cp0, DP_INT, dp->dpc_regs[DPC_CLOCK_REG]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
masked_write(&dp->dpc_regs[reg], value, mask);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -150,5 +190,7 @@ void rdp_interrupt_event(void* opaque)
|
||||
struct rdp_core* dp = (struct rdp_core*)opaque;
|
||||
|
||||
raise_rcp_interrupt(dp->mi, MI_INTR_DP);
|
||||
|
||||
clear_rsp_wait(dp->sp, WAIT_PENDING_DP_SYNC);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,11 @@ enum
|
||||
DPC_STATUS_FREEZE = 0x002,
|
||||
DPC_STATUS_FLUSH = 0x004,
|
||||
DPC_STATUS_START_GCLK = 0x008,
|
||||
DPC_STATUS_TMEM_BUSY = 0x010,
|
||||
DPC_STATUS_PIPE_BUSY = 0x020,
|
||||
DPC_STATUS_CMD_BUSY = 0x040,
|
||||
DPC_STATUS_CBUF_READY = 0x080,
|
||||
DPC_STATUS_DMA_BUSY = 0x100,
|
||||
DPC_STATUS_END_VALID = 0x200,
|
||||
DPC_STATUS_START_VALID = 0x400,
|
||||
/* DPC status - write */
|
||||
|
||||
+125
-104
@@ -76,16 +76,20 @@ static void do_sp_dma(struct rsp_core* sp, const struct sp_dma* dma)
|
||||
pre_framebuffer_read(&sp->dp->fb, dramaddr);
|
||||
|
||||
for(i=0; i<length; i++) {
|
||||
spmem[(memaddr^S8) & 0xfff] = dram[(dramaddr^S8) & 0x7fffff];
|
||||
spmem[(memaddr & 0xfff)^S8] = dram[(dramaddr^S8) & 0x7fffff];
|
||||
memaddr++;
|
||||
dramaddr++;
|
||||
}
|
||||
dramaddr+=skip;
|
||||
}
|
||||
|
||||
sp->regs[SP_MEM_ADDR_REG] = (memaddr & 0xfff) + (dma->memaddr & 0x1000);
|
||||
sp->regs[SP_DRAM_ADDR_REG] = dramaddr;
|
||||
|
||||
sp->regs[SP_MEM_ADDR_REG] = memaddr & 0xfff;
|
||||
sp->regs[SP_DRAM_ADDR_REG] = dramaddr & 0xffffff;
|
||||
sp->regs[SP_RD_LEN_REG] = 0xff8;
|
||||
sp->regs[SP_WR_LEN_REG] = 0xff8;
|
||||
}
|
||||
|
||||
/* schedule end of dma event */
|
||||
@@ -146,69 +150,87 @@ static void fifo_pop(struct rsp_core* sp)
|
||||
static void update_sp_status(struct rsp_core* sp, uint32_t w)
|
||||
{
|
||||
/* clear / set halt */
|
||||
if ((w & 0x3) == 0x1) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_HALT;
|
||||
if ((w & 0x3) == 0x2) sp->regs[SP_STATUS_REG] |= SP_STATUS_HALT;
|
||||
if ((w & SP_CLR_HALT) && !(w & SP_SET_HALT))
|
||||
{
|
||||
sp->rsp_wait &= ~WAIT_HALTED;
|
||||
sp->regs[SP_STATUS_REG] &= ~SP_STATUS_HALT;
|
||||
}
|
||||
if ((w & SP_SET_HALT) && !(w & SP_CLR_HALT))
|
||||
{
|
||||
remove_event(&sp->mi->r4300->cp0.q, SP_INT);
|
||||
sp->rsp_status = 0;
|
||||
sp->first_run = 1;
|
||||
sp->rsp_wait |= WAIT_HALTED;
|
||||
sp->regs[SP_STATUS_REG] |= SP_STATUS_HALT;
|
||||
}
|
||||
|
||||
/* clear broke */
|
||||
if (w & 0x4) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_BROKE;
|
||||
if (w & SP_CLR_BROKE) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_BROKE;
|
||||
|
||||
/* clear SP interrupt */
|
||||
if ((w & 0x18) == 0x8)
|
||||
if ((w & SP_CLR_INTR) && !(w & SP_SET_INTR))
|
||||
{
|
||||
clear_rcp_interrupt(sp->mi, MI_INTR_SP);
|
||||
}
|
||||
/* set SP interrupt */
|
||||
if ((w & 0x18) == 0x10)
|
||||
if ((w & SP_SET_INTR) && !(w & SP_CLR_INTR))
|
||||
{
|
||||
signal_rcp_interrupt(sp->mi, MI_INTR_SP);
|
||||
}
|
||||
|
||||
/* clear / set single step */
|
||||
if ((w & 0x60) == 0x20) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SSTEP;
|
||||
if ((w & 0x60) == 0x40) sp->regs[SP_STATUS_REG] |= SP_STATUS_SSTEP;
|
||||
if ((w & SP_CLR_SSTEP) && !(w & SP_SET_SSTEP)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SSTEP;
|
||||
if ((w & SP_SET_SSTEP) && !(w & SP_CLR_SSTEP)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SSTEP;
|
||||
|
||||
/* clear / set interrupt on break */
|
||||
if ((w & 0x180) == 0x80) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_INTR_BREAK;
|
||||
if ((w & 0x180) == 0x100) sp->regs[SP_STATUS_REG] |= SP_STATUS_INTR_BREAK;
|
||||
if ((w & SP_CLR_INTR_BREAK) && !(w & SP_SET_INTR_BREAK))
|
||||
{
|
||||
if (sp->rsp_wait & WAIT_PENDING_SP_INT_BROKE)
|
||||
{
|
||||
// If a game clears SP_SET_INTR_BREAK before the interrupt happens,
|
||||
// that means it would have been cleared before the BREAK command
|
||||
remove_event(&sp->mi->r4300->cp0.q, SP_INT);
|
||||
sp->rsp_wait &= ~WAIT_PENDING_SP_INT_BROKE;
|
||||
sp->regs[SP_STATUS_REG] = sp->rsp_status;
|
||||
sp->rsp_status = 0;
|
||||
}
|
||||
sp->regs[SP_STATUS_REG] &= ~SP_STATUS_INTR_BREAK;
|
||||
}
|
||||
if ((w & SP_SET_INTR_BREAK) && !(w & SP_CLR_INTR_BREAK)) sp->regs[SP_STATUS_REG] |= SP_STATUS_INTR_BREAK;
|
||||
|
||||
/* clear / set signal 0 */
|
||||
if ((w & 0x600) == 0x200) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG0;
|
||||
if ((w & 0x600) == 0x400) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG0;
|
||||
if ((w & SP_CLR_SIG0) && !(w & SP_SET_SIG0)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG0;
|
||||
if ((w & SP_SET_SIG0) && !(w & SP_CLR_SIG0)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG0;
|
||||
|
||||
/* clear / set signal 1 */
|
||||
if ((w & 0x1800) == 0x800) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG1;
|
||||
if ((w & 0x1800) == 0x1000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG1;
|
||||
if ((w & SP_CLR_SIG1) && !(w & SP_SET_SIG1)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG1;
|
||||
if ((w & SP_SET_SIG1) && !(w & SP_CLR_SIG1)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG1;
|
||||
|
||||
/* clear / set signal 2 */
|
||||
if ((w & 0x6000) == 0x2000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG2;
|
||||
if ((w & 0x6000) == 0x4000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG2;
|
||||
if ((w & SP_CLR_SIG2) && !(w & SP_SET_SIG2)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG2;
|
||||
if ((w & SP_SET_SIG2) && !(w & SP_CLR_SIG2)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG2;
|
||||
|
||||
/* clear / set signal 3 */
|
||||
if ((w & 0x18000) == 0x8000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG3;
|
||||
if ((w & 0x18000) == 0x10000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG3;
|
||||
if ((w & SP_CLR_SIG3) && !(w & SP_SET_SIG3)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG3;
|
||||
if ((w & SP_SET_SIG3) && !(w & SP_CLR_SIG3)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG3;
|
||||
|
||||
/* clear / set signal 4 */
|
||||
if ((w & 0x60000) == 0x20000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG4;
|
||||
if ((w & 0x60000) == 0x40000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG4;
|
||||
if ((w & SP_CLR_SIG4) && !(w & SP_SET_SIG4)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG4;
|
||||
if ((w & SP_SET_SIG4) && !(w & SP_CLR_SIG4)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG4;
|
||||
|
||||
/* clear / set signal 5 */
|
||||
if ((w & 0x180000) == 0x80000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG5;
|
||||
if ((w & 0x180000) == 0x100000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG5;
|
||||
if ((w & SP_CLR_SIG5) && !(w & SP_SET_SIG5)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG5;
|
||||
if ((w & SP_SET_SIG5) && !(w & SP_CLR_SIG5)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG5;
|
||||
|
||||
/* clear / set signal 6 */
|
||||
if ((w & 0x600000) == 0x200000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG6;
|
||||
if ((w & 0x600000) == 0x400000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG6;
|
||||
if ((w & SP_CLR_SIG6) && !(w & SP_SET_SIG6)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG6;
|
||||
if ((w & SP_SET_SIG6) && !(w & SP_CLR_SIG6)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG6;
|
||||
|
||||
/* clear / set signal 7 */
|
||||
if ((w & 0x1800000) == 0x800000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG7;
|
||||
if ((w & 0x1800000) == 0x1000000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG7;
|
||||
if ((w & SP_CLR_SIG7) && !(w & SP_SET_SIG7)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG7;
|
||||
if ((w & SP_SET_SIG7) && !(w & SP_CLR_SIG7)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG7;
|
||||
|
||||
if (sp->rsp_task_locked && (get_event(&sp->mi->r4300->cp0.q, SP_INT))) return;
|
||||
if (!((w & 0x3) == 1) && !(w & 0x4) && !sp->rsp_task_locked)
|
||||
return;
|
||||
|
||||
if (!(sp->regs[SP_STATUS_REG] & SP_STATUS_HALT))
|
||||
do_SP_Task(sp);
|
||||
do_SP_Task(sp);
|
||||
}
|
||||
|
||||
void init_rsp(struct rsp_core* sp,
|
||||
@@ -230,7 +252,9 @@ void poweron_rsp(struct rsp_core* sp)
|
||||
memset(sp->regs2, 0, SP_REGS2_COUNT*sizeof(uint32_t));
|
||||
memset(sp->fifo, 0, SP_DMA_FIFO_SIZE*sizeof(struct sp_dma));
|
||||
|
||||
sp->rsp_task_locked = 0;
|
||||
sp->rsp_status = 0;
|
||||
sp->first_run = 1;
|
||||
sp->rsp_wait = 0;
|
||||
sp->mi->r4300->cp0.interrupt_unsafe_state &= ~INTR_UNSAFE_RSP;
|
||||
sp->regs[SP_STATUS_REG] = 1;
|
||||
sp->regs[SP_RD_LEN_REG] = 0xff8;
|
||||
@@ -286,6 +310,12 @@ void write_rsp_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mas
|
||||
|
||||
switch(reg)
|
||||
{
|
||||
case SP_MEM_ADDR_REG:
|
||||
sp->regs[SP_MEM_ADDR_REG] &= 0x1ff8;
|
||||
break;
|
||||
case SP_DRAM_ADDR_REG:
|
||||
sp->regs[SP_DRAM_ADDR_REG] &= 0xfffff8;
|
||||
break;
|
||||
case SP_RD_LEN_REG:
|
||||
fifo_push(sp, SP_DMA_WRITE);
|
||||
break;
|
||||
@@ -317,7 +347,10 @@ void write_rsp_regs2(void* opaque, uint32_t address, uint32_t value, uint32_t ma
|
||||
uint32_t reg = rsp_reg2(address);
|
||||
|
||||
if (reg == SP_PC_REG)
|
||||
mask &= 0xffc;
|
||||
{
|
||||
masked_write(&sp->regs2[SP_PC_REG], value & 0xffc, mask);
|
||||
return;
|
||||
}
|
||||
|
||||
if (reg < SP_REGS2_COUNT)
|
||||
masked_write(&sp->regs2[reg], value, mask);
|
||||
@@ -325,97 +358,71 @@ void write_rsp_regs2(void* opaque, uint32_t address, uint32_t value, uint32_t ma
|
||||
|
||||
void do_SP_Task(struct rsp_core* sp)
|
||||
{
|
||||
uint32_t save_pc = sp->regs2[SP_PC_REG] & ~0xfff;
|
||||
if (sp->rsp_wait)
|
||||
return;
|
||||
if (get_event(&sp->mi->r4300->cp0.q, RSP_TSK_EVT))
|
||||
return;
|
||||
|
||||
uint32_t sp_delay_time;
|
||||
uint32_t saved_status = sp->regs[SP_STATUS_REG];
|
||||
uint32_t sp_bit_set = sp->mi->regs[MI_INTR_REG] & MI_INTR_SP;
|
||||
uint32_t dp_bit_set = sp->mi->regs[MI_INTR_REG] & MI_INTR_DP;
|
||||
|
||||
if (sp->mem[0xfc0/4] == 1)
|
||||
unprotect_framebuffers(&sp->dp->fb);
|
||||
uint32_t rsp_cycles = rsp.doRspCycles(sp->first_run) / 2;
|
||||
|
||||
if (sp->mi->regs[MI_INTR_REG] & MI_INTR_DP && !dp_bit_set)
|
||||
{
|
||||
unprotect_framebuffers(&sp->dp->fb);
|
||||
|
||||
//gfx.processDList();
|
||||
sp->regs2[SP_PC_REG] &= 0xfff;
|
||||
#if defined(PROFILE)
|
||||
timed_section_start(TIMED_SECTION_GFX);
|
||||
#endif
|
||||
rsp.doRspCycles(0xffffffff);
|
||||
#if defined(PROFILE)
|
||||
timed_section_end(TIMED_SECTION_GFX);
|
||||
#endif
|
||||
sp->regs2[SP_PC_REG] |= save_pc;
|
||||
new_frame();
|
||||
|
||||
if (sp->mi->regs[MI_INTR_REG] & MI_INTR_DP)
|
||||
{
|
||||
sp->mi->regs[MI_INTR_REG] &= ~MI_INTR_DP;
|
||||
if (sp->dp->dpc_regs[DPC_STATUS_REG] & DPC_STATUS_FREEZE) {
|
||||
sp->dp->do_on_unfreeze |= DELAY_DP_INT;
|
||||
} else {
|
||||
cp0_update_count(sp->mi->r4300);
|
||||
add_interrupt_event(&sp->mi->r4300->cp0, DP_INT, 4000);
|
||||
}
|
||||
sp->mi->regs[MI_INTR_REG] &= ~MI_INTR_DP;
|
||||
sp->rsp_wait |= WAIT_PENDING_DP_SYNC;
|
||||
if (sp->dp->dpc_regs[DPC_STATUS_REG] & DPC_STATUS_FREEZE) {
|
||||
sp->dp->do_on_unfreeze |= DELAY_DP_INT;
|
||||
} else {
|
||||
cp0_update_count(sp->mi->r4300);
|
||||
add_interrupt_event(&sp->mi->r4300->cp0, DP_INT, rsp_cycles + sp->dp->dpc_regs[DPC_CLOCK_REG]);
|
||||
}
|
||||
sp_delay_time = 1000;
|
||||
|
||||
protect_framebuffers(&sp->dp->fb);
|
||||
}
|
||||
else if (sp->mem[0xfc0/4] == 2)
|
||||
{
|
||||
//audio.processAList();
|
||||
sp->regs2[SP_PC_REG] &= 0xfff;
|
||||
#if defined(PROFILE)
|
||||
timed_section_start(TIMED_SECTION_AUDIO);
|
||||
#endif
|
||||
rsp.doRspCycles(0xffffffff);
|
||||
#if defined(PROFILE)
|
||||
timed_section_end(TIMED_SECTION_AUDIO);
|
||||
#endif
|
||||
sp->regs2[SP_PC_REG] |= save_pc;
|
||||
|
||||
sp_delay_time = 4000;
|
||||
sp->rsp_status = sp->regs[SP_STATUS_REG];
|
||||
if ((sp->regs[SP_STATUS_REG] & SP_STATUS_HALT) == 0)
|
||||
{
|
||||
add_interrupt_event(&sp->mi->r4300->cp0, RSP_TSK_EVT, rsp_cycles);
|
||||
sp->first_run = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sp->regs2[SP_PC_REG] &= 0xfff;
|
||||
rsp.doRspCycles(0xffffffff);
|
||||
sp->regs2[SP_PC_REG] |= save_pc;
|
||||
|
||||
sp_delay_time = 0;
|
||||
sp->rsp_wait |= WAIT_HALTED;
|
||||
sp->first_run = 1;
|
||||
}
|
||||
|
||||
sp->rsp_task_locked = 0;
|
||||
sp->mi->r4300->cp0.interrupt_unsafe_state &= ~INTR_UNSAFE_RSP;
|
||||
if ((sp->regs[SP_STATUS_REG] & (SP_STATUS_HALT | SP_STATUS_BROKE)) == 0)
|
||||
{
|
||||
sp->rsp_task_locked = 1;
|
||||
sp->mi->r4300->cp0.interrupt_unsafe_state |= INTR_UNSAFE_RSP;
|
||||
sp->mi->regs[MI_INTR_REG] |= MI_INTR_SP;
|
||||
}
|
||||
if (sp->mi->regs[MI_INTR_REG] & MI_INTR_SP)
|
||||
if ((sp->regs[SP_STATUS_REG] & SP_STATUS_BROKE) && (sp->regs[SP_STATUS_REG] & SP_STATUS_INTR_BREAK))
|
||||
{
|
||||
sp->rsp_wait |= WAIT_PENDING_SP_INT_BROKE;
|
||||
cp0_update_count(sp->mi->r4300);
|
||||
add_interrupt_event(&sp->mi->r4300->cp0, SP_INT, sp_delay_time);
|
||||
sp->mi->regs[MI_INTR_REG] &= ~MI_INTR_SP;
|
||||
add_interrupt_event(&sp->mi->r4300->cp0, SP_INT, rsp_cycles);
|
||||
sp->regs[SP_STATUS_REG] = saved_status;
|
||||
}
|
||||
else if (sp->mi->regs[MI_INTR_REG] & MI_INTR_SP && !sp_bit_set)
|
||||
{
|
||||
sp->rsp_wait |= WAIT_PENDING_SP_INT;
|
||||
cp0_update_count(sp->mi->r4300);
|
||||
add_interrupt_event(&sp->mi->r4300->cp0, SP_INT, rsp_cycles);
|
||||
}
|
||||
sp->mi->r4300->cp0.interrupt_unsafe_state |= INTR_UNSAFE_RSP;
|
||||
if (!sp_bit_set)
|
||||
sp->mi->regs[MI_INTR_REG] &= ~MI_INTR_SP;
|
||||
|
||||
sp->regs[SP_STATUS_REG] &=
|
||||
~(SP_STATUS_TASKDONE | SP_STATUS_BROKE | SP_STATUS_HALT);
|
||||
protect_framebuffers(&sp->dp->fb);
|
||||
}
|
||||
|
||||
void rsp_interrupt_event(void* opaque)
|
||||
{
|
||||
struct rsp_core* sp = (struct rsp_core*)opaque;
|
||||
|
||||
if (!sp->rsp_task_locked)
|
||||
{
|
||||
sp->regs[SP_STATUS_REG] |=
|
||||
SP_STATUS_TASKDONE | SP_STATUS_BROKE | SP_STATUS_HALT;
|
||||
}
|
||||
sp->regs[SP_STATUS_REG] = sp->rsp_status;
|
||||
sp->rsp_status = 0;
|
||||
sp->mi->r4300->cp0.interrupt_unsafe_state &= ~INTR_UNSAFE_RSP;
|
||||
raise_rcp_interrupt(sp->mi, MI_INTR_SP);
|
||||
|
||||
if ((sp->regs[SP_STATUS_REG] & SP_STATUS_INTR_BREAK) != 0)
|
||||
{
|
||||
raise_rcp_interrupt(sp->mi, MI_INTR_SP);
|
||||
}
|
||||
clear_rsp_wait(sp, WAIT_PENDING_SP_INT | WAIT_PENDING_SP_INT_BROKE);
|
||||
}
|
||||
|
||||
void rsp_end_of_dma_event(void* opaque)
|
||||
@@ -423,3 +430,17 @@ void rsp_end_of_dma_event(void* opaque)
|
||||
struct rsp_core* sp = (struct rsp_core*)opaque;
|
||||
fifo_pop(sp);
|
||||
}
|
||||
|
||||
void rsp_task_event(void* opaque)
|
||||
{
|
||||
struct rsp_core* sp = (struct rsp_core*)opaque;
|
||||
|
||||
do_SP_Task(sp);
|
||||
}
|
||||
|
||||
void clear_rsp_wait(struct rsp_core* sp, uint32_t value)
|
||||
{
|
||||
sp->rsp_wait &= ~value;
|
||||
|
||||
do_SP_Task(sp);
|
||||
}
|
||||
|
||||
@@ -55,6 +55,36 @@ enum
|
||||
SP_STATUS_SIG7 = 0x4000,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
/* SP_STATUS - write */
|
||||
SP_CLR_HALT = 0x0000001,
|
||||
SP_SET_HALT = 0x0000002,
|
||||
SP_CLR_BROKE = 0x0000004,
|
||||
SP_CLR_INTR = 0x0000008,
|
||||
SP_SET_INTR = 0x0000010,
|
||||
SP_CLR_SSTEP = 0x0000020,
|
||||
SP_SET_SSTEP = 0x0000040,
|
||||
SP_CLR_INTR_BREAK = 0x0000080,
|
||||
SP_SET_INTR_BREAK = 0x0000100,
|
||||
SP_CLR_SIG0 = 0x0000200,
|
||||
SP_SET_SIG0 = 0x0000400,
|
||||
SP_CLR_SIG1 = 0x0000800,
|
||||
SP_SET_SIG1 = 0x0001000,
|
||||
SP_CLR_SIG2 = 0x0002000,
|
||||
SP_SET_SIG2 = 0x0004000,
|
||||
SP_CLR_SIG3 = 0x0008000,
|
||||
SP_SET_SIG3 = 0x0010000,
|
||||
SP_CLR_SIG4 = 0x0020000,
|
||||
SP_SET_SIG4 = 0x0040000,
|
||||
SP_CLR_SIG5 = 0x0080000,
|
||||
SP_SET_SIG5 = 0x0100000,
|
||||
SP_CLR_SIG6 = 0x0200000,
|
||||
SP_SET_SIG6 = 0x0400000,
|
||||
SP_CLR_SIG7 = 0x0800000,
|
||||
SP_SET_SIG7 = 0x1000000,
|
||||
};
|
||||
|
||||
enum sp_registers
|
||||
{
|
||||
SP_MEM_ADDR_REG,
|
||||
@@ -81,6 +111,14 @@ enum sp_dma_dir
|
||||
SP_DMA_WRITE
|
||||
};
|
||||
|
||||
enum sp_rsp_wait
|
||||
{
|
||||
WAIT_PENDING_SP_INT_BROKE = 0x1,
|
||||
WAIT_PENDING_SP_INT = 0x2,
|
||||
WAIT_PENDING_DP_SYNC = 0x4,
|
||||
WAIT_HALTED = 0x8
|
||||
};
|
||||
|
||||
enum { SP_DMA_FIFO_SIZE = 2} ;
|
||||
|
||||
struct sp_dma
|
||||
@@ -96,7 +134,9 @@ struct rsp_core
|
||||
uint32_t* mem;
|
||||
uint32_t regs[SP_REGS_COUNT];
|
||||
uint32_t regs2[SP_REGS2_COUNT];
|
||||
uint32_t rsp_task_locked;
|
||||
uint32_t rsp_status;
|
||||
uint32_t first_run;
|
||||
uint32_t rsp_wait;
|
||||
|
||||
struct mi_controller* mi;
|
||||
struct rdp_core* dp;
|
||||
@@ -141,4 +181,7 @@ void do_SP_Task(struct rsp_core* sp);
|
||||
void rsp_interrupt_event(void* opaque);
|
||||
void rsp_end_of_dma_event(void* opaque);
|
||||
|
||||
void rsp_task_event(void* opaque);
|
||||
void clear_rsp_wait(struct rsp_core* sp, uint32_t value);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -87,7 +87,7 @@ void read_vi_regs(void* opaque, uint32_t address, uint32_t* value)
|
||||
{
|
||||
struct vi_controller* vi = (struct vi_controller*)opaque;
|
||||
uint32_t reg = vi_reg(address);
|
||||
const uint32_t* cp0_regs = r4300_cp0_regs(&vi->mi->r4300->cp0);
|
||||
const uint64_t* cp0_regs = r4300_cp0_regs(&vi->mi->r4300->cp0);
|
||||
|
||||
if (reg == VI_CURRENT_REG)
|
||||
{
|
||||
|
||||
+6
-6
@@ -334,8 +334,10 @@ static m64p_error init_video_capture_backend(const struct video_capture_backend_
|
||||
DebugMessage(M64MSG_INFO, "Using video capture backend: %s", (*ivcap)->name);
|
||||
}
|
||||
else {
|
||||
DebugMessage(M64MSG_ERROR, "Failed to initialize video capture backend %s: %s", (*ivcap)->name, CoreErrorMessage(err));
|
||||
*ivcap = NULL;
|
||||
DebugMessage(M64MSG_ERROR, "Failed to initialize video capture backend %s: %s, falling back to dummy backend", (*ivcap)->name, CoreErrorMessage(err));
|
||||
/* fallback to dummy backend */
|
||||
*ivcap = get_video_capture_backend(NULL);
|
||||
(*ivcap)->init(vcap, section);
|
||||
}
|
||||
|
||||
free(section);
|
||||
@@ -1069,6 +1071,7 @@ static void pause_loop(void)
|
||||
* Allow the core to perform various things */
|
||||
void new_vi(void)
|
||||
{
|
||||
new_frame();
|
||||
#if defined(PROFILE)
|
||||
timed_sections_refresh();
|
||||
#endif
|
||||
@@ -1704,10 +1707,7 @@ m64p_error main_run(void)
|
||||
|
||||
/* init GbCamera backend specified in the configuration file */
|
||||
init_video_capture_backend(&igbcam_backend, &gbcam_backend,
|
||||
g_CoreConfig, "GbCameraVideoCaptureBackend1");
|
||||
|
||||
/* open GB cam video device */
|
||||
igbcam_backend->open(gbcam_backend, M64282FP_SENSOR_W, M64282FP_SENSOR_H);
|
||||
g_CoreConfig, "GbCameraVideoCaptureBackend1");
|
||||
|
||||
/* open storage files, provide default content if not present */
|
||||
open_mpk_file(&mpk);
|
||||
|
||||
+1
-1
@@ -818,7 +818,7 @@ void netplay_check_sync(struct cp0* cp0)
|
||||
|
||||
if (l_vi_counter % 600 == 0)
|
||||
{
|
||||
const uint32_t* cp0_regs = r4300_cp0_regs(cp0);
|
||||
const uint64_t* cp0_regs = r4300_cp0_regs(cp0);
|
||||
|
||||
l_check_sync_packet->data[0] = UDP_SYNC_DATA;
|
||||
netplay_write32(l_vi_counter, &l_check_sync_packet->data[1]); //current VI count
|
||||
|
||||
+28
-17
@@ -63,7 +63,7 @@ enum { GB_CART_FINGERPRINT_OFFSET = 0x134 };
|
||||
enum { DD_DISK_ID_OFFSET = 0x43670 };
|
||||
|
||||
static const char* savestate_magic = "M64+SAVE";
|
||||
static const int savestate_latest_version = 0x00010900; /* 1.9 */
|
||||
static const int savestate_latest_version = 0x00020000; /* 2.0 */
|
||||
static const unsigned char pj64_magic[4] = { 0xC8, 0xA6, 0xD8, 0x23 };
|
||||
|
||||
static savestates_job job = savestates_job_nothing;
|
||||
@@ -208,7 +208,7 @@ static int savestates_load_m64p(struct device* dev, char *filepath)
|
||||
unsigned char using_tlb_data[4];
|
||||
unsigned char data_0001_0200[4096]; // 4k for extra state from v1.2
|
||||
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&dev->r4300.cp0);
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(&dev->r4300.cp0);
|
||||
|
||||
SDL_LockMutex(savestates_lock);
|
||||
|
||||
@@ -561,8 +561,8 @@ static int savestates_load_m64p(struct device* dev, char *filepath)
|
||||
|
||||
unsigned int enabled = ALIGNED_GETDATA(curr, uint32_t);
|
||||
unsigned int bank = ALIGNED_GETDATA(curr, uint32_t);
|
||||
unsigned int access_mode = ALIGNED_GETDATA(curr, uint32_t);
|
||||
unsigned int access_mode_changed = ALIGNED_GETDATA(curr, uint32_t);
|
||||
unsigned int cart_enabled = ALIGNED_GETDATA(curr, uint32_t);
|
||||
unsigned int reset_state = ALIGNED_GETDATA(curr, uint32_t);
|
||||
COPYARRAY(gb_fingerprint, curr, uint8_t, GB_CART_FINGERPRINT_SIZE);
|
||||
if (gb_fingerprint[0] != 0) {
|
||||
rom_bank = ALIGNED_GETDATA(curr, uint32_t);
|
||||
@@ -581,8 +581,8 @@ static int savestates_load_m64p(struct device* dev, char *filepath)
|
||||
/* init transferpak state if enabled and not controlled by input plugin */
|
||||
dev->transferpaks[i].enabled = enabled;
|
||||
dev->transferpaks[i].bank = bank;
|
||||
dev->transferpaks[i].access_mode = access_mode;
|
||||
dev->transferpaks[i].access_mode_changed = access_mode_changed;
|
||||
dev->transferpaks[i].cart_enabled = cart_enabled;
|
||||
dev->transferpaks[i].reset_state = reset_state;
|
||||
|
||||
/* if it holds a valid cartridge init gbcart */
|
||||
if (dev->transferpaks[i].gb_cart != NULL
|
||||
@@ -706,8 +706,8 @@ static int savestates_load_m64p(struct device* dev, char *filepath)
|
||||
|
||||
unsigned int enabled = GETDATA(curr, uint32_t);
|
||||
unsigned int bank = GETDATA(curr, uint32_t);
|
||||
unsigned int access_mode = GETDATA(curr, uint32_t);
|
||||
unsigned int access_mode_changed = GETDATA(curr, uint32_t);
|
||||
unsigned int cart_enabled = GETDATA(curr, uint32_t);
|
||||
unsigned int reset_state = GETDATA(curr, uint32_t);
|
||||
COPYARRAY(gb_fingerprint, curr, uint8_t, GB_CART_FINGERPRINT_SIZE);
|
||||
if (gb_fingerprint[0] != 0) {
|
||||
rom_bank = GETDATA(curr, uint32_t);
|
||||
@@ -726,8 +726,8 @@ static int savestates_load_m64p(struct device* dev, char *filepath)
|
||||
/* init transferpak state if enabled and not controlled by input plugin */
|
||||
dev->transferpaks[i].enabled = enabled;
|
||||
dev->transferpaks[i].bank = bank;
|
||||
dev->transferpaks[i].access_mode = access_mode;
|
||||
dev->transferpaks[i].access_mode_changed = access_mode_changed;
|
||||
dev->transferpaks[i].cart_enabled = cart_enabled;
|
||||
dev->transferpaks[i].reset_state = reset_state;
|
||||
|
||||
/* if it holds a valid cartridge init gbcart */
|
||||
if (dev->transferpaks[i].gb_cart != NULL
|
||||
@@ -887,6 +887,14 @@ static int savestates_load_m64p(struct device* dev, char *filepath)
|
||||
*r4300_cp0_latch(&dev->r4300.cp0) = GETDATA(curr, uint64_t);
|
||||
*r4300_cp2_latch(&dev->r4300.cp2) = GETDATA(curr, uint64_t);
|
||||
}
|
||||
|
||||
if (version >= 0x00020000)
|
||||
{
|
||||
/* extra rsp state */
|
||||
dev->sp.rsp_status = GETDATA(curr, uint32_t);
|
||||
dev->sp.first_run = GETDATA(curr, uint32_t);
|
||||
dev->sp.rsp_wait = GETDATA(curr, uint32_t);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -958,7 +966,6 @@ static int savestates_load_m64p(struct device* dev, char *filepath)
|
||||
/* reset fb state */
|
||||
poweron_fb(&dev->dp.fb);
|
||||
|
||||
dev->sp.rsp_task_locked = 0;
|
||||
dev->r4300.cp0.interrupt_unsafe_state = 0;
|
||||
|
||||
*r4300_cp0_last_addr(&dev->r4300.cp0) = *r4300_pc(&dev->r4300);
|
||||
@@ -983,7 +990,7 @@ static int savestates_load_pj64(struct device* dev,
|
||||
size_t savestateSize;
|
||||
unsigned char *savestateData, *curr;
|
||||
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&dev->r4300.cp0);
|
||||
uint64_t* cp0_regs = r4300_cp0_regs(&dev->r4300.cp0);
|
||||
|
||||
/* Read and check Project64 magic number. */
|
||||
if (!read_func(handle, header, 8))
|
||||
@@ -1262,7 +1269,6 @@ static int savestates_load_pj64(struct device* dev,
|
||||
// No flashram info in pj64 savestate.
|
||||
poweron_flashram(&dev->cart.flashram);
|
||||
|
||||
dev->sp.rsp_task_locked = 0;
|
||||
dev->r4300.cp0.interrupt_unsafe_state = 0;
|
||||
|
||||
/* extra fb state */
|
||||
@@ -1537,7 +1543,7 @@ static int savestates_save_m64p(const struct device* dev, char *filepath)
|
||||
char *curr;
|
||||
|
||||
/* OK to cast away const qualifier */
|
||||
const uint32_t* cp0_regs = r4300_cp0_regs((struct cp0*)&dev->r4300.cp0);
|
||||
const uint64_t* cp0_regs = r4300_cp0_regs((struct cp0*)&dev->r4300.cp0);
|
||||
|
||||
save = malloc(sizeof(*save));
|
||||
if (!save) {
|
||||
@@ -1805,8 +1811,8 @@ static int savestates_save_m64p(const struct device* dev, char *filepath)
|
||||
for (i = 0; i < GAME_CONTROLLERS_COUNT; ++i) {
|
||||
PUTDATA(curr, uint32_t, dev->transferpaks[i].enabled);
|
||||
PUTDATA(curr, uint32_t, dev->transferpaks[i].bank);
|
||||
PUTDATA(curr, uint32_t, dev->transferpaks[i].access_mode);
|
||||
PUTDATA(curr, uint32_t, dev->transferpaks[i].access_mode_changed);
|
||||
PUTDATA(curr, uint32_t, dev->transferpaks[i].cart_enabled);
|
||||
PUTDATA(curr, uint32_t, dev->transferpaks[i].reset_state);
|
||||
|
||||
if (dev->transferpaks[i].gb_cart == NULL) {
|
||||
uint8_t gb_fingerprint[GB_CART_FINGERPRINT_SIZE];
|
||||
@@ -1924,6 +1930,11 @@ static int savestates_save_m64p(const struct device* dev, char *filepath)
|
||||
PUTDATA(curr, uint64_t, *r4300_cp0_latch((struct cp0*)&dev->r4300.cp0));
|
||||
PUTDATA(curr, uint64_t, *r4300_cp2_latch((struct cp2*)&dev->r4300.cp2));
|
||||
|
||||
/* rsp state (since 2.0) */
|
||||
PUTDATA(curr, uint32_t, dev->sp.rsp_status);
|
||||
PUTDATA(curr, uint32_t, dev->sp.first_run);
|
||||
PUTDATA(curr, uint32_t, dev->sp.rsp_wait);
|
||||
|
||||
init_work(&save->work, savestates_save_m64p_work);
|
||||
queue_work(&save->work);
|
||||
|
||||
@@ -1940,7 +1951,7 @@ static int savestates_save_pj64(const struct device* dev,
|
||||
size_t savestateSize;
|
||||
unsigned char *savestateData, *curr;
|
||||
|
||||
const uint32_t* cp0_regs = r4300_cp0_regs((struct cp0*)&dev->r4300.cp0);
|
||||
const uint64_t* cp0_regs = r4300_cp0_regs((struct cp0*)&dev->r4300.cp0);
|
||||
|
||||
// Allocate memory for the save state data
|
||||
savestateSize = 8 + SaveRDRAMSize + 0x2754;
|
||||
|
||||
+15
-9
@@ -152,21 +152,27 @@ static char *GetNextScreenshotPath(void)
|
||||
if (*pccNameChar == 0)
|
||||
{
|
||||
// generate the base name of the screenshot
|
||||
// add the ROM name, convert to lowercase, convert spaces to underscores
|
||||
strcpy(ScreenshotFileName, ROM_PARAMS.headername);
|
||||
for (pch = ScreenshotFileName; *pch != '\0'; pch++)
|
||||
*pch = ((*pch == ' ') || (*pch == ':')) ? '_' : tolower(*pch);
|
||||
// add the ROM name and convert to lowercase
|
||||
if (ROM_PARAMS.headername[0] != 0)
|
||||
{
|
||||
strcpy(ScreenshotFileName, ROM_PARAMS.headername);
|
||||
for (pch = ScreenshotFileName; *pch != '\0'; pch++)
|
||||
*pch = tolower(*pch);
|
||||
}
|
||||
else
|
||||
{
|
||||
// fallback to using MD5 when there's no internal ROM name set
|
||||
strcpy(ScreenshotFileName, ROM_SETTINGS.MD5);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ShiftJis2UTF8((unsigned char *) ROM_PARAMS.headername, (unsigned char *) ScreenshotFileName, sizeof(ScreenshotFileName));
|
||||
for (pch = ScreenshotFileName; *pch != '\0'; pch++)
|
||||
{
|
||||
if (*pch == ' ' || *pch == ':')
|
||||
*pch = '_';
|
||||
}
|
||||
}
|
||||
|
||||
// sanitize filename
|
||||
string_replace_chars(ScreenshotFileName, " :<>\"/\\|?*", '_');
|
||||
|
||||
strcat(ScreenshotFileName, "-###.png");
|
||||
|
||||
// add the base path to the screenshot file name
|
||||
|
||||
+1
-1
@@ -71,7 +71,7 @@ impl GcAdapter {
|
||||
})
|
||||
.ok_or(rusb::Error::NoDevice)?;
|
||||
|
||||
let mut handle = device.open()?;
|
||||
let handle = device.open()?;
|
||||
|
||||
if handle.kernel_driver_active(0).unwrap_or(false) {
|
||||
handle.detach_kernel_driver(0)?;
|
||||
|
||||
+8
-12
@@ -359,25 +359,21 @@ impl BUTTONS__bindgen_ty_1 {
|
||||
}
|
||||
#[inline]
|
||||
pub fn X_AXIS(&self) -> ::std::os::raw::c_int {
|
||||
unsafe { ::std::mem::transmute(self._bitfield_1.get(16usize, 8u8) as u32) }
|
||||
u32::cast_signed(self._bitfield_1.get(16usize, 8u8) as u32)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_X_AXIS(&mut self, val: ::std::os::raw::c_int) {
|
||||
unsafe {
|
||||
let val: u32 = ::std::mem::transmute(val);
|
||||
self._bitfield_1.set(16usize, 8u8, val as u64)
|
||||
}
|
||||
let val: u32 = i32::cast_unsigned(val);
|
||||
self._bitfield_1.set(16usize, 8u8, val as u64)
|
||||
}
|
||||
#[inline]
|
||||
pub fn Y_AXIS(&self) -> ::std::os::raw::c_int {
|
||||
unsafe { ::std::mem::transmute(self._bitfield_1.get(24usize, 8u8) as u32) }
|
||||
u32::cast_signed(self._bitfield_1.get(24usize, 8u8) as u32)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_Y_AXIS(&mut self, val: ::std::os::raw::c_int) {
|
||||
unsafe {
|
||||
let val: u32 = ::std::mem::transmute(val);
|
||||
self._bitfield_1.set(24usize, 8u8, val as u64)
|
||||
}
|
||||
let val: u32 = i32::cast_unsigned(val);
|
||||
self._bitfield_1.set(24usize, 8u8, val as u64)
|
||||
}
|
||||
#[inline]
|
||||
pub fn new_bitfield_1(
|
||||
@@ -466,11 +462,11 @@ impl BUTTONS__bindgen_ty_1 {
|
||||
Reserved2 as u64
|
||||
});
|
||||
__bindgen_bitfield_unit.set(16usize, 8u8, {
|
||||
let X_AXIS: u32 = unsafe { ::std::mem::transmute(X_AXIS) };
|
||||
let X_AXIS: u32 = i32::cast_unsigned(X_AXIS);
|
||||
X_AXIS as u64
|
||||
});
|
||||
__bindgen_bitfield_unit.set(24usize, 8u8, {
|
||||
let Y_AXIS: u32 = unsafe { ::std::mem::transmute(Y_AXIS) };
|
||||
let Y_AXIS: u32 = i32::cast_unsigned(Y_AXIS);
|
||||
Y_AXIS as u64
|
||||
});
|
||||
__bindgen_bitfield_unit
|
||||
|
||||
+8
-12
@@ -359,25 +359,21 @@ impl BUTTONS__bindgen_ty_1 {
|
||||
}
|
||||
#[inline]
|
||||
pub fn X_AXIS(&self) -> ::std::os::raw::c_int {
|
||||
unsafe { ::std::mem::transmute(self._bitfield_1.get(16usize, 8u8) as u32) }
|
||||
u32::cast_signed(self._bitfield_1.get(16usize, 8u8) as u32)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_X_AXIS(&mut self, val: ::std::os::raw::c_int) {
|
||||
unsafe {
|
||||
let val: u32 = ::std::mem::transmute(val);
|
||||
self._bitfield_1.set(16usize, 8u8, val as u64)
|
||||
}
|
||||
let val: u32 = i32::cast_unsigned(val);
|
||||
self._bitfield_1.set(16usize, 8u8, val as u64)
|
||||
}
|
||||
#[inline]
|
||||
pub fn Y_AXIS(&self) -> ::std::os::raw::c_int {
|
||||
unsafe { ::std::mem::transmute(self._bitfield_1.get(24usize, 8u8) as u32) }
|
||||
u32::cast_signed(self._bitfield_1.get(24usize, 8u8) as u32)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_Y_AXIS(&mut self, val: ::std::os::raw::c_int) {
|
||||
unsafe {
|
||||
let val: u32 = ::std::mem::transmute(val);
|
||||
self._bitfield_1.set(24usize, 8u8, val as u64)
|
||||
}
|
||||
let val: u32 = i32::cast_unsigned(val);
|
||||
self._bitfield_1.set(24usize, 8u8, val as u64)
|
||||
}
|
||||
#[inline]
|
||||
pub fn new_bitfield_1(
|
||||
@@ -466,11 +462,11 @@ impl BUTTONS__bindgen_ty_1 {
|
||||
Reserved2 as u64
|
||||
});
|
||||
__bindgen_bitfield_unit.set(16usize, 8u8, {
|
||||
let X_AXIS: u32 = unsafe { ::std::mem::transmute(X_AXIS) };
|
||||
let X_AXIS: u32 = i32::cast_unsigned(X_AXIS);
|
||||
X_AXIS as u64
|
||||
});
|
||||
__bindgen_bitfield_unit.set(24usize, 8u8, {
|
||||
let Y_AXIS: u32 = unsafe { ::std::mem::transmute(Y_AXIS) };
|
||||
let Y_AXIS: u32 = i32::cast_unsigned(Y_AXIS);
|
||||
Y_AXIS as u64
|
||||
});
|
||||
__bindgen_bitfield_unit
|
||||
|
||||
+9
-2
@@ -129,13 +129,20 @@ void hle_execute(struct hle_t* hle)
|
||||
|
||||
if (!match)
|
||||
{
|
||||
/* wrap around when needed */
|
||||
if (cached_ucodes->count >= CACHED_UCODES_MAX_SIZE)
|
||||
cached_ucodes->count = 0;
|
||||
|
||||
info = &cached_ucodes->infos[cached_ucodes->count];
|
||||
info->uc_start = uc_start;
|
||||
info->uc_dstart = uc_dstart;
|
||||
info->uc_dsize = uc_dsize;
|
||||
info->uc_pfunc = task_detection(hle);
|
||||
cached_ucodes->count++;
|
||||
assert(cached_ucodes->count <= CACHED_UCODES_MAX_SIZE);
|
||||
|
||||
/* ensure we stay within bounds */
|
||||
if (cached_ucodes->count < CACHED_UCODES_MAX_SIZE)
|
||||
cached_ucodes->count++;
|
||||
|
||||
assert(info->uc_pfunc != NULL);
|
||||
}
|
||||
|
||||
|
||||
+10
-29
@@ -20,8 +20,6 @@ RSP::CPU cpu;
|
||||
#else
|
||||
RSP::JIT::CPU cpu;
|
||||
#endif
|
||||
short MFC0_count[32];
|
||||
int SP_STATUS_TIMEOUT;
|
||||
} // namespace RSP
|
||||
|
||||
extern "C"
|
||||
@@ -53,47 +51,33 @@ extern "C"
|
||||
|
||||
EXPORT unsigned int CALL DoRspCycles(unsigned int cycles)
|
||||
{
|
||||
if (*RSP::rsp.SP_STATUS_REG & (SP_STATUS_HALT | SP_STATUS_BROKE))
|
||||
return 0;
|
||||
|
||||
// We don't know if Mupen from the outside invalidated our IMEM.
|
||||
RSP::cpu.invalidate_imem();
|
||||
if (cycles)
|
||||
{
|
||||
RSP::cpu.get_state().last_instruction_type = RSP::VU_INSTRUCTION;
|
||||
RSP::cpu.get_state().instruction_pipeline = 0;
|
||||
RSP::cpu.invalidate_imem();
|
||||
}
|
||||
|
||||
// Run CPU until we either break or we need to fire an IRQ.
|
||||
RSP::cpu.get_state().pc = *RSP::rsp.SP_PC_REG & 0xfff;
|
||||
RSP::cpu.get_state().instruction_count = 0;
|
||||
|
||||
#ifdef INTENSE_DEBUG
|
||||
fprintf(stderr, "RUN TASK: %u\n", RSP::cpu.get_state().pc);
|
||||
log_rsp_mem_parallel();
|
||||
#endif
|
||||
|
||||
for (auto &count : RSP::MFC0_count)
|
||||
count = 0;
|
||||
|
||||
while (!(*RSP::rsp.SP_STATUS_REG & SP_STATUS_HALT))
|
||||
{
|
||||
auto mode = RSP::cpu.run();
|
||||
if (mode == RSP::MODE_CHECK_FLAGS && (*RSP::cpu.get_state().cp0.irq & 1))
|
||||
break;
|
||||
if (mode == RSP::MODE_EXIT)
|
||||
break;
|
||||
}
|
||||
|
||||
*RSP::rsp.SP_PC_REG = 0x04001000 | (RSP::cpu.get_state().pc & 0xffc);
|
||||
|
||||
// From CXD4.
|
||||
if (*RSP::rsp.SP_STATUS_REG & SP_STATUS_BROKE)
|
||||
return cycles;
|
||||
else if (*RSP::cpu.get_state().cp0.irq & 1)
|
||||
RSP::rsp.CheckInterrupts();
|
||||
else if (*RSP::rsp.SP_STATUS_REG & SP_STATUS_HALT)
|
||||
return cycles;
|
||||
else if (*RSP::rsp.SP_SEMAPHORE_REG != 0) // Semaphore lock fixes.
|
||||
{
|
||||
}
|
||||
else
|
||||
RSP::SP_STATUS_TIMEOUT = 16; // From now on, wait 16 times, not 0x7fff
|
||||
|
||||
// CPU restarts with the correct SIGs.
|
||||
*RSP::rsp.SP_STATUS_REG &= ~SP_STATUS_HALT;
|
||||
*RSP::rsp.SP_PC_REG = (RSP::cpu.get_state().pc & 0xffc);
|
||||
|
||||
return cycles;
|
||||
}
|
||||
@@ -157,9 +141,6 @@ extern "C"
|
||||
*cr[RSP::CP0_REGISTER_SP_STATUS] = SP_STATUS_HALT;
|
||||
RSP::cpu.get_state().cp0.irq = RSP::rsp.MI_INTR_REG;
|
||||
|
||||
// From CXD4.
|
||||
RSP::SP_STATUS_TIMEOUT = 0x7fff;
|
||||
|
||||
RSP::cpu.set_dmem(reinterpret_cast<uint32_t *>(Rsp_Info.DMEM));
|
||||
RSP::cpu.set_imem(reinterpret_cast<uint32_t *>(Rsp_Info.IMEM));
|
||||
RSP::cpu.set_rdram(reinterpret_cast<uint32_t *>(Rsp_Info.RDRAM));
|
||||
|
||||
+130
-87
@@ -6,8 +6,6 @@
|
||||
namespace RSP
|
||||
{
|
||||
extern RSP_INFO rsp;
|
||||
extern short MFC0_count[32];
|
||||
extern int SP_STATUS_TIMEOUT;
|
||||
} // namespace RSP
|
||||
#endif
|
||||
|
||||
@@ -28,34 +26,15 @@ extern "C"
|
||||
rsp->sr[rt] = res;
|
||||
|
||||
#ifdef PARALLEL_INTEGRATION
|
||||
if (rd == CP0_REGISTER_SP_STATUS)
|
||||
{
|
||||
// Might be waiting for the CPU to set a signal bit on the STATUS register. Increment timeout
|
||||
RSP::MFC0_count[rt] += 1;
|
||||
if (RSP::MFC0_count[rt] >= RSP::SP_STATUS_TIMEOUT)
|
||||
{
|
||||
*RSP::rsp.SP_STATUS_REG |= SP_STATUS_HALT;
|
||||
return MODE_CHECK_FLAGS;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0 // FIXME: this is broken with upstream mupen64plus-core
|
||||
if (rd == CP0_REGISTER_SP_SEMAPHORE)
|
||||
{
|
||||
if (*rsp->cp0.cr[CP0_REGISTER_SP_SEMAPHORE])
|
||||
{
|
||||
#ifdef PARALLEL_INTEGRATION
|
||||
RSP::MFC0_count[rt] += 8; // Almost certainly waiting on the CPU. Timeout faster.
|
||||
if (RSP::MFC0_count[rt] >= RSP::SP_STATUS_TIMEOUT)
|
||||
{
|
||||
*RSP::rsp.SP_STATUS_REG |= SP_STATUS_HALT;
|
||||
return MODE_CHECK_FLAGS;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
*rsp->cp0.cr[CP0_REGISTER_SP_SEMAPHORE] = 1;
|
||||
*rsp->cp0.cr[CP0_REGISTER_SP_SEMAPHORE] = 1;
|
||||
return MODE_EXIT;
|
||||
}
|
||||
// We don't return control to the CPU if the RDP FREEZE bit is set, doing so seems to cause flickering
|
||||
else if (rd == CP0_REGISTER_SP_STATUS && (*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] & DPC_STATUS_FREEZE) == 0)
|
||||
{
|
||||
return MODE_EXIT;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -65,12 +44,44 @@ extern "C"
|
||||
return MODE_CONTINUE;
|
||||
}
|
||||
|
||||
#define RSP_HANDLE_STATUS_WRITE(flag) \
|
||||
switch (rt & (SP_SET_##flag | SP_CLR_##flag)) \
|
||||
{ \
|
||||
case SP_SET_##flag: status |= SP_STATUS_##flag; break; \
|
||||
case SP_CLR_##flag: status &= ~SP_STATUS_##flag; break; \
|
||||
default: break; \
|
||||
static inline void rdp_status_write(RSP::CPUState *rsp, uint32_t rt)
|
||||
{
|
||||
uint32_t status = *rsp->cp0.cr[CP0_REGISTER_CMD_STATUS];
|
||||
if (rt & DPC_CLR_XBUS_DMEM_DMA)
|
||||
status &= ~DPC_STATUS_XBUS_DMEM_DMA;
|
||||
else if (rt & DPC_SET_XBUS_DMEM_DMA)
|
||||
status |= DPC_STATUS_XBUS_DMEM_DMA;
|
||||
|
||||
if (rt & DPC_CLR_FREEZE)
|
||||
status &= ~DPC_STATUS_FREEZE;
|
||||
else if (rt & DPC_SET_FREEZE)
|
||||
status |= DPC_STATUS_FREEZE;
|
||||
|
||||
if (rt & DPC_CLR_FLUSH)
|
||||
status &= ~DPC_STATUS_FLUSH;
|
||||
else if (rt & DPC_SET_FLUSH)
|
||||
status |= DPC_STATUS_FLUSH;
|
||||
|
||||
if (rt & DPC_CLR_TMEM_CTR)
|
||||
{
|
||||
status &= ~DPC_STATUS_TMEM_BUSY;
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_TMEM_BUSY] = 0;
|
||||
}
|
||||
if (rt & DPC_CLR_PIPE_CTR)
|
||||
{
|
||||
status &= ~DPC_STATUS_PIPE_BUSY;
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_PIPE_BUSY] = 0;
|
||||
}
|
||||
if (rt & DPC_CLR_CMD_CTR)
|
||||
{
|
||||
status &= ~DPC_STATUS_CMD_BUSY;
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_BUSY] = 0;
|
||||
}
|
||||
|
||||
if (rt & DPC_CLR_CLOCK_CTR)
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_CLOCK] = 0;
|
||||
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] = status;
|
||||
}
|
||||
|
||||
static inline int rsp_status_write(RSP::CPUState *rsp, uint32_t rt)
|
||||
@@ -79,28 +90,69 @@ extern "C"
|
||||
|
||||
uint32_t status = *rsp->cp0.cr[CP0_REGISTER_SP_STATUS];
|
||||
|
||||
RSP_HANDLE_STATUS_WRITE(HALT)
|
||||
RSP_HANDLE_STATUS_WRITE(SSTEP)
|
||||
RSP_HANDLE_STATUS_WRITE(INTR_BREAK)
|
||||
RSP_HANDLE_STATUS_WRITE(SIG0)
|
||||
RSP_HANDLE_STATUS_WRITE(SIG1)
|
||||
RSP_HANDLE_STATUS_WRITE(SIG2)
|
||||
RSP_HANDLE_STATUS_WRITE(SIG3)
|
||||
RSP_HANDLE_STATUS_WRITE(SIG4)
|
||||
RSP_HANDLE_STATUS_WRITE(SIG5)
|
||||
RSP_HANDLE_STATUS_WRITE(SIG6)
|
||||
RSP_HANDLE_STATUS_WRITE(SIG7)
|
||||
|
||||
switch (rt & (SP_SET_INTR | SP_CLR_INTR))
|
||||
{
|
||||
case SP_SET_INTR: *rsp->cp0.irq |= 1; break;
|
||||
case SP_CLR_INTR: *rsp->cp0.irq &= ~1; break;
|
||||
default: break;
|
||||
}
|
||||
if ((rt & SP_CLR_HALT) && !(rt & SP_SET_HALT))
|
||||
status &= ~SP_STATUS_HALT;
|
||||
if ((rt & SP_SET_HALT) && !(rt & SP_CLR_HALT))
|
||||
status |= SP_STATUS_HALT;
|
||||
|
||||
if (rt & SP_CLR_BROKE)
|
||||
status &= ~SP_STATUS_BROKE;
|
||||
|
||||
if ((rt & SP_CLR_INTR) && !(rt & SP_SET_INTR))
|
||||
*rsp->cp0.irq &= ~1;
|
||||
if ((rt & SP_SET_INTR) && !(rt & SP_CLR_INTR))
|
||||
*rsp->cp0.irq |= 1;
|
||||
|
||||
if ((rt & SP_CLR_SSTEP) && !(rt & SP_SET_SSTEP))
|
||||
status &= ~SP_STATUS_SSTEP;
|
||||
if ((rt & SP_SET_SSTEP) && !(rt & SP_CLR_SSTEP))
|
||||
status |= SP_STATUS_SSTEP;
|
||||
|
||||
if ((rt & SP_CLR_INTR_BREAK) && !(rt & SP_SET_INTR_BREAK))
|
||||
status &= ~SP_STATUS_INTR_BREAK;
|
||||
if ((rt & SP_SET_INTR_BREAK) && !(rt & SP_CLR_INTR_BREAK))
|
||||
status |= SP_STATUS_INTR_BREAK;
|
||||
|
||||
if ((rt & SP_CLR_SIG0) && !(rt & SP_SET_SIG0))
|
||||
status &= ~SP_STATUS_SIG0;
|
||||
if ((rt & SP_SET_SIG0) && !(rt & SP_CLR_SIG0))
|
||||
status |= SP_STATUS_SIG0;
|
||||
|
||||
if ((rt & SP_CLR_SIG1) && !(rt & SP_SET_SIG1))
|
||||
status &= ~SP_STATUS_SIG1;
|
||||
if ((rt & SP_SET_SIG1) && !(rt & SP_CLR_SIG1))
|
||||
status |= SP_STATUS_SIG1;
|
||||
|
||||
if ((rt & SP_CLR_SIG2) && !(rt & SP_SET_SIG2))
|
||||
status &= ~SP_STATUS_SIG2;
|
||||
if ((rt & SP_SET_SIG2) && !(rt & SP_CLR_SIG2))
|
||||
status |= SP_STATUS_SIG2;
|
||||
|
||||
if ((rt & SP_CLR_SIG3) && !(rt & SP_SET_SIG3))
|
||||
status &= ~SP_STATUS_SIG3;
|
||||
if ((rt & SP_SET_SIG3) && !(rt & SP_CLR_SIG3))
|
||||
status |= SP_STATUS_SIG3;
|
||||
|
||||
if ((rt & SP_CLR_SIG4) && !(rt & SP_SET_SIG4))
|
||||
status &= ~SP_STATUS_SIG4;
|
||||
if ((rt & SP_SET_SIG4) && !(rt & SP_CLR_SIG4))
|
||||
status |= SP_STATUS_SIG4;
|
||||
|
||||
if ((rt & SP_CLR_SIG5) && !(rt & SP_SET_SIG5))
|
||||
status &= ~SP_STATUS_SIG5;
|
||||
if ((rt & SP_SET_SIG5) && !(rt & SP_CLR_SIG5))
|
||||
status |= SP_STATUS_SIG5;
|
||||
|
||||
if ((rt & SP_CLR_SIG6) && !(rt & SP_SET_SIG6))
|
||||
status &= ~SP_STATUS_SIG6;
|
||||
if ((rt & SP_SET_SIG6) && !(rt & SP_CLR_SIG6))
|
||||
status |= SP_STATUS_SIG6;
|
||||
|
||||
if ((rt & SP_CLR_SIG7) && !(rt & SP_SET_SIG7))
|
||||
status &= ~SP_STATUS_SIG7;
|
||||
if ((rt & SP_SET_SIG7) && !(rt & SP_CLR_SIG7))
|
||||
status |= SP_STATUS_SIG7;
|
||||
|
||||
*rsp->cp0.cr[CP0_REGISTER_SP_STATUS] = status;
|
||||
return ((*rsp->cp0.irq & 1) || (status & SP_STATUS_HALT)) ? MODE_CHECK_FLAGS : MODE_CONTINUE;
|
||||
}
|
||||
@@ -109,14 +161,9 @@ extern "C"
|
||||
static int rsp_dma_read(RSP::CPUState *rsp)
|
||||
{
|
||||
uint32_t length_reg = *rsp->cp0.cr[CP0_REGISTER_DMA_READ_LENGTH];
|
||||
uint32_t length = (length_reg & 0xFFF) + 1;
|
||||
uint32_t skip = (length_reg >> 20) & 0xFFF;
|
||||
unsigned count = (length_reg >> 12) & 0xFF;
|
||||
|
||||
// Force alignment.
|
||||
length = (length + 0x7) & ~0x7;
|
||||
*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] &= ~0x3;
|
||||
*rsp->cp0.cr[CP0_REGISTER_DMA_DRAM] &= ~0x7;
|
||||
uint32_t length = ((length_reg & 0xFFF) | 7) + 1;
|
||||
uint32_t skip = (length_reg >> 20) & 0xFF8;
|
||||
unsigned count = ((length_reg >> 12) & 0xFF) + 1;
|
||||
|
||||
// Check length.
|
||||
if (((*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] & 0xFFF) + length) > 0x1000)
|
||||
@@ -156,7 +203,7 @@ extern "C"
|
||||
|
||||
source += length + skip;
|
||||
dest += length;
|
||||
} while (++i <= count);
|
||||
} while (++i < count);
|
||||
|
||||
*rsp->cp0.cr[CP0_REGISTER_DMA_DRAM] = source;
|
||||
*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] = dest;
|
||||
@@ -171,14 +218,9 @@ extern "C"
|
||||
static void rsp_dma_write(RSP::CPUState *rsp)
|
||||
{
|
||||
uint32_t length_reg = *rsp->cp0.cr[CP0_REGISTER_DMA_WRITE_LENGTH];
|
||||
uint32_t length = (length_reg & 0xFFF) + 1;
|
||||
uint32_t skip = (length_reg >> 20) & 0xFFF;
|
||||
unsigned count = (length_reg >> 12) & 0xFF;
|
||||
|
||||
// Force alignment.
|
||||
length = (length + 0x7) & ~0x7;
|
||||
*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] &= ~0x3;
|
||||
*rsp->cp0.cr[CP0_REGISTER_DMA_DRAM] &= ~0x7;
|
||||
uint32_t length = ((length_reg & 0xFFF) | 7) + 1;
|
||||
uint32_t skip = (length_reg >> 20) & 0xFF8;
|
||||
unsigned count = ((length_reg >> 12) & 0xFF) + 1;
|
||||
|
||||
// Check length.
|
||||
if (((*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] & 0xFFF) + length) > 0x1000)
|
||||
@@ -210,7 +252,7 @@ extern "C"
|
||||
|
||||
source += length;
|
||||
dest += length + skip;
|
||||
} while (++i <= count);
|
||||
} while (++i < count);
|
||||
|
||||
*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] = source;
|
||||
*rsp->cp0.cr[CP0_REGISTER_DMA_DRAM] = dest;
|
||||
@@ -228,11 +270,11 @@ extern "C"
|
||||
switch (static_cast<CP0Registers>(rd & 15))
|
||||
{
|
||||
case CP0_REGISTER_DMA_CACHE:
|
||||
*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] = val & 0x1fff;
|
||||
*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] = val & 0x1ff8;
|
||||
break;
|
||||
|
||||
case CP0_REGISTER_DMA_DRAM:
|
||||
*rsp->cp0.cr[CP0_REGISTER_DMA_DRAM] = val & 0xffffff;
|
||||
*rsp->cp0.cr[CP0_REGISTER_DMA_DRAM] = val & 0xfffff8;
|
||||
break;
|
||||
|
||||
case CP0_REGISTER_DMA_READ_LENGTH:
|
||||
@@ -254,26 +296,34 @@ extern "C"
|
||||
return rsp_status_write(rsp, val);
|
||||
|
||||
case CP0_REGISTER_SP_SEMAPHORE:
|
||||
// Any write to the semaphore register, regardless of value, sets it to 0 for the next read
|
||||
*rsp->cp0.cr[CP0_REGISTER_SP_SEMAPHORE] = 0;
|
||||
break;
|
||||
|
||||
case CP0_REGISTER_CMD_START:
|
||||
#ifdef INTENSE_DEBUG
|
||||
fprintf(stderr, "CMD_START 0x%x\n", val & 0xfffffff8u);
|
||||
fprintf(stderr, "CMD_START 0x%x\n", val & 0xfffff8u);
|
||||
#endif
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_START] = *rsp->cp0.cr[CP0_REGISTER_CMD_CURRENT] =
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_END] = val & 0xfffffff8u;
|
||||
if (!(*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] & DPC_STATUS_START_VALID))
|
||||
{
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_START] = val & 0xfffff8u;
|
||||
}
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] |= DPC_STATUS_START_VALID;
|
||||
break;
|
||||
|
||||
case CP0_REGISTER_CMD_END:
|
||||
#ifdef INTENSE_DEBUG
|
||||
fprintf(stderr, "CMD_END 0x%x\n", val & 0xfffffff8u);
|
||||
fprintf(stderr, "CMD_END 0x%x\n", val & 0xfffff8u);
|
||||
#endif
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_END] = val & 0xfffffff8u;
|
||||
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_END] = val & 0xfffff8u;
|
||||
if (*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] & DPC_STATUS_START_VALID)
|
||||
{
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_CURRENT] = *rsp->cp0.cr[CP0_REGISTER_CMD_START];
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] &= ~DPC_STATUS_START_VALID;
|
||||
}
|
||||
#ifdef PARALLEL_INTEGRATION
|
||||
RSP::rsp.ProcessRdpList();
|
||||
if (*rsp->cp0.irq & 0x20)
|
||||
return MODE_EXIT;
|
||||
#endif
|
||||
break;
|
||||
|
||||
@@ -282,14 +332,7 @@ extern "C"
|
||||
break;
|
||||
|
||||
case CP0_REGISTER_CMD_STATUS:
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] &= ~(!!(val & 0x1) << 0);
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] |= (!!(val & 0x2) << 0);
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] &= ~(!!(val & 0x4) << 1);
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] |= (!!(val & 0x8) << 1);
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] &= ~(!!(val & 0x10) << 2);
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] |= (!!(val & 0x20) << 2);
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_TMEM_BUSY] &= !(val & 0x40) * -1;
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_CLOCK] &= !(val & 0x200) * -1;
|
||||
rdp_status_write(rsp, val);
|
||||
break;
|
||||
|
||||
case CP0_REGISTER_CMD_CURRENT:
|
||||
|
||||
+1
-2
@@ -1927,14 +1927,13 @@ ReturnMode CPU::run()
|
||||
{
|
||||
case MODE_BREAK:
|
||||
*state.cp0.cr[CP0_REGISTER_SP_STATUS] |= SP_STATUS_BROKE | SP_STATUS_HALT;
|
||||
if (*state.cp0.cr[CP0_REGISTER_SP_STATUS] & SP_STATUS_INTR_BREAK)
|
||||
*state.cp0.irq |= 1;
|
||||
#ifndef PARALLEL_INTEGRATION
|
||||
print_registers();
|
||||
#endif
|
||||
return MODE_BREAK;
|
||||
|
||||
case MODE_CHECK_FLAGS:
|
||||
case MODE_EXIT:
|
||||
case MODE_DMA_READ:
|
||||
return static_cast<ReturnMode>(ret);
|
||||
|
||||
|
||||
+36
-1
@@ -48,6 +48,31 @@ enum CP0Registers
|
||||
CP0_REGISTER_CMD_TMEM_BUSY = 15,
|
||||
};
|
||||
|
||||
// CMD_STATUS read bits.
|
||||
#define DPC_STATUS_XBUS_DMEM_DMA 0x001
|
||||
#define DPC_STATUS_FREEZE 0x002
|
||||
#define DPC_STATUS_FLUSH 0x004
|
||||
#define DPC_STATUS_START_GCLK 0x008
|
||||
#define DPC_STATUS_TMEM_BUSY 0x010
|
||||
#define DPC_STATUS_PIPE_BUSY 0x020
|
||||
#define DPC_STATUS_CMD_BUSY 0x040
|
||||
#define DPC_STATUS_CBUF_READY 0x080
|
||||
#define DPC_STATUS_DMA_BUSY 0x100
|
||||
#define DPC_STATUS_END_VALID 0x200
|
||||
#define DPC_STATUS_START_VALID 0x400
|
||||
|
||||
// CMD_STATUS write bits.
|
||||
#define DPC_CLR_XBUS_DMEM_DMA 0x001
|
||||
#define DPC_SET_XBUS_DMEM_DMA 0x002
|
||||
#define DPC_CLR_FREEZE 0x004
|
||||
#define DPC_SET_FREEZE 0x008
|
||||
#define DPC_CLR_FLUSH 0x010
|
||||
#define DPC_SET_FLUSH 0x020
|
||||
#define DPC_CLR_TMEM_CTR 0x040
|
||||
#define DPC_CLR_PIPE_CTR 0x080
|
||||
#define DPC_CLR_CMD_CTR 0x100
|
||||
#define DPC_CLR_CLOCK_CTR 0x200
|
||||
|
||||
// SP_STATUS read bits.
|
||||
#define SP_STATUS_HALT 0x0001
|
||||
#define SP_STATUS_BROKE 0x0002
|
||||
@@ -117,6 +142,9 @@ struct alignas(64) CP2
|
||||
struct CPUState
|
||||
{
|
||||
uint32_t pc = 0;
|
||||
uint32_t instruction_count = 0;
|
||||
uint32_t last_instruction_type = 0;
|
||||
uint32_t instruction_pipeline = 0;
|
||||
uint32_t dirty_blocks = 0;
|
||||
static_assert(CODE_BLOCKS <= 32, "Code blocks must fit in 32-bit register.");
|
||||
|
||||
@@ -138,7 +166,14 @@ enum ReturnMode
|
||||
MODE_CONTINUE = 1,
|
||||
MODE_BREAK = 2,
|
||||
MODE_DMA_READ = 3,
|
||||
MODE_CHECK_FLAGS = 4
|
||||
MODE_CHECK_FLAGS = 4,
|
||||
MODE_EXIT = 5
|
||||
};
|
||||
|
||||
enum InstructionType
|
||||
{
|
||||
VU_INSTRUCTION = 0,
|
||||
SU_INSTRUCTION = 1
|
||||
};
|
||||
|
||||
} // namespace RSP
|
||||
|
||||
@@ -62,6 +62,7 @@ static void apply_coresettings_overlay(void)
|
||||
CoreSettingsSetValue(SettingsID::Core_CountPerOpDenomPot, CoreSettingsGetIntValue(SettingsID::CoreOverlay_CountPerOpDenomPot));
|
||||
CoreSettingsSetValue(SettingsID::Core_SiDmaDuration, CoreSettingsGetIntValue(SettingsID::CoreOverlay_SiDmaDuration));
|
||||
CoreSettingsSetValue(SettingsID::Core_SaveFileNameFormat, CoreSettingsGetIntValue(SettingsID::CoreOverLay_SaveFileNameFormat));
|
||||
CoreSettingsSetValue(SettingsID::Core_GbCameraVideoCaptureBackend1, CoreSettingsGetStringValue(SettingsID::CoreOverlay_GbCameraVideoCaptureBackend1));
|
||||
}
|
||||
|
||||
static void apply_game_coresettings_overlay(void)
|
||||
|
||||
@@ -254,6 +254,9 @@ static l_Setting get_setting(SettingsID settingId)
|
||||
case SettingsID::Core_SaveFileNameFormat:
|
||||
setting = {SETTING_SECTION_M64P, "SaveFilenameFormat", 1};
|
||||
break;
|
||||
case SettingsID::Core_GbCameraVideoCaptureBackend1:
|
||||
setting = {SETTING_SECTION_M64P, "GbCameraVideoCaptureBackend1", std::string("sdl3")};
|
||||
break;
|
||||
|
||||
case SettingsID::CoreOverlay_RandomizeInterrupt:
|
||||
setting = {SETTING_SECTION_OVERLAY, "RandomizeInterrupt", true};
|
||||
@@ -279,6 +282,9 @@ static l_Setting get_setting(SettingsID settingId)
|
||||
case SettingsID::CoreOverLay_SaveFileNameFormat:
|
||||
setting = {SETTING_SECTION_OVERLAY, "SaveFilenameFormat", 1};
|
||||
break;
|
||||
case SettingsID::CoreOverlay_GbCameraVideoCaptureBackend1:
|
||||
setting = {SETTING_SECTION_OVERLAY, "GbCameraVideoCaptureBackend1", std::string("sdl3")};
|
||||
break;
|
||||
|
||||
case SettingsID::Core_ScreenshotPath:
|
||||
setting = {SETTING_SECTION_M64P, "ScreenshotPath", CoreGetDefaultScreenshotDirectory().string(), "", true};
|
||||
|
||||
@@ -91,6 +91,7 @@ enum class SettingsID
|
||||
Core_CountPerOpDenomPot,
|
||||
Core_SiDmaDuration,
|
||||
Core_SaveFileNameFormat,
|
||||
Core_GbCameraVideoCaptureBackend1,
|
||||
|
||||
// (mupen64plus) Overlay Core Settings
|
||||
CoreOverlay_RandomizeInterrupt,
|
||||
@@ -101,6 +102,7 @@ enum class SettingsID
|
||||
CoreOverlay_CountPerOpDenomPot,
|
||||
CoreOverlay_SiDmaDuration,
|
||||
CoreOverLay_SaveFileNameFormat,
|
||||
CoreOverlay_GbCameraVideoCaptureBackend1,
|
||||
|
||||
// (mupen64plus) Core Directory Settings
|
||||
Core_ScreenshotPath,
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QIcon>
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
@@ -42,6 +43,11 @@ OptionsDialog::OptionsDialog(QWidget* parent, OptionsDialogSettings settings,
|
||||
this->hideEmulationInfoText();
|
||||
}
|
||||
|
||||
this->clearGameboyRomButton->setText("");
|
||||
this->clearGameboyRomButton->setIcon(QIcon::fromTheme("delete-bin-line"));
|
||||
this->clearGameboySaveButton->setText("");
|
||||
this->clearGameboySaveButton->setIcon(QIcon::fromTheme("delete-bin-line"));
|
||||
|
||||
this->currentJoystick = joystick;
|
||||
this->currentController = controller;
|
||||
|
||||
@@ -112,6 +118,11 @@ void OptionsDialog::on_changeGameboyRomButton_clicked()
|
||||
}
|
||||
}
|
||||
|
||||
void OptionsDialog::on_clearGameboyRomButton_clicked()
|
||||
{
|
||||
this->gameboyRomLineEdit->clear();
|
||||
}
|
||||
|
||||
void OptionsDialog::on_changeGameboySaveButton_clicked()
|
||||
{
|
||||
QString gameBoySave = QFileDialog::getOpenFileName(this, tr("Open Gameboy Save"), "", "Gameboy save (*.sav *.ram)");
|
||||
@@ -121,6 +132,11 @@ void OptionsDialog::on_changeGameboySaveButton_clicked()
|
||||
}
|
||||
}
|
||||
|
||||
void OptionsDialog::on_clearGameboySaveButton_clicked()
|
||||
{
|
||||
this->gameboySaveLineEdit->clear();
|
||||
}
|
||||
|
||||
void OptionsDialog::on_testRumbleButton_clicked()
|
||||
{
|
||||
#if SDL_VERSION_ATLEAST(2,0,18) && !SDL_VERSION_ATLEAST(3,0,0) // TODO: port this to SDL3
|
||||
|
||||
@@ -58,7 +58,11 @@ private slots:
|
||||
void on_controllerPakComboBox_currentIndexChanged(int index);
|
||||
|
||||
void on_changeGameboyRomButton_clicked();
|
||||
void on_clearGameboyRomButton_clicked();
|
||||
|
||||
void on_changeGameboySaveButton_clicked();
|
||||
void on_clearGameboySaveButton_clicked();
|
||||
|
||||
void on_testRumbleButton_clicked();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -116,6 +116,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="clearGameboyRomButton">
|
||||
<property name="text">
|
||||
<string>Clear</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -139,6 +146,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="clearGameboySaveButton">
|
||||
<property name="text">
|
||||
<string>Clear</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -117,6 +117,14 @@ SettingsDialog::SettingsDialog(QWidget *parent, QString file) : QDialog(parent)
|
||||
// connect hotkey settings to slot
|
||||
this->commonHotkeySettings(SettingsDialogAction::ConnectSignals);
|
||||
|
||||
// set icons for certain buttons
|
||||
this->clearJapaneseIPLRomPathButton->setText("");
|
||||
this->clearJapaneseIPLRomPathButton->setIcon(QIcon::fromTheme("delete-bin-line"));
|
||||
this->clearAmericanIPLRomPathButton->setText("");
|
||||
this->clearAmericanIPLRomPathButton->setIcon(QIcon::fromTheme("delete-bin-line"));
|
||||
this->clearDevelopmentIPLRomPathButton->setText("");
|
||||
this->clearDevelopmentIPLRomPathButton->setIcon(QIcon::fromTheme("delete-bin-line"));
|
||||
|
||||
#ifndef NETPLAY
|
||||
this->innerInterfaceTabWidget->setTabVisible((int)SettingsDialogTab::InterfaceNetplay, false);
|
||||
#endif // !NETPLAY
|
||||
@@ -284,6 +292,7 @@ void SettingsDialog::loadCoreSettings(void)
|
||||
bool disableExtraMem = CoreSettingsGetBoolValue(SettingsID::CoreOverlay_DisableExtraMem);
|
||||
int counterFactor = CoreSettingsGetIntValue(SettingsID::CoreOverlay_CountPerOp);
|
||||
const int cpuEmulator = CoreSettingsGetIntValue(SettingsID::CoreOverlay_CPU_Emulator);
|
||||
const QString videoCaptureBackend = QString::fromStdString(CoreSettingsGetStringValue(SettingsID::CoreOverlay_GbCameraVideoCaptureBackend1));
|
||||
const int saveFilenameFormat = CoreSettingsGetIntValue(SettingsID::CoreOverLay_SaveFileNameFormat);
|
||||
int siDmaDuration = CoreSettingsGetIntValue(SettingsID::CoreOverlay_SiDmaDuration);
|
||||
const bool randomizeInterrupt = CoreSettingsGetBoolValue(SettingsID::CoreOverlay_RandomizeInterrupt);
|
||||
@@ -293,6 +302,7 @@ void SettingsDialog::loadCoreSettings(void)
|
||||
const bool overrideGameSettings = CoreSettingsGetBoolValue(SettingsID::Core_OverrideGameSpecificSettings);
|
||||
|
||||
this->coreCpuEmulatorComboBox->setCurrentIndex(cpuEmulator);
|
||||
this->coreVideoCaptureBackendComboBox->setCurrentIndex(videoCaptureBackend == "sdl3" ? 1 : 0);
|
||||
this->coreSaveFilenameFormatComboBox->setCurrentIndex(saveFilenameFormat);
|
||||
this->coreRandomizeTimingCheckBox->setChecked(randomizeInterrupt);
|
||||
|
||||
@@ -543,6 +553,7 @@ void SettingsDialog::loadDefaultCoreSettings(void)
|
||||
bool disableExtraMem = CoreSettingsGetDefaultBoolValue(SettingsID::CoreOverlay_DisableExtraMem);
|
||||
int counterFactor = CoreSettingsGetDefaultIntValue(SettingsID::CoreOverlay_CountPerOp);
|
||||
const int cpuEmulator = CoreSettingsGetDefaultIntValue(SettingsID::CoreOverlay_CPU_Emulator);
|
||||
const QString videoCaptureBackend = QString::fromStdString(CoreSettingsGetDefaultStringValue(SettingsID::CoreOverlay_GbCameraVideoCaptureBackend1));
|
||||
int siDmaDuration = CoreSettingsGetDefaultIntValue(SettingsID::CoreOverlay_SiDmaDuration);
|
||||
const int saveFilenameFormat = CoreSettingsGetDefaultIntValue(SettingsID::CoreOverLay_SaveFileNameFormat);
|
||||
const bool randomizeInterrupt = CoreSettingsGetDefaultBoolValue(SettingsID::CoreOverlay_RandomizeInterrupt);
|
||||
@@ -552,6 +563,7 @@ void SettingsDialog::loadDefaultCoreSettings(void)
|
||||
const bool overrideGameSettings = CoreSettingsGetDefaultBoolValue(SettingsID::Core_OverrideGameSpecificSettings);
|
||||
|
||||
this->coreCpuEmulatorComboBox->setCurrentIndex(cpuEmulator);
|
||||
this->coreVideoCaptureBackendComboBox->setCurrentIndex(videoCaptureBackend == "sdl3" ? 1 : 0);
|
||||
this->coreSaveFilenameFormatComboBox->setCurrentIndex(saveFilenameFormat);
|
||||
this->coreRandomizeTimingCheckBox->setChecked(randomizeInterrupt);
|
||||
|
||||
@@ -724,6 +736,7 @@ void SettingsDialog::saveCoreSettings(void)
|
||||
bool disableExtraMem = (this->coreMemorySizeComboBox->currentIndex() == 0);
|
||||
int counterFactor = this->coreCounterFactorComboBox->currentIndex() + 1;
|
||||
const int cpuEmulator = this->coreCpuEmulatorComboBox->currentIndex();
|
||||
const int videoCaptureBackend = this->coreVideoCaptureBackendComboBox->currentIndex();
|
||||
const int saveFilenameFormat = this->coreSaveFilenameFormatComboBox->currentIndex();
|
||||
int siDmaDuration = this->coreSiDmaDurationSpinBox->value();
|
||||
const bool randomizeInterrupt = this->coreRandomizeTimingCheckBox->isChecked();
|
||||
@@ -733,6 +746,7 @@ void SettingsDialog::saveCoreSettings(void)
|
||||
const bool overrideGameSettings = this->coreOverrideGameSettingsGroup->isChecked();
|
||||
|
||||
CoreSettingsSetValue(SettingsID::CoreOverlay_CPU_Emulator, cpuEmulator);
|
||||
CoreSettingsSetValue(SettingsID::CoreOverlay_GbCameraVideoCaptureBackend1, std::string((videoCaptureBackend == 1) ? "sdl3" : ""));
|
||||
CoreSettingsSetValue(SettingsID::CoreOverLay_SaveFileNameFormat, saveFilenameFormat);
|
||||
CoreSettingsSetValue(SettingsID::CoreOverlay_RandomizeInterrupt, randomizeInterrupt);
|
||||
CoreSettingsSetValue(SettingsID::Core_PIF_Use, usePIF);
|
||||
@@ -1399,6 +1413,21 @@ void SettingsDialog::on_changeDevelopmentIPLRomPathButton_clicked(void)
|
||||
this->chooseFile(this->developmentIPLRomLineEdit, tr("Open Japanese Development 64DD IPL"), "IPL ROMs (*.n64)");
|
||||
}
|
||||
|
||||
void SettingsDialog::on_clearJapaneseIPLRomPathButton_clicked(void)
|
||||
{
|
||||
this->japaneseIPLRomLineEdit->clear();
|
||||
}
|
||||
|
||||
void SettingsDialog::on_clearAmericanIPLRomPathButton_clicked(void)
|
||||
{
|
||||
this->americanIPLRomLineEdit->clear();
|
||||
}
|
||||
|
||||
void SettingsDialog::on_clearDevelopmentIPLRomPathButton_clicked(void)
|
||||
{
|
||||
this->developmentIPLRomLineEdit->clear();
|
||||
}
|
||||
|
||||
void SettingsDialog::on_changeBackgroundColorButton_clicked(void)
|
||||
{
|
||||
this->chooseColor(this->changeBackgroundColorButton, &this->currentBackgroundColor);
|
||||
|
||||
@@ -149,6 +149,10 @@ class SettingsDialog : public QDialog, private Ui::SettingsDialog
|
||||
void on_changeAmericanIPLRomPathButton_clicked(void);
|
||||
void on_changeDevelopmentIPLRomPathButton_clicked(void);
|
||||
|
||||
void on_clearJapaneseIPLRomPathButton_clicked(void);
|
||||
void on_clearAmericanIPLRomPathButton_clicked(void);
|
||||
void on_clearDevelopmentIPLRomPathButton_clicked(void);
|
||||
|
||||
void on_changeBackgroundColorButton_clicked(void);
|
||||
void on_changeTextColorButton_clicked(void);
|
||||
|
||||
|
||||
@@ -1817,6 +1817,31 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_47">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_26">
|
||||
<property name="text">
|
||||
<string>Video capture backend</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="coreVideoCaptureBackendComboBox">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>None</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>SDL3</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="usePifRomGroupBox">
|
||||
<property name="title">
|
||||
@@ -3006,6 +3031,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="clearJapaneseIPLRomPathButton">
|
||||
<property name="text">
|
||||
<string>Clear</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -3029,6 +3061,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="clearAmericanIPLRomPathButton">
|
||||
<property name="text">
|
||||
<string>Clear</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -3052,6 +3091,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="clearDevelopmentIPLRomPathButton">
|
||||
<property name="text">
|
||||
<string>Clear</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
#include <QSettings>
|
||||
#include <QStatusBar>
|
||||
#include <QMenuBar>
|
||||
#include <cstdlib>
|
||||
#include <QString>
|
||||
#include <QTimer>
|
||||
#include <cmath>
|
||||
@@ -322,11 +323,7 @@ void MainWindow::configureUI(QApplication* app, bool showUI)
|
||||
this->installEventFilter(this->ui_EventFilter);
|
||||
this->ui_Widget_Dummy->installEventFilter(this->ui_EventFilter);
|
||||
|
||||
this->ui_WindowTitle = QCoreApplication::applicationName();
|
||||
this->ui_WindowTitle += " (";
|
||||
this->ui_WindowTitle += QString::fromStdString(CoreGetVersion());
|
||||
this->ui_WindowTitle += ")";
|
||||
|
||||
this->ui_WindowTitle = this->getWindowTitle();
|
||||
this->setWindowTitle(this->ui_WindowTitle);
|
||||
}
|
||||
|
||||
@@ -435,6 +432,51 @@ void MainWindow::configureTheme(QApplication* app)
|
||||
QIcon::setFallbackThemeName(fallbackThemeName);
|
||||
}
|
||||
|
||||
QString MainWindow::getWindowTitle(void)
|
||||
{
|
||||
const QDate currentDate = QDateTime::currentDateTime().date();
|
||||
const QStringList firstWordList = {
|
||||
{
|
||||
"lesbian",
|
||||
"gay",
|
||||
"bisexual",
|
||||
"transgender",
|
||||
"queer",
|
||||
}};
|
||||
const QStringList secondWordList = {
|
||||
{
|
||||
" rights!!!",
|
||||
"s rise up!!!"
|
||||
}};
|
||||
|
||||
QString windowTitle = QCoreApplication::applicationName();
|
||||
|
||||
// initialize random seed
|
||||
srand(time(nullptr));
|
||||
|
||||
bool showCustomWindowTitle = (rand() % 10) < 3;
|
||||
|
||||
if (showCustomWindowTitle && currentDate.month() == 3 && currentDate.day() == 31)
|
||||
{
|
||||
QString secondWord = secondWordList.at(rand() % secondWordList.count());
|
||||
windowTitle += " (transgender" + secondWord + ")";
|
||||
}
|
||||
else if (showCustomWindowTitle && currentDate.month() == 6)
|
||||
{
|
||||
QString firstWsord = firstWordList.at(rand() % firstWordList.count());
|
||||
QString secondWord = secondWordList.at(rand() % secondWordList.count());
|
||||
windowTitle += " (" + firstWsord + secondWord + ")";
|
||||
}
|
||||
else
|
||||
{
|
||||
windowTitle += " (";
|
||||
windowTitle += QString::fromStdString(CoreGetVersion());
|
||||
windowTitle += ")";
|
||||
}
|
||||
|
||||
return windowTitle;
|
||||
}
|
||||
|
||||
void MainWindow::showErrorMessage(QString text, QString details, bool force)
|
||||
{
|
||||
// fallback to helper when forced
|
||||
|
||||
@@ -129,6 +129,8 @@ class MainWindow : public QMainWindow, private Ui::MainWindow
|
||||
void configureUI(QApplication* app, bool showUI);
|
||||
void configureTheme(QApplication* app);
|
||||
|
||||
QString getWindowTitle(void);
|
||||
|
||||
void showErrorMessage(QString text, QString details = "", bool force = true);
|
||||
|
||||
void updateUI(bool inEmulation, bool isPaused);
|
||||
|
||||
Reference in New Issue
Block a user