1 /*
2  * Z80SIM  -  a Z80-CPU simulator
3  *
4  * Common I/O devices used by various simulated machines
5  *
6  * Copyright (C) 2015-2019 by Udo Munk
7  * Copyright (C) 2018 David McNaughton
8  *
9  * Emulation of a Cromemco DAZZLER S100 board
10  *
11  * History:
12  * 24-APR-15 first version
13  * 25-APR-15 fixed a few things, good enough for a BETA release now
14  * 27-APR-15 fixed logic bugs with on/off state and thread handling
15  * 08-MAY-15 fixed Xlib multithreading problems
16  * 26-AUG-15 implemented double buffering to prevent flicker
17  * 27-AUG-15 more bug fixes
18  * 15-NOV-16 fixed logic bug, display wasn't always clear after
19  *           the device is switched off
20  * 06-DEC-16 added bus request for the DMA
21  * 16-DEC-16 use DMA function for memory access
22  * 26-JAN-17 optimization
23  * 15-JUL-18 use logging
24  * 19-JUL-18 integrate webfrontend
25  * 04-NOV-19 remove fake DMA bus request
26  */
27 
28 #include <X11/X.h>
29 #include <X11/Xlib.h>
30 #include <X11/Xutil.h>
31 #include <pthread.h>
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <signal.h>
35 #include <sys/time.h>
36 #include "sim.h"
37 #include "simglb.h"
38 #include "config.h"
39 #include "../../frontpanel/frontpanel.h"
40 #include "memory.h"
41 #ifdef HAS_NETSERVER
42 #include "netsrv.h"
43 #endif
44 /* #define LOG_LOCAL_LEVEL LOG_DEBUG */
45 #include "log.h"
46 
47 #ifdef HAS_DAZZLER
48 
49 static const char *TAG = "DAZZLER";
50 
51 /* X11 stuff */
52 #define WSIZE 512
53 static int size = WSIZE;
54 static Display *display;
55 static Window window;
56 static int screen;
57 static GC gc;
58 static XWindowAttributes wa;
59 static Pixmap pixmap;
60 static Colormap colormap;
61 static XColor colors[16];
62 static XColor grays[16];
63 static char color0[] =  "#000000";
64 static char color1[] =  "#800000";
65 static char color2[] =  "#008000";
66 static char color3[] =  "#808000";
67 static char color4[] =  "#000080";
68 static char color5[] =  "#800080";
69 static char color6[] =  "#008080";
70 static char color7[] =  "#808080";
71 static char color8[] =  "#000000";
72 static char color9[] =  "#FF0000";
73 static char color10[] = "#00FF00";
74 static char color11[] = "#FFFF00";
75 static char color12[] = "#0000FF";
76 static char color13[] = "#FF00FF";
77 static char color14[] = "#00FFFF";
78 static char color15[] = "#FFFFFF";
79 static char gray0[] =   "#000000";
80 static char gray1[] =   "#101010";
81 static char gray2[] =   "#202020";
82 static char gray3[] =   "#303030";
83 static char gray4[] =   "#404040";
84 static char gray5[] =   "#505050";
85 static char gray6[] =   "#606060";
86 static char gray7[] =   "#707070";
87 static char gray8[] =   "#808080";
88 static char gray9[] =   "#909090";
89 static char gray10[] =  "#A0A0A0";
90 static char gray11[] =  "#B0B0B0";
91 static char gray12[] =  "#C0C0C0";
92 static char gray13[] =  "#D0D0D0";
93 static char gray14[] =  "#E0E0E0";
94 static char gray15[] =  "#FFFFFF";
95 
96 /* DAZZLER stuff */
97 static int state;
98 static WORD dma_addr;
99 static BYTE flags = 64;
100 static BYTE format;
101 
102 /* UNIX stuff */
103 static pthread_t thread;
104 
105 #ifdef HAS_NETSERVER
106 static void ws_clear(void);
107 static BYTE formatBuf = 0;
108 #endif
109 
110 /* create the X11 window for DAZZLER display */
open_display(void)111 static void open_display(void)
112 {
113 	Window rootwindow;
114 	XSizeHints *size_hints = XAllocSizeHints();
115 	Atom wm_delete_window;
116 
117 	display = XOpenDisplay(NULL);
118 	XLockDisplay(display);
119 	screen = DefaultScreen(display);
120 	rootwindow = RootWindow(display, screen);
121 	XGetWindowAttributes(display, rootwindow, &wa);
122 	window = XCreateSimpleWindow(display, rootwindow, 0, 0,
123 					size, size, 1, 0, 0);
124 	XStoreName(display, window, "Cromemco DAzzLER");
125 	size_hints->flags = PSize | PMinSize | PMaxSize;
126 	size_hints->min_width = size;
127 	size_hints->min_height = size;
128 	size_hints->base_width = size;
129 	size_hints->base_height = size;
130 	size_hints->max_width = size;
131 	size_hints->max_height = size;
132 	XSetWMNormalHints(display, window, size_hints);
133 	XFree(size_hints);
134 	wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False);
135 	XSetWMProtocols(display, window, &wm_delete_window, 1);
136 	colormap = DefaultColormap(display, 0);
137 	gc = XCreateGC(display, window, 0, NULL);
138 	XSetFillStyle(display, gc, FillSolid);
139 	pixmap = XCreatePixmap(display, rootwindow, size, size,
140 		 wa.depth);
141 
142 	XParseColor(display, colormap, color0, &colors[0]);
143 	XAllocColor(display, colormap, &colors[0]);
144 	XParseColor(display, colormap, color1, &colors[1]);
145 	XAllocColor(display, colormap, &colors[1]);
146 	XParseColor(display, colormap, color2, &colors[2]);
147 	XAllocColor(display, colormap, &colors[2]);
148 	XParseColor(display, colormap, color3, &colors[3]);
149 	XAllocColor(display, colormap, &colors[3]);
150 	XParseColor(display, colormap, color4, &colors[4]);
151 	XAllocColor(display, colormap, &colors[4]);
152 	XParseColor(display, colormap, color5, &colors[5]);
153 	XAllocColor(display, colormap, &colors[5]);
154 	XParseColor(display, colormap, color6, &colors[6]);
155 	XAllocColor(display, colormap, &colors[6]);
156 	XParseColor(display, colormap, color7, &colors[7]);
157 	XAllocColor(display, colormap, &colors[7]);
158 	XParseColor(display, colormap, color8, &colors[8]);
159 	XAllocColor(display, colormap, &colors[8]);
160 	XParseColor(display, colormap, color9, &colors[9]);
161 	XAllocColor(display, colormap, &colors[9]);
162 	XParseColor(display, colormap, color10, &colors[10]);
163 	XAllocColor(display, colormap, &colors[10]);
164 	XParseColor(display, colormap, color11, &colors[11]);
165 	XAllocColor(display, colormap, &colors[11]);
166 	XParseColor(display, colormap, color12, &colors[12]);
167 	XAllocColor(display, colormap, &colors[12]);
168 	XParseColor(display, colormap, color13, &colors[13]);
169 	XAllocColor(display, colormap, &colors[13]);
170 	XParseColor(display, colormap, color14, &colors[14]);
171 	XAllocColor(display, colormap, &colors[14]);
172 	XParseColor(display, colormap, color15, &colors[15]);
173 	XAllocColor(display, colormap, &colors[15]);
174 
175 	XParseColor(display, colormap, gray0, &grays[0]);
176 	XAllocColor(display, colormap, &grays[0]);
177 	XParseColor(display, colormap, gray1, &grays[1]);
178 	XAllocColor(display, colormap, &grays[1]);
179 	XParseColor(display, colormap, gray2, &grays[2]);
180 	XAllocColor(display, colormap, &grays[2]);
181 	XParseColor(display, colormap, gray3, &grays[3]);
182 	XAllocColor(display, colormap, &grays[3]);
183 	XParseColor(display, colormap, gray4, &grays[4]);
184 	XAllocColor(display, colormap, &grays[4]);
185 	XParseColor(display, colormap, gray5, &grays[5]);
186 	XAllocColor(display, colormap, &grays[5]);
187 	XParseColor(display, colormap, gray6, &grays[6]);
188 	XAllocColor(display, colormap, &grays[6]);
189 	XParseColor(display, colormap, gray7, &grays[7]);
190 	XAllocColor(display, colormap, &grays[7]);
191 	XParseColor(display, colormap, gray8, &grays[8]);
192 	XAllocColor(display, colormap, &grays[8]);
193 	XParseColor(display, colormap, gray9, &grays[9]);
194 	XAllocColor(display, colormap, &grays[9]);
195 	XParseColor(display, colormap, gray10, &grays[10]);
196 	XAllocColor(display, colormap, &grays[10]);
197 	XParseColor(display, colormap, gray11, &grays[11]);
198 	XAllocColor(display, colormap, &grays[11]);
199 	XParseColor(display, colormap, gray12, &grays[12]);
200 	XAllocColor(display, colormap, &grays[12]);
201 	XParseColor(display, colormap, gray13, &grays[13]);
202 	XAllocColor(display, colormap, &grays[13]);
203 	XParseColor(display, colormap, gray14, &grays[14]);
204 	XAllocColor(display, colormap, &grays[14]);
205 	XParseColor(display, colormap, gray15, &grays[15]);
206 	XAllocColor(display, colormap, &grays[15]);
207 
208 	XMapWindow(display, window);
209 	XUnlockDisplay(display);
210 }
211 
212 /* switch DAZZLER off from front panel */
cromemco_dazzler_off(void)213 void cromemco_dazzler_off(void)
214 {
215 	state = 0;
216 	SLEEP_MS(50);
217 
218 	if (thread != 0) {
219 		pthread_cancel(thread);
220 		pthread_join(thread, NULL);
221 		thread = 0;
222 	}
223 
224 	if (display != NULL) {
225 		XLockDisplay(display);
226 		XFreePixmap(display, pixmap);
227 		XFreeGC(display, gc);
228 		XUnlockDisplay(display);
229 		XCloseDisplay(display);
230 		display = NULL;
231 	}
232 
233 #ifdef HAS_NETSERVER
234 	ws_clear();
235 #endif
236 }
237 
238 /* draw pixels for one frame in hires */
draw_hires(void)239 static void draw_hires(void)
240 {
241 	int psize, x, y, i;
242 	WORD addr = dma_addr;
243 
244 	/* set color or grayscale from lower nibble in graphics format */
245 	i = format & 0x0f;
246 	if (format & 16)
247 		XSetForeground(display, gc, colors[i].pixel);
248 	else
249 		XSetForeground(display, gc, grays[i].pixel);
250 
251 	if (format & 32) {	/* 2048 bytes memory */
252 		psize = size / 128;	/* size of one pixel for 128x128 */
253 		for (y = 0; y < 64; y += 2) {
254 			for (x = 0; x < 64;) {
255 				i = dma_read(addr);
256 				if (i & 1)
257 					XFillRectangle(display, pixmap, gc,
258 						x * psize, y * psize,
259 						psize, psize);
260 				if (i & 2)
261 					XFillRectangle(display, pixmap, gc,
262 						(x+1) * psize, y * psize,
263 						psize, psize);
264 				if (i & 4)
265 					XFillRectangle(display, pixmap, gc,
266 						x * psize, (y+1) * psize,
267 						psize, psize);
268 				if (i & 8)
269 					XFillRectangle(display, pixmap, gc,
270 						(x+1) * psize, (y+1) * psize,
271 						psize, psize);
272 				if (i & 16)
273 					XFillRectangle(display, pixmap, gc,
274 						(x+2) * psize, y * psize,
275 						psize, psize);
276 				if (i & 32)
277 					XFillRectangle(display, pixmap, gc,
278 						(x+3) * psize, y * psize,
279 						psize, psize);
280 				if (i & 64)
281 					XFillRectangle(display, pixmap, gc,
282 						(x+2) * psize, (y+1) * psize,
283 						psize, psize);
284 				if (i & 128)
285 					XFillRectangle(display, pixmap, gc,
286 						(x+3) * psize, (y+1) * psize,
287 						psize, psize);
288 				x += 4;
289 				addr++;
290 			}
291 		}
292 		for (y = 0; y < 64; y += 2) {
293 			for (x = 64; x < 128;) {
294 				i = dma_read(addr);
295 				if (i & 1)
296 					XFillRectangle(display, pixmap, gc,
297 						x * psize, y * psize,
298 						psize, psize);
299 				if (i & 2)
300 					XFillRectangle(display, pixmap, gc,
301 						(x+1) * psize, y * psize,
302 						psize, psize);
303 				if (i & 4)
304 					XFillRectangle(display, pixmap, gc,
305 						x * psize, (y+1) * psize,
306 						psize, psize);
307 				if (i & 8)
308 					XFillRectangle(display, pixmap, gc,
309 						(x+1) * psize, (y+1) * psize,
310 						psize, psize);
311 				if (i & 16)
312 					XFillRectangle(display, pixmap, gc,
313 						(x+2) * psize, y * psize,
314 						psize, psize);
315 				if (i & 32)
316 					XFillRectangle(display, pixmap, gc,
317 						(x+3) * psize, y * psize,
318 						psize, psize);
319 				if (i & 64)
320 					XFillRectangle(display, pixmap, gc,
321 						(x+2) * psize, (y+1) * psize,
322 						psize, psize);
323 				if (i & 128)
324 					XFillRectangle(display, pixmap, gc,
325 						(x+3) * psize, (y+1) * psize,
326 						psize, psize);
327 				x += 4;
328 				addr++;
329 			}
330 		}
331 		for (y = 64; y < 128; y += 2) {
332 			for (x = 0; x < 64;) {
333 				i = dma_read(addr);
334 				if (i & 1)
335 					XFillRectangle(display, pixmap, gc,
336 						x * psize, y * psize,
337 						psize, psize);
338 				if (i & 2)
339 					XFillRectangle(display, pixmap, gc,
340 						(x+1) * psize, y * psize,
341 						psize, psize);
342 				if (i & 4)
343 					XFillRectangle(display, pixmap, gc,
344 						x * psize, (y+1) * psize,
345 						psize, psize);
346 				if (i & 8)
347 					XFillRectangle(display, pixmap, gc,
348 						(x+1) * psize, (y+1) * psize,
349 						psize, psize);
350 				if (i & 16)
351 					XFillRectangle(display, pixmap, gc,
352 						(x+2) * psize, y * psize,
353 						psize, psize);
354 				if (i & 32)
355 					XFillRectangle(display, pixmap, gc,
356 						(x+3) * psize, y * psize,
357 						psize, psize);
358 				if (i & 64)
359 					XFillRectangle(display, pixmap, gc,
360 						(x+2) * psize, (y+1) * psize,
361 						psize, psize);
362 				if (i & 128)
363 					XFillRectangle(display, pixmap, gc,
364 						(x+3) * psize, (y+1) * psize,
365 						psize, psize);
366 				x += 4;
367 				addr++;
368 			}
369 		}
370 		for (y = 64; y < 128; y += 2) {
371 			for (x = 64; x < 128;) {
372 				i = dma_read(addr);
373 				if (i & 1)
374 					XFillRectangle(display, pixmap, gc,
375 						x * psize, y * psize,
376 						psize, psize);
377 				if (i & 2)
378 					XFillRectangle(display, pixmap, gc,
379 						(x+1) * psize, y * psize,
380 						psize, psize);
381 				if (i & 4)
382 					XFillRectangle(display, pixmap, gc,
383 						x * psize, (y+1) * psize,
384 						psize, psize);
385 				if (i & 8)
386 					XFillRectangle(display, pixmap, gc,
387 						(x+1) * psize, (y+1) * psize,
388 						psize, psize);
389 				if (i & 16)
390 					XFillRectangle(display, pixmap, gc,
391 						(x+2) * psize, y * psize,
392 						psize, psize);
393 				if (i & 32)
394 					XFillRectangle(display, pixmap, gc,
395 						(x+3) * psize, y * psize,
396 						psize, psize);
397 				if (i & 64)
398 					XFillRectangle(display, pixmap, gc,
399 						(x+2) * psize, (y+1) * psize,
400 						psize, psize);
401 				if (i & 128)
402 					XFillRectangle(display, pixmap, gc,
403 						(x+3) * psize, (y+1) * psize,
404 						psize, psize);
405 				x += 4;
406 				addr++;
407 			}
408 		}
409 	} else {		/* 512 bytes memory */
410 		psize = size / 64;	/* size of one pixel for 64x64 */
411 		for (y = 0; y < 64; y += 2) {
412 			for (x = 0; x < 64;) {
413 				i = dma_read(addr);
414 				if (i & 1)
415 					XFillRectangle(display, pixmap, gc,
416 						x * psize, y * psize,
417 						psize, psize);
418 				if (i & 2)
419 					XFillRectangle(display, pixmap, gc,
420 						(x+1) * psize, y * psize,
421 						psize, psize);
422 				if (i & 4)
423 					XFillRectangle(display, pixmap, gc,
424 						x * psize, (y+1) * psize,
425 						psize, psize);
426 				if (i & 8)
427 					XFillRectangle(display, pixmap, gc,
428 						(x+1) * psize, (y+1) * psize,
429 						psize, psize);
430 				if (i & 16)
431 					XFillRectangle(display, pixmap, gc,
432 						(x+2) * psize, y * psize,
433 						psize, psize);
434 				if (i & 32)
435 					XFillRectangle(display, pixmap, gc,
436 						(x+3) * psize, y * psize,
437 						psize, psize);
438 				if (i & 64)
439 					XFillRectangle(display, pixmap, gc,
440 						(x+2) * psize, (y+1) * psize,
441 						psize, psize);
442 				if (i & 128)
443 					XFillRectangle(display, pixmap, gc,
444 						(x+3) * psize, (y+1) * psize,
445 						psize, psize);
446 				x += 4;
447 				addr++;
448 			}
449 		}
450 	}
451 }
452 
453 /* draw pixels for one frame in lowres */
draw_lowres(void)454 static void draw_lowres(void)
455 {
456 	int psize, x, y, i;
457 	WORD addr = dma_addr;
458 
459 	/* get size of DMA memory and draw the pixels */
460 	if (format & 32) {	/* 2048 bytes memory */
461 		psize = size / 64;	/* size of one pixel for 64x64 */
462 		for (y = 0; y < 32; y++) {
463 			for (x = 0; x < 32;) {
464 				i = dma_read(addr) & 0x0f;
465 				if (format & 16)
466 					XSetForeground(display, gc,
467 							colors[i].pixel);
468 				else
469 					XSetForeground(display, gc,
470 							grays[i].pixel);
471 				XFillRectangle(display, pixmap, gc,
472 					x * psize, y * psize,
473 					psize, psize);
474 				x++;
475 				i = (dma_read(addr) & 0xf0) >> 4;
476 				if (format & 16)
477 					XSetForeground(display, gc,
478 							colors[i].pixel);
479 				else
480 					XSetForeground(display, gc,
481 							grays[i].pixel);
482 				XFillRectangle(display, pixmap, gc,
483 					x * psize, y * psize,
484 					psize, psize);
485 				x++;
486 				addr++;
487 			}
488 		}
489 		for (y = 0; y < 32; y++) {
490 			for (x = 32; x < 64;) {
491 				i = dma_read(addr) & 0x0f;
492 				if (format & 16)
493 					XSetForeground(display, gc,
494 							colors[i].pixel);
495 				else
496 					XSetForeground(display, gc,
497 							grays[i].pixel);
498 				XFillRectangle(display, pixmap, gc,
499 					x * psize, y * psize,
500 					psize, psize);
501 				x++;
502 				i = (dma_read(addr) & 0xf0) >> 4;
503 				if (format & 16)
504 					XSetForeground(display, gc,
505 							colors[i].pixel);
506 				else
507 					XSetForeground(display, gc,
508 							grays[i].pixel);
509 				XFillRectangle(display, pixmap, gc,
510 					x * psize, y * psize,
511 					psize, psize);
512 				x++;
513 				addr++;
514 			}
515 		}
516 		for (y = 32; y < 64; y++) {
517 			for (x = 0; x < 32;) {
518 				i = dma_read(addr) & 0x0f;
519 				if (format & 16)
520 					XSetForeground(display, gc,
521 							colors[i].pixel);
522 				else
523 					XSetForeground(display, gc,
524 							grays[i].pixel);
525 				XFillRectangle(display, pixmap, gc,
526 					x * psize, y * psize,
527 					psize, psize);
528 				x++;
529 				i = (dma_read(addr) & 0xf0) >> 4;
530 				if (format & 16)
531 					XSetForeground(display, gc,
532 							colors[i].pixel);
533 				else
534 					XSetForeground(display, gc,
535 							grays[i].pixel);
536 				XFillRectangle(display, pixmap, gc,
537 					x * psize, y * psize,
538 					psize, psize);
539 				x++;
540 				addr++;
541 			}
542 		}
543 		for (y = 32; y < 64; y++) {
544 			for (x = 32; x < 64;) {
545 				i = dma_read(addr) & 0x0f;
546 				if (format & 16)
547 					XSetForeground(display, gc,
548 							colors[i].pixel);
549 				else
550 					XSetForeground(display, gc,
551 							grays[i].pixel);
552 				XFillRectangle(display, pixmap, gc,
553 					x * psize, y * psize,
554 					psize, psize);
555 				x++;
556 				i = (dma_read(addr) & 0xf0) >> 4;
557 				if (format & 16)
558 					XSetForeground(display, gc,
559 							colors[i].pixel);
560 				else
561 					XSetForeground(display, gc,
562 							grays[i].pixel);
563 				XFillRectangle(display, pixmap, gc,
564 					x * psize, y * psize,
565 					psize, psize);
566 				x++;
567 				addr++;
568 			}
569 		}
570 	} else {		/* 512 bytes memory */
571 		psize = size / 32;	/* size of one pixel for 32x32 */
572 		for (y = 0; y < 32; y++) {
573 			for (x = 0; x < 32;) {
574 				i = dma_read(addr) & 0x0f;
575 				if (format & 16)
576 					XSetForeground(display, gc,
577 							colors[i].pixel);
578 				else
579 					XSetForeground(display, gc,
580 							grays[i].pixel);
581 				XFillRectangle(display, pixmap, gc,
582 					x * psize, y * psize,
583 					psize, psize);
584 				x++;
585 				i = (dma_read(addr) & 0xf0) >> 4;
586 				if (format & 16)
587 					XSetForeground(display, gc,
588 							colors[i].pixel);
589 				else
590 					XSetForeground(display, gc,
591 							grays[i].pixel);
592 				XFillRectangle(display, pixmap, gc,
593 					x * psize, y * psize,
594 					psize, psize);
595 				x++;
596 				addr++;
597 			}
598 		}
599 	}
600 }
601 
602 #ifdef HAS_NETSERVER
603 static uint8_t dblbuf[2048];
604 
605 static struct {
606 	uint16_t format;
607 	uint16_t addr;
608 	uint16_t len;
609 	uint8_t buf[2048];
610 } msg;
611 
ws_clear(void)612 void ws_clear(void)
613 {
614 	memset(dblbuf, 0, 2048);
615 
616 	msg.format = 0;
617 	msg.addr = 0xFFFF;
618 	msg.len = 0;
619 	net_device_send(DEV_DZLR, (char *) &msg, msg.len + 6);
620 	LOGD(TAG, "Clear the screen.");
621 }
622 
ws_refresh(void)623 static void ws_refresh(void)
624 {
625 
626 	int len = (format & 32) ? 2048 : 512;
627 	int addr;
628 	int i, n, x, la_count;
629 	bool cont;
630 	uint8_t val;
631 
632 	for (i = 0; i < len; i++) {
633 		addr = i;
634 		n = 0;
635 		la_count = 0;
636 		cont = true;
637 		while (cont && (i < len)) {
638 			val = dma_read(dma_addr + i);
639 			while ((val != dblbuf[i]) && (i < len)) {
640 				dblbuf[i++] = val;
641 				msg.buf[n++] = val;
642 				cont = false;
643 				val = dma_read(dma_addr + i);
644 			}
645 			if (cont)
646 				break;
647 			x = 0;
648 #define LOOKAHEAD 6
649 			/* look-ahead up to n bytes for next change */
650 			while ((x < LOOKAHEAD) && !cont && (i < len)) {
651 				val = dma_read(dma_addr + i++);
652 				msg.buf[n++] = val;
653 				la_count++;
654 				val = dma_read(dma_addr + i);
655 				if ((i < len) && (val != dblbuf[i])) {
656 					cont = true;
657 				}
658 				x++;
659 			}
660 			if (!cont) {
661 				n -= x;
662 				la_count -= x;
663 			}
664 		}
665 		if (n || (format != formatBuf)) {
666 			formatBuf = format;
667 			msg.format = format;
668 			msg.addr = addr;
669 			msg.len = n;
670 			net_device_send(DEV_DZLR, (char *) &msg, msg.len + 6);
671 			LOGD(TAG, "BUF update 0x%04X-0x%04X len: %d format: 0x%02X l/a: %d",
672 			     msg.addr, msg.addr + msg.len, msg.len, msg.format, la_count);
673 		}
674 	}
675 }
676 #endif
677 
678 /* thread for updating the display */
update_display(void * arg)679 static void *update_display(void *arg)
680 {
681 	extern int time_diff(struct timeval *, struct timeval *);
682 
683 	struct timeval t1, t2;
684 	int tdiff;
685 
686 	arg = arg;	/* to avoid compiler warning */
687 	gettimeofday(&t1, NULL);
688 
689 	while (1) {	/* do forever or until canceled */
690 
691 		/* draw one frame dependend on graphics format */
692 		if (state == 1) {	/* draw frame if on */
693 #ifndef HAS_NETSERVER
694 			XLockDisplay(display);
695 			XSetForeground(display, gc, colors[0].pixel);
696 			XFillRectangle(display, pixmap, gc, 0, 0, size, size);
697 			if (format & 64)
698 				draw_hires();
699 			else
700 				draw_lowres();
701 			XCopyArea(display, pixmap, window, gc, 0, 0,
702 				  size, size, 0, 0);
703 			XSync(display, True);
704 			XUnlockDisplay(display);
705 #else
706 			UNUSED(draw_hires);
707 			UNUSED(draw_lowres);
708 			if (net_device_alive(DEV_DZLR)) {
709 				ws_refresh();
710 			} else {
711 				if (msg.format) {
712 					memset(dblbuf, 0, 2048);
713 					msg.format = 0;
714 				}
715 			}
716 #endif
717 		}
718 
719 		/* frame done, set frame flag for 4ms */
720 		flags = 0;
721 		SLEEP_MS(4);
722 		flags = 64;
723 
724 		/* sleep rest to 33ms so that we get 30 fps */
725 		gettimeofday(&t2, NULL);
726 		tdiff = time_diff(&t1, &t2);
727 		if ((tdiff > 0) && (tdiff < 33000))
728 			SLEEP_MS(33 - (tdiff / 1000));
729 
730 		gettimeofday(&t1, NULL);
731 	}
732 
733 	/* just in case it ever gets here */
734 	pthread_exit(NULL);
735 }
736 
cromemco_dazzler_ctl_out(BYTE data)737 void cromemco_dazzler_ctl_out(BYTE data)
738 {
739 	/* get DMA address for display memory */
740 	dma_addr = (data & 0x7f) << 9;
741 
742 	/* switch DAZZLER on/off */
743 	if (data & 128) {
744 #ifndef HAS_NETSERVER
745 		state = 1;
746 		if (display == NULL) {
747 			open_display();
748 		}
749 #else
750 		UNUSED(open_display);
751 		if (state == 0)
752 			ws_clear();
753 		state = 1;
754 #endif
755 		if (thread == 0) {
756 			if (pthread_create(&thread, NULL, update_display,
757 			    (void *) NULL)) {
758 				LOGE(TAG, "can't create thread");
759 				exit(1);
760 			}
761 		}
762 	} else {
763 		if (state == 1) {
764 			state = 0;
765 			SLEEP_MS(50);
766 #ifndef HAS_NETSERVER
767 			XLockDisplay(display);
768 			XClearWindow(display, window);
769 			XSync(display, True);
770 			XUnlockDisplay(display);
771 #else
772 			ws_clear();
773 #endif
774 		}
775 	}
776 }
777 
cromemco_dazzler_flags_in(void)778 BYTE cromemco_dazzler_flags_in(void)
779 {
780 	if (thread != 0)
781 		return(flags);
782 	else
783 		return((BYTE) 0xff);
784 }
785 
cromemco_dazzler_format_out(BYTE data)786 void cromemco_dazzler_format_out(BYTE data)
787 {
788 	format = data;
789 }
790 
791 #endif /* HAS_DAZZLER */
792