1 // license:BSD-3-Clause
2 // copyright-holders:Phil Bennett
3 /***************************************************************************
4 
5     Fairlight Intelligent Alphanumeric Keyboard
6 
7     This ASCII serial keyboard was developed for Fairlight's Qasar System.
8     The output signals are driven at RS232 levels, though the connector is
9     custom.
10 
11 ***************************************************************************/
12 
13 #include "emu.h"
14 #include "cmi_ankbd.h"
15 
16 #include "cpu/m6800/m6800.h"
17 #include "machine/clock.h"
18 #include "machine/input_merger.h"
19 
20 DEFINE_DEVICE_TYPE(CMI_ALPHANUMERIC_KEYBOARD, cmi_alphanumeric_keyboard_device, "cmi_ankbd", "Fairlight Intelligent Alphanumeric Keyboard")
21 
cmi_alphanumeric_keyboard_device(const machine_config & mconfig,const char * tag,device_t * owner,u32 clock)22 cmi_alphanumeric_keyboard_device::cmi_alphanumeric_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
23 	: device_t(mconfig, CMI_ALPHANUMERIC_KEYBOARD, tag, owner, clock)
24 	, m_txd_handler(*this)
25 	, m_rts_handler(*this)
26 	, m_kbdcpu(*this, "kbdcpu")
27 	, m_pia(*this, "pia")
28 	, m_row_ports(*this, "ROW%u", 0)
29 {
30 }
31 
device_resolve_objects()32 void cmi_alphanumeric_keyboard_device::device_resolve_objects()
33 {
34 	m_txd_handler.resolve_safe();
35 	m_rts_handler.resolve_safe();
36 }
37 
device_start()38 void cmi_alphanumeric_keyboard_device::device_start()
39 {
40 }
41 
col_r()42 u8 cmi_alphanumeric_keyboard_device::col_r()
43 {
44 	int row = m_pia->b_output() ^ 0xff;
45 
46 	switch (row)
47 	{
48 		case 0x01: return m_row_ports[0]->read();
49 		case 0x02: return m_row_ports[1]->read();
50 		case 0x04: return m_row_ports[2]->read();
51 		case 0x08: return m_row_ports[3]->read();
52 		case 0x10: return m_row_ports[4]->read();
53 		case 0x20: return m_row_ports[5]->read();
54 		case 0x40: return m_row_ports[6]->read();
55 		case 0x80: return m_row_ports[7]->read();
56 		default:   return 0xff;
57 	}
58 }
59 
WRITE_LINE_MEMBER(cmi_alphanumeric_keyboard_device::rxd_w)60 WRITE_LINE_MEMBER( cmi_alphanumeric_keyboard_device::rxd_w )
61 {
62 	m_pia->cb2_w(state);
63 }
64 
WRITE_LINE_MEMBER(cmi_alphanumeric_keyboard_device::cts_w)65 WRITE_LINE_MEMBER( cmi_alphanumeric_keyboard_device::cts_w )
66 {
67 	m_pia->ca1_w(state);
68 }
69 
WRITE_LINE_MEMBER(cmi_alphanumeric_keyboard_device::txd_w)70 WRITE_LINE_MEMBER( cmi_alphanumeric_keyboard_device::txd_w )
71 {
72 	m_txd_handler(state);
73 }
74 
WRITE_LINE_MEMBER(cmi_alphanumeric_keyboard_device::rts_w)75 WRITE_LINE_MEMBER( cmi_alphanumeric_keyboard_device::rts_w )
76 {
77 	m_rts_handler(state);
78 }
79 
alphakeys_map(address_map & map)80 void cmi_alphanumeric_keyboard_device::alphakeys_map(address_map &map)
81 {
82 	map.unmap_value_high();
83 	map(0x4000, 0x7fff).portr("OPTIONS");
84 	map(0x8000, 0xbfff).rw(m_pia, FUNC(pia6821_device::read), FUNC(pia6821_device::write));
85 	map(0xc000, 0xc3ff).rom().mirror(0x3c00);
86 }
87 
88 static INPUT_PORTS_START( cmi_alphanumeric_keyboard )
89 	/* Alphanumeric keyboard */
90 	PORT_START("OPTIONS")
91 	PORT_DIPNAME( 0x07, 0x00, "Speed (baud)" )
92 	PORT_DIPSETTING(    0x00, "9600" )
93 	PORT_DIPSETTING(    0x01, "4800" )
94 	PORT_DIPSETTING(    0x02, "2400" )
95 	PORT_DIPSETTING(    0x03, "1200" )
96 	PORT_DIPSETTING(    0x04, "600"  )
97 	PORT_DIPSETTING(    0x05, "300"  )
98 	PORT_DIPSETTING(    0x06, "150"  )
99 	PORT_DIPSETTING(    0x07, "110"  )
100 
101 	PORT_DIPNAME( 0x30, 0x20, "Parity" )
102 	PORT_DIPSETTING(    0x00, "Even" )
103 	PORT_DIPSETTING(    0x10, "None, bit 7 is 0" )
104 	PORT_DIPSETTING(    0x20, "Odd" )
105 	PORT_DIPSETTING(    0x30, "None, bit 7 is 1" )
106 
107 	PORT_START("ROW0")
PORT_CODE(KEYCODE_2)108 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_2)                PORT_CHAR('2')
109 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_4)                PORT_CHAR('4')
110 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_6)                PORT_CHAR('6')
111 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_8)                PORT_CHAR('8')
112 	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS)            PORT_CHAR('-')
113 	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_PLUS_PAD)         PORT_CHAR('+')
114 	PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON)            PORT_CHAR(':')
115 	PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_9)                PORT_CHAR('9')
116 
117 	PORT_START("ROW1")
118 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_1)                PORT_CHAR('1')
119 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_3)                PORT_CHAR('3')
120 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_T)                PORT_CHAR('T')
121 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_U)                PORT_CHAR('U')
122 	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_RIGHT)            PORT_NAME("Right")
123 	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_UP)               PORT_NAME("Up")
124 	PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS_PAD)        PORT_CHAR('-')
125 	PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_0)                PORT_CHAR('0')
126 
127 	PORT_START("ROW2")
128 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ESC)              PORT_CHAR(UCHAR_MAMEKEY(ESC))
129 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_E)                PORT_CHAR('E')
130 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_5)                PORT_CHAR('5')
131 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_J)                PORT_CHAR('J')
132 	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD)                                     PORT_NAME("Set")
133 	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD)                                     PORT_NAME("Add")
134 	PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH)            PORT_CHAR('/')
135 	PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA)            PORT_CHAR(',')
136 
137 	PORT_START("ROW3")
138 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LSHIFT)           PORT_NAME("LShift")
139 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_X)                PORT_CHAR('X')
140 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_V)                PORT_CHAR('V')
141 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_N)                PORT_CHAR('N')
142 	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_DOWN)             PORT_NAME("Down")
143 	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD)                                     PORT_NAME("Clear")
144 	PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD)                                     PORT_NAME("WTF")
145 	PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_L)                PORT_CHAR('L')
146 
147 	PORT_START("ROW4")
148 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q)                PORT_CHAR('Q')
149 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_W)                PORT_CHAR('W')
150 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_G)                PORT_CHAR('G')
151 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_M)                PORT_CHAR('M')
152 	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS)           PORT_CHAR('=')
153 	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD)                                     PORT_NAME("Home")
154 	PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSPACE)        PORT_CHAR(8)
155 	PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_K)                PORT_CHAR('K')
156 
157 	PORT_START("ROW5")
158 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z)                PORT_CHAR('Z')
159 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_C)                PORT_CHAR('C')
160 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F)                PORT_CHAR('F')
161 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_7)                PORT_CHAR('7')
162 	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER)            PORT_NAME("Return (a)")
163 	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER)            PORT_NAME("Return (b)")
164 	PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_P)                PORT_CHAR('P')
165 	PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_I)                PORT_CHAR('I')
166 
167 	PORT_START("ROW6")
168 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_A)                PORT_CHAR('A')
169 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_D)                PORT_CHAR('D')
170 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_B)                PORT_CHAR('S')
171 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_H)                PORT_CHAR('H')
172 	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD)                                     PORT_NAME("Sub")
173 	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE)            PORT_CHAR(' ')
174 	PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_RSHIFT)           PORT_NAME("RShift")
175 	PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP)             PORT_CHAR('.')
176 
177 	PORT_START("ROW7")
178 	PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LCONTROL)
179 	PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_S)                PORT_CHAR('S')
180 	PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_R)                PORT_CHAR('R')
181 	PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y)                PORT_CHAR('Y')
182 	PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_UNUSED)
183 	PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LEFT)             PORT_NAME("Left")
184 	PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED)
185 	PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_O)                PORT_CHAR('O')
186 INPUT_PORTS_END
187 
188 ioport_constructor cmi_alphanumeric_keyboard_device::device_input_ports() const
189 {
190 	return INPUT_PORTS_NAME(cmi_alphanumeric_keyboard);
191 }
192 
device_add_mconfig(machine_config & config)193 void cmi_alphanumeric_keyboard_device::device_add_mconfig(machine_config &config)
194 {
195 	M6802(config, m_kbdcpu, 3.84_MHz_XTAL);
196 	m_kbdcpu->set_addrmap(AS_PROGRAM, &cmi_alphanumeric_keyboard_device::alphakeys_map);
197 
198 	INPUT_MERGER_ANY_HIGH(config, "irqs").output_handler().set_inputline(m_kbdcpu, M6802_IRQ_LINE);
199 
200 	PIA6821(config, m_pia);
201 	m_pia->readpa_handler().set(FUNC(cmi_alphanumeric_keyboard_device::col_r));
202 	m_pia->ca2_handler().set(FUNC(cmi_alphanumeric_keyboard_device::rts_w));
203 	m_pia->cb2_handler().set(FUNC(cmi_alphanumeric_keyboard_device::txd_w));
204 	m_pia->irqa_handler().set("irqs", FUNC(input_merger_device::in_w<0>));
205 	m_pia->irqb_handler().set("irqs", FUNC(input_merger_device::in_w<1>));
206 
207 	clock_device &pia_clock(CLOCK(config, "pia_clock", 3.84_MHz_XTAL / 4 / 100)); // E clock divided by MC14518
208 	pia_clock.signal_handler().set(m_pia, FUNC(pia6821_device::cb1_w));
209 }
210 
211 ROM_START( cmi_ankbd )
212 	// This dump has been trimmed to size from within a roughly 2x-bigger file. The actual size is known based
213 	// on the format apparently used by the dumping device.
214 	ROM_REGION( 0x10000, "kbdcpu", 0 )
CRC(b214fbe9)215 	ROM_LOAD( "cmikeys4.bin", 0xc000, 0x400, CRC(b214fbe9) SHA1(8c404f58ba3e5a50aa42f761e966c74374e96cc9) )
216 ROM_END
217 
218 const tiny_rom_entry *cmi_alphanumeric_keyboard_device::device_rom_region() const
219 {
220 	return ROM_NAME(cmi_ankbd);
221 }
222