trunk/src/mess/machine/psxcport.c
| r22680 | r22681 | |
| 2 | 2 | |
| 3 | 3 | #include "machine/psxcport.h" |
| 4 | 4 | #include "machine/psxanalog.h" |
| 5 | #include "machine/psxmultitap.h" |
| 5 | 6 | |
| 6 | 7 | const device_type PSX_CONTROLLER_PORT = &device_creator<psx_controller_port_device>; |
| 7 | 8 | |
| r22680 | r22681 | |
| 26 | 27 | return MACHINE_CONFIG_NAME( psx_memory_card ); |
| 27 | 28 | } |
| 28 | 29 | |
| 30 | void psx_controller_port_device::disable_card(bool state) |
| 31 | { |
| 32 | if(state) |
| 33 | popmessage("Memory card port %s is disabled\n", m_card->brief_instance_name()); |
| 34 | |
| 35 | m_card->disable(state); |
| 36 | } |
| 37 | |
| 29 | 38 | const device_type PSXCONTROLLERPORTS = &device_creator<psxcontrollerports_device>; |
| 30 | 39 | |
| 31 | 40 | psxcontrollerports_device::psxcontrollerports_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : |
| r22680 | r22681 | |
| 42 | 51 | psxsiodev_device::device_start(); |
| 43 | 52 | } |
| 44 | 53 | |
| 54 | // add controllers to define so they can be connected to the multitap |
| 55 | #define PSX_CONTROLLERS \ |
| 56 | SLOT_INTERFACE("digital_pad", PSX_STANDARD_CONTROLLER) \ |
| 57 | SLOT_INTERFACE("dualshock_pad", PSX_DUALSHOCK) \ |
| 58 | SLOT_INTERFACE("analog_joystick", PSX_ANALOG_JOYSTICK) |
| 59 | |
| 45 | 60 | SLOT_INTERFACE_START(psx_controllers) |
| 46 | | SLOT_INTERFACE("digital_pad", PSX_STANDARD_CONTROLLER) |
| 47 | | SLOT_INTERFACE("dualshock_pad", PSX_DUALSHOCK) |
| 48 | | SLOT_INTERFACE("analog_joystick", PSX_ANALOG_JOYSTICK) |
| 61 | PSX_CONTROLLERS |
| 62 | SLOT_INTERFACE("multitap", PSX_MULTITAP) |
| 49 | 63 | SLOT_INTERFACE_END |
| 50 | 64 | |
| 65 | SLOT_INTERFACE_START(psx_controllers_nomulti) |
| 66 | PSX_CONTROLLERS |
| 67 | SLOT_INTERFACE_END |
| 68 | |
| 51 | 69 | void psxcontrollerports_device::data_in( int data, int mask ) |
| 52 | 70 | { |
| 53 | 71 | m_port0->sel_w((data & PSX_SIO_OUT_DTR)?1:0); |
trunk/src/mess/machine/psxmultitap.c
| r0 | r22681 | |
| 1 | // psx multitap emulation |
| 2 | |
| 3 | #include "machine/psxmultitap.h" |
| 4 | |
| 5 | const device_type PSX_MULTITAP = &device_creator<psx_multitap_device>; |
| 6 | |
| 7 | psx_multitap_device::psx_multitap_device(const machine_config& mconfig, const char* tag, device_t* owner, UINT32 clock) : |
| 8 | device_t(mconfig, PSX_MULTITAP, "Playstation Multitap", tag, owner, clock), |
| 9 | device_psx_controller_interface(mconfig, *this), |
| 10 | m_porta(*this, "a"), |
| 11 | m_portb(*this, "b"), |
| 12 | m_portc(*this, "c"), |
| 13 | m_portd(*this, "d") |
| 14 | { |
| 15 | } |
| 16 | |
| 17 | static MACHINE_CONFIG_FRAGMENT( psx_multitap ) |
| 18 | MCFG_PSX_CTRL_PORT_ADD("a", psx_controllers_nomulti, "digital_pad", NULL) |
| 19 | MCFG_PSX_CTRL_PORT_ADD("b", psx_controllers_nomulti, NULL, NULL) |
| 20 | MCFG_PSX_CTRL_PORT_ADD("c", psx_controllers_nomulti, NULL, NULL) |
| 21 | MCFG_PSX_CTRL_PORT_ADD("d", psx_controllers_nomulti, NULL, NULL) |
| 22 | MACHINE_CONFIG_END |
| 23 | |
| 24 | machine_config_constructor psx_multitap_device::device_mconfig_additions() const |
| 25 | { |
| 26 | return MACHINE_CONFIG_NAME( psx_multitap ); |
| 27 | } |
| 28 | |
| 29 | void psx_multitap_device::device_start() |
| 30 | { |
| 31 | m_porta->setup_ack_cb(psx_controller_port_device::void_cb(FUNC(psx_multitap_device::ack), this)); |
| 32 | m_portb->setup_ack_cb(psx_controller_port_device::void_cb(FUNC(psx_multitap_device::ack), this)); |
| 33 | m_portc->setup_ack_cb(psx_controller_port_device::void_cb(FUNC(psx_multitap_device::ack), this)); |
| 34 | m_portd->setup_ack_cb(psx_controller_port_device::void_cb(FUNC(psx_multitap_device::ack), this)); |
| 35 | m_nextmode = false; |
| 36 | } |
| 37 | |
| 38 | void psx_multitap_device::interface_pre_reset() |
| 39 | { |
| 40 | m_activeport = -1; |
| 41 | m_singlemode = m_nextmode; |
| 42 | m_tapmc = false; |
| 43 | m_cack[0] = m_cack[1] = m_cack[2] = m_cack[3] = true; |
| 44 | memset(m_data, 0xff, sizeof(m_data)); |
| 45 | m_porta->sel_w(false); |
| 46 | m_portb->sel_w(false); |
| 47 | m_portc->sel_w(false); |
| 48 | m_portd->sel_w(false); |
| 49 | m_porta->sel_w(true); |
| 50 | m_portb->sel_w(true); |
| 51 | m_portc->sel_w(true); |
| 52 | m_portd->sel_w(true); |
| 53 | device_psx_controller_interface::interface_pre_reset(); |
| 54 | } |
| 55 | |
| 56 | void psx_multitap_device::set_tx_line(bool tx, int port) |
| 57 | { |
| 58 | psx_controller_port_device *dev; |
| 59 | switch(port) |
| 60 | { |
| 61 | default: |
| 62 | case 0: |
| 63 | dev = m_porta; |
| 64 | break; |
| 65 | case 1: |
| 66 | dev = m_portb; |
| 67 | break; |
| 68 | case 2: |
| 69 | dev = m_portc; |
| 70 | break; |
| 71 | case 3: |
| 72 | dev = m_portd; |
| 73 | break; |
| 74 | } |
| 75 | dev->clock_w(1); |
| 76 | dev->tx_w(tx); |
| 77 | dev->clock_w(0); |
| 78 | } |
| 79 | |
| 80 | bool psx_multitap_device::get_rx_line(int port) |
| 81 | { |
| 82 | psx_controller_port_device *dev; |
| 83 | switch(port) |
| 84 | { |
| 85 | default: |
| 86 | case 0: |
| 87 | dev = m_porta; |
| 88 | break; |
| 89 | case 1: |
| 90 | dev = m_portb; |
| 91 | break; |
| 92 | case 2: |
| 93 | dev = m_portc; |
| 94 | break; |
| 95 | case 3: |
| 96 | dev = m_portd; |
| 97 | break; |
| 98 | } |
| 99 | return dev->rx_r(); |
| 100 | } |
| 101 | |
| 102 | void psx_multitap_device::do_pad() |
| 103 | { |
| 104 | bool tx = device_psx_controller_interface::m_owner->tx_r(); |
| 105 | |
| 106 | // we don't know which controller until after the first byte |
| 107 | if((m_singlemode || m_tapmc) && (m_count >= 1)) |
| 108 | { |
| 109 | if((m_count == 2) && !m_bit && !m_tapmc) |
| 110 | m_nextmode = !tx; |
| 111 | |
| 112 | set_tx_line(tx, m_activeport); |
| 113 | m_rx = get_rx_line(m_activeport); |
| 114 | m_bit = (m_bit + 1) % 8; |
| 115 | if(!m_bit) |
| 116 | m_count++; |
| 117 | return; |
| 118 | } |
| 119 | |
| 120 | if(!m_count) |
| 121 | { |
| 122 | // first send the select byte to all devices until we know whether it's accessing |
| 123 | // a controller or memcard |
| 124 | if(!m_bit) |
| 125 | { |
| 126 | m_porta->sel_w(false); |
| 127 | m_portb->sel_w(false); |
| 128 | m_portc->sel_w(false); |
| 129 | m_portd->sel_w(false); |
| 130 | } |
| 131 | device_psx_controller_interface::do_pad(); |
| 132 | set_tx_line(tx, 0); |
| 133 | set_tx_line(tx, 1); |
| 134 | set_tx_line(tx, 2); |
| 135 | set_tx_line(tx, 3); |
| 136 | if(!m_bit) |
| 137 | { |
| 138 | m_count = 1; |
| 139 | m_tapmc = m_memcard; |
| 140 | m_memcard = false; // make sure we still receive clocks |
| 141 | if(m_singlemode || m_tapmc) |
| 142 | { |
| 143 | m_activeport = (m_idata & 0xf) - 1; |
| 144 | m_porta->sel_w((m_activeport == 0) ? false : true); |
| 145 | m_portb->sel_w((m_activeport == 1) ? false : true); |
| 146 | m_portc->sel_w((m_activeport == 2) ? false : true); |
| 147 | m_portd->sel_w((m_activeport == 3) ? false : true); |
| 148 | } |
| 149 | } |
| 150 | return; |
| 151 | } |
| 152 | else if(m_count <= 2) |
| 153 | return device_psx_controller_interface::do_pad(); |
| 154 | else if(m_count < 11) |
| 155 | { |
| 156 | if((m_count == 3) && !m_bit) |
| 157 | m_nextmode = !m_idata; |
| 158 | |
| 159 | if((m_count < 5) && m_cack[0] && m_cack[1] && m_cack[2] && m_cack[3]) |
| 160 | return; // no acks? hang up. |
| 161 | |
| 162 | // all of the ports are polled here, port a is passed though. the data |
| 163 | // from the other ports is stored and can be retrieved at a much higher clock rate |
| 164 | // don't poll a port that is inactive or done |
| 165 | if(!m_cack[0]) |
| 166 | { |
| 167 | set_tx_line(tx, 0); |
| 168 | m_rx = m_porta->rx_r(); |
| 169 | } |
| 170 | else |
| 171 | { |
| 172 | m_rx = true; |
| 173 | m_porta->sel_w(true); |
| 174 | } |
| 175 | |
| 176 | if(!m_cack[1]) |
| 177 | { |
| 178 | set_tx_line(tx, 1); |
| 179 | m_data[0][m_count - 3] &= ~(!m_portb->rx_r() << m_bit); |
| 180 | } |
| 181 | else |
| 182 | m_portb->sel_w(true); |
| 183 | |
| 184 | if(!m_cack[2]) |
| 185 | { |
| 186 | set_tx_line(tx, 2); |
| 187 | m_data[1][m_count - 3] &= ~(!m_portc->rx_r() << m_bit); |
| 188 | } |
| 189 | else |
| 190 | m_portc->sel_w(true); |
| 191 | |
| 192 | if(!m_cack[3]) |
| 193 | { |
| 194 | set_tx_line(tx, 3); |
| 195 | m_data[2][m_count - 3] &= ~(!m_portd->rx_r() << m_bit); |
| 196 | } |
| 197 | else |
| 198 | m_portd->sel_w(true); |
| 199 | } |
| 200 | else if(m_count < 19) |
| 201 | // send stored port b data |
| 202 | m_rx = ((m_data[0][m_count - 11] & (1 << m_bit)) ? 1 : 0); |
| 203 | else if(m_count < 27) |
| 204 | // send stored port c data |
| 205 | m_rx = ((m_data[1][m_count - 19] & (1 << m_bit)) ? 1 : 0); |
| 206 | else |
| 207 | // send stored port d data |
| 208 | m_rx = ((m_data[2][m_count - 27] & (1 << m_bit)) ? 1 : 0); |
| 209 | |
| 210 | if(m_bit == 7) |
| 211 | { |
| 212 | // ports won't ack if they are done |
| 213 | m_cack[0] = m_cack[1] = m_cack[2] = m_cack[3] = true; |
| 214 | if(m_count < 11) |
| 215 | m_ack_timer->adjust(attotime::from_usec(12), 0); // give a bit of time for the ports to ack |
| 216 | else if(m_count < 35) |
| 217 | m_ack_timer->adjust(attotime::from_usec(10), 0); |
| 218 | } |
| 219 | |
| 220 | m_bit = (m_bit + 1) % 8; |
| 221 | if(!m_bit) |
| 222 | m_count++; |
| 223 | } |
| 224 | |
| 225 | bool psx_multitap_device::get_pad(int count, UINT8 *odata, UINT8 idata) |
| 226 | { |
| 227 | if(!count) |
| 228 | *odata = 0x80; |
| 229 | else |
| 230 | *odata = 0x5a; |
| 231 | return true; |
| 232 | } |
| 233 | |
| 234 | void psx_multitap_device::ack() |
| 235 | { |
| 236 | if(m_activeport != -1) |
| 237 | { |
| 238 | switch(m_activeport) |
| 239 | { |
| 240 | case 0: |
| 241 | m_ack = m_porta->ack_r(); |
| 242 | break; |
| 243 | case 1: |
| 244 | m_ack = m_portb->ack_r(); |
| 245 | break; |
| 246 | case 2: |
| 247 | m_ack = m_portc->ack_r(); |
| 248 | break; |
| 249 | case 3: |
| 250 | m_ack = m_portd->ack_r(); |
| 251 | break; |
| 252 | default: |
| 253 | return; |
| 254 | } |
| 255 | device_psx_controller_interface::m_owner->ack(); |
| 256 | return; |
| 257 | } |
| 258 | if(!m_porta->ack_r()) |
| 259 | m_cack[0] = false; |
| 260 | if(!m_portb->ack_r()) |
| 261 | m_cack[1] = false; |
| 262 | if(!m_portc->ack_r()) |
| 263 | m_cack[2] = false; |
| 264 | if(!m_portd->ack_r()) |
| 265 | m_cack[3] = false; |
| 266 | } |
trunk/src/mess/machine/psxmultitap.h
| r0 | r22681 | |
| 1 | #ifndef PSXMULTITAP_H_ |
| 2 | #define PSXMULTITAP_H_ |
| 3 | |
| 4 | #include "machine/psxcport.h" |
| 5 | |
| 6 | SLOT_INTERFACE_EXTERN(psx_controllers_nomulti); |
| 7 | |
| 8 | class psx_multitap_device : public device_t, |
| 9 | public device_psx_controller_interface |
| 10 | { |
| 11 | public: |
| 12 | psx_multitap_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 13 | virtual machine_config_constructor device_mconfig_additions() const; |
| 14 | |
| 15 | protected: |
| 16 | virtual void device_start(); |
| 17 | virtual void device_stop() { device_psx_controller_interface::m_owner->disable_card(false); } |
| 18 | virtual void device_reset() { device_psx_controller_interface::m_owner->disable_card(true); } |
| 19 | virtual void device_config_complete() { m_shortname = "psx_multitap"; } |
| 20 | virtual void interface_pre_reset(); |
| 21 | |
| 22 | private: |
| 23 | virtual bool get_pad(int count, UINT8 *odata, UINT8 idata); |
| 24 | virtual void do_pad(); |
| 25 | void ack(); |
| 26 | void set_tx_line(bool tx, int port); |
| 27 | bool get_rx_line(int port); |
| 28 | |
| 29 | int m_activeport; |
| 30 | bool m_cack[4]; |
| 31 | bool m_singlemode, m_nextmode, m_tapmc; |
| 32 | UINT8 m_data[3][8]; // port a is passed though |
| 33 | required_device<psx_controller_port_device> m_porta; |
| 34 | required_device<psx_controller_port_device> m_portb; |
| 35 | required_device<psx_controller_port_device> m_portc; |
| 36 | required_device<psx_controller_port_device> m_portd; |
| 37 | }; |
| 38 | |
| 39 | extern const device_type PSX_MULTITAP; |
| 40 | |
| 41 | #endif /* PSXMULTITAP_H_ */ |