Fix up some style nits of last uq/master merge
[qemu/ar7.git] / hw / vga.c
blob851fd689b32427279f81e54d2133c6885e1641c0
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 base = 0xb8000;
180 size = 0x8000;
181 break;
183 region = g_malloc(sizeof(*region));
184 memory_region_init_alias(region, "vga.chain4", &s->vram, offset, size);
185 memory_region_add_subregion_overlap(s->legacy_address_space, base,
186 region, 2);
187 s->chain4_alias = region;
189 if (old_region) {
190 memory_region_del_subregion(s->legacy_address_space, old_region);
191 memory_region_destroy(old_region);
192 g_free(old_region);
193 s->plane_updated = 0xf;
197 static void vga_dumb_update_retrace_info(VGACommonState *s)
199 (void) s;
202 static void vga_precise_update_retrace_info(VGACommonState *s)
204 int htotal_chars;
205 int hretr_start_char;
206 int hretr_skew_chars;
207 int hretr_end_char;
209 int vtotal_lines;
210 int vretr_start_line;
211 int vretr_end_line;
213 int dots;
214 #if 0
215 int div2, sldiv2;
216 #endif
217 int clocking_mode;
218 int clock_sel;
219 const int clk_hz[] = {25175000, 28322000, 25175000, 25175000};
220 int64_t chars_per_sec;
221 struct vga_precise_retrace *r = &s->retrace_info.precise;
223 htotal_chars = s->cr[0x00] + 5;
224 hretr_start_char = s->cr[0x04];
225 hretr_skew_chars = (s->cr[0x05] >> 5) & 3;
226 hretr_end_char = s->cr[0x05] & 0x1f;
228 vtotal_lines = (s->cr[0x06]
229 | (((s->cr[0x07] & 1) | ((s->cr[0x07] >> 4) & 2)) << 8)) + 2
231 vretr_start_line = s->cr[0x10]
232 | ((((s->cr[0x07] >> 2) & 1) | ((s->cr[0x07] >> 6) & 2)) << 8)
234 vretr_end_line = s->cr[0x11] & 0xf;
238 clocking_mode = (s->sr[0x01] >> 3) & 1;
239 clock_sel = (s->msr >> 2) & 3;
240 dots = (s->msr & 1) ? 8 : 9;
242 chars_per_sec = clk_hz[clock_sel] / dots;
244 htotal_chars <<= clocking_mode;
246 r->total_chars = vtotal_lines * htotal_chars;
247 if (r->freq) {
248 r->ticks_per_char = get_ticks_per_sec() / (r->total_chars * r->freq);
249 } else {
250 r->ticks_per_char = get_ticks_per_sec() / chars_per_sec;
253 r->vstart = vretr_start_line;
254 r->vend = r->vstart + vretr_end_line + 1;
256 r->hstart = hretr_start_char + hretr_skew_chars;
257 r->hend = r->hstart + hretr_end_char + 1;
258 r->htotal = htotal_chars;
260 #if 0
261 div2 = (s->cr[0x17] >> 2) & 1;
262 sldiv2 = (s->cr[0x17] >> 3) & 1;
263 printf (
264 "hz=%f\n"
265 "htotal = %d\n"
266 "hretr_start = %d\n"
267 "hretr_skew = %d\n"
268 "hretr_end = %d\n"
269 "vtotal = %d\n"
270 "vretr_start = %d\n"
271 "vretr_end = %d\n"
272 "div2 = %d sldiv2 = %d\n"
273 "clocking_mode = %d\n"
274 "clock_sel = %d %d\n"
275 "dots = %d\n"
276 "ticks/char = %" PRId64 "\n"
277 "\n",
278 (double) get_ticks_per_sec() / (r->ticks_per_char * r->total_chars),
279 htotal_chars,
280 hretr_start_char,
281 hretr_skew_chars,
282 hretr_end_char,
283 vtotal_lines,
284 vretr_start_line,
285 vretr_end_line,
286 div2, sldiv2,
287 clocking_mode,
288 clock_sel,
289 clk_hz[clock_sel],
290 dots,
291 r->ticks_per_char
293 #endif
296 static uint8_t vga_precise_retrace(VGACommonState *s)
298 struct vga_precise_retrace *r = &s->retrace_info.precise;
299 uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE);
301 if (r->total_chars) {
302 int cur_line, cur_line_char, cur_char;
303 int64_t cur_tick;
305 cur_tick = qemu_get_clock_ns(vm_clock);
307 cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
308 cur_line = cur_char / r->htotal;
310 if (cur_line >= r->vstart && cur_line <= r->vend) {
311 val |= ST01_V_RETRACE | ST01_DISP_ENABLE;
312 } else {
313 cur_line_char = cur_char % r->htotal;
314 if (cur_line_char >= r->hstart && cur_line_char <= r->hend) {
315 val |= ST01_DISP_ENABLE;
319 return val;
320 } else {
321 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
325 static uint8_t vga_dumb_retrace(VGACommonState *s)
327 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
330 int vga_ioport_invalid(VGACommonState *s, uint32_t addr)
332 if (s->msr & MSR_COLOR_EMULATION) {
333 /* Color */
334 return (addr >= 0x3b0 && addr <= 0x3bf);
335 } else {
336 /* Monochrome */
337 return (addr >= 0x3d0 && addr <= 0x3df);
341 uint32_t vga_ioport_read(void *opaque, uint32_t addr)
343 VGACommonState *s = opaque;
344 int val, index;
346 if (vga_ioport_invalid(s, addr)) {
347 val = 0xff;
348 } else {
349 switch(addr) {
350 case 0x3c0:
351 if (s->ar_flip_flop == 0) {
352 val = s->ar_index;
353 } else {
354 val = 0;
356 break;
357 case 0x3c1:
358 index = s->ar_index & 0x1f;
359 if (index < 21)
360 val = s->ar[index];
361 else
362 val = 0;
363 break;
364 case 0x3c2:
365 val = s->st00;
366 break;
367 case 0x3c4:
368 val = s->sr_index;
369 break;
370 case 0x3c5:
371 val = s->sr[s->sr_index];
372 #ifdef DEBUG_VGA_REG
373 printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
374 #endif
375 break;
376 case 0x3c7:
377 val = s->dac_state;
378 break;
379 case 0x3c8:
380 val = s->dac_write_index;
381 break;
382 case 0x3c9:
383 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
384 if (++s->dac_sub_index == 3) {
385 s->dac_sub_index = 0;
386 s->dac_read_index++;
388 break;
389 case 0x3ca:
390 val = s->fcr;
391 break;
392 case 0x3cc:
393 val = s->msr;
394 break;
395 case 0x3ce:
396 val = s->gr_index;
397 break;
398 case 0x3cf:
399 val = s->gr[s->gr_index];
400 #ifdef DEBUG_VGA_REG
401 printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
402 #endif
403 break;
404 case 0x3b4:
405 case 0x3d4:
406 val = s->cr_index;
407 break;
408 case 0x3b5:
409 case 0x3d5:
410 val = s->cr[s->cr_index];
411 #ifdef DEBUG_VGA_REG
412 printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
413 #endif
414 break;
415 case 0x3ba:
416 case 0x3da:
417 /* just toggle to fool polling */
418 val = s->st01 = s->retrace(s);
419 s->ar_flip_flop = 0;
420 break;
421 default:
422 val = 0x00;
423 break;
426 #if defined(DEBUG_VGA)
427 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
428 #endif
429 return val;
432 void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
434 VGACommonState *s = opaque;
435 int index;
437 /* check port range access depending on color/monochrome mode */
438 if (vga_ioport_invalid(s, addr)) {
439 return;
441 #ifdef DEBUG_VGA
442 printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
443 #endif
445 switch(addr) {
446 case 0x3c0:
447 if (s->ar_flip_flop == 0) {
448 val &= 0x3f;
449 s->ar_index = val;
450 } else {
451 index = s->ar_index & 0x1f;
452 switch(index) {
453 case 0x00 ... 0x0f:
454 s->ar[index] = val & 0x3f;
455 break;
456 case 0x10:
457 s->ar[index] = val & ~0x10;
458 break;
459 case 0x11:
460 s->ar[index] = val;
461 break;
462 case 0x12:
463 s->ar[index] = val & ~0xc0;
464 break;
465 case 0x13:
466 s->ar[index] = val & ~0xf0;
467 break;
468 case 0x14:
469 s->ar[index] = val & ~0xf0;
470 break;
471 default:
472 break;
475 s->ar_flip_flop ^= 1;
476 break;
477 case 0x3c2:
478 s->msr = val & ~0x10;
479 s->update_retrace_info(s);
480 break;
481 case 0x3c4:
482 s->sr_index = val & 7;
483 break;
484 case 0x3c5:
485 #ifdef DEBUG_VGA_REG
486 printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
487 #endif
488 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
489 if (s->sr_index == 1) s->update_retrace_info(s);
490 vga_update_memory_access(s);
491 break;
492 case 0x3c7:
493 s->dac_read_index = val;
494 s->dac_sub_index = 0;
495 s->dac_state = 3;
496 break;
497 case 0x3c8:
498 s->dac_write_index = val;
499 s->dac_sub_index = 0;
500 s->dac_state = 0;
501 break;
502 case 0x3c9:
503 s->dac_cache[s->dac_sub_index] = val;
504 if (++s->dac_sub_index == 3) {
505 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
506 s->dac_sub_index = 0;
507 s->dac_write_index++;
509 break;
510 case 0x3ce:
511 s->gr_index = val & 0x0f;
512 break;
513 case 0x3cf:
514 #ifdef DEBUG_VGA_REG
515 printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
516 #endif
517 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
518 vga_update_memory_access(s);
519 break;
520 case 0x3b4:
521 case 0x3d4:
522 s->cr_index = val;
523 break;
524 case 0x3b5:
525 case 0x3d5:
526 #ifdef DEBUG_VGA_REG
527 printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
528 #endif
529 /* handle CR0-7 protection */
530 if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
531 /* can always write bit 4 of CR7 */
532 if (s->cr_index == 7)
533 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
534 return;
536 s->cr[s->cr_index] = val;
538 switch(s->cr_index) {
539 case 0x00:
540 case 0x04:
541 case 0x05:
542 case 0x06:
543 case 0x07:
544 case 0x11:
545 case 0x17:
546 s->update_retrace_info(s);
547 break;
549 break;
550 case 0x3ba:
551 case 0x3da:
552 s->fcr = val & 0x10;
553 break;
557 #ifdef CONFIG_BOCHS_VBE
558 static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
560 VGACommonState *s = opaque;
561 uint32_t val;
562 val = s->vbe_index;
563 return val;
566 static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
568 VGACommonState *s = opaque;
569 uint32_t val;
571 if (s->vbe_index < VBE_DISPI_INDEX_NB) {
572 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
573 switch(s->vbe_index) {
574 /* XXX: do not hardcode ? */
575 case VBE_DISPI_INDEX_XRES:
576 val = VBE_DISPI_MAX_XRES;
577 break;
578 case VBE_DISPI_INDEX_YRES:
579 val = VBE_DISPI_MAX_YRES;
580 break;
581 case VBE_DISPI_INDEX_BPP:
582 val = VBE_DISPI_MAX_BPP;
583 break;
584 default:
585 val = s->vbe_regs[s->vbe_index];
586 break;
588 } else {
589 val = s->vbe_regs[s->vbe_index];
591 } else if (s->vbe_index == VBE_DISPI_INDEX_VIDEO_MEMORY_64K) {
592 val = s->vram_size / (64 * 1024);
593 } else {
594 val = 0;
596 #ifdef DEBUG_BOCHS_VBE
597 printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
598 #endif
599 return val;
602 static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
604 VGACommonState *s = opaque;
605 s->vbe_index = val;
608 static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
610 VGACommonState *s = opaque;
612 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
613 #ifdef DEBUG_BOCHS_VBE
614 printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
615 #endif
616 switch(s->vbe_index) {
617 case VBE_DISPI_INDEX_ID:
618 if (val == VBE_DISPI_ID0 ||
619 val == VBE_DISPI_ID1 ||
620 val == VBE_DISPI_ID2 ||
621 val == VBE_DISPI_ID3 ||
622 val == VBE_DISPI_ID4) {
623 s->vbe_regs[s->vbe_index] = val;
625 break;
626 case VBE_DISPI_INDEX_XRES:
627 if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
628 s->vbe_regs[s->vbe_index] = val;
630 break;
631 case VBE_DISPI_INDEX_YRES:
632 if (val <= VBE_DISPI_MAX_YRES) {
633 s->vbe_regs[s->vbe_index] = val;
635 break;
636 case VBE_DISPI_INDEX_BPP:
637 if (val == 0)
638 val = 8;
639 if (val == 4 || val == 8 || val == 15 ||
640 val == 16 || val == 24 || val == 32) {
641 s->vbe_regs[s->vbe_index] = val;
643 break;
644 case VBE_DISPI_INDEX_BANK:
645 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
646 val &= (s->vbe_bank_mask >> 2);
647 } else {
648 val &= s->vbe_bank_mask;
650 s->vbe_regs[s->vbe_index] = val;
651 s->bank_offset = (val << 16);
652 vga_update_memory_access(s);
653 break;
654 case VBE_DISPI_INDEX_ENABLE:
655 if ((val & VBE_DISPI_ENABLED) &&
656 !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
657 int h, shift_control;
659 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
660 s->vbe_regs[VBE_DISPI_INDEX_XRES];
661 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
662 s->vbe_regs[VBE_DISPI_INDEX_YRES];
663 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
664 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
666 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
667 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
668 else
669 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
670 ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
671 s->vbe_start_addr = 0;
673 /* clear the screen (should be done in BIOS) */
674 if (!(val & VBE_DISPI_NOCLEARMEM)) {
675 memset(s->vram_ptr, 0,
676 s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
679 /* we initialize the VGA graphic mode (should be done
680 in BIOS) */
681 s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
682 s->cr[0x17] |= 3; /* no CGA modes */
683 s->cr[0x13] = s->vbe_line_offset >> 3;
684 /* width */
685 s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
686 /* height (only meaningful if < 1024) */
687 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
688 s->cr[0x12] = h;
689 s->cr[0x07] = (s->cr[0x07] & ~0x42) |
690 ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
691 /* line compare to 1023 */
692 s->cr[0x18] = 0xff;
693 s->cr[0x07] |= 0x10;
694 s->cr[0x09] |= 0x40;
696 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
697 shift_control = 0;
698 s->sr[0x01] &= ~8; /* no double line */
699 } else {
700 shift_control = 2;
701 s->sr[4] |= 0x08; /* set chain 4 mode */
702 s->sr[2] |= 0x0f; /* activate all planes */
704 s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
705 s->cr[0x09] &= ~0x9f; /* no double scan */
706 } else {
707 /* XXX: the bios should do that */
708 s->bank_offset = 0;
710 s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
711 s->vbe_regs[s->vbe_index] = val;
712 vga_update_memory_access(s);
713 break;
714 case VBE_DISPI_INDEX_VIRT_WIDTH:
716 int w, h, line_offset;
718 if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
719 return;
720 w = val;
721 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
722 line_offset = w >> 1;
723 else
724 line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
725 h = s->vram_size / line_offset;
726 /* XXX: support weird bochs semantics ? */
727 if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
728 return;
729 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
730 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
731 s->vbe_line_offset = line_offset;
733 break;
734 case VBE_DISPI_INDEX_X_OFFSET:
735 case VBE_DISPI_INDEX_Y_OFFSET:
737 int x;
738 s->vbe_regs[s->vbe_index] = val;
739 s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
740 x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
741 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
742 s->vbe_start_addr += x >> 1;
743 else
744 s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
745 s->vbe_start_addr >>= 2;
747 break;
748 default:
749 break;
753 #endif
755 /* called for accesses between 0xa0000 and 0xc0000 */
756 uint32_t vga_mem_readb(VGACommonState *s, target_phys_addr_t addr)
758 int memory_map_mode, plane;
759 uint32_t ret;
761 /* convert to VGA memory offset */
762 memory_map_mode = (s->gr[6] >> 2) & 3;
763 addr &= 0x1ffff;
764 switch(memory_map_mode) {
765 case 0:
766 break;
767 case 1:
768 if (addr >= 0x10000)
769 return 0xff;
770 addr += s->bank_offset;
771 break;
772 case 2:
773 addr -= 0x10000;
774 if (addr >= 0x8000)
775 return 0xff;
776 break;
777 default:
778 case 3:
779 addr -= 0x18000;
780 if (addr >= 0x8000)
781 return 0xff;
782 break;
785 if (s->sr[4] & 0x08) {
786 /* chain 4 mode : simplest access */
787 ret = s->vram_ptr[addr];
788 } else if (s->gr[5] & 0x10) {
789 /* odd/even mode (aka text mode mapping) */
790 plane = (s->gr[4] & 2) | (addr & 1);
791 ret = s->vram_ptr[((addr & ~1) << 1) | plane];
792 } else {
793 /* standard VGA latched access */
794 s->latch = ((uint32_t *)s->vram_ptr)[addr];
796 if (!(s->gr[5] & 0x08)) {
797 /* read mode 0 */
798 plane = s->gr[4];
799 ret = GET_PLANE(s->latch, plane);
800 } else {
801 /* read mode 1 */
802 ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
803 ret |= ret >> 16;
804 ret |= ret >> 8;
805 ret = (~ret) & 0xff;
808 return ret;
811 /* called for accesses between 0xa0000 and 0xc0000 */
812 void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val)
814 int memory_map_mode, plane, write_mode, b, func_select, mask;
815 uint32_t write_mask, bit_mask, set_mask;
817 #ifdef DEBUG_VGA_MEM
818 printf("vga: [0x" TARGET_FMT_plx "] = 0x%02x\n", addr, val);
819 #endif
820 /* convert to VGA memory offset */
821 memory_map_mode = (s->gr[6] >> 2) & 3;
822 addr &= 0x1ffff;
823 switch(memory_map_mode) {
824 case 0:
825 break;
826 case 1:
827 if (addr >= 0x10000)
828 return;
829 addr += s->bank_offset;
830 break;
831 case 2:
832 addr -= 0x10000;
833 if (addr >= 0x8000)
834 return;
835 break;
836 default:
837 case 3:
838 addr -= 0x18000;
839 if (addr >= 0x8000)
840 return;
841 break;
844 if (s->sr[4] & 0x08) {
845 /* chain 4 mode : simplest access */
846 plane = addr & 3;
847 mask = (1 << plane);
848 if (s->sr[2] & mask) {
849 s->vram_ptr[addr] = val;
850 #ifdef DEBUG_VGA_MEM
851 printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
852 #endif
853 s->plane_updated |= mask; /* only used to detect font change */
854 memory_region_set_dirty(&s->vram, addr);
856 } else if (s->gr[5] & 0x10) {
857 /* odd/even mode (aka text mode mapping) */
858 plane = (s->gr[4] & 2) | (addr & 1);
859 mask = (1 << plane);
860 if (s->sr[2] & mask) {
861 addr = ((addr & ~1) << 1) | plane;
862 s->vram_ptr[addr] = val;
863 #ifdef DEBUG_VGA_MEM
864 printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
865 #endif
866 s->plane_updated |= mask; /* only used to detect font change */
867 memory_region_set_dirty(&s->vram, addr);
869 } else {
870 /* standard VGA latched access */
871 write_mode = s->gr[5] & 3;
872 switch(write_mode) {
873 default:
874 case 0:
875 /* rotate */
876 b = s->gr[3] & 7;
877 val = ((val >> b) | (val << (8 - b))) & 0xff;
878 val |= val << 8;
879 val |= val << 16;
881 /* apply set/reset mask */
882 set_mask = mask16[s->gr[1]];
883 val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
884 bit_mask = s->gr[8];
885 break;
886 case 1:
887 val = s->latch;
888 goto do_write;
889 case 2:
890 val = mask16[val & 0x0f];
891 bit_mask = s->gr[8];
892 break;
893 case 3:
894 /* rotate */
895 b = s->gr[3] & 7;
896 val = (val >> b) | (val << (8 - b));
898 bit_mask = s->gr[8] & val;
899 val = mask16[s->gr[0]];
900 break;
903 /* apply logical operation */
904 func_select = s->gr[3] >> 3;
905 switch(func_select) {
906 case 0:
907 default:
908 /* nothing to do */
909 break;
910 case 1:
911 /* and */
912 val &= s->latch;
913 break;
914 case 2:
915 /* or */
916 val |= s->latch;
917 break;
918 case 3:
919 /* xor */
920 val ^= s->latch;
921 break;
924 /* apply bit mask */
925 bit_mask |= bit_mask << 8;
926 bit_mask |= bit_mask << 16;
927 val = (val & bit_mask) | (s->latch & ~bit_mask);
929 do_write:
930 /* mask data according to sr[2] */
931 mask = s->sr[2];
932 s->plane_updated |= mask; /* only used to detect font change */
933 write_mask = mask16[mask];
934 ((uint32_t *)s->vram_ptr)[addr] =
935 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
936 (val & write_mask);
937 #ifdef DEBUG_VGA_MEM
938 printf("vga: latch: [0x" TARGET_FMT_plx "] mask=0x%08x val=0x%08x\n",
939 addr * 4, write_mask, val);
940 #endif
941 memory_region_set_dirty(&s->vram, addr << 2);
945 typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
946 const uint8_t *font_ptr, int h,
947 uint32_t fgcol, uint32_t bgcol);
948 typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
949 const uint8_t *font_ptr, int h,
950 uint32_t fgcol, uint32_t bgcol, int dup9);
951 typedef void vga_draw_line_func(VGACommonState *s1, uint8_t *d,
952 const uint8_t *s, int width);
954 #define DEPTH 8
955 #include "vga_template.h"
957 #define DEPTH 15
958 #include "vga_template.h"
960 #define BGR_FORMAT
961 #define DEPTH 15
962 #include "vga_template.h"
964 #define DEPTH 16
965 #include "vga_template.h"
967 #define BGR_FORMAT
968 #define DEPTH 16
969 #include "vga_template.h"
971 #define DEPTH 32
972 #include "vga_template.h"
974 #define BGR_FORMAT
975 #define DEPTH 32
976 #include "vga_template.h"
978 static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
980 unsigned int col;
981 col = rgb_to_pixel8(r, g, b);
982 col |= col << 8;
983 col |= col << 16;
984 return col;
987 static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
989 unsigned int col;
990 col = rgb_to_pixel15(r, g, b);
991 col |= col << 16;
992 return col;
995 static unsigned int rgb_to_pixel15bgr_dup(unsigned int r, unsigned int g,
996 unsigned int b)
998 unsigned int col;
999 col = rgb_to_pixel15bgr(r, g, b);
1000 col |= col << 16;
1001 return col;
1004 static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
1006 unsigned int col;
1007 col = rgb_to_pixel16(r, g, b);
1008 col |= col << 16;
1009 return col;
1012 static unsigned int rgb_to_pixel16bgr_dup(unsigned int r, unsigned int g,
1013 unsigned int b)
1015 unsigned int col;
1016 col = rgb_to_pixel16bgr(r, g, b);
1017 col |= col << 16;
1018 return col;
1021 static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
1023 unsigned int col;
1024 col = rgb_to_pixel32(r, g, b);
1025 return col;
1028 static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b)
1030 unsigned int col;
1031 col = rgb_to_pixel32bgr(r, g, b);
1032 return col;
1035 /* return true if the palette was modified */
1036 static int update_palette16(VGACommonState *s)
1038 int full_update, i;
1039 uint32_t v, col, *palette;
1041 full_update = 0;
1042 palette = s->last_palette;
1043 for(i = 0; i < 16; i++) {
1044 v = s->ar[i];
1045 if (s->ar[0x10] & 0x80)
1046 v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
1047 else
1048 v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
1049 v = v * 3;
1050 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1051 c6_to_8(s->palette[v + 1]),
1052 c6_to_8(s->palette[v + 2]));
1053 if (col != palette[i]) {
1054 full_update = 1;
1055 palette[i] = col;
1058 return full_update;
1061 /* return true if the palette was modified */
1062 static int update_palette256(VGACommonState *s)
1064 int full_update, i;
1065 uint32_t v, col, *palette;
1067 full_update = 0;
1068 palette = s->last_palette;
1069 v = 0;
1070 for(i = 0; i < 256; i++) {
1071 if (s->dac_8bit) {
1072 col = s->rgb_to_pixel(s->palette[v],
1073 s->palette[v + 1],
1074 s->palette[v + 2]);
1075 } else {
1076 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1077 c6_to_8(s->palette[v + 1]),
1078 c6_to_8(s->palette[v + 2]));
1080 if (col != palette[i]) {
1081 full_update = 1;
1082 palette[i] = col;
1084 v += 3;
1086 return full_update;
1089 static void vga_get_offsets(VGACommonState *s,
1090 uint32_t *pline_offset,
1091 uint32_t *pstart_addr,
1092 uint32_t *pline_compare)
1094 uint32_t start_addr, line_offset, line_compare;
1095 #ifdef CONFIG_BOCHS_VBE
1096 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1097 line_offset = s->vbe_line_offset;
1098 start_addr = s->vbe_start_addr;
1099 line_compare = 65535;
1100 } else
1101 #endif
1103 /* compute line_offset in bytes */
1104 line_offset = s->cr[0x13];
1105 line_offset <<= 3;
1107 /* starting address */
1108 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
1110 /* line compare */
1111 line_compare = s->cr[0x18] |
1112 ((s->cr[0x07] & 0x10) << 4) |
1113 ((s->cr[0x09] & 0x40) << 3);
1115 *pline_offset = line_offset;
1116 *pstart_addr = start_addr;
1117 *pline_compare = line_compare;
1120 /* update start_addr and line_offset. Return TRUE if modified */
1121 static int update_basic_params(VGACommonState *s)
1123 int full_update;
1124 uint32_t start_addr, line_offset, line_compare;
1126 full_update = 0;
1128 s->get_offsets(s, &line_offset, &start_addr, &line_compare);
1130 if (line_offset != s->line_offset ||
1131 start_addr != s->start_addr ||
1132 line_compare != s->line_compare) {
1133 s->line_offset = line_offset;
1134 s->start_addr = start_addr;
1135 s->line_compare = line_compare;
1136 full_update = 1;
1138 return full_update;
1141 #define NB_DEPTHS 7
1143 static inline int get_depth_index(DisplayState *s)
1145 switch(ds_get_bits_per_pixel(s)) {
1146 default:
1147 case 8:
1148 return 0;
1149 case 15:
1150 return 1;
1151 case 16:
1152 return 2;
1153 case 32:
1154 if (is_surface_bgr(s->surface))
1155 return 4;
1156 else
1157 return 3;
1161 static vga_draw_glyph8_func * const vga_draw_glyph8_table[NB_DEPTHS] = {
1162 vga_draw_glyph8_8,
1163 vga_draw_glyph8_16,
1164 vga_draw_glyph8_16,
1165 vga_draw_glyph8_32,
1166 vga_draw_glyph8_32,
1167 vga_draw_glyph8_16,
1168 vga_draw_glyph8_16,
1171 static vga_draw_glyph8_func * const vga_draw_glyph16_table[NB_DEPTHS] = {
1172 vga_draw_glyph16_8,
1173 vga_draw_glyph16_16,
1174 vga_draw_glyph16_16,
1175 vga_draw_glyph16_32,
1176 vga_draw_glyph16_32,
1177 vga_draw_glyph16_16,
1178 vga_draw_glyph16_16,
1181 static vga_draw_glyph9_func * const vga_draw_glyph9_table[NB_DEPTHS] = {
1182 vga_draw_glyph9_8,
1183 vga_draw_glyph9_16,
1184 vga_draw_glyph9_16,
1185 vga_draw_glyph9_32,
1186 vga_draw_glyph9_32,
1187 vga_draw_glyph9_16,
1188 vga_draw_glyph9_16,
1191 static const uint8_t cursor_glyph[32 * 4] = {
1192 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
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,
1210 static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight,
1211 int *pcwidth, int *pcheight)
1213 int width, cwidth, height, cheight;
1215 /* total width & height */
1216 cheight = (s->cr[9] & 0x1f) + 1;
1217 cwidth = 8;
1218 if (!(s->sr[1] & 0x01))
1219 cwidth = 9;
1220 if (s->sr[1] & 0x08)
1221 cwidth = 16; /* NOTE: no 18 pixel wide */
1222 width = (s->cr[0x01] + 1);
1223 if (s->cr[0x06] == 100) {
1224 /* ugly hack for CGA 160x100x16 - explain me the logic */
1225 height = 100;
1226 } else {
1227 height = s->cr[0x12] |
1228 ((s->cr[0x07] & 0x02) << 7) |
1229 ((s->cr[0x07] & 0x40) << 3);
1230 height = (height + 1) / cheight;
1233 *pwidth = width;
1234 *pheight = height;
1235 *pcwidth = cwidth;
1236 *pcheight = cheight;
1239 typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
1241 static rgb_to_pixel_dup_func * const rgb_to_pixel_dup_table[NB_DEPTHS] = {
1242 rgb_to_pixel8_dup,
1243 rgb_to_pixel15_dup,
1244 rgb_to_pixel16_dup,
1245 rgb_to_pixel32_dup,
1246 rgb_to_pixel32bgr_dup,
1247 rgb_to_pixel15bgr_dup,
1248 rgb_to_pixel16bgr_dup,
1252 * Text mode update
1253 * Missing:
1254 * - double scan
1255 * - double width
1256 * - underline
1257 * - flashing
1259 static void vga_draw_text(VGACommonState *s, int full_update)
1261 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1262 int cx_min, cx_max, linesize, x_incr, line, line1;
1263 uint32_t offset, fgcol, bgcol, v, cursor_offset;
1264 uint8_t *d1, *d, *src, *dest, *cursor_ptr;
1265 const uint8_t *font_ptr, *font_base[2];
1266 int dup9, line_offset, depth_index;
1267 uint32_t *palette;
1268 uint32_t *ch_attr_ptr;
1269 vga_draw_glyph8_func *vga_draw_glyph8;
1270 vga_draw_glyph9_func *vga_draw_glyph9;
1272 /* compute font data address (in plane 2) */
1273 v = s->sr[3];
1274 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1275 if (offset != s->font_offsets[0]) {
1276 s->font_offsets[0] = offset;
1277 full_update = 1;
1279 font_base[0] = s->vram_ptr + offset;
1281 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1282 font_base[1] = s->vram_ptr + offset;
1283 if (offset != s->font_offsets[1]) {
1284 s->font_offsets[1] = offset;
1285 full_update = 1;
1287 if (s->plane_updated & (1 << 2) || s->chain4_alias) {
1288 /* if the plane 2 was modified since the last display, it
1289 indicates the font may have been modified */
1290 s->plane_updated = 0;
1291 full_update = 1;
1293 full_update |= update_basic_params(s);
1295 line_offset = s->line_offset;
1297 vga_get_text_resolution(s, &width, &height, &cw, &cheight);
1298 if ((height * width) > CH_ATTR_SIZE) {
1299 /* better than nothing: exit if transient size is too big */
1300 return;
1303 if (width != s->last_width || height != s->last_height ||
1304 cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
1305 s->last_scr_width = width * cw;
1306 s->last_scr_height = height * cheight;
1307 qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height);
1308 s->last_depth = 0;
1309 s->last_width = width;
1310 s->last_height = height;
1311 s->last_ch = cheight;
1312 s->last_cw = cw;
1313 full_update = 1;
1315 s->rgb_to_pixel =
1316 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1317 full_update |= update_palette16(s);
1318 palette = s->last_palette;
1319 x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1321 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1322 if (cursor_offset != s->cursor_offset ||
1323 s->cr[0xa] != s->cursor_start ||
1324 s->cr[0xb] != s->cursor_end) {
1325 /* if the cursor position changed, we update the old and new
1326 chars */
1327 if (s->cursor_offset < CH_ATTR_SIZE)
1328 s->last_ch_attr[s->cursor_offset] = -1;
1329 if (cursor_offset < CH_ATTR_SIZE)
1330 s->last_ch_attr[cursor_offset] = -1;
1331 s->cursor_offset = cursor_offset;
1332 s->cursor_start = s->cr[0xa];
1333 s->cursor_end = s->cr[0xb];
1335 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
1337 depth_index = get_depth_index(s->ds);
1338 if (cw == 16)
1339 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1340 else
1341 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
1342 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1344 dest = ds_get_data(s->ds);
1345 linesize = ds_get_linesize(s->ds);
1346 ch_attr_ptr = s->last_ch_attr;
1347 line = 0;
1348 offset = s->start_addr * 4;
1349 for(cy = 0; cy < height; cy++) {
1350 d1 = dest;
1351 src = s->vram_ptr + offset;
1352 cx_min = width;
1353 cx_max = -1;
1354 for(cx = 0; cx < width; cx++) {
1355 ch_attr = *(uint16_t *)src;
1356 if (full_update || ch_attr != *ch_attr_ptr) {
1357 if (cx < cx_min)
1358 cx_min = cx;
1359 if (cx > cx_max)
1360 cx_max = cx;
1361 *ch_attr_ptr = ch_attr;
1362 #ifdef HOST_WORDS_BIGENDIAN
1363 ch = ch_attr >> 8;
1364 cattr = ch_attr & 0xff;
1365 #else
1366 ch = ch_attr & 0xff;
1367 cattr = ch_attr >> 8;
1368 #endif
1369 font_ptr = font_base[(cattr >> 3) & 1];
1370 font_ptr += 32 * 4 * ch;
1371 bgcol = palette[cattr >> 4];
1372 fgcol = palette[cattr & 0x0f];
1373 if (cw != 9) {
1374 vga_draw_glyph8(d1, linesize,
1375 font_ptr, cheight, fgcol, bgcol);
1376 } else {
1377 dup9 = 0;
1378 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1379 dup9 = 1;
1380 vga_draw_glyph9(d1, linesize,
1381 font_ptr, cheight, fgcol, bgcol, dup9);
1383 if (src == cursor_ptr &&
1384 !(s->cr[0x0a] & 0x20)) {
1385 int line_start, line_last, h;
1386 /* draw the cursor */
1387 line_start = s->cr[0x0a] & 0x1f;
1388 line_last = s->cr[0x0b] & 0x1f;
1389 /* XXX: check that */
1390 if (line_last > cheight - 1)
1391 line_last = cheight - 1;
1392 if (line_last >= line_start && line_start < cheight) {
1393 h = line_last - line_start + 1;
1394 d = d1 + linesize * line_start;
1395 if (cw != 9) {
1396 vga_draw_glyph8(d, linesize,
1397 cursor_glyph, h, fgcol, bgcol);
1398 } else {
1399 vga_draw_glyph9(d, linesize,
1400 cursor_glyph, h, fgcol, bgcol, 1);
1405 d1 += x_incr;
1406 src += 4;
1407 ch_attr_ptr++;
1409 if (cx_max != -1) {
1410 dpy_update(s->ds, cx_min * cw, cy * cheight,
1411 (cx_max - cx_min + 1) * cw, cheight);
1413 dest += linesize * cheight;
1414 line1 = line + cheight;
1415 offset += line_offset;
1416 if (line < s->line_compare && line1 >= s->line_compare) {
1417 offset = 0;
1419 line = line1;
1423 enum {
1424 VGA_DRAW_LINE2,
1425 VGA_DRAW_LINE2D2,
1426 VGA_DRAW_LINE4,
1427 VGA_DRAW_LINE4D2,
1428 VGA_DRAW_LINE8D2,
1429 VGA_DRAW_LINE8,
1430 VGA_DRAW_LINE15,
1431 VGA_DRAW_LINE16,
1432 VGA_DRAW_LINE24,
1433 VGA_DRAW_LINE32,
1434 VGA_DRAW_LINE_NB,
1437 static vga_draw_line_func * const vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
1438 vga_draw_line2_8,
1439 vga_draw_line2_16,
1440 vga_draw_line2_16,
1441 vga_draw_line2_32,
1442 vga_draw_line2_32,
1443 vga_draw_line2_16,
1444 vga_draw_line2_16,
1446 vga_draw_line2d2_8,
1447 vga_draw_line2d2_16,
1448 vga_draw_line2d2_16,
1449 vga_draw_line2d2_32,
1450 vga_draw_line2d2_32,
1451 vga_draw_line2d2_16,
1452 vga_draw_line2d2_16,
1454 vga_draw_line4_8,
1455 vga_draw_line4_16,
1456 vga_draw_line4_16,
1457 vga_draw_line4_32,
1458 vga_draw_line4_32,
1459 vga_draw_line4_16,
1460 vga_draw_line4_16,
1462 vga_draw_line4d2_8,
1463 vga_draw_line4d2_16,
1464 vga_draw_line4d2_16,
1465 vga_draw_line4d2_32,
1466 vga_draw_line4d2_32,
1467 vga_draw_line4d2_16,
1468 vga_draw_line4d2_16,
1470 vga_draw_line8d2_8,
1471 vga_draw_line8d2_16,
1472 vga_draw_line8d2_16,
1473 vga_draw_line8d2_32,
1474 vga_draw_line8d2_32,
1475 vga_draw_line8d2_16,
1476 vga_draw_line8d2_16,
1478 vga_draw_line8_8,
1479 vga_draw_line8_16,
1480 vga_draw_line8_16,
1481 vga_draw_line8_32,
1482 vga_draw_line8_32,
1483 vga_draw_line8_16,
1484 vga_draw_line8_16,
1486 vga_draw_line15_8,
1487 vga_draw_line15_15,
1488 vga_draw_line15_16,
1489 vga_draw_line15_32,
1490 vga_draw_line15_32bgr,
1491 vga_draw_line15_15bgr,
1492 vga_draw_line15_16bgr,
1494 vga_draw_line16_8,
1495 vga_draw_line16_15,
1496 vga_draw_line16_16,
1497 vga_draw_line16_32,
1498 vga_draw_line16_32bgr,
1499 vga_draw_line16_15bgr,
1500 vga_draw_line16_16bgr,
1502 vga_draw_line24_8,
1503 vga_draw_line24_15,
1504 vga_draw_line24_16,
1505 vga_draw_line24_32,
1506 vga_draw_line24_32bgr,
1507 vga_draw_line24_15bgr,
1508 vga_draw_line24_16bgr,
1510 vga_draw_line32_8,
1511 vga_draw_line32_15,
1512 vga_draw_line32_16,
1513 vga_draw_line32_32,
1514 vga_draw_line32_32bgr,
1515 vga_draw_line32_15bgr,
1516 vga_draw_line32_16bgr,
1519 static int vga_get_bpp(VGACommonState *s)
1521 int ret;
1522 #ifdef CONFIG_BOCHS_VBE
1523 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1524 ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
1525 } else
1526 #endif
1528 ret = 0;
1530 return ret;
1533 static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
1535 int width, height;
1537 #ifdef CONFIG_BOCHS_VBE
1538 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1539 width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
1540 height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
1541 } else
1542 #endif
1544 width = (s->cr[0x01] + 1) * 8;
1545 height = s->cr[0x12] |
1546 ((s->cr[0x07] & 0x02) << 7) |
1547 ((s->cr[0x07] & 0x40) << 3);
1548 height = (height + 1);
1550 *pwidth = width;
1551 *pheight = height;
1554 void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2)
1556 int y;
1557 if (y1 >= VGA_MAX_HEIGHT)
1558 return;
1559 if (y2 >= VGA_MAX_HEIGHT)
1560 y2 = VGA_MAX_HEIGHT;
1561 for(y = y1; y < y2; y++) {
1562 s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1566 static void vga_sync_dirty_bitmap(VGACommonState *s)
1568 memory_region_sync_dirty_bitmap(&s->vram);
1571 void vga_dirty_log_start(VGACommonState *s)
1573 memory_region_set_log(&s->vram, true, DIRTY_MEMORY_VGA);
1576 void vga_dirty_log_stop(VGACommonState *s)
1578 memory_region_set_log(&s->vram, false, DIRTY_MEMORY_VGA);
1582 * graphic modes
1584 static void vga_draw_graphic(VGACommonState *s, int full_update)
1586 int y1, y, update, linesize, y_start, double_scan, mask, depth;
1587 int width, height, shift_control, line_offset, bwidth, bits;
1588 ram_addr_t page0, page1, page_min, page_max;
1589 int disp_width, multi_scan, multi_run;
1590 uint8_t *d;
1591 uint32_t v, addr1, addr;
1592 vga_draw_line_func *vga_draw_line;
1594 full_update |= update_basic_params(s);
1596 if (!full_update)
1597 vga_sync_dirty_bitmap(s);
1599 s->get_resolution(s, &width, &height);
1600 disp_width = width;
1602 shift_control = (s->gr[0x05] >> 5) & 3;
1603 double_scan = (s->cr[0x09] >> 7);
1604 if (shift_control != 1) {
1605 multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
1606 } else {
1607 /* in CGA modes, multi_scan is ignored */
1608 /* XXX: is it correct ? */
1609 multi_scan = double_scan;
1611 multi_run = multi_scan;
1612 if (shift_control != s->shift_control ||
1613 double_scan != s->double_scan) {
1614 full_update = 1;
1615 s->shift_control = shift_control;
1616 s->double_scan = double_scan;
1619 if (shift_control == 0) {
1620 if (s->sr[0x01] & 8) {
1621 disp_width <<= 1;
1623 } else if (shift_control == 1) {
1624 if (s->sr[0x01] & 8) {
1625 disp_width <<= 1;
1629 depth = s->get_bpp(s);
1630 if (s->line_offset != s->last_line_offset ||
1631 disp_width != s->last_width ||
1632 height != s->last_height ||
1633 s->last_depth != depth) {
1634 #if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
1635 if (depth == 16 || depth == 32) {
1636 #else
1637 if (depth == 32) {
1638 #endif
1639 qemu_free_displaysurface(s->ds);
1640 s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth,
1641 s->line_offset,
1642 s->vram_ptr + (s->start_addr * 4));
1643 #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
1644 s->ds->surface->pf = qemu_different_endianness_pixelformat(depth);
1645 #endif
1646 dpy_resize(s->ds);
1647 } else {
1648 qemu_console_resize(s->ds, disp_width, height);
1650 s->last_scr_width = disp_width;
1651 s->last_scr_height = height;
1652 s->last_width = disp_width;
1653 s->last_height = height;
1654 s->last_line_offset = s->line_offset;
1655 s->last_depth = depth;
1656 full_update = 1;
1657 } else if (is_buffer_shared(s->ds->surface) &&
1658 (full_update || s->ds->surface->data != s->vram_ptr + (s->start_addr * 4))) {
1659 s->ds->surface->data = s->vram_ptr + (s->start_addr * 4);
1660 dpy_setdata(s->ds);
1663 s->rgb_to_pixel =
1664 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1666 if (shift_control == 0) {
1667 full_update |= update_palette16(s);
1668 if (s->sr[0x01] & 8) {
1669 v = VGA_DRAW_LINE4D2;
1670 } else {
1671 v = VGA_DRAW_LINE4;
1673 bits = 4;
1674 } else if (shift_control == 1) {
1675 full_update |= update_palette16(s);
1676 if (s->sr[0x01] & 8) {
1677 v = VGA_DRAW_LINE2D2;
1678 } else {
1679 v = VGA_DRAW_LINE2;
1681 bits = 4;
1682 } else {
1683 switch(s->get_bpp(s)) {
1684 default:
1685 case 0:
1686 full_update |= update_palette256(s);
1687 v = VGA_DRAW_LINE8D2;
1688 bits = 4;
1689 break;
1690 case 8:
1691 full_update |= update_palette256(s);
1692 v = VGA_DRAW_LINE8;
1693 bits = 8;
1694 break;
1695 case 15:
1696 v = VGA_DRAW_LINE15;
1697 bits = 16;
1698 break;
1699 case 16:
1700 v = VGA_DRAW_LINE16;
1701 bits = 16;
1702 break;
1703 case 24:
1704 v = VGA_DRAW_LINE24;
1705 bits = 24;
1706 break;
1707 case 32:
1708 v = VGA_DRAW_LINE32;
1709 bits = 32;
1710 break;
1713 vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
1715 if (!is_buffer_shared(s->ds->surface) && s->cursor_invalidate)
1716 s->cursor_invalidate(s);
1718 line_offset = s->line_offset;
1719 #if 0
1720 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",
1721 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1722 #endif
1723 addr1 = (s->start_addr * 4);
1724 bwidth = (width * bits + 7) / 8;
1725 y_start = -1;
1726 page_min = -1;
1727 page_max = 0;
1728 d = ds_get_data(s->ds);
1729 linesize = ds_get_linesize(s->ds);
1730 y1 = 0;
1731 for(y = 0; y < height; y++) {
1732 addr = addr1;
1733 if (!(s->cr[0x17] & 1)) {
1734 int shift;
1735 /* CGA compatibility handling */
1736 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1737 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1739 if (!(s->cr[0x17] & 2)) {
1740 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1742 page0 = addr & TARGET_PAGE_MASK;
1743 page1 = (addr + bwidth - 1) & TARGET_PAGE_MASK;
1744 update = full_update |
1745 memory_region_get_dirty(&s->vram, page0, DIRTY_MEMORY_VGA) |
1746 memory_region_get_dirty(&s->vram, page1, DIRTY_MEMORY_VGA);
1747 if ((page1 - page0) > TARGET_PAGE_SIZE) {
1748 /* if wide line, can use another page */
1749 update |= memory_region_get_dirty(&s->vram,
1750 page0 + TARGET_PAGE_SIZE,
1751 DIRTY_MEMORY_VGA);
1753 /* explicit invalidation for the hardware cursor */
1754 update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
1755 if (update) {
1756 if (y_start < 0)
1757 y_start = y;
1758 if (page0 < page_min)
1759 page_min = page0;
1760 if (page1 > page_max)
1761 page_max = page1;
1762 if (!(is_buffer_shared(s->ds->surface))) {
1763 vga_draw_line(s, d, s->vram_ptr + addr, width);
1764 if (s->cursor_draw_line)
1765 s->cursor_draw_line(s, d, y);
1767 } else {
1768 if (y_start >= 0) {
1769 /* flush to display */
1770 dpy_update(s->ds, 0, y_start,
1771 disp_width, y - y_start);
1772 y_start = -1;
1775 if (!multi_run) {
1776 mask = (s->cr[0x17] & 3) ^ 3;
1777 if ((y1 & mask) == mask)
1778 addr1 += line_offset;
1779 y1++;
1780 multi_run = multi_scan;
1781 } else {
1782 multi_run--;
1784 /* line compare acts on the displayed lines */
1785 if (y == s->line_compare)
1786 addr1 = 0;
1787 d += linesize;
1789 if (y_start >= 0) {
1790 /* flush to display */
1791 dpy_update(s->ds, 0, y_start,
1792 disp_width, y - y_start);
1794 /* reset modified pages */
1795 if (page_max >= page_min) {
1796 memory_region_reset_dirty(&s->vram,
1797 page_min,
1798 page_max + TARGET_PAGE_SIZE - page_min,
1799 DIRTY_MEMORY_VGA);
1801 memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
1804 static void vga_draw_blank(VGACommonState *s, int full_update)
1806 int i, w, val;
1807 uint8_t *d;
1809 if (!full_update)
1810 return;
1811 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1812 return;
1814 s->rgb_to_pixel =
1815 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1816 if (ds_get_bits_per_pixel(s->ds) == 8)
1817 val = s->rgb_to_pixel(0, 0, 0);
1818 else
1819 val = 0;
1820 w = s->last_scr_width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1821 d = ds_get_data(s->ds);
1822 for(i = 0; i < s->last_scr_height; i++) {
1823 memset(d, val, w);
1824 d += ds_get_linesize(s->ds);
1826 dpy_update(s->ds, 0, 0,
1827 s->last_scr_width, s->last_scr_height);
1830 #define GMODE_TEXT 0
1831 #define GMODE_GRAPH 1
1832 #define GMODE_BLANK 2
1834 static void vga_update_display(void *opaque)
1836 VGACommonState *s = opaque;
1837 int full_update, graphic_mode;
1839 if (ds_get_bits_per_pixel(s->ds) == 0) {
1840 /* nothing to do */
1841 } else {
1842 full_update = 0;
1843 if (!(s->ar_index & 0x20)) {
1844 graphic_mode = GMODE_BLANK;
1845 } else {
1846 graphic_mode = s->gr[6] & 1;
1848 if (graphic_mode != s->graphic_mode) {
1849 s->graphic_mode = graphic_mode;
1850 full_update = 1;
1852 switch(graphic_mode) {
1853 case GMODE_TEXT:
1854 vga_draw_text(s, full_update);
1855 break;
1856 case GMODE_GRAPH:
1857 vga_draw_graphic(s, full_update);
1858 break;
1859 case GMODE_BLANK:
1860 default:
1861 vga_draw_blank(s, full_update);
1862 break;
1867 /* force a full display refresh */
1868 static void vga_invalidate_display(void *opaque)
1870 VGACommonState *s = opaque;
1872 s->last_width = -1;
1873 s->last_height = -1;
1876 void vga_common_reset(VGACommonState *s)
1878 s->sr_index = 0;
1879 memset(s->sr, '\0', sizeof(s->sr));
1880 s->gr_index = 0;
1881 memset(s->gr, '\0', sizeof(s->gr));
1882 s->ar_index = 0;
1883 memset(s->ar, '\0', sizeof(s->ar));
1884 s->ar_flip_flop = 0;
1885 s->cr_index = 0;
1886 memset(s->cr, '\0', sizeof(s->cr));
1887 s->msr = 0;
1888 s->fcr = 0;
1889 s->st00 = 0;
1890 s->st01 = 0;
1891 s->dac_state = 0;
1892 s->dac_sub_index = 0;
1893 s->dac_read_index = 0;
1894 s->dac_write_index = 0;
1895 memset(s->dac_cache, '\0', sizeof(s->dac_cache));
1896 s->dac_8bit = 0;
1897 memset(s->palette, '\0', sizeof(s->palette));
1898 s->bank_offset = 0;
1899 #ifdef CONFIG_BOCHS_VBE
1900 s->vbe_index = 0;
1901 memset(s->vbe_regs, '\0', sizeof(s->vbe_regs));
1902 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID5;
1903 s->vbe_start_addr = 0;
1904 s->vbe_line_offset = 0;
1905 s->vbe_bank_mask = (s->vram_size >> 16) - 1;
1906 #endif
1907 memset(s->font_offsets, '\0', sizeof(s->font_offsets));
1908 s->graphic_mode = -1; /* force full update */
1909 s->shift_control = 0;
1910 s->double_scan = 0;
1911 s->line_offset = 0;
1912 s->line_compare = 0;
1913 s->start_addr = 0;
1914 s->plane_updated = 0;
1915 s->last_cw = 0;
1916 s->last_ch = 0;
1917 s->last_width = 0;
1918 s->last_height = 0;
1919 s->last_scr_width = 0;
1920 s->last_scr_height = 0;
1921 s->cursor_start = 0;
1922 s->cursor_end = 0;
1923 s->cursor_offset = 0;
1924 memset(s->invalidated_y_table, '\0', sizeof(s->invalidated_y_table));
1925 memset(s->last_palette, '\0', sizeof(s->last_palette));
1926 memset(s->last_ch_attr, '\0', sizeof(s->last_ch_attr));
1927 switch (vga_retrace_method) {
1928 case VGA_RETRACE_DUMB:
1929 break;
1930 case VGA_RETRACE_PRECISE:
1931 memset(&s->retrace_info, 0, sizeof (s->retrace_info));
1932 break;
1934 vga_update_memory_access(s);
1937 static void vga_reset(void *opaque)
1939 VGACommonState *s = opaque;
1940 vga_common_reset(s);
1943 #define TEXTMODE_X(x) ((x) % width)
1944 #define TEXTMODE_Y(x) ((x) / width)
1945 #define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1946 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1947 /* relay text rendering to the display driver
1948 * instead of doing a full vga_update_display() */
1949 static void vga_update_text(void *opaque, console_ch_t *chardata)
1951 VGACommonState *s = opaque;
1952 int graphic_mode, i, cursor_offset, cursor_visible;
1953 int cw, cheight, width, height, size, c_min, c_max;
1954 uint32_t *src;
1955 console_ch_t *dst, val;
1956 char msg_buffer[80];
1957 int full_update = 0;
1959 if (!(s->ar_index & 0x20)) {
1960 graphic_mode = GMODE_BLANK;
1961 } else {
1962 graphic_mode = s->gr[6] & 1;
1964 if (graphic_mode != s->graphic_mode) {
1965 s->graphic_mode = graphic_mode;
1966 full_update = 1;
1968 if (s->last_width == -1) {
1969 s->last_width = 0;
1970 full_update = 1;
1973 switch (graphic_mode) {
1974 case GMODE_TEXT:
1975 /* TODO: update palette */
1976 full_update |= update_basic_params(s);
1978 /* total width & height */
1979 cheight = (s->cr[9] & 0x1f) + 1;
1980 cw = 8;
1981 if (!(s->sr[1] & 0x01))
1982 cw = 9;
1983 if (s->sr[1] & 0x08)
1984 cw = 16; /* NOTE: no 18 pixel wide */
1985 width = (s->cr[0x01] + 1);
1986 if (s->cr[0x06] == 100) {
1987 /* ugly hack for CGA 160x100x16 - explain me the logic */
1988 height = 100;
1989 } else {
1990 height = s->cr[0x12] |
1991 ((s->cr[0x07] & 0x02) << 7) |
1992 ((s->cr[0x07] & 0x40) << 3);
1993 height = (height + 1) / cheight;
1996 size = (height * width);
1997 if (size > CH_ATTR_SIZE) {
1998 if (!full_update)
1999 return;
2001 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
2002 width, height);
2003 break;
2006 if (width != s->last_width || height != s->last_height ||
2007 cw != s->last_cw || cheight != s->last_ch) {
2008 s->last_scr_width = width * cw;
2009 s->last_scr_height = height * cheight;
2010 s->ds->surface->width = width;
2011 s->ds->surface->height = height;
2012 dpy_resize(s->ds);
2013 s->last_width = width;
2014 s->last_height = height;
2015 s->last_ch = cheight;
2016 s->last_cw = cw;
2017 full_update = 1;
2020 /* Update "hardware" cursor */
2021 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
2022 if (cursor_offset != s->cursor_offset ||
2023 s->cr[0xa] != s->cursor_start ||
2024 s->cr[0xb] != s->cursor_end || full_update) {
2025 cursor_visible = !(s->cr[0xa] & 0x20);
2026 if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
2027 dpy_cursor(s->ds,
2028 TEXTMODE_X(cursor_offset),
2029 TEXTMODE_Y(cursor_offset));
2030 else
2031 dpy_cursor(s->ds, -1, -1);
2032 s->cursor_offset = cursor_offset;
2033 s->cursor_start = s->cr[0xa];
2034 s->cursor_end = s->cr[0xb];
2037 src = (uint32_t *) s->vram_ptr + s->start_addr;
2038 dst = chardata;
2040 if (full_update) {
2041 for (i = 0; i < size; src ++, dst ++, i ++)
2042 console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src)));
2044 dpy_update(s->ds, 0, 0, width, height);
2045 } else {
2046 c_max = 0;
2048 for (i = 0; i < size; src ++, dst ++, i ++) {
2049 console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
2050 if (*dst != val) {
2051 *dst = val;
2052 c_max = i;
2053 break;
2056 c_min = i;
2057 for (; i < size; src ++, dst ++, i ++) {
2058 console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
2059 if (*dst != val) {
2060 *dst = val;
2061 c_max = i;
2065 if (c_min <= c_max) {
2066 i = TEXTMODE_Y(c_min);
2067 dpy_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
2071 return;
2072 case GMODE_GRAPH:
2073 if (!full_update)
2074 return;
2076 s->get_resolution(s, &width, &height);
2077 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
2078 width, height);
2079 break;
2080 case GMODE_BLANK:
2081 default:
2082 if (!full_update)
2083 return;
2085 snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
2086 break;
2089 /* Display a message */
2090 s->last_width = 60;
2091 s->last_height = height = 3;
2092 dpy_cursor(s->ds, -1, -1);
2093 s->ds->surface->width = s->last_width;
2094 s->ds->surface->height = height;
2095 dpy_resize(s->ds);
2097 for (dst = chardata, i = 0; i < s->last_width * height; i ++)
2098 console_write_ch(dst ++, ' ');
2100 size = strlen(msg_buffer);
2101 width = (s->last_width - size) / 2;
2102 dst = chardata + s->last_width + width;
2103 for (i = 0; i < size; i ++)
2104 console_write_ch(dst ++, 0x00200100 | msg_buffer[i]);
2106 dpy_update(s->ds, 0, 0, s->last_width, height);
2109 static uint64_t vga_mem_read(void *opaque, target_phys_addr_t addr,
2110 unsigned size)
2112 VGACommonState *s = opaque;
2114 return vga_mem_readb(s, addr);
2117 static void vga_mem_write(void *opaque, target_phys_addr_t addr,
2118 uint64_t data, unsigned size)
2120 VGACommonState *s = opaque;
2122 return vga_mem_writeb(s, addr, data);
2125 const MemoryRegionOps vga_mem_ops = {
2126 .read = vga_mem_read,
2127 .write = vga_mem_write,
2128 .endianness = DEVICE_LITTLE_ENDIAN,
2129 .impl = {
2130 .min_access_size = 1,
2131 .max_access_size = 1,
2135 static int vga_common_post_load(void *opaque, int version_id)
2137 VGACommonState *s = opaque;
2139 /* force refresh */
2140 s->graphic_mode = -1;
2141 return 0;
2144 const VMStateDescription vmstate_vga_common = {
2145 .name = "vga",
2146 .version_id = 2,
2147 .minimum_version_id = 2,
2148 .minimum_version_id_old = 2,
2149 .post_load = vga_common_post_load,
2150 .fields = (VMStateField []) {
2151 VMSTATE_UINT32(latch, VGACommonState),
2152 VMSTATE_UINT8(sr_index, VGACommonState),
2153 VMSTATE_PARTIAL_BUFFER(sr, VGACommonState, 8),
2154 VMSTATE_UINT8(gr_index, VGACommonState),
2155 VMSTATE_PARTIAL_BUFFER(gr, VGACommonState, 16),
2156 VMSTATE_UINT8(ar_index, VGACommonState),
2157 VMSTATE_BUFFER(ar, VGACommonState),
2158 VMSTATE_INT32(ar_flip_flop, VGACommonState),
2159 VMSTATE_UINT8(cr_index, VGACommonState),
2160 VMSTATE_BUFFER(cr, VGACommonState),
2161 VMSTATE_UINT8(msr, VGACommonState),
2162 VMSTATE_UINT8(fcr, VGACommonState),
2163 VMSTATE_UINT8(st00, VGACommonState),
2164 VMSTATE_UINT8(st01, VGACommonState),
2166 VMSTATE_UINT8(dac_state, VGACommonState),
2167 VMSTATE_UINT8(dac_sub_index, VGACommonState),
2168 VMSTATE_UINT8(dac_read_index, VGACommonState),
2169 VMSTATE_UINT8(dac_write_index, VGACommonState),
2170 VMSTATE_BUFFER(dac_cache, VGACommonState),
2171 VMSTATE_BUFFER(palette, VGACommonState),
2173 VMSTATE_INT32(bank_offset, VGACommonState),
2174 VMSTATE_UINT8_EQUAL(is_vbe_vmstate, VGACommonState),
2175 #ifdef CONFIG_BOCHS_VBE
2176 VMSTATE_UINT16(vbe_index, VGACommonState),
2177 VMSTATE_UINT16_ARRAY(vbe_regs, VGACommonState, VBE_DISPI_INDEX_NB),
2178 VMSTATE_UINT32(vbe_start_addr, VGACommonState),
2179 VMSTATE_UINT32(vbe_line_offset, VGACommonState),
2180 VMSTATE_UINT32(vbe_bank_mask, VGACommonState),
2181 #endif
2182 VMSTATE_END_OF_LIST()
2186 void vga_common_init(VGACommonState *s, int vga_ram_size)
2188 int i, j, v, b;
2190 for(i = 0;i < 256; i++) {
2191 v = 0;
2192 for(j = 0; j < 8; j++) {
2193 v |= ((i >> j) & 1) << (j * 4);
2195 expand4[i] = v;
2197 v = 0;
2198 for(j = 0; j < 4; j++) {
2199 v |= ((i >> (2 * j)) & 3) << (j * 4);
2201 expand2[i] = v;
2203 for(i = 0; i < 16; i++) {
2204 v = 0;
2205 for(j = 0; j < 4; j++) {
2206 b = ((i >> j) & 1);
2207 v |= b << (2 * j);
2208 v |= b << (2 * j + 1);
2210 expand4to8[i] = v;
2213 #ifdef CONFIG_BOCHS_VBE
2214 s->is_vbe_vmstate = 1;
2215 #else
2216 s->is_vbe_vmstate = 0;
2217 #endif
2218 memory_region_init_ram(&s->vram, NULL, "vga.vram", vga_ram_size);
2219 s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
2220 s->vram_size = vga_ram_size;
2221 s->get_bpp = vga_get_bpp;
2222 s->get_offsets = vga_get_offsets;
2223 s->get_resolution = vga_get_resolution;
2224 s->update = vga_update_display;
2225 s->invalidate = vga_invalidate_display;
2226 s->screen_dump = vga_screen_dump;
2227 s->text_update = vga_update_text;
2228 switch (vga_retrace_method) {
2229 case VGA_RETRACE_DUMB:
2230 s->retrace = vga_dumb_retrace;
2231 s->update_retrace_info = vga_dumb_update_retrace_info;
2232 break;
2234 case VGA_RETRACE_PRECISE:
2235 s->retrace = vga_precise_retrace;
2236 s->update_retrace_info = vga_precise_update_retrace_info;
2237 break;
2239 vga_dirty_log_start(s);
2242 /* used by both ISA and PCI */
2243 MemoryRegion *vga_init_io(VGACommonState *s)
2245 MemoryRegion *vga_mem;
2247 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
2249 register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
2250 register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
2251 register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
2252 register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
2254 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
2256 register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
2257 register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
2258 register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
2259 register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
2261 #ifdef CONFIG_BOCHS_VBE
2262 #if defined (TARGET_I386)
2263 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2264 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
2266 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2267 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
2268 #else
2269 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2270 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
2272 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2273 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
2274 #endif
2275 #endif /* CONFIG_BOCHS_VBE */
2277 vga_mem = g_malloc(sizeof(*vga_mem));
2278 memory_region_init_io(vga_mem, &vga_mem_ops, s,
2279 "vga-lowmem", 0x20000);
2281 return vga_mem;
2284 void vga_init(VGACommonState *s, MemoryRegion *address_space)
2286 MemoryRegion *vga_io_memory;
2288 qemu_register_reset(vga_reset, s);
2290 s->bank_offset = 0;
2292 s->legacy_address_space = address_space;
2294 vga_io_memory = vga_init_io(s);
2295 memory_region_add_subregion_overlap(address_space,
2296 isa_mem_base + 0x000a0000,
2297 vga_io_memory,
2299 memory_region_set_coalescing(vga_io_memory);
2302 void vga_init_vbe(VGACommonState *s, MemoryRegion *system_memory)
2304 #ifdef CONFIG_BOCHS_VBE
2305 /* XXX: use optimized standard vga accesses */
2306 memory_region_add_subregion(system_memory,
2307 VBE_DISPI_LFB_PHYSICAL_ADDRESS,
2308 &s->vram);
2309 s->vbe_mapped = 1;
2310 #endif
2312 /********************************************************/
2313 /* vga screen dump */
2315 static void vga_save_dpy_update(DisplayState *ds,
2316 int x, int y, int w, int h)
2318 if (screen_dump_filename) {
2319 ppm_save(screen_dump_filename, ds->surface);
2320 screen_dump_filename = NULL;
2324 static void vga_save_dpy_resize(DisplayState *s)
2328 static void vga_save_dpy_refresh(DisplayState *s)
2332 int ppm_save(const char *filename, struct DisplaySurface *ds)
2334 FILE *f;
2335 uint8_t *d, *d1;
2336 uint32_t v;
2337 int y, x;
2338 uint8_t r, g, b;
2339 int ret;
2340 char *linebuf, *pbuf;
2342 f = fopen(filename, "wb");
2343 if (!f)
2344 return -1;
2345 fprintf(f, "P6\n%d %d\n%d\n",
2346 ds->width, ds->height, 255);
2347 linebuf = g_malloc(ds->width * 3);
2348 d1 = ds->data;
2349 for(y = 0; y < ds->height; y++) {
2350 d = d1;
2351 pbuf = linebuf;
2352 for(x = 0; x < ds->width; x++) {
2353 if (ds->pf.bits_per_pixel == 32)
2354 v = *(uint32_t *)d;
2355 else
2356 v = (uint32_t) (*(uint16_t *)d);
2357 r = ((v >> ds->pf.rshift) & ds->pf.rmax) * 256 /
2358 (ds->pf.rmax + 1);
2359 g = ((v >> ds->pf.gshift) & ds->pf.gmax) * 256 /
2360 (ds->pf.gmax + 1);
2361 b = ((v >> ds->pf.bshift) & ds->pf.bmax) * 256 /
2362 (ds->pf.bmax + 1);
2363 *pbuf++ = r;
2364 *pbuf++ = g;
2365 *pbuf++ = b;
2366 d += ds->pf.bytes_per_pixel;
2368 d1 += ds->linesize;
2369 ret = fwrite(linebuf, 1, pbuf - linebuf, f);
2370 (void)ret;
2372 g_free(linebuf);
2373 fclose(f);
2374 return 0;
2377 static DisplayChangeListener* vga_screen_dump_init(DisplayState *ds)
2379 DisplayChangeListener *dcl;
2381 dcl = g_malloc0(sizeof(DisplayChangeListener));
2382 dcl->dpy_update = vga_save_dpy_update;
2383 dcl->dpy_resize = vga_save_dpy_resize;
2384 dcl->dpy_refresh = vga_save_dpy_refresh;
2385 register_displaychangelistener(ds, dcl);
2386 return dcl;
2389 /* save the vga display in a PPM image even if no display is
2390 available */
2391 static void vga_screen_dump(void *opaque, const char *filename)
2393 VGACommonState *s = opaque;
2395 if (!screen_dump_dcl)
2396 screen_dump_dcl = vga_screen_dump_init(s->ds);
2398 screen_dump_filename = (char *)filename;
2399 vga_invalidate_display(s);
2400 vga_hw_update();