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
31 //#define DEBUG_BOCHS_VBE
33 /* force some bits to zero */
34 const uint8_t sr_mask
[8] = {
45 const uint8_t gr_mask
[16] = {
46 (uint8_t)~0xf0, /* 0x00 */
47 (uint8_t)~0xf0, /* 0x01 */
48 (uint8_t)~0xf0, /* 0x02 */
49 (uint8_t)~0xe0, /* 0x03 */
50 (uint8_t)~0xfc, /* 0x04 */
51 (uint8_t)~0x84, /* 0x05 */
52 (uint8_t)~0xf0, /* 0x06 */
53 (uint8_t)~0xf0, /* 0x07 */
54 (uint8_t)~0x00, /* 0x08 */
55 (uint8_t)~0xff, /* 0x09 */
56 (uint8_t)~0xff, /* 0x0a */
57 (uint8_t)~0xff, /* 0x0b */
58 (uint8_t)~0xff, /* 0x0c */
59 (uint8_t)~0xff, /* 0x0d */
60 (uint8_t)~0xff, /* 0x0e */
61 (uint8_t)~0xff, /* 0x0f */
64 #define cbswap_32(__x) \
66 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
67 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
68 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
69 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
71 #ifdef WORDS_BIGENDIAN
72 #define PAT(x) cbswap_32(x)
77 #ifdef WORDS_BIGENDIAN
83 #ifdef WORDS_BIGENDIAN
84 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
86 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
89 static const uint32_t mask16
[16] = {
110 #ifdef WORDS_BIGENDIAN
113 #define PAT(x) cbswap_32(x)
116 static const uint32_t dmask16
[16] = {
135 static const uint32_t dmask4
[4] = {
142 static uint32_t expand4
[256];
143 static uint16_t expand2
[256];
144 static uint8_t expand4to8
[16];
146 static void vga_screen_dump(void *opaque
, const char *filename
);
148 static uint32_t vga_ioport_read(void *opaque
, uint32_t addr
)
150 VGAState
*s
= opaque
;
153 /* check port range access depending on color/monochrome mode */
154 if ((addr
>= 0x3b0 && addr
<= 0x3bf && (s
->msr
& MSR_COLOR_EMULATION
)) ||
155 (addr
>= 0x3d0 && addr
<= 0x3df && !(s
->msr
& MSR_COLOR_EMULATION
))) {
160 if (s
->ar_flip_flop
== 0) {
167 index
= s
->ar_index
& 0x1f;
180 val
= s
->sr
[s
->sr_index
];
182 printf("vga: read SR%x = 0x%02x\n", s
->sr_index
, val
);
189 val
= s
->dac_write_index
;
192 val
= s
->palette
[s
->dac_read_index
* 3 + s
->dac_sub_index
];
193 if (++s
->dac_sub_index
== 3) {
194 s
->dac_sub_index
= 0;
208 val
= s
->gr
[s
->gr_index
];
210 printf("vga: read GR%x = 0x%02x\n", s
->gr_index
, val
);
219 val
= s
->cr
[s
->cr_index
];
221 printf("vga: read CR%x = 0x%02x\n", s
->cr_index
, val
);
226 /* just toggle to fool polling */
227 s
->st01
^= ST01_V_RETRACE
| ST01_DISP_ENABLE
;
236 #if defined(DEBUG_VGA)
237 printf("VGA: read addr=0x%04x data=0x%02x\n", addr
, val
);
242 static void vga_ioport_write(void *opaque
, uint32_t addr
, uint32_t val
)
244 VGAState
*s
= opaque
;
247 /* check port range access depending on color/monochrome mode */
248 if ((addr
>= 0x3b0 && addr
<= 0x3bf && (s
->msr
& MSR_COLOR_EMULATION
)) ||
249 (addr
>= 0x3d0 && addr
<= 0x3df && !(s
->msr
& MSR_COLOR_EMULATION
)))
253 printf("VGA: write addr=0x%04x data=0x%02x\n", addr
, val
);
258 if (s
->ar_flip_flop
== 0) {
262 index
= s
->ar_index
& 0x1f;
265 s
->ar
[index
] = val
& 0x3f;
268 s
->ar
[index
] = val
& ~0x10;
274 s
->ar
[index
] = val
& ~0xc0;
277 s
->ar
[index
] = val
& ~0xf0;
280 s
->ar
[index
] = val
& ~0xf0;
286 s
->ar_flip_flop
^= 1;
289 s
->msr
= val
& ~0x10;
292 s
->sr_index
= val
& 7;
296 printf("vga: write SR%x = 0x%02x\n", s
->sr_index
, val
);
298 s
->sr
[s
->sr_index
] = val
& sr_mask
[s
->sr_index
];
301 s
->dac_read_index
= val
;
302 s
->dac_sub_index
= 0;
306 s
->dac_write_index
= val
;
307 s
->dac_sub_index
= 0;
311 s
->dac_cache
[s
->dac_sub_index
] = val
;
312 if (++s
->dac_sub_index
== 3) {
313 memcpy(&s
->palette
[s
->dac_write_index
* 3], s
->dac_cache
, 3);
314 s
->dac_sub_index
= 0;
315 s
->dac_write_index
++;
319 s
->gr_index
= val
& 0x0f;
323 printf("vga: write GR%x = 0x%02x\n", s
->gr_index
, val
);
325 s
->gr
[s
->gr_index
] = val
& gr_mask
[s
->gr_index
];
334 printf("vga: write CR%x = 0x%02x\n", s
->cr_index
, val
);
336 /* handle CR0-7 protection */
337 if ((s
->cr
[0x11] & 0x80) && s
->cr_index
<= 7) {
338 /* can always write bit 4 of CR7 */
339 if (s
->cr_index
== 7)
340 s
->cr
[7] = (s
->cr
[7] & ~0x10) | (val
& 0x10);
343 switch(s
->cr_index
) {
344 case 0x01: /* horizontal display end */
349 case 0x12: /* veritcal display end */
350 s
->cr
[s
->cr_index
] = val
;
353 s
->cr
[s
->cr_index
] = val
;
364 #ifdef CONFIG_BOCHS_VBE
365 static uint32_t vbe_ioport_read_index(void *opaque
, uint32_t addr
)
367 VGAState
*s
= opaque
;
373 static uint32_t vbe_ioport_read_data(void *opaque
, uint32_t addr
)
375 VGAState
*s
= opaque
;
378 if (s
->vbe_index
<= VBE_DISPI_INDEX_NB
) {
379 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_GETCAPS
) {
380 switch(s
->vbe_index
) {
381 /* XXX: do not hardcode ? */
382 case VBE_DISPI_INDEX_XRES
:
383 val
= VBE_DISPI_MAX_XRES
;
385 case VBE_DISPI_INDEX_YRES
:
386 val
= VBE_DISPI_MAX_YRES
;
388 case VBE_DISPI_INDEX_BPP
:
389 val
= VBE_DISPI_MAX_BPP
;
392 val
= s
->vbe_regs
[s
->vbe_index
];
396 val
= s
->vbe_regs
[s
->vbe_index
];
401 #ifdef DEBUG_BOCHS_VBE
402 printf("VBE: read index=0x%x val=0x%x\n", s
->vbe_index
, val
);
407 static void vbe_ioport_write_index(void *opaque
, uint32_t addr
, uint32_t val
)
409 VGAState
*s
= opaque
;
413 static void vbe_ioport_write_data(void *opaque
, uint32_t addr
, uint32_t val
)
415 VGAState
*s
= opaque
;
417 if (s
->vbe_index
<= VBE_DISPI_INDEX_NB
) {
418 #ifdef DEBUG_BOCHS_VBE
419 printf("VBE: write index=0x%x val=0x%x\n", s
->vbe_index
, val
);
421 switch(s
->vbe_index
) {
422 case VBE_DISPI_INDEX_ID
:
423 if (val
== VBE_DISPI_ID0
||
424 val
== VBE_DISPI_ID1
||
425 val
== VBE_DISPI_ID2
) {
426 s
->vbe_regs
[s
->vbe_index
] = val
;
429 case VBE_DISPI_INDEX_XRES
:
430 if ((val
<= VBE_DISPI_MAX_XRES
) && ((val
& 7) == 0)) {
431 s
->vbe_regs
[s
->vbe_index
] = val
;
434 case VBE_DISPI_INDEX_YRES
:
435 if (val
<= VBE_DISPI_MAX_YRES
) {
436 s
->vbe_regs
[s
->vbe_index
] = val
;
439 case VBE_DISPI_INDEX_BPP
:
442 if (val
== 4 || val
== 8 || val
== 15 ||
443 val
== 16 || val
== 24 || val
== 32) {
444 s
->vbe_regs
[s
->vbe_index
] = val
;
447 case VBE_DISPI_INDEX_BANK
:
448 val
&= s
->vbe_bank_mask
;
449 s
->vbe_regs
[s
->vbe_index
] = val
;
450 s
->bank_offset
= (val
<< 16);
452 case VBE_DISPI_INDEX_ENABLE
:
453 if ((val
& VBE_DISPI_ENABLED
) &&
454 !(s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
)) {
455 int h
, shift_control
;
457 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] =
458 s
->vbe_regs
[VBE_DISPI_INDEX_XRES
];
459 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_HEIGHT
] =
460 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
];
461 s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
] = 0;
462 s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
] = 0;
464 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
465 s
->vbe_line_offset
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 1;
467 s
->vbe_line_offset
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] *
468 ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
469 s
->vbe_start_addr
= 0;
471 /* clear the screen (should be done in BIOS) */
472 if (!(val
& VBE_DISPI_NOCLEARMEM
)) {
473 memset(s
->vram_ptr
, 0,
474 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] * s
->vbe_line_offset
);
477 /* we initialize the VGA graphic mode (should be done
479 s
->gr
[0x06] = (s
->gr
[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
480 s
->cr
[0x17] |= 3; /* no CGA modes */
481 s
->cr
[0x13] = s
->vbe_line_offset
>> 3;
483 s
->cr
[0x01] = (s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 3) - 1;
484 /* height (only meaningful if < 1024) */
485 h
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] - 1;
487 s
->cr
[0x07] = (s
->cr
[0x07] & ~0x42) |
488 ((h
>> 7) & 0x02) | ((h
>> 3) & 0x40);
489 /* line compare to 1023 */
494 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
496 s
->sr
[0x01] &= ~8; /* no double line */
499 s
->sr
[4] |= 0x08; /* set chain 4 mode */
500 s
->sr
[2] |= 0x0f; /* activate all planes */
502 s
->gr
[0x05] = (s
->gr
[0x05] & ~0x60) | (shift_control
<< 5);
503 s
->cr
[0x09] &= ~0x9f; /* no double scan */
505 /* XXX: the bios should do that */
508 s
->vbe_regs
[s
->vbe_index
] = val
;
510 case VBE_DISPI_INDEX_VIRT_WIDTH
:
512 int w
, h
, line_offset
;
514 if (val
< s
->vbe_regs
[VBE_DISPI_INDEX_XRES
])
517 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
518 line_offset
= w
>> 1;
520 line_offset
= w
* ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
521 h
= s
->vram_size
/ line_offset
;
522 /* XXX: support weird bochs semantics ? */
523 if (h
< s
->vbe_regs
[VBE_DISPI_INDEX_YRES
])
525 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] = w
;
526 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_HEIGHT
] = h
;
527 s
->vbe_line_offset
= line_offset
;
530 case VBE_DISPI_INDEX_X_OFFSET
:
531 case VBE_DISPI_INDEX_Y_OFFSET
:
534 s
->vbe_regs
[s
->vbe_index
] = val
;
535 s
->vbe_start_addr
= s
->vbe_line_offset
* s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
];
536 x
= s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
];
537 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
538 s
->vbe_start_addr
+= x
>> 1;
540 s
->vbe_start_addr
+= x
* ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
541 s
->vbe_start_addr
>>= 2;
551 /* called for accesses between 0xa0000 and 0xc0000 */
552 uint32_t vga_mem_readb(void *opaque
, target_phys_addr_t addr
)
554 VGAState
*s
= opaque
;
555 int memory_map_mode
, plane
;
558 /* convert to VGA memory offset */
559 memory_map_mode
= (s
->gr
[6] >> 2) & 3;
561 switch(memory_map_mode
) {
567 addr
+= s
->bank_offset
;
582 if (s
->sr
[4] & 0x08) {
583 /* chain 4 mode : simplest access */
584 ret
= s
->vram_ptr
[addr
];
585 } else if (s
->gr
[5] & 0x10) {
586 /* odd/even mode (aka text mode mapping) */
587 plane
= (s
->gr
[4] & 2) | (addr
& 1);
588 ret
= s
->vram_ptr
[((addr
& ~1) << 1) | plane
];
590 /* standard VGA latched access */
591 s
->latch
= ((uint32_t *)s
->vram_ptr
)[addr
];
593 if (!(s
->gr
[5] & 0x08)) {
596 ret
= GET_PLANE(s
->latch
, plane
);
599 ret
= (s
->latch
^ mask16
[s
->gr
[2]]) & mask16
[s
->gr
[7]];
608 static uint32_t vga_mem_readw(void *opaque
, target_phys_addr_t addr
)
611 #ifdef TARGET_WORDS_BIGENDIAN
612 v
= vga_mem_readb(opaque
, addr
) << 8;
613 v
|= vga_mem_readb(opaque
, addr
+ 1);
615 v
= vga_mem_readb(opaque
, addr
);
616 v
|= vga_mem_readb(opaque
, addr
+ 1) << 8;
621 static uint32_t vga_mem_readl(void *opaque
, target_phys_addr_t addr
)
624 #ifdef TARGET_WORDS_BIGENDIAN
625 v
= vga_mem_readb(opaque
, addr
) << 24;
626 v
|= vga_mem_readb(opaque
, addr
+ 1) << 16;
627 v
|= vga_mem_readb(opaque
, addr
+ 2) << 8;
628 v
|= vga_mem_readb(opaque
, addr
+ 3);
630 v
= vga_mem_readb(opaque
, addr
);
631 v
|= vga_mem_readb(opaque
, addr
+ 1) << 8;
632 v
|= vga_mem_readb(opaque
, addr
+ 2) << 16;
633 v
|= vga_mem_readb(opaque
, addr
+ 3) << 24;
638 /* called for accesses between 0xa0000 and 0xc0000 */
639 void vga_mem_writeb(void *opaque
, target_phys_addr_t addr
, uint32_t val
)
641 VGAState
*s
= opaque
;
642 int memory_map_mode
, plane
, write_mode
, b
, func_select
, mask
;
643 uint32_t write_mask
, bit_mask
, set_mask
;
646 printf("vga: [0x%x] = 0x%02x\n", addr
, val
);
648 /* convert to VGA memory offset */
649 memory_map_mode
= (s
->gr
[6] >> 2) & 3;
651 switch(memory_map_mode
) {
657 addr
+= s
->bank_offset
;
672 if (s
->sr
[4] & 0x08) {
673 /* chain 4 mode : simplest access */
676 if (s
->sr
[2] & mask
) {
677 s
->vram_ptr
[addr
] = val
;
679 printf("vga: chain4: [0x%x]\n", addr
);
681 s
->plane_updated
|= mask
; /* only used to detect font change */
682 cpu_physical_memory_set_dirty(s
->vram_offset
+ addr
);
684 } else if (s
->gr
[5] & 0x10) {
685 /* odd/even mode (aka text mode mapping) */
686 plane
= (s
->gr
[4] & 2) | (addr
& 1);
688 if (s
->sr
[2] & mask
) {
689 addr
= ((addr
& ~1) << 1) | plane
;
690 s
->vram_ptr
[addr
] = val
;
692 printf("vga: odd/even: [0x%x]\n", addr
);
694 s
->plane_updated
|= mask
; /* only used to detect font change */
695 cpu_physical_memory_set_dirty(s
->vram_offset
+ addr
);
698 /* standard VGA latched access */
699 write_mode
= s
->gr
[5] & 3;
705 val
= ((val
>> b
) | (val
<< (8 - b
))) & 0xff;
709 /* apply set/reset mask */
710 set_mask
= mask16
[s
->gr
[1]];
711 val
= (val
& ~set_mask
) | (mask16
[s
->gr
[0]] & set_mask
);
718 val
= mask16
[val
& 0x0f];
724 val
= (val
>> b
) | (val
<< (8 - b
));
726 bit_mask
= s
->gr
[8] & val
;
727 val
= mask16
[s
->gr
[0]];
731 /* apply logical operation */
732 func_select
= s
->gr
[3] >> 3;
733 switch(func_select
) {
753 bit_mask
|= bit_mask
<< 8;
754 bit_mask
|= bit_mask
<< 16;
755 val
= (val
& bit_mask
) | (s
->latch
& ~bit_mask
);
758 /* mask data according to sr[2] */
760 s
->plane_updated
|= mask
; /* only used to detect font change */
761 write_mask
= mask16
[mask
];
762 ((uint32_t *)s
->vram_ptr
)[addr
] =
763 (((uint32_t *)s
->vram_ptr
)[addr
] & ~write_mask
) |
766 printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
767 addr
* 4, write_mask
, val
);
769 cpu_physical_memory_set_dirty(s
->vram_offset
+ (addr
<< 2));
773 static void vga_mem_writew(void *opaque
, target_phys_addr_t addr
, uint32_t val
)
775 #ifdef TARGET_WORDS_BIGENDIAN
776 vga_mem_writeb(opaque
, addr
, (val
>> 8) & 0xff);
777 vga_mem_writeb(opaque
, addr
+ 1, val
& 0xff);
779 vga_mem_writeb(opaque
, addr
, val
& 0xff);
780 vga_mem_writeb(opaque
, addr
+ 1, (val
>> 8) & 0xff);
784 static void vga_mem_writel(void *opaque
, target_phys_addr_t addr
, uint32_t val
)
786 #ifdef TARGET_WORDS_BIGENDIAN
787 vga_mem_writeb(opaque
, addr
, (val
>> 24) & 0xff);
788 vga_mem_writeb(opaque
, addr
+ 1, (val
>> 16) & 0xff);
789 vga_mem_writeb(opaque
, addr
+ 2, (val
>> 8) & 0xff);
790 vga_mem_writeb(opaque
, addr
+ 3, val
& 0xff);
792 vga_mem_writeb(opaque
, addr
, val
& 0xff);
793 vga_mem_writeb(opaque
, addr
+ 1, (val
>> 8) & 0xff);
794 vga_mem_writeb(opaque
, addr
+ 2, (val
>> 16) & 0xff);
795 vga_mem_writeb(opaque
, addr
+ 3, (val
>> 24) & 0xff);
799 typedef void vga_draw_glyph8_func(uint8_t *d
, int linesize
,
800 const uint8_t *font_ptr
, int h
,
801 uint32_t fgcol
, uint32_t bgcol
);
802 typedef void vga_draw_glyph9_func(uint8_t *d
, int linesize
,
803 const uint8_t *font_ptr
, int h
,
804 uint32_t fgcol
, uint32_t bgcol
, int dup9
);
805 typedef void vga_draw_line_func(VGAState
*s1
, uint8_t *d
,
806 const uint8_t *s
, int width
);
808 static inline unsigned int rgb_to_pixel8(unsigned int r
, unsigned int g
, unsigned b
)
810 return ((r
>> 5) << 5) | ((g
>> 5) << 2) | (b
>> 6);
813 static inline unsigned int rgb_to_pixel15(unsigned int r
, unsigned int g
, unsigned b
)
815 return ((r
>> 3) << 10) | ((g
>> 3) << 5) | (b
>> 3);
818 static inline unsigned int rgb_to_pixel16(unsigned int r
, unsigned int g
, unsigned b
)
820 return ((r
>> 3) << 11) | ((g
>> 2) << 5) | (b
>> 3);
823 static inline unsigned int rgb_to_pixel32(unsigned int r
, unsigned int g
, unsigned b
)
825 return (r
<< 16) | (g
<< 8) | b
;
828 static inline unsigned int rgb_to_pixel32bgr(unsigned int r
, unsigned int g
, unsigned b
)
830 return (b
<< 16) | (g
<< 8) | r
;
834 #include "vga_template.h"
837 #include "vga_template.h"
840 #include "vga_template.h"
843 #include "vga_template.h"
847 #include "vga_template.h"
849 static unsigned int rgb_to_pixel8_dup(unsigned int r
, unsigned int g
, unsigned b
)
852 col
= rgb_to_pixel8(r
, g
, b
);
858 static unsigned int rgb_to_pixel15_dup(unsigned int r
, unsigned int g
, unsigned b
)
861 col
= rgb_to_pixel15(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_pixel32_dup(unsigned int r
, unsigned int g
, unsigned b
)
877 col
= rgb_to_pixel32(r
, g
, b
);
881 static unsigned int rgb_to_pixel32bgr_dup(unsigned int r
, unsigned int g
, unsigned b
)
884 col
= rgb_to_pixel32bgr(r
, g
, b
);
888 /* return true if the palette was modified */
889 static int update_palette16(VGAState
*s
)
892 uint32_t v
, col
, *palette
;
895 palette
= s
->last_palette
;
896 for(i
= 0; i
< 16; i
++) {
898 if (s
->ar
[0x10] & 0x80)
899 v
= ((s
->ar
[0x14] & 0xf) << 4) | (v
& 0xf);
901 v
= ((s
->ar
[0x14] & 0xc) << 4) | (v
& 0x3f);
903 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
904 c6_to_8(s
->palette
[v
+ 1]),
905 c6_to_8(s
->palette
[v
+ 2]));
906 if (col
!= palette
[i
]) {
914 /* return true if the palette was modified */
915 static int update_palette256(VGAState
*s
)
918 uint32_t v
, col
, *palette
;
921 palette
= s
->last_palette
;
923 for(i
= 0; i
< 256; i
++) {
924 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
925 c6_to_8(s
->palette
[v
+ 1]),
926 c6_to_8(s
->palette
[v
+ 2]));
927 if (col
!= palette
[i
]) {
936 static void vga_get_offsets(VGAState
*s
,
937 uint32_t *pline_offset
,
938 uint32_t *pstart_addr
,
939 uint32_t *pline_compare
)
941 uint32_t start_addr
, line_offset
, line_compare
;
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
;
946 line_compare
= 65535;
950 /* compute line_offset in bytes */
951 line_offset
= s
->cr
[0x13];
954 /* starting address */
955 start_addr
= s
->cr
[0x0d] | (s
->cr
[0x0c] << 8);
958 line_compare
= s
->cr
[0x18] |
959 ((s
->cr
[0x07] & 0x10) << 4) |
960 ((s
->cr
[0x09] & 0x40) << 3);
962 *pline_offset
= line_offset
;
963 *pstart_addr
= start_addr
;
964 *pline_compare
= line_compare
;
967 /* update start_addr and line_offset. Return TRUE if modified */
968 static int update_basic_params(VGAState
*s
)
971 uint32_t start_addr
, line_offset
, line_compare
;
975 s
->get_offsets(s
, &line_offset
, &start_addr
, &line_compare
);
977 if (line_offset
!= s
->line_offset
||
978 start_addr
!= s
->start_addr
||
979 line_compare
!= s
->line_compare
) {
980 s
->line_offset
= line_offset
;
981 s
->start_addr
= start_addr
;
982 s
->line_compare
= line_compare
;
990 static inline int get_depth_index(DisplayState
*s
)
1008 static vga_draw_glyph8_func
*vga_draw_glyph8_table
[NB_DEPTHS
] = {
1016 static vga_draw_glyph8_func
*vga_draw_glyph16_table
[NB_DEPTHS
] = {
1018 vga_draw_glyph16_16
,
1019 vga_draw_glyph16_16
,
1020 vga_draw_glyph16_32
,
1021 vga_draw_glyph16_32
,
1024 static vga_draw_glyph9_func
*vga_draw_glyph9_table
[NB_DEPTHS
] = {
1032 static const uint8_t cursor_glyph
[32 * 4] = {
1033 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
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,
1059 static void vga_draw_text(VGAState
*s
, int full_update
)
1061 int cx
, cy
, cheight
, cw
, ch
, cattr
, height
, width
, ch_attr
;
1062 int cx_min
, cx_max
, linesize
, x_incr
;
1063 uint32_t offset
, fgcol
, bgcol
, v
, cursor_offset
;
1064 uint8_t *d1
, *d
, *src
, *s1
, *dest
, *cursor_ptr
;
1065 const uint8_t *font_ptr
, *font_base
[2];
1066 int dup9
, line_offset
, depth_index
;
1068 uint32_t *ch_attr_ptr
;
1069 vga_draw_glyph8_func
*vga_draw_glyph8
;
1070 vga_draw_glyph9_func
*vga_draw_glyph9
;
1072 full_update
|= update_palette16(s
);
1073 palette
= s
->last_palette
;
1075 /* compute font data address (in plane 2) */
1077 offset
= (((v
>> 4) & 1) | ((v
<< 1) & 6)) * 8192 * 4 + 2;
1078 if (offset
!= s
->font_offsets
[0]) {
1079 s
->font_offsets
[0] = offset
;
1082 font_base
[0] = s
->vram_ptr
+ offset
;
1084 offset
= (((v
>> 5) & 1) | ((v
>> 1) & 6)) * 8192 * 4 + 2;
1085 font_base
[1] = s
->vram_ptr
+ offset
;
1086 if (offset
!= s
->font_offsets
[1]) {
1087 s
->font_offsets
[1] = offset
;
1090 if (s
->plane_updated
& (1 << 2)) {
1091 /* if the plane 2 was modified since the last display, it
1092 indicates the font may have been modified */
1093 s
->plane_updated
= 0;
1096 full_update
|= update_basic_params(s
);
1098 line_offset
= s
->line_offset
;
1099 s1
= s
->vram_ptr
+ (s
->start_addr
* 4);
1101 /* total width & height */
1102 cheight
= (s
->cr
[9] & 0x1f) + 1;
1104 if (!(s
->sr
[1] & 0x01))
1106 if (s
->sr
[1] & 0x08)
1107 cw
= 16; /* NOTE: no 18 pixel wide */
1108 x_incr
= cw
* ((s
->ds
->depth
+ 7) >> 3);
1109 width
= (s
->cr
[0x01] + 1);
1110 if (s
->cr
[0x06] == 100) {
1111 /* ugly hack for CGA 160x100x16 - explain me the logic */
1114 height
= s
->cr
[0x12] |
1115 ((s
->cr
[0x07] & 0x02) << 7) |
1116 ((s
->cr
[0x07] & 0x40) << 3);
1117 height
= (height
+ 1) / cheight
;
1119 if ((height
* width
) > CH_ATTR_SIZE
) {
1120 /* better than nothing: exit if transient size is too big */
1124 if (width
!= s
->last_width
|| height
!= s
->last_height
||
1125 cw
!= s
->last_cw
|| cheight
!= s
->last_ch
) {
1126 s
->last_scr_width
= width
* cw
;
1127 s
->last_scr_height
= height
* cheight
;
1128 dpy_resize(s
->ds
, s
->last_scr_width
, s
->last_scr_height
);
1129 s
->last_width
= width
;
1130 s
->last_height
= height
;
1131 s
->last_ch
= cheight
;
1135 cursor_offset
= ((s
->cr
[0x0e] << 8) | s
->cr
[0x0f]) - s
->start_addr
;
1136 if (cursor_offset
!= s
->cursor_offset
||
1137 s
->cr
[0xa] != s
->cursor_start
||
1138 s
->cr
[0xb] != s
->cursor_end
) {
1139 /* if the cursor position changed, we update the old and new
1141 if (s
->cursor_offset
< CH_ATTR_SIZE
)
1142 s
->last_ch_attr
[s
->cursor_offset
] = -1;
1143 if (cursor_offset
< CH_ATTR_SIZE
)
1144 s
->last_ch_attr
[cursor_offset
] = -1;
1145 s
->cursor_offset
= cursor_offset
;
1146 s
->cursor_start
= s
->cr
[0xa];
1147 s
->cursor_end
= s
->cr
[0xb];
1149 cursor_ptr
= s
->vram_ptr
+ (s
->start_addr
+ cursor_offset
) * 4;
1151 depth_index
= get_depth_index(s
->ds
);
1153 vga_draw_glyph8
= vga_draw_glyph16_table
[depth_index
];
1155 vga_draw_glyph8
= vga_draw_glyph8_table
[depth_index
];
1156 vga_draw_glyph9
= vga_draw_glyph9_table
[depth_index
];
1159 linesize
= s
->ds
->linesize
;
1160 ch_attr_ptr
= s
->last_ch_attr
;
1161 for(cy
= 0; cy
< height
; cy
++) {
1166 for(cx
= 0; cx
< width
; cx
++) {
1167 ch_attr
= *(uint16_t *)src
;
1168 if (full_update
|| ch_attr
!= *ch_attr_ptr
) {
1173 *ch_attr_ptr
= ch_attr
;
1174 #ifdef WORDS_BIGENDIAN
1176 cattr
= ch_attr
& 0xff;
1178 ch
= ch_attr
& 0xff;
1179 cattr
= ch_attr
>> 8;
1181 font_ptr
= font_base
[(cattr
>> 3) & 1];
1182 font_ptr
+= 32 * 4 * ch
;
1183 bgcol
= palette
[cattr
>> 4];
1184 fgcol
= palette
[cattr
& 0x0f];
1186 vga_draw_glyph8(d1
, linesize
,
1187 font_ptr
, cheight
, fgcol
, bgcol
);
1190 if (ch
>= 0xb0 && ch
<= 0xdf && (s
->ar
[0x10] & 0x04))
1192 vga_draw_glyph9(d1
, linesize
,
1193 font_ptr
, cheight
, fgcol
, bgcol
, dup9
);
1195 if (src
== cursor_ptr
&&
1196 !(s
->cr
[0x0a] & 0x20)) {
1197 int line_start
, line_last
, h
;
1198 /* draw the cursor */
1199 line_start
= s
->cr
[0x0a] & 0x1f;
1200 line_last
= s
->cr
[0x0b] & 0x1f;
1201 /* XXX: check that */
1202 if (line_last
> cheight
- 1)
1203 line_last
= cheight
- 1;
1204 if (line_last
>= line_start
&& line_start
< cheight
) {
1205 h
= line_last
- line_start
+ 1;
1206 d
= d1
+ linesize
* line_start
;
1208 vga_draw_glyph8(d
, linesize
,
1209 cursor_glyph
, h
, fgcol
, bgcol
);
1211 vga_draw_glyph9(d
, linesize
,
1212 cursor_glyph
, h
, fgcol
, bgcol
, 1);
1222 dpy_update(s
->ds
, cx_min
* cw
, cy
* cheight
,
1223 (cx_max
- cx_min
+ 1) * cw
, cheight
);
1225 dest
+= linesize
* cheight
;
1244 static vga_draw_line_func
*vga_draw_line_table
[NB_DEPTHS
* VGA_DRAW_LINE_NB
] = {
1252 vga_draw_line2d2_16
,
1253 vga_draw_line2d2_16
,
1254 vga_draw_line2d2_32
,
1255 vga_draw_line2d2_32
,
1264 vga_draw_line4d2_16
,
1265 vga_draw_line4d2_16
,
1266 vga_draw_line4d2_32
,
1267 vga_draw_line4d2_32
,
1270 vga_draw_line8d2_16
,
1271 vga_draw_line8d2_16
,
1272 vga_draw_line8d2_32
,
1273 vga_draw_line8d2_32
,
1285 vga_draw_line15_32bgr
,
1291 vga_draw_line16_32bgr
,
1297 vga_draw_line24_32bgr
,
1303 vga_draw_line32_32bgr
,
1306 typedef unsigned int rgb_to_pixel_dup_func(unsigned int r
, unsigned int g
, unsigned b
);
1308 static rgb_to_pixel_dup_func
*rgb_to_pixel_dup_table
[NB_DEPTHS
] = {
1313 rgb_to_pixel32bgr_dup
,
1316 static int vga_get_bpp(VGAState
*s
)
1319 #ifdef CONFIG_BOCHS_VBE
1320 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1321 ret
= s
->vbe_regs
[VBE_DISPI_INDEX_BPP
];
1330 static void vga_get_resolution(VGAState
*s
, int *pwidth
, int *pheight
)
1334 #ifdef CONFIG_BOCHS_VBE
1335 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1336 width
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
];
1337 height
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
];
1341 width
= (s
->cr
[0x01] + 1) * 8;
1342 height
= s
->cr
[0x12] |
1343 ((s
->cr
[0x07] & 0x02) << 7) |
1344 ((s
->cr
[0x07] & 0x40) << 3);
1345 height
= (height
+ 1);
1351 void vga_invalidate_scanlines(VGAState
*s
, int y1
, int y2
)
1354 if (y1
>= VGA_MAX_HEIGHT
)
1356 if (y2
>= VGA_MAX_HEIGHT
)
1357 y2
= VGA_MAX_HEIGHT
;
1358 for(y
= y1
; y
< y2
; y
++) {
1359 s
->invalidated_y_table
[y
>> 5] |= 1 << (y
& 0x1f);
1366 static void vga_draw_graphic(VGAState
*s
, int full_update
)
1368 int y1
, y
, update
, page_min
, page_max
, linesize
, y_start
, double_scan
, mask
;
1369 int width
, height
, shift_control
, line_offset
, page0
, page1
, bwidth
;
1370 int disp_width
, multi_scan
, multi_run
;
1372 uint32_t v
, addr1
, addr
;
1373 vga_draw_line_func
*vga_draw_line
;
1375 full_update
|= update_basic_params(s
);
1377 s
->get_resolution(s
, &width
, &height
);
1380 shift_control
= (s
->gr
[0x05] >> 5) & 3;
1381 double_scan
= (s
->cr
[0x09] >> 7);
1382 if (shift_control
!= 1) {
1383 multi_scan
= (((s
->cr
[0x09] & 0x1f) + 1) << double_scan
) - 1;
1385 /* in CGA modes, multi_scan is ignored */
1386 /* XXX: is it correct ? */
1387 multi_scan
= double_scan
;
1389 multi_run
= multi_scan
;
1390 if (shift_control
!= s
->shift_control
||
1391 double_scan
!= s
->double_scan
) {
1393 s
->shift_control
= shift_control
;
1394 s
->double_scan
= double_scan
;
1397 if (shift_control
== 0) {
1398 full_update
|= update_palette16(s
);
1399 if (s
->sr
[0x01] & 8) {
1400 v
= VGA_DRAW_LINE4D2
;
1405 } else if (shift_control
== 1) {
1406 full_update
|= update_palette16(s
);
1407 if (s
->sr
[0x01] & 8) {
1408 v
= VGA_DRAW_LINE2D2
;
1414 switch(s
->get_bpp(s
)) {
1417 full_update
|= update_palette256(s
);
1418 v
= VGA_DRAW_LINE8D2
;
1421 full_update
|= update_palette256(s
);
1425 v
= VGA_DRAW_LINE15
;
1428 v
= VGA_DRAW_LINE16
;
1431 v
= VGA_DRAW_LINE24
;
1434 v
= VGA_DRAW_LINE32
;
1438 vga_draw_line
= vga_draw_line_table
[v
* NB_DEPTHS
+ get_depth_index(s
->ds
)];
1440 if (disp_width
!= s
->last_width
||
1441 height
!= s
->last_height
) {
1442 dpy_resize(s
->ds
, disp_width
, height
);
1443 s
->last_scr_width
= disp_width
;
1444 s
->last_scr_height
= height
;
1445 s
->last_width
= disp_width
;
1446 s
->last_height
= height
;
1449 if (s
->cursor_invalidate
)
1450 s
->cursor_invalidate(s
);
1452 line_offset
= s
->line_offset
;
1454 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",
1455 width
, height
, v
, line_offset
, s
->cr
[9], s
->cr
[0x17], s
->line_compare
, s
->sr
[0x01]);
1457 addr1
= (s
->start_addr
* 4);
1460 page_min
= 0x7fffffff;
1463 linesize
= s
->ds
->linesize
;
1465 for(y
= 0; y
< height
; y
++) {
1467 if (!(s
->cr
[0x17] & 1)) {
1469 /* CGA compatibility handling */
1470 shift
= 14 + ((s
->cr
[0x17] >> 6) & 1);
1471 addr
= (addr
& ~(1 << shift
)) | ((y1
& 1) << shift
);
1473 if (!(s
->cr
[0x17] & 2)) {
1474 addr
= (addr
& ~0x8000) | ((y1
& 2) << 14);
1476 page0
= s
->vram_offset
+ (addr
& TARGET_PAGE_MASK
);
1477 page1
= s
->vram_offset
+ ((addr
+ bwidth
- 1) & TARGET_PAGE_MASK
);
1478 update
= full_update
|
1479 cpu_physical_memory_get_dirty(page0
, VGA_DIRTY_FLAG
) |
1480 cpu_physical_memory_get_dirty(page1
, VGA_DIRTY_FLAG
);
1481 if ((page1
- page0
) > TARGET_PAGE_SIZE
) {
1482 /* if wide line, can use another page */
1483 update
|= cpu_physical_memory_get_dirty(page0
+ TARGET_PAGE_SIZE
,
1486 /* explicit invalidation for the hardware cursor */
1487 update
|= (s
->invalidated_y_table
[y
>> 5] >> (y
& 0x1f)) & 1;
1491 if (page0
< page_min
)
1493 if (page1
> page_max
)
1495 vga_draw_line(s
, d
, s
->vram_ptr
+ addr
, width
);
1496 if (s
->cursor_draw_line
)
1497 s
->cursor_draw_line(s
, d
, y
);
1500 /* flush to display */
1501 dpy_update(s
->ds
, 0, y_start
,
1502 disp_width
, y
- y_start
);
1507 mask
= (s
->cr
[0x17] & 3) ^ 3;
1508 if ((y1
& mask
) == mask
)
1509 addr1
+= line_offset
;
1511 multi_run
= multi_scan
;
1515 /* line compare acts on the displayed lines */
1516 if (y
== s
->line_compare
)
1521 /* flush to display */
1522 dpy_update(s
->ds
, 0, y_start
,
1523 disp_width
, y
- y_start
);
1525 /* reset modified pages */
1526 if (page_max
!= -1) {
1527 cpu_physical_memory_reset_dirty(page_min
, page_max
+ TARGET_PAGE_SIZE
,
1530 memset(s
->invalidated_y_table
, 0, ((height
+ 31) >> 5) * 4);
1533 static void vga_draw_blank(VGAState
*s
, int full_update
)
1540 if (s
->last_scr_width
<= 0 || s
->last_scr_height
<= 0)
1542 if (s
->ds
->depth
== 8)
1543 val
= s
->rgb_to_pixel(0, 0, 0);
1546 w
= s
->last_scr_width
* ((s
->ds
->depth
+ 7) >> 3);
1548 for(i
= 0; i
< s
->last_scr_height
; i
++) {
1550 d
+= s
->ds
->linesize
;
1552 dpy_update(s
->ds
, 0, 0,
1553 s
->last_scr_width
, s
->last_scr_height
);
1556 #define GMODE_TEXT 0
1557 #define GMODE_GRAPH 1
1558 #define GMODE_BLANK 2
1560 static void vga_update_display(void *opaque
)
1562 VGAState
*s
= (VGAState
*)opaque
;
1563 int full_update
, graphic_mode
;
1565 if (s
->ds
->depth
== 0) {
1569 rgb_to_pixel_dup_table
[get_depth_index(s
->ds
)];
1572 if (!(s
->ar_index
& 0x20)) {
1573 graphic_mode
= GMODE_BLANK
;
1575 graphic_mode
= s
->gr
[6] & 1;
1577 if (graphic_mode
!= s
->graphic_mode
) {
1578 s
->graphic_mode
= graphic_mode
;
1581 switch(graphic_mode
) {
1583 vga_draw_text(s
, full_update
);
1586 vga_draw_graphic(s
, full_update
);
1590 vga_draw_blank(s
, full_update
);
1596 /* force a full display refresh */
1597 static void vga_invalidate_display(void *opaque
)
1599 VGAState
*s
= (VGAState
*)opaque
;
1602 s
->last_height
= -1;
1605 static void vga_reset(VGAState
*s
)
1607 memset(s
, 0, sizeof(VGAState
));
1608 s
->graphic_mode
= -1; /* force full update */
1611 static CPUReadMemoryFunc
*vga_mem_read
[3] = {
1617 static CPUWriteMemoryFunc
*vga_mem_write
[3] = {
1623 static void vga_save(QEMUFile
*f
, void *opaque
)
1625 VGAState
*s
= opaque
;
1629 pci_device_save(s
->pci_dev
, f
);
1631 qemu_put_be32s(f
, &s
->latch
);
1632 qemu_put_8s(f
, &s
->sr_index
);
1633 qemu_put_buffer(f
, s
->sr
, 8);
1634 qemu_put_8s(f
, &s
->gr_index
);
1635 qemu_put_buffer(f
, s
->gr
, 16);
1636 qemu_put_8s(f
, &s
->ar_index
);
1637 qemu_put_buffer(f
, s
->ar
, 21);
1638 qemu_put_be32s(f
, &s
->ar_flip_flop
);
1639 qemu_put_8s(f
, &s
->cr_index
);
1640 qemu_put_buffer(f
, s
->cr
, 256);
1641 qemu_put_8s(f
, &s
->msr
);
1642 qemu_put_8s(f
, &s
->fcr
);
1643 qemu_put_8s(f
, &s
->st00
);
1644 qemu_put_8s(f
, &s
->st01
);
1646 qemu_put_8s(f
, &s
->dac_state
);
1647 qemu_put_8s(f
, &s
->dac_sub_index
);
1648 qemu_put_8s(f
, &s
->dac_read_index
);
1649 qemu_put_8s(f
, &s
->dac_write_index
);
1650 qemu_put_buffer(f
, s
->dac_cache
, 3);
1651 qemu_put_buffer(f
, s
->palette
, 768);
1653 qemu_put_be32s(f
, &s
->bank_offset
);
1654 #ifdef CONFIG_BOCHS_VBE
1655 qemu_put_byte(f
, 1);
1656 qemu_put_be16s(f
, &s
->vbe_index
);
1657 for(i
= 0; i
< VBE_DISPI_INDEX_NB
; i
++)
1658 qemu_put_be16s(f
, &s
->vbe_regs
[i
]);
1659 qemu_put_be32s(f
, &s
->vbe_start_addr
);
1660 qemu_put_be32s(f
, &s
->vbe_line_offset
);
1661 qemu_put_be32s(f
, &s
->vbe_bank_mask
);
1663 qemu_put_byte(f
, 0);
1667 static int vga_load(QEMUFile
*f
, void *opaque
, int version_id
)
1669 VGAState
*s
= opaque
;
1675 if (s
->pci_dev
&& version_id
>= 2) {
1676 ret
= pci_device_load(s
->pci_dev
, f
);
1681 qemu_get_be32s(f
, &s
->latch
);
1682 qemu_get_8s(f
, &s
->sr_index
);
1683 qemu_get_buffer(f
, s
->sr
, 8);
1684 qemu_get_8s(f
, &s
->gr_index
);
1685 qemu_get_buffer(f
, s
->gr
, 16);
1686 qemu_get_8s(f
, &s
->ar_index
);
1687 qemu_get_buffer(f
, s
->ar
, 21);
1688 qemu_get_be32s(f
, &s
->ar_flip_flop
);
1689 qemu_get_8s(f
, &s
->cr_index
);
1690 qemu_get_buffer(f
, s
->cr
, 256);
1691 qemu_get_8s(f
, &s
->msr
);
1692 qemu_get_8s(f
, &s
->fcr
);
1693 qemu_get_8s(f
, &s
->st00
);
1694 qemu_get_8s(f
, &s
->st01
);
1696 qemu_get_8s(f
, &s
->dac_state
);
1697 qemu_get_8s(f
, &s
->dac_sub_index
);
1698 qemu_get_8s(f
, &s
->dac_read_index
);
1699 qemu_get_8s(f
, &s
->dac_write_index
);
1700 qemu_get_buffer(f
, s
->dac_cache
, 3);
1701 qemu_get_buffer(f
, s
->palette
, 768);
1703 qemu_get_be32s(f
, &s
->bank_offset
);
1704 is_vbe
= qemu_get_byte(f
);
1705 #ifdef CONFIG_BOCHS_VBE
1708 qemu_get_be16s(f
, &s
->vbe_index
);
1709 for(i
= 0; i
< VBE_DISPI_INDEX_NB
; i
++)
1710 qemu_get_be16s(f
, &s
->vbe_regs
[i
]);
1711 qemu_get_be32s(f
, &s
->vbe_start_addr
);
1712 qemu_get_be32s(f
, &s
->vbe_line_offset
);
1713 qemu_get_be32s(f
, &s
->vbe_bank_mask
);
1720 s
->graphic_mode
= -1;
1724 typedef struct PCIVGAState
{
1729 static void vga_map(PCIDevice
*pci_dev
, int region_num
,
1730 uint32_t addr
, uint32_t size
, int type
)
1732 PCIVGAState
*d
= (PCIVGAState
*)pci_dev
;
1733 VGAState
*s
= &d
->vga_state
;
1734 if (region_num
== PCI_ROM_SLOT
) {
1735 cpu_register_physical_memory(addr
, s
->bios_size
, s
->bios_offset
);
1737 cpu_register_physical_memory(addr
, s
->vram_size
, s
->vram_offset
);
1741 void vga_common_init(VGAState
*s
, DisplayState
*ds
, uint8_t *vga_ram_base
,
1742 unsigned long vga_ram_offset
, int vga_ram_size
)
1746 for(i
= 0;i
< 256; i
++) {
1748 for(j
= 0; j
< 8; j
++) {
1749 v
|= ((i
>> j
) & 1) << (j
* 4);
1754 for(j
= 0; j
< 4; j
++) {
1755 v
|= ((i
>> (2 * j
)) & 3) << (j
* 4);
1759 for(i
= 0; i
< 16; i
++) {
1761 for(j
= 0; j
< 4; j
++) {
1764 v
|= b
<< (2 * j
+ 1);
1771 s
->vram_ptr
= vga_ram_base
;
1772 s
->vram_offset
= vga_ram_offset
;
1773 s
->vram_size
= vga_ram_size
;
1775 s
->get_bpp
= vga_get_bpp
;
1776 s
->get_offsets
= vga_get_offsets
;
1777 s
->get_resolution
= vga_get_resolution
;
1778 graphic_console_init(s
->ds
, vga_update_display
, vga_invalidate_display
,
1779 vga_screen_dump
, s
);
1782 /* used by both ISA and PCI */
1783 static void vga_init(VGAState
*s
)
1787 register_savevm("vga", 0, 2, vga_save
, vga_load
, s
);
1789 register_ioport_write(0x3c0, 16, 1, vga_ioport_write
, s
);
1791 register_ioport_write(0x3b4, 2, 1, vga_ioport_write
, s
);
1792 register_ioport_write(0x3d4, 2, 1, vga_ioport_write
, s
);
1793 register_ioport_write(0x3ba, 1, 1, vga_ioport_write
, s
);
1794 register_ioport_write(0x3da, 1, 1, vga_ioport_write
, s
);
1796 register_ioport_read(0x3c0, 16, 1, vga_ioport_read
, s
);
1798 register_ioport_read(0x3b4, 2, 1, vga_ioport_read
, s
);
1799 register_ioport_read(0x3d4, 2, 1, vga_ioport_read
, s
);
1800 register_ioport_read(0x3ba, 1, 1, vga_ioport_read
, s
);
1801 register_ioport_read(0x3da, 1, 1, vga_ioport_read
, s
);
1804 #ifdef CONFIG_BOCHS_VBE
1805 s
->vbe_regs
[VBE_DISPI_INDEX_ID
] = VBE_DISPI_ID0
;
1806 s
->vbe_bank_mask
= ((s
->vram_size
>> 16) - 1);
1807 #if defined (TARGET_I386)
1808 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index
, s
);
1809 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data
, s
);
1811 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index
, s
);
1812 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data
, s
);
1814 /* old Bochs IO ports */
1815 register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index
, s
);
1816 register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data
, s
);
1818 register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index
, s
);
1819 register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data
, s
);
1821 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index
, s
);
1822 register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data
, s
);
1824 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index
, s
);
1825 register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data
, s
);
1827 #endif /* CONFIG_BOCHS_VBE */
1829 vga_io_memory
= cpu_register_io_memory(0, vga_mem_read
, vga_mem_write
, s
);
1830 cpu_register_physical_memory(isa_mem_base
+ 0x000a0000, 0x20000,
1834 int isa_vga_init(DisplayState
*ds
, uint8_t *vga_ram_base
,
1835 unsigned long vga_ram_offset
, int vga_ram_size
)
1839 s
= qemu_mallocz(sizeof(VGAState
));
1843 vga_common_init(s
, ds
, vga_ram_base
, vga_ram_offset
, vga_ram_size
);
1846 #ifdef CONFIG_BOCHS_VBE
1847 /* XXX: use optimized standard vga accesses */
1848 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS
,
1849 vga_ram_size
, vga_ram_offset
);
1854 int pci_vga_init(PCIBus
*bus
, DisplayState
*ds
, uint8_t *vga_ram_base
,
1855 unsigned long vga_ram_offset
, int vga_ram_size
,
1856 unsigned long vga_bios_offset
, int vga_bios_size
)
1862 d
= (PCIVGAState
*)pci_register_device(bus
, "VGA",
1863 sizeof(PCIVGAState
),
1869 vga_common_init(s
, ds
, vga_ram_base
, vga_ram_offset
, vga_ram_size
);
1871 s
->pci_dev
= &d
->dev
;
1873 pci_conf
= d
->dev
.config
;
1874 pci_conf
[0x00] = 0x34; // dummy VGA (same as Bochs ID)
1875 pci_conf
[0x01] = 0x12;
1876 pci_conf
[0x02] = 0x11;
1877 pci_conf
[0x03] = 0x11;
1878 pci_conf
[0x0a] = 0x00; // VGA controller
1879 pci_conf
[0x0b] = 0x03;
1880 pci_conf
[0x0e] = 0x00; // header_type
1882 /* XXX: vga_ram_size must be a power of two */
1883 pci_register_io_region(&d
->dev
, 0, vga_ram_size
,
1884 PCI_ADDRESS_SPACE_MEM_PREFETCH
, vga_map
);
1885 if (vga_bios_size
!= 0) {
1886 unsigned int bios_total_size
;
1887 s
->bios_offset
= vga_bios_offset
;
1888 s
->bios_size
= vga_bios_size
;
1889 /* must be a power of two */
1890 bios_total_size
= 1;
1891 while (bios_total_size
< vga_bios_size
)
1892 bios_total_size
<<= 1;
1893 pci_register_io_region(&d
->dev
, PCI_ROM_SLOT
, bios_total_size
,
1894 PCI_ADDRESS_SPACE_MEM_PREFETCH
, vga_map
);
1899 /********************************************************/
1900 /* vga screen dump */
1902 static int vga_save_w
, vga_save_h
;
1904 static void vga_save_dpy_update(DisplayState
*s
,
1905 int x
, int y
, int w
, int h
)
1909 static void vga_save_dpy_resize(DisplayState
*s
, int w
, int h
)
1911 s
->linesize
= w
* 4;
1912 s
->data
= qemu_malloc(h
* s
->linesize
);
1917 static void vga_save_dpy_refresh(DisplayState
*s
)
1921 static int ppm_save(const char *filename
, uint8_t *data
,
1922 int w
, int h
, int linesize
)
1929 f
= fopen(filename
, "wb");
1932 fprintf(f
, "P6\n%d %d\n%d\n",
1935 for(y
= 0; y
< h
; y
++) {
1937 for(x
= 0; x
< w
; x
++) {
1939 fputc((v
>> 16) & 0xff, f
);
1940 fputc((v
>> 8) & 0xff, f
);
1941 fputc((v
) & 0xff, f
);
1950 /* save the vga display in a PPM image even if no display is
1952 static void vga_screen_dump(void *opaque
, const char *filename
)
1954 VGAState
*s
= (VGAState
*)opaque
;
1955 DisplayState
*saved_ds
, ds1
, *ds
= &ds1
;
1957 /* XXX: this is a little hackish */
1958 vga_invalidate_display(s
);
1961 memset(ds
, 0, sizeof(DisplayState
));
1962 ds
->dpy_update
= vga_save_dpy_update
;
1963 ds
->dpy_resize
= vga_save_dpy_resize
;
1964 ds
->dpy_refresh
= vga_save_dpy_refresh
;
1968 s
->graphic_mode
= -1;
1969 vga_update_display(s
);
1972 ppm_save(filename
, ds
->data
, vga_save_w
, vga_save_h
,
1974 qemu_free(ds
->data
);