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 #include "dosbox.h" 00020 #include "inout.h" 00021 #include "render.h" 00022 #include "vga.h" 00023 00024 extern bool vga_enable_3C6_ramdac; 00025 extern bool vga_8bit_dac; 00026 00027 /* 00028 3C6h (R/W): PEL Mask 00029 bit 0-7 This register is anded with the palette index sent for each dot. 00030 Should be set to FFh. 00031 00032 3C7h (R): DAC State Register 00033 bit 0-1 0 indicates the DAC is in Write Mode and 3 indicates Read mode. 00034 00035 3C7h (W): PEL Address Read Mode 00036 bit 0-7 The PEL data register (0..255) to be read from 3C9h. 00037 Note: After reading the 3 bytes at 3C9h this register will increment, 00038 pointing to the next data register. 00039 00040 3C8h (R/W): PEL Address Write Mode 00041 bit 0-7 The PEL data register (0..255) to be written to 3C9h. 00042 Note: After writing the 3 bytes at 3C9h this register will increment, pointing 00043 to the next data register. 00044 00045 3C9h (R/W): PEL Data Register 00046 bit 0-5 Color value 00047 Note: Each read or write of this register will cycle through first the 00048 registers for Red, Blue and Green, then increment the appropriate 00049 address register, thus the entire palette can be loaded by writing 0 to 00050 the PEL Address Write Mode register 3C8h and then writing all 768 bytes 00051 of the palette to this register. 00052 */ 00053 00054 enum {DAC_READ,DAC_WRITE}; 00055 00056 static void VGA_DAC_SendColor( Bitu index, Bitu src ) { 00057 const Bit8u dacshift = vga_8bit_dac ? 0u : 2u; 00058 const Bit8u red = vga.dac.rgb[src].red << dacshift; 00059 const Bit8u green = vga.dac.rgb[src].green << dacshift; 00060 const Bit8u blue = vga.dac.rgb[src].blue << dacshift; 00061 00062 /* FIXME: CGA composite mode calls RENDER_SetPal itself, which conflicts with this code */ 00063 if (vga.mode == M_CGA16) 00064 return; 00065 00066 /* FIXME: Can someone behind the GCC project explain how (unsigned int) OR (unsigned int) somehow becomes (signed int)?? */ 00067 00068 if (GFX_bpp >= 24) /* FIXME: Assumes 8:8:8. What happens when desktops start using the 10:10:10 format? */ 00069 vga.dac.xlat32[index] = 00070 (uint32_t)((blue&0xffu) << (GFX_Bshift)) | 00071 (uint32_t)((green&0xffu) << (GFX_Gshift)) | 00072 (uint32_t)((red&0xffu) << (GFX_Rshift)) | 00073 (uint32_t)GFX_Amask; 00074 else { 00075 /* FIXME: Assumes 5:6:5. I need to test against 5:5:5 format sometime. Perhaps I could dig out some older VGA cards and XFree86 drivers that support that format? */ 00076 vga.dac.xlat16[index] = 00077 (uint16_t)(((blue&0xffu)>>3u)<<GFX_Bshift) | 00078 (uint16_t)(((green&0xffu)>>2u)<<GFX_Gshift) | 00079 (uint16_t)(((red&0xffu)>>3u)<<GFX_Rshift) | 00080 (uint16_t)GFX_Amask; 00081 00082 /* PC-98 mode always renders 32bpp, therefore needs this fix */ 00083 if (GFX_Bshift == 0) 00084 vga.dac.xlat32[index] = (uint32_t)(blue << 0U) | (uint32_t)(green << 8U) | (uint32_t)(red << 16U); 00085 else 00086 vga.dac.xlat32[index] = (uint32_t)(blue << 16U) | (uint32_t)(green << 8U) | (uint32_t)(red << 0U); 00087 } 00088 00089 RENDER_SetPal( (Bit8u)index, red, green, blue ); 00090 } 00091 00092 void VGA_DAC_UpdateColor( Bitu index ) { 00093 Bitu maskIndex; 00094 00095 if (IS_VGA_ARCH) { 00096 if (vga.mode == M_VGA || vga.mode == M_LIN8) { 00097 /* WARNING: This code assumes index < 256 */ 00098 switch (VGA_AC_remap) { 00099 case AC_4x4: 00100 default: // <- just in case 00101 /* Standard VGA hardware (including the original IBM PS/2 hardware) */ 00102 maskIndex = vga.dac.combine[index&0xF] & 0x0F; 00103 maskIndex += (vga.dac.combine[index>>4u] & 0x0F) << 4u; 00104 maskIndex &= vga.dac.pel_mask; 00105 break; 00106 case AC_low4: 00107 /* Tseng ET4000 behavior, according to the SVGA card I have where only the low 4 bits are translated. --J.C. */ 00108 maskIndex = vga.dac.combine[index&0xF] & 0x0F; 00109 00110 if (vga.attr.mode_control & 0x80u) 00111 maskIndex += Bitu(vga.attr.color_select << 4u); 00112 else 00113 maskIndex += index & 0xF0u; 00114 00115 maskIndex &= vga.dac.pel_mask; 00116 break; 00117 } 00118 } 00119 else { 00120 maskIndex = vga.dac.combine[index&0xF] & vga.dac.pel_mask; 00121 } 00122 00123 VGA_DAC_SendColor( index, maskIndex ); 00124 } 00125 else if (machine == MCH_MCGA) { 00126 if (vga.mode == M_VGA || vga.mode == M_LIN8) 00127 maskIndex = index & vga.dac.pel_mask; 00128 else 00129 maskIndex = vga.dac.combine[index&0xF] & vga.dac.pel_mask; 00130 00131 VGA_DAC_SendColor( index, maskIndex ); 00132 } 00133 else { 00134 VGA_DAC_SendColor( index, index ); 00135 } 00136 } 00137 00138 void VGA_DAC_UpdateColorPalette() { 00139 for ( Bitu i = 0;i<256;i++) 00140 VGA_DAC_UpdateColor( i ); 00141 } 00142 00143 void write_p3c6(Bitu port,Bitu val,Bitu iolen) { 00144 (void)iolen;//UNUSED 00145 (void)port;//UNUSED 00146 if((IS_VGA_ARCH) && (vga.dac.hidac_counter>3)) { 00147 vga.dac.reg02=(Bit8u)val; 00148 vga.dac.hidac_counter=0; 00149 VGA_StartResize(); 00150 return; 00151 } 00152 if ( vga.dac.pel_mask != val ) { 00153 LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:DCA:Pel Mask set to %X", (int)val); 00154 vga.dac.pel_mask = (Bit8u)val; 00155 00156 // TODO: MCGA 640x480 2-color mode appears to latch the DAC at retrace 00157 // for background/foreground. Does that apply to the PEL mask too? 00158 00159 VGA_DAC_UpdateColorPalette(); 00160 } 00161 } 00162 00163 00164 Bitu read_p3c6(Bitu port,Bitu iolen) { 00165 (void)iolen;//UNUSED 00166 (void)port;//UNUSED 00167 if (vga_enable_3C6_ramdac) 00168 vga.dac.hidac_counter++; 00169 00170 return vga.dac.pel_mask; 00171 } 00172 00173 00174 void write_p3c7(Bitu port,Bitu val,Bitu iolen) { 00175 (void)iolen;//UNUSED 00176 (void)port;//UNUSED 00177 vga.dac.hidac_counter=0; 00178 vga.dac.pel_index=0; 00179 vga.dac.state=DAC_READ; 00180 vga.dac.read_index=(Bit8u)val; /* NTS: Paradise SVGA behavior, read index = x, write index = x + 1 */ 00181 vga.dac.write_index=(Bit8u)(val + 1); 00182 } 00183 00184 Bitu read_p3c7(Bitu port,Bitu iolen) { 00185 (void)iolen;//UNUSED 00186 (void)port;//UNUSED 00187 vga.dac.hidac_counter=0; 00188 if (vga.dac.state==DAC_READ) return 0x3; 00189 else return 0x0; 00190 } 00191 00192 void write_p3c8(Bitu port,Bitu val,Bitu iolen) { 00193 (void)iolen;//UNUSED 00194 (void)port;//UNUSED 00195 vga.dac.hidac_counter=0; 00196 vga.dac.pel_index=0; 00197 vga.dac.state=DAC_WRITE; 00198 vga.dac.write_index=(Bit8u)val; /* NTS: Paradise SVGA behavior, this affects write index, but not read index */ 00199 if (svgaCard != SVGA_ParadisePVGA1A) 00200 vga.dac.read_index = (Bit8u)(val - 1); 00201 } 00202 00203 Bitu read_p3c8(Bitu port, Bitu iolen){ 00204 (void)iolen;//UNUSED 00205 (void)port;//UNUSED 00206 vga.dac.hidac_counter=0; 00207 return vga.dac.write_index; 00208 } 00209 00210 extern bool enable_vga_8bit_dac; 00211 extern bool vga_palette_update_on_full_load; 00212 00213 static unsigned char tmp_dac[3] = {0,0,0}; 00214 00215 void write_p3c9(Bitu port,Bitu val,Bitu iolen) { 00216 bool update = false; 00217 00218 (void)iolen;//UNUSED 00219 (void)port;//UNUSED 00220 vga.dac.hidac_counter=0; 00221 00222 // allow the full 8 bit ONLY if 8-bit DAC emulation is enabled AND 8-bit DAC mode is on. 00223 // masking to 6 bits is REQUIRED for some games like "Amulets and Armor", where apparently 00224 // the use of signed char with palette values can cause "overbright" effects if it can 00225 // read back the full 8 bits. 00226 if (!vga_8bit_dac) 00227 val&=0x3f; 00228 00229 if (vga.dac.pel_index < 3) { 00230 tmp_dac[vga.dac.pel_index]=(unsigned char)val; 00231 00232 if (!vga_palette_update_on_full_load) { 00233 /* update palette right away, partial change */ 00234 switch (vga.dac.pel_index) { 00235 case 0: 00236 vga.dac.rgb[vga.dac.write_index].red=tmp_dac[0]; 00237 break; 00238 case 1: 00239 vga.dac.rgb[vga.dac.write_index].green=tmp_dac[1]; 00240 break; 00241 case 2: 00242 vga.dac.rgb[vga.dac.write_index].blue=tmp_dac[2]; 00243 break; 00244 } 00245 update = true; 00246 } 00247 else if (vga.dac.pel_index == 2) { 00248 /* update palette ONLY when all three are given */ 00249 vga.dac.rgb[vga.dac.write_index].red=tmp_dac[0]; 00250 vga.dac.rgb[vga.dac.write_index].green=tmp_dac[1]; 00251 vga.dac.rgb[vga.dac.write_index].blue=tmp_dac[2]; 00252 update = true; 00253 } 00254 00255 if ((++vga.dac.pel_index) >= 3) 00256 vga.dac.pel_index = 0; 00257 } 00258 00259 if (update) { 00260 // As seen on real hardware: 640x480 2-color is the ONLY video mode 00261 // where the MCGA hardware appears to latch foreground and background 00262 // colors from the DAC at retrace, instead of always reading through 00263 // the DAC. 00264 // 00265 // Perhaps IBM couldn't get the DAC to run fast enough for 640x480 2-color mode. 00266 if (machine == MCH_MCGA && (vga.other.mcga_mode_control & 2)) { 00267 /* do not update the palette right now. 00268 * MCGA double-buffers foreground and background colors */ 00269 } 00270 else { 00271 VGA_DAC_UpdateColorPalette(); // FIXME: Yes, this is very inefficient. Will improve later. 00272 } 00273 00274 /* only if we just completed a color should we advance */ 00275 if (vga.dac.pel_index == 0) 00276 vga.dac.read_index = vga.dac.write_index++; // NTS: Paradise SVGA behavior 00277 } 00278 } 00279 00280 Bitu read_p3c9(Bitu port,Bitu iolen) { 00281 (void)iolen;//UNUSED 00282 (void)port;//UNUSED 00283 vga.dac.hidac_counter=0; 00284 Bit8u ret; 00285 switch (vga.dac.pel_index) { 00286 case 0: 00287 ret=vga.dac.rgb[vga.dac.read_index].red; 00288 vga.dac.pel_index=1; 00289 break; 00290 case 1: 00291 ret=vga.dac.rgb[vga.dac.read_index].green; 00292 vga.dac.pel_index=2; 00293 break; 00294 case 2: 00295 ret=vga.dac.rgb[vga.dac.read_index].blue; 00296 vga.dac.pel_index=0; 00297 vga.dac.read_index=vga.dac.write_index++; // NTS: Paradise SVGA behavior 00298 break; 00299 default: 00300 LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:DAC:Illegal Pel Index"); //If this can actually happen that will be the day 00301 ret=0; 00302 break; 00303 } 00304 return ret; 00305 } 00306 00307 void VGA_DAC_CombineColor(Bit8u attr,Bit8u pal) { 00308 vga.dac.combine[attr] = pal; 00309 00310 if (IS_VGA_ARCH) { 00311 if (vga.mode == M_VGA || vga.mode == M_LIN8) { 00312 switch (VGA_AC_remap) { 00313 case AC_4x4: 00314 default: // <- just in case 00315 /* Standard VGA hardware (including the original IBM PS/2 hardware) */ 00316 for (unsigned int i=(unsigned int)attr;i < 0x100;i += 0x10) 00317 VGA_DAC_UpdateColor( i ); 00318 for (unsigned int i=0;i < 0x10;i++) 00319 VGA_DAC_UpdateColor( i + ((unsigned int)attr<<4u) ); 00320 break; 00321 case AC_low4: 00322 /* Tseng ET4000 behavior, according to the SVGA card I have where only the low 4 bits are translated. --J.C. */ 00323 for (unsigned int i=(unsigned int)attr;i < 0x100;i += 0x10) 00324 VGA_DAC_UpdateColor( i ); 00325 break; 00326 } 00327 } 00328 else { 00329 for (unsigned int i=(unsigned int)attr;i < 0x100;i += 0x10) 00330 VGA_DAC_UpdateColor( i ); 00331 } 00332 } 00333 else if (machine == MCH_MCGA) { 00334 VGA_DAC_UpdateColor( attr ); 00335 } 00336 else { 00337 VGA_DAC_SendColor( attr, pal ); 00338 } 00339 } 00340 00341 void VGA_DAC_SetEntry(Bitu entry,Bit8u red,Bit8u green,Bit8u blue) { 00342 //Should only be called in machine != vga 00343 vga.dac.rgb[entry].red=red; 00344 vga.dac.rgb[entry].green=green; 00345 vga.dac.rgb[entry].blue=blue; 00346 for (Bitu i=0;i<16;i++) 00347 if (vga.dac.combine[i]==entry) 00348 VGA_DAC_SendColor( i, i ); 00349 } 00350 00351 void VGA_SetupDAC(void) { 00352 vga.dac.first_changed=256; 00353 vga.dac.bits=6; 00354 vga.dac.pel_mask=0xff; 00355 vga.dac.pel_index=0; 00356 vga.dac.state=DAC_READ; 00357 vga.dac.read_index=0; 00358 vga.dac.write_index=0; 00359 vga.dac.hidac_counter=0; 00360 vga.dac.reg02=0; 00361 if (IS_VGA_ARCH || machine == MCH_MCGA) { 00362 /* Setup the DAC IO port Handlers */ 00363 if (svga.setup_dac) { 00364 svga.setup_dac(); 00365 } else { 00366 IO_RegisterWriteHandler(0x3c6,write_p3c6,IO_MB); 00367 IO_RegisterReadHandler(0x3c6,read_p3c6,IO_MB); 00368 IO_RegisterWriteHandler(0x3c7,write_p3c7,IO_MB); 00369 IO_RegisterReadHandler(0x3c7,read_p3c7,IO_MB); 00370 IO_RegisterWriteHandler(0x3c8,write_p3c8,IO_MB); 00371 IO_RegisterReadHandler(0x3c8,read_p3c8,IO_MB); 00372 IO_RegisterWriteHandler(0x3c9,write_p3c9,IO_MB); 00373 IO_RegisterReadHandler(0x3c9,read_p3c9,IO_MB); 00374 } 00375 } 00376 } 00377 00378 void VGA_UnsetupDAC(void) { 00379 IO_FreeWriteHandler(0x3c6,IO_MB); 00380 IO_FreeReadHandler(0x3c6,IO_MB); 00381 IO_FreeWriteHandler(0x3c7,IO_MB); 00382 IO_FreeReadHandler(0x3c7,IO_MB); 00383 IO_FreeWriteHandler(0x3c8,IO_MB); 00384 IO_FreeReadHandler(0x3c8,IO_MB); 00385 IO_FreeWriteHandler(0x3c9,IO_MB); 00386 IO_FreeReadHandler(0x3c9,IO_MB); 00387 } 00388 00389 // save state support 00390 void POD_Save_VGA_Dac( std::ostream& stream ) 00391 { 00392 // - pure struct data 00393 WRITE_POD( &vga.dac, vga.dac ); 00394 00395 00396 // no static globals found 00397 } 00398 00399 00400 void POD_Load_VGA_Dac( std::istream& stream ) 00401 { 00402 // - pure struct data 00403 READ_POD( &vga.dac, vga.dac ); 00404 00405 00406 // no static globals found 00407 }