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