Generic interpreted DSP
This commit is contained in:
parent
63a70e0f62
commit
8c3247d1b2
|
@ -1,4 +1,4 @@
|
|||
#include "dsp.h"
|
||||
#include "dsp.h"
|
||||
#include "aica_mem.h"
|
||||
#include "hw/aica/aica_if.h"
|
||||
#include "oslib/oslib.h"
|
||||
|
@ -22,6 +22,54 @@
|
|||
|
||||
DECL_ALIGN(4096) dsp_t dsp;
|
||||
|
||||
//float format is ?
|
||||
u16 DYNACALL PACK(s32 val)
|
||||
{
|
||||
u32 temp;
|
||||
int sign,exponent,k;
|
||||
|
||||
sign = (val >> 23) & 0x1;
|
||||
temp = (val ^ (val << 1)) & 0xFFFFFF;
|
||||
exponent = 0;
|
||||
for (k=0; k<12; k++)
|
||||
{
|
||||
if (temp & 0x800000)
|
||||
break;
|
||||
temp <<= 1;
|
||||
exponent += 1;
|
||||
}
|
||||
if (exponent < 12)
|
||||
val = (val << exponent) & 0x3FFFFF;
|
||||
else
|
||||
val <<= 11;
|
||||
val >>= 11;
|
||||
val |= sign << 15;
|
||||
val |= exponent << 11;
|
||||
|
||||
return (u16)val;
|
||||
}
|
||||
|
||||
s32 DYNACALL UNPACK(u16 val)
|
||||
{
|
||||
int sign,exponent,mantissa;
|
||||
s32 uval;
|
||||
|
||||
sign = (val >> 15) & 0x1;
|
||||
exponent = (val >> 11) & 0xF;
|
||||
mantissa = val & 0x7FF;
|
||||
uval = mantissa << 11;
|
||||
if (exponent > 11)
|
||||
exponent = 11;
|
||||
else
|
||||
uval |= (sign ^ 1) << 22;
|
||||
uval |= sign << 23;
|
||||
uval <<= 8;
|
||||
uval >>= 8;
|
||||
uval >>= exponent;
|
||||
|
||||
return uval;
|
||||
}
|
||||
|
||||
#if HOST_CPU == CPU_X86 && FEAT_DSPREC == DYNAREC_JIT
|
||||
#include "emitter/x86_emitter.h"
|
||||
|
||||
|
@ -32,38 +80,6 @@ const bool SUPPORT_NOFL=false;
|
|||
|
||||
#pragma warning(disable:4311)
|
||||
|
||||
struct _INST
|
||||
{
|
||||
unsigned int TRA;
|
||||
unsigned int TWT;
|
||||
unsigned int TWA;
|
||||
|
||||
unsigned int XSEL;
|
||||
unsigned int YSEL;
|
||||
unsigned int IRA;
|
||||
unsigned int IWT;
|
||||
unsigned int IWA;
|
||||
|
||||
unsigned int EWT;
|
||||
unsigned int EWA;
|
||||
unsigned int ADRL;
|
||||
unsigned int FRCL;
|
||||
unsigned int SHIFT;
|
||||
unsigned int YRL;
|
||||
unsigned int NEGB;
|
||||
unsigned int ZERO;
|
||||
unsigned int BSEL;
|
||||
|
||||
unsigned int NOFL; //MRQ set
|
||||
unsigned int TABLE; //MRQ set
|
||||
unsigned int MWT; //MRQ set
|
||||
unsigned int MRD; //MRQ set
|
||||
unsigned int MASA; //MRQ set
|
||||
unsigned int ADREB; //MRQ set
|
||||
unsigned int NXADR; //MRQ set
|
||||
};
|
||||
|
||||
|
||||
#define DYNBUF 0x10000
|
||||
/*
|
||||
//#define USEFLOATPACK
|
||||
|
@ -127,55 +143,6 @@ _negme:
|
|||
}
|
||||
}*/
|
||||
|
||||
//float format is ?
|
||||
static u16 DYNACALL PACK(s32 val)
|
||||
{
|
||||
u32 temp;
|
||||
int sign,exponent,k;
|
||||
|
||||
sign = (val >> 23) & 0x1;
|
||||
temp = (val ^ (val << 1)) & 0xFFFFFF;
|
||||
exponent = 0;
|
||||
for (k=0; k<12; k++)
|
||||
{
|
||||
if (temp & 0x800000)
|
||||
break;
|
||||
temp <<= 1;
|
||||
exponent += 1;
|
||||
}
|
||||
if (exponent < 12)
|
||||
val = (val << exponent) & 0x3FFFFF;
|
||||
else
|
||||
val <<= 11;
|
||||
val >>= 11;
|
||||
val |= sign << 15;
|
||||
val |= exponent << 11;
|
||||
|
||||
return (u16)val;
|
||||
}
|
||||
|
||||
static s32 DYNACALL UNPACK(u16 val)
|
||||
{
|
||||
int sign,exponent,mantissa;
|
||||
s32 uval;
|
||||
|
||||
sign = (val >> 15) & 0x1;
|
||||
exponent = (val >> 11) & 0xF;
|
||||
mantissa = val & 0x7FF;
|
||||
uval = mantissa << 11;
|
||||
if (exponent > 11)
|
||||
exponent = 11;
|
||||
else
|
||||
uval |= (sign ^ 1) << 22;
|
||||
uval |= sign << 23;
|
||||
uval <<= 8;
|
||||
uval >>= 8;
|
||||
uval >>= exponent;
|
||||
|
||||
return uval;
|
||||
}
|
||||
|
||||
|
||||
void dsp_init()
|
||||
{
|
||||
memset(&dsp,0,sizeof(dsp));
|
||||
|
@ -187,7 +154,7 @@ void dsp_init()
|
|||
dsp.regs.MDEC_CT=1;
|
||||
|
||||
|
||||
os_MakeExecutable(dsp.DynCode,sizeof(dsp.DynCode));
|
||||
//os_MakeExecutable(dsp.DynCode,sizeof(dsp.DynCode));
|
||||
}
|
||||
void dsp_recompile();
|
||||
void DecodeInst(u32 *IPtr,_INST *i)
|
||||
|
@ -252,8 +219,8 @@ void _dsp_debug_step_end()
|
|||
verify(dsp.regs_init.TEMPS);
|
||||
verify(dsp.regs_init.EFREG);
|
||||
}
|
||||
#define nwtn(x) verify(!dsp.regs_init.##x)
|
||||
#define wtn(x) nwtn(x);dsp.regs_init.##x=true;
|
||||
#define nwtn(x) verify(!dsp.regs_init.x)
|
||||
#define wtn(x) nwtn(x);dsp.regs_init.x=true;
|
||||
|
||||
//sign extend to 32 bits
|
||||
void dsp_rec_se(x86_block& x86e,x86_gpr_reg reg,u32 src_sz,u32 dst_sz=0xFF)
|
||||
|
@ -864,10 +831,4 @@ void dsp_readmem(u32 addr)
|
|||
{
|
||||
//nothing ? :p
|
||||
}
|
||||
#else
|
||||
|
||||
void dsp_init() { }
|
||||
void dsp_term() { }
|
||||
void dsp_step() { }
|
||||
void dsp_writenmem(u32 addr) { }
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -8,9 +8,9 @@ struct dsp_t
|
|||
|
||||
//buffered DSP state
|
||||
//24 bit wide
|
||||
u32 TEMP[128];
|
||||
s32 TEMP[128];
|
||||
//24 bit wide
|
||||
u32 MEMS[32];
|
||||
s32 MEMS[32];
|
||||
//20 bit wide
|
||||
s32 MIXS[16];
|
||||
|
||||
|
@ -59,7 +59,7 @@ struct dsp_t
|
|||
u32 NOFL_2;
|
||||
}regs;
|
||||
//DEC counter :)
|
||||
u32 DEC;
|
||||
//u32 DEC;
|
||||
|
||||
//various dsp regs
|
||||
signed int ACC; //26 bit
|
||||
|
@ -81,6 +81,8 @@ struct dsp_t
|
|||
//EFREG *16
|
||||
//EXTS *2
|
||||
|
||||
// Interpreter flags
|
||||
bool Stopped;
|
||||
|
||||
//Dynarec flags
|
||||
bool dyndirty;
|
||||
|
@ -92,4 +94,39 @@ extern dsp_t dsp;
|
|||
void dsp_init();
|
||||
void dsp_term();
|
||||
void dsp_step();
|
||||
void dsp_writenmem(u32 addr);
|
||||
void dsp_writenmem(u32 addr);
|
||||
|
||||
struct _INST
|
||||
{
|
||||
unsigned int TRA;
|
||||
unsigned int TWT;
|
||||
unsigned int TWA;
|
||||
|
||||
unsigned int XSEL;
|
||||
unsigned int YSEL;
|
||||
unsigned int IRA;
|
||||
unsigned int IWT;
|
||||
unsigned int IWA;
|
||||
|
||||
unsigned int EWT;
|
||||
unsigned int EWA;
|
||||
unsigned int ADRL;
|
||||
unsigned int FRCL;
|
||||
unsigned int SHIFT;
|
||||
unsigned int YRL;
|
||||
unsigned int NEGB;
|
||||
unsigned int ZERO;
|
||||
unsigned int BSEL;
|
||||
|
||||
unsigned int NOFL; //MRQ set
|
||||
unsigned int TABLE; //MRQ set
|
||||
unsigned int MWT; //MRQ set
|
||||
unsigned int MRD; //MRQ set
|
||||
unsigned int MASA; //MRQ set
|
||||
unsigned int ADREB; //MRQ set
|
||||
unsigned int NXADR; //MRQ set
|
||||
};
|
||||
|
||||
void DecodeInst(u32 *IPtr,_INST *i);
|
||||
u16 DYNACALL PACK(s32 val);
|
||||
s32 DYNACALL UNPACK(u16 val);
|
||||
|
|
|
@ -0,0 +1,326 @@
|
|||
//
|
||||
// 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_NONE
|
||||
|
||||
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 ADDR = 0;
|
||||
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;
|
||||
|
||||
u32 TRA = (IPtr[0] >> 9) & 0x7F;
|
||||
u32 TWT = (IPtr[0] >> 8) & 0x01;
|
||||
u32 TWA = (IPtr[0] >> 1) & 0x7F;
|
||||
|
||||
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 IWA = (IPtr[1] >> 1) & 0x1F;
|
||||
|
||||
u32 TABLE = (IPtr[2] >> 15) & 0x01;
|
||||
u32 MWT = (IPtr[2] >> 14) & 0x01;
|
||||
u32 MRD = (IPtr[2] >> 13) & 0x01;
|
||||
u32 EWT = (IPtr[2] >> 12) & 0x01;
|
||||
u32 EWA = (IPtr[2] >> 8) & 0x0F;
|
||||
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 NOFL = (IPtr[3] >> 15) & 1; //????
|
||||
verify(!NOFL);
|
||||
u32 COEF = step;
|
||||
|
||||
u32 MASA = (IPtr[3] >> 9) & 0x3f; //???
|
||||
u32 ADREB = (IPtr[3] >> 8) & 0x1;
|
||||
u32 NXADR = (IPtr[3] >> 7) & 0x1;
|
||||
|
||||
// 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;
|
||||
|
||||
INPUTS <<= 8;
|
||||
INPUTS >>= 8;
|
||||
|
||||
if (IWT)
|
||||
{
|
||||
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];
|
||||
B <<= 8; //Sign extend
|
||||
B >>= 8;
|
||||
}
|
||||
if (NEGB)
|
||||
B = 0 - B;
|
||||
}
|
||||
else
|
||||
B = 0;
|
||||
|
||||
// X
|
||||
if (XSEL)
|
||||
X = INPUTS;
|
||||
else
|
||||
{
|
||||
X = DSP->TEMP[(TRA + DSP->regs.MDEC_CT) & 0x7F];
|
||||
X <<= 8;
|
||||
X >>= 8;
|
||||
}
|
||||
|
||||
// Y
|
||||
if (YSEL == 0)
|
||||
Y = FRC_REG;
|
||||
else if (YSEL == 1)
|
||||
Y = DSPData->COEF[COEF] >> 3; //COEF is 16 bits
|
||||
else if (YSEL == 2)
|
||||
Y = (Y_REG >> 11) & 0x1FFF;
|
||||
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 >> 2; // 26 bits -> 24 bits
|
||||
if (SHIFTED > 0x0007FFFF)
|
||||
SHIFTED = 0x0007FFFF;
|
||||
if (SHIFTED < (-0x00080000))
|
||||
SHIFTED = -0x00080000;
|
||||
}
|
||||
else if (SHIFT == 1)
|
||||
{
|
||||
SHIFTED = ACC >> 1; // 26 bits -> 24 bits and x2 scale
|
||||
if (SHIFTED > 0x0007FFFF)
|
||||
SHIFTED = 0x0007FFFF;
|
||||
if (SHIFTED < (-0x00080000))
|
||||
SHIFTED = -0x00080000;
|
||||
}
|
||||
else if (SHIFT == 2)
|
||||
{
|
||||
SHIFTED = ACC >> 1;
|
||||
SHIFTED <<= 8;
|
||||
SHIFTED >>= 8;
|
||||
}
|
||||
else if (SHIFT == 3)
|
||||
{
|
||||
SHIFTED = ACC >> 2;
|
||||
SHIFTED <<= 8;
|
||||
SHIFTED >>= 8;
|
||||
}
|
||||
|
||||
// ACCUM
|
||||
Y <<= 19;
|
||||
Y >>= 19;
|
||||
|
||||
s64 v = ((s64)X * (s64)Y) >> 10; // magic value from dynarec. 1 sign bit + 24-1 bits + 13-1 bits -> 26 bits?
|
||||
v <<= 6; // 26 bits only
|
||||
v >>= 6;
|
||||
ACC = v + B;
|
||||
ACC <<= 6; // 26 bits only
|
||||
ACC >>= 6;
|
||||
|
||||
if (TWT)
|
||||
DSP->TEMP[(TWA + DSP->regs.MDEC_CT) & 0x7F] = SHIFTED;
|
||||
|
||||
if (FRCL)
|
||||
{
|
||||
if (SHIFT == 3)
|
||||
FRC_REG = SHIFTED & 0x0FFF;
|
||||
else
|
||||
FRC_REG = (SHIFTED >> 11) & 0x1FFF;
|
||||
}
|
||||
|
||||
if ((MRD || MWT) && (step & 1))
|
||||
{
|
||||
ADDR = DSPData->MADRS[MASA];
|
||||
if (ADREB)
|
||||
ADDR += ADRS_REG & 0x0FFF;
|
||||
if (NXADR)
|
||||
ADDR++;
|
||||
if (!TABLE)
|
||||
ADDR += DSP->regs.MDEC_CT;
|
||||
if (!TABLE)
|
||||
ADDR &= DSP->RBL; // RBL is ring buffer length - 1
|
||||
else
|
||||
ADDR &= 0xFFFF;
|
||||
// ADDR <<= 1;
|
||||
// ADDR += DSP->RBP << 13;
|
||||
// MEMVAL = DSP->AICARAM[ADDR >> 1];
|
||||
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]);
|
||||
}
|
||||
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] = PACK(SHIFTED);
|
||||
}
|
||||
}
|
||||
|
||||
if (ADRL)
|
||||
{
|
||||
if (SHIFT == 3)
|
||||
ADRS_REG = (SHIFTED >> 12) & 0xFFF;
|
||||
else
|
||||
ADRS_REG = (INPUTS >> 16);
|
||||
}
|
||||
|
||||
if (EWT)
|
||||
// 4 ????
|
||||
DSPData->EFREG[EWA] += SHIFTED >> 4; // dynarec uses = instead of +=
|
||||
|
||||
}
|
||||
--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
|
|
@ -1,4 +1,4 @@
|
|||
#include "sgc_if.h"
|
||||
#include "sgc_if.h"
|
||||
#include "dsp.h"
|
||||
#include "aica_mem.h"
|
||||
#include "hw/aica/aica_if.h"
|
||||
|
@ -1359,8 +1359,16 @@ void AICA_Sample()
|
|||
{
|
||||
VOLPAN(EXTS0L,dsp_out_vol[16].EFSDL,dsp_out_vol[16].EFPAN,mixl,mixr);
|
||||
VOLPAN(EXTS0R,dsp_out_vol[17].EFSDL,dsp_out_vol[17].EFPAN,mixl,mixr);
|
||||
|
||||
DSPData->EXTS[0] = EXTS0L;
|
||||
DSPData->EXTS[1] = EXTS0R;
|
||||
}
|
||||
if (settings.aica.DSPEnabled)
|
||||
else
|
||||
{
|
||||
DSPData->EXTS[0] = 0;
|
||||
DSPData->EXTS[1] = 0;
|
||||
}
|
||||
//if (settings.aica.DSPEnabled)
|
||||
{
|
||||
dsp_step();
|
||||
|
||||
|
|
Loading…
Reference in New Issue