DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/vga.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 /* NTS: Hardware notes
00020  *
00021  * S3 Virge DX (PCI):
00022  *
00023  *   VGA 256-color chained mode appears to work differently than
00024  *   expected. Groups of 4 pixels are spread across the VGA planes
00025  *   as expected, but actual memory storage of those 32-bit quantities
00026  *   are 4 "bytes" apart (probably the inspiration for DOSBox's
00027  *   chain emulation using addr = ((addr & ~3) << 2) + (addr & 3) when
00028  *   emulating chained mode).
00029  *
00030  *   The attribute controller has a bug where if you attempt to read
00031  *   the palette indexes 0x00-0x0F with PAS=1 (see FreeVGA for more
00032  *   info) the returned value will be correct except for bit 5 which
00033  *   will be 1 i.e. if palette index 0x2 is read in this way and
00034  *   contains 0x02 you will get 0x22 instead. The trick is to write
00035  *   the index with PAS=0 and read the data, then issue the index with
00036  *   PAS=1. Related: the S3 acts as if there are different flip-flops
00037  *   associated with reading vs writing i.e. writing to 0x3C0, then
00038  *   reading port 0x3C1, then writing port 0x3C0, will treat the second
00039  *   write to 0x3C0 as data still, not as an index. Both flip flops are
00040  *   reset by reading 3xAh though.
00041  *
00042  *   VGA BIOS does not support INT 10h TTY functions in VESA BIOS modes.
00043  *
00044  *   Raw planar dumps of the VGA memory in alphanumeric modes suggest
00045  *   that, not only do the cards direct even writes to 0/2 and odd to 1/3,
00046  *   it does so without shifting down the address. So in a raw planar
00047  *   dump, you will see on plane 0 something like "C : \ > " where the
00048  *   spaces are hex 0x00, and in plane 1, something like 0x07 0x00 0x07 0x00 ...
00049  *   the card however (in even/odd mode) does mask out bit A0 which
00050  *   explains why the Plane 1 capture is 0x07 0x00 ... not 0x00 0x07.
00051  *
00052  * ATI Rage 128 (AGP):
00053  *
00054  *   VGA 256-color chained mode appears to work in the same weird way
00055  *   that S3 Virge DX does (see above).
00056  *
00057  *   VGA BIOS supports TTY INT 10h functions in 16 & 256-color modes
00058  *   only. There are apparently INT 10h functions for 15/16bpp modes
00059  *   as well, but they don't appear to render anything except shades
00060  *   of green.
00061  *
00062  *   The VESA BIOS interface seems to have INT 10h aliases for many
00063  *   VBE 1.2 modes i.e. mode 0x110 is also mode 0x42.
00064  *
00065  *   The Attribute Controller palette indexes work as expected in all
00066  *   VGA modes, however in SVGA VESA BIOS modes, the Attribute Controller
00067  *   palette has no effect on output EXCEPT in 16-color (4bpp) VESA BIOS
00068  *   modes.
00069  *
00070  *   Raw planar layout of alphanumeric text modes apply the same rules
00071  *   as mentioned above in the S3 Virge DX description.
00072  *
00073  * Compaq Elite LTE 4/50CX laptop:
00074  *
00075  *   No SVGA modes. All modes work as expected.
00076  *
00077  *   VGA 256-color chained mode acts the same weird way as described
00078  *   above, seems to act like addr = ((addr & ~3) << 2) + (addr & 3)
00079  *
00080  *   There seems to be undocumented INT 10h modes:
00081  *
00082  *        0x22:  640x480x?? INT 10h text is all green and garbled
00083  *        0x28:  320x200x?? INT 10h text is all green and garbled
00084  *        0x32:  640x480x?? INT 10h text is all yellow and garbled
00085  *        0x5E:  640x400x256-color with bank switching
00086  *        0x5F:  640x480x256-color with bank switching
00087  *        0x62:  640x480x?? INT 10h text is all dark gray
00088  *        0x68:  320x200x?? INT 10h text is all dark gray
00089  *        0x72:  640x480x?? INT 10h text is all dark gray
00090  *        0x78:  320x200x?? INT 10h text is all dark gray
00091  *
00092  *   And yet, the BIOS does not implement VESA BIOS extensions. Hm..
00093  *
00094  * Sharp PC-9030 with Cirrus SVGA (1996):
00095  *
00096  *   VGA 256-color chained mode acts the same weird way, as if:
00097  *   addr = ((addr & ~3) << 2) + (addr & 3)
00098  * 
00099  *   All VESA BIOS modes support INT 10h TTY output.
00100  *
00101  * Tseng ET4000AX:
00102  *
00103  *   The ET4000 cards appear to be the ONLY SVGA chipset out there
00104  *   that does NOT do the odd VGA 256-color chained mode that
00105  *   other cards do.
00106  *
00107  *   Chained 256-color on ET4000:
00108  *       addr = addr                             (addr >> 2) byte in planar space, plane select by (addr & 3)
00109  *
00110  *   Other VGA cards:
00111  *       addr = ((addr & ~3) << 2) + (addr & 3)  (addr & ~3) byte in planar space, plane select by (addr & 3)
00112  *
00113  *   I suspect that this difference may be the reason several 1992-1993-ish DOS demos have problems clearing
00114  *   VRAM. It's possible they noticed that zeroing RAM was faster in planar mode, and coded their routines
00115  *   around ET4000 cards, not knowing that Trident, Cirrus, and every VGA clone thereafter implemented the
00116  *   chained 256-color modes differently.
00117  */
00118 
00119 #include "dosbox.h"
00120 #include "setup.h"
00121 #include "video.h"
00122 #include "pic.h"
00123 #include "vga.h"
00124 #include "inout.h"
00125 #include "programs.h"
00126 #include "support.h"
00127 #include "setup.h"
00128 #include "timer.h"
00129 #include "mem.h"
00130 #include "util_units.h"
00131 #include "control.h"
00132 #include "pc98_cg.h"
00133 #include "pc98_dac.h"
00134 #include "pc98_gdc.h"
00135 #include "pc98_gdc_const.h"
00136 #include "mixer.h"
00137 #include "menu.h"
00138 #include "mem.h"
00139 
00140 #include <string.h>
00141 #include <stdlib.h>
00142 #include <string>
00143 #include <stdio.h>
00144 
00145 #if defined(_MSC_VER)
00146 # pragma warning(disable:4244) /* const fmath::local::uint64_t to double possible loss of data */
00147 #endif
00148 
00149 #include "zipfile.h"
00150 
00151 extern ZIPFile savestate_zip;
00152 
00153 using namespace std;
00154 
00155 extern int                          vga_memio_delay_ns;
00156 extern bool                         gdc_5mhz_mode;
00157 extern bool                         enable_pc98_egc;
00158 extern bool                         enable_pc98_grcg;
00159 extern bool                         enable_pc98_16color;
00160 extern bool                         enable_pc98_188usermod;
00161 extern bool                         GDC_vsync_interrupt;
00162 extern uint8_t                      GDC_display_plane;
00163 
00164 extern uint8_t                      pc98_gdc_tile_counter;
00165 extern uint8_t                      pc98_gdc_modereg;
00166 extern uint8_t                      pc98_gdc_vramop;
00167 extern egc_quad                     pc98_gdc_tiles;
00168 
00169 extern uint8_t                      pc98_egc_srcmask[2]; /* host given (Neko: egc.srcmask) */
00170 extern uint8_t                      pc98_egc_maskef[2]; /* effective (Neko: egc.mask2) */
00171 extern uint8_t                      pc98_egc_mask[2]; /* host given (Neko: egc.mask) */
00172 
00173 uint32_t S3_LFB_BASE =              S3_LFB_BASE_DEFAULT;
00174 
00175 bool                                enable_pci_vga = true;
00176 
00177 VGA_Type vga;
00178 SVGA_Driver svga;
00179 int enableCGASnow;
00180 int vesa_modelist_cap = 0;
00181 int vesa_mode_width_cap = 0;
00182 int vesa_mode_height_cap = 0;
00183 bool vesa_bios_modelist_in_info = false;
00184 bool vga_3da_polled = false;
00185 bool vga_page_flip_occurred = false;
00186 bool enable_page_flip_debugging_marker = false;
00187 bool enable_vretrace_poll_debugging_marker = false;
00188 bool vga_enable_hretrace_effects = false;
00189 bool vga_enable_hpel_effects = false;
00190 bool vga_enable_3C6_ramdac = false;
00191 bool vga_sierra_lock_565 = false;
00192 bool enable_vga_resize_delay = false;
00193 bool vga_ignore_hdispend_change_if_smaller = false;
00194 bool ignore_vblank_wraparound = false;
00195 bool non_cga_ignore_oddeven = false;
00196 bool non_cga_ignore_oddeven_engage = false;
00197 bool vga_palette_update_on_full_load = true;
00198 bool vga_double_buffered_line_compare = false;
00199 bool pc98_allow_scanline_effect = true;
00200 bool pc98_allow_4_display_partitions = false;
00201 bool pc98_graphics_hide_odd_raster_200line = false;
00202 bool pc98_attr4_graphic = false;
00203 bool gdc_analog = true;
00204 bool pc98_31khz_mode = false;
00205 bool int10_vesa_map_as_128kb = false;
00206 
00207 unsigned char VGA_AC_remap = AC_4x4;
00208 
00209 unsigned int vga_display_start_hretrace = 0;
00210 float hretrace_fx_avg_weight = 3;
00211 
00212 bool allow_vesa_4bpp_packed = true;
00213 bool allow_vesa_lowres_modes = true;
00214 bool vesa12_modes_32bpp = true;
00215 bool allow_vesa_32bpp = true;
00216 bool allow_vesa_24bpp = true;
00217 bool allow_vesa_16bpp = true;
00218 bool allow_vesa_15bpp = true;
00219 bool allow_vesa_8bpp = true;
00220 bool allow_vesa_4bpp = true;
00221 bool allow_vesa_tty = true;
00222 
00223 void gdc_5mhz_mode_update_vars(void);
00224 void pc98_port6A_command_write(unsigned char b);
00225 void pc98_wait_write(Bitu port,Bitu val,Bitu iolen);
00226 void pc98_crtc_write(Bitu port,Bitu val,Bitu iolen);
00227 void pc98_port68_command_write(unsigned char b);
00228 Bitu pc98_crtc_read(Bitu port,Bitu iolen);
00229 Bitu pc98_a1_read(Bitu port,Bitu iolen);
00230 void pc98_a1_write(Bitu port,Bitu val,Bitu iolen);
00231 void pc98_gdc_write(Bitu port,Bitu val,Bitu iolen);
00232 Bitu pc98_gdc_read(Bitu port,Bitu iolen);
00233 Bitu pc98_egc4a0_read(Bitu port,Bitu iolen);
00234 void pc98_egc4a0_write(Bitu port,Bitu val,Bitu iolen);
00235 Bitu pc98_egc4a0_read_warning(Bitu port,Bitu iolen);
00236 void pc98_egc4a0_write_warning(Bitu port,Bitu val,Bitu iolen);
00237 
00238 void page_flip_debug_notify() {
00239     if (enable_page_flip_debugging_marker)
00240         vga_page_flip_occurred = true;
00241 }
00242 
00243 void vsync_poll_debug_notify() {
00244     if (enable_vretrace_poll_debugging_marker)
00245         vga_3da_polled = true;
00246 }
00247 
00248 Bit32u CGA_2_Table[16];
00249 Bit32u CGA_4_Table[256];
00250 Bit32u CGA_4_HiRes_Table[256];
00251 Bit32u CGA_16_Table[256];
00252 Bit32u TXT_Font_Table[16];
00253 Bit32u TXT_FG_Table[16];
00254 Bit32u TXT_BG_Table[16];
00255 Bit32u ExpandTable[256];
00256 Bit32u Expand16Table[4][16];
00257 Bit32u FillTable[16];
00258 Bit32u ColorTable[16];
00259 double vga_force_refresh_rate = -1;
00260 
00261 void VGA_SetModeNow(VGAModes mode) {
00262     if (vga.mode == mode) return;
00263     vga.mode=mode;
00264     VGA_SetupHandlers();
00265     VGA_StartResize(0);
00266 }
00267 
00268 
00269 void VGA_SetMode(VGAModes mode) {
00270     if (vga.mode == mode) return;
00271     vga.mode=mode;
00272     VGA_SetupHandlers();
00273     VGA_StartResize();
00274 }
00275 
00276 void VGA_DetermineMode(void) {
00277     if (svga.determine_mode) {
00278         svga.determine_mode();
00279         return;
00280     }
00281     /* Test for VGA output active or direct color modes */
00282     switch (vga.s3.misc_control_2 >> 4) {
00283     case 0:
00284         if (vga.attr.mode_control & 1) { // graphics mode
00285             if (IS_VGA_ARCH && ((vga.gfx.mode & 0x40)||(vga.s3.reg_3a&0x10))) {
00286                 // access above 256k?
00287                 if (vga.s3.reg_31 & 0x8) VGA_SetMode(M_LIN8);
00288                 else VGA_SetMode(M_VGA);
00289             }
00290             else if (vga.gfx.mode & 0x20) VGA_SetMode(M_CGA4);
00291             else if ((vga.gfx.miscellaneous & 0x0c)==0x0c) VGA_SetMode(M_CGA2);
00292             else {
00293                 // access above 256k?
00294                 if (vga.s3.reg_31 & 0x8) VGA_SetMode(M_LIN4);
00295                 else VGA_SetMode(M_EGA);
00296             }
00297         } else {
00298             VGA_SetMode(M_TEXT);
00299         }
00300         break;
00301     case 1:VGA_SetMode(M_LIN8);break;
00302     case 3:VGA_SetMode(M_LIN15);break;
00303     case 5:VGA_SetMode(M_LIN16);break;
00304     case 7:VGA_SetMode(M_LIN24);break;
00305     case 13:VGA_SetMode(M_LIN32);break;
00306     case 15:VGA_SetMode(M_PACKED4);break;// hacked
00307     }
00308 }
00309 
00310 void VGA_StartResize(Bitu delay /*=50*/) {
00311     if (!vga.draw.resizing) {
00312         /* even if the user disables the delay, we can avoid a lot of window resizing by at least having 1ms of delay */
00313         if (!enable_vga_resize_delay && delay > 1) delay = 1;
00314 
00315         vga.draw.resizing=true;
00316         if (vga.mode==M_ERROR) delay = 5;
00317         /* Start a resize after delay (default 50 ms) */
00318         if (delay==0) VGA_SetupDrawing(0);
00319         else PIC_AddEvent(VGA_SetupDrawing,(float)delay);
00320     }
00321 }
00322 
00323 #define IS_RESET ((vga.seq.reset&0x3)!=0x3)
00324 #define IS_SCREEN_ON ((vga.seq.clocking_mode&0x20)==0)
00325 //static bool hadReset = false;
00326 
00327 // disabled for later improvement
00328 // Idea behind this: If the sequencer was reset and screen off we can
00329 // Problem is some programs measure the refresh rate after switching mode,
00330 // and get it wrong because of the 50ms guard time.
00331 // On the other side, buggers like UniVBE switch the screen mode several
00332 // times so the window is flickering.
00333 // Also the demos that switch display end on screen (Dowhackado)
00334 // would need some attention
00335 
00336 void VGA_SequReset(bool reset) {
00337     (void)reset;//UNUSED
00338     //if(!reset && !IS_SCREEN_ON) hadReset=true;
00339 }
00340 
00341 void VGA_Screenstate(bool enabled) {
00342     (void)enabled;//UNUSED
00343     /*if(enabled && hadReset) {
00344         hadReset=false;
00345         PIC_RemoveEvents(VGA_SetupDrawing);
00346         VGA_SetupDrawing(0);
00347     }*/
00348 }
00349 
00350 void VGA_SetClock(Bitu which,Bitu target) {
00351     if (svga.set_clock) {
00352         svga.set_clock(which, target);
00353         return;
00354     }
00355     struct{
00356         Bitu n,m;
00357         Bits err;
00358     } best;
00359     best.err=(Bits)target;
00360     best.m=1u;
00361     best.n=1u;
00362     Bitu n,r;
00363     Bits m;
00364 
00365     for (r = 0; r <= 3; r++) {
00366         Bitu f_vco = target * (1u << r);
00367         if (MIN_VCO <= f_vco && f_vco < MAX_VCO) break;
00368     }
00369     for (n=1;n<=31;n++) {
00370         m=(Bits)((target * (n + 2u) * (1u << r) + (S3_CLOCK_REF / 2u)) / S3_CLOCK_REF) - 2u;
00371         if (0 <= m && m <= 127) {
00372             Bitu temp_target = (Bitu)S3_CLOCK(m,n,r);
00373             Bits err = (Bits)(target - temp_target);
00374             if (err < 0) err = -err;
00375             if (err < best.err) {
00376                 best.err = err;
00377                 best.m = (Bitu)m;
00378                 best.n = (Bitu)n;
00379             }
00380         }
00381     }
00382     /* Program the s3 clock chip */
00383     vga.s3.clk[which].m=best.m;
00384     vga.s3.clk[which].r=r;
00385     vga.s3.clk[which].n=best.n;
00386     VGA_StartResize();
00387 }
00388 
00389 void VGA_SetCGA2Table(Bit8u val0,Bit8u val1) {
00390     const Bit8u total[2] = {val0,val1};
00391     for (Bitu i=0;i<16u;i++) {
00392         CGA_2_Table[i]=
00393 #ifdef WORDS_BIGENDIAN
00394             ((Bitu)total[(i >> 0u) & 1u] << 0u  ) | ((Bitu)total[(i >> 1u) & 1u] << 8u  ) |
00395             ((Bitu)total[(i >> 2u) & 1u] << 16u ) | ((Bitu)total[(i >> 3u) & 1u] << 24u );
00396 #else 
00397             ((Bitu)total[(i >> 3u) & 1u] << 0u  ) | ((Bitu)total[(i >> 2u) & 1u] << 8u  ) |
00398             ((Bitu)total[(i >> 1u) & 1u] << 16u ) | ((Bitu)total[(i >> 0u) & 1u] << 24u );
00399 #endif
00400     }
00401 
00402     if (machine == MCH_MCGA) {
00403         VGA_DAC_CombineColor(0x0,val0);
00404         VGA_DAC_CombineColor(0x1,val1);
00405     }
00406 }
00407 
00408 void VGA_SetCGA4Table(Bit8u val0,Bit8u val1,Bit8u val2,Bit8u val3) {
00409     const Bit8u total[4] = {val0,val1,val2,val3};
00410     for (Bitu i=0;i<256u;i++) {
00411         CGA_4_Table[i]=
00412 #ifdef WORDS_BIGENDIAN
00413             ((Bitu)total[(i >> 0u) & 3u] << 0u  ) | ((Bitu)total[(i >> 2u) & 3u] << 8u  ) |
00414             ((Bitu)total[(i >> 4u) & 3u] << 16u ) | ((Bitu)total[(i >> 6u) & 3u] << 24u );
00415 #else
00416             ((Bitu)total[(i >> 6u) & 3u] << 0u  ) | ((Bitu)total[(i >> 4u) & 3u] << 8u  ) |
00417             ((Bitu)total[(i >> 2u) & 3u] << 16u ) | ((Bitu)total[(i >> 0u) & 3u] << 24u );
00418 #endif
00419         CGA_4_HiRes_Table[i]=
00420 #ifdef WORDS_BIGENDIAN
00421             ((Bitu)total[((i >> 0u) & 1u) | ((i >> 3u) & 2u)] << 0u  ) | (Bitu)(total[((i >> 1u) & 1u) | ((i >> 4u) & 2u)] << 8u  ) |
00422             ((Bitu)total[((i >> 2u) & 1u) | ((i >> 5u) & 2u)] << 16u ) | (Bitu)(total[((i >> 3u) & 1u) | ((i >> 6u) & 2u)] << 24u );
00423 #else
00424             ((Bitu)total[((i >> 3u) & 1u) | ((i >> 6u) & 2u)] << 0u  ) | (Bitu)(total[((i >> 2u) & 1u) | ((i >> 5u) & 2u)] << 8u  ) |
00425             ((Bitu)total[((i >> 1u) & 1u) | ((i >> 4u) & 2u)] << 16u ) | (Bitu)(total[((i >> 0u) & 1u) | ((i >> 3u) & 2u)] << 24u );
00426 #endif
00427     }
00428 
00429     if (machine == MCH_MCGA) {
00430         VGA_DAC_CombineColor(0x0,val0);
00431         VGA_DAC_CombineColor(0x1,val1);
00432         VGA_DAC_CombineColor(0x2,val2);
00433         VGA_DAC_CombineColor(0x3,val3);
00434     }
00435 }
00436 
00437 class VFRCRATE : public Program {
00438 public:
00439     void Run(void) {
00440         WriteOut("Video refresh rate.\n\n");
00441         if (cmd->FindExist("/?", false)) {
00442                         WriteOut("VFRCRATE [SET [OFF|PAL|NTSC|rate]\n");
00443                         WriteOut("  SET OFF   unlock\n");
00444                         WriteOut("  SET PAL   lock to PAL frame rate\n");
00445                         WriteOut("  SET NTSC  lock to NTSC frame rate\n");
00446                         WriteOut("  SET rate  lock to integer frame rate, e.g. 15\n");
00447                         WriteOut("  SET rate  lock to decimal frame rate, e.g. 29.97\n");
00448                         WriteOut("  SET rate  lock to fractional frame rate, e.g. 60000/1001\n");
00449                         return;
00450                 }
00451         if (cmd->FindString("SET",temp_line,false)) {
00452             char *x = (char*)temp_line.c_str();
00453 
00454             if (!strncasecmp(x,"off",3))
00455                 vga_force_refresh_rate = -1;
00456             else if (!strncasecmp(x,"ntsc",4))
00457                 vga_force_refresh_rate = 60000.0/1001;
00458             else if (!strncasecmp(x,"pal",3))
00459                 vga_force_refresh_rate = 50;
00460             else if (strchr(x,'.'))
00461                 vga_force_refresh_rate = atof(x);
00462             else {
00463                 /* fraction */
00464                 int major = -1,minor = 0;
00465                 major = strtol(x,&x,0);
00466                 if (*x == '/' || *x == ':') {
00467                     x++; minor = strtol(x,NULL,0);
00468                 }
00469 
00470                 if (major > 0) {
00471                     vga_force_refresh_rate = (double)major;
00472                     if (minor > 1) vga_force_refresh_rate /= minor;
00473                 }
00474             }
00475 
00476             VGA_SetupHandlers();
00477             VGA_StartResize();
00478         }
00479 
00480         if (vga_force_refresh_rate > 0)
00481             WriteOut("Locked to %.3f fps\n",vga_force_refresh_rate);
00482         else
00483             WriteOut("Unlocked\n");
00484     }
00485 };
00486 
00487 static void VFRCRATE_ProgramStart(Program * * make) {
00488     *make=new VFRCRATE;
00489 }
00490 
00497 class CGASNOW : public Program {
00498 public:
00501     void Run(void) {
00502         if(cmd->FindExist("ON")) {
00503             WriteOut("CGA snow enabled\n");
00504             enableCGASnow = 1;
00505             if (vga.mode == M_TEXT || vga.mode == M_TANDY_TEXT) {
00506                 VGA_SetupHandlers();
00507                 VGA_StartResize();
00508             }
00509         }
00510         else if(cmd->FindExist("OFF")) {
00511             WriteOut("CGA snow disabled\n");
00512             enableCGASnow = 0;
00513             if (vga.mode == M_TEXT || vga.mode == M_TANDY_TEXT) {
00514                 VGA_SetupHandlers();
00515                 VGA_StartResize();
00516             }
00517         }
00518         else {
00519             WriteOut("CGA snow currently %s\n",
00520                 enableCGASnow ? "enabled" : "disabled");
00521         }
00522     }
00523 };
00524 
00525 static void CGASNOW_ProgramStart(Program * * make) {
00526     *make=new CGASNOW;
00527 }
00528 
00529 /* TODO: move to general header */
00530 static inline unsigned int int_log2(unsigned int val) {
00531     unsigned int log = 0;
00532     while ((val >>= 1u) != 0u) log++;
00533     return log;
00534 }
00535 
00536 extern bool pcibus_enable;
00537 extern int hack_lfb_yadjust;
00538 extern uint8_t GDC_display_plane_wait_for_vsync;
00539 
00540 void VGA_VsyncUpdateMode(VGA_Vsync vsyncmode);
00541 
00542 VGA_Vsync VGA_Vsync_Decode(const char *vsyncmodestr) {
00543     if (!strcasecmp(vsyncmodestr,"off")) return VS_Off;
00544     else if (!strcasecmp(vsyncmodestr,"on")) return VS_On;
00545     else if (!strcasecmp(vsyncmodestr,"force")) return VS_Force;
00546     else if (!strcasecmp(vsyncmodestr,"host")) return VS_Host;
00547     else
00548         LOG_MSG("Illegal vsync type %s, falling back to off.",vsyncmodestr);
00549 
00550     return VS_Off;
00551 }
00552 
00553 bool has_pcibus_enable(void);
00554 Bit32u MEM_get_address_bits();
00555 
00556 void VGA_Reset(Section*) {
00557     Section_prop * section=static_cast<Section_prop *>(control->GetSection("dosbox"));
00558     bool lfb_default = false;
00559     string str;
00560     int i;
00561 
00562     Bit32u cpu_addr_bits = MEM_get_address_bits();
00563     Bit64u cpu_max_addr = (Bit64u)1 << (Bit64u)cpu_addr_bits;
00564 
00565     LOG(LOG_MISC,LOG_DEBUG)("VGA_Reset() reinitializing VGA emulation");
00566 
00567     GDC_display_plane_wait_for_vsync = section->Get_bool("pc-98 buffer page flip");
00568 
00569     enable_pci_vga = section->Get_bool("pci vga");
00570 
00571     S3_LFB_BASE = section->Get_hex("svga lfb base");
00572     if (S3_LFB_BASE == 0) {
00573         if (cpu_addr_bits >= 32)
00574             S3_LFB_BASE = S3_LFB_BASE_DEFAULT;
00575         else if (cpu_addr_bits >= 26)
00576             S3_LFB_BASE = (enable_pci_vga && has_pcibus_enable()) ? 0x02000000 : 0x03400000;
00577         else if (cpu_addr_bits >= 24)
00578             S3_LFB_BASE = 0x00C00000;
00579         else
00580             S3_LFB_BASE = S3_LFB_BASE_DEFAULT;
00581 
00582         lfb_default = true;
00583     }
00584 
00585     /* no farther than 32MB below the top */
00586     if (S3_LFB_BASE > 0xFE000000UL)
00587         S3_LFB_BASE = 0xFE000000UL;
00588 
00589     /* if the user WANTS the base address to be PCI misaligned, then turn off PCI VGA emulation */
00590     if (enable_pci_vga && has_pcibus_enable() && (S3_LFB_BASE & 0x1FFFFFFul)) {
00591         if (!lfb_default)
00592             LOG(LOG_VGA,LOG_DEBUG)("S3 linear framebuffer was set by user to an address not aligned to 32MB, switching off PCI VGA emulation");
00593 
00594         enable_pci_vga = false;
00595     }
00596     /* if memalias is below 26 bits, PCI VGA emulation is impossible */
00597     if (cpu_addr_bits < 26) {
00598         if (IS_VGA_ARCH && enable_pci_vga && has_pcibus_enable())
00599             LOG(LOG_VGA,LOG_DEBUG)("CPU memalias setting is below 26 bits, switching off PCI VGA emulation");
00600 
00601         enable_pci_vga = false;
00602     }
00603 
00604     if (enable_pci_vga && has_pcibus_enable()) {
00605         /* must be 32MB aligned (PCI) */
00606         S3_LFB_BASE +=  0x0FFFFFFUL;
00607         S3_LFB_BASE &= ~0x1FFFFFFUL;
00608     }
00609     else {
00610         /* must be 64KB aligned (ISA) */
00611         S3_LFB_BASE +=  0x7FFFUL;
00612         S3_LFB_BASE &= ~0xFFFFUL;
00613     }
00614 
00615     /* must not overlap system RAM */
00616     if (S3_LFB_BASE < (MEM_TotalPages()*4096))
00617         S3_LFB_BASE = (MEM_TotalPages()*4096);
00618 
00619     /* if the constraints we imposed make it impossible to maintain the alignment required for PCI,
00620      * then just switch off PCI VGA emulation. */
00621     if (IS_VGA_ARCH && enable_pci_vga && has_pcibus_enable()) {
00622         if (S3_LFB_BASE & 0x1FFFFFFUL) { /* not 32MB aligned */
00623             LOG(LOG_VGA,LOG_DEBUG)("S3 linear framebuffer is not 32MB aligned, switching off PCI VGA emulation");
00624             enable_pci_vga = false;
00625         }
00626     }
00627 
00628     /* announce LFB framebuffer address only if actually emulating the S3 */
00629     if (IS_VGA_ARCH && svgaCard == SVGA_S3Trio)
00630         LOG(LOG_VGA,LOG_DEBUG)("S3 linear framebuffer at 0x%lx%s as %s",
00631             (unsigned long)S3_LFB_BASE,lfb_default?" by default":"",
00632             (enable_pci_vga && has_pcibus_enable()) ? "PCI" : "(E)ISA");
00633 
00634     /* other applicable warnings: */
00635     /* Microsoft Windows 3.1 S3 driver:
00636      *   If the LFB is set to an address below 16MB, the driver will program the base to something
00637      *   odd like 0x73000000 and access MMIO through 0x74000000.
00638      *
00639      *   Because of this, if memalias < 31 and LFB is below 16MB mark, Windows won't use the
00640      *   accelerated features of the S3 emulation properly.
00641      *
00642      *   If memalias=24, the driver hangs and nothing appears on screen.
00643      *
00644      *   As far as I can tell, it's mapping for the LFB, not the MMIO. It uses the MMIO in the
00645      *   A0000-AFFFF range anyway. The failure to blit and draw seems to be caused by mapping the
00646      *   LFB out of range like that and then trying to draw on the LFB.
00647      *
00648      *   As far as I can tell from http://www.vgamuseum.info and the list of S3 cards, the S3 chipsets
00649      *   emulated by DOSBox-X and DOSBox SVN here are all EISA and PCI cards, so it's likely the driver
00650      *   is written around the assumption that memory addresses are the full 32 bits to the card, not
00651      *   just the low 24 seen on the ISA slot. So it is unlikely the driver could ever support the
00652      *   card on a 386SX nor could such a card work on a 386SX. It shouldn't even work on a 486SX
00653      *   (26-bit limit), but it could. */
00654     if (IS_VGA_ARCH && svgaCard == SVGA_S3Trio && cpu_addr_bits <= 24)
00655         LOG(LOG_VGA,LOG_WARN)("S3 linear framebuffer warning: memalias setting is known to cause the Windows 3.1 S3 driver to crash");
00656     if (IS_VGA_ARCH && svgaCard == SVGA_S3Trio && cpu_addr_bits < 31 && S3_LFB_BASE < 0x1000000ul) /* below 16MB and memalias == 31 bits */
00657         LOG(LOG_VGA,LOG_WARN)("S3 linear framebuffer warning: A linear framebuffer below the 16MB mark in physical memory when memalias < 31 is known to have problems with the Windows 3.1 S3 driver");
00658 
00659     pc98_allow_scanline_effect = section->Get_bool("pc-98 allow scanline effect");
00660     mainMenu.get_item("pc98_allow_200scanline").check(pc98_allow_scanline_effect).refresh_item(mainMenu);
00661 
00662     // whether the GDC is running at 2.5MHz or 5.0MHz.
00663     // Some games require the GDC to run at 5.0MHz.
00664     // To enable these games we default to 5.0MHz.
00665     // NTS: There are also games that refuse to run if 5MHz switched on (TH03)
00666     gdc_5mhz_mode = section->Get_bool("pc-98 start gdc at 5mhz");
00667     mainMenu.get_item("pc98_5mhz_gdc").check(gdc_5mhz_mode).refresh_item(mainMenu);
00668 
00669     enable_pc98_egc = section->Get_bool("pc-98 enable egc");
00670     enable_pc98_grcg = section->Get_bool("pc-98 enable grcg");
00671     enable_pc98_16color = section->Get_bool("pc-98 enable 16-color");
00672     enable_pc98_188usermod = section->Get_bool("pc-98 enable 188 user cg");
00673 
00674     // EGC implies GRCG
00675     if (enable_pc98_egc) enable_pc98_grcg = true;
00676 
00677     // EGC implies 16-color
00678     if (enable_pc98_16color) enable_pc98_16color = true;
00679 
00680     str = section->Get_string("vga attribute controller mapping");
00681     if (str == "4x4")
00682         VGA_AC_remap = AC_4x4;
00683     else if (str == "4low")
00684         VGA_AC_remap = AC_low4;
00685     else {
00686         /* auto:
00687          *
00688          * 4x4 by default.
00689          * except for ET4000 which is 4low */
00690         VGA_AC_remap = AC_4x4;
00691         if (IS_VGA_ARCH) {
00692             if (svgaCard == SVGA_TsengET3K || svgaCard == SVGA_TsengET4K)
00693                 VGA_AC_remap = AC_low4;
00694         }
00695     }
00696 
00697     str = section->Get_string("pc-98 video mode");
00698     if (str == "31khz")
00699         pc98_31khz_mode = true;
00700     else if (str == "15khz")/*TODO*/
00701         pc98_31khz_mode = false;
00702     else
00703         pc98_31khz_mode = false;
00704     //TODO: Announce 31-KHz mode in BIOS config area. --yksoft1
00705     
00706     i = section->Get_int("pc-98 allow 4 display partition graphics");
00707     pc98_allow_4_display_partitions = (i < 0/*auto*/ || i == 1/*on*/);
00708     mainMenu.get_item("pc98_allow_4partitions").check(pc98_allow_4_display_partitions).refresh_item(mainMenu);
00709     // TODO: "auto" will default to true if old PC-9801, false if PC-9821, or
00710     //       a more refined automatic choice according to actual hardware.
00711 
00712     mainMenu.get_item("pc98_enable_egc").check(enable_pc98_egc).refresh_item(mainMenu);
00713     mainMenu.get_item("pc98_enable_grcg").check(enable_pc98_grcg).refresh_item(mainMenu);
00714     mainMenu.get_item("pc98_enable_analog").check(enable_pc98_16color).refresh_item(mainMenu);
00715     mainMenu.get_item("pc98_enable_188user").check(enable_pc98_188usermod).refresh_item(mainMenu);
00716 
00717     vga_force_refresh_rate = -1;
00718     str=section->Get_string("forcerate");
00719     if (str == "ntsc")
00720         vga_force_refresh_rate = 60000.0 / 1001;
00721     else if (str == "pal")
00722         vga_force_refresh_rate = 50;
00723     else if (str.find_first_of('/') != string::npos) {
00724         char *p = (char*)str.c_str();
00725         int num = 1,den = 1;
00726         num = strtol(p,&p,0);
00727         if (*p == '/') p++;
00728         den = strtol(p,&p,0);
00729         if (num < 1) num = 1;
00730         if (den < 1) den = 1;
00731         vga_force_refresh_rate = (double)num / den;
00732     }
00733     else {
00734         vga_force_refresh_rate = atof(str.c_str());
00735     }
00736 
00737     enableCGASnow = section->Get_bool("cgasnow");
00738     vesa_modelist_cap = section->Get_int("vesa modelist cap");
00739     vesa_mode_width_cap = section->Get_int("vesa modelist width limit");
00740     vesa_mode_height_cap = section->Get_int("vesa modelist height limit");
00741     vga_enable_3C6_ramdac = section->Get_bool("sierra ramdac");
00742     vga_enable_hpel_effects = section->Get_bool("allow hpel effects");
00743     vga_sierra_lock_565 = section->Get_bool("sierra ramdac lock 565");
00744     hretrace_fx_avg_weight = section->Get_double("hretrace effect weight");
00745     ignore_vblank_wraparound = section->Get_bool("ignore vblank wraparound");
00746     int10_vesa_map_as_128kb = section->Get_bool("vesa map non-lfb modes to 128kb region");
00747     vga_enable_hretrace_effects = section->Get_bool("allow hretrace effects");
00748     enable_page_flip_debugging_marker = section->Get_bool("page flip debug line");
00749     vga_palette_update_on_full_load = section->Get_bool("vga palette update on full load");
00750     non_cga_ignore_oddeven = section->Get_bool("ignore odd-even mode in non-cga modes");
00751     enable_vretrace_poll_debugging_marker = section->Get_bool("vertical retrace poll debug line");
00752     vga_double_buffered_line_compare = section->Get_bool("double-buffered line compare");
00753     hack_lfb_yadjust = section->Get_int("vesa lfb base scanline adjust");
00754     allow_vesa_lowres_modes = section->Get_bool("allow low resolution vesa modes");
00755     vesa12_modes_32bpp = section->Get_bool("vesa vbe 1.2 modes are 32bpp");
00756     allow_vesa_4bpp_packed = section->Get_bool("allow 4bpp packed vesa modes");
00757     allow_vesa_32bpp = section->Get_bool("allow 32bpp vesa modes");
00758     allow_vesa_24bpp = section->Get_bool("allow 24bpp vesa modes");
00759     allow_vesa_16bpp = section->Get_bool("allow 16bpp vesa modes");
00760     allow_vesa_15bpp = section->Get_bool("allow 15bpp vesa modes");
00761     allow_vesa_8bpp = section->Get_bool("allow 8bpp vesa modes");
00762     allow_vesa_4bpp = section->Get_bool("allow 4bpp vesa modes");
00763     allow_vesa_tty = section->Get_bool("allow tty vesa modes");
00764     enable_vga_resize_delay = section->Get_bool("enable vga resize delay");
00765     vga_ignore_hdispend_change_if_smaller = section->Get_bool("resize only on vga active display width increase");
00766     vesa_bios_modelist_in_info = section->Get_bool("vesa vbe put modelist in vesa information");
00767 
00768     /* sanity check: "VBE 1.2 modes 32bpp" doesn't make any sense if neither 24bpp or 32bpp is enabled */
00769     if (!allow_vesa_32bpp && !allow_vesa_24bpp)
00770         vesa12_modes_32bpp = 0;
00771     /* sanity check: "VBE 1.2 modes 32bpp=true" doesn't make sense if the user disabled 32bpp */
00772     else if (vesa12_modes_32bpp && !allow_vesa_32bpp)
00773         vesa12_modes_32bpp = 0;
00774     /* sanity check: "VBE 1.2 modes 32bpp=false" doesn't make sense if the user disabled 24bpp */
00775     else if (!vesa12_modes_32bpp && !allow_vesa_24bpp && allow_vesa_32bpp)
00776         vesa12_modes_32bpp = 1;
00777 
00778     if (vga_force_refresh_rate > 0)
00779         LOG(LOG_VGA,LOG_NORMAL)("VGA forced refresh rate active = %.3f",vga_force_refresh_rate);
00780 
00781     vga.draw.resizing=false;
00782     vga.mode=M_ERROR;           //For first init
00783 
00784     vga_memio_delay_ns = section->Get_int("vmemdelay");
00785     if (vga_memio_delay_ns < 0) {
00786         if (IS_EGAVGA_ARCH) {
00787             if (pcibus_enable) {
00788                 /* some delay based on PCI bus protocol with frame start, turnaround, and burst transfer */
00789                 double t = (1000000000.0 * clockdom_PCI_BCLK.freq_div * (1/*turnaround*/+1/*frame start*/+1/*burst*/-0.25/*fudge*/)) / clockdom_PCI_BCLK.freq;
00790                 vga_memio_delay_ns = (int)floor(t);
00791             }
00792             else {
00793                 /* very optimistic setting, ISA bus cycles are longer than 2, but also the 386/486/Pentium pipeline
00794                  * instruction decoding. so it's not a matter of sucking up enough CPU cycle counts to match the
00795                  * duration of a memory I/O cycle, because real hardware probably has another instruction decode
00796                  * going while it does it.
00797                  *
00798                  * this is long enough to fix some demo's raster effects to work properly but not enough to
00799                  * significantly bring DOS games to a crawl. Apparently, this also fixes Future Crew "Panic!"
00800                  * by making the shadebob take long enough to allow the 3D rotating dot object to finish it's
00801                  * routine just in time to become the FC logo, instead of sitting there waiting awkwardly
00802                  * for 3-5 seconds. */
00803                 double t = (1000000000.0 * clockdom_ISA_BCLK.freq_div * 3.75) / clockdom_ISA_BCLK.freq;
00804                 vga_memio_delay_ns = (int)floor(t);
00805             }
00806         }
00807         else if (machine == MCH_CGA || machine == MCH_HERC || machine == MCH_MDA) {
00808             /* default IBM PC/XT 4.77MHz timing. this is carefully tuned so that Trixter's CGA test program
00809              * times our CGA emulation as having about 305KB/sec reading speed. */
00810             double t = (1000000000.0 * clockdom_ISA_OSC.freq_div * 143) / (clockdom_ISA_OSC.freq * 3);
00811             vga_memio_delay_ns = (int)floor(t);
00812         }
00813         else {
00814             /* dunno. pick something */
00815             double t = (1000000000.0 * clockdom_ISA_BCLK.freq_div * 6) / clockdom_ISA_BCLK.freq;
00816             vga_memio_delay_ns = (int)floor(t);
00817         }
00818     }
00819 
00820     LOG(LOG_VGA,LOG_DEBUG)("VGA memory I/O delay %uns",vga_memio_delay_ns);
00821 
00822     /* mainline compatible vmemsize (in MB)
00823      * plus vmemsizekb for KB-level control.
00824      * then we round up a page.
00825      *
00826      * FIXME: If PCjr/Tandy uses system memory as video memory,
00827      *        can we get away with pointing at system memory
00828      *        directly and not allocate a dedicated char[]
00829      *        array for VRAM? Likewise for VGA emulation of
00830      *        various motherboard chipsets known to "steal"
00831      *        off the top of system RAM, like Intel and
00832      *        Chips & Tech VGA implementations? */
00833     vga.mem.memsize  = _MB_bytes(section->Get_int("vmemsize"));
00834     vga.mem.memsize += _KB_bytes(section->Get_int("vmemsizekb"));
00835     vga.mem.memsize  = (vga.mem.memsize + 0xFFFu) & (~0xFFFu);
00836     /* mainline compatible: vmemsize == 0 means 512KB */
00837     if (vga.mem.memsize == 0) vga.mem.memsize = _KB_bytes(512);
00838 
00839     /* round up to the nearest power of 2 (TODO: Any video hardware that uses non-power-of-2 sizes?).
00840      * A lot of DOSBox's VGA emulation code assumes power-of-2 VRAM sizes especially when wrapping
00841      * memory addresses with (a & (vmemsize - 1)) type code. */
00842     if (!is_power_of_2(vga.mem.memsize)) {
00843         Bitu i = int_log2(vga.mem.memsize) + 1u;
00844         vga.mem.memsize = 1u << i;
00845         LOG(LOG_VGA,LOG_WARN)("VGA RAM size requested is not a power of 2, rounding up to %uKB",vga.mem.memsize>>10);
00846     }
00847 
00848     /* sanity check according to adapter type.
00849      * FIXME: Again it was foolish for DOSBox to standardize on machine=
00850      * for selecting machine type AND video card. */
00851     switch (machine) {
00852         case MCH_HERC:
00853             if (vga.mem.memsize < _KB_bytes(64)) vga.mem.memsize = _KB_bytes(64);
00854             break;
00855         case MCH_MDA:
00856             if (vga.mem.memsize < _KB_bytes(4)) vga.mem.memsize = _KB_bytes(4);
00857             break;
00858         case MCH_CGA:
00859             if (vga.mem.memsize < _KB_bytes(16)) vga.mem.memsize = _KB_bytes(16);
00860             break;
00861         case MCH_TANDY:
00862         case MCH_PCJR:
00863             if (vga.mem.memsize < _KB_bytes(128)) vga.mem.memsize = _KB_bytes(128); /* FIXME: Right? */
00864             break;
00865         case MCH_EGA:
00866                  // EGA cards supported either 64KB, 128KB or 256KB.
00867                  if (vga.mem.memsize <= _KB_bytes(64))  vga.mem.memsize = _KB_bytes(64);
00868             else if (vga.mem.memsize <= _KB_bytes(128)) vga.mem.memsize = _KB_bytes(128);
00869             else                                        vga.mem.memsize = _KB_bytes(256);
00870             break;
00871         case MCH_VGA:
00872             // TODO: There are reports of VGA cards that have less than 256KB in the early days of VGA.
00873             //       How does that work exactly, especially when 640x480 requires about 37KB per plane?
00874             //       Did these cards have some means to chain two bitplanes odd/even in the same way
00875             //       tha EGA did it?
00876             if (vga.mem.memsize < _KB_bytes(256)) vga.mem.memsize = _KB_bytes(256);
00877             break;
00878         case MCH_AMSTRAD:
00879             if (vga.mem.memsize < _KB_bytes(64)) vga.mem.memsize = _KB_bytes(64); /* FIXME: Right? */
00880             break;
00881         case MCH_PC98:
00882             if (vga.mem.memsize < _KB_bytes(512)) vga.mem.memsize = _KB_bytes(512);
00883             break;
00884         case MCH_MCGA:
00885             if (vga.mem.memsize < _KB_bytes(64)) vga.mem.memsize = _KB_bytes(64);
00886             break;
00887         default:
00888             E_Exit("Unexpected machine");
00889     };
00890 
00891     /* I'm sorry, emulating 640x350 4-color chained EGA graphics is
00892      * harder than I thought and would require revision of quite a
00893      * bit of VGA planar emulation to update only bitplane 0 and 2
00894      * in such a manner. --J.C. */
00895     if (IS_EGA_ARCH && vga.mem.memsize < _KB_bytes(128))
00896         LOG_MSG("WARNING: EGA 64KB emulation is very experimental and not well supported");
00897 
00898     if (!IS_PC98_ARCH)
00899         SVGA_Setup_Driver();        // svga video memory size is set here, possibly over-riding the user's selection
00900 
00901     vga.mem.memmask = vga.mem.memsize - 1u;
00902 
00903     LOG(LOG_VGA,LOG_NORMAL)("Video RAM: %uKB",vga.mem.memsize>>10);
00904 
00905     // TODO: If S3 emulation, and linear framebuffer bumps up against the CPU memalias limits,
00906     //       trim Video RAM to fit (within reasonable limits) or else E_Exit() to let the user
00907     //       know of impossible constraints.
00908 
00909     VGA_SetupMemory();      // memory is allocated here
00910     if (!IS_PC98_ARCH) {
00911         VGA_SetupMisc();
00912         VGA_SetupDAC();
00913         VGA_SetupGFX();
00914         VGA_SetupSEQ();
00915         VGA_SetupAttr();
00916         VGA_SetupOther();
00917         VGA_SetupXGA();
00918         VGA_SetClock(0,CLK_25);
00919         VGA_SetClock(1,CLK_28);
00920         /* Generate tables */
00921         VGA_SetCGA2Table(0,1);
00922         VGA_SetCGA4Table(0,1,2,3);
00923     }
00924 
00925     Section_prop * section2=static_cast<Section_prop *>(control->GetSection("vsync"));
00926 
00927     const char * vsyncmodestr;
00928     vsyncmodestr=section2->Get_string("vsyncmode");
00929     void change_output(int output);
00930     change_output(8);
00931     VGA_VsyncUpdateMode(VGA_Vsync_Decode(vsyncmodestr));
00932 
00933     const char * vsyncratestr;
00934     vsyncratestr=section2->Get_string("vsyncrate");
00935     double vsyncrate=70;
00936     if (!strcasecmp(vsyncmodestr,"host")) {
00937 #if defined (WIN32)
00938         DEVMODE devmode;
00939 
00940         if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &devmode))
00941             vsyncrate=devmode.dmDisplayFrequency;
00942         else
00943             sscanf(vsyncratestr,"%lf",&vsyncrate);
00944 #endif
00945     }
00946     else {
00947         sscanf(vsyncratestr,"%lf",&vsyncrate);
00948     }
00949 
00950     vsync.period = (1000.0F)/vsyncrate;
00951 
00952     // TODO: Code to remove programs added by PROGRAMS_MakeFile
00953 
00954     if (machine == MCH_CGA) PROGRAMS_MakeFile("CGASNOW.COM",CGASNOW_ProgramStart);
00955     PROGRAMS_MakeFile("VFRCRATE.COM",VFRCRATE_ProgramStart);
00956 
00957     if (IS_PC98_ARCH) {
00958         void VGA_OnEnterPC98(Section *sec);
00959         void VGA_OnEnterPC98_phase2(Section *sec);
00960         void PC98_FM_OnEnterPC98(Section *sec);
00961 
00962         VGA_OnEnterPC98(NULL);
00963         VGA_OnEnterPC98_phase2(NULL);
00964 
00965         // TODO: Move to separate file
00966         PC98_FM_OnEnterPC98(NULL);
00967     }
00968 }
00969 
00970 extern void VGA_TweakUserVsyncOffset(float val);
00971 void INT10_PC98_CurMode_Relocate(void);
00972 void VGA_UnsetupMisc(void);
00973 void VGA_UnsetupAttr(void);
00974 void VGA_UnsetupDAC(void);
00975 void VGA_UnsetupGFX(void);
00976 void VGA_UnsetupSEQ(void);
00977 
00978 #define gfx(blah) vga.gfx.blah
00979 #define seq(blah) vga.seq.blah
00980 #define crtc(blah) vga.crtc.blah
00981 
00982 void VGA_OnEnterPC98(Section *sec) {
00983     (void)sec;//UNUSED
00984     VGA_UnsetupMisc();
00985     VGA_UnsetupAttr();
00986     VGA_UnsetupDAC();
00987     VGA_UnsetupGFX();
00988     VGA_UnsetupSEQ();
00989 
00990     LOG_MSG("PC-98: GDC is running at %.1fMHz.",gdc_5mhz_mode ? 5.0 : 2.5);
00991 
00992     pc98_egc_srcmask[0] = 0xFF;
00993     pc98_egc_srcmask[1] = 0xFF;
00994     pc98_egc_maskef[0] = 0xFF;
00995     pc98_egc_maskef[1] = 0xFF;
00996     pc98_egc_mask[0] = 0xFF;
00997     pc98_egc_mask[1] = 0xFF;
00998 
00999     for (unsigned int i=0;i < 8;i++)
01000         pc98_pal_digital[i] = i;
01001 
01002     for (unsigned int i=0;i < 8;i++) {
01003         pc98_pal_analog[(i*3) + 0] = (i & 4) ? 0x0F : 0x00;
01004         pc98_pal_analog[(i*3) + 1] = (i & 2) ? 0x0F : 0x00;
01005         pc98_pal_analog[(i*3) + 2] = (i & 1) ? 0x0F : 0x00;
01006 
01007         if (i != 0) {
01008             pc98_pal_analog[((i+8)*3) + 0] = (i & 4) ? 0x0A : 0x00;
01009             pc98_pal_analog[((i+8)*3) + 1] = (i & 2) ? 0x0A : 0x00;
01010             pc98_pal_analog[((i+8)*3) + 2] = (i & 1) ? 0x0A : 0x00;
01011         }
01012         else {
01013             pc98_pal_analog[((i+8)*3) + 0] = 0x07;
01014             pc98_pal_analog[((i+8)*3) + 1] = 0x07;
01015             pc98_pal_analog[((i+8)*3) + 2] = 0x07;
01016         }
01017     }
01018 
01019     pc98_update_palette();
01020 
01021     {
01022         unsigned char r,g,b;
01023 
01024         for (unsigned int i=0;i < 8;i++) {
01025             r = (i & 2) ? 255 : 0;
01026             g = (i & 4) ? 255 : 0;
01027             b = (i & 1) ? 255 : 0;
01028 
01029             if (GFX_bpp >= 24) /* FIXME: Assumes 8:8:8. What happens when desktops start using the 10:10:10 format? */
01030                 pc98_text_palette[i] = ((Bitu)(((Bitu)b << GFX_Bshift) + ((Bitu)g << GFX_Gshift) + ((Bitu)r << GFX_Rshift) + (Bitu)GFX_Amask));
01031             else {
01032                 /* FIXME: PC-98 mode renders as 32bpp regardless (at this time), so we have to fake 32bpp order */
01033                 /*        Since PC-98 itself has 4-bit RGB precision, it might be best to offer a 16bpp rendering mode,
01034                  *        or even just have PC-98 mode stay in 16bpp entirely. */
01035                 if (GFX_Bshift == 0)
01036                     pc98_text_palette[i] = (Bitu)(((Bitu)b <<  0U) + ((Bitu)g <<  8U) + ((Bitu)r << 16U));
01037                 else
01038                     pc98_text_palette[i] = (Bitu)(((Bitu)b << 16U) + ((Bitu)g <<  8U) + ((Bitu)r <<  0U));
01039             }
01040         }
01041     }
01042 
01043     pc98_gdc_tile_counter=0;
01044     pc98_gdc_modereg=0;
01045     for (unsigned int i=0;i < 4;i++) pc98_gdc_tiles[i].w = 0;
01046 
01047     vga.dac.pel_mask = 0xFF;
01048     vga.crtc.maximum_scan_line = 15;
01049 
01050     /* 200-line tradition on PC-98 seems to be to render only every other scanline */
01051     pc98_graphics_hide_odd_raster_200line = true;
01052 
01053     // as a transition to PC-98 GDC emulation, move VGA alphanumeric buffer
01054     // down to A0000-AFFFFh.
01055     gdc_analog = false;
01056     pc98_gdc_vramop &= ~(1 << VOPBIT_ANALOG);
01057     gfx(miscellaneous) &= ~0x0C; /* bits[3:2] = 0 to map A0000-BFFFF */
01058     VGA_DetermineMode();
01059     VGA_SetupHandlers();
01060     VGA_DAC_UpdateColorPalette();
01061     INT10_PC98_CurMode_Relocate(); /* make sure INT 10h knows */
01062 
01063     if(!pc98_31khz_mode) { /* Set up 24KHz hsync 56.42Hz rate */
01064         vga.crtc.horizontal_total = 106 - 5;
01065         vga.crtc.vertical_total = (440 - 2) & 0xFF;
01066         vga.crtc.end_vertical_blanking = (440 - 2 - 8) & 0xFF; // FIXME
01067         vga.crtc.vertical_retrace_start = (440 - 2 - 30) & 0xFF; // FIXME
01068         vga.crtc.vertical_retrace_end = (440 - 2 - 28) & 0xFF; // FIXME
01069         vga.crtc.start_vertical_blanking = (400 + 8) & 0xFF; // FIXME
01070         vga.crtc.overflow |=  0x01;
01071         vga.crtc.overflow &= ~0x20;
01072     } else { //Set up 31-KHz mode. Values guessed according to other 640x400 modes in int10_modes.cpp.
01073         //TODO: Find the right values by inspecting a real PC-9821 system.
01074         vga.crtc.horizontal_total = 100 - 5;
01075         vga.crtc.vertical_total = (449 - 2) & 0xFF;
01076         vga.crtc.end_vertical_blanking = (449 - 2 - 8) & 0xFF; // FIXME
01077         vga.crtc.vertical_retrace_start = (449 - 2 - 30) & 0xFF; // FIXME
01078         vga.crtc.vertical_retrace_end = (449 - 2 - 28) & 0xFF; // FIXME
01079         vga.crtc.start_vertical_blanking = (400 + 8) & 0xFF; // FIXME
01080         vga.crtc.overflow |=  0x01;
01081         vga.crtc.overflow &= ~0x20;
01082     }
01083 
01084     /* 8-char wide mode. change to 25MHz clock to match. */
01085     vga.config.addr_shift = 0;
01086     seq(clocking_mode) |= 1; /* 8-bit wide char */
01087     vga.misc_output &= ~0x0C; /* bits[3:2] = 0 25MHz clock */
01088 
01089     /* PC-98 seems to favor a block cursor */
01090     vga.draw.cursor.enabled = true;
01091     crtc(cursor_start) = 0;
01092     vga.draw.cursor.sline = 0;
01093     crtc(cursor_end) = 15;
01094     vga.draw.cursor.eline = 15;
01095 
01096     /* now, switch to PC-98 video emulation */
01097     for (unsigned int i=0;i < 16;i++) VGA_ATTR_SetPalette(i,i);
01098     for (unsigned int i=0;i < 16;i++) vga.dac.combine[i] = i;
01099 
01100     vga.mode=M_PC98;
01101     assert(vga.mem.memsize >= 0x80000);
01102     memset(vga.mem.linear,0,0x80000);
01103 
01104     VGA_StartResize();
01105 }
01106 
01107 void MEM_ResetPageHandler_Unmapped(Bitu phys_page, Bitu pages);
01108 
01109 void updateGDCpartitions4(bool enable) {
01110     pc98_allow_4_display_partitions = enable;
01111     pc98_gdc[GDC_SLAVE].display_partition_mask = pc98_allow_4_display_partitions ? 3 : 1;
01112 }
01113 
01114 void VGA_OnEnterPC98_phase2(Section *sec) {
01115     (void)sec;//UNUSED
01116     VGA_SetupHandlers();
01117 
01118     /* GDC 2.5/5.0MHz setting is also reflected in BIOS data area and DIP switch registers */
01119     gdc_5mhz_mode_update_vars();
01120 
01121     /* delay I/O port at 0x5F (0.6us) */
01122     IO_RegisterWriteHandler(0x5F,pc98_wait_write,IO_MB);
01123 
01124     /* master GDC at 0x60-0x6F (even)
01125      * slave GDC at 0xA0-0xAF (even) */
01126     for (unsigned int i=0x60;i <= 0xA0;i += 0x40) {
01127         for (unsigned int j=0;j < 0x10;j += 2) {
01128             IO_RegisterWriteHandler(i+j,pc98_gdc_write,IO_MB);
01129             IO_RegisterReadHandler(i+j,pc98_gdc_read,IO_MB);
01130         }
01131     }
01132 
01133     /* There are some font character RAM controls at 0xA1-0xA5 (odd)
01134      * combined with A4000-A4FFF. Found by unknown I/O tracing in DOSBox-X
01135      * and by tracing INT 18h AH=1Ah on an actual system using DEBUG.COM.
01136      *
01137      * If I find documentation on what exactly these ports are, I will
01138      * list them as such.
01139      *
01140      * Some games (Touhou Project) load font RAM directly through these
01141      * ports instead of using the BIOS. */
01142     for (unsigned int i=0xA1;i <= 0xA9;i += 2) {
01143         IO_RegisterWriteHandler(i,pc98_a1_write,IO_MB);
01144     }
01145     /* Touhou Project appears to read font RAM as well */
01146     IO_RegisterReadHandler(0xA9,pc98_a1_read,IO_MB);
01147 
01148     /* CRTC at 0x70-0x7F (even) */
01149     for (unsigned int j=0x70;j < 0x80;j += 2) {
01150         IO_RegisterWriteHandler(j,pc98_crtc_write,IO_MB);
01151         IO_RegisterReadHandler(j,pc98_crtc_read,IO_MB);
01152     }
01153 
01154     /* EGC at 0x4A0-0x4AF (even).
01155      * All I/O ports are 16-bit.
01156      * NTS: On real hardware, doing 8-bit I/O on these ports will often hang the system. */
01157     for (unsigned int i=0;i < 0x10;i += 2) {
01158         IO_RegisterWriteHandler(i+0x4A0,pc98_egc4a0_write_warning,IO_MB);
01159         IO_RegisterWriteHandler(i+0x4A0,pc98_egc4a0_write,        IO_MW);
01160         IO_RegisterWriteHandler(i+0x4A1,pc98_egc4a0_write_warning,IO_MB);
01161         IO_RegisterWriteHandler(i+0x4A1,pc98_egc4a0_write_warning,IO_MW);
01162 
01163         IO_RegisterReadHandler(i+0x4A0,pc98_egc4a0_read_warning,IO_MB);
01164         IO_RegisterReadHandler(i+0x4A0,pc98_egc4a0_read,        IO_MW);
01165         IO_RegisterReadHandler(i+0x4A1,pc98_egc4a0_read_warning,IO_MB);
01166         IO_RegisterReadHandler(i+0x4A1,pc98_egc4a0_read_warning,IO_MW);
01167     }
01168 
01169     pc98_gdc[GDC_MASTER].master_sync = true;
01170     pc98_gdc[GDC_MASTER].display_enable = true;
01171     pc98_gdc[GDC_MASTER].row_height = 16;
01172     pc98_gdc[GDC_MASTER].display_pitch = 80;
01173     pc98_gdc[GDC_MASTER].active_display_words_per_line = 80;
01174     pc98_gdc[GDC_MASTER].display_partition_mask = 3;
01175 
01176     //TODO: Find the correct GDC SYNC parameters in 31-KHz mode by inspecting a real PC-9821.
01177     if(!pc98_31khz_mode) { 
01178         pc98_gdc[GDC_MASTER].force_fifo_complete();
01179         pc98_gdc[GDC_MASTER].write_fifo_command(0x0F/*sync DE=1*/);
01180         pc98_gdc[GDC_MASTER].write_fifo_param(0x10);
01181         pc98_gdc[GDC_MASTER].write_fifo_param(0x4E);
01182         pc98_gdc[GDC_MASTER].write_fifo_param(0x07);
01183         pc98_gdc[GDC_MASTER].write_fifo_param(0x25);
01184         pc98_gdc[GDC_MASTER].force_fifo_complete();
01185         pc98_gdc[GDC_MASTER].write_fifo_param(0x07);
01186         pc98_gdc[GDC_MASTER].write_fifo_param(0x07);
01187         pc98_gdc[GDC_MASTER].write_fifo_param(0x90);
01188         pc98_gdc[GDC_MASTER].write_fifo_param(0x65);
01189         pc98_gdc[GDC_MASTER].force_fifo_complete();
01190     } else { //Use 31KHz HS, VS, VFP, VBP
01191         pc98_gdc[GDC_MASTER].force_fifo_complete();
01192         pc98_gdc[GDC_MASTER].write_fifo_command(0x0F/*sync DE=1*/);
01193         pc98_gdc[GDC_MASTER].write_fifo_param(0x10);
01194         pc98_gdc[GDC_MASTER].write_fifo_param(0x4E);
01195         pc98_gdc[GDC_MASTER].write_fifo_param(0x41);
01196         pc98_gdc[GDC_MASTER].write_fifo_param(0x24);
01197         pc98_gdc[GDC_MASTER].force_fifo_complete();
01198         pc98_gdc[GDC_MASTER].write_fifo_param(0x07); 
01199         pc98_gdc[GDC_MASTER].write_fifo_param(0x0C); 
01200         pc98_gdc[GDC_MASTER].write_fifo_param(0x90);
01201         pc98_gdc[GDC_MASTER].write_fifo_param(0x8D);
01202         pc98_gdc[GDC_MASTER].force_fifo_complete();     
01203     }
01204 
01205     pc98_gdc[GDC_SLAVE].master_sync = false;
01206     pc98_gdc[GDC_SLAVE].display_enable = false;//FIXME
01207     pc98_gdc[GDC_SLAVE].row_height = 1;
01208     pc98_gdc[GDC_SLAVE].display_pitch = 40;
01209     pc98_gdc[GDC_SLAVE].active_display_words_per_line = 40; /* 40 16-bit WORDs per line */
01210     pc98_gdc[GDC_SLAVE].display_partition_mask = pc98_allow_4_display_partitions ? 3 : 1;
01211 
01212     if(!pc98_31khz_mode) {
01213         pc98_gdc[GDC_SLAVE].force_fifo_complete();
01214         pc98_gdc[GDC_SLAVE].write_fifo_command(0x0F/*sync DE=1*/);
01215         pc98_gdc[GDC_SLAVE].write_fifo_param(0x02);
01216         pc98_gdc[GDC_SLAVE].write_fifo_param(0x26);
01217         pc98_gdc[GDC_SLAVE].write_fifo_param(0x03);
01218         pc98_gdc[GDC_SLAVE].write_fifo_param(0x11);
01219         pc98_gdc[GDC_SLAVE].force_fifo_complete();
01220         pc98_gdc[GDC_SLAVE].write_fifo_param(0x83);
01221         pc98_gdc[GDC_SLAVE].write_fifo_param(0x07);
01222         pc98_gdc[GDC_SLAVE].write_fifo_param(0x90);
01223         pc98_gdc[GDC_SLAVE].write_fifo_param(0x65);
01224         pc98_gdc[GDC_SLAVE].force_fifo_complete();
01225     } else { //Use 31KHz HS, VS, VFP, VBP
01226         pc98_gdc[GDC_SLAVE].write_fifo_command(0x0F/*sync DE=1*/);
01227         pc98_gdc[GDC_SLAVE].write_fifo_param(0x02);
01228         pc98_gdc[GDC_SLAVE].write_fifo_param(0x26);
01229         pc98_gdc[GDC_SLAVE].write_fifo_param(0x40);
01230         pc98_gdc[GDC_SLAVE].write_fifo_param(0x10);
01231         pc98_gdc[GDC_SLAVE].force_fifo_complete();
01232         pc98_gdc[GDC_SLAVE].write_fifo_param(0x83);
01233         pc98_gdc[GDC_SLAVE].write_fifo_param(0x0C);
01234         pc98_gdc[GDC_SLAVE].write_fifo_param(0x90);
01235         pc98_gdc[GDC_SLAVE].write_fifo_param(0x8D);
01236         pc98_gdc[GDC_SLAVE].force_fifo_complete();
01237     }
01238 
01239     VGA_StartResize();
01240 }
01241 
01242 void VGA_Destroy(Section*) {
01243     void PC98_FM_Destroy(Section *sec);
01244     PC98_FM_Destroy(NULL);
01245 }
01246 
01247 extern uint8_t                     pc98_pal_analog[256*3]; /* G R B    0x0..0xF */
01248 extern uint8_t                     pc98_pal_digital[8];    /* G R B    0x0..0x7 */
01249 
01250 void pc98_update_palette(void);
01251 
01252 void VGA_LoadState(Section *sec) {
01253     (void)sec;//UNUSED
01254 
01255     if (IS_PC98_ARCH) {
01256         {
01257             ZIPFileEntry *ent = savestate_zip.get_entry("vga.pc98.analog.palette.bin");
01258             if (ent != NULL) {
01259                 ent->rewind();
01260                 ent->read(pc98_pal_analog, 256*3);
01261             }
01262         }
01263 
01264         {
01265             ZIPFileEntry *ent = savestate_zip.get_entry("vga.pc98.digital.palette.bin");
01266             if (ent != NULL) {
01267                 ent->rewind();
01268                 ent->read(pc98_pal_digital, 8);
01269             }
01270         }
01271 
01272         pc98_update_palette();
01273     }
01274     else {
01275         {
01276             ZIPFileEntry *ent = savestate_zip.get_entry("vga.ac.palette.bin");
01277             if (ent != NULL) {
01278                 ent->rewind();
01279                 ent->read(vga.attr.palette, 0x10);
01280             }
01281         }
01282 
01283         {
01284             unsigned char tmp[256 * 3];
01285 
01286             ZIPFileEntry *ent = savestate_zip.get_entry("vga.dac.palette.bin");
01287             if (ent != NULL) {
01288                 ent->rewind();
01289                 ent->read(tmp, 256 * 3);
01290                 for (unsigned int c=0;c < 256;c++) {
01291                     vga.dac.rgb[c].red =   tmp[c*3 + 0];
01292                     vga.dac.rgb[c].green = tmp[c*3 + 1];
01293                     vga.dac.rgb[c].blue =  tmp[c*3 + 2];
01294                 }
01295             }
01296         }
01297 
01298         for (unsigned int i=0;i < 0x10;i++)
01299             VGA_ATTR_SetPalette(i,vga.attr.palette[i]);
01300 
01301         VGA_DAC_UpdateColorPalette();
01302     }
01303 }
01304 
01305 void VGA_SaveState(Section *sec) {
01306     (void)sec;//UNUSED
01307 
01308     if (IS_PC98_ARCH) {
01309         {
01310             ZIPFileEntry *ent = savestate_zip.new_entry("vga.pc98.analog.palette.bin");
01311             if (ent != NULL) {
01312                 ent->write(pc98_pal_analog, 256*3);
01313             }
01314         }
01315 
01316         {
01317             ZIPFileEntry *ent = savestate_zip.new_entry("vga.pc98.digital.palette.bin");
01318             if (ent != NULL) {
01319                 ent->write(pc98_pal_digital, 8);
01320             }
01321         }
01322     }
01323     else {
01324         {
01325             ZIPFileEntry *ent = savestate_zip.new_entry("vga.ac.palette.bin");
01326             if (ent != NULL) {
01327                 ent->write(vga.attr.palette, 0x10);
01328             }
01329         }
01330 
01331         {
01332             unsigned char tmp[256 * 3];
01333 
01334             ZIPFileEntry *ent = savestate_zip.new_entry("vga.dac.palette.bin");
01335             if (ent != NULL) {
01336                 for (unsigned int c=0;c < 256;c++) {
01337                     tmp[c*3 + 0] = vga.dac.rgb[c].red;
01338                     tmp[c*3 + 1] = vga.dac.rgb[c].green;
01339                     tmp[c*3 + 2] = vga.dac.rgb[c].blue;
01340                 }
01341                 ent->write(tmp, 256 * 3);
01342             }
01343         }
01344     }
01345 }
01346 
01347 void VGA_Init() {
01348     string str;
01349     Bitu i,j;
01350 
01351     vga.other.mcga_mode_control = 0;
01352 
01353         vga.config.chained = false;
01354 
01355     vga.draw.render_step = 0;
01356     vga.draw.render_max = 1;
01357 
01358     vga.tandy.draw_base = NULL;
01359     vga.tandy.mem_base = NULL;
01360     LOG(LOG_MISC,LOG_DEBUG)("Initializing VGA");
01361 
01362     VGA_TweakUserVsyncOffset(0.0f);
01363 
01364     for (i=0;i<256;i++) {
01365         ExpandTable[i]=(Bitu)(i + (i << 8u) + (i << 16u) + (i << 24u));
01366     }
01367     for (i=0;i<16;i++) {
01368         TXT_FG_Table[i]=(Bitu)(i + (i << 8u) + (i << 16u) + (i << 24u));
01369         TXT_BG_Table[i]=(Bitu)(i + (i << 8u) + (i << 16u) + (i << 24u));
01370 #ifdef WORDS_BIGENDIAN
01371         FillTable[i]=
01372             ((i & 1u) ? 0xff000000u : 0u) |
01373             ((i & 2u) ? 0x00ff0000u : 0u) |
01374             ((i & 4u) ? 0x0000ff00u : 0u) |
01375             ((i & 8u) ? 0x000000ffu : 0u) ;
01376         TXT_Font_Table[i]=
01377             ((i & 1u) ? 0x000000ffu : 0u) |
01378             ((i & 2u) ? 0x0000ff00u : 0u) |
01379             ((i & 4u) ? 0x00ff0000u : 0u) |
01380             ((i & 8u) ? 0xff000000u : 0u) ;
01381 #else 
01382         FillTable[i]=
01383             ((i & 1u) ? 0x000000ffu : 0u) |
01384             ((i & 2u) ? 0x0000ff00u : 0u) |
01385             ((i & 4u) ? 0x00ff0000u : 0u) |
01386             ((i & 8u) ? 0xff000000u : 0u) ;
01387         TXT_Font_Table[i]=  
01388             ((i & 1u) ? 0xff000000u : 0u) |
01389             ((i & 2u) ? 0x00ff0000u : 0u) |
01390             ((i & 4u) ? 0x0000ff00u : 0u) |
01391             ((i & 8u) ? 0x000000ffu : 0u) ;
01392 #endif
01393     }
01394     for (j=0;j<4;j++) {
01395         for (i=0;i<16;i++) {
01396 #ifdef WORDS_BIGENDIAN
01397             Expand16Table[j][i] =
01398                 ((i & 1u) ? 1u <<        j  : 0u) |
01399                 ((i & 2u) ? 1u << (8u +  j) : 0u) |
01400                 ((i & 4u) ? 1u << (16u + j) : 0u) |
01401                 ((i & 8u) ? 1u << (24u + j) : 0u);
01402 #else
01403             Expand16Table[j][i] =
01404                 ((i & 1u) ? 1u << (24u + j) : 0u) |
01405                 ((i & 2u) ? 1u << (16u + j) : 0u) |
01406                 ((i & 4u) ? 1u << (8u  + j) : 0u) |
01407                 ((i & 8u) ? 1u <<        j  : 0u);
01408 #endif
01409         }
01410     }
01411 
01412     AddExitFunction(AddExitFunctionFuncPair(VGA_Destroy));
01413     AddVMEventFunction(VM_EVENT_RESET,AddVMEventFunctionFuncPair(VGA_Reset));
01414 
01415     AddVMEventFunction(VM_EVENT_LOAD_STATE,AddVMEventFunctionFuncPair(VGA_LoadState));
01416     AddVMEventFunction(VM_EVENT_SAVE_STATE,AddVMEventFunctionFuncPair(VGA_SaveState));
01417 }
01418 
01419 void SVGA_Setup_Driver(void) {
01420     memset(&svga, 0, sizeof(SVGA_Driver));
01421 
01422     switch(svgaCard) {
01423     case SVGA_S3Trio:
01424         SVGA_Setup_S3Trio();
01425         break;
01426     case SVGA_TsengET4K:
01427         SVGA_Setup_TsengET4K();
01428         break;
01429     case SVGA_TsengET3K:
01430         SVGA_Setup_TsengET3K();
01431         break;
01432     case SVGA_ParadisePVGA1A:
01433         SVGA_Setup_ParadisePVGA1A();
01434         break;
01435     default:
01436         break;
01437     }
01438 }