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
30 #include "pixel_ops.h"
31 #include "qemu-timer.h"
35 //#define DEBUG_VGA_MEM
36 //#define DEBUG_VGA_REG
38 //#define DEBUG_BOCHS_VBE
41 * Video Graphics Array (VGA)
43 * Chipset docs for original IBM VGA:
44 * http://www.mcamafia.de/pdf/ibm_vgaxga_trm2.pdf
47 * http://www.osdever.net/FreeVGA/home.htm
49 * Standard VGA features and Bochs VBE extensions are implemented.
52 /* force some bits to zero */
53 const uint8_t sr_mask
[8] = {
64 const uint8_t gr_mask
[16] = {
83 #define cbswap_32(__x) \
85 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
86 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
87 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
88 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
90 #ifdef HOST_WORDS_BIGENDIAN
91 #define PAT(x) cbswap_32(x)
96 #ifdef HOST_WORDS_BIGENDIAN
102 #ifdef HOST_WORDS_BIGENDIAN
103 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
105 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
108 static const uint32_t mask16
[16] = {
129 #ifdef HOST_WORDS_BIGENDIAN
132 #define PAT(x) cbswap_32(x)
135 static const uint32_t dmask16
[16] = {
154 static const uint32_t dmask4
[4] = {
161 static uint32_t expand4
[256];
162 static uint16_t expand2
[256];
163 static uint8_t expand4to8
[16];
165 static void vga_screen_dump(void *opaque
, const char *filename
);
166 static const char *screen_dump_filename
;
167 static DisplayChangeListener
*screen_dump_dcl
;
169 static void vga_update_memory_access(VGACommonState
*s
)
171 MemoryRegion
*region
, *old_region
= s
->chain4_alias
;
172 target_phys_addr_t base
, offset
, size
;
174 s
->chain4_alias
= NULL
;
176 if ((s
->sr
[VGA_SEQ_PLANE_WRITE
] & VGA_SR02_ALL_PLANES
) ==
177 VGA_SR02_ALL_PLANES
&& s
->sr
[VGA_SEQ_MEMORY_MODE
] & VGA_SR04_CHN_4M
) {
179 switch ((s
->gr
[VGA_GFX_MISC
] >> 2) & 3) {
187 offset
= s
->bank_offset
;
199 base
+= isa_mem_base
;
200 region
= g_malloc(sizeof(*region
));
201 memory_region_init_alias(region
, "vga.chain4", &s
->vram
, offset
, size
);
202 memory_region_add_subregion_overlap(s
->legacy_address_space
, base
,
204 s
->chain4_alias
= region
;
207 memory_region_del_subregion(s
->legacy_address_space
, old_region
);
208 memory_region_destroy(old_region
);
210 s
->plane_updated
= 0xf;
214 static void vga_dumb_update_retrace_info(VGACommonState
*s
)
219 static void vga_precise_update_retrace_info(VGACommonState
*s
)
222 int hretr_start_char
;
223 int hretr_skew_chars
;
227 int vretr_start_line
;
236 const int clk_hz
[] = {25175000, 28322000, 25175000, 25175000};
237 int64_t chars_per_sec
;
238 struct vga_precise_retrace
*r
= &s
->retrace_info
.precise
;
240 htotal_chars
= s
->cr
[VGA_CRTC_H_TOTAL
] + 5;
241 hretr_start_char
= s
->cr
[VGA_CRTC_H_SYNC_START
];
242 hretr_skew_chars
= (s
->cr
[VGA_CRTC_H_SYNC_END
] >> 5) & 3;
243 hretr_end_char
= s
->cr
[VGA_CRTC_H_SYNC_END
] & 0x1f;
245 vtotal_lines
= (s
->cr
[VGA_CRTC_V_TOTAL
] |
246 (((s
->cr
[VGA_CRTC_OVERFLOW
] & 1) |
247 ((s
->cr
[VGA_CRTC_OVERFLOW
] >> 4) & 2)) << 8)) + 2;
248 vretr_start_line
= s
->cr
[VGA_CRTC_V_SYNC_START
] |
249 ((((s
->cr
[VGA_CRTC_OVERFLOW
] >> 2) & 1) |
250 ((s
->cr
[VGA_CRTC_OVERFLOW
] >> 6) & 2)) << 8);
251 vretr_end_line
= s
->cr
[VGA_CRTC_V_SYNC_END
] & 0xf;
253 clocking_mode
= (s
->sr
[VGA_SEQ_CLOCK_MODE
] >> 3) & 1;
254 clock_sel
= (s
->msr
>> 2) & 3;
255 dots
= (s
->msr
& 1) ? 8 : 9;
257 chars_per_sec
= clk_hz
[clock_sel
] / dots
;
259 htotal_chars
<<= clocking_mode
;
261 r
->total_chars
= vtotal_lines
* htotal_chars
;
263 r
->ticks_per_char
= get_ticks_per_sec() / (r
->total_chars
* r
->freq
);
265 r
->ticks_per_char
= get_ticks_per_sec() / chars_per_sec
;
268 r
->vstart
= vretr_start_line
;
269 r
->vend
= r
->vstart
+ vretr_end_line
+ 1;
271 r
->hstart
= hretr_start_char
+ hretr_skew_chars
;
272 r
->hend
= r
->hstart
+ hretr_end_char
+ 1;
273 r
->htotal
= htotal_chars
;
276 div2
= (s
->cr
[VGA_CRTC_MODE
] >> 2) & 1;
277 sldiv2
= (s
->cr
[VGA_CRTC_MODE
] >> 3) & 1;
287 "div2 = %d sldiv2 = %d\n"
288 "clocking_mode = %d\n"
289 "clock_sel = %d %d\n"
291 "ticks/char = %" PRId64
"\n"
293 (double) get_ticks_per_sec() / (r
->ticks_per_char
* r
->total_chars
),
311 static uint8_t vga_precise_retrace(VGACommonState
*s
)
313 struct vga_precise_retrace
*r
= &s
->retrace_info
.precise
;
314 uint8_t val
= s
->st01
& ~(ST01_V_RETRACE
| ST01_DISP_ENABLE
);
316 if (r
->total_chars
) {
317 int cur_line
, cur_line_char
, cur_char
;
320 cur_tick
= qemu_get_clock_ns(vm_clock
);
322 cur_char
= (cur_tick
/ r
->ticks_per_char
) % r
->total_chars
;
323 cur_line
= cur_char
/ r
->htotal
;
325 if (cur_line
>= r
->vstart
&& cur_line
<= r
->vend
) {
326 val
|= ST01_V_RETRACE
| ST01_DISP_ENABLE
;
328 cur_line_char
= cur_char
% r
->htotal
;
329 if (cur_line_char
>= r
->hstart
&& cur_line_char
<= r
->hend
) {
330 val
|= ST01_DISP_ENABLE
;
336 return s
->st01
^ (ST01_V_RETRACE
| ST01_DISP_ENABLE
);
340 static uint8_t vga_dumb_retrace(VGACommonState
*s
)
342 return s
->st01
^ (ST01_V_RETRACE
| ST01_DISP_ENABLE
);
345 int vga_ioport_invalid(VGACommonState
*s
, uint32_t addr
)
347 if (s
->msr
& VGA_MIS_COLOR
) {
349 return (addr
>= 0x3b0 && addr
<= 0x3bf);
352 return (addr
>= 0x3d0 && addr
<= 0x3df);
356 uint32_t vga_ioport_read(void *opaque
, uint32_t addr
)
358 VGACommonState
*s
= opaque
;
361 if (vga_ioport_invalid(s
, addr
)) {
366 if (s
->ar_flip_flop
== 0) {
373 index
= s
->ar_index
& 0x1f;
374 if (index
< VGA_ATT_C
) {
387 val
= s
->sr
[s
->sr_index
];
389 printf("vga: read SR%x = 0x%02x\n", s
->sr_index
, val
);
396 val
= s
->dac_write_index
;
399 val
= s
->palette
[s
->dac_read_index
* 3 + s
->dac_sub_index
];
400 if (++s
->dac_sub_index
== 3) {
401 s
->dac_sub_index
= 0;
415 val
= s
->gr
[s
->gr_index
];
417 printf("vga: read GR%x = 0x%02x\n", s
->gr_index
, val
);
426 val
= s
->cr
[s
->cr_index
];
428 printf("vga: read CR%x = 0x%02x\n", s
->cr_index
, val
);
433 /* just toggle to fool polling */
434 val
= s
->st01
= s
->retrace(s
);
442 #if defined(DEBUG_VGA)
443 printf("VGA: read addr=0x%04x data=0x%02x\n", addr
, val
);
448 void vga_ioport_write(void *opaque
, uint32_t addr
, uint32_t val
)
450 VGACommonState
*s
= opaque
;
453 /* check port range access depending on color/monochrome mode */
454 if (vga_ioport_invalid(s
, addr
)) {
458 printf("VGA: write addr=0x%04x data=0x%02x\n", addr
, val
);
463 if (s
->ar_flip_flop
== 0) {
467 index
= s
->ar_index
& 0x1f;
469 case VGA_ATC_PALETTE0
... VGA_ATC_PALETTEF
:
470 s
->ar
[index
] = val
& 0x3f;
473 s
->ar
[index
] = val
& ~0x10;
475 case VGA_ATC_OVERSCAN
:
478 case VGA_ATC_PLANE_ENABLE
:
479 s
->ar
[index
] = val
& ~0xc0;
482 s
->ar
[index
] = val
& ~0xf0;
484 case VGA_ATC_COLOR_PAGE
:
485 s
->ar
[index
] = val
& ~0xf0;
491 s
->ar_flip_flop
^= 1;
494 s
->msr
= val
& ~0x10;
495 s
->update_retrace_info(s
);
498 s
->sr_index
= val
& 7;
502 printf("vga: write SR%x = 0x%02x\n", s
->sr_index
, val
);
504 s
->sr
[s
->sr_index
] = val
& sr_mask
[s
->sr_index
];
505 if (s
->sr_index
== VGA_SEQ_CLOCK_MODE
) {
506 s
->update_retrace_info(s
);
508 vga_update_memory_access(s
);
511 s
->dac_read_index
= val
;
512 s
->dac_sub_index
= 0;
516 s
->dac_write_index
= val
;
517 s
->dac_sub_index
= 0;
521 s
->dac_cache
[s
->dac_sub_index
] = val
;
522 if (++s
->dac_sub_index
== 3) {
523 memcpy(&s
->palette
[s
->dac_write_index
* 3], s
->dac_cache
, 3);
524 s
->dac_sub_index
= 0;
525 s
->dac_write_index
++;
529 s
->gr_index
= val
& 0x0f;
533 printf("vga: write GR%x = 0x%02x\n", s
->gr_index
, val
);
535 s
->gr
[s
->gr_index
] = val
& gr_mask
[s
->gr_index
];
536 vga_update_memory_access(s
);
545 printf("vga: write CR%x = 0x%02x\n", s
->cr_index
, val
);
547 /* handle CR0-7 protection */
548 if ((s
->cr
[VGA_CRTC_V_SYNC_END
] & VGA_CR11_LOCK_CR0_CR7
) &&
549 s
->cr_index
<= VGA_CRTC_OVERFLOW
) {
550 /* can always write bit 4 of CR7 */
551 if (s
->cr_index
== VGA_CRTC_OVERFLOW
) {
552 s
->cr
[VGA_CRTC_OVERFLOW
] = (s
->cr
[VGA_CRTC_OVERFLOW
] & ~0x10) |
557 s
->cr
[s
->cr_index
] = val
;
559 switch(s
->cr_index
) {
560 case VGA_CRTC_H_TOTAL
:
561 case VGA_CRTC_H_SYNC_START
:
562 case VGA_CRTC_H_SYNC_END
:
563 case VGA_CRTC_V_TOTAL
:
564 case VGA_CRTC_OVERFLOW
:
565 case VGA_CRTC_V_SYNC_END
:
567 s
->update_retrace_info(s
);
578 #ifdef CONFIG_BOCHS_VBE
579 static uint32_t vbe_ioport_read_index(void *opaque
, uint32_t addr
)
581 VGACommonState
*s
= opaque
;
587 static uint32_t vbe_ioport_read_data(void *opaque
, uint32_t addr
)
589 VGACommonState
*s
= opaque
;
592 if (s
->vbe_index
< VBE_DISPI_INDEX_NB
) {
593 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_GETCAPS
) {
594 switch(s
->vbe_index
) {
595 /* XXX: do not hardcode ? */
596 case VBE_DISPI_INDEX_XRES
:
597 val
= VBE_DISPI_MAX_XRES
;
599 case VBE_DISPI_INDEX_YRES
:
600 val
= VBE_DISPI_MAX_YRES
;
602 case VBE_DISPI_INDEX_BPP
:
603 val
= VBE_DISPI_MAX_BPP
;
606 val
= s
->vbe_regs
[s
->vbe_index
];
610 val
= s
->vbe_regs
[s
->vbe_index
];
612 } else if (s
->vbe_index
== VBE_DISPI_INDEX_VIDEO_MEMORY_64K
) {
613 val
= s
->vram_size
/ (64 * 1024);
617 #ifdef DEBUG_BOCHS_VBE
618 printf("VBE: read index=0x%x val=0x%x\n", s
->vbe_index
, val
);
623 static void vbe_ioport_write_index(void *opaque
, uint32_t addr
, uint32_t val
)
625 VGACommonState
*s
= opaque
;
629 static void vbe_ioport_write_data(void *opaque
, uint32_t addr
, uint32_t val
)
631 VGACommonState
*s
= opaque
;
633 if (s
->vbe_index
<= VBE_DISPI_INDEX_NB
) {
634 #ifdef DEBUG_BOCHS_VBE
635 printf("VBE: write index=0x%x val=0x%x\n", s
->vbe_index
, val
);
637 switch(s
->vbe_index
) {
638 case VBE_DISPI_INDEX_ID
:
639 if (val
== VBE_DISPI_ID0
||
640 val
== VBE_DISPI_ID1
||
641 val
== VBE_DISPI_ID2
||
642 val
== VBE_DISPI_ID3
||
643 val
== VBE_DISPI_ID4
) {
644 s
->vbe_regs
[s
->vbe_index
] = val
;
647 case VBE_DISPI_INDEX_XRES
:
648 if ((val
<= VBE_DISPI_MAX_XRES
) && ((val
& 7) == 0)) {
649 s
->vbe_regs
[s
->vbe_index
] = val
;
652 case VBE_DISPI_INDEX_YRES
:
653 if (val
<= VBE_DISPI_MAX_YRES
) {
654 s
->vbe_regs
[s
->vbe_index
] = val
;
657 case VBE_DISPI_INDEX_BPP
:
660 if (val
== 4 || val
== 8 || val
== 15 ||
661 val
== 16 || val
== 24 || val
== 32) {
662 s
->vbe_regs
[s
->vbe_index
] = val
;
665 case VBE_DISPI_INDEX_BANK
:
666 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
667 val
&= (s
->vbe_bank_mask
>> 2);
669 val
&= s
->vbe_bank_mask
;
671 s
->vbe_regs
[s
->vbe_index
] = val
;
672 s
->bank_offset
= (val
<< 16);
673 vga_update_memory_access(s
);
675 case VBE_DISPI_INDEX_ENABLE
:
676 if ((val
& VBE_DISPI_ENABLED
) &&
677 !(s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
)) {
678 int h
, shift_control
;
680 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] =
681 s
->vbe_regs
[VBE_DISPI_INDEX_XRES
];
682 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_HEIGHT
] =
683 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
];
684 s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
] = 0;
685 s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
] = 0;
687 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
688 s
->vbe_line_offset
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 1;
690 s
->vbe_line_offset
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] *
691 ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
692 s
->vbe_start_addr
= 0;
694 /* clear the screen (should be done in BIOS) */
695 if (!(val
& VBE_DISPI_NOCLEARMEM
)) {
696 memset(s
->vram_ptr
, 0,
697 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] * s
->vbe_line_offset
);
700 /* we initialize the VGA graphic mode (should be done
702 /* graphic mode + memory map 1 */
703 s
->gr
[VGA_GFX_MISC
] = (s
->gr
[VGA_GFX_MISC
] & ~0x0c) | 0x04 |
704 VGA_GR06_GRAPHICS_MODE
;
705 s
->cr
[VGA_CRTC_MODE
] |= 3; /* no CGA modes */
706 s
->cr
[VGA_CRTC_OFFSET
] = s
->vbe_line_offset
>> 3;
708 s
->cr
[VGA_CRTC_H_DISP
] =
709 (s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 3) - 1;
710 /* height (only meaningful if < 1024) */
711 h
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] - 1;
712 s
->cr
[VGA_CRTC_V_DISP_END
] = h
;
713 s
->cr
[VGA_CRTC_OVERFLOW
] = (s
->cr
[VGA_CRTC_OVERFLOW
] & ~0x42) |
714 ((h
>> 7) & 0x02) | ((h
>> 3) & 0x40);
715 /* line compare to 1023 */
716 s
->cr
[VGA_CRTC_LINE_COMPARE
] = 0xff;
717 s
->cr
[VGA_CRTC_OVERFLOW
] |= 0x10;
718 s
->cr
[VGA_CRTC_MAX_SCAN
] |= 0x40;
720 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
722 s
->sr
[VGA_SEQ_CLOCK_MODE
] &= ~8; /* no double line */
725 /* set chain 4 mode */
726 s
->sr
[VGA_SEQ_MEMORY_MODE
] |= VGA_SR04_CHN_4M
;
727 /* activate all planes */
728 s
->sr
[VGA_SEQ_PLANE_WRITE
] |= VGA_SR02_ALL_PLANES
;
730 s
->gr
[VGA_GFX_MODE
] = (s
->gr
[VGA_GFX_MODE
] & ~0x60) |
731 (shift_control
<< 5);
732 s
->cr
[VGA_CRTC_MAX_SCAN
] &= ~0x9f; /* no double scan */
734 /* XXX: the bios should do that */
737 s
->dac_8bit
= (val
& VBE_DISPI_8BIT_DAC
) > 0;
738 s
->vbe_regs
[s
->vbe_index
] = val
;
739 vga_update_memory_access(s
);
741 case VBE_DISPI_INDEX_VIRT_WIDTH
:
743 int w
, h
, line_offset
;
745 if (val
< s
->vbe_regs
[VBE_DISPI_INDEX_XRES
])
748 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
749 line_offset
= w
>> 1;
751 line_offset
= w
* ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
752 h
= s
->vram_size
/ line_offset
;
753 /* XXX: support weird bochs semantics ? */
754 if (h
< s
->vbe_regs
[VBE_DISPI_INDEX_YRES
])
756 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] = w
;
757 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_HEIGHT
] = h
;
758 s
->vbe_line_offset
= line_offset
;
761 case VBE_DISPI_INDEX_X_OFFSET
:
762 case VBE_DISPI_INDEX_Y_OFFSET
:
765 s
->vbe_regs
[s
->vbe_index
] = val
;
766 s
->vbe_start_addr
= s
->vbe_line_offset
* s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
];
767 x
= s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
];
768 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
769 s
->vbe_start_addr
+= x
>> 1;
771 s
->vbe_start_addr
+= x
* ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
772 s
->vbe_start_addr
>>= 2;
782 /* called for accesses between 0xa0000 and 0xc0000 */
783 uint32_t vga_mem_readb(VGACommonState
*s
, target_phys_addr_t addr
)
785 int memory_map_mode
, plane
;
788 /* convert to VGA memory offset */
789 memory_map_mode
= (s
->gr
[VGA_GFX_MISC
] >> 2) & 3;
791 switch(memory_map_mode
) {
797 addr
+= s
->bank_offset
;
812 if (s
->sr
[VGA_SEQ_MEMORY_MODE
] & VGA_SR04_CHN_4M
) {
813 /* chain 4 mode : simplest access */
814 ret
= s
->vram_ptr
[addr
];
815 } else if (s
->gr
[VGA_GFX_MODE
] & 0x10) {
816 /* odd/even mode (aka text mode mapping) */
817 plane
= (s
->gr
[VGA_GFX_PLANE_READ
] & 2) | (addr
& 1);
818 ret
= s
->vram_ptr
[((addr
& ~1) << 1) | plane
];
820 /* standard VGA latched access */
821 s
->latch
= ((uint32_t *)s
->vram_ptr
)[addr
];
823 if (!(s
->gr
[VGA_GFX_MODE
] & 0x08)) {
825 plane
= s
->gr
[VGA_GFX_PLANE_READ
];
826 ret
= GET_PLANE(s
->latch
, plane
);
829 ret
= (s
->latch
^ mask16
[s
->gr
[VGA_GFX_COMPARE_VALUE
]]) &
830 mask16
[s
->gr
[VGA_GFX_COMPARE_MASK
]];
839 /* called for accesses between 0xa0000 and 0xc0000 */
840 void vga_mem_writeb(VGACommonState
*s
, target_phys_addr_t addr
, uint32_t val
)
842 int memory_map_mode
, plane
, write_mode
, b
, func_select
, mask
;
843 uint32_t write_mask
, bit_mask
, set_mask
;
846 printf("vga: [0x" TARGET_FMT_plx
"] = 0x%02x\n", addr
, val
);
848 /* convert to VGA memory offset */
849 memory_map_mode
= (s
->gr
[VGA_GFX_MISC
] >> 2) & 3;
851 switch(memory_map_mode
) {
857 addr
+= s
->bank_offset
;
872 if (s
->sr
[VGA_SEQ_MEMORY_MODE
] & VGA_SR04_CHN_4M
) {
873 /* chain 4 mode : simplest access */
876 if (s
->sr
[VGA_SEQ_PLANE_WRITE
] & mask
) {
877 s
->vram_ptr
[addr
] = val
;
879 printf("vga: chain4: [0x" TARGET_FMT_plx
"]\n", addr
);
881 s
->plane_updated
|= mask
; /* only used to detect font change */
882 memory_region_set_dirty(&s
->vram
, addr
, 1);
884 } else if (s
->gr
[VGA_GFX_MODE
] & 0x10) {
885 /* odd/even mode (aka text mode mapping) */
886 plane
= (s
->gr
[VGA_GFX_PLANE_READ
] & 2) | (addr
& 1);
888 if (s
->sr
[VGA_SEQ_PLANE_WRITE
] & mask
) {
889 addr
= ((addr
& ~1) << 1) | plane
;
890 s
->vram_ptr
[addr
] = val
;
892 printf("vga: odd/even: [0x" TARGET_FMT_plx
"]\n", addr
);
894 s
->plane_updated
|= mask
; /* only used to detect font change */
895 memory_region_set_dirty(&s
->vram
, addr
, 1);
898 /* standard VGA latched access */
899 write_mode
= s
->gr
[VGA_GFX_MODE
] & 3;
904 b
= s
->gr
[VGA_GFX_DATA_ROTATE
] & 7;
905 val
= ((val
>> b
) | (val
<< (8 - b
))) & 0xff;
909 /* apply set/reset mask */
910 set_mask
= mask16
[s
->gr
[VGA_GFX_SR_ENABLE
]];
911 val
= (val
& ~set_mask
) |
912 (mask16
[s
->gr
[VGA_GFX_SR_VALUE
]] & set_mask
);
913 bit_mask
= s
->gr
[VGA_GFX_BIT_MASK
];
919 val
= mask16
[val
& 0x0f];
920 bit_mask
= s
->gr
[VGA_GFX_BIT_MASK
];
924 b
= s
->gr
[VGA_GFX_DATA_ROTATE
] & 7;
925 val
= (val
>> b
) | (val
<< (8 - b
));
927 bit_mask
= s
->gr
[VGA_GFX_BIT_MASK
] & val
;
928 val
= mask16
[s
->gr
[VGA_GFX_SR_VALUE
]];
932 /* apply logical operation */
933 func_select
= s
->gr
[VGA_GFX_DATA_ROTATE
] >> 3;
934 switch(func_select
) {
954 bit_mask
|= bit_mask
<< 8;
955 bit_mask
|= bit_mask
<< 16;
956 val
= (val
& bit_mask
) | (s
->latch
& ~bit_mask
);
959 /* mask data according to sr[2] */
960 mask
= s
->sr
[VGA_SEQ_PLANE_WRITE
];
961 s
->plane_updated
|= mask
; /* only used to detect font change */
962 write_mask
= mask16
[mask
];
963 ((uint32_t *)s
->vram_ptr
)[addr
] =
964 (((uint32_t *)s
->vram_ptr
)[addr
] & ~write_mask
) |
967 printf("vga: latch: [0x" TARGET_FMT_plx
"] mask=0x%08x val=0x%08x\n",
968 addr
* 4, write_mask
, val
);
970 memory_region_set_dirty(&s
->vram
, addr
<< 2, sizeof(uint32_t));
974 typedef void vga_draw_glyph8_func(uint8_t *d
, int linesize
,
975 const uint8_t *font_ptr
, int h
,
976 uint32_t fgcol
, uint32_t bgcol
);
977 typedef void vga_draw_glyph9_func(uint8_t *d
, int linesize
,
978 const uint8_t *font_ptr
, int h
,
979 uint32_t fgcol
, uint32_t bgcol
, int dup9
);
980 typedef void vga_draw_line_func(VGACommonState
*s1
, uint8_t *d
,
981 const uint8_t *s
, int width
);
984 #include "vga_template.h"
987 #include "vga_template.h"
991 #include "vga_template.h"
994 #include "vga_template.h"
998 #include "vga_template.h"
1001 #include "vga_template.h"
1005 #include "vga_template.h"
1007 static unsigned int rgb_to_pixel8_dup(unsigned int r
, unsigned int g
, unsigned b
)
1010 col
= rgb_to_pixel8(r
, g
, b
);
1016 static unsigned int rgb_to_pixel15_dup(unsigned int r
, unsigned int g
, unsigned b
)
1019 col
= rgb_to_pixel15(r
, g
, b
);
1024 static unsigned int rgb_to_pixel15bgr_dup(unsigned int r
, unsigned int g
,
1028 col
= rgb_to_pixel15bgr(r
, g
, b
);
1033 static unsigned int rgb_to_pixel16_dup(unsigned int r
, unsigned int g
, unsigned b
)
1036 col
= rgb_to_pixel16(r
, g
, b
);
1041 static unsigned int rgb_to_pixel16bgr_dup(unsigned int r
, unsigned int g
,
1045 col
= rgb_to_pixel16bgr(r
, g
, b
);
1050 static unsigned int rgb_to_pixel32_dup(unsigned int r
, unsigned int g
, unsigned b
)
1053 col
= rgb_to_pixel32(r
, g
, b
);
1057 static unsigned int rgb_to_pixel32bgr_dup(unsigned int r
, unsigned int g
, unsigned b
)
1060 col
= rgb_to_pixel32bgr(r
, g
, b
);
1064 /* return true if the palette was modified */
1065 static int update_palette16(VGACommonState
*s
)
1068 uint32_t v
, col
, *palette
;
1071 palette
= s
->last_palette
;
1072 for(i
= 0; i
< 16; i
++) {
1074 if (s
->ar
[VGA_ATC_MODE
] & 0x80) {
1075 v
= ((s
->ar
[VGA_ATC_COLOR_PAGE
] & 0xf) << 4) | (v
& 0xf);
1077 v
= ((s
->ar
[VGA_ATC_COLOR_PAGE
] & 0xc) << 4) | (v
& 0x3f);
1080 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
1081 c6_to_8(s
->palette
[v
+ 1]),
1082 c6_to_8(s
->palette
[v
+ 2]));
1083 if (col
!= palette
[i
]) {
1091 /* return true if the palette was modified */
1092 static int update_palette256(VGACommonState
*s
)
1095 uint32_t v
, col
, *palette
;
1098 palette
= s
->last_palette
;
1100 for(i
= 0; i
< 256; i
++) {
1102 col
= s
->rgb_to_pixel(s
->palette
[v
],
1106 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
1107 c6_to_8(s
->palette
[v
+ 1]),
1108 c6_to_8(s
->palette
[v
+ 2]));
1110 if (col
!= palette
[i
]) {
1119 static void vga_get_offsets(VGACommonState
*s
,
1120 uint32_t *pline_offset
,
1121 uint32_t *pstart_addr
,
1122 uint32_t *pline_compare
)
1124 uint32_t start_addr
, line_offset
, line_compare
;
1125 #ifdef CONFIG_BOCHS_VBE
1126 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1127 line_offset
= s
->vbe_line_offset
;
1128 start_addr
= s
->vbe_start_addr
;
1129 line_compare
= 65535;
1133 /* compute line_offset in bytes */
1134 line_offset
= s
->cr
[VGA_CRTC_OFFSET
];
1137 /* starting address */
1138 start_addr
= s
->cr
[VGA_CRTC_START_LO
] |
1139 (s
->cr
[VGA_CRTC_START_HI
] << 8);
1142 line_compare
= s
->cr
[VGA_CRTC_LINE_COMPARE
] |
1143 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x10) << 4) |
1144 ((s
->cr
[VGA_CRTC_MAX_SCAN
] & 0x40) << 3);
1146 *pline_offset
= line_offset
;
1147 *pstart_addr
= start_addr
;
1148 *pline_compare
= line_compare
;
1151 /* update start_addr and line_offset. Return TRUE if modified */
1152 static int update_basic_params(VGACommonState
*s
)
1155 uint32_t start_addr
, line_offset
, line_compare
;
1159 s
->get_offsets(s
, &line_offset
, &start_addr
, &line_compare
);
1161 if (line_offset
!= s
->line_offset
||
1162 start_addr
!= s
->start_addr
||
1163 line_compare
!= s
->line_compare
) {
1164 s
->line_offset
= line_offset
;
1165 s
->start_addr
= start_addr
;
1166 s
->line_compare
= line_compare
;
1174 static inline int get_depth_index(DisplayState
*s
)
1176 switch(ds_get_bits_per_pixel(s
)) {
1185 if (is_surface_bgr(s
->surface
))
1192 static vga_draw_glyph8_func
* const vga_draw_glyph8_table
[NB_DEPTHS
] = {
1202 static vga_draw_glyph8_func
* const vga_draw_glyph16_table
[NB_DEPTHS
] = {
1204 vga_draw_glyph16_16
,
1205 vga_draw_glyph16_16
,
1206 vga_draw_glyph16_32
,
1207 vga_draw_glyph16_32
,
1208 vga_draw_glyph16_16
,
1209 vga_draw_glyph16_16
,
1212 static vga_draw_glyph9_func
* const vga_draw_glyph9_table
[NB_DEPTHS
] = {
1222 static const uint8_t cursor_glyph
[32 * 4] = {
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,
1233 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1234 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1235 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1236 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1237 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1238 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1241 static void vga_get_text_resolution(VGACommonState
*s
, int *pwidth
, int *pheight
,
1242 int *pcwidth
, int *pcheight
)
1244 int width
, cwidth
, height
, cheight
;
1246 /* total width & height */
1247 cheight
= (s
->cr
[VGA_CRTC_MAX_SCAN
] & 0x1f) + 1;
1249 if (!(s
->sr
[VGA_SEQ_CLOCK_MODE
] & VGA_SR01_CHAR_CLK_8DOTS
)) {
1252 if (s
->sr
[VGA_SEQ_CLOCK_MODE
] & 0x08) {
1253 cwidth
= 16; /* NOTE: no 18 pixel wide */
1255 width
= (s
->cr
[VGA_CRTC_H_DISP
] + 1);
1256 if (s
->cr
[VGA_CRTC_V_TOTAL
] == 100) {
1257 /* ugly hack for CGA 160x100x16 - explain me the logic */
1260 height
= s
->cr
[VGA_CRTC_V_DISP_END
] |
1261 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x02) << 7) |
1262 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x40) << 3);
1263 height
= (height
+ 1) / cheight
;
1269 *pcheight
= cheight
;
1272 typedef unsigned int rgb_to_pixel_dup_func(unsigned int r
, unsigned int g
, unsigned b
);
1274 static rgb_to_pixel_dup_func
* const rgb_to_pixel_dup_table
[NB_DEPTHS
] = {
1279 rgb_to_pixel32bgr_dup
,
1280 rgb_to_pixel15bgr_dup
,
1281 rgb_to_pixel16bgr_dup
,
1292 static void vga_draw_text(VGACommonState
*s
, int full_update
)
1294 int cx
, cy
, cheight
, cw
, ch
, cattr
, height
, width
, ch_attr
;
1295 int cx_min
, cx_max
, linesize
, x_incr
, line
, line1
;
1296 uint32_t offset
, fgcol
, bgcol
, v
, cursor_offset
;
1297 uint8_t *d1
, *d
, *src
, *dest
, *cursor_ptr
;
1298 const uint8_t *font_ptr
, *font_base
[2];
1299 int dup9
, line_offset
, depth_index
;
1301 uint32_t *ch_attr_ptr
;
1302 vga_draw_glyph8_func
*vga_draw_glyph8
;
1303 vga_draw_glyph9_func
*vga_draw_glyph9
;
1305 /* compute font data address (in plane 2) */
1306 v
= s
->sr
[VGA_SEQ_CHARACTER_MAP
];
1307 offset
= (((v
>> 4) & 1) | ((v
<< 1) & 6)) * 8192 * 4 + 2;
1308 if (offset
!= s
->font_offsets
[0]) {
1309 s
->font_offsets
[0] = offset
;
1312 font_base
[0] = s
->vram_ptr
+ offset
;
1314 offset
= (((v
>> 5) & 1) | ((v
>> 1) & 6)) * 8192 * 4 + 2;
1315 font_base
[1] = s
->vram_ptr
+ offset
;
1316 if (offset
!= s
->font_offsets
[1]) {
1317 s
->font_offsets
[1] = offset
;
1320 if (s
->plane_updated
& (1 << 2) || s
->chain4_alias
) {
1321 /* if the plane 2 was modified since the last display, it
1322 indicates the font may have been modified */
1323 s
->plane_updated
= 0;
1326 full_update
|= update_basic_params(s
);
1328 line_offset
= s
->line_offset
;
1330 vga_get_text_resolution(s
, &width
, &height
, &cw
, &cheight
);
1331 if ((height
* width
) > CH_ATTR_SIZE
) {
1332 /* better than nothing: exit if transient size is too big */
1336 if (width
!= s
->last_width
|| height
!= s
->last_height
||
1337 cw
!= s
->last_cw
|| cheight
!= s
->last_ch
|| s
->last_depth
) {
1338 s
->last_scr_width
= width
* cw
;
1339 s
->last_scr_height
= height
* cheight
;
1340 qemu_console_resize(s
->ds
, s
->last_scr_width
, s
->last_scr_height
);
1342 s
->last_width
= width
;
1343 s
->last_height
= height
;
1344 s
->last_ch
= cheight
;
1349 rgb_to_pixel_dup_table
[get_depth_index(s
->ds
)];
1350 full_update
|= update_palette16(s
);
1351 palette
= s
->last_palette
;
1352 x_incr
= cw
* ((ds_get_bits_per_pixel(s
->ds
) + 7) >> 3);
1354 cursor_offset
= ((s
->cr
[VGA_CRTC_CURSOR_HI
] << 8) |
1355 s
->cr
[VGA_CRTC_CURSOR_LO
]) - s
->start_addr
;
1356 if (cursor_offset
!= s
->cursor_offset
||
1357 s
->cr
[VGA_CRTC_CURSOR_START
] != s
->cursor_start
||
1358 s
->cr
[VGA_CRTC_CURSOR_END
] != s
->cursor_end
) {
1359 /* if the cursor position changed, we update the old and new
1361 if (s
->cursor_offset
< CH_ATTR_SIZE
)
1362 s
->last_ch_attr
[s
->cursor_offset
] = -1;
1363 if (cursor_offset
< CH_ATTR_SIZE
)
1364 s
->last_ch_attr
[cursor_offset
] = -1;
1365 s
->cursor_offset
= cursor_offset
;
1366 s
->cursor_start
= s
->cr
[VGA_CRTC_CURSOR_START
];
1367 s
->cursor_end
= s
->cr
[VGA_CRTC_CURSOR_END
];
1369 cursor_ptr
= s
->vram_ptr
+ (s
->start_addr
+ cursor_offset
) * 4;
1371 depth_index
= get_depth_index(s
->ds
);
1373 vga_draw_glyph8
= vga_draw_glyph16_table
[depth_index
];
1375 vga_draw_glyph8
= vga_draw_glyph8_table
[depth_index
];
1376 vga_draw_glyph9
= vga_draw_glyph9_table
[depth_index
];
1378 dest
= ds_get_data(s
->ds
);
1379 linesize
= ds_get_linesize(s
->ds
);
1380 ch_attr_ptr
= s
->last_ch_attr
;
1382 offset
= s
->start_addr
* 4;
1383 for(cy
= 0; cy
< height
; cy
++) {
1385 src
= s
->vram_ptr
+ offset
;
1388 for(cx
= 0; cx
< width
; cx
++) {
1389 ch_attr
= *(uint16_t *)src
;
1390 if (full_update
|| ch_attr
!= *ch_attr_ptr
) {
1395 *ch_attr_ptr
= ch_attr
;
1396 #ifdef HOST_WORDS_BIGENDIAN
1398 cattr
= ch_attr
& 0xff;
1400 ch
= ch_attr
& 0xff;
1401 cattr
= ch_attr
>> 8;
1403 font_ptr
= font_base
[(cattr
>> 3) & 1];
1404 font_ptr
+= 32 * 4 * ch
;
1405 bgcol
= palette
[cattr
>> 4];
1406 fgcol
= palette
[cattr
& 0x0f];
1408 vga_draw_glyph8(d1
, linesize
,
1409 font_ptr
, cheight
, fgcol
, bgcol
);
1412 if (ch
>= 0xb0 && ch
<= 0xdf &&
1413 (s
->ar
[VGA_ATC_MODE
] & 0x04)) {
1416 vga_draw_glyph9(d1
, linesize
,
1417 font_ptr
, cheight
, fgcol
, bgcol
, dup9
);
1419 if (src
== cursor_ptr
&&
1420 !(s
->cr
[VGA_CRTC_CURSOR_START
] & 0x20)) {
1421 int line_start
, line_last
, h
;
1422 /* draw the cursor */
1423 line_start
= s
->cr
[VGA_CRTC_CURSOR_START
] & 0x1f;
1424 line_last
= s
->cr
[VGA_CRTC_CURSOR_END
] & 0x1f;
1425 /* XXX: check that */
1426 if (line_last
> cheight
- 1)
1427 line_last
= cheight
- 1;
1428 if (line_last
>= line_start
&& line_start
< cheight
) {
1429 h
= line_last
- line_start
+ 1;
1430 d
= d1
+ linesize
* line_start
;
1432 vga_draw_glyph8(d
, linesize
,
1433 cursor_glyph
, h
, fgcol
, bgcol
);
1435 vga_draw_glyph9(d
, linesize
,
1436 cursor_glyph
, h
, fgcol
, bgcol
, 1);
1446 dpy_update(s
->ds
, cx_min
* cw
, cy
* cheight
,
1447 (cx_max
- cx_min
+ 1) * cw
, cheight
);
1449 dest
+= linesize
* cheight
;
1450 line1
= line
+ cheight
;
1451 offset
+= line_offset
;
1452 if (line
< s
->line_compare
&& line1
>= s
->line_compare
) {
1473 static vga_draw_line_func
* const vga_draw_line_table
[NB_DEPTHS
* VGA_DRAW_LINE_NB
] = {
1483 vga_draw_line2d2_16
,
1484 vga_draw_line2d2_16
,
1485 vga_draw_line2d2_32
,
1486 vga_draw_line2d2_32
,
1487 vga_draw_line2d2_16
,
1488 vga_draw_line2d2_16
,
1499 vga_draw_line4d2_16
,
1500 vga_draw_line4d2_16
,
1501 vga_draw_line4d2_32
,
1502 vga_draw_line4d2_32
,
1503 vga_draw_line4d2_16
,
1504 vga_draw_line4d2_16
,
1507 vga_draw_line8d2_16
,
1508 vga_draw_line8d2_16
,
1509 vga_draw_line8d2_32
,
1510 vga_draw_line8d2_32
,
1511 vga_draw_line8d2_16
,
1512 vga_draw_line8d2_16
,
1526 vga_draw_line15_32bgr
,
1527 vga_draw_line15_15bgr
,
1528 vga_draw_line15_16bgr
,
1534 vga_draw_line16_32bgr
,
1535 vga_draw_line16_15bgr
,
1536 vga_draw_line16_16bgr
,
1542 vga_draw_line24_32bgr
,
1543 vga_draw_line24_15bgr
,
1544 vga_draw_line24_16bgr
,
1550 vga_draw_line32_32bgr
,
1551 vga_draw_line32_15bgr
,
1552 vga_draw_line32_16bgr
,
1555 static int vga_get_bpp(VGACommonState
*s
)
1558 #ifdef CONFIG_BOCHS_VBE
1559 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1560 ret
= s
->vbe_regs
[VBE_DISPI_INDEX_BPP
];
1569 static void vga_get_resolution(VGACommonState
*s
, int *pwidth
, int *pheight
)
1573 #ifdef CONFIG_BOCHS_VBE
1574 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1575 width
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
];
1576 height
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
];
1580 width
= (s
->cr
[VGA_CRTC_H_DISP
] + 1) * 8;
1581 height
= s
->cr
[VGA_CRTC_V_DISP_END
] |
1582 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x02) << 7) |
1583 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x40) << 3);
1584 height
= (height
+ 1);
1590 void vga_invalidate_scanlines(VGACommonState
*s
, int y1
, int y2
)
1593 if (y1
>= VGA_MAX_HEIGHT
)
1595 if (y2
>= VGA_MAX_HEIGHT
)
1596 y2
= VGA_MAX_HEIGHT
;
1597 for(y
= y1
; y
< y2
; y
++) {
1598 s
->invalidated_y_table
[y
>> 5] |= 1 << (y
& 0x1f);
1602 static void vga_sync_dirty_bitmap(VGACommonState
*s
)
1604 memory_region_sync_dirty_bitmap(&s
->vram
);
1607 void vga_dirty_log_start(VGACommonState
*s
)
1609 memory_region_set_log(&s
->vram
, true, DIRTY_MEMORY_VGA
);
1612 void vga_dirty_log_stop(VGACommonState
*s
)
1614 memory_region_set_log(&s
->vram
, false, DIRTY_MEMORY_VGA
);
1620 static void vga_draw_graphic(VGACommonState
*s
, int full_update
)
1622 int y1
, y
, update
, linesize
, y_start
, double_scan
, mask
, depth
;
1623 int width
, height
, shift_control
, line_offset
, bwidth
, bits
;
1624 ram_addr_t page0
, page1
, page_min
, page_max
;
1625 int disp_width
, multi_scan
, multi_run
;
1627 uint32_t v
, addr1
, addr
;
1628 vga_draw_line_func
*vga_draw_line
;
1630 full_update
|= update_basic_params(s
);
1633 vga_sync_dirty_bitmap(s
);
1635 s
->get_resolution(s
, &width
, &height
);
1638 shift_control
= (s
->gr
[VGA_GFX_MODE
] >> 5) & 3;
1639 double_scan
= (s
->cr
[VGA_CRTC_MAX_SCAN
] >> 7);
1640 if (shift_control
!= 1) {
1641 multi_scan
= (((s
->cr
[VGA_CRTC_MAX_SCAN
] & 0x1f) + 1) << double_scan
)
1644 /* in CGA modes, multi_scan is ignored */
1645 /* XXX: is it correct ? */
1646 multi_scan
= double_scan
;
1648 multi_run
= multi_scan
;
1649 if (shift_control
!= s
->shift_control
||
1650 double_scan
!= s
->double_scan
) {
1652 s
->shift_control
= shift_control
;
1653 s
->double_scan
= double_scan
;
1656 if (shift_control
== 0) {
1657 if (s
->sr
[VGA_SEQ_CLOCK_MODE
] & 8) {
1660 } else if (shift_control
== 1) {
1661 if (s
->sr
[VGA_SEQ_CLOCK_MODE
] & 8) {
1666 depth
= s
->get_bpp(s
);
1667 if (s
->line_offset
!= s
->last_line_offset
||
1668 disp_width
!= s
->last_width
||
1669 height
!= s
->last_height
||
1670 s
->last_depth
!= depth
) {
1671 #if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
1672 if (depth
== 16 || depth
== 32) {
1676 qemu_free_displaysurface(s
->ds
);
1677 s
->ds
->surface
= qemu_create_displaysurface_from(disp_width
, height
, depth
,
1679 s
->vram_ptr
+ (s
->start_addr
* 4));
1680 #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
1681 s
->ds
->surface
->pf
= qemu_different_endianness_pixelformat(depth
);
1685 qemu_console_resize(s
->ds
, disp_width
, height
);
1687 s
->last_scr_width
= disp_width
;
1688 s
->last_scr_height
= height
;
1689 s
->last_width
= disp_width
;
1690 s
->last_height
= height
;
1691 s
->last_line_offset
= s
->line_offset
;
1692 s
->last_depth
= depth
;
1694 } else if (is_buffer_shared(s
->ds
->surface
) &&
1695 (full_update
|| s
->ds
->surface
->data
!= s
->vram_ptr
+ (s
->start_addr
* 4))) {
1696 s
->ds
->surface
->data
= s
->vram_ptr
+ (s
->start_addr
* 4);
1701 rgb_to_pixel_dup_table
[get_depth_index(s
->ds
)];
1703 if (shift_control
== 0) {
1704 full_update
|= update_palette16(s
);
1705 if (s
->sr
[VGA_SEQ_CLOCK_MODE
] & 8) {
1706 v
= VGA_DRAW_LINE4D2
;
1711 } else if (shift_control
== 1) {
1712 full_update
|= update_palette16(s
);
1713 if (s
->sr
[VGA_SEQ_CLOCK_MODE
] & 8) {
1714 v
= VGA_DRAW_LINE2D2
;
1720 switch(s
->get_bpp(s
)) {
1723 full_update
|= update_palette256(s
);
1724 v
= VGA_DRAW_LINE8D2
;
1728 full_update
|= update_palette256(s
);
1733 v
= VGA_DRAW_LINE15
;
1737 v
= VGA_DRAW_LINE16
;
1741 v
= VGA_DRAW_LINE24
;
1745 v
= VGA_DRAW_LINE32
;
1750 vga_draw_line
= vga_draw_line_table
[v
* NB_DEPTHS
+ get_depth_index(s
->ds
)];
1752 if (!is_buffer_shared(s
->ds
->surface
) && s
->cursor_invalidate
)
1753 s
->cursor_invalidate(s
);
1755 line_offset
= s
->line_offset
;
1757 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",
1758 width
, height
, v
, line_offset
, s
->cr
[9], s
->cr
[VGA_CRTC_MODE
],
1759 s
->line_compare
, s
->sr
[VGA_SEQ_CLOCK_MODE
]);
1761 addr1
= (s
->start_addr
* 4);
1762 bwidth
= (width
* bits
+ 7) / 8;
1766 d
= ds_get_data(s
->ds
);
1767 linesize
= ds_get_linesize(s
->ds
);
1769 for(y
= 0; y
< height
; y
++) {
1771 if (!(s
->cr
[VGA_CRTC_MODE
] & 1)) {
1773 /* CGA compatibility handling */
1774 shift
= 14 + ((s
->cr
[VGA_CRTC_MODE
] >> 6) & 1);
1775 addr
= (addr
& ~(1 << shift
)) | ((y1
& 1) << shift
);
1777 if (!(s
->cr
[VGA_CRTC_MODE
] & 2)) {
1778 addr
= (addr
& ~0x8000) | ((y1
& 2) << 14);
1780 update
= full_update
;
1782 page1
= addr
+ bwidth
- 1;
1783 update
|= memory_region_get_dirty(&s
->vram
, page0
, page1
- page0
,
1785 /* explicit invalidation for the hardware cursor */
1786 update
|= (s
->invalidated_y_table
[y
>> 5] >> (y
& 0x1f)) & 1;
1790 if (page0
< page_min
)
1792 if (page1
> page_max
)
1794 if (!(is_buffer_shared(s
->ds
->surface
))) {
1795 vga_draw_line(s
, d
, s
->vram_ptr
+ addr
, width
);
1796 if (s
->cursor_draw_line
)
1797 s
->cursor_draw_line(s
, d
, y
);
1801 /* flush to display */
1802 dpy_update(s
->ds
, 0, y_start
,
1803 disp_width
, y
- y_start
);
1808 mask
= (s
->cr
[VGA_CRTC_MODE
] & 3) ^ 3;
1809 if ((y1
& mask
) == mask
)
1810 addr1
+= line_offset
;
1812 multi_run
= multi_scan
;
1816 /* line compare acts on the displayed lines */
1817 if (y
== s
->line_compare
)
1822 /* flush to display */
1823 dpy_update(s
->ds
, 0, y_start
,
1824 disp_width
, y
- y_start
);
1826 /* reset modified pages */
1827 if (page_max
>= page_min
) {
1828 memory_region_reset_dirty(&s
->vram
,
1830 page_max
- page_min
,
1833 memset(s
->invalidated_y_table
, 0, ((height
+ 31) >> 5) * 4);
1836 static void vga_draw_blank(VGACommonState
*s
, int full_update
)
1843 if (s
->last_scr_width
<= 0 || s
->last_scr_height
<= 0)
1847 rgb_to_pixel_dup_table
[get_depth_index(s
->ds
)];
1848 if (ds_get_bits_per_pixel(s
->ds
) == 8)
1849 val
= s
->rgb_to_pixel(0, 0, 0);
1852 w
= s
->last_scr_width
* ((ds_get_bits_per_pixel(s
->ds
) + 7) >> 3);
1853 d
= ds_get_data(s
->ds
);
1854 for(i
= 0; i
< s
->last_scr_height
; i
++) {
1856 d
+= ds_get_linesize(s
->ds
);
1858 dpy_update(s
->ds
, 0, 0,
1859 s
->last_scr_width
, s
->last_scr_height
);
1862 #define GMODE_TEXT 0
1863 #define GMODE_GRAPH 1
1864 #define GMODE_BLANK 2
1866 static void vga_update_display(void *opaque
)
1868 VGACommonState
*s
= opaque
;
1869 int full_update
, graphic_mode
;
1871 qemu_flush_coalesced_mmio_buffer();
1873 if (ds_get_bits_per_pixel(s
->ds
) == 0) {
1877 if (!(s
->ar_index
& 0x20)) {
1878 graphic_mode
= GMODE_BLANK
;
1880 graphic_mode
= s
->gr
[VGA_GFX_MISC
] & VGA_GR06_GRAPHICS_MODE
;
1882 if (graphic_mode
!= s
->graphic_mode
) {
1883 s
->graphic_mode
= graphic_mode
;
1886 switch(graphic_mode
) {
1888 vga_draw_text(s
, full_update
);
1891 vga_draw_graphic(s
, full_update
);
1895 vga_draw_blank(s
, full_update
);
1901 /* force a full display refresh */
1902 static void vga_invalidate_display(void *opaque
)
1904 VGACommonState
*s
= opaque
;
1907 s
->last_height
= -1;
1910 void vga_common_reset(VGACommonState
*s
)
1913 memset(s
->sr
, '\0', sizeof(s
->sr
));
1915 memset(s
->gr
, '\0', sizeof(s
->gr
));
1917 memset(s
->ar
, '\0', sizeof(s
->ar
));
1918 s
->ar_flip_flop
= 0;
1920 memset(s
->cr
, '\0', sizeof(s
->cr
));
1926 s
->dac_sub_index
= 0;
1927 s
->dac_read_index
= 0;
1928 s
->dac_write_index
= 0;
1929 memset(s
->dac_cache
, '\0', sizeof(s
->dac_cache
));
1931 memset(s
->palette
, '\0', sizeof(s
->palette
));
1933 #ifdef CONFIG_BOCHS_VBE
1935 memset(s
->vbe_regs
, '\0', sizeof(s
->vbe_regs
));
1936 s
->vbe_regs
[VBE_DISPI_INDEX_ID
] = VBE_DISPI_ID5
;
1937 s
->vbe_start_addr
= 0;
1938 s
->vbe_line_offset
= 0;
1939 s
->vbe_bank_mask
= (s
->vram_size
>> 16) - 1;
1941 memset(s
->font_offsets
, '\0', sizeof(s
->font_offsets
));
1942 s
->graphic_mode
= -1; /* force full update */
1943 s
->shift_control
= 0;
1946 s
->line_compare
= 0;
1948 s
->plane_updated
= 0;
1953 s
->last_scr_width
= 0;
1954 s
->last_scr_height
= 0;
1955 s
->cursor_start
= 0;
1957 s
->cursor_offset
= 0;
1958 memset(s
->invalidated_y_table
, '\0', sizeof(s
->invalidated_y_table
));
1959 memset(s
->last_palette
, '\0', sizeof(s
->last_palette
));
1960 memset(s
->last_ch_attr
, '\0', sizeof(s
->last_ch_attr
));
1961 switch (vga_retrace_method
) {
1962 case VGA_RETRACE_DUMB
:
1964 case VGA_RETRACE_PRECISE
:
1965 memset(&s
->retrace_info
, 0, sizeof (s
->retrace_info
));
1968 vga_update_memory_access(s
);
1971 static void vga_reset(void *opaque
)
1973 VGACommonState
*s
= opaque
;
1974 vga_common_reset(s
);
1977 #define TEXTMODE_X(x) ((x) % width)
1978 #define TEXTMODE_Y(x) ((x) / width)
1979 #define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1980 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1981 /* relay text rendering to the display driver
1982 * instead of doing a full vga_update_display() */
1983 static void vga_update_text(void *opaque
, console_ch_t
*chardata
)
1985 VGACommonState
*s
= opaque
;
1986 int graphic_mode
, i
, cursor_offset
, cursor_visible
;
1987 int cw
, cheight
, width
, height
, size
, c_min
, c_max
;
1989 console_ch_t
*dst
, val
;
1990 char msg_buffer
[80];
1991 int full_update
= 0;
1993 qemu_flush_coalesced_mmio_buffer();
1995 if (!(s
->ar_index
& 0x20)) {
1996 graphic_mode
= GMODE_BLANK
;
1998 graphic_mode
= s
->gr
[VGA_GFX_MISC
] & VGA_GR06_GRAPHICS_MODE
;
2000 if (graphic_mode
!= s
->graphic_mode
) {
2001 s
->graphic_mode
= graphic_mode
;
2004 if (s
->last_width
== -1) {
2009 switch (graphic_mode
) {
2011 /* TODO: update palette */
2012 full_update
|= update_basic_params(s
);
2014 /* total width & height */
2015 cheight
= (s
->cr
[VGA_CRTC_MAX_SCAN
] & 0x1f) + 1;
2017 if (!(s
->sr
[VGA_SEQ_CLOCK_MODE
] & VGA_SR01_CHAR_CLK_8DOTS
)) {
2020 if (s
->sr
[VGA_SEQ_CLOCK_MODE
] & 0x08) {
2021 cw
= 16; /* NOTE: no 18 pixel wide */
2023 width
= (s
->cr
[VGA_CRTC_H_DISP
] + 1);
2024 if (s
->cr
[VGA_CRTC_V_TOTAL
] == 100) {
2025 /* ugly hack for CGA 160x100x16 - explain me the logic */
2028 height
= s
->cr
[VGA_CRTC_V_DISP_END
] |
2029 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x02) << 7) |
2030 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x40) << 3);
2031 height
= (height
+ 1) / cheight
;
2034 size
= (height
* width
);
2035 if (size
> CH_ATTR_SIZE
) {
2039 snprintf(msg_buffer
, sizeof(msg_buffer
), "%i x %i Text mode",
2044 if (width
!= s
->last_width
|| height
!= s
->last_height
||
2045 cw
!= s
->last_cw
|| cheight
!= s
->last_ch
) {
2046 s
->last_scr_width
= width
* cw
;
2047 s
->last_scr_height
= height
* cheight
;
2048 s
->ds
->surface
->width
= width
;
2049 s
->ds
->surface
->height
= height
;
2051 s
->last_width
= width
;
2052 s
->last_height
= height
;
2053 s
->last_ch
= cheight
;
2058 /* Update "hardware" cursor */
2059 cursor_offset
= ((s
->cr
[VGA_CRTC_CURSOR_HI
] << 8) |
2060 s
->cr
[VGA_CRTC_CURSOR_LO
]) - s
->start_addr
;
2061 if (cursor_offset
!= s
->cursor_offset
||
2062 s
->cr
[VGA_CRTC_CURSOR_START
] != s
->cursor_start
||
2063 s
->cr
[VGA_CRTC_CURSOR_END
] != s
->cursor_end
|| full_update
) {
2064 cursor_visible
= !(s
->cr
[VGA_CRTC_CURSOR_START
] & 0x20);
2065 if (cursor_visible
&& cursor_offset
< size
&& cursor_offset
>= 0)
2067 TEXTMODE_X(cursor_offset
),
2068 TEXTMODE_Y(cursor_offset
));
2070 dpy_cursor(s
->ds
, -1, -1);
2071 s
->cursor_offset
= cursor_offset
;
2072 s
->cursor_start
= s
->cr
[VGA_CRTC_CURSOR_START
];
2073 s
->cursor_end
= s
->cr
[VGA_CRTC_CURSOR_END
];
2076 src
= (uint32_t *) s
->vram_ptr
+ s
->start_addr
;
2080 for (i
= 0; i
< size
; src
++, dst
++, i
++)
2081 console_write_ch(dst
, VMEM2CHTYPE(le32_to_cpu(*src
)));
2083 dpy_update(s
->ds
, 0, 0, width
, height
);
2087 for (i
= 0; i
< size
; src
++, dst
++, i
++) {
2088 console_write_ch(&val
, VMEM2CHTYPE(le32_to_cpu(*src
)));
2096 for (; i
< size
; src
++, dst
++, i
++) {
2097 console_write_ch(&val
, VMEM2CHTYPE(le32_to_cpu(*src
)));
2104 if (c_min
<= c_max
) {
2105 i
= TEXTMODE_Y(c_min
);
2106 dpy_update(s
->ds
, 0, i
, width
, TEXTMODE_Y(c_max
) - i
+ 1);
2115 s
->get_resolution(s
, &width
, &height
);
2116 snprintf(msg_buffer
, sizeof(msg_buffer
), "%i x %i Graphic mode",
2124 snprintf(msg_buffer
, sizeof(msg_buffer
), "VGA Blank mode");
2128 /* Display a message */
2130 s
->last_height
= height
= 3;
2131 dpy_cursor(s
->ds
, -1, -1);
2132 s
->ds
->surface
->width
= s
->last_width
;
2133 s
->ds
->surface
->height
= height
;
2136 for (dst
= chardata
, i
= 0; i
< s
->last_width
* height
; i
++)
2137 console_write_ch(dst
++, ' ');
2139 size
= strlen(msg_buffer
);
2140 width
= (s
->last_width
- size
) / 2;
2141 dst
= chardata
+ s
->last_width
+ width
;
2142 for (i
= 0; i
< size
; i
++)
2143 console_write_ch(dst
++, 0x00200100 | msg_buffer
[i
]);
2145 dpy_update(s
->ds
, 0, 0, s
->last_width
, height
);
2148 static uint64_t vga_mem_read(void *opaque
, target_phys_addr_t addr
,
2151 VGACommonState
*s
= opaque
;
2153 return vga_mem_readb(s
, addr
);
2156 static void vga_mem_write(void *opaque
, target_phys_addr_t addr
,
2157 uint64_t data
, unsigned size
)
2159 VGACommonState
*s
= opaque
;
2161 return vga_mem_writeb(s
, addr
, data
);
2164 const MemoryRegionOps vga_mem_ops
= {
2165 .read
= vga_mem_read
,
2166 .write
= vga_mem_write
,
2167 .endianness
= DEVICE_LITTLE_ENDIAN
,
2169 .min_access_size
= 1,
2170 .max_access_size
= 1,
2174 static int vga_common_post_load(void *opaque
, int version_id
)
2176 VGACommonState
*s
= opaque
;
2179 s
->graphic_mode
= -1;
2183 const VMStateDescription vmstate_vga_common
= {
2186 .minimum_version_id
= 2,
2187 .minimum_version_id_old
= 2,
2188 .post_load
= vga_common_post_load
,
2189 .fields
= (VMStateField
[]) {
2190 VMSTATE_UINT32(latch
, VGACommonState
),
2191 VMSTATE_UINT8(sr_index
, VGACommonState
),
2192 VMSTATE_PARTIAL_BUFFER(sr
, VGACommonState
, 8),
2193 VMSTATE_UINT8(gr_index
, VGACommonState
),
2194 VMSTATE_PARTIAL_BUFFER(gr
, VGACommonState
, 16),
2195 VMSTATE_UINT8(ar_index
, VGACommonState
),
2196 VMSTATE_BUFFER(ar
, VGACommonState
),
2197 VMSTATE_INT32(ar_flip_flop
, VGACommonState
),
2198 VMSTATE_UINT8(cr_index
, VGACommonState
),
2199 VMSTATE_BUFFER(cr
, VGACommonState
),
2200 VMSTATE_UINT8(msr
, VGACommonState
),
2201 VMSTATE_UINT8(fcr
, VGACommonState
),
2202 VMSTATE_UINT8(st00
, VGACommonState
),
2203 VMSTATE_UINT8(st01
, VGACommonState
),
2205 VMSTATE_UINT8(dac_state
, VGACommonState
),
2206 VMSTATE_UINT8(dac_sub_index
, VGACommonState
),
2207 VMSTATE_UINT8(dac_read_index
, VGACommonState
),
2208 VMSTATE_UINT8(dac_write_index
, VGACommonState
),
2209 VMSTATE_BUFFER(dac_cache
, VGACommonState
),
2210 VMSTATE_BUFFER(palette
, VGACommonState
),
2212 VMSTATE_INT32(bank_offset
, VGACommonState
),
2213 VMSTATE_UINT8_EQUAL(is_vbe_vmstate
, VGACommonState
),
2214 #ifdef CONFIG_BOCHS_VBE
2215 VMSTATE_UINT16(vbe_index
, VGACommonState
),
2216 VMSTATE_UINT16_ARRAY(vbe_regs
, VGACommonState
, VBE_DISPI_INDEX_NB
),
2217 VMSTATE_UINT32(vbe_start_addr
, VGACommonState
),
2218 VMSTATE_UINT32(vbe_line_offset
, VGACommonState
),
2219 VMSTATE_UINT32(vbe_bank_mask
, VGACommonState
),
2221 VMSTATE_END_OF_LIST()
2225 void vga_common_init(VGACommonState
*s
, int vga_ram_size
)
2229 for(i
= 0;i
< 256; i
++) {
2231 for(j
= 0; j
< 8; j
++) {
2232 v
|= ((i
>> j
) & 1) << (j
* 4);
2237 for(j
= 0; j
< 4; j
++) {
2238 v
|= ((i
>> (2 * j
)) & 3) << (j
* 4);
2242 for(i
= 0; i
< 16; i
++) {
2244 for(j
= 0; j
< 4; j
++) {
2247 v
|= b
<< (2 * j
+ 1);
2252 #ifdef CONFIG_BOCHS_VBE
2253 s
->is_vbe_vmstate
= 1;
2255 s
->is_vbe_vmstate
= 0;
2257 memory_region_init_ram(&s
->vram
, "vga.vram", vga_ram_size
);
2258 vmstate_register_ram_global(&s
->vram
);
2259 xen_register_framebuffer(&s
->vram
);
2260 s
->vram_ptr
= memory_region_get_ram_ptr(&s
->vram
);
2261 s
->vram_size
= vga_ram_size
;
2262 s
->get_bpp
= vga_get_bpp
;
2263 s
->get_offsets
= vga_get_offsets
;
2264 s
->get_resolution
= vga_get_resolution
;
2265 s
->update
= vga_update_display
;
2266 s
->invalidate
= vga_invalidate_display
;
2267 s
->screen_dump
= vga_screen_dump
;
2268 s
->text_update
= vga_update_text
;
2269 switch (vga_retrace_method
) {
2270 case VGA_RETRACE_DUMB
:
2271 s
->retrace
= vga_dumb_retrace
;
2272 s
->update_retrace_info
= vga_dumb_update_retrace_info
;
2275 case VGA_RETRACE_PRECISE
:
2276 s
->retrace
= vga_precise_retrace
;
2277 s
->update_retrace_info
= vga_precise_update_retrace_info
;
2280 vga_dirty_log_start(s
);
2283 static const MemoryRegionPortio vga_portio_list
[] = {
2284 { 0x04, 2, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3b4 */
2285 { 0x0a, 1, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3ba */
2286 { 0x10, 16, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3c0 */
2287 { 0x24, 2, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3d4 */
2288 { 0x2a, 1, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3da */
2289 PORTIO_END_OF_LIST(),
2292 #ifdef CONFIG_BOCHS_VBE
2293 static const MemoryRegionPortio vbe_portio_list
[] = {
2294 { 0, 1, 2, .read
= vbe_ioport_read_index
, .write
= vbe_ioport_write_index
},
2296 { 1, 1, 2, .read
= vbe_ioport_read_data
, .write
= vbe_ioport_write_data
},
2298 { 2, 1, 2, .read
= vbe_ioport_read_data
, .write
= vbe_ioport_write_data
},
2300 PORTIO_END_OF_LIST(),
2302 #endif /* CONFIG_BOCHS_VBE */
2304 /* Used by both ISA and PCI */
2305 MemoryRegion
*vga_init_io(VGACommonState
*s
,
2306 const MemoryRegionPortio
**vga_ports
,
2307 const MemoryRegionPortio
**vbe_ports
)
2309 MemoryRegion
*vga_mem
;
2311 *vga_ports
= vga_portio_list
;
2313 #ifdef CONFIG_BOCHS_VBE
2314 *vbe_ports
= vbe_portio_list
;
2317 vga_mem
= g_malloc(sizeof(*vga_mem
));
2318 memory_region_init_io(vga_mem
, &vga_mem_ops
, s
,
2319 "vga-lowmem", 0x20000);
2324 void vga_init(VGACommonState
*s
, MemoryRegion
*address_space
,
2325 MemoryRegion
*address_space_io
, bool init_vga_ports
)
2327 MemoryRegion
*vga_io_memory
;
2328 const MemoryRegionPortio
*vga_ports
, *vbe_ports
;
2329 PortioList
*vga_port_list
= g_new(PortioList
, 1);
2330 PortioList
*vbe_port_list
= g_new(PortioList
, 1);
2332 qemu_register_reset(vga_reset
, s
);
2336 s
->legacy_address_space
= address_space
;
2338 vga_io_memory
= vga_init_io(s
, &vga_ports
, &vbe_ports
);
2339 memory_region_add_subregion_overlap(address_space
,
2340 isa_mem_base
+ 0x000a0000,
2343 memory_region_set_coalescing(vga_io_memory
);
2344 if (init_vga_ports
) {
2345 portio_list_init(vga_port_list
, vga_ports
, s
, "vga");
2346 portio_list_add(vga_port_list
, address_space_io
, 0x3b0);
2349 portio_list_init(vbe_port_list
, vbe_ports
, s
, "vbe");
2350 portio_list_add(vbe_port_list
, address_space_io
, 0x1ce);
2354 void vga_init_vbe(VGACommonState
*s
, MemoryRegion
*system_memory
)
2356 #ifdef CONFIG_BOCHS_VBE
2357 /* XXX: use optimized standard vga accesses */
2358 memory_region_add_subregion(system_memory
,
2359 VBE_DISPI_LFB_PHYSICAL_ADDRESS
,
2364 /********************************************************/
2365 /* vga screen dump */
2367 static void vga_save_dpy_update(DisplayState
*ds
,
2368 int x
, int y
, int w
, int h
)
2370 if (screen_dump_filename
) {
2371 ppm_save(screen_dump_filename
, ds
->surface
);
2375 static void vga_save_dpy_resize(DisplayState
*s
)
2379 static void vga_save_dpy_refresh(DisplayState
*s
)
2383 int ppm_save(const char *filename
, struct DisplaySurface
*ds
)
2391 char *linebuf
, *pbuf
;
2393 f
= fopen(filename
, "wb");
2396 fprintf(f
, "P6\n%d %d\n%d\n",
2397 ds
->width
, ds
->height
, 255);
2398 linebuf
= g_malloc(ds
->width
* 3);
2400 for(y
= 0; y
< ds
->height
; y
++) {
2403 for(x
= 0; x
< ds
->width
; x
++) {
2404 if (ds
->pf
.bits_per_pixel
== 32)
2407 v
= (uint32_t) (*(uint16_t *)d
);
2408 /* Limited to 8 or fewer bits per channel: */
2409 r
= ((v
>> ds
->pf
.rshift
) & ds
->pf
.rmax
) << (8 - ds
->pf
.rbits
);
2410 g
= ((v
>> ds
->pf
.gshift
) & ds
->pf
.gmax
) << (8 - ds
->pf
.gbits
);
2411 b
= ((v
>> ds
->pf
.bshift
) & ds
->pf
.bmax
) << (8 - ds
->pf
.bbits
);
2415 d
+= ds
->pf
.bytes_per_pixel
;
2418 ret
= fwrite(linebuf
, 1, pbuf
- linebuf
, f
);
2426 static DisplayChangeListener
* vga_screen_dump_init(DisplayState
*ds
)
2428 DisplayChangeListener
*dcl
;
2430 dcl
= g_malloc0(sizeof(DisplayChangeListener
));
2431 dcl
->dpy_update
= vga_save_dpy_update
;
2432 dcl
->dpy_resize
= vga_save_dpy_resize
;
2433 dcl
->dpy_refresh
= vga_save_dpy_refresh
;
2434 register_displaychangelistener(ds
, dcl
);
2438 /* save the vga display in a PPM image even if no display is
2440 static void vga_screen_dump(void *opaque
, const char *filename
)
2442 VGACommonState
*s
= opaque
;
2444 if (!screen_dump_dcl
)
2445 screen_dump_dcl
= vga_screen_dump_init(s
->ds
);
2447 screen_dump_filename
= filename
;
2448 vga_invalidate_display(s
);
2450 screen_dump_filename
= NULL
;