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_dumb_update_retrace_info(VGACommonState
*s
)
160 static void vga_precise_update_retrace_info(VGACommonState
*s
)
163 int hretr_start_char
;
164 int hretr_skew_chars
;
168 int vretr_start_line
;
177 const int clk_hz
[] = {25175000, 28322000, 25175000, 25175000};
178 int64_t chars_per_sec
;
179 struct vga_precise_retrace
*r
= &s
->retrace_info
.precise
;
181 htotal_chars
= s
->cr
[0x00] + 5;
182 hretr_start_char
= s
->cr
[0x04];
183 hretr_skew_chars
= (s
->cr
[0x05] >> 5) & 3;
184 hretr_end_char
= s
->cr
[0x05] & 0x1f;
186 vtotal_lines
= (s
->cr
[0x06]
187 | (((s
->cr
[0x07] & 1) | ((s
->cr
[0x07] >> 4) & 2)) << 8)) + 2
189 vretr_start_line
= s
->cr
[0x10]
190 | ((((s
->cr
[0x07] >> 2) & 1) | ((s
->cr
[0x07] >> 6) & 2)) << 8)
192 vretr_end_line
= s
->cr
[0x11] & 0xf;
196 clocking_mode
= (s
->sr
[0x01] >> 3) & 1;
197 clock_sel
= (s
->msr
>> 2) & 3;
198 dots
= (s
->msr
& 1) ? 8 : 9;
200 chars_per_sec
= clk_hz
[clock_sel
] / dots
;
202 htotal_chars
<<= clocking_mode
;
204 r
->total_chars
= vtotal_lines
* htotal_chars
;
206 r
->ticks_per_char
= get_ticks_per_sec() / (r
->total_chars
* r
->freq
);
208 r
->ticks_per_char
= get_ticks_per_sec() / chars_per_sec
;
211 r
->vstart
= vretr_start_line
;
212 r
->vend
= r
->vstart
+ vretr_end_line
+ 1;
214 r
->hstart
= hretr_start_char
+ hretr_skew_chars
;
215 r
->hend
= r
->hstart
+ hretr_end_char
+ 1;
216 r
->htotal
= htotal_chars
;
219 div2
= (s
->cr
[0x17] >> 2) & 1;
220 sldiv2
= (s
->cr
[0x17] >> 3) & 1;
230 "div2 = %d sldiv2 = %d\n"
231 "clocking_mode = %d\n"
232 "clock_sel = %d %d\n"
234 "ticks/char = %" PRId64
"\n"
236 (double) get_ticks_per_sec() / (r
->ticks_per_char
* r
->total_chars
),
254 static uint8_t vga_precise_retrace(VGACommonState
*s
)
256 struct vga_precise_retrace
*r
= &s
->retrace_info
.precise
;
257 uint8_t val
= s
->st01
& ~(ST01_V_RETRACE
| ST01_DISP_ENABLE
);
259 if (r
->total_chars
) {
260 int cur_line
, cur_line_char
, cur_char
;
263 cur_tick
= qemu_get_clock(vm_clock
);
265 cur_char
= (cur_tick
/ r
->ticks_per_char
) % r
->total_chars
;
266 cur_line
= cur_char
/ r
->htotal
;
268 if (cur_line
>= r
->vstart
&& cur_line
<= r
->vend
) {
269 val
|= ST01_V_RETRACE
| ST01_DISP_ENABLE
;
271 cur_line_char
= cur_char
% r
->htotal
;
272 if (cur_line_char
>= r
->hstart
&& cur_line_char
<= r
->hend
) {
273 val
|= ST01_DISP_ENABLE
;
279 return s
->st01
^ (ST01_V_RETRACE
| ST01_DISP_ENABLE
);
283 static uint8_t vga_dumb_retrace(VGACommonState
*s
)
285 return s
->st01
^ (ST01_V_RETRACE
| ST01_DISP_ENABLE
);
288 int vga_ioport_invalid(VGACommonState
*s
, uint32_t addr
)
290 if (s
->msr
& MSR_COLOR_EMULATION
) {
292 return (addr
>= 0x3b0 && addr
<= 0x3bf);
295 return (addr
>= 0x3d0 && addr
<= 0x3df);
299 uint32_t vga_ioport_read(void *opaque
, uint32_t addr
)
301 VGACommonState
*s
= opaque
;
304 if (vga_ioport_invalid(s
, addr
)) {
309 if (s
->ar_flip_flop
== 0) {
316 index
= s
->ar_index
& 0x1f;
329 val
= s
->sr
[s
->sr_index
];
331 printf("vga: read SR%x = 0x%02x\n", s
->sr_index
, val
);
338 val
= s
->dac_write_index
;
341 val
= s
->palette
[s
->dac_read_index
* 3 + s
->dac_sub_index
];
342 if (++s
->dac_sub_index
== 3) {
343 s
->dac_sub_index
= 0;
357 val
= s
->gr
[s
->gr_index
];
359 printf("vga: read GR%x = 0x%02x\n", s
->gr_index
, val
);
368 val
= s
->cr
[s
->cr_index
];
370 printf("vga: read CR%x = 0x%02x\n", s
->cr_index
, val
);
375 /* just toggle to fool polling */
376 val
= s
->st01
= s
->retrace(s
);
384 #if defined(DEBUG_VGA)
385 printf("VGA: read addr=0x%04x data=0x%02x\n", addr
, val
);
390 void vga_ioport_write(void *opaque
, uint32_t addr
, uint32_t val
)
392 VGACommonState
*s
= opaque
;
395 /* check port range access depending on color/monochrome mode */
396 if (vga_ioport_invalid(s
, addr
)) {
400 printf("VGA: write addr=0x%04x data=0x%02x\n", addr
, val
);
405 if (s
->ar_flip_flop
== 0) {
409 index
= s
->ar_index
& 0x1f;
412 s
->ar
[index
] = val
& 0x3f;
415 s
->ar
[index
] = val
& ~0x10;
421 s
->ar
[index
] = val
& ~0xc0;
424 s
->ar
[index
] = val
& ~0xf0;
427 s
->ar
[index
] = val
& ~0xf0;
433 s
->ar_flip_flop
^= 1;
436 s
->msr
= val
& ~0x10;
437 s
->update_retrace_info(s
);
440 s
->sr_index
= val
& 7;
444 printf("vga: write SR%x = 0x%02x\n", s
->sr_index
, val
);
446 s
->sr
[s
->sr_index
] = val
& sr_mask
[s
->sr_index
];
447 if (s
->sr_index
== 1) s
->update_retrace_info(s
);
450 s
->dac_read_index
= val
;
451 s
->dac_sub_index
= 0;
455 s
->dac_write_index
= val
;
456 s
->dac_sub_index
= 0;
460 s
->dac_cache
[s
->dac_sub_index
] = val
;
461 if (++s
->dac_sub_index
== 3) {
462 memcpy(&s
->palette
[s
->dac_write_index
* 3], s
->dac_cache
, 3);
463 s
->dac_sub_index
= 0;
464 s
->dac_write_index
++;
468 s
->gr_index
= val
& 0x0f;
472 printf("vga: write GR%x = 0x%02x\n", s
->gr_index
, val
);
474 s
->gr
[s
->gr_index
] = val
& gr_mask
[s
->gr_index
];
483 printf("vga: write CR%x = 0x%02x\n", s
->cr_index
, val
);
485 /* handle CR0-7 protection */
486 if ((s
->cr
[0x11] & 0x80) && s
->cr_index
<= 7) {
487 /* can always write bit 4 of CR7 */
488 if (s
->cr_index
== 7)
489 s
->cr
[7] = (s
->cr
[7] & ~0x10) | (val
& 0x10);
492 s
->cr
[s
->cr_index
] = val
;
494 switch(s
->cr_index
) {
502 s
->update_retrace_info(s
);
513 #ifdef CONFIG_BOCHS_VBE
514 static uint32_t vbe_ioport_read_index(void *opaque
, uint32_t addr
)
516 VGACommonState
*s
= opaque
;
522 static uint32_t vbe_ioport_read_data(void *opaque
, uint32_t addr
)
524 VGACommonState
*s
= opaque
;
527 if (s
->vbe_index
< VBE_DISPI_INDEX_NB
) {
528 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_GETCAPS
) {
529 switch(s
->vbe_index
) {
530 /* XXX: do not hardcode ? */
531 case VBE_DISPI_INDEX_XRES
:
532 val
= VBE_DISPI_MAX_XRES
;
534 case VBE_DISPI_INDEX_YRES
:
535 val
= VBE_DISPI_MAX_YRES
;
537 case VBE_DISPI_INDEX_BPP
:
538 val
= VBE_DISPI_MAX_BPP
;
541 val
= s
->vbe_regs
[s
->vbe_index
];
545 val
= s
->vbe_regs
[s
->vbe_index
];
547 } else if (s
->vbe_index
== VBE_DISPI_INDEX_VIDEO_MEMORY_64K
) {
548 val
= s
->vram_size
/ (64 * 1024);
552 #ifdef DEBUG_BOCHS_VBE
553 printf("VBE: read index=0x%x val=0x%x\n", s
->vbe_index
, val
);
558 static void vbe_ioport_write_index(void *opaque
, uint32_t addr
, uint32_t val
)
560 VGACommonState
*s
= opaque
;
564 static void vbe_ioport_write_data(void *opaque
, uint32_t addr
, uint32_t val
)
566 VGACommonState
*s
= opaque
;
568 if (s
->vbe_index
<= VBE_DISPI_INDEX_NB
) {
569 #ifdef DEBUG_BOCHS_VBE
570 printf("VBE: write index=0x%x val=0x%x\n", s
->vbe_index
, val
);
572 switch(s
->vbe_index
) {
573 case VBE_DISPI_INDEX_ID
:
574 if (val
== VBE_DISPI_ID0
||
575 val
== VBE_DISPI_ID1
||
576 val
== VBE_DISPI_ID2
||
577 val
== VBE_DISPI_ID3
||
578 val
== VBE_DISPI_ID4
) {
579 s
->vbe_regs
[s
->vbe_index
] = val
;
582 case VBE_DISPI_INDEX_XRES
:
583 if ((val
<= VBE_DISPI_MAX_XRES
) && ((val
& 7) == 0)) {
584 s
->vbe_regs
[s
->vbe_index
] = val
;
587 case VBE_DISPI_INDEX_YRES
:
588 if (val
<= VBE_DISPI_MAX_YRES
) {
589 s
->vbe_regs
[s
->vbe_index
] = val
;
592 case VBE_DISPI_INDEX_BPP
:
595 if (val
== 4 || val
== 8 || val
== 15 ||
596 val
== 16 || val
== 24 || val
== 32) {
597 s
->vbe_regs
[s
->vbe_index
] = val
;
600 case VBE_DISPI_INDEX_BANK
:
601 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
602 val
&= (s
->vbe_bank_mask
>> 2);
604 val
&= s
->vbe_bank_mask
;
606 s
->vbe_regs
[s
->vbe_index
] = val
;
607 s
->bank_offset
= (val
<< 16);
609 case VBE_DISPI_INDEX_ENABLE
:
610 if ((val
& VBE_DISPI_ENABLED
) &&
611 !(s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
)) {
612 int h
, shift_control
;
614 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] =
615 s
->vbe_regs
[VBE_DISPI_INDEX_XRES
];
616 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_HEIGHT
] =
617 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
];
618 s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
] = 0;
619 s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
] = 0;
621 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
622 s
->vbe_line_offset
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 1;
624 s
->vbe_line_offset
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] *
625 ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
626 s
->vbe_start_addr
= 0;
628 /* clear the screen (should be done in BIOS) */
629 if (!(val
& VBE_DISPI_NOCLEARMEM
)) {
630 memset(s
->vram_ptr
, 0,
631 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] * s
->vbe_line_offset
);
634 /* we initialize the VGA graphic mode (should be done
636 s
->gr
[0x06] = (s
->gr
[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
637 s
->cr
[0x17] |= 3; /* no CGA modes */
638 s
->cr
[0x13] = s
->vbe_line_offset
>> 3;
640 s
->cr
[0x01] = (s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 3) - 1;
641 /* height (only meaningful if < 1024) */
642 h
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] - 1;
644 s
->cr
[0x07] = (s
->cr
[0x07] & ~0x42) |
645 ((h
>> 7) & 0x02) | ((h
>> 3) & 0x40);
646 /* line compare to 1023 */
651 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
653 s
->sr
[0x01] &= ~8; /* no double line */
656 s
->sr
[4] |= 0x08; /* set chain 4 mode */
657 s
->sr
[2] |= 0x0f; /* activate all planes */
659 s
->gr
[0x05] = (s
->gr
[0x05] & ~0x60) | (shift_control
<< 5);
660 s
->cr
[0x09] &= ~0x9f; /* no double scan */
662 /* XXX: the bios should do that */
665 s
->dac_8bit
= (val
& VBE_DISPI_8BIT_DAC
) > 0;
666 s
->vbe_regs
[s
->vbe_index
] = val
;
668 case VBE_DISPI_INDEX_VIRT_WIDTH
:
670 int w
, h
, line_offset
;
672 if (val
< s
->vbe_regs
[VBE_DISPI_INDEX_XRES
])
675 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
676 line_offset
= w
>> 1;
678 line_offset
= w
* ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
679 h
= s
->vram_size
/ line_offset
;
680 /* XXX: support weird bochs semantics ? */
681 if (h
< s
->vbe_regs
[VBE_DISPI_INDEX_YRES
])
683 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] = w
;
684 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_HEIGHT
] = h
;
685 s
->vbe_line_offset
= line_offset
;
688 case VBE_DISPI_INDEX_X_OFFSET
:
689 case VBE_DISPI_INDEX_Y_OFFSET
:
692 s
->vbe_regs
[s
->vbe_index
] = val
;
693 s
->vbe_start_addr
= s
->vbe_line_offset
* s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
];
694 x
= s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
];
695 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
696 s
->vbe_start_addr
+= x
>> 1;
698 s
->vbe_start_addr
+= x
* ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
699 s
->vbe_start_addr
>>= 2;
709 /* called for accesses between 0xa0000 and 0xc0000 */
710 uint32_t vga_mem_readb(void *opaque
, target_phys_addr_t addr
)
712 VGACommonState
*s
= opaque
;
713 int memory_map_mode
, plane
;
716 /* convert to VGA memory offset */
717 memory_map_mode
= (s
->gr
[6] >> 2) & 3;
719 switch(memory_map_mode
) {
725 addr
+= s
->bank_offset
;
740 if (s
->sr
[4] & 0x08) {
741 /* chain 4 mode : simplest access */
742 ret
= s
->vram_ptr
[addr
];
743 } else if (s
->gr
[5] & 0x10) {
744 /* odd/even mode (aka text mode mapping) */
745 plane
= (s
->gr
[4] & 2) | (addr
& 1);
746 ret
= s
->vram_ptr
[((addr
& ~1) << 1) | plane
];
748 /* standard VGA latched access */
749 s
->latch
= ((uint32_t *)s
->vram_ptr
)[addr
];
751 if (!(s
->gr
[5] & 0x08)) {
754 ret
= GET_PLANE(s
->latch
, plane
);
757 ret
= (s
->latch
^ mask16
[s
->gr
[2]]) & mask16
[s
->gr
[7]];
766 static uint32_t vga_mem_readw(void *opaque
, target_phys_addr_t addr
)
769 v
= vga_mem_readb(opaque
, addr
);
770 v
|= vga_mem_readb(opaque
, addr
+ 1) << 8;
774 static uint32_t vga_mem_readl(void *opaque
, target_phys_addr_t addr
)
777 v
= vga_mem_readb(opaque
, addr
);
778 v
|= vga_mem_readb(opaque
, addr
+ 1) << 8;
779 v
|= vga_mem_readb(opaque
, addr
+ 2) << 16;
780 v
|= vga_mem_readb(opaque
, addr
+ 3) << 24;
784 /* called for accesses between 0xa0000 and 0xc0000 */
785 void vga_mem_writeb(void *opaque
, target_phys_addr_t addr
, uint32_t val
)
787 VGACommonState
*s
= opaque
;
788 int memory_map_mode
, plane
, write_mode
, b
, func_select
, mask
;
789 uint32_t write_mask
, bit_mask
, set_mask
;
792 printf("vga: [0x" TARGET_FMT_plx
"] = 0x%02x\n", addr
, val
);
794 /* convert to VGA memory offset */
795 memory_map_mode
= (s
->gr
[6] >> 2) & 3;
797 switch(memory_map_mode
) {
803 addr
+= s
->bank_offset
;
818 if (s
->sr
[4] & 0x08) {
819 /* chain 4 mode : simplest access */
822 if (s
->sr
[2] & mask
) {
823 s
->vram_ptr
[addr
] = val
;
825 printf("vga: chain4: [0x" TARGET_FMT_plx
"]\n", addr
);
827 s
->plane_updated
|= mask
; /* only used to detect font change */
828 cpu_physical_memory_set_dirty(s
->vram_offset
+ addr
);
830 } else if (s
->gr
[5] & 0x10) {
831 /* odd/even mode (aka text mode mapping) */
832 plane
= (s
->gr
[4] & 2) | (addr
& 1);
834 if (s
->sr
[2] & mask
) {
835 addr
= ((addr
& ~1) << 1) | plane
;
836 s
->vram_ptr
[addr
] = val
;
838 printf("vga: odd/even: [0x" TARGET_FMT_plx
"]\n", addr
);
840 s
->plane_updated
|= mask
; /* only used to detect font change */
841 cpu_physical_memory_set_dirty(s
->vram_offset
+ addr
);
844 /* standard VGA latched access */
845 write_mode
= s
->gr
[5] & 3;
851 val
= ((val
>> b
) | (val
<< (8 - b
))) & 0xff;
855 /* apply set/reset mask */
856 set_mask
= mask16
[s
->gr
[1]];
857 val
= (val
& ~set_mask
) | (mask16
[s
->gr
[0]] & set_mask
);
864 val
= mask16
[val
& 0x0f];
870 val
= (val
>> b
) | (val
<< (8 - b
));
872 bit_mask
= s
->gr
[8] & val
;
873 val
= mask16
[s
->gr
[0]];
877 /* apply logical operation */
878 func_select
= s
->gr
[3] >> 3;
879 switch(func_select
) {
899 bit_mask
|= bit_mask
<< 8;
900 bit_mask
|= bit_mask
<< 16;
901 val
= (val
& bit_mask
) | (s
->latch
& ~bit_mask
);
904 /* mask data according to sr[2] */
906 s
->plane_updated
|= mask
; /* only used to detect font change */
907 write_mask
= mask16
[mask
];
908 ((uint32_t *)s
->vram_ptr
)[addr
] =
909 (((uint32_t *)s
->vram_ptr
)[addr
] & ~write_mask
) |
912 printf("vga: latch: [0x" TARGET_FMT_plx
"] mask=0x%08x val=0x%08x\n",
913 addr
* 4, write_mask
, val
);
915 cpu_physical_memory_set_dirty(s
->vram_offset
+ (addr
<< 2));
919 static void vga_mem_writew(void *opaque
, target_phys_addr_t addr
, uint32_t val
)
921 vga_mem_writeb(opaque
, addr
, val
& 0xff);
922 vga_mem_writeb(opaque
, addr
+ 1, (val
>> 8) & 0xff);
925 static void vga_mem_writel(void *opaque
, target_phys_addr_t addr
, uint32_t val
)
927 vga_mem_writeb(opaque
, addr
, val
& 0xff);
928 vga_mem_writeb(opaque
, addr
+ 1, (val
>> 8) & 0xff);
929 vga_mem_writeb(opaque
, addr
+ 2, (val
>> 16) & 0xff);
930 vga_mem_writeb(opaque
, addr
+ 3, (val
>> 24) & 0xff);
933 typedef void vga_draw_glyph8_func(uint8_t *d
, int linesize
,
934 const uint8_t *font_ptr
, int h
,
935 uint32_t fgcol
, uint32_t bgcol
);
936 typedef void vga_draw_glyph9_func(uint8_t *d
, int linesize
,
937 const uint8_t *font_ptr
, int h
,
938 uint32_t fgcol
, uint32_t bgcol
, int dup9
);
939 typedef void vga_draw_line_func(VGACommonState
*s1
, uint8_t *d
,
940 const uint8_t *s
, int width
);
943 #include "vga_template.h"
946 #include "vga_template.h"
950 #include "vga_template.h"
953 #include "vga_template.h"
957 #include "vga_template.h"
960 #include "vga_template.h"
964 #include "vga_template.h"
966 static unsigned int rgb_to_pixel8_dup(unsigned int r
, unsigned int g
, unsigned b
)
969 col
= rgb_to_pixel8(r
, g
, b
);
975 static unsigned int rgb_to_pixel15_dup(unsigned int r
, unsigned int g
, unsigned b
)
978 col
= rgb_to_pixel15(r
, g
, b
);
983 static unsigned int rgb_to_pixel15bgr_dup(unsigned int r
, unsigned int g
,
987 col
= rgb_to_pixel15bgr(r
, g
, b
);
992 static unsigned int rgb_to_pixel16_dup(unsigned int r
, unsigned int g
, unsigned b
)
995 col
= rgb_to_pixel16(r
, g
, b
);
1000 static unsigned int rgb_to_pixel16bgr_dup(unsigned int r
, unsigned int g
,
1004 col
= rgb_to_pixel16bgr(r
, g
, b
);
1009 static unsigned int rgb_to_pixel32_dup(unsigned int r
, unsigned int g
, unsigned b
)
1012 col
= rgb_to_pixel32(r
, g
, b
);
1016 static unsigned int rgb_to_pixel32bgr_dup(unsigned int r
, unsigned int g
, unsigned b
)
1019 col
= rgb_to_pixel32bgr(r
, g
, b
);
1023 /* return true if the palette was modified */
1024 static int update_palette16(VGACommonState
*s
)
1027 uint32_t v
, col
, *palette
;
1030 palette
= s
->last_palette
;
1031 for(i
= 0; i
< 16; i
++) {
1033 if (s
->ar
[0x10] & 0x80)
1034 v
= ((s
->ar
[0x14] & 0xf) << 4) | (v
& 0xf);
1036 v
= ((s
->ar
[0x14] & 0xc) << 4) | (v
& 0x3f);
1038 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
1039 c6_to_8(s
->palette
[v
+ 1]),
1040 c6_to_8(s
->palette
[v
+ 2]));
1041 if (col
!= palette
[i
]) {
1049 /* return true if the palette was modified */
1050 static int update_palette256(VGACommonState
*s
)
1053 uint32_t v
, col
, *palette
;
1056 palette
= s
->last_palette
;
1058 for(i
= 0; i
< 256; i
++) {
1060 col
= s
->rgb_to_pixel(s
->palette
[v
],
1064 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
1065 c6_to_8(s
->palette
[v
+ 1]),
1066 c6_to_8(s
->palette
[v
+ 2]));
1068 if (col
!= palette
[i
]) {
1077 static void vga_get_offsets(VGACommonState
*s
,
1078 uint32_t *pline_offset
,
1079 uint32_t *pstart_addr
,
1080 uint32_t *pline_compare
)
1082 uint32_t start_addr
, line_offset
, line_compare
;
1083 #ifdef CONFIG_BOCHS_VBE
1084 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1085 line_offset
= s
->vbe_line_offset
;
1086 start_addr
= s
->vbe_start_addr
;
1087 line_compare
= 65535;
1091 /* compute line_offset in bytes */
1092 line_offset
= s
->cr
[0x13];
1095 /* starting address */
1096 start_addr
= s
->cr
[0x0d] | (s
->cr
[0x0c] << 8);
1099 line_compare
= s
->cr
[0x18] |
1100 ((s
->cr
[0x07] & 0x10) << 4) |
1101 ((s
->cr
[0x09] & 0x40) << 3);
1103 *pline_offset
= line_offset
;
1104 *pstart_addr
= start_addr
;
1105 *pline_compare
= line_compare
;
1108 /* update start_addr and line_offset. Return TRUE if modified */
1109 static int update_basic_params(VGACommonState
*s
)
1112 uint32_t start_addr
, line_offset
, line_compare
;
1116 s
->get_offsets(s
, &line_offset
, &start_addr
, &line_compare
);
1118 if (line_offset
!= s
->line_offset
||
1119 start_addr
!= s
->start_addr
||
1120 line_compare
!= s
->line_compare
) {
1121 s
->line_offset
= line_offset
;
1122 s
->start_addr
= start_addr
;
1123 s
->line_compare
= line_compare
;
1131 static inline int get_depth_index(DisplayState
*s
)
1133 switch(ds_get_bits_per_pixel(s
)) {
1142 if (is_surface_bgr(s
->surface
))
1149 static vga_draw_glyph8_func
* const vga_draw_glyph8_table
[NB_DEPTHS
] = {
1159 static vga_draw_glyph8_func
* const vga_draw_glyph16_table
[NB_DEPTHS
] = {
1161 vga_draw_glyph16_16
,
1162 vga_draw_glyph16_16
,
1163 vga_draw_glyph16_32
,
1164 vga_draw_glyph16_32
,
1165 vga_draw_glyph16_16
,
1166 vga_draw_glyph16_16
,
1169 static vga_draw_glyph9_func
* const vga_draw_glyph9_table
[NB_DEPTHS
] = {
1179 static const uint8_t cursor_glyph
[32 * 4] = {
1180 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1181 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1182 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1183 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1184 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1185 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1186 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1187 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1188 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1189 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1190 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1191 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
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,
1198 static void vga_get_text_resolution(VGACommonState
*s
, int *pwidth
, int *pheight
,
1199 int *pcwidth
, int *pcheight
)
1201 int width
, cwidth
, height
, cheight
;
1203 /* total width & height */
1204 cheight
= (s
->cr
[9] & 0x1f) + 1;
1206 if (!(s
->sr
[1] & 0x01))
1208 if (s
->sr
[1] & 0x08)
1209 cwidth
= 16; /* NOTE: no 18 pixel wide */
1210 width
= (s
->cr
[0x01] + 1);
1211 if (s
->cr
[0x06] == 100) {
1212 /* ugly hack for CGA 160x100x16 - explain me the logic */
1215 height
= s
->cr
[0x12] |
1216 ((s
->cr
[0x07] & 0x02) << 7) |
1217 ((s
->cr
[0x07] & 0x40) << 3);
1218 height
= (height
+ 1) / cheight
;
1224 *pcheight
= cheight
;
1227 typedef unsigned int rgb_to_pixel_dup_func(unsigned int r
, unsigned int g
, unsigned b
);
1229 static rgb_to_pixel_dup_func
* const rgb_to_pixel_dup_table
[NB_DEPTHS
] = {
1234 rgb_to_pixel32bgr_dup
,
1235 rgb_to_pixel15bgr_dup
,
1236 rgb_to_pixel16bgr_dup
,
1247 static void vga_draw_text(VGACommonState
*s
, int full_update
)
1249 int cx
, cy
, cheight
, cw
, ch
, cattr
, height
, width
, ch_attr
;
1250 int cx_min
, cx_max
, linesize
, x_incr
, line
, line1
;
1251 uint32_t offset
, fgcol
, bgcol
, v
, cursor_offset
;
1252 uint8_t *d1
, *d
, *src
, *dest
, *cursor_ptr
;
1253 const uint8_t *font_ptr
, *font_base
[2];
1254 int dup9
, line_offset
, depth_index
;
1256 uint32_t *ch_attr_ptr
;
1257 vga_draw_glyph8_func
*vga_draw_glyph8
;
1258 vga_draw_glyph9_func
*vga_draw_glyph9
;
1260 /* compute font data address (in plane 2) */
1262 offset
= (((v
>> 4) & 1) | ((v
<< 1) & 6)) * 8192 * 4 + 2;
1263 if (offset
!= s
->font_offsets
[0]) {
1264 s
->font_offsets
[0] = offset
;
1267 font_base
[0] = s
->vram_ptr
+ offset
;
1269 offset
= (((v
>> 5) & 1) | ((v
>> 1) & 6)) * 8192 * 4 + 2;
1270 font_base
[1] = s
->vram_ptr
+ offset
;
1271 if (offset
!= s
->font_offsets
[1]) {
1272 s
->font_offsets
[1] = offset
;
1275 if (s
->plane_updated
& (1 << 2)) {
1276 /* if the plane 2 was modified since the last display, it
1277 indicates the font may have been modified */
1278 s
->plane_updated
= 0;
1281 full_update
|= update_basic_params(s
);
1283 line_offset
= s
->line_offset
;
1285 vga_get_text_resolution(s
, &width
, &height
, &cw
, &cheight
);
1286 if ((height
* width
) > CH_ATTR_SIZE
) {
1287 /* better than nothing: exit if transient size is too big */
1291 if (width
!= s
->last_width
|| height
!= s
->last_height
||
1292 cw
!= s
->last_cw
|| cheight
!= s
->last_ch
|| s
->last_depth
) {
1293 s
->last_scr_width
= width
* cw
;
1294 s
->last_scr_height
= height
* cheight
;
1295 qemu_console_resize(s
->ds
, s
->last_scr_width
, s
->last_scr_height
);
1297 s
->last_width
= width
;
1298 s
->last_height
= height
;
1299 s
->last_ch
= cheight
;
1304 rgb_to_pixel_dup_table
[get_depth_index(s
->ds
)];
1305 full_update
|= update_palette16(s
);
1306 palette
= s
->last_palette
;
1307 x_incr
= cw
* ((ds_get_bits_per_pixel(s
->ds
) + 7) >> 3);
1309 cursor_offset
= ((s
->cr
[0x0e] << 8) | s
->cr
[0x0f]) - s
->start_addr
;
1310 if (cursor_offset
!= s
->cursor_offset
||
1311 s
->cr
[0xa] != s
->cursor_start
||
1312 s
->cr
[0xb] != s
->cursor_end
) {
1313 /* if the cursor position changed, we update the old and new
1315 if (s
->cursor_offset
< CH_ATTR_SIZE
)
1316 s
->last_ch_attr
[s
->cursor_offset
] = -1;
1317 if (cursor_offset
< CH_ATTR_SIZE
)
1318 s
->last_ch_attr
[cursor_offset
] = -1;
1319 s
->cursor_offset
= cursor_offset
;
1320 s
->cursor_start
= s
->cr
[0xa];
1321 s
->cursor_end
= s
->cr
[0xb];
1323 cursor_ptr
= s
->vram_ptr
+ (s
->start_addr
+ cursor_offset
) * 4;
1325 depth_index
= get_depth_index(s
->ds
);
1327 vga_draw_glyph8
= vga_draw_glyph16_table
[depth_index
];
1329 vga_draw_glyph8
= vga_draw_glyph8_table
[depth_index
];
1330 vga_draw_glyph9
= vga_draw_glyph9_table
[depth_index
];
1332 dest
= ds_get_data(s
->ds
);
1333 linesize
= ds_get_linesize(s
->ds
);
1334 ch_attr_ptr
= s
->last_ch_attr
;
1336 offset
= s
->start_addr
* 4;
1337 for(cy
= 0; cy
< height
; cy
++) {
1339 src
= s
->vram_ptr
+ offset
;
1342 for(cx
= 0; cx
< width
; cx
++) {
1343 ch_attr
= *(uint16_t *)src
;
1344 if (full_update
|| ch_attr
!= *ch_attr_ptr
) {
1349 *ch_attr_ptr
= ch_attr
;
1350 #ifdef HOST_WORDS_BIGENDIAN
1352 cattr
= ch_attr
& 0xff;
1354 ch
= ch_attr
& 0xff;
1355 cattr
= ch_attr
>> 8;
1357 font_ptr
= font_base
[(cattr
>> 3) & 1];
1358 font_ptr
+= 32 * 4 * ch
;
1359 bgcol
= palette
[cattr
>> 4];
1360 fgcol
= palette
[cattr
& 0x0f];
1362 vga_draw_glyph8(d1
, linesize
,
1363 font_ptr
, cheight
, fgcol
, bgcol
);
1366 if (ch
>= 0xb0 && ch
<= 0xdf && (s
->ar
[0x10] & 0x04))
1368 vga_draw_glyph9(d1
, linesize
,
1369 font_ptr
, cheight
, fgcol
, bgcol
, dup9
);
1371 if (src
== cursor_ptr
&&
1372 !(s
->cr
[0x0a] & 0x20)) {
1373 int line_start
, line_last
, h
;
1374 /* draw the cursor */
1375 line_start
= s
->cr
[0x0a] & 0x1f;
1376 line_last
= s
->cr
[0x0b] & 0x1f;
1377 /* XXX: check that */
1378 if (line_last
> cheight
- 1)
1379 line_last
= cheight
- 1;
1380 if (line_last
>= line_start
&& line_start
< cheight
) {
1381 h
= line_last
- line_start
+ 1;
1382 d
= d1
+ linesize
* line_start
;
1384 vga_draw_glyph8(d
, linesize
,
1385 cursor_glyph
, h
, fgcol
, bgcol
);
1387 vga_draw_glyph9(d
, linesize
,
1388 cursor_glyph
, h
, fgcol
, bgcol
, 1);
1398 dpy_update(s
->ds
, cx_min
* cw
, cy
* cheight
,
1399 (cx_max
- cx_min
+ 1) * cw
, cheight
);
1401 dest
+= linesize
* cheight
;
1402 line1
= line
+ cheight
;
1403 offset
+= line_offset
;
1404 if (line
< s
->line_compare
&& line1
>= s
->line_compare
) {
1425 static vga_draw_line_func
* const vga_draw_line_table
[NB_DEPTHS
* VGA_DRAW_LINE_NB
] = {
1435 vga_draw_line2d2_16
,
1436 vga_draw_line2d2_16
,
1437 vga_draw_line2d2_32
,
1438 vga_draw_line2d2_32
,
1439 vga_draw_line2d2_16
,
1440 vga_draw_line2d2_16
,
1451 vga_draw_line4d2_16
,
1452 vga_draw_line4d2_16
,
1453 vga_draw_line4d2_32
,
1454 vga_draw_line4d2_32
,
1455 vga_draw_line4d2_16
,
1456 vga_draw_line4d2_16
,
1459 vga_draw_line8d2_16
,
1460 vga_draw_line8d2_16
,
1461 vga_draw_line8d2_32
,
1462 vga_draw_line8d2_32
,
1463 vga_draw_line8d2_16
,
1464 vga_draw_line8d2_16
,
1478 vga_draw_line15_32bgr
,
1479 vga_draw_line15_15bgr
,
1480 vga_draw_line15_16bgr
,
1486 vga_draw_line16_32bgr
,
1487 vga_draw_line16_15bgr
,
1488 vga_draw_line16_16bgr
,
1494 vga_draw_line24_32bgr
,
1495 vga_draw_line24_15bgr
,
1496 vga_draw_line24_16bgr
,
1502 vga_draw_line32_32bgr
,
1503 vga_draw_line32_15bgr
,
1504 vga_draw_line32_16bgr
,
1507 static int vga_get_bpp(VGACommonState
*s
)
1510 #ifdef CONFIG_BOCHS_VBE
1511 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1512 ret
= s
->vbe_regs
[VBE_DISPI_INDEX_BPP
];
1521 static void vga_get_resolution(VGACommonState
*s
, int *pwidth
, int *pheight
)
1525 #ifdef CONFIG_BOCHS_VBE
1526 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1527 width
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
];
1528 height
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
];
1532 width
= (s
->cr
[0x01] + 1) * 8;
1533 height
= s
->cr
[0x12] |
1534 ((s
->cr
[0x07] & 0x02) << 7) |
1535 ((s
->cr
[0x07] & 0x40) << 3);
1536 height
= (height
+ 1);
1542 void vga_invalidate_scanlines(VGACommonState
*s
, int y1
, int y2
)
1545 if (y1
>= VGA_MAX_HEIGHT
)
1547 if (y2
>= VGA_MAX_HEIGHT
)
1548 y2
= VGA_MAX_HEIGHT
;
1549 for(y
= y1
; y
< y2
; y
++) {
1550 s
->invalidated_y_table
[y
>> 5] |= 1 << (y
& 0x1f);
1554 static void vga_sync_dirty_bitmap(VGACommonState
*s
)
1557 cpu_physical_sync_dirty_bitmap(s
->map_addr
, s
->map_end
);
1559 if (s
->lfb_vram_mapped
) {
1560 cpu_physical_sync_dirty_bitmap(isa_mem_base
+ 0xa0000, 0xa8000);
1561 cpu_physical_sync_dirty_bitmap(isa_mem_base
+ 0xa8000, 0xb0000);
1564 #ifdef CONFIG_BOCHS_VBE
1565 if (s
->vbe_mapped
) {
1566 cpu_physical_sync_dirty_bitmap(VBE_DISPI_LFB_PHYSICAL_ADDRESS
,
1567 VBE_DISPI_LFB_PHYSICAL_ADDRESS
+ s
->vram_size
);
1573 void vga_dirty_log_start(VGACommonState
*s
)
1576 cpu_physical_log_start(s
->map_addr
, s
->map_end
- s
->map_addr
);
1579 if (s
->lfb_vram_mapped
) {
1580 cpu_physical_log_start(isa_mem_base
+ 0xa0000, 0x8000);
1581 cpu_physical_log_start(isa_mem_base
+ 0xa8000, 0x8000);
1584 #ifdef CONFIG_BOCHS_VBE
1585 if (s
->vbe_mapped
) {
1586 cpu_physical_log_start(VBE_DISPI_LFB_PHYSICAL_ADDRESS
, s
->vram_size
);
1591 void vga_dirty_log_stop(VGACommonState
*s
)
1594 cpu_physical_log_stop(s
->map_addr
, s
->map_end
- s
->map_addr
);
1597 if (s
->lfb_vram_mapped
) {
1598 cpu_physical_log_stop(isa_mem_base
+ 0xa0000, 0x8000);
1599 cpu_physical_log_stop(isa_mem_base
+ 0xa8000, 0x8000);
1602 #ifdef CONFIG_BOCHS_VBE
1603 if (s
->vbe_mapped
) {
1604 cpu_physical_log_stop(VBE_DISPI_LFB_PHYSICAL_ADDRESS
, s
->vram_size
);
1609 void vga_dirty_log_restart(VGACommonState
*s
)
1611 vga_dirty_log_stop(s
);
1612 vga_dirty_log_start(s
);
1618 static void vga_draw_graphic(VGACommonState
*s
, int full_update
)
1620 int y1
, y
, update
, linesize
, y_start
, double_scan
, mask
, depth
;
1621 int width
, height
, shift_control
, line_offset
, bwidth
, bits
;
1622 ram_addr_t page0
, page1
, page_min
, page_max
;
1623 int disp_width
, multi_scan
, multi_run
;
1625 uint32_t v
, addr1
, addr
;
1626 vga_draw_line_func
*vga_draw_line
;
1628 full_update
|= update_basic_params(s
);
1631 vga_sync_dirty_bitmap(s
);
1633 s
->get_resolution(s
, &width
, &height
);
1636 shift_control
= (s
->gr
[0x05] >> 5) & 3;
1637 double_scan
= (s
->cr
[0x09] >> 7);
1638 if (shift_control
!= 1) {
1639 multi_scan
= (((s
->cr
[0x09] & 0x1f) + 1) << double_scan
) - 1;
1641 /* in CGA modes, multi_scan is ignored */
1642 /* XXX: is it correct ? */
1643 multi_scan
= double_scan
;
1645 multi_run
= multi_scan
;
1646 if (shift_control
!= s
->shift_control
||
1647 double_scan
!= s
->double_scan
) {
1649 s
->shift_control
= shift_control
;
1650 s
->double_scan
= double_scan
;
1653 if (shift_control
== 0) {
1654 if (s
->sr
[0x01] & 8) {
1657 } else if (shift_control
== 1) {
1658 if (s
->sr
[0x01] & 8) {
1663 depth
= s
->get_bpp(s
);
1664 if (s
->line_offset
!= s
->last_line_offset
||
1665 disp_width
!= s
->last_width
||
1666 height
!= s
->last_height
||
1667 s
->last_depth
!= depth
) {
1668 #if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
1669 if (depth
== 16 || depth
== 32) {
1673 qemu_free_displaysurface(s
->ds
);
1674 s
->ds
->surface
= qemu_create_displaysurface_from(disp_width
, height
, depth
,
1676 s
->vram_ptr
+ (s
->start_addr
* 4));
1677 #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
1678 s
->ds
->surface
->pf
= qemu_different_endianness_pixelformat(depth
);
1682 qemu_console_resize(s
->ds
, disp_width
, height
);
1684 s
->last_scr_width
= disp_width
;
1685 s
->last_scr_height
= height
;
1686 s
->last_width
= disp_width
;
1687 s
->last_height
= height
;
1688 s
->last_line_offset
= s
->line_offset
;
1689 s
->last_depth
= depth
;
1691 } else if (is_buffer_shared(s
->ds
->surface
) &&
1692 (full_update
|| s
->ds
->surface
->data
!= s
->vram_ptr
+ (s
->start_addr
* 4))) {
1693 s
->ds
->surface
->data
= s
->vram_ptr
+ (s
->start_addr
* 4);
1698 rgb_to_pixel_dup_table
[get_depth_index(s
->ds
)];
1700 if (shift_control
== 0) {
1701 full_update
|= update_palette16(s
);
1702 if (s
->sr
[0x01] & 8) {
1703 v
= VGA_DRAW_LINE4D2
;
1708 } else if (shift_control
== 1) {
1709 full_update
|= update_palette16(s
);
1710 if (s
->sr
[0x01] & 8) {
1711 v
= VGA_DRAW_LINE2D2
;
1717 switch(s
->get_bpp(s
)) {
1720 full_update
|= update_palette256(s
);
1721 v
= VGA_DRAW_LINE8D2
;
1725 full_update
|= update_palette256(s
);
1730 v
= VGA_DRAW_LINE15
;
1734 v
= VGA_DRAW_LINE16
;
1738 v
= VGA_DRAW_LINE24
;
1742 v
= VGA_DRAW_LINE32
;
1747 vga_draw_line
= vga_draw_line_table
[v
* NB_DEPTHS
+ get_depth_index(s
->ds
)];
1749 if (!is_buffer_shared(s
->ds
->surface
) && s
->cursor_invalidate
)
1750 s
->cursor_invalidate(s
);
1752 line_offset
= s
->line_offset
;
1754 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",
1755 width
, height
, v
, line_offset
, s
->cr
[9], s
->cr
[0x17], s
->line_compare
, s
->sr
[0x01]);
1757 addr1
= (s
->start_addr
* 4);
1758 bwidth
= (width
* bits
+ 7) / 8;
1762 d
= ds_get_data(s
->ds
);
1763 linesize
= ds_get_linesize(s
->ds
);
1765 for(y
= 0; y
< height
; y
++) {
1767 if (!(s
->cr
[0x17] & 1)) {
1769 /* CGA compatibility handling */
1770 shift
= 14 + ((s
->cr
[0x17] >> 6) & 1);
1771 addr
= (addr
& ~(1 << shift
)) | ((y1
& 1) << shift
);
1773 if (!(s
->cr
[0x17] & 2)) {
1774 addr
= (addr
& ~0x8000) | ((y1
& 2) << 14);
1776 page0
= s
->vram_offset
+ (addr
& TARGET_PAGE_MASK
);
1777 page1
= s
->vram_offset
+ ((addr
+ bwidth
- 1) & TARGET_PAGE_MASK
);
1778 update
= full_update
|
1779 cpu_physical_memory_get_dirty(page0
, VGA_DIRTY_FLAG
) |
1780 cpu_physical_memory_get_dirty(page1
, VGA_DIRTY_FLAG
);
1781 if ((page1
- page0
) > TARGET_PAGE_SIZE
) {
1782 /* if wide line, can use another page */
1783 update
|= cpu_physical_memory_get_dirty(page0
+ TARGET_PAGE_SIZE
,
1786 /* explicit invalidation for the hardware cursor */
1787 update
|= (s
->invalidated_y_table
[y
>> 5] >> (y
& 0x1f)) & 1;
1791 if (page0
< page_min
)
1793 if (page1
> page_max
)
1795 if (!(is_buffer_shared(s
->ds
->surface
))) {
1796 vga_draw_line(s
, d
, s
->vram_ptr
+ addr
, width
);
1797 if (s
->cursor_draw_line
)
1798 s
->cursor_draw_line(s
, d
, y
);
1802 /* flush to display */
1803 dpy_update(s
->ds
, 0, y_start
,
1804 disp_width
, y
- y_start
);
1809 mask
= (s
->cr
[0x17] & 3) ^ 3;
1810 if ((y1
& mask
) == mask
)
1811 addr1
+= line_offset
;
1813 multi_run
= multi_scan
;
1817 /* line compare acts on the displayed lines */
1818 if (y
== s
->line_compare
)
1823 /* flush to display */
1824 dpy_update(s
->ds
, 0, y_start
,
1825 disp_width
, y
- y_start
);
1827 /* reset modified pages */
1828 if (page_max
>= page_min
) {
1829 cpu_physical_memory_reset_dirty(page_min
, page_max
+ TARGET_PAGE_SIZE
,
1832 memset(s
->invalidated_y_table
, 0, ((height
+ 31) >> 5) * 4);
1835 static void vga_draw_blank(VGACommonState
*s
, int full_update
)
1842 if (s
->last_scr_width
<= 0 || s
->last_scr_height
<= 0)
1846 rgb_to_pixel_dup_table
[get_depth_index(s
->ds
)];
1847 if (ds_get_bits_per_pixel(s
->ds
) == 8)
1848 val
= s
->rgb_to_pixel(0, 0, 0);
1851 w
= s
->last_scr_width
* ((ds_get_bits_per_pixel(s
->ds
) + 7) >> 3);
1852 d
= ds_get_data(s
->ds
);
1853 for(i
= 0; i
< s
->last_scr_height
; i
++) {
1855 d
+= ds_get_linesize(s
->ds
);
1857 dpy_update(s
->ds
, 0, 0,
1858 s
->last_scr_width
, s
->last_scr_height
);
1861 #define GMODE_TEXT 0
1862 #define GMODE_GRAPH 1
1863 #define GMODE_BLANK 2
1865 static void vga_update_display(void *opaque
)
1867 VGACommonState
*s
= opaque
;
1868 int full_update
, graphic_mode
;
1870 if (ds_get_bits_per_pixel(s
->ds
) == 0) {
1874 if (!(s
->ar_index
& 0x20)) {
1875 graphic_mode
= GMODE_BLANK
;
1877 graphic_mode
= s
->gr
[6] & 1;
1879 if (graphic_mode
!= s
->graphic_mode
) {
1880 s
->graphic_mode
= graphic_mode
;
1883 switch(graphic_mode
) {
1885 vga_draw_text(s
, full_update
);
1888 vga_draw_graphic(s
, full_update
);
1892 vga_draw_blank(s
, full_update
);
1898 /* force a full display refresh */
1899 static void vga_invalidate_display(void *opaque
)
1901 VGACommonState
*s
= opaque
;
1904 s
->last_height
= -1;
1907 void vga_common_reset(VGACommonState
*s
)
1913 s
->lfb_vram_mapped
= 0;
1915 memset(s
->sr
, '\0', sizeof(s
->sr
));
1917 memset(s
->gr
, '\0', sizeof(s
->gr
));
1919 memset(s
->ar
, '\0', sizeof(s
->ar
));
1920 s
->ar_flip_flop
= 0;
1922 memset(s
->cr
, '\0', sizeof(s
->cr
));
1928 s
->dac_sub_index
= 0;
1929 s
->dac_read_index
= 0;
1930 s
->dac_write_index
= 0;
1931 memset(s
->dac_cache
, '\0', sizeof(s
->dac_cache
));
1933 memset(s
->palette
, '\0', sizeof(s
->palette
));
1935 #ifdef CONFIG_BOCHS_VBE
1937 memset(s
->vbe_regs
, '\0', sizeof(s
->vbe_regs
));
1938 s
->vbe_regs
[VBE_DISPI_INDEX_ID
] = VBE_DISPI_ID5
;
1939 s
->vbe_start_addr
= 0;
1940 s
->vbe_line_offset
= 0;
1941 s
->vbe_bank_mask
= (s
->vram_size
>> 16) - 1;
1943 memset(s
->font_offsets
, '\0', sizeof(s
->font_offsets
));
1944 s
->graphic_mode
= -1; /* force full update */
1945 s
->shift_control
= 0;
1948 s
->line_compare
= 0;
1950 s
->plane_updated
= 0;
1955 s
->last_scr_width
= 0;
1956 s
->last_scr_height
= 0;
1957 s
->cursor_start
= 0;
1959 s
->cursor_offset
= 0;
1960 memset(s
->invalidated_y_table
, '\0', sizeof(s
->invalidated_y_table
));
1961 memset(s
->last_palette
, '\0', sizeof(s
->last_palette
));
1962 memset(s
->last_ch_attr
, '\0', sizeof(s
->last_ch_attr
));
1963 switch (vga_retrace_method
) {
1964 case VGA_RETRACE_DUMB
:
1966 case VGA_RETRACE_PRECISE
:
1967 memset(&s
->retrace_info
, 0, sizeof (s
->retrace_info
));
1972 static void vga_reset(void *opaque
)
1974 VGACommonState
*s
= opaque
;
1975 vga_common_reset(s
);
1978 #define TEXTMODE_X(x) ((x) % width)
1979 #define TEXTMODE_Y(x) ((x) / width)
1980 #define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1981 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1982 /* relay text rendering to the display driver
1983 * instead of doing a full vga_update_display() */
1984 static void vga_update_text(void *opaque
, console_ch_t
*chardata
)
1986 VGACommonState
*s
= opaque
;
1987 int graphic_mode
, i
, cursor_offset
, cursor_visible
;
1988 int cw
, cheight
, width
, height
, size
, c_min
, c_max
;
1990 console_ch_t
*dst
, val
;
1991 char msg_buffer
[80];
1992 int full_update
= 0;
1994 if (!(s
->ar_index
& 0x20)) {
1995 graphic_mode
= GMODE_BLANK
;
1997 graphic_mode
= s
->gr
[6] & 1;
1999 if (graphic_mode
!= s
->graphic_mode
) {
2000 s
->graphic_mode
= graphic_mode
;
2003 if (s
->last_width
== -1) {
2008 switch (graphic_mode
) {
2010 /* TODO: update palette */
2011 full_update
|= update_basic_params(s
);
2013 /* total width & height */
2014 cheight
= (s
->cr
[9] & 0x1f) + 1;
2016 if (!(s
->sr
[1] & 0x01))
2018 if (s
->sr
[1] & 0x08)
2019 cw
= 16; /* NOTE: no 18 pixel wide */
2020 width
= (s
->cr
[0x01] + 1);
2021 if (s
->cr
[0x06] == 100) {
2022 /* ugly hack for CGA 160x100x16 - explain me the logic */
2025 height
= s
->cr
[0x12] |
2026 ((s
->cr
[0x07] & 0x02) << 7) |
2027 ((s
->cr
[0x07] & 0x40) << 3);
2028 height
= (height
+ 1) / cheight
;
2031 size
= (height
* width
);
2032 if (size
> CH_ATTR_SIZE
) {
2036 snprintf(msg_buffer
, sizeof(msg_buffer
), "%i x %i Text mode",
2041 if (width
!= s
->last_width
|| height
!= s
->last_height
||
2042 cw
!= s
->last_cw
|| cheight
!= s
->last_ch
) {
2043 s
->last_scr_width
= width
* cw
;
2044 s
->last_scr_height
= height
* cheight
;
2045 s
->ds
->surface
->width
= width
;
2046 s
->ds
->surface
->height
= height
;
2048 s
->last_width
= width
;
2049 s
->last_height
= height
;
2050 s
->last_ch
= cheight
;
2055 /* Update "hardware" cursor */
2056 cursor_offset
= ((s
->cr
[0x0e] << 8) | s
->cr
[0x0f]) - s
->start_addr
;
2057 if (cursor_offset
!= s
->cursor_offset
||
2058 s
->cr
[0xa] != s
->cursor_start
||
2059 s
->cr
[0xb] != s
->cursor_end
|| full_update
) {
2060 cursor_visible
= !(s
->cr
[0xa] & 0x20);
2061 if (cursor_visible
&& cursor_offset
< size
&& cursor_offset
>= 0)
2063 TEXTMODE_X(cursor_offset
),
2064 TEXTMODE_Y(cursor_offset
));
2066 dpy_cursor(s
->ds
, -1, -1);
2067 s
->cursor_offset
= cursor_offset
;
2068 s
->cursor_start
= s
->cr
[0xa];
2069 s
->cursor_end
= s
->cr
[0xb];
2072 src
= (uint32_t *) s
->vram_ptr
+ s
->start_addr
;
2076 for (i
= 0; i
< size
; src
++, dst
++, i
++)
2077 console_write_ch(dst
, VMEM2CHTYPE(le32_to_cpu(*src
)));
2079 dpy_update(s
->ds
, 0, 0, width
, height
);
2083 for (i
= 0; i
< size
; src
++, dst
++, i
++) {
2084 console_write_ch(&val
, VMEM2CHTYPE(le32_to_cpu(*src
)));
2092 for (; i
< size
; src
++, dst
++, i
++) {
2093 console_write_ch(&val
, VMEM2CHTYPE(le32_to_cpu(*src
)));
2100 if (c_min
<= c_max
) {
2101 i
= TEXTMODE_Y(c_min
);
2102 dpy_update(s
->ds
, 0, i
, width
, TEXTMODE_Y(c_max
) - i
+ 1);
2111 s
->get_resolution(s
, &width
, &height
);
2112 snprintf(msg_buffer
, sizeof(msg_buffer
), "%i x %i Graphic mode",
2120 snprintf(msg_buffer
, sizeof(msg_buffer
), "VGA Blank mode");
2124 /* Display a message */
2126 s
->last_height
= height
= 3;
2127 dpy_cursor(s
->ds
, -1, -1);
2128 s
->ds
->surface
->width
= s
->last_width
;
2129 s
->ds
->surface
->height
= height
;
2132 for (dst
= chardata
, i
= 0; i
< s
->last_width
* height
; i
++)
2133 console_write_ch(dst
++, ' ');
2135 size
= strlen(msg_buffer
);
2136 width
= (s
->last_width
- size
) / 2;
2137 dst
= chardata
+ s
->last_width
+ width
;
2138 for (i
= 0; i
< size
; i
++)
2139 console_write_ch(dst
++, 0x00200100 | msg_buffer
[i
]);
2141 dpy_update(s
->ds
, 0, 0, s
->last_width
, height
);
2144 CPUReadMemoryFunc
* const vga_mem_read
[3] = {
2150 CPUWriteMemoryFunc
* const vga_mem_write
[3] = {
2156 static int vga_common_post_load(void *opaque
, int version_id
)
2158 VGACommonState
*s
= opaque
;
2161 s
->graphic_mode
= -1;
2165 const VMStateDescription vmstate_vga_common
= {
2168 .minimum_version_id
= 2,
2169 .minimum_version_id_old
= 2,
2170 .post_load
= vga_common_post_load
,
2171 .fields
= (VMStateField
[]) {
2172 VMSTATE_UINT32(latch
, VGACommonState
),
2173 VMSTATE_UINT8(sr_index
, VGACommonState
),
2174 VMSTATE_PARTIAL_BUFFER(sr
, VGACommonState
, 8),
2175 VMSTATE_UINT8(gr_index
, VGACommonState
),
2176 VMSTATE_PARTIAL_BUFFER(gr
, VGACommonState
, 16),
2177 VMSTATE_UINT8(ar_index
, VGACommonState
),
2178 VMSTATE_BUFFER(ar
, VGACommonState
),
2179 VMSTATE_INT32(ar_flip_flop
, VGACommonState
),
2180 VMSTATE_UINT8(cr_index
, VGACommonState
),
2181 VMSTATE_BUFFER(cr
, VGACommonState
),
2182 VMSTATE_UINT8(msr
, VGACommonState
),
2183 VMSTATE_UINT8(fcr
, VGACommonState
),
2184 VMSTATE_UINT8(st00
, VGACommonState
),
2185 VMSTATE_UINT8(st01
, VGACommonState
),
2187 VMSTATE_UINT8(dac_state
, VGACommonState
),
2188 VMSTATE_UINT8(dac_sub_index
, VGACommonState
),
2189 VMSTATE_UINT8(dac_read_index
, VGACommonState
),
2190 VMSTATE_UINT8(dac_write_index
, VGACommonState
),
2191 VMSTATE_BUFFER(dac_cache
, VGACommonState
),
2192 VMSTATE_BUFFER(palette
, VGACommonState
),
2194 VMSTATE_INT32(bank_offset
, VGACommonState
),
2195 VMSTATE_UINT8_EQUAL(is_vbe_vmstate
, VGACommonState
),
2196 #ifdef CONFIG_BOCHS_VBE
2197 VMSTATE_UINT16(vbe_index
, VGACommonState
),
2198 VMSTATE_UINT16_ARRAY(vbe_regs
, VGACommonState
, VBE_DISPI_INDEX_NB
),
2199 VMSTATE_UINT32(vbe_start_addr
, VGACommonState
),
2200 VMSTATE_UINT32(vbe_line_offset
, VGACommonState
),
2201 VMSTATE_UINT32(vbe_bank_mask
, VGACommonState
),
2203 VMSTATE_END_OF_LIST()
2207 void vga_common_init(VGACommonState
*s
, int vga_ram_size
)
2211 for(i
= 0;i
< 256; i
++) {
2213 for(j
= 0; j
< 8; j
++) {
2214 v
|= ((i
>> j
) & 1) << (j
* 4);
2219 for(j
= 0; j
< 4; j
++) {
2220 v
|= ((i
>> (2 * j
)) & 3) << (j
* 4);
2224 for(i
= 0; i
< 16; i
++) {
2226 for(j
= 0; j
< 4; j
++) {
2229 v
|= b
<< (2 * j
+ 1);
2234 #ifdef CONFIG_BOCHS_VBE
2235 s
->is_vbe_vmstate
= 1;
2237 s
->is_vbe_vmstate
= 0;
2239 s
->vram_offset
= qemu_ram_alloc(NULL
, "vga.vram", vga_ram_size
);
2240 s
->vram_ptr
= qemu_get_ram_ptr(s
->vram_offset
);
2241 s
->vram_size
= vga_ram_size
;
2242 s
->get_bpp
= vga_get_bpp
;
2243 s
->get_offsets
= vga_get_offsets
;
2244 s
->get_resolution
= vga_get_resolution
;
2245 s
->update
= vga_update_display
;
2246 s
->invalidate
= vga_invalidate_display
;
2247 s
->screen_dump
= vga_screen_dump
;
2248 s
->text_update
= vga_update_text
;
2249 switch (vga_retrace_method
) {
2250 case VGA_RETRACE_DUMB
:
2251 s
->retrace
= vga_dumb_retrace
;
2252 s
->update_retrace_info
= vga_dumb_update_retrace_info
;
2255 case VGA_RETRACE_PRECISE
:
2256 s
->retrace
= vga_precise_retrace
;
2257 s
->update_retrace_info
= vga_precise_update_retrace_info
;
2262 /* used by both ISA and PCI */
2263 int vga_init_io(VGACommonState
*s
)
2265 register_ioport_write(0x3c0, 16, 1, vga_ioport_write
, s
);
2267 register_ioport_write(0x3b4, 2, 1, vga_ioport_write
, s
);
2268 register_ioport_write(0x3d4, 2, 1, vga_ioport_write
, s
);
2269 register_ioport_write(0x3ba, 1, 1, vga_ioport_write
, s
);
2270 register_ioport_write(0x3da, 1, 1, vga_ioport_write
, s
);
2272 register_ioport_read(0x3c0, 16, 1, vga_ioport_read
, s
);
2274 register_ioport_read(0x3b4, 2, 1, vga_ioport_read
, s
);
2275 register_ioport_read(0x3d4, 2, 1, vga_ioport_read
, s
);
2276 register_ioport_read(0x3ba, 1, 1, vga_ioport_read
, s
);
2277 register_ioport_read(0x3da, 1, 1, vga_ioport_read
, s
);
2279 #ifdef CONFIG_BOCHS_VBE
2280 #if defined (TARGET_I386)
2281 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index
, s
);
2282 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data
, s
);
2284 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index
, s
);
2285 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data
, s
);
2287 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index
, s
);
2288 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data
, s
);
2290 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index
, s
);
2291 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data
, s
);
2293 #endif /* CONFIG_BOCHS_VBE */
2295 return cpu_register_io_memory(vga_mem_read
, vga_mem_write
, s
,
2296 DEVICE_LITTLE_ENDIAN
);
2299 void vga_init(VGACommonState
*s
)
2303 qemu_register_reset(vga_reset
, s
);
2307 vga_io_memory
= vga_init_io(s
);
2308 cpu_register_physical_memory(isa_mem_base
+ 0x000a0000, 0x20000,
2310 qemu_register_coalesced_mmio(isa_mem_base
+ 0x000a0000, 0x20000);
2313 void vga_init_vbe(VGACommonState
*s
)
2315 #ifdef CONFIG_BOCHS_VBE
2316 /* XXX: use optimized standard vga accesses */
2317 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS
,
2318 VGA_RAM_SIZE
, s
->vram_offset
);
2322 /********************************************************/
2323 /* vga screen dump */
2325 static void vga_save_dpy_update(DisplayState
*ds
,
2326 int x
, int y
, int w
, int h
)
2328 if (screen_dump_filename
) {
2329 ppm_save(screen_dump_filename
, ds
->surface
);
2330 screen_dump_filename
= NULL
;
2334 static void vga_save_dpy_resize(DisplayState
*s
)
2338 static void vga_save_dpy_refresh(DisplayState
*s
)
2342 int ppm_save(const char *filename
, struct DisplaySurface
*ds
)
2350 f
= fopen(filename
, "wb");
2353 fprintf(f
, "P6\n%d %d\n%d\n",
2354 ds
->width
, ds
->height
, 255);
2356 for(y
= 0; y
< ds
->height
; y
++) {
2358 for(x
= 0; x
< ds
->width
; x
++) {
2359 if (ds
->pf
.bits_per_pixel
== 32)
2362 v
= (uint32_t) (*(uint16_t *)d
);
2363 r
= ((v
>> ds
->pf
.rshift
) & ds
->pf
.rmax
) * 256 /
2365 g
= ((v
>> ds
->pf
.gshift
) & ds
->pf
.gmax
) * 256 /
2367 b
= ((v
>> ds
->pf
.bshift
) & ds
->pf
.bmax
) * 256 /
2372 d
+= ds
->pf
.bytes_per_pixel
;
2380 static DisplayChangeListener
* vga_screen_dump_init(DisplayState
*ds
)
2382 DisplayChangeListener
*dcl
;
2384 dcl
= qemu_mallocz(sizeof(DisplayChangeListener
));
2385 dcl
->dpy_update
= vga_save_dpy_update
;
2386 dcl
->dpy_resize
= vga_save_dpy_resize
;
2387 dcl
->dpy_refresh
= vga_save_dpy_refresh
;
2388 register_displaychangelistener(ds
, dcl
);
2392 /* save the vga display in a PPM image even if no display is
2394 static void vga_screen_dump(void *opaque
, const char *filename
)
2396 VGACommonState
*s
= opaque
;
2398 if (!screen_dump_dcl
)
2399 screen_dump_dcl
= vga_screen_dump_init(s
->ds
);
2401 screen_dump_filename
= (char *)filename
;
2402 vga_invalidate_display(s
);