BizHawk/waterbox/ss/scu_dsp_common.inc

236 lines
4.8 KiB
C++

/******************************************************************************/
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* scu_dsp_common.inc:
** 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.
*/
// base ptr must match the waterbox base load location!
#if (defined(__x86_64__) && defined(__code_model_small__) && !defined(__PIC__) && !defined(__pic__)) || SIZEOF_VOID_P <= 4
#define DSP_INSTR_BASE_UIPT 0x36d00000000ul
#define DSP_INSTR_RECOVER_TCAST uint32
#else
#define DSP_INSTR_BASE_UIPT ((uintptr_t)DSP_Init)
#define DSP_INSTR_RECOVER_TCAST int32
#endif
// See loop in "SCU_UpdateDSP()" in scu.inc, and END/ENDI handling in scu_dsp_misc.cpp
enum { DSP_EndCCSubVal = 1000000 };
void DSP_Init(void);
struct DSP_ITS;
union DSPR48
{
#ifdef MSB_FIRST
struct
{
uint16 dummy;
uint16 H;
uint32 L;
};
#else
struct
{
uint32 L;
uint16 H;
uint16 dummy;
};
#endif
uint64 T; // Upper 16 bits may be non-zero "garbage", so don't assume they're zero in code that reads from this variable.
};
struct DSPS
{
sscpu_timestamp_t LastTS;
int32 CycleCounter;
int32 T0_Until;
//
enum
{
// No execute = 0x00000000 <= 0
// Paused + No execute = 0x80000000 <= 0
// Paused + Execute = 0x80000001 <= 0
// Execute = 0x00000001 > 0
STATE_MASK_PAUSE = 0x80000000,
STATE_MASK_EXECUTE = 0x00000001,
};
int32 State;
INLINE bool IsRunning(void) // returns true if not stopped and not paused.
{
return State > 0;
}
uint64 NextInstr;
uint8 PC;
uint8 RA;
bool FlagZ;
bool FlagS;
bool FlagV;
bool FlagC;
bool FlagEnd;
uint8 TOP;
uint16 LOP; // 12 bits
DSPR48 AC;
DSPR48 P;
union
{
uint8 CT[4]; // 6 bits(each)
uint32 CT32;
};
uint32 RX;
uint32 RY;
uint32 RAO;
uint32 WAO;
uint32 DataRAM[4][64];
uint64 ProgRAM[256]; // Upper 32 bits = actual raw instruction, lower 32 bits = horrible emulator handler pointer madness
};
// ALU Op: bits 26-29 - *16
// X Op: bits 23-25 - * 8
// Y Op: bits 17-19 - * 8
// D1 Op: bits 12-13 - * 4
extern void (*const DSP_GenFuncTable[2][16][8][8][4])(void);
// Hold/Format/Direction: bits 12-14
// Hold: bit 14
// Format: bit 13
// Direction: bit 12
// RAM: bits 8-10
//
extern void (*const DSP_DMAFuncTable[2][8][8])(void);
//
// Dest: bits 26-29
// Condition: bits 19-25
//
extern void (*const DSP_MVIFuncTable[2][16][128])(void);
//
// Condition: bits 19-25
//
extern void (*const DSP_JMPFuncTable[2][128])(void);
//
// LPS, BTM, END, ENDI(bits 29-31 = 0x7)
// bits 27-28
//
extern void (*const DSP_MiscFuncTable[2][4])(void);
extern DSPS DSP;
template<bool looped = false>
static INLINE uint64 DSP_DecodeInstruction(const uint32 instr)
{
void (*aal)(void);
switch((instr >> 28) & 0xF)
{
default:
aal = DSP_GenFuncTable[looped][0][0][0][0];
break;
case 0x0:
case 0x1:
case 0x2:
case 0x3:
aal = DSP_GenFuncTable[looped][(instr >> 26) & 0xF][(instr >> 23) & 0x7][(instr >> 17) & 0x7][(instr >> 12) & 0x3];
break;
case 0x8:
case 0x9:
case 0xA:
case 0xB:
aal = DSP_MVIFuncTable[looped][(instr >> 26) & 0xF][(instr >> 19) & 0x7F];
break;
case 0xC:
aal = DSP_DMAFuncTable[looped][(instr >> 12) & 0x7][(instr >> 8) & 0x7];
break;
case 0xD:
aal = DSP_JMPFuncTable[looped][(instr >> 19) & 0x7F];
break;
case 0xE:
case 0xF:
aal = DSP_MiscFuncTable[looped][(instr >> 27) & 0x3];
break;
}
return ((uint64)instr << 32) | (uint32)((uintptr_t)aal - DSP_INSTR_BASE_UIPT);
}
template<bool looped>
static INLINE uint32 DSP_InstrPre(void)
{
const uint32 instr = DSP.NextInstr >> 32;
if(!looped || !DSP.LOP)
{
DSP.NextInstr = DSP.ProgRAM[DSP.PC];
DSP.PC++;
}
if(looped)
DSP.LOP -= (bool)DSP.LOP;
return instr;
}
template<unsigned cond>
static INLINE bool DSP_TestCond(void)
{
if(!(cond & 0x40))
return true;
//
//
//
bool ret = false;
if(cond & 0x1)
ret |= DSP.FlagZ;
if(cond & 0x2)
ret |= DSP.FlagS;
if(cond & 0x4)
ret |= DSP.FlagC;
if(cond & 0x8)
ret |= (DSP.T0_Until < DSP.CycleCounter);
//if(cond & 0x10) // ?
return ret == (bool)(cond & 0x20);
}