summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/nes_ctrl/arkpaddle.cpp
blob: 80e32c9307283b8180e1c65e55949fbc657c4166 (plain) (blame)
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
// license:BSD-3-Clause
// copyright-holders:Fabio Priuli
/**********************************************************************

    Nintendo Family Computer & Entertainment System -
    Arkanoid Paddle input device

 TODO: Investigate the differences between the 3 paddles released with
 Arkanoid (US), Arkanoid (JP), Arkanoid II (JP). At the moment we only
 emulate the US and daisy-chainable Famicom (Ark2) paddles.

 Known differences: NES and Ark2 paddles have screws to adjust range
 of returned values, Ark2 paddle has an extra expansion port.

 The Ark2 paddle's expansion port is NOT a passthru. OUT0 ($4016 bit 0)
 is passed along when writing. Pins 13 and 7 (normally read as bit 1
 from $4016 and $4017) are read from the daisy chained device and passed
 to the Famicom expansion port pins 5 and 4 (i.e. the Famicom sees them
 as bits 3,4 at $4017). Due to the limited pin connections the Famicom
 Keyboard cannot be daisy chained, so the Data Recorder cannot be used
 simultaneously with the paddle when saving and loading user made levels.

 All paddles return the ones' complement of a 9-bit value from their
 potentiometers, MSB first. The three commercial releases, Arkanoids
 and Chase HQ, only read 8-bits, ignoring the LSB.

**********************************************************************/

#include "emu.h"
#include "arkpaddle.h"

//**************************************************************************
//  DEVICE DEFINITIONS
//**************************************************************************

DEFINE_DEVICE_TYPE(NES_ARKPADDLE,    nes_vaus_device,   "nes_vaus",   "NES Arkanoid Vaus Controller")
DEFINE_DEVICE_TYPE(NES_ARKPADDLE_FC, nes_vausfc_device, "nes_vausfc", "FC Arkanoid Vaus Controller")


static INPUT_PORTS_START( arkanoid_paddle )
	PORT_START("PADDLE")
	// MINMAX range large enough to encompass what Taito games expect, Ark1 will glitch if MIN is too low
	// This may be too wide compared with real paddles, even accounting for those with adjustment screws
	PORT_BIT( 0x1ff, 0x130, IPT_PADDLE ) PORT_SENSITIVITY(50) PORT_KEYDELTA(35) PORT_CENTERDELTA(0) PORT_MINMAX(0x78, 0x1f8)

	PORT_START("BUTTON")
	PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Paddle button")
INPUT_PORTS_END


//-------------------------------------------------
//  input_ports - device-specific input ports
//-------------------------------------------------

ioport_constructor nes_vaus_device::device_input_ports() const
{
	return INPUT_PORTS_NAME( arkanoid_paddle );
}

static void vausfc_daisy(device_slot_interface &device)
{
	device.option_add("vaus", NES_ARKPADDLE_FC);
}


//-------------------------------------------------
//  device_add_mconfig - add device configuration
//-------------------------------------------------

void nes_vausfc_device::device_add_mconfig(machine_config &config)
{
	// expansion port to allow daisy chaining
	NES_CONTROL_PORT(config, m_daisychain, vausfc_daisy, nullptr);
	if (m_port != nullptr)
		m_daisychain->set_screen_tag(m_port->m_screen);
}


//**************************************************************************
//  LIVE DEVICE
//**************************************************************************

//-------------------------------------------------
//  nes_vaus_device - constructor
//-------------------------------------------------

nes_vaus_device::nes_vaus_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, const XTAL &clock)
	: device_t(mconfig, type, tag, owner, clock)
	, device_nes_control_port_interface(mconfig, *this)
	, m_paddle(*this, "PADDLE")
	, m_button(*this, "BUTTON")
	, m_latch(0)
{
}

nes_vaus_device::nes_vaus_device(const machine_config &mconfig, const char *tag, device_t *owner, const XTAL &clock)
	: nes_vaus_device(mconfig, NES_ARKPADDLE, tag, owner, clock)
{
}

nes_vausfc_device::nes_vausfc_device(const machine_config &mconfig, const char *tag, device_t *owner, const XTAL &clock)
	: nes_vaus_device(mconfig, NES_ARKPADDLE_FC, tag, owner, clock)
	, m_daisychain(*this, "subexp")
{
}


//-------------------------------------------------
//  device_start
//-------------------------------------------------

void nes_vaus_device::device_start()
{
	save_item(NAME(m_latch));
	save_item(NAME(m_strobe));
}


//-------------------------------------------------
//  read
//-------------------------------------------------

u8 nes_vaus_device::read_bit34()
{
	u8 ret = m_button->read() << 3;
	ret |= (m_latch & 0x100) >> 4;
	m_latch <<= 1;
	return ret;
}

u8 nes_vausfc_device::read_exp(offs_t offset)
{
	u8 ret;
	if (offset == 0)    //$4016
		ret = m_button->read() << 1;
	else    //$4017
	{
		ret = (m_latch & 0x100) >> 7;
		m_latch <<= 1;
		ret |= (m_daisychain->read_exp(0) & 0x02) << 2;
		ret |= (m_daisychain->read_exp(1) & 0x02) << 3;
	}
	return ret;
}

//-------------------------------------------------
//  write
//-------------------------------------------------

void nes_vaus_device::write(u8 data)
{
	if (write_strobe(data))
		m_latch = ~m_paddle->read();
}

void nes_vausfc_device::write(u8 data)
{
	m_daisychain->write(data & 1);
	nes_vaus_device::write(data);
}