1 /*
2  *  Copyright (C) 2002-2015  The DOSBox Team
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18 
19 
20 #include <string.h>
21 
22 #include "dosbox.h"
23 #include "mem.h"
24 #include "inout.h"
25 #include "int10.h"
26 #include "vga.h"
27 
28 #define _EGA_HALF_CLOCK		0x0001
29 #define _EGA_LINE_DOUBLE	0x0002
30 #define _VGA_PIXEL_DOUBLE	0x0004
31 
32 #define SEQ_REGS 0x05
33 #define GFX_REGS 0x09
34 #define ATT_REGS 0x15
35 
36 VideoModeBlock ModeList_VGA[]={
37 /* mode  ,type     ,sw  ,sh  ,tw ,th ,cw,ch ,pt,pstart  ,plength,htot,vtot,hde,vde special flags */
38 { 0x000  ,M_TEXT   ,360 ,400 ,40 ,25 ,9 ,16 ,8 ,0xB8000 ,0x0800 ,50  ,449 ,40 ,400 ,_EGA_HALF_CLOCK	},
39 { 0x001  ,M_TEXT   ,360 ,400 ,40 ,25 ,9 ,16 ,8 ,0xB8000 ,0x0800 ,50  ,449 ,40 ,400 ,_EGA_HALF_CLOCK	},
40 { 0x002  ,M_TEXT   ,720 ,400 ,80 ,25 ,9 ,16 ,8 ,0xB8000 ,0x1000 ,100 ,449 ,80 ,400 ,0	},
41 { 0x003  ,M_TEXT   ,720 ,400 ,80 ,25 ,9 ,16 ,8 ,0xB8000 ,0x1000 ,100 ,449 ,80 ,400 ,0	},
42 { 0x004  ,M_CGA4   ,320 ,200 ,40 ,25 ,8 ,8  ,1 ,0xB8000 ,0x4000 ,50  ,449 ,40 ,400 ,_EGA_HALF_CLOCK	| _EGA_LINE_DOUBLE},
43 { 0x005  ,M_CGA4   ,320 ,200 ,40 ,25 ,8 ,8  ,1 ,0xB8000 ,0x4000 ,50  ,449 ,40 ,400 ,_EGA_HALF_CLOCK	| _EGA_LINE_DOUBLE},
44 { 0x006  ,M_CGA2   ,640 ,200 ,80 ,25 ,8 ,8  ,1 ,0xB8000 ,0x4000 ,100 ,449 ,80 ,400 ,_EGA_LINE_DOUBLE},
45 { 0x007  ,M_TEXT   ,720 ,400 ,80 ,25 ,9 ,16 ,8 ,0xB0000 ,0x1000 ,100 ,449 ,80 ,400 ,0	},
46 
47 { 0x00D  ,M_EGA    ,320 ,200 ,40 ,25 ,8 ,8  ,8 ,0xA0000 ,0x2000 ,50  ,449 ,40 ,400 ,_EGA_HALF_CLOCK	| _EGA_LINE_DOUBLE	},
48 { 0x00E  ,M_EGA    ,640 ,200 ,80 ,25 ,8 ,8  ,4 ,0xA0000 ,0x4000 ,100 ,449 ,80 ,400 ,_EGA_LINE_DOUBLE },
49 { 0x00F  ,M_EGA    ,640 ,350 ,80 ,25 ,8 ,14 ,2 ,0xA0000 ,0x8000 ,100 ,449 ,80 ,350 ,0	},/*was EGA_2*/
50 { 0x010  ,M_EGA    ,640 ,350 ,80 ,25 ,8 ,14 ,2 ,0xA0000 ,0x8000 ,100 ,449 ,80 ,350 ,0	},
51 { 0x011  ,M_EGA    ,640 ,480 ,80 ,30 ,8 ,16 ,1 ,0xA0000 ,0xA000 ,100 ,525 ,80 ,480 ,0	},/*was EGA_2 */
52 { 0x012  ,M_EGA    ,640 ,480 ,80 ,30 ,8 ,16 ,1 ,0xA0000 ,0xA000 ,100 ,525 ,80 ,480 ,0	},
53 { 0x013  ,M_VGA    ,320 ,200 ,40 ,25 ,8 ,8  ,1 ,0xA0000 ,0x2000 ,100 ,449 ,80 ,400 ,0   },
54 
55 { 0x054  ,M_TEXT   ,1056,344, 132,43, 8,  8, 1 ,0xB8000 ,0x4000, 160, 449, 132,344, 0   },
56 { 0x055  ,M_TEXT   ,1056,400, 132,25, 8, 16, 1 ,0xB8000 ,0x2000, 160, 449, 132,400, 0   },
57 
58 /* Alias of mode 101 */
59 { 0x069  ,M_LIN8   ,640 ,480 ,80 ,30 ,8 ,16 ,1 ,0xA0000 ,0x10000,100 ,525 ,80 ,480 ,0	},
60 /* Alias of mode 102 */
61 { 0x06A  ,M_LIN4   ,800 ,600 ,100,37 ,8 ,16 ,1 ,0xA0000 ,0x10000,128 ,663 ,100,600 ,0	},
62 
63 /* Follow vesa 1.2 for first 0x20 */
64 { 0x100  ,M_LIN8   ,640 ,400 ,80 ,25 ,8 ,16 ,1 ,0xA0000 ,0x10000,100 ,449 ,80 ,400 ,0   },
65 { 0x101  ,M_LIN8   ,640 ,480 ,80 ,30 ,8 ,16 ,1 ,0xA0000 ,0x10000,100 ,525 ,80 ,480 ,0	},
66 { 0x102  ,M_LIN4   ,800 ,600 ,100,37 ,8 ,16 ,1 ,0xA0000 ,0x10000,132 ,628 ,100,600 ,0	},
67 { 0x103  ,M_LIN8   ,800 ,600 ,100,37 ,8 ,16 ,1 ,0xA0000 ,0x10000,132 ,628 ,100,600 ,0	},
68 { 0x104  ,M_LIN4   ,1024,768 ,128,48 ,8 ,16 ,1 ,0xA0000 ,0x10000,168 ,806 ,128,768 ,0	},
69 { 0x105  ,M_LIN8   ,1024,768 ,128,48 ,8 ,16 ,1 ,0xA0000 ,0x10000,168 ,806 ,128,768 ,0	},
70 { 0x106  ,M_LIN4   ,1280,1024,160,64 ,8 ,16 ,1 ,0xA0000 ,0x10000,212 ,1066,160,1024,0	},
71 { 0x107  ,M_LIN8   ,1280,1024,160,64 ,8 ,16 ,1 ,0xA0000 ,0x10000,212 ,1066,160,1024,0	},
72 
73 /* VESA text modes */
74 { 0x108  ,M_TEXT   ,640 ,480,  80,60, 8,  8 ,2 ,0xB8000 ,0x4000, 100 ,525 ,80 ,480 ,0   },
75 { 0x109  ,M_TEXT   ,1056,400, 132,25, 8, 16, 1 ,0xB8000 ,0x2000, 160, 449, 132,400, 0   },
76 { 0x10A  ,M_TEXT   ,1056,688, 132,43, 8,  8, 1 ,0xB8000 ,0x4000, 160, 449, 132,344, 0   },
77 { 0x10B  ,M_TEXT   ,1056,400, 132,50, 8,  8, 1 ,0xB8000 ,0x4000, 160, 449, 132,400, 0   },
78 { 0x10C  ,M_TEXT   ,1056,480, 132,60, 8,  8, 2 ,0xB8000 ,0x4000, 160, 531, 132,480, 0   },
79 
80 /* VESA higher color modes */
81 { 0x10D  ,M_LIN15  ,320 ,200 ,40 ,25 ,8 ,8  ,1 ,0xA0000 ,0x10000,100 ,449 ,80 ,400 , _VGA_PIXEL_DOUBLE | _EGA_LINE_DOUBLE },
82 { 0x10E  ,M_LIN16  ,320 ,200 ,40 ,25 ,8 ,8  ,1 ,0xA0000 ,0x10000,100 ,449 ,80 ,400 , _VGA_PIXEL_DOUBLE | _EGA_LINE_DOUBLE },
83 { 0x10F  ,M_LIN32  ,320 ,200 ,40 ,25 ,8 ,8  ,1 ,0xA0000 ,0x10000,50  ,449 ,40 ,400 , _VGA_PIXEL_DOUBLE | _EGA_LINE_DOUBLE },
84 { 0x110  ,M_LIN15  ,640 ,480 ,80 ,30 ,8 ,16 ,1 ,0xA0000 ,0x10000,200 ,525 ,160,480 ,0   },
85 { 0x111  ,M_LIN16  ,640 ,480 ,80 ,30 ,8 ,16 ,1 ,0xA0000 ,0x10000,200 ,525 ,160,480 ,0   },
86 { 0x112  ,M_LIN32  ,640 ,480 ,80 ,30 ,8 ,16 ,1 ,0xA0000 ,0x10000,100 ,525 ,80 ,480 ,0   },
87 { 0x113  ,M_LIN15  ,800 ,600 ,100,37 ,8 ,16 ,1 ,0xA0000 ,0x10000,264 ,628 ,200,600 ,0   },
88 { 0x114  ,M_LIN16  ,800 ,600 ,100,37 ,8 ,16 ,1 ,0xA0000 ,0x10000,264 ,628 ,200,600 ,0   },
89 { 0x115  ,M_LIN32  ,800 ,600 ,100,37 ,8 ,16 ,1 ,0xA0000 ,0x10000,132 ,628 ,100,600 ,0   },
90 { 0x116  ,M_LIN15  ,1024,768 ,128,48 ,8 ,16 ,1 ,0xA0000 ,0x10000,336 ,806 ,256,768 ,0	},
91 { 0x117  ,M_LIN16  ,1024,768 ,128,48 ,8 ,16 ,1 ,0xA0000 ,0x10000,336 ,806 ,256,768 ,0	},
92 { 0x118  ,M_LIN32  ,1024,768 ,128,48 ,8 ,16 ,1 ,0xA0000 ,0x10000,168 ,806 ,128,768 ,0	},
93 
94 /* those should be interlaced but ok */
95 //{ 0x119  ,M_LIN15  ,1280,1024,160,64 ,8 ,16 ,1 ,0xA0000 ,0x10000,424 ,1066,320,1024,0	},
96 //{ 0x11A  ,M_LIN16  ,1280,1024,160,64 ,8 ,16 ,1 ,0xA0000 ,0x10000,424 ,1066,320,1024,0	},
97 
98 { 0x150  ,M_LIN8   ,320 ,200 ,40 ,25 ,8 ,8  ,1 ,0xA0000 ,0x10000,100 ,449 ,80 ,400 , _VGA_PIXEL_DOUBLE | _EGA_LINE_DOUBLE },
99 { 0x151  ,M_LIN8   ,320 ,240 ,40 ,30 ,8 ,8  ,1 ,0xA0000 ,0x10000,100 ,525 ,80 ,480 , _VGA_PIXEL_DOUBLE | _EGA_LINE_DOUBLE },
100 { 0x152  ,M_LIN8   ,320 ,400 ,40 ,50 ,8 ,8  ,1 ,0xA0000 ,0x10000,100 ,449 ,80 ,400 , _VGA_PIXEL_DOUBLE  },
101 { 0x153  ,M_LIN8   ,320 ,480 ,40 ,60 ,8 ,8  ,1 ,0xA0000 ,0x10000,100 ,525 ,80 ,480 , _VGA_PIXEL_DOUBLE  },
102 
103 { 0x160  ,M_LIN15  ,320 ,240 ,40 ,30 ,8 ,8  ,1 ,0xA0000 ,0x10000,100 ,525 , 80 ,480 , _VGA_PIXEL_DOUBLE | _EGA_LINE_DOUBLE },
104 { 0x161  ,M_LIN15  ,320 ,400 ,40 ,50 ,8 ,8  ,1 ,0xA0000 ,0x10000,100 ,449 , 80 ,400 , _VGA_PIXEL_DOUBLE  },
105 { 0x162  ,M_LIN15  ,320 ,480 ,40 ,60 ,8 ,8  ,1 ,0xA0000 ,0x10000,100 ,525 , 80 ,480 , _VGA_PIXEL_DOUBLE  },
106 { 0x165  ,M_LIN15  ,640 ,400 ,80 ,25 ,8 ,16 ,1 ,0xA0000 ,0x10000,200 ,449 ,160 ,400 ,0   },
107 
108 { 0x170  ,M_LIN16  ,320 ,240 ,40 ,30 ,8 ,8  ,1 ,0xA0000 ,0x10000,100 ,525 , 80 ,480 , _VGA_PIXEL_DOUBLE | _EGA_LINE_DOUBLE },
109 { 0x171  ,M_LIN16  ,320 ,400 ,40 ,50 ,8 ,8  ,1 ,0xA0000 ,0x10000,100 ,449 , 80 ,400 , _VGA_PIXEL_DOUBLE  },
110 { 0x172  ,M_LIN16  ,320 ,480 ,40 ,60 ,8 ,8  ,1 ,0xA0000 ,0x10000,100 ,525 , 80 ,480 , _VGA_PIXEL_DOUBLE  },
111 { 0x175  ,M_LIN16  ,640 ,400 ,80 ,25 ,8 ,16 ,1 ,0xA0000 ,0x10000,200 ,449 ,160 ,400 ,0   },
112 
113 { 0x190  ,M_LIN32  ,320 ,240 ,40 ,30 ,8 ,8  ,1 ,0xA0000 ,0x10000, 50 ,525 ,40 ,480 , _VGA_PIXEL_DOUBLE | _EGA_LINE_DOUBLE },
114 { 0x191  ,M_LIN32  ,320 ,400 ,40 ,50 ,8 ,8  ,1 ,0xA0000 ,0x10000, 50 ,449 ,40 ,400 , _VGA_PIXEL_DOUBLE  },
115 { 0x192  ,M_LIN32  ,320 ,480 ,40 ,60 ,8 ,8  ,1 ,0xA0000 ,0x10000, 50 ,525 ,40 ,480 , _VGA_PIXEL_DOUBLE  },
116 
117 /* S3 specific modes */
118 { 0x207  ,M_LIN8	,1152,864,160,64 ,8 ,16 ,1 ,0xA0000 ,0x10000,182 ,948 ,144,864 ,0	},
119 { 0x209  ,M_LIN15	,1152,864,160,64 ,8 ,16 ,1 ,0xA0000 ,0x10000,364 ,948 ,288,864 ,0	},
120 { 0x20A  ,M_LIN16	,1152,864,160,64 ,8 ,16 ,1 ,0xA0000 ,0x10000,364 ,948 ,288,864 ,0	},
121 //{ 0x20B  ,M_LIN32	,1152,864,160,64 ,8 ,16 ,1 ,0xA0000 ,0x10000,182 ,948 ,144,864 ,0	},
122 { 0x213  ,M_LIN32   ,640 ,400,80 ,25 ,8 ,16 ,1 ,0xA0000 ,0x10000,100 ,449 ,80 ,400 ,0	},
123 
124 /* Some custom modes */
125 //{ 0x220  ,M_LIN32  ,1280,1024,160,64 ,8 ,16 ,1 ,0xA0000 ,0x10000,212 ,1066,160,1024,0	},
126 // A nice 16:9 mode
127 { 0x222  ,M_LIN8   ,848 ,480 ,80 ,30 ,8 ,16 ,1 ,0xA0000 ,0x10000,132 ,525 ,106 ,480 ,0	},
128 { 0x223  ,M_LIN15  ,848 ,480 ,80 ,30 ,8 ,16 ,1 ,0xA0000 ,0x10000,264 ,525 ,212 ,480 ,0  },
129 { 0x224  ,M_LIN16  ,848 ,480 ,80 ,30 ,8 ,16 ,1 ,0xA0000 ,0x10000,264 ,525 ,212 ,480 ,0  },
130 { 0x225  ,M_LIN32  ,848 ,480 ,80 ,30 ,8 ,16 ,1 ,0xA0000 ,0x10000,132 ,525 ,106 ,480 ,0  },
131 
132 {0xFFFF  ,M_ERROR  ,0   ,0   ,0  ,0  ,0 ,0  ,0 ,0x00000 ,0x0000 ,0   ,0   ,0  ,0   ,0 	},
133 };
134 
135 VideoModeBlock ModeList_VGA_Text_200lines[]={
136 /* mode  ,type     ,sw  ,sh  ,tw ,th ,cw,ch ,pt,pstart  ,plength,htot,vtot,hde,vde special flags */
137 { 0x000  ,M_TEXT   ,320 ,200 ,40 ,25 ,8 , 8 ,8 ,0xB8000 ,0x0800 ,50  ,449 ,40 ,400 ,_EGA_HALF_CLOCK | _EGA_LINE_DOUBLE},
138 { 0x001  ,M_TEXT   ,320 ,200 ,40 ,25 ,8 , 8 ,8 ,0xB8000 ,0x0800 ,50  ,449 ,40 ,400 ,_EGA_HALF_CLOCK | _EGA_LINE_DOUBLE},
139 { 0x002  ,M_TEXT   ,640 ,200 ,80 ,25 ,8 , 8 ,8 ,0xB8000 ,0x1000 ,100 ,449 ,80 ,400 ,_EGA_LINE_DOUBLE },
140 { 0x003  ,M_TEXT   ,640 ,200 ,80 ,25 ,8 , 8 ,8 ,0xB8000 ,0x1000 ,100 ,449 ,80 ,400 ,_EGA_LINE_DOUBLE }
141 };
142 
143 VideoModeBlock ModeList_VGA_Text_350lines[]={
144 /* mode  ,type     ,sw  ,sh  ,tw ,th ,cw,ch ,pt,pstart  ,plength,htot,vtot,hde,vde special flags */
145 { 0x000  ,M_TEXT   ,320 ,350 ,40 ,25 ,8 ,14 ,8 ,0xB8000 ,0x0800 ,50  ,449 ,40 ,350 ,_EGA_HALF_CLOCK	},
146 { 0x001  ,M_TEXT   ,320 ,350 ,40 ,25 ,8 ,14 ,8 ,0xB8000 ,0x0800 ,50  ,449 ,40 ,350 ,_EGA_HALF_CLOCK	},
147 { 0x002  ,M_TEXT   ,640 ,350 ,80 ,25 ,8 ,14 ,8 ,0xB8000 ,0x1000 ,100 ,449 ,80 ,350 ,0	},
148 { 0x003  ,M_TEXT   ,640 ,350 ,80 ,25 ,8 ,14 ,8 ,0xB8000 ,0x1000 ,100 ,449 ,80 ,350 ,0	},
149 { 0x007  ,M_TEXT   ,720 ,350 ,80 ,25 ,9 ,14 ,8 ,0xB0000 ,0x1000 ,100 ,449 ,80 ,350 ,0	}
150 };
151 
152 VideoModeBlock ModeList_VGA_Tseng[]={
153 /* mode  ,type     ,sw  ,sh  ,tw ,th ,cw,ch ,pt,pstart  ,plength,htot,vtot,hde,vde special flags */
154 { 0x000  ,M_TEXT   ,360 ,400 ,40 ,25 ,9 ,16 ,8 ,0xB8000 ,0x0800 ,50  ,449 ,40 ,400 ,_EGA_HALF_CLOCK	},
155 { 0x001  ,M_TEXT   ,360 ,400 ,40 ,25 ,9 ,16 ,8 ,0xB8000 ,0x0800 ,50  ,449 ,40 ,400 ,_EGA_HALF_CLOCK	},
156 { 0x002  ,M_TEXT   ,720 ,400 ,80 ,25 ,9 ,16 ,8 ,0xB8000 ,0x1000 ,100 ,449 ,80 ,400 ,0	},
157 { 0x003  ,M_TEXT   ,720 ,400 ,80 ,25 ,9 ,16 ,8 ,0xB8000 ,0x1000 ,100 ,449 ,80 ,400 ,0	},
158 { 0x004  ,M_CGA4   ,320 ,200 ,40 ,25 ,8 ,8  ,1 ,0xB8000 ,0x4000 ,50  ,449 ,40 ,400 ,_EGA_HALF_CLOCK	| _EGA_LINE_DOUBLE},
159 { 0x005  ,M_CGA4   ,320 ,200 ,40 ,25 ,8 ,8  ,1 ,0xB8000 ,0x4000 ,50  ,449 ,40 ,400 ,_EGA_HALF_CLOCK	| _EGA_LINE_DOUBLE},
160 { 0x006  ,M_CGA2   ,640 ,200 ,80 ,25 ,8 ,8  ,1 ,0xB8000 ,0x4000 ,100 ,449 ,80 ,400 ,_EGA_LINE_DOUBLE},
161 { 0x007  ,M_TEXT   ,720 ,400 ,80 ,25 ,9 ,16 ,8 ,0xB0000 ,0x1000 ,100 ,449 ,80 ,400 ,0	},
162 
163 { 0x00D  ,M_EGA    ,320 ,200 ,40 ,25 ,8 ,8  ,8 ,0xA0000 ,0x2000 ,50  ,449 ,40 ,400 ,_EGA_HALF_CLOCK	| _EGA_LINE_DOUBLE	},
164 { 0x00E  ,M_EGA    ,640 ,200 ,80 ,25 ,8 ,8  ,4 ,0xA0000 ,0x4000 ,100 ,449 ,80 ,400 ,_EGA_LINE_DOUBLE },
165 { 0x00F  ,M_EGA    ,640 ,350 ,80 ,25 ,8 ,14 ,2 ,0xA0000 ,0x8000 ,100 ,449 ,80 ,350 ,0	},/*was EGA_2*/
166 { 0x010  ,M_EGA    ,640 ,350 ,80 ,25 ,8 ,14 ,2 ,0xA0000 ,0x8000 ,100 ,449 ,80 ,350 ,0	},
167 { 0x011  ,M_EGA    ,640 ,480 ,80 ,30 ,8 ,16 ,1 ,0xA0000 ,0xA000 ,100 ,525 ,80 ,480 ,0	},/*was EGA_2 */
168 { 0x012  ,M_EGA    ,640 ,480 ,80 ,30 ,8 ,16 ,1 ,0xA0000 ,0xA000 ,100 ,525 ,80 ,480 ,0	},
169 { 0x013  ,M_VGA    ,320 ,200 ,40 ,25 ,8 ,8  ,1 ,0xA0000 ,0x2000 ,100 ,449 ,80 ,400 ,0   },
170 
171 { 0x018  ,M_TEXT   ,1056 ,688, 132,44, 8, 8, 1 ,0xB0000 ,0x4000, 192, 800, 132, 704, 0 },
172 { 0x019  ,M_TEXT   ,1056 ,400, 132,25, 8, 16,1 ,0xB0000 ,0x2000, 192, 449, 132, 400, 0 },
173 { 0x01A  ,M_TEXT   ,1056 ,400, 132,28, 8, 16,1 ,0xB0000 ,0x2000, 192, 449, 132, 448, 0 },
174 { 0x022  ,M_TEXT   ,1056 ,688, 132,44, 8, 8, 1 ,0xB8000 ,0x4000, 192, 800, 132, 704, 0 },
175 { 0x023  ,M_TEXT   ,1056 ,400, 132,25, 8, 16,1 ,0xB8000 ,0x2000, 192, 449, 132, 400, 0 },
176 { 0x024  ,M_TEXT   ,1056 ,400, 132,28, 8, 16,1 ,0xB8000 ,0x2000, 192, 449, 132, 448, 0 },
177 { 0x025  ,M_LIN4   ,640 ,480 ,80 ,30 ,8 ,16 ,1 ,0xA0000 ,0xA000 ,100 ,525 ,80 ,480 , 0 },
178 { 0x029  ,M_LIN4   ,800 ,600 ,100,37 ,8 ,16 ,1 ,0xA0000 ,0xA000, 128 ,663 ,100,600 , 0 },
179 { 0x02D  ,M_LIN8   ,640 ,350 ,80 ,21 ,8 ,16 ,1 ,0xA0000 ,0x10000,100 ,449 ,80 ,350 , 0 },
180 { 0x02E  ,M_LIN8   ,640 ,480 ,80 ,30 ,8 ,16 ,1 ,0xA0000 ,0x10000,100 ,525 ,80 ,480 , 0 },
181 { 0x02F  ,M_LIN8   ,640 ,400 ,80 ,25 ,8 ,16 ,1 ,0xA0000 ,0x10000,100 ,449 ,80 ,400 , 0 },/* ET4000 only */
182 { 0x030  ,M_LIN8   ,800 ,600 ,100,37 ,8 ,16 ,1 ,0xA0000 ,0x10000,128 ,663 ,100,600 , 0 },
183 { 0x036  ,M_LIN4   ,960 , 720,120,45 ,8 ,16 ,1 ,0xA0000 ,0xA000, 120 ,800 ,120,720 , 0 },/* STB only */
184 { 0x037  ,M_LIN4   ,1024, 768,128,48 ,8 ,16 ,1 ,0xA0000 ,0xA000, 128 ,800 ,128,768 , 0 },
185 { 0x038  ,M_LIN8   ,1024 ,768,128,48 ,8 ,16 ,1 ,0xA0000 ,0x10000,128 ,800 ,128,768 , 0 },/* ET4000 only */
186 { 0x03D  ,M_LIN4   ,1280,1024,160,64 ,8 ,16 ,1 ,0xA0000 ,0xA000, 160 ,1152,160,1024, 0 },/* newer ET4000 */
187 { 0x03E  ,M_LIN4   ,1280, 960,160,60 ,8 ,16 ,1 ,0xA0000 ,0xA000, 160 ,1024,160,960 , 0 },/* Definicon only */
188 { 0x06A  ,M_LIN4   ,800 ,600 ,100,37 ,8 ,16 ,1 ,0xA0000 ,0xA000, 128 ,663 ,100,600 , 0 },/* newer ET4000 */
189 
190 {0xFFFF  ,M_ERROR  ,0   ,0   ,0  ,0  ,0 ,0  ,0 ,0x00000 ,0x0000 ,0   ,0   ,0  ,0   ,0 	},
191 };
192 
193 VideoModeBlock ModeList_VGA_Paradise[]={
194 /* mode  ,type     ,sw  ,sh  ,tw ,th ,cw,ch ,pt,pstart  ,plength,htot,vtot,hde,vde special flags */
195 { 0x000  ,M_TEXT   ,360 ,400 ,40 ,25 ,9 ,16 ,8 ,0xB8000 ,0x0800 ,50  ,449 ,40 ,400 ,_EGA_HALF_CLOCK	},
196 { 0x001  ,M_TEXT   ,360 ,400 ,40 ,25 ,9 ,16 ,8 ,0xB8000 ,0x0800 ,50  ,449 ,40 ,400 ,_EGA_HALF_CLOCK	},
197 { 0x002  ,M_TEXT   ,720 ,400 ,80 ,25 ,9 ,16 ,8 ,0xB8000 ,0x1000 ,100 ,449 ,80 ,400 ,0	},
198 { 0x003  ,M_TEXT   ,720 ,400 ,80 ,25 ,9 ,16 ,8 ,0xB8000 ,0x1000 ,100 ,449 ,80 ,400 ,0	},
199 { 0x004  ,M_CGA4   ,320 ,200 ,40 ,25 ,8 ,8  ,1 ,0xB8000 ,0x4000 ,50  ,449 ,40 ,400 ,_EGA_HALF_CLOCK	| _EGA_LINE_DOUBLE},
200 { 0x005  ,M_CGA4   ,320 ,200 ,40 ,25 ,8 ,8  ,1 ,0xB8000 ,0x4000 ,50  ,449 ,40 ,400 ,_EGA_HALF_CLOCK	| _EGA_LINE_DOUBLE},
201 { 0x006  ,M_CGA2   ,640 ,200 ,80 ,25 ,8 ,8  ,1 ,0xB8000 ,0x4000 ,100 ,449 ,80 ,400 ,_EGA_LINE_DOUBLE},
202 { 0x007  ,M_TEXT   ,720 ,400 ,80 ,25 ,9 ,16 ,8 ,0xB0000 ,0x1000 ,100 ,449 ,80 ,400 ,0	},
203 
204 { 0x00D  ,M_EGA    ,320 ,200 ,40 ,25 ,8 ,8  ,8 ,0xA0000 ,0x2000 ,50  ,449 ,40 ,400 ,_EGA_HALF_CLOCK	| _EGA_LINE_DOUBLE	},
205 { 0x00E  ,M_EGA    ,640 ,200 ,80 ,25 ,8 ,8  ,4 ,0xA0000 ,0x4000 ,100 ,449 ,80 ,400 ,_EGA_LINE_DOUBLE },
206 { 0x00F  ,M_EGA    ,640 ,350 ,80 ,25 ,8 ,14 ,2 ,0xA0000 ,0x8000 ,100 ,449 ,80 ,350 ,0	},/*was EGA_2*/
207 { 0x010  ,M_EGA    ,640 ,350 ,80 ,25 ,8 ,14 ,2 ,0xA0000 ,0x8000 ,100 ,449 ,80 ,350 ,0	},
208 { 0x011  ,M_EGA    ,640 ,480 ,80 ,30 ,8 ,16 ,1 ,0xA0000 ,0xA000 ,100 ,525 ,80 ,480 ,0	},/*was EGA_2 */
209 { 0x012  ,M_EGA    ,640 ,480 ,80 ,30 ,8 ,16 ,1 ,0xA0000 ,0xA000 ,100 ,525 ,80 ,480 ,0	},
210 { 0x013  ,M_VGA    ,320 ,200 ,40 ,25 ,8 ,8  ,1 ,0xA0000 ,0x2000 ,100 ,449 ,80 ,400 ,0   },
211 
212 { 0x054  ,M_TEXT   ,1056 ,688, 132,43, 8, 9, 1, 0xB0000, 0x4000, 192, 720, 132,688, 0 },
213 { 0x055  ,M_TEXT   ,1056 ,400, 132,25, 8, 16,1, 0xB0000, 0x2000, 192, 449, 132,400, 0 },
214 { 0x056  ,M_TEXT   ,1056 ,688, 132,43, 8, 9, 1, 0xB0000, 0x4000, 192, 720, 132,688, 0 },
215 { 0x057  ,M_TEXT   ,1056 ,400, 132,25, 8, 16,1, 0xB0000, 0x2000, 192, 449, 132,400, 0 },
216 { 0x058  ,M_LIN4   ,800 , 600, 100,37, 8, 16,1, 0xA0000, 0xA000, 128 ,663 ,100,600, 0 },
217 { 0x05D  ,M_LIN4   ,1024, 768, 128,48 ,8, 16,1, 0xA0000, 0x10000,128 ,800 ,128,768 ,0 }, // documented only on C00 upwards
218 { 0x05E  ,M_LIN8   ,640 , 400, 80 ,25, 8, 16,1, 0xA0000, 0x10000,100 ,449 ,80 ,400, 0 },
219 { 0x05F  ,M_LIN8   ,640 , 480, 80 ,30, 8, 16,1, 0xA0000, 0x10000,100 ,525 ,80 ,480, 0 },
220 
221 {0xFFFF  ,M_ERROR  ,0   ,0   ,0  ,0  ,0 ,0  ,0 ,0x00000 ,0x0000 ,0   ,0   ,0  ,0   ,0 	},
222 };
223 
224 
225 VideoModeBlock ModeList_EGA[]={
226 /* mode  ,type     ,sw  ,sh  ,tw ,th ,cw,ch ,pt,pstart  ,plength,htot,vtot,hde,vde special flags */
227 { 0x000  ,M_TEXT   ,320 ,350 ,40 ,25 ,8 ,14 ,8 ,0xB8000 ,0x0800 ,50  ,366 ,40 ,350 ,_EGA_HALF_CLOCK	},
228 { 0x001  ,M_TEXT   ,320 ,350 ,40 ,25 ,8 ,14 ,8 ,0xB8000 ,0x0800 ,50  ,366 ,40 ,350 ,_EGA_HALF_CLOCK	},
229 { 0x002  ,M_TEXT   ,640 ,350 ,80 ,25 ,8 ,14 ,8 ,0xB8000 ,0x1000 ,96  ,366 ,80 ,350 ,0	},
230 { 0x003  ,M_TEXT   ,640 ,350 ,80 ,25 ,8 ,14 ,8 ,0xB8000 ,0x1000 ,96  ,366 ,80 ,350 ,0	},
231 { 0x004  ,M_CGA4   ,320 ,200 ,40 ,25 ,8 ,8  ,1 ,0xB8000 ,0x4000 ,60  ,262 ,40 ,200 ,_EGA_HALF_CLOCK	| _EGA_LINE_DOUBLE},
232 { 0x005  ,M_CGA4   ,320 ,200 ,40 ,25 ,8 ,8  ,1 ,0xB8000 ,0x4000 ,60  ,262 ,40 ,200 ,_EGA_HALF_CLOCK	| _EGA_LINE_DOUBLE},
233 { 0x006  ,M_CGA2   ,640 ,200 ,80 ,25 ,8 ,8  ,1 ,0xB8000 ,0x4000 ,120 ,262 ,80 ,200 ,_EGA_LINE_DOUBLE},
234 { 0x007  ,M_TEXT   ,720 ,350 ,80 ,25 ,9 ,14 ,8 ,0xB0000 ,0x1000 ,120 ,440 ,80 ,350 ,0	},
235 
236 { 0x00D  ,M_EGA    ,320 ,200 ,40 ,25 ,8 ,8  ,8 ,0xA0000 ,0x2000 ,60  ,262 ,40 ,200 ,_EGA_HALF_CLOCK	| _EGA_LINE_DOUBLE	},
237 { 0x00E  ,M_EGA    ,640 ,200 ,80 ,25 ,8 ,8  ,4 ,0xA0000 ,0x4000 ,120 ,262 ,80 ,200 ,_EGA_LINE_DOUBLE },
238 { 0x00F  ,M_EGA    ,640 ,350 ,80 ,25 ,8 ,14 ,2 ,0xA0000 ,0x8000 ,96  ,366 ,80 ,350 ,0	},/*was EGA_2*/
239 { 0x010  ,M_EGA    ,640 ,350 ,80 ,25 ,8 ,14 ,2 ,0xA0000 ,0x8000 ,96  ,366 ,80 ,350 ,0	},
240 
241 {0xFFFF  ,M_ERROR  ,0   ,0   ,0  ,0  ,0 ,0  ,0 ,0x00000 ,0x0000 ,0   ,0   ,0  ,0   ,0 	},
242 };
243 
244 VideoModeBlock ModeList_OTHER[]={
245 /* mode  ,type     ,sw  ,sh  ,tw ,th ,cw,ch ,pt,pstart  ,plength,htot,vtot,hde,vde ,special flags */
246 { 0x000  ,M_TEXT   ,320 ,400 ,40 ,25 ,8 ,8  ,8 ,0xB8000 ,0x0800 ,56  ,31  ,40 ,25  ,0   },
247 { 0x001  ,M_TEXT   ,320 ,400 ,40 ,25 ,8 ,8  ,8 ,0xB8000 ,0x0800 ,56  ,31  ,40 ,25  ,0	},
248 { 0x002  ,M_TEXT   ,640 ,400 ,80 ,25 ,8 ,8  ,4 ,0xB8000 ,0x1000 ,113 ,31  ,80 ,25  ,0	},
249 { 0x003  ,M_TEXT   ,640 ,400 ,80 ,25 ,8 ,8  ,4 ,0xB8000 ,0x1000 ,113 ,31  ,80 ,25  ,0	},
250 { 0x004  ,M_CGA4   ,320 ,200 ,40 ,25 ,8 ,8  ,1 ,0xB8000 ,0x4000 ,56  ,127 ,40 ,100 ,0   },
251 { 0x005  ,M_CGA4   ,320 ,200 ,40 ,25 ,8 ,8  ,1 ,0xB8000 ,0x4000 ,56  ,127 ,40 ,100 ,0   },
252 { 0x006  ,M_CGA2   ,640 ,200 ,80 ,25 ,8 ,8  ,1 ,0xB8000 ,0x4000 ,56  ,127 ,40 ,100 ,0   },
253 { 0x008  ,M_TANDY16,160 ,200 ,20 ,25 ,8 ,8  ,8 ,0xB8000 ,0x2000 ,56  ,127 ,40 ,100 ,0   },
254 { 0x009  ,M_TANDY16,320 ,200 ,40 ,25 ,8 ,8  ,8 ,0xB8000 ,0x2000 ,113 ,63  ,80 ,50  ,0   },
255 { 0x00A  ,M_CGA4   ,640 ,200 ,80 ,25 ,8 ,8  ,8 ,0xB8000 ,0x2000 ,113 ,63  ,80 ,50  ,0   },
256 //{ 0x00E  ,M_TANDY16,640 ,200 ,80 ,25 ,8 ,8  ,8 ,0xA0000 ,0x10000 ,113 ,256 ,80 ,200 ,0   },
257 {0xFFFF  ,M_ERROR  ,0   ,0   ,0  ,0  ,0 ,0  ,0 ,0x00000 ,0x0000 ,0   ,0   ,0  ,0   ,0 	},
258 };
259 
260 VideoModeBlock Hercules_Mode=
261 { 0x007  ,M_TEXT   ,640 ,350 ,80 ,25 ,8 ,14 ,1 ,0xB0000 ,0x1000 ,97 ,25  ,80 ,25  ,0	};
262 
263 static Bit8u text_palette[64][3]=
264 {
265   {0x00,0x00,0x00},{0x00,0x00,0x2a},{0x00,0x2a,0x00},{0x00,0x2a,0x2a},{0x2a,0x00,0x00},{0x2a,0x00,0x2a},{0x2a,0x2a,0x00},{0x2a,0x2a,0x2a},
266   {0x00,0x00,0x15},{0x00,0x00,0x3f},{0x00,0x2a,0x15},{0x00,0x2a,0x3f},{0x2a,0x00,0x15},{0x2a,0x00,0x3f},{0x2a,0x2a,0x15},{0x2a,0x2a,0x3f},
267   {0x00,0x15,0x00},{0x00,0x15,0x2a},{0x00,0x3f,0x00},{0x00,0x3f,0x2a},{0x2a,0x15,0x00},{0x2a,0x15,0x2a},{0x2a,0x3f,0x00},{0x2a,0x3f,0x2a},
268   {0x00,0x15,0x15},{0x00,0x15,0x3f},{0x00,0x3f,0x15},{0x00,0x3f,0x3f},{0x2a,0x15,0x15},{0x2a,0x15,0x3f},{0x2a,0x3f,0x15},{0x2a,0x3f,0x3f},
269   {0x15,0x00,0x00},{0x15,0x00,0x2a},{0x15,0x2a,0x00},{0x15,0x2a,0x2a},{0x3f,0x00,0x00},{0x3f,0x00,0x2a},{0x3f,0x2a,0x00},{0x3f,0x2a,0x2a},
270   {0x15,0x00,0x15},{0x15,0x00,0x3f},{0x15,0x2a,0x15},{0x15,0x2a,0x3f},{0x3f,0x00,0x15},{0x3f,0x00,0x3f},{0x3f,0x2a,0x15},{0x3f,0x2a,0x3f},
271   {0x15,0x15,0x00},{0x15,0x15,0x2a},{0x15,0x3f,0x00},{0x15,0x3f,0x2a},{0x3f,0x15,0x00},{0x3f,0x15,0x2a},{0x3f,0x3f,0x00},{0x3f,0x3f,0x2a},
272   {0x15,0x15,0x15},{0x15,0x15,0x3f},{0x15,0x3f,0x15},{0x15,0x3f,0x3f},{0x3f,0x15,0x15},{0x3f,0x15,0x3f},{0x3f,0x3f,0x15},{0x3f,0x3f,0x3f}
273 };
274 
275 static Bit8u mtext_palette[64][3]=
276 {
277   {0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},
278   {0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},
279   {0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},
280   {0x3f,0x3f,0x3f},{0x3f,0x3f,0x3f},{0x3f,0x3f,0x3f},{0x3f,0x3f,0x3f},{0x3f,0x3f,0x3f},{0x3f,0x3f,0x3f},{0x3f,0x3f,0x3f},{0x3f,0x3f,0x3f},
281   {0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},
282   {0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},
283   {0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},
284   {0x3f,0x3f,0x3f},{0x3f,0x3f,0x3f},{0x3f,0x3f,0x3f},{0x3f,0x3f,0x3f},{0x3f,0x3f,0x3f},{0x3f,0x3f,0x3f},{0x3f,0x3f,0x3f},{0x3f,0x3f,0x3f}
285 };
286 
287 static Bit8u mtext_s3_palette[64][3]=
288 {
289   {0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},
290   {0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},
291   {0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},
292   {0x3f,0x3f,0x3f},{0x3f,0x3f,0x3f},{0x3f,0x3f,0x3f},{0x3f,0x3f,0x3f},{0x3f,0x3f,0x3f},{0x3f,0x3f,0x3f},{0x3f,0x3f,0x3f},{0x3f,0x3f,0x3f},
293   {0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},
294   {0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},
295   {0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},{0x2a,0x2a,0x2a},
296   {0x3f,0x3f,0x3f},{0x3f,0x3f,0x3f},{0x3f,0x3f,0x3f},{0x3f,0x3f,0x3f},{0x3f,0x3f,0x3f},{0x3f,0x3f,0x3f},{0x3f,0x3f,0x3f},{0x3f,0x3f,0x3f}
297 };
298 
299 static Bit8u ega_palette[64][3]=
300 {
301   {0x00,0x00,0x00}, {0x00,0x00,0x2a}, {0x00,0x2a,0x00}, {0x00,0x2a,0x2a}, {0x2a,0x00,0x00}, {0x2a,0x00,0x2a}, {0x2a,0x15,0x00}, {0x2a,0x2a,0x2a},
302   {0x00,0x00,0x00}, {0x00,0x00,0x2a}, {0x00,0x2a,0x00}, {0x00,0x2a,0x2a}, {0x2a,0x00,0x00}, {0x2a,0x00,0x2a}, {0x2a,0x15,0x00}, {0x2a,0x2a,0x2a},
303   {0x15,0x15,0x15}, {0x15,0x15,0x3f}, {0x15,0x3f,0x15}, {0x15,0x3f,0x3f}, {0x3f,0x15,0x15}, {0x3f,0x15,0x3f}, {0x3f,0x3f,0x15}, {0x3f,0x3f,0x3f},
304   {0x15,0x15,0x15}, {0x15,0x15,0x3f}, {0x15,0x3f,0x15}, {0x15,0x3f,0x3f}, {0x3f,0x15,0x15}, {0x3f,0x15,0x3f}, {0x3f,0x3f,0x15}, {0x3f,0x3f,0x3f},
305   {0x00,0x00,0x00}, {0x00,0x00,0x2a}, {0x00,0x2a,0x00}, {0x00,0x2a,0x2a}, {0x2a,0x00,0x00}, {0x2a,0x00,0x2a}, {0x2a,0x15,0x00}, {0x2a,0x2a,0x2a},
306   {0x00,0x00,0x00}, {0x00,0x00,0x2a}, {0x00,0x2a,0x00}, {0x00,0x2a,0x2a}, {0x2a,0x00,0x00}, {0x2a,0x00,0x2a}, {0x2a,0x15,0x00}, {0x2a,0x2a,0x2a},
307   {0x15,0x15,0x15}, {0x15,0x15,0x3f}, {0x15,0x3f,0x15}, {0x15,0x3f,0x3f}, {0x3f,0x15,0x15}, {0x3f,0x15,0x3f}, {0x3f,0x3f,0x15}, {0x3f,0x3f,0x3f},
308   {0x15,0x15,0x15}, {0x15,0x15,0x3f}, {0x15,0x3f,0x15}, {0x15,0x3f,0x3f}, {0x3f,0x15,0x15}, {0x3f,0x15,0x3f}, {0x3f,0x3f,0x15}, {0x3f,0x3f,0x3f}
309 };
310 
311 static Bit8u cga_palette[16][3]=
312 {
313 	{0x00,0x00,0x00}, {0x00,0x00,0x2a}, {0x00,0x2a,0x00}, {0x00,0x2a,0x2a}, {0x2a,0x00,0x00}, {0x2a,0x00,0x2a}, {0x2a,0x15,0x00}, {0x2a,0x2a,0x2a},
314 	{0x15,0x15,0x15}, {0x15,0x15,0x3f}, {0x15,0x3f,0x15}, {0x15,0x3f,0x3f}, {0x3f,0x15,0x15}, {0x3f,0x15,0x3f}, {0x3f,0x3f,0x15}, {0x3f,0x3f,0x3f},
315 };
316 
317 static Bit8u cga_palette_2[64][3]=
318 {
319 	{0x00,0x00,0x00}, {0x00,0x00,0x2a}, {0x00,0x2a,0x00}, {0x00,0x2a,0x2a}, {0x2a,0x00,0x00}, {0x2a,0x00,0x2a}, {0x2a,0x15,0x00}, {0x2a,0x2a,0x2a},
320 	{0x00,0x00,0x00}, {0x00,0x00,0x2a}, {0x00,0x2a,0x00}, {0x00,0x2a,0x2a}, {0x2a,0x00,0x00}, {0x2a,0x00,0x2a}, {0x2a,0x15,0x00}, {0x2a,0x2a,0x2a},
321 	{0x15,0x15,0x15}, {0x15,0x15,0x3f}, {0x15,0x3f,0x15}, {0x15,0x3f,0x3f}, {0x3f,0x15,0x15}, {0x3f,0x15,0x3f}, {0x3f,0x3f,0x15}, {0x3f,0x3f,0x3f},
322 	{0x15,0x15,0x15}, {0x15,0x15,0x3f}, {0x15,0x3f,0x15}, {0x15,0x3f,0x3f}, {0x3f,0x15,0x15}, {0x3f,0x15,0x3f}, {0x3f,0x3f,0x15}, {0x3f,0x3f,0x3f},
323 	{0x00,0x00,0x00}, {0x00,0x00,0x2a}, {0x00,0x2a,0x00}, {0x00,0x2a,0x2a}, {0x2a,0x00,0x00}, {0x2a,0x00,0x2a}, {0x2a,0x15,0x00}, {0x2a,0x2a,0x2a},
324 	{0x00,0x00,0x00}, {0x00,0x00,0x2a}, {0x00,0x2a,0x00}, {0x00,0x2a,0x2a}, {0x2a,0x00,0x00}, {0x2a,0x00,0x2a}, {0x2a,0x15,0x00}, {0x2a,0x2a,0x2a},
325 	{0x15,0x15,0x15}, {0x15,0x15,0x3f}, {0x15,0x3f,0x15}, {0x15,0x3f,0x3f}, {0x3f,0x15,0x15}, {0x3f,0x15,0x3f}, {0x3f,0x3f,0x15}, {0x3f,0x3f,0x3f},
326 	{0x15,0x15,0x15}, {0x15,0x15,0x3f}, {0x15,0x3f,0x15}, {0x15,0x3f,0x3f}, {0x3f,0x15,0x15}, {0x3f,0x15,0x3f}, {0x3f,0x3f,0x15}, {0x3f,0x3f,0x3f},
327 };
328 
329 static Bit8u vga_palette[248][3]=
330 {
331   {0x00,0x00,0x00},{0x00,0x00,0x2a},{0x00,0x2a,0x00},{0x00,0x2a,0x2a},{0x2a,0x00,0x00},{0x2a,0x00,0x2a},{0x2a,0x15,0x00},{0x2a,0x2a,0x2a},
332   {0x15,0x15,0x15},{0x15,0x15,0x3f},{0x15,0x3f,0x15},{0x15,0x3f,0x3f},{0x3f,0x15,0x15},{0x3f,0x15,0x3f},{0x3f,0x3f,0x15},{0x3f,0x3f,0x3f},
333   {0x00,0x00,0x00},{0x05,0x05,0x05},{0x08,0x08,0x08},{0x0b,0x0b,0x0b},{0x0e,0x0e,0x0e},{0x11,0x11,0x11},{0x14,0x14,0x14},{0x18,0x18,0x18},
334   {0x1c,0x1c,0x1c},{0x20,0x20,0x20},{0x24,0x24,0x24},{0x28,0x28,0x28},{0x2d,0x2d,0x2d},{0x32,0x32,0x32},{0x38,0x38,0x38},{0x3f,0x3f,0x3f},
335   {0x00,0x00,0x3f},{0x10,0x00,0x3f},{0x1f,0x00,0x3f},{0x2f,0x00,0x3f},{0x3f,0x00,0x3f},{0x3f,0x00,0x2f},{0x3f,0x00,0x1f},{0x3f,0x00,0x10},
336   {0x3f,0x00,0x00},{0x3f,0x10,0x00},{0x3f,0x1f,0x00},{0x3f,0x2f,0x00},{0x3f,0x3f,0x00},{0x2f,0x3f,0x00},{0x1f,0x3f,0x00},{0x10,0x3f,0x00},
337   {0x00,0x3f,0x00},{0x00,0x3f,0x10},{0x00,0x3f,0x1f},{0x00,0x3f,0x2f},{0x00,0x3f,0x3f},{0x00,0x2f,0x3f},{0x00,0x1f,0x3f},{0x00,0x10,0x3f},
338   {0x1f,0x1f,0x3f},{0x27,0x1f,0x3f},{0x2f,0x1f,0x3f},{0x37,0x1f,0x3f},{0x3f,0x1f,0x3f},{0x3f,0x1f,0x37},{0x3f,0x1f,0x2f},{0x3f,0x1f,0x27},
339 
340   {0x3f,0x1f,0x1f},{0x3f,0x27,0x1f},{0x3f,0x2f,0x1f},{0x3f,0x37,0x1f},{0x3f,0x3f,0x1f},{0x37,0x3f,0x1f},{0x2f,0x3f,0x1f},{0x27,0x3f,0x1f},
341   {0x1f,0x3f,0x1f},{0x1f,0x3f,0x27},{0x1f,0x3f,0x2f},{0x1f,0x3f,0x37},{0x1f,0x3f,0x3f},{0x1f,0x37,0x3f},{0x1f,0x2f,0x3f},{0x1f,0x27,0x3f},
342   {0x2d,0x2d,0x3f},{0x31,0x2d,0x3f},{0x36,0x2d,0x3f},{0x3a,0x2d,0x3f},{0x3f,0x2d,0x3f},{0x3f,0x2d,0x3a},{0x3f,0x2d,0x36},{0x3f,0x2d,0x31},
343   {0x3f,0x2d,0x2d},{0x3f,0x31,0x2d},{0x3f,0x36,0x2d},{0x3f,0x3a,0x2d},{0x3f,0x3f,0x2d},{0x3a,0x3f,0x2d},{0x36,0x3f,0x2d},{0x31,0x3f,0x2d},
344   {0x2d,0x3f,0x2d},{0x2d,0x3f,0x31},{0x2d,0x3f,0x36},{0x2d,0x3f,0x3a},{0x2d,0x3f,0x3f},{0x2d,0x3a,0x3f},{0x2d,0x36,0x3f},{0x2d,0x31,0x3f},
345   {0x00,0x00,0x1c},{0x07,0x00,0x1c},{0x0e,0x00,0x1c},{0x15,0x00,0x1c},{0x1c,0x00,0x1c},{0x1c,0x00,0x15},{0x1c,0x00,0x0e},{0x1c,0x00,0x07},
346   {0x1c,0x00,0x00},{0x1c,0x07,0x00},{0x1c,0x0e,0x00},{0x1c,0x15,0x00},{0x1c,0x1c,0x00},{0x15,0x1c,0x00},{0x0e,0x1c,0x00},{0x07,0x1c,0x00},
347   {0x00,0x1c,0x00},{0x00,0x1c,0x07},{0x00,0x1c,0x0e},{0x00,0x1c,0x15},{0x00,0x1c,0x1c},{0x00,0x15,0x1c},{0x00,0x0e,0x1c},{0x00,0x07,0x1c},
348 
349   {0x0e,0x0e,0x1c},{0x11,0x0e,0x1c},{0x15,0x0e,0x1c},{0x18,0x0e,0x1c},{0x1c,0x0e,0x1c},{0x1c,0x0e,0x18},{0x1c,0x0e,0x15},{0x1c,0x0e,0x11},
350   {0x1c,0x0e,0x0e},{0x1c,0x11,0x0e},{0x1c,0x15,0x0e},{0x1c,0x18,0x0e},{0x1c,0x1c,0x0e},{0x18,0x1c,0x0e},{0x15,0x1c,0x0e},{0x11,0x1c,0x0e},
351   {0x0e,0x1c,0x0e},{0x0e,0x1c,0x11},{0x0e,0x1c,0x15},{0x0e,0x1c,0x18},{0x0e,0x1c,0x1c},{0x0e,0x18,0x1c},{0x0e,0x15,0x1c},{0x0e,0x11,0x1c},
352   {0x14,0x14,0x1c},{0x16,0x14,0x1c},{0x18,0x14,0x1c},{0x1a,0x14,0x1c},{0x1c,0x14,0x1c},{0x1c,0x14,0x1a},{0x1c,0x14,0x18},{0x1c,0x14,0x16},
353   {0x1c,0x14,0x14},{0x1c,0x16,0x14},{0x1c,0x18,0x14},{0x1c,0x1a,0x14},{0x1c,0x1c,0x14},{0x1a,0x1c,0x14},{0x18,0x1c,0x14},{0x16,0x1c,0x14},
354   {0x14,0x1c,0x14},{0x14,0x1c,0x16},{0x14,0x1c,0x18},{0x14,0x1c,0x1a},{0x14,0x1c,0x1c},{0x14,0x1a,0x1c},{0x14,0x18,0x1c},{0x14,0x16,0x1c},
355   {0x00,0x00,0x10},{0x04,0x00,0x10},{0x08,0x00,0x10},{0x0c,0x00,0x10},{0x10,0x00,0x10},{0x10,0x00,0x0c},{0x10,0x00,0x08},{0x10,0x00,0x04},
356   {0x10,0x00,0x00},{0x10,0x04,0x00},{0x10,0x08,0x00},{0x10,0x0c,0x00},{0x10,0x10,0x00},{0x0c,0x10,0x00},{0x08,0x10,0x00},{0x04,0x10,0x00},
357 
358   {0x00,0x10,0x00},{0x00,0x10,0x04},{0x00,0x10,0x08},{0x00,0x10,0x0c},{0x00,0x10,0x10},{0x00,0x0c,0x10},{0x00,0x08,0x10},{0x00,0x04,0x10},
359   {0x08,0x08,0x10},{0x0a,0x08,0x10},{0x0c,0x08,0x10},{0x0e,0x08,0x10},{0x10,0x08,0x10},{0x10,0x08,0x0e},{0x10,0x08,0x0c},{0x10,0x08,0x0a},
360   {0x10,0x08,0x08},{0x10,0x0a,0x08},{0x10,0x0c,0x08},{0x10,0x0e,0x08},{0x10,0x10,0x08},{0x0e,0x10,0x08},{0x0c,0x10,0x08},{0x0a,0x10,0x08},
361   {0x08,0x10,0x08},{0x08,0x10,0x0a},{0x08,0x10,0x0c},{0x08,0x10,0x0e},{0x08,0x10,0x10},{0x08,0x0e,0x10},{0x08,0x0c,0x10},{0x08,0x0a,0x10},
362   {0x0b,0x0b,0x10},{0x0c,0x0b,0x10},{0x0d,0x0b,0x10},{0x0f,0x0b,0x10},{0x10,0x0b,0x10},{0x10,0x0b,0x0f},{0x10,0x0b,0x0d},{0x10,0x0b,0x0c},
363   {0x10,0x0b,0x0b},{0x10,0x0c,0x0b},{0x10,0x0d,0x0b},{0x10,0x0f,0x0b},{0x10,0x10,0x0b},{0x0f,0x10,0x0b},{0x0d,0x10,0x0b},{0x0c,0x10,0x0b},
364   {0x0b,0x10,0x0b},{0x0b,0x10,0x0c},{0x0b,0x10,0x0d},{0x0b,0x10,0x0f},{0x0b,0x10,0x10},{0x0b,0x0f,0x10},{0x0b,0x0d,0x10},{0x0b,0x0c,0x10}
365 };
366 VideoModeBlock * CurMode;
367 
SetCurMode(VideoModeBlock modeblock[],Bit16u mode)368 static bool SetCurMode(VideoModeBlock modeblock[],Bit16u mode) {
369 	Bitu i=0;
370 	while (modeblock[i].mode!=0xffff) {
371 		if (modeblock[i].mode!=mode) i++;
372 		else {
373 			if ((!int10.vesa_oldvbe) || (ModeList_VGA[i].mode<0x120)) {
374 				CurMode=&modeblock[i];
375 				return true;
376 			}
377 			return false;
378 		}
379 	}
380 	return false;
381 }
382 
SetTextLines(void)383 static void SetTextLines(void) {
384 	// check for scanline backwards compatibility (VESA text modes??)
385 	switch (real_readb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)&0x90) {
386 	case 0x80: // 200 lines emulation
387 		if (CurMode->mode <= 3) {
388 			CurMode = &ModeList_VGA_Text_200lines[CurMode->mode];
389 		} else if (CurMode->mode == 7) {
390 			CurMode = &ModeList_VGA_Text_350lines[4];
391 		}
392 		break;
393 	case 0x00: // 350 lines emulation
394 		if (CurMode->mode <= 3) {
395 			CurMode = &ModeList_VGA_Text_350lines[CurMode->mode];
396 		} else if (CurMode->mode == 7) {
397 			CurMode = &ModeList_VGA_Text_350lines[4];
398 		}
399 		break;
400 	}
401 }
402 
INT10_SetCurMode(void)403 void INT10_SetCurMode(void) {
404 	Bit16u bios_mode=(Bit16u)real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
405 	if (GCC_UNLIKELY(CurMode->mode!=bios_mode)) {
406 		bool mode_changed=false;
407 		switch (machine) {
408 		case MCH_CGA:
409 			if (bios_mode<7) mode_changed=SetCurMode(ModeList_OTHER,bios_mode);
410 			break;
411 		case TANDY_ARCH_CASE:
412 			if (bios_mode!=7 && bios_mode<=0xa) mode_changed=SetCurMode(ModeList_OTHER,bios_mode);
413 			break;
414 		case MCH_HERC:
415 			if (bios_mode<7) mode_changed=SetCurMode(ModeList_OTHER,bios_mode);
416 			else if (bios_mode==7) {mode_changed=true;CurMode=&Hercules_Mode;}
417 			break;
418 		case MCH_EGA:
419 			mode_changed=SetCurMode(ModeList_EGA,bios_mode);
420 			break;
421 		case VGA_ARCH_CASE:
422 			switch (svgaCard) {
423 			case SVGA_TsengET4K:
424 			case SVGA_TsengET3K:
425 				mode_changed=SetCurMode(ModeList_VGA_Tseng,bios_mode);
426 				break;
427 			case SVGA_ParadisePVGA1A:
428 				mode_changed=SetCurMode(ModeList_VGA_Paradise,bios_mode);
429 				break;
430 			case SVGA_S3Trio:
431 				if (bios_mode>=0x68 && CurMode->mode==(bios_mode+0x98)) break;
432 				// fall-through
433 			default:
434 				mode_changed=SetCurMode(ModeList_VGA,bios_mode);
435 				break;
436 			}
437 			if (mode_changed && CurMode->type==M_TEXT) SetTextLines();
438 			break;
439 		}
440 		if (mode_changed) LOG(LOG_INT10,LOG_WARN)("BIOS video mode changed to %X",bios_mode);
441 	}
442 }
443 
FinishSetMode(bool clearmem)444 static void FinishSetMode(bool clearmem) {
445 	/* Clear video memory if needs be */
446 	if (clearmem) {
447 		switch (CurMode->type) {
448 		case M_TANDY16:
449 		case M_CGA4:
450 			if ((machine==MCH_PCJR) && (CurMode->mode >= 9)) {
451 				// PCJR cannot access the full 32k at 0xb800
452 				for (Bit16u ct=0;ct<16*1024;ct++) {
453 					// 0x1800 is the last 32k block in 128k, as set in the CRTCPU_PAGE register
454 					real_writew(0x1800,ct*2,0x0000);
455 				}
456 				break;
457 			}
458 			// fall-through
459 		case M_CGA2:
460 			for (Bit16u ct=0;ct<16*1024;ct++) {
461 				real_writew( 0xb800,ct*2,0x0000);
462 			}
463 			break;
464 		case M_TEXT: {
465 			Bit16u seg = (CurMode->mode==7)?0xb000:0xb800;
466 			for (Bit16u ct=0;ct<16*1024;ct++) real_writew(seg,ct*2,0x0720);
467 			break;
468 		}
469 		case M_EGA:
470 		case M_VGA:
471 		case M_LIN8:
472 		case M_LIN4:
473 		case M_LIN15:
474 		case M_LIN16:
475 		case M_LIN32:
476 			/* Hack we just access the memory directly */
477 			memset(vga.mem.linear,0,vga.vmemsize);
478 			memset(vga.fastmem, 0, vga.vmemsize<<1);
479 		}
480 	}
481 	/* Setup the BIOS */
482 	if (CurMode->mode<128) real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE,(Bit8u)CurMode->mode);
483 	else real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE,(Bit8u)(CurMode->mode-0x98));	//Looks like the s3 bios
484 	real_writew(BIOSMEM_SEG,BIOSMEM_NB_COLS,(Bit16u)CurMode->twidth);
485 	real_writew(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE,(Bit16u)CurMode->plength);
486 	real_writew(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS,((CurMode->mode==7 )|| (CurMode->mode==0x0f)) ? 0x3b4 : 0x3d4);
487 	real_writeb(BIOSMEM_SEG,BIOSMEM_NB_ROWS,(Bit8u)(CurMode->theight-1));
488 	real_writew(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,(Bit16u)CurMode->cheight);
489 	real_writeb(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,(0x60|(clearmem?0:0x80)));
490 	real_writeb(BIOSMEM_SEG,BIOSMEM_SWITCHES,0x09);
491 
492 	// this is an index into the dcc table:
493 	if (IS_VGA_ARCH) real_writeb(BIOSMEM_SEG,BIOSMEM_DCC_INDEX,0x0b);
494 
495 	// Set cursor shape
496 	if (CurMode->type==M_TEXT) {
497 		INT10_SetCursorShape(0x06,07);
498 	}
499 	// Set cursor pos for page 0..7
500 	for (Bit8u ct=0;ct<8;ct++) INT10_SetCursorPos(0,0,ct);
501 	// Set active page 0
502 	INT10_SetActivePage(0);
503 	/* Set some interrupt vectors */
504 	if (CurMode->mode<=3 || CurMode->mode==7)
505 		RealSetVec(0x43,int10.rom.font_8_first);
506 	else {
507 		switch (CurMode->cheight) {
508 		case 8:RealSetVec(0x43,int10.rom.font_8_first);break;
509 		case 14:RealSetVec(0x43,int10.rom.font_14);break;
510 		case 16:RealSetVec(0x43,int10.rom.font_16);break;
511 		}
512 	}
513 }
514 
INT10_SetVideoMode_OTHER(Bit16u mode,bool clearmem)515 bool INT10_SetVideoMode_OTHER(Bit16u mode,bool clearmem) {
516 	switch (machine) {
517 	case MCH_CGA:
518 		if (mode>6) return false;
519 	case TANDY_ARCH_CASE:
520 		if (mode>0xa) return false;
521 		if (mode==7) mode=0; // PCJR defaults to 0 on illegal mode 7
522 		if (!SetCurMode(ModeList_OTHER,mode)) {
523 			LOG(LOG_INT10,LOG_ERROR)("Trying to set illegal mode %X",mode);
524 			return false;
525 		}
526 		break;
527 	case MCH_HERC:
528 		// Allow standard color modes if equipment word is not set to mono (Victory Road)
529 		if ((real_readw(BIOSMEM_SEG,BIOSMEM_INITIAL_MODE)&0x30)!=0x30 && mode<7) {
530 			SetCurMode(ModeList_OTHER,mode);
531 			FinishSetMode(clearmem);
532 			return true;
533 		}
534 		CurMode=&Hercules_Mode;
535 		mode=7; // in case the video parameter table is modified
536 		break;
537 	}
538 	LOG(LOG_INT10,LOG_NORMAL)("Set Video Mode %X",mode);
539 
540 	/* Setup the VGA to the correct mode */
541 //	VGA_SetMode(CurMode->type);
542 	/* Setup the CRTC */
543 	Bitu crtc_base=machine==MCH_HERC ? 0x3b4 : 0x3d4;
544 	//Horizontal total
545 	IO_WriteW(crtc_base,0x00 | (CurMode->htotal) << 8);
546 	//Horizontal displayed
547 	IO_WriteW(crtc_base,0x01 | (CurMode->hdispend) << 8);
548 	//Horizontal sync position
549 	IO_WriteW(crtc_base,0x02 | (CurMode->hdispend+1) << 8);
550 	//Horizontal sync width, seems to be fixed to 0xa, for cga at least, hercules has 0xf
551 	IO_WriteW(crtc_base,0x03 | (0xa) << 8);
552 	////Vertical total
553 	IO_WriteW(crtc_base,0x04 | (CurMode->vtotal) << 8);
554 	//Vertical total adjust, 6 for cga,hercules,tandy
555 	IO_WriteW(crtc_base,0x05 | (6) << 8);
556 	//Vertical displayed
557 	IO_WriteW(crtc_base,0x06 | (CurMode->vdispend) << 8);
558 	//Vertical sync position
559 	IO_WriteW(crtc_base,0x07 | (CurMode->vdispend + ((CurMode->vtotal - CurMode->vdispend)/2)-1) << 8);
560 	//Maximum scanline
561 	Bit8u scanline,crtpage;
562 	scanline=8;
563 	switch(CurMode->type) {
564 	case M_TEXT:
565 		if (machine==MCH_HERC) scanline=14;
566 		else scanline=8;
567 		break;
568 	case M_CGA2:
569 		scanline=2;
570 		break;
571 	case M_CGA4:
572 		if (CurMode->mode!=0xa) scanline=2;
573 		else scanline=4;
574 		break;
575 	case M_TANDY16:
576 		if (CurMode->mode!=0x9) scanline=2;
577 		else scanline=4;
578 		break;
579 	}
580 	IO_WriteW(crtc_base,0x09 | (scanline-1) << 8);
581 	//Setup the CGA palette using VGA DAC palette
582 	for (Bit8u ct=0;ct<16;ct++) VGA_DAC_SetEntry(ct,cga_palette[ct][0],cga_palette[ct][1],cga_palette[ct][2]);
583 	//Setup the tandy palette
584 	for (Bit8u ct=0;ct<16;ct++) VGA_DAC_CombineColor(ct,ct);
585 	//Setup the special registers for each machine type
586 	Bit8u mode_control_list[0xa+1]={
587 		0x2c,0x28,0x2d,0x29,	//0-3
588 		0x2a,0x2e,0x1e,0x29,	//4-7
589 		0x2a,0x2b,0x3b			//8-a
590 	};
591 	Bit8u mode_control_list_pcjr[0xa+1]={
592 		0x0c,0x08,0x0d,0x09,	//0-3
593 		0x0a,0x0e,0x0e,0x09,	//4-7
594 		0x1a,0x1b,0x0b			//8-a
595 	};
596 	Bit8u mode_control,color_select;
597 	switch (machine) {
598 	case MCH_HERC:
599 		IO_WriteB(0x3b8,0x28);	// TEXT mode and blinking characters
600 
601 		Herc_Palette();
602 		VGA_DAC_CombineColor(0,0);
603 		VGA_DAC_CombineColor(1,7);
604 
605 		real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x29); // attribute controls blinking
606 		break;
607 	case MCH_CGA:
608 		mode_control=mode_control_list[CurMode->mode];
609 		if (CurMode->mode == 0x6) color_select=0x3f;
610 		else color_select=0x30;
611 		IO_WriteB(0x3d8,mode_control);
612 		IO_WriteB(0x3d9,color_select);
613 		real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,mode_control);
614 		real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL,color_select);
615 		break;
616 	case MCH_TANDY:
617 		/* Init some registers */
618 		IO_WriteB(0x3da,0x1);IO_WriteB(0x3de,0xf);		//Palette mask always 0xf
619 		IO_WriteB(0x3da,0x2);IO_WriteB(0x3de,0x0);		//black border
620 		IO_WriteB(0x3da,0x3);							//Tandy color overrides?
621 		switch (CurMode->mode) {
622 		case 0x8:
623 			IO_WriteB(0x3de,0x14);break;
624 		case 0x9:
625 			IO_WriteB(0x3de,0x14);break;
626 		case 0xa:
627 			IO_WriteB(0x3de,0x0c);break;
628 		default:
629 			IO_WriteB(0x3de,0x0);break;
630 		}
631 		// write palette
632 		for(Bitu i = 0; i < 16; i++) {
633 			IO_WriteB(0x3da,i+0x10);
634 			IO_WriteB(0x3de,i);
635 		}
636 		//Clear extended mapping
637 		IO_WriteB(0x3da,0x5);
638 		IO_WriteB(0x3de,0x0);
639 		//Clear monitor mode
640 		IO_WriteB(0x3da,0x8);
641 		IO_WriteB(0x3de,0x0);
642 		crtpage=(CurMode->mode>=0x9) ? 0xf6 : 0x3f;
643 		IO_WriteB(0x3df,crtpage);
644 		real_writeb(BIOSMEM_SEG,BIOSMEM_CRTCPU_PAGE,crtpage);
645 		mode_control=mode_control_list[CurMode->mode];
646 		if (CurMode->mode == 0x6 || CurMode->mode==0xa) color_select=0x3f;
647 		else color_select=0x30;
648 		IO_WriteB(0x3d8,mode_control);
649 		IO_WriteB(0x3d9,color_select);
650 		real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,mode_control);
651 		real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL,color_select);
652 		break;
653 	case MCH_PCJR:
654 		/* Init some registers */
655 		IO_ReadB(0x3da);
656 		IO_WriteB(0x3da,0x1);IO_WriteB(0x3da,0xf);		//Palette mask always 0xf
657 		IO_WriteB(0x3da,0x2);IO_WriteB(0x3da,0x0);		//black border
658 		IO_WriteB(0x3da,0x3);
659 		if (CurMode->mode<=0x04) IO_WriteB(0x3da,0x02);
660 		else if (CurMode->mode==0x06) IO_WriteB(0x3da,0x08);
661 		else IO_WriteB(0x3da,0x00);
662 
663 		/* set CRT/Processor page register */
664 		if (CurMode->mode<0x04) crtpage=0x3f;
665 		else if (CurMode->mode>=0x09) crtpage=0xf6;
666 		else crtpage=0x7f;
667 		IO_WriteB(0x3df,crtpage);
668 		real_writeb(BIOSMEM_SEG,BIOSMEM_CRTCPU_PAGE,crtpage);
669 
670 		mode_control=mode_control_list_pcjr[CurMode->mode];
671 		IO_WriteB(0x3da,0x0);IO_WriteB(0x3da,mode_control);
672 		real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,mode_control);
673 
674 		if (CurMode->mode == 0x6 || CurMode->mode==0xa) color_select=0x3f;
675 		else color_select=0x30;
676 		real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL,color_select);
677 		INT10_SetColorSelect(1);
678 		INT10_SetBackgroundBorder(0);
679 		break;
680 	}
681 
682 	RealPt vparams = RealGetVec(0x1d);
683 	if ((vparams != RealMake(0xf000,0xf0a4)) && (mode < 8)) {
684 		// load crtc parameters from video params table
685 		Bit16u crtc_block_index = 0;
686 		if (mode < 2) crtc_block_index = 0;
687 		else if (mode < 4) crtc_block_index = 1;
688 		else if (mode < 7) crtc_block_index = 2;
689 		else if (mode == 7) crtc_block_index = 3; // MDA mono mode; invalid for others
690 		else if (mode < 9) crtc_block_index = 2;
691 		else crtc_block_index = 3; // Tandy/PCjr modes
692 
693 		// init CRTC registers
694 		for (Bit16u i = 0; i < 16; i++)
695 			IO_WriteW(crtc_base, i | (real_readb(RealSeg(vparams),
696 				RealOff(vparams) + i + crtc_block_index*16) << 8));
697 	}
698 	FinishSetMode(clearmem);
699 	return true;
700 }
701 
702 
INT10_SetVideoMode(Bit16u mode)703 bool INT10_SetVideoMode(Bit16u mode) {
704 	bool clearmem=true;Bitu i;
705 	if (mode>=0x100) {
706 		if ((mode & 0x4000) && int10.vesa_nolfb) return false;
707 		if (mode & 0x8000) clearmem=false;
708 		mode&=0xfff;
709 	}
710 	if ((mode<0x100) && (mode & 0x80)) {
711 		clearmem=false;
712 		mode-=0x80;
713 	}
714 	int10.vesa_setmode=0xffff;
715 	LOG(LOG_INT10,LOG_NORMAL)("Set Video Mode %X",mode);
716 	if (!IS_EGAVGA_ARCH) return INT10_SetVideoMode_OTHER(mode,clearmem);
717 
718 	/* First read mode setup settings from bios area */
719 //	Bit8u video_ctl=real_readb(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL);
720 //	Bit8u vga_switches=real_readb(BIOSMEM_SEG,BIOSMEM_SWITCHES);
721 	Bit8u modeset_ctl=real_readb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL);
722 
723 	if (IS_VGA_ARCH) {
724 		if (svga.accepts_mode) {
725 			if (!svga.accepts_mode(mode)) return false;
726 		}
727 
728 		switch(svgaCard) {
729 		case SVGA_TsengET4K:
730 		case SVGA_TsengET3K:
731 			if (!SetCurMode(ModeList_VGA_Tseng,mode)){
732 				LOG(LOG_INT10,LOG_ERROR)("VGA:Trying to set illegal mode %X",mode);
733 				return false;
734 			}
735 			break;
736 		case SVGA_ParadisePVGA1A:
737 			if (!SetCurMode(ModeList_VGA_Paradise,mode)){
738 				LOG(LOG_INT10,LOG_ERROR)("VGA:Trying to set illegal mode %X",mode);
739 				return false;
740 			}
741 			break;
742 		default:
743 			if (!SetCurMode(ModeList_VGA,mode)){
744 				LOG(LOG_INT10,LOG_ERROR)("VGA:Trying to set illegal mode %X",mode);
745 				return false;
746 			}
747 		}
748 		if (CurMode->type==M_TEXT) SetTextLines();
749 	} else {
750 		if (!SetCurMode(ModeList_EGA,mode)){
751 			LOG(LOG_INT10,LOG_ERROR)("EGA:Trying to set illegal mode %X",mode);
752 			return false;
753 		}
754 	}
755 
756 	/* Setup the VGA to the correct mode */
757 
758 	Bit16u crtc_base;
759 	bool mono_mode=(mode == 7) || (mode==0xf);
760 	if (mono_mode) crtc_base=0x3b4;
761 	else crtc_base=0x3d4;
762 
763 	if (IS_VGA_ARCH && (svgaCard == SVGA_S3Trio)) {
764 		// Disable MMIO here so we can read / write memory
765 		IO_Write(crtc_base,0x53);
766 		IO_Write(crtc_base+1,0x0);
767 	}
768 
769 	/* Setup MISC Output Register */
770 	Bit8u misc_output=0x2 | (mono_mode ? 0x0 : 0x1);
771 
772 	if ((CurMode->type==M_TEXT) && (CurMode->cwidth==9)) {
773 		// 28MHz (16MHz EGA) clock for 9-pixel wide chars
774 		misc_output|=0x4;
775 	}
776 
777 	switch (CurMode->vdispend) {
778 	case 400:
779 		misc_output|=0x60;
780 		break;
781 	case 480:
782 		misc_output|=0xe0;
783 		break;
784 	case 350:
785 		misc_output|=0xa0;
786 		break;
787 	default:
788 		misc_output|=0x60;
789 	}
790 	IO_Write(0x3c2,misc_output);		//Setup for 3b4 or 3d4
791 
792 	/* Program Sequencer */
793 	Bit8u seq_data[SEQ_REGS];
794 	memset(seq_data,0,SEQ_REGS);
795 	seq_data[1]|=0x01;	//8 dot fonts by default
796 	if (CurMode->special & _EGA_HALF_CLOCK) seq_data[1]|=0x08; //Check for half clock
797 	if ((machine==MCH_EGA) && (CurMode->special & _EGA_HALF_CLOCK)) seq_data[1]|=0x02;
798 	seq_data[4]|=0x02;	//More than 64kb
799 	switch (CurMode->type) {
800 	case M_TEXT:
801 		if (CurMode->cwidth==9) seq_data[1] &= ~1;
802 		seq_data[2]|=0x3;				//Enable plane 0 and 1
803 		seq_data[4]|=0x01;				//Alpanumeric
804 		if (IS_VGA_ARCH) seq_data[4]|=0x04;				//odd/even enabled
805 		break;
806 	case M_CGA2:
807 		seq_data[2]|=0xf;				//Enable plane 0
808 		if (machine==MCH_EGA) seq_data[4]|=0x04;		//odd/even enabled
809 		break;
810 	case M_CGA4:
811 		if (machine==MCH_EGA) seq_data[2]|=0x03;		//Enable plane 0 and 1
812 		break;
813 	case M_LIN4:
814 	case M_EGA:
815 		seq_data[2]|=0xf;				//Enable all planes for writing
816 		if (machine==MCH_EGA) seq_data[4]|=0x04;		//odd/even enabled
817 		break;
818 	case M_LIN8:						//Seems to have the same reg layout from testing
819 	case M_LIN15:
820 	case M_LIN16:
821 	case M_LIN32:
822 	case M_VGA:
823 		seq_data[2]|=0xf;				//Enable all planes for writing
824 		seq_data[4]|=0xc;				//Graphics - odd/even - Chained
825 		break;
826 	}
827 	for (Bit8u ct=0;ct<SEQ_REGS;ct++) {
828 		IO_Write(0x3c4,ct);
829 		IO_Write(0x3c5,seq_data[ct]);
830 	}
831 	vga.config.compatible_chain4 = true; // this may be changed by SVGA chipset emulation
832 
833 	/* Program CRTC */
834 	/* First disable write protection */
835 	IO_Write(crtc_base,0x11);
836 	IO_Write(crtc_base+1,IO_Read(crtc_base+1)&0x7f);
837 	/* Clear all the regs */
838 	for (Bit8u ct=0x0;ct<=0x18;ct++) {
839 		IO_Write(crtc_base,ct);IO_Write(crtc_base+1,0);
840 	}
841 	Bit8u overflow=0;Bit8u max_scanline=0;
842 	Bit8u ver_overflow=0;Bit8u hor_overflow=0;
843 	/* Horizontal Total */
844 	IO_Write(crtc_base,0x00);IO_Write(crtc_base+1,(Bit8u)(CurMode->htotal-5));
845 	hor_overflow|=((CurMode->htotal-5) & 0x100) >> 8;
846 	/* Horizontal Display End */
847 	IO_Write(crtc_base,0x01);IO_Write(crtc_base+1,(Bit8u)(CurMode->hdispend-1));
848 	hor_overflow|=((CurMode->hdispend-1) & 0x100) >> 7;
849 	/* Start horizontal Blanking */
850 	IO_Write(crtc_base,0x02);IO_Write(crtc_base+1,(Bit8u)CurMode->hdispend);
851 	hor_overflow|=((CurMode->hdispend) & 0x100) >> 6;
852 	/* End horizontal Blanking */
853 	Bitu blank_end=(CurMode->htotal-2) & 0x7f;
854 	IO_Write(crtc_base,0x03);IO_Write(crtc_base+1,0x80|(blank_end & 0x1f));
855 
856 	/* Start Horizontal Retrace */
857 	Bitu ret_start;
858 	if ((CurMode->special & _EGA_HALF_CLOCK) && (CurMode->type!=M_CGA2)) ret_start = (CurMode->hdispend+3);
859 	else if (CurMode->type==M_TEXT) ret_start = (CurMode->hdispend+5);
860 	else ret_start = (CurMode->hdispend+4);
861 	IO_Write(crtc_base,0x04);IO_Write(crtc_base+1,(Bit8u)ret_start);
862 	hor_overflow|=(ret_start & 0x100) >> 4;
863 
864 	/* End Horizontal Retrace */
865 	Bitu ret_end;
866 	if (CurMode->special & _EGA_HALF_CLOCK) {
867 		if (CurMode->type==M_CGA2) ret_end=0;	// mode 6
868 		else if (CurMode->special & _EGA_LINE_DOUBLE) ret_end = (CurMode->htotal-18) & 0x1f;
869 		else ret_end = ((CurMode->htotal-18) & 0x1f) | 0x20; // mode 0&1 have 1 char sync delay
870 	} else if (CurMode->type==M_TEXT) ret_end = (CurMode->htotal-3) & 0x1f;
871 	else ret_end = (CurMode->htotal-4) & 0x1f;
872 
873 	IO_Write(crtc_base,0x05);IO_Write(crtc_base+1,(Bit8u)(ret_end | (blank_end & 0x20) << 2));
874 
875 	/* Vertical Total */
876 	IO_Write(crtc_base,0x06);IO_Write(crtc_base+1,(Bit8u)(CurMode->vtotal-2));
877 	overflow|=((CurMode->vtotal-2) & 0x100) >> 8;
878 	overflow|=((CurMode->vtotal-2) & 0x200) >> 4;
879 	ver_overflow|=((CurMode->vtotal-2) & 0x400) >> 10;
880 
881 	Bitu vretrace;
882 	if (IS_VGA_ARCH) {
883 		switch (CurMode->vdispend) {
884 		case 400: vretrace=CurMode->vdispend+12;
885 				break;
886 		case 480: vretrace=CurMode->vdispend+10;
887 				break;
888 		case 350: vretrace=CurMode->vdispend+37;
889 				break;
890 		default: vretrace=CurMode->vdispend+12;
891 		}
892 	} else {
893 		switch (CurMode->vdispend) {
894 		case 350: vretrace=CurMode->vdispend;
895 				break;
896 		default: vretrace=CurMode->vdispend+24;
897 		}
898 	}
899 
900 	/* Vertical Retrace Start */
901 	IO_Write(crtc_base,0x10);IO_Write(crtc_base+1,(Bit8u)vretrace);
902 	overflow|=(vretrace & 0x100) >> 6;
903 	overflow|=(vretrace & 0x200) >> 2;
904 	ver_overflow|=(vretrace & 0x400) >> 6;
905 
906 	/* Vertical Retrace End */
907 	IO_Write(crtc_base,0x11);IO_Write(crtc_base+1,(vretrace+2) & 0xF);
908 
909 	/* Vertical Display End */
910 	IO_Write(crtc_base,0x12);IO_Write(crtc_base+1,(Bit8u)(CurMode->vdispend-1));
911 	overflow|=((CurMode->vdispend-1) & 0x100) >> 7;
912 	overflow|=((CurMode->vdispend-1) & 0x200) >> 3;
913 	ver_overflow|=((CurMode->vdispend-1) & 0x400) >> 9;
914 
915 	Bitu vblank_trim;
916 	if (IS_VGA_ARCH) {
917 		switch (CurMode->vdispend) {
918 		case 400: vblank_trim=6;
919 				break;
920 		case 480: vblank_trim=7;
921 				break;
922 		case 350: vblank_trim=5;
923 				break;
924 		default: vblank_trim=8;
925 		}
926 	} else {
927 		switch (CurMode->vdispend) {
928 		case 350: vblank_trim=0;
929 				break;
930 		default: vblank_trim=23;
931 		}
932 	}
933 
934 	/* Vertical Blank Start */
935 	IO_Write(crtc_base,0x15);IO_Write(crtc_base+1,(Bit8u)(CurMode->vdispend+vblank_trim));
936 	overflow|=((CurMode->vdispend+vblank_trim) & 0x100) >> 5;
937 	max_scanline|=((CurMode->vdispend+vblank_trim) & 0x200) >> 4;
938 	ver_overflow|=((CurMode->vdispend+vblank_trim) & 0x400) >> 8;
939 
940 	/* Vertical Blank End */
941 	IO_Write(crtc_base,0x16);IO_Write(crtc_base+1,(Bit8u)(CurMode->vtotal-vblank_trim-2));
942 
943 	/* Line Compare */
944 	Bitu line_compare=(CurMode->vtotal < 1024) ? 1023 : 2047;
945 	IO_Write(crtc_base,0x18);IO_Write(crtc_base+1,line_compare&0xff);
946 	overflow|=(line_compare & 0x100) >> 4;
947 	max_scanline|=(line_compare & 0x200) >> 3;
948 	ver_overflow|=(line_compare & 0x400) >> 4;
949 	Bit8u underline=0;
950 	/* Maximum scanline / Underline Location */
951 	if (CurMode->special & _EGA_LINE_DOUBLE) {
952 		if (machine!=MCH_EGA) max_scanline|=0x80;
953 	}
954 	switch (CurMode->type) {
955 	case M_TEXT:
956 		max_scanline|=CurMode->cheight-1;
957 		underline=mono_mode ? CurMode->cheight-1 : 0x1f; // mode 7 uses underline position
958 		break;
959 	case M_VGA:
960 		underline=0x40;
961 		max_scanline|=1;		//Vga doesn't use double line but this
962 		break;
963 	case M_LIN8:
964 	case M_LIN15:
965 	case M_LIN16:
966 	case M_LIN32:
967 		underline=0x60;			//Seems to enable the every 4th clock on my s3
968 		break;
969 	case M_CGA2:
970 	case M_CGA4:
971 		max_scanline|=1;
972 		break;
973 	default:
974 		if (CurMode->vdispend==350) underline=0x0f;
975 		break;
976 	}
977 
978 	IO_Write(crtc_base,0x09);IO_Write(crtc_base+1,max_scanline);
979 	IO_Write(crtc_base,0x14);IO_Write(crtc_base+1,underline);
980 
981 	/* OverFlow */
982 	IO_Write(crtc_base,0x07);IO_Write(crtc_base+1,overflow);
983 
984 	if (svgaCard == SVGA_S3Trio) {
985 		/* Extended Horizontal Overflow */
986 		IO_Write(crtc_base,0x5d);IO_Write(crtc_base+1,hor_overflow);
987 		/* Extended Vertical Overflow */
988 		IO_Write(crtc_base,0x5e);IO_Write(crtc_base+1,ver_overflow);
989 	}
990 
991 	/* Offset Register */
992 	Bitu offset;
993 	switch (CurMode->type) {
994 	case M_LIN8:
995 		offset = CurMode->swidth/8;
996 		break;
997 	case M_LIN15:
998 	case M_LIN16:
999 		offset = 2 * CurMode->swidth/8;
1000 		break;
1001 	case M_LIN32:
1002 		offset = 4 * CurMode->swidth/8;
1003 		break;
1004 	default:
1005 		offset = CurMode->hdispend/2;
1006 	}
1007 	IO_Write(crtc_base,0x13);
1008 	IO_Write(crtc_base + 1,offset & 0xff);
1009 
1010 	if (svgaCard == SVGA_S3Trio) {
1011 		/* Extended System Control 2 Register  */
1012 		/* This register actually has more bits but only use the extended offset ones */
1013 		IO_Write(crtc_base,0x51);
1014 		IO_Write(crtc_base + 1,(Bit8u)((offset & 0x300) >> 4));
1015 		/* Clear remaining bits of the display start */
1016 		IO_Write(crtc_base,0x69);
1017 		IO_Write(crtc_base + 1,0);
1018 		/* Extended Vertical Overflow */
1019 		IO_Write(crtc_base,0x5e);IO_Write(crtc_base+1,ver_overflow);
1020 	}
1021 
1022 	/* Mode Control */
1023 	Bit8u mode_control=0;
1024 
1025 	switch (CurMode->type) {
1026 	case M_CGA2:
1027 		mode_control=0xc2; // 0x06 sets address wrap.
1028 		break;
1029 	case M_CGA4:
1030 		mode_control=0xa2;
1031 		break;
1032 	case M_LIN4:
1033 	case M_EGA:
1034 		if (CurMode->mode==0x11) // 0x11 also sets address wrap.  thought maybe all 2 color modes did but 0x0f doesn't.
1035 			mode_control=0xc3; // so.. 0x11 or 0x0f a one off?
1036 		else {
1037 			if (machine==MCH_EGA) {
1038 				if (CurMode->special & _EGA_LINE_DOUBLE) mode_control=0xc3;
1039 				else mode_control=0x8b;
1040 			} else {
1041 				mode_control=0xe3;
1042 			}
1043 		}
1044 		break;
1045 	case M_TEXT:
1046 	case M_VGA:
1047 	case M_LIN8:
1048 	case M_LIN15:
1049 	case M_LIN16:
1050 	case M_LIN32:
1051 		mode_control=0xa3;
1052 		if (CurMode->special & _VGA_PIXEL_DOUBLE)
1053 			mode_control |= 0x08;
1054 		break;
1055 	}
1056 
1057 	IO_Write(crtc_base,0x17);IO_Write(crtc_base+1,mode_control);
1058 	/* Renable write protection */
1059 	IO_Write(crtc_base,0x11);
1060 	IO_Write(crtc_base+1,IO_Read(crtc_base+1)|0x80);
1061 
1062 	if (svgaCard == SVGA_S3Trio) {
1063 		/* Setup the correct clock */
1064 		if (CurMode->mode>=0x100) {
1065 			if (CurMode->vdispend>480)
1066 				misc_output|=0xc0;	//480-line sync
1067 			misc_output|=0x0c;		//Select clock 3
1068 			Bitu clock=CurMode->vtotal*8*CurMode->htotal*70;
1069 			VGA_SetClock(3,clock/1000);
1070 		}
1071 		Bit8u misc_control_2;
1072 		/* Setup Pixel format */
1073 		switch (CurMode->type) {
1074 		case M_LIN8:
1075 			misc_control_2=0x00;
1076 			break;
1077 		case M_LIN15:
1078 			misc_control_2=0x30;
1079 			break;
1080 		case M_LIN16:
1081 			misc_control_2=0x50;
1082 			break;
1083 		case M_LIN32:
1084 			misc_control_2=0xd0;
1085 			break;
1086 		default:
1087 			misc_control_2=0x0;
1088 			break;
1089 		}
1090 		IO_WriteB(crtc_base,0x67);IO_WriteB(crtc_base+1,misc_control_2);
1091 	}
1092 
1093 	/* Write Misc Output */
1094 	IO_Write(0x3c2,misc_output);
1095 	/* Program Graphics controller */
1096 	Bit8u gfx_data[GFX_REGS];
1097 	memset(gfx_data,0,GFX_REGS);
1098 	gfx_data[0x7]=0xf;				/* Color don't care */
1099 	gfx_data[0x8]=0xff;				/* BitMask */
1100 	switch (CurMode->type) {
1101 	case M_TEXT:
1102 		gfx_data[0x5]|=0x10;		//Odd-Even Mode
1103 		gfx_data[0x6]|=mono_mode ? 0x0a : 0x0e;		//Either b800 or b000
1104 		break;
1105 	case M_LIN8:
1106 	case M_LIN15:
1107 	case M_LIN16:
1108 	case M_LIN32:
1109 	case M_VGA:
1110 		gfx_data[0x5]|=0x40;		//256 color mode
1111 		gfx_data[0x6]|=0x05;		//graphics mode at 0xa000-affff
1112 		break;
1113 	case M_LIN4:
1114 	case M_EGA:
1115 		if (CurMode->mode == 0x0f)
1116 			gfx_data[0x7]=0x05;		// only planes 0 and 2 are used
1117 		gfx_data[0x6]|=0x05;		//graphics mode at 0xa000-affff
1118 		break;
1119 	case M_CGA4:
1120 		gfx_data[0x5]|=0x20;		//CGA mode
1121 		gfx_data[0x6]|=0x0f;		//graphics mode at at 0xb800=0xbfff
1122 		if (machine==MCH_EGA) gfx_data[0x5]|=0x10;
1123 		break;
1124 	case M_CGA2:
1125 		if (machine==MCH_EGA) {
1126 			gfx_data[0x6]|=0x0d;		//graphics mode at at 0xb800=0xbfff
1127 		} else {
1128 			gfx_data[0x6]|=0x0f;		//graphics mode at at 0xb800=0xbfff
1129 		}
1130 		break;
1131 	}
1132 	for (Bit8u ct=0;ct<GFX_REGS;ct++) {
1133 		IO_Write(0x3ce,ct);
1134 		IO_Write(0x3cf,gfx_data[ct]);
1135 	}
1136 	Bit8u att_data[ATT_REGS];
1137 	memset(att_data,0,ATT_REGS);
1138 	att_data[0x12]=0xf;				//Always have all color planes enabled
1139 	/* Program Attribute Controller */
1140 	switch (CurMode->type) {
1141 	case M_EGA:
1142 	case M_LIN4:
1143 		att_data[0x10]=0x01;		//Color Graphics
1144 		switch (CurMode->mode) {
1145 		case 0x0f:
1146 			att_data[0x12]=0x05;	// planes 0 and 2 enabled
1147 			att_data[0x10]|=0x0a;	// monochrome and blinking
1148 
1149 			att_data[0x01]=0x08; // low-intensity
1150 			att_data[0x04]=0x18; // blink-on case
1151 			att_data[0x05]=0x18; // high-intensity
1152 			att_data[0x09]=0x08; // low-intensity in blink-off case
1153 			att_data[0x0d]=0x18; // high-intensity in blink-off
1154 			break;
1155 		case 0x11:
1156 			for (i=1;i<16;i++) att_data[i]=0x3f;
1157 			break;
1158 		case 0x10:
1159 		case 0x12:
1160 			goto att_text16;
1161 		default:
1162 			if ( CurMode->type == M_LIN4 )
1163 				goto att_text16;
1164 			for (Bit8u ct=0;ct<8;ct++) {
1165 				att_data[ct]=ct;
1166 				att_data[ct+8]=ct+0x10;
1167 			}
1168 			break;
1169 		}
1170 		break;
1171 	case M_TANDY16:
1172 		att_data[0x10]=0x01;		//Color Graphics
1173 		for (Bit8u ct=0;ct<16;ct++) att_data[ct]=ct;
1174 		break;
1175 	case M_TEXT:
1176 		if (CurMode->cwidth==9) {
1177 			att_data[0x13]=0x08;	//Pel panning on 8, although we don't have 9 dot text mode
1178 			att_data[0x10]=0x0C;	//Color Text with blinking, 9 Bit characters
1179 		} else {
1180 			att_data[0x13]=0x00;
1181 			att_data[0x10]=0x08;	//Color Text with blinking, 8 Bit characters
1182 		}
1183 		real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL,0x30);
1184 att_text16:
1185 		if (CurMode->mode==7) {
1186 			att_data[0]=0x00;
1187 			att_data[8]=0x10;
1188 			for (i=1; i<8; i++) {
1189 				att_data[i]=0x08;
1190 				att_data[i+8]=0x18;
1191 			}
1192 		} else {
1193 			for (Bit8u ct=0;ct<8;ct++) {
1194 				att_data[ct]=ct;
1195 				att_data[ct+8]=ct+0x38;
1196 			}
1197 			if (IS_VGA_ARCH) att_data[0x06]=0x14;		//Odd Color 6 yellow/brown.
1198 		}
1199 		break;
1200 	case M_CGA2:
1201 		att_data[0x10]=0x01;		//Color Graphics
1202 		att_data[0]=0x0;
1203 		for (i=1;i<0x10;i++) att_data[i]=0x17;
1204 		att_data[0x12]=0x1;			//Only enable 1 plane
1205 		real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL,0x3f);
1206 		break;
1207 	case M_CGA4:
1208 		att_data[0x10]=0x01;		//Color Graphics
1209 		att_data[0]=0x0;
1210 		att_data[1]=0x13;
1211 		att_data[2]=0x15;
1212 		att_data[3]=0x17;
1213 		att_data[4]=0x02;
1214 		att_data[5]=0x04;
1215 		att_data[6]=0x06;
1216 		att_data[7]=0x07;
1217 		for (Bit8u ct=0x8;ct<0x10;ct++)
1218 			att_data[ct] = ct + 0x8;
1219 		real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL,0x30);
1220 		break;
1221 	case M_VGA:
1222 	case M_LIN8:
1223 	case M_LIN15:
1224 	case M_LIN16:
1225 	case M_LIN32:
1226 		for (Bit8u ct=0;ct<16;ct++) att_data[ct]=ct;
1227 		att_data[0x10]=0x41;		//Color Graphics 8-bit
1228 		break;
1229 	}
1230 	IO_Read(mono_mode ? 0x3ba : 0x3da);
1231 	if ((modeset_ctl & 8)==0) {
1232 		for (Bit8u ct=0;ct<ATT_REGS;ct++) {
1233 			IO_Write(0x3c0,ct);
1234 			IO_Write(0x3c0,att_data[ct]);
1235 		}
1236 		vga.config.pel_panning = 0;
1237 		IO_Write(0x3c0,0x20); IO_Write(0x3c0,0x00); //Disable palette access
1238 		IO_Write(0x3c6,0xff); //Reset Pelmask
1239 		/* Setup the DAC */
1240 		IO_Write(0x3c8,0);
1241 		switch (CurMode->type) {
1242 		case M_EGA:
1243 			if (CurMode->mode>0xf) {
1244 				goto dac_text16;
1245 			} else if (CurMode->mode==0xf) {
1246 				for (i=0;i<64;i++) {
1247 					IO_Write(0x3c9,mtext_s3_palette[i][0]);
1248 					IO_Write(0x3c9,mtext_s3_palette[i][1]);
1249 					IO_Write(0x3c9,mtext_s3_palette[i][2]);
1250 				}
1251 			} else {
1252 				for (i=0;i<64;i++) {
1253 					IO_Write(0x3c9,ega_palette[i][0]);
1254 					IO_Write(0x3c9,ega_palette[i][1]);
1255 					IO_Write(0x3c9,ega_palette[i][2]);
1256 				}
1257 			}
1258 			break;
1259 		case M_CGA2:
1260 		case M_CGA4:
1261 		case M_TANDY16:
1262 			for (i=0;i<64;i++) {
1263 				IO_Write(0x3c9,cga_palette_2[i][0]);
1264 				IO_Write(0x3c9,cga_palette_2[i][1]);
1265 				IO_Write(0x3c9,cga_palette_2[i][2]);
1266 			}
1267 			break;
1268 		case M_TEXT:
1269 			if (CurMode->mode==7) {
1270 				if ((IS_VGA_ARCH) && (svgaCard == SVGA_S3Trio)) {
1271 					for (i=0;i<64;i++) {
1272 						IO_Write(0x3c9,mtext_s3_palette[i][0]);
1273 						IO_Write(0x3c9,mtext_s3_palette[i][1]);
1274 						IO_Write(0x3c9,mtext_s3_palette[i][2]);
1275 					}
1276 				} else {
1277 					for (i=0;i<64;i++) {
1278 						IO_Write(0x3c9,mtext_palette[i][0]);
1279 						IO_Write(0x3c9,mtext_palette[i][1]);
1280 						IO_Write(0x3c9,mtext_palette[i][2]);
1281 					}
1282 				}
1283 				break;
1284 			} //FALLTHROUGH!!!!
1285 		case M_LIN4: //Added for CAD Software
1286 dac_text16:
1287 			for (i=0;i<64;i++) {
1288 				IO_Write(0x3c9,text_palette[i][0]);
1289 				IO_Write(0x3c9,text_palette[i][1]);
1290 				IO_Write(0x3c9,text_palette[i][2]);
1291 			}
1292 			break;
1293 		case M_VGA:
1294 		case M_LIN8:
1295 		case M_LIN15:
1296 		case M_LIN16:
1297 		case M_LIN32:
1298 			// IBM and clones use 248 default colors in the palette for 256-color mode.
1299 			// The last 8 colors of the palette are only initialized to 0 at BIOS init.
1300 			// Palette index is left at 0xf8 as on most clones, IBM leaves it at 0x10.
1301 			for (i=0;i<248;i++) {
1302 				IO_Write(0x3c9,vga_palette[i][0]);
1303 				IO_Write(0x3c9,vga_palette[i][1]);
1304 				IO_Write(0x3c9,vga_palette[i][2]);
1305 			}
1306 			break;
1307 		}
1308 		if (IS_VGA_ARCH) {
1309 			/* check if gray scale summing is enabled */
1310 			if (real_readb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL) & 2) {
1311 				INT10_PerformGrayScaleSumming(0,256);
1312 			}
1313 		}
1314 	} else {
1315 		for (Bit8u ct=0x10;ct<ATT_REGS;ct++) {
1316 			if (ct==0x11) continue;	// skip overscan register
1317 			IO_Write(0x3c0,ct);
1318 			IO_Write(0x3c0,att_data[ct]);
1319 		}
1320 		vga.config.pel_panning = 0;
1321 		IO_Write(0x3c0,0x20); //Disable palette access
1322 	}
1323 	/* Write palette register data to dynamic save area if pointer is non-zero */
1324 	RealPt vsavept=real_readd(BIOSMEM_SEG,BIOSMEM_VS_POINTER);
1325 	RealPt dsapt=real_readd(RealSeg(vsavept),RealOff(vsavept)+4);
1326 	if (dsapt) {
1327 		for (Bit8u ct=0;ct<0x10;ct++) {
1328 			real_writeb(RealSeg(dsapt),RealOff(dsapt)+ct,att_data[ct]);
1329 		}
1330 		real_writeb(RealSeg(dsapt),RealOff(dsapt)+0x10,0); // overscan
1331 	}
1332 	/* Setup some special stuff for different modes */
1333 	Bit8u feature=real_readb(BIOSMEM_SEG,BIOSMEM_INITIAL_MODE);
1334 	switch (CurMode->type) {
1335 	case M_CGA2:
1336 		feature=(feature&~0x30)|0x20;
1337 		real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x1e);
1338 		break;
1339 	case M_CGA4:
1340 		feature=(feature&~0x30)|0x20;
1341 		if (CurMode->mode==4) real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x2a);
1342 		else if (CurMode->mode==5) real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x2e);
1343 		else real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x2);
1344 		break;
1345 	case M_TANDY16:
1346 		feature=(feature&~0x30)|0x20;
1347 		break;
1348 	case M_TEXT:
1349 		feature=(feature&~0x30)|0x20;
1350 		switch (CurMode->mode) {
1351 		case 0:real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x2c);break;
1352 		case 1:real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x28);break;
1353 		case 2:real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x2d);break;
1354 		case 3:
1355 		case 7:real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x29);break;
1356 		}
1357 		break;
1358 	case M_LIN4:
1359 	case M_EGA:
1360 	case M_VGA:
1361 		feature=(feature&~0x30);
1362 		break;
1363 	}
1364 	// disabled, has to be set in bios.cpp exclusively
1365 //	real_writeb(BIOSMEM_SEG,BIOSMEM_INITIAL_MODE,feature);
1366 
1367 	if (svgaCard == SVGA_S3Trio) {
1368 		/* Setup the CPU Window */
1369 		IO_Write(crtc_base,0x6a);
1370 		IO_Write(crtc_base+1,0);
1371 		/* Setup the linear frame buffer */
1372 		IO_Write(crtc_base,0x59);
1373 		IO_Write(crtc_base+1,(Bit8u)((S3_LFB_BASE >> 24)&0xff));
1374 		IO_Write(crtc_base,0x5a);
1375 		IO_Write(crtc_base+1,(Bit8u)((S3_LFB_BASE >> 16)&0xff));
1376 		IO_Write(crtc_base,0x6b); // BIOS scratchpad
1377 		IO_Write(crtc_base+1,(Bit8u)((S3_LFB_BASE >> 24)&0xff));
1378 
1379 		/* Setup some remaining S3 registers */
1380 		IO_Write(crtc_base,0x41); // BIOS scratchpad
1381 		IO_Write(crtc_base+1,0x88);
1382 		IO_Write(crtc_base,0x52); // extended BIOS scratchpad
1383 		IO_Write(crtc_base+1,0x80);
1384 
1385 		IO_Write(0x3c4,0x15);
1386 		IO_Write(0x3c5,0x03);
1387 
1388 		// Accellerator setup
1389 		Bitu reg_50=S3_XGA_8BPP;
1390 		switch (CurMode->type) {
1391 			case M_LIN15:
1392 			case M_LIN16: reg_50|=S3_XGA_16BPP; break;
1393 			case M_LIN32: reg_50|=S3_XGA_32BPP; break;
1394 			default: break;
1395 		}
1396 		switch(CurMode->swidth) {
1397 			case 640:  reg_50|=S3_XGA_640; break;
1398 			case 800:  reg_50|=S3_XGA_800; break;
1399 			case 1024: reg_50|=S3_XGA_1024; break;
1400 			case 1152: reg_50|=S3_XGA_1152; break;
1401 			case 1280: reg_50|=S3_XGA_1280; break;
1402 			default: break;
1403 		}
1404 		IO_WriteB(crtc_base,0x50); IO_WriteB(crtc_base+1,reg_50);
1405 
1406 		Bit8u reg_31, reg_3a;
1407 		switch (CurMode->type) {
1408 			case M_LIN15:
1409 			case M_LIN16:
1410 			case M_LIN32:
1411 				reg_3a=0x15;
1412 				break;
1413 			case M_LIN8:
1414 				// S3VBE20 does it this way. The other double pixel bit does not
1415 				// seem to have an effect on the Trio64.
1416 				if(CurMode->special&_VGA_PIXEL_DOUBLE) reg_3a=0x5;
1417 				else reg_3a=0x15;
1418 				break;
1419 			default:
1420 				reg_3a=5;
1421 				break;
1422 		};
1423 
1424 		switch (CurMode->type) {
1425 		case M_LIN4: // <- Theres a discrepance with real hardware on this
1426 		case M_LIN8:
1427 		case M_LIN15:
1428 		case M_LIN16:
1429 		case M_LIN32:
1430 			reg_31 = 9;
1431 			break;
1432 		default:
1433 			reg_31 = 5;
1434 			break;
1435 		}
1436 		IO_Write(crtc_base,0x3a);IO_Write(crtc_base+1,reg_3a);
1437 		IO_Write(crtc_base,0x31);IO_Write(crtc_base+1,reg_31);	//Enable banked memory and 256k+ access
1438 		IO_Write(crtc_base,0x58);IO_Write(crtc_base+1,0x3);		//Enable 8 mb of linear addressing
1439 
1440 		IO_Write(crtc_base,0x38);IO_Write(crtc_base+1,0x48);	//Register lock 1
1441 		IO_Write(crtc_base,0x39);IO_Write(crtc_base+1,0xa5);	//Register lock 2
1442 	} else if (svga.set_video_mode) {
1443 		VGA_ModeExtraData modeData;
1444 		modeData.ver_overflow = ver_overflow;
1445 		modeData.hor_overflow = hor_overflow;
1446 		modeData.offset = offset;
1447 		modeData.modeNo = CurMode->mode;
1448 		modeData.htotal = CurMode->htotal;
1449 		modeData.vtotal = CurMode->vtotal;
1450 		svga.set_video_mode(crtc_base, &modeData);
1451 	}
1452 
1453 	FinishSetMode(clearmem);
1454 
1455 	/* Set vga attrib register into defined state */
1456 	IO_Read(mono_mode ? 0x3ba : 0x3da);
1457 	IO_Write(0x3c0,0x20);
1458 
1459 	/* Load text mode font */
1460 	if (CurMode->type==M_TEXT) {
1461 		INT10_ReloadFont();
1462 	}
1463 	return true;
1464 }
1465 
VideoModeMemSize(Bitu mode)1466 Bitu VideoModeMemSize(Bitu mode) {
1467 	if (!IS_VGA_ARCH)
1468 		return 0;
1469 
1470 	VideoModeBlock* modelist = NULL;
1471 
1472 	switch (svgaCard) {
1473 	case SVGA_TsengET4K:
1474 	case SVGA_TsengET3K:
1475 		modelist = ModeList_VGA_Tseng;
1476 		break;
1477 	case SVGA_ParadisePVGA1A:
1478 		modelist = ModeList_VGA_Paradise;
1479 		break;
1480 	default:
1481 		modelist = ModeList_VGA;
1482 		break;
1483 	}
1484 
1485 	VideoModeBlock* vmodeBlock = NULL;
1486 	Bitu i=0;
1487 	while (modelist[i].mode!=0xffff) {
1488 		if (modelist[i].mode==mode) {
1489 			vmodeBlock = &modelist[i];
1490 			break;
1491 		}
1492 		i++;
1493 	}
1494 	if (!vmodeBlock)
1495         return 0;
1496 
1497 	switch(vmodeBlock->type) {
1498 	case M_LIN4:
1499 		return vmodeBlock->swidth*vmodeBlock->sheight/2;
1500 	case M_LIN8:
1501 		return vmodeBlock->swidth*vmodeBlock->sheight;
1502 	case M_LIN15: case M_LIN16:
1503 		return vmodeBlock->swidth*vmodeBlock->sheight*2;
1504 	case M_LIN32:
1505 		return vmodeBlock->swidth*vmodeBlock->sheight*4;
1506 	case M_TEXT:
1507 		return vmodeBlock->twidth*vmodeBlock->theight*2;
1508 	}
1509 	// Return 0 for all other types, those always fit in memory
1510 	return 0;
1511 }
1512