trunk/src/emu/bus/snes_ctrl/miracle.c
| r0 | r243315 | |
| 1 | /********************************************************************** |
| 2 | |
| 3 | Nintendo SNES - Miracle Piano Keyboard |
| 4 | |
| 5 | TODO: ??? |
| 6 | |
| 7 | Copyright MESS Team. |
| 8 | Visit http://mamedev.org for licensing and usage restrictions. |
| 9 | |
| 10 | **********************************************************************/ |
| 11 | |
| 12 | #include "miracle.h" |
| 13 | |
| 14 | #define MIRACLE_MIDI_WAITING 0 |
| 15 | #define MIRACLE_MIDI_RECEIVE 1 // receive byte from piano |
| 16 | #define MIRACLE_MIDI_SEND 2 // send byte to piano |
| 17 | |
| 18 | //************************************************************************** |
| 19 | // DEVICE DEFINITIONS |
| 20 | //************************************************************************** |
| 21 | |
| 22 | const device_type SNES_MIRACLE = &device_creator<snes_miracle_device>; |
| 23 | |
| 24 | |
| 25 | MACHINE_CONFIG_FRAGMENT( snes_miracle ) |
| 26 | MCFG_MIDI_PORT_ADD("mdin", midiin_slot, "midiin") |
| 27 | MCFG_MIDI_RX_HANDLER(WRITELINE(snes_miracle_device, rx_w)) |
| 28 | |
| 29 | MCFG_MIDI_PORT_ADD("mdout", midiout_slot, "midiout") |
| 30 | MACHINE_CONFIG_END |
| 31 | |
| 32 | machine_config_constructor snes_miracle_device::device_mconfig_additions() const |
| 33 | { |
| 34 | return MACHINE_CONFIG_NAME( snes_miracle ); |
| 35 | } |
| 36 | |
| 37 | |
| 38 | //------------------------------------------------- |
| 39 | // device_timer - handler timer events |
| 40 | //------------------------------------------------- |
| 41 | |
| 42 | void snes_miracle_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) |
| 43 | { |
| 44 | if (id == TIMER_STROBE_ON) |
| 45 | { |
| 46 | m_strobe_clock++; |
| 47 | } |
| 48 | else |
| 49 | { |
| 50 | device_serial_interface::device_timer(timer, id, param, ptr); |
| 51 | } |
| 52 | } |
| 53 | |
| 54 | //************************************************************************** |
| 55 | // LIVE DEVICE |
| 56 | //************************************************************************** |
| 57 | |
| 58 | //------------------------------------------------- |
| 59 | // snes_miracle_device - constructor |
| 60 | //------------------------------------------------- |
| 61 | |
| 62 | snes_miracle_device::snes_miracle_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : |
| 63 | device_t(mconfig, SNES_MIRACLE, "Miracle Piano Controller (SNES)", tag, owner, clock, "snes_miracle", __FILE__), |
| 64 | device_serial_interface(mconfig, *this), |
| 65 | device_snes_control_port_interface(mconfig, *this), |
| 66 | m_midiin(*this, "mdin"), |
| 67 | m_midiout(*this, "mdout") |
| 68 | { |
| 69 | } |
| 70 | |
| 71 | |
| 72 | //------------------------------------------------- |
| 73 | // device_start |
| 74 | //------------------------------------------------- |
| 75 | |
| 76 | void snes_miracle_device::device_start() |
| 77 | { |
| 78 | strobe_timer = timer_alloc(TIMER_STROBE_ON); |
| 79 | strobe_timer->adjust(attotime::never); |
| 80 | save_item(NAME(m_strobe_on)); |
| 81 | save_item(NAME(m_sent_bits)); |
| 82 | save_item(NAME(m_strobe_clock)); |
| 83 | save_item(NAME(m_midi_mode)); |
| 84 | } |
| 85 | |
| 86 | |
| 87 | //------------------------------------------------- |
| 88 | // device_reset |
| 89 | //------------------------------------------------- |
| 90 | |
| 91 | void snes_miracle_device::device_reset() |
| 92 | { |
| 93 | m_strobe_on = 0; |
| 94 | m_sent_bits = 0; |
| 95 | m_strobe_clock = 0; |
| 96 | m_midi_mode = MIRACLE_MIDI_WAITING; |
| 97 | |
| 98 | // set standard MIDI parameters |
| 99 | set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1); |
| 100 | set_rcv_rate(31250); |
| 101 | set_tra_rate(31250); |
| 102 | |
| 103 | m_xmit_read = m_xmit_write = 0; |
| 104 | m_recv_read = m_recv_write = 0; |
| 105 | m_read_status = m_status_bit = false; |
| 106 | m_tx_busy = false; |
| 107 | } |
| 108 | |
| 109 | |
| 110 | //------------------------------------------------- |
| 111 | // read |
| 112 | //------------------------------------------------- |
| 113 | |
| 114 | UINT8 snes_miracle_device::read_pin4() |
| 115 | { |
| 116 | UINT8 ret = 0; |
| 117 | |
| 118 | if (m_midi_mode == MIRACLE_MIDI_RECEIVE) |
| 119 | { |
| 120 | if (m_status_bit) |
| 121 | { |
| 122 | m_status_bit = false; |
| 123 | ret = (m_read_status) ? 1 : 0; |
| 124 | } |
| 125 | else |
| 126 | { |
| 127 | ret = (m_data_sent & 0x80) ? 0 : 1; |
| 128 | m_data_sent <<= 1; |
| 129 | } |
| 130 | } |
| 131 | |
| 132 | return ret; |
| 133 | } |
| 134 | |
| 135 | //------------------------------------------------- |
| 136 | // write |
| 137 | //------------------------------------------------- |
| 138 | |
| 139 | // c4fc = start of recv routine |
| 140 | // c53a = start of send routine |
| 141 | |
| 142 | void snes_miracle_device::write_strobe(UINT8 data) |
| 143 | { |
| 144 | // printf("write: %d (%d %02x %d)\n", data & 1, m_sent_bits, m_data_sent, m_midi_mode); |
| 145 | |
| 146 | if (m_midi_mode == MIRACLE_MIDI_SEND) |
| 147 | { |
| 148 | //SNES writes (data & 1) to Miracle Piano! |
| 149 | // 1st write is data present flag (1=data present) |
| 150 | // next 8 writes are actual data bits (with ^1) |
| 151 | m_sent_bits++; |
| 152 | m_data_sent <<= 1; |
| 153 | m_data_sent |= (data & 1); |
| 154 | // then we go back to waiting |
| 155 | if (m_sent_bits == 8) |
| 156 | { |
| 157 | // printf("xmit MIDI byte %02x\n", m_data_sent); |
| 158 | xmit_char(m_data_sent); |
| 159 | m_midi_mode = MIRACLE_MIDI_WAITING; |
| 160 | m_sent_bits = 0; |
| 161 | } |
| 162 | |
| 163 | return; |
| 164 | } |
| 165 | |
| 166 | if (data == 1 && !m_strobe_on) |
| 167 | { |
| 168 | strobe_timer->adjust(attotime::zero, 0, machine().device<cpu_device>("maincpu")->cycles_to_attotime(1)); |
| 169 | m_strobe_on = 1; |
| 170 | return; |
| 171 | } |
| 172 | |
| 173 | if (m_strobe_on) |
| 174 | { |
| 175 | // was timer running? |
| 176 | if (m_strobe_clock > 0) |
| 177 | { |
| 178 | // printf("got strobe at %d clocks\n", m_strobe_clock); |
| 179 | |
| 180 | if (m_strobe_clock < 528 && data == 0) |
| 181 | { |
| 182 | // short delay is recieve mode |
| 183 | m_midi_mode = MIRACLE_MIDI_RECEIVE; |
| 184 | strobe_timer->reset(); |
| 185 | m_strobe_on = 0; |
| 186 | m_strobe_clock = 0; |
| 187 | |
| 188 | m_status_bit = true; |
| 189 | if (m_recv_read != m_recv_write) |
| 190 | { |
| 191 | // printf("Getting %02x from Miracle[%d]\n", m_recvring[m_recv_read], m_recv_read); |
| 192 | m_data_sent = m_recvring[m_recv_read++]; |
| 193 | if (m_recv_read >= RECV_RING_SIZE) |
| 194 | { |
| 195 | m_recv_read = 0; |
| 196 | } |
| 197 | m_read_status = true; |
| 198 | } |
| 199 | else |
| 200 | { |
| 201 | m_read_status = false; |
| 202 | // printf("Miracle has no data\n"); |
| 203 | } |
| 204 | return; |
| 205 | } |
| 206 | else if (m_strobe_clock >= 528) |
| 207 | { |
| 208 | // more than 528 clocks since strobe on write means send mode |
| 209 | m_midi_mode = MIRACLE_MIDI_SEND; |
| 210 | strobe_timer->reset(); |
| 211 | m_strobe_on = 0; |
| 212 | m_strobe_clock = 0; |
| 213 | m_sent_bits = 1; |
| 214 | m_data_sent <<= 1; |
| 215 | m_data_sent |= (data & 1); |
| 216 | return; |
| 217 | } |
| 218 | } |
| 219 | |
| 220 | if (m_midi_mode == MIRACLE_MIDI_SEND && data == 0) |
| 221 | { |
| 222 | // strobe off after the end of a byte |
| 223 | m_midi_mode = MIRACLE_MIDI_WAITING; |
| 224 | } |
| 225 | } |
| 226 | } |
| 227 | |
| 228 | void snes_miracle_device::rcv_complete() // Rx completed receiving byte |
| 229 | { |
| 230 | receive_register_extract(); |
| 231 | UINT8 rcv = get_received_char(); |
| 232 | |
| 233 | // printf("Got %02x -> [%d]\n", rcv, m_recv_write); |
| 234 | m_recvring[m_recv_write++] = rcv; |
| 235 | if (m_recv_write >= RECV_RING_SIZE) |
| 236 | { |
| 237 | m_recv_write = 0; |
| 238 | } |
| 239 | } |
| 240 | |
| 241 | void snes_miracle_device::tra_complete() // Tx completed sending byte |
| 242 | { |
| 243 | // is there more waiting to send? |
| 244 | if (m_xmit_read != m_xmit_write) |
| 245 | { |
| 246 | transmit_register_setup(m_xmitring[m_xmit_read++]); |
| 247 | if (m_xmit_read >= XMIT_RING_SIZE) |
| 248 | { |
| 249 | m_xmit_read = 0; |
| 250 | } |
| 251 | } |
| 252 | else |
| 253 | { |
| 254 | m_tx_busy = false; |
| 255 | } |
| 256 | } |
| 257 | |
| 258 | void snes_miracle_device::tra_callback() // Tx send bit |
| 259 | { |
| 260 | UINT8 bit = transmit_register_get_data_bit(); |
| 261 | |
| 262 | // send this to midi out |
| 263 | m_midiout->write_txd(bit); |
| 264 | } |
| 265 | |
| 266 | void snes_miracle_device::xmit_char(UINT8 data) |
| 267 | { |
| 268 | // if tx is busy it'll pick this up automatically when it completes |
| 269 | // if not, send now! |
| 270 | if (!m_tx_busy) |
| 271 | { |
| 272 | m_tx_busy = true; |
| 273 | transmit_register_setup(data); |
| 274 | } |
| 275 | else |
| 276 | { |
| 277 | // tx is busy, it'll pick this up next time |
| 278 | m_xmitring[m_xmit_write++] = data; |
| 279 | if (m_xmit_write >= XMIT_RING_SIZE) |
| 280 | { |
| 281 | m_xmit_write = 0; |
| 282 | } |
| 283 | } |
| 284 | } |
| 285 | |
trunk/src/emu/bus/snes_ctrl/miracle.h
| r0 | r243315 | |
| 1 | /********************************************************************** |
| 2 | |
| 3 | Nintendo Entertainment System - Miracle Piano Keyboard |
| 4 | |
| 5 | Copyright MESS Team. |
| 6 | Visit http://mamedev.org for licensing and usage restrictions. |
| 7 | |
| 8 | **********************************************************************/ |
| 9 | |
| 10 | #pragma once |
| 11 | |
| 12 | #ifndef __SNES_MIRACLE__ |
| 13 | #define __SNES_MIRACLE__ |
| 14 | |
| 15 | |
| 16 | #include "emu.h" |
| 17 | #include "ctrl.h" |
| 18 | #include "bus/midi/midi.h" |
| 19 | |
| 20 | //************************************************************************** |
| 21 | // TYPE DEFINITIONS |
| 22 | //************************************************************************** |
| 23 | |
| 24 | // ======================> snes_miracle_device |
| 25 | |
| 26 | class snes_miracle_device : public device_t, |
| 27 | public device_serial_interface, |
| 28 | public device_snes_control_port_interface |
| 29 | { |
| 30 | public: |
| 31 | static const int XMIT_RING_SIZE = 64; |
| 32 | static const int RECV_RING_SIZE = 64; |
| 33 | |
| 34 | // construction/destruction |
| 35 | snes_miracle_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 36 | |
| 37 | virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); |
| 38 | virtual machine_config_constructor device_mconfig_additions() const; |
| 39 | |
| 40 | // serial overrides |
| 41 | virtual void rcv_complete(); // Rx completed receiving byte |
| 42 | virtual void tra_complete(); // Tx completed sending byte |
| 43 | virtual void tra_callback(); // Tx send bit |
| 44 | |
| 45 | void xmit_char(UINT8 data); |
| 46 | |
| 47 | required_device<midi_port_device> m_midiin, m_midiout; |
| 48 | |
| 49 | protected: |
| 50 | // device-level overrides |
| 51 | virtual void device_start(); |
| 52 | virtual void device_reset(); |
| 53 | |
| 54 | virtual UINT8 read_pin4(); |
| 55 | virtual void write_strobe(UINT8 data); |
| 56 | |
| 57 | static const device_timer_id TIMER_STROBE_ON = 0; |
| 58 | emu_timer *strobe_timer; |
| 59 | |
| 60 | int m_strobe_on, m_midi_mode, m_sent_bits; |
| 61 | UINT32 m_strobe_clock; |
| 62 | UINT8 m_data_sent; |
| 63 | UINT8 m_xmitring[XMIT_RING_SIZE], m_recvring[RECV_RING_SIZE]; |
| 64 | int m_xmit_read, m_xmit_write; |
| 65 | int m_recv_read, m_recv_write; |
| 66 | bool m_tx_busy, m_read_status, m_status_bit; |
| 67 | }; |
| 68 | |
| 69 | // device type definition |
| 70 | extern const device_type SNES_MIRACLE; |
| 71 | |
| 72 | #endif |