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
29 #include "pixel_ops.h"
30 #include "qemu-timer.h"
34 //#define DEBUG_VGA_MEM
35 //#define DEBUG_VGA_REG
37 //#define DEBUG_BOCHS_VBE
43 /* force some bits to zero */
44 const uint8_t sr_mask[8] = {
55 const uint8_t gr_mask[16] = {
74 #define cbswap_32(__x) \
76 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
77 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
78 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
79 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
81 #ifdef WORDS_BIGENDIAN
82 #define PAT(x) cbswap_32(x)
87 #ifdef WORDS_BIGENDIAN
93 #ifdef WORDS_BIGENDIAN
94 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
96 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
99 static const uint32_t mask16[16] = {
120 #ifdef WORDS_BIGENDIAN
123 #define PAT(x) cbswap_32(x)
126 static const uint32_t dmask16[16] = {
145 static const uint32_t dmask4[4] = {
152 static uint32_t expand4[256];
153 static uint16_t expand2[256];
154 static uint8_t expand4to8[16];
156 static void vga_screen_dump(void *opaque, const char *filename);
158 static void vga_dumb_update_retrace_info(VGAState *s)
163 static void vga_precise_update_retrace_info(VGAState *s)
166 int hretr_start_char;
167 int hretr_skew_chars;
171 int vretr_start_line;
174 int div2, sldiv2, dots;
177 const int clk_hz[] = {25175000, 28322000, 25175000, 25175000};
178 int64_t chars_per_sec;
179 struct vga_precise_retrace *r = &s->retrace_info.precise;
181 htotal_chars = s->cr[0x00] + 5;
182 hretr_start_char = s->cr[0x04];
183 hretr_skew_chars = (s->cr[0x05] >> 5) & 3;
184 hretr_end_char = s->cr[0x05] & 0x1f;
186 vtotal_lines = (s->cr[0x06]
187 | (((s->cr[0x07] & 1) | ((s->cr[0x07] >> 4) & 2)) << 8)) + 2
189 vretr_start_line = s->cr[0x10]
190 | ((((s->cr[0x07] >> 2) & 1) | ((s->cr[0x07] >> 6) & 2)) << 8)
192 vretr_end_line = s->cr[0x11] & 0xf;
195 div2 = (s->cr[0x17] >> 2) & 1;
196 sldiv2 = (s->cr[0x17] >> 3) & 1;
198 clocking_mode = (s->sr[0x01] >> 3) & 1;
199 clock_sel = (s->msr >> 2) & 3;
200 dots = (s->msr & 1) ? 8 : 9;
202 chars_per_sec = clk_hz[clock_sel] / dots;
204 htotal_chars <<= clocking_mode;
206 r->total_chars = vtotal_lines * htotal_chars;
208 r->ticks_per_char = ticks_per_sec / (r->total_chars * r->freq);
210 r->ticks_per_char = ticks_per_sec / chars_per_sec;
213 r->vstart = vretr_start_line;
214 r->vend = r->vstart + vretr_end_line + 1;
216 r->hstart = hretr_start_char + hretr_skew_chars;
217 r->hend = r->hstart + hretr_end_char + 1;
218 r->htotal = htotal_chars;
230 "div2 = %d sldiv2 = %d\n"
231 "clocking_mode = %d\n"
232 "clock_sel = %d %d\n"
234 "ticks/char = %lld\n"
236 (double) ticks_per_sec / (r->ticks_per_char * r->total_chars),
254 static uint8_t vga_precise_retrace(VGAState *s)
256 struct vga_precise_retrace *r = &s->retrace_info.precise;
257 uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE);
259 if (r->total_chars) {
260 int cur_line, cur_line_char, cur_char;
263 cur_tick = qemu_get_clock(vm_clock);
265 cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
266 cur_line = cur_char / r->htotal;
268 if (cur_line >= r->vstart && cur_line <= r->vend) {
269 val |= ST01_V_RETRACE | ST01_DISP_ENABLE;
271 cur_line_char = cur_char % r->htotal;
272 if (cur_line_char >= r->hstart && cur_line_char <= r->hend) {
273 val |= ST01_DISP_ENABLE;
279 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
283 static uint8_t vga_dumb_retrace(VGAState *s)
285 return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
288 static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
290 VGAState *s = opaque;
293 /* check port range access depending on color/monochrome mode */
294 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
295 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) {
300 if (s->ar_flip_flop == 0) {
307 index = s->ar_index & 0x1f;
320 val = s->sr[s->sr_index];
322 printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
329 val = s->dac_write_index;
332 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
333 if (++s->dac_sub_index == 3) {
334 s->dac_sub_index = 0;
348 val = s->gr[s->gr_index];
350 printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
359 val = s->cr[s->cr_index];
361 printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
366 /* just toggle to fool polling */
367 val = s->st01 = s->retrace(s);
375 #if defined(DEBUG_VGA)
376 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
381 static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
383 VGAState *s = opaque;
386 /* check port range access depending on color/monochrome mode */
387 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
388 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION)))
392 printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
397 if (s->ar_flip_flop == 0) {
400 vga_update_resolution(s);
402 index = s->ar_index & 0x1f;
405 s->ar[index] = val & 0x3f;
408 s->ar[index] = val & ~0x10;
414 s->ar[index] = val & ~0xc0;
417 s->ar[index] = val & ~0xf0;
420 s->ar[index] = val & ~0xf0;
426 s->ar_flip_flop ^= 1;
429 s->msr = val & ~0x10;
430 s->update_retrace_info(s);
433 s->sr_index = val & 7;
437 printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
439 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
440 if (s->sr_index == 1) s->update_retrace_info(s);
441 vga_update_resolution(s);
444 s->dac_read_index = val;
445 s->dac_sub_index = 0;
449 s->dac_write_index = val;
450 s->dac_sub_index = 0;
454 s->dac_cache[s->dac_sub_index] = val;
455 if (++s->dac_sub_index == 3) {
456 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
457 s->dac_sub_index = 0;
458 s->dac_write_index++;
462 s->gr_index = val & 0x0f;
466 printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
468 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
469 vga_update_resolution(s);
478 printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
480 /* handle CR0-7 protection */
481 if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
482 /* can always write bit 4 of CR7 */
483 if (s->cr_index == 7)
484 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
485 vga_update_resolution(s);
488 switch(s->cr_index) {
489 case 0x01: /* horizontal display end */
494 case 0x12: /* vertical display end */
495 s->cr[s->cr_index] = val;
498 s->cr[s->cr_index] = val;
502 switch(s->cr_index) {
510 s->update_retrace_info(s);
513 vga_update_resolution(s);
522 #ifdef CONFIG_BOCHS_VBE
523 static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
525 VGAState *s = opaque;
531 static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
533 VGAState *s = opaque;
536 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
537 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
538 switch(s->vbe_index) {
539 /* XXX: do not hardcode ? */
540 case VBE_DISPI_INDEX_XRES:
541 val = VBE_DISPI_MAX_XRES;
543 case VBE_DISPI_INDEX_YRES:
544 val = VBE_DISPI_MAX_YRES;
546 case VBE_DISPI_INDEX_BPP:
547 val = VBE_DISPI_MAX_BPP;
550 val = s->vbe_regs[s->vbe_index];
554 val = s->vbe_regs[s->vbe_index];
559 #ifdef DEBUG_BOCHS_VBE
560 printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
565 static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
567 VGAState *s = opaque;
571 static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
573 VGAState *s = opaque;
575 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
576 #ifdef DEBUG_BOCHS_VBE
577 printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
579 switch(s->vbe_index) {
580 case VBE_DISPI_INDEX_ID:
581 if (val == VBE_DISPI_ID0 ||
582 val == VBE_DISPI_ID1 ||
583 val == VBE_DISPI_ID2 ||
584 val == VBE_DISPI_ID3 ||
585 val == VBE_DISPI_ID4) {
586 s->vbe_regs[s->vbe_index] = val;
589 case VBE_DISPI_INDEX_XRES:
590 if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
591 s->vbe_regs[s->vbe_index] = val;
593 vga_update_resolution(s);
595 case VBE_DISPI_INDEX_YRES:
596 if (val <= VBE_DISPI_MAX_YRES) {
597 s->vbe_regs[s->vbe_index] = val;
599 vga_update_resolution(s);
601 case VBE_DISPI_INDEX_BPP:
604 if (val == 4 || val == 8 || val == 15 ||
605 val == 16 || val == 24 || val == 32) {
606 s->vbe_regs[s->vbe_index] = val;
608 vga_update_resolution(s);
610 case VBE_DISPI_INDEX_BANK:
611 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
612 val &= (s->vbe_bank_mask >> 2);
614 val &= s->vbe_bank_mask;
616 s->vbe_regs[s->vbe_index] = val;
617 s->bank_offset = (val << 16);
619 case VBE_DISPI_INDEX_ENABLE:
620 if ((val & VBE_DISPI_ENABLED) &&
621 !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
622 int h, shift_control;
624 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
625 s->vbe_regs[VBE_DISPI_INDEX_XRES];
626 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
627 s->vbe_regs[VBE_DISPI_INDEX_YRES];
628 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
629 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
631 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
632 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
634 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
635 ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
636 s->vbe_start_addr = 0;
638 /* clear the screen (should be done in BIOS) */
639 if (!(val & VBE_DISPI_NOCLEARMEM)) {
640 memset(s->vram_ptr, 0,
641 s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
644 /* we initialize the VGA graphic mode (should be done
646 s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
647 s->cr[0x17] |= 3; /* no CGA modes */
648 s->cr[0x13] = s->vbe_line_offset >> 3;
650 s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
651 /* height (only meaningful if < 1024) */
652 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
654 s->cr[0x07] = (s->cr[0x07] & ~0x42) |
655 ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
656 /* line compare to 1023 */
661 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
663 s->sr[0x01] &= ~8; /* no double line */
666 s->sr[4] |= 0x08; /* set chain 4 mode */
667 s->sr[2] |= 0x0f; /* activate all planes */
669 s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
670 s->cr[0x09] &= ~0x9f; /* no double scan */
672 /* XXX: the bios should do that */
675 s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
676 s->vbe_regs[s->vbe_index] = val;
677 vga_update_resolution(s);
679 case VBE_DISPI_INDEX_VIRT_WIDTH:
681 int w, h, line_offset;
683 if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
686 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
687 line_offset = w >> 1;
689 line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
690 h = s->vram_size / line_offset;
691 /* XXX: support weird bochs semantics ? */
692 if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
694 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
695 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
696 s->vbe_line_offset = line_offset;
698 vga_update_resolution(s);
700 case VBE_DISPI_INDEX_X_OFFSET:
701 case VBE_DISPI_INDEX_Y_OFFSET:
704 s->vbe_regs[s->vbe_index] = val;
705 s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
706 x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
707 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
708 s->vbe_start_addr += x >> 1;
710 s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
711 s->vbe_start_addr >>= 2;
713 vga_update_resolution(s);
722 /* called for accesses between 0xa0000 and 0xc0000 */
723 uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
725 VGAState *s = opaque;
726 int memory_map_mode, plane;
729 /* convert to VGA memory offset */
730 memory_map_mode = (s->gr[6] >> 2) & 3;
732 switch(memory_map_mode) {
738 addr += s->bank_offset;
753 if (s->sr[4] & 0x08) {
754 /* chain 4 mode : simplest access */
755 ret = s->vram_ptr[addr];
756 } else if (s->gr[5] & 0x10) {
757 /* odd/even mode (aka text mode mapping) */
758 plane = (s->gr[4] & 2) | (addr & 1);
759 ret = s->vram_ptr[((addr & ~1) << 1) | plane];
761 /* standard VGA latched access */
762 s->latch = ((uint32_t *)s->vram_ptr)[addr];
764 if (!(s->gr[5] & 0x08)) {
767 ret = GET_PLANE(s->latch, plane);
770 ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
779 static uint32_t vga_mem_readw(void *opaque, target_phys_addr_t addr)
782 #ifdef TARGET_WORDS_BIGENDIAN
783 v = vga_mem_readb(opaque, addr) << 8;
784 v |= vga_mem_readb(opaque, addr + 1);
786 v = vga_mem_readb(opaque, addr);
787 v |= vga_mem_readb(opaque, addr + 1) << 8;
792 static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr)
795 #ifdef TARGET_WORDS_BIGENDIAN
796 v = vga_mem_readb(opaque, addr) << 24;
797 v |= vga_mem_readb(opaque, addr + 1) << 16;
798 v |= vga_mem_readb(opaque, addr + 2) << 8;
799 v |= vga_mem_readb(opaque, addr + 3);
801 v = vga_mem_readb(opaque, addr);
802 v |= vga_mem_readb(opaque, addr + 1) << 8;
803 v |= vga_mem_readb(opaque, addr + 2) << 16;
804 v |= vga_mem_readb(opaque, addr + 3) << 24;
809 /* called for accesses between 0xa0000 and 0xc0000 */
810 void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
812 VGAState *s = opaque;
813 int memory_map_mode, plane, write_mode, b, func_select, mask;
814 uint32_t write_mask, bit_mask, set_mask;
817 printf("vga: [0x%x] = 0x%02x\n", addr, val);
819 /* convert to VGA memory offset */
820 memory_map_mode = (s->gr[6] >> 2) & 3;
822 switch(memory_map_mode) {
828 addr += s->bank_offset;
843 if (s->sr[4] & 0x08) {
844 /* chain 4 mode : simplest access */
847 if (s->sr[2] & mask) {
848 s->vram_ptr[addr] = val;
850 printf("vga: chain4: [0x%x]\n", addr);
852 s->plane_updated |= mask; /* only used to detect font change */
853 cpu_physical_memory_set_dirty(s->vram_offset + addr);
855 } else if (s->gr[5] & 0x10) {
856 /* odd/even mode (aka text mode mapping) */
857 plane = (s->gr[4] & 2) | (addr & 1);
859 if (s->sr[2] & mask) {
860 addr = ((addr & ~1) << 1) | plane;
861 s->vram_ptr[addr] = val;
863 printf("vga: odd/even: [0x%x]\n", addr);
865 s->plane_updated |= mask; /* only used to detect font change */
866 cpu_physical_memory_set_dirty(s->vram_offset + addr);
869 /* standard VGA latched access */
870 write_mode = s->gr[5] & 3;
876 val = ((val >> b) | (val << (8 - b))) & 0xff;
880 /* apply set/reset mask */
881 set_mask = mask16[s->gr[1]];
882 val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
889 val = mask16[val & 0x0f];
895 val = (val >> b) | (val << (8 - b));
897 bit_mask = s->gr[8] & val;
898 val = mask16[s->gr[0]];
902 /* apply logical operation */
903 func_select = s->gr[3] >> 3;
904 switch(func_select) {
924 bit_mask |= bit_mask << 8;
925 bit_mask |= bit_mask << 16;
926 val = (val & bit_mask) | (s->latch & ~bit_mask);
929 /* mask data according to sr[2] */
931 s->plane_updated |= mask; /* only used to detect font change */
932 write_mask = mask16[mask];
933 ((uint32_t *)s->vram_ptr)[addr] =
934 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
937 printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
938 addr * 4, write_mask, val);
940 cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
944 static void vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
946 #ifdef TARGET_WORDS_BIGENDIAN
947 vga_mem_writeb(opaque, addr, (val >> 8) & 0xff);
948 vga_mem_writeb(opaque, addr + 1, val & 0xff);
950 vga_mem_writeb(opaque, addr, val & 0xff);
951 vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
955 static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
957 #ifdef TARGET_WORDS_BIGENDIAN
958 vga_mem_writeb(opaque, addr, (val >> 24) & 0xff);
959 vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
960 vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
961 vga_mem_writeb(opaque, addr + 3, val & 0xff);
963 vga_mem_writeb(opaque, addr, val & 0xff);
964 vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
965 vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
966 vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
970 typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
971 const uint8_t *font_ptr, int h,
972 uint32_t fgcol, uint32_t bgcol);
973 typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
974 const uint8_t *font_ptr, int h,
975 uint32_t fgcol, uint32_t bgcol, int dup9);
976 typedef void vga_draw_line_func(VGAState *s1, uint8_t *d,
977 const uint8_t *s, int width);
980 #include "vga_template.h"
983 #include "vga_template.h"
987 #include "vga_template.h"
990 #include "vga_template.h"
994 #include "vga_template.h"
997 #include "vga_template.h"
1001 #include "vga_template.h"
1003 static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
1006 col = rgb_to_pixel8(r, g, b);
1012 static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
1015 col = rgb_to_pixel15(r, g, b);
1020 static unsigned int rgb_to_pixel15bgr_dup(unsigned int r, unsigned int g,
1024 col = rgb_to_pixel15bgr(r, g, b);
1029 static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
1032 col = rgb_to_pixel16(r, g, b);
1037 static unsigned int rgb_to_pixel16bgr_dup(unsigned int r, unsigned int g,
1041 col = rgb_to_pixel16bgr(r, g, b);
1046 static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
1049 col = rgb_to_pixel32(r, g, b);
1053 static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b)
1056 col = rgb_to_pixel32bgr(r, g, b);
1060 /* return true if the palette was modified */
1061 static int update_palette16(VGAState *s)
1064 uint32_t v, col, *palette;
1067 palette = s->last_palette;
1068 for(i = 0; i < 16; i++) {
1070 if (s->ar[0x10] & 0x80)
1071 v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
1073 v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
1075 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1076 c6_to_8(s->palette[v + 1]),
1077 c6_to_8(s->palette[v + 2]));
1078 if (col != palette[i]) {
1086 /* return true if the palette was modified */
1087 static int update_palette256(VGAState *s)
1090 uint32_t v, col, *palette;
1093 palette = s->last_palette;
1095 for(i = 0; i < 256; i++) {
1097 col = s->rgb_to_pixel(s->palette[v],
1101 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1102 c6_to_8(s->palette[v + 1]),
1103 c6_to_8(s->palette[v + 2]));
1105 if (col != palette[i]) {
1114 static void vga_get_offsets(VGAState *s,
1115 uint32_t *pline_offset,
1116 uint32_t *pstart_addr,
1117 uint32_t *pline_compare)
1119 uint32_t start_addr, line_offset, line_compare;
1120 #ifdef CONFIG_BOCHS_VBE
1121 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1122 line_offset = s->vbe_line_offset;
1123 start_addr = s->vbe_start_addr;
1124 line_compare = 65535;
1128 /* compute line_offset in bytes */
1129 line_offset = s->cr[0x13];
1132 /* starting address */
1133 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
1136 line_compare = s->cr[0x18] |
1137 ((s->cr[0x07] & 0x10) << 4) |
1138 ((s->cr[0x09] & 0x40) << 3);
1140 *pline_offset = line_offset;
1141 *pstart_addr = start_addr;
1142 *pline_compare = line_compare;
1145 /* update start_addr and line_offset. Return TRUE if modified */
1146 static int update_basic_params(VGAState *s)
1149 uint32_t start_addr, line_offset, line_compare;
1153 s->get_offsets(s, &line_offset, &start_addr, &line_compare);
1155 if (line_offset != s->line_offset ||
1156 start_addr != s->start_addr ||
1157 line_compare != s->line_compare) {
1158 s->line_offset = line_offset;
1159 s->start_addr = start_addr;
1160 s->line_compare = line_compare;
1168 static inline int get_depth_index(DisplayState *s)
1170 switch(ds_get_bits_per_pixel(s)) {
1179 if (is_surface_bgr(s->surface))
1186 static vga_draw_glyph8_func *vga_draw_glyph8_table[NB_DEPTHS] = {
1196 static vga_draw_glyph8_func *vga_draw_glyph16_table[NB_DEPTHS] = {
1198 vga_draw_glyph16_16,
1199 vga_draw_glyph16_16,
1200 vga_draw_glyph16_32,
1201 vga_draw_glyph16_32,
1202 vga_draw_glyph16_16,
1203 vga_draw_glyph16_16,
1206 static vga_draw_glyph9_func *vga_draw_glyph9_table[NB_DEPTHS] = {
1216 static const uint8_t cursor_glyph[32 * 4] = {
1217 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1218 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1219 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1220 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1221 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1222 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1223 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1224 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1225 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1226 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1227 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1228 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1229 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1230 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1231 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1232 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1235 static void vga_get_text_resolution(VGAState *s, int *pwidth, int *pheight,
1236 int *pcwidth, int *pcheight)
1238 int width, cwidth, height, cheight;
1240 /* total width & height */
1241 cheight = (s->cr[9] & 0x1f) + 1;
1243 if (!(s->sr[1] & 0x01))
1245 if (s->sr[1] & 0x08)
1246 cwidth = 16; /* NOTE: no 18 pixel wide */
1247 width = (s->cr[0x01] + 1);
1248 if (s->cr[0x06] == 100) {
1249 /* ugly hack for CGA 160x100x16 - explain me the logic */
1252 height = s->cr[0x12] |
1253 ((s->cr[0x07] & 0x02) << 7) |
1254 ((s->cr[0x07] & 0x40) << 3);
1255 height = (height + 1) / cheight;
1261 *pcheight = cheight;
1264 typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
1266 static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS] = {
1271 rgb_to_pixel32bgr_dup,
1272 rgb_to_pixel15bgr_dup,
1273 rgb_to_pixel16bgr_dup,
1284 static void vga_draw_text(VGAState *s, int full_update)
1286 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1287 int cx_min, cx_max, linesize, x_incr;
1288 uint32_t offset, fgcol, bgcol, v, cursor_offset;
1289 uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
1290 const uint8_t *font_ptr, *font_base[2];
1291 int dup9, line_offset, depth_index;
1293 uint32_t *ch_attr_ptr;
1294 vga_draw_glyph8_func *vga_draw_glyph8;
1295 vga_draw_glyph9_func *vga_draw_glyph9;
1297 vga_dirty_log_stop(s);
1299 /* compute font data address (in plane 2) */
1301 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1302 if (offset != s->font_offsets[0]) {
1303 s->font_offsets[0] = offset;
1306 font_base[0] = s->vram_ptr + offset;
1308 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1309 font_base[1] = s->vram_ptr + offset;
1310 if (offset != s->font_offsets[1]) {
1311 s->font_offsets[1] = offset;
1314 if (s->plane_updated & (1 << 2)) {
1315 /* if the plane 2 was modified since the last display, it
1316 indicates the font may have been modified */
1317 s->plane_updated = 0;
1321 line_offset = s->line_offset;
1322 s1 = s->vram_ptr + (s->start_addr * 4);
1324 vga_get_text_resolution(s, &width, &height, &cw, &cheight);
1325 x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1326 if ((height * width) > CH_ATTR_SIZE) {
1327 /* better than nothing: exit if transient size is too big */
1332 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1333 full_update |= update_palette16(s);
1334 palette = s->last_palette;
1335 x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1337 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1338 if (cursor_offset != s->cursor_offset ||
1339 s->cr[0xa] != s->cursor_start ||
1340 s->cr[0xb] != s->cursor_end) {
1341 /* if the cursor position changed, we update the old and new
1343 if (s->cursor_offset < CH_ATTR_SIZE)
1344 s->last_ch_attr[s->cursor_offset] = -1;
1345 if (cursor_offset < CH_ATTR_SIZE)
1346 s->last_ch_attr[cursor_offset] = -1;
1347 s->cursor_offset = cursor_offset;
1348 s->cursor_start = s->cr[0xa];
1349 s->cursor_end = s->cr[0xb];
1351 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
1353 depth_index = get_depth_index(s->ds);
1355 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1357 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
1358 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1360 dest = ds_get_data(s->ds);
1361 linesize = ds_get_linesize(s->ds);
1362 ch_attr_ptr = s->last_ch_attr;
1363 for(cy = 0; cy < height; cy++) {
1368 for(cx = 0; cx < width; cx++) {
1369 ch_attr = *(uint16_t *)src;
1370 if (full_update || ch_attr != *ch_attr_ptr) {
1375 *ch_attr_ptr = ch_attr;
1376 #ifdef WORDS_BIGENDIAN
1378 cattr = ch_attr & 0xff;
1380 ch = ch_attr & 0xff;
1381 cattr = ch_attr >> 8;
1383 font_ptr = font_base[(cattr >> 3) & 1];
1384 font_ptr += 32 * 4 * ch;
1385 bgcol = palette[cattr >> 4];
1386 fgcol = palette[cattr & 0x0f];
1388 vga_draw_glyph8(d1, linesize,
1389 font_ptr, cheight, fgcol, bgcol);
1392 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1394 vga_draw_glyph9(d1, linesize,
1395 font_ptr, cheight, fgcol, bgcol, dup9);
1397 if (src == cursor_ptr &&
1398 !(s->cr[0x0a] & 0x20)) {
1399 int line_start, line_last, h;
1400 /* draw the cursor */
1401 line_start = s->cr[0x0a] & 0x1f;
1402 line_last = s->cr[0x0b] & 0x1f;
1403 /* XXX: check that */
1404 if (line_last > cheight - 1)
1405 line_last = cheight - 1;
1406 if (line_last >= line_start && line_start < cheight) {
1407 h = line_last - line_start + 1;
1408 d = d1 + linesize * line_start;
1410 vga_draw_glyph8(d, linesize,
1411 cursor_glyph, h, fgcol, bgcol);
1413 vga_draw_glyph9(d, linesize,
1414 cursor_glyph, h, fgcol, bgcol, 1);
1424 dpy_update(s->ds, cx_min * cw, cy * cheight,
1425 (cx_max - cx_min + 1) * cw, cheight);
1427 dest += linesize * cheight;
1446 static vga_draw_line_func *vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
1456 vga_draw_line2d2_16,
1457 vga_draw_line2d2_16,
1458 vga_draw_line2d2_32,
1459 vga_draw_line2d2_32,
1460 vga_draw_line2d2_16,
1461 vga_draw_line2d2_16,
1472 vga_draw_line4d2_16,
1473 vga_draw_line4d2_16,
1474 vga_draw_line4d2_32,
1475 vga_draw_line4d2_32,
1476 vga_draw_line4d2_16,
1477 vga_draw_line4d2_16,
1480 vga_draw_line8d2_16,
1481 vga_draw_line8d2_16,
1482 vga_draw_line8d2_32,
1483 vga_draw_line8d2_32,
1484 vga_draw_line8d2_16,
1485 vga_draw_line8d2_16,
1499 vga_draw_line15_32bgr,
1500 vga_draw_line15_15bgr,
1501 vga_draw_line15_16bgr,
1507 vga_draw_line16_32bgr,
1508 vga_draw_line16_15bgr,
1509 vga_draw_line16_16bgr,
1515 vga_draw_line24_32bgr,
1516 vga_draw_line24_15bgr,
1517 vga_draw_line24_16bgr,
1523 vga_draw_line32_32bgr,
1524 vga_draw_line32_15bgr,
1525 vga_draw_line32_16bgr,
1528 static int vga_get_bpp(VGAState *s)
1531 #ifdef CONFIG_BOCHS_VBE
1532 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1533 ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
1542 static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight)
1546 #ifdef CONFIG_BOCHS_VBE
1547 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1548 width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
1549 height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
1553 width = (s->cr[0x01] + 1) * 8;
1554 height = s->cr[0x12] |
1555 ((s->cr[0x07] & 0x02) << 7) |
1556 ((s->cr[0x07] & 0x40) << 3);
1557 height = (height + 1);
1563 void vga_invalidate_scanlines(VGAState *s, int y1, int y2)
1566 if (y1 >= VGA_MAX_HEIGHT)
1568 if (y2 >= VGA_MAX_HEIGHT)
1569 y2 = VGA_MAX_HEIGHT;
1570 for(y = y1; y < y2; y++) {
1571 s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1575 static void vga_sync_dirty_bitmap(VGAState *s)
1578 cpu_physical_sync_dirty_bitmap(s->map_addr, s->map_end);
1580 if (s->lfb_vram_mapped) {
1581 cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa0000, 0xa8000);
1582 cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa8000, 0xb0000);
1584 vga_dirty_log_start(s);
1587 static void vga_update_resolution_graphics(VGAState *s)
1589 int depth = s->get_bpp(s);
1590 int width, height, shift_control, double_scan;
1591 int disp_width, multi_scan, multi_run;
1593 s->get_resolution(s, &width, &height);
1596 shift_control = (s->gr[0x05] >> 5) & 3;
1597 double_scan = (s->cr[0x09] >> 7);
1599 if (shift_control != s->shift_control ||
1600 double_scan != s->double_scan) {
1601 s->want_full_update = 1;
1602 s->shift_control = shift_control;
1603 s->double_scan = double_scan;
1606 if (shift_control == 0) {
1607 if (s->sr[0x01] & 8) {
1610 } else if (shift_control == 1) {
1611 if (s->sr[0x01] & 8) {
1617 if (shift_control != 1) {
1618 multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
1620 /* in CGA modes, multi_scan is ignored */
1621 /* XXX: is it correct ? */
1622 multi_scan = double_scan;
1625 multi_run = multi_scan;
1627 if (s->line_offset != s->last_line_offset ||
1628 disp_width != s->last_width ||
1629 height != s->last_height ||
1630 s->last_depth != depth ||
1631 s->multi_run != multi_run ||
1632 s->multi_scan != multi_scan ||
1633 s->want_full_update) {
1634 if (s->ds->surface->pf.depth == 0) {
1635 goto dont_touch_display_surface;
1637 #if defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
1638 if (depth == 16 || depth == 32) {
1642 qemu_free_displaysurface(s->ds);
1643 s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth,
1645 s->vram_ptr + (s->start_addr * 4));
1646 #if defined(WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
1647 s->ds->surface->pf = qemu_different_endianness_pixelformat(depth);
1651 qemu_console_resize(s->ds, disp_width, height);
1653 dont_touch_display_surface:
1654 s->last_scr_width = disp_width;
1655 s->last_scr_height = height;
1656 s->last_width = disp_width;
1657 s->last_height = height;
1658 s->last_line_offset = s->line_offset;
1659 s->last_depth = depth;
1660 s->multi_run = multi_run;
1661 s->multi_scan = multi_scan;
1662 s->want_full_update = 1;
1666 static void vga_update_resolution_text(VGAState *s)
1668 int width, height, cw, cheight;
1670 vga_get_text_resolution(s, &width, &height, &cw, &cheight);
1671 if (width != s->last_width || height != s->last_height ||
1672 cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
1673 s->last_scr_width = width * cw;
1674 s->last_scr_height = height * cheight;
1675 if (s->ds->surface->pf.depth != 0) {
1676 qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height);
1679 * curses expects width and height to be in character cell
1680 * dimensions, not pixels.
1682 s->ds->surface->width = width;
1683 s->ds->surface->height = height;
1687 s->last_width = width;
1688 s->last_height = height;
1689 s->last_ch = cheight;
1691 s->want_full_update = 1;
1695 void vga_update_resolution(VGAState *s)
1699 if (!(s->ar_index & 0x20)) {
1700 graphic_mode = GMODE_BLANK;
1702 graphic_mode = s->gr[6] & 1;
1704 if (graphic_mode != s->graphic_mode) {
1705 s->graphic_mode = graphic_mode;
1706 s->want_full_update = 1;
1708 s->want_full_update |= update_basic_params(s);
1709 switch (graphic_mode) {
1711 vga_update_resolution_text(s);
1714 vga_update_resolution_graphics(s);
1722 static void vga_draw_graphic(VGAState *s, int full_update)
1724 int y1, y, update, linesize, y_start, mask;
1725 int width, height, line_offset, bwidth, bits;
1728 uint32_t v, addr1, addr;
1729 long page0, page1, page_min, page_max;
1730 vga_draw_line_func *vga_draw_line;
1733 vga_sync_dirty_bitmap(s);
1735 s->get_resolution(s, &width, &height);
1736 multi_run = s->multi_run;
1737 if (is_buffer_shared(s->ds->surface) &&
1738 (full_update || s->ds->surface->data != s->vram_ptr + (s->start_addr * 4))) {
1739 s->ds->surface->data = s->vram_ptr + (s->start_addr * 4);
1744 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1746 if (s->shift_control == 0) {
1747 full_update |= update_palette16(s);
1748 if (s->sr[0x01] & 8) {
1749 v = VGA_DRAW_LINE4D2;
1754 } else if (s->shift_control == 1) {
1755 full_update |= update_palette16(s);
1756 if (s->sr[0x01] & 8) {
1757 v = VGA_DRAW_LINE2D2;
1763 switch(s->get_bpp(s)) {
1766 full_update |= update_palette256(s);
1767 v = VGA_DRAW_LINE8D2;
1771 full_update |= update_palette256(s);
1776 v = VGA_DRAW_LINE15;
1780 v = VGA_DRAW_LINE16;
1784 v = VGA_DRAW_LINE24;
1788 v = VGA_DRAW_LINE32;
1793 vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
1795 if (!is_buffer_shared(s->ds->surface) && s->cursor_invalidate)
1796 s->cursor_invalidate(s);
1798 line_offset = s->line_offset;
1800 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",
1801 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1803 addr1 = (s->start_addr * 4);
1804 bwidth = (width * bits + 7) / 8;
1806 page_min = 0x7fffffff;
1808 d = ds_get_data(s->ds);
1809 linesize = ds_get_linesize(s->ds);
1811 for(y = 0; y < height; y++) {
1813 if (!(s->cr[0x17] & 1)) {
1815 /* CGA compatibility handling */
1816 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1817 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1819 if (!(s->cr[0x17] & 2)) {
1820 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1822 page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
1823 page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
1824 update = full_update |
1825 cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
1826 cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
1827 if ((page1 - page0) > TARGET_PAGE_SIZE) {
1828 /* if wide line, can use another page */
1829 update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE,
1832 /* explicit invalidation for the hardware cursor */
1833 update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
1837 if (page0 < page_min)
1839 if (page1 > page_max)
1841 if (!(is_buffer_shared(s->ds->surface))) {
1842 vga_draw_line(s, d, s->vram_ptr + addr, width);
1843 if (s->cursor_draw_line)
1844 s->cursor_draw_line(s, d, y);
1848 /* flush to display */
1849 dpy_update(s->ds, 0, y_start,
1850 s->last_width, y - y_start);
1855 mask = (s->cr[0x17] & 3) ^ 3;
1856 if ((y1 & mask) == mask)
1857 addr1 += line_offset;
1859 multi_run = s->multi_scan;
1863 /* line compare acts on the displayed lines */
1864 if (y == s->line_compare)
1869 /* flush to display */
1870 dpy_update(s->ds, 0, y_start,
1871 s->last_width, y - y_start);
1873 /* reset modified pages */
1874 if (page_max != -1) {
1875 cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
1878 memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
1881 static void vga_draw_blank(VGAState *s, int full_update)
1888 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1890 vga_dirty_log_stop(s);
1893 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1894 if (ds_get_bits_per_pixel(s->ds) == 8)
1895 val = s->rgb_to_pixel(0, 0, 0);
1898 w = s->last_scr_width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1899 d = ds_get_data(s->ds);
1900 for(i = 0; i < s->last_scr_height; i++) {
1902 d += ds_get_linesize(s->ds);
1904 dpy_update(s->ds, 0, 0,
1905 s->last_scr_width, s->last_scr_height);
1908 static void vga_update_display(void *opaque)
1910 VGAState *s = (VGAState *)opaque;
1913 if (ds_get_bits_per_pixel(s->ds) == 0) {
1916 full_update = s->want_full_update;
1917 s->want_full_update = 0;
1918 switch(s->graphic_mode) {
1920 vga_draw_text(s, full_update);
1923 vga_draw_graphic(s, full_update);
1927 vga_draw_blank(s, full_update);
1933 /* force a full display refresh */
1934 static void vga_invalidate_display(void *opaque)
1936 VGAState *s = (VGAState *)opaque;
1938 vga_update_resolution(s);
1939 s->want_full_update = 1;
1942 void vga_reset(void *opaque)
1944 VGAState *s = (VGAState *) opaque;
1950 s->lfb_vram_mapped = 0;
1954 memset(s->sr, '\0', sizeof(s->sr));
1956 memset(s->gr, '\0', sizeof(s->gr));
1958 memset(s->ar, '\0', sizeof(s->ar));
1959 s->ar_flip_flop = 0;
1961 memset(s->cr, '\0', sizeof(s->cr));
1967 s->dac_sub_index = 0;
1968 s->dac_read_index = 0;
1969 s->dac_write_index = 0;
1970 memset(s->dac_cache, '\0', sizeof(s->dac_cache));
1972 memset(s->palette, '\0', sizeof(s->palette));
1974 #ifdef CONFIG_BOCHS_VBE
1976 memset(s->vbe_regs, '\0', sizeof(s->vbe_regs));
1977 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
1978 s->vbe_start_addr = 0;
1979 s->vbe_line_offset = 0;
1980 s->vbe_bank_mask = (s->vram_size >> 16) - 1;
1982 memset(s->font_offsets, '\0', sizeof(s->font_offsets));
1983 s->shift_control = 0;
1986 s->line_compare = 0;
1988 s->plane_updated = 0;
1993 s->last_scr_width = 0;
1994 s->last_scr_height = 0;
1995 s->cursor_start = 0;
1997 s->cursor_offset = 0;
1998 memset(s->invalidated_y_table, '\0', sizeof(s->invalidated_y_table));
1999 memset(s->last_palette, '\0', sizeof(s->last_palette));
2000 memset(s->last_ch_attr, '\0', sizeof(s->last_ch_attr));
2001 switch (vga_retrace_method) {
2002 case VGA_RETRACE_DUMB:
2004 case VGA_RETRACE_PRECISE:
2005 memset(&s->retrace_info, 0, sizeof (s->retrace_info));
2008 vga_update_resolution(s);
2011 #define TEXTMODE_X(x) ((x) % width)
2012 #define TEXTMODE_Y(x) ((x) / width)
2013 #define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
2014 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
2015 /* relay text rendering to the display driver
2016 * instead of doing a full vga_update_display() */
2017 static void vga_update_text(void *opaque, console_ch_t *chardata)
2019 VGAState *s = (VGAState *) opaque;
2020 int i, cursor_offset, cursor_visible;
2021 int cw, cheight, width, height, size, c_min, c_max;
2023 console_ch_t *dst, val;
2024 char msg_buffer[80];
2025 int full_update = s->want_full_update;
2027 s->want_full_update = 0;
2028 switch (s->graphic_mode) {
2030 /* TODO: update palette */
2032 vga_get_text_resolution(s, &width, &height, &cw, &cheight);
2034 if (s->ds->surface->width != width
2035 || s->ds->surface->height != height) {
2036 s->ds->surface->width = width;
2037 s->ds->surface->height = height;
2041 /* total width & height */
2042 size = (height * width);
2043 if (size > CH_ATTR_SIZE) {
2047 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
2052 /* Update "hardware" cursor */
2053 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
2054 if (cursor_offset != s->cursor_offset ||
2055 s->cr[0xa] != s->cursor_start ||
2056 s->cr[0xb] != s->cursor_end || full_update) {
2057 cursor_visible = !(s->cr[0xa] & 0x20);
2058 if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
2060 TEXTMODE_X(cursor_offset),
2061 TEXTMODE_Y(cursor_offset));
2063 dpy_cursor(s->ds, -1, -1);
2064 s->cursor_offset = cursor_offset;
2065 s->cursor_start = s->cr[0xa];
2066 s->cursor_end = s->cr[0xb];
2069 src = (uint32_t *) s->vram_ptr + s->start_addr;
2073 for (i = 0; i < size; src ++, dst ++, i ++)
2074 console_write_ch(dst, VMEM2CHTYPE(*src));
2076 dpy_update(s->ds, 0, 0, width, height);
2080 for (i = 0; i < size; src ++, dst ++, i ++) {
2081 console_write_ch(&val, VMEM2CHTYPE(*src));
2089 for (; i < size; src ++, dst ++, i ++) {
2090 console_write_ch(&val, VMEM2CHTYPE(*src));
2097 if (c_min <= c_max) {
2098 i = TEXTMODE_Y(c_min);
2099 dpy_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
2108 s->get_resolution(s, &width, &height);
2109 snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
2117 snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
2121 /* Display a message */
2123 s->last_height = height = 3;
2124 dpy_cursor(s->ds, -1, -1);
2125 s->ds->surface->width = s->last_width;
2126 s->ds->surface->height = height;
2129 for (dst = chardata, i = 0; i < s->last_width * height; i ++)
2130 console_write_ch(dst ++, ' ');
2132 size = strlen(msg_buffer);
2133 width = (s->last_width - size) / 2;
2134 dst = chardata + s->last_width + width;
2135 for (i = 0; i < size; i ++)
2136 console_write_ch(dst ++, 0x00200100 | msg_buffer[i]);
2138 dpy_update(s->ds, 0, 0, s->last_width, height);
2141 static CPUReadMemoryFunc *vga_mem_read[3] = {
2147 static CPUWriteMemoryFunc *vga_mem_write[3] = {
2153 static void vga_save(QEMUFile *f, void *opaque)
2155 VGAState *s = opaque;
2159 pci_device_save(s->pci_dev, f);
2161 qemu_put_be32s(f, &s->latch);
2162 qemu_put_8s(f, &s->sr_index);
2163 qemu_put_buffer(f, s->sr, 8);
2164 qemu_put_8s(f, &s->gr_index);
2165 qemu_put_buffer(f, s->gr, 16);
2166 qemu_put_8s(f, &s->ar_index);
2167 qemu_put_buffer(f, s->ar, 21);
2168 qemu_put_be32(f, s->ar_flip_flop);
2169 qemu_put_8s(f, &s->cr_index);
2170 qemu_put_buffer(f, s->cr, 256);
2171 qemu_put_8s(f, &s->msr);
2172 qemu_put_8s(f, &s->fcr);
2173 qemu_put_byte(f, s->st00);
2174 qemu_put_8s(f, &s->st01);
2176 qemu_put_8s(f, &s->dac_state);
2177 qemu_put_8s(f, &s->dac_sub_index);
2178 qemu_put_8s(f, &s->dac_read_index);
2179 qemu_put_8s(f, &s->dac_write_index);
2180 qemu_put_buffer(f, s->dac_cache, 3);
2181 qemu_put_buffer(f, s->palette, 768);
2183 qemu_put_be32(f, s->bank_offset);
2184 #ifdef CONFIG_BOCHS_VBE
2185 qemu_put_byte(f, 1);
2186 qemu_put_be16s(f, &s->vbe_index);
2187 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
2188 qemu_put_be16s(f, &s->vbe_regs[i]);
2189 qemu_put_be32s(f, &s->vbe_start_addr);
2190 qemu_put_be32s(f, &s->vbe_line_offset);
2191 qemu_put_be32s(f, &s->vbe_bank_mask);
2193 qemu_put_byte(f, 0);
2197 static int vga_load(QEMUFile *f, void *opaque, int version_id)
2199 VGAState *s = opaque;
2205 if (s->pci_dev && version_id >= 2) {
2206 ret = pci_device_load(s->pci_dev, f);
2211 qemu_get_be32s(f, &s->latch);
2212 qemu_get_8s(f, &s->sr_index);
2213 qemu_get_buffer(f, s->sr, 8);
2214 qemu_get_8s(f, &s->gr_index);
2215 qemu_get_buffer(f, s->gr, 16);
2216 qemu_get_8s(f, &s->ar_index);
2217 qemu_get_buffer(f, s->ar, 21);
2218 s->ar_flip_flop=qemu_get_be32(f);
2219 qemu_get_8s(f, &s->cr_index);
2220 qemu_get_buffer(f, s->cr, 256);
2221 qemu_get_8s(f, &s->msr);
2222 qemu_get_8s(f, &s->fcr);
2223 qemu_get_8s(f, &s->st00);
2224 qemu_get_8s(f, &s->st01);
2226 qemu_get_8s(f, &s->dac_state);
2227 qemu_get_8s(f, &s->dac_sub_index);
2228 qemu_get_8s(f, &s->dac_read_index);
2229 qemu_get_8s(f, &s->dac_write_index);
2230 qemu_get_buffer(f, s->dac_cache, 3);
2231 qemu_get_buffer(f, s->palette, 768);
2233 s->bank_offset=qemu_get_be32(f);
2234 is_vbe = qemu_get_byte(f);
2235 #ifdef CONFIG_BOCHS_VBE
2238 qemu_get_be16s(f, &s->vbe_index);
2239 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
2240 qemu_get_be16s(f, &s->vbe_regs[i]);
2241 qemu_get_be32s(f, &s->vbe_start_addr);
2242 qemu_get_be32s(f, &s->vbe_line_offset);
2243 qemu_get_be32s(f, &s->vbe_bank_mask);
2250 vga_update_resolution(s);
2251 s->want_full_update = 1;
2255 typedef struct PCIVGAState {
2260 void vga_dirty_log_start(VGAState *s)
2262 if (kvm_enabled() && s->map_addr)
2263 kvm_log_start(s->map_addr, s->map_end - s->map_addr);
2265 if (kvm_enabled() && s->lfb_vram_mapped) {
2266 kvm_log_start(isa_mem_base + 0xa0000, 0x8000);
2267 kvm_log_start(isa_mem_base + 0xa8000, 0x8000);
2271 void vga_dirty_log_stop(VGAState *s)
2273 if (kvm_enabled() && s->map_addr)
2274 kvm_log_stop(s->map_addr, s->map_end - s->map_addr);
2276 if (kvm_enabled() && s->lfb_vram_mapped) {
2277 kvm_log_stop(isa_mem_base + 0xa0000, 0x8000);
2278 kvm_log_stop(isa_mem_base + 0xa8000, 0x8000);
2282 static void vga_map(PCIDevice *pci_dev, int region_num,
2283 uint32_t addr, uint32_t size, int type)
2285 PCIVGAState *d = (PCIVGAState *)pci_dev;
2286 VGAState *s = &d->vga_state;
2287 if (region_num == PCI_ROM_SLOT) {
2288 cpu_register_physical_memory(addr, s->bios_size, s->bios_offset);
2290 cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
2294 s->map_end = addr + VGA_RAM_SIZE;
2296 vga_dirty_log_start(s);
2299 void vga_common_init(VGAState *s, uint8_t *vga_ram_base,
2300 ram_addr_t vga_ram_offset, int vga_ram_size)
2304 for(i = 0;i < 256; i++) {
2306 for(j = 0; j < 8; j++) {
2307 v |= ((i >> j) & 1) << (j * 4);
2312 for(j = 0; j < 4; j++) {
2313 v |= ((i >> (2 * j)) & 3) << (j * 4);
2317 for(i = 0; i < 16; i++) {
2319 for(j = 0; j < 4; j++) {
2322 v |= b << (2 * j + 1);
2327 s->vram_ptr = vga_ram_base;
2328 s->vram_offset = vga_ram_offset;
2329 s->vram_size = vga_ram_size;
2330 s->get_bpp = vga_get_bpp;
2331 s->get_offsets = vga_get_offsets;
2332 s->get_resolution = vga_get_resolution;
2333 s->update = vga_update_display;
2334 s->invalidate = vga_invalidate_display;
2335 s->screen_dump = vga_screen_dump;
2336 s->text_update = vga_update_text;
2337 switch (vga_retrace_method) {
2338 case VGA_RETRACE_DUMB:
2339 s->retrace = vga_dumb_retrace;
2340 s->update_retrace_info = vga_dumb_update_retrace_info;
2343 case VGA_RETRACE_PRECISE:
2344 s->retrace = vga_precise_retrace;
2345 s->update_retrace_info = vga_precise_update_retrace_info;
2351 /* used by both ISA and PCI */
2352 void vga_init(VGAState *s)
2356 qemu_register_reset(vga_reset, s);
2357 register_savevm("vga", 0, 2, vga_save, vga_load, s);
2359 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
2361 register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
2362 register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
2363 register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
2364 register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
2366 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
2368 register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
2369 register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
2370 register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
2371 register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
2374 #ifdef CONFIG_BOCHS_VBE
2375 #if defined (TARGET_I386)
2376 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2377 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
2379 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2380 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
2382 /* old Bochs IO ports */
2383 register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
2384 register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
2386 register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
2387 register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s);
2389 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2390 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
2392 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2393 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
2395 #endif /* CONFIG_BOCHS_VBE */
2397 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
2398 cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
2400 qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000);
2403 /* Memory mapped interface */
2404 static uint32_t vga_mm_readb (void *opaque, target_phys_addr_t addr)
2406 VGAState *s = opaque;
2408 return vga_ioport_read(s, addr >> s->it_shift) & 0xff;
2411 static void vga_mm_writeb (void *opaque,
2412 target_phys_addr_t addr, uint32_t value)
2414 VGAState *s = opaque;
2416 vga_ioport_write(s, addr >> s->it_shift, value & 0xff);
2419 static uint32_t vga_mm_readw (void *opaque, target_phys_addr_t addr)
2421 VGAState *s = opaque;
2423 return vga_ioport_read(s, addr >> s->it_shift) & 0xffff;
2426 static void vga_mm_writew (void *opaque,
2427 target_phys_addr_t addr, uint32_t value)
2429 VGAState *s = opaque;
2431 vga_ioport_write(s, addr >> s->it_shift, value & 0xffff);
2434 static uint32_t vga_mm_readl (void *opaque, target_phys_addr_t addr)
2436 VGAState *s = opaque;
2438 return vga_ioport_read(s, addr >> s->it_shift);
2441 static void vga_mm_writel (void *opaque,
2442 target_phys_addr_t addr, uint32_t value)
2444 VGAState *s = opaque;
2446 vga_ioport_write(s, addr >> s->it_shift, value);
2449 static CPUReadMemoryFunc *vga_mm_read_ctrl[] = {
2455 static CPUWriteMemoryFunc *vga_mm_write_ctrl[] = {
2461 static void vga_mm_init(VGAState *s, target_phys_addr_t vram_base,
2462 target_phys_addr_t ctrl_base, int it_shift)
2464 int s_ioport_ctrl, vga_io_memory;
2466 s->it_shift = it_shift;
2467 s_ioport_ctrl = cpu_register_io_memory(0, vga_mm_read_ctrl, vga_mm_write_ctrl, s);
2468 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
2470 register_savevm("vga", 0, 2, vga_save, vga_load, s);
2472 cpu_register_physical_memory(ctrl_base, 0x100000, s_ioport_ctrl);
2474 cpu_register_physical_memory(vram_base + 0x000a0000, 0x20000, vga_io_memory);
2475 qemu_register_coalesced_mmio(vram_base + 0x000a0000, 0x20000);
2478 int isa_vga_init(uint8_t *vga_ram_base,
2479 unsigned long vga_ram_offset, int vga_ram_size)
2483 s = qemu_mallocz(sizeof(VGAState));
2485 vga_common_init(s, vga_ram_base, vga_ram_offset, vga_ram_size);
2488 s->ds = graphic_console_init(s->update, s->invalidate,
2489 s->screen_dump, s->text_update, s);
2491 #ifdef CONFIG_BOCHS_VBE
2492 /* XXX: use optimized standard vga accesses */
2493 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
2494 vga_ram_size, vga_ram_offset);
2499 int isa_vga_mm_init(uint8_t *vga_ram_base,
2500 unsigned long vga_ram_offset, int vga_ram_size,
2501 target_phys_addr_t vram_base, target_phys_addr_t ctrl_base,
2506 s = qemu_mallocz(sizeof(VGAState));
2508 vga_common_init(s, vga_ram_base, vga_ram_offset, vga_ram_size);
2509 vga_mm_init(s, vram_base, ctrl_base, it_shift);
2511 s->ds = graphic_console_init(s->update, s->invalidate,
2512 s->screen_dump, s->text_update, s);
2514 #ifdef CONFIG_BOCHS_VBE
2515 /* XXX: use optimized standard vga accesses */
2516 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
2517 vga_ram_size, vga_ram_offset);
2522 static void pci_vga_write_config(PCIDevice *d,
2523 uint32_t address, uint32_t val, int len)
2525 PCIVGAState *pvs = container_of(d, PCIVGAState, dev);
2526 VGAState *s = &pvs->vga_state;
2528 vga_dirty_log_stop(s);
2529 pci_default_write_config(d, address, val, len);
2530 vga_dirty_log_start(s);
2533 int pci_vga_init(PCIBus *bus, uint8_t *vga_ram_base,
2534 unsigned long vga_ram_offset, int vga_ram_size,
2535 unsigned long vga_bios_offset, int vga_bios_size)
2541 d = (PCIVGAState *)pci_register_device(bus, "VGA",
2542 sizeof(PCIVGAState),
2543 -1, NULL, pci_vga_write_config);
2548 vga_common_init(s, vga_ram_base, vga_ram_offset, vga_ram_size);
2551 s->ds = graphic_console_init(s->update, s->invalidate,
2552 s->screen_dump, s->text_update, s);
2554 s->pci_dev = &d->dev;
2556 pci_conf = d->dev.config;
2557 // dummy VGA (same as Bochs ID)
2558 pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_QEMU);
2559 pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_QEMU_VGA);
2560 pci_config_set_class(pci_conf, PCI_CLASS_DISPLAY_VGA);
2561 pci_conf[0x0e] = 0x00; // header_type
2563 /* XXX: vga_ram_size must be a power of two */
2564 pci_register_io_region(&d->dev, 0, vga_ram_size,
2565 PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
2566 if (vga_bios_size != 0) {
2567 unsigned int bios_total_size;
2568 s->bios_offset = vga_bios_offset;
2569 s->bios_size = vga_bios_size;
2570 /* must be a power of two */
2571 bios_total_size = 1;
2572 while (bios_total_size < vga_bios_size)
2573 bios_total_size <<= 1;
2574 pci_register_io_region(&d->dev, PCI_ROM_SLOT, bios_total_size,
2575 PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
2580 /********************************************************/
2581 /* vga screen dump */
2583 static void vga_save_dpy_update(DisplayState *s,
2584 int x, int y, int w, int h)
2588 static void vga_save_dpy_resize(DisplayState *s)
2592 static void vga_save_dpy_refresh(DisplayState *s)
2596 int ppm_save(const char *filename, struct DisplaySurface *ds)
2604 f = fopen(filename, "wb");
2607 fprintf(f, "P6\n%d %d\n%d\n",
2608 ds->width, ds->height, 255);
2610 for(y = 0; y < ds->height; y++) {
2612 for(x = 0; x < ds->width; x++) {
2613 if (ds->pf.bits_per_pixel == 32)
2616 v = (uint32_t) (*(uint16_t *)d);
2617 r = ((v >> ds->pf.rshift) & ds->pf.rmax) * 256 /
2619 g = ((v >> ds->pf.gshift) & ds->pf.gmax) * 256 /
2621 b = ((v >> ds->pf.bshift) & ds->pf.bmax) * 256 /
2626 d += ds->pf.bytes_per_pixel;
2634 static void vga_screen_dump_blank(VGAState *s, const char *filename)
2637 unsigned int y, x, w, h;
2639 w = s->last_scr_width * sizeof(uint32_t);
2640 h = s->last_scr_height;
2642 f = fopen(filename, "wb");
2645 fprintf(f, "P6\n%d %d\n%d\n", w, h, 255);
2646 for (y = 0; y < h; y++) {
2647 for (x = 0; x < w; x++) {
2654 static void vga_screen_dump_common(VGAState *s, const char *filename,
2657 DisplayState *saved_ds, ds1, *ds = &ds1;
2658 DisplayChangeListener dcl;
2660 /* XXX: this is a little hackish */
2661 vga_invalidate_display(s);
2664 memset(ds, 0, sizeof(DisplayState));
2665 memset(&dcl, 0, sizeof(DisplayChangeListener));
2666 dcl.dpy_update = vga_save_dpy_update;
2667 dcl.dpy_resize = vga_save_dpy_resize;
2668 dcl.dpy_refresh = vga_save_dpy_refresh;
2669 register_displaychangelistener(ds, &dcl);
2670 ds->allocator = &default_allocator;
2671 ds->surface = qemu_create_displaysurface(ds, w, h);
2674 vga_update_resolution(s);
2675 s->want_full_update = 1;
2676 vga_update_display(s);
2678 ppm_save(filename, ds->surface);
2680 qemu_free_displaysurface(ds);
2684 static void vga_screen_dump_graphic(VGAState *s, const char *filename)
2688 s->get_resolution(s, &w, &h);
2689 vga_screen_dump_common(s, filename, w, h);
2692 static void vga_screen_dump_text(VGAState *s, const char *filename)
2694 int w, h, cwidth, cheight;
2696 vga_get_text_resolution(s, &w, &h, &cwidth, &cheight);
2697 vga_screen_dump_common(s, filename, w * cwidth, h * cheight);
2700 /* save the vga display in a PPM image even if no display is
2702 static void vga_screen_dump(void *opaque, const char *filename)
2704 VGAState *s = (VGAState *)opaque;
2706 switch (s->graphic_mode) {
2708 vga_screen_dump_text(s, filename);
2711 vga_screen_dump_graphic(s, filename);
2715 vga_screen_dump_blank(s, filename);