/* 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 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>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>>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