mirror of
https://github.com/holub/mame
synced 2025-04-20 23:42:22 +03:00
(mess) psxmultitap: add multitap support [Carl]
This commit is contained in:
parent
579de8a428
commit
b3150f804e
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -7551,6 +7551,8 @@ src/mess/machine/psxcd.c svneol=native#text/plain
|
||||
src/mess/machine/psxcd.h svneol=native#text/plain
|
||||
src/mess/machine/psxcport.c svneol=native#text/plain
|
||||
src/mess/machine/psxcport.h svneol=native#text/plain
|
||||
src/mess/machine/psxmultitap.c svneol=native#text/plain
|
||||
src/mess/machine/psxmultitap.h svneol=native#text/plain
|
||||
src/mess/machine/radio86.c svneol=native#text/plain
|
||||
src/mess/machine/rm380z.c svneol=native#text/plain
|
||||
src/mess/machine/rmnimbus.c svneol=native#text/plain
|
||||
|
@ -51,6 +51,7 @@ void psxcard_device::device_start()
|
||||
m_ack_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(psxcard_device::ack_timer), this));
|
||||
|
||||
m_ack = true;
|
||||
m_disabled = false;
|
||||
|
||||
// save state registrations
|
||||
/* save_item(NAME(pkt));
|
||||
@ -95,7 +96,7 @@ bool psxcard_device::transfer(UINT8 to, UINT8 *from)
|
||||
switch (state)
|
||||
{
|
||||
case state_illegal:
|
||||
if ((to == 0x81) && is_loaded())
|
||||
if (is_loaded())
|
||||
{
|
||||
// printf("CARD: begin\n");
|
||||
state = state_command;
|
||||
@ -277,6 +278,12 @@ unsigned char psxcard_device::checksum_data(const unsigned char *buf, const unsi
|
||||
|
||||
bool psxcard_device::call_load()
|
||||
{
|
||||
if(m_disabled)
|
||||
{
|
||||
logerror("psxcard: port disabled\n");
|
||||
return IMAGE_INIT_FAIL;
|
||||
}
|
||||
|
||||
if(length() != card_size)
|
||||
return IMAGE_INIT_FAIL;
|
||||
return IMAGE_INIT_PASS;
|
||||
@ -287,6 +294,12 @@ bool psxcard_device::call_create(int format_type, option_resolution *format_opti
|
||||
UINT8 block[block_size];
|
||||
int i, ret;
|
||||
|
||||
if(m_disabled)
|
||||
{
|
||||
logerror("psxcard: port disabled\n");
|
||||
return IMAGE_INIT_FAIL;
|
||||
}
|
||||
|
||||
memset(block, '\0', block_size);
|
||||
for(i = 0; i < (card_size/block_size); i++)
|
||||
{
|
||||
|
@ -29,10 +29,13 @@ public:
|
||||
virtual bool call_load();
|
||||
virtual bool call_create(int format_type, option_resolution *format_options);
|
||||
|
||||
void disable(bool state) { m_disabled = state; if(state) unload(); }
|
||||
|
||||
private:
|
||||
unsigned char pkt[0x8b], pkt_ptr, pkt_sz, cmd;
|
||||
unsigned short addr;
|
||||
int state;
|
||||
bool m_disabled;
|
||||
|
||||
UINT8 m_odata;
|
||||
UINT8 m_idata;
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "machine/psxcport.h"
|
||||
#include "machine/psxanalog.h"
|
||||
#include "machine/psxmultitap.h"
|
||||
|
||||
const device_type PSX_CONTROLLER_PORT = &device_creator<psx_controller_port_device>;
|
||||
|
||||
@ -26,6 +27,14 @@ machine_config_constructor psx_controller_port_device::device_mconfig_additions(
|
||||
return MACHINE_CONFIG_NAME( psx_memory_card );
|
||||
}
|
||||
|
||||
void psx_controller_port_device::disable_card(bool state)
|
||||
{
|
||||
if(state)
|
||||
popmessage("Memory card port %s is disabled\n", m_card->brief_instance_name());
|
||||
|
||||
m_card->disable(state);
|
||||
}
|
||||
|
||||
const device_type PSXCONTROLLERPORTS = &device_creator<psxcontrollerports_device>;
|
||||
|
||||
psxcontrollerports_device::psxcontrollerports_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
|
||||
@ -42,10 +51,19 @@ void psxcontrollerports_device::device_start()
|
||||
psxsiodev_device::device_start();
|
||||
}
|
||||
|
||||
// add controllers to define so they can be connected to the multitap
|
||||
#define PSX_CONTROLLERS \
|
||||
SLOT_INTERFACE("digital_pad", PSX_STANDARD_CONTROLLER) \
|
||||
SLOT_INTERFACE("dualshock_pad", PSX_DUALSHOCK) \
|
||||
SLOT_INTERFACE("analog_joystick", PSX_ANALOG_JOYSTICK)
|
||||
|
||||
SLOT_INTERFACE_START(psx_controllers)
|
||||
SLOT_INTERFACE("digital_pad", PSX_STANDARD_CONTROLLER)
|
||||
SLOT_INTERFACE("dualshock_pad", PSX_DUALSHOCK)
|
||||
SLOT_INTERFACE("analog_joystick", PSX_ANALOG_JOYSTICK)
|
||||
PSX_CONTROLLERS
|
||||
SLOT_INTERFACE("multitap", PSX_MULTITAP)
|
||||
SLOT_INTERFACE_END
|
||||
|
||||
SLOT_INTERFACE_START(psx_controllers_nomulti)
|
||||
PSX_CONTROLLERS
|
||||
SLOT_INTERFACE_END
|
||||
|
||||
void psxcontrollerports_device::data_in( int data, int mask )
|
||||
|
@ -20,6 +20,7 @@ class psx_controller_port_device;
|
||||
|
||||
class device_psx_controller_interface : public device_slot_card_interface
|
||||
{
|
||||
friend class psx_multitap_device;
|
||||
public:
|
||||
device_psx_controller_interface(const machine_config &mconfig, device_t &device);
|
||||
virtual ~device_psx_controller_interface();
|
||||
@ -112,6 +113,8 @@ public:
|
||||
DECLARE_READ_LINE_MEMBER(ack_r) { return (m_dev?m_dev->ack_r():true) && m_card->ack_r(); }
|
||||
DECLARE_READ_LINE_MEMBER(tx_r) { return m_tx; }
|
||||
|
||||
void disable_card(bool status);
|
||||
|
||||
protected:
|
||||
virtual void device_start() {}
|
||||
virtual void device_reset() { m_tx = true; }
|
||||
|
266
src/mess/machine/psxmultitap.c
Normal file
266
src/mess/machine/psxmultitap.c
Normal file
@ -0,0 +1,266 @@
|
||||
// psx multitap emulation
|
||||
|
||||
#include "machine/psxmultitap.h"
|
||||
|
||||
const device_type PSX_MULTITAP = &device_creator<psx_multitap_device>;
|
||||
|
||||
psx_multitap_device::psx_multitap_device(const machine_config& mconfig, const char* tag, device_t* owner, UINT32 clock) :
|
||||
device_t(mconfig, PSX_MULTITAP, "Playstation Multitap", tag, owner, clock),
|
||||
device_psx_controller_interface(mconfig, *this),
|
||||
m_porta(*this, "a"),
|
||||
m_portb(*this, "b"),
|
||||
m_portc(*this, "c"),
|
||||
m_portd(*this, "d")
|
||||
{
|
||||
}
|
||||
|
||||
static MACHINE_CONFIG_FRAGMENT( psx_multitap )
|
||||
MCFG_PSX_CTRL_PORT_ADD("a", psx_controllers_nomulti, "digital_pad", NULL)
|
||||
MCFG_PSX_CTRL_PORT_ADD("b", psx_controllers_nomulti, NULL, NULL)
|
||||
MCFG_PSX_CTRL_PORT_ADD("c", psx_controllers_nomulti, NULL, NULL)
|
||||
MCFG_PSX_CTRL_PORT_ADD("d", psx_controllers_nomulti, NULL, NULL)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
machine_config_constructor psx_multitap_device::device_mconfig_additions() const
|
||||
{
|
||||
return MACHINE_CONFIG_NAME( psx_multitap );
|
||||
}
|
||||
|
||||
void psx_multitap_device::device_start()
|
||||
{
|
||||
m_porta->setup_ack_cb(psx_controller_port_device::void_cb(FUNC(psx_multitap_device::ack), this));
|
||||
m_portb->setup_ack_cb(psx_controller_port_device::void_cb(FUNC(psx_multitap_device::ack), this));
|
||||
m_portc->setup_ack_cb(psx_controller_port_device::void_cb(FUNC(psx_multitap_device::ack), this));
|
||||
m_portd->setup_ack_cb(psx_controller_port_device::void_cb(FUNC(psx_multitap_device::ack), this));
|
||||
m_nextmode = false;
|
||||
}
|
||||
|
||||
void psx_multitap_device::interface_pre_reset()
|
||||
{
|
||||
m_activeport = -1;
|
||||
m_singlemode = m_nextmode;
|
||||
m_tapmc = false;
|
||||
m_cack[0] = m_cack[1] = m_cack[2] = m_cack[3] = true;
|
||||
memset(m_data, 0xff, sizeof(m_data));
|
||||
m_porta->sel_w(false);
|
||||
m_portb->sel_w(false);
|
||||
m_portc->sel_w(false);
|
||||
m_portd->sel_w(false);
|
||||
m_porta->sel_w(true);
|
||||
m_portb->sel_w(true);
|
||||
m_portc->sel_w(true);
|
||||
m_portd->sel_w(true);
|
||||
device_psx_controller_interface::interface_pre_reset();
|
||||
}
|
||||
|
||||
void psx_multitap_device::set_tx_line(bool tx, int port)
|
||||
{
|
||||
psx_controller_port_device *dev;
|
||||
switch(port)
|
||||
{
|
||||
default:
|
||||
case 0:
|
||||
dev = m_porta;
|
||||
break;
|
||||
case 1:
|
||||
dev = m_portb;
|
||||
break;
|
||||
case 2:
|
||||
dev = m_portc;
|
||||
break;
|
||||
case 3:
|
||||
dev = m_portd;
|
||||
break;
|
||||
}
|
||||
dev->clock_w(1);
|
||||
dev->tx_w(tx);
|
||||
dev->clock_w(0);
|
||||
}
|
||||
|
||||
bool psx_multitap_device::get_rx_line(int port)
|
||||
{
|
||||
psx_controller_port_device *dev;
|
||||
switch(port)
|
||||
{
|
||||
default:
|
||||
case 0:
|
||||
dev = m_porta;
|
||||
break;
|
||||
case 1:
|
||||
dev = m_portb;
|
||||
break;
|
||||
case 2:
|
||||
dev = m_portc;
|
||||
break;
|
||||
case 3:
|
||||
dev = m_portd;
|
||||
break;
|
||||
}
|
||||
return dev->rx_r();
|
||||
}
|
||||
|
||||
void psx_multitap_device::do_pad()
|
||||
{
|
||||
bool tx = device_psx_controller_interface::m_owner->tx_r();
|
||||
|
||||
// we don't know which controller until after the first byte
|
||||
if((m_singlemode || m_tapmc) && (m_count >= 1))
|
||||
{
|
||||
if((m_count == 2) && !m_bit && !m_tapmc)
|
||||
m_nextmode = !tx;
|
||||
|
||||
set_tx_line(tx, m_activeport);
|
||||
m_rx = get_rx_line(m_activeport);
|
||||
m_bit = (m_bit + 1) % 8;
|
||||
if(!m_bit)
|
||||
m_count++;
|
||||
return;
|
||||
}
|
||||
|
||||
if(!m_count)
|
||||
{
|
||||
// first send the select byte to all devices until we know whether it's accessing
|
||||
// a controller or memcard
|
||||
if(!m_bit)
|
||||
{
|
||||
m_porta->sel_w(false);
|
||||
m_portb->sel_w(false);
|
||||
m_portc->sel_w(false);
|
||||
m_portd->sel_w(false);
|
||||
}
|
||||
device_psx_controller_interface::do_pad();
|
||||
set_tx_line(tx, 0);
|
||||
set_tx_line(tx, 1);
|
||||
set_tx_line(tx, 2);
|
||||
set_tx_line(tx, 3);
|
||||
if(!m_bit)
|
||||
{
|
||||
m_count = 1;
|
||||
m_tapmc = m_memcard;
|
||||
m_memcard = false; // make sure we still receive clocks
|
||||
if(m_singlemode || m_tapmc)
|
||||
{
|
||||
m_activeport = (m_idata & 0xf) - 1;
|
||||
m_porta->sel_w((m_activeport == 0) ? false : true);
|
||||
m_portb->sel_w((m_activeport == 1) ? false : true);
|
||||
m_portc->sel_w((m_activeport == 2) ? false : true);
|
||||
m_portd->sel_w((m_activeport == 3) ? false : true);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if(m_count <= 2)
|
||||
return device_psx_controller_interface::do_pad();
|
||||
else if(m_count < 11)
|
||||
{
|
||||
if((m_count == 3) && !m_bit)
|
||||
m_nextmode = !m_idata;
|
||||
|
||||
if((m_count < 5) && m_cack[0] && m_cack[1] && m_cack[2] && m_cack[3])
|
||||
return; // no acks? hang up.
|
||||
|
||||
// all of the ports are polled here, port a is passed though. the data
|
||||
// from the other ports is stored and can be retrieved at a much higher clock rate
|
||||
// don't poll a port that is inactive or done
|
||||
if(!m_cack[0])
|
||||
{
|
||||
set_tx_line(tx, 0);
|
||||
m_rx = m_porta->rx_r();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_rx = true;
|
||||
m_porta->sel_w(true);
|
||||
}
|
||||
|
||||
if(!m_cack[1])
|
||||
{
|
||||
set_tx_line(tx, 1);
|
||||
m_data[0][m_count - 3] &= ~(!m_portb->rx_r() << m_bit);
|
||||
}
|
||||
else
|
||||
m_portb->sel_w(true);
|
||||
|
||||
if(!m_cack[2])
|
||||
{
|
||||
set_tx_line(tx, 2);
|
||||
m_data[1][m_count - 3] &= ~(!m_portc->rx_r() << m_bit);
|
||||
}
|
||||
else
|
||||
m_portc->sel_w(true);
|
||||
|
||||
if(!m_cack[3])
|
||||
{
|
||||
set_tx_line(tx, 3);
|
||||
m_data[2][m_count - 3] &= ~(!m_portd->rx_r() << m_bit);
|
||||
}
|
||||
else
|
||||
m_portd->sel_w(true);
|
||||
}
|
||||
else if(m_count < 19)
|
||||
// send stored port b data
|
||||
m_rx = ((m_data[0][m_count - 11] & (1 << m_bit)) ? 1 : 0);
|
||||
else if(m_count < 27)
|
||||
// send stored port c data
|
||||
m_rx = ((m_data[1][m_count - 19] & (1 << m_bit)) ? 1 : 0);
|
||||
else
|
||||
// send stored port d data
|
||||
m_rx = ((m_data[2][m_count - 27] & (1 << m_bit)) ? 1 : 0);
|
||||
|
||||
if(m_bit == 7)
|
||||
{
|
||||
// ports won't ack if they are done
|
||||
m_cack[0] = m_cack[1] = m_cack[2] = m_cack[3] = true;
|
||||
if(m_count < 11)
|
||||
m_ack_timer->adjust(attotime::from_usec(12), 0); // give a bit of time for the ports to ack
|
||||
else if(m_count < 35)
|
||||
m_ack_timer->adjust(attotime::from_usec(10), 0);
|
||||
}
|
||||
|
||||
m_bit = (m_bit + 1) % 8;
|
||||
if(!m_bit)
|
||||
m_count++;
|
||||
}
|
||||
|
||||
bool psx_multitap_device::get_pad(int count, UINT8 *odata, UINT8 idata)
|
||||
{
|
||||
if(!count)
|
||||
*odata = 0x80;
|
||||
else
|
||||
*odata = 0x5a;
|
||||
return true;
|
||||
}
|
||||
|
||||
void psx_multitap_device::ack()
|
||||
{
|
||||
if(m_activeport != -1)
|
||||
{
|
||||
switch(m_activeport)
|
||||
{
|
||||
case 0:
|
||||
m_ack = m_porta->ack_r();
|
||||
break;
|
||||
case 1:
|
||||
m_ack = m_portb->ack_r();
|
||||
break;
|
||||
case 2:
|
||||
m_ack = m_portc->ack_r();
|
||||
break;
|
||||
case 3:
|
||||
m_ack = m_portd->ack_r();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
device_psx_controller_interface::m_owner->ack();
|
||||
return;
|
||||
}
|
||||
if(!m_porta->ack_r())
|
||||
m_cack[0] = false;
|
||||
if(!m_portb->ack_r())
|
||||
m_cack[1] = false;
|
||||
if(!m_portc->ack_r())
|
||||
m_cack[2] = false;
|
||||
if(!m_portd->ack_r())
|
||||
m_cack[3] = false;
|
||||
}
|
41
src/mess/machine/psxmultitap.h
Normal file
41
src/mess/machine/psxmultitap.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef PSXMULTITAP_H_
|
||||
#define PSXMULTITAP_H_
|
||||
|
||||
#include "machine/psxcport.h"
|
||||
|
||||
SLOT_INTERFACE_EXTERN(psx_controllers_nomulti);
|
||||
|
||||
class psx_multitap_device : public device_t,
|
||||
public device_psx_controller_interface
|
||||
{
|
||||
public:
|
||||
psx_multitap_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
virtual machine_config_constructor device_mconfig_additions() const;
|
||||
|
||||
protected:
|
||||
virtual void device_start();
|
||||
virtual void device_stop() { device_psx_controller_interface::m_owner->disable_card(false); }
|
||||
virtual void device_reset() { device_psx_controller_interface::m_owner->disable_card(true); }
|
||||
virtual void device_config_complete() { m_shortname = "psx_multitap"; }
|
||||
virtual void interface_pre_reset();
|
||||
|
||||
private:
|
||||
virtual bool get_pad(int count, UINT8 *odata, UINT8 idata);
|
||||
virtual void do_pad();
|
||||
void ack();
|
||||
void set_tx_line(bool tx, int port);
|
||||
bool get_rx_line(int port);
|
||||
|
||||
int m_activeport;
|
||||
bool m_cack[4];
|
||||
bool m_singlemode, m_nextmode, m_tapmc;
|
||||
UINT8 m_data[3][8]; // port a is passed though
|
||||
required_device<psx_controller_port_device> m_porta;
|
||||
required_device<psx_controller_port_device> m_portb;
|
||||
required_device<psx_controller_port_device> m_portc;
|
||||
required_device<psx_controller_port_device> m_portd;
|
||||
};
|
||||
|
||||
extern const device_type PSX_MULTITAP;
|
||||
|
||||
#endif /* PSXMULTITAP_H_ */
|
@ -1771,6 +1771,7 @@ $(MESSOBJ)/sony.a: \
|
||||
$(MESS_MACHINE)/psxcd.o \
|
||||
$(MESS_MACHINE)/psxcard.o \
|
||||
$(MESS_MACHINE)/psxanalog.o \
|
||||
$(MESS_MACHINE)/psxmultitap.o \
|
||||
$(MESS_DRIVERS)/pockstat.o \
|
||||
$(MESS_DRIVERS)/smc777.o \
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user