From 374c31e07087d24c6386b6faad65e351a1096f3d Mon Sep 17 00:00:00 2001 From: etabeta78 Date: Sun, 1 Feb 2015 22:11:53 +0100 Subject: serve an assist to Arbee for SNES Miracle Piano. nw. --- src/emu/bus/bus.mak | 1 + src/emu/bus/snes_ctrl/ctrl.c | 2 + src/emu/bus/snes_ctrl/miracle.c | 285 ++++++++++++++++++++++++++++++++++++++++ src/emu/bus/snes_ctrl/miracle.h | 72 ++++++++++ 4 files changed, 360 insertions(+) create mode 100644 src/emu/bus/snes_ctrl/miracle.c create mode 100644 src/emu/bus/snes_ctrl/miracle.h diff --git a/src/emu/bus/bus.mak b/src/emu/bus/bus.mak index c47965275ea..efc2cd80804 100644 --- a/src/emu/bus/bus.mak +++ b/src/emu/bus/bus.mak @@ -1142,6 +1142,7 @@ OBJDIRS += $(BUSOBJ)/snes_ctrl BUSOBJS += $(BUSOBJ)/snes_ctrl/ctrl.o BUSOBJS += $(BUSOBJ)/snes_ctrl/bcbattle.o BUSOBJS += $(BUSOBJ)/snes_ctrl/joypad.o +BUSOBJS += $(BUSOBJ)/snes_ctrl/miracle.o BUSOBJS += $(BUSOBJ)/snes_ctrl/mouse.o BUSOBJS += $(BUSOBJ)/snes_ctrl/multitap.o BUSOBJS += $(BUSOBJ)/snes_ctrl/pachinko.o diff --git a/src/emu/bus/snes_ctrl/ctrl.c b/src/emu/bus/snes_ctrl/ctrl.c index a09365dab27..9f13534561e 100644 --- a/src/emu/bus/snes_ctrl/ctrl.c +++ b/src/emu/bus/snes_ctrl/ctrl.c @@ -11,6 +11,7 @@ // slot devices #include "bcbattle.h" #include "joypad.h" +#include "miracle.h" #include "mouse.h" #include "multitap.h" #include "pachinko.h" @@ -132,4 +133,5 @@ SLOT_INTERFACE_START( snes_control_port_devices ) SLOT_INTERFACE("sscope", SNES_SUPERSCOPE) SLOT_INTERFACE("twintap", SNES_TWINTAP) SLOT_INTERFACE("barcode_battler", SNES_BARCODE_BATTLER) + SLOT_INTERFACE("miracle_piano", SNES_MIRACLE) SLOT_INTERFACE_END diff --git a/src/emu/bus/snes_ctrl/miracle.c b/src/emu/bus/snes_ctrl/miracle.c new file mode 100644 index 00000000000..40e9743742b --- /dev/null +++ b/src/emu/bus/snes_ctrl/miracle.c @@ -0,0 +1,285 @@ +/********************************************************************** + + Nintendo SNES - Miracle Piano Keyboard + + TODO: ??? + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +**********************************************************************/ + +#include "miracle.h" + +#define MIRACLE_MIDI_WAITING 0 +#define MIRACLE_MIDI_RECEIVE 1 // receive byte from piano +#define MIRACLE_MIDI_SEND 2 // send byte to piano + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type SNES_MIRACLE = &device_creator; + + +MACHINE_CONFIG_FRAGMENT( snes_miracle ) + MCFG_MIDI_PORT_ADD("mdin", midiin_slot, "midiin") + MCFG_MIDI_RX_HANDLER(WRITELINE(snes_miracle_device, rx_w)) + + MCFG_MIDI_PORT_ADD("mdout", midiout_slot, "midiout") +MACHINE_CONFIG_END + +machine_config_constructor snes_miracle_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( snes_miracle ); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void snes_miracle_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_STROBE_ON) + { + m_strobe_clock++; + } + else + { + device_serial_interface::device_timer(timer, id, param, ptr); + } +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// snes_miracle_device - constructor +//------------------------------------------------- + +snes_miracle_device::snes_miracle_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SNES_MIRACLE, "Miracle Piano Controller (SNES)", tag, owner, clock, "snes_miracle", __FILE__), + device_serial_interface(mconfig, *this), + device_snes_control_port_interface(mconfig, *this), + m_midiin(*this, "mdin"), + m_midiout(*this, "mdout") +{ +} + + +//------------------------------------------------- +// device_start +//------------------------------------------------- + +void snes_miracle_device::device_start() +{ + strobe_timer = timer_alloc(TIMER_STROBE_ON); + strobe_timer->adjust(attotime::never); + save_item(NAME(m_strobe_on)); + save_item(NAME(m_sent_bits)); + save_item(NAME(m_strobe_clock)); + save_item(NAME(m_midi_mode)); +} + + +//------------------------------------------------- +// device_reset +//------------------------------------------------- + +void snes_miracle_device::device_reset() +{ + m_strobe_on = 0; + m_sent_bits = 0; + m_strobe_clock = 0; + m_midi_mode = MIRACLE_MIDI_WAITING; + + // set standard MIDI parameters + set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1); + set_rcv_rate(31250); + set_tra_rate(31250); + + m_xmit_read = m_xmit_write = 0; + m_recv_read = m_recv_write = 0; + m_read_status = m_status_bit = false; + m_tx_busy = false; +} + + +//------------------------------------------------- +// read +//------------------------------------------------- + +UINT8 snes_miracle_device::read_pin4() +{ + UINT8 ret = 0; + + if (m_midi_mode == MIRACLE_MIDI_RECEIVE) + { + if (m_status_bit) + { + m_status_bit = false; + ret = (m_read_status) ? 1 : 0; + } + else + { + ret = (m_data_sent & 0x80) ? 0 : 1; + m_data_sent <<= 1; + } + } + + return ret; +} + +//------------------------------------------------- +// write +//------------------------------------------------- + +// c4fc = start of recv routine +// c53a = start of send routine + +void snes_miracle_device::write_strobe(UINT8 data) +{ +// printf("write: %d (%d %02x %d)\n", data & 1, m_sent_bits, m_data_sent, m_midi_mode); + + if (m_midi_mode == MIRACLE_MIDI_SEND) + { + //SNES writes (data & 1) to Miracle Piano! + // 1st write is data present flag (1=data present) + // next 8 writes are actual data bits (with ^1) + m_sent_bits++; + m_data_sent <<= 1; + m_data_sent |= (data & 1); + // then we go back to waiting + if (m_sent_bits == 8) + { +// printf("xmit MIDI byte %02x\n", m_data_sent); + xmit_char(m_data_sent); + m_midi_mode = MIRACLE_MIDI_WAITING; + m_sent_bits = 0; + } + + return; + } + + if (data == 1 && !m_strobe_on) + { + strobe_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + m_strobe_on = 1; + return; + } + + if (m_strobe_on) + { + // was timer running? + if (m_strobe_clock > 0) + { +// printf("got strobe at %d clocks\n", m_strobe_clock); + + if (m_strobe_clock < 528 && data == 0) + { + // short delay is recieve mode + m_midi_mode = MIRACLE_MIDI_RECEIVE; + strobe_timer->reset(); + m_strobe_on = 0; + m_strobe_clock = 0; + + m_status_bit = true; + if (m_recv_read != m_recv_write) + { +// printf("Getting %02x from Miracle[%d]\n", m_recvring[m_recv_read], m_recv_read); + m_data_sent = m_recvring[m_recv_read++]; + if (m_recv_read >= RECV_RING_SIZE) + { + m_recv_read = 0; + } + m_read_status = true; + } + else + { + m_read_status = false; +// printf("Miracle has no data\n"); + } + return; + } + else if (m_strobe_clock >= 528) + { + // more than 528 clocks since strobe on write means send mode + m_midi_mode = MIRACLE_MIDI_SEND; + strobe_timer->reset(); + m_strobe_on = 0; + m_strobe_clock = 0; + m_sent_bits = 1; + m_data_sent <<= 1; + m_data_sent |= (data & 1); + return; + } + } + + if (m_midi_mode == MIRACLE_MIDI_SEND && data == 0) + { + // strobe off after the end of a byte + m_midi_mode = MIRACLE_MIDI_WAITING; + } + } +} + +void snes_miracle_device::rcv_complete() // Rx completed receiving byte +{ + receive_register_extract(); + UINT8 rcv = get_received_char(); + +// printf("Got %02x -> [%d]\n", rcv, m_recv_write); + m_recvring[m_recv_write++] = rcv; + if (m_recv_write >= RECV_RING_SIZE) + { + m_recv_write = 0; + } +} + +void snes_miracle_device::tra_complete() // Tx completed sending byte +{ + // is there more waiting to send? + if (m_xmit_read != m_xmit_write) + { + transmit_register_setup(m_xmitring[m_xmit_read++]); + if (m_xmit_read >= XMIT_RING_SIZE) + { + m_xmit_read = 0; + } + } + else + { + m_tx_busy = false; + } +} + +void snes_miracle_device::tra_callback() // Tx send bit +{ + UINT8 bit = transmit_register_get_data_bit(); + + // send this to midi out + m_midiout->write_txd(bit); +} + +void snes_miracle_device::xmit_char(UINT8 data) +{ + // if tx is busy it'll pick this up automatically when it completes + // if not, send now! + if (!m_tx_busy) + { + m_tx_busy = true; + transmit_register_setup(data); + } + else + { + // tx is busy, it'll pick this up next time + m_xmitring[m_xmit_write++] = data; + if (m_xmit_write >= XMIT_RING_SIZE) + { + m_xmit_write = 0; + } + } +} + diff --git a/src/emu/bus/snes_ctrl/miracle.h b/src/emu/bus/snes_ctrl/miracle.h new file mode 100644 index 00000000000..383edfbbfda --- /dev/null +++ b/src/emu/bus/snes_ctrl/miracle.h @@ -0,0 +1,72 @@ +/********************************************************************** + + Nintendo Entertainment System - Miracle Piano Keyboard + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +**********************************************************************/ + +#pragma once + +#ifndef __SNES_MIRACLE__ +#define __SNES_MIRACLE__ + + +#include "emu.h" +#include "ctrl.h" +#include "bus/midi/midi.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> snes_miracle_device + +class snes_miracle_device : public device_t, + public device_serial_interface, + public device_snes_control_port_interface +{ +public: + static const int XMIT_RING_SIZE = 64; + static const int RECV_RING_SIZE = 64; + + // construction/destruction + snes_miracle_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual machine_config_constructor device_mconfig_additions() const; + + // serial overrides + virtual void rcv_complete(); // Rx completed receiving byte + virtual void tra_complete(); // Tx completed sending byte + virtual void tra_callback(); // Tx send bit + + void xmit_char(UINT8 data); + + required_device m_midiin, m_midiout; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual UINT8 read_pin4(); + virtual void write_strobe(UINT8 data); + + static const device_timer_id TIMER_STROBE_ON = 0; + emu_timer *strobe_timer; + + int m_strobe_on, m_midi_mode, m_sent_bits; + UINT32 m_strobe_clock; + UINT8 m_data_sent; + UINT8 m_xmitring[XMIT_RING_SIZE], m_recvring[RECV_RING_SIZE]; + int m_xmit_read, m_xmit_write; + int m_recv_read, m_recv_write; + bool m_tx_busy, m_read_status, m_status_bit; +}; + +// device type definition +extern const device_type SNES_MIRACLE; + +#endif -- cgit v1.2.3