[N64] Update RSP-HLE plugin to latest version. (#1213)
* [N64] Update RSP-HLE plugin to latest version. * Updated RSP-HLE dll binary
This commit is contained in:
parent
19908bdd03
commit
637bb90b54
|
@ -5,7 +5,8 @@ Mupen64Plus-rsp-hle is licensed under the GNU General Public License version 2.
|
|||
|
||||
The authors of Mupen64Plus-rsp-hle are:
|
||||
* Richard Goedeken (Richard42)
|
||||
* Bobby Smiles
|
||||
* Bobby Smiles (bsmiles32)
|
||||
* Sven Eckelmann (ecsv)
|
||||
* John Chadwick (NMN)
|
||||
* James Hood (Ebenblues)
|
||||
* Scott Gorman (okaygo)
|
||||
|
@ -29,7 +30,7 @@ Mupen64Plus is based on GPL-licensed source code from Mupen64 v0.5, originally w
|
|||
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.
|
||||
|
||||
|
|
|
@ -1,6 +1,17 @@
|
|||
RSP High-Level Emulation plugin for Mupen64Plus
|
||||
-----------------------------------------------
|
||||
|
||||
Mupen64Plus-rsp-hle v2.5 - April 26, 2015
|
||||
-------------------------------------------------
|
||||
- Game-specific fixes: Bottom of the 9th, IndianaJones, BattleForNaboo, Conkers Bad Fur Day
|
||||
- Support for MusyX microcodes
|
||||
- Improve audio microcode identification
|
||||
- Huge quantity of code cleanups and refactoring to improve organization
|
||||
- Add support for additional audio commands: #16, POLEF, RESAMPLE_ZOH
|
||||
- Multiple bugfixes in audio processing code
|
||||
- Move global variables into a struct so code is re-entrant
|
||||
- bugfix: microcode detection could sometimes fail after reset
|
||||
|
||||
Mupen64Plus-rsp-hle v2.0 - July 4, 2013
|
||||
-------------------------------------------------
|
||||
- Add support for MusyX ucode detection
|
||||
|
|
|
@ -0,0 +1,194 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{2EC7CEE3-C7A7-4F2E-B2C8-4DF6AFEC3E9A}</ProjectGuid>
|
||||
<RootNamespace>mupen64plusrsphle</RootNamespace>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v120_xp</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
|
||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
|
||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
|
||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
|
||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>
|
||||
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
|
||||
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
|
||||
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
|
||||
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
|
||||
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
|
||||
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
|
||||
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
|
||||
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\..\..\mupen64plus-core\src\api;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;inline=__inline;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>true</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||
<CompileAs>Default</CompileAs>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\..\..\mupen64plus-core\src\api;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;inline=__inline;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<CompileAs>Default</CompileAs>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\..\..\mupen64plus-core\src\api;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;inline=__inline;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<CompileAs>Default</CompileAs>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\..\..\mupen64plus-core\src\api;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;inline=__inline;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<CompileAs>Default</CompileAs>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\alist.c" />
|
||||
<ClCompile Include="..\..\src\alist_audio.c" />
|
||||
<ClCompile Include="..\..\src\alist_naudio.c" />
|
||||
<ClCompile Include="..\..\src\alist_nead.c" />
|
||||
<ClCompile Include="..\..\src\audio.c" />
|
||||
<ClCompile Include="..\..\src\cicx105.c" />
|
||||
<ClCompile Include="..\..\src\hle.c" />
|
||||
<ClCompile Include="..\..\src\jpeg.c" />
|
||||
<ClCompile Include="..\..\src\memory.c" />
|
||||
<ClCompile Include="..\..\src\mp3.c" />
|
||||
<ClCompile Include="..\..\src\musyx.c" />
|
||||
<ClCompile Include="..\..\src\osal_dynamiclib_win32.c" />
|
||||
<ClCompile Include="..\..\src\plugin.c" />
|
||||
<ClCompile Include="..\..\src\re2.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\src\alist.h" />
|
||||
<ClInclude Include="..\..\src\arithmetics.h" />
|
||||
<ClInclude Include="..\..\src\audio.h" />
|
||||
<ClInclude Include="..\..\src\common.h" />
|
||||
<ClInclude Include="..\..\src\hle.h" />
|
||||
<ClInclude Include="..\..\src\hle_external.h" />
|
||||
<ClInclude Include="..\..\src\hle_internal.h" />
|
||||
<ClInclude Include="..\..\src\memory.h" />
|
||||
<ClInclude Include="..\..\src\osal_dynamiclib.h" />
|
||||
<ClInclude Include="..\..\src\ucodes.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -187,22 +187,33 @@
|
|||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\alist.c" />
|
||||
<ClCompile Include="..\..\src\alist_audio.c" />
|
||||
<ClCompile Include="..\..\src\alist_naudio.c" />
|
||||
<ClCompile Include="..\..\src\alist_nead.c" />
|
||||
<ClCompile Include="..\..\src\audio.c" />
|
||||
<ClCompile Include="..\..\src\cicx105.c" />
|
||||
<ClCompile Include="..\..\src\hle.c" />
|
||||
<ClCompile Include="..\..\src\jpeg.c" />
|
||||
<ClCompile Include="..\..\src\main.c" />
|
||||
<ClCompile Include="..\..\src\ucode1.cpp" />
|
||||
<ClCompile Include="..\..\src\ucode2.cpp" />
|
||||
<ClCompile Include="..\..\src\ucode3.cpp" />
|
||||
<ClCompile Include="..\..\src\ucode3mp3.cpp" />
|
||||
<ClCompile Include="..\..\src\memory.c" />
|
||||
<ClCompile Include="..\..\src\mp3.c" />
|
||||
<ClCompile Include="..\..\src\musyx.c" />
|
||||
<ClCompile Include="..\..\src\osal_dynamiclib_win32.c" />
|
||||
<ClCompile Include="..\..\src\plugin.c" />
|
||||
<ClCompile Include="..\..\src\re2.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\src\alist.h" />
|
||||
<ClInclude Include="..\..\src\alist_internal.h" />
|
||||
<ClInclude Include="..\..\src\cicx105.h" />
|
||||
<ClInclude Include="..\..\src\arithmetics.h" />
|
||||
<ClInclude Include="..\..\src\audio.h" />
|
||||
<ClInclude Include="..\..\src\common.h" />
|
||||
<ClInclude Include="..\..\src\hle.h" />
|
||||
<ClInclude Include="..\..\src\jpeg.h" />
|
||||
<ClInclude Include="..\..\src\hle_external.h" />
|
||||
<ClInclude Include="..\..\src\hle_internal.h" />
|
||||
<ClInclude Include="..\..\src\memory.h" />
|
||||
<ClInclude Include="..\..\src\osal_dynamiclib.h" />
|
||||
<ClInclude Include="..\..\src\ucodes.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -182,32 +182,56 @@
|
|||
RelativePath="..\..\src\alist.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\alist_audio.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\alist_naudio.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\alist_nead.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\audio.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\cicx105.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\hle.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\jpeg.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\main.c"
|
||||
RelativePath="..\..\src\memory.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\ucode1.cpp"
|
||||
RelativePath="..\..\src\mp3.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\ucode2.cpp"
|
||||
RelativePath="..\..\src\musyx.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\ucode3.cpp"
|
||||
RelativePath="..\..\src\osal_dynamiclib_win32.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\ucode3mp3.cpp"
|
||||
RelativePath="..\..\src\plugin.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\re2.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
|
@ -221,11 +245,15 @@
|
|||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\alist_internal.h"
|
||||
RelativePath="..\..\src\arithmetics.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\cicx105.h"
|
||||
RelativePath="..\..\src\audio.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\common.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
|
@ -233,7 +261,23 @@
|
|||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\jpeg.h"
|
||||
RelativePath="..\..\src\hle_external.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\hle_internal.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\memory.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\osal_dynamiclib.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\ucodes.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
|
|
|
@ -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 @@ ifeq ("$(UNAME)","OpenBSD")
|
|||
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 @@ ifeq ("$(patsubst MINGW%,MINGW,$(UNAME))","MINGW")
|
|||
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
|
||||
|
@ -111,15 +110,20 @@ ifneq ("$(filter arm%,$(HOST_CPU))","")
|
|||
$(warning Architecture "$(HOST_CPU)" not officially supported.')
|
||||
endif
|
||||
endif
|
||||
ifneq ("$(filter mips,$(HOST_CPU))","")
|
||||
CPU := MIPS
|
||||
ARCH_DETECTED := 32BITS
|
||||
PIC ?= 1
|
||||
$(warning Architecture "$(HOST_CPU)" not officially supported.')
|
||||
endif
|
||||
ifeq ("$(CPU)","NONE")
|
||||
$(error CPU type "$(HOST_CPU)" not supported. Please file bug report at 'http://code.google.com/p/mupen64plus/issues')
|
||||
$(error CPU type "$(HOST_CPU)" not supported. Please file bug report at 'https://github.com/mupen64plus/mupen64plus-core/issues')
|
||||
endif
|
||||
|
||||
# base CFLAGS, LDLIBS, and LDFLAGS
|
||||
OPTFLAGS ?= -O3 -flto
|
||||
WARNFLAGS ?= -Wall
|
||||
CFLAGS += $(OPTFLAGS) $(WARNFLAGS) -ffast-math -fno-strict-aliasing -fvisibility=hidden -I../../src
|
||||
CXXFLAGS += -fvisibility-inlines-hidden
|
||||
LDFLAGS += $(SHARED)
|
||||
|
||||
# Since we are building a shared library, we must compile with -fPIC on some architectures
|
||||
|
@ -147,11 +151,10 @@ endif
|
|||
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)
|
||||
|
@ -189,26 +192,24 @@ endif
|
|||
ifneq ($(findstring $(MAKEFLAGS),s),s)
|
||||
ifndef V
|
||||
Q_CC = @echo ' CC '$@;
|
||||
Q_CXX = @echo ' CXX '$@;
|
||||
Q_LD = @echo ' LD '$@;
|
||||
endif
|
||||
endif
|
||||
|
||||
# set base program pointers and flags
|
||||
CC = $(CROSS_COMPILE)gcc
|
||||
CXX = $(CROSS_COMPILE)g++
|
||||
RM ?= rm -f
|
||||
INSTALL ?= install
|
||||
MKDIR ?= mkdir -p
|
||||
COMPILE.c = $(Q_CC)$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
|
||||
COMPILE.cc = $(Q_CXX)$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
|
||||
LINK.o = $(Q_LD)$(CXX) $(CXXFLAGS) $(LDFLAGS) $(TARGET_ARCH)
|
||||
LINK.o = $(Q_LD)$(CC) $(CFLAGS) $(LDFLAGS) $(TARGET_ARCH)
|
||||
|
||||
# set special flags for given Makefile parameters
|
||||
ifeq ($(DEBUG),1)
|
||||
CFLAGS += -g
|
||||
INSTALL_STRIP_FLAG ?=
|
||||
else
|
||||
CFLAGS += -DNDEBUG
|
||||
ifneq ($(OS),OSX)
|
||||
INSTALL_STRIP_FLAG ?= -s
|
||||
endif
|
||||
|
@ -225,23 +226,41 @@ ifeq ($(PLUGINDIR),)
|
|||
PLUGINDIR := $(LIBDIR)/mupen64plus
|
||||
endif
|
||||
|
||||
# enable/disable task dumping support
|
||||
ifeq ($(DUMP), 1)
|
||||
CFLAGS += -DENABLE_TASK_DUMP
|
||||
endif
|
||||
|
||||
|
||||
SRCDIR = ../../src
|
||||
OBJDIR = _obj$(POSTFIX)
|
||||
|
||||
# list of source files to compile
|
||||
SOURCE = \
|
||||
$(SRCDIR)/main.c \
|
||||
$(SRCDIR)/alist.c \
|
||||
$(SRCDIR)/alist_audio.c \
|
||||
$(SRCDIR)/alist_naudio.c \
|
||||
$(SRCDIR)/alist_nead.c \
|
||||
$(SRCDIR)/audio.c \
|
||||
$(SRCDIR)/cicx105.c \
|
||||
$(SRCDIR)/hle.c \
|
||||
$(SRCDIR)/jpeg.c \
|
||||
$(SRCDIR)/ucode3.cpp \
|
||||
$(SRCDIR)/ucode2.cpp \
|
||||
$(SRCDIR)/ucode1.cpp \
|
||||
$(SRCDIR)/ucode3mp3.cpp
|
||||
$(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)))
|
||||
OBJECTS += $(patsubst $(SRCDIR)/%.cpp, $(OBJDIR)/%.o, $(filter %.cpp, $(SOURCE)))
|
||||
OBJDIRS = $(dir $(OBJECTS))
|
||||
$(shell $(MKDIR) $(OBJDIRS))
|
||||
|
||||
|
@ -263,6 +282,7 @@ targets:
|
|||
@echo " WARNFLAGS=flag == compiler warning levels (default: -Wall)"
|
||||
@echo " PIC=(1|0) == Force enable/disable of position independent code"
|
||||
@echo " POSTFIX=name == String added to the name of the the build (default: '')"
|
||||
@echo " DUMP=(1|0) == Enable/Disable unknown task dumping (default: 0)"
|
||||
@echo " Install Options:"
|
||||
@echo " PREFIX=path == install/uninstall prefix (default: /usr/local)"
|
||||
@echo " LIBDIR=path == library prefix (default: PREFIX/lib)"
|
||||
|
@ -287,18 +307,13 @@ clean:
|
|||
rebuild: clean all
|
||||
|
||||
# build dependency files
|
||||
CFLAGS += -MD
|
||||
CFLAGS += -MD -MP
|
||||
-include $(OBJECTS:.o=.d)
|
||||
|
||||
CXXFLAGS += $(CFLAGS)
|
||||
|
||||
# standard build rules
|
||||
$(OBJDIR)/%.o: $(SRCDIR)/%.c
|
||||
$(COMPILE.c) -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
|
||||
$(COMPILE.cc) -o $@ $<
|
||||
|
||||
$(TARGET): $(OBJECTS)
|
||||
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,7 +1,7 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - alist.h *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2002 Hacktarux *
|
||||
* Mupen64Plus homepage: https://mupen64plus.org/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* *
|
||||
* 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 *
|
||||
|
@ -19,15 +19,152 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef ALIST_H
|
||||
#define ALIST_H
|
||||
#ifndef ALIST_INTERNAL_H
|
||||
#define ALIST_INTERNAL_H
|
||||
|
||||
void alist_process_ABI1();
|
||||
void alist_process_ABI2();
|
||||
void alist_process_ABI3();
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// FIXME: to remove when isZeldaABI/isMKABI workaround is gone
|
||||
void init_ucode2();
|
||||
struct hle_t;
|
||||
|
||||
typedef void (*acmd_callback_t)(struct hle_t* hle, uint32_t w1, uint32_t w2);
|
||||
|
||||
void alist_process(struct hle_t* hle, const acmd_callback_t abi[], unsigned int abi_size);
|
||||
uint32_t alist_get_address(struct hle_t* hle, uint32_t so, const uint32_t *segments, size_t n);
|
||||
void alist_set_address(struct hle_t* hle, uint32_t so, uint32_t *segments, size_t n);
|
||||
void alist_clear(struct hle_t* hle, uint16_t dmem, uint16_t count);
|
||||
void alist_load(struct hle_t* hle, uint16_t dmem, uint32_t address, uint16_t count);
|
||||
void alist_save(struct hle_t* hle, uint16_t dmem, uint32_t address, uint16_t count);
|
||||
void alist_move(struct hle_t* hle, uint16_t dmemo, uint16_t dmemi, uint16_t count);
|
||||
void alist_copy_every_other_sample(struct hle_t* hle, uint16_t dmemo, uint16_t dmemi, uint16_t count);
|
||||
void alist_repeat64(struct hle_t* hle, uint16_t dmemo, uint16_t dmemi, uint8_t count);
|
||||
void alist_copy_blocks(struct hle_t* hle, uint16_t dmemo, uint16_t dmemi, uint16_t block_size, uint8_t count);
|
||||
void alist_interleave(struct hle_t* hle, uint16_t dmemo, uint16_t left, uint16_t right, uint16_t count);
|
||||
|
||||
void alist_envmix_exp(
|
||||
struct hle_t* hle,
|
||||
bool init,
|
||||
bool aux,
|
||||
uint16_t dmem_dl, uint16_t dmem_dr,
|
||||
uint16_t dmem_wl, uint16_t dmem_wr,
|
||||
uint16_t dmemi, uint16_t count,
|
||||
int16_t dry, int16_t wet,
|
||||
const int16_t *vol,
|
||||
const int16_t *target,
|
||||
const int32_t *rate,
|
||||
uint32_t address);
|
||||
|
||||
void alist_envmix_ge(
|
||||
struct hle_t* hle,
|
||||
bool init,
|
||||
bool aux,
|
||||
uint16_t dmem_dl, uint16_t dmem_dr,
|
||||
uint16_t dmem_wl, uint16_t dmem_wr,
|
||||
uint16_t dmemi, uint16_t count,
|
||||
int16_t dry, int16_t wet,
|
||||
const int16_t *vol,
|
||||
const int16_t *target,
|
||||
const int32_t *rate,
|
||||
uint32_t address);
|
||||
|
||||
void alist_envmix_lin(
|
||||
struct hle_t* hle,
|
||||
bool init,
|
||||
uint16_t dmem_dl, uint16_t dmem_dr,
|
||||
uint16_t dmem_wl, uint16_t dmem_wr,
|
||||
uint16_t dmemi, uint16_t count,
|
||||
int16_t dry, int16_t wet,
|
||||
const int16_t *vol,
|
||||
const int16_t *target,
|
||||
const int32_t *rate,
|
||||
uint32_t address);
|
||||
|
||||
void alist_envmix_nead(
|
||||
struct hle_t* hle,
|
||||
bool swap_wet_LR,
|
||||
uint16_t dmem_dl,
|
||||
uint16_t dmem_dr,
|
||||
uint16_t dmem_wl,
|
||||
uint16_t dmem_wr,
|
||||
uint16_t dmemi,
|
||||
unsigned count,
|
||||
uint16_t *env_values,
|
||||
uint16_t *env_steps,
|
||||
const int16_t *xors);
|
||||
|
||||
void alist_mix(struct hle_t* hle, uint16_t dmemo, uint16_t dmemi, uint16_t count, int16_t gain);
|
||||
void alist_multQ44(struct hle_t* hle, uint16_t dmem, uint16_t count, int8_t gain);
|
||||
void alist_add(struct hle_t* hle, uint16_t dmemo, uint16_t dmemi, uint16_t count);
|
||||
|
||||
void alist_adpcm(
|
||||
struct hle_t* hle,
|
||||
bool init,
|
||||
bool loop,
|
||||
bool two_bit_per_sample,
|
||||
uint16_t dmemo,
|
||||
uint16_t dmemi,
|
||||
uint16_t count,
|
||||
const int16_t* codebook,
|
||||
uint32_t loop_address,
|
||||
uint32_t last_frame_address);
|
||||
|
||||
void alist_resample(
|
||||
struct hle_t* hle,
|
||||
bool init,
|
||||
bool flag2,
|
||||
uint16_t dmemo, uint16_t dmemi, uint16_t count,
|
||||
uint32_t pitch, uint32_t address);
|
||||
|
||||
void alist_resample_zoh(
|
||||
struct hle_t* hle,
|
||||
uint16_t dmemo,
|
||||
uint16_t dmemi,
|
||||
uint16_t count,
|
||||
uint32_t pitch,
|
||||
uint32_t pitch_accu);
|
||||
|
||||
void alist_filter(
|
||||
struct hle_t* hle,
|
||||
uint16_t dmem,
|
||||
uint16_t count,
|
||||
uint32_t address,
|
||||
const uint32_t* lut_address);
|
||||
|
||||
void alist_polef(
|
||||
struct hle_t* hle,
|
||||
bool init,
|
||||
uint16_t dmemo,
|
||||
uint16_t dmemi,
|
||||
uint16_t count,
|
||||
uint16_t gain,
|
||||
int16_t* table,
|
||||
uint32_t address);
|
||||
|
||||
void alist_iirf(
|
||||
struct hle_t* hle,
|
||||
bool init,
|
||||
uint16_t dmemo,
|
||||
uint16_t dmemi,
|
||||
uint16_t count,
|
||||
int16_t* table,
|
||||
uint32_t address);
|
||||
|
||||
/*
|
||||
* Audio flags
|
||||
*/
|
||||
|
||||
#define A_INIT 0x01
|
||||
#define A_CONTINUE 0x00
|
||||
#define A_LOOP 0x02
|
||||
#define A_OUT 0x02
|
||||
#define A_LEFT 0x02
|
||||
#define A_RIGHT 0x00
|
||||
#define A_VOL 0x04
|
||||
#define A_RATE 0x00
|
||||
#define A_AUX 0x08
|
||||
#define A_NOAUX 0x00
|
||||
#define A_MAIN 0x00
|
||||
#define A_MIX 0x10
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -0,0 +1,310 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - alist_audio.c *
|
||||
* Mupen64Plus homepage: https://mupen64plus.org/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* Copyright (C) 2009 Richard Goedeken *
|
||||
* Copyright (C) 2002 Hacktarux *
|
||||
* *
|
||||
* 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 <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "alist.h"
|
||||
#include "common.h"
|
||||
#include "hle_internal.h"
|
||||
#include "memory.h"
|
||||
#include "ucodes.h"
|
||||
|
||||
enum { DMEM_BASE = 0x5c0 };
|
||||
|
||||
/* helper functions */
|
||||
static uint32_t get_address(struct hle_t* hle, uint32_t so)
|
||||
{
|
||||
return alist_get_address(hle, so, hle->alist_audio.segments, N_SEGMENTS);
|
||||
}
|
||||
|
||||
static void set_address(struct hle_t* hle, uint32_t so)
|
||||
{
|
||||
alist_set_address(hle, so, hle->alist_audio.segments, N_SEGMENTS);
|
||||
}
|
||||
|
||||
static void clear_segments(struct hle_t* hle)
|
||||
{
|
||||
memset(hle->alist_audio.segments, 0, N_SEGMENTS*sizeof(hle->alist_audio.segments[0]));
|
||||
}
|
||||
|
||||
/* audio commands definition */
|
||||
static void SPNOOP(struct hle_t* UNUSED(hle), uint32_t UNUSED(w1), uint32_t UNUSED(w2))
|
||||
{
|
||||
}
|
||||
|
||||
static void CLEARBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t dmem = w1 + DMEM_BASE;
|
||||
uint16_t count = w2 & 0xfff;
|
||||
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
alist_clear(hle, dmem, align(count, 16));
|
||||
}
|
||||
|
||||
static void ENVMIXER(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t flags = (w1 >> 16);
|
||||
uint32_t address = get_address(hle, w2);
|
||||
|
||||
alist_envmix_exp(
|
||||
hle,
|
||||
flags & A_INIT,
|
||||
flags & A_AUX,
|
||||
hle->alist_audio.out, hle->alist_audio.dry_right,
|
||||
hle->alist_audio.wet_left, hle->alist_audio.wet_right,
|
||||
hle->alist_audio.in, hle->alist_audio.count,
|
||||
hle->alist_audio.dry, hle->alist_audio.wet,
|
||||
hle->alist_audio.vol,
|
||||
hle->alist_audio.target,
|
||||
hle->alist_audio.rate,
|
||||
address);
|
||||
}
|
||||
|
||||
static void ENVMIXER_GE(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t flags = (w1 >> 16);
|
||||
uint32_t address = get_address(hle, w2);
|
||||
|
||||
alist_envmix_ge(
|
||||
hle,
|
||||
flags & A_INIT,
|
||||
flags & A_AUX,
|
||||
hle->alist_audio.out, hle->alist_audio.dry_right,
|
||||
hle->alist_audio.wet_left, hle->alist_audio.wet_right,
|
||||
hle->alist_audio.in, hle->alist_audio.count,
|
||||
hle->alist_audio.dry, hle->alist_audio.wet,
|
||||
hle->alist_audio.vol,
|
||||
hle->alist_audio.target,
|
||||
hle->alist_audio.rate,
|
||||
address);
|
||||
}
|
||||
|
||||
static void RESAMPLE(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t flags = (w1 >> 16);
|
||||
uint16_t pitch = w1;
|
||||
uint32_t address = get_address(hle, w2);
|
||||
|
||||
alist_resample(
|
||||
hle,
|
||||
flags & A_INIT,
|
||||
flags & 0x2,
|
||||
hle->alist_audio.out,
|
||||
hle->alist_audio.in,
|
||||
align(hle->alist_audio.count, 16),
|
||||
pitch << 1,
|
||||
address);
|
||||
}
|
||||
|
||||
static void SETVOL(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t flags = (w1 >> 16);
|
||||
|
||||
if (flags & A_AUX) {
|
||||
hle->alist_audio.dry = w1;
|
||||
hle->alist_audio.wet = w2;
|
||||
}
|
||||
else {
|
||||
unsigned lr = (flags & A_LEFT) ? 0 : 1;
|
||||
|
||||
if (flags & A_VOL)
|
||||
hle->alist_audio.vol[lr] = w1;
|
||||
else {
|
||||
hle->alist_audio.target[lr] = w1;
|
||||
hle->alist_audio.rate[lr] = w2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SETLOOP(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
|
||||
{
|
||||
hle->alist_audio.loop = get_address(hle, w2);
|
||||
}
|
||||
|
||||
static void ADPCM(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t flags = (w1 >> 16);
|
||||
uint32_t address = get_address(hle, w2);
|
||||
|
||||
alist_adpcm(
|
||||
hle,
|
||||
flags & A_INIT,
|
||||
flags & A_LOOP,
|
||||
false, /* unsupported in this ucode */
|
||||
hle->alist_audio.out,
|
||||
hle->alist_audio.in,
|
||||
align(hle->alist_audio.count, 32),
|
||||
hle->alist_audio.table,
|
||||
hle->alist_audio.loop,
|
||||
address);
|
||||
}
|
||||
|
||||
static void LOADBUFF(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
|
||||
{
|
||||
uint32_t address = get_address(hle, w2);
|
||||
|
||||
if (hle->alist_audio.count == 0)
|
||||
return;
|
||||
|
||||
alist_load(hle, hle->alist_audio.in, address, hle->alist_audio.count);
|
||||
}
|
||||
|
||||
static void SAVEBUFF(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
|
||||
{
|
||||
uint32_t address = get_address(hle, w2);
|
||||
|
||||
if (hle->alist_audio.count == 0)
|
||||
return;
|
||||
|
||||
alist_save(hle, hle->alist_audio.out, address, hle->alist_audio.count);
|
||||
}
|
||||
|
||||
static void SETBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t flags = (w1 >> 16);
|
||||
|
||||
if (flags & A_AUX) {
|
||||
hle->alist_audio.dry_right = w1 + DMEM_BASE;
|
||||
hle->alist_audio.wet_left = (w2 >> 16) + DMEM_BASE;
|
||||
hle->alist_audio.wet_right = w2 + DMEM_BASE;
|
||||
} else {
|
||||
hle->alist_audio.in = w1 + DMEM_BASE;
|
||||
hle->alist_audio.out = (w2 >> 16) + DMEM_BASE;
|
||||
hle->alist_audio.count = w2;
|
||||
}
|
||||
}
|
||||
|
||||
static void DMEMMOVE(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t dmemi = w1 + DMEM_BASE;
|
||||
uint16_t dmemo = (w2 >> 16) + DMEM_BASE;
|
||||
uint16_t count = w2;
|
||||
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
alist_move(hle, dmemo, dmemi, align(count, 16));
|
||||
}
|
||||
|
||||
static void LOADADPCM(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t count = w1;
|
||||
uint32_t address = get_address(hle, w2);
|
||||
|
||||
dram_load_u16(hle, (uint16_t*)hle->alist_audio.table, address, align(count, 8) >> 1);
|
||||
}
|
||||
|
||||
static void INTERLEAVE(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
|
||||
{
|
||||
uint16_t left = (w2 >> 16) + DMEM_BASE;
|
||||
uint16_t right = w2 + DMEM_BASE;
|
||||
|
||||
if (hle->alist_audio.count == 0)
|
||||
return;
|
||||
|
||||
alist_interleave(hle, hle->alist_audio.out, left, right, align(hle->alist_audio.count, 16));
|
||||
}
|
||||
|
||||
static void MIXER(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
int16_t gain = w1;
|
||||
uint16_t dmemi = (w2 >> 16) + DMEM_BASE;
|
||||
uint16_t dmemo = w2 + DMEM_BASE;
|
||||
|
||||
if (hle->alist_audio.count == 0)
|
||||
return;
|
||||
|
||||
alist_mix(hle, dmemo, dmemi, align(hle->alist_audio.count, 32), gain);
|
||||
}
|
||||
|
||||
static void SEGMENT(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
|
||||
{
|
||||
set_address(hle, w2);
|
||||
}
|
||||
|
||||
static void POLEF(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t flags = (w1 >> 16);
|
||||
uint16_t gain = w1;
|
||||
uint32_t address = get_address(hle, w2);
|
||||
|
||||
if (hle->alist_audio.count == 0)
|
||||
return;
|
||||
|
||||
alist_polef(
|
||||
hle,
|
||||
flags & A_INIT,
|
||||
hle->alist_audio.out,
|
||||
hle->alist_audio.in,
|
||||
align(hle->alist_audio.count, 16),
|
||||
gain,
|
||||
hle->alist_audio.table,
|
||||
address);
|
||||
}
|
||||
|
||||
/* global functions */
|
||||
void alist_process_audio(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x10] = {
|
||||
SPNOOP, ADPCM , CLEARBUFF, ENVMIXER,
|
||||
LOADBUFF, RESAMPLE, SAVEBUFF, SEGMENT,
|
||||
SETBUFF, SETVOL, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, POLEF, SETLOOP
|
||||
};
|
||||
|
||||
clear_segments(hle);
|
||||
alist_process(hle, ABI, 0x10);
|
||||
rsp_break(hle, SP_STATUS_TASKDONE);
|
||||
}
|
||||
|
||||
void alist_process_audio_ge(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x10] = {
|
||||
SPNOOP, ADPCM , CLEARBUFF, ENVMIXER_GE,
|
||||
LOADBUFF, RESAMPLE, SAVEBUFF, SEGMENT,
|
||||
SETBUFF, SETVOL, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, POLEF, SETLOOP
|
||||
};
|
||||
|
||||
clear_segments(hle);
|
||||
alist_process(hle, ABI, 0x10);
|
||||
rsp_break(hle, SP_STATUS_TASKDONE);
|
||||
}
|
||||
|
||||
void alist_process_audio_bc(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x10] = {
|
||||
SPNOOP, ADPCM , CLEARBUFF, ENVMIXER_GE,
|
||||
LOADBUFF, RESAMPLE, SAVEBUFF, SEGMENT,
|
||||
SETBUFF, SETVOL, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, POLEF, SETLOOP
|
||||
};
|
||||
|
||||
clear_segments(hle);
|
||||
alist_process(hle, ABI, 0x10);
|
||||
rsp_break(hle, SP_STATUS_TASKDONE);
|
||||
}
|
|
@ -0,0 +1,333 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - alist_naudio.c *
|
||||
* Mupen64Plus homepage: https://mupen64plus.org/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* Copyright (C) 2009 Richard Goedeken *
|
||||
* Copyright (C) 2002 Hacktarux *
|
||||
* *
|
||||
* 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 <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "alist.h"
|
||||
#include "common.h"
|
||||
#include "hle_external.h"
|
||||
#include "hle_internal.h"
|
||||
#include "memory.h"
|
||||
#include "ucodes.h"
|
||||
|
||||
enum { NAUDIO_COUNT = 0x170 }; /* ie 184 samples */
|
||||
enum {
|
||||
NAUDIO_MAIN = 0x4f0,
|
||||
NAUDIO_MAIN2 = 0x660,
|
||||
NAUDIO_DRY_LEFT = 0x9d0,
|
||||
NAUDIO_DRY_RIGHT = 0xb40,
|
||||
NAUDIO_WET_LEFT = 0xcb0,
|
||||
NAUDIO_WET_RIGHT = 0xe20
|
||||
};
|
||||
|
||||
|
||||
/* audio commands definition */
|
||||
static void UNKNOWN(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t acmd = (w1 >> 24);
|
||||
|
||||
HleWarnMessage(hle->user_defined,
|
||||
"Unknown audio command %d: %08x %08x",
|
||||
acmd, w1, w2);
|
||||
}
|
||||
|
||||
|
||||
static void SPNOOP(struct hle_t* UNUSED(hle), uint32_t UNUSED(w1), uint32_t UNUSED(w2))
|
||||
{
|
||||
}
|
||||
|
||||
static void NAUDIO_0000(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
/* ??? */
|
||||
UNKNOWN(hle, w1, w2);
|
||||
}
|
||||
|
||||
static void NAUDIO_02B0(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
|
||||
{
|
||||
/* emulate code at 0x12b0 (inside SETVOL), because PC always execute in IMEM */
|
||||
hle->alist_naudio.rate[1] &= ~0xffff;
|
||||
hle->alist_naudio.rate[1] |= (w2 & 0xffff);
|
||||
}
|
||||
|
||||
static void NAUDIO_14(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t flags = (w1 >> 16);
|
||||
uint16_t gain = w1;
|
||||
uint8_t select_main = (w2 >> 24);
|
||||
uint32_t address = (w2 & 0xffffff);
|
||||
|
||||
uint16_t dmem = (select_main == 0) ? NAUDIO_MAIN : NAUDIO_MAIN2;
|
||||
|
||||
if (hle->alist_naudio.table[0] == 0 && hle->alist_naudio.table[1] == 0) {
|
||||
alist_polef(
|
||||
hle,
|
||||
flags & A_INIT,
|
||||
dmem,
|
||||
dmem,
|
||||
NAUDIO_COUNT,
|
||||
gain,
|
||||
hle->alist_naudio.table,
|
||||
address);
|
||||
}
|
||||
else
|
||||
{
|
||||
alist_iirf(
|
||||
hle,
|
||||
flags & A_INIT,
|
||||
dmem,
|
||||
dmem,
|
||||
NAUDIO_COUNT,
|
||||
hle->alist_naudio.table,
|
||||
address);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void SETVOL(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t flags = (w1 >> 16);
|
||||
|
||||
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 { /* A_RIGHT */
|
||||
hle->alist_naudio.target[1] = w1;
|
||||
hle->alist_naudio.rate[1] = w2;
|
||||
}
|
||||
}
|
||||
else { /* A_RATE */
|
||||
hle->alist_naudio.target[0] = w1;
|
||||
hle->alist_naudio.rate[0] = w2;
|
||||
}
|
||||
}
|
||||
|
||||
static void ENVMIXER(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t flags = (w1 >> 16);
|
||||
uint32_t address = (w2 & 0xffffff);
|
||||
|
||||
hle->alist_naudio.vol[1] = w1;
|
||||
|
||||
alist_envmix_lin(
|
||||
hle,
|
||||
flags & A_INIT,
|
||||
NAUDIO_DRY_LEFT,
|
||||
NAUDIO_DRY_RIGHT,
|
||||
NAUDIO_WET_LEFT,
|
||||
NAUDIO_WET_RIGHT,
|
||||
NAUDIO_MAIN,
|
||||
NAUDIO_COUNT,
|
||||
hle->alist_naudio.dry,
|
||||
hle->alist_naudio.wet,
|
||||
hle->alist_naudio.vol,
|
||||
hle->alist_naudio.target,
|
||||
hle->alist_naudio.rate,
|
||||
address);
|
||||
}
|
||||
|
||||
static void CLEARBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t dmem = w1 + NAUDIO_MAIN;
|
||||
uint16_t count = w2 & 0xfff;
|
||||
|
||||
alist_clear(hle, dmem, count);
|
||||
}
|
||||
|
||||
static void MIXER(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
int16_t gain = w1;
|
||||
uint16_t dmemi = (w2 >> 16) + NAUDIO_MAIN;
|
||||
uint16_t dmemo = w2 + NAUDIO_MAIN;
|
||||
|
||||
alist_mix(hle, dmemo, dmemi, NAUDIO_COUNT, gain);
|
||||
}
|
||||
|
||||
static void LOADBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t count = (w1 >> 12) & 0xfff;
|
||||
uint16_t dmem = (w1 & 0xfff) + NAUDIO_MAIN;
|
||||
uint32_t address = (w2 & 0xffffff);
|
||||
|
||||
alist_load(hle, dmem, address, count);
|
||||
}
|
||||
|
||||
static void SAVEBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t count = (w1 >> 12) & 0xfff;
|
||||
uint16_t dmem = (w1 & 0xfff) + NAUDIO_MAIN;
|
||||
uint32_t address = (w2 & 0xffffff);
|
||||
|
||||
alist_save(hle, dmem, address, count);
|
||||
}
|
||||
|
||||
static void LOADADPCM(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t count = w1;
|
||||
uint32_t address = (w2 & 0xffffff);
|
||||
|
||||
dram_load_u16(hle, (uint16_t*)hle->alist_naudio.table, address, count >> 1);
|
||||
}
|
||||
|
||||
static void DMEMMOVE(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t dmemi = w1 + NAUDIO_MAIN;
|
||||
uint16_t dmemo = (w2 >> 16) + NAUDIO_MAIN;
|
||||
uint16_t count = w2;
|
||||
|
||||
alist_move(hle, dmemo, dmemi, (count + 3) & ~3);
|
||||
}
|
||||
|
||||
static void SETLOOP(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
|
||||
{
|
||||
hle->alist_naudio.loop = (w2 & 0xffffff);
|
||||
}
|
||||
|
||||
static void ADPCM(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint32_t address = (w1 & 0xffffff);
|
||||
uint8_t flags = (w2 >> 28);
|
||||
uint16_t count = (w2 >> 16) & 0xfff;
|
||||
uint16_t dmemi = ((w2 >> 12) & 0xf) + NAUDIO_MAIN;
|
||||
uint16_t dmemo = (w2 & 0xfff) + NAUDIO_MAIN;
|
||||
|
||||
alist_adpcm(
|
||||
hle,
|
||||
flags & A_INIT,
|
||||
flags & A_LOOP,
|
||||
false, /* unsuported by this ucode */
|
||||
dmemo,
|
||||
dmemi,
|
||||
(count + 0x1f) & ~0x1f,
|
||||
hle->alist_naudio.table,
|
||||
hle->alist_naudio.loop,
|
||||
address);
|
||||
}
|
||||
|
||||
static void RESAMPLE(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint32_t address = (w1 & 0xffffff);
|
||||
uint8_t flags = (w2 >> 30);
|
||||
uint16_t pitch = (w2 >> 14);
|
||||
uint16_t dmemi = ((w2 >> 2) & 0xfff) + NAUDIO_MAIN;
|
||||
uint16_t dmemo = (w2 & 0x3) ? NAUDIO_MAIN2 : NAUDIO_MAIN;
|
||||
|
||||
alist_resample(
|
||||
hle,
|
||||
flags & A_INIT,
|
||||
false, /* TODO: check which ABI supports it */
|
||||
dmemo,
|
||||
dmemi,
|
||||
NAUDIO_COUNT,
|
||||
pitch << 1,
|
||||
address);
|
||||
}
|
||||
|
||||
static void INTERLEAVE(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t UNUSED(w2))
|
||||
{
|
||||
alist_interleave(hle, NAUDIO_MAIN, NAUDIO_DRY_LEFT, NAUDIO_DRY_RIGHT, NAUDIO_COUNT);
|
||||
}
|
||||
|
||||
static void MP3ADDY(struct hle_t* UNUSED(hle), uint32_t UNUSED(w1), uint32_t UNUSED(w2))
|
||||
{
|
||||
}
|
||||
|
||||
static void MP3(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
unsigned index = (w1 & 0x1e);
|
||||
uint32_t address = (w2 & 0xffffff);
|
||||
|
||||
mp3_task(hle, index, address);
|
||||
}
|
||||
|
||||
/* global functions */
|
||||
void alist_process_naudio(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x10] = {
|
||||
SPNOOP, ADPCM, CLEARBUFF, ENVMIXER,
|
||||
LOADBUFF, RESAMPLE, SAVEBUFF, NAUDIO_0000,
|
||||
NAUDIO_0000, SETVOL, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, NAUDIO_02B0, SETLOOP
|
||||
};
|
||||
|
||||
alist_process(hle, ABI, 0x10);
|
||||
rsp_break(hle, SP_STATUS_TASKDONE);
|
||||
}
|
||||
|
||||
void alist_process_naudio_bk(struct hle_t* hle)
|
||||
{
|
||||
/* TODO: see what differs from alist_process_naudio */
|
||||
static const acmd_callback_t ABI[0x10] = {
|
||||
SPNOOP, ADPCM, CLEARBUFF, ENVMIXER,
|
||||
LOADBUFF, RESAMPLE, SAVEBUFF, NAUDIO_0000,
|
||||
NAUDIO_0000, SETVOL, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, NAUDIO_02B0, SETLOOP
|
||||
};
|
||||
|
||||
alist_process(hle, ABI, 0x10);
|
||||
rsp_break(hle, SP_STATUS_TASKDONE);
|
||||
}
|
||||
|
||||
void alist_process_naudio_dk(struct hle_t* hle)
|
||||
{
|
||||
/* TODO: see what differs from alist_process_naudio */
|
||||
static const acmd_callback_t ABI[0x10] = {
|
||||
SPNOOP, ADPCM, CLEARBUFF, ENVMIXER,
|
||||
LOADBUFF, RESAMPLE, SAVEBUFF, MIXER,
|
||||
MIXER, SETVOL, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, NAUDIO_02B0, SETLOOP
|
||||
};
|
||||
|
||||
alist_process(hle, ABI, 0x10);
|
||||
rsp_break(hle, SP_STATUS_TASKDONE);
|
||||
}
|
||||
|
||||
void alist_process_naudio_mp3(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x10] = {
|
||||
UNKNOWN, ADPCM, CLEARBUFF, ENVMIXER,
|
||||
LOADBUFF, RESAMPLE, SAVEBUFF, MP3,
|
||||
MP3ADDY, SETVOL, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, NAUDIO_14, SETLOOP
|
||||
};
|
||||
|
||||
alist_process(hle, ABI, 0x10);
|
||||
rsp_break(hle, SP_STATUS_TASKDONE);
|
||||
}
|
||||
|
||||
void alist_process_naudio_cbfd(struct hle_t* hle)
|
||||
{
|
||||
/* TODO: see what differs from alist_process_naudio_mp3 */
|
||||
static const acmd_callback_t ABI[0x10] = {
|
||||
UNKNOWN, ADPCM, CLEARBUFF, ENVMIXER,
|
||||
LOADBUFF, RESAMPLE, SAVEBUFF, MP3,
|
||||
MP3ADDY, SETVOL, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, NAUDIO_14, SETLOOP
|
||||
};
|
||||
|
||||
alist_process(hle, ABI, 0x10);
|
||||
rsp_break(hle, SP_STATUS_TASKDONE);
|
||||
}
|
|
@ -0,0 +1,556 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - alist_nead.c *
|
||||
* Mupen64Plus homepage: https://mupen64plus.org/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* Copyright (C) 2009 Richard Goedeken *
|
||||
* Copyright (C) 2002 Hacktarux *
|
||||
* *
|
||||
* 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 <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "alist.h"
|
||||
#include "common.h"
|
||||
#include "hle_external.h"
|
||||
#include "hle_internal.h"
|
||||
#include "memory.h"
|
||||
#include "ucodes.h"
|
||||
|
||||
/* remove windows define to 0x06 */
|
||||
#ifdef DUPLICATE
|
||||
#undef DUPLICATE
|
||||
#endif
|
||||
|
||||
/* audio commands definition */
|
||||
static void UNKNOWN(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t acmd = (w1 >> 24);
|
||||
|
||||
HleWarnMessage(hle->user_defined,
|
||||
"Unknown audio command %d: %08x %08x",
|
||||
acmd, w1, w2);
|
||||
}
|
||||
|
||||
|
||||
static void SPNOOP(struct hle_t* UNUSED(hle), uint32_t UNUSED(w1), uint32_t UNUSED(w2))
|
||||
{
|
||||
}
|
||||
|
||||
static void LOADADPCM(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t count = w1;
|
||||
uint32_t address = (w2 & 0xffffff);
|
||||
|
||||
dram_load_u16(hle, (uint16_t*)hle->alist_nead.table, address, count >> 1);
|
||||
}
|
||||
|
||||
static void SETLOOP(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
|
||||
{
|
||||
hle->alist_nead.loop = w2 & 0xffffff;
|
||||
}
|
||||
|
||||
static void SETBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
hle->alist_nead.in = w1;
|
||||
hle->alist_nead.out = (w2 >> 16);
|
||||
hle->alist_nead.count = w2;
|
||||
}
|
||||
|
||||
static void ADPCM(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t flags = (w1 >> 16);
|
||||
uint32_t address = (w2 & 0xffffff);
|
||||
|
||||
alist_adpcm(
|
||||
hle,
|
||||
flags & 0x1,
|
||||
flags & 0x2,
|
||||
flags & 0x4,
|
||||
hle->alist_nead.out,
|
||||
hle->alist_nead.in,
|
||||
(hle->alist_nead.count + 0x1f) & ~0x1f,
|
||||
hle->alist_nead.table,
|
||||
hle->alist_nead.loop,
|
||||
address);
|
||||
}
|
||||
|
||||
static void CLEARBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t dmem = w1;
|
||||
uint16_t count = w2 & 0xfff;
|
||||
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
alist_clear(hle, dmem, count);
|
||||
}
|
||||
|
||||
static void LOADBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t count = (w1 >> 12) & 0xfff;
|
||||
uint16_t dmem = (w1 & 0xfff);
|
||||
uint32_t address = (w2 & 0xffffff);
|
||||
|
||||
alist_load(hle, dmem, address, count);
|
||||
}
|
||||
|
||||
static void SAVEBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t count = (w1 >> 12) & 0xfff;
|
||||
uint16_t dmem = (w1 & 0xfff);
|
||||
uint32_t address = (w2 & 0xffffff);
|
||||
|
||||
alist_save(hle, dmem, address, count);
|
||||
}
|
||||
|
||||
static void MIXER(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t count = (w1 >> 12) & 0xff0;
|
||||
int16_t gain = w1;
|
||||
uint16_t dmemi = (w2 >> 16);
|
||||
uint16_t dmemo = w2;
|
||||
|
||||
alist_mix(hle, dmemo, dmemi, count, gain);
|
||||
}
|
||||
|
||||
|
||||
static void RESAMPLE(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t flags = (w1 >> 16);
|
||||
uint16_t pitch = w1;
|
||||
uint32_t address = (w2 & 0xffffff);
|
||||
|
||||
alist_resample(
|
||||
hle,
|
||||
flags & 0x1,
|
||||
false, /* TODO: check which ABI supports it */
|
||||
hle->alist_nead.out,
|
||||
hle->alist_nead.in,
|
||||
(hle->alist_nead.count + 0xf) & ~0xf,
|
||||
pitch << 1,
|
||||
address);
|
||||
}
|
||||
|
||||
static void RESAMPLE_ZOH(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t pitch = w1;
|
||||
uint16_t pitch_accu = w2;
|
||||
|
||||
alist_resample_zoh(
|
||||
hle,
|
||||
hle->alist_nead.out,
|
||||
hle->alist_nead.in,
|
||||
hle->alist_nead.count,
|
||||
pitch << 1,
|
||||
pitch_accu);
|
||||
}
|
||||
|
||||
static void DMEMMOVE(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t dmemi = w1;
|
||||
uint16_t dmemo = (w2 >> 16);
|
||||
uint16_t count = w2;
|
||||
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
alist_move(hle, dmemo, dmemi, (count + 3) & ~3);
|
||||
}
|
||||
|
||||
static void ENVSETUP1_MK(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
hle->alist_nead.env_values[2] = (w1 >> 8) & 0xff00;
|
||||
hle->alist_nead.env_steps[2] = 0;
|
||||
hle->alist_nead.env_steps[0] = (w2 >> 16);
|
||||
hle->alist_nead.env_steps[1] = w2;
|
||||
}
|
||||
|
||||
static void ENVSETUP1(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
hle->alist_nead.env_values[2] = (w1 >> 8) & 0xff00;
|
||||
hle->alist_nead.env_steps[2] = w1;
|
||||
hle->alist_nead.env_steps[0] = (w2 >> 16);
|
||||
hle->alist_nead.env_steps[1] = w2;
|
||||
}
|
||||
|
||||
static void ENVSETUP2(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
|
||||
{
|
||||
hle->alist_nead.env_values[0] = (w2 >> 16);
|
||||
hle->alist_nead.env_values[1] = w2;
|
||||
}
|
||||
|
||||
static void ENVMIXER_MK(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
int16_t xors[4];
|
||||
|
||||
uint16_t dmemi = (w1 >> 12) & 0xff0;
|
||||
uint8_t count = (w1 >> 8) & 0xff;
|
||||
uint16_t dmem_dl = (w2 >> 20) & 0xff0;
|
||||
uint16_t dmem_dr = (w2 >> 12) & 0xff0;
|
||||
uint16_t dmem_wl = (w2 >> 4) & 0xff0;
|
||||
uint16_t dmem_wr = (w2 << 4) & 0xff0;
|
||||
|
||||
xors[2] = 0; /* unsupported by this ucode */
|
||||
xors[3] = 0; /* unsupported by this ucode */
|
||||
xors[0] = 0 - (int16_t)((w1 & 0x2) >> 1);
|
||||
xors[1] = 0 - (int16_t)((w1 & 0x1) );
|
||||
|
||||
alist_envmix_nead(
|
||||
hle,
|
||||
false, /* unsupported by this ucode */
|
||||
dmem_dl, dmem_dr,
|
||||
dmem_wl, dmem_wr,
|
||||
dmemi, count,
|
||||
hle->alist_nead.env_values,
|
||||
hle->alist_nead.env_steps,
|
||||
xors);
|
||||
}
|
||||
|
||||
static void ENVMIXER(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
int16_t xors[4];
|
||||
|
||||
uint16_t dmemi = (w1 >> 12) & 0xff0;
|
||||
uint8_t count = (w1 >> 8) & 0xff;
|
||||
bool swap_wet_LR = (w1 >> 4) & 0x1;
|
||||
uint16_t dmem_dl = (w2 >> 20) & 0xff0;
|
||||
uint16_t dmem_dr = (w2 >> 12) & 0xff0;
|
||||
uint16_t dmem_wl = (w2 >> 4) & 0xff0;
|
||||
uint16_t dmem_wr = (w2 << 4) & 0xff0;
|
||||
|
||||
xors[2] = 0 - (int16_t)((w1 & 0x8) >> 1);
|
||||
xors[3] = 0 - (int16_t)((w1 & 0x4) >> 1);
|
||||
xors[0] = 0 - (int16_t)((w1 & 0x2) >> 1);
|
||||
xors[1] = 0 - (int16_t)((w1 & 0x1) );
|
||||
|
||||
alist_envmix_nead(
|
||||
hle,
|
||||
swap_wet_LR,
|
||||
dmem_dl, dmem_dr,
|
||||
dmem_wl, dmem_wr,
|
||||
dmemi, count,
|
||||
hle->alist_nead.env_values,
|
||||
hle->alist_nead.env_steps,
|
||||
xors);
|
||||
}
|
||||
|
||||
static void DUPLICATE(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t count = (w1 >> 16);
|
||||
uint16_t dmemi = w1;
|
||||
uint16_t dmemo = (w2 >> 16);
|
||||
|
||||
alist_repeat64(hle, dmemo, dmemi, count);
|
||||
}
|
||||
|
||||
static void INTERL(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t count = w1;
|
||||
uint16_t dmemi = (w2 >> 16);
|
||||
uint16_t dmemo = w2;
|
||||
|
||||
alist_copy_every_other_sample(hle, dmemo, dmemi, count);
|
||||
}
|
||||
|
||||
static void INTERLEAVE_MK(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
|
||||
{
|
||||
uint16_t left = (w2 >> 16);
|
||||
uint16_t right = w2;
|
||||
|
||||
if (hle->alist_nead.count == 0)
|
||||
return;
|
||||
|
||||
alist_interleave(hle, hle->alist_nead.out, left, right, hle->alist_nead.count);
|
||||
}
|
||||
|
||||
static void INTERLEAVE(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t count = ((w1 >> 12) & 0xff0);
|
||||
uint16_t dmemo = w1;
|
||||
uint16_t left = (w2 >> 16);
|
||||
uint16_t right = w2;
|
||||
|
||||
alist_interleave(hle, dmemo, left, right, count);
|
||||
}
|
||||
|
||||
static void ADDMIXER(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t count = (w1 >> 12) & 0xff0;
|
||||
uint16_t dmemi = (w2 >> 16);
|
||||
uint16_t dmemo = w2;
|
||||
|
||||
alist_add(hle, dmemo, dmemi, count);
|
||||
}
|
||||
|
||||
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 & 0xfff;
|
||||
uint16_t dmem = (w2 >> 16);
|
||||
|
||||
alist_multQ44(hle, dmem, count, gain);
|
||||
}
|
||||
|
||||
static void FILTER(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t flags = (w1 >> 16);
|
||||
uint32_t address = (w2 & 0xffffff);
|
||||
|
||||
if (flags > 1) {
|
||||
hle->alist_nead.filter_count = w1;
|
||||
hle->alist_nead.filter_lut_address[0] = address; /* t6 */
|
||||
}
|
||||
else {
|
||||
uint16_t dmem = w1;
|
||||
|
||||
hle->alist_nead.filter_lut_address[1] = address + 0x10; /* t5 */
|
||||
alist_filter(hle, dmem, hle->alist_nead.filter_count, address, hle->alist_nead.filter_lut_address);
|
||||
}
|
||||
}
|
||||
|
||||
static void SEGMENT(struct hle_t* UNUSED(hle), uint32_t UNUSED(w1), uint32_t UNUSED(w2))
|
||||
{
|
||||
}
|
||||
|
||||
static void NEAD_16(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t count = (w1 >> 16);
|
||||
uint16_t dmemi = w1;
|
||||
uint16_t dmemo = (w2 >> 16);
|
||||
uint16_t block_size = w2;
|
||||
|
||||
alist_copy_blocks(hle, dmemo, dmemi, block_size, count);
|
||||
}
|
||||
|
||||
static void POLEF(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t flags = (w1 >> 16);
|
||||
uint16_t gain = w1;
|
||||
uint32_t address = (w2 & 0xffffff);
|
||||
|
||||
if (hle->alist_nead.count == 0)
|
||||
return;
|
||||
|
||||
alist_polef(
|
||||
hle,
|
||||
flags & A_INIT,
|
||||
hle->alist_nead.out,
|
||||
hle->alist_nead.in,
|
||||
hle->alist_nead.count,
|
||||
gain,
|
||||
hle->alist_nead.table,
|
||||
address);
|
||||
}
|
||||
|
||||
|
||||
void alist_process_nead_mk(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x20] = {
|
||||
SPNOOP, ADPCM, CLEARBUFF, SPNOOP,
|
||||
SPNOOP, RESAMPLE, SPNOOP, SEGMENT,
|
||||
SETBUFF, SPNOOP, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE_MK, POLEF, SETLOOP,
|
||||
NEAD_16, INTERL, ENVSETUP1_MK, ENVMIXER_MK,
|
||||
LOADBUFF, SAVEBUFF, ENVSETUP2, SPNOOP,
|
||||
SPNOOP, SPNOOP, SPNOOP, SPNOOP,
|
||||
SPNOOP, SPNOOP, SPNOOP, SPNOOP
|
||||
};
|
||||
|
||||
alist_process(hle, ABI, 0x20);
|
||||
rsp_break(hle, SP_STATUS_TASKDONE);
|
||||
}
|
||||
|
||||
void alist_process_nead_sf(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x20] = {
|
||||
SPNOOP, ADPCM, CLEARBUFF, SPNOOP,
|
||||
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, SPNOOP,
|
||||
SETBUFF, SPNOOP, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE_MK, POLEF, SETLOOP,
|
||||
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
|
||||
LOADBUFF, SAVEBUFF, ENVSETUP2, SPNOOP,
|
||||
HILOGAIN, UNKNOWN, DUPLICATE, SPNOOP,
|
||||
SPNOOP, SPNOOP, SPNOOP, SPNOOP
|
||||
};
|
||||
|
||||
alist_process(hle, ABI, 0x20);
|
||||
rsp_break(hle, SP_STATUS_TASKDONE);
|
||||
}
|
||||
|
||||
void alist_process_nead_sfj(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x20] = {
|
||||
SPNOOP, ADPCM, CLEARBUFF, SPNOOP,
|
||||
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, SPNOOP,
|
||||
SETBUFF, SPNOOP, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE_MK, POLEF, SETLOOP,
|
||||
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
|
||||
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN,
|
||||
HILOGAIN, UNKNOWN, DUPLICATE, SPNOOP,
|
||||
SPNOOP, SPNOOP, SPNOOP, SPNOOP
|
||||
};
|
||||
|
||||
alist_process(hle, ABI, 0x20);
|
||||
rsp_break(hle, SP_STATUS_TASKDONE);
|
||||
}
|
||||
|
||||
void alist_process_nead_fz(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x20] = {
|
||||
UNKNOWN, ADPCM, CLEARBUFF, SPNOOP,
|
||||
ADDMIXER, RESAMPLE, SPNOOP, SPNOOP,
|
||||
SETBUFF, SPNOOP, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, SPNOOP, SETLOOP,
|
||||
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
|
||||
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN,
|
||||
SPNOOP, UNKNOWN, DUPLICATE, SPNOOP,
|
||||
SPNOOP, SPNOOP, SPNOOP, SPNOOP
|
||||
};
|
||||
|
||||
alist_process(hle, ABI, 0x20);
|
||||
rsp_break(hle, SP_STATUS_TASKDONE);
|
||||
}
|
||||
|
||||
void alist_process_nead_wrjb(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x20] = {
|
||||
SPNOOP, ADPCM, CLEARBUFF, UNKNOWN,
|
||||
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, SPNOOP,
|
||||
SETBUFF, SPNOOP, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, SPNOOP, SETLOOP,
|
||||
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
|
||||
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN,
|
||||
HILOGAIN, UNKNOWN, DUPLICATE, FILTER,
|
||||
SPNOOP, SPNOOP, SPNOOP, SPNOOP
|
||||
};
|
||||
|
||||
alist_process(hle, ABI, 0x20);
|
||||
rsp_break(hle, SP_STATUS_TASKDONE);
|
||||
}
|
||||
|
||||
void alist_process_nead_ys(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x18] = {
|
||||
UNKNOWN, ADPCM, CLEARBUFF, UNKNOWN,
|
||||
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, FILTER,
|
||||
SETBUFF, DUPLICATE, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, HILOGAIN, SETLOOP,
|
||||
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
|
||||
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN
|
||||
};
|
||||
|
||||
alist_process(hle, ABI, 0x18);
|
||||
rsp_break(hle, SP_STATUS_TASKDONE);
|
||||
}
|
||||
|
||||
void alist_process_nead_1080(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x18] = {
|
||||
UNKNOWN, ADPCM, CLEARBUFF, UNKNOWN,
|
||||
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, FILTER,
|
||||
SETBUFF, DUPLICATE, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, HILOGAIN, SETLOOP,
|
||||
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
|
||||
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN
|
||||
};
|
||||
|
||||
alist_process(hle, ABI, 0x18);
|
||||
rsp_break(hle, SP_STATUS_TASKDONE);
|
||||
}
|
||||
|
||||
void alist_process_nead_oot(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x18] = {
|
||||
UNKNOWN, ADPCM, CLEARBUFF, UNKNOWN,
|
||||
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, FILTER,
|
||||
SETBUFF, DUPLICATE, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, HILOGAIN, SETLOOP,
|
||||
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
|
||||
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN
|
||||
};
|
||||
|
||||
alist_process(hle, ABI, 0x18);
|
||||
rsp_break(hle, SP_STATUS_TASKDONE);
|
||||
}
|
||||
|
||||
void alist_process_nead_mm(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x18] = {
|
||||
UNKNOWN, ADPCM, CLEARBUFF, SPNOOP,
|
||||
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, FILTER,
|
||||
SETBUFF, DUPLICATE, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, HILOGAIN, SETLOOP,
|
||||
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
|
||||
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN
|
||||
};
|
||||
|
||||
alist_process(hle, ABI, 0x18);
|
||||
rsp_break(hle, SP_STATUS_TASKDONE);
|
||||
}
|
||||
|
||||
void alist_process_nead_mmb(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x18] = {
|
||||
SPNOOP, ADPCM, CLEARBUFF, SPNOOP,
|
||||
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, FILTER,
|
||||
SETBUFF, DUPLICATE, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, HILOGAIN, SETLOOP,
|
||||
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
|
||||
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN
|
||||
};
|
||||
|
||||
alist_process(hle, ABI, 0x18);
|
||||
rsp_break(hle, SP_STATUS_TASKDONE);
|
||||
}
|
||||
|
||||
void alist_process_nead_ac(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x18] = {
|
||||
UNKNOWN, ADPCM, CLEARBUFF, SPNOOP,
|
||||
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, FILTER,
|
||||
SETBUFF, DUPLICATE, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, HILOGAIN, SETLOOP,
|
||||
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
|
||||
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - jpeg.h *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2002 Hacktarux *
|
||||
* Mupen64plus-rsp-hle - arithmetics.h *
|
||||
* Mupen64Plus homepage: https://mupen64plus.org/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* *
|
||||
* 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 *
|
||||
|
@ -19,12 +19,25 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef JPEG_H
|
||||
#define JPEG_H
|
||||
#ifndef ARITHMETICS_H
|
||||
#define ARITHMETICS_H
|
||||
|
||||
void jpeg_decode_PS0();
|
||||
void jpeg_decode_PS();
|
||||
void jpeg_decode_OB();
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
static inline int16_t clamp_s16(int_fast32_t x)
|
||||
{
|
||||
x = (x < INT16_MIN) ? INT16_MIN: x;
|
||||
x = (x > INT16_MAX) ? INT16_MAX: x;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline int32_t vmulf(int16_t x, int16_t y)
|
||||
{
|
||||
return (((int32_t)(x))*((int32_t)(y))+0x4000)>>15;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - audio.c *
|
||||
* Mupen64Plus homepage: https://mupen64plus.org/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* *
|
||||
* 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 <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "arithmetics.h"
|
||||
|
||||
const int16_t RESAMPLE_LUT[64 * 4] = {
|
||||
(int16_t)0x0c39, (int16_t)0x66ad, (int16_t)0x0d46, (int16_t)0xffdf,
|
||||
(int16_t)0x0b39, (int16_t)0x6696, (int16_t)0x0e5f, (int16_t)0xffd8,
|
||||
(int16_t)0x0a44, (int16_t)0x6669, (int16_t)0x0f83, (int16_t)0xffd0,
|
||||
(int16_t)0x095a, (int16_t)0x6626, (int16_t)0x10b4, (int16_t)0xffc8,
|
||||
(int16_t)0x087d, (int16_t)0x65cd, (int16_t)0x11f0, (int16_t)0xffbf,
|
||||
(int16_t)0x07ab, (int16_t)0x655e, (int16_t)0x1338, (int16_t)0xffb6,
|
||||
(int16_t)0x06e4, (int16_t)0x64d9, (int16_t)0x148c, (int16_t)0xffac,
|
||||
(int16_t)0x0628, (int16_t)0x643f, (int16_t)0x15eb, (int16_t)0xffa1,
|
||||
(int16_t)0x0577, (int16_t)0x638f, (int16_t)0x1756, (int16_t)0xff96,
|
||||
(int16_t)0x04d1, (int16_t)0x62cb, (int16_t)0x18cb, (int16_t)0xff8a,
|
||||
(int16_t)0x0435, (int16_t)0x61f3, (int16_t)0x1a4c, (int16_t)0xff7e,
|
||||
(int16_t)0x03a4, (int16_t)0x6106, (int16_t)0x1bd7, (int16_t)0xff71,
|
||||
(int16_t)0x031c, (int16_t)0x6007, (int16_t)0x1d6c, (int16_t)0xff64,
|
||||
(int16_t)0x029f, (int16_t)0x5ef5, (int16_t)0x1f0b, (int16_t)0xff56,
|
||||
(int16_t)0x022a, (int16_t)0x5dd0, (int16_t)0x20b3, (int16_t)0xff48,
|
||||
(int16_t)0x01be, (int16_t)0x5c9a, (int16_t)0x2264, (int16_t)0xff3a,
|
||||
(int16_t)0x015b, (int16_t)0x5b53, (int16_t)0x241e, (int16_t)0xff2c,
|
||||
(int16_t)0x0101, (int16_t)0x59fc, (int16_t)0x25e0, (int16_t)0xff1e,
|
||||
(int16_t)0x00ae, (int16_t)0x5896, (int16_t)0x27a9, (int16_t)0xff10,
|
||||
(int16_t)0x0063, (int16_t)0x5720, (int16_t)0x297a, (int16_t)0xff02,
|
||||
(int16_t)0x001f, (int16_t)0x559d, (int16_t)0x2b50, (int16_t)0xfef4,
|
||||
(int16_t)0xffe2, (int16_t)0x540d, (int16_t)0x2d2c, (int16_t)0xfee8,
|
||||
(int16_t)0xffac, (int16_t)0x5270, (int16_t)0x2f0d, (int16_t)0xfedb,
|
||||
(int16_t)0xff7c, (int16_t)0x50c7, (int16_t)0x30f3, (int16_t)0xfed0,
|
||||
(int16_t)0xff53, (int16_t)0x4f14, (int16_t)0x32dc, (int16_t)0xfec6,
|
||||
(int16_t)0xff2e, (int16_t)0x4d57, (int16_t)0x34c8, (int16_t)0xfebd,
|
||||
(int16_t)0xff0f, (int16_t)0x4b91, (int16_t)0x36b6, (int16_t)0xfeb6,
|
||||
(int16_t)0xfef5, (int16_t)0x49c2, (int16_t)0x38a5, (int16_t)0xfeb0,
|
||||
(int16_t)0xfedf, (int16_t)0x47ed, (int16_t)0x3a95, (int16_t)0xfeac,
|
||||
(int16_t)0xfece, (int16_t)0x4611, (int16_t)0x3c85, (int16_t)0xfeab,
|
||||
(int16_t)0xfec0, (int16_t)0x4430, (int16_t)0x3e74, (int16_t)0xfeac,
|
||||
(int16_t)0xfeb6, (int16_t)0x424a, (int16_t)0x4060, (int16_t)0xfeaf,
|
||||
(int16_t)0xfeaf, (int16_t)0x4060, (int16_t)0x424a, (int16_t)0xfeb6,
|
||||
(int16_t)0xfeac, (int16_t)0x3e74, (int16_t)0x4430, (int16_t)0xfec0,
|
||||
(int16_t)0xfeab, (int16_t)0x3c85, (int16_t)0x4611, (int16_t)0xfece,
|
||||
(int16_t)0xfeac, (int16_t)0x3a95, (int16_t)0x47ed, (int16_t)0xfedf,
|
||||
(int16_t)0xfeb0, (int16_t)0x38a5, (int16_t)0x49c2, (int16_t)0xfef5,
|
||||
(int16_t)0xfeb6, (int16_t)0x36b6, (int16_t)0x4b91, (int16_t)0xff0f,
|
||||
(int16_t)0xfebd, (int16_t)0x34c8, (int16_t)0x4d57, (int16_t)0xff2e,
|
||||
(int16_t)0xfec6, (int16_t)0x32dc, (int16_t)0x4f14, (int16_t)0xff53,
|
||||
(int16_t)0xfed0, (int16_t)0x30f3, (int16_t)0x50c7, (int16_t)0xff7c,
|
||||
(int16_t)0xfedb, (int16_t)0x2f0d, (int16_t)0x5270, (int16_t)0xffac,
|
||||
(int16_t)0xfee8, (int16_t)0x2d2c, (int16_t)0x540d, (int16_t)0xffe2,
|
||||
(int16_t)0xfef4, (int16_t)0x2b50, (int16_t)0x559d, (int16_t)0x001f,
|
||||
(int16_t)0xff02, (int16_t)0x297a, (int16_t)0x5720, (int16_t)0x0063,
|
||||
(int16_t)0xff10, (int16_t)0x27a9, (int16_t)0x5896, (int16_t)0x00ae,
|
||||
(int16_t)0xff1e, (int16_t)0x25e0, (int16_t)0x59fc, (int16_t)0x0101,
|
||||
(int16_t)0xff2c, (int16_t)0x241e, (int16_t)0x5b53, (int16_t)0x015b,
|
||||
(int16_t)0xff3a, (int16_t)0x2264, (int16_t)0x5c9a, (int16_t)0x01be,
|
||||
(int16_t)0xff48, (int16_t)0x20b3, (int16_t)0x5dd0, (int16_t)0x022a,
|
||||
(int16_t)0xff56, (int16_t)0x1f0b, (int16_t)0x5ef5, (int16_t)0x029f,
|
||||
(int16_t)0xff64, (int16_t)0x1d6c, (int16_t)0x6007, (int16_t)0x031c,
|
||||
(int16_t)0xff71, (int16_t)0x1bd7, (int16_t)0x6106, (int16_t)0x03a4,
|
||||
(int16_t)0xff7e, (int16_t)0x1a4c, (int16_t)0x61f3, (int16_t)0x0435,
|
||||
(int16_t)0xff8a, (int16_t)0x18cb, (int16_t)0x62cb, (int16_t)0x04d1,
|
||||
(int16_t)0xff96, (int16_t)0x1756, (int16_t)0x638f, (int16_t)0x0577,
|
||||
(int16_t)0xffa1, (int16_t)0x15eb, (int16_t)0x643f, (int16_t)0x0628,
|
||||
(int16_t)0xffac, (int16_t)0x148c, (int16_t)0x64d9, (int16_t)0x06e4,
|
||||
(int16_t)0xffb6, (int16_t)0x1338, (int16_t)0x655e, (int16_t)0x07ab,
|
||||
(int16_t)0xffbf, (int16_t)0x11f0, (int16_t)0x65cd, (int16_t)0x087d,
|
||||
(int16_t)0xffc8, (int16_t)0x10b4, (int16_t)0x6626, (int16_t)0x095a,
|
||||
(int16_t)0xffd0, (int16_t)0x0f83, (int16_t)0x6669, (int16_t)0x0a44,
|
||||
(int16_t)0xffd8, (int16_t)0x0e5f, (int16_t)0x6696, (int16_t)0x0b39,
|
||||
(int16_t)0xffdf, (int16_t)0x0d46, (int16_t)0x66ad, (int16_t)0x0c39
|
||||
};
|
||||
|
||||
int32_t rdot(size_t n, const int16_t *x, const int16_t *y)
|
||||
{
|
||||
int32_t accu = 0;
|
||||
|
||||
y += n;
|
||||
|
||||
while (n != 0) {
|
||||
accu += *(x++) * *(--y);
|
||||
--n;
|
||||
}
|
||||
|
||||
return accu;
|
||||
}
|
||||
|
||||
void adpcm_compute_residuals(int16_t* dst, const int16_t* src,
|
||||
const int16_t* cb_entry, const int16_t* last_samples, size_t count)
|
||||
{
|
||||
const int16_t* const book1 = cb_entry;
|
||||
const int16_t* const book2 = cb_entry + 8;
|
||||
|
||||
const int16_t l1 = last_samples[0];
|
||||
const int16_t l2 = last_samples[1];
|
||||
|
||||
size_t i;
|
||||
|
||||
assert(count <= 8);
|
||||
|
||||
for(i = 0; i < count; ++i) {
|
||||
int32_t accu = (int32_t)src[i] << 11;
|
||||
accu += book1[i]*l1 + book2[i]*l2 + rdot(i, book2, src);
|
||||
dst[i] = clamp_s16(accu >> 11);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - alist_internal.h *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2002 Hacktarux *
|
||||
* Mupen64plus-rsp-hle - audio.h *
|
||||
* Mupen64Plus homepage: https://mupen64plus.org/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* *
|
||||
* 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 *
|
||||
|
@ -19,32 +19,27 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef ALIST_INTERNAL_H
|
||||
#define ALIST_INTERNAL_H
|
||||
#ifndef AUDIO_H
|
||||
#define AUDIO_H
|
||||
|
||||
#include "hle.h"
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef void (*acmd_callback_t)(u32 inst1, u32 inst2);
|
||||
#include "common.h"
|
||||
|
||||
/*
|
||||
* Audio flags
|
||||
*/
|
||||
extern const int16_t RESAMPLE_LUT[64 * 4];
|
||||
|
||||
#define A_INIT 0x01
|
||||
#define A_CONTINUE 0x00
|
||||
#define A_LOOP 0x02
|
||||
#define A_OUT 0x02
|
||||
#define A_LEFT 0x02
|
||||
#define A_RIGHT 0x00
|
||||
#define A_VOL 0x04
|
||||
#define A_RATE 0x00
|
||||
#define A_AUX 0x08
|
||||
#define A_NOAUX 0x00
|
||||
#define A_MAIN 0x00
|
||||
#define A_MIX 0x10
|
||||
int32_t rdot(size_t n, const int16_t *x, const int16_t *y);
|
||||
|
||||
extern u16 AudioInBuffer, AudioOutBuffer, AudioCount;
|
||||
extern u16 AudioAuxA, AudioAuxC, AudioAuxE;
|
||||
extern u32 loopval; // Value set by A_SETLOOP : Possible conflict with SETVOLUME???
|
||||
static inline int16_t adpcm_predict_sample(uint8_t byte, uint8_t mask,
|
||||
unsigned lshift, unsigned rshift)
|
||||
{
|
||||
int16_t sample = (uint16_t)(byte & mask) << lshift;
|
||||
sample >>= rshift; /* signed */
|
||||
return sample;
|
||||
}
|
||||
|
||||
void adpcm_compute_residuals(int16_t* dst, const int16_t* src,
|
||||
const int16_t* cb_entry, const int16_t* last_samples, size_t count);
|
||||
|
||||
#endif
|
|
@ -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 *
|
||||
|
@ -23,33 +23,34 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
#include "hle.h"
|
||||
#include "hle_internal.h"
|
||||
|
||||
/**
|
||||
* During IPL3 stage of CIC x105 games, the RSP performs some checks and transactions
|
||||
* necessary for booting the game.
|
||||
*
|
||||
*
|
||||
* We only implement the needed DMA transactions for booting.
|
||||
*
|
||||
* Found in Banjo-Tooie, Zelda, Perfect Dark, ...)
|
||||
**/
|
||||
void cicx105_ucode()
|
||||
void cicx105_ucode(struct hle_t* hle)
|
||||
{
|
||||
// memcpy is okay to use because access constrains are met (alignment, size)
|
||||
/* memcpy is okay to use because access constrains are met (alignment, size) */
|
||||
unsigned int i;
|
||||
unsigned char * dst = rsp.RDRAM + 0x2fb1f0;
|
||||
unsigned char * src = rsp.IMEM + 0x120;
|
||||
unsigned char *dst = hle->dram + 0x2fb1f0;
|
||||
unsigned char *src = hle->imem + 0x120;
|
||||
|
||||
/* dma_read(0x1120, 0x1e8, 0x1e8) */
|
||||
memcpy(rsp.IMEM + 0x120, rsp.RDRAM + 0x1e8, 0x1f0);
|
||||
memcpy(hle->imem + 0x120, hle->dram + 0x1e8, 0x1f0);
|
||||
|
||||
/* dma_write(0x1120, 0x2fb1f0, 0xfe817000) */
|
||||
for (i = 0; i < 24; ++i)
|
||||
{
|
||||
for (i = 0; i < 24; ++i) {
|
||||
memcpy(dst, src, 8);
|
||||
dst += 0xff0;
|
||||
src += 0x8;
|
||||
|
||||
}
|
||||
|
||||
rsp_break(hle, 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - cicx105.h *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2002 Hacktarux *
|
||||
* Mupen64plus-rsp-hle - common.h *
|
||||
* Mupen64Plus homepage: https://mupen64plus.org/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* *
|
||||
* 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 *
|
||||
|
@ -19,10 +19,20 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef CICX105_H
|
||||
#define CICX105_H
|
||||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
void cicx105_ucode();
|
||||
/* macro for unused variable warning suppression */
|
||||
#ifdef __GNUC__
|
||||
# define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
|
||||
#else
|
||||
# define UNUSED(x) UNUSED_ ## x
|
||||
#endif
|
||||
|
||||
/* macro for inline keyword */
|
||||
#ifdef _MSC_VER
|
||||
#define inline __inline
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,489 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - hle.c *
|
||||
* Mupen64Plus homepage: https://mupen64plus.org/ *
|
||||
* Copyright (C) 2012 Bobby Smiles *
|
||||
* Copyright (C) 2009 Richard Goedeken *
|
||||
* Copyright (C) 2002 Hacktarux *
|
||||
* *
|
||||
* 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 <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef ENABLE_TASK_DUMP
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include "hle_external.h"
|
||||
#include "hle_internal.h"
|
||||
#include "memory.h"
|
||||
#include "ucodes.h"
|
||||
|
||||
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
/* some rdp status flags */
|
||||
#define DP_STATUS_FREEZE 0x2
|
||||
|
||||
|
||||
|
||||
/* 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 send_dlist_to_gfx_plugin(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 bool try_re2_task_dispatching(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);
|
||||
#endif
|
||||
|
||||
/* Global functions */
|
||||
void hle_init(struct hle_t* hle,
|
||||
unsigned char* dram,
|
||||
unsigned char* dmem,
|
||||
unsigned char* imem,
|
||||
unsigned int* mi_intr,
|
||||
unsigned int* sp_mem_addr,
|
||||
unsigned int* sp_dram_addr,
|
||||
unsigned int* sp_rd_length,
|
||||
unsigned int* sp_wr_length,
|
||||
unsigned int* sp_status,
|
||||
unsigned int* sp_dma_full,
|
||||
unsigned int* sp_dma_busy,
|
||||
unsigned int* sp_pc,
|
||||
unsigned int* sp_semaphore,
|
||||
unsigned int* dpc_start,
|
||||
unsigned int* dpc_end,
|
||||
unsigned int* dpc_current,
|
||||
unsigned int* dpc_status,
|
||||
unsigned int* dpc_clock,
|
||||
unsigned int* dpc_bufbusy,
|
||||
unsigned int* dpc_pipebusy,
|
||||
unsigned int* dpc_tmem,
|
||||
void* user_defined)
|
||||
{
|
||||
hle->dram = dram;
|
||||
hle->dmem = dmem;
|
||||
hle->imem = imem;
|
||||
hle->mi_intr = mi_intr;
|
||||
hle->sp_mem_addr = sp_mem_addr;
|
||||
hle->sp_dram_addr = sp_dram_addr;
|
||||
hle->sp_rd_length = sp_rd_length;
|
||||
hle->sp_wr_length = sp_wr_length;
|
||||
hle->sp_status = sp_status;
|
||||
hle->sp_dma_full = sp_dma_full;
|
||||
hle->sp_dma_busy = sp_dma_busy;
|
||||
hle->sp_pc = sp_pc;
|
||||
hle->sp_semaphore = sp_semaphore;
|
||||
hle->dpc_start = dpc_start;
|
||||
hle->dpc_end = dpc_end;
|
||||
hle->dpc_current = dpc_current;
|
||||
hle->dpc_status = dpc_status;
|
||||
hle->dpc_clock = dpc_clock;
|
||||
hle->dpc_bufbusy = dpc_bufbusy;
|
||||
hle->dpc_pipebusy = dpc_pipebusy;
|
||||
hle->dpc_tmem = dpc_tmem;
|
||||
hle->user_defined = user_defined;
|
||||
}
|
||||
|
||||
void hle_execute(struct hle_t* hle)
|
||||
{
|
||||
if (is_task(hle)) {
|
||||
if (!try_fast_task_dispatching(hle))
|
||||
normal_task_dispatching(hle);
|
||||
} else {
|
||||
non_task_dispatching(hle);
|
||||
}
|
||||
}
|
||||
|
||||
/* local functions */
|
||||
static unsigned int sum_bytes(const unsigned char *bytes, unsigned int size)
|
||||
{
|
||||
unsigned int sum = 0;
|
||||
const unsigned char *const bytes_end = bytes + size;
|
||||
|
||||
while (bytes != bytes_end)
|
||||
sum += *bytes++;
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to figure if the RSP was launched using osSpTask* functions
|
||||
* and not run directly (in which case DMEM[0xfc0-0xfff] is meaningless).
|
||||
*
|
||||
* Previously, the ucode_size field was used to determine this,
|
||||
* but it is not robust enough (hi Pokemon Stadium !) because games could write anything
|
||||
* in this field : most ucode_boot discard the value and just use 0xf7f anyway.
|
||||
*
|
||||
* Using ucode_boot_size should be more robust in this regard.
|
||||
**/
|
||||
static bool is_task(struct hle_t* hle)
|
||||
{
|
||||
return (*dmem_u32(hle, TASK_UCODE_BOOT_SIZE) <= 0x1000);
|
||||
}
|
||||
|
||||
void rsp_break(struct hle_t* hle, unsigned int setbits)
|
||||
{
|
||||
*hle->sp_status |= setbits | SP_STATUS_BROKE | SP_STATUS_HALT;
|
||||
|
||||
if ((*hle->sp_status & SP_STATUS_INTR_ON_BREAK)) {
|
||||
*hle->mi_intr |= MI_INTR_SP;
|
||||
HleCheckInterrupts(hle->user_defined);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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 bool try_fast_audio_dispatching(struct hle_t* hle)
|
||||
{
|
||||
/* identify audio ucode by using the content of ucode_data */
|
||||
uint32_t ucode_data = *dmem_u32(hle, TASK_UCODE_DATA);
|
||||
uint32_t v;
|
||||
|
||||
if (*dram_u32(hle, ucode_data) == 0x00000001) {
|
||||
if (*dram_u32(hle, ucode_data + 0x30) == 0xf0000f00) {
|
||||
v = *dram_u32(hle, ucode_data + 0x28);
|
||||
switch(v)
|
||||
{
|
||||
case 0x1e24138c: /* audio ABI (most common) */
|
||||
alist_process_audio(hle); return true;
|
||||
case 0x1dc8138c: /* GoldenEye */
|
||||
alist_process_audio_ge(hle); return true;
|
||||
case 0x1e3c1390: /* BlastCorp, DiddyKongRacing */
|
||||
alist_process_audio_bc(hle); return true;
|
||||
default:
|
||||
HleWarnMessage(hle->user_defined, "ABI1 identification regression: v=%08x", v);
|
||||
}
|
||||
} else {
|
||||
v = *dram_u32(hle, ucode_data + 0x10);
|
||||
switch(v)
|
||||
{
|
||||
case 0x11181350: /* MarioKart, WaveRace (E) */
|
||||
alist_process_nead_mk(hle); return true;
|
||||
case 0x111812e0: /* StarFox (J) */
|
||||
alist_process_nead_sfj(hle); return true;
|
||||
case 0x110412ac: /* WaveRace (J RevB) */
|
||||
alist_process_nead_wrjb(hle); return true;
|
||||
case 0x110412cc: /* StarFox/LylatWars (except J) */
|
||||
alist_process_nead_sf(hle); return true;
|
||||
case 0x1cd01250: /* FZeroX */
|
||||
alist_process_nead_fz(hle); return true;
|
||||
case 0x1f08122c: /* YoshisStory */
|
||||
alist_process_nead_ys(hle); return true;
|
||||
case 0x1f38122c: /* 1080° Snowboarding */
|
||||
alist_process_nead_1080(hle); return true;
|
||||
case 0x1f681230: /* Zelda OoT / Zelda MM (J, J RevA) */
|
||||
alist_process_nead_oot(hle); return true;
|
||||
case 0x1f801250: /* Zelda MM (except J, J RevA, E Beta), PokemonStadium 2 */
|
||||
alist_process_nead_mm(hle); return true;
|
||||
case 0x109411f8: /* Zelda MM (E Beta) */
|
||||
alist_process_nead_mmb(hle); return true;
|
||||
case 0x1eac11b8: /* AnimalCrossing */
|
||||
alist_process_nead_ac(hle); return true;
|
||||
case 0x00010010: /* MusyX v2 (IndianaJones, BattleForNaboo) */
|
||||
musyx_v2_task(hle); return true;
|
||||
case 0x1f701238: /* Mario Artist Talent Studio */
|
||||
alist_process_nead_mats(hle); return true;
|
||||
case 0x1f4c1230: /* FZeroX Expansion */
|
||||
alist_process_nead_efz(hle); return true;
|
||||
default:
|
||||
HleWarnMessage(hle->user_defined, "ABI2 identification regression: v=%08x", v);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
v = *dram_u32(hle, ucode_data + 0x10);
|
||||
switch(v)
|
||||
{
|
||||
case 0x00000001: /* MusyX v1
|
||||
RogueSquadron, ResidentEvil2, PolarisSnoCross,
|
||||
TheWorldIsNotEnough, RugratsInParis, NBAShowTime,
|
||||
HydroThunder, Tarzan, GauntletLegend, Rush2049 */
|
||||
musyx_v1_task(hle); return true;
|
||||
case 0x0000127c: /* naudio (many games) */
|
||||
alist_process_naudio(hle); return true;
|
||||
case 0x00001280: /* BanjoKazooie */
|
||||
alist_process_naudio_bk(hle); return true;
|
||||
case 0x1c58126c: /* DonkeyKong */
|
||||
alist_process_naudio_dk(hle); return true;
|
||||
case 0x1ae8143c: /* BanjoTooie, JetForceGemini, MickeySpeedWayUSA, PerfectDark */
|
||||
alist_process_naudio_mp3(hle); return true;
|
||||
case 0x1ab0140c: /* ConkerBadFurDay */
|
||||
alist_process_naudio_cbfd(hle); return true;
|
||||
|
||||
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:
|
||||
/* Resident evil 2 */
|
||||
if (*dmem_u32(hle, TASK_DATA_PTR) == 0) {
|
||||
return try_re2_task_dispatching(hle);
|
||||
}
|
||||
|
||||
if (hle->hle_gfx) {
|
||||
send_dlist_to_gfx_plugin(hle);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (hle->hle_aud) {
|
||||
send_alist_to_audio_plugin(hle);
|
||||
return true;
|
||||
} else if (try_fast_audio_dispatching(hle))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 7:
|
||||
HleShowCFB(hle->user_defined);
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void normal_task_dispatching(struct hle_t* hle)
|
||||
{
|
||||
const 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 */
|
||||
rsp_break(hle, SP_STATUS_TASKDONE);
|
||||
return;
|
||||
|
||||
/* GFX: Twintris [misleading task->type == 0] */
|
||||
case 0x212ee:
|
||||
if (hle->hle_gfx) {
|
||||
send_dlist_to_gfx_plugin(hle);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
/* JPEG: found in Pokemon Stadium J */
|
||||
case 0x2c85a:
|
||||
jpeg_decode_PS0(hle);
|
||||
return;
|
||||
|
||||
/* JPEG: found in Zelda Ocarina of Time, Pokemon Stadium 1, Pokemon Stadium 2 */
|
||||
case 0x2caa6:
|
||||
jpeg_decode_PS(hle);
|
||||
return;
|
||||
|
||||
/* JPEG: found in Ogre Battle, Bottom of the 9th */
|
||||
case 0x130de:
|
||||
case 0x278b0:
|
||||
jpeg_decode_OB(hle);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/* Forward task to RSP Fallback.
|
||||
* If task is not forwarded, use the regular "unknown ucode" path */
|
||||
if (HleForwardTask(hle->user_defined) != 0) {
|
||||
|
||||
HleWarnMessage(hle->user_defined, "unknown RSP code: sum: %x PC:%x", sum, *hle->sp_pc);
|
||||
#ifdef ENABLE_TASK_DUMP
|
||||
dump_unknown_non_task(hle, sum);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Resident evil 2 */
|
||||
static bool try_re2_task_dispatching(struct hle_t* hle)
|
||||
{
|
||||
const unsigned int sum =
|
||||
sum_bytes((void*)dram_u32(hle, *dmem_u32(hle, TASK_UCODE)), 256);
|
||||
|
||||
switch (sum) {
|
||||
|
||||
case 0x450f:
|
||||
resize_bilinear_task(hle);
|
||||
return true;
|
||||
|
||||
case 0x3b44:
|
||||
decode_video_frame_task(hle);
|
||||
return true;
|
||||
|
||||
case 0x3d84:
|
||||
fill_video_double_buffer_task(hle);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_TASK_DUMP
|
||||
static void dump_unknown_task(struct hle_t* hle, unsigned int sum)
|
||||
{
|
||||
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);
|
||||
dump_task(hle, filename);
|
||||
|
||||
/* dump ucode_boot */
|
||||
sprintf(&filename[0], "ucode_boot_%x.bin", sum);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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)
|
||||
{
|
||||
char filename[256];
|
||||
|
||||
/* dump IMEM & DMEM for further analysis */
|
||||
sprintf(&filename[0], "imem_%x.bin", sum);
|
||||
dump_binary(hle, filename, hle->imem, 0x1000);
|
||||
|
||||
sprintf(&filename[0], "dmem_%x.bin", sum);
|
||||
dump_binary(hle, filename, hle->dmem, 0x1000);
|
||||
}
|
||||
|
||||
static void dump_binary(struct hle_t* hle, const char *const filename,
|
||||
const unsigned char *const bytes, unsigned int size)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
/* if file already exists, do nothing */
|
||||
f = fopen(filename, "r");
|
||||
if (f == NULL) {
|
||||
/* else we write bytes to the file */
|
||||
f = fopen(filename, "wb");
|
||||
if (f != NULL) {
|
||||
if (fwrite(bytes, 1, size, f) != size)
|
||||
HleErrorMessage(hle->user_defined, "Writing error on %s", filename);
|
||||
fclose(f);
|
||||
} else
|
||||
HleErrorMessage(hle->user_defined, "Couldn't open %s for writing !", filename);
|
||||
} else
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
static void dump_task(struct hle_t* hle, const char *const filename)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
f = fopen(filename, "r");
|
||||
if (f == NULL) {
|
||||
f = fopen(filename, "w");
|
||||
fprintf(f,
|
||||
"type = %d\n"
|
||||
"flags = %d\n"
|
||||
"ucode_boot = %#08x size = %#x\n"
|
||||
"ucode = %#08x size = %#x\n"
|
||||
"ucode_data = %#08x size = %#x\n"
|
||||
"dram_stack = %#08x size = %#x\n"
|
||||
"output_buff = %#08x *size = %#x\n"
|
||||
"data = %#08x size = %#x\n"
|
||||
"yield_data = %#08x size = %#x\n",
|
||||
*dmem_u32(hle, TASK_TYPE),
|
||||
*dmem_u32(hle, TASK_FLAGS),
|
||||
*dmem_u32(hle, TASK_UCODE_BOOT), *dmem_u32(hle, TASK_UCODE_BOOT_SIZE),
|
||||
*dmem_u32(hle, TASK_UCODE), *dmem_u32(hle, TASK_UCODE_SIZE),
|
||||
*dmem_u32(hle, TASK_UCODE_DATA), *dmem_u32(hle, TASK_UCODE_DATA_SIZE),
|
||||
*dmem_u32(hle, TASK_DRAM_STACK), *dmem_u32(hle, TASK_DRAM_STACK_SIZE),
|
||||
*dmem_u32(hle, TASK_OUTPUT_BUFF), *dmem_u32(hle, TASK_OUTPUT_BUFF_SIZE),
|
||||
*dmem_u32(hle, TASK_DATA_PTR), *dmem_u32(hle, TASK_DATA_SIZE),
|
||||
*dmem_u32(hle, TASK_YIELD_DATA_PTR), *dmem_u32(hle, TASK_YIELD_DATA_SIZE));
|
||||
fclose(f);
|
||||
} else
|
||||
fclose(f);
|
||||
}
|
||||
#endif
|
|
@ -1,7 +1,7 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - hle.h *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2002 Hacktarux *
|
||||
* Mupen64Plus homepage: https://mupen64plus.org/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* *
|
||||
* 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 *
|
||||
|
@ -22,68 +22,33 @@
|
|||
#ifndef HLE_H
|
||||
#define HLE_H
|
||||
|
||||
#define M64P_PLUGIN_PROTOTYPES 1
|
||||
#include "m64p_plugin.h"
|
||||
#include "hle_internal.h"
|
||||
|
||||
#define RSP_HLE_VERSION 0x020000
|
||||
#define RSP_PLUGIN_API_VERSION 0x020000
|
||||
void hle_init(struct hle_t* hle,
|
||||
unsigned char* dram,
|
||||
unsigned char* dmem,
|
||||
unsigned char* imem,
|
||||
unsigned int* mi_intr,
|
||||
unsigned int* sp_mem_addr,
|
||||
unsigned int* sp_dram_addr,
|
||||
unsigned int* sp_rd_length,
|
||||
unsigned int* sp_wr_length,
|
||||
unsigned int* sp_status,
|
||||
unsigned int* sp_dma_full,
|
||||
unsigned int* sp_dma_busy,
|
||||
unsigned int* sp_pc,
|
||||
unsigned int* sp_semaphore,
|
||||
unsigned int* dpc_start,
|
||||
unsigned int* dpc_end,
|
||||
unsigned int* dpc_current,
|
||||
unsigned int* dpc_status,
|
||||
unsigned int* dpc_clock,
|
||||
unsigned int* dpc_bufbusy,
|
||||
unsigned int* dpc_pipebusy,
|
||||
unsigned int* dpc_tmem,
|
||||
void* user_defined);
|
||||
|
||||
#ifdef M64P_BIG_ENDIAN
|
||||
#define S 0
|
||||
#define S16 0
|
||||
#define S8 0
|
||||
#else
|
||||
#define S 1
|
||||
#define S16 2
|
||||
#define S8 3
|
||||
#endif
|
||||
|
||||
// types
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned long long u64;
|
||||
|
||||
typedef signed char s8;
|
||||
typedef signed short s16;
|
||||
typedef signed int s32;
|
||||
typedef signed long long s64;
|
||||
|
||||
extern RSP_INFO rsp;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int type;
|
||||
unsigned int flags;
|
||||
|
||||
unsigned int ucode_boot;
|
||||
unsigned int ucode_boot_size;
|
||||
|
||||
unsigned int ucode;
|
||||
unsigned int ucode_size;
|
||||
|
||||
unsigned int ucode_data;
|
||||
unsigned int ucode_data_size;
|
||||
|
||||
unsigned int dram_stack;
|
||||
unsigned int dram_stack_size;
|
||||
|
||||
unsigned int output_buff;
|
||||
unsigned int output_buff_size;
|
||||
|
||||
unsigned int data_ptr;
|
||||
unsigned int data_size;
|
||||
|
||||
unsigned int yield_data_ptr;
|
||||
unsigned int yield_data_size;
|
||||
} OSTask_t;
|
||||
|
||||
static const OSTask_t * const get_task()
|
||||
{
|
||||
return (OSTask_t*)(rsp.DMEM + 0xfc0);
|
||||
}
|
||||
|
||||
void DebugMessage(int level, const char *message, ...);
|
||||
void hle_execute(struct hle_t* hle);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - hle_external.h *
|
||||
* Mupen64Plus homepage: https://mupen64plus.org/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* *
|
||||
* 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. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef HLE_EXTERNAL_H
|
||||
#define HLE_EXTERNAL_H
|
||||
|
||||
/* users of the hle core are expected to define these functions */
|
||||
|
||||
void HleVerboseMessage(void* user_defined, const char *message, ...);
|
||||
void HleInfoMessage(void* user_defined, const char *message, ...);
|
||||
void HleErrorMessage(void* user_defined, const char *message, ...);
|
||||
void HleWarnMessage(void* user_defined, const char *message, ...);
|
||||
|
||||
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
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - hle_internal.h *
|
||||
* Mupen64Plus homepage: https://mupen64plus.org/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* *
|
||||
* 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. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef HLE_INTERNAL_H
|
||||
#define HLE_INTERNAL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "ucodes.h"
|
||||
|
||||
/* rsp hle internal state - internal usage only */
|
||||
struct hle_t
|
||||
{
|
||||
unsigned char* dram;
|
||||
unsigned char* dmem;
|
||||
unsigned char* imem;
|
||||
|
||||
unsigned int* mi_intr;
|
||||
|
||||
unsigned int* sp_mem_addr;
|
||||
unsigned int* sp_dram_addr;
|
||||
unsigned int* sp_rd_length;
|
||||
unsigned int* sp_wr_length;
|
||||
unsigned int* sp_status;
|
||||
unsigned int* sp_dma_full;
|
||||
unsigned int* sp_dma_busy;
|
||||
unsigned int* sp_pc;
|
||||
unsigned int* sp_semaphore;
|
||||
|
||||
unsigned int* dpc_start;
|
||||
unsigned int* dpc_end;
|
||||
unsigned int* dpc_current;
|
||||
unsigned int* dpc_status;
|
||||
unsigned int* dpc_clock;
|
||||
unsigned int* dpc_bufbusy;
|
||||
unsigned int* dpc_pipebusy;
|
||||
unsigned int* dpc_tmem;
|
||||
|
||||
/* 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];
|
||||
|
||||
/* alist_audio.c */
|
||||
struct alist_audio_t alist_audio;
|
||||
|
||||
/* alist_naudio.c */
|
||||
struct alist_naudio_t alist_naudio;
|
||||
|
||||
/* alist_nead.c */
|
||||
struct alist_nead_t alist_nead;
|
||||
|
||||
/* mp3.c */
|
||||
uint8_t mp3_buffer[0x1000];
|
||||
};
|
||||
|
||||
/* 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
|
||||
|
|
@ -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 *
|
||||
|
@ -22,49 +22,48 @@
|
|||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define M64P_PLUGIN_PROTOTYPES 1
|
||||
#include "m64p_types.h"
|
||||
#include "m64p_plugin.h"
|
||||
#include "hle.h"
|
||||
#include "arithmetics.h"
|
||||
#include "hle_external.h"
|
||||
#include "hle_internal.h"
|
||||
#include "memory.h"
|
||||
|
||||
#define SUBBLOCK_SIZE 64
|
||||
|
||||
typedef void (*tile_line_emitter_t)(const int16_t *y, const int16_t *u, uint32_t address);
|
||||
typedef void (*std_macroblock_decoder_t)(int16_t *macroblock, unsigned int subblock_count, const int16_t qtables[3][SUBBLOCK_SIZE]);
|
||||
|
||||
/* rdram operations */
|
||||
// FIXME: these functions deserve their own module
|
||||
static void rdram_read_many_u16(uint16_t *dst, uint32_t address, unsigned int count);
|
||||
static void rdram_write_many_u16(const uint16_t *src, uint32_t address, unsigned int count);
|
||||
static uint32_t rdram_read_u32(uint32_t address);
|
||||
static void rdram_write_many_u32(const uint32_t *src, uint32_t address, unsigned int count);
|
||||
typedef void (*tile_line_emitter_t)(struct hle_t* hle, const int16_t *y, const int16_t *u, uint32_t address);
|
||||
typedef void (*subblock_transform_t)(int16_t *dst, const int16_t *src);
|
||||
|
||||
/* standard jpeg ucode decoder */
|
||||
static void jpeg_decode_std(const char * const version, const std_macroblock_decoder_t decode_mb, const tile_line_emitter_t emit_line);
|
||||
static void jpeg_decode_std(struct hle_t* hle,
|
||||
const char *const version,
|
||||
const subblock_transform_t transform_luma,
|
||||
const subblock_transform_t transform_chroma,
|
||||
const tile_line_emitter_t emit_line);
|
||||
|
||||
/* helper functions */
|
||||
static uint8_t clamp_u8(int16_t x);
|
||||
static int16_t clamp_s12(int16_t x);
|
||||
static int16_t clamp_s16(int32_t x);
|
||||
static uint16_t clamp_RGBA_component(int16_t x);
|
||||
|
||||
/* pixel conversion & foratting */
|
||||
/* pixel conversion & formatting */
|
||||
static uint32_t GetUYVY(int16_t y1, int16_t y2, int16_t u, int16_t v);
|
||||
static uint16_t GetRGBA(int16_t y, int16_t u, int16_t v);
|
||||
|
||||
/* tile line emitters */
|
||||
static void EmitYUVTileLine(const int16_t *y, const int16_t *u, uint32_t address);
|
||||
static void EmitRGBATileLine(const int16_t *y, const int16_t *u, uint32_t address);
|
||||
static void EmitYUVTileLine(struct hle_t* hle, const int16_t *y, const int16_t *u, uint32_t address);
|
||||
static void EmitRGBATileLine(struct hle_t* hle, const int16_t *y, const int16_t *u, uint32_t address);
|
||||
|
||||
/* macroblocks operations */
|
||||
static void DecodeMacroblock1(int16_t *macroblock, int32_t *y_dc, int32_t *u_dc, int32_t *v_dc, const int16_t *qtable);
|
||||
static void DecodeMacroblock2(int16_t *macroblock, unsigned int subblock_count, const int16_t qtables[3][SUBBLOCK_SIZE]);
|
||||
static void DecodeMacroblock3(int16_t *macroblock, unsigned int subblock_count, const int16_t qtables[3][SUBBLOCK_SIZE]);
|
||||
static void EmitTilesMode0(const tile_line_emitter_t emit_line, const int16_t *macroblock, uint32_t address);
|
||||
static void EmitTilesMode2(const tile_line_emitter_t emit_line, const int16_t *macroblock, uint32_t address);
|
||||
static void decode_macroblock_ob(int16_t *macroblock, int32_t *y_dc, int32_t *u_dc, int32_t *v_dc, const int16_t *qtable);
|
||||
static void decode_macroblock_std(const subblock_transform_t transform_luma,
|
||||
const subblock_transform_t transform_chroma,
|
||||
int16_t *macroblock,
|
||||
unsigned int subblock_count,
|
||||
const int16_t qtables[3][SUBBLOCK_SIZE]);
|
||||
static void EmitTilesMode0(struct hle_t* hle, const tile_line_emitter_t emit_line, const int16_t *macroblock, uint32_t address);
|
||||
static void EmitTilesMode2(struct hle_t* hle, const tile_line_emitter_t emit_line, const int16_t *macroblock, uint32_t address);
|
||||
|
||||
/* subblocks operations */
|
||||
static void TransposeSubBlock(int16_t *dst, const int16_t *src);
|
||||
|
@ -73,14 +72,13 @@ static void ReorderSubBlock(int16_t *dst, const int16_t *src, const unsigned int
|
|||
static void MultSubBlocks(int16_t *dst, const int16_t *src1, const int16_t *src2, unsigned int shift);
|
||||
static void ScaleSubBlock(int16_t *dst, const int16_t *src, int16_t scale);
|
||||
static void RShiftSubBlock(int16_t *dst, const int16_t *src, unsigned int shift);
|
||||
static void InverseDCT1D(const float * const x, float *dst, unsigned int stride);
|
||||
static void InverseDCT1D(const float *const x, float *dst, unsigned int stride);
|
||||
static void InverseDCTSubBlock(int16_t *dst, const int16_t *src);
|
||||
static void RescaleYSubBlock(int16_t *dst, const int16_t *src);
|
||||
static void RescaleUVSubBlock(int16_t *dst, const int16_t *src);
|
||||
|
||||
/* transposed dequantization table */
|
||||
static const int16_t DEFAULT_QTABLE[SUBBLOCK_SIZE] =
|
||||
{
|
||||
static const int16_t DEFAULT_QTABLE[SUBBLOCK_SIZE] = {
|
||||
16, 12, 14, 14, 18, 24, 49, 72,
|
||||
11, 12, 13, 17, 22, 35, 64, 92,
|
||||
10, 14, 16, 22, 37, 55, 78, 95,
|
||||
|
@ -92,8 +90,7 @@ static const int16_t DEFAULT_QTABLE[SUBBLOCK_SIZE] =
|
|||
};
|
||||
|
||||
/* zig-zag indices */
|
||||
static const unsigned int ZIGZAG_TABLE[SUBBLOCK_SIZE] =
|
||||
{
|
||||
static const unsigned int ZIGZAG_TABLE[SUBBLOCK_SIZE] = {
|
||||
0, 1, 5, 6, 14, 15, 27, 28,
|
||||
2, 4, 7, 13, 16, 26, 29, 42,
|
||||
3, 8, 12, 17, 25, 30, 41, 43,
|
||||
|
@ -105,8 +102,7 @@ static const unsigned int ZIGZAG_TABLE[SUBBLOCK_SIZE] =
|
|||
};
|
||||
|
||||
/* transposition indices */
|
||||
static const unsigned int TRANSPOSE_TABLE[SUBBLOCK_SIZE] =
|
||||
{
|
||||
static const unsigned int TRANSPOSE_TABLE[SUBBLOCK_SIZE] = {
|
||||
0, 8, 16, 24, 32, 40, 48, 56,
|
||||
1, 9, 17, 25, 33, 41, 49, 57,
|
||||
2, 10, 18, 26, 34, 42, 50, 58,
|
||||
|
@ -123,18 +119,17 @@ static const unsigned int TRANSPOSE_TABLE[SUBBLOCK_SIZE] =
|
|||
* Cn = alpha * cos(n * PI / 16) (alpha is chosen such as C4 = 1) */
|
||||
static const float IDCT_C3 = 1.175875602f;
|
||||
static const float IDCT_C6 = 0.541196100f;
|
||||
static const float IDCT_K[10] =
|
||||
{
|
||||
0.765366865f, /* C2-C6 */
|
||||
-1.847759065f, /* -C2-C6 */
|
||||
-0.390180644f, /* C5-C3 */
|
||||
-1.961570561f, /* -C5-C3 */
|
||||
1.501321110f, /* C1+C3-C5-C7 */
|
||||
2.053119869f, /* C1+C3-C5+C7 */
|
||||
3.072711027f, /* C1+C3+C5-C7 */
|
||||
0.298631336f, /* -C1+C3+C5-C7 */
|
||||
-0.899976223f, /* C7-C3 */
|
||||
-2.562915448f /* -C1-C3 */
|
||||
static const float IDCT_K[10] = {
|
||||
0.765366865f, /* C2-C6 */
|
||||
-1.847759065f, /* -C2-C6 */
|
||||
-0.390180644f, /* C5-C3 */
|
||||
-1.961570561f, /* -C5-C3 */
|
||||
1.501321110f, /* C1+C3-C5-C7 */
|
||||
2.053119869f, /* C1+C3-C5+C7 */
|
||||
3.072711027f, /* C1+C3+C5-C7 */
|
||||
0.298631336f, /* -C1+C3+C5-C7 */
|
||||
-0.899976223f, /* C7-C3 */
|
||||
-2.562915448f /* -C1-C3 */
|
||||
};
|
||||
|
||||
|
||||
|
@ -143,24 +138,26 @@ static const float IDCT_K[10] =
|
|||
/***************************************************************************
|
||||
* JPEG decoding ucode found in Japanese exclusive version of Pokemon Stadium.
|
||||
**************************************************************************/
|
||||
void jpeg_decode_PS0()
|
||||
void jpeg_decode_PS0(struct hle_t* hle)
|
||||
{
|
||||
jpeg_decode_std("PS0", DecodeMacroblock3, EmitYUVTileLine);
|
||||
jpeg_decode_std(hle, "PS0", RescaleYSubBlock, RescaleUVSubBlock, EmitYUVTileLine);
|
||||
rsp_break(hle, SP_STATUS_TASKDONE);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* JPEG decoding ucode found in Ocarina of Time, Pokemon Stadium 1 and
|
||||
* Pokemon Stadium 2.
|
||||
**************************************************************************/
|
||||
void jpeg_decode_PS()
|
||||
void jpeg_decode_PS(struct hle_t* hle)
|
||||
{
|
||||
jpeg_decode_std("PS", DecodeMacroblock2, EmitRGBATileLine);
|
||||
jpeg_decode_std(hle, "PS", NULL, NULL, EmitRGBATileLine);
|
||||
rsp_break(hle, SP_STATUS_TASKDONE);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* JPEG decoding ucode found in Ogre Battle and Bottom of the 9th.
|
||||
**************************************************************************/
|
||||
void jpeg_decode_OB()
|
||||
void jpeg_decode_OB(struct hle_t* hle)
|
||||
{
|
||||
int16_t qtable[SUBBLOCK_SIZE];
|
||||
unsigned int mb;
|
||||
|
@ -168,45 +165,43 @@ void jpeg_decode_OB()
|
|||
int32_t y_dc = 0;
|
||||
int32_t u_dc = 0;
|
||||
int32_t v_dc = 0;
|
||||
|
||||
const OSTask_t * const task = get_task();
|
||||
|
||||
uint32_t address = task->data_ptr;
|
||||
const unsigned int macroblock_count = task->data_size;
|
||||
const int qscale = task->yield_data_size;
|
||||
uint32_t address = *dmem_u32(hle, TASK_DATA_PTR);
|
||||
const unsigned int macroblock_count = *dmem_u32(hle, TASK_DATA_SIZE);
|
||||
const int qscale = *dmem_u32(hle, TASK_YIELD_DATA_SIZE);
|
||||
|
||||
DebugMessage(M64MSG_VERBOSE, "jpeg_decode_OB: *buffer=%x, #MB=%d, qscale=%d",
|
||||
address,
|
||||
macroblock_count,
|
||||
qscale);
|
||||
HleVerboseMessage(hle->user_defined,
|
||||
"jpeg_decode_OB: *buffer=%x, #MB=%d, qscale=%d",
|
||||
address,
|
||||
macroblock_count,
|
||||
qscale);
|
||||
|
||||
if (qscale != 0)
|
||||
{
|
||||
if (qscale != 0) {
|
||||
if (qscale > 0)
|
||||
{
|
||||
ScaleSubBlock(qtable, DEFAULT_QTABLE, qscale);
|
||||
}
|
||||
else
|
||||
{
|
||||
RShiftSubBlock(qtable, DEFAULT_QTABLE, -qscale);
|
||||
}
|
||||
}
|
||||
|
||||
for (mb = 0; mb < macroblock_count; ++mb)
|
||||
{
|
||||
int16_t macroblock[6*SUBBLOCK_SIZE];
|
||||
for (mb = 0; mb < macroblock_count; ++mb) {
|
||||
int16_t macroblock[6 * SUBBLOCK_SIZE];
|
||||
|
||||
rdram_read_many_u16((uint16_t*)macroblock, address, 6*SUBBLOCK_SIZE);
|
||||
DecodeMacroblock1(macroblock, &y_dc, &u_dc, &v_dc, (qscale != 0) ? qtable : NULL);
|
||||
EmitTilesMode2(EmitYUVTileLine, macroblock, address);
|
||||
dram_load_u16(hle, (uint16_t *)macroblock, address, 6 * SUBBLOCK_SIZE);
|
||||
decode_macroblock_ob(macroblock, &y_dc, &u_dc, &v_dc, (qscale != 0) ? qtable : NULL);
|
||||
EmitTilesMode2(hle, EmitYUVTileLine, macroblock, address);
|
||||
|
||||
address += (2*6*SUBBLOCK_SIZE);
|
||||
address += (2 * 6 * SUBBLOCK_SIZE);
|
||||
}
|
||||
rsp_break(hle, SP_STATUS_TASKDONE);
|
||||
}
|
||||
|
||||
|
||||
/* local functions */
|
||||
static void jpeg_decode_std(const char * const version, const std_macroblock_decoder_t decode_mb, const tile_line_emitter_t emit_line)
|
||||
static void jpeg_decode_std(struct hle_t* hle,
|
||||
const char *const version,
|
||||
const subblock_transform_t transform_luma,
|
||||
const subblock_transform_t transform_chroma,
|
||||
const tile_line_emitter_t emit_line)
|
||||
{
|
||||
int16_t qtables[3][SUBBLOCK_SIZE];
|
||||
unsigned int mb;
|
||||
|
@ -218,68 +213,59 @@ static void jpeg_decode_std(const char * const version, const std_macroblock_dec
|
|||
uint32_t qtableV_ptr;
|
||||
unsigned int subblock_count;
|
||||
unsigned int macroblock_size;
|
||||
int16_t *macroblock;
|
||||
const OSTask_t * const task = get_task();
|
||||
/* macroblock contains at most 6 subblocks */
|
||||
int16_t macroblock[6 * SUBBLOCK_SIZE];
|
||||
uint32_t data_ptr;
|
||||
|
||||
if (task->flags & 0x1)
|
||||
{
|
||||
DebugMessage(M64MSG_WARNING, "jpeg_decode_%s: task yielding not implemented", version);
|
||||
if (*dmem_u32(hle, TASK_FLAGS) & 0x1) {
|
||||
HleWarnMessage(hle->user_defined,
|
||||
"jpeg_decode_%s: task yielding not implemented", version);
|
||||
return;
|
||||
}
|
||||
|
||||
address = rdram_read_u32(task->data_ptr);
|
||||
macroblock_count = rdram_read_u32(task->data_ptr + 4);
|
||||
mode = rdram_read_u32(task->data_ptr + 8);
|
||||
qtableY_ptr = rdram_read_u32(task->data_ptr + 12);
|
||||
qtableU_ptr = rdram_read_u32(task->data_ptr + 16);
|
||||
qtableV_ptr = rdram_read_u32(task->data_ptr + 20);
|
||||
data_ptr = *dmem_u32(hle, TASK_DATA_PTR);
|
||||
address = *dram_u32(hle, data_ptr);
|
||||
macroblock_count = *dram_u32(hle, data_ptr + 4);
|
||||
mode = *dram_u32(hle, data_ptr + 8);
|
||||
qtableY_ptr = *dram_u32(hle, data_ptr + 12);
|
||||
qtableU_ptr = *dram_u32(hle, data_ptr + 16);
|
||||
qtableV_ptr = *dram_u32(hle, data_ptr + 20);
|
||||
|
||||
DebugMessage(M64MSG_VERBOSE, "jpeg_decode_%s: *buffer=%x, #MB=%d, mode=%d, *Qy=%x, *Qu=%x, *Qv=%x",
|
||||
version,
|
||||
address,
|
||||
macroblock_count,
|
||||
mode,
|
||||
qtableY_ptr,
|
||||
qtableU_ptr,
|
||||
qtableV_ptr);
|
||||
HleVerboseMessage(hle->user_defined,
|
||||
"jpeg_decode_%s: *buffer=%x, #MB=%d, mode=%d, *Qy=%x, *Qu=%x, *Qv=%x",
|
||||
version,
|
||||
address,
|
||||
macroblock_count,
|
||||
mode,
|
||||
qtableY_ptr,
|
||||
qtableU_ptr,
|
||||
qtableV_ptr);
|
||||
|
||||
if (mode != 0 && mode != 2)
|
||||
{
|
||||
DebugMessage(M64MSG_WARNING, "jpeg_decode_%s: invalid mode %d", version, mode);
|
||||
if (mode != 0 && mode != 2) {
|
||||
HleWarnMessage(hle->user_defined,
|
||||
"jpeg_decode_%s: invalid mode %d", version, mode);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
subblock_count = mode + 4;
|
||||
macroblock_size = 2*subblock_count*SUBBLOCK_SIZE;
|
||||
macroblock_size = subblock_count * SUBBLOCK_SIZE;
|
||||
|
||||
rdram_read_many_u16((uint16_t*)qtables[0], qtableY_ptr, SUBBLOCK_SIZE);
|
||||
rdram_read_many_u16((uint16_t*)qtables[1], qtableU_ptr, SUBBLOCK_SIZE);
|
||||
rdram_read_many_u16((uint16_t*)qtables[2], qtableV_ptr, SUBBLOCK_SIZE);
|
||||
dram_load_u16(hle, (uint16_t *)qtables[0], qtableY_ptr, SUBBLOCK_SIZE);
|
||||
dram_load_u16(hle, (uint16_t *)qtables[1], qtableU_ptr, SUBBLOCK_SIZE);
|
||||
dram_load_u16(hle, (uint16_t *)qtables[2], qtableV_ptr, SUBBLOCK_SIZE);
|
||||
|
||||
macroblock = malloc(sizeof(*macroblock) * macroblock_size);
|
||||
if (!macroblock)
|
||||
{
|
||||
DebugMessage(M64MSG_WARNING, "jpeg_decode_%s: could not allocate macroblock", version);
|
||||
return;
|
||||
}
|
||||
|
||||
for (mb = 0; mb < macroblock_count; ++mb)
|
||||
{
|
||||
rdram_read_many_u16((uint16_t*)macroblock, address, macroblock_size >> 1);
|
||||
decode_mb(macroblock, subblock_count, (const int16_t (*)[SUBBLOCK_SIZE])qtables);
|
||||
for (mb = 0; mb < macroblock_count; ++mb) {
|
||||
dram_load_u16(hle, (uint16_t *)macroblock, address, macroblock_size);
|
||||
decode_macroblock_std(transform_luma, transform_chroma,
|
||||
macroblock, subblock_count, (const int16_t (*)[SUBBLOCK_SIZE])qtables);
|
||||
|
||||
if (mode == 0)
|
||||
{
|
||||
EmitTilesMode0(emit_line, macroblock, address);
|
||||
}
|
||||
EmitTilesMode0(hle, emit_line, macroblock, address);
|
||||
else
|
||||
{
|
||||
EmitTilesMode2(emit_line, macroblock, address);
|
||||
}
|
||||
EmitTilesMode2(hle, emit_line, macroblock, address);
|
||||
|
||||
address += macroblock_size;
|
||||
address += 2 * macroblock_size;
|
||||
}
|
||||
free(macroblock);
|
||||
}
|
||||
|
||||
static uint8_t clamp_u8(int16_t x)
|
||||
|
@ -289,28 +275,28 @@ static uint8_t clamp_u8(int16_t x)
|
|||
|
||||
static int16_t clamp_s12(int16_t x)
|
||||
{
|
||||
if (x < -0x800) { x = -0x800; } else if (x > 0x7f0) { x = 0x7f0; }
|
||||
return x;
|
||||
}
|
||||
|
||||
static int16_t clamp_s16(int32_t x)
|
||||
{
|
||||
if (x > 32767) { x = 32767; } else if (x < -32768) { x = -32768; }
|
||||
if (x < -0x800)
|
||||
x = -0x800;
|
||||
else if (x > 0x7f0)
|
||||
x = 0x7f0;
|
||||
return x;
|
||||
}
|
||||
|
||||
static uint16_t clamp_RGBA_component(int16_t x)
|
||||
{
|
||||
if (x > 0xff0) { x = 0xff0; } else if (x < 0) { x = 0; }
|
||||
if (x > 0xff0)
|
||||
x = 0xff0;
|
||||
else if (x < 0)
|
||||
x = 0;
|
||||
return (x & 0xf80);
|
||||
}
|
||||
|
||||
static uint32_t GetUYVY(int16_t y1, int16_t y2, int16_t u, int16_t v)
|
||||
{
|
||||
return (uint32_t)clamp_u8(u) << 24
|
||||
| (uint32_t)clamp_u8(y1) << 16
|
||||
| (uint32_t)clamp_u8(v) << 8
|
||||
| (uint32_t)clamp_u8(y2);
|
||||
return (uint32_t)clamp_u8(u) << 24 |
|
||||
(uint32_t)clamp_u8(y1) << 16 |
|
||||
(uint32_t)clamp_u8(v) << 8 |
|
||||
(uint32_t)clamp_u8(y2);
|
||||
}
|
||||
|
||||
static uint16_t GetRGBA(int16_t y, int16_t u, int16_t v)
|
||||
|
@ -319,19 +305,19 @@ static uint16_t GetRGBA(int16_t y, int16_t u, int16_t v)
|
|||
const float fU = (float)u;
|
||||
const float fV = (float)v;
|
||||
|
||||
const uint16_t r = clamp_RGBA_component((int16_t)(fY + 1.4025*fV));
|
||||
const uint16_t g = clamp_RGBA_component((int16_t)(fY - 0.3443*fU - 0.7144*fV));
|
||||
const uint16_t b = clamp_RGBA_component((int16_t)(fY + 1.7729*fU ));
|
||||
const uint16_t r = clamp_RGBA_component((int16_t)(fY + 1.4025 * fV));
|
||||
const uint16_t g = clamp_RGBA_component((int16_t)(fY - 0.3443 * fU - 0.7144 * fV));
|
||||
const uint16_t b = clamp_RGBA_component((int16_t)(fY + 1.7729 * fU));
|
||||
|
||||
return (r << 4) | (g >> 1) | (b >> 6) | 1;
|
||||
}
|
||||
|
||||
static void EmitYUVTileLine(const int16_t *y, const int16_t *u, uint32_t address)
|
||||
static void EmitYUVTileLine(struct hle_t* hle, const int16_t *y, const int16_t *u, uint32_t address)
|
||||
{
|
||||
uint32_t uyvy[8];
|
||||
|
||||
const int16_t * const v = u + SUBBLOCK_SIZE;
|
||||
const int16_t * const y2 = y + SUBBLOCK_SIZE;
|
||||
const int16_t *const v = u + SUBBLOCK_SIZE;
|
||||
const int16_t *const y2 = y + SUBBLOCK_SIZE;
|
||||
|
||||
uyvy[0] = GetUYVY(y[0], y[1], u[0], v[0]);
|
||||
uyvy[1] = GetUYVY(y[2], y[3], u[1], v[1]);
|
||||
|
@ -342,15 +328,15 @@ static void EmitYUVTileLine(const int16_t *y, const int16_t *u, uint32_t address
|
|||
uyvy[6] = GetUYVY(y2[4], y2[5], u[6], v[6]);
|
||||
uyvy[7] = GetUYVY(y2[6], y2[7], u[7], v[7]);
|
||||
|
||||
rdram_write_many_u32(uyvy, address, 8);
|
||||
dram_store_u32(hle, uyvy, address, 8);
|
||||
}
|
||||
|
||||
static void EmitRGBATileLine(const int16_t *y, const int16_t *u, uint32_t address)
|
||||
static void EmitRGBATileLine(struct hle_t* hle, const int16_t *y, const int16_t *u, uint32_t address)
|
||||
{
|
||||
uint16_t rgba[16];
|
||||
|
||||
const int16_t * const v = u + SUBBLOCK_SIZE;
|
||||
const int16_t * const y2 = y + SUBBLOCK_SIZE;
|
||||
const int16_t *const v = u + SUBBLOCK_SIZE;
|
||||
const int16_t *const y2 = y + SUBBLOCK_SIZE;
|
||||
|
||||
rgba[0] = GetRGBA(y[0], u[0], v[0]);
|
||||
rgba[1] = GetRGBA(y[1], u[0], v[0]);
|
||||
|
@ -369,19 +355,18 @@ static void EmitRGBATileLine(const int16_t *y, const int16_t *u, uint32_t addres
|
|||
rgba[14] = GetRGBA(y2[6], u[7], v[7]);
|
||||
rgba[15] = GetRGBA(y2[7], u[7], v[7]);
|
||||
|
||||
rdram_write_many_u16(rgba, address, 16);
|
||||
dram_store_u16(hle, rgba, address, 16);
|
||||
}
|
||||
|
||||
static void EmitTilesMode0(const tile_line_emitter_t emit_line, const int16_t *macroblock, uint32_t address)
|
||||
static void EmitTilesMode0(struct hle_t* hle, const tile_line_emitter_t emit_line, const int16_t *macroblock, uint32_t address)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
unsigned int y_offset = 0;
|
||||
unsigned int u_offset = 2*SUBBLOCK_SIZE;
|
||||
unsigned int u_offset = 2 * SUBBLOCK_SIZE;
|
||||
|
||||
for (i = 0; i < 8; ++i)
|
||||
{
|
||||
emit_line(¯oblock[y_offset], ¯oblock[u_offset], address);
|
||||
for (i = 0; i < 8; ++i) {
|
||||
emit_line(hle, ¯oblock[y_offset], ¯oblock[u_offset], address);
|
||||
|
||||
y_offset += 8;
|
||||
u_offset += 8;
|
||||
|
@ -389,95 +374,86 @@ static void EmitTilesMode0(const tile_line_emitter_t emit_line, const int16_t *m
|
|||
}
|
||||
}
|
||||
|
||||
static void EmitTilesMode2(const tile_line_emitter_t emit_line, const int16_t *macroblock, uint32_t address)
|
||||
static void EmitTilesMode2(struct hle_t* hle, const tile_line_emitter_t emit_line, const int16_t *macroblock, uint32_t address)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
unsigned int y_offset = 0;
|
||||
unsigned int u_offset = 4*SUBBLOCK_SIZE;
|
||||
unsigned int u_offset = 4 * SUBBLOCK_SIZE;
|
||||
|
||||
for (i = 0; i < 8; ++i)
|
||||
{
|
||||
emit_line(¯oblock[y_offset], ¯oblock[u_offset], address);
|
||||
emit_line(¯oblock[y_offset + 8], ¯oblock[u_offset], address + 32);
|
||||
for (i = 0; i < 8; ++i) {
|
||||
emit_line(hle, ¯oblock[y_offset], ¯oblock[u_offset], address);
|
||||
emit_line(hle, ¯oblock[y_offset + 8], ¯oblock[u_offset], address + 32);
|
||||
|
||||
y_offset += (i == 3) ? SUBBLOCK_SIZE+16 : 16;
|
||||
y_offset += (i == 3) ? SUBBLOCK_SIZE + 16 : 16;
|
||||
u_offset += 8;
|
||||
address += 64;
|
||||
}
|
||||
}
|
||||
|
||||
static void DecodeMacroblock1(int16_t *macroblock, int32_t *y_dc, int32_t *u_dc, int32_t *v_dc, const int16_t *qtable)
|
||||
static void decode_macroblock_ob(int16_t *macroblock, int32_t *y_dc, int32_t *u_dc, int32_t *v_dc, const int16_t *qtable)
|
||||
{
|
||||
int sb;
|
||||
|
||||
for (sb = 0; sb < 6; ++sb)
|
||||
{
|
||||
for (sb = 0; sb < 6; ++sb) {
|
||||
int16_t tmp_sb[SUBBLOCK_SIZE];
|
||||
|
||||
/* update DC */
|
||||
int32_t dc = (int32_t)macroblock[0];
|
||||
switch(sb)
|
||||
{
|
||||
case 0: case 1: case 2: case 3:
|
||||
*y_dc += dc; macroblock[0] = *y_dc & 0xffff; break;
|
||||
case 4: *u_dc += dc; macroblock[0] = *u_dc & 0xffff; break;
|
||||
case 5: *v_dc += dc; macroblock[0] = *v_dc & 0xffff; break;
|
||||
switch (sb) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
*y_dc += dc;
|
||||
macroblock[0] = *y_dc & 0xffff;
|
||||
break;
|
||||
case 4:
|
||||
*u_dc += dc;
|
||||
macroblock[0] = *u_dc & 0xffff;
|
||||
break;
|
||||
case 5:
|
||||
*v_dc += dc;
|
||||
macroblock[0] = *v_dc & 0xffff;
|
||||
break;
|
||||
}
|
||||
|
||||
ZigZagSubBlock(tmp_sb, macroblock);
|
||||
if (qtable != NULL) { MultSubBlocks(tmp_sb, tmp_sb, qtable, 0); }
|
||||
if (qtable != NULL)
|
||||
MultSubBlocks(tmp_sb, tmp_sb, qtable, 0);
|
||||
TransposeSubBlock(macroblock, tmp_sb);
|
||||
InverseDCTSubBlock(macroblock, macroblock);
|
||||
|
||||
|
||||
macroblock += SUBBLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static void DecodeMacroblock2(int16_t *macroblock, unsigned int subblock_count, const int16_t qtables[3][SUBBLOCK_SIZE])
|
||||
static void decode_macroblock_std(const subblock_transform_t transform_luma,
|
||||
const subblock_transform_t transform_chroma,
|
||||
int16_t *macroblock,
|
||||
unsigned int subblock_count,
|
||||
const int16_t qtables[3][SUBBLOCK_SIZE])
|
||||
{
|
||||
unsigned int sb;
|
||||
unsigned int q = 0;
|
||||
|
||||
for (sb = 0; sb < subblock_count; ++sb)
|
||||
{
|
||||
for (sb = 0; sb < subblock_count; ++sb) {
|
||||
int16_t tmp_sb[SUBBLOCK_SIZE];
|
||||
const int isChromaSubBlock = (subblock_count - sb <= 2);
|
||||
|
||||
if (isChromaSubBlock) { ++q; }
|
||||
|
||||
MultSubBlocks(macroblock, macroblock, qtables[q], 4);
|
||||
ZigZagSubBlock(tmp_sb, macroblock);
|
||||
InverseDCTSubBlock(macroblock, tmp_sb);
|
||||
|
||||
macroblock += SUBBLOCK_SIZE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void DecodeMacroblock3(int16_t *macroblock, unsigned int subblock_count, const int16_t qtables[3][SUBBLOCK_SIZE])
|
||||
{
|
||||
unsigned int sb;
|
||||
unsigned int q = 0;
|
||||
|
||||
for (sb = 0; sb < subblock_count; ++sb)
|
||||
{
|
||||
int16_t tmp_sb[SUBBLOCK_SIZE];
|
||||
const int isChromaSubBlock = (subblock_count - sb <= 2);
|
||||
|
||||
if (isChromaSubBlock) { ++q; }
|
||||
|
||||
MultSubBlocks(macroblock, macroblock, qtables[q], 4);
|
||||
ZigZagSubBlock(tmp_sb, macroblock);
|
||||
InverseDCTSubBlock(macroblock, tmp_sb);
|
||||
|
||||
if (isChromaSubBlock)
|
||||
{
|
||||
RescaleUVSubBlock(macroblock, macroblock);
|
||||
}
|
||||
else
|
||||
{
|
||||
RescaleYSubBlock(macroblock, macroblock);
|
||||
++q;
|
||||
|
||||
MultSubBlocks(macroblock, macroblock, qtables[q], 4);
|
||||
ZigZagSubBlock(tmp_sb, macroblock);
|
||||
InverseDCTSubBlock(macroblock, tmp_sb);
|
||||
|
||||
if (isChromaSubBlock) {
|
||||
if (transform_chroma != NULL)
|
||||
transform_chroma(macroblock, macroblock);
|
||||
} else {
|
||||
if (transform_luma != NULL)
|
||||
transform_luma(macroblock, macroblock);
|
||||
}
|
||||
|
||||
macroblock += SUBBLOCK_SIZE;
|
||||
|
@ -499,20 +475,17 @@ static void ReorderSubBlock(int16_t *dst, const int16_t *src, const unsigned int
|
|||
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]];
|
||||
}
|
||||
}
|
||||
|
||||
static void MultSubBlocks(int16_t *dst, const int16_t *src1, const int16_t *src2, unsigned int shift)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < SUBBLOCK_SIZE; ++i)
|
||||
{
|
||||
for (i = 0; i < SUBBLOCK_SIZE; ++i) {
|
||||
int32_t v = src1[i] * src2[i];
|
||||
dst[i] = clamp_s16(v) << shift;
|
||||
}
|
||||
|
@ -522,8 +495,7 @@ static void ScaleSubBlock(int16_t *dst, const int16_t *src, int16_t scale)
|
|||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < SUBBLOCK_SIZE; ++i)
|
||||
{
|
||||
for (i = 0; i < SUBBLOCK_SIZE; ++i) {
|
||||
int32_t v = src[i] * scale;
|
||||
dst[i] = clamp_s16(v);
|
||||
}
|
||||
|
@ -534,9 +506,7 @@ static void RShiftSubBlock(int16_t *dst, const int16_t *src, unsigned int shift)
|
|||
unsigned int i;
|
||||
|
||||
for (i = 0; i < SUBBLOCK_SIZE; ++i)
|
||||
{
|
||||
dst[i] = src[i] >> shift;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
|
@ -545,7 +515,7 @@ static void RShiftSubBlock(int16_t *dst, const int16_t *src, unsigned int shift)
|
|||
* Implementation based on Wikipedia :
|
||||
* http://fr.wikipedia.org/wiki/Transform%C3%A9e_en_cosinus_discr%C3%A8te
|
||||
**************************************************************************/
|
||||
static void InverseDCT1D(const float * const x, float *dst, unsigned int stride)
|
||||
static void InverseDCT1D(const float *const x, float *dst, unsigned int stride)
|
||||
{
|
||||
float e[4];
|
||||
float f[4];
|
||||
|
@ -560,22 +530,29 @@ static void InverseDCT1D(const float * const x, float *dst, unsigned int stride)
|
|||
|
||||
f[0] = x[0] + x[4];
|
||||
f[1] = x[0] - x[4];
|
||||
f[2] = x26 + IDCT_K[0]*x[2];
|
||||
f[3] = x26 + IDCT_K[1]*x[6];
|
||||
f[2] = x26 + IDCT_K[0] * x[2];
|
||||
f[3] = x26 + IDCT_K[1] * x[6];
|
||||
|
||||
e[0] = x1357 + x15 + IDCT_K[4]*x[1] + x17;
|
||||
e[1] = x1357 + x37 + IDCT_K[6]*x[3] + x35;
|
||||
e[2] = x1357 + x15 + IDCT_K[5]*x[5] + x35;
|
||||
e[3] = x1357 + x37 + IDCT_K[7]*x[7] + x17;
|
||||
e[0] = x1357 + x15 + IDCT_K[4] * x[1] + x17;
|
||||
e[1] = x1357 + x37 + IDCT_K[6] * x[3] + x35;
|
||||
e[2] = x1357 + x15 + IDCT_K[5] * x[5] + x35;
|
||||
e[3] = x1357 + x37 + IDCT_K[7] * x[7] + x17;
|
||||
|
||||
*dst = f[0] + f[2] + e[0]; dst += stride;
|
||||
*dst = f[1] + f[3] + e[1]; dst += stride;
|
||||
*dst = f[1] - f[3] + e[2]; dst += stride;
|
||||
*dst = f[0] - f[2] + e[3]; dst += stride;
|
||||
*dst = f[0] - f[2] - e[3]; dst += stride;
|
||||
*dst = f[1] - f[3] - e[2]; dst += stride;
|
||||
*dst = f[1] + f[3] - e[1]; dst += stride;
|
||||
*dst = f[0] + f[2] - e[0]; dst += stride;
|
||||
*dst = f[0] + f[2] + e[0];
|
||||
dst += stride;
|
||||
*dst = f[1] + f[3] + e[1];
|
||||
dst += stride;
|
||||
*dst = f[1] - f[3] + e[2];
|
||||
dst += stride;
|
||||
*dst = f[0] - f[2] + e[3];
|
||||
dst += stride;
|
||||
*dst = f[0] - f[2] - e[3];
|
||||
dst += stride;
|
||||
*dst = f[1] - f[3] - e[2];
|
||||
dst += stride;
|
||||
*dst = f[1] + f[3] - e[1];
|
||||
dst += stride;
|
||||
*dst = f[0] + f[2] - e[0];
|
||||
}
|
||||
|
||||
static void InverseDCTSubBlock(int16_t *dst, const int16_t *src)
|
||||
|
@ -585,26 +562,20 @@ static void InverseDCTSubBlock(int16_t *dst, const int16_t *src)
|
|||
unsigned int i, j;
|
||||
|
||||
/* idct 1d on rows (+transposition) */
|
||||
for (i = 0; i < 8; ++i)
|
||||
{
|
||||
for (i = 0; i < 8; ++i) {
|
||||
for (j = 0; j < 8; ++j)
|
||||
{
|
||||
x[j] = (float)src[i*8+j];
|
||||
}
|
||||
x[j] = (float)src[i * 8 + j];
|
||||
|
||||
InverseDCT1D(x, &block[i], 8);
|
||||
}
|
||||
|
||||
/* idct 1d on columns (thanks to previous transposition) */
|
||||
for (i = 0; i < 8; ++i)
|
||||
{
|
||||
InverseDCT1D(&block[i*8], x, 1);
|
||||
for (i = 0; i < 8; ++i) {
|
||||
InverseDCT1D(&block[i * 8], x, 1);
|
||||
|
||||
/* C4 = 1 normalization implies a division by 8 */
|
||||
for (j = 0; j < 8; ++j)
|
||||
{
|
||||
dst[i+j*8] = (int16_t)x[j] >> 3;
|
||||
}
|
||||
dst[i + j * 8] = (int16_t)x[j] >> 3;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -613,9 +584,7 @@ static void RescaleYSubBlock(int16_t *dst, const int16_t *src)
|
|||
unsigned int i;
|
||||
|
||||
for (i = 0; i < SUBBLOCK_SIZE; ++i)
|
||||
{
|
||||
dst[i] = (((uint32_t)(clamp_s12(src[i]) + 0x800) * 0xdb0) >> 16) + 0x10;
|
||||
}
|
||||
}
|
||||
|
||||
static void RescaleUVSubBlock(int16_t *dst, const int16_t *src)
|
||||
|
@ -623,61 +592,6 @@ static void RescaleUVSubBlock(int16_t *dst, const int16_t *src)
|
|||
unsigned int i;
|
||||
|
||||
for (i = 0; i < SUBBLOCK_SIZE; ++i)
|
||||
{
|
||||
dst[i] = (((int)clamp_s12(src[i]) * 0xe00) >> 16) + 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* FIXME: assume presence of expansion pack */
|
||||
#define MEMMASK 0x7fffff
|
||||
|
||||
static void rdram_read_many_u16(uint16_t *dst, uint32_t address, unsigned int count)
|
||||
{
|
||||
while (count != 0)
|
||||
{
|
||||
uint16_t s = rsp.RDRAM[((address++)^S8) & MEMMASK];
|
||||
s <<= 8;
|
||||
s |= rsp.RDRAM[((address++)^S8) & MEMMASK];
|
||||
|
||||
*(dst++) = s;
|
||||
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
static void rdram_write_many_u16(const uint16_t *src, uint32_t address, unsigned int count)
|
||||
{
|
||||
while (count != 0)
|
||||
{
|
||||
rsp.RDRAM[((address++)^S8) & MEMMASK] = (uint8_t)(*src >> 8);
|
||||
rsp.RDRAM[((address++)^S8) & MEMMASK] = (uint8_t)(*(src++) & 0xff);
|
||||
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t rdram_read_u32(uint32_t address)
|
||||
{
|
||||
uint32_t r = rsp.RDRAM[((address++) ^ S8) & MEMMASK]; r <<= 8;
|
||||
r |= rsp.RDRAM[((address++) ^ S8) & MEMMASK]; r <<= 8;
|
||||
r |= rsp.RDRAM[((address++) ^ S8) & MEMMASK]; r <<= 8;
|
||||
r |= rsp.RDRAM[((address++) ^ S8) & MEMMASK];
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void rdram_write_many_u32(const uint32_t *src, uint32_t address, unsigned int count)
|
||||
{
|
||||
while (count != 0)
|
||||
{
|
||||
rsp.RDRAM[((address++)^S8) & MEMMASK] = (uint8_t)(*src >> 24);
|
||||
rsp.RDRAM[((address++)^S8) & MEMMASK] = (uint8_t)(*src >> 16);
|
||||
rsp.RDRAM[((address++)^S8) & MEMMASK] = (uint8_t)(*src >> 8);
|
||||
rsp.RDRAM[((address++)^S8) & MEMMASK] = (uint8_t)(*(src++) & 0xff);
|
||||
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,476 +0,0 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - main.c *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2012 Bobby Smiles *
|
||||
* Copyright (C) 2009 Richard Goedeken *
|
||||
* Copyright (C) 2002 Hacktarux *
|
||||
* *
|
||||
* 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 <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define M64P_PLUGIN_PROTOTYPES 1
|
||||
#include "m64p_types.h"
|
||||
#include "m64p_common.h"
|
||||
#include "m64p_plugin.h"
|
||||
#include "hle.h"
|
||||
#include "alist.h"
|
||||
#include "cicx105.h"
|
||||
#include "jpeg.h"
|
||||
|
||||
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
/* some rsp status flags */
|
||||
#define RSP_STATUS_HALT 0x1
|
||||
#define RSP_STATUS_BROKE 0x2
|
||||
#define RSP_STATUS_INTR_ON_BREAK 0x40
|
||||
#define RSP_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 void dump_binary(const char * const filename, const unsigned char * const bytes,
|
||||
unsigned int size);
|
||||
static void dump_task(const char * const filename, const OSTask_t * const task);
|
||||
|
||||
static void handle_unknown_task(unsigned int sum);
|
||||
static void handle_unknown_non_task(unsigned int sum);
|
||||
|
||||
/* global variables */
|
||||
RSP_INFO rsp;
|
||||
|
||||
/* local variables */
|
||||
static const int FORWARD_AUDIO = 0, FORWARD_GFX = 1;
|
||||
static void (*l_DebugCallback)(void *, int, const char *) = NULL;
|
||||
static void *l_DebugCallContext = NULL;
|
||||
static int l_PluginInit = 0;
|
||||
|
||||
/* local functions */
|
||||
|
||||
|
||||
/**
|
||||
* Try to figure if the RSP was launched using osSpTask* functions
|
||||
* and not run directly (in which case DMEM[0xfc0-0xfff] is meaningless).
|
||||
*
|
||||
* Previously, the ucode_size field was used to determine this,
|
||||
* but it is not robust enough (hi Pokemon Stadium !) because games could write anything
|
||||
* in this field : most ucode_boot discard the value and just use 0xf7f anyway.
|
||||
*
|
||||
* Using ucode_boot_size should be more robust in this regard.
|
||||
**/
|
||||
static int is_task()
|
||||
{
|
||||
return (get_task()->ucode_boot_size <= 0x1000);
|
||||
}
|
||||
|
||||
static void rsp_break(unsigned int setbits)
|
||||
{
|
||||
*rsp.SP_STATUS_REG |= setbits | RSP_STATUS_BROKE | RSP_STATUS_HALT;
|
||||
|
||||
if ((*rsp.SP_STATUS_REG & RSP_STATUS_INTR_ON_BREAK))
|
||||
{
|
||||
*rsp.MI_INTR_REG |= MI_INTR_SP;
|
||||
rsp.CheckInterrupts();
|
||||
}
|
||||
}
|
||||
|
||||
static void forward_gfx_task()
|
||||
{
|
||||
if (rsp.ProcessDlistList != NULL)
|
||||
{
|
||||
rsp.ProcessDlistList();
|
||||
*rsp.DPC_STATUS_REG &= ~DP_STATUS_FREEZE;
|
||||
}
|
||||
}
|
||||
|
||||
static void forward_audio_task()
|
||||
{
|
||||
if (rsp.ProcessAlistList != NULL)
|
||||
{
|
||||
rsp.ProcessAlistList();
|
||||
}
|
||||
}
|
||||
|
||||
static void show_cfb()
|
||||
{
|
||||
if (rsp.ShowCFB != NULL)
|
||||
{
|
||||
rsp.ShowCFB();
|
||||
}
|
||||
}
|
||||
|
||||
static int try_fast_audio_dispatching()
|
||||
{
|
||||
/* identify audio ucode by using the content of ucode_data */
|
||||
const OSTask_t * const task = get_task();
|
||||
const unsigned char * const udata_ptr = rsp.RDRAM + task->ucode_data;
|
||||
|
||||
if (*(unsigned int*)(udata_ptr + 0) == 0x00000001)
|
||||
{
|
||||
if (*(unsigned int*)(udata_ptr + 0x30) == 0xf0000f00)
|
||||
{
|
||||
/**
|
||||
* Many games including:
|
||||
* Super Mario 64, Diddy Kong Racing, BlastCorp, GoldenEye, ... (most common)
|
||||
**/
|
||||
alist_process_ABI1(); return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/**
|
||||
* Mario Kart / Wave Race,
|
||||
* LylatWars,
|
||||
* FZeroX,
|
||||
* Yoshi Story,
|
||||
* 1080 Snowboarding,
|
||||
* Zelda Ocarina of Time,
|
||||
* Zelda Majoras Mask / Pokemon Stadium 2,
|
||||
* Animal Crossing
|
||||
*
|
||||
* FIXME: in fact, all these games do not share the same ABI.
|
||||
* That's the reason of the workaround in ucode2.cpp with isZeldaABI and isMKABI
|
||||
**/
|
||||
alist_process_ABI2(); return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*(unsigned int*)(udata_ptr + 0x10) == 0x00000001)
|
||||
{
|
||||
/**
|
||||
* Musyx ucode found in following games:
|
||||
* RogueSquadron, ResidentEvil2, SnowCrossPolaris, TheWorldIsNotEnough,
|
||||
* RugratsInParis, NBAShowTime, HydroThunder, Tarzan,
|
||||
* GauntletLegend, Rush2049, IndianaJones, BattleForNaboo
|
||||
* TODO: implement ucode
|
||||
**/
|
||||
DebugMessage(M64MSG_WARNING, "MusyX ucode not implemented.");
|
||||
/* return 1; */
|
||||
}
|
||||
else
|
||||
{
|
||||
/**
|
||||
* Many games including:
|
||||
* Pokemon Stadium, Banjo Kazooie, Donkey Kong, Banjo Tooie, Jet Force Gemini,
|
||||
* Mickey SpeedWay USA, Perfect Dark, Conker Bad Fur Day ...
|
||||
**/
|
||||
alist_process_ABI3(); return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int try_fast_task_dispatching()
|
||||
{
|
||||
/* identify task ucode by its type */
|
||||
const OSTask_t * const task = get_task();
|
||||
|
||||
switch (task->type)
|
||||
{
|
||||
case 1: if (FORWARD_GFX) { forward_gfx_task(); return 1; } break;
|
||||
|
||||
case 2:
|
||||
if (FORWARD_AUDIO) { forward_audio_task(); return 1; }
|
||||
else if (try_fast_audio_dispatching()) { return 1; }
|
||||
break;
|
||||
|
||||
case 7: show_cfb(); return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void normal_task_dispatching()
|
||||
{
|
||||
const OSTask_t * const task = get_task();
|
||||
const unsigned int sum =
|
||||
sum_bytes(rsp.RDRAM + task->ucode, min(task->ucode_size, 0xf80) >> 1);
|
||||
|
||||
switch (sum)
|
||||
{
|
||||
/* StoreVe12: found in Zelda Ocarina of Time [misleading task->type == 4] */
|
||||
case 0x278: /* Nothing to emulate */ return;
|
||||
|
||||
/* GFX: Twintris [misleading task->type == 0] */
|
||||
case 0x212ee:
|
||||
if (FORWARD_GFX) { forward_gfx_task(); return; }
|
||||
break;
|
||||
|
||||
/* JPEG: found in Pokemon Stadium J */
|
||||
case 0x2c85a: jpeg_decode_PS0(); return;
|
||||
|
||||
/* JPEG: found in Zelda Ocarina of Time, Pokemon Stadium 1, Pokemon Stadium 2 */
|
||||
case 0x2caa6: jpeg_decode_PS(); return;
|
||||
|
||||
/* JPEG: found in Ogre Battle, Bottom of the 9th */
|
||||
case 0x130de: jpeg_decode_OB(); return;
|
||||
}
|
||||
|
||||
handle_unknown_task(sum);
|
||||
}
|
||||
|
||||
static void non_task_dispatching()
|
||||
{
|
||||
const unsigned int sum = sum_bytes(rsp.IMEM, 0x1000 >> 1);
|
||||
|
||||
switch(sum)
|
||||
{
|
||||
/* CIC x105 ucode (used during boot of CIC x105 games) */
|
||||
case 0x9e2: /* CIC 6105 */
|
||||
case 0x9f2: /* CIC 7105 */
|
||||
cicx105_ucode(); return;
|
||||
}
|
||||
|
||||
handle_unknown_non_task(sum);
|
||||
}
|
||||
|
||||
static void handle_unknown_task(unsigned int sum)
|
||||
{
|
||||
char filename[256];
|
||||
const OSTask_t * const task = get_task();
|
||||
|
||||
DebugMessage(M64MSG_WARNING, "unknown OSTask: sum %x PC:%x", sum, *rsp.SP_PC_REG);
|
||||
|
||||
sprintf(&filename[0], "task_%x.log", sum);
|
||||
dump_task(filename, task);
|
||||
|
||||
// dump ucode_boot
|
||||
sprintf(&filename[0], "ucode_boot_%x.bin", sum);
|
||||
dump_binary(filename, rsp.RDRAM + (task->ucode_boot & 0x7fffff), task->ucode_boot_size);
|
||||
|
||||
// dump ucode
|
||||
if (task->ucode != 0)
|
||||
{
|
||||
sprintf(&filename[0], "ucode_%x.bin", sum);
|
||||
dump_binary(filename, rsp.RDRAM + (task->ucode & 0x7fffff), 0xf80);
|
||||
}
|
||||
|
||||
// dump ucode_data
|
||||
if (task->ucode_data != 0)
|
||||
{
|
||||
sprintf(&filename[0], "ucode_data_%x.bin", sum);
|
||||
dump_binary(filename, rsp.RDRAM + (task->ucode_data & 0x7fffff), task->ucode_data_size);
|
||||
}
|
||||
|
||||
// dump data
|
||||
if (task->data_ptr != 0)
|
||||
{
|
||||
sprintf(&filename[0], "data_%x.bin", sum);
|
||||
dump_binary(filename, rsp.RDRAM + (task->data_ptr & 0x7fffff), task->data_size);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_unknown_non_task(unsigned int sum)
|
||||
{
|
||||
char filename[256];
|
||||
|
||||
DebugMessage(M64MSG_WARNING, "unknown RSP code: sum: %x PC:%x", sum, *rsp.SP_PC_REG);
|
||||
|
||||
// dump IMEM & DMEM for further analysis
|
||||
sprintf(&filename[0], "imem_%x.bin", sum);
|
||||
dump_binary(filename, rsp.IMEM, 0x1000);
|
||||
|
||||
sprintf(&filename[0], "dmem_%x.bin", sum);
|
||||
dump_binary(filename, rsp.DMEM, 0x1000);
|
||||
}
|
||||
|
||||
|
||||
/* Global functions */
|
||||
void DebugMessage(int level, const char *message, ...)
|
||||
{
|
||||
char msgbuf[1024];
|
||||
va_list args;
|
||||
|
||||
if (l_DebugCallback == NULL)
|
||||
return;
|
||||
|
||||
va_start(args, message);
|
||||
vsprintf(msgbuf, message, args);
|
||||
|
||||
(*l_DebugCallback)(l_DebugCallContext, level, msgbuf);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* DLL-exported functions */
|
||||
EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Context,
|
||||
void (*DebugCallback)(void *, int, const char *))
|
||||
{
|
||||
if (l_PluginInit)
|
||||
return M64ERR_ALREADY_INIT;
|
||||
|
||||
/* first thing is to set the callback function for debug info */
|
||||
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 */
|
||||
|
||||
l_PluginInit = 1;
|
||||
return M64ERR_SUCCESS;
|
||||
}
|
||||
|
||||
EXPORT m64p_error CALL PluginShutdown(void)
|
||||
{
|
||||
if (!l_PluginInit)
|
||||
return M64ERR_NOT_INIT;
|
||||
|
||||
/* reset some local variable */
|
||||
l_DebugCallback = NULL;
|
||||
l_DebugCallContext = NULL;
|
||||
|
||||
l_PluginInit = 0;
|
||||
return M64ERR_SUCCESS;
|
||||
}
|
||||
|
||||
EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities)
|
||||
{
|
||||
/* set version info */
|
||||
if (PluginType != NULL)
|
||||
*PluginType = M64PLUGIN_RSP;
|
||||
|
||||
if (PluginVersion != NULL)
|
||||
*PluginVersion = RSP_HLE_VERSION;
|
||||
|
||||
if (APIVersion != NULL)
|
||||
*APIVersion = RSP_PLUGIN_API_VERSION;
|
||||
|
||||
if (PluginNamePtr != NULL)
|
||||
*PluginNamePtr = "Hacktarux/Azimer High-Level Emulation RSP Plugin";
|
||||
|
||||
if (Capabilities != NULL)
|
||||
{
|
||||
*Capabilities = 0;
|
||||
}
|
||||
|
||||
return M64ERR_SUCCESS;
|
||||
}
|
||||
|
||||
EXPORT unsigned int CALL DoRspCycles(unsigned int Cycles)
|
||||
{
|
||||
if (is_task())
|
||||
{
|
||||
if (!try_fast_task_dispatching()) { normal_task_dispatching(); }
|
||||
rsp_break(RSP_STATUS_TASKDONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
non_task_dispatching();
|
||||
rsp_break(0);
|
||||
}
|
||||
|
||||
return Cycles;
|
||||
}
|
||||
|
||||
EXPORT void CALL InitiateRSP(RSP_INFO Rsp_Info, unsigned int *CycleCount)
|
||||
{
|
||||
rsp = Rsp_Info;
|
||||
}
|
||||
|
||||
EXPORT void CALL RomClosed(void)
|
||||
{
|
||||
memset(rsp.DMEM, 0, 0x1000);
|
||||
memset(rsp.IMEM, 0, 0x1000);
|
||||
|
||||
init_ucode2();
|
||||
}
|
||||
|
||||
|
||||
/* local helper functions */
|
||||
static unsigned int sum_bytes(const unsigned char *bytes, unsigned int size)
|
||||
{
|
||||
unsigned int sum = 0;
|
||||
const unsigned char * const bytes_end = bytes + size;
|
||||
|
||||
while (bytes != bytes_end)
|
||||
sum += *bytes++;
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
||||
static void dump_binary(const char * const filename, const unsigned char * const bytes,
|
||||
unsigned int size)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
// if file already exists, do nothing
|
||||
f = fopen(filename, "r");
|
||||
if (f == NULL)
|
||||
{
|
||||
// else we write bytes to the file
|
||||
f= fopen(filename, "wb");
|
||||
if (f != NULL) {
|
||||
if (fwrite(bytes, 1, size, f) != size)
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "Writing error on %s", filename);
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "Couldn't open %s for writing !", filename);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_task(const char * const filename, const OSTask_t * const task)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
f = fopen(filename, "r");
|
||||
if (f == NULL)
|
||||
{
|
||||
f = fopen(filename, "w");
|
||||
fprintf(f,
|
||||
"type = %d\n"
|
||||
"flags = %d\n"
|
||||
"ucode_boot = %#08x size = %#x\n"
|
||||
"ucode = %#08x size = %#x\n"
|
||||
"ucode_data = %#08x size = %#x\n"
|
||||
"dram_stack = %#08x size = %#x\n"
|
||||
"output_buff = %#08x *size = %#x\n"
|
||||
"data = %#08x size = %#x\n"
|
||||
"yield_data = %#08x size = %#x\n",
|
||||
task->type, task->flags,
|
||||
task->ucode_boot, task->ucode_boot_size,
|
||||
task->ucode, task->ucode_size,
|
||||
task->ucode_data, task->ucode_data_size,
|
||||
task->dram_stack, task->dram_stack_size,
|
||||
task->output_buff, task->output_buff_size,
|
||||
task->data_ptr, task->data_size,
|
||||
task->yield_data_ptr, task->yield_data_size);
|
||||
fclose(f);
|
||||
}
|
||||
else
|
||||
{
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - memory.c *
|
||||
* Mupen64Plus homepage: https://mupen64plus.org/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* *
|
||||
* 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 <string.h>
|
||||
|
||||
#include "memory.h"
|
||||
|
||||
/* Global functions */
|
||||
void load_u8(uint8_t* dst, const unsigned char* buffer, unsigned address, size_t count)
|
||||
{
|
||||
while (count != 0) {
|
||||
*(dst++) = *u8(buffer, address);
|
||||
address += 1;
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
void load_u16(uint16_t* dst, const unsigned char* buffer, unsigned address, size_t count)
|
||||
{
|
||||
while (count != 0) {
|
||||
*(dst++) = *u16(buffer, address);
|
||||
address += 2;
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
void load_u32(uint32_t* dst, const unsigned char* buffer, unsigned address, size_t count)
|
||||
{
|
||||
/* Optimization for uint32_t */
|
||||
memcpy(dst, u32(buffer, address), count * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
void store_u8(unsigned char* buffer, unsigned address, const uint8_t* src, size_t count)
|
||||
{
|
||||
while (count != 0) {
|
||||
*u8(buffer, address) = *(src++);
|
||||
address += 1;
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
void store_u16(unsigned char* buffer, unsigned address, const uint16_t* src, size_t count)
|
||||
{
|
||||
while (count != 0) {
|
||||
*u16(buffer, address) = *(src++);
|
||||
address += 2;
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
void store_u32(unsigned char* buffer, unsigned address, const uint32_t* src, size_t count)
|
||||
{
|
||||
/* Optimization for uint32_t */
|
||||
memcpy(u32(buffer, address), src, count * sizeof(uint32_t));
|
||||
}
|
||||
|
|
@ -0,0 +1,185 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - memory.h *
|
||||
* Mupen64Plus homepage: https://mupen64plus.org/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* *
|
||||
* 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. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef MEMORY_H
|
||||
#define MEMORY_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "hle_internal.h"
|
||||
|
||||
#ifdef M64P_BIG_ENDIAN
|
||||
#define S 0
|
||||
#define S16 0
|
||||
#define S8 0
|
||||
#else
|
||||
#define S 1
|
||||
#define S16 2
|
||||
#define S8 3
|
||||
#endif
|
||||
|
||||
enum {
|
||||
TASK_TYPE = 0xfc0,
|
||||
TASK_FLAGS = 0xfc4,
|
||||
TASK_UCODE_BOOT = 0xfc8,
|
||||
TASK_UCODE_BOOT_SIZE = 0xfcc,
|
||||
TASK_UCODE = 0xfd0,
|
||||
TASK_UCODE_SIZE = 0xfd4,
|
||||
TASK_UCODE_DATA = 0xfd8,
|
||||
TASK_UCODE_DATA_SIZE = 0xfdc,
|
||||
TASK_DRAM_STACK = 0xfe0,
|
||||
TASK_DRAM_STACK_SIZE = 0xfe4,
|
||||
TASK_OUTPUT_BUFF = 0xfe8,
|
||||
TASK_OUTPUT_BUFF_SIZE = 0xfec,
|
||||
TASK_DATA_PTR = 0xff0,
|
||||
TASK_DATA_SIZE = 0xff4,
|
||||
TASK_YIELD_DATA_PTR = 0xff8,
|
||||
TASK_YIELD_DATA_SIZE = 0xffc
|
||||
};
|
||||
|
||||
static inline unsigned int align(unsigned int x, unsigned amount)
|
||||
{
|
||||
--amount;
|
||||
return (x + amount) & ~amount;
|
||||
}
|
||||
|
||||
static inline uint8_t* u8(const unsigned char* buffer, unsigned address)
|
||||
{
|
||||
return (uint8_t*)(buffer + (address ^ S8));
|
||||
}
|
||||
|
||||
static inline uint16_t* u16(const unsigned char* buffer, unsigned address)
|
||||
{
|
||||
assert((address & 1) == 0);
|
||||
return (uint16_t*)(buffer + (address ^ S16));
|
||||
}
|
||||
|
||||
static inline uint32_t* u32(const unsigned char* buffer, unsigned address)
|
||||
{
|
||||
assert((address & 3) == 0);
|
||||
return (uint32_t*)(buffer + address);
|
||||
}
|
||||
|
||||
void load_u8 (uint8_t* dst, const unsigned char* buffer, unsigned address, size_t count);
|
||||
void load_u16(uint16_t* dst, const unsigned char* buffer, unsigned address, size_t count);
|
||||
void load_u32(uint32_t* dst, const unsigned char* buffer, unsigned address, size_t count);
|
||||
void store_u8 (unsigned char* buffer, unsigned address, const uint8_t* src, size_t count);
|
||||
void store_u16(unsigned char* buffer, unsigned address, const uint16_t* src, size_t count);
|
||||
void store_u32(unsigned char* buffer, unsigned address, const uint32_t* src, size_t count);
|
||||
|
||||
|
||||
/* convenient functions for DMEM access */
|
||||
static inline uint8_t* dmem_u8(struct hle_t* hle, uint16_t address)
|
||||
{
|
||||
return u8(hle->dmem, address & 0xfff);
|
||||
}
|
||||
|
||||
static inline uint16_t* dmem_u16(struct hle_t* hle, uint16_t address)
|
||||
{
|
||||
return u16(hle->dmem, address & 0xfff);
|
||||
}
|
||||
|
||||
static inline uint32_t* dmem_u32(struct hle_t* hle, uint16_t address)
|
||||
{
|
||||
return u32(hle->dmem, address & 0xfff);
|
||||
}
|
||||
|
||||
static inline void dmem_load_u8(struct hle_t* hle, uint8_t* dst, uint16_t address, size_t count)
|
||||
{
|
||||
load_u8(dst, hle->dmem, address & 0xfff, count);
|
||||
}
|
||||
|
||||
static inline void dmem_load_u16(struct hle_t* hle, uint16_t* dst, uint16_t address, size_t count)
|
||||
{
|
||||
load_u16(dst, hle->dmem, address & 0xfff, count);
|
||||
}
|
||||
|
||||
static inline void dmem_load_u32(struct hle_t* hle, uint32_t* dst, uint16_t address, size_t count)
|
||||
{
|
||||
load_u32(dst, hle->dmem, address & 0xfff, count);
|
||||
}
|
||||
|
||||
static inline void dmem_store_u8(struct hle_t* hle, const uint8_t* src, uint16_t address, size_t count)
|
||||
{
|
||||
store_u8(hle->dmem, address & 0xfff, src, count);
|
||||
}
|
||||
|
||||
static inline void dmem_store_u16(struct hle_t* hle, const uint16_t* src, uint16_t address, size_t count)
|
||||
{
|
||||
store_u16(hle->dmem, address & 0xfff, src, count);
|
||||
}
|
||||
|
||||
static inline void dmem_store_u32(struct hle_t* hle, const uint32_t* src, uint16_t address, size_t count)
|
||||
{
|
||||
store_u32(hle->dmem, address & 0xfff, src, count);
|
||||
}
|
||||
|
||||
/* convenient functions DRAM access */
|
||||
static inline uint8_t* dram_u8(struct hle_t* hle, uint32_t address)
|
||||
{
|
||||
return u8(hle->dram, address & 0xffffff);
|
||||
}
|
||||
|
||||
static inline uint16_t* dram_u16(struct hle_t* hle, uint32_t address)
|
||||
{
|
||||
return u16(hle->dram, address & 0xffffff);
|
||||
}
|
||||
|
||||
static inline uint32_t* dram_u32(struct hle_t* hle, uint32_t address)
|
||||
{
|
||||
return u32(hle->dram, address & 0xffffff);
|
||||
}
|
||||
|
||||
static inline void dram_load_u8(struct hle_t* hle, uint8_t* dst, uint32_t address, size_t count)
|
||||
{
|
||||
load_u8(dst, hle->dram, address & 0xffffff, count);
|
||||
}
|
||||
|
||||
static inline void dram_load_u16(struct hle_t* hle, uint16_t* dst, uint32_t address, size_t count)
|
||||
{
|
||||
load_u16(dst, hle->dram, address & 0xffffff, count);
|
||||
}
|
||||
|
||||
static inline void dram_load_u32(struct hle_t* hle, uint32_t* dst, uint32_t address, size_t count)
|
||||
{
|
||||
load_u32(dst, hle->dram, address & 0xffffff, count);
|
||||
}
|
||||
|
||||
static inline void dram_store_u8(struct hle_t* hle, const uint8_t* src, uint32_t address, size_t count)
|
||||
{
|
||||
store_u8(hle->dram, address & 0xffffff, src, count);
|
||||
}
|
||||
|
||||
static inline void dram_store_u16(struct hle_t* hle, const uint16_t* src, uint32_t address, size_t count)
|
||||
{
|
||||
store_u16(hle->dram, address & 0xffffff, src, count);
|
||||
}
|
||||
|
||||
static inline void dram_store_u32(struct hle_t* hle, const uint32_t* src, uint32_t address, size_t count)
|
||||
{
|
||||
store_u32(hle->dram, address & 0xffffff, src, count);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,684 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - mp3.c *
|
||||
* Mupen64Plus homepage: https://mupen64plus.org/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* Copyright (C) 2009 Richard Goedeken *
|
||||
* Copyright (C) 2002 Hacktarux *
|
||||
* *
|
||||
* 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 <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "arithmetics.h"
|
||||
#include "hle_internal.h"
|
||||
#include "memory.h"
|
||||
|
||||
static void InnerLoop(struct hle_t* hle,
|
||||
uint32_t outPtr, uint32_t inPtr,
|
||||
uint32_t t6, uint32_t t5, uint32_t t4);
|
||||
|
||||
static const uint16_t DeWindowLUT [0x420] = {
|
||||
0x0000, 0xFFF3, 0x005D, 0xFF38, 0x037A, 0xF736, 0x0B37, 0xC00E,
|
||||
0x7FFF, 0x3FF2, 0x0B37, 0x08CA, 0x037A, 0x00C8, 0x005D, 0x000D,
|
||||
0x0000, 0xFFF3, 0x005D, 0xFF38, 0x037A, 0xF736, 0x0B37, 0xC00E,
|
||||
0x7FFF, 0x3FF2, 0x0B37, 0x08CA, 0x037A, 0x00C8, 0x005D, 0x000D,
|
||||
0x0000, 0xFFF2, 0x005F, 0xFF1D, 0x0369, 0xF697, 0x0A2A, 0xBCE7,
|
||||
0x7FEB, 0x3CCB, 0x0C2B, 0x082B, 0x0385, 0x00AF, 0x005B, 0x000B,
|
||||
0x0000, 0xFFF2, 0x005F, 0xFF1D, 0x0369, 0xF697, 0x0A2A, 0xBCE7,
|
||||
0x7FEB, 0x3CCB, 0x0C2B, 0x082B, 0x0385, 0x00AF, 0x005B, 0x000B,
|
||||
0x0000, 0xFFF1, 0x0061, 0xFF02, 0x0354, 0xF5F9, 0x0905, 0xB9C4,
|
||||
0x7FB0, 0x39A4, 0x0D08, 0x078C, 0x038C, 0x0098, 0x0058, 0x000A,
|
||||
0x0000, 0xFFF1, 0x0061, 0xFF02, 0x0354, 0xF5F9, 0x0905, 0xB9C4,
|
||||
0x7FB0, 0x39A4, 0x0D08, 0x078C, 0x038C, 0x0098, 0x0058, 0x000A,
|
||||
0x0000, 0xFFEF, 0x0062, 0xFEE6, 0x033B, 0xF55C, 0x07C8, 0xB6A4,
|
||||
0x7F4D, 0x367E, 0x0DCE, 0x06EE, 0x038F, 0x0080, 0x0056, 0x0009,
|
||||
0x0000, 0xFFEF, 0x0062, 0xFEE6, 0x033B, 0xF55C, 0x07C8, 0xB6A4,
|
||||
0x7F4D, 0x367E, 0x0DCE, 0x06EE, 0x038F, 0x0080, 0x0056, 0x0009,
|
||||
0x0000, 0xFFEE, 0x0063, 0xFECA, 0x031C, 0xF4C3, 0x0671, 0xB38C,
|
||||
0x7EC2, 0x335D, 0x0E7C, 0x0652, 0x038E, 0x006B, 0x0053, 0x0008,
|
||||
0x0000, 0xFFEE, 0x0063, 0xFECA, 0x031C, 0xF4C3, 0x0671, 0xB38C,
|
||||
0x7EC2, 0x335D, 0x0E7C, 0x0652, 0x038E, 0x006B, 0x0053, 0x0008,
|
||||
0x0000, 0xFFEC, 0x0064, 0xFEAC, 0x02F7, 0xF42C, 0x0502, 0xB07C,
|
||||
0x7E12, 0x3041, 0x0F14, 0x05B7, 0x038A, 0x0056, 0x0050, 0x0007,
|
||||
0x0000, 0xFFEC, 0x0064, 0xFEAC, 0x02F7, 0xF42C, 0x0502, 0xB07C,
|
||||
0x7E12, 0x3041, 0x0F14, 0x05B7, 0x038A, 0x0056, 0x0050, 0x0007,
|
||||
0x0000, 0xFFEB, 0x0064, 0xFE8E, 0x02CE, 0xF399, 0x037A, 0xAD75,
|
||||
0x7D3A, 0x2D2C, 0x0F97, 0x0520, 0x0382, 0x0043, 0x004D, 0x0007,
|
||||
0x0000, 0xFFEB, 0x0064, 0xFE8E, 0x02CE, 0xF399, 0x037A, 0xAD75,
|
||||
0x7D3A, 0x2D2C, 0x0F97, 0x0520, 0x0382, 0x0043, 0x004D, 0x0007,
|
||||
0xFFFF, 0xFFE9, 0x0063, 0xFE6F, 0x029E, 0xF30B, 0x01D8, 0xAA7B,
|
||||
0x7C3D, 0x2A1F, 0x1004, 0x048B, 0x0377, 0x0030, 0x004A, 0x0006,
|
||||
0xFFFF, 0xFFE9, 0x0063, 0xFE6F, 0x029E, 0xF30B, 0x01D8, 0xAA7B,
|
||||
0x7C3D, 0x2A1F, 0x1004, 0x048B, 0x0377, 0x0030, 0x004A, 0x0006,
|
||||
0xFFFF, 0xFFE7, 0x0062, 0xFE4F, 0x0269, 0xF282, 0x001F, 0xA78D,
|
||||
0x7B1A, 0x271C, 0x105D, 0x03F9, 0x036A, 0x001F, 0x0046, 0x0006,
|
||||
0xFFFF, 0xFFE7, 0x0062, 0xFE4F, 0x0269, 0xF282, 0x001F, 0xA78D,
|
||||
0x7B1A, 0x271C, 0x105D, 0x03F9, 0x036A, 0x001F, 0x0046, 0x0006,
|
||||
0xFFFF, 0xFFE4, 0x0061, 0xFE2F, 0x022F, 0xF1FF, 0xFE4C, 0xA4AF,
|
||||
0x79D3, 0x2425, 0x10A2, 0x036C, 0x0359, 0x0010, 0x0043, 0x0005,
|
||||
0xFFFF, 0xFFE4, 0x0061, 0xFE2F, 0x022F, 0xF1FF, 0xFE4C, 0xA4AF,
|
||||
0x79D3, 0x2425, 0x10A2, 0x036C, 0x0359, 0x0010, 0x0043, 0x0005,
|
||||
0xFFFF, 0xFFE2, 0x005E, 0xFE10, 0x01EE, 0xF184, 0xFC61, 0xA1E1,
|
||||
0x7869, 0x2139, 0x10D3, 0x02E3, 0x0346, 0x0001, 0x0040, 0x0004,
|
||||
0xFFFF, 0xFFE2, 0x005E, 0xFE10, 0x01EE, 0xF184, 0xFC61, 0xA1E1,
|
||||
0x7869, 0x2139, 0x10D3, 0x02E3, 0x0346, 0x0001, 0x0040, 0x0004,
|
||||
0xFFFF, 0xFFE0, 0x005B, 0xFDF0, 0x01A8, 0xF111, 0xFA5F, 0x9F27,
|
||||
0x76DB, 0x1E5C, 0x10F2, 0x025E, 0x0331, 0xFFF3, 0x003D, 0x0004,
|
||||
0xFFFF, 0xFFE0, 0x005B, 0xFDF0, 0x01A8, 0xF111, 0xFA5F, 0x9F27,
|
||||
0x76DB, 0x1E5C, 0x10F2, 0x025E, 0x0331, 0xFFF3, 0x003D, 0x0004,
|
||||
0xFFFF, 0xFFDE, 0x0057, 0xFDD0, 0x015B, 0xF0A7, 0xF845, 0x9C80,
|
||||
0x752C, 0x1B8E, 0x1100, 0x01DE, 0x0319, 0xFFE7, 0x003A, 0x0003,
|
||||
0xFFFF, 0xFFDE, 0x0057, 0xFDD0, 0x015B, 0xF0A7, 0xF845, 0x9C80,
|
||||
0x752C, 0x1B8E, 0x1100, 0x01DE, 0x0319, 0xFFE7, 0x003A, 0x0003,
|
||||
0xFFFE, 0xFFDB, 0x0053, 0xFDB0, 0x0108, 0xF046, 0xF613, 0x99EE,
|
||||
0x735C, 0x18D1, 0x10FD, 0x0163, 0x0300, 0xFFDC, 0x0037, 0x0003,
|
||||
0xFFFE, 0xFFDB, 0x0053, 0xFDB0, 0x0108, 0xF046, 0xF613, 0x99EE,
|
||||
0x735C, 0x18D1, 0x10FD, 0x0163, 0x0300, 0xFFDC, 0x0037, 0x0003,
|
||||
0xFFFE, 0xFFD8, 0x004D, 0xFD90, 0x00B0, 0xEFF0, 0xF3CC, 0x9775,
|
||||
0x716C, 0x1624, 0x10EA, 0x00EE, 0x02E5, 0xFFD2, 0x0033, 0x0003,
|
||||
0xFFFE, 0xFFD8, 0x004D, 0xFD90, 0x00B0, 0xEFF0, 0xF3CC, 0x9775,
|
||||
0x716C, 0x1624, 0x10EA, 0x00EE, 0x02E5, 0xFFD2, 0x0033, 0x0003,
|
||||
0xFFFE, 0xFFD6, 0x0047, 0xFD72, 0x0051, 0xEFA6, 0xF16F, 0x9514,
|
||||
0x6F5E, 0x138A, 0x10C8, 0x007E, 0x02CA, 0xFFC9, 0x0030, 0x0003,
|
||||
0xFFFE, 0xFFD6, 0x0047, 0xFD72, 0x0051, 0xEFA6, 0xF16F, 0x9514,
|
||||
0x6F5E, 0x138A, 0x10C8, 0x007E, 0x02CA, 0xFFC9, 0x0030, 0x0003,
|
||||
0xFFFE, 0xFFD3, 0x0040, 0xFD54, 0xFFEC, 0xEF68, 0xEEFC, 0x92CD,
|
||||
0x6D33, 0x1104, 0x1098, 0x0014, 0x02AC, 0xFFC0, 0x002D, 0x0002,
|
||||
0xFFFE, 0xFFD3, 0x0040, 0xFD54, 0xFFEC, 0xEF68, 0xEEFC, 0x92CD,
|
||||
0x6D33, 0x1104, 0x1098, 0x0014, 0x02AC, 0xFFC0, 0x002D, 0x0002,
|
||||
0x0030, 0xFFC9, 0x02CA, 0x007E, 0x10C8, 0x138A, 0x6F5E, 0x9514,
|
||||
0xF16F, 0xEFA6, 0x0051, 0xFD72, 0x0047, 0xFFD6, 0xFFFE, 0x0003,
|
||||
0x0030, 0xFFC9, 0x02CA, 0x007E, 0x10C8, 0x138A, 0x6F5E, 0x9514,
|
||||
0xF16F, 0xEFA6, 0x0051, 0xFD72, 0x0047, 0xFFD6, 0xFFFE, 0x0003,
|
||||
0x0033, 0xFFD2, 0x02E5, 0x00EE, 0x10EA, 0x1624, 0x716C, 0x9775,
|
||||
0xF3CC, 0xEFF0, 0x00B0, 0xFD90, 0x004D, 0xFFD8, 0xFFFE, 0x0003,
|
||||
0x0033, 0xFFD2, 0x02E5, 0x00EE, 0x10EA, 0x1624, 0x716C, 0x9775,
|
||||
0xF3CC, 0xEFF0, 0x00B0, 0xFD90, 0x004D, 0xFFD8, 0xFFFE, 0x0003,
|
||||
0x0037, 0xFFDC, 0x0300, 0x0163, 0x10FD, 0x18D1, 0x735C, 0x99EE,
|
||||
0xF613, 0xF046, 0x0108, 0xFDB0, 0x0053, 0xFFDB, 0xFFFE, 0x0003,
|
||||
0x0037, 0xFFDC, 0x0300, 0x0163, 0x10FD, 0x18D1, 0x735C, 0x99EE,
|
||||
0xF613, 0xF046, 0x0108, 0xFDB0, 0x0053, 0xFFDB, 0xFFFE, 0x0003,
|
||||
0x003A, 0xFFE7, 0x0319, 0x01DE, 0x1100, 0x1B8E, 0x752C, 0x9C80,
|
||||
0xF845, 0xF0A7, 0x015B, 0xFDD0, 0x0057, 0xFFDE, 0xFFFF, 0x0003,
|
||||
0x003A, 0xFFE7, 0x0319, 0x01DE, 0x1100, 0x1B8E, 0x752C, 0x9C80,
|
||||
0xF845, 0xF0A7, 0x015B, 0xFDD0, 0x0057, 0xFFDE, 0xFFFF, 0x0004,
|
||||
0x003D, 0xFFF3, 0x0331, 0x025E, 0x10F2, 0x1E5C, 0x76DB, 0x9F27,
|
||||
0xFA5F, 0xF111, 0x01A8, 0xFDF0, 0x005B, 0xFFE0, 0xFFFF, 0x0004,
|
||||
0x003D, 0xFFF3, 0x0331, 0x025E, 0x10F2, 0x1E5C, 0x76DB, 0x9F27,
|
||||
0xFA5F, 0xF111, 0x01A8, 0xFDF0, 0x005B, 0xFFE0, 0xFFFF, 0x0004,
|
||||
0x0040, 0x0001, 0x0346, 0x02E3, 0x10D3, 0x2139, 0x7869, 0xA1E1,
|
||||
0xFC61, 0xF184, 0x01EE, 0xFE10, 0x005E, 0xFFE2, 0xFFFF, 0x0004,
|
||||
0x0040, 0x0001, 0x0346, 0x02E3, 0x10D3, 0x2139, 0x7869, 0xA1E1,
|
||||
0xFC61, 0xF184, 0x01EE, 0xFE10, 0x005E, 0xFFE2, 0xFFFF, 0x0005,
|
||||
0x0043, 0x0010, 0x0359, 0x036C, 0x10A2, 0x2425, 0x79D3, 0xA4AF,
|
||||
0xFE4C, 0xF1FF, 0x022F, 0xFE2F, 0x0061, 0xFFE4, 0xFFFF, 0x0005,
|
||||
0x0043, 0x0010, 0x0359, 0x036C, 0x10A2, 0x2425, 0x79D3, 0xA4AF,
|
||||
0xFE4C, 0xF1FF, 0x022F, 0xFE2F, 0x0061, 0xFFE4, 0xFFFF, 0x0006,
|
||||
0x0046, 0x001F, 0x036A, 0x03F9, 0x105D, 0x271C, 0x7B1A, 0xA78D,
|
||||
0x001F, 0xF282, 0x0269, 0xFE4F, 0x0062, 0xFFE7, 0xFFFF, 0x0006,
|
||||
0x0046, 0x001F, 0x036A, 0x03F9, 0x105D, 0x271C, 0x7B1A, 0xA78D,
|
||||
0x001F, 0xF282, 0x0269, 0xFE4F, 0x0062, 0xFFE7, 0xFFFF, 0x0006,
|
||||
0x004A, 0x0030, 0x0377, 0x048B, 0x1004, 0x2A1F, 0x7C3D, 0xAA7B,
|
||||
0x01D8, 0xF30B, 0x029E, 0xFE6F, 0x0063, 0xFFE9, 0xFFFF, 0x0006,
|
||||
0x004A, 0x0030, 0x0377, 0x048B, 0x1004, 0x2A1F, 0x7C3D, 0xAA7B,
|
||||
0x01D8, 0xF30B, 0x029E, 0xFE6F, 0x0063, 0xFFE9, 0xFFFF, 0x0007,
|
||||
0x004D, 0x0043, 0x0382, 0x0520, 0x0F97, 0x2D2C, 0x7D3A, 0xAD75,
|
||||
0x037A, 0xF399, 0x02CE, 0xFE8E, 0x0064, 0xFFEB, 0x0000, 0x0007,
|
||||
0x004D, 0x0043, 0x0382, 0x0520, 0x0F97, 0x2D2C, 0x7D3A, 0xAD75,
|
||||
0x037A, 0xF399, 0x02CE, 0xFE8E, 0x0064, 0xFFEB, 0x0000, 0x0007,
|
||||
0x0050, 0x0056, 0x038A, 0x05B7, 0x0F14, 0x3041, 0x7E12, 0xB07C,
|
||||
0x0502, 0xF42C, 0x02F7, 0xFEAC, 0x0064, 0xFFEC, 0x0000, 0x0007,
|
||||
0x0050, 0x0056, 0x038A, 0x05B7, 0x0F14, 0x3041, 0x7E12, 0xB07C,
|
||||
0x0502, 0xF42C, 0x02F7, 0xFEAC, 0x0064, 0xFFEC, 0x0000, 0x0008,
|
||||
0x0053, 0x006B, 0x038E, 0x0652, 0x0E7C, 0x335D, 0x7EC2, 0xB38C,
|
||||
0x0671, 0xF4C3, 0x031C, 0xFECA, 0x0063, 0xFFEE, 0x0000, 0x0008,
|
||||
0x0053, 0x006B, 0x038E, 0x0652, 0x0E7C, 0x335D, 0x7EC2, 0xB38C,
|
||||
0x0671, 0xF4C3, 0x031C, 0xFECA, 0x0063, 0xFFEE, 0x0000, 0x0009,
|
||||
0x0056, 0x0080, 0x038F, 0x06EE, 0x0DCE, 0x367E, 0x7F4D, 0xB6A4,
|
||||
0x07C8, 0xF55C, 0x033B, 0xFEE6, 0x0062, 0xFFEF, 0x0000, 0x0009,
|
||||
0x0056, 0x0080, 0x038F, 0x06EE, 0x0DCE, 0x367E, 0x7F4D, 0xB6A4,
|
||||
0x07C8, 0xF55C, 0x033B, 0xFEE6, 0x0062, 0xFFEF, 0x0000, 0x000A,
|
||||
0x0058, 0x0098, 0x038C, 0x078C, 0x0D08, 0x39A4, 0x7FB0, 0xB9C4,
|
||||
0x0905, 0xF5F9, 0x0354, 0xFF02, 0x0061, 0xFFF1, 0x0000, 0x000A,
|
||||
0x0058, 0x0098, 0x038C, 0x078C, 0x0D08, 0x39A4, 0x7FB0, 0xB9C4,
|
||||
0x0905, 0xF5F9, 0x0354, 0xFF02, 0x0061, 0xFFF1, 0x0000, 0x000B,
|
||||
0x005B, 0x00AF, 0x0385, 0x082B, 0x0C2B, 0x3CCB, 0x7FEB, 0xBCE7,
|
||||
0x0A2A, 0xF697, 0x0369, 0xFF1D, 0x005F, 0xFFF2, 0x0000, 0x000B,
|
||||
0x005B, 0x00AF, 0x0385, 0x082B, 0x0C2B, 0x3CCB, 0x7FEB, 0xBCE7,
|
||||
0x0A2A, 0xF697, 0x0369, 0xFF1D, 0x005F, 0xFFF2, 0x0000, 0x000D,
|
||||
0x005D, 0x00C8, 0x037A, 0x08CA, 0x0B37, 0x3FF2, 0x7FFF, 0xC00E,
|
||||
0x0B37, 0xF736, 0x037A, 0xFF38, 0x005D, 0xFFF3, 0x0000, 0x000D,
|
||||
0x005D, 0x00C8, 0x037A, 0x08CA, 0x0B37, 0x3FF2, 0x7FFF, 0xC00E,
|
||||
0x0B37, 0xF736, 0x037A, 0xFF38, 0x005D, 0xFFF3, 0x0000, 0x0000
|
||||
};
|
||||
|
||||
static void MP3AB0(int32_t* v)
|
||||
{
|
||||
/* Part 2 - 100% Accurate */
|
||||
static const uint16_t LUT2[8] = {
|
||||
0xFEC4, 0xF4FA, 0xC5E4, 0xE1C4,
|
||||
0x1916, 0x4A50, 0xA268, 0x78AE
|
||||
};
|
||||
static const uint16_t LUT3[4] = { 0xFB14, 0xD4DC, 0x31F2, 0x8E3A };
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
v[16 + i] = v[0 + i] + v[8 + i];
|
||||
v[24 + i] = ((v[0 + i] - v[8 + i]) * LUT2[i]) >> 0x10;
|
||||
}
|
||||
|
||||
/* Part 3: 4-wide butterflies */
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
v[0 + i] = v[16 + i] + v[20 + i];
|
||||
v[4 + i] = ((v[16 + i] - v[20 + i]) * LUT3[i]) >> 0x10;
|
||||
|
||||
v[8 + i] = v[24 + i] + v[28 + i];
|
||||
v[12 + i] = ((v[24 + i] - v[28 + i]) * LUT3[i]) >> 0x10;
|
||||
}
|
||||
|
||||
/* Part 4: 2-wide butterflies - 100% Accurate */
|
||||
|
||||
for (i = 0; i < 16; i += 4) {
|
||||
v[16 + i] = v[0 + i] + v[2 + i];
|
||||
v[18 + i] = ((v[0 + i] - v[2 + i]) * 0xEC84) >> 0x10;
|
||||
|
||||
v[17 + i] = v[1 + i] + v[3 + i];
|
||||
v[19 + i] = ((v[1 + i] - v[3 + i]) * 0x61F8) >> 0x10;
|
||||
}
|
||||
}
|
||||
|
||||
void mp3_task(struct hle_t* hle, unsigned int index, uint32_t address)
|
||||
{
|
||||
uint32_t inPtr, outPtr;
|
||||
uint32_t t6;/* = 0x08A0; - I think these are temporary storage buffers */
|
||||
uint32_t t5;/* = 0x0AC0; */
|
||||
uint32_t t4;/* = (w1 & 0x1E); */
|
||||
|
||||
/* Initialization Code */
|
||||
uint32_t readPtr; /* s5 */
|
||||
uint32_t writePtr; /* s6 */
|
||||
uint32_t tmp;
|
||||
int cnt, cnt2;
|
||||
|
||||
/* I think these are temporary storage buffers */
|
||||
t6 = 0x08A0;
|
||||
t5 = 0x0AC0;
|
||||
t4 = index;
|
||||
|
||||
writePtr = readPtr = address;
|
||||
/* Just do that for efficiency... may remove and use directly later anyway */
|
||||
memcpy(hle->mp3_buffer + 0xCE8, hle->dram + readPtr, 8);
|
||||
/* This must be a header byte or whatnot */
|
||||
readPtr += 8;
|
||||
|
||||
for (cnt = 0; cnt < 0x480; cnt += 0x180) {
|
||||
/* DMA: 0xCF0 <- RDRAM[s5] : 0x180 */
|
||||
memcpy(hle->mp3_buffer + 0xCF0, hle->dram + readPtr, 0x180);
|
||||
inPtr = 0xCF0; /* s7 */
|
||||
outPtr = 0xE70; /* s3 */
|
||||
/* --------------- Inner Loop Start -------------------- */
|
||||
for (cnt2 = 0; cnt2 < 0x180; cnt2 += 0x40) {
|
||||
t6 &= 0xFFE0;
|
||||
t5 &= 0xFFE0;
|
||||
t6 |= t4;
|
||||
t5 |= t4;
|
||||
InnerLoop(hle, outPtr, inPtr, t6, t5, t4);
|
||||
t4 = (t4 - 2) & 0x1E;
|
||||
tmp = t6;
|
||||
t6 = t5;
|
||||
t5 = tmp;
|
||||
inPtr += 0x40;
|
||||
outPtr += 0x40;
|
||||
}
|
||||
/* --------------- Inner Loop End -------------------- */
|
||||
memcpy(hle->dram + writePtr, hle->mp3_buffer + 0xe70, 0x180);
|
||||
writePtr += 0x180;
|
||||
readPtr += 0x180;
|
||||
}
|
||||
}
|
||||
|
||||
static void InnerLoop(struct hle_t* hle,
|
||||
uint32_t outPtr, uint32_t inPtr,
|
||||
uint32_t t6, uint32_t t5, uint32_t t4)
|
||||
{
|
||||
/* Part 1: 100% Accurate */
|
||||
|
||||
/* 0, 1, 3, 2, 7, 6, 4, 5, 7, 6, 4, 5, 0, 1, 3, 2 */
|
||||
static const uint16_t LUT6[16] = {
|
||||
0xFFB2, 0xFD3A, 0xF10A, 0xF854,
|
||||
0xBDAE, 0xCDA0, 0xE76C, 0xDB94,
|
||||
0x1920, 0x4B20, 0xAC7C, 0x7C68,
|
||||
0xABEC, 0x9880, 0xDAE8, 0x839C
|
||||
};
|
||||
int i;
|
||||
uint32_t t0;
|
||||
uint32_t t1;
|
||||
uint32_t t2;
|
||||
uint32_t t3;
|
||||
int32_t v2 = 0, v4 = 0, v6 = 0, v8 = 0;
|
||||
uint32_t offset;
|
||||
uint32_t addptr;
|
||||
int x;
|
||||
int32_t mult6;
|
||||
int32_t mult4;
|
||||
int tmp;
|
||||
int32_t hi0;
|
||||
int32_t hi1;
|
||||
int32_t vt;
|
||||
int32_t v[32];
|
||||
|
||||
v[0] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x00 ^ S16));
|
||||
v[31] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x3E ^ S16));
|
||||
v[0] += v[31];
|
||||
v[1] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x02 ^ S16));
|
||||
v[30] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x3C ^ S16));
|
||||
v[1] += v[30];
|
||||
v[2] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x06 ^ S16));
|
||||
v[28] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x38 ^ S16));
|
||||
v[2] += v[28];
|
||||
v[3] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x04 ^ S16));
|
||||
v[29] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x3A ^ S16));
|
||||
v[3] += v[29];
|
||||
|
||||
v[4] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x0E ^ S16));
|
||||
v[24] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x30 ^ S16));
|
||||
v[4] += v[24];
|
||||
v[5] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x0C ^ S16));
|
||||
v[25] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x32 ^ S16));
|
||||
v[5] += v[25];
|
||||
v[6] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x08 ^ S16));
|
||||
v[27] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x36 ^ S16));
|
||||
v[6] += v[27];
|
||||
v[7] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x0A ^ S16));
|
||||
v[26] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x34 ^ S16));
|
||||
v[7] += v[26];
|
||||
|
||||
v[8] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x1E ^ S16));
|
||||
v[16] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x20 ^ S16));
|
||||
v[8] += v[16];
|
||||
v[9] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x1C ^ S16));
|
||||
v[17] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x22 ^ S16));
|
||||
v[9] += v[17];
|
||||
v[10] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x18 ^ S16));
|
||||
v[19] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x26 ^ S16));
|
||||
v[10] += v[19];
|
||||
v[11] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x1A ^ S16));
|
||||
v[18] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x24 ^ S16));
|
||||
v[11] += v[18];
|
||||
|
||||
v[12] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x10 ^ S16));
|
||||
v[23] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x2E ^ S16));
|
||||
v[12] += v[23];
|
||||
v[13] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x12 ^ S16));
|
||||
v[22] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x2C ^ S16));
|
||||
v[13] += v[22];
|
||||
v[14] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x16 ^ S16));
|
||||
v[20] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x28 ^ S16));
|
||||
v[14] += v[20];
|
||||
v[15] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x14 ^ S16));
|
||||
v[21] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x2A ^ S16));
|
||||
v[15] += v[21];
|
||||
|
||||
/* Part 2-4 */
|
||||
|
||||
MP3AB0(v);
|
||||
|
||||
/* Part 5 - 1-Wide Butterflies - 100% Accurate but need SSVs!!! */
|
||||
|
||||
t0 = t6 + 0x100;
|
||||
t1 = t6 + 0x200;
|
||||
t2 = t5 + 0x100;
|
||||
t3 = t5 + 0x200;
|
||||
|
||||
/* 0x13A8 */
|
||||
v[1] = 0;
|
||||
v[11] = ((v[16] - v[17]) * 0xB504) >> 0x10;
|
||||
|
||||
v[16] = -v[16] - v[17];
|
||||
v[2] = v[18] + v[19];
|
||||
/* ** Store v[11] -> (T6 + 0)** */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t6 + (short)0x0))) = (short)v[11];
|
||||
|
||||
|
||||
v[11] = -v[11];
|
||||
/* ** Store v[16] -> (T3 + 0)** */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t3 + (short)0x0))) = (short)v[16];
|
||||
/* ** Store v[11] -> (T5 + 0)** */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t5 + (short)0x0))) = (short)v[11];
|
||||
/* 0x13E8 - Verified.... */
|
||||
v[2] = -v[2];
|
||||
/* ** Store v[2] -> (T2 + 0)** */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t2 + (short)0x0))) = (short)v[2];
|
||||
v[3] = (((v[18] - v[19]) * 0x16A09) >> 0x10) + v[2];
|
||||
/* ** Store v[3] -> (T0 + 0)** */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t0 + (short)0x0))) = (short)v[3];
|
||||
/* 0x1400 - Verified */
|
||||
v[4] = -v[20] - v[21];
|
||||
v[6] = v[22] + v[23];
|
||||
v[5] = ((v[20] - v[21]) * 0x16A09) >> 0x10;
|
||||
/* ** Store v[4] -> (T3 + 0xFF80) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t3 + (short)0xFF80))) = (short)v[4];
|
||||
v[7] = ((v[22] - v[23]) * 0x2D413) >> 0x10;
|
||||
v[5] = v[5] - v[4];
|
||||
v[7] = v[7] - v[5];
|
||||
v[6] = v[6] + v[6];
|
||||
v[5] = v[5] - v[6];
|
||||
v[4] = -v[4] - v[6];
|
||||
/* *** Store v[7] -> (T1 + 0xFF80) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t1 + (short)0xFF80))) = (short)v[7];
|
||||
/* *** Store v[4] -> (T2 + 0xFF80) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t2 + (short)0xFF80))) = (short)v[4];
|
||||
/* *** Store v[5] -> (T0 + 0xFF80) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t0 + (short)0xFF80))) = (short)v[5];
|
||||
v[8] = v[24] + v[25];
|
||||
|
||||
|
||||
v[9] = ((v[24] - v[25]) * 0x16A09) >> 0x10;
|
||||
v[2] = v[8] + v[9];
|
||||
v[11] = ((v[26] - v[27]) * 0x2D413) >> 0x10;
|
||||
v[13] = ((v[28] - v[29]) * 0x2D413) >> 0x10;
|
||||
|
||||
v[10] = v[26] + v[27];
|
||||
v[10] = v[10] + v[10];
|
||||
v[12] = v[28] + v[29];
|
||||
v[12] = v[12] + v[12];
|
||||
v[14] = v[30] + v[31];
|
||||
v[3] = v[8] + v[10];
|
||||
v[14] = v[14] + v[14];
|
||||
v[13] = (v[13] - v[2]) + v[12];
|
||||
v[15] = (((v[30] - v[31]) * 0x5A827) >> 0x10) - (v[11] + v[2]);
|
||||
v[14] = -(v[14] + v[14]) + v[3];
|
||||
v[17] = v[13] - v[10];
|
||||
v[9] = v[9] + v[14];
|
||||
/* ** Store v[9] -> (T6 + 0x40) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t6 + (short)0x40))) = (short)v[9];
|
||||
v[11] = v[11] - v[13];
|
||||
/* ** Store v[17] -> (T0 + 0xFFC0) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t0 + (short)0xFFC0))) = (short)v[17];
|
||||
v[12] = v[8] - v[12];
|
||||
/* ** Store v[11] -> (T0 + 0x40) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t0 + (short)0x40))) = (short)v[11];
|
||||
v[8] = -v[8];
|
||||
/* ** Store v[15] -> (T1 + 0xFFC0) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t1 + (short)0xFFC0))) = (short)v[15];
|
||||
v[10] = -v[10] - v[12];
|
||||
/* ** Store v[12] -> (T2 + 0x40) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t2 + (short)0x40))) = (short)v[12];
|
||||
/* ** Store v[8] -> (T3 + 0xFFC0) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t3 + (short)0xFFC0))) = (short)v[8];
|
||||
/* ** Store v[14] -> (T5 + 0x40) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t5 + (short)0x40))) = (short)v[14];
|
||||
/* ** Store v[10] -> (T2 + 0xFFC0) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t2 + (short)0xFFC0))) = (short)v[10];
|
||||
/* 0x14FC - Verified... */
|
||||
|
||||
/* Part 6 - 100% Accurate */
|
||||
|
||||
v[0] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x00 ^ S16));
|
||||
v[31] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x3E ^ S16));
|
||||
v[0] -= v[31];
|
||||
v[1] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x02 ^ S16));
|
||||
v[30] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x3C ^ S16));
|
||||
v[1] -= v[30];
|
||||
v[2] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x06 ^ S16));
|
||||
v[28] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x38 ^ S16));
|
||||
v[2] -= v[28];
|
||||
v[3] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x04 ^ S16));
|
||||
v[29] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x3A ^ S16));
|
||||
v[3] -= v[29];
|
||||
|
||||
v[4] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x0E ^ S16));
|
||||
v[24] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x30 ^ S16));
|
||||
v[4] -= v[24];
|
||||
v[5] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x0C ^ S16));
|
||||
v[25] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x32 ^ S16));
|
||||
v[5] -= v[25];
|
||||
v[6] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x08 ^ S16));
|
||||
v[27] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x36 ^ S16));
|
||||
v[6] -= v[27];
|
||||
v[7] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x0A ^ S16));
|
||||
v[26] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x34 ^ S16));
|
||||
v[7] -= v[26];
|
||||
|
||||
v[8] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x1E ^ S16));
|
||||
v[16] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x20 ^ S16));
|
||||
v[8] -= v[16];
|
||||
v[9] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x1C ^ S16));
|
||||
v[17] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x22 ^ S16));
|
||||
v[9] -= v[17];
|
||||
v[10] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x18 ^ S16));
|
||||
v[19] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x26 ^ S16));
|
||||
v[10] -= v[19];
|
||||
v[11] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x1A ^ S16));
|
||||
v[18] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x24 ^ S16));
|
||||
v[11] -= v[18];
|
||||
|
||||
v[12] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x10 ^ S16));
|
||||
v[23] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x2E ^ S16));
|
||||
v[12] -= v[23];
|
||||
v[13] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x12 ^ S16));
|
||||
v[22] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x2C ^ S16));
|
||||
v[13] -= v[22];
|
||||
v[14] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x16 ^ S16));
|
||||
v[20] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x28 ^ S16));
|
||||
v[14] -= v[20];
|
||||
v[15] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x14 ^ S16));
|
||||
v[21] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x2A ^ S16));
|
||||
v[15] -= v[21];
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
v[0 + i] = (v[0 + i] * LUT6[i]) >> 0x10;
|
||||
v[0] = v[0] + v[0];
|
||||
v[1] = v[1] + v[1];
|
||||
v[2] = v[2] + v[2];
|
||||
v[3] = v[3] + v[3];
|
||||
v[4] = v[4] + v[4];
|
||||
v[5] = v[5] + v[5];
|
||||
v[6] = v[6] + v[6];
|
||||
v[7] = v[7] + v[7];
|
||||
v[12] = v[12] + v[12];
|
||||
v[13] = v[13] + v[13];
|
||||
v[15] = v[15] + v[15];
|
||||
|
||||
MP3AB0(v);
|
||||
|
||||
/* Part 7: - 100% Accurate + SSV - Unoptimized */
|
||||
|
||||
v[0] = (v[17] + v[16]) >> 1;
|
||||
v[1] = ((v[17] * (int)((short)0xA57E * 2)) + (v[16] * 0xB504)) >> 0x10;
|
||||
v[2] = -v[18] - v[19];
|
||||
v[3] = ((v[18] - v[19]) * 0x16A09) >> 0x10;
|
||||
v[4] = v[20] + v[21] + v[0];
|
||||
v[5] = (((v[20] - v[21]) * 0x16A09) >> 0x10) + v[1];
|
||||
v[6] = (((v[22] + v[23]) << 1) + v[0]) - v[2];
|
||||
v[7] = (((v[22] - v[23]) * 0x2D413) >> 0x10) + v[0] + v[1] + v[3];
|
||||
/* 0x16A8 */
|
||||
/* Save v[0] -> (T3 + 0xFFE0) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t3 + (short)0xFFE0))) = (short) - v[0];
|
||||
v[8] = v[24] + v[25];
|
||||
v[9] = ((v[24] - v[25]) * 0x16A09) >> 0x10;
|
||||
v[10] = ((v[26] + v[27]) << 1) + v[8];
|
||||
v[11] = (((v[26] - v[27]) * 0x2D413) >> 0x10) + v[8] + v[9];
|
||||
v[12] = v[4] - ((v[28] + v[29]) << 1);
|
||||
/* ** Store v12 -> (T2 + 0x20) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t2 + (short)0x20))) = (short)v[12];
|
||||
v[13] = (((v[28] - v[29]) * 0x2D413) >> 0x10) - v[12] - v[5];
|
||||
v[14] = v[30] + v[31];
|
||||
v[14] = v[14] + v[14];
|
||||
v[14] = v[14] + v[14];
|
||||
v[14] = v[6] - v[14];
|
||||
v[15] = (((v[30] - v[31]) * 0x5A827) >> 0x10) - v[7];
|
||||
/* Store v14 -> (T5 + 0x20) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t5 + (short)0x20))) = (short)v[14];
|
||||
v[14] = v[14] + v[1];
|
||||
/* Store v[14] -> (T6 + 0x20) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t6 + (short)0x20))) = (short)v[14];
|
||||
/* Store v[15] -> (T1 + 0xFFE0) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t1 + (short)0xFFE0))) = (short)v[15];
|
||||
v[9] = v[9] + v[10];
|
||||
v[1] = v[1] + v[6];
|
||||
v[6] = v[10] - v[6];
|
||||
v[1] = v[9] - v[1];
|
||||
/* Store v[6] -> (T5 + 0x60) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t5 + (short)0x60))) = (short)v[6];
|
||||
v[10] = v[10] + v[2];
|
||||
v[10] = v[4] - v[10];
|
||||
/* Store v[10] -> (T2 + 0xFFA0) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t2 + (short)0xFFA0))) = (short)v[10];
|
||||
v[12] = v[2] - v[12];
|
||||
/* Store v[12] -> (T2 + 0xFFE0) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t2 + (short)0xFFE0))) = (short)v[12];
|
||||
v[5] = v[4] + v[5];
|
||||
v[4] = v[8] - v[4];
|
||||
/* Store v[4] -> (T2 + 0x60) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t2 + (short)0x60))) = (short)v[4];
|
||||
v[0] = v[0] - v[8];
|
||||
/* Store v[0] -> (T3 + 0xFFA0) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t3 + (short)0xFFA0))) = (short)v[0];
|
||||
v[7] = v[7] - v[11];
|
||||
/* Store v[7] -> (T1 + 0xFFA0) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t1 + (short)0xFFA0))) = (short)v[7];
|
||||
v[11] = v[11] - v[3];
|
||||
/* Store v[1] -> (T6 + 0x60) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t6 + (short)0x60))) = (short)v[1];
|
||||
v[11] = v[11] - v[5];
|
||||
/* Store v[11] -> (T0 + 0x60) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t0 + (short)0x60))) = (short)v[11];
|
||||
v[3] = v[3] - v[13];
|
||||
/* Store v[3] -> (T0 + 0x20) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t0 + (short)0x20))) = (short)v[3];
|
||||
v[13] = v[13] + v[2];
|
||||
/* Store v[13] -> (T0 + 0xFFE0) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t0 + (short)0xFFE0))) = (short)v[13];
|
||||
v[2] = (v[5] - v[2]) - v[9];
|
||||
/* Store v[2] -> (T0 + 0xFFA0) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t0 + (short)0xFFA0))) = (short)v[2];
|
||||
/* 0x7A8 - Verified... */
|
||||
|
||||
/* Step 8 - Dewindowing */
|
||||
|
||||
addptr = t6 & 0xFFE0;
|
||||
|
||||
offset = 0x10 - (t4 >> 1);
|
||||
for (x = 0; x < 8; x++) {
|
||||
int32_t v0;
|
||||
int32_t v18;
|
||||
v2 = v4 = v6 = v8 = 0;
|
||||
|
||||
for (i = 7; i >= 0; i--) {
|
||||
v2 += ((int) * (int16_t *)(hle->mp3_buffer + (addptr) + 0x00) * (short)DeWindowLUT[offset + 0x00] + 0x4000) >> 0xF;
|
||||
v4 += ((int) * (int16_t *)(hle->mp3_buffer + (addptr) + 0x10) * (short)DeWindowLUT[offset + 0x08] + 0x4000) >> 0xF;
|
||||
v6 += ((int) * (int16_t *)(hle->mp3_buffer + (addptr) + 0x20) * (short)DeWindowLUT[offset + 0x20] + 0x4000) >> 0xF;
|
||||
v8 += ((int) * (int16_t *)(hle->mp3_buffer + (addptr) + 0x30) * (short)DeWindowLUT[offset + 0x28] + 0x4000) >> 0xF;
|
||||
addptr += 2;
|
||||
offset++;
|
||||
}
|
||||
v0 = v2 + v4;
|
||||
v18 = v6 + v8;
|
||||
/* Clamp(v0); */
|
||||
/* Clamp(v18); */
|
||||
/* clamp??? */
|
||||
*(int16_t *)(hle->mp3_buffer + (outPtr ^ S16)) = v0;
|
||||
*(int16_t *)(hle->mp3_buffer + ((outPtr + 2)^S16)) = v18;
|
||||
outPtr += 4;
|
||||
addptr += 0x30;
|
||||
offset += 0x38;
|
||||
}
|
||||
|
||||
offset = 0x10 - (t4 >> 1) + 8 * 0x40;
|
||||
v2 = v4 = 0;
|
||||
for (i = 0; i < 4; i++) {
|
||||
v2 += ((int) * (int16_t *)(hle->mp3_buffer + (addptr) + 0x00) * (short)DeWindowLUT[offset + 0x00] + 0x4000) >> 0xF;
|
||||
v2 += ((int) * (int16_t *)(hle->mp3_buffer + (addptr) + 0x10) * (short)DeWindowLUT[offset + 0x08] + 0x4000) >> 0xF;
|
||||
addptr += 2;
|
||||
offset++;
|
||||
v4 += ((int) * (int16_t *)(hle->mp3_buffer + (addptr) + 0x00) * (short)DeWindowLUT[offset + 0x00] + 0x4000) >> 0xF;
|
||||
v4 += ((int) * (int16_t *)(hle->mp3_buffer + (addptr) + 0x10) * (short)DeWindowLUT[offset + 0x08] + 0x4000) >> 0xF;
|
||||
addptr += 2;
|
||||
offset++;
|
||||
}
|
||||
mult6 = *(int32_t *)(hle->mp3_buffer + 0xCE8);
|
||||
mult4 = *(int32_t *)(hle->mp3_buffer + 0xCEC);
|
||||
if (t4 & 0x2) {
|
||||
v2 = (v2 **(uint32_t *)(hle->mp3_buffer + 0xCE8)) >> 0x10;
|
||||
*(int16_t *)(hle->mp3_buffer + (outPtr ^ S16)) = v2;
|
||||
} else {
|
||||
v4 = (v4 **(uint32_t *)(hle->mp3_buffer + 0xCE8)) >> 0x10;
|
||||
*(int16_t *)(hle->mp3_buffer + (outPtr ^ S16)) = v4;
|
||||
mult4 = *(uint32_t *)(hle->mp3_buffer + 0xCE8);
|
||||
}
|
||||
addptr -= 0x50;
|
||||
|
||||
for (x = 0; x < 8; x++) {
|
||||
int32_t v0;
|
||||
int32_t v18;
|
||||
v2 = v4 = v6 = v8 = 0;
|
||||
|
||||
offset = (0x22F - (t4 >> 1) + x * 0x40);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
v2 += ((int) * (int16_t *)(hle->mp3_buffer + (addptr) + 0x20) * (short)DeWindowLUT[offset + 0x00] + 0x4000) >> 0xF;
|
||||
v2 -= ((int) * (int16_t *)(hle->mp3_buffer + ((addptr + 2)) + 0x20) * (short)DeWindowLUT[offset + 0x01] + 0x4000) >> 0xF;
|
||||
v4 += ((int) * (int16_t *)(hle->mp3_buffer + (addptr) + 0x30) * (short)DeWindowLUT[offset + 0x08] + 0x4000) >> 0xF;
|
||||
v4 -= ((int) * (int16_t *)(hle->mp3_buffer + ((addptr + 2)) + 0x30) * (short)DeWindowLUT[offset + 0x09] + 0x4000) >> 0xF;
|
||||
v6 += ((int) * (int16_t *)(hle->mp3_buffer + (addptr) + 0x00) * (short)DeWindowLUT[offset + 0x20] + 0x4000) >> 0xF;
|
||||
v6 -= ((int) * (int16_t *)(hle->mp3_buffer + ((addptr + 2)) + 0x00) * (short)DeWindowLUT[offset + 0x21] + 0x4000) >> 0xF;
|
||||
v8 += ((int) * (int16_t *)(hle->mp3_buffer + (addptr) + 0x10) * (short)DeWindowLUT[offset + 0x28] + 0x4000) >> 0xF;
|
||||
v8 -= ((int) * (int16_t *)(hle->mp3_buffer + ((addptr + 2)) + 0x10) * (short)DeWindowLUT[offset + 0x29] + 0x4000) >> 0xF;
|
||||
addptr += 4;
|
||||
offset += 2;
|
||||
}
|
||||
v0 = v2 + v4;
|
||||
v18 = v6 + v8;
|
||||
/* Clamp(v0); */
|
||||
/* Clamp(v18); */
|
||||
/* clamp??? */
|
||||
*(int16_t *)(hle->mp3_buffer + ((outPtr + 2)^S16)) = v0;
|
||||
*(int16_t *)(hle->mp3_buffer + ((outPtr + 4)^S16)) = v18;
|
||||
outPtr += 4;
|
||||
addptr -= 0x50;
|
||||
}
|
||||
|
||||
tmp = outPtr;
|
||||
hi0 = mult6;
|
||||
hi1 = mult4;
|
||||
|
||||
hi0 = (int)hi0 >> 0x10;
|
||||
hi1 = (int)hi1 >> 0x10;
|
||||
for (i = 0; i < 8; i++) {
|
||||
/* v0 */
|
||||
vt = (*(int16_t *)(hle->mp3_buffer + ((tmp - 0x40)^S16)) * hi0);
|
||||
*(int16_t *)((uint8_t *)hle->mp3_buffer + ((tmp - 0x40)^S16)) = clamp_s16(vt);
|
||||
|
||||
/* v17 */
|
||||
vt = (*(int16_t *)(hle->mp3_buffer + ((tmp - 0x30)^S16)) * hi0);
|
||||
*(int16_t *)((uint8_t *)hle->mp3_buffer + ((tmp - 0x30)^S16)) = clamp_s16(vt);
|
||||
|
||||
/* v2 */
|
||||
vt = (*(int16_t *)(hle->mp3_buffer + ((tmp - 0x1E)^S16)) * hi1);
|
||||
*(int16_t *)((uint8_t *)hle->mp3_buffer + ((tmp - 0x1E)^S16)) = clamp_s16(vt);
|
||||
|
||||
/* v4 */
|
||||
vt = (*(int16_t *)(hle->mp3_buffer + ((tmp - 0xE)^S16)) * hi1);
|
||||
*(int16_t *)((uint8_t *)hle->mp3_buffer + ((tmp - 0xE)^S16)) = clamp_s16(vt);
|
||||
|
||||
tmp += 2;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,988 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - musyx.c *
|
||||
* Mupen64Plus homepage: https://mupen64plus.org/ *
|
||||
* Copyright (C) 2013 Bobby Smiles *
|
||||
* *
|
||||
* 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 <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "arithmetics.h"
|
||||
#include "audio.h"
|
||||
#include "common.h"
|
||||
#include "hle_external.h"
|
||||
#include "hle_internal.h"
|
||||
#include "memory.h"
|
||||
|
||||
/* various constants */
|
||||
enum { SUBFRAME_SIZE = 192 };
|
||||
enum { MAX_VOICES = 32 };
|
||||
|
||||
enum { SAMPLE_BUFFER_SIZE = 0x200 };
|
||||
|
||||
|
||||
enum {
|
||||
SFD_VOICE_COUNT = 0x0,
|
||||
SFD_SFX_INDEX = 0x2,
|
||||
SFD_VOICE_BITMASK = 0x4,
|
||||
SFD_STATE_PTR = 0x8,
|
||||
SFD_SFX_PTR = 0xc,
|
||||
SFD_VOICES = 0x10,
|
||||
|
||||
/* v2 only */
|
||||
SFD2_10_PTR = 0x10,
|
||||
SFD2_14_BITMASK = 0x14,
|
||||
SFD2_15_BITMASK = 0x15,
|
||||
SFD2_16_BITMASK = 0x16,
|
||||
SFD2_18_PTR = 0x18,
|
||||
SFD2_1C_PTR = 0x1c,
|
||||
SFD2_20_PTR = 0x20,
|
||||
SFD2_24_PTR = 0x24,
|
||||
SFD2_VOICES = 0x28
|
||||
};
|
||||
|
||||
enum {
|
||||
VOICE_ENV_BEGIN = 0x00,
|
||||
VOICE_ENV_STEP = 0x10,
|
||||
VOICE_PITCH_Q16 = 0x20,
|
||||
VOICE_PITCH_SHIFT = 0x22,
|
||||
VOICE_CATSRC_0 = 0x24,
|
||||
VOICE_CATSRC_1 = 0x30,
|
||||
VOICE_ADPCM_FRAMES = 0x3c,
|
||||
VOICE_SKIP_SAMPLES = 0x3e,
|
||||
|
||||
/* for PCM16 */
|
||||
VOICE_U16_40 = 0x40,
|
||||
VOICE_U16_42 = 0x42,
|
||||
|
||||
/* for ADPCM */
|
||||
VOICE_ADPCM_TABLE_PTR = 0x40,
|
||||
|
||||
VOICE_INTERLEAVED_PTR = 0x44,
|
||||
VOICE_END_POINT = 0x48,
|
||||
VOICE_RESTART_POINT = 0x4a,
|
||||
VOICE_U16_4C = 0x4c,
|
||||
VOICE_U16_4E = 0x4e,
|
||||
|
||||
VOICE_SIZE = 0x50
|
||||
};
|
||||
|
||||
enum {
|
||||
CATSRC_PTR1 = 0x00,
|
||||
CATSRC_PTR2 = 0x04,
|
||||
CATSRC_SIZE1 = 0x08,
|
||||
CATSRC_SIZE2 = 0x0a
|
||||
};
|
||||
|
||||
enum {
|
||||
STATE_LAST_SAMPLE = 0x0,
|
||||
STATE_BASE_VOL = 0x100,
|
||||
STATE_CC0 = 0x110,
|
||||
STATE_740_LAST4_V1 = 0x290,
|
||||
|
||||
STATE_740_LAST4_V2 = 0x110
|
||||
};
|
||||
|
||||
enum {
|
||||
SFX_CBUFFER_PTR = 0x00,
|
||||
SFX_CBUFFER_LENGTH = 0x04,
|
||||
SFX_TAP_COUNT = 0x08,
|
||||
SFX_FIR4_HGAIN = 0x0a,
|
||||
SFX_TAP_DELAYS = 0x0c,
|
||||
SFX_TAP_GAINS = 0x2c,
|
||||
SFX_U16_3C = 0x3c,
|
||||
SFX_U16_3E = 0x3e,
|
||||
SFX_FIR4_HCOEFFS = 0x40
|
||||
};
|
||||
|
||||
|
||||
/* struct definition */
|
||||
typedef struct {
|
||||
/* internal subframes */
|
||||
int16_t left[SUBFRAME_SIZE];
|
||||
int16_t right[SUBFRAME_SIZE];
|
||||
int16_t cc0[SUBFRAME_SIZE];
|
||||
int16_t e50[SUBFRAME_SIZE];
|
||||
|
||||
/* internal subframes base volumes */
|
||||
int32_t base_vol[4];
|
||||
|
||||
/* */
|
||||
int16_t subframe_740_last4[4];
|
||||
} musyx_t;
|
||||
|
||||
typedef void (*mix_sfx_with_main_subframes_t)(musyx_t *musyx, const int16_t *subframe,
|
||||
const uint16_t* gains);
|
||||
|
||||
/* helper functions prototypes */
|
||||
static void load_base_vol(struct hle_t* hle, int32_t *base_vol, uint32_t address);
|
||||
static void save_base_vol(struct hle_t* hle, const int32_t *base_vol, uint32_t address);
|
||||
static void update_base_vol(struct hle_t* hle, int32_t *base_vol,
|
||||
uint32_t voice_mask, uint32_t last_sample_ptr,
|
||||
uint8_t mask_15, uint32_t ptr_24);
|
||||
|
||||
static void init_subframes_v1(musyx_t *musyx);
|
||||
static void init_subframes_v2(musyx_t *musyx);
|
||||
|
||||
static uint32_t voice_stage(struct hle_t* hle, musyx_t *musyx,
|
||||
uint32_t voice_ptr, uint32_t last_sample_ptr);
|
||||
|
||||
static void dma_cat8(struct hle_t* hle, uint8_t *dst, uint32_t catsrc_ptr);
|
||||
static void dma_cat16(struct hle_t* hle, uint16_t *dst, uint32_t catsrc_ptr);
|
||||
|
||||
static void load_samples_PCM16(struct hle_t* hle, uint32_t voice_ptr, int16_t *samples,
|
||||
unsigned *segbase, unsigned *offset);
|
||||
static void load_samples_ADPCM(struct hle_t* hle, uint32_t voice_ptr, int16_t *samples,
|
||||
unsigned *segbase, unsigned *offset);
|
||||
|
||||
static void adpcm_decode_frames(struct hle_t* hle,
|
||||
int16_t *dst, const uint8_t *src,
|
||||
const int16_t *table, uint8_t count,
|
||||
uint8_t skip_samples);
|
||||
|
||||
static void adpcm_predict_frame(int16_t *dst, const uint8_t *src,
|
||||
const uint8_t *nibbles,
|
||||
unsigned int rshift);
|
||||
|
||||
static void mix_voice_samples(struct hle_t* hle, musyx_t *musyx,
|
||||
uint32_t voice_ptr, const int16_t *samples,
|
||||
unsigned segbase, unsigned offset, uint32_t last_sample_ptr);
|
||||
|
||||
static void sfx_stage(struct hle_t* hle,
|
||||
mix_sfx_with_main_subframes_t mix_sfx_with_main_subframes,
|
||||
musyx_t *musyx, uint32_t sfx_ptr, uint16_t idx);
|
||||
|
||||
static void mix_sfx_with_main_subframes_v1(musyx_t *musyx, const int16_t *subframe,
|
||||
const uint16_t* gains);
|
||||
static void mix_sfx_with_main_subframes_v2(musyx_t *musyx, const int16_t *subframe,
|
||||
const uint16_t* gains);
|
||||
|
||||
static void mix_samples(int16_t *y, int16_t x, int16_t hgain);
|
||||
static void mix_subframes(int16_t *y, const int16_t *x, int16_t hgain);
|
||||
static void mix_fir4(int16_t *y, const int16_t *x, int16_t hgain, const int16_t *hcoeffs);
|
||||
|
||||
|
||||
static void interleave_stage_v1(struct hle_t* hle, musyx_t *musyx,
|
||||
uint32_t output_ptr);
|
||||
|
||||
static void interleave_stage_v2(struct hle_t* hle, musyx_t *musyx,
|
||||
uint16_t mask_16, uint32_t ptr_18,
|
||||
uint32_t ptr_1c, uint32_t output_ptr);
|
||||
|
||||
static int32_t dot4(const int16_t *x, const int16_t *y)
|
||||
{
|
||||
size_t i;
|
||||
int32_t accu = 0;
|
||||
|
||||
for (i = 0; i < 4; ++i)
|
||||
accu = clamp_s16(accu + (((int32_t)x[i] * (int32_t)y[i]) >> 15));
|
||||
|
||||
return accu;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* MusyX v1 audio ucode
|
||||
**************************************************************************/
|
||||
void musyx_v1_task(struct hle_t* hle)
|
||||
{
|
||||
uint32_t sfd_ptr = *dmem_u32(hle, TASK_DATA_PTR);
|
||||
uint32_t sfd_count = *dmem_u32(hle, TASK_DATA_SIZE);
|
||||
uint32_t state_ptr;
|
||||
musyx_t musyx;
|
||||
|
||||
HleVerboseMessage(hle->user_defined,
|
||||
"musyx_v1_task: *data=%x, #SF=%d",
|
||||
sfd_ptr,
|
||||
sfd_count);
|
||||
|
||||
state_ptr = *dram_u32(hle, sfd_ptr + SFD_STATE_PTR);
|
||||
|
||||
/* load initial state */
|
||||
load_base_vol(hle, musyx.base_vol, state_ptr + STATE_BASE_VOL);
|
||||
dram_load_u16(hle, (uint16_t *)musyx.cc0, state_ptr + STATE_CC0, SUBFRAME_SIZE);
|
||||
dram_load_u16(hle, (uint16_t *)musyx.subframe_740_last4, state_ptr + STATE_740_LAST4_V1,
|
||||
4);
|
||||
|
||||
for (;;) {
|
||||
/* parse SFD structure */
|
||||
uint16_t sfx_index = *dram_u16(hle, sfd_ptr + SFD_SFX_INDEX);
|
||||
uint32_t voice_mask = *dram_u32(hle, sfd_ptr + SFD_VOICE_BITMASK);
|
||||
uint32_t sfx_ptr = *dram_u32(hle, sfd_ptr + SFD_SFX_PTR);
|
||||
uint32_t voice_ptr = sfd_ptr + SFD_VOICES;
|
||||
uint32_t last_sample_ptr = state_ptr + STATE_LAST_SAMPLE;
|
||||
uint32_t output_ptr;
|
||||
|
||||
/* initialize internal subframes using updated base volumes */
|
||||
update_base_vol(hle, musyx.base_vol, voice_mask, last_sample_ptr, 0, 0);
|
||||
init_subframes_v1(&musyx);
|
||||
|
||||
/* active voices get mixed into L,R,cc0,e50 subframes (optional) */
|
||||
output_ptr = voice_stage(hle, &musyx, voice_ptr, last_sample_ptr);
|
||||
|
||||
/* apply delay-based effects (optional) */
|
||||
sfx_stage(hle, mix_sfx_with_main_subframes_v1,
|
||||
&musyx, sfx_ptr, sfx_index);
|
||||
|
||||
/* emit interleaved L,R subframes */
|
||||
interleave_stage_v1(hle, &musyx, output_ptr);
|
||||
|
||||
--sfd_count;
|
||||
if (sfd_count == 0)
|
||||
break;
|
||||
|
||||
sfd_ptr += SFD_VOICES + MAX_VOICES * VOICE_SIZE;
|
||||
state_ptr = *dram_u32(hle, sfd_ptr + SFD_STATE_PTR);
|
||||
}
|
||||
|
||||
/* writeback updated state */
|
||||
save_base_vol(hle, musyx.base_vol, state_ptr + STATE_BASE_VOL);
|
||||
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);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* MusyX v2 audio ucode
|
||||
**************************************************************************/
|
||||
void musyx_v2_task(struct hle_t* hle)
|
||||
{
|
||||
uint32_t sfd_ptr = *dmem_u32(hle, TASK_DATA_PTR);
|
||||
uint32_t sfd_count = *dmem_u32(hle, TASK_DATA_SIZE);
|
||||
musyx_t musyx;
|
||||
|
||||
HleVerboseMessage(hle->user_defined,
|
||||
"musyx_v2_task: *data=%x, #SF=%d",
|
||||
sfd_ptr,
|
||||
sfd_count);
|
||||
|
||||
for (;;) {
|
||||
/* parse SFD structure */
|
||||
uint16_t sfx_index = *dram_u16(hle, sfd_ptr + SFD_SFX_INDEX);
|
||||
uint32_t voice_mask = *dram_u32(hle, sfd_ptr + SFD_VOICE_BITMASK);
|
||||
uint32_t state_ptr = *dram_u32(hle, sfd_ptr + SFD_STATE_PTR);
|
||||
uint32_t sfx_ptr = *dram_u32(hle, sfd_ptr + SFD_SFX_PTR);
|
||||
uint32_t voice_ptr = sfd_ptr + SFD2_VOICES;
|
||||
|
||||
uint32_t ptr_10 = *dram_u32(hle, sfd_ptr + SFD2_10_PTR);
|
||||
uint8_t mask_14 = *dram_u8 (hle, sfd_ptr + SFD2_14_BITMASK);
|
||||
uint8_t mask_15 = *dram_u8 (hle, sfd_ptr + SFD2_15_BITMASK);
|
||||
uint16_t mask_16 = *dram_u16(hle, sfd_ptr + SFD2_16_BITMASK);
|
||||
uint32_t ptr_18 = *dram_u32(hle, sfd_ptr + SFD2_18_PTR);
|
||||
uint32_t ptr_1c = *dram_u32(hle, sfd_ptr + SFD2_1C_PTR);
|
||||
uint32_t ptr_20 = *dram_u32(hle, sfd_ptr + SFD2_20_PTR);
|
||||
uint32_t ptr_24 = *dram_u32(hle, sfd_ptr + SFD2_24_PTR);
|
||||
|
||||
uint32_t last_sample_ptr = state_ptr + STATE_LAST_SAMPLE;
|
||||
uint32_t output_ptr;
|
||||
|
||||
/* load state */
|
||||
load_base_vol(hle, musyx.base_vol, state_ptr + STATE_BASE_VOL);
|
||||
dram_load_u16(hle, (uint16_t *)musyx.subframe_740_last4,
|
||||
state_ptr + STATE_740_LAST4_V2, 4);
|
||||
|
||||
/* initialize internal subframes using updated base volumes */
|
||||
update_base_vol(hle, musyx.base_vol, voice_mask, last_sample_ptr, mask_15, ptr_24);
|
||||
init_subframes_v2(&musyx);
|
||||
|
||||
if (ptr_10) {
|
||||
/* TODO */
|
||||
HleWarnMessage(hle->user_defined,
|
||||
"ptr_10=%08x mask_14=%02x ptr_24=%08x",
|
||||
ptr_10, mask_14, ptr_24);
|
||||
}
|
||||
|
||||
/* active voices get mixed into L,R,cc0,e50 subframes (optional) */
|
||||
output_ptr = voice_stage(hle, &musyx, voice_ptr, last_sample_ptr);
|
||||
|
||||
/* apply delay-based effects (optional) */
|
||||
sfx_stage(hle, mix_sfx_with_main_subframes_v2,
|
||||
&musyx, sfx_ptr, sfx_index);
|
||||
|
||||
dram_store_u16(hle, (uint16_t*)musyx.left, output_ptr , SUBFRAME_SIZE);
|
||||
dram_store_u16(hle, (uint16_t*)musyx.right, output_ptr + 2*SUBFRAME_SIZE, SUBFRAME_SIZE);
|
||||
dram_store_u16(hle, (uint16_t*)musyx.cc0, output_ptr + 4*SUBFRAME_SIZE, SUBFRAME_SIZE);
|
||||
|
||||
/* store state */
|
||||
save_base_vol(hle, musyx.base_vol, state_ptr + STATE_BASE_VOL);
|
||||
dram_store_u16(hle, (uint16_t*)musyx.subframe_740_last4,
|
||||
state_ptr + STATE_740_LAST4_V2, 4);
|
||||
|
||||
if (mask_16)
|
||||
interleave_stage_v2(hle, &musyx, mask_16, ptr_18, ptr_1c, ptr_20);
|
||||
|
||||
--sfd_count;
|
||||
if (sfd_count == 0)
|
||||
break;
|
||||
|
||||
sfd_ptr += SFD2_VOICES + MAX_VOICES * VOICE_SIZE;
|
||||
}
|
||||
|
||||
rsp_break(hle, SP_STATUS_TASKDONE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static void load_base_vol(struct hle_t* hle, int32_t *base_vol, uint32_t address)
|
||||
{
|
||||
base_vol[0] = ((uint32_t)(*dram_u16(hle, address)) << 16) | (*dram_u16(hle, address + 8));
|
||||
base_vol[1] = ((uint32_t)(*dram_u16(hle, address + 2)) << 16) | (*dram_u16(hle, address + 10));
|
||||
base_vol[2] = ((uint32_t)(*dram_u16(hle, address + 4)) << 16) | (*dram_u16(hle, address + 12));
|
||||
base_vol[3] = ((uint32_t)(*dram_u16(hle, address + 6)) << 16) | (*dram_u16(hle, address + 14));
|
||||
}
|
||||
|
||||
static void save_base_vol(struct hle_t* hle, const int32_t *base_vol, uint32_t address)
|
||||
{
|
||||
unsigned k;
|
||||
|
||||
for (k = 0; k < 4; ++k) {
|
||||
*dram_u16(hle, address) = (uint16_t)(base_vol[k] >> 16);
|
||||
address += 2;
|
||||
}
|
||||
|
||||
for (k = 0; k < 4; ++k) {
|
||||
*dram_u16(hle, address) = (uint16_t)(base_vol[k]);
|
||||
address += 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void update_base_vol(struct hle_t* hle, int32_t *base_vol,
|
||||
uint32_t voice_mask, uint32_t last_sample_ptr,
|
||||
uint8_t mask_15, uint32_t ptr_24)
|
||||
{
|
||||
unsigned i, k;
|
||||
uint32_t mask;
|
||||
|
||||
HleVerboseMessage(hle->user_defined, "base_vol voice_mask = %08x", voice_mask);
|
||||
HleVerboseMessage(hle->user_defined,
|
||||
"BEFORE: base_vol = %08x %08x %08x %08x",
|
||||
base_vol[0], base_vol[1], base_vol[2], base_vol[3]);
|
||||
|
||||
/* optim: skip voices contributions entirely if voice_mask is empty */
|
||||
if (voice_mask != 0) {
|
||||
for (i = 0, mask = 1; i < MAX_VOICES;
|
||||
++i, mask <<= 1, last_sample_ptr += 8) {
|
||||
if ((voice_mask & mask) == 0)
|
||||
continue;
|
||||
|
||||
for (k = 0; k < 4; ++k)
|
||||
base_vol[k] += (int16_t)*dram_u16(hle, last_sample_ptr + k * 2);
|
||||
}
|
||||
}
|
||||
|
||||
/* optim: skip contributions entirely if mask_15 is empty */
|
||||
if (mask_15 != 0) {
|
||||
for(i = 0, mask = 1; i < 4;
|
||||
++i, mask <<= 1, ptr_24 += 8) {
|
||||
if ((mask_15 & mask) == 0)
|
||||
continue;
|
||||
|
||||
for(k = 0; k < 4; ++k)
|
||||
base_vol[k] += (int16_t)*dram_u16(hle, ptr_24 + k * 2);
|
||||
}
|
||||
}
|
||||
|
||||
/* apply 3% decay */
|
||||
for (k = 0; k < 4; ++k)
|
||||
base_vol[k] = (base_vol[k] * 0x0000f850) >> 16;
|
||||
|
||||
HleVerboseMessage(hle->user_defined,
|
||||
"AFTER: base_vol = %08x %08x %08x %08x",
|
||||
base_vol[0], base_vol[1], base_vol[2], base_vol[3]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static void init_subframes_v1(musyx_t *musyx)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
int16_t base_cc0 = clamp_s16(musyx->base_vol[2]);
|
||||
int16_t base_e50 = clamp_s16(musyx->base_vol[3]);
|
||||
|
||||
int16_t *left = musyx->left;
|
||||
int16_t *right = musyx->right;
|
||||
int16_t *cc0 = musyx->cc0;
|
||||
int16_t *e50 = musyx->e50;
|
||||
|
||||
for (i = 0; i < SUBFRAME_SIZE; ++i) {
|
||||
*(e50++) = base_e50;
|
||||
*(left++) = clamp_s16(*cc0 + base_cc0);
|
||||
*(right++) = clamp_s16(-*cc0 - base_cc0);
|
||||
*(cc0++) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void init_subframes_v2(musyx_t *musyx)
|
||||
{
|
||||
unsigned i,k;
|
||||
int16_t values[4];
|
||||
int16_t* subframes[4];
|
||||
|
||||
for(k = 0; k < 4; ++k)
|
||||
values[k] = clamp_s16(musyx->base_vol[k]);
|
||||
|
||||
subframes[0] = musyx->left;
|
||||
subframes[1] = musyx->right;
|
||||
subframes[2] = musyx->cc0;
|
||||
subframes[3] = musyx->e50;
|
||||
|
||||
for (i = 0; i < SUBFRAME_SIZE; ++i) {
|
||||
|
||||
for(k = 0; k < 4; ++k)
|
||||
*(subframes[k]++) = values[k];
|
||||
}
|
||||
}
|
||||
|
||||
/* Process voices, and returns interleaved subframe destination address */
|
||||
static uint32_t voice_stage(struct hle_t* hle, musyx_t *musyx,
|
||||
uint32_t voice_ptr, uint32_t last_sample_ptr)
|
||||
{
|
||||
uint32_t output_ptr;
|
||||
int i = 0;
|
||||
|
||||
/* voice stage can be skipped if first voice has no samples */
|
||||
if (*dram_u16(hle, voice_ptr + VOICE_CATSRC_0 + CATSRC_SIZE1) == 0) {
|
||||
HleVerboseMessage(hle->user_defined, "Skipping Voice stage");
|
||||
output_ptr = *dram_u32(hle, voice_ptr + VOICE_INTERLEAVED_PTR);
|
||||
} else {
|
||||
/* otherwise process voices until a non null output_ptr is encountered */
|
||||
for (;;) {
|
||||
/* load voice samples (PCM16 or APDCM) */
|
||||
int16_t samples[SAMPLE_BUFFER_SIZE];
|
||||
unsigned segbase;
|
||||
unsigned offset;
|
||||
|
||||
HleVerboseMessage(hle->user_defined, "Processing Voice #%d", i);
|
||||
|
||||
if (*dram_u8(hle, voice_ptr + VOICE_ADPCM_FRAMES) == 0)
|
||||
load_samples_PCM16(hle, voice_ptr, samples, &segbase, &offset);
|
||||
else
|
||||
load_samples_ADPCM(hle, voice_ptr, samples, &segbase, &offset);
|
||||
|
||||
/* mix them with each internal subframes */
|
||||
mix_voice_samples(hle, musyx, voice_ptr, samples, segbase, offset,
|
||||
last_sample_ptr + i * 8);
|
||||
|
||||
/* check break condition */
|
||||
output_ptr = *dram_u32(hle, voice_ptr + VOICE_INTERLEAVED_PTR);
|
||||
if (output_ptr != 0)
|
||||
break;
|
||||
|
||||
/* next voice */
|
||||
++i;
|
||||
voice_ptr += VOICE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
return output_ptr;
|
||||
}
|
||||
|
||||
static void dma_cat8(struct hle_t* hle, uint8_t *dst, uint32_t catsrc_ptr)
|
||||
{
|
||||
uint32_t ptr1 = *dram_u32(hle, catsrc_ptr + CATSRC_PTR1);
|
||||
uint32_t ptr2 = *dram_u32(hle, catsrc_ptr + CATSRC_PTR2);
|
||||
uint16_t size1 = *dram_u16(hle, catsrc_ptr + CATSRC_SIZE1);
|
||||
uint16_t size2 = *dram_u16(hle, catsrc_ptr + CATSRC_SIZE2);
|
||||
|
||||
size_t count1 = size1;
|
||||
size_t count2 = size2;
|
||||
|
||||
HleVerboseMessage(hle->user_defined,
|
||||
"dma_cat: %08x %08x %04x %04x",
|
||||
ptr1,
|
||||
ptr2,
|
||||
size1,
|
||||
size2);
|
||||
|
||||
dram_load_u8(hle, dst, ptr1, count1);
|
||||
|
||||
if (size2 == 0)
|
||||
return;
|
||||
|
||||
dram_load_u8(hle, dst + count1, ptr2, count2);
|
||||
}
|
||||
|
||||
static void dma_cat16(struct hle_t* hle, uint16_t *dst, uint32_t catsrc_ptr)
|
||||
{
|
||||
uint32_t ptr1 = *dram_u32(hle, catsrc_ptr + CATSRC_PTR1);
|
||||
uint32_t ptr2 = *dram_u32(hle, catsrc_ptr + CATSRC_PTR2);
|
||||
uint16_t size1 = *dram_u16(hle, catsrc_ptr + CATSRC_SIZE1);
|
||||
uint16_t size2 = *dram_u16(hle, catsrc_ptr + CATSRC_SIZE2);
|
||||
|
||||
size_t count1 = size1 >> 1;
|
||||
size_t count2 = size2 >> 1;
|
||||
|
||||
HleVerboseMessage(hle->user_defined,
|
||||
"dma_cat: %08x %08x %04x %04x",
|
||||
ptr1,
|
||||
ptr2,
|
||||
size1,
|
||||
size2);
|
||||
|
||||
dram_load_u16(hle, dst, ptr1, count1);
|
||||
|
||||
if (size2 == 0)
|
||||
return;
|
||||
|
||||
dram_load_u16(hle, dst + count1, ptr2, count2);
|
||||
}
|
||||
|
||||
static void load_samples_PCM16(struct hle_t* hle, uint32_t voice_ptr, int16_t *samples,
|
||||
unsigned *segbase, unsigned *offset)
|
||||
{
|
||||
|
||||
uint8_t u8_3e = *dram_u8(hle, voice_ptr + VOICE_SKIP_SAMPLES);
|
||||
uint16_t u16_40 = *dram_u16(hle, voice_ptr + VOICE_U16_40);
|
||||
uint16_t u16_42 = *dram_u16(hle, voice_ptr + VOICE_U16_42);
|
||||
|
||||
unsigned count = align(u16_40 + u8_3e, 4);
|
||||
|
||||
HleVerboseMessage(hle->user_defined, "Format: PCM16");
|
||||
|
||||
*segbase = SAMPLE_BUFFER_SIZE - count;
|
||||
*offset = u8_3e;
|
||||
|
||||
dma_cat16(hle, (uint16_t *)samples + *segbase, voice_ptr + VOICE_CATSRC_0);
|
||||
|
||||
if (u16_42 != 0)
|
||||
dma_cat16(hle, (uint16_t *)samples, voice_ptr + VOICE_CATSRC_1);
|
||||
}
|
||||
|
||||
static void load_samples_ADPCM(struct hle_t* hle, uint32_t voice_ptr, int16_t *samples,
|
||||
unsigned *segbase, unsigned *offset)
|
||||
{
|
||||
/* decompressed samples cannot exceed 0x400 bytes;
|
||||
* ADPCM has a compression ratio of 5/16 */
|
||||
uint8_t buffer[SAMPLE_BUFFER_SIZE * 2 * 5 / 16];
|
||||
int16_t adpcm_table[128];
|
||||
|
||||
uint8_t u8_3c = *dram_u8(hle, voice_ptr + VOICE_ADPCM_FRAMES );
|
||||
uint8_t u8_3d = *dram_u8(hle, voice_ptr + VOICE_ADPCM_FRAMES + 1);
|
||||
uint8_t u8_3e = *dram_u8(hle, voice_ptr + VOICE_SKIP_SAMPLES );
|
||||
uint8_t u8_3f = *dram_u8(hle, voice_ptr + VOICE_SKIP_SAMPLES + 1);
|
||||
uint32_t adpcm_table_ptr = *dram_u32(hle, voice_ptr + VOICE_ADPCM_TABLE_PTR);
|
||||
unsigned count;
|
||||
|
||||
HleVerboseMessage(hle->user_defined, "Format: ADPCM");
|
||||
|
||||
HleVerboseMessage(hle->user_defined, "Loading ADPCM table: %08x", adpcm_table_ptr);
|
||||
dram_load_u16(hle, (uint16_t *)adpcm_table, adpcm_table_ptr, 128);
|
||||
|
||||
count = u8_3c << 5;
|
||||
|
||||
*segbase = SAMPLE_BUFFER_SIZE - count;
|
||||
*offset = u8_3e & 0x1f;
|
||||
|
||||
dma_cat8(hle, buffer, voice_ptr + VOICE_CATSRC_0);
|
||||
adpcm_decode_frames(hle, samples + *segbase, buffer, adpcm_table, u8_3c, u8_3e);
|
||||
|
||||
if (u8_3d != 0) {
|
||||
dma_cat8(hle, buffer, voice_ptr + VOICE_CATSRC_1);
|
||||
adpcm_decode_frames(hle, samples, buffer, adpcm_table, u8_3d, u8_3f);
|
||||
}
|
||||
}
|
||||
|
||||
static void adpcm_decode_frames(struct hle_t* hle,
|
||||
int16_t *dst, const uint8_t *src,
|
||||
const int16_t *table, uint8_t count,
|
||||
uint8_t skip_samples)
|
||||
{
|
||||
int16_t frame[32];
|
||||
const uint8_t *nibbles = src + 8;
|
||||
unsigned i;
|
||||
bool jump_gap = false;
|
||||
|
||||
HleVerboseMessage(hle->user_defined,
|
||||
"ADPCM decode: count=%d, skip=%d",
|
||||
count, skip_samples);
|
||||
|
||||
if (skip_samples >= 32) {
|
||||
jump_gap = true;
|
||||
nibbles += 16;
|
||||
src += 4;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
uint8_t c2 = nibbles[0];
|
||||
|
||||
const int16_t *book = (c2 & 0xf0) + table;
|
||||
unsigned int rshift = (c2 & 0x0f);
|
||||
|
||||
adpcm_predict_frame(frame, src, nibbles, rshift);
|
||||
|
||||
memcpy(dst, frame, 2 * sizeof(frame[0]));
|
||||
adpcm_compute_residuals(dst + 2, frame + 2, book, dst , 6);
|
||||
adpcm_compute_residuals(dst + 8, frame + 8, book, dst + 6, 8);
|
||||
adpcm_compute_residuals(dst + 16, frame + 16, book, dst + 14, 8);
|
||||
adpcm_compute_residuals(dst + 24, frame + 24, book, dst + 22, 8);
|
||||
|
||||
if (jump_gap) {
|
||||
nibbles += 8;
|
||||
src += 32;
|
||||
}
|
||||
|
||||
jump_gap = !jump_gap;
|
||||
nibbles += 16;
|
||||
src += 4;
|
||||
dst += 32;
|
||||
}
|
||||
}
|
||||
|
||||
static void adpcm_predict_frame(int16_t *dst, const uint8_t *src,
|
||||
const uint8_t *nibbles,
|
||||
unsigned int rshift)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
*(dst++) = (src[0] << 8) | src[1];
|
||||
*(dst++) = (src[2] << 8) | src[3];
|
||||
|
||||
for (i = 1; i < 16; ++i) {
|
||||
uint8_t byte = nibbles[i];
|
||||
|
||||
*(dst++) = adpcm_predict_sample(byte, 0xf0, 8, rshift);
|
||||
*(dst++) = adpcm_predict_sample(byte, 0x0f, 12, rshift);
|
||||
}
|
||||
}
|
||||
|
||||
static void mix_voice_samples(struct hle_t* hle, musyx_t *musyx,
|
||||
uint32_t voice_ptr, const int16_t *samples,
|
||||
unsigned segbase, unsigned offset, uint32_t last_sample_ptr)
|
||||
{
|
||||
int i, k;
|
||||
|
||||
/* parse VOICE structure */
|
||||
const uint16_t pitch_q16 = *dram_u16(hle, voice_ptr + VOICE_PITCH_Q16);
|
||||
const uint16_t pitch_shift = *dram_u16(hle, voice_ptr + VOICE_PITCH_SHIFT); /* Q4.12 */
|
||||
|
||||
const uint16_t end_point = *dram_u16(hle, voice_ptr + VOICE_END_POINT);
|
||||
const uint16_t restart_point = *dram_u16(hle, voice_ptr + VOICE_RESTART_POINT);
|
||||
|
||||
const uint16_t u16_4e = *dram_u16(hle, voice_ptr + VOICE_U16_4E);
|
||||
|
||||
/* init values and pointers */
|
||||
const int16_t *sample = samples + segbase + offset + u16_4e;
|
||||
const int16_t *const sample_end = samples + segbase + end_point;
|
||||
const int16_t *const sample_restart = samples + (restart_point & 0x7fff) +
|
||||
(((restart_point & 0x8000) != 0) ? 0x000 : segbase);
|
||||
|
||||
|
||||
uint32_t pitch_accu = pitch_q16;
|
||||
uint32_t pitch_step = pitch_shift << 4;
|
||||
|
||||
int32_t v4_env[4];
|
||||
int32_t v4_env_step[4];
|
||||
int16_t *v4_dst[4];
|
||||
int16_t v4[4];
|
||||
|
||||
dram_load_u32(hle, (uint32_t *)v4_env, voice_ptr + VOICE_ENV_BEGIN, 4);
|
||||
dram_load_u32(hle, (uint32_t *)v4_env_step, voice_ptr + VOICE_ENV_STEP, 4);
|
||||
|
||||
v4_dst[0] = musyx->left;
|
||||
v4_dst[1] = musyx->right;
|
||||
v4_dst[2] = musyx->cc0;
|
||||
v4_dst[3] = musyx->e50;
|
||||
|
||||
HleVerboseMessage(hle->user_defined,
|
||||
"Voice debug: segbase=%d"
|
||||
"\tu16_4e=%04x\n"
|
||||
"\tpitch: frac0=%04x shift=%04x\n"
|
||||
"\tend_point=%04x restart_point=%04x\n"
|
||||
"\tenv = %08x %08x %08x %08x\n"
|
||||
"\tenv_step = %08x %08x %08x %08x\n",
|
||||
segbase,
|
||||
u16_4e,
|
||||
pitch_q16, pitch_shift,
|
||||
end_point, restart_point,
|
||||
v4_env[0], v4_env[1], v4_env[2], v4_env[3],
|
||||
v4_env_step[0], v4_env_step[1], v4_env_step[2], v4_env_step[3]);
|
||||
|
||||
for (i = 0; i < SUBFRAME_SIZE; ++i) {
|
||||
/* update sample and lut pointers and then pitch_accu */
|
||||
const int16_t *lut = (RESAMPLE_LUT + ((pitch_accu & 0xfc00) >> 8));
|
||||
int dist;
|
||||
int16_t v;
|
||||
|
||||
sample += (pitch_accu >> 16);
|
||||
pitch_accu &= 0xffff;
|
||||
pitch_accu += pitch_step;
|
||||
|
||||
/* handle end/restart points */
|
||||
dist = sample - sample_end;
|
||||
if (dist >= 0)
|
||||
sample = sample_restart + dist;
|
||||
|
||||
/* apply resample filter */
|
||||
v = clamp_s16(dot4(sample, lut));
|
||||
|
||||
for (k = 0; k < 4; ++k) {
|
||||
/* envmix */
|
||||
int32_t accu = (v * (v4_env[k] >> 16)) >> 15;
|
||||
v4[k] = clamp_s16(accu);
|
||||
*(v4_dst[k]) = clamp_s16(accu + *(v4_dst[k]));
|
||||
|
||||
/* update envelopes and dst pointers */
|
||||
++(v4_dst[k]);
|
||||
v4_env[k] += v4_env_step[k];
|
||||
}
|
||||
}
|
||||
|
||||
/* save last resampled sample */
|
||||
dram_store_u16(hle, (uint16_t *)v4, last_sample_ptr, 4);
|
||||
|
||||
HleVerboseMessage(hle->user_defined,
|
||||
"last_sample = %04x %04x %04x %04x",
|
||||
v4[0], v4[1], v4[2], v4[3]);
|
||||
}
|
||||
|
||||
|
||||
static void sfx_stage(struct hle_t* hle, mix_sfx_with_main_subframes_t mix_sfx_with_main_subframes,
|
||||
musyx_t *musyx, uint32_t sfx_ptr, uint16_t idx)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
int16_t buffer[SUBFRAME_SIZE + 4];
|
||||
int16_t *subframe = buffer + 4;
|
||||
|
||||
uint32_t tap_delays[8];
|
||||
int16_t tap_gains[8];
|
||||
int16_t fir4_hcoeffs[4];
|
||||
|
||||
int16_t delayed[SUBFRAME_SIZE];
|
||||
int dpos, dlength;
|
||||
|
||||
const uint32_t pos = idx * SUBFRAME_SIZE;
|
||||
|
||||
uint32_t cbuffer_ptr;
|
||||
uint32_t cbuffer_length;
|
||||
uint16_t tap_count;
|
||||
int16_t fir4_hgain;
|
||||
uint16_t sfx_gains[2];
|
||||
|
||||
HleVerboseMessage(hle->user_defined, "SFX: %08x, idx=%d", sfx_ptr, idx);
|
||||
|
||||
if (sfx_ptr == 0)
|
||||
return;
|
||||
|
||||
/* load sfx parameters */
|
||||
cbuffer_ptr = *dram_u32(hle, sfx_ptr + SFX_CBUFFER_PTR);
|
||||
cbuffer_length = *dram_u32(hle, sfx_ptr + SFX_CBUFFER_LENGTH);
|
||||
|
||||
tap_count = *dram_u16(hle, sfx_ptr + SFX_TAP_COUNT);
|
||||
|
||||
dram_load_u32(hle, tap_delays, sfx_ptr + SFX_TAP_DELAYS, 8);
|
||||
dram_load_u16(hle, (uint16_t *)tap_gains, sfx_ptr + SFX_TAP_GAINS, 8);
|
||||
|
||||
fir4_hgain = *dram_u16(hle, sfx_ptr + SFX_FIR4_HGAIN);
|
||||
dram_load_u16(hle, (uint16_t *)fir4_hcoeffs, sfx_ptr + SFX_FIR4_HCOEFFS, 4);
|
||||
|
||||
sfx_gains[0] = *dram_u16(hle, sfx_ptr + SFX_U16_3C);
|
||||
sfx_gains[1] = *dram_u16(hle, sfx_ptr + SFX_U16_3E);
|
||||
|
||||
HleVerboseMessage(hle->user_defined,
|
||||
"cbuffer: ptr=%08x length=%x", cbuffer_ptr,
|
||||
cbuffer_length);
|
||||
|
||||
HleVerboseMessage(hle->user_defined,
|
||||
"fir4: hgain=%04x hcoeff=%04x %04x %04x %04x",
|
||||
fir4_hgain,
|
||||
fir4_hcoeffs[0], fir4_hcoeffs[1], fir4_hcoeffs[2], fir4_hcoeffs[3]);
|
||||
|
||||
HleVerboseMessage(hle->user_defined,
|
||||
"tap count=%d\n"
|
||||
"delays: %08x %08x %08x %08x %08x %08x %08x %08x\n"
|
||||
"gains: %04x %04x %04x %04x %04x %04x %04x %04x",
|
||||
tap_count,
|
||||
tap_delays[0], tap_delays[1], tap_delays[2], tap_delays[3],
|
||||
tap_delays[4], tap_delays[5], tap_delays[6], tap_delays[7],
|
||||
tap_gains[0], tap_gains[1], tap_gains[2], tap_gains[3],
|
||||
tap_gains[4], tap_gains[5], tap_gains[6], tap_gains[7]);
|
||||
|
||||
HleVerboseMessage(hle->user_defined, "sfx_gains=%04x %04x", sfx_gains[0], sfx_gains[1]);
|
||||
|
||||
/* mix up to 8 delayed subframes */
|
||||
memset(subframe, 0, SUBFRAME_SIZE * sizeof(subframe[0]));
|
||||
for (i = 0; i < tap_count; ++i) {
|
||||
|
||||
dpos = pos - tap_delays[i];
|
||||
if (dpos <= 0)
|
||||
dpos += cbuffer_length;
|
||||
dlength = SUBFRAME_SIZE;
|
||||
|
||||
if ((uint32_t)(dpos + SUBFRAME_SIZE) > cbuffer_length) {
|
||||
dlength = cbuffer_length - dpos;
|
||||
dram_load_u16(hle, (uint16_t *)delayed + dlength, cbuffer_ptr, SUBFRAME_SIZE - dlength);
|
||||
}
|
||||
|
||||
dram_load_u16(hle, (uint16_t *)delayed, cbuffer_ptr + dpos * 2, dlength);
|
||||
|
||||
mix_subframes(subframe, delayed, tap_gains[i]);
|
||||
}
|
||||
|
||||
/* add resulting subframe to main subframes */
|
||||
mix_sfx_with_main_subframes(musyx, subframe, sfx_gains);
|
||||
|
||||
/* apply FIR4 filter and writeback filtered result */
|
||||
memcpy(buffer, musyx->subframe_740_last4, 4 * sizeof(int16_t));
|
||||
memcpy(musyx->subframe_740_last4, subframe + SUBFRAME_SIZE - 4, 4 * sizeof(int16_t));
|
||||
mix_fir4(musyx->e50, buffer + 1, fir4_hgain, fir4_hcoeffs);
|
||||
dram_store_u16(hle, (uint16_t *)musyx->e50, cbuffer_ptr + pos * 2, SUBFRAME_SIZE);
|
||||
}
|
||||
|
||||
static void mix_sfx_with_main_subframes_v1(musyx_t *musyx, const int16_t *subframe,
|
||||
const uint16_t* UNUSED(gains))
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < SUBFRAME_SIZE; ++i) {
|
||||
int16_t v = subframe[i];
|
||||
musyx->left[i] = clamp_s16(musyx->left[i] + v);
|
||||
musyx->right[i] = clamp_s16(musyx->right[i] + v);
|
||||
}
|
||||
}
|
||||
|
||||
static void mix_sfx_with_main_subframes_v2(musyx_t *musyx, const int16_t *subframe,
|
||||
const uint16_t* gains)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < SUBFRAME_SIZE; ++i) {
|
||||
int16_t v = subframe[i];
|
||||
int16_t v1 = (int32_t)(v * gains[0]) >> 16;
|
||||
int16_t v2 = (int32_t)(v * gains[1]) >> 16;
|
||||
|
||||
musyx->left[i] = clamp_s16(musyx->left[i] + v1);
|
||||
musyx->right[i] = clamp_s16(musyx->right[i] + v1);
|
||||
musyx->cc0[i] = clamp_s16(musyx->cc0[i] + v2);
|
||||
}
|
||||
}
|
||||
|
||||
static void mix_samples(int16_t *y, int16_t x, int16_t hgain)
|
||||
{
|
||||
*y = clamp_s16(*y + ((x * hgain + 0x4000) >> 15));
|
||||
}
|
||||
|
||||
static void mix_subframes(int16_t *y, const int16_t *x, int16_t hgain)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < SUBFRAME_SIZE; ++i)
|
||||
mix_samples(&y[i], x[i], hgain);
|
||||
}
|
||||
|
||||
static void mix_fir4(int16_t *y, const int16_t *x, int16_t hgain, const int16_t *hcoeffs)
|
||||
{
|
||||
unsigned int i;
|
||||
int32_t h[4];
|
||||
|
||||
h[0] = (hgain * hcoeffs[0]) >> 15;
|
||||
h[1] = (hgain * hcoeffs[1]) >> 15;
|
||||
h[2] = (hgain * hcoeffs[2]) >> 15;
|
||||
h[3] = (hgain * hcoeffs[3]) >> 15;
|
||||
|
||||
for (i = 0; i < SUBFRAME_SIZE; ++i) {
|
||||
int32_t v = (h[0] * x[i] + h[1] * x[i + 1] + h[2] * x[i + 2] + h[3] * x[i + 3]) >> 15;
|
||||
y[i] = clamp_s16(y[i] + v);
|
||||
}
|
||||
}
|
||||
|
||||
static void interleave_stage_v1(struct hle_t* hle, musyx_t *musyx, uint32_t output_ptr)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
int16_t base_left;
|
||||
int16_t base_right;
|
||||
|
||||
int16_t *left;
|
||||
int16_t *right;
|
||||
uint32_t *dst;
|
||||
|
||||
HleVerboseMessage(hle->user_defined, "interleave: %08x", output_ptr);
|
||||
|
||||
base_left = clamp_s16(musyx->base_vol[0]);
|
||||
base_right = clamp_s16(musyx->base_vol[1]);
|
||||
|
||||
left = musyx->left;
|
||||
right = musyx->right;
|
||||
dst = dram_u32(hle, output_ptr);
|
||||
|
||||
for (i = 0; i < SUBFRAME_SIZE; ++i) {
|
||||
uint16_t l = clamp_s16(*(left++) + base_left);
|
||||
uint16_t r = clamp_s16(*(right++) + base_right);
|
||||
|
||||
*(dst++) = (l << 16) | r;
|
||||
}
|
||||
}
|
||||
|
||||
static void interleave_stage_v2(struct hle_t* hle, musyx_t *musyx,
|
||||
uint16_t mask_16, uint32_t ptr_18,
|
||||
uint32_t ptr_1c, uint32_t output_ptr)
|
||||
{
|
||||
unsigned i, k;
|
||||
int16_t subframe[SUBFRAME_SIZE];
|
||||
uint32_t *dst;
|
||||
uint16_t mask;
|
||||
|
||||
HleVerboseMessage(hle->user_defined,
|
||||
"mask_16=%04x ptr_18=%08x ptr_1c=%08x output_ptr=%08x",
|
||||
mask_16, ptr_18, ptr_1c, output_ptr);
|
||||
|
||||
/* compute L_total, R_total and update subframe @ptr_1c */
|
||||
memset(subframe, 0, SUBFRAME_SIZE*sizeof(subframe[0]));
|
||||
|
||||
for(i = 0; i < SUBFRAME_SIZE; ++i) {
|
||||
int16_t v = *dram_u16(hle, ptr_1c + i*2);
|
||||
musyx->left[i] = v;
|
||||
musyx->right[i] = clamp_s16(-v);
|
||||
}
|
||||
|
||||
for (k = 0, mask = 1; k < 8; ++k, mask <<= 1, ptr_18 += 8) {
|
||||
int16_t hgain;
|
||||
uint32_t address;
|
||||
|
||||
if ((mask_16 & mask) == 0)
|
||||
continue;
|
||||
|
||||
address = *dram_u32(hle, ptr_18);
|
||||
hgain = *dram_u16(hle, ptr_18 + 4);
|
||||
|
||||
for(i = 0; i < SUBFRAME_SIZE; ++i, address += 2) {
|
||||
mix_samples(&musyx->left[i], *dram_u16(hle, address), hgain);
|
||||
mix_samples(&musyx->right[i], *dram_u16(hle, address + 2*SUBFRAME_SIZE), hgain);
|
||||
mix_samples(&subframe[i], *dram_u16(hle, address + 4*SUBFRAME_SIZE), hgain);
|
||||
}
|
||||
}
|
||||
|
||||
/* interleave L_total and R_total */
|
||||
dst = dram_u32(hle, output_ptr);
|
||||
for(i = 0; i < SUBFRAME_SIZE; ++i) {
|
||||
uint16_t l = musyx->left[i];
|
||||
uint16_t r = musyx->right[i];
|
||||
*(dst++) = (l << 16) | r;
|
||||
}
|
||||
|
||||
/* writeback subframe @ptr_1c */
|
||||
dram_store_u16(hle, (uint16_t*)subframe, ptr_1c, SUBFRAME_SIZE);
|
||||
}
|
|
@ -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 */
|
||||
|
|
@ -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 <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
|
@ -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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <windows.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -0,0 +1,495 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - plugin.c *
|
||||
* Mupen64Plus homepage: https://mupen64plus.org/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* Copyright (C) 2009 Richard Goedeken *
|
||||
* Copyright (C) 2002 Hacktarux *
|
||||
* *
|
||||
* 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 <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#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"
|
||||
|
||||
#include "osal_dynamiclib.h"
|
||||
|
||||
#define CONFIG_API_VERSION 0x020100
|
||||
#define CONFIG_PARAM_VERSION 1.00
|
||||
|
||||
#define RSP_API_VERSION 0x20000
|
||||
#define RSP_HLE_VERSION 0x020500
|
||||
#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;
|
||||
static void (*l_CheckInterrupts)(void) = NULL;
|
||||
static void (*l_ProcessDlistList)(void) = NULL;
|
||||
static void (*l_ProcessAlistList)(void) = NULL;
|
||||
static void (*l_ProcessRdpList)(void) = NULL;
|
||||
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_ConfigSaveSection ConfigSaveSection = 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];
|
||||
|
||||
if (l_DebugCallback == NULL)
|
||||
return;
|
||||
|
||||
vsprintf(msgbuf, message, args);
|
||||
|
||||
(*l_DebugCallback)(l_DebugCallContext, level, msgbuf);
|
||||
}
|
||||
|
||||
/* Global functions needed by HLE core */
|
||||
void HleVerboseMessage(void* UNUSED(user_defined), const char *message, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
DebugMessage(M64MSG_VERBOSE, message, args);
|
||||
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;
|
||||
va_start(args, message);
|
||||
DebugMessage(M64MSG_ERROR, message, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void HleWarnMessage(void* UNUSED(user_defined), const char *message, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
DebugMessage(M64MSG_WARNING, message, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void HleCheckInterrupts(void* UNUSED(user_defined))
|
||||
{
|
||||
if (l_CheckInterrupts == NULL)
|
||||
return;
|
||||
|
||||
(*l_CheckInterrupts)();
|
||||
}
|
||||
|
||||
void HleProcessDlistList(void* UNUSED(user_defined))
|
||||
{
|
||||
if (l_ProcessDlistList == NULL)
|
||||
return;
|
||||
|
||||
(*l_ProcessDlistList)();
|
||||
}
|
||||
|
||||
void HleProcessAlistList(void* UNUSED(user_defined))
|
||||
{
|
||||
if (l_ProcessAlistList == NULL)
|
||||
return;
|
||||
|
||||
(*l_ProcessAlistList)();
|
||||
}
|
||||
|
||||
void HleProcessRdpList(void* UNUSED(user_defined))
|
||||
{
|
||||
if (l_ProcessRdpList == NULL)
|
||||
return;
|
||||
|
||||
(*l_ProcessRdpList)();
|
||||
}
|
||||
|
||||
void HleShowCFB(void* UNUSED(user_defined))
|
||||
{
|
||||
if (l_ShowCFB == NULL)
|
||||
return;
|
||||
|
||||
(*l_ShowCFB)();
|
||||
}
|
||||
|
||||
|
||||
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 CoreLibHandle, void *Context,
|
||||
void (*DebugCallback)(void *, int, const char *))
|
||||
{
|
||||
ptr_CoreGetAPIVersions CoreAPIVersionFunc;
|
||||
int ConfigAPIVersion, DebugAPIVersion, VidextAPIVersion, bSaveConfig;
|
||||
float fConfigParamsVersion = 0.0f;
|
||||
|
||||
if (l_PluginInit)
|
||||
return M64ERR_ALREADY_INIT;
|
||||
|
||||
/* first thing is to set the callback function for debug info */
|
||||
l_DebugCallback = DebugCallback;
|
||||
l_DebugCallContext = Context;
|
||||
|
||||
/* 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");
|
||||
ConfigSaveSection = (ptr_ConfigSaveSection) osal_dynlib_getproc(CoreLibHandle, "ConfigSaveSection");
|
||||
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;
|
||||
|
||||
/* ConfigSaveSection was added in Config API v2.1.0 */
|
||||
if (ConfigAPIVersion >= 0x020100 && !ConfigSaveSection)
|
||||
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 */
|
||||
bSaveConfig = 0;
|
||||
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);
|
||||
bSaveConfig = 1;
|
||||
}
|
||||
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);
|
||||
bSaveConfig = 1;
|
||||
}
|
||||
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);
|
||||
bSaveConfig = 1;
|
||||
}
|
||||
|
||||
/* 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");
|
||||
|
||||
if (bSaveConfig && ConfigAPIVersion >= 0x020100)
|
||||
ConfigSaveSection(RSP_HLE_CONFIG_SECTION);
|
||||
|
||||
l_CoreHandle = CoreLibHandle;
|
||||
|
||||
l_PluginInit = 1;
|
||||
return M64ERR_SUCCESS;
|
||||
}
|
||||
|
||||
EXPORT m64p_error CALL PluginShutdown(void)
|
||||
{
|
||||
if (!l_PluginInit)
|
||||
return M64ERR_NOT_INIT;
|
||||
|
||||
/* reset some local variable */
|
||||
l_DebugCallback = NULL;
|
||||
l_DebugCallContext = NULL;
|
||||
l_CoreHandle = NULL;
|
||||
|
||||
teardown_rsp_fallback();
|
||||
|
||||
l_PluginInit = 0;
|
||||
return M64ERR_SUCCESS;
|
||||
}
|
||||
|
||||
EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities)
|
||||
{
|
||||
/* set version info */
|
||||
if (PluginType != NULL)
|
||||
*PluginType = M64PLUGIN_RSP;
|
||||
|
||||
if (PluginVersion != NULL)
|
||||
*PluginVersion = RSP_HLE_VERSION;
|
||||
|
||||
if (APIVersion != NULL)
|
||||
*APIVersion = RSP_PLUGIN_API_VERSION;
|
||||
|
||||
if (PluginNamePtr != NULL)
|
||||
*PluginNamePtr = "Hacktarux/Azimer High-Level Emulation RSP Plugin";
|
||||
|
||||
if (Capabilities != NULL)
|
||||
*Capabilities = 0;
|
||||
|
||||
return M64ERR_SUCCESS;
|
||||
}
|
||||
|
||||
EXPORT unsigned int CALL DoRspCycles(unsigned int Cycles)
|
||||
{
|
||||
hle_execute(&g_hle);
|
||||
return Cycles;
|
||||
}
|
||||
|
||||
EXPORT void CALL InitiateRSP(RSP_INFO Rsp_Info, unsigned int* CycleCount)
|
||||
{
|
||||
hle_init(&g_hle,
|
||||
Rsp_Info.RDRAM,
|
||||
Rsp_Info.DMEM,
|
||||
Rsp_Info.IMEM,
|
||||
Rsp_Info.MI_INTR_REG,
|
||||
Rsp_Info.SP_MEM_ADDR_REG,
|
||||
Rsp_Info.SP_DRAM_ADDR_REG,
|
||||
Rsp_Info.SP_RD_LEN_REG,
|
||||
Rsp_Info.SP_WR_LEN_REG,
|
||||
Rsp_Info.SP_STATUS_REG,
|
||||
Rsp_Info.SP_DMA_FULL_REG,
|
||||
Rsp_Info.SP_DMA_BUSY_REG,
|
||||
Rsp_Info.SP_PC_REG,
|
||||
Rsp_Info.SP_SEMAPHORE_REG,
|
||||
Rsp_Info.DPC_START_REG,
|
||||
Rsp_Info.DPC_END_REG,
|
||||
Rsp_Info.DPC_CURRENT_REG,
|
||||
Rsp_Info.DPC_STATUS_REG,
|
||||
Rsp_Info.DPC_CLOCK_REG,
|
||||
Rsp_Info.DPC_BUFBUSY_REG,
|
||||
Rsp_Info.DPC_PIPEBUSY_REG,
|
||||
Rsp_Info.DPC_TMEM_REG,
|
||||
NULL);
|
||||
|
||||
l_CheckInterrupts = Rsp_Info.CheckInterrupts;
|
||||
l_ProcessDlistList = Rsp_Info.ProcessDlistList;
|
||||
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));
|
||||
|
||||
m64p_rom_header rom_header;
|
||||
CoreDoCommand(M64CMD_ROM_GET_HEADER, sizeof(rom_header), &rom_header);
|
||||
|
||||
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)
|
||||
{
|
||||
/* notify fallback plugin */
|
||||
if (l_RomClosed) {
|
||||
l_RomClosed();
|
||||
}
|
||||
}
|
|
@ -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 <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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);
|
||||
}
|
|
@ -1,951 +0,0 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - ucode1.cpp *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2009 Richard Goedeken *
|
||||
* Copyright (C) 2002 Hacktarux *
|
||||
* *
|
||||
* 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 <string.h>
|
||||
|
||||
extern "C" {
|
||||
#include "hle.h"
|
||||
#include "alist_internal.h"
|
||||
}
|
||||
|
||||
//#include "rsp.h"
|
||||
//#define SAFE_MEMORY
|
||||
/*
|
||||
#ifndef SAFE_MEMORY
|
||||
# define wr8 (src , address);
|
||||
# define rd8 (dest, address);
|
||||
# define wr16 (src, address);
|
||||
# define rd16 (dest, address);
|
||||
# define wr32 (src, address);
|
||||
# define rd32 (dest, address);
|
||||
# define wr64 (src, address);
|
||||
# define rd64 (dest, address);
|
||||
# define dmamem (dest, src, size) memcpy (dest, src, size);
|
||||
# define clrmem (dest, size) memset (dest, 0, size);
|
||||
#else
|
||||
void wr8 (u8 src, void *address);
|
||||
void rd8 (u8 dest, void *address);
|
||||
void wr16 (u16 src, void *address);
|
||||
void rd16 (u16 dest, void *address);
|
||||
void wr32 (u16 src, void *address);
|
||||
void rd32 (u16 dest, void *address);
|
||||
void wr64 (u16 src, void *address);
|
||||
void rd64 (u16 dest, void *address);
|
||||
void dmamem (void *dest, void *src, int size);
|
||||
void clrmem (void *dest, int size);
|
||||
#endif
|
||||
*/
|
||||
/******** DMEM Memory Map for ABI 1 ***************
|
||||
Address/Range Description
|
||||
------------- -------------------------------
|
||||
0x000..0x2BF UCodeData
|
||||
0x000-0x00F Constants - 0000 0001 0002 FFFF 0020 0800 7FFF 4000
|
||||
0x010-0x02F Function Jump Table (16 Functions * 2 bytes each = 32) 0x20
|
||||
0x030-0x03F Constants - F000 0F00 00F0 000F 0001 0010 0100 1000
|
||||
0x040-0x03F Used by the Envelope Mixer (But what for?)
|
||||
0x070-0x07F Used by the Envelope Mixer (But what for?)
|
||||
0x2C0..0x31F <Unknown>
|
||||
0x320..0x35F Segments
|
||||
0x360 Audio In Buffer (Location)
|
||||
0x362 Audio Out Buffer (Location)
|
||||
0x364 Audio Buffer Size (Location)
|
||||
0x366 Initial Volume for Left Channel
|
||||
0x368 Initial Volume for Right Channel
|
||||
0x36A Auxillary Buffer #1 (Location)
|
||||
0x36C Auxillary Buffer #2 (Location)
|
||||
0x36E Auxillary Buffer #3 (Location)
|
||||
0x370 Loop Value (shared location)
|
||||
0x370 Target Volume (Left)
|
||||
0x372 Ramp?? (Left)
|
||||
0x374 Rate?? (Left)
|
||||
0x376 Target Volume (Right)
|
||||
0x378 Ramp?? (Right)
|
||||
0x37A Rate?? (Right)
|
||||
0x37C Dry??
|
||||
0x37E Wet??
|
||||
0x380..0x4BF Alist data
|
||||
0x4C0..0x4FF ADPCM CodeBook
|
||||
0x500..0x5BF <Unknown>
|
||||
0x5C0..0xF7F Buffers...
|
||||
0xF80..0xFFF <Unknown>
|
||||
***************************************************/
|
||||
#ifdef USE_EXPANSION
|
||||
#define MEMMASK 0x7FFFFF
|
||||
#else
|
||||
#define MEMMASK 0x3FFFFF
|
||||
#endif
|
||||
|
||||
static void SPNOOP (u32 inst1, u32 inst2) {
|
||||
//MessageBox (NULL, "Unknown Audio Command in ABI 1", "Audio HLE Error", MB_OK);
|
||||
}
|
||||
|
||||
u32 SEGMENTS[0x10]; // 0x0320
|
||||
// T8 = 0x360
|
||||
u16 AudioInBuffer; // 0x0000(T8)
|
||||
u16 AudioOutBuffer; // 0x0002(T8)
|
||||
u16 AudioCount; // 0x0004(T8)
|
||||
s16 Vol_Left; // 0x0006(T8)
|
||||
s16 Vol_Right; // 0x0008(T8)
|
||||
u16 AudioAuxA; // 0x000A(T8)
|
||||
u16 AudioAuxC; // 0x000C(T8)
|
||||
u16 AudioAuxE; // 0x000E(T8)
|
||||
u32 loopval; // 0x0010(T8) // Value set by A_SETLOOP : Possible conflict with SETVOLUME???
|
||||
s16 VolTrg_Left; // 0x0010(T8)
|
||||
s32 VolRamp_Left; // m_LeftVolTarget
|
||||
//u16 VolRate_Left; // m_LeftVolRate
|
||||
s16 VolTrg_Right; // m_RightVol
|
||||
s32 VolRamp_Right; // m_RightVolTarget
|
||||
//u16 VolRate_Right; // m_RightVolRate
|
||||
s16 Env_Dry; // 0x001C(T8)
|
||||
s16 Env_Wet; // 0x001E(T8)
|
||||
|
||||
u8 BufferSpace[0x10000];
|
||||
|
||||
short hleMixerWorkArea[256];
|
||||
u16 adpcmtable[0x88];
|
||||
|
||||
extern const u16 ResampleLUT [0x200] = {
|
||||
0x0C39, 0x66AD, 0x0D46, 0xFFDF, 0x0B39, 0x6696, 0x0E5F, 0xFFD8,
|
||||
0x0A44, 0x6669, 0x0F83, 0xFFD0, 0x095A, 0x6626, 0x10B4, 0xFFC8,
|
||||
0x087D, 0x65CD, 0x11F0, 0xFFBF, 0x07AB, 0x655E, 0x1338, 0xFFB6,
|
||||
0x06E4, 0x64D9, 0x148C, 0xFFAC, 0x0628, 0x643F, 0x15EB, 0xFFA1,
|
||||
0x0577, 0x638F, 0x1756, 0xFF96, 0x04D1, 0x62CB, 0x18CB, 0xFF8A,
|
||||
0x0435, 0x61F3, 0x1A4C, 0xFF7E, 0x03A4, 0x6106, 0x1BD7, 0xFF71,
|
||||
0x031C, 0x6007, 0x1D6C, 0xFF64, 0x029F, 0x5EF5, 0x1F0B, 0xFF56,
|
||||
0x022A, 0x5DD0, 0x20B3, 0xFF48, 0x01BE, 0x5C9A, 0x2264, 0xFF3A,
|
||||
0x015B, 0x5B53, 0x241E, 0xFF2C, 0x0101, 0x59FC, 0x25E0, 0xFF1E,
|
||||
0x00AE, 0x5896, 0x27A9, 0xFF10, 0x0063, 0x5720, 0x297A, 0xFF02,
|
||||
0x001F, 0x559D, 0x2B50, 0xFEF4, 0xFFE2, 0x540D, 0x2D2C, 0xFEE8,
|
||||
0xFFAC, 0x5270, 0x2F0D, 0xFEDB, 0xFF7C, 0x50C7, 0x30F3, 0xFED0,
|
||||
0xFF53, 0x4F14, 0x32DC, 0xFEC6, 0xFF2E, 0x4D57, 0x34C8, 0xFEBD,
|
||||
0xFF0F, 0x4B91, 0x36B6, 0xFEB6, 0xFEF5, 0x49C2, 0x38A5, 0xFEB0,
|
||||
0xFEDF, 0x47ED, 0x3A95, 0xFEAC, 0xFECE, 0x4611, 0x3C85, 0xFEAB,
|
||||
0xFEC0, 0x4430, 0x3E74, 0xFEAC, 0xFEB6, 0x424A, 0x4060, 0xFEAF,
|
||||
0xFEAF, 0x4060, 0x424A, 0xFEB6, 0xFEAC, 0x3E74, 0x4430, 0xFEC0,
|
||||
0xFEAB, 0x3C85, 0x4611, 0xFECE, 0xFEAC, 0x3A95, 0x47ED, 0xFEDF,
|
||||
0xFEB0, 0x38A5, 0x49C2, 0xFEF5, 0xFEB6, 0x36B6, 0x4B91, 0xFF0F,
|
||||
0xFEBD, 0x34C8, 0x4D57, 0xFF2E, 0xFEC6, 0x32DC, 0x4F14, 0xFF53,
|
||||
0xFED0, 0x30F3, 0x50C7, 0xFF7C, 0xFEDB, 0x2F0D, 0x5270, 0xFFAC,
|
||||
0xFEE8, 0x2D2C, 0x540D, 0xFFE2, 0xFEF4, 0x2B50, 0x559D, 0x001F,
|
||||
0xFF02, 0x297A, 0x5720, 0x0063, 0xFF10, 0x27A9, 0x5896, 0x00AE,
|
||||
0xFF1E, 0x25E0, 0x59FC, 0x0101, 0xFF2C, 0x241E, 0x5B53, 0x015B,
|
||||
0xFF3A, 0x2264, 0x5C9A, 0x01BE, 0xFF48, 0x20B3, 0x5DD0, 0x022A,
|
||||
0xFF56, 0x1F0B, 0x5EF5, 0x029F, 0xFF64, 0x1D6C, 0x6007, 0x031C,
|
||||
0xFF71, 0x1BD7, 0x6106, 0x03A4, 0xFF7E, 0x1A4C, 0x61F3, 0x0435,
|
||||
0xFF8A, 0x18CB, 0x62CB, 0x04D1, 0xFF96, 0x1756, 0x638F, 0x0577,
|
||||
0xFFA1, 0x15EB, 0x643F, 0x0628, 0xFFAC, 0x148C, 0x64D9, 0x06E4,
|
||||
0xFFB6, 0x1338, 0x655E, 0x07AB, 0xFFBF, 0x11F0, 0x65CD, 0x087D,
|
||||
0xFFC8, 0x10B4, 0x6626, 0x095A, 0xFFD0, 0x0F83, 0x6669, 0x0A44,
|
||||
0xFFD8, 0x0E5F, 0x6696, 0x0B39, 0xFFDF, 0x0D46, 0x66AD, 0x0C39
|
||||
};
|
||||
|
||||
static void CLEARBUFF (u32 inst1, u32 inst2) {
|
||||
u32 addr = (u32)(inst1 & 0xffff);
|
||||
u32 count = (u32)(inst2 & 0xffff);
|
||||
addr &= 0xFFFC;
|
||||
memset(BufferSpace+addr, 0, (count+3)&0xFFFC);
|
||||
}
|
||||
|
||||
//FILE *dfile = fopen ("d:\\envmix.txt", "wt");
|
||||
|
||||
static void ENVMIXER (u32 inst1, u32 inst2) {
|
||||
//static int envmixcnt = 0;
|
||||
u8 flags = (u8)((inst1 >> 16) & 0xff);
|
||||
u32 addy = (inst2 & 0xFFFFFF);// + SEGMENTS[(inst2>>24)&0xf];
|
||||
//static
|
||||
// ********* Make sure these conditions are met... ***********
|
||||
/*if ((AudioInBuffer | AudioOutBuffer | AudioAuxA | AudioAuxC | AudioAuxE | AudioCount) & 0x3) {
|
||||
MessageBox (NULL, "Unaligned EnvMixer... please report this to Azimer with the following information: RomTitle, Place in the rom it occurred, and any save state just before the error", "AudioHLE Error", MB_OK);
|
||||
}*/
|
||||
// ------------------------------------------------------------
|
||||
short *inp=(short *)(BufferSpace+AudioInBuffer);
|
||||
short *out=(short *)(BufferSpace+AudioOutBuffer);
|
||||
short *aux1=(short *)(BufferSpace+AudioAuxA);
|
||||
short *aux2=(short *)(BufferSpace+AudioAuxC);
|
||||
short *aux3=(short *)(BufferSpace+AudioAuxE);
|
||||
s32 MainR;
|
||||
s32 MainL;
|
||||
s32 AuxR;
|
||||
s32 AuxL;
|
||||
int i1,o1,a1,a2=0,a3=0;
|
||||
unsigned short AuxIncRate=1;
|
||||
short zero[8];
|
||||
memset(zero,0,16);
|
||||
s32 LVol, RVol;
|
||||
s32 LAcc, RAcc;
|
||||
s32 LTrg, RTrg;
|
||||
s16 Wet, Dry;
|
||||
u32 ptr = 0;
|
||||
s32 RRamp, LRamp;
|
||||
s32 LAdderStart, RAdderStart, LAdderEnd, RAdderEnd;
|
||||
s32 oMainR, oMainL, oAuxR, oAuxL;
|
||||
|
||||
//envmixcnt++;
|
||||
|
||||
//fprintf (dfile, "\n----------------------------------------------------\n");
|
||||
if (flags & A_INIT) {
|
||||
LVol = ((Vol_Left * (s32)VolRamp_Left));
|
||||
RVol = ((Vol_Right * (s32)VolRamp_Right));
|
||||
Wet = (s16)Env_Wet; Dry = (s16)Env_Dry; // Save Wet/Dry values
|
||||
LTrg = (VolTrg_Left << 16); RTrg = (VolTrg_Right << 16); // Save Current Left/Right Targets
|
||||
LAdderStart = Vol_Left << 16;
|
||||
RAdderStart = Vol_Right << 16;
|
||||
LAdderEnd = LVol;
|
||||
RAdderEnd = RVol;
|
||||
RRamp = VolRamp_Right;
|
||||
LRamp = VolRamp_Left;
|
||||
} else {
|
||||
// Load LVol, RVol, LAcc, and RAcc (all 32bit)
|
||||
// Load Wet, Dry, LTrg, RTrg
|
||||
memcpy((u8 *)hleMixerWorkArea, (rsp.RDRAM+addy), 80);
|
||||
Wet = *(s16 *)(hleMixerWorkArea + 0); // 0-1
|
||||
Dry = *(s16 *)(hleMixerWorkArea + 2); // 2-3
|
||||
LTrg = *(s32 *)(hleMixerWorkArea + 4); // 4-5
|
||||
RTrg = *(s32 *)(hleMixerWorkArea + 6); // 6-7
|
||||
LRamp= *(s32 *)(hleMixerWorkArea + 8); // 8-9 (hleMixerWorkArea is a 16bit pointer)
|
||||
RRamp= *(s32 *)(hleMixerWorkArea + 10); // 10-11
|
||||
LAdderEnd = *(s32 *)(hleMixerWorkArea + 12); // 12-13
|
||||
RAdderEnd = *(s32 *)(hleMixerWorkArea + 14); // 14-15
|
||||
LAdderStart = *(s32 *)(hleMixerWorkArea + 16); // 12-13
|
||||
RAdderStart = *(s32 *)(hleMixerWorkArea + 18); // 14-15
|
||||
}
|
||||
|
||||
if(!(flags&A_AUX)) {
|
||||
AuxIncRate=0;
|
||||
aux2=aux3=zero;
|
||||
}
|
||||
|
||||
oMainL = (Dry * (LTrg>>16) + 0x4000) >> 15;
|
||||
oAuxL = (Wet * (LTrg>>16) + 0x4000) >> 15;
|
||||
oMainR = (Dry * (RTrg>>16) + 0x4000) >> 15;
|
||||
oAuxR = (Wet * (RTrg>>16) + 0x4000) >> 15;
|
||||
|
||||
for (int y = 0; y < AudioCount; y += 0x10) {
|
||||
|
||||
if (LAdderStart != LTrg) {
|
||||
LAcc = LAdderStart;
|
||||
LVol = (LAdderEnd - LAdderStart) >> 3;
|
||||
LAdderEnd = (s32) (((s64)LAdderEnd * (s64)LRamp) >> 16);
|
||||
LAdderStart = (s32) (((s64)LAcc * (s64)LRamp) >> 16);
|
||||
} else {
|
||||
LAcc = LTrg;
|
||||
LVol = 0;
|
||||
}
|
||||
|
||||
if (RAdderStart != RTrg) {
|
||||
RAcc = RAdderStart;
|
||||
RVol = (RAdderEnd - RAdderStart) >> 3;
|
||||
RAdderEnd = (s32) (((s64)RAdderEnd * (s64)RRamp) >> 16);
|
||||
RAdderStart = (s32) (((s64)RAcc * (s64)RRamp) >> 16);
|
||||
} else {
|
||||
RAcc = RTrg;
|
||||
RVol = 0;
|
||||
}
|
||||
|
||||
for (int x = 0; x < 8; x++) {
|
||||
i1=(int)inp[ptr^S];
|
||||
o1=(int)out[ptr^S];
|
||||
a1=(int)aux1[ptr^S];
|
||||
if (AuxIncRate) {
|
||||
a2=(int)aux2[ptr^S];
|
||||
a3=(int)aux3[ptr^S];
|
||||
}
|
||||
// TODO: here...
|
||||
//LAcc = LTrg;
|
||||
//RAcc = RTrg;
|
||||
|
||||
LAcc += LVol;
|
||||
RAcc += RVol;
|
||||
|
||||
if (LVol <= 0) { // Decrementing
|
||||
if (LAcc < LTrg) {
|
||||
LAcc = LTrg;
|
||||
LAdderStart = LTrg;
|
||||
MainL = oMainL;
|
||||
AuxL = oAuxL;
|
||||
} else {
|
||||
MainL = (Dry * ((s32)LAcc>>16) + 0x4000) >> 15;
|
||||
AuxL = (Wet * ((s32)LAcc>>16) + 0x4000) >> 15;
|
||||
}
|
||||
} else {
|
||||
if (LAcc > LTrg) {
|
||||
LAcc = LTrg;
|
||||
LAdderStart = LTrg;
|
||||
MainL = oMainL;
|
||||
AuxL = oAuxL;
|
||||
} else {
|
||||
MainL = (Dry * ((s32)LAcc>>16) + 0x4000) >> 15;
|
||||
AuxL = (Wet * ((s32)LAcc>>16) + 0x4000) >> 15;
|
||||
}
|
||||
}
|
||||
|
||||
if (RVol <= 0) { // Decrementing
|
||||
if (RAcc < RTrg) {
|
||||
RAcc = RTrg;
|
||||
RAdderStart = RTrg;
|
||||
MainR = oMainR;
|
||||
AuxR = oAuxR;
|
||||
} else {
|
||||
MainR = (Dry * ((s32)RAcc>>16) + 0x4000) >> 15;
|
||||
AuxR = (Wet * ((s32)RAcc>>16) + 0x4000) >> 15;
|
||||
}
|
||||
} else {
|
||||
if (RAcc > RTrg) {
|
||||
RAcc = RTrg;
|
||||
RAdderStart = RTrg;
|
||||
MainR = oMainR;
|
||||
AuxR = oAuxR;
|
||||
} else {
|
||||
MainR = (Dry * ((s32)RAcc>>16) + 0x4000) >> 15;
|
||||
AuxR = (Wet * ((s32)RAcc>>16) + 0x4000) >> 15;
|
||||
}
|
||||
}
|
||||
|
||||
//fprintf (dfile, "%04X ", (LAcc>>16));
|
||||
|
||||
/*MainL = (((s64)Dry*2 * (s64)(LAcc>>16)) + 0x8000) >> 16;
|
||||
MainR = (((s64)Dry*2 * (s64)(RAcc>>16)) + 0x8000) >> 16;
|
||||
AuxL = (((s64)Wet*2 * (s64)(LAcc>>16)) + 0x8000) >> 16;
|
||||
AuxR = (((s64)Wet*2 * (s64)(RAcc>>16)) + 0x8000) >> 16;*/
|
||||
/*
|
||||
if (MainL>32767) MainL = 32767;
|
||||
else if (MainL<-32768) MainL = -32768;
|
||||
if (MainR>32767) MainR = 32767;
|
||||
else if (MainR<-32768) MainR = -32768;
|
||||
if (AuxL>32767) AuxL = 32767;
|
||||
else if (AuxL<-32768) AuxR = -32768;
|
||||
if (AuxR>32767) AuxR = 32767;
|
||||
else if (AuxR<-32768) AuxR = -32768;*/
|
||||
/*
|
||||
MainR = (Dry * RTrg + 0x10000) >> 15;
|
||||
MainL = (Dry * LTrg + 0x10000) >> 15;
|
||||
AuxR = (Wet * RTrg + 0x8000) >> 16;
|
||||
AuxL = (Wet * LTrg + 0x8000) >> 16;*/
|
||||
|
||||
o1+=(/*(o1*0x7fff)+*/(i1*MainR)+0x4000)>>15;
|
||||
a1+=(/*(a1*0x7fff)+*/(i1*MainL)+0x4000)>>15;
|
||||
|
||||
/* o1=((s64)(((s64)o1*0xfffe)+((s64)i1*MainR*2)+0x8000)>>16);
|
||||
|
||||
a1=((s64)(((s64)a1*0xfffe)+((s64)i1*MainL*2)+0x8000)>>16);*/
|
||||
|
||||
if(o1>32767) o1=32767;
|
||||
else if(o1<-32768) o1=-32768;
|
||||
|
||||
if(a1>32767) a1=32767;
|
||||
else if(a1<-32768) a1=-32768;
|
||||
|
||||
out[ptr^S]=o1;
|
||||
aux1[ptr^S]=a1;
|
||||
if (AuxIncRate) {
|
||||
//a2=((s64)(((s64)a2*0xfffe)+((s64)i1*AuxR*2)+0x8000)>>16);
|
||||
|
||||
//a3=((s64)(((s64)a3*0xfffe)+((s64)i1*AuxL*2)+0x8000)>>16);
|
||||
a2+=(/*(a2*0x7fff)+*/(i1*AuxR)+0x4000)>>15;
|
||||
a3+=(/*(a3*0x7fff)+*/(i1*AuxL)+0x4000)>>15;
|
||||
|
||||
if(a2>32767) a2=32767;
|
||||
else if(a2<-32768) a2=-32768;
|
||||
|
||||
if(a3>32767) a3=32767;
|
||||
else if(a3<-32768) a3=-32768;
|
||||
|
||||
aux2[ptr^S]=a2;
|
||||
aux3[ptr^S]=a3;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
/*LAcc = LAdderEnd;
|
||||
RAcc = RAdderEnd;*/
|
||||
|
||||
*(s16 *)(hleMixerWorkArea + 0) = Wet; // 0-1
|
||||
*(s16 *)(hleMixerWorkArea + 2) = Dry; // 2-3
|
||||
*(s32 *)(hleMixerWorkArea + 4) = LTrg; // 4-5
|
||||
*(s32 *)(hleMixerWorkArea + 6) = RTrg; // 6-7
|
||||
*(s32 *)(hleMixerWorkArea + 8) = LRamp; // 8-9 (hleMixerWorkArea is a 16bit pointer)
|
||||
*(s32 *)(hleMixerWorkArea + 10) = RRamp; // 10-11
|
||||
*(s32 *)(hleMixerWorkArea + 12) = LAdderEnd; // 12-13
|
||||
*(s32 *)(hleMixerWorkArea + 14) = RAdderEnd; // 14-15
|
||||
*(s32 *)(hleMixerWorkArea + 16) = LAdderStart; // 12-13
|
||||
*(s32 *)(hleMixerWorkArea + 18) = RAdderStart; // 14-15
|
||||
memcpy(rsp.RDRAM+addy, (u8 *)hleMixerWorkArea,80);
|
||||
}
|
||||
|
||||
static void RESAMPLE (u32 inst1, u32 inst2) {
|
||||
unsigned char Flags=(u8)((inst1>>16)&0xff);
|
||||
unsigned int Pitch=((inst1&0xffff))<<1;
|
||||
u32 addy = (inst2 & 0xffffff);// + SEGMENTS[(inst2>>24)&0xf];
|
||||
unsigned int Accum=0;
|
||||
unsigned int location;
|
||||
s16 *lut/*, *lut2*/;
|
||||
short *dst;
|
||||
s16 *src;
|
||||
dst=(short *)(BufferSpace);
|
||||
src=(s16 *)(BufferSpace);
|
||||
u32 srcPtr=(AudioInBuffer/2);
|
||||
u32 dstPtr=(AudioOutBuffer/2);
|
||||
s32 temp;
|
||||
s32 accum;
|
||||
/*
|
||||
if (addy > (1024*1024*8))
|
||||
addy = (inst2 & 0xffffff);
|
||||
*/
|
||||
srcPtr -= 4;
|
||||
|
||||
if ((Flags & 0x1) == 0) {
|
||||
//memcpy (src+srcPtr, rsp.RDRAM+addy, 0x8);
|
||||
for (int x=0; x < 4; x++)
|
||||
src[(srcPtr+x)^S] = ((u16 *)rsp.RDRAM)[((addy/2)+x)^S];
|
||||
Accum = *(u16 *)(rsp.RDRAM+addy+10);
|
||||
} else {
|
||||
for (int x=0; x < 4; x++)
|
||||
src[(srcPtr+x)^S] = 0;//*(u16 *)(rsp.RDRAM+((addy+x)^2));
|
||||
}
|
||||
|
||||
for(int i=0;i < ((AudioCount+0xf)&0xFFF0)/2;i++) {
|
||||
//location = (((Accum * 0x40) >> 0x10) * 8);
|
||||
// location is the fractional position between two samples
|
||||
location = (Accum >> 0xa) * 4;
|
||||
lut = (s16*)ResampleLUT + location;
|
||||
|
||||
// mov eax, dword ptr [src+srcPtr];
|
||||
// movsx edx, word ptr [lut];
|
||||
// shl edx, 1
|
||||
// imul edx
|
||||
// test eax, 08000h
|
||||
// setz ecx
|
||||
// shl ecx, 16
|
||||
// xor eax, 08000h
|
||||
// add eax, ecx
|
||||
// and edx, 0f000h
|
||||
|
||||
// imul
|
||||
temp = ((s32)*(s16*)(src+((srcPtr+0)^S))*((s32)((s16)lut[0])));
|
||||
accum = (s32)(temp >> 15);
|
||||
|
||||
temp = ((s32)*(s16*)(src+((srcPtr+1)^S))*((s32)((s16)lut[1])));
|
||||
accum += (s32)(temp >> 15);
|
||||
|
||||
temp = ((s32)*(s16*)(src+((srcPtr+2)^S))*((s32)((s16)lut[2])));
|
||||
accum += (s32)(temp >> 15);
|
||||
|
||||
temp = ((s32)*(s16*)(src+((srcPtr+3)^S))*((s32)((s16)lut[3])));
|
||||
accum += (s32)(temp >> 15);
|
||||
|
||||
if (accum > 32767) accum = 32767;
|
||||
if (accum < -32768) accum = -32768;
|
||||
|
||||
dst[dstPtr^S] = (accum);
|
||||
dstPtr++;
|
||||
Accum += Pitch;
|
||||
srcPtr += (Accum>>16);
|
||||
Accum&=0xffff;
|
||||
}
|
||||
for (int x=0; x < 4; x++)
|
||||
((u16 *)rsp.RDRAM)[((addy/2)+x)^S] = src[(srcPtr+x)^S];
|
||||
//memcpy (RSWORK, src+srcPtr, 0x8);
|
||||
*(u16 *)(rsp.RDRAM+addy+10) = Accum;
|
||||
}
|
||||
|
||||
static void SETVOL (u32 inst1, u32 inst2) {
|
||||
// Might be better to unpack these depending on the flags...
|
||||
u8 flags = (u8)((inst1 >> 16) & 0xff);
|
||||
u16 vol = (s16)(inst1 & 0xffff);
|
||||
//u16 voltarg =(u16)((inst2 >> 16)&0xffff);
|
||||
u16 volrate = (u16)((inst2 & 0xffff));
|
||||
|
||||
if (flags & A_AUX) {
|
||||
Env_Dry = (s16)vol; // m_MainVol
|
||||
Env_Wet = (s16)volrate; // m_AuxVol
|
||||
return;
|
||||
}
|
||||
|
||||
if(flags & A_VOL) { // Set the Source(start) Volumes
|
||||
if(flags & A_LEFT) {
|
||||
Vol_Left = (s16)vol; // m_LeftVolume
|
||||
} else { // A_RIGHT
|
||||
Vol_Right = (s16)vol; // m_RightVolume
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//0x370 Loop Value (shared location)
|
||||
//0x370 Target Volume (Left)
|
||||
//u16 VolRamp_Left; // 0x0012(T8)
|
||||
if(flags & A_LEFT) { // Set the Ramping values Target, Ramp
|
||||
//loopval = (((u32)vol << 0x10) | (u32)voltarg);
|
||||
VolTrg_Left = (s16)inst1; // m_LeftVol
|
||||
//VolRamp_Left = (s32)inst2;
|
||||
VolRamp_Left = (s32)inst2;//(u16)(inst2) | (s32)(s16)(inst2 << 0x10);
|
||||
//fprintf (dfile, "Ramp Left: %f\n", (float)VolRamp_Left/65536.0);
|
||||
//fprintf (dfile, "Ramp Left: %08X\n", inst2);
|
||||
//VolRamp_Left = (s16)voltarg; // m_LeftVolTarget
|
||||
//VolRate_Left = (s16)volrate; // m_LeftVolRate
|
||||
} else { // A_RIGHT
|
||||
VolTrg_Right = (s16)inst1; // m_RightVol
|
||||
//VolRamp_Right = (s32)inst2;
|
||||
VolRamp_Right = (s32)inst2;//(u16)(inst2 >> 0x10) | (s32)(s16)(inst2 << 0x10);
|
||||
//fprintf (dfile, "Ramp Right: %f\n", (float)VolRamp_Right/65536.0);
|
||||
//fprintf (dfile, "Ramp Right: %08X\n", inst2);
|
||||
//VolRamp_Right = (s16)voltarg; // m_RightVolTarget
|
||||
//VolRate_Right = (s16)volrate; // m_RightVolRate
|
||||
}
|
||||
}
|
||||
|
||||
static void UNKNOWN (u32 inst1, u32 inst2) {}
|
||||
|
||||
static void SETLOOP (u32 inst1, u32 inst2) {
|
||||
loopval = (inst2 & 0xffffff);// + SEGMENTS[(inst2>>24)&0xf];
|
||||
//VolTrg_Left = (s16)(loopval>>16); // m_LeftVol
|
||||
//VolRamp_Left = (s16)(loopval); // m_LeftVolTarget
|
||||
}
|
||||
|
||||
static void ADPCM (u32 inst1, u32 inst2) { // Work in progress! :)
|
||||
unsigned char Flags=(u8)(inst1>>16)&0xff;
|
||||
//unsigned short Gain=(u16)(inst1&0xffff);
|
||||
unsigned int Address=(inst2 & 0xffffff);// + SEGMENTS[(inst2>>24)&0xf];
|
||||
unsigned short inPtr=0;
|
||||
//short *out=(s16 *)(testbuff+(AudioOutBuffer>>2));
|
||||
short *out=(short *)(BufferSpace+AudioOutBuffer);
|
||||
//unsigned char *in=(unsigned char *)(BufferSpace+AudioInBuffer);
|
||||
short count=(short)AudioCount;
|
||||
unsigned char icode;
|
||||
unsigned char code;
|
||||
int vscale;
|
||||
unsigned short index;
|
||||
unsigned short j;
|
||||
int a[8];
|
||||
short *book1,*book2;
|
||||
/*
|
||||
if (Address > (1024*1024*8))
|
||||
Address = (inst2 & 0xffffff);
|
||||
*/
|
||||
memset(out,0,32);
|
||||
|
||||
if(!(Flags&0x1))
|
||||
{
|
||||
if(Flags&0x2) {
|
||||
memcpy(out,&rsp.RDRAM[loopval&MEMMASK],32);
|
||||
} else {
|
||||
memcpy(out,&rsp.RDRAM[Address],32);
|
||||
}
|
||||
}
|
||||
|
||||
int l1=out[14^S];
|
||||
int l2=out[15^S];
|
||||
int inp1[8];
|
||||
int inp2[8];
|
||||
out+=16;
|
||||
while(count>0)
|
||||
{
|
||||
// the first interation through, these values are
|
||||
// either 0 in the case of A_INIT, from a special
|
||||
// area of memory in the case of A_LOOP or just
|
||||
// the values we calculated the last time
|
||||
|
||||
code=BufferSpace[(AudioInBuffer+inPtr)^S8];
|
||||
index=code&0xf;
|
||||
index<<=4; // index into the adpcm code table
|
||||
book1=(short *)&adpcmtable[index];
|
||||
book2=book1+8;
|
||||
code>>=4; // upper nibble is scale
|
||||
vscale=(0x8000>>((12-code)-1)); // very strange. 0x8000 would be .5 in 16:16 format
|
||||
// so this appears to be a fractional scale based
|
||||
// on the 12 based inverse of the scale value. note
|
||||
// that this could be negative, in which case we do
|
||||
// not use the calculated vscale value... see the
|
||||
// if(code>12) check below
|
||||
|
||||
inPtr++; // coded adpcm data lies next
|
||||
j=0;
|
||||
while(j<8) // loop of 8, for 8 coded nibbles from 4 bytes
|
||||
// which yields 8 short pcm values
|
||||
{
|
||||
icode=BufferSpace[(AudioInBuffer+inPtr)^S8];
|
||||
inPtr++;
|
||||
|
||||
inp1[j]=(s16)((icode&0xf0)<<8); // this will in effect be signed
|
||||
if(code<12)
|
||||
inp1[j]=((int)((int)inp1[j]*(int)vscale)>>16);
|
||||
/*else
|
||||
int catchme=1;*/
|
||||
j++;
|
||||
|
||||
inp1[j]=(s16)((icode&0xf)<<12);
|
||||
if(code<12)
|
||||
inp1[j]=((int)((int)inp1[j]*(int)vscale)>>16);
|
||||
/*else
|
||||
int catchme=1;*/
|
||||
j++;
|
||||
}
|
||||
j=0;
|
||||
while(j<8)
|
||||
{
|
||||
icode=BufferSpace[(AudioInBuffer+inPtr)^S8];
|
||||
inPtr++;
|
||||
|
||||
inp2[j]=(short)((icode&0xf0)<<8); // this will in effect be signed
|
||||
if(code<12)
|
||||
inp2[j]=((int)((int)inp2[j]*(int)vscale)>>16);
|
||||
/*else
|
||||
int catchme=1;*/
|
||||
j++;
|
||||
|
||||
inp2[j]=(short)((icode&0xf)<<12);
|
||||
if(code<12)
|
||||
inp2[j]=((int)((int)inp2[j]*(int)vscale)>>16);
|
||||
/*else
|
||||
int catchme=1;*/
|
||||
j++;
|
||||
}
|
||||
|
||||
a[0]= (int)book1[0]*(int)l1;
|
||||
a[0]+=(int)book2[0]*(int)l2;
|
||||
a[0]+=(int)inp1[0]*(int)2048;
|
||||
|
||||
a[1] =(int)book1[1]*(int)l1;
|
||||
a[1]+=(int)book2[1]*(int)l2;
|
||||
a[1]+=(int)book2[0]*inp1[0];
|
||||
a[1]+=(int)inp1[1]*(int)2048;
|
||||
|
||||
a[2] =(int)book1[2]*(int)l1;
|
||||
a[2]+=(int)book2[2]*(int)l2;
|
||||
a[2]+=(int)book2[1]*inp1[0];
|
||||
a[2]+=(int)book2[0]*inp1[1];
|
||||
a[2]+=(int)inp1[2]*(int)2048;
|
||||
|
||||
a[3] =(int)book1[3]*(int)l1;
|
||||
a[3]+=(int)book2[3]*(int)l2;
|
||||
a[3]+=(int)book2[2]*inp1[0];
|
||||
a[3]+=(int)book2[1]*inp1[1];
|
||||
a[3]+=(int)book2[0]*inp1[2];
|
||||
a[3]+=(int)inp1[3]*(int)2048;
|
||||
|
||||
a[4] =(int)book1[4]*(int)l1;
|
||||
a[4]+=(int)book2[4]*(int)l2;
|
||||
a[4]+=(int)book2[3]*inp1[0];
|
||||
a[4]+=(int)book2[2]*inp1[1];
|
||||
a[4]+=(int)book2[1]*inp1[2];
|
||||
a[4]+=(int)book2[0]*inp1[3];
|
||||
a[4]+=(int)inp1[4]*(int)2048;
|
||||
|
||||
a[5] =(int)book1[5]*(int)l1;
|
||||
a[5]+=(int)book2[5]*(int)l2;
|
||||
a[5]+=(int)book2[4]*inp1[0];
|
||||
a[5]+=(int)book2[3]*inp1[1];
|
||||
a[5]+=(int)book2[2]*inp1[2];
|
||||
a[5]+=(int)book2[1]*inp1[3];
|
||||
a[5]+=(int)book2[0]*inp1[4];
|
||||
a[5]+=(int)inp1[5]*(int)2048;
|
||||
|
||||
a[6] =(int)book1[6]*(int)l1;
|
||||
a[6]+=(int)book2[6]*(int)l2;
|
||||
a[6]+=(int)book2[5]*inp1[0];
|
||||
a[6]+=(int)book2[4]*inp1[1];
|
||||
a[6]+=(int)book2[3]*inp1[2];
|
||||
a[6]+=(int)book2[2]*inp1[3];
|
||||
a[6]+=(int)book2[1]*inp1[4];
|
||||
a[6]+=(int)book2[0]*inp1[5];
|
||||
a[6]+=(int)inp1[6]*(int)2048;
|
||||
|
||||
a[7] =(int)book1[7]*(int)l1;
|
||||
a[7]+=(int)book2[7]*(int)l2;
|
||||
a[7]+=(int)book2[6]*inp1[0];
|
||||
a[7]+=(int)book2[5]*inp1[1];
|
||||
a[7]+=(int)book2[4]*inp1[2];
|
||||
a[7]+=(int)book2[3]*inp1[3];
|
||||
a[7]+=(int)book2[2]*inp1[4];
|
||||
a[7]+=(int)book2[1]*inp1[5];
|
||||
a[7]+=(int)book2[0]*inp1[6];
|
||||
a[7]+=(int)inp1[7]*(int)2048;
|
||||
|
||||
for(j=0;j<8;j++)
|
||||
{
|
||||
a[j^S]>>=11;
|
||||
if(a[j^S]>32767) a[j^S]=32767;
|
||||
else if(a[j^S]<-32768) a[j^S]=-32768;
|
||||
*(out++)=a[j^S];
|
||||
}
|
||||
l1=a[6];
|
||||
l2=a[7];
|
||||
|
||||
a[0]= (int)book1[0]*(int)l1;
|
||||
a[0]+=(int)book2[0]*(int)l2;
|
||||
a[0]+=(int)inp2[0]*(int)2048;
|
||||
|
||||
a[1] =(int)book1[1]*(int)l1;
|
||||
a[1]+=(int)book2[1]*(int)l2;
|
||||
a[1]+=(int)book2[0]*inp2[0];
|
||||
a[1]+=(int)inp2[1]*(int)2048;
|
||||
|
||||
a[2] =(int)book1[2]*(int)l1;
|
||||
a[2]+=(int)book2[2]*(int)l2;
|
||||
a[2]+=(int)book2[1]*inp2[0];
|
||||
a[2]+=(int)book2[0]*inp2[1];
|
||||
a[2]+=(int)inp2[2]*(int)2048;
|
||||
|
||||
a[3] =(int)book1[3]*(int)l1;
|
||||
a[3]+=(int)book2[3]*(int)l2;
|
||||
a[3]+=(int)book2[2]*inp2[0];
|
||||
a[3]+=(int)book2[1]*inp2[1];
|
||||
a[3]+=(int)book2[0]*inp2[2];
|
||||
a[3]+=(int)inp2[3]*(int)2048;
|
||||
|
||||
a[4] =(int)book1[4]*(int)l1;
|
||||
a[4]+=(int)book2[4]*(int)l2;
|
||||
a[4]+=(int)book2[3]*inp2[0];
|
||||
a[4]+=(int)book2[2]*inp2[1];
|
||||
a[4]+=(int)book2[1]*inp2[2];
|
||||
a[4]+=(int)book2[0]*inp2[3];
|
||||
a[4]+=(int)inp2[4]*(int)2048;
|
||||
|
||||
a[5] =(int)book1[5]*(int)l1;
|
||||
a[5]+=(int)book2[5]*(int)l2;
|
||||
a[5]+=(int)book2[4]*inp2[0];
|
||||
a[5]+=(int)book2[3]*inp2[1];
|
||||
a[5]+=(int)book2[2]*inp2[2];
|
||||
a[5]+=(int)book2[1]*inp2[3];
|
||||
a[5]+=(int)book2[0]*inp2[4];
|
||||
a[5]+=(int)inp2[5]*(int)2048;
|
||||
|
||||
a[6] =(int)book1[6]*(int)l1;
|
||||
a[6]+=(int)book2[6]*(int)l2;
|
||||
a[6]+=(int)book2[5]*inp2[0];
|
||||
a[6]+=(int)book2[4]*inp2[1];
|
||||
a[6]+=(int)book2[3]*inp2[2];
|
||||
a[6]+=(int)book2[2]*inp2[3];
|
||||
a[6]+=(int)book2[1]*inp2[4];
|
||||
a[6]+=(int)book2[0]*inp2[5];
|
||||
a[6]+=(int)inp2[6]*(int)2048;
|
||||
|
||||
a[7] =(int)book1[7]*(int)l1;
|
||||
a[7]+=(int)book2[7]*(int)l2;
|
||||
a[7]+=(int)book2[6]*inp2[0];
|
||||
a[7]+=(int)book2[5]*inp2[1];
|
||||
a[7]+=(int)book2[4]*inp2[2];
|
||||
a[7]+=(int)book2[3]*inp2[3];
|
||||
a[7]+=(int)book2[2]*inp2[4];
|
||||
a[7]+=(int)book2[1]*inp2[5];
|
||||
a[7]+=(int)book2[0]*inp2[6];
|
||||
a[7]+=(int)inp2[7]*(int)2048;
|
||||
|
||||
for(j=0;j<8;j++)
|
||||
{
|
||||
a[j^S]>>=11;
|
||||
if(a[j^S]>32767) a[j^S]=32767;
|
||||
else if(a[j^S]<-32768) a[j^S]=-32768;
|
||||
*(out++)=a[j^S];
|
||||
}
|
||||
l1=a[6];
|
||||
l2=a[7];
|
||||
|
||||
count-=32;
|
||||
}
|
||||
out-=16;
|
||||
memcpy(&rsp.RDRAM[Address],out,32);
|
||||
}
|
||||
|
||||
static void LOADBUFF (u32 inst1, u32 inst2) { // memcpy causes static... endianess issue :(
|
||||
u32 v0;
|
||||
//u32 cnt;
|
||||
if (AudioCount == 0)
|
||||
return;
|
||||
v0 = (inst2 & 0xfffffc);// + SEGMENTS[(inst2>>24)&0xf];
|
||||
memcpy (BufferSpace+(AudioInBuffer&0xFFFC), rsp.RDRAM+v0, (AudioCount+3)&0xFFFC);
|
||||
}
|
||||
|
||||
static void SAVEBUFF (u32 inst1, u32 inst2) { // memcpy causes static... endianess issue :(
|
||||
u32 v0;
|
||||
//u32 cnt;
|
||||
if (AudioCount == 0)
|
||||
return;
|
||||
v0 = (inst2 & 0xfffffc);// + SEGMENTS[(inst2>>24)&0xf];
|
||||
memcpy (rsp.RDRAM+v0, BufferSpace+(AudioOutBuffer&0xFFFC), (AudioCount+3)&0xFFFC);
|
||||
}
|
||||
|
||||
static void SETBUFF (u32 inst1, u32 inst2) { // Should work ;-)
|
||||
if ((inst1 >> 0x10) & 0x8) { // A_AUX - Auxillary Sound Buffer Settings
|
||||
AudioAuxA = u16(inst1);
|
||||
AudioAuxC = u16((inst2 >> 0x10));
|
||||
AudioAuxE = u16(inst2);
|
||||
} else { // A_MAIN - Main Sound Buffer Settings
|
||||
AudioInBuffer = u16(inst1); // 0x00
|
||||
AudioOutBuffer = u16((inst2 >> 0x10)); // 0x02
|
||||
AudioCount = u16(inst2); // 0x04
|
||||
}
|
||||
}
|
||||
|
||||
static void DMEMMOVE (u32 inst1, u32 inst2) { // Doesn't sound just right?... will fix when HLE is ready - 03-11-01
|
||||
u32 v0, v1;
|
||||
u32 cnt;
|
||||
if ((inst2 & 0xffff)==0)
|
||||
return;
|
||||
v0 = (inst1 & 0xFFFF);
|
||||
v1 = (inst2 >> 0x10);
|
||||
//assert ((v1 & 0x3) == 0);
|
||||
//assert ((v0 & 0x3) == 0);
|
||||
u32 count = ((inst2+3) & 0xfffc);
|
||||
//v0 = (v0) & 0xfffc;
|
||||
//v1 = (v1) & 0xfffc;
|
||||
|
||||
//memcpy (BufferSpace+v1, BufferSpace+v0, count-1);
|
||||
for (cnt = 0; cnt < count; cnt++) {
|
||||
*(u8 *)(BufferSpace+((cnt+v1)^S8)) = *(u8 *)(BufferSpace+((cnt+v0)^S8));
|
||||
}
|
||||
}
|
||||
|
||||
static void LOADADPCM (u32 inst1, u32 inst2) { // Loads an ADPCM table - Works 100% Now 03-13-01
|
||||
u32 v0;
|
||||
v0 = (inst2 & 0xffffff);// + SEGMENTS[(inst2>>24)&0xf];
|
||||
/* if (v0 > (1024*1024*8))
|
||||
v0 = (inst2 & 0xffffff);*/
|
||||
//memcpy (dmem+0x4c0, rsp.RDRAM+v0, inst1&0xffff); // Could prolly get away with not putting this in dmem
|
||||
//assert ((inst1&0xffff) <= 0x80);
|
||||
u16 *table = (u16 *)(rsp.RDRAM+v0);
|
||||
for (u32 x = 0; x < ((inst1&0xffff)>>0x4); x++) {
|
||||
adpcmtable[(0x0+(x<<3))^S] = table[0];
|
||||
adpcmtable[(0x1+(x<<3))^S] = table[1];
|
||||
|
||||
adpcmtable[(0x2+(x<<3))^S] = table[2];
|
||||
adpcmtable[(0x3+(x<<3))^S] = table[3];
|
||||
|
||||
adpcmtable[(0x4+(x<<3))^S] = table[4];
|
||||
adpcmtable[(0x5+(x<<3))^S] = table[5];
|
||||
|
||||
adpcmtable[(0x6+(x<<3))^S] = table[6];
|
||||
adpcmtable[(0x7+(x<<3))^S] = table[7];
|
||||
table += 8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void INTERLEAVE (u32 inst1, u32 inst2) { // Works... - 3-11-01
|
||||
u32 inL, inR;
|
||||
u16 *outbuff = (u16 *)(AudioOutBuffer+BufferSpace);
|
||||
u16 *inSrcR;
|
||||
u16 *inSrcL;
|
||||
u16 Left, Right, Left2, Right2;
|
||||
|
||||
inL = inst2 & 0xFFFF;
|
||||
inR = (inst2 >> 16) & 0xFFFF;
|
||||
|
||||
inSrcR = (u16 *)(BufferSpace+inR);
|
||||
inSrcL = (u16 *)(BufferSpace+inL);
|
||||
|
||||
for (int x = 0; x < (AudioCount/4); x++) {
|
||||
Left=*(inSrcL++);
|
||||
Right=*(inSrcR++);
|
||||
Left2=*(inSrcL++);
|
||||
Right2=*(inSrcR++);
|
||||
|
||||
#ifdef M64P_BIG_ENDIAN
|
||||
*(outbuff++)=Right;
|
||||
*(outbuff++)=Left;
|
||||
*(outbuff++)=Right2;
|
||||
*(outbuff++)=Left2;
|
||||
#else
|
||||
*(outbuff++)=Right2;
|
||||
*(outbuff++)=Left2;
|
||||
*(outbuff++)=Right;
|
||||
*(outbuff++)=Left;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void MIXER (u32 inst1, u32 inst2) { // Fixed a sign issue... 03-14-01
|
||||
u32 dmemin = (u16)(inst2 >> 0x10);
|
||||
u32 dmemout = (u16)(inst2 & 0xFFFF);
|
||||
//u8 flags = (u8)((inst1 >> 16) & 0xff);
|
||||
s32 gain = (s16)(inst1 & 0xFFFF);
|
||||
s32 temp;
|
||||
|
||||
if (AudioCount == 0)
|
||||
return;
|
||||
|
||||
for (int x=0; x < AudioCount; x+=2) { // I think I can do this a lot easier
|
||||
temp = (*(s16 *)(BufferSpace+dmemin+x) * gain) >> 15;
|
||||
temp += *(s16 *)(BufferSpace+dmemout+x);
|
||||
|
||||
if ((s32)temp > 32767)
|
||||
temp = 32767;
|
||||
if ((s32)temp < -32768)
|
||||
temp = -32768;
|
||||
|
||||
*(u16 *)(BufferSpace+dmemout+x) = (u16)(temp & 0xFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
// TOP Performance Hogs:
|
||||
//Command: ADPCM - Calls: 48 - Total Time: 331226 - Avg Time: 6900.54 - Percent: 31.53%
|
||||
//Command: ENVMIXER - Calls: 48 - Total Time: 408563 - Avg Time: 8511.73 - Percent: 38.90%
|
||||
//Command: LOADBUFF - Calls: 56 - Total Time: 21551 - Avg Time: 384.84 - Percent: 2.05%
|
||||
//Command: RESAMPLE - Calls: 48 - Total Time: 225922 - Avg Time: 4706.71 - Percent: 21.51%
|
||||
|
||||
//Command: ADPCM - Calls: 48 - Total Time: 391600 - Avg Time: 8158.33 - Percent: 32.52%
|
||||
//Command: ENVMIXER - Calls: 48 - Total Time: 444091 - Avg Time: 9251.90 - Percent: 36.88%
|
||||
//Command: LOADBUFF - Calls: 58 - Total Time: 29945 - Avg Time: 516.29 - Percent: 2.49%
|
||||
//Command: RESAMPLE - Calls: 48 - Total Time: 276354 - Avg Time: 5757.38 - Percent: 22.95%
|
||||
|
||||
|
||||
extern "C" const acmd_callback_t ABI1[0x10] = { // TOP Performace Hogs: MIXER, RESAMPLE, ENVMIXER
|
||||
SPNOOP , ADPCM , CLEARBUFF, ENVMIXER , LOADBUFF, RESAMPLE , SAVEBUFF, UNKNOWN,
|
||||
SETBUFF, SETVOL, DMEMMOVE , LOADADPCM , MIXER , INTERLEAVE, UNKNOWN , SETLOOP
|
||||
};
|
||||
|
||||
/* BACKUPS
|
||||
void MIXER (u32 inst1, u32 inst2) { // Fixed a sign issue... 03-14-01
|
||||
u16 dmemin = (u16)(inst2 >> 0x10);
|
||||
u16 dmemout = (u16)(inst2 & 0xFFFF);
|
||||
u16 gain = (u16)(inst1 & 0xFFFF);
|
||||
u8 flags = (u8)((inst1 >> 16) & 0xff);
|
||||
u64 temp;
|
||||
|
||||
if (AudioCount == 0)
|
||||
return;
|
||||
|
||||
for (int x=0; x < AudioCount; x+=2) { // I think I can do this a lot easier
|
||||
temp = (s64)(*(s16 *)(BufferSpace+dmemout+x)) * (s64)((s16)(0x7FFF)*2);
|
||||
|
||||
if (temp & 0x8000)
|
||||
temp = (temp^0x8000) + 0x10000;
|
||||
else
|
||||
temp = (temp^0x8000);
|
||||
|
||||
temp = (temp & 0xFFFFFFFFFFFF);
|
||||
|
||||
temp += ((*(s16 *)(BufferSpace+dmemin+x) * (s64)((s16)gain*2))) & 0xFFFFFFFFFFFF;
|
||||
|
||||
temp = (s32)(temp >> 16);
|
||||
if ((s32)temp > 32767)
|
||||
temp = 32767;
|
||||
if ((s32)temp < -32768)
|
||||
temp = -32768;
|
||||
|
||||
*(u16 *)(BufferSpace+dmemout+x) = (u16)(temp & 0xFFFF);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
|
@ -1,930 +0,0 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - ucode2.cpp *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2009 Richard Goedeken *
|
||||
* Copyright (C) 2002 Hacktarux *
|
||||
* *
|
||||
* 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 <string.h>
|
||||
# include <stdio.h>
|
||||
|
||||
extern "C" {
|
||||
#include "m64p_types.h"
|
||||
#include "hle.h"
|
||||
#include "alist_internal.h"
|
||||
}
|
||||
|
||||
extern u8 BufferSpace[0x10000];
|
||||
|
||||
static void SPNOOP (u32 inst1, u32 inst2) {
|
||||
DebugMessage(M64MSG_ERROR, "Unknown/Unimplemented Audio Command %i in ABI 2", (int)(inst1 >> 24));
|
||||
}
|
||||
extern u16 AudioInBuffer; // 0x0000(T8)
|
||||
extern u16 AudioOutBuffer; // 0x0002(T8)
|
||||
extern u16 AudioCount; // 0x0004(T8)
|
||||
extern u32 loopval; // 0x0010(T8)
|
||||
extern u32 SEGMENTS[0x10];
|
||||
|
||||
extern u16 adpcmtable[0x88];
|
||||
|
||||
extern const u16 ResampleLUT [0x200];
|
||||
|
||||
bool isMKABI = false;
|
||||
bool isZeldaABI = false;
|
||||
|
||||
extern "C" void init_ucode2() { isMKABI = isZeldaABI = false; }
|
||||
|
||||
static void LOADADPCM2 (u32 inst1, u32 inst2) { // Loads an ADPCM table - Works 100% Now 03-13-01
|
||||
u32 v0;
|
||||
v0 = (inst2 & 0xffffff);// + SEGMENTS[(inst2>>24)&0xf];
|
||||
u16 *table = (u16 *)(rsp.RDRAM+v0); // Zelda2 Specific...
|
||||
|
||||
for (u32 x = 0; x < ((inst1&0xffff)>>0x4); x++) {
|
||||
adpcmtable[(0x0+(x<<3))^S] = table[0];
|
||||
adpcmtable[(0x1+(x<<3))^S] = table[1];
|
||||
|
||||
adpcmtable[(0x2+(x<<3))^S] = table[2];
|
||||
adpcmtable[(0x3+(x<<3))^S] = table[3];
|
||||
|
||||
adpcmtable[(0x4+(x<<3))^S] = table[4];
|
||||
adpcmtable[(0x5+(x<<3))^S] = table[5];
|
||||
|
||||
adpcmtable[(0x6+(x<<3))^S] = table[6];
|
||||
adpcmtable[(0x7+(x<<3))^S] = table[7];
|
||||
table += 8;
|
||||
}
|
||||
}
|
||||
|
||||
static void SETLOOP2 (u32 inst1, u32 inst2) {
|
||||
loopval = inst2 & 0xffffff; // No segment?
|
||||
}
|
||||
|
||||
static void SETBUFF2 (u32 inst1, u32 inst2) {
|
||||
AudioInBuffer = u16(inst1); // 0x00
|
||||
AudioOutBuffer = u16((inst2 >> 0x10)); // 0x02
|
||||
AudioCount = u16(inst2); // 0x04
|
||||
}
|
||||
|
||||
static void ADPCM2 (u32 inst1, u32 inst2) { // Verified to be 100% Accurate...
|
||||
unsigned char Flags=(u8)(inst1>>16)&0xff;
|
||||
//unsigned short Gain=(u16)(inst1&0xffff);
|
||||
unsigned int Address=(inst2 & 0xffffff);// + SEGMENTS[(inst2>>24)&0xf];
|
||||
unsigned short inPtr=0;
|
||||
//short *out=(s16 *)(testbuff+(AudioOutBuffer>>2));
|
||||
short *out=(short *)(BufferSpace+AudioOutBuffer);
|
||||
//unsigned char *in=(unsigned char *)(BufferSpace+AudioInBuffer);
|
||||
short count=(short)AudioCount;
|
||||
unsigned char icode;
|
||||
unsigned char code;
|
||||
int vscale;
|
||||
unsigned short index;
|
||||
unsigned short j;
|
||||
int a[8];
|
||||
short *book1,*book2;
|
||||
|
||||
u8 srange;
|
||||
u8 mask1;
|
||||
u8 mask2;
|
||||
u8 shifter;
|
||||
|
||||
memset(out,0,32);
|
||||
|
||||
if (Flags & 0x4) { // Tricky lil Zelda MM and ABI2!!! hahaha I know your secrets! :DDD
|
||||
srange = 0xE;
|
||||
mask1 = 0xC0;
|
||||
mask2 = 0x30;
|
||||
shifter = 10;
|
||||
} else {
|
||||
srange = 0xC;
|
||||
mask1 = 0xf0;
|
||||
mask2 = 0x0f;
|
||||
shifter = 12;
|
||||
}
|
||||
|
||||
if(!(Flags&0x1))
|
||||
{
|
||||
if(Flags&0x2)
|
||||
{/*
|
||||
for(int i=0;i<16;i++)
|
||||
{
|
||||
out[i]=*(short *)&rsp.RDRAM[(loopval+i*2)^2];
|
||||
}*/
|
||||
memcpy(out,&rsp.RDRAM[loopval],32);
|
||||
}
|
||||
else
|
||||
{/*
|
||||
for(int i=0;i<16;i++)
|
||||
{
|
||||
out[i]=*(short *)&rsp.RDRAM[(Address+i*2)^2];
|
||||
}*/
|
||||
memcpy(out,&rsp.RDRAM[Address],32);
|
||||
}
|
||||
}
|
||||
|
||||
int l1=out[14^S];
|
||||
int l2=out[15^S];
|
||||
int inp1[8];
|
||||
int inp2[8];
|
||||
out+=16;
|
||||
while(count>0) {
|
||||
code=BufferSpace[(AudioInBuffer+inPtr)^S8];
|
||||
index=code&0xf;
|
||||
index<<=4;
|
||||
book1=(short *)&adpcmtable[index];
|
||||
book2=book1+8;
|
||||
code>>=4;
|
||||
vscale=(0x8000>>((srange-code)-1));
|
||||
|
||||
inPtr++;
|
||||
j=0;
|
||||
|
||||
while(j<8) {
|
||||
icode=BufferSpace[(AudioInBuffer+inPtr)^S8];
|
||||
inPtr++;
|
||||
|
||||
inp1[j]=(s16)((icode&mask1) << 8); // this will in effect be signed
|
||||
if(code<srange) inp1[j]=((int)((int)inp1[j]*(int)vscale)>>16);
|
||||
//else int catchme=1;
|
||||
j++;
|
||||
|
||||
inp1[j]=(s16)((icode&mask2)<<shifter);
|
||||
if(code<srange) inp1[j]=((int)((int)inp1[j]*(int)vscale)>>16);
|
||||
//else int catchme=1;
|
||||
j++;
|
||||
|
||||
if (Flags & 4) {
|
||||
inp1[j]=(s16)((icode&0xC) << 12); // this will in effect be signed
|
||||
if(code < 0xE) inp1[j]=((int)((int)inp1[j]*(int)vscale)>>16);
|
||||
//else int catchme=1;
|
||||
j++;
|
||||
|
||||
inp1[j]=(s16)((icode&0x3) << 14);
|
||||
if(code < 0xE) inp1[j]=((int)((int)inp1[j]*(int)vscale)>>16);
|
||||
//else int catchme=1;
|
||||
j++;
|
||||
} // end flags
|
||||
} // end while
|
||||
|
||||
|
||||
|
||||
j=0;
|
||||
while(j<8) {
|
||||
icode=BufferSpace[(AudioInBuffer+inPtr)^S8];
|
||||
inPtr++;
|
||||
|
||||
inp2[j]=(s16)((icode&mask1) << 8);
|
||||
if(code<srange) inp2[j]=((int)((int)inp2[j]*(int)vscale)>>16);
|
||||
//else int catchme=1;
|
||||
j++;
|
||||
|
||||
inp2[j]=(s16)((icode&mask2)<<shifter);
|
||||
if(code<srange) inp2[j]=((int)((int)inp2[j]*(int)vscale)>>16);
|
||||
//else int catchme=1;
|
||||
j++;
|
||||
|
||||
if (Flags & 4) {
|
||||
inp2[j]=(s16)((icode&0xC) << 12);
|
||||
if(code < 0xE) inp2[j]=((int)((int)inp2[j]*(int)vscale)>>16);
|
||||
//else int catchme=1;
|
||||
j++;
|
||||
|
||||
inp2[j]=(s16)((icode&0x3) << 14);
|
||||
if(code < 0xE) inp2[j]=((int)((int)inp2[j]*(int)vscale)>>16);
|
||||
//else int catchme=1;
|
||||
j++;
|
||||
} // end flags
|
||||
}
|
||||
|
||||
a[0]= (int)book1[0]*(int)l1;
|
||||
a[0]+=(int)book2[0]*(int)l2;
|
||||
a[0]+=(int)inp1[0]*(int)2048;
|
||||
|
||||
a[1] =(int)book1[1]*(int)l1;
|
||||
a[1]+=(int)book2[1]*(int)l2;
|
||||
a[1]+=(int)book2[0]*inp1[0];
|
||||
a[1]+=(int)inp1[1]*(int)2048;
|
||||
|
||||
a[2] =(int)book1[2]*(int)l1;
|
||||
a[2]+=(int)book2[2]*(int)l2;
|
||||
a[2]+=(int)book2[1]*inp1[0];
|
||||
a[2]+=(int)book2[0]*inp1[1];
|
||||
a[2]+=(int)inp1[2]*(int)2048;
|
||||
|
||||
a[3] =(int)book1[3]*(int)l1;
|
||||
a[3]+=(int)book2[3]*(int)l2;
|
||||
a[3]+=(int)book2[2]*inp1[0];
|
||||
a[3]+=(int)book2[1]*inp1[1];
|
||||
a[3]+=(int)book2[0]*inp1[2];
|
||||
a[3]+=(int)inp1[3]*(int)2048;
|
||||
|
||||
a[4] =(int)book1[4]*(int)l1;
|
||||
a[4]+=(int)book2[4]*(int)l2;
|
||||
a[4]+=(int)book2[3]*inp1[0];
|
||||
a[4]+=(int)book2[2]*inp1[1];
|
||||
a[4]+=(int)book2[1]*inp1[2];
|
||||
a[4]+=(int)book2[0]*inp1[3];
|
||||
a[4]+=(int)inp1[4]*(int)2048;
|
||||
|
||||
a[5] =(int)book1[5]*(int)l1;
|
||||
a[5]+=(int)book2[5]*(int)l2;
|
||||
a[5]+=(int)book2[4]*inp1[0];
|
||||
a[5]+=(int)book2[3]*inp1[1];
|
||||
a[5]+=(int)book2[2]*inp1[2];
|
||||
a[5]+=(int)book2[1]*inp1[3];
|
||||
a[5]+=(int)book2[0]*inp1[4];
|
||||
a[5]+=(int)inp1[5]*(int)2048;
|
||||
|
||||
a[6] =(int)book1[6]*(int)l1;
|
||||
a[6]+=(int)book2[6]*(int)l2;
|
||||
a[6]+=(int)book2[5]*inp1[0];
|
||||
a[6]+=(int)book2[4]*inp1[1];
|
||||
a[6]+=(int)book2[3]*inp1[2];
|
||||
a[6]+=(int)book2[2]*inp1[3];
|
||||
a[6]+=(int)book2[1]*inp1[4];
|
||||
a[6]+=(int)book2[0]*inp1[5];
|
||||
a[6]+=(int)inp1[6]*(int)2048;
|
||||
|
||||
a[7] =(int)book1[7]*(int)l1;
|
||||
a[7]+=(int)book2[7]*(int)l2;
|
||||
a[7]+=(int)book2[6]*inp1[0];
|
||||
a[7]+=(int)book2[5]*inp1[1];
|
||||
a[7]+=(int)book2[4]*inp1[2];
|
||||
a[7]+=(int)book2[3]*inp1[3];
|
||||
a[7]+=(int)book2[2]*inp1[4];
|
||||
a[7]+=(int)book2[1]*inp1[5];
|
||||
a[7]+=(int)book2[0]*inp1[6];
|
||||
a[7]+=(int)inp1[7]*(int)2048;
|
||||
|
||||
for(j=0;j<8;j++)
|
||||
{
|
||||
a[j^S]>>=11;
|
||||
if(a[j^S]>32767) a[j^S]=32767;
|
||||
else if(a[j^S]<-32768) a[j^S]=-32768;
|
||||
*(out++)=a[j^S];
|
||||
}
|
||||
l1=a[6];
|
||||
l2=a[7];
|
||||
|
||||
a[0]= (int)book1[0]*(int)l1;
|
||||
a[0]+=(int)book2[0]*(int)l2;
|
||||
a[0]+=(int)inp2[0]*(int)2048;
|
||||
|
||||
a[1] =(int)book1[1]*(int)l1;
|
||||
a[1]+=(int)book2[1]*(int)l2;
|
||||
a[1]+=(int)book2[0]*inp2[0];
|
||||
a[1]+=(int)inp2[1]*(int)2048;
|
||||
|
||||
a[2] =(int)book1[2]*(int)l1;
|
||||
a[2]+=(int)book2[2]*(int)l2;
|
||||
a[2]+=(int)book2[1]*inp2[0];
|
||||
a[2]+=(int)book2[0]*inp2[1];
|
||||
a[2]+=(int)inp2[2]*(int)2048;
|
||||
|
||||
a[3] =(int)book1[3]*(int)l1;
|
||||
a[3]+=(int)book2[3]*(int)l2;
|
||||
a[3]+=(int)book2[2]*inp2[0];
|
||||
a[3]+=(int)book2[1]*inp2[1];
|
||||
a[3]+=(int)book2[0]*inp2[2];
|
||||
a[3]+=(int)inp2[3]*(int)2048;
|
||||
|
||||
a[4] =(int)book1[4]*(int)l1;
|
||||
a[4]+=(int)book2[4]*(int)l2;
|
||||
a[4]+=(int)book2[3]*inp2[0];
|
||||
a[4]+=(int)book2[2]*inp2[1];
|
||||
a[4]+=(int)book2[1]*inp2[2];
|
||||
a[4]+=(int)book2[0]*inp2[3];
|
||||
a[4]+=(int)inp2[4]*(int)2048;
|
||||
|
||||
a[5] =(int)book1[5]*(int)l1;
|
||||
a[5]+=(int)book2[5]*(int)l2;
|
||||
a[5]+=(int)book2[4]*inp2[0];
|
||||
a[5]+=(int)book2[3]*inp2[1];
|
||||
a[5]+=(int)book2[2]*inp2[2];
|
||||
a[5]+=(int)book2[1]*inp2[3];
|
||||
a[5]+=(int)book2[0]*inp2[4];
|
||||
a[5]+=(int)inp2[5]*(int)2048;
|
||||
|
||||
a[6] =(int)book1[6]*(int)l1;
|
||||
a[6]+=(int)book2[6]*(int)l2;
|
||||
a[6]+=(int)book2[5]*inp2[0];
|
||||
a[6]+=(int)book2[4]*inp2[1];
|
||||
a[6]+=(int)book2[3]*inp2[2];
|
||||
a[6]+=(int)book2[2]*inp2[3];
|
||||
a[6]+=(int)book2[1]*inp2[4];
|
||||
a[6]+=(int)book2[0]*inp2[5];
|
||||
a[6]+=(int)inp2[6]*(int)2048;
|
||||
|
||||
a[7] =(int)book1[7]*(int)l1;
|
||||
a[7]+=(int)book2[7]*(int)l2;
|
||||
a[7]+=(int)book2[6]*inp2[0];
|
||||
a[7]+=(int)book2[5]*inp2[1];
|
||||
a[7]+=(int)book2[4]*inp2[2];
|
||||
a[7]+=(int)book2[3]*inp2[3];
|
||||
a[7]+=(int)book2[2]*inp2[4];
|
||||
a[7]+=(int)book2[1]*inp2[5];
|
||||
a[7]+=(int)book2[0]*inp2[6];
|
||||
a[7]+=(int)inp2[7]*(int)2048;
|
||||
|
||||
for(j=0;j<8;j++)
|
||||
{
|
||||
a[j^S]>>=11;
|
||||
if(a[j^S]>32767) a[j^S]=32767;
|
||||
else if(a[j^S]<-32768) a[j^S]=-32768;
|
||||
*(out++)=a[j^S];
|
||||
}
|
||||
l1=a[6];
|
||||
l2=a[7];
|
||||
|
||||
count-=32;
|
||||
}
|
||||
out-=16;
|
||||
memcpy(&rsp.RDRAM[Address],out,32);
|
||||
}
|
||||
|
||||
static void CLEARBUFF2 (u32 inst1, u32 inst2) {
|
||||
u16 addr = (u16)(inst1 & 0xffff);
|
||||
u16 count = (u16)(inst2 & 0xffff);
|
||||
if (count > 0)
|
||||
memset(BufferSpace+addr, 0, count);
|
||||
}
|
||||
|
||||
static void LOADBUFF2 (u32 inst1, u32 inst2) { // Needs accuracy verification...
|
||||
u32 v0;
|
||||
u32 cnt = (((inst1 >> 0xC)+3)&0xFFC);
|
||||
v0 = (inst2 & 0xfffffc);// + SEGMENTS[(inst2>>24)&0xf];
|
||||
memcpy (BufferSpace+(inst1&0xfffc), rsp.RDRAM+v0, (cnt+3)&0xFFFC);
|
||||
}
|
||||
|
||||
static void SAVEBUFF2 (u32 inst1, u32 inst2) { // Needs accuracy verification...
|
||||
u32 v0;
|
||||
u32 cnt = (((inst1 >> 0xC)+3)&0xFFC);
|
||||
v0 = (inst2 & 0xfffffc);// + SEGMENTS[(inst2>>24)&0xf];
|
||||
memcpy (rsp.RDRAM+v0, BufferSpace+(inst1&0xfffc), (cnt+3)&0xFFFC);
|
||||
}
|
||||
|
||||
|
||||
static void MIXER2 (u32 inst1, u32 inst2) { // Needs accuracy verification...
|
||||
u16 dmemin = (u16)(inst2 >> 0x10);
|
||||
u16 dmemout = (u16)(inst2 & 0xFFFF);
|
||||
u32 count = ((inst1 >> 12) & 0xFF0);
|
||||
s32 gain = (s16)(inst1 & 0xFFFF);
|
||||
s32 temp;
|
||||
|
||||
for (unsigned int x=0; x < count; x+=2) { // I think I can do this a lot easier
|
||||
|
||||
temp = (*(s16 *)(BufferSpace+dmemin+x) * gain) >> 15;
|
||||
temp += *(s16 *)(BufferSpace+dmemout+x);
|
||||
|
||||
if ((s32)temp > 32767)
|
||||
temp = 32767;
|
||||
if ((s32)temp < -32768)
|
||||
temp = -32768;
|
||||
|
||||
*(u16 *)(BufferSpace+dmemout+x) = (u16)(temp & 0xFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void RESAMPLE2 (u32 inst1, u32 inst2) {
|
||||
unsigned char Flags=(u8)((inst1>>16)&0xff);
|
||||
unsigned int Pitch=((inst1&0xffff))<<1;
|
||||
u32 addy = (inst2 & 0xffffff);// + SEGMENTS[(inst2>>24)&0xf];
|
||||
unsigned int Accum=0;
|
||||
unsigned int location;
|
||||
s16 *lut;
|
||||
short *dst;
|
||||
s16 *src;
|
||||
dst=(short *)(BufferSpace);
|
||||
src=(s16 *)(BufferSpace);
|
||||
u32 srcPtr=(AudioInBuffer/2);
|
||||
u32 dstPtr=(AudioOutBuffer/2);
|
||||
s32 temp;
|
||||
s32 accum;
|
||||
|
||||
if (addy > (1024*1024*8))
|
||||
addy = (inst2 & 0xffffff);
|
||||
|
||||
srcPtr -= 4;
|
||||
|
||||
if ((Flags & 0x1) == 0) {
|
||||
for (int x=0; x < 4; x++) //memcpy (src+srcPtr, rsp.RDRAM+addy, 0x8);
|
||||
src[(srcPtr+x)^S] = ((u16 *)rsp.RDRAM)[((addy/2)+x)^S];
|
||||
Accum = *(u16 *)(rsp.RDRAM+addy+10);
|
||||
} else {
|
||||
for (int x=0; x < 4; x++)
|
||||
src[(srcPtr+x)^S] = 0;//*(u16 *)(rsp.RDRAM+((addy+x)^2));
|
||||
}
|
||||
|
||||
for(int i=0;i < ((AudioCount+0xf)&0xFFF0)/2;i++) {
|
||||
location = (((Accum * 0x40) >> 0x10) * 8);
|
||||
//location = (Accum >> 0xa) << 0x3;
|
||||
lut = (s16 *)(((u8 *)ResampleLUT) + location);
|
||||
|
||||
temp = ((s32)*(s16*)(src+((srcPtr+0)^S))*((s32)((s16)lut[0])));
|
||||
accum = (s32)(temp >> 15);
|
||||
|
||||
temp = ((s32)*(s16*)(src+((srcPtr+1)^S))*((s32)((s16)lut[1])));
|
||||
accum += (s32)(temp >> 15);
|
||||
|
||||
temp = ((s32)*(s16*)(src+((srcPtr+2)^S))*((s32)((s16)lut[2])));
|
||||
accum += (s32)(temp >> 15);
|
||||
|
||||
temp = ((s32)*(s16*)(src+((srcPtr+3)^S))*((s32)((s16)lut[3])));
|
||||
accum += (s32)(temp >> 15);
|
||||
|
||||
if (accum > 32767) accum = 32767;
|
||||
if (accum < -32768) accum = -32768;
|
||||
|
||||
dst[dstPtr^S] = (s16)(accum);
|
||||
dstPtr++;
|
||||
Accum += Pitch;
|
||||
srcPtr += (Accum>>16);
|
||||
Accum&=0xffff;
|
||||
}
|
||||
for (int x=0; x < 4; x++)
|
||||
((u16 *)rsp.RDRAM)[((addy/2)+x)^S] = src[(srcPtr+x)^S];
|
||||
*(u16 *)(rsp.RDRAM+addy+10) = (u16)Accum;
|
||||
//memcpy (RSWORK, src+srcPtr, 0x8);
|
||||
}
|
||||
|
||||
static void DMEMMOVE2 (u32 inst1, u32 inst2) { // Needs accuracy verification...
|
||||
u32 v0, v1;
|
||||
u32 cnt;
|
||||
if ((inst2 & 0xffff)==0)
|
||||
return;
|
||||
v0 = (inst1 & 0xFFFF);
|
||||
v1 = (inst2 >> 0x10);
|
||||
//assert ((v1 & 0x3) == 0);
|
||||
//assert ((v0 & 0x3) == 0);
|
||||
u32 count = ((inst2+3) & 0xfffc);
|
||||
//v0 = (v0) & 0xfffc;
|
||||
//v1 = (v1) & 0xfffc;
|
||||
|
||||
//memcpy (dmem+v1, dmem+v0, count-1);
|
||||
for (cnt = 0; cnt < count; cnt++) {
|
||||
*(u8 *)(BufferSpace+((cnt+v1)^S8)) = *(u8 *)(BufferSpace+((cnt+v0)^S8));
|
||||
}
|
||||
}
|
||||
|
||||
static u32 t3, s5, s6;
|
||||
static u16 env[8];
|
||||
|
||||
static void ENVSETUP1 (u32 inst1, u32 inst2) {
|
||||
u32 tmp;
|
||||
|
||||
//fprintf (dfile, "ENVSETUP1: inst1 = %08X, inst2 = %08X\n", inst1, inst2);
|
||||
t3 = inst1 & 0xFFFF;
|
||||
tmp = (inst1 >> 0x8) & 0xFF00;
|
||||
env[4] = (u16)tmp;
|
||||
tmp += t3;
|
||||
env[5] = (u16)tmp;
|
||||
s5 = inst2 >> 0x10;
|
||||
s6 = inst2 & 0xFFFF;
|
||||
//fprintf (dfile, " t3 = %X / s5 = %X / s6 = %X / env[4] = %X / env[5] = %X\n", t3, s5, s6, env[4], env[5]);
|
||||
}
|
||||
|
||||
static void ENVSETUP2 (u32 inst1, u32 inst2) {
|
||||
u32 tmp;
|
||||
|
||||
//fprintf (dfile, "ENVSETUP2: inst1 = %08X, inst2 = %08X\n", inst1, inst2);
|
||||
tmp = (inst2 >> 0x10);
|
||||
env[0] = (u16)tmp;
|
||||
tmp += s5;
|
||||
env[1] = (u16)tmp;
|
||||
tmp = inst2 & 0xffff;
|
||||
env[2] = (u16)tmp;
|
||||
tmp += s6;
|
||||
env[3] = (u16)tmp;
|
||||
//fprintf (dfile, " env[0] = %X / env[1] = %X / env[2] = %X / env[3] = %X\n", env[0], env[1], env[2], env[3]);
|
||||
}
|
||||
|
||||
static void ENVMIXER2 (u32 inst1, u32 inst2) {
|
||||
//fprintf (dfile, "ENVMIXER: inst1 = %08X, inst2 = %08X\n", inst1, inst2);
|
||||
|
||||
s16 *bufft6, *bufft7, *buffs0, *buffs1;
|
||||
s16 *buffs3;
|
||||
s32 count;
|
||||
u32 adder;
|
||||
|
||||
s16 vec9, vec10;
|
||||
|
||||
s16 v2[8];
|
||||
|
||||
buffs3 = (s16 *)(BufferSpace + ((inst1 >> 0x0c)&0x0ff0));
|
||||
bufft6 = (s16 *)(BufferSpace + ((inst2 >> 0x14)&0x0ff0));
|
||||
bufft7 = (s16 *)(BufferSpace + ((inst2 >> 0x0c)&0x0ff0));
|
||||
buffs0 = (s16 *)(BufferSpace + ((inst2 >> 0x04)&0x0ff0));
|
||||
buffs1 = (s16 *)(BufferSpace + ((inst2 << 0x04)&0x0ff0));
|
||||
|
||||
|
||||
v2[0] = 0 - (s16)((inst1 & 0x2) >> 1);
|
||||
v2[1] = 0 - (s16)((inst1 & 0x1));
|
||||
v2[2] = 0 - (s16)((inst1 & 0x8) >> 1);
|
||||
v2[3] = 0 - (s16)((inst1 & 0x4) >> 1);
|
||||
|
||||
count = (inst1 >> 8) & 0xff;
|
||||
|
||||
if (!isMKABI) {
|
||||
s5 *= 2; s6 *= 2; t3 *= 2;
|
||||
adder = 0x10;
|
||||
} else {
|
||||
inst1 = 0;
|
||||
adder = 0x8;
|
||||
t3 = 0;
|
||||
}
|
||||
|
||||
|
||||
while (count > 0) {
|
||||
int temp, x;
|
||||
for (x=0; x < 0x8; x++) {
|
||||
vec9 = (s16)(((s32)buffs3[x^S] * (u32)env[0]) >> 0x10) ^ v2[0];
|
||||
vec10 = (s16)(((s32)buffs3[x^S] * (u32)env[2]) >> 0x10) ^ v2[1];
|
||||
temp = bufft6[x^S] + vec9;
|
||||
if (temp > 32767) temp = 32767; if (temp < -32768) temp = -32768;
|
||||
bufft6[x^S] = temp;
|
||||
temp = bufft7[x^S] + vec10;
|
||||
if (temp > 32767) temp = 32767; if (temp < -32768) temp = -32768;
|
||||
bufft7[x^S] = temp;
|
||||
vec9 = (s16)(((s32)vec9 * (u32)env[4]) >> 0x10) ^ v2[2];
|
||||
vec10 = (s16)(((s32)vec10 * (u32)env[4]) >> 0x10) ^ v2[3];
|
||||
if (inst1 & 0x10) {
|
||||
temp = buffs0[x^S] + vec10;
|
||||
if (temp > 32767) temp = 32767; if (temp < -32768) temp = -32768;
|
||||
buffs0[x^S] = temp;
|
||||
temp = buffs1[x^S] + vec9;
|
||||
if (temp > 32767) temp = 32767; if (temp < -32768) temp = -32768;
|
||||
buffs1[x^S] = temp;
|
||||
} else {
|
||||
temp = buffs0[x^S] + vec9;
|
||||
if (temp > 32767) temp = 32767; if (temp < -32768) temp = -32768;
|
||||
buffs0[x^S] = temp;
|
||||
temp = buffs1[x^S] + vec10;
|
||||
if (temp > 32767) temp = 32767; if (temp < -32768) temp = -32768;
|
||||
buffs1[x^S] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isMKABI)
|
||||
for (x=0x8; x < 0x10; x++) {
|
||||
vec9 = (s16)(((s32)buffs3[x^S] * (u32)env[1]) >> 0x10) ^ v2[0];
|
||||
vec10 = (s16)(((s32)buffs3[x^S] * (u32)env[3]) >> 0x10) ^ v2[1];
|
||||
temp = bufft6[x^S] + vec9;
|
||||
if (temp > 32767) temp = 32767; if (temp < -32768) temp = -32768;
|
||||
bufft6[x^S] = temp;
|
||||
temp = bufft7[x^S] + vec10;
|
||||
if (temp > 32767) temp = 32767; if (temp < -32768) temp = -32768;
|
||||
bufft7[x^S] = temp;
|
||||
vec9 = (s16)(((s32)vec9 * (u32)env[5]) >> 0x10) ^ v2[2];
|
||||
vec10 = (s16)(((s32)vec10 * (u32)env[5]) >> 0x10) ^ v2[3];
|
||||
if (inst1 & 0x10) {
|
||||
temp = buffs0[x^S] + vec10;
|
||||
if (temp > 32767) temp = 32767; if (temp < -32768) temp = -32768;
|
||||
buffs0[x^S] = temp;
|
||||
temp = buffs1[x^S] + vec9;
|
||||
if (temp > 32767) temp = 32767; if (temp < -32768) temp = -32768;
|
||||
buffs1[x^S] = temp;
|
||||
} else {
|
||||
temp = buffs0[x^S] + vec9;
|
||||
if (temp > 32767) temp = 32767; if (temp < -32768) temp = -32768;
|
||||
buffs0[x^S] = temp;
|
||||
temp = buffs1[x^S] + vec10;
|
||||
if (temp > 32767) temp = 32767; if (temp < -32768) temp = -32768;
|
||||
buffs1[x^S] = temp;
|
||||
}
|
||||
}
|
||||
bufft6 += adder; bufft7 += adder;
|
||||
buffs0 += adder; buffs1 += adder;
|
||||
buffs3 += adder; count -= adder;
|
||||
env[0] += (u16)s5; env[1] += (u16)s5;
|
||||
env[2] += (u16)s6; env[3] += (u16)s6;
|
||||
env[4] += (u16)t3; env[5] += (u16)t3;
|
||||
}
|
||||
}
|
||||
|
||||
static void DUPLICATE2(u32 inst1, u32 inst2) {
|
||||
unsigned short Count = (inst1 >> 16) & 0xff;
|
||||
unsigned short In = inst1&0xffff;
|
||||
unsigned short Out = (inst2>>16);
|
||||
|
||||
unsigned short buff[64];
|
||||
|
||||
memcpy(buff,BufferSpace+In,128);
|
||||
|
||||
while(Count) {
|
||||
memcpy(BufferSpace+Out,buff,128);
|
||||
Out+=128;
|
||||
Count--;
|
||||
}
|
||||
}
|
||||
/*
|
||||
static void INTERL2 (u32 inst1, u32 inst2) { // Make your own...
|
||||
short Count = inst1 & 0xffff;
|
||||
unsigned short Out = inst2 & 0xffff;
|
||||
unsigned short In = (inst2 >> 16);
|
||||
|
||||
short *src,*dst,tmp;
|
||||
src=(short *)&BufferSpace[In];
|
||||
dst=(short *)&BufferSpace[Out];
|
||||
while(Count)
|
||||
{
|
||||
*(dst++)=*(src++);
|
||||
src++;
|
||||
*(dst++)=*(src++);
|
||||
src++;
|
||||
*(dst++)=*(src++);
|
||||
src++;
|
||||
*(dst++)=*(src++);
|
||||
src++;
|
||||
*(dst++)=*(src++);
|
||||
src++;
|
||||
*(dst++)=*(src++);
|
||||
src++;
|
||||
*(dst++)=*(src++);
|
||||
src++;
|
||||
*(dst++)=*(src++);
|
||||
src++;
|
||||
Count-=8;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
static void INTERL2 (u32 inst1, u32 inst2) {
|
||||
short Count = inst1 & 0xffff;
|
||||
unsigned short Out = inst2 & 0xffff;
|
||||
unsigned short In = (inst2 >> 16);
|
||||
|
||||
unsigned char *src,*dst/*,tmp*/;
|
||||
src=(unsigned char *)(BufferSpace);//[In];
|
||||
dst=(unsigned char *)(BufferSpace);//[Out];
|
||||
while(Count) {
|
||||
*(short *)(dst+(Out^S8)) = *(short *)(src+(In^S8));
|
||||
Out += 2;
|
||||
In += 4;
|
||||
Count--;
|
||||
}
|
||||
}
|
||||
|
||||
static void INTERLEAVE2 (u32 inst1, u32 inst2) { // Needs accuracy verification...
|
||||
u32 inL, inR;
|
||||
u16 *outbuff;
|
||||
u16 *inSrcR;
|
||||
u16 *inSrcL;
|
||||
u16 Left, Right, Left2, Right2;
|
||||
u32 count;
|
||||
count = ((inst1 >> 12) & 0xFF0);
|
||||
if (count == 0) {
|
||||
outbuff = (u16 *)(AudioOutBuffer+BufferSpace);
|
||||
count = AudioCount;
|
||||
} else {
|
||||
outbuff = (u16 *)((inst1&0xFFFF)+BufferSpace);
|
||||
}
|
||||
|
||||
inR = inst2 & 0xFFFF;
|
||||
inL = (inst2 >> 16) & 0xFFFF;
|
||||
|
||||
inSrcR = (u16 *)(BufferSpace+inR);
|
||||
inSrcL = (u16 *)(BufferSpace+inL);
|
||||
|
||||
for (u32 x = 0; x < (count/4); x++) {
|
||||
Left=*(inSrcL++);
|
||||
Right=*(inSrcR++);
|
||||
Left2=*(inSrcL++);
|
||||
Right2=*(inSrcR++);
|
||||
|
||||
#ifdef M64P_BIG_ENDIAN
|
||||
*(outbuff++)=Right;
|
||||
*(outbuff++)=Left;
|
||||
*(outbuff++)=Right2;
|
||||
*(outbuff++)=Left2;
|
||||
#else
|
||||
*(outbuff++)=Right2;
|
||||
*(outbuff++)=Left2;
|
||||
*(outbuff++)=Right;
|
||||
*(outbuff++)=Left;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void ADDMIXER (u32 inst1, u32 inst2) {
|
||||
short Count = (inst1 >> 12) & 0x00ff0;
|
||||
u16 InBuffer = (inst2 >> 16);
|
||||
u16 OutBuffer = inst2 & 0xffff;
|
||||
|
||||
s16 *inp, *outp;
|
||||
s32 temp;
|
||||
inp = (s16 *)(BufferSpace + InBuffer);
|
||||
outp = (s16 *)(BufferSpace + OutBuffer);
|
||||
for (int cntr = 0; cntr < Count; cntr+=2) {
|
||||
temp = *outp + *inp;
|
||||
if (temp > 32767) temp = 32767; if (temp < -32768) temp = -32768;
|
||||
*(outp++) = temp;
|
||||
inp++;
|
||||
}
|
||||
}
|
||||
|
||||
static void HILOGAIN (u32 inst1, u32 inst2) {
|
||||
u16 cnt = inst1 & 0xffff;
|
||||
u16 out = (inst2 >> 16) & 0xffff;
|
||||
s16 hi = (s16)((inst1 >> 4) & 0xf000);
|
||||
u16 lo = (inst1 >> 20) & 0xf;
|
||||
s16 *src;
|
||||
|
||||
src = (s16 *)(BufferSpace+out);
|
||||
s32 tmp, val;
|
||||
|
||||
while(cnt) {
|
||||
val = (s32)*src;
|
||||
//tmp = ((val * (s32)hi) + ((u64)(val * lo) << 16) >> 16);
|
||||
tmp = ((val * (s32)hi) >> 16) + (u32)(val * lo);
|
||||
if ((s32)tmp > 32767) tmp = 32767;
|
||||
else if ((s32)tmp < -32768) tmp = -32768;
|
||||
*src = tmp;
|
||||
src++;
|
||||
cnt -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void FILTER2 (u32 inst1, u32 inst2) {
|
||||
static int cnt = 0;
|
||||
static s16 *lutt6;
|
||||
static s16 *lutt5;
|
||||
u8 *save = (rsp.RDRAM+(inst2&0xFFFFFF));
|
||||
u8 t4 = (u8)((inst1 >> 0x10) & 0xFF);
|
||||
int x;
|
||||
|
||||
if (t4 > 1) { // Then set the cnt variable
|
||||
cnt = (inst1 & 0xFFFF);
|
||||
lutt6 = (s16 *)save;
|
||||
// memcpy (dmem+0xFE0, rsp.RDRAM+(inst2&0xFFFFFF), 0x10);
|
||||
return;
|
||||
}
|
||||
|
||||
if (t4 == 0) {
|
||||
// memcpy (dmem+0xFB0, rsp.RDRAM+(inst2&0xFFFFFF), 0x20);
|
||||
lutt5 = (short *)(save+0x10);
|
||||
}
|
||||
|
||||
lutt5 = (short *)(save+0x10);
|
||||
|
||||
// lutt5 = (short *)(dmem + 0xFC0);
|
||||
// lutt6 = (short *)(dmem + 0xFE0);
|
||||
for (x = 0; x < 8; x++) {
|
||||
s32 a;
|
||||
a = (lutt5[x] + lutt6[x]) >> 1;
|
||||
lutt5[x] = lutt6[x] = (short)a;
|
||||
}
|
||||
short *inp1, *inp2;
|
||||
s32 out1[8];
|
||||
s16 outbuff[0x3c0], *outp;
|
||||
u32 inPtr = (u32)(inst1&0xffff);
|
||||
inp1 = (short *)(save);
|
||||
outp = outbuff;
|
||||
inp2 = (short *)(BufferSpace+inPtr);
|
||||
for (x = 0; x < cnt; x+=0x10) {
|
||||
out1[1] = inp1[0]*lutt6[6];
|
||||
out1[1] += inp1[3]*lutt6[7];
|
||||
out1[1] += inp1[2]*lutt6[4];
|
||||
out1[1] += inp1[5]*lutt6[5];
|
||||
out1[1] += inp1[4]*lutt6[2];
|
||||
out1[1] += inp1[7]*lutt6[3];
|
||||
out1[1] += inp1[6]*lutt6[0];
|
||||
out1[1] += inp2[1]*lutt6[1]; // 1
|
||||
|
||||
out1[0] = inp1[3]*lutt6[6];
|
||||
out1[0] += inp1[2]*lutt6[7];
|
||||
out1[0] += inp1[5]*lutt6[4];
|
||||
out1[0] += inp1[4]*lutt6[5];
|
||||
out1[0] += inp1[7]*lutt6[2];
|
||||
out1[0] += inp1[6]*lutt6[3];
|
||||
out1[0] += inp2[1]*lutt6[0];
|
||||
out1[0] += inp2[0]*lutt6[1];
|
||||
|
||||
out1[3] = inp1[2]*lutt6[6];
|
||||
out1[3] += inp1[5]*lutt6[7];
|
||||
out1[3] += inp1[4]*lutt6[4];
|
||||
out1[3] += inp1[7]*lutt6[5];
|
||||
out1[3] += inp1[6]*lutt6[2];
|
||||
out1[3] += inp2[1]*lutt6[3];
|
||||
out1[3] += inp2[0]*lutt6[0];
|
||||
out1[3] += inp2[3]*lutt6[1];
|
||||
|
||||
out1[2] = inp1[5]*lutt6[6];
|
||||
out1[2] += inp1[4]*lutt6[7];
|
||||
out1[2] += inp1[7]*lutt6[4];
|
||||
out1[2] += inp1[6]*lutt6[5];
|
||||
out1[2] += inp2[1]*lutt6[2];
|
||||
out1[2] += inp2[0]*lutt6[3];
|
||||
out1[2] += inp2[3]*lutt6[0];
|
||||
out1[2] += inp2[2]*lutt6[1];
|
||||
|
||||
out1[5] = inp1[4]*lutt6[6];
|
||||
out1[5] += inp1[7]*lutt6[7];
|
||||
out1[5] += inp1[6]*lutt6[4];
|
||||
out1[5] += inp2[1]*lutt6[5];
|
||||
out1[5] += inp2[0]*lutt6[2];
|
||||
out1[5] += inp2[3]*lutt6[3];
|
||||
out1[5] += inp2[2]*lutt6[0];
|
||||
out1[5] += inp2[5]*lutt6[1];
|
||||
|
||||
out1[4] = inp1[7]*lutt6[6];
|
||||
out1[4] += inp1[6]*lutt6[7];
|
||||
out1[4] += inp2[1]*lutt6[4];
|
||||
out1[4] += inp2[0]*lutt6[5];
|
||||
out1[4] += inp2[3]*lutt6[2];
|
||||
out1[4] += inp2[2]*lutt6[3];
|
||||
out1[4] += inp2[5]*lutt6[0];
|
||||
out1[4] += inp2[4]*lutt6[1];
|
||||
|
||||
out1[7] = inp1[6]*lutt6[6];
|
||||
out1[7] += inp2[1]*lutt6[7];
|
||||
out1[7] += inp2[0]*lutt6[4];
|
||||
out1[7] += inp2[3]*lutt6[5];
|
||||
out1[7] += inp2[2]*lutt6[2];
|
||||
out1[7] += inp2[5]*lutt6[3];
|
||||
out1[7] += inp2[4]*lutt6[0];
|
||||
out1[7] += inp2[7]*lutt6[1];
|
||||
|
||||
out1[6] = inp2[1]*lutt6[6];
|
||||
out1[6] += inp2[0]*lutt6[7];
|
||||
out1[6] += inp2[3]*lutt6[4];
|
||||
out1[6] += inp2[2]*lutt6[5];
|
||||
out1[6] += inp2[5]*lutt6[2];
|
||||
out1[6] += inp2[4]*lutt6[3];
|
||||
out1[6] += inp2[7]*lutt6[0];
|
||||
out1[6] += inp2[6]*lutt6[1];
|
||||
outp[1] = /*CLAMP*/((out1[1]+0x4000) >> 0xF);
|
||||
outp[0] = /*CLAMP*/((out1[0]+0x4000) >> 0xF);
|
||||
outp[3] = /*CLAMP*/((out1[3]+0x4000) >> 0xF);
|
||||
outp[2] = /*CLAMP*/((out1[2]+0x4000) >> 0xF);
|
||||
outp[5] = /*CLAMP*/((out1[5]+0x4000) >> 0xF);
|
||||
outp[4] = /*CLAMP*/((out1[4]+0x4000) >> 0xF);
|
||||
outp[7] = /*CLAMP*/((out1[7]+0x4000) >> 0xF);
|
||||
outp[6] = /*CLAMP*/((out1[6]+0x4000) >> 0xF);
|
||||
inp1 = inp2;
|
||||
inp2 += 8;
|
||||
outp += 8;
|
||||
}
|
||||
// memcpy (rsp.RDRAM+(inst2&0xFFFFFF), dmem+0xFB0, 0x20);
|
||||
memcpy (save, inp2-8, 0x10);
|
||||
memcpy (BufferSpace+(inst1&0xffff), outbuff, cnt);
|
||||
}
|
||||
|
||||
static void SEGMENT2 (u32 inst1, u32 inst2) {
|
||||
if (isZeldaABI) {
|
||||
FILTER2 (inst1, inst2);
|
||||
return;
|
||||
}
|
||||
if ((inst1 & 0xffffff) == 0) {
|
||||
isMKABI = true;
|
||||
//SEGMENTS[(inst2>>24)&0xf] = (inst2 & 0xffffff);
|
||||
} else {
|
||||
isMKABI = false;
|
||||
isZeldaABI = true;
|
||||
FILTER2 (inst1, inst2);
|
||||
}
|
||||
}
|
||||
|
||||
static void UNKNOWN (u32 inst1, u32 inst2) {
|
||||
}
|
||||
/*
|
||||
void (*ABI2[0x20])(void) = {
|
||||
SPNOOP, ADPCM2, CLEARBUFF2, SPNOOP, SPNOOP, RESAMPLE2, SPNOOP, SEGMENT2,
|
||||
SETBUFF2, SPNOOP, DMEMMOVE2, LOADADPCM2, MIXER2, INTERLEAVE2, HILOGAIN, SETLOOP2,
|
||||
SPNOOP, INTERL2, ENVSETUP1, ENVMIXER2, LOADBUFF2, SAVEBUFF2, ENVSETUP2, SPNOOP,
|
||||
SPNOOP, SPNOOP, SPNOOP, SPNOOP, SPNOOP, SPNOOP, SPNOOP, SPNOOP
|
||||
};*/
|
||||
|
||||
extern "C" const acmd_callback_t ABI2[0x20] = {
|
||||
SPNOOP , ADPCM2, CLEARBUFF2, UNKNOWN, ADDMIXER, RESAMPLE2, UNKNOWN, SEGMENT2,
|
||||
SETBUFF2 , DUPLICATE2, DMEMMOVE2, LOADADPCM2, MIXER2, INTERLEAVE2, HILOGAIN, SETLOOP2,
|
||||
SPNOOP, INTERL2 , ENVSETUP1, ENVMIXER2, LOADBUFF2, SAVEBUFF2, ENVSETUP2, SPNOOP,
|
||||
HILOGAIN , SPNOOP, DUPLICATE2 , UNKNOWN , SPNOOP , SPNOOP , SPNOOP , SPNOOP
|
||||
};
|
||||
/*
|
||||
void (*ABI2[0x20])(void) = {
|
||||
SPNOOP , ADPCM2, CLEARBUFF2, SPNOOP, SPNOOP, RESAMPLE2 , SPNOOP , SEGMENT2,
|
||||
SETBUFF2 , DUPLICATE2, DMEMMOVE2, LOADADPCM2, MIXER2, INTERLEAVE2, SPNOOP, SETLOOP2,
|
||||
SPNOOP, INTERL2 , ENVSETUP1, ENVMIXER2, LOADBUFF2, SAVEBUFF2, ENVSETUP2, SPNOOP,
|
||||
SPNOOP , SPNOOP, SPNOOP , SPNOOP , SPNOOP , SPNOOP , SPNOOP , SPNOOP
|
||||
};*/
|
||||
/* NOTES:
|
||||
|
||||
FILTER/SEGMENT - Still needs to be finished up... add FILTER?
|
||||
UNKNOWWN #27 - Is this worth doing? Looks like a pain in the ass just for WaveRace64
|
||||
*/
|
||||
|
|
@ -1,834 +0,0 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - ucode3.cpp *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2009 Richard Goedeken *
|
||||
* Copyright (C) 2002 Hacktarux *
|
||||
* *
|
||||
* 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 <string.h>
|
||||
# include <stdio.h>
|
||||
|
||||
extern "C" {
|
||||
#include "m64p_types.h"
|
||||
#include "hle.h"
|
||||
#include "alist_internal.h"
|
||||
}
|
||||
|
||||
/*
|
||||
static void SPNOOP (u32 inst1, u32 inst2) {
|
||||
DebugMessage(M64MSG_ERROR, "Unknown/Unimplemented Audio Command %i in ABI 3", (int)(inst1 >> 24));
|
||||
}
|
||||
*/
|
||||
|
||||
extern const u16 ResampleLUT [0x200];
|
||||
|
||||
extern u32 loopval;
|
||||
|
||||
extern s16 Env_Dry;
|
||||
extern s16 Env_Wet;
|
||||
extern s16 Vol_Left;
|
||||
extern s16 Vol_Right;
|
||||
extern s16 VolTrg_Left;
|
||||
extern s32 VolRamp_Left;
|
||||
//extern u16 VolRate_Left;
|
||||
extern s16 VolTrg_Right;
|
||||
extern s32 VolRamp_Right;
|
||||
//extern u16 VolRate_Right;
|
||||
|
||||
|
||||
extern short hleMixerWorkArea[256];
|
||||
extern u16 adpcmtable[0x88];
|
||||
|
||||
extern u8 BufferSpace[0x10000];
|
||||
|
||||
/*
|
||||
static void SETVOL3 (u32 inst1, u32 inst2) { // Swapped Rate_Left and Vol
|
||||
u8 Flags = (u8)(inst1 >> 0x10);
|
||||
if (Flags & 0x4) { // 288
|
||||
if (Flags & 0x2) { // 290
|
||||
VolTrg_Left = *(s16*)&inst1;
|
||||
VolRamp_Left = *(s32*)&inst2;
|
||||
} else {
|
||||
VolTrg_Right = *(s16*)&inst1;
|
||||
VolRamp_Right = *(s32*)&inst2;
|
||||
}
|
||||
} else {
|
||||
Vol_Left = *(s16*)&inst1;
|
||||
Env_Dry = (s16)(*(s32*)&inst2 >> 0x10);
|
||||
Env_Wet = *(s16*)&inst2;
|
||||
}
|
||||
}
|
||||
*/
|
||||
static void SETVOL3 (u32 inst1, u32 inst2) {
|
||||
u8 Flags = (u8)(inst1 >> 0x10);
|
||||
if (Flags & 0x4) { // 288
|
||||
if (Flags & 0x2) { // 290
|
||||
Vol_Left = (s16)inst1; // 0x50
|
||||
Env_Dry = (s16)(inst2 >> 0x10); // 0x4E
|
||||
Env_Wet = (s16)inst2; // 0x4C
|
||||
} else {
|
||||
VolTrg_Right = (s16)inst1; // 0x46
|
||||
//VolRamp_Right = (u16)(inst2 >> 0x10) | (s32)(s16)(inst2 << 0x10);
|
||||
VolRamp_Right = (s32)inst2; // 0x48/0x4A
|
||||
}
|
||||
} else {
|
||||
VolTrg_Left = (s16)inst1; // 0x40
|
||||
VolRamp_Left = (s32)inst2; // 0x42/0x44
|
||||
}
|
||||
}
|
||||
|
||||
static void ENVMIXER3 (u32 inst1, u32 inst2) {
|
||||
u8 flags = (u8)((inst1 >> 16) & 0xff);
|
||||
u32 addy = (inst2 & 0xFFFFFF);
|
||||
|
||||
short *inp=(short *)(BufferSpace+0x4F0);
|
||||
short *out=(short *)(BufferSpace+0x9D0);
|
||||
short *aux1=(short *)(BufferSpace+0xB40);
|
||||
short *aux2=(short *)(BufferSpace+0xCB0);
|
||||
short *aux3=(short *)(BufferSpace+0xE20);
|
||||
s32 MainR;
|
||||
s32 MainL;
|
||||
s32 AuxR;
|
||||
s32 AuxL;
|
||||
int i1,o1,a1,a2,a3;
|
||||
//unsigned short AuxIncRate=1;
|
||||
short zero[8];
|
||||
memset(zero,0,16);
|
||||
|
||||
s32 LAdder, LAcc, LVol;
|
||||
s32 RAdder, RAcc, RVol;
|
||||
s16 RSig, LSig; // Most significant part of the Ramp Value
|
||||
s16 Wet, Dry;
|
||||
s16 LTrg, RTrg;
|
||||
|
||||
Vol_Right = (s16)inst1;
|
||||
|
||||
if (flags & A_INIT) {
|
||||
LAdder = VolRamp_Left / 8;
|
||||
LAcc = 0;
|
||||
LVol = Vol_Left;
|
||||
LSig = (s16)(VolRamp_Left >> 16);
|
||||
|
||||
RAdder = VolRamp_Right / 8;
|
||||
RAcc = 0;
|
||||
RVol = Vol_Right;
|
||||
RSig = (s16)(VolRamp_Right >> 16);
|
||||
|
||||
Wet = (s16)Env_Wet; Dry = (s16)Env_Dry; // Save Wet/Dry values
|
||||
LTrg = VolTrg_Left; RTrg = VolTrg_Right; // Save Current Left/Right Targets
|
||||
} else {
|
||||
memcpy((u8 *)hleMixerWorkArea, rsp.RDRAM+addy, 80);
|
||||
Wet = *(s16 *)(hleMixerWorkArea + 0); // 0-1
|
||||
Dry = *(s16 *)(hleMixerWorkArea + 2); // 2-3
|
||||
LTrg = *(s16 *)(hleMixerWorkArea + 4); // 4-5
|
||||
RTrg = *(s16 *)(hleMixerWorkArea + 6); // 6-7
|
||||
LAdder = *(s32 *)(hleMixerWorkArea + 8); // 8-9 (hleMixerWorkArea is a 16bit pointer)
|
||||
RAdder = *(s32 *)(hleMixerWorkArea + 10); // 10-11
|
||||
LAcc = *(s32 *)(hleMixerWorkArea + 12); // 12-13
|
||||
RAcc = *(s32 *)(hleMixerWorkArea + 14); // 14-15
|
||||
LVol = *(s32 *)(hleMixerWorkArea + 16); // 16-17
|
||||
RVol = *(s32 *)(hleMixerWorkArea + 18); // 18-19
|
||||
LSig = *(s16 *)(hleMixerWorkArea + 20); // 20-21
|
||||
RSig = *(s16 *)(hleMixerWorkArea + 22); // 22-23
|
||||
//u32 test = *(s32 *)(hleMixerWorkArea + 24); // 22-23
|
||||
//if (test != 0x13371337)
|
||||
}
|
||||
|
||||
|
||||
//if(!(flags&A_AUX)) {
|
||||
// AuxIncRate=0;
|
||||
// aux2=aux3=zero;
|
||||
//}
|
||||
|
||||
for (int y = 0; y < (0x170/2); y++) {
|
||||
|
||||
// Left
|
||||
LAcc += LAdder;
|
||||
LVol += (LAcc >> 16);
|
||||
LAcc &= 0xFFFF;
|
||||
|
||||
// Right
|
||||
RAcc += RAdder;
|
||||
RVol += (RAcc >> 16);
|
||||
RAcc &= 0xFFFF;
|
||||
// ****************************************************************
|
||||
// Clamp Left
|
||||
if (LSig >= 0) { // VLT
|
||||
if (LVol > LTrg) {
|
||||
LVol = LTrg;
|
||||
}
|
||||
} else { // VGE
|
||||
if (LVol < LTrg) {
|
||||
LVol = LTrg;
|
||||
}
|
||||
}
|
||||
|
||||
// Clamp Right
|
||||
if (RSig >= 0) { // VLT
|
||||
if (RVol > RTrg) {
|
||||
RVol = RTrg;
|
||||
}
|
||||
} else { // VGE
|
||||
if (RVol < RTrg) {
|
||||
RVol = RTrg;
|
||||
}
|
||||
}
|
||||
// ****************************************************************
|
||||
MainL = ((Dry * LVol) + 0x4000) >> 15;
|
||||
MainR = ((Dry * RVol) + 0x4000) >> 15;
|
||||
|
||||
o1 = out [y^S];
|
||||
a1 = aux1[y^S];
|
||||
i1 = inp [y^S];
|
||||
|
||||
o1+=((i1*MainL)+0x4000)>>15;
|
||||
a1+=((i1*MainR)+0x4000)>>15;
|
||||
|
||||
// ****************************************************************
|
||||
|
||||
if(o1>32767) o1=32767;
|
||||
else if(o1<-32768) o1=-32768;
|
||||
|
||||
if(a1>32767) a1=32767;
|
||||
else if(a1<-32768) a1=-32768;
|
||||
|
||||
// ****************************************************************
|
||||
|
||||
out[y^S]=o1;
|
||||
aux1[y^S]=a1;
|
||||
|
||||
// ****************************************************************
|
||||
//if (!(flags&A_AUX)) {
|
||||
a2 = aux2[y^S];
|
||||
a3 = aux3[y^S];
|
||||
|
||||
AuxL = ((Wet * LVol) + 0x4000) >> 15;
|
||||
AuxR = ((Wet * RVol) + 0x4000) >> 15;
|
||||
|
||||
a2+=((i1*AuxL)+0x4000)>>15;
|
||||
a3+=((i1*AuxR)+0x4000)>>15;
|
||||
|
||||
if(a2>32767) a2=32767;
|
||||
else if(a2<-32768) a2=-32768;
|
||||
|
||||
if(a3>32767) a3=32767;
|
||||
else if(a3<-32768) a3=-32768;
|
||||
|
||||
aux2[y^S]=a2;
|
||||
aux3[y^S]=a3;
|
||||
}
|
||||
//}
|
||||
|
||||
*(s16 *)(hleMixerWorkArea + 0) = Wet; // 0-1
|
||||
*(s16 *)(hleMixerWorkArea + 2) = Dry; // 2-3
|
||||
*(s16 *)(hleMixerWorkArea + 4) = LTrg; // 4-5
|
||||
*(s16 *)(hleMixerWorkArea + 6) = RTrg; // 6-7
|
||||
*(s32 *)(hleMixerWorkArea + 8) = LAdder; // 8-9 (hleMixerWorkArea is a 16bit pointer)
|
||||
*(s32 *)(hleMixerWorkArea + 10) = RAdder; // 10-11
|
||||
*(s32 *)(hleMixerWorkArea + 12) = LAcc; // 12-13
|
||||
*(s32 *)(hleMixerWorkArea + 14) = RAcc; // 14-15
|
||||
*(s32 *)(hleMixerWorkArea + 16) = LVol; // 16-17
|
||||
*(s32 *)(hleMixerWorkArea + 18) = RVol; // 18-19
|
||||
*(s16 *)(hleMixerWorkArea + 20) = LSig; // 20-21
|
||||
*(s16 *)(hleMixerWorkArea + 22) = RSig; // 22-23
|
||||
//*(u32 *)(hleMixerWorkArea + 24) = 0x13371337; // 22-23
|
||||
memcpy(rsp.RDRAM+addy, (u8 *)hleMixerWorkArea,80);
|
||||
}
|
||||
|
||||
static void CLEARBUFF3 (u32 inst1, u32 inst2) {
|
||||
u16 addr = (u16)(inst1 & 0xffff);
|
||||
u16 count = (u16)(inst2 & 0xffff);
|
||||
memset(BufferSpace+addr+0x4f0, 0, count);
|
||||
}
|
||||
|
||||
static void MIXER3 (u32 inst1, u32 inst2) { // Needs accuracy verification...
|
||||
u16 dmemin = (u16)(inst2 >> 0x10) + 0x4f0;
|
||||
u16 dmemout = (u16)(inst2 & 0xFFFF) + 0x4f0;
|
||||
//u8 flags = (u8)((inst1 >> 16) & 0xff);
|
||||
s32 gain = (s16)(inst1 & 0xFFFF);
|
||||
s32 temp;
|
||||
|
||||
for (int x=0; x < 0x170; x+=2) { // I think I can do this a lot easier
|
||||
temp = (*(s16 *)(BufferSpace+dmemin+x) * gain) >> 15;
|
||||
temp += *(s16 *)(BufferSpace+dmemout+x);
|
||||
|
||||
if ((s32)temp > 32767)
|
||||
temp = 32767;
|
||||
if ((s32)temp < -32768)
|
||||
temp = -32768;
|
||||
|
||||
*(u16 *)(BufferSpace+dmemout+x) = (u16)(temp & 0xFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
static void LOADBUFF3 (u32 inst1, u32 inst2) {
|
||||
u32 v0;
|
||||
u32 cnt = (((inst1 >> 0xC)+3)&0xFFC);
|
||||
v0 = (inst2 & 0xfffffc);
|
||||
u32 src = (inst1&0xffc)+0x4f0;
|
||||
memcpy (BufferSpace+src, rsp.RDRAM+v0, cnt);
|
||||
}
|
||||
|
||||
static void SAVEBUFF3 (u32 inst1, u32 inst2) {
|
||||
u32 v0;
|
||||
u32 cnt = (((inst1 >> 0xC)+3)&0xFFC);
|
||||
v0 = (inst2 & 0xfffffc);
|
||||
u32 src = (inst1&0xffc)+0x4f0;
|
||||
memcpy (rsp.RDRAM+v0, BufferSpace+src, cnt);
|
||||
}
|
||||
|
||||
static void LOADADPCM3 (u32 inst1, u32 inst2) { // Loads an ADPCM table - Works 100% Now 03-13-01
|
||||
u32 v0;
|
||||
v0 = (inst2 & 0xffffff);
|
||||
//memcpy (dmem+0x3f0, rsp.RDRAM+v0, inst1&0xffff);
|
||||
//assert ((inst1&0xffff) <= 0x80);
|
||||
u16 *table = (u16 *)(rsp.RDRAM+v0);
|
||||
for (u32 x = 0; x < ((inst1&0xffff)>>0x4); x++) {
|
||||
adpcmtable[(0x0+(x<<3))^S] = table[0];
|
||||
adpcmtable[(0x1+(x<<3))^S] = table[1];
|
||||
|
||||
adpcmtable[(0x2+(x<<3))^S] = table[2];
|
||||
adpcmtable[(0x3+(x<<3))^S] = table[3];
|
||||
|
||||
adpcmtable[(0x4+(x<<3))^S] = table[4];
|
||||
adpcmtable[(0x5+(x<<3))^S] = table[5];
|
||||
|
||||
adpcmtable[(0x6+(x<<3))^S] = table[6];
|
||||
adpcmtable[(0x7+(x<<3))^S] = table[7];
|
||||
table += 8;
|
||||
}
|
||||
}
|
||||
|
||||
static void DMEMMOVE3 (u32 inst1, u32 inst2) { // Needs accuracy verification...
|
||||
u32 v0, v1;
|
||||
u32 cnt;
|
||||
v0 = (inst1 & 0xFFFF) + 0x4f0;
|
||||
v1 = (inst2 >> 0x10) + 0x4f0;
|
||||
u32 count = ((inst2+3) & 0xfffc);
|
||||
|
||||
//memcpy (dmem+v1, dmem+v0, count-1);
|
||||
for (cnt = 0; cnt < count; cnt++) {
|
||||
*(u8 *)(BufferSpace+((cnt+v1)^S8)) = *(u8 *)(BufferSpace+((cnt+v0)^S8));
|
||||
}
|
||||
}
|
||||
|
||||
static void SETLOOP3 (u32 inst1, u32 inst2) {
|
||||
loopval = (inst2 & 0xffffff);
|
||||
}
|
||||
|
||||
static void ADPCM3 (u32 inst1, u32 inst2) { // Verified to be 100% Accurate...
|
||||
unsigned char Flags=(u8)(inst2>>0x1c)&0xff;
|
||||
//unsigned short Gain=(u16)(inst1&0xffff);
|
||||
unsigned int Address=(inst1 & 0xffffff);// + SEGMENTS[(inst2>>24)&0xf];
|
||||
unsigned short inPtr=(inst2>>12)&0xf;
|
||||
//short *out=(s16 *)(testbuff+(AudioOutBuffer>>2));
|
||||
short *out=(short *)(BufferSpace+(inst2&0xfff)+0x4f0);
|
||||
//unsigned char *in=(unsigned char *)(BufferSpace+((inst2>>12)&0xf)+0x4f0);
|
||||
short count=(short)((inst2 >> 16)&0xfff);
|
||||
unsigned char icode;
|
||||
unsigned char code;
|
||||
int vscale;
|
||||
unsigned short index;
|
||||
unsigned short j;
|
||||
int a[8];
|
||||
short *book1,*book2;
|
||||
|
||||
memset(out,0,32);
|
||||
|
||||
if(!(Flags&0x1))
|
||||
{
|
||||
if(Flags&0x2)
|
||||
{/*
|
||||
for(int i=0;i<16;i++)
|
||||
{
|
||||
out[i]=*(short *)&rsp.RDRAM[(loopval+i*2)^2];
|
||||
}*/
|
||||
memcpy(out,&rsp.RDRAM[loopval],32);
|
||||
}
|
||||
else
|
||||
{/*
|
||||
for(int i=0;i<16;i++)
|
||||
{
|
||||
out[i]=*(short *)&rsp.RDRAM[(Address+i*2)^2];
|
||||
}*/
|
||||
memcpy(out,&rsp.RDRAM[Address],32);
|
||||
}
|
||||
}
|
||||
|
||||
int l1=out[14^S];
|
||||
int l2=out[15^S];
|
||||
int inp1[8];
|
||||
int inp2[8];
|
||||
out+=16;
|
||||
while(count>0)
|
||||
{
|
||||
// the first interation through, these values are
|
||||
// either 0 in the case of A_INIT, from a special
|
||||
// area of memory in the case of A_LOOP or just
|
||||
// the values we calculated the last time
|
||||
|
||||
code=BufferSpace[(0x4f0+inPtr)^S8];
|
||||
index=code&0xf;
|
||||
index<<=4; // index into the adpcm code table
|
||||
book1=(short *)&adpcmtable[index];
|
||||
book2=book1+8;
|
||||
code>>=4; // upper nibble is scale
|
||||
vscale=(0x8000>>((12-code)-1)); // very strange. 0x8000 would be .5 in 16:16 format
|
||||
// so this appears to be a fractional scale based
|
||||
// on the 12 based inverse of the scale value. note
|
||||
// that this could be negative, in which case we do
|
||||
// not use the calculated vscale value... see the
|
||||
// if(code>12) check below
|
||||
|
||||
inPtr++; // coded adpcm data lies next
|
||||
j=0;
|
||||
while(j<8) // loop of 8, for 8 coded nibbles from 4 bytes
|
||||
// which yields 8 short pcm values
|
||||
{
|
||||
icode=BufferSpace[(0x4f0+inPtr)^S8];
|
||||
inPtr++;
|
||||
|
||||
inp1[j]=(s16)((icode&0xf0)<<8); // this will in effect be signed
|
||||
if(code<12)
|
||||
inp1[j]=((int)((int)inp1[j]*(int)vscale)>>16);
|
||||
/*else
|
||||
int catchme=1;*/
|
||||
j++;
|
||||
|
||||
inp1[j]=(s16)((icode&0xf)<<12);
|
||||
if(code<12)
|
||||
inp1[j]=((int)((int)inp1[j]*(int)vscale)>>16);
|
||||
/*else
|
||||
int catchme=1;*/
|
||||
j++;
|
||||
}
|
||||
j=0;
|
||||
while(j<8)
|
||||
{
|
||||
icode=BufferSpace[(0x4f0+inPtr)^S8];
|
||||
inPtr++;
|
||||
|
||||
inp2[j]=(short)((icode&0xf0)<<8); // this will in effect be signed
|
||||
if(code<12)
|
||||
inp2[j]=((int)((int)inp2[j]*(int)vscale)>>16);
|
||||
/*else
|
||||
int catchme=1;*/
|
||||
j++;
|
||||
|
||||
inp2[j]=(short)((icode&0xf)<<12);
|
||||
if(code<12)
|
||||
inp2[j]=((int)((int)inp2[j]*(int)vscale)>>16);
|
||||
/*else
|
||||
int catchme=1;*/
|
||||
j++;
|
||||
}
|
||||
|
||||
a[0]= (int)book1[0]*(int)l1;
|
||||
a[0]+=(int)book2[0]*(int)l2;
|
||||
a[0]+=(int)inp1[0]*(int)2048;
|
||||
|
||||
a[1] =(int)book1[1]*(int)l1;
|
||||
a[1]+=(int)book2[1]*(int)l2;
|
||||
a[1]+=(int)book2[0]*inp1[0];
|
||||
a[1]+=(int)inp1[1]*(int)2048;
|
||||
|
||||
a[2] =(int)book1[2]*(int)l1;
|
||||
a[2]+=(int)book2[2]*(int)l2;
|
||||
a[2]+=(int)book2[1]*inp1[0];
|
||||
a[2]+=(int)book2[0]*inp1[1];
|
||||
a[2]+=(int)inp1[2]*(int)2048;
|
||||
|
||||
a[3] =(int)book1[3]*(int)l1;
|
||||
a[3]+=(int)book2[3]*(int)l2;
|
||||
a[3]+=(int)book2[2]*inp1[0];
|
||||
a[3]+=(int)book2[1]*inp1[1];
|
||||
a[3]+=(int)book2[0]*inp1[2];
|
||||
a[3]+=(int)inp1[3]*(int)2048;
|
||||
|
||||
a[4] =(int)book1[4]*(int)l1;
|
||||
a[4]+=(int)book2[4]*(int)l2;
|
||||
a[4]+=(int)book2[3]*inp1[0];
|
||||
a[4]+=(int)book2[2]*inp1[1];
|
||||
a[4]+=(int)book2[1]*inp1[2];
|
||||
a[4]+=(int)book2[0]*inp1[3];
|
||||
a[4]+=(int)inp1[4]*(int)2048;
|
||||
|
||||
a[5] =(int)book1[5]*(int)l1;
|
||||
a[5]+=(int)book2[5]*(int)l2;
|
||||
a[5]+=(int)book2[4]*inp1[0];
|
||||
a[5]+=(int)book2[3]*inp1[1];
|
||||
a[5]+=(int)book2[2]*inp1[2];
|
||||
a[5]+=(int)book2[1]*inp1[3];
|
||||
a[5]+=(int)book2[0]*inp1[4];
|
||||
a[5]+=(int)inp1[5]*(int)2048;
|
||||
|
||||
a[6] =(int)book1[6]*(int)l1;
|
||||
a[6]+=(int)book2[6]*(int)l2;
|
||||
a[6]+=(int)book2[5]*inp1[0];
|
||||
a[6]+=(int)book2[4]*inp1[1];
|
||||
a[6]+=(int)book2[3]*inp1[2];
|
||||
a[6]+=(int)book2[2]*inp1[3];
|
||||
a[6]+=(int)book2[1]*inp1[4];
|
||||
a[6]+=(int)book2[0]*inp1[5];
|
||||
a[6]+=(int)inp1[6]*(int)2048;
|
||||
|
||||
a[7] =(int)book1[7]*(int)l1;
|
||||
a[7]+=(int)book2[7]*(int)l2;
|
||||
a[7]+=(int)book2[6]*inp1[0];
|
||||
a[7]+=(int)book2[5]*inp1[1];
|
||||
a[7]+=(int)book2[4]*inp1[2];
|
||||
a[7]+=(int)book2[3]*inp1[3];
|
||||
a[7]+=(int)book2[2]*inp1[4];
|
||||
a[7]+=(int)book2[1]*inp1[5];
|
||||
a[7]+=(int)book2[0]*inp1[6];
|
||||
a[7]+=(int)inp1[7]*(int)2048;
|
||||
|
||||
for(j=0;j<8;j++)
|
||||
{
|
||||
a[j^S]>>=11;
|
||||
if(a[j^S]>32767) a[j^S]=32767;
|
||||
else if(a[j^S]<-32768) a[j^S]=-32768;
|
||||
*(out++)=a[j^S];
|
||||
//*(out+j)=a[j^S];
|
||||
}
|
||||
//out += 0x10;
|
||||
l1=a[6];
|
||||
l2=a[7];
|
||||
|
||||
a[0]= (int)book1[0]*(int)l1;
|
||||
a[0]+=(int)book2[0]*(int)l2;
|
||||
a[0]+=(int)inp2[0]*(int)2048;
|
||||
|
||||
a[1] =(int)book1[1]*(int)l1;
|
||||
a[1]+=(int)book2[1]*(int)l2;
|
||||
a[1]+=(int)book2[0]*inp2[0];
|
||||
a[1]+=(int)inp2[1]*(int)2048;
|
||||
|
||||
a[2] =(int)book1[2]*(int)l1;
|
||||
a[2]+=(int)book2[2]*(int)l2;
|
||||
a[2]+=(int)book2[1]*inp2[0];
|
||||
a[2]+=(int)book2[0]*inp2[1];
|
||||
a[2]+=(int)inp2[2]*(int)2048;
|
||||
|
||||
a[3] =(int)book1[3]*(int)l1;
|
||||
a[3]+=(int)book2[3]*(int)l2;
|
||||
a[3]+=(int)book2[2]*inp2[0];
|
||||
a[3]+=(int)book2[1]*inp2[1];
|
||||
a[3]+=(int)book2[0]*inp2[2];
|
||||
a[3]+=(int)inp2[3]*(int)2048;
|
||||
|
||||
a[4] =(int)book1[4]*(int)l1;
|
||||
a[4]+=(int)book2[4]*(int)l2;
|
||||
a[4]+=(int)book2[3]*inp2[0];
|
||||
a[4]+=(int)book2[2]*inp2[1];
|
||||
a[4]+=(int)book2[1]*inp2[2];
|
||||
a[4]+=(int)book2[0]*inp2[3];
|
||||
a[4]+=(int)inp2[4]*(int)2048;
|
||||
|
||||
a[5] =(int)book1[5]*(int)l1;
|
||||
a[5]+=(int)book2[5]*(int)l2;
|
||||
a[5]+=(int)book2[4]*inp2[0];
|
||||
a[5]+=(int)book2[3]*inp2[1];
|
||||
a[5]+=(int)book2[2]*inp2[2];
|
||||
a[5]+=(int)book2[1]*inp2[3];
|
||||
a[5]+=(int)book2[0]*inp2[4];
|
||||
a[5]+=(int)inp2[5]*(int)2048;
|
||||
|
||||
a[6] =(int)book1[6]*(int)l1;
|
||||
a[6]+=(int)book2[6]*(int)l2;
|
||||
a[6]+=(int)book2[5]*inp2[0];
|
||||
a[6]+=(int)book2[4]*inp2[1];
|
||||
a[6]+=(int)book2[3]*inp2[2];
|
||||
a[6]+=(int)book2[2]*inp2[3];
|
||||
a[6]+=(int)book2[1]*inp2[4];
|
||||
a[6]+=(int)book2[0]*inp2[5];
|
||||
a[6]+=(int)inp2[6]*(int)2048;
|
||||
|
||||
a[7] =(int)book1[7]*(int)l1;
|
||||
a[7]+=(int)book2[7]*(int)l2;
|
||||
a[7]+=(int)book2[6]*inp2[0];
|
||||
a[7]+=(int)book2[5]*inp2[1];
|
||||
a[7]+=(int)book2[4]*inp2[2];
|
||||
a[7]+=(int)book2[3]*inp2[3];
|
||||
a[7]+=(int)book2[2]*inp2[4];
|
||||
a[7]+=(int)book2[1]*inp2[5];
|
||||
a[7]+=(int)book2[0]*inp2[6];
|
||||
a[7]+=(int)inp2[7]*(int)2048;
|
||||
|
||||
for(j=0;j<8;j++)
|
||||
{
|
||||
a[j^S]>>=11;
|
||||
if(a[j^S]>32767) a[j^S]=32767;
|
||||
else if(a[j^S]<-32768) a[j^S]=-32768;
|
||||
*(out++)=a[j^S];
|
||||
//*(out+j+0x1f8)=a[j^S];
|
||||
}
|
||||
l1=a[6];
|
||||
l2=a[7];
|
||||
|
||||
count-=32;
|
||||
}
|
||||
out-=16;
|
||||
memcpy(&rsp.RDRAM[Address],out,32);
|
||||
}
|
||||
|
||||
static void RESAMPLE3 (u32 inst1, u32 inst2) {
|
||||
unsigned char Flags=(u8)((inst2>>0x1e));
|
||||
unsigned int Pitch=((inst2>>0xe)&0xffff)<<1;
|
||||
u32 addy = (inst1 & 0xffffff);
|
||||
unsigned int Accum=0;
|
||||
unsigned int location;
|
||||
s16 *lut;
|
||||
short *dst;
|
||||
s16 *src;
|
||||
dst=(short *)(BufferSpace);
|
||||
src=(s16 *)(BufferSpace);
|
||||
u32 srcPtr=((((inst2>>2)&0xfff)+0x4f0)/2);
|
||||
u32 dstPtr;//=(AudioOutBuffer/2);
|
||||
s32 temp;
|
||||
s32 accum;
|
||||
|
||||
//if (addy > (1024*1024*8))
|
||||
// addy = (inst2 & 0xffffff);
|
||||
|
||||
srcPtr -= 4;
|
||||
|
||||
if (inst2 & 0x3) {
|
||||
dstPtr = 0x660/2;
|
||||
} else {
|
||||
dstPtr = 0x4f0/2;
|
||||
}
|
||||
|
||||
if ((Flags & 0x1) == 0) {
|
||||
for (int x=0; x < 4; x++) //memcpy (src+srcPtr, rsp.RDRAM+addy, 0x8);
|
||||
src[(srcPtr+x)^S] = ((u16 *)rsp.RDRAM)[((addy/2)+x)^S];
|
||||
Accum = *(u16 *)(rsp.RDRAM+addy+10);
|
||||
} else {
|
||||
for (int x=0; x < 4; x++)
|
||||
src[(srcPtr+x)^S] = 0;//*(u16 *)(rsp.RDRAM+((addy+x)^2));
|
||||
}
|
||||
|
||||
for(int i=0;i < 0x170/2;i++) {
|
||||
location = (((Accum * 0x40) >> 0x10) * 8);
|
||||
//location = (Accum >> 0xa) << 0x3;
|
||||
lut = (s16 *)(((u8 *)ResampleLUT) + location);
|
||||
|
||||
temp = ((s32)*(s16*)(src+((srcPtr+0)^S))*((s32)((s16)lut[0])));
|
||||
accum = (s32)(temp >> 15);
|
||||
|
||||
temp = ((s32)*(s16*)(src+((srcPtr+1)^S))*((s32)((s16)lut[1])));
|
||||
accum += (s32)(temp >> 15);
|
||||
|
||||
temp = ((s32)*(s16*)(src+((srcPtr+2)^S))*((s32)((s16)lut[2])));
|
||||
accum += (s32)(temp >> 15);
|
||||
|
||||
temp = ((s32)*(s16*)(src+((srcPtr+3)^S))*((s32)((s16)lut[3])));
|
||||
accum += (s32)(temp >> 15);
|
||||
/* temp = ((s64)*(s16*)(src+((srcPtr+0)^S))*((s64)((s16)lut[0]<<1)));
|
||||
if (temp & 0x8000) temp = (temp^0x8000) + 0x10000;
|
||||
else temp = (temp^0x8000);
|
||||
temp = (s32)(temp >> 16);
|
||||
if ((s32)temp > 32767) temp = 32767;
|
||||
if ((s32)temp < -32768) temp = -32768;
|
||||
accum = (s32)(s16)temp;
|
||||
|
||||
temp = ((s64)*(s16*)(src+((srcPtr+1)^S))*((s64)((s16)lut[1]<<1)));
|
||||
if (temp & 0x8000) temp = (temp^0x8000) + 0x10000;
|
||||
else temp = (temp^0x8000);
|
||||
temp = (s32)(temp >> 16);
|
||||
if ((s32)temp > 32767) temp = 32767;
|
||||
if ((s32)temp < -32768) temp = -32768;
|
||||
accum += (s32)(s16)temp;
|
||||
|
||||
temp = ((s64)*(s16*)(src+((srcPtr+2)^S))*((s64)((s16)lut[2]<<1)));
|
||||
if (temp & 0x8000) temp = (temp^0x8000) + 0x10000;
|
||||
else temp = (temp^0x8000);
|
||||
temp = (s32)(temp >> 16);
|
||||
if ((s32)temp > 32767) temp = 32767;
|
||||
if ((s32)temp < -32768) temp = -32768;
|
||||
accum += (s32)(s16)temp;
|
||||
|
||||
temp = ((s64)*(s16*)(src+((srcPtr+3)^S))*((s64)((s16)lut[3]<<1)));
|
||||
if (temp & 0x8000) temp = (temp^0x8000) + 0x10000;
|
||||
else temp = (temp^0x8000);
|
||||
temp = (s32)(temp >> 16);
|
||||
if ((s32)temp > 32767) temp = 32767;
|
||||
if ((s32)temp < -32768) temp = -32768;
|
||||
accum += (s32)(s16)temp;*/
|
||||
|
||||
if (accum > 32767) accum = 32767;
|
||||
if (accum < -32768) accum = -32768;
|
||||
|
||||
dst[dstPtr^S] = (accum);
|
||||
dstPtr++;
|
||||
Accum += Pitch;
|
||||
srcPtr += (Accum>>16);
|
||||
Accum&=0xffff;
|
||||
}
|
||||
for (int x=0; x < 4; x++)
|
||||
((u16 *)rsp.RDRAM)[((addy/2)+x)^S] = src[(srcPtr+x)^S];
|
||||
*(u16 *)(rsp.RDRAM+addy+10) = Accum;
|
||||
}
|
||||
|
||||
static void INTERLEAVE3 (u32 inst1, u32 inst2) { // Needs accuracy verification...
|
||||
//u32 inL, inR;
|
||||
u16 *outbuff = (u16 *)(BufferSpace + 0x4f0);//(u16 *)(AudioOutBuffer+dmem);
|
||||
u16 *inSrcR;
|
||||
u16 *inSrcL;
|
||||
u16 Left, Right, Left2, Right2;
|
||||
|
||||
//inR = inst2 & 0xFFFF;
|
||||
//inL = (inst2 >> 16) & 0xFFFF;
|
||||
|
||||
inSrcR = (u16 *)(BufferSpace+0xb40);
|
||||
inSrcL = (u16 *)(BufferSpace+0x9d0);
|
||||
|
||||
for (int x = 0; x < (0x170/4); x++) {
|
||||
Left=*(inSrcL++);
|
||||
Right=*(inSrcR++);
|
||||
Left2=*(inSrcL++);
|
||||
Right2=*(inSrcR++);
|
||||
|
||||
#ifdef M64P_BIG_ENDIAN
|
||||
*(outbuff++)=Right;
|
||||
*(outbuff++)=Left;
|
||||
*(outbuff++)=Right2;
|
||||
*(outbuff++)=Left2;
|
||||
#else
|
||||
*(outbuff++)=Right2;
|
||||
*(outbuff++)=Left2;
|
||||
*(outbuff++)=Right;
|
||||
*(outbuff++)=Left;
|
||||
#endif
|
||||
/*
|
||||
Left=*(inSrcL++);
|
||||
Right=*(inSrcR++);
|
||||
*(outbuff++)=(u16)Left;
|
||||
Left >>= 16;
|
||||
*(outbuff++)=(u16)Right;
|
||||
Right >>= 16;
|
||||
*(outbuff++)=(u16)Left;
|
||||
*(outbuff++)=(u16)Right;*/
|
||||
}
|
||||
}
|
||||
|
||||
//static void UNKNOWN (u32 inst1, u32 inst2);
|
||||
/*
|
||||
typedef struct {
|
||||
unsigned char sync;
|
||||
|
||||
unsigned char error_protection : 1; // 0=yes, 1=no
|
||||
unsigned char lay : 2; // 4-lay = layerI, II or III
|
||||
unsigned char version : 1; // 3=mpeg 1.0, 2=mpeg 2.5 0=mpeg 2.0
|
||||
unsigned char sync2 : 4;
|
||||
|
||||
unsigned char extension : 1; // Unknown
|
||||
unsigned char padding : 1; // padding
|
||||
unsigned char sampling_freq : 2; // see table below
|
||||
unsigned char bitrate_index : 4; // see table below
|
||||
|
||||
unsigned char emphasis : 2; //see table below
|
||||
unsigned char original : 1; // 0=no 1=yes
|
||||
unsigned char copyright : 1; // 0=no 1=yes
|
||||
unsigned char mode_ext : 2; // used with "joint stereo" mode
|
||||
unsigned char mode : 2; // Channel Mode
|
||||
} mp3struct;
|
||||
|
||||
mp3struct mp3;
|
||||
FILE *mp3dat;
|
||||
*/
|
||||
|
||||
static void WHATISTHIS (u32 inst1, u32 inst2) {
|
||||
}
|
||||
|
||||
//static FILE *fp = fopen ("d:\\mp3info.txt", "wt");
|
||||
u32 setaddr;
|
||||
static void MP3ADDY (u32 inst1, u32 inst2) {
|
||||
setaddr = (inst2 & 0xffffff);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
void rsp_run(void);
|
||||
void mp3setup (unsigned int inst1, unsigned int inst2, unsigned int t8);
|
||||
}
|
||||
|
||||
extern u32 base, dmembase;
|
||||
extern "C" {
|
||||
extern char *pDMEM;
|
||||
}
|
||||
void MP3 (u32 inst1, u32 inst2);
|
||||
/*
|
||||
{
|
||||
// return;
|
||||
// Setup Registers...
|
||||
mp3setup (inst1, inst2, 0xFA0);
|
||||
|
||||
// Setup Memory Locations...
|
||||
//u32 base = ((u32*)dmem)[0xFD0/4]; // Should be 000291A0
|
||||
memcpy (BufferSpace, dmembase+rsp.RDRAM, 0x10);
|
||||
((u32*)BufferSpace)[0x0] = base;
|
||||
((u32*)BufferSpace)[0x008/4] += base;
|
||||
((u32*)BufferSpace)[0xFFC/4] = loopval;
|
||||
((u32*)BufferSpace)[0xFF8/4] = dmembase;
|
||||
|
||||
memcpy (imem+0x238, rsp.RDRAM+((u32*)BufferSpace)[0x008/4], 0x9C0);
|
||||
((u32*)BufferSpace)[0xFF4/4] = setaddr;
|
||||
pDMEM = (char *)BufferSpace;
|
||||
rsp_run (void);
|
||||
dmembase = ((u32*)BufferSpace)[0xFF8/4];
|
||||
loopval = ((u32*)BufferSpace)[0xFFC/4];
|
||||
//0x1A98 SW S1, 0x0FF4 (R0)
|
||||
//0x1A9C SW S0, 0x0FF8 (R0)
|
||||
//0x1AA0 SW T7, 0x0FFC (R0)
|
||||
//0x1AA4 SW T3, 0x0FF0 (R0)
|
||||
//fprintf (fp, "mp3: inst1: %08X, inst2: %08X\n", inst1, inst2);
|
||||
}*/
|
||||
/*
|
||||
FFT = Fast Fourier Transform
|
||||
DCT = Discrete Cosine Transform
|
||||
MPEG-1 Layer 3 retains Layer 2's 1152-sample window, as well as the FFT polyphase filter for
|
||||
backward compatibility, but adds a modified DCT filter. DCT's advantages over DFTs (discrete
|
||||
Fourier transforms) include half as many multiply-accumulate operations and half the
|
||||
generated coefficients because the sinusoidal portion of the calculation is absent, and DCT
|
||||
generally involves simpler math. The finite lengths of a conventional DCTs' bandpass impulse
|
||||
responses, however, may result in block-boundary effects. MDCTs overlap the analysis blocks
|
||||
and lowpass-filter the decoded audio to remove aliases, eliminating these effects. MDCTs also
|
||||
have a higher transform coding gain than the standard DCT, and their basic functions
|
||||
correspond to better bandpass response.
|
||||
|
||||
MPEG-1 Layer 3's DCT sub-bands are unequally sized, and correspond to the human auditory
|
||||
system's critical bands. In Layer 3 decoders must support both constant- and variable-bit-rate
|
||||
bit streams. (However, many Layer 1 and 2 decoders also handle variable bit rates). Finally,
|
||||
Layer 3 encoders Huffman-code the quantized coefficients before archiving or transmission for
|
||||
additional lossless compression. Bit streams range from 32 to 320 kbps, and 128-kbps rates
|
||||
achieve near-CD quality, an important specification to enable dual-channel ISDN
|
||||
(integrated-services-digital-network) to be the future high-bandwidth pipe to the home.
|
||||
|
||||
*/
|
||||
static void DISABLE (u32 inst1, u32 inst2) {
|
||||
//MessageBox (NULL, "Help", "ABI 3 Command 0", MB_OK);
|
||||
//ChangeABI (5);
|
||||
}
|
||||
|
||||
|
||||
extern "C" const acmd_callback_t ABI3[0x10] = {
|
||||
DISABLE , ADPCM3 , CLEARBUFF3, ENVMIXER3 , LOADBUFF3, RESAMPLE3 , SAVEBUFF3, MP3,
|
||||
MP3ADDY, SETVOL3, DMEMMOVE3 , LOADADPCM3 , MIXER3 , INTERLEAVE3, WHATISTHIS , SETLOOP3
|
||||
};
|
||||
|
||||
|
|
@ -1,604 +0,0 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - ucode3mp3.h *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2009 Richard Goedeken *
|
||||
* Copyright (C) 2002 Hacktarux *
|
||||
* *
|
||||
* 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 <string.h>
|
||||
# include <stdio.h>
|
||||
|
||||
extern "C" {
|
||||
#include "hle.h"
|
||||
#include "alist_internal.h"
|
||||
}
|
||||
|
||||
static const u16 DeWindowLUT [0x420] = {
|
||||
0x0000, 0xFFF3, 0x005D, 0xFF38, 0x037A, 0xF736, 0x0B37, 0xC00E,
|
||||
0x7FFF, 0x3FF2, 0x0B37, 0x08CA, 0x037A, 0x00C8, 0x005D, 0x000D,
|
||||
0x0000, 0xFFF3, 0x005D, 0xFF38, 0x037A, 0xF736, 0x0B37, 0xC00E,
|
||||
0x7FFF, 0x3FF2, 0x0B37, 0x08CA, 0x037A, 0x00C8, 0x005D, 0x000D,
|
||||
0x0000, 0xFFF2, 0x005F, 0xFF1D, 0x0369, 0xF697, 0x0A2A, 0xBCE7,
|
||||
0x7FEB, 0x3CCB, 0x0C2B, 0x082B, 0x0385, 0x00AF, 0x005B, 0x000B,
|
||||
0x0000, 0xFFF2, 0x005F, 0xFF1D, 0x0369, 0xF697, 0x0A2A, 0xBCE7,
|
||||
0x7FEB, 0x3CCB, 0x0C2B, 0x082B, 0x0385, 0x00AF, 0x005B, 0x000B,
|
||||
0x0000, 0xFFF1, 0x0061, 0xFF02, 0x0354, 0xF5F9, 0x0905, 0xB9C4,
|
||||
0x7FB0, 0x39A4, 0x0D08, 0x078C, 0x038C, 0x0098, 0x0058, 0x000A,
|
||||
0x0000, 0xFFF1, 0x0061, 0xFF02, 0x0354, 0xF5F9, 0x0905, 0xB9C4,
|
||||
0x7FB0, 0x39A4, 0x0D08, 0x078C, 0x038C, 0x0098, 0x0058, 0x000A,
|
||||
0x0000, 0xFFEF, 0x0062, 0xFEE6, 0x033B, 0xF55C, 0x07C8, 0xB6A4,
|
||||
0x7F4D, 0x367E, 0x0DCE, 0x06EE, 0x038F, 0x0080, 0x0056, 0x0009,
|
||||
0x0000, 0xFFEF, 0x0062, 0xFEE6, 0x033B, 0xF55C, 0x07C8, 0xB6A4,
|
||||
0x7F4D, 0x367E, 0x0DCE, 0x06EE, 0x038F, 0x0080, 0x0056, 0x0009,
|
||||
0x0000, 0xFFEE, 0x0063, 0xFECA, 0x031C, 0xF4C3, 0x0671, 0xB38C,
|
||||
0x7EC2, 0x335D, 0x0E7C, 0x0652, 0x038E, 0x006B, 0x0053, 0x0008,
|
||||
0x0000, 0xFFEE, 0x0063, 0xFECA, 0x031C, 0xF4C3, 0x0671, 0xB38C,
|
||||
0x7EC2, 0x335D, 0x0E7C, 0x0652, 0x038E, 0x006B, 0x0053, 0x0008,
|
||||
0x0000, 0xFFEC, 0x0064, 0xFEAC, 0x02F7, 0xF42C, 0x0502, 0xB07C,
|
||||
0x7E12, 0x3041, 0x0F14, 0x05B7, 0x038A, 0x0056, 0x0050, 0x0007,
|
||||
0x0000, 0xFFEC, 0x0064, 0xFEAC, 0x02F7, 0xF42C, 0x0502, 0xB07C,
|
||||
0x7E12, 0x3041, 0x0F14, 0x05B7, 0x038A, 0x0056, 0x0050, 0x0007,
|
||||
0x0000, 0xFFEB, 0x0064, 0xFE8E, 0x02CE, 0xF399, 0x037A, 0xAD75,
|
||||
0x7D3A, 0x2D2C, 0x0F97, 0x0520, 0x0382, 0x0043, 0x004D, 0x0007,
|
||||
0x0000, 0xFFEB, 0x0064, 0xFE8E, 0x02CE, 0xF399, 0x037A, 0xAD75,
|
||||
0x7D3A, 0x2D2C, 0x0F97, 0x0520, 0x0382, 0x0043, 0x004D, 0x0007,
|
||||
0xFFFF, 0xFFE9, 0x0063, 0xFE6F, 0x029E, 0xF30B, 0x01D8, 0xAA7B,
|
||||
0x7C3D, 0x2A1F, 0x1004, 0x048B, 0x0377, 0x0030, 0x004A, 0x0006,
|
||||
0xFFFF, 0xFFE9, 0x0063, 0xFE6F, 0x029E, 0xF30B, 0x01D8, 0xAA7B,
|
||||
0x7C3D, 0x2A1F, 0x1004, 0x048B, 0x0377, 0x0030, 0x004A, 0x0006,
|
||||
0xFFFF, 0xFFE7, 0x0062, 0xFE4F, 0x0269, 0xF282, 0x001F, 0xA78D,
|
||||
0x7B1A, 0x271C, 0x105D, 0x03F9, 0x036A, 0x001F, 0x0046, 0x0006,
|
||||
0xFFFF, 0xFFE7, 0x0062, 0xFE4F, 0x0269, 0xF282, 0x001F, 0xA78D,
|
||||
0x7B1A, 0x271C, 0x105D, 0x03F9, 0x036A, 0x001F, 0x0046, 0x0006,
|
||||
0xFFFF, 0xFFE4, 0x0061, 0xFE2F, 0x022F, 0xF1FF, 0xFE4C, 0xA4AF,
|
||||
0x79D3, 0x2425, 0x10A2, 0x036C, 0x0359, 0x0010, 0x0043, 0x0005,
|
||||
0xFFFF, 0xFFE4, 0x0061, 0xFE2F, 0x022F, 0xF1FF, 0xFE4C, 0xA4AF,
|
||||
0x79D3, 0x2425, 0x10A2, 0x036C, 0x0359, 0x0010, 0x0043, 0x0005,
|
||||
0xFFFF, 0xFFE2, 0x005E, 0xFE10, 0x01EE, 0xF184, 0xFC61, 0xA1E1,
|
||||
0x7869, 0x2139, 0x10D3, 0x02E3, 0x0346, 0x0001, 0x0040, 0x0004,
|
||||
0xFFFF, 0xFFE2, 0x005E, 0xFE10, 0x01EE, 0xF184, 0xFC61, 0xA1E1,
|
||||
0x7869, 0x2139, 0x10D3, 0x02E3, 0x0346, 0x0001, 0x0040, 0x0004,
|
||||
0xFFFF, 0xFFE0, 0x005B, 0xFDF0, 0x01A8, 0xF111, 0xFA5F, 0x9F27,
|
||||
0x76DB, 0x1E5C, 0x10F2, 0x025E, 0x0331, 0xFFF3, 0x003D, 0x0004,
|
||||
0xFFFF, 0xFFE0, 0x005B, 0xFDF0, 0x01A8, 0xF111, 0xFA5F, 0x9F27,
|
||||
0x76DB, 0x1E5C, 0x10F2, 0x025E, 0x0331, 0xFFF3, 0x003D, 0x0004,
|
||||
0xFFFF, 0xFFDE, 0x0057, 0xFDD0, 0x015B, 0xF0A7, 0xF845, 0x9C80,
|
||||
0x752C, 0x1B8E, 0x1100, 0x01DE, 0x0319, 0xFFE7, 0x003A, 0x0003,
|
||||
0xFFFF, 0xFFDE, 0x0057, 0xFDD0, 0x015B, 0xF0A7, 0xF845, 0x9C80,
|
||||
0x752C, 0x1B8E, 0x1100, 0x01DE, 0x0319, 0xFFE7, 0x003A, 0x0003,
|
||||
0xFFFE, 0xFFDB, 0x0053, 0xFDB0, 0x0108, 0xF046, 0xF613, 0x99EE,
|
||||
0x735C, 0x18D1, 0x10FD, 0x0163, 0x0300, 0xFFDC, 0x0037, 0x0003,
|
||||
0xFFFE, 0xFFDB, 0x0053, 0xFDB0, 0x0108, 0xF046, 0xF613, 0x99EE,
|
||||
0x735C, 0x18D1, 0x10FD, 0x0163, 0x0300, 0xFFDC, 0x0037, 0x0003,
|
||||
0xFFFE, 0xFFD8, 0x004D, 0xFD90, 0x00B0, 0xEFF0, 0xF3CC, 0x9775,
|
||||
0x716C, 0x1624, 0x10EA, 0x00EE, 0x02E5, 0xFFD2, 0x0033, 0x0003,
|
||||
0xFFFE, 0xFFD8, 0x004D, 0xFD90, 0x00B0, 0xEFF0, 0xF3CC, 0x9775,
|
||||
0x716C, 0x1624, 0x10EA, 0x00EE, 0x02E5, 0xFFD2, 0x0033, 0x0003,
|
||||
0xFFFE, 0xFFD6, 0x0047, 0xFD72, 0x0051, 0xEFA6, 0xF16F, 0x9514,
|
||||
0x6F5E, 0x138A, 0x10C8, 0x007E, 0x02CA, 0xFFC9, 0x0030, 0x0003,
|
||||
0xFFFE, 0xFFD6, 0x0047, 0xFD72, 0x0051, 0xEFA6, 0xF16F, 0x9514,
|
||||
0x6F5E, 0x138A, 0x10C8, 0x007E, 0x02CA, 0xFFC9, 0x0030, 0x0003,
|
||||
0xFFFE, 0xFFD3, 0x0040, 0xFD54, 0xFFEC, 0xEF68, 0xEEFC, 0x92CD,
|
||||
0x6D33, 0x1104, 0x1098, 0x0014, 0x02AC, 0xFFC0, 0x002D, 0x0002,
|
||||
0xFFFE, 0xFFD3, 0x0040, 0xFD54, 0xFFEC, 0xEF68, 0xEEFC, 0x92CD,
|
||||
0x6D33, 0x1104, 0x1098, 0x0014, 0x02AC, 0xFFC0, 0x002D, 0x0002,
|
||||
0x0030, 0xFFC9, 0x02CA, 0x007E, 0x10C8, 0x138A, 0x6F5E, 0x9514,
|
||||
0xF16F, 0xEFA6, 0x0051, 0xFD72, 0x0047, 0xFFD6, 0xFFFE, 0x0003,
|
||||
0x0030, 0xFFC9, 0x02CA, 0x007E, 0x10C8, 0x138A, 0x6F5E, 0x9514,
|
||||
0xF16F, 0xEFA6, 0x0051, 0xFD72, 0x0047, 0xFFD6, 0xFFFE, 0x0003,
|
||||
0x0033, 0xFFD2, 0x02E5, 0x00EE, 0x10EA, 0x1624, 0x716C, 0x9775,
|
||||
0xF3CC, 0xEFF0, 0x00B0, 0xFD90, 0x004D, 0xFFD8, 0xFFFE, 0x0003,
|
||||
0x0033, 0xFFD2, 0x02E5, 0x00EE, 0x10EA, 0x1624, 0x716C, 0x9775,
|
||||
0xF3CC, 0xEFF0, 0x00B0, 0xFD90, 0x004D, 0xFFD8, 0xFFFE, 0x0003,
|
||||
0x0037, 0xFFDC, 0x0300, 0x0163, 0x10FD, 0x18D1, 0x735C, 0x99EE,
|
||||
0xF613, 0xF046, 0x0108, 0xFDB0, 0x0053, 0xFFDB, 0xFFFE, 0x0003,
|
||||
0x0037, 0xFFDC, 0x0300, 0x0163, 0x10FD, 0x18D1, 0x735C, 0x99EE,
|
||||
0xF613, 0xF046, 0x0108, 0xFDB0, 0x0053, 0xFFDB, 0xFFFE, 0x0003,
|
||||
0x003A, 0xFFE7, 0x0319, 0x01DE, 0x1100, 0x1B8E, 0x752C, 0x9C80,
|
||||
0xF845, 0xF0A7, 0x015B, 0xFDD0, 0x0057, 0xFFDE, 0xFFFF, 0x0003,
|
||||
0x003A, 0xFFE7, 0x0319, 0x01DE, 0x1100, 0x1B8E, 0x752C, 0x9C80,
|
||||
0xF845, 0xF0A7, 0x015B, 0xFDD0, 0x0057, 0xFFDE, 0xFFFF, 0x0004,
|
||||
0x003D, 0xFFF3, 0x0331, 0x025E, 0x10F2, 0x1E5C, 0x76DB, 0x9F27,
|
||||
0xFA5F, 0xF111, 0x01A8, 0xFDF0, 0x005B, 0xFFE0, 0xFFFF, 0x0004,
|
||||
0x003D, 0xFFF3, 0x0331, 0x025E, 0x10F2, 0x1E5C, 0x76DB, 0x9F27,
|
||||
0xFA5F, 0xF111, 0x01A8, 0xFDF0, 0x005B, 0xFFE0, 0xFFFF, 0x0004,
|
||||
0x0040, 0x0001, 0x0346, 0x02E3, 0x10D3, 0x2139, 0x7869, 0xA1E1,
|
||||
0xFC61, 0xF184, 0x01EE, 0xFE10, 0x005E, 0xFFE2, 0xFFFF, 0x0004,
|
||||
0x0040, 0x0001, 0x0346, 0x02E3, 0x10D3, 0x2139, 0x7869, 0xA1E1,
|
||||
0xFC61, 0xF184, 0x01EE, 0xFE10, 0x005E, 0xFFE2, 0xFFFF, 0x0005,
|
||||
0x0043, 0x0010, 0x0359, 0x036C, 0x10A2, 0x2425, 0x79D3, 0xA4AF,
|
||||
0xFE4C, 0xF1FF, 0x022F, 0xFE2F, 0x0061, 0xFFE4, 0xFFFF, 0x0005,
|
||||
0x0043, 0x0010, 0x0359, 0x036C, 0x10A2, 0x2425, 0x79D3, 0xA4AF,
|
||||
0xFE4C, 0xF1FF, 0x022F, 0xFE2F, 0x0061, 0xFFE4, 0xFFFF, 0x0006,
|
||||
0x0046, 0x001F, 0x036A, 0x03F9, 0x105D, 0x271C, 0x7B1A, 0xA78D,
|
||||
0x001F, 0xF282, 0x0269, 0xFE4F, 0x0062, 0xFFE7, 0xFFFF, 0x0006,
|
||||
0x0046, 0x001F, 0x036A, 0x03F9, 0x105D, 0x271C, 0x7B1A, 0xA78D,
|
||||
0x001F, 0xF282, 0x0269, 0xFE4F, 0x0062, 0xFFE7, 0xFFFF, 0x0006,
|
||||
0x004A, 0x0030, 0x0377, 0x048B, 0x1004, 0x2A1F, 0x7C3D, 0xAA7B,
|
||||
0x01D8, 0xF30B, 0x029E, 0xFE6F, 0x0063, 0xFFE9, 0xFFFF, 0x0006,
|
||||
0x004A, 0x0030, 0x0377, 0x048B, 0x1004, 0x2A1F, 0x7C3D, 0xAA7B,
|
||||
0x01D8, 0xF30B, 0x029E, 0xFE6F, 0x0063, 0xFFE9, 0xFFFF, 0x0007,
|
||||
0x004D, 0x0043, 0x0382, 0x0520, 0x0F97, 0x2D2C, 0x7D3A, 0xAD75,
|
||||
0x037A, 0xF399, 0x02CE, 0xFE8E, 0x0064, 0xFFEB, 0x0000, 0x0007,
|
||||
0x004D, 0x0043, 0x0382, 0x0520, 0x0F97, 0x2D2C, 0x7D3A, 0xAD75,
|
||||
0x037A, 0xF399, 0x02CE, 0xFE8E, 0x0064, 0xFFEB, 0x0000, 0x0007,
|
||||
0x0050, 0x0056, 0x038A, 0x05B7, 0x0F14, 0x3041, 0x7E12, 0xB07C,
|
||||
0x0502, 0xF42C, 0x02F7, 0xFEAC, 0x0064, 0xFFEC, 0x0000, 0x0007,
|
||||
0x0050, 0x0056, 0x038A, 0x05B7, 0x0F14, 0x3041, 0x7E12, 0xB07C,
|
||||
0x0502, 0xF42C, 0x02F7, 0xFEAC, 0x0064, 0xFFEC, 0x0000, 0x0008,
|
||||
0x0053, 0x006B, 0x038E, 0x0652, 0x0E7C, 0x335D, 0x7EC2, 0xB38C,
|
||||
0x0671, 0xF4C3, 0x031C, 0xFECA, 0x0063, 0xFFEE, 0x0000, 0x0008,
|
||||
0x0053, 0x006B, 0x038E, 0x0652, 0x0E7C, 0x335D, 0x7EC2, 0xB38C,
|
||||
0x0671, 0xF4C3, 0x031C, 0xFECA, 0x0063, 0xFFEE, 0x0000, 0x0009,
|
||||
0x0056, 0x0080, 0x038F, 0x06EE, 0x0DCE, 0x367E, 0x7F4D, 0xB6A4,
|
||||
0x07C8, 0xF55C, 0x033B, 0xFEE6, 0x0062, 0xFFEF, 0x0000, 0x0009,
|
||||
0x0056, 0x0080, 0x038F, 0x06EE, 0x0DCE, 0x367E, 0x7F4D, 0xB6A4,
|
||||
0x07C8, 0xF55C, 0x033B, 0xFEE6, 0x0062, 0xFFEF, 0x0000, 0x000A,
|
||||
0x0058, 0x0098, 0x038C, 0x078C, 0x0D08, 0x39A4, 0x7FB0, 0xB9C4,
|
||||
0x0905, 0xF5F9, 0x0354, 0xFF02, 0x0061, 0xFFF1, 0x0000, 0x000A,
|
||||
0x0058, 0x0098, 0x038C, 0x078C, 0x0D08, 0x39A4, 0x7FB0, 0xB9C4,
|
||||
0x0905, 0xF5F9, 0x0354, 0xFF02, 0x0061, 0xFFF1, 0x0000, 0x000B,
|
||||
0x005B, 0x00AF, 0x0385, 0x082B, 0x0C2B, 0x3CCB, 0x7FEB, 0xBCE7,
|
||||
0x0A2A, 0xF697, 0x0369, 0xFF1D, 0x005F, 0xFFF2, 0x0000, 0x000B,
|
||||
0x005B, 0x00AF, 0x0385, 0x082B, 0x0C2B, 0x3CCB, 0x7FEB, 0xBCE7,
|
||||
0x0A2A, 0xF697, 0x0369, 0xFF1D, 0x005F, 0xFFF2, 0x0000, 0x000D,
|
||||
0x005D, 0x00C8, 0x037A, 0x08CA, 0x0B37, 0x3FF2, 0x7FFF, 0xC00E,
|
||||
0x0B37, 0xF736, 0x037A, 0xFF38, 0x005D, 0xFFF3, 0x0000, 0x000D,
|
||||
0x005D, 0x00C8, 0x037A, 0x08CA, 0x0B37, 0x3FF2, 0x7FFF, 0xC00E,
|
||||
0x0B37, 0xF736, 0x037A, 0xFF38, 0x005D, 0xFFF3, 0x0000, 0x0000
|
||||
};
|
||||
|
||||
//static u16 myVector[32][8];
|
||||
|
||||
static u8 mp3data[0x1000];
|
||||
|
||||
static s32 v[32];
|
||||
|
||||
static void MP3AB0 () {
|
||||
// Part 2 - 100% Accurate
|
||||
const u16 LUT2[8] = { 0xFEC4, 0xF4FA, 0xC5E4, 0xE1C4,
|
||||
0x1916, 0x4A50, 0xA268, 0x78AE };
|
||||
const u16 LUT3[4] = { 0xFB14, 0xD4DC, 0x31F2, 0x8E3A };
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
v[16+i] = v[0+i] + v[8+i];
|
||||
v[24+i] = ((v[0+i] - v[8+i]) * LUT2[i]) >> 0x10;
|
||||
}
|
||||
|
||||
// Part 3: 4-wide butterflies
|
||||
|
||||
for (i=0; i < 4; i++) {
|
||||
v[0+i] = v[16+i] + v[20+i];
|
||||
v[4+i] = ((v[16+i] - v[20+i]) * LUT3[i]) >> 0x10;
|
||||
|
||||
v[8+i] = v[24+i] + v[28+i];
|
||||
v[12+i] = ((v[24+i] - v[28+i]) * LUT3[i]) >> 0x10;
|
||||
}
|
||||
|
||||
// Part 4: 2-wide butterflies - 100% Accurate
|
||||
|
||||
for (i = 0; i < 16; i+=4) {
|
||||
v[16+i] = v[0+i] + v[2+i];
|
||||
v[18+i] = ((v[0+i] - v[2+i]) * 0xEC84) >> 0x10;
|
||||
|
||||
v[17+i] = v[1+i] + v[3+i];
|
||||
v[19+i] = ((v[1+i] - v[3+i]) * 0x61F8) >> 0x10;
|
||||
}
|
||||
}
|
||||
|
||||
static void InnerLoop ();
|
||||
|
||||
static u32 inPtr, outPtr;
|
||||
|
||||
static u32 t6;// = 0x08A0; // I think these are temporary storage buffers
|
||||
static u32 t5;// = 0x0AC0;
|
||||
static u32 t4;// = (inst1 & 0x1E);
|
||||
|
||||
void MP3 (u32 inst1, u32 inst2) {
|
||||
// Initialization Code
|
||||
u32 readPtr; // s5
|
||||
u32 writePtr; // s6
|
||||
//u32 Count = 0x0480; // s4
|
||||
u32 tmp;
|
||||
//u32 inPtr, outPtr;
|
||||
|
||||
t6 = 0x08A0; // I think these are temporary storage buffers
|
||||
t5 = 0x0AC0;
|
||||
t4 = (inst1 & 0x1E);
|
||||
|
||||
writePtr = inst2 & 0xFFFFFF;
|
||||
readPtr = writePtr;
|
||||
memcpy (mp3data+0xCE8, rsp.RDRAM+readPtr, 8); // Just do that for efficiency... may remove and use directly later anyway
|
||||
readPtr += 8; // This must be a header byte or whatnot
|
||||
|
||||
for (int cnt = 0; cnt < 0x480; cnt += 0x180) {
|
||||
memcpy (mp3data+0xCF0, rsp.RDRAM+readPtr, 0x180); // DMA: 0xCF0 <- RDRAM[s5] : 0x180
|
||||
inPtr = 0xCF0; // s7
|
||||
outPtr = 0xE70; // s3
|
||||
// --------------- Inner Loop Start --------------------
|
||||
for (int cnt2 = 0; cnt2 < 0x180; cnt2 += 0x40) {
|
||||
t6 &= 0xFFE0;
|
||||
t5 &= 0xFFE0;
|
||||
t6 |= t4;
|
||||
t5 |= t4;
|
||||
InnerLoop ();
|
||||
t4 = (t4-2)&0x1E;
|
||||
tmp = t6;
|
||||
t6 = t5;
|
||||
t5 = tmp;
|
||||
//outPtr += 0x40;
|
||||
inPtr += 0x40;
|
||||
}
|
||||
// --------------- Inner Loop End --------------------
|
||||
memcpy (rsp.RDRAM+writePtr, mp3data+0xe70, 0x180);
|
||||
writePtr += 0x180;
|
||||
readPtr += 0x180;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void InnerLoop () {
|
||||
// Part 1: 100% Accurate
|
||||
|
||||
int i;
|
||||
v[0] = *(s16 *)(mp3data+inPtr+(0x00^S16)); v[31] = *(s16 *)(mp3data+inPtr+(0x3E^S16)); v[0] += v[31];
|
||||
v[1] = *(s16 *)(mp3data+inPtr+(0x02^S16)); v[30] = *(s16 *)(mp3data+inPtr+(0x3C^S16)); v[1] += v[30];
|
||||
v[2] = *(s16 *)(mp3data+inPtr+(0x06^S16)); v[28] = *(s16 *)(mp3data+inPtr+(0x38^S16)); v[2] += v[28];
|
||||
v[3] = *(s16 *)(mp3data+inPtr+(0x04^S16)); v[29] = *(s16 *)(mp3data+inPtr+(0x3A^S16)); v[3] += v[29];
|
||||
|
||||
v[4] = *(s16 *)(mp3data+inPtr+(0x0E^S16)); v[24] = *(s16 *)(mp3data+inPtr+(0x30^S16)); v[4] += v[24];
|
||||
v[5] = *(s16 *)(mp3data+inPtr+(0x0C^S16)); v[25] = *(s16 *)(mp3data+inPtr+(0x32^S16)); v[5] += v[25];
|
||||
v[6] = *(s16 *)(mp3data+inPtr+(0x08^S16)); v[27] = *(s16 *)(mp3data+inPtr+(0x36^S16)); v[6] += v[27];
|
||||
v[7] = *(s16 *)(mp3data+inPtr+(0x0A^S16)); v[26] = *(s16 *)(mp3data+inPtr+(0x34^S16)); v[7] += v[26];
|
||||
|
||||
v[8] = *(s16 *)(mp3data+inPtr+(0x1E^S16)); v[16] = *(s16 *)(mp3data+inPtr+(0x20^S16)); v[8] += v[16];
|
||||
v[9] = *(s16 *)(mp3data+inPtr+(0x1C^S16)); v[17] = *(s16 *)(mp3data+inPtr+(0x22^S16)); v[9] += v[17];
|
||||
v[10]= *(s16 *)(mp3data+inPtr+(0x18^S16)); v[19] = *(s16 *)(mp3data+inPtr+(0x26^S16)); v[10]+= v[19];
|
||||
v[11]= *(s16 *)(mp3data+inPtr+(0x1A^S16)); v[18] = *(s16 *)(mp3data+inPtr+(0x24^S16)); v[11]+= v[18];
|
||||
|
||||
v[12]= *(s16 *)(mp3data+inPtr+(0x10^S16)); v[23] = *(s16 *)(mp3data+inPtr+(0x2E^S16)); v[12]+= v[23];
|
||||
v[13]= *(s16 *)(mp3data+inPtr+(0x12^S16)); v[22] = *(s16 *)(mp3data+inPtr+(0x2C^S16)); v[13]+= v[22];
|
||||
v[14]= *(s16 *)(mp3data+inPtr+(0x16^S16)); v[20] = *(s16 *)(mp3data+inPtr+(0x28^S16)); v[14]+= v[20];
|
||||
v[15]= *(s16 *)(mp3data+inPtr+(0x14^S16)); v[21] = *(s16 *)(mp3data+inPtr+(0x2A^S16)); v[15]+= v[21];
|
||||
|
||||
// Part 2-4
|
||||
|
||||
MP3AB0 ();
|
||||
|
||||
// Part 5 - 1-Wide Butterflies - 100% Accurate but need SSVs!!!
|
||||
|
||||
u32 t0 = t6 + 0x100;
|
||||
u32 t1 = t6 + 0x200;
|
||||
u32 t2 = t5 + 0x100;
|
||||
u32 t3 = t5 + 0x200;
|
||||
/*RSP_GPR[0x8].W = t0;
|
||||
RSP_GPR[0x9].W = t1;
|
||||
RSP_GPR[0xA].W = t2;
|
||||
RSP_GPR[0xB].W = t3;
|
||||
|
||||
RSP_Vect[0].DW[1] = 0xB504A57E00016A09;
|
||||
RSP_Vect[0].DW[0] = 0x0002D4130005A827;
|
||||
*/
|
||||
|
||||
// 0x13A8
|
||||
v[1] = 0;
|
||||
v[11] = ((v[16] - v[17]) * 0xB504) >> 0x10;
|
||||
|
||||
v[16] = -v[16] -v[17];
|
||||
v[2] = v[18] + v[19];
|
||||
// ** Store v[11] -> (T6 + 0)**
|
||||
*(s16 *)(mp3data+((t6+(short)0x0))) = (short)v[11];
|
||||
|
||||
|
||||
v[11] = -v[11];
|
||||
// ** Store v[16] -> (T3 + 0)**
|
||||
*(s16 *)(mp3data+((t3+(short)0x0))) = (short)v[16];
|
||||
// ** Store v[11] -> (T5 + 0)**
|
||||
*(s16 *)(mp3data+((t5+(short)0x0))) = (short)v[11];
|
||||
// 0x13E8 - Verified....
|
||||
v[2] = -v[2];
|
||||
// ** Store v[2] -> (T2 + 0)**
|
||||
*(s16 *)(mp3data+((t2+(short)0x0))) = (short)v[2];
|
||||
v[3] = (((v[18] - v[19]) * 0x16A09) >> 0x10) + v[2];
|
||||
// ** Store v[3] -> (T0 + 0)**
|
||||
*(s16 *)(mp3data+((t0+(short)0x0))) = (short)v[3];
|
||||
// 0x1400 - Verified
|
||||
v[4] = -v[20] -v[21];
|
||||
v[6] = v[22] + v[23];
|
||||
v[5] = ((v[20] - v[21]) * 0x16A09) >> 0x10;
|
||||
// ** Store v[4] -> (T3 + 0xFF80)
|
||||
*(s16 *)(mp3data+((t3+(short)0xFF80))) = (short)v[4];
|
||||
v[7] = ((v[22] - v[23]) * 0x2D413) >> 0x10;
|
||||
v[5] = v[5] - v[4];
|
||||
v[7] = v[7] - v[5];
|
||||
v[6] = v[6] + v[6];
|
||||
v[5] = v[5] - v[6];
|
||||
v[4] = -v[4] - v[6];
|
||||
// *** Store v[7] -> (T1 + 0xFF80)
|
||||
*(s16 *)(mp3data+((t1+(short)0xFF80))) = (short)v[7];
|
||||
// *** Store v[4] -> (T2 + 0xFF80)
|
||||
*(s16 *)(mp3data+((t2+(short)0xFF80))) = (short)v[4];
|
||||
// *** Store v[5] -> (T0 + 0xFF80)
|
||||
*(s16 *)(mp3data+((t0+(short)0xFF80))) = (short)v[5];
|
||||
v[8] = v[24] + v[25];
|
||||
|
||||
|
||||
v[9] = ((v[24] - v[25]) * 0x16A09) >> 0x10;
|
||||
v[2] = v[8] + v[9];
|
||||
v[11] = ((v[26] - v[27]) * 0x2D413) >> 0x10;
|
||||
v[13] = ((v[28] - v[29]) * 0x2D413) >> 0x10;
|
||||
|
||||
v[10] = v[26] + v[27]; v[10] = v[10] + v[10];
|
||||
v[12] = v[28] + v[29]; v[12] = v[12] + v[12];
|
||||
v[14] = v[30] + v[31];
|
||||
v[3] = v[8] + v[10];
|
||||
v[14] = v[14] + v[14];
|
||||
v[13] = (v[13] - v[2]) + v[12];
|
||||
v[15] = (((v[30] - v[31]) * 0x5A827) >> 0x10) - (v[11] + v[2]);
|
||||
v[14] = -(v[14] + v[14]) + v[3];
|
||||
v[17] = v[13] - v[10];
|
||||
v[9] = v[9] + v[14];
|
||||
// ** Store v[9] -> (T6 + 0x40)
|
||||
*(s16 *)(mp3data+((t6+(short)0x40))) = (short)v[9];
|
||||
v[11] = v[11] - v[13];
|
||||
// ** Store v[17] -> (T0 + 0xFFC0)
|
||||
*(s16 *)(mp3data+((t0+(short)0xFFC0))) = (short)v[17];
|
||||
v[12] = v[8] - v[12];
|
||||
// ** Store v[11] -> (T0 + 0x40)
|
||||
*(s16 *)(mp3data+((t0+(short)0x40))) = (short)v[11];
|
||||
v[8] = -v[8];
|
||||
// ** Store v[15] -> (T1 + 0xFFC0)
|
||||
*(s16 *)(mp3data+((t1+(short)0xFFC0))) = (short)v[15];
|
||||
v[10] = -v[10] -v[12];
|
||||
// ** Store v[12] -> (T2 + 0x40)
|
||||
*(s16 *)(mp3data+((t2+(short)0x40))) = (short)v[12];
|
||||
// ** Store v[8] -> (T3 + 0xFFC0)
|
||||
*(s16 *)(mp3data+((t3+(short)0xFFC0))) = (short)v[8];
|
||||
// ** Store v[14] -> (T5 + 0x40)
|
||||
*(s16 *)(mp3data+((t5+(short)0x40))) = (short)v[14];
|
||||
// ** Store v[10] -> (T2 + 0xFFC0)
|
||||
*(s16 *)(mp3data+((t2+(short)0xFFC0))) = (short)v[10];
|
||||
// 0x14FC - Verified...
|
||||
|
||||
// Part 6 - 100% Accurate
|
||||
|
||||
v[0] = *(s16 *)(mp3data+inPtr+(0x00^S16)); v[31] = *(s16 *)(mp3data+inPtr+(0x3E^S16)); v[0] -= v[31];
|
||||
v[1] = *(s16 *)(mp3data+inPtr+(0x02^S16)); v[30] = *(s16 *)(mp3data+inPtr+(0x3C^S16)); v[1] -= v[30];
|
||||
v[2] = *(s16 *)(mp3data+inPtr+(0x06^S16)); v[28] = *(s16 *)(mp3data+inPtr+(0x38^S16)); v[2] -= v[28];
|
||||
v[3] = *(s16 *)(mp3data+inPtr+(0x04^S16)); v[29] = *(s16 *)(mp3data+inPtr+(0x3A^S16)); v[3] -= v[29];
|
||||
|
||||
v[4] = *(s16 *)(mp3data+inPtr+(0x0E^S16)); v[24] = *(s16 *)(mp3data+inPtr+(0x30^S16)); v[4] -= v[24];
|
||||
v[5] = *(s16 *)(mp3data+inPtr+(0x0C^S16)); v[25] = *(s16 *)(mp3data+inPtr+(0x32^S16)); v[5] -= v[25];
|
||||
v[6] = *(s16 *)(mp3data+inPtr+(0x08^S16)); v[27] = *(s16 *)(mp3data+inPtr+(0x36^S16)); v[6] -= v[27];
|
||||
v[7] = *(s16 *)(mp3data+inPtr+(0x0A^S16)); v[26] = *(s16 *)(mp3data+inPtr+(0x34^S16)); v[7] -= v[26];
|
||||
|
||||
v[8] = *(s16 *)(mp3data+inPtr+(0x1E^S16)); v[16] = *(s16 *)(mp3data+inPtr+(0x20^S16)); v[8] -= v[16];
|
||||
v[9] = *(s16 *)(mp3data+inPtr+(0x1C^S16)); v[17] = *(s16 *)(mp3data+inPtr+(0x22^S16)); v[9] -= v[17];
|
||||
v[10]= *(s16 *)(mp3data+inPtr+(0x18^S16)); v[19] = *(s16 *)(mp3data+inPtr+(0x26^S16)); v[10]-= v[19];
|
||||
v[11]= *(s16 *)(mp3data+inPtr+(0x1A^S16)); v[18] = *(s16 *)(mp3data+inPtr+(0x24^S16)); v[11]-= v[18];
|
||||
|
||||
v[12]= *(s16 *)(mp3data+inPtr+(0x10^S16)); v[23] = *(s16 *)(mp3data+inPtr+(0x2E^S16)); v[12]-= v[23];
|
||||
v[13]= *(s16 *)(mp3data+inPtr+(0x12^S16)); v[22] = *(s16 *)(mp3data+inPtr+(0x2C^S16)); v[13]-= v[22];
|
||||
v[14]= *(s16 *)(mp3data+inPtr+(0x16^S16)); v[20] = *(s16 *)(mp3data+inPtr+(0x28^S16)); v[14]-= v[20];
|
||||
v[15]= *(s16 *)(mp3data+inPtr+(0x14^S16)); v[21] = *(s16 *)(mp3data+inPtr+(0x2A^S16)); v[15]-= v[21];
|
||||
|
||||
//0, 1, 3, 2, 7, 6, 4, 5, 7, 6, 4, 5, 0, 1, 3, 2
|
||||
const u16 LUT6[16] = { 0xFFB2, 0xFD3A, 0xF10A, 0xF854,
|
||||
0xBDAE, 0xCDA0, 0xE76C, 0xDB94,
|
||||
0x1920, 0x4B20, 0xAC7C, 0x7C68,
|
||||
0xABEC, 0x9880, 0xDAE8, 0x839C };
|
||||
for (i = 0; i < 16; i++) {
|
||||
v[0+i] = (v[0+i] * LUT6[i]) >> 0x10;
|
||||
}
|
||||
v[0] = v[0] + v[0]; v[1] = v[1] + v[1];
|
||||
v[2] = v[2] + v[2]; v[3] = v[3] + v[3]; v[4] = v[4] + v[4];
|
||||
v[5] = v[5] + v[5]; v[6] = v[6] + v[6]; v[7] = v[7] + v[7];
|
||||
v[12] = v[12] + v[12]; v[13] = v[13] + v[13]; v[15] = v[15] + v[15];
|
||||
|
||||
MP3AB0 ();
|
||||
|
||||
// Part 7: - 100% Accurate + SSV - Unoptimized
|
||||
|
||||
v[0] = ( v[17] + v[16] ) >> 1;
|
||||
v[1] = ((v[17] * (int)((short)0xA57E * 2)) + (v[16] * 0xB504)) >> 0x10;
|
||||
v[2] = -v[18] -v[19];
|
||||
v[3] = ((v[18] - v[19]) * 0x16A09) >> 0x10;
|
||||
v[4] = v[20] + v[21] + v[0];
|
||||
v[5] = (((v[20] - v[21]) * 0x16A09) >> 0x10) + v[1];
|
||||
v[6] = (((v[22] + v[23]) << 1) + v[0]) - v[2];
|
||||
v[7] = (((v[22] - v[23]) * 0x2D413) >> 0x10) + v[0] + v[1] + v[3];
|
||||
// 0x16A8
|
||||
// Save v[0] -> (T3 + 0xFFE0)
|
||||
*(s16 *)(mp3data+((t3+(short)0xFFE0))) = (short)-v[0];
|
||||
v[8] = v[24] + v[25];
|
||||
v[9] = ((v[24] - v[25]) * 0x16A09) >> 0x10;
|
||||
v[10] = ((v[26] + v[27]) << 1) + v[8];
|
||||
v[11] = (((v[26] - v[27]) * 0x2D413) >> 0x10) + v[8] + v[9];
|
||||
v[12] = v[4] - ((v[28] + v[29]) << 1);
|
||||
// ** Store v12 -> (T2 + 0x20)
|
||||
*(s16 *)(mp3data+((t2+(short)0x20))) = (short)v[12];
|
||||
v[13] = (((v[28] - v[29]) * 0x2D413) >> 0x10) - v[12] - v[5];
|
||||
v[14] = v[30] + v[31];
|
||||
v[14] = v[14] + v[14];
|
||||
v[14] = v[14] + v[14];
|
||||
v[14] = v[6] - v[14];
|
||||
v[15] = (((v[30] - v[31]) * 0x5A827) >> 0x10) - v[7];
|
||||
// Store v14 -> (T5 + 0x20)
|
||||
*(s16 *)(mp3data+((t5+(short)0x20))) = (short)v[14];
|
||||
v[14] = v[14] + v[1];
|
||||
// Store v[14] -> (T6 + 0x20)
|
||||
*(s16 *)(mp3data+((t6+(short)0x20))) = (short)v[14];
|
||||
// Store v[15] -> (T1 + 0xFFE0)
|
||||
*(s16 *)(mp3data+((t1+(short)0xFFE0))) = (short)v[15];
|
||||
v[9] = v[9] + v[10];
|
||||
v[1] = v[1] + v[6];
|
||||
v[6] = v[10] - v[6];
|
||||
v[1] = v[9] - v[1];
|
||||
// Store v[6] -> (T5 + 0x60)
|
||||
*(s16 *)(mp3data+((t5+(short)0x60))) = (short)v[6];
|
||||
v[10] = v[10] + v[2];
|
||||
v[10] = v[4] - v[10];
|
||||
// Store v[10] -> (T2 + 0xFFA0)
|
||||
*(s16 *)(mp3data+((t2+(short)0xFFA0))) = (short)v[10];
|
||||
v[12] = v[2] - v[12];
|
||||
// Store v[12] -> (T2 + 0xFFE0)
|
||||
*(s16 *)(mp3data+((t2+(short)0xFFE0))) = (short)v[12];
|
||||
v[5] = v[4] + v[5];
|
||||
v[4] = v[8] - v[4];
|
||||
// Store v[4] -> (T2 + 0x60)
|
||||
*(s16 *)(mp3data+((t2+(short)0x60))) = (short)v[4];
|
||||
v[0] = v[0] - v[8];
|
||||
// Store v[0] -> (T3 + 0xFFA0)
|
||||
*(s16 *)(mp3data+((t3+(short)0xFFA0))) = (short)v[0];
|
||||
v[7] = v[7] - v[11];
|
||||
// Store v[7] -> (T1 + 0xFFA0)
|
||||
*(s16 *)(mp3data+((t1+(short)0xFFA0))) = (short)v[7];
|
||||
v[11] = v[11] - v[3];
|
||||
// Store v[1] -> (T6 + 0x60)
|
||||
*(s16 *)(mp3data+((t6+(short)0x60))) = (short)v[1];
|
||||
v[11] = v[11] - v[5];
|
||||
// Store v[11] -> (T0 + 0x60)
|
||||
*(s16 *)(mp3data+((t0+(short)0x60))) = (short)v[11];
|
||||
v[3] = v[3] - v[13];
|
||||
// Store v[3] -> (T0 + 0x20)
|
||||
*(s16 *)(mp3data+((t0+(short)0x20))) = (short)v[3];
|
||||
v[13] = v[13] + v[2];
|
||||
// Store v[13] -> (T0 + 0xFFE0)
|
||||
*(s16 *)(mp3data+((t0+(short)0xFFE0))) = (short)v[13];
|
||||
//v[2] = ;
|
||||
v[2] = (v[5] - v[2]) - v[9];
|
||||
// Store v[2] -> (T0 + 0xFFA0)
|
||||
*(s16 *)(mp3data+((t0+(short)0xFFA0))) = (short)v[2];
|
||||
// 0x7A8 - Verified...
|
||||
|
||||
// Step 8 - Dewindowing
|
||||
|
||||
//u64 *DW = (u64 *)&DeWindowLUT[0x10-(t4>>1)];
|
||||
u32 offset = 0x10-(t4>>1);
|
||||
|
||||
u32 addptr = t6 & 0xFFE0;
|
||||
offset = 0x10-(t4>>1);
|
||||
|
||||
s32 v2=0, v4=0, v6=0, v8=0;
|
||||
//s32 z2=0, z4=0, z6=0, z8=0;
|
||||
|
||||
offset = 0x10-(t4>>1);// + x*0x40;
|
||||
int x;
|
||||
for (x = 0; x < 8; x++) {
|
||||
v2 = v4 = v6 = v8 = 0;
|
||||
|
||||
//addptr = t1;
|
||||
|
||||
for (i = 7; i >= 0; i--) {
|
||||
v2 += ((int)*(s16 *)(mp3data+(addptr)+0x00) * (short)DeWindowLUT[offset+0x00] + 0x4000) >> 0xF;
|
||||
v4 += ((int)*(s16 *)(mp3data+(addptr)+0x10) * (short)DeWindowLUT[offset+0x08] + 0x4000) >> 0xF;
|
||||
v6 += ((int)*(s16 *)(mp3data+(addptr)+0x20) * (short)DeWindowLUT[offset+0x20] + 0x4000) >> 0xF;
|
||||
v8 += ((int)*(s16 *)(mp3data+(addptr)+0x30) * (short)DeWindowLUT[offset+0x28] + 0x4000) >> 0xF;
|
||||
addptr+=2; offset++;
|
||||
}
|
||||
s32 v0 = v2 + v4;
|
||||
s32 v18 = v6 + v8;
|
||||
//Clamp(v0);
|
||||
//Clamp(v18);
|
||||
// clamp???
|
||||
*(s16 *)(mp3data+(outPtr^S16)) = v0;
|
||||
*(s16 *)(mp3data+((outPtr+2)^S16)) = v18;
|
||||
outPtr+=4;
|
||||
addptr += 0x30;
|
||||
offset += 0x38;
|
||||
}
|
||||
|
||||
offset = 0x10-(t4>>1) + 8*0x40;
|
||||
v2 = v4 = 0;
|
||||
for (i = 0; i < 4; i++) {
|
||||
v2 += ((int)*(s16 *)(mp3data+(addptr)+0x00) * (short)DeWindowLUT[offset+0x00] + 0x4000) >> 0xF;
|
||||
v2 += ((int)*(s16 *)(mp3data+(addptr)+0x10) * (short)DeWindowLUT[offset+0x08] + 0x4000) >> 0xF;
|
||||
addptr+=2; offset++;
|
||||
v4 += ((int)*(s16 *)(mp3data+(addptr)+0x00) * (short)DeWindowLUT[offset+0x00] + 0x4000) >> 0xF;
|
||||
v4 += ((int)*(s16 *)(mp3data+(addptr)+0x10) * (short)DeWindowLUT[offset+0x08] + 0x4000) >> 0xF;
|
||||
addptr+=2; offset++;
|
||||
}
|
||||
s32 mult6 = *(s32 *)(mp3data+0xCE8);
|
||||
s32 mult4 = *(s32 *)(mp3data+0xCEC);
|
||||
if (t4 & 0x2) {
|
||||
v2 = (v2 * *(u32 *)(mp3data+0xCE8)) >> 0x10;
|
||||
*(s16 *)(mp3data+(outPtr^S16)) = v2;
|
||||
} else {
|
||||
v4 = (v4 * *(u32 *)(mp3data+0xCE8)) >> 0x10;
|
||||
*(s16 *)(mp3data+(outPtr^S16)) = v4;
|
||||
mult4 = *(u32 *)(mp3data+0xCE8);
|
||||
}
|
||||
addptr -= 0x50;
|
||||
|
||||
for (x = 0; x < 8; x++) {
|
||||
v2 = v4 = v6 = v8 = 0;
|
||||
|
||||
offset = (0x22F-(t4>>1) + x*0x40);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
v2 += ((int)*(s16 *)(mp3data+(addptr )+0x20) * (short)DeWindowLUT[offset+0x00] + 0x4000) >> 0xF;
|
||||
v2 -= ((int)*(s16 *)(mp3data+((addptr+2))+0x20) * (short)DeWindowLUT[offset+0x01] + 0x4000) >> 0xF;
|
||||
v4 += ((int)*(s16 *)(mp3data+(addptr )+0x30) * (short)DeWindowLUT[offset+0x08] + 0x4000) >> 0xF;
|
||||
v4 -= ((int)*(s16 *)(mp3data+((addptr+2))+0x30) * (short)DeWindowLUT[offset+0x09] + 0x4000) >> 0xF;
|
||||
v6 += ((int)*(s16 *)(mp3data+(addptr )+0x00) * (short)DeWindowLUT[offset+0x20] + 0x4000) >> 0xF;
|
||||
v6 -= ((int)*(s16 *)(mp3data+((addptr+2))+0x00) * (short)DeWindowLUT[offset+0x21] + 0x4000) >> 0xF;
|
||||
v8 += ((int)*(s16 *)(mp3data+(addptr )+0x10) * (short)DeWindowLUT[offset+0x28] + 0x4000) >> 0xF;
|
||||
v8 -= ((int)*(s16 *)(mp3data+((addptr+2))+0x10) * (short)DeWindowLUT[offset+0x29] + 0x4000) >> 0xF;
|
||||
addptr+=4; offset+=2;
|
||||
}
|
||||
s32 v0 = v2 + v4;
|
||||
s32 v18 = v6 + v8;
|
||||
//Clamp(v0);
|
||||
//Clamp(v18);
|
||||
// clamp???
|
||||
*(s16 *)(mp3data+((outPtr+2)^S16)) = v0;
|
||||
*(s16 *)(mp3data+((outPtr+4)^S16)) = v18;
|
||||
outPtr+=4;
|
||||
addptr -= 0x50;
|
||||
}
|
||||
|
||||
int tmp = outPtr;
|
||||
s32 hi0 = mult6;
|
||||
s32 hi1 = mult4;
|
||||
s32 v;
|
||||
|
||||
hi0 = (int)hi0 >> 0x10;
|
||||
hi1 = (int)hi1 >> 0x10;
|
||||
for (i = 0; i < 8; i++) {
|
||||
// v0
|
||||
v = (*(s16 *)(mp3data+((tmp-0x40)^S16)) * hi0);
|
||||
if (v > 32767) v = 32767; else if (v < -32767) v = -32767;
|
||||
*(s16 *)((u8 *)mp3data+((tmp-0x40)^S16)) = (s16)v;
|
||||
// v17
|
||||
v = (*(s16 *)(mp3data+((tmp-0x30)^S16)) * hi0);
|
||||
if (v > 32767) v = 32767; else if (v < -32767) v = -32767;
|
||||
*(s16 *)((u8 *)mp3data+((tmp-0x30)^S16)) = v;
|
||||
// v2
|
||||
v = (*(s16 *)(mp3data+((tmp-0x1E)^S16)) * hi1);
|
||||
if (v > 32767) v = 32767; else if (v < -32767) v = -32767;
|
||||
*(s16 *)((u8 *)mp3data+((tmp-0x1E)^S16)) = v;
|
||||
// v4
|
||||
v = (*(s16 *)(mp3data+((tmp-0xE)^S16)) * hi1);
|
||||
if (v > 32767) v = 32767; else if (v < -32767) v = -32767;
|
||||
*(s16 *)((u8 *)mp3data+((tmp-0xE)^S16)) = v;
|
||||
tmp += 2;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - ucodes.h *
|
||||
* Mupen64Plus homepage: https://mupen64plus.org/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* *
|
||||
* 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. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef UCODES_H
|
||||
#define UCODES_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct hle_t;
|
||||
|
||||
|
||||
/* cic_x105 ucode */
|
||||
void cicx105_ucode(struct hle_t* hle);
|
||||
|
||||
|
||||
/* audio list ucodes - audio */
|
||||
enum { N_SEGMENTS = 16 };
|
||||
struct alist_audio_t {
|
||||
/* segments */
|
||||
uint32_t segments[N_SEGMENTS];
|
||||
|
||||
/* main buffers */
|
||||
uint16_t in;
|
||||
uint16_t out;
|
||||
uint16_t count;
|
||||
|
||||
/* auxiliary buffers */
|
||||
uint16_t dry_right;
|
||||
uint16_t wet_left;
|
||||
uint16_t wet_right;
|
||||
|
||||
/* gains */
|
||||
int16_t dry;
|
||||
int16_t wet;
|
||||
|
||||
/* envelopes (0:left, 1:right) */
|
||||
int16_t vol[2];
|
||||
int16_t target[2];
|
||||
int32_t rate[2];
|
||||
|
||||
/* ADPCM loop point address */
|
||||
uint32_t loop;
|
||||
|
||||
/* storage for ADPCM table and polef coefficients */
|
||||
int16_t table[16 * 8];
|
||||
};
|
||||
|
||||
void alist_process_audio (struct hle_t* hle);
|
||||
void alist_process_audio_ge(struct hle_t* hle);
|
||||
void alist_process_audio_bc(struct hle_t* hle);
|
||||
|
||||
|
||||
/* audio list ucodes - naudio */
|
||||
struct alist_naudio_t {
|
||||
/* gains */
|
||||
int16_t dry;
|
||||
int16_t wet;
|
||||
|
||||
/* envelopes (0:left, 1:right) */
|
||||
int16_t vol[2];
|
||||
int16_t target[2];
|
||||
int32_t rate[2];
|
||||
|
||||
/* ADPCM loop point address */
|
||||
uint32_t loop;
|
||||
|
||||
/* storage for ADPCM table and polef coefficients */
|
||||
int16_t table[16 * 8];
|
||||
};
|
||||
|
||||
void alist_process_naudio (struct hle_t* hle);
|
||||
void alist_process_naudio_bk (struct hle_t* hle);
|
||||
void alist_process_naudio_dk (struct hle_t* hle);
|
||||
void alist_process_naudio_mp3 (struct hle_t* hle);
|
||||
void alist_process_naudio_cbfd(struct hle_t* hle);
|
||||
|
||||
|
||||
/* audio list ucodes - nead */
|
||||
struct alist_nead_t {
|
||||
/* main buffers */
|
||||
uint16_t in;
|
||||
uint16_t out;
|
||||
uint16_t count;
|
||||
|
||||
/* envmixer ramps */
|
||||
uint16_t env_values[3];
|
||||
uint16_t env_steps[3];
|
||||
|
||||
/* ADPCM loop point address */
|
||||
uint32_t loop;
|
||||
|
||||
/* storage for ADPCM table and polef coefficients */
|
||||
int16_t table[16 * 8];
|
||||
|
||||
/* filter audio command state */
|
||||
uint16_t filter_count;
|
||||
uint32_t filter_lut_address[2];
|
||||
};
|
||||
|
||||
void alist_process_nead_mk (struct hle_t* hle);
|
||||
void alist_process_nead_sfj (struct hle_t* hle);
|
||||
void alist_process_nead_sf (struct hle_t* hle);
|
||||
void alist_process_nead_fz (struct hle_t* hle);
|
||||
void alist_process_nead_wrjb(struct hle_t* hle);
|
||||
void alist_process_nead_ys (struct hle_t* hle);
|
||||
void alist_process_nead_1080(struct hle_t* hle);
|
||||
void alist_process_nead_oot (struct hle_t* hle);
|
||||
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);
|
||||
|
||||
|
||||
/* musyx ucodes */
|
||||
void musyx_v1_task(struct hle_t* hle);
|
||||
void musyx_v2_task(struct hle_t* hle);
|
||||
|
||||
|
||||
/* jpeg ucodes */
|
||||
void jpeg_decode_PS0(struct hle_t* hle);
|
||||
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);
|
||||
|
||||
#endif
|
||||
|
Binary file not shown.
Loading…
Reference in New Issue