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