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