1 // license:BSD-3-Clause
2 // copyright-holders:Fabio Priuli
3 /**********************************************************************
4 
5     Mattel Intellivision Hand Controllers
6 
7 **********************************************************************/
8 
9 #include "emu.h"
10 #include "handctrl.h"
11 
12 //**************************************************************************
13 //  DEVICE DEFINITIONS
14 //**************************************************************************
15 
16 DEFINE_DEVICE_TYPE(INTV_HANDCTRL, intv_handctrl_device, "intv_handctrl", "Mattel Intellivision Hand Controller")
17 
18 
INPUT_PORTS_START(intv_handctrl)19 static INPUT_PORTS_START( intv_handctrl )
20 	PORT_START("KEYPAD")
21 	PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("1") PORT_CODE(KEYCODE_1_PAD)
22 	PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("2") PORT_CODE(KEYCODE_2_PAD)
23 	PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("3") PORT_CODE(KEYCODE_3_PAD)
24 	PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("4") PORT_CODE(KEYCODE_4_PAD)
25 	PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("5") PORT_CODE(KEYCODE_5_PAD)
26 	PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("6") PORT_CODE(KEYCODE_6_PAD)
27 	PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("7") PORT_CODE(KEYCODE_7_PAD)
28 	PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("8") PORT_CODE(KEYCODE_8_PAD)
29 	PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("9") PORT_CODE(KEYCODE_9_PAD)
30 	PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Clear") PORT_CODE(KEYCODE_DEL_PAD)
31 	PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("0") PORT_CODE(KEYCODE_0_PAD)
32 	PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Enter") PORT_CODE(KEYCODE_ENTER_PAD)
33 	PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Upper") PORT_PLAYER(1)
34 	PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Lower-Left") PORT_PLAYER(1)
35 	PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("Lower-Right") PORT_PLAYER(1)
36 	PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_UNUSED )
37 
38 	PORT_START("DISC_DG")
39 	PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_NAME("Up") PORT_PLAYER(1) PORT_CONDITION("OPTIONS",0x01,EQUALS,0x00)
40 	PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Up-Up-Right") PORT_CONDITION("OPTIONS",0x01,EQUALS,0x00)
41 	PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Up-Right") PORT_CONDITION("OPTIONS",0x01,EQUALS,0x00)
42 	PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Right-Up-Right") PORT_CONDITION("OPTIONS",0x01,EQUALS,0x00)
43 	PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_NAME("Right") PORT_PLAYER(1) PORT_CONDITION("OPTIONS",0x01,EQUALS,0x00)
44 	PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Right-Down-Right") PORT_CONDITION("OPTIONS",0x01,EQUALS,0x00)
45 	PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Down-Right") PORT_CONDITION("OPTIONS",0x01,EQUALS,0x00)
46 	PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Down-Down-Right") PORT_CONDITION("OPTIONS",0x01,EQUALS,0x00)
47 	PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_NAME("Down") PORT_PLAYER(1) PORT_CONDITION("OPTIONS",0x01,EQUALS,0x00)
48 	PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Down-Down-Left") PORT_CONDITION("OPTIONS",0x01,EQUALS,0x00)
49 	PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Down-Left") PORT_CONDITION("OPTIONS",0x01,EQUALS,0x00)
50 	PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Left-Down-Left") PORT_CONDITION("OPTIONS",0x01,EQUALS,0x00)
51 	PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_NAME("Left") PORT_PLAYER(1) PORT_CONDITION("OPTIONS",0x01,EQUALS,0x00)
52 	PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Left-Up-Left") PORT_CONDITION("OPTIONS",0x01,EQUALS,0x00)
53 	PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Up-Left") PORT_CONDITION("OPTIONS",0x01,EQUALS,0x00)
54 	PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Up-Up-Left") PORT_CONDITION("OPTIONS",0x01,EQUALS,0x00)
55 
56 	PORT_START("DISC_AN_X")
57 	PORT_BIT( 0xff, 0x50, IPT_AD_STICK_X ) PORT_NAME("X") PORT_MINMAX(0x00,0x9f) PORT_SENSITIVITY(100) PORT_KEYDELTA(0x50) PORT_CODE_DEC(KEYCODE_LEFT) PORT_CODE_INC(KEYCODE_RIGHT) PORT_PLAYER(1) PORT_CONDITION("OPTIONS",0x01,EQUALS,0x01)
58 
59 	PORT_START("DISC_AN_Y")
60 	PORT_BIT( 0xff, 0x50, IPT_AD_STICK_Y ) PORT_NAME("Y") PORT_MINMAX(0x00,0x9f) PORT_SENSITIVITY(100) PORT_KEYDELTA(0x50) PORT_CODE_DEC(KEYCODE_UP) PORT_CODE_INC(KEYCODE_DOWN) PORT_PLAYER(1) PORT_CONDITION("OPTIONS",0x01,EQUALS,0x01)
61 
62 
63 	PORT_START("OPTIONS")
64 	PORT_CONFNAME( 0x01, 0x01, "Controller Disc Emulation" )
65 	PORT_CONFSETTING(    0x00, "Digital" )
66 	PORT_CONFSETTING(    0x01, "Analog" )
67 INPUT_PORTS_END
68 
69 
70 //-------------------------------------------------
71 //  input_ports - device-specific input ports
72 //-------------------------------------------------
73 
74 ioport_constructor intv_handctrl_device::device_input_ports() const
75 {
76 	return INPUT_PORTS_NAME( intv_handctrl );
77 }
78 
79 
80 
81 //**************************************************************************
82 //  LIVE DEVICE
83 //**************************************************************************
84 
85 //-------------------------------------------------
86 //  intv_handctrl_device - constructor
87 //-------------------------------------------------
88 
intv_handctrl_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)89 intv_handctrl_device::intv_handctrl_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
90 	device_t(mconfig, INTV_HANDCTRL, tag, owner, clock),
91 	device_intv_control_port_interface(mconfig, *this),
92 	m_cfg(*this, "OPTIONS"),
93 	m_keypad(*this, "KEYPAD"),
94 	m_disc_dig(*this, "DISC_DG"),
95 	m_disc_anx(*this, "DISC_AN_X"),
96 	m_disc_any(*this, "DISC_AN_Y")
97 {
98 }
99 
100 
101 //-------------------------------------------------
102 //  device_start - device-specific startup
103 //-------------------------------------------------
104 
device_start()105 void intv_handctrl_device::device_start()
106 {
107 }
108 
109 
110 //-------------------------------------------------
111 //  device_reset - device-specific reset
112 //-------------------------------------------------
113 
device_reset()114 void intv_handctrl_device::device_reset()
115 {
116 }
117 
118 
119 //-------------------------------------------------
120 //  read_ctrl
121 //-------------------------------------------------
122 
read_ctrl()123 uint8_t intv_handctrl_device::read_ctrl()
124 {
125 	static const uint8_t keypad_table[] =
126 	{
127 		0xff, 0x3f, 0x9f, 0x5f, 0xd7, 0xb7, 0x77, 0xdb,
128 		0xbb, 0x7b, 0xdd, 0xbd, 0x7d, 0xde, 0xbe, 0x7e
129 	};
130 
131 	static const uint8_t disc_table[] =
132 	{
133 		0xf3, 0xe3, 0xe7, 0xf7, 0xf6, 0xe6, 0xee, 0xfe,
134 		0xfc, 0xec, 0xed, 0xfd, 0xf9, 0xe9, 0xeb, 0xfb
135 	};
136 
137 	static const uint8_t discyx_table[5][5] =
138 	{
139 		{ 0xe3, 0xf3, 0xfb, 0xeb, 0xe9 },
140 		{ 0xe7, 0xe3, 0xfb, 0xe9, 0xf9 },
141 		{ 0xf7, 0xf7, 0xff, 0xfd, 0xfd },
142 		{ 0xf6, 0xe6, 0xfe, 0xec, 0xed },
143 		{ 0xe6, 0xee, 0xfe, 0xfc, 0xec }
144 	};
145 
146 	int x, y;
147 	uint8_t res = 0xff;
148 
149 	/* keypad */
150 	x = m_keypad->read();
151 	for (int i = 0; i < 16; i++)
152 	{
153 		if (BIT(x, i))
154 			res &= keypad_table[i];
155 	}
156 
157 	switch (m_cfg->read() & 1)
158 	{
159 		/* disc == digital */
160 		case 0:
161 		default:
162 			x = m_disc_dig->read();
163 			for (int i = 0; i < 16; i++)
164 			{
165 				if (BIT(x, i))
166 					res &= disc_table[i];
167 			}
168 			break;
169 
170 		/* disc == _fake_ analog */
171 		case 1:
172 			x = m_disc_anx->read();
173 			y = m_disc_any->read();
174 			res &= discyx_table[y / 32][x / 32];
175 			break;
176 	}
177 
178 	return res;
179 }
180