3 Commits

Author SHA1 Message Date
clobber c5df0565e6 Bump version for sparkle updater 2018-03-18 14:28:39 -05:00
clobber c06e10d458 SG/MD/SCD/MCD: Fix PAR 2018-03-18 14:28:11 -05:00
clobber 0419c81f9e Sync with https://github.com/ekeeke/Genesis-Plus-GX/commit/726b7112d806ae23694b2a1634d8d866c87c4864 2018-03-18 13:43:08 -05:00
13 changed files with 387 additions and 262 deletions
+11 -6
View File
@@ -197,7 +197,7 @@ static __weak GenPlusGameCore *_current;
if([[self systemIdentifier] isEqualToString:@"openemu.system.sg"] || [[self systemIdentifier] isEqualToString:@"openemu.system.scd"])
{
// Set initial viewport size because the system briefly outputs 256x192 when it boots
bitmap.viewport.w = 320;
bitmap.viewport.w = 292;
bitmap.viewport.h = 224;
}
@@ -312,7 +312,9 @@ static __weak GenPlusGameCore *_current;
}
else
{
return OEIntSizeMake(4, 3); // TODO: Correct PAR.
// H32 mode (256px * 8:7 PAR)
// H40 mode (320px * 32:35 PAR)
return OEIntSizeMake(292, 224);
}
}
@@ -572,11 +574,11 @@ const int MasterSystemMap[] = {INPUT_UP, INPUT_DOWN, INPUT_LEFT, INPUT_RIGHT, IN
if (bitmap.viewport.w == 320)
{
input.analog[4][0] = aPoint.x;
input.analog[4][1] = aPoint.y * 0.933333;
input.analog[4][1] = aPoint.y * 0.912500;
}
else // w == 256
{
input.analog[4][0] = aPoint.x * 0.857143;
input.analog[4][0] = aPoint.x * 0.876712;
input.analog[4][1] = aPoint.y;
}
}
@@ -708,15 +710,18 @@ const int MasterSystemMap[] = {INPUT_UP, INPUT_DOWN, INPUT_LEFT, INPUT_RIGHT, IN
config.hq_fm = 1; /* high-quality FM resampling (slower) */
config.hq_psg = 1; /* high-quality PSG resampling (slower) */
config.filter = 0; /* no filter */
config.lp_range = 0x9999; /* 0.6 in 16.16 fixed point */
config.lp_range = 0x7fff; /* 0.5 in 0.16 fixed point */
config.low_freq = 880;
config.high_freq = 5000;
config.lg = 100;
config.mg = 100;
config.hg = 100;
config.dac_bits = 14; /* MAX DEPTH */
config.ym2612 = YM2612_DISCRETE;
config.ym2413 = 2; /* AUTO */
config.mono = 0; /* STEREO output */
#ifdef HAVE_YM3438_CORE
config.ym3438 = 0;
#endif
/* system options */
config.system = 0; /* AUTO */
+1 -1
View File
@@ -19,7 +19,7 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.7.4.7</string>
<string>1.7.4.8</string>
<key>NSPrincipalClass</key>
<string>OEGameCoreController</string>
<key>OEGameCoreClass</key>
+5 -5
View File
@@ -5,7 +5,7 @@
* Support for SG-1000, Mark-III, Master System, Game Gear, Mega Drive & Mega CD hardware
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2018 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@@ -474,8 +474,8 @@ void gen_zbusreq_w(unsigned int data, unsigned int cycles)
/* check if Z80 is going to be restarted */
if (zstate == 3)
{
/* resynchronize with 68k */
Z80.cycles = cycles;
/* resynchronize with 68k (Z80 cycles should remain a multiple of 15 MClocks) */
Z80.cycles = ((cycles + 14) / 15) * 15;
/* disable 68k access to Z80 bus */
m68k.memory_map[0xa0].read8 = m68k_read_bus_8;
@@ -496,8 +496,8 @@ void gen_zreset_w(unsigned int data, unsigned int cycles)
/* check if Z80 is going to be restarted */
if (zstate == 0)
{
/* resynchronize with 68k */
Z80.cycles = cycles;
/* resynchronize with 68k (Z80 cycles should remain a multiple of 15 MClocks) */
Z80.cycles = ((cycles + 14) / 15) * 15;
/* reset Z80 & YM2612 */
z80_reset();
+1 -1
View File
@@ -5,7 +5,7 @@
* Support for SG-1000, Mark-III, Master System, Game Gear, Mega Drive & Mega CD hardware
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2018 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
+211 -135
View File
@@ -3,7 +3,7 @@
* Sound Hardware
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2018 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@@ -40,6 +40,9 @@
#include "shared.h"
#include "blip_buf.h"
/* YM2612 internal clock = input clock / 6 = (master clock / 7) / 6 */
#define YM2612_CLOCK_RATIO (7*6)
/* 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];
@@ -51,28 +54,121 @@ static int fm_last[2];
static int *fm_ptr;
/* Cycle-accurate FM samples */
static uint32 fm_cycles_ratio;
static uint32 fm_cycles_start;
static uint32 fm_cycles_count;
static int fm_cycles_ratio;
static int fm_cycles_start;
static int fm_cycles_count;
static int fm_cycles_busy;
/* YM chip function pointers */
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);
void (*fm_reset)(unsigned int cycles);
void (*fm_write)(unsigned int cycles, unsigned int address, unsigned int data);
unsigned int (*fm_read)(unsigned int cycles, unsigned int address);
#ifdef HAVE_YM3438_CORE
static ym3438_t ym3438;
static int ym3438_accm[24][2];
static short ym3438_accm[24][2];
static int ym3438_sample[2];
static unsigned int ym3438_cycles;
static int ym3438_cycles;
#endif
void YM3438_Reset(void)
/* Run FM chip until required M-cycles */
INLINE void fm_update(int cycles)
{
OPN2_Reset(&ym3438);
if (cycles > fm_cycles_count)
{
/* number of samples to run */
int samples = (cycles - fm_cycles_count + fm_cycles_ratio - 1) / fm_cycles_ratio;
/* run FM chip to sample buffer */
YM_Update(fm_ptr, samples);
/* update FM buffer pointer */
fm_ptr += (samples * 2);
/* update FM cycle counter */
fm_cycles_count += (samples * fm_cycles_ratio);
}
}
void YM3438_Update(int *buffer, int length)
static void YM2612_Reset(unsigned int cycles)
{
/* synchronize FM chip with CPU */
fm_update(cycles);
/* reset FM chip */
YM2612ResetChip();
fm_cycles_busy = 0;
}
static void YM2612_Write(unsigned int cycles, unsigned int a, unsigned int v)
{
/* detect DATA port write */
if (a & 1)
{
/* synchronize FM chip with CPU */
fm_update(cycles);
/* set FM BUSY end cycle (discrete or ASIC-integrated YM2612 chip only) */
if (config.ym2612 < YM2612_ENHANCED)
{
fm_cycles_busy = (((cycles + YM2612_CLOCK_RATIO - 1) / YM2612_CLOCK_RATIO) + 32) * YM2612_CLOCK_RATIO;
}
}
/* write FM register */
YM2612Write(a, v);
}
static unsigned int YM2612_Read(unsigned int cycles, unsigned int a)
{
/* FM status can only be read from (A0,A1)=(0,0) on discrete YM2612 */
if ((a == 0) || (config.ym2612 > YM2612_DISCRETE))
{
/* synchronize FM chip with CPU */
fm_update(cycles - fm_cycles_ratio + 1);
/* read FM status */
if (cycles >= fm_cycles_busy)
{
/* BUSY flag cleared */
return YM2612Read();
}
else
{
/* BUSY flag set */
return YM2612Read() | 0x80;
}
}
/* invalid FM status address */
return 0x00;
}
static void YM2413_Reset(unsigned int cycles)
{
/* synchronize FM chip with CPU */
fm_update(cycles);
/* reset FM chip */
YM2413ResetChip();
}
static void YM2413_Write(unsigned int cycles, unsigned int a, unsigned int v)
{
/* detect DATA port write */
if (a & 1)
{
/* synchronize FM chip with CPU */
fm_update(cycles);
}
/* write FM register */
YM2413Write(a, v);
}
#ifdef HAVE_YM3438_CORE
static void YM3438_Update(int *buffer, int length)
{
int i, j;
for (i = 0; i < length; i++)
@@ -94,36 +190,34 @@ void YM3438_Update(int *buffer, int length)
}
}
void YM3438_Write(unsigned int a, unsigned int v)
static void YM3438_Reset(unsigned int cycles)
{
/* synchronize FM chip with CPU */
fm_update(cycles);
/* reset FM chip */
OPN2_Reset(&ym3438);
}
static void YM3438_Write(unsigned int cycles, unsigned int a, unsigned int v)
{
/* synchronize FM chip with CPU */
fm_update(cycles);
/* write FM register */
OPN2_Write(&ym3438, a, v);
}
unsigned int YM3438_Read(unsigned int a)
static unsigned int YM3438_Read(unsigned int cycles, unsigned int a)
{
/* synchronize FM chip with CPU */
fm_update(cycles - fm_cycles_ratio + 1);
/* read FM status */
return OPN2_Read(&ym3438, a);
}
#endif
/* Run FM chip until required M-cycles */
INLINE void fm_update(unsigned int cycles)
{
if (cycles > fm_cycles_count)
{
/* number of samples to run */
unsigned int samples = (cycles - fm_cycles_count + fm_cycles_ratio - 1) / fm_cycles_ratio;
/* run FM chip to sample buffer */
YM_Update(fm_ptr, samples);
/* update FM buffer pointer */
fm_ptr += (samples << 1);
/* update FM cycle counter */
fm_cycles_count += samples * fm_cycles_ratio;
}
}
void sound_init( void )
{
/* Initialize FM chip */
@@ -137,37 +231,37 @@ void sound_init( void )
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;
fm_reset = YM3438_Reset;
fm_write = YM3438_Write;
fm_read = YM3438_Read;
/* chip is running at VCLK / 6 = MCLK / 7 / 6 */
fm_cycles_ratio = 6 * 7;
/* chip is running at internal clock */
fm_cycles_ratio = YM2612_CLOCK_RATIO;
}
else
#endif
{
/* MAME */
/* MAME OPN2*/
YM2612Init();
YM2612Config(config.dac_bits);
YM_Reset = YM2612ResetChip;
YM2612Config(config.ym2612);
YM_Update = YM2612Update;
YM_Write = YM2612Write;
YM_Read = YM2612Read;
fm_reset = YM2612_Reset;
fm_write = YM2612_Write;
fm_read = YM2612_Read;
/* chip is running at VCLK / 144 = MCLK / 7 / 144 */
fm_cycles_ratio = 144 * 7;
/* chip is running at sample clock */
fm_cycles_ratio = YM2612_CLOCK_RATIO * 24;
}
}
else
{
/* YM2413 */
YM2413Init();
YM_Reset = YM2413ResetChip;
YM_Update = YM2413Update;
YM_Write = YM2413Write;
YM_Read = NULL;
YM_Update = (config.ym2413 & 1) ? YM2413Update : NULL;
fm_reset = YM2413_Reset;
fm_write = YM2413_Write;
fm_read = NULL;
/* chip is running at ZCLK / 72 = MCLK / 15 / 72 */
fm_cycles_ratio = 72 * 15;
@@ -180,7 +274,7 @@ void sound_init( void )
void sound_reset(void)
{
/* reset sound chips */
YM_Reset();
fm_reset(0);
psg_reset();
psg_config(0, config.psg_preamp, 0xff);
@@ -196,73 +290,85 @@ void sound_reset(void)
int sound_update(unsigned int cycles)
{
int prev_l, prev_r, preamp, time, l, r, *ptr;
/* Run PSG chip until end of frame */
psg_end_frame(cycles);
/* Run FM chip until end of frame */
fm_update(cycles);
/* FM output pre-amplification */
preamp = config.fm_preamp;
/* FM frame initial timestamp */
time = fm_cycles_start;
/* Restore last FM outputs from previous frame */
prev_l = fm_last[0];
prev_r = fm_last[1];
/* FM buffer start pointer */
ptr = fm_buffer;
/* flush FM samples */
if (config.hq_fm)
/* FM chip is enabled ? */
if (YM_Update)
{
/* high-quality Band-Limited synthesis */
do
int prev_l, prev_r, preamp, time, l, r, *ptr;
/* Run FM chip until end of frame */
fm_update(cycles);
/* FM output pre-amplification */
preamp = config.fm_preamp;
/* FM frame initial timestamp */
time = fm_cycles_start;
/* Restore last FM outputs from previous frame */
prev_l = fm_last[0];
prev_r = fm_last[1];
/* FM buffer start pointer */
ptr = fm_buffer;
/* flush FM samples */
if (config.hq_fm)
{
/* left & right channels */
l = ((*ptr++ * preamp) / 100);
r = ((*ptr++ * preamp) / 100);
blip_add_delta(snd.blips[0], time, l-prev_l, r-prev_r);
prev_l = l;
prev_r = r;
/* high-quality Band-Limited synthesis */
do
{
/* left & right channels */
l = ((*ptr++ * preamp) / 100);
r = ((*ptr++ * preamp) / 100);
blip_add_delta(snd.blips[0], time, l-prev_l, r-prev_r);
prev_l = l;
prev_r = r;
/* increment time counter */
time += fm_cycles_ratio;
/* increment time counter */
time += fm_cycles_ratio;
}
while (time < cycles);
}
while (time < cycles);
}
else
{
/* faster Linear Interpolation */
do
else
{
/* left & right channels */
l = ((*ptr++ * preamp) / 100);
r = ((*ptr++ * preamp) / 100);
blip_add_delta_fast(snd.blips[0], time, l-prev_l, r-prev_r);
prev_l = l;
prev_r = r;
/* faster Linear Interpolation */
do
{
/* left & right channels */
l = ((*ptr++ * preamp) / 100);
r = ((*ptr++ * preamp) / 100);
blip_add_delta_fast(snd.blips[0], time, l-prev_l, r-prev_r);
prev_l = l;
prev_r = r;
/* increment time counter */
time += fm_cycles_ratio;
/* increment time counter */
time += fm_cycles_ratio;
}
while (time < cycles);
}
/* reset FM buffer pointer */
fm_ptr = fm_buffer;
/* save last FM output for next frame */
fm_last[0] = prev_l;
fm_last[1] = prev_r;
/* adjust FM cycle counters for next frame */
fm_cycles_count = fm_cycles_start = time - cycles;
if (fm_cycles_busy > cycles)
{
fm_cycles_busy -= cycles;
}
else
{
fm_cycles_busy = 0;
}
while (time < cycles);
}
/* reset FM buffer pointer */
fm_ptr = fm_buffer;
/* save last FM output for next frame */
fm_last[0] = prev_l;
fm_last[1] = prev_r;
/* adjust FM cycle counters for next frame */
fm_cycles_count = fm_cycles_start = time - cycles;
/* end of blip buffer time frame */
blip_end_frame(snd.blips[0], cycles);
@@ -288,7 +394,6 @@ int sound_context_save(uint8 *state)
else
{
bufferptr += YM2612SaveContext(state + sizeof(config.ym3438));
YM2612Config(config.dac_bits);
}
#else
bufferptr = YM2612SaveContext(state);
@@ -325,11 +430,9 @@ int sound_context_load(uint8 *state)
else
{
bufferptr += YM2612LoadContext(state + sizeof(config_ym3438));
YM2612Config(config.dac_bits);
}
#else
bufferptr = YM2612LoadContext(state);
YM2612Config(config.dac_bits);
#endif
}
else
@@ -344,30 +447,3 @@ int sound_context_load(uint8 *state)
return bufferptr;
}
void fm_reset(unsigned int cycles)
{
/* synchronize FM chip with CPU */
fm_update(cycles);
/* reset FM chip */
YM_Reset();
}
void fm_write(unsigned int cycles, unsigned int address, unsigned int data)
{
/* synchronize FM chip with CPU */
fm_update(cycles);
/* write FM register */
YM_Write(address, data);
}
unsigned int fm_read(unsigned int cycles, unsigned int address)
{
/* synchronize FM chip with CPU */
fm_update(cycles);
/* read FM status (YM2612 only) */
return YM_Read(address);
}
+4 -4
View File
@@ -3,7 +3,7 @@
* Sound Hardware
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2016 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2018 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@@ -46,8 +46,8 @@ extern void sound_reset(void);
extern int sound_context_save(uint8 *state);
extern int sound_context_load(uint8 *state);
extern int sound_update(unsigned int cycles);
extern void fm_reset(unsigned int cycles);
extern void fm_write(unsigned int cycles, unsigned int address, unsigned int data);
extern unsigned int fm_read(unsigned int cycles, unsigned int address);
extern void (*fm_reset)(unsigned int cycles);
extern void (*fm_write)(unsigned int cycles, unsigned int address, unsigned int data);
extern unsigned int (*fm_read)(unsigned int cycles, unsigned int address);
#endif /* _SOUND_H_ */
+111 -47
View File
@@ -15,15 +15,16 @@
** Additional info from YM2612 die shot analysis by Sauraen
** See http://gendev.spritesmind.net/forum/viewtopic.php?t=386
**
** TODO:
** - better documentation
** - BUSY flag emulation
** - accurate DAC output
*/
/*
** CHANGELOG:
**
** 03-12-2017 Eke-Eke (Genesis Plus GX):
** - improved 9-bit DAC emulation accuracy
** - added discrete YM2612 DAC distortion emulation ("ladder effect")
** - replaced configurable DAC depth with configurable chip types (discrete, integrated or enhanced)
**
** 26-09-2017 Eke-Eke (Genesis Plus GX):
** - fixed EG counter loopback behavior (verified on YM3438 die)
** - reverted changes to EG rates 2-7 increment values
@@ -626,8 +627,11 @@ static YM2612 ym2612;
/* current chip state */
static INT32 m2,c1,c2; /* Phase Modulation input for operators 2,3,4 */
static INT32 mem; /* one sample delay memory */
static INT32 out_fm[8]; /* outputs of working channels */
static UINT32 bitmask; /* working channels output bitmasking (DAC quantization) */
static INT32 out_fm[6]; /* outputs of working channels */
/* chip type */
static UINT32 op_mask[8][4]; /* operator output bitmasking (DAC quantization) */
static int chip_type = YM2612_DISCRETE;
INLINE void FM_KEYON(FM_CH *CH , int s )
@@ -1408,22 +1412,22 @@ INLINE void refresh_fc_eg_chan(FM_CH *CH )
#define volume_calc(OP) ((OP)->vol_out + (AM & (OP)->AMmask))
INLINE signed int op_calc(UINT32 phase, unsigned int env, unsigned int pm)
INLINE signed int op_calc(UINT32 phase, unsigned int env, unsigned int pm, unsigned int opmask)
{
UINT32 p = (env<<3) + sin_tab[ ( (phase >> SIN_BITS) + (pm >> 1) ) & SIN_MASK ];
if (p >= TL_TAB_LEN)
return 0;
return tl_tab[p];
return (tl_tab[p] & opmask);
}
INLINE signed int op_calc1(UINT32 phase, unsigned int env, unsigned int pm)
INLINE signed int op_calc1(UINT32 phase, unsigned int env, unsigned int pm, unsigned int opmask)
{
UINT32 p = (env<<3) + sin_tab[ ( ( phase >> SIN_BITS ) + pm ) & SIN_MASK ];
if (p >= TL_TAB_LEN)
return 0;
return tl_tab[p];
return (tl_tab[p] & opmask);
}
INLINE void chan_calc(FM_CH *CH, int num)
@@ -1433,6 +1437,7 @@ INLINE void chan_calc(FM_CH *CH, int num)
INT32 out = 0;
UINT32 AM = ym2612.OPN.LFO_AM >> CH->ams;
unsigned int eg_out = volume_calc(&CH->SLOT[SLOT1]);
UINT32 *mask = op_mask[CH->ALGO];
m2 = c1 = c2 = mem = 0;
@@ -1443,7 +1448,7 @@ INLINE void chan_calc(FM_CH *CH, int num)
if (CH->FB < SIN_BITS)
out = (CH->op1_out[0] + CH->op1_out[1]) >> CH->FB;
out = op_calc1(CH->SLOT[SLOT1].phase, eg_out, out );
out = op_calc1(CH->SLOT[SLOT1].phase, eg_out, out, mask[0]);
}
CH->op1_out[0] = CH->op1_out[1];
@@ -1459,22 +1464,21 @@ INLINE void chan_calc(FM_CH *CH, int num)
eg_out = volume_calc(&CH->SLOT[SLOT3]);
if( eg_out < ENV_QUIET ) /* SLOT 3 */
*CH->connect3 += op_calc(CH->SLOT[SLOT3].phase, eg_out, m2);
*CH->connect3 += op_calc(CH->SLOT[SLOT3].phase, eg_out, m2, mask[2]);
eg_out = volume_calc(&CH->SLOT[SLOT2]);
if( eg_out < ENV_QUIET ) /* SLOT 2 */
*CH->connect2 += op_calc(CH->SLOT[SLOT2].phase, eg_out, c1);
*CH->connect2 += op_calc(CH->SLOT[SLOT2].phase, eg_out, c1, mask[1]);
eg_out = volume_calc(&CH->SLOT[SLOT4]);
if( eg_out < ENV_QUIET ) /* SLOT 4 */
*CH->connect4 += op_calc(CH->SLOT[SLOT4].phase, eg_out, c2);
*CH->connect4 += op_calc(CH->SLOT[SLOT4].phase, eg_out, c2, mask[3]);
/* store current MEM */
CH->mem_value = mem;
/* update phase counters AFTER output calculations */
if(CH->pms)
if (CH->pms)
{
/* 3-slot mode */
if ((ym2612.OPN.ST.mode & 0xC0) && (CH == &ym2612.CH[2]))
@@ -1515,7 +1519,7 @@ INLINE void OPNWriteMode(int r, int v)
case 0x21: /* Test */
break;
case 0x22: /* LFO FREQ (YM2608/YM2610/YM2610B/ym2612) */
case 0x22: /* LFO FREQ */
if (v&8) /* LFO enabled ? */
{
ym2612.OPN.lfo_timer_overflow = lfo_samples_per_step[v&7];
@@ -1550,7 +1554,6 @@ INLINE void OPNWriteMode(int r, int v)
if( c == 3 ) break;
if (v&0x04) c+=3; /* CH 4-6 */
CH = &ym2612.CH[c];
if (v&0x10) FM_KEYON(CH,SLOT1); else FM_KEYOFF(CH,SLOT1);
if (v&0x20) FM_KEYON(CH,SLOT2); else FM_KEYOFF(CH,SLOT2);
if (v&0x40) FM_KEYON(CH,SLOT3); else FM_KEYOFF(CH,SLOT3);
@@ -1686,8 +1689,6 @@ INLINE void OPNWriteReg(int r, int v)
That is not necessary, but then EG will be generating Attack phase.
*/
break;
case 0xa0:
@@ -1722,7 +1723,7 @@ INLINE void OPNWriteReg(int r, int v)
ym2612.OPN.SL3.block_fnum[c] = (blk<<11) | fn;
ym2612.CH[2].SLOT[SLOT1].Incr=-1;
}
break;
break;
case 3: /* 0xac-0xae : 3CH FNUM2,BLK */
if(r < 0x100)
ym2612.OPN.SL3.fn_h = v&0x3f;
@@ -1737,7 +1738,7 @@ INLINE void OPNWriteReg(int r, int v)
CH->ALGO = v&7;
CH->FB = SIN_BITS - ((v>>3)&7);
setup_connection( CH, c );
break;
break;
}
case 1: /* 0xb4-0xb6 : L , R , AMS , PMS */
/* b0-2 PMS */
@@ -1747,8 +1748,8 @@ INLINE void OPNWriteReg(int r, int v)
CH->ams = lfo_ams_depth_shift[(v>>4) & 0x03];
/* PAN : b7 = L, b6 = R */
ym2612.OPN.pan[ c*2 ] = (v & 0x80) ? bitmask : 0;
ym2612.OPN.pan[ c*2+1 ] = (v & 0x40) ? bitmask : 0;
ym2612.OPN.pan[ c*2 ] = (v & 0x80) ? 0xffffffff : 0;
ym2612.OPN.pan[ c*2+1 ] = (v & 0x40) ? 0xffffffff : 0;
break;
}
break;
@@ -1884,6 +1885,15 @@ static void init_tables(void)
}
}
/* build default OP mask table */
for (i = 0;i < 8;i++)
{
for (d = 0;d < 4;d++)
{
op_mask[i][d] = 0xffffffff;
}
}
}
@@ -1984,9 +1994,9 @@ void YM2612Write(unsigned int a, unsigned int v)
}
}
unsigned int YM2612Read(unsigned int a)
unsigned int YM2612Read(void)
{
return ym2612.OPN.ST.status & 0xff;
return ym2612.OPN.ST.status;
}
/* Generate samples for ym2612 */
@@ -2020,7 +2030,7 @@ void YM2612Update(int *buffer, int length)
refresh_fc_eg_chan(&ym2612.CH[5]);
/* buffering */
for(i=0; i<length ; i++)
for(i=0; i<length; i++)
{
/* clear outputs */
out_fm[0] = 0;
@@ -2066,21 +2076,21 @@ void YM2612Update(int *buffer, int length)
advance_eg_channels(&ym2612.CH[0], ym2612.OPN.eg_cnt);
}
/* 14-bit accumulator channels outputs (range is -8192;+8192) */
if (out_fm[0] > 8192) out_fm[0] = 8192;
/* channels accumulator output clipping (14-bit max) */
if (out_fm[0] > 8191) out_fm[0] = 8191;
else if (out_fm[0] < -8192) out_fm[0] = -8192;
if (out_fm[1] > 8192) out_fm[1] = 8192;
if (out_fm[1] > 8191) out_fm[1] = 8191;
else if (out_fm[1] < -8192) out_fm[1] = -8192;
if (out_fm[2] > 8192) out_fm[2] = 8192;
if (out_fm[2] > 8191) out_fm[2] = 8191;
else if (out_fm[2] < -8192) out_fm[2] = -8192;
if (out_fm[3] > 8192) out_fm[3] = 8192;
if (out_fm[3] > 8191) out_fm[3] = 8191;
else if (out_fm[3] < -8192) out_fm[3] = -8192;
if (out_fm[4] > 8192) out_fm[4] = 8192;
if (out_fm[4] > 8191) out_fm[4] = 8191;
else if (out_fm[4] < -8192) out_fm[4] = -8192;
if (out_fm[5] > 8192) out_fm[5] = 8192;
if (out_fm[5] > 8191) out_fm[5] = 8191;
else if (out_fm[5] < -8192) out_fm[5] = -8192;
/* stereo DAC channels outputs mixing */
/* stereo DAC output panning & mixing */
lt = ((out_fm[0]) & ym2612.OPN.pan[0]);
rt = ((out_fm[0]) & ym2612.OPN.pan[1]);
lt += ((out_fm[1]) & ym2612.OPN.pan[2]);
@@ -2094,11 +2104,34 @@ void YM2612Update(int *buffer, int length)
lt += ((out_fm[5]) & ym2612.OPN.pan[10]);
rt += ((out_fm[5]) & ym2612.OPN.pan[11]);
/* discrete YM2612 DAC */
if (chip_type == YM2612_DISCRETE)
{
int i;
/* DAC 'ladder effect' */
for (i=0; i<6; i++)
{
if (out_fm[i] < 0)
{
/* -4 offset (-3 when not muted) on negative channel output (9-bit) */
lt -= ((4 - (ym2612.OPN.pan[(2*i)+0] & 1)) << 5);
rt -= ((4 - (ym2612.OPN.pan[(2*i)+1] & 1)) << 5);
}
else
{
/* +4 offset (when muted or not) on positive channel output (9-bit) */
lt += (4 << 5);
rt += (4 << 5);
}
}
}
/* buffering */
*buffer++ = lt;
*buffer++ = rt;
/* CSM mode: if CSM Key ON has occured, CSM Key OFF need to be sent */
/* CSM mode: if CSM Key ON has occurred, CSM Key OFF need to be sent */
/* only if Timer A does not overflow again (i.e CSM Key ON not set again) */
ym2612.OPN.SL3.key_csm <<= 1;
@@ -2121,20 +2154,51 @@ void YM2612Update(int *buffer, int length)
INTERNAL_TIMER_B(length);
}
void YM2612Config(unsigned char dac_bits)
void YM2612Config(int type)
{
int i;
/* YM2612 chip type */
chip_type = type;
/* DAC precision (normally 9-bit on real hardware, implemented through simple 14-bit channel output bitmasking) */
bitmask = ~((1 << (TL_BITS - dac_bits)) - 1);
/* update L/R panning bitmasks */
for (i=0; i<2*6; i++)
/* carrier operator outputs bitmask */
if (chip_type < YM2612_ENHANCED)
{
if (ym2612.OPN.pan[i])
{
ym2612.OPN.pan[i] = bitmask;
}
/* 9-bit DAC */
op_mask[0][3] = 0xffffffe0;
op_mask[1][3] = 0xffffffe0;
op_mask[2][3] = 0xffffffe0;
op_mask[3][3] = 0xffffffe0;
op_mask[4][1] = 0xffffffe0;
op_mask[4][3] = 0xffffffe0;
op_mask[5][1] = 0xffffffe0;
op_mask[5][2] = 0xffffffe0;
op_mask[5][3] = 0xffffffe0;
op_mask[6][1] = 0xffffffe0;
op_mask[6][2] = 0xffffffe0;
op_mask[6][3] = 0xffffffe0;
op_mask[7][0] = 0xffffffe0;
op_mask[7][1] = 0xffffffe0;
op_mask[7][2] = 0xffffffe0;
op_mask[7][3] = 0xffffffe0;
}
else
{
/* 14-bit DAC */
op_mask[0][3] = 0xffffffff;
op_mask[1][3] = 0xffffffff;
op_mask[2][3] = 0xffffffff;
op_mask[3][3] = 0xffffffff;
op_mask[4][1] = 0xffffffff;
op_mask[4][3] = 0xffffffff;
op_mask[5][1] = 0xffffffff;
op_mask[5][2] = 0xffffffff;
op_mask[5][3] = 0xffffffff;
op_mask[6][1] = 0xffffffff;
op_mask[6][2] = 0xffffffff;
op_mask[6][3] = 0xffffffff;
op_mask[7][0] = 0xffffffff;
op_mask[7][1] = 0xffffffff;
op_mask[7][2] = 0xffffffff;
op_mask[7][3] = 0xffffffff;
}
}
+8 -2
View File
@@ -16,12 +16,18 @@
#ifndef _H_YM2612_
#define _H_YM2612_
enum {
YM2612_DISCRETE = 0,
YM2612_INTEGRATED,
YM2612_ENHANCED
};
extern void YM2612Init(void);
extern void YM2612Config(unsigned char dac_bits);
extern void YM2612Config(int type);
extern void YM2612ResetChip(void);
extern void YM2612Update(int *buffer, int length);
extern void YM2612Write(unsigned int a, unsigned int v);
extern unsigned int YM2612Read(unsigned int a);
extern unsigned int YM2612Read(void);
extern int YM2612LoadContext(unsigned char *state);
extern int YM2612SaveContext(unsigned char *state);
+23 -13
View File
@@ -40,7 +40,7 @@
* OPLx decapsulated(Matthew Gambrell, Olli Niemitalo):
* OPL2 ROMs.
*
* version: 1.0.7
* version: 1.0.8
*/
#include <string.h>
@@ -233,7 +233,7 @@ static const Bit32u fm_algorithm[4][6][8] = {
}
};
static Bit32u chip_type = ym3438_type_discrete;
static Bit32u chip_type = ym3438_mode_readmode;
void OPN2_DoIO(ym3438_t *chip)
{
@@ -995,7 +995,7 @@ void OPN2_ChOutput(ym3438_t *chip)
chip->mol = 0;
chip->mor = 0;
if (chip_type == ym3438_type_ym2612)
if (chip_type & ym3438_mode_ym2612)
{
out_en = ((cycles & 3) == 3) || test_dac;
/* YM2612 DAC emulation(not verified) */
@@ -1028,11 +1028,6 @@ void OPN2_ChOutput(ym3438_t *chip)
else
{
out_en = ((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;
@@ -1223,7 +1218,7 @@ void OPN2_SetChipType(Bit32u type)
chip_type = type;
}
void OPN2_Clock(ym3438_t *chip, Bit32u *buffer)
void OPN2_Clock(ym3438_t *chip, Bit16s *buffer)
{
chip->lfo_inc = chip->mode_test_21[1];
chip->pg_read >>= 1;
@@ -1355,6 +1350,9 @@ void OPN2_Clock(ym3438_t *chip, Bit32u *buffer)
buffer[0] = chip->mol;
buffer[1] = chip->mor;
if (chip->status_time)
chip->status_time--;
}
void OPN2_Write(ym3438_t *chip, Bit32u port, Bit8u data)
@@ -1394,7 +1392,7 @@ Bit32u OPN2_ReadIRQPin(ym3438_t *chip)
Bit8u OPN2_Read(ym3438_t *chip, Bit32u port)
{
if ((port & 3) == 0 || chip_type == ym3438_type_asic)
if ((port & 3) == 0 || (chip_type & ym3438_mode_readmode))
{
if (chip->mode_test_21[6])
{
@@ -1411,18 +1409,30 @@ Bit8u OPN2_Read(ym3438_t *chip, Bit32u port)
}
if (chip->mode_test_21[7])
{
return testdata & 0xff;
chip->status = testdata & 0xff;
}
else
{
return testdata >> 8;
chip->status = testdata >> 8;
}
}
else
{
return (chip->busy << 7) | (chip->timer_b_overflow_flag << 1)
chip->status = (chip->busy << 7) | (chip->timer_b_overflow_flag << 1)
| chip->timer_a_overflow_flag;
}
if (chip_type & ym3438_mode_ym2612)
{
chip->status_time = 300000;
}
else
{
chip->status_time = 40000000;
}
}
if (chip->status_time)
{
return chip->status;
}
return 0;
}
+6 -5
View File
@@ -39,16 +39,15 @@
* OPLx decapsulated(Matthew Gambrell, Olli Niemitalo):
* OPL2 ROMs.
*
* version: 1.0.7
* version: 1.0.8
*/
#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) */
ym3438_mode_ym2612 = 0x01, /* Enables YM2612 emulation (MD1, MD2 VA2) */
ym3438_mode_readmode = 0x02, /* Enables status read on any port (TeraDrive, MD1 VA7, MD2, etc) */
};
#include <stdint.h>
@@ -205,11 +204,13 @@ typedef struct
Bit8u pan_l[6], pan_r[6];
Bit8u ams[6];
Bit8u pms[6];
Bit8u status;
Bit32u status_time;
} ym3438_t;
void OPN2_Reset(ym3438_t *chip);
void OPN2_SetChipType(Bit32u type);
void OPN2_Clock(ym3438_t *chip, Bit32u *buffer);
void OPN2_Clock(ym3438_t *chip, Bit16s *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);
+1 -41
View File
@@ -5,7 +5,7 @@
* Support for 16-bit & 8-bit hardware modes
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2017 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2018 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@@ -467,10 +467,6 @@ void system_frame_gen(int do_skip)
{
z80_run(788);
}
else
{
Z80.cycles = 788;
}
/* set VINT flag */
status |= 0x80;
@@ -493,10 +489,6 @@ void system_frame_gen(int do_skip)
{
z80_run(MCYCLES_PER_LINE);
}
else
{
Z80.cycles = MCYCLES_PER_LINE;
}
/* Z80 interrupt is cleared at the end of the line */
Z80.irq_state = CLEAR_LINE;
@@ -538,10 +530,6 @@ void system_frame_gen(int do_skip)
{
z80_run(mcycles_vdp + MCYCLES_PER_LINE);
}
else
{
Z80.cycles = mcycles_vdp + MCYCLES_PER_LINE;
}
/* run SVP chip */
if (svp)
@@ -590,10 +578,6 @@ void system_frame_gen(int do_skip)
{
z80_run(mcycles_vdp + MCYCLES_PER_LINE);
}
else
{
Z80.cycles = mcycles_vdp + MCYCLES_PER_LINE;
}
/* run SVP chip */
if (svp)
@@ -654,10 +638,6 @@ void system_frame_gen(int do_skip)
{
z80_run(mcycles_vdp + MCYCLES_PER_LINE);
}
else
{
Z80.cycles = mcycles_vdp + MCYCLES_PER_LINE;
}
/* run SVP chip */
if (svp)
@@ -826,10 +806,6 @@ void system_frame_scd(int do_skip)
{
z80_run(788);
}
else
{
Z80.cycles = 788;
}
/* set VINT flag */
status |= 0x80;
@@ -854,10 +830,6 @@ void system_frame_scd(int do_skip)
{
z80_run(MCYCLES_PER_LINE);
}
else
{
Z80.cycles = MCYCLES_PER_LINE;
}
/* Z80 interrupt is cleared at the end of the line */
Z80.irq_state = CLEAR_LINE;
@@ -895,10 +867,6 @@ void system_frame_scd(int do_skip)
{
z80_run(mcycles_vdp + MCYCLES_PER_LINE);
}
else
{
Z80.cycles = mcycles_vdp + MCYCLES_PER_LINE;
}
/* update VDP cycle count */
mcycles_vdp += MCYCLES_PER_LINE;
@@ -943,10 +911,6 @@ void system_frame_scd(int do_skip)
{
z80_run(mcycles_vdp + MCYCLES_PER_LINE);
}
else
{
Z80.cycles = mcycles_vdp + MCYCLES_PER_LINE;
}
/* update VDP cycle count */
mcycles_vdp += MCYCLES_PER_LINE;
@@ -1003,10 +967,6 @@ void system_frame_scd(int do_skip)
{
z80_run(mcycles_vdp + MCYCLES_PER_LINE);
}
else
{
Z80.cycles = mcycles_vdp + MCYCLES_PER_LINE;
}
/* update VDP cycle count */
mcycles_vdp += MCYCLES_PER_LINE;
+1 -1
View File
@@ -5,7 +5,7 @@
* Support for 16-bit & 8-bit hardware modes
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2017 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2018 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
+4 -1
View File
@@ -34,8 +34,11 @@ struct
uint8 hq_fm;
uint8 filter;
uint8 hq_psg;
uint8 dac_bits;
uint8 ym2612;
uint8 ym2413;
#ifdef HAVE_YM3438_CORE
uint8 ym3438;
#endif
uint8 mono;
int16 psg_preamp;
int16 fm_preamp;