1 |
/* |
2 |
* Copyright (C) 2003-2005 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.59 2005/02/22 12:15:29 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_state(): |
105 |
*/ |
106 |
int bt459_state(struct cpu *cpu, struct memory *mem, void *extra, int wf, |
107 |
int nr, int *type, char **namep, void **data, size_t *len) |
108 |
{ |
109 |
struct bt459_data *d = (struct bt459_data *) extra; |
110 |
|
111 |
switch (nr) { |
112 |
case 0: if (wf) { |
113 |
memcpy(&d->cursor_on, *data, *len); |
114 |
} else { |
115 |
(*namep) = "cursor_on"; |
116 |
(*type) = DEVICE_STATE_TYPE_INT; |
117 |
*len = sizeof(d->cursor_on); |
118 |
*data = &d->cursor_on; |
119 |
} |
120 |
break; |
121 |
case 1: if (wf) { |
122 |
memcpy(&d->cursor_x, *data, *len); |
123 |
} else { |
124 |
(*namep) = "cursor_x"; |
125 |
(*type) = DEVICE_STATE_TYPE_INT; |
126 |
*len = sizeof(d->cursor_x); |
127 |
*data = &d->cursor_x; |
128 |
} |
129 |
break; |
130 |
case 2: if (wf) { |
131 |
memcpy(&d->cursor_y, *data, *len); |
132 |
} else { |
133 |
(*namep) = "cursor_y"; |
134 |
(*type) = DEVICE_STATE_TYPE_INT; |
135 |
*len = sizeof(d->cursor_y); |
136 |
*data = &d->cursor_y; |
137 |
} |
138 |
break; |
139 |
case 3: if (wf) { |
140 |
memcpy(&d->cursor_xsize, *data, *len); |
141 |
} else { |
142 |
(*namep) = "cursor_xsize"; |
143 |
(*type) = DEVICE_STATE_TYPE_INT; |
144 |
*len = sizeof(d->cursor_xsize); |
145 |
*data = &d->cursor_xsize; |
146 |
} |
147 |
break; |
148 |
case 4: if (wf) { |
149 |
memcpy(&d->cursor_ysize, *data, *len); |
150 |
} else { |
151 |
(*namep) = "cursor_ysize"; |
152 |
(*type) = DEVICE_STATE_TYPE_INT; |
153 |
*len = sizeof(d->cursor_ysize); |
154 |
*data = &d->cursor_ysize; |
155 |
} |
156 |
break; |
157 |
default: |
158 |
return 0; |
159 |
} |
160 |
|
161 |
return 1; |
162 |
} |
163 |
|
164 |
|
165 |
/* |
166 |
* bt459_update_X_cursor(): |
167 |
* |
168 |
* This routine takes the color values in the cursor RAM area, and put them |
169 |
* in the framebuffer window's cursor_pixels. |
170 |
* |
171 |
* d->cursor_xsize and ysize are also updated. |
172 |
*/ |
173 |
static void bt459_update_X_cursor(struct cpu *cpu, struct bt459_data *d) |
174 |
{ |
175 |
int i, x,y, xmax=0, ymax=0; |
176 |
int bw_only = 1; |
177 |
|
178 |
/* First, let's calculate the size of the cursor: */ |
179 |
for (y=0; y<64; y++) |
180 |
for (x=0; x<64; x+=4) { |
181 |
int reg = BT459_REG_CRAM_BASE + y*16 + x/4; |
182 |
unsigned char data = d->bt459_reg[reg]; |
183 |
|
184 |
if (data) |
185 |
ymax = y; |
186 |
|
187 |
for (i=0; i<4; i++) { |
188 |
int color = (data >> (6-2*i)) & 3; |
189 |
if (color != 0) |
190 |
xmax = x + i; |
191 |
if (color != 0 && color != 3) |
192 |
bw_only = 0; |
193 |
} |
194 |
} |
195 |
|
196 |
d->cursor_xsize = xmax + 1; |
197 |
d->cursor_ysize = ymax + 1; |
198 |
|
199 |
/* |
200 |
* The 'bw_only' hack is because it is nicer to have the b/w |
201 |
* text cursor invert whatever it is standing on, not just overwrite |
202 |
* it with a big white box. |
203 |
* |
204 |
* The following seems to work with NetBSD/OpenBSD/Ultrix/Sprite: |
205 |
* 0 = transparent, 1 and 2 = use the color specified by |
206 |
* BT459_REG_CCOLOR_2, 3 = reverse of color 1/2. |
207 |
*/ |
208 |
|
209 |
#ifdef WITH_X11 |
210 |
if (cpu->machine->use_x11 && d->vfb_data->fb_window != NULL) { |
211 |
for (y=0; y<=ymax; y++) { |
212 |
for (x=0; x<=xmax; x+=4) { |
213 |
struct fb_window *win = d->vfb_data->fb_window; |
214 |
int reg = BT459_REG_CRAM_BASE + y*16 + x/4; |
215 |
unsigned char data = d->bt459_reg[reg]; |
216 |
|
217 |
for (i=0; i<4; i++) { |
218 |
int color = (data >> (6-2*i)) & 3; |
219 |
int pixelvalue; |
220 |
|
221 |
if (bw_only) { |
222 |
if (color) |
223 |
pixelvalue = |
224 |
CURSOR_COLOR_INVERT; |
225 |
else |
226 |
pixelvalue = 0; |
227 |
} else { |
228 |
pixelvalue = |
229 |
CURSOR_COLOR_TRANSPARENT; |
230 |
switch (color) { |
231 |
case 1: |
232 |
case 2: pixelvalue = (d-> |
233 |
bt459_reg[ |
234 |
BT459_REG_CCOLOR_2] |
235 |
>> 4) & 0xf; |
236 |
break; |
237 |
case 3: pixelvalue = 15 - |
238 |
((d->bt459_reg[ |
239 |
BT459_REG_CCOLOR_2] |
240 |
>> 4) & 0xf); |
241 |
break; |
242 |
} |
243 |
} |
244 |
|
245 |
win->cursor_pixels[y][x+i] = |
246 |
pixelvalue; |
247 |
#ifdef WITH_CURSOR_DEBUG |
248 |
printf("%i", color); |
249 |
#endif |
250 |
} |
251 |
} |
252 |
#ifdef WITH_CURSOR_DEBUG |
253 |
printf("\n"); |
254 |
#endif |
255 |
} |
256 |
#ifdef WITH_CURSOR_DEBUG |
257 |
printf("color 1,2,3 = 0x%02x, 0x%02x, 0x%02x\n", |
258 |
d->bt459_reg[BT459_REG_CCOLOR_1], |
259 |
d->bt459_reg[BT459_REG_CCOLOR_2], |
260 |
d->bt459_reg[BT459_REG_CCOLOR_3]); |
261 |
printf("\n"); |
262 |
#endif |
263 |
/* |
264 |
* Make sure the cursor is redrawn, if it is on: |
265 |
* |
266 |
* How does this work? Well, 0 is off, and non-zero is on, |
267 |
* but if the old and new differ, the cursor is redrawn. |
268 |
* (Hopefully this will "never" overflow.) |
269 |
*/ |
270 |
if (d->cursor_on) |
271 |
d->cursor_on ++; |
272 |
} |
273 |
#endif |
274 |
} |
275 |
|
276 |
|
277 |
/* |
278 |
* bt459_update_cursor_position(): |
279 |
*/ |
280 |
static void bt459_update_cursor_position(struct bt459_data *d, |
281 |
int old_cursor_on) |
282 |
{ |
283 |
int new_cursor_x = (d->bt459_reg[BT459_REG_CXLO] & 255) + |
284 |
((d->bt459_reg[BT459_REG_CXHI] & 255) << 8) - d->cursor_x_add; |
285 |
int new_cursor_y = (d->bt459_reg[BT459_REG_CYLO] & 255) + |
286 |
((d->bt459_reg[BT459_REG_CYHI] & 255) << 8) - d->cursor_y_add; |
287 |
|
288 |
if (new_cursor_x != d->cursor_x || new_cursor_y != d->cursor_y || |
289 |
d->cursor_on != old_cursor_on) { |
290 |
int on; |
291 |
|
292 |
d->cursor_x = new_cursor_x; |
293 |
d->cursor_y = new_cursor_y; |
294 |
|
295 |
if (!quiet_mode) |
296 |
debug("[ bt459: cursor = %03i,%03i ]\n", |
297 |
d->cursor_x, d->cursor_y); |
298 |
|
299 |
on = d->cursor_on; |
300 |
if (d->cursor_xsize == 0 || d->cursor_ysize == 0) |
301 |
on = 0; |
302 |
|
303 |
dev_fb_setcursor(d->vfb_data, d->cursor_x, d->cursor_y, |
304 |
on, d->cursor_xsize, d->cursor_ysize); |
305 |
} |
306 |
} |
307 |
|
308 |
|
309 |
/* |
310 |
* dev_bt459_tick(): |
311 |
*/ |
312 |
void dev_bt459_tick(struct cpu *cpu, void *extra) |
313 |
{ |
314 |
struct bt459_data *d = extra; |
315 |
int old_cursor_on = d->cursor_on; |
316 |
|
317 |
if (d->need_to_update_cursor_shape) { |
318 |
d->need_to_update_cursor_shape = 0; |
319 |
bt459_update_X_cursor(cpu, d); |
320 |
bt459_update_cursor_position(d, old_cursor_on); |
321 |
} |
322 |
|
323 |
if (d->need_to_redraw_whole_screen) { |
324 |
d->vfb_data->update_x1 = 0; |
325 |
d->vfb_data->update_x2 = d->vfb_data->xsize - 1; |
326 |
d->vfb_data->update_y1 = 0; |
327 |
d->vfb_data->update_y2 = d->vfb_data->ysize - 1; |
328 |
d->need_to_redraw_whole_screen = 0; |
329 |
} |
330 |
|
331 |
/* |
332 |
* Vertical retrace interrupts. (This hack is kind of ugly.) |
333 |
* Once every 'interrupt_time_reset_value', the interrupt is |
334 |
* asserted. It is acked either manually (by someone reading |
335 |
* a normal BT459 register or the Interrupt ack register), |
336 |
* or after another tick has passed. (This is to prevent |
337 |
* lockups from unhandled interrupts.) |
338 |
*/ |
339 |
if (d->type != BT459_PX && d->interrupts_enable && d->irq_nr > 0) { |
340 |
d->interrupt_time --; |
341 |
if (d->interrupt_time < 0) { |
342 |
d->interrupt_time = d->interrupt_time_reset_value; |
343 |
cpu_interrupt(cpu, d->irq_nr); |
344 |
} else |
345 |
cpu_interrupt_ack(cpu, d->irq_nr); |
346 |
} |
347 |
} |
348 |
|
349 |
|
350 |
/* |
351 |
* dev_bt459_irq_access(): |
352 |
*/ |
353 |
int dev_bt459_irq_access(struct cpu *cpu, struct memory *mem, |
354 |
uint64_t relative_addr, unsigned char *data, size_t len, |
355 |
int writeflag, void *extra) |
356 |
{ |
357 |
struct bt459_data *d = (struct bt459_data *) extra; |
358 |
uint64_t idata = 0, odata = 0; |
359 |
|
360 |
idata = memory_readmax64(cpu, data, len); |
361 |
|
362 |
#ifdef BT459_DEBUG |
363 |
fatal("[ bt459: IRQ ack ]\n"); |
364 |
#endif |
365 |
|
366 |
d->interrupts_enable = 1; |
367 |
if (d->irq_nr > 0) |
368 |
cpu_interrupt_ack(cpu, d->irq_nr); |
369 |
|
370 |
if (writeflag == MEM_READ) |
371 |
memory_writemax64(cpu, data, len, odata); |
372 |
|
373 |
return 1; |
374 |
} |
375 |
|
376 |
|
377 |
/* |
378 |
* dev_bt459_access(): |
379 |
*/ |
380 |
int dev_bt459_access(struct cpu *cpu, struct memory *mem, |
381 |
uint64_t relative_addr, unsigned char *data, size_t len, |
382 |
int writeflag, void *extra) |
383 |
{ |
384 |
struct bt459_data *d = (struct bt459_data *) extra; |
385 |
uint64_t idata = 0, odata = 0; |
386 |
int btaddr, old_cursor_on = d->cursor_on, modified; |
387 |
|
388 |
idata = memory_readmax64(cpu, data, len); |
389 |
|
390 |
#ifdef BT459_DEBUG |
391 |
if (writeflag == MEM_WRITE) |
392 |
fatal("[ bt459: write to addr 0x%02x: %08x ]\n", |
393 |
(int)relative_addr, (int)idata); |
394 |
#endif |
395 |
|
396 |
/* |
397 |
* Vertical retrace interrupts are acked either by |
398 |
* accessing a normal BT459 register, or the irq register, |
399 |
* or by simply "missing" it. |
400 |
*/ |
401 |
if (d->irq_nr > 0) |
402 |
cpu_interrupt_ack(cpu, d->irq_nr); |
403 |
|
404 |
/* ID register is read-only, should always be 0x4a or 0x4a4a4a: */ |
405 |
if (d->planes == 24) |
406 |
d->bt459_reg[BT459_REG_ID] = 0x4a4a4a; |
407 |
else { |
408 |
/* |
409 |
* TODO: Is it really 0x4a, or 0x4a0000? |
410 |
* Ultrix panics with a "bad VDAC ID" message if 0x4a |
411 |
* is returned. |
412 |
*/ |
413 |
d->bt459_reg[BT459_REG_ID] = 0x4a0000; |
414 |
} |
415 |
|
416 |
btaddr = ((d->cur_addr_hi << 8) + d->cur_addr_lo) % DEV_BT459_NREGS; |
417 |
|
418 |
/* Read from/write to the bt459: */ |
419 |
switch (relative_addr) { |
420 |
case 0x00: /* Low byte of address: */ |
421 |
if (writeflag == MEM_WRITE) { |
422 |
if (!quiet_mode) |
423 |
debug("[ bt459: write to Low Address Byte, " |
424 |
"0x%02x ]\n", (int)idata); |
425 |
d->cur_addr_lo = idata; |
426 |
d->palette_sub_offset = 0; |
427 |
} else { |
428 |
odata = d->cur_addr_lo; |
429 |
if (!quiet_mode) |
430 |
debug("[ bt459: read from Low Address Byte: " |
431 |
"0x%0x ]\n", (int)odata); |
432 |
} |
433 |
break; |
434 |
case 0x04: /* High byte of address: */ |
435 |
if (writeflag == MEM_WRITE) { |
436 |
if (!quiet_mode) |
437 |
debug("[ bt459: write to High Address Byte, " |
438 |
"0x%02x ]\n", (int)idata); |
439 |
d->cur_addr_hi = idata; |
440 |
d->palette_sub_offset = 0; |
441 |
} else { |
442 |
odata = d->cur_addr_hi; |
443 |
if (!quiet_mode) |
444 |
debug("[ bt459: read from High Address Byte: " |
445 |
"0x%0x ]\n", (int)odata); |
446 |
} |
447 |
break; |
448 |
case 0x08: /* Register access: */ |
449 |
if (writeflag == MEM_WRITE) { |
450 |
if (!quiet_mode) |
451 |
debug("[ bt459: write to BT459 register " |
452 |
"0x%04x, value 0x%02x ]\n", btaddr, |
453 |
(int)idata); |
454 |
modified = (d->bt459_reg[btaddr] != idata); |
455 |
d->bt459_reg[btaddr] = idata; |
456 |
|
457 |
switch (btaddr) { |
458 |
case BT459_REG_CCOLOR_1: |
459 |
case BT459_REG_CCOLOR_2: |
460 |
case BT459_REG_CCOLOR_3: |
461 |
if (modified) |
462 |
d->need_to_update_cursor_shape = 1; |
463 |
break; |
464 |
case BT459_REG_PRM: |
465 |
/* |
466 |
* NetBSD writes 0x00 to this register to |
467 |
* blank the screen (video off), and 0xff |
468 |
* to turn the screen on. |
469 |
*/ |
470 |
switch (idata & 0xff) { |
471 |
case 0: d->video_on = 0; |
472 |
memset(d->rgb_palette, 0, 256*3); |
473 |
d->need_to_redraw_whole_screen = 1; |
474 |
debug("[ bt459: video OFF ]\n"); |
475 |
break; |
476 |
default:d->video_on = 1; |
477 |
memcpy(d->rgb_palette, |
478 |
d->local_rgb_palette, 256*3); |
479 |
d->need_to_redraw_whole_screen = 1; |
480 |
debug("[ bt459: video ON ]\n"); |
481 |
} |
482 |
break; |
483 |
case BT459_REG_CCR: |
484 |
/* Cursor control register: */ |
485 |
switch (idata & 0xff) { |
486 |
case 0x00: d->cursor_on = 0; break; |
487 |
case 0xc0: |
488 |
case 0xc1: d->cursor_on = 1; break; |
489 |
default: |
490 |
fatal("[ bt459: unimplemented CCR " |
491 |
"value 0x%08x ]\n", (int)idata); |
492 |
} |
493 |
if (modified) |
494 |
d->need_to_update_cursor_shape = 1; |
495 |
break; |
496 |
default: |
497 |
if (btaddr < 0x100) |
498 |
fatal("[ bt459: write to BT459 " |
499 |
"register 0x%04x, value 0x%02x ]\n", |
500 |
btaddr, (int)idata); |
501 |
} |
502 |
|
503 |
/* Write to cursor bitmap: */ |
504 |
if (btaddr >= BT459_REG_CRAM_BASE && modified) |
505 |
d->need_to_update_cursor_shape = 1; |
506 |
} else { |
507 |
odata = d->bt459_reg[btaddr]; |
508 |
|
509 |
/* Perhaps this hack is not necessary: */ |
510 |
if (btaddr == BT459_REG_ID && len==1) |
511 |
odata = (odata >> 16) & 255; |
512 |
|
513 |
if (!quiet_mode) |
514 |
debug("[ bt459: read from BT459 register " |
515 |
"0x%04x, value 0x%02x ]\n", btaddr, |
516 |
(int)odata); |
517 |
} |
518 |
|
519 |
/* Go to next register: */ |
520 |
d->cur_addr_lo ++; |
521 |
if (d->cur_addr_lo == 0) |
522 |
d->cur_addr_hi ++; |
523 |
break; |
524 |
case 0xc: /* Color map: */ |
525 |
if (writeflag == MEM_WRITE) { |
526 |
idata &= 255; |
527 |
if (!quiet_mode) |
528 |
debug("[ bt459: write to BT459 colormap " |
529 |
"0x%04x subaddr %i, value 0x%02x ]\n", |
530 |
btaddr, d->palette_sub_offset, (int)idata); |
531 |
|
532 |
if (btaddr < 0x100) { |
533 |
if (d->video_on && |
534 |
d->local_rgb_palette[(btaddr & 0xff) * 3 |
535 |
+ d->palette_sub_offset] != idata) |
536 |
d->need_to_redraw_whole_screen = 1; |
537 |
|
538 |
/* |
539 |
* Actually, the palette should only be |
540 |
* updated after the third write, |
541 |
* but this should probably work fine too: |
542 |
*/ |
543 |
d->local_rgb_palette[(btaddr & 0xff) * 3 |
544 |
+ d->palette_sub_offset] = idata; |
545 |
|
546 |
if (d->video_on) |
547 |
d->rgb_palette[(btaddr & 0xff) * 3 |
548 |
+ d->palette_sub_offset] = idata; |
549 |
} |
550 |
} else { |
551 |
if (btaddr < 0x100) |
552 |
odata = d->local_rgb_palette[(btaddr & 0xff) |
553 |
* 3 + d->palette_sub_offset]; |
554 |
if (!quiet_mode) |
555 |
debug("[ bt459: read from BT459 colormap " |
556 |
"0x%04x subaddr %i, value 0x%02x ]\n", |
557 |
btaddr, d->palette_sub_offset, (int)odata); |
558 |
} |
559 |
|
560 |
d->palette_sub_offset ++; |
561 |
if (d->palette_sub_offset >= 3) { |
562 |
d->palette_sub_offset = 0; |
563 |
|
564 |
d->cur_addr_lo ++; |
565 |
if (d->cur_addr_lo == 0) |
566 |
d->cur_addr_hi ++; |
567 |
} |
568 |
|
569 |
break; |
570 |
default: |
571 |
if (writeflag == MEM_WRITE) { |
572 |
debug("[ bt459: unimplemented write to address 0x%x, " |
573 |
"data=0x%02x ]\n", (int)relative_addr, (int)idata); |
574 |
} else { |
575 |
debug("[ bt459: unimplemented read from address " |
576 |
"0x%x ]\n", (int)relative_addr); |
577 |
} |
578 |
} |
579 |
|
580 |
|
581 |
bt459_update_cursor_position(d, old_cursor_on); |
582 |
|
583 |
if (writeflag == MEM_READ) |
584 |
memory_writemax64(cpu, data, len, odata); |
585 |
|
586 |
#ifdef BT459_DEBUG |
587 |
if (writeflag == MEM_READ) |
588 |
fatal("[ bt459: read from addr 0x%02x: %08x ]\n", |
589 |
(int)relative_addr, (int)idata); |
590 |
#endif |
591 |
|
592 |
return 1; |
593 |
} |
594 |
|
595 |
|
596 |
/* |
597 |
* dev_bt459_init(): |
598 |
*/ |
599 |
void dev_bt459_init(struct machine *machine, struct memory *mem, |
600 |
uint64_t baseaddr, uint64_t baseaddr_irq, struct vfb_data *vfb_data, |
601 |
int planes, int irq_nr, int type) |
602 |
{ |
603 |
struct bt459_data *d = malloc(sizeof(struct bt459_data)); |
604 |
if (d == NULL) { |
605 |
fprintf(stderr, "out of memory\n"); |
606 |
exit(1); |
607 |
} |
608 |
|
609 |
memset(d, 0, sizeof(struct bt459_data)); |
610 |
|
611 |
d->vfb_data = vfb_data; |
612 |
d->rgb_palette = vfb_data->rgb_palette; |
613 |
d->planes = planes; |
614 |
d->irq_nr = irq_nr; |
615 |
d->type = type; |
616 |
d->cursor_x = -1; |
617 |
d->cursor_y = -1; |
618 |
d->cursor_xsize = d->cursor_ysize = 0; /* anything */ |
619 |
d->video_on = 1; |
620 |
|
621 |
/* |
622 |
* These offsets are based on those mentioned in NetBSD, |
623 |
* and then adjusted to look good with both NetBSD and |
624 |
* Ultrix: |
625 |
*/ |
626 |
switch (d->type) { |
627 |
case BT459_PX: |
628 |
d->cursor_x_add = 370; |
629 |
d->cursor_y_add = 37; |
630 |
break; |
631 |
case BT459_BA: |
632 |
d->cursor_x_add = 220; |
633 |
d->cursor_y_add = 35; |
634 |
break; |
635 |
case BT459_BBA: |
636 |
if (vfb_data->xsize == 1280) { |
637 |
/* 1280x1024: */ |
638 |
d->cursor_x_add = 368; |
639 |
d->cursor_y_add = 38; |
640 |
} else { |
641 |
/* 1024x864: */ |
642 |
d->cursor_x_add = 220; |
643 |
d->cursor_y_add = 35; |
644 |
} |
645 |
break; |
646 |
} |
647 |
|
648 |
d->interrupt_time_reset_value = 500; |
649 |
|
650 |
memory_device_register(mem, "bt459", baseaddr, DEV_BT459_LENGTH, |
651 |
dev_bt459_access, (void *)d, MEM_DEFAULT, NULL); |
652 |
|
653 |
if (baseaddr_irq != 0) |
654 |
memory_device_register(mem, "bt459_irq", baseaddr_irq, 0x10000, |
655 |
dev_bt459_irq_access, (void *)d, MEM_DEFAULT, NULL); |
656 |
|
657 |
machine_add_tickfunction(machine, dev_bt459_tick, d, BT459_TICK_SHIFT); |
658 |
|
659 |
memory_device_register_statefunction(mem, d, bt459_state); |
660 |
} |
661 |
|