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
28 //#define DEBUG_VGA_MEM
29 //#define DEBUG_VGA_REG
32 //#define DEBUG_BOCHS_VBE
34 /* S3 VGA is deprecated - another graphic card will be emulated */
35 //#define CONFIG_S3VGA
37 /* force some bits to zero */
38 const uint8_t sr_mask[8] = {
49 const uint8_t gr_mask[16] = {
50 (uint8_t)~0xf0, /* 0x00 */
51 (uint8_t)~0xf0, /* 0x01 */
52 (uint8_t)~0xf0, /* 0x02 */
53 (uint8_t)~0xe0, /* 0x03 */
54 (uint8_t)~0xfc, /* 0x04 */
55 (uint8_t)~0x84, /* 0x05 */
56 (uint8_t)~0xf0, /* 0x06 */
57 (uint8_t)~0xf0, /* 0x07 */
58 (uint8_t)~0x00, /* 0x08 */
59 (uint8_t)~0xff, /* 0x09 */
60 (uint8_t)~0xff, /* 0x0a */
61 (uint8_t)~0xff, /* 0x0b */
62 (uint8_t)~0xff, /* 0x0c */
63 (uint8_t)~0xff, /* 0x0d */
64 (uint8_t)~0xff, /* 0x0e */
65 (uint8_t)~0xff, /* 0x0f */
68 #define cbswap_32(__x) \
70 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
71 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
72 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
73 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
75 #ifdef WORDS_BIGENDIAN
76 #define PAT(x) cbswap_32(x)
81 #ifdef WORDS_BIGENDIAN
87 #ifdef WORDS_BIGENDIAN
88 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
90 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
93 static const uint32_t mask16[16] = {
114 #ifdef WORDS_BIGENDIAN
117 #define PAT(x) cbswap_32(x)
120 static const uint32_t dmask16[16] = {
139 static const uint32_t dmask4[4] = {
146 static uint32_t expand4[256];
147 static uint16_t expand2[256];
148 static uint8_t expand4to8[16];
153 static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
155 VGAState *s = opaque;
158 /* check port range access depending on color/monochrome mode */
159 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
160 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) {
165 if (s->ar_flip_flop == 0) {
172 index = s->ar_index & 0x1f;
185 val = s->sr[s->sr_index];
187 printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
194 val = s->dac_write_index;
197 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
198 if (++s->dac_sub_index == 3) {
199 s->dac_sub_index = 0;
213 val = s->gr[s->gr_index];
215 printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
224 val = s->cr[s->cr_index];
226 printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
229 if (s->cr_index >= 0x20)
230 printf("S3: CR read index=0x%x val=0x%x\n",
236 /* just toggle to fool polling */
237 s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE;
246 #if defined(DEBUG_VGA)
247 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
252 static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
254 VGAState *s = opaque;
257 /* check port range access depending on color/monochrome mode */
258 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
259 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION)))
263 printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
268 if (s->ar_flip_flop == 0) {
272 index = s->ar_index & 0x1f;
275 s->ar[index] = val & 0x3f;
278 s->ar[index] = val & ~0x10;
284 s->ar[index] = val & ~0xc0;
287 s->ar[index] = val & ~0xf0;
290 s->ar[index] = val & ~0xf0;
296 s->ar_flip_flop ^= 1;
299 s->msr = val & ~0x10;
302 s->sr_index = val & 7;
306 printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
308 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
311 s->dac_read_index = val;
312 s->dac_sub_index = 0;
316 s->dac_write_index = val;
317 s->dac_sub_index = 0;
321 s->dac_cache[s->dac_sub_index] = val;
322 if (++s->dac_sub_index == 3) {
323 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
324 s->dac_sub_index = 0;
325 s->dac_write_index++;
329 s->gr_index = val & 0x0f;
333 printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
335 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
344 printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
346 /* handle CR0-7 protection */
347 if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
348 /* can always write bit 4 of CR7 */
349 if (s->cr_index == 7)
350 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
353 switch(s->cr_index) {
354 case 0x01: /* horizontal display end */
359 case 0x12: /* veritcal display end */
360 s->cr[s->cr_index] = val;
369 /* chip ID, cannot write */
372 /* update start address */
375 s->cr[s->cr_index] = val;
377 s->cr[0x69] = (s->cr[69] & ~0x03) | v;
381 /* update start address */
384 s->cr[s->cr_index] = val;
386 s->cr[0x69] = (s->cr[69] & ~0x0c) | (v << 2);
391 s->cr[s->cr_index] = val;
395 if (s->cr_index >= 0x20)
396 printf("S3: CR write index=0x%x val=0x%x\n",
407 #ifdef CONFIG_BOCHS_VBE
408 static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
410 VGAState *s = opaque;
416 static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
418 VGAState *s = opaque;
421 if (s->vbe_index <= VBE_DISPI_INDEX_NB)
422 val = s->vbe_regs[s->vbe_index];
425 #ifdef DEBUG_BOCHS_VBE
426 printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
431 static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
433 VGAState *s = opaque;
437 static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
439 VGAState *s = opaque;
441 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
442 #ifdef DEBUG_BOCHS_VBE
443 printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
445 switch(s->vbe_index) {
446 case VBE_DISPI_INDEX_ID:
447 if (val == VBE_DISPI_ID0 ||
448 val == VBE_DISPI_ID1 ||
449 val == VBE_DISPI_ID2) {
450 s->vbe_regs[s->vbe_index] = val;
453 case VBE_DISPI_INDEX_XRES:
454 if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
455 s->vbe_regs[s->vbe_index] = val;
458 case VBE_DISPI_INDEX_YRES:
459 if (val <= VBE_DISPI_MAX_YRES) {
460 s->vbe_regs[s->vbe_index] = val;
463 case VBE_DISPI_INDEX_BPP:
466 if (val == 4 || val == 8 || val == 15 ||
467 val == 16 || val == 24 || val == 32) {
468 s->vbe_regs[s->vbe_index] = val;
471 case VBE_DISPI_INDEX_BANK:
472 val &= s->vbe_bank_mask;
473 s->vbe_regs[s->vbe_index] = val;
474 s->bank_offset = (val << 16);
476 case VBE_DISPI_INDEX_ENABLE:
477 if (val & VBE_DISPI_ENABLED) {
478 int h, shift_control;
480 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
481 s->vbe_regs[VBE_DISPI_INDEX_XRES];
482 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
483 s->vbe_regs[VBE_DISPI_INDEX_YRES];
484 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
485 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
487 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
488 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
490 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
491 ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
492 s->vbe_start_addr = 0;
494 /* clear the screen (should be done in BIOS) */
495 if (!(val & VBE_DISPI_NOCLEARMEM)) {
496 memset(s->vram_ptr, 0,
497 s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
500 /* we initialize the VGA graphic mode (should be done
502 s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
503 s->cr[0x17] |= 3; /* no CGA modes */
504 s->cr[0x13] = s->vbe_line_offset >> 3;
506 s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
508 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
510 s->cr[0x07] = (s->cr[0x07] & ~0x42) |
511 ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
512 /* line compare to 1023 */
517 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
519 s->sr[0x01] &= ~8; /* no double line */
522 s->sr[4] |= 0x08; /* set chain 4 mode */
523 s->sr[2] |= 0x0f; /* activate all planes */
525 s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
526 s->cr[0x09] &= ~0x9f; /* no double scan */
528 /* XXX: the bios should do that */
531 s->vbe_regs[s->vbe_index] = val;
533 case VBE_DISPI_INDEX_VIRT_WIDTH:
535 int w, h, line_offset;
537 if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
540 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
541 line_offset = w >> 1;
543 line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
544 h = s->vram_size / line_offset;
545 /* XXX: support weird bochs semantics ? */
546 if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
548 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
549 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
550 s->vbe_line_offset = line_offset;
553 case VBE_DISPI_INDEX_X_OFFSET:
554 case VBE_DISPI_INDEX_Y_OFFSET:
557 s->vbe_regs[s->vbe_index] = val;
558 s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
559 x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
560 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
561 s->vbe_start_addr += x >> 1;
563 s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
564 s->vbe_start_addr >>= 2;
574 /* called for accesses between 0xa0000 and 0xc0000 */
575 uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
577 VGAState *s = opaque;
578 int memory_map_mode, plane;
581 /* convert to VGA memory offset */
582 memory_map_mode = (s->gr[6] >> 2) & 3;
584 switch(memory_map_mode) {
590 addr += s->bank_offset;
605 if (s->sr[4] & 0x08) {
606 /* chain 4 mode : simplest access */
607 ret = s->vram_ptr[addr];
608 } else if (s->gr[5] & 0x10) {
609 /* odd/even mode (aka text mode mapping) */
610 plane = (s->gr[4] & 2) | (addr & 1);
611 ret = s->vram_ptr[((addr & ~1) << 1) | plane];
613 /* standard VGA latched access */
614 s->latch = ((uint32_t *)s->vram_ptr)[addr];
616 if (!(s->gr[5] & 0x08)) {
619 ret = GET_PLANE(s->latch, plane);
622 ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
631 static uint32_t vga_mem_readw(void *opaque, target_phys_addr_t addr)
634 #ifdef TARGET_WORDS_BIGENDIAN
635 v = vga_mem_readb(opaque, addr) << 8;
636 v |= vga_mem_readb(opaque, addr + 1);
638 v = vga_mem_readb(opaque, addr);
639 v |= vga_mem_readb(opaque, addr + 1) << 8;
644 static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr)
647 #ifdef TARGET_WORDS_BIGENDIAN
648 v = vga_mem_readb(opaque, addr) << 24;
649 v |= vga_mem_readb(opaque, addr + 1) << 16;
650 v |= vga_mem_readb(opaque, addr + 2) << 8;
651 v |= vga_mem_readb(opaque, addr + 3);
653 v = vga_mem_readb(opaque, addr);
654 v |= vga_mem_readb(opaque, addr + 1) << 8;
655 v |= vga_mem_readb(opaque, addr + 2) << 16;
656 v |= vga_mem_readb(opaque, addr + 3) << 24;
661 /* called for accesses between 0xa0000 and 0xc0000 */
662 void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
664 VGAState *s = opaque;
665 int memory_map_mode, plane, write_mode, b, func_select;
666 uint32_t write_mask, bit_mask, set_mask;
669 printf("vga: [0x%x] = 0x%02x\n", addr, val);
671 /* convert to VGA memory offset */
672 memory_map_mode = (s->gr[6] >> 2) & 3;
674 switch(memory_map_mode) {
680 addr += s->bank_offset;
695 if (s->sr[4] & 0x08) {
696 /* chain 4 mode : simplest access */
698 if (s->sr[2] & (1 << plane)) {
699 s->vram_ptr[addr] = val;
701 printf("vga: chain4: [0x%x]\n", addr);
703 cpu_physical_memory_set_dirty(s->vram_offset + addr);
705 } else if (s->gr[5] & 0x10) {
706 /* odd/even mode (aka text mode mapping) */
707 plane = (s->gr[4] & 2) | (addr & 1);
708 if (s->sr[2] & (1 << plane)) {
709 addr = ((addr & ~1) << 1) | plane;
710 s->vram_ptr[addr] = val;
712 printf("vga: odd/even: [0x%x]\n", addr);
714 cpu_physical_memory_set_dirty(s->vram_offset + addr);
717 /* standard VGA latched access */
718 write_mode = s->gr[5] & 3;
724 val = ((val >> b) | (val << (8 - b))) & 0xff;
728 /* apply set/reset mask */
729 set_mask = mask16[s->gr[1]];
730 val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
737 val = mask16[val & 0x0f];
743 val = (val >> b) | (val << (8 - b));
745 bit_mask = s->gr[8] & val;
746 val = mask16[s->gr[0]];
750 /* apply logical operation */
751 func_select = s->gr[3] >> 3;
752 switch(func_select) {
772 bit_mask |= bit_mask << 8;
773 bit_mask |= bit_mask << 16;
774 val = (val & bit_mask) | (s->latch & ~bit_mask);
777 /* mask data according to sr[2] */
778 write_mask = mask16[s->sr[2]];
779 ((uint32_t *)s->vram_ptr)[addr] =
780 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
783 printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
784 addr * 4, write_mask, val);
786 cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
790 static void vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
792 #ifdef TARGET_WORDS_BIGENDIAN
793 vga_mem_writeb(opaque, addr, (val >> 8) & 0xff);
794 vga_mem_writeb(opaque, addr + 1, val & 0xff);
796 vga_mem_writeb(opaque, addr, val & 0xff);
797 vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
801 static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
803 #ifdef TARGET_WORDS_BIGENDIAN
804 vga_mem_writeb(opaque, addr, (val >> 24) & 0xff);
805 vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
806 vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
807 vga_mem_writeb(opaque, addr + 3, val & 0xff);
809 vga_mem_writeb(opaque, addr, val & 0xff);
810 vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
811 vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
812 vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
816 typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
817 const uint8_t *font_ptr, int h,
818 uint32_t fgcol, uint32_t bgcol);
819 typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
820 const uint8_t *font_ptr, int h,
821 uint32_t fgcol, uint32_t bgcol, int dup9);
822 typedef void vga_draw_line_func(VGAState *s1, uint8_t *d,
823 const uint8_t *s, int width);
825 static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
827 return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
830 static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
832 return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
835 static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
837 return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
840 static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
842 return (r << 16) | (g << 8) | b;
846 #include "vga_template.h"
849 #include "vga_template.h"
852 #include "vga_template.h"
855 #include "vga_template.h"
857 static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
860 col = rgb_to_pixel8(r, g, b);
866 static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
869 col = rgb_to_pixel15(r, g, b);
874 static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
877 col = rgb_to_pixel16(r, g, b);
882 static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
885 col = rgb_to_pixel32(r, g, b);
889 /* return true if the palette was modified */
890 static int update_palette16(VGAState *s)
893 uint32_t v, col, *palette;
896 palette = s->last_palette;
897 for(i = 0; i < 16; i++) {
899 if (s->ar[0x10] & 0x80)
900 v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
902 v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
904 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
905 c6_to_8(s->palette[v + 1]),
906 c6_to_8(s->palette[v + 2]));
907 if (col != palette[i]) {
915 /* return true if the palette was modified */
916 static int update_palette256(VGAState *s)
919 uint32_t v, col, *palette;
922 palette = s->last_palette;
924 for(i = 0; i < 256; i++) {
925 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
926 c6_to_8(s->palette[v + 1]),
927 c6_to_8(s->palette[v + 2]));
928 if (col != palette[i]) {
937 static void vga_get_offsets(VGAState *s,
938 uint32_t *pline_offset,
939 uint32_t *pstart_addr)
941 uint32_t start_addr, line_offset;
942 #ifdef CONFIG_BOCHS_VBE
943 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
944 line_offset = s->vbe_line_offset;
945 start_addr = s->vbe_start_addr;
949 /* compute line_offset in bytes */
950 line_offset = s->cr[0x13];
954 v = (s->cr[0x51] >> 4) & 3; /* S3 extension */
956 v = (s->cr[0x43] >> 2) & 1; /* S3 extension */
957 line_offset |= (v << 8);
962 /* starting address */
963 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
965 start_addr |= (s->cr[0x69] & 0x1f) << 16; /* S3 extension */
968 *pline_offset = line_offset;
969 *pstart_addr = start_addr;
972 /* update start_addr and line_offset. Return TRUE if modified */
973 static int update_basic_params(VGAState *s)
976 uint32_t start_addr, line_offset, line_compare;
980 s->get_offsets(s, &line_offset, &start_addr);
982 line_compare = s->cr[0x18] |
983 ((s->cr[0x07] & 0x10) << 4) |
984 ((s->cr[0x09] & 0x40) << 3);
986 if (line_offset != s->line_offset ||
987 start_addr != s->start_addr ||
988 line_compare != s->line_compare) {
989 s->line_offset = line_offset;
990 s->start_addr = start_addr;
991 s->line_compare = line_compare;
997 static inline int get_depth_index(int depth)
1012 static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = {
1019 static vga_draw_glyph8_func *vga_draw_glyph16_table[4] = {
1021 vga_draw_glyph16_16,
1022 vga_draw_glyph16_16,
1023 vga_draw_glyph16_32,
1026 static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = {
1033 static const uint8_t cursor_glyph[32 * 4] = {
1034 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1035 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1036 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1037 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1038 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1039 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1040 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1041 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1042 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1043 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1044 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1045 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1046 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1047 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1048 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1049 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1060 static void vga_draw_text(VGAState *s, int full_update)
1062 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1063 int cx_min, cx_max, linesize, x_incr;
1064 uint32_t offset, fgcol, bgcol, v, cursor_offset;
1065 uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
1066 const uint8_t *font_ptr, *font_base[2];
1067 int dup9, line_offset, depth_index;
1069 uint32_t *ch_attr_ptr;
1070 vga_draw_glyph8_func *vga_draw_glyph8;
1071 vga_draw_glyph9_func *vga_draw_glyph9;
1073 full_update |= update_palette16(s);
1074 palette = s->last_palette;
1076 /* compute font data address (in plane 2) */
1078 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1079 if (offset != s->font_offsets[0]) {
1080 s->font_offsets[0] = offset;
1083 font_base[0] = s->vram_ptr + offset;
1085 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1086 font_base[1] = s->vram_ptr + offset;
1087 if (offset != s->font_offsets[1]) {
1088 s->font_offsets[1] = offset;
1092 full_update |= update_basic_params(s);
1094 line_offset = s->line_offset;
1095 s1 = s->vram_ptr + (s->start_addr * 4);
1097 /* total width & height */
1098 cheight = (s->cr[9] & 0x1f) + 1;
1100 if (!(s->sr[1] & 0x01))
1102 if (s->sr[1] & 0x08)
1103 cw = 16; /* NOTE: no 18 pixel wide */
1104 x_incr = cw * ((s->ds->depth + 7) >> 3);
1105 width = (s->cr[0x01] + 1);
1106 if (s->cr[0x06] == 100) {
1107 /* ugly hack for CGA 160x100x16 - explain me the logic */
1110 height = s->cr[0x12] |
1111 ((s->cr[0x07] & 0x02) << 7) |
1112 ((s->cr[0x07] & 0x40) << 3);
1113 height = (height + 1) / cheight;
1115 if ((height * width) > CH_ATTR_SIZE) {
1116 /* better than nothing: exit if transient size is too big */
1120 if (width != s->last_width || height != s->last_height ||
1121 cw != s->last_cw || cheight != s->last_ch) {
1122 s->last_scr_width = width * cw;
1123 s->last_scr_height = height * cheight;
1124 dpy_resize(s->ds, s->last_scr_width, s->last_scr_height);
1125 s->last_width = width;
1126 s->last_height = height;
1127 s->last_ch = cheight;
1131 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1132 if (cursor_offset != s->cursor_offset ||
1133 s->cr[0xa] != s->cursor_start ||
1134 s->cr[0xb] != s->cursor_end) {
1135 /* if the cursor position changed, we update the old and new
1137 if (s->cursor_offset < CH_ATTR_SIZE)
1138 s->last_ch_attr[s->cursor_offset] = -1;
1139 if (cursor_offset < CH_ATTR_SIZE)
1140 s->last_ch_attr[cursor_offset] = -1;
1141 s->cursor_offset = cursor_offset;
1142 s->cursor_start = s->cr[0xa];
1143 s->cursor_end = s->cr[0xb];
1145 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
1147 depth_index = get_depth_index(s->ds->depth);
1149 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1151 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
1152 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1155 linesize = s->ds->linesize;
1156 ch_attr_ptr = s->last_ch_attr;
1157 for(cy = 0; cy < height; cy++) {
1162 for(cx = 0; cx < width; cx++) {
1163 ch_attr = *(uint16_t *)src;
1164 if (full_update || ch_attr != *ch_attr_ptr) {
1169 *ch_attr_ptr = ch_attr;
1170 #ifdef WORDS_BIGENDIAN
1172 cattr = ch_attr & 0xff;
1174 ch = ch_attr & 0xff;
1175 cattr = ch_attr >> 8;
1177 font_ptr = font_base[(cattr >> 3) & 1];
1178 font_ptr += 32 * 4 * ch;
1179 bgcol = palette[cattr >> 4];
1180 fgcol = palette[cattr & 0x0f];
1182 vga_draw_glyph8(d1, linesize,
1183 font_ptr, cheight, fgcol, bgcol);
1186 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1188 vga_draw_glyph9(d1, linesize,
1189 font_ptr, cheight, fgcol, bgcol, dup9);
1191 if (src == cursor_ptr &&
1192 !(s->cr[0x0a] & 0x20)) {
1193 int line_start, line_last, h;
1194 /* draw the cursor */
1195 line_start = s->cr[0x0a] & 0x1f;
1196 line_last = s->cr[0x0b] & 0x1f;
1197 /* XXX: check that */
1198 if (line_last > cheight - 1)
1199 line_last = cheight - 1;
1200 if (line_last >= line_start && line_start < cheight) {
1201 h = line_last - line_start + 1;
1202 d = d1 + linesize * line_start;
1204 vga_draw_glyph8(d, linesize,
1205 cursor_glyph, h, fgcol, bgcol);
1207 vga_draw_glyph9(d, linesize,
1208 cursor_glyph, h, fgcol, bgcol, 1);
1218 dpy_update(s->ds, cx_min * cw, cy * cheight,
1219 (cx_max - cx_min + 1) * cw, cheight);
1221 dest += linesize * cheight;
1240 static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = {
1247 vga_draw_line2d2_16,
1248 vga_draw_line2d2_16,
1249 vga_draw_line2d2_32,
1257 vga_draw_line4d2_16,
1258 vga_draw_line4d2_16,
1259 vga_draw_line4d2_32,
1262 vga_draw_line8d2_16,
1263 vga_draw_line8d2_16,
1264 vga_draw_line8d2_32,
1292 static int vga_get_bpp(VGAState *s)
1295 #ifdef CONFIG_BOCHS_VBE
1296 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1297 ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
1306 static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight)
1310 width = (s->cr[0x01] + 1) * 8;
1311 height = s->cr[0x12] |
1312 ((s->cr[0x07] & 0x02) << 7) |
1313 ((s->cr[0x07] & 0x40) << 3);
1314 height = (height + 1);
1319 void vga_invalidate_scanlines(VGAState *s, int y1, int y2)
1322 if (y1 >= VGA_MAX_HEIGHT)
1324 if (y2 >= VGA_MAX_HEIGHT)
1325 y2 = VGA_MAX_HEIGHT;
1326 for(y = y1; y < y2; y++) {
1327 s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1334 static void vga_draw_graphic(VGAState *s, int full_update)
1336 int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask;
1337 int width, height, shift_control, line_offset, page0, page1, bwidth;
1338 int disp_width, multi_scan, multi_run;
1340 uint32_t v, addr1, addr;
1341 vga_draw_line_func *vga_draw_line;
1343 full_update |= update_basic_params(s);
1345 s->get_resolution(s, &width, &height);
1348 shift_control = (s->gr[0x05] >> 5) & 3;
1349 double_scan = (s->cr[0x09] >> 7);
1350 if (shift_control != 1) {
1351 multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
1353 /* in CGA modes, multi_scan is ignored */
1354 /* XXX: is it correct ? */
1355 multi_scan = double_scan;
1357 multi_run = multi_scan;
1358 if (shift_control != s->shift_control ||
1359 double_scan != s->double_scan) {
1361 s->shift_control = shift_control;
1362 s->double_scan = double_scan;
1365 if (shift_control == 0) {
1366 full_update |= update_palette16(s);
1367 if (s->sr[0x01] & 8) {
1368 v = VGA_DRAW_LINE4D2;
1373 } else if (shift_control == 1) {
1374 full_update |= update_palette16(s);
1375 if (s->sr[0x01] & 8) {
1376 v = VGA_DRAW_LINE2D2;
1382 switch(s->get_bpp(s)) {
1385 full_update |= update_palette256(s);
1386 v = VGA_DRAW_LINE8D2;
1389 full_update |= update_palette256(s);
1393 v = VGA_DRAW_LINE15;
1396 v = VGA_DRAW_LINE16;
1399 v = VGA_DRAW_LINE24;
1402 v = VGA_DRAW_LINE32;
1406 vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)];
1408 if (disp_width != s->last_width ||
1409 height != s->last_height) {
1410 dpy_resize(s->ds, disp_width, height);
1411 s->last_scr_width = disp_width;
1412 s->last_scr_height = height;
1413 s->last_width = disp_width;
1414 s->last_height = height;
1417 if (s->cursor_invalidate)
1418 s->cursor_invalidate(s);
1420 line_offset = s->line_offset;
1422 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",
1423 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1425 addr1 = (s->start_addr * 4);
1428 page_min = 0x7fffffff;
1431 linesize = s->ds->linesize;
1433 for(y = 0; y < height; y++) {
1435 if (!(s->cr[0x17] & 1)) {
1437 /* CGA compatibility handling */
1438 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1439 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1441 if (!(s->cr[0x17] & 2)) {
1442 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1444 page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
1445 page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
1446 update = full_update | cpu_physical_memory_is_dirty(page0) |
1447 cpu_physical_memory_is_dirty(page1);
1448 if ((page1 - page0) > TARGET_PAGE_SIZE) {
1449 /* if wide line, can use another page */
1450 update |= cpu_physical_memory_is_dirty(page0 + TARGET_PAGE_SIZE);
1452 /* explicit invalidation for the hardware cursor */
1453 update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
1457 if (page0 < page_min)
1459 if (page1 > page_max)
1461 vga_draw_line(s, d, s->vram_ptr + addr, width);
1462 if (s->cursor_draw_line)
1463 s->cursor_draw_line(s, d, y);
1466 /* flush to display */
1467 dpy_update(s->ds, 0, y_start,
1468 disp_width, y - y_start);
1473 mask = (s->cr[0x17] & 3) ^ 3;
1474 if ((y1 & mask) == mask)
1475 addr1 += line_offset;
1477 multi_run = multi_scan;
1481 /* line compare acts on the displayed lines */
1482 if (y == s->line_compare)
1487 /* flush to display */
1488 dpy_update(s->ds, 0, y_start,
1489 disp_width, y - y_start);
1491 /* reset modified pages */
1492 if (page_max != -1) {
1493 cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE);
1495 memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
1498 static void vga_draw_blank(VGAState *s, int full_update)
1505 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1507 if (s->ds->depth == 8)
1508 val = s->rgb_to_pixel(0, 0, 0);
1511 w = s->last_scr_width * ((s->ds->depth + 7) >> 3);
1513 for(i = 0; i < s->last_scr_height; i++) {
1515 d += s->ds->linesize;
1517 dpy_update(s->ds, 0, 0,
1518 s->last_scr_width, s->last_scr_height);
1521 #define GMODE_TEXT 0
1522 #define GMODE_GRAPH 1
1523 #define GMODE_BLANK 2
1525 void vga_update_display(void)
1527 VGAState *s = vga_state;
1528 int full_update, graphic_mode;
1530 if (s->ds->depth == 0) {
1533 switch(s->ds->depth) {
1535 s->rgb_to_pixel = rgb_to_pixel8_dup;
1538 s->rgb_to_pixel = rgb_to_pixel15_dup;
1542 s->rgb_to_pixel = rgb_to_pixel16_dup;
1545 s->rgb_to_pixel = rgb_to_pixel32_dup;
1550 if (!(s->ar_index & 0x20)) {
1551 graphic_mode = GMODE_BLANK;
1553 graphic_mode = s->gr[6] & 1;
1555 if (graphic_mode != s->graphic_mode) {
1556 s->graphic_mode = graphic_mode;
1559 switch(graphic_mode) {
1561 vga_draw_text(s, full_update);
1564 vga_draw_graphic(s, full_update);
1568 vga_draw_blank(s, full_update);
1574 /* force a full display refresh */
1575 void vga_invalidate_display(void)
1577 VGAState *s = vga_state;
1580 s->last_height = -1;
1583 static void vga_reset(VGAState *s)
1585 memset(s, 0, sizeof(VGAState));
1587 /* chip ID for 8c968 */
1590 s->cr[0x2f] = 0x01; /* XXX: check revision code */
1593 s->graphic_mode = -1; /* force full update */
1596 static CPUReadMemoryFunc *vga_mem_read[3] = {
1602 static CPUWriteMemoryFunc *vga_mem_write[3] = {
1608 static void vga_save(QEMUFile *f, void *opaque)
1610 VGAState *s = opaque;
1613 qemu_put_be32s(f, &s->latch);
1614 qemu_put_8s(f, &s->sr_index);
1615 qemu_put_buffer(f, s->sr, 8);
1616 qemu_put_8s(f, &s->gr_index);
1617 qemu_put_buffer(f, s->gr, 16);
1618 qemu_put_8s(f, &s->ar_index);
1619 qemu_put_buffer(f, s->ar, 21);
1620 qemu_put_be32s(f, &s->ar_flip_flop);
1621 qemu_put_8s(f, &s->cr_index);
1622 qemu_put_buffer(f, s->cr, 256);
1623 qemu_put_8s(f, &s->msr);
1624 qemu_put_8s(f, &s->fcr);
1625 qemu_put_8s(f, &s->st00);
1626 qemu_put_8s(f, &s->st01);
1628 qemu_put_8s(f, &s->dac_state);
1629 qemu_put_8s(f, &s->dac_sub_index);
1630 qemu_put_8s(f, &s->dac_read_index);
1631 qemu_put_8s(f, &s->dac_write_index);
1632 qemu_put_buffer(f, s->dac_cache, 3);
1633 qemu_put_buffer(f, s->palette, 768);
1635 qemu_put_be32s(f, &s->bank_offset);
1636 #ifdef CONFIG_BOCHS_VBE
1637 qemu_put_byte(f, 1);
1638 qemu_put_be16s(f, &s->vbe_index);
1639 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1640 qemu_put_be16s(f, &s->vbe_regs[i]);
1641 qemu_put_be32s(f, &s->vbe_start_addr);
1642 qemu_put_be32s(f, &s->vbe_line_offset);
1643 qemu_put_be32s(f, &s->vbe_bank_mask);
1645 qemu_put_byte(f, 0);
1649 static int vga_load(QEMUFile *f, void *opaque, int version_id)
1651 VGAState *s = opaque;
1654 if (version_id != 1)
1657 qemu_get_be32s(f, &s->latch);
1658 qemu_get_8s(f, &s->sr_index);
1659 qemu_get_buffer(f, s->sr, 8);
1660 qemu_get_8s(f, &s->gr_index);
1661 qemu_get_buffer(f, s->gr, 16);
1662 qemu_get_8s(f, &s->ar_index);
1663 qemu_get_buffer(f, s->ar, 21);
1664 qemu_get_be32s(f, &s->ar_flip_flop);
1665 qemu_get_8s(f, &s->cr_index);
1666 qemu_get_buffer(f, s->cr, 256);
1667 qemu_get_8s(f, &s->msr);
1668 qemu_get_8s(f, &s->fcr);
1669 qemu_get_8s(f, &s->st00);
1670 qemu_get_8s(f, &s->st01);
1672 qemu_get_8s(f, &s->dac_state);
1673 qemu_get_8s(f, &s->dac_sub_index);
1674 qemu_get_8s(f, &s->dac_read_index);
1675 qemu_get_8s(f, &s->dac_write_index);
1676 qemu_get_buffer(f, s->dac_cache, 3);
1677 qemu_get_buffer(f, s->palette, 768);
1679 qemu_get_be32s(f, &s->bank_offset);
1680 is_vbe = qemu_get_byte(f);
1681 #ifdef CONFIG_BOCHS_VBE
1684 qemu_get_be16s(f, &s->vbe_index);
1685 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1686 qemu_get_be16s(f, &s->vbe_regs[i]);
1687 qemu_get_be32s(f, &s->vbe_start_addr);
1688 qemu_get_be32s(f, &s->vbe_line_offset);
1689 qemu_get_be32s(f, &s->vbe_bank_mask);
1696 s->graphic_mode = -1;
1700 static void vga_map(PCIDevice *pci_dev, int region_num,
1701 uint32_t addr, uint32_t size, int type)
1703 VGAState *s = vga_state;
1705 cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
1708 void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
1709 unsigned long vga_ram_offset, int vga_ram_size)
1713 for(i = 0;i < 256; i++) {
1715 for(j = 0; j < 8; j++) {
1716 v |= ((i >> j) & 1) << (j * 4);
1721 for(j = 0; j < 4; j++) {
1722 v |= ((i >> (2 * j)) & 3) << (j * 4);
1726 for(i = 0; i < 16; i++) {
1728 for(j = 0; j < 4; j++) {
1731 v |= b << (2 * j + 1);
1738 s->vram_ptr = vga_ram_base;
1739 s->vram_offset = vga_ram_offset;
1740 s->vram_size = vga_ram_size;
1742 s->get_bpp = vga_get_bpp;
1743 s->get_offsets = vga_get_offsets;
1744 s->get_resolution = vga_get_resolution;
1745 /* XXX: currently needed for display */
1750 int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
1751 unsigned long vga_ram_offset, int vga_ram_size)
1755 s = qemu_mallocz(sizeof(VGAState));
1759 vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
1761 register_savevm("vga", 0, 1, vga_save, vga_load, s);
1763 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
1765 register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
1766 register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
1767 register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
1768 register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
1770 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
1772 register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
1773 register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
1774 register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
1775 register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
1778 #ifdef CONFIG_BOCHS_VBE
1779 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
1780 s->vbe_bank_mask = ((s->vram_size >> 16) - 1);
1781 #if defined (TARGET_I386)
1782 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
1783 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
1785 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
1786 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
1788 /* old Bochs IO ports */
1789 register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
1790 register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
1792 register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
1793 register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s);
1795 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
1796 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
1798 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
1799 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
1801 #endif /* CONFIG_BOCHS_VBE */
1803 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
1804 cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
1811 d = pci_register_device(bus, "VGA",
1814 pci_conf = d->config;
1815 pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID)
1816 pci_conf[0x01] = 0x12;
1817 pci_conf[0x02] = 0x11;
1818 pci_conf[0x03] = 0x11;
1819 pci_conf[0x0a] = 0x00; // VGA controller
1820 pci_conf[0x0b] = 0x03;
1821 pci_conf[0x0e] = 0x00; // header_type
1823 /* XXX: vga_ram_size must be a power of two */
1824 pci_register_io_region(d, 0, vga_ram_size,
1825 PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
1827 #ifdef CONFIG_BOCHS_VBE
1828 /* XXX: use optimized standard vga accesses */
1829 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
1830 vga_ram_size, vga_ram_offset);
1836 /********************************************************/
1837 /* vga screen dump */
1839 static int vga_save_w, vga_save_h;
1841 static void vga_save_dpy_update(DisplayState *s,
1842 int x, int y, int w, int h)
1846 static void vga_save_dpy_resize(DisplayState *s, int w, int h)
1848 s->linesize = w * 4;
1849 s->data = qemu_malloc(h * s->linesize);
1854 static void vga_save_dpy_refresh(DisplayState *s)
1858 static int ppm_save(const char *filename, uint8_t *data,
1859 int w, int h, int linesize)
1866 f = fopen(filename, "wb");
1869 fprintf(f, "P6\n%d %d\n%d\n",
1872 for(y = 0; y < h; y++) {
1874 for(x = 0; x < w; x++) {
1876 fputc((v >> 16) & 0xff, f);
1877 fputc((v >> 8) & 0xff, f);
1878 fputc((v) & 0xff, f);
1887 /* save the vga display in a PPM image even if no display is
1889 void vga_screen_dump(const char *filename)
1891 VGAState *s = vga_state;
1892 DisplayState *saved_ds, ds1, *ds = &ds1;
1894 /* XXX: this is a little hackish */
1895 vga_invalidate_display();
1898 memset(ds, 0, sizeof(DisplayState));
1899 ds->dpy_update = vga_save_dpy_update;
1900 ds->dpy_resize = vga_save_dpy_resize;
1901 ds->dpy_refresh = vga_save_dpy_refresh;
1905 s->graphic_mode = -1;
1906 vga_update_display();
1909 ppm_save(filename, ds->data, vga_save_w, vga_save_h,
1911 qemu_free(ds->data);