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
27 //#define DEBUG_VGA_MEM
28 //#define DEBUG_VGA_REG
31 //#define DEBUG_BOCHS_VBE
33 /* S3 VGA is deprecated - another graphic card will be emulated */
34 //#define CONFIG_S3VGA
36 #define MSR_COLOR_EMULATION 0x01
37 #define MSR_PAGE_SELECT 0x20
39 #define ST01_V_RETRACE 0x08
40 #define ST01_DISP_ENABLE 0x01
42 /* bochs VBE support */
43 #define CONFIG_BOCHS_VBE
45 #define VBE_DISPI_MAX_XRES 1024
46 #define VBE_DISPI_MAX_YRES 768
48 #define VBE_DISPI_INDEX_ID 0x0
49 #define VBE_DISPI_INDEX_XRES 0x1
50 #define VBE_DISPI_INDEX_YRES 0x2
51 #define VBE_DISPI_INDEX_BPP 0x3
52 #define VBE_DISPI_INDEX_ENABLE 0x4
53 #define VBE_DISPI_INDEX_BANK 0x5
54 #define VBE_DISPI_INDEX_VIRT_WIDTH 0x6
55 #define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
56 #define VBE_DISPI_INDEX_X_OFFSET 0x8
57 #define VBE_DISPI_INDEX_Y_OFFSET 0x9
58 #define VBE_DISPI_INDEX_NB 0xa
60 #define VBE_DISPI_ID0 0xB0C0
61 #define VBE_DISPI_ID1 0xB0C1
62 #define VBE_DISPI_ID2 0xB0C2
64 #define VBE_DISPI_DISABLED 0x00
65 #define VBE_DISPI_ENABLED 0x01
66 #define VBE_DISPI_LFB_ENABLED 0x40
67 #define VBE_DISPI_NOCLEARMEM 0x80
69 #define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000
71 typedef struct VGAState {
73 unsigned long vram_offset;
74 unsigned int vram_size;
84 uint8_t cr[256]; /* CRT registers */
85 uint8_t msr; /* Misc Output Register */
86 uint8_t fcr; /* Feature Control Register */
87 uint8_t st00; /* status 0 */
88 uint8_t st01; /* status 1 */
90 uint8_t dac_sub_index;
91 uint8_t dac_read_index;
92 uint8_t dac_write_index;
93 uint8_t dac_cache[3]; /* used when writing */
96 #ifdef CONFIG_BOCHS_VBE
98 uint16_t vbe_regs[VBE_DISPI_INDEX_NB];
99 uint32_t vbe_start_addr;
100 uint32_t vbe_line_offset;
101 uint32_t vbe_bank_mask;
103 /* display refresh support */
105 uint32_t font_offsets[2];
107 uint8_t shift_control;
109 uint32_t line_offset;
110 uint32_t line_compare;
112 uint8_t last_cw, last_ch;
113 uint32_t last_width, last_height; /* in chars or pixels */
114 uint32_t last_scr_width, last_scr_height; /* in pixels */
115 uint8_t cursor_start, cursor_end;
116 uint32_t cursor_offset;
117 unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned b);
118 /* tell for each page if it has been updated since the last time */
119 uint32_t last_palette[256];
120 #define CH_ATTR_SIZE (160 * 100)
121 uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */
124 /* force some bits to zero */
125 static const uint8_t sr_mask[8] = {
136 static const uint8_t gr_mask[16] = {
137 (uint8_t)~0xf0, /* 0x00 */
138 (uint8_t)~0xf0, /* 0x01 */
139 (uint8_t)~0xf0, /* 0x02 */
140 (uint8_t)~0xe0, /* 0x03 */
141 (uint8_t)~0xfc, /* 0x04 */
142 (uint8_t)~0x84, /* 0x05 */
143 (uint8_t)~0xf0, /* 0x06 */
144 (uint8_t)~0xf0, /* 0x07 */
145 (uint8_t)~0x00, /* 0x08 */
146 (uint8_t)~0xff, /* 0x09 */
147 (uint8_t)~0xff, /* 0x0a */
148 (uint8_t)~0xff, /* 0x0b */
149 (uint8_t)~0xff, /* 0x0c */
150 (uint8_t)~0xff, /* 0x0d */
151 (uint8_t)~0xff, /* 0x0e */
152 (uint8_t)~0xff, /* 0x0f */
155 #define cbswap_32(__x) \
157 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
158 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
159 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
160 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
162 #ifdef WORDS_BIGENDIAN
163 #define PAT(x) cbswap_32(x)
168 #ifdef WORDS_BIGENDIAN
174 #ifdef WORDS_BIGENDIAN
175 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
177 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
180 static const uint32_t mask16[16] = {
201 #ifdef WORDS_BIGENDIAN
204 #define PAT(x) cbswap_32(x)
207 static const uint32_t dmask16[16] = {
226 static const uint32_t dmask4[4] = {
233 static uint32_t expand4[256];
234 static uint16_t expand2[256];
235 static uint8_t expand4to8[16];
240 static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
242 VGAState *s = opaque;
245 /* check port range access depending on color/monochrome mode */
246 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
247 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) {
252 if (s->ar_flip_flop == 0) {
259 index = s->ar_index & 0x1f;
272 val = s->sr[s->sr_index];
274 printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
281 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
282 if (++s->dac_sub_index == 3) {
283 s->dac_sub_index = 0;
297 val = s->gr[s->gr_index];
299 printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
308 val = s->cr[s->cr_index];
310 printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
313 if (s->cr_index >= 0x20)
314 printf("S3: CR read index=0x%x val=0x%x\n",
320 /* just toggle to fool polling */
321 s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE;
330 #if defined(DEBUG_VGA)
331 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
336 static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
338 VGAState *s = opaque;
341 /* check port range access depending on color/monochrome mode */
342 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
343 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION)))
347 printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
352 if (s->ar_flip_flop == 0) {
356 index = s->ar_index & 0x1f;
359 s->ar[index] = val & 0x3f;
362 s->ar[index] = val & ~0x10;
368 s->ar[index] = val & ~0xc0;
371 s->ar[index] = val & ~0xf0;
374 s->ar[index] = val & ~0xf0;
380 s->ar_flip_flop ^= 1;
383 s->msr = val & ~0x10;
386 s->sr_index = val & 7;
390 printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
392 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
395 s->dac_read_index = val;
396 s->dac_sub_index = 0;
400 s->dac_write_index = val;
401 s->dac_sub_index = 0;
405 s->dac_cache[s->dac_sub_index] = val;
406 if (++s->dac_sub_index == 3) {
407 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
408 s->dac_sub_index = 0;
409 s->dac_write_index++;
413 s->gr_index = val & 0x0f;
417 printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
419 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
428 printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
430 /* handle CR0-7 protection */
431 if ((s->cr[11] & 0x80) && s->cr_index <= 7) {
432 /* can always write bit 4 of CR7 */
433 if (s->cr_index == 7)
434 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
437 switch(s->cr_index) {
438 case 0x01: /* horizontal display end */
443 case 0x12: /* veritcal display end */
444 s->cr[s->cr_index] = val;
453 /* chip ID, cannot write */
456 /* update start address */
459 s->cr[s->cr_index] = val;
461 s->cr[0x69] = (s->cr[69] & ~0x03) | v;
465 /* update start address */
468 s->cr[s->cr_index] = val;
470 s->cr[0x69] = (s->cr[69] & ~0x0c) | (v << 2);
475 s->cr[s->cr_index] = val;
479 if (s->cr_index >= 0x20)
480 printf("S3: CR write index=0x%x val=0x%x\n",
491 #ifdef CONFIG_BOCHS_VBE
492 static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
494 VGAState *s = opaque;
500 static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
502 VGAState *s = opaque;
505 if (s->vbe_index <= VBE_DISPI_INDEX_NB)
506 val = s->vbe_regs[s->vbe_index];
509 #ifdef DEBUG_BOCHS_VBE
510 printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
515 static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
517 VGAState *s = opaque;
521 static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
523 VGAState *s = opaque;
525 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
526 #ifdef DEBUG_BOCHS_VBE
527 printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
529 switch(s->vbe_index) {
530 case VBE_DISPI_INDEX_ID:
531 if (val == VBE_DISPI_ID0 ||
532 val == VBE_DISPI_ID1 ||
533 val == VBE_DISPI_ID2) {
534 s->vbe_regs[s->vbe_index] = val;
537 case VBE_DISPI_INDEX_XRES:
538 if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
539 s->vbe_regs[s->vbe_index] = val;
542 case VBE_DISPI_INDEX_YRES:
543 if (val <= VBE_DISPI_MAX_YRES) {
544 s->vbe_regs[s->vbe_index] = val;
547 case VBE_DISPI_INDEX_BPP:
550 if (val == 4 || val == 8 || val == 15 ||
551 val == 16 || val == 24 || val == 32) {
552 s->vbe_regs[s->vbe_index] = val;
555 case VBE_DISPI_INDEX_BANK:
556 val &= s->vbe_bank_mask;
557 s->vbe_regs[s->vbe_index] = val;
558 s->bank_offset = (val << 16);
560 case VBE_DISPI_INDEX_ENABLE:
561 if (val & VBE_DISPI_ENABLED) {
562 int h, shift_control;
564 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
565 s->vbe_regs[VBE_DISPI_INDEX_XRES];
566 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
567 s->vbe_regs[VBE_DISPI_INDEX_YRES];
568 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
569 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
571 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
572 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
574 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
575 ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
576 s->vbe_start_addr = 0;
578 /* clear the screen (should be done in BIOS) */
579 if (!(val & VBE_DISPI_NOCLEARMEM)) {
580 memset(s->vram_ptr, 0,
581 s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
584 /* we initialize the VGA graphic mode (should be done
586 s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
587 s->cr[0x17] |= 3; /* no CGA modes */
588 s->cr[0x13] = s->vbe_line_offset >> 3;
590 s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
592 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
594 s->cr[0x07] = (s->cr[0x07] & ~0x42) |
595 ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
596 /* line compare to 1023 */
601 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
603 s->sr[0x01] &= ~8; /* no double line */
606 s->sr[4] |= 0x08; /* set chain 4 mode */
607 s->sr[2] |= 0x0f; /* activate all planes */
609 s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
610 s->cr[0x09] &= ~0x9f; /* no double scan */
612 /* XXX: the bios should do that */
615 s->vbe_regs[s->vbe_index] = val;
617 case VBE_DISPI_INDEX_VIRT_WIDTH:
619 int w, h, line_offset;
621 if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
624 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
625 line_offset = w >> 1;
627 line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
628 h = s->vram_size / line_offset;
629 /* XXX: support weird bochs semantics ? */
630 if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
632 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
633 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
634 s->vbe_line_offset = line_offset;
637 case VBE_DISPI_INDEX_X_OFFSET:
638 case VBE_DISPI_INDEX_Y_OFFSET:
641 s->vbe_regs[s->vbe_index] = val;
642 s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
643 x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
644 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
645 s->vbe_start_addr += x >> 1;
647 s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
648 s->vbe_start_addr >>= 2;
658 /* called for accesses between 0xa0000 and 0xc0000 */
659 static uint32_t vga_mem_readb(target_phys_addr_t addr)
661 VGAState *s = &vga_state;
662 int memory_map_mode, plane;
665 /* convert to VGA memory offset */
666 memory_map_mode = (s->gr[6] >> 2) & 3;
668 switch(memory_map_mode) {
674 addr += s->bank_offset;
689 if (s->sr[4] & 0x08) {
690 /* chain 4 mode : simplest access */
691 ret = s->vram_ptr[addr];
692 } else if (s->gr[5] & 0x10) {
693 /* odd/even mode (aka text mode mapping) */
694 plane = (s->gr[4] & 2) | (addr & 1);
695 ret = s->vram_ptr[((addr & ~1) << 1) | plane];
697 /* standard VGA latched access */
698 s->latch = ((uint32_t *)s->vram_ptr)[addr];
700 if (!(s->gr[5] & 0x08)) {
703 ret = GET_PLANE(s->latch, plane);
706 ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
715 static uint32_t vga_mem_readw(target_phys_addr_t addr)
718 #ifdef TARGET_WORDS_BIGENDIAN
719 v = vga_mem_readb(addr) << 8;
720 v |= vga_mem_readb(addr + 1);
722 v = vga_mem_readb(addr);
723 v |= vga_mem_readb(addr + 1) << 8;
728 static uint32_t vga_mem_readl(target_phys_addr_t addr)
731 #ifdef TARGET_WORDS_BIGENDIAN
732 v = vga_mem_readb(addr) << 24;
733 v |= vga_mem_readb(addr + 1) << 16;
734 v |= vga_mem_readb(addr + 2) << 8;
735 v |= vga_mem_readb(addr + 3);
737 v = vga_mem_readb(addr);
738 v |= vga_mem_readb(addr + 1) << 8;
739 v |= vga_mem_readb(addr + 2) << 16;
740 v |= vga_mem_readb(addr + 3) << 24;
745 /* called for accesses between 0xa0000 and 0xc0000 */
746 static void vga_mem_writeb(target_phys_addr_t addr, uint32_t val)
748 VGAState *s = &vga_state;
749 int memory_map_mode, plane, write_mode, b, func_select;
750 uint32_t write_mask, bit_mask, set_mask;
753 printf("vga: [0x%x] = 0x%02x\n", addr, val);
755 /* convert to VGA memory offset */
756 memory_map_mode = (s->gr[6] >> 2) & 3;
758 switch(memory_map_mode) {
764 addr += s->bank_offset;
779 if (s->sr[4] & 0x08) {
780 /* chain 4 mode : simplest access */
782 if (s->sr[2] & (1 << plane)) {
783 s->vram_ptr[addr] = val;
785 printf("vga: chain4: [0x%x]\n", addr);
787 cpu_physical_memory_set_dirty(s->vram_offset + addr);
789 } else if (s->gr[5] & 0x10) {
790 /* odd/even mode (aka text mode mapping) */
791 plane = (s->gr[4] & 2) | (addr & 1);
792 if (s->sr[2] & (1 << plane)) {
793 addr = ((addr & ~1) << 1) | plane;
794 s->vram_ptr[addr] = val;
796 printf("vga: odd/even: [0x%x]\n", addr);
798 cpu_physical_memory_set_dirty(s->vram_offset + addr);
801 /* standard VGA latched access */
802 write_mode = s->gr[5] & 3;
808 val = ((val >> b) | (val << (8 - b))) & 0xff;
812 /* apply set/reset mask */
813 set_mask = mask16[s->gr[1]];
814 val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
821 val = mask16[val & 0x0f];
827 val = (val >> b) | (val << (8 - b));
829 bit_mask = s->gr[8] & val;
830 val = mask16[s->gr[0]];
834 /* apply logical operation */
835 func_select = s->gr[3] >> 3;
836 switch(func_select) {
856 bit_mask |= bit_mask << 8;
857 bit_mask |= bit_mask << 16;
858 val = (val & bit_mask) | (s->latch & ~bit_mask);
861 /* mask data according to sr[2] */
862 write_mask = mask16[s->sr[2]];
863 ((uint32_t *)s->vram_ptr)[addr] =
864 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
867 printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
868 addr * 4, write_mask, val);
870 cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
874 static void vga_mem_writew(target_phys_addr_t addr, uint32_t val)
876 #ifdef TARGET_WORDS_BIGENDIAN
877 vga_mem_writeb(addr, (val >> 8) & 0xff);
878 vga_mem_writeb(addr + 1, val & 0xff);
880 vga_mem_writeb(addr, val & 0xff);
881 vga_mem_writeb(addr + 1, (val >> 8) & 0xff);
885 static void vga_mem_writel(target_phys_addr_t addr, uint32_t val)
887 #ifdef TARGET_WORDS_BIGENDIAN
888 vga_mem_writeb(addr, (val >> 24) & 0xff);
889 vga_mem_writeb(addr + 1, (val >> 16) & 0xff);
890 vga_mem_writeb(addr + 2, (val >> 8) & 0xff);
891 vga_mem_writeb(addr + 3, val & 0xff);
893 vga_mem_writeb(addr, val & 0xff);
894 vga_mem_writeb(addr + 1, (val >> 8) & 0xff);
895 vga_mem_writeb(addr + 2, (val >> 16) & 0xff);
896 vga_mem_writeb(addr + 3, (val >> 24) & 0xff);
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(VGAState *s1, uint8_t *d,
907 const uint8_t *s, int width);
909 static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
915 static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
917 return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
920 static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
922 return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
925 static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
927 return (r << 16) | (g << 8) | b;
931 #include "vga_template.h"
934 #include "vga_template.h"
937 #include "vga_template.h"
940 #include "vga_template.h"
942 static inline int c6_to_8(int v)
947 return (v << 2) | (b << 1) | b;
950 static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
953 col = rgb_to_pixel8(r, g, b);
959 static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
962 col = rgb_to_pixel15(r, g, b);
967 static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
970 col = rgb_to_pixel16(r, g, b);
975 static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
978 col = rgb_to_pixel32(r, g, b);
982 /* return true if the palette was modified */
983 static int update_palette16(VGAState *s)
986 uint32_t v, col, *palette;
989 palette = s->last_palette;
990 for(i = 0; i < 16; i++) {
992 if (s->ar[0x10] & 0x80)
993 v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
995 v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
997 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
998 c6_to_8(s->palette[v + 1]),
999 c6_to_8(s->palette[v + 2]));
1000 if (col != palette[i]) {
1008 /* return true if the palette was modified */
1009 static int update_palette256(VGAState *s)
1012 uint32_t v, col, *palette;
1015 palette = s->last_palette;
1017 for(i = 0; i < 256; i++) {
1018 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1019 c6_to_8(s->palette[v + 1]),
1020 c6_to_8(s->palette[v + 2]));
1021 if (col != palette[i]) {
1030 /* update start_addr and line_offset. Return TRUE if modified */
1031 static int update_basic_params(VGAState *s)
1034 uint32_t start_addr, line_offset, line_compare;
1038 #ifdef CONFIG_BOCHS_VBE
1039 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1040 line_offset = s->vbe_line_offset;
1041 start_addr = s->vbe_start_addr;
1045 /* compute line_offset in bytes */
1046 line_offset = s->cr[0x13];
1050 v = (s->cr[0x51] >> 4) & 3; /* S3 extension */
1052 v = (s->cr[0x43] >> 2) & 1; /* S3 extension */
1053 line_offset |= (v << 8);
1058 /* starting address */
1059 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
1061 start_addr |= (s->cr[0x69] & 0x1f) << 16; /* S3 extension */
1066 line_compare = s->cr[0x18] |
1067 ((s->cr[0x07] & 0x10) << 4) |
1068 ((s->cr[0x09] & 0x40) << 3);
1070 if (line_offset != s->line_offset ||
1071 start_addr != s->start_addr ||
1072 line_compare != s->line_compare) {
1073 s->line_offset = line_offset;
1074 s->start_addr = start_addr;
1075 s->line_compare = line_compare;
1081 static inline int get_depth_index(int depth)
1096 static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = {
1103 static vga_draw_glyph8_func *vga_draw_glyph16_table[4] = {
1105 vga_draw_glyph16_16,
1106 vga_draw_glyph16_16,
1107 vga_draw_glyph16_32,
1110 static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = {
1117 static const uint8_t cursor_glyph[32 * 4] = {
1118 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1119 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1120 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1121 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1122 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1123 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1124 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1125 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1126 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1127 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1128 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1129 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1130 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1131 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1132 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1133 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1144 static void vga_draw_text(VGAState *s, int full_update)
1146 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1147 int cx_min, cx_max, linesize, x_incr;
1148 uint32_t offset, fgcol, bgcol, v, cursor_offset;
1149 uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
1150 const uint8_t *font_ptr, *font_base[2];
1151 int dup9, line_offset, depth_index;
1153 uint32_t *ch_attr_ptr;
1154 vga_draw_glyph8_func *vga_draw_glyph8;
1155 vga_draw_glyph9_func *vga_draw_glyph9;
1157 full_update |= update_palette16(s);
1158 palette = s->last_palette;
1160 /* compute font data address (in plane 2) */
1162 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1163 if (offset != s->font_offsets[0]) {
1164 s->font_offsets[0] = offset;
1167 font_base[0] = s->vram_ptr + offset;
1169 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1170 font_base[1] = s->vram_ptr + offset;
1171 if (offset != s->font_offsets[1]) {
1172 s->font_offsets[1] = offset;
1176 full_update |= update_basic_params(s);
1178 line_offset = s->line_offset;
1179 s1 = s->vram_ptr + (s->start_addr * 4);
1181 /* total width & height */
1182 cheight = (s->cr[9] & 0x1f) + 1;
1184 if (!(s->sr[1] & 0x01))
1186 if (s->sr[1] & 0x08)
1187 cw = 16; /* NOTE: no 18 pixel wide */
1188 x_incr = cw * ((s->ds->depth + 7) >> 3);
1189 width = (s->cr[0x01] + 1);
1190 if (s->cr[0x06] == 100) {
1191 /* ugly hack for CGA 160x100x16 - explain me the logic */
1194 height = s->cr[0x12] |
1195 ((s->cr[0x07] & 0x02) << 7) |
1196 ((s->cr[0x07] & 0x40) << 3);
1197 height = (height + 1) / cheight;
1199 if ((height * width) > CH_ATTR_SIZE) {
1200 /* better than nothing: exit if transient size is too big */
1204 if (width != s->last_width || height != s->last_height ||
1205 cw != s->last_cw || cheight != s->last_ch) {
1206 s->last_scr_width = width * cw;
1207 s->last_scr_height = height * cheight;
1208 dpy_resize(s->ds, s->last_scr_width, s->last_scr_height);
1209 s->last_width = width;
1210 s->last_height = height;
1211 s->last_ch = cheight;
1215 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1216 if (cursor_offset != s->cursor_offset ||
1217 s->cr[0xa] != s->cursor_start ||
1218 s->cr[0xb] != s->cursor_end) {
1219 /* if the cursor position changed, we update the old and new
1221 if (s->cursor_offset < CH_ATTR_SIZE)
1222 s->last_ch_attr[s->cursor_offset] = -1;
1223 if (cursor_offset < CH_ATTR_SIZE)
1224 s->last_ch_attr[cursor_offset] = -1;
1225 s->cursor_offset = cursor_offset;
1226 s->cursor_start = s->cr[0xa];
1227 s->cursor_end = s->cr[0xb];
1229 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
1231 depth_index = get_depth_index(s->ds->depth);
1233 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1235 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
1236 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1239 linesize = s->ds->linesize;
1240 ch_attr_ptr = s->last_ch_attr;
1241 for(cy = 0; cy < height; cy++) {
1246 for(cx = 0; cx < width; cx++) {
1247 ch_attr = *(uint16_t *)src;
1248 if (full_update || ch_attr != *ch_attr_ptr) {
1253 *ch_attr_ptr = ch_attr;
1254 #ifdef WORDS_BIGENDIAN
1256 cattr = ch_attr & 0xff;
1258 ch = ch_attr & 0xff;
1259 cattr = ch_attr >> 8;
1261 font_ptr = font_base[(cattr >> 3) & 1];
1262 font_ptr += 32 * 4 * ch;
1263 bgcol = palette[cattr >> 4];
1264 fgcol = palette[cattr & 0x0f];
1266 vga_draw_glyph8(d1, linesize,
1267 font_ptr, cheight, fgcol, bgcol);
1270 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1272 vga_draw_glyph9(d1, linesize,
1273 font_ptr, cheight, fgcol, bgcol, dup9);
1275 if (src == cursor_ptr &&
1276 !(s->cr[0x0a] & 0x20)) {
1277 int line_start, line_last, h;
1278 /* draw the cursor */
1279 line_start = s->cr[0x0a] & 0x1f;
1280 line_last = s->cr[0x0b] & 0x1f;
1281 /* XXX: check that */
1282 if (line_last > cheight - 1)
1283 line_last = cheight - 1;
1284 if (line_last >= line_start && line_start < cheight) {
1285 h = line_last - line_start + 1;
1286 d = d1 + linesize * line_start;
1288 vga_draw_glyph8(d, linesize,
1289 cursor_glyph, h, fgcol, bgcol);
1291 vga_draw_glyph9(d, linesize,
1292 cursor_glyph, h, fgcol, bgcol, 1);
1302 dpy_update(s->ds, cx_min * cw, cy * cheight,
1303 (cx_max - cx_min + 1) * cw, cheight);
1305 dest += linesize * cheight;
1324 static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = {
1331 vga_draw_line2d2_16,
1332 vga_draw_line2d2_16,
1333 vga_draw_line2d2_32,
1341 vga_draw_line4d2_16,
1342 vga_draw_line4d2_16,
1343 vga_draw_line4d2_32,
1346 vga_draw_line8d2_16,
1347 vga_draw_line8d2_16,
1348 vga_draw_line8d2_32,
1382 static void vga_draw_graphic(VGAState *s, int full_update)
1384 int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask;
1385 int width, height, shift_control, line_offset, page0, page1, bwidth;
1386 int disp_width, multi_scan, multi_run;
1388 uint32_t v, addr1, addr;
1389 vga_draw_line_func *vga_draw_line;
1391 full_update |= update_basic_params(s);
1393 width = (s->cr[0x01] + 1) * 8;
1394 height = s->cr[0x12] |
1395 ((s->cr[0x07] & 0x02) << 7) |
1396 ((s->cr[0x07] & 0x40) << 3);
1397 height = (height + 1);
1400 shift_control = (s->gr[0x05] >> 5) & 3;
1401 double_scan = (s->cr[0x09] & 0x80);
1402 if (shift_control > 1) {
1403 multi_scan = (s->cr[0x09] & 0x1f);
1407 multi_run = multi_scan;
1408 if (shift_control != s->shift_control ||
1409 double_scan != s->double_scan) {
1411 s->shift_control = shift_control;
1412 s->double_scan = double_scan;
1415 if (shift_control == 0) {
1416 full_update |= update_palette16(s);
1417 if (s->sr[0x01] & 8) {
1418 v = VGA_DRAW_LINE4D2;
1423 } else if (shift_control == 1) {
1424 full_update |= update_palette16(s);
1425 if (s->sr[0x01] & 8) {
1426 v = VGA_DRAW_LINE2D2;
1432 #ifdef CONFIG_BOCHS_VBE
1433 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1434 switch(s->vbe_regs[VBE_DISPI_INDEX_BPP]) {
1437 full_update |= update_palette256(s);
1441 v = VGA_DRAW_LINE15;
1444 v = VGA_DRAW_LINE16;
1447 v = VGA_DRAW_LINE24;
1450 v = VGA_DRAW_LINE32;
1456 full_update |= update_palette256(s);
1457 v = VGA_DRAW_LINE8D2;
1460 vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)];
1462 if (disp_width != s->last_width ||
1463 height != s->last_height) {
1464 dpy_resize(s->ds, disp_width, height);
1465 s->last_scr_width = disp_width;
1466 s->last_scr_height = height;
1467 s->last_width = disp_width;
1468 s->last_height = height;
1472 line_offset = s->line_offset;
1474 printf("w=%d h=%d v=%d line_offset=%d double_scan=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=%02x\n",
1475 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1477 addr1 = (s->start_addr * 4);
1480 page_min = 0x7fffffff;
1483 linesize = s->ds->linesize;
1485 for(y = 0; y < height; y++) {
1487 if (!(s->cr[0x17] & 1)) {
1489 /* CGA compatibility handling */
1490 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1491 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1493 if (!(s->cr[0x17] & 2)) {
1494 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1496 page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
1497 page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
1498 update = full_update | cpu_physical_memory_is_dirty(page0) |
1499 cpu_physical_memory_is_dirty(page1);
1500 if ((page1 - page0) > TARGET_PAGE_SIZE) {
1501 /* if wide line, can use another page */
1502 update |= cpu_physical_memory_is_dirty(page0 + TARGET_PAGE_SIZE);
1507 if (page0 < page_min)
1509 if (page1 > page_max)
1511 vga_draw_line(s, d, s->vram_ptr + addr, width);
1514 /* flush to display */
1515 dpy_update(s->ds, 0, y_start,
1516 disp_width, y - y_start);
1521 if (!double_scan || (y & 1) != 0) {
1522 if (y1 == s->line_compare) {
1525 mask = (s->cr[0x17] & 3) ^ 3;
1526 if ((y1 & mask) == mask)
1527 addr1 += line_offset;
1531 multi_run = multi_scan;
1539 /* flush to display */
1540 dpy_update(s->ds, 0, y_start,
1541 disp_width, y - y_start);
1543 /* reset modified pages */
1544 if (page_max != -1) {
1545 cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE);
1549 static void vga_draw_blank(VGAState *s, int full_update)
1556 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1558 if (s->ds->depth == 8)
1559 val = s->rgb_to_pixel(0, 0, 0);
1562 w = s->last_scr_width * ((s->ds->depth + 7) >> 3);
1564 for(i = 0; i < s->last_scr_height; i++) {
1566 d += s->ds->linesize;
1568 dpy_update(s->ds, 0, 0,
1569 s->last_scr_width, s->last_scr_height);
1572 #define GMODE_TEXT 0
1573 #define GMODE_GRAPH 1
1574 #define GMODE_BLANK 2
1576 void vga_update_display(void)
1578 VGAState *s = &vga_state;
1579 int full_update, graphic_mode;
1581 if (s->ds->depth == 0) {
1584 switch(s->ds->depth) {
1586 s->rgb_to_pixel = rgb_to_pixel8_dup;
1589 s->rgb_to_pixel = rgb_to_pixel15_dup;
1593 s->rgb_to_pixel = rgb_to_pixel16_dup;
1596 s->rgb_to_pixel = rgb_to_pixel32_dup;
1601 if (!(s->ar_index & 0x20)) {
1602 graphic_mode = GMODE_BLANK;
1604 graphic_mode = s->gr[6] & 1;
1606 if (graphic_mode != s->graphic_mode) {
1607 s->graphic_mode = graphic_mode;
1610 switch(graphic_mode) {
1612 vga_draw_text(s, full_update);
1615 vga_draw_graphic(s, full_update);
1619 vga_draw_blank(s, full_update);
1625 static void vga_reset(VGAState *s)
1627 memset(s, 0, sizeof(VGAState));
1629 /* chip ID for 8c968 */
1632 s->cr[0x2f] = 0x01; /* XXX: check revision code */
1635 s->graphic_mode = -1; /* force full update */
1638 static CPUReadMemoryFunc *vga_mem_read[3] = {
1644 static CPUWriteMemoryFunc *vga_mem_write[3] = {
1650 static void vga_save(QEMUFile *f, void *opaque)
1652 VGAState *s = opaque;
1655 qemu_put_be32s(f, &s->latch);
1656 qemu_put_8s(f, &s->sr_index);
1657 qemu_put_buffer(f, s->sr, 8);
1658 qemu_put_8s(f, &s->gr_index);
1659 qemu_put_buffer(f, s->gr, 16);
1660 qemu_put_8s(f, &s->ar_index);
1661 qemu_put_buffer(f, s->ar, 21);
1662 qemu_put_be32s(f, &s->ar_flip_flop);
1663 qemu_put_8s(f, &s->cr_index);
1664 qemu_put_buffer(f, s->cr, 256);
1665 qemu_put_8s(f, &s->msr);
1666 qemu_put_8s(f, &s->fcr);
1667 qemu_put_8s(f, &s->st00);
1668 qemu_put_8s(f, &s->st01);
1670 qemu_put_8s(f, &s->dac_state);
1671 qemu_put_8s(f, &s->dac_sub_index);
1672 qemu_put_8s(f, &s->dac_read_index);
1673 qemu_put_8s(f, &s->dac_write_index);
1674 qemu_put_buffer(f, s->dac_cache, 3);
1675 qemu_put_buffer(f, s->palette, 768);
1677 qemu_put_be32s(f, &s->bank_offset);
1678 #ifdef CONFIG_BOCHS_VBE
1679 qemu_put_byte(f, 1);
1680 qemu_put_be16s(f, &s->vbe_index);
1681 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1682 qemu_put_be16s(f, &s->vbe_regs[i]);
1683 qemu_put_be32s(f, &s->vbe_start_addr);
1684 qemu_put_be32s(f, &s->vbe_line_offset);
1685 qemu_put_be32s(f, &s->vbe_bank_mask);
1687 qemu_put_byte(f, 0);
1691 static int vga_load(QEMUFile *f, void *opaque, int version_id)
1693 VGAState *s = opaque;
1696 if (version_id != 1)
1699 qemu_get_be32s(f, &s->latch);
1700 qemu_get_8s(f, &s->sr_index);
1701 qemu_get_buffer(f, s->sr, 8);
1702 qemu_get_8s(f, &s->gr_index);
1703 qemu_get_buffer(f, s->gr, 16);
1704 qemu_get_8s(f, &s->ar_index);
1705 qemu_get_buffer(f, s->ar, 21);
1706 qemu_get_be32s(f, &s->ar_flip_flop);
1707 qemu_get_8s(f, &s->cr_index);
1708 qemu_get_buffer(f, s->cr, 256);
1709 qemu_get_8s(f, &s->msr);
1710 qemu_get_8s(f, &s->fcr);
1711 qemu_get_8s(f, &s->st00);
1712 qemu_get_8s(f, &s->st01);
1714 qemu_get_8s(f, &s->dac_state);
1715 qemu_get_8s(f, &s->dac_sub_index);
1716 qemu_get_8s(f, &s->dac_read_index);
1717 qemu_get_8s(f, &s->dac_write_index);
1718 qemu_get_buffer(f, s->dac_cache, 3);
1719 qemu_get_buffer(f, s->palette, 768);
1721 qemu_get_be32s(f, &s->bank_offset);
1722 is_vbe = qemu_get_byte(f);
1723 #ifdef CONFIG_BOCHS_VBE
1726 qemu_get_be16s(f, &s->vbe_index);
1727 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1728 qemu_get_be16s(f, &s->vbe_regs[i]);
1729 qemu_get_be32s(f, &s->vbe_start_addr);
1730 qemu_get_be32s(f, &s->vbe_line_offset);
1731 qemu_get_be32s(f, &s->vbe_bank_mask);
1738 s->graphic_mode = -1;
1742 static void vga_map(PCIDevice *pci_dev, int region_num,
1743 uint32_t addr, uint32_t size, int type)
1745 VGAState *s = &vga_state;
1747 cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
1750 int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base,
1751 unsigned long vga_ram_offset, int vga_ram_size,
1754 VGAState *s = &vga_state;
1757 for(i = 0;i < 256; i++) {
1759 for(j = 0; j < 8; j++) {
1760 v |= ((i >> j) & 1) << (j * 4);
1765 for(j = 0; j < 4; j++) {
1766 v |= ((i >> (2 * j)) & 3) << (j * 4);
1770 for(i = 0; i < 16; i++) {
1772 for(j = 0; j < 4; j++) {
1775 v |= b << (2 * j + 1);
1782 s->vram_ptr = vga_ram_base;
1783 s->vram_offset = vga_ram_offset;
1784 s->vram_size = vga_ram_size;
1787 register_savevm("vga", 0, 1, vga_save, vga_load, s);
1789 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
1791 register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
1792 register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
1793 register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
1794 register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
1796 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
1798 register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
1799 register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
1800 register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
1801 register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
1804 #ifdef CONFIG_BOCHS_VBE
1805 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
1806 s->vbe_bank_mask = ((s->vram_size >> 16) - 1);
1807 #if defined (TARGET_I386)
1808 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
1809 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
1811 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
1812 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
1814 /* old Bochs IO ports */
1815 register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
1816 register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
1818 register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
1819 register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s);
1821 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
1822 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
1824 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
1825 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
1827 #endif /* CONFIG_BOCHS_VBE */
1829 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write);
1830 cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
1837 d = pci_register_device("VGA",
1841 pci_conf = d->config;
1842 pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID)
1843 pci_conf[0x01] = 0x12;
1844 pci_conf[0x02] = 0x11;
1845 pci_conf[0x03] = 0x11;
1846 pci_conf[0x0a] = 0x00; // VGA controller
1847 pci_conf[0x0b] = 0x03;
1848 pci_conf[0x0e] = 0x00; // header_type
1850 /* XXX: vga_ram_size must be a power of two */
1851 pci_register_io_region(d, 0, vga_ram_size,
1852 PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
1854 #ifdef CONFIG_BOCHS_VBE
1855 /* XXX: use optimized standard vga accesses */
1856 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
1857 vga_ram_size, vga_ram_offset);
1863 /********************************************************/
1864 /* vga screen dump */
1866 static int vga_save_w, vga_save_h;
1868 static void vga_save_dpy_update(DisplayState *s,
1869 int x, int y, int w, int h)
1873 static void vga_save_dpy_resize(DisplayState *s, int w, int h)
1875 s->linesize = w * 4;
1876 s->data = qemu_malloc(h * s->linesize);
1881 static void vga_save_dpy_refresh(DisplayState *s)
1885 static int ppm_save(const char *filename, uint8_t *data,
1886 int w, int h, int linesize)
1893 f = fopen(filename, "wb");
1896 fprintf(f, "P6\n%d %d\n%d\n",
1899 for(y = 0; y < h; y++) {
1901 for(x = 0; x < w; x++) {
1903 fputc((v >> 16) & 0xff, f);
1904 fputc((v >> 8) & 0xff, f);
1905 fputc((v) & 0xff, f);
1914 /* save the vga display in a PPM image even if no display is
1916 void vga_screen_dump(const char *filename)
1918 VGAState *s = &vga_state;
1919 DisplayState *saved_ds, ds1, *ds = &ds1;
1921 /* XXX: this is a little hackish */
1923 s->last_height = -1;
1926 memset(ds, 0, sizeof(DisplayState));
1927 ds->dpy_update = vga_save_dpy_update;
1928 ds->dpy_resize = vga_save_dpy_resize;
1929 ds->dpy_refresh = vga_save_dpy_refresh;
1933 s->graphic_mode = -1;
1934 vga_update_display();
1937 ppm_save(filename, ds->data, vga_save_w, vga_save_h,
1939 qemu_free(ds->data);