messing about with the zelda ucode hle code, not really getting anywhere :/
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3472 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
212c406d0b
commit
4a5cf26160
|
@ -19,6 +19,7 @@
|
|||
// Zelda: The Windwaker, Mario Sunshine, Mario Kart, Twilight Princess
|
||||
|
||||
#include "../Globals.h"
|
||||
#include "FileUtil.h"
|
||||
#include "UCodes.h"
|
||||
#include "UCode_Zelda.h"
|
||||
#include "../MailHandler.h"
|
||||
|
@ -27,6 +28,99 @@
|
|||
#include "Mixer.h"
|
||||
|
||||
|
||||
namespace {
|
||||
CompileTimeAssert<sizeof(ZPB) == 0x180> dummy_name;
|
||||
}
|
||||
|
||||
// TODO: replace with table from RAM.
|
||||
unsigned short afccoef[16][2] =
|
||||
{{0,0},
|
||||
{0x0800,0},
|
||||
{0,0x0800},
|
||||
{0x0400,0x0400},
|
||||
{0x1000,0xf800},
|
||||
{0x0e00,0xfa00},
|
||||
{0x0c00,0xfc00},
|
||||
{0x1200,0xf600},
|
||||
{0x1068,0xf738},
|
||||
{0x12c0,0xf704},
|
||||
{0x1400,0xf400},
|
||||
{0x0800,0xf800},
|
||||
{0x0400,0xfc00},
|
||||
{0xfc00,0x0400},
|
||||
{0xfc00,0},
|
||||
{0xf800,0}};
|
||||
|
||||
|
||||
// Decoder from in_cube by hcs/destop/etc. Haven't yet found a valid use for it.
|
||||
|
||||
// Looking at in_cube, it seems to be 9 bytes of input = 16 samples of output.
|
||||
// Different from AX ADPCM which is 8 bytes of input = 14 samples of output.
|
||||
void AFCdecodebuffer
|
||||
(
|
||||
u8 *input, // location of encoded source samples
|
||||
s16 *out, // location of destination buffer (16 bits / sample)
|
||||
short *histp,
|
||||
short *hist2p
|
||||
)
|
||||
{
|
||||
int sample;
|
||||
short nibbles[16];
|
||||
u8 *src, *dst;
|
||||
short idx;
|
||||
short delta;
|
||||
short hist=*histp;
|
||||
short hist2=*hist2p;
|
||||
|
||||
dst = (u8 *)out;
|
||||
|
||||
src = input;
|
||||
delta = 1 << (((*src) >> 4)&0xf);
|
||||
idx = (*src) & 0xf;
|
||||
|
||||
src++;
|
||||
|
||||
for (int i = 0; i < 16; i = i + 2)
|
||||
{
|
||||
int j = ( *src & 255) >> 4;
|
||||
nibbles[i] = j;
|
||||
j = *src & 255 & 15;
|
||||
nibbles[i + 1] = j;
|
||||
src++;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i = i + 1)
|
||||
{
|
||||
if (nibbles[i] >= 8)
|
||||
nibbles[i] = nibbles[i] - 16;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i = i + 1)
|
||||
{
|
||||
sample = (delta * nibbles[i]) << 11;
|
||||
sample += ((long)hist * afccoef[idx][0]) + ((long)hist2 * afccoef[idx][1]);
|
||||
sample = sample >> 11;
|
||||
|
||||
if(sample > 32767) {
|
||||
sample = 32767;
|
||||
}
|
||||
if(sample < -32768) {
|
||||
sample = -32768;
|
||||
}
|
||||
|
||||
*(short*)dst = (short)sample;
|
||||
dst = dst + 2;
|
||||
|
||||
hist2 = hist;
|
||||
hist = (short)sample;
|
||||
}
|
||||
|
||||
*histp=hist;
|
||||
*hist2p=hist2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
CUCode_Zelda::CUCode_Zelda(CMailHandler& _rMailHandler)
|
||||
: IUCode(_rMailHandler)
|
||||
, m_bSyncInProgress(false)
|
||||
|
@ -44,6 +138,7 @@ CUCode_Zelda::CUCode_Zelda(CMailHandler& _rMailHandler)
|
|||
, m_readOffset(0)
|
||||
{
|
||||
DEBUG_LOG(DSPHLE, "UCode_Zelda - add boot mails for handshake");
|
||||
|
||||
m_rMailHandler.PushMail(DSP_INIT);
|
||||
g_dspInitialize.pGenerateDSPInterrupt();
|
||||
m_rMailHandler.PushMail(0xF3551111); // handshake
|
||||
|
@ -172,11 +267,6 @@ void CUCode_Zelda::HandleMail(u32 _uMail)
|
|||
}
|
||||
}
|
||||
|
||||
void CUCode_Zelda::MixAdd(short* buffer, int size)
|
||||
{
|
||||
//TODO(XK): Zelda UCode MixAdd?
|
||||
}
|
||||
|
||||
void CUCode_Zelda::ExecuteList()
|
||||
{
|
||||
// begin with the list
|
||||
|
@ -196,16 +286,18 @@ void CUCode_Zelda::ExecuteList()
|
|||
// DsetupTable ... zelda ww jumps to 0x0095
|
||||
case 0x01:
|
||||
{
|
||||
num_param_blocks = ExtraData;
|
||||
u32 tmp[4];
|
||||
tmp[0] = Read32();
|
||||
param_blocks_ptr = tmp[0] = Read32();
|
||||
tmp[1] = Read32();
|
||||
tmp[2] = Read32();
|
||||
tmp[3] = Read32();
|
||||
param_blocks2_ptr = tmp[3] = Read32();
|
||||
|
||||
m_SyncMaxStep = CmdMail & 0xFFFF;
|
||||
|
||||
DEBUG_LOG(DSPHLE, "DsetupTable");
|
||||
DEBUG_LOG(DSPHLE, "Some mixing buffer: 0x%08x", tmp[0]);
|
||||
DEBUG_LOG(DSPHLE, "Num param blocks: %i", num_param_blocks);
|
||||
DEBUG_LOG(DSPHLE, "Param blocks 1: 0x%08x", tmp[0]);
|
||||
|
||||
// This points to some strange data table.
|
||||
DEBUG_LOG(DSPHLE, "DSPRES_FILTER (size: 0x40): 0x%08x", tmp[1]);
|
||||
|
@ -216,7 +308,7 @@ void CUCode_Zelda::ExecuteList()
|
|||
// There's also a lot more table-looking data immediately after - maybe alternative
|
||||
// tables? I wonder where the parameter blocks are?
|
||||
DEBUG_LOG(DSPHLE, "DSPADPCM_FILTER (size: 0x500): 0x%08x", tmp[2]);
|
||||
DEBUG_LOG(DSPHLE, "Some other mixing buffer: 0x%08x", tmp[3]);
|
||||
DEBUG_LOG(DSPHLE, "Param blocks 2: 0x%08x", tmp[3]);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -228,9 +320,9 @@ void CUCode_Zelda::ExecuteList()
|
|||
tmp[1] = Read32();
|
||||
|
||||
// We're ready to mix
|
||||
// soundStream->GetMixer()->SetHLEReady(true);
|
||||
// DEBUG_LOG(DSPHLE, "Update the SoundThread to be in sync");
|
||||
// soundStream->Update(); //do it in this thread to avoid sync problems
|
||||
// soundStream->GetMixer()->SetHLEReady(true);
|
||||
// DEBUG_LOG(DSPHLE, "Update the SoundThread to be in sync");
|
||||
soundStream->Update(); //do it in this thread to avoid sync problems
|
||||
|
||||
m_bSyncCmdPending = true;
|
||||
m_SyncEndSync = Sync;
|
||||
|
@ -243,6 +335,59 @@ void CUCode_Zelda::ExecuteList()
|
|||
// but not at, the ADMA read addresses.
|
||||
DEBUG_LOG(DSPHLE, "Left mixing buffer? 0x%08x", tmp[0]);
|
||||
DEBUG_LOG(DSPHLE, "Right mixing buffer? 0x%08x", tmp[1]);
|
||||
|
||||
// Let's log the parameter blocks.
|
||||
// Copy and byteswap the parameter blocks.
|
||||
|
||||
// For some reason, in Z:WW we get no param blocks until in-game,
|
||||
// while Zelda Four Swords happily sets param blocks as soon as the title screen comes up.
|
||||
// Looks like it's playing midi music.
|
||||
DEBUG_LOG(DSPHLE, "Param block at %08x:", param_blocks_ptr);
|
||||
CopyPBsFromRAM();
|
||||
for (int i = 0; i < num_param_blocks; i++)
|
||||
{
|
||||
// The only thing that consistently looks like a pointer in the param blocks.
|
||||
u32 addr = (zpbs[i].addr_high << 16) | zpbs[i].addr_low;
|
||||
if (addr)
|
||||
{
|
||||
DEBUG_LOG(DSPHLE, "Param block: ==== %i ( %08x ) ====", i, GetParamBlockAddr(i));
|
||||
DEBUG_LOG(DSPHLE, "Addr: %08x", addr);
|
||||
|
||||
// Got one! Read from ARAM, dump to file.
|
||||
// I can't get the below to produce anything resembling sane audio :(
|
||||
//addr *= 2;
|
||||
/*
|
||||
int size = 0x10000;
|
||||
u8 *temp = new u8[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
temp[i] = g_dspInitialize.pARAM_Read_U8(addr + i);
|
||||
}
|
||||
s16 *audio = new s16[size * 4];
|
||||
int aoff = 0;
|
||||
short hist1 = 0, hist2 = 0;
|
||||
for (int i = 0; i < size; i+=9)
|
||||
{
|
||||
AFCdecodebuffer(temp + i, audio + aoff, &hist1, &hist2);
|
||||
aoff += 16;
|
||||
}
|
||||
char fname[256];
|
||||
sprintf(fname, "%08x.bin", addr);
|
||||
if (File::Exists(fname))
|
||||
continue;
|
||||
|
||||
FILE *f = fopen(fname, "wb");
|
||||
fwrite(audio, 1, size*4, f);
|
||||
fclose(f);
|
||||
|
||||
sprintf(fname, "%08x_raw.bin", addr);
|
||||
|
||||
f = fopen(fname, "wb");
|
||||
fwrite(temp, 1, size, f);
|
||||
fclose(f);
|
||||
*/
|
||||
}
|
||||
}
|
||||
CopyPBsToRAM();
|
||||
}
|
||||
return;
|
||||
break;
|
||||
|
@ -300,3 +445,39 @@ void CUCode_Zelda::ExecuteList()
|
|||
}
|
||||
|
||||
|
||||
void CUCode_Zelda::CopyPBsFromRAM()
|
||||
{
|
||||
for (int i = 0; i < num_param_blocks; i++)
|
||||
{
|
||||
u32 addr = param_blocks_ptr + i * sizeof(ZPB);
|
||||
const u16 *src_ptr = (u16 *)g_dspInitialize.pGetMemoryPointer(addr);
|
||||
u16 *dst_ptr = (u16 *)&zpbs[i];
|
||||
for (size_t p = 0; p < sizeof(ZPB) / 2; p++)
|
||||
{
|
||||
dst_ptr[p] = Common::swap16(src_ptr[p]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CUCode_Zelda::CopyPBsToRAM()
|
||||
{
|
||||
for (int i = 0; i < num_param_blocks; i++)
|
||||
{
|
||||
u32 addr = param_blocks_ptr + i * sizeof(ZPB);
|
||||
const u16 *src_ptr = (u16 *)&zpbs[i];
|
||||
u16 *dst_ptr = (u16 *)g_dspInitialize.pGetMemoryPointer(addr);
|
||||
for (size_t p = 0; p < sizeof(ZPB) / 2; p++)
|
||||
{
|
||||
dst_ptr[p] = Common::swap16(src_ptr[p]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CUCode_Zelda::MixAdd(short* buffer, int size)
|
||||
{
|
||||
//TODO(XK): Zelda UCode MixAdd?
|
||||
// for (int i = 0; i < size; i++) {
|
||||
// buffer[i] = rand();
|
||||
// }
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,26 @@
|
|||
#include "Common.h"
|
||||
#include "UCodes.h"
|
||||
|
||||
|
||||
// Here's a piece of pure guesswork, looking at random supposedly-PBs
|
||||
// from Zelda Four Swords.
|
||||
|
||||
// These are 0x180 bytes large.
|
||||
struct ZPB
|
||||
{
|
||||
u16 temp[0x80];
|
||||
u16 temp2; u16 temp3;
|
||||
u16 whatever[0x14 / 2];
|
||||
|
||||
// Not sure what addresses this is, hopefully to sample data in ARAM.
|
||||
// These are the only things in the param blocks that look a lot like pointers.
|
||||
u16 addr_high; // at 0x18 = 0xC * 2
|
||||
u16 addr_low;
|
||||
|
||||
u16 filler[(0x80 - 0x1C) / 2];
|
||||
};
|
||||
|
||||
|
||||
class CUCode_Zelda : public IUCode
|
||||
{
|
||||
private:
|
||||
|
@ -58,6 +78,24 @@ private:
|
|||
|
||||
u32 m_readOffset;
|
||||
|
||||
|
||||
|
||||
// HLE state
|
||||
int num_param_blocks;
|
||||
|
||||
u32 param_blocks_ptr;
|
||||
u32 param_blocks2_ptr;
|
||||
|
||||
ZPB zpbs[0x40];
|
||||
ZPB zpbs2[4];
|
||||
|
||||
void CopyPBsFromRAM();
|
||||
void CopyPBsToRAM();
|
||||
|
||||
u32 GetParamBlockAddr(int block_no) const {
|
||||
return param_blocks_ptr + sizeof(ZPB) * block_no;
|
||||
}
|
||||
|
||||
u8 Read8()
|
||||
{
|
||||
return m_Buffer[m_readOffset++];
|
||||
|
@ -74,6 +112,9 @@ private:
|
|||
{
|
||||
u32 res = *(u32*)&m_Buffer[m_readOffset];
|
||||
m_readOffset += 4;
|
||||
if ((m_readOffset >> 2) >= m_numSteps + 1) {
|
||||
WARN_LOG(DSPHLE, "Read32 out of bounds");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
public:
|
||||
|
|
Loading…
Reference in New Issue