Nuked OPN2: ASIC YM3438 & YM2612 emulation

This commit is contained in:
nukeykt 2017-09-29 01:45:49 +09:00
parent 27a77147aa
commit 51f802b2cc
6 changed files with 228 additions and 150 deletions

View File

@ -67,9 +67,14 @@ static int ym3438_accm[24][2];
static int ym3438_sample[2];
static unsigned int ym3438_cycles;
void sound_ym3438_set_type(uint8 type)
{
OPN2_SetChipType(&ym3438, type);
}
void YM3438_Reset(void)
{
OPN2_Reset(&ym3438);
OPN2_Reset(&ym3438, config.ym3438_type);
}
void YM3438_Update(int *buffer, int length)
@ -89,8 +94,8 @@ void YM3438_Update(int *buffer, int length)
ym3438_sample[1] += ym3438_accm[j][1];
}
}
*buffer++ = ym3438_sample[0] * 8;
*buffer++ = ym3438_sample[1] * 8;
*buffer++ = ym3438_sample[0] * 11;
*buffer++ = ym3438_sample[1] * 11;
}
}

View File

@ -41,6 +41,9 @@
#define _SOUND_H_
/* Function prototypes */
#ifdef HAVE_YM3438_CORE
extern void sound_ym3438_set_type(uint8 type);
#endif
extern void sound_init(void);
extern void sound_reset(void);
extern int sound_context_save(uint8 *state);

View File

@ -39,7 +39,7 @@
* OPLx decapsulated(Matthew Gambrell, Olli Niemitalo):
* OPL2 ROMs.
*
* version: 1.0.5
* version: 1.0.6
*/
#include <string.h>
@ -966,6 +966,8 @@ void OPN2_ChOutput(ym3438_t *chip)
Bit32u channel = chip->channel;
Bit32u test_dac = chip->mode_test_2c[5];
Bit16s out;
Bit16s sign;
Bit32u out_en;
chip->ch_read = chip->ch_lock;
if (chip->slot < 12)
{
@ -995,13 +997,53 @@ void OPN2_ChOutput(ym3438_t *chip)
}
chip->mol = 0;
chip->mor = 0;
if (chip->ch_lock_l)
if (chip->chip_type == ym3438_type_ym2612)
{
chip->mol = out;
out_en = ((chip->cycles & 3) == 3) || test_dac;
/* YM2612 DAC emulation(not verified) */
sign = out >> 8;
if (out >= 0)
{
out++;
sign++;
}
if (chip->ch_lock_l && out_en)
{
chip->mol = out;
}
else
{
chip->mol = sign;
}
if (chip->ch_lock_r && out_en)
{
chip->mor = out;
}
else
{
chip->mor = sign;
}
/* Amplify signal */
chip->mol *= 3;
chip->mor *= 3;
}
if (chip->ch_lock_r)
else
{
chip->mor = out;
out_en = ((chip->cycles & 3) != 0) || test_dac;
/* Discrete YM3438 seems has the ladder effect too */
if (out >= 0 && chip->chip_type == ym3438_type_discrete)
{
out++;
}
if (chip->ch_lock_l && out_en)
{
chip->mol = out;
}
if (chip->ch_lock_r && out_en)
{
chip->mor = out;
}
}
}
@ -1161,7 +1203,7 @@ void OPN2_KeyOn(ym3438_t*chip)
}
}
void OPN2_Reset(ym3438_t *chip)
void OPN2_Reset(ym3438_t *chip, Bit32u type)
{
Bit32u i;
memset(chip, 0, sizeof(ym3438_t));
@ -1177,6 +1219,12 @@ void OPN2_Reset(ym3438_t *chip)
chip->pan_l[i] = 1;
chip->pan_r[i] = 1;
}
chip->chip_type = type;
}
void OPN2_SetChipType(ym3438_t *chip, Bit32u type)
{
chip->chip_type = type;
}
void OPN2_Clock(ym3438_t *chip, Bit32u *buffer)
@ -1350,7 +1398,7 @@ Bit32u OPN2_ReadIRQPin(ym3438_t *chip)
Bit8u OPN2_Read(ym3438_t *chip, Bit32u port)
{
if ((port & 3) == 0)
if ((port & 3) == 0 || chip->chip_type == ym3438_type_asic)
{
if (chip->mode_test_21[6])
{

View File

@ -45,6 +45,12 @@
#ifndef YM3438_H
#define YM3438_H
enum {
ym3438_type_discrete = 0, /* Discrete YM3438 (Teradrive) */
ym3438_type_asic = 1, /* ASIC YM3438 (MD1 VA7, MD2, MD3, etc) */
ym3438_type_ym2612 = 2 /* YM2612 (MD1, MD2 VA2) */
};
#include <stdint.h>
typedef uintptr_t Bitu;
@ -60,148 +66,150 @@ typedef int8_t Bit8s;
typedef struct
{
Bit32u cycles;
Bit32u slot;
Bit32u channel;
Bit16s mol, mor;
/* IO */
Bit16u write_data;
Bit8u write_a;
Bit8u write_d;
Bit8u write_a_en;
Bit8u write_d_en;
Bit8u write_busy;
Bit8u write_busy_cnt;
Bit8u write_fm_address;
Bit8u write_fm_data;
Bit8u write_fm_mode_a;
Bit16u address;
Bit8u data;
Bit8u pin_test_in;
Bit8u pin_irq;
Bit8u busy;
/* LFO */
Bit8u lfo_en;
Bit8u lfo_freq;
Bit8u lfo_pm;
Bit8u lfo_am;
Bit8u lfo_cnt;
Bit8u lfo_inc;
Bit8u lfo_quotient;
/* Phase generator */
Bit16u pg_fnum;
Bit8u pg_block;
Bit8u pg_kcode;
Bit32u pg_inc[24];
Bit32u pg_phase[24];
Bit8u pg_reset[24];
Bit32u pg_read;
/* Envelope generator */
Bit8u eg_cycle;
Bit8u eg_cycle_stop;
Bit8u eg_shift;
Bit8u eg_shift_lock;
Bit8u eg_timer_low_lock;
Bit16u eg_timer;
Bit8u eg_timer_inc;
Bit16u eg_quotient;
Bit8u eg_custom_timer;
Bit8u eg_rate;
Bit8u eg_ksv;
Bit8u eg_inc;
Bit8u eg_ratemax;
Bit8u eg_sl[2];
Bit8u eg_lfo_am;
Bit8u eg_tl[2];
Bit8u eg_state[24];
Bit16u eg_level[24];
Bit16u eg_out[24];
Bit8u eg_kon[24];
Bit8u eg_kon_csm[24];
Bit8u eg_kon_latch[24];
Bit8u eg_csm_mode[24];
Bit8u eg_ssg_enable[24];
Bit8u eg_ssg_pgrst_latch[24];
Bit8u eg_ssg_repeat_latch[24];
Bit8u eg_ssg_hold_up_latch[24];
Bit8u eg_ssg_dir[24];
Bit8u eg_ssg_inv[24];
Bit32u eg_read[2];
Bit8u eg_read_inc;
/* FM */
Bit16s fm_op1[6][2];
Bit16s fm_op2[6];
Bit16s fm_out[24];
Bit16u fm_mod[24];
/* Channel */
Bit16s ch_acc[6];
Bit16s ch_out[6];
Bit16s ch_lock;
Bit8u ch_lock_l;
Bit8u ch_lock_r;
Bit16s ch_read;
/* Timer */
Bit16u timer_a_cnt;
Bit16u timer_a_reg;
Bit8u timer_a_load_lock;
Bit8u timer_a_load;
Bit8u timer_a_enable;
Bit8u timer_a_reset;
Bit8u timer_a_load_latch;
Bit8u timer_a_overflow_flag;
Bit8u timer_a_overflow;
Bit16u timer_b_cnt;
Bit8u timer_b_subcnt;
Bit16u timer_b_reg;
Bit8u timer_b_load_lock;
Bit8u timer_b_load;
Bit8u timer_b_enable;
Bit8u timer_b_reset;
Bit8u timer_b_load_latch;
Bit8u timer_b_overflow_flag;
Bit8u timer_b_overflow;
/* Register set */
Bit8u mode_test_21[8];
Bit8u mode_test_2c[8];
Bit8u mode_ch3;
Bit8u mode_kon_channel;
Bit8u mode_kon_operator[4];
Bit8u mode_kon[24];
Bit8u mode_csm;
Bit8u mode_kon_csm;
Bit8u dacen;
Bit16s dacdata;
Bit8u ks[24];
Bit8u ar[24];
Bit8u sr[24];
Bit8u dt[24];
Bit8u multi[24];
Bit8u sl[24];
Bit8u rr[24];
Bit8u dr[24];
Bit8u am[24];
Bit8u tl[24];
Bit8u ssg_eg[24];
Bit16u fnum[6];
Bit8u block[6];
Bit8u kcode[6];
Bit16u fnum_3ch[6];
Bit8u block_3ch[6];
Bit8u kcode_3ch[6];
Bit8u reg_a4;
Bit8u reg_ac;
Bit8u connect[6];
Bit8u fb[6];
Bit8u pan_l[6], pan_r[6];
Bit8u ams[6];
Bit8u pms[6];
Bit32u chip_type;
Bit32u cycles;
Bit32u slot;
Bit32u channel;
Bit16s mol, mor;
/* IO */
Bit16u write_data;
Bit8u write_a;
Bit8u write_d;
Bit8u write_a_en;
Bit8u write_d_en;
Bit8u write_busy;
Bit8u write_busy_cnt;
Bit8u write_fm_address;
Bit8u write_fm_data;
Bit8u write_fm_mode_a;
Bit16u address;
Bit8u data;
Bit8u pin_test_in;
Bit8u pin_irq;
Bit8u busy;
/* LFO */
Bit8u lfo_en;
Bit8u lfo_freq;
Bit8u lfo_pm;
Bit8u lfo_am;
Bit8u lfo_cnt;
Bit8u lfo_inc;
Bit8u lfo_quotient;
/* Phase generator */
Bit16u pg_fnum;
Bit8u pg_block;
Bit8u pg_kcode;
Bit32u pg_inc[24];
Bit32u pg_phase[24];
Bit8u pg_reset[24];
Bit32u pg_read;
/* Envelope generator */
Bit8u eg_cycle;
Bit8u eg_cycle_stop;
Bit8u eg_shift;
Bit8u eg_shift_lock;
Bit8u eg_timer_low_lock;
Bit16u eg_timer;
Bit8u eg_timer_inc;
Bit16u eg_quotient;
Bit8u eg_custom_timer;
Bit8u eg_rate;
Bit8u eg_ksv;
Bit8u eg_inc;
Bit8u eg_ratemax;
Bit8u eg_sl[2];
Bit8u eg_lfo_am;
Bit8u eg_tl[2];
Bit8u eg_state[24];
Bit16u eg_level[24];
Bit16u eg_out[24];
Bit8u eg_kon[24];
Bit8u eg_kon_csm[24];
Bit8u eg_kon_latch[24];
Bit8u eg_csm_mode[24];
Bit8u eg_ssg_enable[24];
Bit8u eg_ssg_pgrst_latch[24];
Bit8u eg_ssg_repeat_latch[24];
Bit8u eg_ssg_hold_up_latch[24];
Bit8u eg_ssg_dir[24];
Bit8u eg_ssg_inv[24];
Bit32u eg_read[2];
Bit8u eg_read_inc;
/* FM */
Bit16s fm_op1[6][2];
Bit16s fm_op2[6];
Bit16s fm_out[24];
Bit16u fm_mod[24];
/* Channel */
Bit16s ch_acc[6];
Bit16s ch_out[6];
Bit16s ch_lock;
Bit8u ch_lock_l;
Bit8u ch_lock_r;
Bit16s ch_read;
/* Timer */
Bit16u timer_a_cnt;
Bit16u timer_a_reg;
Bit8u timer_a_load_lock;
Bit8u timer_a_load;
Bit8u timer_a_enable;
Bit8u timer_a_reset;
Bit8u timer_a_load_latch;
Bit8u timer_a_overflow_flag;
Bit8u timer_a_overflow;
Bit16u timer_b_cnt;
Bit8u timer_b_subcnt;
Bit16u timer_b_reg;
Bit8u timer_b_load_lock;
Bit8u timer_b_load;
Bit8u timer_b_enable;
Bit8u timer_b_reset;
Bit8u timer_b_load_latch;
Bit8u timer_b_overflow_flag;
Bit8u timer_b_overflow;
/* Register set */
Bit8u mode_test_21[8];
Bit8u mode_test_2c[8];
Bit8u mode_ch3;
Bit8u mode_kon_channel;
Bit8u mode_kon_operator[4];
Bit8u mode_kon[24];
Bit8u mode_csm;
Bit8u mode_kon_csm;
Bit8u dacen;
Bit16s dacdata;
Bit8u ks[24];
Bit8u ar[24];
Bit8u sr[24];
Bit8u dt[24];
Bit8u multi[24];
Bit8u sl[24];
Bit8u rr[24];
Bit8u dr[24];
Bit8u am[24];
Bit8u tl[24];
Bit8u ssg_eg[24];
Bit16u fnum[6];
Bit8u block[6];
Bit8u kcode[6];
Bit16u fnum_3ch[6];
Bit8u block_3ch[6];
Bit8u kcode_3ch[6];
Bit8u reg_a4;
Bit8u reg_ac;
Bit8u connect[6];
Bit8u fb[6];
Bit8u pan_l[6], pan_r[6];
Bit8u ams[6];
Bit8u pms[6];
} ym3438_t;
void OPN2_Reset(ym3438_t *chip);
void OPN2_Reset(ym3438_t *chip, Bit32u type);
void OPN2_SetChipType(ym3438_t *chip, Bit32u type);
void OPN2_Clock(ym3438_t *chip, Bit32u *buffer);
void OPN2_Write(ym3438_t *chip, Bit32u port, Bit8u data);
void OPN2_SetTestPin(ym3438_t *chip, Bit32u value);

View File

@ -1117,6 +1117,18 @@ static void check_variables(void)
sound_reset();
}
}
var.key = "genesis_plus_gx_ym3438_type";
environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var);
{
if (!strcmp(var.value, "ym2612"))
config.ym3438_type = ym3438_type_ym2612;
else if (!strcmp(var.value, "ym3438 asic"))
config.ym3438_type = ym3438_type_asic;
else
config.ym3438_type = ym3438_type_discrete;
sound_ym3438_set_type(config.ym3438_type);
}
#endif
var.key = "genesis_plus_gx_blargg_ntsc_filter";
@ -1657,6 +1669,7 @@ void retro_set_environment(retro_environment_t cb)
{ "genesis_plus_gx_dac_bits", "YM2612 DAC quantization; disabled|enabled" },
#ifdef HAVE_YM3438_CORE
{ "genesis_plus_gx_ym3438", "YM2612/YM3438 core; mame|nuked opn2" },
{ "genesis_plus_gx_ym3438_type", "YM2612/YM3438 type(Nuked OPN2); ym2612|ym3438 asic|ym3438 discrete" },
#endif
{ "genesis_plus_gx_audio_filter", "Audio filter; disabled|low-pass" },

View File

@ -93,6 +93,7 @@ struct
uint8 ym2413;
#ifdef HAVE_YM3438_CORE
uint8 ym3438;
uint8 ym3438_type;
#endif
uint8 mono;
int16 psg_preamp;