(mess) psxmultitap: add multitap support [Carl]

This commit is contained in:
cracyc 2013-05-06 00:09:10 +00:00
parent 579de8a428
commit b3150f804e
8 changed files with 351 additions and 4 deletions

2
.gitattributes vendored
View File

@ -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

View File

@ -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++)
{

View File

@ -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;

View File

@ -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 )

View File

@ -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; }

View 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;
}

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

View File

@ -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 \