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