/[gxemul]/trunk/src/devices/dev_vga.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 /trunk/src/devices/dev_vga.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 18 - (show annotations)
Mon Oct 8 16:19:11 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 33386 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1004 2005/10/27 14:01:10 debug Exp $
20051011        Passing -A as the default boot arg for CATS (works fine with
                OpenBSD/cats).
20051012	Fixing the VGA cursor offset bug, and speeding up framebuffer
		redraws if character cells contain the same thing as during
		the last redraw.
20051013	Adding a slow strd ARM instruction hack.
20051017	Minor updates: Adding a dummy i80321 Verde controller (for
		XScale emulation), fixing the disassembly of the ARM "ldrd"
		instruction, adding "support" for less-than-4KB pages for ARM
		(by not adding them to translation tables).
20051020	Continuing on some HPCarm stuff. A NetBSD/hpcarm kernel prints
		some boot messages on an emulated Jornada 720.
		Making dev_ram work better with dyntrans (speeds up some things
		quite a bit).
20051021	Automatically generating some of the most common ARM load/store
		multiple instructions.
20051022	Better statistics gathering for the ARM load/store multiple.
		Various other dyntrans and device updates.
20051023	Various minor updates.
20051024	Continuing; minor device and dyntrans fine-tuning. Adding the
		first "reasonable" instruction combination hacks for ARM (the
		cores of NetBSD/cats' memset and memcpy).
20051025	Fixing a dyntrans-related bug in dev_vga. Also changing the
		dyntrans low/high access notification to only be updated on
		writes, not reads. Hopefully it will be enough. (dev_vga in
		charcell mode now seems to work correctly with both reads and
		writes.)
		Experimenting with gathering dyntrans statistics (which parts
		of emulated RAM that are actually executed), and adding
		instruction combination hacks for cache cleaning and a part of
		NetBSD's scanc() function.
20051026	Adding a bitmap for ARM emulation which indicates if a page is
		(specifically) user accessible; loads and stores with the t-
		flag set can now use the translation arrays, which results in
		a measurable speedup.
20051027	Dyntrans updates; adding an extra bitmap array for 32-bit
		emulation modes, speeding up the check whether a physical page
		has any code translations or not (O(n) -> O(1)). Doing a
		similar reduction of O(n) to O(1) by avoiding the scan through
		the translation entries on a translation update (32-bit mode
		only).
		Various other minor hacks.
20051029	Quick release, without any testing at all.

==============  RELEASE 0.3.6.2  ==============


1 /*
2 * Copyright (C) 2004-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_vga.c,v 1.86 2005/10/27 14:01:14 debug Exp $
29 *
30 * VGA charcell and graphics device.
31 *
32 * It should work with 80x25 and 40x25 text modes, and with a few graphics
33 * modes as long as no fancy VGA features are used.
34 */
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 #include "console.h"
41 #include "cpu.h"
42 #include "devices.h"
43 #include "machine.h"
44 #include "memory.h"
45 #include "misc.h"
46
47 #include "vga.h"
48
49 /* These are generated from binary font files: */
50 #include "fonts/font8x8.c"
51 #include "fonts/font8x10.c"
52 #include "fonts/font8x16.c"
53
54
55 /* For videomem -> framebuffer updates: */
56 #define VGA_TICK_SHIFT 19
57
58 #define MAX_RETRACE_SCANLINES 420
59 #define N_IS1_READ_THRESHOLD 50
60
61 #define GFX_ADDR_WINDOW 0x18000
62
63 #define VGA_FB_ADDR 0x1c00000000ULL
64
65 #define MODE_CHARCELL 1
66 #define MODE_GRAPHICS 2
67
68 #define GRAPHICS_MODE_8BIT 1
69 #define GRAPHICS_MODE_4BIT 2
70
71 struct vga_data {
72 uint64_t videomem_base;
73 uint64_t control_base;
74
75 struct vfb_data *fb;
76 size_t fb_size;
77
78 int fb_max_x; /* pixels */
79 int fb_max_y; /* pixels */
80 int max_x; /* charcells or pixels */
81 int max_y; /* charcells or pixels */
82
83 /* Selects charcell mode or graphics mode: */
84 int cur_mode;
85
86 /* Common for text and graphics modes: */
87 int pixel_repx, pixel_repy;
88
89 /* Textmode: */
90 int font_width;
91 int font_height;
92 unsigned char *font;
93 size_t charcells_size;
94 unsigned char *charcells; /* 2 bytes per char */
95 unsigned char *charcells_outputed; /* text */
96 unsigned char *charcells_drawn; /* framebuffer */
97
98 /* Graphics: */
99 int graphics_mode;
100 int bits_per_pixel;
101 unsigned char *gfx_mem;
102 size_t gfx_mem_size;
103
104 /* Registers: */
105 int attribute_state; /* 0 or 1 */
106 unsigned char attribute_reg_select;
107 unsigned char attribute_reg[256];
108
109 unsigned char misc_output_reg;
110
111 unsigned char sequencer_reg_select;
112 unsigned char sequencer_reg[256];
113
114 unsigned char graphcontr_reg_select;
115 unsigned char graphcontr_reg[256];
116
117 unsigned char crtc_reg_select;
118 unsigned char crtc_reg[256];
119
120 unsigned char palette_read_index;
121 char palette_read_subindex;
122 unsigned char palette_write_index;
123 char palette_write_subindex;
124
125 int current_retrace_line;
126 int input_status_1;
127
128 /* Palette per scanline during retrace: */
129 unsigned char *retrace_palette;
130 int use_palette_per_line;
131 int64_t n_is1_reads;
132
133 /* Misc.: */
134 int console_handle;
135
136 int cursor_x;
137 int cursor_y;
138
139 int modified;
140 int update_x1;
141 int update_y1;
142 int update_x2;
143 int update_y2;
144 };
145
146
147 /*
148 * recalc_cursor_position():
149 *
150 * Should be called whenever the cursor location _or_ the display
151 * base has been changed.
152 */
153 static void recalc_cursor_position(struct vga_data *d)
154 {
155 int base = (d->crtc_reg[VGA_CRTC_START_ADDR_HIGH] << 8)
156 + d->crtc_reg[VGA_CRTC_START_ADDR_LOW];
157 int ofs = d->crtc_reg[VGA_CRTC_CURSOR_LOCATION_HIGH] * 256 +
158 d->crtc_reg[VGA_CRTC_CURSOR_LOCATION_LOW];
159 ofs -= base;
160 d->cursor_x = ofs % d->max_x;
161 d->cursor_y = ofs / d->max_x;
162 }
163
164
165 /*
166 * register_reset():
167 *
168 * Resets many registers to sane values.
169 */
170 static void register_reset(struct vga_data *d)
171 {
172 /* Home cursor and start at the top: */
173 d->crtc_reg[VGA_CRTC_CURSOR_LOCATION_HIGH] =
174 d->crtc_reg[VGA_CRTC_CURSOR_LOCATION_LOW] = 0;
175 d->crtc_reg[VGA_CRTC_START_ADDR_HIGH] =
176 d->crtc_reg[VGA_CRTC_START_ADDR_LOW] = 0;
177
178 recalc_cursor_position(d);
179
180 /* Reset cursor scanline stuff: */
181 d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_START] = d->font_height - 2;
182 d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_END] = d->font_height - 1;
183
184 d->sequencer_reg[VGA_SEQ_MAP_MASK] = 0x0f;
185 d->graphcontr_reg[VGA_GRAPHCONTR_MASK] = 0xff;
186
187 d->misc_output_reg = VGA_MISC_OUTPUT_IOAS;
188 d->n_is1_reads = 0;
189 }
190
191
192 static void c_putstr(struct vga_data *d, char *s)
193 {
194 while (*s)
195 console_putchar(d->console_handle, *s++);
196 }
197
198
199 /*
200 * reset_palette():
201 */
202 static void reset_palette(struct vga_data *d, int grayscale)
203 {
204 int i, r, g, b;
205
206 /* TODO: default values for entry 16..255? */
207 for (i=16; i<256; i++)
208 d->fb->rgb_palette[i*3 + 0] = d->fb->rgb_palette[i*3 + 1] =
209 d->fb->rgb_palette[i*3 + 2] = (i & 15) * 4;
210
211 i = 0;
212
213 if (grayscale) {
214 for (r=0; r<2; r++)
215 for (g=0; g<2; g++)
216 for (b=0; b<2; b++) {
217 d->fb->rgb_palette[i + 0] =
218 d->fb->rgb_palette[i + 1] =
219 d->fb->rgb_palette[i + 2] =
220 (r+g+b) * 0xaa / 3;
221 d->fb->rgb_palette[i + 8*3 + 0] =
222 d->fb->rgb_palette[i + 8*3 + 1] =
223 d->fb->rgb_palette[i + 8*3 + 2] =
224 (r+g+b) * 0xaa / 3 + 0x55;
225 i+=3;
226 }
227 return;
228 }
229
230 for (r=0; r<2; r++)
231 for (g=0; g<2; g++)
232 for (b=0; b<2; b++) {
233 d->fb->rgb_palette[i + 0] = r * 0xaa;
234 d->fb->rgb_palette[i + 1] = g * 0xaa;
235 d->fb->rgb_palette[i + 2] = b * 0xaa;
236 i+=3;
237 }
238 for (r=0; r<2; r++)
239 for (g=0; g<2; g++)
240 for (b=0; b<2; b++) {
241 d->fb->rgb_palette[i + 0] = r * 0xaa + 0x55;
242 d->fb->rgb_palette[i + 1] = g * 0xaa + 0x55;
243 d->fb->rgb_palette[i + 2] = b * 0xaa + 0x55;
244 i+=3;
245 }
246 }
247
248
249 /*
250 * vga_update_textmode():
251 *
252 * Called from vga_update() when use_x11 is false. This causes modified
253 * character cells to be "simulated" by outputing ANSI escape sequences
254 * that draw the characters in a terminal window instead.
255 */
256 static void vga_update_textmode(struct machine *machine,
257 struct vga_data *d, int base, int start, int end)
258 {
259 char s[50];
260 int i, oldcolor = -1, printed_last = 0;
261
262 for (i=start; i<=end; i+=2) {
263 unsigned char ch = d->charcells[base+i];
264 int fg = d->charcells[base+i+1] & 15;
265 int bg = (d->charcells[base+i+1] >> 4) & 15;
266 /* top bit of bg = blink */
267 int x = (i/2) % d->max_x;
268 int y = (i/2) / d->max_x;
269
270 if (d->charcells[base+i] == d->charcells_outputed[i] &&
271 d->charcells[base+i+1] == d->charcells_outputed[i+1]) {
272 printed_last = 0;
273 continue;
274 }
275
276 d->charcells_outputed[i] = d->charcells[base+i];
277 d->charcells_outputed[i+1] = d->charcells[base+i+1];
278
279 if (!printed_last || x == 0) {
280 snprintf(s, sizeof(s), "\033[%i;%iH", y + 1, x + 1);
281 c_putstr(d, s);
282 }
283 if (oldcolor < 0 || (bg<<4)+fg != oldcolor || !printed_last) {
284 snprintf(s, sizeof(s), "\033[0;"); c_putstr(d, s);
285
286 switch (fg & 7) {
287 case 0: c_putstr(d, "30"); break;
288 case 1: c_putstr(d, "34"); break;
289 case 2: c_putstr(d, "32"); break;
290 case 3: c_putstr(d, "36"); break;
291 case 4: c_putstr(d, "31"); break;
292 case 5: c_putstr(d, "35"); break;
293 case 6: c_putstr(d, "33"); break;
294 case 7: c_putstr(d, "37"); break;
295 }
296 if (fg & 8)
297 c_putstr(d, ";1");
298 c_putstr(d, ";");
299 switch (bg & 7) {
300 case 0: c_putstr(d, "40"); break;
301 case 1: c_putstr(d, "44"); break;
302 case 2: c_putstr(d, "42"); break;
303 case 3: c_putstr(d, "46"); break;
304 case 4: c_putstr(d, "41"); break;
305 case 5: c_putstr(d, "45"); break;
306 case 6: c_putstr(d, "43"); break;
307 case 7: c_putstr(d, "47"); break;
308 }
309 /* TODO: blink */
310 c_putstr(d, "m");
311 }
312
313 if (ch >= 0x20 && ch != 127)
314 console_putchar(d->console_handle, ch);
315
316 oldcolor = (bg << 4) + fg;
317 printed_last = 1;
318 }
319
320 /* Restore the terminal's cursor position: */
321 snprintf(s, sizeof(s), "\033[%i;%iH", d->cursor_y + 1, d->cursor_x + 1);
322 c_putstr(d, s);
323 }
324
325
326 /*
327 * vga_update_graphics():
328 *
329 * This function should be called whenever any part of d->gfx_mem[] has
330 * been written to. It will redraw all pixels within the range x1,y1
331 * .. x2,y2 using the right palette.
332 */
333 static void vga_update_graphics(struct machine *machine, struct vga_data *d,
334 int x1, int y1, int x2, int y2)
335 {
336 int x, y, ix, iy, c, rx = d->pixel_repx, ry = d->pixel_repy;
337 unsigned char pixel[3];
338
339 for (y=y1; y<=y2; y++)
340 for (x=x1; x<=x2; x++) {
341 /* addr is where to read from VGA memory, addr2 is
342 where to write on the 24-bit framebuffer device */
343 int addr = (y * d->max_x + x) * d->bits_per_pixel;
344 switch (d->bits_per_pixel) {
345 case 8: addr >>= 3;
346 c = d->gfx_mem[addr];
347 pixel[0] = d->fb->rgb_palette[c*3+0];
348 pixel[1] = d->fb->rgb_palette[c*3+1];
349 pixel[2] = d->fb->rgb_palette[c*3+2];
350 break;
351 case 4: addr >>= 2;
352 if (addr & 1)
353 c = d->gfx_mem[addr >> 1] >> 4;
354 else
355 c = d->gfx_mem[addr >> 1] & 0xf;
356 pixel[0] = d->fb->rgb_palette[c*3+0];
357 pixel[1] = d->fb->rgb_palette[c*3+1];
358 pixel[2] = d->fb->rgb_palette[c*3+2];
359 break;
360 }
361 for (iy=y*ry; iy<(y+1)*ry; iy++)
362 for (ix=x*rx; ix<(x+1)*rx; ix++) {
363 int addr2 = (d->fb_max_x * iy + ix) * 3;
364 if (addr2 < d->fb_size)
365 dev_fb_access(machine->cpus[0],
366 machine->memory, addr2,
367 pixel, sizeof(pixel),
368 MEM_WRITE, d->fb);
369 }
370 }
371 }
372
373
374 /*
375 * vga_update_text():
376 *
377 * This function should be called whenever any part of d->charcells[] has
378 * been written to. It will redraw all characters within the range x1,y1
379 * .. x2,y2 using the right palette.
380 */
381 static void vga_update_text(struct machine *machine, struct vga_data *d,
382 int x1, int y1, int x2, int y2)
383 {
384 int fg, bg, i, x,y, subx, line, start, end, base;
385 int font_size = d->font_height;
386 int font_width = d->font_width;
387 unsigned char *pal = d->fb->rgb_palette;
388
389 /* Hm... I'm still using the old start..end code: */
390 start = (d->max_x * y1 + x1) * 2;
391 end = (d->max_x * y2 + x2) * 2;
392
393 start &= ~1;
394 end |= 1;
395
396 if (end >= d->charcells_size)
397 end = d->charcells_size - 1;
398
399 base = ((d->crtc_reg[VGA_CRTC_START_ADDR_HIGH] << 8)
400 + d->crtc_reg[VGA_CRTC_START_ADDR_LOW]) * 2;
401
402 if (!machine->use_x11)
403 vga_update_textmode(machine, d, base, start, end);
404
405 for (i=start; i<=end; i+=2) {
406 unsigned char ch = d->charcells[i + base];
407
408 if (d->charcells_drawn[i] == ch &&
409 d->charcells_drawn[i+1] == d->charcells[i+base+1])
410 continue;
411
412 d->charcells_drawn[i] = ch;
413 d->charcells_drawn[i+1] = d->charcells[i + base + 1];
414
415 fg = d->charcells[i+base + 1] & 15;
416 bg = (d->charcells[i+base + 1] >> 4) & 7;
417
418 /* Blink is hard to do :-), but inversion might be ok too: */
419 if (d->charcells[i+base + 1] & 128) {
420 int tmp = fg; fg = bg; bg = tmp;
421 }
422
423 x = (i/2) % d->max_x; x *= font_width;
424 y = (i/2) / d->max_x; y *= font_size;
425
426 /* Draw the character: */
427 for (line = 0; line < font_size; line++) {
428 for (subx = 0; subx < font_width; subx++) {
429 int ix, iy, color_index;
430
431 if (d->use_palette_per_line) {
432 int sline = d->pixel_repy * (line+y);
433 if (sline < MAX_RETRACE_SCANLINES)
434 pal = d->retrace_palette
435 + sline * 256*3;
436 else
437 pal = d->fb->rgb_palette;
438 }
439
440 if (d->font[ch * font_size + line] &
441 (128 >> subx))
442 color_index = fg;
443 else
444 color_index = bg;
445
446 for (iy=0; iy<d->pixel_repy; iy++)
447 for (ix=0; ix<d->pixel_repx; ix++) {
448 int addr = (d->fb_max_x* (d->pixel_repy
449 * (line+y) + iy) + (x+subx) *
450 d->pixel_repx + ix) * 3;
451
452 if (addr >= d->fb_size)
453 continue;
454 dev_fb_access(machine->cpus[0],
455 machine->memory, addr,
456 &pal[color_index * 3], 3,
457 MEM_WRITE, d->fb);
458 }
459 }
460 }
461 }
462 }
463
464
465 /*
466 * vga_update_cursor():
467 */
468 static void vga_update_cursor(struct machine *machine, struct vga_data *d)
469 {
470 int onoff = 1, height = d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_END]
471 - d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_START] + 1;
472
473 if (d->cur_mode != MODE_CHARCELL)
474 onoff = 0;
475
476 if (d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_START] >
477 d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_END]) {
478 onoff = 0;
479 height = 1;
480 }
481
482 if (d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_START] >= d->font_height)
483 onoff = 0;
484
485 dev_fb_setcursor(d->fb,
486 d->cursor_x * d->font_width * d->pixel_repx, (d->cursor_y *
487 d->font_height + d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_START]) *
488 d->pixel_repy, onoff, d->font_width * d->pixel_repx, height *
489 d->pixel_repy);
490 }
491
492
493 /*
494 * dev_vga_tick():
495 */
496 void dev_vga_tick(struct cpu *cpu, void *extra)
497 {
498 struct vga_data *d = extra;
499 int64_t low = -1, high;
500
501 vga_update_cursor(cpu->machine, d);
502
503 /* TODO: text vs graphics tick? */
504 memory_device_dyntrans_access(cpu, cpu->mem, extra,
505 (uint64_t *) &low, (uint64_t *) &high);
506
507 if (low != -1) {
508 int base = ((d->crtc_reg[VGA_CRTC_START_ADDR_HIGH] << 8)
509 + d->crtc_reg[VGA_CRTC_START_ADDR_LOW]) * 2;
510 int new_u_y1, new_u_y2;
511 debug("[ dev_vga_tick: dyntrans access, %llx .. %llx ]\n",
512 (long long)low, (long long)high);
513 low -= base;
514 high -= base;
515 d->update_x1 = 0;
516 d->update_x2 = d->max_x - 1;
517 new_u_y1 = (low/2) / d->max_x;
518 new_u_y2 = ((high/2) / d->max_x) + 1;
519 if (new_u_y1 < d->update_y1)
520 d->update_y1 = new_u_y1;
521 if (new_u_y2 > d->update_y2)
522 d->update_y2 = new_u_y2;
523 if (d->update_y1 < 0)
524 d->update_y1 = 0;
525 if (d->update_y2 >= d->max_y)
526 d->update_y2 = d->max_y - 1;
527 d->modified = 1;
528 }
529
530 if (d->n_is1_reads > N_IS1_READ_THRESHOLD &&
531 d->retrace_palette != NULL) {
532 d->use_palette_per_line = 1;
533 d->update_x1 = 0;
534 d->update_x2 = d->max_x - 1;
535 d->update_y1 = 0;
536 d->update_y2 = d->max_y - 1;
537 d->modified = 1;
538 } else {
539 if (d->use_palette_per_line) {
540 d->use_palette_per_line = 0;
541 d->update_x1 = 0;
542 d->update_x2 = d->max_x - 1;
543 d->update_y1 = 0;
544 d->update_y2 = d->max_y - 1;
545 d->modified = 1;
546 }
547 }
548
549 if (!cpu->machine->use_x11) {
550 /* NOTE: 2 > 0, so this only updates the cursor, no
551 character cells. */
552 vga_update_textmode(cpu->machine, d, 0, 2, 0);
553 }
554
555 if (d->modified) {
556 if (d->cur_mode == MODE_CHARCELL)
557 vga_update_text(cpu->machine, d, d->update_x1,
558 d->update_y1, d->update_x2, d->update_y2);
559 else
560 vga_update_graphics(cpu->machine, d, d->update_x1,
561 d->update_y1, d->update_x2, d->update_y2);
562
563 d->modified = 0;
564 d->update_x1 = 999999;
565 d->update_x2 = -1;
566 d->update_y1 = 999999;
567 d->update_y2 = -1;
568 }
569
570 if (d->n_is1_reads > N_IS1_READ_THRESHOLD)
571 d->n_is1_reads = 0;
572 }
573
574
575 /*
576 * vga_graphics_access():
577 *
578 * Reads and writes to the VGA video memory (pixels).
579 */
580 int dev_vga_graphics_access(struct cpu *cpu, struct memory *mem,
581 uint64_t relative_addr, unsigned char *data, size_t len,
582 int writeflag, void *extra)
583 {
584 struct vga_data *d = extra;
585 int i,j, x=0, y=0, x2=0, y2=0, modified = 0;
586
587 if (relative_addr + len >= GFX_ADDR_WINDOW)
588 return 0;
589
590 if (d->cur_mode != MODE_GRAPHICS)
591 return 1;
592
593 switch (d->graphics_mode) {
594 case GRAPHICS_MODE_8BIT:
595 y = relative_addr / d->max_x;
596 x = relative_addr % d->max_x;
597 y2 = (relative_addr+len-1) / d->max_x;
598 x2 = (relative_addr+len-1) % d->max_x;
599
600 if (writeflag == MEM_WRITE) {
601 memcpy(d->gfx_mem + relative_addr, data, len);
602 modified = 1;
603 } else
604 memcpy(data, d->gfx_mem + relative_addr, len);
605 break;
606 case GRAPHICS_MODE_4BIT:
607 y = relative_addr * 8 / d->max_x;
608 x = relative_addr * 8 % d->max_x;
609 y2 = ((relative_addr+len)*8-1) / d->max_x;
610 x2 = ((relative_addr+len)*8-1) % d->max_x;
611 /* TODO: color stuff */
612
613 /* Read/write d->gfx_mem in 4-bit color: */
614 if (writeflag == MEM_WRITE) {
615 /* i is byte index to write, j is bit index */
616 for (i=0; i<len; i++)
617 for (j=0; j<8; j++) {
618 int pixelmask = 1 << (7-j);
619 int b = data[i] & pixelmask;
620 int m = d->sequencer_reg[
621 VGA_SEQ_MAP_MASK] & 0x0f;
622 int addr = (y * d->max_x + x + i*8 + j)
623 * d->bits_per_pixel / 8;
624 unsigned char byte;
625 if (!(d->graphcontr_reg[
626 VGA_GRAPHCONTR_MASK] & pixelmask))
627 continue;
628 if (addr >= d->gfx_mem_size)
629 continue;
630 byte = d->gfx_mem[addr];
631 if (b && j&1)
632 byte |= m << 4;
633 if (b && !(j&1))
634 byte |= m;
635 if (!b && j&1)
636 byte &= ~(m << 4);
637 if (!b && !(j&1))
638 byte &= ~m;
639 d->gfx_mem[addr] = byte;
640 }
641 modified = 1;
642 } else {
643 fatal("TODO: 4 bit graphics read, mask=0x%02x\n",
644 d->sequencer_reg[VGA_SEQ_MAP_MASK]);
645 for (i=0; i<len; i++)
646 data[i] = random();
647 }
648 break;
649 default:fatal("dev_vga: Unimplemented graphics mode %i\n",
650 d->graphics_mode);
651 cpu->running = 0;
652 }
653
654 if (modified) {
655 d->modified = 1;
656 if (x < d->update_x1) d->update_x1 = x;
657 if (x > d->update_x2) d->update_x2 = x;
658 if (y < d->update_y1) d->update_y1 = y;
659 if (y > d->update_y2) d->update_y2 = y;
660 if (x2 < d->update_x1) d->update_x1 = x2;
661 if (x2 > d->update_x2) d->update_x2 = x2;
662 if (y2 < d->update_y1) d->update_y1 = y2;
663 if (y2 > d->update_y2) d->update_y2 = y2;
664 if (y != y2) {
665 d->update_x1 = 0;
666 d->update_x2 = d->max_x - 1;
667 }
668 }
669 return 1;
670 }
671
672
673 /*
674 * dev_vga_access():
675 *
676 * Reads and writes to the VGA video memory (charcells).
677 */
678 int dev_vga_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr,
679 unsigned char *data, size_t len, int writeflag, void *extra)
680 {
681 struct vga_data *d = extra;
682 uint64_t idata = 0, odata = 0;
683 int i, x, y, x2, y2, r, base;
684
685 if (writeflag == MEM_WRITE)
686 idata = memory_readmax64(cpu, data, len);
687
688 base = ((d->crtc_reg[VGA_CRTC_START_ADDR_HIGH] << 8)
689 + d->crtc_reg[VGA_CRTC_START_ADDR_LOW]) * 2;
690 r = relative_addr - base;
691 y = r / (d->max_x * 2);
692 x = (r/2) % d->max_x;
693 y2 = (r+len-1) / (d->max_x * 2);
694 x2 = ((r+len-1)/2) % d->max_x;
695
696 if (relative_addr + len - 1 < d->charcells_size) {
697 if (writeflag == MEM_WRITE) {
698 for (i=0; i<len; i++) {
699 int old = d->charcells[relative_addr + i];
700 if (old != data[i]) {
701 d->charcells[relative_addr + i] =
702 data[i];
703 d->modified = 1;
704 }
705 }
706
707 if (d->modified) {
708 if (x < d->update_x1) d->update_x1 = x;
709 if (x > d->update_x2) d->update_x2 = x;
710 if (y < d->update_y1) d->update_y1 = y;
711 if (y > d->update_y2) d->update_y2 = y;
712 if (x2 < d->update_x1) d->update_x1 = x2;
713 if (x2 > d->update_x2) d->update_x2 = x2;
714 if (y2 < d->update_y1) d->update_y1 = y2;
715 if (y2 > d->update_y2) d->update_y2 = y2;
716
717 if (y != y2) {
718 d->update_x1 = 0;
719 d->update_x2 = d->max_x - 1;
720 }
721 }
722 } else
723 memcpy(data, d->charcells + relative_addr, len);
724 return 1;
725 }
726
727 switch (relative_addr) {
728 default:
729 if (writeflag==MEM_READ) {
730 debug("[ vga: read from 0x%08lx ]\n",
731 (long)relative_addr);
732 } else {
733 debug("[ vga: write to 0x%08lx: 0x%08x ]\n",
734 (long)relative_addr, idata);
735 }
736 }
737
738 if (writeflag == MEM_READ)
739 memory_writemax64(cpu, data, len, odata);
740
741 return 1;
742 }
743
744
745 /*
746 * vga_crtc_reg_write():
747 *
748 * Writes to VGA CRTC registers.
749 */
750 static void vga_crtc_reg_write(struct machine *machine, struct vga_data *d,
751 int regnr, int idata)
752 {
753 int grayscale;
754
755 switch (regnr) {
756 case VGA_CRTC_CURSOR_SCANLINE_START: /* 0x0a */
757 case VGA_CRTC_CURSOR_SCANLINE_END: /* 0x0b */
758 break;
759 case VGA_CRTC_START_ADDR_HIGH: /* 0x0c */
760 case VGA_CRTC_START_ADDR_LOW: /* 0x0d */
761 d->update_x1 = 0;
762 d->update_x2 = d->max_x - 1;
763 d->update_y1 = 0;
764 d->update_y2 = d->max_y - 1;
765 d->modified = 1;
766 recalc_cursor_position(d);
767 break;
768 case VGA_CRTC_CURSOR_LOCATION_HIGH: /* 0x0e */
769 case VGA_CRTC_CURSOR_LOCATION_LOW: /* 0x0f */
770 recalc_cursor_position(d);
771 break;
772 case 0xff:
773 grayscale = 0;
774 switch (d->crtc_reg[0xff]) {
775 case 0x00:
776 grayscale = 1;
777 case 0x01:
778 d->cur_mode = MODE_CHARCELL;
779 d->max_x = 40; d->max_y = 25;
780 d->pixel_repx = 2; d->pixel_repy = 1;
781 d->font_width = 8;
782 d->font_height = 16;
783 d->font = font8x16;
784 break;
785 case 0x02:
786 grayscale = 1;
787 case 0x03:
788 d->cur_mode = MODE_CHARCELL;
789 d->max_x = 80; d->max_y = 25;
790 d->pixel_repx = d->pixel_repy = 1;
791 d->font_width = 8;
792 d->font_height = 16;
793 d->font = font8x16;
794 break;
795 case 0x08:
796 d->cur_mode = MODE_GRAPHICS;
797 d->max_x = 160; d->max_y = 200;
798 d->graphics_mode = GRAPHICS_MODE_4BIT;
799 d->bits_per_pixel = 4;
800 d->pixel_repx = 4;
801 d->pixel_repy = 2;
802 break;
803 case 0x09:
804 case 0x0d:
805 d->cur_mode = MODE_GRAPHICS;
806 d->max_x = 320; d->max_y = 200;
807 d->graphics_mode = GRAPHICS_MODE_4BIT;
808 d->bits_per_pixel = 4;
809 d->pixel_repx = d->pixel_repy = 2;
810 break;
811 case 0x0e:
812 d->cur_mode = MODE_GRAPHICS;
813 d->max_x = 640; d->max_y = 200;
814 d->graphics_mode = GRAPHICS_MODE_4BIT;
815 d->bits_per_pixel = 4;
816 d->pixel_repx = 1;
817 d->pixel_repy = 2;
818 break;
819 case 0x10:
820 d->cur_mode = MODE_GRAPHICS;
821 d->max_x = 640; d->max_y = 350;
822 d->graphics_mode = GRAPHICS_MODE_4BIT;
823 d->bits_per_pixel = 4;
824 d->pixel_repx = d->pixel_repy = 1;
825 break;
826 case 0x12:
827 d->cur_mode = MODE_GRAPHICS;
828 d->max_x = 640; d->max_y = 480;
829 d->graphics_mode = GRAPHICS_MODE_4BIT;
830 d->bits_per_pixel = 4;
831 d->pixel_repx = d->pixel_repy = 1;
832 break;
833 case 0x13:
834 d->cur_mode = MODE_GRAPHICS;
835 d->max_x = 320; d->max_y = 200;
836 d->graphics_mode = GRAPHICS_MODE_8BIT;
837 d->bits_per_pixel = 8;
838 d->pixel_repx = d->pixel_repy = 2;
839 break;
840 default:
841 fatal("TODO! video mode change hack (mode 0x%02x)\n",
842 d->crtc_reg[0xff]);
843 exit(1);
844 }
845
846 if (d->cur_mode == MODE_CHARCELL) {
847 dev_fb_resize(d->fb, d->max_x * d->font_width *
848 d->pixel_repx, d->max_y * d->font_height *
849 d->pixel_repy);
850 d->fb_size = d->max_x * d->pixel_repx * d->font_width *
851 d->max_y * d->pixel_repy * d->font_height * 3;
852 } else {
853 dev_fb_resize(d->fb, d->max_x * d->pixel_repx,
854 d->max_y * d->pixel_repy);
855 d->fb_size = d->max_x * d->pixel_repx *
856 d->max_y * d->pixel_repy * 3;
857 }
858
859 if (d->gfx_mem != NULL)
860 free(d->gfx_mem);
861 d->gfx_mem_size = 1;
862 if (d->cur_mode == MODE_GRAPHICS)
863 d->gfx_mem_size = d->max_x * d->max_y /
864 (d->graphics_mode == GRAPHICS_MODE_8BIT? 1 : 2);
865 d->gfx_mem = malloc(d->gfx_mem_size);
866
867 /* Clear screen and reset the palette: */
868 memset(d->charcells_outputed, 0, d->charcells_size);
869 memset(d->charcells_drawn, 0, d->charcells_size);
870 memset(d->gfx_mem, 0, d->gfx_mem_size);
871 d->update_x1 = 0;
872 d->update_x2 = d->max_x - 1;
873 d->update_y1 = 0;
874 d->update_y2 = d->max_y - 1;
875 d->modified = 1;
876 reset_palette(d, grayscale);
877 register_reset(d);
878 break;
879 default:fatal("[ vga_crtc_reg_write: regnr=0x%02x idata=0x%02x ]\n",
880 regnr, idata);
881 }
882 }
883
884
885 /*
886 * vga_sequencer_reg_write():
887 *
888 * Writes to VGA Sequencer registers.
889 */
890 static void vga_sequencer_reg_write(struct machine *machine, struct vga_data *d,
891 int regnr, int idata)
892 {
893 switch (regnr) {
894 case VGA_SEQ_MAP_MASK: /* 0x02 */
895 break;
896 default:fatal("[ vga_sequencer_reg_write: select %i ]\n", regnr);
897 /* cpu->running = 0; */
898 }
899 }
900
901
902 /*
903 * vga_graphcontr_reg_write():
904 *
905 * Writes to VGA Graphics Controller registers.
906 */
907 static void vga_graphcontr_reg_write(struct machine *machine,
908 struct vga_data *d, int regnr, int idata)
909 {
910 switch (regnr) {
911 case VGA_GRAPHCONTR_MASK: /* 0x08 */
912 break;
913 default:fatal("[ vga_graphcontr_reg_write: select %i ]\n", regnr);
914 /* cpu->running = 0; */
915 }
916 }
917
918
919 /*
920 * vga_attribute_reg_write():
921 *
922 * Writes to VGA Attribute registers.
923 */
924 static void vga_attribute_reg_write(struct machine *machine, struct vga_data *d,
925 int regnr, int idata)
926 {
927 /* 0-15 are palette registers: TODO */
928 if (regnr >= 0 && regnr <= 0xf)
929 return;
930
931 switch (regnr) {
932 default:fatal("[ vga_attribute_reg_write: select %i ]\n", regnr);
933 /* cpu->running = 0; */
934 }
935 }
936
937
938 /*
939 * dev_vga_ctrl_access():
940 *
941 * Reads and writes of the VGA control registers.
942 */
943 int dev_vga_ctrl_access(struct cpu *cpu, struct memory *mem,
944 uint64_t relative_addr, unsigned char *data, size_t len,
945 int writeflag, void *extra)
946 {
947 struct vga_data *d = extra;
948 int i;
949 uint64_t idata = 0, odata = 0;
950
951 for (i=0; i<len; i++) {
952 idata = data[i];
953
954 /* 0x3C0 + relative_addr... */
955
956 switch (relative_addr) {
957
958 case VGA_ATTRIBUTE_ADDR: /* 0x00 */
959 switch (d->attribute_state) {
960 case 0: if (writeflag == MEM_READ)
961 odata = d->attribute_reg_select;
962 else {
963 d->attribute_reg_select = 1;
964 d->attribute_state = 1;
965 }
966 break;
967 case 1: d->attribute_state = 0;
968 d->attribute_reg[d->attribute_reg_select] =
969 idata;
970 vga_attribute_reg_write(cpu->machine, d,
971 d->attribute_reg_select, idata);
972 break;
973 }
974 break;
975 case VGA_ATTRIBUTE_DATA_READ: /* 0x01 */
976 if (writeflag == MEM_WRITE)
977 fatal("[ dev_vga: WARNING: Write to "
978 "VGA_ATTRIBUTE_DATA_READ? ]\n");
979 else {
980 if (d->attribute_state == 0)
981 fatal("[ dev_vga: WARNING: Read from "
982 "VGA_ATTRIBUTE_DATA_READ, but no"
983 " register selected? ]\n");
984 else
985 odata = d->attribute_reg[
986 d->attribute_reg_select];
987 }
988 break;
989
990 case VGA_MISC_OUTPUT_W: /* 0x02 */
991 if (writeflag == MEM_WRITE)
992 d->misc_output_reg = idata;
993 else {
994 /* Reads: Input Status 0 */
995 odata = 0x00;
996 }
997 break;
998
999 case VGA_SEQUENCER_ADDR: /* 0x04 */
1000 if (writeflag == MEM_READ)
1001 odata = d->sequencer_reg_select;
1002 else
1003 d->sequencer_reg_select = idata;
1004 break;
1005 case VGA_SEQUENCER_DATA: /* 0x05 */
1006 if (writeflag == MEM_READ)
1007 odata = d->sequencer_reg[
1008 d->sequencer_reg_select];
1009 else {
1010 d->sequencer_reg[d->
1011 sequencer_reg_select] = idata;
1012 vga_sequencer_reg_write(cpu->machine, d,
1013 d->sequencer_reg_select, idata);
1014 }
1015 break;
1016
1017 case VGA_DAC_ADDR_READ: /* 0x07 */
1018 if (writeflag == MEM_WRITE) {
1019 d->palette_read_index = idata;
1020 d->palette_read_subindex = 0;
1021 } else {
1022 debug("[ dev_vga: WARNING: Read from "
1023 "VGA_DAC_ADDR_READ? TODO ]\n");
1024 /* TODO */
1025 }
1026 break;
1027 case VGA_DAC_ADDR_WRITE: /* 0x08 */
1028 if (writeflag == MEM_WRITE) {
1029 d->palette_write_index = idata;
1030 d->palette_write_subindex = 0;
1031
1032 /* TODO: Is this correct? */
1033 d->palette_read_index = idata;
1034 d->palette_read_subindex = 0;
1035 } else {
1036 fatal("[ dev_vga: WARNING: Read from "
1037 "VGA_DAC_ADDR_WRITE? ]\n");
1038 odata = d->palette_write_index;
1039 }
1040 break;
1041 case VGA_DAC_DATA: /* 0x09 */
1042 if (writeflag == MEM_WRITE) {
1043 int new = (idata & 63) << 2;
1044 int old = d->fb->rgb_palette[d->
1045 palette_write_index*3+d->
1046 palette_write_subindex];
1047 d->fb->rgb_palette[d->palette_write_index * 3 +
1048 d->palette_write_subindex] = new;
1049 /* Redraw whole screen, if the
1050 palette changed: */
1051 if (new != old) {
1052 d->modified = 1;
1053 d->update_x1 = d->update_y1 = 0;
1054 d->update_x2 = d->max_x - 1;
1055 d->update_y2 = d->max_y - 1;
1056 }
1057 d->palette_write_subindex ++;
1058 if (d->palette_write_subindex == 3) {
1059 d->palette_write_index ++;
1060 d->palette_write_subindex = 0;
1061 }
1062 } else {
1063 odata = (d->fb->rgb_palette[d->
1064 palette_read_index * 3 +
1065 d->palette_read_subindex] >> 2) & 63;
1066 d->palette_read_subindex ++;
1067 if (d->palette_read_subindex == 3) {
1068 d->palette_read_index ++;
1069 d->palette_read_subindex = 0;
1070 }
1071 }
1072 break;
1073
1074 case VGA_MISC_OUTPUT_R:
1075 odata = d->misc_output_reg;
1076 break;
1077
1078 case VGA_GRAPHCONTR_ADDR: /* 0x0e */
1079 if (writeflag == MEM_READ)
1080 odata = d->graphcontr_reg_select;
1081 else
1082 d->graphcontr_reg_select = idata;
1083 break;
1084 case VGA_GRAPHCONTR_DATA: /* 0x0f */
1085 if (writeflag == MEM_READ)
1086 odata = d->graphcontr_reg[
1087 d->graphcontr_reg_select];
1088 else {
1089 d->graphcontr_reg[d->
1090 graphcontr_reg_select] = idata;
1091 vga_graphcontr_reg_write(cpu->machine, d,
1092 d->graphcontr_reg_select, idata);
1093 }
1094 break;
1095
1096 case VGA_CRTC_ADDR: /* 0x14 */
1097 if (writeflag == MEM_READ)
1098 odata = d->crtc_reg_select;
1099 else
1100 d->crtc_reg_select = idata;
1101 break;
1102 case VGA_CRTC_DATA: /* 0x15 */
1103 if (writeflag == MEM_READ)
1104 odata = d->crtc_reg[d->crtc_reg_select];
1105 else {
1106 d->crtc_reg[d->crtc_reg_select] = idata;
1107 vga_crtc_reg_write(cpu->machine, d,
1108 d->crtc_reg_select, idata);
1109 }
1110 break;
1111
1112 case VGA_INPUT_STATUS_1: /* 0x1A */
1113 odata = 0;
1114 d->n_is1_reads ++;
1115 d->current_retrace_line ++;
1116 d->current_retrace_line %= (MAX_RETRACE_SCANLINES * 8);
1117 /* Whenever we are "inside" a scan line, copy the
1118 current palette into retrace_palette[][]: */
1119 if ((d->current_retrace_line & 7) == 7) {
1120 if (d->retrace_palette == NULL &&
1121 d->n_is1_reads > N_IS1_READ_THRESHOLD) {
1122 d->retrace_palette = malloc(
1123 MAX_RETRACE_SCANLINES * 256*3);
1124 if (d->retrace_palette == NULL) {
1125 fatal("out of memory\n");
1126 exit(1);
1127 }
1128 }
1129 if (d->retrace_palette != NULL)
1130 memcpy(d->retrace_palette + (d->
1131 current_retrace_line >> 3) * 256*3,
1132 d->fb->rgb_palette, d->cur_mode ==
1133 MODE_CHARCELL? (16*3) : (256*3));
1134 }
1135 /* These need to go on and off, to fake the
1136 real vertical and horizontal retrace info. */
1137 if (d->current_retrace_line < 20*8)
1138 odata |= VGA_IS1_DISPLAY_VRETRACE;
1139 else {
1140 if ((d->current_retrace_line & 7) == 0)
1141 odata = VGA_IS1_DISPLAY_DISPLAY_DISABLE;
1142 }
1143 break;
1144
1145 default:
1146 if (writeflag==MEM_READ) {
1147 debug("[ vga_ctrl: read from 0x%08lx ]\n",
1148 (long)relative_addr);
1149 } else {
1150 debug("[ vga_ctrl: write to 0x%08lx: 0x%08x"
1151 " ]\n", (long)relative_addr, (int)idata);
1152 }
1153 }
1154
1155 if (writeflag == MEM_READ)
1156 data[i] = odata;
1157
1158 /* For multi-byte accesses: */
1159 relative_addr ++;
1160 }
1161
1162 return 1;
1163 }
1164
1165
1166 /*
1167 * dev_vga_init():
1168 *
1169 * Register a VGA text console device. max_x and max_y could be something
1170 * like 80 and 25, respectively.
1171 */
1172 void dev_vga_init(struct machine *machine, struct memory *mem,
1173 uint64_t videomem_base, uint64_t control_base, char *name)
1174 {
1175 struct vga_data *d;
1176 int i;
1177 size_t allocsize;
1178
1179 d = malloc(sizeof(struct vga_data));
1180 if (d == NULL) {
1181 fprintf(stderr, "out of memory\n");
1182 exit(1);
1183 }
1184 memset(d, 0, sizeof(struct vga_data));
1185
1186 d->console_handle = console_start_slave(machine, name);
1187
1188 d->videomem_base = videomem_base;
1189 d->control_base = control_base;
1190 d->max_x = 80;
1191 d->max_y = 25;
1192 d->pixel_repx = 1;
1193 d->pixel_repy = 1;
1194 d->cur_mode = MODE_CHARCELL;
1195 d->crtc_reg[0xff] = 0x03;
1196 d->charcells_size = 0x8000;
1197 d->gfx_mem_size = 1; /* Nothing, as we start in text mode */
1198
1199 /* Allocate in full pages, to make it possible to use bintrans: */
1200 allocsize = ((d->charcells_size-1) | (machine->arch_pagesize-1)) + 1;
1201 d->charcells = malloc(d->charcells_size);
1202 d->charcells_outputed = malloc(d->charcells_size);
1203 d->charcells_drawn = malloc(d->charcells_size);
1204 d->gfx_mem = malloc(d->gfx_mem_size);
1205 if (d->charcells == NULL || d->charcells_outputed == NULL ||
1206 d->charcells_drawn == NULL || d->gfx_mem == NULL) {
1207 fprintf(stderr, "out of memory in dev_vga_init()\n");
1208 exit(1);
1209 }
1210
1211 memset(d->charcells_drawn, 0, d->charcells_size);
1212
1213 for (i=0; i<d->charcells_size; i+=2) {
1214 d->charcells[i] = ' ';
1215 d->charcells[i+1] = 0x07; /* Default color */
1216 d->charcells_drawn[i] = ' ';
1217 d->charcells_drawn[i+1] = 0x07;
1218 }
1219
1220 memset(d->charcells_outputed, 0, d->charcells_size);
1221 memset(d->gfx_mem, 0, d->gfx_mem_size);
1222
1223 d->font = font8x16;
1224 d->font_width = 8;
1225 d->font_height = 16;
1226
1227 d->fb_max_x = d->pixel_repx * d->max_x;
1228 d->fb_max_y = d->pixel_repy * d->max_y;
1229 if (d->cur_mode == MODE_CHARCELL) {
1230 d->fb_max_x *= d->font_width;
1231 d->fb_max_y *= d->font_height;
1232 }
1233
1234 memory_device_register(mem, "vga_charcells", videomem_base + 0x18000,
1235 allocsize, dev_vga_access, d, MEM_DYNTRANS_OK |
1236 MEM_DYNTRANS_WRITE_OK | MEM_READING_HAS_NO_SIDE_EFFECTS,
1237 d->charcells);
1238 memory_device_register(mem, "vga_gfx", videomem_base, GFX_ADDR_WINDOW,
1239 dev_vga_graphics_access, d, MEM_DEFAULT |
1240 MEM_READING_HAS_NO_SIDE_EFFECTS, d->gfx_mem);
1241 memory_device_register(mem, "vga_ctrl", control_base,
1242 32, dev_vga_ctrl_access, d, MEM_DEFAULT, NULL);
1243
1244 d->fb = dev_fb_init(machine, mem, VGA_FB_ADDR, VFB_GENERIC,
1245 d->fb_max_x, d->fb_max_y, d->fb_max_x, d->fb_max_y, 24, "VGA");
1246 d->fb_size = d->fb_max_x * d->fb_max_y * 3;
1247
1248 reset_palette(d, 0);
1249
1250 /* This will force an initial redraw/resynch: */
1251 d->update_x1 = 0;
1252 d->update_x2 = d->max_x - 1;
1253 d->update_y1 = 0;
1254 d->update_y2 = d->max_y - 1;
1255 d->modified = 1;
1256
1257 machine_add_tickfunction(machine, dev_vga_tick, d, VGA_TICK_SHIFT);
1258
1259 register_reset(d);
1260
1261 vga_update_cursor(machine, d);
1262 }
1263

  ViewVC Help
Powered by ViewVC 1.1.26