BizHawk/waterbox/ss/scsp.h

320 lines
6.0 KiB
C++

/******************************************************************************/
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* scsp.h:
** Copyright (C) 2015-2016 Mednafen Team
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public License
** as published by the Free Software Foundation; either version 2
** of the License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software Foundation, Inc.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
class SS_SCSP
{
public:
SS_SCSP() MDFN_COLD;
~SS_SCSP() MDFN_COLD;
void Reset(bool powering_up) MDFN_COLD;
void RunSample(int16* outlr);
template<typename T, bool IsWrite>
void RW(uint32 A, T& V); //, void (*time_sucker)();
INLINE uint16* GetEXTSPtr(void)
{
return EXTS;
}
INLINE uint16* GetRAMPtr(void)
{
return RAM;
}
enum
{
GSREG_MVOL = 0,
GSREG_DAC18B,
GSREG_MEM4MB,
GSREG_RBP,
GSREG_RBL,
GSREG_MSLC,
};
uint32 GetRegister(const unsigned id, char* const special, const uint32 special_len) MDFN_COLD;
void SetRegister(const unsigned id, const uint32 value) MDFN_COLD;
private:
void RecalcSoundInt(void);
void RecalcMainInt(void);
enum
{
ENV_PHASE_ATTACK = 0,
ENV_PHASE_DECAY1 = 1,
ENV_PHASE_DECAY2 = 2,
ENV_PHASE_RELEASE = 3
};
uint16 SlotRegs[0x20][0x10];
struct Slot
{
bool KeyBit;
uint32 StartAddr; // 20 bits, memory address.
uint16 LoopStart; // 16 bits, in samples.
uint16 LoopEnd; // 16 bits, in samples.
bool WF8Bit;
uint8 LoopMode;
enum
{
LOOP_DISABLED = 0,
LOOP_NORMAL = 1,
LOOP_REVERSE = 2,
LOOP_ALTERNATING = 3
};
uint8 SourceControl;
enum
{
SOURCE_MEMORY = 0,
SOURCE_NOISE = 1,
SOURCE_ZERO = 2,
SOURCE_UNDEFINED = 3
};
uint8 SBControl;
union
{
struct
{
uint8 AttackRate;
uint8 Decay1Rate;
uint8 Decay2Rate;
uint8 ReleaseRate;
};
uint8 EnvRates[4];
};
bool AttackHold;
bool AttackLoopLink;
uint8 DecayLevel;
uint8 KRS;
uint8 TotalLevel;
bool SoundDirect; // When true, bypass EG, TL, ALFO volume control
bool StackWriteInhibit;
uint8 ModLevel;
uint8 ModInputX;
uint8 ModInputY;
uint8 Octave;
uint16 FreqNum;
uint8 ALFOModLevel;
uint8 ALFOWaveform;
uint8 PLFOModLevel;
uint8 PLFOWaveform;
uint8 LFOFreq;
bool LFOReset;
// DSP mix stack
uint8 ToDSPSelect;
uint8 ToDSPLevel;
int16 DirectVolume[2]; // 1.14 fixed point, derived from DISDL and DIPAN
int16 EffectVolume[2]; // 1.14 fixed point, derived from EFSDL and EFPAN
//
//
uint32 PhaseWhacker;
uint16 CurrentAddr;
bool InLoop;
bool LoopSub;
bool WFAllowAccess;
uint32 EnvLevel; // 0 ... 0x3FF
uint8 EnvPhase; // ENV_PHASE_ATTACK ... ENV_PHASE_RELEASE (0...3)
bool EnvGCBTPrev;
uint8 LFOCounter;
int16 LFOTimeCounter;
} Slots[32];
uint16 EXTS[2];
void RunEG(Slot* s, const unsigned key_eg_scale);
uint8 GetALFO(Slot* s);
int GetPLFO(Slot* s);
void RunLFO(Slot* s);
uint16 SoundStack[0x40];
uint16 SoundStackDelayer[4];
uint16 MasterVolume; // 1.8 fixed point, derived from MVOL
uint8 MVOL;
bool DAC18bit;
bool Mem4Mb;
uint32 SlotMonitorWhich;
uint16 SlotMonitorData;
bool KeyExecute;
uint32 LFSR;
uint32 GlobalCounter;
//
//
enum
{
MIDIF_INPUT_EMPTY = 0x01,
MIDIF_INPUT_FULL = 0x02,
MIDIF_INPUT_OFLOW = 0x04,
MIDIF_OUTPUT_EMPTY= 0x08,
MIDIF_OUTPUT_FULL = 0x10
};
struct
{
uint8 InputFIFO[4];
uint8 InputRP, InputWP, InputCount;
uint8 OutputFIFO[4];
uint8 OutputRP, OutputWP, OutputCount;
uint8 Flags;
//
INLINE uint8 ReadInput(void)
{
uint8 ret = InputFIFO[InputRP]; // May not be correct for InputCount == 0; test.
if(InputCount)
{
InputRP = (InputRP + 1) & 0x3;
InputCount--;
Flags &= ~MIDIF_INPUT_FULL;
if(!InputCount)
Flags |= MIDIF_INPUT_EMPTY;
}
return ret;
}
INLINE void WriteOutput(uint8 V)
{
if(OutputCount == 4) // May not be correct; test.
return;
OutputFIFO[OutputWP] = V;
OutputWP = (OutputWP + 1) & 0x3;
OutputCount++;
Flags &= ~MIDIF_OUTPUT_EMPTY;
if(OutputCount == 4)
Flags |= MIDIF_OUTPUT_FULL;
}
void Reset(void)
{
memset(InputFIFO, 0, sizeof(InputFIFO));
memset(OutputFIFO, 0, sizeof(OutputFIFO));
InputRP = InputWP = InputCount = 0;
OutputRP = OutputWP = OutputCount = 0;
Flags = MIDIF_INPUT_EMPTY | MIDIF_OUTPUT_EMPTY;
}
} MIDI;
//
//
uint16 SCIEB;
uint16 SCIPD;
uint16 MCIEB;
uint16 MCIPD;
uint8 SCILV[3];
//
//
struct
{
uint8 Control;
uint8 Counter;
bool PrevClockIn;
int32 Reload;
} Timers[3];
//
//
// DMEA, DRGA, and DTLG are apparently not altered by executing DMA.
//
uint32 DMEA;
uint16 DRGA;
uint16 DTLG;
bool DMA_Execute;
bool DMA_Direction;
bool DMA_Gate;
void RunDMA(void);
//
//
uint8 RBP;
uint8 RBL;
void RunDSP(void);
struct DSPS
{
uint64 MPROG[0x80];
uint32 TEMP[0x80]; // 24 bit
uint32 MEMS[0x20]; // 24 bit
uint16 COEF[64]; // 13 bit
uint16 MADRS[32]; // 16 bit
uint32 MIXS[0x10]; // 20 bit
uint16 EFREG[0x10];
uint32 INPUTS; // 24 bit
uint32 Product; // 26 bit
uint32 SFT_REG; // 26 bit
uint16 FRC_REG; // 13 bit
uint32 Y_REG; // 24 bit, latches INPUTS
uint16 ADRS_REG; // 12 bit, latches output of A_SEL(which selects between shifter output and upper 8 bits of INPUTS
uint16 MDEC_CT;
uint32 RWAddr;
bool WritePending;
uint16 WriteValue;
uint8 ReadPending; // = 1 (NOFL=0), =2 (NOFL=1) at time or MRT
uint32 ReadValue;
} DSP;
//
//
uint16 RAM[262144 * 2]; // *2 for dummy so we don't have to have so many conditionals in the playback code.
};