Compare commits

...

22 Commits

Author SHA1 Message Date
Rosalie Wanders cd89473f7e beep boop more wip changes 2025-09-28 14:18:53 +02:00
Rosalie Wanders b89fed20e8 Fix 2 small tests 2025-09-28 13:02:40 +02:00
Rosalie Wanders 28af6a436e 3rdParty: make mupen64plus-core use 64bit cop0 registers 2025-09-28 13:02:40 +02:00
Rosalie Wanders 9c53a846b8 Package: v0.8.3 2025-09-28 08:41:31 +02:00
Rosalie Wanders 816bb4c426 3rdParty: include rsp state in save states in mupen64plus-core 2025-09-28 08:20:48 +02:00
Rosalie Wanders c119e5f128 RMG: add clear buttons for the 64DD IPL settings in SettingsDialog 2025-09-27 19:32:12 +02:00
Rosalie Wanders d64b23bdfe 3rdParty: fix cargo warnings for mupen64plus-input-gca 2025-09-27 19:16:25 +02:00
Rosalie Wanders b03f118b04 3rdParty: fix frame count being 0 in mupen64plus-core 2025-09-27 18:52:48 +02:00
Rosalie Wanders d18ac4076f 3rdParty: update mupen64plus-core 2025-09-27 18:40:16 +02:00
Rosalie Wanders 4620c1beb8 3rdParty: fix crash in mupen64plus-rsp-hle with Mario Artist Talent Studio 2025-09-27 18:11:27 +02:00
Rosalie Wanders 55431be957 Package: v0.8.2 2025-09-26 23:02:03 +02:00
Rosalie Wanders 18946b1d92 3rdParty: apply RSP fixes patch to mupen64plus-rsp-parallel 2025-09-26 22:53:56 +02:00
Rosalie Wanders c517862b3c 3rdParty: apply transfer pak fixes patch to mupen64plus-core 2025-09-26 22:51:48 +02:00
Rosalie Wanders e8d4d6341b 3rdParty: apply RSP fixes patch to mupen64plus-core 2025-09-26 22:48:32 +02:00
Rosalie Wanders 2246b6f25b RMG: add "Video capture backend" setting to SettingsDialog 2025-09-25 18:09:59 +02:00
Rosalie Wanders cd754fafa9 3rdParty: add MD5 fallback to screenshot filename in mupen64plus-core 2025-09-25 17:31:40 +02:00
Rosalie Wanders 8660ced35f RMG: add clear buttons for the gameboy rom/save settings 2025-09-25 16:32:39 +02:00
Rosalie Wanders 1c7276b4f8 3rdParty: update SDL3 gameboy camera backend patch in mupen64plus-core 2025-09-25 16:20:49 +02:00
Rosalie Wanders 4b793c4ad4 RMG-Core: add GbCameraVideoCaptureBackend1 to CoreOverlay 2025-09-24 23:54:16 +02:00
Rosalie Wanders e9dc24d947 3rdParty: apply SDL3 gameboy camera backend patch to mupen64plus-core 2025-09-24 23:46:55 +02:00
Rosalie Wanders 51b712a8c9 RMG: misc changes 2025-09-24 22:33:58 +02:00
Rosalie Wanders 1ce70fba22 RMG: improve window title generation 2025-09-24 02:41:31 +02:00
51 changed files with 1224 additions and 478 deletions
+1 -1
View File
@@ -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 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
};
@@ -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;
};
+1
View File
@@ -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
+5 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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));
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+1
View File
@@ -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)
+6
View File
@@ -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};
+2
View File
@@ -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>
+47 -5
View File
@@ -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
+2
View File
@@ -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);
+1 -1
View File
@@ -1 +1 @@
v0.8.1
v0.8.3