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
;
183 region
= g_malloc(sizeof(*region
));
184 memory_region_init_alias(region
, "vga.chain4", &s
->vram
, offset
, size
);
185 memory_region_add_subregion_overlap(s
->legacy_address_space
, base
,
187 s
->chain4_alias
= region
;
190 memory_region_del_subregion(s
->legacy_address_space
, old_region
);
191 memory_region_destroy(old_region
);
193 s
->plane_updated
= 0xf;
197 static void vga_dumb_update_retrace_info(VGACommonState
*s
)
202 static void vga_precise_update_retrace_info(VGACommonState
*s
)
205 int hretr_start_char
;
206 int hretr_skew_chars
;
210 int vretr_start_line
;
219 const int clk_hz
[] = {25175000, 28322000, 25175000, 25175000};
220 int64_t chars_per_sec
;
221 struct vga_precise_retrace
*r
= &s
->retrace_info
.precise
;
223 htotal_chars
= s
->cr
[0x00] + 5;
224 hretr_start_char
= s
->cr
[0x04];
225 hretr_skew_chars
= (s
->cr
[0x05] >> 5) & 3;
226 hretr_end_char
= s
->cr
[0x05] & 0x1f;
228 vtotal_lines
= (s
->cr
[0x06]
229 | (((s
->cr
[0x07] & 1) | ((s
->cr
[0x07] >> 4) & 2)) << 8)) + 2
231 vretr_start_line
= s
->cr
[0x10]
232 | ((((s
->cr
[0x07] >> 2) & 1) | ((s
->cr
[0x07] >> 6) & 2)) << 8)
234 vretr_end_line
= s
->cr
[0x11] & 0xf;
238 clocking_mode
= (s
->sr
[0x01] >> 3) & 1;
239 clock_sel
= (s
->msr
>> 2) & 3;
240 dots
= (s
->msr
& 1) ? 8 : 9;
242 chars_per_sec
= clk_hz
[clock_sel
] / dots
;
244 htotal_chars
<<= clocking_mode
;
246 r
->total_chars
= vtotal_lines
* htotal_chars
;
248 r
->ticks_per_char
= get_ticks_per_sec() / (r
->total_chars
* r
->freq
);
250 r
->ticks_per_char
= get_ticks_per_sec() / chars_per_sec
;
253 r
->vstart
= vretr_start_line
;
254 r
->vend
= r
->vstart
+ vretr_end_line
+ 1;
256 r
->hstart
= hretr_start_char
+ hretr_skew_chars
;
257 r
->hend
= r
->hstart
+ hretr_end_char
+ 1;
258 r
->htotal
= htotal_chars
;
261 div2
= (s
->cr
[0x17] >> 2) & 1;
262 sldiv2
= (s
->cr
[0x17] >> 3) & 1;
272 "div2 = %d sldiv2 = %d\n"
273 "clocking_mode = %d\n"
274 "clock_sel = %d %d\n"
276 "ticks/char = %" PRId64
"\n"
278 (double) get_ticks_per_sec() / (r
->ticks_per_char
* r
->total_chars
),
296 static uint8_t vga_precise_retrace(VGACommonState
*s
)
298 struct vga_precise_retrace
*r
= &s
->retrace_info
.precise
;
299 uint8_t val
= s
->st01
& ~(ST01_V_RETRACE
| ST01_DISP_ENABLE
);
301 if (r
->total_chars
) {
302 int cur_line
, cur_line_char
, cur_char
;
305 cur_tick
= qemu_get_clock_ns(vm_clock
);
307 cur_char
= (cur_tick
/ r
->ticks_per_char
) % r
->total_chars
;
308 cur_line
= cur_char
/ r
->htotal
;
310 if (cur_line
>= r
->vstart
&& cur_line
<= r
->vend
) {
311 val
|= ST01_V_RETRACE
| ST01_DISP_ENABLE
;
313 cur_line_char
= cur_char
% r
->htotal
;
314 if (cur_line_char
>= r
->hstart
&& cur_line_char
<= r
->hend
) {
315 val
|= ST01_DISP_ENABLE
;
321 return s
->st01
^ (ST01_V_RETRACE
| ST01_DISP_ENABLE
);
325 static uint8_t vga_dumb_retrace(VGACommonState
*s
)
327 return s
->st01
^ (ST01_V_RETRACE
| ST01_DISP_ENABLE
);
330 int vga_ioport_invalid(VGACommonState
*s
, uint32_t addr
)
332 if (s
->msr
& MSR_COLOR_EMULATION
) {
334 return (addr
>= 0x3b0 && addr
<= 0x3bf);
337 return (addr
>= 0x3d0 && addr
<= 0x3df);
341 uint32_t vga_ioport_read(void *opaque
, uint32_t addr
)
343 VGACommonState
*s
= opaque
;
346 if (vga_ioport_invalid(s
, addr
)) {
351 if (s
->ar_flip_flop
== 0) {
358 index
= s
->ar_index
& 0x1f;
371 val
= s
->sr
[s
->sr_index
];
373 printf("vga: read SR%x = 0x%02x\n", s
->sr_index
, val
);
380 val
= s
->dac_write_index
;
383 val
= s
->palette
[s
->dac_read_index
* 3 + s
->dac_sub_index
];
384 if (++s
->dac_sub_index
== 3) {
385 s
->dac_sub_index
= 0;
399 val
= s
->gr
[s
->gr_index
];
401 printf("vga: read GR%x = 0x%02x\n", s
->gr_index
, val
);
410 val
= s
->cr
[s
->cr_index
];
412 printf("vga: read CR%x = 0x%02x\n", s
->cr_index
, val
);
417 /* just toggle to fool polling */
418 val
= s
->st01
= s
->retrace(s
);
426 #if defined(DEBUG_VGA)
427 printf("VGA: read addr=0x%04x data=0x%02x\n", addr
, val
);
432 void vga_ioport_write(void *opaque
, uint32_t addr
, uint32_t val
)
434 VGACommonState
*s
= opaque
;
437 /* check port range access depending on color/monochrome mode */
438 if (vga_ioport_invalid(s
, addr
)) {
442 printf("VGA: write addr=0x%04x data=0x%02x\n", addr
, val
);
447 if (s
->ar_flip_flop
== 0) {
451 index
= s
->ar_index
& 0x1f;
454 s
->ar
[index
] = val
& 0x3f;
457 s
->ar
[index
] = val
& ~0x10;
463 s
->ar
[index
] = val
& ~0xc0;
466 s
->ar
[index
] = val
& ~0xf0;
469 s
->ar
[index
] = val
& ~0xf0;
475 s
->ar_flip_flop
^= 1;
478 s
->msr
= val
& ~0x10;
479 s
->update_retrace_info(s
);
482 s
->sr_index
= val
& 7;
486 printf("vga: write SR%x = 0x%02x\n", s
->sr_index
, val
);
488 s
->sr
[s
->sr_index
] = val
& sr_mask
[s
->sr_index
];
489 if (s
->sr_index
== 1) s
->update_retrace_info(s
);
490 vga_update_memory_access(s
);
493 s
->dac_read_index
= val
;
494 s
->dac_sub_index
= 0;
498 s
->dac_write_index
= val
;
499 s
->dac_sub_index
= 0;
503 s
->dac_cache
[s
->dac_sub_index
] = val
;
504 if (++s
->dac_sub_index
== 3) {
505 memcpy(&s
->palette
[s
->dac_write_index
* 3], s
->dac_cache
, 3);
506 s
->dac_sub_index
= 0;
507 s
->dac_write_index
++;
511 s
->gr_index
= val
& 0x0f;
515 printf("vga: write GR%x = 0x%02x\n", s
->gr_index
, val
);
517 s
->gr
[s
->gr_index
] = val
& gr_mask
[s
->gr_index
];
518 vga_update_memory_access(s
);
527 printf("vga: write CR%x = 0x%02x\n", s
->cr_index
, val
);
529 /* handle CR0-7 protection */
530 if ((s
->cr
[0x11] & 0x80) && s
->cr_index
<= 7) {
531 /* can always write bit 4 of CR7 */
532 if (s
->cr_index
== 7)
533 s
->cr
[7] = (s
->cr
[7] & ~0x10) | (val
& 0x10);
536 s
->cr
[s
->cr_index
] = val
;
538 switch(s
->cr_index
) {
546 s
->update_retrace_info(s
);
557 #ifdef CONFIG_BOCHS_VBE
558 static uint32_t vbe_ioport_read_index(void *opaque
, uint32_t addr
)
560 VGACommonState
*s
= opaque
;
566 static uint32_t vbe_ioport_read_data(void *opaque
, uint32_t addr
)
568 VGACommonState
*s
= opaque
;
571 if (s
->vbe_index
< VBE_DISPI_INDEX_NB
) {
572 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_GETCAPS
) {
573 switch(s
->vbe_index
) {
574 /* XXX: do not hardcode ? */
575 case VBE_DISPI_INDEX_XRES
:
576 val
= VBE_DISPI_MAX_XRES
;
578 case VBE_DISPI_INDEX_YRES
:
579 val
= VBE_DISPI_MAX_YRES
;
581 case VBE_DISPI_INDEX_BPP
:
582 val
= VBE_DISPI_MAX_BPP
;
585 val
= s
->vbe_regs
[s
->vbe_index
];
589 val
= s
->vbe_regs
[s
->vbe_index
];
591 } else if (s
->vbe_index
== VBE_DISPI_INDEX_VIDEO_MEMORY_64K
) {
592 val
= s
->vram_size
/ (64 * 1024);
596 #ifdef DEBUG_BOCHS_VBE
597 printf("VBE: read index=0x%x val=0x%x\n", s
->vbe_index
, val
);
602 static void vbe_ioport_write_index(void *opaque
, uint32_t addr
, uint32_t val
)
604 VGACommonState
*s
= opaque
;
608 static void vbe_ioport_write_data(void *opaque
, uint32_t addr
, uint32_t val
)
610 VGACommonState
*s
= opaque
;
612 if (s
->vbe_index
<= VBE_DISPI_INDEX_NB
) {
613 #ifdef DEBUG_BOCHS_VBE
614 printf("VBE: write index=0x%x val=0x%x\n", s
->vbe_index
, val
);
616 switch(s
->vbe_index
) {
617 case VBE_DISPI_INDEX_ID
:
618 if (val
== VBE_DISPI_ID0
||
619 val
== VBE_DISPI_ID1
||
620 val
== VBE_DISPI_ID2
||
621 val
== VBE_DISPI_ID3
||
622 val
== VBE_DISPI_ID4
) {
623 s
->vbe_regs
[s
->vbe_index
] = val
;
626 case VBE_DISPI_INDEX_XRES
:
627 if ((val
<= VBE_DISPI_MAX_XRES
) && ((val
& 7) == 0)) {
628 s
->vbe_regs
[s
->vbe_index
] = val
;
631 case VBE_DISPI_INDEX_YRES
:
632 if (val
<= VBE_DISPI_MAX_YRES
) {
633 s
->vbe_regs
[s
->vbe_index
] = val
;
636 case VBE_DISPI_INDEX_BPP
:
639 if (val
== 4 || val
== 8 || val
== 15 ||
640 val
== 16 || val
== 24 || val
== 32) {
641 s
->vbe_regs
[s
->vbe_index
] = val
;
644 case VBE_DISPI_INDEX_BANK
:
645 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
646 val
&= (s
->vbe_bank_mask
>> 2);
648 val
&= s
->vbe_bank_mask
;
650 s
->vbe_regs
[s
->vbe_index
] = val
;
651 s
->bank_offset
= (val
<< 16);
652 vga_update_memory_access(s
);
654 case VBE_DISPI_INDEX_ENABLE
:
655 if ((val
& VBE_DISPI_ENABLED
) &&
656 !(s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
)) {
657 int h
, shift_control
;
659 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] =
660 s
->vbe_regs
[VBE_DISPI_INDEX_XRES
];
661 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_HEIGHT
] =
662 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
];
663 s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
] = 0;
664 s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
] = 0;
666 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
667 s
->vbe_line_offset
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 1;
669 s
->vbe_line_offset
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] *
670 ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
671 s
->vbe_start_addr
= 0;
673 /* clear the screen (should be done in BIOS) */
674 if (!(val
& VBE_DISPI_NOCLEARMEM
)) {
675 memset(s
->vram_ptr
, 0,
676 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] * s
->vbe_line_offset
);
679 /* we initialize the VGA graphic mode (should be done
681 s
->gr
[0x06] = (s
->gr
[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
682 s
->cr
[0x17] |= 3; /* no CGA modes */
683 s
->cr
[0x13] = s
->vbe_line_offset
>> 3;
685 s
->cr
[0x01] = (s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 3) - 1;
686 /* height (only meaningful if < 1024) */
687 h
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] - 1;
689 s
->cr
[0x07] = (s
->cr
[0x07] & ~0x42) |
690 ((h
>> 7) & 0x02) | ((h
>> 3) & 0x40);
691 /* line compare to 1023 */
696 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
698 s
->sr
[0x01] &= ~8; /* no double line */
701 s
->sr
[4] |= 0x08; /* set chain 4 mode */
702 s
->sr
[2] |= 0x0f; /* activate all planes */
704 s
->gr
[0x05] = (s
->gr
[0x05] & ~0x60) | (shift_control
<< 5);
705 s
->cr
[0x09] &= ~0x9f; /* no double scan */
707 /* XXX: the bios should do that */
710 s
->dac_8bit
= (val
& VBE_DISPI_8BIT_DAC
) > 0;
711 s
->vbe_regs
[s
->vbe_index
] = val
;
712 vga_update_memory_access(s
);
714 case VBE_DISPI_INDEX_VIRT_WIDTH
:
716 int w
, h
, line_offset
;
718 if (val
< s
->vbe_regs
[VBE_DISPI_INDEX_XRES
])
721 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
722 line_offset
= w
>> 1;
724 line_offset
= w
* ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
725 h
= s
->vram_size
/ line_offset
;
726 /* XXX: support weird bochs semantics ? */
727 if (h
< s
->vbe_regs
[VBE_DISPI_INDEX_YRES
])
729 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] = w
;
730 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_HEIGHT
] = h
;
731 s
->vbe_line_offset
= line_offset
;
734 case VBE_DISPI_INDEX_X_OFFSET
:
735 case VBE_DISPI_INDEX_Y_OFFSET
:
738 s
->vbe_regs
[s
->vbe_index
] = val
;
739 s
->vbe_start_addr
= s
->vbe_line_offset
* s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
];
740 x
= s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
];
741 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
742 s
->vbe_start_addr
+= x
>> 1;
744 s
->vbe_start_addr
+= x
* ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
745 s
->vbe_start_addr
>>= 2;
755 /* called for accesses between 0xa0000 and 0xc0000 */
756 uint32_t vga_mem_readb(VGACommonState
*s
, target_phys_addr_t addr
)
758 int memory_map_mode
, plane
;
761 /* convert to VGA memory offset */
762 memory_map_mode
= (s
->gr
[6] >> 2) & 3;
764 switch(memory_map_mode
) {
770 addr
+= s
->bank_offset
;
785 if (s
->sr
[4] & 0x08) {
786 /* chain 4 mode : simplest access */
787 ret
= s
->vram_ptr
[addr
];
788 } else if (s
->gr
[5] & 0x10) {
789 /* odd/even mode (aka text mode mapping) */
790 plane
= (s
->gr
[4] & 2) | (addr
& 1);
791 ret
= s
->vram_ptr
[((addr
& ~1) << 1) | plane
];
793 /* standard VGA latched access */
794 s
->latch
= ((uint32_t *)s
->vram_ptr
)[addr
];
796 if (!(s
->gr
[5] & 0x08)) {
799 ret
= GET_PLANE(s
->latch
, plane
);
802 ret
= (s
->latch
^ mask16
[s
->gr
[2]]) & mask16
[s
->gr
[7]];
811 /* called for accesses between 0xa0000 and 0xc0000 */
812 void vga_mem_writeb(VGACommonState
*s
, target_phys_addr_t addr
, uint32_t val
)
814 int memory_map_mode
, plane
, write_mode
, b
, func_select
, mask
;
815 uint32_t write_mask
, bit_mask
, set_mask
;
818 printf("vga: [0x" TARGET_FMT_plx
"] = 0x%02x\n", addr
, val
);
820 /* convert to VGA memory offset */
821 memory_map_mode
= (s
->gr
[6] >> 2) & 3;
823 switch(memory_map_mode
) {
829 addr
+= s
->bank_offset
;
844 if (s
->sr
[4] & 0x08) {
845 /* chain 4 mode : simplest access */
848 if (s
->sr
[2] & mask
) {
849 s
->vram_ptr
[addr
] = val
;
851 printf("vga: chain4: [0x" TARGET_FMT_plx
"]\n", addr
);
853 s
->plane_updated
|= mask
; /* only used to detect font change */
854 memory_region_set_dirty(&s
->vram
, addr
);
856 } else if (s
->gr
[5] & 0x10) {
857 /* odd/even mode (aka text mode mapping) */
858 plane
= (s
->gr
[4] & 2) | (addr
& 1);
860 if (s
->sr
[2] & mask
) {
861 addr
= ((addr
& ~1) << 1) | plane
;
862 s
->vram_ptr
[addr
] = val
;
864 printf("vga: odd/even: [0x" TARGET_FMT_plx
"]\n", addr
);
866 s
->plane_updated
|= mask
; /* only used to detect font change */
867 memory_region_set_dirty(&s
->vram
, addr
);
870 /* standard VGA latched access */
871 write_mode
= s
->gr
[5] & 3;
877 val
= ((val
>> b
) | (val
<< (8 - b
))) & 0xff;
881 /* apply set/reset mask */
882 set_mask
= mask16
[s
->gr
[1]];
883 val
= (val
& ~set_mask
) | (mask16
[s
->gr
[0]] & set_mask
);
890 val
= mask16
[val
& 0x0f];
896 val
= (val
>> b
) | (val
<< (8 - b
));
898 bit_mask
= s
->gr
[8] & val
;
899 val
= mask16
[s
->gr
[0]];
903 /* apply logical operation */
904 func_select
= s
->gr
[3] >> 3;
905 switch(func_select
) {
925 bit_mask
|= bit_mask
<< 8;
926 bit_mask
|= bit_mask
<< 16;
927 val
= (val
& bit_mask
) | (s
->latch
& ~bit_mask
);
930 /* mask data according to sr[2] */
932 s
->plane_updated
|= mask
; /* only used to detect font change */
933 write_mask
= mask16
[mask
];
934 ((uint32_t *)s
->vram_ptr
)[addr
] =
935 (((uint32_t *)s
->vram_ptr
)[addr
] & ~write_mask
) |
938 printf("vga: latch: [0x" TARGET_FMT_plx
"] mask=0x%08x val=0x%08x\n",
939 addr
* 4, write_mask
, val
);
941 memory_region_set_dirty(&s
->vram
, addr
<< 2);
945 typedef void vga_draw_glyph8_func(uint8_t *d
, int linesize
,
946 const uint8_t *font_ptr
, int h
,
947 uint32_t fgcol
, uint32_t bgcol
);
948 typedef void vga_draw_glyph9_func(uint8_t *d
, int linesize
,
949 const uint8_t *font_ptr
, int h
,
950 uint32_t fgcol
, uint32_t bgcol
, int dup9
);
951 typedef void vga_draw_line_func(VGACommonState
*s1
, uint8_t *d
,
952 const uint8_t *s
, int width
);
955 #include "vga_template.h"
958 #include "vga_template.h"
962 #include "vga_template.h"
965 #include "vga_template.h"
969 #include "vga_template.h"
972 #include "vga_template.h"
976 #include "vga_template.h"
978 static unsigned int rgb_to_pixel8_dup(unsigned int r
, unsigned int g
, unsigned b
)
981 col
= rgb_to_pixel8(r
, g
, b
);
987 static unsigned int rgb_to_pixel15_dup(unsigned int r
, unsigned int g
, unsigned b
)
990 col
= rgb_to_pixel15(r
, g
, b
);
995 static unsigned int rgb_to_pixel15bgr_dup(unsigned int r
, unsigned int g
,
999 col
= rgb_to_pixel15bgr(r
, g
, b
);
1004 static unsigned int rgb_to_pixel16_dup(unsigned int r
, unsigned int g
, unsigned b
)
1007 col
= rgb_to_pixel16(r
, g
, b
);
1012 static unsigned int rgb_to_pixel16bgr_dup(unsigned int r
, unsigned int g
,
1016 col
= rgb_to_pixel16bgr(r
, g
, b
);
1021 static unsigned int rgb_to_pixel32_dup(unsigned int r
, unsigned int g
, unsigned b
)
1024 col
= rgb_to_pixel32(r
, g
, b
);
1028 static unsigned int rgb_to_pixel32bgr_dup(unsigned int r
, unsigned int g
, unsigned b
)
1031 col
= rgb_to_pixel32bgr(r
, g
, b
);
1035 /* return true if the palette was modified */
1036 static int update_palette16(VGACommonState
*s
)
1039 uint32_t v
, col
, *palette
;
1042 palette
= s
->last_palette
;
1043 for(i
= 0; i
< 16; i
++) {
1045 if (s
->ar
[0x10] & 0x80)
1046 v
= ((s
->ar
[0x14] & 0xf) << 4) | (v
& 0xf);
1048 v
= ((s
->ar
[0x14] & 0xc) << 4) | (v
& 0x3f);
1050 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
1051 c6_to_8(s
->palette
[v
+ 1]),
1052 c6_to_8(s
->palette
[v
+ 2]));
1053 if (col
!= palette
[i
]) {
1061 /* return true if the palette was modified */
1062 static int update_palette256(VGACommonState
*s
)
1065 uint32_t v
, col
, *palette
;
1068 palette
= s
->last_palette
;
1070 for(i
= 0; i
< 256; i
++) {
1072 col
= s
->rgb_to_pixel(s
->palette
[v
],
1076 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
1077 c6_to_8(s
->palette
[v
+ 1]),
1078 c6_to_8(s
->palette
[v
+ 2]));
1080 if (col
!= palette
[i
]) {
1089 static void vga_get_offsets(VGACommonState
*s
,
1090 uint32_t *pline_offset
,
1091 uint32_t *pstart_addr
,
1092 uint32_t *pline_compare
)
1094 uint32_t start_addr
, line_offset
, line_compare
;
1095 #ifdef CONFIG_BOCHS_VBE
1096 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1097 line_offset
= s
->vbe_line_offset
;
1098 start_addr
= s
->vbe_start_addr
;
1099 line_compare
= 65535;
1103 /* compute line_offset in bytes */
1104 line_offset
= s
->cr
[0x13];
1107 /* starting address */
1108 start_addr
= s
->cr
[0x0d] | (s
->cr
[0x0c] << 8);
1111 line_compare
= s
->cr
[0x18] |
1112 ((s
->cr
[0x07] & 0x10) << 4) |
1113 ((s
->cr
[0x09] & 0x40) << 3);
1115 *pline_offset
= line_offset
;
1116 *pstart_addr
= start_addr
;
1117 *pline_compare
= line_compare
;
1120 /* update start_addr and line_offset. Return TRUE if modified */
1121 static int update_basic_params(VGACommonState
*s
)
1124 uint32_t start_addr
, line_offset
, line_compare
;
1128 s
->get_offsets(s
, &line_offset
, &start_addr
, &line_compare
);
1130 if (line_offset
!= s
->line_offset
||
1131 start_addr
!= s
->start_addr
||
1132 line_compare
!= s
->line_compare
) {
1133 s
->line_offset
= line_offset
;
1134 s
->start_addr
= start_addr
;
1135 s
->line_compare
= line_compare
;
1143 static inline int get_depth_index(DisplayState
*s
)
1145 switch(ds_get_bits_per_pixel(s
)) {
1154 if (is_surface_bgr(s
->surface
))
1161 static vga_draw_glyph8_func
* const vga_draw_glyph8_table
[NB_DEPTHS
] = {
1171 static vga_draw_glyph8_func
* const vga_draw_glyph16_table
[NB_DEPTHS
] = {
1173 vga_draw_glyph16_16
,
1174 vga_draw_glyph16_16
,
1175 vga_draw_glyph16_32
,
1176 vga_draw_glyph16_32
,
1177 vga_draw_glyph16_16
,
1178 vga_draw_glyph16_16
,
1181 static vga_draw_glyph9_func
* const vga_draw_glyph9_table
[NB_DEPTHS
] = {
1191 static const uint8_t cursor_glyph
[32 * 4] = {
1192 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
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,
1210 static void vga_get_text_resolution(VGACommonState
*s
, int *pwidth
, int *pheight
,
1211 int *pcwidth
, int *pcheight
)
1213 int width
, cwidth
, height
, cheight
;
1215 /* total width & height */
1216 cheight
= (s
->cr
[9] & 0x1f) + 1;
1218 if (!(s
->sr
[1] & 0x01))
1220 if (s
->sr
[1] & 0x08)
1221 cwidth
= 16; /* NOTE: no 18 pixel wide */
1222 width
= (s
->cr
[0x01] + 1);
1223 if (s
->cr
[0x06] == 100) {
1224 /* ugly hack for CGA 160x100x16 - explain me the logic */
1227 height
= s
->cr
[0x12] |
1228 ((s
->cr
[0x07] & 0x02) << 7) |
1229 ((s
->cr
[0x07] & 0x40) << 3);
1230 height
= (height
+ 1) / cheight
;
1236 *pcheight
= cheight
;
1239 typedef unsigned int rgb_to_pixel_dup_func(unsigned int r
, unsigned int g
, unsigned b
);
1241 static rgb_to_pixel_dup_func
* const rgb_to_pixel_dup_table
[NB_DEPTHS
] = {
1246 rgb_to_pixel32bgr_dup
,
1247 rgb_to_pixel15bgr_dup
,
1248 rgb_to_pixel16bgr_dup
,
1259 static void vga_draw_text(VGACommonState
*s
, int full_update
)
1261 int cx
, cy
, cheight
, cw
, ch
, cattr
, height
, width
, ch_attr
;
1262 int cx_min
, cx_max
, linesize
, x_incr
, line
, line1
;
1263 uint32_t offset
, fgcol
, bgcol
, v
, cursor_offset
;
1264 uint8_t *d1
, *d
, *src
, *dest
, *cursor_ptr
;
1265 const uint8_t *font_ptr
, *font_base
[2];
1266 int dup9
, line_offset
, depth_index
;
1268 uint32_t *ch_attr_ptr
;
1269 vga_draw_glyph8_func
*vga_draw_glyph8
;
1270 vga_draw_glyph9_func
*vga_draw_glyph9
;
1272 /* compute font data address (in plane 2) */
1274 offset
= (((v
>> 4) & 1) | ((v
<< 1) & 6)) * 8192 * 4 + 2;
1275 if (offset
!= s
->font_offsets
[0]) {
1276 s
->font_offsets
[0] = offset
;
1279 font_base
[0] = s
->vram_ptr
+ offset
;
1281 offset
= (((v
>> 5) & 1) | ((v
>> 1) & 6)) * 8192 * 4 + 2;
1282 font_base
[1] = s
->vram_ptr
+ offset
;
1283 if (offset
!= s
->font_offsets
[1]) {
1284 s
->font_offsets
[1] = offset
;
1287 if (s
->plane_updated
& (1 << 2) || s
->chain4_alias
) {
1288 /* if the plane 2 was modified since the last display, it
1289 indicates the font may have been modified */
1290 s
->plane_updated
= 0;
1293 full_update
|= update_basic_params(s
);
1295 line_offset
= s
->line_offset
;
1297 vga_get_text_resolution(s
, &width
, &height
, &cw
, &cheight
);
1298 if ((height
* width
) > CH_ATTR_SIZE
) {
1299 /* better than nothing: exit if transient size is too big */
1303 if (width
!= s
->last_width
|| height
!= s
->last_height
||
1304 cw
!= s
->last_cw
|| cheight
!= s
->last_ch
|| s
->last_depth
) {
1305 s
->last_scr_width
= width
* cw
;
1306 s
->last_scr_height
= height
* cheight
;
1307 qemu_console_resize(s
->ds
, s
->last_scr_width
, s
->last_scr_height
);
1309 s
->last_width
= width
;
1310 s
->last_height
= height
;
1311 s
->last_ch
= cheight
;
1316 rgb_to_pixel_dup_table
[get_depth_index(s
->ds
)];
1317 full_update
|= update_palette16(s
);
1318 palette
= s
->last_palette
;
1319 x_incr
= cw
* ((ds_get_bits_per_pixel(s
->ds
) + 7) >> 3);
1321 cursor_offset
= ((s
->cr
[0x0e] << 8) | s
->cr
[0x0f]) - s
->start_addr
;
1322 if (cursor_offset
!= s
->cursor_offset
||
1323 s
->cr
[0xa] != s
->cursor_start
||
1324 s
->cr
[0xb] != s
->cursor_end
) {
1325 /* if the cursor position changed, we update the old and new
1327 if (s
->cursor_offset
< CH_ATTR_SIZE
)
1328 s
->last_ch_attr
[s
->cursor_offset
] = -1;
1329 if (cursor_offset
< CH_ATTR_SIZE
)
1330 s
->last_ch_attr
[cursor_offset
] = -1;
1331 s
->cursor_offset
= cursor_offset
;
1332 s
->cursor_start
= s
->cr
[0xa];
1333 s
->cursor_end
= s
->cr
[0xb];
1335 cursor_ptr
= s
->vram_ptr
+ (s
->start_addr
+ cursor_offset
) * 4;
1337 depth_index
= get_depth_index(s
->ds
);
1339 vga_draw_glyph8
= vga_draw_glyph16_table
[depth_index
];
1341 vga_draw_glyph8
= vga_draw_glyph8_table
[depth_index
];
1342 vga_draw_glyph9
= vga_draw_glyph9_table
[depth_index
];
1344 dest
= ds_get_data(s
->ds
);
1345 linesize
= ds_get_linesize(s
->ds
);
1346 ch_attr_ptr
= s
->last_ch_attr
;
1348 offset
= s
->start_addr
* 4;
1349 for(cy
= 0; cy
< height
; cy
++) {
1351 src
= s
->vram_ptr
+ offset
;
1354 for(cx
= 0; cx
< width
; cx
++) {
1355 ch_attr
= *(uint16_t *)src
;
1356 if (full_update
|| ch_attr
!= *ch_attr_ptr
) {
1361 *ch_attr_ptr
= ch_attr
;
1362 #ifdef HOST_WORDS_BIGENDIAN
1364 cattr
= ch_attr
& 0xff;
1366 ch
= ch_attr
& 0xff;
1367 cattr
= ch_attr
>> 8;
1369 font_ptr
= font_base
[(cattr
>> 3) & 1];
1370 font_ptr
+= 32 * 4 * ch
;
1371 bgcol
= palette
[cattr
>> 4];
1372 fgcol
= palette
[cattr
& 0x0f];
1374 vga_draw_glyph8(d1
, linesize
,
1375 font_ptr
, cheight
, fgcol
, bgcol
);
1378 if (ch
>= 0xb0 && ch
<= 0xdf && (s
->ar
[0x10] & 0x04))
1380 vga_draw_glyph9(d1
, linesize
,
1381 font_ptr
, cheight
, fgcol
, bgcol
, dup9
);
1383 if (src
== cursor_ptr
&&
1384 !(s
->cr
[0x0a] & 0x20)) {
1385 int line_start
, line_last
, h
;
1386 /* draw the cursor */
1387 line_start
= s
->cr
[0x0a] & 0x1f;
1388 line_last
= s
->cr
[0x0b] & 0x1f;
1389 /* XXX: check that */
1390 if (line_last
> cheight
- 1)
1391 line_last
= cheight
- 1;
1392 if (line_last
>= line_start
&& line_start
< cheight
) {
1393 h
= line_last
- line_start
+ 1;
1394 d
= d1
+ linesize
* line_start
;
1396 vga_draw_glyph8(d
, linesize
,
1397 cursor_glyph
, h
, fgcol
, bgcol
);
1399 vga_draw_glyph9(d
, linesize
,
1400 cursor_glyph
, h
, fgcol
, bgcol
, 1);
1410 dpy_update(s
->ds
, cx_min
* cw
, cy
* cheight
,
1411 (cx_max
- cx_min
+ 1) * cw
, cheight
);
1413 dest
+= linesize
* cheight
;
1414 line1
= line
+ cheight
;
1415 offset
+= line_offset
;
1416 if (line
< s
->line_compare
&& line1
>= s
->line_compare
) {
1437 static vga_draw_line_func
* const vga_draw_line_table
[NB_DEPTHS
* VGA_DRAW_LINE_NB
] = {
1447 vga_draw_line2d2_16
,
1448 vga_draw_line2d2_16
,
1449 vga_draw_line2d2_32
,
1450 vga_draw_line2d2_32
,
1451 vga_draw_line2d2_16
,
1452 vga_draw_line2d2_16
,
1463 vga_draw_line4d2_16
,
1464 vga_draw_line4d2_16
,
1465 vga_draw_line4d2_32
,
1466 vga_draw_line4d2_32
,
1467 vga_draw_line4d2_16
,
1468 vga_draw_line4d2_16
,
1471 vga_draw_line8d2_16
,
1472 vga_draw_line8d2_16
,
1473 vga_draw_line8d2_32
,
1474 vga_draw_line8d2_32
,
1475 vga_draw_line8d2_16
,
1476 vga_draw_line8d2_16
,
1490 vga_draw_line15_32bgr
,
1491 vga_draw_line15_15bgr
,
1492 vga_draw_line15_16bgr
,
1498 vga_draw_line16_32bgr
,
1499 vga_draw_line16_15bgr
,
1500 vga_draw_line16_16bgr
,
1506 vga_draw_line24_32bgr
,
1507 vga_draw_line24_15bgr
,
1508 vga_draw_line24_16bgr
,
1514 vga_draw_line32_32bgr
,
1515 vga_draw_line32_15bgr
,
1516 vga_draw_line32_16bgr
,
1519 static int vga_get_bpp(VGACommonState
*s
)
1522 #ifdef CONFIG_BOCHS_VBE
1523 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1524 ret
= s
->vbe_regs
[VBE_DISPI_INDEX_BPP
];
1533 static void vga_get_resolution(VGACommonState
*s
, int *pwidth
, int *pheight
)
1537 #ifdef CONFIG_BOCHS_VBE
1538 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1539 width
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
];
1540 height
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
];
1544 width
= (s
->cr
[0x01] + 1) * 8;
1545 height
= s
->cr
[0x12] |
1546 ((s
->cr
[0x07] & 0x02) << 7) |
1547 ((s
->cr
[0x07] & 0x40) << 3);
1548 height
= (height
+ 1);
1554 void vga_invalidate_scanlines(VGACommonState
*s
, int y1
, int y2
)
1557 if (y1
>= VGA_MAX_HEIGHT
)
1559 if (y2
>= VGA_MAX_HEIGHT
)
1560 y2
= VGA_MAX_HEIGHT
;
1561 for(y
= y1
; y
< y2
; y
++) {
1562 s
->invalidated_y_table
[y
>> 5] |= 1 << (y
& 0x1f);
1566 static void vga_sync_dirty_bitmap(VGACommonState
*s
)
1568 memory_region_sync_dirty_bitmap(&s
->vram
);
1571 void vga_dirty_log_start(VGACommonState
*s
)
1573 memory_region_set_log(&s
->vram
, true, DIRTY_MEMORY_VGA
);
1576 void vga_dirty_log_stop(VGACommonState
*s
)
1578 memory_region_set_log(&s
->vram
, false, DIRTY_MEMORY_VGA
);
1584 static void vga_draw_graphic(VGACommonState
*s
, int full_update
)
1586 int y1
, y
, update
, linesize
, y_start
, double_scan
, mask
, depth
;
1587 int width
, height
, shift_control
, line_offset
, bwidth
, bits
;
1588 ram_addr_t page0
, page1
, page_min
, page_max
;
1589 int disp_width
, multi_scan
, multi_run
;
1591 uint32_t v
, addr1
, addr
;
1592 vga_draw_line_func
*vga_draw_line
;
1594 full_update
|= update_basic_params(s
);
1597 vga_sync_dirty_bitmap(s
);
1599 s
->get_resolution(s
, &width
, &height
);
1602 shift_control
= (s
->gr
[0x05] >> 5) & 3;
1603 double_scan
= (s
->cr
[0x09] >> 7);
1604 if (shift_control
!= 1) {
1605 multi_scan
= (((s
->cr
[0x09] & 0x1f) + 1) << double_scan
) - 1;
1607 /* in CGA modes, multi_scan is ignored */
1608 /* XXX: is it correct ? */
1609 multi_scan
= double_scan
;
1611 multi_run
= multi_scan
;
1612 if (shift_control
!= s
->shift_control
||
1613 double_scan
!= s
->double_scan
) {
1615 s
->shift_control
= shift_control
;
1616 s
->double_scan
= double_scan
;
1619 if (shift_control
== 0) {
1620 if (s
->sr
[0x01] & 8) {
1623 } else if (shift_control
== 1) {
1624 if (s
->sr
[0x01] & 8) {
1629 depth
= s
->get_bpp(s
);
1630 if (s
->line_offset
!= s
->last_line_offset
||
1631 disp_width
!= s
->last_width
||
1632 height
!= s
->last_height
||
1633 s
->last_depth
!= depth
) {
1634 #if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
1635 if (depth
== 16 || depth
== 32) {
1639 qemu_free_displaysurface(s
->ds
);
1640 s
->ds
->surface
= qemu_create_displaysurface_from(disp_width
, height
, depth
,
1642 s
->vram_ptr
+ (s
->start_addr
* 4));
1643 #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
1644 s
->ds
->surface
->pf
= qemu_different_endianness_pixelformat(depth
);
1648 qemu_console_resize(s
->ds
, disp_width
, height
);
1650 s
->last_scr_width
= disp_width
;
1651 s
->last_scr_height
= height
;
1652 s
->last_width
= disp_width
;
1653 s
->last_height
= height
;
1654 s
->last_line_offset
= s
->line_offset
;
1655 s
->last_depth
= depth
;
1657 } else if (is_buffer_shared(s
->ds
->surface
) &&
1658 (full_update
|| s
->ds
->surface
->data
!= s
->vram_ptr
+ (s
->start_addr
* 4))) {
1659 s
->ds
->surface
->data
= s
->vram_ptr
+ (s
->start_addr
* 4);
1664 rgb_to_pixel_dup_table
[get_depth_index(s
->ds
)];
1666 if (shift_control
== 0) {
1667 full_update
|= update_palette16(s
);
1668 if (s
->sr
[0x01] & 8) {
1669 v
= VGA_DRAW_LINE4D2
;
1674 } else if (shift_control
== 1) {
1675 full_update
|= update_palette16(s
);
1676 if (s
->sr
[0x01] & 8) {
1677 v
= VGA_DRAW_LINE2D2
;
1683 switch(s
->get_bpp(s
)) {
1686 full_update
|= update_palette256(s
);
1687 v
= VGA_DRAW_LINE8D2
;
1691 full_update
|= update_palette256(s
);
1696 v
= VGA_DRAW_LINE15
;
1700 v
= VGA_DRAW_LINE16
;
1704 v
= VGA_DRAW_LINE24
;
1708 v
= VGA_DRAW_LINE32
;
1713 vga_draw_line
= vga_draw_line_table
[v
* NB_DEPTHS
+ get_depth_index(s
->ds
)];
1715 if (!is_buffer_shared(s
->ds
->surface
) && s
->cursor_invalidate
)
1716 s
->cursor_invalidate(s
);
1718 line_offset
= s
->line_offset
;
1720 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",
1721 width
, height
, v
, line_offset
, s
->cr
[9], s
->cr
[0x17], s
->line_compare
, s
->sr
[0x01]);
1723 addr1
= (s
->start_addr
* 4);
1724 bwidth
= (width
* bits
+ 7) / 8;
1728 d
= ds_get_data(s
->ds
);
1729 linesize
= ds_get_linesize(s
->ds
);
1731 for(y
= 0; y
< height
; y
++) {
1733 if (!(s
->cr
[0x17] & 1)) {
1735 /* CGA compatibility handling */
1736 shift
= 14 + ((s
->cr
[0x17] >> 6) & 1);
1737 addr
= (addr
& ~(1 << shift
)) | ((y1
& 1) << shift
);
1739 if (!(s
->cr
[0x17] & 2)) {
1740 addr
= (addr
& ~0x8000) | ((y1
& 2) << 14);
1742 page0
= addr
& TARGET_PAGE_MASK
;
1743 page1
= (addr
+ bwidth
- 1) & TARGET_PAGE_MASK
;
1744 update
= full_update
|
1745 memory_region_get_dirty(&s
->vram
, page0
, DIRTY_MEMORY_VGA
) |
1746 memory_region_get_dirty(&s
->vram
, page1
, DIRTY_MEMORY_VGA
);
1747 if ((page1
- page0
) > TARGET_PAGE_SIZE
) {
1748 /* if wide line, can use another page */
1749 update
|= memory_region_get_dirty(&s
->vram
,
1750 page0
+ TARGET_PAGE_SIZE
,
1753 /* explicit invalidation for the hardware cursor */
1754 update
|= (s
->invalidated_y_table
[y
>> 5] >> (y
& 0x1f)) & 1;
1758 if (page0
< page_min
)
1760 if (page1
> page_max
)
1762 if (!(is_buffer_shared(s
->ds
->surface
))) {
1763 vga_draw_line(s
, d
, s
->vram_ptr
+ addr
, width
);
1764 if (s
->cursor_draw_line
)
1765 s
->cursor_draw_line(s
, d
, y
);
1769 /* flush to display */
1770 dpy_update(s
->ds
, 0, y_start
,
1771 disp_width
, y
- y_start
);
1776 mask
= (s
->cr
[0x17] & 3) ^ 3;
1777 if ((y1
& mask
) == mask
)
1778 addr1
+= line_offset
;
1780 multi_run
= multi_scan
;
1784 /* line compare acts on the displayed lines */
1785 if (y
== s
->line_compare
)
1790 /* flush to display */
1791 dpy_update(s
->ds
, 0, y_start
,
1792 disp_width
, y
- y_start
);
1794 /* reset modified pages */
1795 if (page_max
>= page_min
) {
1796 memory_region_reset_dirty(&s
->vram
,
1798 page_max
+ TARGET_PAGE_SIZE
- page_min
,
1801 memset(s
->invalidated_y_table
, 0, ((height
+ 31) >> 5) * 4);
1804 static void vga_draw_blank(VGACommonState
*s
, int full_update
)
1811 if (s
->last_scr_width
<= 0 || s
->last_scr_height
<= 0)
1815 rgb_to_pixel_dup_table
[get_depth_index(s
->ds
)];
1816 if (ds_get_bits_per_pixel(s
->ds
) == 8)
1817 val
= s
->rgb_to_pixel(0, 0, 0);
1820 w
= s
->last_scr_width
* ((ds_get_bits_per_pixel(s
->ds
) + 7) >> 3);
1821 d
= ds_get_data(s
->ds
);
1822 for(i
= 0; i
< s
->last_scr_height
; i
++) {
1824 d
+= ds_get_linesize(s
->ds
);
1826 dpy_update(s
->ds
, 0, 0,
1827 s
->last_scr_width
, s
->last_scr_height
);
1830 #define GMODE_TEXT 0
1831 #define GMODE_GRAPH 1
1832 #define GMODE_BLANK 2
1834 static void vga_update_display(void *opaque
)
1836 VGACommonState
*s
= opaque
;
1837 int full_update
, graphic_mode
;
1839 if (ds_get_bits_per_pixel(s
->ds
) == 0) {
1843 if (!(s
->ar_index
& 0x20)) {
1844 graphic_mode
= GMODE_BLANK
;
1846 graphic_mode
= s
->gr
[6] & 1;
1848 if (graphic_mode
!= s
->graphic_mode
) {
1849 s
->graphic_mode
= graphic_mode
;
1852 switch(graphic_mode
) {
1854 vga_draw_text(s
, full_update
);
1857 vga_draw_graphic(s
, full_update
);
1861 vga_draw_blank(s
, full_update
);
1867 /* force a full display refresh */
1868 static void vga_invalidate_display(void *opaque
)
1870 VGACommonState
*s
= opaque
;
1873 s
->last_height
= -1;
1876 void vga_common_reset(VGACommonState
*s
)
1879 memset(s
->sr
, '\0', sizeof(s
->sr
));
1881 memset(s
->gr
, '\0', sizeof(s
->gr
));
1883 memset(s
->ar
, '\0', sizeof(s
->ar
));
1884 s
->ar_flip_flop
= 0;
1886 memset(s
->cr
, '\0', sizeof(s
->cr
));
1892 s
->dac_sub_index
= 0;
1893 s
->dac_read_index
= 0;
1894 s
->dac_write_index
= 0;
1895 memset(s
->dac_cache
, '\0', sizeof(s
->dac_cache
));
1897 memset(s
->palette
, '\0', sizeof(s
->palette
));
1899 #ifdef CONFIG_BOCHS_VBE
1901 memset(s
->vbe_regs
, '\0', sizeof(s
->vbe_regs
));
1902 s
->vbe_regs
[VBE_DISPI_INDEX_ID
] = VBE_DISPI_ID5
;
1903 s
->vbe_start_addr
= 0;
1904 s
->vbe_line_offset
= 0;
1905 s
->vbe_bank_mask
= (s
->vram_size
>> 16) - 1;
1907 memset(s
->font_offsets
, '\0', sizeof(s
->font_offsets
));
1908 s
->graphic_mode
= -1; /* force full update */
1909 s
->shift_control
= 0;
1912 s
->line_compare
= 0;
1914 s
->plane_updated
= 0;
1919 s
->last_scr_width
= 0;
1920 s
->last_scr_height
= 0;
1921 s
->cursor_start
= 0;
1923 s
->cursor_offset
= 0;
1924 memset(s
->invalidated_y_table
, '\0', sizeof(s
->invalidated_y_table
));
1925 memset(s
->last_palette
, '\0', sizeof(s
->last_palette
));
1926 memset(s
->last_ch_attr
, '\0', sizeof(s
->last_ch_attr
));
1927 switch (vga_retrace_method
) {
1928 case VGA_RETRACE_DUMB
:
1930 case VGA_RETRACE_PRECISE
:
1931 memset(&s
->retrace_info
, 0, sizeof (s
->retrace_info
));
1934 vga_update_memory_access(s
);
1937 static void vga_reset(void *opaque
)
1939 VGACommonState
*s
= opaque
;
1940 vga_common_reset(s
);
1943 #define TEXTMODE_X(x) ((x) % width)
1944 #define TEXTMODE_Y(x) ((x) / width)
1945 #define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1946 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1947 /* relay text rendering to the display driver
1948 * instead of doing a full vga_update_display() */
1949 static void vga_update_text(void *opaque
, console_ch_t
*chardata
)
1951 VGACommonState
*s
= opaque
;
1952 int graphic_mode
, i
, cursor_offset
, cursor_visible
;
1953 int cw
, cheight
, width
, height
, size
, c_min
, c_max
;
1955 console_ch_t
*dst
, val
;
1956 char msg_buffer
[80];
1957 int full_update
= 0;
1959 if (!(s
->ar_index
& 0x20)) {
1960 graphic_mode
= GMODE_BLANK
;
1962 graphic_mode
= s
->gr
[6] & 1;
1964 if (graphic_mode
!= s
->graphic_mode
) {
1965 s
->graphic_mode
= graphic_mode
;
1968 if (s
->last_width
== -1) {
1973 switch (graphic_mode
) {
1975 /* TODO: update palette */
1976 full_update
|= update_basic_params(s
);
1978 /* total width & height */
1979 cheight
= (s
->cr
[9] & 0x1f) + 1;
1981 if (!(s
->sr
[1] & 0x01))
1983 if (s
->sr
[1] & 0x08)
1984 cw
= 16; /* NOTE: no 18 pixel wide */
1985 width
= (s
->cr
[0x01] + 1);
1986 if (s
->cr
[0x06] == 100) {
1987 /* ugly hack for CGA 160x100x16 - explain me the logic */
1990 height
= s
->cr
[0x12] |
1991 ((s
->cr
[0x07] & 0x02) << 7) |
1992 ((s
->cr
[0x07] & 0x40) << 3);
1993 height
= (height
+ 1) / cheight
;
1996 size
= (height
* width
);
1997 if (size
> CH_ATTR_SIZE
) {
2001 snprintf(msg_buffer
, sizeof(msg_buffer
), "%i x %i Text mode",
2006 if (width
!= s
->last_width
|| height
!= s
->last_height
||
2007 cw
!= s
->last_cw
|| cheight
!= s
->last_ch
) {
2008 s
->last_scr_width
= width
* cw
;
2009 s
->last_scr_height
= height
* cheight
;
2010 s
->ds
->surface
->width
= width
;
2011 s
->ds
->surface
->height
= height
;
2013 s
->last_width
= width
;
2014 s
->last_height
= height
;
2015 s
->last_ch
= cheight
;
2020 /* Update "hardware" cursor */
2021 cursor_offset
= ((s
->cr
[0x0e] << 8) | s
->cr
[0x0f]) - s
->start_addr
;
2022 if (cursor_offset
!= s
->cursor_offset
||
2023 s
->cr
[0xa] != s
->cursor_start
||
2024 s
->cr
[0xb] != s
->cursor_end
|| full_update
) {
2025 cursor_visible
= !(s
->cr
[0xa] & 0x20);
2026 if (cursor_visible
&& cursor_offset
< size
&& cursor_offset
>= 0)
2028 TEXTMODE_X(cursor_offset
),
2029 TEXTMODE_Y(cursor_offset
));
2031 dpy_cursor(s
->ds
, -1, -1);
2032 s
->cursor_offset
= cursor_offset
;
2033 s
->cursor_start
= s
->cr
[0xa];
2034 s
->cursor_end
= s
->cr
[0xb];
2037 src
= (uint32_t *) s
->vram_ptr
+ s
->start_addr
;
2041 for (i
= 0; i
< size
; src
++, dst
++, i
++)
2042 console_write_ch(dst
, VMEM2CHTYPE(le32_to_cpu(*src
)));
2044 dpy_update(s
->ds
, 0, 0, width
, height
);
2048 for (i
= 0; i
< size
; src
++, dst
++, i
++) {
2049 console_write_ch(&val
, VMEM2CHTYPE(le32_to_cpu(*src
)));
2057 for (; i
< size
; src
++, dst
++, i
++) {
2058 console_write_ch(&val
, VMEM2CHTYPE(le32_to_cpu(*src
)));
2065 if (c_min
<= c_max
) {
2066 i
= TEXTMODE_Y(c_min
);
2067 dpy_update(s
->ds
, 0, i
, width
, TEXTMODE_Y(c_max
) - i
+ 1);
2076 s
->get_resolution(s
, &width
, &height
);
2077 snprintf(msg_buffer
, sizeof(msg_buffer
), "%i x %i Graphic mode",
2085 snprintf(msg_buffer
, sizeof(msg_buffer
), "VGA Blank mode");
2089 /* Display a message */
2091 s
->last_height
= height
= 3;
2092 dpy_cursor(s
->ds
, -1, -1);
2093 s
->ds
->surface
->width
= s
->last_width
;
2094 s
->ds
->surface
->height
= height
;
2097 for (dst
= chardata
, i
= 0; i
< s
->last_width
* height
; i
++)
2098 console_write_ch(dst
++, ' ');
2100 size
= strlen(msg_buffer
);
2101 width
= (s
->last_width
- size
) / 2;
2102 dst
= chardata
+ s
->last_width
+ width
;
2103 for (i
= 0; i
< size
; i
++)
2104 console_write_ch(dst
++, 0x00200100 | msg_buffer
[i
]);
2106 dpy_update(s
->ds
, 0, 0, s
->last_width
, height
);
2109 static uint64_t vga_mem_read(void *opaque
, target_phys_addr_t addr
,
2112 VGACommonState
*s
= opaque
;
2114 return vga_mem_readb(s
, addr
);
2117 static void vga_mem_write(void *opaque
, target_phys_addr_t addr
,
2118 uint64_t data
, unsigned size
)
2120 VGACommonState
*s
= opaque
;
2122 return vga_mem_writeb(s
, addr
, data
);
2125 const MemoryRegionOps vga_mem_ops
= {
2126 .read
= vga_mem_read
,
2127 .write
= vga_mem_write
,
2128 .endianness
= DEVICE_LITTLE_ENDIAN
,
2130 .min_access_size
= 1,
2131 .max_access_size
= 1,
2135 static int vga_common_post_load(void *opaque
, int version_id
)
2137 VGACommonState
*s
= opaque
;
2140 s
->graphic_mode
= -1;
2144 const VMStateDescription vmstate_vga_common
= {
2147 .minimum_version_id
= 2,
2148 .minimum_version_id_old
= 2,
2149 .post_load
= vga_common_post_load
,
2150 .fields
= (VMStateField
[]) {
2151 VMSTATE_UINT32(latch
, VGACommonState
),
2152 VMSTATE_UINT8(sr_index
, VGACommonState
),
2153 VMSTATE_PARTIAL_BUFFER(sr
, VGACommonState
, 8),
2154 VMSTATE_UINT8(gr_index
, VGACommonState
),
2155 VMSTATE_PARTIAL_BUFFER(gr
, VGACommonState
, 16),
2156 VMSTATE_UINT8(ar_index
, VGACommonState
),
2157 VMSTATE_BUFFER(ar
, VGACommonState
),
2158 VMSTATE_INT32(ar_flip_flop
, VGACommonState
),
2159 VMSTATE_UINT8(cr_index
, VGACommonState
),
2160 VMSTATE_BUFFER(cr
, VGACommonState
),
2161 VMSTATE_UINT8(msr
, VGACommonState
),
2162 VMSTATE_UINT8(fcr
, VGACommonState
),
2163 VMSTATE_UINT8(st00
, VGACommonState
),
2164 VMSTATE_UINT8(st01
, VGACommonState
),
2166 VMSTATE_UINT8(dac_state
, VGACommonState
),
2167 VMSTATE_UINT8(dac_sub_index
, VGACommonState
),
2168 VMSTATE_UINT8(dac_read_index
, VGACommonState
),
2169 VMSTATE_UINT8(dac_write_index
, VGACommonState
),
2170 VMSTATE_BUFFER(dac_cache
, VGACommonState
),
2171 VMSTATE_BUFFER(palette
, VGACommonState
),
2173 VMSTATE_INT32(bank_offset
, VGACommonState
),
2174 VMSTATE_UINT8_EQUAL(is_vbe_vmstate
, VGACommonState
),
2175 #ifdef CONFIG_BOCHS_VBE
2176 VMSTATE_UINT16(vbe_index
, VGACommonState
),
2177 VMSTATE_UINT16_ARRAY(vbe_regs
, VGACommonState
, VBE_DISPI_INDEX_NB
),
2178 VMSTATE_UINT32(vbe_start_addr
, VGACommonState
),
2179 VMSTATE_UINT32(vbe_line_offset
, VGACommonState
),
2180 VMSTATE_UINT32(vbe_bank_mask
, VGACommonState
),
2182 VMSTATE_END_OF_LIST()
2186 void vga_common_init(VGACommonState
*s
, int vga_ram_size
)
2190 for(i
= 0;i
< 256; i
++) {
2192 for(j
= 0; j
< 8; j
++) {
2193 v
|= ((i
>> j
) & 1) << (j
* 4);
2198 for(j
= 0; j
< 4; j
++) {
2199 v
|= ((i
>> (2 * j
)) & 3) << (j
* 4);
2203 for(i
= 0; i
< 16; i
++) {
2205 for(j
= 0; j
< 4; j
++) {
2208 v
|= b
<< (2 * j
+ 1);
2213 #ifdef CONFIG_BOCHS_VBE
2214 s
->is_vbe_vmstate
= 1;
2216 s
->is_vbe_vmstate
= 0;
2218 memory_region_init_ram(&s
->vram
, NULL
, "vga.vram", vga_ram_size
);
2219 s
->vram_ptr
= memory_region_get_ram_ptr(&s
->vram
);
2220 s
->vram_size
= vga_ram_size
;
2221 s
->get_bpp
= vga_get_bpp
;
2222 s
->get_offsets
= vga_get_offsets
;
2223 s
->get_resolution
= vga_get_resolution
;
2224 s
->update
= vga_update_display
;
2225 s
->invalidate
= vga_invalidate_display
;
2226 s
->screen_dump
= vga_screen_dump
;
2227 s
->text_update
= vga_update_text
;
2228 switch (vga_retrace_method
) {
2229 case VGA_RETRACE_DUMB
:
2230 s
->retrace
= vga_dumb_retrace
;
2231 s
->update_retrace_info
= vga_dumb_update_retrace_info
;
2234 case VGA_RETRACE_PRECISE
:
2235 s
->retrace
= vga_precise_retrace
;
2236 s
->update_retrace_info
= vga_precise_update_retrace_info
;
2239 vga_dirty_log_start(s
);
2242 /* used by both ISA and PCI */
2243 MemoryRegion
*vga_init_io(VGACommonState
*s
)
2245 MemoryRegion
*vga_mem
;
2247 register_ioport_write(0x3c0, 16, 1, vga_ioport_write
, s
);
2249 register_ioport_write(0x3b4, 2, 1, vga_ioport_write
, s
);
2250 register_ioport_write(0x3d4, 2, 1, vga_ioport_write
, s
);
2251 register_ioport_write(0x3ba, 1, 1, vga_ioport_write
, s
);
2252 register_ioport_write(0x3da, 1, 1, vga_ioport_write
, s
);
2254 register_ioport_read(0x3c0, 16, 1, vga_ioport_read
, s
);
2256 register_ioport_read(0x3b4, 2, 1, vga_ioport_read
, s
);
2257 register_ioport_read(0x3d4, 2, 1, vga_ioport_read
, s
);
2258 register_ioport_read(0x3ba, 1, 1, vga_ioport_read
, s
);
2259 register_ioport_read(0x3da, 1, 1, vga_ioport_read
, s
);
2261 #ifdef CONFIG_BOCHS_VBE
2262 #if defined (TARGET_I386)
2263 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index
, s
);
2264 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data
, s
);
2266 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index
, s
);
2267 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data
, s
);
2269 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index
, s
);
2270 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data
, s
);
2272 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index
, s
);
2273 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data
, s
);
2275 #endif /* CONFIG_BOCHS_VBE */
2277 vga_mem
= g_malloc(sizeof(*vga_mem
));
2278 memory_region_init_io(vga_mem
, &vga_mem_ops
, s
,
2279 "vga-lowmem", 0x20000);
2284 void vga_init(VGACommonState
*s
, MemoryRegion
*address_space
)
2286 MemoryRegion
*vga_io_memory
;
2288 qemu_register_reset(vga_reset
, s
);
2292 s
->legacy_address_space
= address_space
;
2294 vga_io_memory
= vga_init_io(s
);
2295 memory_region_add_subregion_overlap(address_space
,
2296 isa_mem_base
+ 0x000a0000,
2299 memory_region_set_coalescing(vga_io_memory
);
2302 void vga_init_vbe(VGACommonState
*s
, MemoryRegion
*system_memory
)
2304 #ifdef CONFIG_BOCHS_VBE
2305 /* XXX: use optimized standard vga accesses */
2306 memory_region_add_subregion(system_memory
,
2307 VBE_DISPI_LFB_PHYSICAL_ADDRESS
,
2312 /********************************************************/
2313 /* vga screen dump */
2315 static void vga_save_dpy_update(DisplayState
*ds
,
2316 int x
, int y
, int w
, int h
)
2318 if (screen_dump_filename
) {
2319 ppm_save(screen_dump_filename
, ds
->surface
);
2320 screen_dump_filename
= NULL
;
2324 static void vga_save_dpy_resize(DisplayState
*s
)
2328 static void vga_save_dpy_refresh(DisplayState
*s
)
2332 int ppm_save(const char *filename
, struct DisplaySurface
*ds
)
2340 char *linebuf
, *pbuf
;
2342 f
= fopen(filename
, "wb");
2345 fprintf(f
, "P6\n%d %d\n%d\n",
2346 ds
->width
, ds
->height
, 255);
2347 linebuf
= g_malloc(ds
->width
* 3);
2349 for(y
= 0; y
< ds
->height
; y
++) {
2352 for(x
= 0; x
< ds
->width
; x
++) {
2353 if (ds
->pf
.bits_per_pixel
== 32)
2356 v
= (uint32_t) (*(uint16_t *)d
);
2357 r
= ((v
>> ds
->pf
.rshift
) & ds
->pf
.rmax
) * 256 /
2359 g
= ((v
>> ds
->pf
.gshift
) & ds
->pf
.gmax
) * 256 /
2361 b
= ((v
>> ds
->pf
.bshift
) & ds
->pf
.bmax
) * 256 /
2366 d
+= ds
->pf
.bytes_per_pixel
;
2369 ret
= fwrite(linebuf
, 1, pbuf
- linebuf
, f
);
2377 static DisplayChangeListener
* vga_screen_dump_init(DisplayState
*ds
)
2379 DisplayChangeListener
*dcl
;
2381 dcl
= g_malloc0(sizeof(DisplayChangeListener
));
2382 dcl
->dpy_update
= vga_save_dpy_update
;
2383 dcl
->dpy_resize
= vga_save_dpy_resize
;
2384 dcl
->dpy_refresh
= vga_save_dpy_refresh
;
2385 register_displaychangelistener(ds
, dcl
);
2389 /* save the vga display in a PPM image even if no display is
2391 static void vga_screen_dump(void *opaque
, const char *filename
)
2393 VGACommonState
*s
= opaque
;
2395 if (!screen_dump_dcl
)
2396 screen_dump_dcl
= vga_screen_dump_init(s
->ds
);
2398 screen_dump_filename
= (char *)filename
;
2399 vga_invalidate_display(s
);