DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator
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_EGA_ARCH) {
00095         VGA_DAC_SendColor( index, index );
00096     }
00097     else {
00098         switch (vga.mode) {
00099             case M_VGA:
00100             case M_LIN8:
00101                 maskIndex = index & vga.dac.pel_mask;
00102                 VGA_DAC_SendColor( index, maskIndex );
00103                 break;
00104             default:
00105                 /* Remember the lookup table is there to handle the color palette AND the DAC mask AND the attribute controller palette */
00106                 /* FIXME: Is it: index -> attribute controller -> dac mask, or
00107                  *               index -> dac mask -> attribute controller? */
00108                 maskIndex = vga.dac.combine[index&0xF] & vga.dac.pel_mask;
00109                 VGA_DAC_SendColor( index, maskIndex );
00110                 break;
00111         }
00112     }
00113 }
00114 
00115 void VGA_DAC_UpdateColorPalette() {
00116     for ( Bitu i = 0;i<256;i++) 
00117         VGA_DAC_UpdateColor( i );
00118 }
00119 
00120 void write_p3c6(Bitu port,Bitu val,Bitu iolen) {
00121     (void)iolen;//UNUSED
00122     (void)port;//UNUSED
00123     if((IS_VGA_ARCH) && (svgaCard==SVGA_None) && (vga.dac.hidac_counter>3)) {
00124         vga.dac.reg02=val;
00125         vga.dac.hidac_counter=0;
00126         VGA_StartResize();
00127         return;
00128     }
00129     if ( vga.dac.pel_mask != val ) {
00130         LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:DCA:Pel Mask set to %X", (int)val);
00131         vga.dac.pel_mask = val;
00132         VGA_DAC_UpdateColorPalette();
00133     }
00134 }
00135 
00136 
00137 Bitu read_p3c6(Bitu port,Bitu iolen) {
00138     (void)iolen;//UNUSED
00139     (void)port;//UNUSED
00140     if (vga_enable_3C6_ramdac)
00141         vga.dac.hidac_counter++;
00142 
00143     return vga.dac.pel_mask;
00144 }
00145 
00146 
00147 void write_p3c7(Bitu port,Bitu val,Bitu iolen) {
00148     (void)iolen;//UNUSED
00149     (void)port;//UNUSED
00150     vga.dac.hidac_counter=0;
00151     vga.dac.pel_index=0;
00152     vga.dac.state=DAC_READ;
00153     vga.dac.read_index=val;         /* NTS: Paradise SVGA behavior, read index = x, write index = x + 1 */
00154     vga.dac.write_index=val + 1;
00155 }
00156 
00157 Bitu read_p3c7(Bitu port,Bitu iolen) {
00158     (void)iolen;//UNUSED
00159     (void)port;//UNUSED
00160     vga.dac.hidac_counter=0;
00161     if (vga.dac.state==DAC_READ) return 0x3;
00162     else return 0x0;
00163 }
00164 
00165 void write_p3c8(Bitu port,Bitu val,Bitu iolen) {
00166     (void)iolen;//UNUSED
00167     (void)port;//UNUSED
00168     vga.dac.hidac_counter=0;
00169     vga.dac.pel_index=0;
00170     vga.dac.state=DAC_WRITE;
00171     vga.dac.write_index=val;        /* NTS: Paradise SVGA behavior, this affects write index, but not read index */
00172 }
00173 
00174 Bitu read_p3c8(Bitu port, Bitu iolen){
00175     (void)iolen;//UNUSED
00176     (void)port;//UNUSED
00177     vga.dac.hidac_counter=0;
00178     return vga.dac.write_index;
00179 }
00180 
00181 void write_p3c9(Bitu port,Bitu val,Bitu iolen) {
00182     (void)iolen;//UNUSED
00183     (void)port;//UNUSED
00184     vga.dac.hidac_counter=0;
00185     val&=0x3f;
00186     switch (vga.dac.pel_index) {
00187     case 0:
00188         vga.dac.rgb[vga.dac.write_index].red=val;
00189         vga.dac.pel_index=1;
00190         break;
00191     case 1:
00192         vga.dac.rgb[vga.dac.write_index].green=val;
00193         vga.dac.pel_index=2;
00194         break;
00195     case 2:
00196         vga.dac.rgb[vga.dac.write_index].blue=val;
00197         switch (vga.mode) {
00198         case M_VGA:
00199         case M_LIN8:
00200             VGA_DAC_UpdateColor( vga.dac.write_index );
00201             if ( GCC_UNLIKELY( vga.dac.pel_mask != 0xff)) {
00202                 Bitu index = vga.dac.write_index;
00203                 if ( (index & vga.dac.pel_mask) == index ) {
00204                     for ( Bitu i = index+1;i<256;i++) 
00205                         if ( (i & vga.dac.pel_mask) == index )
00206                             VGA_DAC_UpdateColor( i );
00207                 }
00208             } 
00209             break;
00210         default:
00211             /* Check for attributes and DAC entry link */
00212             for (Bitu i=0;i<16;i++) {
00213                 if (vga.dac.combine[i]==vga.dac.write_index) {
00214                     VGA_DAC_SendColor( i, vga.dac.write_index );
00215                 }
00216             }
00217         }
00218         vga.dac.read_index=vga.dac.write_index++;                           // NTS: Paradise SVGA behavior
00219         vga.dac.pel_index=0;
00220         break;
00221     default:
00222         LOG(LOG_VGAGFX,LOG_NORMAL)("VGA:DAC:Illegal Pel Index");            //If this can actually happen that will be the day
00223         break;
00224     };
00225 }
00226 
00227 Bitu read_p3c9(Bitu port,Bitu iolen) {
00228     (void)iolen;//UNUSED
00229     (void)port;//UNUSED
00230     vga.dac.hidac_counter=0;
00231     Bit8u ret;
00232     switch (vga.dac.pel_index) {
00233     case 0:
00234         ret=vga.dac.rgb[vga.dac.read_index].red;
00235         vga.dac.pel_index=1;
00236         break;
00237     case 1:
00238         ret=vga.dac.rgb[vga.dac.read_index].green;
00239         vga.dac.pel_index=2;
00240         break;
00241     case 2:
00242         ret=vga.dac.rgb[vga.dac.read_index].blue;
00243         vga.dac.pel_index=0;
00244         vga.dac.read_index=vga.dac.write_index++;                           // NTS: Paradise SVGA behavior
00245         break;
00246     default:
00247         LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:DAC:Illegal Pel Index");           //If this can actually happen that will be the day
00248         ret=0;
00249         break;
00250     }
00251     return ret;
00252 }
00253 
00254 void VGA_DAC_CombineColor(Bit8u attr,Bit8u pal) {
00255     /* Check if this is a new color */
00256     vga.dac.combine[attr]=pal;
00257     switch (vga.mode) {
00258     case M_LIN8:
00259         break;
00260     case M_VGA:
00261         // used by copper demo; almost no video card seems to support it
00262         // Update: supported by ET4000AX (and not by ET4000AF)
00263     default:
00264         VGA_DAC_SendColor( attr, pal );
00265     }
00266 }
00267 
00268 void VGA_DAC_SetEntry(Bitu entry,Bit8u red,Bit8u green,Bit8u blue) {
00269     //Should only be called in machine != vga
00270     vga.dac.rgb[entry].red=red;
00271     vga.dac.rgb[entry].green=green;
00272     vga.dac.rgb[entry].blue=blue;
00273     for (Bitu i=0;i<16;i++) 
00274         if (vga.dac.combine[i]==entry)
00275             VGA_DAC_SendColor( i, i );
00276 }
00277 
00278 void VGA_SetupDAC(void) {
00279     vga.dac.first_changed=256;
00280     vga.dac.bits=6;
00281     vga.dac.pel_mask=0xff;
00282     vga.dac.pel_index=0;
00283     vga.dac.state=DAC_READ;
00284     vga.dac.read_index=0;
00285     vga.dac.write_index=0;
00286     vga.dac.hidac_counter=0;
00287     vga.dac.reg02=0;
00288     if (IS_VGA_ARCH) {
00289         /* Setup the DAC IO port Handlers */
00290         if (svga.setup_dac) {
00291             svga.setup_dac();
00292         } else {
00293             IO_RegisterWriteHandler(0x3c6,write_p3c6,IO_MB);
00294             IO_RegisterReadHandler(0x3c6,read_p3c6,IO_MB);
00295             IO_RegisterWriteHandler(0x3c7,write_p3c7,IO_MB);
00296             IO_RegisterReadHandler(0x3c7,read_p3c7,IO_MB);
00297             IO_RegisterWriteHandler(0x3c8,write_p3c8,IO_MB);
00298             IO_RegisterReadHandler(0x3c8,read_p3c8,IO_MB);
00299             IO_RegisterWriteHandler(0x3c9,write_p3c9,IO_MB);
00300             IO_RegisterReadHandler(0x3c9,read_p3c9,IO_MB);
00301         }
00302     }
00303 }
00304 
00305 void VGA_UnsetupDAC(void) {
00306     IO_FreeWriteHandler(0x3c6,IO_MB);
00307     IO_FreeReadHandler(0x3c6,IO_MB);
00308     IO_FreeWriteHandler(0x3c7,IO_MB);
00309     IO_FreeReadHandler(0x3c7,IO_MB);
00310     IO_FreeWriteHandler(0x3c8,IO_MB);
00311     IO_FreeReadHandler(0x3c8,IO_MB);
00312     IO_FreeWriteHandler(0x3c9,IO_MB);
00313     IO_FreeReadHandler(0x3c9,IO_MB);
00314 }
00315