From a2f24bfa7bcd42b19fd2887591a5d81b4964d376 Mon Sep 17 00:00:00 2001 From: hiroshica Date: Mon, 24 Feb 2020 13:42:53 +0900 Subject: [PATCH] adding ym2413 MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit squashed commits: YM2413追加中 一通り実装したけどポートへの書き込み方が不明でまだ音が出ない 細かい修正(未テスト) resetで初期化されるのをなんとかしたい sound 初期化と終了を追加してみた SN76496を参考にYM2413のアップデート方法を変更してみた stereoフラグをアップデートサイズに変更 処理順番を整理したら音が出た stateセーブに対応してみた addition: Support for the Japanese Mark-III extended FM sound source unit --- .gitignore | 4 + .gitmodules | 3 + AUTHORS | 1 + pico/pico.c | 2 + pico/pico.h | 2 +- pico/pico_int.h | 4 + pico/sms.c | 156 +++++++++++++++++++++++------------ pico/sound/emu2413 | 1 + pico/sound/sound.c | 91 +++++++++++++++++++- pico/state.c | 11 ++- platform/common/common.mak | 1 + platform/common/menu_pico.c | 1 + platform/common/menu_pico.h | 1 + platform/gizmondo/Makefile | 1 + platform/gizmondo/menu.c | 1 + platform/libretro/libretro.c | 2 +- platform/psp/menu.c | 1 + 17 files changed, 224 insertions(+), 59 deletions(-) create mode 160000 pico/sound/emu2413 diff --git a/.gitignore b/.gitignore index b7ef852d..022f987e 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,7 @@ obj/ .opk_data PicoDrive PicoDrive.opk +pico_int_offs.h +amalgamate +textfilter + diff --git a/.gitmodules b/.gitmodules index 36091a2d..b778188f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "cpu/cyclone"] path = cpu/cyclone url = https://github.com/notaz/cyclone68000.git +[submodule "pico/sound/emu2413"] + path = pico/sound/emu2413 + url = https://github.com/digital-sound-antiques/emu2413.git diff --git a/AUTHORS b/AUTHORS index d4791101..36dd861b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -53,4 +53,5 @@ Additional thanks * Paul Cercueil for OpenDingux port. * Inder for some graphics. * squarepusher for some libretro fixes +* Hiroshica for support of japanese Mark-III extended YM2413 sound * Anyone else I forgot. Let me know if it's you. diff --git a/pico/pico.c b/pico/pico.c index 579cdd0d..577701ba 100644 --- a/pico/pico.c +++ b/pico/pico.c @@ -38,6 +38,7 @@ void PicoInit(void) PicoInitMCD(); PicoSVPInit(); Pico32xInit(); + PsndInit(); PicoDrawInit(); PicoDraw2Init(); @@ -50,6 +51,7 @@ void PicoExit(void) PicoExitMCD(); PicoCartUnload(); z80_exit(); + PsndExit(); free(Pico.sv.data); Pico.sv.data = NULL; diff --git a/pico/pico.h b/pico/pico.h index d8c5959c..5dac5c29 100644 --- a/pico/pico.h +++ b/pico/pico.h @@ -55,7 +55,7 @@ extern void *p32x_bios_g, *p32x_bios_m, *p32x_bios_s; #define POPT_EN_Z80 (1<< 2) #define POPT_EN_STEREO (1<< 3) #define POPT_ALT_RENDERER (1<< 4) // 00 00x0 -// unused (1<< 5) +#define POPT_EN_YM2413 (1<< 5) // unused (1<< 6) #define POPT_ACC_SPRITES (1<< 7) #define POPT_DIS_32C_BORDER (1<< 8) // 00 0x00 diff --git a/pico/pico_int.h b/pico/pico_int.h index 2d688a9f..1a1205f8 100644 --- a/pico/pico_int.h +++ b/pico/pico_int.h @@ -434,6 +434,7 @@ struct PicoSound unsigned int dac_pos; // last DAC position in Q20 unsigned int fm_pos; // last FM position in Q20 unsigned int psg_pos; // last PSG position in Q16 + unsigned int ym2413_pos; // last YM2413 position }; // run tools/mkoffsets pico/pico_int_offs.h if you change these @@ -897,10 +898,13 @@ PICO_INTERNAL_ASM void wram_2M_to_1M(unsigned char *m); PICO_INTERNAL_ASM void wram_1M_to_2M(unsigned char *m); // sound/sound.c +PICO_INTERNAL void PsndInit(void); +PICO_INTERNAL void PsndExit(void); PICO_INTERNAL void PsndReset(void); PICO_INTERNAL void PsndStartFrame(void); PICO_INTERNAL void PsndDoDAC(int cycle_to); PICO_INTERNAL void PsndDoPSG(int line_to); +PICO_INTERNAL void PsndDoYM2413(int line_to); PICO_INTERNAL void PsndDoFM(int line_to); PICO_INTERNAL void PsndClear(void); PICO_INTERNAL void PsndGetSamples(int y); diff --git a/pico/sms.c b/pico/sms.c index 0f4a48ad..5ddbebd2 100644 --- a/pico/sms.c +++ b/pico/sms.c @@ -15,6 +15,13 @@ #include "pico_int.h" #include "memory.h" #include "sound/sn76496.h" +#include "sound/emu2413/emu2413.h" + +extern void YM2413_regWrite(unsigned reg); +extern void YM2413_dataWrite(unsigned data); + + +static unsigned short ymflag = 0xffff; static unsigned char vdp_data_read(void) { @@ -100,42 +107,61 @@ static unsigned char z80_sms_in(unsigned short a) unsigned char d = 0; elprintf(EL_IO, "z80 port %04x read", a); - a &= 0xc1; - switch (a) - { - case 0x00: - case 0x01: - d = 0xff; - break; - - case 0x40: /* V counter */ - d = Pico.video.v_counter; - elprintf(EL_HVCNT, "V counter read: %02x", d); - break; - - case 0x41: /* H counter */ - d = Pico.m.rotate++; - elprintf(EL_HVCNT, "H counter read: %02x", d); - break; - - case 0x80: - d = vdp_data_read(); - break; - - case 0x81: - d = vdp_ctl_read(); + if((a&0xff)>= 0xf0){ + switch((a&0xff)) + { + case 0xf0: + // FM reg port break; - - case 0xc0: /* I/O port A and B */ - d = ~((PicoIn.pad[0] & 0x3f) | (PicoIn.pad[1] << 6)); + case 0xf1: + // FM data port break; - - case 0xc1: /* I/O port B and miscellaneous */ - d = (Pico.ms.io_ctl & 0x80) | ((Pico.ms.io_ctl << 1) & 0x40) | 0x30; - d |= ~(PicoIn.pad[1] >> 2) & 0x0f; + case 0xf2: + // bit 0 = 1 active FM Pac + if (PicoIn.opt & POPT_EN_YM2413){ + d = ymflag; + //printf("read FM Check = %02x\n", d); + } break; + } + } + else{ + a &= 0xc1; + switch (a) + { + case 0x00: + case 0x01: + d = 0xff; + break; + + case 0x40: /* V counter */ + d = Pico.video.v_counter; + elprintf(EL_HVCNT, "V counter read: %02x", d); + break; + + case 0x41: /* H counter */ + d = Pico.m.rotate++; + elprintf(EL_HVCNT, "H counter read: %02x", d); + break; + + case 0x80: + d = vdp_data_read(); + break; + + case 0x81: + d = vdp_ctl_read(); + break; + + case 0xc0: /* I/O port A and B */ + d = ~((PicoIn.pad[0] & 0x3f) | (PicoIn.pad[1] << 6)); + break; + + case 0xc1: /* I/O port B and miscellaneous */ + d = (Pico.ms.io_ctl & 0x80) | ((Pico.ms.io_ctl << 1) & 0x40) | 0x30; + d |= ~(PicoIn.pad[1] >> 2) & 0x0f; + break; + } } - elprintf(EL_IO, "ret = %02x", d); return d; } @@ -143,27 +169,52 @@ static unsigned char z80_sms_in(unsigned short a) static void z80_sms_out(unsigned short a, unsigned char d) { elprintf(EL_IO, "z80 port %04x write %02x", a, d); - a &= 0xc1; - switch (a) - { - case 0x01: - Pico.ms.io_ctl = d; - break; - - case 0x40: - case 0x41: - if ((d & 0x90) == 0x90) - PsndDoPSG(Pico.m.scanline); - SN76496Write(d); - break; - case 0x80: - vdp_data_write(d); - break; - - case 0x81: - vdp_ctl_write(d); - break; + if((a&0xff)>= 0xf0){ + switch((a&0xff)) + { + case 0xf0: + // FM reg port + YM2413_regWrite(d); + //printf("write FM register = %02x\n", d); + break; + case 0xf1: + // FM data port + YM2413_dataWrite(d); + //printf("write FM data = %02x\n", d); + break; + case 0xf2: + // bit 0 = 1 active FM Pac + if (PicoIn.opt & POPT_EN_YM2413){ + ymflag = d; + //printf("write FM Check = %02x\n", d); + } + break; + } + } + else{ + a &= 0xc1; + switch (a) + { + case 0x01: + Pico.ms.io_ctl = d; + break; + + case 0x40: + case 0x41: + if ((d & 0x90) == 0x90) + PsndDoPSG(Pico.m.scanline); + SN76496Write(d); + break; + + case 0x80: + vdp_data_write(d); + break; + + case 0x81: + vdp_ctl_write(d); + break; + } } } @@ -212,6 +263,7 @@ void PicoResetMS(void) { z80_reset(); PsndReset(); // pal must be known here + ymflag = 0xffff; } void PicoPowerMS(void) diff --git a/pico/sound/emu2413 b/pico/sound/emu2413 new file mode 160000 index 00000000..9f1dcf84 --- /dev/null +++ b/pico/sound/emu2413 @@ -0,0 +1 @@ +Subproject commit 9f1dcf848d0e33e775e49352f7bc83a9c0e87a81 diff --git a/pico/sound/sound.c b/pico/sound/sound.c index 0b371f25..6204a66a 100644 --- a/pico/sound/sound.c +++ b/pico/sound/sound.c @@ -13,6 +13,7 @@ #include "../pico_int.h" #include "../cd/cue.h" #include "mix.h" +#include "emu2413/emu2413.h" void (*PsndMix_32_to_16l)(short *dest, int *src, int count) = mix_32_to_16l_stereo; @@ -25,6 +26,25 @@ short cdda_out_buffer[2*1152]; // sn76496 extern int *sn76496_regs; +// ym2413 +#define YM2413_CLK 3579545 +OPLL old_opll; +static OPLL *opll = NULL; +unsigned YM2413_reg; + + +PICO_INTERNAL void PsndInit(void) +{ + opll = OPLL_new(YM2413_CLK, PicoIn.sndRate); + OPLL_setChipType(opll,0); + OPLL_reset(opll); +} + +PICO_INTERNAL void PsndExit(void) +{ + OPLL_delete(opll); + opll = NULL; +} PICO_INTERNAL void PsndReset(void) { @@ -59,6 +79,12 @@ void PsndRerate(int preserve_state) SN76496_init(Pico.m.pal ? OSC_PAL/15 : OSC_NTSC/15, PicoIn.sndRate); if (preserve_state) memcpy(sn76496_regs, state, 28*4); // restore old state + if(opll != NULL){ + if (preserve_state) memcpy(&old_opll, opll, sizeof(OPLL)); // remember old state + OPLL_setRate(opll, PicoIn.sndRate); + OPLL_reset(opll); + } + if (state) free(state); @@ -161,6 +187,48 @@ PICO_INTERNAL void PsndDoPSG(int line_to) SN76496Update(PicoIn.sndOut + pos, len, stereo); } +#if 0 +PICO_INTERNAL void PsndDoYM2413(int line_to) +{ + int pos, len; + int stereo = 0; + short *buf; + + // Q16, number of samples since last call + len = ((line_to+1) * Pico.snd.smpl_mult) - Pico.snd.ym2413_pos; + if (len <= 0) + return; + + // update position and calculate buffer offset and length + pos = (Pico.snd.ym2413_pos+0x8000) >> 16; + Pico.snd.ym2413_pos += len; + len = ((Pico.snd.ym2413_pos+0x8000) >> 16) - pos; + + if (!PicoIn.sndOut || !(PicoIn.opt & POPT_EN_YM2413)) + return; + + if (PicoIn.opt & POPT_EN_STEREO) { + stereo = 1; + pos <<= 1; + } + + buf = PicoIn.sndOut + pos; + while (len-- > 0) { + int16_t getdata = OPLL_calc(opll) * 3; + *buf++ += getdata; + buf += stereo; // only left for stereo, to be mixed to right later + } +} +#endif + +void YM2413_regWrite(unsigned data){ + OPLL_writeIO(opll,0,data); +} +void YM2413_dataWrite(unsigned data){ + OPLL_writeIO(opll,1,data); +} + + PICO_INTERNAL void PsndDoFM(int cyc_to) { int pos, len; @@ -249,7 +317,7 @@ PICO_INTERNAL void PsndClear(void) if (!(PicoIn.opt & POPT_EN_FM)) memset32(PsndBuffer, 0, PicoIn.opt & POPT_EN_STEREO ? len*2 : len); // drop pos remainder to avoid rounding errors (not entirely correct though) - Pico.snd.dac_pos = Pico.snd.fm_pos = Pico.snd.psg_pos = 0; + Pico.snd.dac_pos = Pico.snd.fm_pos = Pico.snd.psg_pos = Pico.snd.ym2413_pos = 0; } @@ -344,6 +412,7 @@ static int PsndRenderMS(int offset, int length) { int stereo = (PicoIn.opt & 8) >> 3; int psglen = ((Pico.snd.psg_pos+0x8000) >> 16); + int ym2413len = ((Pico.snd.ym2413_pos+0x8000) >> 16); pprof_start(sound); @@ -355,11 +424,25 @@ static int PsndRenderMS(int offset, int length) SN76496Update(psgbuf, length-psglen, stereo); } + if (length-ym2413len > 0) { + short *ym2413buf = PicoIn.sndOut + (ym2413len << stereo); + Pico.snd.ym2413_pos += (length-ym2413len) << 16; + int len = (length-ym2413len); + if (PicoIn.opt & POPT_EN_YM2413){ + while (len-- > 0) { + int16_t getdata = OPLL_calc(opll) * 3; + *ym2413buf += getdata; + ym2413buf += 1< 0; i--, p++) - *p |= *p << 16; + int i; + short *p; + for (i = length, p = (short *)PicoIn.sndOut; i > 0; i--, p+=2) + *(p + 1) = *p; } pprof_end(sound); diff --git a/pico/state.c b/pico/state.c index b0b6a334..da6b6fd8 100644 --- a/pico/state.c +++ b/pico/state.c @@ -11,10 +11,12 @@ #include "../cpu/sh2/sh2.h" #include "sound/ym2612.h" +#include "sound/emu2413/emu2413.h" #include "state.h" -// sn76496 +// sn76496 & ym2413 extern int *sn76496_regs; +extern OPLL old_opll; static arearw *areaRead; static arearw *areaWrite; @@ -123,6 +125,8 @@ typedef enum { CHUNK_DRAM, CHUNK_32XPAL, CHUNK_32X_EVT, + CHUNK_YM2413, //40 + //rename CHUNK_32X_FIRST = CHUNK_MSH2, CHUNK_32X_LAST = CHUNK_32X_EVT, // add new stuff here @@ -133,6 +137,7 @@ typedef enum { // CHUNK_DEFAULT_COUNT, CHUNK_CARTHW_ = CHUNK_CARTHW, // 64 (defined in PicoInt) + } chunk_name_e; static const char * const chunk_names[CHUNK_DEFAULT_COUNT] = { @@ -179,6 +184,7 @@ static const char * const chunk_names[CHUNK_DEFAULT_COUNT] = { "DRAM", "PAL", "events", + "YM2413", //40 }; static int write_chunk(chunk_name_e name, int len, void *data, void *file) @@ -283,6 +289,8 @@ static int state_save(void *file) memcpy(buff, pcd_event_times, sizeof(pcd_event_times)); CHECKED_WRITE(CHUNK_CD_EVT, 0x40, buff); + CHECKED_WRITE(CHUNK_YM2413, sizeof(OPLL), &old_opll); + len = gfx_context_save(buf2); CHECKED_WRITE(CHUNK_CD_GFX, len, buf2); len = cdc_context_save(buf2); @@ -442,6 +450,7 @@ static int state_load(void *file) case CHUNK_IOPORTS: CHECKED_READ_BUFF(PicoMem.ioports); break; case CHUNK_PSG: CHECKED_READ2(28*4, sn76496_regs); break; + case CHUNK_YM2413: CHECKED_READ2(sizeof(OPLL), &old_opll); break; case CHUNK_FM: ym2612_regs = YM2612GetRegs(); CHECKED_READ2(0x200+4, ym2612_regs); diff --git a/platform/common/common.mak b/platform/common/common.mak index 599f246f..8afe5d3f 100644 --- a/platform/common/common.mak +++ b/platform/common/common.mak @@ -124,6 +124,7 @@ endif # sound SRCS_COMMON += $(R)pico/sound/sound.c SRCS_COMMON += $(R)pico/sound/sn76496.c $(R)pico/sound/ym2612.c +SRCS_COMMON += $(R)pico/sound/emu2413/emu2413.c ifneq "$(ARCH)$(asm_mix)" "arm1" SRCS_COMMON += $(R)pico/sound/mix.c endif diff --git a/platform/common/menu_pico.c b/platform/common/menu_pico.c index 1d46e634..2e0e1279 100644 --- a/platform/common/menu_pico.c +++ b/platform/common/menu_pico.c @@ -501,6 +501,7 @@ static menu_entry e_menu_adv_options[] = mee_onoff ("Emulate YM2612 (FM)", MA_OPT2_ENABLE_YM2612, PicoIn.opt, POPT_EN_FM), mee_onoff ("Disable YM2612 SSG-EG", MA_OPT2_DISABLE_YM_SSG,PicoIn.opt, POPT_DIS_FM_SSGEG), mee_onoff ("Emulate SN76496 (PSG)", MA_OPT2_ENABLE_SN76496,PicoIn.opt, POPT_EN_PSG), + mee_onoff ("Emulate YM2413 (FM)", MA_OPT2_ENABLE_YM2413 ,PicoIn.opt, POPT_EN_YM2413), mee_onoff ("gzip savestates", MA_OPT2_GZIP_STATES, currentConfig.EmuOpt, EOPT_GZIP_SAVES), mee_onoff ("Don't save last used ROM", MA_OPT2_NO_LAST_ROM, currentConfig.EmuOpt, EOPT_NO_AUTOSVCFG), mee_onoff ("Disable idle loop patching",MA_OPT2_NO_IDLE_LOOPS,PicoIn.opt, POPT_DIS_IDLE_DET), diff --git a/platform/common/menu_pico.h b/platform/common/menu_pico.h index d15113fc..0abbfb03 100644 --- a/platform/common/menu_pico.h +++ b/platform/common/menu_pico.h @@ -50,6 +50,7 @@ typedef enum MA_OPT2_ENABLE_YM2612, MA_OPT2_DISABLE_YM_SSG, MA_OPT2_ENABLE_SN76496, + MA_OPT2_ENABLE_YM2413, MA_OPT2_GZIP_STATES, MA_OPT2_NO_LAST_ROM, MA_OPT2_RAMTIMINGS, /* gp2x */ diff --git a/platform/gizmondo/Makefile b/platform/gizmondo/Makefile index 7228be56..31530d79 100644 --- a/platform/gizmondo/Makefile +++ b/platform/gizmondo/Makefile @@ -64,6 +64,7 @@ OBJS += pico/sound/sound.o endif OBJS += pico/sound/mix_asm.o OBJS += pico/sound/sn76496.o pico/sound/ym2612.o +OBJS += pico/sound/emu2413/emu2413.o # zlib OBJS += zlib/gzio.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o zlib/trees.o \ zlib/deflate.o zlib/crc32.o zlib/adler32.o zlib/zutil.o zlib/compress.o diff --git a/platform/gizmondo/menu.c b/platform/gizmondo/menu.c index 1045f47b..47778be2 100644 --- a/platform/gizmondo/menu.c +++ b/platform/gizmondo/menu.c @@ -931,6 +931,7 @@ menu_entry opt2_entries[] = { "Emulate Z80", MB_ONOFF, MA_OPT2_ENABLE_Z80, &PicoIn.opt, 0x00004, 0, 0, 1, 1 }, { "Emulate YM2612 (FM)", MB_ONOFF, MA_OPT2_ENABLE_YM2612, &PicoIn.opt, 0x00001, 0, 0, 1, 1 }, { "Emulate SN76496 (PSG)", MB_ONOFF, MA_OPT2_ENABLE_SN76496,&PicoIn.opt, 0x00002, 0, 0, 1, 1 }, + { "Emulate YM2413 (FM)", MB_ONOFF, MA_OPT2_ENABLE_YM2413, &PicoIn.opt, 0x00020, 0, 0, 1, 1 }, { "Double buffering", MB_ONOFF, MA_OPT2_DBLBUFF, ¤tConfig.EmuOpt, 0x8000, 0, 0, 1, 1 }, { "Wait for V-sync (slow)", MB_ONOFF, MA_OPT2_VSYNC, ¤tConfig.EmuOpt, 0x2000, 0, 0, 1, 1 }, { "gzip savestates", MB_ONOFF, MA_OPT2_GZIP_STATES, ¤tConfig.EmuOpt, 0x0008, 0, 0, 1, 1 }, diff --git a/platform/libretro/libretro.c b/platform/libretro/libretro.c index 0794f555..23cd3df2 100644 --- a/platform/libretro/libretro.c +++ b/platform/libretro/libretro.c @@ -1366,7 +1366,7 @@ void retro_init(void) sceBlock = getVMBlock(); #endif - PicoIn.opt = POPT_EN_STEREO|POPT_EN_FM|POPT_EN_PSG|POPT_EN_Z80 + PicoIn.opt = POPT_EN_STEREO|POPT_EN_FM|POPT_EN_PSG|POPT_EN_Z80|POPT_EN_YM2413 | POPT_EN_MCD_PCM|POPT_EN_MCD_CDDA|POPT_EN_MCD_GFX | POPT_EN_32X|POPT_EN_PWM | POPT_ACC_SPRITES|POPT_DIS_32C_BORDER; diff --git a/platform/psp/menu.c b/platform/psp/menu.c index fc31b8e7..1b714238 100644 --- a/platform/psp/menu.c +++ b/platform/psp/menu.c @@ -1119,6 +1119,7 @@ menu_entry opt2_entries[] = { "Emulate Z80", MB_ONOFF, MA_OPT2_ENABLE_Z80, &PicoIn.opt, 0x00004, 0, 0, 1, 1 }, { "Emulate YM2612 (FM)", MB_ONOFF, MA_OPT2_ENABLE_YM2612, &PicoIn.opt, 0x00001, 0, 0, 1, 1 }, { "Emulate SN76496 (PSG)", MB_ONOFF, MA_OPT2_ENABLE_SN76496, &PicoIn.opt, 0x00002, 0, 0, 1, 1 }, + { "Emulate YM2413 (FM)", MB_ONOFF, MA_OPT2_ENABLE_YM2413, &PicoIn.opt, 0x00020, 0, 0, 1, 1 }, { "gzip savestates", MB_ONOFF, MA_OPT2_GZIP_STATES, ¤tConfig.EmuOpt, 0x00008, 0, 0, 1, 1 }, { "Don't save last used ROM", MB_ONOFF, MA_OPT2_NO_LAST_ROM, ¤tConfig.EmuOpt, 0x00020, 0, 0, 1, 1 }, { "Status line in main menu", MB_ONOFF, MA_OPT2_STATUS_LINE, ¤tConfig.EmuOpt, 0x20000, 0, 0, 1, 1 }, -- 2.39.2