/[gxemul]/upstream/0.4.0.1/src/devices/dev_bt459.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /upstream/0.4.0.1/src/devices/dev_bt459.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 27 - (show annotations)
Mon Oct 8 16:20:18 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 15477 byte(s)
0.4.0.1
1 /*
2 * Copyright (C) 2003-2006 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: dev_bt459.c,v 1.64 2006/03/04 12:38:47 debug Exp $
29 *
30 * Brooktree 459 vdac, used by TURBOchannel graphics cards.
31 */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include "cpu.h"
38 #include "devices.h"
39 #include "machine.h"
40 #include "memory.h"
41 #include "misc.h"
42 #include "x11.h"
43
44 #include "bt459.h"
45
46
47 #ifdef WITH_X11
48 #include <X11/Xlib.h>
49 #include <X11/Xutil.h>
50 #endif
51
52 extern int quiet_mode;
53
54
55 /* #define BT459_DEBUG */
56 /* #define WITH_CURSOR_DEBUG */
57 #define BT459_TICK_SHIFT 14
58
59 struct bt459_data {
60 uint32_t bt459_reg[DEV_BT459_NREGS];
61
62 unsigned char cur_addr_hi;
63 unsigned char cur_addr_lo;
64
65 int planes;
66 int type;
67
68 int irq_nr;
69 int interrupts_enable;
70 int interrupt_time;
71 int interrupt_time_reset_value;
72
73 int cursor_x_add;
74 int cursor_y_add;
75
76 int need_to_redraw_whole_screen;
77
78 int need_to_update_cursor_shape;
79 int cursor_on;
80 int cursor_x;
81 int cursor_y;
82 int cursor_xsize;
83 int cursor_ysize;
84
85 int palette_sub_offset; /* 0, 1, or 2 */
86
87 struct vfb_data *vfb_data;
88
89 /*
90 * There is one pointer to the framebuffer's RGB palette,
91 * and then a local copy of the palette. 256 * 3 bytes (r,g,b).
92 * The reason for this is that when we need to blank the screen
93 * (ie video_on = 0), we can set the framebuffer's palette to all
94 * zeroes, but keep our own copy intact, to be reused later again
95 * when the screen is unblanked.
96 */
97 int video_on;
98 unsigned char *rgb_palette; /* 256 * 3 (r,g,b) */
99 unsigned char local_rgb_palette[256 * 3];
100 };
101
102
103 /*
104 * bt459_update_X_cursor():
105 *
106 * This routine takes the color values in the cursor RAM area, and put them
107 * in the framebuffer window's cursor_pixels.
108 *
109 * d->cursor_xsize and ysize are also updated.
110 */
111 static void bt459_update_X_cursor(struct cpu *cpu, struct bt459_data *d)
112 {
113 int i, x,y, xmax=0, ymax=0;
114 int bw_only = 1;
115
116 /* First, let's calculate the size of the cursor: */
117 for (y=0; y<64; y++)
118 for (x=0; x<64; x+=4) {
119 int reg = BT459_REG_CRAM_BASE + y*16 + x/4;
120 unsigned char data = d->bt459_reg[reg];
121
122 if (data)
123 ymax = y;
124
125 for (i=0; i<4; i++) {
126 int color = (data >> (6-2*i)) & 3;
127 if (color != 0)
128 xmax = x + i;
129 if (color != 0 && color != 3)
130 bw_only = 0;
131 }
132 }
133
134 d->cursor_xsize = xmax + 1;
135 d->cursor_ysize = ymax + 1;
136
137 /*
138 * The 'bw_only' hack is because it is nicer to have the b/w
139 * text cursor invert whatever it is standing on, not just overwrite
140 * it with a big white box.
141 *
142 * The following seems to work with NetBSD/OpenBSD/Ultrix/Sprite:
143 * 0 = transparent, 1 and 2 = use the color specified by
144 * BT459_REG_CCOLOR_2, 3 = reverse of color 1/2.
145 */
146
147 #ifdef WITH_X11
148 if (cpu->machine->use_x11 && d->vfb_data->fb_window != NULL) {
149 for (y=0; y<=ymax; y++) {
150 for (x=0; x<=xmax; x+=4) {
151 struct fb_window *win = d->vfb_data->fb_window;
152 int reg = BT459_REG_CRAM_BASE + y*16 + x/4;
153 unsigned char data = d->bt459_reg[reg];
154
155 for (i=0; i<4; i++) {
156 int color = (data >> (6-2*i)) & 3;
157 int pixelvalue;
158
159 if (bw_only) {
160 if (color)
161 pixelvalue =
162 CURSOR_COLOR_INVERT;
163 else
164 pixelvalue = 0;
165 } else {
166 pixelvalue =
167 CURSOR_COLOR_TRANSPARENT;
168 switch (color) {
169 case 1:
170 case 2: pixelvalue = (d->
171 bt459_reg[
172 BT459_REG_CCOLOR_2]
173 >> 4) & 0xf;
174 break;
175 case 3: pixelvalue = 15 -
176 ((d->bt459_reg[
177 BT459_REG_CCOLOR_2]
178 >> 4) & 0xf);
179 break;
180 }
181 }
182
183 win->cursor_pixels[y][x+i] =
184 pixelvalue;
185 #ifdef WITH_CURSOR_DEBUG
186 printf("%i", color);
187 #endif
188 }
189 }
190 #ifdef WITH_CURSOR_DEBUG
191 printf("\n");
192 #endif
193 }
194 #ifdef WITH_CURSOR_DEBUG
195 printf("color 1,2,3 = 0x%02x, 0x%02x, 0x%02x\n",
196 d->bt459_reg[BT459_REG_CCOLOR_1],
197 d->bt459_reg[BT459_REG_CCOLOR_2],
198 d->bt459_reg[BT459_REG_CCOLOR_3]);
199 printf("\n");
200 #endif
201 /*
202 * Make sure the cursor is redrawn, if it is on:
203 *
204 * How does this work? Well, 0 is off, and non-zero is on,
205 * but if the old and new differ, the cursor is redrawn.
206 * (Hopefully this will "never" overflow.)
207 */
208 if (d->cursor_on)
209 d->cursor_on ++;
210 }
211 #endif
212 }
213
214
215 /*
216 * bt459_update_cursor_position():
217 */
218 static void bt459_update_cursor_position(struct bt459_data *d,
219 int old_cursor_on)
220 {
221 int new_cursor_x = (d->bt459_reg[BT459_REG_CXLO] & 255) +
222 ((d->bt459_reg[BT459_REG_CXHI] & 255) << 8) - d->cursor_x_add;
223 int new_cursor_y = (d->bt459_reg[BT459_REG_CYLO] & 255) +
224 ((d->bt459_reg[BT459_REG_CYHI] & 255) << 8) - d->cursor_y_add;
225
226 if (new_cursor_x != d->cursor_x || new_cursor_y != d->cursor_y ||
227 d->cursor_on != old_cursor_on) {
228 int on;
229
230 d->cursor_x = new_cursor_x;
231 d->cursor_y = new_cursor_y;
232
233 if (!quiet_mode)
234 debug("[ bt459: cursor = %03i,%03i ]\n",
235 d->cursor_x, d->cursor_y);
236
237 on = d->cursor_on;
238 if (d->cursor_xsize == 0 || d->cursor_ysize == 0)
239 on = 0;
240
241 dev_fb_setcursor(d->vfb_data, d->cursor_x, d->cursor_y,
242 on, d->cursor_xsize, d->cursor_ysize);
243 }
244 }
245
246
247 /*
248 * dev_bt459_tick():
249 */
250 void dev_bt459_tick(struct cpu *cpu, void *extra)
251 {
252 struct bt459_data *d = extra;
253 int old_cursor_on = d->cursor_on;
254
255 if (d->need_to_update_cursor_shape) {
256 d->need_to_update_cursor_shape = 0;
257 bt459_update_X_cursor(cpu, d);
258 bt459_update_cursor_position(d, old_cursor_on);
259 }
260
261 if (d->need_to_redraw_whole_screen) {
262 d->vfb_data->update_x1 = 0;
263 d->vfb_data->update_x2 = d->vfb_data->xsize - 1;
264 d->vfb_data->update_y1 = 0;
265 d->vfb_data->update_y2 = d->vfb_data->ysize - 1;
266 d->need_to_redraw_whole_screen = 0;
267 }
268
269 /*
270 * Vertical retrace interrupts. (This hack is kind of ugly.)
271 * Once every 'interrupt_time_reset_value', the interrupt is
272 * asserted. It is acked either manually (by someone reading
273 * a normal BT459 register or the Interrupt ack register),
274 * or after another tick has passed. (This is to prevent
275 * lockups from unhandled interrupts.)
276 */
277 if (d->type != BT459_PX && d->interrupts_enable && d->irq_nr > 0) {
278 d->interrupt_time --;
279 if (d->interrupt_time < 0) {
280 d->interrupt_time = d->interrupt_time_reset_value;
281 cpu_interrupt(cpu, d->irq_nr);
282 } else
283 cpu_interrupt_ack(cpu, d->irq_nr);
284 }
285 }
286
287
288 /*
289 * dev_bt459_irq_access():
290 */
291 DEVICE_ACCESS(bt459_irq)
292 {
293 struct bt459_data *d = (struct bt459_data *) extra;
294 uint64_t idata = 0, odata = 0;
295
296 if (writeflag == MEM_WRITE)
297 idata = memory_readmax64(cpu, data, len);
298
299 #ifdef BT459_DEBUG
300 fatal("[ bt459: IRQ ack ]\n");
301 #endif
302
303 d->interrupts_enable = 1;
304 if (d->irq_nr > 0)
305 cpu_interrupt_ack(cpu, d->irq_nr);
306
307 if (writeflag == MEM_READ)
308 memory_writemax64(cpu, data, len, odata);
309
310 return 1;
311 }
312
313
314 /*
315 * dev_bt459_access():
316 */
317 DEVICE_ACCESS(bt459)
318 {
319 struct bt459_data *d = (struct bt459_data *) extra;
320 uint64_t idata = 0, odata = 0;
321 int btaddr, old_cursor_on = d->cursor_on, modified;
322
323 idata = memory_readmax64(cpu, data, len);
324
325 #ifdef BT459_DEBUG
326 if (writeflag == MEM_WRITE)
327 fatal("[ bt459: write to addr 0x%02x: %08x ]\n",
328 (int)relative_addr, (int)idata);
329 #endif
330
331 /*
332 * Vertical retrace interrupts are acked either by
333 * accessing a normal BT459 register, or the irq register,
334 * or by simply "missing" it.
335 */
336 if (d->irq_nr > 0)
337 cpu_interrupt_ack(cpu, d->irq_nr);
338
339 /* ID register is read-only, should always be 0x4a or 0x4a4a4a: */
340 if (d->planes == 24)
341 d->bt459_reg[BT459_REG_ID] = 0x4a4a4a;
342 else {
343 /*
344 * TODO: Is it really 0x4a, or 0x4a0000?
345 * Ultrix panics with a "bad VDAC ID" message if 0x4a
346 * is returned.
347 */
348 d->bt459_reg[BT459_REG_ID] = 0x4a0000;
349 }
350
351 btaddr = ((d->cur_addr_hi << 8) + d->cur_addr_lo) % DEV_BT459_NREGS;
352
353 /* Read from/write to the bt459: */
354 switch (relative_addr) {
355 case 0x00: /* Low byte of address: */
356 if (writeflag == MEM_WRITE) {
357 if (!quiet_mode)
358 debug("[ bt459: write to Low Address Byte, "
359 "0x%02x ]\n", (int)idata);
360 d->cur_addr_lo = idata;
361 d->palette_sub_offset = 0;
362 } else {
363 odata = d->cur_addr_lo;
364 if (!quiet_mode)
365 debug("[ bt459: read from Low Address Byte: "
366 "0x%0x ]\n", (int)odata);
367 }
368 break;
369 case 0x04: /* High byte of address: */
370 if (writeflag == MEM_WRITE) {
371 if (!quiet_mode)
372 debug("[ bt459: write to High Address Byte, "
373 "0x%02x ]\n", (int)idata);
374 d->cur_addr_hi = idata;
375 d->palette_sub_offset = 0;
376 } else {
377 odata = d->cur_addr_hi;
378 if (!quiet_mode)
379 debug("[ bt459: read from High Address Byte: "
380 "0x%0x ]\n", (int)odata);
381 }
382 break;
383 case 0x08: /* Register access: */
384 if (writeflag == MEM_WRITE) {
385 if (!quiet_mode)
386 debug("[ bt459: write to BT459 register "
387 "0x%04x, value 0x%02x ]\n", btaddr,
388 (int)idata);
389 modified = (d->bt459_reg[btaddr] != idata);
390 d->bt459_reg[btaddr] = idata;
391
392 switch (btaddr) {
393 case BT459_REG_CCOLOR_1:
394 case BT459_REG_CCOLOR_2:
395 case BT459_REG_CCOLOR_3:
396 if (modified)
397 d->need_to_update_cursor_shape = 1;
398 break;
399 case BT459_REG_PRM:
400 /*
401 * NetBSD writes 0x00 to this register to
402 * blank the screen (video off), and 0xff
403 * to turn the screen on.
404 */
405 switch (idata & 0xff) {
406 case 0: d->video_on = 0;
407 memset(d->rgb_palette, 0, 256*3);
408 d->need_to_redraw_whole_screen = 1;
409 debug("[ bt459: video OFF ]\n");
410 break;
411 default:d->video_on = 1;
412 memcpy(d->rgb_palette,
413 d->local_rgb_palette, 256*3);
414 d->need_to_redraw_whole_screen = 1;
415 debug("[ bt459: video ON ]\n");
416 }
417 break;
418 case BT459_REG_CCR:
419 /* Cursor control register: */
420 switch (idata & 0xff) {
421 case 0x00: d->cursor_on = 0; break;
422 case 0xc0:
423 case 0xc1: d->cursor_on = 1; break;
424 default:
425 fatal("[ bt459: unimplemented CCR "
426 "value 0x%08x ]\n", (int)idata);
427 }
428 if (modified)
429 d->need_to_update_cursor_shape = 1;
430 break;
431 default:
432 if (btaddr < 0x100)
433 fatal("[ bt459: write to BT459 "
434 "register 0x%04x, value 0x%02x ]\n",
435 btaddr, (int)idata);
436 }
437
438 /* Write to cursor bitmap: */
439 if (btaddr >= BT459_REG_CRAM_BASE && modified)
440 d->need_to_update_cursor_shape = 1;
441 } else {
442 odata = d->bt459_reg[btaddr];
443
444 /* Perhaps this hack is not necessary: */
445 if (btaddr == BT459_REG_ID && len==1)
446 odata = (odata >> 16) & 255;
447
448 if (!quiet_mode)
449 debug("[ bt459: read from BT459 register "
450 "0x%04x, value 0x%02x ]\n", btaddr,
451 (int)odata);
452 }
453
454 /* Go to next register: */
455 d->cur_addr_lo ++;
456 if (d->cur_addr_lo == 0)
457 d->cur_addr_hi ++;
458 break;
459 case 0xc: /* Color map: */
460 if (writeflag == MEM_WRITE) {
461 idata &= 255;
462 if (!quiet_mode)
463 debug("[ bt459: write to BT459 colormap "
464 "0x%04x subaddr %i, value 0x%02x ]\n",
465 btaddr, d->palette_sub_offset, (int)idata);
466
467 if (btaddr < 0x100) {
468 if (d->video_on &&
469 d->local_rgb_palette[(btaddr & 0xff) * 3
470 + d->palette_sub_offset] != idata)
471 d->need_to_redraw_whole_screen = 1;
472
473 /*
474 * Actually, the palette should only be
475 * updated after the third write,
476 * but this should probably work fine too:
477 */
478 d->local_rgb_palette[(btaddr & 0xff) * 3
479 + d->palette_sub_offset] = idata;
480
481 if (d->video_on)
482 d->rgb_palette[(btaddr & 0xff) * 3
483 + d->palette_sub_offset] = idata;
484 }
485 } else {
486 if (btaddr < 0x100)
487 odata = d->local_rgb_palette[(btaddr & 0xff)
488 * 3 + d->palette_sub_offset];
489 if (!quiet_mode)
490 debug("[ bt459: read from BT459 colormap "
491 "0x%04x subaddr %i, value 0x%02x ]\n",
492 btaddr, d->palette_sub_offset, (int)odata);
493 }
494
495 d->palette_sub_offset ++;
496 if (d->palette_sub_offset >= 3) {
497 d->palette_sub_offset = 0;
498
499 d->cur_addr_lo ++;
500 if (d->cur_addr_lo == 0)
501 d->cur_addr_hi ++;
502 }
503
504 break;
505 default:
506 if (writeflag == MEM_WRITE) {
507 debug("[ bt459: unimplemented write to address 0x%x, "
508 "data=0x%02x ]\n", (int)relative_addr, (int)idata);
509 } else {
510 debug("[ bt459: unimplemented read from address "
511 "0x%x ]\n", (int)relative_addr);
512 }
513 }
514
515
516 bt459_update_cursor_position(d, old_cursor_on);
517
518 if (writeflag == MEM_READ)
519 memory_writemax64(cpu, data, len, odata);
520
521 #ifdef BT459_DEBUG
522 if (writeflag == MEM_READ)
523 fatal("[ bt459: read from addr 0x%02x: %08x ]\n",
524 (int)relative_addr, (int)idata);
525 #endif
526
527 return 1;
528 }
529
530
531 /*
532 * dev_bt459_init():
533 */
534 void dev_bt459_init(struct machine *machine, struct memory *mem,
535 uint64_t baseaddr, uint64_t baseaddr_irq, struct vfb_data *vfb_data,
536 int planes, int irq_nr, int type)
537 {
538 struct bt459_data *d = malloc(sizeof(struct bt459_data));
539 if (d == NULL) {
540 fprintf(stderr, "out of memory\n");
541 exit(1);
542 }
543
544 memset(d, 0, sizeof(struct bt459_data));
545
546 d->vfb_data = vfb_data;
547 d->rgb_palette = vfb_data->rgb_palette;
548 d->planes = planes;
549 d->irq_nr = irq_nr;
550 d->type = type;
551 d->cursor_x = -1;
552 d->cursor_y = -1;
553 d->cursor_xsize = d->cursor_ysize = 0; /* anything */
554 d->video_on = 1;
555
556 /*
557 * These offsets are based on those mentioned in NetBSD,
558 * and then adjusted to look good with both NetBSD and
559 * Ultrix:
560 */
561 switch (d->type) {
562 case BT459_PX:
563 d->cursor_x_add = 370;
564 d->cursor_y_add = 37;
565 break;
566 case BT459_BA:
567 d->cursor_x_add = 220;
568 d->cursor_y_add = 35;
569 break;
570 case BT459_BBA:
571 if (vfb_data->xsize == 1280) {
572 /* 1280x1024: */
573 d->cursor_x_add = 368;
574 d->cursor_y_add = 38;
575 } else {
576 /* 1024x864: */
577 d->cursor_x_add = 220;
578 d->cursor_y_add = 35;
579 }
580 break;
581 }
582
583 d->interrupt_time_reset_value = 500;
584
585 memory_device_register(mem, "bt459", baseaddr, DEV_BT459_LENGTH,
586 dev_bt459_access, (void *)d, DM_DEFAULT, NULL);
587
588 if (baseaddr_irq != 0)
589 memory_device_register(mem, "bt459_irq", baseaddr_irq, 0x10000,
590 dev_bt459_irq_access, (void *)d, DM_DEFAULT, NULL);
591
592 machine_add_tickfunction(machine, dev_bt459_tick, d,
593 BT459_TICK_SHIFT, 0.0);
594 }
595

  ViewVC Help
Powered by ViewVC 1.1.26