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>
48 #define NO_THUNK_TYPE_SIZE
52 //#define DEBUG_VGA_MEM
54 #define MSR_COLOR_EMULATION 0x01
55 #define MSR_PAGE_SELECT 0x20
57 #define ST01_V_RETRACE 0x08
58 #define ST01_DISP_ENABLE 0x01
60 typedef struct VGAState {
62 unsigned long vram_offset;
63 unsigned int vram_size;
73 uint8_t cr[256]; /* CRT registers */
74 uint8_t msr; /* Misc Output Register */
75 uint8_t fcr; /* Feature Control Register */
76 uint8_t st00; /* status 0 */
77 uint8_t st01; /* status 1 */
79 uint8_t dac_sub_index;
80 uint8_t dac_read_index;
81 uint8_t dac_write_index;
82 uint8_t dac_cache[3]; /* used when writing */
85 /* display refresh support */
87 uint32_t font_offsets[2];
89 uint8_t shift_control;
92 uint32_t line_compare;
94 uint8_t last_cw, last_ch;
95 uint32_t last_width, last_height;
96 uint8_t cursor_start, cursor_end;
97 uint32_t cursor_offset;
98 unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned b);
99 /* tell for each page if it has been updated since the last time */
100 uint8_t vram_updated[VGA_RAM_SIZE / 4096];
101 uint32_t last_palette[256];
102 #define CH_ATTR_SIZE (160 * 100)
103 uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */
106 /* force some bits to zero */
107 static const uint8_t sr_mask[8] = {
118 static const uint8_t gr_mask[16] = {
119 (uint8_t)~0xf0, /* 0x00 */
120 (uint8_t)~0xf0, /* 0x01 */
121 (uint8_t)~0xf0, /* 0x02 */
122 (uint8_t)~0xe0, /* 0x03 */
123 (uint8_t)~0xfc, /* 0x04 */
124 (uint8_t)~0x84, /* 0x05 */
125 (uint8_t)~0xf0, /* 0x06 */
126 (uint8_t)~0xf0, /* 0x07 */
127 (uint8_t)~0x00, /* 0x08 */
128 (uint8_t)~0xff, /* 0x09 */
129 (uint8_t)~0xff, /* 0x0a */
130 (uint8_t)~0xff, /* 0x0b */
131 (uint8_t)~0xff, /* 0x0c */
132 (uint8_t)~0xff, /* 0x0d */
133 (uint8_t)~0xff, /* 0x0e */
134 (uint8_t)~0xff, /* 0x0f */
137 #define cbswap_32(__x) \
139 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
140 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
141 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
142 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
144 #ifdef WORD_BIGENDIAN
145 #define PAT(x) cbswap_32(x)
150 static const uint32_t mask16[16] = {
171 #ifdef WORD_BIGENDIAN
174 #define PAT(x) cbswap_32(x)
177 static const uint32_t dmask16[16] = {
196 static const uint32_t dmask4[4] = {
203 static uint32_t expand4[256];
204 static uint16_t expand2[256];
205 static uint8_t expand4to8[16];
210 static uint32_t vga_ioport_read(CPUX86State *env, uint32_t addr)
212 VGAState *s = &vga_state;
215 /* check port range access depending on color/monochrome mode */
216 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
217 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) {
222 if (s->ar_flip_flop == 0) {
229 index = s->ar_index & 0x1f;
242 val = s->sr[s->sr_index];
248 val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
249 if (++s->dac_sub_index == 3) {
250 s->dac_sub_index = 0;
264 val = s->gr[s->gr_index];
272 val = s->cr[s->cr_index];
276 /* just toggle to fool polling */
277 s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE;
287 printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
292 static void vga_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val)
294 VGAState *s = &vga_state;
297 /* check port range access depending on color/monochrome mode */
298 if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
299 (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION)))
303 printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
308 if (s->ar_flip_flop == 0) {
312 index = s->ar_index & 0x1f;
315 s->ar[index] = val & 0x3f;
318 s->ar[index] = val & ~0x10;
324 s->ar[index] = val & ~0xc0;
327 s->ar[index] = val & ~0xf0;
330 s->ar[index] = val & ~0xf0;
336 s->ar_flip_flop ^= 1;
339 s->msr = val & ~0x10;
342 s->sr_index = val & 7;
345 s->sr[s->sr_index] = val & sr_mask[s->sr_index];
348 s->dac_read_index = val;
349 s->dac_sub_index = 0;
353 s->dac_write_index = val;
354 s->dac_sub_index = 0;
358 s->dac_cache[s->dac_sub_index] = val;
359 if (++s->dac_sub_index == 3) {
360 memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
361 s->dac_sub_index = 0;
362 s->dac_write_index++;
366 s->gr_index = val & 0x0f;
369 s->gr[s->gr_index] = val & gr_mask[s->gr_index];
377 /* handle CR0-7 protection */
378 if ((s->cr[11] & 0x80) && s->cr_index <= 7) {
379 /* can always write bit 4 of CR7 */
380 if (s->cr_index == 7)
381 s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
384 switch(s->cr_index) {
385 case 0x01: /* horizontal display end */
390 case 0x12: /* veritcal display end */
391 s->cr[s->cr_index] = val;
399 /* chip ID, cannot write */
402 /* update start address */
403 s->cr[s->cr_index] = val;
405 s->cr[0x69] = (s->cr[69] & ~0x03) | v;
408 /* update start address */
409 s->cr[s->cr_index] = val;
411 s->cr[0x69] = (s->cr[69] & ~0x0c) | (v << 2);
414 s->cr[s->cr_index] = val;
425 /* called for accesses between 0xa0000 and 0xc0000 */
426 static uint32_t vga_mem_readb(uint32_t addr)
428 VGAState *s = &vga_state;
429 int memory_map_mode, plane;
432 /* convert to VGA memory offset */
433 memory_map_mode = (s->gr[6] >> 2) & 3;
434 switch(memory_map_mode) {
454 if (s->sr[4] & 0x08) {
455 /* chain 4 mode : simplest access */
456 ret = s->vram_ptr[addr];
457 } else if (s->gr[5] & 0x10) {
458 /* odd/even mode (aka text mode mapping) */
459 plane = (s->gr[4] & 2) | (addr & 1);
460 ret = s->vram_ptr[((addr & ~1) << 1) | plane];
462 /* standard VGA latched access */
463 s->latch = ((uint32_t *)s->vram_ptr)[addr];
465 if (!(s->gr[5] & 0x08)) {
468 #ifdef WORD_BIGENDIAN
469 ret = (s->latch >> (24 - (plane * 8))) & 0xff;
471 ret = (s->latch >> (plane * 8)) & 0xff;
475 ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
484 static uint32_t vga_mem_readw(uint32_t addr)
487 v = vga_mem_readb(addr);
488 v |= vga_mem_readb(addr + 1) << 8;
492 static uint32_t vga_mem_readl(uint32_t addr)
495 v = vga_mem_readb(addr);
496 v |= vga_mem_readb(addr + 1) << 8;
497 v |= vga_mem_readb(addr + 2) << 16;
498 v |= vga_mem_readb(addr + 3) << 24;
503 /* called for accesses between 0xa0000 and 0xc0000 */
504 void vga_mem_writeb(uint32_t addr, uint32_t val)
506 VGAState *s = &vga_state;
507 int memory_map_mode, plane, write_mode, b, func_select;
508 uint32_t write_mask, bit_mask, set_mask;
511 printf("vga: [0x%x] = 0x%02x\n", addr, val);
513 /* convert to VGA memory offset */
514 memory_map_mode = (s->gr[6] >> 2) & 3;
515 switch(memory_map_mode) {
535 if (s->sr[4] & 0x08) {
536 /* chain 4 mode : simplest access */
538 if (s->sr[2] & (1 << plane)) {
539 s->vram_ptr[addr] = val;
541 printf("vga: chain4: [0x%x]\n", addr);
543 s->vram_updated[addr >> 12] = 1;
545 } else if (s->gr[5] & 0x10) {
546 /* odd/even mode (aka text mode mapping) */
547 plane = (s->gr[4] & 2) | (addr & 1);
548 if (s->sr[2] & (1 << plane)) {
549 addr = ((addr & ~1) << 1) | plane;
550 s->vram_ptr[addr] = val;
552 printf("vga: odd/even: [0x%x]\n", addr);
554 s->vram_updated[addr >> 12] = 1;
557 /* standard VGA latched access */
558 write_mode = s->gr[5] & 3;
564 val = ((val >> b) | (val << (8 - b))) & 0xff;
568 /* apply set/reset mask */
569 set_mask = mask16[s->gr[1]];
570 val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
577 val = mask16[val & 0x0f];
583 val = ((val >> b) | (val << (8 - b)));
585 bit_mask = s->gr[8] & val;
586 val = mask16[s->gr[0]];
590 /* apply logical operation */
591 func_select = s->gr[3] >> 3;
592 switch(func_select) {
612 bit_mask |= bit_mask << 8;
613 bit_mask |= bit_mask << 16;
614 val = (val & bit_mask) | (s->latch & ~bit_mask);
617 /* mask data according to sr[2] */
618 write_mask = mask16[s->sr[2]];
619 ((uint32_t *)s->vram_ptr)[addr] =
620 (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
623 printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
624 addr * 4, write_mask, val);
626 s->vram_updated[addr >> 10] = 1;
630 void vga_mem_writew(uint32_t addr, uint32_t val)
632 vga_mem_writeb(addr, val & 0xff);
633 vga_mem_writeb(addr + 1, (val >> 8) & 0xff);
636 void vga_mem_writel(uint32_t addr, uint32_t val)
638 vga_mem_writeb(addr, val & 0xff);
639 vga_mem_writeb(addr + 1, (val >> 8) & 0xff);
640 vga_mem_writeb(addr + 2, (val >> 16) & 0xff);
641 vga_mem_writeb(addr + 3, (val >> 24) & 0xff);
644 #ifdef WORD_BIGENDIAN
650 #ifdef WORDS_BIGENDIAN
651 #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
653 #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
656 typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
657 const uint8_t *font_ptr, int h,
658 uint32_t fgcol, uint32_t bgcol);
659 typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
660 const uint8_t *font_ptr, int h,
661 uint32_t fgcol, uint32_t bgcol, int dup9);
662 typedef void vga_draw_line_func(VGAState *s1, uint8_t *d,
663 const uint8_t *s, int width);
665 static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
671 static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
673 return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
676 static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
678 return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
681 static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
683 return (r << 16) | (g << 8) | b;
687 #include "vga_template.h"
690 #include "vga_template.h"
693 #include "vga_template.h"
696 #include "vga_template.h"
698 static inline int c6_to_8(int v)
703 return (v << 2) | (b << 1) | b;
706 static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
709 col = rgb_to_pixel8(r, g, b);
715 static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
718 col = rgb_to_pixel15(r, g, b);
723 static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
726 col = rgb_to_pixel16(r, g, b);
731 static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
734 col = rgb_to_pixel32(r, g, b);
738 /* return true if the palette was modified */
739 static int update_palette16(VGAState *s)
742 uint32_t v, col, *palette;
745 palette = s->last_palette;
746 for(i = 0; i < 16; i++) {
748 if (s->ar[0x10] & 0x80)
749 v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
751 v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
753 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
754 c6_to_8(s->palette[v + 1]),
755 c6_to_8(s->palette[v + 2]));
756 if (col != palette[i]) {
764 /* return true if the palette was modified */
765 static int update_palette256(VGAState *s)
768 uint32_t v, col, *palette;
771 palette = s->last_palette;
773 for(i = 0; i < 256; i++) {
774 col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
775 c6_to_8(s->palette[v + 1]),
776 c6_to_8(s->palette[v + 2]));
777 if (col != palette[i]) {
786 /* update start_addr and line_offset. Return TRUE if modified */
787 static int update_basic_params(VGAState *s)
790 uint32_t start_addr, line_offset, line_compare, v;
793 /* compute line_offset in bytes */
794 v = (s->cr[0x51] >> 4) & 3; /* S3 extension */
796 v = (s->cr[0x43] >> 2) & 1; /* S3 extension */
797 line_offset = s->cr[0x13] | (v << 8);
800 /* starting address */
801 start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
802 start_addr |= (s->cr[0x69] & 0x1f) << 16; /* S3 extension */
805 line_compare = s->cr[0x18] |
806 ((s->cr[0x07] & 0x10) << 4) |
807 ((s->cr[0x09] & 0x40) << 3);
809 if (line_offset != s->line_offset ||
810 start_addr != s->start_addr ||
811 line_compare != s->line_compare) {
812 s->line_offset = line_offset;
813 s->start_addr = start_addr;
814 s->line_compare = line_compare;
820 static inline int get_depth_index(int depth)
835 static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = {
842 static vga_draw_glyph8_func *vga_draw_glyph16_table[4] = {
849 static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = {
856 static const uint8_t cursor_glyph[32 * 4] = {
857 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
858 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
859 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
860 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
861 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
862 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
863 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
864 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
865 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
866 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
867 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
868 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
869 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
870 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
871 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
872 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
883 static void vga_draw_text(VGAState *s, int full_update)
885 int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
886 int cx_min, cx_max, linesize, x_incr;
887 uint32_t offset, fgcol, bgcol, v, cursor_offset;
888 uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
889 const uint8_t *font_ptr, *font_base[2];
890 int dup9, line_offset, depth_index;
892 uint32_t *ch_attr_ptr;
893 vga_draw_glyph8_func *vga_draw_glyph8;
894 vga_draw_glyph9_func *vga_draw_glyph9;
896 full_update |= update_palette16(s);
897 palette = s->last_palette;
899 /* compute font data address (in plane 2) */
901 offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
902 if (offset != s->font_offsets[0]) {
903 s->font_offsets[0] = offset;
906 font_base[0] = s->vram_ptr + offset;
908 offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
909 font_base[1] = s->vram_ptr + offset;
910 if (offset != s->font_offsets[1]) {
911 s->font_offsets[1] = offset;
915 full_update |= update_basic_params(s);
917 line_offset = s->line_offset;
918 s1 = s->vram_ptr + (s->start_addr * 4);
920 /* total width & height */
921 cheight = (s->cr[9] & 0x1f) + 1;
926 cw = 16; /* NOTE: no 18 pixel wide */
927 x_incr = cw * ((s->ds->depth + 7) >> 3);
928 width = (s->cr[0x01] + 1);
929 if (s->cr[0x06] == 100) {
930 /* ugly hack for CGA 160x100x16 - explain me the logic */
933 height = s->cr[0x12] |
934 ((s->cr[0x07] & 0x02) << 7) |
935 ((s->cr[0x07] & 0x40) << 3);
936 height = (height + 1) / cheight;
938 if (width != s->last_width || height != s->last_height ||
939 cw != s->last_cw || cw != s->last_cw) {
940 dpy_resize(s->ds, width * cw, height * cheight);
941 s->last_width = width;
942 s->last_height = height;
943 s->last_ch = cheight;
947 cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
948 if (cursor_offset != s->cursor_offset ||
949 s->cr[0xa] != s->cursor_start ||
950 s->cr[0xb] != s->cursor_end) {
951 /* if the cursor position changed, we update the old and new
953 if (s->cursor_offset < CH_ATTR_SIZE)
954 s->last_ch_attr[s->cursor_offset] = -1;
955 if (cursor_offset < CH_ATTR_SIZE)
956 s->last_ch_attr[cursor_offset] = -1;
957 s->cursor_offset = cursor_offset;
958 s->cursor_start = s->cr[0xa];
959 s->cursor_end = s->cr[0xb];
961 cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
963 depth_index = get_depth_index(s->ds->depth);
965 vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
967 vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
968 vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
971 linesize = s->ds->linesize;
972 ch_attr_ptr = s->last_ch_attr;
973 for(cy = 0; cy < height; cy++) {
978 for(cx = 0; cx < width; cx++) {
979 ch_attr = *(uint16_t *)src;
980 if (full_update || ch_attr != *ch_attr_ptr) {
985 *ch_attr_ptr = ch_attr;
986 #ifdef WORDS_BIGENDIAN
988 cattr = ch_attr & 0xff;
991 cattr = ch_attr >> 8;
993 font_ptr = font_base[(cattr >> 3) & 1];
994 font_ptr += 32 * 4 * ch;
995 bgcol = palette[cattr >> 4];
996 fgcol = palette[cattr & 0x0f];
998 vga_draw_glyph8(d1, linesize,
999 font_ptr, cheight, fgcol, bgcol);
1002 if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1004 vga_draw_glyph9(d1, linesize,
1005 font_ptr, cheight, fgcol, bgcol, dup9);
1007 if (src == cursor_ptr &&
1008 !(s->cr[0x0a] & 0x20)) {
1009 int line_start, line_last, h;
1010 /* draw the cursor */
1011 line_start = s->cr[0x0a] & 0x1f;
1012 line_last = s->cr[0x0b] & 0x1f;
1013 /* XXX: check that */
1014 if (line_last > cheight - 1)
1015 line_last = cheight - 1;
1016 if (line_last >= line_start && line_start < cheight) {
1017 h = line_last - line_start + 1;
1018 d = d1 + linesize * line_start;
1020 vga_draw_glyph8(d, linesize,
1021 cursor_glyph, h, fgcol, bgcol);
1023 vga_draw_glyph9(d, linesize,
1024 cursor_glyph, h, fgcol, bgcol, 1);
1034 dpy_update(s->ds, cx_min * cw, cy * cheight,
1035 (cx_max - cx_min + 1) * cw, cheight);
1037 dest += linesize * cheight;
1055 static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = {
1062 vga_draw_line2d2_16,
1063 vga_draw_line2d2_16,
1064 vga_draw_line2d2_32,
1072 vga_draw_line4d2_16,
1073 vga_draw_line4d2_16,
1074 vga_draw_line4d2_32,
1077 vga_draw_line8d2_16,
1078 vga_draw_line8d2_16,
1079 vga_draw_line8d2_32,
1108 static void vga_draw_graphic(VGAState *s, int full_update)
1110 int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask;
1111 int width, height, shift_control, line_offset, page0, page1, bwidth;
1114 uint32_t v, addr1, addr;
1115 vga_draw_line_func *vga_draw_line;
1117 full_update |= update_basic_params(s);
1119 width = (s->cr[0x01] + 1) * 8;
1120 height = s->cr[0x12] |
1121 ((s->cr[0x07] & 0x02) << 7) |
1122 ((s->cr[0x07] & 0x40) << 3);
1123 height = (height + 1);
1126 shift_control = (s->gr[0x05] >> 5) & 3;
1127 double_scan = (s->cr[0x09] & 0x80);
1128 if (shift_control != s->shift_control ||
1129 double_scan != s->double_scan) {
1131 s->shift_control = shift_control;
1132 s->double_scan = double_scan;
1135 if (shift_control == 0) {
1136 full_update |= update_palette16(s);
1137 if (s->sr[0x01] & 8) {
1138 v = VGA_DRAW_LINE4D2;
1143 } else if (shift_control == 1) {
1144 full_update |= update_palette16(s);
1145 if (s->sr[0x01] & 8) {
1146 v = VGA_DRAW_LINE2D2;
1152 full_update |= update_palette256(s);
1153 v = VGA_DRAW_LINE8D2;
1154 double_scan = 1; /* XXX: explain me why it is always activated */
1156 vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)];
1158 if (disp_width != s->last_width ||
1159 height != s->last_height) {
1160 dpy_resize(s->ds, disp_width, height);
1161 s->last_width = disp_width;
1162 s->last_height = height;
1166 line_offset = s->line_offset;
1168 printf("w=%d h=%d v=%d line_offset=%d double_scan=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=%02x\n",
1169 width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1171 addr1 = (s->start_addr * 4);
1174 page_min = 0x7fffffff;
1177 linesize = s->ds->linesize;
1179 for(y = 0; y < height; y++) {
1181 if (!(s->cr[0x17] & 1)) {
1183 /* CGA compatibility handling */
1184 shift = 14 + ((s->cr[0x17] >> 6) & 1);
1185 addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1187 if (!(s->cr[0x17] & 2)) {
1188 addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1191 page1 = (addr + bwidth - 1) >> 12;
1192 update = full_update | s->vram_updated[page0] | s->vram_updated[page1];
1193 if ((page1 - page0) > 1) {
1194 /* if wide line, can use another page */
1195 update |= s->vram_updated[page0 + 1];
1200 if (page0 < page_min)
1202 if (page1 > page_max)
1204 vga_draw_line(s, d, s->vram_ptr + addr, width);
1207 /* flush to display */
1208 dpy_update(s->ds, 0, y_start,
1209 disp_width, y - y_start);
1213 if (!double_scan || (y & 1) != 0) {
1214 if (y1 == s->line_compare) {
1217 mask = (s->cr[0x17] & 3) ^ 3;
1218 if ((y1 & mask) == mask)
1219 addr1 += line_offset;
1226 /* flush to display */
1227 dpy_update(s->ds, 0, y_start,
1228 disp_width, y - y_start);
1230 /* reset modified pages */
1231 if (page_max != -1) {
1232 memset(s->vram_updated + page_min, 0, page_max - page_min + 1);
1236 /* draw text terminal (very limited, just for simple boot debug
1238 static int last_cursor_pos;
1240 void vga_draw_dumb(VGAState *s)
1242 int c, i, cursor_pos, eol;
1244 cursor_pos = s->cr[0x0f] | (s->cr[0x0e] << 8);
1246 for(i = last_cursor_pos; i < cursor_pos; i++) {
1247 /* XXX: should use vga RAM */
1248 c = phys_ram_base[0xb8000 + (i) * 2];
1259 last_cursor_pos = cursor_pos;
1262 void vga_update_display(void)
1264 VGAState *s = &vga_state;
1265 int full_update, graphic_mode;
1267 if (s->ds->depth == 0) {
1271 graphic_mode = s->gr[6] & 1;
1272 if (graphic_mode != s->graphic_mode) {
1273 s->graphic_mode = graphic_mode;
1277 vga_draw_graphic(s, full_update);
1279 vga_draw_text(s, full_update);
1283 void vga_reset(VGAState *s)
1285 memset(s, 0, sizeof(VGAState));
1286 /* chip ID for 8c968 */
1289 s->cr[0x2f] = 0x01; /* XXX: check revision code */
1291 s->graphic_mode = -1; /* force full update */
1294 CPUReadMemoryFunc *vga_mem_read[3] = {
1300 CPUWriteMemoryFunc *vga_mem_write[3] = {
1306 int vga_init(DisplayState *ds, uint8_t *vga_ram_base,
1307 unsigned long vga_ram_offset, int vga_ram_size)
1309 VGAState *s = &vga_state;
1312 for(i = 0;i < 256; i++) {
1314 for(j = 0; j < 8; j++) {
1315 v |= ((i >> j) & 1) << (j * 4);
1320 for(j = 0; j < 4; j++) {
1321 v |= ((i >> (2 * j)) & 3) << (j * 4);
1325 for(i = 0; i < 16; i++) {
1327 for(j = 0; j < 4; j++) {
1330 v |= b << (2 * j + 1);
1339 s->rgb_to_pixel = rgb_to_pixel8_dup;
1342 s->rgb_to_pixel = rgb_to_pixel15_dup;
1346 s->rgb_to_pixel = rgb_to_pixel16_dup;
1349 s->rgb_to_pixel = rgb_to_pixel32_dup;
1353 s->vram_ptr = vga_ram_base;
1354 s->vram_offset = vga_ram_offset;
1355 s->vram_size = vga_ram_size;
1358 register_ioport_write(0x3c0, 16, vga_ioport_write, 1);
1360 register_ioport_write(0x3b4, 2, vga_ioport_write, 1);
1361 register_ioport_write(0x3d4, 2, vga_ioport_write, 1);
1362 register_ioport_write(0x3ba, 1, vga_ioport_write, 1);
1363 register_ioport_write(0x3da, 1, vga_ioport_write, 1);
1365 register_ioport_read(0x3c0, 16, vga_ioport_read, 1);
1367 register_ioport_read(0x3b4, 2, vga_ioport_read, 1);
1368 register_ioport_read(0x3d4, 2, vga_ioport_read, 1);
1369 register_ioport_read(0x3ba, 1, vga_ioport_read, 1);
1370 register_ioport_read(0x3da, 1, vga_ioport_read, 1);
1372 vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write);
1373 cpu_register_physical_memory(0xa0000, 0x20000, vga_io_memory);