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
, mask
;
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 */
699 if (s
->sr
[2] & mask
) {
700 s
->vram_ptr
[addr
] = val
;
702 printf("vga: chain4: [0x%x]\n", addr
);
704 s
->plane_updated
|= mask
; /* only used to detect font change */
705 cpu_physical_memory_set_dirty(s
->vram_offset
+ addr
);
707 } else if (s
->gr
[5] & 0x10) {
708 /* odd/even mode (aka text mode mapping) */
709 plane
= (s
->gr
[4] & 2) | (addr
& 1);
711 if (s
->sr
[2] & mask
) {
712 addr
= ((addr
& ~1) << 1) | plane
;
713 s
->vram_ptr
[addr
] = val
;
715 printf("vga: odd/even: [0x%x]\n", addr
);
717 s
->plane_updated
|= mask
; /* only used to detect font change */
718 cpu_physical_memory_set_dirty(s
->vram_offset
+ addr
);
721 /* standard VGA latched access */
722 write_mode
= s
->gr
[5] & 3;
728 val
= ((val
>> b
) | (val
<< (8 - b
))) & 0xff;
732 /* apply set/reset mask */
733 set_mask
= mask16
[s
->gr
[1]];
734 val
= (val
& ~set_mask
) | (mask16
[s
->gr
[0]] & set_mask
);
741 val
= mask16
[val
& 0x0f];
747 val
= (val
>> b
) | (val
<< (8 - b
));
749 bit_mask
= s
->gr
[8] & val
;
750 val
= mask16
[s
->gr
[0]];
754 /* apply logical operation */
755 func_select
= s
->gr
[3] >> 3;
756 switch(func_select
) {
776 bit_mask
|= bit_mask
<< 8;
777 bit_mask
|= bit_mask
<< 16;
778 val
= (val
& bit_mask
) | (s
->latch
& ~bit_mask
);
781 /* mask data according to sr[2] */
783 s
->plane_updated
|= mask
; /* only used to detect font change */
784 write_mask
= mask16
[mask
];
785 ((uint32_t *)s
->vram_ptr
)[addr
] =
786 (((uint32_t *)s
->vram_ptr
)[addr
] & ~write_mask
) |
789 printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
790 addr
* 4, write_mask
, val
);
792 cpu_physical_memory_set_dirty(s
->vram_offset
+ (addr
<< 2));
796 static void vga_mem_writew(void *opaque
, target_phys_addr_t addr
, uint32_t val
)
798 #ifdef TARGET_WORDS_BIGENDIAN
799 vga_mem_writeb(opaque
, addr
, (val
>> 8) & 0xff);
800 vga_mem_writeb(opaque
, addr
+ 1, val
& 0xff);
802 vga_mem_writeb(opaque
, addr
, val
& 0xff);
803 vga_mem_writeb(opaque
, addr
+ 1, (val
>> 8) & 0xff);
807 static void vga_mem_writel(void *opaque
, target_phys_addr_t addr
, uint32_t val
)
809 #ifdef TARGET_WORDS_BIGENDIAN
810 vga_mem_writeb(opaque
, addr
, (val
>> 24) & 0xff);
811 vga_mem_writeb(opaque
, addr
+ 1, (val
>> 16) & 0xff);
812 vga_mem_writeb(opaque
, addr
+ 2, (val
>> 8) & 0xff);
813 vga_mem_writeb(opaque
, addr
+ 3, val
& 0xff);
815 vga_mem_writeb(opaque
, addr
, val
& 0xff);
816 vga_mem_writeb(opaque
, addr
+ 1, (val
>> 8) & 0xff);
817 vga_mem_writeb(opaque
, addr
+ 2, (val
>> 16) & 0xff);
818 vga_mem_writeb(opaque
, addr
+ 3, (val
>> 24) & 0xff);
822 typedef void vga_draw_glyph8_func(uint8_t *d
, int linesize
,
823 const uint8_t *font_ptr
, int h
,
824 uint32_t fgcol
, uint32_t bgcol
);
825 typedef void vga_draw_glyph9_func(uint8_t *d
, int linesize
,
826 const uint8_t *font_ptr
, int h
,
827 uint32_t fgcol
, uint32_t bgcol
, int dup9
);
828 typedef void vga_draw_line_func(VGAState
*s1
, uint8_t *d
,
829 const uint8_t *s
, int width
);
831 static inline unsigned int rgb_to_pixel8(unsigned int r
, unsigned int g
, unsigned b
)
833 return ((r
>> 5) << 5) | ((g
>> 5) << 2) | (b
>> 6);
836 static inline unsigned int rgb_to_pixel15(unsigned int r
, unsigned int g
, unsigned b
)
838 return ((r
>> 3) << 10) | ((g
>> 3) << 5) | (b
>> 3);
841 static inline unsigned int rgb_to_pixel16(unsigned int r
, unsigned int g
, unsigned b
)
843 return ((r
>> 3) << 11) | ((g
>> 2) << 5) | (b
>> 3);
846 static inline unsigned int rgb_to_pixel32(unsigned int r
, unsigned int g
, unsigned b
)
848 return (r
<< 16) | (g
<< 8) | b
;
852 #include "vga_template.h"
855 #include "vga_template.h"
858 #include "vga_template.h"
861 #include "vga_template.h"
863 static unsigned int rgb_to_pixel8_dup(unsigned int r
, unsigned int g
, unsigned b
)
866 col
= rgb_to_pixel8(r
, g
, b
);
872 static unsigned int rgb_to_pixel15_dup(unsigned int r
, unsigned int g
, unsigned b
)
875 col
= rgb_to_pixel15(r
, g
, b
);
880 static unsigned int rgb_to_pixel16_dup(unsigned int r
, unsigned int g
, unsigned b
)
883 col
= rgb_to_pixel16(r
, g
, b
);
888 static unsigned int rgb_to_pixel32_dup(unsigned int r
, unsigned int g
, unsigned b
)
891 col
= rgb_to_pixel32(r
, g
, b
);
895 /* return true if the palette was modified */
896 static int update_palette16(VGAState
*s
)
899 uint32_t v
, col
, *palette
;
902 palette
= s
->last_palette
;
903 for(i
= 0; i
< 16; i
++) {
905 if (s
->ar
[0x10] & 0x80)
906 v
= ((s
->ar
[0x14] & 0xf) << 4) | (v
& 0xf);
908 v
= ((s
->ar
[0x14] & 0xc) << 4) | (v
& 0x3f);
910 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
911 c6_to_8(s
->palette
[v
+ 1]),
912 c6_to_8(s
->palette
[v
+ 2]));
913 if (col
!= palette
[i
]) {
921 /* return true if the palette was modified */
922 static int update_palette256(VGAState
*s
)
925 uint32_t v
, col
, *palette
;
928 palette
= s
->last_palette
;
930 for(i
= 0; i
< 256; i
++) {
931 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
932 c6_to_8(s
->palette
[v
+ 1]),
933 c6_to_8(s
->palette
[v
+ 2]));
934 if (col
!= palette
[i
]) {
943 static void vga_get_offsets(VGAState
*s
,
944 uint32_t *pline_offset
,
945 uint32_t *pstart_addr
)
947 uint32_t start_addr
, line_offset
;
948 #ifdef CONFIG_BOCHS_VBE
949 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
950 line_offset
= s
->vbe_line_offset
;
951 start_addr
= s
->vbe_start_addr
;
955 /* compute line_offset in bytes */
956 line_offset
= s
->cr
[0x13];
960 v
= (s
->cr
[0x51] >> 4) & 3; /* S3 extension */
962 v
= (s
->cr
[0x43] >> 2) & 1; /* S3 extension */
963 line_offset
|= (v
<< 8);
968 /* starting address */
969 start_addr
= s
->cr
[0x0d] | (s
->cr
[0x0c] << 8);
971 start_addr
|= (s
->cr
[0x69] & 0x1f) << 16; /* S3 extension */
974 *pline_offset
= line_offset
;
975 *pstart_addr
= start_addr
;
978 /* update start_addr and line_offset. Return TRUE if modified */
979 static int update_basic_params(VGAState
*s
)
982 uint32_t start_addr
, line_offset
, line_compare
;
986 s
->get_offsets(s
, &line_offset
, &start_addr
);
988 line_compare
= s
->cr
[0x18] |
989 ((s
->cr
[0x07] & 0x10) << 4) |
990 ((s
->cr
[0x09] & 0x40) << 3);
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
;
1003 static inline int get_depth_index(int depth
)
1018 static vga_draw_glyph8_func
*vga_draw_glyph8_table
[4] = {
1025 static vga_draw_glyph8_func
*vga_draw_glyph16_table
[4] = {
1027 vga_draw_glyph16_16
,
1028 vga_draw_glyph16_16
,
1029 vga_draw_glyph16_32
,
1032 static vga_draw_glyph9_func
*vga_draw_glyph9_table
[4] = {
1039 static const uint8_t cursor_glyph
[32 * 4] = {
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,
1050 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1051 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1052 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1053 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1054 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1055 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1066 static void vga_draw_text(VGAState
*s
, int full_update
)
1068 int cx
, cy
, cheight
, cw
, ch
, cattr
, height
, width
, ch_attr
;
1069 int cx_min
, cx_max
, linesize
, x_incr
;
1070 uint32_t offset
, fgcol
, bgcol
, v
, cursor_offset
;
1071 uint8_t *d1
, *d
, *src
, *s1
, *dest
, *cursor_ptr
;
1072 const uint8_t *font_ptr
, *font_base
[2];
1073 int dup9
, line_offset
, depth_index
;
1075 uint32_t *ch_attr_ptr
;
1076 vga_draw_glyph8_func
*vga_draw_glyph8
;
1077 vga_draw_glyph9_func
*vga_draw_glyph9
;
1079 full_update
|= update_palette16(s
);
1080 palette
= s
->last_palette
;
1082 /* compute font data address (in plane 2) */
1084 offset
= (((v
>> 4) & 1) | ((v
<< 1) & 6)) * 8192 * 4 + 2;
1085 if (offset
!= s
->font_offsets
[0]) {
1086 s
->font_offsets
[0] = offset
;
1089 font_base
[0] = s
->vram_ptr
+ offset
;
1091 offset
= (((v
>> 5) & 1) | ((v
>> 1) & 6)) * 8192 * 4 + 2;
1092 font_base
[1] = s
->vram_ptr
+ offset
;
1093 if (offset
!= s
->font_offsets
[1]) {
1094 s
->font_offsets
[1] = offset
;
1097 if (s
->plane_updated
& (1 << 2)) {
1098 /* if the plane 2 was modified since the last display, it
1099 indicates the font may have been modified */
1100 s
->plane_updated
= 0;
1103 full_update
|= update_basic_params(s
);
1105 line_offset
= s
->line_offset
;
1106 s1
= s
->vram_ptr
+ (s
->start_addr
* 4);
1108 /* total width & height */
1109 cheight
= (s
->cr
[9] & 0x1f) + 1;
1111 if (!(s
->sr
[1] & 0x01))
1113 if (s
->sr
[1] & 0x08)
1114 cw
= 16; /* NOTE: no 18 pixel wide */
1115 x_incr
= cw
* ((s
->ds
->depth
+ 7) >> 3);
1116 width
= (s
->cr
[0x01] + 1);
1117 if (s
->cr
[0x06] == 100) {
1118 /* ugly hack for CGA 160x100x16 - explain me the logic */
1121 height
= s
->cr
[0x12] |
1122 ((s
->cr
[0x07] & 0x02) << 7) |
1123 ((s
->cr
[0x07] & 0x40) << 3);
1124 height
= (height
+ 1) / cheight
;
1126 if ((height
* width
) > CH_ATTR_SIZE
) {
1127 /* better than nothing: exit if transient size is too big */
1131 if (width
!= s
->last_width
|| height
!= s
->last_height
||
1132 cw
!= s
->last_cw
|| cheight
!= s
->last_ch
) {
1133 s
->last_scr_width
= width
* cw
;
1134 s
->last_scr_height
= height
* cheight
;
1135 dpy_resize(s
->ds
, s
->last_scr_width
, s
->last_scr_height
);
1136 s
->last_width
= width
;
1137 s
->last_height
= height
;
1138 s
->last_ch
= cheight
;
1142 cursor_offset
= ((s
->cr
[0x0e] << 8) | s
->cr
[0x0f]) - s
->start_addr
;
1143 if (cursor_offset
!= s
->cursor_offset
||
1144 s
->cr
[0xa] != s
->cursor_start
||
1145 s
->cr
[0xb] != s
->cursor_end
) {
1146 /* if the cursor position changed, we update the old and new
1148 if (s
->cursor_offset
< CH_ATTR_SIZE
)
1149 s
->last_ch_attr
[s
->cursor_offset
] = -1;
1150 if (cursor_offset
< CH_ATTR_SIZE
)
1151 s
->last_ch_attr
[cursor_offset
] = -1;
1152 s
->cursor_offset
= cursor_offset
;
1153 s
->cursor_start
= s
->cr
[0xa];
1154 s
->cursor_end
= s
->cr
[0xb];
1156 cursor_ptr
= s
->vram_ptr
+ (s
->start_addr
+ cursor_offset
) * 4;
1158 depth_index
= get_depth_index(s
->ds
->depth
);
1160 vga_draw_glyph8
= vga_draw_glyph16_table
[depth_index
];
1162 vga_draw_glyph8
= vga_draw_glyph8_table
[depth_index
];
1163 vga_draw_glyph9
= vga_draw_glyph9_table
[depth_index
];
1166 linesize
= s
->ds
->linesize
;
1167 ch_attr_ptr
= s
->last_ch_attr
;
1168 for(cy
= 0; cy
< height
; cy
++) {
1173 for(cx
= 0; cx
< width
; cx
++) {
1174 ch_attr
= *(uint16_t *)src
;
1175 if (full_update
|| ch_attr
!= *ch_attr_ptr
) {
1180 *ch_attr_ptr
= ch_attr
;
1181 #ifdef WORDS_BIGENDIAN
1183 cattr
= ch_attr
& 0xff;
1185 ch
= ch_attr
& 0xff;
1186 cattr
= ch_attr
>> 8;
1188 font_ptr
= font_base
[(cattr
>> 3) & 1];
1189 font_ptr
+= 32 * 4 * ch
;
1190 bgcol
= palette
[cattr
>> 4];
1191 fgcol
= palette
[cattr
& 0x0f];
1193 vga_draw_glyph8(d1
, linesize
,
1194 font_ptr
, cheight
, fgcol
, bgcol
);
1197 if (ch
>= 0xb0 && ch
<= 0xdf && (s
->ar
[0x10] & 0x04))
1199 vga_draw_glyph9(d1
, linesize
,
1200 font_ptr
, cheight
, fgcol
, bgcol
, dup9
);
1202 if (src
== cursor_ptr
&&
1203 !(s
->cr
[0x0a] & 0x20)) {
1204 int line_start
, line_last
, h
;
1205 /* draw the cursor */
1206 line_start
= s
->cr
[0x0a] & 0x1f;
1207 line_last
= s
->cr
[0x0b] & 0x1f;
1208 /* XXX: check that */
1209 if (line_last
> cheight
- 1)
1210 line_last
= cheight
- 1;
1211 if (line_last
>= line_start
&& line_start
< cheight
) {
1212 h
= line_last
- line_start
+ 1;
1213 d
= d1
+ linesize
* line_start
;
1215 vga_draw_glyph8(d
, linesize
,
1216 cursor_glyph
, h
, fgcol
, bgcol
);
1218 vga_draw_glyph9(d
, linesize
,
1219 cursor_glyph
, h
, fgcol
, bgcol
, 1);
1229 dpy_update(s
->ds
, cx_min
* cw
, cy
* cheight
,
1230 (cx_max
- cx_min
+ 1) * cw
, cheight
);
1232 dest
+= linesize
* cheight
;
1251 static vga_draw_line_func
*vga_draw_line_table
[4 * VGA_DRAW_LINE_NB
] = {
1258 vga_draw_line2d2_16
,
1259 vga_draw_line2d2_16
,
1260 vga_draw_line2d2_32
,
1268 vga_draw_line4d2_16
,
1269 vga_draw_line4d2_16
,
1270 vga_draw_line4d2_32
,
1273 vga_draw_line8d2_16
,
1274 vga_draw_line8d2_16
,
1275 vga_draw_line8d2_32
,
1303 static int vga_get_bpp(VGAState
*s
)
1306 #ifdef CONFIG_BOCHS_VBE
1307 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1308 ret
= s
->vbe_regs
[VBE_DISPI_INDEX_BPP
];
1317 static void vga_get_resolution(VGAState
*s
, int *pwidth
, int *pheight
)
1321 width
= (s
->cr
[0x01] + 1) * 8;
1322 height
= s
->cr
[0x12] |
1323 ((s
->cr
[0x07] & 0x02) << 7) |
1324 ((s
->cr
[0x07] & 0x40) << 3);
1325 height
= (height
+ 1);
1330 void vga_invalidate_scanlines(VGAState
*s
, int y1
, int y2
)
1333 if (y1
>= VGA_MAX_HEIGHT
)
1335 if (y2
>= VGA_MAX_HEIGHT
)
1336 y2
= VGA_MAX_HEIGHT
;
1337 for(y
= y1
; y
< y2
; y
++) {
1338 s
->invalidated_y_table
[y
>> 5] |= 1 << (y
& 0x1f);
1345 static void vga_draw_graphic(VGAState
*s
, int full_update
)
1347 int y1
, y
, update
, page_min
, page_max
, linesize
, y_start
, double_scan
, mask
;
1348 int width
, height
, shift_control
, line_offset
, page0
, page1
, bwidth
;
1349 int disp_width
, multi_scan
, multi_run
;
1351 uint32_t v
, addr1
, addr
;
1352 vga_draw_line_func
*vga_draw_line
;
1354 full_update
|= update_basic_params(s
);
1356 s
->get_resolution(s
, &width
, &height
);
1359 shift_control
= (s
->gr
[0x05] >> 5) & 3;
1360 double_scan
= (s
->cr
[0x09] >> 7);
1361 if (shift_control
!= 1) {
1362 multi_scan
= (((s
->cr
[0x09] & 0x1f) + 1) << double_scan
) - 1;
1364 /* in CGA modes, multi_scan is ignored */
1365 /* XXX: is it correct ? */
1366 multi_scan
= double_scan
;
1368 multi_run
= multi_scan
;
1369 if (shift_control
!= s
->shift_control
||
1370 double_scan
!= s
->double_scan
) {
1372 s
->shift_control
= shift_control
;
1373 s
->double_scan
= double_scan
;
1376 if (shift_control
== 0) {
1377 full_update
|= update_palette16(s
);
1378 if (s
->sr
[0x01] & 8) {
1379 v
= VGA_DRAW_LINE4D2
;
1384 } else if (shift_control
== 1) {
1385 full_update
|= update_palette16(s
);
1386 if (s
->sr
[0x01] & 8) {
1387 v
= VGA_DRAW_LINE2D2
;
1393 switch(s
->get_bpp(s
)) {
1396 full_update
|= update_palette256(s
);
1397 v
= VGA_DRAW_LINE8D2
;
1400 full_update
|= update_palette256(s
);
1404 v
= VGA_DRAW_LINE15
;
1407 v
= VGA_DRAW_LINE16
;
1410 v
= VGA_DRAW_LINE24
;
1413 v
= VGA_DRAW_LINE32
;
1417 vga_draw_line
= vga_draw_line_table
[v
* 4 + get_depth_index(s
->ds
->depth
)];
1419 if (disp_width
!= s
->last_width
||
1420 height
!= s
->last_height
) {
1421 dpy_resize(s
->ds
, disp_width
, height
);
1422 s
->last_scr_width
= disp_width
;
1423 s
->last_scr_height
= height
;
1424 s
->last_width
= disp_width
;
1425 s
->last_height
= height
;
1428 if (s
->cursor_invalidate
)
1429 s
->cursor_invalidate(s
);
1431 line_offset
= s
->line_offset
;
1433 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",
1434 width
, height
, v
, line_offset
, s
->cr
[9], s
->cr
[0x17], s
->line_compare
, s
->sr
[0x01]);
1436 addr1
= (s
->start_addr
* 4);
1439 page_min
= 0x7fffffff;
1442 linesize
= s
->ds
->linesize
;
1444 for(y
= 0; y
< height
; y
++) {
1446 if (!(s
->cr
[0x17] & 1)) {
1448 /* CGA compatibility handling */
1449 shift
= 14 + ((s
->cr
[0x17] >> 6) & 1);
1450 addr
= (addr
& ~(1 << shift
)) | ((y1
& 1) << shift
);
1452 if (!(s
->cr
[0x17] & 2)) {
1453 addr
= (addr
& ~0x8000) | ((y1
& 2) << 14);
1455 page0
= s
->vram_offset
+ (addr
& TARGET_PAGE_MASK
);
1456 page1
= s
->vram_offset
+ ((addr
+ bwidth
- 1) & TARGET_PAGE_MASK
);
1457 update
= full_update
| cpu_physical_memory_is_dirty(page0
) |
1458 cpu_physical_memory_is_dirty(page1
);
1459 if ((page1
- page0
) > TARGET_PAGE_SIZE
) {
1460 /* if wide line, can use another page */
1461 update
|= cpu_physical_memory_is_dirty(page0
+ TARGET_PAGE_SIZE
);
1463 /* explicit invalidation for the hardware cursor */
1464 update
|= (s
->invalidated_y_table
[y
>> 5] >> (y
& 0x1f)) & 1;
1468 if (page0
< page_min
)
1470 if (page1
> page_max
)
1472 vga_draw_line(s
, d
, s
->vram_ptr
+ addr
, width
);
1473 if (s
->cursor_draw_line
)
1474 s
->cursor_draw_line(s
, d
, y
);
1477 /* flush to display */
1478 dpy_update(s
->ds
, 0, y_start
,
1479 disp_width
, y
- y_start
);
1484 mask
= (s
->cr
[0x17] & 3) ^ 3;
1485 if ((y1
& mask
) == mask
)
1486 addr1
+= line_offset
;
1488 multi_run
= multi_scan
;
1492 /* line compare acts on the displayed lines */
1493 if (y
== s
->line_compare
)
1498 /* flush to display */
1499 dpy_update(s
->ds
, 0, y_start
,
1500 disp_width
, y
- y_start
);
1502 /* reset modified pages */
1503 if (page_max
!= -1) {
1504 cpu_physical_memory_reset_dirty(page_min
, page_max
+ TARGET_PAGE_SIZE
);
1506 memset(s
->invalidated_y_table
, 0, ((height
+ 31) >> 5) * 4);
1509 static void vga_draw_blank(VGAState
*s
, int full_update
)
1516 if (s
->last_scr_width
<= 0 || s
->last_scr_height
<= 0)
1518 if (s
->ds
->depth
== 8)
1519 val
= s
->rgb_to_pixel(0, 0, 0);
1522 w
= s
->last_scr_width
* ((s
->ds
->depth
+ 7) >> 3);
1524 for(i
= 0; i
< s
->last_scr_height
; i
++) {
1526 d
+= s
->ds
->linesize
;
1528 dpy_update(s
->ds
, 0, 0,
1529 s
->last_scr_width
, s
->last_scr_height
);
1532 #define GMODE_TEXT 0
1533 #define GMODE_GRAPH 1
1534 #define GMODE_BLANK 2
1536 void vga_update_display(void)
1538 VGAState
*s
= vga_state
;
1539 int full_update
, graphic_mode
;
1541 if (s
->ds
->depth
== 0) {
1544 switch(s
->ds
->depth
) {
1546 s
->rgb_to_pixel
= rgb_to_pixel8_dup
;
1549 s
->rgb_to_pixel
= rgb_to_pixel15_dup
;
1553 s
->rgb_to_pixel
= rgb_to_pixel16_dup
;
1556 s
->rgb_to_pixel
= rgb_to_pixel32_dup
;
1561 if (!(s
->ar_index
& 0x20)) {
1562 graphic_mode
= GMODE_BLANK
;
1564 graphic_mode
= s
->gr
[6] & 1;
1566 if (graphic_mode
!= s
->graphic_mode
) {
1567 s
->graphic_mode
= graphic_mode
;
1570 switch(graphic_mode
) {
1572 vga_draw_text(s
, full_update
);
1575 vga_draw_graphic(s
, full_update
);
1579 vga_draw_blank(s
, full_update
);
1585 /* force a full display refresh */
1586 void vga_invalidate_display(void)
1588 VGAState
*s
= vga_state
;
1591 s
->last_height
= -1;
1594 static void vga_reset(VGAState
*s
)
1596 memset(s
, 0, sizeof(VGAState
));
1598 /* chip ID for 8c968 */
1601 s
->cr
[0x2f] = 0x01; /* XXX: check revision code */
1604 s
->graphic_mode
= -1; /* force full update */
1607 static CPUReadMemoryFunc
*vga_mem_read
[3] = {
1613 static CPUWriteMemoryFunc
*vga_mem_write
[3] = {
1619 static void vga_save(QEMUFile
*f
, void *opaque
)
1621 VGAState
*s
= opaque
;
1624 qemu_put_be32s(f
, &s
->latch
);
1625 qemu_put_8s(f
, &s
->sr_index
);
1626 qemu_put_buffer(f
, s
->sr
, 8);
1627 qemu_put_8s(f
, &s
->gr_index
);
1628 qemu_put_buffer(f
, s
->gr
, 16);
1629 qemu_put_8s(f
, &s
->ar_index
);
1630 qemu_put_buffer(f
, s
->ar
, 21);
1631 qemu_put_be32s(f
, &s
->ar_flip_flop
);
1632 qemu_put_8s(f
, &s
->cr_index
);
1633 qemu_put_buffer(f
, s
->cr
, 256);
1634 qemu_put_8s(f
, &s
->msr
);
1635 qemu_put_8s(f
, &s
->fcr
);
1636 qemu_put_8s(f
, &s
->st00
);
1637 qemu_put_8s(f
, &s
->st01
);
1639 qemu_put_8s(f
, &s
->dac_state
);
1640 qemu_put_8s(f
, &s
->dac_sub_index
);
1641 qemu_put_8s(f
, &s
->dac_read_index
);
1642 qemu_put_8s(f
, &s
->dac_write_index
);
1643 qemu_put_buffer(f
, s
->dac_cache
, 3);
1644 qemu_put_buffer(f
, s
->palette
, 768);
1646 qemu_put_be32s(f
, &s
->bank_offset
);
1647 #ifdef CONFIG_BOCHS_VBE
1648 qemu_put_byte(f
, 1);
1649 qemu_put_be16s(f
, &s
->vbe_index
);
1650 for(i
= 0; i
< VBE_DISPI_INDEX_NB
; i
++)
1651 qemu_put_be16s(f
, &s
->vbe_regs
[i
]);
1652 qemu_put_be32s(f
, &s
->vbe_start_addr
);
1653 qemu_put_be32s(f
, &s
->vbe_line_offset
);
1654 qemu_put_be32s(f
, &s
->vbe_bank_mask
);
1656 qemu_put_byte(f
, 0);
1660 static int vga_load(QEMUFile
*f
, void *opaque
, int version_id
)
1662 VGAState
*s
= opaque
;
1665 if (version_id
!= 1)
1668 qemu_get_be32s(f
, &s
->latch
);
1669 qemu_get_8s(f
, &s
->sr_index
);
1670 qemu_get_buffer(f
, s
->sr
, 8);
1671 qemu_get_8s(f
, &s
->gr_index
);
1672 qemu_get_buffer(f
, s
->gr
, 16);
1673 qemu_get_8s(f
, &s
->ar_index
);
1674 qemu_get_buffer(f
, s
->ar
, 21);
1675 qemu_get_be32s(f
, &s
->ar_flip_flop
);
1676 qemu_get_8s(f
, &s
->cr_index
);
1677 qemu_get_buffer(f
, s
->cr
, 256);
1678 qemu_get_8s(f
, &s
->msr
);
1679 qemu_get_8s(f
, &s
->fcr
);
1680 qemu_get_8s(f
, &s
->st00
);
1681 qemu_get_8s(f
, &s
->st01
);
1683 qemu_get_8s(f
, &s
->dac_state
);
1684 qemu_get_8s(f
, &s
->dac_sub_index
);
1685 qemu_get_8s(f
, &s
->dac_read_index
);
1686 qemu_get_8s(f
, &s
->dac_write_index
);
1687 qemu_get_buffer(f
, s
->dac_cache
, 3);
1688 qemu_get_buffer(f
, s
->palette
, 768);
1690 qemu_get_be32s(f
, &s
->bank_offset
);
1691 is_vbe
= qemu_get_byte(f
);
1692 #ifdef CONFIG_BOCHS_VBE
1695 qemu_get_be16s(f
, &s
->vbe_index
);
1696 for(i
= 0; i
< VBE_DISPI_INDEX_NB
; i
++)
1697 qemu_get_be16s(f
, &s
->vbe_regs
[i
]);
1698 qemu_get_be32s(f
, &s
->vbe_start_addr
);
1699 qemu_get_be32s(f
, &s
->vbe_line_offset
);
1700 qemu_get_be32s(f
, &s
->vbe_bank_mask
);
1707 s
->graphic_mode
= -1;
1711 static void vga_map(PCIDevice
*pci_dev
, int region_num
,
1712 uint32_t addr
, uint32_t size
, int type
)
1714 VGAState
*s
= vga_state
;
1716 cpu_register_physical_memory(addr
, s
->vram_size
, s
->vram_offset
);
1719 void vga_common_init(VGAState
*s
, DisplayState
*ds
, uint8_t *vga_ram_base
,
1720 unsigned long vga_ram_offset
, int vga_ram_size
)
1724 for(i
= 0;i
< 256; i
++) {
1726 for(j
= 0; j
< 8; j
++) {
1727 v
|= ((i
>> j
) & 1) << (j
* 4);
1732 for(j
= 0; j
< 4; j
++) {
1733 v
|= ((i
>> (2 * j
)) & 3) << (j
* 4);
1737 for(i
= 0; i
< 16; i
++) {
1739 for(j
= 0; j
< 4; j
++) {
1742 v
|= b
<< (2 * j
+ 1);
1749 s
->vram_ptr
= vga_ram_base
;
1750 s
->vram_offset
= vga_ram_offset
;
1751 s
->vram_size
= vga_ram_size
;
1753 s
->get_bpp
= vga_get_bpp
;
1754 s
->get_offsets
= vga_get_offsets
;
1755 s
->get_resolution
= vga_get_resolution
;
1756 /* XXX: currently needed for display */
1761 int vga_initialize(PCIBus
*bus
, DisplayState
*ds
, uint8_t *vga_ram_base
,
1762 unsigned long vga_ram_offset
, int vga_ram_size
)
1766 s
= qemu_mallocz(sizeof(VGAState
));
1770 vga_common_init(s
, ds
, vga_ram_base
, vga_ram_offset
, vga_ram_size
);
1772 register_savevm("vga", 0, 1, vga_save
, vga_load
, s
);
1774 register_ioport_write(0x3c0, 16, 1, vga_ioport_write
, s
);
1776 register_ioport_write(0x3b4, 2, 1, vga_ioport_write
, s
);
1777 register_ioport_write(0x3d4, 2, 1, vga_ioport_write
, s
);
1778 register_ioport_write(0x3ba, 1, 1, vga_ioport_write
, s
);
1779 register_ioport_write(0x3da, 1, 1, vga_ioport_write
, s
);
1781 register_ioport_read(0x3c0, 16, 1, vga_ioport_read
, s
);
1783 register_ioport_read(0x3b4, 2, 1, vga_ioport_read
, s
);
1784 register_ioport_read(0x3d4, 2, 1, vga_ioport_read
, s
);
1785 register_ioport_read(0x3ba, 1, 1, vga_ioport_read
, s
);
1786 register_ioport_read(0x3da, 1, 1, vga_ioport_read
, s
);
1789 #ifdef CONFIG_BOCHS_VBE
1790 s
->vbe_regs
[VBE_DISPI_INDEX_ID
] = VBE_DISPI_ID0
;
1791 s
->vbe_bank_mask
= ((s
->vram_size
>> 16) - 1);
1792 #if defined (TARGET_I386)
1793 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index
, s
);
1794 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data
, s
);
1796 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index
, s
);
1797 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data
, s
);
1799 /* old Bochs IO ports */
1800 register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index
, s
);
1801 register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data
, s
);
1803 register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index
, s
);
1804 register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data
, s
);
1806 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index
, s
);
1807 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data
, s
);
1809 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index
, s
);
1810 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data
, s
);
1812 #endif /* CONFIG_BOCHS_VBE */
1814 vga_io_memory
= cpu_register_io_memory(0, vga_mem_read
, vga_mem_write
, s
);
1815 cpu_register_physical_memory(isa_mem_base
+ 0x000a0000, 0x20000,
1822 d
= pci_register_device(bus
, "VGA",
1825 pci_conf
= d
->config
;
1826 pci_conf
[0x00] = 0x34; // dummy VGA (same as Bochs ID)
1827 pci_conf
[0x01] = 0x12;
1828 pci_conf
[0x02] = 0x11;
1829 pci_conf
[0x03] = 0x11;
1830 pci_conf
[0x0a] = 0x00; // VGA controller
1831 pci_conf
[0x0b] = 0x03;
1832 pci_conf
[0x0e] = 0x00; // header_type
1834 /* XXX: vga_ram_size must be a power of two */
1835 pci_register_io_region(d
, 0, vga_ram_size
,
1836 PCI_ADDRESS_SPACE_MEM_PREFETCH
, vga_map
);
1838 #ifdef CONFIG_BOCHS_VBE
1839 /* XXX: use optimized standard vga accesses */
1840 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS
,
1841 vga_ram_size
, vga_ram_offset
);
1847 /********************************************************/
1848 /* vga screen dump */
1850 static int vga_save_w
, vga_save_h
;
1852 static void vga_save_dpy_update(DisplayState
*s
,
1853 int x
, int y
, int w
, int h
)
1857 static void vga_save_dpy_resize(DisplayState
*s
, int w
, int h
)
1859 s
->linesize
= w
* 4;
1860 s
->data
= qemu_malloc(h
* s
->linesize
);
1865 static void vga_save_dpy_refresh(DisplayState
*s
)
1869 static int ppm_save(const char *filename
, uint8_t *data
,
1870 int w
, int h
, int linesize
)
1877 f
= fopen(filename
, "wb");
1880 fprintf(f
, "P6\n%d %d\n%d\n",
1883 for(y
= 0; y
< h
; y
++) {
1885 for(x
= 0; x
< w
; x
++) {
1887 fputc((v
>> 16) & 0xff, f
);
1888 fputc((v
>> 8) & 0xff, f
);
1889 fputc((v
) & 0xff, f
);
1898 /* save the vga display in a PPM image even if no display is
1900 void vga_screen_dump(const char *filename
)
1902 VGAState
*s
= vga_state
;
1903 DisplayState
*saved_ds
, ds1
, *ds
= &ds1
;
1905 /* XXX: this is a little hackish */
1906 vga_invalidate_display();
1909 memset(ds
, 0, sizeof(DisplayState
));
1910 ds
->dpy_update
= vga_save_dpy_update
;
1911 ds
->dpy_resize
= vga_save_dpy_resize
;
1912 ds
->dpy_refresh
= vga_save_dpy_refresh
;
1916 s
->graphic_mode
= -1;
1917 vga_update_display();
1920 ppm_save(filename
, ds
->data
, vga_save_w
, vga_save_h
,
1922 qemu_free(ds
->data
);