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 00021 #include "dosbox.h" 00022 #include "setup.h" 00023 #include "vga.h" 00024 #include "inout.h" 00025 #include "mem.h" 00026 #include "regs.h" 00027 #include <cstdlib> 00028 00029 extern bool vga_enable_3C6_ramdac; 00030 extern bool vga_sierra_lock_565; 00031 00032 // Tseng ET4K data 00033 typedef struct { 00034 Bit8u extensionsEnabled; 00035 00036 // Current DAC mode 00037 Bit8u hicolorDACcmdmode; 00038 // HiColor DAC control register. See comments below. Only bits 5-7 are emulated, close to SC11485 version. 00039 Bit8u hicolorDACcommand; 00040 00041 // Stored exact values of some registers. Documentation only specifies some bits but hardware checks may 00042 // expect other bits to be preserved. 00043 Bitu store_3d4_31; 00044 Bitu store_3d4_32; 00045 Bitu store_3d4_33; 00046 Bitu store_3d4_34; 00047 Bitu store_3d4_35; 00048 Bitu store_3d4_36; 00049 Bitu store_3d4_37; 00050 Bitu store_3d4_3f; 00051 00052 Bitu store_3c0_16; 00053 Bitu store_3c0_17; 00054 00055 Bitu store_3c4_06; 00056 Bitu store_3c4_07; 00057 00058 Bitu clockFreq[16]; 00059 Bitu biosMode; 00060 } SVGA_ET4K_DATA; 00061 00062 static SVGA_ET4K_DATA et4k = { 1,0,0,0,0,0,0,0,0,0,0, 0,0, 0,0, 00063 { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0 }; 00064 00065 #define STORE_ET4K(port, index) \ 00066 case 0x##index: \ 00067 et4k.store_##port##_##index = val; \ 00068 break; 00069 00070 #define RESTORE_ET4K(port, index) \ 00071 case 0x##index: \ 00072 return et4k.store_##port##_##index; 00073 00074 // Tseng ET4K implementation 00075 void write_p3d5_et4k(Bitu reg,Bitu val,Bitu iolen) { 00076 (void)iolen;//UNUSED 00077 if(!et4k.extensionsEnabled && reg!=0x33) 00078 return; 00079 00080 switch(reg) { 00081 /* 00082 3d4h index 31h (R/W): General Purpose 00083 bit 0-3 Scratch pad 00084 6-7 Clock Select bits 3-4. Bits 0-1 are in 3C2h/3CCh bits 2-3. 00085 */ 00086 STORE_ET4K(3d4, 31); 00087 00088 // 3d4h index 32h - RAS/CAS Configuration (R/W) 00089 // No effect on emulation. Should not be written by software. 00090 STORE_ET4K(3d4, 32); 00091 00092 case 0x33: 00093 // 3d4 index 33h (R/W): Extended start Address 00094 // 0-1 Display Start Address bits 16-17 00095 // 2-3 Cursor start address bits 16-17 00096 // Used by standard Tseng ID scheme 00097 et4k.store_3d4_33 = val; 00098 vga.config.display_start = (vga.config.display_start & 0xffff) | ((val & 0x03)<<16); 00099 vga.config.cursor_start = (vga.config.cursor_start & 0xffff) | ((val & 0x0c)<<14); 00100 break; 00101 00102 /* 00103 3d4h index 34h (R/W): 6845 Compatibility Control Register 00104 bit 0 Enable CS0 (alternate clock timing) 00105 1 Clock Select bit 2. Bits 0-1 in 3C2h bits 2-3, bits 3-4 are in 3d4h 00106 index 31h bits 6-7 00107 2 Tristate ET4000 bus and color outputs if set 00108 3 Video Subsystem Enable Register at 46E8h if set, at 3C3h if clear. 00109 4 Enable Translation ROM for reading CRTC and MISCOUT if set 00110 5 Enable Translation ROM for writing CRTC and MISCOUT if set 00111 6 Enable double scan in AT&T compatibility mode if set 00112 7 Enable 6845 compatibility if set 00113 */ 00114 // TODO: Bit 6 may have effect on emulation 00115 STORE_ET4K(3d4, 34); 00116 00117 case 0x35: 00118 /* 00119 3d4h index 35h (R/W): Overflow High 00120 bit 0 Vertical Blank Start Bit 10 (3d4h index 15h). 00121 1 Vertical Total Bit 10 (3d4h index 6). 00122 2 Vertical Display End Bit 10 (3d4h index 12h). 00123 3 Vertical Sync Start Bit 10 (3d4h index 10h). 00124 4 Line Compare Bit 10 (3d4h index 18h). 00125 5 Gen-Lock Enabled if set (External sync) 00126 6 (4000) Read/Modify/Write Enabled if set. Currently not implemented. 00127 7 Vertical interlace if set. The Vertical timing registers are 00128 programmed as if the mode was non-interlaced!! 00129 */ 00130 et4k.store_3d4_35 = val; 00131 vga.config.line_compare = (vga.config.line_compare & 0x3ff) | ((val&0x10)<<6); 00132 // Abusing s3 ex_ver_overflow field. This is to be cleaned up later. 00133 { 00134 Bit8u s3val = 00135 ((val & 0x01) << 2) | // vbstart 00136 ((val & 0x02) >> 1) | // vtotal 00137 ((val & 0x04) >> 1) | // vdispend 00138 ((val & 0x08) << 1) | // vsyncstart (?) 00139 ((val & 0x10) << 2); // linecomp 00140 if ((s3val ^ vga.s3.ex_ver_overflow) & 0x3) { 00141 vga.s3.ex_ver_overflow=s3val; 00142 VGA_StartResize(); 00143 } else vga.s3.ex_ver_overflow=s3val; 00144 } 00145 break; 00146 00147 // 3d4h index 36h - Video System Configuration 1 (R/W) 00148 // VGADOC provides a lot of info on this register, Ferraro has significantly less detail. 00149 // This is unlikely to be used by any games. Bit 4 switches chipset into linear mode - 00150 // that may be useful in some cases if there is any software actually using it. 00151 // TODO (not near future): support linear addressing 00152 STORE_ET4K(3d4, 36); 00153 00154 // 3d4h index 37 - Video System Configuration 2 (R/W) 00155 // Bits 0,1, and 3 provides information about memory size: 00156 // 0-1 Bus width (1: 8 bit, 2: 16 bit, 3: 32 bit) 00157 // 3 Size of RAM chips (0: 64Kx, 1: 256Kx) 00158 // Other bits have no effect on emulation. 00159 case 0x37: 00160 if (val != et4k.store_3d4_37) { 00161 et4k.store_3d4_37 = val; 00162 vga.mem.memmask = (((64u*1024u*((val&8u)?4u:1u))<<((val&3u)-1u)) - 1u) & (vga.mem.memsize-1u); 00163 VGA_SetupHandlers(); 00164 } 00165 break; 00166 00167 case 0x3f: 00168 /* 00169 3d4h index 3Fh (R/W): 00170 bit 0 Bit 8 of the Horizontal Total (3d4h index 0) 00171 2 Bit 8 of the Horizontal Blank Start (3d4h index 3) 00172 4 Bit 8 of the Horizontal Retrace Start (3d4h index 4) 00173 7 Bit 8 of the CRTC offset register (3d4h index 13h). 00174 */ 00175 // The only unimplemented one is bit 7 00176 et4k.store_3d4_3f = val; 00177 // Abusing s3 ex_hor_overflow field which very similar. This is 00178 // to be cleaned up later 00179 if ((val ^ vga.s3.ex_hor_overflow) & 3) { 00180 vga.s3.ex_hor_overflow=(val&0x15); 00181 VGA_StartResize(); 00182 } else vga.s3.ex_hor_overflow=(val&0x15); 00183 break; 00184 default: 00185 LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:CRTC:ET4K:Write to illegal index %2X", (int)reg); 00186 break; 00187 } 00188 } 00189 00190 Bitu read_p3d5_et4k(Bitu reg,Bitu iolen) { 00191 (void)iolen;//UNUSED 00192 if (!et4k.extensionsEnabled && reg!=0x33) 00193 return 0x0; 00194 switch(reg) { 00195 RESTORE_ET4K(3d4, 31); 00196 RESTORE_ET4K(3d4, 32); 00197 RESTORE_ET4K(3d4, 33); 00198 RESTORE_ET4K(3d4, 34); 00199 RESTORE_ET4K(3d4, 35); 00200 RESTORE_ET4K(3d4, 36); 00201 RESTORE_ET4K(3d4, 37); 00202 RESTORE_ET4K(3d4, 3f); 00203 default: 00204 LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:CRTC:ET4K:Read from illegal index %2X", (int)reg); 00205 break; 00206 } 00207 return 0x0; 00208 } 00209 00210 void write_p3c5_et4k(Bitu reg,Bitu val,Bitu iolen) { 00211 (void)iolen;//UNUSED 00212 switch(reg) { 00213 /* 00214 3C4h index 6 (R/W): TS State Control 00215 bit 1-2 Font Width Select in dots/character 00216 If 3C4h index 4 bit 0 clear: 00217 0: 9 dots, 1: 10 dots, 2: 12 dots, 3: 6 dots 00218 If 3C4h index 5 bit 0 set: 00219 0: 8 dots, 1: 11 dots, 2: 7 dots, 3: 16 dots 00220 Only valid if 3d4h index 34h bit 3 set. 00221 */ 00222 // TODO: Figure out if this has any practical use 00223 STORE_ET4K(3c4, 06); 00224 // 3C4h index 7 (R/W): TS Auxiliary Mode 00225 // Unlikely to be used by games (things like ROM enable/disable and emulation of VGA vs EGA) 00226 STORE_ET4K(3c4, 07); 00227 default: 00228 LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:SEQ:ET4K:Write to illegal index %2X", (int)reg); 00229 break; 00230 } 00231 } 00232 00233 Bitu read_p3c5_et4k(Bitu reg,Bitu iolen) { 00234 (void)iolen;//UNUSED 00235 switch(reg) { 00236 RESTORE_ET4K(3c4, 06); 00237 RESTORE_ET4K(3c4, 07); 00238 default: 00239 LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:SEQ:ET4K:Read from illegal index %2X", (int)reg); 00240 break; 00241 } 00242 return 0x0; 00243 } 00244 00245 /* 00246 3CDh (R/W): Segment Select 00247 bit 0-3 64k Write bank number (0..15) 00248 4-7 64k Read bank number (0..15) 00249 */ 00250 void write_p3cd_et4k(Bitu port,Bitu val,Bitu iolen) { 00251 (void)port;//UNUSED 00252 (void)iolen;//UNUSED 00253 vga.svga.bank_write = val & 0x0fu; 00254 vga.svga.bank_read = (val>>4u) & 0x0fu; 00255 VGA_SetupHandlers(); 00256 } 00257 00258 Bitu read_p3cd_et4k(Bitu port,Bitu iolen) { 00259 (void)port;//UNUSED 00260 (void)iolen;//UNUSED 00261 return (Bitu)((vga.svga.bank_read<<4u)|vga.svga.bank_write); 00262 } 00263 00264 void write_p3c0_et4k(Bitu reg,Bitu val,Bitu iolen) { 00265 (void)iolen;//UNUSED 00266 switch(reg) { 00267 // 3c0 index 16h: ATC Miscellaneous 00268 // VGADOC provides a lot of information, Ferarro documents only two bits 00269 // and even those incompletely. The register is used as part of identification 00270 // scheme. 00271 // Unlikely to be used by any games but double timing may be useful. 00272 // TODO: Figure out if this has any practical use 00273 STORE_ET4K(3c0, 16); 00274 /* 00275 3C0h index 17h (R/W): Miscellaneous 1 00276 bit 7 If set protects the internal palette ram and redefines the attribute 00277 bits as follows: 00278 Monochrome: 00279 bit 0-2 Select font 0-7 00280 3 If set selects blinking 00281 4 If set selects underline 00282 5 If set prevents the character from being displayed 00283 6 If set displays the character at half intensity 00284 7 If set selects reverse video 00285 Color: 00286 bit 0-1 Selects font 0-3 00287 2 Foreground Blue 00288 3 Foreground Green 00289 4 Foreground Red 00290 5 Background Blue 00291 6 Background Green 00292 7 Background Red 00293 */ 00294 // TODO: Figure out if this has any practical use 00295 STORE_ET4K(3c0, 17); 00296 default: 00297 LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:ATTR:ET4K:Write to illegal index %2X", (int)reg); 00298 break; 00299 } 00300 } 00301 00302 Bitu read_p3c1_et4k(Bitu reg,Bitu iolen) { 00303 (void)iolen;//UNUSED 00304 switch(reg) { 00305 RESTORE_ET4K(3c0, 16); 00306 RESTORE_ET4K(3c0, 17); 00307 default: 00308 LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:ATTR:ET4K:Read from illegal index %2X", (int)reg); 00309 break; 00310 } 00311 return 0x0; 00312 } 00313 00314 /* 00315 These ports are used but have little if any effect on emulation: 00316 3BFh (R/W): Hercules Compatibility Mode 00317 3CBh (R/W): PEL Address/Data Wd 00318 3CEh index 0Dh (R/W): Microsequencer Mode 00319 3CEh index 0Eh (R/W): Microsequencer Reset 00320 3d8h (R/W): Display Mode Control 00321 3DEh (W); AT&T Mode Control Register 00322 */ 00323 00324 static Bitu get_clock_index_et4k() { 00325 // Ignoring bit 4, using "only" 16 frequencies. Looks like most implementations had only that 00326 return ((vga.misc_output>>2)&3) | ((et4k.store_3d4_34<<1)&4) | ((et4k.store_3d4_31>>3)&8); 00327 } 00328 00329 static void set_clock_index_et4k(Bitu index) { 00330 // Shortwiring register reads/writes for simplicity 00331 IO_Write(0x3c2, (vga.misc_output&~0x0cu)|((index&3u)<<2u)); 00332 et4k.store_3d4_34 = (et4k.store_3d4_34&~0x02u)|((index&4u)>>1u); 00333 et4k.store_3d4_31 = (et4k.store_3d4_31&~0xc0u)|((index&8u)<<3u); // (index&0x18) if 32 clock frequencies are to be supported 00334 } 00335 00336 void FinishSetMode_ET4K(Bitu crtc_base, VGA_ModeExtraData* modeData) { 00337 // Note that switching to a mode always puts the DAC in 15-bit color. An extra BIOS call is necessary to switch to 16-bit color. 00338 // We are also forcing the mode back to work exactly the way it did on the real hardware 00339 if (modeData->modeNo & 0x200u) { 00340 et4k.hicolorDACcommand = 0xa0u; 00341 modeData->modeNo &= ~0x200u; 00342 } else { 00343 et4k.hicolorDACcommand = 0x00u; 00344 } 00345 00346 et4k.biosMode = modeData->modeNo; 00347 00348 IO_Write(0x3cd, 0x00); // both banks to 0 00349 00350 // Reinterpret hor_overflow. Curiously, three bits out of four are 00351 // in the same places. Input has hdispend (not supported), output 00352 // has CRTC offset (also not supported) 00353 Bit8u et4k_hor_overflow = 00354 (modeData->hor_overflow & 0x01) | 00355 (modeData->hor_overflow & 0x04) | 00356 (modeData->hor_overflow & 0x10); 00357 IO_Write(crtc_base,0x3f);IO_Write(crtc_base+1,et4k_hor_overflow); 00358 00359 // Reinterpret ver_overflow 00360 Bit8u et4k_ver_overflow = 00361 ((modeData->ver_overflow & 0x01) << 1) | // vtotal10 00362 ((modeData->ver_overflow & 0x02) << 1) | // vdispend10 00363 ((modeData->ver_overflow & 0x04) >> 2) | // vbstart10 00364 ((modeData->ver_overflow & 0x10) >> 1) | // vretrace10 (tseng has vsync start?) 00365 ((modeData->ver_overflow & 0x40) >> 2); // line_compare 00366 IO_Write(crtc_base,0x35);IO_Write(crtc_base+1,et4k_ver_overflow); 00367 00368 // Clear remaining ext CRTC registers 00369 IO_Write(crtc_base,0x31);IO_Write(crtc_base+1,0); 00370 IO_Write(crtc_base,0x32);IO_Write(crtc_base+1,0); 00371 IO_Write(crtc_base,0x33);IO_Write(crtc_base+1,0); 00372 IO_Write(crtc_base,0x34);IO_Write(crtc_base+1,0); 00373 IO_Write(crtc_base,0x36);IO_Write(crtc_base+1,0); 00374 IO_Write(crtc_base,0x37);IO_Write(crtc_base+1,0x0c|(vga.mem.memsize==1024*1024?3:vga.mem.memsize==512*1024?2:1)); 00375 // Clear ext SEQ 00376 IO_Write(0x3c4,0x06);IO_Write(0x3c5,0); 00377 IO_Write(0x3c4,0x07);IO_Write(0x3c5,0); 00378 // Clear ext ATTR 00379 IO_Write(0x3c0,0x16);IO_Write(0x3c0,0); 00380 IO_Write(0x3c0,0x17);IO_Write(0x3c0,0); 00381 00382 // Select SVGA clock to get close to 60Hz (not particularly clean implementation) 00383 if (modeData->modeNo > 0x13) { 00384 Bits target = static_cast<Bits>(modeData->vtotal * 8 * modeData->htotal * 60); 00385 Bitu best = 1; 00386 int dist = 100000000; 00387 for (Bitu i = 0; i < 16; i++) { 00388 int cdiff = abs( static_cast<int>(target - static_cast<Bits>(et4k.clockFreq[i])) ); 00389 if (cdiff < dist) { 00390 best = i; 00391 dist = cdiff; 00392 } 00393 } 00394 set_clock_index_et4k(best); 00395 } 00396 00397 if(svga.determine_mode) 00398 svga.determine_mode(); 00399 00400 // Verified (on real hardware and in a few games): Tseng ET4000 used chain4 implementation 00401 // different from standard VGA. It was also not limited to 64K in regular mode 13h. 00402 vga.config.compatible_chain4 = false; 00403 // vga.vmemwrap = vga.mem.memsize; 00404 00405 VGA_SetupHandlers(); 00406 } 00407 00408 void DetermineMode_ET4K() { 00409 // Special case for HiColor DAC enabled modes 00410 if ((et4k.hicolorDACcommand & 0xc0) == 0x80) { 00411 VGA_SetMode(vga_sierra_lock_565 ? M_LIN16 : M_LIN15); 00412 return; 00413 } else if ((et4k.hicolorDACcommand & 0xc0) == 0xc0) { 00414 VGA_SetMode(M_LIN16); 00415 return; 00416 } 00417 // Close replica from the base implementation. It will stay here 00418 // until I figure a way to either distinguish M_VGA and M_LIN8 or 00419 // merge them. 00420 if (vga.attr.mode_control & 1) { 00421 if (vga.gfx.mode & 0x40) VGA_SetMode((et4k.biosMode<=0x13)?M_VGA:M_LIN8); // Ugly... 00422 else if (vga.gfx.mode & 0x20) VGA_SetMode(M_CGA4); 00423 else if ((vga.gfx.miscellaneous & 0x0c)==0x0c) VGA_SetMode(M_CGA2); 00424 else VGA_SetMode((et4k.biosMode<=0x13)?M_EGA:M_LIN4); 00425 } else { 00426 VGA_SetMode(M_TEXT); 00427 } 00428 } 00429 00430 void SetClock_ET4K(Bitu which,Bitu target) { 00431 et4k.clockFreq[which]=1000*target; 00432 VGA_StartResize(); 00433 } 00434 00435 Bitu GetClock_ET4K() { 00436 return et4k.clockFreq[get_clock_index_et4k()]; 00437 } 00438 00439 bool AcceptsMode_ET4K(Bitu mode) { 00440 return VideoModeMemSize(mode) < vga.mem.memsize; 00441 // return mode != 0x3d; 00442 } 00443 00444 // Support for HiColor DAC 00445 // Support is sufficient for proper detection (WHATVGA detects UMC 70c178, similar to Sierra SC11487, slightly simpler to work with). 00446 // Control over 15/16-bit color is also implemented. Need better documentation and/or test cases to advance the implementation. 00447 /* 00448 REG06 (R/W): Command Register 00449 bit 0 (SC11487) (R) Set if bits 5-7 is 1 or 3, clear otherwise 00450 3-4 (SC11487) Accesses bits 3-4 of the PEL Mask registers (REG02) 00451 5 (not SC11481/6/8) 00452 If set two pixel clocks are used to latch the two bytes 00453 needed for each pixel. Low byte is latched first. 00454 If clear the low byte is latched on the rising edge of the 00455 pixel clock and the high byte is latched on the falling edge. 00456 Only some VGA chips (ET4000 and C&T655x0) can handle this. 00457 6 (SC11485/7/9, OTI66HC, UM70C178) Set in 16bit (64k) modes (Only valid 00458 if bit 7 set). On the SC11482/3/4 this bit is read/writable, but 00459 has no function. On the SC11481/6/8 this bit does not exist. 00460 7 Set in HiColor (32k/64k) modes, clear in palette modes. 00461 Note: This register can also be accessed at 3C6h by reading 3C6h four times, 00462 then all accesses to 3C6h will go the this register until one of the 00463 registers 3C7h, 3C8h or 3C9h is accessed. 00464 */ 00465 00466 // Need to pass-through all DAC registers 00467 void write_p3c6(Bitu port,Bitu val,Bitu iolen); 00468 void write_p3c7(Bitu port,Bitu val,Bitu iolen); 00469 void write_p3c8(Bitu port,Bitu val,Bitu iolen); 00470 void write_p3c9(Bitu port,Bitu val,Bitu iolen); 00471 Bitu read_p3c6(Bitu port,Bitu iolen); 00472 Bitu read_p3c7(Bitu port,Bitu iolen); 00473 Bitu read_p3c8(Bitu port,Bitu iolen); 00474 Bitu read_p3c9(Bitu port,Bitu iolen); 00475 00476 bool et4k_highcolor_half_pixel_rate() { 00477 /* if highcolor and NOT using two clocks per pixel */ 00478 return (et4k.hicolorDACcommand & 0x80) && (!(et4k.hicolorDACcommand & 0x20)); 00479 } 00480 00481 void write_p3c6_et4k(Bitu port,Bitu val,Bitu iolen) { 00482 if (et4k.hicolorDACcmdmode <= 3) { 00483 write_p3c6(port, val, iolen); 00484 } else { 00485 Bit8u command = val & 0xe0; 00486 if (command != et4k.hicolorDACcommand) { 00487 et4k.hicolorDACcommand = command; 00488 DetermineMode_ET4K(); 00489 } 00490 } 00491 } 00492 void write_p3c7_et4k(Bitu port,Bitu val,Bitu iolen) { 00493 et4k.hicolorDACcmdmode = 0; 00494 write_p3c7(port, val, iolen); 00495 } 00496 void write_p3c8_et4k(Bitu port,Bitu val,Bitu iolen) { 00497 et4k.hicolorDACcmdmode = 0; 00498 write_p3c8(port, val, iolen); 00499 } 00500 void write_p3c9_et4k(Bitu port,Bitu val,Bitu iolen) { 00501 et4k.hicolorDACcmdmode = 0; 00502 write_p3c9(port, val, iolen); 00503 } 00504 Bitu read_p3c6_et4k(Bitu port,Bitu iolen) { 00505 if (et4k.hicolorDACcmdmode <= 3) { 00506 if (vga_enable_3C6_ramdac) 00507 et4k.hicolorDACcmdmode++; 00508 00509 return read_p3c6(port, iolen); 00510 } else { 00511 return et4k.hicolorDACcommand; 00512 } 00513 } 00514 Bitu read_p3c7_et4k(Bitu port,Bitu iolen) { 00515 et4k.hicolorDACcmdmode = 0; 00516 return read_p3c7(port, iolen); 00517 } 00518 Bitu read_p3c8_et4k(Bitu port,Bitu iolen) { 00519 et4k.hicolorDACcmdmode = 0; 00520 return read_p3c8(port, iolen); 00521 } 00522 Bitu read_p3c9_et4k(Bitu port,Bitu iolen) { 00523 et4k.hicolorDACcmdmode = 0; 00524 return read_p3c9(port, iolen); 00525 } 00526 00527 void SetupDAC_ET4K() { 00528 IO_RegisterWriteHandler(0x3c6,write_p3c6_et4k,IO_MB); 00529 IO_RegisterReadHandler(0x3c6,read_p3c6_et4k,IO_MB); 00530 IO_RegisterWriteHandler(0x3c7,write_p3c7_et4k,IO_MB); 00531 IO_RegisterReadHandler(0x3c7,read_p3c7_et4k,IO_MB); 00532 IO_RegisterWriteHandler(0x3c8,write_p3c8_et4k,IO_MB); 00533 IO_RegisterReadHandler(0x3c8,read_p3c8_et4k,IO_MB); 00534 IO_RegisterWriteHandler(0x3c9,write_p3c9_et4k,IO_MB); 00535 IO_RegisterReadHandler(0x3c9,read_p3c9_et4k,IO_MB); 00536 } 00537 00538 // BIOS extensions for HiColor-enabled cards 00539 bool INT10_SetVideoMode(Bit16u mode); 00540 00541 void INT10Extensions_ET4K() { 00542 switch (reg_ax) { 00543 case 0x10F0: /* ET4000: SET HiColor GRAPHICS MODE */ 00544 if (INT10_SetVideoMode(0x200 | Bit16u(reg_bl))) { 00545 reg_ax = 0x0010; 00546 } 00547 break; 00548 case 0x10F1: /* ET4000: GET DAC TYPE */ 00549 reg_ax = 0x0010; 00550 if (vga_enable_3C6_ramdac) 00551 reg_bl = 0x01; 00552 else 00553 reg_bl = 0x00; 00554 break; 00555 case 0x10F2: /* ET4000: CHECK/SET HiColor MODE */ 00556 switch (reg_bl) { 00557 case 0: 00558 reg_ax = 0x0010; 00559 break; 00560 case 1: case 2: 00561 { 00562 Bit8u val = (reg_bl == 1) ? 0xa0 : 0xe0; 00563 if (val != et4k.hicolorDACcommand) { 00564 et4k.hicolorDACcommand = val; 00565 DetermineMode_ET4K(); 00566 reg_ax = 0x0010; 00567 } 00568 } 00569 break; 00570 } 00571 switch (et4k.hicolorDACcommand & 0xc0) { 00572 case 0x80: 00573 reg_bl = 1; 00574 break; 00575 case 0xc0: 00576 reg_bl = 2; 00577 break; 00578 default: 00579 reg_bl = 0; 00580 break; 00581 } 00582 } 00583 } 00584 00585 void SVGA_Setup_TsengET4K(void) { 00586 svga.write_p3d5 = &write_p3d5_et4k; 00587 svga.read_p3d5 = &read_p3d5_et4k; 00588 svga.write_p3c5 = &write_p3c5_et4k; 00589 svga.read_p3c5 = &read_p3c5_et4k; 00590 svga.write_p3c0 = &write_p3c0_et4k; 00591 svga.read_p3c1 = &read_p3c1_et4k; 00592 00593 svga.set_video_mode = &FinishSetMode_ET4K; 00594 svga.determine_mode = &DetermineMode_ET4K; 00595 svga.set_clock = &SetClock_ET4K; 00596 svga.get_clock = &GetClock_ET4K; 00597 svga.accepts_mode = &AcceptsMode_ET4K; 00598 svga.setup_dac = &SetupDAC_ET4K; 00599 svga.int10_extensions = &INT10Extensions_ET4K; 00600 00601 // From the depths of X86Config, probably inexact 00602 VGA_SetClock(0,CLK_25); 00603 VGA_SetClock(1,CLK_28); 00604 VGA_SetClock(2,32400); 00605 VGA_SetClock(3,35900); 00606 VGA_SetClock(4,39900); 00607 VGA_SetClock(5,44700); 00608 VGA_SetClock(6,31400); 00609 VGA_SetClock(7,37500); 00610 VGA_SetClock(8,50000); 00611 VGA_SetClock(9,56500); 00612 VGA_SetClock(10,64900); 00613 VGA_SetClock(11,71900); 00614 VGA_SetClock(12,79900); 00615 VGA_SetClock(13,89600); 00616 VGA_SetClock(14,62800); 00617 VGA_SetClock(15,74800); 00618 00619 IO_RegisterReadHandler(0x3cd,read_p3cd_et4k,IO_MB); 00620 IO_RegisterWriteHandler(0x3cd,write_p3cd_et4k,IO_MB); 00621 00622 // Default to 1M of VRAM 00623 if (vga.mem.memsize == 0) 00624 vga.mem.memsize = 1024*1024; 00625 00626 if (vga.mem.memsize < 512*1024) 00627 vga.mem.memsize = 256*1024; 00628 else if (vga.mem.memsize < 1024*1024) 00629 vga.mem.memsize = 512*1024; 00630 else 00631 vga.mem.memsize = 1024*1024; 00632 00633 // Tseng ROM signature 00634 phys_writes(PhysMake(0xc000,0)+0x0075, " Tseng ", 8); 00635 } 00636 00637 00638 // Tseng ET3K implementation 00639 typedef struct { 00640 // Stored exact values of some registers. Documentation only specifies some bits but hardware checks may 00641 // expect other bits to be preserved. 00642 Bitu store_3d4_1b; 00643 Bitu store_3d4_1c; 00644 Bitu store_3d4_1d; 00645 Bitu store_3d4_1e; 00646 Bitu store_3d4_1f; 00647 Bitu store_3d4_20; 00648 Bitu store_3d4_21; 00649 Bitu store_3d4_23; // note that 22 is missing 00650 Bitu store_3d4_24; 00651 Bitu store_3d4_25; 00652 00653 Bitu store_3c0_16; 00654 Bitu store_3c0_17; 00655 00656 Bitu store_3c4_06; 00657 Bitu store_3c4_07; 00658 00659 Bitu clockFreq[8]; 00660 Bitu biosMode; 00661 } SVGA_ET3K_DATA; 00662 00663 static SVGA_ET3K_DATA et3k = { 0,0,0,0,0,0,0,0,0,0, 0,0, 0,0, {0,0,0,0,0,0,0,0}, 0 }; 00664 00665 #define STORE_ET3K(port, index) \ 00666 case 0x##index: \ 00667 et3k.store_##port##_##index = val; \ 00668 break; 00669 00670 #define RESTORE_ET3K(port, index) \ 00671 case 0x##index: \ 00672 return et3k.store_##port##_##index; 00673 00674 00675 void write_p3d5_et3k(Bitu reg,Bitu val,Bitu iolen) { 00676 (void)iolen;//UNUSED 00677 switch(reg) { 00678 // 3d4 index 1bh-21h: Hardware zoom control registers 00679 // I am not sure if there was a piece of software that used these. 00680 // Not implemented and will probably stay this way. 00681 STORE_ET3K(3d4, 1b); 00682 STORE_ET3K(3d4, 1c); 00683 STORE_ET3K(3d4, 1d); 00684 STORE_ET3K(3d4, 1e); 00685 STORE_ET3K(3d4, 1f); 00686 STORE_ET3K(3d4, 20); 00687 STORE_ET3K(3d4, 21); 00688 00689 case 0x23: 00690 /* 00691 3d4h index 23h (R/W): Extended start ET3000 00692 bit 0 Cursor start address bit 16 00693 1 Display start address bit 16 00694 2 Zoom start address bit 16 00695 7 If set memory address 8 is output on the MBSL pin (allowing access to 00696 1MB), if clear the blanking signal is output. 00697 */ 00698 // Only bits 1 and 2 are supported. Bit 2 is related to hardware zoom, bit 7 is too obscure to be useful 00699 et3k.store_3d4_23 = val; 00700 vga.config.display_start = (vga.config.display_start & 0xffff) | ((val & 0x02)<<15); 00701 vga.config.cursor_start = (vga.config.cursor_start & 0xffff) | ((val & 0x01)<<16); 00702 break; 00703 00704 00705 /* 00706 3d4h index 24h (R/W): Compatibility Control 00707 bit 0 Enable Clock Translate if set 00708 1 Clock Select bit 2. Bits 0-1 are in 3C2h/3CCh. 00709 2 Enable tri-state for all output pins if set 00710 3 Enable input A8 of 1MB DRAMs from the INTL output if set 00711 4 Reserved 00712 5 Enable external ROM CRTC translation if set 00713 6 Enable Double Scan and Underline Attribute if set 00714 7 Enable 6845 compatibility if set. 00715 */ 00716 // TODO: Some of these may be worth implementing. 00717 STORE_ET3K(3d4, 24); 00718 00719 00720 case 0x25: 00721 /* 00722 3d4h index 25h (R/W): Overflow High 00723 bit 0 Vertical Blank Start bit 10 00724 1 Vertical Total Start bit 10 00725 2 Vertical Display End bit 10 00726 3 Vertical Sync Start bit 10 00727 4 Line Compare bit 10 00728 5-6 Reserved 00729 7 Vertical Interlace if set 00730 */ 00731 et3k.store_3d4_25 = val; 00732 vga.config.line_compare = (vga.config.line_compare & 0x3ff) | ((val&0x10)<<6); 00733 // Abusing s3 ex_ver_overflow field. This is to be cleaned up later. 00734 { 00735 Bit8u s3val = 00736 ((val & 0x01) << 2) | // vbstart 00737 ((val & 0x02) >> 1) | // vtotal 00738 ((val & 0x04) >> 1) | // vdispend 00739 ((val & 0x08) << 1) | // vsyncstart (?) 00740 ((val & 0x10) << 2); // linecomp 00741 if ((s3val ^ vga.s3.ex_ver_overflow) & 0x3) { 00742 vga.s3.ex_ver_overflow=s3val; 00743 VGA_StartResize(); 00744 } else vga.s3.ex_ver_overflow=s3val; 00745 } 00746 break; 00747 00748 default: 00749 LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:CRTC:ET3K:Write to illegal index %2X", (int)reg); 00750 break; 00751 } 00752 } 00753 00754 Bitu read_p3d5_et3k(Bitu reg,Bitu iolen) { 00755 (void)iolen;//UNUSED 00756 switch(reg) { 00757 RESTORE_ET3K(3d4, 1b); 00758 RESTORE_ET3K(3d4, 1c); 00759 RESTORE_ET3K(3d4, 1d); 00760 RESTORE_ET3K(3d4, 1e); 00761 RESTORE_ET3K(3d4, 1f); 00762 RESTORE_ET3K(3d4, 20); 00763 RESTORE_ET3K(3d4, 21); 00764 RESTORE_ET3K(3d4, 23); 00765 RESTORE_ET3K(3d4, 24); 00766 RESTORE_ET3K(3d4, 25); 00767 default: 00768 LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:CRTC:ET3K:Read from illegal index %2X", (int)reg); 00769 break; 00770 } 00771 return 0x0; 00772 } 00773 00774 void write_p3c5_et3k(Bitu reg,Bitu val,Bitu iolen) { 00775 (void)iolen;//UNUSED 00776 switch(reg) { 00777 // Both registers deal mostly with hardware zoom which is not implemented. Other bits 00778 // seem to be useless for emulation with the exception of index 7 bit 4 (font select) 00779 STORE_ET3K(3c4, 06); 00780 STORE_ET3K(3c4, 07); 00781 default: 00782 LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:SEQ:ET3K:Write to illegal index %2X", (int)reg); 00783 break; 00784 } 00785 } 00786 00787 Bitu read_p3c5_et3k(Bitu reg,Bitu iolen) { 00788 (void)iolen;//UNUSED 00789 switch(reg) { 00790 RESTORE_ET3K(3c4, 06); 00791 RESTORE_ET3K(3c4, 07); 00792 default: 00793 LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:SEQ:ET3K:Read from illegal index %2X", (int)reg); 00794 break; 00795 } 00796 return 0x0; 00797 } 00798 00799 /* 00800 3CDh (R/W): Segment Select 00801 bit 0-2 64k Write bank number 00802 3-5 64k Read bank number 00803 6-7 Segment Configuration. 00804 0 128K segments 00805 1 64K segments 00806 2 1M linear memory 00807 NOTES: 1M linear memory is not supported 00808 */ 00809 void write_p3cd_et3k(Bitu port,Bitu val,Bitu iolen) { 00810 (void)port; 00811 (void)iolen;//UNUSED 00812 vga.svga.bank_write = val & 0x07; 00813 vga.svga.bank_read = (val>>3) & 0x07; 00814 vga.svga.bank_size = (val&0x40)?64*1024:128*1024; 00815 VGA_SetupHandlers(); 00816 } 00817 00818 Bitu read_p3cd_et3k(Bitu port,Bitu iolen) { 00819 (void)port; 00820 (void)iolen;//UNUSED 00821 return (Bitu)(((Bitu)vga.svga.bank_read<<3u)|(Bitu)vga.svga.bank_write|((vga.svga.bank_size==128u*1024u)?0u:0x40u)); 00822 } 00823 00824 void write_p3c0_et3k(Bitu reg,Bitu val,Bitu iolen) { 00825 (void)iolen;//UNUSED 00826 // See ET4K notes. 00827 switch(reg) { 00828 STORE_ET3K(3c0, 16); 00829 STORE_ET3K(3c0, 17); 00830 default: 00831 LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:ATTR:ET3K:Write to illegal index %2X", (int)reg); 00832 break; 00833 } 00834 } 00835 00836 Bitu read_p3c1_et3k(Bitu reg,Bitu iolen) { 00837 (void)iolen;//UNUSED 00838 switch(reg) { 00839 RESTORE_ET3K(3c0, 16); 00840 RESTORE_ET3K(3c0, 17); 00841 default: 00842 LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:ATTR:ET3K:Read from illegal index %2X", (int)reg); 00843 break; 00844 } 00845 return 0x0; 00846 } 00847 00848 /* 00849 These ports are used but have little if any effect on emulation: 00850 3B8h (W): Display Mode Control Register 00851 3BFh (R/W): Hercules Compatibility Mode 00852 3CBh (R/W): PEL Address/Data Wd 00853 3CEh index 0Dh (R/W): Microsequencer Mode 00854 3CEh index 0Eh (R/W): Microsequencer Reset 00855 3d8h (R/W): Display Mode Control 00856 3D9h (W): Color Select Register 00857 3dAh (W): Feature Control Register 00858 3DEh (W); AT&T Mode Control Register 00859 */ 00860 00861 static Bitu get_clock_index_et3k() { 00862 return ((vga.misc_output>>2)&3) | ((et3k.store_3d4_24<<1)&4); 00863 } 00864 00865 static void set_clock_index_et3k(Bitu index) { 00866 // Shortwiring register reads/writes for simplicity 00867 IO_Write(0x3c2, (vga.misc_output&~0x0cu)|((index&3u)<<2u)); 00868 et3k.store_3d4_24 = (et3k.store_3d4_24&~0x02u)|((index&4u)>>1u); 00869 } 00870 00871 void FinishSetMode_ET3K(Bitu crtc_base, VGA_ModeExtraData* modeData) { 00872 et3k.biosMode = modeData->modeNo; 00873 00874 IO_Write(0x3cd, 0x40); // both banks to 0, 64K bank size 00875 00876 // Tseng ET3K does not have horizontal overflow bits 00877 // Reinterpret ver_overflow 00878 Bit8u et4k_ver_overflow = 00879 ((modeData->ver_overflow & 0x01) << 1) | // vtotal10 00880 ((modeData->ver_overflow & 0x02) << 1) | // vdispend10 00881 ((modeData->ver_overflow & 0x04) >> 2) | // vbstart10 00882 ((modeData->ver_overflow & 0x10) >> 1) | // vretrace10 (tseng has vsync start?) 00883 ((modeData->ver_overflow & 0x40) >> 2); // line_compare 00884 IO_Write(crtc_base,0x25);IO_Write(crtc_base+1,et4k_ver_overflow); 00885 00886 // Clear remaining ext CRTC registers 00887 for (Bit8u i=0x16; i<=0x21; i++) { 00888 IO_Write(crtc_base,i); 00889 IO_Write(crtc_base+1,0); 00890 } 00891 00892 IO_Write(crtc_base,0x23);IO_Write(crtc_base+1,0); 00893 IO_Write(crtc_base,0x24);IO_Write(crtc_base+1,0); 00894 // Clear ext SEQ 00895 IO_Write(0x3c4,0x06);IO_Write(0x3c5,0); 00896 IO_Write(0x3c4,0x07);IO_Write(0x3c5,0x40); // 0 in this register breaks WHATVGA 00897 // Clear ext ATTR 00898 IO_Write(0x3c0,0x16);IO_Write(0x3c0,0); 00899 IO_Write(0x3c0,0x17);IO_Write(0x3c0,0); 00900 00901 // Select SVGA clock to get close to 60Hz (not particularly clean implementation) 00902 if (modeData->modeNo > 0x13) { 00903 Bits target = static_cast<Bits>(modeData->vtotal * 8 * modeData->htotal * 60); 00904 Bitu best = 1; 00905 int dist = 100000000; 00906 for (Bitu i = 0; i < 8; i++) { 00907 int cdiff = abs( static_cast<Bit32s>(target - static_cast<Bits>(et3k.clockFreq[i])) ); 00908 if (cdiff < dist) { 00909 best = i; 00910 dist = cdiff; 00911 } 00912 } 00913 set_clock_index_et3k(best); 00914 } 00915 00916 if (svga.determine_mode) 00917 svga.determine_mode(); 00918 00919 // Verified on functioning (at last!) hardware: Tseng ET3000 is the same as ET4000 when 00920 // it comes to chain4 architecture 00921 vga.config.compatible_chain4 = false; 00922 // vga.vmemwrap = vga.mem.memsize; 00923 00924 VGA_SetupHandlers(); 00925 } 00926 00927 void DetermineMode_ET3K() { 00928 // Close replica from the base implementation. It will stay here 00929 // until I figure a way to either distinguish M_VGA and M_LIN8 or 00930 // merge them. 00931 if (vga.attr.mode_control & 1) { 00932 if (vga.gfx.mode & 0x40) VGA_SetMode((et3k.biosMode<=0x13)?M_VGA:M_LIN8); // Ugly... 00933 else if (vga.gfx.mode & 0x20) VGA_SetMode(M_CGA4); 00934 else if ((vga.gfx.miscellaneous & 0x0c)==0x0c) VGA_SetMode(M_CGA2); 00935 else VGA_SetMode((et3k.biosMode<=0x13)?M_EGA:M_LIN4); 00936 } else { 00937 VGA_SetMode(M_TEXT); 00938 } 00939 } 00940 00941 void SetClock_ET3K(Bitu which,Bitu target) { 00942 et3k.clockFreq[which]=1000*target; 00943 VGA_StartResize(); 00944 } 00945 00946 Bitu GetClock_ET3K() { 00947 return et3k.clockFreq[get_clock_index_et3k()]; 00948 } 00949 00950 bool AcceptsMode_ET3K(Bitu mode) { 00951 return mode <= 0x37 && mode != 0x2f && VideoModeMemSize(mode) < vga.mem.memsize; 00952 } 00953 00954 void SVGA_Setup_TsengET3K(void) { 00955 svga.write_p3d5 = &write_p3d5_et3k; 00956 svga.read_p3d5 = &read_p3d5_et3k; 00957 svga.write_p3c5 = &write_p3c5_et3k; 00958 svga.read_p3c5 = &read_p3c5_et3k; 00959 svga.write_p3c0 = &write_p3c0_et3k; 00960 svga.read_p3c1 = &read_p3c1_et3k; 00961 00962 svga.set_video_mode = &FinishSetMode_ET3K; 00963 svga.determine_mode = &DetermineMode_ET3K; 00964 svga.set_clock = &SetClock_ET3K; 00965 svga.get_clock = &GetClock_ET3K; 00966 svga.accepts_mode = &AcceptsMode_ET3K; 00967 00968 VGA_SetClock(0,CLK_25); 00969 VGA_SetClock(1,CLK_28); 00970 VGA_SetClock(2,32400); 00971 VGA_SetClock(3,35900); 00972 VGA_SetClock(4,39900); 00973 VGA_SetClock(5,44700); 00974 VGA_SetClock(6,31400); 00975 VGA_SetClock(7,37500); 00976 00977 IO_RegisterReadHandler(0x3cd,read_p3cd_et3k,IO_MB); 00978 IO_RegisterWriteHandler(0x3cd,write_p3cd_et3k,IO_MB); 00979 00980 vga.mem.memsize = 512*1024; // Cannot figure how this was supposed to work on the real card 00981 00982 // Tseng ROM signature 00983 PhysPt rom_base=PhysMake(0xc000,0); 00984 phys_writeb(rom_base+0x0075,' '); 00985 phys_writeb(rom_base+0x0076,'T'); 00986 phys_writeb(rom_base+0x0077,'s'); 00987 phys_writeb(rom_base+0x0078,'e'); 00988 phys_writeb(rom_base+0x0079,'n'); 00989 phys_writeb(rom_base+0x007a,'g'); 00990 phys_writeb(rom_base+0x007b,' '); 00991 } 00992 00993 // save state support 00994 void POD_Save_VGA_Tseng( std::ostream& stream ) 00995 { 00996 // static globals 00997 00998 00999 // - pure struct data 01000 WRITE_POD( &et4k, et4k ); 01001 WRITE_POD( &et3k, et3k ); 01002 } 01003 01004 01005 void POD_Load_VGA_Tseng( std::istream& stream ) 01006 { 01007 // static globals 01008 01009 01010 // - pure struct data 01011 READ_POD( &et4k, et4k ); 01012 READ_POD( &et3k, et3k ); 01013 }