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