1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
|
// license:BSD-3-Clause
// copyright-holders:Fabio Priuli
/**********************************************************************
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.
**********************************************************************/
#include "emu.h"
#include "hori.h"
#include "joypad.h"
//**************************************************************************
// DEVICE DEFINITIONS
//**************************************************************************
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 4 Players Adaptor")
static INPUT_PORTS_START( nes_hori4p )
PORT_START("CONFIG")
PORT_CONFNAME( 0x01, 0x00, "4 Players / 2 Players")
PORT_CONFSETTING( 0x00, "2 Players" )
PORT_CONFSETTING( 0x01, "4 Players" )
INPUT_PORTS_END
//-------------------------------------------------
// input_ports - device-specific input ports
//-------------------------------------------------
ioport_constructor nes_hori4p_device::device_input_ports() const
{
return INPUT_PORTS_NAME( nes_hori4p );
}
static void hori_adapter(device_slot_interface &device)
{
device.option_add("joypad", NES_FCPAD_EXP);
}
//-------------------------------------------------
// device_add_mconfig - add device configuration
//-------------------------------------------------
void nes_horitwin_device::device_add_mconfig(machine_config &config)
{
for (int i = 0; i < 2; i++)
{
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)
{
for (int i = 0; i < 4; i++)
{
NES_CONTROL_PORT(config, m_subexp[i], hori_adapter, "joypad");
if (m_port != nullptr)
m_subexp[i]->set_screen_tag(m_port->m_screen);
}
}
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
//-------------------------------------------------
// nes_horitwin_device - constructor
//-------------------------------------------------
nes_horitwin_device::nes_horitwin_device(const machine_config &mconfig, const char *tag, device_t *owner, const XTAL &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, const XTAL &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")
{
}
//-------------------------------------------------
// 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();
}
//-------------------------------------------------
// read
//-------------------------------------------------
u8 nes_horitwin_device::read_exp(offs_t offset)
{
return m_subexp[offset]->read_exp(0);
}
u8 nes_hori4p_device::read_exp(offs_t offset)
{
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
{
int port = 2 * (BIT(m_count[offset], 3) & mode4p) + offset;
ret = m_subexp[port]->read_exp(0);
}
else // excess reads return a distinct signature byte on both $4016 and $4017
{
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;
}
//-------------------------------------------------
// write
//-------------------------------------------------
void nes_horitwin_device::write(u8 data)
{
m_subexp[0]->write(data);
m_subexp[1]->write(data);
}
void nes_hori4p_device::write(u8 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;
}
|