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