diff options
Diffstat (limited to 'trunk/src/mame/audio/irem.c')
-rw-r--r-- | trunk/src/mame/audio/irem.c | 502 |
1 files changed, 502 insertions, 0 deletions
diff --git a/trunk/src/mame/audio/irem.c b/trunk/src/mame/audio/irem.c new file mode 100644 index 00000000000..a94a915dba9 --- /dev/null +++ b/trunk/src/mame/audio/irem.c @@ -0,0 +1,502 @@ +/*************************************************************************** + + Irem M52/M62 sound hardware + +***************************************************************************/ + +#include "emu.h" +#include "cpu/m6800/m6800.h" +#include "sound/ay8910.h" +#include "sound/msm5205.h" +#include "sound/discrete.h" +#include "audio/irem.h" + +typedef struct _irem_audio_state irem_audio_state; +struct _irem_audio_state +{ + UINT8 m_port1; + UINT8 m_port2; + + device_t *m_ay1; + device_t *m_ay2; + device_t *m_adpcm1; + device_t *m_adpcm2; +}; + +INLINE irem_audio_state *get_safe_token( device_t *device ) +{ + assert(device != NULL); + assert(device->type() == IREM_AUDIO); + + return (irem_audio_state *)downcast<legacy_device_base *>(device)->token(); +} + + + +/************************************* + * + * Sound board initialization + * + *************************************/ + +static DEVICE_START( irem_audio ) +{ + irem_audio_state *state = get_safe_token(device); + running_machine &machine = device->machine(); + + state->m_adpcm1 = machine.device("msm1"); + state->m_adpcm2 = machine.device("msm2"); + state->m_ay1 = machine.device("ay1"); + state->m_ay2 = machine.device("ay2"); + + device->save_item(NAME(state->m_port1)); + device->save_item(NAME(state->m_port2)); +} + + + +/************************************* + * + * External writes to the sound + * command register + * + *************************************/ + +WRITE8_HANDLER( irem_sound_cmd_w ) +{ + if ((data & 0x80) == 0) + soundlatch_w(space, 0, data & 0x7f); + else + cputag_set_input_line(space->machine(), "iremsound", 0, ASSERT_LINE); +} + + + +/************************************* + * + * 6803 output ports + * + *************************************/ + +static WRITE8_DEVICE_HANDLER( m6803_port1_w ) +{ + irem_audio_state *state = get_safe_token(device); + + state->m_port1 = data; +} + + +static WRITE8_DEVICE_HANDLER( m6803_port2_w ) +{ + irem_audio_state *state = get_safe_token(device); + + /* write latch */ + if ((state->m_port2 & 0x01) && !(data & 0x01)) + { + /* control or data port? */ + if (state->m_port2 & 0x04) + { + /* PSG 0 or 1? */ + if (state->m_port2 & 0x08) + ay8910_address_w(state->m_ay1, 0, state->m_port1); + if (state->m_port2 & 0x10) + ay8910_address_w(state->m_ay2, 0, state->m_port1); + } + else + { + /* PSG 0 or 1? */ + if (state->m_port2 & 0x08) + ay8910_data_w(state->m_ay1, 0, state->m_port1); + if (state->m_port2 & 0x10) + ay8910_data_w(state->m_ay2, 0, state->m_port1); + } + } + state->m_port2 = data; +} + + + +/************************************* + * + * 6803 input ports ports + * + *************************************/ + +static READ8_DEVICE_HANDLER( m6803_port1_r ) +{ + irem_audio_state *state = get_safe_token(device); + + /* PSG 0 or 1? */ + if (state->m_port2 & 0x08) + return ay8910_r(state->m_ay1, 0); + if (state->m_port2 & 0x10) + return ay8910_r(state->m_ay2, 0); + return 0xff; +} + + +static READ8_DEVICE_HANDLER( m6803_port2_r ) +{ + return 0; +} + + + +/************************************* + * + * AY-8910 output ports + * + *************************************/ + +static WRITE8_DEVICE_HANDLER( ay8910_0_portb_w ) +{ + irem_audio_state *state = get_safe_token(device); + + /* bits 2-4 select MSM5205 clock & 3b/4b playback mode */ + msm5205_playmode_w(state->m_adpcm1, (data >> 2) & 7); + if (state->m_adpcm2 != NULL) + msm5205_playmode_w(state->m_adpcm2, ((data >> 2) & 4) | 3); /* always in slave mode */ + + /* bits 0 and 1 reset the two chips */ + msm5205_reset_w(state->m_adpcm1, data & 1); + if (state->m_adpcm2 != NULL) + msm5205_reset_w(state->m_adpcm2, data & 2); +} + + +static WRITE8_DEVICE_HANDLER( ay8910_1_porta_w ) +{ +#ifdef MAME_DEBUG + if (data & 0x0f) popmessage("analog sound %x",data&0x0f); +#endif +} + + + +/************************************* + * + * Memory-mapped accesses + * + *************************************/ + +static WRITE8_HANDLER( sound_irq_ack_w ) +{ + cputag_set_input_line(space->machine(), "iremsound", 0, CLEAR_LINE); +} + + +static WRITE8_DEVICE_HANDLER( m52_adpcm_w ) +{ + irem_audio_state *state = get_safe_token(device); + + if (offset & 1) + { + msm5205_data_w(state->m_adpcm1, data); + } + if (offset & 2) + { + if (state->m_adpcm2 != NULL) + msm5205_data_w(state->m_adpcm2, data); + } +} + + +static WRITE8_DEVICE_HANDLER( m62_adpcm_w ) +{ + irem_audio_state *state = get_safe_token(device); + + device_t *adpcm = (offset & 1) ? state->m_adpcm2 : state->m_adpcm1; + if (adpcm != NULL) + msm5205_data_w(adpcm, data); +} + + + +/************************************* + * + * MSM5205 data ready signals + * + *************************************/ + +static void adpcm_int(device_t *device) +{ + device_t *adpcm2 = device->machine().device("msm2"); + + cputag_set_input_line(device->machine(), "iremsound", INPUT_LINE_NMI, PULSE_LINE); + + /* the first MSM5205 clocks the second */ + if (adpcm2 != NULL) + { + msm5205_vclk_w(adpcm2, 1); + msm5205_vclk_w(adpcm2, 0); + } +} + + + +/************************************* + * + * Sound interfaces + * + *************************************/ + +/* All 6 (3*2) AY-3-8910 outputs are tied together + * and put with 470 Ohm to gnd. + * The following is a approximation, since + * it does not take cross-chip mixing effects into account. + */ + +static const ay8910_interface irem_ay8910_interface_1 = +{ + AY8910_SINGLE_OUTPUT | AY8910_DISCRETE_OUTPUT, + {470, 0, 0}, + DEVCB_MEMORY_HANDLER("iremsound", PROGRAM, soundlatch_r), + DEVCB_NULL, + DEVCB_NULL, + DEVCB_DEVICE_HANDLER("irem_audio", ay8910_0_portb_w) +}; + +static const ay8910_interface irem_ay8910_interface_2 = +{ + AY8910_SINGLE_OUTPUT | AY8910_DISCRETE_OUTPUT, + {470, 0, 0}, + DEVCB_NULL, + DEVCB_NULL, + DEVCB_HANDLER(ay8910_1_porta_w), + DEVCB_NULL +}; + +static const msm5205_interface irem_msm5205_interface_1 = +{ + adpcm_int, /* interrupt function */ + MSM5205_S96_4B /* default to 4KHz, but can be changed at run time */ +}; + +static const msm5205_interface irem_msm5205_interface_2 = +{ + 0, /* interrupt function */ + MSM5205_SEX_4B /* default to 4KHz, but can be changed at run time, slave */ +}; + +/* + * http://newsgroups.derkeiler.com/Archive/Rec/rec.games.video.arcade.collecting/2006-06/msg03108.html + * + * mentions, that moon patrol does work on moon ranger hardware. + * There is no MSM5250, but a 74LS00 producing white noise for explosions + */ + +/* Certain values are different from schematics + * I did my test to verify against pcb pictures of "tropical angel" + */ + +#define M52_R9 560 +#define M52_R10 330 +#define M52_R12 RES_K(10) +#define M52_R13 RES_K(10) +#define M52_R14 RES_K(10) +#define M52_R15 RES_K(2.2) /* schematics RES_K(22) , althought 10-Yard states 2.2 */ +#define M52_R19 RES_K(10) +#define M52_R22 RES_K(47) +#define M52_R23 RES_K(2.2) +#define M52_R25 RES_K(10) +#define M52_VR1 RES_K(50) + +#define M52_C28 CAP_U(1) +#define M52_C30 CAP_U(0.022) +#define M52_C32 CAP_U(0.022) +#define M52_C35 CAP_U(47) +#define M52_C37 CAP_U(0.1) +#define M52_C38 CAP_U(0.0068) + +/* + * C35 is disabled, the mixer would just deliver + * no signals if it is enabled. + * TODO: Check discrete mixer + * + */ + +static const discrete_mixer_desc m52_sound_c_stage1 = + {DISC_MIXER_IS_RESISTOR, + {M52_R19, M52_R22, M52_R23 }, + { 0, 0, 0 }, /* variable resistors */ + {M52_C37, 0, 0 }, /* node capacitors */ + 0, 0, /* rI, rF */ + M52_C35*0, /* cF */ + 0, /* cAmp */ + 0, 1}; + +static const discrete_op_amp_filt_info m52_sound_c_sallen_key = + { M52_R13, M52_R14, 0, 0, 0, + M52_C32, M52_C38, 0 + }; + +static const discrete_mixer_desc m52_sound_c_mix1 = + {DISC_MIXER_IS_RESISTOR, + {M52_R25, M52_R15 }, + { 0, 0 }, /* variable resistors */ + { 0, 0 }, /* node capacitors */ + 0, M52_VR1, /* rI, rF */ + 0, /* cF */ + CAP_U(1), /* cAmp */ + 0, 1}; + +static DISCRETE_SOUND_START( m52_sound_c ) + + /* Chip AY8910/1 */ + DISCRETE_INPUTX_STREAM(NODE_01, 0, 1.0, 0) + /* Chip AY8910/2 */ + DISCRETE_INPUTX_STREAM(NODE_02, 1, 1.0, 0) + /* Chip MSM5250 */ + DISCRETE_INPUTX_STREAM(NODE_03, 2, 1.0, 0) + + /* Just mix the two AY8910s */ + DISCRETE_ADDER2(NODE_09, 1, NODE_01, NODE_02) + DISCRETE_DIVIDE(NODE_10, 1, NODE_09, 2.0) + + /* Mix in 5 V to MSM5250 signal */ + DISCRETE_MIXER3(NODE_20, 1, NODE_03, 32767.0, 0, &m52_sound_c_stage1) + + /* Sallen - Key Filter */ + /* TODO: R12, C30: This looks like a band pass */ + DISCRETE_RCFILTER(NODE_25, NODE_20, M52_R12, M52_C30) + DISCRETE_SALLEN_KEY_FILTER(NODE_30, 1, NODE_25, DISC_SALLEN_KEY_LOW_PASS, &m52_sound_c_sallen_key) + + /* Mix signals */ + DISCRETE_MIXER2(NODE_40, 1, NODE_10, NODE_25, &m52_sound_c_mix1) + DISCRETE_CRFILTER(NODE_45, NODE_40, M52_R10+M52_R9, M52_C28) + + DISCRETE_OUTPUT(NODE_40, 18.0) + +DISCRETE_SOUND_END + +/************************************* + * + * Address maps + * + *************************************/ + +/* complete address map verified from Moon Patrol/10 Yard Fight schematics */ +/* large map uses 8k ROMs, small map uses 4k ROMs; this is selected via a jumper */ +static ADDRESS_MAP_START( m52_small_sound_map, AS_PROGRAM, 8 ) + ADDRESS_MAP_GLOBAL_MASK(0x7fff) + AM_RANGE(0x0000, 0x0fff) AM_DEVWRITE("irem_audio", m52_adpcm_w) + AM_RANGE(0x1000, 0x1fff) AM_WRITE(sound_irq_ack_w) + AM_RANGE(0x2000, 0x7fff) AM_ROM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( m52_large_sound_map, AS_PROGRAM, 8 ) + AM_RANGE(0x0000, 0x1fff) AM_DEVWRITE("irem_audio", m52_adpcm_w) + AM_RANGE(0x2000, 0x3fff) AM_WRITE(sound_irq_ack_w) + AM_RANGE(0x4000, 0xffff) AM_ROM +ADDRESS_MAP_END + + +/* complete address map verified from Kid Niki schematics */ +static ADDRESS_MAP_START( m62_sound_map, AS_PROGRAM, 8 ) + AM_RANGE(0x0800, 0x0800) AM_MIRROR(0xf7fc) AM_WRITE(sound_irq_ack_w) + AM_RANGE(0x0801, 0x0802) AM_MIRROR(0xf7fc) AM_DEVWRITE("irem_audio", m62_adpcm_w) + AM_RANGE(0x4000, 0xffff) AM_ROM +ADDRESS_MAP_END + + +static ADDRESS_MAP_START( irem_sound_portmap, AS_IO, 8 ) + AM_RANGE(M6801_PORT1, M6801_PORT1) AM_DEVREADWRITE("irem_audio", m6803_port1_r, m6803_port1_w) + AM_RANGE(M6801_PORT2, M6801_PORT2) AM_DEVREADWRITE("irem_audio", m6803_port2_r, m6803_port2_w) +ADDRESS_MAP_END + + + +/************************************* + * + * Machine drivers + * + *************************************/ + +static MACHINE_CONFIG_FRAGMENT( irem_audio_base ) + + /* basic machine hardware */ + MCFG_CPU_ADD("iremsound", M6803, XTAL_3_579545MHz) /* verified on pcb */ + MCFG_CPU_IO_MAP(irem_sound_portmap) + + /* sound hardware */ + MCFG_SPEAKER_STANDARD_MONO("mono") + + MCFG_SOUND_ADD("irem_audio", IREM_AUDIO, 0) + + MCFG_SOUND_ADD("ay1", AY8910, XTAL_3_579545MHz/4) /* verified on pcb */ + MCFG_SOUND_CONFIG(irem_ay8910_interface_1) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.80) + + MCFG_SOUND_ADD("ay2", AY8910, XTAL_3_579545MHz/4) /* verified on pcb */ + MCFG_SOUND_CONFIG(irem_ay8910_interface_2) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.80) + + MCFG_SOUND_ADD("msm1", MSM5205, XTAL_384kHz) /* verified on pcb */ + MCFG_SOUND_CONFIG(irem_msm5205_interface_1) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.80) + + MCFG_SOUND_ADD("msm2", MSM5205, XTAL_384kHz) /* verified on pcb */ + MCFG_SOUND_CONFIG(irem_msm5205_interface_2) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.80) +MACHINE_CONFIG_END + +MACHINE_CONFIG_FRAGMENT( m52_sound_c_audio ) + + /* basic machine hardware */ + MCFG_CPU_ADD("iremsound", M6803, XTAL_3_579545MHz) /* verified on pcb */ + MCFG_CPU_IO_MAP(irem_sound_portmap) + MCFG_CPU_PROGRAM_MAP(m52_small_sound_map) + + /* sound hardware */ + MCFG_SPEAKER_STANDARD_MONO("mono") + + MCFG_SOUND_ADD("irem_audio", IREM_AUDIO, 0) + + MCFG_SOUND_ADD("ay1", AY8910, XTAL_3_579545MHz/4) /* verified on pcb */ + MCFG_SOUND_CONFIG(irem_ay8910_interface_1) + MCFG_SOUND_ROUTE_EX(0, "filtermix", 1.0, 0) + + MCFG_SOUND_ADD("ay2", AY8910, XTAL_3_579545MHz/4) /* verified on pcb */ + MCFG_SOUND_CONFIG(irem_ay8910_interface_2) + MCFG_SOUND_ROUTE_EX(0, "filtermix", 1.0, 1) + + MCFG_SOUND_ADD("msm1", MSM5205, XTAL_384kHz) /* verified on pcb */ + MCFG_SOUND_CONFIG(irem_msm5205_interface_1) + MCFG_SOUND_ROUTE_EX(0, "filtermix", 1.0, 2) + + MCFG_SOUND_ADD("filtermix", DISCRETE, 0) + MCFG_SOUND_CONFIG_DISCRETE(m52_sound_c) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0) + +MACHINE_CONFIG_END + +MACHINE_CONFIG_DERIVED( m52_large_audio, irem_audio_base ) /* 10 yard fight */ + + /* basic machine hardware */ + MCFG_CPU_MODIFY("iremsound") + MCFG_CPU_PROGRAM_MAP(m52_large_sound_map) +MACHINE_CONFIG_END + + +MACHINE_CONFIG_DERIVED( m62_audio, irem_audio_base ) + + /* basic machine hardware */ + MCFG_CPU_MODIFY("iremsound") + MCFG_CPU_PROGRAM_MAP(m62_sound_map) +MACHINE_CONFIG_END + +/***************************************************************************** + DEVICE DEFINITION +*****************************************************************************/ + + +static const char DEVTEMPLATE_SOURCE[] = __FILE__; + +#define DEVTEMPLATE_ID(p,s) p##irem_audio##s +#define DEVTEMPLATE_FEATURES DT_HAS_START +#define DEVTEMPLATE_NAME "Irem Audio" +#define DEVTEMPLATE_FAMILY "Irem Audio IC" +#include "devtempl.h" + + +DEFINE_LEGACY_SOUND_DEVICE(IREM_AUDIO, irem_audio); |