1 /*
2 * This file is part of x48, an emulator of the HP-48sx Calculator.
3 * Copyright (C) 1994 Eddie C. Dost (ecd@dressler.de)
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 /* $Log: lcd.c,v $
21 * Revision 1.13 1995/01/11 18:20:01 ecd
22 * major update to support HP48 G/GX
23 *
24 * Revision 1.12 1994/12/08 22:14:50 ecd
25 * fixed bug with XShmPutImage causing errors in init_display
26 *
27 * Revision 1.11 1994/12/07 20:20:50 ecd
28 * added support for icon colors
29 *
30 * Revision 1.10 1994/11/28 02:00:51 ecd
31 * added support for colors on icon
32 *
33 * Revision 1.9 1994/11/02 14:44:28 ecd
34 * minor fixes
35 *
36 * Revision 1.8 1994/10/09 20:32:02 ecd
37 * implemented bit offset stuff.
38 *
39 * Revision 1.7 1994/10/06 16:30:05 ecd
40 * added Shared Memory stuff
41 *
42 * Revision 1.6 1994/10/05 08:36:44 ecd
43 * pixmaps for nibble updates
44 *
45 * Revision 1.5 1994/09/30 12:37:09 ecd
46 * new display code makes x48 a lot faster
47 *
48 * Revision 1.4 1994/09/18 15:29:22 ecd
49 * turned off unused rcsid message
50 *
51 * Revision 1.3 1994/09/13 16:57:00 ecd
52 * changed to plain X11
53 *
54 * Revision 1.2 1994/08/31 18:23:21 ecd
55 * changed display initialization.
56 *
57 * Revision 1.1 1994/08/26 11:09:02 ecd
58 * Initial revision
59 *
60 * $Id: lcd.c,v 1.13 1995/01/11 18:20:01 ecd Exp ecd $
61 */
62
63
64 #include "global.h"
65
66 #include <stdio.h>
67 #include <unistd.h>
68 #include <string.h>
69 #ifdef SUNOS
70 #include <memory.h>
71 #endif
72 #include <X11/Xlib.h>
73 #include <X11/Xutil.h>
74
75 #include "hp48.h"
76 #include "hp48_emu.h"
77 #include "x48_x11.h"
78 #include "annunc.h"
79 #include "device.h"
80
81 static int last_annunc_state = -1;
82
83 display_t display;
84
85 #define DISP_ROWS 64
86
87 #define NIBS_PER_BUFFER_ROW (NIBBLES_PER_ROW + 2)
88
89 unsigned char disp_buf[DISP_ROWS][NIBS_PER_BUFFER_ROW];
90 unsigned char lcd_buffer[DISP_ROWS][NIBS_PER_BUFFER_ROW];
91
92 Pixmap nibble_maps[16];
93
94 unsigned char nibbles[16][2] =
95 {
96 { 0x00, 0x00 }, /* ---- */
97 { 0x03, 0x03 }, /* *--- */
98 { 0x0c, 0x0c }, /* -*-- */
99 { 0x0f, 0x0f }, /* **-- */
100 { 0x30, 0x30 }, /* --*- */
101 { 0x33, 0x33 }, /* *-*- */
102 { 0x3c, 0x3c }, /* -**- */
103 { 0x3f, 0x3f }, /* ***- */
104 { 0xc0, 0xc0 }, /* ---* */
105 { 0xc3, 0xc3 }, /* *--* */
106 { 0xcc, 0xcc }, /* -*-* */
107 { 0xcf, 0xcf }, /* **-* */
108 { 0xf0, 0xf0 }, /* --** */
109 { 0xf3, 0xf3 }, /* *-** */
110 { 0xfc, 0xfc }, /* -*** */
111 { 0xff, 0xff } /* **** */
112 };
113
114 static unsigned char nibble_bits[16];
115
116 void
117 #ifdef __FunctionProto__
init_nibble_maps(void)118 init_nibble_maps(void)
119 #else
120 init_nibble_maps()
121 #endif
122 {
123 int i;
124
125 for (i = 0; i < 16; i++) {
126 nibble_maps[i] = XCreateBitmapFromData(dpy, disp.win,
127 (char *)nibbles[i], 8, 2);
128 }
129 #ifdef HAVE_XSHM
130 if (shm_flag) {
131 if (disp.disp_image->bitmap_bit_order == MSBFirst) {
132 nibble_bits[0x0] = 0x00; /* ---- */
133 nibble_bits[0x1] = 0xc0; /* *--- */
134 nibble_bits[0x2] = 0x30; /* -*-- */
135 nibble_bits[0x3] = 0xf0; /* **-- */
136 nibble_bits[0x4] = 0x0c; /* --*- */
137 nibble_bits[0x5] = 0xcc; /* *-*- */
138 nibble_bits[0x6] = 0x3c; /* -**- */
139 nibble_bits[0x7] = 0xfc; /* ***- */
140 nibble_bits[0x8] = 0x03; /* ---* */
141 nibble_bits[0x9] = 0xc3; /* *--* */
142 nibble_bits[0xa] = 0x33; /* -*-* */
143 nibble_bits[0xb] = 0xf3; /* **-* */
144 nibble_bits[0xc] = 0x0f; /* --** */
145 nibble_bits[0xd] = 0xcf; /* *-** */
146 nibble_bits[0xe] = 0x3f; /* -*** */
147 nibble_bits[0xf] = 0xff; /* **** */
148 } else {
149 nibble_bits[0x0] = 0x00; /* ---- */
150 nibble_bits[0x1] = 0x03; /* *--- */
151 nibble_bits[0x2] = 0x0c; /* -*-- */
152 nibble_bits[0x3] = 0x0f; /* **-- */
153 nibble_bits[0x4] = 0x30; /* --*- */
154 nibble_bits[0x5] = 0x33; /* *-*- */
155 nibble_bits[0x6] = 0x3c; /* -**- */
156 nibble_bits[0x7] = 0x3f; /* ***- */
157 nibble_bits[0x8] = 0xc0; /* ---* */
158 nibble_bits[0x9] = 0xc3; /* *--* */
159 nibble_bits[0xa] = 0xcc; /* -*-* */
160 nibble_bits[0xb] = 0xcf; /* **-* */
161 nibble_bits[0xc] = 0xf0; /* --** */
162 nibble_bits[0xd] = 0xf3; /* *-** */
163 nibble_bits[0xe] = 0xfc; /* -*** */
164 nibble_bits[0xf] = 0xff; /* **** */
165 }
166 }
167 #endif
168 }
169
170 void
171 #ifdef __FunctionProto__
init_display(void)172 init_display(void)
173 #else
174 init_display()
175 #endif
176 {
177 display.on = (int)(saturn.disp_io & 0x8) >> 3;
178
179 display.disp_start = (saturn.disp_addr & 0xffffe);
180 display.offset = (saturn.disp_io & 0x7);
181 disp.offset = 2 * display.offset;
182
183 display.lines = (saturn.line_count & 0x3f);
184 if (display.lines == 0)
185 display.lines = 63;
186 disp.lines = 2 * display.lines;
187 if (disp.lines < 110)
188 disp.lines = 110;
189
190 if (display.offset > 3)
191 display.nibs_per_line = (NIBBLES_PER_ROW+saturn.line_offset+2) & 0xfff;
192 else
193 display.nibs_per_line = (NIBBLES_PER_ROW+saturn.line_offset) & 0xfff;
194
195 display.disp_end = display.disp_start +
196 (display.nibs_per_line * (display.lines + 1));
197
198 display.menu_start = saturn.menu_addr;
199 display.menu_end = saturn.menu_addr + 0x110;
200
201 display.contrast = saturn.contrast_ctrl;
202 display.contrast |= ((saturn.disp_test & 0x1) << 4);
203
204 display.annunc = saturn.annunc;
205
206 memset(disp_buf, 0xf0, sizeof(disp_buf));
207 memset(lcd_buffer, 0xf0, sizeof(lcd_buffer));
208
209 init_nibble_maps();
210 }
211
212 static inline void
213 #ifdef __FunctionProto__
draw_nibble(int c,int r,int val)214 draw_nibble(int c, int r, int val)
215 #else
216 draw_nibble(c, r, val)
217 int c;
218 int r;
219 int val;
220 #endif
221 {
222 int x, y;
223
224 x = (c * 8) + 5;
225 if (r <= display.lines)
226 x -= disp.offset;
227 y = (r * 2) + 20;
228 val &= 0x0f;
229 if (val != lcd_buffer[r][c]) {
230 XCopyPlane(dpy, nibble_maps[val], disp.win, disp.gc, 0, 0, 8, 2, x, y, 1);
231 lcd_buffer[r][c] = val;
232 }
233 }
234
235 static inline void
236 #ifdef __FunctionProto__
draw_row(long addr,int row)237 draw_row(long addr, int row)
238 #else
239 draw_row(addr, row)
240 long addr;
241 int row;
242 #endif
243 {
244 int i, v;
245 int line_length;
246
247 line_length = NIBBLES_PER_ROW;
248 if ((display.offset > 3) && (row <= display.lines))
249 line_length += 2;
250 for (i = 0; i < line_length; i++) {
251 v = read_nibble(addr + i);
252 if (v != disp_buf[row][i]) {
253 disp_buf[row][i] = v;
254 draw_nibble(i, row, v);
255 }
256 }
257 }
258
259 void
260 #ifdef __FunctionProto__
update_display(void)261 update_display(void)
262 #else
263 update_display()
264 #endif
265 {
266 int i, j;
267 long addr;
268 static int old_offset = -1;
269 static int old_lines = -1;
270 #ifdef HAVE_XSHM
271 int addr_pad;
272 int val, line_pad, line_length;
273 word_20 data_addr, data_addr_2;
274 #endif
275
276 if (!disp.mapped)
277 {
278 refresh_icon();
279 return;
280 }
281 if (display.on) {
282 addr = display.disp_start;
283 #ifdef HAVE_XSHM
284 if (shm_flag) {
285 data_addr = 0;
286 data_addr_2 = disp.disp_image->bytes_per_line;
287 line_length = NIBBLES_PER_ROW;
288 if (display.offset > 3)
289 line_length += 2;
290 line_pad = 2 * disp.disp_image->bytes_per_line - line_length;
291 addr_pad = display.nibs_per_line - line_length;
292 for (i = 0; i <= display.lines; i++) {
293 for (j = 0; j < line_length; j++) {
294 val = read_nibble(addr++);
295 disp.disp_image->data[data_addr++] = nibble_bits[val];
296 disp.disp_image->data[data_addr_2++] = nibble_bits[val];
297 }
298 addr += addr_pad;
299 data_addr += line_pad;
300 data_addr_2 += line_pad;
301 }
302 disp.display_update |= UPDATE_DISP;
303 } else {
304 #endif
305 if (display.offset != old_offset) {
306 memset(disp_buf, 0xf0,
307 (size_t)((display.lines+1) * NIBS_PER_BUFFER_ROW));
308 memset(lcd_buffer, 0xf0,
309 (size_t)((display.lines+1) * NIBS_PER_BUFFER_ROW));
310 old_offset = display.offset;
311 }
312 if (display.lines != old_lines) {
313 memset(&disp_buf[56][0], 0xf0, (size_t)(8 * NIBS_PER_BUFFER_ROW));
314 memset(&lcd_buffer[56][0], 0xf0, (size_t)(8 * NIBS_PER_BUFFER_ROW));
315 old_lines = display.lines;
316 }
317 for (i = 0; i <= display.lines; i++) {
318 draw_row(addr, i);
319 addr += display.nibs_per_line;
320 }
321 #ifdef HAVE_XSHM
322 }
323 #endif
324 if (i < DISP_ROWS) {
325 addr = display.menu_start;
326 #ifdef HAVE_XSHM
327 if (shm_flag) {
328 data_addr = 0;
329 data_addr_2 = disp.menu_image->bytes_per_line;
330 line_pad = 2 * disp.menu_image->bytes_per_line - NIBBLES_PER_ROW;
331 for (; i < DISP_ROWS; i++) {
332 for (j = 0; j < NIBBLES_PER_ROW; j++) {
333 val = read_nibble(addr++);
334 disp.menu_image->data[data_addr++] = nibble_bits[val];
335 disp.menu_image->data[data_addr_2++] = nibble_bits[val];
336 }
337 data_addr += line_pad;
338 data_addr_2 += line_pad;
339 }
340 disp.display_update |= UPDATE_MENU;
341 } else {
342 #endif
343 for (; i < DISP_ROWS; i++) {
344 draw_row(addr, i);
345 addr += NIBBLES_PER_ROW;
346 }
347 #ifdef HAVE_XSHM
348 }
349 #endif
350 }
351 } else {
352 #ifdef HAVE_XSHM
353 if (shm_flag) {
354 memset(disp.disp_image->data, 0,
355 (size_t)(disp.disp_image->bytes_per_line * disp.disp_image->height));
356 memset(disp.menu_image->data, 0,
357 (size_t)(disp.menu_image->bytes_per_line * disp.menu_image->height));
358 disp.display_update = UPDATE_DISP | UPDATE_MENU;
359 } else {
360 #endif
361 memset(disp_buf, 0xf0, sizeof(disp_buf));
362 for (i = 0; i < 64; i++) {
363 for (j = 0; j < NIBBLES_PER_ROW; j++) {
364 draw_nibble(j, i, 0x00);
365 }
366 }
367 #ifdef HAVE_XSHM
368 }
369 #endif
370 }
371 }
372
373 void
374 #ifdef __FunctionProto__
redraw_display(void)375 redraw_display(void)
376 #else
377 redraw_display()
378 #endif
379 {
380 XClearWindow(dpy, disp.win);
381 memset(disp_buf, 0, sizeof(disp_buf));
382 memset(lcd_buffer, 0, sizeof(lcd_buffer));
383 update_display();
384 }
385
386 void
387 #ifdef __FunctionProto__
disp_draw_nibble(word_20 addr,word_4 val)388 disp_draw_nibble(word_20 addr, word_4 val)
389 #else
390 disp_draw_nibble(addr, val)
391 word_20 addr;
392 word_4 val;
393 #endif
394 {
395 long offset;
396 #ifdef HAVE_XSHM
397 int shm_addr;
398 #endif
399 int x, y;
400
401 offset = (addr - display.disp_start);
402 x = offset % display.nibs_per_line;
403 if (x < 0 || x > 35)
404 return;
405 if (display.nibs_per_line != 0) {
406 y = offset / display.nibs_per_line;
407 if (y < 0 || y > 63)
408 return;
409 #ifdef HAVE_XSHM
410 if (shm_flag) {
411 shm_addr = (2 * y * disp.disp_image->bytes_per_line) + x;
412 disp.disp_image->data[shm_addr] = nibble_bits[val];
413 disp.disp_image->data[shm_addr+disp.disp_image->bytes_per_line] =
414 nibble_bits[val];
415 disp.display_update |= UPDATE_DISP;
416 } else {
417 #endif
418 if (val != disp_buf[y][x]) {
419 disp_buf[y][x] = val;
420 draw_nibble(x, y, val);
421 }
422 #ifdef HAVE_XSHM
423 }
424 #endif
425 } else {
426 #ifdef HAVE_XSHM
427 if (shm_flag) {
428 shm_addr = x;
429 for (y = 0; y < display.lines; y++) {
430 disp.disp_image->data[shm_addr] = nibble_bits[val];
431 shm_addr += disp.disp_image->bytes_per_line;
432 disp.disp_image->data[shm_addr]
433 = nibble_bits[val];
434 shm_addr += disp.disp_image->bytes_per_line;
435 }
436 disp.display_update |= UPDATE_DISP;
437 } else {
438 #endif
439 for (y = 0; y < display.lines; y++) {
440 if (val != disp_buf[y][x]) {
441 disp_buf[y][x] = val;
442 draw_nibble(x, y, val);
443 }
444 }
445 #ifdef HAVE_XSHM
446 }
447 #endif
448 }
449 }
450
451 void
452 #ifdef __FunctionProto__
menu_draw_nibble(word_20 addr,word_4 val)453 menu_draw_nibble(word_20 addr, word_4 val)
454 #else
455 menu_draw_nibble(addr, val)
456 word_20 addr;
457 word_4 val;
458 #endif
459 {
460 long offset;
461 #ifdef HAVE_XSHM
462 int shm_addr;
463 #endif
464 int x, y;
465
466 offset = (addr - display.menu_start);
467 #ifdef HAVE_XSHM
468 if (shm_flag) {
469 shm_addr = 2 * (offset / NIBBLES_PER_ROW) * disp.menu_image->bytes_per_line
470 + (offset % NIBBLES_PER_ROW);
471 disp.menu_image->data[shm_addr] = nibble_bits[val];
472 disp.menu_image->data[shm_addr+disp.menu_image->bytes_per_line] =
473 nibble_bits[val];
474 disp.display_update |= UPDATE_MENU;
475 } else {
476 #endif
477 x = offset % NIBBLES_PER_ROW;
478 y = display.lines + (offset / NIBBLES_PER_ROW) + 1;
479 if (val != disp_buf[y][x]) {
480 disp_buf[y][x] = val;
481 draw_nibble(x, y, val);
482 }
483 #ifdef HAVE_XSHM
484 }
485 #endif
486 }
487
488
489 struct ann_struct {
490 int bit;
491 int x;
492 int y;
493 unsigned int width;
494 unsigned int height;
495 unsigned char *bits;
496 Pixmap pixmap;
497 } ann_tbl[] = {
498 { ANN_LEFT, 16, 4, ann_left_width, ann_left_height, ann_left_bits },
499 { ANN_RIGHT, 61, 4, ann_right_width, ann_right_height, ann_right_bits },
500 { ANN_ALPHA, 106, 4, ann_alpha_width, ann_alpha_height, ann_alpha_bits },
501 { ANN_BATTERY, 151, 4, ann_battery_width, ann_battery_height,
502 ann_battery_bits },
503 { ANN_BUSY, 196, 4, ann_busy_width, ann_busy_height, ann_busy_bits },
504 { ANN_IO, 241, 4, ann_io_width, ann_io_height, ann_io_bits },
505 { 0 }
506 };
507
508 void
509 #ifdef __FunctionProto__
draw_annunc(void)510 draw_annunc(void)
511 #else
512 draw_annunc()
513 #endif
514 {
515 int val;
516 int i;
517
518 val = display.annunc;
519
520 if (val == last_annunc_state)
521 return;
522 last_annunc_state = val;
523 for (i = 0; ann_tbl[i].bit; i++)
524 {
525 if ((ann_tbl[i].bit & val) == ann_tbl[i].bit)
526 {
527 XCopyPlane(dpy, ann_tbl[i].pixmap, disp.win, disp.gc, 0, 0,
528 ann_tbl[i].width, ann_tbl[i].height,
529 ann_tbl[i].x, ann_tbl[i].y, 1);
530 }
531 else
532 {
533 XClearArea(dpy, disp.win, ann_tbl[i].x, ann_tbl[i].y,
534 ann_tbl[i].width, ann_tbl[i].height, False);
535 }
536 }
537 refresh_icon();
538 }
539
540 void
541 #ifdef __FunctionProto__
redraw_annunc(void)542 redraw_annunc(void)
543 #else
544 redraw_annunc()
545 #endif
546 {
547 last_annunc_state = -1;
548 draw_annunc();
549 }
550
551 void
552 #ifdef __FunctionProto__
init_annunc(void)553 init_annunc(void)
554 #else
555 init_annunc()
556 #endif
557 {
558 int i;
559
560 for (i = 0; ann_tbl[i].bit; i++) {
561 ann_tbl[i].pixmap = XCreateBitmapFromData(dpy, disp.win,
562 (char *)ann_tbl[i].bits,
563 ann_tbl[i].width,
564 ann_tbl[i].height);
565 }
566 }
567
568