Merge pull request #1615 from ramapcsx2/psxmode-rebase-spu2x

psxmode: SPU2-X backwards compatibility with the original SPU
This commit is contained in:
ramapcsx2 2016-10-10 15:36:50 +02:00 committed by GitHub
commit 0f022da98c
6 changed files with 265 additions and 83 deletions

View File

@ -20,6 +20,8 @@
#define NOMINMAX
extern bool psxmode;
struct StereoOut16;
struct StereoOut32;
struct StereoOutFloat;

View File

@ -834,9 +834,9 @@ void Mix()
}
// Commit Core 0 output to ram before mixing Core 1:
spu2M_WriteFast(0x800 + OutPos, Ext.Left);
spu2M_WriteFast(0xA00 + OutPos, Ext.Right);
spu2M_WriteFast( 0x800 + OutPos, Ext.Left );
spu2M_WriteFast( 0xA00 + OutPos, Ext.Right );
WaveDump::WriteCore( 0, CoreSrc_External, Ext );
Ext = ApplyVolume( Ext, Cores[1].ExtVol );

View File

@ -31,6 +31,7 @@
//
StereoOut32 V_Core::ReadInput_HiFi()
{
if (psxmode)ConLog("ReadInput_HiFi!!!!!\n");
InputPosRead &= ~1;
//
//#ifdef PCM24_S1_INTERLEAVE

View File

@ -164,13 +164,6 @@ void UpdateDebugDialog()
TextOut(hdc,IX+4,IY+32,t,6);
vcd.displayPeak = 0;
if(vcd.lastSetStartA != vc.StartA)
{
printf(" *** Warning! Core %d Voice %d: StartA should be %06x, and is %06x.\n",
c,v,vcd.lastSetStartA,vc.StartA);
vcd.lastSetStartA = vc.StartA;
}
}
// top now: 400

View File

@ -441,6 +441,10 @@ struct V_Core
u32 KeyOn; // not the KON register (though maybe it is)
// psxmode caches
u16 psxSoundDataTransferControl;
u16 psxSPUSTAT;
StereoOut32 downbuf[8];
StereoOut32 upbuf[8];
int dbpos, ubpos;

View File

@ -42,6 +42,8 @@ int PlayMode;
bool has_to_call_irq=false;
bool psxmode = false;
void SetIrqCall(int core)
{
// reset by an irq disable/enable cycle, behaviour found by
@ -116,6 +118,7 @@ void V_Core::Init( int index )
{
ConLog( "* SPU2-X: Init SPU2 core %d \n", index );
memset( this, 0, sizeof(V_Core) );
psxmode = false;
const int c = Index = index;
@ -258,23 +261,27 @@ void V_Core::UpdateFeedbackBuffersB()
void V_Core::UpdateEffectsBufferSize()
{
const s32 newbufsize = EffectsEndA - EffectsStartA + 1;
//printf("Rvb Area change: ESA = %x, EEA = %x, Size(dec) = %d, Size(hex) = %x FxEnable = %d\n", EffectsStartA, EffectsEndA, newbufsize * 2, newbufsize * 2, FxEnable);
if( (newbufsize*2) > 0x20000 ) // max 128kb per core
{
//printf("too big, returning\n");
//return;
}
if (newbufsize == EffectsBufferSize && EffectsStartA == EffectsBufferStart) return;
// bad optimization?
//if (newbufsize == EffectsBufferSize && EffectsStartA == EffectsBufferStart) return;
//printf("Rvb Area change: ESA = %x, EEA = %x, Size(dec) = %d, Size(hex) = %x FxEnable = %d\n", EffectsStartA, EffectsEndA, newbufsize * 2, newbufsize * 2, FxEnable);
RevBuffers.NeedsUpdated = false;
EffectsBufferSize = newbufsize;
EffectsBufferStart = EffectsStartA;
if( EffectsBufferSize <= 0 ) return;
//AnalyzeReverbPreset();
// debug: shows reverb parameters in console
if(MsgToConsole()) AnalyzeReverbPreset();
// Rebuild buffer indexers.
RevBuffers.ACC_SRC_A0 = EffectsBufferIndexer( Revb.ACC_SRC_A0 );
RevBuffers.ACC_SRC_A1 = EffectsBufferIndexer( Revb.ACC_SRC_A1 );
@ -401,6 +408,7 @@ __forceinline void TimeUpdate(u32 cClocks)
Cores[0].DMAICounter-=TickInterval;
if(Cores[0].DMAICounter<=0)
{
//ConLog("counter set and callback!\n");
Cores[0].MADR=Cores[0].TADR;
Cores[0].DMAICounter=0;
if(dma4callback) dma4callback();
@ -489,6 +497,17 @@ void V_VolumeSlide::RegSet( u16 src )
Value = GetVol32( src );
}
static u32 map_spu1to2(u32 addr)
{
return addr * 4 + (addr >= 0x200 ? 0xc0000 : 0);
}
static u32 map_spu2to1(u32 addr)
{
// if (addr >= 0x800 && addr < 0xc0000) oh dear
return (addr - (addr >= 0xc0000 ? 0xc0000 : 0)) / 4;
}
void V_Core::WriteRegPS1( u32 mem, u16 value )
{
pxAssume( Index == 0 ); // Valid on Core 0 only!
@ -504,29 +523,59 @@ void V_Core::WriteRegPS1( u32 mem, u16 value )
switch(vval)
{
case 0x0: //VOLL (Volume L)
Voices[voice].Volume.Left.Mode = 0;
Voices[voice].Volume.Left.RegSet( value << 1 );
Voices[voice].Volume.Left.Reg_VOL = value;
break;
case 0x2: //VOLR (Volume R)
Voices[voice].Volume.Right.Mode = 0;
Voices[voice].Volume.Right.RegSet( value << 1 );
Voices[voice].Volume.Right.Reg_VOL = value;
break;
{
V_VolumeSlide& thisvol = vval == 0 ? Voices[voice].Volume.Left : Voices[voice].Volume.Right;
thisvol.Reg_VOL = value;
case 0x4: Voices[voice].Pitch = value; break;
case 0x6: Voices[voice].StartA = (u32)value << 8; break;
if (value & 0x8000) // +Lin/-Lin/+Exp/-Exp
{
thisvol.Mode = (value & 0xF000) >> 12;
thisvol.Increment = (value & 0x7F);
// We're not sure slides work 100%
if (IsDevBuild) ConLog("* SPU2: Voice uses Slides in Mode = %x, Increment = %x\n", thisvol.Mode, thisvol.Increment);
}
else
{
// Constant Volume mode (no slides or envelopes)
// Volumes range from 0x3fff to 0x7fff, with 0x4000 serving as
// the "sign" bit, so a simple bitwise extension will do the trick:
thisvol.RegSet(value << 1);
thisvol.Mode = 0;
thisvol.Increment = 0;
}
//ConLog("voice %x VOL%c write: %x\n", voice, vval == 0 ? 'L' : 'R', value);
break;
}
case 0x4:
if (value > 0x3fff) ConLog("* SPU2: Pitch setting too big: 0x%x\n", value);
Voices[voice].Pitch = value & 0x3fff;
//ConLog("voice %x Pitch write: %x\n", voice, Voices[voice].Pitch);
break;
case 0x6:
Voices[voice].StartA = map_spu1to2(value);
//ConLog("voice %x StartA write: %x\n", voice, Voices[voice].StartA);
break;
case 0x8: // ADSR1 (Envelope)
Voices[voice].ADSR.regADSR1 = value;
//ConLog("voice %x regADSR1 write: %x\n", voice, Voices[voice].ADSR.regADSR1);
break;
case 0xa: // ADSR2 (Envelope)
Voices[voice].ADSR.regADSR2 = value;
//ConLog("voice %x regADSR2 write: %x\n", voice, Voices[voice].ADSR.regADSR2);
break;
case 0xc: // Voice 0..23 ADSR Current Volume
// not commonly set by games
Voices[voice].ADSR.Value = value * 0x10001U;
ConLog("voice %x ADSR.Value write: %x\n", voice, Voices[voice].ADSR.Value);
break;
case 0xe:
Voices[voice].LoopStartA = map_spu1to2(value);
//ConLog("voice %x LoopStartA write: %x\n", voice, Voices[voice].LoopStartA);
break;
case 0xe: Voices[voice].LoopStartA = (u32)value << 8; break;
jNO_DEFAULT;
}
@ -568,70 +617,154 @@ void V_Core::WriteRegPS1( u32 mem, u16 value )
case 0x1d90:// Channel FM (pitch lfo) mode (0-15)
SPU2_FastWrite(REG_S_PMON,value);
if (value!=0)ConLog("spu2x warning: wants to set Pitch Modulation reg1 to %x \n", value);
break;
case 0x1d92:// Channel FM (pitch lfo) mode (16-23)
SPU2_FastWrite(REG_S_PMON+2,value);
if (value != 0)ConLog("spu2x warning: wants to set Pitch Modulation reg2 to %x \n", value);
break;
case 0x1d94:// Channel Noise mode (0-15)
SPU2_FastWrite(REG_S_NON,value);
if (value != 0) ConLog("spu2x warning: wants to set Channel Noise mode reg1 to %x\n", value);
break;
case 0x1d96:// Channel Noise mode (16-23)
SPU2_FastWrite(REG_S_NON+2,value);
if (value != 0) ConLog("spu2x warning: wants to set Channel Noise mode reg2 to %x\n", value);
break;
case 0x1d98:// Channel Reverb mode (0-15)
case 0x1d98:// 1F801D98h - Voice 0..23 Reverb mode aka Echo On (EON) (R/W)
//Regs.VMIXEL = value & 0xFFFF;
SPU2_FastWrite(REG_S_VMIXEL,value);
SPU2_FastWrite(REG_S_VMIXER,value);
//ConLog("spu2x warning: setting reverb mode reg1 to %x \n", Regs.VMIXEL);
break;
case 0x1d9a:// Channel Reverb mode (16-23)
case 0x1d9a:// 1F801D98h + 2 - Voice 0..23 Reverb mode aka Echo On (EON) (R/W)
//Regs.VMIXEL = value << 16;
SPU2_FastWrite(REG_S_VMIXEL+2,value);
SPU2_FastWrite(REG_S_VMIXER+2,value);
//ConLog("spu2x warning: setting reverb mode reg2 to %x \n", Regs.VMIXEL);
break;
case 0x1d9c:// Channel Reverb mode (0-15)
SPU2_FastWrite(REG_S_VMIXL,value);
SPU2_FastWrite(REG_S_VMIXR,value);
// this was wrong? // edit: appears so!
//case 0x1d9c:// Channel Reverb mode (0-15)
// SPU2_FastWrite(REG_S_VMIXL,value);
// SPU2_FastWrite(REG_S_VMIXR,value);
//break;
//case 0x1d9e:// Channel Reverb mode (16-23)
// SPU2_FastWrite(REG_S_VMIXL+2,value);
// SPU2_FastWrite(REG_S_VMIXR+2,value);
//break;
case 0x1d9c: // Voice 0..15 ON/OFF (status) (ENDX) (R) // writeable but hw overrides it shortly after
//Regs.ENDX &= 0xff0000;
ConLog("spu2x warning: wants to set ENDX reg1 to %x \n", value);
break;
case 0x1d9e:// Channel Reverb mode (16-23)
SPU2_FastWrite(REG_S_VMIXL+2,value);
SPU2_FastWrite(REG_S_VMIXR+2,value);
case 0x1d9e:// // Voice 15..23 ON/OFF (status) (ENDX) (R) // writeable but hw overrides it shortly after
//Regs.ENDX &= 0xffff;
ConLog("spu2x warning: wants to set ENDX reg2 to %x \n", value);
break;
case 0x1da2:// Reverb work area start
{
u32 val = (u32)value << 8;
SPU2_FastWrite(REG_A_ESA, val&0xFFFF);
SPU2_FastWrite(REG_A_ESA+2,val>>16);
EffectsStartA = map_spu1to2(value);
//EffectsEndA = 0xFFFFF; // fixed EndA in psx mode
Cores[0].RevBuffers.NeedsUpdated = true;
ReverbX = 0;
}
break;
case 0x1da4:
IRQA = (u32)value<<8;
IRQA = map_spu1to2(value);
//ConLog("SPU2-X Setting IRQA to %x \n", IRQA);
break;
case 0x1da6:
TSA = (u32)value<<8;
TSA = map_spu1to2(value);
//ConLog("SPU2-X Setting TSA to %x \n", TSA);
break;
case 0x1da8: // Spu Write to Memory
//ConLog("SPU direct DMA Write. Current TSA = %x\n", TSA);
if (Cores[0].IRQEnable && (Cores[0].IRQA <= Cores[0].TSA))
{
SetIrqCall(0);
_irqcallback();
}
DmaWrite(value);
show = false;
break;
case 0x1daa:
SPU2_FastWrite(REG_C_ATTR,value);
SPU2_FastWrite(REG_C_ATTR, value);
break;
case 0x1dae:
SPU2_FastWrite(REG_P_STATX,value);
case 0x1dac: // 1F801DACh - Sound RAM Data Transfer Control (should be 0004h)
ConLog("SPU Sound RAM Data Transfer Control (should be 4) : value = %x \n", value);
psxSoundDataTransferControl = value;
break;
case 0x1da8:// Spu Write to Memory
DmaWrite(value);
show=false;
case 0x1dae: // 1F801DAEh - SPU Status Register (SPUSTAT) (R)
// The SPUSTAT register should be treated read-only (writing is possible in so far that the written
// value can be read-back for a short moment, however, thereafter the hardware is overwriting that value).
//Regs.STATX = value;
break;
case 0x1DB0: // 1F801DB0h 4 CD Volume Left/Right
break; // cd left?
case 0x1DB2:
break;// cd right?
case 0x1DB4: // 1F801DB4h 4 Extern Volume Left / Right
break; // Extern left?
case 0x1DB6:
break; // Extern right?
case 0x1DB8: // 1F801DB8h 4 Current Main Volume Left/Right
break; // Current left?
case 0x1DBA:
break; // Current right?
case 0x1DBC: // 1F801DBCh 4 Unknown? (R/W)
break;
case 0x1DBE:
break;
case 0x1DC0: Revb.FB_SRC_A = value * 4; break;
case 0x1DC2: Revb.FB_SRC_B = value * 4; break;
case 0x1DC4: Revb.IIR_ALPHA = value; break;
case 0x1DC6: Revb.ACC_COEF_A = value; break;
case 0x1DC8: Revb.ACC_COEF_B = value; break;
case 0x1DCA: Revb.ACC_COEF_C = value; break;
case 0x1DCC: Revb.ACC_COEF_D = value; break;
case 0x1DCE: Revb.IIR_COEF = value; break;
case 0x1DD0: Revb.FB_ALPHA = value; break;
case 0x1DD2: Revb.FB_X = value; break;
case 0x1DD4: Revb.IIR_DEST_A0 = value * 4; break;
case 0x1DD6: Revb.IIR_DEST_A1 = value * 4; break;
case 0x1DD8: Revb.ACC_SRC_A0 = value * 4; break;
case 0x1DDA: Revb.ACC_SRC_A1 = value * 4; break;
case 0x1DDC: Revb.ACC_SRC_B0 = value * 4; break;
case 0x1DDE: Revb.ACC_SRC_B1 = value * 4; break;
case 0x1DE0: Revb.IIR_SRC_A0 = value * 4; break;
case 0x1DE2: Revb.IIR_SRC_A1 = value * 4; break;
case 0x1DE4: Revb.IIR_DEST_B0 = value * 4; break;
case 0x1DE6: Revb.IIR_DEST_B1 = value * 4; break;
case 0x1DE8: Revb.ACC_SRC_C0 = value * 4; break;
case 0x1DEA: Revb.ACC_SRC_C1 = value * 4; break;
case 0x1DEC: Revb.ACC_SRC_D0 = value * 4; break;
case 0x1DEE: Revb.ACC_SRC_D1 = value * 4; break;
case 0x1DF0: Revb.IIR_SRC_B0 = value * 4; break; // IIR_SRC_B0 and IIR_SRC_B1 supposedly swapped on SPU2
case 0x1DF2: Revb.IIR_SRC_B1 = value * 4; break; // but I don't believe it! (games in psxmode sound better unswapped)
case 0x1DF4: Revb.MIX_DEST_A0 = value * 4; break;
case 0x1DF6: Revb.MIX_DEST_A1 = value * 4; break;
case 0x1DF8: Revb.MIX_DEST_B0 = value * 4; break;
case 0x1DFA: Revb.MIX_DEST_B1 = value * 4; break;
case 0x1DFC: Revb.IN_COEF_L = value; break;
case 0x1DFE: Revb.IN_COEF_R = value; break;
}
if(show) FileLog("[%10d] (!) SPU write mem %08x value %04x\n",Cycles,mem,value);
@ -655,24 +788,40 @@ u16 V_Core::ReadRegPS1(u32 mem)
u8 vval = reg&0xf;
switch(vval)
{
case 0: //VOLL (Volume L)
case 0x0: //VOLL (Volume L)
//value=Voices[voice].VolumeL.Mode;
//value=Voices[voice].VolumeL.Value;
value = Voices[voice].Volume.Left.Reg_VOL;
break;
break;
case 1: //VOLR (Volume R)
case 0x2: //VOLR (Volume R)
//value=Voices[voice].VolumeR.Mode;
//value=Voices[voice].VolumeR.Value;
value = Voices[voice].Volume.Right.Reg_VOL;
break;
break;
case 2: value = Voices[voice].Pitch; break;
case 3: value = Voices[voice].StartA; break;
case 4: value = Voices[voice].ADSR.regADSR1; break;
case 5: value = Voices[voice].ADSR.regADSR2; break;
case 6: value = Voices[voice].ADSR.Value >> 16; break;
case 7: value = Voices[voice].LoopStartA; break;
case 0x4:
value = Voices[voice].Pitch;
//ConLog("voice %d read pitch result = %x\n", voice, value);
break;
case 0x6:
value = map_spu2to1(Voices[voice].StartA);
//ConLog("voice %d read StartA result = %x\n", voice, value);
break;
case 0x8:
value = Voices[voice].ADSR.regADSR1;
break;
case 0xa:
value = Voices[voice].ADSR.regADSR2;
break;
case 0xc: // Voice 0..23 ADSR Current Volume
value = Voices[voice].ADSR.Value >> 16; // no clue
//if (value != 0) ConLog("voice %d read ADSR.Value result = %x\n", voice, value);
break;
case 0xe:
value = map_spu2to1(Voices[voice].LoopStartA);
//ConLog("voice %d read LoopStartA result = %x\n", voice, value);
break;
jNO_DEFAULT;
}
@ -684,48 +833,50 @@ u16 V_Core::ReadRegPS1(u32 mem)
case 0x1d84: value = FxVol.Left >> 16; break;
case 0x1d86: value = FxVol.Right >> 16; break;
case 0x1d88: value = 0; break;
case 0x1d88: value = 0; break; // Voice 0..23 Key ON(Start Attack / Decay / Sustain) (W)
case 0x1d8a: value = 0; break;
case 0x1d8c: value = 0; break;
case 0x1d8c: value = 0; break; // Voice 0..23 Key OFF (Start Release) (W)
case 0x1d8e: value = 0; break;
case 0x1d90: value = Regs.PMON&0xFFFF; break;
case 0x1d90: value = Regs.PMON&0xFFFF; break; // Voice 0..23 Channel FM(pitch lfo) mode(R / W)
case 0x1d92: value = Regs.PMON>>16; break;
case 0x1d94: value = Regs.NON&0xFFFF; break;
case 0x1d94: value = Regs.NON&0xFFFF; break; // Voice 0..23 Channel Noise mode (R/W)
case 0x1d96: value = Regs.NON>>16; break;
case 0x1d98: value = Regs.VMIXEL&0xFFFF; break;
case 0x1d98: value = Regs.VMIXEL&0xFFFF; break; // Voice 0..23 Channel Reverb mode (R/W)
case 0x1d9a: value = Regs.VMIXEL>>16; break;
case 0x1d9c: value = Regs.VMIXL&0xFFFF; break;
case 0x1d9e: value = Regs.VMIXL>>16; break;
/*case 0x1d9c: value = Regs.VMIXL&0xFFFF; break;*/ // this is wrong?
/*case 0x1d9e: value = Regs.VMIXL >> 16; break;*/
case 0x1d9c: value = Regs.ENDX & 0xFFFF; break;// Voice 0..23 Channel ON / OFF(status) (R) (ENDX)
case 0x1d9e: value = Regs.ENDX >> 16;
case 0x1da2:
#if 0
// This smells of old hack
if( value != EffectsStartA>>3 )
{
value = EffectsStartA>>3;
UpdateEffectsBufferSize();
ReverbX = 0;
}
#else
value = EffectsStartA >> 3;
#endif
break;
case 0x1da4: value = IRQA>>3; break;
case 0x1da6: value = TSA>>3; break;
case 0x1daa:
value = SPU2read(REG_C_ATTR);
value = map_spu2to1(EffectsStartA);
break;
case 0x1dae:
value = 0; //SPU2read(REG_P_STATX)<<3;
case 0x1da4:
value = map_spu2to1(IRQA);
//ConLog("SPU2-X IRQA read: 0x1da4 = %x , (IRQA = %x)\n", value, IRQA);
break;
case 0x1da6:
value = map_spu2to1(TSA);
//ConLog("SPU2-X TSA read: 0x1da6 = %x , (TSA = %x)\n", value, TSA);
break;
case 0x1da8:
value = DmaRead();
show=false;
break;
case 0x1daa:
value = Cores[0].Regs.ATTR;
//ConLog("SPU2-X ps1 reg psxSPUCNT read return value: %x\n", value);
break;
case 0x1dac: // 1F801DACh - Sound RAM Data Transfer Control (should be 0004h)
value = psxSoundDataTransferControl;
break;
case 0x1dae:
value = Cores[0].Regs.STATX;
//ConLog("SPU2-X ps1 reg REG_P_STATX read return value: %x\n", value);
break;
}
if(show) FileLog("[%10d] (!) SPU read mem %08x value %04x\n",Cycles,mem,value);
@ -1122,6 +1273,37 @@ static void __fastcall RegWrite_Core( u16 value )
case REG_S_ADMAS:
if ( MsgToConsole() ) ConLog("* SPU2-X: Core %d AutoDMAControl set to %d (at cycle %d)\n",core,value, Cycles);
if (psxmode) ConLog("* SPU2-X: Writing to REG_S_ADMAS while in PSX mode! value: %x",value);
// hack for ps1driver which writes -1 (and never turns the adma off after psxlogo).
// adma isn't available in psx mode either
if (value == 32767) {
psxmode = true;
//memset(_spu2mem, 0, 0x200000);
Cores[1].FxEnable = 0;
Cores[1].EffectsStartA = 0x7FFF8; // park core1 effect area in inaccessible mem
Cores[1].EffectsEndA = 0x7FFFF;
Cores[1].ExtEffectsStartA = 0x7FFF8; // park core1 ext effect area in high mem
Cores[1].ExtEffectsStartA = 0x7FFFF;
Cores[1].ReverbX = 0;
Cores[1].RevBuffers.NeedsUpdated = true;
Cores[0].ReverbX = 0;
Cores[0].RevBuffers.NeedsUpdated = true;
for (uint v = 0; v < 24; ++v)
{
Cores[1].Voices[v].Volume = V_VolumeSlideLR(0, 0); // V_VolumeSlideLR::Max;
Cores[1].Voices[v].SCurrent = 28;
Cores[1].Voices[v].ADSR.Value = 0;
Cores[1].Voices[v].ADSR.Phase = 0;
Cores[1].Voices[v].Pitch = 0x0;
Cores[1].Voices[v].NextA = 0x6FFFF;
Cores[1].Voices[v].StartA = 0x6FFFF;
Cores[1].Voices[v].LoopStartA = 0x6FFFF;
Cores[1].Voices[v].Modulated = 0;
}
return;
}
thiscore.AutoDMACtrl=value;
if(value==0)