Added HLE audio to LazyUSF, disabled because it's incomplete

CQTexperiment
Chris Moeller 2014-03-04 21:39:37 -08:00
parent c75cfa27bd
commit 5b456915f3
28 changed files with 5792 additions and 0 deletions

View File

@ -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 = "<group>"; };
8378415518C6E56B002C4FE5 /* alist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = alist.h; sourceTree = "<group>"; };
8378415618C6E56B002C4FE5 /* alist_audio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = alist_audio.c; sourceTree = "<group>"; };
8378415718C6E56B002C4FE5 /* alist_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = alist_internal.h; sourceTree = "<group>"; };
8378415818C6E56B002C4FE5 /* alist_naudio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = alist_naudio.c; sourceTree = "<group>"; };
8378415918C6E56B002C4FE5 /* alist_nead.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = alist_nead.c; sourceTree = "<group>"; };
8378415A18C6E56B002C4FE5 /* arithmetics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = arithmetics.h; sourceTree = "<group>"; };
8378415B18C6E56B002C4FE5 /* audio_hle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = audio_hle.c; sourceTree = "<group>"; };
8378415C18C6E56B002C4FE5 /* audio_hle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = audio_hle.h; sourceTree = "<group>"; };
8378415D18C6E56B002C4FE5 /* cicx105.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cicx105.c; sourceTree = "<group>"; };
8378415E18C6E56B002C4FE5 /* cicx105.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cicx105.h; sourceTree = "<group>"; };
8378415F18C6E56B002C4FE5 /* jpeg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = jpeg.c; sourceTree = "<group>"; };
8378416018C6E56B002C4FE5 /* jpeg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jpeg.h; sourceTree = "<group>"; };
8378416118C6E56B002C4FE5 /* main_hle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = main_hle.c; sourceTree = "<group>"; };
8378416218C6E56B002C4FE5 /* main_hle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = main_hle.h; sourceTree = "<group>"; };
8378416318C6E56B002C4FE5 /* memory_hle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = memory_hle.c; sourceTree = "<group>"; };
8378416418C6E56B002C4FE5 /* memory_hle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memory_hle.h; sourceTree = "<group>"; };
8378416518C6E56B002C4FE5 /* mp3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mp3.c; sourceTree = "<group>"; };
8378416618C6E56B002C4FE5 /* musyx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = musyx.c; sourceTree = "<group>"; };
8378416718C6E56B002C4FE5 /* musyx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = musyx.h; sourceTree = "<group>"; };
8378416818C6E56B002C4FE5 /* plugin_hle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = plugin_hle.c; sourceTree = "<group>"; };
8378416918C6E56B002C4FE5 /* plugin_hle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = plugin_hle.h; sourceTree = "<group>"; };
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 = "<group>"; };
83C8B65A18AF58080071B040 /* audio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = audio.h; sourceTree = "<group>"; };
@ -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 = "<group>";
};
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;

View File

@ -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;
}

View File

@ -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

View File

@ -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 <stdbool.h>
#include <stdint.h>
#include <string.h>
#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);
}

View File

@ -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

View File

@ -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 <stdbool.h>
#include <stdint.h>
#include <string.h>
#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);
}

View File

@ -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 <stdbool.h>
#include <stdint.h>
#include <stddef.h>
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

View File

@ -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 <stdbool.h>
#include <stdint.h>
#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);
}

View File

@ -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 <stdbool.h>
#include <stdint.h>
#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);
}

View File

@ -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 <stdint.h>
static inline int16_t clamp_s16(int_fast32_t x)
{
x = (x < INT16_MIN) ? INT16_MIN: x;
x = (x > INT16_MAX) ? INT16_MAX: x;
return x;
}
#endif

View File

@ -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 <assert.h>
#include <stddef.h>
#include <stdint.h>
#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);
}
}

View File

@ -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 <stddef.h>
#include <stdint.h>
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

View File

@ -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 <string.h>
#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;
}
}

View File

@ -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

View File

@ -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 <assert.h>
#include <stdint.h>
#include <stdlib.h>
#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, &macroblock[y_offset], &macroblock[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, &macroblock[y_offset], &macroblock[u_offset], address);
emit_line(state, &macroblock[y_offset + 8], &macroblock[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;
}

View File

@ -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

View File

@ -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 <stdbool.h>
#include <stdint.h>
#ifdef ENABLE_TASK_DUMP
#include <stdio.h>
#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

View File

@ -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

View File

@ -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 <string.h>
#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));
}

View File

@ -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 <assert.h>
#include <stddef.h>
#include <stdint.h>
#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

View File

@ -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 <string.h>
#include <stdint.h>
#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;
}
}

View File

@ -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 <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <stddef.h>
#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);
}

View File

@ -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

View File

@ -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 <stdarg.h>
#include <string.h>
#include <stdio.h>
#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 );
}

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -13,6 +13,23 @@ struct usf_state_helper
typedef uint32_t RCPREG;
#endif
#include <stdio.h>
// 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;