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 | 49 | #include "thunk.h" |
| 50 | 50 | |
| 51 | 51 | //#define DEBUG_VGA |
| 52 | +//#define DEBUG_VGA_MEM | |
| 52 | 53 | |
| 53 | 54 | #define MSR_COLOR_EMULATION 0x01 |
| 54 | 55 | #define MSR_PAGE_SELECT 0x20 |
| ... | ... | @@ -85,7 +86,8 @@ typedef struct VGAState { |
| 85 | 86 | DisplayState *ds; |
| 86 | 87 | uint32_t font_offsets[2]; |
| 87 | 88 | int graphic_mode; |
| 88 | - int shift_control; | |
| 89 | + uint8_t shift_control; | |
| 90 | + uint8_t double_scan; | |
| 89 | 91 | uint32_t line_offset; |
| 90 | 92 | uint32_t line_compare; |
| 91 | 93 | uint32_t start_addr; |
| ... | ... | @@ -93,10 +95,11 @@ typedef struct VGAState { |
| 93 | 95 | uint32_t last_width, last_height; |
| 94 | 96 | uint8_t cursor_start, cursor_end; |
| 95 | 97 | uint32_t cursor_offset; |
| 98 | + unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned b); | |
| 96 | 99 | /* tell for each page if it has been updated since the last time */ |
| 97 | 100 | uint8_t vram_updated[VGA_RAM_SIZE / 4096]; |
| 98 | 101 | uint32_t last_palette[256]; |
| 99 | -#define CH_ATTR_SIZE (132 * 60) | |
| 102 | +#define CH_ATTR_SIZE (160 * 100) | |
| 100 | 103 | uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */ |
| 101 | 104 | } VGAState; |
| 102 | 105 | |
| ... | ... | @@ -199,6 +202,7 @@ static const uint32_t dmask4[4] = { |
| 199 | 202 | |
| 200 | 203 | static uint32_t expand4[256]; |
| 201 | 204 | static uint16_t expand2[256]; |
| 205 | +static uint8_t expand4to8[16]; | |
| 202 | 206 | |
| 203 | 207 | VGAState vga_state; |
| 204 | 208 | int vga_io_memory; |
| ... | ... | @@ -503,7 +507,7 @@ void vga_mem_writeb(uint32_t addr, uint32_t val) |
| 503 | 507 | int memory_map_mode, plane, write_mode, b, func_select; |
| 504 | 508 | uint32_t write_mask, bit_mask, set_mask; |
| 505 | 509 | |
| 506 | -#ifdef DEBUG_VGA | |
| 510 | +#ifdef DEBUG_VGA_MEM | |
| 507 | 511 | printf("vga: [0x%x] = 0x%02x\n", addr, val); |
| 508 | 512 | #endif |
| 509 | 513 | /* convert to VGA memory offset */ |
| ... | ... | @@ -533,7 +537,7 @@ void vga_mem_writeb(uint32_t addr, uint32_t val) |
| 533 | 537 | plane = addr & 3; |
| 534 | 538 | if (s->sr[2] & (1 << plane)) { |
| 535 | 539 | s->vram_ptr[addr] = val; |
| 536 | -#ifdef DEBUG_VGA | |
| 540 | +#ifdef DEBUG_VGA_MEM | |
| 537 | 541 | printf("vga: chain4: [0x%x]\n", addr); |
| 538 | 542 | #endif |
| 539 | 543 | s->vram_updated[addr >> 12] = 1; |
| ... | ... | @@ -544,7 +548,7 @@ void vga_mem_writeb(uint32_t addr, uint32_t val) |
| 544 | 548 | if (s->sr[2] & (1 << plane)) { |
| 545 | 549 | addr = ((addr & ~1) << 1) | plane; |
| 546 | 550 | s->vram_ptr[addr] = val; |
| 547 | -#ifdef DEBUG_VGA | |
| 551 | +#ifdef DEBUG_VGA_MEM | |
| 548 | 552 | printf("vga: odd/even: [0x%x]\n", addr); |
| 549 | 553 | #endif |
| 550 | 554 | s->vram_updated[addr >> 12] = 1; |
| ... | ... | @@ -615,7 +619,7 @@ void vga_mem_writeb(uint32_t addr, uint32_t val) |
| 615 | 619 | ((uint32_t *)s->vram_ptr)[addr] = |
| 616 | 620 | (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) | |
| 617 | 621 | (val & write_mask); |
| 618 | -#ifdef DEBUG_VGA | |
| 622 | +#ifdef DEBUG_VGA_MEM | |
| 619 | 623 | printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n", |
| 620 | 624 | addr * 4, write_mask, val); |
| 621 | 625 | #endif |
| ... | ... | @@ -699,28 +703,43 @@ static inline int c6_to_8(int v) |
| 699 | 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 | 738 | /* return true if the palette was modified */ |
| 703 | 739 | static int update_palette16(VGAState *s) |
| 704 | 740 | { |
| 705 | - int full_update, i, depth; | |
| 741 | + int full_update, i; | |
| 706 | 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 | 744 | full_update = 0; |
| 726 | 745 | palette = s->last_palette; |
| ... | ... | @@ -731,21 +750,35 @@ static int update_palette16(VGAState *s) |
| 731 | 750 | else |
| 732 | 751 | v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f); |
| 733 | 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 | 777 | if (col != palette[i]) { |
| 746 | 778 | full_update = 1; |
| 747 | 779 | palette[i] = col; |
| 748 | 780 | } |
| 781 | + v += 3; | |
| 749 | 782 | } |
| 750 | 783 | return full_update; |
| 751 | 784 | } |
| ... | ... | @@ -806,6 +839,13 @@ static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = { |
| 806 | 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 | 849 | static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = { |
| 810 | 850 | vga_draw_glyph9_8, |
| 811 | 851 | vga_draw_glyph9_16, |
| ... | ... | @@ -882,12 +922,19 @@ static void vga_draw_text(VGAState *s, int full_update) |
| 882 | 922 | cw = 8; |
| 883 | 923 | if (s->sr[1] & 0x01) |
| 884 | 924 | cw = 9; |
| 925 | + if (s->sr[1] & 0x08) | |
| 926 | + cw = 16; /* NOTE: no 18 pixel wide */ | |
| 885 | 927 | x_incr = cw * ((s->ds->depth + 7) >> 3); |
| 886 | 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 | 938 | if (width != s->last_width || height != s->last_height || |
| 892 | 939 | cw != s->last_cw || cw != s->last_cw) { |
| 893 | 940 | dpy_resize(s->ds, width * cw, height * cheight); |
| ... | ... | @@ -914,7 +961,10 @@ static void vga_draw_text(VGAState *s, int full_update) |
| 914 | 961 | cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4; |
| 915 | 962 | |
| 916 | 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 | 968 | vga_draw_glyph9 = vga_draw_glyph9_table[depth_index]; |
| 919 | 969 | |
| 920 | 970 | dest = s->ds->data; |
| ... | ... | @@ -944,7 +994,7 @@ static void vga_draw_text(VGAState *s, int full_update) |
| 944 | 994 | font_ptr += 32 * 4 * ch; |
| 945 | 995 | bgcol = palette[cattr >> 4]; |
| 946 | 996 | fgcol = palette[cattr & 0x0f]; |
| 947 | - if (cw == 8) { | |
| 997 | + if (cw != 9) { | |
| 948 | 998 | vga_draw_glyph8(d1, linesize, |
| 949 | 999 | font_ptr, cheight, fgcol, bgcol); |
| 950 | 1000 | } else { |
| ... | ... | @@ -966,7 +1016,7 @@ static void vga_draw_text(VGAState *s, int full_update) |
| 966 | 1016 | if (line_last >= line_start && line_start < cheight) { |
| 967 | 1017 | h = line_last - line_start + 1; |
| 968 | 1018 | d = d1 + linesize * line_start; |
| 969 | - if (cw == 8) { | |
| 1019 | + if (cw != 9) { | |
| 970 | 1020 | vga_draw_glyph8(d, linesize, |
| 971 | 1021 | cursor_glyph, h, fgcol, bgcol); |
| 972 | 1022 | } else { |
| ... | ... | @@ -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 | 1056 | vga_draw_line2_8, |
| 994 | 1057 | vga_draw_line2_16, |
| 995 | 1058 | vga_draw_line2_16, |
| 996 | 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 | 1066 | vga_draw_line4_8, |
| 999 | 1067 | vga_draw_line4_16, |
| 1000 | 1068 | vga_draw_line4_16, |
| 1001 | 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 | 1081 | vga_draw_line8_8, |
| 1004 | 1082 | vga_draw_line8_16, |
| 1005 | 1083 | vga_draw_line8_16, |
| ... | ... | @@ -1029,14 +1107,13 @@ static vga_draw_line_func *vga_draw_line_table[4 * 6] = { |
| 1029 | 1107 | */ |
| 1030 | 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 | 1111 | int width, height, shift_control, line_offset, page0, page1, bwidth; |
| 1112 | + int disp_width; | |
| 1034 | 1113 | uint8_t *d; |
| 1035 | 1114 | uint32_t v, addr1, addr; |
| 1036 | 1115 | vga_draw_line_func *vga_draw_line; |
| 1037 | - | |
| 1038 | - full_update |= update_palette16(s); | |
| 1039 | - | |
| 1116 | + | |
| 1040 | 1117 | full_update |= update_basic_params(s); |
| 1041 | 1118 | |
| 1042 | 1119 | width = (s->cr[0x01] + 1) * 8; |
| ... | ... | @@ -1044,30 +1121,53 @@ static void vga_draw_graphic(VGAState *s, int full_update) |
| 1044 | 1121 | ((s->cr[0x07] & 0x02) << 7) | |
| 1045 | 1122 | ((s->cr[0x07] & 0x40) << 3); |
| 1046 | 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 | 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 | 1130 | full_update = 1; |
| 1059 | 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 | 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 | 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 | 1171 | addr1 = (s->start_addr * 4); |
| 1072 | 1172 | bwidth = width * 4; |
| 1073 | 1173 | y_start = -1; |
| ... | ... | @@ -1075,14 +1175,17 @@ static void vga_draw_graphic(VGAState *s, int full_update) |
| 1075 | 1175 | page_max = -1; |
| 1076 | 1176 | d = s->ds->data; |
| 1077 | 1177 | linesize = s->ds->linesize; |
| 1178 | + y1 = 0; | |
| 1078 | 1179 | for(y = 0; y < height; y++) { |
| 1079 | 1180 | addr = addr1; |
| 1080 | 1181 | if (!(s->cr[0x17] & 1)) { |
| 1182 | + int shift; | |
| 1081 | 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 | 1187 | if (!(s->cr[0x17] & 2)) { |
| 1085 | - addr = (addr & ~0x4000) | ((y & 2) << 13); | |
| 1188 | + addr = (addr & ~0x8000) | ((y1 & 2) << 14); | |
| 1086 | 1189 | } |
| 1087 | 1190 | page0 = addr >> 12; |
| 1088 | 1191 | page1 = (addr + bwidth - 1) >> 12; |
| ... | ... | @@ -1103,21 +1206,26 @@ static void vga_draw_graphic(VGAState *s, int full_update) |
| 1103 | 1206 | if (y_start >= 0) { |
| 1104 | 1207 | /* flush to display */ |
| 1105 | 1208 | dpy_update(s->ds, 0, y_start, |
| 1106 | - width, y - y_start); | |
| 1209 | + disp_width, y - y_start); | |
| 1107 | 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 | 1223 | d += linesize; |
| 1116 | 1224 | } |
| 1117 | 1225 | if (y_start >= 0) { |
| 1118 | 1226 | /* flush to display */ |
| 1119 | 1227 | dpy_update(s->ds, 0, y_start, |
| 1120 | - width, y - y_start); | |
| 1228 | + disp_width, y - y_start); | |
| 1121 | 1229 | } |
| 1122 | 1230 | /* reset modified pages */ |
| 1123 | 1231 | if (page_max != -1) { |
| ... | ... | @@ -1199,7 +1307,7 @@ int vga_init(DisplayState *ds, uint8_t *vga_ram_base, |
| 1199 | 1307 | unsigned long vga_ram_offset, int vga_ram_size) |
| 1200 | 1308 | { |
| 1201 | 1309 | VGAState *s = &vga_state; |
| 1202 | - int i, j, v; | |
| 1310 | + int i, j, v, b; | |
| 1203 | 1311 | |
| 1204 | 1312 | for(i = 0;i < 256; i++) { |
| 1205 | 1313 | v = 0; |
| ... | ... | @@ -1214,9 +1322,34 @@ int vga_init(DisplayState *ds, uint8_t *vga_ram_base, |
| 1214 | 1322 | } |
| 1215 | 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 | 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 | 1353 | s->vram_ptr = vga_ram_base; |
| 1221 | 1354 | s->vram_offset = vga_ram_offset; |
| 1222 | 1355 | s->vram_size = vga_ram_size; | ... | ... |
hw/vga_template.h
| ... | ... | @@ -37,15 +37,11 @@ |
| 37 | 37 | |
| 38 | 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 | 45 | #if BPP == 1 |
| 50 | 46 | ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol; |
| 51 | 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 | 60 | ((uint32_t *)d)[6] = ((-(font_data >> 1) & 1) & xorcol) ^ bgcol; |
| 65 | 61 | ((uint32_t *)d)[7] = ((-(font_data >> 0) & 1) & xorcol) ^ bgcol; |
| 66 | 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 | 95 | font_ptr += 4; |
| 68 | 96 | d += linesize; |
| 69 | 97 | } while (--h); |
| ... | ... | @@ -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 | 225 | * 16 color mode |
| 156 | 226 | */ |
| ... | ... | @@ -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 | 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 | 414 | #endif |
| 290 | 415 | } |
| 291 | 416 | |
| 417 | +#undef PUT_PIXEL2 | |
| 292 | 418 | #undef DEPTH |
| 293 | 419 | #undef BPP |
| 294 | 420 | #undef PIXEL_TYPE | ... | ... |