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