Files
2014-08-21 13:32:02 -05:00

1295 lines
30 KiB
C++

/*
www.freedo.org
The first and only working 3DO multiplayer emulator.
The FreeDO licensed under modified GNU LGPL, with following notes:
* The owners and original authors of the FreeDO have full right to develop closed source derivative work.
* Any non-commercial uses of the FreeDO sources or any knowledge obtained by studying or reverse engineering
of the sources, or any other material published by FreeDO have to be accompanied with full credits.
* Any commercial uses of FreeDO sources or any knowledge obtained by studying or reverse engineering of the sources,
or any other material published by FreeDO is strictly forbidden without owners approval.
The above notes are taking precedence over GNU LGPL in conflicting situations.
Project authors:
Alexander Troosh
Maxim Grishin
Allen Wright
John Sammons
Felix Lazarev
*/
// DSP.cpp: implementation of the CDSP class.
//
//////////////////////////////////////////////////////////////////////
#include "freedoconfig.h"
#include "DSP.h"
#include "Clio.h"
#if 0 //20 bit ALU
#define ALUSIZEMASK 0xFFFFf000
#else //32 bit ALU
#define ALUSIZEMASK 0xFFFFFFFF
#endif
//////////////////////////////////////////////////////////////////////
// Flag logic
//////////////////////////////////////////////////////////////////////
#define TOPBIT 0x80000000
#define ADDCFLAG(A,B,rd) (((((A)&(B))&TOPBIT) || (((A)&~rd)&TOPBIT) || (((B)&~rd)&TOPBIT)) ? 1 : 0 )
#define SUBCFLAG(A,B,rd) (((((A)&~(B))&TOPBIT) || (((A)&~rd)&TOPBIT) || ((~(B)&~rd)&TOPBIT)) ? 1 : 0 )
#define ADDVFLAG(A,B,rd) ( ((((A)&(B)&~rd)&TOPBIT) || ((~(A)&~(B)&rd)&TOPBIT)) ? 1 : 0 )
#define SUBVFLAG(A,B,rd) ( ((((A)&~(B)&~rd)&TOPBIT) || ((~(A)&(B)&rd)&TOPBIT)) ? 1 : 0 )
#define WAVELET (11025)
unsigned short __fastcall RegBase(unsigned int reg);
unsigned short __fastcall ireadh(unsigned int addr);
void __fastcall iwriteh(unsigned int addr, unsigned short val);
void __fastcall OperandLoader(int Requests);
int __fastcall OperandLoaderNWB(void);
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
#pragma pack(push,1)
struct CIFTAG{
unsigned int BCH_ADDR :10;
unsigned int FLAG_MASK :2;
unsigned int FLGSEL :1;
unsigned int MODE :2;
unsigned int PAD :1;
};
struct BRNTAG{
unsigned int BCH_ADDR:10;
unsigned int FLAGM0 :1;
unsigned int FLAGM1 :1;
unsigned int FLAGSEL:1;
unsigned int MODE0 :1;
unsigned int MODE1 :1;
unsigned int AC :1;
};
struct BRNBITS {
unsigned int BCH_ADDR:10;
unsigned int bits :5;
unsigned int AC :1;
};
struct AIFTAG{
unsigned int BS :4;
unsigned int ALU :4;
unsigned int MUXB :2;
unsigned int MUXA :2;
signed int M2SEL :1;
unsigned int NUMOPS :2;
signed int PAD :1;
};
struct IOFTAG{
signed int IMMEDIATE :13;
signed int JUSTIFY :1;
unsigned int TYPE :2;
};
struct NROFTAG{
unsigned int OP_ADDR :10;
signed int DI :1;
unsigned int WB1 :1;
unsigned int PAD :1;
unsigned int TYPE :3;
};
struct R2OFTAG{
unsigned int R1 :4;
signed int R1_DI :1;
unsigned int R2 :4;
signed int R2_DI :1;
unsigned int NUMREGS :1;
unsigned int WB1 :1;
unsigned int WB2 :1;
unsigned int TYPE :3;
};
struct R3OFTAG{
unsigned int R1 :4;
signed int R1_DI :1;
unsigned int R2 :4;
signed int R2_DI :1;
unsigned int R3 :4;
signed int R3_DI :1;
unsigned int TYPE :1;
};
union ITAG{
unsigned int raw;
AIFTAG aif;
CIFTAG cif;
IOFTAG iof;
NROFTAG nrof;
R2OFTAG r2of;
R3OFTAG r3of;
BRNTAG branch;
BRNBITS br;
};
struct RQFTAG{
unsigned int BS:1;
unsigned int ALU2:1;
unsigned int ALU1:1;
unsigned int MULT2:1;
unsigned int MULT1:1;
};
union _requnion
{
unsigned char raw;
RQFTAG rq;
};
struct __INSTTRAS
{
_requnion req;
char BS; // 4+1 bits
}; // only for ALU command
struct REGSTAG{
unsigned int PC;//0x0ee
unsigned short NOISE;//0x0ea
unsigned short AudioOutStatus;//audlock,lftfull,rgtfull -- 0x0eb//0x3eb
unsigned short Sema4Status;//0x0ec//0x3ec
unsigned short Sema4Data;//0x0ed//0x3ed
short DSPPCNT;//0x0ef
short DSPPRLD;//0x3ef
short AUDCNT;
unsigned short INT;//0x3ee
};
struct INTAG{
signed short MULT1;
signed short MULT2;
signed short ALU1;
signed short ALU2;
int BS;
unsigned short RMAP;
unsigned short nOP_MASK;
unsigned short WRITEBACK;
_requnion req;
bool Running;
bool GenFIQ;
};
struct DSPDatum
{
unsigned int RBASEx4;
__INSTTRAS INSTTRAS[0x8000];
unsigned short REGCONV[8][16];
bool BRCONDTAB[32][32];
unsigned short NMem[2048];
unsigned short IMem[1024];
int REGi;
REGSTAG dregs;
INTAG flags;
unsigned int g_seed;
bool CPUSupply[16];
};
#pragma pack(pop)
static DSPDatum dsp;
#include <memory.h>
unsigned int _dsp_SaveSize()
{
return sizeof(DSPDatum);
}
void _dsp_Save(void *buff)
{
memcpy(buff,&dsp,sizeof(DSPDatum));
}
void _dsp_Load(void *buff)
{
memcpy(&dsp,buff,sizeof(DSPDatum));
}
#define RBASEx4 dsp.RBASEx4
#define INSTTRAS dsp.INSTTRAS
#define REGCONV dsp.REGCONV
#define BRCONDTAB dsp.BRCONDTAB
#define NMem dsp.NMem
#define IMem dsp.IMem
#define REGi dsp.REGi
#define dregs dsp.dregs
#define flags dsp.flags
#define g_seed dsp.g_seed
#define CPUSupply dsp.CPUSupply
int fastrand()
{
g_seed=69069*g_seed+1;
return g_seed & 0xFFFF;
}
void _dsp_Init()
{
int a,c;
ITAG inst;
unsigned int i;
g_seed=0xa5a5a5a5;
//FRAMES=0;
for(a=0;a<16;a++)
for(c=0;c<8;c++)
{
flags.RMAP=c;
REGCONV[c][a]=RegBase(a);
}
for(inst.raw=0;inst.raw<0x8000;inst.raw++)
{
flags.req.raw=0;
if(inst.aif.BS==0x8)
flags.req.rq.BS=1;
switch(inst.aif.MUXA)
{
case 3:
flags.req.rq.MULT1=1;
flags.req.rq.MULT2=inst.aif.M2SEL;
break;
case 1:
flags.req.rq.ALU1=1;
break;
case 2:
flags.req.rq.ALU2=1;
break;
}
switch(inst.aif.MUXB)
{
case 1:
flags.req.rq.ALU1=1;
break;
case 2:
flags.req.rq.ALU2=1;
break;
case 3:
flags.req.rq.MULT1=1;
flags.req.rq.MULT2=inst.aif.M2SEL;
break;
}
INSTTRAS[inst.raw].req.raw=flags.req.raw;
INSTTRAS[inst.raw].BS=inst.aif.BS | ((inst.aif.ALU&8)<<(4-3));
}
{
bool MD0, MD1, MD2, MD3;
bool STAT0, STAT1;
bool NSTAT0, NSTAT1;
bool TDCARE0, TDCARE1;
bool RDCARE;
bool MD12S;
bool SUPER0, SUPER1;
bool ALLZERO, NALLZERO;
bool SDS;
bool NVTest;
bool TMPCS;
bool CZTest, XactTest;
bool MD3S;
// int Flags.Zero;
// int Flags.Nega;
// int Flags.Carry;//not borrow
// int Flags.Over;
int fExact;
union {
struct {
char Zero;
char Nega;
char Carry;//not borrow
char Over;
};
unsigned int raw;
} Flags;
for(inst.raw=0xA000; inst.raw<=0xFFFF; inst.raw+=1024)
for(Flags.Zero=0;Flags.Zero<2;Flags.Zero++)
for(Flags.Nega=0;Flags.Nega<2;Flags.Nega++)
for(Flags.Carry=0;Flags.Carry<2;Flags.Carry++)
for(Flags.Over=0;Flags.Over<2;Flags.Over++)
for(fExact=0;fExact<2;fExact++)
{
MD0=!inst.branch.MODE1 && !inst.branch.MODE0;
MD1=!inst.branch.MODE1 && inst.branch.MODE0;
MD2=inst.branch.MODE1 && !inst.branch.MODE0;
MD3=inst.branch.MODE1 && inst.branch.MODE0;
STAT0=(inst.branch.FLAGSEL && Flags.Carry) || (!inst.branch.FLAGSEL && Flags.Nega);
STAT1=(inst.branch.FLAGSEL && Flags.Zero) || (!inst.branch.FLAGSEL && Flags.Over);
NSTAT0=STAT0!=MD2;
NSTAT1=STAT1!=MD2;
TDCARE1=!inst.branch.FLAGM1 || (inst.branch.FLAGM1 && NSTAT0);
TDCARE0=!inst.branch.FLAGM0 || (inst.branch.FLAGM0 && NSTAT1);
RDCARE=!inst.branch.FLAGM1 && !inst.branch.FLAGM0;
MD12S=TDCARE1 && TDCARE0 && (inst.branch.MODE1!=inst.branch.MODE0) && !RDCARE;
SUPER0= MD1 && !inst.branch.FLAGSEL && RDCARE;
SUPER1= MD1 && inst.branch.FLAGSEL && RDCARE;
ALLZERO=SUPER0 && Flags.Zero && fExact;
NALLZERO=SUPER1 && !(Flags.Zero && fExact);
SDS=ALLZERO || NALLZERO;
NVTest=( ((Flags.Nega!=Flags.Over) || (Flags.Zero && inst.branch.FLAGM0)) != inst.branch.FLAGM1) && !inst.branch.FLAGSEL;
TMPCS=Flags.Carry && ! Flags.Zero;
CZTest=(TMPCS != inst.branch.FLAGM0) && inst.branch.FLAGSEL && !inst.branch.FLAGM1;
XactTest=(fExact != inst.branch.FLAGM0) && inst.branch.FLAGSEL && inst.branch.FLAGM1;
MD3S=(NVTest || CZTest || XactTest)&&MD3;
BRCONDTAB[inst.br.bits][fExact+((Flags.raw*0x10080402)>>24)] = (MD12S || MD3S || SDS)? true : false;
}
}
flags.Running=0;
flags.GenFIQ=false;
dregs.DSPPRLD=567;
dregs.AUDCNT=567;
_dsp_Reset();
dregs.Sema4Status = 0; //?? 8-CPU last, 4-DSP last, 2-CPU ACK, 1 DSP ACK ??
for( i=0;i<sizeof(NMem)/sizeof(NMem[0]);i++) NMem[i]=0x8380; //SLEEP
for(i=0;i<16;i++) CPUSupply[i]=0;
}
void _dsp_Reset()
{
dregs.DSPPCNT=dregs.DSPPRLD;
dregs.PC=0;
RBASEx4=0;
REGi=0;
flags.nOP_MASK=~0;
}
#include "freedocore.h"
extern _ext_Interface io_interface;
void _Arithmetic_Debug(uint16 nrc, uint16 opmask)
{
bool MULT1_RQST_L,MULT2_RQST_L,ALU1_RQST_L,ALU2_RQST_L,BS_RQST_L;
int NUMBER_OPERANDS=0, cnt=0;
if( ((nrc&0x300)==0x300 || (nrc&0xC00)==0xC00) && !(opmask&0x10) )
{MULT1_RQST_L=true;cnt++;}
else MULT1_RQST_L=false;
if( ((nrc&0x300)==0x300 || (nrc&0xC00)==0xC00) && !(opmask&0x8) && (nrc&0x1000) )
{MULT2_RQST_L=true;cnt++;}
else MULT2_RQST_L=false;
if( ((nrc&0x300)==0x100 || (nrc&0xC00)==0x400) && !(opmask&0x4) )
{ALU1_RQST_L=true;cnt++;}
else ALU1_RQST_L=false;
if( ((nrc&0x300)==0x200 || (nrc&0xC00)==0x800) && !(opmask&0x2) )
{ALU2_RQST_L=true;cnt++;}
else ALU2_RQST_L=false;
if( (nrc&0xf)==0x8 && !(opmask&0x1) )
{BS_RQST_L=true;cnt++;}
else BS_RQST_L=false;
NUMBER_OPERANDS=(nrc>>13)&3;
if(!NUMBER_OPERANDS && (ALU1_RQST_L || ALU2_RQST_L) )NUMBER_OPERANDS=4;
//what if RQ is more than NUM_OPS????
if(NUMBER_OPERANDS<cnt)io_interface(EXT_DEBUG_PRINT,(void*)">>>DSP NUM_OPS_CONFLICT!!!\n");
}
unsigned int _dsp_Loop()
{
unsigned int AOP, BOP; //1st & 2nd operand
unsigned int Y; //accumulator
unsigned int RBSR; //return address
union {
struct {
bool Zero;
bool Nega;
bool Carry;//not borrow
bool Over;
};
unsigned int raw;
} Flags;
bool fExact;
bool Work;
if(flags.Running&1)
{
_dsp_Reset();
Flags.raw=0;
fExact=0;
AOP=0;
BOP=0;
Y=0;
RBSR=0;
Work=true;
do
{
ITAG inst;
inst.raw=NMem[dregs.PC++];
//DSPCYCLES++;
if(inst.aif.PAD)
{//Control instruction
switch((inst.raw>>7)&255) //special
{
case 0://NOP TODO
break;
case 1://branch accum
dregs.PC=(Y>>16)&0x3ff;
break;
case 2://set rbase
RBASEx4=(inst.cif.BCH_ADDR&0x3f)<<2;
break;
case 3://set rmap
REGi=inst.cif.BCH_ADDR&7;
break;
case 4://RTS
dregs.PC=RBSR;
break;
case 5://set op_mask
flags.nOP_MASK=~(inst.cif.BCH_ADDR&0x1f);
break;
case 6:// -not used2- ins
break;
case 7://SLEEP
Work=false;
break;
case 8: case 9: case 10: case 11:
case 12: case 13: case 14: case 15:
//jump //branch only if not branched
dregs.PC=inst.cif.BCH_ADDR;
break;
case 16: case 17: case 18: case 19:
case 20: case 21: case 22: case 23:
//jsr
RBSR=dregs.PC;
dregs.PC=inst.cif.BCH_ADDR;
break;
case 24: case 25: case 26: case 27:
case 28: case 29: case 30: case 31:
// branch only if was branched
dregs.PC=inst.cif.BCH_ADDR;
break;
case 32: case 33: case 34: case 35:
case 36: case 37: case 38: case 39:
case 40: case 41: case 42: case 43: // ??? -not used- instr's
case 44: case 45: case 46: case 47: // ??? -not used- instr's
// MOVEREG
{
int Operand=OperandLoaderNWB();
if(inst.r2of.R1_DI)
iwriteh(ireadh(REGCONV[REGi][inst.r2of.R1]^RBASEx4),Operand);
else
iwriteh(REGCONV[REGi][inst.r2of.R1]^RBASEx4,Operand);
}
break;
case 48: case 49: case 50: case 51:
case 52: case 53: case 54: case 55:
case 56: case 57: case 58: case 59:
case 60: case 61: case 62: case 63:
// MOVE
{
int Operand=OperandLoaderNWB();
if(inst.nrof.DI)
iwriteh(ireadh(inst.cif.BCH_ADDR),Operand);
else
iwriteh(inst.cif.BCH_ADDR,Operand);
}
break;
default: // Coundition branch
if(1&BRCONDTAB[inst.br.bits][fExact+((Flags.raw*0x10080402)>>24)]) dregs.PC=inst.cif.BCH_ADDR;
break;
}//switch((inst.raw>>7)&255) //special
}
else //if(inst.aif.PAD)
{
//ALU instruction
#if _DEBUG
_Arithmetic_Debug(inst.raw, ~flags.nOP_MASK);
#endif
flags.req.raw=INSTTRAS[inst.raw].req.raw;
flags.BS =INSTTRAS[inst.raw].BS;
OperandLoader(inst.aif.NUMOPS);
switch(inst.aif.MUXA)
{
case 3:
if(inst.aif.M2SEL==0)
{
if((inst.aif.ALU==3)||(inst.aif.ALU==5)) // ACSBU signal
AOP=Flags.Carry? ((int)flags.MULT1<<16)&ALUSIZEMASK : 0;
else
AOP=( ((int)flags.MULT1*(((signed int)Y>>15)&~1))&ALUSIZEMASK );
}
else
AOP=( ((int)flags.MULT1*(int)flags.MULT2*2)&ALUSIZEMASK );
break;
case 1:
AOP=flags.ALU1<<16;
break;
case 0:
AOP=Y;
break;
case 2:
AOP=flags.ALU2<<16;
break;
}
if((inst.aif.ALU==3)||(inst.aif.ALU==5)) // ACSBU signal
{
BOP=Flags.Carry<<16;
}
else
{
switch(inst.aif.MUXB)
{
case 0:
BOP=Y;
break;
case 1:
BOP=flags.ALU1<<16;
break;
case 2:
BOP=flags.ALU2<<16;
break;
case 3:
if(inst.aif.M2SEL==0) // ACSBU==0 here always
BOP=( ((int)flags.MULT1*(((signed int)Y>>15))&~1)&ALUSIZEMASK );
else
BOP=( ((int)flags.MULT1*(int)flags.MULT2*2)&ALUSIZEMASK );
break;
}
}
//ok now ALU itself.
//unsigned char ctt1,ctt2;
Flags.Over=Flags.Carry=0; // Any ALU op. change Over and possible Carry
switch(inst.aif.ALU)
{
case 0:
Y=AOP;
break;
//*
case 1:
Y=0-BOP;
Flags.Carry=SUBCFLAG(0,BOP,Y);
Flags.Over=SUBVFLAG(0,BOP,Y);
break;
case 2:
case 3:
Y=AOP+BOP;
Flags.Carry=ADDCFLAG(AOP,BOP,Y);
Flags.Over=ADDVFLAG(AOP,BOP,Y);
break;
case 4:
case 5:
Y=AOP-BOP;
Flags.Carry=SUBCFLAG(AOP,BOP,Y);
Flags.Over=SUBVFLAG(AOP,BOP,Y);
break;
case 6:
Y=AOP+0x1000;
Flags.Carry=ADDCFLAG(AOP,0x1000,Y);
Flags.Over=ADDVFLAG(AOP,0x1000,Y);
break;
case 7:
Y=AOP-0x1000;
Flags.Carry=SUBCFLAG(AOP,0x1000,Y);
Flags.Over=SUBVFLAG(AOP,0x1000,Y);
break;
case 8: // A
Y=AOP;
break;
case 9: // NOT A
Y=AOP^ALUSIZEMASK;
break;
case 10: // A AND B
Y=AOP&BOP;
break;
case 11: // A NAND B
Y=(AOP&BOP)^ALUSIZEMASK;
break;
case 12: // A OR B
Y=AOP|BOP;
break;
case 13: // A NOR B
Y=(AOP|BOP)^ALUSIZEMASK;
break;
case 14: // A XOR B
Y=AOP^BOP;
break;
case 15: // A XNOR B
Y=AOP^BOP^ALUSIZEMASK;
break;
}
Flags.Zero=(Y&0xFFFF0000)?0:1;
Flags.Nega=(Y>>31)?1:0;
fExact=(Y&0x0000F000)?0:1;
//and BarrelShifter
switch(flags.BS)
{
case 1:
case 17:
Y=Y<<1;
break;
case 2:
case 18:
Y=Y<<2;
break;
case 3:
case 19:
Y=Y<<3;
break;
case 4:
case 20:
Y=Y<<4;
break;
case 5:
case 21:
Y=Y<<5;
break;
case 6:
case 22:
Y=Y<<8;
break;
//arithmetic shifts
case 9:
Y=(signed int)Y>>16;
Y&=ALUSIZEMASK;
break;
case 10:
Y=(signed int)Y>>8;
Y&=ALUSIZEMASK;
break;
case 11:
Y=(signed int)Y>>5;
Y&=ALUSIZEMASK;
break;
case 12:
Y=(signed int)Y>>4;
Y&=ALUSIZEMASK;
break;
case 13:
Y=(signed int)Y>>3;
Y&=ALUSIZEMASK;
break;
case 14:
Y=(signed int)Y>>2;
Y&=ALUSIZEMASK;
break;
case 15:
Y=(signed int)Y>>1;
Y&=ALUSIZEMASK;
break;
// logocal shift
case 7: // CLIP ari
case 23:// CLIP log
if(1&Flags.Over)
{
if(1&Flags.Nega) Y=0x7FFFf000;
else Y=0x80000000;
}
break;
case 8: // Load operand load sameself again (ari)
case 24:// same, but logicalshift
{
//int temp=Flags.Carry;
Flags.Carry=(signed)Y<0; // shift out bit to Carry
//Y=Y<<1;
//Y|=temp<<16;
Y=((Y<<1)&0xfffe0000)|(Flags.Carry?1<<16:0)|(Y&0xf000);
}
break;
case 25:
Y=(unsigned int)Y>>16;
Y&=ALUSIZEMASK;
break;
case 26:
Y=(unsigned int)Y>>8;
Y&=ALUSIZEMASK;
break;
case 27:
Y=(unsigned int)Y>>5;
Y&=ALUSIZEMASK;
break;
case 28:
Y=(unsigned int)Y>>4;
Y&=ALUSIZEMASK;
break;
case 29:
Y=(unsigned int)Y>>3;
Y&=ALUSIZEMASK;
break;
case 30:
Y=(unsigned int)Y>>2;
Y&=ALUSIZEMASK;
break;
case 31:
Y=(unsigned int)Y>>1;
Y&=ALUSIZEMASK;
break;
}
//now write back. (assuming in WRITEBACK there is an address where to write
if(flags.WRITEBACK)
{
iwriteh(flags.WRITEBACK,((signed int)Y)>>16);
}
//fin :)
}//else //if(inst.aif.PAD)
}while(Work);//big while!!!
if(1&flags.GenFIQ)
{
flags.GenFIQ=false;
_clio_GenerateFiq(0x800,0);//AudioFIQ
//printf("#!!! AudioFIQ Generated 0x%4.4X\n!!!",val);
}
dregs.DSPPCNT-=567;
if(dregs.DSPPCNT<=0)
dregs.DSPPCNT+=dregs.DSPPRLD;
}
return ((IMem[0x3ff]<<16)|IMem[0x3fe]);
}
void __fastcall _dsp_WriteMemory(unsigned short addr, unsigned short val) //CPU writes NMEM of DSP
{
//mwriteh(addr,val);
//printf("#NWRITE 0x%3.3X<=0x%4.4X\n",addr,val);
NMem[addr&0x3ff]=val;
}
unsigned short __fastcall RegBase(unsigned int reg)
{
unsigned short res;
unsigned char twi,x,y;
reg&=0xf;
x=(reg>>2)&1;
y=(reg>>3)&1;
switch(flags.RMAP)
{
case 0:
case 1:
case 2:
case 3:
twi=x;
break;
case 4:
twi=y;
break;
case 5:
twi=!y;
break;
case 6:
twi=x&y;
break;
case 7:
twi=x|y;
break;
}
res=(reg&7);
res|=twi<<8;
res|=(reg>>3)<<9;
////printf("RegSel=0x%X\n",res);
return res;
}
unsigned short __fastcall ireadh(unsigned int addr) //DSP IREAD (includes EI, I)
{
unsigned short val;
// addr&=0x3ff;
switch(addr)
{
case 0xea:
dregs.NOISE=fastrand();
return dregs.NOISE;
break;
case 0xeb:
//printf("#DSP read AudioOutStatus (0x%4.4X)\n",dregs.AudioOutStatus);
return dregs.AudioOutStatus;
break;
case 0xec:
//printf("#DSP read Sema4Status: 0x%4.4X\n",dregs.Sema4Status);
return dregs.Sema4Status;
break;
case 0xed:
//printf("#DSP read Sema4Data: 0x%4.4X\n",dregs.Sema4Data);
return dregs.Sema4Data;
break;
case 0xee:
//printf("#DSP read PC (0x%4.4X)\n",dregs.PC);
return dregs.PC;
break;
case 0xef:
//printf("#DSP read DSPPCNT (0x%4.4X)\n",dregs.DSPPCNT); //?? 0x4000 always
return dregs.DSPPCNT;
break;
case 0xf0: case 0xf1: case 0xf2: case 0xf3:
case 0xf4: case 0xf5: case 0xf6: case 0xf7:
case 0xf8: case 0xf9: case 0xfa: case 0xfb:
case 0xfc:
if(CPUSupply[addr-0xf0])
{
CPUSupply[addr-0xf0]=0;
//printf("#DSP read from CPU!!! chan=0x%x\n",addr&0x0f);
//val=IMem[addr-0x80];
val=(fastrand()<<16)|fastrand();
}
else
val=_clio_EIFIFO(addr&0x0f);
//val=rand();
//printf("#DSP read EIFifo 0x%4.4X>=0x%4.4X\n",addr&0x0f,val);
/*FILE * flo;
flo=fopen("z:\\inp.raw","ab");
if(flo)
{
fwrite(&val,2,1,flo);
fclose(flo);
}*/
return val;
break;
case 0x70: case 0x71: case 0x72: case 0x73:
case 0x74: case 0x75: case 0x76: case 0x77:
case 0x78: case 0x79: case 0x7a: case 0x7b:
case 0x7c:
if(CPUSupply[addr-0x70])
{
CPUSupply[addr-0x70]=0;
//printf("#DSP read from CPU!!! chan=0x%x\n",addr&0x0f);
return IMem[addr];
}
else
return _clio_EIFIFONI(addr&0x0f);
break;
case 0xd0: case 0xd1: case 0xd2: case 0xd3:
case 0xd4: case 0xd5: case 0xd6: case 0xd7:
case 0xd8: case 0xd9: case 0xda: case 0xdb:
case 0xdc: case 0xdd: case 0xde: // what is last two case's?
//if(CPUSupply[addr&0x0f])
//{
//CPUSupply[addr&0x0f]=0;
//printf("#DSP read from CPU!!! chan=0x%x\n",addr&0x0f);
//return IMem[0x70+addr&0x0f];
//}
//else
//printf("#DSP read EIFifo status 0x%4.4X\n",addr&0x0f);
if(CPUSupply[addr&0xf])
return 2;
else
return _clio_GetEIFIFOStat(addr&0xf);
//return CPUSupply[addr-0xd0]||CClio::GetEIFIFOStat(addr-0xd0);
break;
case 0xe0:
case 0xe1:
case 0xe2:
case 0xe3:
//printf("#DSP read EOFifo status 0x%4.4X\n",addr&0x0f);
return _clio_GetEOFIFOStat(addr&0x0f);
break;
default:
//printf("#EIRead 0x%3.3X>=0x%4.4X\n",addr, IMem[addr&0x7f]);
addr-=0x100;
if((addr<0x200))
{
return IMem[addr|0x100];
}
else
return IMem[addr&0x7f];
}
}
void __fastcall iwriteh(unsigned int addr, unsigned short val) //DSP IWRITE (includes EO,I)
{
//unsigned short imem;
addr&=0x3ff;
switch(addr)
{
case 0x3eb: dregs.AudioOutStatus=val;
//if(val&0x8000)
// dregs.DSPPRLD=568;
break;
case 0x3ec: // DSP write to Sema4ACK
//printf("#DSP write Sema4ACK=0x%4.4X\n",val);
dregs.Sema4Status|=0x1;
//printf("#DSP write Sema4Status=0x%4.4X\n",val);
break;
case 0x3ed: dregs.Sema4Data=val;
//printf("#DSP write Sema4Data=0x%4.4X\n",val);
dregs.Sema4Status=0x4; // DSP write to Sema4Data
//printf("Sema4Status set to 0x%4.4X\n",dregs.Sema4Status);
break;
case 0x3ee: dregs.INT=val;
flags.GenFIQ=true;
break;
case 0x3ef: dregs.DSPPRLD=val;
//if(val>0)io_interface(EXT_DEBUG_PRINT,(void*)"DSP_CNT_REL > 0");
//else if(val==567)io_interface(EXT_DEBUG_PRINT,(void*)"DSP_CNT_REL == 567");
//else io_interface(EXT_DEBUG_PRINT,(void*)"DSP_CNT_REL == 0");
break;
case 0x3f0:
case 0x3f1:
case 0x3f2:
case 0x3f3:
_clio_EOFIFO(addr&0x0f,val);
break;
case 0x3fd:
//FLUSH EOFIFO
break;
case 0x3fe: // DAC Left channel
case 0x3ff: // DAC Right channel
IMem[addr]=val;
break;
default:
if(addr<0x100)
{ //printf("#OPUS !!!DPC=0x%3.3X write to r/o == addr 0x%3.3X , val 0x%4.4X\n",dregs.PC,addr,val);
return;
}
//printf("#EOWRITE 0x%3.3X<=0x%4.4X\n",addr,val);
/*if( (addr>=0x310) && (addr<0x3eb))
printf("# UnEmulated registers write addr=0x%3.3X, pc=0x%3.3X\n",addr,dregs.PC);
*/
addr-=0x100;
if(addr<0x200)
{
IMem[addr|0x100]=val;
}
else
IMem[addr+0x100]=val;
return;
}
}
void __fastcall _dsp_SetRunning(bool val)
{
flags.Running= val;
}
void __fastcall _dsp_WriteIMem(unsigned short addr, unsigned short val)//CPU writes to EI,I of DSP
{
switch(addr)
{
/*case 0xea:
case 0x6a:
dregs.NOISE=val;
break;
case 0xeb:
case 0x6b:
dregs.AudioOutStatus=val;
break;
case 0xec:
case 0x6c:
//printf("#Arm write Sema4ACK=0x%4.4X\n",val);
dregs.Sema4Status |= 0x2;
break;
case 0xed:
case 0x6d:
dregs.Sema4Data=val; // ARM write to Sema4Data
dregs.Sema4Status = 0x8;
//printf("#Arm write Sema4Data=0x%4.4X\n",val);
//printf("#Sema4Status set to 0x%4.4X\n",dregs.Sema4Status);
break;
case 0xee:
//io_interface(EXT_DEBUG_PRINT,(void*)">>>DSP PC WRITED 0xEE!!!\n");
case 0x6e:
dregs.PC=val;
//io_interface(EXT_DEBUG_PRINT,(void*)">>>DSP PC WRITED 0x6E!!!\n");
break;
case 0xef:
case 0x6f:
dregs.DSPPCNT=val;
break;*/
case 0x70: case 0x71: case 0x72: case 0x73:
case 0x74: case 0x75: case 0x76: case 0x77:
case 0x78: case 0x79: case 0x7a: case 0x7b:
case 0x7c:
CPUSupply[addr-0x70]=1;
//printf("# Coeff ARM write=0x%3.3X, val=0x%4.4X\n",addr,val);
IMem[addr&0x7f]=val;
io_interface(EXT_DEBUG_PRINT,(void*)">>>ARM TO DSP FIFO DIRECT!!!\n");
break;
default:
//if( (addr>=0x0) && (addr<0x6f))
// printf("# Coeff ARM write=0x%3.3X, val=0x%4.4X\n",addr,val);
if(!(addr&0x80))IMem[addr&0x7f]=val;
else io_interface(EXT_DEBUG_PRINT,(void*)">>>ARM TO DSP HZ!!!\n");
break;
}
}
void __fastcall _dsp_ARMwrite2sema4(unsigned int val)
{
// How about Sema4ACK? Now don't think about it
dregs.Sema4Data=val&0xffff; // ARM write to Sema4Data low 16 bits
dregs.Sema4Status=0x8; // ARM be last
//printf("#Arm write Sema4Data=0x%4.4X\n",val);
//printf("Sema4Status set to 0x%4.4X\n",dregs.Sema4Status);
}
unsigned short __fastcall _dsp_ReadIMem(unsigned short addr) //CPU reads from EO,I of DSP
{
switch(addr)
{
case 0x3eb:
//printf("#ARM read AudioOutStatus (0x%4.4X)\n",dregs.AudioOutStatus);
return dregs.AudioOutStatus;
break;
case 0x3ec:
//printf("#Arm read Sema4Status = 0x%4.4X\n",dregs.Sema4Status);
return dregs.Sema4Status;
break;
case 0x3ed:
//printf("#Arm read Sema4Data = 0x%4.4X\n",dregs.Sema4Status);
return dregs.Sema4Data;
break;
case 0x3ee:
//printf("#ARM read dregs.INT (0x%04X)\n",dregs.INT);
return dregs.INT;
break;
case 0x3ef:
//printf("#ARM read DSPPRLD (0x%4.4X)\n",dregs.DSPPRLD);
return dregs.DSPPRLD;
break;
default:
// printf("#Arm read IMem[0x%3.3X]=0x%4.4X\n",addr, IMem[addr]);
return IMem[addr];
break;
}
}
unsigned int _dsp_ARMread2sema4(void)
{
//printf("#Arm read both Sema4Status & Sema4Data\n");
return (dregs.Sema4Status<<16) | dregs.Sema4Data;
}
void __fastcall OperandLoader(int Requests)
{
int Operands;//total of operands
int Ptr;
unsigned short OperandPool[6]; // c'mon -- 5 is real maximum
unsigned short GWRITEBACK;
ITAG operand;
flags.WRITEBACK=0;
if(Requests==0)
{
if(flags.req.raw)
Requests=4;
else
return;
}
//DSPCYCLES+=Requests;
Operands=0;
GWRITEBACK=0;
do
{
operand.raw=NMem[dregs.PC++];
if(operand.nrof.TYPE==4)
{
//non reg format ///IT'S an address!!!
if(operand.nrof.DI)
OperandPool[Operands]=ireadh(flags.WRITEBACK=ireadh(operand.nrof.OP_ADDR));
else
OperandPool[Operands]=ireadh(flags.WRITEBACK= operand.nrof.OP_ADDR);
Operands++;
if(operand.nrof.WB1)
GWRITEBACK=flags.WRITEBACK;
}else if ((operand.nrof.TYPE&6)==6)
{
//case 6: and case 7: immediate format
OperandPool[Operands]=operand.iof.IMMEDIATE<<(operand.iof.JUSTIFY&3);
flags.WRITEBACK=OperandPool[Operands++];
}else if(!(operand.nrof.TYPE&4)) // case 0..3
{
if(operand.r3of.R3_DI)
OperandPool[Operands]=ireadh(ireadh(REGCONV[REGi][operand.r3of.R3]^RBASEx4));
else
OperandPool[Operands]=ireadh( REGCONV[REGi][operand.r3of.R3]^RBASEx4 );
Operands++;
if(operand.r3of.R2_DI)
OperandPool[Operands]=ireadh(ireadh(REGCONV[REGi][operand.r3of.R2]^RBASEx4));
else
OperandPool[Operands]=ireadh( REGCONV[REGi][operand.r3of.R2]^RBASEx4 );
Operands++;
// only R1 can be WRITEBACK
if(operand.r3of.R1_DI)
OperandPool[Operands]=ireadh(flags.WRITEBACK=ireadh(REGCONV[REGi][operand.r3of.R1]^RBASEx4));
else
OperandPool[Operands]=ireadh(flags.WRITEBACK= REGCONV[REGi][operand.r3of.R1]^RBASEx4 );
Operands++;
}else //if(operand.nrof.TYPE==5)
{
//regged 1/2 format
if(operand.r2of.NUMREGS)
{
if(operand.r2of.R2_DI)
OperandPool[Operands]=ireadh(flags.WRITEBACK=ireadh(REGCONV[REGi][operand.r2of.R2]^RBASEx4));
else
OperandPool[Operands]=ireadh(flags.WRITEBACK= REGCONV[REGi][operand.r2of.R2]^RBASEx4 );
Operands++;
if(operand.r2of.WB2)
GWRITEBACK=flags.WRITEBACK;
}
if(operand.r2of.R1_DI)
OperandPool[Operands]=ireadh(flags.WRITEBACK=ireadh(REGCONV[REGi][operand.r2of.R1]^RBASEx4));
else
OperandPool[Operands]=ireadh(flags.WRITEBACK= REGCONV[REGi][operand.r2of.R1]^RBASEx4 );
Operands++;
if(operand.r2of.WB1)
GWRITEBACK=flags.WRITEBACK;
}//if
}while(Operands<Requests);
//ok let's clean out Requests (using op_mask)
flags.req.raw&=flags.nOP_MASK;
Ptr=0;
if(flags.req.rq.MULT1)
flags.MULT1=OperandPool[Ptr++];
if(flags.req.rq.MULT2)
flags.MULT2=OperandPool[Ptr++];
if(flags.req.rq.ALU1)
flags.ALU1=OperandPool[Ptr++];
if(flags.req.rq.ALU2)
flags.ALU2=OperandPool[Ptr++];
if(flags.req.rq.BS)
flags.BS=OperandPool[Ptr++];
if(Operands!=Ptr)
{
if(GWRITEBACK)
flags.WRITEBACK=GWRITEBACK;
//else flags.WRITEBACK=0;
}
else
flags.WRITEBACK=GWRITEBACK;
}
int __fastcall OperandLoaderNWB(void)
{
int Operand;
ITAG operand;
operand.raw=NMem[dregs.PC++];
if(operand.nrof.TYPE==4)
{
//non reg format ///IT'S an address!!!
if(operand.nrof.DI)
Operand=ireadh(ireadh(operand.nrof.OP_ADDR));
else
Operand=ireadh( operand.nrof.OP_ADDR);
}else if(!(operand.nrof.TYPE&4)) // case 0..3
{
if(operand.r3of.R3_DI) // ???
Operand=ireadh(ireadh(REGCONV[REGi][operand.r3of.R3]^RBASEx4));
else
Operand=ireadh( REGCONV[REGi][operand.r3of.R3]^RBASEx4 );
}else if ((operand.nrof.TYPE&6)==6)
{
//case 6: and case 7: immediate format
Operand=operand.iof.IMMEDIATE<<(operand.iof.JUSTIFY&3);
}else if(operand.nrof.TYPE==5)
{ //if(operand.r2of.NUMREGS) ignore... It's right?
if(operand.r2of.R1_DI)
Operand=ireadh(ireadh(REGCONV[REGi][operand.r2of.R1]^RBASEx4));
else
Operand=ireadh( REGCONV[REGi][operand.r2of.R1]^RBASEx4 );
}
return Operand;
}