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"
31 #include "exec-memory.h"
34 //#define DEBUG_VGA_MEM
35 //#define DEBUG_VGA_REG
37 //#define DEBUG_BOCHS_VBE
39 /* force some bits to zero */
40 const uint8_t sr_mask
[8] = {
51 const uint8_t gr_mask
[16] = {
70 #define cbswap_32(__x) \
72 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
73 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
74 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
75 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
77 #ifdef HOST_WORDS_BIGENDIAN
78 #define PAT(x) cbswap_32(x)
83 #ifdef HOST_WORDS_BIGENDIAN
89 #ifdef HOST_WORDS_BIGENDIAN
90 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
92 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
95 static const uint32_t mask16
[16] = {
116 #ifdef HOST_WORDS_BIGENDIAN
119 #define PAT(x) cbswap_32(x)
122 static const uint32_t dmask16
[16] = {
141 static const uint32_t dmask4
[4] = {
148 static uint32_t expand4
[256];
149 static uint16_t expand2
[256];
150 static uint8_t expand4to8
[16];
152 static void vga_screen_dump(void *opaque
, const char *filename
);
153 static char *screen_dump_filename
;
154 static DisplayChangeListener
*screen_dump_dcl
;
156 static void vga_dumb_update_retrace_info(VGACommonState
*s
)
161 static void vga_precise_update_retrace_info(VGACommonState
*s
)
164 int hretr_start_char
;
165 int hretr_skew_chars
;
169 int vretr_start_line
;
178 const int clk_hz
[] = {25175000, 28322000, 25175000, 25175000};
179 int64_t chars_per_sec
;
180 struct vga_precise_retrace
*r
= &s
->retrace_info
.precise
;
182 htotal_chars
= s
->cr
[0x00] + 5;
183 hretr_start_char
= s
->cr
[0x04];
184 hretr_skew_chars
= (s
->cr
[0x05] >> 5) & 3;
185 hretr_end_char
= s
->cr
[0x05] & 0x1f;
187 vtotal_lines
= (s
->cr
[0x06]
188 | (((s
->cr
[0x07] & 1) | ((s
->cr
[0x07] >> 4) & 2)) << 8)) + 2
190 vretr_start_line
= s
->cr
[0x10]
191 | ((((s
->cr
[0x07] >> 2) & 1) | ((s
->cr
[0x07] >> 6) & 2)) << 8)
193 vretr_end_line
= s
->cr
[0x11] & 0xf;
197 clocking_mode
= (s
->sr
[0x01] >> 3) & 1;
198 clock_sel
= (s
->msr
>> 2) & 3;
199 dots
= (s
->msr
& 1) ? 8 : 9;
201 chars_per_sec
= clk_hz
[clock_sel
] / dots
;
203 htotal_chars
<<= clocking_mode
;
205 r
->total_chars
= vtotal_lines
* htotal_chars
;
207 r
->ticks_per_char
= get_ticks_per_sec() / (r
->total_chars
* r
->freq
);
209 r
->ticks_per_char
= get_ticks_per_sec() / chars_per_sec
;
212 r
->vstart
= vretr_start_line
;
213 r
->vend
= r
->vstart
+ vretr_end_line
+ 1;
215 r
->hstart
= hretr_start_char
+ hretr_skew_chars
;
216 r
->hend
= r
->hstart
+ hretr_end_char
+ 1;
217 r
->htotal
= htotal_chars
;
220 div2
= (s
->cr
[0x17] >> 2) & 1;
221 sldiv2
= (s
->cr
[0x17] >> 3) & 1;
231 "div2 = %d sldiv2 = %d\n"
232 "clocking_mode = %d\n"
233 "clock_sel = %d %d\n"
235 "ticks/char = %" PRId64
"\n"
237 (double) get_ticks_per_sec() / (r
->ticks_per_char
* r
->total_chars
),
255 static uint8_t vga_precise_retrace(VGACommonState
*s
)
257 struct vga_precise_retrace
*r
= &s
->retrace_info
.precise
;
258 uint8_t val
= s
->st01
& ~(ST01_V_RETRACE
| ST01_DISP_ENABLE
);
260 if (r
->total_chars
) {
261 int cur_line
, cur_line_char
, cur_char
;
264 cur_tick
= qemu_get_clock_ns(vm_clock
);
266 cur_char
= (cur_tick
/ r
->ticks_per_char
) % r
->total_chars
;
267 cur_line
= cur_char
/ r
->htotal
;
269 if (cur_line
>= r
->vstart
&& cur_line
<= r
->vend
) {
270 val
|= ST01_V_RETRACE
| ST01_DISP_ENABLE
;
272 cur_line_char
= cur_char
% r
->htotal
;
273 if (cur_line_char
>= r
->hstart
&& cur_line_char
<= r
->hend
) {
274 val
|= ST01_DISP_ENABLE
;
280 return s
->st01
^ (ST01_V_RETRACE
| ST01_DISP_ENABLE
);
284 static uint8_t vga_dumb_retrace(VGACommonState
*s
)
286 return s
->st01
^ (ST01_V_RETRACE
| ST01_DISP_ENABLE
);
289 int vga_ioport_invalid(VGACommonState
*s
, uint32_t addr
)
291 if (s
->msr
& MSR_COLOR_EMULATION
) {
293 return (addr
>= 0x3b0 && addr
<= 0x3bf);
296 return (addr
>= 0x3d0 && addr
<= 0x3df);
300 uint32_t vga_ioport_read(void *opaque
, uint32_t addr
)
302 VGACommonState
*s
= opaque
;
305 if (vga_ioport_invalid(s
, addr
)) {
310 if (s
->ar_flip_flop
== 0) {
317 index
= s
->ar_index
& 0x1f;
330 val
= s
->sr
[s
->sr_index
];
332 printf("vga: read SR%x = 0x%02x\n", s
->sr_index
, val
);
339 val
= s
->dac_write_index
;
342 val
= s
->palette
[s
->dac_read_index
* 3 + s
->dac_sub_index
];
343 if (++s
->dac_sub_index
== 3) {
344 s
->dac_sub_index
= 0;
358 val
= s
->gr
[s
->gr_index
];
360 printf("vga: read GR%x = 0x%02x\n", s
->gr_index
, val
);
369 val
= s
->cr
[s
->cr_index
];
371 printf("vga: read CR%x = 0x%02x\n", s
->cr_index
, val
);
376 /* just toggle to fool polling */
377 val
= s
->st01
= s
->retrace(s
);
385 #if defined(DEBUG_VGA)
386 printf("VGA: read addr=0x%04x data=0x%02x\n", addr
, val
);
391 void vga_ioport_write(void *opaque
, uint32_t addr
, uint32_t val
)
393 VGACommonState
*s
= opaque
;
396 /* check port range access depending on color/monochrome mode */
397 if (vga_ioport_invalid(s
, addr
)) {
401 printf("VGA: write addr=0x%04x data=0x%02x\n", addr
, val
);
406 if (s
->ar_flip_flop
== 0) {
410 index
= s
->ar_index
& 0x1f;
413 s
->ar
[index
] = val
& 0x3f;
416 s
->ar
[index
] = val
& ~0x10;
422 s
->ar
[index
] = val
& ~0xc0;
425 s
->ar
[index
] = val
& ~0xf0;
428 s
->ar
[index
] = val
& ~0xf0;
434 s
->ar_flip_flop
^= 1;
437 s
->msr
= val
& ~0x10;
438 s
->update_retrace_info(s
);
441 s
->sr_index
= val
& 7;
445 printf("vga: write SR%x = 0x%02x\n", s
->sr_index
, val
);
447 s
->sr
[s
->sr_index
] = val
& sr_mask
[s
->sr_index
];
448 if (s
->sr_index
== 1) s
->update_retrace_info(s
);
451 s
->dac_read_index
= val
;
452 s
->dac_sub_index
= 0;
456 s
->dac_write_index
= val
;
457 s
->dac_sub_index
= 0;
461 s
->dac_cache
[s
->dac_sub_index
] = val
;
462 if (++s
->dac_sub_index
== 3) {
463 memcpy(&s
->palette
[s
->dac_write_index
* 3], s
->dac_cache
, 3);
464 s
->dac_sub_index
= 0;
465 s
->dac_write_index
++;
469 s
->gr_index
= val
& 0x0f;
473 printf("vga: write GR%x = 0x%02x\n", s
->gr_index
, val
);
475 s
->gr
[s
->gr_index
] = val
& gr_mask
[s
->gr_index
];
484 printf("vga: write CR%x = 0x%02x\n", s
->cr_index
, val
);
486 /* handle CR0-7 protection */
487 if ((s
->cr
[0x11] & 0x80) && s
->cr_index
<= 7) {
488 /* can always write bit 4 of CR7 */
489 if (s
->cr_index
== 7)
490 s
->cr
[7] = (s
->cr
[7] & ~0x10) | (val
& 0x10);
493 s
->cr
[s
->cr_index
] = val
;
495 switch(s
->cr_index
) {
503 s
->update_retrace_info(s
);
514 #ifdef CONFIG_BOCHS_VBE
515 static uint32_t vbe_ioport_read_index(void *opaque
, uint32_t addr
)
517 VGACommonState
*s
= opaque
;
523 static uint32_t vbe_ioport_read_data(void *opaque
, uint32_t addr
)
525 VGACommonState
*s
= opaque
;
528 if (s
->vbe_index
< VBE_DISPI_INDEX_NB
) {
529 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_GETCAPS
) {
530 switch(s
->vbe_index
) {
531 /* XXX: do not hardcode ? */
532 case VBE_DISPI_INDEX_XRES
:
533 val
= VBE_DISPI_MAX_XRES
;
535 case VBE_DISPI_INDEX_YRES
:
536 val
= VBE_DISPI_MAX_YRES
;
538 case VBE_DISPI_INDEX_BPP
:
539 val
= VBE_DISPI_MAX_BPP
;
542 val
= s
->vbe_regs
[s
->vbe_index
];
546 val
= s
->vbe_regs
[s
->vbe_index
];
548 } else if (s
->vbe_index
== VBE_DISPI_INDEX_VIDEO_MEMORY_64K
) {
549 val
= s
->vram_size
/ (64 * 1024);
553 #ifdef DEBUG_BOCHS_VBE
554 printf("VBE: read index=0x%x val=0x%x\n", s
->vbe_index
, val
);
559 static void vbe_ioport_write_index(void *opaque
, uint32_t addr
, uint32_t val
)
561 VGACommonState
*s
= opaque
;
565 static void vbe_ioport_write_data(void *opaque
, uint32_t addr
, uint32_t val
)
567 VGACommonState
*s
= opaque
;
569 if (s
->vbe_index
<= VBE_DISPI_INDEX_NB
) {
570 #ifdef DEBUG_BOCHS_VBE
571 printf("VBE: write index=0x%x val=0x%x\n", s
->vbe_index
, val
);
573 switch(s
->vbe_index
) {
574 case VBE_DISPI_INDEX_ID
:
575 if (val
== VBE_DISPI_ID0
||
576 val
== VBE_DISPI_ID1
||
577 val
== VBE_DISPI_ID2
||
578 val
== VBE_DISPI_ID3
||
579 val
== VBE_DISPI_ID4
) {
580 s
->vbe_regs
[s
->vbe_index
] = val
;
583 case VBE_DISPI_INDEX_XRES
:
584 if ((val
<= VBE_DISPI_MAX_XRES
) && ((val
& 7) == 0)) {
585 s
->vbe_regs
[s
->vbe_index
] = val
;
588 case VBE_DISPI_INDEX_YRES
:
589 if (val
<= VBE_DISPI_MAX_YRES
) {
590 s
->vbe_regs
[s
->vbe_index
] = val
;
593 case VBE_DISPI_INDEX_BPP
:
596 if (val
== 4 || val
== 8 || val
== 15 ||
597 val
== 16 || val
== 24 || val
== 32) {
598 s
->vbe_regs
[s
->vbe_index
] = val
;
601 case VBE_DISPI_INDEX_BANK
:
602 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
603 val
&= (s
->vbe_bank_mask
>> 2);
605 val
&= s
->vbe_bank_mask
;
607 s
->vbe_regs
[s
->vbe_index
] = val
;
608 s
->bank_offset
= (val
<< 16);
610 case VBE_DISPI_INDEX_ENABLE
:
611 if ((val
& VBE_DISPI_ENABLED
) &&
612 !(s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
)) {
613 int h
, shift_control
;
615 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] =
616 s
->vbe_regs
[VBE_DISPI_INDEX_XRES
];
617 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_HEIGHT
] =
618 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
];
619 s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
] = 0;
620 s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
] = 0;
622 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
623 s
->vbe_line_offset
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 1;
625 s
->vbe_line_offset
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] *
626 ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
627 s
->vbe_start_addr
= 0;
629 /* clear the screen (should be done in BIOS) */
630 if (!(val
& VBE_DISPI_NOCLEARMEM
)) {
631 memset(s
->vram_ptr
, 0,
632 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] * s
->vbe_line_offset
);
635 /* we initialize the VGA graphic mode (should be done
637 s
->gr
[0x06] = (s
->gr
[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
638 s
->cr
[0x17] |= 3; /* no CGA modes */
639 s
->cr
[0x13] = s
->vbe_line_offset
>> 3;
641 s
->cr
[0x01] = (s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 3) - 1;
642 /* height (only meaningful if < 1024) */
643 h
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] - 1;
645 s
->cr
[0x07] = (s
->cr
[0x07] & ~0x42) |
646 ((h
>> 7) & 0x02) | ((h
>> 3) & 0x40);
647 /* line compare to 1023 */
652 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
654 s
->sr
[0x01] &= ~8; /* no double line */
657 s
->sr
[4] |= 0x08; /* set chain 4 mode */
658 s
->sr
[2] |= 0x0f; /* activate all planes */
660 s
->gr
[0x05] = (s
->gr
[0x05] & ~0x60) | (shift_control
<< 5);
661 s
->cr
[0x09] &= ~0x9f; /* no double scan */
663 /* XXX: the bios should do that */
666 s
->dac_8bit
= (val
& VBE_DISPI_8BIT_DAC
) > 0;
667 s
->vbe_regs
[s
->vbe_index
] = val
;
669 case VBE_DISPI_INDEX_VIRT_WIDTH
:
671 int w
, h
, line_offset
;
673 if (val
< s
->vbe_regs
[VBE_DISPI_INDEX_XRES
])
676 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
677 line_offset
= w
>> 1;
679 line_offset
= w
* ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
680 h
= s
->vram_size
/ line_offset
;
681 /* XXX: support weird bochs semantics ? */
682 if (h
< s
->vbe_regs
[VBE_DISPI_INDEX_YRES
])
684 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] = w
;
685 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_HEIGHT
] = h
;
686 s
->vbe_line_offset
= line_offset
;
689 case VBE_DISPI_INDEX_X_OFFSET
:
690 case VBE_DISPI_INDEX_Y_OFFSET
:
693 s
->vbe_regs
[s
->vbe_index
] = val
;
694 s
->vbe_start_addr
= s
->vbe_line_offset
* s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
];
695 x
= s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
];
696 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
697 s
->vbe_start_addr
+= x
>> 1;
699 s
->vbe_start_addr
+= x
* ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
700 s
->vbe_start_addr
>>= 2;
710 /* called for accesses between 0xa0000 and 0xc0000 */
711 uint32_t vga_mem_readb(VGACommonState
*s
, target_phys_addr_t addr
)
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 /* called for accesses between 0xa0000 and 0xc0000 */
767 void vga_mem_writeb(VGACommonState
*s
, target_phys_addr_t addr
, uint32_t val
)
769 int memory_map_mode
, plane
, write_mode
, b
, func_select
, mask
;
770 uint32_t write_mask
, bit_mask
, set_mask
;
773 printf("vga: [0x" TARGET_FMT_plx
"] = 0x%02x\n", addr
, val
);
775 /* convert to VGA memory offset */
776 memory_map_mode
= (s
->gr
[6] >> 2) & 3;
778 switch(memory_map_mode
) {
784 addr
+= s
->bank_offset
;
799 if (s
->sr
[4] & 0x08) {
800 /* chain 4 mode : simplest access */
803 if (s
->sr
[2] & mask
) {
804 s
->vram_ptr
[addr
] = val
;
806 printf("vga: chain4: [0x" TARGET_FMT_plx
"]\n", addr
);
808 s
->plane_updated
|= mask
; /* only used to detect font change */
809 memory_region_set_dirty(&s
->vram
, addr
);
811 } else if (s
->gr
[5] & 0x10) {
812 /* odd/even mode (aka text mode mapping) */
813 plane
= (s
->gr
[4] & 2) | (addr
& 1);
815 if (s
->sr
[2] & mask
) {
816 addr
= ((addr
& ~1) << 1) | plane
;
817 s
->vram_ptr
[addr
] = val
;
819 printf("vga: odd/even: [0x" TARGET_FMT_plx
"]\n", addr
);
821 s
->plane_updated
|= mask
; /* only used to detect font change */
822 memory_region_set_dirty(&s
->vram
, addr
);
825 /* standard VGA latched access */
826 write_mode
= s
->gr
[5] & 3;
832 val
= ((val
>> b
) | (val
<< (8 - b
))) & 0xff;
836 /* apply set/reset mask */
837 set_mask
= mask16
[s
->gr
[1]];
838 val
= (val
& ~set_mask
) | (mask16
[s
->gr
[0]] & set_mask
);
845 val
= mask16
[val
& 0x0f];
851 val
= (val
>> b
) | (val
<< (8 - b
));
853 bit_mask
= s
->gr
[8] & val
;
854 val
= mask16
[s
->gr
[0]];
858 /* apply logical operation */
859 func_select
= s
->gr
[3] >> 3;
860 switch(func_select
) {
880 bit_mask
|= bit_mask
<< 8;
881 bit_mask
|= bit_mask
<< 16;
882 val
= (val
& bit_mask
) | (s
->latch
& ~bit_mask
);
885 /* mask data according to sr[2] */
887 s
->plane_updated
|= mask
; /* only used to detect font change */
888 write_mask
= mask16
[mask
];
889 ((uint32_t *)s
->vram_ptr
)[addr
] =
890 (((uint32_t *)s
->vram_ptr
)[addr
] & ~write_mask
) |
893 printf("vga: latch: [0x" TARGET_FMT_plx
"] mask=0x%08x val=0x%08x\n",
894 addr
* 4, write_mask
, val
);
896 memory_region_set_dirty(&s
->vram
, addr
<< 2);
900 typedef void vga_draw_glyph8_func(uint8_t *d
, int linesize
,
901 const uint8_t *font_ptr
, int h
,
902 uint32_t fgcol
, uint32_t bgcol
);
903 typedef void vga_draw_glyph9_func(uint8_t *d
, int linesize
,
904 const uint8_t *font_ptr
, int h
,
905 uint32_t fgcol
, uint32_t bgcol
, int dup9
);
906 typedef void vga_draw_line_func(VGACommonState
*s1
, uint8_t *d
,
907 const uint8_t *s
, int width
);
910 #include "vga_template.h"
913 #include "vga_template.h"
917 #include "vga_template.h"
920 #include "vga_template.h"
924 #include "vga_template.h"
927 #include "vga_template.h"
931 #include "vga_template.h"
933 static unsigned int rgb_to_pixel8_dup(unsigned int r
, unsigned int g
, unsigned b
)
936 col
= rgb_to_pixel8(r
, g
, b
);
942 static unsigned int rgb_to_pixel15_dup(unsigned int r
, unsigned int g
, unsigned b
)
945 col
= rgb_to_pixel15(r
, g
, b
);
950 static unsigned int rgb_to_pixel15bgr_dup(unsigned int r
, unsigned int g
,
954 col
= rgb_to_pixel15bgr(r
, g
, b
);
959 static unsigned int rgb_to_pixel16_dup(unsigned int r
, unsigned int g
, unsigned b
)
962 col
= rgb_to_pixel16(r
, g
, b
);
967 static unsigned int rgb_to_pixel16bgr_dup(unsigned int r
, unsigned int g
,
971 col
= rgb_to_pixel16bgr(r
, g
, b
);
976 static unsigned int rgb_to_pixel32_dup(unsigned int r
, unsigned int g
, unsigned b
)
979 col
= rgb_to_pixel32(r
, g
, b
);
983 static unsigned int rgb_to_pixel32bgr_dup(unsigned int r
, unsigned int g
, unsigned b
)
986 col
= rgb_to_pixel32bgr(r
, g
, b
);
990 /* return true if the palette was modified */
991 static int update_palette16(VGACommonState
*s
)
994 uint32_t v
, col
, *palette
;
997 palette
= s
->last_palette
;
998 for(i
= 0; i
< 16; i
++) {
1000 if (s
->ar
[0x10] & 0x80)
1001 v
= ((s
->ar
[0x14] & 0xf) << 4) | (v
& 0xf);
1003 v
= ((s
->ar
[0x14] & 0xc) << 4) | (v
& 0x3f);
1005 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
1006 c6_to_8(s
->palette
[v
+ 1]),
1007 c6_to_8(s
->palette
[v
+ 2]));
1008 if (col
!= palette
[i
]) {
1016 /* return true if the palette was modified */
1017 static int update_palette256(VGACommonState
*s
)
1020 uint32_t v
, col
, *palette
;
1023 palette
= s
->last_palette
;
1025 for(i
= 0; i
< 256; i
++) {
1027 col
= s
->rgb_to_pixel(s
->palette
[v
],
1031 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
1032 c6_to_8(s
->palette
[v
+ 1]),
1033 c6_to_8(s
->palette
[v
+ 2]));
1035 if (col
!= palette
[i
]) {
1044 static void vga_get_offsets(VGACommonState
*s
,
1045 uint32_t *pline_offset
,
1046 uint32_t *pstart_addr
,
1047 uint32_t *pline_compare
)
1049 uint32_t start_addr
, line_offset
, line_compare
;
1050 #ifdef CONFIG_BOCHS_VBE
1051 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1052 line_offset
= s
->vbe_line_offset
;
1053 start_addr
= s
->vbe_start_addr
;
1054 line_compare
= 65535;
1058 /* compute line_offset in bytes */
1059 line_offset
= s
->cr
[0x13];
1062 /* starting address */
1063 start_addr
= s
->cr
[0x0d] | (s
->cr
[0x0c] << 8);
1066 line_compare
= s
->cr
[0x18] |
1067 ((s
->cr
[0x07] & 0x10) << 4) |
1068 ((s
->cr
[0x09] & 0x40) << 3);
1070 *pline_offset
= line_offset
;
1071 *pstart_addr
= start_addr
;
1072 *pline_compare
= line_compare
;
1075 /* update start_addr and line_offset. Return TRUE if modified */
1076 static int update_basic_params(VGACommonState
*s
)
1079 uint32_t start_addr
, line_offset
, line_compare
;
1083 s
->get_offsets(s
, &line_offset
, &start_addr
, &line_compare
);
1085 if (line_offset
!= s
->line_offset
||
1086 start_addr
!= s
->start_addr
||
1087 line_compare
!= s
->line_compare
) {
1088 s
->line_offset
= line_offset
;
1089 s
->start_addr
= start_addr
;
1090 s
->line_compare
= line_compare
;
1098 static inline int get_depth_index(DisplayState
*s
)
1100 switch(ds_get_bits_per_pixel(s
)) {
1109 if (is_surface_bgr(s
->surface
))
1116 static vga_draw_glyph8_func
* const vga_draw_glyph8_table
[NB_DEPTHS
] = {
1126 static vga_draw_glyph8_func
* const vga_draw_glyph16_table
[NB_DEPTHS
] = {
1128 vga_draw_glyph16_16
,
1129 vga_draw_glyph16_16
,
1130 vga_draw_glyph16_32
,
1131 vga_draw_glyph16_32
,
1132 vga_draw_glyph16_16
,
1133 vga_draw_glyph16_16
,
1136 static vga_draw_glyph9_func
* const vga_draw_glyph9_table
[NB_DEPTHS
] = {
1146 static const uint8_t cursor_glyph
[32 * 4] = {
1147 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1148 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1149 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1150 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1151 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1152 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1153 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1154 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1155 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1156 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1157 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1158 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1159 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1160 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1161 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1162 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1165 static void vga_get_text_resolution(VGACommonState
*s
, int *pwidth
, int *pheight
,
1166 int *pcwidth
, int *pcheight
)
1168 int width
, cwidth
, height
, cheight
;
1170 /* total width & height */
1171 cheight
= (s
->cr
[9] & 0x1f) + 1;
1173 if (!(s
->sr
[1] & 0x01))
1175 if (s
->sr
[1] & 0x08)
1176 cwidth
= 16; /* NOTE: no 18 pixel wide */
1177 width
= (s
->cr
[0x01] + 1);
1178 if (s
->cr
[0x06] == 100) {
1179 /* ugly hack for CGA 160x100x16 - explain me the logic */
1182 height
= s
->cr
[0x12] |
1183 ((s
->cr
[0x07] & 0x02) << 7) |
1184 ((s
->cr
[0x07] & 0x40) << 3);
1185 height
= (height
+ 1) / cheight
;
1191 *pcheight
= cheight
;
1194 typedef unsigned int rgb_to_pixel_dup_func(unsigned int r
, unsigned int g
, unsigned b
);
1196 static rgb_to_pixel_dup_func
* const rgb_to_pixel_dup_table
[NB_DEPTHS
] = {
1201 rgb_to_pixel32bgr_dup
,
1202 rgb_to_pixel15bgr_dup
,
1203 rgb_to_pixel16bgr_dup
,
1214 static void vga_draw_text(VGACommonState
*s
, int full_update
)
1216 int cx
, cy
, cheight
, cw
, ch
, cattr
, height
, width
, ch_attr
;
1217 int cx_min
, cx_max
, linesize
, x_incr
, line
, line1
;
1218 uint32_t offset
, fgcol
, bgcol
, v
, cursor_offset
;
1219 uint8_t *d1
, *d
, *src
, *dest
, *cursor_ptr
;
1220 const uint8_t *font_ptr
, *font_base
[2];
1221 int dup9
, line_offset
, depth_index
;
1223 uint32_t *ch_attr_ptr
;
1224 vga_draw_glyph8_func
*vga_draw_glyph8
;
1225 vga_draw_glyph9_func
*vga_draw_glyph9
;
1227 /* compute font data address (in plane 2) */
1229 offset
= (((v
>> 4) & 1) | ((v
<< 1) & 6)) * 8192 * 4 + 2;
1230 if (offset
!= s
->font_offsets
[0]) {
1231 s
->font_offsets
[0] = offset
;
1234 font_base
[0] = s
->vram_ptr
+ offset
;
1236 offset
= (((v
>> 5) & 1) | ((v
>> 1) & 6)) * 8192 * 4 + 2;
1237 font_base
[1] = s
->vram_ptr
+ offset
;
1238 if (offset
!= s
->font_offsets
[1]) {
1239 s
->font_offsets
[1] = offset
;
1242 if (s
->plane_updated
& (1 << 2)) {
1243 /* if the plane 2 was modified since the last display, it
1244 indicates the font may have been modified */
1245 s
->plane_updated
= 0;
1248 full_update
|= update_basic_params(s
);
1250 line_offset
= s
->line_offset
;
1252 vga_get_text_resolution(s
, &width
, &height
, &cw
, &cheight
);
1253 if ((height
* width
) > CH_ATTR_SIZE
) {
1254 /* better than nothing: exit if transient size is too big */
1258 if (width
!= s
->last_width
|| height
!= s
->last_height
||
1259 cw
!= s
->last_cw
|| cheight
!= s
->last_ch
|| s
->last_depth
) {
1260 s
->last_scr_width
= width
* cw
;
1261 s
->last_scr_height
= height
* cheight
;
1262 qemu_console_resize(s
->ds
, s
->last_scr_width
, s
->last_scr_height
);
1264 s
->last_width
= width
;
1265 s
->last_height
= height
;
1266 s
->last_ch
= cheight
;
1271 rgb_to_pixel_dup_table
[get_depth_index(s
->ds
)];
1272 full_update
|= update_palette16(s
);
1273 palette
= s
->last_palette
;
1274 x_incr
= cw
* ((ds_get_bits_per_pixel(s
->ds
) + 7) >> 3);
1276 cursor_offset
= ((s
->cr
[0x0e] << 8) | s
->cr
[0x0f]) - s
->start_addr
;
1277 if (cursor_offset
!= s
->cursor_offset
||
1278 s
->cr
[0xa] != s
->cursor_start
||
1279 s
->cr
[0xb] != s
->cursor_end
) {
1280 /* if the cursor position changed, we update the old and new
1282 if (s
->cursor_offset
< CH_ATTR_SIZE
)
1283 s
->last_ch_attr
[s
->cursor_offset
] = -1;
1284 if (cursor_offset
< CH_ATTR_SIZE
)
1285 s
->last_ch_attr
[cursor_offset
] = -1;
1286 s
->cursor_offset
= cursor_offset
;
1287 s
->cursor_start
= s
->cr
[0xa];
1288 s
->cursor_end
= s
->cr
[0xb];
1290 cursor_ptr
= s
->vram_ptr
+ (s
->start_addr
+ cursor_offset
) * 4;
1292 depth_index
= get_depth_index(s
->ds
);
1294 vga_draw_glyph8
= vga_draw_glyph16_table
[depth_index
];
1296 vga_draw_glyph8
= vga_draw_glyph8_table
[depth_index
];
1297 vga_draw_glyph9
= vga_draw_glyph9_table
[depth_index
];
1299 dest
= ds_get_data(s
->ds
);
1300 linesize
= ds_get_linesize(s
->ds
);
1301 ch_attr_ptr
= s
->last_ch_attr
;
1303 offset
= s
->start_addr
* 4;
1304 for(cy
= 0; cy
< height
; cy
++) {
1306 src
= s
->vram_ptr
+ offset
;
1309 for(cx
= 0; cx
< width
; cx
++) {
1310 ch_attr
= *(uint16_t *)src
;
1311 if (full_update
|| ch_attr
!= *ch_attr_ptr
) {
1316 *ch_attr_ptr
= ch_attr
;
1317 #ifdef HOST_WORDS_BIGENDIAN
1319 cattr
= ch_attr
& 0xff;
1321 ch
= ch_attr
& 0xff;
1322 cattr
= ch_attr
>> 8;
1324 font_ptr
= font_base
[(cattr
>> 3) & 1];
1325 font_ptr
+= 32 * 4 * ch
;
1326 bgcol
= palette
[cattr
>> 4];
1327 fgcol
= palette
[cattr
& 0x0f];
1329 vga_draw_glyph8(d1
, linesize
,
1330 font_ptr
, cheight
, fgcol
, bgcol
);
1333 if (ch
>= 0xb0 && ch
<= 0xdf && (s
->ar
[0x10] & 0x04))
1335 vga_draw_glyph9(d1
, linesize
,
1336 font_ptr
, cheight
, fgcol
, bgcol
, dup9
);
1338 if (src
== cursor_ptr
&&
1339 !(s
->cr
[0x0a] & 0x20)) {
1340 int line_start
, line_last
, h
;
1341 /* draw the cursor */
1342 line_start
= s
->cr
[0x0a] & 0x1f;
1343 line_last
= s
->cr
[0x0b] & 0x1f;
1344 /* XXX: check that */
1345 if (line_last
> cheight
- 1)
1346 line_last
= cheight
- 1;
1347 if (line_last
>= line_start
&& line_start
< cheight
) {
1348 h
= line_last
- line_start
+ 1;
1349 d
= d1
+ linesize
* line_start
;
1351 vga_draw_glyph8(d
, linesize
,
1352 cursor_glyph
, h
, fgcol
, bgcol
);
1354 vga_draw_glyph9(d
, linesize
,
1355 cursor_glyph
, h
, fgcol
, bgcol
, 1);
1365 dpy_update(s
->ds
, cx_min
* cw
, cy
* cheight
,
1366 (cx_max
- cx_min
+ 1) * cw
, cheight
);
1368 dest
+= linesize
* cheight
;
1369 line1
= line
+ cheight
;
1370 offset
+= line_offset
;
1371 if (line
< s
->line_compare
&& line1
>= s
->line_compare
) {
1392 static vga_draw_line_func
* const vga_draw_line_table
[NB_DEPTHS
* VGA_DRAW_LINE_NB
] = {
1402 vga_draw_line2d2_16
,
1403 vga_draw_line2d2_16
,
1404 vga_draw_line2d2_32
,
1405 vga_draw_line2d2_32
,
1406 vga_draw_line2d2_16
,
1407 vga_draw_line2d2_16
,
1418 vga_draw_line4d2_16
,
1419 vga_draw_line4d2_16
,
1420 vga_draw_line4d2_32
,
1421 vga_draw_line4d2_32
,
1422 vga_draw_line4d2_16
,
1423 vga_draw_line4d2_16
,
1426 vga_draw_line8d2_16
,
1427 vga_draw_line8d2_16
,
1428 vga_draw_line8d2_32
,
1429 vga_draw_line8d2_32
,
1430 vga_draw_line8d2_16
,
1431 vga_draw_line8d2_16
,
1445 vga_draw_line15_32bgr
,
1446 vga_draw_line15_15bgr
,
1447 vga_draw_line15_16bgr
,
1453 vga_draw_line16_32bgr
,
1454 vga_draw_line16_15bgr
,
1455 vga_draw_line16_16bgr
,
1461 vga_draw_line24_32bgr
,
1462 vga_draw_line24_15bgr
,
1463 vga_draw_line24_16bgr
,
1469 vga_draw_line32_32bgr
,
1470 vga_draw_line32_15bgr
,
1471 vga_draw_line32_16bgr
,
1474 static int vga_get_bpp(VGACommonState
*s
)
1477 #ifdef CONFIG_BOCHS_VBE
1478 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1479 ret
= s
->vbe_regs
[VBE_DISPI_INDEX_BPP
];
1488 static void vga_get_resolution(VGACommonState
*s
, int *pwidth
, int *pheight
)
1492 #ifdef CONFIG_BOCHS_VBE
1493 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1494 width
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
];
1495 height
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
];
1499 width
= (s
->cr
[0x01] + 1) * 8;
1500 height
= s
->cr
[0x12] |
1501 ((s
->cr
[0x07] & 0x02) << 7) |
1502 ((s
->cr
[0x07] & 0x40) << 3);
1503 height
= (height
+ 1);
1509 void vga_invalidate_scanlines(VGACommonState
*s
, int y1
, int y2
)
1512 if (y1
>= VGA_MAX_HEIGHT
)
1514 if (y2
>= VGA_MAX_HEIGHT
)
1515 y2
= VGA_MAX_HEIGHT
;
1516 for(y
= y1
; y
< y2
; y
++) {
1517 s
->invalidated_y_table
[y
>> 5] |= 1 << (y
& 0x1f);
1521 static void vga_sync_dirty_bitmap(VGACommonState
*s
)
1523 memory_region_sync_dirty_bitmap(&s
->vram
);
1526 void vga_dirty_log_start(VGACommonState
*s
)
1528 memory_region_set_log(&s
->vram
, true, DIRTY_MEMORY_VGA
);
1531 void vga_dirty_log_stop(VGACommonState
*s
)
1533 memory_region_set_log(&s
->vram
, false, DIRTY_MEMORY_VGA
);
1536 void vga_dirty_log_restart(VGACommonState
*s
)
1538 vga_dirty_log_stop(s
);
1539 vga_dirty_log_start(s
);
1545 static void vga_draw_graphic(VGACommonState
*s
, int full_update
)
1547 int y1
, y
, update
, linesize
, y_start
, double_scan
, mask
, depth
;
1548 int width
, height
, shift_control
, line_offset
, bwidth
, bits
;
1549 ram_addr_t page0
, page1
, page_min
, page_max
;
1550 int disp_width
, multi_scan
, multi_run
;
1552 uint32_t v
, addr1
, addr
;
1553 vga_draw_line_func
*vga_draw_line
;
1555 full_update
|= update_basic_params(s
);
1558 vga_sync_dirty_bitmap(s
);
1560 s
->get_resolution(s
, &width
, &height
);
1563 shift_control
= (s
->gr
[0x05] >> 5) & 3;
1564 double_scan
= (s
->cr
[0x09] >> 7);
1565 if (shift_control
!= 1) {
1566 multi_scan
= (((s
->cr
[0x09] & 0x1f) + 1) << double_scan
) - 1;
1568 /* in CGA modes, multi_scan is ignored */
1569 /* XXX: is it correct ? */
1570 multi_scan
= double_scan
;
1572 multi_run
= multi_scan
;
1573 if (shift_control
!= s
->shift_control
||
1574 double_scan
!= s
->double_scan
) {
1576 s
->shift_control
= shift_control
;
1577 s
->double_scan
= double_scan
;
1580 if (shift_control
== 0) {
1581 if (s
->sr
[0x01] & 8) {
1584 } else if (shift_control
== 1) {
1585 if (s
->sr
[0x01] & 8) {
1590 depth
= s
->get_bpp(s
);
1591 if (s
->line_offset
!= s
->last_line_offset
||
1592 disp_width
!= s
->last_width
||
1593 height
!= s
->last_height
||
1594 s
->last_depth
!= depth
) {
1595 #if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
1596 if (depth
== 16 || depth
== 32) {
1600 qemu_free_displaysurface(s
->ds
);
1601 s
->ds
->surface
= qemu_create_displaysurface_from(disp_width
, height
, depth
,
1603 s
->vram_ptr
+ (s
->start_addr
* 4));
1604 #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
1605 s
->ds
->surface
->pf
= qemu_different_endianness_pixelformat(depth
);
1609 qemu_console_resize(s
->ds
, disp_width
, height
);
1611 s
->last_scr_width
= disp_width
;
1612 s
->last_scr_height
= height
;
1613 s
->last_width
= disp_width
;
1614 s
->last_height
= height
;
1615 s
->last_line_offset
= s
->line_offset
;
1616 s
->last_depth
= depth
;
1618 } else if (is_buffer_shared(s
->ds
->surface
) &&
1619 (full_update
|| s
->ds
->surface
->data
!= s
->vram_ptr
+ (s
->start_addr
* 4))) {
1620 s
->ds
->surface
->data
= s
->vram_ptr
+ (s
->start_addr
* 4);
1625 rgb_to_pixel_dup_table
[get_depth_index(s
->ds
)];
1627 if (shift_control
== 0) {
1628 full_update
|= update_palette16(s
);
1629 if (s
->sr
[0x01] & 8) {
1630 v
= VGA_DRAW_LINE4D2
;
1635 } else if (shift_control
== 1) {
1636 full_update
|= update_palette16(s
);
1637 if (s
->sr
[0x01] & 8) {
1638 v
= VGA_DRAW_LINE2D2
;
1644 switch(s
->get_bpp(s
)) {
1647 full_update
|= update_palette256(s
);
1648 v
= VGA_DRAW_LINE8D2
;
1652 full_update
|= update_palette256(s
);
1657 v
= VGA_DRAW_LINE15
;
1661 v
= VGA_DRAW_LINE16
;
1665 v
= VGA_DRAW_LINE24
;
1669 v
= VGA_DRAW_LINE32
;
1674 vga_draw_line
= vga_draw_line_table
[v
* NB_DEPTHS
+ get_depth_index(s
->ds
)];
1676 if (!is_buffer_shared(s
->ds
->surface
) && s
->cursor_invalidate
)
1677 s
->cursor_invalidate(s
);
1679 line_offset
= s
->line_offset
;
1681 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",
1682 width
, height
, v
, line_offset
, s
->cr
[9], s
->cr
[0x17], s
->line_compare
, s
->sr
[0x01]);
1684 addr1
= (s
->start_addr
* 4);
1685 bwidth
= (width
* bits
+ 7) / 8;
1689 d
= ds_get_data(s
->ds
);
1690 linesize
= ds_get_linesize(s
->ds
);
1692 for(y
= 0; y
< height
; y
++) {
1694 if (!(s
->cr
[0x17] & 1)) {
1696 /* CGA compatibility handling */
1697 shift
= 14 + ((s
->cr
[0x17] >> 6) & 1);
1698 addr
= (addr
& ~(1 << shift
)) | ((y1
& 1) << shift
);
1700 if (!(s
->cr
[0x17] & 2)) {
1701 addr
= (addr
& ~0x8000) | ((y1
& 2) << 14);
1703 page0
= addr
& TARGET_PAGE_MASK
;
1704 page1
= (addr
+ bwidth
- 1) & TARGET_PAGE_MASK
;
1705 update
= full_update
|
1706 memory_region_get_dirty(&s
->vram
, page0
, DIRTY_MEMORY_VGA
) |
1707 memory_region_get_dirty(&s
->vram
, page1
, DIRTY_MEMORY_VGA
);
1708 if ((page1
- page0
) > TARGET_PAGE_SIZE
) {
1709 /* if wide line, can use another page */
1710 update
|= memory_region_get_dirty(&s
->vram
,
1711 page0
+ TARGET_PAGE_SIZE
,
1714 /* explicit invalidation for the hardware cursor */
1715 update
|= (s
->invalidated_y_table
[y
>> 5] >> (y
& 0x1f)) & 1;
1719 if (page0
< page_min
)
1721 if (page1
> page_max
)
1723 if (!(is_buffer_shared(s
->ds
->surface
))) {
1724 vga_draw_line(s
, d
, s
->vram_ptr
+ addr
, width
);
1725 if (s
->cursor_draw_line
)
1726 s
->cursor_draw_line(s
, d
, y
);
1730 /* flush to display */
1731 dpy_update(s
->ds
, 0, y_start
,
1732 disp_width
, y
- y_start
);
1737 mask
= (s
->cr
[0x17] & 3) ^ 3;
1738 if ((y1
& mask
) == mask
)
1739 addr1
+= line_offset
;
1741 multi_run
= multi_scan
;
1745 /* line compare acts on the displayed lines */
1746 if (y
== s
->line_compare
)
1751 /* flush to display */
1752 dpy_update(s
->ds
, 0, y_start
,
1753 disp_width
, y
- y_start
);
1755 /* reset modified pages */
1756 if (page_max
>= page_min
) {
1757 memory_region_reset_dirty(&s
->vram
,
1759 page_max
+ TARGET_PAGE_SIZE
- page_min
,
1762 memset(s
->invalidated_y_table
, 0, ((height
+ 31) >> 5) * 4);
1765 static void vga_draw_blank(VGACommonState
*s
, int full_update
)
1772 if (s
->last_scr_width
<= 0 || s
->last_scr_height
<= 0)
1776 rgb_to_pixel_dup_table
[get_depth_index(s
->ds
)];
1777 if (ds_get_bits_per_pixel(s
->ds
) == 8)
1778 val
= s
->rgb_to_pixel(0, 0, 0);
1781 w
= s
->last_scr_width
* ((ds_get_bits_per_pixel(s
->ds
) + 7) >> 3);
1782 d
= ds_get_data(s
->ds
);
1783 for(i
= 0; i
< s
->last_scr_height
; i
++) {
1785 d
+= ds_get_linesize(s
->ds
);
1787 dpy_update(s
->ds
, 0, 0,
1788 s
->last_scr_width
, s
->last_scr_height
);
1791 #define GMODE_TEXT 0
1792 #define GMODE_GRAPH 1
1793 #define GMODE_BLANK 2
1795 static void vga_update_display(void *opaque
)
1797 VGACommonState
*s
= opaque
;
1798 int full_update
, graphic_mode
;
1800 if (ds_get_bits_per_pixel(s
->ds
) == 0) {
1804 if (!(s
->ar_index
& 0x20)) {
1805 graphic_mode
= GMODE_BLANK
;
1807 graphic_mode
= s
->gr
[6] & 1;
1809 if (graphic_mode
!= s
->graphic_mode
) {
1810 s
->graphic_mode
= graphic_mode
;
1813 switch(graphic_mode
) {
1815 vga_draw_text(s
, full_update
);
1818 vga_draw_graphic(s
, full_update
);
1822 vga_draw_blank(s
, full_update
);
1828 /* force a full display refresh */
1829 static void vga_invalidate_display(void *opaque
)
1831 VGACommonState
*s
= opaque
;
1834 s
->last_height
= -1;
1837 void vga_common_reset(VGACommonState
*s
)
1840 memset(s
->sr
, '\0', sizeof(s
->sr
));
1842 memset(s
->gr
, '\0', sizeof(s
->gr
));
1844 memset(s
->ar
, '\0', sizeof(s
->ar
));
1845 s
->ar_flip_flop
= 0;
1847 memset(s
->cr
, '\0', sizeof(s
->cr
));
1853 s
->dac_sub_index
= 0;
1854 s
->dac_read_index
= 0;
1855 s
->dac_write_index
= 0;
1856 memset(s
->dac_cache
, '\0', sizeof(s
->dac_cache
));
1858 memset(s
->palette
, '\0', sizeof(s
->palette
));
1860 #ifdef CONFIG_BOCHS_VBE
1862 memset(s
->vbe_regs
, '\0', sizeof(s
->vbe_regs
));
1863 s
->vbe_regs
[VBE_DISPI_INDEX_ID
] = VBE_DISPI_ID5
;
1864 s
->vbe_start_addr
= 0;
1865 s
->vbe_line_offset
= 0;
1866 s
->vbe_bank_mask
= (s
->vram_size
>> 16) - 1;
1868 memset(s
->font_offsets
, '\0', sizeof(s
->font_offsets
));
1869 s
->graphic_mode
= -1; /* force full update */
1870 s
->shift_control
= 0;
1873 s
->line_compare
= 0;
1875 s
->plane_updated
= 0;
1880 s
->last_scr_width
= 0;
1881 s
->last_scr_height
= 0;
1882 s
->cursor_start
= 0;
1884 s
->cursor_offset
= 0;
1885 memset(s
->invalidated_y_table
, '\0', sizeof(s
->invalidated_y_table
));
1886 memset(s
->last_palette
, '\0', sizeof(s
->last_palette
));
1887 memset(s
->last_ch_attr
, '\0', sizeof(s
->last_ch_attr
));
1888 switch (vga_retrace_method
) {
1889 case VGA_RETRACE_DUMB
:
1891 case VGA_RETRACE_PRECISE
:
1892 memset(&s
->retrace_info
, 0, sizeof (s
->retrace_info
));
1897 static void vga_reset(void *opaque
)
1899 VGACommonState
*s
= opaque
;
1900 vga_common_reset(s
);
1903 #define TEXTMODE_X(x) ((x) % width)
1904 #define TEXTMODE_Y(x) ((x) / width)
1905 #define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1906 ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1907 /* relay text rendering to the display driver
1908 * instead of doing a full vga_update_display() */
1909 static void vga_update_text(void *opaque
, console_ch_t
*chardata
)
1911 VGACommonState
*s
= opaque
;
1912 int graphic_mode
, i
, cursor_offset
, cursor_visible
;
1913 int cw
, cheight
, width
, height
, size
, c_min
, c_max
;
1915 console_ch_t
*dst
, val
;
1916 char msg_buffer
[80];
1917 int full_update
= 0;
1919 if (!(s
->ar_index
& 0x20)) {
1920 graphic_mode
= GMODE_BLANK
;
1922 graphic_mode
= s
->gr
[6] & 1;
1924 if (graphic_mode
!= s
->graphic_mode
) {
1925 s
->graphic_mode
= graphic_mode
;
1928 if (s
->last_width
== -1) {
1933 switch (graphic_mode
) {
1935 /* TODO: update palette */
1936 full_update
|= update_basic_params(s
);
1938 /* total width & height */
1939 cheight
= (s
->cr
[9] & 0x1f) + 1;
1941 if (!(s
->sr
[1] & 0x01))
1943 if (s
->sr
[1] & 0x08)
1944 cw
= 16; /* NOTE: no 18 pixel wide */
1945 width
= (s
->cr
[0x01] + 1);
1946 if (s
->cr
[0x06] == 100) {
1947 /* ugly hack for CGA 160x100x16 - explain me the logic */
1950 height
= s
->cr
[0x12] |
1951 ((s
->cr
[0x07] & 0x02) << 7) |
1952 ((s
->cr
[0x07] & 0x40) << 3);
1953 height
= (height
+ 1) / cheight
;
1956 size
= (height
* width
);
1957 if (size
> CH_ATTR_SIZE
) {
1961 snprintf(msg_buffer
, sizeof(msg_buffer
), "%i x %i Text mode",
1966 if (width
!= s
->last_width
|| height
!= s
->last_height
||
1967 cw
!= s
->last_cw
|| cheight
!= s
->last_ch
) {
1968 s
->last_scr_width
= width
* cw
;
1969 s
->last_scr_height
= height
* cheight
;
1970 s
->ds
->surface
->width
= width
;
1971 s
->ds
->surface
->height
= height
;
1973 s
->last_width
= width
;
1974 s
->last_height
= height
;
1975 s
->last_ch
= cheight
;
1980 /* Update "hardware" cursor */
1981 cursor_offset
= ((s
->cr
[0x0e] << 8) | s
->cr
[0x0f]) - s
->start_addr
;
1982 if (cursor_offset
!= s
->cursor_offset
||
1983 s
->cr
[0xa] != s
->cursor_start
||
1984 s
->cr
[0xb] != s
->cursor_end
|| full_update
) {
1985 cursor_visible
= !(s
->cr
[0xa] & 0x20);
1986 if (cursor_visible
&& cursor_offset
< size
&& cursor_offset
>= 0)
1988 TEXTMODE_X(cursor_offset
),
1989 TEXTMODE_Y(cursor_offset
));
1991 dpy_cursor(s
->ds
, -1, -1);
1992 s
->cursor_offset
= cursor_offset
;
1993 s
->cursor_start
= s
->cr
[0xa];
1994 s
->cursor_end
= s
->cr
[0xb];
1997 src
= (uint32_t *) s
->vram_ptr
+ s
->start_addr
;
2001 for (i
= 0; i
< size
; src
++, dst
++, i
++)
2002 console_write_ch(dst
, VMEM2CHTYPE(le32_to_cpu(*src
)));
2004 dpy_update(s
->ds
, 0, 0, width
, height
);
2008 for (i
= 0; i
< size
; src
++, dst
++, i
++) {
2009 console_write_ch(&val
, VMEM2CHTYPE(le32_to_cpu(*src
)));
2017 for (; i
< size
; src
++, dst
++, i
++) {
2018 console_write_ch(&val
, VMEM2CHTYPE(le32_to_cpu(*src
)));
2025 if (c_min
<= c_max
) {
2026 i
= TEXTMODE_Y(c_min
);
2027 dpy_update(s
->ds
, 0, i
, width
, TEXTMODE_Y(c_max
) - i
+ 1);
2036 s
->get_resolution(s
, &width
, &height
);
2037 snprintf(msg_buffer
, sizeof(msg_buffer
), "%i x %i Graphic mode",
2045 snprintf(msg_buffer
, sizeof(msg_buffer
), "VGA Blank mode");
2049 /* Display a message */
2051 s
->last_height
= height
= 3;
2052 dpy_cursor(s
->ds
, -1, -1);
2053 s
->ds
->surface
->width
= s
->last_width
;
2054 s
->ds
->surface
->height
= height
;
2057 for (dst
= chardata
, i
= 0; i
< s
->last_width
* height
; i
++)
2058 console_write_ch(dst
++, ' ');
2060 size
= strlen(msg_buffer
);
2061 width
= (s
->last_width
- size
) / 2;
2062 dst
= chardata
+ s
->last_width
+ width
;
2063 for (i
= 0; i
< size
; i
++)
2064 console_write_ch(dst
++, 0x00200100 | msg_buffer
[i
]);
2066 dpy_update(s
->ds
, 0, 0, s
->last_width
, height
);
2069 static uint64_t vga_mem_read(void *opaque
, target_phys_addr_t addr
,
2072 VGACommonState
*s
= opaque
;
2074 return vga_mem_readb(s
, addr
);
2077 static void vga_mem_write(void *opaque
, target_phys_addr_t addr
,
2078 uint64_t data
, unsigned size
)
2080 VGACommonState
*s
= opaque
;
2082 return vga_mem_writeb(s
, addr
, data
);
2085 const MemoryRegionOps vga_mem_ops
= {
2086 .read
= vga_mem_read
,
2087 .write
= vga_mem_write
,
2088 .endianness
= DEVICE_LITTLE_ENDIAN
,
2090 .min_access_size
= 1,
2091 .max_access_size
= 1,
2095 static int vga_common_post_load(void *opaque
, int version_id
)
2097 VGACommonState
*s
= opaque
;
2100 s
->graphic_mode
= -1;
2104 const VMStateDescription vmstate_vga_common
= {
2107 .minimum_version_id
= 2,
2108 .minimum_version_id_old
= 2,
2109 .post_load
= vga_common_post_load
,
2110 .fields
= (VMStateField
[]) {
2111 VMSTATE_UINT32(latch
, VGACommonState
),
2112 VMSTATE_UINT8(sr_index
, VGACommonState
),
2113 VMSTATE_PARTIAL_BUFFER(sr
, VGACommonState
, 8),
2114 VMSTATE_UINT8(gr_index
, VGACommonState
),
2115 VMSTATE_PARTIAL_BUFFER(gr
, VGACommonState
, 16),
2116 VMSTATE_UINT8(ar_index
, VGACommonState
),
2117 VMSTATE_BUFFER(ar
, VGACommonState
),
2118 VMSTATE_INT32(ar_flip_flop
, VGACommonState
),
2119 VMSTATE_UINT8(cr_index
, VGACommonState
),
2120 VMSTATE_BUFFER(cr
, VGACommonState
),
2121 VMSTATE_UINT8(msr
, VGACommonState
),
2122 VMSTATE_UINT8(fcr
, VGACommonState
),
2123 VMSTATE_UINT8(st00
, VGACommonState
),
2124 VMSTATE_UINT8(st01
, VGACommonState
),
2126 VMSTATE_UINT8(dac_state
, VGACommonState
),
2127 VMSTATE_UINT8(dac_sub_index
, VGACommonState
),
2128 VMSTATE_UINT8(dac_read_index
, VGACommonState
),
2129 VMSTATE_UINT8(dac_write_index
, VGACommonState
),
2130 VMSTATE_BUFFER(dac_cache
, VGACommonState
),
2131 VMSTATE_BUFFER(palette
, VGACommonState
),
2133 VMSTATE_INT32(bank_offset
, VGACommonState
),
2134 VMSTATE_UINT8_EQUAL(is_vbe_vmstate
, VGACommonState
),
2135 #ifdef CONFIG_BOCHS_VBE
2136 VMSTATE_UINT16(vbe_index
, VGACommonState
),
2137 VMSTATE_UINT16_ARRAY(vbe_regs
, VGACommonState
, VBE_DISPI_INDEX_NB
),
2138 VMSTATE_UINT32(vbe_start_addr
, VGACommonState
),
2139 VMSTATE_UINT32(vbe_line_offset
, VGACommonState
),
2140 VMSTATE_UINT32(vbe_bank_mask
, VGACommonState
),
2142 VMSTATE_END_OF_LIST()
2146 void vga_common_init(VGACommonState
*s
, int vga_ram_size
)
2150 for(i
= 0;i
< 256; i
++) {
2152 for(j
= 0; j
< 8; j
++) {
2153 v
|= ((i
>> j
) & 1) << (j
* 4);
2158 for(j
= 0; j
< 4; j
++) {
2159 v
|= ((i
>> (2 * j
)) & 3) << (j
* 4);
2163 for(i
= 0; i
< 16; i
++) {
2165 for(j
= 0; j
< 4; j
++) {
2168 v
|= b
<< (2 * j
+ 1);
2173 #ifdef CONFIG_BOCHS_VBE
2174 s
->is_vbe_vmstate
= 1;
2176 s
->is_vbe_vmstate
= 0;
2178 memory_region_init_ram(&s
->vram
, NULL
, "vga.vram", vga_ram_size
);
2179 s
->vram_ptr
= memory_region_get_ram_ptr(&s
->vram
);
2180 s
->vram_size
= vga_ram_size
;
2181 s
->get_bpp
= vga_get_bpp
;
2182 s
->get_offsets
= vga_get_offsets
;
2183 s
->get_resolution
= vga_get_resolution
;
2184 s
->update
= vga_update_display
;
2185 s
->invalidate
= vga_invalidate_display
;
2186 s
->screen_dump
= vga_screen_dump
;
2187 s
->text_update
= vga_update_text
;
2188 switch (vga_retrace_method
) {
2189 case VGA_RETRACE_DUMB
:
2190 s
->retrace
= vga_dumb_retrace
;
2191 s
->update_retrace_info
= vga_dumb_update_retrace_info
;
2194 case VGA_RETRACE_PRECISE
:
2195 s
->retrace
= vga_precise_retrace
;
2196 s
->update_retrace_info
= vga_precise_update_retrace_info
;
2199 vga_dirty_log_start(s
);
2202 /* used by both ISA and PCI */
2203 MemoryRegion
*vga_init_io(VGACommonState
*s
)
2205 MemoryRegion
*vga_mem
;
2207 register_ioport_write(0x3c0, 16, 1, vga_ioport_write
, s
);
2209 register_ioport_write(0x3b4, 2, 1, vga_ioport_write
, s
);
2210 register_ioport_write(0x3d4, 2, 1, vga_ioport_write
, s
);
2211 register_ioport_write(0x3ba, 1, 1, vga_ioport_write
, s
);
2212 register_ioport_write(0x3da, 1, 1, vga_ioport_write
, s
);
2214 register_ioport_read(0x3c0, 16, 1, vga_ioport_read
, s
);
2216 register_ioport_read(0x3b4, 2, 1, vga_ioport_read
, s
);
2217 register_ioport_read(0x3d4, 2, 1, vga_ioport_read
, s
);
2218 register_ioport_read(0x3ba, 1, 1, vga_ioport_read
, s
);
2219 register_ioport_read(0x3da, 1, 1, vga_ioport_read
, s
);
2221 #ifdef CONFIG_BOCHS_VBE
2222 #if defined (TARGET_I386)
2223 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index
, s
);
2224 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data
, s
);
2226 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index
, s
);
2227 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data
, s
);
2229 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index
, s
);
2230 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data
, s
);
2232 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index
, s
);
2233 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data
, s
);
2235 #endif /* CONFIG_BOCHS_VBE */
2237 vga_mem
= qemu_malloc(sizeof(*vga_mem
));
2238 memory_region_init_io(vga_mem
, &vga_mem_ops
, s
,
2239 "vga-lowmem", 0x20000);
2244 void vga_init(VGACommonState
*s
)
2246 MemoryRegion
*vga_io_memory
;
2248 qemu_register_reset(vga_reset
, s
);
2252 vga_io_memory
= vga_init_io(s
);
2253 memory_region_add_subregion_overlap(get_system_memory(),
2254 isa_mem_base
+ 0x000a0000,
2257 memory_region_set_coalescing(vga_io_memory
);
2260 void vga_init_vbe(VGACommonState
*s
)
2262 #ifdef CONFIG_BOCHS_VBE
2263 /* XXX: use optimized standard vga accesses */
2264 memory_region_add_subregion(get_system_memory(),
2265 VBE_DISPI_LFB_PHYSICAL_ADDRESS
,
2270 /********************************************************/
2271 /* vga screen dump */
2273 static void vga_save_dpy_update(DisplayState
*ds
,
2274 int x
, int y
, int w
, int h
)
2276 if (screen_dump_filename
) {
2277 ppm_save(screen_dump_filename
, ds
->surface
);
2278 screen_dump_filename
= NULL
;
2282 static void vga_save_dpy_resize(DisplayState
*s
)
2286 static void vga_save_dpy_refresh(DisplayState
*s
)
2290 int ppm_save(const char *filename
, struct DisplaySurface
*ds
)
2298 char *linebuf
, *pbuf
;
2300 f
= fopen(filename
, "wb");
2303 fprintf(f
, "P6\n%d %d\n%d\n",
2304 ds
->width
, ds
->height
, 255);
2305 linebuf
= qemu_malloc(ds
->width
* 3);
2307 for(y
= 0; y
< ds
->height
; y
++) {
2310 for(x
= 0; x
< ds
->width
; x
++) {
2311 if (ds
->pf
.bits_per_pixel
== 32)
2314 v
= (uint32_t) (*(uint16_t *)d
);
2315 r
= ((v
>> ds
->pf
.rshift
) & ds
->pf
.rmax
) * 256 /
2317 g
= ((v
>> ds
->pf
.gshift
) & ds
->pf
.gmax
) * 256 /
2319 b
= ((v
>> ds
->pf
.bshift
) & ds
->pf
.bmax
) * 256 /
2324 d
+= ds
->pf
.bytes_per_pixel
;
2327 ret
= fwrite(linebuf
, 1, pbuf
- linebuf
, f
);
2335 static DisplayChangeListener
* vga_screen_dump_init(DisplayState
*ds
)
2337 DisplayChangeListener
*dcl
;
2339 dcl
= qemu_mallocz(sizeof(DisplayChangeListener
));
2340 dcl
->dpy_update
= vga_save_dpy_update
;
2341 dcl
->dpy_resize
= vga_save_dpy_resize
;
2342 dcl
->dpy_refresh
= vga_save_dpy_refresh
;
2343 register_displaychangelistener(ds
, dcl
);
2347 /* save the vga display in a PPM image even if no display is
2349 static void vga_screen_dump(void *opaque
, const char *filename
)
2351 VGACommonState
*s
= opaque
;
2353 if (!screen_dump_dcl
)
2354 screen_dump_dcl
= vga_screen_dump_init(s
->ds
);
2356 screen_dump_filename
= (char *)filename
;
2357 vga_invalidate_display(s
);