allow "swapping" of hle'd ucodes

hle the gba ucode

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6046 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
Shawn Hoffman
2010-08-04 11:44:06 +00:00
parent dc0a67b53a
commit 0a3c150f69
16 changed files with 809 additions and 415 deletions

View File

@ -570,6 +570,14 @@
RelativePath=".\Src\UCodes\UCode_CARD.h"
>
</File>
<File
RelativePath=".\Src\UCodes\UCode_GBA.cpp"
>
</File>
<File
RelativePath=".\Src\UCodes\UCode_GBA.h"
>
</File>
<File
RelativePath=".\Src\UCodes\UCode_InitAudioSystem.cpp"
>

View File

@ -21,6 +21,7 @@ CDSPHandler* CDSPHandler::m_pInstance = NULL;
CDSPHandler::CDSPHandler()
: m_pUCode(NULL),
m_lastUCode(NULL),
m_bHalt(false),
m_bAssertInt(false)
{
@ -86,3 +87,23 @@ void CDSPHandler::SetUCode(u32 _crc)
m_MailHandler.Clear();
m_pUCode = UCodeFactory(_crc, m_MailHandler);
}
// TODO do it better?
// Assumes that every odd call to this func is by the persistent ucode.
// Even callers are deleted.
void CDSPHandler::SwapUCode(u32 _crc)
{
m_MailHandler.Clear();
if (m_lastUCode == NULL)
{
m_lastUCode = m_pUCode;
m_pUCode = UCodeFactory(_crc, m_MailHandler);
}
else
{
delete m_pUCode;
m_pUCode = m_lastUCode;
m_lastUCode = NULL;
}
}

View File

@ -32,6 +32,7 @@ public:
void SendMailToDSP(u32 _uMail);
IUCode* GetUCode();
void SetUCode(u32 _crc);
void SwapUCode(u32 _crc);
CMailHandler& AccessMailHandler() { return m_MailHandler; }
@ -63,6 +64,8 @@ private:
static CDSPHandler* m_pInstance;
IUCode* m_pUCode;
IUCode* m_lastUCode;
UDSPControl m_DSPControl;
CMailHandler m_MailHandler;

View File

@ -45,7 +45,7 @@ public:
else
{
// WARN_LOG(DSPHLE, "GetNextMail: No mails");
return 0; //
return 0;
}
}

View File

@ -0,0 +1,157 @@
// Copyright (C) 2003 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "../Globals.h"
#include "../DSPHandler.h"
#include "UCodes.h"
#include "UCode_GBA.h"
CUCode_GBA::CUCode_GBA(CMailHandler& _rMailHandler)
: IUCode(_rMailHandler)
{
m_rMailHandler.PushMail(DSP_INIT);
}
CUCode_GBA::~CUCode_GBA()
{
m_rMailHandler.Clear();
}
void CUCode_GBA::Update(int cycles)
{
// check if we have to send something
if (!m_rMailHandler.IsEmpty())
{
g_dspInitialize.pGenerateDSPInterrupt();
}
}
#pragma optimize("", off)
void CUCode_GBA::HandleMail(u32 _uMail)
{
static bool nextmail_is_mramaddr = false;
static bool calc_done = false;
if (m_UploadSetupInProgress)
{
PrepareBootUCode(_uMail);
}
else if ((_uMail >> 16 == 0xabba) && !nextmail_is_mramaddr)
{
nextmail_is_mramaddr = true;
}
else if (nextmail_is_mramaddr)
{
nextmail_is_mramaddr = false;
u32 mramaddr = _uMail;
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] = Memory_Read_U32(mramaddr);
// This is the main decrypt routine
u16 x11 = 0, x12 = 0,
x20 = 0, x21 = 0, x22 = 0, x23 = 0;
x20 = ((sec_params.key[0] >> 8) | (sec_params.key[0] << 8)) ^ 0x6f64;
x21 = ((sec_params.key[1] >> 8) | (sec_params.key[1] << 8)) ^ 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) & 0x4000ffff) << 2;
u32 u = (((size << 16) | 0x3f80) & 0x3f80ffff) << 1;
t += u;
s16 u_low = (s8)(u >> 8);
t += (u_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*)Memory_Get_Pointer(sec_params.dest_addr) = Common::swap32((x20 << 16) | x21);
*(u32*)Memory_Get_Pointer(sec_params.dest_addr+4) = Common::swap32((x22 << 16) | x23);
// Done!
WARN_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);
calc_done = true;
m_rMailHandler.PushMail(DSP_DONE);
}
else if ((_uMail >> 16 == 0xcdd1) && calc_done)
{
switch (_uMail & 0xffff)
{
case 1:
m_UploadSetupInProgress = true;
break;
case 2:
CDSPHandler::GetInstance().SetUCode(UCODE_ROM);
break;
default:
DEBUG_LOG(DSPHLE, "CUCode_GBA - unknown 0xcdd1 cmd: %08x", _uMail);
break;
}
}
else
{
DEBUG_LOG(DSPHLE, "CUCode_GBA - unknown cmd: %08x", _uMail);
}
}
#pragma optimize("", on)

View File

@ -0,0 +1,29 @@
// Copyright (C) 2003 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#pragma once
#include "UCodes.h"
struct CUCode_GBA : public IUCode
{
CUCode_GBA(CMailHandler& _rMailHandler);
virtual ~CUCode_GBA();
void HandleMail(u32 _uMail);
void Update(int cycles);
};

View File

@ -22,9 +22,6 @@
CUCode_InitAudioSystem::CUCode_InitAudioSystem(CMailHandler& _rMailHandler)
: IUCode(_rMailHandler)
, m_BootTask_numSteps(0)
, m_NextParameter(0)
, IsInitialized(false)
{
DEBUG_LOG(DSPHLE, "CUCode_InitAudioSystem - initialized");
}

View File

@ -29,25 +29,6 @@ public:
void HandleMail(u32 _uMail);
void Update(int cycles);
void Init();
private:
struct SUCode
{
u32 m_RAMAddress;
u32 m_Length;
u32 m_IMEMAddress;
u32 m_DMEMLength;
u32 m_StartPC;
};
SUCode m_CurrentUCode;
int m_BootTask_numSteps;
u32 m_NextParameter;
bool IsInitialized;
void BootUCode();
};
#endif

View File

@ -19,9 +19,11 @@
#include "../DSPHandler.h"
#include "UCodes.h"
#include "UCode_ROM.h"
#include "Hash.h"
CUCode_Rom::CUCode_Rom(CMailHandler& _rMailHandler)
: IUCode(_rMailHandler)
, m_CurrentUCode()
, m_BootTask_numSteps(0)
, m_NextParameter(0)
{
@ -93,25 +95,19 @@ void CUCode_Rom::HandleMail(u32 _uMail)
void CUCode_Rom::BootUCode()
{
// simple non-scientific crc invented by ector :P
// too annoying to change now, and probably good enough anyway
u32 crc = 0;
for (u32 i = 0; i < m_CurrentUCode.m_Length; i++)
{
crc ^= Memory_Read_U8(m_CurrentUCode.m_RAMAddress + i);
//let's rol
crc = (crc << 3) | (crc >> 29);
}
u32 ector_crc = HashEctor(
(u8*)Memory_Get_Pointer(m_CurrentUCode.m_RAMAddress),
m_CurrentUCode.m_Length);
DEBUG_LOG(DSPHLE, "CurrentUCode SOURCE Addr: 0x%08x", m_CurrentUCode.m_RAMAddress);
DEBUG_LOG(DSPHLE, "CurrentUCode Length: 0x%08x", m_CurrentUCode.m_Length);
DEBUG_LOG(DSPHLE, "CurrentUCode DEST Addr: 0x%08x", m_CurrentUCode.m_IMEMAddress);
DEBUG_LOG(DSPHLE, "CurrentUCode DMEM Length: 0x%08x", m_CurrentUCode.m_DMEMLength);
DEBUG_LOG(DSPHLE, "CurrentUCode init_vector: 0x%08x", m_CurrentUCode.m_StartPC);
DEBUG_LOG(DSPHLE, "CurrentUCode CRC: 0x%08x", crc);
DEBUG_LOG(DSPHLE, "CurrentUCode CRC: 0x%08x", ector_crc);
DEBUG_LOG(DSPHLE, "BootTask - done");
CDSPHandler::GetInstance().SetUCode(crc);
CDSPHandler::GetInstance().SetUCode(ector_crc);
}

View File

@ -38,7 +38,6 @@ private:
u32 m_DMEMLength;
u32 m_StartPC;
};
SUCode m_CurrentUCode;
int m_BootTask_numSteps;

View File

@ -28,6 +28,8 @@
#include "Mixer.h"
#include "WaveFile.h"
#include "../DSPHandler.h"
CUCode_Zelda::CUCode_Zelda(CMailHandler& _rMailHandler, u32 _CRC)
:
@ -118,6 +120,12 @@ void CUCode_Zelda::Update(int cycles)
if (m_rMailHandler.GetNextMail() == DSP_FRAME_END)
g_dspInitialize.pGenerateDSPInterrupt();
}
if (NeedsResumeMail())
{
m_rMailHandler.PushMail(DSP_RESUME);
g_dspInitialize.pGenerateDSPInterrupt();
}
}
void CUCode_Zelda::HandleMail(u32 _uMail)
@ -284,6 +292,13 @@ void CUCode_Zelda::HandleMail_SMSVersion(u32 _uMail)
void CUCode_Zelda::HandleMail_NormalVersion(u32 _uMail)
{
// WARN_LOG(DSPHLE, "Zelda uCode: Handle mail %08X", _uMail);
if (m_UploadSetupInProgress) // evaluated first!
{
PrepareBootUCode(_uMail);
return;
}
if (m_bSyncInProgress)
{
if (m_bSyncCmdPending)
@ -381,23 +396,31 @@ void CUCode_Zelda::HandleMail_NormalVersion(u32 _uMail)
m_numSteps = _uMail;
m_step = 0;
}
else if ((_uMail >> 16) == 0xCDD1) // A 0xCDD1000X mail should come right after we send a DSP_SYNCEND mail
else if ((_uMail >> 16) == 0xCDD1) // A 0xCDD1000X mail should come right after we send a DSP_FRAME_END mail
{
// The low part of the mail tells the operation to perform
// Seeing as every possible operation number halts the uCode,
// except 3, that thing seems to be intended for debugging
switch (_uMail & 0xFFFF)
{
case 0x0003: // Do nothing
case 0x0003: // Do nothing - continue normally
return;
case 0x0000: // Halt
case 0x0001: // Dump memory? and halt
case 0x0002: // Do something and halt
case 0x0001: // accepts params to either dma to iram and/or dram (used for hotbooting a new ucode)
// TODO find a better way to protect from HLEMixer?
soundStream->GetMixer()->SetHLEReady(false);
m_UploadSetupInProgress = true;
return;
case 0x0002: // Let IROM play us off
CDSPHandler::GetInstance().SetUCode(UCODE_ROM);
return;
case 0x0000: // Halt
WARN_LOG(DSPHLE, "Zelda uCode: received halting operation %04X", _uMail & 0xFFFF);
return;
default: // Invalid (the real ucode would likely crash)
default: // Invalid (the real ucode would likely crash)
WARN_LOG(DSPHLE, "Zelda uCode: received invalid operation %04X", _uMail & 0xFFFF);
return;
}
@ -594,6 +617,8 @@ void CUCode_Zelda::DoState(PointerWrap &p)
p.Do(m_PBAddress);
p.Do(m_PBAddress2);
p.Do(m_UploadSetupInProgress);
m_rMailHandler.DoState(p);
m_csMix.Leave();

View File

@ -25,6 +25,9 @@
#include "UCode_ROM.h"
#include "UCode_CARD.h"
#include "UCode_InitAudioSystem.h"
#include "UCode_GBA.h"
#include "Hash.h"
#include "../DSPHandler.h"
IUCode* UCodeFactory(u32 _CRC, CMailHandler& _rMailHandler)
{
@ -42,14 +45,18 @@ IUCode* UCodeFactory(u32 _CRC, CMailHandler& _rMailHandler)
INFO_LOG(DSPHLE, "Switching to CARD ucode");
return new CUCode_CARD(_rMailHandler);
case 0xdd7e72d5:
INFO_LOG(DSPHLE, "Switching to GBA ucode");
return new CUCode_GBA(_rMailHandler);
case 0x3ad3b7ac: // Naruto3, Paper Mario - The Thousand Year Door
case 0x3daf59b9: // Alien Hominid
case 0x4e8a8b21: // spdemo, ctaxi, 18 wheeler, disney, monkeyball 1/2,cubivore,puzzlecollection,wario,
// capcom vs snk, naruto2, lost kingdoms, star fox, mario party 4, mortal kombat,
// smugglers run warzone, smash brothers, sonic mega collection, ZooCube
// nddemo, starfox
// capcom vs snk, naruto2, lost kingdoms, star fox, mario party 4, mortal kombat,
// smugglers run warzone, smash brothers, sonic mega collection, ZooCube
// nddemo, starfox
case 0x07f88145: // bustamove, ikaruga, fzero, robotech battle cry, star soldier, soul calibur2,
// Zelda:OOT, Tony hawk, viewtiful joe
// Zelda:OOT, Tony hawk, viewtiful joe
case 0xe2136399: // billy hatcher, dragonballz, mario party 5, TMNT, ava1080
INFO_LOG(DSPHLE, "CRC %08x: AX ucode chosen", _CRC);
return new CUCode_AX(_rMailHandler);
@ -103,4 +110,65 @@ IUCode* UCodeFactory(u32 _CRC, CMailHandler& _rMailHandler)
return NULL;
}
bool IUCode::NeedsResumeMail()
{
if (m_NeedsResumeMail)
{
m_NeedsResumeMail = false;
return true;
}
return false;
}
void IUCode::PrepareBootUCode(u32 mail)
{
switch (m_NextUCode_steps)
{
case 0: m_NextUCode.mram_dest_addr = mail; break;
case 1: m_NextUCode.mram_size = mail & 0xffff; break;
case 2: m_NextUCode.mram_dram_addr = mail & 0xffff; break;
case 3: m_NextUCode.iram_mram_addr = mail; break;
case 4: m_NextUCode.iram_size = mail & 0xffff; break;
case 5: m_NextUCode.iram_dest = mail & 0xffff; break;
case 6: m_NextUCode.iram_startpc = mail & 0xffff; break;
case 7: m_NextUCode.dram_mram_addr = mail; break;
case 8: m_NextUCode.dram_size = mail & 0xffff; break;
case 9: m_NextUCode.dram_dest = mail & 0xffff; break;
}
m_NextUCode_steps++;
if (m_NextUCode_steps == 10)
{
m_NextUCode_steps = 0;
m_NeedsResumeMail = true;
m_UploadSetupInProgress = false;
u32 ector_crc = HashEctor(
(u8*)Memory_Get_Pointer(m_NextUCode.iram_mram_addr),
m_NextUCode.iram_size);
DEBUG_LOG(DSPHLE, "PrepareBootUCode 0x%08x", ector_crc);
DEBUG_LOG(DSPHLE, "DRAM -> MRAM: src %04x dst %08x size %04x",
m_NextUCode.mram_dram_addr, m_NextUCode.mram_dest_addr,
m_NextUCode.mram_size);
DEBUG_LOG(DSPHLE, "MRAM -> IRAM: src %08x dst %04x size %04x startpc %04x",
m_NextUCode.iram_mram_addr, m_NextUCode.iram_dest,
m_NextUCode.iram_size, m_NextUCode.iram_startpc);
DEBUG_LOG(DSPHLE, "MRAM -> DRAM: src %08x dst %04x size %04x",
m_NextUCode.dram_mram_addr, m_NextUCode.dram_dest,
m_NextUCode.dram_size);
if (m_NextUCode.mram_size)
{
WARN_LOG(DSPHLE,
"Trying to boot new ucode with dram download - not implemented");
}
if (m_NextUCode.dram_size)
{
WARN_LOG(DSPHLE,
"Trying to boot new ucode with dram upload - not implemented");
}
CDSPHandler::GetInstance().SwapUCode(ector_crc);
}
}

View File

@ -32,6 +32,10 @@ class IUCode
public:
IUCode(CMailHandler& _rMailHandler)
: m_rMailHandler(_rMailHandler)
, m_NextUCode_steps(0)
, m_NextUCode()
, m_NeedsResumeMail(false)
, m_UploadSetupInProgress(false)
{}
virtual ~IUCode()
@ -46,6 +50,13 @@ public:
virtual void DoState(PointerWrap &p) {}
protected:
void PrepareBootUCode(u32 mail);
// Some ucodes (notably zelda) require a resume mail to be
// sent if they are be started via PrepareBootUCode.
// The HLE can use this to
bool NeedsResumeMail();
CMailHandler& m_rMailHandler;
Common::CriticalSection m_csMix;
@ -58,6 +69,29 @@ protected:
DSP_SYNC = 0xDCD10004,
DSP_FRAME_END = 0xDCD10005,
};
// UCode is forwarding mails to PrepareBootUCode
// UCode only needs to set this to true, IUCode will set to false when done!
bool m_UploadSetupInProgress;
private:
struct SUCode
{
u32 mram_dest_addr;
u16 mram_size;
u16 mram_dram_addr;
u32 iram_mram_addr;
u16 iram_size;
u16 iram_dest;
u16 iram_startpc;
u32 dram_mram_addr;
u16 dram_size;
u16 dram_dest;
};
SUCode m_NextUCode;
int m_NextUCode_steps;
bool m_NeedsResumeMail;
};
extern IUCode* UCodeFactory(u32 _CRC, CMailHandler& _rMailHandler);

View File

@ -92,6 +92,7 @@ u32 DSPHost_CodeLoaded(const u8 *ptr, int size)
case 0x3daf59b9: success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_D9D066EA.txt"); break;
case 0x4e8a8b21: success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_6A696CE7.txt"); break;
case 0xe2136399: success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_EB79C705.txt"); break;
case 0xdd7e72d5: success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_3B3B30CA.txt"); break;
default: success = false; break;
}