Skip to content
Permalink
Browse files

Merge pull request #2846 from delroth/new-zelda-hle

Reimplement Zelda HLE
  • Loading branch information...
Tilka committed Aug 14, 2015
2 parents c306095 + 86c28bf commit dae6fdc2119ce646166f30d1f02461ccc7a3d1ab
@@ -74,9 +74,6 @@ set(SRCS ActionReplay.cpp
HW/DSPHLE/UCodes/ROM.cpp
HW/DSPHLE/UCodes/UCodes.cpp
HW/DSPHLE/UCodes/Zelda.cpp
HW/DSPHLE/UCodes/ZeldaADPCM.cpp
HW/DSPHLE/UCodes/ZeldaSynth.cpp
HW/DSPHLE/UCodes/ZeldaVoice.cpp
HW/DSPHLE/MailHandler.cpp
HW/DSPHLE/DSPHLE.cpp
HW/DSPLLE/DSPDebugInterface.cpp
@@ -284,6 +284,7 @@ void SConfig::SaveDSPSettings(IniFile& ini)

dsp->Set("EnableJIT", m_DSPEnableJIT);
dsp->Set("DumpAudio", m_DumpAudio);
dsp->Set("DumpUCode", m_DumpUCode);
dsp->Set("Backend", sBackend);
dsp->Set("Volume", m_Volume);
dsp->Set("CaptureLog", m_DSPCaptureLog);
@@ -543,6 +544,7 @@ void SConfig::LoadDSPSettings(IniFile& ini)

dsp->Get("EnableJIT", &m_DSPEnableJIT, true);
dsp->Get("DumpAudio", &m_DumpAudio, false);
dsp->Get("DumpUCode", &m_DumpUCode, false);
#if defined __linux__ && HAVE_ALSA
dsp->Get("Backend", &sBackend, BACKEND_ALSA);
#elif defined __APPLE__
@@ -255,6 +255,7 @@ struct SConfig : NonCopyable
bool m_DSPCaptureLog;
bool m_DumpAudio;
bool m_IsMuted;
bool m_DumpUCode;
int m_Volume;
std::string sBackend;

@@ -108,9 +108,6 @@
<ClCompile Include="HW\DSPHLE\UCodes\INIT.cpp" />
<ClCompile Include="HW\DSPHLE\UCodes\ROM.cpp" />
<ClCompile Include="HW\DSPHLE\UCodes\Zelda.cpp" />
<ClCompile Include="HW\DSPHLE\UCodes\ZeldaADPCM.cpp" />
<ClCompile Include="HW\DSPHLE\UCodes\ZeldaSynth.cpp" />
<ClCompile Include="HW\DSPHLE\UCodes\ZeldaVoice.cpp" />
<ClCompile Include="HW\DSPLLE\DSPDebugInterface.cpp" />
<ClCompile Include="HW\DSPLLE\DSPHost.cpp" />
<ClCompile Include="HW\DSPLLE\DSPLLE.cpp" />
@@ -336,15 +336,6 @@
<ClCompile Include="HW\DSPHLE\UCodes\Zelda.cpp">
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
</ClCompile>
<ClCompile Include="HW\DSPHLE\UCodes\ZeldaADPCM.cpp">
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
</ClCompile>
<ClCompile Include="HW\DSPHLE\UCodes\ZeldaSynth.cpp">
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
</ClCompile>
<ClCompile Include="HW\DSPHLE\UCodes\ZeldaVoice.cpp">
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
</ClCompile>
<ClCompile Include="HW\DSPHLE\UCodes\UCodes.cpp">
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
</ClCompile>
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.

#include "Common/ChunkFile.h"
#include "Core/HW/DSP.h"
#include "Core/HW/DSPHLE/MailHandler.h"

CMailHandler::CMailHandler()
@@ -14,9 +15,20 @@ CMailHandler::~CMailHandler()
Clear();
}

void CMailHandler::PushMail(u32 _Mail)
void CMailHandler::PushMail(u32 _Mail, bool interrupt)
{
m_Mails.push(_Mail);
if (interrupt)
{
if (m_Mails.empty())
{
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
}
else
{
m_Mails.front().second = true;
}
}
m_Mails.emplace(_Mail, false);
DEBUG_LOG(DSP_MAIL, "DSP writes 0x%08x", _Mail);
}

@@ -25,7 +37,7 @@ u16 CMailHandler::ReadDSPMailboxHigh()
// check if we have a mail for the core
if (!m_Mails.empty())
{
u16 result = (m_Mails.front() >> 16) & 0xFFFF;
u16 result = (m_Mails.front().first >> 16) & 0xFFFF;
return result;
}
return 0x00;
@@ -36,8 +48,15 @@ u16 CMailHandler::ReadDSPMailboxLow()
// check if we have a mail for the core
if (!m_Mails.empty())
{
u16 result = m_Mails.front() & 0xFFFF;
u16 result = m_Mails.front().first & 0xFFFF;
bool generate_interrupt = m_Mails.front().second;
m_Mails.pop();

if (generate_interrupt)
{
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
}

return result;
}
return 0x00;
@@ -59,7 +78,7 @@ void CMailHandler::Halt(bool _Halt)
if (_Halt)
{
Clear();
m_Mails.push(0x80544348);
PushMail(0x80544348);
}
}

@@ -73,31 +92,36 @@ void CMailHandler::DoState(PointerWrap &p)
for (int i = 0; i < sz; i++)
{
u32 mail = 0;
bool interrupt = false;
p.Do(mail);
m_Mails.push(mail);
p.Do(interrupt);
m_Mails.emplace(mail, interrupt);
}
}
else // WRITE and MEASURE
{
std::queue<u32> temp;
std::queue<std::pair<u32, bool>> temp;
int sz = (int)m_Mails.size();
p.Do(sz);
for (int i = 0; i < sz; i++)
{
u32 value = m_Mails.front();
u32 value = m_Mails.front().first;
bool interrupt = m_Mails.front().second;
m_Mails.pop();
p.Do(value);
temp.push(value);
p.Do(interrupt);
temp.emplace(value, interrupt);
}
if (!m_Mails.empty())
PanicAlert("CMailHandler::DoState - WTF?");

// Restore queue.
for (int i = 0; i < sz; i++)
{
u32 value = temp.front();
u32 value = temp.front().first;
bool interrupt = temp.front().second;
temp.pop();
m_Mails.push(value);
m_Mails.emplace(value, interrupt);
}
}
}
@@ -5,6 +5,8 @@
#pragma once

#include <queue>
#include <utility>

#include "Common/CommonTypes.h"

class PointerWrap;
@@ -15,7 +17,7 @@ class CMailHandler
CMailHandler();
~CMailHandler();

void PushMail(u32 _Mail);
void PushMail(u32 _Mail, bool interrupt = false);
void Clear();
void Halt(bool _Halt);
void DoState(PointerWrap &p);
@@ -24,20 +26,7 @@ class CMailHandler
u16 ReadDSPMailboxHigh();
u16 ReadDSPMailboxLow();

u32 GetNextMail() const
{
if (!m_Mails.empty())
{
return m_Mails.front();
}
else
{
// WARN_LOG(DSPHLE, "GetNextMail: No mails");
return 0;
}
}

private:
// mail handler
std::queue<u32> m_Mails;
std::queue<std::pair<u32, bool>> m_Mails;
};
@@ -7,6 +7,81 @@
#include "Core/HW/DSPHLE/UCodes/GBA.h"
#include "Core/HW/DSPHLE/UCodes/UCodes.h"

void ProcessGBACrypto(u32 address)
{
struct sec_params_t
{
u16 key[2];
u16 unk1[2];
u16 unk2[2];
u32 length;
u32 dest_addr;
u32 pad[3];
} sec_params;

// 32 bytes from mram addr to DRAM @ 0
for (int i = 0; i < 8; i++, address += 4)
((u32*)&sec_params)[i] = HLEMemory_Read_U32(address);

// This is the main decrypt routine
u16 x11 = 0, x12 = 0,
x20 = 0, x21 = 0, x22 = 0, x23 = 0;

x20 = Common::swap16(sec_params.key[0]) ^ 0x6f64;
x21 = Common::swap16(sec_params.key[1]) ^ 0x6573;

s16 unk2 = (s8)sec_params.unk2[0];
if (unk2 < 0)
{
x11 = ((~unk2 + 3) << 1) | (sec_params.unk1[0] << 4);
}
else if (unk2 == 0)
{
x11 = (sec_params.unk1[0] << 1) | 0x70;
}
else // unk2 > 0
{
x11 = ((unk2 - 1) << 1) | (sec_params.unk1[0] << 4);
}

s32 rounded_sub = ((sec_params.length + 7) & ~7) - 0x200;
u16 size = (rounded_sub < 0) ? 0 : rounded_sub >> 3;

u32 t = (((size << 16) | 0x3f80) & 0x3f80ffff) << 1;
s16 t_low = (s8)(t >> 8);
t += (t_low & size) << 16;
x12 = t >> 16;
x11 |= (size & 0x4000) >> 14; // this would be stored in ac0.h if we weren't constrained to 32bit :)
t = ((x11 & 0xff) << 16) + ((x12 & 0xff) << 16) + (x12 << 8);

u16 final11 = 0, final12 = 0;
final11 = x11 | ((t >> 8) & 0xff00) | 0x8080;
final12 = x12 | 0x8080;

if ((final12 & 0x200) != 0)
{
x22 = final11 ^ 0x6f64;
x23 = final12 ^ 0x6573;
}
else
{
x22 = final11 ^ 0x6177;
x23 = final12 ^ 0x614b;
}

// Send the result back to mram
*(u32*)HLEMemory_Get_Pointer(sec_params.dest_addr) = Common::swap32((x20 << 16) | x21);
*(u32*)HLEMemory_Get_Pointer(sec_params.dest_addr+4) = Common::swap32((x22 << 16) | x23);

// Done!
DEBUG_LOG(DSPHLE, "\n%08x -> key: %08x, len: %08x, dest_addr: %08x, unk1: %08x, unk2: %08x"
" 22: %04x, 23: %04x",
address,
*(u32*)sec_params.key, sec_params.length, sec_params.dest_addr,
*(u32*)sec_params.unk1, *(u32*)sec_params.unk2,
x22, x23);
}

GBAUCode::GBAUCode(DSPHLE *dsphle, u32 crc)
: UCodeInterface(dsphle, crc)
{
@@ -48,79 +123,8 @@ void GBAUCode::HandleMail(u32 mail)
else if (nextmail_is_mramaddr)
{
nextmail_is_mramaddr = false;
u32 mramaddr = mail;

struct sec_params_t
{
u16 key[2];
u16 unk1[2];
u16 unk2[2];
u32 length;
u32 dest_addr;
u32 pad[3];
} sec_params;

// 32 bytes from mram addr to DRAM @ 0
for (int i = 0; i < 8; i++, mramaddr += 4)
((u32*)&sec_params)[i] = HLEMemory_Read_U32(mramaddr);

// This is the main decrypt routine
u16 x11 = 0, x12 = 0,
x20 = 0, x21 = 0, x22 = 0, x23 = 0;

x20 = Common::swap16(sec_params.key[0]) ^ 0x6f64;
x21 = Common::swap16(sec_params.key[1]) ^ 0x6573;

s16 unk2 = (s8)sec_params.unk2[0];
if (unk2 < 0)
{
x11 = ((~unk2 + 3) << 1) | (sec_params.unk1[0] << 4);
}
else if (unk2 == 0)
{
x11 = (sec_params.unk1[0] << 1) | 0x70;
}
else // unk2 > 0
{
x11 = ((unk2 - 1) << 1) | (sec_params.unk1[0] << 4);
}

s32 rounded_sub = ((sec_params.length + 7) & ~7) - 0x200;
u16 size = (rounded_sub < 0) ? 0 : rounded_sub >> 3;

u32 t = (((size << 16) | 0x3f80) & 0x3f80ffff) << 1;
s16 t_low = (s8)(t >> 8);
t += (t_low & size) << 16;
x12 = t >> 16;
x11 |= (size & 0x4000) >> 14; // this would be stored in ac0.h if we weren't constrained to 32bit :)
t = ((x11 & 0xff) << 16) + ((x12 & 0xff) << 16) + (x12 << 8);

u16 final11 = 0, final12 = 0;
final11 = x11 | ((t >> 8) & 0xff00) | 0x8080;
final12 = x12 | 0x8080;

if ((final12 & 0x200) != 0)
{
x22 = final11 ^ 0x6f64;
x23 = final12 ^ 0x6573;
}
else
{
x22 = final11 ^ 0x6177;
x23 = final12 ^ 0x614b;
}

// Send the result back to mram
*(u32*)HLEMemory_Get_Pointer(sec_params.dest_addr) = Common::swap32((x20 << 16) | x21);
*(u32*)HLEMemory_Get_Pointer(sec_params.dest_addr+4) = Common::swap32((x22 << 16) | x23);

// Done!
DEBUG_LOG(DSPHLE, "\n%08x -> key: %08x, len: %08x, dest_addr: %08x, unk1: %08x, unk2: %08x"
" 22: %04x, 23: %04x",
mramaddr,
*(u32*)sec_params.key, sec_params.length, sec_params.dest_addr,
*(u32*)sec_params.unk1, *(u32*)sec_params.unk2,
x22, x23);
ProcessGBACrypto(mail);

calc_done = true;
m_mail_handler.PushMail(DSP_DONE);
@@ -6,6 +6,11 @@

#include "Core/HW/DSPHLE/UCodes/UCodes.h"

// Computes two 32 bit integers to be returned to the game, based on the
// provided crypto parameters at the provided MRAM address. The integers are
// written back to RAM at the dest address provided in the crypto parameters.
void ProcessGBACrypto(u32 address);

struct GBAUCode : public UCodeInterface
{
GBAUCode(DSPHLE *dsphle, u32 crc);
Oops, something went wrong.

0 comments on commit dae6fdc

Please sign in to comment.
You can’t perform that action at this time.