DSP comments & minor reorganization (moved all DSP state into the g_dsp struct). No functionality change.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@4813 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
hrydgard 2010-01-12 21:38:39 +00:00
parent 532ab905c4
commit af08186daa
8 changed files with 117 additions and 79 deletions

View File

@ -16,6 +16,7 @@
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "DSPCore.h"
#include "DSPHost.h"
#include "DSPHWInterface.h"
@ -24,16 +25,16 @@
// The hardware adpcm decoder :)
s16 ADPCM_Step(u32& _rSamplePos)
{
const s16 *pCoefTable = (const s16 *)&gdsp_ifx_regs[DSP_COEF_A1_0];
const s16 *pCoefTable = (const s16 *)&g_dsp.ifx_regs[DSP_COEF_A1_0];
if (((_rSamplePos) & 15) == 0)
{
gdsp_ifx_regs[DSP_PRED_SCALE] = DSPHost_ReadHostMemory((_rSamplePos & ~15) >> 1);
g_dsp.ifx_regs[DSP_PRED_SCALE] = DSPHost_ReadHostMemory((_rSamplePos & ~15) >> 1);
_rSamplePos += 2;
}
int scale = 1 << (gdsp_ifx_regs[DSP_PRED_SCALE] & 0xF);
int coef_idx = gdsp_ifx_regs[DSP_PRED_SCALE] >> 4;
int scale = 1 << (g_dsp.ifx_regs[DSP_PRED_SCALE] & 0xF);
int coef_idx = g_dsp.ifx_regs[DSP_PRED_SCALE] >> 4;
s32 coef1 = pCoefTable[coef_idx * 2 + 0];
s32 coef2 = pCoefTable[coef_idx * 2 + 1];
@ -46,7 +47,7 @@ s16 ADPCM_Step(u32& _rSamplePos)
temp -= 16;
// 0x400 = 0.5 in 11-bit fixed point
int val = (scale * temp) + ((0x400 + coef1 * (s16)gdsp_ifx_regs[DSP_YN1] + coef2 * (s16)gdsp_ifx_regs[DSP_YN2]) >> 11);
int val = (scale * temp) + ((0x400 + coef1 * (s16)g_dsp.ifx_regs[DSP_YN1] + coef2 * (s16)g_dsp.ifx_regs[DSP_YN2]) >> 11);
// Clamp values.
if (val > 0x7FFF)
@ -54,8 +55,8 @@ s16 ADPCM_Step(u32& _rSamplePos)
else if (val < -0x7FFF)
val = -0x7FFF;
gdsp_ifx_regs[DSP_YN2] = gdsp_ifx_regs[DSP_YN1];
gdsp_ifx_regs[DSP_YN1] = val;
g_dsp.ifx_regs[DSP_YN2] = g_dsp.ifx_regs[DSP_YN1];
g_dsp.ifx_regs[DSP_YN1] = val;
_rSamplePos++;
@ -67,10 +68,10 @@ s16 ADPCM_Step(u32& _rSamplePos)
u16 dsp_read_aram_d3()
{
// Zelda ucode reads ARAM through 0xffd3.
const u32 EndAddress = (gdsp_ifx_regs[DSP_ACEAH] << 16) | gdsp_ifx_regs[DSP_ACEAL];
u32 Address = (gdsp_ifx_regs[DSP_ACCAH] << 16) | gdsp_ifx_regs[DSP_ACCAL];
const u32 EndAddress = (g_dsp.ifx_regs[DSP_ACEAH] << 16) | g_dsp.ifx_regs[DSP_ACEAL];
u32 Address = (g_dsp.ifx_regs[DSP_ACCAH] << 16) | g_dsp.ifx_regs[DSP_ACCAL];
u16 val = 0;
switch (gdsp_ifx_regs[DSP_FORMAT]) {
switch (g_dsp.ifx_regs[DSP_FORMAT]) {
case 0x5: // unsigned 8-bit reads .. I think.
val = DSPHost_ReadHostMemory(Address);
Address++;
@ -80,16 +81,16 @@ u16 dsp_read_aram_d3()
Address += 2;
break;
default:
ERROR_LOG(DSPLLE, "dsp_read_aram_d3: Unseen Format %i", gdsp_ifx_regs[DSP_FORMAT]);
ERROR_LOG(DSPLLE, "dsp_read_aram_d3: Unseen Format %i", g_dsp.ifx_regs[DSP_FORMAT]);
break;
}
if (Address >= EndAddress)
{
// Set address back to start address.
Address = (gdsp_ifx_regs[DSP_ACSAH] << 16) | gdsp_ifx_regs[DSP_ACSAL];
Address = (g_dsp.ifx_regs[DSP_ACSAH] << 16) | g_dsp.ifx_regs[DSP_ACSAL];
}
gdsp_ifx_regs[DSP_ACCAH] = Address >> 16;
gdsp_ifx_regs[DSP_ACCAL] = Address & 0xffff;
g_dsp.ifx_regs[DSP_ACCAH] = Address >> 16;
g_dsp.ifx_regs[DSP_ACCAL] = Address & 0xffff;
return val;
}
@ -97,26 +98,26 @@ void dsp_write_aram_d3(u16 value)
{
// Zelda ucode writes a bunch of zeros to ARAM through d3 during
// initialization. Don't know if it ever does it later, too.
const u32 EndAddress = (gdsp_ifx_regs[DSP_ACEAH] << 16) | gdsp_ifx_regs[DSP_ACEAL];
u32 Address = (gdsp_ifx_regs[DSP_ACCAH] << 16) | gdsp_ifx_regs[DSP_ACCAL];
switch (gdsp_ifx_regs[DSP_FORMAT]) {
const u32 EndAddress = (g_dsp.ifx_regs[DSP_ACEAH] << 16) | g_dsp.ifx_regs[DSP_ACEAL];
u32 Address = (g_dsp.ifx_regs[DSP_ACCAH] << 16) | g_dsp.ifx_regs[DSP_ACCAL];
switch (g_dsp.ifx_regs[DSP_FORMAT]) {
case 0xA: // 16-bit writes
DSPHost_WriteHostMemory(value >> 8, Address);
DSPHost_WriteHostMemory(value & 0xFF, Address + 1);
Address += 2;
break;
default:
ERROR_LOG(DSPLLE, "dsp_write_aram_d3: Unseen Format %i", gdsp_ifx_regs[DSP_FORMAT]);
ERROR_LOG(DSPLLE, "dsp_write_aram_d3: Unseen Format %i", g_dsp.ifx_regs[DSP_FORMAT]);
break;
}
gdsp_ifx_regs[DSP_ACCAH] = Address >> 16;
gdsp_ifx_regs[DSP_ACCAL] = Address & 0xffff;
g_dsp.ifx_regs[DSP_ACCAH] = Address >> 16;
g_dsp.ifx_regs[DSP_ACCAL] = Address & 0xffff;
}
u16 dsp_read_accelerator()
{
const u32 EndAddress = (gdsp_ifx_regs[DSP_ACEAH] << 16) | gdsp_ifx_regs[DSP_ACEAL];
u32 Address = (gdsp_ifx_regs[DSP_ACCAH] << 16) | gdsp_ifx_regs[DSP_ACCAL];
const u32 EndAddress = (g_dsp.ifx_regs[DSP_ACEAH] << 16) | g_dsp.ifx_regs[DSP_ACEAL];
u32 Address = (g_dsp.ifx_regs[DSP_ACCAH] << 16) | g_dsp.ifx_regs[DSP_ACCAL];
u16 val;
@ -126,7 +127,7 @@ u16 dsp_read_accelerator()
// extention and do/do not use ADPCM. It also remains to be figured out
// whether there's a difference between the usual accelerator "read
// address" and 0xd3.
switch (gdsp_ifx_regs[DSP_FORMAT])
switch (g_dsp.ifx_regs[DSP_FORMAT])
{
case 0x00: // ADPCM audio
val = ADPCM_Step(Address);
@ -135,8 +136,8 @@ u16 dsp_read_accelerator()
case 0x0A: // 16-bit PCM audio
val = (DSPHost_ReadHostMemory(Address) << 8) | DSPHost_ReadHostMemory(Address + 1);
gdsp_ifx_regs[DSP_YN2] = gdsp_ifx_regs[DSP_YN1];
gdsp_ifx_regs[DSP_YN1] = val;
g_dsp.ifx_regs[DSP_YN2] = g_dsp.ifx_regs[DSP_YN1];
g_dsp.ifx_regs[DSP_YN1] = val;
Address += 2;
break;
@ -144,7 +145,7 @@ u16 dsp_read_accelerator()
default:
val = (DSPHost_ReadHostMemory(Address) << 8) | DSPHost_ReadHostMemory(Address + 1);
Address += 2;
ERROR_LOG(DSPLLE, "Unknown DSP Format %i", gdsp_ifx_regs[DSP_FORMAT]);
ERROR_LOG(DSPLLE, "Unknown DSP Format %i", g_dsp.ifx_regs[DSP_FORMAT]);
break;
}
@ -154,7 +155,7 @@ u16 dsp_read_accelerator()
if (Address >= EndAddress)
{
// Set address back to start address.
Address = (gdsp_ifx_regs[DSP_ACSAH] << 16) | gdsp_ifx_regs[DSP_ACSAL];
Address = (g_dsp.ifx_regs[DSP_ACSAH] << 16) | g_dsp.ifx_regs[DSP_ACSAL];
// Do we really need both? (nakee: seems to cause problems with some
// AX games)
@ -167,7 +168,7 @@ u16 dsp_read_accelerator()
// the DSP program do that, at least if DSP_FORMAT == 0x0A.
}
gdsp_ifx_regs[DSP_ACCAH] = Address >> 16;
gdsp_ifx_regs[DSP_ACCAL] = Address & 0xffff;
g_dsp.ifx_regs[DSP_ACCAH] = Address >> 16;
g_dsp.ifx_regs[DSP_ACCAL] = Address & 0xffff;
return(val);
}

View File

@ -26,6 +26,8 @@
#ifndef _DSPCORE_H
#define _DSPCORE_H
#include "Thread.h"
#include "DSPBreakpoints.h"
#define DSP_IRAM_BYTE_SIZE 0x2000
@ -172,6 +174,8 @@
#define EXP_6 6 // 0x000c
#define EXP_INT 7 // 0x000e external int (message from cpu)
// All the state of the DSP should be in this struct. Any DSP state that is not filled on init
// should be moved here.
struct SDSP
{
u16 r[32];
@ -190,15 +194,27 @@ struct SDSP
u8 exceptions; // pending exceptions
int exception_in_progress; // inside exp flag
// Let's make stack depth 32 for now. The real DSP has different depths
// for the different stacks, but it would be strange if any ucode relied on stack
// overflows since on the DSP, when the stack overflows, you're screwed.
// DSP hardware stacks. They're mapped to a bunch of registers, such that writes
// to them push and reads pop.
// Let's make stack depth 32 for now, which is way more than what's needed.
// The real DSP has different depths for the different stacks, but it would
// be strange if any ucode relied on stack overflows since on the DSP, when
// the stack overflows, you're screwed.
u16 reg_stack[4][DSP_STACK_DEPTH];
// For debugging.
u32 iram_crc;
u64 step_counter;
// Mailbox.
volatile u16 mbox[2][2];
// Mutex protecting the mailbox.
Common::CriticalSection g_CriticalSection;
// Accelerator / DMA / other hardware registers. Not GPRs.
u16 ifx_regs[256];
// When state saving, all of the above can just be memcpy'd into the save state.
// The below needs special handling.
u16 *iram;

View File

@ -40,21 +40,17 @@ void gdsp_do_dma();
Common::CriticalSection g_CriticalSection;
static volatile u16 gdsp_mbox[2][2];
u16 gdsp_ifx_regs[256];
void gdsp_ifx_init()
{
for (int i = 0; i < 256; i++)
{
gdsp_ifx_regs[i] = 0;
g_dsp.ifx_regs[i] = 0;
}
gdsp_mbox[0][0] = 0;
gdsp_mbox[0][1] = 0;
gdsp_mbox[1][0] = 0;
gdsp_mbox[1][1] = 0;
g_dsp.mbox[0][0] = 0;
g_dsp.mbox[0][1] = 0;
g_dsp.mbox[1][0] = 0;
g_dsp.mbox[1][1] = 0;
}
@ -62,7 +58,7 @@ u32 gdsp_mbox_peek(u8 mbx)
{
if (DSPHost_OnThread())
g_CriticalSection.Enter();
u32 value = ((gdsp_mbox[mbx][0] << 16) | gdsp_mbox[mbx][1]);
u32 value = ((g_dsp.mbox[mbx][0] << 16) | g_dsp.mbox[mbx][1]);
if (DSPHost_OnThread())
g_CriticalSection.Leave();
return value;
@ -72,7 +68,7 @@ void gdsp_mbox_write_h(u8 mbx, u16 val)
{
if (DSPHost_OnThread())
g_CriticalSection.Enter();
gdsp_mbox[mbx][0] = val & 0x7fff;
g_dsp.mbox[mbx][0] = val & 0x7fff;
if (DSPHost_OnThread())
g_CriticalSection.Leave();
}
@ -82,8 +78,8 @@ void gdsp_mbox_write_l(u8 mbx, u16 val)
{
if (DSPHost_OnThread())
g_CriticalSection.Enter();
gdsp_mbox[mbx][1] = val;
gdsp_mbox[mbx][0] |= 0x8000;
g_dsp.mbox[mbx][1] = val;
g_dsp.mbox[mbx][0] |= 0x8000;
if (DSPHost_OnThread())
g_CriticalSection.Leave();
@ -100,7 +96,7 @@ void gdsp_mbox_write_l(u8 mbx, u16 val)
u16 gdsp_mbox_read_h(u8 mbx)
{
return gdsp_mbox[mbx][0]; // TODO: mask away the top bit?
return g_dsp.mbox[mbx][0]; // TODO: mask away the top bit?
}
@ -109,8 +105,8 @@ u16 gdsp_mbox_read_l(u8 mbx)
if (DSPHost_OnThread())
g_CriticalSection.Enter();
u16 val = gdsp_mbox[mbx][1];
gdsp_mbox[mbx][0] &= ~0x8000;
u16 val = g_dsp.mbox[mbx][1];
g_dsp.mbox[mbx][0] &= ~0x8000;
if (DSPHost_OnThread())
@ -155,9 +151,9 @@ void gdsp_ifx_write(u16 addr, u16 val)
return gdsp_mbox_write_l(GDSP_MBOX_CPU, val);
case 0xcb: // DSBL
gdsp_ifx_regs[addr & 0xFF] = val;
g_dsp.ifx_regs[addr & 0xFF] = val;
gdsp_do_dma();
gdsp_ifx_regs[DSP_DSCR] &= ~0x0004;
g_dsp.ifx_regs[DSP_DSCR] &= ~0x0004;
break;
case 0xd3: // ZeldaUnk (accelerator WRITE)
@ -172,7 +168,7 @@ void gdsp_ifx_write(u16 addr, u16 val)
case 0xce:
case 0xcf:
case 0xc9:
gdsp_ifx_regs[addr & 0xFF] = val;
g_dsp.ifx_regs[addr & 0xFF] = val;
break;
default:
@ -187,7 +183,7 @@ void gdsp_ifx_write(u16 addr, u16 val)
else {
ERROR_LOG(DSPLLE, "%04x MW %04x (%04x)", g_dsp.pc, addr, val);
}
gdsp_ifx_regs[addr & 0xFF] = val;
g_dsp.ifx_regs[addr & 0xFF] = val;
break;
}
}
@ -209,7 +205,7 @@ u16 gdsp_ifx_read(u16 addr)
return gdsp_mbox_read_l(GDSP_MBOX_CPU);
case 0xc9:
return gdsp_ifx_regs[addr & 0xFF];
return g_dsp.ifx_regs[addr & 0xFF];
case 0xdd: // ADPCM Accelerator reads
return dsp_read_accelerator();
@ -221,16 +217,16 @@ u16 gdsp_ifx_read(u16 addr)
default:
if ((addr & 0xff) >= 0xa0) {
if (pdlabels[(addr & 0xFF) - 0xa0].name && pdlabels[(addr & 0xFF) - 0xa0].description) {
INFO_LOG(DSPLLE, "%04x MR %s (%04x)", g_dsp.pc, pdlabels[(addr & 0xFF) - 0xa0].name, gdsp_ifx_regs[addr & 0xFF]);
INFO_LOG(DSPLLE, "%04x MR %s (%04x)", g_dsp.pc, pdlabels[(addr & 0xFF) - 0xa0].name, g_dsp.ifx_regs[addr & 0xFF]);
}
else {
ERROR_LOG(DSPLLE, "%04x MR %04x (%04x)", g_dsp.pc, addr, gdsp_ifx_regs[addr & 0xFF]);
ERROR_LOG(DSPLLE, "%04x MR %04x (%04x)", g_dsp.pc, addr, g_dsp.ifx_regs[addr & 0xFF]);
}
}
else {
ERROR_LOG(DSPLLE, "%04x MR %04x (%04x)", g_dsp.pc, addr, gdsp_ifx_regs[addr & 0xFF]);
ERROR_LOG(DSPLLE, "%04x MR %04x (%04x)", g_dsp.pc, addr, g_dsp.ifx_regs[addr & 0xFF]);
}
return gdsp_ifx_regs[addr & 0xFF];
return g_dsp.ifx_regs[addr & 0xFF];
}
}
@ -293,10 +289,10 @@ void gdsp_do_dma()
u16 dsp_addr;
u16 len;
addr = (gdsp_ifx_regs[DSP_DSMAH] << 16) | gdsp_ifx_regs[DSP_DSMAL];
ctl = gdsp_ifx_regs[DSP_DSCR];
dsp_addr = gdsp_ifx_regs[DSP_DSPA] * 2;
len = gdsp_ifx_regs[DSP_DSBL];
addr = (g_dsp.ifx_regs[DSP_DSMAH] << 16) | g_dsp.ifx_regs[DSP_DSMAL];
ctl = g_dsp.ifx_regs[DSP_DSCR];
dsp_addr = g_dsp.ifx_regs[DSP_DSPA] * 2;
len = g_dsp.ifx_regs[DSP_DSBL];
if ((ctl > 3) || (len > 0x4000))
{

View File

@ -22,6 +22,7 @@
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
====================================================================*/
#ifndef _GDSP_INTERFACE_H
#define _GDSP_INTERFACE_H
@ -30,8 +31,6 @@
#define GDSP_MBOX_CPU 0
#define GDSP_MBOX_DSP 1
extern u16 gdsp_ifx_regs[256];
u32 gdsp_mbox_peek(u8 mbx);
void gdsp_mbox_write_h(u8 mbx, u16 val);
void gdsp_mbox_write_l(u8 mbx, u16 val);
@ -45,6 +44,4 @@ u16 gdsp_ifx_read(u16 addr);
void gdsp_idma_in(u16 dsp_addr, u32 addr, u32 size);
#endif

View File

@ -427,6 +427,10 @@ void nop(const UDSPInstruction& opc)
} // end namespace ext
} // end namespace DSPInterpeter
// The Writebacklog needs more commenting. It seems to be a way of writing values from the
// "beginning" of the execution of an instruction, at the end of the execution.
void applyWriteBackLog()
{
// always make sure to have an extra entry at the end w/ -1 to avoid
@ -442,6 +446,10 @@ void zeroWriteBackLog()
{
// always make sure to have an extra entry at the end w/ -1 to avoid
// infinitive loops
// What does this actually do? It just writes zeroes to registers that are
// mentioned in the write back log, without checking that the indexes aren't -1.
// Doesn't really seem sane - shouldn't it check for -1, at least?
for (int i = 0; writeBackLogIdx[i] != -1; i++)
dsp_op_write_reg(writeBackLogIdx[i], 0);
}

View File

@ -63,6 +63,7 @@ void nop(const UDSPInstruction& opc);
} // end namespace Ext
} // end namespace DSPinterpeter
// Needs comments.
inline void writeToBackLog(int i, int idx, u16 value)
{
writeBackLog[i] = value;

View File

@ -296,7 +296,6 @@ void cmpi(const UDSPInstruction& opc)
s64 imm = (s64)(s16)dsp_fetch_code() << 16;
s64 val = dsp_get_long_acc(reg);
Update_SR_Register64(val - imm);
}
// XORI $acD.m, #I

View File

@ -163,11 +163,32 @@ void DllConfig(HWND _hParent)
#endif
}
void DoState(unsigned char **ptr, int mode)
{
PointerWrap p(ptr, mode);
p.Do(g_InitMixer);
// Enable this when the HLE is fixed to save/load the same amount of data,
// no matter how bogus, so that one can switch LLE->HLE. The other way is unlikely to work very well.
#if 0
p.Do(g_dsp.r);
p.Do(g_dsp.pc);
p.Do(g_dsp.err_pc);
p.Do(g_dsp.cr);
p.Do(g_dsp.reg_stack_ptr);
p.Do(g_dsp.exceptions);
p.Do(g_dsp.exceptions_in_progress);
for (int i = 0; i < 4; i++) {
p.Do(g_dsp.reg_stack[i]);
}
p.Do(g_dsp.iram_crc);
p.Do(g_dsp.step_counter);
p.Do(g_dsp.ifx_regs);
p.Do(g_dsp.mbox[0]);
p.Do(g_dsp.mbox[1]);
p.DoArray(g_dsp.iram, DSP_IRAM_BYTE_SIZE);
p.DoArray(g_dsp.dram, DSP_DRAM_BYTE_SIZE);
#endif
}
void EmuStateChange(PLUGIN_EMUSTATE newState)
@ -371,10 +392,9 @@ void DSP_SendAIBuffer(unsigned int address, unsigned int num_samples)
CMixer *pMixer = soundStream->GetMixer();
if (pMixer && address)
if (pMixer != 0 && address != 0)
{
short *samples = (short *)Memory_Get_Pointer(address);
pMixer->PushSamples(samples, num_samples);
}
@ -384,6 +404,6 @@ void DSP_SendAIBuffer(unsigned int address, unsigned int num_samples)
void DSP_ClearAudioBuffer()
{
if (soundStream)
soundStream->Clear(*g_dspInitialize.pEmulatorState);
soundStream->Clear((*g_dspInitialize.pEmulatorState) ? true : false);
}