2 * QEMU VGA Emulator. An S3 86c968 is emulated
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>
43 #define NO_THUNK_TYPE_SIZE
52 //#define DEBUG_VGA_MEM
53 //#define DEBUG_VGA_REG
58 #define MSR_COLOR_EMULATION 0x01
59 #define MSR_PAGE_SELECT 0x20
61 #define ST01_V_RETRACE 0x08
62 #define ST01_DISP_ENABLE 0x01
64 typedef struct VGAState {
66 unsigned long vram_offset;
67 unsigned int vram_size;
77 uint8_t cr[256]; /* CRT registers */
78 uint8_t msr; /* Misc Output Register */
79 uint8_t fcr; /* Feature Control Register */
80 uint8_t st00; /* status 0 */
81 uint8_t st01; /* status 1 */
83 uint8_t dac_sub_index;
84 uint8_t dac_read_index;
85 uint8_t dac_write_index;
86 uint8_t dac_cache[3]; /* used when writing */
89 /* display refresh support */
91 uint32_t font_offsets[2];
93 uint8_t shift_control;
96 uint32_t line_compare;
98 uint8_t last_cw, last_ch;
99 uint32_t last_width, last_height;
100 uint8_t cursor_start, cursor_end;
101 uint32_t cursor_offset;
102 unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned b);
103 /* tell for each page if it has been updated since the last time */
104 uint8_t vram_updated[VGA_RAM_SIZE / 4096];
105 uint32_t last_palette[256];
106 #define CH_ATTR_SIZE (160 * 100)
107 uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */
110 /* force some bits to zero */
111 static const uint8_t sr_mask[8] = {
122 static const uint8_t gr_mask[16] = {
123 (uint8_t)~0xf0, /* 0x00 */
124 (uint8_t)~0xf0, /* 0x01 */
125 (uint8_t)~0xf0, /* 0x02 */
126 (uint8_t)~0xe0, /* 0x03 */
127 (uint8_t)~0xfc, /* 0x04 */
128 (uint8_t)~0x84, /* 0x05 */
129 (uint8_t)~0xf0, /* 0x06 */
130 (uint8_t)~0xf0, /* 0x07 */
131 (uint8_t)~0x00, /* 0x08 */
132 (uint8_t)~0xff, /* 0x09 */
133 (uint8_t)~0xff, /* 0x0a */
134 (uint8_t)~0xff, /* 0x0b */
135 (uint8_t)~0xff, /* 0x0c */
136 (uint8_t)~0xff, /* 0x0d */
137 (uint8_t)~0xff, /* 0x0e */
138 (uint8_t)~0xff, /* 0x0f */
141 #define cbswap_32(__x) \
143 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
144 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
145 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
146 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
148 #ifdef WORDS_BIGENDIAN
149 #define PAT(x) cbswap_32(x)
154 #ifdef WORDS_BIGENDIAN
160 #ifdef WORDS_BIGENDIAN
161 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
163 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
166 static const uint32_t mask16[16] = {
187 #ifdef WORDS_BIGENDIAN
190 #define PAT(x) cbswap_32(x)
193 static const uint32_t dmask16[16] = {
212 static const uint32_t dmask4[4] = {
219 static uint32_t expand4[256];
220 static uint16_t expand2[256];
221 static uint8_t expand4to8[16];
226 static uint32_t vga_ioport_read(CPUState *env, uint32_t addr)
228 VGAState *s = &vga_state;
231 /* check port range access depending on color/monochrome mode */
232 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
233 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) {
238 if (s->ar_flip_flop == 0) {
245 index = s->ar_index & 0x1f;
258 val = s->sr[s->sr_index];
260 printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
267 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
268 if (++s->dac_sub_index == 3) {
269 s->dac_sub_index = 0;
283 val = s->gr[s->gr_index];
285 printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
294 val = s->cr[s->cr_index];
296 printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
299 if (s->cr_index >= 0x20)
300 printf("S3: CR read index=0x%x val=0x%x\n",
306 /* just toggle to fool polling */
307 s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE;
317 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
322 static void vga_ioport_write(CPUState *env, uint32_t addr, uint32_t val)
324 VGAState *s = &vga_state;
327 /* check port range access depending on color/monochrome mode */
328 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
329 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION)))
333 printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
338 if (s->ar_flip_flop == 0) {
342 index = s->ar_index & 0x1f;
345 s->ar[index] = val & 0x3f;
348 s->ar[index] = val & ~0x10;
354 s->ar[index] = val & ~0xc0;
357 s->ar[index] = val & ~0xf0;
360 s->ar[index] = val & ~0xf0;
366 s->ar_flip_flop ^= 1;
369 s->msr = val & ~0x10;
372 s->sr_index = val & 7;
376 printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
378 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
381 s->dac_read_index = val;
382 s->dac_sub_index = 0;
386 s->dac_write_index = val;
387 s->dac_sub_index = 0;
391 s->dac_cache[s->dac_sub_index] = val;
392 if (++s->dac_sub_index == 3) {
393 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
394 s->dac_sub_index = 0;
395 s->dac_write_index++;
399 s->gr_index = val & 0x0f;
403 printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
405 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
414 printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
416 /* handle CR0-7 protection */
417 if ((s->cr[11] & 0x80) && s->cr_index <= 7) {
418 /* can always write bit 4 of CR7 */
419 if (s->cr_index == 7)
420 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
423 switch(s->cr_index) {
424 case 0x01: /* horizontal display end */
429 case 0x12: /* veritcal display end */
430 s->cr[s->cr_index] = val;
439 /* chip ID, cannot write */
442 /* update start address */
443 s->cr[s->cr_index] = val;
445 s->cr[0x69] = (s->cr[69] & ~0x03) | v;
448 /* update start address */
449 s->cr[s->cr_index] = val;
451 s->cr[0x69] = (s->cr[69] & ~0x0c) | (v << 2);
455 s->cr[s->cr_index] = val;
459 if (s->cr_index >= 0x20)
460 printf("S3: CR write index=0x%x val=0x%x\n",
471 /* called for accesses between 0xa0000 and 0xc0000 */
472 static uint32_t vga_mem_readb(uint32_t addr)
474 VGAState *s = &vga_state;
475 int memory_map_mode, plane;
478 /* convert to VGA memory offset */
479 memory_map_mode = (s->gr[6] >> 2) & 3;
480 switch(memory_map_mode) {
500 if (s->sr[4] & 0x08) {
501 /* chain 4 mode : simplest access */
502 ret = s->vram_ptr[addr];
503 } else if (s->gr[5] & 0x10) {
504 /* odd/even mode (aka text mode mapping) */
505 plane = (s->gr[4] & 2) | (addr & 1);
506 ret = s->vram_ptr[((addr & ~1) << 1) | plane];
508 /* standard VGA latched access */
509 s->latch = ((uint32_t *)s->vram_ptr)[addr];
511 if (!(s->gr[5] & 0x08)) {
514 ret = GET_PLANE(s->latch, plane);
517 ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
526 static uint32_t vga_mem_readw(uint32_t addr)
529 v = vga_mem_readb(addr);
530 v |= vga_mem_readb(addr + 1) << 8;
534 static uint32_t vga_mem_readl(uint32_t addr)
537 v = vga_mem_readb(addr);
538 v |= vga_mem_readb(addr + 1) << 8;
539 v |= vga_mem_readb(addr + 2) << 16;
540 v |= vga_mem_readb(addr + 3) << 24;
544 /* called for accesses between 0xa0000 and 0xc0000 */
545 void vga_mem_writeb(uint32_t addr, uint32_t val)
547 VGAState *s = &vga_state;
548 int memory_map_mode, plane, write_mode, b, func_select;
549 uint32_t write_mask, bit_mask, set_mask;
552 printf("vga: [0x%x] = 0x%02x\n", addr, val);
554 /* convert to VGA memory offset */
555 memory_map_mode = (s->gr[6] >> 2) & 3;
556 switch(memory_map_mode) {
576 if (s->sr[4] & 0x08) {
577 /* chain 4 mode : simplest access */
579 if (s->sr[2] & (1 << plane)) {
580 s->vram_ptr[addr] = val;
582 printf("vga: chain4: [0x%x]\n", addr);
584 s->vram_updated[addr >> 12] = 1;
586 } else if (s->gr[5] & 0x10) {
587 /* odd/even mode (aka text mode mapping) */
588 plane = (s->gr[4] & 2) | (addr & 1);
589 if (s->sr[2] & (1 << plane)) {
590 addr = ((addr & ~1) << 1) | plane;
591 s->vram_ptr[addr] = val;
593 printf("vga: odd/even: [0x%x]\n", addr);
595 s->vram_updated[addr >> 12] = 1;
598 /* standard VGA latched access */
599 write_mode = s->gr[5] & 3;
605 val = ((val >> b) | (val << (8 - b))) & 0xff;
609 /* apply set/reset mask */
610 set_mask = mask16[s->gr[1]];
611 val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
618 val = mask16[val & 0x0f];
624 val = (val >> b) | (val << (8 - b));
626 bit_mask = s->gr[8] & val;
627 val = mask16[s->gr[0]];
631 /* apply logical operation */
632 func_select = s->gr[3] >> 3;
633 switch(func_select) {
653 bit_mask |= bit_mask << 8;
654 bit_mask |= bit_mask << 16;
655 val = (val & bit_mask) | (s->latch & ~bit_mask);
658 /* mask data according to sr[2] */
659 write_mask = mask16[s->sr[2]];
660 ((uint32_t *)s->vram_ptr)[addr] =
661 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
664 printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
665 addr * 4, write_mask, val);
667 s->vram_updated[addr >> 10] = 1;
671 void vga_mem_writew(uint32_t addr, uint32_t val)
673 vga_mem_writeb(addr, val & 0xff);
674 vga_mem_writeb(addr + 1, (val >> 8) & 0xff);
677 void vga_mem_writel(uint32_t addr, uint32_t val)
679 vga_mem_writeb(addr, val & 0xff);
680 vga_mem_writeb(addr + 1, (val >> 8) & 0xff);
681 vga_mem_writeb(addr + 2, (val >> 16) & 0xff);
682 vga_mem_writeb(addr + 3, (val >> 24) & 0xff);
685 typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
686 const uint8_t *font_ptr, int h,
687 uint32_t fgcol, uint32_t bgcol);
688 typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
689 const uint8_t *font_ptr, int h,
690 uint32_t fgcol, uint32_t bgcol, int dup9);
691 typedef void vga_draw_line_func(VGAState *s1, uint8_t *d,
692 const uint8_t *s, int width);
694 static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
700 static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
702 return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
705 static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
707 return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
710 static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
712 return (r << 16) | (g << 8) | b;
716 #include "vga_template.h"
719 #include "vga_template.h"
722 #include "vga_template.h"
725 #include "vga_template.h"
727 static inline int c6_to_8(int v)
732 return (v << 2) | (b << 1) | b;
735 static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
738 col = rgb_to_pixel8(r, g, b);
744 static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
747 col = rgb_to_pixel15(r, g, b);
752 static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
755 col = rgb_to_pixel16(r, g, b);
760 static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
763 col = rgb_to_pixel32(r, g, b);
767 /* return true if the palette was modified */
768 static int update_palette16(VGAState *s)
771 uint32_t v, col, *palette;
774 palette = s->last_palette;
775 for(i = 0; i < 16; i++) {
777 if (s->ar[0x10] & 0x80)
778 v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
780 v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
782 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
783 c6_to_8(s->palette[v + 1]),
784 c6_to_8(s->palette[v + 2]));
785 if (col != palette[i]) {
793 /* return true if the palette was modified */
794 static int update_palette256(VGAState *s)
797 uint32_t v, col, *palette;
800 palette = s->last_palette;
802 for(i = 0; i < 256; i++) {
803 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
804 c6_to_8(s->palette[v + 1]),
805 c6_to_8(s->palette[v + 2]));
806 if (col != palette[i]) {
815 /* update start_addr and line_offset. Return TRUE if modified */
816 static int update_basic_params(VGAState *s)
819 uint32_t start_addr, line_offset, line_compare, v;
822 /* compute line_offset in bytes */
823 line_offset = s->cr[0x13];
825 v = (s->cr[0x51] >> 4) & 3; /* S3 extension */
827 v = (s->cr[0x43] >> 2) & 1; /* S3 extension */
828 line_offset |= (v << 8);
832 /* starting address */
833 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
835 start_addr |= (s->cr[0x69] & 0x1f) << 16; /* S3 extension */
839 line_compare = s->cr[0x18] |
840 ((s->cr[0x07] & 0x10) << 4) |
841 ((s->cr[0x09] & 0x40) << 3);
843 if (line_offset != s->line_offset ||
844 start_addr != s->start_addr ||
845 line_compare != s->line_compare) {
846 s->line_offset = line_offset;
847 s->start_addr = start_addr;
848 s->line_compare = line_compare;
854 static inline int get_depth_index(int depth)
869 static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = {
876 static vga_draw_glyph8_func *vga_draw_glyph16_table[4] = {
883 static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = {
890 static const uint8_t cursor_glyph[32 * 4] = {
891 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
892 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
893 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
894 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
895 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
896 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
897 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
898 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
899 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
900 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
901 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
902 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
903 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
904 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
905 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
906 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
917 static void vga_draw_text(VGAState *s, int full_update)
919 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
920 int cx_min, cx_max, linesize, x_incr;
921 uint32_t offset, fgcol, bgcol, v, cursor_offset;
922 uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
923 const uint8_t *font_ptr, *font_base[2];
924 int dup9, line_offset, depth_index;
926 uint32_t *ch_attr_ptr;
927 vga_draw_glyph8_func *vga_draw_glyph8;
928 vga_draw_glyph9_func *vga_draw_glyph9;
930 full_update |= update_palette16(s);
931 palette = s->last_palette;
933 /* compute font data address (in plane 2) */
935 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
936 if (offset != s->font_offsets[0]) {
937 s->font_offsets[0] = offset;
940 font_base[0] = s->vram_ptr + offset;
942 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
943 font_base[1] = s->vram_ptr + offset;
944 if (offset != s->font_offsets[1]) {
945 s->font_offsets[1] = offset;
949 full_update |= update_basic_params(s);
951 line_offset = s->line_offset;
952 s1 = s->vram_ptr + (s->start_addr * 4);
954 /* total width & height */
955 cheight = (s->cr[9] & 0x1f) + 1;
960 cw = 16; /* NOTE: no 18 pixel wide */
961 x_incr = cw * ((s->ds->depth + 7) >> 3);
962 width = (s->cr[0x01] + 1);
963 if (s->cr[0x06] == 100) {
964 /* ugly hack for CGA 160x100x16 - explain me the logic */
967 height = s->cr[0x12] |
968 ((s->cr[0x07] & 0x02) << 7) |
969 ((s->cr[0x07] & 0x40) << 3);
970 height = (height + 1) / cheight;
972 if (width != s->last_width || height != s->last_height ||
973 cw != s->last_cw || cw != s->last_cw) {
974 dpy_resize(s->ds, width * cw, height * cheight);
975 s->last_width = width;
976 s->last_height = height;
977 s->last_ch = cheight;
981 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
982 if (cursor_offset != s->cursor_offset ||
983 s->cr[0xa] != s->cursor_start ||
984 s->cr[0xb] != s->cursor_end) {
985 /* if the cursor position changed, we update the old and new
987 if (s->cursor_offset < CH_ATTR_SIZE)
988 s->last_ch_attr[s->cursor_offset] = -1;
989 if (cursor_offset < CH_ATTR_SIZE)
990 s->last_ch_attr[cursor_offset] = -1;
991 s->cursor_offset = cursor_offset;
992 s->cursor_start = s->cr[0xa];
993 s->cursor_end = s->cr[0xb];
995 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
997 depth_index = get_depth_index(s->ds->depth);
999 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1001 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
1002 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1005 linesize = s->ds->linesize;
1006 ch_attr_ptr = s->last_ch_attr;
1007 for(cy = 0; cy < height; cy++) {
1012 for(cx = 0; cx < width; cx++) {
1013 ch_attr = *(uint16_t *)src;
1014 if (full_update || ch_attr != *ch_attr_ptr) {
1019 *ch_attr_ptr = ch_attr;
1020 #ifdef WORDS_BIGENDIAN
1022 cattr = ch_attr & 0xff;
1024 ch = ch_attr & 0xff;
1025 cattr = ch_attr >> 8;
1027 font_ptr = font_base[(cattr >> 3) & 1];
1028 font_ptr += 32 * 4 * ch;
1029 bgcol = palette[cattr >> 4];
1030 fgcol = palette[cattr & 0x0f];
1032 vga_draw_glyph8(d1, linesize,
1033 font_ptr, cheight, fgcol, bgcol);
1036 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1038 vga_draw_glyph9(d1, linesize,
1039 font_ptr, cheight, fgcol, bgcol, dup9);
1041 if (src == cursor_ptr &&
1042 !(s->cr[0x0a] & 0x20)) {
1043 int line_start, line_last, h;
1044 /* draw the cursor */
1045 line_start = s->cr[0x0a] & 0x1f;
1046 line_last = s->cr[0x0b] & 0x1f;
1047 /* XXX: check that */
1048 if (line_last > cheight - 1)
1049 line_last = cheight - 1;
1050 if (line_last >= line_start && line_start < cheight) {
1051 h = line_last - line_start + 1;
1052 d = d1 + linesize * line_start;
1054 vga_draw_glyph8(d, linesize,
1055 cursor_glyph, h, fgcol, bgcol);
1057 vga_draw_glyph9(d, linesize,
1058 cursor_glyph, h, fgcol, bgcol, 1);
1068 dpy_update(s->ds, cx_min * cw, cy * cheight,
1069 (cx_max - cx_min + 1) * cw, cheight);
1071 dest += linesize * cheight;
1089 static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = {
1096 vga_draw_line2d2_16,
1097 vga_draw_line2d2_16,
1098 vga_draw_line2d2_32,
1106 vga_draw_line4d2_16,
1107 vga_draw_line4d2_16,
1108 vga_draw_line4d2_32,
1111 vga_draw_line8d2_16,
1112 vga_draw_line8d2_16,
1113 vga_draw_line8d2_32,
1142 static void vga_draw_graphic(VGAState *s, int full_update)
1144 int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask;
1145 int width, height, shift_control, line_offset, page0, page1, bwidth;
1146 int disp_width, multi_scan, multi_run;
1148 uint32_t v, addr1, addr;
1149 vga_draw_line_func *vga_draw_line;
1151 full_update |= update_basic_params(s);
1153 width = (s->cr[0x01] + 1) * 8;
1154 height = s->cr[0x12] |
1155 ((s->cr[0x07] & 0x02) << 7) |
1156 ((s->cr[0x07] & 0x40) << 3);
1157 height = (height + 1);
1160 shift_control = (s->gr[0x05] >> 5) & 3;
1161 double_scan = (s->cr[0x09] & 0x80);
1162 if (shift_control > 1) {
1163 multi_scan = (s->cr[0x09] & 0x1f);
1167 multi_run = multi_scan;
1168 if (shift_control != s->shift_control ||
1169 double_scan != s->double_scan) {
1171 s->shift_control = shift_control;
1172 s->double_scan = double_scan;
1175 if (shift_control == 0) {
1176 full_update |= update_palette16(s);
1177 if (s->sr[0x01] & 8) {
1178 v = VGA_DRAW_LINE4D2;
1183 } else if (shift_control == 1) {
1184 full_update |= update_palette16(s);
1185 if (s->sr[0x01] & 8) {
1186 v = VGA_DRAW_LINE2D2;
1192 full_update |= update_palette256(s);
1193 v = VGA_DRAW_LINE8D2;
1195 vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)];
1197 if (disp_width != s->last_width ||
1198 height != s->last_height) {
1199 dpy_resize(s->ds, disp_width, height);
1200 s->last_width = disp_width;
1201 s->last_height = height;
1205 line_offset = s->line_offset;
1207 printf("w=%d h=%d v=%d line_offset=%d double_scan=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=%02x\n",
1208 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1210 addr1 = (s->start_addr * 4);
1213 page_min = 0x7fffffff;
1216 linesize = s->ds->linesize;
1218 for(y = 0; y < height; y++) {
1220 if (!(s->cr[0x17] & 1)) {
1222 /* CGA compatibility handling */
1223 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1224 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1226 if (!(s->cr[0x17] & 2)) {
1227 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1230 page1 = (addr + bwidth - 1) >> 12;
1231 update = full_update | s->vram_updated[page0] | s->vram_updated[page1];
1232 if ((page1 - page0) > 1) {
1233 /* if wide line, can use another page */
1234 update |= s->vram_updated[page0 + 1];
1239 if (page0 < page_min)
1241 if (page1 > page_max)
1243 vga_draw_line(s, d, s->vram_ptr + addr, width);
1246 /* flush to display */
1247 dpy_update(s->ds, 0, y_start,
1248 disp_width, y - y_start);
1253 if (!double_scan || (y & 1) != 0) {
1254 if (y1 == s->line_compare) {
1257 mask = (s->cr[0x17] & 3) ^ 3;
1258 if ((y1 & mask) == mask)
1259 addr1 += line_offset;
1263 multi_run = multi_scan;
1271 /* flush to display */
1272 dpy_update(s->ds, 0, y_start,
1273 disp_width, y - y_start);
1275 /* reset modified pages */
1276 if (page_max != -1) {
1277 memset(s->vram_updated + page_min, 0, page_max - page_min + 1);
1281 /* draw text terminal (very limited, just for simple boot debug
1283 static int last_cursor_pos;
1285 void vga_draw_dumb(VGAState *s)
1287 int c, i, cursor_pos, eol;
1289 cursor_pos = s->cr[0x0f] | (s->cr[0x0e] << 8);
1291 for(i = last_cursor_pos; i < cursor_pos; i++) {
1292 /* XXX: should use vga RAM */
1293 c = phys_ram_base[0xb8000 + (i) * 2];
1304 last_cursor_pos = cursor_pos;
1307 void vga_update_display(void)
1309 VGAState *s = &vga_state;
1310 int full_update, graphic_mode;
1312 if (s->ds->depth == 0) {
1316 graphic_mode = s->gr[6] & 1;
1317 if (graphic_mode != s->graphic_mode) {
1318 s->graphic_mode = graphic_mode;
1322 vga_draw_graphic(s, full_update);
1324 vga_draw_text(s, full_update);
1328 void vga_reset(VGAState *s)
1330 memset(s, 0, sizeof(VGAState));
1332 /* chip ID for 8c968 */
1335 s->cr[0x2f] = 0x01; /* XXX: check revision code */
1338 s->graphic_mode = -1; /* force full update */
1341 CPUReadMemoryFunc *vga_mem_read[3] = {
1347 CPUWriteMemoryFunc *vga_mem_write[3] = {
1353 int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base,
1354 unsigned long vga_ram_offset, int vga_ram_size)
1356 VGAState *s = &vga_state;
1359 for(i = 0;i < 256; i++) {
1361 for(j = 0; j < 8; j++) {
1362 v |= ((i >> j) & 1) << (j * 4);
1367 for(j = 0; j < 4; j++) {
1368 v |= ((i >> (2 * j)) & 3) << (j * 4);
1372 for(i = 0; i < 16; i++) {
1374 for(j = 0; j < 4; j++) {
1377 v |= b << (2 * j + 1);
1386 s->rgb_to_pixel = rgb_to_pixel8_dup;
1389 s->rgb_to_pixel = rgb_to_pixel15_dup;
1393 s->rgb_to_pixel = rgb_to_pixel16_dup;
1396 s->rgb_to_pixel = rgb_to_pixel32_dup;
1400 s->vram_ptr = vga_ram_base;
1401 s->vram_offset = vga_ram_offset;
1402 s->vram_size = vga_ram_size;
1405 register_ioport_write(0x3c0, 16, vga_ioport_write, 1);
1407 register_ioport_write(0x3b4, 2, vga_ioport_write, 1);
1408 register_ioport_write(0x3d4, 2, vga_ioport_write, 1);
1409 register_ioport_write(0x3ba, 1, vga_ioport_write, 1);
1410 register_ioport_write(0x3da, 1, vga_ioport_write, 1);
1412 register_ioport_read(0x3c0, 16, vga_ioport_read, 1);
1414 register_ioport_read(0x3b4, 2, vga_ioport_read, 1);
1415 register_ioport_read(0x3d4, 2, vga_ioport_read, 1);
1416 register_ioport_read(0x3ba, 1, vga_ioport_read, 1);
1417 register_ioport_read(0x3da, 1, vga_ioport_read, 1);
1419 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write);
1420 #if defined (TARGET_I386)
1421 cpu_register_physical_memory(0x000a0000, 0x20000, vga_io_memory);
1422 #elif defined (TARGET_PPC)
1423 cpu_register_physical_memory(0xf00a0000, 0x20000, vga_io_memory);