diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj
index 12dd2899..30bd4148 100644
--- a/Core/Core.vcxproj
+++ b/Core/Core.vcxproj
@@ -558,6 +558,7 @@
+
@@ -1000,6 +1001,7 @@
+
diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters
index 59589989..dc4fa6b9 100644
--- a/Core/Core.vcxproj.filters
+++ b/Core/Core.vcxproj.filters
@@ -1517,6 +1517,9 @@
Nes\Mappers\VRC
+
+ Nes\Mappers\EPSG
+
@@ -1825,5 +1828,8 @@
Nes\Mappers\VRC
+
+ Nes\Mappers\EPSG
+
\ No newline at end of file
diff --git a/Core/EPSGAudio.h b/Core/EPSGAudio.h
index d8079ff7..bf15af3e 100644
--- a/Core/EPSGAudio.h
+++ b/Core/EPSGAudio.h
@@ -18,6 +18,8 @@ private:
int16_t _lastOutputs[2];
int16_t _currentOutputs[2];
+ uint8_t writeValue;
+ int16_t writeAddr;
double _clock;
@@ -150,6 +152,32 @@ public:
{
EPSGSSGAudio::WriteRegister(addr, value);
+ if (addr == 0x4016) {
+ if ((value & 0x0F) == 0x02) {
+ writeValue = value;
+ writeAddr = 0xC000;
+ }
+ if ((value & 0x0F) == 0x0A) {
+ writeValue = value;
+ writeAddr = 0xE000;
+ }
+ if ((value & 0x0F) == 0x06) {
+ writeValue = value;
+ writeAddr = 0xC002;
+ }
+ if ((value & 0x0F) == 0x0E) {
+ writeValue = value;
+ writeAddr = 0xE002;
+ }
+ if ((value & 0x0F) == 0x00) {
+ writeValue = (writeValue & 0xF0) | (value >> 4);
+
+ const uint8_t a04016 = (writeAddr & 0xF000) == 0xE000;
+ const uint8_t a14016 = !!(writeAddr & 0xF);
+ WriteToChip(a04016 | (a14016 << 1), writeValue);
+ }
+ }
+
switch(addr) {
case 0xC000:
case 0xE000:
diff --git a/Core/MMC3.h b/Core/MMC3.h
index ab1e43ad..6fec697a 100644
--- a/Core/MMC3.h
+++ b/Core/MMC3.h
@@ -285,6 +285,11 @@ public:
_audio->WriteRegister(addr, value);
break;
}
+ switch (addr & 0x4016) {
+ case 0x4016:
+ _audio->WriteRegister(addr, value);
+ break;
+ }
}
virtual void TriggerIrq()
diff --git a/Core/emu2149.cpp b/Core/emu2149.cpp
new file mode 100644
index 00000000..41641c79
--- /dev/null
+++ b/Core/emu2149.cpp
@@ -0,0 +1,375 @@
+/****************************************************************************
+
+ emu2149.c -- YM2149/AY-3-8910 emulator by Mitsutaka Okazaki 2001-2016
+
+ 2001 04-28 : Version 1.00beta -- 1st Beta Release.
+ 2001 08-14 : Version 1.10
+ 2001 10-03 : Version 1.11 -- Added PSG_set_quality().
+ 2002 03-02 : Version 1.12 -- Removed PSG_init & PSG_close.
+ 2002 10-13 : Version 1.14 -- Fixed the envelope unit.
+ 2003 09-19 : Version 1.15 -- Added PSG_setMask and PSG_toggleMask
+ 2004 01-11 : Version 1.16 -- Fixed the envelope problem where the envelope
+ frequency register is written before key-on.
+ 2015 12-13 : Version 1.17 -- Changed own integer types to C99 stdint.h types.
+ 2016 09-06 : Version 1.20 -- Support per-channel output.
+
+ References:
+ psg.vhd -- 2000 written by Kazuhiro Tsujikawa.
+ s_fme7.c -- 1999,2000 written by Mamiya (NEZplug).
+ ay8910.c -- 1998-2001 Author unknown (MAME).
+ MSX-Datapack -- 1991 ASCII Corp.
+ AY-3-8910 data sheet
+
+*****************************************************************************/
+#include "stdafx.h"
+#include
+#include
+#include
+#include "emu2149.h"
+
+static uint32_t voltbl[2][32] = {
+ {0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x07, 0x09,
+ 0x0B, 0x0D, 0x0F, 0x12,
+ 0x16, 0x1A, 0x1F, 0x25, 0x2D, 0x35, 0x3F, 0x4C, 0x5A, 0x6A, 0x7F, 0x97,
+ 0xB4, 0xD6, 0xFF, 0xFF},
+ {0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x05, 0x05, 0x07, 0x07,
+ 0x0B, 0x0B, 0x0F, 0x0F,
+ 0x16, 0x16, 0x1F, 0x1F, 0x2D, 0x2D, 0x3F, 0x3F, 0x5A, 0x5A, 0x7F, 0x7F,
+ 0xB4, 0xB4, 0xFF, 0xFF}
+};
+
+static uint8_t regmsk[16] = {
+ 0xff, 0x0f, 0xff, 0x0f, 0xff, 0x0f, 0x1f, 0x3f,
+ 0x1f, 0x1f, 0x1f, 0xff, 0xff, 0x0f, 0xff, 0xff
+};
+
+#define GETA_BITS 24
+
+static void
+internal_refresh (PSG * psg)
+{
+ if (psg->quality)
+ {
+ psg->base_incr = 1 << GETA_BITS;
+ psg->realstep = (uint32_t) ((1 << 31) / psg->rate);
+ psg->psgstep = (uint32_t) ((1 << 31) / (psg->clk / 16));
+ psg->psgtime = 0;
+ }
+ else
+ {
+ psg->base_incr =
+ (uint32_t) ((double) psg->clk * (1 << GETA_BITS) / (16 * psg->rate));
+ }
+}
+
+void
+PSG_set_rate (PSG * psg, uint32_t r)
+{
+ psg->rate = r ? r : 44100;
+ internal_refresh (psg);
+}
+
+void
+PSG_set_quality (PSG * psg, uint32_t q)
+{
+ psg->quality = q;
+ internal_refresh (psg);
+}
+
+PSG *
+PSG_new (uint32_t c, uint32_t r)
+{
+ PSG *psg;
+
+ psg = (PSG *) malloc (sizeof (PSG));
+ if (psg == NULL)
+ return NULL;
+
+ PSG_setVolumeMode (psg, EMU2149_VOL_DEFAULT);
+ psg->clk = c;
+ psg->rate = r ? r : 44100;
+ PSG_set_quality (psg, 0);
+
+ return psg;
+}
+
+void
+PSG_setVolumeMode (PSG * psg, int type)
+{
+ switch (type)
+ {
+ case 1:
+ psg->voltbl = voltbl[EMU2149_VOL_YM2149];
+ break;
+ case 2:
+ psg->voltbl = voltbl[EMU2149_VOL_AY_3_8910];
+ break;
+ default:
+ psg->voltbl = voltbl[EMU2149_VOL_DEFAULT];
+ break;
+ }
+}
+
+uint32_t
+PSG_setMask (PSG *psg, uint32_t mask)
+{
+ uint32_t ret = 0;
+ if(psg)
+ {
+ ret = psg->mask;
+ psg->mask = mask;
+ }
+ return ret;
+}
+
+uint32_t
+PSG_toggleMask (PSG *psg, uint32_t mask)
+{
+ uint32_t ret = 0;
+ if(psg)
+ {
+ ret = psg->mask;
+ psg->mask ^= mask;
+ }
+ return ret;
+}
+
+void
+PSG_reset (PSG * psg)
+{
+ int i;
+
+ psg->base_count = 0;
+
+ for (i = 0; i < 3; i++)
+ {
+ psg->count[i] = 0x1000;
+ psg->freq[i] = 0;
+ psg->edge[i] = 0;
+ psg->volume[i] = 0;
+ psg->ch_out[i] = 0;
+ }
+
+ psg->mask = 0;
+
+ for (i = 0; i < 16; i++)
+ psg->reg[i] = 0;
+ psg->adr = 0;
+
+ psg->noise_seed = 0xffff;
+ psg->noise_count = 0x40;
+ psg->noise_freq = 0;
+
+ psg->env_volume = 0;
+ psg->env_ptr = 0;
+ psg->env_freq = 0;
+ psg->env_count = 0;
+ psg->env_pause = 1;
+
+ psg->out = 0;
+
+}
+
+void
+PSG_delete (PSG * psg)
+{
+ free (psg);
+}
+
+uint8_t
+PSG_readIO (PSG * psg)
+{
+ return (uint8_t) (psg->reg[psg->adr]);
+}
+
+uint8_t
+PSG_readReg (PSG * psg, uint32_t reg)
+{
+ return (uint8_t) (psg->reg[reg & 0x1f]);
+
+}
+
+void
+PSG_writeIO (PSG * psg, uint32_t adr, uint32_t val)
+{
+ if (adr & 1)
+ PSG_writeReg (psg, psg->adr, val);
+ else
+ psg->adr = val & 0x1f;
+}
+
+static inline void
+update_output (PSG * psg)
+{
+
+ int i, noise;
+ uint32_t incr;
+
+ psg->base_count += psg->base_incr;
+ incr = (psg->base_count >> GETA_BITS);
+ psg->base_count &= (1 << GETA_BITS) - 1;
+
+ /* Envelope */
+ psg->env_count += incr;
+ while (psg->env_count>=0x10000 && psg->env_freq!=0)
+ {
+ if (!psg->env_pause)
+ {
+ if(psg->env_face)
+ psg->env_ptr = (psg->env_ptr + 1) & 0x3f ;
+ else
+ psg->env_ptr = (psg->env_ptr + 0x3f) & 0x3f;
+ }
+
+ if (psg->env_ptr & 0x20) /* if carry or borrow */
+ {
+ if (psg->env_continue)
+ {
+ if (psg->env_alternate^psg->env_hold) psg->env_face ^= 1;
+ if (psg->env_hold) psg->env_pause = 1;
+ psg->env_ptr = psg->env_face?0:0x1f;
+ }
+ else
+ {
+ psg->env_pause = 1;
+ psg->env_ptr = 0;
+ }
+ }
+
+ psg->env_count -= psg->env_freq;
+ }
+
+ /* Noise */
+ psg->noise_count += incr;
+ if (psg->noise_count & 0x40)
+ {
+ if (psg->noise_seed & 1)
+ psg->noise_seed ^= 0x24000;
+ psg->noise_seed >>= 1;
+ psg->noise_count -= psg->noise_freq?psg->noise_freq:(1<<1);
+ }
+ noise = psg->noise_seed & 1;
+
+ /* Tone */
+ for (i = 0; i < 3; i++)
+ {
+ psg->count[i] += incr;
+ if (psg->count[i] & 0x1000)
+ {
+ if (psg->freq[i] > 1)
+ {
+ psg->edge[i] = !psg->edge[i];
+ psg->count[i] -= psg->freq[i];
+ }
+ else
+ {
+ psg->edge[i] = 1;
+ }
+ }
+
+ if (psg->mask&PSG_MASK_CH(i))
+ continue;
+
+ if ((psg->tmask[i]||psg->edge[i]) && (psg->nmask[i]||noise))
+ {
+ if (!(psg->volume[i] & 32))
+ psg->ch_out[i] += (psg->voltbl[psg->volume[i] & 31] << 4);
+ else
+ psg->ch_out[i] += (psg->voltbl[psg->env_ptr] << 4);
+ }
+
+ psg->ch_out[i] >>= 1;
+
+ }
+
+}
+
+static inline int16_t
+mix_output(PSG *psg) {
+ return (int16_t)(psg->out = psg->ch_out[0] + psg->ch_out[1] + psg->ch_out[2]);
+}
+
+int16_t
+PSG_calc (PSG * psg)
+{
+ if (!psg->quality) {
+ update_output(psg);
+ return mix_output(psg);
+ }
+
+ /* Simple rate converter */
+ while (psg->realstep > psg->psgtime)
+ {
+ psg->psgtime += psg->psgstep;
+ update_output(psg);
+ }
+ psg->psgtime = psg->psgtime - psg->realstep;
+
+ return mix_output(psg);
+}
+
+void
+PSG_writeReg (PSG * psg, uint32_t reg, uint32_t val)
+{
+ int c;
+
+ if (reg > 15) return;
+
+ val &= regmsk[reg];
+
+ psg->reg[reg] = (uint8_t) (val & 0xff);
+ switch (reg)
+ {
+ case 0:
+ case 2:
+ case 4:
+ case 1:
+ case 3:
+ case 5:
+ c = reg >> 1;
+ psg->freq[c] = ((psg->reg[c * 2 + 1] & 15) << 8) + psg->reg[c * 2];
+ break;
+
+ case 6:
+ psg->noise_freq = (val & 31) << 1;
+ break;
+
+ case 7:
+ psg->tmask[0] = (val & 1);
+ psg->tmask[1] = (val & 2);
+ psg->tmask[2] = (val & 4);
+ psg->nmask[0] = (val & 8);
+ psg->nmask[1] = (val & 16);
+ psg->nmask[2] = (val & 32);
+ break;
+
+ case 8:
+ case 9:
+ case 10:
+ psg->volume[reg - 8] = val << 1;
+ break;
+
+ case 11:
+ case 12:
+ psg->env_freq = (psg->reg[12] << 8) + psg->reg[11];
+ break;
+
+ case 13:
+ psg->env_continue = (val >> 3) & 1;
+ psg->env_attack = (val >> 2) & 1;
+ psg->env_alternate = (val >> 1) & 1;
+ psg->env_hold = val & 1;
+ psg->env_face = psg->env_attack;
+ psg->env_pause = 0;
+ psg->env_count = 0x10000 - psg->env_freq;
+ psg->env_ptr = psg->env_face?0:0x1f;
+ break;
+
+ case 14:
+ case 15:
+ default:
+ break;
+ }
+
+ return;
+}
\ No newline at end of file
diff --git a/Core/emu2149.h b/Core/emu2149.h
new file mode 100644
index 00000000..538edf75
--- /dev/null
+++ b/Core/emu2149.h
@@ -0,0 +1,88 @@
+/* emu2149.h */
+#ifndef _EMU2149_H_
+#define _EMU2149_H_
+
+#include
+
+#define EMU2149_VOL_DEFAULT 1
+#define EMU2149_VOL_YM2149 0
+#define EMU2149_VOL_AY_3_8910 1
+
+#define PSG_MASK_CH(x) (1<<(x))
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ typedef struct __PSG
+ {
+
+ /* Volume Table */
+ uint32_t *voltbl;
+
+ uint8_t reg[0x20];
+ int32_t out;
+
+ uint32_t clk, rate, base_incr, quality;
+
+ uint32_t count[3];
+ uint32_t volume[3];
+ uint32_t freq[3];
+ uint32_t edge[3];
+ uint32_t tmask[3];
+ uint32_t nmask[3];
+ uint32_t mask;
+
+ uint32_t base_count;
+
+ uint32_t env_volume;
+ uint32_t env_ptr;
+ uint32_t env_face;
+
+ uint32_t env_continue;
+ uint32_t env_attack;
+ uint32_t env_alternate;
+ uint32_t env_hold;
+ uint32_t env_pause;
+ uint32_t env_reset;
+
+ uint32_t env_freq;
+ uint32_t env_count;
+
+ uint32_t noise_seed;
+ uint32_t noise_count;
+ uint32_t noise_freq;
+
+ /* rate converter */
+ uint32_t realstep;
+ uint32_t psgtime;
+ uint32_t psgstep;
+
+ /* I/O Ctrl */
+ uint32_t adr;
+
+ /* output of channels */
+ int16_t ch_out[3];
+
+ } PSG;
+
+ void PSG_set_quality (PSG * psg, uint32_t q);
+ void PSG_set_rate (PSG * psg, uint32_t r);
+ PSG *PSG_new (uint32_t clk, uint32_t rate);
+ void PSG_reset (PSG *);
+ void PSG_delete (PSG *);
+ void PSG_writeReg (PSG *, uint32_t reg, uint32_t val);
+ void PSG_writeIO (PSG * psg, uint32_t adr, uint32_t val);
+ uint8_t PSG_readReg (PSG * psg, uint32_t reg);
+ uint8_t PSG_readIO (PSG * psg);
+ int16_t PSG_calc (PSG *);
+ void PSG_setVolumeMode (PSG * psg, int type);
+ uint32_t PSG_setMask (PSG *, uint32_t mask);
+ uint32_t PSG_toggleMask (PSG *, uint32_t mask);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif