trunk/src/emu/bus/psx/analogue.c
| r0 | r241420 | |
| 1 | #include "analogue.h" |
| 2 | |
| 3 | const device_type PSX_ANALOG_JOYSTICK = &device_creator<psx_analog_joystick_device>; |
| 4 | const device_type PSX_DUALSHOCK = &device_creator<psx_dualshock_device>; |
| 5 | |
| 6 | psx_analog_controller_device::psx_analog_controller_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : |
| 7 | device_t(mconfig, type, name, tag, owner, clock, shortname, source), |
| 8 | device_psx_controller_interface(mconfig, *this), |
| 9 | m_pad0(*this, "PSXPAD0"), |
| 10 | m_pad1(*this, "PSXPAD1"), |
| 11 | m_rstickx(*this, "PSXRSTICKX"), |
| 12 | m_rsticky(*this, "PSXRSTICKY"), |
| 13 | m_lstickx(*this, "PSXLSTICKX"), |
| 14 | m_lsticky(*this, "PSXLSTICKY") |
| 15 | { |
| 16 | } |
| 17 | |
| 18 | psx_dualshock_device::psx_dualshock_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : |
| 19 | psx_analog_controller_device(mconfig, PSX_DUALSHOCK, "Playstation Dualshock Pad", tag, owner, clock, "psx_dualshock_pad", __FILE__) |
| 20 | { |
| 21 | m_type = DUALSHOCK; |
| 22 | } |
| 23 | |
| 24 | psx_analog_joystick_device::psx_analog_joystick_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : |
| 25 | psx_analog_controller_device(mconfig, PSX_ANALOG_JOYSTICK, "Playstation Analog Joystick", tag, owner, clock, "psx_analog_joystick", __FILE__) |
| 26 | { |
| 27 | m_type = JOYSTICK; |
| 28 | } |
| 29 | |
| 30 | void psx_analog_controller_device::device_reset() |
| 31 | { |
| 32 | m_confmode = false; |
| 33 | m_analogmode = false; |
| 34 | m_analoglock = false; |
| 35 | |
| 36 | m_cmd = 0; |
| 37 | } |
| 38 | |
| 39 | UINT8 psx_analog_controller_device::pad_data(int count, bool analog) |
| 40 | { |
| 41 | UINT8 data = 0; |
| 42 | switch(count) |
| 43 | { |
| 44 | case 2: |
| 45 | data = m_pad0->read(); |
| 46 | if(!analog || (m_type == JOYSTICK)) |
| 47 | data |= 6; // l3/r3 |
| 48 | break; |
| 49 | case 3: |
| 50 | data = m_pad1->read(); |
| 51 | break; |
| 52 | case 4: |
| 53 | data = m_rstickx->read(); |
| 54 | break; |
| 55 | case 5: |
| 56 | data = m_rsticky->read(); |
| 57 | break; |
| 58 | case 6: |
| 59 | data = m_lstickx->read(); |
| 60 | break; |
| 61 | case 7: |
| 62 | data = m_lsticky->read(); |
| 63 | break; |
| 64 | } |
| 65 | return data; |
| 66 | } |
| 67 | |
| 68 | bool psx_analog_controller_device::get_pad(int count, UINT8 *odata, UINT8 idata) |
| 69 | { |
| 70 | if(m_confmode) |
| 71 | { |
| 72 | switch(count) |
| 73 | { |
| 74 | case 0: |
| 75 | m_temp = 0; |
| 76 | *odata = 0xf3; |
| 77 | break; |
| 78 | case 1: |
| 79 | m_cmd = idata; |
| 80 | if((m_cmd & 0xf0) != 0x40) |
| 81 | return false; |
| 82 | *odata = 0x5a; |
| 83 | break; |
| 84 | default: |
| 85 | switch(m_cmd) |
| 86 | { |
| 87 | default: // 40,41,48,49,4a,4b,4f -- all unknown |
| 88 | *odata = 0x00; |
| 89 | break; |
| 90 | case CONFIG_MODE: // 43 |
| 91 | if(count == 3) |
| 92 | m_temp = idata; |
| 93 | /* no break */ |
| 94 | case QUERY_PAD_STATE: // 42 |
| 95 | *odata = pad_data(count, true); |
| 96 | break; |
| 97 | case 0x44: // set mode and lock ? |
| 98 | switch(count) |
| 99 | { |
| 100 | case 3: |
| 101 | m_analogmode = idata ? true : false; // only 0x01 ? |
| 102 | break; |
| 103 | case 4: |
| 104 | m_analoglock = idata ? true : false; // only 0x03 ? |
| 105 | break; |
| 106 | } |
| 107 | *odata = 0x00; |
| 108 | break; |
| 109 | case 0x45: // get mode ? |
| 110 | { |
| 111 | const UINT8 val[] = { 1, 2, 0, 2, 1, 0 }; |
| 112 | if(count == 4) |
| 113 | *odata = m_analogmode; |
| 114 | else |
| 115 | *odata = val[count-2]; |
| 116 | break; |
| 117 | } |
| 118 | case 0x46: // query act (vibrate) ? |
| 119 | { |
| 120 | const UINT8 val[2][6] = {{ 0, 0, 1, 2, 0, 10 }, |
| 121 | { 0, 0, 1, 1, 1, 14 }}; |
| 122 | *odata = val[m_temp][count-2]; |
| 123 | if(count == 3) |
| 124 | m_temp = idata ? 1 : 0; |
| 125 | break; |
| 126 | } |
| 127 | case 0x47: // query comb (combination?) ? |
| 128 | { |
| 129 | const UINT8 val[] = { 0, 0, 2, 0, 1, 0 }; |
| 130 | *odata = val[count-2]; |
| 131 | break; |
| 132 | } |
| 133 | case 0x4c: // query mode ? |
| 134 | switch(count) |
| 135 | { |
| 136 | case 3: |
| 137 | m_temp = idata; |
| 138 | /* no break */ |
| 139 | default: |
| 140 | *odata = 0x00; |
| 141 | break; |
| 142 | case 5: |
| 143 | *odata = m_analogmode ? 0x07 : 0x04; // ? |
| 144 | break; |
| 145 | } |
| 146 | break; |
| 147 | case 0x4d: // set act (vibrate) ? |
| 148 | *odata = 0xff; |
| 149 | break; |
| 150 | } |
| 151 | break; |
| 152 | case 8: |
| 153 | if(m_cmd == CONFIG_MODE) |
| 154 | m_confmode = m_temp; |
| 155 | return false; |
| 156 | } |
| 157 | } |
| 158 | else if(m_analogmode) |
| 159 | { |
| 160 | switch(count) |
| 161 | { |
| 162 | case 0: |
| 163 | if(m_type == JOYSTICK) |
| 164 | *odata = 0x53; |
| 165 | else |
| 166 | *odata = 0x73; |
| 167 | break; |
| 168 | case 1: |
| 169 | m_cmd = idata; |
| 170 | if((m_cmd & 0xfe) != QUERY_PAD_STATE) |
| 171 | return false; |
| 172 | *odata = 0x5a; |
| 173 | break; |
| 174 | case 3: |
| 175 | if(m_cmd == CONFIG_MODE) |
| 176 | m_temp = idata; |
| 177 | /* no break */ |
| 178 | default: |
| 179 | *odata = pad_data(count, true); |
| 180 | break; |
| 181 | case 8: |
| 182 | if(m_cmd == CONFIG_MODE) |
| 183 | m_confmode = m_temp; |
| 184 | return false; |
| 185 | } |
| 186 | } |
| 187 | else |
| 188 | { |
| 189 | switch(count) |
| 190 | { |
| 191 | case 0: |
| 192 | *odata = 0x41; |
| 193 | break; |
| 194 | case 1: |
| 195 | m_cmd = idata; |
| 196 | if((m_cmd & 0xfe) != QUERY_PAD_STATE) |
| 197 | return false; |
| 198 | *odata = 0x5a; |
| 199 | break; |
| 200 | case 3: |
| 201 | if(m_cmd == CONFIG_MODE) |
| 202 | m_temp = idata; |
| 203 | /* no break */ |
| 204 | default: |
| 205 | *odata = pad_data(count, false); |
| 206 | break; |
| 207 | case 4: |
| 208 | if(m_cmd == CONFIG_MODE) |
| 209 | m_confmode = m_temp; |
| 210 | return false; |
| 211 | } |
| 212 | } |
| 213 | return true; |
| 214 | } |
| 215 | |
| 216 | static INPUT_PORTS_START( psx_analog_controller ) |
| 217 | PORT_START("PSXPAD0") |
| 218 | PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) |
| 219 | PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) |
| 220 | PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) |
| 221 | PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) |
| 222 | PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START ) |
| 223 | PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON9 ) PORT_NAME("R3") |
| 224 | PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON10 ) PORT_NAME("L3") |
| 225 | PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_SELECT ) |
| 226 | |
| 227 | PORT_START("PSXPAD1") |
| 228 | PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("Square") |
| 229 | PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("Cross") |
| 230 | PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("Circle") |
| 231 | PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("Triangle") |
| 232 | PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("R1") |
| 233 | PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("L1") |
| 234 | PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON7 ) PORT_NAME("R2") |
| 235 | PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON8 ) PORT_NAME("L2") |
| 236 | |
| 237 | PORT_START("PSXRSTICKX") |
| 238 | PORT_BIT( 0xff, 0x80, IPT_AD_STICK_X ) PORT_NAME("Right Analog X") PORT_SENSITIVITY(100) |
| 239 | |
| 240 | PORT_START("PSXRSTICKY") |
| 241 | PORT_BIT( 0xff, 0x80, IPT_AD_STICK_Y ) PORT_NAME("Right Analog Y") PORT_SENSITIVITY(100) |
| 242 | |
| 243 | PORT_START("PSXLSTICKX") |
| 244 | PORT_BIT( 0xff, 0x80, IPT_AD_STICK_Z ) PORT_NAME("Left Analog X") PORT_SENSITIVITY(100) |
| 245 | |
| 246 | PORT_START("PSXLSTICKY") |
| 247 | PORT_BIT( 0xff, 0x80, IPT_PADDLE ) PORT_NAME("Left Analog Y") PORT_SENSITIVITY(100) |
| 248 | |
| 249 | PORT_START("PSXMISC") |
| 250 | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON11 ) PORT_NAME("Analog") PORT_TOGGLE PORT_CHANGED_MEMBER(DEVICE_SELF, psx_analog_controller_device, change_mode, 0) |
| 251 | INPUT_PORTS_END |
| 252 | |
| 253 | ioport_constructor psx_analog_controller_device::device_input_ports() const |
| 254 | { |
| 255 | return INPUT_PORTS_NAME(psx_analog_controller); |
| 256 | } |
| 257 | |
| 258 | INPUT_CHANGED_MEMBER(psx_analog_controller_device::change_mode) |
| 259 | { |
| 260 | if(!m_analoglock) |
| 261 | m_analogmode = newval; |
| 262 | } |
trunk/src/emu/bus/psx/analogue.h
| r0 | r241420 | |
| 1 | #ifndef PSXANALOG_H_ |
| 2 | #define PSXANALOG_H_ |
| 3 | |
| 4 | #include "ctlrport.h" |
| 5 | |
| 6 | extern const device_type PSX_DUALSHOCK; |
| 7 | extern const device_type PSX_ANALOG_JOYSTICK; |
| 8 | |
| 9 | class psx_analog_controller_device : public device_t, |
| 10 | public device_psx_controller_interface |
| 11 | { |
| 12 | public: |
| 13 | psx_analog_controller_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); |
| 14 | |
| 15 | virtual ioport_constructor device_input_ports() const; |
| 16 | DECLARE_INPUT_CHANGED_MEMBER(change_mode); |
| 17 | protected: |
| 18 | virtual void device_reset(); |
| 19 | virtual void device_start() {} |
| 20 | enum { |
| 21 | JOYSTICK, |
| 22 | DUALSHOCK |
| 23 | } m_type; |
| 24 | private: |
| 25 | virtual bool get_pad(int count, UINT8 *odata, UINT8 idata); |
| 26 | UINT8 pad_data(int count, bool analog); |
| 27 | |
| 28 | bool m_confmode; |
| 29 | bool m_analogmode; |
| 30 | bool m_analoglock; |
| 31 | |
| 32 | UINT8 m_temp; |
| 33 | UINT8 m_cmd; |
| 34 | |
| 35 | required_ioport m_pad0; |
| 36 | required_ioport m_pad1; |
| 37 | required_ioport m_rstickx; |
| 38 | required_ioport m_rsticky; |
| 39 | required_ioport m_lstickx; |
| 40 | required_ioport m_lsticky; |
| 41 | }; |
| 42 | |
| 43 | class psx_dualshock_device : public psx_analog_controller_device |
| 44 | { |
| 45 | public: |
| 46 | psx_dualshock_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 47 | }; |
| 48 | |
| 49 | class psx_analog_joystick_device : public psx_analog_controller_device |
| 50 | { |
| 51 | public: |
| 52 | psx_analog_joystick_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 53 | }; |
| 54 | |
| 55 | #endif /* PSXANALOG_H_ */ |
trunk/src/emu/bus/psx/ctlrport.c
| r0 | r241420 | |
| 1 | /* PAD emulation */ |
| 2 | |
| 3 | #include "ctlrport.h" |
| 4 | #include "analogue.h" |
| 5 | #include "multitap.h" |
| 6 | |
| 7 | const device_type PSX_CONTROLLER_PORT = &device_creator<psx_controller_port_device>; |
| 8 | |
| 9 | psx_controller_port_device::psx_controller_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : |
| 10 | device_t(mconfig, PSX_CONTROLLER_PORT, "Playstation Controller Port", tag, owner, clock, "psx_controller_port", __FILE__), |
| 11 | device_slot_interface(mconfig, *this), |
| 12 | m_card(*this, "card") |
| 13 | { |
| 14 | } |
| 15 | |
| 16 | void psx_controller_port_device::device_config_complete() |
| 17 | { |
| 18 | m_dev = dynamic_cast<device_psx_controller_interface *>(get_card_device()); |
| 19 | } |
| 20 | |
| 21 | static MACHINE_CONFIG_FRAGMENT( psx_memory_card ) |
| 22 | MCFG_PSXCARD_ADD("card") |
| 23 | MACHINE_CONFIG_END |
| 24 | |
| 25 | machine_config_constructor psx_controller_port_device::device_mconfig_additions() const |
| 26 | { |
| 27 | return MACHINE_CONFIG_NAME( psx_memory_card ); |
| 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 | |
| 38 | const device_type PSXCONTROLLERPORTS = &device_creator<psxcontrollerports_device>; |
| 39 | |
| 40 | psxcontrollerports_device::psxcontrollerports_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : |
| 41 | psxsiodev_device(mconfig, PSXCONTROLLERPORTS, "PSXCONTROLLERPORTS", tag, owner, clock, "psxcontrollerports", __FILE__) |
| 42 | { |
| 43 | } |
| 44 | |
| 45 | void psxcontrollerports_device::device_start() |
| 46 | { |
| 47 | m_port0 = machine().device<psx_controller_port_device>("port1"); |
| 48 | m_port1 = machine().device<psx_controller_port_device>("port2"); |
| 49 | m_port0->setup_ack_cb(psx_controller_port_device::void_cb(FUNC(psxcontrollerports_device::ack), this)); |
| 50 | m_port1->setup_ack_cb(psx_controller_port_device::void_cb(FUNC(psxcontrollerports_device::ack), this)); |
| 51 | psxsiodev_device::device_start(); |
| 52 | } |
| 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 | |
| 60 | SLOT_INTERFACE_START(psx_controllers) |
| 61 | PSX_CONTROLLERS |
| 62 | SLOT_INTERFACE("multitap", PSX_MULTITAP) |
| 63 | SLOT_INTERFACE_END |
| 64 | |
| 65 | SLOT_INTERFACE_START(psx_controllers_nomulti) |
| 66 | PSX_CONTROLLERS |
| 67 | SLOT_INTERFACE_END |
| 68 | |
| 69 | void psxcontrollerports_device::data_in( int data, int mask ) |
| 70 | { |
| 71 | m_port0->sel_w((data & PSX_SIO_OUT_DTR)?1:0); |
| 72 | m_port0->tx_w((data & PSX_SIO_OUT_DATA)?1:0); |
| 73 | m_port0->clock_w((data & PSX_SIO_OUT_CLOCK)?1:0); // clock must be last |
| 74 | |
| 75 | m_port1->tx_w((data & PSX_SIO_OUT_DATA)?1:0); |
| 76 | m_port1->sel_w((data & PSX_SIO_OUT_DTR)?0:1); // not dtr |
| 77 | m_port1->clock_w((data & PSX_SIO_OUT_CLOCK)?1:0); |
| 78 | |
| 79 | data_out(((m_port0->rx_r() && m_port1->rx_r()) * PSX_SIO_IN_DATA), PSX_SIO_IN_DATA); |
| 80 | } |
| 81 | |
| 82 | void psxcontrollerports_device::ack() |
| 83 | { |
| 84 | data_out((!(m_port0->ack_r() && m_port1->ack_r()) * PSX_SIO_IN_DSR), PSX_SIO_IN_DSR); |
| 85 | } |
| 86 | |
| 87 | device_psx_controller_interface::device_psx_controller_interface(const machine_config &mconfig, device_t &device) : |
| 88 | device_slot_card_interface(mconfig, device), |
| 89 | m_ack(true) |
| 90 | { |
| 91 | } |
| 92 | |
| 93 | device_psx_controller_interface::~device_psx_controller_interface() |
| 94 | { |
| 95 | } |
| 96 | |
| 97 | void device_psx_controller_interface::interface_pre_reset() |
| 98 | { |
| 99 | m_bit = 0; |
| 100 | m_count = 0; |
| 101 | m_idata = 0; |
| 102 | m_memcard = false; |
| 103 | |
| 104 | m_clock = true; |
| 105 | m_sel = true; |
| 106 | m_rx = true; |
| 107 | m_ack = true; |
| 108 | m_owner->ack(); |
| 109 | } |
| 110 | |
| 111 | void device_psx_controller_interface::interface_pre_start() |
| 112 | { |
| 113 | m_owner = dynamic_cast<psx_controller_port_device *>(device().owner()); |
| 114 | m_ack_timer = device().machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(device_psx_controller_interface::ack_timer), this)); |
| 115 | } |
| 116 | |
| 117 | void device_psx_controller_interface::ack_timer(void *ptr, int param) |
| 118 | { |
| 119 | m_ack = param; |
| 120 | m_owner->ack(); |
| 121 | |
| 122 | if(!param) |
| 123 | m_ack_timer->adjust(attotime::from_usec(2), 1); |
| 124 | } |
| 125 | |
| 126 | void device_psx_controller_interface::do_pad() |
| 127 | { |
| 128 | if(!m_bit) |
| 129 | { |
| 130 | if(!m_count) |
| 131 | m_odata = 0xff; |
| 132 | m_idata = 0; |
| 133 | } |
| 134 | |
| 135 | m_rx = (m_odata & (1 << m_bit)) ? true : false; |
| 136 | m_idata |= (m_owner->tx_r()?1:0) << m_bit; |
| 137 | m_bit = (m_bit + 1) % 8; |
| 138 | |
| 139 | if(!m_bit) |
| 140 | { |
| 141 | if((!m_count) && (m_idata & 0xf0)) |
| 142 | { |
| 143 | m_memcard = true; |
| 144 | return; |
| 145 | } |
| 146 | |
| 147 | if(get_pad(m_count++, &m_odata, m_idata)) |
| 148 | m_ack_timer->adjust(attotime::from_usec(10), 0); |
| 149 | else |
| 150 | m_count = 0; |
| 151 | } |
| 152 | } |
| 153 | |
| 154 | void device_psx_controller_interface::sel_w(bool state) { |
| 155 | if(state && !m_sel) |
| 156 | interface_pre_reset(); // don't reset the controller, just the interface |
| 157 | m_sel = state; |
| 158 | } |
| 159 | |
| 160 | const device_type PSX_STANDARD_CONTROLLER = &device_creator<psx_standard_controller_device>; |
| 161 | |
| 162 | psx_standard_controller_device::psx_standard_controller_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : |
| 163 | device_t(mconfig, PSX_STANDARD_CONTROLLER, "Playstation Standard Controller", tag, owner, clock, "psx_standard_controller", __FILE__), |
| 164 | device_psx_controller_interface(mconfig, *this), |
| 165 | m_pad0(*this,"PSXPAD0"), |
| 166 | m_pad1(*this,"PSXPAD1") |
| 167 | { |
| 168 | } |
| 169 | |
| 170 | bool psx_standard_controller_device::get_pad(int count, UINT8 *odata, UINT8 idata) |
| 171 | { |
| 172 | switch(count) |
| 173 | { |
| 174 | case 0: |
| 175 | *odata = 0x41; |
| 176 | break; |
| 177 | case 1: |
| 178 | if(idata != QUERY_PAD_STATE) |
| 179 | return false; |
| 180 | *odata = 0x5a; |
| 181 | break; |
| 182 | case 2: |
| 183 | *odata = m_pad0->read(); |
| 184 | break; |
| 185 | case 3: |
| 186 | *odata = m_pad1->read(); |
| 187 | break; |
| 188 | case 4: |
| 189 | return false; |
| 190 | } |
| 191 | return true; |
| 192 | } |
| 193 | |
| 194 | static INPUT_PORTS_START( psx_standard_controller ) |
| 195 | PORT_START("PSXPAD0") |
| 196 | PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) |
| 197 | PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) |
| 198 | PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) |
| 199 | PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) |
| 200 | PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START ) |
| 201 | PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) |
| 202 | PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) |
| 203 | PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_SELECT ) |
| 204 | |
| 205 | PORT_START("PSXPAD1") |
| 206 | PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("Square") |
| 207 | PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("Cross") |
| 208 | PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("Circle") |
| 209 | PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("Triangle") |
| 210 | PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("R1") |
| 211 | PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("L1") |
| 212 | PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON7 ) PORT_NAME("R2") |
| 213 | PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON8 ) PORT_NAME("L2") |
| 214 | INPUT_PORTS_END |
| 215 | |
| 216 | ioport_constructor psx_standard_controller_device::device_input_ports() const |
| 217 | { |
| 218 | return INPUT_PORTS_NAME(psx_standard_controller); |
| 219 | } |
trunk/src/emu/bus/psx/ctlrport.h
| r0 | r241420 | |
| 1 | #pragma once |
| 2 | |
| 3 | #ifndef __PSXCPORT_H__ |
| 4 | #define __PSXCPORT_H__ |
| 5 | |
| 6 | #include "cpu/psx/siodev.h" |
| 7 | #include "memcard.h" |
| 8 | |
| 9 | #define MCFG_PSX_CTRL_PORT_ADD(_tag, _slot_intf, _def_slot) \ |
| 10 | MCFG_DEVICE_ADD(_tag, PSX_CONTROLLER_PORT, 0) \ |
| 11 | MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) |
| 12 | |
| 13 | SLOT_INTERFACE_EXTERN(psx_controllers); |
| 14 | |
| 15 | extern const device_type PSXCONTROLLERPORTS; |
| 16 | extern const device_type PSX_CONTROLLER_PORT; |
| 17 | extern const device_type PSX_STANDARD_CONTROLLER; |
| 18 | |
| 19 | class psx_controller_port_device; |
| 20 | |
| 21 | class device_psx_controller_interface : public device_slot_card_interface |
| 22 | { |
| 23 | friend class psx_multitap_device; |
| 24 | public: |
| 25 | device_psx_controller_interface(const machine_config &mconfig, device_t &device); |
| 26 | virtual ~device_psx_controller_interface(); |
| 27 | |
| 28 | void clock_w(bool state) { if(m_clock && !m_sel && !state && !m_memcard) do_pad(); m_clock = state; } |
| 29 | void sel_w(bool state); |
| 30 | |
| 31 | bool rx_r() { return m_rx; } |
| 32 | bool ack_r() { return m_ack; } |
| 33 | |
| 34 | protected: |
| 35 | virtual void interface_pre_reset(); |
| 36 | virtual void interface_pre_start(); |
| 37 | |
| 38 | enum |
| 39 | { |
| 40 | QUERY_PAD_STATE = 0x42, |
| 41 | CONFIG_MODE = 0x43, |
| 42 | }; |
| 43 | |
| 44 | private: |
| 45 | virtual bool get_pad(int count, UINT8 *odata, UINT8 idata) = 0; |
| 46 | virtual void do_pad(); |
| 47 | void ack_timer(void *ptr, int param); |
| 48 | |
| 49 | UINT8 m_odata; |
| 50 | UINT8 m_idata; |
| 51 | int m_bit; |
| 52 | int m_count; |
| 53 | bool m_memcard; |
| 54 | |
| 55 | bool m_clock; |
| 56 | bool m_sel; |
| 57 | bool m_ack; |
| 58 | bool m_rx; |
| 59 | |
| 60 | emu_timer *m_ack_timer; |
| 61 | psx_controller_port_device *m_owner; |
| 62 | }; |
| 63 | |
| 64 | class psx_standard_controller_device : public device_t, |
| 65 | public device_psx_controller_interface |
| 66 | { |
| 67 | public: |
| 68 | psx_standard_controller_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 69 | |
| 70 | virtual ioport_constructor device_input_ports() const; |
| 71 | |
| 72 | protected: |
| 73 | virtual void device_start() { } |
| 74 | private: |
| 75 | virtual bool get_pad(int count, UINT8 *odata, UINT8 idata); |
| 76 | |
| 77 | required_ioport m_pad0; |
| 78 | required_ioport m_pad1; |
| 79 | }; |
| 80 | |
| 81 | class psxcontrollerports_device : public psxsiodev_device |
| 82 | { |
| 83 | public: |
| 84 | psxcontrollerports_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 85 | void ack(); |
| 86 | |
| 87 | protected: |
| 88 | virtual void device_start(); |
| 89 | |
| 90 | private: |
| 91 | virtual void data_in(int data, int mask); |
| 92 | |
| 93 | psx_controller_port_device *m_port0; |
| 94 | psx_controller_port_device *m_port1; |
| 95 | }; |
| 96 | |
| 97 | class psx_controller_port_device : public device_t, |
| 98 | public device_slot_interface |
| 99 | { |
| 100 | public: |
| 101 | psx_controller_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 102 | virtual machine_config_constructor device_mconfig_additions() const; |
| 103 | |
| 104 | typedef delegate<void ()> void_cb; |
| 105 | void ack() { if(!ack_cb.isnull()) ack_cb(); } |
| 106 | void setup_ack_cb(void_cb cb) { ack_cb = cb; } |
| 107 | |
| 108 | DECLARE_WRITE_LINE_MEMBER(tx_w) { m_tx = state; } |
| 109 | DECLARE_WRITE_LINE_MEMBER(sel_w) { if(m_dev) m_dev->sel_w(state); m_card->sel_w(state); } |
| 110 | DECLARE_WRITE_LINE_MEMBER(clock_w) { if(m_dev) m_dev->clock_w(state); m_card->clock_w(state); } |
| 111 | |
| 112 | DECLARE_READ_LINE_MEMBER(rx_r) { return (m_dev?m_dev->rx_r():true) && m_card->rx_r(); } |
| 113 | DECLARE_READ_LINE_MEMBER(ack_r) { return (m_dev?m_dev->ack_r():true) && m_card->ack_r(); } |
| 114 | DECLARE_READ_LINE_MEMBER(tx_r) { return m_tx; } |
| 115 | |
| 116 | void disable_card(bool status); |
| 117 | |
| 118 | protected: |
| 119 | virtual void device_start() {} |
| 120 | virtual void device_reset() { m_tx = true; } |
| 121 | virtual void device_config_complete(); |
| 122 | |
| 123 | private: |
| 124 | void_cb ack_cb; |
| 125 | bool m_tx; |
| 126 | |
| 127 | device_psx_controller_interface *m_dev; |
| 128 | required_device<psxcard_device> m_card; |
| 129 | }; |
| 130 | #endif |
trunk/src/emu/bus/psx/memcard.c
| r0 | r241420 | |
| 1 | /* |
| 2 | psxcard.c - Sony PlayStation memory card device |
| 3 | |
| 4 | by pSXAuthor |
| 5 | MESS conversion by R. Belmont |
| 6 | */ |
| 7 | |
| 8 | #include "emu.h" |
| 9 | #include "memcard.h" |
| 10 | #include "ctlrport.h" |
| 11 | |
| 12 | // |
| 13 | // |
| 14 | // |
| 15 | |
| 16 | //#define debug_card |
| 17 | |
| 18 | // |
| 19 | // |
| 20 | // |
| 21 | |
| 22 | static const int block_size = 128; |
| 23 | static const int card_size = block_size * 1024; |
| 24 | |
| 25 | const device_type PSXCARD = &device_creator<psxcard_device>; |
| 26 | |
| 27 | enum transfer_states |
| 28 | { |
| 29 | state_illegal=0, |
| 30 | state_command, |
| 31 | state_cmdack, |
| 32 | state_wait, |
| 33 | state_addr_hi, |
| 34 | state_addr_lo, |
| 35 | state_read, |
| 36 | state_write, |
| 37 | state_writeack_2, |
| 38 | state_writechk, |
| 39 | state_end |
| 40 | }; |
| 41 | |
| 42 | psxcard_device::psxcard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 43 | : device_t(mconfig, PSXCARD, "Sony PSX Memory Card", tag, owner, clock, "psxcard", __FILE__), |
| 44 | device_image_interface(mconfig, *this) |
| 45 | { |
| 46 | } |
| 47 | |
| 48 | void psxcard_device::device_start() |
| 49 | { |
| 50 | m_owner = dynamic_cast<psx_controller_port_device *>(owner()); |
| 51 | m_ack_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(psxcard_device::ack_timer), this)); |
| 52 | |
| 53 | m_ack = true; |
| 54 | m_disabled = false; |
| 55 | |
| 56 | // save state registrations |
| 57 | save_item(NAME(pkt)); |
| 58 | save_item(NAME(pkt_ptr)); |
| 59 | save_item(NAME(pkt_sz)); |
| 60 | save_item(NAME(cmd)); |
| 61 | save_item(NAME(addr)); |
| 62 | save_item(NAME(state)); |
| 63 | save_item(NAME(m_disabled)); |
| 64 | save_item(NAME(m_odata)); |
| 65 | save_item(NAME(m_idata)); |
| 66 | save_item(NAME(m_bit)); |
| 67 | save_item(NAME(m_count)); |
| 68 | save_item(NAME(m_pad)); |
| 69 | } |
| 70 | |
| 71 | void psxcard_device::device_reset() |
| 72 | { |
| 73 | state = state_illegal; |
| 74 | addr = 0; |
| 75 | |
| 76 | m_bit = 0; |
| 77 | m_count = 0; |
| 78 | m_pad = false; |
| 79 | m_idata = 0; |
| 80 | |
| 81 | m_clock = true; |
| 82 | m_sel = true; |
| 83 | m_rx = true; |
| 84 | m_ack = true; |
| 85 | m_owner->ack(); |
| 86 | } |
| 87 | |
| 88 | void psxcard_device::device_config_complete() |
| 89 | { |
| 90 | update_names(PSXCARD, "memcard", "mc"); |
| 91 | } |
| 92 | |
| 93 | // |
| 94 | // |
| 95 | // |
| 96 | |
| 97 | bool psxcard_device::transfer(UINT8 to, UINT8 *from) |
| 98 | { |
| 99 | bool ret=true; |
| 100 | |
| 101 | switch (state) |
| 102 | { |
| 103 | case state_illegal: |
| 104 | if (is_loaded()) |
| 105 | { |
| 106 | // printf("CARD: begin\n"); |
| 107 | state = state_command; |
| 108 | *from = 0x00; |
| 109 | } |
| 110 | else |
| 111 | { |
| 112 | ret = false; |
| 113 | } |
| 114 | break; |
| 115 | |
| 116 | case state_command: |
| 117 | cmd=to; |
| 118 | *from=0x5a; |
| 119 | state=state_cmdack; |
| 120 | break; |
| 121 | |
| 122 | case state_cmdack: |
| 123 | *from=0x5d; |
| 124 | state=state_wait; |
| 125 | break; |
| 126 | |
| 127 | case state_wait: |
| 128 | *from=0x00; |
| 129 | state=state_addr_hi; |
| 130 | break; |
| 131 | |
| 132 | case state_addr_hi: |
| 133 | addr=(to<<8); |
| 134 | // printf("addr_hi: %02x, addr = %x\n", to, addr); |
| 135 | *from=to; |
| 136 | state=state_addr_lo; |
| 137 | break; |
| 138 | |
| 139 | case state_addr_lo: |
| 140 | addr|=(to&0xff); |
| 141 | // printf("addr_lo: %02x, addr = %x, cmd = %x\n", to, addr, cmd); |
| 142 | |
| 143 | switch (cmd) |
| 144 | { |
| 145 | case 'R': // 0x52 |
| 146 | { |
| 147 | pkt[0]=*from=0x5c; |
| 148 | pkt[1]=0x5d; |
| 149 | pkt[2]=(addr>>8); |
| 150 | pkt[3]=(addr&0xff); |
| 151 | read_card(addr,&pkt[4]); |
| 152 | pkt[4+128]=checksum_data(&pkt[2],128+2); |
| 153 | pkt[5+128]=0x47; |
| 154 | pkt_sz=6+128; |
| 155 | pkt_ptr=1; |
| 156 | state=state_read; |
| 157 | break; |
| 158 | } |
| 159 | case 'W': // 0x57 |
| 160 | { |
| 161 | pkt[0]=addr>>8; |
| 162 | pkt[1]=addr&0xff; |
| 163 | pkt_sz=129+2; |
| 164 | pkt_ptr=2; |
| 165 | state=state_write; |
| 166 | *from=to; |
| 167 | break; |
| 168 | } |
| 169 | default: |
| 170 | state=state_illegal; |
| 171 | break; |
| 172 | } |
| 173 | break; |
| 174 | |
| 175 | case state_read: |
| 176 | //assert(to==0); |
| 177 | // printf("state_read: pkt_ptr = %d, pkt_sz = %d\n", pkt_ptr, pkt_sz); |
| 178 | *from=pkt[pkt_ptr++]; |
| 179 | if (pkt_ptr==pkt_sz) |
| 180 | { |
| 181 | #ifdef debug_card |
| 182 | printf("card: read finished\n"); |
| 183 | #endif |
| 184 | |
| 185 | state=state_end; |
| 186 | } |
| 187 | break; |
| 188 | |
| 189 | case state_write: |
| 190 | *from=to; |
| 191 | pkt[pkt_ptr++]=to; |
| 192 | if (pkt_ptr==pkt_sz) |
| 193 | { |
| 194 | *from=0x5c; |
| 195 | state=state_writeack_2; |
| 196 | } |
| 197 | break; |
| 198 | |
| 199 | case state_writeack_2: |
| 200 | *from=0x5d; |
| 201 | state=state_writechk; |
| 202 | break; |
| 203 | |
| 204 | case state_writechk: |
| 205 | { |
| 206 | unsigned char chk=checksum_data(pkt,128+2); |
| 207 | if (chk==pkt[128+2]) |
| 208 | { |
| 209 | #ifdef debug_card |
| 210 | printf("card: write ok\n"); |
| 211 | #endif |
| 212 | |
| 213 | write_card(addr,pkt+2); |
| 214 | |
| 215 | *from='G'; |
| 216 | } else |
| 217 | { |
| 218 | #ifdef debug_card |
| 219 | printf("card: write fail\n"); |
| 220 | #endif |
| 221 | |
| 222 | *from='N'; |
| 223 | } |
| 224 | state=state_end; |
| 225 | break; |
| 226 | } |
| 227 | |
| 228 | case state_end: |
| 229 | ret = false; |
| 230 | state = state_illegal; |
| 231 | break; |
| 232 | |
| 233 | default: /*assert(0);*/ ret=false; break; |
| 234 | } |
| 235 | |
| 236 | #ifdef debug_card |
| 237 | // printf("card: transfer to=%02x from=%02x ret=%c\n",to,*from,ret ? 'T' : 'F'); |
| 238 | #endif |
| 239 | |
| 240 | return ret; |
| 241 | } |
| 242 | |
| 243 | void psxcard_device::read_card(const unsigned short addr, unsigned char *buf) |
| 244 | { |
| 245 | #ifdef debug_card |
| 246 | printf("card: read block %d\n",addr); |
| 247 | #endif |
| 248 | |
| 249 | if (addr<(card_size/block_size)) |
| 250 | { |
| 251 | fseek(addr*block_size, SEEK_SET); |
| 252 | fread(buf, block_size); |
| 253 | } else |
| 254 | { |
| 255 | memset(buf,0,block_size); |
| 256 | } |
| 257 | } |
| 258 | |
| 259 | // |
| 260 | // |
| 261 | // |
| 262 | |
| 263 | void psxcard_device::write_card(const unsigned short addr, unsigned char *buf) |
| 264 | { |
| 265 | #ifdef debug_card |
| 266 | printf("card: write block %d\n",addr); |
| 267 | #endif |
| 268 | |
| 269 | if (addr<(card_size/block_size)) |
| 270 | { |
| 271 | fseek(addr*block_size, SEEK_SET); |
| 272 | fwrite(buf, block_size); |
| 273 | } |
| 274 | } |
| 275 | |
| 276 | unsigned char psxcard_device::checksum_data(const unsigned char *buf, const unsigned int sz) |
| 277 | { |
| 278 | unsigned char chk=*buf++; |
| 279 | int left=sz; |
| 280 | while (--left) chk^=*buf++; |
| 281 | return chk; |
| 282 | } |
| 283 | |
| 284 | bool psxcard_device::call_load() |
| 285 | { |
| 286 | if(m_disabled) |
| 287 | { |
| 288 | logerror("psxcard: port disabled\n"); |
| 289 | return IMAGE_INIT_FAIL; |
| 290 | } |
| 291 | |
| 292 | if(length() != card_size) |
| 293 | return IMAGE_INIT_FAIL; |
| 294 | return IMAGE_INIT_PASS; |
| 295 | } |
| 296 | |
| 297 | bool psxcard_device::call_create(int format_type, option_resolution *format_options) |
| 298 | { |
| 299 | UINT8 block[block_size]; |
| 300 | int i, ret; |
| 301 | |
| 302 | if(m_disabled) |
| 303 | { |
| 304 | logerror("psxcard: port disabled\n"); |
| 305 | return IMAGE_INIT_FAIL; |
| 306 | } |
| 307 | |
| 308 | memset(block, '\0', block_size); |
| 309 | for(i = 0; i < (card_size/block_size); i++) |
| 310 | { |
| 311 | ret = fwrite(block, block_size); |
| 312 | if(ret != block_size) |
| 313 | return IMAGE_INIT_FAIL; |
| 314 | } |
| 315 | return IMAGE_INIT_PASS; |
| 316 | } |
| 317 | |
| 318 | void psxcard_device::do_card() |
| 319 | { |
| 320 | if(!m_bit) |
| 321 | { |
| 322 | m_idata = 0; |
| 323 | if(!m_count) |
| 324 | m_odata = 0xff; |
| 325 | } |
| 326 | |
| 327 | m_rx = (m_odata & (1 << m_bit)) ? true : false; |
| 328 | m_idata |= (m_owner->tx_r()?1:0) << m_bit; |
| 329 | m_bit = (m_bit + 1) % 8; |
| 330 | |
| 331 | if(!m_bit) |
| 332 | { |
| 333 | if((!m_count) && !(m_idata & 0x80)) |
| 334 | { |
| 335 | m_pad = true; |
| 336 | return; |
| 337 | } |
| 338 | |
| 339 | if(transfer(m_idata, &m_odata)) |
| 340 | { |
| 341 | m_count++; |
| 342 | m_ack_timer->adjust(attotime::from_usec(10), 0); |
| 343 | } |
| 344 | else |
| 345 | m_count = 0; |
| 346 | } |
| 347 | } |
| 348 | |
| 349 | void psxcard_device::ack_timer(void *ptr, int param) |
| 350 | { |
| 351 | m_ack = param; |
| 352 | m_owner->ack(); |
| 353 | |
| 354 | if(!param) |
| 355 | m_ack_timer->adjust(attotime::from_usec(2), 1); |
| 356 | } |
| 357 | |
| 358 | void psxcard_device::sel_w(bool state) |
| 359 | { |
| 360 | if(state && !m_sel) |
| 361 | reset(); |
| 362 | m_sel = state; |
| 363 | } |
trunk/src/emu/bus/psx/memcard.h
| r0 | r241420 | |
| 1 | #pragma once |
| 2 | |
| 3 | #ifndef _PSXCARD_ |
| 4 | #define _PSXCARD_ |
| 5 | |
| 6 | #include "emu.h" |
| 7 | |
| 8 | class psx_controller_port_device; |
| 9 | |
| 10 | #define MCFG_PSXCARD_ADD(_tag) \ |
| 11 | MCFG_DEVICE_ADD(_tag, PSXCARD, 0) |
| 12 | |
| 13 | class psxcard_device : public device_t, |
| 14 | public device_image_interface |
| 15 | { |
| 16 | public: |
| 17 | psxcard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 18 | |
| 19 | virtual iodevice_t image_type() const { return IO_MEMCARD; } |
| 20 | |
| 21 | virtual bool is_readable() const { return 1; } |
| 22 | virtual bool is_writeable() const { return 1; } |
| 23 | virtual bool is_creatable() const { return 1; } |
| 24 | virtual bool must_be_loaded() const { return 0; } |
| 25 | virtual bool is_reset_on_load() const { return 0; } |
| 26 | virtual const char *file_extensions() const { return "mc"; } |
| 27 | virtual const option_guide *create_option_guide() const { return NULL; } |
| 28 | |
| 29 | virtual bool call_load(); |
| 30 | virtual bool call_create(int format_type, option_resolution *format_options); |
| 31 | |
| 32 | void disable(bool state) { m_disabled = state; if(state) unload(); } |
| 33 | |
| 34 | private: |
| 35 | unsigned char pkt[0x8b], pkt_ptr, pkt_sz, cmd; |
| 36 | unsigned short addr; |
| 37 | int state; |
| 38 | bool m_disabled; |
| 39 | |
| 40 | UINT8 m_odata; |
| 41 | UINT8 m_idata; |
| 42 | int m_bit; |
| 43 | int m_count; |
| 44 | bool m_pad; |
| 45 | |
| 46 | bool m_clock; |
| 47 | bool m_sel; |
| 48 | bool m_ack; |
| 49 | bool m_rx; |
| 50 | |
| 51 | emu_timer *m_ack_timer; |
| 52 | psx_controller_port_device *m_owner; |
| 53 | |
| 54 | void read_card(const unsigned short addr, unsigned char *buf); |
| 55 | void write_card(const unsigned short addr, unsigned char *buf); |
| 56 | unsigned char checksum_data(const unsigned char *buf, const unsigned int sz); |
| 57 | void do_card(); |
| 58 | bool transfer(UINT8 to, UINT8 *from); |
| 59 | void ack_timer(void *ptr, int param); |
| 60 | |
| 61 | public: |
| 62 | virtual void device_start(); |
| 63 | virtual void device_reset(); |
| 64 | virtual void device_config_complete(); |
| 65 | |
| 66 | void clock_w(bool state) { if(m_clock && !m_sel && !state && !m_pad) do_card(); m_clock = state; } |
| 67 | void sel_w(bool state); |
| 68 | bool rx_r() { return m_rx; } |
| 69 | bool ack_r() { return m_ack; } |
| 70 | }; |
| 71 | |
| 72 | // device type definition |
| 73 | extern const device_type PSXCARD; |
| 74 | |
| 75 | #endif |
trunk/src/emu/bus/psx/multitap.c
| r0 | r241420 | |
| 1 | // psx multitap emulation |
| 2 | |
| 3 | #include "multitap.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, "psx_multitap", __FILE__), |
| 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") |
| 19 | MCFG_PSX_CTRL_PORT_ADD("b", psx_controllers_nomulti, NULL) |
| 20 | MCFG_PSX_CTRL_PORT_ADD("c", psx_controllers_nomulti, NULL) |
| 21 | MCFG_PSX_CTRL_PORT_ADD("d", psx_controllers_nomulti, 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 | save_item(NAME(m_activeport)); |
| 38 | save_item(NAME(m_cack)); |
| 39 | save_item(NAME(m_singlemode)); |
| 40 | save_item(NAME(m_nextmode)); |
| 41 | save_item(NAME(m_tapmc)); |
| 42 | save_item(NAME(m_data)); |
| 43 | } |
| 44 | |
| 45 | void psx_multitap_device::interface_pre_reset() |
| 46 | { |
| 47 | m_activeport = -1; |
| 48 | m_singlemode = m_nextmode; |
| 49 | m_tapmc = false; |
| 50 | m_cack[0] = m_cack[1] = m_cack[2] = m_cack[3] = true; |
| 51 | memset(m_data, 0xff, sizeof(m_data)); |
| 52 | m_porta->sel_w(false); |
| 53 | m_portb->sel_w(false); |
| 54 | m_portc->sel_w(false); |
| 55 | m_portd->sel_w(false); |
| 56 | m_porta->sel_w(true); |
| 57 | m_portb->sel_w(true); |
| 58 | m_portc->sel_w(true); |
| 59 | m_portd->sel_w(true); |
| 60 | device_psx_controller_interface::interface_pre_reset(); |
| 61 | } |
| 62 | |
| 63 | void psx_multitap_device::set_tx_line(bool tx, int port) |
| 64 | { |
| 65 | psx_controller_port_device *dev; |
| 66 | switch(port) |
| 67 | { |
| 68 | default: |
| 69 | case 0: |
| 70 | dev = m_porta; |
| 71 | break; |
| 72 | case 1: |
| 73 | dev = m_portb; |
| 74 | break; |
| 75 | case 2: |
| 76 | dev = m_portc; |
| 77 | break; |
| 78 | case 3: |
| 79 | dev = m_portd; |
| 80 | break; |
| 81 | } |
| 82 | dev->clock_w(1); |
| 83 | dev->tx_w(tx); |
| 84 | dev->clock_w(0); |
| 85 | } |
| 86 | |
| 87 | bool psx_multitap_device::get_rx_line(int port) |
| 88 | { |
| 89 | psx_controller_port_device *dev; |
| 90 | switch(port) |
| 91 | { |
| 92 | default: |
| 93 | case 0: |
| 94 | dev = m_porta; |
| 95 | break; |
| 96 | case 1: |
| 97 | dev = m_portb; |
| 98 | break; |
| 99 | case 2: |
| 100 | dev = m_portc; |
| 101 | break; |
| 102 | case 3: |
| 103 | dev = m_portd; |
| 104 | break; |
| 105 | } |
| 106 | return dev->rx_r(); |
| 107 | } |
| 108 | |
| 109 | void psx_multitap_device::do_pad() |
| 110 | { |
| 111 | bool tx = device_psx_controller_interface::m_owner->tx_r(); |
| 112 | |
| 113 | // we don't know which controller until after the first byte |
| 114 | if((m_singlemode || m_tapmc) && (m_count >= 1)) |
| 115 | { |
| 116 | if((m_count == 2) && !m_bit && !m_tapmc) |
| 117 | m_nextmode = !tx; |
| 118 | |
| 119 | set_tx_line(tx, m_activeport); |
| 120 | m_rx = get_rx_line(m_activeport); |
| 121 | m_bit = (m_bit + 1) % 8; |
| 122 | if(!m_bit) |
| 123 | m_count++; |
| 124 | return; |
| 125 | } |
| 126 | |
| 127 | if(!m_count) |
| 128 | { |
| 129 | // first send the select byte to all devices until we know whether it's accessing |
| 130 | // a controller or memcard |
| 131 | if(!m_bit) |
| 132 | { |
| 133 | m_porta->sel_w(false); |
| 134 | m_portb->sel_w(false); |
| 135 | m_portc->sel_w(false); |
| 136 | m_portd->sel_w(false); |
| 137 | } |
| 138 | device_psx_controller_interface::do_pad(); |
| 139 | set_tx_line(tx, 0); |
| 140 | set_tx_line(tx, 1); |
| 141 | set_tx_line(tx, 2); |
| 142 | set_tx_line(tx, 3); |
| 143 | if(!m_bit) |
| 144 | { |
| 145 | m_count = 1; |
| 146 | m_tapmc = m_memcard; |
| 147 | m_memcard = false; // make sure we still receive clocks |
| 148 | if(m_singlemode || m_tapmc) |
| 149 | { |
| 150 | m_activeport = (m_idata & 0xf) - 1; |
| 151 | m_porta->sel_w((m_activeport == 0) ? false : true); |
| 152 | m_portb->sel_w((m_activeport == 1) ? false : true); |
| 153 | m_portc->sel_w((m_activeport == 2) ? false : true); |
| 154 | m_portd->sel_w((m_activeport == 3) ? false : true); |
| 155 | } |
| 156 | } |
| 157 | return; |
| 158 | } |
| 159 | else if(m_count <= 2) |
| 160 | return device_psx_controller_interface::do_pad(); |
| 161 | else if(m_count < 11) |
| 162 | { |
| 163 | if((m_count == 3) && !m_bit) |
| 164 | m_nextmode = !m_idata; |
| 165 | |
| 166 | if((m_count < 5) && m_cack[0] && m_cack[1] && m_cack[2] && m_cack[3]) |
| 167 | return; // no acks? hang up. |
| 168 | |
| 169 | // all of the ports are polled here, port a is passed though. the data |
| 170 | // from the other ports is stored and can be retrieved at a much higher clock rate |
| 171 | // don't poll a port that is inactive or done |
| 172 | if(!m_cack[0]) |
| 173 | { |
| 174 | set_tx_line(tx, 0); |
| 175 | m_rx = m_porta->rx_r(); |
| 176 | } |
| 177 | else |
| 178 | { |
| 179 | m_rx = true; |
| 180 | m_porta->sel_w(true); |
| 181 | } |
| 182 | |
| 183 | if(!m_cack[1]) |
| 184 | { |
| 185 | set_tx_line(tx, 1); |
| 186 | m_data[0][m_count - 3] &= ~(!m_portb->rx_r() << m_bit); |
| 187 | } |
| 188 | else |
| 189 | m_portb->sel_w(true); |
| 190 | |
| 191 | if(!m_cack[2]) |
| 192 | { |
| 193 | set_tx_line(tx, 2); |
| 194 | m_data[1][m_count - 3] &= ~(!m_portc->rx_r() << m_bit); |
| 195 | } |
| 196 | else |
| 197 | m_portc->sel_w(true); |
| 198 | |
| 199 | if(!m_cack[3]) |
| 200 | { |
| 201 | set_tx_line(tx, 3); |
| 202 | m_data[2][m_count - 3] &= ~(!m_portd->rx_r() << m_bit); |
| 203 | } |
| 204 | else |
| 205 | m_portd->sel_w(true); |
| 206 | } |
| 207 | else if(m_count < 19) |
| 208 | // send stored port b data |
| 209 | m_rx = ((m_data[0][m_count - 11] & (1 << m_bit)) ? 1 : 0); |
| 210 | else if(m_count < 27) |
| 211 | // send stored port c data |
| 212 | m_rx = ((m_data[1][m_count - 19] & (1 << m_bit)) ? 1 : 0); |
| 213 | else |
| 214 | // send stored port d data |
| 215 | m_rx = ((m_data[2][m_count - 27] & (1 << m_bit)) ? 1 : 0); |
| 216 | |
| 217 | if(m_bit == 7) |
| 218 | { |
| 219 | // ports won't ack if they are done |
| 220 | m_cack[0] = m_cack[1] = m_cack[2] = m_cack[3] = true; |
| 221 | if(m_count < 11) |
| 222 | m_ack_timer->adjust(attotime::from_usec(12), 0); // give a bit of time for the ports to ack |
| 223 | else if(m_count < 35) |
| 224 | m_ack_timer->adjust(attotime::from_usec(10), 0); |
| 225 | } |
| 226 | |
| 227 | m_bit = (m_bit + 1) % 8; |
| 228 | if(!m_bit) |
| 229 | m_count++; |
| 230 | } |
| 231 | |
| 232 | bool psx_multitap_device::get_pad(int count, UINT8 *odata, UINT8 idata) |
| 233 | { |
| 234 | if(!count) |
| 235 | *odata = 0x80; |
| 236 | else |
| 237 | *odata = 0x5a; |
| 238 | return true; |
| 239 | } |
| 240 | |
| 241 | void psx_multitap_device::ack() |
| 242 | { |
| 243 | if(m_activeport != -1) |
| 244 | { |
| 245 | switch(m_activeport) |
| 246 | { |
| 247 | case 0: |
| 248 | m_ack = m_porta->ack_r(); |
| 249 | break; |
| 250 | case 1: |
| 251 | m_ack = m_portb->ack_r(); |
| 252 | break; |
| 253 | case 2: |
| 254 | m_ack = m_portc->ack_r(); |
| 255 | break; |
| 256 | case 3: |
| 257 | m_ack = m_portd->ack_r(); |
| 258 | break; |
| 259 | default: |
| 260 | return; |
| 261 | } |
| 262 | device_psx_controller_interface::m_owner->ack(); |
| 263 | return; |
| 264 | } |
| 265 | if(!m_porta->ack_r()) |
| 266 | m_cack[0] = false; |
| 267 | if(!m_portb->ack_r()) |
| 268 | m_cack[1] = false; |
| 269 | if(!m_portc->ack_r()) |
| 270 | m_cack[2] = false; |
| 271 | if(!m_portd->ack_r()) |
| 272 | m_cack[3] = false; |
| 273 | } |
trunk/src/emu/bus/psx/multitap.h
| r0 | r241420 | |
| 1 | #ifndef PSXMULTITAP_H_ |
| 2 | #define PSXMULTITAP_H_ |
| 3 | |
| 4 | #include "ctlrport.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_ */ |
trunk/src/mame/drivers/taitogn.c
| r241419 | r241420 | |
| 336 | 336 | #include "machine/intelfsh.h" |
| 337 | 337 | #include "machine/mb3773.h" |
| 338 | 338 | #include "machine/rf5c296.h" |
| 339 | | #include "machine/znsec.h" |
| 339 | #include "machine/cat702.h" |
| 340 | 340 | #include "machine/zndip.h" |
| 341 | 341 | #include "sound/spu.h" |
| 342 | 342 | #include "video/psx.h" |
| r241419 | r241420 | |
| 346 | 346 | public: |
| 347 | 347 | taitogn_state(const machine_config &mconfig, device_type type, const char *tag) : |
| 348 | 348 | driver_device(mconfig, type, tag), |
| 349 | | m_znsec0(*this,"maincpu:sio0:znsec0"), |
| 350 | | m_znsec1(*this,"maincpu:sio0:znsec1"), |
| 349 | m_cat702_1(*this,"maincpu:sio0:cat702_1"), |
| 350 | m_cat702_2(*this,"maincpu:sio0:cat702_2"), |
| 351 | 351 | m_zndip(*this,"maincpu:sio0:zndip"), |
| 352 | 352 | m_maincpu(*this, "maincpu"), |
| 353 | 353 | m_mn10200(*this, "mn10200"), |
| r241419 | r241420 | |
| 384 | 384 | virtual void machine_reset(); |
| 385 | 385 | |
| 386 | 386 | private: |
| 387 | | required_device<znsec_device> m_znsec0; |
| 388 | | required_device<znsec_device> m_znsec1; |
| 387 | required_device<cat702_device> m_cat702_1; |
| 388 | required_device<cat702_device> m_cat702_2; |
| 389 | 389 | required_device<zndip_device> m_zndip; |
| 390 | 390 | required_device<cpu_device> m_maincpu; |
| 391 | 391 | required_device<cpu_device> m_mn10200; |
| r241419 | r241420 | |
| 511 | 511 | |
| 512 | 512 | WRITE8_MEMBER(taitogn_state::znsecsel_w) |
| 513 | 513 | { |
| 514 | | m_znsec0->select( ( data >> 2 ) & 1 ); |
| 515 | | m_znsec1->select( ( data >> 3 ) & 1 ); |
| 514 | m_cat702_1->select( ( data >> 2 ) & 1 ); |
| 515 | m_cat702_2->select( ( data >> 3 ) & 1 ); |
| 516 | 516 | m_zndip->select( ( data & 0x8c ) != 0x8c ); |
| 517 | 517 | |
| 518 | 518 | m_n_znsecsel = data; |
| r241419 | r241420 | |
| 579 | 579 | |
| 580 | 580 | void taitogn_state::driver_start() |
| 581 | 581 | { |
| 582 | | m_znsec0->init(tt10); |
| 583 | | m_znsec1->init(tt16); |
| 582 | m_cat702_1->init(tt10); |
| 583 | m_cat702_2->init(tt16); |
| 584 | 584 | } |
| 585 | 585 | |
| 586 | 586 | void taitogn_state::machine_reset() |
| r241419 | r241420 | |
| 657 | 657 | MCFG_RAM_MODIFY("maincpu:ram") |
| 658 | 658 | MCFG_RAM_DEFAULT_SIZE("4M") |
| 659 | 659 | |
| 660 | | MCFG_DEVICE_ADD("maincpu:sio0:znsec0", ZNSEC, 0) |
| 661 | | MCFG_DEVICE_ADD("maincpu:sio0:znsec1", ZNSEC, 0) |
| 660 | MCFG_DEVICE_ADD("maincpu:sio0:cat702_1", CAT702, 0) |
| 661 | MCFG_DEVICE_ADD("maincpu:sio0:cat702_2", CAT702, 0) |
| 662 | 662 | MCFG_DEVICE_ADD("maincpu:sio0:zndip", ZNDIP, 0) |
| 663 | 663 | MCFG_ZNDIP_DATA_HANDLER(IOPORT(":DSW")) |
| 664 | 664 | |
trunk/src/mame/drivers/zn.c
| r241419 | r241420 | |
| 17 | 17 | #include "machine/nvram.h" |
| 18 | 18 | #include "machine/mb3773.h" |
| 19 | 19 | #include "machine/7200fifo.h" |
| 20 | | #include "machine/znsec.h" |
| 20 | #include "machine/cat702.h" |
| 21 | 21 | #include "machine/zndip.h" |
| 22 | 22 | #include "machine/ataintf.h" |
| 23 | 23 | #include "machine/vt83c461.h" |
| r241419 | r241420 | |
| 38 | 38 | driver_device(mconfig, type, tag), |
| 39 | 39 | m_gpu(*this, "gpu"), |
| 40 | 40 | m_gpu_screen(*this, "gpu:screen"), |
| 41 | | m_znsec0(*this,"maincpu:sio0:znsec0"), |
| 42 | | m_znsec1(*this,"maincpu:sio0:znsec1"), |
| 41 | m_cat702_1(*this,"maincpu:sio0:cat702_1"), |
| 42 | m_cat702_2(*this,"maincpu:sio0:cat702_2"), |
| 43 | 43 | m_zndip(*this,"maincpu:sio0:zndip"), |
| 44 | 44 | m_maincpu(*this, "maincpu"), |
| 45 | 45 | m_audiocpu(*this, "audiocpu"), |
| r241419 | r241420 | |
| 124 | 124 | |
| 125 | 125 | required_device<psxgpu_device> m_gpu; |
| 126 | 126 | required_device<screen_device> m_gpu_screen; |
| 127 | | required_device<znsec_device> m_znsec0; |
| 128 | | required_device<znsec_device> m_znsec1; |
| 127 | required_device<cat702_device> m_cat702_1; |
| 128 | required_device<cat702_device> m_cat702_2; |
| 129 | 129 | required_device<zndip_device> m_zndip; |
| 130 | 130 | required_device<cpu_device> m_maincpu; |
| 131 | 131 | optional_device<cpu_device> m_audiocpu; |
| r241419 | r241420 | |
| 333 | 333 | { |
| 334 | 334 | verboselog(2, "znsecsel_w( %08x, %08x, %08x )\n", offset, data, mem_mask ); |
| 335 | 335 | |
| 336 | | m_znsec0->select( ( data >> 2 ) & 1 ); |
| 337 | | m_znsec1->select( ( data >> 3 ) & 1 ); |
| 336 | m_cat702_1->select( ( data >> 2 ) & 1 ); |
| 337 | m_cat702_2->select( ( data >> 3 ) & 1 ); |
| 338 | 338 | m_zndip->select( ( data & 0x8c ) != 0x8c ); |
| 339 | 339 | |
| 340 | 340 | m_n_znsecsel = data; |
| r241419 | r241420 | |
| 432 | 432 | { |
| 433 | 433 | if( strcmp( machine().system().name, zn_config_table[ n_game ].s_name ) == 0 ) |
| 434 | 434 | { |
| 435 | | m_znsec0->init( zn_config_table[ n_game ].p_n_mainsec ); |
| 436 | | m_znsec1->init( zn_config_table[ n_game ].p_n_gamesec ); |
| 435 | m_cat702_1->init( zn_config_table[ n_game ].p_n_mainsec ); |
| 436 | m_cat702_2->init( zn_config_table[ n_game ].p_n_gamesec ); |
| 437 | 437 | break; |
| 438 | 438 | } |
| 439 | 439 | n_game++; |
| r241419 | r241420 | |
| 449 | 449 | MCFG_RAM_MODIFY("maincpu:ram") |
| 450 | 450 | MCFG_RAM_DEFAULT_SIZE("4M") |
| 451 | 451 | |
| 452 | | MCFG_DEVICE_ADD("maincpu:sio0:znsec0", ZNSEC, 0) |
| 453 | | MCFG_DEVICE_ADD("maincpu:sio0:znsec1", ZNSEC, 0) |
| 452 | MCFG_DEVICE_ADD("maincpu:sio0:cat702_1", CAT702, 0) |
| 453 | MCFG_DEVICE_ADD("maincpu:sio0:cat702_2", CAT702, 0) |
| 454 | 454 | MCFG_DEVICE_ADD("maincpu:sio0:zndip", ZNDIP, 0) |
| 455 | 455 | MCFG_ZNDIP_DATA_HANDLER(IOPORT(":DSW")) |
| 456 | 456 | |
| r241419 | r241420 | |
| 483 | 483 | MCFG_RAM_MODIFY("maincpu:ram") |
| 484 | 484 | MCFG_RAM_DEFAULT_SIZE("4M") |
| 485 | 485 | |
| 486 | | MCFG_DEVICE_ADD("maincpu:sio0:znsec0", ZNSEC, 0) |
| 487 | | MCFG_DEVICE_ADD("maincpu:sio0:znsec1", ZNSEC, 0) |
| 486 | MCFG_DEVICE_ADD("maincpu:sio0:cat702_1", CAT702, 0) |
| 487 | MCFG_DEVICE_ADD("maincpu:sio0:cat702_2", CAT702, 0) |
| 488 | 488 | MCFG_DEVICE_ADD("maincpu:sio0:zndip", ZNDIP, 0) |
| 489 | 489 | MCFG_ZNDIP_DATA_HANDLER(IOPORT(":DSW")) |
| 490 | 490 | |
trunk/src/mame/machine/cat702.c
| r0 | r241420 | |
| 1 | /* |
| 2 | |
| 3 | CAT702 ZN security chip |
| 4 | |
| 5 | A serial magic latch. |
| 6 | |
| 7 | It's a DIP20 chip with a sticker of the form XXnn, where XX is the |
| 8 | company and nn a number: |
| 9 | AC = Acclaim |
| 10 | AT = Atlus |
| 11 | CP = Capcom |
| 12 | ET = Raizing |
| 13 | KN = Konami |
| 14 | MG = Tecmo |
| 15 | TT = Taito |
| 16 | TW = Atari |
| 17 | |
| 18 | There usually are 2 of them, one on the cpu board and one on the rom |
| 19 | board. The cpu board one is usually numbered 01. |
| 20 | |
| 21 | Pinout: GND -11 10- GND |
| 22 | ? -12 9- +5V |
| 23 | +5V -13 8- Data in |
| 24 | Data out- 14 7- Clock |
| 25 | +5V -15 6- Select |
| 26 | ? -16 5- Select |
| 27 | +5V -17 4- +5V |
| 28 | +5V -18 3- +5V |
| 29 | +5V -19 2- +5V |
| 30 | +5V -20 1- ? |
| 31 | |
| 32 | The chip works with the '?' lines left unconnected. |
| 33 | |
| 34 | The communication protocol is serial, and in practice the standard |
| 35 | psx controller communication protocol minus the ack. Drive both |
| 36 | select to ground to start a communication, send bits and get the |
| 37 | results on the raising clock. Put both select back to +5V when |
| 38 | finished. The bios seems to use two communication clock speeds, |
| 39 | ~300KHz (standard psx) and ~2MHz. Driving it with lower clocks |
| 40 | works reasonably, at least at 1KHz. |
| 41 | |
| 42 | The data is divided in bytes but there is no signal for end-of-byte. |
| 43 | In all of the following the data will be considered coming and going |
| 44 | lower-bit first. |
| 45 | |
| 46 | Internally the chip has a 8-bit state, initialized at communication |
| 47 | start to 0xfc. The structure is simple: |
| 48 | |
| 49 | |
| 50 | +---------+ bit number +--------+ |
| 51 | Clock ------->| bit |-----+-------------------->| bit |---------> Data out |
| 52 | | counter | | | select | |
| 53 | +---------+ v +-------+ out | | |
| 54 | | +-----+ | 8bit |=====>| | |
| 55 | Data in ------------|------->| TF1 |<=>| state | +--------+ |
| 56 | | +-----+ | | |
| 57 | | | | |
| 58 | | start +-----+ | | |
| 59 | +------->| TF2 |<=>| | |
| 60 | +-----+ +-------+ |
| 61 | |
| 62 | The chip starts by tranforming the state with TF2. Then, for each |
| 63 | input bit from 0 to 7: |
| 64 | - the nth bit from the state is sent to the output |
| 65 | - the state is transformed by TF1 if the input bit is 0 |
| 66 | |
| 67 | TF2 is a fixed linear substitution box (* = and, + = xor): |
| 68 | o = ff*s0 + fe*s1 + fc*s2 + f8*s3 + f0*s4 + e0*s5 + c0*s6 + 7f*s7 |
| 69 | |
| 70 | TF1 is a chip-dependent set of 8 linear sboxes, one per bit number. |
| 71 | In practice, only the sbox for bit 0 is defined for the chip, the 7 |
| 72 | other are derived from it. Defining the byte transformation Shift |
| 73 | as: |
| 74 | Shift(i7..i0) = i6..i0, i7^i6 |
| 75 | |
| 76 | and noting the sboxes as: |
| 77 | Sbox(n, i7..i0) = Xor( c[n, bit]*i[bit]) |
| 78 | 0<=bit<=7 |
| 79 | then |
| 80 | c[n, bit=0..6] = Shift(c[n-1, (bit-1)&7]) |
| 81 | c[n, 7] = Shift(c[n-1, 6])^c[n, 0] |
| 82 | = Shift(c[n-1, 6])^Shift(c[n-1, 7]) |
| 83 | */ |
| 84 | |
| 85 | #include "cat702.h" |
| 86 | |
| 87 | const device_type CAT702 = &device_creator<cat702_device>; |
| 88 | |
| 89 | cat702_device::cat702_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : |
| 90 | psxsiodev_device(mconfig, CAT702, "CAT702", tag, owner, clock, "cat702", __FILE__) |
| 91 | { |
| 92 | } |
| 93 | |
| 94 | void cat702_device::device_start() |
| 95 | { |
| 96 | psxsiodev_device::device_start(); |
| 97 | |
| 98 | save_item(NAME(m_select)); |
| 99 | save_item(NAME(m_state)); |
| 100 | save_item(NAME(m_bit)); |
| 101 | } |
| 102 | |
| 103 | // Given the value for x7..x0 and linear transform coefficients a7..a0 |
| 104 | // compute the value of the transform |
| 105 | #if 0 |
| 106 | static int c_linear(UINT8 x, UINT8 a) |
| 107 | { |
| 108 | int i; |
| 109 | UINT8 r; |
| 110 | x &= a; |
| 111 | r = 0; |
| 112 | for(i=0; i<8; i++) |
| 113 | if(x & (1<<i)) |
| 114 | r = !r; |
| 115 | return r; |
| 116 | } |
| 117 | #endif |
| 118 | |
| 119 | // Derive the sbox xor mask for a given input and select bit |
| 120 | UINT8 cat702_device::compute_sbox_coef(int sel, int bit) |
| 121 | { |
| 122 | if(!sel) |
| 123 | return m_transform[bit]; |
| 124 | |
| 125 | UINT8 r = compute_sbox_coef((sel-1) & 7, (bit-1) & 7); |
| 126 | r = (r << 1)|(((r >> 7)^(r >> 6)) & 1); |
| 127 | if(bit != 7) |
| 128 | return r; |
| 129 | |
| 130 | return r ^ compute_sbox_coef(sel, 0); |
| 131 | } |
| 132 | |
| 133 | // Apply the sbox for a input 0 bit |
| 134 | void cat702_device::apply_bit_sbox(int sel) |
| 135 | { |
| 136 | int i; |
| 137 | UINT8 r = 0; |
| 138 | for(i=0; i<8; i++) |
| 139 | if(m_state & (1<<i)) |
| 140 | r ^= compute_sbox_coef(sel, i); |
| 141 | |
| 142 | m_state = r; |
| 143 | } |
| 144 | |
| 145 | // Apply a sbox |
| 146 | void cat702_device::apply_sbox(const UINT8 *sbox) |
| 147 | { |
| 148 | int i; |
| 149 | UINT8 r = 0; |
| 150 | for(i=0; i<8; i++) |
| 151 | if(m_state & (1<<i)) |
| 152 | r ^= sbox[i]; |
| 153 | |
| 154 | m_state = r; |
| 155 | } |
| 156 | |
| 157 | void cat702_device::init(const UINT8 *transform) |
| 158 | { |
| 159 | m_transform = transform; |
| 160 | } |
| 161 | |
| 162 | void cat702_device::select(int select) |
| 163 | { |
| 164 | if (m_select != select) |
| 165 | { |
| 166 | if (!select) |
| 167 | { |
| 168 | m_state = 0xfc; |
| 169 | m_bit = 0; |
| 170 | } |
| 171 | else |
| 172 | { |
| 173 | data_out(0, PSX_SIO_IN_DATA); |
| 174 | } |
| 175 | |
| 176 | m_select = select; |
| 177 | } |
| 178 | } |
| 179 | |
| 180 | void cat702_device::data_in( int data, int mask ) |
| 181 | { |
| 182 | static const UINT8 initial_sbox[8] = { 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x7f }; |
| 183 | |
| 184 | if ( !m_select && (mask & PSX_SIO_OUT_CLOCK) != 0 && (data & PSX_SIO_OUT_CLOCK) == 0) |
| 185 | { |
| 186 | if (m_bit==0) |
| 187 | { |
| 188 | // Apply the initial sbox |
| 189 | apply_sbox(initial_sbox); |
| 190 | } |
| 191 | |
| 192 | // Compute the output and change the state |
| 193 | data_out(((m_state >> m_bit) & 1) != 0 ? PSX_SIO_IN_DATA : 0, PSX_SIO_IN_DATA); |
| 194 | |
| 195 | if((data & PSX_SIO_OUT_DATA)==0) |
| 196 | apply_bit_sbox(m_bit); |
| 197 | |
| 198 | m_bit++; |
| 199 | m_bit&=7; |
| 200 | } |
| 201 | } |
trunk/src/mame/machine/znsec.c
| r241419 | r241420 | |
| 1 | | /* |
| 2 | | |
| 3 | | CAT702 ZN security chip |
| 4 | | |
| 5 | | A serial magic latch. |
| 6 | | |
| 7 | | It's a DIP20 chip with a sticker of the form XXnn, where XX is the |
| 8 | | company and nn a number: |
| 9 | | AC = Acclaim |
| 10 | | AT = Atlus |
| 11 | | CP = Capcom |
| 12 | | ET = Raizing |
| 13 | | KN = Konami |
| 14 | | MG = Tecmo |
| 15 | | TT = Taito |
| 16 | | TW = Atari |
| 17 | | |
| 18 | | There usually are 2 of them, one on the cpu board and one on the rom |
| 19 | | board. The cpu board one is usually numbered 01. |
| 20 | | |
| 21 | | Pinout: GND -11 10- GND |
| 22 | | ? -12 9- +5V |
| 23 | | +5V -13 8- Data in |
| 24 | | Data out- 14 7- Clock |
| 25 | | +5V -15 6- Select |
| 26 | | ? -16 5- Select |
| 27 | | +5V -17 4- +5V |
| 28 | | +5V -18 3- +5V |
| 29 | | +5V -19 2- +5V |
| 30 | | +5V -20 1- ? |
| 31 | | |
| 32 | | The chip works with the '?' lines left unconnected. |
| 33 | | |
| 34 | | The communication protocol is serial, and in practice the standard |
| 35 | | psx controller communication protocol minus the ack. Drive both |
| 36 | | select to ground to start a communication, send bits and get the |
| 37 | | results on the raising clock. Put both select back to +5V when |
| 38 | | finished. The bios seems to use two communication clock speeds, |
| 39 | | ~300KHz (standard psx) and ~2MHz. Driving it with lower clocks |
| 40 | | works reasonably, at least at 1KHz. |
| 41 | | |
| 42 | | The data is divided in bytes but there is no signal for end-of-byte. |
| 43 | | In all of the following the data will be considered coming and going |
| 44 | | lower-bit first. |
| 45 | | |
| 46 | | Internally the chip has a 8-bit state, initialized at communication |
| 47 | | start to 0xfc. The structure is simple: |
| 48 | | |
| 49 | | |
| 50 | | +---------+ bit number +--------+ |
| 51 | | Clock ------->| bit |-----+-------------------->| bit |---------> Data out |
| 52 | | | counter | | | select | |
| 53 | | +---------+ v +-------+ out | | |
| 54 | | | +-----+ | 8bit |=====>| | |
| 55 | | Data in ------------|------->| TF1 |<=>| state | +--------+ |
| 56 | | | +-----+ | | |
| 57 | | | | | |
| 58 | | | start +-----+ | | |
| 59 | | +------->| TF2 |<=>| | |
| 60 | | +-----+ +-------+ |
| 61 | | |
| 62 | | The chip starts by tranforming the state with TF2. Then, for each |
| 63 | | input bit from 0 to 7: |
| 64 | | - the nth bit from the state is sent to the output |
| 65 | | - the state is transformed by TF1 if the input bit is 0 |
| 66 | | |
| 67 | | TF2 is a fixed linear substitution box (* = and, + = xor): |
| 68 | | o = ff*s0 + fe*s1 + fc*s2 + f8*s3 + f0*s4 + e0*s5 + c0*s6 + 7f*s7 |
| 69 | | |
| 70 | | TF1 is a chip-dependent set of 8 linear sboxes, one per bit number. |
| 71 | | In practice, only the sbox for bit 0 is defined for the chip, the 7 |
| 72 | | other are derived from it. Defining the byte transformation Shift |
| 73 | | as: |
| 74 | | Shift(i7..i0) = i6..i0, i7^i6 |
| 75 | | |
| 76 | | and noting the sboxes as: |
| 77 | | Sbox(n, i7..i0) = Xor( c[n, bit]*i[bit]) |
| 78 | | 0<=bit<=7 |
| 79 | | then |
| 80 | | c[n, bit=0..6] = Shift(c[n-1, (bit-1)&7]) |
| 81 | | c[n, 7] = Shift(c[n-1, 6])^c[n, 0] |
| 82 | | = Shift(c[n-1, 6])^Shift(c[n-1, 7]) |
| 83 | | */ |
| 84 | | |
| 85 | | #include "znsec.h" |
| 86 | | |
| 87 | | const device_type ZNSEC = &device_creator<znsec_device>; |
| 88 | | |
| 89 | | znsec_device::znsec_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : |
| 90 | | psxsiodev_device(mconfig, ZNSEC, "ZNSEC", tag, owner, clock, "znsec", __FILE__) |
| 91 | | { |
| 92 | | } |
| 93 | | |
| 94 | | void znsec_device::device_start() |
| 95 | | { |
| 96 | | psxsiodev_device::device_start(); |
| 97 | | |
| 98 | | save_item(NAME(m_select)); |
| 99 | | save_item(NAME(m_state)); |
| 100 | | save_item(NAME(m_bit)); |
| 101 | | } |
| 102 | | |
| 103 | | // Given the value for x7..x0 and linear transform coefficients a7..a0 |
| 104 | | // compute the value of the transform |
| 105 | | #if 0 |
| 106 | | static int c_linear(UINT8 x, UINT8 a) |
| 107 | | { |
| 108 | | int i; |
| 109 | | UINT8 r; |
| 110 | | x &= a; |
| 111 | | r = 0; |
| 112 | | for(i=0; i<8; i++) |
| 113 | | if(x & (1<<i)) |
| 114 | | r = !r; |
| 115 | | return r; |
| 116 | | } |
| 117 | | #endif |
| 118 | | |
| 119 | | // Derive the sbox xor mask for a given input and select bit |
| 120 | | UINT8 znsec_device::compute_sbox_coef(int sel, int bit) |
| 121 | | { |
| 122 | | if(!sel) |
| 123 | | return m_transform[bit]; |
| 124 | | |
| 125 | | UINT8 r = compute_sbox_coef((sel-1) & 7, (bit-1) & 7); |
| 126 | | r = (r << 1)|(((r >> 7)^(r >> 6)) & 1); |
| 127 | | if(bit != 7) |
| 128 | | return r; |
| 129 | | |
| 130 | | return r ^ compute_sbox_coef(sel, 0); |
| 131 | | } |
| 132 | | |
| 133 | | // Apply the sbox for a input 0 bit |
| 134 | | void znsec_device::apply_bit_sbox(int sel) |
| 135 | | { |
| 136 | | int i; |
| 137 | | UINT8 r = 0; |
| 138 | | for(i=0; i<8; i++) |
| 139 | | if(m_state & (1<<i)) |
| 140 | | r ^= compute_sbox_coef(sel, i); |
| 141 | | |
| 142 | | m_state = r; |
| 143 | | } |
| 144 | | |
| 145 | | // Apply a sbox |
| 146 | | void znsec_device::apply_sbox(const UINT8 *sbox) |
| 147 | | { |
| 148 | | int i; |
| 149 | | UINT8 r = 0; |
| 150 | | for(i=0; i<8; i++) |
| 151 | | if(m_state & (1<<i)) |
| 152 | | r ^= sbox[i]; |
| 153 | | |
| 154 | | m_state = r; |
| 155 | | } |
| 156 | | |
| 157 | | void znsec_device::init(const UINT8 *transform) |
| 158 | | { |
| 159 | | m_transform = transform; |
| 160 | | } |
| 161 | | |
| 162 | | void znsec_device::select(int select) |
| 163 | | { |
| 164 | | if (m_select != select) |
| 165 | | { |
| 166 | | if (!select) |
| 167 | | { |
| 168 | | m_state = 0xfc; |
| 169 | | m_bit = 0; |
| 170 | | } |
| 171 | | else |
| 172 | | { |
| 173 | | data_out(0, PSX_SIO_IN_DATA); |
| 174 | | } |
| 175 | | |
| 176 | | m_select = select; |
| 177 | | } |
| 178 | | } |
| 179 | | |
| 180 | | void znsec_device::data_in( int data, int mask ) |
| 181 | | { |
| 182 | | static const UINT8 initial_sbox[8] = { 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x7f }; |
| 183 | | |
| 184 | | if ( !m_select && (mask & PSX_SIO_OUT_CLOCK) != 0 && (data & PSX_SIO_OUT_CLOCK) == 0) |
| 185 | | { |
| 186 | | if (m_bit==0) |
| 187 | | { |
| 188 | | // Apply the initial sbox |
| 189 | | apply_sbox(initial_sbox); |
| 190 | | } |
| 191 | | |
| 192 | | // Compute the output and change the state |
| 193 | | data_out(((m_state >> m_bit) & 1) != 0 ? PSX_SIO_IN_DATA : 0, PSX_SIO_IN_DATA); |
| 194 | | |
| 195 | | if((data & PSX_SIO_OUT_DATA)==0) |
| 196 | | apply_bit_sbox(m_bit); |
| 197 | | |
| 198 | | m_bit++; |
| 199 | | m_bit&=7; |
| 200 | | } |
| 201 | | } |
trunk/src/mess/machine/psxanalog.c
| r241419 | r241420 | |
| 1 | | #include "machine/psxanalog.h" |
| 2 | | |
| 3 | | const device_type PSX_ANALOG_JOYSTICK = &device_creator<psx_analog_joystick_device>; |
| 4 | | const device_type PSX_DUALSHOCK = &device_creator<psx_dualshock_device>; |
| 5 | | |
| 6 | | psx_analog_controller_device::psx_analog_controller_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : |
| 7 | | device_t(mconfig, type, name, tag, owner, clock, shortname, source), |
| 8 | | device_psx_controller_interface(mconfig, *this), |
| 9 | | m_pad0(*this, "PSXPAD0"), |
| 10 | | m_pad1(*this, "PSXPAD1"), |
| 11 | | m_rstickx(*this, "PSXRSTICKX"), |
| 12 | | m_rsticky(*this, "PSXRSTICKY"), |
| 13 | | m_lstickx(*this, "PSXLSTICKX"), |
| 14 | | m_lsticky(*this, "PSXLSTICKY") |
| 15 | | { |
| 16 | | } |
| 17 | | |
| 18 | | psx_dualshock_device::psx_dualshock_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : |
| 19 | | psx_analog_controller_device(mconfig, PSX_DUALSHOCK, "Playstation Dualshock Pad", tag, owner, clock, "psx_dualshock_pad", __FILE__) |
| 20 | | { |
| 21 | | m_type = DUALSHOCK; |
| 22 | | } |
| 23 | | |
| 24 | | psx_analog_joystick_device::psx_analog_joystick_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : |
| 25 | | psx_analog_controller_device(mconfig, PSX_ANALOG_JOYSTICK, "Playstation Analog Joystick", tag, owner, clock, "psx_analog_joystick", __FILE__) |
| 26 | | { |
| 27 | | m_type = JOYSTICK; |
| 28 | | } |
| 29 | | |
| 30 | | void psx_analog_controller_device::device_reset() |
| 31 | | { |
| 32 | | m_confmode = false; |
| 33 | | m_analogmode = false; |
| 34 | | m_analoglock = false; |
| 35 | | |
| 36 | | m_cmd = 0; |
| 37 | | } |
| 38 | | |
| 39 | | UINT8 psx_analog_controller_device::pad_data(int count, bool analog) |
| 40 | | { |
| 41 | | UINT8 data = 0; |
| 42 | | switch(count) |
| 43 | | { |
| 44 | | case 2: |
| 45 | | data = m_pad0->read(); |
| 46 | | if(!analog || (m_type == JOYSTICK)) |
| 47 | | data |= 6; // l3/r3 |
| 48 | | break; |
| 49 | | case 3: |
| 50 | | data = m_pad1->read(); |
| 51 | | break; |
| 52 | | case 4: |
| 53 | | data = m_rstickx->read(); |
| 54 | | break; |
| 55 | | case 5: |
| 56 | | data = m_rsticky->read(); |
| 57 | | break; |
| 58 | | case 6: |
| 59 | | data = m_lstickx->read(); |
| 60 | | break; |
| 61 | | case 7: |
| 62 | | data = m_lsticky->read(); |
| 63 | | break; |
| 64 | | } |
| 65 | | return data; |
| 66 | | } |
| 67 | | |
| 68 | | bool psx_analog_controller_device::get_pad(int count, UINT8 *odata, UINT8 idata) |
| 69 | | { |
| 70 | | if(m_confmode) |
| 71 | | { |
| 72 | | switch(count) |
| 73 | | { |
| 74 | | case 0: |
| 75 | | m_temp = 0; |
| 76 | | *odata = 0xf3; |
| 77 | | break; |
| 78 | | case 1: |
| 79 | | m_cmd = idata; |
| 80 | | if((m_cmd & 0xf0) != 0x40) |
| 81 | | return false; |
| 82 | | *odata = 0x5a; |
| 83 | | break; |
| 84 | | default: |
| 85 | | switch(m_cmd) |
| 86 | | { |
| 87 | | default: // 40,41,48,49,4a,4b,4f -- all unknown |
| 88 | | *odata = 0x00; |
| 89 | | break; |
| 90 | | case CONFIG_MODE: // 43 |
| 91 | | if(count == 3) |
| 92 | | m_temp = idata; |
| 93 | | /* no break */ |
| 94 | | case QUERY_PAD_STATE: // 42 |
| 95 | | *odata = pad_data(count, true); |
| 96 | | break; |
| 97 | | case 0x44: // set mode and lock ? |
| 98 | | switch(count) |
| 99 | | { |
| 100 | | case 3: |
| 101 | | m_analogmode = idata ? true : false; // only 0x01 ? |
| 102 | | break; |
| 103 | | case 4: |
| 104 | | m_analoglock = idata ? true : false; // only 0x03 ? |
| 105 | | break; |
| 106 | | } |
| 107 | | *odata = 0x00; |
| 108 | | break; |
| 109 | | case 0x45: // get mode ? |
| 110 | | { |
| 111 | | const UINT8 val[] = { 1, 2, 0, 2, 1, 0 }; |
| 112 | | if(count == 4) |
| 113 | | *odata = m_analogmode; |
| 114 | | else |
| 115 | | *odata = val[count-2]; |
| 116 | | break; |
| 117 | | } |
| 118 | | case 0x46: // query act (vibrate) ? |
| 119 | | { |
| 120 | | const UINT8 val[2][6] = {{ 0, 0, 1, 2, 0, 10 }, |
| 121 | | { 0, 0, 1, 1, 1, 14 }}; |
| 122 | | *odata = val[m_temp][count-2]; |
| 123 | | if(count == 3) |
| 124 | | m_temp = idata ? 1 : 0; |
| 125 | | break; |
| 126 | | } |
| 127 | | case 0x47: // query comb (combination?) ? |
| 128 | | { |
| 129 | | const UINT8 val[] = { 0, 0, 2, 0, 1, 0 }; |
| 130 | | *odata = val[count-2]; |
| 131 | | break; |
| 132 | | } |
| 133 | | case 0x4c: // query mode ? |
| 134 | | switch(count) |
| 135 | | { |
| 136 | | case 3: |
| 137 | | m_temp = idata; |
| 138 | | /* no break */ |
| 139 | | default: |
| 140 | | *odata = 0x00; |
| 141 | | break; |
| 142 | | case 5: |
| 143 | | *odata = m_analogmode ? 0x07 : 0x04; // ? |
| 144 | | break; |
| 145 | | } |
| 146 | | break; |
| 147 | | case 0x4d: // set act (vibrate) ? |
| 148 | | *odata = 0xff; |
| 149 | | break; |
| 150 | | } |
| 151 | | break; |
| 152 | | case 8: |
| 153 | | if(m_cmd == CONFIG_MODE) |
| 154 | | m_confmode = m_temp; |
| 155 | | return false; |
| 156 | | } |
| 157 | | } |
| 158 | | else if(m_analogmode) |
| 159 | | { |
| 160 | | switch(count) |
| 161 | | { |
| 162 | | case 0: |
| 163 | | if(m_type == JOYSTICK) |
| 164 | | *odata = 0x53; |
| 165 | | else |
| 166 | | *odata = 0x73; |
| 167 | | break; |
| 168 | | case 1: |
| 169 | | m_cmd = idata; |
| 170 | | if((m_cmd & 0xfe) != QUERY_PAD_STATE) |
| 171 | | return false; |
| 172 | | *odata = 0x5a; |
| 173 | | break; |
| 174 | | case 3: |
| 175 | | if(m_cmd == CONFIG_MODE) |
| 176 | | m_temp = idata; |
| 177 | | /* no break */ |
| 178 | | default: |
| 179 | | *odata = pad_data(count, true); |
| 180 | | break; |
| 181 | | case 8: |
| 182 | | if(m_cmd == CONFIG_MODE) |
| 183 | | m_confmode = m_temp; |
| 184 | | return false; |
| 185 | | } |
| 186 | | } |
| 187 | | else |
| 188 | | { |
| 189 | | switch(count) |
| 190 | | { |
| 191 | | case 0: |
| 192 | | *odata = 0x41; |
| 193 | | break; |
| 194 | | case 1: |
| 195 | | m_cmd = idata; |
| 196 | | if((m_cmd & 0xfe) != QUERY_PAD_STATE) |
| 197 | | return false; |
| 198 | | *odata = 0x5a; |
| 199 | | break; |
| 200 | | case 3: |
| 201 | | if(m_cmd == CONFIG_MODE) |
| 202 | | m_temp = idata; |
| 203 | | /* no break */ |
| 204 | | default: |
| 205 | | *odata = pad_data(count, false); |
| 206 | | break; |
| 207 | | case 4: |
| 208 | | if(m_cmd == CONFIG_MODE) |
| 209 | | m_confmode = m_temp; |
| 210 | | return false; |
| 211 | | } |
| 212 | | } |
| 213 | | return true; |
| 214 | | } |
| 215 | | |
| 216 | | static INPUT_PORTS_START( psx_analog_controller ) |
| 217 | | PORT_START("PSXPAD0") |
| 218 | | PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) |
| 219 | | PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) |
| 220 | | PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) |
| 221 | | PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) |
| 222 | | PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START ) |
| 223 | | PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON9 ) PORT_NAME("R3") |
| 224 | | PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON10 ) PORT_NAME("L3") |
| 225 | | PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_SELECT ) |
| 226 | | |
| 227 | | PORT_START("PSXPAD1") |
| 228 | | PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("Square") |
| 229 | | PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("Cross") |
| 230 | | PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("Circle") |
| 231 | | PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("Triangle") |
| 232 | | PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("R1") |
| 233 | | PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("L1") |
| 234 | | PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON7 ) PORT_NAME("R2") |
| 235 | | PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON8 ) PORT_NAME("L2") |
| 236 | | |
| 237 | | PORT_START("PSXRSTICKX") |
| 238 | | PORT_BIT( 0xff, 0x80, IPT_AD_STICK_X ) PORT_NAME("Right Analog X") PORT_SENSITIVITY(100) |
| 239 | | |
| 240 | | PORT_START("PSXRSTICKY") |
| 241 | | PORT_BIT( 0xff, 0x80, IPT_AD_STICK_Y ) PORT_NAME("Right Analog Y") PORT_SENSITIVITY(100) |
| 242 | | |
| 243 | | PORT_START("PSXLSTICKX") |
| 244 | | PORT_BIT( 0xff, 0x80, IPT_AD_STICK_Z ) PORT_NAME("Left Analog X") PORT_SENSITIVITY(100) |
| 245 | | |
| 246 | | PORT_START("PSXLSTICKY") |
| 247 | | PORT_BIT( 0xff, 0x80, IPT_PADDLE ) PORT_NAME("Left Analog Y") PORT_SENSITIVITY(100) |
| 248 | | |
| 249 | | PORT_START("PSXMISC") |
| 250 | | PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON11 ) PORT_NAME("Analog") PORT_TOGGLE PORT_CHANGED_MEMBER(DEVICE_SELF, psx_analog_controller_device, change_mode, 0) |
| 251 | | INPUT_PORTS_END |
| 252 | | |
| 253 | | ioport_constructor psx_analog_controller_device::device_input_ports() const |
| 254 | | { |
| 255 | | return INPUT_PORTS_NAME(psx_analog_controller); |
| 256 | | } |
| 257 | | |
| 258 | | INPUT_CHANGED_MEMBER(psx_analog_controller_device::change_mode) |
| 259 | | { |
| 260 | | if(!m_analoglock) |
| 261 | | m_analogmode = newval; |
| 262 | | } |
trunk/src/mess/machine/psxanalog.h
| r241419 | r241420 | |
| 1 | | #ifndef PSXANALOG_H_ |
| 2 | | #define PSXANALOG_H_ |
| 3 | | |
| 4 | | #include "machine/psxcport.h" |
| 5 | | |
| 6 | | extern const device_type PSX_DUALSHOCK; |
| 7 | | extern const device_type PSX_ANALOG_JOYSTICK; |
| 8 | | |
| 9 | | class psx_analog_controller_device : public device_t, |
| 10 | | public device_psx_controller_interface |
| 11 | | { |
| 12 | | public: |
| 13 | | psx_analog_controller_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); |
| 14 | | |
| 15 | | virtual ioport_constructor device_input_ports() const; |
| 16 | | DECLARE_INPUT_CHANGED_MEMBER(change_mode); |
| 17 | | protected: |
| 18 | | virtual void device_reset(); |
| 19 | | virtual void device_start() {} |
| 20 | | enum { |
| 21 | | JOYSTICK, |
| 22 | | DUALSHOCK |
| 23 | | } m_type; |
| 24 | | private: |
| 25 | | virtual bool get_pad(int count, UINT8 *odata, UINT8 idata); |
| 26 | | UINT8 pad_data(int count, bool analog); |
| 27 | | |
| 28 | | bool m_confmode; |
| 29 | | bool m_analogmode; |
| 30 | | bool m_analoglock; |
| 31 | | |
| 32 | | UINT8 m_temp; |
| 33 | | UINT8 m_cmd; |
| 34 | | |
| 35 | | required_ioport m_pad0; |
| 36 | | required_ioport m_pad1; |
| 37 | | required_ioport m_rstickx; |
| 38 | | required_ioport m_rsticky; |
| 39 | | required_ioport m_lstickx; |
| 40 | | required_ioport m_lsticky; |
| 41 | | }; |
| 42 | | |
| 43 | | class psx_dualshock_device : public psx_analog_controller_device |
| 44 | | { |
| 45 | | public: |
| 46 | | psx_dualshock_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 47 | | }; |
| 48 | | |
| 49 | | class psx_analog_joystick_device : public psx_analog_controller_device |
| 50 | | { |
| 51 | | public: |
| 52 | | psx_analog_joystick_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 53 | | }; |
| 54 | | |
| 55 | | #endif /* PSXANALOG_H_ */ |
trunk/src/mess/machine/psxcard.c
| r241419 | r241420 | |
| 1 | | /* |
| 2 | | psxcard.c - Sony PlayStation memory card device |
| 3 | | |
| 4 | | by pSXAuthor |
| 5 | | MESS conversion by R. Belmont |
| 6 | | */ |
| 7 | | |
| 8 | | #include "emu.h" |
| 9 | | #include "psxcard.h" |
| 10 | | #include "machine/psxcport.h" |
| 11 | | |
| 12 | | // |
| 13 | | // |
| 14 | | // |
| 15 | | |
| 16 | | //#define debug_card |
| 17 | | |
| 18 | | // |
| 19 | | // |
| 20 | | // |
| 21 | | |
| 22 | | static const int block_size = 128; |
| 23 | | static const int card_size = block_size * 1024; |
| 24 | | |
| 25 | | const device_type PSXCARD = &device_creator<psxcard_device>; |
| 26 | | |
| 27 | | enum transfer_states |
| 28 | | { |
| 29 | | state_illegal=0, |
| 30 | | state_command, |
| 31 | | state_cmdack, |
| 32 | | state_wait, |
| 33 | | state_addr_hi, |
| 34 | | state_addr_lo, |
| 35 | | state_read, |
| 36 | | state_write, |
| 37 | | state_writeack_2, |
| 38 | | state_writechk, |
| 39 | | state_end |
| 40 | | }; |
| 41 | | |
| 42 | | psxcard_device::psxcard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 43 | | : device_t(mconfig, PSXCARD, "Sony PSX Memory Card", tag, owner, clock, "psxcard", __FILE__), |
| 44 | | device_image_interface(mconfig, *this) |
| 45 | | { |
| 46 | | } |
| 47 | | |
| 48 | | void psxcard_device::device_start() |
| 49 | | { |
| 50 | | m_owner = dynamic_cast<psx_controller_port_device *>(owner()); |
| 51 | | m_ack_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(psxcard_device::ack_timer), this)); |
| 52 | | |
| 53 | | m_ack = true; |
| 54 | | m_disabled = false; |
| 55 | | |
| 56 | | // save state registrations |
| 57 | | save_item(NAME(pkt)); |
| 58 | | save_item(NAME(pkt_ptr)); |
| 59 | | save_item(NAME(pkt_sz)); |
| 60 | | save_item(NAME(cmd)); |
| 61 | | save_item(NAME(addr)); |
| 62 | | save_item(NAME(state)); |
| 63 | | save_item(NAME(m_disabled)); |
| 64 | | save_item(NAME(m_odata)); |
| 65 | | save_item(NAME(m_idata)); |
| 66 | | save_item(NAME(m_bit)); |
| 67 | | save_item(NAME(m_count)); |
| 68 | | save_item(NAME(m_pad)); |
| 69 | | } |
| 70 | | |
| 71 | | void psxcard_device::device_reset() |
| 72 | | { |
| 73 | | state = state_illegal; |
| 74 | | addr = 0; |
| 75 | | |
| 76 | | m_bit = 0; |
| 77 | | m_count = 0; |
| 78 | | m_pad = false; |
| 79 | | m_idata = 0; |
| 80 | | |
| 81 | | m_clock = true; |
| 82 | | m_sel = true; |
| 83 | | m_rx = true; |
| 84 | | m_ack = true; |
| 85 | | m_owner->ack(); |
| 86 | | } |
| 87 | | |
| 88 | | void psxcard_device::device_config_complete() |
| 89 | | { |
| 90 | | update_names(PSXCARD, "memcard", "mc"); |
| 91 | | } |
| 92 | | |
| 93 | | // |
| 94 | | // |
| 95 | | // |
| 96 | | |
| 97 | | bool psxcard_device::transfer(UINT8 to, UINT8 *from) |
| 98 | | { |
| 99 | | bool ret=true; |
| 100 | | |
| 101 | | switch (state) |
| 102 | | { |
| 103 | | case state_illegal: |
| 104 | | if (is_loaded()) |
| 105 | | { |
| 106 | | // printf("CARD: begin\n"); |
| 107 | | state = state_command; |
| 108 | | *from = 0x00; |
| 109 | | } |
| 110 | | else |
| 111 | | { |
| 112 | | ret = false; |
| 113 | | } |
| 114 | | break; |
| 115 | | |
| 116 | | case state_command: |
| 117 | | cmd=to; |
| 118 | | *from=0x5a; |
| 119 | | state=state_cmdack; |
| 120 | | break; |
| 121 | | |
| 122 | | case state_cmdack: |
| 123 | | *from=0x5d; |
| 124 | | state=state_wait; |
| 125 | | break; |
| 126 | | |
| 127 | | case state_wait: |
| 128 | | *from=0x00; |
| 129 | | state=state_addr_hi; |
| 130 | | break; |
| 131 | | |
| 132 | | case state_addr_hi: |
| 133 | | addr=(to<<8); |
| 134 | | // printf("addr_hi: %02x, addr = %x\n", to, addr); |
| 135 | | *from=to; |
| 136 | | state=state_addr_lo; |
| 137 | | break; |
| 138 | | |
| 139 | | case state_addr_lo: |
| 140 | | addr|=(to&0xff); |
| 141 | | // printf("addr_lo: %02x, addr = %x, cmd = %x\n", to, addr, cmd); |
| 142 | | |
| 143 | | switch (cmd) |
| 144 | | { |
| 145 | | case 'R': // 0x52 |
| 146 | | { |
| 147 | | pkt[0]=*from=0x5c; |
| 148 | | pkt[1]=0x5d; |
| 149 | | pkt[2]=(addr>>8); |
| 150 | | pkt[3]=(addr&0xff); |
| 151 | | read_card(addr,&pkt[4]); |
| 152 | | pkt[4+128]=checksum_data(&pkt[2],128+2); |
| 153 | | pkt[5+128]=0x47; |
| 154 | | pkt_sz=6+128; |
| 155 | | pkt_ptr=1; |
| 156 | | state=state_read; |
| 157 | | break; |
| 158 | | } |
| 159 | | case 'W': // 0x57 |
| 160 | | { |
| 161 | | pkt[0]=addr>>8; |
| 162 | | pkt[1]=addr&0xff; |
| 163 | | pkt_sz=129+2; |
| 164 | | pkt_ptr=2; |
| 165 | | state=state_write; |
| 166 | | *from=to; |
| 167 | | break; |
| 168 | | } |
| 169 | | default: |
| 170 | | state=state_illegal; |
| 171 | | break; |
| 172 | | } |
| 173 | | break; |
| 174 | | |
| 175 | | case state_read: |
| 176 | | //assert(to==0); |
| 177 | | // printf("state_read: pkt_ptr = %d, pkt_sz = %d\n", pkt_ptr, pkt_sz); |
| 178 | | *from=pkt[pkt_ptr++]; |
| 179 | | if (pkt_ptr==pkt_sz) |
| 180 | | { |
| 181 | | #ifdef debug_card |
| 182 | | printf("card: read finished\n"); |
| 183 | | #endif |
| 184 | | |
| 185 | | state=state_end; |
| 186 | | } |
| 187 | | break; |
| 188 | | |
| 189 | | case state_write: |
| 190 | | *from=to; |
| 191 | | pkt[pkt_ptr++]=to; |
| 192 | | if (pkt_ptr==pkt_sz) |
| 193 | | { |
| 194 | | *from=0x5c; |
| 195 | | state=state_writeack_2; |
| 196 | | } |
| 197 | | break; |
| 198 | | |
| 199 | | case state_writeack_2: |
| 200 | | *from=0x5d; |
| 201 | | state=state_writechk; |
| 202 | | break; |
| 203 | | |
| 204 | | case state_writechk: |
| 205 | | { |
| 206 | | unsigned char chk=checksum_data(pkt,128+2); |
| 207 | | if (chk==pkt[128+2]) |
| 208 | | { |
| 209 | | #ifdef debug_card |
| 210 | | printf("card: write ok\n"); |
| 211 | | #endif |
| 212 | | |
| 213 | | write_card(addr,pkt+2); |
| 214 | | |
| 215 | | *from='G'; |
| 216 | | } else |
| 217 | | { |
| 218 | | #ifdef debug_card |
| 219 | | printf("card: write fail\n"); |
| 220 | | #endif |
| 221 | | |
| 222 | | *from='N'; |
| 223 | | } |
| 224 | | state=state_end; |
| 225 | | break; |
| 226 | | } |
| 227 | | |
| 228 | | case state_end: |
| 229 | | ret = false; |
| 230 | | state = state_illegal; |
| 231 | | break; |
| 232 | | |
| 233 | | default: /*assert(0);*/ ret=false; break; |
| 234 | | } |
| 235 | | |
| 236 | | #ifdef debug_card |
| 237 | | // printf("card: transfer to=%02x from=%02x ret=%c\n",to,*from,ret ? 'T' : 'F'); |
| 238 | | #endif |
| 239 | | |
| 240 | | return ret; |
| 241 | | } |
| 242 | | |
| 243 | | void psxcard_device::read_card(const unsigned short addr, unsigned char *buf) |
| 244 | | { |
| 245 | | #ifdef debug_card |
| 246 | | printf("card: read block %d\n",addr); |
| 247 | | #endif |
| 248 | | |
| 249 | | if (addr<(card_size/block_size)) |
| 250 | | { |
| 251 | | fseek(addr*block_size, SEEK_SET); |
| 252 | | fread(buf, block_size); |
| 253 | | } else |
| 254 | | { |
| 255 | | memset(buf,0,block_size); |
| 256 | | } |
| 257 | | } |
| 258 | | |
| 259 | | // |
| 260 | | // |
| 261 | | // |
| 262 | | |
| 263 | | void psxcard_device::write_card(const unsigned short addr, unsigned char *buf) |
| 264 | | { |
| 265 | | #ifdef debug_card |
| 266 | | printf("card: write block %d\n",addr); |
| 267 | | #endif |
| 268 | | |
| 269 | | if (addr<(card_size/block_size)) |
| 270 | | { |
| 271 | | fseek(addr*block_size, SEEK_SET); |
| 272 | | fwrite(buf, block_size); |
| 273 | | } |
| 274 | | } |
| 275 | | |
| 276 | | unsigned char psxcard_device::checksum_data(const unsigned char *buf, const unsigned int sz) |
| 277 | | { |
| 278 | | unsigned char chk=*buf++; |
| 279 | | int left=sz; |
| 280 | | while (--left) chk^=*buf++; |
| 281 | | return chk; |
| 282 | | } |
| 283 | | |
| 284 | | bool psxcard_device::call_load() |
| 285 | | { |
| 286 | | if(m_disabled) |
| 287 | | { |
| 288 | | logerror("psxcard: port disabled\n"); |
| 289 | | return IMAGE_INIT_FAIL; |
| 290 | | } |
| 291 | | |
| 292 | | if(length() != card_size) |
| 293 | | return IMAGE_INIT_FAIL; |
| 294 | | return IMAGE_INIT_PASS; |
| 295 | | } |
| 296 | | |
| 297 | | bool psxcard_device::call_create(int format_type, option_resolution *format_options) |
| 298 | | { |
| 299 | | UINT8 block[block_size]; |
| 300 | | int i, ret; |
| 301 | | |
| 302 | | if(m_disabled) |
| 303 | | { |
| 304 | | logerror("psxcard: port disabled\n"); |
| 305 | | return IMAGE_INIT_FAIL; |
| 306 | | } |
| 307 | | |
| 308 | | memset(block, '\0', block_size); |
| 309 | | for(i = 0; i < (card_size/block_size); i++) |
| 310 | | { |
| 311 | | ret = fwrite(block, block_size); |
| 312 | | if(ret != block_size) |
| 313 | | return IMAGE_INIT_FAIL; |
| 314 | | } |
| 315 | | return IMAGE_INIT_PASS; |
| 316 | | } |
| 317 | | |
| 318 | | void psxcard_device::do_card() |
| 319 | | { |
| 320 | | if(!m_bit) |
| 321 | | { |
| 322 | | m_idata = 0; |
| 323 | | if(!m_count) |
| 324 | | m_odata = 0xff; |
| 325 | | } |
| 326 | | |
| 327 | | m_rx = (m_odata & (1 << m_bit)) ? true : false; |
| 328 | | m_idata |= (m_owner->tx_r()?1:0) << m_bit; |
| 329 | | m_bit = (m_bit + 1) % 8; |
| 330 | | |
| 331 | | if(!m_bit) |
| 332 | | { |
| 333 | | if((!m_count) && !(m_idata & 0x80)) |
| 334 | | { |
| 335 | | m_pad = true; |
| 336 | | return; |
| 337 | | } |
| 338 | | |
| 339 | | if(transfer(m_idata, &m_odata)) |
| 340 | | { |
| 341 | | m_count++; |
| 342 | | m_ack_timer->adjust(attotime::from_usec(10), 0); |
| 343 | | } |
| 344 | | else |
| 345 | | m_count = 0; |
| 346 | | } |
| 347 | | } |
| 348 | | |
| 349 | | void psxcard_device::ack_timer(void *ptr, int param) |
| 350 | | { |
| 351 | | m_ack = param; |
| 352 | | m_owner->ack(); |
| 353 | | |
| 354 | | if(!param) |
| 355 | | m_ack_timer->adjust(attotime::from_usec(2), 1); |
| 356 | | } |
| 357 | | |
| 358 | | void psxcard_device::sel_w(bool state) |
| 359 | | { |
| 360 | | if(state && !m_sel) |
| 361 | | reset(); |
| 362 | | m_sel = state; |
| 363 | | } |
trunk/src/mess/machine/psxcard.h
| r241419 | r241420 | |
| 1 | | #pragma once |
| 2 | | |
| 3 | | #ifndef _PSXCARD_ |
| 4 | | #define _PSXCARD_ |
| 5 | | |
| 6 | | #include "emu.h" |
| 7 | | |
| 8 | | class psx_controller_port_device; |
| 9 | | |
| 10 | | #define MCFG_PSXCARD_ADD(_tag) \ |
| 11 | | MCFG_DEVICE_ADD(_tag, PSXCARD, 0) |
| 12 | | |
| 13 | | class psxcard_device : public device_t, |
| 14 | | public device_image_interface |
| 15 | | { |
| 16 | | public: |
| 17 | | psxcard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 18 | | |
| 19 | | virtual iodevice_t image_type() const { return IO_MEMCARD; } |
| 20 | | |
| 21 | | virtual bool is_readable() const { return 1; } |
| 22 | | virtual bool is_writeable() const { return 1; } |
| 23 | | virtual bool is_creatable() const { return 1; } |
| 24 | | virtual bool must_be_loaded() const { return 0; } |
| 25 | | virtual bool is_reset_on_load() const { return 0; } |
| 26 | | virtual const char *file_extensions() const { return "mc"; } |
| 27 | | virtual const option_guide *create_option_guide() const { return NULL; } |
| 28 | | |
| 29 | | virtual bool call_load(); |
| 30 | | virtual bool call_create(int format_type, option_resolution *format_options); |
| 31 | | |
| 32 | | void disable(bool state) { m_disabled = state; if(state) unload(); } |
| 33 | | |
| 34 | | private: |
| 35 | | unsigned char pkt[0x8b], pkt_ptr, pkt_sz, cmd; |
| 36 | | unsigned short addr; |
| 37 | | int state; |
| 38 | | bool m_disabled; |
| 39 | | |
| 40 | | UINT8 m_odata; |
| 41 | | UINT8 m_idata; |
| 42 | | int m_bit; |
| 43 | | int m_count; |
| 44 | | bool m_pad; |
| 45 | | |
| 46 | | bool m_clock; |
| 47 | | bool m_sel; |
| 48 | | bool m_ack; |
| 49 | | bool m_rx; |
| 50 | | |
| 51 | | emu_timer *m_ack_timer; |
| 52 | | psx_controller_port_device *m_owner; |
| 53 | | |
| 54 | | void read_card(const unsigned short addr, unsigned char *buf); |
| 55 | | void write_card(const unsigned short addr, unsigned char *buf); |
| 56 | | unsigned char checksum_data(const unsigned char *buf, const unsigned int sz); |
| 57 | | void do_card(); |
| 58 | | bool transfer(UINT8 to, UINT8 *from); |
| 59 | | void ack_timer(void *ptr, int param); |
| 60 | | |
| 61 | | public: |
| 62 | | virtual void device_start(); |
| 63 | | virtual void device_reset(); |
| 64 | | virtual void device_config_complete(); |
| 65 | | |
| 66 | | void clock_w(bool state) { if(m_clock && !m_sel && !state && !m_pad) do_card(); m_clock = state; } |
| 67 | | void sel_w(bool state); |
| 68 | | bool rx_r() { return m_rx; } |
| 69 | | bool ack_r() { return m_ack; } |
| 70 | | }; |
| 71 | | |
| 72 | | // device type definition |
| 73 | | extern const device_type PSXCARD; |
| 74 | | |
| 75 | | #endif |
trunk/src/mess/machine/psxcport.c
| r241419 | r241420 | |
| 1 | | /* PAD emulation */ |
| 2 | | |
| 3 | | #include "machine/psxcport.h" |
| 4 | | #include "machine/psxanalog.h" |
| 5 | | #include "machine/psxmultitap.h" |
| 6 | | |
| 7 | | const device_type PSX_CONTROLLER_PORT = &device_creator<psx_controller_port_device>; |
| 8 | | |
| 9 | | psx_controller_port_device::psx_controller_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : |
| 10 | | device_t(mconfig, PSX_CONTROLLER_PORT, "Playstation Controller Port", tag, owner, clock, "psx_controller_port", __FILE__), |
| 11 | | device_slot_interface(mconfig, *this), |
| 12 | | m_card(*this, "card") |
| 13 | | { |
| 14 | | } |
| 15 | | |
| 16 | | void psx_controller_port_device::device_config_complete() |
| 17 | | { |
| 18 | | m_dev = dynamic_cast<device_psx_controller_interface *>(get_card_device()); |
| 19 | | } |
| 20 | | |
| 21 | | static MACHINE_CONFIG_FRAGMENT( psx_memory_card ) |
| 22 | | MCFG_PSXCARD_ADD("card") |
| 23 | | MACHINE_CONFIG_END |
| 24 | | |
| 25 | | machine_config_constructor psx_controller_port_device::device_mconfig_additions() const |
| 26 | | { |
| 27 | | return MACHINE_CONFIG_NAME( psx_memory_card ); |
| 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 | | |
| 38 | | const device_type PSXCONTROLLERPORTS = &device_creator<psxcontrollerports_device>; |
| 39 | | |
| 40 | | psxcontrollerports_device::psxcontrollerports_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : |
| 41 | | psxsiodev_device(mconfig, PSXCONTROLLERPORTS, "PSXCONTROLLERPORTS", tag, owner, clock, "psxcontrollerports", __FILE__) |
| 42 | | { |
| 43 | | } |
| 44 | | |
| 45 | | void psxcontrollerports_device::device_start() |
| 46 | | { |
| 47 | | m_port0 = machine().device<psx_controller_port_device>("port1"); |
| 48 | | m_port1 = machine().device<psx_controller_port_device>("port2"); |
| 49 | | m_port0->setup_ack_cb(psx_controller_port_device::void_cb(FUNC(psxcontrollerports_device::ack), this)); |
| 50 | | m_port1->setup_ack_cb(psx_controller_port_device::void_cb(FUNC(psxcontrollerports_device::ack), this)); |
| 51 | | psxsiodev_device::device_start(); |
| 52 | | } |
| 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 | | |
| 60 | | SLOT_INTERFACE_START(psx_controllers) |
| 61 | | PSX_CONTROLLERS |
| 62 | | SLOT_INTERFACE("multitap", PSX_MULTITAP) |
| 63 | | SLOT_INTERFACE_END |
| 64 | | |
| 65 | | SLOT_INTERFACE_START(psx_controllers_nomulti) |
| 66 | | PSX_CONTROLLERS |
| 67 | | SLOT_INTERFACE_END |
| 68 | | |
| 69 | | void psxcontrollerports_device::data_in( int data, int mask ) |
| 70 | | { |
| 71 | | m_port0->sel_w((data & PSX_SIO_OUT_DTR)?1:0); |
| 72 | | m_port0->tx_w((data & PSX_SIO_OUT_DATA)?1:0); |
| 73 | | m_port0->clock_w((data & PSX_SIO_OUT_CLOCK)?1:0); // clock must be last |
| 74 | | |
| 75 | | m_port1->tx_w((data & PSX_SIO_OUT_DATA)?1:0); |
| 76 | | m_port1->sel_w((data & PSX_SIO_OUT_DTR)?0:1); // not dtr |
| 77 | | m_port1->clock_w((data & PSX_SIO_OUT_CLOCK)?1:0); |
| 78 | | |
| 79 | | data_out(((m_port0->rx_r() && m_port1->rx_r()) * PSX_SIO_IN_DATA), PSX_SIO_IN_DATA); |
| 80 | | } |
| 81 | | |
| 82 | | void psxcontrollerports_device::ack() |
| 83 | | { |
| 84 | | data_out((!(m_port0->ack_r() && m_port1->ack_r()) * PSX_SIO_IN_DSR), PSX_SIO_IN_DSR); |
| 85 | | } |
| 86 | | |
| 87 | | device_psx_controller_interface::device_psx_controller_interface(const machine_config &mconfig, device_t &device) : |
| 88 | | device_slot_card_interface(mconfig, device), |
| 89 | | m_ack(true) |
| 90 | | { |
| 91 | | } |
| 92 | | |
| 93 | | device_psx_controller_interface::~device_psx_controller_interface() |
| 94 | | { |
| 95 | | } |
| 96 | | |
| 97 | | void device_psx_controller_interface::interface_pre_reset() |
| 98 | | { |
| 99 | | m_bit = 0; |
| 100 | | m_count = 0; |
| 101 | | m_idata = 0; |
| 102 | | m_memcard = false; |
| 103 | | |
| 104 | | m_clock = true; |
| 105 | | m_sel = true; |
| 106 | | m_rx = true; |
| 107 | | m_ack = true; |
| 108 | | m_owner->ack(); |
| 109 | | } |
| 110 | | |
| 111 | | void device_psx_controller_interface::interface_pre_start() |
| 112 | | { |
| 113 | | m_owner = dynamic_cast<psx_controller_port_device *>(device().owner()); |
| 114 | | m_ack_timer = device().machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(device_psx_controller_interface::ack_timer), this)); |
| 115 | | } |
| 116 | | |
| 117 | | void device_psx_controller_interface::ack_timer(void *ptr, int param) |
| 118 | | { |
| 119 | | m_ack = param; |
| 120 | | m_owner->ack(); |
| 121 | | |
| 122 | | if(!param) |
| 123 | | m_ack_timer->adjust(attotime::from_usec(2), 1); |
| 124 | | } |
| 125 | | |
| 126 | | void device_psx_controller_interface::do_pad() |
| 127 | | { |
| 128 | | if(!m_bit) |
| 129 | | { |
| 130 | | if(!m_count) |
| 131 | | m_odata = 0xff; |
| 132 | | m_idata = 0; |
| 133 | | } |
| 134 | | |
| 135 | | m_rx = (m_odata & (1 << m_bit)) ? true : false; |
| 136 | | m_idata |= (m_owner->tx_r()?1:0) << m_bit; |
| 137 | | m_bit = (m_bit + 1) % 8; |
| 138 | | |
| 139 | | if(!m_bit) |
| 140 | | { |
| 141 | | if((!m_count) && (m_idata & 0xf0)) |
| 142 | | { |
| 143 | | m_memcard = true; |
| 144 | | return; |
| 145 | | } |
| 146 | | |
| 147 | | if(get_pad(m_count++, &m_odata, m_idata)) |
| 148 | | m_ack_timer->adjust(attotime::from_usec(10), 0); |
| 149 | | else |
| 150 | | m_count = 0; |
| 151 | | } |
| 152 | | } |
| 153 | | |
| 154 | | void device_psx_controller_interface::sel_w(bool state) { |
| 155 | | if(state && !m_sel) |
| 156 | | interface_pre_reset(); // don't reset the controller, just the interface |
| 157 | | m_sel = state; |
| 158 | | } |
| 159 | | |
| 160 | | const device_type PSX_STANDARD_CONTROLLER = &device_creator<psx_standard_controller_device>; |
| 161 | | |
| 162 | | psx_standard_controller_device::psx_standard_controller_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : |
| 163 | | device_t(mconfig, PSX_STANDARD_CONTROLLER, "Playstation Standard Controller", tag, owner, clock, "psx_standard_controller", __FILE__), |
| 164 | | device_psx_controller_interface(mconfig, *this), |
| 165 | | m_pad0(*this,"PSXPAD0"), |
| 166 | | m_pad1(*this,"PSXPAD1") |
| 167 | | { |
| 168 | | } |
| 169 | | |
| 170 | | bool psx_standard_controller_device::get_pad(int count, UINT8 *odata, UINT8 idata) |
| 171 | | { |
| 172 | | switch(count) |
| 173 | | { |
| 174 | | case 0: |
| 175 | | *odata = 0x41; |
| 176 | | break; |
| 177 | | case 1: |
| 178 | | if(idata != QUERY_PAD_STATE) |
| 179 | | return false; |
| 180 | | *odata = 0x5a; |
| 181 | | break; |
| 182 | | case 2: |
| 183 | | *odata = m_pad0->read(); |
| 184 | | break; |
| 185 | | case 3: |
| 186 | | *odata = m_pad1->read(); |
| 187 | | break; |
| 188 | | case 4: |
| 189 | | return false; |
| 190 | | } |
| 191 | | return true; |
| 192 | | } |
| 193 | | |
| 194 | | static INPUT_PORTS_START( psx_standard_controller ) |
| 195 | | PORT_START("PSXPAD0") |
| 196 | | PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) |
| 197 | | PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) |
| 198 | | PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) |
| 199 | | PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) |
| 200 | | PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START ) |
| 201 | | PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) |
| 202 | | PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) |
| 203 | | PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_SELECT ) |
| 204 | | |
| 205 | | PORT_START("PSXPAD1") |
| 206 | | PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("Square") |
| 207 | | PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("Cross") |
| 208 | | PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("Circle") |
| 209 | | PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("Triangle") |
| 210 | | PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("R1") |
| 211 | | PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("L1") |
| 212 | | PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON7 ) PORT_NAME("R2") |
| 213 | | PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON8 ) PORT_NAME("L2") |
| 214 | | INPUT_PORTS_END |
| 215 | | |
| 216 | | ioport_constructor psx_standard_controller_device::device_input_ports() const |
| 217 | | { |
| 218 | | return INPUT_PORTS_NAME(psx_standard_controller); |
| 219 | | } |
trunk/src/mess/machine/psxcport.h
| r241419 | r241420 | |
| 1 | | #pragma once |
| 2 | | |
| 3 | | #ifndef __PSXCPORT_H__ |
| 4 | | #define __PSXCPORT_H__ |
| 5 | | |
| 6 | | #include "cpu/psx/siodev.h" |
| 7 | | #include "machine/psxcard.h" |
| 8 | | |
| 9 | | #define MCFG_PSX_CTRL_PORT_ADD(_tag, _slot_intf, _def_slot) \ |
| 10 | | MCFG_DEVICE_ADD(_tag, PSX_CONTROLLER_PORT, 0) \ |
| 11 | | MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) |
| 12 | | |
| 13 | | SLOT_INTERFACE_EXTERN(psx_controllers); |
| 14 | | |
| 15 | | extern const device_type PSXCONTROLLERPORTS; |
| 16 | | extern const device_type PSX_CONTROLLER_PORT; |
| 17 | | extern const device_type PSX_STANDARD_CONTROLLER; |
| 18 | | |
| 19 | | class psx_controller_port_device; |
| 20 | | |
| 21 | | class device_psx_controller_interface : public device_slot_card_interface |
| 22 | | { |
| 23 | | friend class psx_multitap_device; |
| 24 | | public: |
| 25 | | device_psx_controller_interface(const machine_config &mconfig, device_t &device); |
| 26 | | virtual ~device_psx_controller_interface(); |
| 27 | | |
| 28 | | void clock_w(bool state) { if(m_clock && !m_sel && !state && !m_memcard) do_pad(); m_clock = state; } |
| 29 | | void sel_w(bool state); |
| 30 | | |
| 31 | | bool rx_r() { return m_rx; } |
| 32 | | bool ack_r() { return m_ack; } |
| 33 | | |
| 34 | | protected: |
| 35 | | virtual void interface_pre_reset(); |
| 36 | | virtual void interface_pre_start(); |
| 37 | | |
| 38 | | enum |
| 39 | | { |
| 40 | | QUERY_PAD_STATE = 0x42, |
| 41 | | CONFIG_MODE = 0x43, |
| 42 | | }; |
| 43 | | |
| 44 | | private: |
| 45 | | virtual bool get_pad(int count, UINT8 *odata, UINT8 idata) = 0; |
| 46 | | virtual void do_pad(); |
| 47 | | void ack_timer(void *ptr, int param); |
| 48 | | |
| 49 | | UINT8 m_odata; |
| 50 | | UINT8 m_idata; |
| 51 | | int m_bit; |
| 52 | | int m_count; |
| 53 | | bool m_memcard; |
| 54 | | |
| 55 | | bool m_clock; |
| 56 | | bool m_sel; |
| 57 | | bool m_ack; |
| 58 | | bool m_rx; |
| 59 | | |
| 60 | | emu_timer *m_ack_timer; |
| 61 | | psx_controller_port_device *m_owner; |
| 62 | | }; |
| 63 | | |
| 64 | | class psx_standard_controller_device : public device_t, |
| 65 | | public device_psx_controller_interface |
| 66 | | { |
| 67 | | public: |
| 68 | | psx_standard_controller_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 69 | | |
| 70 | | virtual ioport_constructor device_input_ports() const; |
| 71 | | |
| 72 | | protected: |
| 73 | | virtual void device_start() { } |
| 74 | | private: |
| 75 | | virtual bool get_pad(int count, UINT8 *odata, UINT8 idata); |
| 76 | | |
| 77 | | required_ioport m_pad0; |
| 78 | | required_ioport m_pad1; |
| 79 | | }; |
| 80 | | |
| 81 | | class psxcontrollerports_device : public psxsiodev_device |
| 82 | | { |
| 83 | | public: |
| 84 | | psxcontrollerports_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 85 | | void ack(); |
| 86 | | |
| 87 | | protected: |
| 88 | | virtual void device_start(); |
| 89 | | |
| 90 | | private: |
| 91 | | virtual void data_in(int data, int mask); |
| 92 | | |
| 93 | | psx_controller_port_device *m_port0; |
| 94 | | psx_controller_port_device *m_port1; |
| 95 | | }; |
| 96 | | |
| 97 | | class psx_controller_port_device : public device_t, |
| 98 | | public device_slot_interface |
| 99 | | { |
| 100 | | public: |
| 101 | | psx_controller_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 102 | | virtual machine_config_constructor device_mconfig_additions() const; |
| 103 | | |
| 104 | | typedef delegate<void ()> void_cb; |
| 105 | | void ack() { if(!ack_cb.isnull()) ack_cb(); } |
| 106 | | void setup_ack_cb(void_cb cb) { ack_cb = cb; } |
| 107 | | |
| 108 | | DECLARE_WRITE_LINE_MEMBER(tx_w) { m_tx = state; } |
| 109 | | DECLARE_WRITE_LINE_MEMBER(sel_w) { if(m_dev) m_dev->sel_w(state); m_card->sel_w(state); } |
| 110 | | DECLARE_WRITE_LINE_MEMBER(clock_w) { if(m_dev) m_dev->clock_w(state); m_card->clock_w(state); } |
| 111 | | |
| 112 | | DECLARE_READ_LINE_MEMBER(rx_r) { return (m_dev?m_dev->rx_r():true) && m_card->rx_r(); } |
| 113 | | DECLARE_READ_LINE_MEMBER(ack_r) { return (m_dev?m_dev->ack_r():true) && m_card->ack_r(); } |
| 114 | | DECLARE_READ_LINE_MEMBER(tx_r) { return m_tx; } |
| 115 | | |
| 116 | | void disable_card(bool status); |
| 117 | | |
| 118 | | protected: |
| 119 | | virtual void device_start() {} |
| 120 | | virtual void device_reset() { m_tx = true; } |
| 121 | | virtual void device_config_complete(); |
| 122 | | |
| 123 | | private: |
| 124 | | void_cb ack_cb; |
| 125 | | bool m_tx; |
| 126 | | |
| 127 | | device_psx_controller_interface *m_dev; |
| 128 | | required_device<psxcard_device> m_card; |
| 129 | | }; |
| 130 | | #endif |
trunk/src/mess/machine/psxmultitap.c
| r241419 | r241420 | |
| 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, "psx_multitap", __FILE__), |
| 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") |
| 19 | | MCFG_PSX_CTRL_PORT_ADD("b", psx_controllers_nomulti, NULL) |
| 20 | | MCFG_PSX_CTRL_PORT_ADD("c", psx_controllers_nomulti, NULL) |
| 21 | | MCFG_PSX_CTRL_PORT_ADD("d", psx_controllers_nomulti, 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 | | save_item(NAME(m_activeport)); |
| 38 | | save_item(NAME(m_cack)); |
| 39 | | save_item(NAME(m_singlemode)); |
| 40 | | save_item(NAME(m_nextmode)); |
| 41 | | save_item(NAME(m_tapmc)); |
| 42 | | save_item(NAME(m_data)); |
| 43 | | } |
| 44 | | |
| 45 | | void psx_multitap_device::interface_pre_reset() |
| 46 | | { |
| 47 | | m_activeport = -1; |
| 48 | | m_singlemode = m_nextmode; |
| 49 | | m_tapmc = false; |
| 50 | | m_cack[0] = m_cack[1] = m_cack[2] = m_cack[3] = true; |
| 51 | | memset(m_data, 0xff, sizeof(m_data)); |
| 52 | | m_porta->sel_w(false); |
| 53 | | m_portb->sel_w(false); |
| 54 | | m_portc->sel_w(false); |
| 55 | | m_portd->sel_w(false); |
| 56 | | m_porta->sel_w(true); |
| 57 | | m_portb->sel_w(true); |
| 58 | | m_portc->sel_w(true); |
| 59 | | m_portd->sel_w(true); |
| 60 | | device_psx_controller_interface::interface_pre_reset(); |
| 61 | | } |
| 62 | | |
| 63 | | void psx_multitap_device::set_tx_line(bool tx, int port) |
| 64 | | { |
| 65 | | psx_controller_port_device *dev; |
| 66 | | switch(port) |
| 67 | | { |
| 68 | | default: |
| 69 | | case 0: |
| 70 | | dev = m_porta; |
| 71 | | break; |
| 72 | | case 1: |
| 73 | | dev = m_portb; |
| 74 | | break; |
| 75 | | case 2: |
| 76 | | dev = m_portc; |
| 77 | | break; |
| 78 | | case 3: |
| 79 | | dev = m_portd; |
| 80 | | break; |
| 81 | | } |
| 82 | | dev->clock_w(1); |
| 83 | | dev->tx_w(tx); |
| 84 | | dev->clock_w(0); |
| 85 | | } |
| 86 | | |
| 87 | | bool psx_multitap_device::get_rx_line(int port) |
| 88 | | { |
| 89 | | psx_controller_port_device *dev; |
| 90 | | switch(port) |
| 91 | | { |
| 92 | | default: |
| 93 | | case 0: |
| 94 | | dev = m_porta; |
| 95 | | break; |
| 96 | | case 1: |
| 97 | | dev = m_portb; |
| 98 | | break; |
| 99 | | case 2: |
| 100 | | dev = m_portc; |
| 101 | | break; |
| 102 | | case 3: |
| 103 | | dev = m_portd; |
| 104 | | break; |
| 105 | | } |
| 106 | | return dev->rx_r(); |
| 107 | | } |
| 108 | | |
| 109 | | void psx_multitap_device::do_pad() |
| 110 | | { |
| 111 | | bool tx = device_psx_controller_interface::m_owner->tx_r(); |
| 112 | | |
| 113 | | // we don't know which controller until after the first byte |
| 114 | | if((m_singlemode || m_tapmc) && (m_count >= 1)) |
| 115 | | { |
| 116 | | if((m_count == 2) && !m_bit && !m_tapmc) |
| 117 | | m_nextmode = !tx; |
| 118 | | |
| 119 | | set_tx_line(tx, m_activeport); |
| 120 | | m_rx = get_rx_line(m_activeport); |
| 121 | | m_bit = (m_bit + 1) % 8; |
| 122 | | if(!m_bit) |
| 123 | | m_count++; |
| 124 | | return; |
| 125 | | } |
| 126 | | |
| 127 | | if(!m_count) |
| 128 | | { |
| 129 | | // first send the select byte to all devices until we know whether it's accessing |
| 130 | | // a controller or memcard |
| 131 | | if(!m_bit) |
| 132 | | { |
| 133 | | m_porta->sel_w(false); |
| 134 | | m_portb->sel_w(false); |
| 135 | | m_portc->sel_w(false); |
| 136 | | m_portd->sel_w(false); |
| 137 | | } |
| 138 | | device_psx_controller_interface::do_pad(); |
| 139 | | set_tx_line(tx, 0); |
| 140 | | set_tx_line(tx, 1); |
| 141 | | set_tx_line(tx, 2); |
| 142 | | set_tx_line(tx, 3); |
| 143 | | if(!m_bit) |
| 144 | | { |
| 145 | | m_count = 1; |
| 146 | | m_tapmc = m_memcard; |
| 147 | | m_memcard = false; // make sure we still receive clocks |
| 148 | | if(m_singlemode || m_tapmc) |
| 149 | | { |
| 150 | | m_activeport = (m_idata & 0xf) - 1; |
| 151 | | m_porta->sel_w((m_activeport == 0) ? false : true); |
| 152 | | m_portb->sel_w((m_activeport == 1) ? false : true); |
| 153 | | m_portc->sel_w((m_activeport == 2) ? false : true); |
| 154 | | m_portd->sel_w((m_activeport == 3) ? false : true); |
| 155 | | } |
| 156 | | } |
| 157 | | return; |
| 158 | | } |
| 159 | | else if(m_count <= 2) |
| 160 | | return device_psx_controller_interface::do_pad(); |
| 161 | | else if(m_count < 11) |
| 162 | | { |
| 163 | | if((m_count == 3) && !m_bit) |
| 164 | | m_nextmode = !m_idata; |
| 165 | | |
| 166 | | if((m_count < 5) && m_cack[0] && m_cack[1] && m_cack[2] && m_cack[3]) |
| 167 | | return; // no acks? hang up. |
| 168 | | |
| 169 | | // all of the ports are polled here, port a is passed though. the data |
| 170 | | // from the other ports is stored and can be retrieved at a much higher clock rate |
| 171 | | // don't poll a port that is inactive or done |
| 172 | | if(!m_cack[0]) |
| 173 | | { |
| 174 | | set_tx_line(tx, 0); |
| 175 | | m_rx = m_porta->rx_r(); |
| 176 | | } |
| 177 | | else |
| 178 | | { |
| 179 | | m_rx = true; |
| 180 | | m_porta->sel_w(true); |
| 181 | | } |
| 182 | | |
| 183 | | if(!m_cack[1]) |
| 184 | | { |
| 185 | | set_tx_line(tx, 1); |
| 186 | | m_data[0][m_count - 3] &= ~(!m_portb->rx_r() << m_bit); |
| 187 | | } |
| 188 | | else |
| 189 | | m_portb->sel_w(true); |
| 190 | | |
| 191 | | if(!m_cack[2]) |
| 192 | | { |
| 193 | | set_tx_line(tx, 2); |
| 194 | | m_data[1][m_count - 3] &= ~(!m_portc->rx_r() << m_bit); |
| 195 | | } |
| 196 | | else |
| 197 | | m_portc->sel_w(true); |
| 198 | | |
| 199 | | if(!m_cack[3]) |
| 200 | | { |
| 201 | | set_tx_line(tx, 3); |
| 202 | | m_data[2][m_count - 3] &= ~(!m_portd->rx_r() << m_bit); |
| 203 | | } |
| 204 | | else |
| 205 | | m_portd->sel_w(true); |
| 206 | | } |
| 207 | | else if(m_count < 19) |
| 208 | | // send stored port b data |
| 209 | | m_rx = ((m_data[0][m_count - 11] & (1 << m_bit)) ? 1 : 0); |
| 210 | | else if(m_count < 27) |
| 211 | | // send stored port c data |
| 212 | | m_rx = ((m_data[1][m_count - 19] & (1 << m_bit)) ? 1 : 0); |
| 213 | | else |
| 214 | | // send stored port d data |
| 215 | | m_rx = ((m_data[2][m_count - 27] & (1 << m_bit)) ? 1 : 0); |
| 216 | | |
| 217 | | if(m_bit == 7) |
| 218 | | { |
| 219 | | // ports won't ack if they are done |
| 220 | | m_cack[0] = m_cack[1] = m_cack[2] = m_cack[3] = true; |
| 221 | | if(m_count < 11) |
| 222 | | m_ack_timer->adjust(attotime::from_usec(12), 0); // give a bit of time for the ports to ack |
| 223 | | else if(m_count < 35) |
| 224 | | m_ack_timer->adjust(attotime::from_usec(10), 0); |
| 225 | | } |
| 226 | | |
| 227 | | m_bit = (m_bit + 1) % 8; |
| 228 | | if(!m_bit) |
| 229 | | m_count++; |
| 230 | | } |
| 231 | | |
| 232 | | bool psx_multitap_device::get_pad(int count, UINT8 *odata, UINT8 idata) |
| 233 | | { |
| 234 | | if(!count) |
| 235 | | *odata = 0x80; |
| 236 | | else |
| 237 | | *odata = 0x5a; |
| 238 | | return true; |
| 239 | | } |
| 240 | | |
| 241 | | void psx_multitap_device::ack() |
| 242 | | { |
| 243 | | if(m_activeport != -1) |
| 244 | | { |
| 245 | | switch(m_activeport) |
| 246 | | { |
| 247 | | case 0: |
| 248 | | m_ack = m_porta->ack_r(); |
| 249 | | break; |
| 250 | | case 1: |
| 251 | | m_ack = m_portb->ack_r(); |
| 252 | | break; |
| 253 | | case 2: |
| 254 | | m_ack = m_portc->ack_r(); |
| 255 | | break; |
| 256 | | case 3: |
| 257 | | m_ack = m_portd->ack_r(); |
| 258 | | break; |
| 259 | | default: |
| 260 | | return; |
| 261 | | } |
| 262 | | device_psx_controller_interface::m_owner->ack(); |
| 263 | | return; |
| 264 | | } |
| 265 | | if(!m_porta->ack_r()) |
| 266 | | m_cack[0] = false; |
| 267 | | if(!m_portb->ack_r()) |
| 268 | | m_cack[1] = false; |
| 269 | | if(!m_portc->ack_r()) |
| 270 | | m_cack[2] = false; |
| 271 | | if(!m_portd->ack_r()) |
| 272 | | m_cack[3] = false; |
| 273 | | } |
trunk/src/mess/machine/psxmultitap.h
| r241419 | r241420 | |
| 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_ */ |