mirror of
https://github.com/ekeeke/Genesis-Plus-GX.git
synced 2024-12-27 03:31:49 +01:00
Merge pull request #179 from nukeykt/ym3438
Nuked OPN2: minor optimization + ASIC YM3438 & YM2612 DAC emulation (experimental)
This commit is contained in:
commit
296b3c7a08
@ -89,8 +89,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@
|
||||
* OPLx decapsulated(Matthew Gambrell, Olli Niemitalo):
|
||||
* OPL2 ROMs.
|
||||
*
|
||||
* version: 1.0.4
|
||||
* version: 1.0.6
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
@ -232,6 +232,8 @@ static const Bit32u fm_algorithm[4][6][8] = {
|
||||
}
|
||||
};
|
||||
|
||||
static Bit32u chip_type = ym3438_type_discrete;
|
||||
|
||||
void OPN2_DoIO(ym3438_t *chip)
|
||||
{
|
||||
/* Write signal check */
|
||||
@ -506,7 +508,7 @@ void OPN2_PhaseCalcIncrement(ym3438_t *chip)
|
||||
basefreq = (fnum << chip->pg_block) >> 2;
|
||||
|
||||
/* Apply detune */
|
||||
if (dt & 0x03)
|
||||
if (dt_l)
|
||||
{
|
||||
if (kcode > 0x1c)
|
||||
{
|
||||
@ -514,7 +516,7 @@ void OPN2_PhaseCalcIncrement(ym3438_t *chip)
|
||||
}
|
||||
block = kcode >> 2;
|
||||
note = kcode & 0x03;
|
||||
sum = block + 1 + ((dt_l == 3) | (dt_l & 0x02) | ((dt_l != 0) << 3));
|
||||
sum = block + 9 + ((dt_l == 3) | (dt_l & 0x02));
|
||||
sum_h = sum >> 1;
|
||||
sum_l = sum & 0x01;
|
||||
detune = pg_detune[(sum_l << 2) | note] >> (9 - sum_h);
|
||||
@ -671,7 +673,7 @@ void OPN2_EnvelopeADSR(ym3438_t *chip)
|
||||
}
|
||||
break;
|
||||
case eg_num_decay:
|
||||
if (!eg_off && (level >> 5) == chip->eg_sl[1])
|
||||
if ((level >> 5) == chip->eg_sl[1])
|
||||
{
|
||||
nextstate = eg_num_sustain;
|
||||
}
|
||||
@ -803,11 +805,11 @@ void OPN2_EnvelopePrepare(ym3438_t *chip)
|
||||
chip->eg_ksv = chip->pg_kcode >> (chip->ks[slot] ^ 0x03);
|
||||
if (chip->am[slot])
|
||||
{
|
||||
chip->eg_am_shift = chip->ams[chip->channel];
|
||||
chip->eg_lfo_am = chip->lfo_am >> eg_am_shift[chip->ams[chip->channel]];
|
||||
}
|
||||
else
|
||||
{
|
||||
chip->eg_am_shift = 0;
|
||||
chip->eg_lfo_am = 0;
|
||||
}
|
||||
/* Delay TL & SL value */
|
||||
chip->eg_tl[1] = chip->eg_tl[0];
|
||||
@ -835,7 +837,7 @@ void OPN2_EnvelopeGenerate(ym3438_t *chip)
|
||||
level &= 0x3ff;
|
||||
|
||||
/* Apply AM LFO */
|
||||
level += chip->lfo_am >> eg_am_shift[chip->eg_am_shift];
|
||||
level += chip->eg_lfo_am;
|
||||
|
||||
/* Apply TL */
|
||||
if (!(chip->mode_csm && chip->channel == 2 + 1))
|
||||
@ -966,6 +968,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 +999,53 @@ void OPN2_ChOutput(ym3438_t *chip)
|
||||
}
|
||||
chip->mol = 0;
|
||||
chip->mor = 0;
|
||||
if (chip->ch_lock_l)
|
||||
|
||||
if (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_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1179,6 +1223,11 @@ void OPN2_Reset(ym3438_t *chip)
|
||||
}
|
||||
}
|
||||
|
||||
void OPN2_SetChipType(Bit32u type)
|
||||
{
|
||||
chip_type = type;
|
||||
}
|
||||
|
||||
void OPN2_Clock(ym3438_t *chip, Bit32u *buffer)
|
||||
{
|
||||
chip->lfo_inc = chip->mode_test_21[1];
|
||||
@ -1350,7 +1399,7 @@ Bit32u OPN2_ReadIRQPin(ym3438_t *chip)
|
||||
|
||||
Bit8u OPN2_Read(ym3438_t *chip, Bit32u port)
|
||||
{
|
||||
if ((port & 3) == 0)
|
||||
if ((port & 3) == 0 || chip_type == ym3438_type_asic)
|
||||
{
|
||||
if (chip->mode_test_21[6])
|
||||
{
|
||||
|
@ -39,12 +39,18 @@
|
||||
* OPLx decapsulated(Matthew Gambrell, Olli Niemitalo):
|
||||
* OPL2 ROMs.
|
||||
*
|
||||
* version: 1.0.4
|
||||
* version: 1.0.6
|
||||
*/
|
||||
|
||||
#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,149 @@ 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_am_shift;
|
||||
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 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_SetChipType(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);
|
||||
|
@ -1106,12 +1106,25 @@ static void check_variables(void)
|
||||
environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var);
|
||||
{
|
||||
orig_value = config.ym3438;
|
||||
if (!strcmp(var.value, "nuked opn2"))
|
||||
if (!strcmp(var.value, "nuked (ym2612)"))
|
||||
{
|
||||
OPN2_SetChipType(ym3438_type_ym2612);
|
||||
config.ym3438 = 1;
|
||||
}
|
||||
else if (!strcmp(var.value, "nuked (asic ym3438)"))
|
||||
{
|
||||
OPN2_SetChipType(ym3438_type_asic);
|
||||
config.ym3438 = 2;
|
||||
}
|
||||
else if (!strcmp(var.value, "nuked (discrete ym3438)"))
|
||||
{
|
||||
OPN2_SetChipType(ym3438_type_discrete);
|
||||
config.ym3438 = 3;
|
||||
}
|
||||
else
|
||||
config.ym3438 = 0;
|
||||
|
||||
if (orig_value != config.ym3438)
|
||||
if (orig_value == 0 && config.ym3438 > 0 || orig_value > 0 && config.ym3438 == 0)
|
||||
{
|
||||
sound_init();
|
||||
sound_reset();
|
||||
@ -1656,7 +1669,7 @@ void retro_set_environment(retro_environment_t cb)
|
||||
{ "genesis_plus_gx_ym2413", "Master System FM; auto|disabled|enabled" },
|
||||
{ "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", "YM2612/YM3438 core; mame|nuked (ym2612)|nuked (asic ym3438)|nuked (discrete ym3438)" },
|
||||
#endif
|
||||
|
||||
{ "genesis_plus_gx_audio_filter", "Audio filter; disabled|low-pass" },
|
||||
|
Loading…
Reference in New Issue
Block a user