4 * Copyright (c) 2003 Fabrice Bellard
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 #include "pixel_ops.h"
30 #include "qemu-timer.h"
33 //#define DEBUG_VGA_MEM
34 //#define DEBUG_VGA_REG
36 //#define DEBUG_BOCHS_VBE
38 /* force some bits to zero */
39 const uint8_t sr_mask
[8] = {
50 const uint8_t gr_mask
[16] = {
69 #define cbswap_32(__x) \
71 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
72 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
73 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
74 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
76 #ifdef HOST_WORDS_BIGENDIAN
77 #define PAT(x) cbswap_32(x)
82 #ifdef HOST_WORDS_BIGENDIAN
88 #ifdef HOST_WORDS_BIGENDIAN
89 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
91 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
94 static const uint32_t mask16
[16] = {
115 #ifdef HOST_WORDS_BIGENDIAN
118 #define PAT(x) cbswap_32(x)
121 static const uint32_t dmask16
[16] = {
140 static const uint32_t dmask4
[4] = {
147 static uint32_t expand4
[256];
148 static uint16_t expand2
[256];
149 static uint8_t expand4to8
[16];
151 static void vga_screen_dump(void *opaque
, const char *filename
);
152 static char *screen_dump_filename
;
153 static DisplayChangeListener
*screen_dump_dcl
;
155 static void vga_update_memory_access(VGACommonState
*s
)
157 MemoryRegion
*region
, *old_region
= s
->chain4_alias
;
158 target_phys_addr_t base
, offset
, size
;
160 s
->chain4_alias
= NULL
;
162 if ((s
->sr
[0x02] & 0xf) == 0xf && s
->sr
[0x04] & 0x08) {
164 switch ((s
->gr
[6] >> 2) & 3) {
172 offset
= s
->bank_offset
;
184 region
= g_malloc(sizeof(*region
));
185 memory_region_init_alias(region
, "vga.chain4", &s
->vram
, offset
, size
);
186 memory_region_add_subregion_overlap(s
->legacy_address_space
, base
,
188 s
->chain4_alias
= region
;
191 memory_region_del_subregion(s
->legacy_address_space
, old_region
);
192 memory_region_destroy(old_region
);
194 s
->plane_updated
= 0xf;
198 static void vga_dumb_update_retrace_info(VGACommonState
*s
)
203 static void vga_precise_update_retrace_info(VGACommonState
*s
)
206 int hretr_start_char
;
207 int hretr_skew_chars
;
211 int vretr_start_line
;
220 const int clk_hz
[] = {25175000, 28322000, 25175000, 25175000};
221 int64_t chars_per_sec
;
222 struct vga_precise_retrace
*r
= &s
->retrace_info
.precise
;
224 htotal_chars
= s
->cr
[0x00] + 5;
225 hretr_start_char
= s
->cr
[0x04];
226 hretr_skew_chars
= (s
->cr
[0x05] >> 5) & 3;
227 hretr_end_char
= s
->cr
[0x05] & 0x1f;
229 vtotal_lines
= (s
->cr
[0x06]
230 | (((s
->cr
[0x07] & 1) | ((s
->cr
[0x07] >> 4) & 2)) << 8)) + 2
232 vretr_start_line
= s
->cr
[0x10]
233 | ((((s
->cr
[0x07] >> 2) & 1) | ((s
->cr
[0x07] >> 6) & 2)) << 8)
235 vretr_end_line
= s
->cr
[0x11] & 0xf;
239 clocking_mode
= (s
->sr
[0x01] >> 3) & 1;
240 clock_sel
= (s
->msr
>> 2) & 3;
241 dots
= (s
->msr
& 1) ? 8 : 9;
243 chars_per_sec
= clk_hz
[clock_sel
] / dots
;
245 htotal_chars
<<= clocking_mode
;
247 r
->total_chars
= vtotal_lines
* htotal_chars
;
249 r
->ticks_per_char
= get_ticks_per_sec() / (r
->total_chars
* r
->freq
);
251 r
->ticks_per_char
= get_ticks_per_sec() / chars_per_sec
;
254 r
->vstart
= vretr_start_line
;
255 r
->vend
= r
->vstart
+ vretr_end_line
+ 1;
257 r
->hstart
= hretr_start_char
+ hretr_skew_chars
;
258 r
->hend
= r
->hstart
+ hretr_end_char
+ 1;
259 r
->htotal
= htotal_chars
;
262 div2
= (s
->cr
[0x17] >> 2) & 1;
263 sldiv2
= (s
->cr
[0x17] >> 3) & 1;
273 "div2 = %d sldiv2 = %d\n"
274 "clocking_mode = %d\n"
275 "clock_sel = %d %d\n"
277 "ticks/char = %" PRId64
"\n"
279 (double) get_ticks_per_sec() / (r
->ticks_per_char
* r
->total_chars
),
297 static uint8_t vga_precise_retrace(VGACommonState
*s
)
299 struct vga_precise_retrace
*r
= &s
->retrace_info
.precise
;
300 uint8_t val
= s
->st01
& ~(ST01_V_RETRACE
| ST01_DISP_ENABLE
);
302 if (r
->total_chars
) {
303 int cur_line
, cur_line_char
, cur_char
;
306 cur_tick
= qemu_get_clock_ns(vm_clock
);
308 cur_char
= (cur_tick
/ r
->ticks_per_char
) % r
->total_chars
;
309 cur_line
= cur_char
/ r
->htotal
;
311 if (cur_line
>= r
->vstart
&& cur_line
<= r
->vend
) {
312 val
|= ST01_V_RETRACE
| ST01_DISP_ENABLE
;
314 cur_line_char
= cur_char
% r
->htotal
;
315 if (cur_line_char
>= r
->hstart
&& cur_line_char
<= r
->hend
) {
316 val
|= ST01_DISP_ENABLE
;
322 return s
->st01
^ (ST01_V_RETRACE
| ST01_DISP_ENABLE
);
326 static uint8_t vga_dumb_retrace(VGACommonState
*s
)
328 return s
->st01
^ (ST01_V_RETRACE
| ST01_DISP_ENABLE
);
331 int vga_ioport_invalid(VGACommonState
*s
, uint32_t addr
)
333 if (s
->msr
& MSR_COLOR_EMULATION
) {
335 return (addr
>= 0x3b0 && addr
<= 0x3bf);
338 return (addr
>= 0x3d0 && addr
<= 0x3df);
342 uint32_t vga_ioport_read(void *opaque
, uint32_t addr
)
344 VGACommonState
*s
= opaque
;
347 if (vga_ioport_invalid(s
, addr
)) {
352 if (s
->ar_flip_flop
== 0) {
359 index
= s
->ar_index
& 0x1f;
372 val
= s
->sr
[s
->sr_index
];
374 printf("vga: read SR%x = 0x%02x\n", s
->sr_index
, val
);
381 val
= s
->dac_write_index
;
384 val
= s
->palette
[s
->dac_read_index
* 3 + s
->dac_sub_index
];
385 if (++s
->dac_sub_index
== 3) {
386 s
->dac_sub_index
= 0;
400 val
= s
->gr
[s
->gr_index
];
402 printf("vga: read GR%x = 0x%02x\n", s
->gr_index
, val
);
411 val
= s
->cr
[s
->cr_index
];
413 printf("vga: read CR%x = 0x%02x\n", s
->cr_index
, val
);
418 /* just toggle to fool polling */
419 val
= s
->st01
= s
->retrace(s
);
427 #if defined(DEBUG_VGA)
428 printf("VGA: read addr=0x%04x data=0x%02x\n", addr
, val
);
433 void vga_ioport_write(void *opaque
, uint32_t addr
, uint32_t val
)
435 VGACommonState
*s
= opaque
;
438 /* check port range access depending on color/monochrome mode */
439 if (vga_ioport_invalid(s
, addr
)) {
443 printf("VGA: write addr=0x%04x data=0x%02x\n", addr
, val
);
448 if (s
->ar_flip_flop
== 0) {
452 index
= s
->ar_index
& 0x1f;
455 s
->ar
[index
] = val
& 0x3f;
458 s
->ar
[index
] = val
& ~0x10;
464 s
->ar
[index
] = val
& ~0xc0;
467 s
->ar
[index
] = val
& ~0xf0;
470 s
->ar
[index
] = val
& ~0xf0;
476 s
->ar_flip_flop
^= 1;
479 s
->msr
= val
& ~0x10;
480 s
->update_retrace_info(s
);
483 s
->sr_index
= val
& 7;
487 printf("vga: write SR%x = 0x%02x\n", s
->sr_index
, val
);
489 s
->sr
[s
->sr_index
] = val
& sr_mask
[s
->sr_index
];
490 if (s
->sr_index
== 1) s
->update_retrace_info(s
);
491 vga_update_memory_access(s
);
494 s
->dac_read_index
= val
;
495 s
->dac_sub_index
= 0;
499 s
->dac_write_index
= val
;
500 s
->dac_sub_index
= 0;
504 s
->dac_cache
[s
->dac_sub_index
] = val
;
505 if (++s
->dac_sub_index
== 3) {
506 memcpy(&s
->palette
[s
->dac_write_index
* 3], s
->dac_cache
, 3);
507 s
->dac_sub_index
= 0;
508 s
->dac_write_index
++;
512 s
->gr_index
= val
& 0x0f;
516 printf("vga: write GR%x = 0x%02x\n", s
->gr_index
, val
);
518 s
->gr
[s
->gr_index
] = val
& gr_mask
[s
->gr_index
];
519 vga_update_memory_access(s
);
528 printf("vga: write CR%x = 0x%02x\n", s
->cr_index
, val
);
530 /* handle CR0-7 protection */
531 if ((s
->cr
[0x11] & 0x80) && s
->cr_index
<= 7) {
532 /* can always write bit 4 of CR7 */
533 if (s
->cr_index
== 7)
534 s
->cr
[7] = (s
->cr
[7] & ~0x10) | (val
& 0x10);
537 s
->cr
[s
->cr_index
] = val
;
539 switch(s
->cr_index
) {
547 s
->update_retrace_info(s
);
558 #ifdef CONFIG_BOCHS_VBE
559 static uint32_t vbe_ioport_read_index(void *opaque
, uint32_t addr
)
561 VGACommonState
*s
= opaque
;
567 static uint32_t vbe_ioport_read_data(void *opaque
, uint32_t addr
)
569 VGACommonState
*s
= opaque
;
572 if (s
->vbe_index
< VBE_DISPI_INDEX_NB
) {
573 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_GETCAPS
) {
574 switch(s
->vbe_index
) {
575 /* XXX: do not hardcode ? */
576 case VBE_DISPI_INDEX_XRES
:
577 val
= VBE_DISPI_MAX_XRES
;
579 case VBE_DISPI_INDEX_YRES
:
580 val
= VBE_DISPI_MAX_YRES
;
582 case VBE_DISPI_INDEX_BPP
:
583 val
= VBE_DISPI_MAX_BPP
;
586 val
= s
->vbe_regs
[s
->vbe_index
];
590 val
= s
->vbe_regs
[s
->vbe_index
];
592 } else if (s
->vbe_index
== VBE_DISPI_INDEX_VIDEO_MEMORY_64K
) {
593 val
= s
->vram_size
/ (64 * 1024);
597 #ifdef DEBUG_BOCHS_VBE
598 printf("VBE: read index=0x%x val=0x%x\n", s
->vbe_index
, val
);
603 static void vbe_ioport_write_index(void *opaque
, uint32_t addr
, uint32_t val
)
605 VGACommonState
*s
= opaque
;
609 static void vbe_ioport_write_data(void *opaque
, uint32_t addr
, uint32_t val
)
611 VGACommonState
*s
= opaque
;
613 if (s
->vbe_index
<= VBE_DISPI_INDEX_NB
) {
614 #ifdef DEBUG_BOCHS_VBE
615 printf("VBE: write index=0x%x val=0x%x\n", s
->vbe_index
, val
);
617 switch(s
->vbe_index
) {
618 case VBE_DISPI_INDEX_ID
:
619 if (val
== VBE_DISPI_ID0
||
620 val
== VBE_DISPI_ID1
||
621 val
== VBE_DISPI_ID2
||
622 val
== VBE_DISPI_ID3
||
623 val
== VBE_DISPI_ID4
) {
624 s
->vbe_regs
[s
->vbe_index
] = val
;
627 case VBE_DISPI_INDEX_XRES
:
628 if ((val
<= VBE_DISPI_MAX_XRES
) && ((val
& 7) == 0)) {
629 s
->vbe_regs
[s
->vbe_index
] = val
;
632 case VBE_DISPI_INDEX_YRES
:
633 if (val
<= VBE_DISPI_MAX_YRES
) {
634 s
->vbe_regs
[s
->vbe_index
] = val
;
637 case VBE_DISPI_INDEX_BPP
:
640 if (val
== 4 || val
== 8 || val
== 15 ||
641 val
== 16 || val
== 24 || val
== 32) {
642 s
->vbe_regs
[s
->vbe_index
] = val
;
645 case VBE_DISPI_INDEX_BANK
:
646 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
647 val
&= (s
->vbe_bank_mask
>> 2);
649 val
&= s
->vbe_bank_mask
;
651 s
->vbe_regs
[s
->vbe_index
] = val
;
652 s
->bank_offset
= (val
<< 16);
653 vga_update_memory_access(s
);
655 case VBE_DISPI_INDEX_ENABLE
:
656 if ((val
& VBE_DISPI_ENABLED
) &&
657 !(s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
)) {
658 int h
, shift_control
;
660 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] =
661 s
->vbe_regs
[VBE_DISPI_INDEX_XRES
];
662 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_HEIGHT
] =
663 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
];
664 s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
] = 0;
665 s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
] = 0;
667 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
668 s
->vbe_line_offset
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 1;
670 s
->vbe_line_offset
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] *
671 ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
672 s
->vbe_start_addr
= 0;
674 /* clear the screen (should be done in BIOS) */
675 if (!(val
& VBE_DISPI_NOCLEARMEM
)) {
676 memset(s
->vram_ptr
, 0,
677 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] * s
->vbe_line_offset
);
680 /* we initialize the VGA graphic mode (should be done
682 s
->gr
[0x06] = (s
->gr
[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
683 s
->cr
[0x17] |= 3; /* no CGA modes */
684 s
->cr
[0x13] = s
->vbe_line_offset
>> 3;
686 s
->cr
[0x01] = (s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 3) - 1;
687 /* height (only meaningful if < 1024) */
688 h
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] - 1;
690 s
->cr
[0x07] = (s
->cr
[0x07] & ~0x42) |
691 ((h
>> 7) & 0x02) | ((h
>> 3) & 0x40);
692 /* line compare to 1023 */
697 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
699 s
->sr
[0x01] &= ~8; /* no double line */
702 s
->sr
[4] |= 0x08; /* set chain 4 mode */
703 s
->sr
[2] |= 0x0f; /* activate all planes */
705 s
->gr
[0x05] = (s
->gr
[0x05] & ~0x60) | (shift_control
<< 5);
706 s
->cr
[0x09] &= ~0x9f; /* no double scan */
708 /* XXX: the bios should do that */
711 s
->dac_8bit
= (val
& VBE_DISPI_8BIT_DAC
) > 0;
712 s
->vbe_regs
[s
->vbe_index
] = val
;
713 vga_update_memory_access(s
);
715 case VBE_DISPI_INDEX_VIRT_WIDTH
:
717 int w
, h
, line_offset
;
719 if (val
< s
->vbe_regs
[VBE_DISPI_INDEX_XRES
])
722 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
723 line_offset
= w
>> 1;
725 line_offset
= w
* ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
726 h
= s
->vram_size
/ line_offset
;
727 /* XXX: support weird bochs semantics ? */
728 if (h
< s
->vbe_regs
[VBE_DISPI_INDEX_YRES
])
730 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] = w
;
731 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_HEIGHT
] = h
;
732 s
->vbe_line_offset
= line_offset
;
735 case VBE_DISPI_INDEX_X_OFFSET
:
736 case VBE_DISPI_INDEX_Y_OFFSET
:
739 s
->vbe_regs
[s
->vbe_index
] = val
;
740 s
->vbe_start_addr
= s
->vbe_line_offset
* s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
];
741 x
= s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
];
742 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
743 s
->vbe_start_addr
+= x
>> 1;
745 s
->vbe_start_addr
+= x
* ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
746 s
->vbe_start_addr
>>= 2;
756 /* called for accesses between 0xa0000 and 0xc0000 */
757 uint32_t vga_mem_readb(VGACommonState
*s
, target_phys_addr_t addr
)
759 int memory_map_mode
, plane
;
762 /* convert to VGA memory offset */
763 memory_map_mode
= (s
->gr
[6] >> 2) & 3;
765 switch(memory_map_mode
) {
771 addr
+= s
->bank_offset
;
786 if (s
->sr
[4] & 0x08) {
787 /* chain 4 mode : simplest access */
788 ret
= s
->vram_ptr
[addr
];
789 } else if (s
->gr
[5] & 0x10) {
790 /* odd/even mode (aka text mode mapping) */
791 plane
= (s
->gr
[4] & 2) | (addr
& 1);
792 ret
= s
->vram_ptr
[((addr
& ~1) << 1) | plane
];
794 /* standard VGA latched access */
795 s
->latch
= ((uint32_t *)s
->vram_ptr
)[addr
];
797 if (!(s
->gr
[5] & 0x08)) {
800 ret
= GET_PLANE(s
->latch
, plane
);
803 ret
= (s
->latch
^ mask16
[s
->gr
[2]]) & mask16
[s
->gr
[7]];
812 /* called for accesses between 0xa0000 and 0xc0000 */
813 void vga_mem_writeb(VGACommonState
*s
, target_phys_addr_t addr
, uint32_t val
)
815 int memory_map_mode
, plane
, write_mode
, b
, func_select
, mask
;
816 uint32_t write_mask
, bit_mask
, set_mask
;
819 printf("vga: [0x" TARGET_FMT_plx
"] = 0x%02x\n", addr
, val
);
821 /* convert to VGA memory offset */
822 memory_map_mode
= (s
->gr
[6] >> 2) & 3;
824 switch(memory_map_mode
) {
830 addr
+= s
->bank_offset
;
845 if (s
->sr
[4] & 0x08) {
846 /* chain 4 mode : simplest access */
849 if (s
->sr
[2] & mask
) {
850 s
->vram_ptr
[addr
] = val
;
852 printf("vga: chain4: [0x" TARGET_FMT_plx
"]\n", addr
);
854 s
->plane_updated
|= mask
; /* only used to detect font change */
855 memory_region_set_dirty(&s
->vram
, addr
);
857 } else if (s
->gr
[5] & 0x10) {
858 /* odd/even mode (aka text mode mapping) */
859 plane
= (s
->gr
[4] & 2) | (addr
& 1);
861 if (s
->sr
[2] & mask
) {
862 addr
= ((addr
& ~1) << 1) | plane
;
863 s
->vram_ptr
[addr
] = val
;
865 printf("vga: odd/even: [0x" TARGET_FMT_plx
"]\n", addr
);
867 s
->plane_updated
|= mask
; /* only used to detect font change */
868 memory_region_set_dirty(&s
->vram
, addr
);
871 /* standard VGA latched access */
872 write_mode
= s
->gr
[5] & 3;
878 val
= ((val
>> b
) | (val
<< (8 - b
))) & 0xff;
882 /* apply set/reset mask */
883 set_mask
= mask16
[s
->gr
[1]];
884 val
= (val
& ~set_mask
) | (mask16
[s
->gr
[0]] & set_mask
);
891 val
= mask16
[val
& 0x0f];
897 val
= (val
>> b
) | (val
<< (8 - b
));
899 bit_mask
= s
->gr
[8] & val
;
900 val
= mask16
[s
->gr
[0]];
904 /* apply logical operation */
905 func_select
= s
->gr
[3] >> 3;
906 switch(func_select
) {
926 bit_mask
|= bit_mask
<< 8;
927 bit_mask
|= bit_mask
<< 16;
928 val
= (val
& bit_mask
) | (s
->latch
& ~bit_mask
);
931 /* mask data according to sr[2] */
933 s
->plane_updated
|= mask
; /* only used to detect font change */
934 write_mask
= mask16
[mask
];
935 ((uint32_t *)s
->vram_ptr
)[addr
] =
936 (((uint32_t *)s
->vram_ptr
)[addr
] & ~write_mask
) |
939 printf("vga: latch: [0x" TARGET_FMT_plx
"] mask=0x%08x val=0x%08x\n",
940 addr
* 4, write_mask
, val
);
942 memory_region_set_dirty(&s
->vram
, addr
<< 2);
946 typedef void vga_draw_glyph8_func(uint8_t *d
, int linesize
,
947 const uint8_t *font_ptr
, int h
,
948 uint32_t fgcol
, uint32_t bgcol
);
949 typedef void vga_draw_glyph9_func(uint8_t *d
, int linesize
,
950 const uint8_t *font_ptr
, int h
,
951 uint32_t fgcol
, uint32_t bgcol
, int dup9
);
952 typedef void vga_draw_line_func(VGACommonState
*s1
, uint8_t *d
,
953 const uint8_t *s
, int width
);
956 #include "vga_template.h"
959 #include "vga_template.h"
963 #include "vga_template.h"
966 #include "vga_template.h"
970 #include "vga_template.h"
973 #include "vga_template.h"
977 #include "vga_template.h"
979 static unsigned int rgb_to_pixel8_dup(unsigned int r
, unsigned int g
, unsigned b
)
982 col
= rgb_to_pixel8(r
, g
, b
);
988 static unsigned int rgb_to_pixel15_dup(unsigned int r
, unsigned int g
, unsigned b
)
991 col
= rgb_to_pixel15(r
, g
, b
);
996 static unsigned int rgb_to_pixel15bgr_dup(unsigned int r
, unsigned int g
,
1000 col
= rgb_to_pixel15bgr(r
, g
, b
);
1005 static unsigned int rgb_to_pixel16_dup(unsigned int r
, unsigned int g
, unsigned b
)
1008 col
= rgb_to_pixel16(r
, g
, b
);
1013 static unsigned int rgb_to_pixel16bgr_dup(unsigned int r
, unsigned int g
,
1017 col
= rgb_to_pixel16bgr(r
, g
, b
);
1022 static unsigned int rgb_to_pixel32_dup(unsigned int r
, unsigned int g
, unsigned b
)
1025 col
= rgb_to_pixel32(r
, g
, b
);
1029 static unsigned int rgb_to_pixel32bgr_dup(unsigned int r
, unsigned int g
, unsigned b
)
1032 col
= rgb_to_pixel32bgr(r
, g
, b
);
1036 /* return true if the palette was modified */
1037 static int update_palette16(VGACommonState
*s
)
1040 uint32_t v
, col
, *palette
;
1043 palette
= s
->last_palette
;
1044 for(i
= 0; i
< 16; i
++) {
1046 if (s
->ar
[0x10] & 0x80)
1047 v
= ((s
->ar
[0x14] & 0xf) << 4) | (v
& 0xf);
1049 v
= ((s
->ar
[0x14] & 0xc) << 4) | (v
& 0x3f);
1051 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
1052 c6_to_8(s
->palette
[v
+ 1]),
1053 c6_to_8(s
->palette
[v
+ 2]));
1054 if (col
!= palette
[i
]) {
1062 /* return true if the palette was modified */
1063 static int update_palette256(VGACommonState
*s
)
1066 uint32_t v
, col
, *palette
;
1069 palette
= s
->last_palette
;
1071 for(i
= 0; i
< 256; i
++) {
1073 col
= s
->rgb_to_pixel(s
->palette
[v
],
1077 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
1078 c6_to_8(s
->palette
[v
+ 1]),
1079 c6_to_8(s
->palette
[v
+ 2]));
1081 if (col
!= palette
[i
]) {
1090 static void vga_get_offsets(VGACommonState
*s
,
1091 uint32_t *pline_offset
,
1092 uint32_t *pstart_addr
,
1093 uint32_t *pline_compare
)
1095 uint32_t start_addr
, line_offset
, line_compare
;
1096 #ifdef CONFIG_BOCHS_VBE
1097 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1098 line_offset
= s
->vbe_line_offset
;
1099 start_addr
= s
->vbe_start_addr
;
1100 line_compare
= 65535;
1104 /* compute line_offset in bytes */
1105 line_offset
= s
->cr
[0x13];
1108 /* starting address */
1109 start_addr
= s
->cr
[0x0d] | (s
->cr
[0x0c] << 8);
1112 line_compare
= s
->cr
[0x18] |
1113 ((s
->cr
[0x07] & 0x10) << 4) |
1114 ((s
->cr
[0x09] & 0x40) << 3);
1116 *pline_offset
= line_offset
;
1117 *pstart_addr
= start_addr
;
1118 *pline_compare
= line_compare
;
1121 /* update start_addr and line_offset. Return TRUE if modified */
1122 static int update_basic_params(VGACommonState
*s
)
1125 uint32_t start_addr
, line_offset
, line_compare
;
1129 s
->get_offsets(s
, &line_offset
, &start_addr
, &line_compare
);
1131 if (line_offset
!= s
->line_offset
||
1132 start_addr
!= s
->start_addr
||
1133 line_compare
!= s
->line_compare
) {
1134 s
->line_offset
= line_offset
;
1135 s
->start_addr
= start_addr
;
1136 s
->line_compare
= line_compare
;
1144 static inline int get_depth_index(DisplayState
*s
)
1146 switch(ds_get_bits_per_pixel(s
)) {
1155 if (is_surface_bgr(s
->surface
))
1162 static vga_draw_glyph8_func
* const vga_draw_glyph8_table
[NB_DEPTHS
] = {
1172 static vga_draw_glyph8_func
* const vga_draw_glyph16_table
[NB_DEPTHS
] = {
1174 vga_draw_glyph16_16
,
1175 vga_draw_glyph16_16
,
1176 vga_draw_glyph16_32
,
1177 vga_draw_glyph16_32
,
1178 vga_draw_glyph16_16
,
1179 vga_draw_glyph16_16
,
1182 static vga_draw_glyph9_func
* const vga_draw_glyph9_table
[NB_DEPTHS
] = {
1192 static const uint8_t cursor_glyph
[32 * 4] = {
1193 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1194 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
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,
1211 static void vga_get_text_resolution(VGACommonState
*s
, int *pwidth
, int *pheight
,
1212 int *pcwidth
, int *pcheight
)
1214 int width
, cwidth
, height
, cheight
;
1216 /* total width & height */
1217 cheight
= (s
->cr
[9] & 0x1f) + 1;
1219 if (!(s
->sr
[1] & 0x01))
1221 if (s
->sr
[1] & 0x08)
1222 cwidth
= 16; /* NOTE: no 18 pixel wide */
1223 width
= (s
->cr
[0x01] + 1);
1224 if (s
->cr
[0x06] == 100) {
1225 /* ugly hack for CGA 160x100x16 - explain me the logic */
1228 height
= s
->cr
[0x12] |
1229 ((s
->cr
[0x07] & 0x02) << 7) |
1230 ((s
->cr
[0x07] & 0x40) << 3);
1231 height
= (height
+ 1) / cheight
;
1237 *pcheight
= cheight
;
1240 typedef unsigned int rgb_to_pixel_dup_func(unsigned int r
, unsigned int g
, unsigned b
);
1242 static rgb_to_pixel_dup_func
* const rgb_to_pixel_dup_table
[NB_DEPTHS
] = {
1247 rgb_to_pixel32bgr_dup
,
1248 rgb_to_pixel15bgr_dup
,
1249 rgb_to_pixel16bgr_dup
,
1260 static void vga_draw_text(VGACommonState
*s
, int full_update
)
1262 int cx
, cy
, cheight
, cw
, ch
, cattr
, height
, width
, ch_attr
;
1263 int cx_min
, cx_max
, linesize
, x_incr
, line
, line1
;
1264 uint32_t offset
, fgcol
, bgcol
, v
, cursor_offset
;
1265 uint8_t *d1
, *d
, *src
, *dest
, *cursor_ptr
;
1266 const uint8_t *font_ptr
, *font_base
[2];
1267 int dup9
, line_offset
, depth_index
;
1269 uint32_t *ch_attr_ptr
;
1270 vga_draw_glyph8_func
*vga_draw_glyph8
;
1271 vga_draw_glyph9_func
*vga_draw_glyph9
;
1273 /* compute font data address (in plane 2) */
1275 offset
= (((v
>> 4) & 1) | ((v
<< 1) & 6)) * 8192 * 4 + 2;
1276 if (offset
!= s
->font_offsets
[0]) {
1277 s
->font_offsets
[0] = offset
;
1280 font_base
[0] = s
->vram_ptr
+ offset
;
1282 offset
= (((v
>> 5) & 1) | ((v
>> 1) & 6)) * 8192 * 4 + 2;
1283 font_base
[1] = s
->vram_ptr
+ offset
;
1284 if (offset
!= s
->font_offsets
[1]) {
1285 s
->font_offsets
[1] = offset
;
1288 if (s
->plane_updated
& (1 << 2) || s
->chain4_alias
) {
1289 /* if the plane 2 was modified since the last display, it
1290 indicates the font may have been modified */
1291 s
->plane_updated
= 0;
1294 full_update
|= update_basic_params(s
);
1296 line_offset
= s
->line_offset
;
1298 vga_get_text_resolution(s
, &width
, &height
, &cw
, &cheight
);
1299 if ((height
* width
) > CH_ATTR_SIZE
) {
1300 /* better than nothing: exit if transient size is too big */
1304 if (width
!= s
->last_width
|| height
!= s
->last_height
||
1305 cw
!= s
->last_cw
|| cheight
!= s
->last_ch
|| s
->last_depth
) {
1306 s
->last_scr_width
= width
* cw
;
1307 s
->last_scr_height
= height
* cheight
;
1308 qemu_console_resize(s
->ds
, s
->last_scr_width
, s
->last_scr_height
);
1310 s
->last_width
= width
;
1311 s
->last_height
= height
;
1312 s
->last_ch
= cheight
;
1317 rgb_to_pixel_dup_table
[get_depth_index(s
->ds
)];
1318 full_update
|= update_palette16(s
);
1319 palette
= s
->last_palette
;
1320 x_incr
= cw
* ((ds_get_bits_per_pixel(s
->ds
) + 7) >> 3);
1322 cursor_offset
= ((s
->cr
[0x0e] << 8) | s
->cr
[0x0f]) - s
->start_addr
;
1323 if (cursor_offset
!= s
->cursor_offset
||
1324 s
->cr
[0xa] != s
->cursor_start
||
1325 s
->cr
[0xb] != s
->cursor_end
) {
1326 /* if the cursor position changed, we update the old and new
1328 if (s
->cursor_offset
< CH_ATTR_SIZE
)
1329 s
->last_ch_attr
[s
->cursor_offset
] = -1;
1330 if (cursor_offset
< CH_ATTR_SIZE
)
1331 s
->last_ch_attr
[cursor_offset
] = -1;
1332 s
->cursor_offset
= cursor_offset
;
1333 s
->cursor_start
= s
->cr
[0xa];
1334 s
->cursor_end
= s
->cr
[0xb];
1336 cursor_ptr
= s
->vram_ptr
+ (s
->start_addr
+ cursor_offset
) * 4;
1338 depth_index
= get_depth_index(s
->ds
);
1340 vga_draw_glyph8
= vga_draw_glyph16_table
[depth_index
];
1342 vga_draw_glyph8
= vga_draw_glyph8_table
[depth_index
];
1343 vga_draw_glyph9
= vga_draw_glyph9_table
[depth_index
];
1345 dest
= ds_get_data(s
->ds
);
1346 linesize
= ds_get_linesize(s
->ds
);
1347 ch_attr_ptr
= s
->last_ch_attr
;
1349 offset
= s
->start_addr
* 4;
1350 for(cy
= 0; cy
< height
; cy
++) {
1352 src
= s
->vram_ptr
+ offset
;
1355 for(cx
= 0; cx
< width
; cx
++) {
1356 ch_attr
= *(uint16_t *)src
;
1357 if (full_update
|| ch_attr
!= *ch_attr_ptr
) {
1362 *ch_attr_ptr
= ch_attr
;
1363 #ifdef HOST_WORDS_BIGENDIAN
1365 cattr
= ch_attr
& 0xff;
1367 ch
= ch_attr
& 0xff;
1368 cattr
= ch_attr
>> 8;
1370 font_ptr
= font_base
[(cattr
>> 3) & 1];
1371 font_ptr
+= 32 * 4 * ch
;
1372 bgcol
= palette
[cattr
>> 4];
1373 fgcol
= palette
[cattr
& 0x0f];
1375 vga_draw_glyph8(d1
, linesize
,
1376 font_ptr
, cheight
, fgcol
, bgcol
);
1379 if (ch
>= 0xb0 && ch
<= 0xdf && (s
->ar
[0x10] & 0x04))
1381 vga_draw_glyph9(d1
, linesize
,
1382 font_ptr
, cheight
, fgcol
, bgcol
, dup9
);
1384 if (src
== cursor_ptr
&&
1385 !(s
->cr
[0x0a] & 0x20)) {
1386 int line_start
, line_last
, h
;
1387 /* draw the cursor */
1388 line_start
= s
->cr
[0x0a] & 0x1f;
1389 line_last
= s
->cr
[0x0b] & 0x1f;
1390 /* XXX: check that */
1391 if (line_last
> cheight
- 1)
1392 line_last
= cheight
- 1;
1393 if (line_last
>= line_start
&& line_start
< cheight
) {
1394 h
= line_last
- line_start
+ 1;
1395 d
= d1
+ linesize
* line_start
;
1397 vga_draw_glyph8(d
, linesize
,
1398 cursor_glyph
, h
, fgcol
, bgcol
);
1400 vga_draw_glyph9(d
, linesize
,
1401 cursor_glyph
, h
, fgcol
, bgcol
, 1);
1411 dpy_update(s
->ds
, cx_min
* cw
, cy
* cheight
,
1412 (cx_max
- cx_min
+ 1) * cw
, cheight
);
1414 dest
+= linesize
* cheight
;
1415 line1
= line
+ cheight
;
1416 offset
+= line_offset
;
1417 if (line
< s
->line_compare
&& line1
>= s
->line_compare
) {
1438 static vga_draw_line_func
* const vga_draw_line_table
[NB_DEPTHS
* VGA_DRAW_LINE_NB
] = {
1448 vga_draw_line2d2_16
,
1449 vga_draw_line2d2_16
,
1450 vga_draw_line2d2_32
,
1451 vga_draw_line2d2_32
,
1452 vga_draw_line2d2_16
,
1453 vga_draw_line2d2_16
,
1464 vga_draw_line4d2_16
,
1465 vga_draw_line4d2_16
,
1466 vga_draw_line4d2_32
,
1467 vga_draw_line4d2_32
,
1468 vga_draw_line4d2_16
,
1469 vga_draw_line4d2_16
,
1472 vga_draw_line8d2_16
,
1473 vga_draw_line8d2_16
,
1474 vga_draw_line8d2_32
,
1475 vga_draw_line8d2_32
,
1476 vga_draw_line8d2_16
,
1477 vga_draw_line8d2_16
,
1491 vga_draw_line15_32bgr
,
1492 vga_draw_line15_15bgr
,
1493 vga_draw_line15_16bgr
,
1499 vga_draw_line16_32bgr
,
1500 vga_draw_line16_15bgr
,
1501 vga_draw_line16_16bgr
,
1507 vga_draw_line24_32bgr
,
1508 vga_draw_line24_15bgr
,
1509 vga_draw_line24_16bgr
,
1515 vga_draw_line32_32bgr
,
1516 vga_draw_line32_15bgr
,
1517 vga_draw_line32_16bgr
,
1520 static int vga_get_bpp(VGACommonState
*s
)
1523 #ifdef CONFIG_BOCHS_VBE
1524 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1525 ret
= s
->vbe_regs
[VBE_DISPI_INDEX_BPP
];
1534 static void vga_get_resolution(VGACommonState
*s
, int *pwidth
, int *pheight
)
1538 #ifdef CONFIG_BOCHS_VBE
1539 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1540 width
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
];
1541 height
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
];
1545 width
= (s
->cr
[0x01] + 1) * 8;
1546 height
= s
->cr
[0x12] |
1547 ((s
->cr
[0x07] & 0x02) << 7) |
1548 ((s
->cr
[0x07] & 0x40) << 3);
1549 height
= (height
+ 1);
1555 void vga_invalidate_scanlines(VGACommonState
*s
, int y1
, int y2
)
1558 if (y1
>= VGA_MAX_HEIGHT
)
1560 if (y2
>= VGA_MAX_HEIGHT
)
1561 y2
= VGA_MAX_HEIGHT
;
1562 for(y
= y1
; y
< y2
; y
++) {
1563 s
->invalidated_y_table
[y
>> 5] |= 1 << (y
& 0x1f);
1567 static void vga_sync_dirty_bitmap(VGACommonState
*s
)
1569 memory_region_sync_dirty_bitmap(&s
->vram
);
1572 void vga_dirty_log_start(VGACommonState
*s
)
1574 memory_region_set_log(&s
->vram
, true, DIRTY_MEMORY_VGA
);
1577 void vga_dirty_log_stop(VGACommonState
*s
)
1579 memory_region_set_log(&s
->vram
, false, DIRTY_MEMORY_VGA
);
1585 static void vga_draw_graphic(VGACommonState
*s
, int full_update
)
1587 int y1
, y
, update
, linesize
, y_start
, double_scan
, mask
, depth
;
1588 int width
, height
, shift_control
, line_offset
, bwidth
, bits
;
1589 ram_addr_t page0
, page1
, page_min
, page_max
;
1590 int disp_width
, multi_scan
, multi_run
;
1592 uint32_t v
, addr1
, addr
;
1593 vga_draw_line_func
*vga_draw_line
;
1595 full_update
|= update_basic_params(s
);
1598 vga_sync_dirty_bitmap(s
);
1600 s
->get_resolution(s
, &width
, &height
);
1603 shift_control
= (s
->gr
[0x05] >> 5) & 3;
1604 double_scan
= (s
->cr
[0x09] >> 7);
1605 if (shift_control
!= 1) {
1606 multi_scan
= (((s
->cr
[0x09] & 0x1f) + 1) << double_scan
) - 1;
1608 /* in CGA modes, multi_scan is ignored */
1609 /* XXX: is it correct ? */
1610 multi_scan
= double_scan
;
1612 multi_run
= multi_scan
;
1613 if (shift_control
!= s
->shift_control
||
1614 double_scan
!= s
->double_scan
) {
1616 s
->shift_control
= shift_control
;
1617 s
->double_scan
= double_scan
;
1620 if (shift_control
== 0) {
1621 if (s
->sr
[0x01] & 8) {
1624 } else if (shift_control
== 1) {
1625 if (s
->sr
[0x01] & 8) {
1630 depth
= s
->get_bpp(s
);
1631 if (s
->line_offset
!= s
->last_line_offset
||
1632 disp_width
!= s
->last_width
||
1633 height
!= s
->last_height
||
1634 s
->last_depth
!= depth
) {
1635 #if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
1636 if (depth
== 16 || depth
== 32) {
1640 qemu_free_displaysurface(s
->ds
);
1641 s
->ds
->surface
= qemu_create_displaysurface_from(disp_width
, height
, depth
,
1643 s
->vram_ptr
+ (s
->start_addr
* 4));
1644 #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
1645 s
->ds
->surface
->pf
= qemu_different_endianness_pixelformat(depth
);
1649 qemu_console_resize(s
->ds
, disp_width
, height
);
1651 s
->last_scr_width
= disp_width
;
1652 s
->last_scr_height
= height
;
1653 s
->last_width
= disp_width
;
1654 s
->last_height
= height
;
1655 s
->last_line_offset
= s
->line_offset
;
1656 s
->last_depth
= depth
;
1658 } else if (is_buffer_shared(s
->ds
->surface
) &&
1659 (full_update
|| s
->ds
->surface
->data
!= s
->vram_ptr
+ (s
->start_addr
* 4))) {
1660 s
->ds
->surface
->data
= s
->vram_ptr
+ (s
->start_addr
* 4);
1665 rgb_to_pixel_dup_table
[get_depth_index(s
->ds
)];
1667 if (shift_control
== 0) {
1668 full_update
|= update_palette16(s
);
1669 if (s
->sr
[0x01] & 8) {
1670 v
= VGA_DRAW_LINE4D2
;
1675 } else if (shift_control
== 1) {
1676 full_update
|= update_palette16(s
);
1677 if (s
->sr
[0x01] & 8) {
1678 v
= VGA_DRAW_LINE2D2
;
1684 switch(s
->get_bpp(s
)) {
1687 full_update
|= update_palette256(s
);
1688 v
= VGA_DRAW_LINE8D2
;
1692 full_update
|= update_palette256(s
);
1697 v
= VGA_DRAW_LINE15
;
1701 v
= VGA_DRAW_LINE16
;
1705 v
= VGA_DRAW_LINE24
;
1709 v
= VGA_DRAW_LINE32
;
1714 vga_draw_line
= vga_draw_line_table
[v
* NB_DEPTHS
+ get_depth_index(s
->ds
)];
1716 if (!is_buffer_shared(s
->ds
->surface
) && s
->cursor_invalidate
)
1717 s
->cursor_invalidate(s
);
1719 line_offset
= s
->line_offset
;
1721 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",
1722 width
, height
, v
, line_offset
, s
->cr
[9], s
->cr
[0x17], s
->line_compare
, s
->sr
[0x01]);
1724 addr1
= (s
->start_addr
* 4);
1725 bwidth
= (width
* bits
+ 7) / 8;
1729 d
= ds_get_data(s
->ds
);
1730 linesize
= ds_get_linesize(s
->ds
);
1732 for(y
= 0; y
< height
; y
++) {
1734 if (!(s
->cr
[0x17] & 1)) {
1736 /* CGA compatibility handling */
1737 shift
= 14 + ((s
->cr
[0x17] >> 6) & 1);
1738 addr
= (addr
& ~(1 << shift
)) | ((y1
& 1) << shift
);
1740 if (!(s
->cr
[0x17] & 2)) {
1741 addr
= (addr
& ~0x8000) | ((y1
& 2) << 14);
1743 page0
= addr
& TARGET_PAGE_MASK
;
1744 page1
= (addr
+ bwidth
- 1) & TARGET_PAGE_MASK
;
1745 update
= full_update
|
1746 memory_region_get_dirty(&s
->vram
, page0
, DIRTY_MEMORY_VGA
) |
1747 memory_region_get_dirty(&s
->vram
, page1
, DIRTY_MEMORY_VGA
);
1748 if ((page1
- page0
) > TARGET_PAGE_SIZE
) {
1749 /* if wide line, can use another page */
1750 update
|= memory_region_get_dirty(&s
->vram
,
1751 page0
+ TARGET_PAGE_SIZE
,
1754 /* explicit invalidation for the hardware cursor */
1755 update
|= (s
->invalidated_y_table
[y
>> 5] >> (y
& 0x1f)) & 1;
1759 if (page0
< page_min
)
1761 if (page1
> page_max
)
1763 if (!(is_buffer_shared(s
->ds
->surface
))) {
1764 vga_draw_line(s
, d
, s
->vram_ptr
+ addr
, width
);
1765 if (s
->cursor_draw_line
)
1766 s
->cursor_draw_line(s
, d
, y
);
1770 /* flush to display */
1771 dpy_update(s
->ds
, 0, y_start
,
1772 disp_width
, y
- y_start
);
1777 mask
= (s
->cr
[0x17] & 3) ^ 3;
1778 if ((y1
& mask
) == mask
)
1779 addr1
+= line_offset
;
1781 multi_run
= multi_scan
;
1785 /* line compare acts on the displayed lines */
1786 if (y
== s
->line_compare
)
1791 /* flush to display */
1792 dpy_update(s
->ds
, 0, y_start
,
1793 disp_width
, y
- y_start
);
1795 /* reset modified pages */
1796 if (page_max
>= page_min
) {
1797 memory_region_reset_dirty(&s
->vram
,
1799 page_max
+ TARGET_PAGE_SIZE
- page_min
,
1802 memset(s
->invalidated_y_table
, 0, ((height
+ 31) >> 5) * 4);
1805 static void vga_draw_blank(VGACommonState
*s
, int full_update
)
1812 if (s
->last_scr_width
<= 0 || s
->last_scr_height
<= 0)
1816 rgb_to_pixel_dup_table
[get_depth_index(s
->ds
)];
1817 if (ds_get_bits_per_pixel(s
->ds
) == 8)
1818 val
= s
->rgb_to_pixel(0, 0, 0);
1821 w
= s
->last_scr_width
* ((ds_get_bits_per_pixel(s
->ds
) + 7) >> 3);
1822 d
= ds_get_data(s
->ds
);
1823 for(i
= 0; i
< s
->last_scr_height
; i
++) {
1825 d
+= ds_get_linesize(s
->ds
);
1827 dpy_update(s
->ds
, 0, 0,
1828 s
->last_scr_width
, s
->last_scr_height
);
1831 #define GMODE_TEXT 0
1832 #define GMODE_GRAPH 1
1833 #define GMODE_BLANK 2
1835 static void vga_update_display(void *opaque
)
1837 VGACommonState
*s
= opaque
;
1838 int full_update
, graphic_mode
;
1840 if (ds_get_bits_per_pixel(s
->ds
) == 0) {
1844 if (!(s
->ar_index
& 0x20)) {
1845 graphic_mode
= GMODE_BLANK
;
1847 graphic_mode
= s
->gr
[6] & 1;
1849 if (graphic_mode
!= s
->graphic_mode
) {
1850 s
->graphic_mode
= graphic_mode
;
1853 switch(graphic_mode
) {
1855 vga_draw_text(s
, full_update
);
1858 vga_draw_graphic(s
, full_update
);
1862 vga_draw_blank(s
, full_update
);
1868 /* force a full display refresh */
1869 static void vga_invalidate_display(void *opaque
)
1871 VGACommonState
*s
= opaque
;
1874 s
->last_height
= -1;
1877 void vga_common_reset(VGACommonState
*s
)
1880 memset(s
->sr
, '\0', sizeof(s
->sr
));
1882 memset(s
->gr
, '\0', sizeof(s
->gr
));
1884 memset(s
->ar
, '\0', sizeof(s
->ar
));
1885 s
->ar_flip_flop
= 0;
1887 memset(s
->cr
, '\0', sizeof(s
->cr
));
1893 s
->dac_sub_index
= 0;
1894 s
->dac_read_index
= 0;
1895 s
->dac_write_index
= 0;
1896 memset(s
->dac_cache
, '\0', sizeof(s
->dac_cache
));
1898 memset(s
->palette
, '\0', sizeof(s
->palette
));
1900 #ifdef CONFIG_BOCHS_VBE
1902 memset(s
->vbe_regs
, '\0', sizeof(s
->vbe_regs
));
1903 s
->vbe_regs
[VBE_DISPI_INDEX_ID
] = VBE_DISPI_ID5
;
1904 s
->vbe_start_addr
= 0;
1905 s
->vbe_line_offset
= 0;
1906 s
->vbe_bank_mask
= (s
->vram_size
>> 16) - 1;
1908 memset(s
->font_offsets
, '\0', sizeof(s
->font_offsets
));
1909 s
->graphic_mode
= -1; /* force full update */
1910 s
->shift_control
= 0;
1913 s
->line_compare
= 0;
1915 s
->plane_updated
= 0;
1920 s
->last_scr_width
= 0;
1921 s
->last_scr_height
= 0;
1922 s
->cursor_start
= 0;
1924 s
->cursor_offset
= 0;
1925 memset(s
->invalidated_y_table
, '\0', sizeof(s
->invalidated_y_table
));
1926 memset(s
->last_palette
, '\0', sizeof(s
->last_palette
));
1927 memset(s
->last_ch_attr
, '\0', sizeof(s
->last_ch_attr
));
1928 switch (vga_retrace_method
) {
1929 case VGA_RETRACE_DUMB
:
1931 case VGA_RETRACE_PRECISE
:
1932 memset(&s
->retrace_info
, 0, sizeof (s
->retrace_info
));
1935 vga_update_memory_access(s
);
1938 static void vga_reset(void *opaque
)
1940 VGACommonState
*s
= opaque
;
1941 vga_common_reset(s
);
1944 #define TEXTMODE_X(x) ((x) % width)
1945 #define TEXTMODE_Y(x) ((x) / width)
1946 #define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1947 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1948 /* relay text rendering to the display driver
1949 * instead of doing a full vga_update_display() */
1950 static void vga_update_text(void *opaque
, console_ch_t
*chardata
)
1952 VGACommonState
*s
= opaque
;
1953 int graphic_mode
, i
, cursor_offset
, cursor_visible
;
1954 int cw
, cheight
, width
, height
, size
, c_min
, c_max
;
1956 console_ch_t
*dst
, val
;
1957 char msg_buffer
[80];
1958 int full_update
= 0;
1960 if (!(s
->ar_index
& 0x20)) {
1961 graphic_mode
= GMODE_BLANK
;
1963 graphic_mode
= s
->gr
[6] & 1;
1965 if (graphic_mode
!= s
->graphic_mode
) {
1966 s
->graphic_mode
= graphic_mode
;
1969 if (s
->last_width
== -1) {
1974 switch (graphic_mode
) {
1976 /* TODO: update palette */
1977 full_update
|= update_basic_params(s
);
1979 /* total width & height */
1980 cheight
= (s
->cr
[9] & 0x1f) + 1;
1982 if (!(s
->sr
[1] & 0x01))
1984 if (s
->sr
[1] & 0x08)
1985 cw
= 16; /* NOTE: no 18 pixel wide */
1986 width
= (s
->cr
[0x01] + 1);
1987 if (s
->cr
[0x06] == 100) {
1988 /* ugly hack for CGA 160x100x16 - explain me the logic */
1991 height
= s
->cr
[0x12] |
1992 ((s
->cr
[0x07] & 0x02) << 7) |
1993 ((s
->cr
[0x07] & 0x40) << 3);
1994 height
= (height
+ 1) / cheight
;
1997 size
= (height
* width
);
1998 if (size
> CH_ATTR_SIZE
) {
2002 snprintf(msg_buffer
, sizeof(msg_buffer
), "%i x %i Text mode",
2007 if (width
!= s
->last_width
|| height
!= s
->last_height
||
2008 cw
!= s
->last_cw
|| cheight
!= s
->last_ch
) {
2009 s
->last_scr_width
= width
* cw
;
2010 s
->last_scr_height
= height
* cheight
;
2011 s
->ds
->surface
->width
= width
;
2012 s
->ds
->surface
->height
= height
;
2014 s
->last_width
= width
;
2015 s
->last_height
= height
;
2016 s
->last_ch
= cheight
;
2021 /* Update "hardware" cursor */
2022 cursor_offset
= ((s
->cr
[0x0e] << 8) | s
->cr
[0x0f]) - s
->start_addr
;
2023 if (cursor_offset
!= s
->cursor_offset
||
2024 s
->cr
[0xa] != s
->cursor_start
||
2025 s
->cr
[0xb] != s
->cursor_end
|| full_update
) {
2026 cursor_visible
= !(s
->cr
[0xa] & 0x20);
2027 if (cursor_visible
&& cursor_offset
< size
&& cursor_offset
>= 0)
2029 TEXTMODE_X(cursor_offset
),
2030 TEXTMODE_Y(cursor_offset
));
2032 dpy_cursor(s
->ds
, -1, -1);
2033 s
->cursor_offset
= cursor_offset
;
2034 s
->cursor_start
= s
->cr
[0xa];
2035 s
->cursor_end
= s
->cr
[0xb];
2038 src
= (uint32_t *) s
->vram_ptr
+ s
->start_addr
;
2042 for (i
= 0; i
< size
; src
++, dst
++, i
++)
2043 console_write_ch(dst
, VMEM2CHTYPE(le32_to_cpu(*src
)));
2045 dpy_update(s
->ds
, 0, 0, width
, height
);
2049 for (i
= 0; i
< size
; src
++, dst
++, i
++) {
2050 console_write_ch(&val
, VMEM2CHTYPE(le32_to_cpu(*src
)));
2058 for (; i
< size
; src
++, dst
++, i
++) {
2059 console_write_ch(&val
, VMEM2CHTYPE(le32_to_cpu(*src
)));
2066 if (c_min
<= c_max
) {
2067 i
= TEXTMODE_Y(c_min
);
2068 dpy_update(s
->ds
, 0, i
, width
, TEXTMODE_Y(c_max
) - i
+ 1);
2077 s
->get_resolution(s
, &width
, &height
);
2078 snprintf(msg_buffer
, sizeof(msg_buffer
), "%i x %i Graphic mode",
2086 snprintf(msg_buffer
, sizeof(msg_buffer
), "VGA Blank mode");
2090 /* Display a message */
2092 s
->last_height
= height
= 3;
2093 dpy_cursor(s
->ds
, -1, -1);
2094 s
->ds
->surface
->width
= s
->last_width
;
2095 s
->ds
->surface
->height
= height
;
2098 for (dst
= chardata
, i
= 0; i
< s
->last_width
* height
; i
++)
2099 console_write_ch(dst
++, ' ');
2101 size
= strlen(msg_buffer
);
2102 width
= (s
->last_width
- size
) / 2;
2103 dst
= chardata
+ s
->last_width
+ width
;
2104 for (i
= 0; i
< size
; i
++)
2105 console_write_ch(dst
++, 0x00200100 | msg_buffer
[i
]);
2107 dpy_update(s
->ds
, 0, 0, s
->last_width
, height
);
2110 static uint64_t vga_mem_read(void *opaque
, target_phys_addr_t addr
,
2113 VGACommonState
*s
= opaque
;
2115 return vga_mem_readb(s
, addr
);
2118 static void vga_mem_write(void *opaque
, target_phys_addr_t addr
,
2119 uint64_t data
, unsigned size
)
2121 VGACommonState
*s
= opaque
;
2123 return vga_mem_writeb(s
, addr
, data
);
2126 const MemoryRegionOps vga_mem_ops
= {
2127 .read
= vga_mem_read
,
2128 .write
= vga_mem_write
,
2129 .endianness
= DEVICE_LITTLE_ENDIAN
,
2131 .min_access_size
= 1,
2132 .max_access_size
= 1,
2136 static int vga_common_post_load(void *opaque
, int version_id
)
2138 VGACommonState
*s
= opaque
;
2141 s
->graphic_mode
= -1;
2145 const VMStateDescription vmstate_vga_common
= {
2148 .minimum_version_id
= 2,
2149 .minimum_version_id_old
= 2,
2150 .post_load
= vga_common_post_load
,
2151 .fields
= (VMStateField
[]) {
2152 VMSTATE_UINT32(latch
, VGACommonState
),
2153 VMSTATE_UINT8(sr_index
, VGACommonState
),
2154 VMSTATE_PARTIAL_BUFFER(sr
, VGACommonState
, 8),
2155 VMSTATE_UINT8(gr_index
, VGACommonState
),
2156 VMSTATE_PARTIAL_BUFFER(gr
, VGACommonState
, 16),
2157 VMSTATE_UINT8(ar_index
, VGACommonState
),
2158 VMSTATE_BUFFER(ar
, VGACommonState
),
2159 VMSTATE_INT32(ar_flip_flop
, VGACommonState
),
2160 VMSTATE_UINT8(cr_index
, VGACommonState
),
2161 VMSTATE_BUFFER(cr
, VGACommonState
),
2162 VMSTATE_UINT8(msr
, VGACommonState
),
2163 VMSTATE_UINT8(fcr
, VGACommonState
),
2164 VMSTATE_UINT8(st00
, VGACommonState
),
2165 VMSTATE_UINT8(st01
, VGACommonState
),
2167 VMSTATE_UINT8(dac_state
, VGACommonState
),
2168 VMSTATE_UINT8(dac_sub_index
, VGACommonState
),
2169 VMSTATE_UINT8(dac_read_index
, VGACommonState
),
2170 VMSTATE_UINT8(dac_write_index
, VGACommonState
),
2171 VMSTATE_BUFFER(dac_cache
, VGACommonState
),
2172 VMSTATE_BUFFER(palette
, VGACommonState
),
2174 VMSTATE_INT32(bank_offset
, VGACommonState
),
2175 VMSTATE_UINT8_EQUAL(is_vbe_vmstate
, VGACommonState
),
2176 #ifdef CONFIG_BOCHS_VBE
2177 VMSTATE_UINT16(vbe_index
, VGACommonState
),
2178 VMSTATE_UINT16_ARRAY(vbe_regs
, VGACommonState
, VBE_DISPI_INDEX_NB
),
2179 VMSTATE_UINT32(vbe_start_addr
, VGACommonState
),
2180 VMSTATE_UINT32(vbe_line_offset
, VGACommonState
),
2181 VMSTATE_UINT32(vbe_bank_mask
, VGACommonState
),
2183 VMSTATE_END_OF_LIST()
2187 void vga_common_init(VGACommonState
*s
, int vga_ram_size
)
2191 for(i
= 0;i
< 256; i
++) {
2193 for(j
= 0; j
< 8; j
++) {
2194 v
|= ((i
>> j
) & 1) << (j
* 4);
2199 for(j
= 0; j
< 4; j
++) {
2200 v
|= ((i
>> (2 * j
)) & 3) << (j
* 4);
2204 for(i
= 0; i
< 16; i
++) {
2206 for(j
= 0; j
< 4; j
++) {
2209 v
|= b
<< (2 * j
+ 1);
2214 #ifdef CONFIG_BOCHS_VBE
2215 s
->is_vbe_vmstate
= 1;
2217 s
->is_vbe_vmstate
= 0;
2219 memory_region_init_ram(&s
->vram
, NULL
, "vga.vram", vga_ram_size
);
2220 s
->vram_ptr
= memory_region_get_ram_ptr(&s
->vram
);
2221 s
->vram_size
= vga_ram_size
;
2222 s
->get_bpp
= vga_get_bpp
;
2223 s
->get_offsets
= vga_get_offsets
;
2224 s
->get_resolution
= vga_get_resolution
;
2225 s
->update
= vga_update_display
;
2226 s
->invalidate
= vga_invalidate_display
;
2227 s
->screen_dump
= vga_screen_dump
;
2228 s
->text_update
= vga_update_text
;
2229 switch (vga_retrace_method
) {
2230 case VGA_RETRACE_DUMB
:
2231 s
->retrace
= vga_dumb_retrace
;
2232 s
->update_retrace_info
= vga_dumb_update_retrace_info
;
2235 case VGA_RETRACE_PRECISE
:
2236 s
->retrace
= vga_precise_retrace
;
2237 s
->update_retrace_info
= vga_precise_update_retrace_info
;
2240 vga_dirty_log_start(s
);
2243 /* used by both ISA and PCI */
2244 MemoryRegion
*vga_init_io(VGACommonState
*s
)
2246 MemoryRegion
*vga_mem
;
2248 register_ioport_write(0x3c0, 16, 1, vga_ioport_write
, s
);
2250 register_ioport_write(0x3b4, 2, 1, vga_ioport_write
, s
);
2251 register_ioport_write(0x3d4, 2, 1, vga_ioport_write
, s
);
2252 register_ioport_write(0x3ba, 1, 1, vga_ioport_write
, s
);
2253 register_ioport_write(0x3da, 1, 1, vga_ioport_write
, s
);
2255 register_ioport_read(0x3c0, 16, 1, vga_ioport_read
, s
);
2257 register_ioport_read(0x3b4, 2, 1, vga_ioport_read
, s
);
2258 register_ioport_read(0x3d4, 2, 1, vga_ioport_read
, s
);
2259 register_ioport_read(0x3ba, 1, 1, vga_ioport_read
, s
);
2260 register_ioport_read(0x3da, 1, 1, vga_ioport_read
, s
);
2262 #ifdef CONFIG_BOCHS_VBE
2263 #if defined (TARGET_I386)
2264 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index
, s
);
2265 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data
, s
);
2267 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index
, s
);
2268 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data
, s
);
2270 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index
, s
);
2271 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data
, s
);
2273 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index
, s
);
2274 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data
, s
);
2276 #endif /* CONFIG_BOCHS_VBE */
2278 vga_mem
= g_malloc(sizeof(*vga_mem
));
2279 memory_region_init_io(vga_mem
, &vga_mem_ops
, s
,
2280 "vga-lowmem", 0x20000);
2285 void vga_init(VGACommonState
*s
, MemoryRegion
*address_space
)
2287 MemoryRegion
*vga_io_memory
;
2289 qemu_register_reset(vga_reset
, s
);
2293 s
->legacy_address_space
= address_space
;
2295 vga_io_memory
= vga_init_io(s
);
2296 memory_region_add_subregion_overlap(address_space
,
2297 isa_mem_base
+ 0x000a0000,
2300 memory_region_set_coalescing(vga_io_memory
);
2303 void vga_init_vbe(VGACommonState
*s
, MemoryRegion
*system_memory
)
2305 #ifdef CONFIG_BOCHS_VBE
2306 /* XXX: use optimized standard vga accesses */
2307 memory_region_add_subregion(system_memory
,
2308 VBE_DISPI_LFB_PHYSICAL_ADDRESS
,
2313 /********************************************************/
2314 /* vga screen dump */
2316 static void vga_save_dpy_update(DisplayState
*ds
,
2317 int x
, int y
, int w
, int h
)
2319 if (screen_dump_filename
) {
2320 ppm_save(screen_dump_filename
, ds
->surface
);
2321 screen_dump_filename
= NULL
;
2325 static void vga_save_dpy_resize(DisplayState
*s
)
2329 static void vga_save_dpy_refresh(DisplayState
*s
)
2333 int ppm_save(const char *filename
, struct DisplaySurface
*ds
)
2341 char *linebuf
, *pbuf
;
2343 f
= fopen(filename
, "wb");
2346 fprintf(f
, "P6\n%d %d\n%d\n",
2347 ds
->width
, ds
->height
, 255);
2348 linebuf
= g_malloc(ds
->width
* 3);
2350 for(y
= 0; y
< ds
->height
; y
++) {
2353 for(x
= 0; x
< ds
->width
; x
++) {
2354 if (ds
->pf
.bits_per_pixel
== 32)
2357 v
= (uint32_t) (*(uint16_t *)d
);
2358 r
= ((v
>> ds
->pf
.rshift
) & ds
->pf
.rmax
) * 256 /
2360 g
= ((v
>> ds
->pf
.gshift
) & ds
->pf
.gmax
) * 256 /
2362 b
= ((v
>> ds
->pf
.bshift
) & ds
->pf
.bmax
) * 256 /
2367 d
+= ds
->pf
.bytes_per_pixel
;
2370 ret
= fwrite(linebuf
, 1, pbuf
- linebuf
, f
);
2378 static DisplayChangeListener
* vga_screen_dump_init(DisplayState
*ds
)
2380 DisplayChangeListener
*dcl
;
2382 dcl
= g_malloc0(sizeof(DisplayChangeListener
));
2383 dcl
->dpy_update
= vga_save_dpy_update
;
2384 dcl
->dpy_resize
= vga_save_dpy_resize
;
2385 dcl
->dpy_refresh
= vga_save_dpy_refresh
;
2386 register_displaychangelistener(ds
, dcl
);
2390 /* save the vga display in a PPM image even if no display is
2392 static void vga_screen_dump(void *opaque
, const char *filename
)
2394 VGACommonState
*s
= opaque
;
2396 if (!screen_dump_dcl
)
2397 screen_dump_dcl
= vga_screen_dump_init(s
->ds
);
2399 screen_dump_filename
= (char *)filename
;
2400 vga_invalidate_display(s
);