diff options
Diffstat (limited to 'src/devices/machine/ym2148.cpp')
-rw-r--r-- | src/devices/machine/ym2148.cpp | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/src/devices/machine/ym2148.cpp b/src/devices/machine/ym2148.cpp new file mode 100644 index 00000000000..d0f45fc8844 --- /dev/null +++ b/src/devices/machine/ym2148.cpp @@ -0,0 +1,209 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/************************************************************************** + + Yamaha YM-2148 emulation + +TODO: +- Finish implemention of midi out + +**************************************************************************/ + +#include "emu.h" +#include "ym2148.h" + + +const device_type YM2148 = &device_creator<ym2148_device>; + + +ym2148_device::ym2148_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, YM2148, "YM2148", tag, owner, clock, "ym2148", __FILE__) + , device_serial_interface(mconfig, *this) + , m_txd_handler(*this) + , m_irq_handler(*this) + , m_port_write_handler(*this) + , m_port_read_handler(*this) + , m_irq_state(CLEAR_LINE) + , m_irq_vector(0xff) // guess + , m_external_irq_vector(0xff) // guess + , m_data_out(0) + , m_data_in(0) + , m_control(0) + , m_status(0) + , m_rxd(1) + , m_tx_busy(false) +{ +} + + +void ym2148_device::device_start() +{ + m_txd_handler.resolve_safe(); + m_irq_handler.resolve_safe(); + m_port_write_handler.resolve_safe(); + m_port_read_handler.resolve_safe(0xff); + + // Start a timer to trigger at clock / 8 / 16 + m_timer = timer_alloc(0); + m_timer->adjust(attotime::from_hz(m_clock / 8 / 16), 0, attotime::from_hz(m_clock / 8 / 16)); +} + + +void ym2148_device::device_reset() +{ + set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1); + transmit_register_reset(); + receive_register_reset(); + m_status |= STATUS_TRANSMIT_READY; +} + + +void ym2148_device::receive_clock() +{ + if (m_control & CONTROL_RECEIVE_ENABLE) + { + /* get bit received from other side and update receive register */ + receive_register_update_bit(m_rxd); + + if (is_receive_register_full()) + { + receive_register_extract(); + + m_data_in = get_received_char(); + + if (m_status & STATUS_RECEIVE_BUFFER_FULL) + { + // Overrun error + m_status |= STATUS_OVERRUN_ERROR; + } + m_status |= STATUS_RECEIVE_BUFFER_FULL; + update_irq(); + } + } +} + + +void ym2148_device::transmit_clock() +{ + if (m_control & CONTROL_TRANSMIT_ENABLE) + { + if (!(m_status & STATUS_TRANSMIT_READY)) + { + /* is diserial ready for it? */ + if (is_transmit_register_empty()) + { + /* set it up */ + transmit_register_setup(m_data_out); + /* ready for next transmit */ + m_status |= STATUS_TRANSMIT_READY; + } + } + + /* if diserial has bits to send, make them so */ + if (!is_transmit_register_empty()) + { + UINT8 data = transmit_register_get_data_bit(); + m_tx_busy = true; + m_txd_handler(data); + } + + // is transmitter totally done? + if ((m_status & STATUS_TRANSMIT_READY) && is_transmit_register_empty()) + { + m_tx_busy = false; + } + } +} + + +void ym2148_device::update_irq() +{ + m_irq_state = CLEAR_LINE; + + if ((m_status & STATUS_RECEIVE_BUFFER_FULL) && (m_control & CONTROL_RECEIVE_IRQ_ENABLE)) + { + m_irq_state = ASSERT_LINE; + } + if ((m_status & STATUS_TRANSMIT_READY) && (m_control & CONTROL_TRANSMIT_IRQ_ENABLE)) + { +// m_irq_state = ASSERT_LINE; + } + + m_irq_handler(m_irq_state); +} + + +void ym2148_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + receive_clock(); + transmit_clock(); +} + + +READ8_MEMBER(ym2148_device::read) +{ + switch (offset & 7) + { + case 2: // External port read + return m_port_read_handler(); + + case 5: // Midi data read register + m_status &= ~STATUS_RECEIVE_BUFFER_FULL; + update_irq(); + return m_data_in; + + case 6: // Midi status register + return m_status; + } + return 0xff; +} + + +WRITE8_MEMBER(ym2148_device::write) +{ + switch (offset & 7) + { + case 2: // External port write + m_port_write_handler(data); + break; + + case 3: // IRQ vector + m_irq_vector = data; + break; + + case 4: // External IRQ vector + m_external_irq_vector = data; + break; + + case 5: // Midi data write register + m_data_out = data; + m_status &= ~STATUS_TRANSMIT_READY; + break; + + case 6: // Midi control register + m_control = data; + + if (m_control & 0x80) + { + // Reset + receive_clock(); + transmit_clock(); + m_irq_state = CLEAR_LINE; + m_irq_handler(m_irq_state); + } + update_irq(); + break; + } +} + + +UINT8 ym2148_device::get_irq_vector() +{ + return (m_irq_state == ASSERT_LINE) ? m_irq_vector : m_external_irq_vector; +} + + +WRITE_LINE_MEMBER(ym2148_device::write_rxd) +{ + m_rxd = state; +} |