337 lines
6.4 KiB
C++
337 lines
6.4 KiB
C++
//
|
|
// Audio Overload SDK
|
|
//
|
|
// Copyright (c) 2007-2009 R. Belmont and Richard Bannister, and others.
|
|
// All rights reserved.
|
|
//
|
|
#include "dsp.h"
|
|
#include "aica_if.h"
|
|
#include "aica_mem.h"
|
|
|
|
#if FEAT_DSPREC != DYNAREC_JIT
|
|
|
|
#ifdef RELEASE
|
|
#undef verify
|
|
#define verify(...)
|
|
#endif
|
|
|
|
void AICADSP_Init(struct dsp_t *DSP)
|
|
{
|
|
memset(DSP, 0, sizeof(*DSP));
|
|
DSP->RBL = 0x8000 - 1;
|
|
DSP->Stopped = 1;
|
|
dsp.regs.MDEC_CT = 1;
|
|
}
|
|
|
|
void AICADSP_Step(struct dsp_t *DSP)
|
|
{
|
|
s32 ACC = 0; //26 bit
|
|
s32 SHIFTED = 0; //24 bit
|
|
s32 X = 0; //24 bit
|
|
s32 Y = 0; //13 bit
|
|
s32 B = 0; //26 bit
|
|
s32 INPUTS = 0; //24 bit
|
|
s32 MEMVAL[4] = {0};
|
|
s32 FRC_REG = 0; //13 bit
|
|
s32 Y_REG = 0; //24 bit
|
|
u32 ADRS_REG = 0; //13 bit
|
|
int step;
|
|
|
|
memset(DSPData->EFREG, 0, sizeof(DSPData->EFREG));
|
|
|
|
if (DSP->Stopped)
|
|
return;
|
|
|
|
#if 0
|
|
int dump = 0;
|
|
FILE *f = NULL;
|
|
if (dump)
|
|
f = fopen("dsp.txt", "wt");
|
|
#endif
|
|
|
|
for (step = 0; step < 128; ++step)
|
|
{
|
|
u32 *IPtr = DSPData->MPRO + step * 4;
|
|
|
|
if (IPtr[0] == 0 && IPtr[1] == 0 && IPtr[2] == 0 && IPtr[3] == 0)
|
|
{
|
|
// Empty instruction shortcut
|
|
X = DSP->TEMP[DSP->regs.MDEC_CT & 0x7F];
|
|
X <<= 8;
|
|
X >>= 8;
|
|
Y = FRC_REG;
|
|
Y <<= 19;
|
|
Y >>= 19;
|
|
|
|
s64 v = ((s64)X * (s64)Y) >> 10;
|
|
v <<= 6; // 26 bits only
|
|
v >>= 6;
|
|
ACC = v + X;
|
|
ACC <<= 6; // 26 bits only
|
|
ACC >>= 6;
|
|
|
|
continue;
|
|
}
|
|
|
|
u32 TRA = (IPtr[0] >> 9) & 0x7F;
|
|
u32 TWT = (IPtr[0] >> 8) & 0x01;
|
|
|
|
u32 XSEL = (IPtr[1] >> 15) & 0x01;
|
|
u32 YSEL = (IPtr[1] >> 13) & 0x03;
|
|
u32 IRA = (IPtr[1] >> 7) & 0x3F;
|
|
u32 IWT = (IPtr[1] >> 6) & 0x01;
|
|
|
|
u32 EWT = (IPtr[2] >> 12) & 0x01;
|
|
u32 ADRL = (IPtr[2] >> 7) & 0x01;
|
|
u32 FRCL = (IPtr[2] >> 6) & 0x01;
|
|
u32 SHIFT = (IPtr[2] >> 4) & 0x03;
|
|
u32 YRL = (IPtr[2] >> 3) & 0x01;
|
|
u32 NEGB = (IPtr[2] >> 2) & 0x01;
|
|
u32 ZERO = (IPtr[2] >> 1) & 0x01;
|
|
u32 BSEL = (IPtr[2] >> 0) & 0x01;
|
|
|
|
u32 COEF = step;
|
|
|
|
// operations are done at 24 bit precision
|
|
#if 0
|
|
#define DUMP(v) printf(" " #v ": %04X",v);
|
|
|
|
printf("%d: ",step);
|
|
DUMP(ACC);
|
|
DUMP(SHIFTED);
|
|
DUMP(X);
|
|
DUMP(Y);
|
|
DUMP(B);
|
|
DUMP(INPUTS);
|
|
DUMP(MEMVAL);
|
|
DUMP(FRC_REG);
|
|
DUMP(Y_REG);
|
|
DUMP(ADDR);
|
|
DUMP(ADRS_REG);
|
|
printf("\n");
|
|
#endif
|
|
|
|
// INPUTS RW
|
|
verify(IRA < 0x38);
|
|
if (IRA <= 0x1f)
|
|
INPUTS = DSP->MEMS[IRA];
|
|
else if (IRA <= 0x2F)
|
|
INPUTS = DSP->MIXS[IRA - 0x20] << 4; // MIXS is 20 bit
|
|
else if (IRA <= 0x31)
|
|
INPUTS = DSPData->EXTS[IRA - 0x30] << 8; // EXTS is 16 bits
|
|
else
|
|
INPUTS = 0;
|
|
|
|
if (IWT)
|
|
{
|
|
u32 IWA = (IPtr[1] >> 1) & 0x1F;
|
|
DSP->MEMS[IWA] = MEMVAL[step & 3]; // MEMVAL was selected in previous MRD
|
|
// "When read and write are specified simultaneously in the same step for INPUTS, TEMP, etc., write is executed after read."
|
|
//if (IRA == IWA)
|
|
// INPUTS = MEMVAL[step & 3];
|
|
}
|
|
|
|
// Operand sel
|
|
// B
|
|
if (!ZERO)
|
|
{
|
|
if (BSEL)
|
|
B = ACC;
|
|
else
|
|
B = DSP->TEMP[(TRA + DSP->regs.MDEC_CT) & 0x7F];
|
|
if (NEGB)
|
|
B = -B;
|
|
}
|
|
else
|
|
{
|
|
B = 0;
|
|
}
|
|
|
|
// X
|
|
if (XSEL)
|
|
X = INPUTS;
|
|
else
|
|
X = DSP->TEMP[(TRA + DSP->regs.MDEC_CT) & 0x7F];
|
|
|
|
// Y
|
|
if (YSEL == 0)
|
|
Y = FRC_REG;
|
|
else if (YSEL == 1)
|
|
Y = ((s32)(s16)DSPData->COEF[COEF]) >> 3; //COEF is 16 bits
|
|
else if (YSEL == 2)
|
|
Y = Y_REG >> 11;
|
|
else if (YSEL == 3)
|
|
Y = (Y_REG >> 4) & 0x0FFF;
|
|
|
|
if (YRL)
|
|
Y_REG = INPUTS;
|
|
|
|
// Shifter
|
|
// There's a 1-step delay at the output of the X*Y + B adder. So we use the ACC value from the previous step.
|
|
if (SHIFT == 0)
|
|
{
|
|
SHIFTED = ACC;
|
|
if (SHIFTED > 0x007FFFFF)
|
|
SHIFTED = 0x007FFFFF;
|
|
if (SHIFTED < (-0x00800000))
|
|
SHIFTED = -0x00800000;
|
|
}
|
|
else if (SHIFT == 1)
|
|
{
|
|
SHIFTED = ACC << 1; // x2 scale
|
|
if (SHIFTED > 0x007FFFFF)
|
|
SHIFTED = 0x007FFFFF;
|
|
if (SHIFTED < (-0x00800000))
|
|
SHIFTED = -0x00800000;
|
|
}
|
|
else if (SHIFT == 2)
|
|
{
|
|
SHIFTED = ACC << 1; // x2 scale
|
|
}
|
|
else if (SHIFT == 3)
|
|
{
|
|
SHIFTED = ACC;
|
|
}
|
|
|
|
// ACCUM
|
|
ACC = (((s64)X * (s64)Y) >> 12) + B;
|
|
|
|
if (TWT)
|
|
{
|
|
u32 TWA = (IPtr[0] >> 1) & 0x7F;
|
|
DSP->TEMP[(TWA + DSP->regs.MDEC_CT) & 0x7F] = SHIFTED;
|
|
}
|
|
|
|
if (FRCL)
|
|
{
|
|
if (SHIFT == 3)
|
|
FRC_REG = SHIFTED & 0x0FFF;
|
|
else
|
|
FRC_REG = SHIFTED >> 11;
|
|
}
|
|
|
|
if (step & 1)
|
|
{
|
|
u32 MWT = (IPtr[2] >> 14) & 0x01;
|
|
u32 MRD = (IPtr[2] >> 13) & 0x01;
|
|
|
|
if (MRD || MWT)
|
|
{
|
|
u32 TABLE = (IPtr[2] >> 15) & 0x01;
|
|
|
|
u32 NOFL = (IPtr[3] >> 15) & 1; //????
|
|
verify(!NOFL);
|
|
u32 MASA = (IPtr[3] >> 9) & 0x3f; //???
|
|
u32 ADREB = (IPtr[3] >> 8) & 0x1;
|
|
u32 NXADR = (IPtr[3] >> 7) & 0x1;
|
|
|
|
u32 ADDR = DSPData->MADRS[MASA];
|
|
if (ADREB)
|
|
ADDR += ADRS_REG & 0x0FFF;
|
|
if (NXADR)
|
|
ADDR++;
|
|
if (!TABLE)
|
|
{
|
|
ADDR += DSP->regs.MDEC_CT;
|
|
ADDR &= DSP->RBL; // RBL is ring buffer length - 1
|
|
}
|
|
else
|
|
ADDR &= 0xFFFF;
|
|
|
|
ADDR <<= 1; // Word -> byte address
|
|
ADDR += DSP->RBP; // RBP is already a byte address
|
|
if (MRD) // memory only allowed on odd. DoA inserts NOPs on even
|
|
{
|
|
//if (NOFL)
|
|
// MEMVAL[(step + 2) & 3] = (*(s16 *)&aica_ram[ADDR]) << 8;
|
|
//else
|
|
MEMVAL[(step + 2) & 3] = UNPACK(*(u16 *)&aica_ram[ADDR & ARAM_MASK]);
|
|
}
|
|
if (MWT)
|
|
{
|
|
// FIXME We should wait for the next step to copy stuff to SRAM (same as read)
|
|
//if (NOFL)
|
|
// *(s16 *)&aica_ram[ADDR] = SHIFTED >> 8;
|
|
//else
|
|
*(u16 *)&aica_ram[ADDR & ARAM_MASK] = PACK(SHIFTED);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ADRL)
|
|
{
|
|
if (SHIFT == 3)
|
|
ADRS_REG = SHIFTED >> 12;
|
|
else
|
|
ADRS_REG = INPUTS >> 16;
|
|
}
|
|
|
|
if (EWT)
|
|
{
|
|
u32 EWA = (IPtr[2] >> 8) & 0x0F;
|
|
DSPData->EFREG[EWA] = SHIFTED >> 4;
|
|
}
|
|
|
|
}
|
|
--DSP->regs.MDEC_CT;
|
|
if (dsp.regs.MDEC_CT == 0)
|
|
dsp.regs.MDEC_CT = dsp.RBL + 1; // RBL is ring buffer length - 1
|
|
|
|
// memset(DSP->MIXS, 0, sizeof(DSP->MIXS));
|
|
// if(f)
|
|
// fclose(f);
|
|
}
|
|
|
|
void AICADSP_Start(struct dsp_t *DSP)
|
|
{
|
|
dsp.Stopped = 1;
|
|
for (int i = 127; i >= 0; --i)
|
|
{
|
|
u32 *IPtr = DSPData->MPRO + i * 4;
|
|
|
|
if (IPtr[0] != 0 || IPtr[1] != 0 || IPtr[2 ]!= 0 || IPtr[3] != 0)
|
|
{
|
|
DSP->Stopped = 0;
|
|
//printf("DSP: starting %d steps\n", i + 1);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void dsp_init()
|
|
{
|
|
AICADSP_Init(&dsp);
|
|
AICADSP_Start(&dsp);
|
|
}
|
|
|
|
void dsp_term()
|
|
{
|
|
dsp.Stopped = 1;
|
|
}
|
|
|
|
void dsp_step()
|
|
{
|
|
AICADSP_Step(&dsp);
|
|
}
|
|
|
|
void dsp_writenmem(u32 addr)
|
|
{
|
|
if (addr >= 0x3400 && addr < 0x3C00)
|
|
{
|
|
AICADSP_Start(&dsp);
|
|
}
|
|
else if (addr >= 0x4000 && addr < 0x4400)
|
|
{
|
|
// TODO proper sharing of memory with sh4 through DSPData
|
|
memset(dsp.TEMP, 0, sizeof(dsp.TEMP));
|
|
}
|
|
else if (addr >= 0x4400 && addr < 0x4500)
|
|
{
|
|
// TODO proper sharing of memory with sh4 through DSPData
|
|
memset(dsp.MEMS, 0, sizeof(dsp.MEMS));
|
|
}
|
|
}
|
|
|
|
#endif
|