Преглед изворни кода

adding ym2413

squashed commits:
YM2413追加中
一通り実装したけどポートへの書き込み方が不明でまだ音が出ない
細かい修正(未テスト)
resetで初期化されるのをなんとかしたい
sound 初期化と終了を追加してみた
SN76496を参考にYM2413のアップデート方法を変更してみた
stereoフラグをアップデートサイズに変更
処理順番を整理したら音が出た
stateセーブに対応してみた
addition: Support for the Japanese Mark-III extended FM sound source unit
hiroshica пре 4 година
родитељ
комит
a2f24bfa7b

+ 4 - 0
.gitignore

@@ -19,3 +19,7 @@ obj/
 .opk_data
 PicoDrive
 PicoDrive.opk
+pico_int_offs.h
+amalgamate
+textfilter
+

+ 3 - 0
.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

+ 1 - 0
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.

+ 2 - 0
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;

+ 1 - 1
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

+ 4 - 0
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);

+ 104 - 52
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)

+ 1 - 0
pico/sound/emu2413

@@ -0,0 +1 @@
+Subproject commit 9f1dcf848d0e33e775e49352f7bc83a9c0e87a81

+ 87 - 4
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<<stereo;
+      }
+    }
+  }
+
   // upmix to "stereo" if needed
   if (PicoIn.opt & POPT_EN_STEREO) {
-    int i, *p;
-    for (i = length, p = (void *)PicoIn.sndOut; i > 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);

+ 10 - 1
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);

+ 1 - 0
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

+ 1 - 0
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),

+ 1 - 0
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 */

+ 1 - 0
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

+ 1 - 0
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,       &currentConfig.EmuOpt, 0x8000, 0, 0, 1, 1 },
 	{ "Wait for V-sync (slow)",    MB_ONOFF, MA_OPT2_VSYNC,         &currentConfig.EmuOpt, 0x2000, 0, 0, 1, 1 },
 	{ "gzip savestates",           MB_ONOFF, MA_OPT2_GZIP_STATES,   &currentConfig.EmuOpt, 0x0008, 0, 0, 1, 1 },

+ 1 - 1
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;

+ 1 - 0
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,    &currentConfig.EmuOpt, 0x00008, 0, 0, 1, 1 },
 	{ "Don't save last used ROM",  MB_ONOFF, MA_OPT2_NO_LAST_ROM,    &currentConfig.EmuOpt, 0x00020, 0, 0, 1, 1 },
 	{ "Status line in main menu",  MB_ONOFF, MA_OPT2_STATUS_LINE,    &currentConfig.EmuOpt, 0x20000, 0, 0, 1, 1 },