4 * Copyright (c) 2003 Fabrice Bellard
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 //#define DEBUG_VGA_MEM
28 //#define DEBUG_VGA_REG
31 //#define DEBUG_BOCHS_VBE
33 /* S3 VGA is deprecated - another graphic card will be emulated */
34 //#define CONFIG_S3VGA
36 #define MSR_COLOR_EMULATION 0x01
37 #define MSR_PAGE_SELECT 0x20
39 #define ST01_V_RETRACE 0x08
40 #define ST01_DISP_ENABLE 0x01
42 /* bochs VBE support */
43 #define CONFIG_BOCHS_VBE
45 #define VBE_DISPI_MAX_XRES 1024
46 #define VBE_DISPI_MAX_YRES 768
48 #define VBE_DISPI_INDEX_ID 0x0
49 #define VBE_DISPI_INDEX_XRES 0x1
50 #define VBE_DISPI_INDEX_YRES 0x2
51 #define VBE_DISPI_INDEX_BPP 0x3
52 #define VBE_DISPI_INDEX_ENABLE 0x4
53 #define VBE_DISPI_INDEX_BANK 0x5
54 #define VBE_DISPI_INDEX_VIRT_WIDTH 0x6
55 #define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
56 #define VBE_DISPI_INDEX_X_OFFSET 0x8
57 #define VBE_DISPI_INDEX_Y_OFFSET 0x9
58 #define VBE_DISPI_INDEX_NB 0xa
60 #define VBE_DISPI_ID0 0xB0C0
61 #define VBE_DISPI_ID1 0xB0C1
62 #define VBE_DISPI_ID2 0xB0C2
64 #define VBE_DISPI_DISABLED 0x00
65 #define VBE_DISPI_ENABLED 0x01
66 #define VBE_DISPI_LFB_ENABLED 0x40
67 #define VBE_DISPI_NOCLEARMEM 0x80
69 #define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000
71 typedef struct VGAState
{
73 unsigned long vram_offset
;
74 unsigned int vram_size
;
84 uint8_t cr
[256]; /* CRT registers */
85 uint8_t msr
; /* Misc Output Register */
86 uint8_t fcr
; /* Feature Control Register */
87 uint8_t st00
; /* status 0 */
88 uint8_t st01
; /* status 1 */
90 uint8_t dac_sub_index
;
91 uint8_t dac_read_index
;
92 uint8_t dac_write_index
;
93 uint8_t dac_cache
[3]; /* used when writing */
96 #ifdef CONFIG_BOCHS_VBE
98 uint16_t vbe_regs
[VBE_DISPI_INDEX_NB
];
99 uint32_t vbe_start_addr
;
100 uint32_t vbe_line_offset
;
101 uint32_t vbe_bank_mask
;
103 /* display refresh support */
105 uint32_t font_offsets
[2];
107 uint8_t shift_control
;
109 uint32_t line_offset
;
110 uint32_t line_compare
;
112 uint8_t last_cw
, last_ch
;
113 uint32_t last_width
, last_height
; /* in chars or pixels */
114 uint32_t last_scr_width
, last_scr_height
; /* in pixels */
115 uint8_t cursor_start
, cursor_end
;
116 uint32_t cursor_offset
;
117 unsigned int (*rgb_to_pixel
)(unsigned int r
, unsigned int g
, unsigned b
);
118 /* tell for each page if it has been updated since the last time */
119 uint32_t last_palette
[256];
120 #define CH_ATTR_SIZE (160 * 100)
121 uint32_t last_ch_attr
[CH_ATTR_SIZE
]; /* XXX: make it dynamic */
124 /* force some bits to zero */
125 static const uint8_t sr_mask
[8] = {
136 static const uint8_t gr_mask
[16] = {
137 (uint8_t)~0xf0, /* 0x00 */
138 (uint8_t)~0xf0, /* 0x01 */
139 (uint8_t)~0xf0, /* 0x02 */
140 (uint8_t)~0xe0, /* 0x03 */
141 (uint8_t)~0xfc, /* 0x04 */
142 (uint8_t)~0x84, /* 0x05 */
143 (uint8_t)~0xf0, /* 0x06 */
144 (uint8_t)~0xf0, /* 0x07 */
145 (uint8_t)~0x00, /* 0x08 */
146 (uint8_t)~0xff, /* 0x09 */
147 (uint8_t)~0xff, /* 0x0a */
148 (uint8_t)~0xff, /* 0x0b */
149 (uint8_t)~0xff, /* 0x0c */
150 (uint8_t)~0xff, /* 0x0d */
151 (uint8_t)~0xff, /* 0x0e */
152 (uint8_t)~0xff, /* 0x0f */
155 #define cbswap_32(__x) \
157 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
158 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
159 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
160 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
162 #ifdef WORDS_BIGENDIAN
163 #define PAT(x) cbswap_32(x)
168 #ifdef WORDS_BIGENDIAN
174 #ifdef WORDS_BIGENDIAN
175 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
177 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
180 static const uint32_t mask16
[16] = {
201 #ifdef WORDS_BIGENDIAN
204 #define PAT(x) cbswap_32(x)
207 static const uint32_t dmask16
[16] = {
226 static const uint32_t dmask4
[4] = {
233 static uint32_t expand4
[256];
234 static uint16_t expand2
[256];
235 static uint8_t expand4to8
[16];
240 static uint32_t vga_ioport_read(void *opaque
, uint32_t addr
)
242 VGAState
*s
= opaque
;
245 /* check port range access depending on color/monochrome mode */
246 if ((addr
>= 0x3b0 && addr
<= 0x3bf && (s
->msr
& MSR_COLOR_EMULATION
)) ||
247 (addr
>= 0x3d0 && addr
<= 0x3df && !(s
->msr
& MSR_COLOR_EMULATION
))) {
252 if (s
->ar_flip_flop
== 0) {
259 index
= s
->ar_index
& 0x1f;
272 val
= s
->sr
[s
->sr_index
];
274 printf("vga: read SR%x = 0x%02x\n", s
->sr_index
, val
);
281 val
= s
->palette
[s
->dac_read_index
* 3 + s
->dac_sub_index
];
282 if (++s
->dac_sub_index
== 3) {
283 s
->dac_sub_index
= 0;
297 val
= s
->gr
[s
->gr_index
];
299 printf("vga: read GR%x = 0x%02x\n", s
->gr_index
, val
);
308 val
= s
->cr
[s
->cr_index
];
310 printf("vga: read CR%x = 0x%02x\n", s
->cr_index
, val
);
313 if (s
->cr_index
>= 0x20)
314 printf("S3: CR read index=0x%x val=0x%x\n",
320 /* just toggle to fool polling */
321 s
->st01
^= ST01_V_RETRACE
| ST01_DISP_ENABLE
;
330 #if defined(DEBUG_VGA)
331 printf("VGA: read addr=0x%04x data=0x%02x\n", addr
, val
);
336 static void vga_ioport_write(void *opaque
, uint32_t addr
, uint32_t val
)
338 VGAState
*s
= opaque
;
341 /* check port range access depending on color/monochrome mode */
342 if ((addr
>= 0x3b0 && addr
<= 0x3bf && (s
->msr
& MSR_COLOR_EMULATION
)) ||
343 (addr
>= 0x3d0 && addr
<= 0x3df && !(s
->msr
& MSR_COLOR_EMULATION
)))
347 printf("VGA: write addr=0x%04x data=0x%02x\n", addr
, val
);
352 if (s
->ar_flip_flop
== 0) {
356 index
= s
->ar_index
& 0x1f;
359 s
->ar
[index
] = val
& 0x3f;
362 s
->ar
[index
] = val
& ~0x10;
368 s
->ar
[index
] = val
& ~0xc0;
371 s
->ar
[index
] = val
& ~0xf0;
374 s
->ar
[index
] = val
& ~0xf0;
380 s
->ar_flip_flop
^= 1;
383 s
->msr
= val
& ~0x10;
386 s
->sr_index
= val
& 7;
390 printf("vga: write SR%x = 0x%02x\n", s
->sr_index
, val
);
392 s
->sr
[s
->sr_index
] = val
& sr_mask
[s
->sr_index
];
395 s
->dac_read_index
= val
;
396 s
->dac_sub_index
= 0;
400 s
->dac_write_index
= val
;
401 s
->dac_sub_index
= 0;
405 s
->dac_cache
[s
->dac_sub_index
] = val
;
406 if (++s
->dac_sub_index
== 3) {
407 memcpy(&s
->palette
[s
->dac_write_index
* 3], s
->dac_cache
, 3);
408 s
->dac_sub_index
= 0;
409 s
->dac_write_index
++;
413 s
->gr_index
= val
& 0x0f;
417 printf("vga: write GR%x = 0x%02x\n", s
->gr_index
, val
);
419 s
->gr
[s
->gr_index
] = val
& gr_mask
[s
->gr_index
];
428 printf("vga: write CR%x = 0x%02x\n", s
->cr_index
, val
);
430 /* handle CR0-7 protection */
431 if ((s
->cr
[11] & 0x80) && s
->cr_index
<= 7) {
432 /* can always write bit 4 of CR7 */
433 if (s
->cr_index
== 7)
434 s
->cr
[7] = (s
->cr
[7] & ~0x10) | (val
& 0x10);
437 switch(s
->cr_index
) {
438 case 0x01: /* horizontal display end */
443 case 0x12: /* veritcal display end */
444 s
->cr
[s
->cr_index
] = val
;
453 /* chip ID, cannot write */
456 /* update start address */
459 s
->cr
[s
->cr_index
] = val
;
461 s
->cr
[0x69] = (s
->cr
[69] & ~0x03) | v
;
465 /* update start address */
468 s
->cr
[s
->cr_index
] = val
;
470 s
->cr
[0x69] = (s
->cr
[69] & ~0x0c) | (v
<< 2);
475 s
->cr
[s
->cr_index
] = val
;
479 if (s
->cr_index
>= 0x20)
480 printf("S3: CR write index=0x%x val=0x%x\n",
491 #ifdef CONFIG_BOCHS_VBE
492 static uint32_t vbe_ioport_read(void *opaque
, uint32_t addr
)
494 VGAState
*s
= opaque
;
501 if (s
->vbe_index
<= VBE_DISPI_INDEX_NB
)
502 val
= s
->vbe_regs
[s
->vbe_index
];
505 #ifdef DEBUG_BOCHS_VBE
506 printf("VBE: read index=0x%x val=0x%x\n", s
->vbe_index
, val
);
512 static void vbe_ioport_write(void *opaque
, uint32_t addr
, uint32_t val
)
514 VGAState
*s
= opaque
;
519 } else if (s
->vbe_index
<= VBE_DISPI_INDEX_NB
) {
520 #ifdef DEBUG_BOCHS_VBE
521 printf("VBE: write index=0x%x val=0x%x\n", s
->vbe_index
, val
);
523 switch(s
->vbe_index
) {
524 case VBE_DISPI_INDEX_ID
:
525 if (val
== VBE_DISPI_ID0
||
526 val
== VBE_DISPI_ID1
||
527 val
== VBE_DISPI_ID2
) {
528 s
->vbe_regs
[s
->vbe_index
] = val
;
531 case VBE_DISPI_INDEX_XRES
:
532 if ((val
<= VBE_DISPI_MAX_XRES
) && ((val
& 7) == 0)) {
533 s
->vbe_regs
[s
->vbe_index
] = val
;
536 case VBE_DISPI_INDEX_YRES
:
537 if (val
<= VBE_DISPI_MAX_YRES
) {
538 s
->vbe_regs
[s
->vbe_index
] = val
;
541 case VBE_DISPI_INDEX_BPP
:
544 if (val
== 4 || val
== 8 || val
== 15 ||
545 val
== 16 || val
== 24 || val
== 32) {
546 s
->vbe_regs
[s
->vbe_index
] = val
;
549 case VBE_DISPI_INDEX_BANK
:
550 val
&= s
->vbe_bank_mask
;
551 s
->vbe_regs
[s
->vbe_index
] = val
;
552 s
->bank_offset
= (val
<< 16);
554 case VBE_DISPI_INDEX_ENABLE
:
555 if (val
& VBE_DISPI_ENABLED
) {
556 int h
, shift_control
;
558 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] =
559 s
->vbe_regs
[VBE_DISPI_INDEX_XRES
];
560 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_HEIGHT
] =
561 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
];
562 s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
] = 0;
563 s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
] = 0;
565 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
566 s
->vbe_line_offset
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 1;
568 s
->vbe_line_offset
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] *
569 ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
570 s
->vbe_start_addr
= 0;
572 /* clear the screen (should be done in BIOS) */
573 if (!(val
& VBE_DISPI_NOCLEARMEM
)) {
574 memset(s
->vram_ptr
, 0,
575 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] * s
->vbe_line_offset
);
578 /* we initialize the VGA graphic mode (should be done
580 s
->gr
[0x06] = (s
->gr
[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
581 s
->cr
[0x17] |= 3; /* no CGA modes */
582 s
->cr
[0x13] = s
->vbe_line_offset
>> 3;
584 s
->cr
[0x01] = (s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 3) - 1;
586 h
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] - 1;
588 s
->cr
[0x07] = (s
->cr
[0x07] & ~0x42) |
589 ((h
>> 7) & 0x02) | ((h
>> 3) & 0x40);
590 /* line compare to 1023 */
595 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
597 s
->sr
[0x01] &= ~8; /* no double line */
600 s
->sr
[4] |= 0x08; /* set chain 4 mode */
601 s
->sr
[2] |= 0x0f; /* activate all planes */
603 s
->gr
[0x05] = (s
->gr
[0x05] & ~0x60) | (shift_control
<< 5);
604 s
->cr
[0x09] &= ~0x9f; /* no double scan */
606 /* XXX: the bios should do that */
609 s
->vbe_regs
[s
->vbe_index
] = val
;
611 case VBE_DISPI_INDEX_VIRT_WIDTH
:
613 int w
, h
, line_offset
;
615 if (val
< s
->vbe_regs
[VBE_DISPI_INDEX_XRES
])
618 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
619 line_offset
= w
>> 1;
621 line_offset
= w
* ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
622 h
= s
->vram_size
/ line_offset
;
623 /* XXX: support weird bochs semantics ? */
624 if (h
< s
->vbe_regs
[VBE_DISPI_INDEX_YRES
])
626 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] = w
;
627 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_HEIGHT
] = h
;
628 s
->vbe_line_offset
= line_offset
;
631 case VBE_DISPI_INDEX_X_OFFSET
:
632 case VBE_DISPI_INDEX_Y_OFFSET
:
635 s
->vbe_regs
[s
->vbe_index
] = val
;
636 s
->vbe_start_addr
= s
->vbe_line_offset
* s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
];
637 x
= s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
];
638 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
639 s
->vbe_start_addr
+= x
>> 1;
641 s
->vbe_start_addr
+= x
* ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
642 s
->vbe_start_addr
>>= 2;
652 /* called for accesses between 0xa0000 and 0xc0000 */
653 static uint32_t vga_mem_readb(target_phys_addr_t addr
)
655 VGAState
*s
= &vga_state
;
656 int memory_map_mode
, plane
;
659 /* convert to VGA memory offset */
660 memory_map_mode
= (s
->gr
[6] >> 2) & 3;
662 switch(memory_map_mode
) {
668 addr
+= s
->bank_offset
;
683 if (s
->sr
[4] & 0x08) {
684 /* chain 4 mode : simplest access */
685 ret
= s
->vram_ptr
[addr
];
686 } else if (s
->gr
[5] & 0x10) {
687 /* odd/even mode (aka text mode mapping) */
688 plane
= (s
->gr
[4] & 2) | (addr
& 1);
689 ret
= s
->vram_ptr
[((addr
& ~1) << 1) | plane
];
691 /* standard VGA latched access */
692 s
->latch
= ((uint32_t *)s
->vram_ptr
)[addr
];
694 if (!(s
->gr
[5] & 0x08)) {
697 ret
= GET_PLANE(s
->latch
, plane
);
700 ret
= (s
->latch
^ mask16
[s
->gr
[2]]) & mask16
[s
->gr
[7]];
709 static uint32_t vga_mem_readw(target_phys_addr_t addr
)
712 v
= vga_mem_readb(addr
);
713 v
|= vga_mem_readb(addr
+ 1) << 8;
717 static uint32_t vga_mem_readl(target_phys_addr_t addr
)
720 v
= vga_mem_readb(addr
);
721 v
|= vga_mem_readb(addr
+ 1) << 8;
722 v
|= vga_mem_readb(addr
+ 2) << 16;
723 v
|= vga_mem_readb(addr
+ 3) << 24;
727 /* called for accesses between 0xa0000 and 0xc0000 */
728 static void vga_mem_writeb(target_phys_addr_t addr
, uint32_t val
)
730 VGAState
*s
= &vga_state
;
731 int memory_map_mode
, plane
, write_mode
, b
, func_select
;
732 uint32_t write_mask
, bit_mask
, set_mask
;
735 printf("vga: [0x%x] = 0x%02x\n", addr
, val
);
737 /* convert to VGA memory offset */
738 memory_map_mode
= (s
->gr
[6] >> 2) & 3;
740 switch(memory_map_mode
) {
746 addr
+= s
->bank_offset
;
761 if (s
->sr
[4] & 0x08) {
762 /* chain 4 mode : simplest access */
764 if (s
->sr
[2] & (1 << plane
)) {
765 s
->vram_ptr
[addr
] = val
;
767 printf("vga: chain4: [0x%x]\n", addr
);
769 cpu_physical_memory_set_dirty(s
->vram_offset
+ addr
);
771 } else if (s
->gr
[5] & 0x10) {
772 /* odd/even mode (aka text mode mapping) */
773 plane
= (s
->gr
[4] & 2) | (addr
& 1);
774 if (s
->sr
[2] & (1 << plane
)) {
775 addr
= ((addr
& ~1) << 1) | plane
;
776 s
->vram_ptr
[addr
] = val
;
778 printf("vga: odd/even: [0x%x]\n", addr
);
780 cpu_physical_memory_set_dirty(s
->vram_offset
+ addr
);
783 /* standard VGA latched access */
784 write_mode
= s
->gr
[5] & 3;
790 val
= ((val
>> b
) | (val
<< (8 - b
))) & 0xff;
794 /* apply set/reset mask */
795 set_mask
= mask16
[s
->gr
[1]];
796 val
= (val
& ~set_mask
) | (mask16
[s
->gr
[0]] & set_mask
);
803 val
= mask16
[val
& 0x0f];
809 val
= (val
>> b
) | (val
<< (8 - b
));
811 bit_mask
= s
->gr
[8] & val
;
812 val
= mask16
[s
->gr
[0]];
816 /* apply logical operation */
817 func_select
= s
->gr
[3] >> 3;
818 switch(func_select
) {
838 bit_mask
|= bit_mask
<< 8;
839 bit_mask
|= bit_mask
<< 16;
840 val
= (val
& bit_mask
) | (s
->latch
& ~bit_mask
);
843 /* mask data according to sr[2] */
844 write_mask
= mask16
[s
->sr
[2]];
845 ((uint32_t *)s
->vram_ptr
)[addr
] =
846 (((uint32_t *)s
->vram_ptr
)[addr
] & ~write_mask
) |
849 printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
850 addr
* 4, write_mask
, val
);
852 cpu_physical_memory_set_dirty(s
->vram_offset
+ (addr
<< 2));
856 static void vga_mem_writew(target_phys_addr_t addr
, uint32_t val
)
858 vga_mem_writeb(addr
, val
& 0xff);
859 vga_mem_writeb(addr
+ 1, (val
>> 8) & 0xff);
862 static void vga_mem_writel(target_phys_addr_t addr
, uint32_t val
)
864 vga_mem_writeb(addr
, val
& 0xff);
865 vga_mem_writeb(addr
+ 1, (val
>> 8) & 0xff);
866 vga_mem_writeb(addr
+ 2, (val
>> 16) & 0xff);
867 vga_mem_writeb(addr
+ 3, (val
>> 24) & 0xff);
870 typedef void vga_draw_glyph8_func(uint8_t *d
, int linesize
,
871 const uint8_t *font_ptr
, int h
,
872 uint32_t fgcol
, uint32_t bgcol
);
873 typedef void vga_draw_glyph9_func(uint8_t *d
, int linesize
,
874 const uint8_t *font_ptr
, int h
,
875 uint32_t fgcol
, uint32_t bgcol
, int dup9
);
876 typedef void vga_draw_line_func(VGAState
*s1
, uint8_t *d
,
877 const uint8_t *s
, int width
);
879 static inline unsigned int rgb_to_pixel8(unsigned int r
, unsigned int g
, unsigned b
)
885 static inline unsigned int rgb_to_pixel15(unsigned int r
, unsigned int g
, unsigned b
)
887 return ((r
>> 3) << 10) | ((g
>> 3) << 5) | (b
>> 3);
890 static inline unsigned int rgb_to_pixel16(unsigned int r
, unsigned int g
, unsigned b
)
892 return ((r
>> 3) << 11) | ((g
>> 2) << 5) | (b
>> 3);
895 static inline unsigned int rgb_to_pixel32(unsigned int r
, unsigned int g
, unsigned b
)
897 return (r
<< 16) | (g
<< 8) | b
;
901 #include "vga_template.h"
904 #include "vga_template.h"
907 #include "vga_template.h"
910 #include "vga_template.h"
912 static inline int c6_to_8(int v
)
917 return (v
<< 2) | (b
<< 1) | b
;
920 static unsigned int rgb_to_pixel8_dup(unsigned int r
, unsigned int g
, unsigned b
)
923 col
= rgb_to_pixel8(r
, g
, b
);
929 static unsigned int rgb_to_pixel15_dup(unsigned int r
, unsigned int g
, unsigned b
)
932 col
= rgb_to_pixel15(r
, g
, b
);
937 static unsigned int rgb_to_pixel16_dup(unsigned int r
, unsigned int g
, unsigned b
)
940 col
= rgb_to_pixel16(r
, g
, b
);
945 static unsigned int rgb_to_pixel32_dup(unsigned int r
, unsigned int g
, unsigned b
)
948 col
= rgb_to_pixel32(r
, g
, b
);
952 /* return true if the palette was modified */
953 static int update_palette16(VGAState
*s
)
956 uint32_t v
, col
, *palette
;
959 palette
= s
->last_palette
;
960 for(i
= 0; i
< 16; i
++) {
962 if (s
->ar
[0x10] & 0x80)
963 v
= ((s
->ar
[0x14] & 0xf) << 4) | (v
& 0xf);
965 v
= ((s
->ar
[0x14] & 0xc) << 4) | (v
& 0x3f);
967 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
968 c6_to_8(s
->palette
[v
+ 1]),
969 c6_to_8(s
->palette
[v
+ 2]));
970 if (col
!= palette
[i
]) {
978 /* return true if the palette was modified */
979 static int update_palette256(VGAState
*s
)
982 uint32_t v
, col
, *palette
;
985 palette
= s
->last_palette
;
987 for(i
= 0; i
< 256; i
++) {
988 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
989 c6_to_8(s
->palette
[v
+ 1]),
990 c6_to_8(s
->palette
[v
+ 2]));
991 if (col
!= palette
[i
]) {
1000 /* update start_addr and line_offset. Return TRUE if modified */
1001 static int update_basic_params(VGAState
*s
)
1004 uint32_t start_addr
, line_offset
, line_compare
;
1008 #ifdef CONFIG_BOCHS_VBE
1009 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1010 line_offset
= s
->vbe_line_offset
;
1011 start_addr
= s
->vbe_start_addr
;
1015 /* compute line_offset in bytes */
1016 line_offset
= s
->cr
[0x13];
1020 v
= (s
->cr
[0x51] >> 4) & 3; /* S3 extension */
1022 v
= (s
->cr
[0x43] >> 2) & 1; /* S3 extension */
1023 line_offset
|= (v
<< 8);
1028 /* starting address */
1029 start_addr
= s
->cr
[0x0d] | (s
->cr
[0x0c] << 8);
1031 start_addr
|= (s
->cr
[0x69] & 0x1f) << 16; /* S3 extension */
1036 line_compare
= s
->cr
[0x18] |
1037 ((s
->cr
[0x07] & 0x10) << 4) |
1038 ((s
->cr
[0x09] & 0x40) << 3);
1040 if (line_offset
!= s
->line_offset
||
1041 start_addr
!= s
->start_addr
||
1042 line_compare
!= s
->line_compare
) {
1043 s
->line_offset
= line_offset
;
1044 s
->start_addr
= start_addr
;
1045 s
->line_compare
= line_compare
;
1051 static inline int get_depth_index(int depth
)
1066 static vga_draw_glyph8_func
*vga_draw_glyph8_table
[4] = {
1073 static vga_draw_glyph8_func
*vga_draw_glyph16_table
[4] = {
1075 vga_draw_glyph16_16
,
1076 vga_draw_glyph16_16
,
1077 vga_draw_glyph16_32
,
1080 static vga_draw_glyph9_func
*vga_draw_glyph9_table
[4] = {
1087 static const uint8_t cursor_glyph
[32 * 4] = {
1088 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1089 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1090 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1091 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1092 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1093 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1094 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1095 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1096 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1097 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1098 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1099 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1100 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1101 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1102 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1103 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1114 static void vga_draw_text(VGAState
*s
, int full_update
)
1116 int cx
, cy
, cheight
, cw
, ch
, cattr
, height
, width
, ch_attr
;
1117 int cx_min
, cx_max
, linesize
, x_incr
;
1118 uint32_t offset
, fgcol
, bgcol
, v
, cursor_offset
;
1119 uint8_t *d1
, *d
, *src
, *s1
, *dest
, *cursor_ptr
;
1120 const uint8_t *font_ptr
, *font_base
[2];
1121 int dup9
, line_offset
, depth_index
;
1123 uint32_t *ch_attr_ptr
;
1124 vga_draw_glyph8_func
*vga_draw_glyph8
;
1125 vga_draw_glyph9_func
*vga_draw_glyph9
;
1127 full_update
|= update_palette16(s
);
1128 palette
= s
->last_palette
;
1130 /* compute font data address (in plane 2) */
1132 offset
= (((v
>> 5) & 1) | ((v
>> 1) & 6)) * 8192 * 4 + 2;
1133 if (offset
!= s
->font_offsets
[0]) {
1134 s
->font_offsets
[0] = offset
;
1137 font_base
[0] = s
->vram_ptr
+ offset
;
1139 offset
= (((v
>> 4) & 1) | ((v
<< 1) & 6)) * 8192 * 4 + 2;
1140 font_base
[1] = s
->vram_ptr
+ offset
;
1141 if (offset
!= s
->font_offsets
[1]) {
1142 s
->font_offsets
[1] = offset
;
1146 full_update
|= update_basic_params(s
);
1148 line_offset
= s
->line_offset
;
1149 s1
= s
->vram_ptr
+ (s
->start_addr
* 4);
1151 /* total width & height */
1152 cheight
= (s
->cr
[9] & 0x1f) + 1;
1154 if (!(s
->sr
[1] & 0x01))
1156 if (s
->sr
[1] & 0x08)
1157 cw
= 16; /* NOTE: no 18 pixel wide */
1158 x_incr
= cw
* ((s
->ds
->depth
+ 7) >> 3);
1159 width
= (s
->cr
[0x01] + 1);
1160 if (s
->cr
[0x06] == 100) {
1161 /* ugly hack for CGA 160x100x16 - explain me the logic */
1164 height
= s
->cr
[0x12] |
1165 ((s
->cr
[0x07] & 0x02) << 7) |
1166 ((s
->cr
[0x07] & 0x40) << 3);
1167 height
= (height
+ 1) / cheight
;
1169 if ((height
* width
) > CH_ATTR_SIZE
) {
1170 /* better than nothing: exit if transient size is too big */
1174 if (width
!= s
->last_width
|| height
!= s
->last_height
||
1175 cw
!= s
->last_cw
|| cheight
!= s
->last_ch
) {
1176 s
->last_scr_width
= width
* cw
;
1177 s
->last_scr_height
= height
* cheight
;
1178 dpy_resize(s
->ds
, s
->last_scr_width
, s
->last_scr_height
);
1179 s
->last_width
= width
;
1180 s
->last_height
= height
;
1181 s
->last_ch
= cheight
;
1185 cursor_offset
= ((s
->cr
[0x0e] << 8) | s
->cr
[0x0f]) - s
->start_addr
;
1186 if (cursor_offset
!= s
->cursor_offset
||
1187 s
->cr
[0xa] != s
->cursor_start
||
1188 s
->cr
[0xb] != s
->cursor_end
) {
1189 /* if the cursor position changed, we update the old and new
1191 if (s
->cursor_offset
< CH_ATTR_SIZE
)
1192 s
->last_ch_attr
[s
->cursor_offset
] = -1;
1193 if (cursor_offset
< CH_ATTR_SIZE
)
1194 s
->last_ch_attr
[cursor_offset
] = -1;
1195 s
->cursor_offset
= cursor_offset
;
1196 s
->cursor_start
= s
->cr
[0xa];
1197 s
->cursor_end
= s
->cr
[0xb];
1199 cursor_ptr
= s
->vram_ptr
+ (s
->start_addr
+ cursor_offset
) * 4;
1201 depth_index
= get_depth_index(s
->ds
->depth
);
1203 vga_draw_glyph8
= vga_draw_glyph16_table
[depth_index
];
1205 vga_draw_glyph8
= vga_draw_glyph8_table
[depth_index
];
1206 vga_draw_glyph9
= vga_draw_glyph9_table
[depth_index
];
1209 linesize
= s
->ds
->linesize
;
1210 ch_attr_ptr
= s
->last_ch_attr
;
1211 for(cy
= 0; cy
< height
; cy
++) {
1216 for(cx
= 0; cx
< width
; cx
++) {
1217 ch_attr
= *(uint16_t *)src
;
1218 if (full_update
|| ch_attr
!= *ch_attr_ptr
) {
1223 *ch_attr_ptr
= ch_attr
;
1224 #ifdef WORDS_BIGENDIAN
1226 cattr
= ch_attr
& 0xff;
1228 ch
= ch_attr
& 0xff;
1229 cattr
= ch_attr
>> 8;
1231 font_ptr
= font_base
[(cattr
>> 3) & 1];
1232 font_ptr
+= 32 * 4 * ch
;
1233 bgcol
= palette
[cattr
>> 4];
1234 fgcol
= palette
[cattr
& 0x0f];
1236 vga_draw_glyph8(d1
, linesize
,
1237 font_ptr
, cheight
, fgcol
, bgcol
);
1240 if (ch
>= 0xb0 && ch
<= 0xdf && (s
->ar
[0x10] & 0x04))
1242 vga_draw_glyph9(d1
, linesize
,
1243 font_ptr
, cheight
, fgcol
, bgcol
, dup9
);
1245 if (src
== cursor_ptr
&&
1246 !(s
->cr
[0x0a] & 0x20)) {
1247 int line_start
, line_last
, h
;
1248 /* draw the cursor */
1249 line_start
= s
->cr
[0x0a] & 0x1f;
1250 line_last
= s
->cr
[0x0b] & 0x1f;
1251 /* XXX: check that */
1252 if (line_last
> cheight
- 1)
1253 line_last
= cheight
- 1;
1254 if (line_last
>= line_start
&& line_start
< cheight
) {
1255 h
= line_last
- line_start
+ 1;
1256 d
= d1
+ linesize
* line_start
;
1258 vga_draw_glyph8(d
, linesize
,
1259 cursor_glyph
, h
, fgcol
, bgcol
);
1261 vga_draw_glyph9(d
, linesize
,
1262 cursor_glyph
, h
, fgcol
, bgcol
, 1);
1272 dpy_update(s
->ds
, cx_min
* cw
, cy
* cheight
,
1273 (cx_max
- cx_min
+ 1) * cw
, cheight
);
1275 dest
+= linesize
* cheight
;
1294 static vga_draw_line_func
*vga_draw_line_table
[4 * VGA_DRAW_LINE_NB
] = {
1301 vga_draw_line2d2_16
,
1302 vga_draw_line2d2_16
,
1303 vga_draw_line2d2_32
,
1311 vga_draw_line4d2_16
,
1312 vga_draw_line4d2_16
,
1313 vga_draw_line4d2_32
,
1316 vga_draw_line8d2_16
,
1317 vga_draw_line8d2_16
,
1318 vga_draw_line8d2_32
,
1352 static void vga_draw_graphic(VGAState
*s
, int full_update
)
1354 int y1
, y
, update
, page_min
, page_max
, linesize
, y_start
, double_scan
, mask
;
1355 int width
, height
, shift_control
, line_offset
, page0
, page1
, bwidth
;
1356 int disp_width
, multi_scan
, multi_run
;
1358 uint32_t v
, addr1
, addr
;
1359 vga_draw_line_func
*vga_draw_line
;
1361 full_update
|= update_basic_params(s
);
1363 width
= (s
->cr
[0x01] + 1) * 8;
1364 height
= s
->cr
[0x12] |
1365 ((s
->cr
[0x07] & 0x02) << 7) |
1366 ((s
->cr
[0x07] & 0x40) << 3);
1367 height
= (height
+ 1);
1370 shift_control
= (s
->gr
[0x05] >> 5) & 3;
1371 double_scan
= (s
->cr
[0x09] & 0x80);
1372 if (shift_control
> 1) {
1373 multi_scan
= (s
->cr
[0x09] & 0x1f);
1377 multi_run
= multi_scan
;
1378 if (shift_control
!= s
->shift_control
||
1379 double_scan
!= s
->double_scan
) {
1381 s
->shift_control
= shift_control
;
1382 s
->double_scan
= double_scan
;
1385 if (shift_control
== 0) {
1386 full_update
|= update_palette16(s
);
1387 if (s
->sr
[0x01] & 8) {
1388 v
= VGA_DRAW_LINE4D2
;
1393 } else if (shift_control
== 1) {
1394 full_update
|= update_palette16(s
);
1395 if (s
->sr
[0x01] & 8) {
1396 v
= VGA_DRAW_LINE2D2
;
1402 #ifdef CONFIG_BOCHS_VBE
1403 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1404 switch(s
->vbe_regs
[VBE_DISPI_INDEX_BPP
]) {
1407 full_update
|= update_palette256(s
);
1411 v
= VGA_DRAW_LINE15
;
1414 v
= VGA_DRAW_LINE16
;
1417 v
= VGA_DRAW_LINE24
;
1420 v
= VGA_DRAW_LINE32
;
1426 full_update
|= update_palette256(s
);
1427 v
= VGA_DRAW_LINE8D2
;
1430 vga_draw_line
= vga_draw_line_table
[v
* 4 + get_depth_index(s
->ds
->depth
)];
1432 if (disp_width
!= s
->last_width
||
1433 height
!= s
->last_height
) {
1434 dpy_resize(s
->ds
, disp_width
, height
);
1435 s
->last_scr_width
= disp_width
;
1436 s
->last_scr_height
= height
;
1437 s
->last_width
= disp_width
;
1438 s
->last_height
= height
;
1442 line_offset
= s
->line_offset
;
1444 printf("w=%d h=%d v=%d line_offset=%d double_scan=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=%02x\n",
1445 width
, height
, v
, line_offset
, s
->cr
[9], s
->cr
[0x17], s
->line_compare
, s
->sr
[0x01]);
1447 addr1
= (s
->start_addr
* 4);
1450 page_min
= 0x7fffffff;
1453 linesize
= s
->ds
->linesize
;
1455 for(y
= 0; y
< height
; y
++) {
1457 if (!(s
->cr
[0x17] & 1)) {
1459 /* CGA compatibility handling */
1460 shift
= 14 + ((s
->cr
[0x17] >> 6) & 1);
1461 addr
= (addr
& ~(1 << shift
)) | ((y1
& 1) << shift
);
1463 if (!(s
->cr
[0x17] & 2)) {
1464 addr
= (addr
& ~0x8000) | ((y1
& 2) << 14);
1466 page0
= s
->vram_offset
+ (addr
& TARGET_PAGE_MASK
);
1467 page1
= s
->vram_offset
+ ((addr
+ bwidth
- 1) & TARGET_PAGE_MASK
);
1468 update
= full_update
| cpu_physical_memory_is_dirty(page0
) |
1469 cpu_physical_memory_is_dirty(page1
);
1470 if ((page1
- page0
) > TARGET_PAGE_SIZE
) {
1471 /* if wide line, can use another page */
1472 update
|= cpu_physical_memory_is_dirty(page0
+ TARGET_PAGE_SIZE
);
1477 if (page0
< page_min
)
1479 if (page1
> page_max
)
1481 vga_draw_line(s
, d
, s
->vram_ptr
+ addr
, width
);
1484 /* flush to display */
1485 dpy_update(s
->ds
, 0, y_start
,
1486 disp_width
, y
- y_start
);
1491 if (!double_scan
|| (y
& 1) != 0) {
1492 if (y1
== s
->line_compare
) {
1495 mask
= (s
->cr
[0x17] & 3) ^ 3;
1496 if ((y1
& mask
) == mask
)
1497 addr1
+= line_offset
;
1501 multi_run
= multi_scan
;
1509 /* flush to display */
1510 dpy_update(s
->ds
, 0, y_start
,
1511 disp_width
, y
- y_start
);
1513 /* reset modified pages */
1514 if (page_max
!= -1) {
1515 cpu_physical_memory_reset_dirty(page_min
, page_max
+ TARGET_PAGE_SIZE
);
1519 static void vga_draw_blank(VGAState
*s
, int full_update
)
1526 if (s
->last_scr_width
<= 0 || s
->last_scr_height
<= 0)
1528 if (s
->ds
->depth
== 8)
1529 val
= s
->rgb_to_pixel(0, 0, 0);
1532 w
= s
->last_scr_width
* ((s
->ds
->depth
+ 7) >> 3);
1534 for(i
= 0; i
< s
->last_scr_height
; i
++) {
1536 d
+= s
->ds
->linesize
;
1538 dpy_update(s
->ds
, 0, 0,
1539 s
->last_scr_width
, s
->last_scr_height
);
1542 #define GMODE_TEXT 0
1543 #define GMODE_GRAPH 1
1544 #define GMODE_BLANK 2
1546 void vga_update_display(void)
1548 VGAState
*s
= &vga_state
;
1549 int full_update
, graphic_mode
;
1551 if (s
->ds
->depth
== 0) {
1554 switch(s
->ds
->depth
) {
1556 s
->rgb_to_pixel
= rgb_to_pixel8_dup
;
1559 s
->rgb_to_pixel
= rgb_to_pixel15_dup
;
1563 s
->rgb_to_pixel
= rgb_to_pixel16_dup
;
1566 s
->rgb_to_pixel
= rgb_to_pixel32_dup
;
1571 if (!(s
->ar_index
& 0x20)) {
1572 graphic_mode
= GMODE_BLANK
;
1574 graphic_mode
= s
->gr
[6] & 1;
1576 if (graphic_mode
!= s
->graphic_mode
) {
1577 s
->graphic_mode
= graphic_mode
;
1580 switch(graphic_mode
) {
1582 vga_draw_text(s
, full_update
);
1585 vga_draw_graphic(s
, full_update
);
1589 vga_draw_blank(s
, full_update
);
1595 static void vga_reset(VGAState
*s
)
1597 memset(s
, 0, sizeof(VGAState
));
1599 /* chip ID for 8c968 */
1602 s
->cr
[0x2f] = 0x01; /* XXX: check revision code */
1605 s
->graphic_mode
= -1; /* force full update */
1608 static CPUReadMemoryFunc
*vga_mem_read
[3] = {
1614 static CPUWriteMemoryFunc
*vga_mem_write
[3] = {
1620 static void vga_save(QEMUFile
*f
, void *opaque
)
1622 VGAState
*s
= opaque
;
1625 qemu_put_be32s(f
, &s
->latch
);
1626 qemu_put_8s(f
, &s
->sr_index
);
1627 qemu_put_buffer(f
, s
->sr
, 8);
1628 qemu_put_8s(f
, &s
->gr_index
);
1629 qemu_put_buffer(f
, s
->gr
, 16);
1630 qemu_put_8s(f
, &s
->ar_index
);
1631 qemu_put_buffer(f
, s
->ar
, 21);
1632 qemu_put_be32s(f
, &s
->ar_flip_flop
);
1633 qemu_put_8s(f
, &s
->cr_index
);
1634 qemu_put_buffer(f
, s
->cr
, 256);
1635 qemu_put_8s(f
, &s
->msr
);
1636 qemu_put_8s(f
, &s
->fcr
);
1637 qemu_put_8s(f
, &s
->st00
);
1638 qemu_put_8s(f
, &s
->st01
);
1640 qemu_put_8s(f
, &s
->dac_state
);
1641 qemu_put_8s(f
, &s
->dac_sub_index
);
1642 qemu_put_8s(f
, &s
->dac_read_index
);
1643 qemu_put_8s(f
, &s
->dac_write_index
);
1644 qemu_put_buffer(f
, s
->dac_cache
, 3);
1645 qemu_put_buffer(f
, s
->palette
, 768);
1647 qemu_put_be32s(f
, &s
->bank_offset
);
1648 #ifdef CONFIG_BOCHS_VBE
1649 qemu_put_byte(f
, 1);
1650 qemu_put_be16s(f
, &s
->vbe_index
);
1651 for(i
= 0; i
< VBE_DISPI_INDEX_NB
; i
++)
1652 qemu_put_be16s(f
, &s
->vbe_regs
[i
]);
1653 qemu_put_be32s(f
, &s
->vbe_start_addr
);
1654 qemu_put_be32s(f
, &s
->vbe_line_offset
);
1655 qemu_put_be32s(f
, &s
->vbe_bank_mask
);
1657 qemu_put_byte(f
, 0);
1661 static int vga_load(QEMUFile
*f
, void *opaque
, int version_id
)
1663 VGAState
*s
= opaque
;
1666 if (version_id
!= 1)
1669 qemu_get_be32s(f
, &s
->latch
);
1670 qemu_get_8s(f
, &s
->sr_index
);
1671 qemu_get_buffer(f
, s
->sr
, 8);
1672 qemu_get_8s(f
, &s
->gr_index
);
1673 qemu_get_buffer(f
, s
->gr
, 16);
1674 qemu_get_8s(f
, &s
->ar_index
);
1675 qemu_get_buffer(f
, s
->ar
, 21);
1676 qemu_get_be32s(f
, &s
->ar_flip_flop
);
1677 qemu_get_8s(f
, &s
->cr_index
);
1678 qemu_get_buffer(f
, s
->cr
, 256);
1679 qemu_get_8s(f
, &s
->msr
);
1680 qemu_get_8s(f
, &s
->fcr
);
1681 qemu_get_8s(f
, &s
->st00
);
1682 qemu_get_8s(f
, &s
->st01
);
1684 qemu_get_8s(f
, &s
->dac_state
);
1685 qemu_get_8s(f
, &s
->dac_sub_index
);
1686 qemu_get_8s(f
, &s
->dac_read_index
);
1687 qemu_get_8s(f
, &s
->dac_write_index
);
1688 qemu_get_buffer(f
, s
->dac_cache
, 3);
1689 qemu_get_buffer(f
, s
->palette
, 768);
1691 qemu_get_be32s(f
, &s
->bank_offset
);
1692 is_vbe
= qemu_get_byte(f
);
1693 #ifdef CONFIG_BOCHS_VBE
1696 qemu_get_be16s(f
, &s
->vbe_index
);
1697 for(i
= 0; i
< VBE_DISPI_INDEX_NB
; i
++)
1698 qemu_get_be16s(f
, &s
->vbe_regs
[i
]);
1699 qemu_get_be32s(f
, &s
->vbe_start_addr
);
1700 qemu_get_be32s(f
, &s
->vbe_line_offset
);
1701 qemu_get_be32s(f
, &s
->vbe_bank_mask
);
1708 s
->graphic_mode
= -1;
1712 int vga_initialize(DisplayState
*ds
, uint8_t *vga_ram_base
,
1713 unsigned long vga_ram_offset
, int vga_ram_size
)
1715 VGAState
*s
= &vga_state
;
1718 for(i
= 0;i
< 256; i
++) {
1720 for(j
= 0; j
< 8; j
++) {
1721 v
|= ((i
>> j
) & 1) << (j
* 4);
1726 for(j
= 0; j
< 4; j
++) {
1727 v
|= ((i
>> (2 * j
)) & 3) << (j
* 4);
1731 for(i
= 0; i
< 16; i
++) {
1733 for(j
= 0; j
< 4; j
++) {
1736 v
|= b
<< (2 * j
+ 1);
1743 s
->vram_ptr
= vga_ram_base
;
1744 s
->vram_offset
= vga_ram_offset
;
1745 s
->vram_size
= vga_ram_size
;
1748 register_savevm("vga", 0, 1, vga_save
, vga_load
, s
);
1750 register_ioport_write(0x3c0, 16, 1, vga_ioport_write
, s
);
1752 register_ioport_write(0x3b4, 2, 1, vga_ioport_write
, s
);
1753 register_ioport_write(0x3d4, 2, 1, vga_ioport_write
, s
);
1754 register_ioport_write(0x3ba, 1, 1, vga_ioport_write
, s
);
1755 register_ioport_write(0x3da, 1, 1, vga_ioport_write
, s
);
1757 register_ioport_read(0x3c0, 16, 1, vga_ioport_read
, s
);
1759 register_ioport_read(0x3b4, 2, 1, vga_ioport_read
, s
);
1760 register_ioport_read(0x3d4, 2, 1, vga_ioport_read
, s
);
1761 register_ioport_read(0x3ba, 1, 1, vga_ioport_read
, s
);
1762 register_ioport_read(0x3da, 1, 1, vga_ioport_read
, s
);
1765 #ifdef CONFIG_BOCHS_VBE
1766 s
->vbe_regs
[VBE_DISPI_INDEX_ID
] = VBE_DISPI_ID0
;
1767 s
->vbe_bank_mask
= ((s
->vram_size
>> 16) - 1);
1768 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read
, s
);
1769 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read
, s
);
1771 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write
, s
);
1772 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write
, s
);
1774 /* old Bochs IO ports */
1775 register_ioport_read(0xff80, 1, 2, vbe_ioport_read
, s
);
1776 register_ioport_read(0xff81, 1, 2, vbe_ioport_read
, s
);
1778 register_ioport_write(0xff80, 1, 2, vbe_ioport_write
, s
);
1779 register_ioport_write(0xff81, 1, 2, vbe_ioport_write
, s
);
1782 vga_io_memory
= cpu_register_io_memory(0, vga_mem_read
, vga_mem_write
);
1783 cpu_register_physical_memory(isa_mem_base
+ 0x000a0000, 0x20000,
1785 #ifdef CONFIG_BOCHS_VBE
1786 #if defined (TARGET_I386)
1787 /* XXX: use optimized standard vga accesses */
1788 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS
,
1789 vga_ram_size
, vga_ram_offset
);
1795 /********************************************************/
1796 /* vga screen dump */
1798 static int vga_save_w
, vga_save_h
;
1800 static void vga_save_dpy_update(DisplayState
*s
,
1801 int x
, int y
, int w
, int h
)
1805 static void vga_save_dpy_resize(DisplayState
*s
, int w
, int h
)
1807 s
->linesize
= w
* 4;
1808 s
->data
= qemu_malloc(h
* s
->linesize
);
1813 static void vga_save_dpy_refresh(DisplayState
*s
)
1817 static int ppm_save(const char *filename
, uint8_t *data
,
1818 int w
, int h
, int linesize
)
1825 f
= fopen(filename
, "wb");
1828 fprintf(f
, "P6\n%d %d\n%d\n",
1831 for(y
= 0; y
< h
; y
++) {
1833 for(x
= 0; x
< w
; x
++) {
1835 fputc((v
>> 16) & 0xff, f
);
1836 fputc((v
>> 8) & 0xff, f
);
1837 fputc((v
) & 0xff, f
);
1846 /* save the vga display in a PPM image even if no display is
1848 void vga_screen_dump(const char *filename
)
1850 VGAState
*s
= &vga_state
;
1851 DisplayState
*saved_ds
, ds1
, *ds
= &ds1
;
1853 /* XXX: this is a little hackish */
1855 s
->last_height
= -1;
1858 memset(ds
, 0, sizeof(DisplayState
));
1859 ds
->dpy_update
= vga_save_dpy_update
;
1860 ds
->dpy_resize
= vga_save_dpy_resize
;
1861 ds
->dpy_refresh
= vga_save_dpy_refresh
;
1865 s
->graphic_mode
= -1;
1866 vga_update_display();
1869 ppm_save(filename
, ds
->data
, vga_save_w
, vga_save_h
,
1871 qemu_free(ds
->data
);