From 5b456915f3539d33b8424f42870924bad9189820 Mon Sep 17 00:00:00 2001 From: Chris Moeller Date: Tue, 4 Mar 2014 21:39:37 -0800 Subject: [PATCH] Added HLE audio to LazyUSF, disabled because it's incomplete --- .../lazyusf/lazyusf.xcodeproj/project.pbxproj | 96 ++ Frameworks/lazyusf/lazyusf/rsp/rsp.c | 16 + Frameworks/lazyusf/lazyusf/rsp/rsp.h | 45 + Frameworks/lazyusf/lazyusf/rsp_hle/alist.c | 868 ++++++++++++++++ Frameworks/lazyusf/lazyusf/rsp_hle/alist.h | 46 + .../lazyusf/lazyusf/rsp_hle/alist_audio.c | 291 ++++++ .../lazyusf/lazyusf/rsp_hle/alist_internal.h | 145 +++ .../lazyusf/lazyusf/rsp_hle/alist_naudio.c | 302 ++++++ .../lazyusf/lazyusf/rsp_hle/alist_nead.c | 524 ++++++++++ .../lazyusf/lazyusf/rsp_hle/arithmetics.h | 36 + .../lazyusf/lazyusf/rsp_hle/audio_hle.c | 96 ++ .../lazyusf/lazyusf/rsp_hle/audio_hle.h | 43 + Frameworks/lazyusf/lazyusf/rsp_hle/cicx105.c | 59 ++ Frameworks/lazyusf/lazyusf/rsp_hle/cicx105.h | 28 + Frameworks/lazyusf/lazyusf/rsp_hle/jpeg.c | 594 +++++++++++ Frameworks/lazyusf/lazyusf/rsp_hle/jpeg.h | 30 + Frameworks/lazyusf/lazyusf/rsp_hle/main_hle.c | 393 +++++++ Frameworks/lazyusf/lazyusf/rsp_hle/main_hle.h | 28 + .../lazyusf/lazyusf/rsp_hle/memory_hle.c | 127 +++ .../lazyusf/lazyusf/rsp_hle/memory_hle.h | 118 +++ Frameworks/lazyusf/lazyusf/rsp_hle/mp3.c | 702 +++++++++++++ Frameworks/lazyusf/lazyusf/rsp_hle/musyx.c | 972 ++++++++++++++++++ Frameworks/lazyusf/lazyusf/rsp_hle/musyx.h | 28 + .../lazyusf/lazyusf/rsp_hle/plugin_hle.c | 60 ++ .../lazyusf/lazyusf/rsp_hle/plugin_hle.h | 32 + Frameworks/lazyusf/lazyusf/usf.c | 7 + Frameworks/lazyusf/lazyusf/usf.h | 4 + Frameworks/lazyusf/lazyusf/usf_internal.h | 102 ++ 28 files changed, 5792 insertions(+) create mode 100644 Frameworks/lazyusf/lazyusf/rsp_hle/alist.c create mode 100644 Frameworks/lazyusf/lazyusf/rsp_hle/alist.h create mode 100644 Frameworks/lazyusf/lazyusf/rsp_hle/alist_audio.c create mode 100644 Frameworks/lazyusf/lazyusf/rsp_hle/alist_internal.h create mode 100644 Frameworks/lazyusf/lazyusf/rsp_hle/alist_naudio.c create mode 100644 Frameworks/lazyusf/lazyusf/rsp_hle/alist_nead.c create mode 100644 Frameworks/lazyusf/lazyusf/rsp_hle/arithmetics.h create mode 100644 Frameworks/lazyusf/lazyusf/rsp_hle/audio_hle.c create mode 100644 Frameworks/lazyusf/lazyusf/rsp_hle/audio_hle.h create mode 100644 Frameworks/lazyusf/lazyusf/rsp_hle/cicx105.c create mode 100644 Frameworks/lazyusf/lazyusf/rsp_hle/cicx105.h create mode 100644 Frameworks/lazyusf/lazyusf/rsp_hle/jpeg.c create mode 100644 Frameworks/lazyusf/lazyusf/rsp_hle/jpeg.h create mode 100644 Frameworks/lazyusf/lazyusf/rsp_hle/main_hle.c create mode 100644 Frameworks/lazyusf/lazyusf/rsp_hle/main_hle.h create mode 100644 Frameworks/lazyusf/lazyusf/rsp_hle/memory_hle.c create mode 100644 Frameworks/lazyusf/lazyusf/rsp_hle/memory_hle.h create mode 100644 Frameworks/lazyusf/lazyusf/rsp_hle/mp3.c create mode 100644 Frameworks/lazyusf/lazyusf/rsp_hle/musyx.c create mode 100644 Frameworks/lazyusf/lazyusf/rsp_hle/musyx.h create mode 100644 Frameworks/lazyusf/lazyusf/rsp_hle/plugin_hle.c create mode 100644 Frameworks/lazyusf/lazyusf/rsp_hle/plugin_hle.h diff --git a/Frameworks/lazyusf/lazyusf.xcodeproj/project.pbxproj b/Frameworks/lazyusf/lazyusf.xcodeproj/project.pbxproj index a9ffea242..ab86287ad 100644 --- a/Frameworks/lazyusf/lazyusf.xcodeproj/project.pbxproj +++ b/Frameworks/lazyusf/lazyusf.xcodeproj/project.pbxproj @@ -7,6 +7,28 @@ objects = { /* Begin PBXBuildFile section */ + 8378416A18C6E56B002C4FE5 /* alist.c in Sources */ = {isa = PBXBuildFile; fileRef = 8378415418C6E56B002C4FE5 /* alist.c */; }; + 8378416B18C6E56B002C4FE5 /* alist.h in Headers */ = {isa = PBXBuildFile; fileRef = 8378415518C6E56B002C4FE5 /* alist.h */; }; + 8378416C18C6E56B002C4FE5 /* alist_audio.c in Sources */ = {isa = PBXBuildFile; fileRef = 8378415618C6E56B002C4FE5 /* alist_audio.c */; }; + 8378416D18C6E56B002C4FE5 /* alist_internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 8378415718C6E56B002C4FE5 /* alist_internal.h */; }; + 8378416E18C6E56B002C4FE5 /* alist_naudio.c in Sources */ = {isa = PBXBuildFile; fileRef = 8378415818C6E56B002C4FE5 /* alist_naudio.c */; }; + 8378416F18C6E56B002C4FE5 /* alist_nead.c in Sources */ = {isa = PBXBuildFile; fileRef = 8378415918C6E56B002C4FE5 /* alist_nead.c */; }; + 8378417018C6E56B002C4FE5 /* arithmetics.h in Headers */ = {isa = PBXBuildFile; fileRef = 8378415A18C6E56B002C4FE5 /* arithmetics.h */; }; + 8378417118C6E56B002C4FE5 /* audio_hle.c in Sources */ = {isa = PBXBuildFile; fileRef = 8378415B18C6E56B002C4FE5 /* audio_hle.c */; }; + 8378417218C6E56B002C4FE5 /* audio_hle.h in Headers */ = {isa = PBXBuildFile; fileRef = 8378415C18C6E56B002C4FE5 /* audio_hle.h */; }; + 8378417318C6E56B002C4FE5 /* cicx105.c in Sources */ = {isa = PBXBuildFile; fileRef = 8378415D18C6E56B002C4FE5 /* cicx105.c */; }; + 8378417418C6E56B002C4FE5 /* cicx105.h in Headers */ = {isa = PBXBuildFile; fileRef = 8378415E18C6E56B002C4FE5 /* cicx105.h */; }; + 8378417518C6E56B002C4FE5 /* jpeg.c in Sources */ = {isa = PBXBuildFile; fileRef = 8378415F18C6E56B002C4FE5 /* jpeg.c */; }; + 8378417618C6E56B002C4FE5 /* jpeg.h in Headers */ = {isa = PBXBuildFile; fileRef = 8378416018C6E56B002C4FE5 /* jpeg.h */; }; + 8378417718C6E56B002C4FE5 /* main_hle.c in Sources */ = {isa = PBXBuildFile; fileRef = 8378416118C6E56B002C4FE5 /* main_hle.c */; }; + 8378417818C6E56B002C4FE5 /* main_hle.h in Headers */ = {isa = PBXBuildFile; fileRef = 8378416218C6E56B002C4FE5 /* main_hle.h */; }; + 8378417918C6E56B002C4FE5 /* memory_hle.c in Sources */ = {isa = PBXBuildFile; fileRef = 8378416318C6E56B002C4FE5 /* memory_hle.c */; }; + 8378417A18C6E56B002C4FE5 /* memory_hle.h in Headers */ = {isa = PBXBuildFile; fileRef = 8378416418C6E56B002C4FE5 /* memory_hle.h */; }; + 8378417B18C6E56B002C4FE5 /* mp3.c in Sources */ = {isa = PBXBuildFile; fileRef = 8378416518C6E56B002C4FE5 /* mp3.c */; }; + 8378417C18C6E56B002C4FE5 /* musyx.c in Sources */ = {isa = PBXBuildFile; fileRef = 8378416618C6E56B002C4FE5 /* musyx.c */; }; + 8378417D18C6E56B002C4FE5 /* musyx.h in Headers */ = {isa = PBXBuildFile; fileRef = 8378416718C6E56B002C4FE5 /* musyx.h */; }; + 8378417E18C6E56B002C4FE5 /* plugin_hle.c in Sources */ = {isa = PBXBuildFile; fileRef = 8378416818C6E56B002C4FE5 /* plugin_hle.c */; }; + 8378417F18C6E56B002C4FE5 /* plugin_hle.h in Headers */ = {isa = PBXBuildFile; fileRef = 8378416918C6E56B002C4FE5 /* plugin_hle.h */; }; 83C8B6AB18AF58080071B040 /* audio.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C8B65918AF58080071B040 /* audio.c */; }; 83C8B6AC18AF58080071B040 /* audio.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B65A18AF58080071B040 /* audio.h */; }; 83C8B6AD18AF58080071B040 /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8B65B18AF58080071B040 /* config.h */; }; @@ -90,6 +112,28 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 8378415418C6E56B002C4FE5 /* alist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = alist.c; sourceTree = ""; }; + 8378415518C6E56B002C4FE5 /* alist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = alist.h; sourceTree = ""; }; + 8378415618C6E56B002C4FE5 /* alist_audio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = alist_audio.c; sourceTree = ""; }; + 8378415718C6E56B002C4FE5 /* alist_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = alist_internal.h; sourceTree = ""; }; + 8378415818C6E56B002C4FE5 /* alist_naudio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = alist_naudio.c; sourceTree = ""; }; + 8378415918C6E56B002C4FE5 /* alist_nead.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = alist_nead.c; sourceTree = ""; }; + 8378415A18C6E56B002C4FE5 /* arithmetics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = arithmetics.h; sourceTree = ""; }; + 8378415B18C6E56B002C4FE5 /* audio_hle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = audio_hle.c; sourceTree = ""; }; + 8378415C18C6E56B002C4FE5 /* audio_hle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = audio_hle.h; sourceTree = ""; }; + 8378415D18C6E56B002C4FE5 /* cicx105.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cicx105.c; sourceTree = ""; }; + 8378415E18C6E56B002C4FE5 /* cicx105.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cicx105.h; sourceTree = ""; }; + 8378415F18C6E56B002C4FE5 /* jpeg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = jpeg.c; sourceTree = ""; }; + 8378416018C6E56B002C4FE5 /* jpeg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jpeg.h; sourceTree = ""; }; + 8378416118C6E56B002C4FE5 /* main_hle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = main_hle.c; sourceTree = ""; }; + 8378416218C6E56B002C4FE5 /* main_hle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = main_hle.h; sourceTree = ""; }; + 8378416318C6E56B002C4FE5 /* memory_hle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = memory_hle.c; sourceTree = ""; }; + 8378416418C6E56B002C4FE5 /* memory_hle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memory_hle.h; sourceTree = ""; }; + 8378416518C6E56B002C4FE5 /* mp3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mp3.c; sourceTree = ""; }; + 8378416618C6E56B002C4FE5 /* musyx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = musyx.c; sourceTree = ""; }; + 8378416718C6E56B002C4FE5 /* musyx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = musyx.h; sourceTree = ""; }; + 8378416818C6E56B002C4FE5 /* plugin_hle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = plugin_hle.c; sourceTree = ""; }; + 8378416918C6E56B002C4FE5 /* plugin_hle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = plugin_hle.h; sourceTree = ""; }; 83C8B62218AF57770071B040 /* lazyusf.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = lazyusf.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 83C8B65918AF58080071B040 /* audio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = audio.c; sourceTree = ""; }; 83C8B65A18AF58080071B040 /* audio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = audio.h; sourceTree = ""; }; @@ -185,6 +229,35 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 8378415318C6E56B002C4FE5 /* rsp_hle */ = { + isa = PBXGroup; + children = ( + 8378415418C6E56B002C4FE5 /* alist.c */, + 8378415518C6E56B002C4FE5 /* alist.h */, + 8378415618C6E56B002C4FE5 /* alist_audio.c */, + 8378415718C6E56B002C4FE5 /* alist_internal.h */, + 8378415818C6E56B002C4FE5 /* alist_naudio.c */, + 8378415918C6E56B002C4FE5 /* alist_nead.c */, + 8378415A18C6E56B002C4FE5 /* arithmetics.h */, + 8378415B18C6E56B002C4FE5 /* audio_hle.c */, + 8378415C18C6E56B002C4FE5 /* audio_hle.h */, + 8378415D18C6E56B002C4FE5 /* cicx105.c */, + 8378415E18C6E56B002C4FE5 /* cicx105.h */, + 8378415F18C6E56B002C4FE5 /* jpeg.c */, + 8378416018C6E56B002C4FE5 /* jpeg.h */, + 8378416118C6E56B002C4FE5 /* main_hle.c */, + 8378416218C6E56B002C4FE5 /* main_hle.h */, + 8378416318C6E56B002C4FE5 /* memory_hle.c */, + 8378416418C6E56B002C4FE5 /* memory_hle.h */, + 8378416518C6E56B002C4FE5 /* mp3.c */, + 8378416618C6E56B002C4FE5 /* musyx.c */, + 8378416718C6E56B002C4FE5 /* musyx.h */, + 8378416818C6E56B002C4FE5 /* plugin_hle.c */, + 8378416918C6E56B002C4FE5 /* plugin_hle.h */, + ); + path = rsp_hle; + sourceTree = ""; + }; 83C8B61818AF57770071B040 = { isa = PBXGroup; children = ( @@ -220,6 +293,7 @@ 83C8B62B18AF57770071B040 /* lazyusf */ = { isa = PBXGroup; children = ( + 8378415318C6E56B002C4FE5 /* rsp_hle */, 83C8B6FD18AF59E70071B040 /* lazyusf-Info.plist */, 83C8B65918AF58080071B040 /* audio.c */, 83C8B65A18AF58080071B040 /* audio.h */, @@ -338,11 +412,15 @@ files = ( 83C8B6FA18AF58090071B040 /* usf.h in Headers */, 83C8B6AC18AF58080071B040 /* audio.h in Headers */, + 8378416D18C6E56B002C4FE5 /* alist_internal.h in Headers */, + 8378417618C6E56B002C4FE5 /* jpeg.h in Headers */, 83C8B6B118AF58080071B040 /* dma.h in Headers */, 83C8B6AD18AF58080071B040 /* config.h in Headers */, + 8378417F18C6E56B002C4FE5 /* plugin_hle.h in Headers */, 83C8B6B518AF58080071B040 /* interpreter_cpu.h in Headers */, 83C8B6B918AF58080071B040 /* main.h in Headers */, 83C8B6F418AF58090071B040 /* rsp.h in Headers */, + 8378417018C6E56B002C4FE5 /* arithmetics.h in Headers */, 83C8B6C018AF58080071B040 /* registers.h in Headers */, 83C8B6BE18AF58080071B040 /* pif.h in Headers */, 83C8B6F618AF58090071B040 /* tlb.h in Headers */, @@ -352,13 +430,16 @@ 83C8B6B718AF58080071B040 /* interpreter_ops.h in Headers */, 83C8B6B318AF58080071B040 /* exception.h in Headers */, 83C8B6AF18AF58080071B040 /* cpu.h in Headers */, + 8378417818C6E56B002C4FE5 /* main_hle.h in Headers */, 83C8B6F118AF58090071B040 /* vsubc.h in Headers */, 83C8B6F018AF58090071B040 /* vsub.h in Headers */, + 8378417218C6E56B002C4FE5 /* audio_hle.h in Headers */, 83C8B6E018AF58080071B040 /* vmudn.h in Headers */, 83C8B6EF18AF58090071B040 /* vsaw.h in Headers */, 83C8B6C918AF58080071B040 /* shuffle.h in Headers */, 83C8B6DD18AF58080071B040 /* vmudh.h in Headers */, 83C8B6E118AF58080071B040 /* vmulf.h in Headers */, + 8378417A18C6E56B002C4FE5 /* memory_hle.h in Headers */, 83C8B6CE18AF58080071B040 /* vch.h in Headers */, 83C8B6CB18AF58080071B040 /* vadd.h in Headers */, 83C8B6D618AF58080071B040 /* vmacu.h in Headers */, @@ -369,6 +450,7 @@ 83C8B6D218AF58080071B040 /* vge.h in Headers */, 83C8B6C518AF58080071B040 /* su.h in Headers */, 83C8B6C218AF58080071B040 /* execute.h in Headers */, + 8378417418C6E56B002C4FE5 /* cicx105.h in Headers */, 83C8B6E518AF58080071B040 /* vnop.h in Headers */, 83C8B6E418AF58080071B040 /* vne.h in Headers */, 83C8B6D418AF58080071B040 /* vmacf.h in Headers */, @@ -378,7 +460,9 @@ 83C8B6F318AF58090071B040 /* vxor.h in Headers */, 83C8B6EC18AF58090071B040 /* vrsq.h in Headers */, 83C8B6D018AF58080071B040 /* vcr.h in Headers */, + 8378416B18C6E56B002C4FE5 /* alist.h in Headers */, 83C8B6EA18AF58090071B040 /* vrcph.h in Headers */, + 8378417D18C6E56B002C4FE5 /* musyx.h in Headers */, 83C8B6F818AF58090071B040 /* usf_internal.h in Headers */, 83C8B6EE18AF58090071B040 /* vrsql.h in Headers */, 83C8B6D118AF58080071B040 /* veq.h in Headers */, @@ -472,14 +556,26 @@ 83C8B6C318AF58080071B040 /* rsp.c in Sources */, 83C8B6BD18AF58080071B040 /* pif.c in Sources */, 83C8B6B418AF58080071B040 /* interpreter_cpu.c in Sources */, + 8378417118C6E56B002C4FE5 /* audio_hle.c in Sources */, + 8378417518C6E56B002C4FE5 /* jpeg.c in Sources */, + 8378417C18C6E56B002C4FE5 /* musyx.c in Sources */, + 8378417B18C6E56B002C4FE5 /* mp3.c in Sources */, + 8378416F18C6E56B002C4FE5 /* alist_nead.c in Sources */, 83C8B6B618AF58080071B040 /* interpreter_ops.c in Sources */, + 8378416C18C6E56B002C4FE5 /* alist_audio.c in Sources */, 83C8B6BA18AF58080071B040 /* memory.c in Sources */, 83C8B6B018AF58080071B040 /* dma.c in Sources */, + 8378417318C6E56B002C4FE5 /* cicx105.c in Sources */, + 8378416A18C6E56B002C4FE5 /* alist.c in Sources */, 83C8B6AE18AF58080071B040 /* cpu.c in Sources */, 83C8B6AB18AF58080071B040 /* audio.c in Sources */, + 8378416E18C6E56B002C4FE5 /* alist_naudio.c in Sources */, + 8378417718C6E56B002C4FE5 /* main_hle.c in Sources */, 83C8B6B218AF58080071B040 /* exception.c in Sources */, + 8378417918C6E56B002C4FE5 /* memory_hle.c in Sources */, 83C8B6BF18AF58080071B040 /* registers.c in Sources */, 83C8B6F918AF58090071B040 /* usf.c in Sources */, + 8378417E18C6E56B002C4FE5 /* plugin_hle.c in Sources */, 83C8B6B818AF58080071B040 /* main.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Frameworks/lazyusf/lazyusf/rsp/rsp.c b/Frameworks/lazyusf/lazyusf/rsp/rsp.c index 3aa510c66..c2a249bdb 100644 --- a/Frameworks/lazyusf/lazyusf/rsp/rsp.c +++ b/Frameworks/lazyusf/lazyusf/rsp/rsp.c @@ -33,6 +33,8 @@ #include "rsp.h" +#include "../rsp_hle/main_hle.h" + void real_run_rsp(usf_state_t * state, uint32_t cycles) { (void)cycles; @@ -42,6 +44,20 @@ void real_run_rsp(usf_state_t * state, uint32_t cycles) message(state, "SP_STATUS_HALT", 3); return; } + switch (*(unsigned int *)(state->DMEM + 0xFC0)) + { /* Simulation barrier to redirect processing externally. */ + case 0x00000002: /* OSTask.type == M_AUDTASK */ + if (state->enable_hle_audio == 0) + break; + hle_execute(state); + SP_STATUS_REG |= 0x00000203; + if (SP_STATUS_REG & 0x00000040) /* SP_STATUS_INTR_BREAK */ + { + MI_INTR_REG |= 0x00000001; /* VR4300 SP interrupt */ + CheckInterrupts(state); + } + return; + } run_task(state); return; } diff --git a/Frameworks/lazyusf/lazyusf/rsp/rsp.h b/Frameworks/lazyusf/lazyusf/rsp/rsp.h index e408fb3e2..2242642f2 100644 --- a/Frameworks/lazyusf/lazyusf/rsp/rsp.h +++ b/Frameworks/lazyusf/lazyusf/rsp/rsp.h @@ -60,6 +60,10 @@ NOINLINE void update_conf(const char* source) (void)source; } +#ifdef SP_EXECUTE_LOG +extern void step_SP_commands(usf_state_t * state, int PC, uint32_t inst); +#endif + #include "su.h" #include "vu/vu.h" @@ -67,4 +71,45 @@ NOINLINE void update_conf(const char* source) NOINLINE extern void run_task(usf_state_t * state); #include "execute.h" +#ifdef SP_EXECUTE_LOG +#include "matrix.h" + +void step_SP_commands(usf_state_t * state, int PC, uint32_t inst) +{ + const char digits[16] = { + '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' + }; + char text[256]; + char offset[4] = ""; + char code[9] = ""; + char disasm[24]; + unsigned char endian_swap[4]; + + endian_swap[00] = (unsigned char)(inst >> 24); + endian_swap[01] = (unsigned char)(inst >> 16); + endian_swap[02] = (unsigned char)(inst >> 8); + endian_swap[03] = (unsigned char)inst; + offset[00] = digits[(PC & 0xF00) >> 8]; + offset[01] = digits[(PC & 0x0F0) >> 4]; + offset[02] = digits[(PC & 0x00F) >> 0]; + code[00] = digits[(inst & 0xF0000000) >> 28]; + code[01] = digits[(inst & 0x0F000000) >> 24]; + code[02] = digits[(inst & 0x00F00000) >> 20]; + code[03] = digits[(inst & 0x000F0000) >> 16]; + code[04] = digits[(inst & 0x0000F000) >> 12]; + code[05] = digits[(inst & 0x00000F00) >> 8]; + code[06] = digits[(inst & 0x000000F0) >> 4]; + code[07] = digits[(inst & 0x0000000F) >> 0]; + strcpy(text, "RSP:\t"); + strcat(text, offset); + strcat(text, ":\t"); + strcat(text, code); + strcat(text, "\t"); + disassemble(disasm, inst); + strcat(text, disasm); + strcat(text, "\n"); + fputs(text, stdout); +} +#endif + #endif diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/alist.c b/Frameworks/lazyusf/lazyusf/rsp_hle/alist.c new file mode 100644 index 000000000..15e5b5954 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/alist.c @@ -0,0 +1,868 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-rsp-hle - alist.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * 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 +#include +#include + +#include "../usf.h" + +#include "alist_internal.h" +#include "arithmetics.h" +#include "audio_hle.h" +#include "memory_hle.h" +#include "plugin_hle.h" + +#include "../usf_internal.h" + +struct ramp_t +{ + int64_t value; + int64_t step; + int64_t target; +}; + +/* local functions */ +static void swap(int16_t **a, int16_t **b) +{ + int16_t* tmp = *b; + *b = *a; + *a = tmp; +} + +static int16_t* sample(usf_state_t * state, unsigned pos) +{ + return (int16_t*)state->BufferSpace + (pos ^ S); +} + +static void sample_mix(int16_t* dst, int16_t src, int16_t gain) +{ + *dst = clamp_s16(*dst + ((src * gain) >> 15)); +} + +static void alist_envmix_mix(size_t n, int16_t** dst, const int16_t* gains, int16_t src) +{ + size_t i; + + for(i = 0; i < n; ++i) + sample_mix(dst[i], src, gains[i]); +} + +static int16_t ramp_step(struct ramp_t* ramp) +{ + ramp->value += ramp->step; + + bool target_reached = (ramp->step <= 0) + ? (ramp->value <= ramp->target) + : (ramp->value >= ramp->target); + + if (target_reached) + { + ramp->value = ramp->target; + ramp->step = 0; + } + + return (ramp->value >> 16); +} + +/* global functions */ +void alist_process(usf_state_t* state, const acmd_callback_t abi[], unsigned int abi_size) +{ + uint32_t w1, w2; + unsigned int acmd; + + const uint32_t *alist = dram_u32(state, *dmem_u32(state, TASK_DATA_PTR)); + const uint32_t *const alist_end = alist + (*dmem_u32(state, TASK_DATA_SIZE) >> 2); + + while (alist != alist_end) { + w1 = *(alist++); + w2 = *(alist++); + + acmd = (w1 >> 24) & 0x7f; + + if (acmd < abi_size) + (*abi[acmd])(state, w1, w2); + else + DebugMessage(state, M64MSG_WARNING, "Invalid ABI command %u", acmd); + } +} + +uint32_t alist_get_address(usf_state_t* state, uint32_t so, const uint32_t *segments, size_t n) +{ + uint8_t segment = (so >> 24); + uint32_t offset = (so & 0xffffff); + + if (segment >= n) { + DebugMessage(state, M64MSG_WARNING, "Invalid segment %u", segment); + return offset; + } + + return segments[segment] + offset; +} + +void alist_set_address(usf_state_t* state, uint32_t so, uint32_t *segments, size_t n) +{ + uint8_t segment = (so >> 24); + uint32_t offset = (so & 0xffffff); + + if (segment >= n) { + DebugMessage(state, M64MSG_WARNING, "Invalid segment %u", segment); + return; + } + + segments[segment] = offset; +} + +void alist_clear(usf_state_t* state, uint16_t dmem, uint16_t count) +{ + while(count != 0) { + state->BufferSpace[(dmem++)^S8] = 0; + --count; + } +} + +void alist_load(usf_state_t* state, uint16_t dmem, uint32_t address, uint16_t count) +{ + /* enforce DMA alignment constraints */ + dmem &= ~3; + address &= ~7; + count = align(count, 8); + memcpy(state->BufferSpace + dmem, state->N64MEM + address, count); +} + +void alist_save(usf_state_t* state, uint16_t dmem, uint32_t address, uint16_t count) +{ + /* enforce DMA alignment constraints */ + dmem &= ~3; + address &= ~7; + count = align(count, 8); + memcpy(state->N64MEM + address, state->BufferSpace + dmem, count); +} + +void alist_move(usf_state_t* state, uint16_t dmemo, uint16_t dmemi, uint16_t count) +{ + while (count != 0) { + state->BufferSpace[(dmemo++)^S8] = state->BufferSpace[(dmemi++)^S8]; + --count; + } +} + +void alist_copy_every_other_sample(usf_state_t* state, uint16_t dmemo, uint16_t dmemi, uint16_t count) +{ + while (count != 0) { + *(uint16_t*)(state->BufferSpace + (dmemo^S8)) = *(uint16_t*)(state->BufferSpace + (dmemi^S8)); + dmemo += 2; + dmemi += 4; + --count; + } +} + +void alist_repeat64(usf_state_t* state, uint16_t dmemo, uint16_t dmemi, uint8_t count) +{ + uint16_t buffer[64]; + + memcpy(buffer, state->BufferSpace + dmemi, 128); + + while(count != 0) { + memcpy(state->BufferSpace + dmemo, buffer, 128); + dmemo += 128; + --count; + } +} + +void alist_copy_blocks(usf_state_t* state, uint16_t dmemo, uint16_t dmemi, uint16_t block_size, uint8_t count) +{ + int block_left = count; + + do + { + int bytes_left = block_size; + + do + { + memcpy(state->BufferSpace + dmemo, state->BufferSpace + dmemi, 0x20); + bytes_left -= 0x20; + + dmemi += 0x20; + dmemo += 0x20; + + } while(bytes_left > 0); + + --block_left; + } while(block_left > 0); +} + +void alist_interleave(usf_state_t* state, uint16_t dmemo, uint16_t left, uint16_t right, uint16_t count) +{ + uint16_t *dst = (uint16_t*)(state->BufferSpace + dmemo); + const uint16_t *srcL = (uint16_t*)(state->BufferSpace + left); + const uint16_t *srcR = (uint16_t*)(state->BufferSpace + right); + + count >>= 2; + + while(count != 0) { + uint16_t l1 = *(srcL++); + uint16_t l2 = *(srcL++); + uint16_t r1 = *(srcR++); + uint16_t r2 = *(srcR++); + +#if M64P_BIG_ENDIAN + *(dst++) = l1; + *(dst++) = r1; + *(dst++) = l2; + *(dst++) = r2; +#else + *(dst++) = r2; + *(dst++) = l2; + *(dst++) = r1; + *(dst++) = l1; +#endif + --count; + } +} + + +void alist_envmix_exp( + usf_state_t* state, + 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) +{ + size_t n = (aux) ? 4 : 2; + + const int16_t* const in = (int16_t*)(state->BufferSpace + dmemi); + int16_t* const dl = (int16_t*)(state->BufferSpace + dmem_dl); + int16_t* const dr = (int16_t*)(state->BufferSpace + dmem_dr); + int16_t* const wl = (int16_t*)(state->BufferSpace + dmem_wl); + int16_t* const wr = (int16_t*)(state->BufferSpace + dmem_wr); + + struct ramp_t ramps[2]; + int32_t exp_seq[2]; + int32_t exp_rates[2]; + + uint32_t ptr = 0; + int x, y; + short save_buffer[40]; + + if (init) { + ramps[0].value = (vol[0] << 16); + ramps[1].value = (vol[1] << 16); + ramps[0].target = (target[0] << 16); + ramps[1].target = (target[1] << 16); + exp_rates[0] = rate[0]; + exp_rates[1] = rate[1]; + exp_seq[0] = (vol[0] * rate[0]); + exp_seq[1] = (vol[1] * rate[1]); + } else { + memcpy((uint8_t *)save_buffer, (state->N64MEM + address), 80); + wet = *(int16_t *)(save_buffer + 0); /* 0-1 */ + dry = *(int16_t *)(save_buffer + 2); /* 2-3 */ + ramps[0].target = *(int32_t *)(save_buffer + 4); /* 4-5 */ + ramps[1].target = *(int32_t *)(save_buffer + 6); /* 6-7 */ + exp_rates[0] = *(int32_t *)(save_buffer + 8); /* 8-9 (save_buffer is a 16bit pointer) */ + exp_rates[1] = *(int32_t *)(save_buffer + 10); /* 10-11 */ + exp_seq[0] = *(int32_t *)(save_buffer + 12); /* 12-13 */ + exp_seq[1] = *(int32_t *)(save_buffer + 14); /* 14-15 */ + ramps[0].value = *(int32_t *)(save_buffer + 16); /* 12-13 */ + ramps[1].value = *(int32_t *)(save_buffer + 18); /* 14-15 */ + } + + /* init which ensure ramp.step != 0 iff ramp.value == ramp.target */ + ramps[0].step = ramps[0].target - ramps[0].value; + ramps[1].step = ramps[1].target - ramps[1].value; + + for (y = 0; y < count; y += 16) { + + if (ramps[0].step != 0) + { + exp_seq[0] = ((int64_t)exp_seq[0]*(int64_t)exp_rates[0]) >> 16; + ramps[0].step = (exp_seq[0] - ramps[0].value) >> 3; + } + + if (ramps[1].step != 0) + { + exp_seq[1] = ((int64_t)exp_seq[1]*(int64_t)exp_rates[1]) >> 16; + ramps[1].step = (exp_seq[1] - ramps[1].value) >> 3; + } + + for (x = 0; x < 8; ++x) { + int16_t gains[4]; + int16_t* buffers[4]; + int16_t l_vol = ramp_step(&ramps[0]); + int16_t r_vol = ramp_step(&ramps[1]); + + buffers[0] = dl + (ptr^S); + buffers[1] = dr + (ptr^S); + buffers[2] = wl + (ptr^S); + buffers[3] = wr + (ptr^S); + + gains[0] = clamp_s16((l_vol * dry + 0x4000) >> 15); + gains[1] = clamp_s16((r_vol * dry + 0x4000) >> 15); + gains[2] = clamp_s16((l_vol * wet + 0x4000) >> 15); + gains[3] = clamp_s16((r_vol * wet + 0x4000) >> 15); + + alist_envmix_mix(n, buffers, gains, in[ptr^S]); + ++ptr; + } + } + + *(int16_t *)(save_buffer + 0) = wet; /* 0-1 */ + *(int16_t *)(save_buffer + 2) = dry; /* 2-3 */ + *(int32_t *)(save_buffer + 4) = ramps[0].target; /* 4-5 */ + *(int32_t *)(save_buffer + 6) = ramps[1].target; /* 6-7 */ + *(int32_t *)(save_buffer + 8) = exp_rates[0]; /* 8-9 (save_buffer is a 16bit pointer) */ + *(int32_t *)(save_buffer + 10) = exp_rates[1]; /* 10-11 */ + *(int32_t *)(save_buffer + 12) = exp_seq[0]; /* 12-13 */ + *(int32_t *)(save_buffer + 14) = exp_seq[1]; /* 14-15 */ + *(int32_t *)(save_buffer + 16) = ramps[0].value; /* 12-13 */ + *(int32_t *)(save_buffer + 18) = ramps[1].value; /* 14-15 */ + memcpy(state->N64MEM + address, (uint8_t *)save_buffer, 80); +} + +void alist_envmix_lin( + usf_state_t* state, + 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) +{ + size_t k; + struct ramp_t ramps[2]; + int16_t save_buffer[40]; + + const int16_t * const in = (int16_t*)(state->BufferSpace + dmemi); + int16_t* const dl = (int16_t*)(state->BufferSpace + dmem_dl); + int16_t* const dr = (int16_t*)(state->BufferSpace + dmem_dr); + int16_t* const wl = (int16_t*)(state->BufferSpace + dmem_wl); + int16_t* const wr = (int16_t*)(state->BufferSpace + dmem_wr); + + if (init) { + ramps[0].step = rate[0] / 8; + ramps[0].value = (vol[0] << 16); + ramps[0].target = (target[0] << 16); + ramps[1].step = rate[1] / 8; + ramps[1].value = (vol[1] << 16); + ramps[1].target = (target[1] << 16); + } + else { + memcpy((uint8_t *)save_buffer, state->N64MEM + address, 80); + wet = *(int16_t *)(save_buffer + 0); /* 0-1 */ + dry = *(int16_t *)(save_buffer + 2); /* 2-3 */ + ramps[0].target = *(int16_t *)(save_buffer + 4) << 16; /* 4-5 */ + ramps[1].target = *(int16_t *)(save_buffer + 6) << 16; /* 6-7 */ + ramps[0].step = *(int32_t *)(save_buffer + 8); /* 8-9 (save_buffer is a 16bit pointer) */ + ramps[1].step = *(int32_t *)(save_buffer + 10); /* 10-11 */ + ramps[0].value = *(int32_t *)(save_buffer + 16); /* 16-17 */ + ramps[1].value = *(int32_t *)(save_buffer + 18); /* 16-17 */ + } + + count >>= 1; + for(k = 0; k < count; ++k) { + int16_t gains[4]; + int16_t* buffers[4]; + int16_t l_vol = ramp_step(&ramps[0]); + int16_t r_vol = ramp_step(&ramps[1]); + + buffers[0] = dl + (k^S); + buffers[1] = dr + (k^S); + buffers[2] = wl + (k^S); + buffers[3] = wr + (k^S); + + gains[0] = clamp_s16((l_vol * dry + 0x4000) >> 15); + gains[1] = clamp_s16((r_vol * dry + 0x4000) >> 15); + gains[2] = clamp_s16((l_vol * wet + 0x4000) >> 15); + gains[3] = clamp_s16((r_vol * wet + 0x4000) >> 15); + + alist_envmix_mix(4, buffers, gains, in[k^S]); + } + + *(int16_t *)(save_buffer + 0) = wet; /* 0-1 */ + *(int16_t *)(save_buffer + 2) = dry; /* 2-3 */ + *(int16_t *)(save_buffer + 4) = ramps[0].target >> 16; /* 4-5 */ + *(int16_t *)(save_buffer + 6) = ramps[1].target >> 16; /* 6-7 */ + *(int32_t *)(save_buffer + 8) = ramps[0].step; /* 8-9 (save_buffer is a 16bit pointer) */ + *(int32_t *)(save_buffer + 10) = ramps[1].step; /* 10-11 */ + *(int32_t *)(save_buffer + 16) = ramps[0].value; /* 16-17 */ + *(int32_t *)(save_buffer + 18) = ramps[1].value; /* 18-19 */ + memcpy(state->N64MEM + address, (uint8_t *)save_buffer, 80); +} + +void alist_envmix_nead( + usf_state_t* state, + 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) +{ + /* make sure count is a multiple of 8 */ + count = align(count, 8); + + int16_t *in = (int16_t*)(state->BufferSpace + dmemi); + int16_t *dl = (int16_t*)(state->BufferSpace + dmem_dl); + int16_t *dr = (int16_t*)(state->BufferSpace + dmem_dr); + int16_t *wl = (int16_t*)(state->BufferSpace + dmem_wl); + int16_t *wr = (int16_t*)(state->BufferSpace + dmem_wr); + + if (swap_wet_LR) + swap(&wl, &wr); + + while (count != 0) { + size_t i; + for(i = 0; i < 8; ++i) { + int16_t l = (((int32_t)in[i^S] * (uint32_t)env_values[0]) >> 16) ^ xors[0]; + int16_t r = (((int32_t)in[i^S] * (uint32_t)env_values[1]) >> 16) ^ xors[1]; + int16_t l2 = (((int32_t)l * (uint32_t)env_values[2]) >> 16) ^ xors[2]; + int16_t r2 = (((int32_t)r * (uint32_t)env_values[2]) >> 16) ^ xors[3]; + + dl[i^S] = clamp_s16(dl[i^S] + l); + dr[i^S] = clamp_s16(dr[i^S] + r); + wl[i^S] = clamp_s16(wl[i^S] + l2); + wr[i^S] = clamp_s16(wr[i^S] + r2); + } + + env_values[0] += env_steps[0]; + env_values[1] += env_steps[1]; + env_values[2] += env_steps[2]; + + dl += 8; + dr += 8; + wl += 8; + wr += 8; + in += 8; + count -= 8; + } +} + + +void alist_mix(usf_state_t* state, uint16_t dmemo, uint16_t dmemi, uint16_t count, int16_t gain) +{ + int16_t *dst = (int16_t*)(state->BufferSpace + dmemo); + const int16_t *src = (int16_t*)(state->BufferSpace + dmemi); + + count >>= 1; + + while(count != 0) { + sample_mix(dst, *src, gain); + + ++dst; + ++src; + --count; + } +} + +void alist_multQ44(usf_state_t* state, uint16_t dmem, uint16_t count, int8_t gain) +{ + int16_t *dst = (int16_t*)(state->BufferSpace + dmem); + + count >>= 1; + + while(count != 0) { + *dst = clamp_s16(*dst * gain >> 4); + + ++dst; + --count; + } +} + +void alist_add(usf_state_t* state, uint16_t dmemo, uint16_t dmemi, uint16_t count) +{ + int16_t *dst = (int16_t*)(state->BufferSpace + dmemo); + const int16_t *src = (int16_t*)(state->BufferSpace + dmemi); + + count >>= 1; + + while(count != 0) { + *dst = clamp_s16(*dst + *src); + + ++dst; + ++src; + --count; + } +} + +static void alist_resample_reset(usf_state_t* state, uint16_t pos, uint32_t* pitch_accu) +{ + unsigned k; + + for(k = 0; k < 4; ++k) + *sample(state, pos + k) = 0; + + *pitch_accu = 0; +} + +static void alist_resample_load(usf_state_t* state, uint32_t address, uint16_t pos, uint32_t* pitch_accu) +{ + *sample(state, pos + 0) = *dram_u16(state, address + 0); + *sample(state, pos + 1) = *dram_u16(state, address + 2); + *sample(state, pos + 2) = *dram_u16(state, address + 4); + *sample(state, pos + 3) = *dram_u16(state, address + 6); + + *pitch_accu = *dram_u16(state, address + 8); +} + +static void alist_resample_save(usf_state_t* state, uint32_t address, uint16_t pos, uint32_t pitch_accu) +{ + *dram_u16(state, address + 0) = *sample(state, pos + 0); + *dram_u16(state, address + 2) = *sample(state, pos + 1); + *dram_u16(state, address + 4) = *sample(state, pos + 2); + *dram_u16(state, address + 6) = *sample(state, pos + 3); + + *dram_u16(state, address + 8) = pitch_accu; +} + +void alist_resample( + usf_state_t* state, + bool init, + bool flag2, + uint16_t dmemo, + uint16_t dmemi, + uint16_t count, + uint32_t pitch, /* Q16.16 */ + uint32_t address) +{ + uint32_t pitch_accu; + + uint16_t ipos = dmemi >> 1; + uint16_t opos = dmemo >> 1; + count >>= 1; + ipos -= 4; + + if (flag2) + DebugMessage(state, M64MSG_WARNING, "alist_resample: flag2 is not implemented"); + + if (init) + alist_resample_reset(state, ipos, &pitch_accu); + else + alist_resample_load(state, address, ipos, &pitch_accu); + + while (count != 0) { + const int16_t* lut = RESAMPLE_LUT + ((pitch_accu & 0xfc00) >> 8); + + *sample(state, opos++) = clamp_s16( + ((*sample(state, ipos ) * lut[0]) >> 15) + + ((*sample(state, ipos + 1) * lut[1]) >> 15) + + ((*sample(state, ipos + 2) * lut[2]) >> 15) + + ((*sample(state, ipos + 3) * lut[3]) >> 15)); + + pitch_accu += pitch; + ipos += (pitch_accu >> 16); + pitch_accu &= 0xffff; + --count; + } + + alist_resample_save(state, address, ipos, pitch_accu); +} + +void alist_resample_zoh( + usf_state_t* state, + uint16_t dmemo, + uint16_t dmemi, + uint16_t count, + uint32_t pitch, + uint32_t pitch_accu) +{ + uint16_t ipos = dmemi >> 1; + uint16_t opos = dmemo >> 1; + count >>= 1; + + while(count != 0) { + + *sample(state, opos++) = *sample(state, ipos); + + pitch_accu += pitch; + ipos += (pitch_accu >> 16); + pitch_accu &= 0xffff; + --count; + } +} + +typedef unsigned int (*adpcm_predict_frame_t)(usf_state_t* state, int16_t* dst, uint16_t dmemi, unsigned char scale); + +static unsigned int adpcm_predict_frame_4bits(usf_state_t* state, int16_t* dst, uint16_t dmemi, unsigned char scale) +{ + unsigned int i; + unsigned int rshift = (scale < 12) ? 12 - scale : 0; + + for(i = 0; i < 8; ++i) { + uint8_t byte = state->BufferSpace[(dmemi++)^S8]; + + *(dst++) = adpcm_predict_sample(byte, 0xf0, 8, rshift); + *(dst++) = adpcm_predict_sample(byte, 0x0f, 12, rshift); + } + + return 8; +} + +static unsigned int adpcm_predict_frame_2bits(usf_state_t* state, int16_t* dst, uint16_t dmemi, unsigned char scale) +{ + unsigned int i; + unsigned int rshift = (scale < 14) ? 14 - scale : 0; + + for(i = 0; i < 4; ++i) { + uint8_t byte = state->BufferSpace[(dmemi++)^S8]; + + *(dst++) = adpcm_predict_sample(byte, 0xc0, 8, rshift); + *(dst++) = adpcm_predict_sample(byte, 0x30, 10, rshift); + *(dst++) = adpcm_predict_sample(byte, 0x0c, 12, rshift); + *(dst++) = adpcm_predict_sample(byte, 0x03, 14, rshift); + } + + return 4; +} + +void alist_adpcm( + usf_state_t* state, + 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) +{ + assert((count & 0x1f) == 0); + + int16_t last_frame[16]; + size_t i; + + if (init) + memset(last_frame, 0, 16*sizeof(last_frame[0])); + else + dram_load_u16(state, (uint16_t*)last_frame, (loop) ? loop_address : last_frame_address, 16); + + for(i = 0; i < 16; ++i, dmemo += 2) + *(int16_t*)(state->BufferSpace + (dmemo ^ S16)) = last_frame[i]; + + adpcm_predict_frame_t predict_frame = (two_bit_per_sample) + ? adpcm_predict_frame_2bits + : adpcm_predict_frame_4bits; + + while (count != 0) { + int16_t frame[16]; + uint8_t code = state->BufferSpace[(dmemi++)^S8]; + unsigned char scale = (code & 0xf0) >> 4; + const int16_t* const cb_entry = codebook + ((code & 0xf) << 4); + + dmemi += predict_frame(state, frame, dmemi, scale); + + adpcm_compute_residuals(last_frame , frame , cb_entry, last_frame + 14, 8); + adpcm_compute_residuals(last_frame + 8, frame + 8, cb_entry, last_frame + 6 , 8); + + for(i = 0; i < 16; ++i, dmemo += 2) + *(int16_t*)(state->BufferSpace + (dmemo ^ S16)) = last_frame[i]; + + count -= 32; + } + + dram_store_u16(state, (uint16_t*)last_frame, last_frame_address, 16); +} + + +void alist_filter(usf_state_t* state, uint16_t dmem, uint16_t count, uint32_t address, const uint32_t* lut_address) +{ + int x; + int16_t outbuff[0x3c0]; + int16_t *outp = outbuff; + + int16_t* const lutt6 = (int16_t*)(state->N64MEM + lut_address[0]); + int16_t* const lutt5 = (int16_t*)(state->N64MEM + lut_address[1]); + + int16_t* in1 = (int16_t*)(state->N64MEM + address); + int16_t* in2 = (int16_t*)(state->BufferSpace + dmem); + + + for (x = 0; x < 8; ++x) { + int32_t v = (lutt5[x] + lutt6[x]) >> 1; + lutt5[x] = lutt6[x] = v; + } + + for (x = 0; x < count; x += 16) { + int32_t v[8]; + + v[1] = in1[0] * lutt6[6]; + v[1] += in1[3] * lutt6[7]; + v[1] += in1[2] * lutt6[4]; + v[1] += in1[5] * lutt6[5]; + v[1] += in1[4] * lutt6[2]; + v[1] += in1[7] * lutt6[3]; + v[1] += in1[6] * lutt6[0]; + v[1] += in2[1] * lutt6[1]; /* 1 */ + + v[0] = in1[3] * lutt6[6]; + v[0] += in1[2] * lutt6[7]; + v[0] += in1[5] * lutt6[4]; + v[0] += in1[4] * lutt6[5]; + v[0] += in1[7] * lutt6[2]; + v[0] += in1[6] * lutt6[3]; + v[0] += in2[1] * lutt6[0]; + v[0] += in2[0] * lutt6[1]; + + v[3] = in1[2] * lutt6[6]; + v[3] += in1[5] * lutt6[7]; + v[3] += in1[4] * lutt6[4]; + v[3] += in1[7] * lutt6[5]; + v[3] += in1[6] * lutt6[2]; + v[3] += in2[1] * lutt6[3]; + v[3] += in2[0] * lutt6[0]; + v[3] += in2[3] * lutt6[1]; + + v[2] = in1[5] * lutt6[6]; + v[2] += in1[4] * lutt6[7]; + v[2] += in1[7] * lutt6[4]; + v[2] += in1[6] * lutt6[5]; + v[2] += in2[1] * lutt6[2]; + v[2] += in2[0] * lutt6[3]; + v[2] += in2[3] * lutt6[0]; + v[2] += in2[2] * lutt6[1]; + + v[5] = in1[4] * lutt6[6]; + v[5] += in1[7] * lutt6[7]; + v[5] += in1[6] * lutt6[4]; + v[5] += in2[1] * lutt6[5]; + v[5] += in2[0] * lutt6[2]; + v[5] += in2[3] * lutt6[3]; + v[5] += in2[2] * lutt6[0]; + v[5] += in2[5] * lutt6[1]; + + v[4] = in1[7] * lutt6[6]; + v[4] += in1[6] * lutt6[7]; + v[4] += in2[1] * lutt6[4]; + v[4] += in2[0] * lutt6[5]; + v[4] += in2[3] * lutt6[2]; + v[4] += in2[2] * lutt6[3]; + v[4] += in2[5] * lutt6[0]; + v[4] += in2[4] * lutt6[1]; + + v[7] = in1[6] * lutt6[6]; + v[7] += in2[1] * lutt6[7]; + v[7] += in2[0] * lutt6[4]; + v[7] += in2[3] * lutt6[5]; + v[7] += in2[2] * lutt6[2]; + v[7] += in2[5] * lutt6[3]; + v[7] += in2[4] * lutt6[0]; + v[7] += in2[7] * lutt6[1]; + + v[6] = in2[1] * lutt6[6]; + v[6] += in2[0] * lutt6[7]; + v[6] += in2[3] * lutt6[4]; + v[6] += in2[2] * lutt6[5]; + v[6] += in2[5] * lutt6[2]; + v[6] += in2[4] * lutt6[3]; + v[6] += in2[7] * lutt6[0]; + v[6] += in2[6] * lutt6[1]; + + outp[1] = ((v[1] + 0x4000) >> 15); + outp[0] = ((v[0] + 0x4000) >> 15); + outp[3] = ((v[3] + 0x4000) >> 15); + outp[2] = ((v[2] + 0x4000) >> 15); + outp[5] = ((v[5] + 0x4000) >> 15); + outp[4] = ((v[4] + 0x4000) >> 15); + outp[7] = ((v[7] + 0x4000) >> 15); + outp[6] = ((v[6] + 0x4000) >> 15); + in1 = in2; + in2 += 8; + outp += 8; + } + + memcpy(state->N64MEM + address, in2 - 8, 16); + memcpy(state->BufferSpace + dmem, outbuff, count); +} + +void alist_polef( + usf_state_t* state, + bool init, + uint16_t dmemo, + uint16_t dmemi, + uint16_t count, + uint16_t gain, + int16_t* table, + uint32_t address) +{ + int16_t *dst = (int16_t*)(state->BufferSpace + dmemo); + + const int16_t* const h1 = table; + int16_t* const h2 = table + 8; + + unsigned i; + int16_t l1, l2; + int16_t h2_before[8]; + + count = align(count, 16); + + if (init) { + l1 = 0; + l2 = 0; + } + else { + l1 = *dram_u16(state, address + 4); + l2 = *dram_u16(state, address + 6); + } + + for(i = 0; i < 8; ++i) { + h2_before[i] = h2[i]; + h2[i] = (((int32_t)h2[i] * gain) >> 14); + } + + do + { + int16_t frame[8]; + + for(i = 0; i < 8; ++i, dmemi += 2) { + frame[i] = *(int16_t*)(state->BufferSpace + (dmemi ^ S16)); + } + + for(i = 0; i < 8; ++i) { + int32_t accu = frame[i] * gain; + accu += h1[i]*l1 + h2_before[i]*l2 + rdot(i, h2, frame); + dst[i^S] = clamp_s16(accu >> 14); + } + + l1 = dst[6^S]; + l2 = dst[7^S]; + + dst += 8; + count -= 16; + } while (count != 0); + + dram_store_u16(state, (uint16_t*)(dst - 4), address, 4); +} diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/alist.h b/Frameworks/lazyusf/lazyusf/rsp_hle/alist.h new file mode 100644 index 000000000..1cf812b95 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/alist.h @@ -0,0 +1,46 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-rsp-hle - alist.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * 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 ALIST_H +#define ALIST_H + +void alist_process_audio(usf_state_t* state); +void alist_process_audio_ge(usf_state_t* state); +void alist_process_audio_bc(usf_state_t* state); +void alist_process_nead_mk(usf_state_t* state); +void alist_process_nead_sfj(usf_state_t* state); +void alist_process_nead_sf(usf_state_t* state); +void alist_process_nead_fz(usf_state_t* state); +void alist_process_nead_wrjb(usf_state_t* state); +void alist_process_nead_ys(usf_state_t* state); +void alist_process_nead_1080(usf_state_t* state); +void alist_process_nead_oot(usf_state_t* state); +void alist_process_nead_mm(usf_state_t* state); +void alist_process_nead_mmb(usf_state_t* state); +void alist_process_nead_ac(usf_state_t* state); +void alist_process_naudio(usf_state_t* state); +void alist_process_naudio_bk(usf_state_t* state); +void alist_process_naudio_dk(usf_state_t* state); +void alist_process_naudio_mp3(usf_state_t* state); +void alist_process_naudio_cbfd(usf_state_t* state); + +#endif + diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/alist_audio.c b/Frameworks/lazyusf/lazyusf/rsp_hle/alist_audio.c new file mode 100644 index 000000000..bb59ef9af --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/alist_audio.c @@ -0,0 +1,291 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-rsp-hle - alist_audio.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * 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 +#include +#include + +#include "../usf.h" + +#include "alist_internal.h" +#include "memory_hle.h" + +#include "../usf_internal.h" + +/* state moved to usf_internal.h */ + +/* helper functions */ +static uint32_t get_address(usf_state_t* state, uint32_t so) +{ + return alist_get_address(state, so, state->l_alist_audio.segments, N_SEGMENTS); +} + +static void set_address(usf_state_t* state, uint32_t so) +{ + alist_set_address(state, so, state->l_alist_audio.segments, N_SEGMENTS); +} + +static void clear_segments(usf_state_t* state) +{ + memset(state->l_alist_audio.segments, 0, N_SEGMENTS*sizeof(state->l_alist_audio.segments[0])); +} + +/* audio commands definition */ +static void SPNOOP(usf_state_t* state, uint32_t w1, uint32_t w2) +{ +} + +static void CLEARBUFF(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + uint16_t dmem = w1 + DMEM_BASE; + uint16_t count = w2; + + if (count == 0) + return; + + alist_clear(state, dmem, align(count, 16)); +} + +static void ENVMIXER(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + uint8_t flags = (w1 >> 16); + uint32_t address = get_address(state, w2); + + alist_envmix_exp( + state, + flags & A_INIT, + flags & A_AUX, + state->l_alist_audio.out, state->l_alist_audio.dry_right, + state->l_alist_audio.wet_left, state->l_alist_audio.wet_right, + state->l_alist_audio.in, state->l_alist_audio.count, + state->l_alist_audio.dry, state->l_alist_audio.wet, + state->l_alist_audio.vol, + state->l_alist_audio.target, + state->l_alist_audio.rate, + address); +} + +static void RESAMPLE(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + uint8_t flags = (w1 >> 16); + uint16_t pitch = w1; + uint32_t address = get_address(state, w2); + + alist_resample( + state, + flags & 0x1, + flags & 0x2, + state->l_alist_audio.out, + state->l_alist_audio.in, + align(state->l_alist_audio.count, 16), + pitch << 1, + address); +} + +static void SETVOL(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + uint8_t flags = (w1 >> 16); + + if (flags & A_AUX) { + state->l_alist_audio.dry = w1; + state->l_alist_audio.wet = w2; + } + else { + unsigned lr = (flags & A_LEFT) ? 0 : 1; + + if (flags & A_VOL) + state->l_alist_audio.vol[lr] = w1; + else { + state->l_alist_audio.target[lr] = w1; + state->l_alist_audio.rate[lr] = w2; + } + } +} + +static void SETLOOP(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + state->l_alist_audio.loop = get_address(state, w2); +} + +static void ADPCM(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + uint8_t flags = (w1 >> 16); + uint32_t address = get_address(state, w2); + + alist_adpcm( + state, + flags & 0x1, + flags & 0x2, + false, /* unsupported in this ucode */ + state->l_alist_audio.out, + state->l_alist_audio.in, + align(state->l_alist_audio.count, 32), + state->l_alist_audio.table, + state->l_alist_audio.loop, + address); +} + +static void LOADBUFF(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + uint32_t address = get_address(state, w2); + + if (state->l_alist_audio.count == 0) + return; + + alist_load(state, state->l_alist_audio.in, address, state->l_alist_audio.count); +} + +static void SAVEBUFF(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + uint32_t address = get_address(state, w2); + + if (state->l_alist_audio.count == 0) + return; + + alist_save(state, state->l_alist_audio.out, address, state->l_alist_audio.count); +} + +static void SETBUFF(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + uint8_t flags = (w1 >> 16); + + if (flags & A_AUX) { + state->l_alist_audio.dry_right = w1 + DMEM_BASE; + state->l_alist_audio.wet_left = (w2 >> 16) + DMEM_BASE; + state->l_alist_audio.wet_right = w2 + DMEM_BASE; + } else { + state->l_alist_audio.in = w1 + DMEM_BASE; + state->l_alist_audio.out = (w2 >> 16) + DMEM_BASE; + state->l_alist_audio.count = w2; + } +} + +static void DMEMMOVE(usf_state_t* state, 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(state, dmemo, dmemi, align(count, 16)); +} + +static void LOADADPCM(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + uint16_t count = w1; + uint32_t address = get_address(state, w2); + + dram_load_u16(state, (uint16_t*)state->l_alist_audio.table, address, align(count, 8) >> 1); +} + +static void INTERLEAVE(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + uint16_t left = (w2 >> 16) + DMEM_BASE; + uint16_t right = w2 + DMEM_BASE; + + if (state->l_alist_audio.count == 0) + return; + + alist_interleave(state, state->l_alist_audio.out, left, right, align(state->l_alist_audio.count, 16)); +} + +static void MIXER(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + int16_t gain = w1; + uint16_t dmemi = (w2 >> 16) + DMEM_BASE; + uint16_t dmemo = w2 + DMEM_BASE; + + if (state->l_alist_audio.count == 0) + return; + + alist_mix(state, dmemo, dmemi, align(state->l_alist_audio.count, 32), gain); +} + +static void SEGMENT(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + set_address(state, w2); +} + +static void POLEF(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + uint8_t flags = (w1 >> 16); + uint16_t gain = w1; + uint32_t address = get_address(state, w2); + + if (state->l_alist_audio.count == 0) + return; + + alist_polef( + state, + flags & A_INIT, + state->l_alist_audio.out, + state->l_alist_audio.in, + align(state->l_alist_audio.count, 16), + gain, + state->l_alist_audio.table, + address); +} + +/* global functions */ +void alist_process_audio(usf_state_t* state) +{ + 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(state); + alist_process(state, ABI, 0x10); +} + +void alist_process_audio_ge(usf_state_t* state) +{ + /* TODO: see what differs from alist_process_audio */ + 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(state); + alist_process(state, ABI, 0x10); +} + +void alist_process_audio_bc(usf_state_t* state) +{ + /* TODO: see what differs from alist_process_audio */ + 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(state); + alist_process(state, ABI, 0x10); +} diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/alist_internal.h b/Frameworks/lazyusf/lazyusf/rsp_hle/alist_internal.h new file mode 100644 index 000000000..012b9b1e0 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/alist_internal.h @@ -0,0 +1,145 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-rsp-hle - alist_internal.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * 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 ALIST_INTERNAL_H +#define ALIST_INTERNAL_H + +#include +#include +#include + +typedef void (*acmd_callback_t)(usf_state_t* state, uint32_t w1, uint32_t w2); + +void alist_process(usf_state_t* state, const acmd_callback_t abi[], unsigned int abi_size); +uint32_t alist_get_address(usf_state_t* state, uint32_t so, const uint32_t *segments, size_t n); +void alist_set_address(usf_state_t* state, uint32_t so, uint32_t *segments, size_t n); +void alist_clear(usf_state_t* state, uint16_t dmem, uint16_t count); +void alist_load(usf_state_t* state, uint16_t dmem, uint32_t address, uint16_t count); +void alist_save(usf_state_t* state, uint16_t dmem, uint32_t address, uint16_t count); +void alist_move(usf_state_t* state, uint16_t dmemo, uint16_t dmemi, uint16_t count); +void alist_copy_every_other_sample(usf_state_t* state, uint16_t dmemo, uint16_t dmemi, uint16_t count); +void alist_repeat64(usf_state_t* state, uint16_t dmemo, uint16_t dmemi, uint8_t count); +void alist_copy_blocks(usf_state_t* state, uint16_t dmemo, uint16_t dmemi, uint16_t block_size, uint8_t count); +void alist_interleave(usf_state_t* state, uint16_t dmemo, uint16_t left, uint16_t right, uint16_t count); + +void alist_envmix_exp( + usf_state_t* state, + 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( + usf_state_t* state, + 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( + usf_state_t* state, + 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(usf_state_t* state, uint16_t dmemo, uint16_t dmemi, uint16_t count, int16_t gain); +void alist_multQ44(usf_state_t* state, uint16_t dmem, uint16_t count, int8_t gain); +void alist_add(usf_state_t* state, uint16_t dmemo, uint16_t dmemi, uint16_t count); + +void alist_adpcm( + usf_state_t* state, + 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( + usf_state_t* state, + bool init, + bool flag2, + uint16_t dmemo, uint16_t dmemi, uint16_t count, + uint32_t pitch, uint32_t address); + +void alist_resample_zoh( + usf_state_t* state, + uint16_t dmemo, + uint16_t dmemi, + uint16_t count, + uint32_t pitch, + uint32_t pitch_accu); + +void alist_filter( + usf_state_t* state, + uint16_t dmem, + uint16_t count, + uint32_t address, + const uint32_t* lut_address); + +void alist_polef( + usf_state_t* state, + bool init, + uint16_t dmemo, + uint16_t dmemi, + uint16_t count, + uint16_t gain, + 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 diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/alist_naudio.c b/Frameworks/lazyusf/lazyusf/rsp_hle/alist_naudio.c new file mode 100644 index 000000000..d0f74af05 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/alist_naudio.c @@ -0,0 +1,302 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-rsp-hle - alist_naudio.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * 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 +#include + +#include "../usf.h" + +#include "alist_internal.h" +#include "memory_hle.h" +#include "plugin_hle.h" + +#include "../usf_internal.h" + +void MP3(usf_state_t* state, uint32_t w1, uint32_t w2); + +/* audio commands definition */ +static void UNKNOWN(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + uint8_t acmd = (w1 >> 24); + + DebugMessage(state, M64MSG_WARNING, + "Unknown audio comand %d: %08x %08x", + acmd, w1, w2); +} + + +static void SPNOOP(usf_state_t* state, uint32_t w1, uint32_t w2) +{ +} + +static void NAUDIO_0000(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + /* ??? */ + UNKNOWN(state, w1, w2); +} + +static void NAUDIO_02B0(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + /* ??? */ + /* UNKNOWN(state, w1, w2); commented to avoid constant spamming during gameplay */ +} + +static void NAUDIO_14(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + if (state->l_alist_naudio.table[0] == 0 && state->l_alist_naudio.table[1] == 0) { + + 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; + + alist_polef( + state, + flags & A_INIT, + dmem, + dmem, + NAUDIO_COUNT, + gain, + state->l_alist_naudio.table, + address); + } + else + DebugMessage(state, M64MSG_VERBOSE, "NAUDIO_14: non null codebook[0-3] case not implemented."); +} + +static void SETVOL(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + uint8_t flags = (w1 >> 16); + + if (flags & 0x4) { + if (flags & 0x2) { + state->l_alist_naudio.vol[0] = w1; + state->l_alist_naudio.dry = (w2 >> 16); + state->l_alist_naudio.wet = w2; + } + else { + state->l_alist_naudio.target[1] = w1; + state->l_alist_naudio.rate[1] = w2; + } + } + else { + state->l_alist_naudio.target[0] = w1; + state->l_alist_naudio.rate[0] = w2; + } +} + +static void ENVMIXER(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + uint8_t flags = (w1 >> 16); + uint32_t address = (w2 & 0xffffff); + + state->l_alist_naudio.vol[1] = w1; + + alist_envmix_lin( + state, + flags & 0x1, + NAUDIO_DRY_LEFT, + NAUDIO_DRY_RIGHT, + NAUDIO_WET_LEFT, + NAUDIO_WET_RIGHT, + NAUDIO_MAIN, + NAUDIO_COUNT, + state->l_alist_naudio.dry, + state->l_alist_naudio.wet, + state->l_alist_naudio.vol, + state->l_alist_naudio.target, + state->l_alist_naudio.rate, + address); +} + +static void CLEARBUFF(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + uint16_t dmem = w1 + NAUDIO_MAIN; + uint16_t count = w2; + + alist_clear(state, dmem, count); +} + +static void MIXER(usf_state_t* state, 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(state, dmemo, dmemi, NAUDIO_COUNT, gain); +} + +static void LOADBUFF(usf_state_t* state, 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(state, dmem, address, count); +} + +static void SAVEBUFF(usf_state_t* state, 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(state, dmem, address, count); +} + +static void LOADADPCM(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + uint16_t count = w1; + uint32_t address = (w2 & 0xffffff); + + dram_load_u16(state, (uint16_t*)state->l_alist_naudio.table, address, count >> 1); +} + +static void DMEMMOVE(usf_state_t* state, 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(state, dmemo, dmemi, (count + 3) & ~3); +} + +static void SETLOOP(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + state->l_alist_naudio.loop = (w2 & 0xffffff); +} + +static void ADPCM(usf_state_t* state, 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( + state, + flags & 0x1, + flags & 0x2, + false, /* unsuported by this ucode */ + dmemo, + dmemi, + (count + 0x1f) & ~0x1f, + state->l_alist_naudio.table, + state->l_alist_naudio.loop, + address); +} + +static void RESAMPLE(usf_state_t* state, 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( + state, + flags & 0x1, + false, /* TODO: check which ABI supports it */ + dmemo, + dmemi, + NAUDIO_COUNT, + pitch << 1, + address); +} + +static void INTERLEAVE(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + alist_interleave(state, NAUDIO_MAIN, NAUDIO_DRY_LEFT, NAUDIO_DRY_RIGHT, NAUDIO_COUNT); +} + +static void MP3ADDY(usf_state_t* state, uint32_t w1, uint32_t w2) +{ +} + +/* global functions */ +void alist_process_naudio(usf_state_t* state) +{ + 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(state, ABI, 0x10); +} + +void alist_process_naudio_bk(usf_state_t* state) +{ + /* 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(state, ABI, 0x10); +} + +void alist_process_naudio_dk(usf_state_t* state) +{ + /* 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(state, ABI, 0x10); +} + +void alist_process_naudio_mp3(usf_state_t* state) +{ + 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(state, ABI, 0x10); +} + +void alist_process_naudio_cbfd(usf_state_t* state) +{ + /* 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(state, ABI, 0x10); +} diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/alist_nead.c b/Frameworks/lazyusf/lazyusf/rsp_hle/alist_nead.c new file mode 100644 index 000000000..c1a8ad9c5 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/alist_nead.c @@ -0,0 +1,524 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-rsp-hle - alist_nead.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * 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 +#include + +#include "../usf.h" + +#include "alist_internal.h" +#include "memory_hle.h" +#include "plugin_hle.h" + +#include "../usf_internal.h" + +/* remove windows define to 0x06 */ +#ifdef DUPLICATE +#undef DUPLICATE +#endif + + + +/* audio commands definition */ +static void UNKNOWN(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + uint8_t acmd = (w1 >> 24); + + DebugMessage(state, M64MSG_WARNING, + "Unknown audio comand %d: %08x %08x", + acmd, w1, w2); +} + + +static void SPNOOP(usf_state_t* state, uint32_t w1, uint32_t w2) +{ +} + +static void LOADADPCM(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + uint16_t count = w1; + uint32_t address = (w2 & 0xffffff); + + dram_load_u16(state, (uint16_t*)state->l_alist_nead.table, address, count >> 1); +} + +static void SETLOOP(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + state->l_alist_nead.loop = w2 & 0xffffff; +} + +static void SETBUFF(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + state->l_alist_nead.in = w1; + state->l_alist_nead.out = (w2 >> 16); + state->l_alist_nead.count = w2; +} + +static void ADPCM(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + uint8_t flags = (w1 >> 16); + uint32_t address = (w2 & 0xffffff); + + alist_adpcm( + state, + flags & 0x1, + flags & 0x2, + flags & 0x4, + state->l_alist_nead.out, + state->l_alist_nead.in, + (state->l_alist_nead.count + 0x1f) & ~0x1f, + state->l_alist_nead.table, + state->l_alist_nead.loop, + address); +} + +static void CLEARBUFF(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + uint16_t dmem = w1; + uint16_t count = w2; + + if (count == 0) + return; + + alist_clear(state, dmem, count); +} + +static void LOADBUFF(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + uint16_t count = (w1 >> 12) & 0xfff; + uint16_t dmem = (w1 & 0xfff); + uint32_t address = (w2 & 0xffffff); + + alist_load(state, dmem, address, count); +} + +static void SAVEBUFF(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + uint16_t count = (w1 >> 12) & 0xfff; + uint16_t dmem = (w1 & 0xfff); + uint32_t address = (w2 & 0xffffff); + + alist_save(state, dmem, address, count); +} + +static void MIXER(usf_state_t* state, 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(state, dmemo, dmemi, count, gain); +} + + +static void RESAMPLE(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + uint8_t flags = (w1 >> 16); + uint16_t pitch = w1; + uint32_t address = (w2 & 0xffffff); + + alist_resample( + state, + flags & 0x1, + false, /* TODO: check which ABI supports it */ + state->l_alist_nead.out, + state->l_alist_nead.in, + (state->l_alist_nead.count + 0xf) & ~0xf, + pitch << 1, + address); +} + +static void RESAMPLE_ZOH(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + uint16_t pitch = w1; + uint16_t pitch_accu = w2; + + alist_resample_zoh( + state, + state->l_alist_nead.out, + state->l_alist_nead.in, + state->l_alist_nead.count, + pitch << 1, + pitch_accu); +} + +static void DMEMMOVE(usf_state_t* state, 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(state, dmemo, dmemi, (count + 3) & ~3); +} + +static void ENVSETUP1_MK(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + state->l_alist_nead.env_values[2] = (w1 >> 8) & 0xff00; + state->l_alist_nead.env_steps[2] = 0; + state->l_alist_nead.env_steps[0] = (w2 >> 16); + state->l_alist_nead.env_steps[1] = w2; +} + +static void ENVSETUP1(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + state->l_alist_nead.env_values[2] = (w1 >> 8) & 0xff00; + state->l_alist_nead.env_steps[2] = w1; + state->l_alist_nead.env_steps[0] = (w2 >> 16); + state->l_alist_nead.env_steps[1] = w2; +} + +static void ENVSETUP2(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + state->l_alist_nead.env_values[0] = (w2 >> 16); + state->l_alist_nead.env_values[1] = w2; +} + +static void ENVMIXER_MK(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + int16_t xors[4]; + + uint16_t dmemi = (w1 >> 12) & 0xff0; + uint8_t count = (w1 >> 8) & 0xff; + 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) ); + 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; + + alist_envmix_nead( + state, + false, /* unsupported by this ucode */ + dmem_dl, dmem_dr, + dmem_wl, dmem_wr, + dmemi, count, + state->l_alist_nead.env_values, + state->l_alist_nead.env_steps, + xors); +} + +static void ENVMIXER(usf_state_t* state, 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; + 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) ); + 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; + + alist_envmix_nead( + state, + swap_wet_LR, + dmem_dl, dmem_dr, + dmem_wl, dmem_wr, + dmemi, count, + state->l_alist_nead.env_values, + state->l_alist_nead.env_steps, + xors); +} + +static void DUPLICATE(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + uint8_t count = (w1 >> 16); + uint16_t dmemi = w1; + uint16_t dmemo = (w2 >> 16); + + alist_repeat64(state, dmemo, dmemi, count); +} + +static void INTERL(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + uint16_t count = w1; + uint16_t dmemi = (w2 >> 16); + uint16_t dmemo = w2; + + alist_copy_every_other_sample(state, dmemo, dmemi, count); +} + +static void INTERLEAVE_MK(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + uint16_t left = (w2 >> 16); + uint16_t right = w2; + + if (state->l_alist_nead.count == 0) + return; + + alist_interleave(state, state->l_alist_nead.out, left, right, state->l_alist_nead.count); +} + +static void INTERLEAVE(usf_state_t* state, 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(state, dmemo, left, right, count); +} + +static void ADDMIXER(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + uint16_t count = (w1 >> 12) & 0xff0; + uint16_t dmemi = (w2 >> 16); + uint16_t dmemo = w2; + + alist_add(state, dmemo, dmemi, count); +} + +static void HILOGAIN(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + int8_t gain = (w1 >> 16); /* Q4.4 signed */ + uint16_t count = w1; + uint16_t dmem = (w2 >> 16); + + alist_multQ44(state, dmem, count, gain); +} + +static void FILTER(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + uint8_t flags = (w1 >> 16); + uint32_t address = (w2 & 0xffffff); + + if (flags > 1) { + state->l_alist_nead.filter_count = w1; + state->l_alist_nead.filter_lut_address[0] = address; /* t6 */ + } + else { + uint16_t dmem = w1; + + state->l_alist_nead.filter_lut_address[1] = address + 0x10; /* t5 */ + alist_filter(state, dmem, state->l_alist_nead.filter_count, address, state->l_alist_nead.filter_lut_address); + } +} + +static void SEGMENT(usf_state_t* state, uint32_t w1, uint32_t w2) +{ +} + +static void NEAD_16(usf_state_t* state, 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(state, dmemo, dmemi, block_size, count); +} + +static void POLEF(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + uint8_t flags = (w1 >> 16); + uint16_t gain = w1; + uint32_t address = (w2 & 0xffffff); + + if (state->l_alist_nead.count == 0) + return; + + alist_polef( + state, + flags & A_INIT, + state->l_alist_nead.out, + state->l_alist_nead.in, + state->l_alist_nead.count, + gain, + state->l_alist_nead.table, + address); +} + + +void alist_process_nead_mk(usf_state_t* state) +{ + 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(state, ABI, 0x20); +} + +void alist_process_nead_sf(usf_state_t* state) +{ + 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(state, ABI, 0x20); +} + +void alist_process_nead_sfj(usf_state_t* state) +{ + 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(state, ABI, 0x20); +} + +void alist_process_nead_fz(usf_state_t* state) +{ + 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(state, ABI, 0x20); +} + +void alist_process_nead_wrjb(usf_state_t* state) +{ + 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(state, ABI, 0x20); +} + +void alist_process_nead_ys(usf_state_t* state) +{ + 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(state, ABI, 0x18); +} + +void alist_process_nead_1080(usf_state_t* state) +{ + 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(state, ABI, 0x18); +} + +void alist_process_nead_oot(usf_state_t* state) +{ + 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(state, ABI, 0x18); +} + +void alist_process_nead_mm(usf_state_t* state) +{ + 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(state, ABI, 0x18); +} + +void alist_process_nead_mmb(usf_state_t* state) +{ + 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(state, ABI, 0x18); +} + +void alist_process_nead_ac(usf_state_t* state) +{ + 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(state, ABI, 0x18); +} diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/arithmetics.h b/Frameworks/lazyusf/lazyusf/rsp_hle/arithmetics.h new file mode 100644 index 000000000..3d0edf6fb --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/arithmetics.h @@ -0,0 +1,36 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-rsp-hle - arithmetics.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * 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 ARITHMETICS_H +#define ARITHMETICS_H + +#include + +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; +} + +#endif + diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/audio_hle.c b/Frameworks/lazyusf/lazyusf/rsp_hle/audio_hle.c new file mode 100644 index 000000000..3c94bf9fa --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/audio_hle.c @@ -0,0 +1,96 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-rsp-hle - audio.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * 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 +#include +#include + +#include "arithmetics.h" + +const int16_t RESAMPLE_LUT[64 * 4] = { + 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 +}; + +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) +{ + assert(count <= 8); + + 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; + + 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); + } +} + diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/audio_hle.h b/Frameworks/lazyusf/lazyusf/rsp_hle/audio_hle.h new file mode 100644 index 000000000..e2c34cd08 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/audio_hle.h @@ -0,0 +1,43 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-rsp-hle - audio.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * 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 AUDIO_H +#define AUDIO_H + +#include +#include + +extern const int16_t RESAMPLE_LUT[64 * 4]; + +int32_t rdot(size_t n, const int16_t *x, const int16_t *y); + +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 diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/cicx105.c b/Frameworks/lazyusf/lazyusf/rsp_hle/cicx105.c new file mode 100644 index 000000000..9cec98416 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/cicx105.c @@ -0,0 +1,59 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-rsp-hle - cicx105.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 + +#include "../usf.h" + +#include "plugin_hle.h" +#include "cicx105.h" + +#include "../usf_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(usf_state_t* state) +{ + /* memcpy is okay to use because access constrains are met (alignment, size) */ + unsigned int i; + unsigned char *dst = state->N64MEM + 0x2fb1f0; + unsigned char *src = state->IMEM + 0x120; + + /* dma_read(0x1120, 0x1e8, 0x1e8) */ + memcpy(state->IMEM + 0x120, state->N64MEM + 0x1e8, 0x1f0); + + /* dma_write(0x1120, 0x2fb1f0, 0xfe817000) */ + for (i = 0; i < 24; ++i) { + memcpy(dst, src, 8); + dst += 0xff0; + src += 0x8; + + } +} + diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/cicx105.h b/Frameworks/lazyusf/lazyusf/rsp_hle/cicx105.h new file mode 100644 index 000000000..1a282e8c8 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/cicx105.h @@ -0,0 +1,28 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-rsp-hle - cicx105.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2012 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 CICX105_H +#define CICX105_H + +void cicx105_ucode(usf_state_t* state); + +#endif + diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/jpeg.c b/Frameworks/lazyusf/lazyusf/rsp_hle/jpeg.c new file mode 100644 index 000000000..35205c68a --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/jpeg.c @@ -0,0 +1,594 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-rsp-hle - jpeg.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 +#include +#include + +#include "../usf.h" + +#include "arithmetics.h" +#include "memory_hle.h" +#include "plugin_hle.h" + +#include "../usf_internal.h" + +#define SUBBLOCK_SIZE 64 + +typedef void (*tile_line_emitter_t)(usf_state_t* state, 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(usf_state_t* state, + 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 uint16_t clamp_RGBA_component(int16_t x); + +/* 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(usf_state_t* state, const int16_t *y, const int16_t *u, uint32_t address); +static void EmitRGBATileLine(usf_state_t* state, const int16_t *y, const int16_t *u, uint32_t address); + +/* macroblocks operations */ +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(usf_state_t* state, const tile_line_emitter_t emit_line, const int16_t *macroblock, uint32_t address); +static void EmitTilesMode2(usf_state_t* state, 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); +static void ZigZagSubBlock(int16_t *dst, const int16_t *src); +static void ReorderSubBlock(int16_t *dst, const int16_t *src, const unsigned int *table); +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 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] = { + 16, 12, 14, 14, 18, 24, 49, 72, + 11, 12, 13, 17, 22, 35, 64, 92, + 10, 14, 16, 22, 37, 55, 78, 95, + 16, 19, 24, 29, 56, 64, 87, 98, + 24, 26, 40, 51, 68, 81, 103, 112, + 40, 58, 57, 87, 109, 104, 121, 100, + 51, 60, 69, 80, 103, 113, 120, 103, + 61, 55, 56, 62, 77, 92, 101, 99 +}; + +/* zig-zag indices */ +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, + 9, 11, 18, 24, 31, 40, 44, 53, + 10, 19, 23, 32, 39, 45, 52, 54, + 20, 22, 33, 38, 46, 51, 55, 60, + 21, 34, 37, 47, 50, 56, 59, 61, + 35, 36, 48, 49, 57, 58, 62, 63 +}; + +/* transposition indices */ +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, + 3, 11, 19, 27, 35, 43, 51, 59, + 4, 12, 20, 28, 36, 44, 52, 60, + 5, 13, 21, 29, 37, 45, 53, 61, + 6, 14, 22, 30, 38, 46, 54, 62, + 7, 15, 23, 31, 39, 47, 55, 63 +}; + + + +/* IDCT related constants + * 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 */ +}; + + +/* global functions */ + +/*************************************************************************** + * JPEG decoding ucode found in Japanese exclusive version of Pokemon Stadium. + **************************************************************************/ +void jpeg_decode_PS0(usf_state_t* state) +{ + jpeg_decode_std(state, "PS0", RescaleYSubBlock, RescaleUVSubBlock, EmitYUVTileLine); +} + +/*************************************************************************** + * JPEG decoding ucode found in Ocarina of Time, Pokemon Stadium 1 and + * Pokemon Stadium 2. + **************************************************************************/ +void jpeg_decode_PS(usf_state_t* state) +{ + jpeg_decode_std(state, "PS", NULL, NULL, EmitRGBATileLine); +} + +/*************************************************************************** + * JPEG decoding ucode found in Ogre Battle and Bottom of the 9th. + **************************************************************************/ +void jpeg_decode_OB(usf_state_t* state) +{ + int16_t qtable[SUBBLOCK_SIZE]; + unsigned int mb; + + int32_t y_dc = 0; + int32_t u_dc = 0; + int32_t v_dc = 0; + + uint32_t address = *dmem_u32(state, TASK_DATA_PTR); + const unsigned int macroblock_count = *dmem_u32(state, TASK_DATA_SIZE); + const int qscale = *dmem_u32(state, TASK_YIELD_DATA_SIZE); + + DebugMessage(state, + M64MSG_VERBOSE, "jpeg_decode_OB: *buffer=%x, #MB=%d, qscale=%d", + address, + macroblock_count, + qscale); + + 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]; + + dram_load_u16(state, (uint16_t *)macroblock, address, 6 * SUBBLOCK_SIZE); + decode_macroblock_ob(macroblock, &y_dc, &u_dc, &v_dc, (qscale != 0) ? qtable : NULL); + EmitTilesMode2(state, EmitYUVTileLine, macroblock, address); + + address += (2 * 6 * SUBBLOCK_SIZE); + } +} + + +/* local functions */ +static void jpeg_decode_std(usf_state_t* state, + 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; + uint32_t address; + uint32_t macroblock_count; + uint32_t mode; + uint32_t qtableY_ptr; + uint32_t qtableU_ptr; + uint32_t qtableV_ptr; + unsigned int subblock_count; + unsigned int macroblock_size; + /* macroblock contains at most 6 subblocks */ + int16_t macroblock[6 * SUBBLOCK_SIZE]; + uint32_t data_ptr; + + if (*dmem_u32(state, TASK_FLAGS) & 0x1) { + DebugMessage(state, M64MSG_WARNING, "jpeg_decode_%s: task yielding not implemented", version); + return; + } + + data_ptr = *dmem_u32(state, TASK_DATA_PTR); + address = *dram_u32(state, data_ptr); + macroblock_count = *dram_u32(state, data_ptr + 4); + mode = *dram_u32(state, data_ptr + 8); + qtableY_ptr = *dram_u32(state, data_ptr + 12); + qtableU_ptr = *dram_u32(state, data_ptr + 16); + qtableV_ptr = *dram_u32(state, data_ptr + 20); + + DebugMessage(state, 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); + + if (mode != 0 && mode != 2) { + DebugMessage(state, M64MSG_WARNING, "jpeg_decode_%s: invalid mode %d", version, mode); + return; + } + + subblock_count = mode + 4; + macroblock_size = subblock_count * SUBBLOCK_SIZE; + + dram_load_u16(state, (uint16_t *)qtables[0], qtableY_ptr, SUBBLOCK_SIZE); + dram_load_u16(state, (uint16_t *)qtables[1], qtableU_ptr, SUBBLOCK_SIZE); + dram_load_u16(state, (uint16_t *)qtables[2], qtableV_ptr, SUBBLOCK_SIZE); + + for (mb = 0; mb < macroblock_count; ++mb) { + dram_load_u16(state, (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(state, emit_line, macroblock, address); + else + EmitTilesMode2(state, emit_line, macroblock, address); + + address += 2 * macroblock_size; + } +} + +static uint8_t clamp_u8(int16_t x) +{ + return (x & (0xff00)) ? ((-x) >> 15) & 0xff : x; +} + +static int16_t clamp_s12(int16_t x) +{ + 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; + 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); +} + +static uint16_t GetRGBA(int16_t y, int16_t u, int16_t v) +{ + const float fY = (float)y + 2048.0f; + 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)); + + return (r << 4) | (g >> 1) | (b >> 6) | 1; +} + +static void EmitYUVTileLine(usf_state_t* state, 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; + + uyvy[0] = GetUYVY(y[0], y[1], u[0], v[0]); + uyvy[1] = GetUYVY(y[2], y[3], u[1], v[1]); + uyvy[2] = GetUYVY(y[4], y[5], u[2], v[2]); + uyvy[3] = GetUYVY(y[6], y[7], u[3], v[3]); + uyvy[4] = GetUYVY(y2[0], y2[1], u[4], v[4]); + uyvy[5] = GetUYVY(y2[2], y2[3], u[5], v[5]); + uyvy[6] = GetUYVY(y2[4], y2[5], u[6], v[6]); + uyvy[7] = GetUYVY(y2[6], y2[7], u[7], v[7]); + + dram_store_u32(state, uyvy, address, 8); +} + +static void EmitRGBATileLine(usf_state_t* state, 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; + + rgba[0] = GetRGBA(y[0], u[0], v[0]); + rgba[1] = GetRGBA(y[1], u[0], v[0]); + rgba[2] = GetRGBA(y[2], u[1], v[1]); + rgba[3] = GetRGBA(y[3], u[1], v[1]); + rgba[4] = GetRGBA(y[4], u[2], v[2]); + rgba[5] = GetRGBA(y[5], u[2], v[2]); + rgba[6] = GetRGBA(y[6], u[3], v[3]); + rgba[7] = GetRGBA(y[7], u[3], v[3]); + rgba[8] = GetRGBA(y2[0], u[4], v[4]); + rgba[9] = GetRGBA(y2[1], u[4], v[4]); + rgba[10] = GetRGBA(y2[2], u[5], v[5]); + rgba[11] = GetRGBA(y2[3], u[5], v[5]); + rgba[12] = GetRGBA(y2[4], u[6], v[6]); + rgba[13] = GetRGBA(y2[5], u[6], v[6]); + rgba[14] = GetRGBA(y2[6], u[7], v[7]); + rgba[15] = GetRGBA(y2[7], u[7], v[7]); + + dram_store_u16(state, rgba, address, 16); +} + +static void EmitTilesMode0(usf_state_t* state, 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; + + for (i = 0; i < 8; ++i) { + emit_line(state, ¯oblock[y_offset], ¯oblock[u_offset], address); + + y_offset += 8; + u_offset += 8; + address += 32; + } +} + +static void EmitTilesMode2(usf_state_t* state, 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; + + for (i = 0; i < 8; ++i) { + emit_line(state, ¯oblock[y_offset], ¯oblock[u_offset], address); + emit_line(state, ¯oblock[y_offset + 8], ¯oblock[u_offset], address + 32); + + y_offset += (i == 3) ? SUBBLOCK_SIZE + 16 : 16; + u_offset += 8; + address += 64; + } +} + +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) { + 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; + } + + ZigZagSubBlock(tmp_sb, macroblock); + if (qtable != NULL) + MultSubBlocks(tmp_sb, tmp_sb, qtable, 0); + TransposeSubBlock(macroblock, tmp_sb); + InverseDCTSubBlock(macroblock, macroblock); + + macroblock += 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) { + 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) { + if (transform_chroma != NULL) + transform_chroma(macroblock, macroblock); + } else { + if (transform_luma != NULL) + transform_luma(macroblock, macroblock); + } + + macroblock += SUBBLOCK_SIZE; + } +} + +static void TransposeSubBlock(int16_t *dst, const int16_t *src) +{ + ReorderSubBlock(dst, src, TRANSPOSE_TABLE); +} + +static void ZigZagSubBlock(int16_t *dst, const int16_t *src) +{ + ReorderSubBlock(dst, src, ZIGZAG_TABLE); +} + +static void ReorderSubBlock(int16_t *dst, const int16_t *src, const unsigned int *table) +{ + unsigned int i; + + /* source and destination sublocks cannot overlap */ + assert(abs(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) { + int32_t v = src1[i] * src2[i]; + dst[i] = clamp_s16(v) << shift; + } +} + +static void ScaleSubBlock(int16_t *dst, const int16_t *src, int16_t scale) +{ + unsigned int i; + + for (i = 0; i < SUBBLOCK_SIZE; ++i) { + int32_t v = src[i] * scale; + dst[i] = clamp_s16(v); + } +} + +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; +} + +/*************************************************************************** + * Fast 2D IDCT using separable formulation and normalization + * Computations use single precision floats + * 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) +{ + float e[4]; + float f[4]; + float x26, x1357, x15, x37, x17, x35; + + x15 = IDCT_K[2] * (x[1] + x[5]); + x37 = IDCT_K[3] * (x[3] + x[7]); + x17 = IDCT_K[8] * (x[1] + x[7]); + x35 = IDCT_K[9] * (x[3] + x[5]); + x1357 = IDCT_C3 * (x[1] + x[3] + x[5] + x[7]); + x26 = IDCT_C6 * (x[2] + x[6]); + + 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]; + + 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]; +} + +static void InverseDCTSubBlock(int16_t *dst, const int16_t *src) +{ + float x[8]; + float block[SUBBLOCK_SIZE]; + unsigned int i, j; + + /* idct 1d on rows (+transposition) */ + for (i = 0; i < 8; ++i) { + for (j = 0; j < 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); + + /* C4 = 1 normalization implies a division by 8 */ + for (j = 0; j < 8; ++j) + dst[i + j * 8] = (int16_t)x[j] >> 3; + } +} + +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) +{ + unsigned int i; + + for (i = 0; i < SUBBLOCK_SIZE; ++i) + dst[i] = (((int)clamp_s12(src[i]) * 0xe00) >> 16) + 0x80; +} + diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/jpeg.h b/Frameworks/lazyusf/lazyusf/rsp_hle/jpeg.h new file mode 100644 index 000000000..32eb381b6 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/jpeg.h @@ -0,0 +1,30 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-rsp-hle - jpeg.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2012 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 JPEG_H +#define JPEG_H + +void jpeg_decode_PS0(usf_state_t* state); +void jpeg_decode_PS(usf_state_t* state); +void jpeg_decode_OB(usf_state_t* state); + +#endif + diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/main_hle.c b/Frameworks/lazyusf/lazyusf/rsp_hle/main_hle.c new file mode 100644 index 000000000..9588cce11 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/main_hle.c @@ -0,0 +1,393 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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 +#include + +#ifdef ENABLE_TASK_DUMP +#include +#endif + +#include "../usf.h" + +#include "memory_hle.h" +#include "plugin_hle.h" + +#include "alist.h" +#include "cicx105.h" +#include "jpeg.h" +#include "musyx.h" + +#include "../exception.h" +#include "../registers.h" + +#include "../usf_internal.h" + +#define min(a,b) (((a) < (b)) ? (a) : (b)) + +#define SP_STATUS_INTR_ON_BREAK 0x40 +#define SP_STATUS_TASKDONE 0x200 + +/* 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(usf_state_t* state); +static void rsp_break(usf_state_t* state, unsigned int setbits); +static void forward_gfx_task(usf_state_t* state); +static void forward_audio_task(usf_state_t* state); +static void show_cfb(usf_state_t* state); +static bool try_fast_audio_dispatching(usf_state_t* state); +static bool try_fast_task_dispatching(usf_state_t* state); +static void normal_task_dispatching(usf_state_t* state); +static void non_task_dispatching(usf_state_t* state); + +#ifdef ENABLE_TASK_DUMP +static void dump_binary(usf_state_t* state, const char *const filename, const unsigned char *const bytes, + unsigned int size); +static void dump_task(usf_state_t* state, const char *const filename); +static void dump_unknown_task(usf_state_t* state, unsigned int sum); +static void dump_unknown_non_task(usf_state_t* state, unsigned int sum); +#endif + +/* local variables */ +static const bool FORWARD_AUDIO = false, FORWARD_GFX = true; + +/* Global functions */ +void hle_execute(usf_state_t* state) +{ + if (is_task(state)) { + if (!try_fast_task_dispatching(state)) + normal_task_dispatching(state); + rsp_break(state, SP_STATUS_TASKDONE); + } else { + non_task_dispatching(state); + rsp_break(state, 0); + } +} + +/* 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(usf_state_t* state) +{ + return (*dmem_u32(state, TASK_UCODE_BOOT_SIZE) <= 0x1000); +} + +static void rsp_break(usf_state_t* state, unsigned int setbits) +{ + SP_STATUS_REG |= setbits | SP_STATUS_BROKE | SP_STATUS_HALT; + + if ((SP_STATUS_REG & SP_STATUS_INTR_ON_BREAK)) { + MI_INTR_REG |= MI_INTR_SP; + CheckInterrupts(state); + } +} + +static bool try_fast_audio_dispatching(usf_state_t* state) +{ + /* identify audio ucode by using the content of ucode_data */ + uint32_t ucode_data = *dmem_u32(state, TASK_UCODE_DATA); + uint32_t v; + + if (*dram_u32(state, ucode_data) == 0x00000001) { + if (*dram_u32(state, ucode_data + 0x30) == 0xf0000f00) { + v = *dram_u32(state, ucode_data + 0x28); + switch(v) + { + case 0x1e24138c: /* audio ABI (most common) */ + alist_process_audio(state); return true; + case 0x1dc8138c: /* GoldenEye */ + alist_process_audio_ge(state); return true; + case 0x1e3c1390: /* BlastCorp, DiddyKongRacing */ + alist_process_audio_bc(state); return true; + default: + DebugMessage(state, M64MSG_WARNING, "ABI1 identification regression: v=%08x", v); + } + } else { + v = *dram_u32(state, ucode_data + 0x10); + switch(v) + { + case 0x11181350: /* MarioKart, WaveRace (E) */ + alist_process_nead_mk(state); return true; + case 0x111812e0: /* StarFox (J) */ + alist_process_nead_sfj(state); return true; + case 0x110412ac: /* WaveRace (J RevB) */ + alist_process_nead_wrjb(state); return true; + case 0x110412cc: /* StarFox/LylatWars (except J) */ + alist_process_nead_sf(state); return true; + case 0x1cd01250: /* FZeroX */ + alist_process_nead_fz(state); return true; + case 0x1f08122c: /* YoshisStory */ + alist_process_nead_ys(state); return true; + case 0x1f38122c: /* 1080° Snowboarding */ + alist_process_nead_1080(state); return true; + case 0x1f681230: /* Zelda OoT / Zelda MM (J, J RevA) */ + alist_process_nead_oot(state); return true; + case 0x1f801250: /* Zelda MM (except J, J RevA, E Beta), PokemonStadium 2 */ + alist_process_nead_mm(state); return true; + case 0x109411f8: /* Zelda MM (E Beta) */ + alist_process_nead_mmb(state); return true; + case 0x1eac11b8: /* AnimalCrossing */ + alist_process_nead_ac(state); return true; + case 0x00010010: /* MusyX v2 (IndianaJones, BattleForNaboo) */ + musyx_v2_task(state); return true; + + default: + DebugMessage(state, M64MSG_WARNING, "ABI2 identification regression: v=%08x", v); + } + } + } else { + v = *dram_u32(state, ucode_data + 0x10); + switch(v) + { + case 0x00000001: /* MusyX v1 + RogueSquadron, ResidentEvil2, PolarisSnoCross, + TheWorldIsNotEnough, RugratsInParis, NBAShowTime, + HydroThunder, Tarzan, GauntletLegend, Rush2049 */ + musyx_v1_task(state); return true; + case 0x0000127c: /* naudio (many games) */ + alist_process_naudio(state); return true; + case 0x00001280: /* BanjoKazooie */ + alist_process_naudio_bk(state); return true; + case 0x1c58126c: /* DonkeyKong */ + alist_process_naudio_dk(state); return true; + case 0x1ae8143c: /* BanjoTooie, JetForceGemini, MickeySpeedWayUSA, PerfectDark */ + alist_process_naudio_mp3(state); return true; + case 0x1ab0140c: /* ConkerBadFurDay */ + alist_process_naudio_cbfd(state); return true; + + default: + DebugMessage(state, M64MSG_WARNING, "ABI3 identification regression: v=%08x", v); + } + } + + return false; +} + +static bool try_fast_task_dispatching(usf_state_t* state) +{ + /* identify task ucode by its type */ + switch (*dmem_u32(state, TASK_TYPE)) { + case 1: + /*if (FORWARD_GFX) { + forward_gfx_task(); + return true; + }*/ + break; + + case 2: + /*if (FORWARD_AUDIO) { + forward_audio_task(); + return true; + } else*/ if (try_fast_audio_dispatching(state)) + return true; + break; + + case 7: + /*show_cfb();*/ + return true; + } + + return false; +} + +static void normal_task_dispatching(usf_state_t* state) +{ + const unsigned int sum = + sum_bytes((void*)dram_u32(state, *dmem_u32(state, TASK_UCODE)), min(*dmem_u32(state, 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(state); + return; + + /* JPEG: found in Zelda Ocarina of Time, Pokemon Stadium 1, Pokemon Stadium 2 */ + case 0x2caa6: + jpeg_decode_PS(state); + return; + + /* JPEG: found in Ogre Battle, Bottom of the 9th */ + case 0x130de: + case 0x278b0: + jpeg_decode_OB(state); + return; + } + + DebugMessage(state, M64MSG_WARNING, "unknown OSTask: sum: %x PC:%x", sum, SP_PC_REG); +#ifdef ENABLE_TASK_DUMP + dump_unknown_task(state, sum); +#endif +} + +static void non_task_dispatching(usf_state_t* state) +{ + const unsigned int sum = sum_bytes(state->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(state); + return; + } + + DebugMessage(state, M64MSG_WARNING, "unknown RSP code: sum: %x PC:%x", sum, SP_PC_REG); +#ifdef ENABLE_TASK_DUMP + dump_unknown_non_task(state, sum); +#endif +} + + +#ifdef ENABLE_TASK_DUMP +static void dump_unknown_task(usf_state_t* state, unsigned int sum) +{ + char filename[256]; + uint32_t ucode = *dmem_u32(state, TASK_UCODE); + uint32_t ucode_data = *dmem_u32(state, TASK_UCODE_DATA); + uint32_t data_ptr = *dmem_u32(state, TASK_DATA_PTR); + + sprintf(&filename[0], "task_%x.log", sum); + dump_task(state, filename); + + /* dump ucode_boot */ + sprintf(&filename[0], "ucode_boot_%x.bin", sum); + dump_binary(state, filename, (void*)dram_u32(state, *dmem_u32(state, TASK_UCODE_BOOT)), *dmem_u32(state, TASK_UCODE_BOOT_SIZE)); + + /* dump ucode */ + if (ucode != 0) { + sprintf(&filename[0], "ucode_%x.bin", sum); + dump_binary(state, filename, (void*)dram_u32(state, ucode), 0xf80); + } + + /* dump ucode_data */ + if (ucode_data != 0) { + sprintf(&filename[0], "ucode_data_%x.bin", sum); + dump_binary(state, filename, (void*)dram_u32(state, ucode_data), *dmem_u32(state, TASK_UCODE_DATA_SIZE)); + } + + /* dump data */ + if (data_ptr != 0) { + sprintf(&filename[0], "data_%x.bin", sum); + dump_binary(state, filename, (void*)dram_u32(state, data_ptr), *dmem_u32(state, TASK_DATA_SIZE)); + } +} + +static void dump_unknown_non_task(usf_state_t* state, unsigned int sum) +{ + char filename[256]; + + /* dump IMEM & DMEM for further analysis */ + sprintf(&filename[0], "imem_%x.bin", sum); + dump_binary(state, filename, state->IMEM, 0x1000); + + sprintf(&filename[0], "dmem_%x.bin", sum); + dump_binary(state, filename, state->DMEM, 0x1000); +} + +static void dump_binary(usf_state_t* state, 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(state, M64MSG_ERROR, "Writing error on %s", filename); + fclose(f); + } else + DebugMessage(state, M64MSG_ERROR, "Couldn't open %s for writing !", filename); + } else + fclose(f); +} + +static void dump_task(usf_state_t* state, 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(state, TASK_TYPE), + *dmem_u32(state, TASK_FLAGS), + *dmem_u32(state, TASK_UCODE_BOOT), *dmem_u32(state, TASK_UCODE_BOOT_SIZE), + *dmem_u32(state, TASK_UCODE), *dmem_u32(state, TASK_UCODE_SIZE), + *dmem_u32(state, TASK_UCODE_DATA), *dmem_u32(state, TASK_UCODE_DATA_SIZE), + *dmem_u32(state, TASK_DRAM_STACK), *dmem_u32(state, TASK_DRAM_STACK_SIZE), + *dmem_u32(state, TASK_OUTPUT_BUFF), *dmem_u32(state, TASK_OUTPUT_BUFF_SIZE), + *dmem_u32(state, TASK_DATA_PTR), *dmem_u32(state, TASK_DATA_SIZE), + *dmem_u32(state, TASK_YIELD_DATA_PTR), *dmem_u32(state, TASK_YIELD_DATA_SIZE)); + fclose(f); + } else + fclose(f); +} +#endif diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/main_hle.h b/Frameworks/lazyusf/lazyusf/rsp_hle/main_hle.h new file mode 100644 index 000000000..4c5ebd6c6 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/main_hle.h @@ -0,0 +1,28 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-rsp-hle - main.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * 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 MAIN_H +#define MAIN_H + +void hle_execute(usf_state_t* state); + +#endif + diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/memory_hle.c b/Frameworks/lazyusf/lazyusf/rsp_hle/memory_hle.c new file mode 100644 index 000000000..52f442479 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/memory_hle.c @@ -0,0 +1,127 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-rsp-hle - memory.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * 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 + +#include "../usf.h" + +#include "memory_hle.h" + +#include "../usf_internal.h" + +/* Global functions */ +void dmem_load_u8 (usf_state_t* state, uint8_t* dst, uint16_t address, size_t count) +{ + while (count != 0) { + *(dst++) = *dmem_u8(state, address); + address += 1; + --count; + } +} + +void dmem_load_u16(usf_state_t* state, uint16_t* dst, uint16_t address, size_t count) +{ + while (count != 0) { + *(dst++) = *dmem_u16(state, address); + address += 2; + --count; + } +} + +void dmem_load_u32(usf_state_t* state, uint32_t* dst, uint16_t address, size_t count) +{ + /* Optimization for uint32_t */ + memcpy(dst, dmem_u32(state, address), count * sizeof(uint32_t)); +} + +void dmem_store_u8 (usf_state_t* state, const uint8_t* src, uint16_t address, size_t count) +{ + while (count != 0) { + *dmem_u8(state, address) = *(src++); + address += 1; + --count; + } +} + +void dmem_store_u16(usf_state_t* state, const uint16_t* src, uint16_t address, size_t count) +{ + while (count != 0) { + *dmem_u16(state, address) = *(src++); + address += 2; + --count; + } +} + +void dmem_store_u32(usf_state_t* state, const uint32_t* src, uint16_t address, size_t count) +{ + /* Optimization for uint32_t */ + memcpy(dmem_u32(state, address), src, count * sizeof(uint32_t)); +} + + +void dram_load_u8 (usf_state_t* state, uint8_t* dst, uint32_t address, size_t count) +{ + while (count != 0) { + *(dst++) = *dram_u8(state, address); + address += 1; + --count; + } +} + +void dram_load_u16(usf_state_t* state, uint16_t* dst, uint32_t address, size_t count) +{ + while (count != 0) { + *(dst++) = *dram_u16(state, address); + address += 2; + --count; + } +} + +void dram_load_u32(usf_state_t* state, uint32_t* dst, uint32_t address, size_t count) +{ + /* Optimization for uint32_t */ + memcpy(dst, dram_u32(state, address), count * sizeof(uint32_t)); +} + +void dram_store_u8 (usf_state_t* state, const uint8_t* src, uint32_t address, size_t count) +{ + while (count != 0) { + *dram_u8(state, address) = *(src++); + address += 1; + --count; + } +} + +void dram_store_u16(usf_state_t* state, const uint16_t* src, uint32_t address, size_t count) +{ + while (count != 0) { + *dram_u16(state, address) = *(src++); + address += 2; + --count; + } +} + +void dram_store_u32(usf_state_t* state, const uint32_t* src, uint32_t address, size_t count) +{ + /* Optimization for uint32_t */ + memcpy(dram_u32(state, address), src, count * sizeof(uint32_t)); +} + diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/memory_hle.h b/Frameworks/lazyusf/lazyusf/rsp_hle/memory_hle.h new file mode 100644 index 000000000..ead24a5e9 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/memory_hle.h @@ -0,0 +1,118 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-rsp-hle - memory.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * 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 +#include +#include + +#include "../usf.h" +#include "../usf_internal.h" + +#include "plugin_hle.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* const dmem_u8(usf_state_t* state, uint16_t address) +{ + return (uint8_t*)(&state->DMEM[(address & 0xfff) ^ S8]); +} + +static inline uint16_t* const dmem_u16(usf_state_t* state, uint16_t address) +{ + assert((address & 1) == 0); + return (uint16_t*)(&state->DMEM[(address & 0xfff) ^ S16]); +} + +static inline uint32_t* const dmem_u32(usf_state_t* state, uint16_t address) +{ + assert((address & 3) == 0); + return (uint32_t*)(&state->DMEM[(address & 0xfff)]); +} + +static inline uint8_t* const dram_u8(usf_state_t* state, uint32_t address) +{ + return (uint8_t*)&state->N64MEM[(address & 0xffffff) ^ S8]; +} + +static inline uint16_t* const dram_u16(usf_state_t* state, uint32_t address) +{ + assert((address & 1) == 0); + return (uint16_t*)&state->N64MEM[(address & 0xffffff) ^ S16]; +} + +static inline uint32_t* const dram_u32(usf_state_t* state, uint32_t address) +{ + assert((address & 3) == 0); + return (uint32_t*)&state->N64MEM[address & 0xffffff]; +} + +void dmem_load_u8 (usf_state_t* state, uint8_t* dst, uint16_t address, size_t count); +void dmem_load_u16(usf_state_t* state, uint16_t* dst, uint16_t address, size_t count); +void dmem_load_u32(usf_state_t* state, uint32_t* dst, uint16_t address, size_t count); +void dmem_store_u8 (usf_state_t* state, const uint8_t* src, uint16_t address, size_t count); +void dmem_store_u16(usf_state_t* state, const uint16_t* src, uint16_t address, size_t count); +void dmem_store_u32(usf_state_t* state, const uint32_t* src, uint16_t address, size_t count); + +void dram_load_u8 (usf_state_t* state, uint8_t* dst, uint32_t address, size_t count); +void dram_load_u16(usf_state_t* state, uint16_t* dst, uint32_t address, size_t count); +void dram_load_u32(usf_state_t* state, uint32_t* dst, uint32_t address, size_t count); +void dram_store_u8 (usf_state_t* state, const uint8_t* src, uint32_t address, size_t count); +void dram_store_u16(usf_state_t* state, const uint16_t* src, uint32_t address, size_t count); +void dram_store_u32(usf_state_t* state, const uint32_t* src, uint32_t address, size_t count); + +#endif + diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/mp3.c b/Frameworks/lazyusf/lazyusf/rsp_hle/mp3.c new file mode 100644 index 000000000..220dfb34d --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/mp3.c @@ -0,0 +1,702 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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 +#include + +#include "../usf.h" + +#include "memory_hle.h" +#include "plugin_hle.h" + +#include "../usf_internal.h" + +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(usf_state_t* state) +{ + /* 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++) { + state->mp3_v[16 + i] = state->mp3_v[0 + i] + state->mp3_v[8 + i]; + state->mp3_v[24 + i] = ((state->mp3_v[0 + i] - state->mp3_v[8 + i]) * LUT2[i]) >> 0x10; + } + + /* Part 3: 4-wide butterflies */ + + for (i = 0; i < 4; i++) { + state->mp3_v[0 + i] = state->mp3_v[16 + i] + state->mp3_v[20 + i]; + state->mp3_v[4 + i] = ((state->mp3_v[16 + i] - state->mp3_v[20 + i]) * LUT3[i]) >> 0x10; + + state->mp3_v[8 + i] = state->mp3_v[24 + i] + state->mp3_v[28 + i]; + state->mp3_v[12 + i] = ((state->mp3_v[24 + i] - state->mp3_v[28 + i]) * LUT3[i]) >> 0x10; + } + + /* Part 4: 2-wide butterflies - 100% Accurate */ + + for (i = 0; i < 16; i += 4) { + state->mp3_v[16 + i] = state->mp3_v[0 + i] + state->mp3_v[2 + i]; + state->mp3_v[18 + i] = ((state->mp3_v[0 + i] - state->mp3_v[2 + i]) * 0xEC84) >> 0x10; + + state->mp3_v[17 + i] = state->mp3_v[1 + i] + state->mp3_v[3 + i]; + state->mp3_v[19 + i] = ((state->mp3_v[1 + i] - state->mp3_v[3 + i]) * 0x61F8) >> 0x10; + } +} + +static void InnerLoop(usf_state_t* state); + + +void MP3(usf_state_t* state, uint32_t w1, uint32_t w2) +{ + /* Initialization Code */ + uint32_t readPtr; /* s5 */ + uint32_t writePtr; /* s6 */ + uint32_t tmp; + int cnt, cnt2; + + /* I think these are temporary storage buffers */ + state->mp3_t6 = 0x08A0; + state->mp3_t5 = 0x0AC0; + state->mp3_t4 = (w1 & 0x1E); + + writePtr = w2 & 0xFFFFFF; + readPtr = writePtr; + /* Just do that for efficiency... may remove and use directly later anyway */ + memcpy(state->mp3data + 0xCE8, state->N64MEM + 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(state->mp3data + 0xCF0, state->N64MEM + readPtr, 0x180); + state->mp3_inPtr = 0xCF0; /* s7 */ + state->mp3_outPtr = 0xE70; /* s3 */ +/* --------------- Inner Loop Start -------------------- */ + for (cnt2 = 0; cnt2 < 0x180; cnt2 += 0x40) { + state->mp3_t6 &= 0xFFE0; + state->mp3_t5 &= 0xFFE0; + state->mp3_t6 |= state->mp3_t4; + state->mp3_t5 |= state->mp3_t4; + InnerLoop(state); + state->mp3_t4 = (state->mp3_t4 - 2) & 0x1E; + tmp = state->mp3_t6; + state->mp3_t6 = state->mp3_t5; + state->mp3_t5 = tmp; + state->mp3_inPtr += 0x40; + } +/* --------------- Inner Loop End -------------------- */ + memcpy(state->N64MEM + writePtr, state->mp3data + 0xe70, 0x180); + writePtr += 0x180; + readPtr += 0x180; + } +} + + + +static void InnerLoop(usf_state_t* state) +{ + /* 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; + + state->mp3_v[0] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x00 ^ S16)); + state->mp3_v[31] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x3E ^ S16)); + state->mp3_v[0] += state->mp3_v[31]; + state->mp3_v[1] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x02 ^ S16)); + state->mp3_v[30] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x3C ^ S16)); + state->mp3_v[1] += state->mp3_v[30]; + state->mp3_v[2] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x06 ^ S16)); + state->mp3_v[28] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x38 ^ S16)); + state->mp3_v[2] += state->mp3_v[28]; + state->mp3_v[3] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x04 ^ S16)); + state->mp3_v[29] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x3A ^ S16)); + state->mp3_v[3] += state->mp3_v[29]; + + state->mp3_v[4] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x0E ^ S16)); + state->mp3_v[24] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x30 ^ S16)); + state->mp3_v[4] += state->mp3_v[24]; + state->mp3_v[5] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x0C ^ S16)); + state->mp3_v[25] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x32 ^ S16)); + state->mp3_v[5] += state->mp3_v[25]; + state->mp3_v[6] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x08 ^ S16)); + state->mp3_v[27] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x36 ^ S16)); + state->mp3_v[6] += state->mp3_v[27]; + state->mp3_v[7] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x0A ^ S16)); + state->mp3_v[26] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x34 ^ S16)); + state->mp3_v[7] += state->mp3_v[26]; + + state->mp3_v[8] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x1E ^ S16)); + state->mp3_v[16] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x20 ^ S16)); + state->mp3_v[8] += state->mp3_v[16]; + state->mp3_v[9] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x1C ^ S16)); + state->mp3_v[17] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x22 ^ S16)); + state->mp3_v[9] += state->mp3_v[17]; + state->mp3_v[10] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x18 ^ S16)); + state->mp3_v[19] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x26 ^ S16)); + state->mp3_v[10] += state->mp3_v[19]; + state->mp3_v[11] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x1A ^ S16)); + state->mp3_v[18] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x24 ^ S16)); + state->mp3_v[11] += state->mp3_v[18]; + + state->mp3_v[12] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x10 ^ S16)); + state->mp3_v[23] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x2E ^ S16)); + state->mp3_v[12] += state->mp3_v[23]; + state->mp3_v[13] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x12 ^ S16)); + state->mp3_v[22] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x2C ^ S16)); + state->mp3_v[13] += state->mp3_v[22]; + state->mp3_v[14] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x16 ^ S16)); + state->mp3_v[20] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x28 ^ S16)); + state->mp3_v[14] += state->mp3_v[20]; + state->mp3_v[15] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x14 ^ S16)); + state->mp3_v[21] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x2A ^ S16)); + state->mp3_v[15] += state->mp3_v[21]; + + /* Part 2-4 */ + + MP3AB0(state); + + /* Part 5 - 1-Wide Butterflies - 100% Accurate but need SSVs!!! */ + + t0 = state->mp3_t6 + 0x100; + t1 = state->mp3_t6 + 0x200; + t2 = state->mp3_t5 + 0x100; + t3 = state->mp3_t5 + 0x200; + + /* 0x13A8 */ + state->mp3_v[1] = 0; + state->mp3_v[11] = ((state->mp3_v[16] - state->mp3_v[17]) * 0xB504) >> 0x10; + + state->mp3_v[16] = -state->mp3_v[16] - state->mp3_v[17]; + state->mp3_v[2] = state->mp3_v[18] + state->mp3_v[19]; + /* ** Store state->mp3_v[11] -> (T6 + 0)** */ + *(int16_t *)(state->mp3data + ((state->mp3_t6 + (short)0x0))) = (short)state->mp3_v[11]; + + + state->mp3_v[11] = -state->mp3_v[11]; + /* ** Store state->mp3_v[16] -> (T3 + 0)** */ + *(int16_t *)(state->mp3data + ((t3 + (short)0x0))) = (short)state->mp3_v[16]; + /* ** Store state->mp3_v[11] -> (T5 + 0)** */ + *(int16_t *)(state->mp3data + ((state->mp3_t5 + (short)0x0))) = (short)state->mp3_v[11]; + /* 0x13E8 - Verified.... */ + state->mp3_v[2] = -state->mp3_v[2]; + /* ** Store state->mp3_v[2] -> (T2 + 0)** */ + *(int16_t *)(state->mp3data + ((t2 + (short)0x0))) = (short)state->mp3_v[2]; + state->mp3_v[3] = (((state->mp3_v[18] - state->mp3_v[19]) * 0x16A09) >> 0x10) + state->mp3_v[2]; + /* ** Store state->mp3_v[3] -> (T0 + 0)** */ + *(int16_t *)(state->mp3data + ((t0 + (short)0x0))) = (short)state->mp3_v[3]; + /* 0x1400 - Verified */ + state->mp3_v[4] = -state->mp3_v[20] - state->mp3_v[21]; + state->mp3_v[6] = state->mp3_v[22] + state->mp3_v[23]; + state->mp3_v[5] = ((state->mp3_v[20] - state->mp3_v[21]) * 0x16A09) >> 0x10; + /* ** Store state->mp3_v[4] -> (T3 + 0xFF80) */ + *(int16_t *)(state->mp3data + ((t3 + (short)0xFF80))) = (short)state->mp3_v[4]; + state->mp3_v[7] = ((state->mp3_v[22] - state->mp3_v[23]) * 0x2D413) >> 0x10; + state->mp3_v[5] = state->mp3_v[5] - state->mp3_v[4]; + state->mp3_v[7] = state->mp3_v[7] - state->mp3_v[5]; + state->mp3_v[6] = state->mp3_v[6] + state->mp3_v[6]; + state->mp3_v[5] = state->mp3_v[5] - state->mp3_v[6]; + state->mp3_v[4] = -state->mp3_v[4] - state->mp3_v[6]; + /* *** Store state->mp3_v[7] -> (T1 + 0xFF80) */ + *(int16_t *)(state->mp3data + ((t1 + (short)0xFF80))) = (short)state->mp3_v[7]; + /* *** Store state->mp3_v[4] -> (T2 + 0xFF80) */ + *(int16_t *)(state->mp3data + ((t2 + (short)0xFF80))) = (short)state->mp3_v[4]; + /* *** Store state->mp3_v[5] -> (T0 + 0xFF80) */ + *(int16_t *)(state->mp3data + ((t0 + (short)0xFF80))) = (short)state->mp3_v[5]; + state->mp3_v[8] = state->mp3_v[24] + state->mp3_v[25]; + + + state->mp3_v[9] = ((state->mp3_v[24] - state->mp3_v[25]) * 0x16A09) >> 0x10; + state->mp3_v[2] = state->mp3_v[8] + state->mp3_v[9]; + state->mp3_v[11] = ((state->mp3_v[26] - state->mp3_v[27]) * 0x2D413) >> 0x10; + state->mp3_v[13] = ((state->mp3_v[28] - state->mp3_v[29]) * 0x2D413) >> 0x10; + + state->mp3_v[10] = state->mp3_v[26] + state->mp3_v[27]; + state->mp3_v[10] = state->mp3_v[10] + state->mp3_v[10]; + state->mp3_v[12] = state->mp3_v[28] + state->mp3_v[29]; + state->mp3_v[12] = state->mp3_v[12] + state->mp3_v[12]; + state->mp3_v[14] = state->mp3_v[30] + state->mp3_v[31]; + state->mp3_v[3] = state->mp3_v[8] + state->mp3_v[10]; + state->mp3_v[14] = state->mp3_v[14] + state->mp3_v[14]; + state->mp3_v[13] = (state->mp3_v[13] - state->mp3_v[2]) + state->mp3_v[12]; + state->mp3_v[15] = (((state->mp3_v[30] - state->mp3_v[31]) * 0x5A827) >> 0x10) - (state->mp3_v[11] + state->mp3_v[2]); + state->mp3_v[14] = -(state->mp3_v[14] + state->mp3_v[14]) + state->mp3_v[3]; + state->mp3_v[17] = state->mp3_v[13] - state->mp3_v[10]; + state->mp3_v[9] = state->mp3_v[9] + state->mp3_v[14]; + /* ** Store state->mp3_v[9] -> (T6 + 0x40) */ + *(int16_t *)(state->mp3data + ((state->mp3_t6 + (short)0x40))) = (short)state->mp3_v[9]; + state->mp3_v[11] = state->mp3_v[11] - state->mp3_v[13]; + /* ** Store state->mp3_v[17] -> (T0 + 0xFFC0) */ + *(int16_t *)(state->mp3data + ((t0 + (short)0xFFC0))) = (short)state->mp3_v[17]; + state->mp3_v[12] = state->mp3_v[8] - state->mp3_v[12]; + /* ** Store state->mp3_v[11] -> (T0 + 0x40) */ + *(int16_t *)(state->mp3data + ((t0 + (short)0x40))) = (short)state->mp3_v[11]; + state->mp3_v[8] = -state->mp3_v[8]; + /* ** Store state->mp3_v[15] -> (T1 + 0xFFC0) */ + *(int16_t *)(state->mp3data + ((t1 + (short)0xFFC0))) = (short)state->mp3_v[15]; + state->mp3_v[10] = -state->mp3_v[10] - state->mp3_v[12]; + /* ** Store state->mp3_v[12] -> (T2 + 0x40) */ + *(int16_t *)(state->mp3data + ((t2 + (short)0x40))) = (short)state->mp3_v[12]; + /* ** Store state->mp3_v[8] -> (T3 + 0xFFC0) */ + *(int16_t *)(state->mp3data + ((t3 + (short)0xFFC0))) = (short)state->mp3_v[8]; + /* ** Store state->mp3_v[14] -> (T5 + 0x40) */ + *(int16_t *)(state->mp3data + ((state->mp3_t5 + (short)0x40))) = (short)state->mp3_v[14]; + /* ** Store state->mp3_v[10] -> (T2 + 0xFFC0) */ + *(int16_t *)(state->mp3data + ((t2 + (short)0xFFC0))) = (short)state->mp3_v[10]; + /* 0x14FC - Verified... */ + + /* Part 6 - 100% Accurate */ + + state->mp3_v[0] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x00 ^ S16)); + state->mp3_v[31] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x3E ^ S16)); + state->mp3_v[0] -= state->mp3_v[31]; + state->mp3_v[1] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x02 ^ S16)); + state->mp3_v[30] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x3C ^ S16)); + state->mp3_v[1] -= state->mp3_v[30]; + state->mp3_v[2] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x06 ^ S16)); + state->mp3_v[28] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x38 ^ S16)); + state->mp3_v[2] -= state->mp3_v[28]; + state->mp3_v[3] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x04 ^ S16)); + state->mp3_v[29] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x3A ^ S16)); + state->mp3_v[3] -= state->mp3_v[29]; + + state->mp3_v[4] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x0E ^ S16)); + state->mp3_v[24] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x30 ^ S16)); + state->mp3_v[4] -= state->mp3_v[24]; + state->mp3_v[5] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x0C ^ S16)); + state->mp3_v[25] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x32 ^ S16)); + state->mp3_v[5] -= state->mp3_v[25]; + state->mp3_v[6] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x08 ^ S16)); + state->mp3_v[27] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x36 ^ S16)); + state->mp3_v[6] -= state->mp3_v[27]; + state->mp3_v[7] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x0A ^ S16)); + state->mp3_v[26] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x34 ^ S16)); + state->mp3_v[7] -= state->mp3_v[26]; + + state->mp3_v[8] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x1E ^ S16)); + state->mp3_v[16] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x20 ^ S16)); + state->mp3_v[8] -= state->mp3_v[16]; + state->mp3_v[9] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x1C ^ S16)); + state->mp3_v[17] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x22 ^ S16)); + state->mp3_v[9] -= state->mp3_v[17]; + state->mp3_v[10] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x18 ^ S16)); + state->mp3_v[19] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x26 ^ S16)); + state->mp3_v[10] -= state->mp3_v[19]; + state->mp3_v[11] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x1A ^ S16)); + state->mp3_v[18] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x24 ^ S16)); + state->mp3_v[11] -= state->mp3_v[18]; + + state->mp3_v[12] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x10 ^ S16)); + state->mp3_v[23] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x2E ^ S16)); + state->mp3_v[12] -= state->mp3_v[23]; + state->mp3_v[13] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x12 ^ S16)); + state->mp3_v[22] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x2C ^ S16)); + state->mp3_v[13] -= state->mp3_v[22]; + state->mp3_v[14] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x16 ^ S16)); + state->mp3_v[20] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x28 ^ S16)); + state->mp3_v[14] -= state->mp3_v[20]; + state->mp3_v[15] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x14 ^ S16)); + state->mp3_v[21] = *(int16_t *)(state->mp3data + state->mp3_inPtr + (0x2A ^ S16)); + state->mp3_v[15] -= state->mp3_v[21]; + + for (i = 0; i < 16; i++) + state->mp3_v[0 + i] = (state->mp3_v[0 + i] * LUT6[i]) >> 0x10; + state->mp3_v[0] = state->mp3_v[0] + state->mp3_v[0]; + state->mp3_v[1] = state->mp3_v[1] + state->mp3_v[1]; + state->mp3_v[2] = state->mp3_v[2] + state->mp3_v[2]; + state->mp3_v[3] = state->mp3_v[3] + state->mp3_v[3]; + state->mp3_v[4] = state->mp3_v[4] + state->mp3_v[4]; + state->mp3_v[5] = state->mp3_v[5] + state->mp3_v[5]; + state->mp3_v[6] = state->mp3_v[6] + state->mp3_v[6]; + state->mp3_v[7] = state->mp3_v[7] + state->mp3_v[7]; + state->mp3_v[12] = state->mp3_v[12] + state->mp3_v[12]; + state->mp3_v[13] = state->mp3_v[13] + state->mp3_v[13]; + state->mp3_v[15] = state->mp3_v[15] + state->mp3_v[15]; + + MP3AB0(state); + + /* Part 7: - 100% Accurate + SSV - Unoptimized */ + + state->mp3_v[0] = (state->mp3_v[17] + state->mp3_v[16]) >> 1; + state->mp3_v[1] = ((state->mp3_v[17] * (int)((short)0xA57E * 2)) + (state->mp3_v[16] * 0xB504)) >> 0x10; + state->mp3_v[2] = -state->mp3_v[18] - state->mp3_v[19]; + state->mp3_v[3] = ((state->mp3_v[18] - state->mp3_v[19]) * 0x16A09) >> 0x10; + state->mp3_v[4] = state->mp3_v[20] + state->mp3_v[21] + state->mp3_v[0]; + state->mp3_v[5] = (((state->mp3_v[20] - state->mp3_v[21]) * 0x16A09) >> 0x10) + state->mp3_v[1]; + state->mp3_v[6] = (((state->mp3_v[22] + state->mp3_v[23]) << 1) + state->mp3_v[0]) - state->mp3_v[2]; + state->mp3_v[7] = (((state->mp3_v[22] - state->mp3_v[23]) * 0x2D413) >> 0x10) + state->mp3_v[0] + state->mp3_v[1] + state->mp3_v[3]; + /* 0x16A8 */ + /* Save state->mp3_v[0] -> (T3 + 0xFFE0) */ + *(int16_t *)(state->mp3data + ((t3 + (short)0xFFE0))) = (short) - state->mp3_v[0]; + state->mp3_v[8] = state->mp3_v[24] + state->mp3_v[25]; + state->mp3_v[9] = ((state->mp3_v[24] - state->mp3_v[25]) * 0x16A09) >> 0x10; + state->mp3_v[10] = ((state->mp3_v[26] + state->mp3_v[27]) << 1) + state->mp3_v[8]; + state->mp3_v[11] = (((state->mp3_v[26] - state->mp3_v[27]) * 0x2D413) >> 0x10) + state->mp3_v[8] + state->mp3_v[9]; + state->mp3_v[12] = state->mp3_v[4] - ((state->mp3_v[28] + state->mp3_v[29]) << 1); + /* ** Store v12 -> (T2 + 0x20) */ + *(int16_t *)(state->mp3data + ((t2 + (short)0x20))) = (short)state->mp3_v[12]; + state->mp3_v[13] = (((state->mp3_v[28] - state->mp3_v[29]) * 0x2D413) >> 0x10) - state->mp3_v[12] - state->mp3_v[5]; + state->mp3_v[14] = state->mp3_v[30] + state->mp3_v[31]; + state->mp3_v[14] = state->mp3_v[14] + state->mp3_v[14]; + state->mp3_v[14] = state->mp3_v[14] + state->mp3_v[14]; + state->mp3_v[14] = state->mp3_v[6] - state->mp3_v[14]; + state->mp3_v[15] = (((state->mp3_v[30] - state->mp3_v[31]) * 0x5A827) >> 0x10) - state->mp3_v[7]; + /* Store v14 -> (T5 + 0x20) */ + *(int16_t *)(state->mp3data + ((state->mp3_t5 + (short)0x20))) = (short)state->mp3_v[14]; + state->mp3_v[14] = state->mp3_v[14] + state->mp3_v[1]; + /* Store state->mp3_v[14] -> (T6 + 0x20) */ + *(int16_t *)(state->mp3data + ((state->mp3_t6 + (short)0x20))) = (short)state->mp3_v[14]; + /* Store state->mp3_v[15] -> (T1 + 0xFFE0) */ + *(int16_t *)(state->mp3data + ((t1 + (short)0xFFE0))) = (short)state->mp3_v[15]; + state->mp3_v[9] = state->mp3_v[9] + state->mp3_v[10]; + state->mp3_v[1] = state->mp3_v[1] + state->mp3_v[6]; + state->mp3_v[6] = state->mp3_v[10] - state->mp3_v[6]; + state->mp3_v[1] = state->mp3_v[9] - state->mp3_v[1]; + /* Store state->mp3_v[6] -> (T5 + 0x60) */ + *(int16_t *)(state->mp3data + ((state->mp3_t5 + (short)0x60))) = (short)state->mp3_v[6]; + state->mp3_v[10] = state->mp3_v[10] + state->mp3_v[2]; + state->mp3_v[10] = state->mp3_v[4] - state->mp3_v[10]; + /* Store state->mp3_v[10] -> (T2 + 0xFFA0) */ + *(int16_t *)(state->mp3data + ((t2 + (short)0xFFA0))) = (short)state->mp3_v[10]; + state->mp3_v[12] = state->mp3_v[2] - state->mp3_v[12]; + /* Store state->mp3_v[12] -> (T2 + 0xFFE0) */ + *(int16_t *)(state->mp3data + ((t2 + (short)0xFFE0))) = (short)state->mp3_v[12]; + state->mp3_v[5] = state->mp3_v[4] + state->mp3_v[5]; + state->mp3_v[4] = state->mp3_v[8] - state->mp3_v[4]; + /* Store state->mp3_v[4] -> (T2 + 0x60) */ + *(int16_t *)(state->mp3data + ((t2 + (short)0x60))) = (short)state->mp3_v[4]; + state->mp3_v[0] = state->mp3_v[0] - state->mp3_v[8]; + /* Store state->mp3_v[0] -> (T3 + 0xFFA0) */ + *(int16_t *)(state->mp3data + ((t3 + (short)0xFFA0))) = (short)state->mp3_v[0]; + state->mp3_v[7] = state->mp3_v[7] - state->mp3_v[11]; + /* Store state->mp3_v[7] -> (T1 + 0xFFA0) */ + *(int16_t *)(state->mp3data + ((t1 + (short)0xFFA0))) = (short)state->mp3_v[7]; + state->mp3_v[11] = state->mp3_v[11] - state->mp3_v[3]; + /* Store state->mp3_v[1] -> (T6 + 0x60) */ + *(int16_t *)(state->mp3data + ((state->mp3_t6 + (short)0x60))) = (short)state->mp3_v[1]; + state->mp3_v[11] = state->mp3_v[11] - state->mp3_v[5]; + /* Store state->mp3_v[11] -> (T0 + 0x60) */ + *(int16_t *)(state->mp3data + ((t0 + (short)0x60))) = (short)state->mp3_v[11]; + state->mp3_v[3] = state->mp3_v[3] - state->mp3_v[13]; + /* Store state->mp3_v[3] -> (T0 + 0x20) */ + *(int16_t *)(state->mp3data + ((t0 + (short)0x20))) = (short)state->mp3_v[3]; + state->mp3_v[13] = state->mp3_v[13] + state->mp3_v[2]; + /* Store state->mp3_v[13] -> (T0 + 0xFFE0) */ + *(int16_t *)(state->mp3data + ((t0 + (short)0xFFE0))) = (short)state->mp3_v[13]; + state->mp3_v[2] = (state->mp3_v[5] - state->mp3_v[2]) - state->mp3_v[9]; + /* Store state->mp3_v[2] -> (T0 + 0xFFA0) */ + *(int16_t *)(state->mp3data + ((t0 + (short)0xFFA0))) = (short)state->mp3_v[2]; + /* 0x7A8 - Verified... */ + + /* Step 8 - Dewindowing */ + + addptr = state->mp3_t6 & 0xFFE0; + + offset = 0x10 - (state->mp3_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 *)(state->mp3data + (addptr) + 0x00) * (short)DeWindowLUT[offset + 0x00] + 0x4000) >> 0xF; + v4 += ((int) * (int16_t *)(state->mp3data + (addptr) + 0x10) * (short)DeWindowLUT[offset + 0x08] + 0x4000) >> 0xF; + v6 += ((int) * (int16_t *)(state->mp3data + (addptr) + 0x20) * (short)DeWindowLUT[offset + 0x20] + 0x4000) >> 0xF; + v8 += ((int) * (int16_t *)(state->mp3data + (addptr) + 0x30) * (short)DeWindowLUT[offset + 0x28] + 0x4000) >> 0xF; + addptr += 2; + offset++; + } + v0 = v2 + v4; + v18 = v6 + v8; + /* Clamp(v0); */ + /* Clamp(v18); */ + /* clamp??? */ + *(int16_t *)(state->mp3data + (state->mp3_outPtr ^ S16)) = v0; + *(int16_t *)(state->mp3data + ((state->mp3_outPtr + 2)^S16)) = v18; + state->mp3_outPtr += 4; + addptr += 0x30; + offset += 0x38; + } + + offset = 0x10 - (state->mp3_t4 >> 1) + 8 * 0x40; + v2 = v4 = 0; + for (i = 0; i < 4; i++) { + v2 += ((int) * (int16_t *)(state->mp3data + (addptr) + 0x00) * (short)DeWindowLUT[offset + 0x00] + 0x4000) >> 0xF; + v2 += ((int) * (int16_t *)(state->mp3data + (addptr) + 0x10) * (short)DeWindowLUT[offset + 0x08] + 0x4000) >> 0xF; + addptr += 2; + offset++; + v4 += ((int) * (int16_t *)(state->mp3data + (addptr) + 0x00) * (short)DeWindowLUT[offset + 0x00] + 0x4000) >> 0xF; + v4 += ((int) * (int16_t *)(state->mp3data + (addptr) + 0x10) * (short)DeWindowLUT[offset + 0x08] + 0x4000) >> 0xF; + addptr += 2; + offset++; + } + mult6 = *(int32_t *)(state->mp3data + 0xCE8); + mult4 = *(int32_t *)(state->mp3data + 0xCEC); + if (state->mp3_t4 & 0x2) { + v2 = (v2 **(uint32_t *)(state->mp3data + 0xCE8)) >> 0x10; + *(int16_t *)(state->mp3data + (state->mp3_outPtr ^ S16)) = v2; + } else { + v4 = (v4 **(uint32_t *)(state->mp3data + 0xCE8)) >> 0x10; + *(int16_t *)(state->mp3data + (state->mp3_outPtr ^ S16)) = v4; + mult4 = *(uint32_t *)(state->mp3data + 0xCE8); + } + addptr -= 0x50; + + for (x = 0; x < 8; x++) { + int32_t v0; + int32_t v18; + v2 = v4 = v6 = v8 = 0; + + offset = (0x22F - (state->mp3_t4 >> 1) + x * 0x40); + + for (i = 0; i < 4; i++) { + v2 += ((int) * (int16_t *)(state->mp3data + (addptr) + 0x20) * (short)DeWindowLUT[offset + 0x00] + 0x4000) >> 0xF; + v2 -= ((int) * (int16_t *)(state->mp3data + ((addptr + 2)) + 0x20) * (short)DeWindowLUT[offset + 0x01] + 0x4000) >> 0xF; + v4 += ((int) * (int16_t *)(state->mp3data + (addptr) + 0x30) * (short)DeWindowLUT[offset + 0x08] + 0x4000) >> 0xF; + v4 -= ((int) * (int16_t *)(state->mp3data + ((addptr + 2)) + 0x30) * (short)DeWindowLUT[offset + 0x09] + 0x4000) >> 0xF; + v6 += ((int) * (int16_t *)(state->mp3data + (addptr) + 0x00) * (short)DeWindowLUT[offset + 0x20] + 0x4000) >> 0xF; + v6 -= ((int) * (int16_t *)(state->mp3data + ((addptr + 2)) + 0x00) * (short)DeWindowLUT[offset + 0x21] + 0x4000) >> 0xF; + v8 += ((int) * (int16_t *)(state->mp3data + (addptr) + 0x10) * (short)DeWindowLUT[offset + 0x28] + 0x4000) >> 0xF; + v8 -= ((int) * (int16_t *)(state->mp3data + ((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 *)(state->mp3data + ((state->mp3_outPtr + 2)^S16)) = v0; + *(int16_t *)(state->mp3data + ((state->mp3_outPtr + 4)^S16)) = v18; + state->mp3_outPtr += 4; + addptr -= 0x50; + } + + tmp = state->mp3_outPtr; + hi0 = mult6; + hi1 = mult4; + + hi0 = (int)hi0 >> 0x10; + hi1 = (int)hi1 >> 0x10; + for (i = 0; i < 8; i++) { + /* v0 */ + vt = (*(int16_t *)(state->mp3data + ((tmp - 0x40)^S16)) * hi0); + if (vt > 32767) { + vt = 32767; + } else { + if (vt < -32767) + vt = -32767; + } + *(int16_t *)((uint8_t *)state->mp3data + ((tmp - 0x40)^S16)) = (int16_t)vt; + + /* v17 */ + vt = (*(int16_t *)(state->mp3data + ((tmp - 0x30)^S16)) * hi0); + if (vt > 32767) { + vt = 32767; + } else { + if (vt < -32767) + vt = -32767; + } + *(int16_t *)((uint8_t *)state->mp3data + ((tmp - 0x30)^S16)) = vt; + + /* v2 */ + vt = (*(int16_t *)(state->mp3data + ((tmp - 0x1E)^S16)) * hi1); + if (vt > 32767) { + vt = 32767; + } else { + if (vt < -32767) + vt = -32767; + } + *(int16_t *)((uint8_t *)state->mp3data + ((tmp - 0x1E)^S16)) = vt; + + /* v4 */ + vt = (*(int16_t *)(state->mp3data + ((tmp - 0xE)^S16)) * hi1); + if (vt > 32767) { + vt = 32767; + } else { + if (vt < -32767) + vt = -32767; + } + *(int16_t *)((uint8_t *)state->mp3data + ((tmp - 0xE)^S16)) = vt; + tmp += 2; + } +} + diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/musyx.c b/Frameworks/lazyusf/lazyusf/rsp_hle/musyx.c new file mode 100644 index 000000000..841b0d2fd --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/musyx.c @@ -0,0 +1,972 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-rsp-hle - musyx.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * 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 +#include +#include +#include + +#include "../usf.h" + +#include "arithmetics.h" +#include "memory_hle.h" +#include "plugin_hle.h" +#include "audio_hle.h" + +#include "../usf_internal.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(usf_state_t* state, int32_t *base_vol, uint32_t address); +static void save_base_vol(usf_state_t* state, const int32_t *base_vol, uint32_t address); +static void update_base_vol(usf_state_t* state, 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(usf_state_t* state, musyx_t *musyx, uint32_t voice_ptr, + uint32_t last_sample_ptr); + +static void dma_cat8(usf_state_t* state, uint8_t *dst, uint32_t catsrc_ptr); +static void dma_cat16(usf_state_t* state, uint16_t *dst, uint32_t catsrc_ptr); + +static void load_samples_PCM16(usf_state_t* state, uint32_t voice_ptr, int16_t *samples, + unsigned *segbase, unsigned *offset); +static void load_samples_ADPCM(usf_state_t* state, uint32_t voice_ptr, int16_t *samples, + unsigned *segbase, unsigned *offset); + +static void adpcm_decode_frames(usf_state_t* state, 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(usf_state_t* state, musyx_t *musyx, uint32_t voice_ptr, + const int16_t *samples, unsigned segbase, + unsigned offset, uint32_t last_sample_ptr); + +static void sfx_stage(usf_state_t* state, 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(usf_state_t* state, musyx_t *musyx, uint32_t output_ptr); + +static void interleave_stage_v2(usf_state_t* state, 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(usf_state_t* state) +{ + uint32_t sfd_ptr = *dmem_u32(state, TASK_DATA_PTR); + uint32_t sfd_count = *dmem_u32(state, TASK_DATA_SIZE); + uint32_t state_ptr; + musyx_t musyx; + + DebugMessage(state, M64MSG_VERBOSE, "musyx_v1_task: *data=%x, #SF=%d", + sfd_ptr, + sfd_count); + + state_ptr = *dram_u32(state, sfd_ptr + SFD_STATE_PTR); + + /* load initial state */ + load_base_vol(state, musyx.base_vol, state_ptr + STATE_BASE_VOL); + dram_load_u16(state, (uint16_t *)musyx.cc0, state_ptr + STATE_CC0, SUBFRAME_SIZE); + dram_load_u16(state, (uint16_t *)musyx.subframe_740_last4, state_ptr + STATE_740_LAST4_V1, + 4); + + for (;;) { + /* parse SFD structure */ + uint16_t sfx_index = *dram_u16(state, sfd_ptr + SFD_SFX_INDEX); + uint32_t voice_mask = *dram_u32(state, sfd_ptr + SFD_VOICE_BITMASK); + uint32_t sfx_ptr = *dram_u32(state, 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(state, 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(state, &musyx, voice_ptr, last_sample_ptr); + + /* apply delay-based effects (optional) */ + sfx_stage(state, mix_sfx_with_main_subframes_v1, + &musyx, sfx_ptr, sfx_index); + + /* emit interleaved L,R subframes */ + interleave_stage_v1(state, &musyx, output_ptr); + + --sfd_count; + if (sfd_count == 0) + break; + + sfd_ptr += SFD_VOICES + MAX_VOICES * VOICE_SIZE; + state_ptr = *dram_u32(state, sfd_ptr + SFD_STATE_PTR); + } + + /* writeback updated state */ + save_base_vol(state, musyx.base_vol, state_ptr + STATE_BASE_VOL); + dram_store_u16(state, (uint16_t *)musyx.cc0, state_ptr + STATE_CC0, SUBFRAME_SIZE); + dram_store_u16(state, (uint16_t *)musyx.subframe_740_last4, state_ptr + STATE_740_LAST4_V1, + 4); +} + +/************************************************************************** + * MusyX v2 audio ucode + **************************************************************************/ +void musyx_v2_task(usf_state_t* state) +{ + uint32_t sfd_ptr = *dmem_u32(state, TASK_DATA_PTR); + uint32_t sfd_count = *dmem_u32(state, TASK_DATA_SIZE); + musyx_t musyx; + + DebugMessage(state, M64MSG_VERBOSE, "musyx_v2_task: *data=%x, #SF=%d", + sfd_ptr, + sfd_count); + + for (;;) { + /* parse SFD structure */ + uint16_t sfx_index = *dram_u16(state, sfd_ptr + SFD_SFX_INDEX); + uint32_t voice_mask = *dram_u32(state, sfd_ptr + SFD_VOICE_BITMASK); + uint32_t state_ptr = *dram_u32(state, sfd_ptr + SFD_STATE_PTR); + uint32_t sfx_ptr = *dram_u32(state, sfd_ptr + SFD_SFX_PTR); + uint32_t voice_ptr = sfd_ptr + SFD2_VOICES; + + uint32_t ptr_10 = *dram_u32(state, sfd_ptr + SFD2_10_PTR); + uint8_t mask_14 = *dram_u8 (state, sfd_ptr + SFD2_14_BITMASK); + uint8_t mask_15 = *dram_u8 (state, sfd_ptr + SFD2_15_BITMASK); + uint16_t mask_16 = *dram_u16(state, sfd_ptr + SFD2_16_BITMASK); + uint32_t ptr_18 = *dram_u32(state, sfd_ptr + SFD2_18_PTR); + uint32_t ptr_1c = *dram_u32(state, sfd_ptr + SFD2_1C_PTR); + uint32_t ptr_20 = *dram_u32(state, sfd_ptr + SFD2_20_PTR); + uint32_t ptr_24 = *dram_u32(state, sfd_ptr + SFD2_24_PTR); + + uint32_t last_sample_ptr = state_ptr + STATE_LAST_SAMPLE; + uint32_t output_ptr; + + /* load state */ + load_base_vol(state, musyx.base_vol, state_ptr + STATE_BASE_VOL); + dram_load_u16(state, (uint16_t *)musyx.subframe_740_last4, + state_ptr + STATE_740_LAST4_V2, 4); + + /* initialize internal subframes using updated base volumes */ + update_base_vol(state, musyx.base_vol, voice_mask, last_sample_ptr, mask_15, ptr_24); + init_subframes_v2(&musyx); + + if (ptr_10) { + /* TODO */ + DebugMessage(state, M64MSG_WARNING, "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(state, &musyx, voice_ptr, last_sample_ptr); + + /* apply delay-based effects (optional) */ + sfx_stage(state, mix_sfx_with_main_subframes_v2, + &musyx, sfx_ptr, sfx_index); + + dram_store_u16(state, (uint16_t*)musyx.left, output_ptr , SUBFRAME_SIZE); + dram_store_u16(state, (uint16_t*)musyx.right, output_ptr + 2*SUBFRAME_SIZE, SUBFRAME_SIZE); + dram_store_u16(state, (uint16_t*)musyx.cc0, output_ptr + 4*SUBFRAME_SIZE, SUBFRAME_SIZE); + + /* store state */ + save_base_vol(state, musyx.base_vol, state_ptr + STATE_BASE_VOL); + dram_store_u16(state, (uint16_t*)musyx.subframe_740_last4, + state_ptr + STATE_740_LAST4_V2, 4); + + if (mask_16) + interleave_stage_v2(state, &musyx, mask_16, ptr_18, ptr_1c, ptr_20); + + --sfd_count; + if (sfd_count == 0) + break; + + sfd_ptr += SFD2_VOICES + MAX_VOICES * VOICE_SIZE; + } +} + + + + + +static void load_base_vol(usf_state_t* state, int32_t *base_vol, uint32_t address) +{ + base_vol[0] = ((uint32_t)(*dram_u16(state, address)) << 16) | (*dram_u16(state, address + 8)); + base_vol[1] = ((uint32_t)(*dram_u16(state, address + 2)) << 16) | (*dram_u16(state, address + 10)); + base_vol[2] = ((uint32_t)(*dram_u16(state, address + 4)) << 16) | (*dram_u16(state, address + 12)); + base_vol[3] = ((uint32_t)(*dram_u16(state, address + 6)) << 16) | (*dram_u16(state, address + 14)); +} + +static void save_base_vol(usf_state_t* state, const int32_t *base_vol, uint32_t address) +{ + unsigned k; + + for (k = 0; k < 4; ++k) { + *dram_u16(state, address) = (uint16_t)(base_vol[k] >> 16); + address += 2; + } + + for (k = 0; k < 4; ++k) { + *dram_u16(state, address) = (uint16_t)(base_vol[k]); + address += 2; + } +} + +static void update_base_vol(usf_state_t* state, 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; + + DebugMessage(state, M64MSG_VERBOSE, "base_vol voice_mask = %08x", voice_mask); + DebugMessage(state, M64MSG_VERBOSE, "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(state, 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(state, ptr_24 + k * 2); + } + } + + /* apply 3% decay */ + for (k = 0; k < 4; ++k) + base_vol[k] = (base_vol[k] * 0x0000f850) >> 16; + + DebugMessage(state, M64MSG_VERBOSE, "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] = { + clamp_s16(musyx->base_vol[0]), + clamp_s16(musyx->base_vol[1]), + clamp_s16(musyx->base_vol[2]), + clamp_s16(musyx->base_vol[3]) + }; + + int16_t* subframes[4] = { + musyx->left, + musyx->right, + musyx->cc0, + 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(usf_state_t* state, 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(state, voice_ptr + VOICE_CATSRC_0 + CATSRC_SIZE1) == 0) { + DebugMessage(state, M64MSG_VERBOSE, "Skipping Voice stage"); + output_ptr = *dram_u32(state, 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; + + DebugMessage(state, M64MSG_VERBOSE, "Processing Voice #%d", i); + + if (*dram_u8(state, voice_ptr + VOICE_ADPCM_FRAMES) == 0) + load_samples_PCM16(state, voice_ptr, samples, &segbase, &offset); + else + load_samples_ADPCM(state, voice_ptr, samples, &segbase, &offset); + + /* mix them with each internal subframes */ + mix_voice_samples(state, musyx, voice_ptr, samples, segbase, offset, + last_sample_ptr + i * 8); + + /* check break condition */ + output_ptr = *dram_u32(state, voice_ptr + VOICE_INTERLEAVED_PTR); + if (output_ptr != 0) + break; + + /* next voice */ + ++i; + voice_ptr += VOICE_SIZE; + } + } + + return output_ptr; +} + +static void dma_cat8(usf_state_t* state, uint8_t *dst, uint32_t catsrc_ptr) +{ + uint32_t ptr1 = *dram_u32(state, catsrc_ptr + CATSRC_PTR1); + uint32_t ptr2 = *dram_u32(state, catsrc_ptr + CATSRC_PTR2); + uint16_t size1 = *dram_u16(state, catsrc_ptr + CATSRC_SIZE1); + uint16_t size2 = *dram_u16(state, catsrc_ptr + CATSRC_SIZE2); + + size_t count1 = size1; + size_t count2 = size2; + + DebugMessage(state, M64MSG_VERBOSE, "dma_cat: %08x %08x %04x %04x", + ptr1, + ptr2, + size1, + size2); + + dram_load_u8(state, dst, ptr1, count1); + + if (size2 == 0) + return; + + dram_load_u8(state, dst + count1, ptr2, count2); +} + +static void dma_cat16(usf_state_t* state, uint16_t *dst, uint32_t catsrc_ptr) +{ + uint32_t ptr1 = *dram_u32(state, catsrc_ptr + CATSRC_PTR1); + uint32_t ptr2 = *dram_u32(state, catsrc_ptr + CATSRC_PTR2); + uint16_t size1 = *dram_u16(state, catsrc_ptr + CATSRC_SIZE1); + uint16_t size2 = *dram_u16(state, catsrc_ptr + CATSRC_SIZE2); + + size_t count1 = size1 >> 1; + size_t count2 = size2 >> 1; + + DebugMessage(state, M64MSG_VERBOSE, "dma_cat: %08x %08x %04x %04x", + ptr1, + ptr2, + size1, + size2); + + dram_load_u16(state, dst, ptr1, count1); + + if (size2 == 0) + return; + + dram_load_u16(state, dst + count1, ptr2, count2); +} + +static void load_samples_PCM16(usf_state_t* state, uint32_t voice_ptr, int16_t *samples, + unsigned *segbase, unsigned *offset) +{ + + uint8_t u8_3e = *dram_u8(state, voice_ptr + VOICE_SKIP_SAMPLES); + uint16_t u16_40 = *dram_u16(state, voice_ptr + VOICE_U16_40); + uint16_t u16_42 = *dram_u16(state, voice_ptr + VOICE_U16_42); + + unsigned count = align(u16_40 + u8_3e, 4); + + DebugMessage(state, M64MSG_VERBOSE, "Format: PCM16"); + + *segbase = SAMPLE_BUFFER_SIZE - count; + *offset = u8_3e; + + dma_cat16(state, (uint16_t *)samples + *segbase, voice_ptr + VOICE_CATSRC_0); + + if (u16_42 != 0) + dma_cat16(state, (uint16_t *)samples, voice_ptr + VOICE_CATSRC_1); +} + +static void load_samples_ADPCM(usf_state_t* state, 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(state, voice_ptr + VOICE_ADPCM_FRAMES ); + uint8_t u8_3d = *dram_u8(state, voice_ptr + VOICE_ADPCM_FRAMES + 1); + uint8_t u8_3e = *dram_u8(state, voice_ptr + VOICE_SKIP_SAMPLES ); + uint8_t u8_3f = *dram_u8(state, voice_ptr + VOICE_SKIP_SAMPLES + 1); + uint32_t adpcm_table_ptr = *dram_u32(state, voice_ptr + VOICE_ADPCM_TABLE_PTR); + unsigned count; + + DebugMessage(state, M64MSG_VERBOSE, "Format: ADPCM"); + + DebugMessage(state, M64MSG_VERBOSE, "Loading ADPCM table: %08x", adpcm_table_ptr); + dram_load_u16(state, (uint16_t *)adpcm_table, adpcm_table_ptr, 128); + + count = u8_3c << 5; + + *segbase = SAMPLE_BUFFER_SIZE - count; + *offset = u8_3e & 0x1f; + + dma_cat8(state, buffer, voice_ptr + VOICE_CATSRC_0); + adpcm_decode_frames(state, samples + *segbase, buffer, adpcm_table, u8_3c, u8_3e); + + if (u8_3d != 0) { + dma_cat8(state, buffer, voice_ptr + VOICE_CATSRC_1); + adpcm_decode_frames(state, samples, buffer, adpcm_table, u8_3d, u8_3f); + } +} + +static void adpcm_decode_frames(usf_state_t* state, 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; + + DebugMessage(state, M64MSG_VERBOSE, "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(usf_state_t* state, 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(state, voice_ptr + VOICE_PITCH_Q16); + const uint16_t pitch_shift = *dram_u16(state, voice_ptr + VOICE_PITCH_SHIFT); /* Q4.12 */ + + const uint16_t end_point = *dram_u16(state, voice_ptr + VOICE_END_POINT); + const uint16_t restart_point = *dram_u16(state, voice_ptr + VOICE_RESTART_POINT); + + const uint16_t u16_4e = *dram_u16(state, 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(state, (uint32_t *)v4_env, voice_ptr + VOICE_ENV_BEGIN, 4); + dram_load_u32(state, (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; + + DebugMessage(state, M64MSG_VERBOSE, + "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(state, (uint16_t *)v4, last_sample_ptr, 4); + + DebugMessage(state, M64MSG_VERBOSE, "last_sample = %04x %04x %04x %04x", + v4[0], v4[1], v4[2], v4[3]); +} + + +static void sfx_stage(usf_state_t* state, 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]; + + DebugMessage(state, M64MSG_VERBOSE, "SFX: %08x, idx=%d", sfx_ptr, idx); + + if (sfx_ptr == 0) + return; + + /* load sfx parameters */ + cbuffer_ptr = *dram_u32(state, sfx_ptr + SFX_CBUFFER_PTR); + cbuffer_length = *dram_u32(state, sfx_ptr + SFX_CBUFFER_LENGTH); + + tap_count = *dram_u16(state, sfx_ptr + SFX_TAP_COUNT); + + dram_load_u32(state, tap_delays, sfx_ptr + SFX_TAP_DELAYS, 8); + dram_load_u16(state, (uint16_t *)tap_gains, sfx_ptr + SFX_TAP_GAINS, 8); + + fir4_hgain = *dram_u16(state, sfx_ptr + SFX_FIR4_HGAIN); + dram_load_u16(state, (uint16_t *)fir4_hcoeffs, sfx_ptr + SFX_FIR4_HCOEFFS, 4); + + sfx_gains[0] = *dram_u16(state, sfx_ptr + SFX_U16_3C); + sfx_gains[1] = *dram_u16(state, sfx_ptr + SFX_U16_3E); + + DebugMessage(state, M64MSG_VERBOSE, "cbuffer: ptr=%08x length=%x", cbuffer_ptr, + cbuffer_length); + + DebugMessage(state, M64MSG_VERBOSE, "fir4: hgain=%04x hcoeff=%04x %04x %04x %04x", + fir4_hgain, fir4_hcoeffs[0], fir4_hcoeffs[1], fir4_hcoeffs[2], + fir4_hcoeffs[3]); + + DebugMessage(state, M64MSG_VERBOSE, + "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]); + + DebugMessage(state, M64MSG_VERBOSE, "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 (dpos + SUBFRAME_SIZE > cbuffer_length) { + dlength = cbuffer_length - dpos; + dram_load_u16(state, (uint16_t *)delayed + dlength, cbuffer_ptr, SUBFRAME_SIZE - dlength); + } + + dram_load_u16(state, (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(state, (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* 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(usf_state_t* state, 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; + + DebugMessage(state, M64MSG_VERBOSE, "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(state, 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(usf_state_t* state, 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; + + DebugMessage(state, M64MSG_VERBOSE, "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(state, 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(state, ptr_18); + hgain = *dram_u16(state, ptr_18 + 4); + + for(i = 0; i < SUBFRAME_SIZE; ++i, address += 2) { + mix_samples(&musyx->left[i], *dram_u16(state, address), hgain); + mix_samples(&musyx->right[i], *dram_u16(state, address + 2*SUBFRAME_SIZE), hgain); + mix_samples(&subframe[i], *dram_u16(state, address + 4*SUBFRAME_SIZE), hgain); + } + } + + /* interleave L_total and R_total */ + dst = dram_u32(state, 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(state, (uint16_t*)subframe, ptr_1c, SUBFRAME_SIZE); +} diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/musyx.h b/Frameworks/lazyusf/lazyusf/rsp_hle/musyx.h new file mode 100644 index 000000000..5b6fadd59 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/musyx.h @@ -0,0 +1,28 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-rsp-hle - musyx.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * 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. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef MUSYX_H +#define MUSYX_H + +void musyx_v1_task(usf_state_t* state); +void musyx_v2_task(usf_state_t* state); + +#endif diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/plugin_hle.c b/Frameworks/lazyusf/lazyusf/rsp_hle/plugin_hle.c new file mode 100644 index 000000000..ab8a9512c --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/plugin_hle.c @@ -0,0 +1,60 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-rsp-hle - plugin.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * 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 +#include +#include + +#include "../usf.h" + +#include "main_hle.h" +#include "plugin_hle.h" + +#include "../main.h" + +#include "../usf_internal.h" + +/* Global functions */ +void DebugMessage(usf_state_t* state, int level, const char *message, ...) +{ + char msgbuf[1024]; + va_list args; + size_t len; + + if ( level < M64MSG_WARNING ) + return; + + va_list ap; + + len = strlen( state->error_message ); + + if ( len ) + state->error_message[ len++ ] = '\n'; + + va_start( ap, message ); + vsprintf( state->error_message + len, message, ap ); + va_end( ap ); + + state->last_error = state->error_message; + StopEmulation( state ); +} diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/plugin_hle.h b/Frameworks/lazyusf/lazyusf/rsp_hle/plugin_hle.h new file mode 100644 index 000000000..d8c9dc867 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/plugin_hle.h @@ -0,0 +1,32 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-rsp-hle - plugin.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * 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 PLUGIN_H +#define PLUGIN_H + +#define M64MSG_VERBOSE 0 +#define M64MSG_WARNING 1 +#define M64MSG_ERROR 2 + +void DebugMessage(usf_state_t * state, int level, const char *message, ...); + +#endif + diff --git a/Frameworks/lazyusf/lazyusf/usf.c b/Frameworks/lazyusf/lazyusf/usf.c index 9d5d39244..c2baeb9fc 100644 --- a/Frameworks/lazyusf/lazyusf/usf.c +++ b/Frameworks/lazyusf/lazyusf/usf.c @@ -33,6 +33,8 @@ void usf_clear(void * state) //USF_STATE->enablecompare = 0; //USF_STATE->enableFIFOfull = 0; + //USF_STATE->enable_hle_audio = 0; + //USF_STATE->NextInstruction = 0; //USF_STATE->JumpToLocation = 0; //USF_STATE->AudioIntrReg = 0; @@ -80,6 +82,11 @@ void usf_set_fifo_full(void * state, int enable) USF_STATE->enableFIFOfull = enable; } +void usf_set_hle_audio(void * state, int enable) +{ + USF_STATE->enable_hle_audio = enable; +} + static uint32_t get_le32( const void * _p ) { const uint8_t * p = (const uint8_t *) _p; diff --git a/Frameworks/lazyusf/lazyusf/usf.h b/Frameworks/lazyusf/lazyusf/usf.h index 05ac5797e..654e66791 100644 --- a/Frameworks/lazyusf/lazyusf/usf.h +++ b/Frameworks/lazyusf/lazyusf/usf.h @@ -29,6 +29,10 @@ void usf_clear(void * state); _enablecompare or _enablefifofull tags are present in the file. */ void usf_set_compare(void * state, int enable); void usf_set_fifo_full(void * state, int enable); + +/* This option should speed up decoding significantly, at the expense + of accuracy, and potentially emulation bugs. */ +void usf_set_hle_audio(void * state, int enable); /* This processes and uploads the ROM and/or Project 64 save state data present in the reserved section of each USF file. They should be diff --git a/Frameworks/lazyusf/lazyusf/usf_internal.h b/Frameworks/lazyusf/lazyusf/usf_internal.h index 47368c32a..0470e8b05 100644 --- a/Frameworks/lazyusf/lazyusf/usf_internal.h +++ b/Frameworks/lazyusf/lazyusf/usf_internal.h @@ -13,6 +13,23 @@ struct usf_state_helper typedef uint32_t RCPREG; #endif +#include + +// rsp_hle/alist_audio.c +enum { DMEM_BASE = 0x5c0 }; +enum { N_SEGMENTS = 16 }; + +// rsp_hle/alist_naudio.c +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 +}; + struct usf_state { // RSP vector registers, need to be aligned to 16 bytes @@ -42,6 +59,14 @@ struct usf_state short comp[8]; /* $vcc: low byte (VEQ, VNE, VLT, VGE, VCL, VCH, VCR) */ short vce[8]; /* $vce: vector compare extension register */ + // rsp_hle/mp3.c, let's see if aligning this helps anything + uint8_t mp3data[0x1000]; + int32_t mp3_v[32]; + uint32_t mp3_inPtr, mp3_outPtr; + uint32_t mp3_t6;/* = 0x08A0; - I think these are temporary storage buffers */ + uint32_t mp3_t5;/* = 0x0AC0; */ + uint32_t mp3_t4;/* = (w1 & 0x1E); */ + // All further members of the structure need not be aligned // rsp/vu/divrom.h @@ -54,14 +79,91 @@ struct usf_state int DPH; // rsp/rsp.h + int stage; // unused since EMULATE_STATIC_PC is defined by default in rsp/config.h int temp_PC; short MFC0_count[32]; + // rsp_hle/alist.c + uint8_t BufferSpace[0x10000]; + + // rsp_hle/alist_audio.c + /* alist audio state */ + struct { + /* 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]; + } l_alist_audio; + + struct { + /* 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]; + } l_alist_naudio; + + struct { + /* 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]; + } l_alist_nead; + uint32_t cpu_running, cpu_stopped; // options from file tags uint32_t enablecompare, enableFIFOfull; + // options for decoding + uint32_t enable_hle_audio; + // buffering for rendered sample data size_t sample_buffer_count; int16_t * sample_buffer;