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 */
601 s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
602 s->cr[0x09] &= ~0x9f; /* no double scan */
603 s->vbe_regs[s->vbe_index] = val;
605 /* XXX: the bios should do that */
609 case VBE_DISPI_INDEX_VIRT_WIDTH:
611 int w, h, line_offset;
613 if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
616 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
617 line_offset = w >> 1;
619 line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
620 h = s->vram_size / line_offset;
621 /* XXX: support weird bochs semantics ? */
622 if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
624 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
625 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
626 s->vbe_line_offset = line_offset;
629 case VBE_DISPI_INDEX_X_OFFSET:
630 case VBE_DISPI_INDEX_Y_OFFSET:
633 s->vbe_regs[s->vbe_index] = val;
634 s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
635 x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
636 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
637 s->vbe_start_addr += x >> 1;
639 s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
640 s->vbe_start_addr >>= 2;
650 /* called for accesses between 0xa0000 and 0xc0000 */
651 static uint32_t vga_mem_readb(target_phys_addr_t addr)
653 VGAState *s = &vga_state;
654 int memory_map_mode, plane;
657 /* convert to VGA memory offset */
658 memory_map_mode = (s->gr[6] >> 2) & 3;
660 switch(memory_map_mode) {
666 addr += s->bank_offset;
681 if (s->sr[4] & 0x08) {
682 /* chain 4 mode : simplest access */
683 ret = s->vram_ptr[addr];
684 } else if (s->gr[5] & 0x10) {
685 /* odd/even mode (aka text mode mapping) */
686 plane = (s->gr[4] & 2) | (addr & 1);
687 ret = s->vram_ptr[((addr & ~1) << 1) | plane];
689 /* standard VGA latched access */
690 s->latch = ((uint32_t *)s->vram_ptr)[addr];
692 if (!(s->gr[5] & 0x08)) {
695 ret = GET_PLANE(s->latch, plane);
698 ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
707 static uint32_t vga_mem_readw(target_phys_addr_t addr)
710 v = vga_mem_readb(addr);
711 v |= vga_mem_readb(addr + 1) << 8;
715 static uint32_t vga_mem_readl(target_phys_addr_t addr)
718 v = vga_mem_readb(addr);
719 v |= vga_mem_readb(addr + 1) << 8;
720 v |= vga_mem_readb(addr + 2) << 16;
721 v |= vga_mem_readb(addr + 3) << 24;
725 /* called for accesses between 0xa0000 and 0xc0000 */
726 static void vga_mem_writeb(target_phys_addr_t addr, uint32_t val)
728 VGAState *s = &vga_state;
729 int memory_map_mode, plane, write_mode, b, func_select;
730 uint32_t write_mask, bit_mask, set_mask;
733 printf("vga: [0x%x] = 0x%02x\n", addr, val);
735 /* convert to VGA memory offset */
736 memory_map_mode = (s->gr[6] >> 2) & 3;
738 switch(memory_map_mode) {
744 addr += s->bank_offset;
759 if (s->sr[4] & 0x08) {
760 /* chain 4 mode : simplest access */
762 if (s->sr[2] & (1 << plane)) {
763 s->vram_ptr[addr] = val;
765 printf("vga: chain4: [0x%x]\n", addr);
767 cpu_physical_memory_set_dirty(s->vram_offset + addr);
769 } else if (s->gr[5] & 0x10) {
770 /* odd/even mode (aka text mode mapping) */
771 plane = (s->gr[4] & 2) | (addr & 1);
772 if (s->sr[2] & (1 << plane)) {
773 addr = ((addr & ~1) << 1) | plane;
774 s->vram_ptr[addr] = val;
776 printf("vga: odd/even: [0x%x]\n", addr);
778 cpu_physical_memory_set_dirty(s->vram_offset + addr);
781 /* standard VGA latched access */
782 write_mode = s->gr[5] & 3;
788 val = ((val >> b) | (val << (8 - b))) & 0xff;
792 /* apply set/reset mask */
793 set_mask = mask16[s->gr[1]];
794 val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
801 val = mask16[val & 0x0f];
807 val = (val >> b) | (val << (8 - b));
809 bit_mask = s->gr[8] & val;
810 val = mask16[s->gr[0]];
814 /* apply logical operation */
815 func_select = s->gr[3] >> 3;
816 switch(func_select) {
836 bit_mask |= bit_mask << 8;
837 bit_mask |= bit_mask << 16;
838 val = (val & bit_mask) | (s->latch & ~bit_mask);
841 /* mask data according to sr[2] */
842 write_mask = mask16[s->sr[2]];
843 ((uint32_t *)s->vram_ptr)[addr] =
844 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
847 printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
848 addr * 4, write_mask, val);
850 cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
854 static void vga_mem_writew(target_phys_addr_t addr, uint32_t val)
856 vga_mem_writeb(addr, val & 0xff);
857 vga_mem_writeb(addr + 1, (val >> 8) & 0xff);
860 static void vga_mem_writel(target_phys_addr_t addr, uint32_t val)
862 vga_mem_writeb(addr, val & 0xff);
863 vga_mem_writeb(addr + 1, (val >> 8) & 0xff);
864 vga_mem_writeb(addr + 2, (val >> 16) & 0xff);
865 vga_mem_writeb(addr + 3, (val >> 24) & 0xff);
868 typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
869 const uint8_t *font_ptr, int h,
870 uint32_t fgcol, uint32_t bgcol);
871 typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
872 const uint8_t *font_ptr, int h,
873 uint32_t fgcol, uint32_t bgcol, int dup9);
874 typedef void vga_draw_line_func(VGAState *s1, uint8_t *d,
875 const uint8_t *s, int width);
877 static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
883 static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
885 return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
888 static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
890 return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
893 static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
895 return (r << 16) | (g << 8) | b;
899 #include "vga_template.h"
902 #include "vga_template.h"
905 #include "vga_template.h"
908 #include "vga_template.h"
910 static inline int c6_to_8(int v)
915 return (v << 2) | (b << 1) | b;
918 static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
921 col = rgb_to_pixel8(r, g, b);
927 static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
930 col = rgb_to_pixel15(r, g, b);
935 static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
938 col = rgb_to_pixel16(r, g, b);
943 static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
946 col = rgb_to_pixel32(r, g, b);
950 /* return true if the palette was modified */
951 static int update_palette16(VGAState *s)
954 uint32_t v, col, *palette;
957 palette = s->last_palette;
958 for(i = 0; i < 16; i++) {
960 if (s->ar[0x10] & 0x80)
961 v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
963 v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
965 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
966 c6_to_8(s->palette[v + 1]),
967 c6_to_8(s->palette[v + 2]));
968 if (col != palette[i]) {
976 /* return true if the palette was modified */
977 static int update_palette256(VGAState *s)
980 uint32_t v, col, *palette;
983 palette = s->last_palette;
985 for(i = 0; i < 256; i++) {
986 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
987 c6_to_8(s->palette[v + 1]),
988 c6_to_8(s->palette[v + 2]));
989 if (col != palette[i]) {
998 /* update start_addr and line_offset. Return TRUE if modified */
999 static int update_basic_params(VGAState *s)
1002 uint32_t start_addr, line_offset, line_compare;
1006 #ifdef CONFIG_BOCHS_VBE
1007 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1008 line_offset = s->vbe_line_offset;
1009 start_addr = s->vbe_start_addr;
1013 /* compute line_offset in bytes */
1014 line_offset = s->cr[0x13];
1018 v = (s->cr[0x51] >> 4) & 3; /* S3 extension */
1020 v = (s->cr[0x43] >> 2) & 1; /* S3 extension */
1021 line_offset |= (v << 8);
1026 /* starting address */
1027 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
1029 start_addr |= (s->cr[0x69] & 0x1f) << 16; /* S3 extension */
1034 line_compare = s->cr[0x18] |
1035 ((s->cr[0x07] & 0x10) << 4) |
1036 ((s->cr[0x09] & 0x40) << 3);
1038 if (line_offset != s->line_offset ||
1039 start_addr != s->start_addr ||
1040 line_compare != s->line_compare) {
1041 s->line_offset = line_offset;
1042 s->start_addr = start_addr;
1043 s->line_compare = line_compare;
1049 static inline int get_depth_index(int depth)
1064 static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = {
1071 static vga_draw_glyph8_func *vga_draw_glyph16_table[4] = {
1073 vga_draw_glyph16_16,
1074 vga_draw_glyph16_16,
1075 vga_draw_glyph16_32,
1078 static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = {
1085 static const uint8_t cursor_glyph[32 * 4] = {
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,
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,
1112 static void vga_draw_text(VGAState *s, int full_update)
1114 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1115 int cx_min, cx_max, linesize, x_incr;
1116 uint32_t offset, fgcol, bgcol, v, cursor_offset;
1117 uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
1118 const uint8_t *font_ptr, *font_base[2];
1119 int dup9, line_offset, depth_index;
1121 uint32_t *ch_attr_ptr;
1122 vga_draw_glyph8_func *vga_draw_glyph8;
1123 vga_draw_glyph9_func *vga_draw_glyph9;
1125 full_update |= update_palette16(s);
1126 palette = s->last_palette;
1128 /* compute font data address (in plane 2) */
1130 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1131 if (offset != s->font_offsets[0]) {
1132 s->font_offsets[0] = offset;
1135 font_base[0] = s->vram_ptr + offset;
1137 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1138 font_base[1] = s->vram_ptr + offset;
1139 if (offset != s->font_offsets[1]) {
1140 s->font_offsets[1] = offset;
1144 full_update |= update_basic_params(s);
1146 line_offset = s->line_offset;
1147 s1 = s->vram_ptr + (s->start_addr * 4);
1149 /* total width & height */
1150 cheight = (s->cr[9] & 0x1f) + 1;
1152 if (!(s->sr[1] & 0x01))
1154 if (s->sr[1] & 0x08)
1155 cw = 16; /* NOTE: no 18 pixel wide */
1156 x_incr = cw * ((s->ds->depth + 7) >> 3);
1157 width = (s->cr[0x01] + 1);
1158 if (s->cr[0x06] == 100) {
1159 /* ugly hack for CGA 160x100x16 - explain me the logic */
1162 height = s->cr[0x12] |
1163 ((s->cr[0x07] & 0x02) << 7) |
1164 ((s->cr[0x07] & 0x40) << 3);
1165 height = (height + 1) / cheight;
1167 if ((height * width) > CH_ATTR_SIZE) {
1168 /* better than nothing: exit if transient size is too big */
1172 if (width != s->last_width || height != s->last_height ||
1173 cw != s->last_cw || cheight != s->last_ch) {
1174 s->last_scr_width = width * cw;
1175 s->last_scr_height = height * cheight;
1176 dpy_resize(s->ds, s->last_scr_width, s->last_scr_height);
1177 s->last_width = width;
1178 s->last_height = height;
1179 s->last_ch = cheight;
1183 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1184 if (cursor_offset != s->cursor_offset ||
1185 s->cr[0xa] != s->cursor_start ||
1186 s->cr[0xb] != s->cursor_end) {
1187 /* if the cursor position changed, we update the old and new
1189 if (s->cursor_offset < CH_ATTR_SIZE)
1190 s->last_ch_attr[s->cursor_offset] = -1;
1191 if (cursor_offset < CH_ATTR_SIZE)
1192 s->last_ch_attr[cursor_offset] = -1;
1193 s->cursor_offset = cursor_offset;
1194 s->cursor_start = s->cr[0xa];
1195 s->cursor_end = s->cr[0xb];
1197 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
1199 depth_index = get_depth_index(s->ds->depth);
1201 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1203 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
1204 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1207 linesize = s->ds->linesize;
1208 ch_attr_ptr = s->last_ch_attr;
1209 for(cy = 0; cy < height; cy++) {
1214 for(cx = 0; cx < width; cx++) {
1215 ch_attr = *(uint16_t *)src;
1216 if (full_update || ch_attr != *ch_attr_ptr) {
1221 *ch_attr_ptr = ch_attr;
1222 #ifdef WORDS_BIGENDIAN
1224 cattr = ch_attr & 0xff;
1226 ch = ch_attr & 0xff;
1227 cattr = ch_attr >> 8;
1229 font_ptr = font_base[(cattr >> 3) & 1];
1230 font_ptr += 32 * 4 * ch;
1231 bgcol = palette[cattr >> 4];
1232 fgcol = palette[cattr & 0x0f];
1234 vga_draw_glyph8(d1, linesize,
1235 font_ptr, cheight, fgcol, bgcol);
1238 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1240 vga_draw_glyph9(d1, linesize,
1241 font_ptr, cheight, fgcol, bgcol, dup9);
1243 if (src == cursor_ptr &&
1244 !(s->cr[0x0a] & 0x20)) {
1245 int line_start, line_last, h;
1246 /* draw the cursor */
1247 line_start = s->cr[0x0a] & 0x1f;
1248 line_last = s->cr[0x0b] & 0x1f;
1249 /* XXX: check that */
1250 if (line_last > cheight - 1)
1251 line_last = cheight - 1;
1252 if (line_last >= line_start && line_start < cheight) {
1253 h = line_last - line_start + 1;
1254 d = d1 + linesize * line_start;
1256 vga_draw_glyph8(d, linesize,
1257 cursor_glyph, h, fgcol, bgcol);
1259 vga_draw_glyph9(d, linesize,
1260 cursor_glyph, h, fgcol, bgcol, 1);
1270 dpy_update(s->ds, cx_min * cw, cy * cheight,
1271 (cx_max - cx_min + 1) * cw, cheight);
1273 dest += linesize * cheight;
1292 static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = {
1299 vga_draw_line2d2_16,
1300 vga_draw_line2d2_16,
1301 vga_draw_line2d2_32,
1309 vga_draw_line4d2_16,
1310 vga_draw_line4d2_16,
1311 vga_draw_line4d2_32,
1314 vga_draw_line8d2_16,
1315 vga_draw_line8d2_16,
1316 vga_draw_line8d2_32,
1350 static void vga_draw_graphic(VGAState *s, int full_update)
1352 int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask;
1353 int width, height, shift_control, line_offset, page0, page1, bwidth;
1354 int disp_width, multi_scan, multi_run;
1356 uint32_t v, addr1, addr;
1357 vga_draw_line_func *vga_draw_line;
1359 full_update |= update_basic_params(s);
1361 width = (s->cr[0x01] + 1) * 8;
1362 height = s->cr[0x12] |
1363 ((s->cr[0x07] & 0x02) << 7) |
1364 ((s->cr[0x07] & 0x40) << 3);
1365 height = (height + 1);
1368 shift_control = (s->gr[0x05] >> 5) & 3;
1369 double_scan = (s->cr[0x09] & 0x80);
1370 if (shift_control > 1) {
1371 multi_scan = (s->cr[0x09] & 0x1f);
1375 multi_run = multi_scan;
1376 if (shift_control != s->shift_control ||
1377 double_scan != s->double_scan) {
1379 s->shift_control = shift_control;
1380 s->double_scan = double_scan;
1383 if (shift_control == 0) {
1384 full_update |= update_palette16(s);
1385 if (s->sr[0x01] & 8) {
1386 v = VGA_DRAW_LINE4D2;
1391 } else if (shift_control == 1) {
1392 full_update |= update_palette16(s);
1393 if (s->sr[0x01] & 8) {
1394 v = VGA_DRAW_LINE2D2;
1400 #ifdef CONFIG_BOCHS_VBE
1401 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1402 switch(s->vbe_regs[VBE_DISPI_INDEX_BPP]) {
1405 full_update |= update_palette256(s);
1409 v = VGA_DRAW_LINE15;
1412 v = VGA_DRAW_LINE16;
1415 v = VGA_DRAW_LINE24;
1418 v = VGA_DRAW_LINE32;
1424 full_update |= update_palette256(s);
1425 v = VGA_DRAW_LINE8D2;
1428 vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)];
1430 if (disp_width != s->last_width ||
1431 height != s->last_height) {
1432 dpy_resize(s->ds, disp_width, height);
1433 s->last_scr_width = disp_width;
1434 s->last_scr_height = height;
1435 s->last_width = disp_width;
1436 s->last_height = height;
1440 line_offset = s->line_offset;
1442 printf("w=%d h=%d v=%d line_offset=%d double_scan=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=%02x\n",
1443 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1445 addr1 = (s->start_addr * 4);
1448 page_min = 0x7fffffff;
1451 linesize = s->ds->linesize;
1453 for(y = 0; y < height; y++) {
1455 if (!(s->cr[0x17] & 1)) {
1457 /* CGA compatibility handling */
1458 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1459 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1461 if (!(s->cr[0x17] & 2)) {
1462 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1464 page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
1465 page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
1466 update = full_update | cpu_physical_memory_is_dirty(page0) |
1467 cpu_physical_memory_is_dirty(page1);
1468 if ((page1 - page0) > TARGET_PAGE_SIZE) {
1469 /* if wide line, can use another page */
1470 update |= cpu_physical_memory_is_dirty(page0 + TARGET_PAGE_SIZE);
1475 if (page0 < page_min)
1477 if (page1 > page_max)
1479 vga_draw_line(s, d, s->vram_ptr + addr, width);
1482 /* flush to display */
1483 dpy_update(s->ds, 0, y_start,
1484 disp_width, y - y_start);
1489 if (!double_scan || (y & 1) != 0) {
1490 if (y1 == s->line_compare) {
1493 mask = (s->cr[0x17] & 3) ^ 3;
1494 if ((y1 & mask) == mask)
1495 addr1 += line_offset;
1499 multi_run = multi_scan;
1507 /* flush to display */
1508 dpy_update(s->ds, 0, y_start,
1509 disp_width, y - y_start);
1511 /* reset modified pages */
1512 if (page_max != -1) {
1513 cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE);
1517 static void vga_draw_blank(VGAState *s, int full_update)
1524 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1526 if (s->ds->depth == 8)
1527 val = s->rgb_to_pixel(0, 0, 0);
1530 w = s->last_scr_width * ((s->ds->depth + 7) >> 3);
1532 for(i = 0; i < s->last_scr_height; i++) {
1534 d += s->ds->linesize;
1536 dpy_update(s->ds, 0, 0,
1537 s->last_scr_width, s->last_scr_height);
1540 #define GMODE_TEXT 0
1541 #define GMODE_GRAPH 1
1542 #define GMODE_BLANK 2
1544 void vga_update_display(void)
1546 VGAState *s = &vga_state;
1547 int full_update, graphic_mode;
1549 if (s->ds->depth == 0) {
1552 switch(s->ds->depth) {
1554 s->rgb_to_pixel = rgb_to_pixel8_dup;
1557 s->rgb_to_pixel = rgb_to_pixel15_dup;
1561 s->rgb_to_pixel = rgb_to_pixel16_dup;
1564 s->rgb_to_pixel = rgb_to_pixel32_dup;
1569 if (!(s->ar_index & 0x20)) {
1570 graphic_mode = GMODE_BLANK;
1572 graphic_mode = s->gr[6] & 1;
1574 if (graphic_mode != s->graphic_mode) {
1575 s->graphic_mode = graphic_mode;
1578 switch(graphic_mode) {
1580 vga_draw_text(s, full_update);
1583 vga_draw_graphic(s, full_update);
1587 vga_draw_blank(s, full_update);
1593 static void vga_reset(VGAState *s)
1595 memset(s, 0, sizeof(VGAState));
1597 /* chip ID for 8c968 */
1600 s->cr[0x2f] = 0x01; /* XXX: check revision code */
1603 s->graphic_mode = -1; /* force full update */
1606 static CPUReadMemoryFunc *vga_mem_read[3] = {
1612 static CPUWriteMemoryFunc *vga_mem_write[3] = {
1618 static void vga_save(QEMUFile *f, void *opaque)
1620 VGAState *s = opaque;
1623 qemu_put_be32s(f, &s->latch);
1624 qemu_put_8s(f, &s->sr_index);
1625 qemu_put_buffer(f, s->sr, 8);
1626 qemu_put_8s(f, &s->gr_index);
1627 qemu_put_buffer(f, s->gr, 16);
1628 qemu_put_8s(f, &s->ar_index);
1629 qemu_put_buffer(f, s->ar, 21);
1630 qemu_put_be32s(f, &s->ar_flip_flop);
1631 qemu_put_8s(f, &s->cr_index);
1632 qemu_put_buffer(f, s->cr, 256);
1633 qemu_put_8s(f, &s->msr);
1634 qemu_put_8s(f, &s->fcr);
1635 qemu_put_8s(f, &s->st00);
1636 qemu_put_8s(f, &s->st01);
1638 qemu_put_8s(f, &s->dac_state);
1639 qemu_put_8s(f, &s->dac_sub_index);
1640 qemu_put_8s(f, &s->dac_read_index);
1641 qemu_put_8s(f, &s->dac_write_index);
1642 qemu_put_buffer(f, s->dac_cache, 3);
1643 qemu_put_buffer(f, s->palette, 768);
1645 qemu_put_be32s(f, &s->bank_offset);
1646 #ifdef CONFIG_BOCHS_VBE
1647 qemu_put_byte(f, 1);
1648 qemu_put_be16s(f, &s->vbe_index);
1649 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1650 qemu_put_be16s(f, &s->vbe_regs[i]);
1651 qemu_put_be32s(f, &s->vbe_start_addr);
1652 qemu_put_be32s(f, &s->vbe_line_offset);
1653 qemu_put_be32s(f, &s->vbe_bank_mask);
1655 qemu_put_byte(f, 0);
1659 static int vga_load(QEMUFile *f, void *opaque, int version_id)
1661 VGAState *s = opaque;
1664 if (version_id != 1)
1667 qemu_get_be32s(f, &s->latch);
1668 qemu_get_8s(f, &s->sr_index);
1669 qemu_get_buffer(f, s->sr, 8);
1670 qemu_get_8s(f, &s->gr_index);
1671 qemu_get_buffer(f, s->gr, 16);
1672 qemu_get_8s(f, &s->ar_index);
1673 qemu_get_buffer(f, s->ar, 21);
1674 qemu_get_be32s(f, &s->ar_flip_flop);
1675 qemu_get_8s(f, &s->cr_index);
1676 qemu_get_buffer(f, s->cr, 256);
1677 qemu_get_8s(f, &s->msr);
1678 qemu_get_8s(f, &s->fcr);
1679 qemu_get_8s(f, &s->st00);
1680 qemu_get_8s(f, &s->st01);
1682 qemu_get_8s(f, &s->dac_state);
1683 qemu_get_8s(f, &s->dac_sub_index);
1684 qemu_get_8s(f, &s->dac_read_index);
1685 qemu_get_8s(f, &s->dac_write_index);
1686 qemu_get_buffer(f, s->dac_cache, 3);
1687 qemu_get_buffer(f, s->palette, 768);
1689 qemu_get_be32s(f, &s->bank_offset);
1690 is_vbe = qemu_get_byte(f);
1691 #ifdef CONFIG_BOCHS_VBE
1694 qemu_get_be16s(f, &s->vbe_index);
1695 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1696 qemu_get_be16s(f, &s->vbe_regs[i]);
1697 qemu_get_be32s(f, &s->vbe_start_addr);
1698 qemu_get_be32s(f, &s->vbe_line_offset);
1699 qemu_get_be32s(f, &s->vbe_bank_mask);
1706 s->graphic_mode = -1;
1710 int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base,
1711 unsigned long vga_ram_offset, int vga_ram_size)
1713 VGAState *s = &vga_state;
1716 for(i = 0;i < 256; i++) {
1718 for(j = 0; j < 8; j++) {
1719 v |= ((i >> j) & 1) << (j * 4);
1724 for(j = 0; j < 4; j++) {
1725 v |= ((i >> (2 * j)) & 3) << (j * 4);
1729 for(i = 0; i < 16; i++) {
1731 for(j = 0; j < 4; j++) {
1734 v |= b << (2 * j + 1);
1741 s->vram_ptr = vga_ram_base;
1742 s->vram_offset = vga_ram_offset;
1743 s->vram_size = vga_ram_size;
1746 register_savevm("vga", 0, 1, vga_save, vga_load, s);
1748 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
1750 register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
1751 register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
1752 register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
1753 register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
1755 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
1757 register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
1758 register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
1759 register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
1760 register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
1763 #ifdef CONFIG_BOCHS_VBE
1764 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
1765 s->vbe_bank_mask = ((s->vram_size >> 16) - 1);
1766 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read, s);
1767 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read, s);
1769 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write, s);
1770 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write, s);
1773 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write);
1774 cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
1776 #ifdef CONFIG_BOCHS_VBE
1777 #if defined (TARGET_I386)
1778 /* XXX: use optimized standard vga accesses */
1779 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
1780 vga_ram_size, vga_ram_offset);
1786 /********************************************************/
1787 /* vga screen dump */
1789 static int vga_save_w, vga_save_h;
1791 static void vga_save_dpy_update(DisplayState *s,
1792 int x, int y, int w, int h)
1796 static void vga_save_dpy_resize(DisplayState *s, int w, int h)
1798 s->linesize = w * 4;
1799 s->data = qemu_malloc(h * s->linesize);
1804 static void vga_save_dpy_refresh(DisplayState *s)
1808 static int ppm_save(const char *filename, uint8_t *data,
1809 int w, int h, int linesize)
1816 f = fopen(filename, "wb");
1819 fprintf(f, "P6\n%d %d\n%d\n",
1822 for(y = 0; y < h; y++) {
1824 for(x = 0; x < w; x++) {
1826 fputc((v >> 16) & 0xff, f);
1827 fputc((v >> 8) & 0xff, f);
1828 fputc((v) & 0xff, f);
1837 /* save the vga display in a PPM image even if no display is
1839 void vga_screen_dump(const char *filename)
1841 VGAState *s = &vga_state;
1842 DisplayState *saved_ds, ds1, *ds = &ds1;
1844 /* XXX: this is a little hackish */
1846 s->last_height = -1;
1849 memset(ds, 0, sizeof(DisplayState));
1850 ds->dpy_update = vga_save_dpy_update;
1851 ds->dpy_resize = vga_save_dpy_resize;
1852 ds->dpy_refresh = vga_save_dpy_refresh;
1856 s->graphic_mode = -1;
1857 vga_update_display();
1860 ppm_save(filename, ds->data, vga_save_w, vga_save_h,
1862 qemu_free(ds->data);