From 4a5cf2616007233ab7f5a5f0a2eb0c9597d5e2f4 Mon Sep 17 00:00:00 2001 From: hrydgard Date: Tue, 16 Jun 2009 21:58:49 +0000 Subject: [PATCH] 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 --- .../Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.cpp | 205 +++++++++++++++++- .../Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.h | 41 ++++ 2 files changed, 234 insertions(+), 12 deletions(-) diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.cpp b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.cpp index 639dd90bf1..519b51d89a 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.cpp +++ b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.cpp @@ -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 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(); +// } +} + diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.h b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.h index 772eaccce6..e5f0e10448 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.h +++ b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.h @@ -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: