Supermodel/Src/Sound/SCSPDSP.cpp

493 lines
10 KiB
C++
Raw Permalink Normal View History

/**
** Supermodel
** A Sega Model 3 Arcade Emulator.
** Copyright 2011 Bart Trzynadlowski, Nik Henson
**
** This file is part of Supermodel.
**
** Supermodel 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 3 of the License, or (at your option)
** any later version.
**
** Supermodel 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 Supermodel. If not, see <http://www.gnu.org/licenses/>.
**/
/*
* SCSPDSP.cpp
*
* SCSP DSP emulation.
*/
#include "Supermodel.h"
2011-04-24 01:14:00 +00:00
#include "SCSPDSP.h"
//#include <assert.h>
#define assert(x) ; // disable assert() for releases
//#include <memory.h>
//#include <stdio.h>
//#include <malloc.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
2011-04-24 01:14:00 +00:00
#pragma warning(disable:4311)
#define DYNBUF 0x10000
//this doesn't work at all
//#define USEFLOATPACK
//the PACK func in asm plus mov [esi],ax
unsigned char PackFunc[]={0x8B,0xD8,0xA9,0x00,0x00,0x80,0x00,0x75,0x02,0xF7,0xD3,0xF7,0xD3,0x0F,0xBD,0xCB,
0xF7,0xD9,0xC1,0xE0,0x08,0x83,0xC1,0x16,0xD3,0xE0,0xC1,0xF8,0x13,0xC1,0xE1,0x0B,
0x25,0xFF,0x87,0x00,0x00,0x0B,0xC1,0x66,0x89,0x06};
unsigned char UnpackFunc[]={0x8B,0xD8,0x8B,0xC8,0x81,0xE3,0x00,0x80,0x00,0x00,0x25,0xFF,0x07,
0x00,0x00,0xC1,0xE9,0x0B,0xC1,0xE0,0x0B,0xC1,0xE3,0x08,0x83,0xE1,0x0F,0x0B,0xC3,
0xD1,0xEB,0x81,0xF3,0x00,0x00,0x40,0x00,0x0B,0xC3,0x83,0xC1,0x08,0xC1,0xE0,0x08,
0xD3,0xF8};
//#if 0
//unsigned short inline PACK(signed int val)
//{
///* signed int v1=val;
// int n=0;
// while(((v1>>22)&1) == ((v1>>23)&1))
// {
// v1<<=1;
// ++n;
// }
// v1<<=8;
// v1>>=11+8;
// v1=(v1&(~0x7800))|(n<<11);
// return v1;
//*/
//#ifdef USEFLOATPACK
// unsigned short f;
// __asm
// {
// mov eax,val
// mov ebx,eax
// test eax,0x00800000
// jne negval
// not ebx
//negval: not ebx
// bsr ecx,ebx
// neg ecx
// shl eax,8
// add ecx,22
// shl eax,cl
// sar eax,8+11
// shl ecx,11
// and eax,~0x7800
// or eax,ecx
// mov f,ax
// }
// return f;
//#else
//
// //cut to 16 bits
// unsigned int f=((unsigned int ) val)>>8;
// return f;
//#endif
//}
//
//signed int inline UNPACK(unsigned short val)
//{
///* if(val)
// int a=1;
// unsigned int mant=val&0x7ff;
// unsigned int exp=(val>>11)&0xf;
// unsigned int sign=(val>>15)&1;
// signed int r=0;
// r|=mant<<11;
// r|=sign<<23;
// r|=(sign^1)<<22;
//
// //signed int r=val<<8;
// //if(r&0x00800000)
// // r|=0xFF000000;
// r<<=8;
// r>>=8+exp;
// return r;
//*/
//#ifdef USEFLOATPACK
// signed int r;
// __asm
// {
// xor eax,eax
// mov ax,val
// mov ebx,eax
// mov ecx,eax
// and ebx,0x8000
// and eax,0x07ff
// shr ecx,11
// shl eax,11
// shl ebx,8
// and ecx,0xF
// or eax,ebx
// shr ebx,1
// xor ebx,0x00400000
// or eax,ebx
// add ecx,8
// shl eax,8
// sar eax,cl
// mov r,eax
// }
//#else
// //unpack 16->24
// signed int r=val<<8;
// r<<=8;
// r>>=8;
//#endif
// return r;
//}
//#else
static UINT16 PACK(INT32 val)
2011-04-24 01:14:00 +00:00
{
int sign = (val >> 23) & 0x1;
UINT32 temp = (val ^ (val << 1)) & 0xFFFFFF;
int exponent = 0;
for (int k = 0; k < 12; k++)
2011-04-24 01:14:00 +00:00
{
if (temp & 0x800000)
break;
temp <<= 1;
exponent += 1;
}
if (exponent < 12)
val = (val << exponent) & 0x3FFFFF;
else
val <<= 11;
val >>= 11;
val &= 0x7FF;
2011-04-24 01:14:00 +00:00
val |= sign << 15;
val |= exponent << 11;
return (UINT16)val;
2011-04-24 01:14:00 +00:00
}
static INT32 UNPACK(UINT16 val)
2011-04-24 01:14:00 +00:00
{
int sign = (val >> 15) & 0x1;
int exponent = (val >> 11) & 0xF;
int mantissa = val & 0x7FF;
INT32 uval = mantissa << 11;
2011-04-24 01:14:00 +00:00
if (exponent > 11)
{
2011-04-24 01:14:00 +00:00
exponent = 11;
uval |= sign << 22;
}
2011-04-24 01:14:00 +00:00
else
{
2011-04-24 01:14:00 +00:00
uval |= (sign ^ 1) << 22;
}
2011-04-24 01:14:00 +00:00
uval |= sign << 23;
uval <<= 8;
uval >>= 8;
uval >>= exponent;
return uval;
}
//#endif
2011-04-24 01:14:00 +00:00
void SCSPDSP_Init(_SCSPDSP *DSP)
{
memset(DSP, 0, sizeof(_SCSPDSP));
DSP->RBL = (8 * 1024); // Initial RBL is 0
DSP->Stopped = 1;
2011-04-24 01:14:00 +00:00
}
//#ifndef DYNDSP
2011-04-24 01:14:00 +00:00
void SCSPDSP_Step(_SCSPDSP *DSP)
{
INT32 ACC = 0; //26 bit
INT32 SHIFTED = 0; //24 bit
INT32 X = 0; //24 bit
INT32 Y = 0; //13 bit
INT32 B = 0; //26 bit
INT32 INPUTS = 0; //24 bit
INT32 MEMVAL = 0;
INT32 FRC_REG = 0; //13 bit
INT32 Y_REG = 0; //24 bit
UINT32 ADDR = 0;
UINT32 ADRS_REG = 0; //13 bit
int step;
if (DSP->Stopped)
2011-04-24 01:14:00 +00:00
return;
memset(DSP->EFREG, 0, 2 * 16);
for (step = 0; step </*128*/DSP->LastStep; ++step)
2011-04-24 01:14:00 +00:00
{
UINT16 *IPtr = DSP->MPRO + step * 4;
// if(IPtr[0]==0 && IPtr[1]==0 && IPtr[2]==0 && IPtr[3]==0)
// break;
UINT32 TRA = (IPtr[0] >> 8) & 0x7F;
UINT32 TWT = (IPtr[0] >> 7) & 0x01;
UINT32 TWA = (IPtr[0] >> 0) & 0x7F;
UINT32 XSEL = (IPtr[1] >> 15) & 0x01;
UINT32 YSEL = (IPtr[1] >> 13) & 0x03;
UINT32 IRA = (IPtr[1] >> 6) & 0x3F;
UINT32 IWT = (IPtr[1] >> 5) & 0x01;
UINT32 IWA = (IPtr[1] >> 0) & 0x1F;
UINT32 TABLE = (IPtr[2] >> 15) & 0x01;
UINT32 MWT = (IPtr[2] >> 14) & 0x01;
UINT32 MRD = (IPtr[2] >> 13) & 0x01;
UINT32 EWT = (IPtr[2] >> 12) & 0x01;
UINT32 EWA = (IPtr[2] >> 8) & 0x0F;
UINT32 ADRL = (IPtr[2] >> 7) & 0x01;
UINT32 FRCL = (IPtr[2] >> 6) & 0x01;
UINT32 SHIFT = (IPtr[2] >> 4) & 0x03;
UINT32 YRL = (IPtr[2] >> 3) & 0x01;
UINT32 NEGB = (IPtr[2] >> 2) & 0x01;
UINT32 ZERO = (IPtr[2] >> 1) & 0x01;
UINT32 BSEL = (IPtr[2] >> 0) & 0x01;
UINT32 NOFL = (IPtr[3] >> 15) & 0x01; //????
UINT32 COEF = (IPtr[3] >> 9) & 0x3f;
UINT32 MASA = (IPtr[3] >> 2) & 0x1f; //???
UINT32 ADREB = (IPtr[3] >> 1) & 0x01;
UINT32 NXADR = (IPtr[3] >> 0) & 0x01;
INT64 v;
2011-04-24 01:14:00 +00:00
//operations are done at 24 bit precision
#if 0
if (MASA)
int a = 1;
if (NOFL)
int a = 1;
#endif
2011-04-24 01:14:00 +00:00
//INPUTS RW
// colmns97 hits this
// assert(IRA<0x32);
if (IRA <= 0x1f)
INPUTS = DSP->MEMS[IRA];
else if (IRA <= 0x2F)
INPUTS = DSP->MIXS[IRA - 0x20] << 4; //MIXS is 20 bit
else if (IRA <= 0x31)
INPUTS = DSP->EXTS[IRA - 0x30] << 8; //EXTS is 16 bit
else
return;
2011-04-24 01:14:00 +00:00
INPUTS <<= 8;
INPUTS >>= 8;
2011-04-24 01:14:00 +00:00
//if(INPUTS&0x00800000)
// INPUTS|=0xFF000000;
if (IWT)
2011-04-24 01:14:00 +00:00
{
DSP->MEMS[IWA] = MEMVAL; //MEMVAL was selected in previous MRD
if (IRA == IWA)
INPUTS = MEMVAL;
2011-04-24 01:14:00 +00:00
}
//Operand sel
//B
if (!ZERO)
2011-04-24 01:14:00 +00:00
{
if (BSEL)
B = ACC;
2011-04-24 01:14:00 +00:00
else
{
B = DSP->TEMP[(TRA + DSP->DEC) & 0x7F];
B <<= 8;
B >>= 8;
2011-04-24 01:14:00 +00:00
//if(B&0x00800000)
// B|=0xFF000000; //Sign extend
2011-04-24 01:14:00 +00:00
}
if (NEGB)
B = 0 - B;
2011-04-24 01:14:00 +00:00
}
else
B = 0;
2011-04-24 01:14:00 +00:00
//X
if (XSEL)
X = INPUTS;
2011-04-24 01:14:00 +00:00
else
{
X = DSP->TEMP[(TRA + DSP->DEC) & 0x7F];
X <<= 8;
X >>= 8;
2011-04-24 01:14:00 +00:00
//if(X&0x00800000)
// X|=0xFF000000;
}
//Y
if (YSEL == 0)
Y = FRC_REG;
else if (YSEL == 1)
Y = DSP->COEF[COEF] >> 3; //COEF is 16 bits
else if (YSEL == 2)
Y = (Y_REG >> 11) & 0x1FFF;
else if (YSEL == 3)
Y = (Y_REG >> 4) & 0x0FFF;
if (YRL)
Y_REG = INPUTS;
2011-04-24 01:14:00 +00:00
//Shifter
if (SHIFT == 0)
2011-04-24 01:14:00 +00:00
{
SHIFTED = ACC;
if (SHIFTED > 0x007FFFFF)
SHIFTED = 0x007FFFFF;
if (SHIFTED < (-0x00800000))
SHIFTED = -0x00800000;
2011-04-24 01:14:00 +00:00
}
else if (SHIFT == 1)
2011-04-24 01:14:00 +00:00
{
SHIFTED = ACC * 2;
if (SHIFTED > 0x007FFFFF)
SHIFTED = 0x007FFFFF;
if (SHIFTED < (-0x00800000))
SHIFTED = -0x00800000;
2011-04-24 01:14:00 +00:00
}
else if (SHIFT == 2)
2011-04-24 01:14:00 +00:00
{
SHIFTED = ACC * 2;
SHIFTED <<= 8;
SHIFTED >>= 8;
2011-04-24 01:14:00 +00:00
//SHIFTED&=0x00FFFFFF;
//if(SHIFTED&0x00800000)
// SHIFTED|=0xFF000000;
}
else if (SHIFT == 3)
2011-04-24 01:14:00 +00:00
{
SHIFTED = ACC;
SHIFTED <<= 8;
SHIFTED >>= 8;
2011-04-24 01:14:00 +00:00
//SHIFTED&=0x00FFFFFF;
//if(SHIFTED&0x00800000)
// SHIFTED|=0xFF000000;
}
//ACCUM
Y <<= 19;
Y >>= 19;
2011-04-24 01:14:00 +00:00
//if(Y&0x1000)
// Y|=0xFFFFF000;
v = (((INT64)X*(INT64)Y) >> 12);
ACC = (int)v + B;
2011-04-24 01:14:00 +00:00
if (TWT)
DSP->TEMP[(TWA + DSP->DEC) & 0x7F] = SHIFTED;
2011-04-24 01:14:00 +00:00
if (FRCL)
2011-04-24 01:14:00 +00:00
{
if (SHIFT == 3)
FRC_REG = SHIFTED & 0x0FFF;
2011-04-24 01:14:00 +00:00
else
FRC_REG = (SHIFTED >> 11) & 0x1FFF;
2011-04-24 01:14:00 +00:00
}
if (MRD || MWT)
//if(0)
2011-04-24 01:14:00 +00:00
{
ADDR = DSP->MADRS[MASA];
if (!TABLE)
ADDR += DSP->DEC;
if (ADREB)
ADDR += ADRS_REG & 0x0FFF;
if (NXADR)
2011-04-24 01:14:00 +00:00
ADDR++;
if (!TABLE)
ADDR &= DSP->RBL - 1;
2011-04-24 01:14:00 +00:00
else
ADDR &= 0xFFFF;
2011-04-24 01:14:00 +00:00
//ADDR<<=1;
//ADDR+=DSP->RBP<<13;
//MEMVAL=DSP->SCSPRAM[ADDR>>1];
ADDR += DSP->RBP << 12;
if (ADDR > 0x7ffff) ADDR = 0; //!! MAME has ADDR <<= 1 in here, but this seems to be wrong?
if (MRD && (step & 1)) //memory only allowed on odd? DoA inserts NOPs on even
2011-04-24 01:14:00 +00:00
{
if (NOFL)
MEMVAL = DSP->SCSPRAM[ADDR] << 8;
2011-04-24 01:14:00 +00:00
else
MEMVAL = UNPACK(DSP->SCSPRAM[ADDR]);
2011-04-24 01:14:00 +00:00
}
if (MWT && (step & 1))
2011-04-24 01:14:00 +00:00
{
if (NOFL)
DSP->SCSPRAM[ADDR] = SHIFTED >> 8;
2011-04-24 01:14:00 +00:00
else
DSP->SCSPRAM[ADDR] = PACK(SHIFTED);
2011-04-24 01:14:00 +00:00
}
}
if (ADRL)
2011-04-24 01:14:00 +00:00
{
if (SHIFT == 3)
ADRS_REG = (SHIFTED >> 12) & 0xFFF;
2011-04-24 01:14:00 +00:00
else
ADRS_REG = (INPUTS >> 16);
2011-04-24 01:14:00 +00:00
}
if (EWT)
DSP->EFREG[EWA] += SHIFTED >> 8;
2011-04-24 01:14:00 +00:00
}
--DSP->DEC;
memset(DSP->MIXS, 0, 4 * 16);
2011-04-24 01:14:00 +00:00
}
void SCSPDSP_SetSample(_SCSPDSP *DSP, INT32 sample, int SEL, int MXL)
2011-04-24 01:14:00 +00:00
{
//DSP->MIXS[SEL]+=sample<<(MXL+1)/*7*/;
DSP->MIXS[SEL] += sample;
// if(MXL)
// int a=1;
2011-04-24 01:14:00 +00:00
}
void SCSPDSP_Start(_SCSPDSP *DSP)
{
int i;
DSP->Stopped = 0;
for (i = 127; i >= 0; --i)
2011-04-24 01:14:00 +00:00
{
UINT16 *IPtr = DSP->MPRO + i * 4;
2011-04-24 01:14:00 +00:00
if (IPtr[0] != 0 || IPtr[1] != 0 || IPtr[2] != 0 || IPtr[3] != 0)
2011-04-24 01:14:00 +00:00
break;
}
DSP->LastStep = i + 1;
2011-04-24 01:14:00 +00:00
/*
2011-04-24 01:14:00 +00:00
int test=0;
if(test)
{
//test
FILE *f1;
f1=fopen("MPRO","wb");
fwrite(DSP->MPRO,128*4*2,1,f1);
fwrite(DSP->COEF,64*2,1,f1);
fwrite(DSP->MADRS,32*2,1,f1);
fclose(f1);
}
*/
2011-04-24 01:14:00 +00:00
for(int t=0;t<0x10000;++t)
{
signed int unp=UNPACK(t);
unsigned short t2=PACK(unp);
if(t2!=t)
int a=1;
}
#ifdef DYNDSP
SCSPDSP_Recompile(DSP);
#endif
}