adding ym2413

squashed commits:
YM2413追加中
一通り実装したけどポートへの書き込み方が不明でまだ音が出ない
細かい修正(未テスト)
resetで初期化されるのをなんとかしたい
sound 初期化と終了を追加してみた
SN76496を参考にYM2413のアップデート方法を変更してみた
stereoフラグをアップデートサイズに変更
処理順番を整理したら音が出た
stateセーブに対応してみた
addition: Support for the Japanese Mark-III extended FM sound source unit
This commit is contained in:
hiroshica 2020-02-24 13:42:53 +09:00 committed by kub
parent 7980d47767
commit a2f24bfa7b
17 changed files with 221 additions and 56 deletions

View file

@ -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;

View file

@ -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

View file

@ -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);

View file

@ -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;
if((a&0xff)>= 0xf0){
switch((a&0xff))
{
case 0xf0:
// FM reg port
break;
case 0x40: /* V counter */
d = Pico.video.v_counter;
elprintf(EL_HVCNT, "V counter read: %02x", d);
case 0xf1:
// FM data port
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;
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;
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 0x80:
vdp_data_write(d);
break;
case 0x40:
case 0x41:
if ((d & 0x90) == 0x90)
PsndDoPSG(Pico.m.scanline);
SN76496Write(d);
break;
case 0x81:
vdp_ctl_write(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
pico/sound/emu2413 Submodule

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

View file

@ -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);

View file

@ -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);