diff options
Diffstat (limited to 'src/devices/bus/nes_ctrl/hori.cpp')
-rw-r--r-- | src/devices/bus/nes_ctrl/hori.cpp | 165 |
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; } |