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/debian/changelog b/debian/changelog index 93b745b..7d33e92 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,6 @@ -mupen64plus-rsp-hle (2.5-6) UNRELEASED; urgency=medium - +mupen64plus-rsp-hle (2.5.9+git20210210.1.88766c6-1) UNRELEASED; urgency=medium + + [ Sven Eckelmann ] * debian/control: - Upgraded to policy 4.5.1, no changes required - Allow build without (fake)root @@ -12,7 +13,10 @@ * debian/rules: - Drop default flag --as-needed from linker flags - -- Sven Eckelmann Fri, 04 Oct 2019 13:23:00 +0200 + [ Debian Janitor ] + * New upstream snapshot. + + -- Sven Eckelmann Tue, 08 Jun 2021 07:33:32 -0000 mupen64plus-rsp-hle (2.5-5) unstable; urgency=medium 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