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
41 #include <netinet/in.h>
49 //#define DEBUG_VGA_MEM
50 //#define DEBUG_VGA_REG
53 //#define DEBUG_BOCHS_VBE
57 #define MSR_COLOR_EMULATION 0x01
58 #define MSR_PAGE_SELECT 0x20
60 #define ST01_V_RETRACE 0x08
61 #define ST01_DISP_ENABLE 0x01
63 /* bochs VBE support */
64 #define CONFIG_BOCHS_VBE
66 #define VBE_DISPI_MAX_XRES 1024
67 #define VBE_DISPI_MAX_YRES 768
69 #define VBE_DISPI_INDEX_ID 0x0
70 #define VBE_DISPI_INDEX_XRES 0x1
71 #define VBE_DISPI_INDEX_YRES 0x2
72 #define VBE_DISPI_INDEX_BPP 0x3
73 #define VBE_DISPI_INDEX_ENABLE 0x4
74 #define VBE_DISPI_INDEX_BANK 0x5
75 #define VBE_DISPI_INDEX_VIRT_WIDTH 0x6
76 #define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
77 #define VBE_DISPI_INDEX_X_OFFSET 0x8
78 #define VBE_DISPI_INDEX_Y_OFFSET 0x9
79 #define VBE_DISPI_INDEX_NB 0xa
81 #define VBE_DISPI_ID0 0xB0C0
82 #define VBE_DISPI_ID1 0xB0C1
83 #define VBE_DISPI_ID2 0xB0C2
85 #define VBE_DISPI_DISABLED 0x00
86 #define VBE_DISPI_ENABLED 0x01
87 #define VBE_DISPI_LFB_ENABLED 0x40
88 #define VBE_DISPI_NOCLEARMEM 0x80
90 #define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000
92 typedef struct VGAState {
94 unsigned long vram_offset;
95 unsigned int vram_size;
105 uint8_t cr[256]; /* CRT registers */
106 uint8_t msr; /* Misc Output Register */
107 uint8_t fcr; /* Feature Control Register */
108 uint8_t st00; /* status 0 */
109 uint8_t st01; /* status 1 */
111 uint8_t dac_sub_index;
112 uint8_t dac_read_index;
113 uint8_t dac_write_index;
114 uint8_t dac_cache[3]; /* used when writing */
115 uint8_t palette[768];
116 uint32_t bank_offset;
117 #ifdef CONFIG_BOCHS_VBE
119 uint16_t vbe_regs[VBE_DISPI_INDEX_NB];
120 uint32_t vbe_start_addr;
121 uint32_t vbe_line_offset;
122 uint32_t vbe_bank_mask;
124 /* display refresh support */
126 uint32_t font_offsets[2];
128 uint8_t shift_control;
130 uint32_t line_offset;
131 uint32_t line_compare;
133 uint8_t last_cw, last_ch;
134 uint32_t last_width, last_height;
135 uint8_t cursor_start, cursor_end;
136 uint32_t cursor_offset;
137 unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned b);
138 /* tell for each page if it has been updated since the last time */
139 uint32_t last_palette[256];
140 #define CH_ATTR_SIZE (160 * 100)
141 uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */
144 /* force some bits to zero */
145 static const uint8_t sr_mask[8] = {
156 static const uint8_t gr_mask[16] = {
157 (uint8_t)~0xf0, /* 0x00 */
158 (uint8_t)~0xf0, /* 0x01 */
159 (uint8_t)~0xf0, /* 0x02 */
160 (uint8_t)~0xe0, /* 0x03 */
161 (uint8_t)~0xfc, /* 0x04 */
162 (uint8_t)~0x84, /* 0x05 */
163 (uint8_t)~0xf0, /* 0x06 */
164 (uint8_t)~0xf0, /* 0x07 */
165 (uint8_t)~0x00, /* 0x08 */
166 (uint8_t)~0xff, /* 0x09 */
167 (uint8_t)~0xff, /* 0x0a */
168 (uint8_t)~0xff, /* 0x0b */
169 (uint8_t)~0xff, /* 0x0c */
170 (uint8_t)~0xff, /* 0x0d */
171 (uint8_t)~0xff, /* 0x0e */
172 (uint8_t)~0xff, /* 0x0f */
175 #define cbswap_32(__x) \
177 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
178 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
179 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
180 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
182 #ifdef WORDS_BIGENDIAN
183 #define PAT(x) cbswap_32(x)
188 #ifdef WORDS_BIGENDIAN
194 #ifdef WORDS_BIGENDIAN
195 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
197 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
200 static const uint32_t mask16[16] = {
221 #ifdef WORDS_BIGENDIAN
224 #define PAT(x) cbswap_32(x)
227 static const uint32_t dmask16[16] = {
246 static const uint32_t dmask4[4] = {
253 static uint32_t expand4[256];
254 static uint16_t expand2[256];
255 static uint8_t expand4to8[16];
260 static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
262 VGAState *s = opaque;
265 /* check port range access depending on color/monochrome mode */
266 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
267 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) {
272 if (s->ar_flip_flop == 0) {
279 index = s->ar_index & 0x1f;
292 val = s->sr[s->sr_index];
294 printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
301 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
302 if (++s->dac_sub_index == 3) {
303 s->dac_sub_index = 0;
317 val = s->gr[s->gr_index];
319 printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
328 val = s->cr[s->cr_index];
330 printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
333 if (s->cr_index >= 0x20)
334 printf("S3: CR read index=0x%x val=0x%x\n",
340 /* just toggle to fool polling */
341 s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE;
350 #if defined(DEBUG_VGA)
351 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
356 static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
358 VGAState *s = opaque;
361 /* check port range access depending on color/monochrome mode */
362 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
363 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION)))
367 printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
372 if (s->ar_flip_flop == 0) {
376 index = s->ar_index & 0x1f;
379 s->ar[index] = val & 0x3f;
382 s->ar[index] = val & ~0x10;
388 s->ar[index] = val & ~0xc0;
391 s->ar[index] = val & ~0xf0;
394 s->ar[index] = val & ~0xf0;
400 s->ar_flip_flop ^= 1;
403 s->msr = val & ~0x10;
406 s->sr_index = val & 7;
410 printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
412 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
415 s->dac_read_index = val;
416 s->dac_sub_index = 0;
420 s->dac_write_index = val;
421 s->dac_sub_index = 0;
425 s->dac_cache[s->dac_sub_index] = val;
426 if (++s->dac_sub_index == 3) {
427 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
428 s->dac_sub_index = 0;
429 s->dac_write_index++;
433 s->gr_index = val & 0x0f;
437 printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
439 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
448 printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
450 /* handle CR0-7 protection */
451 if ((s->cr[11] & 0x80) && s->cr_index <= 7) {
452 /* can always write bit 4 of CR7 */
453 if (s->cr_index == 7)
454 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
457 switch(s->cr_index) {
458 case 0x01: /* horizontal display end */
463 case 0x12: /* veritcal display end */
464 s->cr[s->cr_index] = val;
473 /* chip ID, cannot write */
476 /* update start address */
477 s->cr[s->cr_index] = val;
479 s->cr[0x69] = (s->cr[69] & ~0x03) | v;
482 /* update start address */
483 s->cr[s->cr_index] = val;
485 s->cr[0x69] = (s->cr[69] & ~0x0c) | (v << 2);
489 s->cr[s->cr_index] = val;
493 if (s->cr_index >= 0x20)
494 printf("S3: CR write index=0x%x val=0x%x\n",
505 #ifdef CONFIG_BOCHS_VBE
506 static uint32_t vbe_ioport_read(void *opaque, uint32_t addr)
508 VGAState *s = opaque;
515 if (s->vbe_index <= VBE_DISPI_INDEX_NB)
516 val = s->vbe_regs[s->vbe_index];
519 #ifdef DEBUG_BOCHS_VBE
520 printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
526 static void vbe_ioport_write(void *opaque, uint32_t addr, uint32_t val)
528 VGAState *s = opaque;
533 } else if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
534 #ifdef DEBUG_BOCHS_VBE
535 printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
537 switch(s->vbe_index) {
538 case VBE_DISPI_INDEX_ID:
539 if (val == VBE_DISPI_ID0 ||
540 val == VBE_DISPI_ID1 ||
541 val == VBE_DISPI_ID2) {
542 s->vbe_regs[s->vbe_index] = val;
545 case VBE_DISPI_INDEX_XRES:
546 if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
547 s->vbe_regs[s->vbe_index] = val;
550 case VBE_DISPI_INDEX_YRES:
551 if (val <= VBE_DISPI_MAX_YRES) {
552 s->vbe_regs[s->vbe_index] = val;
555 case VBE_DISPI_INDEX_BPP:
558 if (val == 4 || val == 8 || val == 15 ||
559 val == 16 || val == 24 || val == 32) {
560 s->vbe_regs[s->vbe_index] = val;
563 case VBE_DISPI_INDEX_BANK:
564 val &= s->vbe_bank_mask;
565 s->vbe_regs[s->vbe_index] = val;
566 s->bank_offset = (val << 16) - 0xa0000;
568 case VBE_DISPI_INDEX_ENABLE:
569 if (val & VBE_DISPI_ENABLED) {
570 int h, shift_control;
572 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
573 s->vbe_regs[VBE_DISPI_INDEX_XRES];
574 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
575 s->vbe_regs[VBE_DISPI_INDEX_YRES];
576 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
577 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
579 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
580 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
582 s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
583 ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
584 s->vbe_start_addr = 0;
586 /* clear the screen (should be done in BIOS) */
587 if (!(val & VBE_DISPI_NOCLEARMEM)) {
588 memset(s->vram_ptr, 0,
589 s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
592 /* we initialize the VGA graphic mode (should be done
594 s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
595 s->cr[0x17] |= 3; /* no CGA modes */
596 s->cr[0x13] = s->vbe_line_offset >> 3;
598 s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
600 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
602 s->cr[0x07] = (s->cr[0x07] & ~0x42) |
603 ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
604 /* line compare to 1023 */
609 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
611 s->sr[0x01] &= ~8; /* no double line */
615 s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
616 s->cr[0x09] &= ~0x9f; /* no double scan */
617 s->vbe_regs[s->vbe_index] = val;
619 /* XXX: the bios should do that */
620 s->bank_offset = -0xa0000;
623 case VBE_DISPI_INDEX_VIRT_WIDTH:
625 int w, h, line_offset;
627 if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
630 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
631 line_offset = w >> 1;
633 line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
634 h = s->vram_size / line_offset;
635 /* XXX: support weird bochs semantics ? */
636 if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
638 s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
639 s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
640 s->vbe_line_offset = line_offset;
643 case VBE_DISPI_INDEX_X_OFFSET:
644 case VBE_DISPI_INDEX_Y_OFFSET:
647 s->vbe_regs[s->vbe_index] = val;
648 s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
649 x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
650 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
651 s->vbe_start_addr += x >> 1;
653 s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
654 s->vbe_start_addr >>= 2;
664 /* called for accesses between 0xa0000 and 0xc0000 */
665 static uint32_t vga_mem_readb(uint32_t addr)
667 VGAState *s = &vga_state;
668 int memory_map_mode, plane;
671 /* convert to VGA memory offset */
672 memory_map_mode = (s->gr[6] >> 2) & 3;
673 switch(memory_map_mode) {
680 addr += s->bank_offset;
695 if (s->sr[4] & 0x08) {
696 /* chain 4 mode : simplest access */
697 ret = s->vram_ptr[addr];
698 } else if (s->gr[5] & 0x10) {
699 /* odd/even mode (aka text mode mapping) */
700 plane = (s->gr[4] & 2) | (addr & 1);
701 ret = s->vram_ptr[((addr & ~1) << 1) | plane];
703 /* standard VGA latched access */
704 s->latch = ((uint32_t *)s->vram_ptr)[addr];
706 if (!(s->gr[5] & 0x08)) {
709 ret = GET_PLANE(s->latch, plane);
712 ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
721 static uint32_t vga_mem_readw(uint32_t addr)
724 v = vga_mem_readb(addr);
725 v |= vga_mem_readb(addr + 1) << 8;
729 static uint32_t vga_mem_readl(uint32_t addr)
732 v = vga_mem_readb(addr);
733 v |= vga_mem_readb(addr + 1) << 8;
734 v |= vga_mem_readb(addr + 2) << 16;
735 v |= vga_mem_readb(addr + 3) << 24;
739 /* called for accesses between 0xa0000 and 0xc0000 */
740 static void vga_mem_writeb(uint32_t addr, uint32_t val, uint32_t vaddr)
742 VGAState *s = &vga_state;
743 int memory_map_mode, plane, write_mode, b, func_select;
744 uint32_t write_mask, bit_mask, set_mask;
747 printf("vga: [0x%x] = 0x%02x\n", addr, val);
749 /* convert to VGA memory offset */
750 memory_map_mode = (s->gr[6] >> 2) & 3;
751 switch(memory_map_mode) {
758 addr += s->bank_offset;
773 if (s->sr[4] & 0x08) {
774 /* chain 4 mode : simplest access */
776 if (s->sr[2] & (1 << plane)) {
777 s->vram_ptr[addr] = val;
779 printf("vga: chain4: [0x%x]\n", addr);
781 cpu_physical_memory_set_dirty(s->vram_offset + addr);
783 } else if (s->gr[5] & 0x10) {
784 /* odd/even mode (aka text mode mapping) */
785 plane = (s->gr[4] & 2) | (addr & 1);
786 if (s->sr[2] & (1 << plane)) {
787 addr = ((addr & ~1) << 1) | plane;
788 s->vram_ptr[addr] = val;
790 printf("vga: odd/even: [0x%x]\n", addr);
792 cpu_physical_memory_set_dirty(s->vram_offset + addr);
795 /* standard VGA latched access */
796 write_mode = s->gr[5] & 3;
802 val = ((val >> b) | (val << (8 - b))) & 0xff;
806 /* apply set/reset mask */
807 set_mask = mask16[s->gr[1]];
808 val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
815 val = mask16[val & 0x0f];
821 val = (val >> b) | (val << (8 - b));
823 bit_mask = s->gr[8] & val;
824 val = mask16[s->gr[0]];
828 /* apply logical operation */
829 func_select = s->gr[3] >> 3;
830 switch(func_select) {
850 bit_mask |= bit_mask << 8;
851 bit_mask |= bit_mask << 16;
852 val = (val & bit_mask) | (s->latch & ~bit_mask);
855 /* mask data according to sr[2] */
856 write_mask = mask16[s->sr[2]];
857 ((uint32_t *)s->vram_ptr)[addr] =
858 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
861 printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
862 addr * 4, write_mask, val);
864 cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
868 static void vga_mem_writew(uint32_t addr, uint32_t val, uint32_t vaddr)
870 vga_mem_writeb(addr, val & 0xff, vaddr);
871 vga_mem_writeb(addr + 1, (val >> 8) & 0xff, vaddr);
874 static void vga_mem_writel(uint32_t addr, uint32_t val, uint32_t vaddr)
876 vga_mem_writeb(addr, val & 0xff, vaddr);
877 vga_mem_writeb(addr + 1, (val >> 8) & 0xff, vaddr);
878 vga_mem_writeb(addr + 2, (val >> 16) & 0xff, vaddr);
879 vga_mem_writeb(addr + 3, (val >> 24) & 0xff, vaddr);
882 typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
883 const uint8_t *font_ptr, int h,
884 uint32_t fgcol, uint32_t bgcol);
885 typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
886 const uint8_t *font_ptr, int h,
887 uint32_t fgcol, uint32_t bgcol, int dup9);
888 typedef void vga_draw_line_func(VGAState *s1, uint8_t *d,
889 const uint8_t *s, int width);
891 static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
897 static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
899 return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
902 static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
904 return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
907 static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
909 return (r << 16) | (g << 8) | b;
913 #include "vga_template.h"
916 #include "vga_template.h"
919 #include "vga_template.h"
922 #include "vga_template.h"
924 static inline int c6_to_8(int v)
929 return (v << 2) | (b << 1) | b;
932 static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
935 col = rgb_to_pixel8(r, g, b);
941 static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
944 col = rgb_to_pixel15(r, g, b);
949 static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
952 col = rgb_to_pixel16(r, g, b);
957 static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
960 col = rgb_to_pixel32(r, g, b);
964 /* return true if the palette was modified */
965 static int update_palette16(VGAState *s)
968 uint32_t v, col, *palette;
971 palette = s->last_palette;
972 for(i = 0; i < 16; i++) {
974 if (s->ar[0x10] & 0x80)
975 v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
977 v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
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]) {
990 /* return true if the palette was modified */
991 static int update_palette256(VGAState *s)
994 uint32_t v, col, *palette;
997 palette = s->last_palette;
999 for(i = 0; i < 256; i++) {
1000 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1001 c6_to_8(s->palette[v + 1]),
1002 c6_to_8(s->palette[v + 2]));
1003 if (col != palette[i]) {
1012 /* update start_addr and line_offset. Return TRUE if modified */
1013 static int update_basic_params(VGAState *s)
1016 uint32_t start_addr, line_offset, line_compare, v;
1020 #ifdef CONFIG_BOCHS_VBE
1021 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1022 line_offset = s->vbe_line_offset;
1023 start_addr = s->vbe_start_addr;
1027 /* compute line_offset in bytes */
1028 line_offset = s->cr[0x13];
1030 v = (s->cr[0x51] >> 4) & 3; /* S3 extension */
1032 v = (s->cr[0x43] >> 2) & 1; /* S3 extension */
1033 line_offset |= (v << 8);
1037 /* starting address */
1038 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
1040 start_addr |= (s->cr[0x69] & 0x1f) << 16; /* S3 extension */
1045 line_compare = s->cr[0x18] |
1046 ((s->cr[0x07] & 0x10) << 4) |
1047 ((s->cr[0x09] & 0x40) << 3);
1049 if (line_offset != s->line_offset ||
1050 start_addr != s->start_addr ||
1051 line_compare != s->line_compare) {
1052 s->line_offset = line_offset;
1053 s->start_addr = start_addr;
1054 s->line_compare = line_compare;
1060 static inline int get_depth_index(int depth)
1075 static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = {
1082 static vga_draw_glyph8_func *vga_draw_glyph16_table[4] = {
1084 vga_draw_glyph16_16,
1085 vga_draw_glyph16_16,
1086 vga_draw_glyph16_32,
1089 static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = {
1096 static const uint8_t cursor_glyph[32 * 4] = {
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,
1104 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1105 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1106 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1107 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1108 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1109 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1110 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1111 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1112 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1123 static void vga_draw_text(VGAState *s, int full_update)
1125 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1126 int cx_min, cx_max, linesize, x_incr;
1127 uint32_t offset, fgcol, bgcol, v, cursor_offset;
1128 uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
1129 const uint8_t *font_ptr, *font_base[2];
1130 int dup9, line_offset, depth_index;
1132 uint32_t *ch_attr_ptr;
1133 vga_draw_glyph8_func *vga_draw_glyph8;
1134 vga_draw_glyph9_func *vga_draw_glyph9;
1136 full_update |= update_palette16(s);
1137 palette = s->last_palette;
1139 /* compute font data address (in plane 2) */
1141 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1142 if (offset != s->font_offsets[0]) {
1143 s->font_offsets[0] = offset;
1146 font_base[0] = s->vram_ptr + offset;
1148 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1149 font_base[1] = s->vram_ptr + offset;
1150 if (offset != s->font_offsets[1]) {
1151 s->font_offsets[1] = offset;
1155 full_update |= update_basic_params(s);
1157 line_offset = s->line_offset;
1158 s1 = s->vram_ptr + (s->start_addr * 4);
1160 /* total width & height */
1161 cheight = (s->cr[9] & 0x1f) + 1;
1163 if (s->sr[1] & 0x01)
1165 if (s->sr[1] & 0x08)
1166 cw = 16; /* NOTE: no 18 pixel wide */
1167 x_incr = cw * ((s->ds->depth + 7) >> 3);
1168 width = (s->cr[0x01] + 1);
1169 if (s->cr[0x06] == 100) {
1170 /* ugly hack for CGA 160x100x16 - explain me the logic */
1173 height = s->cr[0x12] |
1174 ((s->cr[0x07] & 0x02) << 7) |
1175 ((s->cr[0x07] & 0x40) << 3);
1176 height = (height + 1) / cheight;
1178 if (width != s->last_width || height != s->last_height ||
1179 cw != s->last_cw || cw != s->last_cw) {
1180 dpy_resize(s->ds, width * cw, height * cheight);
1181 s->last_width = width;
1182 s->last_height = height;
1183 s->last_ch = cheight;
1187 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1188 if (cursor_offset != s->cursor_offset ||
1189 s->cr[0xa] != s->cursor_start ||
1190 s->cr[0xb] != s->cursor_end) {
1191 /* if the cursor position changed, we update the old and new
1193 if (s->cursor_offset < CH_ATTR_SIZE)
1194 s->last_ch_attr[s->cursor_offset] = -1;
1195 if (cursor_offset < CH_ATTR_SIZE)
1196 s->last_ch_attr[cursor_offset] = -1;
1197 s->cursor_offset = cursor_offset;
1198 s->cursor_start = s->cr[0xa];
1199 s->cursor_end = s->cr[0xb];
1201 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
1203 depth_index = get_depth_index(s->ds->depth);
1205 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1207 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
1208 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1211 linesize = s->ds->linesize;
1212 ch_attr_ptr = s->last_ch_attr;
1213 for(cy = 0; cy < height; cy++) {
1218 for(cx = 0; cx < width; cx++) {
1219 ch_attr = *(uint16_t *)src;
1220 if (full_update || ch_attr != *ch_attr_ptr) {
1225 *ch_attr_ptr = ch_attr;
1226 #ifdef WORDS_BIGENDIAN
1228 cattr = ch_attr & 0xff;
1230 ch = ch_attr & 0xff;
1231 cattr = ch_attr >> 8;
1233 font_ptr = font_base[(cattr >> 3) & 1];
1234 font_ptr += 32 * 4 * ch;
1235 bgcol = palette[cattr >> 4];
1236 fgcol = palette[cattr & 0x0f];
1238 vga_draw_glyph8(d1, linesize,
1239 font_ptr, cheight, fgcol, bgcol);
1242 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1244 vga_draw_glyph9(d1, linesize,
1245 font_ptr, cheight, fgcol, bgcol, dup9);
1247 if (src == cursor_ptr &&
1248 !(s->cr[0x0a] & 0x20)) {
1249 int line_start, line_last, h;
1250 /* draw the cursor */
1251 line_start = s->cr[0x0a] & 0x1f;
1252 line_last = s->cr[0x0b] & 0x1f;
1253 /* XXX: check that */
1254 if (line_last > cheight - 1)
1255 line_last = cheight - 1;
1256 if (line_last >= line_start && line_start < cheight) {
1257 h = line_last - line_start + 1;
1258 d = d1 + linesize * line_start;
1260 vga_draw_glyph8(d, linesize,
1261 cursor_glyph, h, fgcol, bgcol);
1263 vga_draw_glyph9(d, linesize,
1264 cursor_glyph, h, fgcol, bgcol, 1);
1274 dpy_update(s->ds, cx_min * cw, cy * cheight,
1275 (cx_max - cx_min + 1) * cw, cheight);
1277 dest += linesize * cheight;
1296 static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = {
1303 vga_draw_line2d2_16,
1304 vga_draw_line2d2_16,
1305 vga_draw_line2d2_32,
1313 vga_draw_line4d2_16,
1314 vga_draw_line4d2_16,
1315 vga_draw_line4d2_32,
1318 vga_draw_line8d2_16,
1319 vga_draw_line8d2_16,
1320 vga_draw_line8d2_32,
1354 static void vga_draw_graphic(VGAState *s, int full_update)
1356 int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask;
1357 int width, height, shift_control, line_offset, page0, page1, bwidth;
1358 int disp_width, multi_scan, multi_run;
1360 uint32_t v, addr1, addr;
1361 vga_draw_line_func *vga_draw_line;
1363 full_update |= update_basic_params(s);
1365 width = (s->cr[0x01] + 1) * 8;
1366 height = s->cr[0x12] |
1367 ((s->cr[0x07] & 0x02) << 7) |
1368 ((s->cr[0x07] & 0x40) << 3);
1369 height = (height + 1);
1372 shift_control = (s->gr[0x05] >> 5) & 3;
1373 double_scan = (s->cr[0x09] & 0x80);
1374 if (shift_control > 1) {
1375 multi_scan = (s->cr[0x09] & 0x1f);
1379 multi_run = multi_scan;
1380 if (shift_control != s->shift_control ||
1381 double_scan != s->double_scan) {
1383 s->shift_control = shift_control;
1384 s->double_scan = double_scan;
1387 if (shift_control == 0) {
1388 full_update |= update_palette16(s);
1389 if (s->sr[0x01] & 8) {
1390 v = VGA_DRAW_LINE4D2;
1395 } else if (shift_control == 1) {
1396 full_update |= update_palette16(s);
1397 if (s->sr[0x01] & 8) {
1398 v = VGA_DRAW_LINE2D2;
1404 #ifdef CONFIG_BOCHS_VBE
1405 if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1406 switch(s->vbe_regs[VBE_DISPI_INDEX_BPP]) {
1409 full_update |= update_palette256(s);
1413 v = VGA_DRAW_LINE15;
1416 v = VGA_DRAW_LINE16;
1419 v = VGA_DRAW_LINE24;
1422 v = VGA_DRAW_LINE32;
1428 full_update |= update_palette256(s);
1429 v = VGA_DRAW_LINE8D2;
1432 vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)];
1434 if (disp_width != s->last_width ||
1435 height != s->last_height) {
1436 dpy_resize(s->ds, disp_width, 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 void vga_update_display(void)
1521 VGAState *s = &vga_state;
1522 int full_update, graphic_mode;
1524 if (s->ds->depth == 0) {
1527 switch(s->ds->depth) {
1529 s->rgb_to_pixel = rgb_to_pixel8_dup;
1532 s->rgb_to_pixel = rgb_to_pixel15_dup;
1536 s->rgb_to_pixel = rgb_to_pixel16_dup;
1539 s->rgb_to_pixel = rgb_to_pixel32_dup;
1544 graphic_mode = s->gr[6] & 1;
1545 if (graphic_mode != s->graphic_mode) {
1546 s->graphic_mode = graphic_mode;
1550 vga_draw_graphic(s, full_update);
1552 vga_draw_text(s, full_update);
1556 static void vga_reset(VGAState *s)
1558 memset(s, 0, sizeof(VGAState));
1560 /* chip ID for 8c968 */
1563 s->cr[0x2f] = 0x01; /* XXX: check revision code */
1566 s->graphic_mode = -1; /* force full update */
1569 static CPUReadMemoryFunc *vga_mem_read[3] = {
1575 static CPUWriteMemoryFunc *vga_mem_write[3] = {
1581 static void vga_save(QEMUFile *f, void *opaque)
1583 VGAState *s = opaque;
1586 qemu_put_be32s(f, &s->latch);
1587 qemu_put_8s(f, &s->sr_index);
1588 qemu_put_buffer(f, s->sr, 8);
1589 qemu_put_8s(f, &s->gr_index);
1590 qemu_put_buffer(f, s->gr, 16);
1591 qemu_put_8s(f, &s->ar_index);
1592 qemu_put_buffer(f, s->ar, 21);
1593 qemu_put_be32s(f, &s->ar_flip_flop);
1594 qemu_put_8s(f, &s->cr_index);
1595 qemu_put_buffer(f, s->cr, 256);
1596 qemu_put_8s(f, &s->msr);
1597 qemu_put_8s(f, &s->fcr);
1598 qemu_put_8s(f, &s->st00);
1599 qemu_put_8s(f, &s->st01);
1601 qemu_put_8s(f, &s->dac_state);
1602 qemu_put_8s(f, &s->dac_sub_index);
1603 qemu_put_8s(f, &s->dac_read_index);
1604 qemu_put_8s(f, &s->dac_write_index);
1605 qemu_put_buffer(f, s->dac_cache, 3);
1606 qemu_put_buffer(f, s->palette, 768);
1608 qemu_put_be32s(f, &s->bank_offset);
1609 #ifdef CONFIG_BOCHS_VBE
1610 qemu_put_byte(f, 1);
1611 qemu_put_be16s(f, &s->vbe_index);
1612 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1613 qemu_put_be16s(f, &s->vbe_regs[i]);
1614 qemu_put_be32s(f, &s->vbe_start_addr);
1615 qemu_put_be32s(f, &s->vbe_line_offset);
1616 qemu_put_be32s(f, &s->vbe_bank_mask);
1618 qemu_put_byte(f, 0);
1622 static int vga_load(QEMUFile *f, void *opaque, int version_id)
1624 VGAState *s = opaque;
1627 if (version_id != 1)
1630 qemu_get_be32s(f, &s->latch);
1631 qemu_get_8s(f, &s->sr_index);
1632 qemu_get_buffer(f, s->sr, 8);
1633 qemu_get_8s(f, &s->gr_index);
1634 qemu_get_buffer(f, s->gr, 16);
1635 qemu_get_8s(f, &s->ar_index);
1636 qemu_get_buffer(f, s->ar, 21);
1637 qemu_get_be32s(f, &s->ar_flip_flop);
1638 qemu_get_8s(f, &s->cr_index);
1639 qemu_get_buffer(f, s->cr, 256);
1640 qemu_get_8s(f, &s->msr);
1641 qemu_get_8s(f, &s->fcr);
1642 qemu_get_8s(f, &s->st00);
1643 qemu_get_8s(f, &s->st01);
1645 qemu_get_8s(f, &s->dac_state);
1646 qemu_get_8s(f, &s->dac_sub_index);
1647 qemu_get_8s(f, &s->dac_read_index);
1648 qemu_get_8s(f, &s->dac_write_index);
1649 qemu_get_buffer(f, s->dac_cache, 3);
1650 qemu_get_buffer(f, s->palette, 768);
1652 qemu_get_be32s(f, &s->bank_offset);
1653 is_vbe = qemu_get_byte(f);
1654 #ifdef CONFIG_BOCHS_VBE
1657 qemu_get_be16s(f, &s->vbe_index);
1658 for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1659 qemu_get_be16s(f, &s->vbe_regs[i]);
1660 qemu_get_be32s(f, &s->vbe_start_addr);
1661 qemu_get_be32s(f, &s->vbe_line_offset);
1662 qemu_get_be32s(f, &s->vbe_bank_mask);
1669 s->graphic_mode = -1;
1673 int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base,
1674 unsigned long vga_ram_offset, int vga_ram_size)
1676 VGAState *s = &vga_state;
1679 for(i = 0;i < 256; i++) {
1681 for(j = 0; j < 8; j++) {
1682 v |= ((i >> j) & 1) << (j * 4);
1687 for(j = 0; j < 4; j++) {
1688 v |= ((i >> (2 * j)) & 3) << (j * 4);
1692 for(i = 0; i < 16; i++) {
1694 for(j = 0; j < 4; j++) {
1697 v |= b << (2 * j + 1);
1704 s->vram_ptr = vga_ram_base;
1705 s->vram_offset = vga_ram_offset;
1706 s->vram_size = vga_ram_size;
1709 register_savevm("vga", 0, 1, vga_save, vga_load, s);
1711 register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
1713 register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
1714 register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
1715 register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
1716 register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
1718 register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
1720 register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
1721 register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
1722 register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
1723 register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
1724 s->bank_offset = -0xa0000;
1726 #ifdef CONFIG_BOCHS_VBE
1727 s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
1728 s->vbe_bank_mask = ((s->vram_size >> 16) - 1);
1729 register_ioport_read(0x1ce, 1, 2, vbe_ioport_read, s);
1730 register_ioport_read(0x1cf, 1, 2, vbe_ioport_read, s);
1732 register_ioport_write(0x1ce, 1, 2, vbe_ioport_write, s);
1733 register_ioport_write(0x1cf, 1, 2, vbe_ioport_write, s);
1736 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write);
1737 #if defined (TARGET_I386)
1738 cpu_register_physical_memory(0x000a0000, 0x20000, vga_io_memory);
1739 #ifdef CONFIG_BOCHS_VBE
1740 /* XXX: use optimized standard vga accesses */
1741 cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
1742 vga_ram_size, vga_ram_offset);
1744 #elif defined (TARGET_PPC)
1745 cpu_register_physical_memory(0xf00a0000, 0x20000, vga_io_memory);
1750 /********************************************************/
1751 /* vga screen dump */
1753 static int vga_save_w, vga_save_h;
1755 static void vga_save_dpy_update(DisplayState *s,
1756 int x, int y, int w, int h)
1760 static void vga_save_dpy_resize(DisplayState *s, int w, int h)
1762 s->linesize = w * 4;
1763 s->data = qemu_malloc(h * s->linesize);
1768 static void vga_save_dpy_refresh(DisplayState *s)
1772 static int ppm_save(const char *filename, uint8_t *data,
1773 int w, int h, int linesize)
1780 f = fopen(filename, "wb");
1783 fprintf(f, "P6\n%d %d\n%d\n",
1786 for(y = 0; y < h; y++) {
1788 for(x = 0; x < w; x++) {
1790 fputc((v >> 16) & 0xff, f);
1791 fputc((v >> 8) & 0xff, f);
1792 fputc((v) & 0xff, f);
1801 /* save the vga display in a PPM image even if no display is
1803 void vga_screen_dump(const char *filename)
1805 VGAState *s = &vga_state;
1806 DisplayState *saved_ds, ds1, *ds = &ds1;
1808 /* XXX: this is a little hackish */
1810 s->last_height = -1;
1813 memset(ds, 0, sizeof(DisplayState));
1814 ds->dpy_update = vga_save_dpy_update;
1815 ds->dpy_resize = vga_save_dpy_resize;
1816 ds->dpy_refresh = vga_save_dpy_refresh;
1820 s->graphic_mode = -1;
1821 vga_update_display();
1824 ppm_save(filename, ds->data, vga_save_w, vga_save_h,
1826 qemu_free(ds->data);