DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/vga_tseng.cpp
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 }