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