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 if (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
] =
555 (s
->cr
[VGA_CRTC_OVERFLOW
] & ~0x10) | (val
& 0x10);
558 } else if ((vga_cga_hacks
& VGA_CGA_HACK_FONT_HEIGHT
) &&
559 !(s
->sr
[VGA_SEQ_CLOCK_MODE
] & VGA_SR01_CHAR_CLK_8DOTS
)) {
560 /* extra CGA compatibility hacks (not in standard VGA) */
561 if (s
->cr_index
== VGA_CRTC_MAX_SCAN
&&
563 (s
->cr
[VGA_CRTC_MAX_SCAN
] & 0xf) == 0xf) {
565 } else if (s
->cr_index
== VGA_CRTC_CURSOR_START
&&
567 (s
->cr
[VGA_CRTC_MAX_SCAN
] & 0xf) == 0xf) {
569 } else if (s
->cr_index
== VGA_CRTC_CURSOR_END
&&
571 (s
->cr
[VGA_CRTC_MAX_SCAN
] & 0xf) == 0xf) {
576 s
->cr
[s
->cr_index
] = val
;
578 switch(s
->cr_index
) {
579 case VGA_CRTC_H_TOTAL
:
580 case VGA_CRTC_H_SYNC_START
:
581 case VGA_CRTC_H_SYNC_END
:
582 case VGA_CRTC_V_TOTAL
:
583 case VGA_CRTC_OVERFLOW
:
584 case VGA_CRTC_V_SYNC_END
:
586 s
->update_retrace_info(s
);
597 #ifdef CONFIG_BOCHS_VBE
598 static uint32_t vbe_ioport_read_index(void *opaque
, uint32_t addr
)
600 VGACommonState
*s
= opaque
;
606 static uint32_t vbe_ioport_read_data(void *opaque
, uint32_t addr
)
608 VGACommonState
*s
= opaque
;
611 if (s
->vbe_index
< VBE_DISPI_INDEX_NB
) {
612 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_GETCAPS
) {
613 switch(s
->vbe_index
) {
614 /* XXX: do not hardcode ? */
615 case VBE_DISPI_INDEX_XRES
:
616 val
= VBE_DISPI_MAX_XRES
;
618 case VBE_DISPI_INDEX_YRES
:
619 val
= VBE_DISPI_MAX_YRES
;
621 case VBE_DISPI_INDEX_BPP
:
622 val
= VBE_DISPI_MAX_BPP
;
625 val
= s
->vbe_regs
[s
->vbe_index
];
629 val
= s
->vbe_regs
[s
->vbe_index
];
631 } else if (s
->vbe_index
== VBE_DISPI_INDEX_VIDEO_MEMORY_64K
) {
632 val
= s
->vram_size
/ (64 * 1024);
636 #ifdef DEBUG_BOCHS_VBE
637 printf("VBE: read index=0x%x val=0x%x\n", s
->vbe_index
, val
);
642 static void vbe_ioport_write_index(void *opaque
, uint32_t addr
, uint32_t val
)
644 VGACommonState
*s
= opaque
;
648 static void vbe_ioport_write_data(void *opaque
, uint32_t addr
, uint32_t val
)
650 VGACommonState
*s
= opaque
;
652 if (s
->vbe_index
<= VBE_DISPI_INDEX_NB
) {
653 #ifdef DEBUG_BOCHS_VBE
654 printf("VBE: write index=0x%x val=0x%x\n", s
->vbe_index
, val
);
656 switch(s
->vbe_index
) {
657 case VBE_DISPI_INDEX_ID
:
658 if (val
== VBE_DISPI_ID0
||
659 val
== VBE_DISPI_ID1
||
660 val
== VBE_DISPI_ID2
||
661 val
== VBE_DISPI_ID3
||
662 val
== VBE_DISPI_ID4
) {
663 s
->vbe_regs
[s
->vbe_index
] = val
;
666 case VBE_DISPI_INDEX_XRES
:
667 if ((val
<= VBE_DISPI_MAX_XRES
) && ((val
& 7) == 0)) {
668 s
->vbe_regs
[s
->vbe_index
] = val
;
671 case VBE_DISPI_INDEX_YRES
:
672 if (val
<= VBE_DISPI_MAX_YRES
) {
673 s
->vbe_regs
[s
->vbe_index
] = val
;
676 case VBE_DISPI_INDEX_BPP
:
679 if (val
== 4 || val
== 8 || val
== 15 ||
680 val
== 16 || val
== 24 || val
== 32) {
681 s
->vbe_regs
[s
->vbe_index
] = val
;
684 case VBE_DISPI_INDEX_BANK
:
685 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
686 val
&= (s
->vbe_bank_mask
>> 2);
688 val
&= s
->vbe_bank_mask
;
690 s
->vbe_regs
[s
->vbe_index
] = val
;
691 s
->bank_offset
= (val
<< 16);
692 vga_update_memory_access(s
);
694 case VBE_DISPI_INDEX_ENABLE
:
695 if ((val
& VBE_DISPI_ENABLED
) &&
696 !(s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
)) {
697 int h
, shift_control
;
699 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] =
700 s
->vbe_regs
[VBE_DISPI_INDEX_XRES
];
701 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_HEIGHT
] =
702 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
];
703 s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
] = 0;
704 s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
] = 0;
706 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
707 s
->vbe_line_offset
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 1;
709 s
->vbe_line_offset
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] *
710 ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
711 s
->vbe_start_addr
= 0;
713 /* clear the screen (should be done in BIOS) */
714 if (!(val
& VBE_DISPI_NOCLEARMEM
)) {
715 memset(s
->vram_ptr
, 0,
716 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] * s
->vbe_line_offset
);
719 /* we initialize the VGA graphic mode (should be done
721 /* graphic mode + memory map 1 */
722 s
->gr
[VGA_GFX_MISC
] = (s
->gr
[VGA_GFX_MISC
] & ~0x0c) | 0x04 |
723 VGA_GR06_GRAPHICS_MODE
;
724 s
->cr
[VGA_CRTC_MODE
] |= 3; /* no CGA modes */
725 s
->cr
[VGA_CRTC_OFFSET
] = s
->vbe_line_offset
>> 3;
727 s
->cr
[VGA_CRTC_H_DISP
] =
728 (s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 3) - 1;
729 /* height (only meaningful if < 1024) */
730 h
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] - 1;
731 s
->cr
[VGA_CRTC_V_DISP_END
] = h
;
732 s
->cr
[VGA_CRTC_OVERFLOW
] = (s
->cr
[VGA_CRTC_OVERFLOW
] & ~0x42) |
733 ((h
>> 7) & 0x02) | ((h
>> 3) & 0x40);
734 /* line compare to 1023 */
735 s
->cr
[VGA_CRTC_LINE_COMPARE
] = 0xff;
736 s
->cr
[VGA_CRTC_OVERFLOW
] |= 0x10;
737 s
->cr
[VGA_CRTC_MAX_SCAN
] |= 0x40;
739 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
741 s
->sr
[VGA_SEQ_CLOCK_MODE
] &= ~8; /* no double line */
744 /* set chain 4 mode */
745 s
->sr
[VGA_SEQ_MEMORY_MODE
] |= VGA_SR04_CHN_4M
;
746 /* activate all planes */
747 s
->sr
[VGA_SEQ_PLANE_WRITE
] |= VGA_SR02_ALL_PLANES
;
749 s
->gr
[VGA_GFX_MODE
] = (s
->gr
[VGA_GFX_MODE
] & ~0x60) |
750 (shift_control
<< 5);
751 s
->cr
[VGA_CRTC_MAX_SCAN
] &= ~0x9f; /* no double scan */
753 /* XXX: the bios should do that */
756 s
->dac_8bit
= (val
& VBE_DISPI_8BIT_DAC
) > 0;
757 s
->vbe_regs
[s
->vbe_index
] = val
;
758 vga_update_memory_access(s
);
760 case VBE_DISPI_INDEX_VIRT_WIDTH
:
762 int w
, h
, line_offset
;
764 if (val
< s
->vbe_regs
[VBE_DISPI_INDEX_XRES
])
767 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
768 line_offset
= w
>> 1;
770 line_offset
= w
* ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
771 h
= s
->vram_size
/ line_offset
;
772 /* XXX: support weird bochs semantics ? */
773 if (h
< s
->vbe_regs
[VBE_DISPI_INDEX_YRES
])
775 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] = w
;
776 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_HEIGHT
] = h
;
777 s
->vbe_line_offset
= line_offset
;
780 case VBE_DISPI_INDEX_X_OFFSET
:
781 case VBE_DISPI_INDEX_Y_OFFSET
:
784 s
->vbe_regs
[s
->vbe_index
] = val
;
785 s
->vbe_start_addr
= s
->vbe_line_offset
* s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
];
786 x
= s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
];
787 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
788 s
->vbe_start_addr
+= x
>> 1;
790 s
->vbe_start_addr
+= x
* ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
791 s
->vbe_start_addr
>>= 2;
801 /* called for accesses between 0xa0000 and 0xc0000 */
802 uint32_t vga_mem_readb(VGACommonState
*s
, target_phys_addr_t addr
)
804 int memory_map_mode
, plane
;
807 /* convert to VGA memory offset */
808 memory_map_mode
= (s
->gr
[VGA_GFX_MISC
] >> 2) & 3;
810 switch(memory_map_mode
) {
816 addr
+= s
->bank_offset
;
831 if (s
->sr
[VGA_SEQ_MEMORY_MODE
] & VGA_SR04_CHN_4M
) {
832 /* chain 4 mode : simplest access */
833 ret
= s
->vram_ptr
[addr
];
834 } else if (s
->gr
[VGA_GFX_MODE
] & 0x10) {
835 /* odd/even mode (aka text mode mapping) */
836 plane
= (s
->gr
[VGA_GFX_PLANE_READ
] & 2) | (addr
& 1);
837 ret
= s
->vram_ptr
[((addr
& ~1) << 1) | plane
];
839 /* standard VGA latched access */
840 s
->latch
= ((uint32_t *)s
->vram_ptr
)[addr
];
842 if (!(s
->gr
[VGA_GFX_MODE
] & 0x08)) {
844 plane
= s
->gr
[VGA_GFX_PLANE_READ
];
845 ret
= GET_PLANE(s
->latch
, plane
);
848 ret
= (s
->latch
^ mask16
[s
->gr
[VGA_GFX_COMPARE_VALUE
]]) &
849 mask16
[s
->gr
[VGA_GFX_COMPARE_MASK
]];
858 /* called for accesses between 0xa0000 and 0xc0000 */
859 void vga_mem_writeb(VGACommonState
*s
, target_phys_addr_t addr
, uint32_t val
)
861 int memory_map_mode
, plane
, write_mode
, b
, func_select
, mask
;
862 uint32_t write_mask
, bit_mask
, set_mask
;
865 printf("vga: [0x" TARGET_FMT_plx
"] = 0x%02x\n", addr
, val
);
867 /* convert to VGA memory offset */
868 memory_map_mode
= (s
->gr
[VGA_GFX_MISC
] >> 2) & 3;
870 switch(memory_map_mode
) {
876 addr
+= s
->bank_offset
;
891 if (s
->sr
[VGA_SEQ_MEMORY_MODE
] & VGA_SR04_CHN_4M
) {
892 /* chain 4 mode : simplest access */
895 if (s
->sr
[VGA_SEQ_PLANE_WRITE
] & mask
) {
896 s
->vram_ptr
[addr
] = val
;
898 printf("vga: chain4: [0x" TARGET_FMT_plx
"]\n", addr
);
900 s
->plane_updated
|= mask
; /* only used to detect font change */
901 memory_region_set_dirty(&s
->vram
, addr
, 1);
903 } else if (s
->gr
[VGA_GFX_MODE
] & 0x10) {
904 /* odd/even mode (aka text mode mapping) */
905 plane
= (s
->gr
[VGA_GFX_PLANE_READ
] & 2) | (addr
& 1);
907 if (s
->sr
[VGA_SEQ_PLANE_WRITE
] & mask
) {
908 addr
= ((addr
& ~1) << 1) | plane
;
909 s
->vram_ptr
[addr
] = val
;
911 printf("vga: odd/even: [0x" TARGET_FMT_plx
"]\n", addr
);
913 s
->plane_updated
|= mask
; /* only used to detect font change */
914 memory_region_set_dirty(&s
->vram
, addr
, 1);
917 /* standard VGA latched access */
918 write_mode
= s
->gr
[VGA_GFX_MODE
] & 3;
923 b
= s
->gr
[VGA_GFX_DATA_ROTATE
] & 7;
924 val
= ((val
>> b
) | (val
<< (8 - b
))) & 0xff;
928 /* apply set/reset mask */
929 set_mask
= mask16
[s
->gr
[VGA_GFX_SR_ENABLE
]];
930 val
= (val
& ~set_mask
) |
931 (mask16
[s
->gr
[VGA_GFX_SR_VALUE
]] & set_mask
);
932 bit_mask
= s
->gr
[VGA_GFX_BIT_MASK
];
938 val
= mask16
[val
& 0x0f];
939 bit_mask
= s
->gr
[VGA_GFX_BIT_MASK
];
943 b
= s
->gr
[VGA_GFX_DATA_ROTATE
] & 7;
944 val
= (val
>> b
) | (val
<< (8 - b
));
946 bit_mask
= s
->gr
[VGA_GFX_BIT_MASK
] & val
;
947 val
= mask16
[s
->gr
[VGA_GFX_SR_VALUE
]];
951 /* apply logical operation */
952 func_select
= s
->gr
[VGA_GFX_DATA_ROTATE
] >> 3;
953 switch(func_select
) {
973 bit_mask
|= bit_mask
<< 8;
974 bit_mask
|= bit_mask
<< 16;
975 val
= (val
& bit_mask
) | (s
->latch
& ~bit_mask
);
978 /* mask data according to sr[2] */
979 mask
= s
->sr
[VGA_SEQ_PLANE_WRITE
];
980 s
->plane_updated
|= mask
; /* only used to detect font change */
981 write_mask
= mask16
[mask
];
982 ((uint32_t *)s
->vram_ptr
)[addr
] =
983 (((uint32_t *)s
->vram_ptr
)[addr
] & ~write_mask
) |
986 printf("vga: latch: [0x" TARGET_FMT_plx
"] mask=0x%08x val=0x%08x\n",
987 addr
* 4, write_mask
, val
);
989 memory_region_set_dirty(&s
->vram
, addr
<< 2, sizeof(uint32_t));
993 typedef void vga_draw_glyph8_func(uint8_t *d
, int linesize
,
994 const uint8_t *font_ptr
, int h
,
995 uint32_t fgcol
, uint32_t bgcol
);
996 typedef void vga_draw_glyph9_func(uint8_t *d
, int linesize
,
997 const uint8_t *font_ptr
, int h
,
998 uint32_t fgcol
, uint32_t bgcol
, int dup9
);
999 typedef void vga_draw_line_func(VGACommonState
*s1
, uint8_t *d
,
1000 const uint8_t *s
, int width
);
1003 #include "vga_template.h"
1006 #include "vga_template.h"
1010 #include "vga_template.h"
1013 #include "vga_template.h"
1017 #include "vga_template.h"
1020 #include "vga_template.h"
1024 #include "vga_template.h"
1026 static unsigned int rgb_to_pixel8_dup(unsigned int r
, unsigned int g
, unsigned b
)
1029 col
= rgb_to_pixel8(r
, g
, b
);
1035 static unsigned int rgb_to_pixel15_dup(unsigned int r
, unsigned int g
, unsigned b
)
1038 col
= rgb_to_pixel15(r
, g
, b
);
1043 static unsigned int rgb_to_pixel15bgr_dup(unsigned int r
, unsigned int g
,
1047 col
= rgb_to_pixel15bgr(r
, g
, b
);
1052 static unsigned int rgb_to_pixel16_dup(unsigned int r
, unsigned int g
, unsigned b
)
1055 col
= rgb_to_pixel16(r
, g
, b
);
1060 static unsigned int rgb_to_pixel16bgr_dup(unsigned int r
, unsigned int g
,
1064 col
= rgb_to_pixel16bgr(r
, g
, b
);
1069 static unsigned int rgb_to_pixel32_dup(unsigned int r
, unsigned int g
, unsigned b
)
1072 col
= rgb_to_pixel32(r
, g
, b
);
1076 static unsigned int rgb_to_pixel32bgr_dup(unsigned int r
, unsigned int g
, unsigned b
)
1079 col
= rgb_to_pixel32bgr(r
, g
, b
);
1083 /* return true if the palette was modified */
1084 static int update_palette16(VGACommonState
*s
)
1087 uint32_t v
, col
, *palette
;
1090 palette
= s
->last_palette
;
1091 for(i
= 0; i
< 16; i
++) {
1093 if (s
->ar
[VGA_ATC_MODE
] & 0x80) {
1094 v
= ((s
->ar
[VGA_ATC_COLOR_PAGE
] & 0xf) << 4) | (v
& 0xf);
1096 v
= ((s
->ar
[VGA_ATC_COLOR_PAGE
] & 0xc) << 4) | (v
& 0x3f);
1099 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
1100 c6_to_8(s
->palette
[v
+ 1]),
1101 c6_to_8(s
->palette
[v
+ 2]));
1102 if (col
!= palette
[i
]) {
1110 /* return true if the palette was modified */
1111 static int update_palette256(VGACommonState
*s
)
1114 uint32_t v
, col
, *palette
;
1117 palette
= s
->last_palette
;
1119 for(i
= 0; i
< 256; i
++) {
1121 col
= s
->rgb_to_pixel(s
->palette
[v
],
1125 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
1126 c6_to_8(s
->palette
[v
+ 1]),
1127 c6_to_8(s
->palette
[v
+ 2]));
1129 if (col
!= palette
[i
]) {
1138 static void vga_get_offsets(VGACommonState
*s
,
1139 uint32_t *pline_offset
,
1140 uint32_t *pstart_addr
,
1141 uint32_t *pline_compare
)
1143 uint32_t start_addr
, line_offset
, line_compare
;
1144 #ifdef CONFIG_BOCHS_VBE
1145 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1146 line_offset
= s
->vbe_line_offset
;
1147 start_addr
= s
->vbe_start_addr
;
1148 line_compare
= 65535;
1152 /* compute line_offset in bytes */
1153 line_offset
= s
->cr
[VGA_CRTC_OFFSET
];
1156 /* starting address */
1157 start_addr
= s
->cr
[VGA_CRTC_START_LO
] |
1158 (s
->cr
[VGA_CRTC_START_HI
] << 8);
1161 line_compare
= s
->cr
[VGA_CRTC_LINE_COMPARE
] |
1162 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x10) << 4) |
1163 ((s
->cr
[VGA_CRTC_MAX_SCAN
] & 0x40) << 3);
1165 *pline_offset
= line_offset
;
1166 *pstart_addr
= start_addr
;
1167 *pline_compare
= line_compare
;
1170 /* update start_addr and line_offset. Return TRUE if modified */
1171 static int update_basic_params(VGACommonState
*s
)
1174 uint32_t start_addr
, line_offset
, line_compare
;
1178 s
->get_offsets(s
, &line_offset
, &start_addr
, &line_compare
);
1180 if (line_offset
!= s
->line_offset
||
1181 start_addr
!= s
->start_addr
||
1182 line_compare
!= s
->line_compare
) {
1183 s
->line_offset
= line_offset
;
1184 s
->start_addr
= start_addr
;
1185 s
->line_compare
= line_compare
;
1193 static inline int get_depth_index(DisplayState
*s
)
1195 switch(ds_get_bits_per_pixel(s
)) {
1204 if (is_surface_bgr(s
->surface
))
1211 static vga_draw_glyph8_func
* const vga_draw_glyph8_table
[NB_DEPTHS
] = {
1221 static vga_draw_glyph8_func
* const vga_draw_glyph16_table
[NB_DEPTHS
] = {
1223 vga_draw_glyph16_16
,
1224 vga_draw_glyph16_16
,
1225 vga_draw_glyph16_32
,
1226 vga_draw_glyph16_32
,
1227 vga_draw_glyph16_16
,
1228 vga_draw_glyph16_16
,
1231 static vga_draw_glyph9_func
* const vga_draw_glyph9_table
[NB_DEPTHS
] = {
1241 static const uint8_t cursor_glyph
[32 * 4] = {
1242 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1243 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1244 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1245 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1246 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1247 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1248 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1249 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1250 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1251 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1252 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1253 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1254 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1255 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1256 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1257 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1260 static void vga_get_text_resolution(VGACommonState
*s
, int *pwidth
, int *pheight
,
1261 int *pcwidth
, int *pcheight
)
1263 int width
, cwidth
, height
, cheight
;
1265 /* total width & height */
1266 cheight
= (s
->cr
[VGA_CRTC_MAX_SCAN
] & 0x1f) + 1;
1268 if (!(s
->sr
[VGA_SEQ_CLOCK_MODE
] & VGA_SR01_CHAR_CLK_8DOTS
)) {
1271 if (s
->sr
[VGA_SEQ_CLOCK_MODE
] & 0x08) {
1272 cwidth
= 16; /* NOTE: no 18 pixel wide */
1274 width
= (s
->cr
[VGA_CRTC_H_DISP
] + 1);
1275 if (s
->cr
[VGA_CRTC_V_TOTAL
] == 100) {
1276 /* ugly hack for CGA 160x100x16 - explain me the logic */
1279 height
= s
->cr
[VGA_CRTC_V_DISP_END
] |
1280 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x02) << 7) |
1281 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x40) << 3);
1282 height
= (height
+ 1) / cheight
;
1288 *pcheight
= cheight
;
1291 typedef unsigned int rgb_to_pixel_dup_func(unsigned int r
, unsigned int g
, unsigned b
);
1293 static rgb_to_pixel_dup_func
* const rgb_to_pixel_dup_table
[NB_DEPTHS
] = {
1298 rgb_to_pixel32bgr_dup
,
1299 rgb_to_pixel15bgr_dup
,
1300 rgb_to_pixel16bgr_dup
,
1311 static void vga_draw_text(VGACommonState
*s
, int full_update
)
1313 int cx
, cy
, cheight
, cw
, ch
, cattr
, height
, width
, ch_attr
;
1314 int cx_min
, cx_max
, linesize
, x_incr
, line
, line1
;
1315 uint32_t offset
, fgcol
, bgcol
, v
, cursor_offset
;
1316 uint8_t *d1
, *d
, *src
, *dest
, *cursor_ptr
;
1317 const uint8_t *font_ptr
, *font_base
[2];
1318 int dup9
, line_offset
, depth_index
;
1320 uint32_t *ch_attr_ptr
;
1321 vga_draw_glyph8_func
*vga_draw_glyph8
;
1322 vga_draw_glyph9_func
*vga_draw_glyph9
;
1323 int64_t now
= qemu_get_clock_ms(vm_clock
);
1325 /* compute font data address (in plane 2) */
1326 v
= s
->sr
[VGA_SEQ_CHARACTER_MAP
];
1327 offset
= (((v
>> 4) & 1) | ((v
<< 1) & 6)) * 8192 * 4 + 2;
1328 if (offset
!= s
->font_offsets
[0]) {
1329 s
->font_offsets
[0] = offset
;
1332 font_base
[0] = s
->vram_ptr
+ offset
;
1334 offset
= (((v
>> 5) & 1) | ((v
>> 1) & 6)) * 8192 * 4 + 2;
1335 font_base
[1] = s
->vram_ptr
+ offset
;
1336 if (offset
!= s
->font_offsets
[1]) {
1337 s
->font_offsets
[1] = offset
;
1340 if (s
->plane_updated
& (1 << 2) || s
->chain4_alias
) {
1341 /* if the plane 2 was modified since the last display, it
1342 indicates the font may have been modified */
1343 s
->plane_updated
= 0;
1346 full_update
|= update_basic_params(s
);
1348 line_offset
= s
->line_offset
;
1350 vga_get_text_resolution(s
, &width
, &height
, &cw
, &cheight
);
1351 if ((height
* width
) <= 1) {
1352 /* better than nothing: exit if transient size is too small */
1355 if ((height
* width
) > CH_ATTR_SIZE
) {
1356 /* better than nothing: exit if transient size is too big */
1360 if (width
!= s
->last_width
|| height
!= s
->last_height
||
1361 cw
!= s
->last_cw
|| cheight
!= s
->last_ch
|| s
->last_depth
) {
1362 s
->last_scr_width
= width
* cw
;
1363 s
->last_scr_height
= height
* cheight
;
1364 qemu_console_resize(s
->ds
, s
->last_scr_width
, s
->last_scr_height
);
1366 s
->last_width
= width
;
1367 s
->last_height
= height
;
1368 s
->last_ch
= cheight
;
1373 rgb_to_pixel_dup_table
[get_depth_index(s
->ds
)];
1374 full_update
|= update_palette16(s
);
1375 palette
= s
->last_palette
;
1376 x_incr
= cw
* ((ds_get_bits_per_pixel(s
->ds
) + 7) >> 3);
1378 cursor_offset
= ((s
->cr
[VGA_CRTC_CURSOR_HI
] << 8) |
1379 s
->cr
[VGA_CRTC_CURSOR_LO
]) - s
->start_addr
;
1380 if (cursor_offset
!= s
->cursor_offset
||
1381 s
->cr
[VGA_CRTC_CURSOR_START
] != s
->cursor_start
||
1382 s
->cr
[VGA_CRTC_CURSOR_END
] != s
->cursor_end
) {
1383 /* if the cursor position changed, we update the old and new
1385 if (s
->cursor_offset
< CH_ATTR_SIZE
)
1386 s
->last_ch_attr
[s
->cursor_offset
] = -1;
1387 if (cursor_offset
< CH_ATTR_SIZE
)
1388 s
->last_ch_attr
[cursor_offset
] = -1;
1389 s
->cursor_offset
= cursor_offset
;
1390 s
->cursor_start
= s
->cr
[VGA_CRTC_CURSOR_START
];
1391 s
->cursor_end
= s
->cr
[VGA_CRTC_CURSOR_END
];
1393 cursor_ptr
= s
->vram_ptr
+ (s
->start_addr
+ cursor_offset
) * 4;
1394 if (now
>= s
->cursor_blink_time
) {
1395 s
->cursor_blink_time
= now
+ VGA_TEXT_CURSOR_PERIOD_MS
/ 2;
1396 s
->cursor_visible_phase
= !s
->cursor_visible_phase
;
1399 depth_index
= get_depth_index(s
->ds
);
1401 vga_draw_glyph8
= vga_draw_glyph16_table
[depth_index
];
1403 vga_draw_glyph8
= vga_draw_glyph8_table
[depth_index
];
1404 vga_draw_glyph9
= vga_draw_glyph9_table
[depth_index
];
1406 dest
= ds_get_data(s
->ds
);
1407 linesize
= ds_get_linesize(s
->ds
);
1408 ch_attr_ptr
= s
->last_ch_attr
;
1410 offset
= s
->start_addr
* 4;
1411 for(cy
= 0; cy
< height
; cy
++) {
1413 src
= s
->vram_ptr
+ offset
;
1416 for(cx
= 0; cx
< width
; cx
++) {
1417 ch_attr
= *(uint16_t *)src
;
1418 if (full_update
|| ch_attr
!= *ch_attr_ptr
|| src
== cursor_ptr
) {
1423 *ch_attr_ptr
= ch_attr
;
1424 #ifdef HOST_WORDS_BIGENDIAN
1426 cattr
= ch_attr
& 0xff;
1428 ch
= ch_attr
& 0xff;
1429 cattr
= ch_attr
>> 8;
1431 font_ptr
= font_base
[(cattr
>> 3) & 1];
1432 font_ptr
+= 32 * 4 * ch
;
1433 bgcol
= palette
[cattr
>> 4];
1434 fgcol
= palette
[cattr
& 0x0f];
1436 vga_draw_glyph8(d1
, linesize
,
1437 font_ptr
, cheight
, fgcol
, bgcol
);
1440 if (ch
>= 0xb0 && ch
<= 0xdf &&
1441 (s
->ar
[VGA_ATC_MODE
] & 0x04)) {
1444 vga_draw_glyph9(d1
, linesize
,
1445 font_ptr
, cheight
, fgcol
, bgcol
, dup9
);
1447 if (src
== cursor_ptr
&&
1448 !(s
->cr
[VGA_CRTC_CURSOR_START
] & 0x20) &&
1449 s
->cursor_visible_phase
) {
1450 int line_start
, line_last
, h
;
1451 /* draw the cursor */
1452 line_start
= s
->cr
[VGA_CRTC_CURSOR_START
] & 0x1f;
1453 line_last
= s
->cr
[VGA_CRTC_CURSOR_END
] & 0x1f;
1454 /* XXX: check that */
1455 if (line_last
> cheight
- 1)
1456 line_last
= cheight
- 1;
1457 if (line_last
>= line_start
&& line_start
< cheight
) {
1458 h
= line_last
- line_start
+ 1;
1459 d
= d1
+ linesize
* line_start
;
1461 vga_draw_glyph8(d
, linesize
,
1462 cursor_glyph
, h
, fgcol
, bgcol
);
1464 vga_draw_glyph9(d
, linesize
,
1465 cursor_glyph
, h
, fgcol
, bgcol
, 1);
1475 dpy_update(s
->ds
, cx_min
* cw
, cy
* cheight
,
1476 (cx_max
- cx_min
+ 1) * cw
, cheight
);
1478 dest
+= linesize
* cheight
;
1479 line1
= line
+ cheight
;
1480 offset
+= line_offset
;
1481 if (line
< s
->line_compare
&& line1
>= s
->line_compare
) {
1502 static vga_draw_line_func
* const vga_draw_line_table
[NB_DEPTHS
* VGA_DRAW_LINE_NB
] = {
1512 vga_draw_line2d2_16
,
1513 vga_draw_line2d2_16
,
1514 vga_draw_line2d2_32
,
1515 vga_draw_line2d2_32
,
1516 vga_draw_line2d2_16
,
1517 vga_draw_line2d2_16
,
1528 vga_draw_line4d2_16
,
1529 vga_draw_line4d2_16
,
1530 vga_draw_line4d2_32
,
1531 vga_draw_line4d2_32
,
1532 vga_draw_line4d2_16
,
1533 vga_draw_line4d2_16
,
1536 vga_draw_line8d2_16
,
1537 vga_draw_line8d2_16
,
1538 vga_draw_line8d2_32
,
1539 vga_draw_line8d2_32
,
1540 vga_draw_line8d2_16
,
1541 vga_draw_line8d2_16
,
1555 vga_draw_line15_32bgr
,
1556 vga_draw_line15_15bgr
,
1557 vga_draw_line15_16bgr
,
1563 vga_draw_line16_32bgr
,
1564 vga_draw_line16_15bgr
,
1565 vga_draw_line16_16bgr
,
1571 vga_draw_line24_32bgr
,
1572 vga_draw_line24_15bgr
,
1573 vga_draw_line24_16bgr
,
1579 vga_draw_line32_32bgr
,
1580 vga_draw_line32_15bgr
,
1581 vga_draw_line32_16bgr
,
1584 static int vga_get_bpp(VGACommonState
*s
)
1587 #ifdef CONFIG_BOCHS_VBE
1588 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1589 ret
= s
->vbe_regs
[VBE_DISPI_INDEX_BPP
];
1598 static void vga_get_resolution(VGACommonState
*s
, int *pwidth
, int *pheight
)
1602 #ifdef CONFIG_BOCHS_VBE
1603 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1604 width
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
];
1605 height
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
];
1609 width
= (s
->cr
[VGA_CRTC_H_DISP
] + 1) * 8;
1610 height
= s
->cr
[VGA_CRTC_V_DISP_END
] |
1611 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x02) << 7) |
1612 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x40) << 3);
1613 height
= (height
+ 1);
1619 void vga_invalidate_scanlines(VGACommonState
*s
, int y1
, int y2
)
1622 if (y1
>= VGA_MAX_HEIGHT
)
1624 if (y2
>= VGA_MAX_HEIGHT
)
1625 y2
= VGA_MAX_HEIGHT
;
1626 for(y
= y1
; y
< y2
; y
++) {
1627 s
->invalidated_y_table
[y
>> 5] |= 1 << (y
& 0x1f);
1631 static void vga_sync_dirty_bitmap(VGACommonState
*s
)
1633 memory_region_sync_dirty_bitmap(&s
->vram
);
1636 void vga_dirty_log_start(VGACommonState
*s
)
1638 memory_region_set_log(&s
->vram
, true, DIRTY_MEMORY_VGA
);
1641 void vga_dirty_log_stop(VGACommonState
*s
)
1643 memory_region_set_log(&s
->vram
, false, DIRTY_MEMORY_VGA
);
1649 static void vga_draw_graphic(VGACommonState
*s
, int full_update
)
1651 int y1
, y
, update
, linesize
, y_start
, double_scan
, mask
, depth
;
1652 int width
, height
, shift_control
, line_offset
, bwidth
, bits
;
1653 ram_addr_t page0
, page1
, page_min
, page_max
;
1654 int disp_width
, multi_scan
, multi_run
;
1656 uint32_t v
, addr1
, addr
;
1657 vga_draw_line_func
*vga_draw_line
;
1659 full_update
|= update_basic_params(s
);
1662 vga_sync_dirty_bitmap(s
);
1664 s
->get_resolution(s
, &width
, &height
);
1667 shift_control
= (s
->gr
[VGA_GFX_MODE
] >> 5) & 3;
1668 double_scan
= (s
->cr
[VGA_CRTC_MAX_SCAN
] >> 7);
1669 if (shift_control
!= 1) {
1670 multi_scan
= (((s
->cr
[VGA_CRTC_MAX_SCAN
] & 0x1f) + 1) << double_scan
)
1673 /* in CGA modes, multi_scan is ignored */
1674 /* XXX: is it correct ? */
1675 multi_scan
= double_scan
;
1677 multi_run
= multi_scan
;
1678 if (shift_control
!= s
->shift_control
||
1679 double_scan
!= s
->double_scan
) {
1681 s
->shift_control
= shift_control
;
1682 s
->double_scan
= double_scan
;
1685 if (shift_control
== 0) {
1686 if (s
->sr
[VGA_SEQ_CLOCK_MODE
] & 8) {
1689 } else if (shift_control
== 1) {
1690 if (s
->sr
[VGA_SEQ_CLOCK_MODE
] & 8) {
1695 depth
= s
->get_bpp(s
);
1696 if (s
->line_offset
!= s
->last_line_offset
||
1697 disp_width
!= s
->last_width
||
1698 height
!= s
->last_height
||
1699 s
->last_depth
!= depth
) {
1700 #if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
1701 if (depth
== 16 || depth
== 32) {
1705 qemu_free_displaysurface(s
->ds
);
1706 s
->ds
->surface
= qemu_create_displaysurface_from(disp_width
, height
, depth
,
1708 s
->vram_ptr
+ (s
->start_addr
* 4));
1709 #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
1710 s
->ds
->surface
->pf
= qemu_different_endianness_pixelformat(depth
);
1714 qemu_console_resize(s
->ds
, disp_width
, height
);
1716 s
->last_scr_width
= disp_width
;
1717 s
->last_scr_height
= height
;
1718 s
->last_width
= disp_width
;
1719 s
->last_height
= height
;
1720 s
->last_line_offset
= s
->line_offset
;
1721 s
->last_depth
= depth
;
1723 } else if (is_buffer_shared(s
->ds
->surface
) &&
1724 (full_update
|| s
->ds
->surface
->data
!= s
->vram_ptr
+ (s
->start_addr
* 4))) {
1725 s
->ds
->surface
->data
= s
->vram_ptr
+ (s
->start_addr
* 4);
1730 rgb_to_pixel_dup_table
[get_depth_index(s
->ds
)];
1732 if (shift_control
== 0) {
1733 full_update
|= update_palette16(s
);
1734 if (s
->sr
[VGA_SEQ_CLOCK_MODE
] & 8) {
1735 v
= VGA_DRAW_LINE4D2
;
1740 } else if (shift_control
== 1) {
1741 full_update
|= update_palette16(s
);
1742 if (s
->sr
[VGA_SEQ_CLOCK_MODE
] & 8) {
1743 v
= VGA_DRAW_LINE2D2
;
1749 switch(s
->get_bpp(s
)) {
1752 full_update
|= update_palette256(s
);
1753 v
= VGA_DRAW_LINE8D2
;
1757 full_update
|= update_palette256(s
);
1762 v
= VGA_DRAW_LINE15
;
1766 v
= VGA_DRAW_LINE16
;
1770 v
= VGA_DRAW_LINE24
;
1774 v
= VGA_DRAW_LINE32
;
1779 vga_draw_line
= vga_draw_line_table
[v
* NB_DEPTHS
+ get_depth_index(s
->ds
)];
1781 if (!is_buffer_shared(s
->ds
->surface
) && s
->cursor_invalidate
)
1782 s
->cursor_invalidate(s
);
1784 line_offset
= s
->line_offset
;
1786 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",
1787 width
, height
, v
, line_offset
, s
->cr
[9], s
->cr
[VGA_CRTC_MODE
],
1788 s
->line_compare
, s
->sr
[VGA_SEQ_CLOCK_MODE
]);
1790 addr1
= (s
->start_addr
* 4);
1791 bwidth
= (width
* bits
+ 7) / 8;
1795 d
= ds_get_data(s
->ds
);
1796 linesize
= ds_get_linesize(s
->ds
);
1798 for(y
= 0; y
< height
; y
++) {
1800 if (!(s
->cr
[VGA_CRTC_MODE
] & 1)) {
1802 /* CGA compatibility handling */
1803 shift
= 14 + ((s
->cr
[VGA_CRTC_MODE
] >> 6) & 1);
1804 addr
= (addr
& ~(1 << shift
)) | ((y1
& 1) << shift
);
1806 if (!(s
->cr
[VGA_CRTC_MODE
] & 2)) {
1807 addr
= (addr
& ~0x8000) | ((y1
& 2) << 14);
1809 update
= full_update
;
1811 page1
= addr
+ bwidth
- 1;
1812 update
|= memory_region_get_dirty(&s
->vram
, page0
, page1
- page0
,
1814 /* explicit invalidation for the hardware cursor */
1815 update
|= (s
->invalidated_y_table
[y
>> 5] >> (y
& 0x1f)) & 1;
1819 if (page0
< page_min
)
1821 if (page1
> page_max
)
1823 if (!(is_buffer_shared(s
->ds
->surface
))) {
1824 vga_draw_line(s
, d
, s
->vram_ptr
+ addr
, width
);
1825 if (s
->cursor_draw_line
)
1826 s
->cursor_draw_line(s
, d
, y
);
1830 /* flush to display */
1831 dpy_update(s
->ds
, 0, y_start
,
1832 disp_width
, y
- y_start
);
1837 mask
= (s
->cr
[VGA_CRTC_MODE
] & 3) ^ 3;
1838 if ((y1
& mask
) == mask
)
1839 addr1
+= line_offset
;
1841 multi_run
= multi_scan
;
1845 /* line compare acts on the displayed lines */
1846 if (y
== s
->line_compare
)
1851 /* flush to display */
1852 dpy_update(s
->ds
, 0, y_start
,
1853 disp_width
, y
- y_start
);
1855 /* reset modified pages */
1856 if (page_max
>= page_min
) {
1857 memory_region_reset_dirty(&s
->vram
,
1859 page_max
- page_min
,
1862 memset(s
->invalidated_y_table
, 0, ((height
+ 31) >> 5) * 4);
1865 static void vga_draw_blank(VGACommonState
*s
, int full_update
)
1872 if (s
->last_scr_width
<= 0 || s
->last_scr_height
<= 0)
1876 rgb_to_pixel_dup_table
[get_depth_index(s
->ds
)];
1877 if (ds_get_bits_per_pixel(s
->ds
) == 8)
1878 val
= s
->rgb_to_pixel(0, 0, 0);
1881 w
= s
->last_scr_width
* ((ds_get_bits_per_pixel(s
->ds
) + 7) >> 3);
1882 d
= ds_get_data(s
->ds
);
1883 for(i
= 0; i
< s
->last_scr_height
; i
++) {
1885 d
+= ds_get_linesize(s
->ds
);
1887 dpy_update(s
->ds
, 0, 0,
1888 s
->last_scr_width
, s
->last_scr_height
);
1891 #define GMODE_TEXT 0
1892 #define GMODE_GRAPH 1
1893 #define GMODE_BLANK 2
1895 static void vga_update_display(void *opaque
)
1897 VGACommonState
*s
= opaque
;
1898 int full_update
, graphic_mode
;
1900 qemu_flush_coalesced_mmio_buffer();
1902 if (ds_get_bits_per_pixel(s
->ds
) == 0) {
1906 if (!(s
->ar_index
& 0x20) &&
1907 /* extra CGA compatibility hacks (not in standard VGA */
1908 (!(vga_cga_hacks
& VGA_CGA_HACK_PALETTE_BLANKING
) ||
1909 (s
->ar_index
!= 0 && s
->ar_flip_flop
))) {
1910 graphic_mode
= GMODE_BLANK
;
1912 graphic_mode
= s
->gr
[VGA_GFX_MISC
] & VGA_GR06_GRAPHICS_MODE
;
1914 if (graphic_mode
!= s
->graphic_mode
) {
1915 s
->graphic_mode
= graphic_mode
;
1916 s
->cursor_blink_time
= qemu_get_clock_ms(vm_clock
);
1919 switch(graphic_mode
) {
1921 vga_draw_text(s
, full_update
);
1924 vga_draw_graphic(s
, full_update
);
1928 vga_draw_blank(s
, full_update
);
1934 /* force a full display refresh */
1935 static void vga_invalidate_display(void *opaque
)
1937 VGACommonState
*s
= opaque
;
1940 s
->last_height
= -1;
1943 void vga_common_reset(VGACommonState
*s
)
1946 memset(s
->sr
, '\0', sizeof(s
->sr
));
1948 memset(s
->gr
, '\0', sizeof(s
->gr
));
1950 memset(s
->ar
, '\0', sizeof(s
->ar
));
1951 s
->ar_flip_flop
= 0;
1953 memset(s
->cr
, '\0', sizeof(s
->cr
));
1959 s
->dac_sub_index
= 0;
1960 s
->dac_read_index
= 0;
1961 s
->dac_write_index
= 0;
1962 memset(s
->dac_cache
, '\0', sizeof(s
->dac_cache
));
1964 memset(s
->palette
, '\0', sizeof(s
->palette
));
1966 #ifdef CONFIG_BOCHS_VBE
1968 memset(s
->vbe_regs
, '\0', sizeof(s
->vbe_regs
));
1969 s
->vbe_regs
[VBE_DISPI_INDEX_ID
] = VBE_DISPI_ID5
;
1970 s
->vbe_start_addr
= 0;
1971 s
->vbe_line_offset
= 0;
1972 s
->vbe_bank_mask
= (s
->vram_size
>> 16) - 1;
1974 memset(s
->font_offsets
, '\0', sizeof(s
->font_offsets
));
1975 s
->graphic_mode
= -1; /* force full update */
1976 s
->shift_control
= 0;
1979 s
->line_compare
= 0;
1981 s
->plane_updated
= 0;
1986 s
->last_scr_width
= 0;
1987 s
->last_scr_height
= 0;
1988 s
->cursor_start
= 0;
1990 s
->cursor_offset
= 0;
1991 memset(s
->invalidated_y_table
, '\0', sizeof(s
->invalidated_y_table
));
1992 memset(s
->last_palette
, '\0', sizeof(s
->last_palette
));
1993 memset(s
->last_ch_attr
, '\0', sizeof(s
->last_ch_attr
));
1994 switch (vga_retrace_method
) {
1995 case VGA_RETRACE_DUMB
:
1997 case VGA_RETRACE_PRECISE
:
1998 memset(&s
->retrace_info
, 0, sizeof (s
->retrace_info
));
2001 vga_update_memory_access(s
);
2004 static void vga_reset(void *opaque
)
2006 VGACommonState
*s
= opaque
;
2007 vga_common_reset(s
);
2010 #define TEXTMODE_X(x) ((x) % width)
2011 #define TEXTMODE_Y(x) ((x) / width)
2012 #define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
2013 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
2014 /* relay text rendering to the display driver
2015 * instead of doing a full vga_update_display() */
2016 static void vga_update_text(void *opaque
, console_ch_t
*chardata
)
2018 VGACommonState
*s
= opaque
;
2019 int graphic_mode
, i
, cursor_offset
, cursor_visible
;
2020 int cw
, cheight
, width
, height
, size
, c_min
, c_max
;
2022 console_ch_t
*dst
, val
;
2023 char msg_buffer
[80];
2024 int full_update
= 0;
2026 qemu_flush_coalesced_mmio_buffer();
2028 if (!(s
->ar_index
& 0x20)) {
2029 graphic_mode
= GMODE_BLANK
;
2031 graphic_mode
= s
->gr
[VGA_GFX_MISC
] & VGA_GR06_GRAPHICS_MODE
;
2033 if (graphic_mode
!= s
->graphic_mode
) {
2034 s
->graphic_mode
= graphic_mode
;
2037 if (s
->last_width
== -1) {
2042 switch (graphic_mode
) {
2044 /* TODO: update palette */
2045 full_update
|= update_basic_params(s
);
2047 /* total width & height */
2048 cheight
= (s
->cr
[VGA_CRTC_MAX_SCAN
] & 0x1f) + 1;
2050 if (!(s
->sr
[VGA_SEQ_CLOCK_MODE
] & VGA_SR01_CHAR_CLK_8DOTS
)) {
2053 if (s
->sr
[VGA_SEQ_CLOCK_MODE
] & 0x08) {
2054 cw
= 16; /* NOTE: no 18 pixel wide */
2056 width
= (s
->cr
[VGA_CRTC_H_DISP
] + 1);
2057 if (s
->cr
[VGA_CRTC_V_TOTAL
] == 100) {
2058 /* ugly hack for CGA 160x100x16 - explain me the logic */
2061 height
= s
->cr
[VGA_CRTC_V_DISP_END
] |
2062 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x02) << 7) |
2063 ((s
->cr
[VGA_CRTC_OVERFLOW
] & 0x40) << 3);
2064 height
= (height
+ 1) / cheight
;
2067 size
= (height
* width
);
2068 if (size
> CH_ATTR_SIZE
) {
2072 snprintf(msg_buffer
, sizeof(msg_buffer
), "%i x %i Text mode",
2077 if (width
!= s
->last_width
|| height
!= s
->last_height
||
2078 cw
!= s
->last_cw
|| cheight
!= s
->last_ch
) {
2079 s
->last_scr_width
= width
* cw
;
2080 s
->last_scr_height
= height
* cheight
;
2081 s
->ds
->surface
->width
= width
;
2082 s
->ds
->surface
->height
= height
;
2084 s
->last_width
= width
;
2085 s
->last_height
= height
;
2086 s
->last_ch
= cheight
;
2091 /* Update "hardware" cursor */
2092 cursor_offset
= ((s
->cr
[VGA_CRTC_CURSOR_HI
] << 8) |
2093 s
->cr
[VGA_CRTC_CURSOR_LO
]) - s
->start_addr
;
2094 if (cursor_offset
!= s
->cursor_offset
||
2095 s
->cr
[VGA_CRTC_CURSOR_START
] != s
->cursor_start
||
2096 s
->cr
[VGA_CRTC_CURSOR_END
] != s
->cursor_end
|| full_update
) {
2097 cursor_visible
= !(s
->cr
[VGA_CRTC_CURSOR_START
] & 0x20);
2098 if (cursor_visible
&& cursor_offset
< size
&& cursor_offset
>= 0)
2100 TEXTMODE_X(cursor_offset
),
2101 TEXTMODE_Y(cursor_offset
));
2103 dpy_cursor(s
->ds
, -1, -1);
2104 s
->cursor_offset
= cursor_offset
;
2105 s
->cursor_start
= s
->cr
[VGA_CRTC_CURSOR_START
];
2106 s
->cursor_end
= s
->cr
[VGA_CRTC_CURSOR_END
];
2109 src
= (uint32_t *) s
->vram_ptr
+ s
->start_addr
;
2113 for (i
= 0; i
< size
; src
++, dst
++, i
++)
2114 console_write_ch(dst
, VMEM2CHTYPE(le32_to_cpu(*src
)));
2116 dpy_update(s
->ds
, 0, 0, width
, height
);
2120 for (i
= 0; i
< size
; src
++, dst
++, i
++) {
2121 console_write_ch(&val
, VMEM2CHTYPE(le32_to_cpu(*src
)));
2129 for (; i
< size
; src
++, dst
++, i
++) {
2130 console_write_ch(&val
, VMEM2CHTYPE(le32_to_cpu(*src
)));
2137 if (c_min
<= c_max
) {
2138 i
= TEXTMODE_Y(c_min
);
2139 dpy_update(s
->ds
, 0, i
, width
, TEXTMODE_Y(c_max
) - i
+ 1);
2148 s
->get_resolution(s
, &width
, &height
);
2149 snprintf(msg_buffer
, sizeof(msg_buffer
), "%i x %i Graphic mode",
2157 snprintf(msg_buffer
, sizeof(msg_buffer
), "VGA Blank mode");
2161 /* Display a message */
2163 s
->last_height
= height
= 3;
2164 dpy_cursor(s
->ds
, -1, -1);
2165 s
->ds
->surface
->width
= s
->last_width
;
2166 s
->ds
->surface
->height
= height
;
2169 for (dst
= chardata
, i
= 0; i
< s
->last_width
* height
; i
++)
2170 console_write_ch(dst
++, ' ');
2172 size
= strlen(msg_buffer
);
2173 width
= (s
->last_width
- size
) / 2;
2174 dst
= chardata
+ s
->last_width
+ width
;
2175 for (i
= 0; i
< size
; i
++)
2176 console_write_ch(dst
++, 0x00200100 | msg_buffer
[i
]);
2178 dpy_update(s
->ds
, 0, 0, s
->last_width
, height
);
2181 static uint64_t vga_mem_read(void *opaque
, target_phys_addr_t addr
,
2184 VGACommonState
*s
= opaque
;
2186 return vga_mem_readb(s
, addr
);
2189 static void vga_mem_write(void *opaque
, target_phys_addr_t addr
,
2190 uint64_t data
, unsigned size
)
2192 VGACommonState
*s
= opaque
;
2194 return vga_mem_writeb(s
, addr
, data
);
2197 const MemoryRegionOps vga_mem_ops
= {
2198 .read
= vga_mem_read
,
2199 .write
= vga_mem_write
,
2200 .endianness
= DEVICE_LITTLE_ENDIAN
,
2202 .min_access_size
= 1,
2203 .max_access_size
= 1,
2207 static int vga_common_post_load(void *opaque
, int version_id
)
2209 VGACommonState
*s
= opaque
;
2212 s
->graphic_mode
= -1;
2216 const VMStateDescription vmstate_vga_common
= {
2219 .minimum_version_id
= 2,
2220 .minimum_version_id_old
= 2,
2221 .post_load
= vga_common_post_load
,
2222 .fields
= (VMStateField
[]) {
2223 VMSTATE_UINT32(latch
, VGACommonState
),
2224 VMSTATE_UINT8(sr_index
, VGACommonState
),
2225 VMSTATE_PARTIAL_BUFFER(sr
, VGACommonState
, 8),
2226 VMSTATE_UINT8(gr_index
, VGACommonState
),
2227 VMSTATE_PARTIAL_BUFFER(gr
, VGACommonState
, 16),
2228 VMSTATE_UINT8(ar_index
, VGACommonState
),
2229 VMSTATE_BUFFER(ar
, VGACommonState
),
2230 VMSTATE_INT32(ar_flip_flop
, VGACommonState
),
2231 VMSTATE_UINT8(cr_index
, VGACommonState
),
2232 VMSTATE_BUFFER(cr
, VGACommonState
),
2233 VMSTATE_UINT8(msr
, VGACommonState
),
2234 VMSTATE_UINT8(fcr
, VGACommonState
),
2235 VMSTATE_UINT8(st00
, VGACommonState
),
2236 VMSTATE_UINT8(st01
, VGACommonState
),
2238 VMSTATE_UINT8(dac_state
, VGACommonState
),
2239 VMSTATE_UINT8(dac_sub_index
, VGACommonState
),
2240 VMSTATE_UINT8(dac_read_index
, VGACommonState
),
2241 VMSTATE_UINT8(dac_write_index
, VGACommonState
),
2242 VMSTATE_BUFFER(dac_cache
, VGACommonState
),
2243 VMSTATE_BUFFER(palette
, VGACommonState
),
2245 VMSTATE_INT32(bank_offset
, VGACommonState
),
2246 VMSTATE_UINT8_EQUAL(is_vbe_vmstate
, VGACommonState
),
2247 #ifdef CONFIG_BOCHS_VBE
2248 VMSTATE_UINT16(vbe_index
, VGACommonState
),
2249 VMSTATE_UINT16_ARRAY(vbe_regs
, VGACommonState
, VBE_DISPI_INDEX_NB
),
2250 VMSTATE_UINT32(vbe_start_addr
, VGACommonState
),
2251 VMSTATE_UINT32(vbe_line_offset
, VGACommonState
),
2252 VMSTATE_UINT32(vbe_bank_mask
, VGACommonState
),
2254 VMSTATE_END_OF_LIST()
2258 void vga_common_init(VGACommonState
*s
)
2262 for(i
= 0;i
< 256; i
++) {
2264 for(j
= 0; j
< 8; j
++) {
2265 v
|= ((i
>> j
) & 1) << (j
* 4);
2270 for(j
= 0; j
< 4; j
++) {
2271 v
|= ((i
>> (2 * j
)) & 3) << (j
* 4);
2275 for(i
= 0; i
< 16; i
++) {
2277 for(j
= 0; j
< 4; j
++) {
2280 v
|= b
<< (2 * j
+ 1);
2285 /* valid range: 1 MB -> 256 MB */
2286 s
->vram_size
= 1024 * 1024;
2287 while (s
->vram_size
< (s
->vram_size_mb
<< 20) &&
2288 s
->vram_size
< (256 << 20)) {
2291 s
->vram_size_mb
= s
->vram_size
>> 20;
2293 #ifdef CONFIG_BOCHS_VBE
2294 s
->is_vbe_vmstate
= 1;
2296 s
->is_vbe_vmstate
= 0;
2298 memory_region_init_ram(&s
->vram
, "vga.vram", s
->vram_size
);
2299 vmstate_register_ram_global(&s
->vram
);
2300 xen_register_framebuffer(&s
->vram
);
2301 s
->vram_ptr
= memory_region_get_ram_ptr(&s
->vram
);
2302 s
->get_bpp
= vga_get_bpp
;
2303 s
->get_offsets
= vga_get_offsets
;
2304 s
->get_resolution
= vga_get_resolution
;
2305 s
->update
= vga_update_display
;
2306 s
->invalidate
= vga_invalidate_display
;
2307 s
->screen_dump
= vga_screen_dump
;
2308 s
->text_update
= vga_update_text
;
2309 switch (vga_retrace_method
) {
2310 case VGA_RETRACE_DUMB
:
2311 s
->retrace
= vga_dumb_retrace
;
2312 s
->update_retrace_info
= vga_dumb_update_retrace_info
;
2315 case VGA_RETRACE_PRECISE
:
2316 s
->retrace
= vga_precise_retrace
;
2317 s
->update_retrace_info
= vga_precise_update_retrace_info
;
2320 vga_dirty_log_start(s
);
2323 static const MemoryRegionPortio vga_portio_list
[] = {
2324 { 0x04, 2, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3b4 */
2325 { 0x0a, 1, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3ba */
2326 { 0x10, 16, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3c0 */
2327 { 0x24, 2, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3d4 */
2328 { 0x2a, 1, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3da */
2329 PORTIO_END_OF_LIST(),
2332 #ifdef CONFIG_BOCHS_VBE
2333 static const MemoryRegionPortio vbe_portio_list
[] = {
2334 { 0, 1, 2, .read
= vbe_ioport_read_index
, .write
= vbe_ioport_write_index
},
2336 { 1, 1, 2, .read
= vbe_ioport_read_data
, .write
= vbe_ioport_write_data
},
2338 { 2, 1, 2, .read
= vbe_ioport_read_data
, .write
= vbe_ioport_write_data
},
2340 PORTIO_END_OF_LIST(),
2342 #endif /* CONFIG_BOCHS_VBE */
2344 /* Used by both ISA and PCI */
2345 MemoryRegion
*vga_init_io(VGACommonState
*s
,
2346 const MemoryRegionPortio
**vga_ports
,
2347 const MemoryRegionPortio
**vbe_ports
)
2349 MemoryRegion
*vga_mem
;
2351 *vga_ports
= vga_portio_list
;
2353 #ifdef CONFIG_BOCHS_VBE
2354 *vbe_ports
= vbe_portio_list
;
2357 vga_mem
= g_malloc(sizeof(*vga_mem
));
2358 memory_region_init_io(vga_mem
, &vga_mem_ops
, s
,
2359 "vga-lowmem", 0x20000);
2364 void vga_init(VGACommonState
*s
, MemoryRegion
*address_space
,
2365 MemoryRegion
*address_space_io
, bool init_vga_ports
)
2367 MemoryRegion
*vga_io_memory
;
2368 const MemoryRegionPortio
*vga_ports
, *vbe_ports
;
2369 PortioList
*vga_port_list
= g_new(PortioList
, 1);
2370 PortioList
*vbe_port_list
= g_new(PortioList
, 1);
2372 qemu_register_reset(vga_reset
, s
);
2376 s
->legacy_address_space
= address_space
;
2378 vga_io_memory
= vga_init_io(s
, &vga_ports
, &vbe_ports
);
2379 memory_region_add_subregion_overlap(address_space
,
2380 isa_mem_base
+ 0x000a0000,
2383 memory_region_set_coalescing(vga_io_memory
);
2384 if (init_vga_ports
) {
2385 portio_list_init(vga_port_list
, vga_ports
, s
, "vga");
2386 portio_list_add(vga_port_list
, address_space_io
, 0x3b0);
2389 portio_list_init(vbe_port_list
, vbe_ports
, s
, "vbe");
2390 portio_list_add(vbe_port_list
, address_space_io
, 0x1ce);
2394 void vga_init_vbe(VGACommonState
*s
, MemoryRegion
*system_memory
)
2396 #ifdef CONFIG_BOCHS_VBE
2397 /* With pc-0.12 and below we map both the PCI BAR and the fixed VBE region,
2398 * so use an alias to avoid double-mapping the same region.
2400 memory_region_init_alias(&s
->vram_vbe
, "vram.vbe",
2401 &s
->vram
, 0, memory_region_size(&s
->vram
));
2402 /* XXX: use optimized standard vga accesses */
2403 memory_region_add_subregion(system_memory
,
2404 VBE_DISPI_LFB_PHYSICAL_ADDRESS
,
2409 /********************************************************/
2410 /* vga screen dump */
2412 int ppm_save(const char *filename
, struct DisplaySurface
*ds
)
2420 char *linebuf
, *pbuf
;
2422 trace_ppm_save(filename
, ds
);
2423 f
= fopen(filename
, "wb");
2426 fprintf(f
, "P6\n%d %d\n%d\n",
2427 ds
->width
, ds
->height
, 255);
2428 linebuf
= g_malloc(ds
->width
* 3);
2430 for(y
= 0; y
< ds
->height
; y
++) {
2433 for(x
= 0; x
< ds
->width
; x
++) {
2434 if (ds
->pf
.bits_per_pixel
== 32)
2437 v
= (uint32_t) (*(uint16_t *)d
);
2438 /* Limited to 8 or fewer bits per channel: */
2439 r
= ((v
>> ds
->pf
.rshift
) & ds
->pf
.rmax
) << (8 - ds
->pf
.rbits
);
2440 g
= ((v
>> ds
->pf
.gshift
) & ds
->pf
.gmax
) << (8 - ds
->pf
.gbits
);
2441 b
= ((v
>> ds
->pf
.bshift
) & ds
->pf
.bmax
) << (8 - ds
->pf
.bbits
);
2445 d
+= ds
->pf
.bytes_per_pixel
;
2448 ret
= fwrite(linebuf
, 1, pbuf
- linebuf
, f
);
2456 /* save the vga display in a PPM image even if no display is
2458 static void vga_screen_dump(void *opaque
, const char *filename
, bool cswitch
)
2460 VGACommonState
*s
= opaque
;
2463 vga_invalidate_display(s
);
2466 ppm_save(filename
, s
->ds
->surface
);