From: notaz Date: Sat, 3 Jan 2015 23:43:23 +0000 (+0200) Subject: spu: start offload code to TI C64x DSP X-Git-Tag: r21~10 X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=pcsx_rearmed.git;a=commitdiff_plain;h=5514a050f4e936f5c333fa1271b11bf5a6a9ea39 spu: start offload code to TI C64x DSP --- diff --git a/Makefile b/Makefile index 339fcd5e..c15f6ff2 100644 --- a/Makefile +++ b/Makefile @@ -83,6 +83,10 @@ plugins/dfsound/spu.o: plugins/dfsound/adsr.c plugins/dfsound/reverb.c \ ifeq "$(ARCH)" "arm" OBJS += plugins/dfsound/arm_utils.o endif +ifeq "$(HAVE_C64_TOOLS)" "1" +plugins/dfsound/spu.o: CFLAGS += -DC64X_DSP +plugins/dfsound/spu.o: plugins/dfsound/spu_c64x.c +endif ifneq ($(findstring oss,$(SOUND_DRIVERS)),) plugins/dfsound/out.o: CFLAGS += -DHAVE_OSS OBJS += plugins/dfsound/oss.o diff --git a/configure b/configure index e401902e..c02721f9 100755 --- a/configure +++ b/configure @@ -47,6 +47,7 @@ have_armv7="" have_arm_neon="" have_tslib="" have_gles="" +have_c64x_dsp="" enable_dynarec="yes" need_sdl="no" need_xlib="no" @@ -368,6 +369,16 @@ EOF compile_object "$@" } +# see if we have c64_tools for TI C64x DSP +check_c64_tools() +{ + cat > $TMPC < + int f() { return dsp_open(); } +EOF + compile_object "$@" +} + MAIN_LDLIBS="$MAIN_LDLIBS -lz" check_zlib || fail "please install zlib (libz-dev)" @@ -447,6 +458,10 @@ elif compile_binary $CFLAGS_GLES -lEGL -lGLESv1_CM $LDLIBS_GLES; then LDLIBS_GLES="-lEGL -lGLESv1_CM $LDLIBS_GLES" fi +if check_c64_tools; then + have_c64x_dsp="yes" +fi + if [ "$have_gles" = "yes" ]; then plugins="$plugins plugins/gpu-gles/gpu_gles.so" fi @@ -477,6 +492,7 @@ test "x$have_armv6" != "x" || have_armv6="no" test "x$have_armv7" != "x" || have_armv7="no" test "x$have_arm_neon" != "x" || have_arm_neon="no" test "x$have_gles" != "x" || have_gles="no" +test "x$have_c64x_dsp" != "x" || have_c64x_dsp="no" echo "architecture $ARCH" echo "platform $platform" @@ -488,8 +504,11 @@ echo "C compiler flags $CFLAGS" echo "libraries $MAIN_LDLIBS" echo "linker flags $LDFLAGS$MAIN_LDFLAGS" echo "enable dynarec $enable_dynarec" -echo "ARMv7 optimizations $have_armv7" -echo "enable ARM NEON $have_arm_neon" +if [ "$ARCH" = "arm" ]; then + echo "ARMv7 optimizations $have_armv7" + echo "enable ARM NEON $have_arm_neon" + echo "TI C64x DSP support $have_c64x_dsp" +fi echo "tslib support $have_tslib" if [ "$platform" = "generic" ]; then echo "OpenGL ES output $have_gles" @@ -536,6 +555,9 @@ fi if [ "$drc_cache_base" = "yes" ]; then echo "DRC_CACHE_BASE = 1" >> $config_mak fi +if [ "$have_c64x_dsp" = "yes" ]; then + echo "HAVE_C64_TOOLS = 1" >> $config_mak +fi # use pandora's skin (for now) test -e skin || ln -s frontend/pandora/skin skin diff --git a/plugins/dfsound/adsr.c b/plugins/dfsound/adsr.c index a86f461c..836fdbbd 100644 --- a/plugins/dfsound/adsr.c +++ b/plugins/dfsound/adsr.c @@ -57,8 +57,8 @@ void InitADSR(void) // INIT ADSR INLINE void StartADSR(int ch) // MIX ADSR { - s_chan[ch].ADSRX.State=ADSR_ATTACK; // and init some adsr vars - s_chan[ch].ADSRX.EnvelopeVol=0; + spu.s_chan[ch].ADSRX.State = ADSR_ATTACK; // and init some adsr vars + spu.s_chan[ch].ADSRX.EnvelopeVol = 0; } //////////////////////////////////////////////////////////////////////// diff --git a/plugins/dfsound/arm_utils.S b/plugins/dfsound/arm_utils.S index 1726389a..2511bb3d 100644 --- a/plugins/dfsound/arm_utils.S +++ b/plugins/dfsound/arm_utils.S @@ -39,9 +39,10 @@ ptr_SSumLR: .word ESYM(SSumLR) FUNCTION(mix_chan): @ (int start, int count, int lv, int rv) vmov.32 d14[0], r2 vmov.32 d14[1], r3 @ multipliers + load_varadr r2, SSumLR mov r12, r0 load_varadr r0, ChanBuf - load_varadr r2, SSumLR + ldr r2, [r2] add r0, r12, lsl #2 add r2, r12, lsl #3 0: @@ -72,10 +73,11 @@ mc_finish: FUNCTION(mix_chan_rvb): @ (int start, int count, int lv, int rv, int *rvb) vmov.32 d14[0], r2 vmov.32 d14[1], r3 @ multipliers + load_varadr r2, SSumLR mov r12, r0 load_varadr r0, ChanBuf ldr r3, [sp] @ rvb - load_varadr r2, SSumLR + ldr r2, [r2] add r0, r12, lsl #2 add r2, r12, lsl #3 add r3, r12, lsl #3 @@ -116,9 +118,10 @@ FUNCTION(mix_chan): @ (int start, int count, int lv, int rv) stmfd sp!, {r4-r8,lr} orr r3, r2, r3, lsl #16 lsl r3, #1 @ packed multipliers << 1 + load_varadr r2, SSumLR mov r12, r0 load_varadr r0, ChanBuf - load_varadr r2, SSumLR + ldr r2, [r2] add r0, r12, lsl #2 add r2, r12, lsl #3 0: @@ -145,8 +148,9 @@ FUNCTION(mix_chan_rvb): @ (int start, int count, int lv, int rv, int *rvb) stmfd sp!, {r4-r8,lr} orr lr, r2, r3, lsl #16 lsl lr, #1 - ldr r3, [sp] @ rvb load_varadr r2, SSumLR + ldr r3, [sp] @ rvb + ldr r2, [r2] load_varadr r4, ChanBuf add r2, r2, r0, lsl #3 add r3, r3, r0, lsl #3 diff --git a/plugins/dfsound/dma.c b/plugins/dfsound/dma.c index 8d647ff3..4798a19b 100644 --- a/plugins/dfsound/dma.c +++ b/plugins/dfsound/dma.c @@ -27,9 +27,9 @@ unsigned short CALLBACK SPUreadDMA(void) { - unsigned short s=spu.spuMem[spu.spuAddr>>1]; - spu.spuAddr+=2; - if(spu.spuAddr>0x7ffff) spu.spuAddr=0; + unsigned short s = *(unsigned short *)(spu.spuMemC + spu.spuAddr); + spu.spuAddr += 2; + spu.spuAddr &= 0x7fffe; return s; } @@ -47,9 +47,9 @@ void CALLBACK SPUreadDMAMem(unsigned short *pusPSXMem, int iSize, for(i=0;i>1]; // spu addr got by writeregister - spu.spuAddr+=2; // inc spu addr - if(spu.spuAddr>0x7ffff) spu.spuAddr=0; // wrap + *pusPSXMem++ = *(unsigned short *)(spu.spuMemC + spu.spuAddr); + spu.spuAddr += 2; + spu.spuAddr &= 0x7fffe; } } @@ -67,10 +67,10 @@ void CALLBACK SPUreadDMAMem(unsigned short *pusPSXMem, int iSize, void CALLBACK SPUwriteDMA(unsigned short val) { - spu.spuMem[spu.spuAddr>>1] = val; // spu addr got by writeregister + *(unsigned short *)(spu.spuMemC + spu.spuAddr) = val; - spu.spuAddr+=2; // inc spu addr - if(spu.spuAddr>0x7ffff) spu.spuAddr=0; // wrap + spu.spuAddr += 2; + spu.spuAddr &= 0x7fffe; } //////////////////////////////////////////////////////////////////////// @@ -86,16 +86,16 @@ void CALLBACK SPUwriteDMAMem(unsigned short *pusPSXMem, int iSize, if(spu.spuAddr + iSize*2 < 0x80000) { - memcpy(&spu.spuMem[spu.spuAddr>>1], pusPSXMem, iSize*2); + memcpy(spu.spuMemC + spu.spuAddr, pusPSXMem, iSize*2); spu.spuAddr += iSize*2; return; } for(i=0;i>1] = *pusPSXMem++; // spu addr got by writeregister - spu.spuAddr+=2; // inc spu addr - spu.spuAddr&=0x7ffff; // wrap + *(unsigned short *)(spu.spuMemC + spu.spuAddr) = *pusPSXMem++; + spu.spuAddr += 2; + spu.spuAddr &= 0x7fffe; } } diff --git a/plugins/dfsound/externals.h b/plugins/dfsound/externals.h index 3a3ff68a..3047afc8 100644 --- a/plugins/dfsound/externals.h +++ b/plugins/dfsound/externals.h @@ -181,7 +181,10 @@ typedef struct unsigned short spuStat; unsigned int spuAddr; - unsigned char * spuMemC; + union { + unsigned char *spuMemC; + unsigned short *spuMem; + }; unsigned char * pSpuIrq; unsigned int cycles_played; @@ -222,9 +225,10 @@ typedef struct int iLeftXAVol; int iRightXAVol; - int pad[32]; + SPUCHAN * s_chan; + + int pad[31]; unsigned short regArea[0x400]; - unsigned short spuMem[256*1024]; } SPUInfo; /////////////////////////////////////////////////////////// @@ -234,7 +238,6 @@ typedef struct #ifndef _IN_SPU extern SPUInfo spu; -extern SPUCHAN s_chan[]; extern REVERBInfo rvb; void do_samples(unsigned int cycles_to, int do_sync); diff --git a/plugins/dfsound/freeze.c b/plugins/dfsound/freeze.c index 0b11c108..83a7d522 100644 --- a/plugins/dfsound/freeze.c +++ b/plugins/dfsound/freeze.c @@ -264,11 +264,11 @@ long CALLBACK SPUfreeze(uint32_t ulFreezeMode, SPUFreeze_t * pF, for(i=0;is_chan[i],&s_chan[i],i); - if(s_chan[i].pCurr) - pFO->s_chan[i].iCurr=s_chan[i].pCurr-spu.spuMemC; - if(s_chan[i].pLoop) - pFO->s_chan[i].iLoop=s_chan[i].pLoop-spu.spuMemC; + save_channel(&pFO->s_chan[i],&spu.s_chan[i],i); + if(spu.s_chan[i].pCurr) + pFO->s_chan[i].iCurr=spu.s_chan[i].pCurr-spu.spuMemC; + if(spu.s_chan[i].pLoop) + pFO->s_chan[i].iLoop=spu.s_chan[i].pLoop-spu.spuMemC; } return 1; @@ -302,7 +302,7 @@ long CALLBACK SPUfreeze(uint32_t ulFreezeMode, SPUFreeze_t * pF, load_register(H_CDRight, cycles); // fix to prevent new interpolations from crashing - for(i=0;ispuAddr) { - spu.spuAddr = pFO->spuAddr; - if (spu.spuAddr == 0xbaadf00d) spu.spuAddr = 0; + if (pFO->spuAddr == 0xbaadf00d) spu.spuAddr = 0; + else spu.spuAddr = pFO->spuAddr & 0x7fffe; } spu.dwNewChannel=0; @@ -334,10 +334,10 @@ void LoadStateV5(SPUFreeze_t * pF) spu.dwChannelDead=0; for(i=0;is_chan[i],i); + load_channel(&spu.s_chan[i],&pFO->s_chan[i],i); - s_chan[i].pCurr+=(unsigned long)spu.spuMemC; - s_chan[i].pLoop+=(unsigned long)spu.spuMemC; + spu.s_chan[i].pCurr+=(unsigned long)spu.spuMemC; + spu.s_chan[i].pLoop+=(unsigned long)spu.spuMemC; } } @@ -349,7 +349,7 @@ void LoadStateUnknown(SPUFreeze_t * pF, uint32_t cycles) for(i=0;i>8) & 0x007f; - s_chan[ch].ADSRX.DecayRate=(lval>>4) & 0x000f; - s_chan[ch].ADSRX.SustainLevel=lval & 0x000f; + spu.s_chan[ch].ADSRX.AttackModeExp=(lval&0x8000)?1:0; + spu.s_chan[ch].ADSRX.AttackRate=(lval>>8) & 0x007f; + spu.s_chan[ch].ADSRX.DecayRate=(lval>>4) & 0x000f; + spu.s_chan[ch].ADSRX.SustainLevel=lval & 0x000f; //---------------------------------------------// } break; @@ -98,11 +98,11 @@ void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val, const unsigned long lval=val; //----------------------------------------------// - s_chan[ch].ADSRX.SustainModeExp = (lval&0x8000)?1:0; - s_chan[ch].ADSRX.SustainIncrease= (lval&0x4000)?0:1; - s_chan[ch].ADSRX.SustainRate = (lval>>6) & 0x007f; - s_chan[ch].ADSRX.ReleaseModeExp = (lval&0x0020)?1:0; - s_chan[ch].ADSRX.ReleaseRate = lval & 0x001f; + spu.s_chan[ch].ADSRX.SustainModeExp = (lval&0x8000)?1:0; + spu.s_chan[ch].ADSRX.SustainIncrease= (lval&0x4000)?0:1; + spu.s_chan[ch].ADSRX.SustainRate = (lval>>6) & 0x007f; + spu.s_chan[ch].ADSRX.ReleaseModeExp = (lval&0x0020)?1:0; + spu.s_chan[ch].ADSRX.ReleaseRate = lval & 0x001f; //----------------------------------------------// } break; @@ -111,7 +111,7 @@ void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val, break; //------------------------------------------------// case 14: // loop? - s_chan[ch].pLoop=spu.spuMemC+((val&~1)<<3); + spu.s_chan[ch].pLoop=spu.spuMemC+((val&~1)<<3); goto upd_irq; //------------------------------------------------// } @@ -126,9 +126,9 @@ void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val, break; //-------------------------------------------------// case H_SPUdata: - spu.spuMem[spu.spuAddr>>1] = val; - spu.spuAddr+=2; - if(spu.spuAddr>0x7ffff) spu.spuAddr=0; + *(unsigned short *)(spu.spuMemC + spu.spuAddr) = val; + spu.spuAddr += 2; + spu.spuAddr &= 0x7fffe; break; //-------------------------------------------------// case H_SPUctrl: @@ -307,15 +307,15 @@ unsigned short CALLBACK SPUreadRegister(unsigned long reg) const int ch=(r>>4)-0xc0; if(spu.dwNewChannel&(1<>16); + return (unsigned short)(spu.s_chan[ch].ADSRX.EnvelopeVol>>16); } case 14: // get loop address { const int ch=(r>>4)-0xc0; - return (unsigned short)((s_chan[ch].pLoop-spu.spuMemC)>>3); + return (unsigned short)((spu.s_chan[ch].pLoop-spu.spuMemC)>>3); } } } @@ -333,9 +333,9 @@ unsigned short CALLBACK SPUreadRegister(unsigned long reg) case H_SPUdata: { - unsigned short s=spu.spuMem[spu.spuAddr>>1]; - spu.spuAddr+=2; - if(spu.spuAddr>0x7ffff) spu.spuAddr=0; + unsigned short s = *(unsigned short *)(spu.spuMemC + spu.spuAddr); + spu.spuAddr += 2; + spu.spuAddr &= 0x7fffe; return s; } @@ -362,8 +362,8 @@ static void SoundOn(int start,int end,unsigned short val) { if((val&1) && regAreaGet(ch,6)) // mmm... start has to be set before key on !?! { - s_chan[ch].pCurr=spu.spuMemC+((regAreaGet(ch,6)&~1)<<3); // must be block aligned - s_chan[ch].pLoop=spu.spuMemC+((regAreaGet(ch,14)&~1)<<3); + spu.s_chan[ch].pCurr=spu.spuMemC+((regAreaGet(ch,6)&~1)<<3); // must be block aligned + spu.s_chan[ch].pLoop=spu.spuMemC+((regAreaGet(ch,14)&~1)<<3); spu.dwNewChannel|=(1<0) { - s_chan[ch].bFMod=1; // --> sound channel - s_chan[ch-1].bFMod=2; // --> freq channel + spu.s_chan[ch].bFMod=1; // --> sound channel + spu.s_chan[ch-1].bFMod=2; // --> freq channel } } else { - s_chan[ch].bFMod=0; // --> turn off fmod - if(ch>0&&s_chan[ch-1].bFMod==2) - s_chan[ch-1].bFMod=0; + spu.s_chan[ch].bFMod=0; // --> turn off fmod + if(ch>0&&spu.s_chan[ch-1].bFMod==2) + spu.s_chan[ch-1].bFMod=0; } } } @@ -426,7 +426,7 @@ static void NoiseOn(int start,int end,unsigned short val) for(ch=start;ch>=1) // loop channels { - s_chan[ch].bNoise=val&1; // -> noise on/off + spu.s_chan[ch].bNoise=val&1; // -> noise on/off } } @@ -456,7 +456,7 @@ static void SetVolumeL(unsigned char ch,short vol) // LEFT VOLUME } vol&=0x3fff; - s_chan[ch].iLeftVolume=vol; // store volume + spu.s_chan[ch].iLeftVolume=vol; // store volume } //////////////////////////////////////////////////////////////////////// @@ -482,7 +482,7 @@ static void SetVolumeR(unsigned char ch,short vol) // RIGHT VOLUME vol&=0x3fff; - s_chan[ch].iRightVolume=vol; + spu.s_chan[ch].iRightVolume=vol; } //////////////////////////////////////////////////////////////////////// @@ -495,10 +495,10 @@ static void SetPitch(int ch,unsigned short val) // SET PITCH if(val>0x3fff) NP=0x3fff; // get pitch val else NP=val; - s_chan[ch].iRawPitch=NP; - s_chan[ch].sinc=(NP<<4)|8; - s_chan[ch].sinc_inv=0; - if(spu_config.iUseInterpolation==1) s_chan[ch].SB[32]=1; // -> freq change in simple interpolation mode: set flag + spu.s_chan[ch].iRawPitch=NP; + spu.s_chan[ch].sinc=(NP<<4)|8; + spu.s_chan[ch].sinc_inv=0; + if(spu_config.iUseInterpolation==1) spu.s_chan[ch].SB[32]=1; // -> freq change in simple interpolation mode: set flag } //////////////////////////////////////////////////////////////////////// @@ -511,6 +511,6 @@ static void ReverbOn(int start,int end,unsigned short val) for(ch=start;ch>=1) // loop channels { - s_chan[ch].bReverb=val&1; // -> reverb on/off + spu.s_chan[ch].bReverb=val&1; // -> reverb on/off } } diff --git a/plugins/dfsound/reverb.c b/plugins/dfsound/reverb.c index bb5ee8e9..b7bcf12f 100644 --- a/plugins/dfsound/reverb.c +++ b/plugins/dfsound/reverb.c @@ -32,11 +32,11 @@ INLINE void StartREVERB(int ch) { - if(s_chan[ch].bReverb && (spu.spuCtrl&0x80)) // reverb possible? + if(spu.s_chan[ch].bReverb && (spu.spuCtrl&0x80)) // reverb possible? { - s_chan[ch].bRVBActive=!!spu_config.iUseReverb; + spu.s_chan[ch].bRVBActive=!!spu_config.iUseReverb; } - else s_chan[ch].bRVBActive=0; // else -> no reverb + else spu.s_chan[ch].bRVBActive=0; // else -> no reverb } //////////////////////////////////////////////////////////////////////// diff --git a/plugins/dfsound/spu.c b/plugins/dfsound/spu.c index b091efcc..96ef69c5 100644 --- a/plugins/dfsound/spu.c +++ b/plugins/dfsound/spu.c @@ -72,31 +72,21 @@ SPUConfig spu_config; // MAIN infos struct for each channel -SPUCHAN s_chan[MAXCHAN+1]; // channel + 1 infos (1 is security for fmod handling) REVERBInfo rvb; #ifdef THREAD_ENABLED -#include -#include -#include - // worker thread state -static struct { +static struct spu_worker { unsigned int pending:1; unsigned int exit_thread:1; int ns_to; int ctrl; int decode_pos; int silentch; - int *sRVBStart; - unsigned char *ram; unsigned int chmask; unsigned int r_chan_end; unsigned int r_decode_dirty; - pthread_t thread; - sem_t sem_avail; - sem_t sem_done; struct { int spos; int sbpos; @@ -115,14 +105,9 @@ static const void * const worker = NULL; // certain globals (were local before, but with the new timeproc I need em global) -static const int f[8][2] = { { 0, 0 }, - { 60, 0 }, - { 115, -52 }, - { 98, -55 }, - { 122, -60 } }; +static int iFMod[NSSIZE]; int ChanBuf[NSSIZE]; -int SSumLR[NSSIZE*2]; -int iFMod[NSSIZE]; +int *SSumLR; #define CDDA_BUFFER_SIZE (16384 * sizeof(uint32_t)) // must be power of 2 @@ -274,20 +259,22 @@ static int check_irq(int ch, unsigned char *pos) INLINE void StartSound(int ch) { + SPUCHAN *s_chan = &spu.s_chan[ch]; + StartADSR(ch); StartREVERB(ch); - s_chan[ch].prevflags=2; + s_chan->prevflags=2; - s_chan[ch].SB[26]=0; // init mixing vars - s_chan[ch].SB[27]=0; - s_chan[ch].iSBPos=27; + s_chan->SB[26]=0; // init mixing vars + s_chan->SB[27]=0; + s_chan->iSBPos=27; - s_chan[ch].SB[28]=0; - s_chan[ch].SB[29]=0; // init our interpolation helpers - s_chan[ch].SB[30]=0; - s_chan[ch].SB[31]=0; - s_chan[ch].spos=0; + s_chan->SB[28]=0; + s_chan->SB[29]=0; // init our interpolation helpers + s_chan->SB[30]=0; + s_chan->SB[31]=0; + s_chan->spos=0; spu.dwNewChannel&=~(1<pCurr; // set up the current pos if (start == spu.spuMemC) // ? ret = 1; - if (s_chan[ch].prevflags & 1) // 1: stop/loop + if (s_chan->prevflags & 1) // 1: stop/loop { - if (!(s_chan[ch].prevflags & 2)) + if (!(s_chan->prevflags & 2)) ret = 1; - start = s_chan[ch].pLoop; + start = s_chan->pLoop; } else check_irq(ch, start); // hack, see check_irq below.. - predict_nr = (int)start[0]; + predict_nr = start[0]; shift_factor = predict_nr & 0xf; predict_nr >>= 4; @@ -462,20 +457,20 @@ static int decode_block(int ch, int *SB) flags = start[1]; if (flags & 4) - s_chan[ch].pLoop = start; // loop adress + s_chan->pLoop = start; // loop adress start += 16; if (flags & 1) { // 1: stop/loop - start = s_chan[ch].pLoop; + start = s_chan->pLoop; check_irq(ch, start); // hack.. :( } if (start - spu.spuMemC >= 0x80000) start = spu.spuMemC; - s_chan[ch].pCurr = start; // store values for next cycle - s_chan[ch].prevflags = flags; + s_chan->pCurr = start; // store values for next cycle + s_chan->prevflags = flags; return ret; } @@ -483,32 +478,33 @@ static int decode_block(int ch, int *SB) // do block, but ignore sample data static int skip_block(int ch) { - unsigned char *start = s_chan[ch].pCurr; + SPUCHAN *s_chan = &spu.s_chan[ch]; + unsigned char *start = s_chan->pCurr; int flags; int ret = 0; - if (s_chan[ch].prevflags & 1) { - if (!(s_chan[ch].prevflags & 2)) + if (s_chan->prevflags & 1) { + if (!(s_chan->prevflags & 2)) ret = 1; - start = s_chan[ch].pLoop; + start = s_chan->pLoop; } else check_irq(ch, start); flags = start[1]; if (flags & 4) - s_chan[ch].pLoop = start; + s_chan->pLoop = start; start += 16; if (flags & 1) { - start = s_chan[ch].pLoop; + start = s_chan->pLoop; check_irq(ch, start); } - s_chan[ch].pCurr = start; - s_chan[ch].prevflags = flags; + s_chan->pCurr = start; + s_chan->prevflags = flags; return ret; } @@ -517,8 +513,8 @@ static int skip_block(int ch) static int decode_block_work(int ch, int *SB) { + const unsigned char *ram = spu.spuMemC; int predict_nr, shift_factor, flags; - const unsigned char *ram = worker->ram; int start = worker->ch[ch].start; int loop = worker->ch[ch].loop; @@ -548,16 +544,17 @@ static int decode_block_work(int ch, int *SB) // if irq is going to trigger sooner than in upd_samples, set upd_samples static void scan_for_irq(int ch, unsigned int *upd_samples) { + SPUCHAN *s_chan = &spu.s_chan[ch]; int pos, sinc, sinc_inv, end; unsigned char *block; int flags; - block = s_chan[ch].pCurr; - pos = s_chan[ch].spos; - sinc = s_chan[ch].sinc; + block = s_chan->pCurr; + pos = s_chan->spos; + sinc = s_chan->sinc; end = pos + *upd_samples * sinc; - pos += (28 - s_chan[ch].iSBPos) << 16; + pos += (28 - s_chan->iSBPos) << 16; while (pos < end) { if (block == spu.pSpuIrq) @@ -565,7 +562,7 @@ static void scan_for_irq(int ch, unsigned int *upd_samples) flags = block[1]; block += 16; if (flags & 1) { // 1: stop/loop - block = s_chan[ch].pLoop; + block = s_chan->pLoop; if (block == spu.pSpuIrq) // hack.. (see decode_block) break; } @@ -574,11 +571,11 @@ static void scan_for_irq(int ch, unsigned int *upd_samples) if (pos < end) { - sinc_inv = s_chan[ch].sinc_inv; + sinc_inv = s_chan->sinc_inv; if (sinc_inv == 0) - sinc_inv = s_chan[ch].sinc_inv = (0x80000000u / (uint32_t)sinc) << 1; + sinc_inv = s_chan->sinc_inv = (0x80000000u / (uint32_t)sinc) << 1; - pos -= s_chan[ch].spos; + pos -= s_chan->spos; *upd_samples = (((uint64_t)pos * sinc_inv) >> 32) + 1; //xprintf("ch%02d: irq sched: %3d %03d\n", // ch, *upd_samples, *upd_samples * 60 * 263 / 44100); @@ -622,12 +619,12 @@ static noinline int do_samples_##name(int (*decode_f)(int ch, int *SB), int ch, } #define fmod_recv_check \ - if(s_chan[ch].bFMod==1 && iFMod[ns]) \ - sinc = FModChangeFrequency(SB, s_chan[ch].iRawPitch, ns) + if(spu.s_chan[ch].bFMod==1 && iFMod[ns]) \ + sinc = FModChangeFrequency(SB, spu.s_chan[ch].iRawPitch, ns) make_do_samples(default, fmod_recv_check, , - StoreInterpolationVal(SB, sinc, fa, s_chan[ch].bFMod==2), - ChanBuf[ns] = iGetInterpolationVal(SB, sinc, *spos, s_chan[ch].bFMod==2), ) + StoreInterpolationVal(SB, sinc, fa, spu.s_chan[ch].bFMod==2), + ChanBuf[ns] = iGetInterpolationVal(SB, sinc, *spos, spu.s_chan[ch].bFMod==2), ) make_do_samples(noint, , fa = SB[29], , ChanBuf[ns] = fa, SB[29] = fa) #define simple_interp_store \ @@ -648,24 +645,25 @@ make_do_samples(simple, , , static int do_samples_skip(int ch, int ns_to) { + SPUCHAN *s_chan = &spu.s_chan[ch]; int ret = ns_to, ns, d; - s_chan[ch].spos += s_chan[ch].iSBPos << 16; + s_chan->spos += s_chan->iSBPos << 16; for (ns = 0; ns < ns_to; ns++) { - s_chan[ch].spos += s_chan[ch].sinc; - while (s_chan[ch].spos >= 28*0x10000) + s_chan->spos += s_chan->sinc; + while (s_chan->spos >= 28*0x10000) { d = skip_block(ch); if (d && ns < ret) ret = ns; - s_chan[ch].spos -= 28*0x10000; + s_chan->spos -= 28*0x10000; } } - s_chan[ch].iSBPos = s_chan[ch].spos >> 16; - s_chan[ch].spos &= 0xffff; + s_chan->iSBPos = s_chan->spos >> 16; + s_chan->spos &= 0xffff; return ret; } @@ -776,33 +774,38 @@ static noinline void do_decode_bufs(unsigned short *mem, int which, static void do_silent_chans(int ns_to, int silentch) { + unsigned int mask; + SPUCHAN *s_chan; int ch; - for (ch = 0; ch < MAXCHAN; ch++) + mask = silentch & 0xffffff; + for (ch = 0; mask != 0; ch++, mask >>= 1) { - if (!(silentch & (1< spu.pSpuIrq && s_chan[ch].pLoop > spu.pSpuIrq) + + s_chan = &spu.s_chan[ch]; + if (s_chan->pCurr > spu.pSpuIrq && s_chan->pLoop > spu.pSpuIrq) continue; - s_chan[ch].spos += s_chan[ch].iSBPos << 16; - s_chan[ch].iSBPos = 0; + s_chan->spos += s_chan->iSBPos << 16; + s_chan->iSBPos = 0; - s_chan[ch].spos += s_chan[ch].sinc * ns_to; - while (s_chan[ch].spos >= 28 * 0x10000) + s_chan->spos += s_chan->sinc * ns_to; + while (s_chan->spos >= 28 * 0x10000) { - unsigned char *start = s_chan[ch].pCurr; + unsigned char *start = s_chan->pCurr; skip_block(ch); - if (start == s_chan[ch].pCurr || start - spu.spuMemC < 0x1000) + if (start == s_chan->pCurr || start - spu.spuMemC < 0x1000) { // looping on self or stopped(?) spu.dwChannelDead |= 1<spos = 0; break; } - s_chan[ch].spos -= 28 * 0x10000; + s_chan->spos -= 28 * 0x10000; } } } @@ -810,6 +813,7 @@ static void do_silent_chans(int ns_to, int silentch) static void do_channels(int ns_to) { unsigned int mask; + SPUCHAN *s_chan; int *SB, sinc; int ch, d; @@ -820,26 +824,27 @@ static void do_channels(int ns_to) { if (!(mask & 1)) continue; // channel not playing? next - SB = s_chan[ch].SB; - sinc = s_chan[ch].sinc; + s_chan = &spu.s_chan[ch]; + SB = s_chan->SB; + sinc = s_chan->sinc; - if (s_chan[ch].bNoise) + if (s_chan->bNoise) d = do_samples_noise(ch, ns_to); - else if (s_chan[ch].bFMod == 2 - || (s_chan[ch].bFMod == 0 && spu_config.iUseInterpolation == 0)) + else if (s_chan->bFMod == 2 + || (s_chan->bFMod == 0 && spu_config.iUseInterpolation == 0)) d = do_samples_noint(decode_block, ch, ns_to, - SB, sinc, &s_chan[ch].spos, &s_chan[ch].iSBPos); - else if (s_chan[ch].bFMod == 0 && spu_config.iUseInterpolation == 1) + SB, sinc, &s_chan->spos, &s_chan->iSBPos); + else if (s_chan->bFMod == 0 && spu_config.iUseInterpolation == 1) d = do_samples_simple(decode_block, ch, ns_to, - SB, sinc, &s_chan[ch].spos, &s_chan[ch].iSBPos); + SB, sinc, &s_chan->spos, &s_chan->iSBPos); else d = do_samples_default(decode_block, ch, ns_to, - SB, sinc, &s_chan[ch].spos, &s_chan[ch].iSBPos); + SB, sinc, &s_chan->spos, &s_chan->iSBPos); - d = MixADSR(&s_chan[ch].ADSRX, d); + d = MixADSR(&s_chan->ADSRX, d); if (d < ns_to) { spu.dwChannelOn &= ~(1 << ch); - s_chan[ch].ADSRX.EnvelopeVol = 0; + s_chan->ADSRX.EnvelopeVol = 0; memset(&ChanBuf[d], 0, (ns_to - d) * sizeof(ChanBuf[0])); } @@ -849,12 +854,12 @@ static void do_channels(int ns_to) spu.decode_dirty_ch |= 1 << ch; } - if (s_chan[ch].bFMod == 2) // fmod freq channel + if (s_chan->bFMod == 2) // fmod freq channel memcpy(iFMod, &ChanBuf, ns_to * sizeof(iFMod[0])); - if (s_chan[ch].bRVBActive) - mix_chan_rvb(0, ns_to, s_chan[ch].iLeftVolume, s_chan[ch].iRightVolume, spu.sRVBStart); + if (s_chan->bRVBActive) + mix_chan_rvb(0, ns_to, s_chan->iLeftVolume, s_chan->iRightVolume, spu.sRVBStart); else - mix_chan(0, ns_to, s_chan[ch].iLeftVolume, s_chan[ch].iRightVolume); + mix_chan(0, ns_to, s_chan->iLeftVolume, s_chan->iRightVolume); } } @@ -864,8 +869,12 @@ static void do_samples_finish(int ns_to, int silentch, int decode_pos); #ifdef THREAD_ENABLED +static void thread_work_start(void); +static void thread_work_wait_sync(void); + static void queue_channel_work(int ns_to, int silentch) { + const SPUCHAN *s_chan; unsigned int mask; int ch; @@ -873,28 +882,27 @@ static void queue_channel_work(int ns_to, int silentch) worker->ctrl = spu.spuCtrl; worker->decode_pos = spu.decode_pos; worker->silentch = silentch; - worker->sRVBStart = spu.sRVBStart; - worker->ram = spu.spuMemC; mask = worker->chmask = spu.dwChannelOn & 0xffffff; for (ch = 0; mask != 0; ch++, mask >>= 1) { if (!(mask & 1)) continue; - worker->ch[ch].spos = s_chan[ch].spos; - worker->ch[ch].sbpos = s_chan[ch].iSBPos; - worker->ch[ch].sinc = s_chan[ch].sinc; - worker->ch[ch].adsr = s_chan[ch].ADSRX; - worker->ch[ch].start = s_chan[ch].pCurr - spu.spuMemC; - worker->ch[ch].loop = s_chan[ch].pLoop - spu.spuMemC; - if (s_chan[ch].prevflags & 1) + s_chan = &spu.s_chan[ch]; + worker->ch[ch].spos = s_chan->spos; + worker->ch[ch].sbpos = s_chan->iSBPos; + worker->ch[ch].sinc = s_chan->sinc; + worker->ch[ch].adsr = s_chan->ADSRX; + worker->ch[ch].start = s_chan->pCurr - spu.spuMemC; + worker->ch[ch].loop = s_chan->pLoop - spu.spuMemC; + if (s_chan->prevflags & 1) worker->ch[ch].start = worker->ch[ch].loop; worker->ch[ch].ns_to = do_samples_skip(ch, ns_to); } worker->pending = 1; - sem_post(&worker->sem_avail); + thread_work_start(); } static void do_channel_work(void) @@ -903,9 +911,10 @@ static void do_channel_work(void) unsigned int decode_dirty_ch = 0; int *SB, sinc, spos, sbpos; int d, ch, ns_to; + SPUCHAN *s_chan; ns_to = worker->ns_to; - memset(worker->sRVBStart, 0, ns_to * sizeof(worker->sRVBStart[0]) * 2); + memset(spu.sRVBStart, 0, ns_to * sizeof(spu.sRVBStart[0]) * 2); mask = worker->chmask; for (ch = 0; mask != 0; ch++, mask >>= 1) @@ -916,14 +925,16 @@ static void do_channel_work(void) spos = worker->ch[ch].spos; sbpos = worker->ch[ch].sbpos; sinc = worker->ch[ch].sinc; - SB = s_chan[ch].SB; - if (s_chan[ch].bNoise) + s_chan = &spu.s_chan[ch]; + SB = s_chan->SB; + + if (s_chan->bNoise) do_lsfr_samples(d, worker->ctrl, &spu.dwNoiseCount, &spu.dwNoiseVal); - else if (s_chan[ch].bFMod == 2 - || (s_chan[ch].bFMod == 0 && spu_config.iUseInterpolation == 0)) + else if (s_chan->bFMod == 2 + || (s_chan->bFMod == 0 && spu_config.iUseInterpolation == 0)) do_samples_noint(decode_block_work, ch, d, SB, sinc, &spos, &sbpos); - else if (s_chan[ch].bFMod == 0 && spu_config.iUseInterpolation == 1) + else if (s_chan->bFMod == 0 && spu_config.iUseInterpolation == 1) do_samples_simple(decode_block_work, ch, d, SB, sinc, &spos, &sbpos); else do_samples_default(decode_block_work, ch, d, SB, sinc, &spos, &sbpos); @@ -937,16 +948,16 @@ static void do_channel_work(void) if (ch == 1 || ch == 3) { - do_decode_bufs((void *)worker->ram, ch/2, ns_to, worker->decode_pos); + do_decode_bufs(spu.spuMem, ch/2, ns_to, worker->decode_pos); decode_dirty_ch |= 1 << ch; } - if (s_chan[ch].bFMod == 2) // fmod freq channel + if (s_chan->bFMod == 2) // fmod freq channel memcpy(iFMod, &ChanBuf, ns_to * sizeof(iFMod[0])); - if (s_chan[ch].bRVBActive) - mix_chan_rvb(0, ns_to, s_chan[ch].iLeftVolume, s_chan[ch].iRightVolume, worker->sRVBStart); + if (s_chan->bRVBActive) + mix_chan_rvb(0, ns_to, s_chan->iLeftVolume, s_chan->iRightVolume, spu.sRVBStart); else - mix_chan(0, ns_to, s_chan[ch].iLeftVolume, s_chan[ch].iRightVolume); + mix_chan(0, ns_to, s_chan->iLeftVolume, s_chan->iRightVolume); } worker->r_chan_end = endmask; @@ -961,7 +972,7 @@ static void sync_worker_thread(void) if (!worker->pending) return; - sem_wait(&worker->sem_done); + thread_work_wait_sync(); worker->pending = 0; mask = worker->chmask; @@ -969,9 +980,9 @@ static void sync_worker_thread(void) if (!(mask & 1)) continue; // be sure there was no keyoff while thread was working - if (s_chan[ch].ADSRX.State != ADSR_RELEASE) - s_chan[ch].ADSRX.State = worker->ch[ch].adsr.State; - s_chan[ch].ADSRX.EnvelopeVol = worker->ch[ch].adsr.EnvelopeVol; + if (spu.s_chan[ch].ADSRX.State != ADSR_RELEASE) + spu.s_chan[ch].ADSRX.State = worker->ch[ch].adsr.State; + spu.s_chan[ch].ADSRX.EnvelopeVol = worker->ch[ch].adsr.EnvelopeVol; } spu.dwChannelOn &= ~worker->r_chan_end; @@ -1145,8 +1156,8 @@ void schedule_next_irq(void) { if (spu.dwChannelDead & (1 << ch)) continue; - if ((unsigned long)(spu.pSpuIrq - s_chan[ch].pCurr) > IRQ_NEAR_BLOCKS * 16 - && (unsigned long)(spu.pSpuIrq - s_chan[ch].pLoop) > IRQ_NEAR_BLOCKS * 16) + if ((unsigned long)(spu.pSpuIrq - spu.s_chan[ch].pCurr) > IRQ_NEAR_BLOCKS * 16 + && (unsigned long)(spu.pSpuIrq - spu.s_chan[ch].pLoop) > IRQ_NEAR_BLOCKS * 16) continue; scan_for_irq(ch, &upd_samples); @@ -1226,8 +1237,8 @@ int CALLBACK SPUplayCDDAchannel(short *pcm, int nbytes) // to be called after state load void ClearWorkingState(void) { - memset(SSumLR,0,sizeof(SSumLR)); // init some mixing buffers - memset(iFMod,0,sizeof(iFMod)); + memset(SSumLR, 0, NSSIZE * 2 * 4); // init some mixing buffers + memset(iFMod, 0, sizeof(iFMod)); spu.pS=(short *)spu.pSpuBuffer; // setup soundbuffer pointer } @@ -1237,8 +1248,8 @@ void SetupStreams(void) int i; spu.pSpuBuffer = (unsigned char *)malloc(32768); // alloc mixing buffer - spu.sRVBStart = (int *)malloc(NSSIZE*2*4); // alloc reverb buffer - memset(spu.sRVBStart,0,NSSIZE*2*4); + spu.sRVBStart = calloc(NSSIZE * 2, sizeof(spu.sRVBStart[0])); + SSumLR = calloc(NSSIZE * 2, sizeof(SSumLR[0])); spu.XAStart = // alloc xa buffer (uint32_t *)malloc(44100 * sizeof(uint32_t)); @@ -1254,10 +1265,10 @@ void SetupStreams(void) for(i=0;i init sustain - s_chan[i].ADSRX.SustainIncrease = 1; - s_chan[i].pLoop=spu.spuMemC; - s_chan[i].pCurr=spu.spuMemC; + spu.s_chan[i].ADSRX.SustainLevel = 0xf; // -> init sustain + spu.s_chan[i].ADSRX.SustainIncrease = 1; + spu.s_chan[i].pLoop=spu.spuMemC; + spu.s_chan[i].pCurr=spu.spuMemC; } ClearWorkingState(); @@ -1272,24 +1283,53 @@ void RemoveStreams(void) spu.pSpuBuffer = NULL; free(spu.sRVBStart); // free reverb buffer spu.sRVBStart = NULL; + free(SSumLR); + SSumLR = NULL; free(spu.XAStart); // free XA buffer spu.XAStart = NULL; free(spu.CDDAStart); // free CDDA buffer spu.CDDAStart = NULL; } -#ifdef THREAD_ENABLED +#if defined(C64X_DSP) + +/* special code for TI C64x DSP */ +#include "spu_c64x.c" + +#elif defined(THREAD_ENABLED) + +#include +#include +#include + +static struct { + pthread_t thread; + sem_t sem_avail; + sem_t sem_done; +} t; + +/* generic pthread implementation */ + +static void thread_work_start(void) +{ + sem_post(&t.sem_avail); +} + +static void thread_work_wait_sync(void) +{ + sem_wait(&t.sem_done); +} static void *spu_worker_thread(void *unused) { while (1) { - sem_wait(&worker->sem_avail); + sem_wait(&t.sem_avail); if (worker->exit_thread) break; do_channel_work(); - sem_post(&worker->sem_done); + sem_post(&t.sem_done); } return NULL; @@ -1305,23 +1345,23 @@ static void init_spu_thread(void) worker = calloc(1, sizeof(*worker)); if (worker == NULL) return; - ret = sem_init(&worker->sem_avail, 0, 0); + ret = sem_init(&t.sem_avail, 0, 0); if (ret != 0) goto fail_sem_avail; - ret = sem_init(&worker->sem_done, 0, 0); + ret = sem_init(&t.sem_done, 0, 0); if (ret != 0) goto fail_sem_done; - ret = pthread_create(&worker->thread, NULL, spu_worker_thread, NULL); + ret = pthread_create(&t.thread, NULL, spu_worker_thread, NULL); if (ret != 0) goto fail_thread; return; fail_thread: - sem_destroy(&worker->sem_done); + sem_destroy(&t.sem_done); fail_sem_done: - sem_destroy(&worker->sem_avail); + sem_destroy(&t.sem_avail); fail_sem_avail: free(worker); worker = NULL; @@ -1332,10 +1372,10 @@ static void exit_spu_thread(void) if (worker == NULL) return; worker->exit_thread = 1; - sem_post(&worker->sem_avail); - pthread_join(worker->thread, NULL); - sem_destroy(&worker->sem_done); - sem_destroy(&worker->sem_avail); + sem_post(&t.sem_avail); + pthread_join(t.thread, NULL); + sem_destroy(&t.sem_done); + sem_destroy(&t.sem_avail); free(worker); worker = NULL; } @@ -1355,13 +1395,14 @@ static void exit_spu_thread(void) // SPUINIT: this func will be called first by the main emu long CALLBACK SPUinit(void) { - spu.spuMemC = (unsigned char *)spu.spuMem; // just small setup + spu.spuMemC = calloc(1, 512 * 1024); memset((void *)&rvb, 0, sizeof(REVERBInfo)); InitADSR(); - spu.spuAddr = 0xffffffff; + spu.s_chan = calloc(MAXCHAN+1, sizeof(spu.s_chan[0])); // channel + 1 infos (1 is security for fmod handling) + + spu.spuAddr = 0; spu.decode_pos = 0; - memset((void *)s_chan, 0, sizeof(s_chan)); spu.pSpuIrq = spu.spuMemC; SetupStreams(); // prepare streaming @@ -1402,11 +1443,17 @@ long CALLBACK SPUclose(void) long CALLBACK SPUshutdown(void) { SPUclose(); - RemoveStreams(); // no more streaming - spu.bSpuInit=0; exit_spu_thread(); + free(spu.spuMemC); + spu.spuMemC = NULL; + free(spu.s_chan); + spu.s_chan = NULL; + + RemoveStreams(); // no more streaming + spu.bSpuInit=0; + return 0; } @@ -1483,15 +1530,18 @@ void spu_get_debug_info(int *chans_out, int *run_chans, int *fmod_chans_out, int { int ch = 0, fmod_chans = 0, noise_chans = 0, irq_chans = 0; + if (spu.s_chan == NULL) + return; + for(;ch +#include +#include "spu_c64x.h" + +static dsp_mem_region_t region; + +static struct { + void *handle; + int (*dsp_open)(void); + dsp_mem_region_t (*dsp_shm_alloc)(dsp_cache_t _type, sU32 _numBytes); + int (*dsp_shm_free)(dsp_mem_region_t _mem); + void (*dsp_close)(void); + int (*dsp_component_load)(const char *_path, const char *_name, dsp_component_id_t *_id); + int (*dsp_cache_inv_virt)(void *_virtAddr, sU32 _size); + int (*dsp_rpc_send)(const dsp_msg_t *_msgTo); + int (*dsp_rpc_recv)(dsp_msg_t *_msgFrom); + void (*dsp_logbuf_print)(void); +} f; + +static void thread_work_start(void) +{ + do_channel_work(); +} + +static void thread_work_wait_sync(void) +{ +} + +static void init_spu_thread(void) +{ + struct region_mem *mem; + int ret; + + if (f.handle == NULL) { + const char lib[] = "libc64.so.1"; + int failed = 0; + + f.handle = dlopen(lib, RTLD_NOW); + if (f.handle == NULL) { + fprintf(stderr, "can't load %s: %s\n", lib, dlerror()); + return; + } + #define LDS(name) \ + failed |= (f.name = dlsym(f.handle, #name)) == NULL + LDS(dsp_open); + LDS(dsp_close); + LDS(dsp_shm_alloc); + LDS(dsp_shm_free); + LDS(dsp_cache_inv_virt); + LDS(dsp_component_load); + LDS(dsp_rpc_send); + LDS(dsp_rpc_recv); + LDS(dsp_logbuf_print); + #undef LDS + if (failed) { + fprintf(stderr, "missing symbol(s) in %s\n", lib); + dlclose(f.handle); + f.handle = NULL; + return; + } + } + + ret = f.dsp_open(); + if (ret != 0) { + fprintf(stderr, "dsp_open failed: %d\n", ret); + return; + } + + region = f.dsp_shm_alloc(DSP_CACHE_R, sizeof(*mem)); // writethrough + if (region.size < sizeof(*mem) || region.virt_addr == 0) { + fprintf(stderr, "dsp_shm_alloc failed\n"); + goto fail_mem; + } + mem = (void *)region.virt_addr; + + // override default allocations + free(spu.spuMemC); + spu.spuMemC = mem->spu_ram; + free(spu.sRVBStart); + spu.sRVBStart = mem->RVB; + free(SSumLR); + SSumLR = mem->SSumLR; + free(spu.s_chan); + spu.s_chan = mem->s_chan; + worker = &mem->worker; + + printf("C64x DSP ready.\n"); + return; + +fail_mem: + f.dsp_close(); + worker = NULL; +} + +static void exit_spu_thread(void) +{ + if (worker == NULL) + return; + + if (worker->pending) + thread_work_wait_sync(); + f.dsp_shm_free(region); + f.dsp_close(); + + spu.spuMemC = NULL; + spu.sRVBStart = NULL; + SSumLR = NULL; + spu.s_chan = NULL; + worker = NULL; +} + +// vim:shiftwidth=1:expandtab diff --git a/plugins/dfsound/spu_c64x.h b/plugins/dfsound/spu_c64x.h new file mode 100644 index 00000000..ba2a4c37 --- /dev/null +++ b/plugins/dfsound/spu_c64x.h @@ -0,0 +1,9 @@ + +struct region_mem { + unsigned char spu_ram[512 * 1024]; + int RVB[NSSIZE * 2]; + int SSumLR[NSSIZE * 2]; + SPUCHAN s_chan[24 + 1]; + struct spu_worker worker; +}; +