DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/vga_dac.cpp
00001 /*
00002  *  Copyright (C) 2002-2015  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
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 
00026 /*
00027 3C6h (R/W):  PEL Mask
00028 bit 0-7  This register is anded with the palette index sent for each dot.
00029          Should be set to FFh.
00030 
00031 3C7h (R):  DAC State Register
00032 bit 0-1  0 indicates the DAC is in Write Mode and 3 indicates Read mode.
00033 
00034 3C7h (W):  PEL Address Read Mode
00035 bit 0-7  The PEL data register (0..255) to be read from 3C9h.
00036 Note: After reading the 3 bytes at 3C9h this register will increment,
00037       pointing to the next data register.
00038 
00039 3C8h (R/W):  PEL Address Write Mode
00040 bit 0-7  The PEL data register (0..255) to be written to 3C9h.
00041 Note: After writing the 3 bytes at 3C9h this register will increment, pointing
00042       to the next data register.
00043 
00044 3C9h (R/W):  PEL Data Register
00045 bit 0-5  Color value
00046 Note:  Each read or write of this register will cycle through first the
00047        registers for Red, Blue and Green, then increment the appropriate
00048        address register, thus the entire palette can be loaded by writing 0 to
00049        the PEL Address Write Mode register 3C8h and then writing all 768 bytes
00050        of the palette to this register.
00051 */
00052 
00053 enum {DAC_READ,DAC_WRITE};
00054 
00055 static void VGA_DAC_SendColor( Bitu index, Bitu src ) {
00056     /* NTS: Don't forget red/green/blue are 6-bit RGB not 8-bit RGB */
00057     const Bit8u red = vga.dac.rgb[src].red;
00058     const Bit8u green = vga.dac.rgb[src].green;
00059     const Bit8u blue = vga.dac.rgb[src].blue;
00060 
00061     /* FIXME: CGA composite mode calls RENDER_SetPal itself, which conflicts with this code */
00062     if (vga.mode == M_CGA16)
00063         return;
00064 
00065     /* FIXME: Can someone behind the GCC project explain how (unsigned int) OR (unsigned int) somehow becomes (signed int)?? */
00066 
00067     if (GFX_bpp >= 24) /* FIXME: Assumes 8:8:8. What happens when desktops start using the 10:10:10 format? */
00068         vga.dac.xlat32[index] =
00069             (uint32_t)(blue << (2u + GFX_Bshift)) |
00070             (uint32_t)(green << (2u + GFX_Gshift)) |
00071             (uint32_t)(red<<(2u + GFX_Rshift)) |
00072             (uint32_t)GFX_Amask;
00073     else {
00074         /* 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? */
00075         vga.dac.xlat16[index] =
00076             (uint16_t)(((blue&0x3fu)>>1u)<<GFX_Bshift) |
00077             (uint16_t)((green&0x3fu)<<GFX_Gshift) |
00078             (uint16_t)(((red&0x3fu)>>1u)<<GFX_Rshift) |
00079             (uint16_t)GFX_Amask;
00080 
00081         /* PC-98 mode always renders 32bpp, therefore needs this fix */
00082         if (GFX_Bshift == 0)
00083             vga.dac.xlat32[index] = (uint32_t)(blue << 2U) | (uint32_t)(green << 10U) | (uint32_t)(red << 18U);
00084         else
00085             vga.dac.xlat32[index] = (uint32_t)(blue << 18U) | (uint32_t)(green << 10U) | (uint32_t)(red << 2U);
00086     }
00087 
00088     RENDER_SetPal( index, (red << 2u) | ( red >> 4u ), (green << 2u) | ( green >> 4u ), (blue << 2u) | ( blue >> 4u ) );
00089 }
00090 
00091 void VGA_DAC_UpdateColor( Bitu index ) {
00092     Bitu maskIndex;
00093 
00094     if (IS_VGA_ARCH) {
00095         if (vga.mode == M_VGA || vga.mode == M_LIN8) {
00096             /* WARNING: This code assumes index < 256 */
00097             switch (VGA_AC_remap) {
00098                 case AC_4x4:
00099                 default: // <- just in case
00100                     /* Standard VGA hardware (including the original IBM PS/2 hardware) */
00101                     maskIndex  =  vga.dac.combine[index&0xF] & 0x0F;
00102                     maskIndex += (vga.dac.combine[index>>4u] & 0x0F) << 4u;
00103                     maskIndex &=  vga.dac.pel_mask;
00104                     break;
00105                 case AC_low4:
00106                     /* Tseng ET4000 behavior, according to the SVGA card I have where only the low 4 bits are translated. --J.C. */
00107                     maskIndex  =  vga.dac.combine[index&0xF] & 0x0F;
00108 
00109                     /* FIXME: TEST THIS ON THE ACTUAL ET4000. This seems to make COPPER.EXE work correctly.
00110                      *        Is this what actual ET4000 hardware does in 256-color mode with Color Select? */
00111                     if (vga.attr.mode_control & 0x80)
00112                         maskIndex += vga.attr.color_select << 4;
00113                     else
00114                         maskIndex += index & 0xF0;
00115 
00116                     maskIndex &=  vga.dac.pel_mask;
00117                     break;
00118             }
00119         }
00120         else {
00121             maskIndex = vga.dac.combine[index&0xF] & vga.dac.pel_mask;
00122         }
00123 
00124         VGA_DAC_SendColor( index, maskIndex );
00125     }
00126     else {
00127         VGA_DAC_SendColor( index, index );
00128     }
00129 }
00130 
00131 void VGA_DAC_UpdateColorPalette() {
00132     for ( Bitu i = 0;i<256;i++) 
00133         VGA_DAC_UpdateColor( i );
00134 }
00135 
00136 void write_p3c6(Bitu port,Bitu val,Bitu iolen) {
00137     (void)iolen;//UNUSED
00138     (void)port;//UNUSED
00139     if((IS_VGA_ARCH) && (vga.dac.hidac_counter>3)) {
00140         vga.dac.reg02=val;
00141         vga.dac.hidac_counter=0;
00142         VGA_StartResize();
00143         return;
00144     }
00145     if ( vga.dac.pel_mask != val ) {
00146         LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:DCA:Pel Mask set to %X", (int)val);
00147         vga.dac.pel_mask = val;
00148         VGA_DAC_UpdateColorPalette();
00149     }
00150 }
00151 
00152 
00153 Bitu read_p3c6(Bitu port,Bitu iolen) {
00154     (void)iolen;//UNUSED
00155     (void)port;//UNUSED
00156     if (vga_enable_3C6_ramdac)
00157         vga.dac.hidac_counter++;
00158 
00159     return vga.dac.pel_mask;
00160 }
00161 
00162 
00163 void write_p3c7(Bitu port,Bitu val,Bitu iolen) {
00164     (void)iolen;//UNUSED
00165     (void)port;//UNUSED
00166     vga.dac.hidac_counter=0;
00167     vga.dac.pel_index=0;
00168     vga.dac.state=DAC_READ;
00169     vga.dac.read_index=val;         /* NTS: Paradise SVGA behavior, read index = x, write index = x + 1 */
00170     vga.dac.write_index=val + 1;
00171 }
00172 
00173 Bitu read_p3c7(Bitu port,Bitu iolen) {
00174     (void)iolen;//UNUSED
00175     (void)port;//UNUSED
00176     vga.dac.hidac_counter=0;
00177     if (vga.dac.state==DAC_READ) return 0x3;
00178     else return 0x0;
00179 }
00180 
00181 void write_p3c8(Bitu port,Bitu val,Bitu iolen) {
00182     (void)iolen;//UNUSED
00183     (void)port;//UNUSED
00184     vga.dac.hidac_counter=0;
00185     vga.dac.pel_index=0;
00186     vga.dac.state=DAC_WRITE;
00187     vga.dac.write_index=val;        /* NTS: Paradise SVGA behavior, this affects write index, but not read index */
00188 }
00189 
00190 Bitu read_p3c8(Bitu port, Bitu iolen){
00191     (void)iolen;//UNUSED
00192     (void)port;//UNUSED
00193     vga.dac.hidac_counter=0;
00194     return vga.dac.write_index;
00195 }
00196 
00197 extern bool vga_palette_update_on_full_load;
00198 
00199 static unsigned char tmp_dac[3] = {0,0,0};
00200 
00201 void write_p3c9(Bitu port,Bitu val,Bitu iolen) {
00202     bool update = false;
00203 
00204     (void)iolen;//UNUSED
00205     (void)port;//UNUSED
00206     vga.dac.hidac_counter=0;
00207     val&=0x3f;
00208 
00209     if (vga.dac.pel_index < 3) {
00210         tmp_dac[vga.dac.pel_index]=val;
00211 
00212         if (!vga_palette_update_on_full_load) {
00213             /* update palette right away, partial change */
00214             switch (vga.dac.pel_index) {
00215                 case 0:
00216                     vga.dac.rgb[vga.dac.write_index].red=tmp_dac[0];
00217                     break;
00218                 case 1:
00219                     vga.dac.rgb[vga.dac.write_index].green=tmp_dac[1];
00220                     break;
00221                 case 2:
00222                     vga.dac.rgb[vga.dac.write_index].blue=tmp_dac[2];
00223                     break;
00224             }
00225             update = true;
00226         }
00227         else if (vga.dac.pel_index == 2) {
00228             /* update palette ONLY when all three are given */
00229             vga.dac.rgb[vga.dac.write_index].red=tmp_dac[0];
00230             vga.dac.rgb[vga.dac.write_index].green=tmp_dac[1];
00231             vga.dac.rgb[vga.dac.write_index].blue=tmp_dac[2];
00232             update = true;
00233         }
00234 
00235         if ((++vga.dac.pel_index) >= 3)
00236             vga.dac.pel_index = 0;
00237     }
00238 
00239     if (update) {
00240         VGA_DAC_UpdateColorPalette(); // FIXME: Yes, this is very inefficient. Will improve later.
00241 
00242         /* only if we just completed a color should we advance */
00243         if (vga.dac.pel_index == 0)
00244             vga.dac.read_index = vga.dac.write_index++;                           // NTS: Paradise SVGA behavior
00245     }
00246 }
00247 
00248 Bitu read_p3c9(Bitu port,Bitu iolen) {
00249     (void)iolen;//UNUSED
00250     (void)port;//UNUSED
00251     vga.dac.hidac_counter=0;
00252     Bit8u ret;
00253     switch (vga.dac.pel_index) {
00254     case 0:
00255         ret=vga.dac.rgb[vga.dac.read_index].red;
00256         vga.dac.pel_index=1;
00257         break;
00258     case 1:
00259         ret=vga.dac.rgb[vga.dac.read_index].green;
00260         vga.dac.pel_index=2;
00261         break;
00262     case 2:
00263         ret=vga.dac.rgb[vga.dac.read_index].blue;
00264         vga.dac.pel_index=0;
00265         vga.dac.read_index=vga.dac.write_index++;                           // NTS: Paradise SVGA behavior
00266         break;
00267     default:
00268         LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:DAC:Illegal Pel Index");           //If this can actually happen that will be the day
00269         ret=0;
00270         break;
00271     }
00272     return ret;
00273 }
00274 
00275 void VGA_DAC_CombineColor(Bit8u attr,Bit8u pal) {
00276     vga.dac.combine[attr] = pal;
00277 
00278     if (IS_VGA_ARCH) {
00279         if (vga.mode == M_VGA || vga.mode == M_LIN8) {
00280             switch (VGA_AC_remap) {
00281                 case AC_4x4:
00282                 default: // <- just in case
00283                     /* Standard VGA hardware (including the original IBM PS/2 hardware) */
00284                     for (unsigned int i=(unsigned int)attr;i < 0x100;i += 0x10)
00285                         VGA_DAC_UpdateColor( i );
00286                     for (unsigned int i=0;i < 0x10;i++)
00287                         VGA_DAC_UpdateColor( i + (attr<<4u) );
00288                     break;
00289                 case AC_low4:
00290                     /* Tseng ET4000 behavior, according to the SVGA card I have where only the low 4 bits are translated. --J.C. */
00291                     for (unsigned int i=(unsigned int)attr;i < 0x100;i += 0x10)
00292                         VGA_DAC_UpdateColor( i );
00293                     break;
00294             }
00295         }
00296         else {
00297             VGA_DAC_UpdateColor( attr );
00298         }
00299     }
00300     else {
00301         VGA_DAC_SendColor( attr, pal );
00302     }
00303 }
00304 
00305 void VGA_DAC_SetEntry(Bitu entry,Bit8u red,Bit8u green,Bit8u blue) {
00306     //Should only be called in machine != vga
00307     vga.dac.rgb[entry].red=red;
00308     vga.dac.rgb[entry].green=green;
00309     vga.dac.rgb[entry].blue=blue;
00310     for (Bitu i=0;i<16;i++) 
00311         if (vga.dac.combine[i]==entry)
00312             VGA_DAC_SendColor( i, i );
00313 }
00314 
00315 void VGA_SetupDAC(void) {
00316     vga.dac.first_changed=256;
00317     vga.dac.bits=6;
00318     vga.dac.pel_mask=0xff;
00319     vga.dac.pel_index=0;
00320     vga.dac.state=DAC_READ;
00321     vga.dac.read_index=0;
00322     vga.dac.write_index=0;
00323     vga.dac.hidac_counter=0;
00324     vga.dac.reg02=0;
00325     if (IS_VGA_ARCH) {
00326         /* Setup the DAC IO port Handlers */
00327         if (svga.setup_dac) {
00328             svga.setup_dac();
00329         } else {
00330             IO_RegisterWriteHandler(0x3c6,write_p3c6,IO_MB);
00331             IO_RegisterReadHandler(0x3c6,read_p3c6,IO_MB);
00332             IO_RegisterWriteHandler(0x3c7,write_p3c7,IO_MB);
00333             IO_RegisterReadHandler(0x3c7,read_p3c7,IO_MB);
00334             IO_RegisterWriteHandler(0x3c8,write_p3c8,IO_MB);
00335             IO_RegisterReadHandler(0x3c8,read_p3c8,IO_MB);
00336             IO_RegisterWriteHandler(0x3c9,write_p3c9,IO_MB);
00337             IO_RegisterReadHandler(0x3c9,read_p3c9,IO_MB);
00338         }
00339     }
00340 }
00341 
00342 void VGA_UnsetupDAC(void) {
00343     IO_FreeWriteHandler(0x3c6,IO_MB);
00344     IO_FreeReadHandler(0x3c6,IO_MB);
00345     IO_FreeWriteHandler(0x3c7,IO_MB);
00346     IO_FreeReadHandler(0x3c7,IO_MB);
00347     IO_FreeWriteHandler(0x3c8,IO_MB);
00348     IO_FreeReadHandler(0x3c8,IO_MB);
00349     IO_FreeWriteHandler(0x3c9,IO_MB);
00350     IO_FreeReadHandler(0x3c9,IO_MB);
00351 }
00352