--- /dev/null
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ * Copyright (C) 2002 Xodnizel
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "mapinc.h"
+
+static uint16 IRQCount;
+static uint8 IRQa;
+
+static uint8 WRAM[8192];
+static uint8 IRAM[128];
+
+static DECLFR(AWRAM)
+{
+ return(WRAM[A-0x6000]);
+}
+
+static DECLFW(BWRAM)
+{
+ WRAM[A-0x6000]=V;
+}
+
+void Mapper19_ESI(void);
+
+static uint8 NTAPage[4];
+
+static uint8 dopol;
+static uint8 gorfus;
+static uint8 gorko;
+
+static void NamcoSound(int Count);
+static void NamcoSoundHack(void);
+static void DoNamcoSound(int32 *Wave, int Count);
+//static void DoNamcoSoundHQ(void);
+static void SyncHQ(int32 ts);
+
+static int is210; /* Lesser mapper. */
+
+static uint8 PRG[3];
+static uint8 CHR[8];
+
+static SFORMAT N106_StateRegs[]={
+ {PRG,3,"PRG"},
+ {CHR,8,"CHR"},
+ {NTAPage,4,"NTA"},
+ {0}
+};
+
+static void SyncPRG(void)
+{
+ setprg8(0x8000,PRG[0]);
+ setprg8(0xa000,PRG[1]);
+ setprg8(0xc000,PRG[2]);
+ setprg8(0xe000,0x3F);
+}
+
+static void FP_FASTAPASS(1) NamcoIRQHook(int a)
+{
+ if(IRQa)
+ {
+ IRQCount+=a;
+ if(IRQCount>=0x7FFF)
+ {
+ X6502_IRQBegin(FCEU_IQEXT);
+ IRQa=0;
+ IRQCount=0x7FFF; //7FFF;
+ }
+ }
+}
+
+static DECLFR(Namco_Read4800)
+{
+ uint8 ret=IRAM[dopol&0x7f];
+ /* Maybe I should call NamcoSoundHack() here? */
+ if(!fceuindbg)
+ if(dopol&0x80)
+ dopol=(dopol&0x80)|((dopol+1)&0x7f);
+ return ret;
+}
+
+static DECLFR(Namco_Read5000)
+{
+ return(IRQCount);
+}
+
+static DECLFR(Namco_Read5800)
+{
+ return(IRQCount>>8);
+}
+
+static void FASTAPASS(2) DoNTARAMROM(int w, uint8 V)
+{
+ NTAPage[w]=V;
+ if(V>=0xE0)
+ setntamem(NTARAM+((V&1)<<10), 1, w);
+ else
+ {
+ V&=CHRmask1[0];
+ setntamem(CHRptr[0]+(V<<10), 0, w);
+ }
+}
+
+static void FixNTAR(void)
+{
+ int x;
+ for(x=0;x<4;x++)
+ DoNTARAMROM(x,NTAPage[x]);
+}
+
+static void FASTAPASS(2) DoCHRRAMROM(int x, uint8 V)
+{
+ CHR[x]=V;
+ if(!is210 && !((gorfus>>((x>>2)+6))&1) && (V>=0xE0))
+ {
+ // printf("BLAHAHA: %d, %02x\n",x,V);
+ //setchr1r(0x10,x<<10,V&7);
+ }
+ else
+ setchr1(x<<10,V);
+}
+
+static void FixCRR(void)
+{
+ int x;
+ for(x=0;x<8;x++)
+ DoCHRRAMROM(x,CHR[x]);
+}
+
+static DECLFW(Mapper19C0D8_write)
+{
+ DoNTARAMROM((A-0xC000)>>11,V);
+}
+
+static uint32 FreqCache[8];
+static uint32 EnvCache[8];
+static uint32 LengthCache[8];
+
+static void FixCache(int a,int V)
+{
+ int w=(a>>3)&0x7;
+ switch(a&0x07)
+ {
+ case 0x00:FreqCache[w]&=~0x000000FF;FreqCache[w]|=V;break;
+ case 0x02:FreqCache[w]&=~0x0000FF00;FreqCache[w]|=V<<8;break;
+ case 0x04:FreqCache[w]&=~0x00030000;FreqCache[w]|=(V&3)<<16;
+ LengthCache[w]=(8-((V>>2)&7))<<2;
+ break;
+ case 0x07:EnvCache[w]=(double)(V&0xF)*576716;break;
+ }
+}
+
+static DECLFW(Mapper19_write)
+{
+ A&=0xF800;
+ if(A>=0x8000 && A<=0xb800)
+ DoCHRRAMROM((A-0x8000)>>11,V);
+ else switch(A)
+ {
+ case 0x4800:
+ if(dopol&0x40)
+ {
+ if(FSettings.SndRate)
+ {
+ NamcoSoundHack();
+ GameExpSound.Fill=NamcoSound;
+ GameExpSound.HiFill=0;//DoNamcoSoundHQ;
+ GameExpSound.HiSync=SyncHQ;
+ }
+ FixCache(dopol,V);
+ }
+ IRAM[dopol&0x7f]=V;
+ if(dopol&0x80)
+ dopol=(dopol&0x80)|((dopol+1)&0x7f);
+ break;
+ case 0xf800:
+ dopol=V;break;
+ case 0x5000:
+ IRQCount&=0xFF00;IRQCount|=V;X6502_IRQEnd(FCEU_IQEXT);break;
+ case 0x5800:
+ IRQCount&=0x00ff;IRQCount|=(V&0x7F)<<8;
+ IRQa=V&0x80;
+ X6502_IRQEnd(FCEU_IQEXT);
+ break;
+ case 0xE000:
+ gorko=V&0xC0;
+ PRG[0]=V&0x3F;
+ SyncPRG();
+ break;
+ case 0xE800:
+ gorfus=V&0xC0;
+ FixCRR();
+ PRG[1]=V&0x3F;
+ SyncPRG();
+ break;
+ case 0xF000:
+ PRG[2]=V&0x3F;
+ SyncPRG();
+ break;
+ }
+}
+
+static int dwave=0;
+
+static void NamcoSoundHack(void)
+{
+ int32 z,a;
+#if 0
+ if(FSettings.soundq>=1)
+ {
+ DoNamcoSoundHQ();
+ return;
+ }
+#endif
+ z=((SOUNDTS<<16)/soundtsinc)>>4;
+ a=z-dwave;
+ if(a) DoNamcoSound(&Wave[dwave], a);
+ dwave+=a;
+}
+
+static void NamcoSound(int Count)
+{
+ int32 z,a;
+ z=((SOUNDTS<<16)/soundtsinc)>>4;
+ a=z-dwave;
+ if(a) DoNamcoSound(&Wave[dwave], a);
+ dwave=0;
+}
+
+static uint32 PlayIndex[8];
+static int32 vcount[8];
+static int32 CVBC;
+
+#define TOINDEX (16+1)
+
+// 16:15
+static void SyncHQ(int32 ts)
+{
+ CVBC=ts;
+}
+
+
+/* Things to do:
+ 1 Read freq low
+ 2 Read freq mid
+ 3 Read freq high
+ 4 Read envelope
+ ...?
+*/
+
+static INLINE uint32 FetchDuff(uint32 P, uint32 envelope)
+{
+ uint32 duff;
+ duff=IRAM[((IRAM[0x46+(P<<3)]+(PlayIndex[P]>>TOINDEX))&0xFF)>>1];
+ if((IRAM[0x46+(P<<3)]+(PlayIndex[P]>>TOINDEX))&1)
+ duff>>=4;
+ duff&=0xF;
+ duff=(duff*envelope)>>16;
+ return(duff);
+}
+
+#if 0
+static void DoNamcoSoundHQ(void)
+{
+ int32 P,V;
+ int32 cyclesuck=(((IRAM[0x7F]>>4)&7)+1)*15;
+
+ for(P=7;P>=(7-((IRAM[0x7F]>>4)&7));P--)
+ {
+ if((IRAM[0x44+(P<<3)]&0xE0) && (IRAM[0x47+(P<<3)]&0xF))
+ {
+ uint32 freq;
+ int32 vco;
+ uint32 duff2,lengo,envelope;
+
+ vco=vcount[P];
+ freq=FreqCache[P];
+ envelope=EnvCache[P];
+ lengo=LengthCache[P];
+
+ duff2=FetchDuff(P,envelope);
+ for(V=CVBC<<1;V<SOUNDTS<<1;V++)
+ {
+ WaveHi[V>>1]+=duff2;
+ if(!vco)
+ {
+ PlayIndex[P]+=freq;
+ while((PlayIndex[P]>>TOINDEX)>=lengo) PlayIndex[P]-=lengo<<TOINDEX;
+ duff2=FetchDuff(P,envelope);
+ vco=cyclesuck;
+ }
+ vco--;
+ }
+ vcount[P]=vco;
+ }
+ }
+ CVBC=SOUNDTS;
+}
+#endif
+
+static void DoNamcoSound(int32 *Wave, int Count)
+{
+ int P,V;
+ for(P=7;P>=7-((IRAM[0x7F]>>4)&7);P--)
+ {
+ if((IRAM[0x44+(P<<3)]&0xE0) && (IRAM[0x47+(P<<3)]&0xF))
+ {
+ int32 inc;
+ uint32 freq;
+ int32 vco;
+ uint32 duff,duff2,lengo,envelope;
+
+ vco=vcount[P];
+ freq=FreqCache[P];
+ envelope=EnvCache[P];
+ lengo=LengthCache[P];
+
+ if(!freq) {/*printf("Ack");*/ continue;}
+
+ {
+ int c=((IRAM[0x7F]>>4)&7)+1;
+ inc=(long double)(FSettings.SndRate<<15)/((long double)freq*21477272/((long double)0x400000*c*45));
+ }
+
+ duff=IRAM[(((IRAM[0x46+(P<<3)]+PlayIndex[P])&0xFF)>>1)];
+ if((IRAM[0x46+(P<<3)]+PlayIndex[P])&1)
+ duff>>=4;
+ duff&=0xF;
+ duff2=(duff*envelope)>>19;
+ for(V=0;V<Count*16;V++)
+ {
+ if(vco>=inc)
+ {
+ PlayIndex[P]++;
+ if(PlayIndex[P]>=lengo)
+ PlayIndex[P]=0;
+ vco-=inc;
+ duff=IRAM[(((IRAM[0x46+(P<<3)]+PlayIndex[P])&0xFF)>>1)];
+ if((IRAM[0x46+(P<<3)]+PlayIndex[P])&1)
+ duff>>=4;
+ duff&=0xF;
+ duff2=(duff*envelope)>>19;
+ }
+ Wave[V>>4]+=duff2;
+ vco+=0x8000;
+ }
+ vcount[P]=vco;
+ }
+ }
+}
+
+static void Mapper19_StateRestore(int version)
+{
+ SyncPRG();
+ FixNTAR();
+ FixCRR();
+ int x;
+ for(x=0x40;x<0x80;x++)
+ FixCache(x,IRAM[x]);
+}
+
+static void M19SC(void)
+{
+ if(FSettings.SndRate)
+ Mapper19_ESI();
+}
+
+void Mapper19_ESI(void)
+{
+ GameExpSound.RChange=M19SC;
+ memset(vcount,0,sizeof(vcount));
+ memset(PlayIndex,0,sizeof(PlayIndex));
+ CVBC=0;
+}
+
+void NSFN106_Init(void)
+{
+ SetWriteHandler(0xf800,0xffff,Mapper19_write);
+ SetWriteHandler(0x4800,0x4fff,Mapper19_write);
+ SetReadHandler(0x4800,0x4fff,Namco_Read4800);
+ Mapper19_ESI();
+}
+
+static int battery=0;
+
+static void N106_Power(void)
+{
+ int x;
+ SetReadHandler(0x8000,0xFFFF,CartBR);
+ SetWriteHandler(0x8000,0xffff,Mapper19_write);
+ SetWriteHandler(0x4020,0x5fff,Mapper19_write);
+ if(!is210)
+ {
+ SetWriteHandler(0xc000,0xdfff,Mapper19C0D8_write);
+ SetReadHandler(0x4800,0x4fff,Namco_Read4800);
+ SetReadHandler(0x5000,0x57ff,Namco_Read5000);
+ SetReadHandler(0x5800,0x5fff,Namco_Read5800);
+ NTAPage[0]=NTAPage[1]=NTAPage[2]=NTAPage[3]=0xFF;
+ FixNTAR();
+ }
+
+ SetReadHandler(0x6000,0x7FFF,AWRAM);
+ SetWriteHandler(0x6000,0x7FFF,BWRAM);
+ FCEU_CheatAddRAM(8,0x6000,WRAM);
+
+ gorfus=0xFF;
+ SyncPRG();
+ FixCRR();
+
+ if(!battery)
+ {
+ FCEU_dwmemset(WRAM,0,8192);
+ FCEU_dwmemset(IRAM,0,128);
+ }
+ for(x=0x40;x<0x80;x++)
+ FixCache(x,IRAM[x]);
+}
+
+void Mapper19_Init(CartInfo *info)
+{
+ is210=0;
+ battery=info->battery;
+ info->Power=N106_Power;
+
+ MapIRQHook=NamcoIRQHook;
+ GameStateRestore=Mapper19_StateRestore;
+ GameExpSound.RChange=M19SC;
+
+ if(FSettings.SndRate)
+ Mapper19_ESI();
+
+ AddExState(WRAM, 8192, 0, "WRAM");
+ AddExState(IRAM, 128, 0, "WRAM");
+ AddExState(N106_StateRegs, ~0, 0, 0);
+
+ if(info->battery)
+ {
+ info->SaveGame[0]=WRAM;
+ info->SaveGameLen[0]=8192;
+ info->SaveGame[1]=IRAM;
+ info->SaveGameLen[1]=128;
+ }
+}
+
+static void Mapper210_StateRestore(int version)
+{
+ SyncPRG();
+ FixCRR();
+}
+
+void Mapper210_Init(CartInfo *info)
+{
+ is210=1;
+ GameStateRestore=Mapper210_StateRestore;
+ info->Power=N106_Power;
+ AddExState(WRAM, 8192, 0, "WRAM");
+}