diff --git a/Makefile.common b/Makefile.common index f72e37c..fe710f6 100644 --- a/Makefile.common +++ b/Makefile.common @@ -35,6 +35,7 @@ SOURCES_C += \ $(CORE_DIR)/misc.c \ $(CORE_DIR)/fceu.c \ $(CORE_DIR)/fds.c \ + $(CORE_DIR)/fds_apu.c \ $(CORE_DIR)/file.c \ $(CORE_DIR)/filter.c \ $(CORE_DIR)/general.c \ diff --git a/src/boards/103.c b/src/boards/103.c index 9d35e14..3f69a78 100644 --- a/src/boards/103.c +++ b/src/boards/103.c @@ -17,11 +17,12 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * FDS Conversion + * FDS Conversion - Doki Doki Panic * */ #include "mapinc.h" +#include "../fds_apu.h" static uint8 reg0, reg1, reg2; static uint8 *WRAM = NULL; @@ -80,6 +81,7 @@ static DECLFW(M103Write2) { } static void M103Power(void) { + FDSSoundPower(); reg0 = reg1 = 0; reg2 = 0; Sync(); SetReadHandler(0x6000, 0x7FFF, CartBR); diff --git a/src/boards/353.c b/src/boards/353.c index 63222b5..10a49a6 100644 --- a/src/boards/353.c +++ b/src/boards/353.c @@ -25,6 +25,7 @@ #include "mapinc.h" #include "mmc3.h" +#include "../fds_apu.h" static uint8* CHRRAM = NULL; static uint32 CHRRAMSIZE; @@ -96,6 +97,7 @@ static DECLFW(M353Write) { } static void M353Power(void) { + FDSSoundPower(); EXPREGS[0] = 0; GenMMC3Power(); SetWriteHandler(0x8000, 0xFFFF, M353Write); @@ -104,6 +106,7 @@ static void M353Power(void) { static void M353Reset(void) { EXPREGS[0] = 0; MMC3RegReset(); + FDSSoundReset(); } static void M353Close(void) { diff --git a/src/boards/359.c b/src/boards/359.c index c1194b1..926302a 100644 --- a/src/boards/359.c +++ b/src/boards/359.c @@ -23,6 +23,7 @@ */ #include "mapinc.h" +#include "../fds_apu.h" static uint32 mapperNum; static uint8 preg[4]; @@ -140,6 +141,7 @@ static DECLFW(M359WriteEx) { } static void M359Power(void) { + FDSSoundPower(); Sync(); SetReadHandler(0x6000, 0xFFFF, CartBR); SetWriteHandler(0x8000, 0x8FFF, M359WritePRG); @@ -148,6 +150,11 @@ static void M359Power(void) { SetWriteHandler(0xC000, 0xCFFF, M359WriteIRQ); } +static void M359Reset(void) { + FDSSoundReset(); + Sync(); +} + static void FP_FASTAPASS(1) M359CPUHook(int a) { if (!irqPA12) { if (IRQa && IRQCount16) { @@ -177,6 +184,7 @@ static void StateRestore(int version) { void Mapper359_Init(CartInfo* info) { mapperNum = 359; info->Power = M359Power; + info->Reset = M359Reset; MapIRQHook = M359CPUHook; GameHBIRQHook = M359IRQHook; GameStateRestore = StateRestore; diff --git a/src/boards/42.c b/src/boards/42.c index d012258..b507c34 100644 --- a/src/boards/42.c +++ b/src/boards/42.c @@ -23,6 +23,7 @@ */ #include "mapinc.h" +#include "../fds_apu.h" static uint8 preg, creg, mirr; static uint32 IRQCount, IRQa; @@ -54,6 +55,7 @@ static DECLFW(M42Write) { } static void M42Power(void) { + FDSSoundPower(); preg = 0; mirr = 1; /* Ai Senshi Nicol actually has fixed mirroring, but mapper forcing it's default value now */ Sync(); diff --git a/src/boards/539.c b/src/boards/539.c index 8b1927e..e360aa5 100644 --- a/src/boards/539.c +++ b/src/boards/539.c @@ -18,7 +18,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +/* FDS Conversion - Kid Icarus (パルテナの鏡) (Parthena) */ + #include "mapinc.h" +#include "../fds_apu.h" static uint8 preg; static uint8 mirr; @@ -82,6 +85,7 @@ static DECLFW(M539Write) { } static void M539Power(void) { + FDSSoundPower(); preg = 0; mirr = 0; Sync(); diff --git a/src/boards/KS7016.c b/src/boards/KS7016.c index c7f5ff8..18c54d4 100644 --- a/src/boards/KS7016.c +++ b/src/boards/KS7016.c @@ -25,6 +25,7 @@ */ #include "mapinc.h" +#include "../fds_apu.h" static uint8 preg; @@ -68,6 +69,7 @@ static DECLFW(UNLKS7016Write) { } static void UNLKS7016Power(void) { + FDSSoundPower(); preg = 8; Sync(); SetReadHandler(0x6000, 0xffff, CartBR); diff --git a/src/boards/KS7017.c b/src/boards/KS7017.c index b1c9d87..1e4a830 100644 --- a/src/boards/KS7017.c +++ b/src/boards/KS7017.c @@ -17,11 +17,12 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * FDS Conversion + * FDS Conversion - Almana No Kiseki * */ #include "mapinc.h" +#include "../fds_apu.h" static uint8 latche, reg, mirr; static int32 IRQa, IRQCount, IRQLatch; @@ -52,19 +53,23 @@ static DECLFW(UNLKS7017Write) { } else if ((A & 0xFF00) == 0x5100) { reg = latche; Sync(); - } else if (A == 0x4020) { - X6502_IRQEnd(FCEU_IQEXT); - IRQCount &= 0xFF00; - IRQCount |= V; - } else if (A == 0x4021) { - X6502_IRQEnd(FCEU_IQEXT); - IRQCount &= 0xFF; - IRQCount |= V << 8; - IRQa = 1; - } else if (A == 0x4025) { - mirr = ((V & 8) >> 3) ^ 1; + } else { + if (A == 0x4020) { + X6502_IRQEnd(FCEU_IQEXT); + IRQCount &= 0xFF00; + IRQCount |= V; + } else if (A == 0x4021) { + X6502_IRQEnd(FCEU_IQEXT); + IRQCount &= 0xFF; + IRQCount |= V << 8; + IRQa = 1; + } else if (A == 0x4025) { + mirr = ((V & 8) >> 3) ^ 1; + } + FDSSoundWrite(A, V); } } + static DECLFR(FDSRead4030) { X6502_IRQEnd(FCEU_IQEXT); return X.IRQlow & FCEU_IQEXT ? 1 : 0; @@ -81,6 +86,7 @@ static void FP_FASTAPASS(1) UNL7017IRQ(int a) { } static void UNLKS7017Power(void) { + FDSSoundPower(); Sync(); setchr8(0); setprg8r(0x10, 0x6000, 0); diff --git a/src/boards/KS7030.c b/src/boards/KS7030.c index f9ece1f..fd758a5 100644 --- a/src/boards/KS7030.c +++ b/src/boards/KS7030.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * FDS Conversion + * FDS Conversion - Yume Koujou: Doki Doki Panic * * Logical bank layot 32 K BANK 0, 64K BANK 1, 32K ~0 hardwired, 8K is missing * need redump from MASKROM! @@ -26,6 +26,7 @@ */ #include "mapinc.h" +#include "../fds_apu.h" static uint8 reg0, reg1; static uint8 *WRAM = NULL; @@ -108,6 +109,7 @@ static DECLFW(UNLKS7030Write1) { } static void UNLKS7030Power(void) { + FDSSoundPower(); reg0 = reg1 = ~0; Sync(); SetReadHandler(0x6000, 0x7FFF, UNLKS7030RamRead0); diff --git a/src/boards/KS7031.c b/src/boards/KS7031.c index bbd1d84..4f961f4 100644 --- a/src/boards/KS7031.c +++ b/src/boards/KS7031.c @@ -17,11 +17,12 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * FDS Conversion + * FDS Conversion - dracula ii - noroi no fuuin [u][!] * */ #include "mapinc.h" +#include "fds_apu.h" static uint8 reg[4]; @@ -64,6 +65,7 @@ static DECLFW(UNLKS7031Write) { } static void UNLKS7031Power(void) { + FDSSoundPower(); Sync(); SetReadHandler(0x6000, 0xFFFF, CartBR); SetWriteHandler(0x8000, 0xffff, UNLKS7031Write); diff --git a/src/boards/KS7037.c b/src/boards/KS7037.c index 17c047d..0c73c36 100644 --- a/src/boards/KS7037.c +++ b/src/boards/KS7037.c @@ -17,11 +17,12 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * FDS Conversion + * FDS Conversion - Metroid - Jin Ji Zhi Ling (Kaiser)(KS7037)[U][!] * */ #include "mapinc.h" +#include "../fds_apu.h" static uint8 reg[8], cmd; static uint8 *WRAM = NULL; @@ -66,6 +67,7 @@ static DECLFW(UNLKS7037Write) { } static void UNLKS7037Power(void) { + FDSSoundPower(); reg[0] = reg[1] = reg[2] = reg[3] = reg[4] = reg[5] = reg[6] = reg[7] = 0; WSync(); SetReadHandler(0x6000, 0xFFFF, CartBR); diff --git a/src/boards/ac-08.c b/src/boards/ac-08.c index 33bcc24..da26e39 100644 --- a/src/boards/ac-08.c +++ b/src/boards/ac-08.c @@ -24,6 +24,7 @@ */ #include "mapinc.h" +#include "../fds_apu.h" static uint8 reg, mirr; static uint8 prg; @@ -56,6 +57,7 @@ static DECLFW(AC08Write) { } static void AC08Power(void) { + FDSSoundPower(); reg = 0; Sync(); SetReadHandler(0x6000, 0xFFFF, CartBR); diff --git a/src/boards/datalatch.c b/src/boards/datalatch.c index 1c6e577..46a3eee 100644 --- a/src/boards/datalatch.c +++ b/src/boards/datalatch.c @@ -20,6 +20,7 @@ #include "mapinc.h" #include "../ines.h" +#include "../fds_apu.h" static uint8 latche, latcheinit, bus_conflict; static uint16 addrreg0, addrreg1; @@ -518,8 +519,14 @@ static void M538Sync(void) { setmirror(1); } +static void M538Power(void) { + FDSSoundPower(); + LatchPower(); +} + void Mapper538_Init(CartInfo *info) { Latch_Init(info, M538Sync, 0, 0xC000, 0xCFFF, 1, 0); + info->Power = M538Power; } /* ------------------ A65AS --------------------------- */ diff --git a/src/boards/lh32.c b/src/boards/lh32.c index 74a0a83..b0635a9 100644 --- a/src/boards/lh32.c +++ b/src/boards/lh32.c @@ -17,11 +17,12 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * FDS Conversion + * FDS Conversion - Monty no Doki Doki Daisassō, Monty on the Run, cartridge code LH32 * */ #include "mapinc.h" +#include "../fds_apu.h" static uint8 reg; static uint8 *WRAM = NULL; @@ -48,6 +49,7 @@ static DECLFW(LH32Write) { } static void LH32Power(void) { + FDSSoundPower(); Sync(); SetReadHandler(0x6000, 0xFFFF, CartBR); SetWriteHandler(0xC000, 0xDFFF, CartBW); diff --git a/src/boards/lh51.c b/src/boards/lh51.c index 3236485..4a559bb 100644 --- a/src/boards/lh51.c +++ b/src/boards/lh51.c @@ -26,6 +26,7 @@ */ #include "mapinc.h" +#include "../fds_apu.h" static uint8 reg, mirr; static uint8 *WRAM = NULL; @@ -56,6 +57,7 @@ static DECLFW(LH51Write) { } static void LH51Power(void) { + FDSSoundPower(); Sync(); SetReadHandler(0x6000, 0xFFFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); diff --git a/src/boards/lh53.c b/src/boards/lh53.c index 10aae81..1ee1592 100644 --- a/src/boards/lh53.c +++ b/src/boards/lh53.c @@ -17,11 +17,12 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * FDS Conversion + * FDS Conversion - Nazo no Murasamejō * */ #include "mapinc.h" +#include "../fds_apu.h" static uint8 reg, IRQa; static int32 IRQCount; @@ -75,6 +76,7 @@ static void FP_FASTAPASS(1) LH53IRQ(int a) { } static void LH53Power(void) { + FDSSoundPower(); Sync(); SetReadHandler(0x6000, 0xFFFF, CartBR); SetWriteHandler(0xB800, 0xD7FF, LH53RamWrite); diff --git a/src/drivers/libretro/griffin.c b/src/drivers/libretro/griffin.c index 0647180..3158363 100644 --- a/src/drivers/libretro/griffin.c +++ b/src/drivers/libretro/griffin.c @@ -21,6 +21,7 @@ #include "misc.c" #include "fceu.c" #include "fds.c" +#include "fds_apu.c" #include "file.c" #include "filter.c" #include "general.c" diff --git a/src/fds.c b/src/fds.c index f7358ab..3501915 100644 --- a/src/fds.c +++ b/src/fds.c @@ -26,6 +26,7 @@ #include "x6502.h" #include "fceu.h" #include "fds.h" +#include "fds_apu.h" #include "sound.h" #include "general.h" #include "state.h" @@ -106,8 +107,6 @@ static uint8 mapperFDS_diskaccess; /* disk needs to be accessed at least once b #define GET_FDS_DISK() (diskdata[InDisk][mapperFDS_blockstart + mapperFDS_diskaddr]) #define FDS_DISK_INSERTED (InDisk != 255) -uint32 lastDiskPtrRead, lastDiskPtrWrite; - #define DC_INC 1 #define BYTES_PER_SIDE 65500 @@ -139,15 +138,9 @@ static void FDSStateRestore(int version) { } } -void FDSSound(int a); -void FDSSoundReset(void); -void FDSSoundStateAdd(void); -static void RenderSound(void); -static void RenderSoundHQ(void); - static void FDSInit(void) { memset(FDSRegs, 0, sizeof(FDSRegs)); - lastDiskPtrRead = lastDiskPtrWrite = writeskip = DiskPtr = DiskSeekIRQ = 0; + writeskip = DiskPtr = DiskSeekIRQ = 0; setmirror(1); setprg8(0xE000, 0); /* BIOS */ @@ -255,7 +248,6 @@ static DECLFR(FDSRead4031) { static uint8 z = 0; if (InDisk != 255) { z = diskdata[InDisk][DiskPtr]; - lastDiskPtrRead = DiskPtr; #ifdef FCEUDEF_DEBUGGER if (!fceuindbg) #endif @@ -328,261 +320,6 @@ static DECLFR(FDSRead4033) { return 0x80; /* battery */ } -/* Begin FDS sound */ - -#define FDSClock (1789772.7272727272727272 / 2) - -typedef struct { - int64 cycles; /* Cycles per PCM sample */ - int64 count; /* Cycle counter */ - int64 envcount; /* Envelope cycle counter */ - uint32 b19shiftreg60; - uint32 b24adder66; - uint32 b24latch68; - uint32 b17latch76; - int32 clockcount; /* Counter to divide frequency by 8. */ - uint8 b8shiftreg88; /* Modulation register. */ - uint8 amplitude[2]; /* Current amplitudes. */ - uint8 speedo[2]; - uint8 mwcount; - uint8 mwstart; - uint8 mwave[0x20]; /* Modulation waveform */ - uint8 cwave[0x40]; /* Game-defined waveform(carrier) */ - uint8 SPSG[0xB]; -} FDSSOUND; - -static FDSSOUND fdso; - -#define SPSG fdso.SPSG -#define b19shiftreg60 fdso.b19shiftreg60 -#define b24adder66 fdso.b24adder66 -#define b24latch68 fdso.b24latch68 -#define b17latch76 fdso.b17latch76 -#define b8shiftreg88 fdso.b8shiftreg88 -#define clockcount fdso.clockcount -#define amplitude fdso.amplitude -#define speedo fdso.speedo - -void FDSSoundStateAdd(void) { - AddExState(fdso.cwave, 64, 0, "WAVE"); - AddExState(fdso.mwave, 32, 0, "MWAV"); - AddExState(amplitude, 2, 0, "AMPL"); - AddExState(SPSG, 0xB, 0, "SPSG"); - - AddExState(&b8shiftreg88, 1, 0, "B88"); - - AddExState(&clockcount, 4, 1, "CLOC"); - AddExState(&b19shiftreg60, 4, 1, "B60"); - AddExState(&b24adder66, 4, 1, "B66"); - AddExState(&b24latch68, 4, 1, "B68"); - AddExState(&b17latch76, 4, 1, "B76"); -} - -static DECLFR(FDSSRead) { - switch (A & 0xF) { - case 0x0: return(amplitude[0] | (X.DB & 0xC0)); - case 0x2: return(amplitude[1] | (X.DB & 0xC0)); - } - return(X.DB); -} - -static DECLFW(FDSSWrite) { - if (FSettings.SndRate) { - if (FSettings.soundq >= 1) - RenderSoundHQ(); - else - RenderSound(); - } - A -= 0x4080; - switch (A) { - case 0x0: - case 0x4: - if (V & 0x80) - amplitude[(A & 0xF) >> 2] = V & 0x3F; - break; - case 0x7: - b17latch76 = 0; - SPSG[0x5] = 0; - break; - case 0x8: - b17latch76 = 0; - fdso.mwave[SPSG[0x5] & 0x1F] = V & 0x7; - SPSG[0x5] = (SPSG[0x5] + 1) & 0x1F; - break; - } - SPSG[A] = V; -} - -/* $4080 - Fundamental wave amplitude data register 92 - * $4082 - Fundamental wave frequency data register 58 - * $4083 - Same as $4082($4083 is the upper 4 bits). - * - * $4084 - Modulation amplitude data register 78 - * $4086 - Modulation frequency data register 72 - * $4087 - Same as $4086($4087 is the upper 4 bits) - */ - - -static void DoEnv() { - int x; - - for (x = 0; x < 2; x++) - if (!(SPSG[x << 2] & 0x80) && !(SPSG[0x3] & 0x40)) { - static int counto[2] = { 0, 0 }; - - if (counto[x] <= 0) { - if (!(SPSG[x << 2] & 0x80)) { - if (SPSG[x << 2] & 0x40) { - if (amplitude[x] < 0x3F) - amplitude[x]++; - } else { - if (amplitude[x] > 0) - amplitude[x]--; - } - } - counto[x] = (SPSG[x << 2] & 0x3F); - } else - counto[x]--; - } -} - -static DECLFR(FDSWaveRead) { - return(fdso.cwave[A & 0x3f] | (X.DB & 0xC0)); -} - -static DECLFW(FDSWaveWrite) { - if (SPSG[0x9] & 0x80) - fdso.cwave[A & 0x3f] = V & 0x3F; -} - -static int ta; -static INLINE void ClockRise(void) { - if (!clockcount) { - ta++; - - b19shiftreg60 = (SPSG[0x2] | ((SPSG[0x3] & 0xF) << 8)); - b17latch76 = (SPSG[0x6] | ((SPSG[0x07] & 0xF) << 8)) + b17latch76; - - if (!(SPSG[0x7] & 0x80)) { - int t = fdso.mwave[(b17latch76 >> 13) & 0x1F] & 7; - int t2 = amplitude[1]; - int adj = 0; - - if ((t & 3)) { - if ((t & 4)) - adj -= (t2 * ((4 - (t & 3)))); - else - adj += (t2 * ((t & 3))); - } - adj *= 2; - if (adj > 0x7F) adj = 0x7F; - if (adj < -0x80) adj = -0x80; - b8shiftreg88 = 0x80 + adj; - } else { - b8shiftreg88 = 0x80; - } - } else { - b19shiftreg60 <<= 1; - b8shiftreg88 >>= 1; - } - b24adder66 = (b24latch68 + b19shiftreg60) & 0x1FFFFFF; -} - -static INLINE void ClockFall(void) { - if ((b8shiftreg88 & 1)) - b24latch68 = b24adder66; - clockcount = (clockcount + 1) & 7; -} - -static INLINE int32 FDSDoSound(void) { - fdso.count += fdso.cycles; - if (fdso.count >= ((int64)1 << 40)) { - dogk: - fdso.count -= (int64)1 << 40; - ClockRise(); - ClockFall(); - fdso.envcount--; - if (fdso.envcount <= 0) { - fdso.envcount += SPSG[0xA] * 3; - DoEnv(); - } - } - if (fdso.count >= 32768) goto dogk; - - /* Might need to emulate applying the amplitude to the waveform a bit better... */ - { - int k = amplitude[0]; - if (k > 0x20) k = 0x20; - return (fdso.cwave[b24latch68 >> 19] * k) * 4 / ((SPSG[0x9] & 0x3) + 2); - } -} - -static int32 FBC = 0; - -static void RenderSound(void) { - int32 end, start; - int32 x; - - start = FBC; - end = (SOUNDTS << 16) / soundtsinc; - if (end <= start) - return; - FBC = end; - - if (!(SPSG[0x9] & 0x80)) - for (x = start; x < end; x++) { - uint32 t = FDSDoSound(); - t += t >> 1; - t >>= 4; - Wave[x >> 4] += t; /* (t>>2)-(t>>3); */ /* >>3; */ - } -} - -static void RenderSoundHQ(void) { - uint32 x; - - if (!(SPSG[0x9] & 0x80)) - for (x = FBC; x < SOUNDTS; x++) { - uint32 t = FDSDoSound(); - t += t >> 1; - WaveHi[x] += t; /* (t<<2)-(t<<1); */ - } - FBC = SOUNDTS; -} - -static void HQSync(int32 ts) { - FBC = ts; -} - -void FDSSound(int c) { - RenderSound(); - FBC = c; -} - -static void FDS_ESI(void) { - if (FSettings.SndRate) { - if (FSettings.soundq >= 1) { - fdso.cycles = (int64)1 << 39; - } else { - fdso.cycles = ((int64)1 << 40) * FDSClock; - fdso.cycles /= FSettings.SndRate * 16; - } - } - SetReadHandler(0x4040, 0x407f, FDSWaveRead); - SetWriteHandler(0x4040, 0x407f, FDSWaveWrite); - SetWriteHandler(0x4080, 0x408A, FDSSWrite); - SetReadHandler(0x4090, 0x4092, FDSSRead); -} - -void FDSSoundReset(void) { - memset(&fdso, 0, sizeof(fdso)); - FDS_ESI(); - GameExpSound.HiSync = HQSync; - GameExpSound.HiFill = RenderSoundHQ; - GameExpSound.Fill = FDSSound; - GameExpSound.RChange = FDS_ESI; -} - static DECLFW(FDSWrite) { switch (A) { case 0x4020: @@ -618,7 +355,6 @@ static DECLFW(FDSWrite) { else if (DiskPtr >= 2) { DiskWritten = 1; diskdata[InDisk][DiskPtr - 2] = V; - lastDiskPtrWrite = DiskPtr - 2; } } } diff --git a/src/fds.h b/src/fds.h index 236d936..47b6412 100644 --- a/src/fds.h +++ b/src/fds.h @@ -4,12 +4,8 @@ uint8 *FDSROM_ptr(void); uint32 FDSROM_size(void); -void FDSSoundReset(void); - void FCEU_FDSInsert(int oride); void FCEU_FDSEject(void); void FCEU_FDSSelect(void); -extern uint32 lastDiskPtrRead, lastDiskPtrWrite; - #endif diff --git a/src/fds_apu.c b/src/fds_apu.c new file mode 100644 index 0000000..8d67d36 --- /dev/null +++ b/src/fds_apu.c @@ -0,0 +1,298 @@ +/* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* Begin FDS sound */ + +#include "fceu-types.h" +#include "x6502.h" +#include "fceu.h" +#include "sound.h" + +#define FDSClock (1789772.7272727272727272 / 2) + +typedef struct { + int64 cycles; /* Cycles per PCM sample */ + int64 count; /* Cycle counter */ + int64 envcount; /* Envelope cycle counter */ + uint32 b19shiftreg60; + uint32 b24adder66; + uint32 b24latch68; + uint32 b17latch76; + int32 clockcount; /* Counter to divide frequency by 8. */ + uint8 b8shiftreg88; /* Modulation register. */ + uint8 amplitude[2]; /* Current amplitudes. */ + uint8 speedo[2]; + uint8 mwcount; + uint8 mwstart; + uint8 mwave[0x20]; /* Modulation waveform */ + uint8 cwave[0x40]; /* Game-defined waveform(carrier) */ + uint8 SPSG[0xB]; +} FDSSOUND; + +static FDSSOUND fdso; + +#define SPSG fdso.SPSG +#define b19shiftreg60 fdso.b19shiftreg60 +#define b24adder66 fdso.b24adder66 +#define b24latch68 fdso.b24latch68 +#define b17latch76 fdso.b17latch76 +#define b8shiftreg88 fdso.b8shiftreg88 +#define clockcount fdso.clockcount +#define amplitude fdso.amplitude +#define speedo fdso.speedo + +void FDSSoundStateAdd(void) { + AddExState(fdso.cwave, 64, 0, "WAVE"); + AddExState(fdso.mwave, 32, 0, "MWAV"); + AddExState(amplitude, 2, 0, "AMPL"); + AddExState(SPSG, 0xB, 0, "SPSG"); + + AddExState(&b8shiftreg88, 1, 0, "B88"); + + AddExState(&clockcount, 4, 1, "CLOC"); + AddExState(&b19shiftreg60, 4, 1, "B60"); + AddExState(&b24adder66, 4, 1, "B66"); + AddExState(&b24latch68, 4, 1, "B68"); + AddExState(&b17latch76, 4, 1, "B76"); +} + +static DECLFR(FDSSRead) { + switch (A & 0xF) { + case 0x0: return(amplitude[0] | (X.DB & 0xC0)); + case 0x2: return(amplitude[1] | (X.DB & 0xC0)); + } + return(X.DB); +} + +static void RenderSound(void); +static void RenderSoundHQ(void); + +static DECLFW(FDSSWrite) { + if (FSettings.SndRate) { + if (FSettings.soundq >= 1) + RenderSoundHQ(); + else + RenderSound(); + } + A -= 0x4080; + switch (A) { + case 0x0: + case 0x4: + if (V & 0x80) + amplitude[(A & 0xF) >> 2] = V & 0x3F; + break; + case 0x7: + b17latch76 = 0; + SPSG[0x5] = 0; + break; + case 0x8: + b17latch76 = 0; + fdso.mwave[SPSG[0x5] & 0x1F] = V & 0x7; + SPSG[0x5] = (SPSG[0x5] + 1) & 0x1F; + break; + } + SPSG[A] = V; +} + +/* $4080 - Fundamental wave amplitude data register 92 + * $4082 - Fundamental wave frequency data register 58 + * $4083 - Same as $4082($4083 is the upper 4 bits). + * + * $4084 - Modulation amplitude data register 78 + * $4086 - Modulation frequency data register 72 + * $4087 - Same as $4086($4087 is the upper 4 bits) + */ + + +static void DoEnv() { + int x; + + for (x = 0; x < 2; x++) + if (!(SPSG[x << 2] & 0x80) && !(SPSG[0x3] & 0x40)) { + static int counto[2] = { 0, 0 }; + + if (counto[x] <= 0) { + if (!(SPSG[x << 2] & 0x80)) { + if (SPSG[x << 2] & 0x40) { + if (amplitude[x] < 0x3F) + amplitude[x]++; + } else { + if (amplitude[x] > 0) + amplitude[x]--; + } + } + counto[x] = (SPSG[x << 2] & 0x3F); + } else + counto[x]--; + } +} + +static DECLFR(FDSWaveRead) { + return(fdso.cwave[A & 0x3f] | (X.DB & 0xC0)); +} + +static DECLFW(FDSWaveWrite) { + if (SPSG[0x9] & 0x80) + fdso.cwave[A & 0x3f] = V & 0x3F; +} + +static int ta; +static INLINE void ClockRise(void) { + if (!clockcount) { + ta++; + + b19shiftreg60 = (SPSG[0x2] | ((SPSG[0x3] & 0xF) << 8)); + b17latch76 = (SPSG[0x6] | ((SPSG[0x07] & 0xF) << 8)) + b17latch76; + + if (!(SPSG[0x7] & 0x80)) { + int t = fdso.mwave[(b17latch76 >> 13) & 0x1F] & 7; + int t2 = amplitude[1]; + int adj = 0; + + if ((t & 3)) { + if ((t & 4)) + adj -= (t2 * ((4 - (t & 3)))); + else + adj += (t2 * ((t & 3))); + } + adj *= 2; + if (adj > 0x7F) adj = 0x7F; + if (adj < -0x80) adj = -0x80; + b8shiftreg88 = 0x80 + adj; + } else { + b8shiftreg88 = 0x80; + } + } else { + b19shiftreg60 <<= 1; + b8shiftreg88 >>= 1; + } + b24adder66 = (b24latch68 + b19shiftreg60) & 0x1FFFFFF; +} + +static INLINE void ClockFall(void) { + if ((b8shiftreg88 & 1)) + b24latch68 = b24adder66; + clockcount = (clockcount + 1) & 7; +} + +static INLINE int32 FDSDoSound(void) { + fdso.count += fdso.cycles; + if (fdso.count >= ((int64)1 << 40)) { + dogk: + fdso.count -= (int64)1 << 40; + ClockRise(); + ClockFall(); + fdso.envcount--; + if (fdso.envcount <= 0) { + fdso.envcount += SPSG[0xA] * 3; + DoEnv(); + } + } + if (fdso.count >= 32768) goto dogk; + + /* Might need to emulate applying the amplitude to the waveform a bit better... */ + { + int k = amplitude[0]; + if (k > 0x20) k = 0x20; + return (fdso.cwave[b24latch68 >> 19] * k) * 4 / ((SPSG[0x9] & 0x3) + 2); + } +} + +static int32 FBC = 0; + +static void RenderSound(void) { + int32 end, start; + int32 x; + + start = FBC; + end = (SOUNDTS << 16) / soundtsinc; + if (end <= start) + return; + FBC = end; + + if (!(SPSG[0x9] & 0x80)) + for (x = start; x < end; x++) { + uint32 t = FDSDoSound(); + t += t >> 1; + t >>= 4; + Wave[x >> 4] += t; /* (t>>2)-(t>>3); */ /* >>3; */ + } +} + +static void RenderSoundHQ(void) { + uint32 x; + + if (!(SPSG[0x9] & 0x80)) + for (x = FBC; x < SOUNDTS; x++) { + uint32 t = FDSDoSound(); + t += t >> 1; + WaveHi[x] += t; /* (t<<2)-(t<<1); */ + } + FBC = SOUNDTS; +} + +static void HQSync(int32 ts) { + FBC = ts; +} + +void FDSSound(int c) { + RenderSound(); + FBC = c; +} + +static void FDS_ESI(void) { + if (FSettings.SndRate) { + if (FSettings.soundq >= 1) { + fdso.cycles = (int64)1 << 39; + } else { + fdso.cycles = ((int64)1 << 40) * FDSClock; + fdso.cycles /= FSettings.SndRate * 16; + } + } + SetReadHandler(0x4040, 0x407f, FDSWaveRead); + SetWriteHandler(0x4040, 0x407f, FDSWaveWrite); + SetWriteHandler(0x4080, 0x408A, FDSSWrite); + SetReadHandler(0x4090, 0x4092, FDSSRead); +} + +void FDSSoundReset(void) { + memset(&fdso, 0, sizeof(fdso)); + FDS_ESI(); + GameExpSound.HiSync = HQSync; + GameExpSound.HiFill = RenderSoundHQ; + GameExpSound.Fill = FDSSound; + GameExpSound.RChange = FDS_ESI; +} + +DECLFR(FDSSoundRead) { + if (A >= 0x4040 && A < 0x4080) return FDSWaveRead(A); + if (A >= 0x4090 && A < 0x4093) return FDSSRead(A); + return X.DB; +} + +DECLFW(FDSSoundWrite) { + if (A >= 0x4040 && A < 0x4080) FDSWaveWrite(A, V); + else if (A >= 0x4080 && A < 0x408B) FDSSWrite(A, V); +} + +void FDSSoundPower(void) { + FDSSoundReset(); + FDSSoundStateAdd(); +} \ No newline at end of file diff --git a/src/fds_apu.h b/src/fds_apu.h new file mode 100644 index 0000000..0aac02c --- /dev/null +++ b/src/fds_apu.h @@ -0,0 +1,12 @@ +#ifndef FDS_APU_H +#define FDS_APU_H + +void FDSSoundReset(void); +void FDSSoundStateAdd(void); + +/* Used for fds conversion-based mappers to allow access to fds apu registers */ +void FDSSoundPower(void); +DECLFR(FDSSoundRead); /* $4040-$407F, $4090-$4092 */ +DECLFW(FDSSoundWrite); /* $4040-$407F, $4080-$408A */ + +#endif /* FDS_APU_H */ \ No newline at end of file diff --git a/src/nsf.c b/src/nsf.c index 38b385e..a18c694 100644 --- a/src/nsf.c +++ b/src/nsf.c @@ -33,6 +33,7 @@ #include "fceu-memory.h" #include "file.h" #include "fds.h" +#include "fds_apu.h" #include "cart.h" #include "input.h"