1 /*
2 * Z80SIM - a Z80-CPU simulator
3 *
4 * Copyright (C) 2014-2020 by Udo Munk
5 *
6 * This module of the simulator contains the I/O simulation
7 * for a Cromemco Z-1 system
8 *
9 * History:
10 * 15-DEC-14 first version
11 * 20-DEC-14 added 4FDC emulation and machine boots CP/M 2.2
12 * 28-DEC-14 second version with 16FDC, CP/M 2.2 boots
13 * 01-JAN-15 fixed 16FDC, machine now also boots CDOS 2.58 from 8" and 5.25"
14 * 01-JAN-15 fixed frontpanel switch settings, added boot flag to fp switch
15 * 12-JAN-15 fdc and tu-art improvements, implemented banked memory
16 * 02-FEB-15 modified MMU, implemented timers and interrupts
17 * 20-FEB-15 bug fix for release 1.25
18 * 10-MAR-15 added support for two parallel port lpt devices on TU-ART
19 * 26-MAR-15 added support for two serial port tty devices on TU-ART
20 * 29-APR-15 added Cromemco DAZZLER to the machine
21 * 06-DEC-16 implemented status display and stepping for all machine cycles
22 * 22-DEC-16 moved MMU out to the new memory interface module
23 * 15-AUG-17 modified index pulse handling
24 * 22-APR-18 implemented TCP socket polling
25 * 24-APR-18 cleanup
26 * 17-MAY-18 implemented hardware control
27 * 08-JUN-18 moved hardware initialisation and reset to iosim
28 * 18-JUL-18 use logging
29 * 08-SEP-19 bug fixes provided by Alan Cox
30 * 08-OCT-19 (Mike Douglas) added OUT 161 trap to simbdos.c for host file I/O
31 * 19-JUL-20 avoid problems with some third party terminal emulations
32 */
33
34 #include <pthread.h>
35 #include <unistd.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <errno.h>
39 #include <poll.h>
40 #include <string.h>
41 #include <signal.h>
42 #include <fcntl.h>
43 #include <sys/time.h>
44 #include "sim.h"
45 #include "simglb.h"
46 #include "simbdos.h"
47 #include "../../iodevices/unix_network.h"
48 #include "../../iodevices/cromemco-tu-art.h"
49 #include "../../iodevices/cromemco-fdc.h"
50 #include "../../iodevices/cromemco-dazzler.h"
51 #include "../../frontpanel/frontpanel.h"
52 #include "memory.h"
53 /* #define LOG_LOCAL_LEVEL LOG_DEBUG */
54 #include "log.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 fp_in(void), mmu_in(void);
62 static void fp_out(BYTE), mmu_out(BYTE);
63 static BYTE hwctl_in(void);
64 static void hwctl_out(BYTE);
65
66 /*
67 * Forward declarations for support functions
68 */
69 static void *timing(void *);
70 static void interrupt(int);
71
72 static const char *TAG = "IO";
73
74 static int rtc; /* flag for 512ms RTC interrupt */
75 int lpt1, lpt2; /* fds for lpt printer files */
76
77 BYTE hwctl_lock = 0xff; /* lock status hardware control port */
78
79 /* network connections for serial ports on the TU-ART's */
80 struct net_connectors ncons[NUMNSOC];
81
82 /*
83 * This array contains function pointers for every
84 * input I/O port (0 - 255), to do the required I/O.
85 */
86 BYTE (*port_in[256]) (void) = {
87 cromemco_tuart_0a_status_in, /* port 0 */
88 cromemco_tuart_0a_data_in, /* port 1 */
89 io_trap_in, /* port 2 */
90 cromemco_tuart_0a_interrupt_in, /* port 3 */
91 cromemco_fdc_aux_in, /* port 4 */
92 io_trap_in, /* port 5 */
93 io_trap_in, /* port 6 */
94 io_trap_in, /* port 7 */
95 io_trap_in, /* port 8 */
96 io_trap_in, /* port 9 */
97 io_trap_in, /* port 10 */
98 io_trap_in, /* port 11 */
99 io_trap_in, /* port 12 */
100 io_trap_in, /* port 13 */
101 cromemco_dazzler_flags_in, /* port 14 */
102 io_trap_in, /* port 15 */
103 io_trap_in, /* port 16 */
104 io_trap_in, /* port 17 */
105 io_trap_in, /* port 18 */
106 io_trap_in, /* port 19 */
107 io_trap_in, /* port 20 */
108 io_trap_in, /* port 21 */
109 io_trap_in, /* port 22 */
110 io_trap_in, /* port 23 */
111 io_trap_in, /* port 24 */
112 io_trap_in, /* port 25 */
113 io_trap_in, /* port 26 */
114 io_trap_in, /* port 27 */
115 io_trap_in, /* port 28 */
116 io_trap_in, /* port 29 */
117 io_trap_in, /* port 30 */
118 io_trap_in, /* port 31 */
119 cromemco_tuart_1a_status_in, /* port 32 */
120 cromemco_tuart_1a_data_in, /* port 33 */
121 io_trap_in, /* port 34 */
122 cromemco_tuart_1a_interrupt_in, /* port 35 */
123 cromemco_tuart_1a_parallel_in, /* port 36 */
124 io_trap_in, /* port 37 */
125 io_trap_in, /* port 38 */
126 io_trap_in, /* port 39 */
127 io_trap_in, /* port 40 */
128 io_trap_in, /* port 41 */
129 io_trap_in, /* port 42 */
130 io_trap_in, /* port 43 */
131 io_trap_in, /* port 44 */
132 io_trap_in, /* port 45 */
133 io_trap_in, /* port 46 */
134 io_trap_in, /* port 47 */
135 cromemco_fdc_status_in, /* port 48 */
136 cromemco_fdc_track_in, /* port 49 */
137 cromemco_fdc_sector_in, /* port 50 */
138 cromemco_fdc_data_in, /* port 51 */
139 cromemco_fdc_diskflags_in, /* port 52 */
140 io_trap_in, /* port 53 */
141 io_trap_in, /* port 54 */
142 io_trap_in, /* port 55 */
143 io_trap_in, /* port 56 */
144 io_trap_in, /* port 57 */
145 io_trap_in, /* port 58 */
146 io_trap_in, /* port 59 */
147 io_trap_in, /* port 60 */
148 io_trap_in, /* port 61 */
149 io_trap_in, /* port 62 */
150 io_trap_in, /* port 63 */
151 mmu_in, /* port 64 */
152 io_trap_in, /* port 65 */
153 io_trap_in, /* port 66 */
154 io_trap_in, /* port 67 */
155 io_trap_in, /* port 68 */
156 io_trap_in, /* port 69 */
157 io_trap_in, /* port 70 */
158 io_trap_in, /* port 71 */
159 io_trap_in, /* port 72 */
160 io_trap_in, /* port 73 */
161 io_trap_in, /* port 74 */
162 io_trap_in, /* port 75 */
163 io_trap_in, /* port 76 */
164 io_trap_in, /* port 77 */
165 io_trap_in, /* port 78 */
166 io_trap_in, /* port 79 */
167 cromemco_tuart_1b_status_in, /* port 80 */
168 cromemco_tuart_1b_data_in, /* port 81 */
169 io_trap_in, /* port 82 */
170 cromemco_tuart_1b_interrupt_in, /* port 83 */
171 cromemco_tuart_1b_parallel_in, /* port 84 */
172 io_trap_in, /* port 85 */
173 io_trap_in, /* port 86 */
174 io_trap_in, /* port 87 */
175 io_trap_in, /* port 88 */
176 io_trap_in, /* port 89 */
177 io_trap_in, /* port 90 */
178 io_trap_in, /* port 91 */
179 io_trap_in, /* port 92 */
180 io_trap_in, /* port 93 */
181 io_trap_in, /* port 94 */
182 io_trap_in, /* port 95 */
183 io_trap_in, /* port 96 */
184 io_trap_in, /* port 97 */
185 io_trap_in, /* port 98 */
186 io_trap_in, /* port 99 */
187 io_trap_in, /* port 100 */
188 io_trap_in, /* port 101 */
189 io_trap_in, /* port 102 */
190 io_trap_in, /* port 103 */
191 io_trap_in, /* port 104 */
192 io_trap_in, /* port 105 */
193 io_trap_in, /* port 106 */
194 io_trap_in, /* port 107 */
195 io_trap_in, /* port 108 */
196 io_trap_in, /* port 109 */
197 io_trap_in, /* port 110 */
198 io_trap_in, /* port 111 */
199 io_trap_in, /* port 112 */
200 io_trap_in, /* port 113 */
201 io_trap_in, /* port 114 */
202 io_trap_in, /* port 115 */
203 io_trap_in, /* port 116 */
204 io_trap_in, /* port 117 */
205 io_trap_in, /* port 118 */
206 io_trap_in, /* port 119 */
207 io_trap_in, /* port 120 */
208 io_trap_in, /* port 121 */
209 io_trap_in, /* port 122 */
210 io_trap_in, /* port 123 */
211 io_trap_in, /* port 124 */
212 io_trap_in, /* port 125 */
213 io_trap_in, /* port 126 */
214 io_trap_in, /* port 127 */
215 io_trap_in, /* port 128 */
216 io_trap_in, /* port 129 */
217 io_trap_in, /* port 130 */
218 io_trap_in, /* port 131 */
219 io_trap_in, /* port 132 */
220 io_trap_in, /* port 133 */
221 io_trap_in, /* port 134 */
222 io_trap_in, /* port 135 */
223 io_trap_in, /* port 136 */
224 io_trap_in, /* port 137 */
225 io_trap_in, /* port 138 */
226 io_trap_in, /* port 139 */
227 io_trap_in, /* port 140 */
228 io_trap_in, /* port 141 */
229 io_trap_in, /* port 142 */
230 io_trap_in, /* port 143 */
231 io_trap_in, /* port 144 */
232 io_trap_in, /* port 145 */
233 io_trap_in, /* port 146 */
234 io_trap_in, /* port 147 */
235 io_trap_in, /* port 148 */
236 io_trap_in, /* port 149 */
237 io_trap_in, /* port 150 */
238 io_trap_in, /* port 151 */
239 io_trap_in, /* port 152 */
240 io_trap_in, /* port 153 */
241 io_trap_in, /* port 154 */
242 io_trap_in, /* port 155 */
243 io_trap_in, /* port 156 */
244 io_trap_in, /* port 157 */
245 io_trap_in, /* port 158 */
246 io_trap_in, /* port 159 */
247 hwctl_in, /* port 160 */
248 io_trap_in, /* port 161 */
249 io_trap_in, /* port 162 */
250 io_trap_in, /* port 163 */
251 io_trap_in, /* port 164 */
252 io_trap_in, /* port 165 */
253 io_trap_in, /* port 166 */
254 io_trap_in, /* port 167 */
255 io_trap_in, /* port 168 */
256 io_trap_in, /* port 169 */
257 io_trap_in, /* port 170 */
258 io_trap_in, /* port 171 */
259 io_trap_in, /* port 172 */
260 io_trap_in, /* port 173 */
261 io_trap_in, /* port 174 */
262 io_trap_in, /* port 175 */
263 io_trap_in, /* port 176 */
264 io_trap_in, /* port 177 */
265 io_trap_in, /* port 178 */
266 io_trap_in, /* port 179 */
267 io_trap_in, /* port 180 */
268 io_trap_in, /* port 181 */
269 io_trap_in, /* port 182 */
270 io_trap_in, /* port 183 */
271 io_trap_in, /* port 184 */
272 io_trap_in, /* port 185 */
273 io_trap_in, /* port 186 */
274 io_trap_in, /* port 187 */
275 io_trap_in, /* port 188 */
276 io_trap_in, /* port 189 */
277 io_trap_in, /* port 190 */
278 io_trap_in, /* port 191 */
279 io_trap_in, /* port 192 */
280 io_trap_in, /* port 193 */
281 io_trap_in, /* port 194 */
282 io_trap_in, /* port 195 */
283 io_trap_in, /* port 196 */
284 io_trap_in, /* port 197 */
285 io_trap_in, /* port 198 */
286 io_trap_in, /* port 199 */
287 io_trap_in, /* port 200 */
288 io_trap_in, /* port 201 */
289 io_trap_in, /* port 202 */
290 io_trap_in, /* port 203 */
291 io_trap_in, /* port 204 */
292 io_trap_in, /* port 205 */
293 io_trap_in, /* port 206 */
294 io_trap_in, /* port 207 */
295 io_trap_in, /* port 208 */
296 io_trap_in, /* port 209 */
297 io_trap_in, /* port 210 */
298 io_trap_in, /* port 211 */
299 io_trap_in, /* port 212 */
300 io_trap_in, /* port 213 */
301 io_trap_in, /* port 214 */
302 io_trap_in, /* port 215 */
303 io_trap_in, /* port 216 */
304 io_trap_in, /* port 217 */
305 io_trap_in, /* port 218 */
306 io_trap_in, /* port 219 */
307 io_trap_in, /* port 220 */
308 io_trap_in, /* port 221 */
309 io_trap_in, /* port 222 */
310 io_trap_in, /* port 223 */
311 io_trap_in, /* port 224 */
312 io_trap_in, /* port 225 */
313 io_trap_in, /* port 226 */
314 io_trap_in, /* port 227 */
315 io_trap_in, /* port 228 */
316 io_trap_in, /* port 229 */
317 io_trap_in, /* port 230 */
318 io_trap_in, /* port 231 */
319 io_trap_in, /* port 232 */
320 io_trap_in, /* port 233 */
321 io_trap_in, /* port 234 */
322 io_trap_in, /* port 235 */
323 io_trap_in, /* port 236 */
324 io_trap_in, /* port 237 */
325 io_trap_in, /* port 238 */
326 io_trap_in, /* port 239 */
327 io_trap_in, /* port 240 */
328 io_trap_in, /* port 241 */
329 io_trap_in, /* port 242 */
330 io_trap_in, /* port 243 */
331 io_trap_in, /* port 244 */
332 io_trap_in, /* port 245 */
333 io_trap_in, /* port 246 */
334 io_trap_in, /* port 247 */
335 io_trap_in, /* port 248 */
336 io_trap_in, /* port 249 */
337 io_trap_in, /* port 250 */
338 io_trap_in, /* port 251 */
339 io_trap_in, /* port 252 */
340 io_trap_in, /* port 253 */
341 io_trap_in, /* port 254 */
342 fp_in /* port 255 */ /* front panel */
343 };
344
345 /*
346 * This array contains function pointers for every
347 * output I/O port (0 - 255), to do the required I/O.
348 */
349 static void (*port_out[256]) (BYTE) = {
350 cromemco_tuart_0a_baud_out, /* port 0 */
351 cromemco_tuart_0a_data_out, /* port 1 */
352 cromemco_tuart_0a_command_out, /* port 2 */
353 cromemco_tuart_0a_interrupt_out,/* port 3 */
354 cromemco_fdc_aux_out, /* port 4 */
355 cromemco_tuart_0a_timer1_out, /* port 5 */
356 cromemco_tuart_0a_timer2_out, /* port 6 */
357 cromemco_tuart_0a_timer3_out, /* port 7 */
358 cromemco_tuart_0a_timer4_out, /* port 8 */
359 cromemco_tuart_0a_timer5_out, /* port 9 */
360 io_trap_out, /* port 10 */
361 io_trap_out, /* port 11 */
362 io_trap_out, /* port 12 */
363 io_trap_out, /* port 13 */
364 cromemco_dazzler_ctl_out, /* port 14 */
365 cromemco_dazzler_format_out, /* port 15 */
366 io_trap_out, /* port 16 */
367 io_trap_out, /* port 17 */
368 io_trap_out, /* port 18 */
369 io_trap_out, /* port 19 */
370 io_trap_out, /* port 20 */
371 io_trap_out, /* port 21 */
372 io_trap_out, /* port 22 */
373 io_trap_out, /* port 23 */
374 io_trap_out, /* port 24 */
375 io_trap_out, /* port 25 */
376 io_trap_out, /* port 26 */
377 io_trap_out, /* port 27 */
378 io_trap_out, /* port 28 */
379 io_trap_out, /* port 29 */
380 io_trap_out, /* port 30 */
381 io_trap_out, /* port 31 */
382 cromemco_tuart_1a_baud_out, /* port 32 */
383 cromemco_tuart_1a_data_out, /* port 33 */
384 cromemco_tuart_1a_command_out, /* port 34 */
385 cromemco_tuart_1a_interrupt_out,/* port 35 */
386 cromemco_tuart_1a_parallel_out, /* port 36 */
387 io_trap_out, /* port 37 */
388 io_trap_out, /* port 38 */
389 io_trap_out, /* port 39 */
390 io_trap_out, /* port 40 */
391 io_trap_out, /* port 41 */
392 io_trap_out, /* port 42 */
393 io_trap_out, /* port 43 */
394 io_trap_out, /* port 44 */
395 io_trap_out, /* port 45 */
396 io_trap_out, /* port 46 */
397 io_trap_out, /* port 47 */
398 cromemco_fdc_cmd_out, /* port 48 */
399 cromemco_fdc_track_out, /* port 49 */
400 cromemco_fdc_sector_out, /* port 50 */
401 cromemco_fdc_data_out, /* port 51 */
402 cromemco_fdc_diskctl_out, /* port 52 */
403 io_trap_out, /* port 53 */
404 io_trap_out, /* port 54 */
405 io_trap_out, /* port 55 */
406 io_trap_out, /* port 56 */
407 io_trap_out, /* port 57 */
408 io_trap_out, /* port 58 */
409 io_trap_out, /* port 59 */
410 io_trap_out, /* port 60 */
411 io_trap_out, /* port 61 */
412 io_trap_out, /* port 62 */
413 io_trap_out, /* port 63 */
414 mmu_out, /* port 64 */
415 io_trap_out, /* port 65 */
416 io_trap_out, /* port 66 */
417 io_trap_out, /* port 67 */
418 io_trap_out, /* port 68 */
419 io_trap_out, /* port 69 */
420 io_trap_out, /* port 70 */
421 io_trap_out, /* port 71 */
422 io_trap_out, /* port 72 */
423 io_trap_out, /* port 73 */
424 io_trap_out, /* port 74 */
425 io_trap_out, /* port 75 */
426 io_trap_out, /* port 76 */
427 io_trap_out, /* port 77 */
428 io_trap_out, /* port 78 */
429 io_trap_out, /* port 79 */
430 cromemco_tuart_1b_baud_out, /* port 80 */
431 cromemco_tuart_1b_data_out, /* port 81 */
432 cromemco_tuart_1b_command_out, /* port 82 */
433 cromemco_tuart_1b_interrupt_out,/* port 83 */
434 cromemco_tuart_1b_parallel_out, /* port 84 */
435 io_trap_out, /* port 85 */
436 io_trap_out, /* port 86 */
437 io_trap_out, /* port 87 */
438 io_trap_out, /* port 88 */
439 io_trap_out, /* port 89 */
440 io_trap_out, /* port 90 */
441 io_trap_out, /* port 91 */
442 io_trap_out, /* port 92 */
443 io_trap_out, /* port 93 */
444 io_trap_out, /* port 94 */
445 io_trap_out, /* port 95 */
446 io_trap_out, /* port 96 */
447 io_trap_out, /* port 97 */
448 io_trap_out, /* port 98 */
449 io_trap_out, /* port 99 */
450 io_trap_out, /* port 100 */
451 io_trap_out, /* port 101 */
452 io_trap_out, /* port 102 */
453 io_trap_out, /* port 103 */
454 io_trap_out, /* port 104 */
455 io_trap_out, /* port 105 */
456 io_trap_out, /* port 106 */
457 io_trap_out, /* port 107 */
458 io_trap_out, /* port 108 */
459 io_trap_out, /* port 109 */
460 io_trap_out, /* port 110 */
461 io_trap_out, /* port 111 */
462 io_trap_out, /* port 112 */
463 io_trap_out, /* port 113 */
464 io_trap_out, /* port 114 */
465 io_trap_out, /* port 115 */
466 io_trap_out, /* port 116 */
467 io_trap_out, /* port 117 */
468 io_trap_out, /* port 118 */
469 io_trap_out, /* port 119 */
470 io_trap_out, /* port 120 */
471 io_trap_out, /* port 121 */
472 io_trap_out, /* port 122 */
473 io_trap_out, /* port 123 */
474 io_trap_out, /* port 124 */
475 io_trap_out, /* port 125 */
476 io_trap_out, /* port 126 */
477 io_trap_out, /* port 127 */
478 io_trap_out, /* port 128 */
479 io_trap_out, /* port 129 */
480 io_trap_out, /* port 130 */
481 io_trap_out, /* port 131 */
482 io_trap_out, /* port 132 */
483 io_trap_out, /* port 133 */
484 io_trap_out, /* port 134 */
485 io_trap_out, /* port 135 */
486 io_trap_out, /* port 136 */
487 io_trap_out, /* port 137 */
488 io_trap_out, /* port 138 */
489 io_trap_out, /* port 139 */
490 io_trap_out, /* port 140 */
491 io_trap_out, /* port 141 */
492 io_trap_out, /* port 142 */
493 io_trap_out, /* port 143 */
494 io_trap_out, /* port 144 */
495 io_trap_out, /* port 145 */
496 io_trap_out, /* port 146 */
497 io_trap_out, /* port 147 */
498 io_trap_out, /* port 148 */
499 io_trap_out, /* port 149 */
500 io_trap_out, /* port 150 */
501 io_trap_out, /* port 151 */
502 io_trap_out, /* port 152 */
503 io_trap_out, /* port 153 */
504 io_trap_out, /* port 154 */
505 io_trap_out, /* port 155 */
506 io_trap_out, /* port 156 */
507 io_trap_out, /* port 157 */
508 io_trap_out, /* port 158 */
509 io_trap_out, /* port 159 */
510 hwctl_out, /* port 160 */
511 host_bdos_out, /* port 161 */ /* host file I/O hook */
512 io_trap_out, /* port 162 */
513 io_trap_out, /* port 163 */
514 io_trap_out, /* port 164 */
515 io_trap_out, /* port 165 */
516 io_trap_out, /* port 166 */
517 io_trap_out, /* port 167 */
518 io_trap_out, /* port 168 */
519 io_trap_out, /* port 169 */
520 io_trap_out, /* port 170 */
521 io_trap_out, /* port 171 */
522 io_trap_out, /* port 172 */
523 io_trap_out, /* port 173 */
524 io_trap_out, /* port 174 */
525 io_trap_out, /* port 175 */
526 io_trap_out, /* port 176 */
527 io_trap_out, /* port 177 */
528 io_trap_out, /* port 178 */
529 io_trap_out, /* port 179 */
530 io_trap_out, /* port 180 */
531 io_trap_out, /* port 181 */
532 io_trap_out, /* port 182 */
533 io_trap_out, /* port 183 */
534 io_trap_out, /* port 184 */
535 io_trap_out, /* port 185 */
536 io_trap_out, /* port 186 */
537 io_trap_out, /* port 187 */
538 io_trap_out, /* port 188 */
539 io_trap_out, /* port 189 */
540 io_trap_out, /* port 190 */
541 io_trap_out, /* port 191 */
542 io_trap_out, /* port 192 */
543 io_trap_out, /* port 193 */
544 io_trap_out, /* port 194 */
545 io_trap_out, /* port 195 */
546 io_trap_out, /* port 196 */
547 io_trap_out, /* port 197 */
548 io_trap_out, /* port 198 */
549 io_trap_out, /* port 199 */
550 io_trap_out, /* port 200 */
551 io_trap_out, /* port 201 */
552 io_trap_out, /* port 202 */
553 io_trap_out, /* port 203 */
554 io_trap_out, /* port 204 */
555 io_trap_out, /* port 205 */
556 io_trap_out, /* port 206 */
557 io_trap_out, /* port 207 */
558 io_trap_out, /* port 208 */
559 io_trap_out, /* port 209 */
560 io_trap_out, /* port 210 */
561 io_trap_out, /* port 211 */
562 io_trap_out, /* port 212 */
563 io_trap_out, /* port 213 */
564 io_trap_out, /* port 214 */
565 io_trap_out, /* port 215 */
566 io_trap_out, /* port 216 */
567 io_trap_out, /* port 217 */
568 io_trap_out, /* port 218 */
569 io_trap_out, /* port 219 */
570 io_trap_out, /* port 220 */
571 io_trap_out, /* port 221 */
572 io_trap_out, /* port 222 */
573 io_trap_out, /* port 223 */
574 io_trap_out, /* port 224 */
575 io_trap_out, /* port 225 */
576 io_trap_out, /* port 226 */
577 io_trap_out, /* port 227 */
578 io_trap_out, /* port 228 */
579 io_trap_out, /* port 229 */
580 io_trap_out, /* port 230 */
581 io_trap_out, /* port 231 */
582 io_trap_out, /* port 232 */
583 io_trap_out, /* port 233 */
584 io_trap_out, /* port 234 */
585 io_trap_out, /* port 235 */
586 io_trap_out, /* port 236 */
587 io_trap_out, /* port 237 */
588 io_trap_out, /* port 238 */
589 io_trap_out, /* port 239 */
590 io_trap_out, /* port 240 */
591 io_trap_out, /* port 241 */
592 io_trap_out, /* port 242 */
593 io_trap_out, /* port 243 */
594 io_trap_out, /* port 244 */
595 io_trap_out, /* port 245 */
596 io_trap_out, /* port 246 */
597 io_trap_out, /* port 247 */
598 io_trap_out, /* port 248 */
599 io_trap_out, /* port 249 */
600 io_trap_out, /* port 250 */
601 io_trap_out, /* port 251 */
602 io_trap_out, /* port 252 */
603 io_trap_out, /* port 253 */
604 io_trap_out, /* port 254 */
605 fp_out /* port 255 */ /* front panel */
606 };
607
608 /*
609 * This function is to initiate the I/O devices.
610 * It will be called from the CPU simulation before
611 * any operation with the CPU is possible.
612 */
init_io(void)613 void init_io(void)
614 {
615 register int i;
616 pthread_t thread;
617 static struct itimerval tim;
618 static struct sigaction newact;
619
620 /* initialise TCP/IP networking */
621 #ifdef TCPASYNC
622 newact.sa_handler = sigio_tcp_server_socket;
623 memset((void *) &newact.sa_mask, 0, sizeof(newact.sa_mask));
624 newact.sa_flags = 0;
625 sigaction(SIGIO, &newact, NULL);
626 #endif
627
628 for (i = 0; i < NUMNSOC; i++) {
629 ncons[i].port = SERVERPORT + i;
630 ncons[i].telnet = 1;
631 init_tcp_server_socket(&ncons[i]);
632 }
633
634 /* initial TU-ART device interrupt address */
635 uart0a_int = 0xff;
636 uart1a_int = 0xff;
637 uart1b_int = 0xff;
638
639 /* create the thread for timer and interrupt handling */
640 if (pthread_create(&thread, NULL, timing, (void *) NULL)) {
641 LOGE(TAG, "can't create timing thread");
642 exit(1);
643 }
644
645 /* start 10ms interrupt timer, delayed! */
646 newact.sa_handler = interrupt;
647 memset((void *) &newact.sa_mask, 0, sizeof(newact.sa_mask));
648 newact.sa_flags = 0;
649 sigaction(SIGALRM, &newact, NULL);
650 tim.it_value.tv_sec = 5;
651 tim.it_value.tv_usec = 0;
652 tim.it_interval.tv_sec = 0;
653 tim.it_interval.tv_usec = 10000;
654 setitimer(ITIMER_REAL, &tim, NULL);
655
656 LOG(TAG, "\r\n");
657 }
658
659 /*
660 * This function is to stop the I/O devices. It is
661 * called from the CPU simulation on exit.
662 */
exit_io(void)663 void exit_io(void)
664 {
665 register int i;
666
667 /* close line printer files */
668 if (lpt1 != 0)
669 close(lpt1);
670 if (lpt2 != 0)
671 close(lpt2);
672
673 /* close network connections */
674 for (i = 0; i < NUMNSOC; i++) {
675 if (ncons[i].ssc)
676 close(ncons[i].ssc);
677 }
678
679 /* shutdown DAZZLER */
680 cromemco_dazzler_off();
681 }
682
683 /*
684 * This function is to reset the I/O devices. It is
685 * called from the CPU simulation when an External Clear is performed.
686 */
reset_io(void)687 void reset_io(void)
688 {
689 cromemco_dazzler_off();
690 cromemco_fdc_reset();
691 hwctl_lock = 0xff;
692 }
693
694 /*
695 * This is the main handler for all IN op-codes,
696 * called by the simulator. It calls the input
697 * function for port addr.
698 */
io_in(BYTE addrl,BYTE addrh)699 BYTE io_in(BYTE addrl, BYTE addrh)
700 {
701 int val;
702
703 io_port = addrl;
704 io_data = (*port_in[addrl]) ();
705
706 cpu_bus = CPU_WO | CPU_INP;
707
708 fp_clock += 3;
709 fp_led_address = (addrh << 8) + addrl;
710 fp_led_data = io_data;
711 fp_sampleData();
712 val = wait_step();
713
714 /* when single stepped INP get last set value of port */
715 if (val)
716 io_data = (*port_in[io_port]) ();
717
718 return(io_data);
719 }
720
721 /*
722 * This is the main handler for all OUT op-codes,
723 * called by the simulator. It calls the output
724 * function for port addr.
725 */
io_out(BYTE addrl,BYTE addrh,BYTE data)726 void io_out(BYTE addrl, BYTE addrh, BYTE data)
727 {
728 io_port = addrl;
729 io_data = data;
730 (*port_out[addrl]) (data);
731
732 cpu_bus = CPU_OUT;
733
734 fp_clock += 6;
735 fp_led_address = (addrh << 8) + addrl;
736 fp_led_data = io_data;
737 fp_sampleData();
738 wait_step();
739 }
740
741 /*
742 * I/O input trap function
743 * This function should be added into all unused
744 * entries of the input port array. It can stop the
745 * emulation with an I/O error.
746 */
io_trap_in(void)747 static BYTE io_trap_in(void)
748 {
749 if (i_flag) {
750 cpu_error = IOTRAPIN;
751 cpu_state = STOPPED;
752 }
753 return((BYTE) 0xff);
754 }
755
756 /*
757 * I/O output trap function
758 * This function should be added into all unused
759 * entries of the output port array. It can stop the
760 * emulation with an I/O error.
761 */
io_trap_out(BYTE data)762 static void io_trap_out(BYTE data)
763 {
764 data = data; /* to avoid compiler warning */
765
766 if (i_flag) {
767 cpu_error = IOTRAPOUT;
768 cpu_state = STOPPED;
769 }
770 }
771
772 /*
773 * Read input from front panel switches
774 */
fp_in(void)775 static BYTE fp_in(void)
776 {
777 return(address_switch >> 8);
778 }
779
780 /*
781 * Write output to front panel lights
782 */
fp_out(BYTE data)783 static void fp_out(BYTE data)
784 {
785 fp_led_output = data;
786 }
787
788 /*
789 * Input from virtual hardware control port
790 * returns lock status of the port
791 */
hwctl_in(void)792 static BYTE hwctl_in(void)
793 {
794 return(hwctl_lock);
795 }
796
797 /*
798 * Port is locked until magic number 0xaa is received!
799 *
800 * Virtual hardware control output.
801 * Doesn't exist in the real machine, used to shutdown
802 *
803 * bit 7 = 1 halt emulation via I/O
804 */
hwctl_out(BYTE data)805 static void hwctl_out(BYTE data)
806 {
807 /* if port is locked do nothing */
808 if (hwctl_lock && (data != 0xaa))
809 return;
810
811 /* unlock port ? */
812 if (hwctl_lock && (data == 0xaa)) {
813 hwctl_lock = 0;
814 return;
815 }
816
817 /* process output to unlocked port */
818
819 if (data & 128) { /* halt system */
820 cpu_error = IOHALT;
821 cpu_state = STOPPED;
822 }
823 }
824
825 /*
826 * read MMU register
827 */
mmu_in(void)828 static BYTE mmu_in(void)
829 {
830 return(bankio);
831 }
832
833 /*
834 * write MMU register
835 */
mmu_out(BYTE data)836 static void mmu_out(BYTE data)
837 {
838 int sel;
839
840 LOGD(TAG, "mmu select bank %02x", data);
841 bankio = data;
842
843 /* set banks */
844 switch (data) {
845 case 0x00:
846 case 0x01:
847 sel = 0;
848 common = 0;
849 break;
850 case 0x02:
851 sel = 1;
852 common = 0;
853 break;
854 case 0x04:
855 sel = 2;
856 common = 0;
857 break;
858 case 0x08:
859 sel = 3;
860 common = 0;
861 break;
862 case 0x10:
863 sel = 4;
864 common = 0;
865 break;
866 case 0x20:
867 sel = 5;
868 common = 0;
869 break;
870 case 0x40:
871 sel = 6;
872 common = 0;
873 break;
874 case 0x80:
875 case 0x81:
876 sel = 0;
877 common = 1;
878 break;
879 default:
880 LOGE(TAG, "Not supported bank select = %02x", data);
881 cpu_error = IOERROR;
882 cpu_state = STOPPED;
883 return;
884 }
885
886 selbnk = sel;
887 }
888
889 /*
890 * Thread for timing and interrupts
891 */
timing(void * arg)892 void *timing(void *arg)
893 {
894 arg = arg; /* to avoid compiler warning */
895
896 while (1) { /* 1 msec per loop iteration */
897
898 /* make sure index pulse is there long enough */
899 if (index_pulse)
900 index_pulse++;
901
902 /* the tty transmit clear happens irrespective of anything */
903 if (uart0a_tbe == 0)
904 uart0a_tbe = 2;
905
906 /* count down the timers */
907 /* 64 usec steps, so 15*64 usec per loop iteration */
908 if (uart0a_timer1 > 0) {
909 uart0a_timer1 -= 15;
910 if (uart0a_timer1 <= 0) {
911 uart0a_timer1 = -1; /* interrupt pending */
912 }
913 }
914 if (uart0a_timer2 > 0) {
915 uart0a_timer2 -= 15;
916 if (uart0a_timer2 <= 0) {
917 uart0a_timer2 = -1; /* interrupt pending */
918 }
919 }
920 if (uart0a_timer3 > 0) {
921 uart0a_timer3 -= 15;
922 if (uart0a_timer3 <= 0) {
923 uart0a_timer3 = -1; /* interrupt pending */
924 }
925 }
926 if (uart0a_timer4 > 0) {
927 uart0a_timer4 -= 15;
928 if (uart0a_timer4 <= 0) {
929 uart0a_timer4 = -1; /* interrupt pending */
930 }
931 }
932 if (uart0a_timer5 > 0) {
933 uart0a_timer5 -= 15;
934 if (uart0a_timer5 <= 0) {
935 uart0a_timer5 = -1; /* interrupt pending */
936 }
937 }
938
939 /* check for interrupts from highest priority to lowest */
940
941 /* if last interrupt not acknowledged by CPU no new one yet */
942 if (int_int)
943 goto next;
944
945 /* UART 0A timer 1 */
946 if ((uart0a_timer1 == -1) && (uart0a_int_mask & 1)) {
947 uart0a_int = 0xc7;
948 uart0a_int_pending = 1;
949 int_data = 0xc7;
950 int_int = 1;
951 uart0a_timer1 = 0;
952 goto next;
953 }
954
955 /* UART 0A timer 2 */
956 if ((uart0a_timer2 == -1) && (uart0a_int_mask & 2)) {
957 uart0a_int = 0xcf;
958 uart0a_int_pending = 1;
959 int_data = 0xcf;
960 int_int = 1;
961 uart0a_timer2 = 0;
962 goto next;
963 }
964
965 /* EOJ from disk */
966 if ((fdc_flags & 1) && (uart0a_int_mask & 4)) {
967 uart0a_int = 0xd7;
968 uart0a_int_pending = 1;
969 int_data = 0xd7;
970 int_int = 1;
971 goto next;
972 }
973
974 /* UART 0A timer 3 */
975 if ((uart0a_timer3 == -1) && (uart0a_int_mask & 8)) {
976 uart0a_int = 0xdf;
977 uart0a_int_pending = 1;
978 int_data = 0xdf;
979 int_int = 1;
980 uart0a_timer3 = 0;
981 goto next;
982 }
983
984 /* UART 0A receive data available */
985 if ((uart0a_rda) && (uart0a_int_mask & 16)) {
986 uart0a_int = 0xe7;
987 uart0a_int_pending = 1;
988 int_data = 0xe7;
989 int_int = 1;
990 goto next;
991 }
992
993 /* UART 0A transmit buffer empty */
994 /* We use 2 to mean has gone empty->full but an IRQ is
995 pending */
996 if (uart0a_tbe == 2) {
997 uart0a_tbe = 1;
998 if (uart0a_int_mask & 32) {
999 uart0a_int = 0xef;
1000 uart0a_int_pending = 1;
1001 int_data = 0xef;
1002 int_int = 1;
1003 goto next;
1004 }
1005 }
1006
1007 /* UART 0A timer 4 */
1008 if ((uart0a_timer4 == -1) && (uart0a_int_mask & 64)) {
1009 uart0a_int = 0xf7;
1010 uart0a_int_pending = 1;
1011 int_data = 0xf7;
1012 int_int = 1;
1013 uart0a_timer4 = 0;
1014 goto next;
1015 }
1016
1017 /* UART 0A timer 5 */
1018 if ((uart0a_timer5 == -1) && (uart0a_int_mask & 128) && !uart0a_rst7) {
1019 uart0a_int = 0xff;
1020 uart0a_int_pending = 1;
1021 int_data = 0xff;
1022 int_int = 1;
1023 uart0a_timer5 = 0;
1024 goto next;
1025 }
1026
1027 /* 512ms RTC */
1028 if (rtc && uart0a_rst7) {
1029 rtc = 0;
1030 if (uart0a_int_mask & 128) {
1031 uart0a_int = 0xff;
1032 uart0a_int_pending = 1;
1033 int_data = 0xff;
1034 int_int = 1;
1035 goto next;
1036 }
1037 }
1038
1039 /* UART 0A no pending interrupt */
1040 uart0a_int = 0xff;
1041 uart0a_int_pending = 0;
1042
1043 /* UART 1A parallel port sense */
1044 uart1a_lpt_busy = 0;
1045 if (uart1a_sense != 0) {
1046 uart1a_int_pending = 1;
1047 uart1a_int = 0xd7;
1048 if (uart1a_int_mask & 4) {
1049 uart1a_sense = 0;
1050 int_data = 0x24;
1051 int_int = 1;
1052 goto next;
1053 }
1054 }
1055
1056 /* UART 1A receive data available */
1057 if ((uart1a_rda) && (uart1a_int_mask & 16)) {
1058 uart1a_int = 0xe7;
1059 uart1a_int_pending = 1;
1060 int_data = 0x28;
1061 int_int = 1;
1062 goto next;
1063 }
1064
1065 /* UART 1A transmit buffer empty */
1066 if (uart1a_tbe == 0) {
1067 uart1a_tbe = 1;
1068 if (uart1a_int_mask & 32) {
1069 uart1a_int = 0xef;
1070 uart1a_int_pending = 1;
1071 int_data = 0x2a;
1072 int_int = 1;
1073 goto next;
1074 }
1075 }
1076
1077 /* UART 1A no pending interrupt */
1078 uart1a_int_pending = 0;
1079 uart1a_int = 0xff;
1080
1081 /* UART 1B parallel port sense */
1082 uart1b_lpt_busy = 0;
1083 if (uart1b_sense != 0) {
1084 uart1b_int_pending = 1;
1085 uart1b_int = 0xd7;
1086 if (uart1b_int_mask & 4) {
1087 uart1b_sense = 0;
1088 int_data = 0x34;
1089 int_int = 1;
1090 goto next;
1091 }
1092 }
1093
1094 /* UART 1B receive data available */
1095 if ((uart1b_rda) && (uart1b_int_mask & 16)) {
1096 uart1b_int = 0xe7;
1097 uart1b_int_pending = 1;
1098 int_data = 0x38;
1099 int_int = 1;
1100 goto next;
1101 }
1102
1103 /* UART 1B transmit buffer empty */
1104 if (uart1b_tbe == 0) {
1105 uart1b_tbe = 1;
1106 if (uart1b_int_mask & 32) {
1107 uart1b_int = 0xef;
1108 uart1b_int_pending = 1;
1109 int_data = 0x3a;
1110 int_int = 1;
1111 goto next;
1112 }
1113 }
1114
1115 /* UART 1B no pending interrupt */
1116 uart1b_int_pending = 0;
1117 uart1b_int = 0xff;
1118
1119 next:
1120 /* sleep for 1 millisecond */
1121 SLEEP_MS(1);
1122
1123 /* reset disk index pulse */
1124 if (index_pulse > 2)
1125 index_pulse = 0;
1126 }
1127
1128 /* never reached, this thread is running endless */
1129 pthread_exit(NULL);
1130 }
1131
1132 /*
1133 * 10ms interrupt handler
1134 */
interrupt(int sig)1135 void interrupt(int sig)
1136 {
1137 static unsigned long counter = 0L;
1138 struct pollfd p[1];
1139
1140 sig = sig; /* to avoid compiler warning */
1141
1142 counter++;
1143
1144 /* if motor on generate disk index pulse */
1145 if (motoron) {
1146 /* 170ms ~ 360rpm for 8" drives */
1147 if (dtype == LARGE) {
1148 if ((counter % 17) == 0)
1149 index_pulse = 1;
1150 /* 200ms ~ 300rpm for 5.25" drives */
1151 } else {
1152 if ((counter % 20) == 0)
1153 index_pulse = 1;
1154 }
1155 }
1156
1157 /* motor timeout timer */
1158 if (motortimer > 0)
1159 motortimer--;
1160
1161 /* set RTC interrupt flag every 510ms */
1162 if ((counter % 51) == 0)
1163 rtc = 1;
1164
1165 #ifndef TCPASYNC
1166 /* poll TCP sockets if SIGIO not working */
1167 sigio_tcp_server_socket(0);
1168 #endif
1169
1170 /* check for RDA */
1171 p[0].fd = fileno(stdin);
1172 p[0].events = POLLIN;
1173 p[0].revents = 0;
1174 poll(p, 1, 0);
1175 if (p[0].revents & POLLIN)
1176 uart0a_rda = 1;
1177 else
1178 uart0a_rda = 0;
1179 if (p[0].revents & POLLNVAL) {
1180 LOGE(TAG, "can't use terminal, try 'screen simulation ...'");
1181 exit(1);
1182 }
1183
1184 if (ncons[0].ssc != 0) {
1185 p[0].fd = ncons[0].ssc;
1186 p[0].events = POLLIN;
1187 p[0].revents = 0;
1188 poll(p, 1, 0);
1189 if (p[0].revents & POLLHUP) {
1190 close(ncons[0].ssc);
1191 ncons[0].ssc = 0;
1192 uart1a_rda = 0;
1193 } else if (p[0].revents & POLLIN) {
1194 uart1a_rda = 1;
1195 } else {
1196 uart1a_rda = 0;
1197 }
1198 }
1199
1200 if (ncons[1].ssc != 0) {
1201 p[0].fd = ncons[1].ssc;
1202 p[0].events = POLLIN;
1203 p[0].revents = 0;
1204 poll(p, 1, 0);
1205 if (p[0].revents & POLLHUP) {
1206 close(ncons[1].ssc);
1207 ncons[1].ssc = 0;
1208 uart1b_rda = 0;
1209 } else if (p[0].revents & POLLIN) {
1210 uart1b_rda = 1;
1211 } else {
1212 uart1b_rda = 0;
1213 }
1214 }
1215 }
1216