1 /*
2  * Z80SIM  -  a Z80-CPU simulator
3  *
4  * Copyright (C) 2008-2020 by Udo Munk
5  *
6  * This module of the simulator contains the I/O simulation
7  * for an Altair 8800 system
8  *
9  * History:
10  * 20-OCT-08 first version finished
11  * 19-JAN-14 unused I/O ports need to return 00 and not FF
12  * 02-MAR-14 source cleanup and improvements
13  * 14-MAR-14 added Tarbell SD FDC and printer port
14  * 15-MAR-14 modified printer port for Tarbell CP/M 1.4 BIOS
15  * 23-MAR-14 added 10ms timer interrupt for Kildalls timekeeper PL/M program
16  * 16-JUL-14 unused I/O ports need to return FF, see survey.mac
17  * 18-JUL-14 completed all ports used, so that survey would find them
18  * 31-JAN-15 took over some improvements made for the Z-1 emulation
19  * 29-APR-15 added Cromemco DAZZLER to the machine
20  * 12-JUL-16 added 88-SIO to ports 0/1, also connected to tty
21  * 11-AUG-16 moved printer ports to 2/3, most software want it there
22  * 06-DEC-16 implemented status display and stepping for all machine cycles
23  * 26-FEB-17 implemented X11 keyboard for VDM
24  * 22-MAR-17 connected SIO 2 to UNIX domain socket
25  * 27-MAR-17 connected SIO 3 to UNIX domain socket
26  * 24-APR-18 cleanup
27  * 17-MAY-18 improved hardware control
28  * 08-JUN-18 moved hardware initialisation and reset to iosim
29  * 15-JUL-18 use logging
30  * 10-AUG-18 added MITS 88-DCDD floppy disk controller
31  * 08-OCT-19 (Mike Douglas) added OUT 161 trap to simbdos.c for host file I/O
32  */
33 
34 #include <unistd.h>
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <errno.h>
39 #include <signal.h>
40 #include <fcntl.h>
41 #include <sys/time.h>
42 #include "sim.h"
43 #include "simglb.h"
44 #include "simbdos.h"
45 #include "log.h"
46 #include "../../iodevices/unix_network.h"
47 #include "../../iodevices/altair-88-sio.h"
48 #include "../../iodevices/altair-88-2sio.h"
49 #include "../../iodevices/tarbell_fdc.h"
50 #include "../../iodevices/altair-88-dcdd.h"
51 #include "../../iodevices/cromemco-dazzler.h"
52 #include "../../iodevices/proctec-vdm.h"
53 #include "../../frontpanel/frontpanel.h"
54 #include "memory.h"
55 
56 /*
57  *	Forward declarations for I/O functions
58  */
59 static BYTE io_trap_in(void);
60 static void io_trap_out(BYTE);
61 static BYTE hwctl_in(void), fp_in(void);
62 static void hwctl_out(BYTE), fp_out(BYTE);
63 static BYTE lpt_status_in(void), lpt_data_in(void);
64 static void lpt_status_out(BYTE), lpt_data_out(BYTE);
65 static BYTE kbd_status_in(void), kbd_data_in(void);
66 
67 static void io_no_card_out(BYTE);
68 #if 0	/* currently not used */
69 static BYTE io_no_card_in(void);
70 #endif
71 
72 static const char *TAG = "IO";
73 
74 static int printer;		/* fd for file "printer.txt" */
75 struct unix_connectors ucons[NUMUSOC]; /* socket connections for SIO's */
76 BYTE hwctl_lock = 0xff;		/* lock status hardware control port */
77 
78 /*
79  *	This array contains function pointers for every
80  *	input I/O port (0 - 255), to do the required I/O.
81  */
82 BYTE (*port_in[256]) (void) = {
83 	altair_sio0_status_in,	/* port 0 */ /* SIO 0 connected to console */
84 	altair_sio0_data_in,	/* port 1 */ /*  "  */
85 	lpt_status_in,		/* port 2 */ /* printer status */
86 	lpt_data_in,		/* port 3 */ /* printer data */
87 	kbd_status_in,		/* port 4 */ /* status VDM keyboard */
88 	kbd_data_in,		/* port 5 */ /* data VDM keyboard */
89 	altair_sio3_status_in,	/* port 6 */ /* SIO 3 connected to socket */
90 	altair_sio3_data_in,	/* port 7 */ /*  "  */
91 	altair_dsk_status_in,	/* port 8 */ /* MITS 88-DCDD status */
92 	altair_dsk_sec_in,	/* port 9 */ /* MITS 88-DCDD sector position */
93 	altair_dsk_data_in,	/* port 10 *//* MITS 88-DCDD read data */
94 	io_trap_in,		/* port 11 */
95 	io_trap_in,		/* port 12 */
96 	io_trap_in,		/* port 13 */
97 	cromemco_dazzler_flags_in, /* port 14 */ /* Cromemco Dazzler */
98 	io_trap_in,		/* port 15 */
99 	altair_sio1_status_in,	/* port 16 */ /* SIO 1 connected to console */
100 	altair_sio1_data_in,	/* port 17 */ /*  "  */
101 	altair_sio2_status_in,	/* port 18 */ /* SIO 2 connected to socket */
102 	altair_sio2_data_in,	/* port 19 */ /*  "  */
103 	io_trap_in,		/* port 20 */
104 	io_trap_in,		/* port 21 */
105 	io_trap_in,		/* port 22 */
106 	io_trap_in,		/* port 23 */
107 	io_trap_in,		/* port 24 */
108 	io_trap_in,		/* port 25 */
109 	io_trap_in,		/* port 26 */
110 	io_trap_in,		/* port 27 */
111 	io_trap_in,		/* port 28 */
112 	io_trap_in,		/* port 29 */
113 	io_trap_in,		/* port 30 */
114 	io_trap_in,		/* port 31 */
115 	io_trap_in,		/* port 32 */
116 	io_trap_in,		/* port 33 */
117 	io_trap_in,		/* port 34 */
118 	io_trap_in,		/* port 35 */
119 	io_trap_in,		/* port 36 */
120 	io_trap_in,		/* port 37 */
121 	io_trap_in,		/* port 38 */
122 	io_trap_in,		/* port 39 */
123 	io_trap_in,		/* port 40 */
124 	io_trap_in,		/* port 41 */
125 	io_trap_in,		/* port 42 */
126 	io_trap_in,		/* port 43 */
127 	io_trap_in,		/* port 44 */
128 	io_trap_in,		/* port 45 */
129 	io_trap_in,		/* port 46 */
130 	io_trap_in,		/* port 47 */
131 	io_trap_in,		/* port 48 */
132 	io_trap_in,		/* port 49 */
133 	io_trap_in,		/* port 50 */
134 	io_trap_in,		/* port 51 */
135 	io_trap_in,		/* port 52 */
136 	io_trap_in,		/* port 53 */
137 	io_trap_in,		/* port 54 */
138 	io_trap_in,		/* port 55 */
139 	io_trap_in,		/* port 56 */
140 	io_trap_in,		/* port 57 */
141 	io_trap_in,		/* port 58 */
142 	io_trap_in,		/* port 59 */
143 	io_trap_in,		/* port 60 */
144 	io_trap_in,		/* port 61 */
145 	io_trap_in,		/* port 62 */
146 	io_trap_in,		/* port 63 */
147 	io_trap_in,		/* port 64 */
148 	io_trap_in,		/* port 65 */
149 	io_trap_in,		/* port 66 */
150 	io_trap_in,		/* port 67 */
151 	io_trap_in,		/* port 68 */
152 	io_trap_in,		/* port 69 */
153 	io_trap_in,		/* port 70 */
154 	io_trap_in,		/* port 71 */
155 	io_trap_in,		/* port 72 */
156 	io_trap_in,		/* port 73 */
157 	io_trap_in,		/* port 74 */
158 	io_trap_in,		/* port 75 */
159 	io_trap_in,		/* port 76 */
160 	io_trap_in,		/* port 77 */
161 	io_trap_in,		/* port 78 */
162 	io_trap_in,		/* port 79 */
163 	io_trap_in,		/* port 80 */
164 	io_trap_in,		/* port 81 */
165 	io_trap_in,		/* port 82 */
166 	io_trap_in,		/* port 83 */
167 	io_trap_in,		/* port 84 */
168 	io_trap_in,		/* port 85 */
169 	io_trap_in,		/* port 86 */
170 	io_trap_in,		/* port 87 */
171 	io_trap_in,		/* port 88 */
172 	io_trap_in,		/* port 89 */
173 	io_trap_in,		/* port 90 */
174 	io_trap_in,		/* port 91 */
175 	io_trap_in,		/* port 92 */
176 	io_trap_in,		/* port 93 */
177 	io_trap_in,		/* port 94 */
178 	io_trap_in,		/* port 95 */
179 	io_trap_in,		/* port 96 */
180 	io_trap_in,		/* port 97 */
181 	io_trap_in,		/* port 98 */
182 	io_trap_in,		/* port 99 */
183 	io_trap_in,		/* port 100 */
184 	io_trap_in,		/* port 101 */
185 	io_trap_in,		/* port 102 */
186 	io_trap_in,		/* port 103 */
187 	io_trap_in,		/* port 104 */
188 	io_trap_in,		/* port 105 */
189 	io_trap_in,		/* port 106 */
190 	io_trap_in,		/* port 107 */
191 	io_trap_in,		/* port 108 */
192 	io_trap_in,		/* port 109 */
193 	io_trap_in,		/* port 110 */
194 	io_trap_in,		/* port 111 */
195 	io_trap_in,		/* port 112 */
196 	io_trap_in,		/* port 113 */
197 	io_trap_in,		/* port 114 */
198 	io_trap_in,		/* port 115 */
199 	io_trap_in,		/* port 116 */
200 	io_trap_in,		/* port 117 */
201 	io_trap_in,		/* port 118 */
202 	io_trap_in,		/* port 119 */
203 	io_trap_in,		/* port 120 */
204 	io_trap_in,		/* port 121 */
205 	io_trap_in,		/* port 122 */
206 	io_trap_in,		/* port 123 */
207 	io_trap_in,		/* port 124 */
208 	io_trap_in,		/* port 125 */
209 	io_trap_in,		/* port 126 */
210 	io_trap_in,		/* port 127 */
211 	io_trap_in,		/* port 128 */
212 	io_trap_in,		/* port 129 */
213 	io_trap_in,		/* port 130 */
214 	io_trap_in,		/* port 131 */
215 	io_trap_in,		/* port 132 */
216 	io_trap_in,		/* port 133 */
217 	io_trap_in,		/* port 134 */
218 	io_trap_in,		/* port 135 */
219 	io_trap_in,		/* port 136 */
220 	io_trap_in,		/* port 137 */
221 	io_trap_in,		/* port 138 */
222 	io_trap_in,		/* port 139 */
223 	io_trap_in,		/* port 140 */
224 	io_trap_in,		/* port 141 */
225 	io_trap_in,		/* port 142 */
226 	io_trap_in,		/* port 143 */
227 	io_trap_in,		/* port 144 */
228 	io_trap_in,		/* port 145 */
229 	io_trap_in,		/* port 146 */
230 	io_trap_in,		/* port 147 */
231 	io_trap_in,		/* port 148 */
232 	io_trap_in,		/* port 149 */
233 	io_trap_in,		/* port 150 */
234 	io_trap_in,		/* port 151 */
235 	io_trap_in,		/* port 152 */
236 	io_trap_in,		/* port 153 */
237 	io_trap_in,		/* port 154 */
238 	io_trap_in,		/* port 155 */
239 	io_trap_in,		/* port 156 */
240 	io_trap_in,		/* port 157 */
241 	io_trap_in,		/* port 158 */
242 	io_trap_in,		/* port 159 */
243 	hwctl_in,		/* port 160 */	/* virtual hardware control */
244 	io_trap_in,		/* port 161 */
245 	io_trap_in,		/* port 162 */
246 	io_trap_in,		/* port 163 */
247 	io_trap_in,		/* port 164 */
248 	io_trap_in,		/* port 165 */
249 	io_trap_in,		/* port 166 */
250 	io_trap_in,		/* port 167 */
251 	io_trap_in,		/* port 168 */
252 	io_trap_in,		/* port 169 */
253 	io_trap_in,		/* port 170 */
254 	io_trap_in,		/* port 171 */
255 	io_trap_in,		/* port 172 */
256 	io_trap_in,		/* port 173 */
257 	io_trap_in,		/* port 174 */
258 	io_trap_in,		/* port 175 */
259 	io_trap_in,		/* port 176 */
260 	io_trap_in,		/* port 177 */
261 	io_trap_in,		/* port 178 */
262 	io_trap_in,		/* port 179 */
263 	io_trap_in,		/* port 180 */
264 	io_trap_in,		/* port 181 */
265 	io_trap_in,		/* port 182 */
266 	io_trap_in,		/* port 183 */
267 	io_trap_in,		/* port 184 */
268 	io_trap_in,		/* port 185 */
269 	io_trap_in,		/* port 186 */
270 	io_trap_in,		/* port 187 */
271 	io_trap_in,		/* port 188 */
272 	io_trap_in,		/* port 189 */
273 	io_trap_in,		/* port 190 */
274 	io_trap_in,		/* port 191 */
275 	io_trap_in,		/* port 192 */
276 	io_trap_in,		/* port 193 */
277 	io_trap_in,		/* port 194 */
278 	io_trap_in,		/* port 195 */
279 	io_trap_in,		/* port 196 */
280 	io_trap_in,		/* port 197 */
281 	io_trap_in,		/* port 198 */
282 	io_trap_in,		/* port 199 */
283 	io_trap_in,		/* port 200 */
284 	io_trap_in,		/* port 201 */
285 	io_trap_in,		/* port 202 */
286 	io_trap_in,		/* port 203 */
287 	io_trap_in,		/* port 204 */
288 	io_trap_in,		/* port 205 */
289 	io_trap_in,		/* port 206 */
290 	io_trap_in,		/* port 207 */
291 	io_trap_in,		/* port 208 */
292 	io_trap_in,		/* port 209 */
293 	io_trap_in,		/* port 210 */
294 	io_trap_in,		/* port 211 */
295 	io_trap_in,		/* port 212 */
296 	io_trap_in,		/* port 213 */
297 	io_trap_in,		/* port 214 */
298 	io_trap_in,		/* port 215 */
299 	io_trap_in,		/* port 216 */
300 	io_trap_in,		/* port 217 */
301 	io_trap_in,		/* port 218 */
302 	io_trap_in,		/* port 219 */
303 	io_trap_in,		/* port 220 */
304 	io_trap_in,		/* port 221 */
305 	io_trap_in,		/* port 222 */
306 	io_trap_in,		/* port 223 */
307 	io_trap_in,		/* port 224 */
308 	io_trap_in,		/* port 225 */
309 	io_trap_in,		/* port 226 */
310 	io_trap_in,		/* port 227 */
311 	io_trap_in,		/* port 228 */
312 	io_trap_in,		/* port 229 */
313 	io_trap_in,		/* port 230 */
314 	io_trap_in,		/* port 231 */
315 	io_trap_in,		/* port 232 */
316 	io_trap_in,		/* port 233 */
317 	io_trap_in,		/* port 234 */
318 	io_trap_in,		/* port 235 */
319 	io_trap_in,		/* port 236 */
320 	io_trap_in,		/* port 237 */
321 	io_trap_in,		/* port 238 */
322 	io_trap_in,		/* port 239 */
323 	io_trap_in,		/* port 240 */
324 	io_trap_in,		/* port 241 */
325 	io_trap_in,		/* port 242 */
326 	io_trap_in,		/* port 243 */
327 	io_trap_in,		/* port 244 */
328 	io_trap_in,		/* port 245 */
329 	io_trap_in,		/* port 246 */
330 	io_trap_in,		/* port 247 */
331 	tarbell_stat_in,	/* port 248 */ /* Tarbell 1011D status */
332 	tarbell_track_in,	/* port 249 */ /* Tarbell 1011D track */
333 	tarbell_sec_in,		/* port 250 */ /* Tarbell 1011D sector */
334 	tarbell_data_in,	/* port 251 */ /* Tarbell 1011D data */
335 	tarbell_wait_in,	/* port 252 */ /* Tarbell 1011D wait */
336 	io_trap_in,		/* port 253 */
337 	io_trap_in,		/* port 254 */
338 	fp_in			/* port 255 */ /* frontpanel */
339 };
340 
341 /*
342  *	This array contains function pointers for every
343  *	output I/O port (0 - 255), to do the required I/O.
344  */
345 static void (*port_out[256]) (BYTE) = {
346 	altair_sio0_status_out,	/* port 0 */ /* SIO 0 connected to console */
347 	altair_sio0_data_out,	/* port 1 */ /*  "  */
348 	lpt_status_out,		/* port 2 */ /* printer status */
349 	lpt_data_out,		/* port 3 */ /* printer data */
350 	io_no_card_out,		/* port 4 */ /* status VDM keyboard */
351 	io_no_card_out,		/* port 5 */ /* data VDM keyboard */
352 	altair_sio3_status_out,	/* port 6 */ /* SIO 3 connected to socket */
353 	altair_sio3_data_out,	/* port 7 */ /*  "  */
354 	altair_dsk_select_out,	/* port 8 */ /* MITS 88-DCDD disk select */
355 	altair_dsk_control_out,	/* port 9 */ /* MITS 88-DCDD control disk */
356 	altair_dsk_data_out,	/* port 10 *//* MITS 88-DCDD write data */
357 	io_trap_out,		/* port 11 */
358 	io_trap_out,		/* port 12 */
359 	io_trap_out,		/* port 13 */
360 	cromemco_dazzler_ctl_out,	/* port 14 */ /* Cromemco Dazzler */
361 	cromemco_dazzler_format_out,	/* port 15 */ /*  "  */
362 	altair_sio1_status_out,	/* port 16 */ /* SIO 1 connected to console */
363 	altair_sio1_data_out,	/* port 17 */
364 	altair_sio2_status_out,	/* port 18 */ /* SIO 2 connected to socket */
365 	altair_sio2_data_out,	/* port 19 */ /*  "  */
366 	io_trap_out,		/* port 20 */
367 	io_trap_out,		/* port 21 */
368 	io_trap_out,		/* port 22 */
369 	io_trap_out,		/* port 23 */
370 	io_trap_out,		/* port 24 */
371 	io_trap_out,		/* port 25 */
372 	io_trap_out,		/* port 26 */
373 	io_trap_out,		/* port 27 */
374 	io_trap_out,		/* port 28 */
375 	io_trap_out,		/* port 29 */
376 	io_trap_out,		/* port 30 */
377 	io_trap_out,		/* port 31 */
378 	io_trap_out,		/* port 32 */
379 	io_trap_out,		/* port 33 */
380 	io_trap_out,		/* port 34 */
381 	io_trap_out,		/* port 35 */
382 	io_trap_out,		/* port 36 */
383 	io_trap_out,		/* port 37 */
384 	io_trap_out,		/* port 38 */
385 	io_trap_out,		/* port 39 */
386 	io_trap_out,		/* port 40 */
387 	io_trap_out,		/* port 41 */
388 	io_trap_out,		/* port 42 */
389 	io_trap_out,		/* port 43 */
390 	io_trap_out,		/* port 44 */
391 	io_trap_out,		/* port 45 */
392 	io_trap_out,		/* port 46 */
393 	io_trap_out,		/* port 47 */
394 	io_trap_out,		/* port 48 */
395 	io_trap_out,		/* port 49 */
396 	io_trap_out,		/* port 50 */
397 	io_trap_out,		/* port 51 */
398 	io_trap_out,		/* port 52 */
399 	io_trap_out,		/* port 53 */
400 	io_trap_out,		/* port 54 */
401 	io_trap_out,		/* port 55 */
402 	io_trap_out,		/* port 56 */
403 	io_trap_out,		/* port 57 */
404 	io_trap_out,		/* port 58 */
405 	io_trap_out,		/* port 59 */
406 	io_trap_out,		/* port 60 */
407 	io_trap_out,		/* port 61 */
408 	io_trap_out,		/* port 62 */
409 	io_trap_out,		/* port 63 */
410 	io_trap_out,		/* port 64 */
411 	io_trap_out,		/* port 65 */
412 	io_trap_out,		/* port 66 */
413 	io_trap_out,		/* port 67 */
414 	io_trap_out,		/* port 68 */
415 	io_trap_out,		/* port 69 */
416 	io_trap_out,		/* port 70 */
417 	io_trap_out,		/* port 71 */
418 	io_trap_out,		/* port 72 */
419 	io_trap_out,		/* port 73 */
420 	io_trap_out,		/* port 74 */
421 	io_trap_out,		/* port 75 */
422 	io_trap_out,		/* port 76 */
423 	io_trap_out,		/* port 77 */
424 	io_trap_out,		/* port 78 */
425 	io_trap_out,		/* port 79 */
426 	io_trap_out,		/* port 80 */
427 	io_trap_out,		/* port 81 */
428 	io_trap_out,		/* port 82 */
429 	io_trap_out,		/* port 83 */
430 	io_trap_out,		/* port 84 */
431 	io_trap_out,		/* port 85 */
432 	io_trap_out,		/* port 86 */
433 	io_trap_out,		/* port 87 */
434 	io_trap_out,		/* port 88 */
435 	io_trap_out,		/* port 89 */
436 	io_trap_out,		/* port 90 */
437 	io_trap_out,		/* port 91 */
438 	io_trap_out,		/* port 92 */
439 	io_trap_out,		/* port 93 */
440 	io_trap_out,		/* port 94 */
441 	io_trap_out,		/* port 95 */
442 	io_trap_out,		/* port 96 */
443 	io_trap_out,		/* port 97 */
444 	io_trap_out,		/* port 98 */
445 	io_trap_out,		/* port 99 */
446 	io_trap_out,		/* port 100 */
447 	io_trap_out,		/* port 101 */
448 	io_trap_out,		/* port 102 */
449 	io_trap_out,		/* port 103 */
450 	io_trap_out,		/* port 104 */
451 	io_trap_out,		/* port 105 */
452 	io_trap_out,		/* port 106 */
453 	io_trap_out,		/* port 107 */
454 	io_trap_out,		/* port 108 */
455 	io_trap_out,		/* port 109 */
456 	io_trap_out,		/* port 110 */
457 	io_trap_out,		/* port 111 */
458 	io_trap_out,		/* port 112 */
459 	io_trap_out,		/* port 113 */
460 	io_trap_out,		/* port 114 */
461 	io_trap_out,		/* port 115 */
462 	io_trap_out,		/* port 116 */
463 	io_trap_out,		/* port 117 */
464 	io_trap_out,		/* port 118 */
465 	io_trap_out,		/* port 119 */
466 	io_trap_out,		/* port 120 */
467 	io_trap_out,		/* port 121 */
468 	io_trap_out,		/* port 122 */
469 	io_trap_out,		/* port 123 */
470 	io_trap_out,		/* port 124 */
471 	io_trap_out,		/* port 125 */
472 	io_trap_out,		/* port 126 */
473 	io_trap_out,		/* port 127 */
474 	io_trap_out,		/* port 128 */
475 	io_trap_out,		/* port 129 */
476 	io_trap_out,		/* port 130 */
477 	io_trap_out,		/* port 131 */
478 	io_trap_out,		/* port 132 */
479 	io_trap_out,		/* port 133 */
480 	io_trap_out,		/* port 134 */
481 	io_trap_out,		/* port 135 */
482 	io_trap_out,		/* port 136 */
483 	io_trap_out,		/* port 137 */
484 	io_trap_out,		/* port 138 */
485 	io_trap_out,		/* port 139 */
486 	io_trap_out,		/* port 140 */
487 	io_trap_out,		/* port 141 */
488 	io_trap_out,		/* port 142 */
489 	io_trap_out,		/* port 143 */
490 	io_trap_out,		/* port 144 */
491 	io_trap_out,		/* port 145 */
492 	io_trap_out,		/* port 146 */
493 	io_trap_out,		/* port 147 */
494 	io_trap_out,		/* port 148 */
495 	io_trap_out,		/* port 149 */
496 	io_trap_out,		/* port 150 */
497 	io_trap_out,		/* port 151 */
498 	io_trap_out,		/* port 152 */
499 	io_trap_out,		/* port 153 */
500 	io_trap_out,		/* port 154 */
501 	io_trap_out,		/* port 155 */
502 	io_trap_out,		/* port 156 */
503 	io_trap_out,		/* port 157 */
504 	io_trap_out,		/* port 158 */
505 	io_trap_out,		/* port 159 */
506 	hwctl_out,		/* port 160 */	/* virtual hardware control */
507 	host_bdos_out,		/* port 161 */  /* host file I/O hook */
508 	io_trap_out,		/* port 162 */
509 	io_trap_out,		/* port 163 */
510 	io_trap_out,		/* port 164 */
511 	io_trap_out,		/* port 165 */
512 	io_trap_out,		/* port 166 */
513 	io_trap_out,		/* port 167 */
514 	io_trap_out,		/* port 168 */
515 	io_trap_out,		/* port 169 */
516 	io_trap_out,		/* port 170 */
517 	io_trap_out,		/* port 171 */
518 	io_trap_out,		/* port 172 */
519 	io_trap_out,		/* port 173 */
520 	io_trap_out,		/* port 174 */
521 	io_trap_out,		/* port 175 */
522 	io_trap_out,		/* port 176 */
523 	io_trap_out,		/* port 177 */
524 	io_trap_out,		/* port 178 */
525 	io_trap_out,		/* port 179 */
526 	io_trap_out,		/* port 180 */
527 	io_trap_out,		/* port 181 */
528 	io_trap_out,		/* port 182 */
529 	io_trap_out,		/* port 183 */
530 	io_trap_out,		/* port 184 */
531 	io_trap_out,		/* port 185 */
532 	io_trap_out,		/* port 186 */
533 	io_trap_out,		/* port 187 */
534 	io_trap_out,		/* port 188 */
535 	io_trap_out,		/* port 189 */
536 	io_trap_out,		/* port 190 */
537 	io_trap_out,		/* port 191 */
538 	io_trap_out,		/* port 192 */
539 	io_trap_out,		/* port 193 */
540 	io_trap_out,		/* port 194 */
541 	io_trap_out,		/* port 195 */
542 	io_trap_out,		/* port 196 */
543 	io_trap_out,		/* port 197 */
544 	io_trap_out,		/* port 198 */
545 	io_trap_out,		/* port 199 */
546 	proctec_vdm_out,	/* port 200 */ /* Processor Technology VDM */
547 	io_trap_out,		/* port 201 */
548 	io_trap_out,		/* port 202 */
549 	io_trap_out,		/* port 203 */
550 	io_trap_out,		/* port 204 */
551 	io_trap_out,		/* port 205 */
552 	io_trap_out,		/* port 206 */
553 	io_trap_out,		/* port 207 */
554 	io_trap_out,		/* port 208 */
555 	io_trap_out,		/* port 209 */
556 	io_trap_out,		/* port 210 */
557 	io_trap_out,		/* port 211 */
558 	io_trap_out,		/* port 212 */
559 	io_trap_out,		/* port 213 */
560 	io_trap_out,		/* port 214 */
561 	io_trap_out,		/* port 215 */
562 	io_trap_out,		/* port 216 */
563 	io_trap_out,		/* port 217 */
564 	io_trap_out,		/* port 218 */
565 	io_trap_out,		/* port 219 */
566 	io_trap_out,		/* port 220 */
567 	io_trap_out,		/* port 221 */
568 	io_trap_out,		/* port 222 */
569 	io_trap_out,		/* port 223 */
570 	io_trap_out,		/* port 224 */
571 	io_trap_out,		/* port 225 */
572 	io_trap_out,		/* port 226 */
573 	io_trap_out,		/* port 227 */
574 	io_trap_out,		/* port 228 */
575 	io_trap_out,		/* port 229 */
576 	io_trap_out,		/* port 230 */
577 	io_trap_out,		/* port 231 */
578 	io_trap_out,		/* port 232 */
579 	io_trap_out,		/* port 233 */
580 	io_trap_out,		/* port 234 */
581 	io_trap_out,		/* port 235 */
582 	io_trap_out,		/* port 236 */
583 	io_trap_out,		/* port 237 */
584 	io_trap_out,		/* port 238 */
585 	io_trap_out,		/* port 239 */
586 	io_trap_out,		/* port 240 */
587 	io_trap_out,		/* port 241 */
588 	io_trap_out,		/* port 242 */
589 	io_trap_out,		/* port 243 */
590 	io_trap_out,		/* port 244 */
591 	io_trap_out,		/* port 245 */
592 	io_trap_out,		/* port 246 */
593 	io_trap_out,		/* port 247 */
594 	tarbell_cmd_out,	/* port 248 */ /* Tarbell 1011D command */
595 	tarbell_track_out,	/* port 249 */ /* Tarbell 1011D track */
596 	tarbell_sec_out,	/* port 250 */ /* Tarbell 1011D sector */
597 	tarbell_data_out,	/* port 251 */ /* Tarbell 1011D data */
598 	tarbell_ext_out,	/* port 252 */ /* Tarbell 1011D extended cmd */
599 	io_trap_out,		/* port 253 */
600 	io_trap_out,		/* port 254 */
601 	fp_out			/* port 255 */ /* front panel */
602 };
603 
604 /*
605  *	This function is to initiate the I/O devices.
606  *	It will be called from the CPU simulation before
607  *	any operation with the CPU is possible.
608  */
init_io(void)609 void init_io(void)
610 {
611 	/* create local sockets */
612 	init_unix_server_socket(&ucons[0], "altairsim.tape");
613 	init_unix_server_socket(&ucons[1], "altairsim.sio2");
614 }
615 
616 /*
617  *	This function is to stop the I/O devices. It is
618  *	called from the CPU simulation on exit.
619  */
exit_io(void)620 void exit_io(void)
621 {
622 	register int i;
623 
624 	/* close line printer file */
625 	if (printer != 0)
626 		close(printer);
627 
628 	/* close network connections */
629 	for (i = 0; i < NUMUSOC; i++) {
630 		if (ucons[i].ssc)
631 			close(ucons[i].ssc);
632 	}
633 
634 	/* shutdown DAZZLER */
635 	cromemco_dazzler_off();
636 
637 	/* shutdown VDM */
638 	proctec_vdm_off();
639 }
640 
641 /*
642  *	This function is to reset the I/O devices. It is
643  *	called from the CPU simulation when an External Clear is performed.
644  */
reset_io(void)645 void reset_io(void)
646 {
647 	cromemco_dazzler_off();
648 	tarbell_reset();
649 	altair_dsk_reset();
650 	hwctl_lock = 0xff;
651 }
652 
653 /*
654  *	This is the main handler for all IN op-codes,
655  *	called by the simulator. It calls the input
656  *	function for port addr.
657  */
io_in(BYTE addrl,BYTE addrh)658 BYTE io_in(BYTE addrl, BYTE addrh)
659 {
660 	int val;
661 
662 	io_port = addrl;
663 	io_data = (*port_in[addrl]) ();
664 
665 	cpu_bus = CPU_WO | CPU_INP;
666 
667 	fp_clock += 3;
668 	fp_led_address = (addrh << 8) + addrl;
669 	fp_led_data = io_data;
670 	fp_sampleData();
671 	val = wait_step();
672 
673 	/* when single stepped INP get last set value of port */
674 	if (val)
675 		io_data = (*port_in[io_port]) ();
676 
677 	return(io_data);
678 }
679 
680 /*
681  *	This is the main handler for all OUT op-codes,
682  *	called by the simulator. It calls the output
683  *	function for port addr.
684  */
io_out(BYTE addrl,BYTE addrh,BYTE data)685 void io_out(BYTE addrl, BYTE addrh, BYTE data)
686 {
687 	io_port = addrl;
688 	io_data = data;
689 	(*port_out[addrl]) (data);
690 
691 	cpu_bus = CPU_OUT;
692 
693 	fp_clock += 6;
694 	fp_led_address = (addrh << 8) + addrl;
695 	fp_led_data = 0xff;
696 	fp_sampleData();
697 	wait_step();
698 }
699 
700 /*
701  *	I/O input trap function
702  *	This function should be added into all unused
703  *	entries of the input port array. It can stop the
704  *	emulation with an I/O error.
705  */
io_trap_in(void)706 static BYTE io_trap_in(void)
707 {
708 	if (i_flag) {
709 		cpu_error = IOTRAPIN;
710 		cpu_state = STOPPED;
711 	}
712 	return((BYTE) 0xff);
713 }
714 
715 #if 0		/* currently not used */
716 /*
717  *	Same as above, but don't trap as I/O error.
718  *	Used for input ports where I/O cards might be
719  *	installed, but haven't.
720  */
721 static BYTE io_no_card_in(void)
722 {
723 	return((BYTE) 0xff);
724 }
725 #endif
726 
727 /*
728  *      I/O output trap function
729  *      This function should be added into all unused
730  *      entries of the output port array. It can stop the
731  *      emulation with an I/O error.
732  */
io_trap_out(BYTE data)733 static void io_trap_out(BYTE data)
734 {
735 	data = data; /* to avoid compiler warning */
736 
737 	if (i_flag) {
738 		cpu_error = IOTRAPOUT;
739 		cpu_state = STOPPED;
740 	}
741 }
742 
743 /*
744  *	Same as above, but don't trap as I/O error.
745  *	Used for output ports where I/O cards might be
746  *	installed, but haven't.
747  */
io_no_card_out(BYTE data)748 static void io_no_card_out(BYTE data)
749 {
750 	data = data; /* to avoid compiler warning */
751 }
752 
753 /*
754  *	Read input from front panel switches
755  */
fp_in(void)756 static BYTE fp_in(void)
757 {
758 	return(address_switch >> 8);
759 }
760 
761 /*
762  *	Ouput to front panel switch port won't do anything
763  */
fp_out(BYTE data)764 static void fp_out(BYTE data)
765 {
766 	data = data; /* to avoid compiler warning */
767 }
768 
769 /*
770  *	timer interrupt causes RST 38 in IM 0 and IM 1
771  */
int_timer(int sig)772 static void int_timer(int sig)
773 {
774 	sig = sig;	/* to avoid compiler warning */
775 
776 	int_int = 1;
777 	int_data = 0xff;	/* RST 38H for IM 0 */
778 }
779 
780 /*
781  *	Input from virtual hardware control port
782  *	returns lock status of the port
783  */
hwctl_in(void)784 static BYTE hwctl_in(void)
785 {
786 	return(hwctl_lock);
787 }
788 
789 /*
790  *	Port is locked until magic number 0xaa is received!
791  *
792  *	Virtual hardware control output.
793  *	Doesn't exist in the real machine, used to shutdown
794  *	and for RST 38H interrupts every 10ms.
795  *
796  *	bit 0 = 1	start interrupt timer
797  *	bit 0 = 0	stop interrupt timer
798  *	bit 7 = 1       halt emulation via I/O
799  */
hwctl_out(BYTE data)800 static void hwctl_out(BYTE data)
801 {
802 	static struct itimerval tim;
803 	static struct sigaction newact;
804 
805 	/* if port is locked do nothing */
806 	if (hwctl_lock && (data != 0xaa))
807 		return;
808 
809 	/* unlock port ? */
810 	if (hwctl_lock && (data == 0xaa)) {
811 		hwctl_lock = 0;
812 		return;
813 	}
814 
815 	/* process output to unlocked port */
816 
817 	if (data & 128) {	/* halt system */
818 		cpu_error = IOHALT;
819 		cpu_state = STOPPED;
820 	}
821 
822 	if (data & 1) {
823 		newact.sa_handler = int_timer;
824 		memset((void *) &newact.sa_mask, 0, sizeof(newact.sa_mask));
825 		newact.sa_flags = 0;
826 		sigaction(SIGALRM, &newact, NULL);
827 		tim.it_value.tv_sec = 0;
828 		tim.it_value.tv_usec = 10000;
829 		tim.it_interval.tv_sec = 0;
830 		tim.it_interval.tv_usec = 10000;
831 		setitimer(ITIMER_REAL, &tim, NULL);
832 	} else {
833 		newact.sa_handler = SIG_IGN;
834 		memset((void *) &newact.sa_mask, 0, sizeof(newact.sa_mask));
835 		newact.sa_flags = 0;
836 		sigaction(SIGALRM, &newact, NULL);
837 		tim.it_value.tv_sec = 0;
838 		tim.it_value.tv_usec = 0;
839 		setitimer(ITIMER_REAL, &tim, NULL);
840 	}
841 }
842 
843 /*
844  *	Input from data printer port
845  */
lpt_data_in(void)846 static BYTE lpt_data_in(void)
847 {
848 	return((BYTE) 0);
849 }
850 
851 /*
852  *	Print data into the printer file
853  */
lpt_data_out(BYTE data)854 static void lpt_data_out(BYTE data)
855 {
856 	if (printer == 0)
857 		printer = creat("printer.txt", 0664);
858 
859 	if ((data != '\r') && (data != 0x00)) {
860 again:
861 		if (write(printer, (char *) &data, 1) != 1) {
862 			if (errno == EINTR) {
863 				goto again;
864 			} else {
865 				LOGE(TAG, "can't write to printer");
866 				cpu_error = IOERROR;
867 				cpu_state = STOPPED;
868 			}
869 		}
870 	}
871 }
872 
873 /*
874  *	I/O handler for line printer status in:
875  *	Our printer file never is busy, so always return ready.
876  */
lpt_status_in(void)877 static BYTE lpt_status_in(void)
878 {
879 	return((BYTE) 3);
880 }
881 
882 /*
883  *	Output to line printer status port won't do anything
884  */
lpt_status_out(BYTE data)885 static void lpt_status_out(BYTE data)
886 {
887 	data = data; /* to avoid compiler warning */
888 }
889 
890 /*
891  *	Return status of the VDM keyboard
892  */
kbd_status_in(void)893 static BYTE kbd_status_in(void)
894 {
895 	extern int proctec_kbd_status;
896 
897 	return((BYTE) proctec_kbd_status);
898 }
899 
900 /*
901  * Return next data byte from the VDM keyboard
902  */
kbd_data_in(void)903 static BYTE kbd_data_in(void)
904 {
905 	extern int proctec_kbd_status, proctec_kbd_data;
906 	int data;
907 
908 	if (proctec_kbd_data == -1)
909 		return((BYTE) 0);
910 
911 	/* take over data and reset status */
912 	data = proctec_kbd_data;
913 	proctec_kbd_data = -1;
914 	proctec_kbd_status = 1;
915 
916 	return((BYTE) data);
917 }
918