mirror of
https://github.com/ekeeke/Genesis-Plus-GX.git
synced 2024-12-27 03:31:49 +01:00
Merge pull request #173 from nukeykt/ym3438
Add nuked opn2 as alternative core
This commit is contained in:
commit
8d4b95a139
@ -25,6 +25,9 @@
|
||||
#include "psg.h"
|
||||
#include "ym2413.h"
|
||||
#include "ym2612.h"
|
||||
#ifdef HAVE_YM3438_CORE
|
||||
#include "ym3438.h"
|
||||
#endif
|
||||
#include "sram.h"
|
||||
#include "ggenie.h"
|
||||
#include "areplay.h"
|
||||
|
@ -41,7 +41,12 @@
|
||||
#include "blip_buf.h"
|
||||
|
||||
/* FM output buffer (large enough to hold a whole frame at original chips rate) */
|
||||
#ifdef HAVE_YM3438_CORE
|
||||
static int fm_buffer[1080 * 2 * 24];
|
||||
#else
|
||||
static int fm_buffer[1080 * 2];
|
||||
#endif
|
||||
|
||||
static int fm_last[2];
|
||||
static int *fm_ptr;
|
||||
|
||||
@ -54,6 +59,51 @@ static uint32 fm_cycles_count;
|
||||
static void (*YM_Reset)(void);
|
||||
static void (*YM_Update)(int *buffer, int length);
|
||||
static void (*YM_Write)(unsigned int a, unsigned int v);
|
||||
static unsigned int (*YM_Read)(unsigned int a);
|
||||
|
||||
#ifdef HAVE_YM3438_CORE
|
||||
static ym3438_t ym3438;
|
||||
static int ym3438_accm[24][2];
|
||||
static int ym3438_sample[2];
|
||||
static unsigned int ym3438_cycles;
|
||||
|
||||
void YM3438_Reset(void)
|
||||
{
|
||||
OPN2_Reset(&ym3438);
|
||||
}
|
||||
|
||||
void YM3438_Update(int *buffer, int length)
|
||||
{
|
||||
int i, j;
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
OPN2_Clock(&ym3438, ym3438_accm[ym3438_cycles]);
|
||||
ym3438_cycles = (ym3438_cycles + 1) % 24;
|
||||
if (ym3438_cycles == 0)
|
||||
{
|
||||
ym3438_sample[0] = 0;
|
||||
ym3438_sample[1] = 0;
|
||||
for (j = 0; j < 24; j++)
|
||||
{
|
||||
ym3438_sample[0] += ym3438_accm[j][0];
|
||||
ym3438_sample[1] += ym3438_accm[j][1];
|
||||
}
|
||||
}
|
||||
*buffer++ = ym3438_sample[0] * 8;
|
||||
*buffer++ = ym3438_sample[1] * 8;
|
||||
}
|
||||
}
|
||||
|
||||
void YM3438_Write(unsigned int a, unsigned int v)
|
||||
{
|
||||
OPN2_Write(&ym3438, a, v);
|
||||
}
|
||||
|
||||
unsigned int YM3438_Read(unsigned int a)
|
||||
{
|
||||
return OPN2_Read(&ym3438, a);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Run FM chip until required M-cycles */
|
||||
INLINE void fm_update(unsigned int cycles)
|
||||
@ -80,14 +130,35 @@ void sound_init( void )
|
||||
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
|
||||
{
|
||||
/* YM2612 */
|
||||
YM2612Init();
|
||||
YM2612Config(config.dac_bits);
|
||||
YM_Reset = YM2612ResetChip;
|
||||
YM_Update = YM2612Update;
|
||||
YM_Write = YM2612Write;
|
||||
#ifdef HAVE_YM3438_CORE
|
||||
if (config.ym3438)
|
||||
{
|
||||
/* Nuked OPN2 */
|
||||
memset(&ym3438, 0, sizeof(ym3438));
|
||||
memset(&ym3438_sample, 0, sizeof(ym3438_sample));
|
||||
memset(&ym3438_accm, 0, sizeof(ym3438_accm));
|
||||
YM_Reset = YM3438_Reset;
|
||||
YM_Update = YM3438_Update;
|
||||
YM_Write = YM3438_Write;
|
||||
YM_Read = YM3438_Read;
|
||||
|
||||
/* chip is running at VCLK / 144 = MCLK / 7 / 144 */
|
||||
fm_cycles_ratio = 144 * 7;
|
||||
/* chip is running at VCLK / 6 = MCLK / 7 / 6 */
|
||||
fm_cycles_ratio = 6 * 7;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* MAME */
|
||||
YM2612Init();
|
||||
YM2612Config(config.dac_bits);
|
||||
YM_Reset = YM2612ResetChip;
|
||||
YM_Update = YM2612Update;
|
||||
YM_Write = YM2612Write;
|
||||
YM_Read = YM2612Read;
|
||||
|
||||
/* chip is running at VCLK / 144 = MCLK / 7 / 144 */
|
||||
fm_cycles_ratio = 144 * 7;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -96,6 +167,7 @@ void sound_init( void )
|
||||
YM_Reset = YM2413ResetChip;
|
||||
YM_Update = YM2413Update;
|
||||
YM_Write = YM2413Write;
|
||||
YM_Read = NULL;
|
||||
|
||||
/* chip is running at ZCLK / 72 = MCLK / 15 / 72 */
|
||||
fm_cycles_ratio = 72 * 15;
|
||||
@ -204,7 +276,23 @@ int sound_context_save(uint8 *state)
|
||||
|
||||
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
|
||||
{
|
||||
#ifdef HAVE_YM3438_CORE
|
||||
save_param(&config.ym3438, sizeof(config.ym3438));
|
||||
if (config.ym3438)
|
||||
{
|
||||
save_param(&ym3438, sizeof(ym3438));
|
||||
save_param(&ym3438_accm, sizeof(ym3438_accm));
|
||||
save_param(&ym3438_sample, sizeof(ym3438_sample));
|
||||
save_param(&ym3438_cycles, sizeof(ym3438_cycles));
|
||||
}
|
||||
else
|
||||
{
|
||||
bufferptr += YM2612SaveContext(state + sizeof(config.ym3438));
|
||||
YM2612Config(config.dac_bits);
|
||||
}
|
||||
#else
|
||||
bufferptr = YM2612SaveContext(state);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -221,11 +309,28 @@ int sound_context_save(uint8 *state)
|
||||
int sound_context_load(uint8 *state)
|
||||
{
|
||||
int bufferptr = 0;
|
||||
uint8 config_ym3438;
|
||||
|
||||
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
|
||||
{
|
||||
#ifdef HAVE_YM3438_CORE
|
||||
load_param(&config_ym3438, sizeof(config_ym3438));
|
||||
if (config_ym3438)
|
||||
{
|
||||
load_param(&ym3438, sizeof(ym3438));
|
||||
load_param(&ym3438_accm, sizeof(ym3438_accm));
|
||||
load_param(&ym3438_sample, sizeof(ym3438_sample));
|
||||
load_param(&ym3438_cycles, sizeof(ym3438_cycles));
|
||||
}
|
||||
else
|
||||
{
|
||||
bufferptr += YM2612LoadContext(state + sizeof(config_ym3438));
|
||||
YM2612Config(config.dac_bits);
|
||||
}
|
||||
#else
|
||||
bufferptr = YM2612LoadContext(state);
|
||||
YM2612Config(config.dac_bits);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -251,11 +356,8 @@ void fm_reset(unsigned int cycles)
|
||||
|
||||
void fm_write(unsigned int cycles, unsigned int address, unsigned int data)
|
||||
{
|
||||
/* synchronize FM chip with CPU (on data port write only) */
|
||||
if (address & 1)
|
||||
{
|
||||
fm_update(cycles);
|
||||
}
|
||||
/* synchronize FM chip with CPU */
|
||||
fm_update(cycles);
|
||||
|
||||
/* write FM register */
|
||||
YM_Write(address, data);
|
||||
@ -267,5 +369,5 @@ unsigned int fm_read(unsigned int cycles, unsigned int address)
|
||||
fm_update(cycles);
|
||||
|
||||
/* read FM status (YM2612 only) */
|
||||
return YM2612Read();
|
||||
return YM_Read(address);
|
||||
}
|
||||
|
@ -1981,7 +1981,7 @@ void YM2612Write(unsigned int a, unsigned int v)
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int YM2612Read(void)
|
||||
unsigned int YM2612Read(unsigned int a)
|
||||
{
|
||||
return ym2612.OPN.ST.status & 0xff;
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ extern void YM2612Config(unsigned char dac_bits);
|
||||
extern void YM2612ResetChip(void);
|
||||
extern void YM2612Update(int *buffer, int length);
|
||||
extern void YM2612Write(unsigned int a, unsigned int v);
|
||||
extern unsigned int YM2612Read(void);
|
||||
extern unsigned int YM2612Read(unsigned int a);
|
||||
extern int YM2612LoadContext(unsigned char *state);
|
||||
extern int YM2612SaveContext(unsigned char *state);
|
||||
|
||||
|
1383
core/sound/ym3438.c
Normal file
1383
core/sound/ym3438.c
Normal file
File diff suppressed because it is too large
Load Diff
211
core/sound/ym3438.h
Normal file
211
core/sound/ym3438.h
Normal file
@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Alexey Khokholov (Nuke.YKT)
|
||||
*
|
||||
* Redistribution and use of this code or any derivative works are permitted
|
||||
* provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions may not be sold, nor may they be used in a commercial
|
||||
* product or activity.
|
||||
*
|
||||
* - Redistributions that are modified from the original source must include the
|
||||
* complete source code, including the source code for all components used by a
|
||||
* binary built from the modified sources. However, as a special exception, the
|
||||
* source code distributed need not include anything that is normally distributed
|
||||
* (in either source or binary form) with the major components (compiler, kernel,
|
||||
* and so on) of the operating system on which the executable runs, unless that
|
||||
* component itself accompanies the executable.
|
||||
*
|
||||
* - Redistributions must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*
|
||||
* Nuked OPN2(Yamaha YM3438) emulator.
|
||||
* Thanks:
|
||||
* Silicon Pr0n:
|
||||
* Yamaha YM3438 decap and die shot(digshadow).
|
||||
* OPLx decapsulated(Matthew Gambrell, Olli Niemitalo):
|
||||
* OPL2 ROMs.
|
||||
*
|
||||
* version: 1.0.2
|
||||
*/
|
||||
|
||||
#ifndef YM3438_H
|
||||
#define YM3438_H
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
typedef uintptr_t Bitu;
|
||||
typedef intptr_t Bits;
|
||||
typedef uint64_t Bit64u;
|
||||
typedef int64_t Bit64s;
|
||||
typedef uint32_t Bit32u;
|
||||
typedef int32_t Bit32s;
|
||||
typedef uint16_t Bit16u;
|
||||
typedef int16_t Bit16s;
|
||||
typedef uint8_t Bit8u;
|
||||
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];
|
||||
} ym3438_t;
|
||||
|
||||
void OPN2_Reset(ym3438_t *chip);
|
||||
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);
|
||||
Bit32u OPN2_ReadTestPin(ym3438_t *chip);
|
||||
Bit32u OPN2_ReadIRQPin(ym3438_t *chip);
|
||||
Bit8u OPN2_Read(ym3438_t *chip, Bit32u port);
|
||||
#endif
|
@ -1092,6 +1092,20 @@ static void check_variables(void)
|
||||
YM2612Config(config.dac_bits);
|
||||
}
|
||||
|
||||
#ifdef HAVE_YM3438_CORE
|
||||
var.key = "genesis_plus_gx_ym3438";
|
||||
environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var);
|
||||
{
|
||||
if (!strcmp(var.value, "nuked opn2"))
|
||||
config.ym3438 = 1;
|
||||
else
|
||||
config.ym3438 = 0;
|
||||
|
||||
sound_init();
|
||||
sound_reset();
|
||||
}
|
||||
#endif
|
||||
|
||||
var.key = "genesis_plus_gx_blargg_ntsc_filter";
|
||||
environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var);
|
||||
{
|
||||
@ -1628,6 +1642,11 @@ void retro_set_environment(retro_environment_t cb)
|
||||
{ "genesis_plus_gx_lock_on", "Cartridge lock-on; disabled|game genie|action replay (pro)|sonic & knuckles" },
|
||||
{ "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" },
|
||||
#endif
|
||||
|
||||
{ "genesis_plus_gx_audio_filter", "Audio filter; disabled|low-pass" },
|
||||
{ "genesis_plus_gx_lowpass_range", "Low-pass filter %; 60|65|70|75|80|85|90|95|5|10|15|20|25|30|35|40|45|50|55"},
|
||||
|
||||
|
@ -54,6 +54,7 @@
|
||||
<ClCompile Include="..\..\..\core\sound\sound.c" />
|
||||
<ClCompile Include="..\..\..\core\sound\ym2413.c" />
|
||||
<ClCompile Include="..\..\..\core\sound\ym2612.c" />
|
||||
<ClCompile Include="..\..\..\core\sound\ym3438.c" />
|
||||
<ClCompile Include="..\..\..\core\state.c" />
|
||||
<ClCompile Include="..\..\..\core\system.c" />
|
||||
<ClCompile Include="..\..\..\core\tremor\bitwise.c" />
|
||||
|
@ -74,6 +74,8 @@ typedef unsigned char bool;
|
||||
|
||||
#define CHEATS_UPDATE() ROMCheatUpdate()
|
||||
|
||||
#define HAVE_YM3438_CORE
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int8 device;
|
||||
@ -89,6 +91,9 @@ struct
|
||||
uint8 hq_psg;
|
||||
uint8 dac_bits;
|
||||
uint8 ym2413;
|
||||
#ifdef HAVE_YM3438_CORE
|
||||
uint8 ym3438;
|
||||
#endif
|
||||
uint8 mono;
|
||||
int16 psg_preamp;
|
||||
int16 fm_preamp;
|
||||
|
Loading…
Reference in New Issue
Block a user