summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/mame/audio/irem.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/mame/audio/irem.c')
-rw-r--r--trunk/src/mame/audio/irem.c502
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);