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 |