Commit 17b0018b4200b674bfcb7c946fce89f0a5ffaa24
1 parent
39cf7803
Full VGA support, including old CGA modes, VGA planar and mode X
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@346 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
340 additions
and
81 deletions
hw/vga.c
@@ -49,6 +49,7 @@ | @@ -49,6 +49,7 @@ | ||
49 | #include "thunk.h" | 49 | #include "thunk.h" |
50 | 50 | ||
51 | //#define DEBUG_VGA | 51 | //#define DEBUG_VGA |
52 | +//#define DEBUG_VGA_MEM | ||
52 | 53 | ||
53 | #define MSR_COLOR_EMULATION 0x01 | 54 | #define MSR_COLOR_EMULATION 0x01 |
54 | #define MSR_PAGE_SELECT 0x20 | 55 | #define MSR_PAGE_SELECT 0x20 |
@@ -85,7 +86,8 @@ typedef struct VGAState { | @@ -85,7 +86,8 @@ typedef struct VGAState { | ||
85 | DisplayState *ds; | 86 | DisplayState *ds; |
86 | uint32_t font_offsets[2]; | 87 | uint32_t font_offsets[2]; |
87 | int graphic_mode; | 88 | int graphic_mode; |
88 | - int shift_control; | 89 | + uint8_t shift_control; |
90 | + uint8_t double_scan; | ||
89 | uint32_t line_offset; | 91 | uint32_t line_offset; |
90 | uint32_t line_compare; | 92 | uint32_t line_compare; |
91 | uint32_t start_addr; | 93 | uint32_t start_addr; |
@@ -93,10 +95,11 @@ typedef struct VGAState { | @@ -93,10 +95,11 @@ typedef struct VGAState { | ||
93 | uint32_t last_width, last_height; | 95 | uint32_t last_width, last_height; |
94 | uint8_t cursor_start, cursor_end; | 96 | uint8_t cursor_start, cursor_end; |
95 | uint32_t cursor_offset; | 97 | uint32_t cursor_offset; |
98 | + unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned b); | ||
96 | /* tell for each page if it has been updated since the last time */ | 99 | /* tell for each page if it has been updated since the last time */ |
97 | uint8_t vram_updated[VGA_RAM_SIZE / 4096]; | 100 | uint8_t vram_updated[VGA_RAM_SIZE / 4096]; |
98 | uint32_t last_palette[256]; | 101 | uint32_t last_palette[256]; |
99 | -#define CH_ATTR_SIZE (132 * 60) | 102 | +#define CH_ATTR_SIZE (160 * 100) |
100 | uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */ | 103 | uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */ |
101 | } VGAState; | 104 | } VGAState; |
102 | 105 | ||
@@ -199,6 +202,7 @@ static const uint32_t dmask4[4] = { | @@ -199,6 +202,7 @@ static const uint32_t dmask4[4] = { | ||
199 | 202 | ||
200 | static uint32_t expand4[256]; | 203 | static uint32_t expand4[256]; |
201 | static uint16_t expand2[256]; | 204 | static uint16_t expand2[256]; |
205 | +static uint8_t expand4to8[16]; | ||
202 | 206 | ||
203 | VGAState vga_state; | 207 | VGAState vga_state; |
204 | int vga_io_memory; | 208 | int vga_io_memory; |
@@ -503,7 +507,7 @@ void vga_mem_writeb(uint32_t addr, uint32_t val) | @@ -503,7 +507,7 @@ void vga_mem_writeb(uint32_t addr, uint32_t val) | ||
503 | int memory_map_mode, plane, write_mode, b, func_select; | 507 | int memory_map_mode, plane, write_mode, b, func_select; |
504 | uint32_t write_mask, bit_mask, set_mask; | 508 | uint32_t write_mask, bit_mask, set_mask; |
505 | 509 | ||
506 | -#ifdef DEBUG_VGA | 510 | +#ifdef DEBUG_VGA_MEM |
507 | printf("vga: [0x%x] = 0x%02x\n", addr, val); | 511 | printf("vga: [0x%x] = 0x%02x\n", addr, val); |
508 | #endif | 512 | #endif |
509 | /* convert to VGA memory offset */ | 513 | /* convert to VGA memory offset */ |
@@ -533,7 +537,7 @@ void vga_mem_writeb(uint32_t addr, uint32_t val) | @@ -533,7 +537,7 @@ void vga_mem_writeb(uint32_t addr, uint32_t val) | ||
533 | plane = addr & 3; | 537 | plane = addr & 3; |
534 | if (s->sr[2] & (1 << plane)) { | 538 | if (s->sr[2] & (1 << plane)) { |
535 | s->vram_ptr[addr] = val; | 539 | s->vram_ptr[addr] = val; |
536 | -#ifdef DEBUG_VGA | 540 | +#ifdef DEBUG_VGA_MEM |
537 | printf("vga: chain4: [0x%x]\n", addr); | 541 | printf("vga: chain4: [0x%x]\n", addr); |
538 | #endif | 542 | #endif |
539 | s->vram_updated[addr >> 12] = 1; | 543 | s->vram_updated[addr >> 12] = 1; |
@@ -544,7 +548,7 @@ void vga_mem_writeb(uint32_t addr, uint32_t val) | @@ -544,7 +548,7 @@ void vga_mem_writeb(uint32_t addr, uint32_t val) | ||
544 | if (s->sr[2] & (1 << plane)) { | 548 | if (s->sr[2] & (1 << plane)) { |
545 | addr = ((addr & ~1) << 1) | plane; | 549 | addr = ((addr & ~1) << 1) | plane; |
546 | s->vram_ptr[addr] = val; | 550 | s->vram_ptr[addr] = val; |
547 | -#ifdef DEBUG_VGA | 551 | +#ifdef DEBUG_VGA_MEM |
548 | printf("vga: odd/even: [0x%x]\n", addr); | 552 | printf("vga: odd/even: [0x%x]\n", addr); |
549 | #endif | 553 | #endif |
550 | s->vram_updated[addr >> 12] = 1; | 554 | s->vram_updated[addr >> 12] = 1; |
@@ -615,7 +619,7 @@ void vga_mem_writeb(uint32_t addr, uint32_t val) | @@ -615,7 +619,7 @@ void vga_mem_writeb(uint32_t addr, uint32_t val) | ||
615 | ((uint32_t *)s->vram_ptr)[addr] = | 619 | ((uint32_t *)s->vram_ptr)[addr] = |
616 | (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) | | 620 | (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) | |
617 | (val & write_mask); | 621 | (val & write_mask); |
618 | -#ifdef DEBUG_VGA | 622 | +#ifdef DEBUG_VGA_MEM |
619 | printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n", | 623 | printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n", |
620 | addr * 4, write_mask, val); | 624 | addr * 4, write_mask, val); |
621 | #endif | 625 | #endif |
@@ -699,28 +703,43 @@ static inline int c6_to_8(int v) | @@ -699,28 +703,43 @@ static inline int c6_to_8(int v) | ||
699 | return (v << 2) | (b << 1) | b; | 703 | return (v << 2) | (b << 1) | b; |
700 | } | 704 | } |
701 | 705 | ||
706 | +static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b) | ||
707 | +{ | ||
708 | + unsigned int col; | ||
709 | + col = rgb_to_pixel8(r, g, b); | ||
710 | + col |= col << 8; | ||
711 | + col |= col << 16; | ||
712 | + return col; | ||
713 | +} | ||
714 | + | ||
715 | +static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b) | ||
716 | +{ | ||
717 | + unsigned int col; | ||
718 | + col = rgb_to_pixel15(r, g, b); | ||
719 | + col |= col << 16; | ||
720 | + return col; | ||
721 | +} | ||
722 | + | ||
723 | +static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b) | ||
724 | +{ | ||
725 | + unsigned int col; | ||
726 | + col = rgb_to_pixel16(r, g, b); | ||
727 | + col |= col << 16; | ||
728 | + return col; | ||
729 | +} | ||
730 | + | ||
731 | +static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b) | ||
732 | +{ | ||
733 | + unsigned int col; | ||
734 | + col = rgb_to_pixel32(r, g, b); | ||
735 | + return col; | ||
736 | +} | ||
737 | + | ||
702 | /* return true if the palette was modified */ | 738 | /* return true if the palette was modified */ |
703 | static int update_palette16(VGAState *s) | 739 | static int update_palette16(VGAState *s) |
704 | { | 740 | { |
705 | - int full_update, i, depth; | 741 | + int full_update, i; |
706 | uint32_t v, col, *palette; | 742 | uint32_t v, col, *palette; |
707 | - unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned b); | ||
708 | - depth = s->ds->depth; | ||
709 | - switch(depth) { | ||
710 | - case 8: | ||
711 | - rgb_to_pixel = rgb_to_pixel8; | ||
712 | - break; | ||
713 | - case 15: | ||
714 | - rgb_to_pixel = rgb_to_pixel15; | ||
715 | - break; | ||
716 | - default: | ||
717 | - case 16: | ||
718 | - rgb_to_pixel = rgb_to_pixel16; | ||
719 | - break; | ||
720 | - case 32: | ||
721 | - rgb_to_pixel = rgb_to_pixel32; | ||
722 | - break; | ||
723 | - } | ||
724 | 743 | ||
725 | full_update = 0; | 744 | full_update = 0; |
726 | palette = s->last_palette; | 745 | palette = s->last_palette; |
@@ -731,21 +750,35 @@ static int update_palette16(VGAState *s) | @@ -731,21 +750,35 @@ static int update_palette16(VGAState *s) | ||
731 | else | 750 | else |
732 | v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f); | 751 | v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f); |
733 | v = v * 3; | 752 | v = v * 3; |
734 | - col = rgb_to_pixel(c6_to_8(s->palette[v]), | ||
735 | - c6_to_8(s->palette[v + 1]), | ||
736 | - c6_to_8(s->palette[v + 2])); | ||
737 | - | ||
738 | - if (depth == 8) { | ||
739 | - col |= col << 8; | ||
740 | - col |= col << 16; | ||
741 | - } else if (depth <= 16) { | ||
742 | - col |= col << 16; | 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]) { | ||
757 | + full_update = 1; | ||
758 | + palette[i] = col; | ||
743 | } | 759 | } |
744 | - // printf("%2d: %08x\n", i, col); | 760 | + } |
761 | + return full_update; | ||
762 | +} | ||
763 | + | ||
764 | +/* return true if the palette was modified */ | ||
765 | +static int update_palette256(VGAState *s) | ||
766 | +{ | ||
767 | + int full_update, i; | ||
768 | + uint32_t v, col, *palette; | ||
769 | + | ||
770 | + full_update = 0; | ||
771 | + palette = s->last_palette; | ||
772 | + v = 0; | ||
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])); | ||
745 | if (col != palette[i]) { | 777 | if (col != palette[i]) { |
746 | full_update = 1; | 778 | full_update = 1; |
747 | palette[i] = col; | 779 | palette[i] = col; |
748 | } | 780 | } |
781 | + v += 3; | ||
749 | } | 782 | } |
750 | return full_update; | 783 | return full_update; |
751 | } | 784 | } |
@@ -806,6 +839,13 @@ static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = { | @@ -806,6 +839,13 @@ static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = { | ||
806 | vga_draw_glyph8_32, | 839 | vga_draw_glyph8_32, |
807 | }; | 840 | }; |
808 | 841 | ||
842 | +static vga_draw_glyph8_func *vga_draw_glyph16_table[4] = { | ||
843 | + vga_draw_glyph16_8, | ||
844 | + vga_draw_glyph16_16, | ||
845 | + vga_draw_glyph16_16, | ||
846 | + vga_draw_glyph16_32, | ||
847 | +}; | ||
848 | + | ||
809 | static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = { | 849 | static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = { |
810 | vga_draw_glyph9_8, | 850 | vga_draw_glyph9_8, |
811 | vga_draw_glyph9_16, | 851 | vga_draw_glyph9_16, |
@@ -882,12 +922,19 @@ static void vga_draw_text(VGAState *s, int full_update) | @@ -882,12 +922,19 @@ static void vga_draw_text(VGAState *s, int full_update) | ||
882 | cw = 8; | 922 | cw = 8; |
883 | if (s->sr[1] & 0x01) | 923 | if (s->sr[1] & 0x01) |
884 | cw = 9; | 924 | cw = 9; |
925 | + if (s->sr[1] & 0x08) | ||
926 | + cw = 16; /* NOTE: no 18 pixel wide */ | ||
885 | x_incr = cw * ((s->ds->depth + 7) >> 3); | 927 | x_incr = cw * ((s->ds->depth + 7) >> 3); |
886 | width = (s->cr[0x01] + 1); | 928 | width = (s->cr[0x01] + 1); |
887 | - height = s->cr[0x12] | | ||
888 | - ((s->cr[0x07] & 0x02) << 7) | | ||
889 | - ((s->cr[0x07] & 0x40) << 3); | ||
890 | - height = (height + 1) / cheight; | 929 | + if (s->cr[0x06] == 100) { |
930 | + /* ugly hack for CGA 160x100x16 - explain me the logic */ | ||
931 | + height = 100; | ||
932 | + } else { | ||
933 | + height = s->cr[0x12] | | ||
934 | + ((s->cr[0x07] & 0x02) << 7) | | ||
935 | + ((s->cr[0x07] & 0x40) << 3); | ||
936 | + height = (height + 1) / cheight; | ||
937 | + } | ||
891 | if (width != s->last_width || height != s->last_height || | 938 | if (width != s->last_width || height != s->last_height || |
892 | cw != s->last_cw || cw != s->last_cw) { | 939 | cw != s->last_cw || cw != s->last_cw) { |
893 | dpy_resize(s->ds, width * cw, height * cheight); | 940 | dpy_resize(s->ds, width * cw, height * cheight); |
@@ -914,7 +961,10 @@ static void vga_draw_text(VGAState *s, int full_update) | @@ -914,7 +961,10 @@ static void vga_draw_text(VGAState *s, int full_update) | ||
914 | cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4; | 961 | cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4; |
915 | 962 | ||
916 | depth_index = get_depth_index(s->ds->depth); | 963 | depth_index = get_depth_index(s->ds->depth); |
917 | - vga_draw_glyph8 = vga_draw_glyph8_table[depth_index]; | 964 | + if (cw == 16) |
965 | + vga_draw_glyph8 = vga_draw_glyph16_table[depth_index]; | ||
966 | + else | ||
967 | + vga_draw_glyph8 = vga_draw_glyph8_table[depth_index]; | ||
918 | vga_draw_glyph9 = vga_draw_glyph9_table[depth_index]; | 968 | vga_draw_glyph9 = vga_draw_glyph9_table[depth_index]; |
919 | 969 | ||
920 | dest = s->ds->data; | 970 | dest = s->ds->data; |
@@ -944,7 +994,7 @@ static void vga_draw_text(VGAState *s, int full_update) | @@ -944,7 +994,7 @@ static void vga_draw_text(VGAState *s, int full_update) | ||
944 | font_ptr += 32 * 4 * ch; | 994 | font_ptr += 32 * 4 * ch; |
945 | bgcol = palette[cattr >> 4]; | 995 | bgcol = palette[cattr >> 4]; |
946 | fgcol = palette[cattr & 0x0f]; | 996 | fgcol = palette[cattr & 0x0f]; |
947 | - if (cw == 8) { | 997 | + if (cw != 9) { |
948 | vga_draw_glyph8(d1, linesize, | 998 | vga_draw_glyph8(d1, linesize, |
949 | font_ptr, cheight, fgcol, bgcol); | 999 | font_ptr, cheight, fgcol, bgcol); |
950 | } else { | 1000 | } else { |
@@ -966,7 +1016,7 @@ static void vga_draw_text(VGAState *s, int full_update) | @@ -966,7 +1016,7 @@ static void vga_draw_text(VGAState *s, int full_update) | ||
966 | if (line_last >= line_start && line_start < cheight) { | 1016 | if (line_last >= line_start && line_start < cheight) { |
967 | h = line_last - line_start + 1; | 1017 | h = line_last - line_start + 1; |
968 | d = d1 + linesize * line_start; | 1018 | d = d1 + linesize * line_start; |
969 | - if (cw == 8) { | 1019 | + if (cw != 9) { |
970 | vga_draw_glyph8(d, linesize, | 1020 | vga_draw_glyph8(d, linesize, |
971 | cursor_glyph, h, fgcol, bgcol); | 1021 | cursor_glyph, h, fgcol, bgcol); |
972 | } else { | 1022 | } else { |
@@ -989,17 +1039,45 @@ static void vga_draw_text(VGAState *s, int full_update) | @@ -989,17 +1039,45 @@ static void vga_draw_text(VGAState *s, int full_update) | ||
989 | } | 1039 | } |
990 | } | 1040 | } |
991 | 1041 | ||
992 | -static vga_draw_line_func *vga_draw_line_table[4 * 6] = { | 1042 | +enum { |
1043 | + VGA_DRAW_LINE2, | ||
1044 | + VGA_DRAW_LINE2D2, | ||
1045 | + VGA_DRAW_LINE4, | ||
1046 | + VGA_DRAW_LINE4D2, | ||
1047 | + VGA_DRAW_LINE8D2, | ||
1048 | + VGA_DRAW_LINE8, | ||
1049 | + VGA_DRAW_LINE15, | ||
1050 | + VGA_DRAW_LINE16, | ||
1051 | + VGA_DRAW_LINE32, | ||
1052 | + VGA_DRAW_LINE_NB, | ||
1053 | +}; | ||
1054 | + | ||
1055 | +static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = { | ||
993 | vga_draw_line2_8, | 1056 | vga_draw_line2_8, |
994 | vga_draw_line2_16, | 1057 | vga_draw_line2_16, |
995 | vga_draw_line2_16, | 1058 | vga_draw_line2_16, |
996 | vga_draw_line2_32, | 1059 | vga_draw_line2_32, |
997 | 1060 | ||
1061 | + vga_draw_line2d2_8, | ||
1062 | + vga_draw_line2d2_16, | ||
1063 | + vga_draw_line2d2_16, | ||
1064 | + vga_draw_line2d2_32, | ||
1065 | + | ||
998 | vga_draw_line4_8, | 1066 | vga_draw_line4_8, |
999 | vga_draw_line4_16, | 1067 | vga_draw_line4_16, |
1000 | vga_draw_line4_16, | 1068 | vga_draw_line4_16, |
1001 | vga_draw_line4_32, | 1069 | vga_draw_line4_32, |
1002 | 1070 | ||
1071 | + vga_draw_line4d2_8, | ||
1072 | + vga_draw_line4d2_16, | ||
1073 | + vga_draw_line4d2_16, | ||
1074 | + vga_draw_line4d2_32, | ||
1075 | + | ||
1076 | + vga_draw_line8d2_8, | ||
1077 | + vga_draw_line8d2_16, | ||
1078 | + vga_draw_line8d2_16, | ||
1079 | + vga_draw_line8d2_32, | ||
1080 | + | ||
1003 | vga_draw_line8_8, | 1081 | vga_draw_line8_8, |
1004 | vga_draw_line8_16, | 1082 | vga_draw_line8_16, |
1005 | vga_draw_line8_16, | 1083 | vga_draw_line8_16, |
@@ -1029,14 +1107,13 @@ static vga_draw_line_func *vga_draw_line_table[4 * 6] = { | @@ -1029,14 +1107,13 @@ static vga_draw_line_func *vga_draw_line_table[4 * 6] = { | ||
1029 | */ | 1107 | */ |
1030 | static void vga_draw_graphic(VGAState *s, int full_update) | 1108 | static void vga_draw_graphic(VGAState *s, int full_update) |
1031 | { | 1109 | { |
1032 | - int y, update, page_min, page_max, linesize, y_start; | 1110 | + int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask; |
1033 | int width, height, shift_control, line_offset, page0, page1, bwidth; | 1111 | int width, height, shift_control, line_offset, page0, page1, bwidth; |
1112 | + int disp_width; | ||
1034 | uint8_t *d; | 1113 | uint8_t *d; |
1035 | uint32_t v, addr1, addr; | 1114 | uint32_t v, addr1, addr; |
1036 | vga_draw_line_func *vga_draw_line; | 1115 | vga_draw_line_func *vga_draw_line; |
1037 | - | ||
1038 | - full_update |= update_palette16(s); | ||
1039 | - | 1116 | + |
1040 | full_update |= update_basic_params(s); | 1117 | full_update |= update_basic_params(s); |
1041 | 1118 | ||
1042 | width = (s->cr[0x01] + 1) * 8; | 1119 | width = (s->cr[0x01] + 1) * 8; |
@@ -1044,30 +1121,53 @@ static void vga_draw_graphic(VGAState *s, int full_update) | @@ -1044,30 +1121,53 @@ static void vga_draw_graphic(VGAState *s, int full_update) | ||
1044 | ((s->cr[0x07] & 0x02) << 7) | | 1121 | ((s->cr[0x07] & 0x02) << 7) | |
1045 | ((s->cr[0x07] & 0x40) << 3); | 1122 | ((s->cr[0x07] & 0x40) << 3); |
1046 | height = (height + 1); | 1123 | height = (height + 1); |
1047 | - | ||
1048 | - if (width != s->last_width || | ||
1049 | - height != s->last_height) { | ||
1050 | - dpy_resize(s->ds, width, height); | ||
1051 | - s->last_width = width; | ||
1052 | - s->last_height = height; | ||
1053 | - full_update = 1; | ||
1054 | - } | ||
1055 | - | 1124 | + disp_width = width; |
1125 | + | ||
1056 | shift_control = (s->gr[0x05] >> 5) & 3; | 1126 | shift_control = (s->gr[0x05] >> 5) & 3; |
1057 | - if (shift_control != s->shift_control) { | 1127 | + double_scan = (s->cr[0x09] & 0x80); |
1128 | + if (shift_control != s->shift_control || | ||
1129 | + double_scan != s->double_scan) { | ||
1058 | full_update = 1; | 1130 | full_update = 1; |
1059 | s->shift_control = shift_control; | 1131 | s->shift_control = shift_control; |
1132 | + s->double_scan = double_scan; | ||
1060 | } | 1133 | } |
1061 | 1134 | ||
1062 | - if (shift_control == 0) | ||
1063 | - v = 1; /* 4 bit/pixel */ | ||
1064 | - else if (shift_control == 1) | ||
1065 | - v = 0; /* 2 bit/pixel */ | ||
1066 | - else | ||
1067 | - v = 2; /* 8 bit/pixel */ | 1135 | + if (shift_control == 0) { |
1136 | + full_update |= update_palette16(s); | ||
1137 | + if (s->sr[0x01] & 8) { | ||
1138 | + v = VGA_DRAW_LINE4D2; | ||
1139 | + disp_width <<= 1; | ||
1140 | + } else { | ||
1141 | + v = VGA_DRAW_LINE4; | ||
1142 | + } | ||
1143 | + } else if (shift_control == 1) { | ||
1144 | + full_update |= update_palette16(s); | ||
1145 | + if (s->sr[0x01] & 8) { | ||
1146 | + v = VGA_DRAW_LINE2D2; | ||
1147 | + disp_width <<= 1; | ||
1148 | + } else { | ||
1149 | + v = VGA_DRAW_LINE2; | ||
1150 | + } | ||
1151 | + } else { | ||
1152 | + full_update |= update_palette256(s); | ||
1153 | + v = VGA_DRAW_LINE8D2; | ||
1154 | + double_scan = 1; /* XXX: explain me why it is always activated */ | ||
1155 | + } | ||
1068 | vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)]; | 1156 | vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)]; |
1069 | - | 1157 | + |
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; | ||
1163 | + full_update = 1; | ||
1164 | + } | ||
1165 | + | ||
1070 | line_offset = s->line_offset; | 1166 | line_offset = s->line_offset; |
1167 | +#if 0 | ||
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]); | ||
1170 | +#endif | ||
1071 | addr1 = (s->start_addr * 4); | 1171 | addr1 = (s->start_addr * 4); |
1072 | bwidth = width * 4; | 1172 | bwidth = width * 4; |
1073 | y_start = -1; | 1173 | y_start = -1; |
@@ -1075,14 +1175,17 @@ static void vga_draw_graphic(VGAState *s, int full_update) | @@ -1075,14 +1175,17 @@ static void vga_draw_graphic(VGAState *s, int full_update) | ||
1075 | page_max = -1; | 1175 | page_max = -1; |
1076 | d = s->ds->data; | 1176 | d = s->ds->data; |
1077 | linesize = s->ds->linesize; | 1177 | linesize = s->ds->linesize; |
1178 | + y1 = 0; | ||
1078 | for(y = 0; y < height; y++) { | 1179 | for(y = 0; y < height; y++) { |
1079 | addr = addr1; | 1180 | addr = addr1; |
1080 | if (!(s->cr[0x17] & 1)) { | 1181 | if (!(s->cr[0x17] & 1)) { |
1182 | + int shift; | ||
1081 | /* CGA compatibility handling */ | 1183 | /* CGA compatibility handling */ |
1082 | - addr = (addr & ~0x2000) | ((y & 1) << 13); | 1184 | + shift = 14 + ((s->cr[0x17] >> 6) & 1); |
1185 | + addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift); | ||
1083 | } | 1186 | } |
1084 | if (!(s->cr[0x17] & 2)) { | 1187 | if (!(s->cr[0x17] & 2)) { |
1085 | - addr = (addr & ~0x4000) | ((y & 2) << 13); | 1188 | + addr = (addr & ~0x8000) | ((y1 & 2) << 14); |
1086 | } | 1189 | } |
1087 | page0 = addr >> 12; | 1190 | page0 = addr >> 12; |
1088 | page1 = (addr + bwidth - 1) >> 12; | 1191 | page1 = (addr + bwidth - 1) >> 12; |
@@ -1103,21 +1206,26 @@ static void vga_draw_graphic(VGAState *s, int full_update) | @@ -1103,21 +1206,26 @@ static void vga_draw_graphic(VGAState *s, int full_update) | ||
1103 | if (y_start >= 0) { | 1206 | if (y_start >= 0) { |
1104 | /* flush to display */ | 1207 | /* flush to display */ |
1105 | dpy_update(s->ds, 0, y_start, | 1208 | dpy_update(s->ds, 0, y_start, |
1106 | - width, y - y_start); | 1209 | + disp_width, y - y_start); |
1107 | y_start = -1; | 1210 | y_start = -1; |
1108 | } | 1211 | } |
1109 | } | 1212 | } |
1110 | - if (y == s->line_compare) { | ||
1111 | - addr1 = 0; | ||
1112 | - } else { | ||
1113 | - addr1 += line_offset; | 1213 | + if (!double_scan || (y & 1) != 0) { |
1214 | + if (y1 == s->line_compare) { | ||
1215 | + addr1 = 0; | ||
1216 | + } else { | ||
1217 | + mask = (s->cr[0x17] & 3) ^ 3; | ||
1218 | + if ((y1 & mask) == mask) | ||
1219 | + addr1 += line_offset; | ||
1220 | + } | ||
1221 | + y1++; | ||
1114 | } | 1222 | } |
1115 | d += linesize; | 1223 | d += linesize; |
1116 | } | 1224 | } |
1117 | if (y_start >= 0) { | 1225 | if (y_start >= 0) { |
1118 | /* flush to display */ | 1226 | /* flush to display */ |
1119 | dpy_update(s->ds, 0, y_start, | 1227 | dpy_update(s->ds, 0, y_start, |
1120 | - width, y - y_start); | 1228 | + disp_width, y - y_start); |
1121 | } | 1229 | } |
1122 | /* reset modified pages */ | 1230 | /* reset modified pages */ |
1123 | if (page_max != -1) { | 1231 | if (page_max != -1) { |
@@ -1199,7 +1307,7 @@ int vga_init(DisplayState *ds, uint8_t *vga_ram_base, | @@ -1199,7 +1307,7 @@ int vga_init(DisplayState *ds, uint8_t *vga_ram_base, | ||
1199 | unsigned long vga_ram_offset, int vga_ram_size) | 1307 | unsigned long vga_ram_offset, int vga_ram_size) |
1200 | { | 1308 | { |
1201 | VGAState *s = &vga_state; | 1309 | VGAState *s = &vga_state; |
1202 | - int i, j, v; | 1310 | + int i, j, v, b; |
1203 | 1311 | ||
1204 | for(i = 0;i < 256; i++) { | 1312 | for(i = 0;i < 256; i++) { |
1205 | v = 0; | 1313 | v = 0; |
@@ -1214,9 +1322,34 @@ int vga_init(DisplayState *ds, uint8_t *vga_ram_base, | @@ -1214,9 +1322,34 @@ int vga_init(DisplayState *ds, uint8_t *vga_ram_base, | ||
1214 | } | 1322 | } |
1215 | expand2[i] = v; | 1323 | expand2[i] = v; |
1216 | } | 1324 | } |
1325 | + for(i = 0; i < 16; i++) { | ||
1326 | + v = 0; | ||
1327 | + for(j = 0; j < 4; j++) { | ||
1328 | + b = ((i >> j) & 1); | ||
1329 | + v |= b << (2 * j); | ||
1330 | + v |= b << (2 * j + 1); | ||
1331 | + } | ||
1332 | + expand4to8[i] = v; | ||
1333 | + } | ||
1217 | 1334 | ||
1218 | vga_reset(s); | 1335 | vga_reset(s); |
1219 | 1336 | ||
1337 | + switch(ds->depth) { | ||
1338 | + case 8: | ||
1339 | + s->rgb_to_pixel = rgb_to_pixel8_dup; | ||
1340 | + break; | ||
1341 | + case 15: | ||
1342 | + s->rgb_to_pixel = rgb_to_pixel15_dup; | ||
1343 | + break; | ||
1344 | + default: | ||
1345 | + case 16: | ||
1346 | + s->rgb_to_pixel = rgb_to_pixel16_dup; | ||
1347 | + break; | ||
1348 | + case 32: | ||
1349 | + s->rgb_to_pixel = rgb_to_pixel32_dup; | ||
1350 | + break; | ||
1351 | + } | ||
1352 | + | ||
1220 | s->vram_ptr = vga_ram_base; | 1353 | s->vram_ptr = vga_ram_base; |
1221 | s->vram_offset = vga_ram_offset; | 1354 | s->vram_offset = vga_ram_offset; |
1222 | s->vram_size = vga_ram_size; | 1355 | s->vram_size = vga_ram_size; |
hw/vga_template.h
@@ -37,15 +37,11 @@ | @@ -37,15 +37,11 @@ | ||
37 | 37 | ||
38 | #if DEPTH != 15 | 38 | #if DEPTH != 15 |
39 | 39 | ||
40 | -static void glue(vga_draw_glyph8_, DEPTH)(uint8_t *d, int linesize, | ||
41 | - const uint8_t *font_ptr, int h, | ||
42 | - uint32_t fgcol, uint32_t bgcol) | 40 | +static inline void glue(vga_draw_glyph_line_, DEPTH)(uint8_t *d, |
41 | + uint32_t font_data, | ||
42 | + uint32_t xorcol, | ||
43 | + uint32_t bgcol) | ||
43 | { | 44 | { |
44 | - uint32_t font_data, xorcol; | ||
45 | - | ||
46 | - xorcol = bgcol ^ fgcol; | ||
47 | - do { | ||
48 | - font_data = font_ptr[0]; | ||
49 | #if BPP == 1 | 45 | #if BPP == 1 |
50 | ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol; | 46 | ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol; |
51 | ((uint32_t *)d)[3] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol; | 47 | ((uint32_t *)d)[3] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol; |
@@ -64,6 +60,38 @@ static void glue(vga_draw_glyph8_, DEPTH)(uint8_t *d, int linesize, | @@ -64,6 +60,38 @@ static void glue(vga_draw_glyph8_, DEPTH)(uint8_t *d, int linesize, | ||
64 | ((uint32_t *)d)[6] = ((-(font_data >> 1) & 1) & xorcol) ^ bgcol; | 60 | ((uint32_t *)d)[6] = ((-(font_data >> 1) & 1) & xorcol) ^ bgcol; |
65 | ((uint32_t *)d)[7] = ((-(font_data >> 0) & 1) & xorcol) ^ bgcol; | 61 | ((uint32_t *)d)[7] = ((-(font_data >> 0) & 1) & xorcol) ^ bgcol; |
66 | #endif | 62 | #endif |
63 | +} | ||
64 | + | ||
65 | +static void glue(vga_draw_glyph8_, DEPTH)(uint8_t *d, int linesize, | ||
66 | + const uint8_t *font_ptr, int h, | ||
67 | + uint32_t fgcol, uint32_t bgcol) | ||
68 | +{ | ||
69 | + uint32_t font_data, xorcol; | ||
70 | + | ||
71 | + xorcol = bgcol ^ fgcol; | ||
72 | + do { | ||
73 | + font_data = font_ptr[0]; | ||
74 | + glue(vga_draw_glyph_line_, DEPTH)(d, font_data, xorcol, bgcol); | ||
75 | + font_ptr += 4; | ||
76 | + d += linesize; | ||
77 | + } while (--h); | ||
78 | +} | ||
79 | + | ||
80 | +static void glue(vga_draw_glyph16_, DEPTH)(uint8_t *d, int linesize, | ||
81 | + const uint8_t *font_ptr, int h, | ||
82 | + uint32_t fgcol, uint32_t bgcol) | ||
83 | +{ | ||
84 | + uint32_t font_data, xorcol; | ||
85 | + | ||
86 | + xorcol = bgcol ^ fgcol; | ||
87 | + do { | ||
88 | + font_data = font_ptr[0]; | ||
89 | + glue(vga_draw_glyph_line_, DEPTH)(d, | ||
90 | + expand4to8[font_data >> 4], | ||
91 | + xorcol, bgcol); | ||
92 | + glue(vga_draw_glyph_line_, DEPTH)(d + 8 * BPP, | ||
93 | + expand4to8[font_data & 0x0f], | ||
94 | + xorcol, bgcol); | ||
67 | font_ptr += 4; | 95 | font_ptr += 4; |
68 | d += linesize; | 96 | d += linesize; |
69 | } while (--h); | 97 | } while (--h); |
@@ -151,6 +179,48 @@ static void glue(vga_draw_line2_, DEPTH)(VGAState *s1, uint8_t *d, | @@ -151,6 +179,48 @@ static void glue(vga_draw_line2_, DEPTH)(VGAState *s1, uint8_t *d, | ||
151 | } | 179 | } |
152 | } | 180 | } |
153 | 181 | ||
182 | +#if BPP == 1 | ||
183 | +#define PUT_PIXEL2(d, n, v) ((uint16_t *)d)[(n)] = (v) | ||
184 | +#elif BPP == 2 | ||
185 | +#define PUT_PIXEL2(d, n, v) ((uint32_t *)d)[(n)] = (v) | ||
186 | +#else | ||
187 | +#define PUT_PIXEL2(d, n, v) \ | ||
188 | +((uint32_t *)d)[2*(n)] = ((uint32_t *)d)[2*(n)+1] = (v) | ||
189 | +#endif | ||
190 | + | ||
191 | +/* | ||
192 | + * 4 color mode, dup2 horizontal | ||
193 | + */ | ||
194 | +static void glue(vga_draw_line2d2_, DEPTH)(VGAState *s1, uint8_t *d, | ||
195 | + const uint8_t *s, int width) | ||
196 | +{ | ||
197 | + uint32_t plane_mask, *palette, data, v; | ||
198 | + int x; | ||
199 | + | ||
200 | + palette = s1->last_palette; | ||
201 | + plane_mask = mask16[s1->ar[0x12] & 0xf]; | ||
202 | + width >>= 3; | ||
203 | + for(x = 0; x < width; x++) { | ||
204 | + data = ((uint32_t *)s)[0]; | ||
205 | + data &= plane_mask; | ||
206 | + v = expand2[GET_PLANE(data, 0)]; | ||
207 | + v |= expand2[GET_PLANE(data, 2)] << 2; | ||
208 | + PUT_PIXEL2(d, 0, palette[v >> 12]); | ||
209 | + PUT_PIXEL2(d, 1, palette[(v >> 8) & 0xf]); | ||
210 | + PUT_PIXEL2(d, 2, palette[(v >> 4) & 0xf]); | ||
211 | + PUT_PIXEL2(d, 3, palette[(v >> 0) & 0xf]); | ||
212 | + | ||
213 | + v = expand2[GET_PLANE(data, 1)]; | ||
214 | + v |= expand2[GET_PLANE(data, 3)] << 2; | ||
215 | + PUT_PIXEL2(d, 4, palette[v >> 12]); | ||
216 | + PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]); | ||
217 | + PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]); | ||
218 | + PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]); | ||
219 | + d += BPP * 16; | ||
220 | + s += 4; | ||
221 | + } | ||
222 | +} | ||
223 | + | ||
154 | /* | 224 | /* |
155 | * 16 color mode | 225 | * 16 color mode |
156 | */ | 226 | */ |
@@ -184,7 +254,62 @@ static void glue(vga_draw_line4_, DEPTH)(VGAState *s1, uint8_t *d, | @@ -184,7 +254,62 @@ static void glue(vga_draw_line4_, DEPTH)(VGAState *s1, uint8_t *d, | ||
184 | } | 254 | } |
185 | 255 | ||
186 | /* | 256 | /* |
187 | - * 256 color mode | 257 | + * 16 color mode, dup2 horizontal |
258 | + */ | ||
259 | +static void glue(vga_draw_line4d2_, DEPTH)(VGAState *s1, uint8_t *d, | ||
260 | + const uint8_t *s, int width) | ||
261 | +{ | ||
262 | + uint32_t plane_mask, data, v, *palette; | ||
263 | + int x; | ||
264 | + | ||
265 | + palette = s1->last_palette; | ||
266 | + plane_mask = mask16[s1->ar[0x12] & 0xf]; | ||
267 | + width >>= 3; | ||
268 | + for(x = 0; x < width; x++) { | ||
269 | + data = ((uint32_t *)s)[0]; | ||
270 | + data &= plane_mask; | ||
271 | + v = expand4[GET_PLANE(data, 0)]; | ||
272 | + v |= expand4[GET_PLANE(data, 1)] << 1; | ||
273 | + v |= expand4[GET_PLANE(data, 2)] << 2; | ||
274 | + v |= expand4[GET_PLANE(data, 3)] << 3; | ||
275 | + PUT_PIXEL2(d, 0, palette[v >> 28]); | ||
276 | + PUT_PIXEL2(d, 1, palette[(v >> 24) & 0xf]); | ||
277 | + PUT_PIXEL2(d, 2, palette[(v >> 20) & 0xf]); | ||
278 | + PUT_PIXEL2(d, 3, palette[(v >> 16) & 0xf]); | ||
279 | + PUT_PIXEL2(d, 4, palette[(v >> 12) & 0xf]); | ||
280 | + PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]); | ||
281 | + PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]); | ||
282 | + PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]); | ||
283 | + d += BPP * 16; | ||
284 | + s += 4; | ||
285 | + } | ||
286 | +} | ||
287 | + | ||
288 | +/* | ||
289 | + * 256 color mode, double pixels | ||
290 | + * | ||
291 | + * XXX: add plane_mask support (never used in standard VGA modes) | ||
292 | + */ | ||
293 | +static void glue(vga_draw_line8d2_, DEPTH)(VGAState *s1, uint8_t *d, | ||
294 | + const uint8_t *s, int width) | ||
295 | +{ | ||
296 | + uint32_t *palette; | ||
297 | + int x; | ||
298 | + | ||
299 | + palette = s1->last_palette; | ||
300 | + width >>= 3; | ||
301 | + for(x = 0; x < width; x++) { | ||
302 | + PUT_PIXEL2(d, 0, palette[s[0]]); | ||
303 | + PUT_PIXEL2(d, 1, palette[s[1]]); | ||
304 | + PUT_PIXEL2(d, 2, palette[s[2]]); | ||
305 | + PUT_PIXEL2(d, 3, palette[s[3]]); | ||
306 | + d += BPP * 8; | ||
307 | + s += 4; | ||
308 | + } | ||
309 | +} | ||
310 | + | ||
311 | +/* | ||
312 | + * standard 256 color mode | ||
188 | * | 313 | * |
189 | * XXX: add plane_mask support (never used in standard VGA modes) | 314 | * XXX: add plane_mask support (never used in standard VGA modes) |
190 | */ | 315 | */ |
@@ -289,6 +414,7 @@ static void glue(vga_draw_line32_, DEPTH)(VGAState *s1, uint8_t *d, | @@ -289,6 +414,7 @@ static void glue(vga_draw_line32_, DEPTH)(VGAState *s1, uint8_t *d, | ||
289 | #endif | 414 | #endif |
290 | } | 415 | } |
291 | 416 | ||
417 | +#undef PUT_PIXEL2 | ||
292 | #undef DEPTH | 418 | #undef DEPTH |
293 | #undef BPP | 419 | #undef BPP |
294 | #undef PIXEL_TYPE | 420 | #undef PIXEL_TYPE |