/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
- * Copyright (C) 2002 Ben Parnell
+ * 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
#include "mapinc.h"
+static void (*sfun[3])(void);
+
#define vrctemp mapbyte1[0]
-#define regb000 mapbyte3[0]
-#define regb001 mapbyte3[1]
-#define regb002 mapbyte3[2]
-#define exchstat mapbyte4[0]
#define VPSG2 mapbyte3
#define VPSG mapbyte2
static void DoSawV(void);
static int swaparoo;
-static int32 inc;
-static DECLFW(VRC6PSGW90)
-{
- DoSQV1();VPSG[0]=V;
-}
-static DECLFW(VRC6PSGW91)
-{
- DoSQV1();VPSG[2]=V;
-}
-static DECLFW(VRC6PSGW92)
-{
- DoSQV1();VPSG[3]=V;
-}
-static DECLFW(VRC6PSGWA0)
-{
- DoSQV2();VPSG[4]=V;
-}
-static DECLFW(VRC6PSGWA1)
-{
- DoSQV2();VPSG[6]=V;
-}
-static DECLFW(VRC6PSGWA2)
-{
- DoSQV2();VPSG[7]=V;
-}
-static DECLFW(VRC6PSGWB0)
-{
- DoSawV();VPSG2[0]=V;
-}
-static DECLFW(VRC6PSGWB1)
-{
- DoSawV();VPSG2[1]=V;
-}
-static DECLFW(VRC6PSGWB2)
-{
- DoSawV();VPSG2[2]=V;
-}
static int acount=0;
static void FP_FASTAPASS(1) KonamiIRQHook(int a)
{
- #define LCYCS 114
+ #define LCYCS 341
+// #define LCYCS ((227*2)+1)
if(IRQa)
{
- acount+=a;
+ acount+=a*3;
if(acount>=LCYCS)
{
doagainbub:acount-=LCYCS;IRQCount++;
- if(IRQCount==0x100) {TriggerIRQ();IRQCount=IRQLatch;}
+ if(IRQCount==0x100)
+ {
+ X6502_IRQBegin(FCEU_IQEXT);
+ IRQCount=IRQLatch;
+ }
if(acount>=LCYCS) goto doagainbub;
}
}
}
-DECLFW(Mapper24_write)
+static DECLFW(VRC6SW)
{
- if(swaparoo)
- A=(A&0xFFFC)|((A>>1)&1)|((A<<1)&2);
+ A&=0xF003;
+ if(A>=0x9000 && A<=0x9002)
+ {
+ VPSG[A&3]=V;
+ if(sfun[0]) sfun[0]();
+ }
+ else if(A>=0xa000 && A<=0xa002)
+ {
+ VPSG[4|(A&3)]=V;
+ if(sfun[1]) sfun[1]();
+ }
+ else if(A>=0xb000 && A<=0xb002)
+ {
+ VPSG2[A&3]=V;
+ if(sfun[2]) sfun[2]();
+ }
+}
+
+static DECLFW(Mapper24_write)
+{
+ if(swaparoo)
+ A=(A&0xFFFC)|((A>>1)&1)|((A<<1)&2);
+ if(A>=0x9000 && A<=0xb002)
+ {
+ VRC6SW(A,V);
+ return;
+ }
+ A&=0xF003;
+// if(A>=0xF000) printf("%d, %d, $%04x:$%02x\n",scanline,timestamp,A,V);
switch(A&0xF003)
- {
- case 0x8000:ROM_BANK16(0x8000,V);
- X6502_Rebase();break;
+ {
+ case 0x8000:ROM_BANK16(0x8000,V);break;
case 0xB003:
- switch(V&0xF)
- {
- case 0x0:MIRROR_SET2(1);break;
- case 0x4:MIRROR_SET2(0);break;
- case 0x8:onemir(0);break;
- case 0xC:onemir(1);break;
- }
- break;
- case 0xC000:ROM_BANK8(0xC000,V);
- X6502_Rebase();break;
+ switch(V&0xF)
+ {
+ case 0x0:MIRROR_SET2(1);break;
+ case 0x4:MIRROR_SET2(0);break;
+ case 0x8:onemir(0);break;
+ case 0xC:onemir(1);break;
+ }
+ break;
+ case 0xC000:ROM_BANK8(0xC000,V);break;
case 0xD000:VROM_BANK1(0x0000,V);break;
case 0xD001:VROM_BANK1(0x0400,V);break;
case 0xD002:VROM_BANK1(0x0800,V);break;
case 0xE001:VROM_BANK1(0x1400,V);break;
case 0xE002:VROM_BANK1(0x1800,V);break;
case 0xE003:VROM_BANK1(0x1c00,V);break;
- case 0xF000:IRQLatch=V;break;
+ case 0xF000:IRQLatch=V;
+ //acount=0;
+ break;
case 0xF001:IRQa=V&2;
vrctemp=V&1;
- if(V&2) {IRQCount=IRQLatch;}
- //acount=0;
+ if(V&2)
+ {
+ IRQCount=IRQLatch;
+ acount=0;
+ }
+ X6502_IRQEnd(FCEU_IQEXT);
break;
- case 0xf002:IRQa=vrctemp;break;
+ case 0xf002:IRQa=vrctemp;
+ X6502_IRQEnd(FCEU_IQEXT);break;
case 0xF003:break;
}
}
-static int CVBC[3]={0,0,0};
-static int32 vcount[2];
+static int32 CVBC[3];
+static int32 vcount[3];
+static int32 dcount[2];
-static void DoSQV1(void)
+static INLINE void DoSQV(int x)
{
- uint8 amp;
- int32 freq;
- int V;
- int32 start,end;
-
- start=CVBC[0];
- end=(timestamp<<16)/soundtsinc;
- if(end<=start) return;
- CVBC[0]=end;
-
- if(VPSG[0x3]&0x80)
+ int32 V;
+ int32 amp=(((VPSG[x<<2]&15)<<8)*6/8)>>4;
+ int32 start,end;
+
+ start=CVBC[x];
+ end=(SOUNDTS<<16)/soundtsinc;
+ if(end<=start) return;
+ CVBC[x]=end;
+
+ if(VPSG[(x<<2)|0x2]&0x80)
+ {
+ if(VPSG[x<<2]&0x80)
+ {
+ for(V=start;V<end;V++)
+ Wave[V>>4]+=amp;
+ }
+ else
+ {
+ int32 thresh=(VPSG[x<<2]>>4)&7;
+ int32 freq=((VPSG[(x<<2)|0x1]|((VPSG[(x<<2)|0x2]&15)<<8))+1)<<17;
+ for(V=start;V<end;V++)
+ {
+ if(dcount[x]>thresh) /* Greater than, not >=. Important. */
+ Wave[V>>4]+=amp;
+ vcount[x]-=nesincsize;
+ while(vcount[x]<=0) /* Should only be <0 in a few circumstances. */
{
- amp=(VPSG[0]&15)<<4;
- if(VPSG[0]&0x80)
- {
- for(V=start;V<end;V++)
- Wave[V>>4]+=amp;
- }
- else
- {
- unsigned long dcycs;
- freq=(((VPSG[0x2]|((VPSG[0x3]&15)<<8))+1));
- inc=(long double)((unsigned long)((FSettings.SndRate OVERSAMPLE)<<12))/((long double)PSG_base/freq);
- switch(VPSG[0]&0x70)
- {
- default:
- case 0x00:dcycs=inc>>4;break;
- case 0x10:dcycs=inc>>3;break;
- case 0x20:dcycs=(inc*3)>>4;break;
- case 0x30:dcycs=inc>>2;break;
- case 0x40:dcycs=(inc*5)>>4;break;
- case 0x50:dcycs=(inc*6)>>4;break;
- case 0x60:dcycs=(inc*7)>>4;break;
- case 0x70:dcycs=inc>>1;break;
- }
- for(V=start;V<end;V++)
- {
- if(vcount[0]<dcycs)
- Wave[V>>4]+=amp;
- vcount[0]+=0x1000;
- if(vcount[0]>=inc) vcount[0]-=inc;
- }
- }
+ vcount[x]+=freq;
+ dcount[x]=(dcount[x]+1)&15;
}
+ }
+ }
+ }
}
-static void DoSQV2(void)
-{
- uint8 amp;
- int32 freq;
- int V;
- int32 start,end;
- start=CVBC[1];
- end=(timestamp<<16)/soundtsinc;
- if(end<=start) return;
- CVBC[1]=end;
+static void DoSQV1(void)
+{
+ DoSQV(0);
+}
- if(VPSG[0x7]&0x80)
- {
- amp=(VPSG[4]&15)<<4;
- if(VPSG[4]&0x80)
- {
- for(V=start;V<end;V++)
- Wave[V>>4]+=amp;
- }
- else
- {
- unsigned long dcycs;
- freq=(((VPSG[0x6]|((VPSG[0x7]&15)<<8))+1));
- inc=(long double)((unsigned long)((FSettings.SndRate OVERSAMPLE)<<12))/((long double)PSG_base/freq);
- switch(VPSG[4]&0x70)
- {
- default:
- case 0x00:dcycs=inc>>4;break;
- case 0x10:dcycs=inc>>3;break;
- case 0x20:dcycs=(inc*3)>>4;break;
- case 0x30:dcycs=inc>>2;break;
- case 0x40:dcycs=(inc*5)>>4;break;
- case 0x50:dcycs=(inc*6)>>4;break;
- case 0x60:dcycs=(inc*7)>>4;break;
- case 0x70:dcycs=inc>>1;break;
- }
- for(V=start;V<end;V++)
- {
- if(vcount[1]<dcycs)
- Wave[V>>4]+=amp;
- vcount[1]+=0x1000;
- if(vcount[1]>=inc) vcount[1]-=inc;
- }
- }
- }
+static void DoSQV2(void)
+{
+ DoSQV(1);
}
static void DoSawV(void)
int32 start,end;
start=CVBC[2];
- end=(timestamp<<16)/soundtsinc;
+ end=(SOUNDTS<<16)/soundtsinc;
if(end<=start) return;
CVBC[2]=end;
if(VPSG2[2]&0x80)
{
- static int64 saw1phaseacc=0;
+ static int32 saw1phaseacc=0;
uint32 freq3;
static uint8 b3=0;
static int32 phaseacc=0;
for(V=start;V<end;V++)
{
- saw1phaseacc-=nesincsizeLL;
+ saw1phaseacc-=nesincsize;
if(saw1phaseacc<=0)
{
- int64 t;
+ int32 t;
rea:
t=freq3;
- t<<=50; // 49 + 1
+ t<<=18;
saw1phaseacc+=t;
phaseacc+=VPSG2[0]&0x3f;
b3++;
}
if(saw1phaseacc<=0)
goto rea;
- duff=(((phaseacc>>3)&0x1f)<<4);
+ duff=(((phaseacc>>3)&0x1f)<<4)*6/8;
}
Wave[V>>4]+=duff;
}
}
}
-void VRC6Sound(int Count)
+#if 0
+static INLINE void DoSQVHQ(int x)
{
- int x;
+ int32 V;
+ int32 amp=((VPSG[x<<2]&15)<<8)*6/8;
- DoSQV1();
- DoSQV2();
- DoSawV();
- for(x=0;x<3;x++)
- CVBC[x]=Count;
+ if(VPSG[(x<<2)|0x2]&0x80)
+ {
+ if(VPSG[x<<2]&0x80)
+ {
+ for(V=CVBC[x];V<SOUNDTS;V++)
+ WaveHi[V]+=amp;
+ }
+ else
+ {
+ int32 thresh=(VPSG[x<<2]>>4)&7;
+ for(V=CVBC[x];V<SOUNDTS;V++)
+ {
+ if(dcount[x]>thresh) /* Greater than, not >=. Important. */
+ WaveHi[V]+=amp;
+ vcount[x]--;
+ if(vcount[x]<=0) /* Should only be <0 in a few circumstances. */
+ {
+ vcount[x]=(VPSG[(x<<2)|0x1]|((VPSG[(x<<2)|0x2]&15)<<8))+1;
+ dcount[x]=(dcount[x]+1)&15;
+ }
+ }
+ }
+ }
+ CVBC[x]=SOUNDTS;
}
-static int satype=0;
+static void DoSQV1HQ(void)
+{
+ DoSQVHQ(0);
+}
+
+static void DoSQV2HQ(void)
+{
+ DoSQVHQ(1);
+}
-void VRC6SoundC(void)
+static void DoSawVHQ(void)
{
- int x;
+ static uint8 b3=0;
+ static int32 phaseacc=0;
+ int32 V;
- if(FSettings.SndRate)
- VRC6_ESI(satype);
- else
+ if(VPSG2[2]&0x80)
+ {
+ for(V=CVBC[2];V<SOUNDTS;V++)
{
- for(x=000;x<0x1000;x+=4)
+ WaveHi[V]+=(((phaseacc>>3)&0x1f)<<8)*6/8;
+ vcount[2]--;
+ if(vcount[2]<=0)
{
- SetWriteHandler(0x9000+x,0x9002+x,0);
- SetWriteHandler(0xa000+x,0xa002+x,0);
- SetWriteHandler(0xb000+x,0xb002+x,0);
+ vcount[2]=(VPSG2[1]+((VPSG2[2]&15)<<8)+1)<<1;
+ phaseacc+=VPSG2[0]&0x3f;
+ b3++;
+ if(b3==7)
+ {
+ b3=0;
+ phaseacc=0;
+ }
+
}
}
+ }
+ CVBC[2]=SOUNDTS;
+}
+#endif
+
+
+void VRC6Sound(int Count)
+{
+ int x;
+
+ DoSQV1();
+ DoSQV2();
+ DoSawV();
+ for(x=0;x<3;x++)
+ CVBC[x]=Count;
}
-void VRC6_ESI(int t)
+#if 0
+void VRC6SoundHQ(void)
{
- int x;
+ DoSQV1HQ();
+ DoSQV2HQ();
+ DoSawVHQ();
+}
- satype=t;
+void VRC6SyncHQ(int32 ts)
+{
+ int x;
+ for(x=0;x<3;x++) CVBC[x]=ts;
+}
+#endif
- GameExpSound.RChange=VRC6SoundC;
+static void VRC6_ESI(void)
+{
+ GameExpSound.RChange=VRC6_ESI;
GameExpSound.Fill=VRC6Sound;
+ GameExpSound.HiFill=0;//VRC6SoundHQ;
+ GameExpSound.HiSync=0;//VRC6SyncHQ;
+
+ memset(CVBC,0,sizeof(CVBC));
+ memset(vcount,0,sizeof(vcount));
+ memset(dcount,0,sizeof(dcount));
if(FSettings.SndRate)
- for(x=000;x<0x1000;x+=4)
+ {
+#if 0
+ if(FSettings.soundq>=1)
+ {
+ sfun[0]=DoSQV1HQ;
+ sfun[1]=DoSQV2HQ;
+ sfun[2]=DoSawVHQ;
+ }
+ else
+#endif
{
- uint32 a;
-
- a=0x9000+x;
- SetWriteHandler(a,a,VRC6PSGW90);
- SetWriteHandler(a+(1^t),a+(1^t),VRC6PSGW91);
- SetWriteHandler(a+(2^t),a+(2^t),VRC6PSGW92);
-
- a=0xa000+x;
- SetWriteHandler(a,a,VRC6PSGWA0);
- SetWriteHandler(a+(1^t),a+(1^t),VRC6PSGWA1);
- SetWriteHandler(a+(2^t),a+(2^t),VRC6PSGWA2);
-
- a=0xb000+x;
- SetWriteHandler(a,a,VRC6PSGWB0);
- SetWriteHandler(a+(1^t),a+(1^t),VRC6PSGWB1);
- SetWriteHandler(a+(2^t),a+(2^t),VRC6PSGWB2);
+ sfun[0]=DoSQV1;
+ sfun[1]=DoSQV2;
+ sfun[2]=DoSawV;
}
+ }
+ else
+ memset(sfun,0,sizeof(sfun));
}
void Mapper24_init(void)
{
SetWriteHandler(0x8000,0xffff,Mapper24_write);
- if(FSettings.SndRate)
- VRC6_ESI(0);
- GameExpSound.RChange=VRC6SoundC;
+ VRC6_ESI();
MapIRQHook=KonamiIRQHook;
- swaparoo=0;
+ swaparoo=0;
}
void Mapper26_init(void)
{
SetWriteHandler(0x8000,0xffff,Mapper24_write);
- if(FSettings.SndRate)
- VRC6_ESI(3);
- GameExpSound.RChange=VRC6SoundC;
+ VRC6_ESI();
MapIRQHook=KonamiIRQHook;
- swaparoo=1;
+ swaparoo=1;
}
+void NSFVRC6_Init(void)
+{
+ VRC6_ESI();
+ SetWriteHandler(0x8000,0xbfff,VRC6SW);
+}