block: Drop tray status tracking, no longer used
[qemu.git] / hw / vga.c
blob125fb293f23f21787a3ba1657706f3412936734c
1 /*
2 * QEMU VGA Emulator.
4 * Copyright (c) 2003 Fabrice Bellard
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
24 #include "hw.h"
25 #include "console.h"
26 #include "pc.h"
27 #include "pci.h"
28 #include "vga_int.h"
29 #include "pixel_ops.h"
30 #include "qemu-timer.h"
32 //#define DEBUG_VGA
33 //#define DEBUG_VGA_MEM
34 //#define DEBUG_VGA_REG
36 //#define DEBUG_BOCHS_VBE
38 /* force some bits to zero */
39 const uint8_t sr_mask[8] = {
40 0x03,
41 0x3d,
42 0x0f,
43 0x3f,
44 0x0e,
45 0x00,
46 0x00,
47 0xff,
50 const uint8_t gr_mask[16] = {
51 0x0f, /* 0x00 */
52 0x0f, /* 0x01 */
53 0x0f, /* 0x02 */
54 0x1f, /* 0x03 */
55 0x03, /* 0x04 */
56 0x7b, /* 0x05 */
57 0x0f, /* 0x06 */
58 0x0f, /* 0x07 */
59 0xff, /* 0x08 */
60 0x00, /* 0x09 */
61 0x00, /* 0x0a */
62 0x00, /* 0x0b */
63 0x00, /* 0x0c */
64 0x00, /* 0x0d */
65 0x00, /* 0x0e */
66 0x00, /* 0x0f */
69 #define cbswap_32(__x) \
70 ((uint32_t)( \
71 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
72 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
73 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
74 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
76 #ifdef HOST_WORDS_BIGENDIAN
77 #define PAT(x) cbswap_32(x)
78 #else
79 #define PAT(x) (x)
80 #endif
82 #ifdef HOST_WORDS_BIGENDIAN
83 #define BIG 1
84 #else
85 #define BIG 0
86 #endif
88 #ifdef HOST_WORDS_BIGENDIAN
89 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
90 #else
91 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
92 #endif
94 static const uint32_t mask16[16] = {
95 PAT(0x00000000),
96 PAT(0x000000ff),
97 PAT(0x0000ff00),
98 PAT(0x0000ffff),
99 PAT(0x00ff0000),
100 PAT(0x00ff00ff),
101 PAT(0x00ffff00),
102 PAT(0x00ffffff),
103 PAT(0xff000000),
104 PAT(0xff0000ff),
105 PAT(0xff00ff00),
106 PAT(0xff00ffff),
107 PAT(0xffff0000),
108 PAT(0xffff00ff),
109 PAT(0xffffff00),
110 PAT(0xffffffff),
113 #undef PAT
115 #ifdef HOST_WORDS_BIGENDIAN
116 #define PAT(x) (x)
117 #else
118 #define PAT(x) cbswap_32(x)
119 #endif
121 static const uint32_t dmask16[16] = {
122 PAT(0x00000000),
123 PAT(0x000000ff),
124 PAT(0x0000ff00),
125 PAT(0x0000ffff),
126 PAT(0x00ff0000),
127 PAT(0x00ff00ff),
128 PAT(0x00ffff00),
129 PAT(0x00ffffff),
130 PAT(0xff000000),
131 PAT(0xff0000ff),
132 PAT(0xff00ff00),
133 PAT(0xff00ffff),
134 PAT(0xffff0000),
135 PAT(0xffff00ff),
136 PAT(0xffffff00),
137 PAT(0xffffffff),
140 static const uint32_t dmask4[4] = {
141 PAT(0x00000000),
142 PAT(0x0000ffff),
143 PAT(0xffff0000),
144 PAT(0xffffffff),
147 static uint32_t expand4[256];
148 static uint16_t expand2[256];
149 static uint8_t expand4to8[16];
151 static void vga_screen_dump(void *opaque, const char *filename);
152 static char *screen_dump_filename;
153 static DisplayChangeListener *screen_dump_dcl;
155 static void vga_update_memory_access(VGACommonState *s)
157 MemoryRegion *region, *old_region = s->chain4_alias;
158 target_phys_addr_t base, offset, size;
160 s->chain4_alias = NULL;
162 if ((s->sr[0x02] & 0xf) == 0xf && s->sr[0x04] & 0x08) {
163 offset = 0;
164 switch ((s->gr[6] >> 2) & 3) {
165 case 0:
166 base = 0xa0000;
167 size = 0x20000;
168 break;
169 case 1:
170 base = 0xa0000;
171 size = 0x10000;
172 offset = s->bank_offset;
173 break;
174 case 2:
175 base = 0xb0000;
176 size = 0x8000;
177 break;
178 case 3:
179 default:
180 base = 0xb8000;
181 size = 0x8000;
182 break;
184 region = g_malloc(sizeof(*region));
185 memory_region_init_alias(region, "vga.chain4", &s->vram, offset, size);
186 memory_region_add_subregion_overlap(s->legacy_address_space, base,
187 region, 2);
188 s->chain4_alias = region;
190 if (old_region) {
191 memory_region_del_subregion(s->legacy_address_space, old_region);
192 memory_region_destroy(old_region);
193 g_free(old_region);
194 s->plane_updated = 0xf;
198 static void vga_dumb_update_retrace_info(VGACommonState *s)
200 (void) s;
203 static void vga_precise_update_retrace_info(VGACommonState *s)
205 int htotal_chars;
206 int hretr_start_char;
207 int hretr_skew_chars;
208 int hretr_end_char;
210 int vtotal_lines;
211 int vretr_start_line;
212 int vretr_end_line;
214 int dots;
215 #if 0
216 int div2, sldiv2;
217 #endif
218 int clocking_mode;
219 int clock_sel;
220 const int clk_hz[] = {25175000, 28322000, 25175000, 25175000};
221 int64_t chars_per_sec;
222 struct vga_precise_retrace *r = &s->retrace_info.precise;
224 htotal_chars = s->cr[0x00] + 5;
225 hretr_start_char = s->cr[0x04];
226 hretr_skew_chars = (s->cr[0x05] >> 5) & 3;
227 hretr_end_char = s->cr[0x05] & 0x1f;
229 vtotal_lines = (s->cr[0x06]
230 | (((s->cr[0x07] & 1) | ((s->cr[0x07] >> 4) & 2)) << 8)) + 2
232 vretr_start_line = s->cr[0x10]
233 | ((((s->cr[0x07] >> 2) & 1) | ((s->cr[0x07] >> 6) & 2)) << 8)
235 vretr_end_line = s->cr[0x11] & 0xf;
239 clocking_mode = (s->sr[0x01] >> 3) & 1;
240 clock_sel = (s->msr >> 2) & 3;
241 dots = (s->msr & 1) ? 8 : 9;
243 chars_per_sec = clk_hz[clock_sel] / dots;
245 htotal_chars <<= clocking_mode;
247 r->total_chars = vtotal_lines * htotal_chars;
248 if (r->freq) {
249 r->ticks_per_char = get_ticks_per_sec() / (r->total_chars * r->freq);
250 } else {
251 r->ticks_per_char = get_ticks_per_sec() / chars_per_sec;
254 r->vstart = vretr_start_line;
255 r->vend = r->vstart + vretr_end_line + 1;
257 r->hstart = hretr_start_char + hretr_skew_chars;
258 r->hend = r->hstart + hretr_end_char + 1;
259 r->htotal = htotal_chars;
261 #if 0
262 div2 = (s->cr[0x17] >> 2) & 1;
263 sldiv2 = (s->cr[0x17] >> 3) & 1;
264 printf (
265 "hz=%f\n"
266 "htotal = %d\n"
267 "hretr_start = %d\n"
268 "hretr_skew = %d\n"
269 "hretr_end = %d\n"
270 "vtotal = %d\n"
271 "vretr_start = %d\n"
272 "vretr_end = %d\n"
273 "div2 = %d sldiv2 = %d\n"
274 "clocking_mode = %d\n"
275 "clock_sel = %d %d\n"
276 "dots = %d\n"
277 "ticks/char = %" PRId64 "\n"
278 "\n",
279 (double) get_ticks_per_sec() / (r->ticks_per_char * r->total_chars),
280 htotal_chars,
281 hretr_start_char,
282 hretr_skew_chars,
283 hretr_end_char,
284 vtotal_lines,
285 vretr_start_line,
286 vretr_end_line,
287 div2, sldiv2,
288 clocking_mode,
289 clock_sel,
290 clk_hz[clock_sel],
291 dots,
292 r->ticks_per_char
294 #endif
297 static uint8_t vga_precise_retrace(VGACommonState *s)
299 struct vga_precise_retrace *r = &s->retrace_info.precise;
300 uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE);
302 if (r->total_chars) {
303 int cur_line, cur_line_char, cur_char;
304 int64_t cur_tick;
306 cur_tick = qemu_get_clock_ns(vm_clock);
308 cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
309 cur_line = cur_char / r->htotal;
311 if (cur_line >= r->vstart && cur_line <= r->vend) {
312 val |= ST01_V_RETRACE | ST01_DISP_ENABLE;
313 } else {
314 cur_line_char = cur_char % r->htotal;
315 if (cur_line_char >= r->hstart && cur_line_char <= r->hend) {
316 val |= ST01_DISP_ENABLE;
320 return val;
321 } else {
322 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
326 static uint8_t vga_dumb_retrace(VGACommonState *s)
328 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
331 int vga_ioport_invalid(VGACommonState *s, uint32_t addr)
333 if (s->msr & MSR_COLOR_EMULATION) {
334 /* Color */
335 return (addr >= 0x3b0 && addr <= 0x3bf);
336 } else {
337 /* Monochrome */
338 return (addr >= 0x3d0 && addr <= 0x3df);
342 uint32_t vga_ioport_read(void *opaque, uint32_t addr)
344 VGACommonState *s = opaque;
345 int val, index;
347 if (vga_ioport_invalid(s, addr)) {
348 val = 0xff;
349 } else {
350 switch(addr) {
351 case 0x3c0:
352 if (s->ar_flip_flop == 0) {
353 val = s->ar_index;
354 } else {
355 val = 0;
357 break;
358 case 0x3c1:
359 index = s->ar_index & 0x1f;
360 if (index < 21)
361 val = s->ar[index];
362 else
363 val = 0;
364 break;
365 case 0x3c2:
366 val = s->st00;
367 break;
368 case 0x3c4:
369 val = s->sr_index;
370 break;
371 case 0x3c5:
372 val = s->sr[s->sr_index];
373 #ifdef DEBUG_VGA_REG
374 printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
375 #endif
376 break;
377 case 0x3c7:
378 val = s->dac_state;
379 break;
380 case 0x3c8:
381 val = s->dac_write_index;
382 break;
383 case 0x3c9:
384 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
385 if (++s->dac_sub_index == 3) {
386 s->dac_sub_index = 0;
387 s->dac_read_index++;
389 break;
390 case 0x3ca:
391 val = s->fcr;
392 break;
393 case 0x3cc:
394 val = s->msr;
395 break;
396 case 0x3ce:
397 val = s->gr_index;
398 break;
399 case 0x3cf:
400 val = s->gr[s->gr_index];
401 #ifdef DEBUG_VGA_REG
402 printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
403 #endif
404 break;
405 case 0x3b4:
406 case 0x3d4:
407 val = s->cr_index;
408 break;
409 case 0x3b5:
410 case 0x3d5:
411 val = s->cr[s->cr_index];
412 #ifdef DEBUG_VGA_REG
413 printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
414 #endif
415 break;
416 case 0x3ba:
417 case 0x3da:
418 /* just toggle to fool polling */
419 val = s->st01 = s->retrace(s);
420 s->ar_flip_flop = 0;
421 break;
422 default:
423 val = 0x00;
424 break;
427 #if defined(DEBUG_VGA)
428 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
429 #endif
430 return val;
433 void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
435 VGACommonState *s = opaque;
436 int index;
438 /* check port range access depending on color/monochrome mode */
439 if (vga_ioport_invalid(s, addr)) {
440 return;
442 #ifdef DEBUG_VGA
443 printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
444 #endif
446 switch(addr) {
447 case 0x3c0:
448 if (s->ar_flip_flop == 0) {
449 val &= 0x3f;
450 s->ar_index = val;
451 } else {
452 index = s->ar_index & 0x1f;
453 switch(index) {
454 case 0x00 ... 0x0f:
455 s->ar[index] = val & 0x3f;
456 break;
457 case 0x10:
458 s->ar[index] = val & ~0x10;
459 break;
460 case 0x11:
461 s->ar[index] = val;
462 break;
463 case 0x12:
464 s->ar[index] = val & ~0xc0;
465 break;
466 case 0x13:
467 s->ar[index] = val & ~0xf0;
468 break;
469 case 0x14:
470 s->ar[index] = val & ~0xf0;
471 break;
472 default:
473 break;
476 s->ar_flip_flop ^= 1;
477 break;
478 case 0x3c2:
479 s->msr = val & ~0x10;
480 s->update_retrace_info(s);
481 break;
482 case 0x3c4:
483 s->sr_index = val & 7;
484 break;
485 case 0x3c5:
486 #ifdef DEBUG_VGA_REG
487 printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
488 #endif
489 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
490 if (s->sr_index == 1) s->update_retrace_info(s);
491 vga_update_memory_access(s);
492 break;
493 case 0x3c7:
494 s->dac_read_index = val;
495 s->dac_sub_index = 0;
496 s->dac_state = 3;
497 break;
498 case 0x3c8:
499 s->dac_write_index = val;
500 s->dac_sub_index = 0;
501 s->dac_state = 0;
502 break;
503 case 0x3c9:
504 s->dac_cache[s->dac_sub_index] = val;
505 if (++s->dac_sub_index == 3) {
506 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
507 s->dac_sub_index = 0;
508 s->dac_write_index++;
510 break;
511 case 0x3ce:
512 s->gr_index = val & 0x0f;
513 break;
514 case 0x3cf:
515 #ifdef DEBUG_VGA_REG
516 printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
517 #endif
518 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
519 vga_update_memory_access(s);
520 break;
521 case 0x3b4:
522 case 0x3d4:
523 s->cr_index = val;
524 break;
525 case 0x3b5:
526 case 0x3d5:
527 #ifdef DEBUG_VGA_REG
528 printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
529 #endif
530 /* handle CR0-7 protection */
531 if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
532 /* can always write bit 4 of CR7 */
533 if (s->cr_index == 7)
534 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
535 return;
537 s->cr[s->cr_index] = val;
539 switch(s->cr_index) {
540 case 0x00:
541 case 0x04:
542 case 0x05:
543 case 0x06:
544 case 0x07:
545 case 0x11:
546 case 0x17:
547 s->update_retrace_info(s);
548 break;
550 break;
551 case 0x3ba:
552 case 0x3da:
553 s->fcr = val & 0x10;
554 break;
558 #ifdef CONFIG_BOCHS_VBE
559 static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
561 VGACommonState *s = opaque;
562 uint32_t val;
563 val = s->vbe_index;
564 return val;
567 static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
569 VGACommonState *s = opaque;
570 uint32_t val;
572 if (s->vbe_index < VBE_DISPI_INDEX_NB) {
573 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
574 switch(s->vbe_index) {
575 /* XXX: do not hardcode ? */
576 case VBE_DISPI_INDEX_XRES:
577 val = VBE_DISPI_MAX_XRES;
578 break;
579 case VBE_DISPI_INDEX_YRES:
580 val = VBE_DISPI_MAX_YRES;
581 break;
582 case VBE_DISPI_INDEX_BPP:
583 val = VBE_DISPI_MAX_BPP;
584 break;
585 default:
586 val = s->vbe_regs[s->vbe_index];
587 break;
589 } else {
590 val = s->vbe_regs[s->vbe_index];
592 } else if (s->vbe_index == VBE_DISPI_INDEX_VIDEO_MEMORY_64K) {
593 val = s->vram_size / (64 * 1024);
594 } else {
595 val = 0;
597 #ifdef DEBUG_BOCHS_VBE
598 printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
599 #endif
600 return val;
603 static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
605 VGACommonState *s = opaque;
606 s->vbe_index = val;
609 static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
611 VGACommonState *s = opaque;
613 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
614 #ifdef DEBUG_BOCHS_VBE
615 printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
616 #endif
617 switch(s->vbe_index) {
618 case VBE_DISPI_INDEX_ID:
619 if (val == VBE_DISPI_ID0 ||
620 val == VBE_DISPI_ID1 ||
621 val == VBE_DISPI_ID2 ||
622 val == VBE_DISPI_ID3 ||
623 val == VBE_DISPI_ID4) {
624 s->vbe_regs[s->vbe_index] = val;
626 break;
627 case VBE_DISPI_INDEX_XRES:
628 if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
629 s->vbe_regs[s->vbe_index] = val;
631 break;
632 case VBE_DISPI_INDEX_YRES:
633 if (val <= VBE_DISPI_MAX_YRES) {
634 s->vbe_regs[s->vbe_index] = val;
636 break;
637 case VBE_DISPI_INDEX_BPP:
638 if (val == 0)
639 val = 8;
640 if (val == 4 || val == 8 || val == 15 ||
641 val == 16 || val == 24 || val == 32) {
642 s->vbe_regs[s->vbe_index] = val;
644 break;
645 case VBE_DISPI_INDEX_BANK:
646 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
647 val &= (s->vbe_bank_mask >> 2);
648 } else {
649 val &= s->vbe_bank_mask;
651 s->vbe_regs[s->vbe_index] = val;
652 s->bank_offset = (val << 16);
653 vga_update_memory_access(s);
654 break;
655 case VBE_DISPI_INDEX_ENABLE:
656 if ((val & VBE_DISPI_ENABLED) &&
657 !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
658 int h, shift_control;
660 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
661 s->vbe_regs[VBE_DISPI_INDEX_XRES];
662 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
663 s->vbe_regs[VBE_DISPI_INDEX_YRES];
664 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
665 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
667 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
668 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
669 else
670 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
671 ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
672 s->vbe_start_addr = 0;
674 /* clear the screen (should be done in BIOS) */
675 if (!(val & VBE_DISPI_NOCLEARMEM)) {
676 memset(s->vram_ptr, 0,
677 s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
680 /* we initialize the VGA graphic mode (should be done
681 in BIOS) */
682 s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
683 s->cr[0x17] |= 3; /* no CGA modes */
684 s->cr[0x13] = s->vbe_line_offset >> 3;
685 /* width */
686 s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
687 /* height (only meaningful if < 1024) */
688 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
689 s->cr[0x12] = h;
690 s->cr[0x07] = (s->cr[0x07] & ~0x42) |
691 ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
692 /* line compare to 1023 */
693 s->cr[0x18] = 0xff;
694 s->cr[0x07] |= 0x10;
695 s->cr[0x09] |= 0x40;
697 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
698 shift_control = 0;
699 s->sr[0x01] &= ~8; /* no double line */
700 } else {
701 shift_control = 2;
702 s->sr[4] |= 0x08; /* set chain 4 mode */
703 s->sr[2] |= 0x0f; /* activate all planes */
705 s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
706 s->cr[0x09] &= ~0x9f; /* no double scan */
707 } else {
708 /* XXX: the bios should do that */
709 s->bank_offset = 0;
711 s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
712 s->vbe_regs[s->vbe_index] = val;
713 vga_update_memory_access(s);
714 break;
715 case VBE_DISPI_INDEX_VIRT_WIDTH:
717 int w, h, line_offset;
719 if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
720 return;
721 w = val;
722 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
723 line_offset = w >> 1;
724 else
725 line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
726 h = s->vram_size / line_offset;
727 /* XXX: support weird bochs semantics ? */
728 if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
729 return;
730 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
731 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
732 s->vbe_line_offset = line_offset;
734 break;
735 case VBE_DISPI_INDEX_X_OFFSET:
736 case VBE_DISPI_INDEX_Y_OFFSET:
738 int x;
739 s->vbe_regs[s->vbe_index] = val;
740 s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
741 x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
742 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
743 s->vbe_start_addr += x >> 1;
744 else
745 s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
746 s->vbe_start_addr >>= 2;
748 break;
749 default:
750 break;
754 #endif
756 /* called for accesses between 0xa0000 and 0xc0000 */
757 uint32_t vga_mem_readb(VGACommonState *s, target_phys_addr_t addr)
759 int memory_map_mode, plane;
760 uint32_t ret;
762 /* convert to VGA memory offset */
763 memory_map_mode = (s->gr[6] >> 2) & 3;
764 addr &= 0x1ffff;
765 switch(memory_map_mode) {
766 case 0:
767 break;
768 case 1:
769 if (addr >= 0x10000)
770 return 0xff;
771 addr += s->bank_offset;
772 break;
773 case 2:
774 addr -= 0x10000;
775 if (addr >= 0x8000)
776 return 0xff;
777 break;
778 default:
779 case 3:
780 addr -= 0x18000;
781 if (addr >= 0x8000)
782 return 0xff;
783 break;
786 if (s->sr[4] & 0x08) {
787 /* chain 4 mode : simplest access */
788 ret = s->vram_ptr[addr];
789 } else if (s->gr[5] & 0x10) {
790 /* odd/even mode (aka text mode mapping) */
791 plane = (s->gr[4] & 2) | (addr & 1);
792 ret = s->vram_ptr[((addr & ~1) << 1) | plane];
793 } else {
794 /* standard VGA latched access */
795 s->latch = ((uint32_t *)s->vram_ptr)[addr];
797 if (!(s->gr[5] & 0x08)) {
798 /* read mode 0 */
799 plane = s->gr[4];
800 ret = GET_PLANE(s->latch, plane);
801 } else {
802 /* read mode 1 */
803 ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
804 ret |= ret >> 16;
805 ret |= ret >> 8;
806 ret = (~ret) & 0xff;
809 return ret;
812 /* called for accesses between 0xa0000 and 0xc0000 */
813 void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val)
815 int memory_map_mode, plane, write_mode, b, func_select, mask;
816 uint32_t write_mask, bit_mask, set_mask;
818 #ifdef DEBUG_VGA_MEM
819 printf("vga: [0x" TARGET_FMT_plx "] = 0x%02x\n", addr, val);
820 #endif
821 /* convert to VGA memory offset */
822 memory_map_mode = (s->gr[6] >> 2) & 3;
823 addr &= 0x1ffff;
824 switch(memory_map_mode) {
825 case 0:
826 break;
827 case 1:
828 if (addr >= 0x10000)
829 return;
830 addr += s->bank_offset;
831 break;
832 case 2:
833 addr -= 0x10000;
834 if (addr >= 0x8000)
835 return;
836 break;
837 default:
838 case 3:
839 addr -= 0x18000;
840 if (addr >= 0x8000)
841 return;
842 break;
845 if (s->sr[4] & 0x08) {
846 /* chain 4 mode : simplest access */
847 plane = addr & 3;
848 mask = (1 << plane);
849 if (s->sr[2] & mask) {
850 s->vram_ptr[addr] = val;
851 #ifdef DEBUG_VGA_MEM
852 printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
853 #endif
854 s->plane_updated |= mask; /* only used to detect font change */
855 memory_region_set_dirty(&s->vram, addr);
857 } else if (s->gr[5] & 0x10) {
858 /* odd/even mode (aka text mode mapping) */
859 plane = (s->gr[4] & 2) | (addr & 1);
860 mask = (1 << plane);
861 if (s->sr[2] & mask) {
862 addr = ((addr & ~1) << 1) | plane;
863 s->vram_ptr[addr] = val;
864 #ifdef DEBUG_VGA_MEM
865 printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
866 #endif
867 s->plane_updated |= mask; /* only used to detect font change */
868 memory_region_set_dirty(&s->vram, addr);
870 } else {
871 /* standard VGA latched access */
872 write_mode = s->gr[5] & 3;
873 switch(write_mode) {
874 default:
875 case 0:
876 /* rotate */
877 b = s->gr[3] & 7;
878 val = ((val >> b) | (val << (8 - b))) & 0xff;
879 val |= val << 8;
880 val |= val << 16;
882 /* apply set/reset mask */
883 set_mask = mask16[s->gr[1]];
884 val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
885 bit_mask = s->gr[8];
886 break;
887 case 1:
888 val = s->latch;
889 goto do_write;
890 case 2:
891 val = mask16[val & 0x0f];
892 bit_mask = s->gr[8];
893 break;
894 case 3:
895 /* rotate */
896 b = s->gr[3] & 7;
897 val = (val >> b) | (val << (8 - b));
899 bit_mask = s->gr[8] & val;
900 val = mask16[s->gr[0]];
901 break;
904 /* apply logical operation */
905 func_select = s->gr[3] >> 3;
906 switch(func_select) {
907 case 0:
908 default:
909 /* nothing to do */
910 break;
911 case 1:
912 /* and */
913 val &= s->latch;
914 break;
915 case 2:
916 /* or */
917 val |= s->latch;
918 break;
919 case 3:
920 /* xor */
921 val ^= s->latch;
922 break;
925 /* apply bit mask */
926 bit_mask |= bit_mask << 8;
927 bit_mask |= bit_mask << 16;
928 val = (val & bit_mask) | (s->latch & ~bit_mask);
930 do_write:
931 /* mask data according to sr[2] */
932 mask = s->sr[2];
933 s->plane_updated |= mask; /* only used to detect font change */
934 write_mask = mask16[mask];
935 ((uint32_t *)s->vram_ptr)[addr] =
936 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
937 (val & write_mask);
938 #ifdef DEBUG_VGA_MEM
939 printf("vga: latch: [0x" TARGET_FMT_plx "] mask=0x%08x val=0x%08x\n",
940 addr * 4, write_mask, val);
941 #endif
942 memory_region_set_dirty(&s->vram, addr << 2);
946 typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
947 const uint8_t *font_ptr, int h,
948 uint32_t fgcol, uint32_t bgcol);
949 typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
950 const uint8_t *font_ptr, int h,
951 uint32_t fgcol, uint32_t bgcol, int dup9);
952 typedef void vga_draw_line_func(VGACommonState *s1, uint8_t *d,
953 const uint8_t *s, int width);
955 #define DEPTH 8
956 #include "vga_template.h"
958 #define DEPTH 15
959 #include "vga_template.h"
961 #define BGR_FORMAT
962 #define DEPTH 15
963 #include "vga_template.h"
965 #define DEPTH 16
966 #include "vga_template.h"
968 #define BGR_FORMAT
969 #define DEPTH 16
970 #include "vga_template.h"
972 #define DEPTH 32
973 #include "vga_template.h"
975 #define BGR_FORMAT
976 #define DEPTH 32
977 #include "vga_template.h"
979 static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
981 unsigned int col;
982 col = rgb_to_pixel8(r, g, b);
983 col |= col << 8;
984 col |= col << 16;
985 return col;
988 static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
990 unsigned int col;
991 col = rgb_to_pixel15(r, g, b);
992 col |= col << 16;
993 return col;
996 static unsigned int rgb_to_pixel15bgr_dup(unsigned int r, unsigned int g,
997 unsigned int b)
999 unsigned int col;
1000 col = rgb_to_pixel15bgr(r, g, b);
1001 col |= col << 16;
1002 return col;
1005 static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
1007 unsigned int col;
1008 col = rgb_to_pixel16(r, g, b);
1009 col |= col << 16;
1010 return col;
1013 static unsigned int rgb_to_pixel16bgr_dup(unsigned int r, unsigned int g,
1014 unsigned int b)
1016 unsigned int col;
1017 col = rgb_to_pixel16bgr(r, g, b);
1018 col |= col << 16;
1019 return col;
1022 static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
1024 unsigned int col;
1025 col = rgb_to_pixel32(r, g, b);
1026 return col;
1029 static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b)
1031 unsigned int col;
1032 col = rgb_to_pixel32bgr(r, g, b);
1033 return col;
1036 /* return true if the palette was modified */
1037 static int update_palette16(VGACommonState *s)
1039 int full_update, i;
1040 uint32_t v, col, *palette;
1042 full_update = 0;
1043 palette = s->last_palette;
1044 for(i = 0; i < 16; i++) {
1045 v = s->ar[i];
1046 if (s->ar[0x10] & 0x80)
1047 v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
1048 else
1049 v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
1050 v = v * 3;
1051 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1052 c6_to_8(s->palette[v + 1]),
1053 c6_to_8(s->palette[v + 2]));
1054 if (col != palette[i]) {
1055 full_update = 1;
1056 palette[i] = col;
1059 return full_update;
1062 /* return true if the palette was modified */
1063 static int update_palette256(VGACommonState *s)
1065 int full_update, i;
1066 uint32_t v, col, *palette;
1068 full_update = 0;
1069 palette = s->last_palette;
1070 v = 0;
1071 for(i = 0; i < 256; i++) {
1072 if (s->dac_8bit) {
1073 col = s->rgb_to_pixel(s->palette[v],
1074 s->palette[v + 1],
1075 s->palette[v + 2]);
1076 } else {
1077 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1078 c6_to_8(s->palette[v + 1]),
1079 c6_to_8(s->palette[v + 2]));
1081 if (col != palette[i]) {
1082 full_update = 1;
1083 palette[i] = col;
1085 v += 3;
1087 return full_update;
1090 static void vga_get_offsets(VGACommonState *s,
1091 uint32_t *pline_offset,
1092 uint32_t *pstart_addr,
1093 uint32_t *pline_compare)
1095 uint32_t start_addr, line_offset, line_compare;
1096 #ifdef CONFIG_BOCHS_VBE
1097 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1098 line_offset = s->vbe_line_offset;
1099 start_addr = s->vbe_start_addr;
1100 line_compare = 65535;
1101 } else
1102 #endif
1104 /* compute line_offset in bytes */
1105 line_offset = s->cr[0x13];
1106 line_offset <<= 3;
1108 /* starting address */
1109 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
1111 /* line compare */
1112 line_compare = s->cr[0x18] |
1113 ((s->cr[0x07] & 0x10) << 4) |
1114 ((s->cr[0x09] & 0x40) << 3);
1116 *pline_offset = line_offset;
1117 *pstart_addr = start_addr;
1118 *pline_compare = line_compare;
1121 /* update start_addr and line_offset. Return TRUE if modified */
1122 static int update_basic_params(VGACommonState *s)
1124 int full_update;
1125 uint32_t start_addr, line_offset, line_compare;
1127 full_update = 0;
1129 s->get_offsets(s, &line_offset, &start_addr, &line_compare);
1131 if (line_offset != s->line_offset ||
1132 start_addr != s->start_addr ||
1133 line_compare != s->line_compare) {
1134 s->line_offset = line_offset;
1135 s->start_addr = start_addr;
1136 s->line_compare = line_compare;
1137 full_update = 1;
1139 return full_update;
1142 #define NB_DEPTHS 7
1144 static inline int get_depth_index(DisplayState *s)
1146 switch(ds_get_bits_per_pixel(s)) {
1147 default:
1148 case 8:
1149 return 0;
1150 case 15:
1151 return 1;
1152 case 16:
1153 return 2;
1154 case 32:
1155 if (is_surface_bgr(s->surface))
1156 return 4;
1157 else
1158 return 3;
1162 static vga_draw_glyph8_func * const vga_draw_glyph8_table[NB_DEPTHS] = {
1163 vga_draw_glyph8_8,
1164 vga_draw_glyph8_16,
1165 vga_draw_glyph8_16,
1166 vga_draw_glyph8_32,
1167 vga_draw_glyph8_32,
1168 vga_draw_glyph8_16,
1169 vga_draw_glyph8_16,
1172 static vga_draw_glyph8_func * const vga_draw_glyph16_table[NB_DEPTHS] = {
1173 vga_draw_glyph16_8,
1174 vga_draw_glyph16_16,
1175 vga_draw_glyph16_16,
1176 vga_draw_glyph16_32,
1177 vga_draw_glyph16_32,
1178 vga_draw_glyph16_16,
1179 vga_draw_glyph16_16,
1182 static vga_draw_glyph9_func * const vga_draw_glyph9_table[NB_DEPTHS] = {
1183 vga_draw_glyph9_8,
1184 vga_draw_glyph9_16,
1185 vga_draw_glyph9_16,
1186 vga_draw_glyph9_32,
1187 vga_draw_glyph9_32,
1188 vga_draw_glyph9_16,
1189 vga_draw_glyph9_16,
1192 static const uint8_t cursor_glyph[32 * 4] = {
1193 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1194 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1195 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1196 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1197 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1198 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1199 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1200 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1201 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1202 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1203 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1204 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1205 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1206 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1207 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1208 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1211 static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight,
1212 int *pcwidth, int *pcheight)
1214 int width, cwidth, height, cheight;
1216 /* total width & height */
1217 cheight = (s->cr[9] & 0x1f) + 1;
1218 cwidth = 8;
1219 if (!(s->sr[1] & 0x01))
1220 cwidth = 9;
1221 if (s->sr[1] & 0x08)
1222 cwidth = 16; /* NOTE: no 18 pixel wide */
1223 width = (s->cr[0x01] + 1);
1224 if (s->cr[0x06] == 100) {
1225 /* ugly hack for CGA 160x100x16 - explain me the logic */
1226 height = 100;
1227 } else {
1228 height = s->cr[0x12] |
1229 ((s->cr[0x07] & 0x02) << 7) |
1230 ((s->cr[0x07] & 0x40) << 3);
1231 height = (height + 1) / cheight;
1234 *pwidth = width;
1235 *pheight = height;
1236 *pcwidth = cwidth;
1237 *pcheight = cheight;
1240 typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
1242 static rgb_to_pixel_dup_func * const rgb_to_pixel_dup_table[NB_DEPTHS] = {
1243 rgb_to_pixel8_dup,
1244 rgb_to_pixel15_dup,
1245 rgb_to_pixel16_dup,
1246 rgb_to_pixel32_dup,
1247 rgb_to_pixel32bgr_dup,
1248 rgb_to_pixel15bgr_dup,
1249 rgb_to_pixel16bgr_dup,
1253 * Text mode update
1254 * Missing:
1255 * - double scan
1256 * - double width
1257 * - underline
1258 * - flashing
1260 static void vga_draw_text(VGACommonState *s, int full_update)
1262 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1263 int cx_min, cx_max, linesize, x_incr, line, line1;
1264 uint32_t offset, fgcol, bgcol, v, cursor_offset;
1265 uint8_t *d1, *d, *src, *dest, *cursor_ptr;
1266 const uint8_t *font_ptr, *font_base[2];
1267 int dup9, line_offset, depth_index;
1268 uint32_t *palette;
1269 uint32_t *ch_attr_ptr;
1270 vga_draw_glyph8_func *vga_draw_glyph8;
1271 vga_draw_glyph9_func *vga_draw_glyph9;
1273 /* compute font data address (in plane 2) */
1274 v = s->sr[3];
1275 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1276 if (offset != s->font_offsets[0]) {
1277 s->font_offsets[0] = offset;
1278 full_update = 1;
1280 font_base[0] = s->vram_ptr + offset;
1282 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1283 font_base[1] = s->vram_ptr + offset;
1284 if (offset != s->font_offsets[1]) {
1285 s->font_offsets[1] = offset;
1286 full_update = 1;
1288 if (s->plane_updated & (1 << 2) || s->chain4_alias) {
1289 /* if the plane 2 was modified since the last display, it
1290 indicates the font may have been modified */
1291 s->plane_updated = 0;
1292 full_update = 1;
1294 full_update |= update_basic_params(s);
1296 line_offset = s->line_offset;
1298 vga_get_text_resolution(s, &width, &height, &cw, &cheight);
1299 if ((height * width) > CH_ATTR_SIZE) {
1300 /* better than nothing: exit if transient size is too big */
1301 return;
1304 if (width != s->last_width || height != s->last_height ||
1305 cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
1306 s->last_scr_width = width * cw;
1307 s->last_scr_height = height * cheight;
1308 qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height);
1309 s->last_depth = 0;
1310 s->last_width = width;
1311 s->last_height = height;
1312 s->last_ch = cheight;
1313 s->last_cw = cw;
1314 full_update = 1;
1316 s->rgb_to_pixel =
1317 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1318 full_update |= update_palette16(s);
1319 palette = s->last_palette;
1320 x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1322 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1323 if (cursor_offset != s->cursor_offset ||
1324 s->cr[0xa] != s->cursor_start ||
1325 s->cr[0xb] != s->cursor_end) {
1326 /* if the cursor position changed, we update the old and new
1327 chars */
1328 if (s->cursor_offset < CH_ATTR_SIZE)
1329 s->last_ch_attr[s->cursor_offset] = -1;
1330 if (cursor_offset < CH_ATTR_SIZE)
1331 s->last_ch_attr[cursor_offset] = -1;
1332 s->cursor_offset = cursor_offset;
1333 s->cursor_start = s->cr[0xa];
1334 s->cursor_end = s->cr[0xb];
1336 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
1338 depth_index = get_depth_index(s->ds);
1339 if (cw == 16)
1340 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1341 else
1342 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
1343 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1345 dest = ds_get_data(s->ds);
1346 linesize = ds_get_linesize(s->ds);
1347 ch_attr_ptr = s->last_ch_attr;
1348 line = 0;
1349 offset = s->start_addr * 4;
1350 for(cy = 0; cy < height; cy++) {
1351 d1 = dest;
1352 src = s->vram_ptr + offset;
1353 cx_min = width;
1354 cx_max = -1;
1355 for(cx = 0; cx < width; cx++) {
1356 ch_attr = *(uint16_t *)src;
1357 if (full_update || ch_attr != *ch_attr_ptr) {
1358 if (cx < cx_min)
1359 cx_min = cx;
1360 if (cx > cx_max)
1361 cx_max = cx;
1362 *ch_attr_ptr = ch_attr;
1363 #ifdef HOST_WORDS_BIGENDIAN
1364 ch = ch_attr >> 8;
1365 cattr = ch_attr & 0xff;
1366 #else
1367 ch = ch_attr & 0xff;
1368 cattr = ch_attr >> 8;
1369 #endif
1370 font_ptr = font_base[(cattr >> 3) & 1];
1371 font_ptr += 32 * 4 * ch;
1372 bgcol = palette[cattr >> 4];
1373 fgcol = palette[cattr & 0x0f];
1374 if (cw != 9) {
1375 vga_draw_glyph8(d1, linesize,
1376 font_ptr, cheight, fgcol, bgcol);
1377 } else {
1378 dup9 = 0;
1379 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1380 dup9 = 1;
1381 vga_draw_glyph9(d1, linesize,
1382 font_ptr, cheight, fgcol, bgcol, dup9);
1384 if (src == cursor_ptr &&
1385 !(s->cr[0x0a] & 0x20)) {
1386 int line_start, line_last, h;
1387 /* draw the cursor */
1388 line_start = s->cr[0x0a] & 0x1f;
1389 line_last = s->cr[0x0b] & 0x1f;
1390 /* XXX: check that */
1391 if (line_last > cheight - 1)
1392 line_last = cheight - 1;
1393 if (line_last >= line_start && line_start < cheight) {
1394 h = line_last - line_start + 1;
1395 d = d1 + linesize * line_start;
1396 if (cw != 9) {
1397 vga_draw_glyph8(d, linesize,
1398 cursor_glyph, h, fgcol, bgcol);
1399 } else {
1400 vga_draw_glyph9(d, linesize,
1401 cursor_glyph, h, fgcol, bgcol, 1);
1406 d1 += x_incr;
1407 src += 4;
1408 ch_attr_ptr++;
1410 if (cx_max != -1) {
1411 dpy_update(s->ds, cx_min * cw, cy * cheight,
1412 (cx_max - cx_min + 1) * cw, cheight);
1414 dest += linesize * cheight;
1415 line1 = line + cheight;
1416 offset += line_offset;
1417 if (line < s->line_compare && line1 >= s->line_compare) {
1418 offset = 0;
1420 line = line1;
1424 enum {
1425 VGA_DRAW_LINE2,
1426 VGA_DRAW_LINE2D2,
1427 VGA_DRAW_LINE4,
1428 VGA_DRAW_LINE4D2,
1429 VGA_DRAW_LINE8D2,
1430 VGA_DRAW_LINE8,
1431 VGA_DRAW_LINE15,
1432 VGA_DRAW_LINE16,
1433 VGA_DRAW_LINE24,
1434 VGA_DRAW_LINE32,
1435 VGA_DRAW_LINE_NB,
1438 static vga_draw_line_func * const vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
1439 vga_draw_line2_8,
1440 vga_draw_line2_16,
1441 vga_draw_line2_16,
1442 vga_draw_line2_32,
1443 vga_draw_line2_32,
1444 vga_draw_line2_16,
1445 vga_draw_line2_16,
1447 vga_draw_line2d2_8,
1448 vga_draw_line2d2_16,
1449 vga_draw_line2d2_16,
1450 vga_draw_line2d2_32,
1451 vga_draw_line2d2_32,
1452 vga_draw_line2d2_16,
1453 vga_draw_line2d2_16,
1455 vga_draw_line4_8,
1456 vga_draw_line4_16,
1457 vga_draw_line4_16,
1458 vga_draw_line4_32,
1459 vga_draw_line4_32,
1460 vga_draw_line4_16,
1461 vga_draw_line4_16,
1463 vga_draw_line4d2_8,
1464 vga_draw_line4d2_16,
1465 vga_draw_line4d2_16,
1466 vga_draw_line4d2_32,
1467 vga_draw_line4d2_32,
1468 vga_draw_line4d2_16,
1469 vga_draw_line4d2_16,
1471 vga_draw_line8d2_8,
1472 vga_draw_line8d2_16,
1473 vga_draw_line8d2_16,
1474 vga_draw_line8d2_32,
1475 vga_draw_line8d2_32,
1476 vga_draw_line8d2_16,
1477 vga_draw_line8d2_16,
1479 vga_draw_line8_8,
1480 vga_draw_line8_16,
1481 vga_draw_line8_16,
1482 vga_draw_line8_32,
1483 vga_draw_line8_32,
1484 vga_draw_line8_16,
1485 vga_draw_line8_16,
1487 vga_draw_line15_8,
1488 vga_draw_line15_15,
1489 vga_draw_line15_16,
1490 vga_draw_line15_32,
1491 vga_draw_line15_32bgr,
1492 vga_draw_line15_15bgr,
1493 vga_draw_line15_16bgr,
1495 vga_draw_line16_8,
1496 vga_draw_line16_15,
1497 vga_draw_line16_16,
1498 vga_draw_line16_32,
1499 vga_draw_line16_32bgr,
1500 vga_draw_line16_15bgr,
1501 vga_draw_line16_16bgr,
1503 vga_draw_line24_8,
1504 vga_draw_line24_15,
1505 vga_draw_line24_16,
1506 vga_draw_line24_32,
1507 vga_draw_line24_32bgr,
1508 vga_draw_line24_15bgr,
1509 vga_draw_line24_16bgr,
1511 vga_draw_line32_8,
1512 vga_draw_line32_15,
1513 vga_draw_line32_16,
1514 vga_draw_line32_32,
1515 vga_draw_line32_32bgr,
1516 vga_draw_line32_15bgr,
1517 vga_draw_line32_16bgr,
1520 static int vga_get_bpp(VGACommonState *s)
1522 int ret;
1523 #ifdef CONFIG_BOCHS_VBE
1524 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1525 ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
1526 } else
1527 #endif
1529 ret = 0;
1531 return ret;
1534 static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
1536 int width, height;
1538 #ifdef CONFIG_BOCHS_VBE
1539 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1540 width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
1541 height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
1542 } else
1543 #endif
1545 width = (s->cr[0x01] + 1) * 8;
1546 height = s->cr[0x12] |
1547 ((s->cr[0x07] & 0x02) << 7) |
1548 ((s->cr[0x07] & 0x40) << 3);
1549 height = (height + 1);
1551 *pwidth = width;
1552 *pheight = height;
1555 void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2)
1557 int y;
1558 if (y1 >= VGA_MAX_HEIGHT)
1559 return;
1560 if (y2 >= VGA_MAX_HEIGHT)
1561 y2 = VGA_MAX_HEIGHT;
1562 for(y = y1; y < y2; y++) {
1563 s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1567 static void vga_sync_dirty_bitmap(VGACommonState *s)
1569 memory_region_sync_dirty_bitmap(&s->vram);
1572 void vga_dirty_log_start(VGACommonState *s)
1574 memory_region_set_log(&s->vram, true, DIRTY_MEMORY_VGA);
1577 void vga_dirty_log_stop(VGACommonState *s)
1579 memory_region_set_log(&s->vram, false, DIRTY_MEMORY_VGA);
1583 * graphic modes
1585 static void vga_draw_graphic(VGACommonState *s, int full_update)
1587 int y1, y, update, linesize, y_start, double_scan, mask, depth;
1588 int width, height, shift_control, line_offset, bwidth, bits;
1589 ram_addr_t page0, page1, page_min, page_max;
1590 int disp_width, multi_scan, multi_run;
1591 uint8_t *d;
1592 uint32_t v, addr1, addr;
1593 vga_draw_line_func *vga_draw_line;
1595 full_update |= update_basic_params(s);
1597 if (!full_update)
1598 vga_sync_dirty_bitmap(s);
1600 s->get_resolution(s, &width, &height);
1601 disp_width = width;
1603 shift_control = (s->gr[0x05] >> 5) & 3;
1604 double_scan = (s->cr[0x09] >> 7);
1605 if (shift_control != 1) {
1606 multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
1607 } else {
1608 /* in CGA modes, multi_scan is ignored */
1609 /* XXX: is it correct ? */
1610 multi_scan = double_scan;
1612 multi_run = multi_scan;
1613 if (shift_control != s->shift_control ||
1614 double_scan != s->double_scan) {
1615 full_update = 1;
1616 s->shift_control = shift_control;
1617 s->double_scan = double_scan;
1620 if (shift_control == 0) {
1621 if (s->sr[0x01] & 8) {
1622 disp_width <<= 1;
1624 } else if (shift_control == 1) {
1625 if (s->sr[0x01] & 8) {
1626 disp_width <<= 1;
1630 depth = s->get_bpp(s);
1631 if (s->line_offset != s->last_line_offset ||
1632 disp_width != s->last_width ||
1633 height != s->last_height ||
1634 s->last_depth != depth) {
1635 #if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
1636 if (depth == 16 || depth == 32) {
1637 #else
1638 if (depth == 32) {
1639 #endif
1640 qemu_free_displaysurface(s->ds);
1641 s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth,
1642 s->line_offset,
1643 s->vram_ptr + (s->start_addr * 4));
1644 #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
1645 s->ds->surface->pf = qemu_different_endianness_pixelformat(depth);
1646 #endif
1647 dpy_resize(s->ds);
1648 } else {
1649 qemu_console_resize(s->ds, disp_width, height);
1651 s->last_scr_width = disp_width;
1652 s->last_scr_height = height;
1653 s->last_width = disp_width;
1654 s->last_height = height;
1655 s->last_line_offset = s->line_offset;
1656 s->last_depth = depth;
1657 full_update = 1;
1658 } else if (is_buffer_shared(s->ds->surface) &&
1659 (full_update || s->ds->surface->data != s->vram_ptr + (s->start_addr * 4))) {
1660 s->ds->surface->data = s->vram_ptr + (s->start_addr * 4);
1661 dpy_setdata(s->ds);
1664 s->rgb_to_pixel =
1665 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1667 if (shift_control == 0) {
1668 full_update |= update_palette16(s);
1669 if (s->sr[0x01] & 8) {
1670 v = VGA_DRAW_LINE4D2;
1671 } else {
1672 v = VGA_DRAW_LINE4;
1674 bits = 4;
1675 } else if (shift_control == 1) {
1676 full_update |= update_palette16(s);
1677 if (s->sr[0x01] & 8) {
1678 v = VGA_DRAW_LINE2D2;
1679 } else {
1680 v = VGA_DRAW_LINE2;
1682 bits = 4;
1683 } else {
1684 switch(s->get_bpp(s)) {
1685 default:
1686 case 0:
1687 full_update |= update_palette256(s);
1688 v = VGA_DRAW_LINE8D2;
1689 bits = 4;
1690 break;
1691 case 8:
1692 full_update |= update_palette256(s);
1693 v = VGA_DRAW_LINE8;
1694 bits = 8;
1695 break;
1696 case 15:
1697 v = VGA_DRAW_LINE15;
1698 bits = 16;
1699 break;
1700 case 16:
1701 v = VGA_DRAW_LINE16;
1702 bits = 16;
1703 break;
1704 case 24:
1705 v = VGA_DRAW_LINE24;
1706 bits = 24;
1707 break;
1708 case 32:
1709 v = VGA_DRAW_LINE32;
1710 bits = 32;
1711 break;
1714 vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
1716 if (!is_buffer_shared(s->ds->surface) && s->cursor_invalidate)
1717 s->cursor_invalidate(s);
1719 line_offset = s->line_offset;
1720 #if 0
1721 printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n",
1722 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1723 #endif
1724 addr1 = (s->start_addr * 4);
1725 bwidth = (width * bits + 7) / 8;
1726 y_start = -1;
1727 page_min = -1;
1728 page_max = 0;
1729 d = ds_get_data(s->ds);
1730 linesize = ds_get_linesize(s->ds);
1731 y1 = 0;
1732 for(y = 0; y < height; y++) {
1733 addr = addr1;
1734 if (!(s->cr[0x17] & 1)) {
1735 int shift;
1736 /* CGA compatibility handling */
1737 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1738 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1740 if (!(s->cr[0x17] & 2)) {
1741 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1743 page0 = addr & TARGET_PAGE_MASK;
1744 page1 = (addr + bwidth - 1) & TARGET_PAGE_MASK;
1745 update = full_update |
1746 memory_region_get_dirty(&s->vram, page0, DIRTY_MEMORY_VGA) |
1747 memory_region_get_dirty(&s->vram, page1, DIRTY_MEMORY_VGA);
1748 if ((page1 - page0) > TARGET_PAGE_SIZE) {
1749 /* if wide line, can use another page */
1750 update |= memory_region_get_dirty(&s->vram,
1751 page0 + TARGET_PAGE_SIZE,
1752 DIRTY_MEMORY_VGA);
1754 /* explicit invalidation for the hardware cursor */
1755 update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
1756 if (update) {
1757 if (y_start < 0)
1758 y_start = y;
1759 if (page0 < page_min)
1760 page_min = page0;
1761 if (page1 > page_max)
1762 page_max = page1;
1763 if (!(is_buffer_shared(s->ds->surface))) {
1764 vga_draw_line(s, d, s->vram_ptr + addr, width);
1765 if (s->cursor_draw_line)
1766 s->cursor_draw_line(s, d, y);
1768 } else {
1769 if (y_start >= 0) {
1770 /* flush to display */
1771 dpy_update(s->ds, 0, y_start,
1772 disp_width, y - y_start);
1773 y_start = -1;
1776 if (!multi_run) {
1777 mask = (s->cr[0x17] & 3) ^ 3;
1778 if ((y1 & mask) == mask)
1779 addr1 += line_offset;
1780 y1++;
1781 multi_run = multi_scan;
1782 } else {
1783 multi_run--;
1785 /* line compare acts on the displayed lines */
1786 if (y == s->line_compare)
1787 addr1 = 0;
1788 d += linesize;
1790 if (y_start >= 0) {
1791 /* flush to display */
1792 dpy_update(s->ds, 0, y_start,
1793 disp_width, y - y_start);
1795 /* reset modified pages */
1796 if (page_max >= page_min) {
1797 memory_region_reset_dirty(&s->vram,
1798 page_min,
1799 page_max + TARGET_PAGE_SIZE - page_min,
1800 DIRTY_MEMORY_VGA);
1802 memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
1805 static void vga_draw_blank(VGACommonState *s, int full_update)
1807 int i, w, val;
1808 uint8_t *d;
1810 if (!full_update)
1811 return;
1812 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1813 return;
1815 s->rgb_to_pixel =
1816 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1817 if (ds_get_bits_per_pixel(s->ds) == 8)
1818 val = s->rgb_to_pixel(0, 0, 0);
1819 else
1820 val = 0;
1821 w = s->last_scr_width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1822 d = ds_get_data(s->ds);
1823 for(i = 0; i < s->last_scr_height; i++) {
1824 memset(d, val, w);
1825 d += ds_get_linesize(s->ds);
1827 dpy_update(s->ds, 0, 0,
1828 s->last_scr_width, s->last_scr_height);
1831 #define GMODE_TEXT 0
1832 #define GMODE_GRAPH 1
1833 #define GMODE_BLANK 2
1835 static void vga_update_display(void *opaque)
1837 VGACommonState *s = opaque;
1838 int full_update, graphic_mode;
1840 if (ds_get_bits_per_pixel(s->ds) == 0) {
1841 /* nothing to do */
1842 } else {
1843 full_update = 0;
1844 if (!(s->ar_index & 0x20)) {
1845 graphic_mode = GMODE_BLANK;
1846 } else {
1847 graphic_mode = s->gr[6] & 1;
1849 if (graphic_mode != s->graphic_mode) {
1850 s->graphic_mode = graphic_mode;
1851 full_update = 1;
1853 switch(graphic_mode) {
1854 case GMODE_TEXT:
1855 vga_draw_text(s, full_update);
1856 break;
1857 case GMODE_GRAPH:
1858 vga_draw_graphic(s, full_update);
1859 break;
1860 case GMODE_BLANK:
1861 default:
1862 vga_draw_blank(s, full_update);
1863 break;
1868 /* force a full display refresh */
1869 static void vga_invalidate_display(void *opaque)
1871 VGACommonState *s = opaque;
1873 s->last_width = -1;
1874 s->last_height = -1;
1877 void vga_common_reset(VGACommonState *s)
1879 s->sr_index = 0;
1880 memset(s->sr, '\0', sizeof(s->sr));
1881 s->gr_index = 0;
1882 memset(s->gr, '\0', sizeof(s->gr));
1883 s->ar_index = 0;
1884 memset(s->ar, '\0', sizeof(s->ar));
1885 s->ar_flip_flop = 0;
1886 s->cr_index = 0;
1887 memset(s->cr, '\0', sizeof(s->cr));
1888 s->msr = 0;
1889 s->fcr = 0;
1890 s->st00 = 0;
1891 s->st01 = 0;
1892 s->dac_state = 0;
1893 s->dac_sub_index = 0;
1894 s->dac_read_index = 0;
1895 s->dac_write_index = 0;
1896 memset(s->dac_cache, '\0', sizeof(s->dac_cache));
1897 s->dac_8bit = 0;
1898 memset(s->palette, '\0', sizeof(s->palette));
1899 s->bank_offset = 0;
1900 #ifdef CONFIG_BOCHS_VBE
1901 s->vbe_index = 0;
1902 memset(s->vbe_regs, '\0', sizeof(s->vbe_regs));
1903 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID5;
1904 s->vbe_start_addr = 0;
1905 s->vbe_line_offset = 0;
1906 s->vbe_bank_mask = (s->vram_size >> 16) - 1;
1907 #endif
1908 memset(s->font_offsets, '\0', sizeof(s->font_offsets));
1909 s->graphic_mode = -1; /* force full update */
1910 s->shift_control = 0;
1911 s->double_scan = 0;
1912 s->line_offset = 0;
1913 s->line_compare = 0;
1914 s->start_addr = 0;
1915 s->plane_updated = 0;
1916 s->last_cw = 0;
1917 s->last_ch = 0;
1918 s->last_width = 0;
1919 s->last_height = 0;
1920 s->last_scr_width = 0;
1921 s->last_scr_height = 0;
1922 s->cursor_start = 0;
1923 s->cursor_end = 0;
1924 s->cursor_offset = 0;
1925 memset(s->invalidated_y_table, '\0', sizeof(s->invalidated_y_table));
1926 memset(s->last_palette, '\0', sizeof(s->last_palette));
1927 memset(s->last_ch_attr, '\0', sizeof(s->last_ch_attr));
1928 switch (vga_retrace_method) {
1929 case VGA_RETRACE_DUMB:
1930 break;
1931 case VGA_RETRACE_PRECISE:
1932 memset(&s->retrace_info, 0, sizeof (s->retrace_info));
1933 break;
1935 vga_update_memory_access(s);
1938 static void vga_reset(void *opaque)
1940 VGACommonState *s = opaque;
1941 vga_common_reset(s);
1944 #define TEXTMODE_X(x) ((x) % width)
1945 #define TEXTMODE_Y(x) ((x) / width)
1946 #define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1947 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1948 /* relay text rendering to the display driver
1949 * instead of doing a full vga_update_display() */
1950 static void vga_update_text(void *opaque, console_ch_t *chardata)
1952 VGACommonState *s = opaque;
1953 int graphic_mode, i, cursor_offset, cursor_visible;
1954 int cw, cheight, width, height, size, c_min, c_max;
1955 uint32_t *src;
1956 console_ch_t *dst, val;
1957 char msg_buffer[80];
1958 int full_update = 0;
1960 if (!(s->ar_index & 0x20)) {
1961 graphic_mode = GMODE_BLANK;
1962 } else {
1963 graphic_mode = s->gr[6] & 1;
1965 if (graphic_mode != s->graphic_mode) {
1966 s->graphic_mode = graphic_mode;
1967 full_update = 1;
1969 if (s->last_width == -1) {
1970 s->last_width = 0;
1971 full_update = 1;
1974 switch (graphic_mode) {
1975 case GMODE_TEXT:
1976 /* TODO: update palette */
1977 full_update |= update_basic_params(s);
1979 /* total width & height */
1980 cheight = (s->cr[9] & 0x1f) + 1;
1981 cw = 8;
1982 if (!(s->sr[1] & 0x01))
1983 cw = 9;
1984 if (s->sr[1] & 0x08)
1985 cw = 16; /* NOTE: no 18 pixel wide */
1986 width = (s->cr[0x01] + 1);
1987 if (s->cr[0x06] == 100) {
1988 /* ugly hack for CGA 160x100x16 - explain me the logic */
1989 height = 100;
1990 } else {
1991 height = s->cr[0x12] |
1992 ((s->cr[0x07] & 0x02) << 7) |
1993 ((s->cr[0x07] & 0x40) << 3);
1994 height = (height + 1) / cheight;
1997 size = (height * width);
1998 if (size > CH_ATTR_SIZE) {
1999 if (!full_update)
2000 return;
2002 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
2003 width, height);
2004 break;
2007 if (width != s->last_width || height != s->last_height ||
2008 cw != s->last_cw || cheight != s->last_ch) {
2009 s->last_scr_width = width * cw;
2010 s->last_scr_height = height * cheight;
2011 s->ds->surface->width = width;
2012 s->ds->surface->height = height;
2013 dpy_resize(s->ds);
2014 s->last_width = width;
2015 s->last_height = height;
2016 s->last_ch = cheight;
2017 s->last_cw = cw;
2018 full_update = 1;
2021 /* Update "hardware" cursor */
2022 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
2023 if (cursor_offset != s->cursor_offset ||
2024 s->cr[0xa] != s->cursor_start ||
2025 s->cr[0xb] != s->cursor_end || full_update) {
2026 cursor_visible = !(s->cr[0xa] & 0x20);
2027 if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
2028 dpy_cursor(s->ds,
2029 TEXTMODE_X(cursor_offset),
2030 TEXTMODE_Y(cursor_offset));
2031 else
2032 dpy_cursor(s->ds, -1, -1);
2033 s->cursor_offset = cursor_offset;
2034 s->cursor_start = s->cr[0xa];
2035 s->cursor_end = s->cr[0xb];
2038 src = (uint32_t *) s->vram_ptr + s->start_addr;
2039 dst = chardata;
2041 if (full_update) {
2042 for (i = 0; i < size; src ++, dst ++, i ++)
2043 console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src)));
2045 dpy_update(s->ds, 0, 0, width, height);
2046 } else {
2047 c_max = 0;
2049 for (i = 0; i < size; src ++, dst ++, i ++) {
2050 console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
2051 if (*dst != val) {
2052 *dst = val;
2053 c_max = i;
2054 break;
2057 c_min = i;
2058 for (; i < size; src ++, dst ++, i ++) {
2059 console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
2060 if (*dst != val) {
2061 *dst = val;
2062 c_max = i;
2066 if (c_min <= c_max) {
2067 i = TEXTMODE_Y(c_min);
2068 dpy_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
2072 return;
2073 case GMODE_GRAPH:
2074 if (!full_update)
2075 return;
2077 s->get_resolution(s, &width, &height);
2078 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
2079 width, height);
2080 break;
2081 case GMODE_BLANK:
2082 default:
2083 if (!full_update)
2084 return;
2086 snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
2087 break;
2090 /* Display a message */
2091 s->last_width = 60;
2092 s->last_height = height = 3;
2093 dpy_cursor(s->ds, -1, -1);
2094 s->ds->surface->width = s->last_width;
2095 s->ds->surface->height = height;
2096 dpy_resize(s->ds);
2098 for (dst = chardata, i = 0; i < s->last_width * height; i ++)
2099 console_write_ch(dst ++, ' ');
2101 size = strlen(msg_buffer);
2102 width = (s->last_width - size) / 2;
2103 dst = chardata + s->last_width + width;
2104 for (i = 0; i < size; i ++)
2105 console_write_ch(dst ++, 0x00200100 | msg_buffer[i]);
2107 dpy_update(s->ds, 0, 0, s->last_width, height);
2110 static uint64_t vga_mem_read(void *opaque, target_phys_addr_t addr,
2111 unsigned size)
2113 VGACommonState *s = opaque;
2115 return vga_mem_readb(s, addr);
2118 static void vga_mem_write(void *opaque, target_phys_addr_t addr,
2119 uint64_t data, unsigned size)
2121 VGACommonState *s = opaque;
2123 return vga_mem_writeb(s, addr, data);
2126 const MemoryRegionOps vga_mem_ops = {
2127 .read = vga_mem_read,
2128 .write = vga_mem_write,
2129 .endianness = DEVICE_LITTLE_ENDIAN,
2130 .impl = {
2131 .min_access_size = 1,
2132 .max_access_size = 1,
2136 static int vga_common_post_load(void *opaque, int version_id)
2138 VGACommonState *s = opaque;
2140 /* force refresh */
2141 s->graphic_mode = -1;
2142 return 0;
2145 const VMStateDescription vmstate_vga_common = {
2146 .name = "vga",
2147 .version_id = 2,
2148 .minimum_version_id = 2,
2149 .minimum_version_id_old = 2,
2150 .post_load = vga_common_post_load,
2151 .fields = (VMStateField []) {
2152 VMSTATE_UINT32(latch, VGACommonState),
2153 VMSTATE_UINT8(sr_index, VGACommonState),
2154 VMSTATE_PARTIAL_BUFFER(sr, VGACommonState, 8),
2155 VMSTATE_UINT8(gr_index, VGACommonState),
2156 VMSTATE_PARTIAL_BUFFER(gr, VGACommonState, 16),
2157 VMSTATE_UINT8(ar_index, VGACommonState),
2158 VMSTATE_BUFFER(ar, VGACommonState),
2159 VMSTATE_INT32(ar_flip_flop, VGACommonState),
2160 VMSTATE_UINT8(cr_index, VGACommonState),
2161 VMSTATE_BUFFER(cr, VGACommonState),
2162 VMSTATE_UINT8(msr, VGACommonState),
2163 VMSTATE_UINT8(fcr, VGACommonState),
2164 VMSTATE_UINT8(st00, VGACommonState),
2165 VMSTATE_UINT8(st01, VGACommonState),
2167 VMSTATE_UINT8(dac_state, VGACommonState),
2168 VMSTATE_UINT8(dac_sub_index, VGACommonState),
2169 VMSTATE_UINT8(dac_read_index, VGACommonState),
2170 VMSTATE_UINT8(dac_write_index, VGACommonState),
2171 VMSTATE_BUFFER(dac_cache, VGACommonState),
2172 VMSTATE_BUFFER(palette, VGACommonState),
2174 VMSTATE_INT32(bank_offset, VGACommonState),
2175 VMSTATE_UINT8_EQUAL(is_vbe_vmstate, VGACommonState),
2176 #ifdef CONFIG_BOCHS_VBE
2177 VMSTATE_UINT16(vbe_index, VGACommonState),
2178 VMSTATE_UINT16_ARRAY(vbe_regs, VGACommonState, VBE_DISPI_INDEX_NB),
2179 VMSTATE_UINT32(vbe_start_addr, VGACommonState),
2180 VMSTATE_UINT32(vbe_line_offset, VGACommonState),
2181 VMSTATE_UINT32(vbe_bank_mask, VGACommonState),
2182 #endif
2183 VMSTATE_END_OF_LIST()
2187 void vga_common_init(VGACommonState *s, int vga_ram_size)
2189 int i, j, v, b;
2191 for(i = 0;i < 256; i++) {
2192 v = 0;
2193 for(j = 0; j < 8; j++) {
2194 v |= ((i >> j) & 1) << (j * 4);
2196 expand4[i] = v;
2198 v = 0;
2199 for(j = 0; j < 4; j++) {
2200 v |= ((i >> (2 * j)) & 3) << (j * 4);
2202 expand2[i] = v;
2204 for(i = 0; i < 16; i++) {
2205 v = 0;
2206 for(j = 0; j < 4; j++) {
2207 b = ((i >> j) & 1);
2208 v |= b << (2 * j);
2209 v |= b << (2 * j + 1);
2211 expand4to8[i] = v;
2214 #ifdef CONFIG_BOCHS_VBE
2215 s->is_vbe_vmstate = 1;
2216 #else
2217 s->is_vbe_vmstate = 0;
2218 #endif
2219 memory_region_init_ram(&s->vram, NULL, "vga.vram", vga_ram_size);
2220 s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
2221 s->vram_size = vga_ram_size;
2222 s->get_bpp = vga_get_bpp;
2223 s->get_offsets = vga_get_offsets;
2224 s->get_resolution = vga_get_resolution;
2225 s->update = vga_update_display;
2226 s->invalidate = vga_invalidate_display;
2227 s->screen_dump = vga_screen_dump;
2228 s->text_update = vga_update_text;
2229 switch (vga_retrace_method) {
2230 case VGA_RETRACE_DUMB:
2231 s->retrace = vga_dumb_retrace;
2232 s->update_retrace_info = vga_dumb_update_retrace_info;
2233 break;
2235 case VGA_RETRACE_PRECISE:
2236 s->retrace = vga_precise_retrace;
2237 s->update_retrace_info = vga_precise_update_retrace_info;
2238 break;
2240 vga_dirty_log_start(s);
2243 /* used by both ISA and PCI */
2244 MemoryRegion *vga_init_io(VGACommonState *s)
2246 MemoryRegion *vga_mem;
2248 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
2250 register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
2251 register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
2252 register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
2253 register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
2255 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
2257 register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
2258 register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
2259 register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
2260 register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
2262 #ifdef CONFIG_BOCHS_VBE
2263 #if defined (TARGET_I386)
2264 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2265 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
2267 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2268 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
2269 #else
2270 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2271 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
2273 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2274 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
2275 #endif
2276 #endif /* CONFIG_BOCHS_VBE */
2278 vga_mem = g_malloc(sizeof(*vga_mem));
2279 memory_region_init_io(vga_mem, &vga_mem_ops, s,
2280 "vga-lowmem", 0x20000);
2282 return vga_mem;
2285 void vga_init(VGACommonState *s, MemoryRegion *address_space)
2287 MemoryRegion *vga_io_memory;
2289 qemu_register_reset(vga_reset, s);
2291 s->bank_offset = 0;
2293 s->legacy_address_space = address_space;
2295 vga_io_memory = vga_init_io(s);
2296 memory_region_add_subregion_overlap(address_space,
2297 isa_mem_base + 0x000a0000,
2298 vga_io_memory,
2300 memory_region_set_coalescing(vga_io_memory);
2303 void vga_init_vbe(VGACommonState *s, MemoryRegion *system_memory)
2305 #ifdef CONFIG_BOCHS_VBE
2306 /* XXX: use optimized standard vga accesses */
2307 memory_region_add_subregion(system_memory,
2308 VBE_DISPI_LFB_PHYSICAL_ADDRESS,
2309 &s->vram);
2310 s->vbe_mapped = 1;
2311 #endif
2313 /********************************************************/
2314 /* vga screen dump */
2316 static void vga_save_dpy_update(DisplayState *ds,
2317 int x, int y, int w, int h)
2319 if (screen_dump_filename) {
2320 ppm_save(screen_dump_filename, ds->surface);
2321 screen_dump_filename = NULL;
2325 static void vga_save_dpy_resize(DisplayState *s)
2329 static void vga_save_dpy_refresh(DisplayState *s)
2333 int ppm_save(const char *filename, struct DisplaySurface *ds)
2335 FILE *f;
2336 uint8_t *d, *d1;
2337 uint32_t v;
2338 int y, x;
2339 uint8_t r, g, b;
2340 int ret;
2341 char *linebuf, *pbuf;
2343 f = fopen(filename, "wb");
2344 if (!f)
2345 return -1;
2346 fprintf(f, "P6\n%d %d\n%d\n",
2347 ds->width, ds->height, 255);
2348 linebuf = g_malloc(ds->width * 3);
2349 d1 = ds->data;
2350 for(y = 0; y < ds->height; y++) {
2351 d = d1;
2352 pbuf = linebuf;
2353 for(x = 0; x < ds->width; x++) {
2354 if (ds->pf.bits_per_pixel == 32)
2355 v = *(uint32_t *)d;
2356 else
2357 v = (uint32_t) (*(uint16_t *)d);
2358 r = ((v >> ds->pf.rshift) & ds->pf.rmax) * 256 /
2359 (ds->pf.rmax + 1);
2360 g = ((v >> ds->pf.gshift) & ds->pf.gmax) * 256 /
2361 (ds->pf.gmax + 1);
2362 b = ((v >> ds->pf.bshift) & ds->pf.bmax) * 256 /
2363 (ds->pf.bmax + 1);
2364 *pbuf++ = r;
2365 *pbuf++ = g;
2366 *pbuf++ = b;
2367 d += ds->pf.bytes_per_pixel;
2369 d1 += ds->linesize;
2370 ret = fwrite(linebuf, 1, pbuf - linebuf, f);
2371 (void)ret;
2373 g_free(linebuf);
2374 fclose(f);
2375 return 0;
2378 static DisplayChangeListener* vga_screen_dump_init(DisplayState *ds)
2380 DisplayChangeListener *dcl;
2382 dcl = g_malloc0(sizeof(DisplayChangeListener));
2383 dcl->dpy_update = vga_save_dpy_update;
2384 dcl->dpy_resize = vga_save_dpy_resize;
2385 dcl->dpy_refresh = vga_save_dpy_refresh;
2386 register_displaychangelistener(ds, dcl);
2387 return dcl;
2390 /* save the vga display in a PPM image even if no display is
2391 available */
2392 static void vga_screen_dump(void *opaque, const char *filename)
2394 VGACommonState *s = opaque;
2396 if (!screen_dump_dcl)
2397 screen_dump_dcl = vga_screen_dump_init(s->ds);
2399 screen_dump_filename = (char *)filename;
2400 vga_invalidate_display(s);
2401 vga_hw_update();