// license:BSD-3-Clause // copyright-holders:Quench, David Graves, R. Belmont /********************************************************************************************** * * ES8712 Sound Controller chip for MSM5205/6585 and 74157-type TTL pair * Chip is branded by Excellent Systems, probably OEM'd. * * Samples are currently looped, but whether they should and how, is unknown. * Interface to the chip is also not 100% clear. * * Current implementation is based from : * gcpinbal.cpp, by David Graves & R. Belmont. * splitted by cam900 * * It seems that the ES8712 is actually a programmable counter which can stream * ADPCM samples when hooked up to a ROM and a M5205 or M6585 (whose VCK signal * can drive the counter). Neither of these seem to be used in conjunction with * the ES8712 on Dream 9 and Dream 9 Final, which suggests it may have been used * for an entirely different purpose there (perhaps to do with video timing). * **********************************************************************************************/ #include "emu.h" #include "es8712.h" // device type definition DEFINE_DEVICE_TYPE(ES8712, es8712_device, "es8712", "Excellent Systems ES8712 Sound Controller") //************************************************************************** // LIVE DEVICE //************************************************************************** //------------------------------------------------- // es8712_device - constructor //------------------------------------------------- es8712_device::es8712_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, ES8712, tag, owner, clock) , device_rom_interface(mconfig, *this, 20) // TODO : 20 address bits? , m_adpcm_select(*this, "adpcm_select") , m_msm(*this, finder_base::DUMMY_TAG) , m_reset_handler(*this) , m_msm_write_cb(*this) , m_playing(0) , m_base_offset(0) , m_start(0) , m_end(0) , m_adpcm_trigger(0) { } //------------------------------------------------- // device_add_mconfig - device-specific machine // configuration addiitons //------------------------------------------------- MACHINE_CONFIG_START(es8712_device::device_add_mconfig) MCFG_DEVICE_ADD("adpcm_select", HCT157, 0) // TODO : gcpinbal case, differs per games? MCFG_74157_OUT_CB(WRITE8(*this, es8712_device, msm_w)) MACHINE_CONFIG_END //------------------------------------------------- // device_start - start emulation of an ES8712 chip //------------------------------------------------- void es8712_device::device_start() { m_reset_handler.resolve_safe(); m_msm_write_cb.resolve_safe(); es8712_state_save_register(); } //------------------------------------------------- // device_reset - stop emulation of an ES8712-compatible chip //------------------------------------------------- void es8712_device::device_reset() { if (m_playing) { m_playing = 0; } if (m_msm.found()) m_msm->reset_w(1); m_reset_handler(CLEAR_LINE); } //------------------------------------------------- // rom_bank_updated - nothing for now //------------------------------------------------- void es8712_device::rom_bank_updated() { } //------------------------------------------------- // state save support for MAME //------------------------------------------------- void es8712_device::es8712_state_save_register() { save_item(NAME(m_playing)); save_item(NAME(m_base_offset)); save_item(NAME(m_start)); save_item(NAME(m_end)); save_item(NAME(m_adpcm_trigger)); } //------------------------------------------------- // play -- Begin playing the addressed sample //------------------------------------------------- void es8712_device::play() { assert(m_msm.found()); if (m_start < m_end) { if (!m_playing) { logerror("Playing sample range %06x-%06x\n", m_start, m_end); m_playing = 1; m_msm->reset_w(0); m_reset_handler(CLEAR_LINE); m_base_offset = m_start; } } /* invalid samples go here */ else { logerror("Request to play invalid sample range %06x-%06x\n", m_start, m_end); if (m_playing) { /* update the stream */ m_playing = 0; m_reset_handler(ASSERT_LINE); } } } /********************************************************************************************** write -- generic data write functions ***********************************************************************************************/ /********************************************************************************************** * * offset Start End * 0hmmll - 0HMMLL * 00 ----ll * 01 --mm-- * 02 0h---- * 03 ----LL * 04 --MM-- * 05 0H---- * 06 Go! * * Offsets are written in the order -> 00, 02, 01, 03, 05, 04, 06 * Offset 06 is written with the same value as offset 04. * ***********************************************************************************************/ WRITE8_MEMBER(es8712_device::write) { switch (offset) { case 00: m_start &= 0x000fff00; m_start |= ((data & 0xff) << 0); break; case 01: m_start &= 0x000f00ff; m_start |= ((data & 0xff) << 8); break; case 02: m_start &= 0x0000ffff; m_start |= ((data & 0x0f) << 16); break; case 03: m_end &= 0x000fff00; m_end |= ((data & 0xff) << 0); break; case 04: m_end &= 0x000f00ff; m_end |= ((data & 0xff) << 8); break; case 05: m_end &= 0x0000ffff; m_end |= ((data & 0x0f) << 16); break; case 06: play(); break; default: break; } m_start &= 0xfffff; m_end &= 0xfffff; } READ8_MEMBER(es8712_device::read) { // busy state (other bits unknown) if (offset == 0) return m_playing ? 1 : 0; return 0; } WRITE8_MEMBER(es8712_device::msm_w) { m_msm_write_cb(offset, data); } WRITE_LINE_MEMBER(es8712_device::msm_int) { if (!state || !m_playing) return; if (m_base_offset >= 0x100000 || m_base_offset > m_end) { m_playing = 0; m_msm->reset_w(1); m_reset_handler(ASSERT_LINE); //m_base_offset = m_start; m_adpcm_trigger = 0; } else { m_adpcm_select->write_ab(read_byte(m_base_offset)); m_adpcm_select->select_w(m_adpcm_trigger); m_adpcm_trigger ^= 1; if (m_adpcm_trigger == 0) m_base_offset++; } }