236 lines
4.8 KiB
C++
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);
|
|
}
|
|
|