4 * Copyright (c) 2003 Fabrice Bellard
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 #include "pixel_ops.h"
30 #include "qemu-timer.h"
34 //#define DEBUG_VGA_MEM
35 //#define DEBUG_VGA_REG
37 //#define DEBUG_BOCHS_VBE
39 /* force some bits to zero */
40 const uint8_t sr_mask
[8] = {
51 const uint8_t gr_mask
[16] = {
70 #define cbswap_32(__x) \
72 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
73 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
74 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
75 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
77 #ifdef HOST_WORDS_BIGENDIAN
78 #define PAT(x) cbswap_32(x)
83 #ifdef HOST_WORDS_BIGENDIAN
89 #ifdef HOST_WORDS_BIGENDIAN
90 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
92 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
95 static const uint32_t mask16
[16] = {
116 #ifdef HOST_WORDS_BIGENDIAN
119 #define PAT(x) cbswap_32(x)
122 static const uint32_t dmask16
[16] = {
141 static const uint32_t dmask4
[4] = {
148 static uint32_t expand4
[256];
149 static uint16_t expand2
[256];
150 static uint8_t expand4to8
[16];
152 static void vga_screen_dump(void *opaque
, const char *filename
);
153 static const char *screen_dump_filename
;
154 static DisplayChangeListener
*screen_dump_dcl
;
156 static void vga_update_memory_access(VGACommonState
*s
)
158 MemoryRegion
*region
, *old_region
= s
->chain4_alias
;
159 target_phys_addr_t base
, offset
, size
;
161 s
->chain4_alias
= NULL
;
163 if ((s
->sr
[0x02] & 0xf) == 0xf && s
->sr
[0x04] & 0x08) {
165 switch ((s
->gr
[6] >> 2) & 3) {
173 offset
= s
->bank_offset
;
185 base
+= isa_mem_base
;
186 region
= g_malloc(sizeof(*region
));
187 memory_region_init_alias(region
, "vga.chain4", &s
->vram
, offset
, size
);
188 memory_region_add_subregion_overlap(s
->legacy_address_space
, base
,
190 s
->chain4_alias
= region
;
193 memory_region_del_subregion(s
->legacy_address_space
, old_region
);
194 memory_region_destroy(old_region
);
196 s
->plane_updated
= 0xf;
200 static void vga_dumb_update_retrace_info(VGACommonState
*s
)
205 static void vga_precise_update_retrace_info(VGACommonState
*s
)
208 int hretr_start_char
;
209 int hretr_skew_chars
;
213 int vretr_start_line
;
222 const int clk_hz
[] = {25175000, 28322000, 25175000, 25175000};
223 int64_t chars_per_sec
;
224 struct vga_precise_retrace
*r
= &s
->retrace_info
.precise
;
226 htotal_chars
= s
->cr
[0x00] + 5;
227 hretr_start_char
= s
->cr
[0x04];
228 hretr_skew_chars
= (s
->cr
[0x05] >> 5) & 3;
229 hretr_end_char
= s
->cr
[0x05] & 0x1f;
231 vtotal_lines
= (s
->cr
[0x06]
232 | (((s
->cr
[0x07] & 1) | ((s
->cr
[0x07] >> 4) & 2)) << 8)) + 2
234 vretr_start_line
= s
->cr
[0x10]
235 | ((((s
->cr
[0x07] >> 2) & 1) | ((s
->cr
[0x07] >> 6) & 2)) << 8)
237 vretr_end_line
= s
->cr
[0x11] & 0xf;
241 clocking_mode
= (s
->sr
[0x01] >> 3) & 1;
242 clock_sel
= (s
->msr
>> 2) & 3;
243 dots
= (s
->msr
& 1) ? 8 : 9;
245 chars_per_sec
= clk_hz
[clock_sel
] / dots
;
247 htotal_chars
<<= clocking_mode
;
249 r
->total_chars
= vtotal_lines
* htotal_chars
;
251 r
->ticks_per_char
= get_ticks_per_sec() / (r
->total_chars
* r
->freq
);
253 r
->ticks_per_char
= get_ticks_per_sec() / chars_per_sec
;
256 r
->vstart
= vretr_start_line
;
257 r
->vend
= r
->vstart
+ vretr_end_line
+ 1;
259 r
->hstart
= hretr_start_char
+ hretr_skew_chars
;
260 r
->hend
= r
->hstart
+ hretr_end_char
+ 1;
261 r
->htotal
= htotal_chars
;
264 div2
= (s
->cr
[0x17] >> 2) & 1;
265 sldiv2
= (s
->cr
[0x17] >> 3) & 1;
275 "div2 = %d sldiv2 = %d\n"
276 "clocking_mode = %d\n"
277 "clock_sel = %d %d\n"
279 "ticks/char = %" PRId64
"\n"
281 (double) get_ticks_per_sec() / (r
->ticks_per_char
* r
->total_chars
),
299 static uint8_t vga_precise_retrace(VGACommonState
*s
)
301 struct vga_precise_retrace
*r
= &s
->retrace_info
.precise
;
302 uint8_t val
= s
->st01
& ~(ST01_V_RETRACE
| ST01_DISP_ENABLE
);
304 if (r
->total_chars
) {
305 int cur_line
, cur_line_char
, cur_char
;
308 cur_tick
= qemu_get_clock_ns(vm_clock
);
310 cur_char
= (cur_tick
/ r
->ticks_per_char
) % r
->total_chars
;
311 cur_line
= cur_char
/ r
->htotal
;
313 if (cur_line
>= r
->vstart
&& cur_line
<= r
->vend
) {
314 val
|= ST01_V_RETRACE
| ST01_DISP_ENABLE
;
316 cur_line_char
= cur_char
% r
->htotal
;
317 if (cur_line_char
>= r
->hstart
&& cur_line_char
<= r
->hend
) {
318 val
|= ST01_DISP_ENABLE
;
324 return s
->st01
^ (ST01_V_RETRACE
| ST01_DISP_ENABLE
);
328 static uint8_t vga_dumb_retrace(VGACommonState
*s
)
330 return s
->st01
^ (ST01_V_RETRACE
| ST01_DISP_ENABLE
);
333 int vga_ioport_invalid(VGACommonState
*s
, uint32_t addr
)
335 if (s
->msr
& MSR_COLOR_EMULATION
) {
337 return (addr
>= 0x3b0 && addr
<= 0x3bf);
340 return (addr
>= 0x3d0 && addr
<= 0x3df);
344 uint32_t vga_ioport_read(void *opaque
, uint32_t addr
)
346 VGACommonState
*s
= opaque
;
349 if (vga_ioport_invalid(s
, addr
)) {
354 if (s
->ar_flip_flop
== 0) {
361 index
= s
->ar_index
& 0x1f;
374 val
= s
->sr
[s
->sr_index
];
376 printf("vga: read SR%x = 0x%02x\n", s
->sr_index
, val
);
383 val
= s
->dac_write_index
;
386 val
= s
->palette
[s
->dac_read_index
* 3 + s
->dac_sub_index
];
387 if (++s
->dac_sub_index
== 3) {
388 s
->dac_sub_index
= 0;
402 val
= s
->gr
[s
->gr_index
];
404 printf("vga: read GR%x = 0x%02x\n", s
->gr_index
, val
);
413 val
= s
->cr
[s
->cr_index
];
415 printf("vga: read CR%x = 0x%02x\n", s
->cr_index
, val
);
420 /* just toggle to fool polling */
421 val
= s
->st01
= s
->retrace(s
);
429 #if defined(DEBUG_VGA)
430 printf("VGA: read addr=0x%04x data=0x%02x\n", addr
, val
);
435 void vga_ioport_write(void *opaque
, uint32_t addr
, uint32_t val
)
437 VGACommonState
*s
= opaque
;
440 /* check port range access depending on color/monochrome mode */
441 if (vga_ioport_invalid(s
, addr
)) {
445 printf("VGA: write addr=0x%04x data=0x%02x\n", addr
, val
);
450 if (s
->ar_flip_flop
== 0) {
454 index
= s
->ar_index
& 0x1f;
457 s
->ar
[index
] = val
& 0x3f;
460 s
->ar
[index
] = val
& ~0x10;
466 s
->ar
[index
] = val
& ~0xc0;
469 s
->ar
[index
] = val
& ~0xf0;
472 s
->ar
[index
] = val
& ~0xf0;
478 s
->ar_flip_flop
^= 1;
481 s
->msr
= val
& ~0x10;
482 s
->update_retrace_info(s
);
485 s
->sr_index
= val
& 7;
489 printf("vga: write SR%x = 0x%02x\n", s
->sr_index
, val
);
491 s
->sr
[s
->sr_index
] = val
& sr_mask
[s
->sr_index
];
492 if (s
->sr_index
== 1) s
->update_retrace_info(s
);
493 vga_update_memory_access(s
);
496 s
->dac_read_index
= val
;
497 s
->dac_sub_index
= 0;
501 s
->dac_write_index
= val
;
502 s
->dac_sub_index
= 0;
506 s
->dac_cache
[s
->dac_sub_index
] = val
;
507 if (++s
->dac_sub_index
== 3) {
508 memcpy(&s
->palette
[s
->dac_write_index
* 3], s
->dac_cache
, 3);
509 s
->dac_sub_index
= 0;
510 s
->dac_write_index
++;
514 s
->gr_index
= val
& 0x0f;
518 printf("vga: write GR%x = 0x%02x\n", s
->gr_index
, val
);
520 s
->gr
[s
->gr_index
] = val
& gr_mask
[s
->gr_index
];
521 vga_update_memory_access(s
);
530 printf("vga: write CR%x = 0x%02x\n", s
->cr_index
, val
);
532 /* handle CR0-7 protection */
533 if ((s
->cr
[0x11] & 0x80) && s
->cr_index
<= 7) {
534 /* can always write bit 4 of CR7 */
535 if (s
->cr_index
== 7)
536 s
->cr
[7] = (s
->cr
[7] & ~0x10) | (val
& 0x10);
539 s
->cr
[s
->cr_index
] = val
;
541 switch(s
->cr_index
) {
549 s
->update_retrace_info(s
);
560 #ifdef CONFIG_BOCHS_VBE
561 static uint32_t vbe_ioport_read_index(void *opaque
, uint32_t addr
)
563 VGACommonState
*s
= opaque
;
569 static uint32_t vbe_ioport_read_data(void *opaque
, uint32_t addr
)
571 VGACommonState
*s
= opaque
;
574 if (s
->vbe_index
< VBE_DISPI_INDEX_NB
) {
575 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_GETCAPS
) {
576 switch(s
->vbe_index
) {
577 /* XXX: do not hardcode ? */
578 case VBE_DISPI_INDEX_XRES
:
579 val
= VBE_DISPI_MAX_XRES
;
581 case VBE_DISPI_INDEX_YRES
:
582 val
= VBE_DISPI_MAX_YRES
;
584 case VBE_DISPI_INDEX_BPP
:
585 val
= VBE_DISPI_MAX_BPP
;
588 val
= s
->vbe_regs
[s
->vbe_index
];
592 val
= s
->vbe_regs
[s
->vbe_index
];
594 } else if (s
->vbe_index
== VBE_DISPI_INDEX_VIDEO_MEMORY_64K
) {
595 val
= s
->vram_size
/ (64 * 1024);
599 #ifdef DEBUG_BOCHS_VBE
600 printf("VBE: read index=0x%x val=0x%x\n", s
->vbe_index
, val
);
605 static void vbe_ioport_write_index(void *opaque
, uint32_t addr
, uint32_t val
)
607 VGACommonState
*s
= opaque
;
611 static void vbe_ioport_write_data(void *opaque
, uint32_t addr
, uint32_t val
)
613 VGACommonState
*s
= opaque
;
615 if (s
->vbe_index
<= VBE_DISPI_INDEX_NB
) {
616 #ifdef DEBUG_BOCHS_VBE
617 printf("VBE: write index=0x%x val=0x%x\n", s
->vbe_index
, val
);
619 switch(s
->vbe_index
) {
620 case VBE_DISPI_INDEX_ID
:
621 if (val
== VBE_DISPI_ID0
||
622 val
== VBE_DISPI_ID1
||
623 val
== VBE_DISPI_ID2
||
624 val
== VBE_DISPI_ID3
||
625 val
== VBE_DISPI_ID4
) {
626 s
->vbe_regs
[s
->vbe_index
] = val
;
629 case VBE_DISPI_INDEX_XRES
:
630 if ((val
<= VBE_DISPI_MAX_XRES
) && ((val
& 7) == 0)) {
631 s
->vbe_regs
[s
->vbe_index
] = val
;
634 case VBE_DISPI_INDEX_YRES
:
635 if (val
<= VBE_DISPI_MAX_YRES
) {
636 s
->vbe_regs
[s
->vbe_index
] = val
;
639 case VBE_DISPI_INDEX_BPP
:
642 if (val
== 4 || val
== 8 || val
== 15 ||
643 val
== 16 || val
== 24 || val
== 32) {
644 s
->vbe_regs
[s
->vbe_index
] = val
;
647 case VBE_DISPI_INDEX_BANK
:
648 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
649 val
&= (s
->vbe_bank_mask
>> 2);
651 val
&= s
->vbe_bank_mask
;
653 s
->vbe_regs
[s
->vbe_index
] = val
;
654 s
->bank_offset
= (val
<< 16);
655 vga_update_memory_access(s
);
657 case VBE_DISPI_INDEX_ENABLE
:
658 if ((val
& VBE_DISPI_ENABLED
) &&
659 !(s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
)) {
660 int h
, shift_control
;
662 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] =
663 s
->vbe_regs
[VBE_DISPI_INDEX_XRES
];
664 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_HEIGHT
] =
665 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
];
666 s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
] = 0;
667 s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
] = 0;
669 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
670 s
->vbe_line_offset
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 1;
672 s
->vbe_line_offset
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] *
673 ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
674 s
->vbe_start_addr
= 0;
676 /* clear the screen (should be done in BIOS) */
677 if (!(val
& VBE_DISPI_NOCLEARMEM
)) {
678 memset(s
->vram_ptr
, 0,
679 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] * s
->vbe_line_offset
);
682 /* we initialize the VGA graphic mode (should be done
684 s
->gr
[0x06] = (s
->gr
[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
685 s
->cr
[0x17] |= 3; /* no CGA modes */
686 s
->cr
[0x13] = s
->vbe_line_offset
>> 3;
688 s
->cr
[0x01] = (s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 3) - 1;
689 /* height (only meaningful if < 1024) */
690 h
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] - 1;
692 s
->cr
[0x07] = (s
->cr
[0x07] & ~0x42) |
693 ((h
>> 7) & 0x02) | ((h
>> 3) & 0x40);
694 /* line compare to 1023 */
699 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
701 s
->sr
[0x01] &= ~8; /* no double line */
704 s
->sr
[4] |= 0x08; /* set chain 4 mode */
705 s
->sr
[2] |= 0x0f; /* activate all planes */
707 s
->gr
[0x05] = (s
->gr
[0x05] & ~0x60) | (shift_control
<< 5);
708 s
->cr
[0x09] &= ~0x9f; /* no double scan */
710 /* XXX: the bios should do that */
713 s
->dac_8bit
= (val
& VBE_DISPI_8BIT_DAC
) > 0;
714 s
->vbe_regs
[s
->vbe_index
] = val
;
715 vga_update_memory_access(s
);
717 case VBE_DISPI_INDEX_VIRT_WIDTH
:
719 int w
, h
, line_offset
;
721 if (val
< s
->vbe_regs
[VBE_DISPI_INDEX_XRES
])
724 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
725 line_offset
= w
>> 1;
727 line_offset
= w
* ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
728 h
= s
->vram_size
/ line_offset
;
729 /* XXX: support weird bochs semantics ? */
730 if (h
< s
->vbe_regs
[VBE_DISPI_INDEX_YRES
])
732 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] = w
;
733 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_HEIGHT
] = h
;
734 s
->vbe_line_offset
= line_offset
;
737 case VBE_DISPI_INDEX_X_OFFSET
:
738 case VBE_DISPI_INDEX_Y_OFFSET
:
741 s
->vbe_regs
[s
->vbe_index
] = val
;
742 s
->vbe_start_addr
= s
->vbe_line_offset
* s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
];
743 x
= s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
];
744 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
745 s
->vbe_start_addr
+= x
>> 1;
747 s
->vbe_start_addr
+= x
* ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
748 s
->vbe_start_addr
>>= 2;
758 /* called for accesses between 0xa0000 and 0xc0000 */
759 uint32_t vga_mem_readb(VGACommonState
*s
, target_phys_addr_t addr
)
761 int memory_map_mode
, plane
;
764 /* convert to VGA memory offset */
765 memory_map_mode
= (s
->gr
[6] >> 2) & 3;
767 switch(memory_map_mode
) {
773 addr
+= s
->bank_offset
;
788 if (s
->sr
[4] & 0x08) {
789 /* chain 4 mode : simplest access */
790 ret
= s
->vram_ptr
[addr
];
791 } else if (s
->gr
[5] & 0x10) {
792 /* odd/even mode (aka text mode mapping) */
793 plane
= (s
->gr
[4] & 2) | (addr
& 1);
794 ret
= s
->vram_ptr
[((addr
& ~1) << 1) | plane
];
796 /* standard VGA latched access */
797 s
->latch
= ((uint32_t *)s
->vram_ptr
)[addr
];
799 if (!(s
->gr
[5] & 0x08)) {
802 ret
= GET_PLANE(s
->latch
, plane
);
805 ret
= (s
->latch
^ mask16
[s
->gr
[2]]) & mask16
[s
->gr
[7]];
814 /* called for accesses between 0xa0000 and 0xc0000 */
815 void vga_mem_writeb(VGACommonState
*s
, target_phys_addr_t addr
, uint32_t val
)
817 int memory_map_mode
, plane
, write_mode
, b
, func_select
, mask
;
818 uint32_t write_mask
, bit_mask
, set_mask
;
821 printf("vga: [0x" TARGET_FMT_plx
"] = 0x%02x\n", addr
, val
);
823 /* convert to VGA memory offset */
824 memory_map_mode
= (s
->gr
[6] >> 2) & 3;
826 switch(memory_map_mode
) {
832 addr
+= s
->bank_offset
;
847 if (s
->sr
[4] & 0x08) {
848 /* chain 4 mode : simplest access */
851 if (s
->sr
[2] & mask
) {
852 s
->vram_ptr
[addr
] = val
;
854 printf("vga: chain4: [0x" TARGET_FMT_plx
"]\n", addr
);
856 s
->plane_updated
|= mask
; /* only used to detect font change */
857 memory_region_set_dirty(&s
->vram
, addr
);
859 } else if (s
->gr
[5] & 0x10) {
860 /* odd/even mode (aka text mode mapping) */
861 plane
= (s
->gr
[4] & 2) | (addr
& 1);
863 if (s
->sr
[2] & mask
) {
864 addr
= ((addr
& ~1) << 1) | plane
;
865 s
->vram_ptr
[addr
] = val
;
867 printf("vga: odd/even: [0x" TARGET_FMT_plx
"]\n", addr
);
869 s
->plane_updated
|= mask
; /* only used to detect font change */
870 memory_region_set_dirty(&s
->vram
, addr
);
873 /* standard VGA latched access */
874 write_mode
= s
->gr
[5] & 3;
880 val
= ((val
>> b
) | (val
<< (8 - b
))) & 0xff;
884 /* apply set/reset mask */
885 set_mask
= mask16
[s
->gr
[1]];
886 val
= (val
& ~set_mask
) | (mask16
[s
->gr
[0]] & set_mask
);
893 val
= mask16
[val
& 0x0f];
899 val
= (val
>> b
) | (val
<< (8 - b
));
901 bit_mask
= s
->gr
[8] & val
;
902 val
= mask16
[s
->gr
[0]];
906 /* apply logical operation */
907 func_select
= s
->gr
[3] >> 3;
908 switch(func_select
) {
928 bit_mask
|= bit_mask
<< 8;
929 bit_mask
|= bit_mask
<< 16;
930 val
= (val
& bit_mask
) | (s
->latch
& ~bit_mask
);
933 /* mask data according to sr[2] */
935 s
->plane_updated
|= mask
; /* only used to detect font change */
936 write_mask
= mask16
[mask
];
937 ((uint32_t *)s
->vram_ptr
)[addr
] =
938 (((uint32_t *)s
->vram_ptr
)[addr
] & ~write_mask
) |
941 printf("vga: latch: [0x" TARGET_FMT_plx
"] mask=0x%08x val=0x%08x\n",
942 addr
* 4, write_mask
, val
);
944 memory_region_set_dirty(&s
->vram
, addr
<< 2);
948 typedef void vga_draw_glyph8_func(uint8_t *d
, int linesize
,
949 const uint8_t *font_ptr
, int h
,
950 uint32_t fgcol
, uint32_t bgcol
);
951 typedef void vga_draw_glyph9_func(uint8_t *d
, int linesize
,
952 const uint8_t *font_ptr
, int h
,
953 uint32_t fgcol
, uint32_t bgcol
, int dup9
);
954 typedef void vga_draw_line_func(VGACommonState
*s1
, uint8_t *d
,
955 const uint8_t *s
, int width
);
958 #include "vga_template.h"
961 #include "vga_template.h"
965 #include "vga_template.h"
968 #include "vga_template.h"
972 #include "vga_template.h"
975 #include "vga_template.h"
979 #include "vga_template.h"
981 static unsigned int rgb_to_pixel8_dup(unsigned int r
, unsigned int g
, unsigned b
)
984 col
= rgb_to_pixel8(r
, g
, b
);
990 static unsigned int rgb_to_pixel15_dup(unsigned int r
, unsigned int g
, unsigned b
)
993 col
= rgb_to_pixel15(r
, g
, b
);
998 static unsigned int rgb_to_pixel15bgr_dup(unsigned int r
, unsigned int g
,
1002 col
= rgb_to_pixel15bgr(r
, g
, b
);
1007 static unsigned int rgb_to_pixel16_dup(unsigned int r
, unsigned int g
, unsigned b
)
1010 col
= rgb_to_pixel16(r
, g
, b
);
1015 static unsigned int rgb_to_pixel16bgr_dup(unsigned int r
, unsigned int g
,
1019 col
= rgb_to_pixel16bgr(r
, g
, b
);
1024 static unsigned int rgb_to_pixel32_dup(unsigned int r
, unsigned int g
, unsigned b
)
1027 col
= rgb_to_pixel32(r
, g
, b
);
1031 static unsigned int rgb_to_pixel32bgr_dup(unsigned int r
, unsigned int g
, unsigned b
)
1034 col
= rgb_to_pixel32bgr(r
, g
, b
);
1038 /* return true if the palette was modified */
1039 static int update_palette16(VGACommonState
*s
)
1042 uint32_t v
, col
, *palette
;
1045 palette
= s
->last_palette
;
1046 for(i
= 0; i
< 16; i
++) {
1048 if (s
->ar
[0x10] & 0x80)
1049 v
= ((s
->ar
[0x14] & 0xf) << 4) | (v
& 0xf);
1051 v
= ((s
->ar
[0x14] & 0xc) << 4) | (v
& 0x3f);
1053 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
1054 c6_to_8(s
->palette
[v
+ 1]),
1055 c6_to_8(s
->palette
[v
+ 2]));
1056 if (col
!= palette
[i
]) {
1064 /* return true if the palette was modified */
1065 static int update_palette256(VGACommonState
*s
)
1068 uint32_t v
, col
, *palette
;
1071 palette
= s
->last_palette
;
1073 for(i
= 0; i
< 256; i
++) {
1075 col
= s
->rgb_to_pixel(s
->palette
[v
],
1079 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
1080 c6_to_8(s
->palette
[v
+ 1]),
1081 c6_to_8(s
->palette
[v
+ 2]));
1083 if (col
!= palette
[i
]) {
1092 static void vga_get_offsets(VGACommonState
*s
,
1093 uint32_t *pline_offset
,
1094 uint32_t *pstart_addr
,
1095 uint32_t *pline_compare
)
1097 uint32_t start_addr
, line_offset
, line_compare
;
1098 #ifdef CONFIG_BOCHS_VBE
1099 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1100 line_offset
= s
->vbe_line_offset
;
1101 start_addr
= s
->vbe_start_addr
;
1102 line_compare
= 65535;
1106 /* compute line_offset in bytes */
1107 line_offset
= s
->cr
[0x13];
1110 /* starting address */
1111 start_addr
= s
->cr
[0x0d] | (s
->cr
[0x0c] << 8);
1114 line_compare
= s
->cr
[0x18] |
1115 ((s
->cr
[0x07] & 0x10) << 4) |
1116 ((s
->cr
[0x09] & 0x40) << 3);
1118 *pline_offset
= line_offset
;
1119 *pstart_addr
= start_addr
;
1120 *pline_compare
= line_compare
;
1123 /* update start_addr and line_offset. Return TRUE if modified */
1124 static int update_basic_params(VGACommonState
*s
)
1127 uint32_t start_addr
, line_offset
, line_compare
;
1131 s
->get_offsets(s
, &line_offset
, &start_addr
, &line_compare
);
1133 if (line_offset
!= s
->line_offset
||
1134 start_addr
!= s
->start_addr
||
1135 line_compare
!= s
->line_compare
) {
1136 s
->line_offset
= line_offset
;
1137 s
->start_addr
= start_addr
;
1138 s
->line_compare
= line_compare
;
1146 static inline int get_depth_index(DisplayState
*s
)
1148 switch(ds_get_bits_per_pixel(s
)) {
1157 if (is_surface_bgr(s
->surface
))
1164 static vga_draw_glyph8_func
* const vga_draw_glyph8_table
[NB_DEPTHS
] = {
1174 static vga_draw_glyph8_func
* const vga_draw_glyph16_table
[NB_DEPTHS
] = {
1176 vga_draw_glyph16_16
,
1177 vga_draw_glyph16_16
,
1178 vga_draw_glyph16_32
,
1179 vga_draw_glyph16_32
,
1180 vga_draw_glyph16_16
,
1181 vga_draw_glyph16_16
,
1184 static vga_draw_glyph9_func
* const vga_draw_glyph9_table
[NB_DEPTHS
] = {
1194 static const uint8_t cursor_glyph
[32 * 4] = {
1195 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1196 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1197 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1198 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1199 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1200 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1201 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1202 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1203 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1204 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1205 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1206 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1207 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1208 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1209 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1210 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1213 static void vga_get_text_resolution(VGACommonState
*s
, int *pwidth
, int *pheight
,
1214 int *pcwidth
, int *pcheight
)
1216 int width
, cwidth
, height
, cheight
;
1218 /* total width & height */
1219 cheight
= (s
->cr
[9] & 0x1f) + 1;
1221 if (!(s
->sr
[1] & 0x01))
1223 if (s
->sr
[1] & 0x08)
1224 cwidth
= 16; /* NOTE: no 18 pixel wide */
1225 width
= (s
->cr
[0x01] + 1);
1226 if (s
->cr
[0x06] == 100) {
1227 /* ugly hack for CGA 160x100x16 - explain me the logic */
1230 height
= s
->cr
[0x12] |
1231 ((s
->cr
[0x07] & 0x02) << 7) |
1232 ((s
->cr
[0x07] & 0x40) << 3);
1233 height
= (height
+ 1) / cheight
;
1239 *pcheight
= cheight
;
1242 typedef unsigned int rgb_to_pixel_dup_func(unsigned int r
, unsigned int g
, unsigned b
);
1244 static rgb_to_pixel_dup_func
* const rgb_to_pixel_dup_table
[NB_DEPTHS
] = {
1249 rgb_to_pixel32bgr_dup
,
1250 rgb_to_pixel15bgr_dup
,
1251 rgb_to_pixel16bgr_dup
,
1262 static void vga_draw_text(VGACommonState
*s
, int full_update
)
1264 int cx
, cy
, cheight
, cw
, ch
, cattr
, height
, width
, ch_attr
;
1265 int cx_min
, cx_max
, linesize
, x_incr
, line
, line1
;
1266 uint32_t offset
, fgcol
, bgcol
, v
, cursor_offset
;
1267 uint8_t *d1
, *d
, *src
, *dest
, *cursor_ptr
;
1268 const uint8_t *font_ptr
, *font_base
[2];
1269 int dup9
, line_offset
, depth_index
;
1271 uint32_t *ch_attr_ptr
;
1272 vga_draw_glyph8_func
*vga_draw_glyph8
;
1273 vga_draw_glyph9_func
*vga_draw_glyph9
;
1275 /* compute font data address (in plane 2) */
1277 offset
= (((v
>> 4) & 1) | ((v
<< 1) & 6)) * 8192 * 4 + 2;
1278 if (offset
!= s
->font_offsets
[0]) {
1279 s
->font_offsets
[0] = offset
;
1282 font_base
[0] = s
->vram_ptr
+ offset
;
1284 offset
= (((v
>> 5) & 1) | ((v
>> 1) & 6)) * 8192 * 4 + 2;
1285 font_base
[1] = s
->vram_ptr
+ offset
;
1286 if (offset
!= s
->font_offsets
[1]) {
1287 s
->font_offsets
[1] = offset
;
1290 if (s
->plane_updated
& (1 << 2) || s
->chain4_alias
) {
1291 /* if the plane 2 was modified since the last display, it
1292 indicates the font may have been modified */
1293 s
->plane_updated
= 0;
1296 full_update
|= update_basic_params(s
);
1298 line_offset
= s
->line_offset
;
1300 vga_get_text_resolution(s
, &width
, &height
, &cw
, &cheight
);
1301 if ((height
* width
) > CH_ATTR_SIZE
) {
1302 /* better than nothing: exit if transient size is too big */
1306 if (width
!= s
->last_width
|| height
!= s
->last_height
||
1307 cw
!= s
->last_cw
|| cheight
!= s
->last_ch
|| s
->last_depth
) {
1308 s
->last_scr_width
= width
* cw
;
1309 s
->last_scr_height
= height
* cheight
;
1310 qemu_console_resize(s
->ds
, s
->last_scr_width
, s
->last_scr_height
);
1312 s
->last_width
= width
;
1313 s
->last_height
= height
;
1314 s
->last_ch
= cheight
;
1319 rgb_to_pixel_dup_table
[get_depth_index(s
->ds
)];
1320 full_update
|= update_palette16(s
);
1321 palette
= s
->last_palette
;
1322 x_incr
= cw
* ((ds_get_bits_per_pixel(s
->ds
) + 7) >> 3);
1324 cursor_offset
= ((s
->cr
[0x0e] << 8) | s
->cr
[0x0f]) - s
->start_addr
;
1325 if (cursor_offset
!= s
->cursor_offset
||
1326 s
->cr
[0xa] != s
->cursor_start
||
1327 s
->cr
[0xb] != s
->cursor_end
) {
1328 /* if the cursor position changed, we update the old and new
1330 if (s
->cursor_offset
< CH_ATTR_SIZE
)
1331 s
->last_ch_attr
[s
->cursor_offset
] = -1;
1332 if (cursor_offset
< CH_ATTR_SIZE
)
1333 s
->last_ch_attr
[cursor_offset
] = -1;
1334 s
->cursor_offset
= cursor_offset
;
1335 s
->cursor_start
= s
->cr
[0xa];
1336 s
->cursor_end
= s
->cr
[0xb];
1338 cursor_ptr
= s
->vram_ptr
+ (s
->start_addr
+ cursor_offset
) * 4;
1340 depth_index
= get_depth_index(s
->ds
);
1342 vga_draw_glyph8
= vga_draw_glyph16_table
[depth_index
];
1344 vga_draw_glyph8
= vga_draw_glyph8_table
[depth_index
];
1345 vga_draw_glyph9
= vga_draw_glyph9_table
[depth_index
];
1347 dest
= ds_get_data(s
->ds
);
1348 linesize
= ds_get_linesize(s
->ds
);
1349 ch_attr_ptr
= s
->last_ch_attr
;
1351 offset
= s
->start_addr
* 4;
1352 for(cy
= 0; cy
< height
; cy
++) {
1354 src
= s
->vram_ptr
+ offset
;
1357 for(cx
= 0; cx
< width
; cx
++) {
1358 ch_attr
= *(uint16_t *)src
;
1359 if (full_update
|| ch_attr
!= *ch_attr_ptr
) {
1364 *ch_attr_ptr
= ch_attr
;
1365 #ifdef HOST_WORDS_BIGENDIAN
1367 cattr
= ch_attr
& 0xff;
1369 ch
= ch_attr
& 0xff;
1370 cattr
= ch_attr
>> 8;
1372 font_ptr
= font_base
[(cattr
>> 3) & 1];
1373 font_ptr
+= 32 * 4 * ch
;
1374 bgcol
= palette
[cattr
>> 4];
1375 fgcol
= palette
[cattr
& 0x0f];
1377 vga_draw_glyph8(d1
, linesize
,
1378 font_ptr
, cheight
, fgcol
, bgcol
);
1381 if (ch
>= 0xb0 && ch
<= 0xdf && (s
->ar
[0x10] & 0x04))
1383 vga_draw_glyph9(d1
, linesize
,
1384 font_ptr
, cheight
, fgcol
, bgcol
, dup9
);
1386 if (src
== cursor_ptr
&&
1387 !(s
->cr
[0x0a] & 0x20)) {
1388 int line_start
, line_last
, h
;
1389 /* draw the cursor */
1390 line_start
= s
->cr
[0x0a] & 0x1f;
1391 line_last
= s
->cr
[0x0b] & 0x1f;
1392 /* XXX: check that */
1393 if (line_last
> cheight
- 1)
1394 line_last
= cheight
- 1;
1395 if (line_last
>= line_start
&& line_start
< cheight
) {
1396 h
= line_last
- line_start
+ 1;
1397 d
= d1
+ linesize
* line_start
;
1399 vga_draw_glyph8(d
, linesize
,
1400 cursor_glyph
, h
, fgcol
, bgcol
);
1402 vga_draw_glyph9(d
, linesize
,
1403 cursor_glyph
, h
, fgcol
, bgcol
, 1);
1413 dpy_update(s
->ds
, cx_min
* cw
, cy
* cheight
,
1414 (cx_max
- cx_min
+ 1) * cw
, cheight
);
1416 dest
+= linesize
* cheight
;
1417 line1
= line
+ cheight
;
1418 offset
+= line_offset
;
1419 if (line
< s
->line_compare
&& line1
>= s
->line_compare
) {
1440 static vga_draw_line_func
* const vga_draw_line_table
[NB_DEPTHS
* VGA_DRAW_LINE_NB
] = {
1450 vga_draw_line2d2_16
,
1451 vga_draw_line2d2_16
,
1452 vga_draw_line2d2_32
,
1453 vga_draw_line2d2_32
,
1454 vga_draw_line2d2_16
,
1455 vga_draw_line2d2_16
,
1466 vga_draw_line4d2_16
,
1467 vga_draw_line4d2_16
,
1468 vga_draw_line4d2_32
,
1469 vga_draw_line4d2_32
,
1470 vga_draw_line4d2_16
,
1471 vga_draw_line4d2_16
,
1474 vga_draw_line8d2_16
,
1475 vga_draw_line8d2_16
,
1476 vga_draw_line8d2_32
,
1477 vga_draw_line8d2_32
,
1478 vga_draw_line8d2_16
,
1479 vga_draw_line8d2_16
,
1493 vga_draw_line15_32bgr
,
1494 vga_draw_line15_15bgr
,
1495 vga_draw_line15_16bgr
,
1501 vga_draw_line16_32bgr
,
1502 vga_draw_line16_15bgr
,
1503 vga_draw_line16_16bgr
,
1509 vga_draw_line24_32bgr
,
1510 vga_draw_line24_15bgr
,
1511 vga_draw_line24_16bgr
,
1517 vga_draw_line32_32bgr
,
1518 vga_draw_line32_15bgr
,
1519 vga_draw_line32_16bgr
,
1522 static int vga_get_bpp(VGACommonState
*s
)
1525 #ifdef CONFIG_BOCHS_VBE
1526 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1527 ret
= s
->vbe_regs
[VBE_DISPI_INDEX_BPP
];
1536 static void vga_get_resolution(VGACommonState
*s
, int *pwidth
, int *pheight
)
1540 #ifdef CONFIG_BOCHS_VBE
1541 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1542 width
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
];
1543 height
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
];
1547 width
= (s
->cr
[0x01] + 1) * 8;
1548 height
= s
->cr
[0x12] |
1549 ((s
->cr
[0x07] & 0x02) << 7) |
1550 ((s
->cr
[0x07] & 0x40) << 3);
1551 height
= (height
+ 1);
1557 void vga_invalidate_scanlines(VGACommonState
*s
, int y1
, int y2
)
1560 if (y1
>= VGA_MAX_HEIGHT
)
1562 if (y2
>= VGA_MAX_HEIGHT
)
1563 y2
= VGA_MAX_HEIGHT
;
1564 for(y
= y1
; y
< y2
; y
++) {
1565 s
->invalidated_y_table
[y
>> 5] |= 1 << (y
& 0x1f);
1569 static void vga_sync_dirty_bitmap(VGACommonState
*s
)
1571 memory_region_sync_dirty_bitmap(&s
->vram
);
1574 void vga_dirty_log_start(VGACommonState
*s
)
1576 memory_region_set_log(&s
->vram
, true, DIRTY_MEMORY_VGA
);
1579 void vga_dirty_log_stop(VGACommonState
*s
)
1581 memory_region_set_log(&s
->vram
, false, DIRTY_MEMORY_VGA
);
1587 static void vga_draw_graphic(VGACommonState
*s
, int full_update
)
1589 int y1
, y
, update
, linesize
, y_start
, double_scan
, mask
, depth
;
1590 int width
, height
, shift_control
, line_offset
, bwidth
, bits
;
1591 ram_addr_t page0
, page1
, page_min
, page_max
;
1592 int disp_width
, multi_scan
, multi_run
;
1594 uint32_t v
, addr1
, addr
;
1595 vga_draw_line_func
*vga_draw_line
;
1597 full_update
|= update_basic_params(s
);
1600 vga_sync_dirty_bitmap(s
);
1602 s
->get_resolution(s
, &width
, &height
);
1605 shift_control
= (s
->gr
[0x05] >> 5) & 3;
1606 double_scan
= (s
->cr
[0x09] >> 7);
1607 if (shift_control
!= 1) {
1608 multi_scan
= (((s
->cr
[0x09] & 0x1f) + 1) << double_scan
) - 1;
1610 /* in CGA modes, multi_scan is ignored */
1611 /* XXX: is it correct ? */
1612 multi_scan
= double_scan
;
1614 multi_run
= multi_scan
;
1615 if (shift_control
!= s
->shift_control
||
1616 double_scan
!= s
->double_scan
) {
1618 s
->shift_control
= shift_control
;
1619 s
->double_scan
= double_scan
;
1622 if (shift_control
== 0) {
1623 if (s
->sr
[0x01] & 8) {
1626 } else if (shift_control
== 1) {
1627 if (s
->sr
[0x01] & 8) {
1632 depth
= s
->get_bpp(s
);
1633 if (s
->line_offset
!= s
->last_line_offset
||
1634 disp_width
!= s
->last_width
||
1635 height
!= s
->last_height
||
1636 s
->last_depth
!= depth
) {
1637 #if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
1638 if (depth
== 16 || depth
== 32) {
1642 qemu_free_displaysurface(s
->ds
);
1643 s
->ds
->surface
= qemu_create_displaysurface_from(disp_width
, height
, depth
,
1645 s
->vram_ptr
+ (s
->start_addr
* 4));
1646 #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
1647 s
->ds
->surface
->pf
= qemu_different_endianness_pixelformat(depth
);
1651 qemu_console_resize(s
->ds
, disp_width
, height
);
1653 s
->last_scr_width
= disp_width
;
1654 s
->last_scr_height
= height
;
1655 s
->last_width
= disp_width
;
1656 s
->last_height
= height
;
1657 s
->last_line_offset
= s
->line_offset
;
1658 s
->last_depth
= depth
;
1660 } else if (is_buffer_shared(s
->ds
->surface
) &&
1661 (full_update
|| s
->ds
->surface
->data
!= s
->vram_ptr
+ (s
->start_addr
* 4))) {
1662 s
->ds
->surface
->data
= s
->vram_ptr
+ (s
->start_addr
* 4);
1667 rgb_to_pixel_dup_table
[get_depth_index(s
->ds
)];
1669 if (shift_control
== 0) {
1670 full_update
|= update_palette16(s
);
1671 if (s
->sr
[0x01] & 8) {
1672 v
= VGA_DRAW_LINE4D2
;
1677 } else if (shift_control
== 1) {
1678 full_update
|= update_palette16(s
);
1679 if (s
->sr
[0x01] & 8) {
1680 v
= VGA_DRAW_LINE2D2
;
1686 switch(s
->get_bpp(s
)) {
1689 full_update
|= update_palette256(s
);
1690 v
= VGA_DRAW_LINE8D2
;
1694 full_update
|= update_palette256(s
);
1699 v
= VGA_DRAW_LINE15
;
1703 v
= VGA_DRAW_LINE16
;
1707 v
= VGA_DRAW_LINE24
;
1711 v
= VGA_DRAW_LINE32
;
1716 vga_draw_line
= vga_draw_line_table
[v
* NB_DEPTHS
+ get_depth_index(s
->ds
)];
1718 if (!is_buffer_shared(s
->ds
->surface
) && s
->cursor_invalidate
)
1719 s
->cursor_invalidate(s
);
1721 line_offset
= s
->line_offset
;
1723 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",
1724 width
, height
, v
, line_offset
, s
->cr
[9], s
->cr
[0x17], s
->line_compare
, s
->sr
[0x01]);
1726 addr1
= (s
->start_addr
* 4);
1727 bwidth
= (width
* bits
+ 7) / 8;
1731 d
= ds_get_data(s
->ds
);
1732 linesize
= ds_get_linesize(s
->ds
);
1734 for(y
= 0; y
< height
; y
++) {
1736 if (!(s
->cr
[0x17] & 1)) {
1738 /* CGA compatibility handling */
1739 shift
= 14 + ((s
->cr
[0x17] >> 6) & 1);
1740 addr
= (addr
& ~(1 << shift
)) | ((y1
& 1) << shift
);
1742 if (!(s
->cr
[0x17] & 2)) {
1743 addr
= (addr
& ~0x8000) | ((y1
& 2) << 14);
1745 page0
= addr
& TARGET_PAGE_MASK
;
1746 page1
= (addr
+ bwidth
- 1) & TARGET_PAGE_MASK
;
1747 update
= full_update
|
1748 memory_region_get_dirty(&s
->vram
, page0
, DIRTY_MEMORY_VGA
) |
1749 memory_region_get_dirty(&s
->vram
, page1
, DIRTY_MEMORY_VGA
);
1750 if ((page1
- page0
) > TARGET_PAGE_SIZE
) {
1751 /* if wide line, can use another page */
1752 update
|= memory_region_get_dirty(&s
->vram
,
1753 page0
+ TARGET_PAGE_SIZE
,
1756 /* explicit invalidation for the hardware cursor */
1757 update
|= (s
->invalidated_y_table
[y
>> 5] >> (y
& 0x1f)) & 1;
1761 if (page0
< page_min
)
1763 if (page1
> page_max
)
1765 if (!(is_buffer_shared(s
->ds
->surface
))) {
1766 vga_draw_line(s
, d
, s
->vram_ptr
+ addr
, width
);
1767 if (s
->cursor_draw_line
)
1768 s
->cursor_draw_line(s
, d
, y
);
1772 /* flush to display */
1773 dpy_update(s
->ds
, 0, y_start
,
1774 disp_width
, y
- y_start
);
1779 mask
= (s
->cr
[0x17] & 3) ^ 3;
1780 if ((y1
& mask
) == mask
)
1781 addr1
+= line_offset
;
1783 multi_run
= multi_scan
;
1787 /* line compare acts on the displayed lines */
1788 if (y
== s
->line_compare
)
1793 /* flush to display */
1794 dpy_update(s
->ds
, 0, y_start
,
1795 disp_width
, y
- y_start
);
1797 /* reset modified pages */
1798 if (page_max
>= page_min
) {
1799 memory_region_reset_dirty(&s
->vram
,
1801 page_max
+ TARGET_PAGE_SIZE
- page_min
,
1804 memset(s
->invalidated_y_table
, 0, ((height
+ 31) >> 5) * 4);
1807 static void vga_draw_blank(VGACommonState
*s
, int full_update
)
1814 if (s
->last_scr_width
<= 0 || s
->last_scr_height
<= 0)
1818 rgb_to_pixel_dup_table
[get_depth_index(s
->ds
)];
1819 if (ds_get_bits_per_pixel(s
->ds
) == 8)
1820 val
= s
->rgb_to_pixel(0, 0, 0);
1823 w
= s
->last_scr_width
* ((ds_get_bits_per_pixel(s
->ds
) + 7) >> 3);
1824 d
= ds_get_data(s
->ds
);
1825 for(i
= 0; i
< s
->last_scr_height
; i
++) {
1827 d
+= ds_get_linesize(s
->ds
);
1829 dpy_update(s
->ds
, 0, 0,
1830 s
->last_scr_width
, s
->last_scr_height
);
1833 #define GMODE_TEXT 0
1834 #define GMODE_GRAPH 1
1835 #define GMODE_BLANK 2
1837 static void vga_update_display(void *opaque
)
1839 VGACommonState
*s
= opaque
;
1840 int full_update
, graphic_mode
;
1842 qemu_flush_coalesced_mmio_buffer();
1844 if (ds_get_bits_per_pixel(s
->ds
) == 0) {
1848 if (!(s
->ar_index
& 0x20)) {
1849 graphic_mode
= GMODE_BLANK
;
1851 graphic_mode
= s
->gr
[6] & 1;
1853 if (graphic_mode
!= s
->graphic_mode
) {
1854 s
->graphic_mode
= graphic_mode
;
1857 switch(graphic_mode
) {
1859 vga_draw_text(s
, full_update
);
1862 vga_draw_graphic(s
, full_update
);
1866 vga_draw_blank(s
, full_update
);
1872 /* force a full display refresh */
1873 static void vga_invalidate_display(void *opaque
)
1875 VGACommonState
*s
= opaque
;
1878 s
->last_height
= -1;
1881 void vga_common_reset(VGACommonState
*s
)
1884 memset(s
->sr
, '\0', sizeof(s
->sr
));
1886 memset(s
->gr
, '\0', sizeof(s
->gr
));
1888 memset(s
->ar
, '\0', sizeof(s
->ar
));
1889 s
->ar_flip_flop
= 0;
1891 memset(s
->cr
, '\0', sizeof(s
->cr
));
1897 s
->dac_sub_index
= 0;
1898 s
->dac_read_index
= 0;
1899 s
->dac_write_index
= 0;
1900 memset(s
->dac_cache
, '\0', sizeof(s
->dac_cache
));
1902 memset(s
->palette
, '\0', sizeof(s
->palette
));
1904 #ifdef CONFIG_BOCHS_VBE
1906 memset(s
->vbe_regs
, '\0', sizeof(s
->vbe_regs
));
1907 s
->vbe_regs
[VBE_DISPI_INDEX_ID
] = VBE_DISPI_ID5
;
1908 s
->vbe_start_addr
= 0;
1909 s
->vbe_line_offset
= 0;
1910 s
->vbe_bank_mask
= (s
->vram_size
>> 16) - 1;
1912 memset(s
->font_offsets
, '\0', sizeof(s
->font_offsets
));
1913 s
->graphic_mode
= -1; /* force full update */
1914 s
->shift_control
= 0;
1917 s
->line_compare
= 0;
1919 s
->plane_updated
= 0;
1924 s
->last_scr_width
= 0;
1925 s
->last_scr_height
= 0;
1926 s
->cursor_start
= 0;
1928 s
->cursor_offset
= 0;
1929 memset(s
->invalidated_y_table
, '\0', sizeof(s
->invalidated_y_table
));
1930 memset(s
->last_palette
, '\0', sizeof(s
->last_palette
));
1931 memset(s
->last_ch_attr
, '\0', sizeof(s
->last_ch_attr
));
1932 switch (vga_retrace_method
) {
1933 case VGA_RETRACE_DUMB
:
1935 case VGA_RETRACE_PRECISE
:
1936 memset(&s
->retrace_info
, 0, sizeof (s
->retrace_info
));
1939 vga_update_memory_access(s
);
1942 static void vga_reset(void *opaque
)
1944 VGACommonState
*s
= opaque
;
1945 vga_common_reset(s
);
1948 #define TEXTMODE_X(x) ((x) % width)
1949 #define TEXTMODE_Y(x) ((x) / width)
1950 #define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1951 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1952 /* relay text rendering to the display driver
1953 * instead of doing a full vga_update_display() */
1954 static void vga_update_text(void *opaque
, console_ch_t
*chardata
)
1956 VGACommonState
*s
= opaque
;
1957 int graphic_mode
, i
, cursor_offset
, cursor_visible
;
1958 int cw
, cheight
, width
, height
, size
, c_min
, c_max
;
1960 console_ch_t
*dst
, val
;
1961 char msg_buffer
[80];
1962 int full_update
= 0;
1964 qemu_flush_coalesced_mmio_buffer();
1966 if (!(s
->ar_index
& 0x20)) {
1967 graphic_mode
= GMODE_BLANK
;
1969 graphic_mode
= s
->gr
[6] & 1;
1971 if (graphic_mode
!= s
->graphic_mode
) {
1972 s
->graphic_mode
= graphic_mode
;
1975 if (s
->last_width
== -1) {
1980 switch (graphic_mode
) {
1982 /* TODO: update palette */
1983 full_update
|= update_basic_params(s
);
1985 /* total width & height */
1986 cheight
= (s
->cr
[9] & 0x1f) + 1;
1988 if (!(s
->sr
[1] & 0x01))
1990 if (s
->sr
[1] & 0x08)
1991 cw
= 16; /* NOTE: no 18 pixel wide */
1992 width
= (s
->cr
[0x01] + 1);
1993 if (s
->cr
[0x06] == 100) {
1994 /* ugly hack for CGA 160x100x16 - explain me the logic */
1997 height
= s
->cr
[0x12] |
1998 ((s
->cr
[0x07] & 0x02) << 7) |
1999 ((s
->cr
[0x07] & 0x40) << 3);
2000 height
= (height
+ 1) / cheight
;
2003 size
= (height
* width
);
2004 if (size
> CH_ATTR_SIZE
) {
2008 snprintf(msg_buffer
, sizeof(msg_buffer
), "%i x %i Text mode",
2013 if (width
!= s
->last_width
|| height
!= s
->last_height
||
2014 cw
!= s
->last_cw
|| cheight
!= s
->last_ch
) {
2015 s
->last_scr_width
= width
* cw
;
2016 s
->last_scr_height
= height
* cheight
;
2017 s
->ds
->surface
->width
= width
;
2018 s
->ds
->surface
->height
= height
;
2020 s
->last_width
= width
;
2021 s
->last_height
= height
;
2022 s
->last_ch
= cheight
;
2027 /* Update "hardware" cursor */
2028 cursor_offset
= ((s
->cr
[0x0e] << 8) | s
->cr
[0x0f]) - s
->start_addr
;
2029 if (cursor_offset
!= s
->cursor_offset
||
2030 s
->cr
[0xa] != s
->cursor_start
||
2031 s
->cr
[0xb] != s
->cursor_end
|| full_update
) {
2032 cursor_visible
= !(s
->cr
[0xa] & 0x20);
2033 if (cursor_visible
&& cursor_offset
< size
&& cursor_offset
>= 0)
2035 TEXTMODE_X(cursor_offset
),
2036 TEXTMODE_Y(cursor_offset
));
2038 dpy_cursor(s
->ds
, -1, -1);
2039 s
->cursor_offset
= cursor_offset
;
2040 s
->cursor_start
= s
->cr
[0xa];
2041 s
->cursor_end
= s
->cr
[0xb];
2044 src
= (uint32_t *) s
->vram_ptr
+ s
->start_addr
;
2048 for (i
= 0; i
< size
; src
++, dst
++, i
++)
2049 console_write_ch(dst
, VMEM2CHTYPE(le32_to_cpu(*src
)));
2051 dpy_update(s
->ds
, 0, 0, width
, height
);
2055 for (i
= 0; i
< size
; src
++, dst
++, i
++) {
2056 console_write_ch(&val
, VMEM2CHTYPE(le32_to_cpu(*src
)));
2064 for (; i
< size
; src
++, dst
++, i
++) {
2065 console_write_ch(&val
, VMEM2CHTYPE(le32_to_cpu(*src
)));
2072 if (c_min
<= c_max
) {
2073 i
= TEXTMODE_Y(c_min
);
2074 dpy_update(s
->ds
, 0, i
, width
, TEXTMODE_Y(c_max
) - i
+ 1);
2083 s
->get_resolution(s
, &width
, &height
);
2084 snprintf(msg_buffer
, sizeof(msg_buffer
), "%i x %i Graphic mode",
2092 snprintf(msg_buffer
, sizeof(msg_buffer
), "VGA Blank mode");
2096 /* Display a message */
2098 s
->last_height
= height
= 3;
2099 dpy_cursor(s
->ds
, -1, -1);
2100 s
->ds
->surface
->width
= s
->last_width
;
2101 s
->ds
->surface
->height
= height
;
2104 for (dst
= chardata
, i
= 0; i
< s
->last_width
* height
; i
++)
2105 console_write_ch(dst
++, ' ');
2107 size
= strlen(msg_buffer
);
2108 width
= (s
->last_width
- size
) / 2;
2109 dst
= chardata
+ s
->last_width
+ width
;
2110 for (i
= 0; i
< size
; i
++)
2111 console_write_ch(dst
++, 0x00200100 | msg_buffer
[i
]);
2113 dpy_update(s
->ds
, 0, 0, s
->last_width
, height
);
2116 static uint64_t vga_mem_read(void *opaque
, target_phys_addr_t addr
,
2119 VGACommonState
*s
= opaque
;
2121 return vga_mem_readb(s
, addr
);
2124 static void vga_mem_write(void *opaque
, target_phys_addr_t addr
,
2125 uint64_t data
, unsigned size
)
2127 VGACommonState
*s
= opaque
;
2129 return vga_mem_writeb(s
, addr
, data
);
2132 const MemoryRegionOps vga_mem_ops
= {
2133 .read
= vga_mem_read
,
2134 .write
= vga_mem_write
,
2135 .endianness
= DEVICE_LITTLE_ENDIAN
,
2137 .min_access_size
= 1,
2138 .max_access_size
= 1,
2142 static int vga_common_post_load(void *opaque
, int version_id
)
2144 VGACommonState
*s
= opaque
;
2147 s
->graphic_mode
= -1;
2151 const VMStateDescription vmstate_vga_common
= {
2154 .minimum_version_id
= 2,
2155 .minimum_version_id_old
= 2,
2156 .post_load
= vga_common_post_load
,
2157 .fields
= (VMStateField
[]) {
2158 VMSTATE_UINT32(latch
, VGACommonState
),
2159 VMSTATE_UINT8(sr_index
, VGACommonState
),
2160 VMSTATE_PARTIAL_BUFFER(sr
, VGACommonState
, 8),
2161 VMSTATE_UINT8(gr_index
, VGACommonState
),
2162 VMSTATE_PARTIAL_BUFFER(gr
, VGACommonState
, 16),
2163 VMSTATE_UINT8(ar_index
, VGACommonState
),
2164 VMSTATE_BUFFER(ar
, VGACommonState
),
2165 VMSTATE_INT32(ar_flip_flop
, VGACommonState
),
2166 VMSTATE_UINT8(cr_index
, VGACommonState
),
2167 VMSTATE_BUFFER(cr
, VGACommonState
),
2168 VMSTATE_UINT8(msr
, VGACommonState
),
2169 VMSTATE_UINT8(fcr
, VGACommonState
),
2170 VMSTATE_UINT8(st00
, VGACommonState
),
2171 VMSTATE_UINT8(st01
, VGACommonState
),
2173 VMSTATE_UINT8(dac_state
, VGACommonState
),
2174 VMSTATE_UINT8(dac_sub_index
, VGACommonState
),
2175 VMSTATE_UINT8(dac_read_index
, VGACommonState
),
2176 VMSTATE_UINT8(dac_write_index
, VGACommonState
),
2177 VMSTATE_BUFFER(dac_cache
, VGACommonState
),
2178 VMSTATE_BUFFER(palette
, VGACommonState
),
2180 VMSTATE_INT32(bank_offset
, VGACommonState
),
2181 VMSTATE_UINT8_EQUAL(is_vbe_vmstate
, VGACommonState
),
2182 #ifdef CONFIG_BOCHS_VBE
2183 VMSTATE_UINT16(vbe_index
, VGACommonState
),
2184 VMSTATE_UINT16_ARRAY(vbe_regs
, VGACommonState
, VBE_DISPI_INDEX_NB
),
2185 VMSTATE_UINT32(vbe_start_addr
, VGACommonState
),
2186 VMSTATE_UINT32(vbe_line_offset
, VGACommonState
),
2187 VMSTATE_UINT32(vbe_bank_mask
, VGACommonState
),
2189 VMSTATE_END_OF_LIST()
2193 void vga_common_init(VGACommonState
*s
, int vga_ram_size
)
2197 for(i
= 0;i
< 256; i
++) {
2199 for(j
= 0; j
< 8; j
++) {
2200 v
|= ((i
>> j
) & 1) << (j
* 4);
2205 for(j
= 0; j
< 4; j
++) {
2206 v
|= ((i
>> (2 * j
)) & 3) << (j
* 4);
2210 for(i
= 0; i
< 16; i
++) {
2212 for(j
= 0; j
< 4; j
++) {
2215 v
|= b
<< (2 * j
+ 1);
2220 #ifdef CONFIG_BOCHS_VBE
2221 s
->is_vbe_vmstate
= 1;
2223 s
->is_vbe_vmstate
= 0;
2225 memory_region_init_ram(&s
->vram
, "vga.vram", vga_ram_size
);
2226 vmstate_register_ram_global(&s
->vram
);
2227 xen_register_framebuffer(&s
->vram
);
2228 s
->vram_ptr
= memory_region_get_ram_ptr(&s
->vram
);
2229 s
->vram_size
= vga_ram_size
;
2230 s
->get_bpp
= vga_get_bpp
;
2231 s
->get_offsets
= vga_get_offsets
;
2232 s
->get_resolution
= vga_get_resolution
;
2233 s
->update
= vga_update_display
;
2234 s
->invalidate
= vga_invalidate_display
;
2235 s
->screen_dump
= vga_screen_dump
;
2236 s
->text_update
= vga_update_text
;
2237 switch (vga_retrace_method
) {
2238 case VGA_RETRACE_DUMB
:
2239 s
->retrace
= vga_dumb_retrace
;
2240 s
->update_retrace_info
= vga_dumb_update_retrace_info
;
2243 case VGA_RETRACE_PRECISE
:
2244 s
->retrace
= vga_precise_retrace
;
2245 s
->update_retrace_info
= vga_precise_update_retrace_info
;
2248 vga_dirty_log_start(s
);
2251 static const MemoryRegionPortio vga_portio_list
[] = {
2252 { 0x04, 2, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3b4 */
2253 { 0x0a, 1, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3ba */
2254 { 0x10, 16, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3c0 */
2255 { 0x24, 2, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3d4 */
2256 { 0x2a, 1, 1, .read
= vga_ioport_read
, .write
= vga_ioport_write
}, /* 3da */
2257 PORTIO_END_OF_LIST(),
2260 #ifdef CONFIG_BOCHS_VBE
2261 static const MemoryRegionPortio vbe_portio_list
[] = {
2262 { 0, 1, 2, .read
= vbe_ioport_read_index
, .write
= vbe_ioport_write_index
},
2264 { 1, 1, 2, .read
= vbe_ioport_read_data
, .write
= vbe_ioport_write_data
},
2266 { 2, 1, 2, .read
= vbe_ioport_read_data
, .write
= vbe_ioport_write_data
},
2268 PORTIO_END_OF_LIST(),
2270 #endif /* CONFIG_BOCHS_VBE */
2272 /* Used by both ISA and PCI */
2273 MemoryRegion
*vga_init_io(VGACommonState
*s
,
2274 const MemoryRegionPortio
**vga_ports
,
2275 const MemoryRegionPortio
**vbe_ports
)
2277 MemoryRegion
*vga_mem
;
2279 *vga_ports
= vga_portio_list
;
2281 #ifdef CONFIG_BOCHS_VBE
2282 *vbe_ports
= vbe_portio_list
;
2285 vga_mem
= g_malloc(sizeof(*vga_mem
));
2286 memory_region_init_io(vga_mem
, &vga_mem_ops
, s
,
2287 "vga-lowmem", 0x20000);
2292 void vga_init(VGACommonState
*s
, MemoryRegion
*address_space
,
2293 MemoryRegion
*address_space_io
, bool init_vga_ports
)
2295 MemoryRegion
*vga_io_memory
;
2296 const MemoryRegionPortio
*vga_ports
, *vbe_ports
;
2297 PortioList
*vga_port_list
= g_new(PortioList
, 1);
2298 PortioList
*vbe_port_list
= g_new(PortioList
, 1);
2300 qemu_register_reset(vga_reset
, s
);
2304 s
->legacy_address_space
= address_space
;
2306 vga_io_memory
= vga_init_io(s
, &vga_ports
, &vbe_ports
);
2307 memory_region_add_subregion_overlap(address_space
,
2308 isa_mem_base
+ 0x000a0000,
2311 memory_region_set_coalescing(vga_io_memory
);
2312 if (init_vga_ports
) {
2313 portio_list_init(vga_port_list
, vga_ports
, s
, "vga");
2314 portio_list_add(vga_port_list
, address_space_io
, 0x3b0);
2317 portio_list_init(vbe_port_list
, vbe_ports
, s
, "vbe");
2318 portio_list_add(vbe_port_list
, address_space_io
, 0x1ce);
2322 void vga_init_vbe(VGACommonState
*s
, MemoryRegion
*system_memory
)
2324 #ifdef CONFIG_BOCHS_VBE
2325 /* XXX: use optimized standard vga accesses */
2326 memory_region_add_subregion(system_memory
,
2327 VBE_DISPI_LFB_PHYSICAL_ADDRESS
,
2332 /********************************************************/
2333 /* vga screen dump */
2335 static void vga_save_dpy_update(DisplayState
*ds
,
2336 int x
, int y
, int w
, int h
)
2338 if (screen_dump_filename
) {
2339 ppm_save(screen_dump_filename
, ds
->surface
);
2343 static void vga_save_dpy_resize(DisplayState
*s
)
2347 static void vga_save_dpy_refresh(DisplayState
*s
)
2351 int ppm_save(const char *filename
, struct DisplaySurface
*ds
)
2359 char *linebuf
, *pbuf
;
2361 f
= fopen(filename
, "wb");
2364 fprintf(f
, "P6\n%d %d\n%d\n",
2365 ds
->width
, ds
->height
, 255);
2366 linebuf
= g_malloc(ds
->width
* 3);
2368 for(y
= 0; y
< ds
->height
; y
++) {
2371 for(x
= 0; x
< ds
->width
; x
++) {
2372 if (ds
->pf
.bits_per_pixel
== 32)
2375 v
= (uint32_t) (*(uint16_t *)d
);
2376 /* Limited to 8 or fewer bits per channel: */
2377 r
= ((v
>> ds
->pf
.rshift
) & ds
->pf
.rmax
) << (8 - ds
->pf
.rbits
);
2378 g
= ((v
>> ds
->pf
.gshift
) & ds
->pf
.gmax
) << (8 - ds
->pf
.gbits
);
2379 b
= ((v
>> ds
->pf
.bshift
) & ds
->pf
.bmax
) << (8 - ds
->pf
.bbits
);
2383 d
+= ds
->pf
.bytes_per_pixel
;
2386 ret
= fwrite(linebuf
, 1, pbuf
- linebuf
, f
);
2394 static DisplayChangeListener
* vga_screen_dump_init(DisplayState
*ds
)
2396 DisplayChangeListener
*dcl
;
2398 dcl
= g_malloc0(sizeof(DisplayChangeListener
));
2399 dcl
->dpy_update
= vga_save_dpy_update
;
2400 dcl
->dpy_resize
= vga_save_dpy_resize
;
2401 dcl
->dpy_refresh
= vga_save_dpy_refresh
;
2402 register_displaychangelistener(ds
, dcl
);
2406 /* save the vga display in a PPM image even if no display is
2408 static void vga_screen_dump(void *opaque
, const char *filename
)
2410 VGACommonState
*s
= opaque
;
2412 if (!screen_dump_dcl
)
2413 screen_dump_dcl
= vga_screen_dump_init(s
->ds
);
2415 screen_dump_filename
= filename
;
2416 vga_invalidate_display(s
);
2418 screen_dump_filename
= NULL
;