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