New AXWii now working properly in some games I tested

This commit is contained in:
Pierre Bourdon 2012-11-20 03:13:55 +01:00
parent e750bed2a9
commit 954c55e35a
5 changed files with 429 additions and 325 deletions

View File

@ -16,9 +16,11 @@
// http://code.google.com/p/dolphin-emu/ // http://code.google.com/p/dolphin-emu/
#include "UCode_AX.h" #include "UCode_AX.h"
#include "UCode_AX_Voice.h"
#include "../../DSP.h" #include "../../DSP.h"
#define AX_GC
#include "UCode_AX_Voice.h"
CUCode_AX::CUCode_AX(DSPHLE* dsp_hle, u32 crc) CUCode_AX::CUCode_AX(DSPHLE* dsp_hle, u32 crc)
: IUCode(dsp_hle, crc) : IUCode(dsp_hle, crc)
, m_cmdlist_size(0) , m_cmdlist_size(0)
@ -123,7 +125,7 @@ void CUCode_AX::HandleCommandList()
addr_lo = m_cmdlist[curr_idx++]; addr_lo = m_cmdlist[curr_idx++];
addr2_hi = m_cmdlist[curr_idx++]; addr2_hi = m_cmdlist[curr_idx++];
addr2_lo = m_cmdlist[curr_idx++]; addr2_lo = m_cmdlist[curr_idx++];
MixAUXSamples(cmd == CMD_MIX_AUXA, HILO_TO_32(addr), HILO_TO_32(addr2)); MixAUXSamples(cmd - CMD_MIX_AUXA, HILO_TO_32(addr), HILO_TO_32(addr2));
break; break;
case CMD_UPLOAD_LRS: case CMD_UPLOAD_LRS:
@ -327,40 +329,41 @@ void CUCode_AX::ProcessPBList(u32 pb_addr)
} }
} }
void CUCode_AX::MixAUXSamples(bool AUXA, u32 write_addr, u32 read_addr) void CUCode_AX::MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr)
{ {
int buffers[3][5 * 32]; int temp[3][5 * 32];
int* buffers[3] = { 0 };
switch (aux_id)
{
case 0:
buffers[0] = m_samples_auxA_left;
buffers[1] = m_samples_auxA_right;
buffers[2] = m_samples_auxA_surround;
break;
case 1:
buffers[0] = m_samples_auxB_left;
buffers[1] = m_samples_auxB_right;
buffers[2] = m_samples_auxB_surround;
break;
}
// First, we need to send the contents of our AUX buffers to the CPU. // First, we need to send the contents of our AUX buffers to the CPU.
if (write_addr) if (write_addr)
{ {
for (u32 i = 0; i < 5 * 32; ++i) for (u32 i = 0; i < 3 * 32; ++i)
{ for (u32 j = 0; j < 3; ++j)
if (AUXA) temp[j][i] = Common::swap32(buffers[j][i]);
{ memcpy(HLEMemory_Get_Pointer(write_addr), temp, sizeof (temp));
buffers[0][i] = Common::swap32(m_samples_auxA_left[i]);
buffers[1][i] = Common::swap32(m_samples_auxA_right[i]);
buffers[2][i] = Common::swap32(m_samples_auxA_surround[i]);
}
else
{
buffers[0][i] = Common::swap32(m_samples_auxB_left[i]);
buffers[1][i] = Common::swap32(m_samples_auxB_right[i]);
buffers[2][i] = Common::swap32(m_samples_auxB_surround[i]);
}
}
memcpy(HLEMemory_Get_Pointer(write_addr), buffers, sizeof (buffers));
} }
// Then, we read the new buffers from the CPU and add to our current // Then, we read the new temp from the CPU and add to our current
// buffers. // temp.
memcpy(buffers, HLEMemory_Get_Pointer(read_addr), sizeof (buffers)); memcpy(temp, HLEMemory_Get_Pointer(read_addr), sizeof (temp));
for (u32 i = 0; i < 5 * 32; ++i) for (u32 i = 0; i < 5 * 32; ++i)
{ for (u32 j = 0; j < 3; ++j)
m_samples_left[i] += Common::swap32(buffers[0][i]); buffers[j][i] += Common::swap32(temp[j][i]);
m_samples_right[i] += Common::swap32(buffers[1][i]);
m_samples_surround[i] += Common::swap32(buffers[2][i]);
}
} }
void CUCode_AX::UploadLRS(u32 dst_addr) void CUCode_AX::UploadLRS(u32 dst_addr)
@ -495,5 +498,7 @@ void CUCode_AX::DoState(PointerWrap& p)
{ {
std::lock_guard<std::mutex> lk(m_processing); std::lock_guard<std::mutex> lk(m_processing);
// TODO
DoStateShared(p); DoStateShared(p);
} }

View File

@ -29,7 +29,40 @@
#include "UCodes.h" #include "UCodes.h"
#include "UCode_AXStructs.h" #include "UCode_AXStructs.h"
#include "UCode_AX_Voice.h"
// We can't directly use the mixer_control field from the PB because it does
// not mean the same in all AX versions. The AX UCode converts the
// mixer_control value to an AXMixControl bitfield.
enum AXMixControl
{
MIX_L = 0x000001,
MIX_L_RAMP = 0x000002,
MIX_R = 0x000004,
MIX_R_RAMP = 0x000008,
MIX_S = 0x000010,
MIX_S_RAMP = 0x000020,
MIX_AUXA_L = 0x000040,
MIX_AUXA_L_RAMP = 0x000080,
MIX_AUXA_R = 0x000100,
MIX_AUXA_R_RAMP = 0x000200,
MIX_AUXA_S = 0x000400,
MIX_AUXA_S_RAMP = 0x000800,
MIX_AUXB_L = 0x001000,
MIX_AUXB_L_RAMP = 0x002000,
MIX_AUXB_R = 0x004000,
MIX_AUXB_R_RAMP = 0x008000,
MIX_AUXB_S = 0x010000,
MIX_AUXB_S_RAMP = 0x020000,
MIX_AUXC_L = 0x040000,
MIX_AUXC_L_RAMP = 0x080000,
MIX_AUXC_R = 0x100000,
MIX_AUXC_R_RAMP = 0x200000,
MIX_AUXC_S = 0x400000,
MIX_AUXC_S_RAMP = 0x800000
};
class CUCode_AX : public IUCode class CUCode_AX : public IUCode
{ {
@ -37,16 +70,16 @@ public:
CUCode_AX(DSPHLE* dsp_hle, u32 crc); CUCode_AX(DSPHLE* dsp_hle, u32 crc);
virtual ~CUCode_AX(); virtual ~CUCode_AX();
void HandleMail(u32 mail); virtual void HandleMail(u32 mail);
void MixAdd(short* out_buffer, int nsamples); virtual void MixAdd(short* out_buffer, int nsamples);
void Update(int cycles); virtual void Update(int cycles);
void DoState(PointerWrap& p); virtual void DoState(PointerWrap& p);
// Needed because StdThread.h std::thread implem does not support member // Needed because StdThread.h std::thread implem does not support member
// pointers. // pointers.
static void SpawnAXThread(CUCode_AX* self); static void SpawnAXThread(CUCode_AX* self);
private: protected:
enum MailType enum MailType
{ {
MAIL_RESUME = 0xCDD10000, MAIL_RESUME = 0xCDD10000,
@ -59,31 +92,7 @@ private:
MAIL_CMDLIST_MASK = 0xFFFF0000 MAIL_CMDLIST_MASK = 0xFFFF0000
}; };
enum CmdType // 32 * 5 because 32 samples per millisecond, for max 5 milliseconds.
{
CMD_SETUP = 0x00,
CMD_UNK_01 = 0x01,
CMD_PB_ADDR = 0x02,
CMD_PROCESS = 0x03,
CMD_MIX_AUXA = 0x04,
CMD_MIX_AUXB = 0x05,
CMD_UPLOAD_LRS = 0x06,
CMD_SBUFFER_ADDR = 0x07,
CMD_UNK_08 = 0x08,
CMD_MIX_AUXB_NOWRITE = 0x09,
CMD_COMPRESSOR_TABLE_ADDR = 0x0A,
CMD_UNK_0B = 0x0B,
CMD_UNK_0C = 0x0C,
CMD_MORE = 0x0D,
CMD_OUTPUT = 0x0E,
CMD_END = 0x0F,
CMD_UNK_10 = 0x10,
CMD_UNK_11 = 0x11,
CMD_UNK_12 = 0x12,
CMD_UNK_13 = 0x13,
};
// 32 * 5 because 32 samples per millisecond, for 5 milliseconds.
int m_samples_left[32 * 5]; int m_samples_left[32 * 5];
int m_samples_right[32 * 5]; int m_samples_right[32 * 5];
int m_samples_surround[32 * 5]; int m_samples_surround[32 * 5];
@ -119,12 +128,39 @@ private:
void NotifyAXThread(); void NotifyAXThread();
void AXThread(); void AXThread();
void HandleCommandList();
void SetupProcessing(u32 studio_addr); virtual void HandleCommandList();
void SetupProcessing(u32 init_addr);
void ProcessPBList(u32 pb_addr); void ProcessPBList(u32 pb_addr);
void MixAUXSamples(bool AUXA, u32 write_addr, u32 read_addr); void MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr);
void UploadLRS(u32 dst_addr); void UploadLRS(u32 dst_addr);
void OutputSamples(u32 out_addr); void OutputSamples(u32 out_addr);
private:
enum CmdType
{
CMD_SETUP = 0x00,
CMD_UNK_01 = 0x01,
CMD_PB_ADDR = 0x02,
CMD_PROCESS = 0x03,
CMD_MIX_AUXA = 0x04,
CMD_MIX_AUXB = 0x05,
CMD_UPLOAD_LRS = 0x06,
CMD_SBUFFER_ADDR = 0x07,
CMD_UNK_08 = 0x08,
CMD_MIX_AUXB_NOWRITE = 0x09,
CMD_COMPRESSOR_TABLE_ADDR = 0x0A,
CMD_UNK_0B = 0x0B,
CMD_UNK_0C = 0x0C,
CMD_MORE = 0x0D,
CMD_OUTPUT = 0x0E,
CMD_END = 0x0F,
CMD_UNK_10 = 0x10,
CMD_UNK_11 = 0x11,
CMD_UNK_12 = 0x12,
CMD_UNK_13 = 0x13,
};
}; };
#endif // !_UCODE_AX_H #endif // !_UCODE_AX_H

View File

@ -23,249 +23,294 @@
#include "UCodes.h" #include "UCodes.h"
#include "UCode_AXStructs.h" #include "UCode_AXStructs.h"
#include "UCode_AXWii.h" #include "UCode_AXWii.h"
#define AX_WII
#include "UCode_AX_Voice.h" #include "UCode_AX_Voice.h"
CUCode_AXWii::CUCode_AXWii(DSPHLE *dsp_hle, u32 l_CRC) CUCode_AXWii::CUCode_AXWii(DSPHLE *dsp_hle, u32 l_CRC)
: IUCode(dsp_hle, l_CRC) : CUCode_AX(dsp_hle, l_CRC)
, m_addressPBs(0xFFFFFFFF)
{ {
// we got loaded WARN_LOG(DSPHLE, "Instantiating CUCode_AXWii");
m_rMailHandler.PushMail(DSP_INIT);
templbuffer = new int[1024 * 1024];
temprbuffer = new int[1024 * 1024];
wiisportsHack = m_CRC == 0xfa450138;
} }
CUCode_AXWii::~CUCode_AXWii() CUCode_AXWii::~CUCode_AXWii()
{ {
m_rMailHandler.Clear();
delete [] templbuffer;
delete [] temprbuffer;
} }
void CUCode_AXWii::HandleMail(u32 _uMail) void CUCode_AXWii::HandleCommandList()
{ {
if (m_UploadSetupInProgress) // Temp variables for addresses computation
u16 addr_hi, addr_lo;
u16 addr2_hi, addr2_lo;
u16 volume;
// WARN_LOG(DSPHLE, "Command list:");
// for (u32 i = 0; m_cmdlist[i] != CMD_END; ++i)
// WARN_LOG(DSPHLE, "%04x", m_cmdlist[i]);
// WARN_LOG(DSPHLE, "-------------");
u32 curr_idx = 0;
bool end = false;
while (!end)
{ {
PrepareBootUCode(_uMail); u16 cmd = m_cmdlist[curr_idx++];
return;
}
else if ((_uMail & 0xFFFF0000) == MAIL_AX_ALIST)
{
// We are expected to get a new CmdBlock
DEBUG_LOG(DSPHLE, "GetNextCmdBlock (%ibytes)", (u16)_uMail);
}
else switch(_uMail)
{
case 0xCDD10000: // Action 0 - AX_ResumeTask()
m_rMailHandler.PushMail(DSP_RESUME);
break;
case 0xCDD10001: // Action 1 - new ucode upload switch (cmd)
DEBUG_LOG(DSPHLE,"DSP IROM - New Ucode!");
// TODO find a better way to protect from HLEMixer?
soundStream->GetMixer()->SetHLEReady(false);
m_UploadSetupInProgress = true;
break;
case 0xCDD10002: // Action 2 - IROM_Reset(); ( WII: De Blob, Cursed Mountain,...)
DEBUG_LOG(DSPHLE,"DSP IROM - Reset!");
m_DSPHLE->SetUCode(UCODE_ROM);
return;
case 0xCDD10003: // Action 3 - AX_GetNextCmdBlock()
break;
default:
DEBUG_LOG(DSPHLE, " >>>> u32 MAIL : AXTask Mail (%08x)", _uMail);
AXTask(_uMail);
break;
}
}
void CUCode_AXWii::MixAdd(short* _pBuffer, int _iSize)
{
AXPBWii PB;
if (_iSize > 1024 * 1024)
_iSize = 1024 * 1024;
memset(templbuffer, 0, _iSize * sizeof(int));
memset(temprbuffer, 0, _iSize * sizeof(int));
u32 blockAddr = m_addressPBs;
if (!blockAddr)
return;
AXBuffers buffers = {{
templbuffer,
temprbuffer,
NULL
}};
for (int i = 0; i < NUMBER_OF_PBS; i++)
{
if (!ReadPB(blockAddr, PB))
break;
// if (wiisportsHack)
// MixAddVoice(*(AXPBWiiSports*)&PB, buffers, _iSize);
// else
// MixAddVoice(PB, buffers, _iSize);
if (!WritePB(blockAddr, PB))
break;
// next PB, or done
blockAddr = (PB.next_pb_hi << 16) | PB.next_pb_lo;
if (!blockAddr)
break;
}
// We write the sound to _pBuffer
if (_pBuffer)
{
for (int i = 0; i < _iSize; i++)
{ {
// Clamp into 16-bit. Maybe we should add a volume compressor here. // Some of these commands are unknown, or unused in this AX HLE.
int left = templbuffer[i] + _pBuffer[0]; // We still need to skip their arguments using "curr_idx += N".
int right = temprbuffer[i] + _pBuffer[1];
if (left < -32767) left = -32767; case CMD_SETUP:
else if (left > 32767) left = 32767; addr_hi = m_cmdlist[curr_idx++];
if (right < -32767) right = -32767; addr_lo = m_cmdlist[curr_idx++];
else if (right > 32767) right = 32767; SetupProcessing(HILO_TO_32(addr));
*_pBuffer++ = left; break;
*_pBuffer++ = right;
case CMD_UNK_01: curr_idx += 2; break;
case CMD_UNK_02: curr_idx += 2; break;
case CMD_UNK_03: curr_idx += 2; break;
case CMD_PROCESS:
addr_hi = m_cmdlist[curr_idx++];
addr_lo = m_cmdlist[curr_idx++];
ProcessPBList(HILO_TO_32(addr));
break;
case CMD_MIX_AUXA:
case CMD_MIX_AUXB:
case CMD_MIX_AUXC:
curr_idx++; // TODO: Unknown u16
addr_hi = m_cmdlist[curr_idx++];
addr_lo = m_cmdlist[curr_idx++];
addr2_hi = m_cmdlist[curr_idx++];
addr2_lo = m_cmdlist[curr_idx++];
MixAUXSamples(cmd - CMD_MIX_AUXA, HILO_TO_32(addr), HILO_TO_32(addr2));
break;
// These two go together and manipulate some AUX buffers.
case CMD_UNK_08: curr_idx += 13; break;
case CMD_UNK_09: curr_idx += 13; break;
case CMD_UNK_0A: curr_idx += 4; break;
case CMD_OUTPUT:
volume = m_cmdlist[curr_idx++];
addr_hi = m_cmdlist[curr_idx++];
addr_lo = m_cmdlist[curr_idx++];
addr2_hi = m_cmdlist[curr_idx++];
addr2_lo = m_cmdlist[curr_idx++];
OutputSamples(HILO_TO_32(addr2), HILO_TO_32(addr), volume);
break;
case CMD_UNK_0C: curr_idx += 5; break;
case CMD_UNK_0D:
// Wiimote output?
curr_idx += 8;
break;
case CMD_END:
end = true;
break;
} }
} }
} }
void CUCode_AXWii::SetupProcessing(u32 init_addr)
void CUCode_AXWii::Update(int cycles)
{ {
if (NeedsResumeMail()) // TODO: should be easily factorizable with AX
s16 init_data[60];
for (u32 i = 0; i < 60; ++i)
init_data[i] = HLEMemory_Read_U16(init_addr + 2 * i);
// List of all buffers we have to initialize
int* buffers[] = {
m_samples_left,
m_samples_right,
m_samples_surround,
m_samples_auxA_left,
m_samples_auxA_right,
m_samples_auxA_surround,
m_samples_auxB_left,
m_samples_auxB_right,
m_samples_auxB_surround,
m_samples_auxC_left,
m_samples_auxC_right,
m_samples_auxC_surround
};
u32 init_idx = 0;
for (u32 i = 0; i < sizeof (buffers) / sizeof (buffers[0]); ++i)
{ {
m_rMailHandler.PushMail(DSP_RESUME); s32 init_val = (s32)((init_data[init_idx] << 16) | init_data[init_idx + 1]);
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); s16 delta = (s16)init_data[init_idx + 2];
}
// check if we have to send something init_idx += 3;
else if (!m_rMailHandler.IsEmpty())
{ if (!init_val)
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); memset(buffers[i], 0, 3 * 32 * sizeof (int));
else
{
for (u32 j = 0; j < 3 * 32; ++j)
{
buffers[i][j] = init_val;
init_val += delta;
}
}
} }
} }
// AX seems to bootup one task only and waits for resume-callbacks AXMixControl CUCode_AXWii::ConvertMixerControl(u32 mixer_control)
// everytime the DSP has "spare time" it sends a resume-mail to the CPU
// and the __DSPHandler calls a AX-Callback which generates a new AXFrame
bool CUCode_AXWii::AXTask(u32& _uMail)
{ {
u32 uAddress = _uMail; u32 ret = 0;
u32 Addr__AXStudio;
u32 Addr__AXOutSBuffer;
bool bExecuteList = true;
/* if (mixer_control & 0x00000001) ret |= MIX_L;
for (int i=0;i<64;i++) { if (mixer_control & 0x00000002) ret |= MIX_R;
NOTICE_LOG(DSPHLE,"%x - %08x",uAddress+(i*4),HLEMemory_Read_U32(uAddress+(i*4))); if (mixer_control & 0x00000004) ret |= MIX_L_RAMP | MIX_R_RAMP;
} if (mixer_control & 0x00000008) ret |= MIX_S;
*/ if (mixer_control & 0x00000010) ret |= MIX_S_RAMP;
if (mixer_control & 0x00010000) ret |= MIX_AUXA_L;
if (mixer_control & 0x00020000) ret |= MIX_AUXA_R;
if (mixer_control & 0x00040000) ret |= MIX_AUXA_L_RAMP | MIX_AUXA_R_RAMP;
if (mixer_control & 0x00080000) ret |= MIX_AUXA_S;
if (mixer_control & 0x00100000) ret |= MIX_AUXA_S_RAMP;
if (mixer_control & 0x00200000) ret |= MIX_AUXB_L;
if (mixer_control & 0x00400000) ret |= MIX_AUXB_R;
if (mixer_control & 0x00800000) ret |= MIX_AUXB_L_RAMP | MIX_AUXB_R_RAMP;
if (mixer_control & 0x01000000) ret |= MIX_AUXB_S;
if (mixer_control & 0x02000000) ret |= MIX_AUXB_S_RAMP;
if (mixer_control & 0x04000000) ret |= MIX_AUXC_L;
if (mixer_control & 0x08000000) ret |= MIX_AUXC_R;
if (mixer_control & 0x10000000) ret |= MIX_AUXC_L_RAMP | MIX_AUXC_R_RAMP;
if (mixer_control & 0x20000000) ret |= MIX_AUXC_S;
if (mixer_control & 0x40000000) ret |= MIX_AUXC_S_RAMP;
while (bExecuteList) return (AXMixControl)ret;
}
void CUCode_AXWii::ProcessPBList(u32 pb_addr)
{
const u32 spms = 32;
AXPBWii pb;
while (pb_addr)
{ {
u16 iCommand = HLEMemory_Read_U16(uAddress); AXBuffers buffers = {{
uAddress += 2; m_samples_left,
//NOTICE_LOG(DSPHLE,"AXWII - AXLIST CMD %X",iCommand); m_samples_right,
m_samples_surround,
m_samples_auxA_left,
m_samples_auxA_right,
m_samples_auxA_surround,
m_samples_auxB_left,
m_samples_auxB_right,
m_samples_auxB_surround,
m_samples_auxC_left,
m_samples_auxC_right,
m_samples_auxC_surround
}};
switch (iCommand) if (!ReadPB(pb_addr, pb))
break;
for (int curr_ms = 0; curr_ms < 3; ++curr_ms)
{ {
case 0x0000: Process1ms(pb, buffers, ConvertMixerControl(HILO_TO_32(pb.mixer_control)));
Addr__AXStudio = HLEMemory_Read_U32(uAddress);
uAddress += 4;
break;
case 0x0001: // Forward the buffers
uAddress += 4; for (u32 i = 0; i < sizeof (buffers.ptrs) / sizeof (buffers.ptrs[0]); ++i)
break; buffers.ptrs[i] += spms;
case 0x0003:
uAddress += 4;
break;
case 0x0004:
// PBs are here now
m_addressPBs = HLEMemory_Read_U32(uAddress);
soundStream->GetMixer()->SetHLEReady(true);
// soundStream->Update();
uAddress += 4;
break;
case 0x0005:
if (!wiisportsHack)
uAddress += 10;
break;
case 0x0006:
uAddress += 10;
break;
case 0x0007: // AXLIST_SBUFFER
Addr__AXOutSBuffer = HLEMemory_Read_U32(uAddress);
uAddress += 10;
break;
case 0x0008:
uAddress += 26;
break;
case 0x000a:
uAddress += wiisportsHack ? 4 : 8; // AXLIST_COMPRESSORTABLE
break;
case 0x000b:
uAddress += wiisportsHack ? 2 : 10;
break;
case 0x000c:
uAddress += wiisportsHack ? 8 : 10;
break;
case 0x000d:
uAddress += 16;
break;
case 0x000e:
if (wiisportsHack)
uAddress += 16;
else
bExecuteList = false;
break;
case 0x000f: // only for Wii Sports uCode
bExecuteList = false;
break;
default:
INFO_LOG(DSPHLE,"DSPHLE - AXwii - AXLIST - Unknown CMD: %x",iCommand);
// unknown command so stop the execution of this TaskList
bExecuteList = false;
break;
} }
WritePB(pb_addr, pb);
pb_addr = HILO_TO_32(pb.next_pb);
}
}
void CUCode_AXWii::MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr)
{
int temp[3][3 * 32];
int* buffers[3] = { 0 };
switch (aux_id)
{
case 0:
buffers[0] = m_samples_auxA_left;
buffers[1] = m_samples_auxA_right;
buffers[2] = m_samples_auxA_surround;
break;
case 1:
buffers[0] = m_samples_auxB_left;
buffers[1] = m_samples_auxB_right;
buffers[2] = m_samples_auxB_surround;
break;
case 2:
buffers[0] = m_samples_auxC_left;
buffers[1] = m_samples_auxC_right;
buffers[2] = m_samples_auxC_surround;
break;
} }
m_rMailHandler.PushMail(DSP_YIELD); //its here in case there is a CMD fuckup // Send the content of AUX buffers to the CPU
return true; if (write_addr)
{
for (u32 i = 0; i < 3 * 32; ++i)
for (u32 j = 0; j < 3; ++j)
temp[j][i] = Common::swap32(buffers[j][i]);
memcpy(HLEMemory_Get_Pointer(write_addr), temp, sizeof (temp));
}
// Then read the buffers from the CPU and add to our current buffers.
memcpy(temp, HLEMemory_Get_Pointer(read_addr), sizeof (temp));
for (u32 i = 0; i < 3 * 32; ++i)
for (u32 j = 0; j < 3; ++j)
buffers[j][i] += Common::swap32(temp[j][i]);
}
void CUCode_AXWii::OutputSamples(u32 lr_addr, u32 surround_addr, u16 volume)
{
int surround_buffer[3 * 32] = { 0 };
for (u32 i = 0; i < 3 * 32; ++i)
surround_buffer[i] = Common::swap32(m_samples_surround[i]);
memcpy(HLEMemory_Get_Pointer(surround_addr), surround_buffer, sizeof (surround_buffer));
short buffer[3 * 32 * 2];
// Clamp internal buffers to 16 bits.
for (u32 i = 0; i < 3 * 32; ++i)
{
int left = m_samples_left[i];
int right = m_samples_right[i];
if (left < -32767) left = -32767;
if (left > 32767) left = 32767;
if (right < -32767) right = -32767;
if (right > 32767) right = 32767;
m_samples_left[i] = left;
m_samples_right[i] = right;
}
for (u32 i = 0; i < 3 * 32; ++i)
{
buffer[2 * i] = Common::swap16(m_samples_left[i]);
buffer[2 * i + 1] = Common::swap16(m_samples_right[i]);
}
memcpy(HLEMemory_Get_Pointer(lr_addr), buffer, sizeof (buffer));
} }
void CUCode_AXWii::DoState(PointerWrap &p) void CUCode_AXWii::DoState(PointerWrap &p)
{ {
std::lock_guard<std::mutex> lk(m_csMix); std::lock_guard<std::mutex> lk(m_csMix);
p.Do(m_addressPBs); // TODO
p.Do(wiisportsHack);
DoStateShared(p); DoStateShared(p);
} }

View File

@ -12,44 +12,58 @@
// A copy of the GPL 2.0 should have been included with the program. // A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/ // If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at // Official Git repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/ // http://code.google.com/p/dolphin-emu/
#ifndef _UCODE_AXWII #ifndef _UCODE_AXWII_H
#define _UCODE_AXWII #define _UCODE_AXWII_H
#include "UCode_AXStructs.h" #include "UCode_AX.h"
#define NUMBER_OF_PBS 128 class CUCode_AXWii : public CUCode_AX
class CUCode_AXWii : public IUCode
{ {
public: public:
CUCode_AXWii(DSPHLE *dsp_hle, u32 _CRC); CUCode_AXWii(DSPHLE *dsp_hle, u32 _CRC);
virtual ~CUCode_AXWii(); virtual ~CUCode_AXWii();
void HandleMail(u32 _uMail); virtual void DoState(PointerWrap &p);
void MixAdd(short* _pBuffer, int _iSize);
void Update(int cycles); protected:
void DoState(PointerWrap &p); int m_samples_auxC_left[32 * 3];
int m_samples_auxC_right[32 * 3];
int m_samples_auxC_surround[32 * 3];
// Convert a mixer_control bitfield to our internal representation for that
// value. Required because that bitfield has a different meaning in some
// versions of AX.
AXMixControl ConvertMixerControl(u32 mixer_control);
virtual void HandleCommandList();
void SetupProcessing(u32 init_addr);
void ProcessPBList(u32 pb_addr);
void MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr);
void OutputSamples(u32 lr_addr, u32 surround_addr, u16 volume);
private: private:
enum enum CmdType
{ {
MAIL_AX_ALIST = 0xBABE0000, CMD_SETUP = 0x00,
CMD_UNK_01 = 0x01,
CMD_UNK_02 = 0x02,
CMD_UNK_03 = 0x03,
CMD_PROCESS = 0x04,
CMD_MIX_AUXA = 0x05,
CMD_MIX_AUXB = 0x06,
CMD_MIX_AUXC = 0x07,
CMD_UNK_08 = 0x08,
CMD_UNK_09 = 0x09,
CMD_UNK_0A = 0x0A,
CMD_OUTPUT = 0x0B,
CMD_UNK_0C = 0x0C,
CMD_UNK_0D = 0x0D,
CMD_END = 0x0E
}; };
// PBs
u32 m_addressPBs;
bool wiisportsHack;
int *templbuffer;
int *temprbuffer;
// ax task message handler
bool AXTask(u32& _uMail);
void SendMail(u32 _uMail);
}; };
#endif // _UCODE_AXWII #endif // _UCODE_AXWII

View File

@ -15,13 +15,27 @@
// Official Git repository and contact information can be found at // Official Git repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/ // http://code.google.com/p/dolphin-emu/
// This file is UGLY (full of #ifdef) so that it can be used with both GC and
// Wii version of AX. Maybe it would be better to abstract away the parts that
// can be made common.
#ifndef _UCODE_AX_VOICE_H #ifndef _UCODE_AX_VOICE_H
#define _UCODE_AX_VOICE_H #define _UCODE_AX_VOICE_H
#if !defined(AX_GC) && !defined(AX_WII)
#error UCode_AX_Voice.h included without specifying version
#endif
#include "Common.h" #include "Common.h"
#include "UCode_AXStructs.h" #include "UCode_AXStructs.h"
#include "../../DSP.h" #include "../../DSP.h"
#ifdef AX_GC
# define PB_TYPE AXPB
#else
# define PB_TYPE AXPBWii
#endif
// Useful macro to convert xxx_hi + xxx_lo to xxx for 32 bits. // Useful macro to convert xxx_hi + xxx_lo to xxx for 32 bits.
#define HILO_TO_32(name) \ #define HILO_TO_32(name) \
((name##_hi << 16) | name##_lo) ((name##_hi << 16) | name##_lo)
@ -42,41 +56,23 @@ union AXBuffers
int* auxB_left; int* auxB_left;
int* auxB_right; int* auxB_right;
int* auxB_surround; int* auxB_surround;
#ifdef AX_WII
int* auxC_left;
int* auxC_right;
int* auxC_surround;
#endif
}; };
#ifdef AX_GC
int* ptrs[9]; int* ptrs[9];
}; #else
int* ptrs[12];
// We can't directly use the mixer_control field from the PB because it does #endif
// not mean the same in all AX versions. The AX UCode converts the
// mixer_control value to an AXMixControl bitfield.
enum AXMixControl
{
MIX_L = 0x00001,
MIX_L_RAMP = 0x00002,
MIX_R = 0x00004,
MIX_R_RAMP = 0x00008,
MIX_S = 0x00010,
MIX_S_RAMP = 0x00020,
MIX_AUXA_L = 0x00040,
MIX_AUXA_L_RAMP = 0x00080,
MIX_AUXA_R = 0x00100,
MIX_AUXA_R_RAMP = 0x00200,
MIX_AUXA_S = 0x00400,
MIX_AUXA_S_RAMP = 0x00800,
MIX_AUXB_L = 0x01000,
MIX_AUXB_L_RAMP = 0x02000,
MIX_AUXB_R = 0x04000,
MIX_AUXB_R_RAMP = 0x08000,
MIX_AUXB_S = 0x10000,
MIX_AUXB_S_RAMP = 0x20000
}; };
// Read a PB from MRAM/ARAM // Read a PB from MRAM/ARAM
template <typename PBType> bool ReadPB(u32 addr, PB_TYPE& pb)
bool ReadPB(u32 addr, PBType& pb)
{ {
u16* dst = (u16*)&pb; u16* dst = (u16*)&pb;
const u16* src = (const u16*)Memory::GetPointer(addr); const u16* src = (const u16*)Memory::GetPointer(addr);
@ -90,8 +86,7 @@ bool ReadPB(u32 addr, PBType& pb)
} }
// Write a PB back to MRAM/ARAM // Write a PB back to MRAM/ARAM
template <typename PBType> inline bool WritePB(u32 addr, const PB_TYPE& pb)
inline bool WritePB(u32 addr, const PBType& pb)
{ {
const u16* src = (const u16*)&pb; const u16* src = (const u16*)&pb;
u16* dst = (u16*)Memory::GetPointer(addr); u16* dst = (u16*)Memory::GetPointer(addr);
@ -107,10 +102,10 @@ inline bool WritePB(u32 addr, const PBType& pb)
// Simulated accelerator state. // Simulated accelerator state.
static u32 acc_loop_addr, acc_end_addr; static u32 acc_loop_addr, acc_end_addr;
static u32* acc_cur_addr; static u32* acc_cur_addr;
static AXPB* acc_pb; static PB_TYPE* acc_pb;
// Sets up the simulated accelerator. // Sets up the simulated accelerator.
inline void AcceleratorSetup(AXPB* pb, u32* cur_addr) inline void AcceleratorSetup(PB_TYPE* pb, u32* cur_addr)
{ {
acc_pb = pb; acc_pb = pb;
acc_loop_addr = HILO_TO_32(pb->audio_addr.loop_addr); acc_loop_addr = HILO_TO_32(pb->audio_addr.loop_addr);
@ -216,7 +211,7 @@ inline u16 AcceleratorGetSample()
} }
// Read 32 input samples from ARAM, decoding and converting rate if required. // Read 32 input samples from ARAM, decoding and converting rate if required.
inline void GetInputSamples(AXPB& pb, s16* samples) inline void GetInputSamples(PB_TYPE& pb, s16* samples)
{ {
u32 cur_addr = HILO_TO_32(pb.audio_addr.cur_addr); u32 cur_addr = HILO_TO_32(pb.audio_addr.cur_addr);
AcceleratorSetup(&pb, &cur_addr); AcceleratorSetup(&pb, &cur_addr);
@ -319,7 +314,7 @@ inline void MixAdd(int* out, const s16* input, u16* pvol, bool ramp)
} }
// Process 1ms of audio (32 samples) from a PB and mix it to the buffers. // Process 1ms of audio (32 samples) from a PB and mix it to the buffers.
inline void Process1ms(AXPB& pb, const AXBuffers& buffers, AXMixControl mctrl) void Process1ms(PB_TYPE& pb, const AXBuffers& buffers, AXMixControl mctrl)
{ {
// If the voice is not running, nothing to do. // If the voice is not running, nothing to do.
if (!pb.running) if (!pb.running)
@ -370,6 +365,15 @@ inline void Process1ms(AXPB& pb, const AXBuffers& buffers, AXMixControl mctrl)
if (mctrl & MIX_AUXB_S) if (mctrl & MIX_AUXB_S)
MixAdd(buffers.auxB_surround, samples, &pb.mixer.auxB_surround, mctrl & MIX_AUXB_S_RAMP); MixAdd(buffers.auxB_surround, samples, &pb.mixer.auxB_surround, mctrl & MIX_AUXB_S_RAMP);
#ifdef AX_WII
if (mctrl & MIX_AUXC_L)
MixAdd(buffers.auxC_left, samples, &pb.mixer.auxC_left, mctrl & MIX_AUXC_L_RAMP);
if (mctrl & MIX_AUXC_R)
MixAdd(buffers.auxC_right, samples, &pb.mixer.auxC_right, mctrl & MIX_AUXC_R_RAMP);
if (mctrl & MIX_AUXC_S)
MixAdd(buffers.auxC_surround, samples, &pb.mixer.auxC_surround, mctrl & MIX_AUXC_S_RAMP);
#endif
// Optionally, phase shift left or right channel to simulate 3D sound. // Optionally, phase shift left or right channel to simulate 3D sound.
if (pb.initial_time_delay.on) if (pb.initial_time_delay.on)
{ {