DOSBox-X
|
00001 /* 00002 * Copyright (C) 2002-2020 The DOSBox Team 00003 * 00004 * This program is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation; either version 2 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License along 00015 * with this program; if not, write to the Free Software Foundation, Inc., 00016 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 */ 00018 00019 00020 #include "dosbox.h" 00021 #include "inout.h" 00022 #include "vga.h" 00023 00024 #define attr(blah) vga.attr.blah 00025 00026 void VGA_ATTR_SetEGAMonitorPalette(EGAMonitorMode m) { 00027 // palette bit assignment: 00028 // bit | pin | EGA | CGA | monochrome 00029 // ----+-----+------------+-----------+------------ 00030 // 0 | 5 | blue | blue | nc 00031 // 1 | 4 | green | green* | nc 00032 // 2 | 3 | red | red* | nc 00033 // 3 | 7 | blue sec. | nc | video 00034 // 4 | 6 | green sec. | intensity | intensity 00035 // 5 | 2 | red sec. | nc | nc 00036 // 6-7 | not used 00037 // * additive color brown instead of yellow 00038 switch(m) { 00039 case CGA: 00040 //LOG_MSG("Monitor CGA"); 00041 for (Bitu i=0;i<64;i++) { 00042 vga.dac.rgb[i].red=((i & 0x4)? 0x2a:0) + ((i & 0x10)? 0x15:0); 00043 vga.dac.rgb[i].blue=((i & 0x1)? 0x2a:0) + ((i & 0x10)? 0x15:0); 00044 00045 // replace yellow with brown 00046 if ((i & 0x17) == 0x6) vga.dac.rgb[i].green = 0x15; 00047 else vga.dac.rgb[i].green = 00048 ((i & 0x2)? 0x2a:0) + ((i & 0x10)? 0x15:0); 00049 } 00050 break; 00051 case EGA: 00052 //LOG_MSG("Monitor EGA"); 00053 for (Bitu i=0;i<64;i++) { 00054 vga.dac.rgb[i].red=((i & 0x4)? 0x2a:0) + ((i & 0x20)? 0x15:0); 00055 vga.dac.rgb[i].green=((i & 0x2)? 0x2a:0) + ((i & 0x10)? 0x15:0); 00056 vga.dac.rgb[i].blue=((i & 0x1)? 0x2a:0) + ((i & 0x8)? 0x15:0); 00057 } 00058 break; 00059 case MONO: 00060 //LOG_MSG("Monitor MONO"); 00061 for (Bitu i=0;i<64;i++) { 00062 Bit8u value = ((i & 0x8)? 0x2a:0) + ((i & 0x10)? 0x15:0); 00063 vga.dac.rgb[i].red = vga.dac.rgb[i].green = 00064 vga.dac.rgb[i].blue = value; 00065 } 00066 break; 00067 } 00068 00069 // update the mappings 00070 for (Bit8u i=0;i<0x10;i++) 00071 VGA_ATTR_SetPalette(i,vga.attr.palette[i]); 00072 } 00073 00074 void VGA_ATTR_SetPalette(Bit8u index, Bit8u val) { 00075 // the attribute table stores only 6 bits 00076 val &= 63; 00077 vga.attr.palette[index] = val; 00078 00079 if (IS_VGA_ARCH) { 00080 // apply the plane mask 00081 val = vga.attr.palette[index & vga.attr.color_plane_enable]; 00082 00083 // Tseng ET4000AX behavior (according to how COPPER.EXE treats the hardware) 00084 // and according to real hardware: 00085 // 00086 // - If P54S (palette select bits 5-4) are enabled, replace bits 7-4 of the 00087 // color index with the entire color select register. COPPER.EXE line fading 00088 // tricks will not work correctly otherwise. 00089 // 00090 // - If P54S is not enabled, then do not apply any Color Select register bits. 00091 // This is contrary to standard VGA behavior that would always apply Color 00092 // Select bits 3-2 to index bits 7-6 in any mode other than 256-color mode. 00093 if (VGA_AC_remap == AC_low4) { 00094 if (vga.attr.mode_control & 0x80) 00095 val = (val&0xf) | (vga.attr.color_select << 4); 00096 } 00097 // normal VGA/SVGA behavior: 00098 // 00099 // - ignore color select in 256-color mode entirely 00100 // 00101 // - otherwise, if P54S is enabled, replace bits 5-4 with bits 1-0 of color select. 00102 // 00103 // - always replace bits 7-6 with bits 3-2 of color select. 00104 else { 00105 if (!(vga.mode == M_VGA || vga.mode == M_LIN8)) { 00106 // replace bits 5-4 if P54S is enabled 00107 if (vga.attr.mode_control & 0x80) 00108 val = (val&0xf) | ((vga.attr.color_select & 0x3) << 4); 00109 00110 // always replace bits 7-6 00111 val |= (vga.attr.color_select & 0xc) << 4; 00112 } 00113 } 00114 00115 // apply 00116 VGA_DAC_CombineColor(index,val); 00117 } 00118 else { 00119 VGA_DAC_CombineColor(index,index); 00120 } 00121 } 00122 00123 Bitu read_p3c0(Bitu /*port*/,Bitu /*iolen*/) { 00124 // Wcharts, Win 3.11 & 95 SVGA 00125 Bitu retval = attr(index) & 0x1f; 00126 if (!(attr(disabled) & 0x1)) retval |= 0x20; 00127 return retval; 00128 } 00129 00130 void write_p3c0(Bitu /*port*/,Bitu val,Bitu iolen) { 00131 if (!vga.internal.attrindex) { 00132 attr(index)=val & 0x1F; 00133 vga.internal.attrindex=true; 00134 if (val & 0x20) attr(disabled) &= ~1; 00135 else attr(disabled) |= 1; 00136 /* 00137 0-4 Address of data register to write to port 3C0h or read from port 3C1h 00138 5 If set screen output is enabled and the palette can not be modified, 00139 if clear screen output is disabled and the palette can be modified. 00140 */ 00141 /* NOTES: Paradise/Western Digital SVGA appears to respond to 0x00-0x0F as 00142 * expected, but 0x10-0x17 have an alias at 0x18-0x1F according to 00143 * DOSLIB TMODESET.EXE dumps. 00144 * 00145 * Original IBM PS/2 VGA hardware acts the same. 00146 * 00147 * if (val & 0x10) 00148 * index = val & 0x17; 00149 * else 00150 * index = val & 0x0F; 00151 */ 00152 return; 00153 } else { 00154 vga.internal.attrindex=false; 00155 switch (attr(index)) { 00156 /* Palette */ 00157 case 0x00: case 0x01: case 0x02: case 0x03: 00158 case 0x04: case 0x05: case 0x06: case 0x07: 00159 case 0x08: case 0x09: case 0x0a: case 0x0b: 00160 case 0x0c: case 0x0d: case 0x0e: case 0x0f: 00161 if (attr(disabled) & 0x1) { 00162 VGA_ATTR_SetPalette(attr(index),(Bit8u)val); 00163 00164 /* if the color plane enable register is anything other than 0x0F, then 00165 * the whole attribute palette must be re-sent to the DAC because the 00166 * masking causes one entry to affect others due to the way the VGA 00167 * lookup table works (array xlat32[]). This is not necessary for EGA 00168 * emulation because it uses the color plane enable mask directly. */ 00169 if (IS_VGA_ARCH && (attr(color_plane_enable) & 0x0F) != 0x0F) { 00170 /* update entries before the desired index */ 00171 for (Bit8u i=0;i < attr(index);i++) 00172 VGA_ATTR_SetPalette(i,vga.attr.palette[i]); 00173 00174 /* update entries after the desired index */ 00175 for (Bit8u i=attr(index)+1;i < 0x10;i++) 00176 VGA_ATTR_SetPalette(i,vga.attr.palette[i]); 00177 } 00178 } 00179 /* 00180 0-5 Index into the 256 color DAC table. May be modified by 3C0h index 00181 10h and 14h. 00182 */ 00183 break; 00184 case 0x10: { /* Mode Control Register */ 00185 if (!IS_VGA_ARCH) val&=0x1f; // not really correct, but should do it 00186 Bitu difference = attr(mode_control)^val; 00187 attr(mode_control)=(Bit8u)val; 00188 00189 if (difference & 0x80) { 00190 for (Bit8u i=0;i<0x10;i++) 00191 VGA_ATTR_SetPalette(i,vga.attr.palette[i]); 00192 } 00193 if (difference & 0x08) 00194 VGA_SetBlinking(val & 0x8); 00195 00196 if (difference & 0x41) 00197 VGA_DetermineMode(); 00198 if ((difference & 0x40) && (vga.mode == M_VGA)) // 8BIT changes in 256-color mode must be handled 00199 VGA_StartResize(50); 00200 00201 if (difference & 0x04) { 00202 // recompute the panning value 00203 if(vga.mode==M_TEXT) { 00204 Bit8u pan_reg = attr(horizontal_pel_panning); 00205 if (pan_reg > 7) 00206 vga.config.pel_panning=0; 00207 else if (val&0x4) // 9-dot wide characters 00208 vga.config.pel_panning=(Bit8u)(pan_reg+1); 00209 else // 8-dot characters 00210 vga.config.pel_panning=(Bit8u)pan_reg; 00211 } 00212 } 00213 /* 00214 0 Graphics mode if set, Alphanumeric mode else. 00215 1 Monochrome mode if set, color mode else. 00216 2 9-bit wide characters if set. 00217 The 9th bit of characters C0h-DFh will be the same as 00218 the 8th bit. Otherwise it will be the background color. 00219 3 If set Attribute bit 7 is blinking, else high intensity. 00220 5 If set the PEL panning register (3C0h index 13h) is temporarily set 00221 to 0 from when the line compare causes a wrap around until the next 00222 vertical retrace when the register is automatically reloaded with 00223 the old value, else the PEL panning register ignores line compares. 00224 6 If set pixels are 8 bits wide. Used in 256 color modes. 00225 7 If set bit 4-5 of the index into the DAC table are taken from port 00226 3C0h index 14h bit 0-1, else the bits in the palette register are 00227 used. 00228 */ 00229 break; 00230 } 00231 case 0x11: /* Overscan Color Register */ 00232 attr(overscan_color)=(Bit8u)val; 00233 /* 0-5 Color of screen border. Color is defined as in the palette registers. */ 00234 break; 00235 case 0x12: /* Color Plane Enable Register */ 00236 /* Why disable colour planes? */ 00237 /* To support weird modes. */ 00238 if ((attr(color_plane_enable)^val) & 0xf) { 00239 // in case the plane enable bits change... 00240 attr(color_plane_enable)=(Bit8u)val; 00241 for (Bit8u i=0;i<0x10;i++) 00242 VGA_ATTR_SetPalette(i,vga.attr.palette[i]); 00243 } else 00244 attr(color_plane_enable)=(Bit8u)val; 00245 /* 00246 0 Bit plane 0 is enabled if set. 00247 1 Bit plane 1 is enabled if set. 00248 2 Bit plane 2 is enabled if set. 00249 3 Bit plane 3 is enabled if set. 00250 4-5 Video Status MUX. Diagnostics use only. 00251 Two attribute bits appear on bits 4 and 5 of the Input Status 00252 Register 1 (3dAh). 0: Bit 2/0, 1: Bit 5/4, 2: bit 3/1, 3: bit 7/6 00253 */ 00254 break; 00255 case 0x13: /* Horizontal PEL Panning Register */ 00256 attr(horizontal_pel_panning)=val & 0xF; 00257 switch (vga.mode) { 00258 case M_TEXT: 00259 if (val > 7) 00260 vga.config.pel_panning=0; 00261 else if (vga.attr.mode_control&0x4) // 9-dot wide characters 00262 vga.config.pel_panning=(Bit8u)(val+1); 00263 else // 8-dot characters 00264 vga.config.pel_panning=(Bit8u)val; 00265 break; 00266 case M_VGA: 00267 case M_LIN8: 00268 vga.config.pel_panning=(val & 0x7)/2; 00269 break; 00270 case M_LIN16: 00271 default: 00272 vga.config.pel_panning=(val & 0x7); 00273 } 00274 if (machine==MCH_EGA) 00275 // On the EGA panning can be programmed for every scanline: 00276 vga.draw.panning = vga.config.pel_panning; 00277 /* 00278 0-3 Indicates number of pixels to shift the display left 00279 Value 9bit textmode 256color mode Other modes 00280 0 1 0 0 00281 1 2 n/a 1 00282 2 3 1 2 00283 3 4 n/a 3 00284 4 5 2 4 00285 5 6 n/a 5 00286 6 7 3 6 00287 7 8 n/a 7 00288 8 0 n/a n/a 00289 */ 00290 break; 00291 case 0x14: /* Color Select Register */ 00292 if (!IS_VGA_ARCH) { 00293 attr(color_select)=0; 00294 break; 00295 } 00296 if (attr(color_select) ^ val) { 00297 attr(color_select)=(Bit8u)val; 00298 for (Bit8u i=0;i<0x10;i++) 00299 VGA_ATTR_SetPalette(i,vga.attr.palette[i]); 00300 } 00301 /* 00302 0-1 If 3C0h index 10h bit 7 is set these 2 bits are used as bits 4-5 of 00303 the index into the DAC table. 00304 2-3 These 2 bits are used as bit 6-7 of the index into the DAC table 00305 except in 256 color mode. 00306 Note: this register does not affect 256 color modes. 00307 */ 00308 break; 00309 default: 00310 if (svga.write_p3c0) { 00311 svga.write_p3c0(attr(index), val, iolen); 00312 break; 00313 } 00314 LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:ATTR:Write to unkown Index %2X",attr(index)); 00315 break; 00316 } 00317 } 00318 } 00319 00320 Bitu read_p3c1(Bitu /*port*/,Bitu iolen) { 00321 // vga.internal.attrindex=false; 00322 switch (attr(index)) { 00323 /* Palette */ 00324 case 0x00: case 0x01: case 0x02: case 0x03: 00325 case 0x04: case 0x05: case 0x06: case 0x07: 00326 case 0x08: case 0x09: case 0x0a: case 0x0b: 00327 case 0x0c: case 0x0d: case 0x0e: case 0x0f: 00328 return attr(palette[attr(index)]); 00329 case 0x10: /* Mode Control Register */ 00330 return attr(mode_control); 00331 case 0x11: /* Overscan Color Register */ 00332 return attr(overscan_color); 00333 case 0x12: /* Color Plane Enable Register */ 00334 return attr(color_plane_enable); 00335 case 0x13: /* Horizontal PEL Panning Register */ 00336 return attr(horizontal_pel_panning); 00337 case 0x14: /* Color Select Register */ 00338 return attr(color_select); 00339 default: 00340 if (svga.read_p3c1) 00341 return svga.read_p3c1(attr(index), iolen); 00342 LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:ATTR:Read from unkown Index %2X",attr(index)); 00343 } 00344 return 0; 00345 } 00346 00347 00348 void VGA_SetupAttr(void) { 00349 if (IS_EGAVGA_ARCH) { 00350 IO_RegisterWriteHandler(0x3c0,write_p3c0,IO_MB); 00351 if (IS_VGA_ARCH) { 00352 IO_RegisterReadHandler(0x3c0,read_p3c0,IO_MB); 00353 IO_RegisterReadHandler(0x3c1,read_p3c1,IO_MB); 00354 } 00355 } 00356 } 00357 00358 void VGA_UnsetupAttr(void) { 00359 IO_FreeWriteHandler(0x3c0,IO_MB); 00360 IO_FreeReadHandler(0x3c0,IO_MB); 00361 IO_FreeWriteHandler(0x3c1,IO_MB); 00362 IO_FreeReadHandler(0x3c1,IO_MB); 00363 } 00364 00365 // save state support 00366 void POD_Save_VGA_Attr( std::ostream& stream ) 00367 { 00368 // - pure struct data 00369 WRITE_POD( &vga.attr, vga.attr ); 00370 00371 00372 // no static globals found 00373 } 00374 00375 00376 void POD_Load_VGA_Attr( std::istream& stream ) 00377 { 00378 // - pure struct data 00379 READ_POD( &vga.attr, vga.attr ); 00380 00381 00382 // no static globals found 00383 }