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 "mem.h" 00021 #include "inout.h" 00022 #include "int10.h" 00023 00024 #define ACTL_MAX_REG 0x14 00025 00026 static INLINE void ResetACTL(void) { 00027 IO_Read(real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS) + 6u); 00028 } 00029 00030 static INLINE void WriteTandyACTL(Bit8u creg,Bit8u val) { 00031 IO_Write(VGAREG_TDY_ADDRESS,creg); 00032 if (machine==MCH_TANDY) IO_Write(VGAREG_TDY_DATA,val); 00033 else IO_Write(VGAREG_PCJR_DATA,val); 00034 } 00035 00036 void INT10_SetSinglePaletteRegister(Bit8u reg,Bit8u val) { 00037 switch (machine) { 00038 case MCH_PCJR: 00039 reg&=0xf; 00040 IO_Read(VGAREG_TDY_RESET); 00041 WriteTandyACTL(reg+0x10,val); 00042 IO_Write(0x3da,0x0); // palette back on 00043 break; 00044 case MCH_TANDY: 00045 // TODO waits for vertical retrace 00046 switch(vga.mode) { 00047 case M_TANDY2: 00048 if (reg >= 0x10) break; 00049 else if (reg==1) reg = 0x1f; 00050 else reg |= 0x10; 00051 WriteTandyACTL(reg+0x10,val); 00052 break; 00053 case M_TANDY4: { 00054 if (CurMode->mode!=0x0a) { 00055 // Palette values are kept constand by the BIOS. 00056 // The four colors are mapped to special palette values by hardware. 00057 // 3D8/3D9 registers influence this mapping. We need to figure out 00058 // which entry is used for the requested color. 00059 if (reg > 3) break; 00060 if (reg != 0) { // 0 is assumed to be at 0 00061 Bit8u color_select=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL); 00062 reg = reg*2+8; // Green Red Brown 00063 if (color_select& 0x20) reg++; // Cyan Magenta White 00064 } 00065 WriteTandyACTL(reg+0x10,val); 00066 } 00067 // 4-color high resolution mode 0x0a isn't handled specially 00068 else WriteTandyACTL(reg+0x10,val); 00069 break; 00070 } 00071 default: 00072 WriteTandyACTL(reg+0x10,val); 00073 break; 00074 } 00075 IO_Write(0x3da,0x0); // palette back on 00076 break; 00077 case EGAVGA_ARCH_CASE: 00078 if (!IS_VGA_ARCH) reg&=0x1f; 00079 if(reg<=ACTL_MAX_REG) { 00080 ResetACTL(); 00081 IO_Write(VGAREG_ACTL_ADDRESS,reg); 00082 IO_Write(VGAREG_ACTL_WRITE_DATA,val); 00083 } 00084 IO_Write(VGAREG_ACTL_ADDRESS,32); //Enable output and protect palette 00085 break; 00086 default: 00087 break; 00088 } 00089 } 00090 00091 00092 void INT10_SetOverscanBorderColor(Bit8u val) { 00093 switch (machine) { 00094 case TANDY_ARCH_CASE: 00095 IO_Read(VGAREG_TDY_RESET); 00096 WriteTandyACTL(0x02,val); 00097 IO_Write(VGAREG_TDY_ADDRESS, 0); // enable the screen 00098 break; 00099 case EGAVGA_ARCH_CASE: 00100 ResetACTL(); 00101 IO_Write(VGAREG_ACTL_ADDRESS,0x11); 00102 IO_Write(VGAREG_ACTL_WRITE_DATA,val); 00103 IO_Write(VGAREG_ACTL_ADDRESS,32); //Enable output and protect palette 00104 break; 00105 default: 00106 break; 00107 } 00108 } 00109 00110 void INT10_SetAllPaletteRegisters(PhysPt data) { 00111 switch (machine) { 00112 case TANDY_ARCH_CASE: 00113 IO_Read(VGAREG_TDY_RESET); 00114 // First the colors 00115 for(Bit8u i=0;i<0x10;i++) { 00116 WriteTandyACTL(i+0x10,mem_readb(data)); 00117 data++; 00118 } 00119 // Then the border 00120 WriteTandyACTL(0x02,mem_readb(data)); 00121 break; 00122 case EGAVGA_ARCH_CASE: 00123 ResetACTL(); 00124 // First the colors 00125 for(Bit8u i=0;i<0x10;i++) { 00126 IO_Write(VGAREG_ACTL_ADDRESS,i); 00127 IO_Write(VGAREG_ACTL_WRITE_DATA,mem_readb(data)); 00128 data++; 00129 } 00130 // Then the border 00131 IO_Write(VGAREG_ACTL_ADDRESS,0x11); 00132 IO_Write(VGAREG_ACTL_WRITE_DATA,mem_readb(data)); 00133 IO_Write(VGAREG_ACTL_ADDRESS,32); //Enable output and protect palette 00134 break; 00135 default: 00136 break; 00137 } 00138 } 00139 00140 void INT10_ToggleBlinkingBit(Bit8u state) { 00141 if(IS_VGA_ARCH) { 00142 Bit8u value; 00143 // state&=0x01; 00144 if ((state>1) && (svgaCard==SVGA_S3Trio)) return; 00145 ResetACTL(); 00146 00147 IO_Write(VGAREG_ACTL_ADDRESS,0x10); 00148 value=IO_Read(VGAREG_ACTL_READ_DATA); 00149 if (state<=1) { 00150 value&=0xf7; 00151 value|=state<<3; 00152 } 00153 00154 ResetACTL(); 00155 IO_Write(VGAREG_ACTL_ADDRESS,0x10); 00156 IO_Write(VGAREG_ACTL_WRITE_DATA,value); 00157 IO_Write(VGAREG_ACTL_ADDRESS,32); //Enable output and protect palette 00158 00159 if (state<=1) { 00160 Bit8u msrval=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR)&0xdf; 00161 if (state) msrval|=0x20; 00162 real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,msrval); 00163 } 00164 } else { // EGA 00165 // Usually it reads this from the mode list in ROM 00166 if (CurMode->type!=M_TEXT) return; 00167 00168 Bit8u value = (CurMode->cwidth==9)? 0x4:0x0; 00169 if (state) value |= 0x8; 00170 00171 ResetACTL(); 00172 IO_Write(VGAREG_ACTL_ADDRESS,0x10); 00173 IO_Write(VGAREG_ACTL_WRITE_DATA,value); 00174 IO_Write(VGAREG_ACTL_ADDRESS,0x20); 00175 00176 Bit8u msrval=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR)& ~0x20; 00177 if (state) msrval|=0x20; 00178 real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,msrval); 00179 } 00180 } 00181 00182 void INT10_GetSinglePaletteRegister(Bit8u reg,Bit8u * val) { 00183 if(reg<=ACTL_MAX_REG) { 00184 ResetACTL(); 00185 IO_Write(VGAREG_ACTL_ADDRESS,reg+32); 00186 *val=IO_Read(VGAREG_ACTL_READ_DATA); 00187 IO_Write(VGAREG_ACTL_WRITE_DATA,*val); 00188 } 00189 } 00190 00191 void INT10_GetOverscanBorderColor(Bit8u * val) { 00192 ResetACTL(); 00193 IO_Write(VGAREG_ACTL_ADDRESS,0x11+32); 00194 *val=IO_Read(VGAREG_ACTL_READ_DATA); 00195 IO_Write(VGAREG_ACTL_WRITE_DATA,*val); 00196 } 00197 00198 void INT10_GetAllPaletteRegisters(PhysPt data) { 00199 ResetACTL(); 00200 // First the colors 00201 for(Bit8u i=0;i<0x10;i++) { 00202 IO_Write(VGAREG_ACTL_ADDRESS,i); 00203 mem_writeb(data,IO_Read(VGAREG_ACTL_READ_DATA)); 00204 ResetACTL(); 00205 data++; 00206 } 00207 // Then the border 00208 IO_Write(VGAREG_ACTL_ADDRESS,0x11+32); 00209 mem_writeb(data,IO_Read(VGAREG_ACTL_READ_DATA)); 00210 ResetACTL(); 00211 } 00212 00213 void INT10_SetSingleDACRegister(Bit8u index,Bit8u red,Bit8u green,Bit8u blue) { 00214 IO_Write(VGAREG_DAC_WRITE_ADDRESS,(Bit8u)index); 00215 if ((real_readb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)&0x06)==0) { 00216 IO_Write(VGAREG_DAC_DATA,red); 00217 IO_Write(VGAREG_DAC_DATA,green); 00218 IO_Write(VGAREG_DAC_DATA,blue); 00219 } else { 00220 /* calculate clamped intensity, taken from VGABIOS */ 00221 Bit32u i=(( 77u*red + 151u*green + 28u*blue ) + 0x80u) >> 8u; 00222 Bit8u ic=(i>0x3f) ? 0x3f : ((Bit8u)(i & 0xff)); 00223 IO_Write(VGAREG_DAC_DATA,ic); 00224 IO_Write(VGAREG_DAC_DATA,ic); 00225 IO_Write(VGAREG_DAC_DATA,ic); 00226 } 00227 } 00228 00229 void INT10_GetSingleDACRegister(Bit8u index,Bit8u * red,Bit8u * green,Bit8u * blue) { 00230 IO_Write(VGAREG_DAC_READ_ADDRESS,index); 00231 *red=IO_Read(VGAREG_DAC_DATA); 00232 *green=IO_Read(VGAREG_DAC_DATA); 00233 *blue=IO_Read(VGAREG_DAC_DATA); 00234 } 00235 00236 void INT10_SetDACBlock(Bit16u index,Bit16u count,PhysPt data) { 00237 IO_Write(VGAREG_DAC_WRITE_ADDRESS,(Bit8u)index); 00238 if ((real_readb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)&0x06)==0) { 00239 for (;count>0;count--) { 00240 IO_Write(VGAREG_DAC_DATA,mem_readb(data++)); 00241 IO_Write(VGAREG_DAC_DATA,mem_readb(data++)); 00242 IO_Write(VGAREG_DAC_DATA,mem_readb(data++)); 00243 } 00244 } else { 00245 for (;count>0;count--) { 00246 Bit8u red=mem_readb(data++); 00247 Bit8u green=mem_readb(data++); 00248 Bit8u blue=mem_readb(data++); 00249 00250 /* calculate clamped intensity, taken from VGABIOS */ 00251 Bit32u i=(( 77u*red + 151u*green + 28u*blue ) + 0x80u) >> 8u; 00252 Bit8u ic=(i>0x3f) ? 0x3f : ((Bit8u)(i & 0xff)); 00253 IO_Write(VGAREG_DAC_DATA,ic); 00254 IO_Write(VGAREG_DAC_DATA,ic); 00255 IO_Write(VGAREG_DAC_DATA,ic); 00256 } 00257 } 00258 } 00259 00260 void INT10_GetDACBlock(Bit16u index,Bit16u count,PhysPt data) { 00261 IO_Write(VGAREG_DAC_READ_ADDRESS,(Bit8u)index); 00262 for (;count>0;count--) { 00263 mem_writeb(data++,IO_Read(VGAREG_DAC_DATA)); 00264 mem_writeb(data++,IO_Read(VGAREG_DAC_DATA)); 00265 mem_writeb(data++,IO_Read(VGAREG_DAC_DATA)); 00266 } 00267 } 00268 00269 void INT10_SelectDACPage(Bit8u function,Bit8u mode) { 00270 ResetACTL(); 00271 IO_Write(VGAREG_ACTL_ADDRESS,0x10); 00272 Bit8u old10=IO_Read(VGAREG_ACTL_READ_DATA); 00273 if (!function) { //Select paging mode 00274 if (mode) old10|=0x80; 00275 else old10&=0x7f; 00276 //IO_Write(VGAREG_ACTL_ADDRESS,0x10); 00277 IO_Write(VGAREG_ACTL_WRITE_DATA,old10); 00278 } else { //Select page 00279 IO_Write(VGAREG_ACTL_WRITE_DATA,old10); 00280 if (!(old10 & 0x80)) mode<<=2; 00281 mode&=0xf; 00282 IO_Write(VGAREG_ACTL_ADDRESS,0x14); 00283 IO_Write(VGAREG_ACTL_WRITE_DATA,mode); 00284 } 00285 IO_Write(VGAREG_ACTL_ADDRESS,32); //Enable output and protect palette 00286 } 00287 00288 void INT10_GetDACPage(Bit8u* mode,Bit8u* page) { 00289 ResetACTL(); 00290 IO_Write(VGAREG_ACTL_ADDRESS,0x10); 00291 Bit8u reg10=IO_Read(VGAREG_ACTL_READ_DATA); 00292 IO_Write(VGAREG_ACTL_WRITE_DATA,reg10); 00293 *mode=(reg10&0x80)?0x01:0x00; 00294 IO_Write(VGAREG_ACTL_ADDRESS,0x14); 00295 *page=IO_Read(VGAREG_ACTL_READ_DATA); 00296 IO_Write(VGAREG_ACTL_WRITE_DATA,*page); 00297 if(*mode) { 00298 *page&=0xf; 00299 } else { 00300 *page&=0xc; 00301 *page>>=2; 00302 } 00303 00304 /* the operations carried out here blanked the display because of the index (0x10/0x14) without bit 5, 00305 * write a dummy index with bit 5 to reenable the display. Bugfix for "Blue Force" MS-DOS game. 00306 * 00307 * Note that DOSBox SVN has the same bug without this fix, but appears to work because the AC blanking 00308 * doesn't work (2019/12/08). */ 00309 IO_Write(VGAREG_ACTL_ADDRESS,0x10/*index*/ | 0x20/*display enable*/); 00310 /* read both, to avoid having to read 0x3CC or BIOS data area regs */ 00311 IO_Read(0x3BA); /* reset flip flop */ 00312 IO_Read(0x3DA); /* reset flip flop */ 00313 } 00314 00315 void INT10_SetPelMask(Bit8u mask) { 00316 IO_Write(VGAREG_PEL_MASK,mask); 00317 } 00318 00319 void INT10_GetPelMask(Bit8u & mask) { 00320 mask=IO_Read(VGAREG_PEL_MASK); 00321 } 00322 00323 void INT10_SetBackgroundBorder(Bit8u val) { 00324 Bit8u color_select=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL); 00325 color_select=(color_select & 0xe0) | (val & 0x1f); 00326 real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL,color_select); 00327 00328 switch (machine) { 00329 case MCH_CGA: 00330 case MCH_MCGA: 00331 // only write the color select register 00332 IO_Write(0x3d9,color_select); 00333 break; 00334 case MCH_TANDY: 00335 // TODO handle val == 0x1x, wait for retrace 00336 switch(CurMode->mode) { 00337 default: // modes 0-5: write to color select and border 00338 INT10_SetOverscanBorderColor(val); 00339 IO_Write(0x3d9, color_select); 00340 break; 00341 case 0x06: // 2-color: only write the color select register 00342 IO_Write(0x3d9, color_select); 00343 break; 00344 case 0x07: // Tandy monochrome not implemented 00345 break; 00346 case 0x08: 00347 case 0x09: // 16-color: write to color select, border and pal. index 0 00348 INT10_SetOverscanBorderColor(val); 00349 INT10_SetSinglePaletteRegister(0, val); 00350 IO_Write(0x3d9, color_select); 00351 break; 00352 case 0x0a: // 4-color highres: 00353 // write zero to color select, write palette to indexes 1-3 00354 // TODO palette 00355 IO_Write(0x3d9, 0); 00356 break; 00357 } 00358 break; 00359 case MCH_PCJR: 00360 IO_Read(VGAREG_TDY_RESET); // reset the flipflop 00361 if (vga.mode!=M_TANDY_TEXT) { 00362 IO_Write(VGAREG_TDY_ADDRESS, 0x10); 00363 IO_Write(VGAREG_PCJR_DATA, color_select&0xf); 00364 } 00365 IO_Write(VGAREG_TDY_ADDRESS, 0x2); // border color 00366 IO_Write(VGAREG_PCJR_DATA, color_select&0xf); 00367 break; 00368 case EGAVGA_ARCH_CASE: 00369 val = ((val << 1) & 0x10) | (val & 0x7); 00370 /* Always set the overscan color */ 00371 INT10_SetSinglePaletteRegister( 0x11, val ); 00372 /* Don't set any extra colors when in text mode */ 00373 if (CurMode->mode <= 3) 00374 return; 00375 INT10_SetSinglePaletteRegister( 0, val ); 00376 val = (color_select & 0x10) | 2 | ((color_select & 0x20) >> 5); 00377 INT10_SetSinglePaletteRegister( 1, val ); 00378 val+=2; 00379 INT10_SetSinglePaletteRegister( 2, val ); 00380 val+=2; 00381 INT10_SetSinglePaletteRegister( 3, val ); 00382 break; 00383 default: 00384 break; 00385 } 00386 } 00387 00388 void INT10_SetColorSelect(Bit8u val) { 00389 Bit8u temp=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL); 00390 temp=(temp & 0xdf) | ((val & 1) ? 0x20 : 0x0); 00391 real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL,temp); 00392 if (machine == MCH_CGA || machine == MCH_MCGA || machine == MCH_AMSTRAD || machine==MCH_TANDY) 00393 IO_Write(0x3d9,temp); 00394 else if (machine == MCH_PCJR) { 00395 IO_Read(VGAREG_TDY_RESET); // reset the flipflop 00396 switch(vga.mode) { 00397 case M_TANDY2: 00398 IO_Write(VGAREG_TDY_ADDRESS, 0x11); 00399 IO_Write(VGAREG_PCJR_DATA, (val&1)? 0xf:0); 00400 break; 00401 case M_TANDY4: 00402 for(Bit8u i = 0x11; i < 0x14; i++) { 00403 const Bit8u t4_table[] = {0,2,4,6, 0,3,5,0xf}; 00404 IO_Write(VGAREG_TDY_ADDRESS, i); 00405 IO_Write(VGAREG_PCJR_DATA, t4_table[(i-0x10)+((val&1)? 4:0)]); 00406 } 00407 break; 00408 default: 00409 // 16-color modes: always write the same palette 00410 for(Bit8u i = 0x11; i < 0x20; i++) { 00411 IO_Write(VGAREG_TDY_ADDRESS, i); 00412 IO_Write(VGAREG_PCJR_DATA, i-0x10); 00413 } 00414 break; 00415 } 00416 IO_Write(VGAREG_TDY_ADDRESS, 0); // enable palette 00417 } 00418 else if (IS_EGAVGA_ARCH) { 00419 if (CurMode->mode <= 3) //Maybe even skip the total function! 00420 return; 00421 val = (temp & 0x10) | 2 | val; 00422 INT10_SetSinglePaletteRegister( 1, val ); 00423 val+=2; 00424 INT10_SetSinglePaletteRegister( 2, val ); 00425 val+=2; 00426 INT10_SetSinglePaletteRegister( 3, val ); 00427 } 00428 } 00429 00430 void INT10_PerformGrayScaleSumming(Bit16u start_reg,Bit16u count) { 00431 if (count>0x100) count=0x100; 00432 for (Bitu ct=0; ct<count; ct++) { 00433 IO_Write(VGAREG_DAC_READ_ADDRESS,(Bit8u)(start_reg+ct)); 00434 Bit8u red=IO_Read(VGAREG_DAC_DATA); 00435 Bit8u green=IO_Read(VGAREG_DAC_DATA); 00436 Bit8u blue=IO_Read(VGAREG_DAC_DATA); 00437 00438 /* calculate clamped intensity, taken from VGABIOS */ 00439 Bit32u i=(( 77u*red + 151u*green + 28u*blue ) + 0x80u) >> 8u; 00440 Bit8u ic=(i>0x3f) ? 0x3f : ((Bit8u)(i & 0xff)); 00441 INT10_SetSingleDACRegister((Bit8u)(start_reg+ct),ic,ic,ic); 00442 } 00443 }