summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/nes_ctrl/hori.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/nes_ctrl/hori.cpp')
-rw-r--r--src/devices/bus/nes_ctrl/hori.cpp165
1 files changed, 89 insertions, 76 deletions
diff --git a/src/devices/bus/nes_ctrl/hori.cpp b/src/devices/bus/nes_ctrl/hori.cpp
index 5c4f33c8ca9..7b1351af3fd 100644
--- a/src/devices/bus/nes_ctrl/hori.cpp
+++ b/src/devices/bus/nes_ctrl/hori.cpp
@@ -2,20 +2,25 @@
// copyright-holders:Fabio Priuli
/**********************************************************************
- Nintendo Family Computer Hori Twin (and 4P?) adapters
-
- Emulation of the 4Players adapter is quite pointless: if 2P mode
- (default mode) it behaves like a Hori Twin adapter, in 4P mode
- it has P1 and P2 inputs overwriting the inputs coming from the
- main controllers (possibly creating a bit of confusion, since
- you get 6 sets of inputs with only 4 acknowledged by the running
- system).
- For the moment we keep it available for documentation purposes.
-
- TODO: find out confirmation whether in 2P mode, inputs from joypads
- connected to the 4players adapter are really seen as P3 and P4 inputs.
- it seems the most reasonable setup (so that users with only 2
- external pads can use the adapter in 4P games), but one never knows...
+ Nintendo Family Computer Hori Twin and 4 Players adapters
+
+ In general these adapters work by reading pin 13 (the Famicom sees
+ this in memory location $4016, bit 1) of their subports. Other
+ input pins are not connected so various specialty controllers are
+ incompatible with these adapters.
+
+ The Hori Twin passes subport 1's input directly through to $4016
+ bit 1. It reroutes subport 2's to $4017 bit 1. Incidentally, HAL
+ released a device, Joypair, that should be functionally equivalent
+ to the Hori Twin.
+
+ The Hori 4 Players adapter has a 2/4 switch. In 2P mode it works
+ just like the Hori Twin. In 4P mode it still passes through joypad
+ reads to bit 1 of $4016 and $4017, but it operates like the NES Four
+ Score (which in fact uses a Hori PCB). Subport 1 then subport 3
+ inputs are passed serially to $4016 bit 1. Likewise subport 2 and 4
+ go to $4017 bit 1. A signature byte can be read from both locations
+ following this.
**********************************************************************/
@@ -28,7 +33,7 @@
//**************************************************************************
DEFINE_DEVICE_TYPE(NES_HORITWIN, nes_horitwin_device, "nes_horitwin", "FC Hori Twin Adapter")
-DEFINE_DEVICE_TYPE(NES_HORI4P, nes_hori4p_device, "nes_hori4p", "FC Hori 4P Adapter")
+DEFINE_DEVICE_TYPE(NES_HORI4P, nes_hori4p_device, "nes_hori4p", "FC Hori 4 Players Adaptor")
static INPUT_PORTS_START( nes_hori4p )
@@ -51,7 +56,7 @@ ioport_constructor nes_hori4p_device::device_input_ports() const
static void hori_adapter(device_slot_interface &device)
{
- device.option_add("joypad", NES_JOYPAD);
+ device.option_add("joypad", NES_FCPAD_EXP);
}
@@ -61,27 +66,21 @@ static void hori_adapter(device_slot_interface &device)
void nes_horitwin_device::device_add_mconfig(machine_config &config)
{
- NES_CONTROL_PORT(config, m_port1, hori_adapter, "joypad");
- NES_CONTROL_PORT(config, m_port2, hori_adapter, "joypad");
- if (m_port != nullptr)
+ for (int i = 0; i < 2; i++)
{
- m_port1->set_screen_tag(m_port->m_screen);
- m_port2->set_screen_tag(m_port->m_screen);
+ NES_CONTROL_PORT(config, m_subexp[i], hori_adapter, "joypad");
+ if (m_port != nullptr)
+ m_subexp[i]->set_screen_tag(m_port->m_screen);
}
}
void nes_hori4p_device::device_add_mconfig(machine_config &config)
{
- NES_CONTROL_PORT(config, m_port1, hori_adapter, "joypad");
- NES_CONTROL_PORT(config, m_port2, hori_adapter, "joypad");
- NES_CONTROL_PORT(config, m_port3, hori_adapter, "joypad");
- NES_CONTROL_PORT(config, m_port4, hori_adapter, "joypad");
- if (m_port != nullptr)
+ for (int i = 0; i < 4; i++)
{
- m_port1->set_screen_tag(m_port->m_screen);
- m_port2->set_screen_tag(m_port->m_screen);
- m_port3->set_screen_tag(m_port->m_screen);
- m_port4->set_screen_tag(m_port->m_screen);
+ NES_CONTROL_PORT(config, m_subexp[i], hori_adapter, "joypad");
+ if (m_port != nullptr)
+ m_subexp[i]->set_screen_tag(m_port->m_screen);
}
}
@@ -94,23 +93,33 @@ void nes_hori4p_device::device_add_mconfig(machine_config &config)
// nes_horitwin_device - constructor
//-------------------------------------------------
-nes_horitwin_device::nes_horitwin_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
- device_t(mconfig, NES_HORITWIN, tag, owner, clock),
- device_nes_control_port_interface(mconfig, *this),
- m_port1(*this, "port1"),
- m_port2(*this, "port2")
+nes_horitwin_device::nes_horitwin_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, NES_HORITWIN, tag, owner, clock)
+ , device_nes_control_port_interface(mconfig, *this)
+ , m_subexp(*this, "subexp%u", 0)
+{
+}
+
+nes_hori4p_device::nes_hori4p_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, NES_HORI4P, tag, owner, clock)
+ , device_nes_control_port_interface(mconfig, *this)
+ , m_subexp(*this, "subexp%u", 0)
+ , m_cfg(*this, "CONFIG")
{
}
-nes_hori4p_device::nes_hori4p_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
- device_t(mconfig, NES_HORI4P, tag, owner, clock),
- device_nes_control_port_interface(mconfig, *this),
- m_port1(*this, "port1"),
- m_port2(*this, "port2"),
- m_port3(*this, "port3"),
- m_port4(*this, "port4"),
- m_cfg(*this, "CONFIG")
+
+//-------------------------------------------------
+// device_start
+//-------------------------------------------------
+
+void nes_hori4p_device::device_start()
{
+ save_item(NAME(m_count));
+ save_item(NAME(m_sig));
+ save_item(NAME(m_strobe));
+
+ reset_regs();
}
@@ -118,39 +127,32 @@ nes_hori4p_device::nes_hori4p_device(const machine_config &mconfig, const char *
// read
//-------------------------------------------------
-uint8_t nes_horitwin_device::read_exp(offs_t offset)
+u8 nes_horitwin_device::read_exp(offs_t offset)
{
- uint8_t ret = 0;
- if (offset == 0) //$4016
- ret |= (m_port1->read_bit0() << 1);
- else //$4017
- ret |= (m_port2->read_bit0() << 1);
- return ret;
+ return m_subexp[offset]->read_exp(0);
}
-uint8_t nes_hori4p_device::read_exp(offs_t offset)
+u8 nes_hori4p_device::read_exp(offs_t offset)
{
- uint8_t ret = 0;
- if (m_cfg->read() == 0) // 2P
+ u8 ret = 0;
+ int mode4p = m_cfg->read();
+
+ if (m_strobe)
+ reset_regs();
+
+ if (m_count[offset] < 16 || !mode4p) // read from P1/P2 for first byte, P3/P4 for second byte if in 4P mode
{
- if (offset == 0) //$4016
- ret |= (m_port1->read_bit0() << 1);
- else //$4017
- ret |= (m_port2->read_bit0() << 1);
+ int port = 2 * (BIT(m_count[offset], 3) & mode4p) + offset;
+ ret = m_subexp[port]->read_exp(0);
}
- else // 4P
+ else // excess reads return a distinct signature byte on both $4016 and $4017
{
- if (offset == 0) //$4016
- {
- ret |= (m_port1->read_bit0() << 0);
- ret |= (m_port3->read_bit0() << 1);
- }
- else //$4017
- {
- ret |= (m_port2->read_bit0() << 0);
- ret |= (m_port4->read_bit0() << 1);
- }
+ ret = (m_sig[offset] & 1) << 1;
+ m_sig[offset] >>= 1;
+ m_sig[offset] |= 0x80; // reads beyond signature are always 1
}
+ m_count[offset]++;
+
return ret;
}
@@ -158,16 +160,27 @@ uint8_t nes_hori4p_device::read_exp(offs_t offset)
// write
//-------------------------------------------------
-void nes_horitwin_device::write(uint8_t data)
+void nes_horitwin_device::write(u8 data)
{
- m_port1->write(data);
- m_port2->write(data);
+ m_subexp[0]->write(data);
+ m_subexp[1]->write(data);
}
-void nes_hori4p_device::write(uint8_t data)
+void nes_hori4p_device::write(u8 data)
{
- m_port1->write(data);
- m_port2->write(data);
- m_port3->write(data);
- m_port4->write(data);
+ for (int i = 0; i < 4; i++)
+ m_subexp[i]->write(data);
+
+ if (write_strobe(data))
+ reset_regs();
+}
+
+void nes_hori4p_device::reset_regs()
+{
+ m_count[0] = 0;
+ m_count[1] = 0;
+
+ // signature third bytes returned in 4P mode, pair is flipped from what Four Score returns
+ m_sig[0] = 0x04;
+ m_sig[1] = 0x08;
}