diff --git a/.travis.yml b/.travis.yml
index 427f7f6..234cdfb 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,13 +1,46 @@
+sudo: required
+dist: xenial
language: cpp
compiler:
- gcc
- clang
+addons:
+ apt:
+ packages:
+ - git
before_install:
- - sudo apt-get update -qq
- - sudo apt-get install -y git
- git clone --depth=1 --branch=master git://github.com/mupen64plus/mupen64plus-core.git deps/mupen64plus-core
env:
- DUMP=0
- DUMP=1
script:
- make -C projects/unix APIDIR="$(pwd)/deps/mupen64plus-core/src/api/" V=1 clean && LDFLAGS="-Wl,--no-add-needed -Wl,--no-undefined" OPTFLAGS="-O2" make CC="${CC}" CXX="${CXX}" -j$(nproc) -C projects/unix APIDIR="$(pwd)/deps/mupen64plus-core/src/api/" V=1 all
+
+# extra mxe build entries
+matrix:
+ include:
+ - env:
+ - MXE_CPU=i686
+ - PATH="/usr/lib/mxe/usr/bin/:$PATH"
+ before_install:
+ - curl -sSL "https://mirror.mxe.cc/repos/apt/client-conf/mxeapt.gpg" | sudo -E apt-key add -
+ - echo "deb https://mirror.mxe.cc/repos/apt xenial main" | sudo tee -a /etc/apt/sources.list
+ - sudo apt-get update -qq
+ - sudo apt-get -y --allow-unauthenticated install mxe-i686-w64-mingw32.shared-gcc
+ - git clone --depth=1 --branch=master git://github.com/mupen64plus/mupen64plus-core.git deps/mupen64plus-core
+ script:
+ - make UNAME=MINGW CROSS_COMPILE="${MXE_CPU}-w64-mingw32.shared-" CC="${MXE_CPU}-w64-mingw32.shared-gcc" CXX="${MXE_CPU}-w64-mingw32.shared-g++" HOST_CPU="${MXE_CPU}" -C projects/unix APIDIR="$(pwd)/deps/mupen64plus-core/src/api/" V=1 clean &&
+ make UNAME=MINGW CROSS_COMPILE="${MXE_CPU}-w64-mingw32.shared-" CC="${MXE_CPU}-w64-mingw32.shared-gcc" CXX="${MXE_CPU}-w64-mingw32.shared-g++" HOST_CPU="${MXE_CPU}" -C projects/unix APIDIR="$(pwd)/deps/mupen64plus-core/src/api/" V=1 -j$(nproc) all
+
+ - env:
+ - MXE_CPU=x86_64
+ - PATH="/usr/lib/mxe/usr/bin/:$PATH"
+ before_install:
+ - curl -sSL "https://mirror.mxe.cc/repos/apt/client-conf/mxeapt.gpg" | sudo -E apt-key add -
+ - echo "deb https://mirror.mxe.cc/repos/apt xenial main" | sudo tee -a /etc/apt/sources.list
+ - sudo apt-get update -qq
+ - sudo apt-get -y --allow-unauthenticated install mxe-x86-64-w64-mingw32.shared-gcc
+ - git clone --depth=1 --branch=master git://github.com/mupen64plus/mupen64plus-core.git deps/mupen64plus-core
+ script:
+ - make UNAME=MINGW CROSS_COMPILE="${MXE_CPU}-w64-mingw32.shared-" CC="${MXE_CPU}-w64-mingw32.shared-gcc" CXX="${MXE_CPU}-w64-mingw32.shared-g++" HOST_CPU="${MXE_CPU}" -C projects/unix APIDIR="$(pwd)/deps/mupen64plus-core/src/api/" V=1 clean &&
+ make UNAME=MINGW CROSS_COMPILE="${MXE_CPU}-w64-mingw32.shared-" CC="${MXE_CPU}-w64-mingw32.shared-gcc" CXX="${MXE_CPU}-w64-mingw32.shared-g++" HOST_CPU="${MXE_CPU}" -C projects/unix APIDIR="$(pwd)/deps/mupen64plus-core/src/api/" V=1 -j$(nproc) all
diff --git a/LICENSES b/LICENSES
index daea7fc..4319820 100644
--- a/LICENSES
+++ b/LICENSES
@@ -30,7 +30,7 @@
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 675 Mass Ave, Cambridge, MA 02139, USA
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
diff --git a/RELEASE b/RELEASE
index 0b19ad2..4ce99fa 100644
--- a/RELEASE
+++ b/RELEASE
@@ -1,5 +1,9 @@
RSP High-Level Emulation plugin for Mupen64Plus
-----------------------------------------------
+
+Mupen64Plus-rsp-hle v2.5.9 - February 10, 2019
+----------------------------------------------
+ - *** BETA RELEASE *** For Testing Only ***
Mupen64Plus-rsp-hle v2.5 - April 26, 2015
-------------------------------------------------
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 0000000..aac3df2
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,25 @@
+version: 1.0.{build}
+
+configuration:
+ - Release
+platform:
+ - Win32
+ - x64
+
+before_build:
+ - git clone --depth 1 https://github.com/mupen64plus/mupen64plus-core.git ..\mupen64plus-core
+
+build_script:
+ - msbuild projects\msvc\mupen64plus-rsp-hle.vcxproj /p:Configuration=%configuration%;Platform=%platform%
+
+after_build:
+ - ps: $env:rev1 = git describe --tags
+ - set rev2=%platform%
+ - if "%rev2%"=="Win32" set rev2=x86
+ - set filepkg=mupen64plus-rsp-hle_v%rev1%_%rev2%
+ - cd projects\msvc\%platform%\%configuration%
+ - 7z a -t7z ..\..\..\..\build\%filepkg%.7z *.dll
+
+artifacts:
+ - path: build\$(filepkg).7z
+ name: $(filepkg)
diff --git a/projects/VisualStudio2013/mupen64plus-rsp-hle.vcxproj b/projects/VisualStudio2013/mupen64plus-rsp-hle.vcxproj
deleted file mode 100644
index 426775c..0000000
--- a/projects/VisualStudio2013/mupen64plus-rsp-hle.vcxproj
+++ /dev/null
@@ -1,122 +0,0 @@
-
-
-
-
- Debug
- Win32
-
-
- Release
- Win32
-
-
-
- {2EC7CEE3-C7A7-4F2E-B2C8-4DF6AFEC3E9A}
- mupen64plusrsphle
- Win32Proj
-
-
-
- DynamicLibrary
- MultiByte
- true
- v120
-
-
- DynamicLibrary
- MultiByte
- v120
-
-
-
-
-
-
-
-
-
-
-
-
- <_ProjectFileVersion>10.0.40219.1
- $(SolutionDir)$(Configuration)\
- $(Configuration)\
- true
- $(SolutionDir)$(Configuration)\
- $(Configuration)\
- false
- AllRules.ruleset
-
-
- AllRules.ruleset
-
-
-
-
-
- Disabled
- ..\..\..\mupen64plus-core\src\api;%(AdditionalIncludeDirectories)
- WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;inline=__inline;%(PreprocessorDefinitions)
- true
- EnableFastChecks
- MultiThreadedDebugDLL
-
-
- Level3
- EditAndContinue
- Default
-
-
- true
- Windows
- MachineX86
-
-
-
-
- ..\..\..\mupen64plus-core\src\api;%(AdditionalIncludeDirectories)
- WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;inline=__inline;%(PreprocessorDefinitions)
- MultiThreadedDLL
-
-
- Level3
- ProgramDatabase
- Default
-
-
- true
- Windows
- true
- true
- MachineX86
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/projects/msvc/mupen64plus-rsp-hle.vcxproj b/projects/msvc/mupen64plus-rsp-hle.vcxproj
new file mode 100644
index 0000000..8d4b75b
--- /dev/null
+++ b/projects/msvc/mupen64plus-rsp-hle.vcxproj
@@ -0,0 +1,170 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ {2EC7CEE3-C7A7-4F2E-B2C8-4DF6AFEC3E9A}
+ mupen64plusrsphle
+
+
+ $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0'))
+ $(LatestTargetPlatformVersion)
+ $(WindowsTargetPlatformVersion)
+
+
+
+ $(DefaultPlatformToolset)
+
+
+ DynamicLibrary
+ MultiByte
+ true
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+
+
+ DynamicLibrary
+ MultiByte
+ true
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+
+
+ DynamicLibrary
+ MultiByte
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+
+
+ DynamicLibrary
+ MultiByte
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Disabled
+ ..\..\..\mupen64plus-core\src\api;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;inline=__inline;%(PreprocessorDefinitions)
+ EnableFastChecks
+ MultiThreadedDebugDLL
+ Level3
+
+
+ true
+ Windows
+
+
+
+
+ Disabled
+ ..\..\..\mupen64plus-core\src\api;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;inline=__inline;%(PreprocessorDefinitions)
+ EnableFastChecks
+ MultiThreadedDebugDLL
+ Level3
+
+
+ true
+ Windows
+
+
+
+
+ ..\..\..\mupen64plus-core\src\api;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;inline=__inline;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+ Level3
+ MaxSpeed
+ true
+ true
+
+
+ true
+ Windows
+ true
+ true
+
+
+
+
+ ..\..\..\mupen64plus-core\src\api;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;inline=__inline;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+ Level3
+ MaxSpeed
+ true
+ true
+
+
+ true
+ Windows
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/unix/Makefile b/projects/unix/Makefile
index a0d9b4e..213e122 100755
--- a/projects/unix/Makefile
+++ b/projects/unix/Makefile
@@ -1,6 +1,6 @@
#/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
# * mupen64plus-rsp-hle - Makefile *
-# * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+# * Mupen64Plus homepage: https://mupen64plus.org/ *
# * Copyright (C) 2008-2009 Richard Goedeken *
# * Copyright (C) 2007-2008 DarkJeztr Tillin9 *
# * *
@@ -53,7 +53,6 @@
OS = FREEBSD
SO_EXTENSION = so
SHARED = -shared
- $(warning OS type "$(UNAME)" not officially supported.')
endif
ifneq ("$(filter GNU/kFreeBSD kfreebsd,$(UNAME))","")
OS = LINUX
@@ -67,7 +66,7 @@
PIC = 0
endif
ifeq ("$(OS)","NONE")
- $(error OS type "$(UNAME)" not supported. Please file bug report at 'http://code.google.com/p/mupen64plus/issues')
+ $(error OS type "$(UNAME)" not supported. Please file bug report at 'https://github.com/mupen64plus/mupen64plus-core/issues')
endif
# detect system architecture
@@ -103,6 +102,13 @@
PIC ?= 1
$(warning Architecture "$(HOST_CPU)" not officially supported.')
endif
+ifneq ("$(filter ppc64le powerpc64le,$(HOST_CPU))","")
+ CPU := PPC
+ ARCH_DETECTED := 64BITS
+ BIG_ENDIAN := 0
+ PIC ?= 1
+ $(warning Architecture "$(HOST_CPU)" not officially supported.')
+endif
ifneq ("$(filter arm%,$(HOST_CPU))","")
ifeq ("$(filter arm%b,$(HOST_CPU))","")
CPU := ARM
@@ -117,14 +123,24 @@
PIC ?= 1
$(warning Architecture "$(HOST_CPU)" not officially supported.')
endif
+ifneq ("$(filter aarch64,$(HOST_CPU))","")
+ CPU := AARCH
+ ARCH_DETECTED := 64BITS
+ PIC ?= 1
+ NEW_DYNAREC := 1
+ NO_ASM := 1
+endif
ifeq ("$(CPU)","NONE")
- $(error CPU type "$(HOST_CPU)" not supported. Please file bug report at 'http://code.google.com/p/mupen64plus/issues')
-endif
+ $(error CPU type "$(HOST_CPU)" not supported. Please file bug report at 'https://github.com/mupen64plus/mupen64plus-core/issues')
+endif
+
+SRCDIR = ../../src
+OBJDIR = _obj$(POSTFIX)
# base CFLAGS, LDLIBS, and LDFLAGS
OPTFLAGS ?= -O3 -flto
WARNFLAGS ?= -Wall
-CFLAGS += $(OPTFLAGS) $(WARNFLAGS) -ffast-math -fno-strict-aliasing -fvisibility=hidden -I../../src
+CFLAGS += $(OPTFLAGS) $(WARNFLAGS) -ffast-math -fno-strict-aliasing -fvisibility=hidden -I$(SRCDIR)
LDFLAGS += $(SHARED)
# Since we are building a shared library, we must compile with -fPIC on some architectures
@@ -152,15 +168,14 @@
ifeq ($(OS), LINUX)
# only export api symbols
LDFLAGS += -Wl,-version-script,$(SRCDIR)/rsp_api_export.ver
+ LDLIBS += -ldl
endif
ifeq ($(OS), OSX)
- #xcode-select has been around since XCode 3.0, i.e. OS X 10.5
- OSX_SDK_ROOT = $(shell xcode-select -print-path)/Platforms/MacOSX.platform/Developer/SDKs
- OSX_SDK_PATH = $(OSX_SDK_ROOT)/$(shell ls $(OSX_SDK_ROOT) | tail -1)
+ OSX_SDK_PATH = $(shell xcrun --sdk macosx --show-sdk-path)
ifeq ($(CPU), X86)
ifeq ($(ARCH_DETECTED), 64BITS)
- CFLAGS += -pipe -arch x86_64 -mmacosx-version-min=10.5 -isysroot $(OSX_SDK_PATH)
+ CFLAGS += -pipe -arch x86_64 -mmacosx-version-min=10.9 -isysroot $(OSX_SDK_PATH)
else
CFLAGS += -pipe -mmmx -msse -fomit-frame-pointer -arch i686 -mmacosx-version-min=10.5 -isysroot $(OSX_SDK_PATH)
LDFLAGS += -read_only_relocs suppress
@@ -211,6 +226,7 @@
CFLAGS += -g
INSTALL_STRIP_FLAG ?=
else
+ CFLAGS += -DNDEBUG
ifneq ($(OS),OSX)
INSTALL_STRIP_FLAG ?= -s
endif
@@ -231,10 +247,6 @@
ifeq ($(DUMP), 1)
CFLAGS += -DENABLE_TASK_DUMP
endif
-
-
-SRCDIR = ../../src
-OBJDIR = _obj$(POSTFIX)
# list of source files to compile
SOURCE = \
@@ -245,11 +257,21 @@
$(SRCDIR)/audio.c \
$(SRCDIR)/cicx105.c \
$(SRCDIR)/hle.c \
+ $(SRCDIR)/hvqm.c \
$(SRCDIR)/jpeg.c \
$(SRCDIR)/memory.c \
$(SRCDIR)/mp3.c \
$(SRCDIR)/musyx.c \
+ $(SRCDIR)/re2.c \
$(SRCDIR)/plugin.c
+
+ifeq ($(OS), MINGW)
+SOURCE += \
+ $(SRCDIR)/osal_dynamiclib_win32.c
+else
+SOURCE += \
+ $(SRCDIR)/osal_dynamiclib_unix.c
+endif
# generate a list of object files build, make a temporary directory for them
OBJECTS := $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o, $(filter %.c, $(SOURCE)))
diff --git a/src/alist.c b/src/alist.c
index f6c87f0..ef3adc2 100644
--- a/src/alist.c
+++ b/src/alist.c
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - alist.c *
- * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* Copyright (C) 2009 Richard Goedeken *
* Copyright (C) 2002 Hacktarux *
@@ -50,17 +50,17 @@
static int16_t* sample(struct hle_t* hle, unsigned pos)
{
- return (int16_t*)hle->alist_buffer + (pos ^ S);
+ return (int16_t*)hle->alist_buffer + ((pos ^ S) & 0xfff);
}
static uint8_t* alist_u8(struct hle_t* hle, uint16_t dmem)
{
- return u8(hle->alist_buffer, dmem);
+ return (uint8_t*)(hle->alist_buffer + ((dmem ^ S8) & 0xfff));
}
static int16_t* alist_s16(struct hle_t* hle, uint16_t dmem)
{
- return (int16_t*)u16(hle->alist_buffer, dmem);
+ return (int16_t*)(hle->alist_buffer + ((dmem ^ S16) & 0xfff));
}
@@ -282,6 +282,7 @@
int x, y;
short save_buffer[40];
+ memcpy((uint8_t *)save_buffer, (hle->dram + address), sizeof(save_buffer));
if (init) {
ramps[0].value = (vol[0] << 16);
ramps[1].value = (vol[1] << 16);
@@ -292,7 +293,6 @@
exp_seq[0] = (vol[0] * rate[0]);
exp_seq[1] = (vol[1] * rate[1]);
} else {
- memcpy((uint8_t *)save_buffer, (hle->dram + address), 80);
wet = *(int16_t *)(save_buffer + 0); /* 0-1 */
dry = *(int16_t *)(save_buffer + 2); /* 2-3 */
ramps[0].target = *(int32_t *)(save_buffer + 4); /* 4-5 */
@@ -354,7 +354,7 @@
*(int32_t *)(save_buffer + 14) = exp_seq[1]; /* 14-15 */
*(int32_t *)(save_buffer + 16) = (int32_t)ramps[0].value; /* 12-13 */
*(int32_t *)(save_buffer + 18) = (int32_t)ramps[1].value; /* 14-15 */
- memcpy(hle->dram + address, (uint8_t *)save_buffer, 80);
+ memcpy(hle->dram + address, (uint8_t *)save_buffer, sizeof(save_buffer));
}
void alist_envmix_ge(
@@ -382,6 +382,7 @@
struct ramp_t ramps[2];
short save_buffer[40];
+ memcpy((uint8_t *)save_buffer, (hle->dram + address), 80);
if (init) {
ramps[0].value = (vol[0] << 16);
ramps[1].value = (vol[1] << 16);
@@ -390,7 +391,6 @@
ramps[0].step = rate[0] / 8;
ramps[1].step = rate[1] / 8;
} else {
- memcpy((uint8_t *)save_buffer, (hle->dram + address), 80);
wet = *(int16_t *)(save_buffer + 0); /* 0-1 */
dry = *(int16_t *)(save_buffer + 2); /* 2-3 */
ramps[0].target = *(int32_t *)(save_buffer + 4); /* 4-5 */
@@ -458,6 +458,7 @@
int16_t* const wl = (int16_t*)(hle->alist_buffer + dmem_wl);
int16_t* const wr = (int16_t*)(hle->alist_buffer + dmem_wr);
+ memcpy((uint8_t *)save_buffer, hle->dram + address, 80);
if (init) {
ramps[0].step = rate[0] / 8;
ramps[0].value = (vol[0] << 16);
@@ -467,7 +468,6 @@
ramps[1].target = (target[1] << 16);
}
else {
- memcpy((uint8_t *)save_buffer, hle->dram + address, 80);
wet = *(int16_t *)(save_buffer + 0); /* 0-1 */
dry = *(int16_t *)(save_buffer + 2); /* 2-3 */
ramps[0].target = *(int16_t *)(save_buffer + 4) << 16; /* 4-5 */
@@ -666,11 +666,11 @@
while (count != 0) {
const int16_t* lut = RESAMPLE_LUT + ((pitch_accu & 0xfc00) >> 8);
- *sample(hle, opos++) = clamp_s16(
- ((*sample(hle, ipos ) * lut[0]) >> 15) +
- ((*sample(hle, ipos + 1) * lut[1]) >> 15) +
- ((*sample(hle, ipos + 2) * lut[2]) >> 15) +
- ((*sample(hle, ipos + 3) * lut[3]) >> 15));
+ *sample(hle, opos++) = clamp_s16( (
+ (*sample(hle, ipos ) * lut[0]) +
+ (*sample(hle, ipos + 1) * lut[1]) +
+ (*sample(hle, ipos + 2) * lut[2]) +
+ (*sample(hle, ipos + 3) * lut[3]) ) >> 15);
pitch_accu += pitch;
ipos += (pitch_accu >> 16);
@@ -961,7 +961,7 @@
count -= 16;
} while (count != 0);
- dram_store_u16(hle, (uint16_t*)(dst - 4), address, 4);
+ dram_store_u32(hle, (uint32_t*)(dst - 4), address, 2);
}
void alist_iirf(
diff --git a/src/alist.h b/src/alist.h
index 6e61043..398cdb8 100644
--- a/src/alist.h
+++ b/src/alist.h
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - alist.h *
- * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* This program is free software; you can redistribute it and/or modify *
diff --git a/src/alist_audio.c b/src/alist_audio.c
index ac54714..0d2dcea 100644
--- a/src/alist_audio.c
+++ b/src/alist_audio.c
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - alist_audio.c *
- * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* Copyright (C) 2009 Richard Goedeken *
* Copyright (C) 2002 Hacktarux *
@@ -57,7 +57,7 @@
static void CLEARBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint16_t dmem = w1 + DMEM_BASE;
- uint16_t count = w2;
+ uint16_t count = w2 & 0xfff;
if (count == 0)
return;
@@ -111,7 +111,7 @@
alist_resample(
hle,
- flags & 0x1,
+ flags & A_INIT,
flags & 0x2,
hle->alist_audio.out,
hle->alist_audio.in,
@@ -152,8 +152,8 @@
alist_adpcm(
hle,
- flags & 0x1,
- flags & 0x2,
+ flags & A_INIT,
+ flags & A_LOOP,
false, /* unsupported in this ucode */
hle->alist_audio.out,
hle->alist_audio.in,
@@ -278,6 +278,7 @@
clear_segments(hle);
alist_process(hle, ABI, 0x10);
+ rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_audio_ge(struct hle_t* hle)
@@ -291,6 +292,7 @@
clear_segments(hle);
alist_process(hle, ABI, 0x10);
+ rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_audio_bc(struct hle_t* hle)
@@ -304,4 +306,5 @@
clear_segments(hle);
alist_process(hle, ABI, 0x10);
-}
+ rsp_break(hle, SP_STATUS_TASKDONE);
+}
diff --git a/src/alist_naudio.c b/src/alist_naudio.c
index 4cff9f7..bb53dd7 100644
--- a/src/alist_naudio.c
+++ b/src/alist_naudio.c
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - alist_naudio.c *
- * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* Copyright (C) 2009 Richard Goedeken *
* Copyright (C) 2002 Hacktarux *
@@ -108,18 +108,18 @@
{
uint8_t flags = (w1 >> 16);
- if (flags & 0x4) {
- if (flags & 0x2) {
+ if (flags & A_VOL) {
+ if (flags & A_LEFT) {
hle->alist_naudio.vol[0] = w1;
hle->alist_naudio.dry = (w2 >> 16);
hle->alist_naudio.wet = w2;
}
- else {
+ else { /* A_RIGHT */
hle->alist_naudio.target[1] = w1;
hle->alist_naudio.rate[1] = w2;
}
}
- else {
+ else { /* A_RATE */
hle->alist_naudio.target[0] = w1;
hle->alist_naudio.rate[0] = w2;
}
@@ -134,7 +134,7 @@
alist_envmix_lin(
hle,
- flags & 0x1,
+ flags & A_INIT,
NAUDIO_DRY_LEFT,
NAUDIO_DRY_RIGHT,
NAUDIO_WET_LEFT,
@@ -152,7 +152,7 @@
static void CLEARBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint16_t dmem = w1 + NAUDIO_MAIN;
- uint16_t count = w2;
+ uint16_t count = w2 & 0xfff;
alist_clear(hle, dmem, count);
}
@@ -216,8 +216,8 @@
alist_adpcm(
hle,
- flags & 0x1,
- flags & 0x2,
+ flags & A_INIT,
+ flags & A_LOOP,
false, /* unsuported by this ucode */
dmemo,
dmemi,
@@ -237,7 +237,7 @@
alist_resample(
hle,
- flags & 0x1,
+ flags & A_INIT,
false, /* TODO: check which ABI supports it */
dmemo,
dmemi,
@@ -274,6 +274,7 @@
};
alist_process(hle, ABI, 0x10);
+ rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_naudio_bk(struct hle_t* hle)
@@ -287,6 +288,7 @@
};
alist_process(hle, ABI, 0x10);
+ rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_naudio_dk(struct hle_t* hle)
@@ -300,6 +302,7 @@
};
alist_process(hle, ABI, 0x10);
+ rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_naudio_mp3(struct hle_t* hle)
@@ -312,6 +315,7 @@
};
alist_process(hle, ABI, 0x10);
+ rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_naudio_cbfd(struct hle_t* hle)
@@ -325,4 +329,5 @@
};
alist_process(hle, ABI, 0x10);
-}
+ rsp_break(hle, SP_STATUS_TASKDONE);
+}
diff --git a/src/alist_nead.c b/src/alist_nead.c
index b8ce3c9..11dcb80 100644
--- a/src/alist_nead.c
+++ b/src/alist_nead.c
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - alist_nead.c *
- * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* Copyright (C) 2009 Richard Goedeken *
* Copyright (C) 2002 Hacktarux *
@@ -92,7 +92,7 @@
static void CLEARBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint16_t dmem = w1;
- uint16_t count = w2;
+ uint16_t count = w2 & 0xfff;
if (count == 0)
return;
@@ -300,7 +300,7 @@
static void HILOGAIN(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
int8_t gain = (w1 >> 16); /* Q4.4 signed */
- uint16_t count = w1;
+ uint16_t count = w1 & 0xfff;
uint16_t dmem = (w2 >> 16);
alist_multQ44(hle, dmem, count, gain);
@@ -372,6 +372,7 @@
};
alist_process(hle, ABI, 0x20);
+ rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_nead_sf(struct hle_t* hle)
@@ -388,6 +389,7 @@
};
alist_process(hle, ABI, 0x20);
+ rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_nead_sfj(struct hle_t* hle)
@@ -404,6 +406,7 @@
};
alist_process(hle, ABI, 0x20);
+ rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_nead_fz(struct hle_t* hle)
@@ -420,6 +423,7 @@
};
alist_process(hle, ABI, 0x20);
+ rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_nead_wrjb(struct hle_t* hle)
@@ -436,6 +440,7 @@
};
alist_process(hle, ABI, 0x20);
+ rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_nead_ys(struct hle_t* hle)
@@ -450,6 +455,7 @@
};
alist_process(hle, ABI, 0x18);
+ rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_nead_1080(struct hle_t* hle)
@@ -464,6 +470,7 @@
};
alist_process(hle, ABI, 0x18);
+ rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_nead_oot(struct hle_t* hle)
@@ -478,6 +485,7 @@
};
alist_process(hle, ABI, 0x18);
+ rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_nead_mm(struct hle_t* hle)
@@ -492,6 +500,7 @@
};
alist_process(hle, ABI, 0x18);
+ rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_nead_mmb(struct hle_t* hle)
@@ -506,6 +515,7 @@
};
alist_process(hle, ABI, 0x18);
+ rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_nead_ac(struct hle_t* hle)
@@ -520,4 +530,27 @@
};
alist_process(hle, ABI, 0x18);
-}
+ rsp_break(hle, SP_STATUS_TASKDONE);
+}
+
+void alist_process_nead_mats(struct hle_t* hle)
+{
+ /* FIXME: implement proper ucode
+ * Forward the task if possible,
+ * otherwise better to have no sound than garbage sound
+ */
+ if (HleForwardTask(hle->user_defined) != 0) {
+ rsp_break(hle, SP_STATUS_TASKDONE);
+ }
+}
+
+void alist_process_nead_efz(struct hle_t* hle)
+{
+ /* FIXME: implement proper ucode
+ * Forward the task if possible,
+ * otherwise use FZero ucode which should be very similar
+ */
+ if (HleForwardTask(hle->user_defined) != 0) {
+ alist_process_nead_fz(hle);
+ }
+}
diff --git a/src/arithmetics.h b/src/arithmetics.h
index 529293d..2250b24 100644
--- a/src/arithmetics.h
+++ b/src/arithmetics.h
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - arithmetics.h *
- * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* This program is free software; you can redistribute it and/or modify *
diff --git a/src/audio.c b/src/audio.c
index 9a14ad5..fac2a10 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - audio.c *
- * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* This program is free software; you can redistribute it and/or modify *
diff --git a/src/audio.h b/src/audio.h
index 8942a78..21c7a09 100644
--- a/src/audio.h
+++ b/src/audio.h
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - audio.h *
- * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* This program is free software; you can redistribute it and/or modify *
diff --git a/src/cicx105.c b/src/cicx105.c
index 7ed8ae2..bda5eca 100644
--- a/src/cicx105.c
+++ b/src/cicx105.c
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - cicx105.c *
- * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2012 Bobby Smiles *
* Copyright (C) 2009 Richard Goedeken *
* Copyright (C) 2002 Hacktarux *
@@ -50,5 +50,7 @@
src += 0x8;
}
+
+ rsp_break(hle, 0);
}
diff --git a/src/common.h b/src/common.h
index 48a9229..cd5dfa6 100644
--- a/src/common.h
+++ b/src/common.h
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - common.h *
- * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* This program is free software; you can redistribute it and/or modify *
diff --git a/src/hle.c b/src/hle.c
index ea0e1b7..4e65113 100644
--- a/src/hle.c
+++ b/src/hle.c
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - hle.c *
- * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2012 Bobby Smiles *
* Copyright (C) 2009 Richard Goedeken *
* Copyright (C) 2002 Hacktarux *
@@ -35,39 +35,27 @@
#define min(a,b) (((a) < (b)) ? (a) : (b))
-/* some rsp status flags */
-#define SP_STATUS_HALT 0x1
-#define SP_STATUS_BROKE 0x2
-#define SP_STATUS_INTR_ON_BREAK 0x40
-#define SP_STATUS_TASKDONE 0x200
-
/* some rdp status flags */
#define DP_STATUS_FREEZE 0x2
-/* some mips interface interrupt flags */
-#define MI_INTR_SP 0x1
/* helper functions prototypes */
static unsigned int sum_bytes(const unsigned char *bytes, unsigned int size);
static bool is_task(struct hle_t* hle);
-static void rsp_break(struct hle_t* hle, unsigned int setbits);
-static void forward_gfx_task(struct hle_t* hle);
-static bool try_fast_audio_dispatching(struct hle_t* hle);
-static bool try_fast_task_dispatching(struct hle_t* hle);
-static void normal_task_dispatching(struct hle_t* hle);
-static void non_task_dispatching(struct hle_t* hle);
+static void send_dlist_to_gfx_plugin(struct hle_t* hle);
+static ucode_func_t try_audio_task_detection(struct hle_t* hle);
+static ucode_func_t try_normal_task_detection(struct hle_t* hle);
+static ucode_func_t non_task_detection(struct hle_t* hle);
+static ucode_func_t task_detection(struct hle_t* hle);
#ifdef ENABLE_TASK_DUMP
static void dump_binary(struct hle_t* hle, const char *const filename,
const unsigned char *const bytes, unsigned int size);
static void dump_task(struct hle_t* hle, const char *const filename);
-static void dump_unknown_task(struct hle_t* hle, unsigned int sum);
-static void dump_unknown_non_task(struct hle_t* hle, unsigned int sum);
+static void dump_unknown_task(struct hle_t* hle, unsigned int uc_start);
+static void dump_unknown_non_task(struct hle_t* hle, unsigned int uc_start);
#endif
-
-/* local variables */
-static const bool FORWARD_AUDIO = false, FORWARD_GFX = true;
/* Global functions */
void hle_init(struct hle_t* hle,
@@ -120,14 +108,38 @@
void hle_execute(struct hle_t* hle)
{
- if (is_task(hle)) {
- if (!try_fast_task_dispatching(hle))
- normal_task_dispatching(hle);
- rsp_break(hle, SP_STATUS_TASKDONE);
- } else {
- non_task_dispatching(hle);
- rsp_break(hle, 0);
- }
+ uint32_t uc_start = *dmem_u32(hle, TASK_UCODE);
+ uint32_t uc_dstart = *dmem_u32(hle, TASK_UCODE_DATA);
+ uint32_t uc_dsize = *dmem_u32(hle, TASK_UCODE_DATA_SIZE);
+
+ bool match = false;
+ struct cached_ucodes_t * cached_ucodes = &hle->cached_ucodes;
+ struct ucode_info_t *info = NULL;
+ if (cached_ucodes->count > 0)
+ info = &cached_ucodes->infos[cached_ucodes->count-1];
+ for (int i = 0; i < cached_ucodes->count; i++)
+ {
+ if (info->uc_start == uc_start && info->uc_dstart == uc_dstart && info->uc_dsize == uc_dsize)
+ {
+ match = true;
+ break;
+ }
+ info--;
+ }
+
+ if (!match)
+ {
+ 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);
+ assert(info->uc_pfunc != NULL);
+ }
+
+ info->uc_pfunc(hle);
}
/* local functions */
@@ -157,7 +169,7 @@
return (*dmem_u32(hle, TASK_UCODE_BOOT_SIZE) <= 0x1000);
}
-static void rsp_break(struct hle_t* hle, unsigned int setbits)
+void rsp_break(struct hle_t* hle, unsigned int setbits)
{
*hle->sp_status |= setbits | SP_STATUS_BROKE | SP_STATUS_HALT;
@@ -167,12 +179,66 @@
}
}
-static void forward_gfx_task(struct hle_t* hle)
-{
+static void send_alist_to_audio_plugin(struct hle_t* hle)
+{
+ HleProcessAlistList(hle->user_defined);
+ rsp_break(hle, SP_STATUS_TASKDONE);
+}
+
+static void send_dlist_to_gfx_plugin(struct hle_t* hle)
+{
+ /* Since GFX_INFO version 2, these bits are set before calling the ProcessDlistList function.
+ * And the GFX plugin is responsible to unset them if needed.
+ * For GFX_INFO version < 2, the GFX plugin didn't have access to sp_status so
+ * it doesn't matter if we set these bits before calling ProcessDlistList function.
+ */
+ *hle->sp_status |= SP_STATUS_TASKDONE | SP_STATUS_BROKE | SP_STATUS_HALT;
+
HleProcessDlistList(hle->user_defined);
-}
-
-static bool try_fast_audio_dispatching(struct hle_t* hle)
+
+ if ((*hle->sp_status & SP_STATUS_INTR_ON_BREAK) && (*hle->sp_status & (SP_STATUS_TASKDONE | SP_STATUS_BROKE | SP_STATUS_HALT))) {
+ *hle->mi_intr |= MI_INTR_SP;
+ HleCheckInterrupts(hle->user_defined);
+ }
+}
+
+static void task_done(struct hle_t* hle)
+{
+ rsp_break(hle, SP_STATUS_TASKDONE);
+}
+
+static void unknown_ucode(struct hle_t* hle)
+{
+ /* Forward task to RSP Fallback.
+ * If task is not forwarded, use the regular "unknown ucode" path */
+ if (HleForwardTask(hle->user_defined) != 0) {
+
+ uint32_t uc_start = *dmem_u32(hle, TASK_UCODE);
+ HleWarnMessage(hle->user_defined, "unknown RSP code: uc_start: %x PC:%x", uc_start, *hle->sp_pc);
+#ifdef ENABLE_TASK_DUMP
+ dump_unknown_non_task(hle, uc_start);
+#endif
+ }
+}
+
+static void unknown_task(struct hle_t* hle)
+{
+ /* Forward task to RSP Fallback.
+ * If task is not forwarded, use the regular "unknown task" path */
+ if (HleForwardTask(hle->user_defined) != 0) {
+
+ /* Send task_done signal for unknown ucodes to allow further processings */
+ rsp_break(hle, SP_STATUS_TASKDONE);
+
+ uint32_t uc_start = *dmem_u32(hle, TASK_UCODE);
+ HleWarnMessage(hle->user_defined, "unknown OSTask: uc_start: %x PC:%x", uc_start, *hle->sp_pc);
+#ifdef ENABLE_TASK_DUMP
+ dump_unknown_task(hle, uc_start);
+#endif
+ }
+}
+
+static ucode_func_t try_audio_task_detection(struct hle_t* hle)
{
/* identify audio ucode by using the content of ucode_data */
uint32_t ucode_data = *dmem_u32(hle, TASK_UCODE_DATA);
@@ -184,11 +250,11 @@
switch(v)
{
case 0x1e24138c: /* audio ABI (most common) */
- alist_process_audio(hle); return true;
+ return &alist_process_audio;
case 0x1dc8138c: /* GoldenEye */
- alist_process_audio_ge(hle); return true;
+ return &alist_process_audio_ge;
case 0x1e3c1390: /* BlastCorp, DiddyKongRacing */
- alist_process_audio_bc(hle); return true;
+ return &alist_process_audio_bc;
default:
HleWarnMessage(hle->user_defined, "ABI1 identification regression: v=%08x", v);
}
@@ -197,30 +263,33 @@
switch(v)
{
case 0x11181350: /* MarioKart, WaveRace (E) */
- alist_process_nead_mk(hle); return true;
+ return &alist_process_nead_mk;
case 0x111812e0: /* StarFox (J) */
- alist_process_nead_sfj(hle); return true;
+ return &alist_process_nead_sfj;
case 0x110412ac: /* WaveRace (J RevB) */
- alist_process_nead_wrjb(hle); return true;
+ return &alist_process_nead_wrjb;
case 0x110412cc: /* StarFox/LylatWars (except J) */
- alist_process_nead_sf(hle); return true;
+ return &alist_process_nead_sf;
case 0x1cd01250: /* FZeroX */
- alist_process_nead_fz(hle); return true;
+ return &alist_process_nead_fz;
case 0x1f08122c: /* YoshisStory */
- alist_process_nead_ys(hle); return true;
+ return &alist_process_nead_ys;
case 0x1f38122c: /* 1080° Snowboarding */
- alist_process_nead_1080(hle); return true;
+ return &alist_process_nead_1080;
case 0x1f681230: /* Zelda OoT / Zelda MM (J, J RevA) */
- alist_process_nead_oot(hle); return true;
+ return &alist_process_nead_oot;
case 0x1f801250: /* Zelda MM (except J, J RevA, E Beta), PokemonStadium 2 */
- alist_process_nead_mm(hle); return true;
+ return &alist_process_nead_mm;
case 0x109411f8: /* Zelda MM (E Beta) */
- alist_process_nead_mmb(hle); return true;
+ return &alist_process_nead_mmb;
case 0x1eac11b8: /* AnimalCrossing */
- alist_process_nead_ac(hle); return true;
+ return &alist_process_nead_ac;
case 0x00010010: /* MusyX v2 (IndianaJones, BattleForNaboo) */
- musyx_v2_task(hle); return true;
-
+ return &musyx_v2_task;
+ case 0x1f701238: /* Mario Artist Talent Studio */
+ return &alist_process_nead_mats;
+ case 0x1f4c1230: /* FZeroX Expansion */
+ return &alist_process_nead_efz;
default:
HleWarnMessage(hle->user_defined, "ABI2 identification regression: v=%08x", v);
}
@@ -233,156 +302,172 @@
RogueSquadron, ResidentEvil2, PolarisSnoCross,
TheWorldIsNotEnough, RugratsInParis, NBAShowTime,
HydroThunder, Tarzan, GauntletLegend, Rush2049 */
- musyx_v1_task(hle); return true;
+ return &musyx_v1_task;
case 0x0000127c: /* naudio (many games) */
- alist_process_naudio(hle); return true;
+ return &alist_process_naudio;
case 0x00001280: /* BanjoKazooie */
- alist_process_naudio_bk(hle); return true;
+ return &alist_process_naudio_bk;
case 0x1c58126c: /* DonkeyKong */
- alist_process_naudio_dk(hle); return true;
+ return &alist_process_naudio_dk;
case 0x1ae8143c: /* BanjoTooie, JetForceGemini, MickeySpeedWayUSA, PerfectDark */
- alist_process_naudio_mp3(hle); return true;
+ return &alist_process_naudio_mp3;
case 0x1ab0140c: /* ConkerBadFurDay */
- alist_process_naudio_cbfd(hle); return true;
+ return &alist_process_naudio_cbfd;
default:
HleWarnMessage(hle->user_defined, "ABI3 identification regression: v=%08x", v);
}
}
- return false;
-}
-
-static bool try_fast_task_dispatching(struct hle_t* hle)
-{
- /* identify task ucode by its type */
- switch (*dmem_u32(hle, TASK_TYPE)) {
- case 1:
- if (FORWARD_GFX) {
- forward_gfx_task(hle);
- return true;
- }
- break;
-
- case 2:
- if (FORWARD_AUDIO) {
- HleProcessAlistList(hle->user_defined);
- return true;
- } else if (try_fast_audio_dispatching(hle))
- return true;
- break;
-
- case 7:
- HleShowCFB(hle->user_defined);
- return true;
- }
-
- return false;
-}
-
-static void normal_task_dispatching(struct hle_t* hle)
-{
- const unsigned int sum =
+ return NULL;
+}
+
+static ucode_func_t try_normal_task_detection(struct hle_t* hle)
+{
+ unsigned int sum =
sum_bytes((void*)dram_u32(hle, *dmem_u32(hle, TASK_UCODE)), min(*dmem_u32(hle, TASK_UCODE_SIZE), 0xf80) >> 1);
switch (sum) {
/* StoreVe12: found in Zelda Ocarina of Time [misleading task->type == 4] */
case 0x278:
/* Nothing to emulate */
- return;
+ return &task_done;
/* GFX: Twintris [misleading task->type == 0] */
case 0x212ee:
- if (FORWARD_GFX) {
- forward_gfx_task(hle);
- return;
+ if (hle->hle_gfx) {
+ return &send_dlist_to_gfx_plugin;
}
- break;
+ return NULL;
/* JPEG: found in Pokemon Stadium J */
case 0x2c85a:
- jpeg_decode_PS0(hle);
- return;
+ return &jpeg_decode_PS0;
/* JPEG: found in Zelda Ocarina of Time, Pokemon Stadium 1, Pokemon Stadium 2 */
case 0x2caa6:
- jpeg_decode_PS(hle);
- return;
+ return &jpeg_decode_PS;
/* JPEG: found in Ogre Battle, Bottom of the 9th */
case 0x130de:
case 0x278b0:
- jpeg_decode_OB(hle);
- return;
- }
-
- HleWarnMessage(hle->user_defined, "unknown OSTask: sum: %x PC:%x", sum, *hle->sp_pc);
-#ifdef ENABLE_TASK_DUMP
- dump_unknown_task(hle, sum);
-#endif
-}
-
-static void non_task_dispatching(struct hle_t* hle)
+ return &jpeg_decode_OB;
+ }
+
+ /* Resident Evil 2 */
+ sum = sum_bytes((void*)dram_u32(hle, *dmem_u32(hle, TASK_UCODE)), 256);
+ switch (sum) {
+
+ case 0x450f:
+ return &resize_bilinear_task;
+
+ case 0x3b44:
+ return &decode_video_frame_task;
+
+ case 0x3d84:
+ return &fill_video_double_buffer_task;
+ }
+
+ /* HVQM */
+ sum = sum_bytes((void*)dram_u32(hle, *dmem_u32(hle, TASK_UCODE)), 1488);
+ switch (sum) {
+ case 0x19495:
+ return &hvqm2_decode_sp1_task;
+
+ case 0x19728:
+ return &hvqm2_decode_sp2_task;
+ }
+
+ return NULL;
+}
+
+static ucode_func_t non_task_detection(struct hle_t* hle)
{
const unsigned int sum = sum_bytes(hle->imem, 44);
if (sum == 0x9e2)
{
/* CIC x105 ucode (used during boot of CIC x105 games) */
- cicx105_ucode(hle);
- return;
- }
-
- HleWarnMessage(hle->user_defined, "unknown RSP code: sum: %x PC:%x", sum, *hle->sp_pc);
+ return &cicx105_ucode;
+ }
+ return &unknown_ucode;
+}
+
+static ucode_func_t task_detection(struct hle_t* hle)
+{
+ if (is_task(hle)) {
+ ucode_func_t uc_pfunc;
+ uint32_t type = *dmem_u32(hle, TASK_TYPE);
+
+ if (type == 2) {
+ if (hle->hle_aud) {
+ return &send_alist_to_audio_plugin;
+ }
+ uc_pfunc = try_audio_task_detection(hle);
+ if (uc_pfunc)
+ return uc_pfunc;
+ }
+
+ uc_pfunc = try_normal_task_detection(hle);
+ if (uc_pfunc)
+ return uc_pfunc;
+
+ if (type == 1) {
+ if (hle->hle_gfx) {
+ return &send_dlist_to_gfx_plugin;
+ }
+ }
+
+ return &unknown_task;
+ }
+ else {
+ return non_task_detection(hle);
+ }
+}
+
#ifdef ENABLE_TASK_DUMP
- dump_unknown_non_task(hle, sum);
-#endif
-}
-
-
-#ifdef ENABLE_TASK_DUMP
-static void dump_unknown_task(struct hle_t* hle, unsigned int sum)
+static void dump_unknown_task(struct hle_t* hle, unsigned int uc_start)
{
char filename[256];
uint32_t ucode = *dmem_u32(hle, TASK_UCODE);
uint32_t ucode_data = *dmem_u32(hle, TASK_UCODE_DATA);
uint32_t data_ptr = *dmem_u32(hle, TASK_DATA_PTR);
- sprintf(&filename[0], "task_%x.log", sum);
+ sprintf(&filename[0], "task_%x.log", uc_start);
dump_task(hle, filename);
/* dump ucode_boot */
- sprintf(&filename[0], "ucode_boot_%x.bin", sum);
+ sprintf(&filename[0], "ucode_boot_%x.bin", uc_start);
dump_binary(hle, filename, (void*)dram_u32(hle, *dmem_u32(hle, TASK_UCODE_BOOT)), *dmem_u32(hle, TASK_UCODE_BOOT_SIZE));
/* dump ucode */
if (ucode != 0) {
- sprintf(&filename[0], "ucode_%x.bin", sum);
+ sprintf(&filename[0], "ucode_%x.bin", uc_start);
dump_binary(hle, filename, (void*)dram_u32(hle, ucode), 0xf80);
}
/* dump ucode_data */
if (ucode_data != 0) {
- sprintf(&filename[0], "ucode_data_%x.bin", sum);
+ sprintf(&filename[0], "ucode_data_%x.bin", uc_start);
dump_binary(hle, filename, (void*)dram_u32(hle, ucode_data), *dmem_u32(hle, TASK_UCODE_DATA_SIZE));
}
/* dump data */
if (data_ptr != 0) {
- sprintf(&filename[0], "data_%x.bin", sum);
+ sprintf(&filename[0], "data_%x.bin", uc_start);
dump_binary(hle, filename, (void*)dram_u32(hle, data_ptr), *dmem_u32(hle, TASK_DATA_SIZE));
}
}
-static void dump_unknown_non_task(struct hle_t* hle, unsigned int sum)
+static void dump_unknown_non_task(struct hle_t* hle, unsigned int uc_start)
{
char filename[256];
/* dump IMEM & DMEM for further analysis */
- sprintf(&filename[0], "imem_%x.bin", sum);
+ sprintf(&filename[0], "imem_%x.bin", uc_start);
dump_binary(hle, filename, hle->imem, 0x1000);
- sprintf(&filename[0], "dmem_%x.bin", sum);
+ sprintf(&filename[0], "dmem_%x.bin", uc_start);
dump_binary(hle, filename, hle->dmem, 0x1000);
}
diff --git a/src/hle.h b/src/hle.h
index 3c705a9..a420b75 100644
--- a/src/hle.h
+++ b/src/hle.h
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - hle.h *
- * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* This program is free software; you can redistribute it and/or modify *
diff --git a/src/hle_external.h b/src/hle_external.h
index 2f35a3c..766cc51 100644
--- a/src/hle_external.h
+++ b/src/hle_external.h
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - hle_external.h *
- * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* This program is free software; you can redistribute it and/or modify *
@@ -22,17 +22,25 @@
#ifndef HLE_EXTERNAL_H
#define HLE_EXTERNAL_H
+#if defined(__GNUC__)
+#define ATTR_FMT(fmtpos, attrpos) __attribute__ ((format (printf, fmtpos, attrpos)))
+#else
+#define ATTR_FMT(fmtpos, attrpos)
+#endif
+
/* users of the hle core are expected to define these functions */
-void HleVerboseMessage(void* user_defined, const char *message, ...);
-void HleErrorMessage(void* user_defined, const char *message, ...);
-void HleWarnMessage(void* user_defined, const char *message, ...);
+void HleVerboseMessage(void* user_defined, const char *message, ...) ATTR_FMT(2, 3);
+void HleInfoMessage(void* user_defined, const char *message, ...) ATTR_FMT(2, 3);
+void HleErrorMessage(void* user_defined, const char *message, ...) ATTR_FMT(2, 3);
+void HleWarnMessage(void* user_defined, const char *message, ...) ATTR_FMT(2, 3);
void HleCheckInterrupts(void* user_defined);
void HleProcessDlistList(void* user_defined);
void HleProcessAlistList(void* user_defined);
void HleProcessRdpList(void* user_defined);
void HleShowCFB(void* user_defined);
+int HleForwardTask(void* user_defined);
#endif
diff --git a/src/hle_internal.h b/src/hle_internal.h
index 352d956..efdca5c 100644
--- a/src/hle_internal.h
+++ b/src/hle_internal.h
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - hle_internal.h *
- * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* This program is free software; you can redistribute it and/or modify *
@@ -57,6 +57,8 @@
/* for user convenience, this will be passed to "external" functions */
void* user_defined;
+ int hle_gfx;
+ int hle_aud;
/* alist.c */
uint8_t alist_buffer[0x1000];
@@ -72,7 +74,20 @@
/* mp3.c */
uint8_t mp3_buffer[0x1000];
+
+ struct cached_ucodes_t cached_ucodes;
};
+
+/* some mips interface interrupt flags */
+#define MI_INTR_SP 0x1
+
+/* some rsp status flags */
+#define SP_STATUS_HALT 0x1
+#define SP_STATUS_BROKE 0x2
+#define SP_STATUS_INTR_ON_BREAK 0x40
+#define SP_STATUS_TASKDONE 0x200
+
+void rsp_break(struct hle_t* hle, unsigned int setbits);
#endif
diff --git a/src/hvqm.c b/src/hvqm.c
new file mode 100644
index 0000000..8f8a943
--- /dev/null
+++ b/src/hvqm.c
@@ -0,0 +1,354 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Mupen64plus-rsp-hle - hvqm.c *
+ * Mupen64Plus homepage: https://mupen64plus.org/ *
+ * Copyright (C) 2020 Gilles Siberlin *
+ * *
+ * 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
+#include
+#include
+#include
+#include
+
+#include "hle_external.h"
+#include "hle_internal.h"
+#include "memory.h"
+
+ /* Nest size */
+#define HVQM2_NESTSIZE_L 70 /* Number of elements on long side */
+#define HVQM2_NESTSIZE_S 38 /* Number of elements on short side */
+#define HVQM2_NESTSIZE (HVQM2_NESTSIZE_L * HVQM2_NESTSIZE_S)
+
+struct HVQM2Block {
+ uint8_t nbase;
+ uint8_t dc;
+ uint8_t dc_l;
+ uint8_t dc_r;
+ uint8_t dc_u;
+ uint8_t dc_d;
+};
+
+struct HVQM2Basis {
+ uint8_t sx;
+ uint8_t sy;
+ int16_t scale;
+ uint16_t offset;
+ uint16_t lineskip;
+};
+
+struct HVQM2Arg {
+ uint32_t info;
+ uint32_t buf;
+ uint16_t buf_width;
+ uint8_t chroma_step_h;
+ uint8_t chroma_step_v;
+ uint16_t hmcus;
+ uint16_t vmcus;
+ uint8_t alpha;
+ uint32_t nest;
+};
+
+struct RGBA {
+ uint8_t r;
+ uint8_t g;
+ uint8_t b;
+ uint8_t a;
+};
+
+static struct HVQM2Arg arg;
+
+static const int16_t constant[5][16] = {
+{0x0006,0x0008,0x0008,0x0006,0x0008,0x000A,0x000A,0x0008,0x0008,0x000A,0x000A,0x0008,0x0006,0x0008,0x0008,0x0006},
+{0x0002,0x0000,0xFFFF,0xFFFF,0x0002,0x0000,0xFFFF,0xFFFF,0x0002,0x0000,0xFFFF,0xFFFF,0x0002,0x0000,0xFFFF,0xFFFF},
+{0xFFFF,0xFFFF,0x0000,0x0002,0xFFFF,0xFFFF,0x0000,0x0002,0xFFFF,0xFFFF,0x0000,0x0002,0xFFFF,0xFFFF,0x0000,0x0002},
+{0x0002,0x0002,0x0002,0x0002,0x0000,0x0000,0x0000,0x0000,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF},
+{0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0x0000,0x0000,0x0000,0x0000,0x0002,0x0002,0x0002,0x0002}
+};
+
+static int process_info(struct hle_t* hle, uint8_t* base, int16_t* out)
+{
+ struct HVQM2Block block;
+ uint8_t nbase = *base;
+
+ dram_load_u8(hle, (uint8_t*)&block, arg.info, sizeof(struct HVQM2Block));
+ arg.info += 8;
+
+ *base = block.nbase & 0x7;
+
+ if ((block.nbase & nbase) != 0)
+ return 0;
+
+ if (block.nbase == 0)
+ {
+ //LABEL8
+ for (int i = 0; i < 16; i++)
+ {
+ out[i] = constant[0][i] * block.dc;
+ out[i] += constant[1][i] * block.dc_l;
+ out[i] += constant[2][i] * block.dc_r;
+ out[i] += constant[3][i] * block.dc_u;
+ out[i] += constant[4][i] * block.dc_d;
+ out[i] += 4;
+ out[i] >>= 3;
+ }
+ }
+ else if ((block.nbase & 0xf) == 0)
+ {
+ //LABEL7
+ for (int i = 0; i < 16; i++)
+ {
+ out[i] = *dram_u8(hle, arg.info);
+ arg.info++;
+ }
+ }
+ else if (*base == 0)
+ {
+ //LABEL6
+ for (int i = 0; i < 16; i++)
+ {
+ out[i] = *(int8_t*)dram_u8(hle, arg.info) + block.dc;
+ arg.info++;
+ }
+ }
+ else
+ {
+ //LABEL5
+ struct HVQM2Basis basis;
+
+ for (int i = 0; i < 16; i++)
+ out[i] = block.dc;
+
+ for (; *base != 0; (*base)--)
+ {
+ basis.sx = *dram_u8(hle, arg.info);
+ arg.info++;
+ basis.sy = *dram_u8(hle, arg.info);
+ arg.info++;
+ basis.scale = *dram_u16(hle, arg.info);
+ arg.info += 2;
+ basis.offset = *dram_u16(hle, arg.info);
+ arg.info += 2;
+ basis.lineskip = *dram_u16(hle, arg.info);
+ arg.info += 2;
+
+ int16_t vec[16];
+ uint32_t addr = arg.nest + basis.offset;
+ int shift = (basis.sx != 0) ? 1 : 0;
+
+ //LABEL9
+ //LABEL10
+ for (int i = 0; i < 16; i += 4)
+ {
+ vec[i] = *dram_u8(hle, addr);
+ vec[i + 1] = *dram_u8(hle, addr + (1 << shift));
+ vec[i + 2] = *dram_u8(hle, addr + (2 << shift));
+ vec[i + 3] = *dram_u8(hle, addr + (3 << shift));
+ addr += basis.lineskip;
+ }
+
+ //LABEL11
+ int16_t sum = 0x8;
+ for (int i = 0; i < 16; i++)
+ sum += vec[i];
+
+ sum >>= 4;
+
+ int16_t max = 0;
+ for (int i = 0; i < 16; i++)
+ {
+ vec[i] -= sum;
+ max = (abs(vec[i]) > max) ? abs(vec[i]) : max;
+ }
+
+ double dmax = 0.0;
+ if (max > 0)
+ dmax = (double)(basis.scale << 2) / (double)max;
+
+ for (int i = 0; i < 16; i++)
+ out[i] += (vec[i] < 0) ? (int16_t)((double)vec[i] * dmax - 0.5) : (int16_t)((double)vec[i] * dmax + 0.5);
+
+ block.nbase &= 8;
+ }
+
+ assert(block.nbase == 0);
+ //if(block.nbase != 0)
+ // LABEL6
+ }
+
+ return 1;
+}
+
+#define SATURATE8(x) ((unsigned int) x <= 255 ? x : (x < 0 ? 0: 255))
+static struct RGBA YCbCr_to_RGBA(int16_t Y, int16_t Cb, int16_t Cr, uint8_t alpha)
+{
+ struct RGBA color;
+
+ //Format S10.6
+ int r = (int)(((double)Y + 0.5) + (1.765625 * (double)(Cr - 128)));
+ int g = (int)(((double)Y + 0.5) - (0.34375 * (double)(Cr - 128)) - (0.71875 * (double)(Cb - 128)));
+ int b = (int)(((double)Y + 0.5) + (1.40625 * (double)(Cb - 128)));
+
+ color.r = SATURATE8(r);
+ color.g = SATURATE8(g);
+ color.b = SATURATE8(b);
+ color.a = alpha;
+
+ return color;
+}
+
+void store_rgba5551(struct hle_t* hle, struct RGBA color, uint32_t * addr)
+{
+ uint16_t pixel = ((color.b >> 3) << 11) | ((color.g >> 3) << 6) | ((color.r >> 3) << 1) | (color.a & 1);
+ dram_store_u16(hle, &pixel, *addr, 1);
+ *addr += 2;
+}
+
+void store_rgba8888(struct hle_t* hle, struct RGBA color, uint32_t * addr)
+{
+ uint32_t pixel = (color.b << 24) | (color.g << 16) | (color.r << 8) | color.a;
+ dram_store_u32(hle, &pixel, *addr, 1);
+ *addr += 4;
+}
+
+typedef void(*store_pixel_t)(struct hle_t* hle, struct RGBA color, uint32_t * addr);
+
+static void hvqm2_decode(struct hle_t* hle, int is32)
+{
+ //uint32_t uc_data_ptr = *dmem_u32(hle, TASK_UCODE_DATA);
+ uint32_t data_ptr = *dmem_u32(hle, TASK_DATA_PTR);
+
+ assert((*dmem_u32(hle, TASK_FLAGS) & 0x1) == 0);
+
+ /* Fill HVQM2Arg struct */
+ arg.info = *dram_u32(hle, data_ptr);
+ data_ptr += 4;
+ arg.buf = *dram_u32(hle, data_ptr);
+ data_ptr += 4;
+ arg.buf_width = *dram_u16(hle, data_ptr);
+ data_ptr += 2;
+ arg.chroma_step_h = *dram_u8(hle, data_ptr);
+ data_ptr++;
+ arg.chroma_step_v = *dram_u8(hle, data_ptr);
+ data_ptr++;
+ arg.hmcus = *dram_u16(hle, data_ptr);
+ data_ptr += 2;
+ arg.vmcus = *dram_u16(hle, data_ptr);
+ data_ptr += 2;
+ arg.alpha = *dram_u8(hle, data_ptr);
+ arg.nest = data_ptr + 1;
+
+ assert(arg.chroma_step_h == 2);
+ assert((arg.chroma_step_v == 1) || (arg.chroma_step_v == 2));
+ assert((*hle->sp_status & 0x80) == 0); //SP_STATUS_YIELD
+
+ int length, skip;
+ store_pixel_t store_pixel;
+
+ if (is32)
+ {
+ length = 0x20;
+ skip = arg.buf_width << 2;
+ arg.buf_width <<= 4;
+ store_pixel = &store_rgba8888;
+ }
+ else
+ {
+ length = 0x10;
+ skip = arg.buf_width << 1;
+ arg.buf_width <<= 3;
+ store_pixel = &store_rgba5551;
+ }
+
+ if (arg.chroma_step_v == 2)
+ arg.buf_width += arg.buf_width;
+
+ for (int i = arg.vmcus; i != 0; i--)
+ {
+ uint32_t out;
+ int j;
+
+ for (j = arg.hmcus, out = arg.buf; j != 0; j--, out += length)
+ {
+ uint8_t base = 0x80;
+ int16_t Cb[16], Cr[16], Y1[32], Y2[32];
+ int16_t* pCb = Cb;
+ int16_t* pCr = Cr;
+ int16_t* pY1 = Y1;
+ int16_t* pY2 = Y2;
+
+ if (arg.chroma_step_v == 2)
+ {
+ if (process_info(hle, &base, pY1) == 0)
+ continue;
+ if (process_info(hle, &base, pY2) == 0)
+ continue;
+
+ pY1 = &Y1[16];
+ pY2 = &Y2[16];
+ }
+
+ if (process_info(hle, &base, pY1) == 0)
+ continue;
+ if (process_info(hle, &base, pY2) == 0)
+ continue;
+ if (process_info(hle, &base, Cr) == 0)
+ continue;
+ if (process_info(hle, &base, Cb) == 0)
+ continue;
+
+ pY1 = Y1;
+ pY2 = Y2;
+
+ uint32_t out_buf = out;
+ for (int k = 0; k < 4; k++)
+ {
+ for (int m = 0; m < arg.chroma_step_v; m++)
+ {
+ uint32_t addr = out_buf;
+ for (int l = 0; l < 4; l++)
+ {
+ struct RGBA color = YCbCr_to_RGBA(pY1[l], pCb[l >> 1], pCr[l >> 1], arg.alpha);
+ store_pixel(hle, color, &addr);
+ }
+ for (int l = 0; l < 4; l++)
+ {
+ struct RGBA color = YCbCr_to_RGBA(pY2[l], pCb[(l + 4) >> 1], pCr[(l + 4) >> 1], arg.alpha);
+ store_pixel(hle, color, &addr);
+ }
+ out_buf += skip;
+ pY1 += 4;
+ pY2 += 4;
+ }
+ pCr += 4;
+ pCb += 4;
+ }
+ }
+ arg.buf += arg.buf_width;
+ }
+ rsp_break(hle, SP_STATUS_TASKDONE);
+}
+
+void hvqm2_decode_sp1_task(struct hle_t* hle)
+{
+ hvqm2_decode(hle, 0);
+}
+
+void hvqm2_decode_sp2_task(struct hle_t* hle)
+{
+ hvqm2_decode(hle, 1);
+}
\ No newline at end of file
diff --git a/src/jpeg.c b/src/jpeg.c
index 4365c05..ff424c4 100644
--- a/src/jpeg.c
+++ b/src/jpeg.c
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - jpeg.c *
- * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2012 Bobby Smiles *
* Copyright (C) 2009 Richard Goedeken *
* Copyright (C) 2002 Hacktarux *
@@ -141,6 +141,7 @@
void jpeg_decode_PS0(struct hle_t* hle)
{
jpeg_decode_std(hle, "PS0", RescaleYSubBlock, RescaleUVSubBlock, EmitYUVTileLine);
+ rsp_break(hle, SP_STATUS_TASKDONE);
}
/***************************************************************************
@@ -150,6 +151,7 @@
void jpeg_decode_PS(struct hle_t* hle)
{
jpeg_decode_std(hle, "PS", NULL, NULL, EmitRGBATileLine);
+ rsp_break(hle, SP_STATUS_TASKDONE);
}
/***************************************************************************
@@ -190,6 +192,7 @@
address += (2 * 6 * SUBBLOCK_SIZE);
}
+ rsp_break(hle, SP_STATUS_TASKDONE);
}
@@ -472,7 +475,7 @@
unsigned int i;
/* source and destination sublocks cannot overlap */
- assert(abs(dst - src) > SUBBLOCK_SIZE);
+ assert(labs(dst - src) > SUBBLOCK_SIZE);
for (i = 0; i < SUBBLOCK_SIZE; ++i)
dst[i] = src[table[i]];
diff --git a/src/memory.c b/src/memory.c
index ca06d6c..7d5066b 100644
--- a/src/memory.c
+++ b/src/memory.c
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - memory.c *
- * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* This program is free software; you can redistribute it and/or modify *
diff --git a/src/memory.h b/src/memory.h
index 8acc8c3..9c85104 100644
--- a/src/memory.h
+++ b/src/memory.h
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - memory.h *
- * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* This program is free software; you can redistribute it and/or modify *
diff --git a/src/mp3.c b/src/mp3.c
index 06c77a0..4e8ea14 100644
--- a/src/mp3.c
+++ b/src/mp3.c
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - mp3.c *
- * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* Copyright (C) 2009 Richard Goedeken *
* Copyright (C) 2002 Hacktarux *
diff --git a/src/musyx.c b/src/musyx.c
index 5a44917..d5a630a 100644
--- a/src/musyx.c
+++ b/src/musyx.c
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - musyx.c *
- * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2013 Bobby Smiles *
* *
* This program is free software; you can redistribute it and/or modify *
@@ -256,6 +256,8 @@
dram_store_u16(hle, (uint16_t *)musyx.cc0, state_ptr + STATE_CC0, SUBFRAME_SIZE);
dram_store_u16(hle, (uint16_t *)musyx.subframe_740_last4, state_ptr + STATE_740_LAST4_V1,
4);
+
+ rsp_break(hle, SP_STATUS_TASKDONE);
}
/**************************************************************************
@@ -333,6 +335,8 @@
sfd_ptr += SFD2_VOICES + MAX_VOICES * VOICE_SIZE;
}
+
+ rsp_break(hle, SP_STATUS_TASKDONE);
}
diff --git a/src/osal_dynamiclib.h b/src/osal_dynamiclib.h
new file mode 100644
index 0000000..dc5e5ba
--- /dev/null
+++ b/src/osal_dynamiclib.h
@@ -0,0 +1,34 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Mupen64plus-ui-console - osal_dynamiclib.h *
+ * Mupen64Plus homepage: https://mupen64plus.org/ *
+ * Copyright (C) 2009 Richard Goedeken *
+ * *
+ * 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. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#if !defined(OSAL_DYNAMICLIB_H)
+#define OSAL_DYNAMICLIB_H
+
+#include "m64p_types.h"
+
+m64p_error osal_dynlib_open(m64p_dynlib_handle *pLibHandle, const char *pccLibraryPath);
+
+void * osal_dynlib_getproc(m64p_dynlib_handle LibHandle, const char *pccProcedureName);
+
+m64p_error osal_dynlib_close(m64p_dynlib_handle LibHandle);
+
+#endif /* #define OSAL_DYNAMICLIB_H */
+
diff --git a/src/osal_dynamiclib_unix.c b/src/osal_dynamiclib_unix.c
new file mode 100644
index 0000000..9d937ed
--- /dev/null
+++ b/src/osal_dynamiclib_unix.c
@@ -0,0 +1,71 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Mupen64plus-ui-console - osal_dynamiclib_unix.c *
+ * Mupen64Plus homepage: https://mupen64plus.org/ *
+ * Copyright (C) 2009 Richard Goedeken *
+ * *
+ * 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
+#include
+#include
+#include
+
+#include "m64p_types.h"
+#include "hle_external.h"
+#include "osal_dynamiclib.h"
+
+m64p_error osal_dynlib_open(m64p_dynlib_handle *pLibHandle, const char *pccLibraryPath)
+{
+ if (pLibHandle == NULL || pccLibraryPath == NULL)
+ return M64ERR_INPUT_ASSERT;
+
+ *pLibHandle = dlopen(pccLibraryPath, RTLD_NOW);
+
+ if (*pLibHandle == NULL)
+ {
+ /* only print an error message if there is a directory separator (/) in the pathname */
+ /* this prevents us from throwing an error for the use case where Mupen64Plus is not installed */
+ if (strchr(pccLibraryPath, '/') != NULL)
+ HleErrorMessage(NULL, "dlopen('%s') failed: %s", pccLibraryPath, dlerror());
+ return M64ERR_INPUT_NOT_FOUND;
+ }
+
+ return M64ERR_SUCCESS;
+}
+
+void * osal_dynlib_getproc(m64p_dynlib_handle LibHandle, const char *pccProcedureName)
+{
+ if (pccProcedureName == NULL)
+ return NULL;
+
+ return dlsym(LibHandle, pccProcedureName);
+}
+
+m64p_error osal_dynlib_close(m64p_dynlib_handle LibHandle)
+{
+ int rval = dlclose(LibHandle);
+
+ if (rval != 0)
+ {
+ HleErrorMessage(NULL, "dlclose() failed: %s", dlerror());
+ return M64ERR_INTERNAL;
+ }
+
+ return M64ERR_SUCCESS;
+}
+
+
diff --git a/src/osal_dynamiclib_win32.c b/src/osal_dynamiclib_win32.c
new file mode 100644
index 0000000..fe77cf3
--- /dev/null
+++ b/src/osal_dynamiclib_win32.c
@@ -0,0 +1,75 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Mupen64plus-ui-console - osal_dynamiclib_win32.c *
+ * Mupen64Plus homepage: https://mupen64plus.org/ *
+ * Copyright (C) 2009 Richard Goedeken *
+ * *
+ * 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
+#include
+#include
+
+#include "m64p_types.h"
+#include "hle_external.h"
+#include "osal_dynamiclib.h"
+
+m64p_error osal_dynlib_open(m64p_dynlib_handle *pLibHandle, const char *pccLibraryPath)
+{
+ if (pLibHandle == NULL || pccLibraryPath == NULL)
+ return M64ERR_INPUT_ASSERT;
+
+ *pLibHandle = LoadLibrary(pccLibraryPath);
+
+ if (*pLibHandle == NULL)
+ {
+ char *pchErrMsg;
+ DWORD dwErr = GetLastError();
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &pchErrMsg, 0, NULL);
+ HleErrorMessage(NULL, "LoadLibrary('%s') error: %s", pccLibraryPath, pchErrMsg);
+ LocalFree(pchErrMsg);
+ return M64ERR_INPUT_NOT_FOUND;
+ }
+
+ return M64ERR_SUCCESS;
+}
+
+void * osal_dynlib_getproc(m64p_dynlib_handle LibHandle, const char *pccProcedureName)
+{
+ if (pccProcedureName == NULL)
+ return NULL;
+
+ return GetProcAddress(LibHandle, pccProcedureName);
+}
+
+m64p_error osal_dynlib_close(m64p_dynlib_handle LibHandle)
+{
+ int rval = FreeLibrary(LibHandle);
+
+ if (rval == 0)
+ {
+ char *pchErrMsg;
+ DWORD dwErr = GetLastError();
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &pchErrMsg, 0, NULL);
+ HleErrorMessage(NULL, "FreeLibrary() error: %s", pchErrMsg);
+ LocalFree(pchErrMsg);
+ return M64ERR_INTERNAL;
+ }
+
+ return M64ERR_SUCCESS;
+}
diff --git a/src/plugin.c b/src/plugin.c
index 64f8164..7f18b39 100644
--- a/src/plugin.c
+++ b/src/plugin.c
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - plugin.c *
- * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* Copyright (C) 2009 Richard Goedeken *
* Copyright (C) 2002 Hacktarux *
@@ -23,18 +23,41 @@
#include
#include
+#include
#include "common.h"
#include "hle.h"
#include "hle_internal.h"
+#include "hle_external.h"
#define M64P_PLUGIN_PROTOTYPES 1
#include "m64p_common.h"
+#include "m64p_config.h"
+#include "m64p_frontend.h"
#include "m64p_plugin.h"
#include "m64p_types.h"
-#define RSP_HLE_VERSION 0x020500
+#include "osal_dynamiclib.h"
+
+#define CONFIG_API_VERSION 0x020100
+#define CONFIG_PARAM_VERSION 1.00
+
+#define RSP_API_VERSION 0x20000
+#define RSP_HLE_VERSION 0x020509
#define RSP_PLUGIN_API_VERSION 0x020000
+
+#define RSP_HLE_CONFIG_SECTION "Rsp-HLE"
+#define RSP_HLE_CONFIG_VERSION "Version"
+#define RSP_HLE_CONFIG_FALLBACK "RspFallback"
+#define RSP_HLE_CONFIG_HLE_GFX "DisplayListToGraphicsPlugin"
+#define RSP_HLE_CONFIG_HLE_AUD "AudioListToAudioPlugin"
+
+
+#define VERSION_PRINTF_SPLIT(x) (((x) >> 16) & 0xffff), (((x) >> 8) & 0xff), ((x) & 0xff)
+
+/* Handy macro to avoid code bloat when loading symbols */
+#define GET_FUNC(type, field, name) \
+ ((field = (type)osal_dynlib_getproc(handle, name)) != NULL)
/* local variables */
static struct hle_t g_hle;
@@ -45,9 +68,125 @@
static void (*l_ShowCFB)(void) = NULL;
static void (*l_DebugCallback)(void *, int, const char *) = NULL;
static void *l_DebugCallContext = NULL;
+static m64p_dynlib_handle l_CoreHandle = NULL;
static int l_PluginInit = 0;
+static m64p_handle l_ConfigRspHle;
+static m64p_dynlib_handle l_RspFallback;
+static ptr_InitiateRSP l_InitiateRSP = NULL;
+static ptr_DoRspCycles l_DoRspCycles = NULL;
+static ptr_RomClosed l_RomClosed = NULL;
+static ptr_PluginShutdown l_PluginShutdown = NULL;
+
+/* definitions of pointers to Core functions */
+static ptr_ConfigOpenSection ConfigOpenSection = NULL;
+static ptr_ConfigDeleteSection ConfigDeleteSection = NULL;
+static ptr_ConfigSetParameter ConfigSetParameter = NULL;
+static ptr_ConfigGetParameter ConfigGetParameter = NULL;
+static ptr_ConfigSetDefaultInt ConfigSetDefaultInt = NULL;
+static ptr_ConfigSetDefaultFloat ConfigSetDefaultFloat = NULL;
+static ptr_ConfigSetDefaultBool ConfigSetDefaultBool = NULL;
+static ptr_ConfigSetDefaultString ConfigSetDefaultString = NULL;
+static ptr_ConfigGetParamInt ConfigGetParamInt = NULL;
+static ptr_ConfigGetParamFloat ConfigGetParamFloat = NULL;
+static ptr_ConfigGetParamBool ConfigGetParamBool = NULL;
+static ptr_ConfigGetParamString ConfigGetParamString = NULL;
+static ptr_CoreDoCommand CoreDoCommand = NULL;
+
/* local function */
+static void teardown_rsp_fallback()
+{
+ if (l_RspFallback != NULL) {
+ (*l_PluginShutdown)();
+ osal_dynlib_close(l_RspFallback);
+ }
+
+ l_RspFallback = NULL;
+ l_DoRspCycles = NULL;
+ l_InitiateRSP = NULL;
+ l_RomClosed = NULL;
+ l_PluginShutdown = NULL;
+}
+
+static void setup_rsp_fallback(const char* rsp_fallback_path)
+{
+ m64p_dynlib_handle handle = NULL;
+
+ /* reset rsp fallback */
+ teardown_rsp_fallback();
+
+ if (rsp_fallback_path == NULL || strlen(rsp_fallback_path) == 0) {
+ HleInfoMessage(NULL, "RSP Fallback disabled !");
+ return;
+ }
+
+ /* load plugin */
+ if (osal_dynlib_open(&handle, rsp_fallback_path) != M64ERR_SUCCESS) {
+ HleErrorMessage(NULL, "Can't load library: %s", rsp_fallback_path);
+ return;
+ }
+
+ /* call the GetVersion function for the plugin and check compatibility */
+ ptr_PluginGetVersion PluginGetVersion = (ptr_PluginGetVersion) osal_dynlib_getproc(handle, "PluginGetVersion");
+ if (PluginGetVersion == NULL)
+ {
+ HleErrorMessage(NULL, "library '%s' is not a Mupen64Plus library.", rsp_fallback_path);
+ goto close_handle;
+ }
+
+ m64p_plugin_type plugin_type = (m64p_plugin_type)0;
+ int plugin_version = 0;
+ const char *plugin_name = NULL;
+ int api_version = 0;
+
+ (*PluginGetVersion)(&plugin_type, &plugin_version, &api_version, &plugin_name, NULL);
+
+ if (plugin_type != M64PLUGIN_RSP) {
+ HleErrorMessage(NULL, "plugin %s is not an RSP plugin (%u)", plugin_name, plugin_type);
+ goto close_handle;
+ }
+
+ if ((api_version & 0xffff0000) != (RSP_API_VERSION & 0xffff0000)) {
+ HleErrorMessage(NULL, "plugin %s. Version mismatch: %u.%u. Expected >= %u.0",
+ plugin_name,
+ (uint16_t)(api_version >> 16),
+ (uint16_t)(api_version),
+ (uint16_t)(RSP_API_VERSION >> 16));
+ goto close_handle;
+ }
+
+ /* load functions */
+ ptr_PluginStartup PluginStartup;
+
+ if (!GET_FUNC(ptr_PluginStartup, PluginStartup, "PluginStartup") ||
+ !GET_FUNC(ptr_PluginShutdown, l_PluginShutdown, "PluginShutdown") ||
+ !GET_FUNC(ptr_DoRspCycles, l_DoRspCycles, "DoRspCycles") ||
+ !GET_FUNC(ptr_InitiateRSP, l_InitiateRSP, "InitiateRSP") ||
+ !GET_FUNC(ptr_RomClosed, l_RomClosed, "RomClosed"))
+ {
+ HleErrorMessage(NULL, "broken RSP plugin; function(s) not found.");
+ l_PluginShutdown = NULL;
+ l_DoRspCycles = NULL;
+ l_InitiateRSP = NULL;
+ l_RomClosed = NULL;
+ goto close_handle;
+ }
+
+ /* call the plugin's initialization function and make sure it starts okay */
+ if ((*PluginStartup)(l_CoreHandle, l_DebugCallContext, l_DebugCallback) != M64ERR_SUCCESS) {
+ HleErrorMessage(NULL, "Error: %s plugin library '%s' failed to start.", plugin_name, rsp_fallback_path);
+ goto close_handle;
+ }
+
+ /* OK we're done ! */
+ l_RspFallback = handle;
+ HleInfoMessage(NULL, "RSP Fallback '%s' loaded successfully !", rsp_fallback_path);
+ return;
+
+close_handle:
+ osal_dynlib_close(handle);
+}
+
static void DebugMessage(int level, const char *message, va_list args)
{
char msgbuf[1024];
@@ -69,6 +208,14 @@
va_end(args);
}
+void HleInfoMessage(void* UNUSED(user_defined), const char *message, ...)
+{
+ va_list args;
+ va_start(args, message);
+ DebugMessage(M64MSG_INFO, message, args);
+ va_end(args);
+}
+
void HleErrorMessage(void* UNUSED(user_defined), const char *message, ...)
{
va_list args;
@@ -126,10 +273,24 @@
}
+int HleForwardTask(void* user_defined)
+{
+ if (l_DoRspCycles == NULL)
+ return -1;
+
+ (*l_DoRspCycles)(-1);
+ return 0;
+}
+
+
/* DLL-exported functions */
-EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle UNUSED(CoreLibHandle), void *Context,
+EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Context,
void (*DebugCallback)(void *, int, const char *))
{
+ ptr_CoreGetAPIVersions CoreAPIVersionFunc;
+ int ConfigAPIVersion, DebugAPIVersion, VidextAPIVersion;
+ float fConfigParamsVersion = 0.0f;
+
if (l_PluginInit)
return M64ERR_ALREADY_INIT;
@@ -137,7 +298,87 @@
l_DebugCallback = DebugCallback;
l_DebugCallContext = Context;
- /* this plugin doesn't use any Core library functions (ex for Configuration), so no need to keep the CoreLibHandle */
+ /* attach and call the CoreGetAPIVersions function, check Config API version for compatibility */
+ CoreAPIVersionFunc = (ptr_CoreGetAPIVersions) osal_dynlib_getproc(CoreLibHandle, "CoreGetAPIVersions");
+ if (CoreAPIVersionFunc == NULL)
+ {
+ HleErrorMessage(NULL, "Core emulator broken; no CoreAPIVersionFunc() function found.");
+ return M64ERR_INCOMPATIBLE;
+ }
+
+ (*CoreAPIVersionFunc)(&ConfigAPIVersion, &DebugAPIVersion, &VidextAPIVersion, NULL);
+ if ((ConfigAPIVersion & 0xffff0000) != (CONFIG_API_VERSION & 0xffff0000))
+ {
+ HleErrorMessage(NULL, "Emulator core Config API (v%i.%i.%i) incompatible with plugin (v%i.%i.%i)",
+ VERSION_PRINTF_SPLIT(ConfigAPIVersion), VERSION_PRINTF_SPLIT(CONFIG_API_VERSION));
+ return M64ERR_INCOMPATIBLE;
+ }
+
+ /* Get the core config function pointers from the library handle */
+ ConfigOpenSection = (ptr_ConfigOpenSection) osal_dynlib_getproc(CoreLibHandle, "ConfigOpenSection");
+ ConfigDeleteSection = (ptr_ConfigDeleteSection) osal_dynlib_getproc(CoreLibHandle, "ConfigDeleteSection");
+ ConfigSetParameter = (ptr_ConfigSetParameter) osal_dynlib_getproc(CoreLibHandle, "ConfigSetParameter");
+ ConfigGetParameter = (ptr_ConfigGetParameter) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParameter");
+ ConfigSetDefaultInt = (ptr_ConfigSetDefaultInt) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultInt");
+ ConfigSetDefaultFloat = (ptr_ConfigSetDefaultFloat) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultFloat");
+ ConfigSetDefaultBool = (ptr_ConfigSetDefaultBool) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultBool");
+ ConfigSetDefaultString = (ptr_ConfigSetDefaultString) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultString");
+ ConfigGetParamInt = (ptr_ConfigGetParamInt) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamInt");
+ ConfigGetParamFloat = (ptr_ConfigGetParamFloat) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamFloat");
+ ConfigGetParamBool = (ptr_ConfigGetParamBool) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamBool");
+ ConfigGetParamString = (ptr_ConfigGetParamString) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamString");
+
+ if (!ConfigOpenSection || !ConfigDeleteSection || !ConfigSetParameter || !ConfigGetParameter ||
+ !ConfigSetDefaultInt || !ConfigSetDefaultFloat || !ConfigSetDefaultBool || !ConfigSetDefaultString ||
+ !ConfigGetParamInt || !ConfigGetParamFloat || !ConfigGetParamBool || !ConfigGetParamString)
+ return M64ERR_INCOMPATIBLE;
+
+ /* Get core DoCommand function */
+ CoreDoCommand = (ptr_CoreDoCommand) osal_dynlib_getproc(CoreLibHandle, "CoreDoCommand");
+ if (!CoreDoCommand) {
+ return M64ERR_INCOMPATIBLE;
+ }
+
+ /* get a configuration section handle */
+ if (ConfigOpenSection(RSP_HLE_CONFIG_SECTION, &l_ConfigRspHle) != M64ERR_SUCCESS)
+ {
+ HleErrorMessage(NULL, "Couldn't open config section '" RSP_HLE_CONFIG_SECTION "'");
+ return M64ERR_INPUT_NOT_FOUND;
+ }
+
+ /* check the section version number */
+ if (ConfigGetParameter(l_ConfigRspHle, RSP_HLE_CONFIG_VERSION, M64TYPE_FLOAT, &fConfigParamsVersion, sizeof(float)) != M64ERR_SUCCESS)
+ {
+ HleWarnMessage(NULL, "No version number in '" RSP_HLE_CONFIG_SECTION "' config section. Setting defaults.");
+ ConfigDeleteSection(RSP_HLE_CONFIG_SECTION);
+ ConfigOpenSection(RSP_HLE_CONFIG_SECTION, &l_ConfigRspHle);
+ }
+ else if (((int) fConfigParamsVersion) != ((int) CONFIG_PARAM_VERSION))
+ {
+ HleWarnMessage(NULL, "Incompatible version %.2f in '" RSP_HLE_CONFIG_SECTION "' config section: current is %.2f. Setting defaults.", fConfigParamsVersion, (float) CONFIG_PARAM_VERSION);
+ ConfigDeleteSection(RSP_HLE_CONFIG_SECTION);
+ ConfigOpenSection(RSP_HLE_CONFIG_SECTION, &l_ConfigRspHle);
+ }
+ else if ((CONFIG_PARAM_VERSION - fConfigParamsVersion) >= 0.0001f)
+ {
+ /* handle upgrades */
+ float fVersion = CONFIG_PARAM_VERSION;
+ ConfigSetParameter(l_ConfigRspHle, "Version", M64TYPE_FLOAT, &fVersion);
+ HleInfoMessage(NULL, "Updating parameter set version in '" RSP_HLE_CONFIG_SECTION "' config section to %.2f", fVersion);
+ }
+
+ /* set the default values for this plugin */
+ ConfigSetDefaultFloat(l_ConfigRspHle, RSP_HLE_CONFIG_VERSION, CONFIG_PARAM_VERSION,
+ "Mupen64Plus RSP HLE Plugin config parameter version number");
+ ConfigSetDefaultString(l_ConfigRspHle, RSP_HLE_CONFIG_FALLBACK, "",
+ "Path to a RSP plugin which will be used when encountering an unknown ucode."
+ "You can disable this by letting an empty string.");
+ ConfigSetDefaultBool(l_ConfigRspHle, RSP_HLE_CONFIG_HLE_GFX, 1,
+ "Send display lists to the graphics plugin");
+ ConfigSetDefaultBool(l_ConfigRspHle, RSP_HLE_CONFIG_HLE_AUD, 0,
+ "Send audio lists to the audio plugin");
+
+ l_CoreHandle = CoreLibHandle;
l_PluginInit = 1;
return M64ERR_SUCCESS;
@@ -151,6 +392,9 @@
/* reset some local variable */
l_DebugCallback = NULL;
l_DebugCallContext = NULL;
+ l_CoreHandle = NULL;
+
+ teardown_rsp_fallback();
l_PluginInit = 0;
return M64ERR_SUCCESS;
@@ -183,7 +427,7 @@
return Cycles;
}
-EXPORT void CALL InitiateRSP(RSP_INFO Rsp_Info, unsigned int* UNUSED(CycleCount))
+EXPORT void CALL InitiateRSP(RSP_INFO Rsp_Info, unsigned int* CycleCount)
{
hle_init(&g_hle,
Rsp_Info.RDRAM,
@@ -214,9 +458,24 @@
l_ProcessAlistList = Rsp_Info.ProcessAlistList;
l_ProcessRdpList = Rsp_Info.ProcessRdpList;
l_ShowCFB = Rsp_Info.ShowCFB;
+
+ setup_rsp_fallback(ConfigGetParamString(l_ConfigRspHle, RSP_HLE_CONFIG_FALLBACK));
+
+ g_hle.hle_gfx = ConfigGetParamBool(l_ConfigRspHle, RSP_HLE_CONFIG_HLE_GFX);
+ g_hle.hle_aud = ConfigGetParamBool(l_ConfigRspHle, RSP_HLE_CONFIG_HLE_AUD);
+
+ /* notify fallback plugin */
+ if (l_InitiateRSP) {
+ l_InitiateRSP(Rsp_Info, CycleCount);
+ }
}
EXPORT void CALL RomClosed(void)
{
- /* do nothing */
-}
+ g_hle.cached_ucodes.count = 0;
+
+ /* notify fallback plugin */
+ if (l_RomClosed) {
+ l_RomClosed();
+ }
+}
diff --git a/src/re2.c b/src/re2.c
new file mode 100644
index 0000000..8ae1788
--- /dev/null
+++ b/src/re2.c
@@ -0,0 +1,224 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Mupen64plus-rsp-hle - re2.c *
+ * Mupen64Plus homepage: https://mupen64plus.org/ *
+ * Copyright (C) 2016 Gilles Siberlin *
+ * *
+ * 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
+#include
+#include
+
+#include "hle_external.h"
+#include "hle_internal.h"
+#include "memory.h"
+
+#define SATURATE8(x) ((unsigned int) x <= 255 ? x : (x < 0 ? 0: 255))
+
+/**************************************************************************
+ * Resident evil 2 ucodes
+ **************************************************************************/
+void resize_bilinear_task(struct hle_t* hle)
+{
+ int data_ptr = *dmem_u32(hle, TASK_UCODE_DATA);
+
+ int src_addr = *dram_u32(hle, data_ptr);
+ int dst_addr = *dram_u32(hle, data_ptr + 4);
+ int dst_width = *dram_u32(hle, data_ptr + 8);
+ int dst_height = *dram_u32(hle, data_ptr + 12);
+ int x_ratio = *dram_u32(hle, data_ptr + 16);
+ int y_ratio = *dram_u32(hle, data_ptr + 20);
+#if 0 /* unused, but keep it for documentation purpose */
+ int dst_stride = *dram_u32(hle, data_ptr + 24);
+#endif
+ int src_offset = *dram_u32(hle, data_ptr + 36);
+
+ int a, b, c ,d, index, y_index, xr, yr, blue, green, red, addr, i, j;
+ long long x, y, x_diff, y_diff, one_min_x_diff, one_min_y_diff;
+ unsigned short pixel;
+
+ src_addr += (src_offset >> 16) * (320 * 3);
+ x = y = 0;
+
+ for(i = 0; i < dst_height; i++)
+ {
+ yr = (int)(y >> 16);
+ y_diff = y - (yr << 16);
+ one_min_y_diff = 65536 - y_diff;
+ y_index = yr * 320;
+ x = 0;
+
+ for(j = 0; j < dst_width; j++)
+ {
+ xr = (int)(x >> 16);
+ x_diff = x - (xr << 16);
+ one_min_x_diff = 65536 - x_diff;
+ index = y_index + xr;
+ addr = src_addr + (index * 3);
+
+ dram_load_u8(hle, (uint8_t*)&a, addr, 3);
+ dram_load_u8(hle, (uint8_t*)&b, (addr + 3), 3);
+ dram_load_u8(hle, (uint8_t*)&c, (addr + (320 * 3)), 3);
+ dram_load_u8(hle, (uint8_t*)&d, (addr + (320 * 3) + 3), 3);
+
+ blue = (int)(((a&0xff)*one_min_x_diff*one_min_y_diff + (b&0xff)*x_diff*one_min_y_diff +
+ (c&0xff)*y_diff*one_min_x_diff + (d&0xff)*x_diff*y_diff) >> 32);
+
+ green = (int)((((a>>8)&0xff)*one_min_x_diff*one_min_y_diff + ((b>>8)&0xff)*x_diff*one_min_y_diff +
+ ((c>>8)&0xff)*y_diff*one_min_x_diff + ((d>>8)&0xff)*x_diff*y_diff) >> 32);
+
+ red = (int)((((a>>16)&0xff)*one_min_x_diff*one_min_y_diff + ((b>>16)&0xff)*x_diff*one_min_y_diff +
+ ((c>>16)&0xff)*y_diff*one_min_x_diff + ((d>>16)&0xff)*x_diff*y_diff) >> 32);
+
+ blue = (blue >> 3) & 0x001f;
+ green = (green >> 3) & 0x001f;
+ red = (red >> 3) & 0x001f;
+ pixel = (red << 11) | (green << 6) | (blue << 1) | 1;
+
+ dram_store_u16(hle, &pixel, dst_addr, 1);
+ dst_addr += 2;
+
+ x += x_ratio;
+ }
+ y += y_ratio;
+ }
+
+ rsp_break(hle, SP_STATUS_TASKDONE);
+}
+
+static uint32_t YCbCr_to_RGBA(uint8_t Y, uint8_t Cb, uint8_t Cr)
+{
+ int r, g, b;
+
+ r = (int)(((double)Y * 0.582199097) + (0.701004028 * (double)(Cr - 128)));
+ g = (int)(((double)Y * 0.582199097) - (0.357070923 * (double)(Cr - 128)) - (0.172073364 * (double)(Cb - 128)));
+ b = (int)(((double)Y * 0.582199097) + (0.886001587 * (double)(Cb - 128)));
+
+ r = SATURATE8(r);
+ g = SATURATE8(g);
+ b = SATURATE8(b);
+
+ return (r << 24) | (g << 16) | (b << 8) | 0;
+}
+
+void decode_video_frame_task(struct hle_t* hle)
+{
+ int data_ptr = *dmem_u32(hle, TASK_UCODE_DATA);
+
+ int pLuminance = *dram_u32(hle, data_ptr);
+ int pCb = *dram_u32(hle, data_ptr + 4);
+ int pCr = *dram_u32(hle, data_ptr + 8);
+ int pDestination = *dram_u32(hle, data_ptr + 12);
+ int nMovieWidth = *dram_u32(hle, data_ptr + 16);
+ int nMovieHeight = *dram_u32(hle, data_ptr + 20);
+#if 0 /* unused, but keep it for documentation purpose */
+ int nRowsPerDMEM = *dram_u32(hle, data_ptr + 24);
+ int nDMEMPerFrame = *dram_u32(hle, data_ptr + 28);
+ int nLengthSkipCount = *dram_u32(hle, data_ptr + 32);
+#endif
+ int nScreenDMAIncrement = *dram_u32(hle, data_ptr + 36);
+
+ int i, j;
+ uint8_t Y, Cb, Cr;
+ uint32_t pixel;
+ int pY_1st_row, pY_2nd_row, pDest_1st_row, pDest_2nd_row;
+
+ for (i = 0; i < nMovieHeight; i += 2)
+ {
+ pY_1st_row = pLuminance;
+ pY_2nd_row = pLuminance + nMovieWidth;
+ pDest_1st_row = pDestination;
+ pDest_2nd_row = pDestination + (nScreenDMAIncrement >> 1);
+
+ for (j = 0; j < nMovieWidth; j += 2)
+ {
+ dram_load_u8(hle, (uint8_t*)&Cb, pCb++, 1);
+ dram_load_u8(hle, (uint8_t*)&Cr, pCr++, 1);
+
+ /*1st row*/
+ dram_load_u8(hle, (uint8_t*)&Y, pY_1st_row++, 1);
+ pixel = YCbCr_to_RGBA(Y, Cb, Cr);
+ dram_store_u32(hle, &pixel, pDest_1st_row, 1);
+ pDest_1st_row += 4;
+
+ dram_load_u8(hle, (uint8_t*)&Y, pY_1st_row++, 1);
+ pixel = YCbCr_to_RGBA(Y, Cb, Cr);
+ dram_store_u32(hle, &pixel, pDest_1st_row, 1);
+ pDest_1st_row += 4;
+
+ /*2nd row*/
+ dram_load_u8(hle, (uint8_t*)&Y, pY_2nd_row++, 1);
+ pixel = YCbCr_to_RGBA(Y, Cb, Cr);
+ dram_store_u32(hle, &pixel, pDest_2nd_row, 1);
+ pDest_2nd_row += 4;
+
+ dram_load_u8(hle, (uint8_t*)&Y, pY_2nd_row++, 1);
+ pixel = YCbCr_to_RGBA(Y, Cb, Cr);
+ dram_store_u32(hle, &pixel, pDest_2nd_row, 1);
+ pDest_2nd_row += 4;
+ }
+
+ pLuminance += (nMovieWidth << 1);
+ pDestination += nScreenDMAIncrement;
+ }
+
+ rsp_break(hle, SP_STATUS_TASKDONE);
+}
+
+void fill_video_double_buffer_task(struct hle_t* hle)
+{
+ int data_ptr = *dmem_u32(hle, TASK_UCODE_DATA);
+
+ int pSrc = *dram_u32(hle, data_ptr);
+ int pDest = *dram_u32(hle, data_ptr + 0x4);
+ int width = *dram_u32(hle, data_ptr + 0x8) >> 1;
+ int height = *dram_u32(hle, data_ptr + 0x10) << 1;
+ int stride = *dram_u32(hle, data_ptr + 0x1c) >> 1;
+
+ assert((*dram_u32(hle, data_ptr + 0x28) >> 16) == 0x8000);
+
+#if 0 /* unused, but keep it for documentation purpose */
+ int arg3 = *dram_u32(hle, data_ptr + 0xc);
+ int arg5 = *dram_u32(hle, data_ptr + 0x14);
+ int arg6 = *dram_u32(hle, data_ptr + 0x18);
+#endif
+
+ int i, j;
+ int r, g, b;
+ uint32_t pixel, pixel1, pixel2;
+
+ for(i = 0; i < height; i++)
+ {
+ for(j = 0; j < width; j=j+4)
+ {
+ pixel1 = *dram_u32(hle, pSrc+j);
+ pixel2 = *dram_u32(hle, pDest+j);
+
+ r = (((pixel1 >> 24) & 0xff) + ((pixel2 >> 24) & 0xff)) >> 1;
+ g = (((pixel1 >> 16) & 0xff) + ((pixel2 >> 16) & 0xff)) >> 1;
+ b = (((pixel1 >> 8) & 0xff) + ((pixel2 >> 8) & 0xff)) >> 1;
+
+ pixel = (r << 24) | (g << 16) | (b << 8) | 0;
+
+ dram_store_u32(hle, &pixel, pDest+j, 1);
+ }
+ pSrc += stride;
+ pDest += stride;
+ }
+
+ rsp_break(hle, SP_STATUS_TASKDONE);
+}
diff --git a/src/ucodes.h b/src/ucodes.h
index 1a12bf9..8d12bfb 100644
--- a/src/ucodes.h
+++ b/src/ucodes.h
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - ucodes.h *
- * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* This program is free software; you can redistribute it and/or modify *
@@ -24,8 +24,23 @@
#include
+#define CACHED_UCODES_MAX_SIZE 16
+
struct hle_t;
+typedef void(*ucode_func_t)(struct hle_t* hle);
+
+struct ucode_info_t {
+ uint32_t uc_start;
+ uint32_t uc_dstart;
+ uint16_t uc_dsize;
+ ucode_func_t uc_pfunc;
+};
+
+struct cached_ucodes_t {
+ struct ucode_info_t infos[CACHED_UCODES_MAX_SIZE];
+ int count;
+};
/* cic_x105 ucode */
void cicx105_ucode(struct hle_t* hle);
@@ -126,7 +141,8 @@
void alist_process_nead_mm (struct hle_t* hle);
void alist_process_nead_mmb (struct hle_t* hle);
void alist_process_nead_ac (struct hle_t* hle);
-
+void alist_process_nead_mats(struct hle_t* hle);
+void alist_process_nead_efz (struct hle_t* hle);
/* mp3 ucode */
void mp3_task(struct hle_t* hle, unsigned int index, uint32_t address);
@@ -142,5 +158,14 @@
void jpeg_decode_PS(struct hle_t* hle);
void jpeg_decode_OB(struct hle_t* hle);
+/* Resident evil 2 ucode */
+void resize_bilinear_task(struct hle_t* hle);
+void decode_video_frame_task(struct hle_t* hle);
+void fill_video_double_buffer_task(struct hle_t* hle);
+
+/* hvqm2 ucode */
+void hvqm2_decode_sp1_task(struct hle_t* hle);
+void hvqm2_decode_sp2_task(struct hle_t* hle);
+
#endif