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_ */ |