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"
36 //#define DEBUG_VGA_MEM
37 //#define DEBUG_VGA_REG
39 //#define DEBUG_BOCHS_VBE
41 /* 16 state changes per vertical frame @60 Hz */
42 #define VGA_TEXT_CURSOR_PERIOD_MS (1000 * 2 * 16 / 60)
45 * Video Graphics Array (VGA)
47 * Chipset docs for original IBM VGA:
48 * http://www.mcamafia.de/pdf/ibm_vgaxga_trm2.pdf
51 * http://www.osdever.net/FreeVGA/home.htm
53 * Standard VGA features and Bochs VBE extensions are implemented.
56 /* force some bits to zero */
57 const uint8_t sr_mask
[8] = {
68 const uint8_t gr_mask
[16] = {
87 #define cbswap_32(__x) \
89 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
90 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
91 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
92 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
94 #ifdef HOST_WORDS_BIGENDIAN
95 #define PAT(x) cbswap_32(x)
100 #ifdef HOST_WORDS_BIGENDIAN
106 #ifdef HOST_WORDS_BIGENDIAN
107 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
109 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
112 static const uint32_t mask16
[16] = {
133 #ifdef HOST_WORDS_BIGENDIAN
136 #define PAT(x) cbswap_32(x)
139 static const uint32_t dmask16
[16] = {
158 static const uint32_t dmask4
[4] = {
165 static uint32_t expand4
[256];
166 static uint16_t expand2
[256];
167 static uint8_t expand4to8
[16];
169 static void vga_screen_dump(void *opaque
, const char *filename
, bool cswitch
);
171 static void vga_update_memory_access(VGACommonState
*s
)
173 MemoryRegion
*region
, *old_region
= s
->chain4_alias
;
174 target_phys_addr_t base
, offset
, size
;
176 s
->chain4_alias
= NULL
;
178 if ((s
->sr
[VGA_SEQ_PLANE_WRITE
] & VGA_SR02_ALL_PLANES
) ==
179 VGA_SR02_ALL_PLANES
&& s
->sr
[VGA_SEQ_MEMORY_MODE
] & VGA_SR04_CHN_4M
) {
181 switch ((s
->gr
[VGA_GFX_MISC
] >> 2) & 3) {
189 offset
= s
->bank_offset
;
201 base
+= isa_mem_base
;
202 region
= g_malloc(sizeof(*region
));
203 memory_region_init_alias(region
, "vga.chain4", &s
->vram
, offset
, size
);
204 memory_region_add_subregion_overlap(s
->legacy_address_space
, base
,
206 s
->chain4_alias
= region
;
209 memory_region_del_subregion(s
->legacy_address_space
, old_region
);
210 memory_region_destroy(old_region
);
212 s
->plane_updated
= 0xf;
216 static void vga_dumb_update_retrace_info(VGACommonState
*s
)
221 static void vga_precise_update_retrace_info(VGACommonState
*s
)
224 int hretr_start_char
;
225 int hretr_skew_chars
;
229 int vretr_start_line
;
238 const int clk_hz
[] = {25175000, 28322000, 25175000, 25175000};
239 int64_t chars_per_sec
;
240 struct vga_precise_retrace
*r
= &s
->retrace_info
.precise
;
242 htotal_chars
= s
->cr
[VGA_CRTC_H_TOTAL
] + 5;
243 hretr_start_char
= s
->cr
[VGA_CRTC_H_SYNC_START
];
244 hretr_skew_chars
= (s
->cr
[VGA_CRTC_H_SYNC_END
] >> 5) & 3;
245 hretr_end_char
= s
->cr
[VGA_CRTC_H_SYNC_END
] & 0x1f;
247 vtotal_lines
= (s
->cr
[VGA_CRTC_V_TOTAL
] |
248 (((s
->cr
[VGA_CRTC_OVERFLOW
] & 1) |
249 ((s
->cr
[VGA_CRTC_OVERFLOW
] >> 4) & 2)) << 8)) + 2;
250 vretr_start_line
= s
->cr
[VGA_CRTC_V_SYNC_START
] |
251 ((((s
->cr
[VGA_CRTC_OVERFLOW
] >> 2) & 1) |
252 ((s
->cr
[VGA_CRTC_OVERFLOW
] >> 6) & 2)) << 8);
253 vretr_end_line
= s
->cr
[VGA_CRTC_V_SYNC_END
] & 0xf;
255 clocking_mode
= (s
->sr
[VGA_SEQ_CLOCK_MODE
] >> 3) & 1;
256 clock_sel
= (s
->msr
>> 2) & 3;
257 dots
= (s
->msr
& 1) ? 8 : 9;
259 chars_per_sec
= clk_hz
[clock_sel
] / dots
;
261 htotal_chars
<<= clocking_mode
;
263 r
->total_chars
= vtotal_lines
* htotal_chars
;
265 r
->ticks_per_char
= get_ticks_per_sec() / (r
->total_chars
* r
->freq
);
267 r
->ticks_per_char
= get_ticks_per_sec() / chars_per_sec
;
270 r
->vstart
= vretr_start_line
;
271 r
->vend
= r
->vstart
+ vretr_end_line
+ 1;
273 r
->hstart
= hretr_start_char
+ hretr_skew_chars
;
274 r
->hend
= r
->hstart
+ hretr_end_char
+ 1;
275 r
->htotal
= htotal_chars
;
278 div2
= (s
->cr
[VGA_CRTC_MODE
] >> 2) & 1;
279 sldiv2
= (s
->cr
[VGA_CRTC_MODE
] >> 3) & 1;
289 "div2 = %d sldiv2 = %d\n"
290 "clocking_mode = %d\n"
291 "clock_sel = %d %d\n"
293 "ticks/char = %" PRId64
"\n"
295 (double) get_ticks_per_sec() / (r
->ticks_per_char
* r
->total_chars
),
313 static uint8_t vga_precise_retrace(VGACommonState
*s
)
315 struct vga_precise_retrace
*r
= &s
->retrace_info
.precise
;
316 uint8_t val
= s
->st01
& ~(ST01_V_RETRACE
| ST01_DISP_ENABLE
);
318 if (r
->total_chars
) {
319 int cur_line
, cur_line_char
, cur_char
;
322 cur_tick
= qemu_get_clock_ns(vm_clock
);
324 cur_char
= (cur_tick
/ r
->ticks_per_char
) % r
->total_chars
;
325 cur_line
= cur_char
/ r
->htotal
;
327 if (cur_line
>= r
->vstart
&& cur_line
<= r
->vend
) {
328 val
|= ST01_V_RETRACE
| ST01_DISP_ENABLE
;
330 cur_line_char
= cur_char
% r
->htotal
;
331 if (cur_line_char
>= r
->hstart
&& cur_line_char
<= r
->hend
) {
332 val
|= ST01_DISP_ENABLE
;
338 return s
->st01
^ (ST01_V_RETRACE
| ST01_DISP_ENABLE
);
342 static uint8_t vga_dumb_retrace(VGACommonState
*s
)
344 return s
->st01
^ (ST01_V_RETRACE
| ST01_DISP_ENABLE
);
347 int vga_ioport_invalid(VGACommonState
*s
, uint32_t addr
)
349 if (s
->msr
& VGA_MIS_COLOR
) {
351 return (addr
>= 0x3b0 && addr
<= 0x3bf);
354 return (addr
>= 0x3d0 && addr
<= 0x3df);
358 uint32_t vga_ioport_read(void *opaque
, uint32_t addr
)
360 VGACommonState
*s
= opaque
;
363 if (vga_ioport_invalid(s
, addr
)) {
368 if (s
->ar_flip_flop
== 0) {
375 index
= s
->ar_index
& 0x1f;
376 if (index
< VGA_ATT_C
) {
389 val
= s
->sr
[s
->sr_index
];
391 printf("vga: read SR%x = 0x%02x\n", s
->sr_index
, val
);
398 val
= s
->dac_write_index
;
401 val
= s
->palette
[s
->dac_read_index
* 3 + s
->dac_sub_index
];
402 if (++s
->dac_sub_index
== 3) {
403 s
->dac_sub_index
= 0;
417 val
= s
->gr
[s
->gr_index
];
419 printf("vga: read GR%x = 0x%02x\n", s
->gr_index
, val
);
428 val
= s
->cr
[s
->cr_index
];
430 printf("vga: read CR%x = 0x%02x\n", s
->cr_index
, val
);
435 /* just toggle to fool polling */
436 val
= s
->st01
= s
->retrace(s
);
444 #if defined(DEBUG_VGA)
445 printf("VGA: read addr=0x%04x data=0x%02x\n", addr
, val
);
450 void vga_ioport_write(void *opaque
, uint32_t addr
, uint32_t val
)
452 VGACommonState
*s
= opaque
;
455 /* check port range access depending on color/monochrome mode */
456 if (vga_ioport_invalid(s
, addr
)) {
460 printf("VGA: write addr=0x%04x data=0x%02x\n", addr
, val
);
465 if (s
->ar_flip_flop
== 0) {
469 index
= s
->ar_index
& 0x1f;
471 case VGA_ATC_PALETTE0
... VGA_ATC_PALETTEF
:
472 s
->ar
[index
] = val
& 0x3f;
475 s
->ar
[index
] = val
& ~0x10;
477 case VGA_ATC_OVERSCAN
:
480 case VGA_ATC_PLANE_ENABLE
:
481 s
->ar
[index
] = val
& ~0xc0;
484 s
->ar
[index
] = val
& ~0xf0;
486 case VGA_ATC_COLOR_PAGE
:
487 s
->ar
[index
] = val
& ~0xf0;
493 s
->ar_flip_flop
^= 1;
496 s
->msr
= val
& ~0x10;
497 s
->update_retrace_info(s
);
500 s
->sr_index
= val
& 7;
504 printf("vga: write SR%x = 0x%02x\n", s
->sr_index
, val
);
506 s
->sr
[s
->sr_index
] = val
& sr_mask
[s
->sr_index
];
507 if (s
->sr_index
== VGA_SEQ_CLOCK_MODE
) {
508 s
->update_retrace_info(s
);
510 vga_update_memory_access(s
);
513 s
->dac_read_index
= val
;
514 s
->dac_sub_index
= 0;
518 s
->dac_write_index
= val
;
519 s
->dac_sub_index
= 0;
523 s
->dac_cache
[s
->dac_sub_index
] = val
;
524 if (++s
->dac_sub_index
== 3) {
525 memcpy(&s
->palette
[s
->dac_write_index
* 3], s
->dac_cache
, 3);
526 s
->dac_sub_index
= 0;
527 s
->dac_write_index
++;
531 s
->gr_index
= val
& 0x0f;
535 printf("vga: write GR%x = 0x%02x\n", s
->gr_index
, val
);
537 s
->gr
[s
->gr_index
] = val
& gr_mask
[s
->gr_index
];
538 vga_update_memory_access(s
);
547 printf("vga: write CR%x = 0x%02x\n", s
->cr_index
, val
);
549 /* handle CR0-7 protection */
550 if ((s
->cr
[VGA_CRTC_V_SYNC_END
] & VGA_CR11_LOCK_CR0_CR7
) &&
551 s
->cr_index
<= VGA_CRTC_OVERFLOW
) {
552 /* can always write bit 4 of CR7 */
553 if (s
->cr_index
== VGA_CRTC_OVERFLOW
) {
554 s
->cr
[VGA_CRTC_OVERFLOW
] = (s
->cr
[VGA_CRTC_OVERFLOW
] & ~0x10) |
559 s
->cr
[s
->cr_index
] = val
;
561 switch(s
->cr_index
) {
562 case VGA_CRTC_H_TOTAL
:
563 case VGA_CRTC_H_SYNC_START
:
564 case VGA_CRTC_H_SYNC_END
:
565 case VGA_CRTC_V_TOTAL
:
566 case VGA_CRTC_OVERFLOW
:
567 case VGA_CRTC_V_SYNC_END
:
569 s
->update_retrace_info(s
);
580 #ifdef CONFIG_BOCHS_VBE
581 static uint32_t vbe_ioport_read_index(void *opaque
, uint32_t addr
)
583 VGACommonState
*s
= opaque
;
589 static uint32_t vbe_ioport_read_data(void *opaque
, uint32_t addr
)
591 VGACommonState
*s
= opaque
;
594 if (s
->vbe_index
< VBE_DISPI_INDEX_NB
) {
595 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_GETCAPS
) {
596 switch(s
->vbe_index
) {
597 /* XXX: do not hardcode ? */
598 case VBE_DISPI_INDEX_XRES
:
599 val
= VBE_DISPI_MAX_XRES
;
601 case VBE_DISPI_INDEX_YRES
:
602 val
= VBE_DISPI_MAX_YRES
;
604 case VBE_DISPI_INDEX_BPP
:
605 val
= VBE_DISPI_MAX_BPP
;
608 val
= s
->vbe_regs
[s
->vbe_index
];
612 val
= s
->vbe_regs
[s
->vbe_index
];
614 } else if (s
->vbe_index
== VBE_DISPI_INDEX_VIDEO_MEMORY_64K
) {
615 val
= s
->vram_size
/ (64 * 1024);
619 #ifdef DEBUG_BOCHS_VBE
620 printf("VBE: read index=0x%x val=0x%x\n", s
->vbe_index
, val
);
625 static void vbe_ioport_write_index(void *opaque
, uint32_t addr
, uint32_t val
)
627 VGACommonState
*s
= opaque
;
631 static void vbe_ioport_write_data(void *opaque
, uint32_t addr
, uint32_t val
)
633 VGACommonState
*s
= opaque
;
635 if (s
->vbe_index
<= VBE_DISPI_INDEX_NB
) {
636 #ifdef DEBUG_BOCHS_VBE
637 printf("VBE: write index=0x%x val=0x%x\n", s
->vbe_index
, val
);
639 switch(s
->vbe_index
) {
640 case VBE_DISPI_INDEX_ID
:
641 if (val
== VBE_DISPI_ID0
||
642 val
== VBE_DISPI_ID1
||
643 val
== VBE_DISPI_ID2
||
644 val
== VBE_DISPI_ID3
||
645 val
== VBE_DISPI_ID4
) {
646 s
->vbe_regs
[s
->vbe_index
] = val
;
649 case VBE_DISPI_INDEX_XRES
:
650 if ((val
<= VBE_DISPI_MAX_XRES
) && ((val
& 7) == 0)) {
651 s
->vbe_regs
[s
->vbe_index
] = val
;
654 case VBE_DISPI_INDEX_YRES
:
655 if (val
<= VBE_DISPI_MAX_YRES
) {
656 s
->vbe_regs
[s
->vbe_index
] = val
;
659 case VBE_DISPI_INDEX_BPP
:
662 if (val
== 4 || val
== 8 || val
== 15 ||
663 val
== 16 || val
== 24 || val
== 32) {
664 s
->vbe_regs
[s
->vbe_index
] = val
;
667 case VBE_DISPI_INDEX_BANK
:
668 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
669 val
&= (s
->vbe_bank_mask
>> 2);
671 val
&= s
->vbe_bank_mask
;
673 s
->vbe_regs
[s
->vbe_index
] = val
;
674 s
->bank_offset
= (val
<< 16);
675 vga_update_memory_access(s
);
677 case VBE_DISPI_INDEX_ENABLE
:
678 if ((val
& VBE_DISPI_ENABLED
) &&
679 !(s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
)) {
680 int h
, shift_control
;
682 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] =
683 s
->vbe_regs
[VBE_DISPI_INDEX_XRES
];
684 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_HEIGHT
] =
685 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
];
686 s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
] = 0;
687 s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
] = 0;
689 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
690 s
->vbe_line_offset
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 1;
692 s
->vbe_line_offset
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] *
693 ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
694 s
->vbe_start_addr
= 0;
696 /* clear the screen (should be done in BIOS) */
697 if (!(val
& VBE_DISPI_NOCLEARMEM
)) {
698 memset(s
->vram_ptr
, 0,
699 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] * s
->vbe_line_offset
);
702 /* we initialize the VGA graphic mode (should be done
704 /* graphic mode + memory map 1 */
705 s
->gr
[VGA_GFX_MISC
] = (s
->gr
[VGA_GFX_MISC
] & ~0x0c) | 0x04 |
706 VGA_GR06_GRAPHICS_MODE
;
707 s
->cr
[VGA_CRTC_MODE
] |= 3; /* no CGA modes */
708 s
->cr
[VGA_CRTC_OFFSET
] = s
->vbe_line_offset
>> 3;
710 s
->cr
[VGA_CRTC_H_DISP
] =
711 (s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 3) - 1;
712 /* height (only meaningful if < 1024) */
713 h
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] - 1;
714 s
->cr
[VGA_CRTC_V_DISP_END
] = h
;
715 s
->cr
[VGA_CRTC_OVERFLOW
] = (s
->cr
[VGA_CRTC_OVERFLOW
] & ~0x42) |
716 ((h
>> 7) & 0x02) | ((h
>> 3) & 0x40);
717 /* line compare to 1023 */
718 s
->cr
[VGA_CRTC_LINE_COMPARE
] = 0xff;
719 s
->cr
[VGA_CRTC_OVERFLOW
] |= 0x10;
720 s
->cr
[VGA_CRTC_MAX_SCAN
] |= 0x40;
722 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
724 s
->sr
[VGA_SEQ_CLOCK_MODE
] &= ~8; /* no double line */
727 /* set chain 4 mode */
728 s
->sr
[VGA_SEQ_MEMORY_MODE
] |= VGA_SR04_CHN_4M
;
729 /* activate all planes */
730 s
->sr
[VGA_SEQ_PLANE_WRITE
] |= VGA_SR02_ALL_PLANES
;
732 s
->gr
[VGA_GFX_MODE
] = (s
->gr
[VGA_GFX_MODE
] & ~0x60) |
733 (shift_control
<< 5);
734 s
->cr
[VGA_CRTC_MAX_SCAN
] &= ~0x9f; /* no double scan */
736 /* XXX: the bios should do that */
739 s
->dac_8bit
= (val
& VBE_DISPI_8BIT_DAC
) > 0;
740 s
->vbe_regs
[s
->vbe_index
] = val
;
741 vga_update_memory_access(s
);
743 case VBE_DISPI_INDEX_VIRT_WIDTH
:
745 int w
, h
, line_offset
;
747 if (val
< s
->vbe_regs
[VBE_DISPI_INDEX_XRES
])
750 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
751 line_offset
= w
>> 1;
753 line_offset
= w
* ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
754 h
= s
->vram_size
/ line_offset
;
755 /* XXX: support weird bochs semantics ? */
756 if (h
< s
->vbe_regs
[VBE_DISPI_INDEX_YRES
])
758 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] = w
;
759 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_HEIGHT
] = h
;
760 s
->vbe_line_offset
= line_offset
;
763 case VBE_DISPI_INDEX_X_OFFSET
:
764 case VBE_DISPI_INDEX_Y_OFFSET
:
767 s
->vbe_regs
[s
->vbe_index
] = val
;
768 s
->vbe_start_addr
= s
->vbe_line_offset
* s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
];
769 x
= s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
];
770 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
771 s
->vbe_start_addr
+= x
>> 1;
773 s
->vbe_start_addr
+= x
* ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
774 s
->vbe_start_addr
>>= 2;
784 /* called for accesses between 0xa0000 and 0xc0000 */
785 uint32_t vga_mem_readb(VGACommonState
*s
, target_phys_addr_t addr
)
787 int memory_map_mode
, plane
;
790 /* convert to VGA memory offset */
791 memory_map_mode
= (s
->gr
[VGA_GFX_MISC
] >> 2) & 3;
793 switch(memory_map_mode
) {
799 addr
+= s
->bank_offset
;
814 if (s
->sr
[VGA_SEQ_MEMORY_MODE
] & VGA_SR04_CHN_4M
) {
815 /* chain 4 mode : simplest access */
816 ret
= s
->vram_ptr
[addr
];
817 } else if (s
->gr
[VGA_GFX_MODE
] & 0x10) {
818 /* odd/even mode (aka text mode mapping) */
819 plane
= (s
->gr
[VGA_GFX_PLANE_READ
] & 2) | (addr
& 1);
820 ret
= s
->vram_ptr
[((addr
& ~1) << 1) | plane
];
822 /* standard VGA latched access */
823 s
->latch
= ((uint32_t *)s
->vram_ptr
)[addr
];
825 if (!(s
->gr
[VGA_GFX_MODE
] & 0x08)) {
827 plane
= s
->gr
[VGA_GFX_PLANE_READ
];
828 ret
= GET_PLANE(s
->latch
, plane
);
831 ret
= (s
->latch
^ mask16
[s
->gr
[VGA_GFX_COMPARE_VALUE
]]) &
832 mask16
[s
->gr
[VGA_GFX_COMPARE_MASK
]];
841 /* called for accesses between 0xa0000 and 0xc0000 */
842 void vga_mem_writeb(VGACommonState
*s
, target_phys_addr_t addr
, uint32_t val
)
844 int memory_map_mode
, plane
, write_mode
, b
, func_select
, mask
;
845 uint32_t write_mask
, bit_mask
, set_mask
;
848 printf("vga: [0x" TARGET_FMT_plx
"] = 0x%02x\n", addr
, val
);
850 /* convert to VGA memory offset */
851 memory_map_mode
= (s
->gr
[VGA_GFX_MISC
] >> 2) & 3;
853 switch(memory_map_mode
) {
859 addr
+= s
->bank_offset
;
874 if (s
->sr
[VGA_SEQ_MEMORY_MODE
] & VGA_SR04_CHN_4M
) {
875 /* chain 4 mode : simplest access */
878 if (s
->sr
[VGA_SEQ_PLANE_WRITE
] & mask
) {
879 s
->vram_ptr
[addr
] = val
;
881 printf("vga: chain4: [0x" TARGET_FMT_plx
"]\n", addr
);
883 s
->plane_updated
|= mask
; /* only used to detect font change */
884 memory_region_set_dirty(&s
->vram
, addr
, 1);
886 } else if (s
->gr
[VGA_GFX_MODE
] & 0x10) {
887 /* odd/even mode (aka text mode mapping) */
888 plane
= (s
->gr
[VGA_GFX_PLANE_READ
] & 2) | (addr
& 1);
890 if (s
->sr
[VGA_SEQ_PLANE_WRITE
] & mask
) {
891 addr
= ((addr
& ~1) << 1) | plane
;
892 s
->vram_ptr
[addr
] = val
;
894 printf("vga: odd/even: [0x" TARGET_FMT_plx
"]\n", addr
);
896 s
->plane_updated
|= mask
; /* only used to detect font change */
897 memory_region_set_dirty(&s
->vram
, addr
, 1);
900 /* standard VGA latched access */
901 write_mode
= s
->gr
[VGA_GFX_MODE
] & 3;
906 b
= s
->gr
[VGA_GFX_DATA_ROTATE
] & 7;
907 val
= ((val
>> b
) | (val
<< (8 - b
))) & 0xff;
911 /* apply set/reset mask */
912 set_mask
= mask16
[s
->gr
[VGA_GFX_SR_ENABLE
]];
913 val
= (val
& ~set_mask
) |
914 (mask16
[s
->gr
[VGA_GFX_SR_VALUE
]] & set_mask
);
915 bit_mask
= s
->gr
[VGA_GFX_BIT_MASK
];
921 val
= mask16
[val
& 0x0f];
922 bit_mask
= s
->gr
[VGA_GFX_BIT_MASK
];
926 b
= s
->gr
[VGA_GFX_DATA_ROTATE
] & 7;
927 val
= (val
>> b
) | (val
<< (8 - b
));
929 bit_mask
= s
->gr
[VGA_GFX_BIT_MASK
] & val
;
930 val
= mask16
[s
->gr
[VGA_GFX_SR_VALUE
]];
934 /* apply logical operation */
935 func_select
= s
->gr
[VGA_GFX_DATA_ROTATE
] >> 3;
936 switch(func_select
) {
956 bit_mask
|= bit_mask
<< 8;
957 bit_mask
|= bit_mask
<< 16;
958 val
= (val
& bit_mask
) | (s
->latch
& ~bit_mask
);
961 /* mask data according to sr[2] */
962 mask
= s
->sr
[VGA_SEQ_PLANE_WRITE
];
963 s
->plane_updated
|= mask
; /* only used to detect font change */
964 write_mask
= mask16
[mask
];
965 ((uint32_t *)s
->vram_ptr
)[addr
] =
966 (((uint32_t *)s
->vram_ptr
)[addr
] & ~write_mask
) |
969 printf("vga: latch: [0x" TARGET_FMT_plx
"] mask=0x%08x val=0x%08x\n",
970 addr
* 4, write_mask
, val
);
972 memory_region_set_dirty(&s
->vram
, addr
<< 2, sizeof(uint32_t));
976 typedef void vga_draw_glyph8_func(uint8_t *d
, int linesize
,
977 const uint8_t *font_ptr
, int h
,
978 uint32_t fgcol
, uint32_t bgcol
);
979 typedef void vga_draw_glyph9_func(uint8_t *d
, int linesize
,
980 const uint8_t *font_ptr
, int h
,
981 uint32_t fgcol
, uint32_t bgcol
, int dup9
);
982 typedef void vga_draw_line_func(VGACommonState
*s1
, uint8_t *d
,
983 const uint8_t *s
, int width
);
986 #include "vga_template.h"
989 #include "vga_template.h"
993 #include "vga_template.h"
996 #include "vga_template.h"
1000 #include "vga_template.h"
1003 #include "vga_template.h"
1007 #include "vga_template.h"
1009 static unsigned int rgb_to_pixel8_dup(unsigned int r
, unsigned int g
, unsigned b
)
1012 col
= rgb_to_pixel8(r
, g
, b
);
1018 static unsigned int rgb_to_pixel15_dup(unsigned int r
, unsigned int g
, unsigned b
)
1021 col
= rgb_to_pixel15(r
, g
, b
);
1026 static unsigned int rgb_to_pixel15bgr_dup(unsigned int r
, unsigned int g
,
1030 col
= rgb_to_pixel15bgr(r
, g
, b
);
1035 static unsigned int rgb_to_pixel16_dup(unsigned int r
, unsigned int g
, unsigned b
)
1038 col
= rgb_to_pixel16(r
, g
, b
);
1043 static unsigned int rgb_to_pixel16bgr_dup(unsigned int r
, unsigned int g
,
1047 col
= rgb_to_pixel16bgr(r
, g
, b
);
1052 static unsigned int rgb_to_pixel32_dup(unsigned int r
, unsigned int g
, unsigned b
)
1055 col
= rgb_to_pixel32(r
, g
, b
);
1059 static unsigned int rgb_to_pixel32bgr_dup(unsigned int r
, unsigned int g
, unsigned b
)
1062 col
= rgb_to_pixel32bgr(r
, g
, b
);
1066 /* return true if the palette was modified */
1067 static int update_palette16(VGACommonState
*s
)
1070 uint32_t v
, col
, *palette
;
1073 palette
= s
->last_palette
;
1074 for(i
= 0; i
< 16; i
++) {
1076 if (s
->ar
[VGA_ATC_MODE
] & 0x80) {
1077 v
= ((s
->ar
[VGA_ATC_COLOR_PAGE
] & 0xf) << 4) | (v
& 0xf);
1079 v
= ((s
->ar
[VGA_ATC_COLOR_PAGE
] & 0xc) << 4) | (v
& 0x3f);
1082 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
1083 c6_to_8(s
->palette
[v
+ 1]),
1084 c6_to_8(s
->palette
[v
+ 2]));
1085 if (col
!= palette
[i
]) {
1093 /* return true if the palette was modified */
1094 static int update_palette256(VGACommonState
*s
)
1097 uint32_t v
, col
, *palette
;
1100 palette
= s
->last_palette
;
1102 for(i
= 0; i
< 256; i
++) {
1104 col
= s
->rgb_to_pixel(s
->palette
[v
],
1108 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
1109 c6_to_8(s
->palette
[v
+ 1]),
1110 c6_to_8(s
->palette
[v
+ 2]));
1112 if (col
!= palette
[i
]) {
1121 static void vga_get_offsets(VGACommonState
*s
,
1122 uint32_t *pline_offset
,
1123 uint32_t *pstart_addr
,
1124 uint32_t *pline_compare
)
1126 uint32_t start_addr
, line_offset
, line_compare
;
1127 #ifdef CONFIG_BOCHS_VBE
1128 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1129 line_offset
= s
->vbe_line_offset
;
1130 start_addr
= s
->vbe_start_addr
;
1131 line_compare
= 65535;
1135 /* compute line_offset in bytes */
1136 line_offset
= s
->cr
[VGA_CRTC_OFFSET
];
1139 /* starting address */
1140 start_addr
= s
->cr
[VGA_CRTC_START_LO
] |
1141 (s
->cr
[VGA_CRTC_START_HI
] << 8);
1144 line_compare
= s
->cr
[VGA_CRTC_LINE_COMPARE
] |
1145 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x10) << 4) |
1146 ((s
->cr
[VGA_CRTC_MAX_SCAN
] & 0x40) << 3);
1148 *pline_offset
= line_offset
;
1149 *pstart_addr
= start_addr
;
1150 *pline_compare
= line_compare
;
1153 /* update start_addr and line_offset. Return TRUE if modified */
1154 static int update_basic_params(VGACommonState
*s
)
1157 uint32_t start_addr
, line_offset
, line_compare
;
1161 s
->get_offsets(s
, &line_offset
, &start_addr
, &line_compare
);
1163 if (line_offset
!= s
->line_offset
||
1164 start_addr
!= s
->start_addr
||
1165 line_compare
!= s
->line_compare
) {
1166 s
->line_offset
= line_offset
;
1167 s
->start_addr
= start_addr
;
1168 s
->line_compare
= line_compare
;
1176 static inline int get_depth_index(DisplayState
*s
)
1178 switch(ds_get_bits_per_pixel(s
)) {
1187 if (is_surface_bgr(s
->surface
))
1194 static vga_draw_glyph8_func
* const vga_draw_glyph8_table
[NB_DEPTHS
] = {
1204 static vga_draw_glyph8_func
* const vga_draw_glyph16_table
[NB_DEPTHS
] = {
1206 vga_draw_glyph16_16
,
1207 vga_draw_glyph16_16
,
1208 vga_draw_glyph16_32
,
1209 vga_draw_glyph16_32
,
1210 vga_draw_glyph16_16
,
1211 vga_draw_glyph16_16
,
1214 static vga_draw_glyph9_func
* const vga_draw_glyph9_table
[NB_DEPTHS
] = {
1224 static const uint8_t cursor_glyph
[32 * 4] = {
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,
1239 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1240 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1243 static void vga_get_text_resolution(VGACommonState
*s
, int *pwidth
, int *pheight
,
1244 int *pcwidth
, int *pcheight
)
1246 int width
, cwidth
, height
, cheight
;
1248 /* total width & height */
1249 cheight
= (s
->cr
[VGA_CRTC_MAX_SCAN
] & 0x1f) + 1;
1251 if (!(s
->sr
[VGA_SEQ_CLOCK_MODE
] & VGA_SR01_CHAR_CLK_8DOTS
)) {
1254 if (s
->sr
[VGA_SEQ_CLOCK_MODE
] & 0x08) {
1255 cwidth
= 16; /* NOTE: no 18 pixel wide */
1257 width
= (s
->cr
[VGA_CRTC_H_DISP
] + 1);
1258 if (s
->cr
[VGA_CRTC_V_TOTAL
] == 100) {
1259 /* ugly hack for CGA 160x100x16 - explain me the logic */
1262 height
= s
->cr
[VGA_CRTC_V_DISP_END
] |
1263 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x02) << 7) |
1264 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x40) << 3);
1265 height
= (height
+ 1) / cheight
;
1271 *pcheight
= cheight
;
1274 typedef unsigned int rgb_to_pixel_dup_func(unsigned int r
, unsigned int g
, unsigned b
);
1276 static rgb_to_pixel_dup_func
* const rgb_to_pixel_dup_table
[NB_DEPTHS
] = {
1281 rgb_to_pixel32bgr_dup
,
1282 rgb_to_pixel15bgr_dup
,
1283 rgb_to_pixel16bgr_dup
,
1294 static void vga_draw_text(VGACommonState
*s
, int full_update
)
1296 int cx
, cy
, cheight
, cw
, ch
, cattr
, height
, width
, ch_attr
;
1297 int cx_min
, cx_max
, linesize
, x_incr
, line
, line1
;
1298 uint32_t offset
, fgcol
, bgcol
, v
, cursor_offset
;
1299 uint8_t *d1
, *d
, *src
, *dest
, *cursor_ptr
;
1300 const uint8_t *font_ptr
, *font_base
[2];
1301 int dup9
, line_offset
, depth_index
;
1303 uint32_t *ch_attr_ptr
;
1304 vga_draw_glyph8_func
*vga_draw_glyph8
;
1305 vga_draw_glyph9_func
*vga_draw_glyph9
;
1306 int64_t now
= qemu_get_clock_ms(vm_clock
);
1308 /* compute font data address (in plane 2) */
1309 v
= s
->sr
[VGA_SEQ_CHARACTER_MAP
];
1310 offset
= (((v
>> 4) & 1) | ((v
<< 1) & 6)) * 8192 * 4 + 2;
1311 if (offset
!= s
->font_offsets
[0]) {
1312 s
->font_offsets
[0] = offset
;
1315 font_base
[0] = s
->vram_ptr
+ offset
;
1317 offset
= (((v
>> 5) & 1) | ((v
>> 1) & 6)) * 8192 * 4 + 2;
1318 font_base
[1] = s
->vram_ptr
+ offset
;
1319 if (offset
!= s
->font_offsets
[1]) {
1320 s
->font_offsets
[1] = offset
;
1323 if (s
->plane_updated
& (1 << 2) || s
->chain4_alias
) {
1324 /* if the plane 2 was modified since the last display, it
1325 indicates the font may have been modified */
1326 s
->plane_updated
= 0;
1329 full_update
|= update_basic_params(s
);
1331 line_offset
= s
->line_offset
;
1333 vga_get_text_resolution(s
, &width
, &height
, &cw
, &cheight
);
1334 if ((height
* width
) <= 1) {
1335 /* better than nothing: exit if transient size is too small */
1338 if ((height
* width
) > CH_ATTR_SIZE
) {
1339 /* better than nothing: exit if transient size is too big */
1343 if (width
!= s
->last_width
|| height
!= s
->last_height
||
1344 cw
!= s
->last_cw
|| cheight
!= s
->last_ch
|| s
->last_depth
) {
1345 s
->last_scr_width
= width
* cw
;
1346 s
->last_scr_height
= height
* cheight
;
1347 qemu_console_resize(s
->ds
, s
->last_scr_width
, s
->last_scr_height
);
1349 s
->last_width
= width
;
1350 s
->last_height
= height
;
1351 s
->last_ch
= cheight
;
1356 rgb_to_pixel_dup_table
[get_depth_index(s
->ds
)];
1357 full_update
|= update_palette16(s
);
1358 palette
= s
->last_palette
;
1359 x_incr
= cw
* ((ds_get_bits_per_pixel(s
->ds
) + 7) >> 3);
1361 cursor_offset
= ((s
->cr
[VGA_CRTC_CURSOR_HI
] << 8) |
1362 s
->cr
[VGA_CRTC_CURSOR_LO
]) - s
->start_addr
;
1363 if (cursor_offset
!= s
->cursor_offset
||
1364 s
->cr
[VGA_CRTC_CURSOR_START
] != s
->cursor_start
||
1365 s
->cr
[VGA_CRTC_CURSOR_END
] != s
->cursor_end
) {
1366 /* if the cursor position changed, we update the old and new
1368 if (s
->cursor_offset
< CH_ATTR_SIZE
)
1369 s
->last_ch_attr
[s
->cursor_offset
] = -1;
1370 if (cursor_offset
< CH_ATTR_SIZE
)
1371 s
->last_ch_attr
[cursor_offset
] = -1;
1372 s
->cursor_offset
= cursor_offset
;
1373 s
->cursor_start
= s
->cr
[VGA_CRTC_CURSOR_START
];
1374 s
->cursor_end
= s
->cr
[VGA_CRTC_CURSOR_END
];
1376 cursor_ptr
= s
->vram_ptr
+ (s
->start_addr
+ cursor_offset
) * 4;
1377 if (now
>= s
->cursor_blink_time
) {
1378 s
->cursor_blink_time
= now
+ VGA_TEXT_CURSOR_PERIOD_MS
/ 2;
1379 s
->cursor_visible_phase
= !s
->cursor_visible_phase
;
1382 depth_index
= get_depth_index(s
->ds
);
1384 vga_draw_glyph8
= vga_draw_glyph16_table
[depth_index
];
1386 vga_draw_glyph8
= vga_draw_glyph8_table
[depth_index
];
1387 vga_draw_glyph9
= vga_draw_glyph9_table
[depth_index
];
1389 dest
= ds_get_data(s
->ds
);
1390 linesize
= ds_get_linesize(s
->ds
);
1391 ch_attr_ptr
= s
->last_ch_attr
;
1393 offset
= s
->start_addr
* 4;
1394 for(cy
= 0; cy
< height
; cy
++) {
1396 src
= s
->vram_ptr
+ offset
;
1399 for(cx
= 0; cx
< width
; cx
++) {
1400 ch_attr
= *(uint16_t *)src
;
1401 if (full_update
|| ch_attr
!= *ch_attr_ptr
|| src
== cursor_ptr
) {
1406 *ch_attr_ptr
= ch_attr
;
1407 #ifdef HOST_WORDS_BIGENDIAN
1409 cattr
= ch_attr
& 0xff;
1411 ch
= ch_attr
& 0xff;
1412 cattr
= ch_attr
>> 8;
1414 font_ptr
= font_base
[(cattr
>> 3) & 1];
1415 font_ptr
+= 32 * 4 * ch
;
1416 bgcol
= palette
[cattr
>> 4];
1417 fgcol
= palette
[cattr
& 0x0f];
1419 vga_draw_glyph8(d1
, linesize
,
1420 font_ptr
, cheight
, fgcol
, bgcol
);
1423 if (ch
>= 0xb0 && ch
<= 0xdf &&
1424 (s
->ar
[VGA_ATC_MODE
] & 0x04)) {
1427 vga_draw_glyph9(d1
, linesize
,
1428 font_ptr
, cheight
, fgcol
, bgcol
, dup9
);
1430 if (src
== cursor_ptr
&&
1431 !(s
->cr
[VGA_CRTC_CURSOR_START
] & 0x20) &&
1432 s
->cursor_visible_phase
) {
1433 int line_start
, line_last
, h
;
1434 /* draw the cursor */
1435 line_start
= s
->cr
[VGA_CRTC_CURSOR_START
] & 0x1f;
1436 line_last
= s
->cr
[VGA_CRTC_CURSOR_END
] & 0x1f;
1437 /* XXX: check that */
1438 if (line_last
> cheight
- 1)
1439 line_last
= cheight
- 1;
1440 if (line_last
>= line_start
&& line_start
< cheight
) {
1441 h
= line_last
- line_start
+ 1;
1442 d
= d1
+ linesize
* line_start
;
1444 vga_draw_glyph8(d
, linesize
,
1445 cursor_glyph
, h
, fgcol
, bgcol
);
1447 vga_draw_glyph9(d
, linesize
,
1448 cursor_glyph
, h
, fgcol
, bgcol
, 1);
1458 dpy_update(s
->ds
, cx_min
* cw
, cy
* cheight
,
1459 (cx_max
- cx_min
+ 1) * cw
, cheight
);
1461 dest
+= linesize
* cheight
;
1462 line1
= line
+ cheight
;
1463 offset
+= line_offset
;
1464 if (line
< s
->line_compare
&& line1
>= s
->line_compare
) {
1485 static vga_draw_line_func
* const vga_draw_line_table
[NB_DEPTHS
* VGA_DRAW_LINE_NB
] = {
1495 vga_draw_line2d2_16
,
1496 vga_draw_line2d2_16
,
1497 vga_draw_line2d2_32
,
1498 vga_draw_line2d2_32
,
1499 vga_draw_line2d2_16
,
1500 vga_draw_line2d2_16
,
1511 vga_draw_line4d2_16
,
1512 vga_draw_line4d2_16
,
1513 vga_draw_line4d2_32
,
1514 vga_draw_line4d2_32
,
1515 vga_draw_line4d2_16
,
1516 vga_draw_line4d2_16
,
1519 vga_draw_line8d2_16
,
1520 vga_draw_line8d2_16
,
1521 vga_draw_line8d2_32
,
1522 vga_draw_line8d2_32
,
1523 vga_draw_line8d2_16
,
1524 vga_draw_line8d2_16
,
1538 vga_draw_line15_32bgr
,
1539 vga_draw_line15_15bgr
,
1540 vga_draw_line15_16bgr
,
1546 vga_draw_line16_32bgr
,
1547 vga_draw_line16_15bgr
,
1548 vga_draw_line16_16bgr
,
1554 vga_draw_line24_32bgr
,
1555 vga_draw_line24_15bgr
,
1556 vga_draw_line24_16bgr
,
1562 vga_draw_line32_32bgr
,
1563 vga_draw_line32_15bgr
,
1564 vga_draw_line32_16bgr
,
1567 static int vga_get_bpp(VGACommonState
*s
)
1570 #ifdef CONFIG_BOCHS_VBE
1571 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1572 ret
= s
->vbe_regs
[VBE_DISPI_INDEX_BPP
];
1581 static void vga_get_resolution(VGACommonState
*s
, int *pwidth
, int *pheight
)
1585 #ifdef CONFIG_BOCHS_VBE
1586 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1587 width
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
];
1588 height
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
];
1592 width
= (s
->cr
[VGA_CRTC_H_DISP
] + 1) * 8;
1593 height
= s
->cr
[VGA_CRTC_V_DISP_END
] |
1594 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x02) << 7) |
1595 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x40) << 3);
1596 height
= (height
+ 1);
1602 void vga_invalidate_scanlines(VGACommonState
*s
, int y1
, int y2
)
1605 if (y1
>= VGA_MAX_HEIGHT
)
1607 if (y2
>= VGA_MAX_HEIGHT
)
1608 y2
= VGA_MAX_HEIGHT
;
1609 for(y
= y1
; y
< y2
; y
++) {
1610 s
->invalidated_y_table
[y
>> 5] |= 1 << (y
& 0x1f);
1614 static void vga_sync_dirty_bitmap(VGACommonState
*s
)
1616 memory_region_sync_dirty_bitmap(&s
->vram
);
1619 void vga_dirty_log_start(VGACommonState
*s
)
1621 memory_region_set_log(&s
->vram
, true, DIRTY_MEMORY_VGA
);
1624 void vga_dirty_log_stop(VGACommonState
*s
)
1626 memory_region_set_log(&s
->vram
, false, DIRTY_MEMORY_VGA
);
1632 static void vga_draw_graphic(VGACommonState
*s
, int full_update
)
1634 int y1
, y
, update
, linesize
, y_start
, double_scan
, mask
, depth
;
1635 int width
, height
, shift_control
, line_offset
, bwidth
, bits
;
1636 ram_addr_t page0
, page1
, page_min
, page_max
;
1637 int disp_width
, multi_scan
, multi_run
;
1639 uint32_t v
, addr1
, addr
;
1640 vga_draw_line_func
*vga_draw_line
;
1642 full_update
|= update_basic_params(s
);
1645 vga_sync_dirty_bitmap(s
);
1647 s
->get_resolution(s
, &width
, &height
);
1650 shift_control
= (s
->gr
[VGA_GFX_MODE
] >> 5) & 3;
1651 double_scan
= (s
->cr
[VGA_CRTC_MAX_SCAN
] >> 7);
1652 if (shift_control
!= 1) {
1653 multi_scan
= (((s
->cr
[VGA_CRTC_MAX_SCAN
] & 0x1f) + 1) << double_scan
)
1656 /* in CGA modes, multi_scan is ignored */
1657 /* XXX: is it correct ? */
1658 multi_scan
= double_scan
;
1660 multi_run
= multi_scan
;
1661 if (shift_control
!= s
->shift_control
||
1662 double_scan
!= s
->double_scan
) {
1664 s
->shift_control
= shift_control
;
1665 s
->double_scan
= double_scan
;
1668 if (shift_control
== 0) {
1669 if (s
->sr
[VGA_SEQ_CLOCK_MODE
] & 8) {
1672 } else if (shift_control
== 1) {
1673 if (s
->sr
[VGA_SEQ_CLOCK_MODE
] & 8) {
1678 depth
= s
->get_bpp(s
);
1679 if (s
->line_offset
!= s
->last_line_offset
||
1680 disp_width
!= s
->last_width
||
1681 height
!= s
->last_height
||
1682 s
->last_depth
!= depth
) {
1683 #if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
1684 if (depth
== 16 || depth
== 32) {
1688 qemu_free_displaysurface(s
->ds
);
1689 s
->ds
->surface
= qemu_create_displaysurface_from(disp_width
, height
, depth
,
1691 s
->vram_ptr
+ (s
->start_addr
* 4));
1692 #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
1693 s
->ds
->surface
->pf
= qemu_different_endianness_pixelformat(depth
);
1697 qemu_console_resize(s
->ds
, disp_width
, height
);
1699 s
->last_scr_width
= disp_width
;
1700 s
->last_scr_height
= height
;
1701 s
->last_width
= disp_width
;
1702 s
->last_height
= height
;
1703 s
->last_line_offset
= s
->line_offset
;
1704 s
->last_depth
= depth
;
1706 } else if (is_buffer_shared(s
->ds
->surface
) &&
1707 (full_update
|| s
->ds
->surface
->data
!= s
->vram_ptr
+ (s
->start_addr
* 4))) {
1708 s
->ds
->surface
->data
= s
->vram_ptr
+ (s
->start_addr
* 4);
1713 rgb_to_pixel_dup_table
[get_depth_index(s
->ds
)];
1715 if (shift_control
== 0) {
1716 full_update
|= update_palette16(s
);
1717 if (s
->sr
[VGA_SEQ_CLOCK_MODE
] & 8) {
1718 v
= VGA_DRAW_LINE4D2
;
1723 } else if (shift_control
== 1) {
1724 full_update
|= update_palette16(s
);
1725 if (s
->sr
[VGA_SEQ_CLOCK_MODE
] & 8) {
1726 v
= VGA_DRAW_LINE2D2
;
1732 switch(s
->get_bpp(s
)) {
1735 full_update
|= update_palette256(s
);
1736 v
= VGA_DRAW_LINE8D2
;
1740 full_update
|= update_palette256(s
);
1745 v
= VGA_DRAW_LINE15
;
1749 v
= VGA_DRAW_LINE16
;
1753 v
= VGA_DRAW_LINE24
;
1757 v
= VGA_DRAW_LINE32
;
1762 vga_draw_line
= vga_draw_line_table
[v
* NB_DEPTHS
+ get_depth_index(s
->ds
)];
1764 if (!is_buffer_shared(s
->ds
->surface
) && s
->cursor_invalidate
)
1765 s
->cursor_invalidate(s
);
1767 line_offset
= s
->line_offset
;
1769 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",
1770 width
, height
, v
, line_offset
, s
->cr
[9], s
->cr
[VGA_CRTC_MODE
],
1771 s
->line_compare
, s
->sr
[VGA_SEQ_CLOCK_MODE
]);
1773 addr1
= (s
->start_addr
* 4);
1774 bwidth
= (width
* bits
+ 7) / 8;
1778 d
= ds_get_data(s
->ds
);
1779 linesize
= ds_get_linesize(s
->ds
);
1781 for(y
= 0; y
< height
; y
++) {
1783 if (!(s
->cr
[VGA_CRTC_MODE
] & 1)) {
1785 /* CGA compatibility handling */
1786 shift
= 14 + ((s
->cr
[VGA_CRTC_MODE
] >> 6) & 1);
1787 addr
= (addr
& ~(1 << shift
)) | ((y1
& 1) << shift
);
1789 if (!(s
->cr
[VGA_CRTC_MODE
] & 2)) {
1790 addr
= (addr
& ~0x8000) | ((y1
& 2) << 14);
1792 update
= full_update
;
1794 page1
= addr
+ bwidth
- 1;
1795 update
|= memory_region_get_dirty(&s
->vram
, page0
, page1
- page0
,
1797 /* explicit invalidation for the hardware cursor */
1798 update
|= (s
->invalidated_y_table
[y
>> 5] >> (y
& 0x1f)) & 1;
1802 if (page0
< page_min
)
1804 if (page1
> page_max
)
1806 if (!(is_buffer_shared(s
->ds
->surface
))) {
1807 vga_draw_line(s
, d
, s
->vram_ptr
+ addr
, width
);
1808 if (s
->cursor_draw_line
)
1809 s
->cursor_draw_line(s
, d
, y
);
1813 /* flush to display */
1814 dpy_update(s
->ds
, 0, y_start
,
1815 disp_width
, y
- y_start
);
1820 mask
= (s
->cr
[VGA_CRTC_MODE
] & 3) ^ 3;
1821 if ((y1
& mask
) == mask
)
1822 addr1
+= line_offset
;
1824 multi_run
= multi_scan
;
1828 /* line compare acts on the displayed lines */
1829 if (y
== s
->line_compare
)
1834 /* flush to display */
1835 dpy_update(s
->ds
, 0, y_start
,
1836 disp_width
, y
- y_start
);
1838 /* reset modified pages */
1839 if (page_max
>= page_min
) {
1840 memory_region_reset_dirty(&s
->vram
,
1842 page_max
- page_min
,
1845 memset(s
->invalidated_y_table
, 0, ((height
+ 31) >> 5) * 4);
1848 static void vga_draw_blank(VGACommonState
*s
, int full_update
)
1855 if (s
->last_scr_width
<= 0 || s
->last_scr_height
<= 0)
1859 rgb_to_pixel_dup_table
[get_depth_index(s
->ds
)];
1860 if (ds_get_bits_per_pixel(s
->ds
) == 8)
1861 val
= s
->rgb_to_pixel(0, 0, 0);
1864 w
= s
->last_scr_width
* ((ds_get_bits_per_pixel(s
->ds
) + 7) >> 3);
1865 d
= ds_get_data(s
->ds
);
1866 for(i
= 0; i
< s
->last_scr_height
; i
++) {
1868 d
+= ds_get_linesize(s
->ds
);
1870 dpy_update(s
->ds
, 0, 0,
1871 s
->last_scr_width
, s
->last_scr_height
);
1874 #define GMODE_TEXT 0
1875 #define GMODE_GRAPH 1
1876 #define GMODE_BLANK 2
1878 static void vga_update_display(void *opaque
)
1880 VGACommonState
*s
= opaque
;
1881 int full_update
, graphic_mode
;
1883 qemu_flush_coalesced_mmio_buffer();
1885 if (ds_get_bits_per_pixel(s
->ds
) == 0) {
1889 if (!(s
->ar_index
& 0x20)) {
1890 graphic_mode
= GMODE_BLANK
;
1892 graphic_mode
= s
->gr
[VGA_GFX_MISC
] & VGA_GR06_GRAPHICS_MODE
;
1894 if (graphic_mode
!= s
->graphic_mode
) {
1895 s
->graphic_mode
= graphic_mode
;
1896 s
->cursor_blink_time
= qemu_get_clock_ms(vm_clock
);
1899 switch(graphic_mode
) {
1901 vga_draw_text(s
, full_update
);
1904 vga_draw_graphic(s
, full_update
);
1908 vga_draw_blank(s
, full_update
);
1914 /* force a full display refresh */
1915 static void vga_invalidate_display(void *opaque
)
1917 VGACommonState
*s
= opaque
;
1920 s
->last_height
= -1;
1923 void vga_common_reset(VGACommonState
*s
)
1926 memset(s
->sr
, '\0', sizeof(s
->sr
));
1928 memset(s
->gr
, '\0', sizeof(s
->gr
));
1930 memset(s
->ar
, '\0', sizeof(s
->ar
));
1931 s
->ar_flip_flop
= 0;
1933 memset(s
->cr
, '\0', sizeof(s
->cr
));
1939 s
->dac_sub_index
= 0;
1940 s
->dac_read_index
= 0;
1941 s
->dac_write_index
= 0;
1942 memset(s
->dac_cache
, '\0', sizeof(s
->dac_cache
));
1944 memset(s
->palette
, '\0', sizeof(s
->palette
));
1946 #ifdef CONFIG_BOCHS_VBE
1948 memset(s
->vbe_regs
, '\0', sizeof(s
->vbe_regs
));
1949 s
->vbe_regs
[VBE_DISPI_INDEX_ID
] = VBE_DISPI_ID5
;
1950 s
->vbe_start_addr
= 0;
1951 s
->vbe_line_offset
= 0;
1952 s
->vbe_bank_mask
= (s
->vram_size
>> 16) - 1;
1954 memset(s
->font_offsets
, '\0', sizeof(s
->font_offsets
));
1955 s
->graphic_mode
= -1; /* force full update */
1956 s
->shift_control
= 0;
1959 s
->line_compare
= 0;
1961 s
->plane_updated
= 0;
1966 s
->last_scr_width
= 0;
1967 s
->last_scr_height
= 0;
1968 s
->cursor_start
= 0;
1970 s
->cursor_offset
= 0;
1971 memset(s
->invalidated_y_table
, '\0', sizeof(s
->invalidated_y_table
));
1972 memset(s
->last_palette
, '\0', sizeof(s
->last_palette
));
1973 memset(s
->last_ch_attr
, '\0', sizeof(s
->last_ch_attr
));
1974 switch (vga_retrace_method
) {
1975 case VGA_RETRACE_DUMB
:
1977 case VGA_RETRACE_PRECISE
:
1978 memset(&s
->retrace_info
, 0, sizeof (s
->retrace_info
));
1981 vga_update_memory_access(s
);
1984 static void vga_reset(void *opaque
)
1986 VGACommonState
*s
= opaque
;
1987 vga_common_reset(s
);
1990 #define TEXTMODE_X(x) ((x) % width)
1991 #define TEXTMODE_Y(x) ((x) / width)
1992 #define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1993 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1994 /* relay text rendering to the display driver
1995 * instead of doing a full vga_update_display() */
1996 static void vga_update_text(void *opaque
, console_ch_t
*chardata
)
1998 VGACommonState
*s
= opaque
;
1999 int graphic_mode
, i
, cursor_offset
, cursor_visible
;
2000 int cw
, cheight
, width
, height
, size
, c_min
, c_max
;
2002 console_ch_t
*dst
, val
;
2003 char msg_buffer
[80];
2004 int full_update
= 0;
2006 qemu_flush_coalesced_mmio_buffer();
2008 if (!(s
->ar_index
& 0x20)) {
2009 graphic_mode
= GMODE_BLANK
;
2011 graphic_mode
= s
->gr
[VGA_GFX_MISC
] & VGA_GR06_GRAPHICS_MODE
;
2013 if (graphic_mode
!= s
->graphic_mode
) {
2014 s
->graphic_mode
= graphic_mode
;
2017 if (s
->last_width
== -1) {
2022 switch (graphic_mode
) {
2024 /* TODO: update palette */
2025 full_update
|= update_basic_params(s
);
2027 /* total width & height */
2028 cheight
= (s
->cr
[VGA_CRTC_MAX_SCAN
] & 0x1f) + 1;
2030 if (!(s
->sr
[VGA_SEQ_CLOCK_MODE
] & VGA_SR01_CHAR_CLK_8DOTS
)) {
2033 if (s
->sr
[VGA_SEQ_CLOCK_MODE
] & 0x08) {
2034 cw
= 16; /* NOTE: no 18 pixel wide */
2036 width
= (s
->cr
[VGA_CRTC_H_DISP
] + 1);
2037 if (s
->cr
[VGA_CRTC_V_TOTAL
] == 100) {
2038 /* ugly hack for CGA 160x100x16 - explain me the logic */
2041 height
= s
->cr
[VGA_CRTC_V_DISP_END
] |
2042 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x02) << 7) |
2043 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x40) << 3);
2044 height
= (height
+ 1) / cheight
;
2047 size
= (height
* width
);
2048 if (size
> CH_ATTR_SIZE
) {
2052 snprintf(msg_buffer
, sizeof(msg_buffer
), "%i x %i Text mode",
2057 if (width
!= s
->last_width
|| height
!= s
->last_height
||
2058 cw
!= s
->last_cw
|| cheight
!= s
->last_ch
) {
2059 s
->last_scr_width
= width
* cw
;
2060 s
->last_scr_height
= height
* cheight
;
2061 s
->ds
->surface
->width
= width
;
2062 s
->ds
->surface
->height
= height
;
2064 s
->last_width
= width
;
2065 s
->last_height
= height
;
2066 s
->last_ch
= cheight
;
2071 /* Update "hardware" cursor */
2072 cursor_offset
= ((s
->cr
[VGA_CRTC_CURSOR_HI
] << 8) |
2073 s
->cr
[VGA_CRTC_CURSOR_LO
]) - s
->start_addr
;
2074 if (cursor_offset
!= s
->cursor_offset
||
2075 s
->cr
[VGA_CRTC_CURSOR_START
] != s
->cursor_start
||
2076 s
->cr
[VGA_CRTC_CURSOR_END
] != s
->cursor_end
|| full_update
) {
2077 cursor_visible
= !(s
->cr
[VGA_CRTC_CURSOR_START
] & 0x20);
2078 if (cursor_visible
&& cursor_offset
< size
&& cursor_offset
>= 0)
2080 TEXTMODE_X(cursor_offset
),
2081 TEXTMODE_Y(cursor_offset
));
2083 dpy_cursor(s
->ds
, -1, -1);
2084 s
->cursor_offset
= cursor_offset
;
2085 s
->cursor_start
= s
->cr
[VGA_CRTC_CURSOR_START
];
2086 s
->cursor_end
= s
->cr
[VGA_CRTC_CURSOR_END
];
2089 src
= (uint32_t *) s
->vram_ptr
+ s
->start_addr
;
2093 for (i
= 0; i
< size
; src
++, dst
++, i
++)
2094 console_write_ch(dst
, VMEM2CHTYPE(le32_to_cpu(*src
)));
2096 dpy_update(s
->ds
, 0, 0, width
, height
);
2100 for (i
= 0; i
< size
; src
++, dst
++, i
++) {
2101 console_write_ch(&val
, VMEM2CHTYPE(le32_to_cpu(*src
)));
2109 for (; i
< size
; src
++, dst
++, i
++) {
2110 console_write_ch(&val
, VMEM2CHTYPE(le32_to_cpu(*src
)));
2117 if (c_min
<= c_max
) {
2118 i
= TEXTMODE_Y(c_min
);
2119 dpy_update(s
->ds
, 0, i
, width
, TEXTMODE_Y(c_max
) - i
+ 1);
2128 s
->get_resolution(s
, &width
, &height
);
2129 snprintf(msg_buffer
, sizeof(msg_buffer
), "%i x %i Graphic mode",
2137 snprintf(msg_buffer
, sizeof(msg_buffer
), "VGA Blank mode");
2141 /* Display a message */
2143 s
->last_height
= height
= 3;
2144 dpy_cursor(s
->ds
, -1, -1);
2145 s
->ds
->surface
->width
= s
->last_width
;
2146 s
->ds
->surface
->height
= height
;
2149 for (dst
= chardata
, i
= 0; i
< s
->last_width
* height
; i
++)
2150 console_write_ch(dst
++, ' ');
2152 size
= strlen(msg_buffer
);
2153 width
= (s
->last_width
- size
) / 2;
2154 dst
= chardata
+ s
->last_width
+ width
;
2155 for (i
= 0; i
< size
; i
++)
2156 console_write_ch(dst
++, 0x00200100 | msg_buffer
[i
]);
2158 dpy_update(s
->ds
, 0, 0, s
->last_width
, height
);
2161 static uint64_t vga_mem_read(void *opaque
, target_phys_addr_t addr
,
2164 VGACommonState
*s
= opaque
;
2166 return vga_mem_readb(s
, addr
);
2169 static void vga_mem_write(void *opaque
, target_phys_addr_t addr
,
2170 uint64_t data
, unsigned size
)
2172 VGACommonState
*s
= opaque
;
2174 return vga_mem_writeb(s
, addr
, data
);
2177 const MemoryRegionOps vga_mem_ops
= {
2178 .read
= vga_mem_read
,
2179 .write
= vga_mem_write
,
2180 .endianness
= DEVICE_LITTLE_ENDIAN
,
2182 .min_access_size
= 1,
2183 .max_access_size
= 1,
2187 static int vga_common_post_load(void *opaque
, int version_id
)
2189 VGACommonState
*s
= opaque
;
2192 s
->graphic_mode
= -1;
2196 const VMStateDescription vmstate_vga_common
= {
2199 .minimum_version_id
= 2,
2200 .minimum_version_id_old
= 2,
2201 .post_load
= vga_common_post_load
,
2202 .fields
= (VMStateField
[]) {
2203 VMSTATE_UINT32(latch
, VGACommonState
),
2204 VMSTATE_UINT8(sr_index
, VGACommonState
),
2205 VMSTATE_PARTIAL_BUFFER(sr
, VGACommonState
, 8),
2206 VMSTATE_UINT8(gr_index
, VGACommonState
),
2207 VMSTATE_PARTIAL_BUFFER(gr
, VGACommonState
, 16),
2208 VMSTATE_UINT8(ar_index
, VGACommonState
),
2209 VMSTATE_BUFFER(ar
, VGACommonState
),
2210 VMSTATE_INT32(ar_flip_flop
, VGACommonState
),
2211 VMSTATE_UINT8(cr_index
, VGACommonState
),
2212 VMSTATE_BUFFER(cr
, VGACommonState
),
2213 VMSTATE_UINT8(msr
, VGACommonState
),
2214 VMSTATE_UINT8(fcr
, VGACommonState
),
2215 VMSTATE_UINT8(st00
, VGACommonState
),
2216 VMSTATE_UINT8(st01
, VGACommonState
),
2218 VMSTATE_UINT8(dac_state
, VGACommonState
),
2219 VMSTATE_UINT8(dac_sub_index
, VGACommonState
),
2220 VMSTATE_UINT8(dac_read_index
, VGACommonState
),
2221 VMSTATE_UINT8(dac_write_index
, VGACommonState
),
2222 VMSTATE_BUFFER(dac_cache
, VGACommonState
),
2223 VMSTATE_BUFFER(palette
, VGACommonState
),
2225 VMSTATE_INT32(bank_offset
, VGACommonState
),
2226 VMSTATE_UINT8_EQUAL(is_vbe_vmstate
, VGACommonState
),
2227 #ifdef CONFIG_BOCHS_VBE
2228 VMSTATE_UINT16(vbe_index
, VGACommonState
),
2229 VMSTATE_UINT16_ARRAY(vbe_regs
, VGACommonState
, VBE_DISPI_INDEX_NB
),
2230 VMSTATE_UINT32(vbe_start_addr
, VGACommonState
),
2231 VMSTATE_UINT32(vbe_line_offset
, VGACommonState
),
2232 VMSTATE_UINT32(vbe_bank_mask
, VGACommonState
),
2234 VMSTATE_END_OF_LIST()
2238 void vga_common_init(VGACommonState
*s
)
2242 for(i
= 0;i
< 256; i
++) {
2244 for(j
= 0; j
< 8; j
++) {
2245 v
|= ((i
>> j
) & 1) << (j
* 4);
2250 for(j
= 0; j
< 4; j
++) {
2251 v
|= ((i
>> (2 * j
)) & 3) << (j
* 4);
2255 for(i
= 0; i
< 16; i
++) {
2257 for(j
= 0; j
< 4; j
++) {
2260 v
|= b
<< (2 * j
+ 1);
2265 /* valid range: 1 MB -> 256 MB */
2266 s
->vram_size
= 1024 * 1024;
2267 while (s
->vram_size
< (s
->vram_size_mb
<< 20) &&
2268 s
->vram_size
< (256 << 20)) {
2271 s
->vram_size_mb
= s
->vram_size
>> 20;
2273 #ifdef CONFIG_BOCHS_VBE
2274 s
->is_vbe_vmstate
= 1;
2276 s
->is_vbe_vmstate
= 0;
2278 memory_region_init_ram(&s
->vram
, "vga.vram", s
->vram_size
);
2279 vmstate_register_ram_global(&s
->vram
);
2280 xen_register_framebuffer(&s
->vram
);
2281 s
->vram_ptr
= memory_region_get_ram_ptr(&s
->vram
);
2282 s
->get_bpp
= vga_get_bpp
;
2283 s
->get_offsets
= vga_get_offsets
;
2284 s
->get_resolution
= vga_get_resolution
;
2285 s
->update
= vga_update_display
;
2286 s
->invalidate
= vga_invalidate_display
;
2287 s
->screen_dump
= vga_screen_dump
;
2288 s
->text_update
= vga_update_text
;
2289 switch (vga_retrace_method
) {
2290 case VGA_RETRACE_DUMB
:
2291 s
->retrace
= vga_dumb_retrace
;
2292 s
->update_retrace_info
= vga_dumb_update_retrace_info
;
2295 case VGA_RETRACE_PRECISE
:
2296 s
->retrace
= vga_precise_retrace
;
2297 s
->update_retrace_info
= vga_precise_update_retrace_info
;
2300 vga_dirty_log_start(s
);
2303 static const MemoryRegionPortio vga_portio_list
[] = {
2304 { 0x04, 2, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3b4 */
2305 { 0x0a, 1, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3ba */
2306 { 0x10, 16, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3c0 */
2307 { 0x24, 2, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3d4 */
2308 { 0x2a, 1, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3da */
2309 PORTIO_END_OF_LIST(),
2312 #ifdef CONFIG_BOCHS_VBE
2313 static const MemoryRegionPortio vbe_portio_list
[] = {
2314 { 0, 1, 2, .read
= vbe_ioport_read_index
, .write
= vbe_ioport_write_index
},
2316 { 1, 1, 2, .read
= vbe_ioport_read_data
, .write
= vbe_ioport_write_data
},
2318 { 2, 1, 2, .read
= vbe_ioport_read_data
, .write
= vbe_ioport_write_data
},
2320 PORTIO_END_OF_LIST(),
2322 #endif /* CONFIG_BOCHS_VBE */
2324 /* Used by both ISA and PCI */
2325 MemoryRegion
*vga_init_io(VGACommonState
*s
,
2326 const MemoryRegionPortio
**vga_ports
,
2327 const MemoryRegionPortio
**vbe_ports
)
2329 MemoryRegion
*vga_mem
;
2331 *vga_ports
= vga_portio_list
;
2333 #ifdef CONFIG_BOCHS_VBE
2334 *vbe_ports
= vbe_portio_list
;
2337 vga_mem
= g_malloc(sizeof(*vga_mem
));
2338 memory_region_init_io(vga_mem
, &vga_mem_ops
, s
,
2339 "vga-lowmem", 0x20000);
2344 void vga_init(VGACommonState
*s
, MemoryRegion
*address_space
,
2345 MemoryRegion
*address_space_io
, bool init_vga_ports
)
2347 MemoryRegion
*vga_io_memory
;
2348 const MemoryRegionPortio
*vga_ports
, *vbe_ports
;
2349 PortioList
*vga_port_list
= g_new(PortioList
, 1);
2350 PortioList
*vbe_port_list
= g_new(PortioList
, 1);
2352 qemu_register_reset(vga_reset
, s
);
2356 s
->legacy_address_space
= address_space
;
2358 vga_io_memory
= vga_init_io(s
, &vga_ports
, &vbe_ports
);
2359 memory_region_add_subregion_overlap(address_space
,
2360 isa_mem_base
+ 0x000a0000,
2363 memory_region_set_coalescing(vga_io_memory
);
2364 if (init_vga_ports
) {
2365 portio_list_init(vga_port_list
, vga_ports
, s
, "vga");
2366 portio_list_add(vga_port_list
, address_space_io
, 0x3b0);
2369 portio_list_init(vbe_port_list
, vbe_ports
, s
, "vbe");
2370 portio_list_add(vbe_port_list
, address_space_io
, 0x1ce);
2374 void vga_init_vbe(VGACommonState
*s
, MemoryRegion
*system_memory
)
2376 #ifdef CONFIG_BOCHS_VBE
2377 /* With pc-0.12 and below we map both the PCI BAR and the fixed VBE region,
2378 * so use an alias to avoid double-mapping the same region.
2380 memory_region_init_alias(&s
->vram_vbe
, "vram.vbe",
2381 &s
->vram
, 0, memory_region_size(&s
->vram
));
2382 /* XXX: use optimized standard vga accesses */
2383 memory_region_add_subregion(system_memory
,
2384 VBE_DISPI_LFB_PHYSICAL_ADDRESS
,
2389 /********************************************************/
2390 /* vga screen dump */
2392 int ppm_save(const char *filename
, struct DisplaySurface
*ds
)
2400 char *linebuf
, *pbuf
;
2402 trace_ppm_save(filename
, ds
);
2403 f
= fopen(filename
, "wb");
2406 fprintf(f
, "P6\n%d %d\n%d\n",
2407 ds
->width
, ds
->height
, 255);
2408 linebuf
= g_malloc(ds
->width
* 3);
2410 for(y
= 0; y
< ds
->height
; y
++) {
2413 for(x
= 0; x
< ds
->width
; x
++) {
2414 if (ds
->pf
.bits_per_pixel
== 32)
2417 v
= (uint32_t) (*(uint16_t *)d
);
2418 /* Limited to 8 or fewer bits per channel: */
2419 r
= ((v
>> ds
->pf
.rshift
) & ds
->pf
.rmax
) << (8 - ds
->pf
.rbits
);
2420 g
= ((v
>> ds
->pf
.gshift
) & ds
->pf
.gmax
) << (8 - ds
->pf
.gbits
);
2421 b
= ((v
>> ds
->pf
.bshift
) & ds
->pf
.bmax
) << (8 - ds
->pf
.bbits
);
2425 d
+= ds
->pf
.bytes_per_pixel
;
2428 ret
= fwrite(linebuf
, 1, pbuf
- linebuf
, f
);
2436 /* save the vga display in a PPM image even if no display is
2438 static void vga_screen_dump(void *opaque
, const char *filename
, bool cswitch
)
2440 VGACommonState
*s
= opaque
;
2443 vga_invalidate_display(s
);
2446 ppm_save(filename
, s
->ds
->surface
);