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
35 #define MSR_COLOR_EMULATION 0x01
36 #define MSR_PAGE_SELECT 0x20
38 #define ST01_V_RETRACE 0x08
39 #define ST01_DISP_ENABLE 0x01
41 /* bochs VBE support */
42 #define CONFIG_BOCHS_VBE
44 #define VBE_DISPI_MAX_XRES 1024
45 #define VBE_DISPI_MAX_YRES 768
47 #define VBE_DISPI_INDEX_ID 0x0
48 #define VBE_DISPI_INDEX_XRES 0x1
49 #define VBE_DISPI_INDEX_YRES 0x2
50 #define VBE_DISPI_INDEX_BPP 0x3
51 #define VBE_DISPI_INDEX_ENABLE 0x4
52 #define VBE_DISPI_INDEX_BANK 0x5
53 #define VBE_DISPI_INDEX_VIRT_WIDTH 0x6
54 #define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
55 #define VBE_DISPI_INDEX_X_OFFSET 0x8
56 #define VBE_DISPI_INDEX_Y_OFFSET 0x9
57 #define VBE_DISPI_INDEX_NB 0xa
59 #define VBE_DISPI_ID0 0xB0C0
60 #define VBE_DISPI_ID1 0xB0C1
61 #define VBE_DISPI_ID2 0xB0C2
63 #define VBE_DISPI_DISABLED 0x00
64 #define VBE_DISPI_ENABLED 0x01
65 #define VBE_DISPI_LFB_ENABLED 0x40
66 #define VBE_DISPI_NOCLEARMEM 0x80
68 #define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000
70 typedef struct VGAState
{
72 unsigned long vram_offset
;
73 unsigned int vram_size
;
83 uint8_t cr
[256]; /* CRT registers */
84 uint8_t msr
; /* Misc Output Register */
85 uint8_t fcr
; /* Feature Control Register */
86 uint8_t st00
; /* status 0 */
87 uint8_t st01
; /* status 1 */
89 uint8_t dac_sub_index
;
90 uint8_t dac_read_index
;
91 uint8_t dac_write_index
;
92 uint8_t dac_cache
[3]; /* used when writing */
95 #ifdef CONFIG_BOCHS_VBE
97 uint16_t vbe_regs
[VBE_DISPI_INDEX_NB
];
98 uint32_t vbe_start_addr
;
99 uint32_t vbe_line_offset
;
100 uint32_t vbe_bank_mask
;
102 /* display refresh support */
104 uint32_t font_offsets
[2];
106 uint8_t shift_control
;
108 uint32_t line_offset
;
109 uint32_t line_compare
;
111 uint8_t last_cw
, last_ch
;
112 uint32_t last_width
, last_height
; /* in chars or pixels */
113 uint32_t last_scr_width
, last_scr_height
; /* in pixels */
114 uint8_t cursor_start
, cursor_end
;
115 uint32_t cursor_offset
;
116 unsigned int (*rgb_to_pixel
)(unsigned int r
, unsigned int g
, unsigned b
);
117 /* tell for each page if it has been updated since the last time */
118 uint32_t last_palette
[256];
119 #define CH_ATTR_SIZE (160 * 100)
120 uint32_t last_ch_attr
[CH_ATTR_SIZE
]; /* XXX: make it dynamic */
123 /* force some bits to zero */
124 static const uint8_t sr_mask
[8] = {
135 static const uint8_t gr_mask
[16] = {
136 (uint8_t)~0xf0, /* 0x00 */
137 (uint8_t)~0xf0, /* 0x01 */
138 (uint8_t)~0xf0, /* 0x02 */
139 (uint8_t)~0xe0, /* 0x03 */
140 (uint8_t)~0xfc, /* 0x04 */
141 (uint8_t)~0x84, /* 0x05 */
142 (uint8_t)~0xf0, /* 0x06 */
143 (uint8_t)~0xf0, /* 0x07 */
144 (uint8_t)~0x00, /* 0x08 */
145 (uint8_t)~0xff, /* 0x09 */
146 (uint8_t)~0xff, /* 0x0a */
147 (uint8_t)~0xff, /* 0x0b */
148 (uint8_t)~0xff, /* 0x0c */
149 (uint8_t)~0xff, /* 0x0d */
150 (uint8_t)~0xff, /* 0x0e */
151 (uint8_t)~0xff, /* 0x0f */
154 #define cbswap_32(__x) \
156 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
157 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
158 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
159 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
161 #ifdef WORDS_BIGENDIAN
162 #define PAT(x) cbswap_32(x)
167 #ifdef WORDS_BIGENDIAN
173 #ifdef WORDS_BIGENDIAN
174 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
176 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
179 static const uint32_t mask16
[16] = {
200 #ifdef WORDS_BIGENDIAN
203 #define PAT(x) cbswap_32(x)
206 static const uint32_t dmask16
[16] = {
225 static const uint32_t dmask4
[4] = {
232 static uint32_t expand4
[256];
233 static uint16_t expand2
[256];
234 static uint8_t expand4to8
[16];
239 static uint32_t vga_ioport_read(void *opaque
, uint32_t addr
)
241 VGAState
*s
= opaque
;
244 /* check port range access depending on color/monochrome mode */
245 if ((addr
>= 0x3b0 && addr
<= 0x3bf && (s
->msr
& MSR_COLOR_EMULATION
)) ||
246 (addr
>= 0x3d0 && addr
<= 0x3df && !(s
->msr
& MSR_COLOR_EMULATION
))) {
251 if (s
->ar_flip_flop
== 0) {
258 index
= s
->ar_index
& 0x1f;
271 val
= s
->sr
[s
->sr_index
];
273 printf("vga: read SR%x = 0x%02x\n", s
->sr_index
, val
);
280 val
= s
->palette
[s
->dac_read_index
* 3 + s
->dac_sub_index
];
281 if (++s
->dac_sub_index
== 3) {
282 s
->dac_sub_index
= 0;
296 val
= s
->gr
[s
->gr_index
];
298 printf("vga: read GR%x = 0x%02x\n", s
->gr_index
, val
);
307 val
= s
->cr
[s
->cr_index
];
309 printf("vga: read CR%x = 0x%02x\n", s
->cr_index
, val
);
312 if (s
->cr_index
>= 0x20)
313 printf("S3: CR read index=0x%x val=0x%x\n",
319 /* just toggle to fool polling */
320 s
->st01
^= ST01_V_RETRACE
| ST01_DISP_ENABLE
;
329 #if defined(DEBUG_VGA)
330 printf("VGA: read addr=0x%04x data=0x%02x\n", addr
, val
);
335 static void vga_ioport_write(void *opaque
, uint32_t addr
, uint32_t val
)
337 VGAState
*s
= opaque
;
340 /* check port range access depending on color/monochrome mode */
341 if ((addr
>= 0x3b0 && addr
<= 0x3bf && (s
->msr
& MSR_COLOR_EMULATION
)) ||
342 (addr
>= 0x3d0 && addr
<= 0x3df && !(s
->msr
& MSR_COLOR_EMULATION
)))
346 printf("VGA: write addr=0x%04x data=0x%02x\n", addr
, val
);
351 if (s
->ar_flip_flop
== 0) {
355 index
= s
->ar_index
& 0x1f;
358 s
->ar
[index
] = val
& 0x3f;
361 s
->ar
[index
] = val
& ~0x10;
367 s
->ar
[index
] = val
& ~0xc0;
370 s
->ar
[index
] = val
& ~0xf0;
373 s
->ar
[index
] = val
& ~0xf0;
379 s
->ar_flip_flop
^= 1;
382 s
->msr
= val
& ~0x10;
385 s
->sr_index
= val
& 7;
389 printf("vga: write SR%x = 0x%02x\n", s
->sr_index
, val
);
391 s
->sr
[s
->sr_index
] = val
& sr_mask
[s
->sr_index
];
394 s
->dac_read_index
= val
;
395 s
->dac_sub_index
= 0;
399 s
->dac_write_index
= val
;
400 s
->dac_sub_index
= 0;
404 s
->dac_cache
[s
->dac_sub_index
] = val
;
405 if (++s
->dac_sub_index
== 3) {
406 memcpy(&s
->palette
[s
->dac_write_index
* 3], s
->dac_cache
, 3);
407 s
->dac_sub_index
= 0;
408 s
->dac_write_index
++;
412 s
->gr_index
= val
& 0x0f;
416 printf("vga: write GR%x = 0x%02x\n", s
->gr_index
, val
);
418 s
->gr
[s
->gr_index
] = val
& gr_mask
[s
->gr_index
];
427 printf("vga: write CR%x = 0x%02x\n", s
->cr_index
, val
);
429 /* handle CR0-7 protection */
430 if ((s
->cr
[11] & 0x80) && s
->cr_index
<= 7) {
431 /* can always write bit 4 of CR7 */
432 if (s
->cr_index
== 7)
433 s
->cr
[7] = (s
->cr
[7] & ~0x10) | (val
& 0x10);
436 switch(s
->cr_index
) {
437 case 0x01: /* horizontal display end */
442 case 0x12: /* veritcal display end */
443 s
->cr
[s
->cr_index
] = val
;
452 /* chip ID, cannot write */
455 /* update start address */
456 s
->cr
[s
->cr_index
] = val
;
458 s
->cr
[0x69] = (s
->cr
[69] & ~0x03) | v
;
461 /* update start address */
462 s
->cr
[s
->cr_index
] = val
;
464 s
->cr
[0x69] = (s
->cr
[69] & ~0x0c) | (v
<< 2);
468 s
->cr
[s
->cr_index
] = val
;
472 if (s
->cr_index
>= 0x20)
473 printf("S3: CR write index=0x%x val=0x%x\n",
484 #ifdef CONFIG_BOCHS_VBE
485 static uint32_t vbe_ioport_read(void *opaque
, uint32_t addr
)
487 VGAState
*s
= opaque
;
494 if (s
->vbe_index
<= VBE_DISPI_INDEX_NB
)
495 val
= s
->vbe_regs
[s
->vbe_index
];
498 #ifdef DEBUG_BOCHS_VBE
499 printf("VBE: read index=0x%x val=0x%x\n", s
->vbe_index
, val
);
505 static void vbe_ioport_write(void *opaque
, uint32_t addr
, uint32_t val
)
507 VGAState
*s
= opaque
;
512 } else if (s
->vbe_index
<= VBE_DISPI_INDEX_NB
) {
513 #ifdef DEBUG_BOCHS_VBE
514 printf("VBE: write index=0x%x val=0x%x\n", s
->vbe_index
, val
);
516 switch(s
->vbe_index
) {
517 case VBE_DISPI_INDEX_ID
:
518 if (val
== VBE_DISPI_ID0
||
519 val
== VBE_DISPI_ID1
||
520 val
== VBE_DISPI_ID2
) {
521 s
->vbe_regs
[s
->vbe_index
] = val
;
524 case VBE_DISPI_INDEX_XRES
:
525 if ((val
<= VBE_DISPI_MAX_XRES
) && ((val
& 7) == 0)) {
526 s
->vbe_regs
[s
->vbe_index
] = val
;
529 case VBE_DISPI_INDEX_YRES
:
530 if (val
<= VBE_DISPI_MAX_YRES
) {
531 s
->vbe_regs
[s
->vbe_index
] = val
;
534 case VBE_DISPI_INDEX_BPP
:
537 if (val
== 4 || val
== 8 || val
== 15 ||
538 val
== 16 || val
== 24 || val
== 32) {
539 s
->vbe_regs
[s
->vbe_index
] = val
;
542 case VBE_DISPI_INDEX_BANK
:
543 val
&= s
->vbe_bank_mask
;
544 s
->vbe_regs
[s
->vbe_index
] = val
;
545 s
->bank_offset
= (val
<< 16) - 0xa0000;
547 case VBE_DISPI_INDEX_ENABLE
:
548 if (val
& VBE_DISPI_ENABLED
) {
549 int h
, shift_control
;
551 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] =
552 s
->vbe_regs
[VBE_DISPI_INDEX_XRES
];
553 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_HEIGHT
] =
554 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
];
555 s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
] = 0;
556 s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
] = 0;
558 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
559 s
->vbe_line_offset
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 1;
561 s
->vbe_line_offset
= s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] *
562 ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
563 s
->vbe_start_addr
= 0;
565 /* clear the screen (should be done in BIOS) */
566 if (!(val
& VBE_DISPI_NOCLEARMEM
)) {
567 memset(s
->vram_ptr
, 0,
568 s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] * s
->vbe_line_offset
);
571 /* we initialize the VGA graphic mode (should be done
573 s
->gr
[0x06] = (s
->gr
[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
574 s
->cr
[0x17] |= 3; /* no CGA modes */
575 s
->cr
[0x13] = s
->vbe_line_offset
>> 3;
577 s
->cr
[0x01] = (s
->vbe_regs
[VBE_DISPI_INDEX_XRES
] >> 3) - 1;
579 h
= s
->vbe_regs
[VBE_DISPI_INDEX_YRES
] - 1;
581 s
->cr
[0x07] = (s
->cr
[0x07] & ~0x42) |
582 ((h
>> 7) & 0x02) | ((h
>> 3) & 0x40);
583 /* line compare to 1023 */
588 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4) {
590 s
->sr
[0x01] &= ~8; /* no double line */
594 s
->gr
[0x05] = (s
->gr
[0x05] & ~0x60) | (shift_control
<< 5);
595 s
->cr
[0x09] &= ~0x9f; /* no double scan */
596 s
->vbe_regs
[s
->vbe_index
] = val
;
598 /* XXX: the bios should do that */
599 s
->bank_offset
= -0xa0000;
602 case VBE_DISPI_INDEX_VIRT_WIDTH
:
604 int w
, h
, line_offset
;
606 if (val
< s
->vbe_regs
[VBE_DISPI_INDEX_XRES
])
609 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
610 line_offset
= w
>> 1;
612 line_offset
= w
* ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
613 h
= s
->vram_size
/ line_offset
;
614 /* XXX: support weird bochs semantics ? */
615 if (h
< s
->vbe_regs
[VBE_DISPI_INDEX_YRES
])
617 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_WIDTH
] = w
;
618 s
->vbe_regs
[VBE_DISPI_INDEX_VIRT_HEIGHT
] = h
;
619 s
->vbe_line_offset
= line_offset
;
622 case VBE_DISPI_INDEX_X_OFFSET
:
623 case VBE_DISPI_INDEX_Y_OFFSET
:
626 s
->vbe_regs
[s
->vbe_index
] = val
;
627 s
->vbe_start_addr
= s
->vbe_line_offset
* s
->vbe_regs
[VBE_DISPI_INDEX_Y_OFFSET
];
628 x
= s
->vbe_regs
[VBE_DISPI_INDEX_X_OFFSET
];
629 if (s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] == 4)
630 s
->vbe_start_addr
+= x
>> 1;
632 s
->vbe_start_addr
+= x
* ((s
->vbe_regs
[VBE_DISPI_INDEX_BPP
] + 7) >> 3);
633 s
->vbe_start_addr
>>= 2;
643 /* called for accesses between 0xa0000 and 0xc0000 */
644 static uint32_t vga_mem_readb(uint32_t addr
)
646 VGAState
*s
= &vga_state
;
647 int memory_map_mode
, plane
;
650 /* convert to VGA memory offset */
651 memory_map_mode
= (s
->gr
[6] >> 2) & 3;
652 switch(memory_map_mode
) {
659 addr
+= s
->bank_offset
;
674 if (s
->sr
[4] & 0x08) {
675 /* chain 4 mode : simplest access */
676 ret
= s
->vram_ptr
[addr
];
677 } else if (s
->gr
[5] & 0x10) {
678 /* odd/even mode (aka text mode mapping) */
679 plane
= (s
->gr
[4] & 2) | (addr
& 1);
680 ret
= s
->vram_ptr
[((addr
& ~1) << 1) | plane
];
682 /* standard VGA latched access */
683 s
->latch
= ((uint32_t *)s
->vram_ptr
)[addr
];
685 if (!(s
->gr
[5] & 0x08)) {
688 ret
= GET_PLANE(s
->latch
, plane
);
691 ret
= (s
->latch
^ mask16
[s
->gr
[2]]) & mask16
[s
->gr
[7]];
700 static uint32_t vga_mem_readw(uint32_t addr
)
703 v
= vga_mem_readb(addr
);
704 v
|= vga_mem_readb(addr
+ 1) << 8;
708 static uint32_t vga_mem_readl(uint32_t addr
)
711 v
= vga_mem_readb(addr
);
712 v
|= vga_mem_readb(addr
+ 1) << 8;
713 v
|= vga_mem_readb(addr
+ 2) << 16;
714 v
|= vga_mem_readb(addr
+ 3) << 24;
718 /* called for accesses between 0xa0000 and 0xc0000 */
719 static void vga_mem_writeb(uint32_t addr
, uint32_t val
, uint32_t vaddr
)
721 VGAState
*s
= &vga_state
;
722 int memory_map_mode
, plane
, write_mode
, b
, func_select
;
723 uint32_t write_mask
, bit_mask
, set_mask
;
726 printf("vga: [0x%x] = 0x%02x\n", addr
, val
);
728 /* convert to VGA memory offset */
729 memory_map_mode
= (s
->gr
[6] >> 2) & 3;
730 switch(memory_map_mode
) {
737 addr
+= s
->bank_offset
;
752 if (s
->sr
[4] & 0x08) {
753 /* chain 4 mode : simplest access */
755 if (s
->sr
[2] & (1 << plane
)) {
756 s
->vram_ptr
[addr
] = val
;
758 printf("vga: chain4: [0x%x]\n", addr
);
760 cpu_physical_memory_set_dirty(s
->vram_offset
+ addr
);
762 } else if (s
->gr
[5] & 0x10) {
763 /* odd/even mode (aka text mode mapping) */
764 plane
= (s
->gr
[4] & 2) | (addr
& 1);
765 if (s
->sr
[2] & (1 << plane
)) {
766 addr
= ((addr
& ~1) << 1) | plane
;
767 s
->vram_ptr
[addr
] = val
;
769 printf("vga: odd/even: [0x%x]\n", addr
);
771 cpu_physical_memory_set_dirty(s
->vram_offset
+ addr
);
774 /* standard VGA latched access */
775 write_mode
= s
->gr
[5] & 3;
781 val
= ((val
>> b
) | (val
<< (8 - b
))) & 0xff;
785 /* apply set/reset mask */
786 set_mask
= mask16
[s
->gr
[1]];
787 val
= (val
& ~set_mask
) | (mask16
[s
->gr
[0]] & set_mask
);
794 val
= mask16
[val
& 0x0f];
800 val
= (val
>> b
) | (val
<< (8 - b
));
802 bit_mask
= s
->gr
[8] & val
;
803 val
= mask16
[s
->gr
[0]];
807 /* apply logical operation */
808 func_select
= s
->gr
[3] >> 3;
809 switch(func_select
) {
829 bit_mask
|= bit_mask
<< 8;
830 bit_mask
|= bit_mask
<< 16;
831 val
= (val
& bit_mask
) | (s
->latch
& ~bit_mask
);
834 /* mask data according to sr[2] */
835 write_mask
= mask16
[s
->sr
[2]];
836 ((uint32_t *)s
->vram_ptr
)[addr
] =
837 (((uint32_t *)s
->vram_ptr
)[addr
] & ~write_mask
) |
840 printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
841 addr
* 4, write_mask
, val
);
843 cpu_physical_memory_set_dirty(s
->vram_offset
+ (addr
<< 2));
847 static void vga_mem_writew(uint32_t addr
, uint32_t val
, uint32_t vaddr
)
849 vga_mem_writeb(addr
, val
& 0xff, vaddr
);
850 vga_mem_writeb(addr
+ 1, (val
>> 8) & 0xff, vaddr
);
853 static void vga_mem_writel(uint32_t addr
, uint32_t val
, uint32_t vaddr
)
855 vga_mem_writeb(addr
, val
& 0xff, vaddr
);
856 vga_mem_writeb(addr
+ 1, (val
>> 8) & 0xff, vaddr
);
857 vga_mem_writeb(addr
+ 2, (val
>> 16) & 0xff, vaddr
);
858 vga_mem_writeb(addr
+ 3, (val
>> 24) & 0xff, vaddr
);
861 typedef void vga_draw_glyph8_func(uint8_t *d
, int linesize
,
862 const uint8_t *font_ptr
, int h
,
863 uint32_t fgcol
, uint32_t bgcol
);
864 typedef void vga_draw_glyph9_func(uint8_t *d
, int linesize
,
865 const uint8_t *font_ptr
, int h
,
866 uint32_t fgcol
, uint32_t bgcol
, int dup9
);
867 typedef void vga_draw_line_func(VGAState
*s1
, uint8_t *d
,
868 const uint8_t *s
, int width
);
870 static inline unsigned int rgb_to_pixel8(unsigned int r
, unsigned int g
, unsigned b
)
876 static inline unsigned int rgb_to_pixel15(unsigned int r
, unsigned int g
, unsigned b
)
878 return ((r
>> 3) << 10) | ((g
>> 3) << 5) | (b
>> 3);
881 static inline unsigned int rgb_to_pixel16(unsigned int r
, unsigned int g
, unsigned b
)
883 return ((r
>> 3) << 11) | ((g
>> 2) << 5) | (b
>> 3);
886 static inline unsigned int rgb_to_pixel32(unsigned int r
, unsigned int g
, unsigned b
)
888 return (r
<< 16) | (g
<< 8) | b
;
892 #include "vga_template.h"
895 #include "vga_template.h"
898 #include "vga_template.h"
901 #include "vga_template.h"
903 static inline int c6_to_8(int v
)
908 return (v
<< 2) | (b
<< 1) | b
;
911 static unsigned int rgb_to_pixel8_dup(unsigned int r
, unsigned int g
, unsigned b
)
914 col
= rgb_to_pixel8(r
, g
, b
);
920 static unsigned int rgb_to_pixel15_dup(unsigned int r
, unsigned int g
, unsigned b
)
923 col
= rgb_to_pixel15(r
, g
, b
);
928 static unsigned int rgb_to_pixel16_dup(unsigned int r
, unsigned int g
, unsigned b
)
931 col
= rgb_to_pixel16(r
, g
, b
);
936 static unsigned int rgb_to_pixel32_dup(unsigned int r
, unsigned int g
, unsigned b
)
939 col
= rgb_to_pixel32(r
, g
, b
);
943 /* return true if the palette was modified */
944 static int update_palette16(VGAState
*s
)
947 uint32_t v
, col
, *palette
;
950 palette
= s
->last_palette
;
951 for(i
= 0; i
< 16; i
++) {
953 if (s
->ar
[0x10] & 0x80)
954 v
= ((s
->ar
[0x14] & 0xf) << 4) | (v
& 0xf);
956 v
= ((s
->ar
[0x14] & 0xc) << 4) | (v
& 0x3f);
958 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
959 c6_to_8(s
->palette
[v
+ 1]),
960 c6_to_8(s
->palette
[v
+ 2]));
961 if (col
!= palette
[i
]) {
969 /* return true if the palette was modified */
970 static int update_palette256(VGAState
*s
)
973 uint32_t v
, col
, *palette
;
976 palette
= s
->last_palette
;
978 for(i
= 0; i
< 256; i
++) {
979 col
= s
->rgb_to_pixel(c6_to_8(s
->palette
[v
]),
980 c6_to_8(s
->palette
[v
+ 1]),
981 c6_to_8(s
->palette
[v
+ 2]));
982 if (col
!= palette
[i
]) {
991 /* update start_addr and line_offset. Return TRUE if modified */
992 static int update_basic_params(VGAState
*s
)
995 uint32_t start_addr
, line_offset
, line_compare
, v
;
999 #ifdef CONFIG_BOCHS_VBE
1000 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1001 line_offset
= s
->vbe_line_offset
;
1002 start_addr
= s
->vbe_start_addr
;
1006 /* compute line_offset in bytes */
1007 line_offset
= s
->cr
[0x13];
1009 v
= (s
->cr
[0x51] >> 4) & 3; /* S3 extension */
1011 v
= (s
->cr
[0x43] >> 2) & 1; /* S3 extension */
1012 line_offset
|= (v
<< 8);
1016 /* starting address */
1017 start_addr
= s
->cr
[0x0d] | (s
->cr
[0x0c] << 8);
1019 start_addr
|= (s
->cr
[0x69] & 0x1f) << 16; /* S3 extension */
1024 line_compare
= s
->cr
[0x18] |
1025 ((s
->cr
[0x07] & 0x10) << 4) |
1026 ((s
->cr
[0x09] & 0x40) << 3);
1028 if (line_offset
!= s
->line_offset
||
1029 start_addr
!= s
->start_addr
||
1030 line_compare
!= s
->line_compare
) {
1031 s
->line_offset
= line_offset
;
1032 s
->start_addr
= start_addr
;
1033 s
->line_compare
= line_compare
;
1039 static inline int get_depth_index(int depth
)
1054 static vga_draw_glyph8_func
*vga_draw_glyph8_table
[4] = {
1061 static vga_draw_glyph8_func
*vga_draw_glyph16_table
[4] = {
1063 vga_draw_glyph16_16
,
1064 vga_draw_glyph16_16
,
1065 vga_draw_glyph16_32
,
1068 static vga_draw_glyph9_func
*vga_draw_glyph9_table
[4] = {
1075 static const uint8_t cursor_glyph
[32 * 4] = {
1076 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1077 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1078 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1079 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1080 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1081 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1082 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1083 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1084 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1085 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1086 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1087 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
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,
1102 static void vga_draw_text(VGAState
*s
, int full_update
)
1104 int cx
, cy
, cheight
, cw
, ch
, cattr
, height
, width
, ch_attr
;
1105 int cx_min
, cx_max
, linesize
, x_incr
;
1106 uint32_t offset
, fgcol
, bgcol
, v
, cursor_offset
;
1107 uint8_t *d1
, *d
, *src
, *s1
, *dest
, *cursor_ptr
;
1108 const uint8_t *font_ptr
, *font_base
[2];
1109 int dup9
, line_offset
, depth_index
;
1111 uint32_t *ch_attr_ptr
;
1112 vga_draw_glyph8_func
*vga_draw_glyph8
;
1113 vga_draw_glyph9_func
*vga_draw_glyph9
;
1115 full_update
|= update_palette16(s
);
1116 palette
= s
->last_palette
;
1118 /* compute font data address (in plane 2) */
1120 offset
= (((v
>> 5) & 1) | ((v
>> 1) & 6)) * 8192 * 4 + 2;
1121 if (offset
!= s
->font_offsets
[0]) {
1122 s
->font_offsets
[0] = offset
;
1125 font_base
[0] = s
->vram_ptr
+ offset
;
1127 offset
= (((v
>> 4) & 1) | ((v
<< 1) & 6)) * 8192 * 4 + 2;
1128 font_base
[1] = s
->vram_ptr
+ offset
;
1129 if (offset
!= s
->font_offsets
[1]) {
1130 s
->font_offsets
[1] = offset
;
1134 full_update
|= update_basic_params(s
);
1136 line_offset
= s
->line_offset
;
1137 s1
= s
->vram_ptr
+ (s
->start_addr
* 4);
1139 /* total width & height */
1140 cheight
= (s
->cr
[9] & 0x1f) + 1;
1142 if (!(s
->sr
[1] & 0x01))
1144 if (s
->sr
[1] & 0x08)
1145 cw
= 16; /* NOTE: no 18 pixel wide */
1146 x_incr
= cw
* ((s
->ds
->depth
+ 7) >> 3);
1147 width
= (s
->cr
[0x01] + 1);
1148 if (s
->cr
[0x06] == 100) {
1149 /* ugly hack for CGA 160x100x16 - explain me the logic */
1152 height
= s
->cr
[0x12] |
1153 ((s
->cr
[0x07] & 0x02) << 7) |
1154 ((s
->cr
[0x07] & 0x40) << 3);
1155 height
= (height
+ 1) / cheight
;
1157 if (width
!= s
->last_width
|| height
!= s
->last_height
||
1158 cw
!= s
->last_cw
|| cheight
!= s
->last_ch
) {
1159 s
->last_scr_width
= width
* cw
;
1160 s
->last_scr_height
= height
* cheight
;
1161 dpy_resize(s
->ds
, s
->last_scr_width
, s
->last_scr_height
);
1162 s
->last_width
= width
;
1163 s
->last_height
= height
;
1164 s
->last_ch
= cheight
;
1168 cursor_offset
= ((s
->cr
[0x0e] << 8) | s
->cr
[0x0f]) - s
->start_addr
;
1169 if (cursor_offset
!= s
->cursor_offset
||
1170 s
->cr
[0xa] != s
->cursor_start
||
1171 s
->cr
[0xb] != s
->cursor_end
) {
1172 /* if the cursor position changed, we update the old and new
1174 if (s
->cursor_offset
< CH_ATTR_SIZE
)
1175 s
->last_ch_attr
[s
->cursor_offset
] = -1;
1176 if (cursor_offset
< CH_ATTR_SIZE
)
1177 s
->last_ch_attr
[cursor_offset
] = -1;
1178 s
->cursor_offset
= cursor_offset
;
1179 s
->cursor_start
= s
->cr
[0xa];
1180 s
->cursor_end
= s
->cr
[0xb];
1182 cursor_ptr
= s
->vram_ptr
+ (s
->start_addr
+ cursor_offset
) * 4;
1184 depth_index
= get_depth_index(s
->ds
->depth
);
1186 vga_draw_glyph8
= vga_draw_glyph16_table
[depth_index
];
1188 vga_draw_glyph8
= vga_draw_glyph8_table
[depth_index
];
1189 vga_draw_glyph9
= vga_draw_glyph9_table
[depth_index
];
1192 linesize
= s
->ds
->linesize
;
1193 ch_attr_ptr
= s
->last_ch_attr
;
1194 for(cy
= 0; cy
< height
; cy
++) {
1199 for(cx
= 0; cx
< width
; cx
++) {
1200 ch_attr
= *(uint16_t *)src
;
1201 if (full_update
|| ch_attr
!= *ch_attr_ptr
) {
1206 *ch_attr_ptr
= ch_attr
;
1207 #ifdef WORDS_BIGENDIAN
1209 cattr
= ch_attr
& 0xff;
1211 ch
= ch_attr
& 0xff;
1212 cattr
= ch_attr
>> 8;
1214 font_ptr
= font_base
[(cattr
>> 3) & 1];
1215 font_ptr
+= 32 * 4 * ch
;
1216 bgcol
= palette
[cattr
>> 4];
1217 fgcol
= palette
[cattr
& 0x0f];
1219 vga_draw_glyph8(d1
, linesize
,
1220 font_ptr
, cheight
, fgcol
, bgcol
);
1223 if (ch
>= 0xb0 && ch
<= 0xdf && (s
->ar
[0x10] & 0x04))
1225 vga_draw_glyph9(d1
, linesize
,
1226 font_ptr
, cheight
, fgcol
, bgcol
, dup9
);
1228 if (src
== cursor_ptr
&&
1229 !(s
->cr
[0x0a] & 0x20)) {
1230 int line_start
, line_last
, h
;
1231 /* draw the cursor */
1232 line_start
= s
->cr
[0x0a] & 0x1f;
1233 line_last
= s
->cr
[0x0b] & 0x1f;
1234 /* XXX: check that */
1235 if (line_last
> cheight
- 1)
1236 line_last
= cheight
- 1;
1237 if (line_last
>= line_start
&& line_start
< cheight
) {
1238 h
= line_last
- line_start
+ 1;
1239 d
= d1
+ linesize
* line_start
;
1241 vga_draw_glyph8(d
, linesize
,
1242 cursor_glyph
, h
, fgcol
, bgcol
);
1244 vga_draw_glyph9(d
, linesize
,
1245 cursor_glyph
, h
, fgcol
, bgcol
, 1);
1255 dpy_update(s
->ds
, cx_min
* cw
, cy
* cheight
,
1256 (cx_max
- cx_min
+ 1) * cw
, cheight
);
1258 dest
+= linesize
* cheight
;
1277 static vga_draw_line_func
*vga_draw_line_table
[4 * VGA_DRAW_LINE_NB
] = {
1284 vga_draw_line2d2_16
,
1285 vga_draw_line2d2_16
,
1286 vga_draw_line2d2_32
,
1294 vga_draw_line4d2_16
,
1295 vga_draw_line4d2_16
,
1296 vga_draw_line4d2_32
,
1299 vga_draw_line8d2_16
,
1300 vga_draw_line8d2_16
,
1301 vga_draw_line8d2_32
,
1335 static void vga_draw_graphic(VGAState
*s
, int full_update
)
1337 int y1
, y
, update
, page_min
, page_max
, linesize
, y_start
, double_scan
, mask
;
1338 int width
, height
, shift_control
, line_offset
, page0
, page1
, bwidth
;
1339 int disp_width
, multi_scan
, multi_run
;
1341 uint32_t v
, addr1
, addr
;
1342 vga_draw_line_func
*vga_draw_line
;
1344 full_update
|= update_basic_params(s
);
1346 width
= (s
->cr
[0x01] + 1) * 8;
1347 height
= s
->cr
[0x12] |
1348 ((s
->cr
[0x07] & 0x02) << 7) |
1349 ((s
->cr
[0x07] & 0x40) << 3);
1350 height
= (height
+ 1);
1353 shift_control
= (s
->gr
[0x05] >> 5) & 3;
1354 double_scan
= (s
->cr
[0x09] & 0x80);
1355 if (shift_control
> 1) {
1356 multi_scan
= (s
->cr
[0x09] & 0x1f);
1360 multi_run
= multi_scan
;
1361 if (shift_control
!= s
->shift_control
||
1362 double_scan
!= s
->double_scan
) {
1364 s
->shift_control
= shift_control
;
1365 s
->double_scan
= double_scan
;
1368 if (shift_control
== 0) {
1369 full_update
|= update_palette16(s
);
1370 if (s
->sr
[0x01] & 8) {
1371 v
= VGA_DRAW_LINE4D2
;
1376 } else if (shift_control
== 1) {
1377 full_update
|= update_palette16(s
);
1378 if (s
->sr
[0x01] & 8) {
1379 v
= VGA_DRAW_LINE2D2
;
1385 #ifdef CONFIG_BOCHS_VBE
1386 if (s
->vbe_regs
[VBE_DISPI_INDEX_ENABLE
] & VBE_DISPI_ENABLED
) {
1387 switch(s
->vbe_regs
[VBE_DISPI_INDEX_BPP
]) {
1390 full_update
|= update_palette256(s
);
1394 v
= VGA_DRAW_LINE15
;
1397 v
= VGA_DRAW_LINE16
;
1400 v
= VGA_DRAW_LINE24
;
1403 v
= VGA_DRAW_LINE32
;
1409 full_update
|= update_palette256(s
);
1410 v
= VGA_DRAW_LINE8D2
;
1413 vga_draw_line
= vga_draw_line_table
[v
* 4 + get_depth_index(s
->ds
->depth
)];
1415 if (disp_width
!= s
->last_width
||
1416 height
!= s
->last_height
) {
1417 dpy_resize(s
->ds
, disp_width
, height
);
1418 s
->last_scr_width
= disp_width
;
1419 s
->last_scr_height
= height
;
1420 s
->last_width
= disp_width
;
1421 s
->last_height
= height
;
1425 line_offset
= s
->line_offset
;
1427 printf("w=%d h=%d v=%d line_offset=%d double_scan=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=%02x\n",
1428 width
, height
, v
, line_offset
, s
->cr
[9], s
->cr
[0x17], s
->line_compare
, s
->sr
[0x01]);
1430 addr1
= (s
->start_addr
* 4);
1433 page_min
= 0x7fffffff;
1436 linesize
= s
->ds
->linesize
;
1438 for(y
= 0; y
< height
; y
++) {
1440 if (!(s
->cr
[0x17] & 1)) {
1442 /* CGA compatibility handling */
1443 shift
= 14 + ((s
->cr
[0x17] >> 6) & 1);
1444 addr
= (addr
& ~(1 << shift
)) | ((y1
& 1) << shift
);
1446 if (!(s
->cr
[0x17] & 2)) {
1447 addr
= (addr
& ~0x8000) | ((y1
& 2) << 14);
1449 page0
= s
->vram_offset
+ (addr
& TARGET_PAGE_MASK
);
1450 page1
= s
->vram_offset
+ ((addr
+ bwidth
- 1) & TARGET_PAGE_MASK
);
1451 update
= full_update
| cpu_physical_memory_is_dirty(page0
) |
1452 cpu_physical_memory_is_dirty(page1
);
1453 if ((page1
- page0
) > TARGET_PAGE_SIZE
) {
1454 /* if wide line, can use another page */
1455 update
|= cpu_physical_memory_is_dirty(page0
+ TARGET_PAGE_SIZE
);
1460 if (page0
< page_min
)
1462 if (page1
> page_max
)
1464 vga_draw_line(s
, d
, s
->vram_ptr
+ addr
, width
);
1467 /* flush to display */
1468 dpy_update(s
->ds
, 0, y_start
,
1469 disp_width
, y
- y_start
);
1474 if (!double_scan
|| (y
& 1) != 0) {
1475 if (y1
== s
->line_compare
) {
1478 mask
= (s
->cr
[0x17] & 3) ^ 3;
1479 if ((y1
& mask
) == mask
)
1480 addr1
+= line_offset
;
1484 multi_run
= multi_scan
;
1492 /* flush to display */
1493 dpy_update(s
->ds
, 0, y_start
,
1494 disp_width
, y
- y_start
);
1496 /* reset modified pages */
1497 if (page_max
!= -1) {
1498 cpu_physical_memory_reset_dirty(page_min
, page_max
+ TARGET_PAGE_SIZE
);
1502 static void vga_draw_blank(VGAState
*s
, int full_update
)
1509 if (s
->last_scr_width
<= 0 || s
->last_scr_height
<= 0)
1511 if (s
->ds
->depth
== 8)
1512 val
= s
->rgb_to_pixel(0, 0, 0);
1515 w
= s
->last_scr_width
* ((s
->ds
->depth
+ 7) >> 3);
1517 for(i
= 0; i
< s
->last_scr_height
; i
++) {
1519 d
+= s
->ds
->linesize
;
1521 dpy_update(s
->ds
, 0, 0,
1522 s
->last_scr_width
, s
->last_scr_height
);
1525 #define GMODE_TEXT 0
1526 #define GMODE_GRAPH 1
1527 #define GMODE_BLANK 2
1529 void vga_update_display(void)
1531 VGAState
*s
= &vga_state
;
1532 int full_update
, graphic_mode
;
1534 if (s
->ds
->depth
== 0) {
1537 switch(s
->ds
->depth
) {
1539 s
->rgb_to_pixel
= rgb_to_pixel8_dup
;
1542 s
->rgb_to_pixel
= rgb_to_pixel15_dup
;
1546 s
->rgb_to_pixel
= rgb_to_pixel16_dup
;
1549 s
->rgb_to_pixel
= rgb_to_pixel32_dup
;
1554 if (!(s
->ar_index
& 0x20)) {
1555 graphic_mode
= GMODE_BLANK
;
1557 graphic_mode
= s
->gr
[6] & 1;
1559 if (graphic_mode
!= s
->graphic_mode
) {
1560 s
->graphic_mode
= graphic_mode
;
1563 switch(graphic_mode
) {
1565 vga_draw_text(s
, full_update
);
1568 vga_draw_graphic(s
, full_update
);
1572 vga_draw_blank(s
, full_update
);
1578 static void vga_reset(VGAState
*s
)
1580 memset(s
, 0, sizeof(VGAState
));
1582 /* chip ID for 8c968 */
1585 s
->cr
[0x2f] = 0x01; /* XXX: check revision code */
1588 s
->graphic_mode
= -1; /* force full update */
1591 static CPUReadMemoryFunc
*vga_mem_read
[3] = {
1597 static CPUWriteMemoryFunc
*vga_mem_write
[3] = {
1603 static void vga_save(QEMUFile
*f
, void *opaque
)
1605 VGAState
*s
= opaque
;
1608 qemu_put_be32s(f
, &s
->latch
);
1609 qemu_put_8s(f
, &s
->sr_index
);
1610 qemu_put_buffer(f
, s
->sr
, 8);
1611 qemu_put_8s(f
, &s
->gr_index
);
1612 qemu_put_buffer(f
, s
->gr
, 16);
1613 qemu_put_8s(f
, &s
->ar_index
);
1614 qemu_put_buffer(f
, s
->ar
, 21);
1615 qemu_put_be32s(f
, &s
->ar_flip_flop
);
1616 qemu_put_8s(f
, &s
->cr_index
);
1617 qemu_put_buffer(f
, s
->cr
, 256);
1618 qemu_put_8s(f
, &s
->msr
);
1619 qemu_put_8s(f
, &s
->fcr
);
1620 qemu_put_8s(f
, &s
->st00
);
1621 qemu_put_8s(f
, &s
->st01
);
1623 qemu_put_8s(f
, &s
->dac_state
);
1624 qemu_put_8s(f
, &s
->dac_sub_index
);
1625 qemu_put_8s(f
, &s
->dac_read_index
);
1626 qemu_put_8s(f
, &s
->dac_write_index
);
1627 qemu_put_buffer(f
, s
->dac_cache
, 3);
1628 qemu_put_buffer(f
, s
->palette
, 768);
1630 qemu_put_be32s(f
, &s
->bank_offset
);
1631 #ifdef CONFIG_BOCHS_VBE
1632 qemu_put_byte(f
, 1);
1633 qemu_put_be16s(f
, &s
->vbe_index
);
1634 for(i
= 0; i
< VBE_DISPI_INDEX_NB
; i
++)
1635 qemu_put_be16s(f
, &s
->vbe_regs
[i
]);
1636 qemu_put_be32s(f
, &s
->vbe_start_addr
);
1637 qemu_put_be32s(f
, &s
->vbe_line_offset
);
1638 qemu_put_be32s(f
, &s
->vbe_bank_mask
);
1640 qemu_put_byte(f
, 0);
1644 static int vga_load(QEMUFile
*f
, void *opaque
, int version_id
)
1646 VGAState
*s
= opaque
;
1649 if (version_id
!= 1)
1652 qemu_get_be32s(f
, &s
->latch
);
1653 qemu_get_8s(f
, &s
->sr_index
);
1654 qemu_get_buffer(f
, s
->sr
, 8);
1655 qemu_get_8s(f
, &s
->gr_index
);
1656 qemu_get_buffer(f
, s
->gr
, 16);
1657 qemu_get_8s(f
, &s
->ar_index
);
1658 qemu_get_buffer(f
, s
->ar
, 21);
1659 qemu_get_be32s(f
, &s
->ar_flip_flop
);
1660 qemu_get_8s(f
, &s
->cr_index
);
1661 qemu_get_buffer(f
, s
->cr
, 256);
1662 qemu_get_8s(f
, &s
->msr
);
1663 qemu_get_8s(f
, &s
->fcr
);
1664 qemu_get_8s(f
, &s
->st00
);
1665 qemu_get_8s(f
, &s
->st01
);
1667 qemu_get_8s(f
, &s
->dac_state
);
1668 qemu_get_8s(f
, &s
->dac_sub_index
);
1669 qemu_get_8s(f
, &s
->dac_read_index
);
1670 qemu_get_8s(f
, &s
->dac_write_index
);
1671 qemu_get_buffer(f
, s
->dac_cache
, 3);
1672 qemu_get_buffer(f
, s
->palette
, 768);
1674 qemu_get_be32s(f
, &s
->bank_offset
);
1675 is_vbe
= qemu_get_byte(f
);
1676 #ifdef CONFIG_BOCHS_VBE
1679 qemu_get_be16s(f
, &s
->vbe_index
);
1680 for(i
= 0; i
< VBE_DISPI_INDEX_NB
; i
++)
1681 qemu_get_be16s(f
, &s
->vbe_regs
[i
]);
1682 qemu_get_be32s(f
, &s
->vbe_start_addr
);
1683 qemu_get_be32s(f
, &s
->vbe_line_offset
);
1684 qemu_get_be32s(f
, &s
->vbe_bank_mask
);
1691 s
->graphic_mode
= -1;
1695 int vga_initialize(DisplayState
*ds
, uint8_t *vga_ram_base
,
1696 unsigned long vga_ram_offset
, int vga_ram_size
)
1698 VGAState
*s
= &vga_state
;
1701 for(i
= 0;i
< 256; i
++) {
1703 for(j
= 0; j
< 8; j
++) {
1704 v
|= ((i
>> j
) & 1) << (j
* 4);
1709 for(j
= 0; j
< 4; j
++) {
1710 v
|= ((i
>> (2 * j
)) & 3) << (j
* 4);
1714 for(i
= 0; i
< 16; i
++) {
1716 for(j
= 0; j
< 4; j
++) {
1719 v
|= b
<< (2 * j
+ 1);
1726 s
->vram_ptr
= vga_ram_base
;
1727 s
->vram_offset
= vga_ram_offset
;
1728 s
->vram_size
= vga_ram_size
;
1731 register_savevm("vga", 0, 1, vga_save
, vga_load
, s
);
1733 register_ioport_write(0x3c0, 16, 1, vga_ioport_write
, s
);
1735 register_ioport_write(0x3b4, 2, 1, vga_ioport_write
, s
);
1736 register_ioport_write(0x3d4, 2, 1, vga_ioport_write
, s
);
1737 register_ioport_write(0x3ba, 1, 1, vga_ioport_write
, s
);
1738 register_ioport_write(0x3da, 1, 1, vga_ioport_write
, s
);
1740 register_ioport_read(0x3c0, 16, 1, vga_ioport_read
, s
);
1742 register_ioport_read(0x3b4, 2, 1, vga_ioport_read
, s
);
1743 register_ioport_read(0x3d4, 2, 1, vga_ioport_read
, s
);
1744 register_ioport_read(0x3ba, 1, 1, vga_ioport_read
, s
);
1745 register_ioport_read(0x3da, 1, 1, vga_ioport_read
, s
);
1746 s
->bank_offset
= -0xa0000;
1748 #ifdef CONFIG_BOCHS_VBE
1749 s
->vbe_regs
[VBE_DISPI_INDEX_ID
] = VBE_DISPI_ID0
;
1750 s
->vbe_bank_mask
= ((s
->vram_size
>> 16) - 1);
1751 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read
, s
);
1752 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read
, s
);
1754 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write
, s
);
1755 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write
, s
);
1758 vga_io_memory
= cpu_register_io_memory(0, vga_mem_read
, vga_mem_write
);
1759 #if defined (TARGET_I386)
1760 cpu_register_physical_memory(0x000a0000, 0x20000, vga_io_memory
);
1761 #ifdef CONFIG_BOCHS_VBE
1762 /* XXX: use optimized standard vga accesses */
1763 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS
,
1764 vga_ram_size
, vga_ram_offset
);
1766 #elif defined (TARGET_PPC)
1767 cpu_register_physical_memory(0xf00a0000, 0x20000, vga_io_memory
);
1772 /********************************************************/
1773 /* vga screen dump */
1775 static int vga_save_w
, vga_save_h
;
1777 static void vga_save_dpy_update(DisplayState
*s
,
1778 int x
, int y
, int w
, int h
)
1782 static void vga_save_dpy_resize(DisplayState
*s
, int w
, int h
)
1784 s
->linesize
= w
* 4;
1785 s
->data
= qemu_malloc(h
* s
->linesize
);
1790 static void vga_save_dpy_refresh(DisplayState
*s
)
1794 static int ppm_save(const char *filename
, uint8_t *data
,
1795 int w
, int h
, int linesize
)
1802 f
= fopen(filename
, "wb");
1805 fprintf(f
, "P6\n%d %d\n%d\n",
1808 for(y
= 0; y
< h
; y
++) {
1810 for(x
= 0; x
< w
; x
++) {
1812 fputc((v
>> 16) & 0xff, f
);
1813 fputc((v
>> 8) & 0xff, f
);
1814 fputc((v
) & 0xff, f
);
1823 /* save the vga display in a PPM image even if no display is
1825 void vga_screen_dump(const char *filename
)
1827 VGAState
*s
= &vga_state
;
1828 DisplayState
*saved_ds
, ds1
, *ds
= &ds1
;
1830 /* XXX: this is a little hackish */
1832 s
->last_height
= -1;
1835 memset(ds
, 0, sizeof(DisplayState
));
1836 ds
->dpy_update
= vga_save_dpy_update
;
1837 ds
->dpy_resize
= vga_save_dpy_resize
;
1838 ds
->dpy_refresh
= vga_save_dpy_refresh
;
1842 s
->graphic_mode
= -1;
1843 vga_update_display();
1846 ppm_save(filename
, ds
->data
, vga_save_w
, vga_save_h
,
1848 qemu_free(ds
->data
);