From aa966a546651d7033910f06e3b3c325af9cc5ea9 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 29 Apr 2024 15:21:58 -0500 Subject: [PATCH] AtomicSSG AY core --- src/engine/dispatchContainer.cpp | 5 + src/engine/platform/ay.cpp | 61 +++++++- src/engine/platform/ay.h | 12 +- src/engine/platform/sound/atomicssg/ssg.c | 166 ++++++++++++---------- src/engine/platform/sound/atomicssg/ssg.h | 12 +- src/gui/gui.h | 4 + src/gui/settings.cpp | 23 +++ 7 files changed, 202 insertions(+), 81 deletions(-) diff --git a/src/engine/dispatchContainer.cpp b/src/engine/dispatchContainer.cpp index 2d5b2d47b..65ca2383d 100644 --- a/src/engine/dispatchContainer.cpp +++ b/src/engine/dispatchContainer.cpp @@ -393,6 +393,11 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do break; case DIV_SYSTEM_AY8910: dispatch=new DivPlatformAY8910; + if (isRender) { + ((DivPlatformAY8910*)dispatch)->setCore(eng->getConfInt("ayCoreRender",0)==1); + } else { + ((DivPlatformAY8910*)dispatch)->setCore(eng->getConfInt("ayCore",0)==1); + } break; case DIV_SYSTEM_AY8930: dispatch=new DivPlatformAY8930; diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index c97889dcb..015aa3306 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -169,7 +169,7 @@ void DivPlatformAY8910::checkWrites() { } } -void DivPlatformAY8910::acquire(short** buf, size_t len) { +void DivPlatformAY8910::acquire_mame(short** buf, size_t len) { if (ayBufLen>8); + buf[1][i]=((ay_atomic.o_analog[0]*stereoSep)>>8)+ay_atomic.o_analog[1]+ay_atomic.o_analog[2]; + } else { + buf[0][i]=ay_atomic.o_analog[0]+ay_atomic.o_analog[1]+ay_atomic.o_analog[2]; + buf[1][i]=buf[0][i]; + } + + oscBuf[0]->data[oscBuf[0]->needle++]=ay_atomic.o_analog[0]; + oscBuf[1]->data[oscBuf[1]->needle++]=ay_atomic.o_analog[1]; + oscBuf[2]->data[oscBuf[2]->needle++]=ay_atomic.o_analog[2]; + } +} + +void DivPlatformAY8910::acquire(short** buf, size_t len) { + if (selCore) { + acquire_atomic(buf,len); + } else { + acquire_mame(buf,len); + } +} + void DivPlatformAY8910::updateOutSel(bool immediate) { if (immediate) { immWrite(0x07, @@ -778,6 +814,12 @@ void DivPlatformAY8910::reset() { addWrite(0xffffffff,0); } + SSG_Reset(&ay_atomic); + SSG_SetType(&ay_atomic, + (yamaha?0:1)| + (intellivision?2:0) + ); + for (int i=0; i<16; i++) { oldWrites[i]=-1; pendingWrites[i]=-1; @@ -830,6 +872,10 @@ void DivPlatformAY8910::setExtClockDiv(unsigned int eclk, unsigned char ediv) { } } +void DivPlatformAY8910::setCore(unsigned char core) { + selCore=core; +} + void DivPlatformAY8910::setFlags(const DivConfig& flags) { if (extMode) { chipClock=extClock; @@ -888,8 +934,13 @@ void DivPlatformAY8910::setFlags(const DivConfig& flags) { break; } CHECK_CUSTOM_CLOCK; - rate=chipClock/8; - dacRate=rate; + if (selCore) { + rate=chipClock/2; + dacRate=chipClock*2; + } else { + rate=chipClock/8; + dacRate=rate; + } } for (int i=0; i<3; i++) { oscBuf[i]->rate=rate; @@ -900,23 +951,27 @@ void DivPlatformAY8910::setFlags(const DivConfig& flags) { case 1: clockSel=flags.getBool("halfClock",false); ay=new ym2149_device(rate,clockSel); + yamaha=true; sunsoft=false; intellivision=false; break; case 2: ay=new sunsoft_5b_sound_device(rate); + yamaha=true; sunsoft=true; intellivision=false; clockSel=false; break; case 3: ay=new ay8914_device(rate); + yamaha=false; sunsoft=false; intellivision=true; clockSel=false; break; default: ay=new ay8910_device(rate); + yamaha=false; sunsoft=false; intellivision=false; clockSel=false; diff --git a/src/engine/platform/ay.h b/src/engine/platform/ay.h index a64efbd0f..ea37a5cba 100644 --- a/src/engine/platform/ay.h +++ b/src/engine/platform/ay.h @@ -22,6 +22,9 @@ #include "../dispatch.h" #include "../../fixedQueue.h" #include "sound/ay8910.h" +extern "C" { +#include "sound/atomicssg/ssg.h" +} class DivPlatformAY8910: public DivDispatch { protected: @@ -97,6 +100,9 @@ class DivPlatformAY8910: public DivDispatch { unsigned char sampleBank; unsigned char stereoSep; + unsigned char selCore; + + ssg_t ay_atomic; int delay; @@ -106,7 +112,7 @@ class DivPlatformAY8910: public DivDispatch { unsigned char extDiv; unsigned char dacRateDiv; - bool stereo, sunsoft, intellivision, clockSel; + bool stereo, sunsoft, intellivision, clockSel, yamaha; bool ioPortA, ioPortB; unsigned char portAVal, portBVal; @@ -121,6 +127,9 @@ class DivPlatformAY8910: public DivDispatch { void checkWrites(); void updateOutSel(bool immediate=false); + + void acquire_mame(short** buf, size_t len); + void acquire_atomic(short** buf, size_t len); friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); @@ -135,6 +144,7 @@ class DivPlatformAY8910: public DivDispatch { int mapVelocity(int ch, float vel); unsigned char* getRegisterPool(); int getRegisterPoolSize(); + void setCore(unsigned char core); void flushWrites(); void reset(); void forceIns(); diff --git a/src/engine/platform/sound/atomicssg/ssg.c b/src/engine/platform/sound/atomicssg/ssg.c index 071ff85e8..f008b9165 100644 --- a/src/engine/platform/sound/atomicssg/ssg.c +++ b/src/engine/platform/sound/atomicssg/ssg.c @@ -34,76 +34,19 @@ void SSG_Clock(ssg_t* chip, int clk) { int read = !chip->ic && !chip->input.rd && !chip->input.cs; - chip->read0 = !chip->ic && !chip->input.rd && !chip->input.cs && !chip->input.a1 && !chip->input.a0; + chip->read0 = !chip->ic && !chip->input.rd && !chip->input.cs; int write = !chip->input.wr && !chip->input.cs; - int writeaddr = chip->ic || (!chip->input.wr && !chip->input.cs && !chip->input.a0); - int writedata = !chip->ic && !chip->input.wr && !chip->input.cs && chip->input.a0; - int read1 = !chip->ic && !chip->input.rd && !chip->input.cs && !chip->input.a1 && chip->input.a0; - chip->read2 = !chip->ic && !chip->input.rd && !chip->input.cs && chip->input.a1 && !chip->input.a0; - chip->read3 = !chip->ic && !chip->input.rd && !chip->input.cs && chip->input.a1 && chip->input.a0; - chip->write2 = !chip->ic && !chip->input.wr && !chip->input.cs && chip->input.a1 && !chip->input.a0; - chip->write3 = !chip->ic && !chip->input.wr && !chip->input.cs && chip->input.a1 && chip->input.a0; - chip->ssg_write0 = writeaddr && !chip->input.a1; - chip->ssg_write1 = (writedata && !chip->input.a1) || chip->ic; + int writeaddr = chip->ic || (!chip->input.wr && !chip->input.cs); + int writedata = !chip->ic && !chip->input.wr && !chip->input.cs; + int read1 = !chip->ic && !chip->input.rd && !chip->input.cs; + chip->ssg_write0 = writeaddr; + chip->ssg_write1 = writedata || chip->ic; chip->ssg_read1 = read1; chip->o_data_d = !read; - if (writeaddr) - chip->write0_trig0 = 1; - else if (chip->write0_l[0]) - chip->write0_trig0 = 0; - if (chip->clk1) - { - chip->write0_trig1 = chip->write0_trig0; - chip->write0_l[1] = chip->write0_l[0]; - } - if (chip->clk2) - { - chip->write0_l[0] = chip->write0_trig1; - chip->write0_l[2] = chip->write0_l[1]; - } - chip->write0_en = chip->write0_l[0] && !chip->write0_l[2]; - - if (writedata) - chip->write1_trig0 = 1; - else if (chip->write1_l[0]) - chip->write1_trig0 = 0; - if (chip->clk1) - { - chip->write1_trig1 = chip->write1_trig0; - chip->write1_l[1] = chip->write1_l[0]; - } - if (chip->clk2) - { - chip->write1_l[0] = chip->write1_trig1; - chip->write1_l[2] = chip->write1_l[1]; - } - chip->write1_en = chip->write1_l[0] && !chip->write1_l[2]; - - if (writeaddr) - chip->write2_trig0 = 1; - else if (chip->write2_l[0]) - chip->write2_trig0 = 0; - if (chip->clk1) - { - chip->write2_trig1 = chip->write2_trig0; - chip->write2_l[1] = chip->write2_l[0]; - } - if (chip->clk2) - { - chip->write2_l[0] = chip->write2_trig1; - chip->write2_l[2] = chip->write2_l[1]; - } - chip->write2_en = chip->write2_l[0] && !chip->write2_l[2]; - - if (writedata) - chip->write3_trig0 = 1; - else if (chip->write3_l[0]) - chip->write3_trig0 = 0; - if (write) - chip->data_l = (chip->input.data & 255) | (chip->input.a1 << 8); + chip->data_l = (chip->input.data & 255); if (chip->ic) chip->data_bus2 |= 0x2f; @@ -128,12 +71,12 @@ void SSG_Clock(ssg_t* chip, int clk) if (chip->ic) chip->ssg_ssg_addr = 0; else if (chip->ssg_write0) - chip->ssg_ssg_addr = (chip->data_bus1 & 0xf0) == 0; + chip->ssg_ssg_addr = 1; if (chip->ic) chip->ssg_address = 0; - else if (chip->ssg_write0 && (chip->data_bus1 & 0xe0) == 0) - chip->ssg_address = chip->data_bus1 & 0x1f; + else if (chip->ssg_write0) + chip->ssg_address = chip->input.a0 & 0x1f; int ssg_access = chip->ssg_ssg_addr && (chip->ssg_write1 || chip->ssg_read1); @@ -443,26 +386,99 @@ void SSG_Clock(ssg_t* chip, int clk) int sign_b = ((chip->ssg_mode & 2) == 0 && (chip->ssg_sign[0] & 2) != 0) || ((chip->ssg_mode & 16) == 0 && chip->ssg_noise_bit); int sign_c = ((chip->ssg_mode & 4) == 0 && (chip->ssg_sign[0] & 4) != 0) || ((chip->ssg_mode & 32) == 0 && chip->ssg_noise_bit); - static const float volume_lut[32] = { + static const float volume_lut_ay[32] = { + 0.0000, + 0.0000, + 0.0106, + 0.0106, + 0.0150, + 0.0150, + 0.0222, + 0.0222, + 0.0320, + 0.0320, + 0.0466, + 0.0466, + 0.0665, + 0.0665, + 0.1039, + 0.1039, + 0.1237, + 0.1237, + 0.1986, + 0.1986, + 0.2803, + 0.2803, + 0.3548, + 0.3548, + 0.4702, + 0.4702, + 0.6030, + 0.6030, + 0.7530, + 0.7530, + 0.9250, + 0.9250 + }; + + static const float volume_lut_ssg[32] = { 0.0000, 0.0000, 0.0049, 0.0075, 0.0105, 0.0131, 0.0156, 0.0183, 0.0228, 0.0276, 0.0321, 0.0367, 0.0448, 0.0535, 0.0626, 0.0713, 0.0884, 0.1057, 0.1225, 0.1392, 0.1691, 0.2013, 0.2348, 0.2670, 0.3307, 0.3951, 0.4573, 0.5196, 0.6316, 0.7528, 0.8787, 1.0000 }; - - chip->o_analog[0] = volume_lut[sign_a ? 0 : vol_a]; - chip->o_analog[1] = volume_lut[sign_b ? 0 : vol_b]; - chip->o_analog[2] = volume_lut[sign_c ? 0 : vol_c]; + if (chip->type & 1) { + chip->o_analog[0] = volume_lut_ay[sign_a ? 0 : vol_a] * 11806; + chip->o_analog[1] = volume_lut_ay[sign_b ? 0 : vol_b] * 11806; + chip->o_analog[2] = volume_lut_ay[sign_c ? 0 : vol_c] * 11806; + } else { + chip->o_analog[0] = volume_lut_ssg[sign_a ? 0 : vol_a] * 10922; + chip->o_analog[1] = volume_lut_ssg[sign_b ? 0 : vol_b] * 10922; + chip->o_analog[2] = volume_lut_ssg[sign_c ? 0 : vol_c] * 10922; + } } { chip->read_bus = 0; // FIXME - if (chip->ssg_read1 - || chip->read3 - ) + if (chip->ssg_read1) chip->read_bus = chip->data_bus1 & 255; chip->o_data = chip->read_bus; } + + if (clk) + chip->input.cs=1; +} + +void SSG_Reset(ssg_t* chip) { + memset(chip,0,sizeof(ssg_t)); + + chip->input.test=1; + chip->input.ic=1; + SSG_Clock(chip,0); + SSG_Clock(chip,1); + + chip->input.ic=0; + SSG_Clock(chip,0); + SSG_Clock(chip,1); + + chip->input.ic=1; + SSG_Clock(chip,0); + SSG_Clock(chip,1); + + chip->input.cs=1; +} + +void SSG_Write(ssg_t* chip, unsigned char addr, unsigned char val) { + chip->input.cs=0; + chip->input.rd=1; + chip->input.wr=0; + + chip->input.a0=addr; + chip->input.data=val; +} + +void SSG_SetType(ssg_t* chip, int type) { + chip->type=type; } diff --git a/src/engine/platform/sound/atomicssg/ssg.h b/src/engine/platform/sound/atomicssg/ssg.h index 2c205c8ff..4267e148b 100644 --- a/src/engine/platform/sound/atomicssg/ssg.h +++ b/src/engine/platform/sound/atomicssg/ssg.h @@ -25,7 +25,6 @@ typedef struct { int wr; // neg int rd; // neg int a0; - int a1; int data; int test; // set to 1 int gpio_a; @@ -36,6 +35,12 @@ ssg_input_t; typedef struct { ssg_input_t input; + // bitfield + // bit 0: AY-3-8910 (16-step envelope) + // bit 1: AY-3-8914 (different register map and envelope volume) + // bit 2: AY8930 (TODO) + int type; + int ic; int ic_latch1[2]; @@ -143,11 +148,14 @@ typedef struct { int o_gpio_b; int o_gpio_b_d; - float o_analog[3]; + int o_analog[3]; int o_data; int o_data_d; } ssg_t; +void SSG_SetType(ssg_t* chip, int type); +void SSG_Reset(ssg_t* chip); void SSG_Clock(ssg_t* chip, int clk); +void SSG_Write(ssg_t* chip, unsigned char addr, unsigned char val); diff --git a/src/gui/gui.h b/src/gui/gui.h index f6580ed03..e4c786de7 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1667,6 +1667,7 @@ class FurnaceGUI { int opl3Core; int esfmCore; int opllCore; + int ayCore; int bubsysQuality; int dsidQuality; int gbQuality; @@ -1692,6 +1693,7 @@ class FurnaceGUI { int opl3CoreRender; int esfmCoreRender; int opllCoreRender; + int ayCoreRender; int bubsysQualityRender; int dsidQualityRender; int gbQualityRender; @@ -1911,6 +1913,7 @@ class FurnaceGUI { opl3Core(0), esfmCore(0), opllCore(0), + ayCore(0), bubsysQuality(3), dsidQuality(3), gbQuality(3), @@ -1936,6 +1939,7 @@ class FurnaceGUI { opl3CoreRender(0), esfmCoreRender(0), opllCoreRender(0), + ayCoreRender(0), bubsysQualityRender(3), dsidQualityRender(3), gbQualityRender(3), diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 47439b125..03d9b2e81 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -180,6 +180,11 @@ const char* opllCores[]={ "emu2413" }; +const char* ayCores[]={ + "MAME", + "AtomicSSG" +}; + const char* coreQualities[]={ "Lower", "Low", @@ -1781,6 +1786,17 @@ void FurnaceGUI::drawSettings() { ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::Combo("##OPLLCoreRender",&settings.opllCoreRender,opllCores,2)) settingsChanged=true; + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::AlignTextToFramePadding(); + ImGui::Text("AY-3-8910/SSG"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::Combo("##AYCore",&settings.ayCore,ayCores,2)) settingsChanged=true; + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::Combo("##AYCoreRender",&settings.ayCoreRender,ayCores,2)) settingsChanged=true; + ImGui::EndTable(); } @@ -4376,6 +4392,7 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) { settings.opl3Core=conf.getInt("opl3Core",0); settings.esfmCore=conf.getInt("esfmCore",0); settings.opllCore=conf.getInt("opllCore",0); + settings.ayCore=conf.getInt("ayCore",0); settings.bubsysQuality=conf.getInt("bubsysQuality",3); settings.dsidQuality=conf.getInt("dsidQuality",3); @@ -4403,6 +4420,7 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) { settings.opl3CoreRender=conf.getInt("opl3CoreRender",0); settings.esfmCoreRender=conf.getInt("esfmCoreRender",0); settings.opllCoreRender=conf.getInt("opllCoreRender",0); + settings.ayCoreRender=conf.getInt("ayCoreRender",0); settings.bubsysQualityRender=conf.getInt("bubsysQualityRender",3); settings.dsidQualityRender=conf.getInt("dsidQualityRender",3); @@ -4447,6 +4465,7 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) { clampSetting(settings.opl3Core,0,2); clampSetting(settings.esfmCore,0,1); clampSetting(settings.opllCore,0,1); + clampSetting(settings.ayCore,0,1); clampSetting(settings.bubsysQuality,0,5); clampSetting(settings.dsidQuality,0,5); clampSetting(settings.gbQuality,0,5); @@ -4472,6 +4491,7 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) { clampSetting(settings.opl3CoreRender,0,2); clampSetting(settings.esfmCoreRender,0,1); clampSetting(settings.opllCoreRender,0,1); + clampSetting(settings.ayCoreRender,0,1); clampSetting(settings.bubsysQualityRender,0,5); clampSetting(settings.dsidQualityRender,0,5); clampSetting(settings.gbQualityRender,0,5); @@ -4931,6 +4951,7 @@ void FurnaceGUI::writeConfig(DivConfig& conf, FurnaceGUISettingGroups groups) { conf.set("opl3Core",settings.opl3Core); conf.set("esfmCore",settings.esfmCore); conf.set("opllCore",settings.opllCore); + conf.set("ayCore",settings.ayCore); conf.set("bubsysQuality",settings.bubsysQuality); conf.set("dsidQuality",settings.dsidQuality); @@ -4958,6 +4979,7 @@ void FurnaceGUI::writeConfig(DivConfig& conf, FurnaceGUISettingGroups groups) { conf.set("opl3CoreRender",settings.opl3CoreRender); conf.set("esfmCoreRender",settings.esfmCoreRender); conf.set("opllCoreRender",settings.opllCoreRender); + conf.set("ayCoreRender",settings.ayCoreRender); conf.set("bubsysQualityRender",settings.bubsysQualityRender); conf.set("dsidQualityRender",settings.dsidQualityRender); @@ -5018,6 +5040,7 @@ void FurnaceGUI::commitSettings() { settings.opl3Core!=e->getConfInt("opl3Core",0) || settings.esfmCore!=e->getConfInt("esfmCore",0) || settings.opllCore!=e->getConfInt("opllCore",0) || + settings.ayCore!=e->getConfInt("ayCore",0) || settings.bubsysQuality!=e->getConfInt("bubsysQuality",3) || settings.dsidQuality!=e->getConfInt("dsidQuality",3) || settings.gbQuality!=e->getConfInt("gbQuality",3) ||