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"
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] = {
50 const uint8_t gr_mask
[16] = {
51 (uint8_t)~0xf0, /* 0x00 */
52 (uint8_t)~0xf0, /* 0x01 */
53 (uint8_t)~0xf0, /* 0x02 */
54 (uint8_t)~0xe0, /* 0x03 */
55 (uint8_t)~0xfc, /* 0x04 */
56 (uint8_t)~0x84, /* 0x05 */
57 (uint8_t)~0xf0, /* 0x06 */
58 (uint8_t)~0xf0, /* 0x07 */
59 (uint8_t)~0x00, /* 0x08 */
60 (uint8_t)~0xff, /* 0x09 */
61 (uint8_t)~0xff, /* 0x0a */
62 (uint8_t)~0xff, /* 0x0b */
63 (uint8_t)~0xff, /* 0x0c */
64 (uint8_t)~0xff, /* 0x0d */
65 (uint8_t)~0xff, /* 0x0e */
66 (uint8_t)~0xff, /* 0x0f */
69 #define cbswap_32(__x) \
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 WORDS_BIGENDIAN
77 #define PAT(x) cbswap_32(x)
82 #ifdef WORDS_BIGENDIAN
88 #ifdef WORDS_BIGENDIAN
89 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
91 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
94 static const uint32_t mask16
[16] = {
115 #ifdef WORDS_BIGENDIAN
118 #define PAT(x) cbswap_32(x)
121 static const uint32_t dmask16
[16] = {
140 static const uint32_t dmask4
[4] = {
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
);
153 static void vga_dumb_update_retrace_info(VGAState
*s
)
158 static void vga_precise_update_retrace_info(VGAState
*s
)
161 int hretr_start_char
;
162 int hretr_skew_chars
;
166 int vretr_start_line
;
169 int div2
, sldiv2
, dots
;
172 const int hz
[] = {25175000, 28322000, 25175000, 25175000};
173 int64_t chars_per_sec
;
174 struct vga_precise_retrace
*r
= &s
->retrace_info
.precise
;
176 htotal_chars
= s
->cr
[0x00] + 5;
177 hretr_start_char
= s
->cr
[0x04];
178 hretr_skew_chars
= (s
->cr
[0x05] >> 5) & 3;
179 hretr_end_char
= s
->cr
[0x05] & 0x1f;
181 vtotal_lines
= (s
->cr
[0x06]
182 | (((s
->cr
[0x07] & 1) | ((s
->cr
[0x07] >> 4) & 2)) << 8)) + 2
184 vretr_start_line
= s
->cr
[0x10]
185 | ((((s
->cr
[0x07] >> 2) & 1) | ((s
->cr
[0x07] >> 6) & 2)) << 8)
187 vretr_end_line
= s
->cr
[0x11] & 0xf;
190 div2
= (s
->cr
[0x17] >> 2) & 1;
191 sldiv2
= (s
->cr
[0x17] >> 3) & 1;
193 clocking_mode
= (s
->sr
[0x01] >> 3) & 1;
194 clock_sel
= (s
->msr
>> 2) & 3;
195 dots
= (s
->msr
& 1) ? 8 : 9;
197 chars_per_sec
= hz
[clock_sel
] / dots
;
199 htotal_chars
<<= clocking_mode
;
201 r
->total_chars
= vtotal_lines
* htotal_chars
;
202 r
->total_chars
= (vretr_start_line
+ vretr_end_line
+ 1) * htotal_chars
;
204 r
->ticks_per_char
= ticks_per_sec
/ (r
->total_chars
* r
->freq
);
206 r
->ticks_per_char
= ticks_per_sec
/ chars_per_sec
;
209 r
->vstart
= vretr_start_line
;
210 r
->vend
= r
->vstart
+ vretr_end_line
+ 1;
212 r
->hstart
= hretr_start_char
+ hretr_skew_chars
;
213 r
->hend
= r
->hstart
+ hretr_end_char
+ 1;
214 r
->htotal
= htotal_chars
;
227 "div2 = %d sldiv2 = %d\n"
228 "clocking_mode = %d\n"
229 "clock_sel = %d %d\n"
231 "ticks/char = %lld\n"
233 (double) ticks_per_sec
/ (r
->ticks_per_char
* r
->total_chars
),
251 static uint8_t vga_precise_retrace(VGAState
*s
)
253 struct vga_precise_retrace
*r
= &s
->retrace_info
.precise
;
254 uint8_t val
= s
->st01
& ~(ST01_V_RETRACE
| ST01_DISP_ENABLE
);
256 if (r
->total_chars
) {
257 int cur_line
, cur_line_char
, cur_char
;
260 cur_tick
= qemu_get_clock(vm_clock
);
262 cur_char
= (cur_tick
/ r
->ticks_per_char
) % r
->total_chars
;
263 cur_line
= cur_char
/ r
->htotal
;
265 if (cur_line
>= r
->vstart
&& cur_line
<= r
->vend
) {
266 val
|= ST01_V_RETRACE
| ST01_DISP_ENABLE
;
268 cur_line_char
= cur_char
% r
->htotal
;
269 if (cur_line_char
>= r
->hstart
&& cur_line_char
<= r
->hend
) {
270 val
|= ST01_DISP_ENABLE
;
276 return s
->st01
^ (ST01_V_RETRACE
| ST01_DISP_ENABLE
);
280 static uint8_t vga_dumb_retrace(VGAState
*s
)
282 return s
->st01
^ (ST01_V_RETRACE
| ST01_DISP_ENABLE
);
285 static uint32_t vga_ioport_read(void *opaque
, uint32_t addr
)
287 VGAState
*s
= opaque
;
290 /* check port range access depending on color/monochrome mode */
291 if ((addr
>= 0x3b0 && addr
<= 0x3bf && (s
->msr
& MSR_COLOR_EMULATION
)) ||
292 (addr
>= 0x3d0 && addr
<= 0x3df && !(s
->msr
& MSR_COLOR_EMULATION
))) {
297 if (s
->ar_flip_flop
== 0) {
304 index
= s
->ar_index
& 0x1f;
317 val
= s
->sr
[s
->sr_index
];
319 printf("vga: read SR%x = 0x%02x\n", s
->sr_index
, val
);
326 val
= s
->dac_write_index
;
329 val
= s
->palette
[s
->dac_read_index
* 3 + s
->dac_sub_index
];
330 if (++s
->dac_sub_index
== 3) {
331 s
->dac_sub_index
= 0;
345 val
= s
->gr
[s
->gr_index
];
347 printf("vga: read GR%x = 0x%02x\n", s
->gr_index
, val
);
356 val
= s
->cr
[s
->cr_index
];
358 printf("vga: read CR%x = 0x%02x\n", s
->cr_index
, val
);
363 /* just toggle to fool polling */
364 val
= s
->st01
= s
->retrace(s
);
372 #if defined(DEBUG_VGA)
373 printf("VGA: read addr=0x%04x data=0x%02x\n", addr
, val
);
378 static void vga_ioport_write(void *opaque
, uint32_t addr
, uint32_t val
)
380 VGAState
*s
= opaque
;
383 /* check port range access depending on color/monochrome mode */
384 if ((addr
>= 0x3b0 && addr
<= 0x3bf && (s
->msr
& MSR_COLOR_EMULATION
)) ||
385 (addr
>= 0x3d0 && addr
<= 0x3df && !(s
->msr
& MSR_COLOR_EMULATION
)))
389 printf("VGA: write addr=0x%04x data=0x%02x\n", addr
, val
);
394 if (s
->ar_flip_flop
== 0) {
398 index
= s
->ar_index
& 0x1f;
401 s
->ar
[index
] = val
& 0x3f;
404 s
->ar
[index
] = val
& ~0x10;
410 s
->ar
[index
] = val
& ~0xc0;
413 s
->ar
[index
] = val
& ~0xf0;
416 s
->ar
[index
] = val
& ~0xf0;
422 s
->ar_flip_flop
^= 1;
425 s
->msr
= val
& ~0x10;
426 s
->update_retrace_info(s
);
429 s
->sr_index
= val
& 7;
433 printf("vga: write SR%x = 0x%02x\n", s
->sr_index
, val
);
435 s
->sr
[s
->sr_index
] = val
& sr_mask
[s
->sr_index
];
436 if (s
->sr_index
== 1) s
->update_retrace_info(s
);
439 s
->dac_read_index
= val
;
440 s
->dac_sub_index
= 0;
444 s
->dac_write_index
= val
;
445 s
->dac_sub_index
= 0;
449 s
->dac_cache
[s
->dac_sub_index
] = val
;
450 if (++s
->dac_sub_index
== 3) {
451 memcpy(&s
->palette
[s
->dac_write_index
* 3], s
->dac_cache
, 3);
452 s
->dac_sub_index
= 0;
453 s
->dac_write_index
++;
457 s
->gr_index
= val
& 0x0f;
461 printf("vga: write GR%x = 0x%02x\n", s
->gr_index
, val
);
463 s
->gr
[s
->gr_index
] = val
& gr_mask
[s
->gr_index
];
472 printf("vga: write CR%x = 0x%02x\n", s
->cr_index
, val
);
474 /* handle CR0-7 protection */
475 if ((s
->cr
[0x11] & 0x80) && s
->cr_index
<= 7) {
476 /* can always write bit 4 of CR7 */
477 if (s
->cr_index
== 7)
478 s
->cr
[7] = (s
->cr
[7] & ~0x10) | (val
& 0x10);
481 switch(s
->cr_index
) {
482 case 0x01: /* horizontal display end */
487 case 0x12: /* vertical display end */
488 s
->cr
[s
->cr_index
] = val
;
491 s
->cr
[s
->cr_index
] = val
;
495 switch(s
->cr_index
) {
503 s
->update_retrace_info(s
);
514 #ifdef CONFIG_BOCHS_VBE
515 static uint32_t vbe_ioport_read_index(void *opaque
, uint32_t addr
)
517 VGAState
*s
= opaque
;
523 static uint32_t vbe_ioport_read_data(void *opaque
, uint32_t addr
)
525 VGAState
*s
= opaque
;
528 if (s
->vbe_index
<= VBE_DISPI_INDEX_NB
) {
529 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_GETCAPS
) {
530 switch(s
->vbe_index
) {
531 /* XXX: do not hardcode ? */
532 case VBE_DISPI_INDEX_XRES
:
533 val
= VBE_DISPI_MAX_XRES
;
535 case VBE_DISPI_INDEX_YRES
:
536 val
= VBE_DISPI_MAX_YRES
;
538 case VBE_DISPI_INDEX_BPP
:
539 val
= VBE_DISPI_MAX_BPP
;
542 val
= s
->vbe_regs
[s
->vbe_index
];
546 val
= s
->vbe_regs
[s
->vbe_index
];
551 #ifdef DEBUG_BOCHS_VBE
552 printf("VBE: read index=0x%x val=0x%x\n", s
->vbe_index
, val
);
557 static void vbe_ioport_write_index(void *opaque
, uint32_t addr
, uint32_t val
)
559 VGAState
*s
= opaque
;
563 static void vbe_ioport_write_data(void *opaque
, uint32_t addr
, uint32_t val
)
565 VGAState
*s
= opaque
;
567 if (s
->vbe_index
<= VBE_DISPI_INDEX_NB
) {
568 #ifdef DEBUG_BOCHS_VBE
569 printf("VBE: write index=0x%x val=0x%x\n", s
->vbe_index
, val
);
571 switch(s
->vbe_index
) {
572 case VBE_DISPI_INDEX_ID
:
573 if (val
== VBE_DISPI_ID0
||
574 val
== VBE_DISPI_ID1
||
575 val
== VBE_DISPI_ID2
||
576 val
== VBE_DISPI_ID3
||
577 val
== VBE_DISPI_ID4
) {
578 s
->vbe_regs
[s
->vbe_index
] = val
;
581 case VBE_DISPI_INDEX_XRES
:
582 if ((val
<= VBE_DISPI_MAX_XRES
) && ((val
& 7) == 0)) {
583 s
->vbe_regs
[s
->vbe_index
] = val
;
586 case VBE_DISPI_INDEX_YRES
:
587 if (val
<= VBE_DISPI_MAX_YRES
) {
588 s
->vbe_regs
[s
->vbe_index
] = val
;
591 case VBE_DISPI_INDEX_BPP
:
594 if (val
== 4 || val
== 8 || val
== 15 ||
595 val
== 16 || val
== 24 || val
== 32) {
596 s
->vbe_regs
[s
->vbe_index
] = val
;
599 case VBE_DISPI_INDEX_BANK
:
600 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
601 val
&= (s
->vbe_bank_mask
>> 2);
603 val
&= s
->vbe_bank_mask
;
605 s
->vbe_regs
[s
->vbe_index
] = val
;
606 s
->bank_offset
= (val
<< 16);
608 case VBE_DISPI_INDEX_ENABLE
:
609 if ((val
& VBE_DISPI_ENABLED
) &&
610 !(s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
)) {
611 int h
, shift_control
;
613 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] =
614 s
->vbe_regs
[VBE_DISPI_INDEX_XRES
];
615 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_HEIGHT
] =
616 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
];
617 s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
] = 0;
618 s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
] = 0;
620 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
621 s
->vbe_line_offset
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 1;
623 s
->vbe_line_offset
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] *
624 ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
625 s
->vbe_start_addr
= 0;
627 /* clear the screen (should be done in BIOS) */
628 if (!(val
& VBE_DISPI_NOCLEARMEM
)) {
629 memset(s
->vram_ptr
, 0,
630 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] * s
->vbe_line_offset
);
633 /* we initialize the VGA graphic mode (should be done
635 s
->gr
[0x06] = (s
->gr
[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
636 s
->cr
[0x17] |= 3; /* no CGA modes */
637 s
->cr
[0x13] = s
->vbe_line_offset
>> 3;
639 s
->cr
[0x01] = (s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 3) - 1;
640 /* height (only meaningful if < 1024) */
641 h
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] - 1;
643 s
->cr
[0x07] = (s
->cr
[0x07] & ~0x42) |
644 ((h
>> 7) & 0x02) | ((h
>> 3) & 0x40);
645 /* line compare to 1023 */
650 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
652 s
->sr
[0x01] &= ~8; /* no double line */
655 s
->sr
[4] |= 0x08; /* set chain 4 mode */
656 s
->sr
[2] |= 0x0f; /* activate all planes */
658 s
->gr
[0x05] = (s
->gr
[0x05] & ~0x60) | (shift_control
<< 5);
659 s
->cr
[0x09] &= ~0x9f; /* no double scan */
661 /* XXX: the bios should do that */
664 s
->dac_8bit
= (val
& VBE_DISPI_8BIT_DAC
) > 0;
665 s
->vbe_regs
[s
->vbe_index
] = val
;
667 case VBE_DISPI_INDEX_VIRT_WIDTH
:
669 int w
, h
, line_offset
;
671 if (val
< s
->vbe_regs
[VBE_DISPI_INDEX_XRES
])
674 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
675 line_offset
= w
>> 1;
677 line_offset
= w
* ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
678 h
= s
->vram_size
/ line_offset
;
679 /* XXX: support weird bochs semantics ? */
680 if (h
< s
->vbe_regs
[VBE_DISPI_INDEX_YRES
])
682 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] = w
;
683 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_HEIGHT
] = h
;
684 s
->vbe_line_offset
= line_offset
;
687 case VBE_DISPI_INDEX_X_OFFSET
:
688 case VBE_DISPI_INDEX_Y_OFFSET
:
691 s
->vbe_regs
[s
->vbe_index
] = val
;
692 s
->vbe_start_addr
= s
->vbe_line_offset
* s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
];
693 x
= s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
];
694 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
695 s
->vbe_start_addr
+= x
>> 1;
697 s
->vbe_start_addr
+= x
* ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
698 s
->vbe_start_addr
>>= 2;
708 /* called for accesses between 0xa0000 and 0xc0000 */
709 uint32_t vga_mem_readb(void *opaque
, target_phys_addr_t addr
)
711 VGAState
*s
= opaque
;
712 int memory_map_mode
, plane
;
715 /* convert to VGA memory offset */
716 memory_map_mode
= (s
->gr
[6] >> 2) & 3;
718 switch(memory_map_mode
) {
724 addr
+= s
->bank_offset
;
739 if (s
->sr
[4] & 0x08) {
740 /* chain 4 mode : simplest access */
741 ret
= s
->vram_ptr
[addr
];
742 } else if (s
->gr
[5] & 0x10) {
743 /* odd/even mode (aka text mode mapping) */
744 plane
= (s
->gr
[4] & 2) | (addr
& 1);
745 ret
= s
->vram_ptr
[((addr
& ~1) << 1) | plane
];
747 /* standard VGA latched access */
748 s
->latch
= ((uint32_t *)s
->vram_ptr
)[addr
];
750 if (!(s
->gr
[5] & 0x08)) {
753 ret
= GET_PLANE(s
->latch
, plane
);
756 ret
= (s
->latch
^ mask16
[s
->gr
[2]]) & mask16
[s
->gr
[7]];
765 static uint32_t vga_mem_readw(void *opaque
, target_phys_addr_t addr
)
768 #ifdef TARGET_WORDS_BIGENDIAN
769 v
= vga_mem_readb(opaque
, addr
) << 8;
770 v
|= vga_mem_readb(opaque
, addr
+ 1);
772 v
= vga_mem_readb(opaque
, addr
);
773 v
|= vga_mem_readb(opaque
, addr
+ 1) << 8;
778 static uint32_t vga_mem_readl(void *opaque
, target_phys_addr_t addr
)
781 #ifdef TARGET_WORDS_BIGENDIAN
782 v
= vga_mem_readb(opaque
, addr
) << 24;
783 v
|= vga_mem_readb(opaque
, addr
+ 1) << 16;
784 v
|= vga_mem_readb(opaque
, addr
+ 2) << 8;
785 v
|= vga_mem_readb(opaque
, addr
+ 3);
787 v
= vga_mem_readb(opaque
, addr
);
788 v
|= vga_mem_readb(opaque
, addr
+ 1) << 8;
789 v
|= vga_mem_readb(opaque
, addr
+ 2) << 16;
790 v
|= vga_mem_readb(opaque
, addr
+ 3) << 24;
795 /* called for accesses between 0xa0000 and 0xc0000 */
796 void vga_mem_writeb(void *opaque
, target_phys_addr_t addr
, uint32_t val
)
798 VGAState
*s
= opaque
;
799 int memory_map_mode
, plane
, write_mode
, b
, func_select
, mask
;
800 uint32_t write_mask
, bit_mask
, set_mask
;
803 printf("vga: [0x%x] = 0x%02x\n", addr
, val
);
805 /* convert to VGA memory offset */
806 memory_map_mode
= (s
->gr
[6] >> 2) & 3;
808 switch(memory_map_mode
) {
814 addr
+= s
->bank_offset
;
829 if (s
->sr
[4] & 0x08) {
830 /* chain 4 mode : simplest access */
833 if (s
->sr
[2] & mask
) {
834 s
->vram_ptr
[addr
] = val
;
836 printf("vga: chain4: [0x%x]\n", addr
);
838 s
->plane_updated
|= mask
; /* only used to detect font change */
839 cpu_physical_memory_set_dirty(s
->vram_offset
+ addr
);
841 } else if (s
->gr
[5] & 0x10) {
842 /* odd/even mode (aka text mode mapping) */
843 plane
= (s
->gr
[4] & 2) | (addr
& 1);
845 if (s
->sr
[2] & mask
) {
846 addr
= ((addr
& ~1) << 1) | plane
;
847 s
->vram_ptr
[addr
] = val
;
849 printf("vga: odd/even: [0x%x]\n", addr
);
851 s
->plane_updated
|= mask
; /* only used to detect font change */
852 cpu_physical_memory_set_dirty(s
->vram_offset
+ addr
);
855 /* standard VGA latched access */
856 write_mode
= s
->gr
[5] & 3;
862 val
= ((val
>> b
) | (val
<< (8 - b
))) & 0xff;
866 /* apply set/reset mask */
867 set_mask
= mask16
[s
->gr
[1]];
868 val
= (val
& ~set_mask
) | (mask16
[s
->gr
[0]] & set_mask
);
875 val
= mask16
[val
& 0x0f];
881 val
= (val
>> b
) | (val
<< (8 - b
));
883 bit_mask
= s
->gr
[8] & val
;
884 val
= mask16
[s
->gr
[0]];
888 /* apply logical operation */
889 func_select
= s
->gr
[3] >> 3;
890 switch(func_select
) {
910 bit_mask
|= bit_mask
<< 8;
911 bit_mask
|= bit_mask
<< 16;
912 val
= (val
& bit_mask
) | (s
->latch
& ~bit_mask
);
915 /* mask data according to sr[2] */
917 s
->plane_updated
|= mask
; /* only used to detect font change */
918 write_mask
= mask16
[mask
];
919 ((uint32_t *)s
->vram_ptr
)[addr
] =
920 (((uint32_t *)s
->vram_ptr
)[addr
] & ~write_mask
) |
923 printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
924 addr
* 4, write_mask
, val
);
926 cpu_physical_memory_set_dirty(s
->vram_offset
+ (addr
<< 2));
930 static void vga_mem_writew(void *opaque
, target_phys_addr_t addr
, uint32_t val
)
932 #ifdef TARGET_WORDS_BIGENDIAN
933 vga_mem_writeb(opaque
, addr
, (val
>> 8) & 0xff);
934 vga_mem_writeb(opaque
, addr
+ 1, val
& 0xff);
936 vga_mem_writeb(opaque
, addr
, val
& 0xff);
937 vga_mem_writeb(opaque
, addr
+ 1, (val
>> 8) & 0xff);
941 static void vga_mem_writel(void *opaque
, target_phys_addr_t addr
, uint32_t val
)
943 #ifdef TARGET_WORDS_BIGENDIAN
944 vga_mem_writeb(opaque
, addr
, (val
>> 24) & 0xff);
945 vga_mem_writeb(opaque
, addr
+ 1, (val
>> 16) & 0xff);
946 vga_mem_writeb(opaque
, addr
+ 2, (val
>> 8) & 0xff);
947 vga_mem_writeb(opaque
, addr
+ 3, val
& 0xff);
949 vga_mem_writeb(opaque
, addr
, val
& 0xff);
950 vga_mem_writeb(opaque
, addr
+ 1, (val
>> 8) & 0xff);
951 vga_mem_writeb(opaque
, addr
+ 2, (val
>> 16) & 0xff);
952 vga_mem_writeb(opaque
, addr
+ 3, (val
>> 24) & 0xff);
956 typedef void vga_draw_glyph8_func(uint8_t *d
, int linesize
,
957 const uint8_t *font_ptr
, int h
,
958 uint32_t fgcol
, uint32_t bgcol
);
959 typedef void vga_draw_glyph9_func(uint8_t *d
, int linesize
,
960 const uint8_t *font_ptr
, int h
,
961 uint32_t fgcol
, uint32_t bgcol
, int dup9
);
962 typedef void vga_draw_line_func(VGAState
*s1
, uint8_t *d
,
963 const uint8_t *s
, int width
);
966 #include "vga_template.h"
969 #include "vga_template.h"
973 #include "vga_template.h"
976 #include "vga_template.h"
980 #include "vga_template.h"
983 #include "vga_template.h"
987 #include "vga_template.h"
989 static unsigned int rgb_to_pixel8_dup(unsigned int r
, unsigned int g
, unsigned b
)
992 col
= rgb_to_pixel8(r
, g
, b
);
998 static unsigned int rgb_to_pixel15_dup(unsigned int r
, unsigned int g
, unsigned b
)
1001 col
= rgb_to_pixel15(r
, g
, b
);
1006 static unsigned int rgb_to_pixel15bgr_dup(unsigned int r
, unsigned int g
,
1010 col
= rgb_to_pixel15bgr(r
, g
, b
);
1015 static unsigned int rgb_to_pixel16_dup(unsigned int r
, unsigned int g
, unsigned b
)
1018 col
= rgb_to_pixel16(r
, g
, b
);
1023 static unsigned int rgb_to_pixel16bgr_dup(unsigned int r
, unsigned int g
,
1027 col
= rgb_to_pixel16bgr(r
, g
, b
);
1032 static unsigned int rgb_to_pixel32_dup(unsigned int r
, unsigned int g
, unsigned b
)
1035 col
= rgb_to_pixel32(r
, g
, b
);
1039 static unsigned int rgb_to_pixel32bgr_dup(unsigned int r
, unsigned int g
, unsigned b
)
1042 col
= rgb_to_pixel32bgr(r
, g
, b
);
1046 /* return true if the palette was modified */
1047 static int update_palette16(VGAState
*s
)
1050 uint32_t v
, col
, *palette
;
1053 palette
= s
->last_palette
;
1054 for(i
= 0; i
< 16; i
++) {
1056 if (s
->ar
[0x10] & 0x80)
1057 v
= ((s
->ar
[0x14] & 0xf) << 4) | (v
& 0xf);
1059 v
= ((s
->ar
[0x14] & 0xc) << 4) | (v
& 0x3f);
1061 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
1062 c6_to_8(s
->palette
[v
+ 1]),
1063 c6_to_8(s
->palette
[v
+ 2]));
1064 if (col
!= palette
[i
]) {
1072 /* return true if the palette was modified */
1073 static int update_palette256(VGAState
*s
)
1076 uint32_t v
, col
, *palette
;
1079 palette
= s
->last_palette
;
1081 for(i
= 0; i
< 256; i
++) {
1083 col
= s
->rgb_to_pixel(s
->palette
[v
],
1087 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
1088 c6_to_8(s
->palette
[v
+ 1]),
1089 c6_to_8(s
->palette
[v
+ 2]));
1091 if (col
!= palette
[i
]) {
1100 static void vga_get_offsets(VGAState
*s
,
1101 uint32_t *pline_offset
,
1102 uint32_t *pstart_addr
,
1103 uint32_t *pline_compare
)
1105 uint32_t start_addr
, line_offset
, line_compare
;
1106 #ifdef CONFIG_BOCHS_VBE
1107 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1108 line_offset
= s
->vbe_line_offset
;
1109 start_addr
= s
->vbe_start_addr
;
1110 line_compare
= 65535;
1114 /* compute line_offset in bytes */
1115 line_offset
= s
->cr
[0x13];
1118 /* starting address */
1119 start_addr
= s
->cr
[0x0d] | (s
->cr
[0x0c] << 8);
1122 line_compare
= s
->cr
[0x18] |
1123 ((s
->cr
[0x07] & 0x10) << 4) |
1124 ((s
->cr
[0x09] & 0x40) << 3);
1126 *pline_offset
= line_offset
;
1127 *pstart_addr
= start_addr
;
1128 *pline_compare
= line_compare
;
1131 /* update start_addr and line_offset. Return TRUE if modified */
1132 static int update_basic_params(VGAState
*s
)
1135 uint32_t start_addr
, line_offset
, line_compare
;
1139 s
->get_offsets(s
, &line_offset
, &start_addr
, &line_compare
);
1141 if (line_offset
!= s
->line_offset
||
1142 start_addr
!= s
->start_addr
||
1143 line_compare
!= s
->line_compare
) {
1144 s
->line_offset
= line_offset
;
1145 s
->start_addr
= start_addr
;
1146 s
->line_compare
= line_compare
;
1154 static inline int get_depth_index(DisplayState
*s
)
1178 static vga_draw_glyph8_func
*vga_draw_glyph8_table
[NB_DEPTHS
] = {
1188 static vga_draw_glyph8_func
*vga_draw_glyph16_table
[NB_DEPTHS
] = {
1190 vga_draw_glyph16_16
,
1191 vga_draw_glyph16_16
,
1192 vga_draw_glyph16_32
,
1193 vga_draw_glyph16_32
,
1194 vga_draw_glyph16_16
,
1195 vga_draw_glyph16_16
,
1198 static vga_draw_glyph9_func
*vga_draw_glyph9_table
[NB_DEPTHS
] = {
1208 static const uint8_t cursor_glyph
[32 * 4] = {
1209 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1210 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1211 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1212 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1213 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1214 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1215 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1216 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
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,
1235 static void vga_draw_text(VGAState
*s
, int full_update
)
1237 int cx
, cy
, cheight
, cw
, ch
, cattr
, height
, width
, ch_attr
;
1238 int cx_min
, cx_max
, linesize
, x_incr
;
1239 uint32_t offset
, fgcol
, bgcol
, v
, cursor_offset
;
1240 uint8_t *d1
, *d
, *src
, *s1
, *dest
, *cursor_ptr
;
1241 const uint8_t *font_ptr
, *font_base
[2];
1242 int dup9
, line_offset
, depth_index
;
1244 uint32_t *ch_attr_ptr
;
1245 vga_draw_glyph8_func
*vga_draw_glyph8
;
1246 vga_draw_glyph9_func
*vga_draw_glyph9
;
1248 full_update
|= update_palette16(s
);
1249 palette
= s
->last_palette
;
1251 /* compute font data address (in plane 2) */
1253 offset
= (((v
>> 4) & 1) | ((v
<< 1) & 6)) * 8192 * 4 + 2;
1254 if (offset
!= s
->font_offsets
[0]) {
1255 s
->font_offsets
[0] = offset
;
1258 font_base
[0] = s
->vram_ptr
+ offset
;
1260 offset
= (((v
>> 5) & 1) | ((v
>> 1) & 6)) * 8192 * 4 + 2;
1261 font_base
[1] = s
->vram_ptr
+ offset
;
1262 if (offset
!= s
->font_offsets
[1]) {
1263 s
->font_offsets
[1] = offset
;
1266 if (s
->plane_updated
& (1 << 2)) {
1267 /* if the plane 2 was modified since the last display, it
1268 indicates the font may have been modified */
1269 s
->plane_updated
= 0;
1272 full_update
|= update_basic_params(s
);
1274 line_offset
= s
->line_offset
;
1275 s1
= s
->vram_ptr
+ (s
->start_addr
* 4);
1277 /* total width & height */
1278 cheight
= (s
->cr
[9] & 0x1f) + 1;
1280 if (!(s
->sr
[1] & 0x01))
1282 if (s
->sr
[1] & 0x08)
1283 cw
= 16; /* NOTE: no 18 pixel wide */
1284 x_incr
= cw
* ((s
->ds
->depth
+ 7) >> 3);
1285 width
= (s
->cr
[0x01] + 1);
1286 if (s
->cr
[0x06] == 100) {
1287 /* ugly hack for CGA 160x100x16 - explain me the logic */
1290 height
= s
->cr
[0x12] |
1291 ((s
->cr
[0x07] & 0x02) << 7) |
1292 ((s
->cr
[0x07] & 0x40) << 3);
1293 height
= (height
+ 1) / cheight
;
1295 if ((height
* width
) > CH_ATTR_SIZE
) {
1296 /* better than nothing: exit if transient size is too big */
1300 if (width
!= s
->last_width
|| height
!= s
->last_height
||
1301 cw
!= s
->last_cw
|| cheight
!= s
->last_ch
) {
1302 s
->last_scr_width
= width
* cw
;
1303 s
->last_scr_height
= height
* cheight
;
1304 qemu_console_resize(s
->console
, s
->last_scr_width
, s
->last_scr_height
);
1305 s
->last_width
= width
;
1306 s
->last_height
= height
;
1307 s
->last_ch
= cheight
;
1311 cursor_offset
= ((s
->cr
[0x0e] << 8) | s
->cr
[0x0f]) - s
->start_addr
;
1312 if (cursor_offset
!= s
->cursor_offset
||
1313 s
->cr
[0xa] != s
->cursor_start
||
1314 s
->cr
[0xb] != s
->cursor_end
) {
1315 /* if the cursor position changed, we update the old and new
1317 if (s
->cursor_offset
< CH_ATTR_SIZE
)
1318 s
->last_ch_attr
[s
->cursor_offset
] = -1;
1319 if (cursor_offset
< CH_ATTR_SIZE
)
1320 s
->last_ch_attr
[cursor_offset
] = -1;
1321 s
->cursor_offset
= cursor_offset
;
1322 s
->cursor_start
= s
->cr
[0xa];
1323 s
->cursor_end
= s
->cr
[0xb];
1325 cursor_ptr
= s
->vram_ptr
+ (s
->start_addr
+ cursor_offset
) * 4;
1327 depth_index
= get_depth_index(s
->ds
);
1329 vga_draw_glyph8
= vga_draw_glyph16_table
[depth_index
];
1331 vga_draw_glyph8
= vga_draw_glyph8_table
[depth_index
];
1332 vga_draw_glyph9
= vga_draw_glyph9_table
[depth_index
];
1335 linesize
= s
->ds
->linesize
;
1336 ch_attr_ptr
= s
->last_ch_attr
;
1337 for(cy
= 0; cy
< height
; cy
++) {
1342 for(cx
= 0; cx
< width
; cx
++) {
1343 ch_attr
= *(uint16_t *)src
;
1344 if (full_update
|| ch_attr
!= *ch_attr_ptr
) {
1349 *ch_attr_ptr
= ch_attr
;
1350 #ifdef WORDS_BIGENDIAN
1352 cattr
= ch_attr
& 0xff;
1354 ch
= ch_attr
& 0xff;
1355 cattr
= ch_attr
>> 8;
1357 font_ptr
= font_base
[(cattr
>> 3) & 1];
1358 font_ptr
+= 32 * 4 * ch
;
1359 bgcol
= palette
[cattr
>> 4];
1360 fgcol
= palette
[cattr
& 0x0f];
1362 vga_draw_glyph8(d1
, linesize
,
1363 font_ptr
, cheight
, fgcol
, bgcol
);
1366 if (ch
>= 0xb0 && ch
<= 0xdf && (s
->ar
[0x10] & 0x04))
1368 vga_draw_glyph9(d1
, linesize
,
1369 font_ptr
, cheight
, fgcol
, bgcol
, dup9
);
1371 if (src
== cursor_ptr
&&
1372 !(s
->cr
[0x0a] & 0x20)) {
1373 int line_start
, line_last
, h
;
1374 /* draw the cursor */
1375 line_start
= s
->cr
[0x0a] & 0x1f;
1376 line_last
= s
->cr
[0x0b] & 0x1f;
1377 /* XXX: check that */
1378 if (line_last
> cheight
- 1)
1379 line_last
= cheight
- 1;
1380 if (line_last
>= line_start
&& line_start
< cheight
) {
1381 h
= line_last
- line_start
+ 1;
1382 d
= d1
+ linesize
* line_start
;
1384 vga_draw_glyph8(d
, linesize
,
1385 cursor_glyph
, h
, fgcol
, bgcol
);
1387 vga_draw_glyph9(d
, linesize
,
1388 cursor_glyph
, h
, fgcol
, bgcol
, 1);
1398 dpy_update(s
->ds
, cx_min
* cw
, cy
* cheight
,
1399 (cx_max
- cx_min
+ 1) * cw
, cheight
);
1401 dest
+= linesize
* cheight
;
1420 static vga_draw_line_func
*vga_draw_line_table
[NB_DEPTHS
* VGA_DRAW_LINE_NB
] = {
1430 vga_draw_line2d2_16
,
1431 vga_draw_line2d2_16
,
1432 vga_draw_line2d2_32
,
1433 vga_draw_line2d2_32
,
1434 vga_draw_line2d2_16
,
1435 vga_draw_line2d2_16
,
1446 vga_draw_line4d2_16
,
1447 vga_draw_line4d2_16
,
1448 vga_draw_line4d2_32
,
1449 vga_draw_line4d2_32
,
1450 vga_draw_line4d2_16
,
1451 vga_draw_line4d2_16
,
1454 vga_draw_line8d2_16
,
1455 vga_draw_line8d2_16
,
1456 vga_draw_line8d2_32
,
1457 vga_draw_line8d2_32
,
1458 vga_draw_line8d2_16
,
1459 vga_draw_line8d2_16
,
1473 vga_draw_line15_32bgr
,
1474 vga_draw_line15_15bgr
,
1475 vga_draw_line15_16bgr
,
1481 vga_draw_line16_32bgr
,
1482 vga_draw_line16_15bgr
,
1483 vga_draw_line16_16bgr
,
1489 vga_draw_line24_32bgr
,
1490 vga_draw_line24_15bgr
,
1491 vga_draw_line24_16bgr
,
1497 vga_draw_line32_32bgr
,
1498 vga_draw_line32_15bgr
,
1499 vga_draw_line32_16bgr
,
1502 typedef unsigned int rgb_to_pixel_dup_func(unsigned int r
, unsigned int g
, unsigned b
);
1504 static rgb_to_pixel_dup_func
*rgb_to_pixel_dup_table
[NB_DEPTHS
] = {
1509 rgb_to_pixel32bgr_dup
,
1510 rgb_to_pixel15bgr_dup
,
1511 rgb_to_pixel16bgr_dup
,
1514 static int vga_get_bpp(VGAState
*s
)
1517 #ifdef CONFIG_BOCHS_VBE
1518 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1519 ret
= s
->vbe_regs
[VBE_DISPI_INDEX_BPP
];
1528 static void vga_get_resolution(VGAState
*s
, int *pwidth
, int *pheight
)
1532 #ifdef CONFIG_BOCHS_VBE
1533 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1534 width
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
];
1535 height
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
];
1539 width
= (s
->cr
[0x01] + 1) * 8;
1540 height
= s
->cr
[0x12] |
1541 ((s
->cr
[0x07] & 0x02) << 7) |
1542 ((s
->cr
[0x07] & 0x40) << 3);
1543 height
= (height
+ 1);
1549 void vga_invalidate_scanlines(VGAState
*s
, int y1
, int y2
)
1552 if (y1
>= VGA_MAX_HEIGHT
)
1554 if (y2
>= VGA_MAX_HEIGHT
)
1555 y2
= VGA_MAX_HEIGHT
;
1556 for(y
= y1
; y
< y2
; y
++) {
1557 s
->invalidated_y_table
[y
>> 5] |= 1 << (y
& 0x1f);
1564 static void vga_draw_graphic(VGAState
*s
, int full_update
)
1566 int y1
, y
, update
, page_min
, page_max
, linesize
, y_start
, double_scan
, mask
;
1567 int width
, height
, shift_control
, line_offset
, page0
, page1
, bwidth
, bits
;
1568 int disp_width
, multi_scan
, multi_run
;
1570 uint32_t v
, addr1
, addr
;
1571 vga_draw_line_func
*vga_draw_line
;
1573 full_update
|= update_basic_params(s
);
1575 s
->get_resolution(s
, &width
, &height
);
1578 shift_control
= (s
->gr
[0x05] >> 5) & 3;
1579 double_scan
= (s
->cr
[0x09] >> 7);
1580 if (shift_control
!= 1) {
1581 multi_scan
= (((s
->cr
[0x09] & 0x1f) + 1) << double_scan
) - 1;
1583 /* in CGA modes, multi_scan is ignored */
1584 /* XXX: is it correct ? */
1585 multi_scan
= double_scan
;
1587 multi_run
= multi_scan
;
1588 if (shift_control
!= s
->shift_control
||
1589 double_scan
!= s
->double_scan
) {
1591 s
->shift_control
= shift_control
;
1592 s
->double_scan
= double_scan
;
1595 if (shift_control
== 0) {
1596 full_update
|= update_palette16(s
);
1597 if (s
->sr
[0x01] & 8) {
1598 v
= VGA_DRAW_LINE4D2
;
1604 } else if (shift_control
== 1) {
1605 full_update
|= update_palette16(s
);
1606 if (s
->sr
[0x01] & 8) {
1607 v
= VGA_DRAW_LINE2D2
;
1614 switch(s
->get_bpp(s
)) {
1617 full_update
|= update_palette256(s
);
1618 v
= VGA_DRAW_LINE8D2
;
1622 full_update
|= update_palette256(s
);
1627 v
= VGA_DRAW_LINE15
;
1631 v
= VGA_DRAW_LINE16
;
1635 v
= VGA_DRAW_LINE24
;
1639 v
= VGA_DRAW_LINE32
;
1644 vga_draw_line
= vga_draw_line_table
[v
* NB_DEPTHS
+ get_depth_index(s
->ds
)];
1646 if (disp_width
!= s
->last_width
||
1647 height
!= s
->last_height
) {
1648 qemu_console_resize(s
->console
, disp_width
, height
);
1649 s
->last_scr_width
= disp_width
;
1650 s
->last_scr_height
= height
;
1651 s
->last_width
= disp_width
;
1652 s
->last_height
= height
;
1655 if (s
->cursor_invalidate
)
1656 s
->cursor_invalidate(s
);
1658 line_offset
= s
->line_offset
;
1660 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",
1661 width
, height
, v
, line_offset
, s
->cr
[9], s
->cr
[0x17], s
->line_compare
, s
->sr
[0x01]);
1663 addr1
= (s
->start_addr
* 4);
1664 bwidth
= (width
* bits
+ 7) / 8;
1666 page_min
= 0x7fffffff;
1669 linesize
= s
->ds
->linesize
;
1671 for(y
= 0; y
< height
; y
++) {
1673 if (!(s
->cr
[0x17] & 1)) {
1675 /* CGA compatibility handling */
1676 shift
= 14 + ((s
->cr
[0x17] >> 6) & 1);
1677 addr
= (addr
& ~(1 << shift
)) | ((y1
& 1) << shift
);
1679 if (!(s
->cr
[0x17] & 2)) {
1680 addr
= (addr
& ~0x8000) | ((y1
& 2) << 14);
1682 page0
= s
->vram_offset
+ (addr
& TARGET_PAGE_MASK
);
1683 page1
= s
->vram_offset
+ ((addr
+ bwidth
- 1) & TARGET_PAGE_MASK
);
1684 update
= full_update
|
1685 cpu_physical_memory_get_dirty(page0
, VGA_DIRTY_FLAG
) |
1686 cpu_physical_memory_get_dirty(page1
, VGA_DIRTY_FLAG
);
1687 if ((page1
- page0
) > TARGET_PAGE_SIZE
) {
1688 /* if wide line, can use another page */
1689 update
|= cpu_physical_memory_get_dirty(page0
+ TARGET_PAGE_SIZE
,
1692 /* explicit invalidation for the hardware cursor */
1693 update
|= (s
->invalidated_y_table
[y
>> 5] >> (y
& 0x1f)) & 1;
1697 if (page0
< page_min
)
1699 if (page1
> page_max
)
1701 vga_draw_line(s
, d
, s
->vram_ptr
+ addr
, width
);
1702 if (s
->cursor_draw_line
)
1703 s
->cursor_draw_line(s
, d
, y
);
1706 /* flush to display */
1707 dpy_update(s
->ds
, 0, y_start
,
1708 disp_width
, y
- y_start
);
1713 mask
= (s
->cr
[0x17] & 3) ^ 3;
1714 if ((y1
& mask
) == mask
)
1715 addr1
+= line_offset
;
1717 multi_run
= multi_scan
;
1721 /* line compare acts on the displayed lines */
1722 if (y
== s
->line_compare
)
1727 /* flush to display */
1728 dpy_update(s
->ds
, 0, y_start
,
1729 disp_width
, y
- y_start
);
1731 /* reset modified pages */
1732 if (page_max
!= -1) {
1733 cpu_physical_memory_reset_dirty(page_min
, page_max
+ TARGET_PAGE_SIZE
,
1736 memset(s
->invalidated_y_table
, 0, ((height
+ 31) >> 5) * 4);
1739 static void vga_draw_blank(VGAState
*s
, int full_update
)
1746 if (s
->last_scr_width
<= 0 || s
->last_scr_height
<= 0)
1748 if (s
->ds
->depth
== 8)
1749 val
= s
->rgb_to_pixel(0, 0, 0);
1752 w
= s
->last_scr_width
* ((s
->ds
->depth
+ 7) >> 3);
1754 for(i
= 0; i
< s
->last_scr_height
; i
++) {
1756 d
+= s
->ds
->linesize
;
1758 dpy_update(s
->ds
, 0, 0,
1759 s
->last_scr_width
, s
->last_scr_height
);
1762 #define GMODE_TEXT 0
1763 #define GMODE_GRAPH 1
1764 #define GMODE_BLANK 2
1766 static void vga_update_display(void *opaque
)
1768 VGAState
*s
= (VGAState
*)opaque
;
1769 int full_update
, graphic_mode
;
1771 if (s
->ds
->depth
== 0) {
1775 rgb_to_pixel_dup_table
[get_depth_index(s
->ds
)];
1778 if (!(s
->ar_index
& 0x20)) {
1779 graphic_mode
= GMODE_BLANK
;
1781 graphic_mode
= s
->gr
[6] & 1;
1783 if (graphic_mode
!= s
->graphic_mode
) {
1784 s
->graphic_mode
= graphic_mode
;
1787 switch(graphic_mode
) {
1789 vga_draw_text(s
, full_update
);
1792 vga_draw_graphic(s
, full_update
);
1796 vga_draw_blank(s
, full_update
);
1802 /* force a full display refresh */
1803 static void vga_invalidate_display(void *opaque
)
1805 VGAState
*s
= (VGAState
*)opaque
;
1808 s
->last_height
= -1;
1811 static void vga_reset(VGAState
*s
)
1813 memset(s
, 0, sizeof(VGAState
));
1814 s
->graphic_mode
= -1; /* force full update */
1817 #define TEXTMODE_X(x) ((x) % width)
1818 #define TEXTMODE_Y(x) ((x) / width)
1819 #define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1820 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1821 /* relay text rendering to the display driver
1822 * instead of doing a full vga_update_display() */
1823 static void vga_update_text(void *opaque
, console_ch_t
*chardata
)
1825 VGAState
*s
= (VGAState
*) opaque
;
1826 int graphic_mode
, i
, cursor_offset
, cursor_visible
;
1827 int cw
, cheight
, width
, height
, size
, c_min
, c_max
;
1829 console_ch_t
*dst
, val
;
1830 char msg_buffer
[80];
1831 int full_update
= 0;
1833 if (!(s
->ar_index
& 0x20)) {
1834 graphic_mode
= GMODE_BLANK
;
1836 graphic_mode
= s
->gr
[6] & 1;
1838 if (graphic_mode
!= s
->graphic_mode
) {
1839 s
->graphic_mode
= graphic_mode
;
1842 if (s
->last_width
== -1) {
1847 switch (graphic_mode
) {
1849 /* TODO: update palette */
1850 full_update
|= update_basic_params(s
);
1852 /* total width & height */
1853 cheight
= (s
->cr
[9] & 0x1f) + 1;
1855 if (!(s
->sr
[1] & 0x01))
1857 if (s
->sr
[1] & 0x08)
1858 cw
= 16; /* NOTE: no 18 pixel wide */
1859 width
= (s
->cr
[0x01] + 1);
1860 if (s
->cr
[0x06] == 100) {
1861 /* ugly hack for CGA 160x100x16 - explain me the logic */
1864 height
= s
->cr
[0x12] |
1865 ((s
->cr
[0x07] & 0x02) << 7) |
1866 ((s
->cr
[0x07] & 0x40) << 3);
1867 height
= (height
+ 1) / cheight
;
1870 size
= (height
* width
);
1871 if (size
> CH_ATTR_SIZE
) {
1875 snprintf(msg_buffer
, sizeof(msg_buffer
), "%i x %i Text mode",
1880 if (width
!= s
->last_width
|| height
!= s
->last_height
||
1881 cw
!= s
->last_cw
|| cheight
!= s
->last_ch
) {
1882 s
->last_scr_width
= width
* cw
;
1883 s
->last_scr_height
= height
* cheight
;
1884 qemu_console_resize(s
->console
, width
, height
);
1885 s
->last_width
= width
;
1886 s
->last_height
= height
;
1887 s
->last_ch
= cheight
;
1892 /* Update "hardware" cursor */
1893 cursor_offset
= ((s
->cr
[0x0e] << 8) | s
->cr
[0x0f]) - s
->start_addr
;
1894 if (cursor_offset
!= s
->cursor_offset
||
1895 s
->cr
[0xa] != s
->cursor_start
||
1896 s
->cr
[0xb] != s
->cursor_end
|| full_update
) {
1897 cursor_visible
= !(s
->cr
[0xa] & 0x20);
1898 if (cursor_visible
&& cursor_offset
< size
&& cursor_offset
>= 0)
1900 TEXTMODE_X(cursor_offset
),
1901 TEXTMODE_Y(cursor_offset
));
1903 dpy_cursor(s
->ds
, -1, -1);
1904 s
->cursor_offset
= cursor_offset
;
1905 s
->cursor_start
= s
->cr
[0xa];
1906 s
->cursor_end
= s
->cr
[0xb];
1909 src
= (uint32_t *) s
->vram_ptr
+ s
->start_addr
;
1913 for (i
= 0; i
< size
; src
++, dst
++, i
++)
1914 console_write_ch(dst
, VMEM2CHTYPE(*src
));
1916 dpy_update(s
->ds
, 0, 0, width
, height
);
1920 for (i
= 0; i
< size
; src
++, dst
++, i
++) {
1921 console_write_ch(&val
, VMEM2CHTYPE(*src
));
1929 for (; i
< size
; src
++, dst
++, i
++) {
1930 console_write_ch(&val
, VMEM2CHTYPE(*src
));
1937 if (c_min
<= c_max
) {
1938 i
= TEXTMODE_Y(c_min
);
1939 dpy_update(s
->ds
, 0, i
, width
, TEXTMODE_Y(c_max
) - i
+ 1);
1948 s
->get_resolution(s
, &width
, &height
);
1949 snprintf(msg_buffer
, sizeof(msg_buffer
), "%i x %i Graphic mode",
1957 snprintf(msg_buffer
, sizeof(msg_buffer
), "VGA Blank mode");
1961 /* Display a message */
1963 s
->last_height
= height
= 3;
1964 dpy_cursor(s
->ds
, -1, -1);
1965 qemu_console_resize(s
->console
, s
->last_width
, height
);
1967 for (dst
= chardata
, i
= 0; i
< s
->last_width
* height
; i
++)
1968 console_write_ch(dst
++, ' ');
1970 size
= strlen(msg_buffer
);
1971 width
= (s
->last_width
- size
) / 2;
1972 dst
= chardata
+ s
->last_width
+ width
;
1973 for (i
= 0; i
< size
; i
++)
1974 console_write_ch(dst
++, 0x00200100 | msg_buffer
[i
]);
1976 dpy_update(s
->ds
, 0, 0, s
->last_width
, height
);
1979 static CPUReadMemoryFunc
*vga_mem_read
[3] = {
1985 static CPUWriteMemoryFunc
*vga_mem_write
[3] = {
1991 static void vga_save(QEMUFile
*f
, void *opaque
)
1993 VGAState
*s
= opaque
;
1997 pci_device_save(s
->pci_dev
, f
);
1999 qemu_put_be32s(f
, &s
->latch
);
2000 qemu_put_8s(f
, &s
->sr_index
);
2001 qemu_put_buffer(f
, s
->sr
, 8);
2002 qemu_put_8s(f
, &s
->gr_index
);
2003 qemu_put_buffer(f
, s
->gr
, 16);
2004 qemu_put_8s(f
, &s
->ar_index
);
2005 qemu_put_buffer(f
, s
->ar
, 21);
2006 qemu_put_be32(f
, s
->ar_flip_flop
);
2007 qemu_put_8s(f
, &s
->cr_index
);
2008 qemu_put_buffer(f
, s
->cr
, 256);
2009 qemu_put_8s(f
, &s
->msr
);
2010 qemu_put_8s(f
, &s
->fcr
);
2011 qemu_put_byte(f
, s
->st00
);
2012 qemu_put_8s(f
, &s
->st01
);
2014 qemu_put_8s(f
, &s
->dac_state
);
2015 qemu_put_8s(f
, &s
->dac_sub_index
);
2016 qemu_put_8s(f
, &s
->dac_read_index
);
2017 qemu_put_8s(f
, &s
->dac_write_index
);
2018 qemu_put_buffer(f
, s
->dac_cache
, 3);
2019 qemu_put_buffer(f
, s
->palette
, 768);
2021 qemu_put_be32(f
, s
->bank_offset
);
2022 #ifdef CONFIG_BOCHS_VBE
2023 qemu_put_byte(f
, 1);
2024 qemu_put_be16s(f
, &s
->vbe_index
);
2025 for(i
= 0; i
< VBE_DISPI_INDEX_NB
; i
++)
2026 qemu_put_be16s(f
, &s
->vbe_regs
[i
]);
2027 qemu_put_be32s(f
, &s
->vbe_start_addr
);
2028 qemu_put_be32s(f
, &s
->vbe_line_offset
);
2029 qemu_put_be32s(f
, &s
->vbe_bank_mask
);
2031 qemu_put_byte(f
, 0);
2035 static int vga_load(QEMUFile
*f
, void *opaque
, int version_id
)
2037 VGAState
*s
= opaque
;
2043 if (s
->pci_dev
&& version_id
>= 2) {
2044 ret
= pci_device_load(s
->pci_dev
, f
);
2049 qemu_get_be32s(f
, &s
->latch
);
2050 qemu_get_8s(f
, &s
->sr_index
);
2051 qemu_get_buffer(f
, s
->sr
, 8);
2052 qemu_get_8s(f
, &s
->gr_index
);
2053 qemu_get_buffer(f
, s
->gr
, 16);
2054 qemu_get_8s(f
, &s
->ar_index
);
2055 qemu_get_buffer(f
, s
->ar
, 21);
2056 s
->ar_flip_flop
=qemu_get_be32(f
);
2057 qemu_get_8s(f
, &s
->cr_index
);
2058 qemu_get_buffer(f
, s
->cr
, 256);
2059 qemu_get_8s(f
, &s
->msr
);
2060 qemu_get_8s(f
, &s
->fcr
);
2061 qemu_get_8s(f
, &s
->st00
);
2062 qemu_get_8s(f
, &s
->st01
);
2064 qemu_get_8s(f
, &s
->dac_state
);
2065 qemu_get_8s(f
, &s
->dac_sub_index
);
2066 qemu_get_8s(f
, &s
->dac_read_index
);
2067 qemu_get_8s(f
, &s
->dac_write_index
);
2068 qemu_get_buffer(f
, s
->dac_cache
, 3);
2069 qemu_get_buffer(f
, s
->palette
, 768);
2071 s
->bank_offset
=qemu_get_be32(f
);
2072 is_vbe
= qemu_get_byte(f
);
2073 #ifdef CONFIG_BOCHS_VBE
2076 qemu_get_be16s(f
, &s
->vbe_index
);
2077 for(i
= 0; i
< VBE_DISPI_INDEX_NB
; i
++)
2078 qemu_get_be16s(f
, &s
->vbe_regs
[i
]);
2079 qemu_get_be32s(f
, &s
->vbe_start_addr
);
2080 qemu_get_be32s(f
, &s
->vbe_line_offset
);
2081 qemu_get_be32s(f
, &s
->vbe_bank_mask
);
2088 s
->graphic_mode
= -1;
2092 typedef struct PCIVGAState
{
2097 static void vga_map(PCIDevice
*pci_dev
, int region_num
,
2098 uint32_t addr
, uint32_t size
, int type
)
2100 PCIVGAState
*d
= (PCIVGAState
*)pci_dev
;
2101 VGAState
*s
= &d
->vga_state
;
2102 if (region_num
== PCI_ROM_SLOT
) {
2103 cpu_register_physical_memory(addr
, s
->bios_size
, s
->bios_offset
);
2105 cpu_register_physical_memory(addr
, s
->vram_size
, s
->vram_offset
);
2109 void vga_common_init(VGAState
*s
, DisplayState
*ds
, uint8_t *vga_ram_base
,
2110 unsigned long vga_ram_offset
, int vga_ram_size
)
2114 for(i
= 0;i
< 256; i
++) {
2116 for(j
= 0; j
< 8; j
++) {
2117 v
|= ((i
>> j
) & 1) << (j
* 4);
2122 for(j
= 0; j
< 4; j
++) {
2123 v
|= ((i
>> (2 * j
)) & 3) << (j
* 4);
2127 for(i
= 0; i
< 16; i
++) {
2129 for(j
= 0; j
< 4; j
++) {
2132 v
|= b
<< (2 * j
+ 1);
2139 s
->vram_ptr
= vga_ram_base
;
2140 s
->vram_offset
= vga_ram_offset
;
2141 s
->vram_size
= vga_ram_size
;
2143 s
->get_bpp
= vga_get_bpp
;
2144 s
->get_offsets
= vga_get_offsets
;
2145 s
->get_resolution
= vga_get_resolution
;
2146 s
->update
= vga_update_display
;
2147 s
->invalidate
= vga_invalidate_display
;
2148 s
->screen_dump
= vga_screen_dump
;
2149 s
->text_update
= vga_update_text
;
2150 switch (vga_retrace_method
) {
2151 case VGA_RETRACE_DUMB
:
2152 s
->retrace
= vga_dumb_retrace
;
2153 s
->update_retrace_info
= vga_dumb_update_retrace_info
;
2156 case VGA_RETRACE_PRECISE
:
2157 s
->retrace
= vga_precise_retrace
;
2158 s
->update_retrace_info
= vga_precise_update_retrace_info
;
2159 memset(&s
->retrace_info
, 0, sizeof (s
->retrace_info
));
2164 /* used by both ISA and PCI */
2165 void vga_init(VGAState
*s
)
2169 register_savevm("vga", 0, 2, vga_save
, vga_load
, s
);
2171 register_ioport_write(0x3c0, 16, 1, vga_ioport_write
, s
);
2173 register_ioport_write(0x3b4, 2, 1, vga_ioport_write
, s
);
2174 register_ioport_write(0x3d4, 2, 1, vga_ioport_write
, s
);
2175 register_ioport_write(0x3ba, 1, 1, vga_ioport_write
, s
);
2176 register_ioport_write(0x3da, 1, 1, vga_ioport_write
, s
);
2178 register_ioport_read(0x3c0, 16, 1, vga_ioport_read
, s
);
2180 register_ioport_read(0x3b4, 2, 1, vga_ioport_read
, s
);
2181 register_ioport_read(0x3d4, 2, 1, vga_ioport_read
, s
);
2182 register_ioport_read(0x3ba, 1, 1, vga_ioport_read
, s
);
2183 register_ioport_read(0x3da, 1, 1, vga_ioport_read
, s
);
2186 #ifdef CONFIG_BOCHS_VBE
2187 s
->vbe_regs
[VBE_DISPI_INDEX_ID
] = VBE_DISPI_ID0
;
2188 s
->vbe_bank_mask
= ((s
->vram_size
>> 16) - 1);
2189 #if defined (TARGET_I386)
2190 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index
, s
);
2191 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data
, s
);
2193 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index
, s
);
2194 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data
, s
);
2196 /* old Bochs IO ports */
2197 register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index
, s
);
2198 register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data
, s
);
2200 register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index
, s
);
2201 register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data
, s
);
2203 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index
, s
);
2204 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data
, s
);
2206 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index
, s
);
2207 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data
, s
);
2209 #endif /* CONFIG_BOCHS_VBE */
2211 vga_io_memory
= cpu_register_io_memory(0, vga_mem_read
, vga_mem_write
, s
);
2212 cpu_register_physical_memory(isa_mem_base
+ 0x000a0000, 0x20000,
2216 /* Memory mapped interface */
2217 static uint32_t vga_mm_readb (void *opaque
, target_phys_addr_t addr
)
2219 VGAState
*s
= opaque
;
2221 return vga_ioport_read(s
, (addr
- s
->base_ctrl
) >> s
->it_shift
) & 0xff;
2224 static void vga_mm_writeb (void *opaque
,
2225 target_phys_addr_t addr
, uint32_t value
)
2227 VGAState
*s
= opaque
;
2229 vga_ioport_write(s
, (addr
- s
->base_ctrl
) >> s
->it_shift
, value
& 0xff);
2232 static uint32_t vga_mm_readw (void *opaque
, target_phys_addr_t addr
)
2234 VGAState
*s
= opaque
;
2236 return vga_ioport_read(s
, (addr
- s
->base_ctrl
) >> s
->it_shift
) & 0xffff;
2239 static void vga_mm_writew (void *opaque
,
2240 target_phys_addr_t addr
, uint32_t value
)
2242 VGAState
*s
= opaque
;
2244 vga_ioport_write(s
, (addr
- s
->base_ctrl
) >> s
->it_shift
, value
& 0xffff);
2247 static uint32_t vga_mm_readl (void *opaque
, target_phys_addr_t addr
)
2249 VGAState
*s
= opaque
;
2251 return vga_ioport_read(s
, (addr
- s
->base_ctrl
) >> s
->it_shift
);
2254 static void vga_mm_writel (void *opaque
,
2255 target_phys_addr_t addr
, uint32_t value
)
2257 VGAState
*s
= opaque
;
2259 vga_ioport_write(s
, (addr
- s
->base_ctrl
) >> s
->it_shift
, value
);
2262 static CPUReadMemoryFunc
*vga_mm_read_ctrl
[] = {
2268 static CPUWriteMemoryFunc
*vga_mm_write_ctrl
[] = {
2274 static void vga_mm_init(VGAState
*s
, target_phys_addr_t vram_base
,
2275 target_phys_addr_t ctrl_base
, int it_shift
)
2277 int s_ioport_ctrl
, vga_io_memory
;
2279 s
->base_ctrl
= ctrl_base
;
2280 s
->it_shift
= it_shift
;
2281 s_ioport_ctrl
= cpu_register_io_memory(0, vga_mm_read_ctrl
, vga_mm_write_ctrl
, s
);
2282 vga_io_memory
= cpu_register_io_memory(0, vga_mem_read
, vga_mem_write
, s
);
2284 register_savevm("vga", 0, 2, vga_save
, vga_load
, s
);
2286 cpu_register_physical_memory(ctrl_base
, 0x100000, s_ioport_ctrl
);
2288 cpu_register_physical_memory(vram_base
+ 0x000a0000, 0x20000, vga_io_memory
);
2291 int isa_vga_init(DisplayState
*ds
, uint8_t *vga_ram_base
,
2292 unsigned long vga_ram_offset
, int vga_ram_size
)
2296 s
= qemu_mallocz(sizeof(VGAState
));
2300 vga_common_init(s
, ds
, vga_ram_base
, vga_ram_offset
, vga_ram_size
);
2303 s
->console
= graphic_console_init(s
->ds
, s
->update
, s
->invalidate
,
2304 s
->screen_dump
, s
->text_update
, s
);
2306 #ifdef CONFIG_BOCHS_VBE
2307 /* XXX: use optimized standard vga accesses */
2308 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS
,
2309 vga_ram_size
, vga_ram_offset
);
2314 int isa_vga_mm_init(DisplayState
*ds
, uint8_t *vga_ram_base
,
2315 unsigned long vga_ram_offset
, int vga_ram_size
,
2316 target_phys_addr_t vram_base
, target_phys_addr_t ctrl_base
,
2321 s
= qemu_mallocz(sizeof(VGAState
));
2325 vga_common_init(s
, ds
, vga_ram_base
, vga_ram_offset
, vga_ram_size
);
2326 vga_mm_init(s
, vram_base
, ctrl_base
, it_shift
);
2328 s
->console
= graphic_console_init(s
->ds
, s
->update
, s
->invalidate
,
2329 s
->screen_dump
, s
->text_update
, s
);
2331 #ifdef CONFIG_BOCHS_VBE
2332 /* XXX: use optimized standard vga accesses */
2333 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS
,
2334 vga_ram_size
, vga_ram_offset
);
2339 int pci_vga_init(PCIBus
*bus
, DisplayState
*ds
, uint8_t *vga_ram_base
,
2340 unsigned long vga_ram_offset
, int vga_ram_size
,
2341 unsigned long vga_bios_offset
, int vga_bios_size
)
2347 d
= (PCIVGAState
*)pci_register_device(bus
, "VGA",
2348 sizeof(PCIVGAState
),
2354 vga_common_init(s
, ds
, vga_ram_base
, vga_ram_offset
, vga_ram_size
);
2357 s
->console
= graphic_console_init(s
->ds
, s
->update
, s
->invalidate
,
2358 s
->screen_dump
, s
->text_update
, s
);
2360 s
->pci_dev
= &d
->dev
;
2362 pci_conf
= d
->dev
.config
;
2363 pci_conf
[0x00] = 0x34; // dummy VGA (same as Bochs ID)
2364 pci_conf
[0x01] = 0x12;
2365 pci_conf
[0x02] = 0x11;
2366 pci_conf
[0x03] = 0x11;
2367 pci_conf
[0x0a] = 0x00; // VGA controller
2368 pci_conf
[0x0b] = 0x03;
2369 pci_conf
[0x0e] = 0x00; // header_type
2371 /* XXX: vga_ram_size must be a power of two */
2372 pci_register_io_region(&d
->dev
, 0, vga_ram_size
,
2373 PCI_ADDRESS_SPACE_MEM_PREFETCH
, vga_map
);
2374 if (vga_bios_size
!= 0) {
2375 unsigned int bios_total_size
;
2376 s
->bios_offset
= vga_bios_offset
;
2377 s
->bios_size
= vga_bios_size
;
2378 /* must be a power of two */
2379 bios_total_size
= 1;
2380 while (bios_total_size
< vga_bios_size
)
2381 bios_total_size
<<= 1;
2382 pci_register_io_region(&d
->dev
, PCI_ROM_SLOT
, bios_total_size
,
2383 PCI_ADDRESS_SPACE_MEM_PREFETCH
, vga_map
);
2388 /********************************************************/
2389 /* vga screen dump */
2391 static int vga_save_w
, vga_save_h
;
2393 static void vga_save_dpy_update(DisplayState
*s
,
2394 int x
, int y
, int w
, int h
)
2398 static void vga_save_dpy_resize(DisplayState
*s
, int w
, int h
)
2400 s
->linesize
= w
* 4;
2401 s
->data
= qemu_malloc(h
* s
->linesize
);
2406 static void vga_save_dpy_refresh(DisplayState
*s
)
2410 int ppm_save(const char *filename
, uint8_t *data
,
2411 int w
, int h
, int linesize
)
2418 f
= fopen(filename
, "wb");
2421 fprintf(f
, "P6\n%d %d\n%d\n",
2424 for(y
= 0; y
< h
; y
++) {
2426 for(x
= 0; x
< w
; x
++) {
2428 fputc((v
>> 16) & 0xff, f
);
2429 fputc((v
>> 8) & 0xff, f
);
2430 fputc((v
) & 0xff, f
);
2439 /* save the vga display in a PPM image even if no display is
2441 static void vga_screen_dump(void *opaque
, const char *filename
)
2443 VGAState
*s
= (VGAState
*)opaque
;
2444 DisplayState
*saved_ds
, ds1
, *ds
= &ds1
;
2446 /* XXX: this is a little hackish */
2447 vga_invalidate_display(s
);
2450 memset(ds
, 0, sizeof(DisplayState
));
2451 ds
->dpy_update
= vga_save_dpy_update
;
2452 ds
->dpy_resize
= vga_save_dpy_resize
;
2453 ds
->dpy_refresh
= vga_save_dpy_refresh
;
2457 s
->graphic_mode
= -1;
2458 vga_update_display(s
);
2461 ppm_save(filename
, ds
->data
, vga_save_w
, vga_save_h
,
2463 qemu_free(ds
->data
);