// license:BSD-3-Clause // copyright-holders:Derrick Renaud,Couriersud /************************************************************************* audio/qix.c *************************************************************************/ #include "emu.h" #include "includes/qix.h" #include "cpu/m6800/m6800.h" #include "cpu/m6809/m6809.h" #include "sound/discrete.h" #include "sound/sn76496.h" #include "speaker.h" /* Discrete Sound Input Nodes */ #define QIX_DAC_DATA NODE_01 #define QIX_VOL_DATA NODE_02 #define QIX_VOL_DATA_L NODE_03 #define QIX_VOL_DATA_R NODE_04 /*************************************************************************** Audio handlers ***************************************************************************/ WRITE8_MEMBER(qix_state::qix_dac_w) { m_discrete->write(QIX_DAC_DATA, data); } WRITE8_MEMBER(qix_state::qix_vol_w) { m_discrete->write(QIX_VOL_DATA, data); } /************************************************************************/ /* qix Sound System Analog emulation */ /************************************************************************/ /* * This hardware is capable of independent L/R volume control, * but only sdungeon uses it for a stereo effect. * Other games just use it for fixed L/R volume control. * * This is such a basic sound system that there is only one effect. * So I won't bother keeping proper voltages levels, and will just * start with the final gain. */ static const discrete_comp_adder_table qix_attn_table = { DISC_COMP_P_RESISTOR, 0, 4, {RES_K(22)+250, RES_K(10)+250, RES_K(5.6)+250, RES_K(3.3)+250} }; static DISCRETE_SOUND_START(qix_discrete) /* NODE */ DISCRETE_INPUTX_DATA(QIX_DAC_DATA, 128, -128*128, 128) DISCRETE_INPUT_DATA (QIX_VOL_DATA) /* Separate the two 4-bit channels. */ DISCRETE_TRANSFORM3(QIX_VOL_DATA_L, QIX_VOL_DATA, 16, 0x0f, "01/2&") DISCRETE_TRANSFORM2(QIX_VOL_DATA_R, QIX_VOL_DATA, 0x0f, "01&") /* Work out the parallel resistance of the selected resistors. */ DISCRETE_COMP_ADDER(NODE_10, QIX_VOL_DATA_L, &qix_attn_table) DISCRETE_COMP_ADDER(NODE_20, QIX_VOL_DATA_R, &qix_attn_table) /* Then use it for the resistor divider network. */ DISCRETE_TRANSFORM3(NODE_11, NODE_10, RES_K(10), QIX_DAC_DATA, "001+/2*") DISCRETE_TRANSFORM3(NODE_21, NODE_20, RES_K(10), QIX_DAC_DATA, "001+/2*") /* If no resistors are selected (0), then the volume is full. */ DISCRETE_SWITCH(NODE_12, 1, QIX_VOL_DATA_L, QIX_DAC_DATA, NODE_11) DISCRETE_SWITCH(NODE_22, 1, QIX_VOL_DATA_R, QIX_DAC_DATA, NODE_21) /* Filter the DC using the lowest case filter. */ DISCRETE_CRFILTER(NODE_13, NODE_12, RES_K(1.5), CAP_U(1)) DISCRETE_CRFILTER(NODE_23, NODE_22, RES_K(1.5), CAP_U(1)) DISCRETE_OUTPUT(NODE_13, 1) DISCRETE_OUTPUT(NODE_23, 1) DISCRETE_SOUND_END /************************************* * * PIA handlers * *************************************/ WRITE8_MEMBER(qix_state::sndpia_2_warning_w) { popmessage("PIA 5 write!!"); } TIMER_CALLBACK_MEMBER(qix_state::deferred_sndpia1_porta_w) { m_sndpia1->write_porta(param); } WRITE8_MEMBER(qix_state::sync_sndpia1_porta_w) { /* we need to synchronize this so the sound CPU doesn't drop anything important */ machine().scheduler().synchronize(timer_expired_delegate(FUNC(qix_state::deferred_sndpia1_porta_w), this), data); } WRITE8_MEMBER(qix_state::slither_coinctl_w) { machine().bookkeeping().coin_lockout_w(0, (~data >> 6) & 1); machine().bookkeeping().coin_counter_w(0, (data >> 5) & 1); } /************************************* * * IRQ generation * *************************************/ WRITE_LINE_MEMBER(qix_state::qix_pia_dint) { int combined_state = m_sndpia0->irq_a_state() | m_sndpia0->irq_b_state(); /* DINT is connected to the data CPU's IRQ line */ m_maincpu->set_input_line(M6809_IRQ_LINE, combined_state ? ASSERT_LINE : CLEAR_LINE); } WRITE_LINE_MEMBER(qix_state::qix_pia_sint) { int combined_state = m_sndpia1->irq_a_state() | m_sndpia1->irq_b_state(); /* SINT is connected to the sound CPU's IRQ line */ m_audiocpu->set_input_line(M6802_IRQ_LINE, combined_state ? ASSERT_LINE : CLEAR_LINE); } /************************************* * * Audio CPU memory handlers * *************************************/ void qix_state::audio_map(address_map &map) { map(0x2000, 0x2003).mirror(0x5ffc).rw(m_sndpia2, FUNC(pia6821_device::read), FUNC(pia6821_device::write)); map(0x4000, 0x4003).mirror(0x3ffc).rw(m_sndpia1, FUNC(pia6821_device::read), FUNC(pia6821_device::write)); map(0xd000, 0xffff).rom(); } /************************************* * * Machine drivers * *************************************/ void qix_state::qix_audio(machine_config &config) { M6802(config, m_audiocpu, SOUND_CLOCK_OSC/2); /* 0.92 MHz */ m_audiocpu->set_addrmap(AS_PROGRAM, &qix_state::audio_map); PIA6821(config, m_sndpia0, 0); m_sndpia0->writepa_handler().set(FUNC(qix_state::sync_sndpia1_porta_w)); m_sndpia0->writepb_handler().set(FUNC(qix_state::qix_vol_w)); m_sndpia0->ca2_handler().set("sndpia1", FUNC(pia6821_device::ca1_w)); m_sndpia0->cb2_handler().set(FUNC(qix_state::qix_flip_screen_w)); m_sndpia0->irqa_handler().set(FUNC(qix_state::qix_pia_dint)); m_sndpia0->irqb_handler().set(FUNC(qix_state::qix_pia_dint)); PIA6821(config, m_sndpia1, 0); m_sndpia1->writepa_handler().set("sndpia0", FUNC(pia6821_device::porta_w)); m_sndpia1->writepb_handler().set(FUNC(qix_state::qix_dac_w)); m_sndpia1->ca2_handler().set("sndpia0", FUNC(pia6821_device::ca1_w)); m_sndpia1->irqa_handler().set(FUNC(qix_state::qix_pia_sint)); m_sndpia1->irqb_handler().set(FUNC(qix_state::qix_pia_sint)); PIA6821(config, m_sndpia2, 0); m_sndpia2->writepa_handler().set(FUNC(qix_state::sndpia_2_warning_w)); m_sndpia2->writepb_handler().set(FUNC(qix_state::sndpia_2_warning_w)); m_sndpia2->ca2_handler().set(FUNC(qix_state::sndpia_2_warning_w)); m_sndpia2->cb2_handler().set(FUNC(qix_state::sndpia_2_warning_w)); SPEAKER(config, "lspeaker").front_left(); SPEAKER(config, "rspeaker").front_right(); DISCRETE(config, m_discrete, qix_discrete); m_discrete->add_route(0, "lspeaker", 1.0); m_discrete->add_route(1, "rspeaker", 1.0); } void qix_state::slither_audio(machine_config &config) { PIA6821(config, m_sndpia0, 0); m_sndpia0->readpa_handler().set_ioport("P2"); m_sndpia0->writepb_handler().set(FUNC(qix_state::slither_coinctl_w)); m_sndpia0->cb2_handler().set(FUNC(qix_state::qix_flip_screen_w)); m_sndpia0->irqa_handler().set(FUNC(qix_state::qix_pia_dint)); m_sndpia0->irqb_handler().set(FUNC(qix_state::qix_pia_dint)); SPEAKER(config, "mono").front_center(); SN76489(config, m_sn1, SLITHER_CLOCK_OSC/4/4); m_sn1->add_route(ALL_OUTPUTS, "mono", 0.50); SN76489(config, m_sn2, SLITHER_CLOCK_OSC/4/4); m_sn2->add_route(ALL_OUTPUTS, "mono", 0.50); }