mirror of
https://github.com/DaedalusX64/daedalus.git
synced 2025-04-02 10:21:48 -04:00
394 lines
11 KiB
C++
394 lines
11 KiB
C++
/****************************************************************************
|
||
* *
|
||
* Azimer's HLE Audio Plugin for Project64 Compatible N64 Emulators *
|
||
* http://www.apollo64.com/ *
|
||
* Copyright (C) 2000-2019 Azimer. All rights reserved. *
|
||
* *
|
||
* License: *
|
||
* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
|
||
* *
|
||
****************************************************************************/
|
||
|
||
/* memset() and memcpy() */
|
||
#include <string.h>
|
||
|
||
#include "audiohle.h"
|
||
|
||
|
||
//#include "RSP/rsp.h"
|
||
|
||
// For pseudo-HLE code... :)
|
||
//u32 r0, at, v0, v1, a0, a1, a2, a3;
|
||
//u32 t0, t1, t2, t3, t4, t5, t6, t7;
|
||
//u32 s0, s1, s2, s3, s4, s5, s6, s7;
|
||
//u32 t8, t9, k0, k1, gp, sp, s8, ra;
|
||
u32 t9, k0;
|
||
|
||
u64 ProfileStartTimes[30];
|
||
u64 ProfileTimes[30];
|
||
|
||
|
||
// Variables needed for ABI HLE
|
||
u8 BufferSpace[0x10000];
|
||
short hleMixerWorkArea[256];
|
||
u32 SEGMENTS[0x10]; // 0x0320
|
||
u16 AudioInBuffer; // 0x0000(T8)
|
||
u16 AudioOutBuffer; // 0x0002(T8)
|
||
u16 AudioCount; // 0x0004(T8)
|
||
u16 AudioAuxA; // 0x000A(T8)
|
||
u16 AudioAuxC; // 0x000C(T8)
|
||
u16 AudioAuxE; // 0x000E(T8)
|
||
u32 loopval; // 0x0010(T8) // Value set by A_SETLOOP : Possible conflict with SETVOLUME???
|
||
bool isMKABI = false;
|
||
bool isZeldaABI = false;
|
||
|
||
s32 acc[32][N];
|
||
s16 acc_clamped[N];
|
||
|
||
// Audio UCode lists
|
||
// Dummy UCode Handler for UCode detection... (Will always assume UCode1 until the nth list is executed)
|
||
extern p_func SafeABI[NUM_ABI_COMMANDS];
|
||
//---------------------------------------------------------------------------------------------
|
||
//
|
||
// ABI 1 : Mario64, WaveRace USA, Golden Eye 007, Quest64, SF Rush
|
||
// 60% of all games use this. Distributed 3rd Party ABI
|
||
//
|
||
extern p_func ABI1[NUM_ABI_COMMANDS];
|
||
extern p_func ABI1GE[NUM_ABI_COMMANDS];
|
||
//---------------------------------------------------------------------------------------------
|
||
//
|
||
// ABI 2 : WaveRace JAP, MarioKart 64, Mario64 JAP RumbleEdition,
|
||
// Yoshi Story, Pokemon Games, Zelda64, Zelda MoM (miyamoto)
|
||
// Most NCL or NOA games (Most commands)
|
||
extern p_func ABI2[NUM_ABI_COMMANDS];
|
||
//---------------------------------------------------------------------------------------------
|
||
//
|
||
// ABI 3 : DK64, Perfect Dark, Banjo Kazooi, Banjo Tooie
|
||
// All RARE games except Golden Eye 007
|
||
//
|
||
extern p_func ABI3[NUM_ABI_COMMANDS];
|
||
//---------------------------------------------------------------------------------------------
|
||
//
|
||
// ABI 5 : Factor 5 - MoSys/MusyX
|
||
// Rogue Squadron, Tarzan, Hydro Thunder, and TWINE
|
||
// Indiana Jones and Battle for Naboo (?)
|
||
//extern p_func ABI5[NUM_ABI_COMMANDS];
|
||
//---------------------------------------------------------------------------------------------
|
||
//
|
||
// ABI ? : Unknown or unsupported UCode
|
||
//
|
||
extern p_func ABIUnknown[NUM_ABI_COMMANDS];
|
||
//---------------------------------------------------------------------------------------------
|
||
|
||
p_func ABI[NUM_ABI_COMMANDS];
|
||
bool locklistsize = false;
|
||
|
||
//---------------------------------------------------------------------------------------------
|
||
|
||
void SPU () {
|
||
}
|
||
|
||
void SPNOOP() {
|
||
#if 0//_DEBUG
|
||
static char buff[] = "Unknown/Unimplemented Audio Command %i in ABI 3";
|
||
char * sprintf_offset;
|
||
const u8 command = (unsigned char)((k0 & 0xFF000000ul) >> 24);
|
||
|
||
sprintf_offset = strchr(&buff[0], '%'); /* Overwrite "%i" with decimal. */
|
||
*(sprintf_offset + 0) = '0' + (command / 10 % 10);
|
||
*(sprintf_offset + 1) = '0' + (command / 1 % 10);
|
||
if (sprintf_offset[0] == '0')
|
||
sprintf_offset[0] = ' '; /* Leading 0's may confuse decimal w/ octal. */
|
||
MessageBox(NULL, buff, PLUGIN_VERSION, MB_OK);
|
||
#endif
|
||
}
|
||
|
||
u32 UCData, UDataLen;
|
||
|
||
//#define ENABLELOG
|
||
#ifdef ENABLELOG
|
||
#pragma message ("Logging of Timing info is enabled!!!")
|
||
FILE *dfile = fopen ("d:\\HLEInfo.txt", "wt");
|
||
#endif
|
||
|
||
extern "C"
|
||
{
|
||
// MusyX HLE provided by Mupen64Plus authored by Bobby Smiles
|
||
//void ProcessMusyX_v1();
|
||
//void ProcessMusyX_v2();
|
||
}
|
||
|
||
u32 base, dmembase;
|
||
|
||
|
||
|
||
void HLEStart() {
|
||
u32 List = ((u32*)DMEM)[0xFF0 / 4], ListLen = ((u32*)DMEM)[0xFF4 / 4];
|
||
u32 *HLEPtr = (u32 *)(DRAM + List);
|
||
|
||
UCData = ((u32*)DMEM)[0xFD8 / 4];
|
||
UDataLen = ((u32*)DMEM)[0xFDC / 4];
|
||
base = ((u32*)DMEM)[0xFD0 / 4];
|
||
dmembase = ((u32*)DMEM)[0xFD8 / 4];
|
||
|
||
loopval = 0;
|
||
memset(SEGMENTS, 0, 0x10 * 4);
|
||
isMKABI = false;
|
||
isZeldaABI = false;
|
||
|
||
u8 * UData = DRAM + UCData;
|
||
|
||
// Detect uCode
|
||
if (((u32*)UData)[0] != 0x1) {
|
||
switch (*(u32*)(UData + (0x10)))
|
||
{
|
||
case 0x00000001: // MusyX v1
|
||
// RogueSquadron, ResidentEvil2, PolarisSnoCross,
|
||
// TheWorldIsNotEnough, RugratsInParis, NBAShowTime,
|
||
// HydroThunder, Tarzan, GauntletLegend, Rush2049
|
||
//ProcessMusyX_v1();
|
||
return;
|
||
default:
|
||
return;
|
||
|
||
case 0x0000127c: break; // naudio (many games)
|
||
case 0x00001280: break; // BanjoKazooie
|
||
case 0x1c58126c: break; // DonkeyKong
|
||
case 0x1ae8143c: break; // BanjoTooie, JetForceGemini, MickeySpeedWayUSA, PerfectDark
|
||
case 0x1ab0140c: break; // ConkerBadFurDay
|
||
}
|
||
memcpy(ABI, ABI3, NUM_ABI_COMMANDS * sizeof(p_func));
|
||
}
|
||
else
|
||
{
|
||
if (*(u32*)(UData + (0x30)) == 0xF0000F00)
|
||
{ // Should be common in ABI 1
|
||
switch (*(u32*)(UData + (0x28)))
|
||
{
|
||
case 0x1e24138c:
|
||
memcpy(ABI, ABI1, NUM_ABI_COMMANDS * sizeof(p_func));
|
||
break;
|
||
case 0x1dc8138c: // GoldenEye
|
||
memcpy(ABI, ABI1GE, NUM_ABI_COMMANDS * sizeof(p_func));
|
||
break;
|
||
case 0x1e3c1390: // BlastCorp, DiddyKongRacing
|
||
memcpy(ABI, ABI1GE, NUM_ABI_COMMANDS * sizeof(p_func));
|
||
break;
|
||
default: return;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
switch (*(u32*)(UData + (0x10))) // ABI2 and MusyX
|
||
{
|
||
case 0x00010010: // MusyX v2 (IndianaJones, BattleForNaboo)
|
||
//ProcessMusyX_v2();
|
||
return;
|
||
default:
|
||
return;
|
||
|
||
case 0x11181350: break; // MarioKart, WaveRace (E)
|
||
case 0x111812e0: break; // StarFox (J)
|
||
case 0x110412ac: break; // WaveRace (J RevB)
|
||
case 0x110412cc: break; // StarFox/LylatWars (except J)
|
||
case 0x1cd01250: break; // FZeroX
|
||
case 0x1f08122c: break; // YoshisStory
|
||
case 0x1f38122c: break; // 1080<38> Snowboarding
|
||
case 0x1f681230: break; // Zelda OoT / Zelda MM (J, J RevA)
|
||
case 0x1f801250: break; // Zelda MM (except J, J RevA, E Beta), PokemonStadium 2
|
||
case 0x109411f8: break; // Zelda MM (E Beta)
|
||
case 0x1eac11b8: break; // AnimalCrossing
|
||
}
|
||
memcpy(ABI, ABI2, NUM_ABI_COMMANDS * sizeof(p_func));
|
||
}
|
||
}
|
||
|
||
//memcpy (imem+0x80, rdram+((u32*)dmem)[0xFD0/4], ((u32*)dmem)[0xFD4/4]);
|
||
|
||
#ifdef ENABLELOG
|
||
u32 times[NUM_ABI_COMMANDS];
|
||
u32 calls[NUM_ABI_COMMANDS];
|
||
u32 list=0;
|
||
u32 total;
|
||
|
||
//memcpy (dmem, rdram+UCData, UDataLen); // Load UCode Data (for RSP stuff)
|
||
|
||
memset (times, 0, NUM_ABI_COMMANDS * sizeof(u32));
|
||
memset (calls, 0, NUM_ABI_COMMANDS * sizeof(u32));
|
||
u64 start, end;
|
||
#endif
|
||
|
||
ListLen = ListLen >> 2;
|
||
|
||
#if 0
|
||
if (*(u32*)(rdram + UCData + 0x30) == 0x0B396696) {
|
||
//printf ("MusyX Detected\n");
|
||
void smDetect();
|
||
if (ABI[0] != ABI5[0])
|
||
smDetect();
|
||
//ChangeABI (5); // This will be replaced with ProcessMusyX
|
||
//RspClosed();
|
||
//*RSPInfo.SP_PC_REG = 0x1000;
|
||
//DoRspCycles(100);
|
||
return;
|
||
}
|
||
#endif
|
||
|
||
for (u32 x = 0; x < ListLen; x += 2) {
|
||
unsigned char command;
|
||
|
||
k0 = HLEPtr[x + 0];
|
||
t9 = HLEPtr[x + 1];
|
||
command = (unsigned char)((k0 >> 24) & 0xFF);
|
||
#if 0
|
||
assert(command == command % NUM_ABI_COMMANDS);
|
||
command %= NUM_ABI_COMMANDS;
|
||
#endif
|
||
|
||
// fprintf (dfile, "k0: %08X t9: %08X\n", k0, t9);
|
||
#ifdef ENABLELOG
|
||
__asm {
|
||
rdtsc;
|
||
mov dword ptr [start+0], eax;
|
||
mov dword ptr [start+4], edx;
|
||
}
|
||
#endif
|
||
StartProfile (2 + command);
|
||
ABI[command]();
|
||
EndProfile (2 + command);
|
||
#ifdef ENABLELOG
|
||
__asm {
|
||
rdtsc;
|
||
mov dword ptr [end+0], eax;
|
||
mov dword ptr [end+4], edx;
|
||
}
|
||
calls[command]++;
|
||
times[command] += (u32)(end - start);
|
||
#endif
|
||
}
|
||
#ifdef ENABLELOG
|
||
fprintf (dfile, "List #%i\n", list++);
|
||
total = 0;
|
||
for (x = 0; x < NUM_ABI_COMMANDS; x++)
|
||
total += times[x];
|
||
for (x = 0; x < NUM_ABI_COMMANDS; x++) {
|
||
if (calls[x] != 0)
|
||
fprintf (dfile,
|
||
"Command: %02X - Calls: %3i - Total Time: %6i - Avg Time: %8.2f - Percent: %5.2f%%\n",
|
||
x,
|
||
calls[x],
|
||
times[x],
|
||
(float)times[x]/(float)calls[x],
|
||
((float)times[x]/(float)total)*100.0);
|
||
}
|
||
#endif
|
||
|
||
// fclose (dfile);
|
||
// assert(0);
|
||
}
|
||
|
||
#ifndef PREFER_MACRO_FUNCTIONS
|
||
INLINE s32 sats_over(s32 slice)
|
||
{
|
||
#ifdef TWOS_COMPLEMENT_NEGATION
|
||
s32 adder, mask;
|
||
|
||
adder = +32767 - slice;
|
||
mask = ((s32)adder >> 31); /* if (+32767 - x < 0 */
|
||
mask &= ~((s32)slice >> 31); /* && x >= 0) */
|
||
adder &= mask;
|
||
return (s32)(slice + adder); /* slice + (+32767 - slice) == +32767 */
|
||
#else
|
||
if (slice > +32767)
|
||
return +32767;
|
||
return (slice);
|
||
#endif
|
||
}
|
||
INLINE s32 sats_under(s32 slice)
|
||
{
|
||
#ifdef TWOS_COMPLEMENT_NEGATION
|
||
s32 adder, mask;
|
||
|
||
adder = +32768 + slice;
|
||
mask = ((s32)adder >> 31); /* if (x + 32768 < 0 */
|
||
mask &= ((s32)slice >> 31); /* && x < 0) */
|
||
adder &= mask;
|
||
return (s32)(slice - adder); /* slice - (slice + 32768) == -32768 */
|
||
#else
|
||
if (slice < -32768)
|
||
return -32768;
|
||
return (slice);
|
||
#endif
|
||
}
|
||
|
||
s16 pack_signed(s32 slice)
|
||
{
|
||
#ifdef SSE2_SUPPORT
|
||
__m128i xmm;
|
||
|
||
xmm = _mm_cvtsi32_si128(slice);
|
||
xmm = _mm_packs_epi32(xmm, xmm);
|
||
return (s16)_mm_cvtsi128_si32(xmm); /* or: return _mm_extract_epi16(xmm, 0); */
|
||
#else
|
||
s32 result;
|
||
|
||
result = slice;
|
||
result = sats_under(result);
|
||
result = sats_over (result);
|
||
return (s16)(result & 0x0000FFFFul);
|
||
#endif
|
||
}
|
||
|
||
void vsats128(s16* vd, s32* vs)
|
||
{
|
||
#ifdef SSE2_SUPPORT
|
||
__m128i result, xmm_hi, xmm_lo;
|
||
|
||
xmm_hi = _mm_loadu_si128((__m128i *)&vs[0]);
|
||
xmm_lo = _mm_loadu_si128((__m128i *)&vs[4]);
|
||
result = _mm_packs_epi32(xmm_hi, xmm_lo);
|
||
_mm_storeu_si128((__m128i *)vd, result);
|
||
#else
|
||
register size_t i;
|
||
|
||
for (i = 0; i < 8; i++)
|
||
vd[i] = pack_signed(vs[i]);
|
||
#endif
|
||
}
|
||
#endif
|
||
|
||
void copy_vector(void * vd, const void * vs)
|
||
{
|
||
#if defined(SSE2_SUPPORT)
|
||
/* MOVDQU XMMWORD PTR[vd], XMMWORD PTR[vs] */
|
||
_mm_storeu_si128((__m128i *)vd, _mm_loadu_si128((__m128i *)vs));
|
||
#elif defined(SSE1_SUPPORT)
|
||
/* MOVUPS XMMWORD PTR[vd], XMMWORD PTR[vs] */
|
||
_mm_storeu_ps((float *)vd, _mm_loadu_ps((float *)vs));
|
||
#elif 0
|
||
/* MOVDQA XMMWORD PTR[vd], XMMWORD PTR[vs] */
|
||
/* MOVAPS XMMWORD PTR[vd], XMMWORD PTR[vs] */
|
||
*(__m128 *)vd = *(__m128 *)vs; /* Crash if vd or vs not 128-bit aligned! */
|
||
#else
|
||
memcpy(vd, vs, 8 * sizeof(i16));
|
||
#endif
|
||
}
|
||
|
||
void swap_elements(void * vd, const void * vs)
|
||
{
|
||
#ifdef SSE2_SUPPORT
|
||
__m128i RSP_as_XMM;
|
||
|
||
RSP_as_XMM = _mm_loadu_si128((__m128i *)vs);
|
||
RSP_as_XMM = _mm_shufflehi_epi16(RSP_as_XMM, _MM_SHUFFLE(2, 3, 0, 1));
|
||
RSP_as_XMM = _mm_shufflelo_epi16(RSP_as_XMM, _MM_SHUFFLE(2, 3, 0, 1));
|
||
_mm_storeu_si128((__m128i *)vd, RSP_as_XMM);
|
||
#else
|
||
i16 temp_vector[8];
|
||
register size_t i;
|
||
|
||
for (i = 0; i < 8; i++)
|
||
temp_vector[i] = ((i16 *)vs)[i ^ 1];
|
||
copy_vector(vd, temp_vector);
|
||
#endif
|
||
}
|