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
26 #include "pixel_ops.h"
29 //#define DEBUG_VGA_MEM
30 //#define DEBUG_VGA_REG
32 //#define DEBUG_BOCHS_VBE
34 /* force some bits to zero */
35 const uint8_t sr_mask[8] = {
46 const uint8_t gr_mask[16] = {
47 (uint8_t)~0xf0, /* 0x00 */
48 (uint8_t)~0xf0, /* 0x01 */
49 (uint8_t)~0xf0, /* 0x02 */
50 (uint8_t)~0xe0, /* 0x03 */
51 (uint8_t)~0xfc, /* 0x04 */
52 (uint8_t)~0x84, /* 0x05 */
53 (uint8_t)~0xf0, /* 0x06 */
54 (uint8_t)~0xf0, /* 0x07 */
55 (uint8_t)~0x00, /* 0x08 */
56 (uint8_t)~0xff, /* 0x09 */
57 (uint8_t)~0xff, /* 0x0a */
58 (uint8_t)~0xff, /* 0x0b */
59 (uint8_t)~0xff, /* 0x0c */
60 (uint8_t)~0xff, /* 0x0d */
61 (uint8_t)~0xff, /* 0x0e */
62 (uint8_t)~0xff, /* 0x0f */
65 #define cbswap_32(__x) \
67 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
68 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
69 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
70 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
72 #ifdef WORDS_BIGENDIAN
73 #define PAT(x) cbswap_32(x)
78 #ifdef WORDS_BIGENDIAN
84 #ifdef WORDS_BIGENDIAN
85 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
87 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
90 static const uint32_t mask16[16] = {
111 #ifdef WORDS_BIGENDIAN
114 #define PAT(x) cbswap_32(x)
117 static const uint32_t dmask16[16] = {
136 static const uint32_t dmask4[4] = {
143 static uint32_t expand4[256];
144 static uint16_t expand2[256];
145 static uint8_t expand4to8[16];
147 static void vga_screen_dump(void *opaque, const char *filename);
149 static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
151 VGAState *s = opaque;
154 /* check port range access depending on color/monochrome mode */
155 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
156 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) {
161 if (s->ar_flip_flop == 0) {
168 index = s->ar_index & 0x1f;
181 val = s->sr[s->sr_index];
183 printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
190 val = s->dac_write_index;
193 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
194 if (++s->dac_sub_index == 3) {
195 s->dac_sub_index = 0;
209 val = s->gr[s->gr_index];
211 printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
220 val = s->cr[s->cr_index];
222 printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
227 /* just toggle to fool polling */
228 s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE;
237 #if defined(DEBUG_VGA)
238 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
243 static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
245 VGAState *s = opaque;
248 /* check port range access depending on color/monochrome mode */
249 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
250 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION)))
254 printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
259 if (s->ar_flip_flop == 0) {
263 index = s->ar_index & 0x1f;
266 s->ar[index] = val & 0x3f;
269 s->ar[index] = val & ~0x10;
275 s->ar[index] = val & ~0xc0;
278 s->ar[index] = val & ~0xf0;
281 s->ar[index] = val & ~0xf0;
287 s->ar_flip_flop ^= 1;
290 s->msr = val & ~0x10;
293 s->sr_index = val & 7;
297 printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
299 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
302 s->dac_read_index = val;
303 s->dac_sub_index = 0;
307 s->dac_write_index = val;
308 s->dac_sub_index = 0;
312 s->dac_cache[s->dac_sub_index] = val;
313 if (++s->dac_sub_index == 3) {
314 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
315 s->dac_sub_index = 0;
316 s->dac_write_index++;
320 s->gr_index = val & 0x0f;
324 printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
326 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
335 printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
337 /* handle CR0-7 protection */
338 if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
339 /* can always write bit 4 of CR7 */
340 if (s->cr_index == 7)
341 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
344 switch(s->cr_index) {
345 case 0x01: /* horizontal display end */
350 case 0x12: /* vertical display end */
351 s->cr[s->cr_index] = val;
354 s->cr[s->cr_index] = val;
365 #ifdef CONFIG_BOCHS_VBE
366 static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
368 VGAState *s = opaque;
374 static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
376 VGAState *s = opaque;
379 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
380 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
381 switch(s->vbe_index) {
382 /* XXX: do not hardcode ? */
383 case VBE_DISPI_INDEX_XRES:
384 val = VBE_DISPI_MAX_XRES;
386 case VBE_DISPI_INDEX_YRES:
387 val = VBE_DISPI_MAX_YRES;
389 case VBE_DISPI_INDEX_BPP:
390 val = VBE_DISPI_MAX_BPP;
393 val = s->vbe_regs[s->vbe_index];
397 val = s->vbe_regs[s->vbe_index];
402 #ifdef DEBUG_BOCHS_VBE
403 printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
408 static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
410 VGAState *s = opaque;
414 static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
416 VGAState *s = opaque;
418 if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
419 #ifdef DEBUG_BOCHS_VBE
420 printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
422 switch(s->vbe_index) {
423 case VBE_DISPI_INDEX_ID:
424 if (val == VBE_DISPI_ID0 ||
425 val == VBE_DISPI_ID1 ||
426 val == VBE_DISPI_ID2 ||
427 val == VBE_DISPI_ID3 ||
428 val == VBE_DISPI_ID4) {
429 s->vbe_regs[s->vbe_index] = val;
432 case VBE_DISPI_INDEX_XRES:
433 if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
434 s->vbe_regs[s->vbe_index] = val;
437 case VBE_DISPI_INDEX_YRES:
438 if (val <= VBE_DISPI_MAX_YRES) {
439 s->vbe_regs[s->vbe_index] = val;
442 case VBE_DISPI_INDEX_BPP:
445 if (val == 4 || val == 8 || val == 15 ||
446 val == 16 || val == 24 || val == 32) {
447 s->vbe_regs[s->vbe_index] = val;
450 case VBE_DISPI_INDEX_BANK:
451 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
452 val &= (s->vbe_bank_mask >> 2);
454 val &= s->vbe_bank_mask;
456 s->vbe_regs[s->vbe_index] = val;
457 s->bank_offset = (val << 16);
459 case VBE_DISPI_INDEX_ENABLE:
460 if ((val & VBE_DISPI_ENABLED) &&
461 !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
462 int h, shift_control;
464 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
465 s->vbe_regs[VBE_DISPI_INDEX_XRES];
466 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
467 s->vbe_regs[VBE_DISPI_INDEX_YRES];
468 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
469 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
471 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
472 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
474 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
475 ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
476 s->vbe_start_addr = 0;
478 /* clear the screen (should be done in BIOS) */
479 if (!(val & VBE_DISPI_NOCLEARMEM)) {
480 memset(s->vram_ptr, 0,
481 s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
484 /* we initialize the VGA graphic mode (should be done
486 s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
487 s->cr[0x17] |= 3; /* no CGA modes */
488 s->cr[0x13] = s->vbe_line_offset >> 3;
490 s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
491 /* height (only meaningful if < 1024) */
492 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
494 s->cr[0x07] = (s->cr[0x07] & ~0x42) |
495 ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
496 /* line compare to 1023 */
501 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
503 s->sr[0x01] &= ~8; /* no double line */
506 s->sr[4] |= 0x08; /* set chain 4 mode */
507 s->sr[2] |= 0x0f; /* activate all planes */
509 s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
510 s->cr[0x09] &= ~0x9f; /* no double scan */
512 /* XXX: the bios should do that */
515 s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
516 s->vbe_regs[s->vbe_index] = val;
518 case VBE_DISPI_INDEX_VIRT_WIDTH:
520 int w, h, line_offset;
522 if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
525 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
526 line_offset = w >> 1;
528 line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
529 h = s->vram_size / line_offset;
530 /* XXX: support weird bochs semantics ? */
531 if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
533 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
534 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
535 s->vbe_line_offset = line_offset;
538 case VBE_DISPI_INDEX_X_OFFSET:
539 case VBE_DISPI_INDEX_Y_OFFSET:
542 s->vbe_regs[s->vbe_index] = val;
543 s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
544 x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
545 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
546 s->vbe_start_addr += x >> 1;
548 s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
549 s->vbe_start_addr >>= 2;
559 /* called for accesses between 0xa0000 and 0xc0000 */
560 uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
562 VGAState *s = opaque;
563 int memory_map_mode, plane;
566 /* convert to VGA memory offset */
567 memory_map_mode = (s->gr[6] >> 2) & 3;
569 switch(memory_map_mode) {
575 addr += s->bank_offset;
590 if (s->sr[4] & 0x08) {
591 /* chain 4 mode : simplest access */
592 ret = s->vram_ptr[addr];
593 } else if (s->gr[5] & 0x10) {
594 /* odd/even mode (aka text mode mapping) */
595 plane = (s->gr[4] & 2) | (addr & 1);
596 ret = s->vram_ptr[((addr & ~1) << 1) | plane];
598 /* standard VGA latched access */
599 s->latch = ((uint32_t *)s->vram_ptr)[addr];
601 if (!(s->gr[5] & 0x08)) {
604 ret = GET_PLANE(s->latch, plane);
607 ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
616 static uint32_t vga_mem_readw(void *opaque, target_phys_addr_t addr)
619 #ifdef TARGET_WORDS_BIGENDIAN
620 v = vga_mem_readb(opaque, addr) << 8;
621 v |= vga_mem_readb(opaque, addr + 1);
623 v = vga_mem_readb(opaque, addr);
624 v |= vga_mem_readb(opaque, addr + 1) << 8;
629 static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr)
632 #ifdef TARGET_WORDS_BIGENDIAN
633 v = vga_mem_readb(opaque, addr) << 24;
634 v |= vga_mem_readb(opaque, addr + 1) << 16;
635 v |= vga_mem_readb(opaque, addr + 2) << 8;
636 v |= vga_mem_readb(opaque, addr + 3);
638 v = vga_mem_readb(opaque, addr);
639 v |= vga_mem_readb(opaque, addr + 1) << 8;
640 v |= vga_mem_readb(opaque, addr + 2) << 16;
641 v |= vga_mem_readb(opaque, addr + 3) << 24;
646 /* called for accesses between 0xa0000 and 0xc0000 */
647 void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
649 VGAState *s = opaque;
650 int memory_map_mode, plane, write_mode, b, func_select, mask;
651 uint32_t write_mask, bit_mask, set_mask;
654 printf("vga: [0x%x] = 0x%02x\n", addr, val);
656 /* convert to VGA memory offset */
657 memory_map_mode = (s->gr[6] >> 2) & 3;
659 switch(memory_map_mode) {
665 addr += s->bank_offset;
680 if (s->sr[4] & 0x08) {
681 /* chain 4 mode : simplest access */
684 if (s->sr[2] & mask) {
685 s->vram_ptr[addr] = val;
687 printf("vga: chain4: [0x%x]\n", addr);
689 s->plane_updated |= mask; /* only used to detect font change */
690 cpu_physical_memory_set_dirty(s->vram_offset + addr);
692 } else if (s->gr[5] & 0x10) {
693 /* odd/even mode (aka text mode mapping) */
694 plane = (s->gr[4] & 2) | (addr & 1);
696 if (s->sr[2] & mask) {
697 addr = ((addr & ~1) << 1) | plane;
698 s->vram_ptr[addr] = val;
700 printf("vga: odd/even: [0x%x]\n", addr);
702 s->plane_updated |= mask; /* only used to detect font change */
703 cpu_physical_memory_set_dirty(s->vram_offset + addr);
706 /* standard VGA latched access */
707 write_mode = s->gr[5] & 3;
713 val = ((val >> b) | (val << (8 - b))) & 0xff;
717 /* apply set/reset mask */
718 set_mask = mask16[s->gr[1]];
719 val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
726 val = mask16[val & 0x0f];
732 val = (val >> b) | (val << (8 - b));
734 bit_mask = s->gr[8] & val;
735 val = mask16[s->gr[0]];
739 /* apply logical operation */
740 func_select = s->gr[3] >> 3;
741 switch(func_select) {
761 bit_mask |= bit_mask << 8;
762 bit_mask |= bit_mask << 16;
763 val = (val & bit_mask) | (s->latch & ~bit_mask);
766 /* mask data according to sr[2] */
768 s->plane_updated |= mask; /* only used to detect font change */
769 write_mask = mask16[mask];
770 ((uint32_t *)s->vram_ptr)[addr] =
771 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
774 printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
775 addr * 4, write_mask, val);
777 cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
781 static void vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
783 #ifdef TARGET_WORDS_BIGENDIAN
784 vga_mem_writeb(opaque, addr, (val >> 8) & 0xff);
785 vga_mem_writeb(opaque, addr + 1, val & 0xff);
787 vga_mem_writeb(opaque, addr, val & 0xff);
788 vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
792 static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
794 #ifdef TARGET_WORDS_BIGENDIAN
795 vga_mem_writeb(opaque, addr, (val >> 24) & 0xff);
796 vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
797 vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
798 vga_mem_writeb(opaque, addr + 3, val & 0xff);
800 vga_mem_writeb(opaque, addr, val & 0xff);
801 vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
802 vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
803 vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
807 typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
808 const uint8_t *font_ptr, int h,
809 uint32_t fgcol, uint32_t bgcol);
810 typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
811 const uint8_t *font_ptr, int h,
812 uint32_t fgcol, uint32_t bgcol, int dup9);
813 typedef void vga_draw_line_func(VGAState *s1, uint8_t *d,
814 const uint8_t *s, int width);
817 #include "vga_template.h"
820 #include "vga_template.h"
824 #include "vga_template.h"
827 #include "vga_template.h"
831 #include "vga_template.h"
834 #include "vga_template.h"
838 #include "vga_template.h"
840 static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
843 col = rgb_to_pixel8(r, g, b);
849 static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
852 col = rgb_to_pixel15(r, g, b);
857 static unsigned int rgb_to_pixel15bgr_dup(unsigned int r, unsigned int g,
861 col = rgb_to_pixel15bgr(r, g, b);
866 static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
869 col = rgb_to_pixel16(r, g, b);
874 static unsigned int rgb_to_pixel16bgr_dup(unsigned int r, unsigned int g,
878 col = rgb_to_pixel16bgr(r, g, b);
883 static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
886 col = rgb_to_pixel32(r, g, b);
890 static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b)
893 col = rgb_to_pixel32bgr(r, g, b);
897 /* return true if the palette was modified */
898 static int update_palette16(VGAState *s)
901 uint32_t v, col, *palette;
904 palette = s->last_palette;
905 for(i = 0; i < 16; i++) {
907 if (s->ar[0x10] & 0x80)
908 v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
910 v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
912 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
913 c6_to_8(s->palette[v + 1]),
914 c6_to_8(s->palette[v + 2]));
915 if (col != palette[i]) {
923 /* return true if the palette was modified */
924 static int update_palette256(VGAState *s)
927 uint32_t v, col, *palette;
930 palette = s->last_palette;
932 for(i = 0; i < 256; i++) {
934 col = s->rgb_to_pixel(s->palette[v],
938 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
939 c6_to_8(s->palette[v + 1]),
940 c6_to_8(s->palette[v + 2]));
942 if (col != palette[i]) {
951 static void vga_get_offsets(VGAState *s,
952 uint32_t *pline_offset,
953 uint32_t *pstart_addr,
954 uint32_t *pline_compare)
956 uint32_t start_addr, line_offset, line_compare;
957 #ifdef CONFIG_BOCHS_VBE
958 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
959 line_offset = s->vbe_line_offset;
960 start_addr = s->vbe_start_addr;
961 line_compare = 65535;
965 /* compute line_offset in bytes */
966 line_offset = s->cr[0x13];
969 /* starting address */
970 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
973 line_compare = s->cr[0x18] |
974 ((s->cr[0x07] & 0x10) << 4) |
975 ((s->cr[0x09] & 0x40) << 3);
977 *pline_offset = line_offset;
978 *pstart_addr = start_addr;
979 *pline_compare = line_compare;
982 /* update start_addr and line_offset. Return TRUE if modified */
983 static int update_basic_params(VGAState *s)
986 uint32_t start_addr, line_offset, line_compare;
990 s->get_offsets(s, &line_offset, &start_addr, &line_compare);
992 if (line_offset != s->line_offset ||
993 start_addr != s->start_addr ||
994 line_compare != s->line_compare) {
995 s->line_offset = line_offset;
996 s->start_addr = start_addr;
997 s->line_compare = line_compare;
1005 static inline int get_depth_index(DisplayState *s)
1029 static vga_draw_glyph8_func *vga_draw_glyph8_table[NB_DEPTHS] = {
1039 static vga_draw_glyph8_func *vga_draw_glyph16_table[NB_DEPTHS] = {
1041 vga_draw_glyph16_16,
1042 vga_draw_glyph16_16,
1043 vga_draw_glyph16_32,
1044 vga_draw_glyph16_32,
1045 vga_draw_glyph16_16,
1046 vga_draw_glyph16_16,
1049 static vga_draw_glyph9_func *vga_draw_glyph9_table[NB_DEPTHS] = {
1059 static const uint8_t cursor_glyph[32 * 4] = {
1060 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1061 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1062 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1063 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1064 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1065 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1066 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1067 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1068 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1069 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1070 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1071 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1072 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1073 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1074 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1075 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1086 static void vga_draw_text(VGAState *s, int full_update)
1088 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1089 int cx_min, cx_max, linesize, x_incr;
1090 uint32_t offset, fgcol, bgcol, v, cursor_offset;
1091 uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
1092 const uint8_t *font_ptr, *font_base[2];
1093 int dup9, line_offset, depth_index;
1095 uint32_t *ch_attr_ptr;
1096 vga_draw_glyph8_func *vga_draw_glyph8;
1097 vga_draw_glyph9_func *vga_draw_glyph9;
1099 full_update |= update_palette16(s);
1100 palette = s->last_palette;
1102 /* compute font data address (in plane 2) */
1104 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1105 if (offset != s->font_offsets[0]) {
1106 s->font_offsets[0] = offset;
1109 font_base[0] = s->vram_ptr + offset;
1111 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1112 font_base[1] = s->vram_ptr + offset;
1113 if (offset != s->font_offsets[1]) {
1114 s->font_offsets[1] = offset;
1117 if (s->plane_updated & (1 << 2)) {
1118 /* if the plane 2 was modified since the last display, it
1119 indicates the font may have been modified */
1120 s->plane_updated = 0;
1123 full_update |= update_basic_params(s);
1125 line_offset = s->line_offset;
1126 s1 = s->vram_ptr + (s->start_addr * 4);
1128 /* total width & height */
1129 cheight = (s->cr[9] & 0x1f) + 1;
1131 if (!(s->sr[1] & 0x01))
1133 if (s->sr[1] & 0x08)
1134 cw = 16; /* NOTE: no 18 pixel wide */
1135 x_incr = cw * ((s->ds->depth + 7) >> 3);
1136 width = (s->cr[0x01] + 1);
1137 if (s->cr[0x06] == 100) {
1138 /* ugly hack for CGA 160x100x16 - explain me the logic */
1141 height = s->cr[0x12] |
1142 ((s->cr[0x07] & 0x02) << 7) |
1143 ((s->cr[0x07] & 0x40) << 3);
1144 height = (height + 1) / cheight;
1146 if ((height * width) > CH_ATTR_SIZE) {
1147 /* better than nothing: exit if transient size is too big */
1151 if (width != s->last_width || height != s->last_height ||
1152 cw != s->last_cw || cheight != s->last_ch) {
1153 s->last_scr_width = width * cw;
1154 s->last_scr_height = height * cheight;
1155 dpy_resize(s->ds, s->last_scr_width, s->last_scr_height);
1156 s->last_width = width;
1157 s->last_height = height;
1158 s->last_ch = cheight;
1162 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1163 if (cursor_offset != s->cursor_offset ||
1164 s->cr[0xa] != s->cursor_start ||
1165 s->cr[0xb] != s->cursor_end) {
1166 /* if the cursor position changed, we update the old and new
1168 if (s->cursor_offset < CH_ATTR_SIZE)
1169 s->last_ch_attr[s->cursor_offset] = -1;
1170 if (cursor_offset < CH_ATTR_SIZE)
1171 s->last_ch_attr[cursor_offset] = -1;
1172 s->cursor_offset = cursor_offset;
1173 s->cursor_start = s->cr[0xa];
1174 s->cursor_end = s->cr[0xb];
1176 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
1178 depth_index = get_depth_index(s->ds);
1180 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1182 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
1183 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1186 linesize = s->ds->linesize;
1187 ch_attr_ptr = s->last_ch_attr;
1188 for(cy = 0; cy < height; cy++) {
1193 for(cx = 0; cx < width; cx++) {
1194 ch_attr = *(uint16_t *)src;
1195 if (full_update || ch_attr != *ch_attr_ptr) {
1200 *ch_attr_ptr = ch_attr;
1201 #ifdef WORDS_BIGENDIAN
1203 cattr = ch_attr & 0xff;
1205 ch = ch_attr & 0xff;
1206 cattr = ch_attr >> 8;
1208 font_ptr = font_base[(cattr >> 3) & 1];
1209 font_ptr += 32 * 4 * ch;
1210 bgcol = palette[cattr >> 4];
1211 fgcol = palette[cattr & 0x0f];
1213 vga_draw_glyph8(d1, linesize,
1214 font_ptr, cheight, fgcol, bgcol);
1217 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1219 vga_draw_glyph9(d1, linesize,
1220 font_ptr, cheight, fgcol, bgcol, dup9);
1222 if (src == cursor_ptr &&
1223 !(s->cr[0x0a] & 0x20)) {
1224 int line_start, line_last, h;
1225 /* draw the cursor */
1226 line_start = s->cr[0x0a] & 0x1f;
1227 line_last = s->cr[0x0b] & 0x1f;
1228 /* XXX: check that */
1229 if (line_last > cheight - 1)
1230 line_last = cheight - 1;
1231 if (line_last >= line_start && line_start < cheight) {
1232 h = line_last - line_start + 1;
1233 d = d1 + linesize * line_start;
1235 vga_draw_glyph8(d, linesize,
1236 cursor_glyph, h, fgcol, bgcol);
1238 vga_draw_glyph9(d, linesize,
1239 cursor_glyph, h, fgcol, bgcol, 1);
1249 dpy_update(s->ds, cx_min * cw, cy * cheight,
1250 (cx_max - cx_min + 1) * cw, cheight);
1252 dest += linesize * cheight;
1271 static vga_draw_line_func *vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
1281 vga_draw_line2d2_16,
1282 vga_draw_line2d2_16,
1283 vga_draw_line2d2_32,
1284 vga_draw_line2d2_32,
1285 vga_draw_line2d2_16,
1286 vga_draw_line2d2_16,
1297 vga_draw_line4d2_16,
1298 vga_draw_line4d2_16,
1299 vga_draw_line4d2_32,
1300 vga_draw_line4d2_32,
1301 vga_draw_line4d2_16,
1302 vga_draw_line4d2_16,
1305 vga_draw_line8d2_16,
1306 vga_draw_line8d2_16,
1307 vga_draw_line8d2_32,
1308 vga_draw_line8d2_32,
1309 vga_draw_line8d2_16,
1310 vga_draw_line8d2_16,
1324 vga_draw_line15_32bgr,
1325 vga_draw_line15_15bgr,
1326 vga_draw_line15_16bgr,
1332 vga_draw_line16_32bgr,
1333 vga_draw_line16_15bgr,
1334 vga_draw_line16_16bgr,
1340 vga_draw_line24_32bgr,
1341 vga_draw_line24_15bgr,
1342 vga_draw_line24_16bgr,
1348 vga_draw_line32_32bgr,
1349 vga_draw_line32_15bgr,
1350 vga_draw_line32_16bgr,
1353 typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
1355 static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS] = {
1360 rgb_to_pixel32bgr_dup,
1361 rgb_to_pixel15bgr_dup,
1362 rgb_to_pixel16bgr_dup,
1365 static int vga_get_bpp(VGAState *s)
1368 #ifdef CONFIG_BOCHS_VBE
1369 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1370 ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
1379 static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight)
1383 #ifdef CONFIG_BOCHS_VBE
1384 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1385 width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
1386 height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
1390 width = (s->cr[0x01] + 1) * 8;
1391 height = s->cr[0x12] |
1392 ((s->cr[0x07] & 0x02) << 7) |
1393 ((s->cr[0x07] & 0x40) << 3);
1394 height = (height + 1);
1400 void vga_invalidate_scanlines(VGAState *s, int y1, int y2)
1403 if (y1 >= VGA_MAX_HEIGHT)
1405 if (y2 >= VGA_MAX_HEIGHT)
1406 y2 = VGA_MAX_HEIGHT;
1407 for(y = y1; y < y2; y++) {
1408 s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1415 static void vga_draw_graphic(VGAState *s, int full_update)
1417 int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask;
1418 int width, height, shift_control, line_offset, page0, page1, bwidth;
1419 int disp_width, multi_scan, multi_run;
1421 uint32_t v, addr1, addr;
1422 vga_draw_line_func *vga_draw_line;
1424 full_update |= update_basic_params(s);
1426 s->get_resolution(s, &width, &height);
1429 shift_control = (s->gr[0x05] >> 5) & 3;
1430 double_scan = (s->cr[0x09] >> 7);
1431 if (shift_control != 1) {
1432 multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
1434 /* in CGA modes, multi_scan is ignored */
1435 /* XXX: is it correct ? */
1436 multi_scan = double_scan;
1438 multi_run = multi_scan;
1439 if (shift_control != s->shift_control ||
1440 double_scan != s->double_scan) {
1442 s->shift_control = shift_control;
1443 s->double_scan = double_scan;
1446 if (shift_control == 0) {
1447 full_update |= update_palette16(s);
1448 if (s->sr[0x01] & 8) {
1449 v = VGA_DRAW_LINE4D2;
1454 } else if (shift_control == 1) {
1455 full_update |= update_palette16(s);
1456 if (s->sr[0x01] & 8) {
1457 v = VGA_DRAW_LINE2D2;
1463 switch(s->get_bpp(s)) {
1466 full_update |= update_palette256(s);
1467 v = VGA_DRAW_LINE8D2;
1470 full_update |= update_palette256(s);
1474 v = VGA_DRAW_LINE15;
1477 v = VGA_DRAW_LINE16;
1480 v = VGA_DRAW_LINE24;
1483 v = VGA_DRAW_LINE32;
1487 vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
1489 if (disp_width != s->last_width ||
1490 height != s->last_height) {
1491 dpy_resize(s->ds, disp_width, height);
1492 s->last_scr_width = disp_width;
1493 s->last_scr_height = height;
1494 s->last_width = disp_width;
1495 s->last_height = height;
1498 if (s->cursor_invalidate)
1499 s->cursor_invalidate(s);
1501 line_offset = s->line_offset;
1503 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",
1504 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1506 addr1 = (s->start_addr * 4);
1509 page_min = 0x7fffffff;
1512 linesize = s->ds->linesize;
1514 for(y = 0; y < height; y++) {
1516 if (!(s->cr[0x17] & 1)) {
1518 /* CGA compatibility handling */
1519 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1520 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1522 if (!(s->cr[0x17] & 2)) {
1523 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1525 page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
1526 page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
1527 update = full_update |
1528 cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
1529 cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
1530 if ((page1 - page0) > TARGET_PAGE_SIZE) {
1531 /* if wide line, can use another page */
1532 update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE,
1535 /* explicit invalidation for the hardware cursor */
1536 update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
1540 if (page0 < page_min)
1542 if (page1 > page_max)
1544 vga_draw_line(s, d, s->vram_ptr + addr, width);
1545 if (s->cursor_draw_line)
1546 s->cursor_draw_line(s, d, y);
1549 /* flush to display */
1550 dpy_update(s->ds, 0, y_start,
1551 disp_width, y - y_start);
1556 mask = (s->cr[0x17] & 3) ^ 3;
1557 if ((y1 & mask) == mask)
1558 addr1 += line_offset;
1560 multi_run = multi_scan;
1564 /* line compare acts on the displayed lines */
1565 if (y == s->line_compare)
1570 /* flush to display */
1571 dpy_update(s->ds, 0, y_start,
1572 disp_width, y - y_start);
1574 /* reset modified pages */
1575 if (page_max != -1) {
1576 cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
1579 memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
1582 static void vga_draw_blank(VGAState *s, int full_update)
1589 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1591 if (s->ds->depth == 8)
1592 val = s->rgb_to_pixel(0, 0, 0);
1595 w = s->last_scr_width * ((s->ds->depth + 7) >> 3);
1597 for(i = 0; i < s->last_scr_height; i++) {
1599 d += s->ds->linesize;
1601 dpy_update(s->ds, 0, 0,
1602 s->last_scr_width, s->last_scr_height);
1605 #define GMODE_TEXT 0
1606 #define GMODE_GRAPH 1
1607 #define GMODE_BLANK 2
1609 static void vga_update_display(void *opaque)
1611 VGAState *s = (VGAState *)opaque;
1612 int full_update, graphic_mode;
1614 if (s->ds->depth == 0) {
1618 rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1621 if (!(s->ar_index & 0x20)) {
1622 graphic_mode = GMODE_BLANK;
1624 graphic_mode = s->gr[6] & 1;
1626 if (graphic_mode != s->graphic_mode) {
1627 s->graphic_mode = graphic_mode;
1630 switch(graphic_mode) {
1632 vga_draw_text(s, full_update);
1635 vga_draw_graphic(s, full_update);
1639 vga_draw_blank(s, full_update);
1645 /* force a full display refresh */
1646 static void vga_invalidate_display(void *opaque)
1648 VGAState *s = (VGAState *)opaque;
1651 s->last_height = -1;
1654 static void vga_reset(VGAState *s)
1656 memset(s, 0, sizeof(VGAState));
1657 s->graphic_mode = -1; /* force full update */
1660 static CPUReadMemoryFunc *vga_mem_read[3] = {
1666 static CPUWriteMemoryFunc *vga_mem_write[3] = {
1672 static void vga_save(QEMUFile *f, void *opaque)
1674 VGAState *s = opaque;
1678 pci_device_save(s->pci_dev, f);
1680 qemu_put_be32s(f, &s->latch);
1681 qemu_put_8s(f, &s->sr_index);
1682 qemu_put_buffer(f, s->sr, 8);
1683 qemu_put_8s(f, &s->gr_index);
1684 qemu_put_buffer(f, s->gr, 16);
1685 qemu_put_8s(f, &s->ar_index);
1686 qemu_put_buffer(f, s->ar, 21);
1687 qemu_put_be32s(f, &s->ar_flip_flop);
1688 qemu_put_8s(f, &s->cr_index);
1689 qemu_put_buffer(f, s->cr, 256);
1690 qemu_put_8s(f, &s->msr);
1691 qemu_put_8s(f, &s->fcr);
1692 qemu_put_8s(f, &s->st00);
1693 qemu_put_8s(f, &s->st01);
1695 qemu_put_8s(f, &s->dac_state);
1696 qemu_put_8s(f, &s->dac_sub_index);
1697 qemu_put_8s(f, &s->dac_read_index);
1698 qemu_put_8s(f, &s->dac_write_index);
1699 qemu_put_buffer(f, s->dac_cache, 3);
1700 qemu_put_buffer(f, s->palette, 768);
1702 qemu_put_be32s(f, &s->bank_offset);
1703 #ifdef CONFIG_BOCHS_VBE
1704 qemu_put_byte(f, 1);
1705 qemu_put_be16s(f, &s->vbe_index);
1706 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1707 qemu_put_be16s(f, &s->vbe_regs[i]);
1708 qemu_put_be32s(f, &s->vbe_start_addr);
1709 qemu_put_be32s(f, &s->vbe_line_offset);
1710 qemu_put_be32s(f, &s->vbe_bank_mask);
1712 qemu_put_byte(f, 0);
1716 static int vga_load(QEMUFile *f, void *opaque, int version_id)
1718 VGAState *s = opaque;
1724 if (s->pci_dev && version_id >= 2) {
1725 ret = pci_device_load(s->pci_dev, f);
1730 qemu_get_be32s(f, &s->latch);
1731 qemu_get_8s(f, &s->sr_index);
1732 qemu_get_buffer(f, s->sr, 8);
1733 qemu_get_8s(f, &s->gr_index);
1734 qemu_get_buffer(f, s->gr, 16);
1735 qemu_get_8s(f, &s->ar_index);
1736 qemu_get_buffer(f, s->ar, 21);
1737 qemu_get_be32s(f, &s->ar_flip_flop);
1738 qemu_get_8s(f, &s->cr_index);
1739 qemu_get_buffer(f, s->cr, 256);
1740 qemu_get_8s(f, &s->msr);
1741 qemu_get_8s(f, &s->fcr);
1742 qemu_get_8s(f, &s->st00);
1743 qemu_get_8s(f, &s->st01);
1745 qemu_get_8s(f, &s->dac_state);
1746 qemu_get_8s(f, &s->dac_sub_index);
1747 qemu_get_8s(f, &s->dac_read_index);
1748 qemu_get_8s(f, &s->dac_write_index);
1749 qemu_get_buffer(f, s->dac_cache, 3);
1750 qemu_get_buffer(f, s->palette, 768);
1752 qemu_get_be32s(f, &s->bank_offset);
1753 is_vbe = qemu_get_byte(f);
1754 #ifdef CONFIG_BOCHS_VBE
1757 qemu_get_be16s(f, &s->vbe_index);
1758 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1759 qemu_get_be16s(f, &s->vbe_regs[i]);
1760 qemu_get_be32s(f, &s->vbe_start_addr);
1761 qemu_get_be32s(f, &s->vbe_line_offset);
1762 qemu_get_be32s(f, &s->vbe_bank_mask);
1769 s->graphic_mode = -1;
1773 typedef struct PCIVGAState {
1778 static void vga_map(PCIDevice *pci_dev, int region_num,
1779 uint32_t addr, uint32_t size, int type)
1781 PCIVGAState *d = (PCIVGAState *)pci_dev;
1782 VGAState *s = &d->vga_state;
1783 if (region_num == PCI_ROM_SLOT) {
1784 cpu_register_physical_memory(addr, s->bios_size, s->bios_offset);
1786 cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
1790 void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
1791 unsigned long vga_ram_offset, int vga_ram_size)
1795 for(i = 0;i < 256; i++) {
1797 for(j = 0; j < 8; j++) {
1798 v |= ((i >> j) & 1) << (j * 4);
1803 for(j = 0; j < 4; j++) {
1804 v |= ((i >> (2 * j)) & 3) << (j * 4);
1808 for(i = 0; i < 16; i++) {
1810 for(j = 0; j < 4; j++) {
1813 v |= b << (2 * j + 1);
1820 s->vram_ptr = vga_ram_base;
1821 s->vram_offset = vga_ram_offset;
1822 s->vram_size = vga_ram_size;
1824 s->get_bpp = vga_get_bpp;
1825 s->get_offsets = vga_get_offsets;
1826 s->get_resolution = vga_get_resolution;
1827 s->update = vga_update_display;
1828 s->invalidate = vga_invalidate_display;
1829 s->screen_dump = vga_screen_dump;
1832 /* used by both ISA and PCI */
1833 void vga_init(VGAState *s)
1837 register_savevm("vga", 0, 2, vga_save, vga_load, s);
1839 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
1841 register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
1842 register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
1843 register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
1844 register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
1846 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
1848 register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
1849 register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
1850 register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
1851 register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
1854 #ifdef CONFIG_BOCHS_VBE
1855 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
1856 s->vbe_bank_mask = ((s->vram_size >> 16) - 1);
1857 #if defined (TARGET_I386)
1858 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
1859 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
1861 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
1862 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
1864 /* old Bochs IO ports */
1865 register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
1866 register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
1868 register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
1869 register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s);
1871 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
1872 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
1874 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
1875 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
1877 #endif /* CONFIG_BOCHS_VBE */
1879 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
1880 cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
1884 /* Memory mapped interface */
1885 static uint32_t vga_mm_readb (void *opaque, target_phys_addr_t addr)
1887 VGAState *s = opaque;
1889 return vga_ioport_read(s, (addr - s->base_ctrl) >> s->it_shift) & 0xff;
1892 static void vga_mm_writeb (void *opaque,
1893 target_phys_addr_t addr, uint32_t value)
1895 VGAState *s = opaque;
1897 vga_ioport_write(s, (addr - s->base_ctrl) >> s->it_shift, value & 0xff);
1900 static uint32_t vga_mm_readw (void *opaque, target_phys_addr_t addr)
1902 VGAState *s = opaque;
1904 return vga_ioport_read(s, (addr - s->base_ctrl) >> s->it_shift) & 0xffff;
1907 static void vga_mm_writew (void *opaque,
1908 target_phys_addr_t addr, uint32_t value)
1910 VGAState *s = opaque;
1912 vga_ioport_write(s, (addr - s->base_ctrl) >> s->it_shift, value & 0xffff);
1915 static uint32_t vga_mm_readl (void *opaque, target_phys_addr_t addr)
1917 VGAState *s = opaque;
1919 return vga_ioport_read(s, (addr - s->base_ctrl) >> s->it_shift);
1922 static void vga_mm_writel (void *opaque,
1923 target_phys_addr_t addr, uint32_t value)
1925 VGAState *s = opaque;
1927 vga_ioport_write(s, (addr - s->base_ctrl) >> s->it_shift, value);
1930 static CPUReadMemoryFunc *vga_mm_read_ctrl[] = {
1936 static CPUWriteMemoryFunc *vga_mm_write_ctrl[] = {
1942 static void vga_mm_init(VGAState *s, target_phys_addr_t vram_base,
1943 target_phys_addr_t ctrl_base, int it_shift)
1945 int s_ioport_ctrl, vga_io_memory;
1947 s->base_ctrl = ctrl_base;
1948 s->it_shift = it_shift;
1949 s_ioport_ctrl = cpu_register_io_memory(0, vga_mm_read_ctrl, vga_mm_write_ctrl, s);
1950 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
1952 register_savevm("vga", 0, 2, vga_save, vga_load, s);
1954 cpu_register_physical_memory(ctrl_base, 0x100000, s_ioport_ctrl);
1956 cpu_register_physical_memory(vram_base + 0x000a0000, 0x20000, vga_io_memory);
1959 int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base,
1960 unsigned long vga_ram_offset, int vga_ram_size)
1964 s = qemu_mallocz(sizeof(VGAState));
1968 vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
1971 graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s);
1973 #ifdef CONFIG_BOCHS_VBE
1974 /* XXX: use optimized standard vga accesses */
1975 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
1976 vga_ram_size, vga_ram_offset);
1981 int isa_vga_mm_init(DisplayState *ds, uint8_t *vga_ram_base,
1982 unsigned long vga_ram_offset, int vga_ram_size,
1983 target_phys_addr_t vram_base, target_phys_addr_t ctrl_base,
1988 s = qemu_mallocz(sizeof(VGAState));
1992 vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
1993 vga_mm_init(s, vram_base, ctrl_base, it_shift);
1995 graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s);
1997 #ifdef CONFIG_BOCHS_VBE
1998 /* XXX: use optimized standard vga accesses */
1999 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
2000 vga_ram_size, vga_ram_offset);
2005 int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
2006 unsigned long vga_ram_offset, int vga_ram_size,
2007 unsigned long vga_bios_offset, int vga_bios_size)
2013 d = (PCIVGAState *)pci_register_device(bus, "VGA",
2014 sizeof(PCIVGAState),
2020 vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
2023 graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s);
2025 s->pci_dev = &d->dev;
2027 pci_conf = d->dev.config;
2028 pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID)
2029 pci_conf[0x01] = 0x12;
2030 pci_conf[0x02] = 0x11;
2031 pci_conf[0x03] = 0x11;
2032 pci_conf[0x0a] = 0x00; // VGA controller
2033 pci_conf[0x0b] = 0x03;
2034 pci_conf[0x0e] = 0x00; // header_type
2036 /* XXX: vga_ram_size must be a power of two */
2037 pci_register_io_region(&d->dev, 0, vga_ram_size,
2038 PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
2039 if (vga_bios_size != 0) {
2040 unsigned int bios_total_size;
2041 s->bios_offset = vga_bios_offset;
2042 s->bios_size = vga_bios_size;
2043 /* must be a power of two */
2044 bios_total_size = 1;
2045 while (bios_total_size < vga_bios_size)
2046 bios_total_size <<= 1;
2047 pci_register_io_region(&d->dev, PCI_ROM_SLOT, bios_total_size,
2048 PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
2053 /********************************************************/
2054 /* vga screen dump */
2056 static int vga_save_w, vga_save_h;
2058 static void vga_save_dpy_update(DisplayState *s,
2059 int x, int y, int w, int h)
2063 static void vga_save_dpy_resize(DisplayState *s, int w, int h)
2065 s->linesize = w * 4;
2066 s->data = qemu_malloc(h * s->linesize);
2071 static void vga_save_dpy_refresh(DisplayState *s)
2075 int ppm_save(const char *filename, uint8_t *data,
2076 int w, int h, int linesize)
2083 f = fopen(filename, "wb");
2086 fprintf(f, "P6\n%d %d\n%d\n",
2089 for(y = 0; y < h; y++) {
2091 for(x = 0; x < w; x++) {
2093 fputc((v >> 16) & 0xff, f);
2094 fputc((v >> 8) & 0xff, f);
2095 fputc((v) & 0xff, f);
2104 /* save the vga display in a PPM image even if no display is
2106 static void vga_screen_dump(void *opaque, const char *filename)
2108 VGAState *s = (VGAState *)opaque;
2109 DisplayState *saved_ds, ds1, *ds = &ds1;
2111 /* XXX: this is a little hackish */
2112 vga_invalidate_display(s);
2115 memset(ds, 0, sizeof(DisplayState));
2116 ds->dpy_update = vga_save_dpy_update;
2117 ds->dpy_resize = vga_save_dpy_resize;
2118 ds->dpy_refresh = vga_save_dpy_refresh;
2122 s->graphic_mode = -1;
2123 vga_update_display(s);
2126 ppm_save(filename, ds->data, vga_save_w, vga_save_h,
2128 qemu_free(ds->data);