DOSBox-X
|
00001 /* 00002 * Copyright (C) 2002-2020 The DOSBox Team 00003 * 00004 * This program is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation; either version 2 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License along 00015 * with this program; if not, write to the Free Software Foundation, Inc., 00016 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 */ 00018 00019 /* NTS: Valgrind hunting shows memory leak from C++ new operator somewhere 00020 * with the JACK library indirectly invoked by SDL audio. Can we resolve 00021 * that too eventually? */ 00022 00023 /* NTS: Valgrind hunting also shows one of the section INIT functions (I can't 00024 * yet tell which one because the stack trace doesn't show it) is allocating 00025 * something and is not freeing it. */ 00026 00027 /* NTS: Valgrind hunting has a moderate to high signal-to-noise ratio because 00028 * of memory leaks (lazy memory allocation) from other libraries in the 00029 * system, including: 00030 * 00031 * ncurses 00032 * libSDL 00033 * libX11 and libXCB 00034 * libasound (ALSA sound library) 00035 * PulseAudio library calls 00036 * JACK library calls 00037 * libdl (the dlopen/dlclose functions allocate something and never free it) 00038 * and a whole bunch of unidentified malloc calls without a matching free. 00039 * 00040 * On my dev system, a reported leak of 450KB (77KB possibly lost + 384KB still reachable 00041 * according to Valgrind) is normal. 00042 * 00043 * Now you ask: why do I care so much about Valgrind, memory leaks, and cleaning 00044 * up the code? The less spurious memory leaks, the easier it is to identify 00045 * actual leaks among the noise and to patch them up. Thus, "valgrind hunting" --J.C. */ 00046 00047 #include <stdlib.h> 00048 #include <stdarg.h> 00049 #include <stdio.h> 00050 #include <string.h> 00051 #include <ctime> 00052 #include <unistd.h> 00053 #include "dosbox.h" 00054 #include "debug.h" 00055 #include "cpu.h" 00056 #include "video.h" 00057 #include "pic.h" 00058 #include "cpu.h" 00059 #include "ide.h" 00060 #include "callback.h" 00061 #include "inout.h" 00062 #include "mixer.h" 00063 #include "timer.h" 00064 #include "dos_inc.h" 00065 #include "setup.h" 00066 #include "control.h" 00067 #include "cross.h" 00068 #include "programs.h" 00069 #include "support.h" 00070 #include "mapper.h" 00071 #include "ints/int10.h" 00072 #include "menu.h" 00073 #include "render.h" 00074 #include "pci_bus.h" 00075 #include "parport.h" 00076 #include "clockdomain.h" 00077 #include "zip.h" 00078 #include "unzip.h" 00079 #include "ioapi.h" 00080 #include "shell.h" 00081 #include "build_timestamp.h" 00082 #define MAXU32 0xffffffff 00083 #include "vs2015/zlib/contrib/minizip/zip.c" 00084 #include "vs2015/zlib/contrib/minizip/unzip.c" 00085 #include "vs2015/zlib/contrib/minizip/ioapi.c" 00086 00087 #if C_EMSCRIPTEN 00088 # include <emscripten.h> 00089 #endif 00090 00091 #ifdef WIN32 00092 #define WIN32_LEAN_AND_MEAN 00093 #include <windows.h> 00094 #endif 00095 00096 #if defined(unix) || defined(__APPLE__) 00097 # include <utime.h> 00098 #endif 00099 00100 #include <list> 00101 00102 /*===================================TODO: Move to it's own file==============================*/ 00103 #if defined(__SSE__) && !(defined(_M_AMD64) || defined(__e2k__)) 00104 bool sse2_available = false; 00105 00106 # ifdef __GNUC__ 00107 # define cpuid(func,ax,bx,cx,dx)\ 00108 __asm__ __volatile__ ("cpuid":\ 00109 "=a" (ax), "=b" (bx), "=c" (cx), "=d" (dx) : "a" (func)); 00110 # endif /* __GNUC__ */ 00111 00112 # if defined(_MSC_VER) 00113 # define cpuid(func,a,b,c,d)\ 00114 __asm mov eax, func\ 00115 __asm cpuid\ 00116 __asm mov a, eax\ 00117 __asm mov b, ebx\ 00118 __asm mov c, ecx\ 00119 __asm mov d, edx 00120 # endif /* _MSC_VER */ 00121 00122 void CheckSSESupport() 00123 { 00124 #if (defined (__GNUC__) || (_MSC_VER)) && !defined(EMSCRIPTEN) 00125 Bitu a, b, c, d; 00126 cpuid(1, a, b, c, d); 00127 sse2_available = ((d >> 26) & 1)?true:false; 00128 #endif 00129 } 00130 #endif 00131 /*=============================================================================*/ 00132 00133 extern void GFX_SetTitle(Bit32s cycles,Bits frameskip,Bits timing,bool paused); 00134 00135 extern bool force_nocachedir; 00136 extern bool freesizecap; 00137 extern bool wpcolon; 00138 00139 extern Bitu frames; 00140 extern Bitu cycle_count; 00141 extern bool sse2_available; 00142 extern bool dynamic_dos_kernel_alloc; 00143 extern Bitu DOS_PRIVATE_SEGMENT_Size; 00144 extern bool VGA_BIOS_dont_duplicate_CGA_first_half; 00145 extern bool VIDEO_BIOS_always_carry_14_high_font; 00146 extern bool VIDEO_BIOS_always_carry_16_high_font; 00147 extern bool VIDEO_BIOS_enable_CGA_8x8_second_half; 00148 extern bool allow_more_than_640kb; 00149 00150 Bit32u guest_msdos_LoL = 0; 00151 Bit16u guest_msdos_mcb_chain = 0; 00152 int boothax = BOOTHAX_NONE; 00153 00154 bool want_fm_towns = false; 00155 bool force_load_state = false; 00156 00157 bool dos_con_use_int16_to_detect_input = true; 00158 00159 bool dbg_zero_on_dos_allocmem = true; 00160 bool dbg_zero_on_xms_allocmem = true; 00161 bool dbg_zero_on_ems_allocmem = true; 00162 00163 /* the exact frequency of the NTSC color subcarrier ~3.579545454...MHz or 315/88 */ 00164 /* see: http://en.wikipedia.org/wiki/Colorburst */ 00165 #define NTSC_COLOR_SUBCARRIER_NUM (315000000ULL) 00166 #define NTSC_COLOR_SUBCARRIER_DEN (88ULL) 00167 00168 /* PCI bus clock 00169 * Usual setting: 100MHz / 3 = 33.333MHz 00170 * 90MHz / 3 = 30.000MHz */ 00171 ClockDomain clockdom_PCI_BCLK(100000000,3); /* MASTER 100MHz / 3 = 33.33333MHz */ 00172 00173 /* ISA bus OSC clock (14.31818MHz), using a crystal that is 4x the NTSC subcarrier frequency 3.5795454..MHz */ 00174 ClockDomain clockdom_ISA_OSC(NTSC_COLOR_SUBCARRIER_NUM*4,NTSC_COLOR_SUBCARRIER_DEN); 00175 00176 /* ISA bus clock (varies between 4.77MHz to 8.333MHz) 00177 * PC/XT: ISA oscillator clock (14.31818MHz / 3) = 4.77MHz 00178 * Some systems keep CPU synchronous to bus clock: 4.77MHz, 6MHz, 8MHz, 8.333MHz 00179 * Later systems: 25MHz / 3 = 8.333MHz 00180 * 33MHz / 4 = 8.333MHz 00181 * PCI bus systems: PCI bus clock 33MHz / 4 = 8.333MHz (especially Intel chipsets according to PIIX datasheets) */ 00182 ClockDomain clockdom_ISA_BCLK(25000000,3); /* MASTER 25000000Hz / 3 = 8.333333MHz */ 00183 00184 Config* control; 00185 MachineType machine; 00186 bool PS1AudioCard; // Perhaps have PS1 as a machine type...? 00187 SVGACards svgaCard; 00188 bool SDLNetInited; 00189 Bit32s ticksDone; 00190 Bit32u ticksScheduled; 00191 bool ticksLocked; 00192 bool mono_cga=false; 00193 bool ignore_opcode_63 = true; 00194 int dynamic_core_cache_block_size = 32; 00195 Bitu VGA_BIOS_Size_override = 0; 00196 Bitu VGA_BIOS_SEG = 0xC000; 00197 Bitu VGA_BIOS_SEG_END = 0xC800; 00198 Bitu VGA_BIOS_Size = 0x8000; 00199 00200 Bit32u emulator_speed = 100; 00201 00202 static Bit32u ticksRemain; 00203 static Bit32u ticksRemainSpeedFrac; 00204 static Bit32u ticksLast; 00205 static Bit32u ticksLastFramecounter; 00206 static Bit32u ticksLastRTcounter; 00207 static double ticksLastRTtime; 00208 static Bit32u ticksAdded; 00209 static Bit32u Ticks = 0; 00210 extern double rtdelta; 00211 static LoopHandler* loop; 00212 00213 void increaseticks(); 00214 00215 /* The whole load of startups for all the subfunctions */ 00216 void MEM_Init(Section *); 00217 void ISAPNP_Cfg_Init(Section *); 00218 void ROMBIOS_Init(Section *); 00219 void CALLBACK_Init(Section*); 00220 void PROGRAMS_Init(Section*); 00221 void RENDER_Init(Section*); 00222 void VGA_VsyncInit(Section*); 00223 void VGA_Init(Section*); 00224 void DOS_Init(Section*); 00225 void CPU_Init(Section*); 00226 #if C_FPU 00227 void FPU_Init(Section*); 00228 #endif 00229 void DMA_Init(Section*); 00230 void MIXER_Init(Section*); 00231 void MIDI_Init(Section*); 00232 void HARDWARE_Init(Section*); 00233 void PCIBUS_Init(Section*); 00234 void PCI_Init(Section*); 00235 void VOODOO_Init(Section*); 00236 00237 void IDE_Primary_Init(Section*); 00238 void IDE_Secondary_Init(Section*); 00239 void IDE_Tertiary_Init(Section*); 00240 void IDE_Quaternary_Init(Section*); 00241 void IDE_Quinternary_Init(Section*); 00242 void IDE_Sexternary_Init(Section*); 00243 void IDE_Septernary_Init(Section*); 00244 void IDE_Octernary_Init(Section*); 00245 00246 void FDC_Primary_Init(Section*); 00247 00248 void KEYBOARD_Init(Section*); //TODO This should setup INT 16 too but ok ;) 00249 void JOYSTICK_Init(Section*); 00250 void MOUSE_Init(Section*); 00251 void SBLASTER_Init(Section*); 00252 void GUS_Init(Section*); 00253 void MPU401_Init(Section*); 00254 void PCSPEAKER_Init(Section*); 00255 void TANDYSOUND_Init(Section*); 00256 void DISNEY_Init(Section*); 00257 void PS1SOUND_Init(Section*); 00258 void INNOVA_Init(Section*); 00259 void SERIAL_Init(Section*); 00260 void DONGLE_Init(Section*); 00261 #if C_IPX 00262 void IPX_Init(Section*); 00263 #endif 00264 void PIC_Init(Section*); 00265 void TIMER_Init(Section*); 00266 void BIOS_Init(Section*); 00267 void DEBUG_Init(Section*); 00268 void CMOS_Init(Section*); 00269 void MSCDEX_Init(Section*); 00270 void DRIVES_Init(Section*); 00271 void CDROM_Image_Init(Section*); 00272 void EMS_Init(Section*); 00273 void XMS_Init(Section*); 00274 void DOS_KeyboardLayout_Init(Section*); 00275 void AUTOEXEC_Init(Section*); 00276 void INT10_Init(Section*); 00277 #if C_PRINTER 00278 void PRINTER_Init(Section*); 00279 #endif 00280 00281 signed long long time_to_clockdom(const ClockDomain &src,double t) { 00282 signed long long lt = (signed long long)t; 00283 00284 lt *= (signed long long)src.freq; 00285 lt /= (signed long long)src.freq_div; 00286 return lt; 00287 } 00288 00289 unsigned long long update_clockdom_from_now(ClockDomain &dst) { 00290 signed long long s; 00291 00292 /* PIC_Ticks (if I read the code correctly) is millisecond ticks, units of 1/1000 seconds. 00293 * PIC_TickIndexND() units of submillisecond time in units of 1/CPU_CycleMax. */ 00294 s = (signed long long)((unsigned long long)PIC_Ticks * (unsigned long long)dst.freq); 00295 s += (signed long long)(((unsigned long long)PIC_TickIndexND() * (unsigned long long)dst.freq) / (unsigned long long)CPU_CycleMax); 00296 /* convert down to frequency counts, not freq x 1000 */ 00297 s /= (signed long long)(1000ULL * (unsigned long long)dst.freq_div); 00298 00299 /* guard against time going backwards slightly (as PIC_TickIndexND() will do sometimes by tiny amounts) */ 00300 if (dst.counter < (unsigned long long)s) dst.counter = (unsigned long long)s; 00301 00302 return dst.counter; 00303 } 00304 00305 #include "paging.h" 00306 00307 extern bool rom_bios_vptable_enable; 00308 extern bool rom_bios_8x8_cga_font; 00309 extern bool allow_port_92_reset; 00310 extern bool allow_keyb_reset; 00311 00312 extern bool DOSBox_Paused(); 00313 00314 //#define DEBUG_CYCLE_OVERRUN_CALLBACK 00315 00316 //For trying other delays 00317 #define wrap_delay(a) SDL_Delay(a) 00318 00319 static Bitu Normal_Loop(void) { 00320 bool saved_allow = dosbox_allow_nonrecursive_page_fault; 00321 Bits ret; 00322 00323 if (!menu.hidecycles || menu.showrt) { /* sdlmain.cpp/render.cpp doesn't even maintain the frames count when hiding cycles! */ 00324 Bit32u ticksNew = GetTicks(); 00325 if (ticksNew >= Ticks) { 00326 Bit32u interval = ticksNew - ticksLastFramecounter; 00327 double rtnow = PIC_FullIndex(); 00328 00329 if (interval == 0) interval = 1; // avoid divide by zero 00330 00331 rtdelta = rtnow - ticksLastRTtime; 00332 rtdelta = (rtdelta * 1000) / interval; 00333 00334 ticksLastRTtime = rtnow; 00335 ticksLastFramecounter = Ticks; 00336 Ticks = ticksNew + 500; // next update in 500ms 00337 frames = (frames * 1000) / interval; // compensate for interval, be more exact (FIXME: so can we adjust for fractional frame rates) 00338 GFX_SetTitle((Bit32s)CPU_CycleMax,-1,-1,false); 00339 frames = 0; 00340 } 00341 } 00342 00343 try { 00344 while (1) { 00345 if (PIC_RunQueue()) { 00346 /* now is the time to check for the NMI (Non-maskable interrupt) */ 00347 CPU_Check_NMI(); 00348 00349 saved_allow = dosbox_allow_nonrecursive_page_fault; 00350 dosbox_allow_nonrecursive_page_fault = true; 00351 ret = (*cpudecoder)(); 00352 dosbox_allow_nonrecursive_page_fault = saved_allow; 00353 00354 if (GCC_UNLIKELY(ret<0)) 00355 return 1; 00356 00357 if (ret>0) { 00358 if (GCC_UNLIKELY((unsigned int)ret >= CB_MAX)) 00359 return 0; 00360 00361 extern unsigned int last_callback; 00362 unsigned int p_last_callback = last_callback; 00363 last_callback = (unsigned int)ret; 00364 00365 dosbox_allow_nonrecursive_page_fault = false; 00366 Bitu blah = (*CallBack_Handlers[ret])(); 00367 dosbox_allow_nonrecursive_page_fault = saved_allow; 00368 00369 last_callback = p_last_callback; 00370 00371 #ifdef DEBUG_CYCLE_OVERRUN_CALLBACK 00372 { 00373 extern char* CallBack_Description[CB_MAX]; 00374 00375 /* I/O delay can cause negative CPU_Cycles and PIC event / audio rendering issues */ 00376 cpu_cycles_count_t overrun = -std::min(CPU_Cycles,(cpu_cycles_count_t)0); 00377 00378 if (overrun > (CPU_CycleMax/100)) 00379 LOG_MSG("Normal loop: CPU cycles count overrun by %ld (%.3fms) after callback '%s'\n",(signed long)overrun,(double)overrun / CPU_CycleMax,CallBack_Description[ret]); 00380 } 00381 #endif 00382 00383 if (GCC_UNLIKELY(blah > 0U)) 00384 return blah; 00385 } 00386 #if C_DEBUG 00387 if (DEBUG_ExitLoop()) 00388 return 0; 00389 #endif 00390 } else { 00391 GFX_Events(); 00392 if (DOSBox_Paused() == false && ticksRemain > 0) { 00393 TIMER_AddTick(); 00394 ticksRemain--; 00395 } else { 00396 increaseticks(); 00397 return 0; 00398 } 00399 } 00400 } 00401 } 00402 catch (const GuestPageFaultException& pf) { 00403 Bitu FillFlags(void); 00404 00405 ret = 0; 00406 FillFlags(); 00407 dosbox_allow_nonrecursive_page_fault = false; 00408 CPU_Exception(EXCEPTION_PF, pf.faultcode); 00409 dosbox_allow_nonrecursive_page_fault = saved_allow; 00410 } 00411 catch (int x) { 00412 dosbox_allow_nonrecursive_page_fault = saved_allow; 00413 if (x == 4/*CMOS shutdown*/) { 00414 ret = 0; 00415 // LOG_MSG("CMOS shutdown reset acknowledged"); 00416 } 00417 else { 00418 throw; 00419 } 00420 } 00421 return 0; 00422 } 00423 00424 void increaseticks() { //Make it return ticksRemain and set it in the function above to remove the global variable. 00425 static Bit32s lastsleepDone = -1; 00426 static Bitu sleep1count = 0; 00427 if (GCC_UNLIKELY(ticksLocked)) { // For Fast Forward Mode 00428 ticksRemainSpeedFrac = 0; 00429 ticksRemain = 5; 00430 /* Reset any auto cycle guessing for this frame */ 00431 ticksLast = GetTicks(); 00432 ticksAdded = 0; 00433 ticksDone = 0; 00434 ticksScheduled = 0; 00435 return; 00436 } 00437 Bit32u ticksNew = GetTicks(); 00438 ticksScheduled += ticksAdded; 00439 00440 if (ticksNew <= ticksLast) { //lower should not be possible, only equal. 00441 ticksAdded = 0; 00442 00443 if (!CPU_CycleAutoAdjust || CPU_SkipCycleAutoAdjust || sleep1count < 3) { 00444 wrap_delay(1); 00445 } 00446 else { 00447 /* Certain configurations always give an exact sleepingtime of 1, this causes problems due to the fact that 00448 DOSBox-X keeps track of full blocks. 00449 This code introduces some randomness to the time slept, which improves stability on those configurations 00450 */ 00451 static const Bit32u sleeppattern[] = { 2, 2, 3, 2, 2, 4, 2 }; 00452 static Bit32u sleepindex = 0; 00453 if (ticksDone != lastsleepDone) sleepindex = 0; 00454 wrap_delay(sleeppattern[sleepindex++]); 00455 sleepindex %= sizeof(sleeppattern) / sizeof(sleeppattern[0]); 00456 } 00457 Bit32s timeslept = (Bit32s)(GetTicks() - ticksNew); 00458 // Count how many times in the current block (of 250 ms) the time slept was 1 ms 00459 if (CPU_CycleAutoAdjust && !CPU_SkipCycleAutoAdjust && timeslept == 1) sleep1count++; 00460 lastsleepDone = ticksDone; 00461 00462 // Update ticksDone with the time spent sleeping 00463 ticksDone -= timeslept; 00464 00465 if (ticksDone < 0) 00466 ticksDone = 0; 00467 return; 00468 } 00469 00470 //ticksNew > ticksLast 00471 ticksRemain = ticksNew - ticksLast; 00472 00473 if (emulator_speed != 100u) { 00474 ticksRemain *= emulator_speed; 00475 ticksRemain += ticksRemainSpeedFrac; 00476 ticksRemainSpeedFrac = ticksRemain % 100u; 00477 ticksRemain /= 100u; 00478 } 00479 else { 00480 ticksRemainSpeedFrac = 0; 00481 } 00482 00483 ticksLast = ticksNew; 00484 ticksDone += (Bit32s)ticksRemain; 00485 if (ticksRemain > 20) { 00486 ticksRemain = 20; 00487 } 00488 ticksAdded = ticksRemain; 00489 00490 // Is the system in auto cycle mode guessing? If not just exit. (It can be temporarily disabled) 00491 if (!CPU_CycleAutoAdjust || CPU_SkipCycleAutoAdjust) 00492 return; 00493 00494 if (ticksScheduled >= 250 || ticksDone >= 250 || (ticksAdded > 15 && ticksScheduled >= 5)) { 00495 if (ticksDone < 1) ticksDone = 1; // Protect against div by zero 00496 /* ratio we are aiming for is around 90% usage*/ 00497 Bit32s ratio = (Bit32s)((ticksScheduled * (CPU_CyclePercUsed * 90 * 1024 / 100 / 100)) / ticksDone); 00498 Bit32s new_cmax = (Bit32s)CPU_CycleMax; 00499 Bit64s cproc = (Bit64s)CPU_CycleMax * (Bit64s)ticksScheduled; 00500 if (cproc > 0) { 00501 /* ignore the cycles added due to the IO delay code in order 00502 to have smoother auto cycle adjustments */ 00503 double ratioremoved = (double)CPU_IODelayRemoved / (double)cproc; 00504 if (ratioremoved < 1.0) { 00505 double ratio_not_removed = 1 - ratioremoved; 00506 ratio = (Bit32s)((double)ratio * ratio_not_removed); 00507 /* Don't allow very high ratio which can cause us to lock as we don't scale down 00508 * for very low ratios. High ratio might result because of timing resolution */ 00509 if (ticksScheduled >= 250 && ticksDone < 10 && ratio > 16384) 00510 ratio = 16384; 00511 00512 // Limit the ratio even more when the cycles are already way above the realmode default. 00513 if (ticksScheduled >= 250 && ticksDone < 10 && ratio > 5120 && CPU_CycleMax > 50000) 00514 ratio = 5120; 00515 00516 // When downscaling multiple times in a row, ensure a minimum amount of downscaling 00517 if (ticksAdded > 15 && ticksScheduled >= 5 && ticksScheduled <= 20 && ratio > 800) 00518 ratio = 800; 00519 00520 if (ratio <= 1024) { 00521 // ratio_not_removed = 1.0; //enabling this restores the old formula 00522 double r = (1.0 + ratio_not_removed) / (ratio_not_removed + 1024.0 / (static_cast<double>(ratio))); 00523 new_cmax = 1 + static_cast<Bit32s>(CPU_CycleMax * r); 00524 } 00525 else { 00526 Bit64s ratio_with_removed = (Bit64s)((((double)ratio - 1024.0) * ratio_not_removed) + 1024.0); 00527 Bit64s cmax_scaled = (Bit64s)CPU_CycleMax * ratio_with_removed; 00528 new_cmax = (Bit32s)(1 + (CPU_CycleMax >> 1) + cmax_scaled / (Bit64s)2048); 00529 } 00530 } 00531 } 00532 00533 if (new_cmax < CPU_CYCLES_LOWER_LIMIT) 00534 new_cmax = CPU_CYCLES_LOWER_LIMIT; 00535 00536 /* 00537 LOG_MSG("cyclelog: current %6d cmax %6d ratio %5d done %3d sched %3d", 00538 CPU_CycleMax, 00539 new_cmax, 00540 ratio, 00541 ticksDone, 00542 ticksScheduled); 00543 */ 00544 /* ratios below 1% are considered to be dropouts due to 00545 temporary load imbalance, the cycles adjusting is skipped */ 00546 if (ratio > 10) { 00547 /* ratios below 12% along with a large time since the last update 00548 has taken place are most likely caused by heavy load through a 00549 different application, the cycles adjusting is skipped as well */ 00550 if ((ratio > 120) || (ticksDone < 700)) { 00551 CPU_CycleMax = new_cmax; 00552 if (CPU_CycleLimit > 0) { 00553 if (CPU_CycleMax > CPU_CycleLimit) CPU_CycleMax = CPU_CycleLimit; 00554 } 00555 else if (CPU_CycleMax > 2000000) CPU_CycleMax = 2000000; //Hardcoded limit, if no limit was specified. 00556 } 00557 } 00558 00559 //Reset cycleguessing parameters. 00560 CPU_IODelayRemoved = 0; 00561 ticksDone = 0; 00562 ticksScheduled = 0; 00563 lastsleepDone = -1; 00564 sleep1count = 0; 00565 } 00566 else if (ticksAdded > 15) { 00567 /* ticksAdded > 15 but ticksScheduled < 5, lower the cycles 00568 but do not reset the scheduled/done ticks to take them into 00569 account during the next auto cycle adjustment */ 00570 CPU_CycleMax /= 3; 00571 if (CPU_CycleMax < CPU_CYCLES_LOWER_LIMIT) 00572 CPU_CycleMax = CPU_CYCLES_LOWER_LIMIT; 00573 } 00574 } 00575 00576 LoopHandler *DOSBOX_GetLoop(void) { 00577 return loop; 00578 } 00579 00580 void DOSBOX_SetLoop(LoopHandler * handler) { 00581 loop=handler; 00582 } 00583 00584 void DOSBOX_SetNormalLoop() { 00585 loop=Normal_Loop; 00586 } 00587 00588 //#define DEBUG_RECURSION 00589 00590 #ifdef DEBUG_RECURSION 00591 volatile int runmachine_recursion = 0; 00592 #endif 00593 00594 void DOSBOX_RunMachine(void){ 00595 Bitu ret; 00596 00597 extern unsigned int last_callback; 00598 unsigned int p_last_callback = last_callback; 00599 last_callback = 0; 00600 00601 #ifdef DEBUG_RECURSION 00602 if (runmachine_recursion++ != 0) 00603 LOG_MSG("RunMachine recursion"); 00604 #endif 00605 00606 do { 00607 ret=(*loop)(); 00608 } while (!ret); 00609 00610 #ifdef DEBUG_RECURSION 00611 if (--runmachine_recursion < 0) 00612 LOG_MSG("RunMachine recursion leave error"); 00613 #endif 00614 00615 last_callback = p_last_callback; 00616 } 00617 00618 static void DOSBOX_UnlockSpeed( bool pressed ) { 00619 static bool autoadjust = false; 00620 if (pressed) { 00621 LOG_MSG("Fast Forward ON"); 00622 ticksLocked = true; 00623 if (CPU_CycleAutoAdjust) { 00624 autoadjust = true; 00625 CPU_CycleAutoAdjust = false; 00626 CPU_CycleMax /= 3; 00627 if (CPU_CycleMax<1000) CPU_CycleMax=1000; 00628 } 00629 } else { 00630 LOG_MSG("Fast Forward OFF"); 00631 ticksLocked = false; 00632 if (autoadjust) { 00633 autoadjust = false; 00634 CPU_CycleAutoAdjust = true; 00635 } 00636 } 00637 GFX_SetTitle(-1,-1,-1,false); 00638 } 00639 00640 void DOSBOX_UnlockSpeed2( bool pressed ) { 00641 if (pressed) { 00642 ticksLocked = !ticksLocked; 00643 DOSBOX_UnlockSpeed(ticksLocked?true:false); 00644 00645 /* make sure the menu item keeps up with our state */ 00646 mainMenu.get_item("mapper_speedlock2").check(ticksLocked).refresh_item(mainMenu); 00647 } 00648 } 00649 00650 void DOSBOX_NormalSpeed( bool pressed ) { 00651 if (pressed) { 00652 /* should also cancel turbo mode */ 00653 if (ticksLocked) 00654 DOSBOX_UnlockSpeed2(true); 00655 00656 LOG_MSG("Emulation speed restored to normal (100%%)"); 00657 00658 emulator_speed = 100; 00659 ticksRemainSpeedFrac = 0; 00660 } 00661 } 00662 00663 void DOSBOX_SpeedUp( bool pressed ) { 00664 if (pressed) { 00665 ticksRemainSpeedFrac = 0; 00666 if (emulator_speed >= 5) 00667 emulator_speed += 5; 00668 else 00669 emulator_speed = 5; 00670 00671 LOG_MSG("Emulation speed increased to (%u%%)",(unsigned int)emulator_speed); 00672 } 00673 } 00674 00675 void DOSBOX_SlowDown( bool pressed ) { 00676 if (pressed) { 00677 ticksRemainSpeedFrac = 0; 00678 if (emulator_speed > 5) 00679 emulator_speed -= 5; 00680 else 00681 emulator_speed = 1; 00682 00683 LOG_MSG("Emulation speed decreased to (%u%%)",(unsigned int)emulator_speed); 00684 } 00685 } 00686 00687 namespace 00688 { 00689 std::string getTime() 00690 { 00691 const time_t current = time(NULL); 00692 tm* timeinfo; 00693 timeinfo = localtime(¤t); //convert to local time 00694 char buffer[50]; 00695 ::strftime(buffer, 50, "%H:%M:%S", timeinfo); 00696 return buffer; 00697 } 00698 00699 class SlotPos 00700 { 00701 public: 00702 SlotPos() : slot(0) {} 00703 00704 void next() 00705 { 00706 ++slot; 00707 slot %= SaveState::SLOT_COUNT; 00708 } 00709 00710 void previous() 00711 { 00712 slot += SaveState::SLOT_COUNT - 1; 00713 slot %= SaveState::SLOT_COUNT; 00714 } 00715 00716 void set(int value) 00717 { 00718 slot = value; 00719 } 00720 00721 operator size_t() const 00722 { 00723 return slot; 00724 } 00725 private: 00726 size_t slot; 00727 } currentSlot; 00728 00729 void notifyError(const std::string& message) 00730 { 00731 #ifdef WIN32 00732 ::MessageBox(0, message.c_str(), "Error", 0); 00733 #endif 00734 LOG_MSG("%s",message.c_str()); 00735 } 00736 00737 size_t GetGameState(void) { 00738 return currentSlot; 00739 } 00740 00741 void SetGameState(int value) { 00742 char name[6]="slot0"; 00743 name[4]='0'+currentSlot; 00744 mainMenu.get_item(name).check(false).refresh_item(mainMenu); 00745 currentSlot.set(value); 00746 name[4]='0'+currentSlot; 00747 mainMenu.get_item(name).check(true).refresh_item(mainMenu); 00748 00749 const bool emptySlot = SaveState::instance().isEmpty(currentSlot); 00750 LOG_MSG("Active save slot: %d %s", (int)currentSlot + 1, emptySlot ? "[Empty]" : ""); 00751 } 00752 00753 void SaveGameState(bool pressed) { 00754 if (!pressed) return; 00755 00756 try 00757 { 00758 SaveState::instance().save(currentSlot); 00759 LOG_MSG("[%s]: State %d saved!", getTime().c_str(), (int)currentSlot + 1); 00760 char name[6]="slot0"; 00761 name[4]='0'+currentSlot; 00762 std::string command=SaveState::instance().getName(currentSlot); 00763 std::string str="Slot "+(currentSlot>=9?"10":std::string(1, '1'+currentSlot))+(command=="[Empty]"?" [Empty slot]":(command==""?"":" (Program: "+command+")")); 00764 mainMenu.get_item(name).set_text(str.c_str()).refresh_item(mainMenu); 00765 } 00766 catch (const SaveState::Error& err) 00767 { 00768 notifyError(err); 00769 } 00770 } 00771 00772 void LoadGameState(bool pressed) { 00773 if (!pressed) return; 00774 00775 // if (SaveState::instance().isEmpty(currentSlot)) 00776 // { 00777 // LOG_MSG("[%s]: State %d is empty!", getTime().c_str(), currentSlot + 1); 00778 // return; 00779 // } 00780 try 00781 { 00782 SaveState::instance().load(currentSlot); 00783 LOG_MSG("[%s]: State %d loaded!", getTime().c_str(), (int)currentSlot + 1); 00784 } 00785 catch (const SaveState::Error& err) 00786 { 00787 notifyError(err); 00788 } 00789 } 00790 00791 void NextSaveSlot(bool pressed) { 00792 if (!pressed) return; 00793 00794 char name[6]="slot0"; 00795 name[4]='0'+currentSlot; 00796 mainMenu.get_item(name).check(false).refresh_item(mainMenu); 00797 currentSlot.next(); 00798 name[4]='0'+currentSlot; 00799 mainMenu.get_item(name).check(true).refresh_item(mainMenu); 00800 00801 const bool emptySlot = SaveState::instance().isEmpty(currentSlot); 00802 LOG_MSG("Active save slot: %d %s", (int)currentSlot + 1, emptySlot ? "[Empty]" : ""); 00803 } 00804 00805 00806 void PreviousSaveSlot(bool pressed) { 00807 if (!pressed) return; 00808 00809 char name[6]="slot0"; 00810 name[4]='0'+currentSlot; 00811 mainMenu.get_item(name).check(false).refresh_item(mainMenu); 00812 currentSlot.previous(); 00813 name[4]='0'+currentSlot; 00814 mainMenu.get_item(name).check(true).refresh_item(mainMenu); 00815 00816 const bool emptySlot = SaveState::instance().isEmpty(currentSlot); 00817 LOG_MSG("Active save slot: %d %s", (int)currentSlot + 1, emptySlot ? "[Empty]" : ""); 00818 } 00819 } 00820 00821 std::string GetPlatform(void) { 00822 char platform[30]; 00823 strcpy(platform, 00824 #if defined(WIN32) 00825 "Windows" 00826 #elif defined(LINUX) 00827 "Linux" 00828 #elif unix 00829 "Unix" 00830 #elif defined(MACOSX) 00831 "macOS" 00832 #else 00833 "Other" 00834 #endif 00835 ); 00836 #if defined(_M_X64) || defined (_M_AMD64) || defined (_M_ARM64) 00837 strcat(platform, " 64"); 00838 #else 00839 strcat(platform, " 32"); 00840 #endif 00841 strcat(platform, "-bit build"); 00842 return std::string(platform); 00843 } 00844 00845 size_t GetGameState_Run(void) { return GetGameState(); } 00846 void SetGameState_Run(int value) { SetGameState(value); } 00847 void SaveGameState_Run(void) { SaveGameState(true); } 00848 void LoadGameState_Run(void) { LoadGameState(true); } 00849 void NextSaveSlot_Run(void) { NextSaveSlot(true); } 00850 void PreviousSaveSlot_Run(void) { PreviousSaveSlot(true); } 00851 00852 /* TODO: move to utility header */ 00853 #ifdef _MSC_VER /* Microsoft C++ does not have strtoull */ 00854 # if _MSC_VER < 1800 /* But Visual Studio 2013 apparently does (http://www.vogons.org/viewtopic.php?f=41&t=31881&sid=49ff69ebc0459ed6523f5a250daa4d8c&start=400#p355770) */ 00855 unsigned long long strtoull(const char *s,char **endptr,int base) { 00856 return _strtoui64(s,endptr,base); /* pfff... whatever Microsoft */ 00857 } 00858 # endif 00859 #endif 00860 00861 /* utility function. rename as appropriate and move to utility collection */ 00862 void parse_busclk_setting_str(ClockDomain *cd,const char *s) { 00863 const char *d; 00864 00865 /* we're expecting an integer, a float, or an integer ratio */ 00866 d = strchr(s,'/'); 00867 if (d != NULL) { /* it has a slash therefore an integer ratio */ 00868 unsigned long long num,den; 00869 00870 while (*d == ' ' || *d == '/') d++; 00871 num = strtoull(s,NULL,0); 00872 den = strtoull(d,NULL,0); 00873 if (num >= 1ULL && den >= 1ULL) cd->set_frequency(num,den); 00874 } 00875 else { 00876 d = strchr(s,'.'); 00877 if (d != NULL) { /* it has a dot, floating point */ 00878 double f = atof(s); 00879 unsigned long long fi = (unsigned long long)floor((f*1000000)+0.5); 00880 unsigned long long den = 1000000; 00881 00882 while (den > 1ULL) { 00883 if ((fi%10ULL) == 0) { 00884 den /= 10ULL; 00885 fi /= 10ULL; 00886 } 00887 else { 00888 break; 00889 } 00890 } 00891 00892 if (fi >= 1ULL) cd->set_frequency(fi,den); 00893 } 00894 else { 00895 unsigned long long f = strtoull(s,NULL,10); 00896 if (f >= 1ULL) cd->set_frequency(f,1); 00897 } 00898 } 00899 } 00900 00901 unsigned int dosbox_shell_env_size = 0; 00902 00903 void Null_Init(Section *sec) { 00904 (void)sec; 00905 } 00906 00907 extern Bit8u cga_comp; 00908 extern bool new_cga; 00909 00910 bool dpi_aware_enable = true; 00911 00912 std::string dosbox_title; 00913 00914 void DOSBOX_InitTickLoop() { 00915 LOG(LOG_MISC,LOG_DEBUG)("Initializing tick loop management"); 00916 00917 ticksRemain = 0; 00918 ticksLocked = false; 00919 ticksLastRTtime = 0; 00920 ticksLast = GetTicks(); 00921 ticksLastRTcounter = GetTicks(); 00922 ticksLastFramecounter = GetTicks(); 00923 DOSBOX_SetLoop(&Normal_Loop); 00924 } 00925 00926 void Init_VGABIOS() { 00927 Section_prop *section = static_cast<Section_prop *>(control->GetSection("dosbox")); 00928 assert(section != NULL); 00929 00930 if (IS_PC98_ARCH) { 00931 // There IS no VGA BIOS, this is PC-98 mode! 00932 VGA_BIOS_SEG = 0xC000; 00933 VGA_BIOS_SEG_END = 0xC000; // Important: DOS kernel uses this to determine where to place the private area! 00934 VGA_BIOS_Size = 0; 00935 return; 00936 } 00937 00938 // log 00939 LOG(LOG_MISC,LOG_DEBUG)("Init_VGABIOS: Initializing VGA BIOS and parsing it's settings"); 00940 00941 // mem init must have already happened. 00942 // We can remove this once the device callout system is in place. 00943 assert(MemBase != NULL); 00944 00945 force_nocachedir = section->Get_bool("nocachedir"); 00946 freesizecap = section->Get_bool("freesizecap"); 00947 wpcolon = section->Get_bool("leading colon write protect image"); 00948 00949 VGA_BIOS_Size_override = (Bitu)section->Get_int("vga bios size override"); 00950 if (VGA_BIOS_Size_override > 0) VGA_BIOS_Size_override = (VGA_BIOS_Size_override+0x7FFU)&(~0xFFFU); 00951 00952 VGA_BIOS_dont_duplicate_CGA_first_half = section->Get_bool("video bios dont duplicate cga first half rom font"); 00953 VIDEO_BIOS_always_carry_14_high_font = section->Get_bool("video bios always offer 14-pixel high rom font"); 00954 VIDEO_BIOS_always_carry_16_high_font = section->Get_bool("video bios always offer 16-pixel high rom font"); 00955 VIDEO_BIOS_enable_CGA_8x8_second_half = section->Get_bool("video bios enable cga second half rom font"); 00956 /* NTS: mainline compatible mapping demands the 8x8 CGA font */ 00957 rom_bios_8x8_cga_font = section->Get_bool("rom bios 8x8 CGA font"); 00958 rom_bios_vptable_enable = section->Get_bool("rom bios video parameter table"); 00959 00960 /* sanity check */ 00961 if (VGA_BIOS_dont_duplicate_CGA_first_half && !rom_bios_8x8_cga_font) /* can't point at the BIOS copy if it's not there */ 00962 VGA_BIOS_dont_duplicate_CGA_first_half = false; 00963 00964 if (VGA_BIOS_Size_override >= 512 && VGA_BIOS_Size_override <= 65536) 00965 VGA_BIOS_Size = (VGA_BIOS_Size_override + 0x7FFU) & (~0xFFFU); 00966 else if (IS_VGA_ARCH) { 00967 if (svgaCard == SVGA_S3Trio) 00968 VGA_BIOS_Size = 0x4000; 00969 else 00970 VGA_BIOS_Size = 0x4000; // FIXME: Why does 0x3800 cause Windows 3.0 386 enhanced mode to hang? 00971 } 00972 else if (machine == MCH_EGA) { 00973 if (VIDEO_BIOS_always_carry_16_high_font) 00974 VGA_BIOS_Size = 0x3000; 00975 else 00976 VGA_BIOS_Size = 0x2000; 00977 } 00978 else { 00979 if (VIDEO_BIOS_always_carry_16_high_font && VIDEO_BIOS_always_carry_14_high_font) 00980 VGA_BIOS_Size = 0x3000; 00981 else if (VIDEO_BIOS_always_carry_16_high_font || VIDEO_BIOS_always_carry_14_high_font) 00982 VGA_BIOS_Size = 0x2000; 00983 else 00984 VGA_BIOS_Size = 0; 00985 } 00986 VGA_BIOS_SEG = 0xC000; 00987 VGA_BIOS_SEG_END = (VGA_BIOS_SEG + (VGA_BIOS_Size >> 4)); 00988 00989 /* clear for VGA BIOS (FIXME: Why does Project Angel like our BIOS when we memset() here, but don't like it if we memset() in the INT 10 ROM setup routine?) */ 00990 if (VGA_BIOS_Size != 0) 00991 memset((char*)MemBase+0xC0000,0x00,VGA_BIOS_Size); 00992 } 00993 00994 void SetCyclesCount_mapper_shortcut(bool pressed); 00995 void DOSBOX_RealInit() { 00996 DOSBoxMenu::item *item; 00997 00998 LOG(LOG_MISC,LOG_DEBUG)("DOSBOX_RealInit: loading settings and initializing"); 00999 01000 MAPPER_AddHandler(DOSBOX_UnlockSpeed, MK_rightarrow, MMODHOST,"speedlock","Speedlock"); 01001 { 01002 MAPPER_AddHandler(DOSBOX_UnlockSpeed2, MK_nothing, 0, "speedlock2", "Speedlock2", &item); 01003 item->set_description("Toggle emulation speed, to allow running faster than realtime (fast forward)"); 01004 item->set_text("Turbo (Fast Forward)"); 01005 } 01006 { 01007 MAPPER_AddHandler(DOSBOX_NormalSpeed, MK_leftarrow, MMODHOST, "speednorm","SpeedNrm", &item); 01008 item->set_description("Restore normal emulation speed"); 01009 item->set_text("Normal speed"); 01010 } 01011 { 01012 MAPPER_AddHandler(DOSBOX_SpeedUp, MK_rbracket, MMODHOST, "speedup","SpeedUp", &item); 01013 item->set_text("Speed up"); 01014 } 01015 { 01016 MAPPER_AddHandler(DOSBOX_SlowDown, MK_lbracket, MMODHOST,"slowdown","SlowDn", &item); 01017 item->set_text("Slow down"); 01018 } 01019 { 01020 MAPPER_AddHandler(&SetCyclesCount_mapper_shortcut, MK_nothing, 0, "editcycles", "EditCycles", &item); 01021 item->set_text("Edit cycles"); 01022 } 01023 01024 //add support for loading/saving game states 01025 MAPPER_AddHandler(SaveGameState, MK_f9, MMOD1|MMOD2,"savestate","SaveState", &item); 01026 item->set_text("Save state"); 01027 MAPPER_AddHandler(LoadGameState, MK_f10, MMOD1|MMOD2,"loadstate","LoadState", &item); 01028 item->set_text("Load state"); 01029 MAPPER_AddHandler(PreviousSaveSlot, MK_f7, MMOD1|MMOD2,"prevslot","PrevSlot", &item); 01030 item->set_text("Previous slot"); 01031 MAPPER_AddHandler(NextSaveSlot, MK_f8, MMOD1|MMOD2,"nextslot","NextSlot", &item); 01032 item->set_text("Next slot"); 01033 01034 Section_prop *section = static_cast<Section_prop *>(control->GetSection("dosbox")); 01035 assert(section != NULL); 01036 01037 // TODO: allow change at any time. in fact if it were possible for DOSBox-X configuration 01038 // schema code to attach event callbacks when a setting changes, we would set one 01039 // on the title= setting now to auto-update the titlebar when this changes. 01040 dosbox_title = section->Get_string("title"); 01041 01042 // TODO: these should be parsed by DOS kernel at startup 01043 dosbox_shell_env_size = (unsigned int)section->Get_int("shell environment size"); 01044 01045 // TODO: a bit of a challenge: if we put it in the ROM area as mainline DOSBox does then the init 01046 // needs to read this from the BIOS where it can map the memory appropriately. if the allocation 01047 // is dynamic and the private area is down at the base of memory like real DOS, then the BIOS 01048 // should ignore it and the DOS kernel should parse it. If we're going to put it into upper 01049 // areas as well, then we should also consider making it look like adapter ROM at startup 01050 // so it can be enumerated properly by DOS programs scanning the ROM area. 01051 /* private area size param in bytes. round up to nearest paragraph */ 01052 DOS_PRIVATE_SEGMENT_Size = (Bitu)((section->Get_int("private area size") + 8) / 16); 01053 01054 // TODO: these should be parsed by BIOS startup 01055 allow_more_than_640kb = section->Get_bool("allow more than 640kb base memory"); 01056 01057 // TODO: should be parsed by motherboard emulation 01058 allow_port_92_reset = section->Get_bool("allow port 92 reset"); 01059 01060 // CGA/EGA/VGA-specific 01061 extern unsigned char vga_p3da_undefined_bits; 01062 vga_p3da_undefined_bits = (unsigned char)section->Get_hex("vga 3da undefined bits"); 01063 01064 // TODO: should be parsed by motherboard emulation or lower level equiv..? 01065 std::string cmd_machine; 01066 if (control->cmdline->FindString("-machine",cmd_machine,true)){ 01067 //update value in config (else no matching against suggested values 01068 section->HandleInputline(std::string("machine=") + cmd_machine); 01069 } 01070 01071 // TODO: should be parsed by...? perhaps at some point we support machine= for backwards compat 01072 // but translate it into two separate params that specify what machine vs what video hardware. 01073 // or better yet as envisioned, a possible dosbox-x.conf schema that allows a machine with no 01074 // base video of it's own, and then to specify an ISA or PCI card attached to the bus that 01075 // provides video. 01076 std::string mtype(section->Get_string("machine")); 01077 svgaCard = SVGA_None; 01078 machine = MCH_VGA; 01079 int10.vesa_nolfb = false; 01080 int10.vesa_oldvbe = false; 01081 if (mtype == "cga") { machine = MCH_CGA; mono_cga = false; } 01082 else if (mtype == "cga_mono") { machine = MCH_CGA; mono_cga = true; } 01083 else if (mtype == "cga_rgb") { machine = MCH_CGA; mono_cga = false; cga_comp = 2; } 01084 else if (mtype == "cga_composite") { machine = MCH_CGA; mono_cga = false; cga_comp = 1; new_cga = false; } 01085 else if (mtype == "cga_composite2"){ machine = MCH_CGA; mono_cga = false; cga_comp = 1; new_cga = true; } 01086 else if (mtype == "mcga") { machine = MCH_MCGA; } 01087 else if (mtype == "tandy") { machine = MCH_TANDY; } 01088 else if (mtype == "pcjr") { machine = MCH_PCJR; } 01089 else if (mtype == "hercules") { machine = MCH_HERC; } 01090 else if (mtype == "mda") { machine = MCH_MDA; } 01091 else if (mtype == "ega") { machine = MCH_EGA; } 01092 else if (mtype == "svga_s3") { svgaCard = SVGA_S3Trio; } 01093 else if (mtype == "vesa_nolfb") { svgaCard = SVGA_S3Trio; int10.vesa_nolfb = true;} 01094 else if (mtype == "vesa_oldvbe") { svgaCard = SVGA_S3Trio; int10.vesa_oldvbe = true;} 01095 else if (mtype == "svga_et4000") { svgaCard = SVGA_TsengET4K; } 01096 else if (mtype == "svga_et3000") { svgaCard = SVGA_TsengET3K; } 01097 else if (mtype == "svga_paradise") { svgaCard = SVGA_ParadisePVGA1A; } 01098 else if (mtype == "vgaonly") { svgaCard = SVGA_None; } 01099 else if (mtype == "amstrad") { machine = MCH_AMSTRAD; } 01100 else if (mtype == "pc98") { machine = MCH_PC98; } 01101 else if (mtype == "pc9801") { machine = MCH_PC98; } /* Future differentiation */ 01102 else if (mtype == "pc9821") { machine = MCH_PC98; } /* Future differentiation */ 01103 01104 else if (mtype == "fm_towns") { machine = MCH_VGA; want_fm_towns = true; /*machine = MCH_FM_TOWNS;*/ } 01105 01106 else E_Exit("DOSBOX:Unknown machine type %s",mtype.c_str()); 01107 01108 // TODO: should be parsed by motherboard emulation 01109 // FIXME: This re-uses the existing ISA bus delay code for C-BUS in PC-98 mode 01110 std::string isabclk; 01111 01112 if (IS_PC98_ARCH) 01113 isabclk = section->Get_string("cbus bus clock"); 01114 else 01115 isabclk = section->Get_string("isa bus clock"); 01116 01117 if (isabclk == "std10") 01118 clockdom_ISA_BCLK.set_frequency(PIT_TICK_RATE_PC98_10MHZ * 4ul,1); /* 10Mhz (PC-98) */ 01119 else if (isabclk == "std8.3") 01120 clockdom_ISA_BCLK.set_frequency(25000000,3); /* 25MHz / 3 = 8.333MHz, early 386 systems did this, became an industry standard "norm" afterwards */ 01121 else if (isabclk == "std8") { 01122 if (IS_PC98_ARCH) 01123 clockdom_ISA_BCLK.set_frequency(PIT_TICK_RATE_PC98_8MHZ * 4ul,1); /* 8Mhz (PC-98) */ 01124 else 01125 clockdom_ISA_BCLK.set_frequency(8000000,1); /* 8Mhz (IBM PC) */ 01126 } 01127 else if (isabclk == "std6") 01128 clockdom_ISA_BCLK.set_frequency(6000000,1); /* 6MHz */ 01129 else if (isabclk == "std5") 01130 clockdom_ISA_BCLK.set_frequency(PIT_TICK_RATE_PC98_10MHZ * 2ul,1); /* 5Mhz (PC-98) */ 01131 else if (isabclk == "std4.77") 01132 clockdom_ISA_BCLK.set_frequency(clockdom_ISA_OSC.freq,clockdom_ISA_OSC.freq_div*3LL); /* 14.31818MHz / 3 = 4.77MHz */ 01133 else if (isabclk == "oc10") 01134 clockdom_ISA_BCLK.set_frequency(10000000,1); /* 10MHz */ 01135 else if (isabclk == "oc12") 01136 clockdom_ISA_BCLK.set_frequency(12000000,1); /* 12MHz */ 01137 else if (isabclk == "oc15") 01138 clockdom_ISA_BCLK.set_frequency(15000000,1); /* 15MHz */ 01139 else if (isabclk == "oc16") 01140 clockdom_ISA_BCLK.set_frequency(16000000,1); /* 16MHz */ 01141 else 01142 parse_busclk_setting_str(&clockdom_ISA_BCLK,isabclk.c_str()); 01143 01144 std::string pcibclk = section->Get_string("pci bus clock"); 01145 if (pcibclk == "std33.3") 01146 clockdom_PCI_BCLK.set_frequency(100000000,3); /* 100MHz / 3 = 33.333MHz, VERY common PCI speed */ 01147 else if (pcibclk == "std30") 01148 clockdom_PCI_BCLK.set_frequency(30000000,1); /* 30Mhz */ 01149 else if (pcibclk == "std25") 01150 clockdom_PCI_BCLK.set_frequency(25000000,1); /* 25MHz */ 01151 else 01152 parse_busclk_setting_str(&clockdom_PCI_BCLK,pcibclk.c_str()); 01153 01154 LOG_MSG("%s BCLK: %.3fHz (%llu/%llu)", 01155 IS_PC98_ARCH ? "C-BUS" : "ISA", 01156 (double)clockdom_ISA_BCLK.freq / clockdom_ISA_BCLK.freq_div, 01157 (unsigned long long)clockdom_ISA_BCLK.freq, 01158 (unsigned long long)clockdom_ISA_BCLK.freq_div); 01159 01160 clockdom_ISA_OSC.set_name("ISA OSC"); 01161 clockdom_ISA_BCLK.set_name("ISA BCLK"); 01162 clockdom_PCI_BCLK.set_name("PCI BCLK"); 01163 01164 // FM TOWNS is stub so far. According to sources like Wikipedia though, 01165 // it boots from DOS in ROM that then loads bootcode from CD-ROM. So 01166 // for now, allow booting into FM TOWNS mode with a warning. The 01167 // switch to FM Towns will begin in the BOOT command with a flag to 01168 // indicate the ISO is intended for FM TOwns. 01169 if (IS_FM_TOWNS || want_fm_towns) LOG_MSG("FM Towns emulation not yet implemented. It's currently just a stub for future development."); 01170 } 01171 01172 void DOSBOX_SetupConfigSections(void) { 01173 Prop_int* Pint; 01174 Prop_hex* Phex; 01175 Prop_bool* Pbool; 01176 Prop_string* Pstring; 01177 Prop_double* Pdouble; 01178 Prop_multival* Pmulti; 01179 Section_prop * secprop; 01180 Prop_multival_remain* Pmulti_remain; 01181 01182 // Some frequently used option sets 01183 const char* vsyncrate[] = { "%u", 0 }; 01184 const char* force[] = { "", "forced", 0 }; 01185 const char* cyclest[] = { "auto","fixed","max","%u",0 }; 01186 const char* mputypes[] = { "intelligent", "uart", "none", 0 }; 01187 const char* vsyncmode[] = { "off", "on" ,"force", "host", 0 }; 01188 const char* captureformats[] = { "default", "avi-zmbv", "mpegts-h264", 0 }; 01189 const char* blocksizes[] = {"1024", "2048", "4096", "8192", "512", "256", 0}; 01190 const char* capturechromaformats[] = { "auto", "4:4:4", "4:2:2", "4:2:0", 0}; 01191 const char* controllertypes[] = { "auto", "at", "xt", "pcjr", "pc98", 0}; // Future work: Tandy(?) and USB 01192 const char* auxdevices[] = {"none","2button","3button","intellimouse","intellimouse45",0}; 01193 const char* cputype_values[] = {"auto", "8086", "8086_prefetch", "80186", "80186_prefetch", "286", "286_prefetch", "386", "386_prefetch", "486old", "486old_prefetch", "486", "486_prefetch", "pentium", "pentium_mmx", "ppro_slow", 0}; 01194 const char* rates[] = { "44100", "48000", "32000","22050", "16000", "11025", "8000", "49716", 0 }; 01195 const char* oplrates[] = { "44100", "49716", "48000", "32000","22050", "16000", "11025", "8000", 0 }; 01196 #ifdef C_FLUIDSYNTH 01197 const char* devices[] = { "default", "win32", "alsa", "oss", "coreaudio", "coremidi", "mt32", "synth", "fluidsynth", "timidity", "none", 0}; 01198 #else 01199 const char* devices[] = { "default", "win32", "alsa", "oss", "coreaudio", "coremidi", "mt32", "timidity", "none", 0}; // FIXME: add some way to offer the actually available choices. 01200 #endif 01201 const char* apmbiosversions[] = { "auto", "1.0", "1.1", "1.2", 0 }; 01202 const char* driveletters[] = { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", 0}; 01203 const char *mt32log[] = {"off", "on",0}; 01204 const char *mt32thread[] = {"off", "on",0}; 01205 const char *mt32ReverseStereo[] = {"off", "on",0}; 01206 const char *mt32DACModes[] = {"0", "1", "2", "3", "auto",0}; 01207 const char *mt32reverbModes[] = {"0", "1", "2", "3", "auto",0}; 01208 const char *mt32reverbTimes[] = {"0", "1", "2", "3", "4", "5", "6", "7",0}; 01209 const char *mt32reverbLevels[] = {"0", "1", "2", "3", "4", "5", "6", "7",0}; 01210 const char* gustypes[] = { "classic", "classic37", "max", "interwave", 0 }; 01211 const char* sbtypes[] = { "sb1", "sb2", "sbpro1", "sbpro2", "sb16", "sb16vibra", "gb", "ess688", "reveal_sc400", "none", 0 }; 01212 const char* oplmodes[]={ "auto", "cms", "opl2", "dualopl2", "opl3", "opl3gold", "none", "hardware", "hardwaregb", 0}; 01213 const char* serials[] = { "dummy", "disabled", "modem", "nullmodem", "serialmouse", "directserial", "log", "file", 0 }; 01214 const char* acpi_rsd_ptr_settings[] = { "auto", "bios", "ebda", 0 }; 01215 const char* cpm_compat_modes[] = { "auto", "off", "msdos2", "msdos5", "direct", 0 }; 01216 const char* dosv_settings[] = { "off", "japanese", "chinese", "korean", 0 }; 01217 const char* acpisettings[] = { "off", "1.0", "1.0b", "2.0", "2.0a", "2.0b", "2.0c", "3.0", "3.0a", "3.0b", "4.0", "4.0a", "5.0", "5.0a", "6.0", 0 }; 01218 const char* guspantables[] = { "old", "accurate", "default", 0 }; 01219 const char *sidbaseno[] = { "240", "220", "260", "280", "2a0", "2c0", "2e0", "300", 0 }; 01220 const char* joytypes[] = { "auto", "2axis", "4axis", "4axis_2", "fcs", "ch", "none",0}; 01221 // const char* joydeadzone[] = { "0.26", 0 }; 01222 // const char* joyresponse[] = { "1.0", 0 }; 01223 const char* iosgus[] = { "240", "220", "260", "280", "2a0", "2c0", "2e0", "300", "210", "230", "250", 0 }; 01224 const char* mpubases[] = { 01225 "0", /* Auto */ 01226 "300", "310", "320", "330", "332", "334", "336", "340", "360", /* IBM PC */ 01227 "c0d0","c8d0","d0d0","d8d0","e0d0","e8d0","f0d0","f8d0", /* NEC PC-98 MPU98 */ 01228 "80d2","80d4","80d6","80d8","80da","80dc","80de", /* NEC PC-98 SB16 */ 01229 0 }; 01230 const char* ios[] = { 01231 "220", "240", "260", "280", "2a0", "2c0", "2e0", /* IBM PC (base+port i.e. 220h base, 22Ch is DSP) */ 01232 "d2", "d4", "d6", "d8", "da", "dc", "de", /* NEC PC-98 (base+(port << 8) i.e. 00D2h base, 2CD2h is DSP) */ 01233 0 }; 01234 const char* ems_settings[] = { "true", "emsboard", "emm386", "false", 0}; 01235 const char* lfn_settings[] = { "true", "false", "auto", "autostart", 0}; 01236 const char* irqsgus[] = { "5", "3", "7", "9", "10", "11", "12", 0 }; 01237 const char* irqssb[] = { "7", "5", "3", "9", "10", "11", "12", 0 }; 01238 const char* dmasgus[] = { "3", "0", "1", "5", "6", "7", 0 }; 01239 const char* dmassb[] = { "1", "5", "0", "3", "6", "7", 0 }; 01240 const char* oplemus[] = { "default", "compat", "fast", "nuked", "mame", 0 }; 01241 const char *qualityno[] = { "0", "1", "2", "3", 0 }; 01242 const char* tandys[] = { "auto", "on", "off", 0}; 01243 const char* ps1opt[] = { "on", "off", 0}; 01244 const char* numopt[] = { "on", "off", "", 0}; 01245 const char* truefalseautoopt[] = { "true", "false", "1", "0", "auto", 0}; 01246 const char* pc98fmboards[] = { "auto", "off", "false", "board14", "board26k", "board86", "board86c", 0}; 01247 const char* pc98videomodeopt[] = { "", "24khz", "31khz", "15khz", 0}; 01248 const char* aspectmodes[] = { "false", "true", "0", "1", "yes", "no", "nearest", "bilinear", 0}; 01249 const char *vga_ac_mapping_settings[] = { "", "auto", "4x4", "4low", "first16", 0 }; 01250 01251 const char* irqhandler[] = { 01252 "", "simple", "cooperative_2nd", 0 }; 01253 01254 /* Setup all the different modules making up DOSBox-X */ 01255 const char* machines[] = { 01256 "hercules", "cga", "cga_mono", "cga_rgb", "cga_composite", "cga_composite2", "tandy", "pcjr", "ega", 01257 "vgaonly", "svga_s3", "svga_et3000", "svga_et4000", 01258 "svga_paradise", "vesa_nolfb", "vesa_oldvbe", "amstrad", "pc98", "pc9801", "pc9821", 01259 01260 "fm_towns", // STUB 01261 01262 "mcga", "mda", 01263 01264 0 }; 01265 01266 const char* scalers[] = { 01267 "none", "normal2x", "normal3x", "normal4x", "normal5x", 01268 #if RENDER_USE_ADVANCED_SCALERS>2 01269 "advmame2x", "advmame3x", "advinterp2x", "advinterp3x", "hq2x", "hq3x", "2xsai", "super2xsai", "supereagle", 01270 #endif 01271 #if RENDER_USE_ADVANCED_SCALERS>0 01272 "tv2x", "tv3x", "rgb2x", "rgb3x", "scan2x", "scan3x", "gray", "gray2x", 01273 #endif 01274 "hardware_none", "hardware2x", "hardware3x", "hardware4x", "hardware5x", 01275 #if C_XBRZ 01276 "xbrz", "xbrz_bilinear", 01277 #endif 01278 0 }; 01279 01280 const char* cores[] = { "auto", 01281 #if (C_DYNAMIC_X86) || (C_DYNREC) 01282 "dynamic", 01283 #endif 01284 "normal", "full", "simple", 0 }; 01285 01286 const char* voodoo_settings[] = { 01287 "false", 01288 "software", 01289 #if C_OPENGL 01290 "opengl", 01291 #endif 01292 "auto", 01293 0 01294 }; 01295 01296 #if defined(__SSE__) && !(defined(_M_AMD64) || defined(__e2k__)) && !defined(EMSCRIPTEN) 01297 CheckSSESupport(); 01298 #endif 01299 SDLNetInited = false; 01300 01301 secprop=control->AddSection_prop("dosbox",&Null_Init); 01302 Pstring = secprop->Add_path("language",Property::Changeable::Always,""); 01303 Pstring->Set_help("Select another language file."); 01304 01305 Pstring = secprop->Add_path("title",Property::Changeable::Always,""); 01306 Pstring->Set_help("Additional text to place in the title bar of the window"); 01307 01308 Pbool = secprop->Add_bool("enable 8-bit dac",Property::Changeable::OnlyAtStart,true); 01309 Pbool->Set_help("If set, allow VESA BIOS calls in IBM PC mode to set DAC width. Has no effect in PC-98 mode."); 01310 01311 Pstring = secprop->Add_string("dpi aware",Property::Changeable::OnlyAtStart,"auto"); 01312 Pstring->Set_values(truefalseautoopt); 01313 Pstring->Set_help("Set this option (auto by default) to indicate to your OS that DOSBox-X is DPI aware.\n" 01314 "If it is not set, Windows Vista/7/8/10 and higher may upscale the DOSBox-X window\n" 01315 "on higher resolution monitors which is probably not what you want."); 01316 01317 Pbool = secprop->Add_bool("keyboard hook", Property::Changeable::Always, false); 01318 Pbool->Set_help("Use keyboard hook (currently only on Windows) to catch special keys and synchronize the keyboard LEDs with the host"); 01319 01320 // STUB OPTION, NOT YET FULLY IMPLEMENTED 01321 Pbool = secprop->Add_bool("weitek",Property::Changeable::WhenIdle,false); 01322 Pbool->Set_help("If set, emulate the Weitek coprocessor. This option only has effect if cputype=386 or cputype=486."); 01323 01324 Pbool = secprop->Add_bool("bochs debug port e9",Property::Changeable::WhenIdle,false); 01325 Pbool->Set_help("If set, emulate Bochs debug port E9h. ASCII text written to this I/O port is assumed to be debug output, and logged."); 01326 01327 Pstring = secprop->Add_string("machine",Property::Changeable::OnlyAtStart,"svga_s3"); 01328 Pstring->Set_values(machines); 01329 Pstring->Set_help("The type of machine DOSBox-X tries to emulate."); 01330 01331 Phex = secprop->Add_hex("svga lfb base", Property::Changeable::OnlyAtStart, 0); 01332 Phex->Set_help("If nonzero, define the physical memory address of the linear framebuffer."); 01333 01334 Pbool = secprop->Add_bool("pci vga",Property::Changeable::WhenIdle,true); 01335 Pbool->Set_help("If set, SVGA is emulated as if a PCI device (when enable pci bus=true)"); 01336 01337 Pint = secprop->Add_int("vmemdelay", Property::Changeable::WhenIdle,0); 01338 Pint->SetMinMax(-1,100000); 01339 Pint->Set_help( "VGA Memory I/O delay in nanoseconds. Set to -1 to use default, 0 to disable.\n" 01340 "Default off. Enable this option (-1 or nonzero) if you are running a game or\n" 01341 "demo that needs slower VGA memory (like that of older ISA hardware) to work properly.\n" 01342 "If your game is not sensitive to VGA RAM I/O speed, then turning on this option\n" 01343 "will do nothing but cause a significant drop in frame rate which is probably not\n" 01344 "what you want. Recommended values -1, 0 to 2000."); 01345 01346 Pint = secprop->Add_int("vmemsize", Property::Changeable::WhenIdle,-1); 01347 Pint->SetMinMax(-1,16); 01348 Pint->Set_help( 01349 "Amount of video memory in megabytes.\n" 01350 " The maximum resolution and color depth the svga_s3 will be able to display\n" 01351 " is determined by this value.\n " 01352 " -1: auto (vmemsizekb is ignored)\n" 01353 " 0: 512k (800x600 at 256 colors) if vmemsizekb=0\n" 01354 " 1: 1024x768 at 256 colors or 800x600 at 64k colors\n" 01355 " 2: 1600x1200 at 256 colors or 1024x768 at 64k colors or 640x480 at 16M colors\n" 01356 " 4: 1600x1200 at 64k colors or 1024x768 at 16M colors\n" 01357 " 8: up to 1600x1200 at 16M colors\n" 01358 "For build engine games, use more memory than in the list above so it can\n" 01359 "use triple buffering and thus won't flicker.\n" 01360 ); 01361 01362 Pint = secprop->Add_int("vmemsizekb", Property::Changeable::WhenIdle,0); 01363 Pint->SetMinMax(0,1024); 01364 Pint->Set_help( 01365 "Amount of video memory in kilobytes, in addition to vmemsize"); 01366 01367 Pstring = secprop->Add_path("captures",Property::Changeable::Always,"capture"); 01368 Pstring->Set_help("Directory where things like wave, midi, screenshot get captured."); 01369 01370 /* will change to default true unless this causes compatibility issues with other users or their editing software */ 01371 Pbool = secprop->Add_bool("skip encoding unchanged frames",Property::Changeable::WhenIdle,false); 01372 Pbool->Set_help("Unchanged frames will not be sent to the video codec as a possible performance and bandwidth optimization."); 01373 01374 Pstring = secprop->Add_string("capture chroma format", Property::Changeable::OnlyAtStart,"auto"); 01375 Pstring->Set_values(capturechromaformats); 01376 Pstring->Set_help("Chroma format to use when capturing to H.264. 'auto' picks the best quality option.\n" 01377 "4:4:4 Chroma is at full resolution. This provides the best quality, however not widely supported by editing software.\n" 01378 "4:2:2 Chroma is at half horizontal resolution.\n" 01379 "4:2:0 Chroma is at quarter resolution, which may cause minor color smearing.\n" 01380 " However, this chroma format is most likely to be compatible with video editing software."); 01381 01382 Pstring = secprop->Add_string("capture format", Property::Changeable::OnlyAtStart,"default"); 01383 Pstring->Set_values(captureformats); 01384 Pstring->Set_help("Capture format to use when capturing video. The availability of the format depends on how DOSBox-X was compiled.\n" 01385 "default Use compiled-in default (avi-zmbv)\n" 01386 "avi-zmbv Use DOSBox-style AVI + ZMBV codec with PCM audio\n" 01387 "mpegts-h264 Use MPEG transport stream + H.264 + AAC audio. Resolution & refresh rate changes can be contained\n" 01388 " within one file with this choice, however not all software can support mid-stream format changes."); 01389 01390 Pint = secprop->Add_int("shell environment size",Property::Changeable::OnlyAtStart,0); 01391 Pint->SetMinMax(0,65280); 01392 Pint->Set_help("Size of the initial DOSBox-X shell environment block, in bytes. This does not affect the environment block of sub-processes spawned from the shell.\n" 01393 "This option has no effect unless dynamic kernel allocation is enabled."); 01394 01395 Pint = secprop->Add_int("private area size",Property::Changeable::OnlyAtStart,32768); // DOSBox mainline compatible 32KB region 01396 Pint->SetMinMax(16,128*1024); 01397 Pint->Set_help("Set DOSBox-X private memory area size. This area contains private memory structures used by the DOS kernel.\n" 01398 "It is discarded when you boot into another OS. Mainline DOSBox uses 32KB. Testing shows that it is possible\n" 01399 "to run DOSBox with as little as 4KB. If DOSBox-X aborts with error \"not enough memory for internal tables\"\n" 01400 "then you need to increase this value."); 01401 01402 // NOTE: This will be revised as I test the DOSLIB code against more VGA/SVGA hardware! 01403 Pstring = secprop->Add_string("vga attribute controller mapping",Property::Changeable::WhenIdle,"auto"); 01404 Pstring->Set_values(vga_ac_mapping_settings); 01405 Pstring->Set_help( 01406 "This affects how the attribute controller maps colors, especially in 256-color mode.\n" 01407 "Some SVGA cards handle the attribute controller palette differently than most SVGA cards.\n" 01408 " auto Automatically pick the mapping based on the SVGA chipset.\n" 01409 " 4x4 Split into two 4-bit nibbles, map through AC, recombine. This is standard VGA behavior including clone SVGA cards.\n" 01410 " 4low Split into two 4-bit nibbles, remap only the low 4 bits, recombine. This is standard ET4000 behavior.\n" 01411 "\n" 01412 "NOTES:\n" 01413 " Demoscene executable 'COPPER.EXE' requires the '4low' behavior in order to display line-fading effects\n" 01414 " (including scrolling credits) correctly, else those parts of the demo show up as a blank screen.\n" 01415 " \n" 01416 " 4low behavior is default for ET4000 emulation."); 01417 01418 Pstring = secprop->Add_string("a20",Property::Changeable::WhenIdle,"mask"); 01419 Pstring->Set_help("A20 gate emulation mode.\n" 01420 "The on/off/on_fake/off_fake options are intended for testing and debugging DOS development,\n" 01421 "or to emulate obscure hardware, or to work around potential extended memory problems with DOS programs.\n" 01422 "on_fake/off_fake are intended to test whether a program carries out a memory test to ensure the A20\n" 01423 "gate is set as intended (as HIMEM.SYS does). If it goes by the gate bit alone, it WILL crash.\n" 01424 "This parameter is also changeable from the builtin A20GATE command.\n" 01425 " fast Emulate A20 gating by remapping the first 64KB @ 1MB boundary (fast, mainline DOSBox behavior)\n" 01426 " mask Emulate A20 gating by masking memory I/O address (accurate)\n" 01427 " off Lock A20 gate off (Software/OS cannot enable A20)\n" 01428 " on Lock A20 gate on (Software/OS cannot disable A20)\n" 01429 " off_fake Lock A20 gate off but allow bit to toggle (hope your DOS game tests the HMA!)\n" 01430 " on_fake Lock A20 gate on but allow bit to toggle"); 01431 01432 Pbool = secprop->Add_bool("turn off a20 gate on boot",Property::Changeable::WhenIdle,true); 01433 Pbool->Set_help("If enabled, A20 gate is switched off when booting a guest OS.\n" 01434 "Enabled by default. Recommended for MS-DOS when HIMEM.SYS is not installed in the guest OS.\n" 01435 "If disabled, and MS-DOS does not load HIMEM.SYS, programs and features that rely on the 1MB wraparound will fail."); 01436 01437 /* Ref: 01438 * 01439 * "Except the first generation, which C-Bus was synchronous with its 5MHz 8086, PC-98s 01440 * before the age of SuperIO and PCI use either 10MHz (9.8304MHz) or 8MHz (7.9872MHz) 01441 * for its C-Bus. 01442 * 01443 * It's determined by the CPU clock base (2.4756Mhz or 1.9968MHz). For example, on a 01444 * 16MHz 386, C-Bus runs at 8MHz and on a 25MHz 386, C-Bus runs at 10MHz. 01445 * 01446 * After NEC brought SuperIO and PCI to PC-98, C-Bus clock no longer ties to the CPU 01447 * oscillator and got fixed to 10MHz." -Yksoft1 01448 * 01449 * Assuming this is true, the selection is given below */ 01450 01451 Pstring = secprop->Add_string("cbus bus clock",Property::Changeable::WhenIdle,"std10"); 01452 Pstring->Set_help("C-BUS BCLK frequency (PC-98), used to emulate I/O delay.\n" 01453 "WARNING: In future revisions, PCI/motherboard chipset emulation will allow the guest OS/program to alter this value at runtime.\n" 01454 " std10 10MHz (CPU speed multiple of 5MHz or PCI-based)\n" 01455 " std8 8MHz (CPU speed multiple of 4MHz)\n" 01456 " std5 5MHz (older PC-9801)\n" 01457 " <integer or float> Any integer or floating point value will be used as the clock frequency in Hz\n" 01458 " <integer/integer ratio> If a ratio is given (num/den), the ratio will be used as the clock frequency"); 01459 01460 Pstring = secprop->Add_string("isa bus clock",Property::Changeable::WhenIdle,"std8.3"); 01461 Pstring->Set_help("ISA BCLK frequency, used to emulate I/O delay.\n" 01462 "WARNING: In future revisions, PCI/motherboard chipset emulation will allow the guest OS/program to alter this value at runtime.\n" 01463 " std8.3 8.333MHz (typical 386-class or higher)\n" 01464 " std8 8MHz\n" 01465 " std6 6MHz\n" 01466 " std4.77 4.77MHz (precisely 1/3 x 14.31818MHz). Bus frequency of older PC/XT systems.\n" 01467 " oc10 10MHz\n" 01468 " oc12 12MHz\n" 01469 " oc15 15MHz\n" 01470 " oc16 16MHz\n" 01471 " <integer or float> Any integer or floating point value will be used as the clock frequency in Hz\n" 01472 " <integer/integer ratio> If a ratio is given (num/den), the ratio will be used as the clock frequency"); 01473 01474 Pstring = secprop->Add_string("pci bus clock",Property::Changeable::WhenIdle,"std33.3"); 01475 Pstring->Set_help("PCI bus frequency, used to emulate I/O delay.\n" 01476 "WARNING: In future revisions, PCI/motherboard chipset emulation will allow the guest OS/program to alter this value at runtime.\n" 01477 " std33.3 33.333MHz (very common setting on motherboards)\n" 01478 " std30 30MHz (some older mid-1990's Pentium systems)\n" 01479 " std25 25MHz\n" 01480 " <integer or float> Any integer or floating point value will be used as the clock frequency in Hz\n" 01481 " <integer/integer ratio> If a ratio is given (num/den), the ratio will be used as the clock frequency"); 01482 01483 Pstring = secprop->Add_string("call binary on reset",Property::Changeable::WhenIdle,""); 01484 Pstring->Set_help("If set, this is the path of a binary blob to load into the ROM BIOS area and execute immediately after CPU reset.\n" 01485 "It will be executed before the BIOS POST routine, only ONCE. The binary blob is expected either to IRET or to\n" 01486 "jump directly to F000:FFF0 to return control to the BIOS.\n" 01487 "This can be used for x86 assembly language experiments and automated testing against the CPU emulation."); 01488 01489 Pstring = secprop->Add_string("unhandled irq handler",Property::Changeable::WhenIdle,""); 01490 Pstring->Set_values(irqhandler); 01491 Pstring->Set_help("Determines how unhandled IRQs are handled. This may help some errant DOS applications.\n" 01492 "Leave unset for default behavior (simple).\n" 01493 "simple Acknowledge the IRQ, and the master (if slave IRQ)\n" 01494 "mask_isr Acknowledge IRQs in service on master and slave and mask IRQs still in service, to deal with errant handlers (em-dosbox method)"); 01495 01496 Pstring = secprop->Add_string("call binary on boot",Property::Changeable::WhenIdle,""); 01497 Pstring->Set_help("If set, this is the path of a binary blob to load into the ROM BIOS area and execute immediately before booting the DOS system.\n" 01498 "This can be used for x86 assembly language experiments and automated testing against the CPU emulation."); 01499 01500 Pint = secprop->Add_int("rom bios allocation max",Property::Changeable::OnlyAtStart,0); 01501 Pint->SetMinMax(0,128); 01502 Pint->Set_help("Maximum size (top down from 1MB) allowed for ROM BIOS dynamic allocation in KB"); 01503 01504 Pint = secprop->Add_int("rom bios minimum size",Property::Changeable::OnlyAtStart,0); 01505 Pint->SetMinMax(0,128); 01506 Pint->Set_help("Once ROM BIOS layout is finalized, trim total region down to a minimum amount in KB"); 01507 01508 Pint = secprop->Add_int("irq delay ns", Property::Changeable::WhenIdle,-1); 01509 Pint->SetMinMax(-1,100000); 01510 Pint->Set_help( "IRQ delay in nanoseconds. Set to -1 to use default, 0 to disable.\n" 01511 "This is a more precise version of the irqdelay= setting.\n" 01512 "There are some old DOS games and demos that have race conditions with IRQs that need a nonzero value here to work properly."); 01513 01514 Pint = secprop->Add_int("iodelay", Property::Changeable::WhenIdle,-1); 01515 Pint->SetMinMax(-1,100000); 01516 Pint->Set_help( "I/O delay in nanoseconds for I/O port access. Set to -1 to use default, 0 to disable.\n" 01517 "A value of 1000 (1us) is recommended for ISA bus type delays. If your game\n" 01518 "or demo is not sensitive to I/O port and ISA bus timing, you can turn this option off\n" 01519 "(set to 0) to increase game performance."); 01520 01521 Pint = secprop->Add_int("iodelay16", Property::Changeable::WhenIdle,-1); 01522 Pint->SetMinMax(-1,100000); 01523 Pint->Set_help( "I/O delay for 16-bit transfers. -1 to use default, 0 to disable."); 01524 01525 Pint = secprop->Add_int("iodelay32", Property::Changeable::WhenIdle,-1); 01526 Pint->SetMinMax(-1,100000); 01527 Pint->Set_help( "I/O delay for 32-bit transfers. -1 to use default, 0 to disable."); 01528 01529 // STUB OPTION, NOT YET FULLY IMPLEMENTED 01530 Pstring = secprop->Add_string("acpi", Property::Changeable::OnlyAtStart,"off"); 01531 Pstring->Set_values(acpisettings); 01532 Pstring->Set_help("ACPI emulation, and what version of the specification to follow.\n" 01533 "WARNING: This option is very experimental at this time and should not be enabled unless you're willing to accept the consequences.\n" 01534 " Intended for use with ACPI-aware OSes including Linux and Windows 98/ME. This option will also slightly reduce available\n" 01535 " system memory to make room for the ACPI tables, just as real BIOSes do, and reserve an IRQ for ACPI functions."); 01536 01537 // STUB OPTION, NOT YET FULLY IMPLEMENTED 01538 Pstring = secprop->Add_string("acpi rsd ptr location", Property::Changeable::OnlyAtStart,"auto"); 01539 Pstring->Set_values(acpi_rsd_ptr_settings); 01540 Pstring->Set_help("Where to store the Root System Description Pointer structure. You can have it stored in the ROM BIOS area, or the Extended Bios Data Area."); 01541 01542 // STUB OPTION, NOT YET FULLY IMPLEMENTED 01543 Pint = secprop->Add_int("acpi sci irq", Property::Changeable::WhenIdle,-1); 01544 Pint->Set_help("IRQ to assign as ACPI system control interrupt. set to -1 to automatically assign."); 01545 01546 // STUB OPTION, NOT YET FULLY IMPLEMENTED 01547 Phex = secprop->Add_hex("acpi iobase",Property::Changeable::WhenIdle,0); 01548 Phex->Set_help("I/O port base for the ACPI device Power Management registers. Set to 0 for automatic assignment."); 01549 01550 // STUB OPTION, NOT YET FULLY IMPLEMENTED 01551 Pint = secprop->Add_int("acpi reserved size", Property::Changeable::WhenIdle,0); 01552 Pint->Set_help("Amount of memory at top to reserve for ACPI structures and tables. Set to 0 for automatic assignment."); 01553 01554 #if defined(C_EMSCRIPTEN) 01555 Pint = secprop->Add_int("memsize", Property::Changeable::WhenIdle,4); 01556 #else 01557 Pint = secprop->Add_int("memsize", Property::Changeable::WhenIdle,16); 01558 #endif 01559 Pint->SetMinMax(1,3584); // 3.5GB 01560 Pint->Set_help( 01561 "Amount of memory DOSBox-X has in megabytes.\n" 01562 "This value is best left at its default to avoid problems with some games,\n" 01563 "although other games and applications may require a higher value.\n" 01564 "Programs that use 286 protected mode like Windows 3.0 in Standard Mode may crash with more than 15MB."); 01565 01566 Pint = secprop->Add_int("memsizekb", Property::Changeable::WhenIdle,0); 01567 Pint->SetMinMax(0,524288); 01568 Pint->Set_help( 01569 "Amount of memory DOSBox-X has in kilobytes.\n" 01570 "This value should normally be set to 0.\n" 01571 "If nonzero, it is added to the memsize parameter.\n" 01572 "Finer grained control of total memory may be useful in\n" 01573 "emulating ancient DOS machines with less than 640KB of\n" 01574 "RAM or early 386 systems with odd extended memory sizes."); 01575 01576 Pint = secprop->Add_int("dos mem limit", Property::Changeable::WhenIdle,0); 01577 Pint->SetMinMax(0,1023); 01578 Pint->Set_help( "Limit DOS conventional memory to this amount. Does not affect extended memory.\n" 01579 "Setting this option to a value in the range 636-639 can be used to simulate modern BIOSes\n" 01580 "that maintain an EBDA (Extended BIOS Data Area) at the top of conventional memory.\n" 01581 "You may also play with this option for diagnostic purposes or to stress test DOS programs in limited memory setups.\n" 01582 "\n" 01583 "A few DOS games & demos require this option to be set:\n" 01584 " Majic 12 \"Show\": If UMBs are enabled, set this option to 639 to avoid MCB chain corruption error."); 01585 01586 Pbool = secprop->Add_bool("isa memory hole at 512kb",Property::Changeable::WhenIdle,false); 01587 Pbool->Set_help("If set, emulate an ISA memory hole at the 512KB to 640KB area (0x80000-0x9FFFF)."); 01588 01589 Pint = secprop->Add_int("reboot delay", Property::Changeable::WhenIdle,-1); 01590 Pint->SetMinMax(-1,10000); 01591 Pint->Set_help( 01592 "Reboot delay. How long to pause at BIOS POST after reboot in milliseconds.\n" 01593 "This option is provided so that it is possible to see what the guest application\n" 01594 "or OS might have written to the screen before resetting the system. A value of\n" 01595 "-1 means to use a reasonable default."); 01596 01597 Pint = secprop->Add_int("memalias", Property::Changeable::WhenIdle,0); 01598 Pint->SetMinMax(0,32); 01599 Pint->Set_help( 01600 "Memory aliasing emulation, in number of valid address bits.\n" 01601 "Many 386/486 class motherboards and processors prior to 1995\n" 01602 "suffered from memory aliasing for various technical reasons. If the software you are\n" 01603 "trying to run assumes aliasing, or otherwise plays cheap tricks with paging,\n" 01604 "enabling this option can help. Note that enabling this option can cause slight performance degredation. Set to 0 to disable.\n" 01605 "Recommended values when enabled:\n" 01606 " 24: 16MB aliasing. Common on 386SX systems (CPU had 24 external address bits)\n" 01607 " or 386DX and 486 systems where the CPU communicated directly with the ISA bus (A24-A31 tied off)\n" 01608 " 26: 64MB aliasing. Some 486s had only 26 external address bits, some motherboards tied off A26-A31"); 01609 01610 Pbool = secprop->Add_bool("nocachedir",Property::Changeable::WhenIdle,false); 01611 Pbool->Set_help("If set, MOUNT commands will mount with -nocachedir by default."); 01612 01613 Pbool = secprop->Add_bool("freesizecap",Property::Changeable::WhenIdle,true); 01614 Pbool->Set_help("If set, the value of MOUNT -freesize will be applied only if the actual free size is greater than the specified value."); 01615 01616 Pbool = secprop->Add_bool("leading colon write protect image",Property::Changeable::WhenIdle,true); 01617 Pbool->Set_help("If set, BOOT and IMGMOUNT commands will put an image file name with a leading colon (:) in write-protect mode."); 01618 01619 Pint = secprop->Add_int("vga bios size override", Property::Changeable::WhenIdle,0); 01620 Pint->SetMinMax(512,65536); 01621 Pint->Set_help("VGA BIOS size override. Override the size of the VGA BIOS (normally 32KB in compatible or 12KB in non-compatible)."); 01622 01623 Pbool = secprop->Add_bool("video bios dont duplicate cga first half rom font",Property::Changeable::WhenIdle,false); 01624 Pbool->Set_help("If set, save 4KB of EGA/VGA ROM space by pointing to the copy in the ROM BIOS of the first 128 chars"); 01625 01626 Pbool = secprop->Add_bool("video bios always offer 14-pixel high rom font",Property::Changeable::WhenIdle,false); 01627 Pbool->Set_help("If set, video BIOS will always carry the 14-pixel ROM font. If clear, 14-pixel rom font will not be offered except for EGA/VGA emulation."); 01628 01629 Pbool = secprop->Add_bool("video bios always offer 16-pixel high rom font",Property::Changeable::WhenIdle,false); 01630 Pbool->Set_help("If set, video BIOS will always carry the 16-pixel ROM font. If clear, 16-pixel rom font will not be offered except for VGA emulation."); 01631 01632 Pbool = secprop->Add_bool("video bios enable cga second half rom font",Property::Changeable::WhenIdle,true); 01633 Pbool->Set_help("If set, and emulating CGA/PCjr/Tandy, automatically provide the second half of the 8x8 ROM font.\n" 01634 "This setting is ignored for EGA/VGA emulation. If not set, you will need a utility like GRAFTABL.COM to load the second half of the ROM font for graphics.\n" 01635 "NOTE: if you disable the 14 & 16 pixel high font AND the second half when machine=cga, you will disable video bios completely."); 01636 01637 Pstring = secprop->Add_string("forcerate",Property::Changeable::Always,""); 01638 Pstring->Set_help("Force the VGA framerate to a specific value(ntsc, pal, or specific hz), no matter what"); 01639 01640 Pbool = secprop->Add_bool("sierra ramdac",Property::Changeable::WhenIdle,true); 01641 Pbool->Set_help("Whether or not to emulate a Sierra or compatible RAMDAC at port 3C6h-3C9h.\n" 01642 "Some DOS games expect to access port 3C6h to enable highcolor/truecolor SVGA modes on older chipsets.\n" 01643 "Disable if you wish to emulate SVGA hardware that lacks a RAMDAC or (depending on the chipset) does\n" 01644 "not emulate a RAMDAC that is accessible through port 3C6h. This option has no effect for non-VGA video hardware."); 01645 01646 Pbool = secprop->Add_bool("sierra ramdac lock 565",Property::Changeable::WhenIdle,false); 01647 Pbool->Set_help("When emulating High Sierra highcolor RAMDAC, assume 5:6:5 at all times if set. Else,\n" 01648 "bit 6 of the DAC command selects between 5:5:5 and 5:6:5. Set this option for demos or\n" 01649 "games that got the command byte wrong (MFX Transgrassion 2) or any other demo that is\n" 01650 "not rendering highcolor 16bpp correctly."); 01651 01652 Pbool = secprop->Add_bool("page flip debug line",Property::Changeable::Always,false); 01653 Pbool->Set_help("VGA debugging switch. If set, an inverse line will be drawn on the exact scanline that the CRTC display offset registers were written.\n" 01654 "This can be used to help diagnose whether or not the DOS game is page flipping properly according to vertical retrace if the display on-screen is flickering."); 01655 01656 Pbool = secprop->Add_bool("vertical retrace poll debug line",Property::Changeable::Always,false); 01657 Pbool->Set_help("VGA debugging switch. If set, an inverse green dotted line will be drawn on the exact scanline that the CRTC status port (0x3DA) was read.\n" 01658 "This can be used to help diagnose whether the DOS game is propertly waiting for vertical retrace."); 01659 01660 Pbool = secprop->Add_bool("cgasnow",Property::Changeable::WhenIdle,true); 01661 Pbool->Set_help("When machine=cga, determines whether or not to emulate CGA snow in 80x25 text mode"); 01662 01663 /* Default changed to 0x04 for "Blues Brothers" at Allofich's request [https://github.com/joncampbell123/dosbox-x/issues/1273] */ 01664 Phex = secprop->Add_hex("vga 3da undefined bits",Property::Changeable::WhenIdle,0x04); 01665 Phex->Set_help("VGA status port 3BA/3DAh only defines bits 0 and 3. This setting allows you to assign a bit pattern to the undefined bits.\n" 01666 "The purpose of this hack is to deal with demos that read and handle port 3DAh in ways that might crash if all are zero."); 01667 01668 Pbool = secprop->Add_bool("unmask timer on int 10 setmode",Property::Changeable::OnlyAtStart,false); 01669 Pbool->Set_help("If set, INT 10h will unmask IRQ 0 (timer) when setting video modes."); 01670 01671 Pbool = secprop->Add_bool("unmask keyboard on int 16 read",Property::Changeable::OnlyAtStart,true); 01672 Pbool->Set_help("If set, INT 16h will unmask IRQ 1 (keyboard) when asked to read keyboard input.\n" 01673 "It is strongly recommended that you set this option if running Windows 3.11 Windows for Workgroups in DOSBox-X."); 01674 01675 Pbool = secprop->Add_bool("int16 keyboard polling undocumented cf behavior",Property::Changeable::OnlyAtStart,false); 01676 Pbool->Set_help("If set, INT 16h function AH=01h will also set/clear the carry flag depending on whether input was available.\n" 01677 "There are some old DOS games and demos that rely on this behavior to sense keyboard input, and this behavior\n" 01678 "has been verified to occur on some old (early 90s) BIOSes."); 01679 01680 Pbool = secprop->Add_bool("allow port 92 reset",Property::Changeable::OnlyAtStart,true); 01681 Pbool->Set_help("If set (default), allow the application to reset the CPU through port 92h"); 01682 01683 Pbool = secprop->Add_bool("enable port 92",Property::Changeable::WhenIdle,true); 01684 Pbool->Set_help("Emulate port 92h (PS/2 system control port A). If you want to emulate a system that pre-dates the PS/2, set to 0."); 01685 01686 Pbool = secprop->Add_bool("enable 1st dma controller",Property::Changeable::WhenIdle,true); 01687 Pbool->Set_help("Emulate 1st (AT) DMA controller (default). Set to 0 if you wish to emulate a system that lacks DMA (PCjr and some Tandy systems)"); 01688 01689 Pbool = secprop->Add_bool("enable 2nd dma controller",Property::Changeable::WhenIdle,true); 01690 Pbool->Set_help("Emulate 2nd (AT) DMA controller (default). Set to 0 if you wish to emulate a PC/XT system without 16-bit DMA.\n" 01691 "Note: mainline DOSBox automatically disables 16-bit DMA when machine=cga or machine=hercules, while DOSBox-X does not."); 01692 01693 Pbool = secprop->Add_bool("allow dma address decrement",Property::Changeable::WhenIdle,true); 01694 Pbool->Set_help("If set, allow increment & decrement modes as specified in the 8237 datasheet.\n" 01695 "If clear, always increment the address (as if to emulate clone 8237 implementations that skipped the inc/dec bit)."); 01696 01697 Pstring = secprop->Add_string("enable 128k capable 16-bit dma", Property::Changeable::OnlyAtStart,"auto"); 01698 Pstring->Set_values(truefalseautoopt); 01699 Pstring->Set_help("If true, DMA controller emulation models ISA hardware that permits 16-bit DMA to span 128KB.\n" 01700 "If false, DMA controller emulation models PCI hardware that limits 16-bit DMA to 64KB boundaries.\n" 01701 "If auto, the choice is made according to other factors in hardware emulation"); 01702 01703 Pbool = secprop->Add_bool("enable dma extra page registers",Property::Changeable::WhenIdle,true); 01704 Pbool->Set_help("If set, emulate the extra page registers (I/O ports 0x80, 0x84-0x86, 0x88, 0x8C-0x8E), like actual hardware.\n" 01705 "Note that mainline DOSBox behavior is to NOT emulate these registers."); 01706 01707 Pbool = secprop->Add_bool("dma page registers write-only",Property::Changeable::WhenIdle,false); 01708 Pbool->Set_help("Normally (on AT hardware) the DMA page registers are read/write. Set this option if you want to emulate PC/XT hardware where the page registers are write-only."); 01709 01710 Pbool = secprop->Add_bool("cascade interrupt never in service",Property::Changeable::WhenIdle,false); 01711 Pbool->Set_help("If set, PIC emulation will never mark cascade interrupt as in service. This is OFF by default. It is a hack for troublesome games."); 01712 01713 // TODO: "Special mode" which apparently triggers this alternate behavior and used by default on PC-98, is configurable 01714 // by software through the PIC control words, and should control this setting if this is "auto". 01715 // It's time for "auto" default setting to end once and for all the running gag that PC-98 games will not run 01716 // properly without having to add "cascade interrupt ignore in service=true" to your dosbox-x.conf all the time. 01717 Pstring = secprop->Add_string("cascade interrupt ignore in service",Property::Changeable::WhenIdle,"auto"); 01718 Pstring->Set_values(truefalseautoopt); 01719 Pstring->Set_help("If true, PIC emulation will allow slave pic interrupts even if the cascade interrupt is still \"in service\" (common PC-98 behavior)\n" 01720 "If false, PIC emulation will consider cascade in-service state when deciding which interrupt to signal (common IBM PC behavior)\n" 01721 "If auto, setting is chosen based on machine type and other configuration."); 01722 01723 Pbool = secprop->Add_bool("enable slave pic",Property::Changeable::WhenIdle,true); 01724 Pbool->Set_help("Enable slave PIC (IRQ 8-15). Set this to 0 if you want to emulate a PC/XT type arrangement with IRQ 0-7 and no IRQ 2 cascade."); 01725 01726 Pbool = secprop->Add_bool("enable pc nmi mask",Property::Changeable::WhenIdle,true); 01727 Pbool->Set_help("Enable PC/XT style NMI mask register (0xA0). Note that this option conflicts with the secondary PIC and will be ignored if the slave PIC is enabled."); 01728 01729 Pbool = secprop->Add_bool("rom bios 8x8 CGA font",Property::Changeable::Always,true); 01730 Pbool->Set_help("If set, or mainline DOSBox compatible BIOS mapping, a legacy 8x8 CGA font (first 128 characters) is stored at 0xF000:0xFA6E. DOS programs that do not use INT 10h to locate fonts might require that font to be located there."); 01731 01732 Pbool = secprop->Add_bool("rom bios video parameter table",Property::Changeable::Always,true); 01733 Pbool->Set_help("If set, or mainline DOSBox compatible BIOS mapping, DOSBox-X will emulate the video parameter table and assign that to INT 1Dh. If clear, table will not be provided."); 01734 01735 Pbool = secprop->Add_bool("allow more than 640kb base memory",Property::Changeable::Always,false); 01736 Pbool->Set_help("If set, and space is available, allow conventional memory to extend past 640KB.\n" 01737 "For example, if machine=cga, conventional memory can extend out to 0xB800 and provide up to 736KB of RAM.\n" 01738 "This allows you to emulate PC/XT style memory extensions."); 01739 01740 Pbool = secprop->Add_bool("int 10h points at vga bios",Property::Changeable::Always,true); 01741 Pbool->Set_help("If set, INT 10h points at the VGA BIOS. If clear, INT 10h points into the system BIOS. This option only affects EGA/VGA/SVGA emulation.\n" 01742 "This option is needed for some older DOS applications that make additional checks before detecting EGA/VGA hardware (SuperCalc)."); 01743 01744 Pbool = secprop->Add_bool("vesa zero buffer on get information",Property::Changeable::Always,true); 01745 Pbool->Set_help("This setting affects VESA BIOS function INT 10h AX=4F00h. If set, the VESA BIOS will zero the\n" 01746 "256-byte buffer defined by the standard at ES:DI, then fill in the structure. If clear, only\n" 01747 "the structure members will be filled in, and memory outside the initial 20-32 bytes will remain\n" 01748 "unmodified. This setting is ON by default. Some very early 1990s DOS games that support VESA\n" 01749 "BIOS standards may need this setting turned OFF if the programmer did not provide enough space\n" 01750 "for the entire 256 byte structure and the game crashes if it detects VESA BIOS extensions.\n" 01751 "Needed for:\n" 01752 " GETSADAM.EXE"); 01753 01754 /* should be set to zero unless for very specific demos: 01755 * - "Melvindale" by MFX (1996): Set this to 2, the nightmarish visual rendering code appears to draw 2 scanlines 01756 * upward from the VESA linear framebuffer base we return, causing DOSBox to emit warnings about illegal read/writes 01757 * from 0xBFFFF000-0xBFFFFFFF (just before the base of the framebuffer at 0xC0000000). It also has the effect of 01758 * properly centering the picture on the screen. I suppose it's a miracle the demo didn't crash people's computers 01759 * writing to undefined areas like that. */ 01760 Pint = secprop->Add_int("vesa lfb base scanline adjust",Property::Changeable::WhenIdle,0); 01761 Pint->Set_help("If non-zero, the VESA BIOS will report the linear framebuffer offset by this many scanlines.\n" 01762 "This does not affect the linear framebuffer's location. It only affects the linear framebuffer\n" 01763 "location reported by the VESA BIOS. Set to nonzero for DOS games with sloppy VESA graphics pointer management.\n" 01764 " MFX \"Melvindale\" (1996): Set this option to 2 to center the picture properly."); 01765 01766 /* If set, all VESA BIOS modes map 128KB of video RAM at A0000-BFFFF even though VESA BIOS emulation 01767 * reports a 64KB window. Some demos like the 1996 Wired report 01768 * (ftp.scene.org/pub/parties/1995/wired95/misc/e-w95rep.zip) assume they can write past the window 01769 * by spilling into B0000 without bank switching. */ 01770 Pbool = secprop->Add_bool("vesa map non-lfb modes to 128kb region",Property::Changeable::Always,false); 01771 Pbool->Set_help("If set, VESA BIOS SVGA modes will be set to map 128KB of video memory to A0000-BFFFF instead of\n" 01772 "64KB at A0000-AFFFF. This does not affect the SVGA window size or granularity.\n" 01773 "Some games or demoscene productions assume that they can render into the next SVGA window/bank\n" 01774 "by writing to video memory beyond the current SVGA window address and will not appear correctly\n" 01775 "without this option."); 01776 01777 Pbool = secprop->Add_bool("allow hpel effects",Property::Changeable::Always,false); 01778 Pbool->Set_help("If set, allow the DOS demo or program to change the horizontal pel (panning) register per scanline.\n" 01779 "Some early DOS demos use this to create waving or sinus effects on the picture. Not very many VGA\n" 01780 "chipsets allow this, so far, only ATI chipsets are known to support this effect. Disabled by default."); 01781 01782 Pbool = secprop->Add_bool("allow hretrace effects",Property::Changeable::Always,false); 01783 Pbool->Set_help("If set, allow the DOS demo or program to make the picture wavy by playing with the 'start horizontal" 01784 "retrace' register of the CRTC during the active picture. Some early DOS demos (Copper by Surprise!" 01785 "productions) need this option set for some demo effects to work. Disabled by default."); 01786 01787 Pdouble = secprop->Add_double("hretrace effect weight",Property::Changeable::Always,4.0); 01788 Pdouble->Set_help("If emulating hretrace effects, this parameter adds 'weight' to the offset to smooth it out.\n" 01789 "the larger the number, the more averaging is applied. This is intended to emulate the inertia\n" 01790 "of the electron beam in a CRT monitor"); 01791 01792 Pint = secprop->Add_int("vesa modelist cap",Property::Changeable::Always,0); 01793 Pint->Set_help("IF nonzero, the VESA modelist is capped so that it contains no more than the specified number of video modes."); 01794 01795 Pint = secprop->Add_int("vesa modelist width limit",Property::Changeable::Always,1280); 01796 Pint->Set_help("IF nonzero, VESA modes with horizontal resolution higher than the specified pixel count will not be listed.\n" 01797 "This is another way the modelist can be capped for DOS applications that have trouble with long modelists."); 01798 01799 Pint = secprop->Add_int("vesa modelist height limit",Property::Changeable::Always,1024); 01800 Pint->Set_help("IF nonzero, VESA modes with vertical resolution higher than the specified pixel count will not be listed.\n" 01801 "This is another way the modelist can be capped for DOS applications that have trouble with long modelists."); 01802 01803 Pbool = secprop->Add_bool("vesa vbe put modelist in vesa information",Property::Changeable::Always,false); 01804 Pbool->Set_help("If set, the VESA modelist is placed in the VESA information structure itself when the DOS application\n" 01805 "queries information on the VESA BIOS. Setting this option may help with some games, though it limits\n" 01806 "the mode list reported to the DOS application."); 01807 01808 Pbool = secprop->Add_bool("vesa vbe 1.2 modes are 32bpp",Property::Changeable::Always,true); 01809 Pbool->Set_help("If set, truecolor (16M color) VESA BIOS modes in the 0x100-0x11F range are 32bpp. If clear, they are 24bpp.\n" 01810 "Some DOS games and demos assume one bit depth or the other and do not enumerate VESA BIOS modes, which is why this\n" 01811 "option exists."); 01812 01813 Pbool = secprop->Add_bool("allow low resolution vesa modes",Property::Changeable::Always,true); 01814 Pbool->Set_help("If set, allow low resolution VESA modes (320x200x16/24/32bpp and so on). You could set this to false to simulate\n" 01815 "SVGA hardware with a BIOS that does not support the lowres modes for testing purposes."); 01816 01817 Pbool = secprop->Add_bool("allow explicit 24bpp vesa modes",Property::Changeable::Always,false); 01818 Pbool->Set_help("If set, additional 24bpp modes are listed in the modelist regardless whether modes 0x100-0x11F are\n" 01819 "configured to be 24bpp or 32bpp. Setting this option can provide the best testing and development\n" 01820 "environment for new retro DOS code. If clear, 24bpp will only be available in the 0x100-0x11F range\n" 01821 "if the \"vesa vbe 1.2 modes are 32bpp\" is false. Setting to false helps to emulate typical SVGA\n" 01822 "hardware in which either 24bpp is supported, or 32bpp is supported, but not both. Disabled by default."); 01823 01824 Pbool = secprop->Add_bool("allow high definition vesa modes",Property::Changeable::Always,false); 01825 Pbool->Set_help("If set, offer HD video modes in the VESA modelist (such as 1280x720 aka 720p or 1920x1080 aka 1080p).\n" 01826 "This option also offers 4:3 versions (960x720 and 1440x1080) for DOS games that cannot properly handle\n" 01827 "a 16:9 aspect ratio, and several other HD modes. The modes enabled by this option are still limited by the\n" 01828 "width and height limits and available video memory.\n" 01829 "This is unusual for VESA BIOSes to do and is disabled by default."); 01830 01831 Pbool = secprop->Add_bool("allow unusual vesa modes",Property::Changeable::Always,false); 01832 Pbool->Set_help("If set, unusual (uncommon) modes are added to the list. The modes reflect uncommon resolutions\n" 01833 "added by external drivers (UNIVBE), some VESA BIOSes, some laptop and netbook displays, and\n" 01834 "some added by DOSBox-X for additional fun. Disabled by default."); 01835 01836 Pbool = secprop->Add_bool("allow 32bpp vesa modes",Property::Changeable::Always,true); 01837 Pbool->Set_help("If the DOS game or demo has problems with 32bpp VESA modes, set to 'false'"); 01838 01839 Pbool = secprop->Add_bool("allow 24bpp vesa modes",Property::Changeable::Always,true); 01840 Pbool->Set_help("If the DOS game or demo has problems with 24bpp VESA modes, set to 'false'"); 01841 01842 Pbool = secprop->Add_bool("allow 16bpp vesa modes",Property::Changeable::Always,true); 01843 Pbool->Set_help("If the DOS game or demo has problems with 16bpp VESA modes, set to 'false'"); 01844 01845 Pbool = secprop->Add_bool("allow 15bpp vesa modes",Property::Changeable::Always,true); 01846 Pbool->Set_help("If the DOS game or demo has problems with 15bpp VESA modes, set to 'false'"); 01847 01848 Pbool = secprop->Add_bool("allow 8bpp vesa modes",Property::Changeable::Always,true); 01849 Pbool->Set_help("If the DOS game or demo has problems with 8bpp VESA modes, set to 'false'"); 01850 01851 Pbool = secprop->Add_bool("allow 4bpp vesa modes",Property::Changeable::Always,true); 01852 Pbool->Set_help("If the DOS game or demo has problems with 4bpp VESA modes, set to 'false'.\n" 01853 "These modes have the same 16-color planar memory layout as standard VGA, but\n" 01854 "at SVGA resolution."); 01855 01856 Pbool = secprop->Add_bool("allow 4bpp packed vesa modes",Property::Changeable::Always,false); 01857 Pbool->Set_help("If the DOS game or demo has problems with 4bpp packed VESA modes, set to 'false'.\n" 01858 "4bpp (16-color) packed is an unusual novelty mode only seen on specific Chips & Tech 65550\n" 01859 "VESA BIOSes such as the one in a Toshiba Libretto laptop. Disabled by default."); 01860 01861 Pbool = secprop->Add_bool("allow tty vesa modes",Property::Changeable::Always,true); 01862 Pbool->Set_help("If the DOS game or demo has problems with text VESA modes, set to 'false'"); 01863 01864 Pbool = secprop->Add_bool("double-buffered line compare",Property::Changeable::Always,false); 01865 Pbool->Set_help("This setting affects the VGA Line Compare register. Set to false (default value) to emulate most VGA behavior\n" 01866 "Set to true for the value to latch once at the start of the frame."); 01867 01868 Pbool = secprop->Add_bool("ignore vblank wraparound",Property::Changeable::Always,false); 01869 Pbool->Set_help("DOSBox-X can handle active display properly if games or demos reprogram vertical blanking to end in the active picture area.\n" 01870 "If the wraparound handling prevents the game from displaying properly, set this to false. Out of bounds vblank values will be ignored.\n"); 01871 01872 Pbool = secprop->Add_bool("enable vga resize delay",Property::Changeable::Always,false); 01873 Pbool->Set_help("If the DOS game you are running relies on certain VGA raster tricks that affect active display area, enable this option.\n" 01874 "This adds a delay between VGA mode changes and window updates. It also means that if you are capturing a demo or game,\n" 01875 "that your capture will also show a few garbled frames at any point mode changes occur, which is why this option is disabled\n" 01876 "by default. If you intend to run certain DOS games and demos like DoWhackaDo, enable this option."); 01877 01878 Pbool = secprop->Add_bool("resize only on vga active display width increase",Property::Changeable::Always,false); 01879 Pbool->Set_help("If set, changes to the Display End register of the CRTC do not trigger DOSBox-X to resize its window\n" 01880 "IF the value written is less than the current value. Some demos like DoWhackaDo need this option set\n" 01881 "because of the way its raster effects work. If the DOSBox-X window rapidly changes size during a demo\n" 01882 "try setting this option. Else, leave it turned off. Changes to other VGA CRTC registers will trigger\n" 01883 "a DOSBox-X mode change as normal regardless of this setting."); 01884 01885 Pbool = secprop->Add_bool("enable pci bus",Property::Changeable::OnlyAtStart,true); 01886 Pbool->Set_help("Enable PCI bus emulation"); 01887 01888 Pbool = secprop->Add_bool("vga palette update on full load",Property::Changeable::Always,true); 01889 Pbool->Set_help("If set, all three bytes of the palette entry must be loaded before taking the color,\n" 01890 "which is fairly typical SVGA behavior. If not set, partial changes are allowed."); 01891 01892 Pbool = secprop->Add_bool("ignore odd-even mode in non-cga modes",Property::Changeable::Always,false); 01893 Pbool->Set_help("Some demoscene productions use VGA Mode X but accidentally enable odd/even mode.\n" 01894 "Setting this option can correct for that and render the demo properly.\n" 01895 "This option forces VGA emulation to ignore odd/even mode except in text and CGA modes."); 01896 01897 secprop=control->AddSection_prop("pc98",&Null_Init); 01898 Pbool = secprop->Add_bool("pc-98 BIOS copyright string",Property::Changeable::WhenIdle,false); 01899 Pbool->Set_help("If set, the PC-98 BIOS copyright string is placed at E800:0000. Enable this for software that detects PC-98 vs Epson."); 01900 01901 Pbool = secprop->Add_bool("pc-98 int 1b fdc timer wait",Property::Changeable::WhenIdle,false); 01902 Pbool->Set_help("If set, INT 1Bh floppy access will wait for the timer to count down before returning.\n" 01903 "This is needed for Ys II to run without crashing."); 01904 01905 Pbool = secprop->Add_bool("pc-98 pic init to read isr",Property::Changeable::WhenIdle,true); 01906 Pbool->Set_help("If set, the programmable interrupt controllers are initialized by default (if PC-98 mode)\n" 01907 "so that the in-service interrupt status can be read immediately. There seems to be a common\n" 01908 "convention in PC-98 games to program and/or assume this mode for cooperative interrupt handling.\n" 01909 "This option is enabled by default for best compatibility with PC-98 games."); 01910 01911 Pstring = secprop->Add_string("pc-98 fm board",Property::Changeable::Always,"auto"); 01912 Pstring->Set_values(pc98fmboards); 01913 Pstring->Set_help("In PC-98 mode, selects the FM music board to emulate."); 01914 01915 Pint = secprop->Add_int("pc-98 fm board irq", Property::Changeable::WhenIdle,0); 01916 Pint->Set_help("If set, helps to determine the IRQ of the FM board. A setting of zero means to auto-determine the IRQ."); 01917 01918 Phex = secprop->Add_hex("pc-98 fm board io port", Property::Changeable::WhenIdle,0); 01919 Phex->Set_help("If set, helps to determine the base I/O port of the FM board. A setting of zero means to auto-determine the port number."); 01920 01921 Pbool = secprop->Add_bool("pc-98 sound bios",Property::Changeable::WhenIdle,false); 01922 Pbool->Set_help("Set Sound BIOS enabled bit in MEMSW 4 for some games that require it.\n" 01923 "TODO: Real emulation of PC-9801-26K/86 Sound BIOS"); 01924 01925 Pbool = secprop->Add_bool("pc-98 load sound bios rom file",Property::Changeable::WhenIdle,true); 01926 Pbool->Set_help("If set, load SOUND.ROM if available and prsent that to the guest instead of trying to emulate directly.\n" 01927 "This is strongly recommended, and is default enabled.\n" 01928 "SOUND.ROM is a snapshot of the FM board BIOS taken from real PC-98 hardware."); 01929 01930 Pbool = secprop->Add_bool("pc-98 buffer page flip",Property::Changeable::WhenIdle,false); 01931 Pbool->Set_help("If set, the game's request to page flip will be delayed to vertical retrace, which can eliminate tearline artifacts.\n" 01932 "Note that this is NOT the behavior of actual hardware. This option is provided for the user's preference."); 01933 01934 Pbool = secprop->Add_bool("pc-98 enable 256-color planar",Property::Changeable::WhenIdle,true); 01935 Pbool->Set_help("Allow 256-color planar graphics mode if set, disable if not set.\n" 01936 "This is a form of memory access in 256-color mode that existed for a short\n" 01937 "time before later PC-9821 models removed it. This option must be enabled\n" 01938 "to use DOSBox-X with Windows 3.1 and it's built-in 256-color driver."); 01939 01940 Pbool = secprop->Add_bool("pc-98 enable 256-color",Property::Changeable::WhenIdle,true); 01941 Pbool->Set_help("Allow 256-color graphics mode if set, disable if not set"); 01942 01943 Pbool = secprop->Add_bool("pc-98 enable 16-color",Property::Changeable::WhenIdle,true); 01944 Pbool->Set_help("Allow 16-color graphics mode if set, disable if not set"); 01945 01946 Pbool = secprop->Add_bool("pc-98 enable grcg",Property::Changeable::WhenIdle,true); 01947 Pbool->Set_help("Allow GRCG graphics functions if set, disable if not set"); 01948 01949 Pbool = secprop->Add_bool("pc-98 enable egc",Property::Changeable::WhenIdle,true); 01950 Pbool->Set_help("Allow EGC graphics functions if set, disable if not set"); 01951 01952 Pbool = secprop->Add_bool("pc-98 enable 188 user cg",Property::Changeable::WhenIdle,true); 01953 Pbool->Set_help("Allow 188+ user-defined CG cells if set"); 01954 01955 Pbool = secprop->Add_bool("pc-98 start gdc at 5mhz",Property::Changeable::WhenIdle,false); 01956 Pbool->Set_help("Start GDC at 5MHz if set, 2.5MHz if clear. May be required for some games."); 01957 01958 Pbool = secprop->Add_bool("pc-98 allow scanline effect",Property::Changeable::WhenIdle,true); 01959 Pbool->Set_help("If set, PC-98 emulation will allow the DOS application to enable the 'scanline effect'\n" 01960 "in 200-line graphics modes upconverted to 400-line raster display. When enabled, odd\n" 01961 "numbered scanlines are blanked instead of doubled"); 01962 01963 Pbool = secprop->Add_bool("pc-98 bus mouse",Property::Changeable::WhenIdle,true); 01964 Pbool->Set_help("Enable PC-98 bus mouse emulation. Disabling this option does not disable INT 33h emulation."); 01965 01966 Pstring = secprop->Add_string("pc-98 video mode",Property::Changeable::WhenIdle,""); 01967 Pstring->Set_values(pc98videomodeopt); 01968 Pstring->Set_help("Specify the preferred PC-98 video mode.\n" 01969 "Valid values are 15, 24, or 31 for each specific horizontal refresh rate on the platform.\n" 01970 "24khz is default and best supported at this time.\n" 01971 "15khz is not implemented at this time.\n" 01972 "31khz is experimental at this time."); 01973 01974 Pstring = secprop->Add_string("pc-98 timer always cycles",Property::Changeable::WhenIdle,"auto"); 01975 Pstring->Set_values(truefalseautoopt); 01976 Pstring->Set_help("This controls PIT 1 PC speaker behavior related to turning the output on and off.\n" 01977 "Default setting is 'auto' to let the emulator choose for you.\n" 01978 "true: PIT 1 will always cycle whether or not the speaker is on (PC-9801 behavior).\n" 01979 "false: PIT 1 will only cycle when the speaker is on (PC-9821 behavior).\n" 01980 "Some older games will require the PC-9801 behavior to function properly."); 01981 01982 Pint = secprop->Add_int("pc-98 timer master frequency", Property::Changeable::WhenIdle,0); 01983 Pint->SetMinMax(0,2457600); 01984 Pint->Set_help("8254 timer clock frequency (NEC PC-98). Depending on the CPU frequency the clock frequency is one of two common values.\n" 01985 "If your setting is neither of the below the closest appropriate value will be chosen.\n" 01986 "This setting affects the master clock rate that DOS applications must divide down from to program the timer\n" 01987 "at the correct rate, which affects timer interrupt, PC speaker, and the COM1 RS-232C serial port baud rate.\n" 01988 "8MHz is treated as an alias for 4MHz and 10MHz is treated as an alias for 5MHz.\n" 01989 " 0: Use default (auto)\n" 01990 " 4: 1.996MHz (as if 4MHz or multiple thereof CPU clock)\n" 01991 " 5: 2.457MHz (as if 5MHz or multiple thereof CPU clock)"); 01992 01993 Pint = secprop->Add_int("pc-98 allow 4 display partition graphics", Property::Changeable::WhenIdle,-1); 01994 Pint->SetMinMax(-1,1); 01995 Pint->Set_help("According to NEC graphics controller documentation, graphics mode is supposed to support only\n" 01996 "2 display partitions. Some games rely on hardware flaws that allowed 4 partitions.\n" 01997 " -1: Default (choose automatically)\n" 01998 " 0: Disable\n" 01999 " 1: Enable"); 02000 02001 Pbool = secprop->Add_bool("pc-98 force ibm keyboard layout",Property::Changeable::WhenIdle,false); 02002 Pbool->Set_help("Force to use a default keyboard layout like IBM US-English for PC-98 emulation.\n" 02003 "Will only work with apps and games using BIOS for keyboard."); 02004 02005 /* Explanation: NEC's mouse driver MOUSE.COM enables the graphics layer on startup and when INT 33h AX=0 is called. 02006 * Some games by "Orange House" assume this behavior and do not make any effort on their 02007 * own to show and enable graphics. Without this option, those games will not show any 02008 * graphics. PC-98 systems have been confirmed to boot up with the graphics layer disabled 02009 * and set to 640x200 8-color planar mode. This has been confirmed on real hardware. 02010 * See also [https://github.com/joncampbell123/dosbox-x/issues/1305] */ 02011 Pbool = secprop->Add_bool("pc-98 show graphics layer on initialize",Property::Changeable::WhenIdle,true); 02012 Pbool->Set_help("If PC-98 mode and INT 33h emulation is enabled, the graphics layer will be automatically enabled\n" 02013 "at driver startup AND when INT 33h AX=0 is called. This is NEC MOUSE.COM behavior and default\n" 02014 "enabled. To emulate other drivers like QMOUSE that do not follow this behavior, set to false."); 02015 02016 secprop=control->AddSection_prop("render",&Null_Init,true); 02017 Pint = secprop->Add_int("frameskip",Property::Changeable::Always,0); 02018 Pint->SetMinMax(0,10); 02019 Pint->Set_help("How many frames DOSBox-X skips before drawing one."); 02020 02021 Pbool = secprop->Add_bool("alt render",Property::Changeable::Always,false); 02022 Pbool->Set_help("If set, use a new experimental rendering engine"); 02023 02024 Pstring = secprop->Add_string("aspect", Property::Changeable::Always, "false"); 02025 Pstring->Set_values(aspectmodes); 02026 Pstring->Set_help( 02027 "Aspect ratio correction mode. Can be set to the following values:\n" 02028 " 'false' (default):\n" 02029 " 'direct3d'/opengl outputs: image is simply scaled to full window/fullscreen size, possibly resulting in disproportional image\n" 02030 " 'surface' output: it does no aspect ratio correction (default), resulting in disproportional images if VGA mode pixel ratio is not 4:3\n" 02031 " 'true':\n" 02032 " 'direct3d'/opengl outputs: uses output driver functions to scale / pad image with black bars, correcting output to proportional 4:3 image\n" 02033 " In most cases image degradation should not be noticeable (it all depends on the video adapter and how much the image is upscaled).\n" 02034 " Should have none to negligible impact on performance, mostly being done in hardware\n" 02035 " 'surface' output: inherits old DOSBox aspect ratio correction method (adjusting rendered image line count to correct output to 4:3 ratio)\n" 02036 " Due to source image manipulation this mode does not mix well with scalers, i.e. multiline scalers like hq2x/hq3x will work poorly\n" 02037 " Slightly degrades visual image quality. Has a tiny impact on performance" 02038 #if C_XBRZ 02039 "\n" 02040 " When using xBRZ scaler with 'surface' output, aspect ratio correction is done by the scaler itself, so none of the above apply" 02041 #endif 02042 #if C_SURFACE_POSTRENDER_ASPECT 02043 "\n" 02044 " 'nearest':\n" 02045 " 'direct3d'/opengl outputs: not available, fallbacks to 'true' mode automatically\n" 02046 " 'surface' output: scaler friendly aspect ratio correction, works by rescaling rendered image using nearest neighbor scaler\n" 02047 " Complex scalers work. Image quality is on par with 'true' mode (and better with scalers). More CPU intensive than 'true' mode\n" 02048 #if C_XBRZ 02049 " When using xBRZ scaler with 'surface' output, aspect ratio correction is done by the scaler itself, so it fallbacks to 'true' mode\n" 02050 #endif 02051 " 'bilinear':\n" 02052 " 'direct3d'/opengl outputs: not available, fallbacks to 'true' mode automatically\n" 02053 " 'surface' output: scaler friendly aspect ratio correction, works by rescaling rendered image using bilinear scaler\n" 02054 " Complex scalers work. Image quality is much better, should be on par with using 'direct3d' output + 'true' mode\n" 02055 " Very CPU intensive, high end CPU may be required" 02056 #if C_XBRZ 02057 "\n" 02058 " When using xBRZ scaler with 'surface' output, aspect ratio correction is done by the scaler itself, so it fallbacks to 'true' mode" 02059 #endif 02060 #endif 02061 ); 02062 02063 Pbool = secprop->Add_bool("char9",Property::Changeable::Always,true); 02064 Pbool->Set_help("Allow 9-pixel wide text mode fonts."); 02065 02066 /* NTS: In the original code borrowed from yhkong, this was named "multiscan". All it really does is disable 02067 * the doublescan down-rezzing DOSBox normally does with 320x240 graphics so that you get the full rendition of what a VGA output would emit. */ 02068 Pbool = secprop->Add_bool("doublescan",Property::Changeable::Always,true); 02069 Pbool->Set_help("If set, doublescanned output emits two scanlines for each source line, in the\n" 02070 "same manner as the actual VGA output (320x200 is rendered as 640x400 for example).\n" 02071 "If clear, doublescanned output is rendered at the native source resolution (320x200 as 320x200).\n" 02072 "This affects the raster PRIOR to the software or hardware scalers. Choose wisely.\n"); 02073 02074 Pmulti = secprop->Add_multi("scaler",Property::Changeable::Always," "); 02075 Pmulti->SetValue("normal2x",/*init*/true); 02076 Pmulti->Set_help("Scaler used to enlarge/enhance low resolution modes. If 'forced' is appended,\n" 02077 "then the scaler will be used even if the result might not be desired.\n" 02078 "To fit a scaler in the resolution used at full screen may require a border or side bars.\n" 02079 "To fill the screen entirely, depending on your hardware, a different scaler/fullresolution might work."); 02080 Pstring = Pmulti->GetSection()->Add_string("type",Property::Changeable::Always,"normal2x"); 02081 Pstring->Set_values(scalers); 02082 02083 Pstring = Pmulti->GetSection()->Add_string("force",Property::Changeable::Always,""); 02084 Pstring->Set_values(force); 02085 02086 #if C_XBRZ 02087 Pint = secprop->Add_int("xbrz slice",Property::Changeable::OnlyAtStart,16); 02088 Pint->SetMinMax(1,1024); 02089 Pint->Set_help("Number of screen lines to process in single xBRZ scaler taskset task, affects xBRZ performance, 16 is the default"); 02090 02091 Pint = secprop->Add_int("xbrz fixed scale factor",Property::Changeable::OnlyAtStart, 0); 02092 Pint->SetMinMax(0,6); 02093 Pint->Set_help("To use fixed xBRZ scale factor (i.e. to attune performance), set it to 2-6, 0 - use automatic calculation (default)"); 02094 02095 Pint = secprop->Add_int("xbrz max scale factor",Property::Changeable::OnlyAtStart, 0); 02096 Pint->SetMinMax(0,6); 02097 Pint->Set_help("To cap maximum xBRZ scale factor used (i.e. to attune performance), set it to 2-6, 0 - use scaler allowed maximum (default)"); 02098 #endif 02099 02100 Pbool = secprop->Add_bool("autofit",Property::Changeable::Always,true); 02101 Pbool->Set_help( 02102 "Best fits image to window\n" 02103 "- Intended for output=direct3d, fullresolution=original, aspect=true"); 02104 02105 Pmulti = secprop->Add_multi("monochrome_pal",Property::Changeable::Always," "); 02106 Pmulti->SetValue("green",/*init*/true); 02107 Pmulti->Set_help("Specify the color of monochrome display.\n" 02108 "Possible values: green, amber, gray, white\n" 02109 "Append 'bright' for a brighter look."); 02110 Pstring = Pmulti->GetSection()->Add_string("color",Property::Changeable::Always,"green"); 02111 const char* monochrome_pal_colors[]={ 02112 "green","amber","gray","white",0 02113 }; 02114 Pstring->Set_values(monochrome_pal_colors); 02115 Pstring = Pmulti->GetSection()->Add_string("bright",Property::Changeable::Always,""); 02116 const char* bright[] = { "", "bright", 0 }; 02117 Pstring->Set_values(bright); 02118 02119 secprop=control->AddSection_prop("vsync",&Null_Init,true);//done 02120 02121 Pstring = secprop->Add_string("vsyncmode",Property::Changeable::WhenIdle,"off"); 02122 Pstring->Set_values(vsyncmode); 02123 Pstring->Set_help("Synchronize vsync timing to the host display. Requires calibration within DOSBox-X."); 02124 Pstring = secprop->Add_string("vsyncrate",Property::Changeable::WhenIdle,"75"); 02125 Pstring->Set_values(vsyncrate); 02126 Pstring->Set_help("Vsync rate used if vsync is enabled. Ignored if vsyncmode is set to host (win32)."); 02127 02128 secprop=control->AddSection_prop("cpu",&Null_Init,true);//done 02129 Pstring = secprop->Add_string("core",Property::Changeable::WhenIdle,"auto"); 02130 Pstring->Set_values(cores); 02131 Pstring->Set_help("CPU Core used in emulation. auto will switch to dynamic if available and appropriate.\n" 02132 "WARNING: Do not use dynamic or auto setting core with Windows 95 or other preemptive\n" 02133 "multitasking OSes with protected mode paging, you should use the normal core instead."); 02134 02135 Pbool = secprop->Add_bool("fpu",Property::Changeable::Always,true); 02136 Pbool->Set_help("Enable FPU emulation"); 02137 02138 Pbool = secprop->Add_bool("segment limits",Property::Changeable::Always,true); 02139 Pbool->Set_help("Enforce segment limits"); 02140 02141 Pbool = secprop->Add_bool("double fault",Property::Changeable::Always,true); 02142 Pbool->Set_help("Emulate double fault exception"); 02143 02144 Pbool = secprop->Add_bool("reset on triple fault",Property::Changeable::Always,true); 02145 Pbool->Set_help("Reset CPU on triple fault condition (failure to handle double fault)"); 02146 02147 Pbool = secprop->Add_bool("always report double fault",Property::Changeable::Always,false); 02148 Pbool->Set_help("Always report (to log file) double faults if set. Else, a double fault is reported only once. Set this option for debugging purposes."); 02149 02150 Pbool = secprop->Add_bool("always report triple fault",Property::Changeable::Always,false); 02151 Pbool->Set_help("Always report (to log file) triple faults if set. Else, a triple fault is reported only once. Set this option for debugging purposes."); 02152 02153 Pbool = secprop->Add_bool("enable msr",Property::Changeable::Always,true); 02154 Pbool->Set_help("Allow RDMSR/WRMSR instructions. This option is only meaningful when cputype=pentium.\n" 02155 "WARNING: Leaving this option enabled while installing Windows 95/98/ME can cause crashes."); 02156 02157 Pbool = secprop->Add_bool("enable cmpxchg8b",Property::Changeable::Always,true); 02158 Pbool->Set_help("Enable Pentium CMPXCHG8B instruction. Enable this explicitly if using software that uses this instruction.\n" 02159 "You must enable this option to run Windows ME because portions of the kernel rely on this instruction."); 02160 02161 Pbool = secprop->Add_bool("ignore undefined msr",Property::Changeable::Always,false); 02162 Pbool->Set_help("Ignore RDMSR/WRMSR on undefined registers. Normally the CPU will fire an Invalid Opcode exception in that case.\n" 02163 "This option is off by default, enable if using software or drivers that assumes the presence of\n" 02164 "certain MSR registers without checking. If you are using certain versions of the 3Dfx glide drivers for MS-DOS\n" 02165 "you will need to set this to TRUE as 3Dfx appears to have coded GLIDE2.OVL to assume the presence\n" 02166 "of Pentium Pro/Pentium II MTRR registers.\n" 02167 "WARNING: Leaving this option enabled while installing Windows 95/98/ME can cause crashes."); 02168 02169 /* NTS: This setting is honored by all cpu cores except dynamic core */ 02170 Pint = secprop->Add_int("interruptible rep string op",Property::Changeable::Always,-1); 02171 Pint->SetMinMax(-1,65536); 02172 Pint->Set_help("if nonzero, REP string instructions (LODS/MOVS/STOS/INS/OUTS) are interruptible (by interrupts or other events).\n" 02173 "if zero, REP string instructions are carried out in full before processing events and interrupts.\n" 02174 "Set to -1 for a reasonable default setting based on cpu type and other configuration.\n" 02175 "A setting of 0 can improve emulation speed at the expense of emulation accuracy.\n" 02176 "A nonzero setting (1-8) may be needed for DOS games and demos that use the IRQ 0 interrupt to play digitized samples\n" 02177 "while doing VGA palette animation at the same time (use case of REP OUTS), where the non-interruptible version\n" 02178 "would cause an audible drop in audio pitch."); 02179 02180 Pint = secprop->Add_int("dynamic core cache block size",Property::Changeable::Always,32); 02181 Pint->SetMinMax(1,65536); 02182 Pint->Set_help("dynamic core cache block size. default value is 32. change this value carefully.\n" 02183 "according to forum discussion, setting this to 1 can aid debugging, however doing so\n" 02184 "also causes problems with 32-bit protected mode DOS games and reduces the performance\n" 02185 "of the dynamic core.\n"); 02186 02187 Pstring = secprop->Add_string("cputype",Property::Changeable::Always,"auto"); 02188 Pstring->Set_values(cputype_values); 02189 Pstring->Set_help("CPU Type used in emulation. auto emulates a 486 which tolerates Pentium instructions."); 02190 02191 Pmulti_remain = secprop->Add_multiremain("cycles",Property::Changeable::Always," "); 02192 Pmulti_remain->Set_help( 02193 "Amount of instructions DOSBox-X tries to emulate each millisecond.\n" 02194 "Setting this value too high results in sound dropouts and lags.\n" 02195 "Cycles can be set in 3 ways:\n" 02196 " 'auto' tries to guess what a game needs.\n" 02197 " It usually works, but can fail for certain games.\n" 02198 " 'fixed #number' will set a fixed amount of cycles. This is what you usually\n" 02199 " need if 'auto' fails (Example: fixed 4000).\n" 02200 " 'max' will allocate as much cycles as your computer is able to\n" 02201 " handle."); 02202 02203 Pstring = Pmulti_remain->GetSection()->Add_string("type",Property::Changeable::Always,"auto"); 02204 Pmulti_remain->SetValue("auto",/*init*/true); 02205 Pstring->Set_values(cyclest); 02206 02207 Pmulti_remain->GetSection()->Add_string("parameters",Property::Changeable::Always,""); 02208 02209 Pint = secprop->Add_int("cycleup",Property::Changeable::Always,10); 02210 Pint->SetMinMax(1,1000000); 02211 Pint->Set_help("Amount of cycles to decrease/increase with keycombos.(CTRL-F11/CTRL-F12)"); 02212 02213 Pint = secprop->Add_int("cycledown",Property::Changeable::Always,20); 02214 Pint->SetMinMax(1,1000000); 02215 Pint->Set_help("Setting it lower than 100 will be a percentage."); 02216 02217 Pbool = secprop->Add_bool("use dynamic core with paging on",Property::Changeable::Always,true); 02218 Pbool->Set_help("Allow dynamic core with 386 paging enabled. This is generally OK for DOS games and Windows 3.1.\n" 02219 "If the game becomes unstable, turn off this option.\n" 02220 "WARNING: Do NOT use this option with preemptive multitasking OSes including Windows 95 and Windows NT."); 02221 02222 Pbool = secprop->Add_bool("ignore opcode 63",Property::Changeable::Always,true); 02223 Pbool->Set_help("When debugging, do not report illegal opcode 0x63.\n" 02224 "Enable this option to ignore spurious errors while debugging from within Windows 3.1/9x/ME"); 02225 02226 Pbool = secprop->Add_bool("apmbios",Property::Changeable::WhenIdle,true); 02227 Pbool->Set_help("Emulate Advanced Power Management BIOS calls"); 02228 02229 Pbool = secprop->Add_bool("apmbios pnp",Property::Changeable::WhenIdle,false); 02230 Pbool->Set_help("If emulating ISA PnP BIOS, announce APM BIOS in PnP enumeration.\n" 02231 "Warning: this can cause Windows 95 OSR2 and later to enumerate the APM BIOS twice and cause problems."); 02232 02233 Pstring = secprop->Add_string("apmbios version",Property::Changeable::WhenIdle,"auto"); 02234 Pstring->Set_values(apmbiosversions); 02235 Pstring->Set_help("What version of the APM BIOS specification to emulate.\n" 02236 "You will need at least APM BIOS v1.1 for emulation to work with Windows 95/98/ME"); 02237 02238 Pbool = secprop->Add_bool("apmbios allow realmode",Property::Changeable::WhenIdle,true); 02239 Pbool->Set_help("Allow guest OS to connect from real mode."); 02240 02241 Pbool = secprop->Add_bool("apmbios allow 16-bit protected mode",Property::Changeable::WhenIdle,true); 02242 Pbool->Set_help("Allow guest OS to connect from 16-bit protected mode."); 02243 02244 Pbool = secprop->Add_bool("apmbios allow 32-bit protected mode",Property::Changeable::WhenIdle,true); 02245 Pbool->Set_help("Allow guest OS to connect from 32-bit protected mode.\n" 02246 "If you want power management in Windows 95/98/ME (beyond using the APM to shutdown the computer) you MUST enable this option.\n" 02247 "Windows 95/98/ME does not support the 16-bit real and protected mode APM BIOS entry points.\n" 02248 "Please note at this time that 32-bit APM is unstable under Windows ME"); 02249 02250 Pbool = secprop->Add_bool("integration device",Property::Changeable::WhenIdle,false); 02251 Pbool->Set_help("Enable DOSBox-X integration I/O device. This can be used by the guest OS to match mouse pointer position, for example. EXPERIMENTAL!"); 02252 02253 Pbool = secprop->Add_bool("integration device pnp",Property::Changeable::WhenIdle,false); 02254 Pbool->Set_help("List DOSBox-X integration I/O device as part of ISA PnP enumeration. This has no purpose yet."); 02255 02256 Pbool = secprop->Add_bool("isapnpbios",Property::Changeable::WhenIdle,true); 02257 Pbool->Set_help("Emulate ISA Plug & Play BIOS. Enable if using DOSBox-X to run a PnP aware DOS program or if booting Windows 9x.\n" 02258 "Do not disable if Windows 9x is configured around PnP devices, you will likely confuse it."); 02259 02260 Pbool = secprop->Add_bool("realbig16",Property::Changeable::WhenIdle,false); 02261 Pbool->Set_help("Allow the B (big) bit in real mode. If set, allow the DOS program to set the B bit,\n" 02262 "then jump to realmode with B still set (aka Huge Unreal mode). Needed for Project Angel."); 02263 02264 secprop=control->AddSection_prop("keyboard",&Null_Init); 02265 Pbool = secprop->Add_bool("aux",Property::Changeable::OnlyAtStart,true); 02266 Pbool->Set_help("Enable emulation of the 8042 auxiliary port. PS/2 mouse emulation requires this to be enabled.\n" 02267 "You should enable this if you will be running Windows ME or any other OS that does not use the BIOS to receive mouse events."); 02268 02269 Pbool = secprop->Add_bool("allow output port reset",Property::Changeable::OnlyAtStart,true); 02270 Pbool->Set_help("If set (default), allow the application to reset the CPU through the keyboard controller.\n" 02271 "This option is required to allow Windows ME to reboot properly, whereas Windows 9x and earlier\n" 02272 "will reboot without this option using INT 19h"); 02273 02274 Pstring = secprop->Add_string("controllertype",Property::Changeable::OnlyAtStart,"auto"); 02275 Pstring->Set_values(controllertypes); 02276 Pstring->Set_help("Type of keyboard controller (and keyboard) attached.\n" 02277 "auto Automatically pick according to machine type\n" 02278 "at AT (PS/2) type keyboard\n" 02279 "xt IBM PC/XT type keyboard\n" 02280 "pcjr IBM PCjr type keyboard (only if machine=pcjr)\n" 02281 "pc98 PC-98 keyboard emulation (only if machine=pc98)"); 02282 02283 Pstring = secprop->Add_string("auxdevice",Property::Changeable::OnlyAtStart,"intellimouse"); 02284 Pstring->Set_values(auxdevices); 02285 Pstring->Set_help("Type of PS/2 mouse attached to the AUX port"); 02286 02287 secprop=control->AddSection_prop("pci",&Null_Init,false); //PCI bus 02288 02289 Pstring = secprop->Add_string("voodoo",Property::Changeable::WhenIdle,"auto"); 02290 Pstring->Set_values(voodoo_settings); 02291 Pstring->Set_help("Enable VOODOO support."); 02292 02293 secprop=control->AddSection_prop("mixer",&Null_Init); 02294 Pbool = secprop->Add_bool("nosound",Property::Changeable::OnlyAtStart,false); 02295 Pbool->Set_help("Enable silent mode, sound is still emulated though."); 02296 02297 Pbool = secprop->Add_bool("sample accurate",Property::Changeable::OnlyAtStart,false); 02298 Pbool->Set_help("Enable sample accurate mixing, at the expense of some emulation performance. Enable this option for DOS games and demos that\n" 02299 "require such accuracy for correct Tandy/OPL output including digitized speech. This option can also help eliminate minor\n" 02300 "errors in Gravis Ultrasound emulation that result in random echo/attenuation effects."); 02301 02302 Pbool = secprop->Add_bool("swapstereo",Property::Changeable::OnlyAtStart,false); 02303 Pbool->Set_help("Swaps the left and right stereo channels."); 02304 02305 Pint = secprop->Add_int("rate",Property::Changeable::OnlyAtStart,44100); 02306 Pint->SetMinMax(8000,192000); 02307 Pint->Set_help("Mixer sample rate, setting any device's rate higher than this will probably lower their sound quality."); 02308 02309 Pint = secprop->Add_int("blocksize",Property::Changeable::OnlyAtStart,1024); 02310 Pint->Set_values(blocksizes); 02311 Pint->Set_help("Mixer block size, larger blocks might help sound stuttering but sound will also be more lagged."); 02312 02313 Pint = secprop->Add_int("prebuffer",Property::Changeable::OnlyAtStart,25); 02314 Pint->SetMinMax(0,100); 02315 Pint->Set_help("How many milliseconds of data to keep on top of the blocksize."); 02316 02317 secprop=control->AddSection_prop("midi",&Null_Init,true);//done 02318 02319 Pstring = secprop->Add_string("mpu401",Property::Changeable::WhenIdle,"intelligent"); 02320 Pstring->Set_values(mputypes); 02321 Pstring->Set_help("Type of MPU-401 to emulate."); 02322 02323 Phex = secprop->Add_hex("mpubase",Property::Changeable::WhenIdle,0/*default*/); 02324 Phex->Set_values(mpubases); 02325 Phex->Set_help("The IO address of the MPU-401.\n" 02326 "Set to 0 to use a default I/O address.\n" 02327 "300h to 330h are for use with IBM PC mode.\n" 02328 "C0D0h to F8D0h (in steps of 800h) are for use with NEC PC-98 mode (MPU98).\n" 02329 "80D2h through 80DEh are for use with NEC PC-98 Sound Blaster 16 MPU-401 emulation.\n" 02330 "If not assigned (0), 330h is the default for IBM PC and E0D0h is the default for PC-98."); 02331 02332 Pstring = secprop->Add_string("mididevice",Property::Changeable::WhenIdle,"default"); 02333 Pstring->Set_values(devices); 02334 Pstring->Set_help("Device that will receive the MIDI data from MPU-401."); 02335 02336 Pstring = secprop->Add_string("midiconfig",Property::Changeable::WhenIdle,""); 02337 Pstring->Set_help("Special configuration options for the device driver. This is usually the id or part of the name of the device you want to use (find the id/name with mixer/listmidi).\n" 02338 "Or in the case of coreaudio or synth, you can specify a soundfont here.\n" 02339 "When using a Roland MT-32 rev. 0 as midi output device, some games may require a delay in order to prevent 'buffer overflow' issues.\n" 02340 "In that case, add 'delaysysex', for example: midiconfig=2 delaysysex\n" 02341 "See the README/Manual for more details."); 02342 02343 Pint = secprop->Add_int("samplerate",Property::Changeable::WhenIdle,44100); 02344 Pint->Set_values(rates); 02345 Pint->Set_help("Sample rate for MIDI synthesizer, if applicable."); 02346 02347 Pint = secprop->Add_int("mpuirq",Property::Changeable::WhenIdle,-1); 02348 Pint->SetMinMax(-1,15); 02349 Pint->Set_help("MPU-401 IRQ. -1 to automatically choose."); 02350 02351 /* mt32.romdir added from DOSBox ECE by request. This romdir code taken from DOSBox ECE */ 02352 Pstring = secprop->Add_string("mt32.romdir",Property::Changeable::WhenIdle,""); 02353 Pstring->Set_help("Name of the directory where MT-32 Control and PCM ROM files can be found. Emulation requires these files to work.\n" 02354 " Accepted file names are as follows:\n" 02355 " MT32_CONTROL.ROM or CM32L_CONTROL.ROM - control ROM file.\n" 02356 " MT32_PCM.ROM or CM32L_PCM.ROM - PCM ROM file."); 02357 02358 Pstring = secprop->Add_string("mt32.reverse.stereo",Property::Changeable::WhenIdle,"off"); 02359 Pstring->Set_values(mt32ReverseStereo); 02360 Pstring->Set_help("Reverse stereo channels for MT-32 output"); 02361 02362 Pstring = secprop->Add_string("mt32.verbose",Property::Changeable::WhenIdle,"off"); 02363 Pstring->Set_values(mt32log); 02364 Pstring->Set_help("MT-32 debug logging"); 02365 02366 Pstring = secprop->Add_string("mt32.thread",Property::Changeable::WhenIdle,"off"); 02367 Pstring->Set_values(mt32thread); 02368 Pstring->Set_help("MT-32 rendering in separate thread"); 02369 02370 Pstring = secprop->Add_string("mt32.dac",Property::Changeable::WhenIdle,"auto"); 02371 Pstring->Set_values(mt32DACModes); 02372 Pstring->Set_help("MT-32 DAC input emulation mode\n" 02373 "Nice = 0 - default\n" 02374 "Produces samples at double the volume, without tricks.\n" 02375 "Higher quality than the real devices\n\n" 02376 02377 "Pure = 1\n" 02378 "Produces samples that exactly match the bits output from the emulated LA32.\n" 02379 "Nicer overdrive characteristics than the DAC hacks (it simply clips samples within range)\n" 02380 "Much less likely to overdrive than any other mode.\n" 02381 "Half the volume of any of the other modes, meaning its volume relative to the reverb\n" 02382 "output when mixed together directly will sound wrong. So, reverb level must be lowered.\n" 02383 "Perfect for developers while debugging :)\n\n" 02384 02385 "GENERATION1 = 2\n" 02386 "Re-orders the LA32 output bits as in early generation MT-32s (according to Wikipedia).\n" 02387 "Bit order at DAC (where each number represents the original LA32 output bit number, and XX means the bit is always low):\n" 02388 "15 13 12 11 10 09 08 07 06 05 04 03 02 01 00 XX\n\n" 02389 02390 "GENERATION2 = 3\n" 02391 "Re-orders the LA32 output bits as in later geneerations (personally confirmed on my CM-32L - KG).\n" 02392 "Bit order at DAC (where each number represents the original LA32 output bit number):\n" 02393 "15 13 12 11 10 09 08 07 06 05 04 03 02 01 00 14\n"); 02394 02395 Pstring = secprop->Add_string("mt32.reverb.mode",Property::Changeable::WhenIdle,"auto"); 02396 Pstring->Set_values(mt32reverbModes); 02397 Pstring->Set_help("MT-32 reverb mode"); 02398 02399 Pint = secprop->Add_int("mt32.reverb.time",Property::Changeable::WhenIdle,5); 02400 Pint->Set_values(mt32reverbTimes); 02401 Pint->Set_help("MT-32 reverb decaying time"); 02402 02403 Pint = secprop->Add_int("mt32.reverb.level",Property::Changeable::WhenIdle,3); 02404 Pint->Set_values(mt32reverbLevels); 02405 Pint->Set_help("MT-32 reverb level"); 02406 02407 Pint = secprop->Add_int("mt32.partials",Property::Changeable::WhenIdle,32); 02408 Pint->SetMinMax(0,256); 02409 Pint->Set_help("MT-32 max partials allowed (0-256)"); 02410 02411 #ifdef C_FLUIDSYNTH 02412 const char *fluiddrivers[] = {"pulseaudio", "alsa", "oss", "coreaudio", "dsound", "portaudio", "sndman", "jack", "file", "default",0}; 02413 Pstring = secprop->Add_string("fluid.driver",Property::Changeable::WhenIdle,"default"); 02414 Pstring->Set_values(fluiddrivers); 02415 Pstring->Set_help("Driver to use with Fluidsynth, not needed under Windows. Available drivers depend on what Fluidsynth was compiled with."); 02416 02417 Pstring = secprop->Add_string("fluid.soundfont",Property::Changeable::WhenIdle,""); 02418 Pstring->Set_help("Soundfont to use with Fluidsynth. One must be specified."); 02419 02420 Pstring = secprop->Add_string("fluid.samplerate",Property::Changeable::WhenIdle,"48000"); 02421 Pstring->Set_help("Sample rate to use with Fluidsynth."); 02422 02423 Pstring = secprop->Add_string("fluid.gain",Property::Changeable::WhenIdle,".6"); 02424 Pstring->Set_help("Fluidsynth gain."); 02425 02426 Pint = secprop->Add_int("fluid.polyphony",Property::Changeable::WhenIdle,256); 02427 Pint->Set_help("Fluidsynth polyphony."); 02428 02429 Pstring = secprop->Add_string("fluid.cores",Property::Changeable::WhenIdle,"default"); 02430 Pstring->Set_help("Fluidsynth CPU cores to use, or default."); 02431 02432 Pstring = secprop->Add_string("fluid.periods",Property::Changeable::WhenIdle,"default"); 02433 Pstring->Set_help("Fluidsynth periods, or default."); 02434 02435 Pstring = secprop->Add_string("fluid.periodsize",Property::Changeable::WhenIdle,"default"); 02436 Pstring->Set_help("Fluidsynth period size, or default."); 02437 02438 const char *fluidreverb[] = {"no", "yes",0}; 02439 Pstring = secprop->Add_string("fluid.reverb",Property::Changeable::WhenIdle,"yes"); 02440 Pstring->Set_values(fluidreverb); 02441 Pstring->Set_help("Fluidsynth use reverb."); 02442 02443 const char *fluidchorus[] = {"no", "yes",0}; 02444 Pstring = secprop->Add_string("fluid.chorus",Property::Changeable::WhenIdle,"yes"); 02445 Pstring->Set_values(fluidchorus); 02446 Pstring->Set_help("Fluidsynth use chorus."); 02447 02448 Pstring = secprop->Add_string("fluid.reverb.roomsize",Property::Changeable::WhenIdle,".61"); 02449 Pstring->Set_help("Fluidsynth reverb room size."); 02450 02451 Pstring = secprop->Add_string("fluid.reverb.damping",Property::Changeable::WhenIdle,".23"); 02452 Pstring->Set_help("Fluidsynth reverb damping."); 02453 02454 Pstring = secprop->Add_string("fluid.reverb.width",Property::Changeable::WhenIdle,".76"); 02455 Pstring->Set_help("Fluidsynth reverb width."); 02456 02457 Pstring = secprop->Add_string("fluid.reverb.level",Property::Changeable::WhenIdle,".57"); 02458 Pstring->Set_help("Fluidsynth reverb level."); 02459 02460 Pint = secprop->Add_int("fluid.chorus.number",Property::Changeable::WhenIdle,3); 02461 Pint->Set_help("Fluidsynth chorus voices"); 02462 02463 Pstring = secprop->Add_string("fluid.chorus.level",Property::Changeable::WhenIdle,"1.2"); 02464 Pstring->Set_help("Fluidsynth chorus level."); 02465 02466 Pstring = secprop->Add_string("fluid.chorus.speed",Property::Changeable::WhenIdle,".3"); 02467 Pstring->Set_help("Fluidsynth chorus speed."); 02468 02469 Pstring = secprop->Add_string("fluid.chorus.depth",Property::Changeable::WhenIdle,"8.0"); 02470 Pstring->Set_help("Fluidsynth chorus depth."); 02471 02472 const char *fluidchorustypes[] = {"0", "1",0}; 02473 Pint = secprop->Add_int("fluid.chorus.type",Property::Changeable::WhenIdle,0); 02474 Pint->Set_values(fluidchorustypes); 02475 Pint->Set_help("Fluidsynth chorus type. 0 is sine wave, 1 is triangle wave."); 02476 #endif 02477 02478 secprop=control->AddSection_prop("sblaster",&Null_Init,true); 02479 02480 Pstring = secprop->Add_string("sbtype",Property::Changeable::WhenIdle,"sb16"); 02481 Pstring->Set_values(sbtypes); 02482 Pstring->Set_help("Type of Sound Blaster to emulate. 'gb' is Game Blaster."); 02483 02484 Phex = secprop->Add_hex("sbbase",Property::Changeable::WhenIdle,0x220); 02485 Phex->Set_values(ios); 02486 Phex->Set_help("The IO address of the Sound Blaster.\n" 02487 "220h to 2E0h are for use with IBM PC Sound Blaster emulation.\n" 02488 "D2h to DEh are for use with NEC PC-98 Sound Blaster 16 emulation."); 02489 02490 Pint = secprop->Add_int("irq",Property::Changeable::WhenIdle,7); 02491 Pint->Set_values(irqssb); 02492 Pint->Set_help("The IRQ number of the Sound Blaster. Set to -1 to start DOSBox-X with the IRQ unassigned"); 02493 02494 Pint = secprop->Add_int("mindma",Property::Changeable::OnlyAtStart,-1); 02495 Pint->Set_help( "Minimum DMA transfer left to increase attention across DSP blocks, in milliseconds. Set to -1 for default.\n" 02496 "There are some DOS games/demos that use single-cycle DSP playback in their music tracker and they micromanage\n" 02497 "the DMA transfer per block poorly in a way that causes popping and artifacts. Setting this option to 0 for\n" 02498 "such DOS applications may reduce audible popping and artifacts."); 02499 02500 /* Sound Blaster IRQ hacks. 02501 * 02502 * These hacks reduce emulation accuracy but can be set to work around bugs or mistakes in some old 02503 * games and demos related to handling the Sound Blaster IRQ. 02504 * 02505 * - Saga by Dust (1993): 02506 * Sound Blaster support has a fatal flaw in that the Sound Blaster interrupt handler it installs assumes 02507 * DS == CS. It uses the DS register to read local variables needed to manage the Sound Blaster card but 02508 * it makes no attempt to push DS and then load the DS segment value it needs. While the demo may seem to 02509 * run normally at first, eventually the interrupt is fired at just the right time to catch the demo in 02510 * the middle of it's graphics routines (DS=A000). Since the ISR uses DS to load the Sound Blaster DSP 02511 * I/O port, it reads some random value from *video RAM* and then hangs in a loop waiting for that I/O 02512 * port to clear bit 7! Setting 'cs_equ_ds' works around that bug by instructing PIC emulation not to 02513 * fire the interrupt unless segment registers CS and DS match. */ 02514 Pstring = secprop->Add_string("irq hack",Property::Changeable::WhenIdle,"none"); 02515 Pstring->Set_help("Specify a hack related to the Sound Blaster IRQ to avoid crashes in a handful of games and demos.\n" 02516 " none Emulate IRQs normally\n" 02517 " cs_equ_ds Do not fire IRQ unless two CPU segment registers match: CS == DS. Read Dosbox-X Wiki or source code for details."); 02518 02519 Pint = secprop->Add_int("dma",Property::Changeable::WhenIdle,1); 02520 Pint->Set_values(dmassb); 02521 Pint->Set_help("The DMA number of the Sound Blaster. Set to -1 to start DOSBox-X with the DMA unassigned"); 02522 02523 Pint = secprop->Add_int("hdma",Property::Changeable::WhenIdle,5); 02524 Pint->Set_values(dmassb); 02525 Pint->Set_help("The High DMA number of the Sound Blaster. Set to -1 to start DOSBox-X with the High DMA unassigned"); 02526 02527 Pbool = secprop->Add_bool("pic unmask irq",Property::Changeable::WhenIdle,false); 02528 Pbool->Set_help("Start the DOS virtual machine with the Sound Blaster IRQ already unmasked at the PIC.\n" 02529 "Some early DOS games/demos that support Sound Blaster expect the IRQ to fire but make\n" 02530 "no attempt to unmask the IRQ. If audio cuts out no matter what IRQ you try, then try\n" 02531 "setting this option.\n" 02532 "Option is needed for:\n" 02533 " Public NMI \"jump\" demo (1992)"); 02534 02535 Pbool = secprop->Add_bool("enable speaker",Property::Changeable::WhenIdle,false); 02536 Pbool->Set_help("Start the DOS virtual machine with the Sound Blaster speaker enabled.\n" 02537 "Sound Blaster Pro and older cards have a speaker disable/enable command.\n" 02538 "Normally the card boots up with the speaker disabled. If a DOS game or demo\n" 02539 "attempts to play without enabling the speaker, set this option to true to\n" 02540 "compensate. This setting has no meaning if emulating a Sound Blaster 16 card."); 02541 02542 Pbool = secprop->Add_bool("enable asp",Property::Changeable::WhenIdle,false); 02543 Pbool->Set_help("If set, emulate the presence of the Sound Blaster 16 Advanced Sound Processor/Creative Sound Processor chip.\n" 02544 "NOTE: This only emulates it's presence and the basic DSP commands to communicate with it. Actual ASP/CSP functions are not yet implemented."); 02545 02546 Pbool = secprop->Add_bool("disable filtering",Property::Changeable::WhenIdle,false); 02547 Pbool->Set_help("By default DOSBox-X filters Sound Blaster output to emulate lowpass filters and analog output limitations.\n" 02548 "Set this option to true to disable filtering. Note that doing so disables emulation of the Sound Blaster Pro\n" 02549 "output filter and ESS AudioDrive lowpass filter."); 02550 02551 Pbool = secprop->Add_bool("dsp write buffer status must return 0x7f or 0xff",Property::Changeable::WhenIdle,false); 02552 Pbool->Set_help("If set, force port 22Ch (DSP write buffer status) to return 0x7F or 0xFF. If not set, the port\n" 02553 "may return 0x7F or 0xFF depending on what type of Sound Blaster is being emulated.\n" 02554 "Set this option for some early DOS demos that make that assumption about port 22Ch.\n" 02555 "Option is needed for:\n" 02556 " Overload by Hysteria (1992) - Audio will crackle/saturate (8-bit overflow) except when sbtype=sb16"); 02557 02558 Pbool = secprop->Add_bool("pre-set sbpro stereo",Property::Changeable::WhenIdle,false); 02559 Pbool->Set_help("Start the DOS virtual machine with the Sound Blaster Pro stereo bit set (in the mixer).\n" 02560 "A few demos support Sound Blaster Pro but forget to set this bit.\n" 02561 "Option is needed for:\n" 02562 " Inconexia by Iguana (1993)"); 02563 02564 Pbool = secprop->Add_bool("sbmixer",Property::Changeable::WhenIdle,true); 02565 Pbool->Set_help("Allow the Sound Blaster mixer to modify the DOSBox-X mixer."); 02566 02567 Pstring = secprop->Add_string("oplmode",Property::Changeable::WhenIdle,"auto"); 02568 Pstring->Set_values(oplmodes); 02569 Pstring->Set_help("Type of OPL emulation. On 'auto' the mode is determined by the 'sbtype' setting.\n" 02570 "All OPL modes are AdLib-compatible, except for 'cms' (set 'sbtype=none' with 'cms' for a Game Blaster)."); 02571 02572 Pbool = secprop->Add_bool("adlib force timer overflow on detect",Property::Changeable::WhenIdle,false); 02573 Pbool->Set_help("If set, Adlib/OPL emulation will signal 'overflow' on timers after 50 I/O reads.\n" 02574 "This is a temporary hack to work around timing bugs noted in DOSBox-X. Certain\n" 02575 "games (Wolfenstein 3D) poll the Adlib status port a fixed number of times assuming\n" 02576 "that the poll loop takes long enough for the Adlib timer to run out. If the game\n" 02577 "cannot reliably detect Adlib at higher cycles counts, but can reliably detect at\n" 02578 "lower cycles counts, set this option.\n" 02579 "NOTE: Technically this decreases emulation accuracy, however it also reflects the\n" 02580 " fact that DOSBox-X's I/O timing code needs some work to better match the\n" 02581 " slowness of the ISA bus per I/O read in consideration of DOS games. So this\n" 02582 " option is ON by default."); 02583 /* NTS: The reason I mention Wolfenstein 3D is that it seems coded not to probe for Sound Blaster unless it 02584 * first detects the Adlib at port 0x388. No Adlib, no Sound Blaster. */ 02585 /* ^ NTS: To see what I mean, download Wolf3d source code, look at ID_SD.C line 1585 (Adlib detection routine). 02586 * Note it sets Timer 1, then reads port 388h 100 times before reading status to detect whether the 02587 * timer "overflowed" (fairly typical Adlib detection code). 02588 * Some quick math: 8333333Hz ISA BCLK / 6 cycles per read (3 wait states) = 1388888 reads/second possible 02589 * 100 I/O reads * (1 / 1388888) = 72us */ 02590 02591 Pstring = secprop->Add_string("oplemu",Property::Changeable::WhenIdle,"default"); 02592 Pstring->Set_values(oplemus); 02593 Pstring->Set_help("Provider for the OPL emulation. 'compat' might provide better quality.\n" 02594 "'nuked' is the most accurate (but the most CPU-intensive). See oplrate as well."); 02595 02596 Pint = secprop->Add_int("oplrate",Property::Changeable::WhenIdle,44100); 02597 Pint->Set_values(oplrates); 02598 Pint->Set_help("Sample rate of OPL music emulation. Use 49716 for highest quality (set the mixer rate accordingly)."); 02599 02600 Phex = secprop->Add_hex("hardwarebase",Property::Changeable::WhenIdle,0x220); 02601 Phex->Set_help("base address of the real hardware Sound Blaster:\n"\ 02602 "210,220,230,240,250,260,280"); 02603 02604 Pbool = secprop->Add_bool("force dsp auto-init",Property::Changeable::WhenIdle,false); 02605 Pbool->Set_help("Treat all single-cycle DSP commands as auto-init to keep playback going.\n" 02606 "This option is a workaround for DOS games or demos that use single-cycle DSP playback commands and\n" 02607 "have problems with missing the Sound Blaster IRQ under load. Do not enable unless you need this workaround.\n" 02608 "Needed for:\n" 02609 " - Extreme \"lunatic\" demo (1993)"); 02610 02611 Pbool = secprop->Add_bool("force goldplay",Property::Changeable::WhenIdle,false); 02612 Pbool->Set_help("Always render Sound Blaster output sample-at-a-time. Testing option. You probably don't want to enable this."); 02613 02614 Pbool = secprop->Add_bool("goldplay",Property::Changeable::WhenIdle,true); 02615 Pbool->Set_help("Enable goldplay emulation."); 02616 02617 Pbool = secprop->Add_bool("goldplay stereo",Property::Changeable::WhenIdle,true); 02618 Pbool->Set_help("Enable workaround for goldplay stereo playback. Many DOS demos using this technique\n" 02619 "don't seem to know they need to double the frequency when programming the DSP time constant for Pro stereo output.\n" 02620 "If stereo playback seems to have artifacts consider enabling this option. For accurate emulation of Sound Blaster\n" 02621 "hardware, disable this option."); 02622 02623 Pstring = secprop->Add_string("dsp require interrupt acknowledge",Property::Changeable::WhenIdle,"auto"); 02624 Pstring->Set_help("If set, the DSP will halt DMA playback until IRQ acknowledgement occurs even in auto-init mode (SB16 behavior).\n" 02625 "If clear, IRQ acknowledgement will have no effect on auto-init playback (SB Pro and earlier & clone behavior)\n" 02626 "If set to 'auto' then behavior is determined by sbtype= setting.\n" 02627 "This is a setting for hardware accuracy in emulation. If audio briefly plays then stops then your DOS game\n" 02628 "and it's not using IRQ (but using DMA), try setting this option to 'false'"); 02629 02630 Pint = secprop->Add_int("dsp write busy delay",Property::Changeable::WhenIdle,-1); 02631 Pint->Set_help("Amount of time in nanoseconds the DSP chip signals 'busy' after writing to the DSP (port 2xCh). Set to -1 to use card-specific defaults.\n" 02632 "WARNING: Setting the value too high (above 20000ns) may have detrimental effects to DOS games that use IRQ 0 and DSP command 0x10 to play audio.\n" 02633 " Setting the value way too high (above 1000000ns) can cause significant lag in DOS games."); 02634 02635 Pbool = secprop->Add_bool("blaster environment variable",Property::Changeable::WhenIdle,true); 02636 Pbool->Set_help("Whether or not to set the BLASTER environment variable automatically at startup"); 02637 02638 Pbool = secprop->Add_bool("sample rate limits",Property::Changeable::WhenIdle,true); 02639 Pbool->Set_help("If set (default), limit DSP sample rate to what real hardware is limited to"); 02640 02641 /* recommended for: 02642 * 1992 demo "overload" (if set, Sound Blaster support can run at 24KHz without causing demo to hang in the IRQ 0 timer) 02643 * 1993 demo "xmas 93" (superiority complex) because the demo's Sound Blaster mode writes at the timer interrupt rate without polling the DSP to check busy state */ 02644 Pbool = secprop->Add_bool("instant direct dac",Property::Changeable::WhenIdle,false); 02645 Pbool->Set_help("If set, direct DAC output commands are instantaneous. This option is intended as a quick fix for\n" 02646 "games or demos that play direct DAC music/sound from the IRQ 0 timer who a) write the DSP command\n" 02647 "and data without polling the DSP to ensure it's ready or b) can get locked into the IRQ 0 handler\n" 02648 "waiting for DSP status when instructed to play at or beyond the DSP's maximum direct DAC sample rate.\n" 02649 "This fix allows broken Sound Blaster code to work and should not be enabled unless necessary."); 02650 02651 /* accuracy emulation: SB16 does not honor SBPro stereo bit in the mixer */ 02652 Pbool = secprop->Add_bool("stereo control with sbpro only",Property::Changeable::WhenIdle,true); 02653 Pbool->Set_help("Default on. If set, Sound Blaster Pro stereo is not available when emulating sb16 or sb16vibra.\n" 02654 "If clear, sb16 emulation will honor the sbpro stereo bit. Note that Creative SB16 cards do not\n" 02655 "honor the stereo bit, and this option allows DOSBox-X emulate that fact. Accuracy setting."); 02656 02657 /* NTS: It turns out (SB16 at least) the DSP will periodically set bit 7 (busy) by itself at some 02658 * clock rate even if it's idle. Casual testing on an old Pentium system with a ViBRA shows 02659 * it's possible to see both 0x7F and 0xFF come back if you repeatedly type "i 22c" in DOS 02660 * DEBUG.EXE. FIXME: At what clock rate and duty cycle does this happen? */ 02661 Pint = secprop->Add_int("dsp busy cycle rate",Property::Changeable::WhenIdle,-1/*default*/); 02662 Pint->Set_help("Sound Blaster 16 DSP chips appear to go busy periodically at some high clock rate\n" 02663 "whether the DSP is actually doing anything for the system or not. This is an accuracy\n" 02664 "option for Sound Blaster emulation. If this option is nonzero, it will be interpreted\n" 02665 "as the busy cycle rate in Hz. If zero, busy cycle will not be emulated. If -1, sound\n" 02666 "blaster emulation will automatically choose a setting based on the sbtype= setting"); 02667 02668 Pint = secprop->Add_int("dsp busy cycle always",Property::Changeable::WhenIdle,-1/*default*/); 02669 Pint->Set_help("If set, the DSP busy cycle always happens. If clear, DSP busy cycle only happens when\n" 02670 "audio playback is running. Default setting is to pick according to the sound card."); 02671 02672 Pint = secprop->Add_int("dsp busy cycle duty",Property::Changeable::WhenIdle,-1/*default*/); 02673 Pint->Set_help("If emulating SB16 busy cycle, this value (0 to 100) controls the duty cycle of the busy cycle.\n" 02674 "If this option is set to -1, Sound Blaster emulation will choose a value automatically according\n" 02675 "to sbtype=. If 0, busy cycle emulation is disabled."); 02676 02677 /* NTS: Confirmed: My Sound Blaster 2.0 (at least) mirrors the DSP on port 22Ch and 22Dh. This option 02678 * will only take effect with sbtype sb1 and sb2, so make it enabled by default. Accuracy setting. */ 02679 Pbool = secprop->Add_bool("io port aliasing",Property::Changeable::WhenIdle,true); 02680 Pbool->Set_help("If set, Sound Blaster ports alias by not decoding the LSB of the I/O port.\n" 02681 "This option only applies when sbtype is set to sb1 or sb2 (not SBPro or SB16).\n" 02682 "This is a hack for the Electromotive Force 'Internal Damage' demo which apparently\n" 02683 "relies on this behavior for Sound Blaster output and should be enabled for accuracy in emulation."); 02684 02685 secprop=control->AddSection_prop("gus",&Null_Init,true); //done 02686 Pbool = secprop->Add_bool("gus",Property::Changeable::WhenIdle,false); 02687 Pbool->Set_help("Enable the Gravis Ultrasound emulation."); 02688 02689 Pbool = secprop->Add_bool("autoamp",Property::Changeable::WhenIdle,false); 02690 Pbool->Set_help("If set, GF1 output will reduce in volume automatically if the sum of all channels exceeds full volume.\n" 02691 "If not set, then loud music will clip to full volume just as it would on real hardware.\n" 02692 "Enable this option for loud music if you want a more pleasing rendition without saturation and distortion."); 02693 02694 Pbool = secprop->Add_bool("unmask dma",Property::Changeable::WhenIdle,false); 02695 Pbool->Set_help("Start the DOS virtual machine with the DMA channel already unmasked at the controller.\n" 02696 "Use this for DOS applications that expect to operate the GUS but forget to unmask the DMA channel."); 02697 02698 Pbool = secprop->Add_bool("ignore channel count while active",Property::Changeable::WhenIdle,false); 02699 Pbool->Set_help("Ignore writes to the active channel count register when the DAC is enabled (bit 1 of GUS reset)\n" 02700 "This is a HACK for demoscene prod 'Ice Fever' without which the music sounds wrong.\n" 02701 "According to current testing real hardware does not behave this way."); 02702 02703 Pbool = secprop->Add_bool("pic unmask irq",Property::Changeable::WhenIdle,false); 02704 Pbool->Set_help("Start the DOS virtual machine with the GUS IRQ already unmasked at the PIC."); 02705 02706 Pbool = secprop->Add_bool("startup initialized",Property::Changeable::WhenIdle,false); 02707 Pbool->Set_help("If set, start the GF1 in a fully initialized state (as if ULTRINIT had been run).\n" 02708 "If clear, leave the card in an uninitialized state (as if cold boot).\n" 02709 "Some DOS games or demoscene productions will hang or fail to use the Ultrasound hardware\n" 02710 "because they assume the card is initialized and their hardware detect does not fully initialize the card."); 02711 02712 Pbool = secprop->Add_bool("dma enable on dma control polling",Property::Changeable::WhenIdle,false); 02713 Pbool->Set_help("If set, automatically enable GUS DMA transfer bit in specific cases when the DMA control register is being polled.\n" 02714 "THIS IS A HACK. Some games and demoscene productions need this hack to avoid hanging while uploading sample data\n" 02715 "to the Gravis Ultrasound due to bugs in their implementation."); 02716 02717 Pbool = secprop->Add_bool("clear dma tc irq if excess polling",Property::Changeable::WhenIdle,false); 02718 Pbool->Set_help("If the DOS application is seen polling the IRQ status register rapidly, automatically clear the DMA TC IRQ status.\n" 02719 "This is a hack that should only be used with DOS applications that need it to avoid bugs in their GUS support code.\n" 02720 "Needed for:\n" 02721 " Warcraft II by Blizzard ............. if using GUS for music and sound, set this option to prevent the game from\n" 02722 " hanging when you click on the buttons in the main menu."); 02723 02724 /* some DOS demos, especially where the programmers wrote their own tracker, forget to set "master IRQ enable" on the GUS, 02725 * and then wonder why music isn't playing. prior to some GUS bugfixes they happend to work anyway because DOSBox also 02726 * ignored master IRQ enable. you can restore that buggy behavior here. 02727 * 02728 * DOS games & demos that need this: 02729 * - "Juice" by Psychic Link (writes 0x300 to GUS reset which only enables DAC and takes card out of reset, does not enable IRQ) */ 02730 Pbool = secprop->Add_bool("force master irq enable",Property::Changeable::WhenIdle,false); 02731 Pbool->Set_help("Set this option if a DOS game or demo initializes the GUS but is unable to play any music.\n" 02732 "Usually the cause is buggy GUS support that resets the GUS but fails to set the Master IRQ enable bit."); 02733 02734 Pstring = secprop->Add_string("gus panning table",Property::Changeable::WhenIdle,"default"); 02735 Pstring->Set_values(guspantables); 02736 Pstring->Set_help("Controls which table or equation is used for the Gravis Ultrasound panning emulation.\n" 02737 "accurate emulation attempts to better reflect how the actual hardware handles panning,\n" 02738 "while the old emulation uses a simpler idealistic mapping."); 02739 02740 Pint = secprop->Add_int("gusrate",Property::Changeable::WhenIdle,44100); 02741 Pint->Set_values(rates); 02742 Pint->Set_help("Sample rate of Ultrasound emulation."); 02743 02744 Pbool = secprop->Add_bool("gus fixed render rate",Property::Changeable::WhenIdle,false); 02745 Pbool->Set_help("If set, Gravis Ultrasound audio output is rendered at a fixed sample rate specified by 'gusrate'. This can provide better quality than real hardware,\n" 02746 "if desired. Else, Gravis Ultrasound emulation will change the sample rate of it's output according to the number of active channels, just like real hardware.\n" 02747 "Note: DOSBox-X defaults to 'false', while mainline DOSBox SVN is currently hardcoded to render as if this setting is 'true'."); 02748 02749 Pint = secprop->Add_int("gusmemsize",Property::Changeable::WhenIdle,-1); 02750 Pint->SetMinMax(-1,1024); 02751 Pint->Set_help("Amount of RAM on the Gravis Ultrasound in KB. Set to -1 for default."); 02752 02753 Pdouble = secprop->Add_double("gus master volume",Property::Changeable::WhenIdle,0); 02754 Pdouble->SetMinMax(-120.0,6.0); 02755 Pdouble->Set_help("Master Gravis Ultrasound GF1 volume, in decibels. Reducing the master volume can help with games or demoscene productions where the music is too loud and clipping"); 02756 02757 Phex = secprop->Add_hex("gusbase",Property::Changeable::WhenIdle,0x240); 02758 Phex->Set_values(iosgus); 02759 Phex->Set_help("The IO base address of the Gravis Ultrasound."); 02760 02761 Pint = secprop->Add_int("gusirq",Property::Changeable::WhenIdle,5); 02762 Pint->Set_values(irqsgus); 02763 Pint->Set_help("The IRQ number of the Gravis Ultrasound."); 02764 02765 Pint = secprop->Add_int("gusdma",Property::Changeable::WhenIdle,3); 02766 Pint->Set_values(dmasgus); 02767 Pint->Set_help("The DMA channel of the Gravis Ultrasound."); 02768 02769 Pstring = secprop->Add_string("irq hack",Property::Changeable::WhenIdle,"none"); 02770 Pstring->Set_help("Specify a hack related to the Gravis Ultrasound IRQ to avoid crashes in a handful of games and demos.\n" 02771 " none Emulate IRQs normally\n" 02772 " cs_equ_ds Do not fire IRQ unless two CPU segment registers match: CS == DS. Read Dosbox-X Wiki or source code for details."); 02773 02774 Pstring = secprop->Add_string("gustype",Property::Changeable::WhenIdle,"classic"); 02775 Pstring->Set_values(gustypes); 02776 Pstring->Set_help( "Type of Gravis Ultrasound to emulate.\n" 02777 "classic Original Gravis Ultrasound chipset\n" 02778 "classic37 Original Gravis Ultrasound with ICS Mixer (rev 3.7)\n" 02779 "max Gravis Ultrasound MAX emulation (with CS4231 codec)\n" 02780 "interwave Gravis Ultrasound Plug & Play (interwave)"); 02781 02782 Pstring = secprop->Add_string("ultradir",Property::Changeable::WhenIdle,"C:\\ULTRASND"); 02783 Pstring->Set_help( 02784 "Path to Ultrasound directory. In this directory\n" 02785 "there should be a MIDI directory that contains\n" 02786 "the patch files for GUS playback. Patch sets used\n" 02787 "with Timidity should work fine."); 02788 02789 secprop = control->AddSection_prop("innova",&Null_Init,true);//done 02790 Pbool = secprop->Add_bool("innova",Property::Changeable::WhenIdle,false); 02791 Pbool->Set_help("Enable the Innovation SSI-2001 emulation."); 02792 Pint = secprop->Add_int("samplerate",Property::Changeable::WhenIdle,22050); 02793 Pint->Set_values(rates); 02794 Pint->Set_help("Sample rate of Innovation SSI-2001 emulation"); 02795 Phex = secprop->Add_hex("sidbase",Property::Changeable::WhenIdle,0x280); 02796 Phex->Set_values(sidbaseno); 02797 Phex->Set_help("SID base port (typically 280h)."); 02798 Pint = secprop->Add_int("quality",Property::Changeable::WhenIdle,0); 02799 Pint->Set_values(qualityno); 02800 Pint->Set_help("Set SID emulation quality level (0 to 3)."); 02801 02802 secprop = control->AddSection_prop("speaker",&Null_Init,true);//done 02803 Pbool = secprop->Add_bool("pcspeaker",Property::Changeable::WhenIdle,true); 02804 Pbool->Set_help("Enable PC-Speaker emulation."); 02805 02806 /* added for "baoxiao-sanguozhi" which for some reason uses both port 61h bit 4 (DRAM refresh) and PIT timer 2 (PC speaker) 02807 * for game timing IN ADDITION TO the BIOS timer counter in the BIOS data area. Game does not set bit 0 itself, so if the 02808 * bit wasn't set, the game will hang when asking for a password. Setting this option to "true" tells the BIOS to start the 02809 * system with that bit set so games like that can run. [https://github.com/joncampbell123/dosbox-x/issues/1274]. 02810 * 02811 * Note that setting clock gate enable will not make audible sound through the PC speaker unless bit 1 (output gate enable) 02812 * is also set. Setting bits [1:0] = to 01 is a way to cycle PIT timer 2 without making audible noise. */ 02813 Pbool = secprop->Add_bool("pcspeaker clock gate enable at startup",Property::Changeable::WhenIdle,false); 02814 Pbool->Set_help("Start system with the clock gate (bit 0 of port 61h) on. Needed for some games that use the PC speaker for timing on IBM compatible systems.\n" 02815 "This option has no effect in PC-98 mode."); 02816 02817 Pint = secprop->Add_int("initial frequency",Property::Changeable::WhenIdle,-1); 02818 Pint->Set_help("PC speaker PIT timer is programmed to this frequency on startup. If the DOS game\n" 02819 "or demo causes a long audible beep at startup (leaving the gate open) try setting\n" 02820 "this option to 0 to silence the PC speaker until reprogrammed by the demo.\n" 02821 "Set to 0 for some early Abaddon demos including \"Torso\" and \"Cycling\"."); 02822 02823 Pint = secprop->Add_int("pcrate",Property::Changeable::WhenIdle,44100); 02824 Pint->Set_values(rates); 02825 Pint->Set_help("Sample rate of the PC-Speaker sound generation."); 02826 02827 Pstring = secprop->Add_string("tandy",Property::Changeable::WhenIdle,"auto"); 02828 Pstring->Set_values(tandys); 02829 Pstring->Set_help("Enable Tandy Sound System emulation. For 'auto', emulation is present only if machine is set to 'tandy'."); 02830 02831 Pint = secprop->Add_int("tandyrate",Property::Changeable::WhenIdle,44100); 02832 Pint->Set_values(rates); 02833 Pint->Set_help("Sample rate of the Tandy 3-Voice generation."); 02834 02835 Pbool = secprop->Add_bool("disney",Property::Changeable::WhenIdle,false); 02836 Pbool->Set_help("Enable Disney Sound Source emulation. (Covox Voice Master and Speech Thing compatible)."); 02837 Pstring = secprop->Add_string("ps1audio",Property::Changeable::WhenIdle,"off"); 02838 Pstring->Set_values(ps1opt); 02839 Pstring->Set_help("Enable PS1 audio emulation."); 02840 Pint = secprop->Add_int("ps1audiorate",Property::Changeable::OnlyAtStart,22050); 02841 Pint->Set_values(rates); 02842 Pint->Set_help("Sample rate of the PS1 audio emulation."); 02843 02844 secprop=control->AddSection_prop("joystick",&Null_Init,false);//done 02845 Pstring = secprop->Add_string("joysticktype",Property::Changeable::WhenIdle,"auto"); 02846 Pstring->Set_values(joytypes); 02847 Pstring->Set_help( 02848 "Type of joystick to emulate: auto (default), none,\n" 02849 "2axis (supports two joysticks),\n" 02850 "4axis (supports one joystick, first joystick used),\n" 02851 "4axis_2 (supports one joystick, second joystick used),\n" 02852 "fcs (Thrustmaster), ch (CH Flightstick).\n" 02853 "none disables joystick emulation.\n" 02854 "auto chooses emulation depending on real joystick(s).\n" 02855 "(Remember to reset dosbox's mapperfile if you saved it earlier)"); 02856 02857 Pbool = secprop->Add_bool("timed",Property::Changeable::WhenIdle,true); 02858 Pbool->Set_help("enable timed intervals for axis. Experiment with this option, if your joystick drifts (away)."); 02859 02860 Pbool = secprop->Add_bool("autofire",Property::Changeable::WhenIdle,false); 02861 Pbool->Set_help("continuously fires as long as you keep the button pressed."); 02862 02863 Pbool = secprop->Add_bool("swap34",Property::Changeable::WhenIdle,false); 02864 Pbool->Set_help("swap the 3rd and the 4th axis. can be useful for certain joysticks."); 02865 02866 Pbool = secprop->Add_bool("buttonwrap",Property::Changeable::WhenIdle,false); 02867 Pbool->Set_help("enable button wrapping at the number of emulated buttons."); 02868 02869 /*improved joystick 02870 * each axis has its own deadzone and response 02871 * each axis index can be remapped, e.g. fix poor driver mappings 02872 */ 02873 02874 /* logical axes settings*/ 02875 std::vector<int> sticks = { 2, 1 }; 02876 for (auto i = 0u; i < sticks.size(); i++) 02877 { 02878 const auto count = sticks[i]; 02879 for (auto j = 0; j < count; j++) 02880 { 02881 const auto joy = std::to_string(i + 1); 02882 const auto stick = std::to_string(j + 1); 02883 const auto name = "joy" + joy + "deadzone" + stick; 02884 const auto help = "deadzone for joystick " + joy + " thumbstick " + stick + "."; 02885 Pdouble = secprop->Add_double(name, Property::Changeable::WhenIdle, 0.25); 02886 Pdouble->SetMinMax(0.0, 1.0); 02887 Pdouble->Set_help(help); 02888 } 02889 } 02890 for (auto i = 0u; i < sticks.size(); i++) 02891 { 02892 const auto count = sticks[i]; 02893 for (auto j = 0; j < count; j++) 02894 { 02895 const auto joy = std::to_string(i + 1); 02896 const auto stick = std::to_string(j + 1); 02897 const auto name = "joy" + joy + "response" + stick; 02898 const auto help = "response for joystick " + joy + " thumbstick " + stick + "."; 02899 Pdouble = secprop->Add_double(name, Property::Changeable::WhenIdle, 1.0); 02900 Pdouble->SetMinMax(-5.0, 5.0); 02901 Pdouble->Set_help(help); 02902 } 02903 } 02904 02905 const auto joysticks = 2; 02906 const auto axes = 8; 02907 for (auto i = 0; i < joysticks; i++) 02908 { 02909 for (auto j = 0; j < axes; j++) 02910 { 02911 const auto joy = std::to_string(i + 1); 02912 const auto axis = std::to_string(j); 02913 const auto propname = "joy" + joy + "axis" + axis; 02914 Pint = secprop->Add_int(propname, Property::Changeable::WhenIdle, j); 02915 Pint->SetMinMax(0, axes - 1); 02916 const auto help = "axis for joystick " + joy + " axis " + axis + "."; 02917 Pint->Set_help(help); 02918 } 02919 } 02920 /*physical axes settings*/ 02921 secprop = control->AddSection_prop("mapper", &Null_Init, true); 02922 02923 const auto directions = 2; 02924 for (auto i = 0; i < joysticks; i++) 02925 { 02926 for (auto j = 0; j < axes; j++) 02927 { 02928 for (auto k = 0; k < directions; k++) 02929 { 02930 const auto joy = std::to_string(i + 1); 02931 const auto axis = std::to_string(j); 02932 const auto dir = k == 0 ? "-" : "+"; 02933 const auto name = "joy" + joy + "deadzone" + axis + dir; 02934 Pdouble = secprop->Add_double(name, Property::Changeable::WhenIdle, 0.6); 02935 Pdouble->SetMinMax(0.0, 1.0); 02936 const auto help = "deadzone for joystick " + joy + " axis " + axis + dir; 02937 Pdouble->Set_help(help); 02938 } 02939 } 02940 } 02941 02942 02943 secprop=control->AddSection_prop("serial",&Null_Init,true); 02944 02945 Pmulti_remain = secprop->Add_multiremain("serial1",Property::Changeable::WhenIdle," "); 02946 Pstring = Pmulti_remain->GetSection()->Add_string("type",Property::Changeable::WhenIdle,"dummy"); 02947 Pmulti_remain->SetValue("dummy",/*init*/true); 02948 Pstring->Set_values(serials); 02949 Pmulti_remain->GetSection()->Add_string("parameters",Property::Changeable::WhenIdle,""); 02950 Pmulti_remain->Set_help( 02951 "set type of device connected to com port.\n" 02952 "Can be disabled, dummy, modem, nullmodem, directserial.\n" 02953 "Additional parameters must be in the same line in the form of\n" 02954 "parameter:value. Parameter for all types is irq (optional).\n" 02955 "for directserial: realport (required), rxdelay (optional).\n" 02956 " (realport:COM1 realport:ttyS0).\n" 02957 "for modem: listenport (optional).\n" 02958 "for nullmodem: server, rxdelay, txdelay, telnet, usedtr,\n" 02959 " transparent, port, inhsocket, nonlocal (all optional).\n" 02960 " connections are limited to localhost unless you specify nonlocal:1\n" 02961 "Example: serial1=modem listenport:5000"); 02962 02963 Pmulti_remain = secprop->Add_multiremain("serial2",Property::Changeable::WhenIdle," "); 02964 Pstring = Pmulti_remain->GetSection()->Add_string("type",Property::Changeable::WhenIdle,"dummy"); 02965 Pmulti_remain->SetValue("dummy",/*init*/true); 02966 Pstring->Set_values(serials); 02967 Pmulti_remain->GetSection()->Add_string("parameters",Property::Changeable::WhenIdle,""); 02968 Pmulti_remain->Set_help("see serial1"); 02969 02970 Pmulti_remain = secprop->Add_multiremain("serial3",Property::Changeable::WhenIdle," "); 02971 Pstring = Pmulti_remain->GetSection()->Add_string("type",Property::Changeable::WhenIdle,"disabled"); 02972 Pmulti_remain->SetValue("disabled",/*init*/true); 02973 Pstring->Set_values(serials); 02974 Pmulti_remain->GetSection()->Add_string("parameters",Property::Changeable::WhenIdle,""); 02975 Pmulti_remain->Set_help("see serial1"); 02976 02977 Pmulti_remain = secprop->Add_multiremain("serial4",Property::Changeable::WhenIdle," "); 02978 Pstring = Pmulti_remain->GetSection()->Add_string("type",Property::Changeable::WhenIdle,"disabled"); 02979 Pmulti_remain->SetValue("disabled",/*init*/true); 02980 Pstring->Set_values(serials); 02981 Pmulti_remain->GetSection()->Add_string("parameters",Property::Changeable::WhenIdle,""); 02982 Pmulti_remain->Set_help("see serial1"); 02983 02984 Pstring = secprop->Add_path("phonebookfile", Property::Changeable::OnlyAtStart, "phonebook-" VERSION ".txt"); 02985 Pstring->Set_help("File used to map fake phone numbers to addresses."); 02986 02987 // printer redirection parameters 02988 secprop = control->AddSection_prop("printer", &Null_Init); 02989 Pbool = secprop->Add_bool("printer", Property::Changeable::WhenIdle, true); 02990 Pbool->Set_help("Enable printer emulation."); 02991 //secprop->Add_string("fontpath","%%windir%%\\fonts"); 02992 Pint = secprop->Add_int("dpi", Property::Changeable::WhenIdle, 360); 02993 Pint->Set_help("Resolution of printer (default 360)."); 02994 Pint = secprop->Add_int("width", Property::Changeable::WhenIdle, 85); 02995 Pint->Set_help("Width of paper in 1/10 inch (default 85 = 8.5'')."); 02996 Pint = secprop->Add_int("height", Property::Changeable::WhenIdle, 110); 02997 Pint->Set_help("Height of paper in 1/10 inch (default 110 = 11.0'')."); 02998 #ifdef C_LIBPNG 02999 Pstring = secprop->Add_string("printoutput", Property::Changeable::WhenIdle, "png"); 03000 #else 03001 Pstring = secprop->Add_string("printoutput", Property::Changeable::WhenIdle, "ps"); 03002 #endif 03003 Pstring->Set_help("Output method for finished pages: \n" 03004 #ifdef C_LIBPNG 03005 " png : Creates PNG images (default)\n" 03006 #endif 03007 " ps : Creates PostScript\n" 03008 " bmp : Creates BMP images (very huge files, not recommended)\n" 03009 #if defined (WIN32) 03010 " printer : Send to an actual printer (Print dialog will appear)" 03011 #endif 03012 ); 03013 03014 Pbool = secprop->Add_bool("multipage", Property::Changeable::WhenIdle, false); 03015 Pbool->Set_help("Adds all pages to one PostScript file or printer job until CTRL-F2 is pressed."); 03016 03017 Pstring = secprop->Add_string("docpath", Property::Changeable::WhenIdle, "."); 03018 Pstring->Set_help("The path where the output files are stored."); 03019 03020 Pint = secprop->Add_int("timeout", Property::Changeable::WhenIdle, 0); 03021 Pint->Set_help("(in milliseconds) if nonzero: the time the page will be ejected automatically after when no more data arrives at the printer."); 03022 03023 // parallel ports 03024 secprop=control->AddSection_prop("parallel",&Null_Init,true); 03025 Pstring = secprop->Add_string("parallel1",Property::Changeable::WhenIdle,"disabled"); 03026 Pstring->Set_help( 03027 "parallel1-3 -- set type of device connected to lpt port.\n" 03028 "Can be:\n" 03029 " reallpt (direct parallel port passthrough),\n" 03030 " file (records data to a file or passes it to a device),\n" 03031 " printer (virtual dot-matrix printer, see [printer] section)\n" 03032 " disney (attach Disney Sound Source emulation to this port)\n" 03033 "Additional parameters must be in the same line in the form of\n" 03034 "parameter:value.\n" 03035 " for reallpt:\n" 03036 " Windows:\n" 03037 " realbase (the base address of your real parallel port).\n" 03038 " Default: 378\n" 03039 " ecpbase (base address of the ECP registers, optional).\n" 03040 " Linux: realport (the parallel port device i.e. /dev/parport0).\n" 03041 " for file: \n" 03042 " dev:<devname> (i.e. dev:lpt1) to forward data to a device,\n" 03043 " or append:<file> appends data to the specified file.\n" 03044 " Without the above parameters data is written to files in the capture dir.\n" 03045 " Additional parameters: timeout:<milliseconds> = how long to wait before\n" 03046 " closing the file on inactivity (default:500), addFF to add a formfeed when\n" 03047 " closing, addLF to add a linefeed if the app doesn't, cp:<codepage number>\n" 03048 " to perform codepage translation, i.e. cp:437\n" 03049 " for printer:\n" 03050 " printer still has it's own configuration section above." 03051 ); 03052 Pstring = secprop->Add_string("parallel2",Property::Changeable::WhenIdle,"disabled"); 03053 Pstring->Set_help("see parallel1"); 03054 Pstring = secprop->Add_string("parallel3",Property::Changeable::WhenIdle,"disabled"); 03055 Pstring->Set_help("see parallel1"); 03056 03057 Pbool = secprop->Add_bool("dongle",Property::Changeable::WhenIdle,false); 03058 Pbool->Set_help("Enable dongle"); 03059 03060 /* All the DOS Related stuff, which will eventually start up in the shell */ 03061 secprop=control->AddSection_prop("dos",&Null_Init,false);//done 03062 Pbool = secprop->Add_bool("xms",Property::Changeable::WhenIdle,true); 03063 Pbool->Set_help("Enable XMS support."); 03064 03065 Pint = secprop->Add_int("xms handles",Property::Changeable::WhenIdle,0); 03066 Pint->Set_help("Number of XMS handles available for the DOS environment, or 0 to use a reasonable default"); 03067 03068 Pbool = secprop->Add_bool("shell configuration as commands",Property::Changeable::WhenIdle,false); 03069 Pbool->Set_help("Allow entering dosbox-x.conf configuration parameters as shell commands to get and set settings.\n" 03070 "This is disabled by default to avoid conflicts between commands and executables.\n" 03071 "It is recommended to get and set dosbox-x.conf settings using the CONFIG command instead.\n" 03072 "Compatibility with DOSBox SVN can be improved by enabling this option."); 03073 03074 Pbool = secprop->Add_bool("hma",Property::Changeable::WhenIdle,true); 03075 Pbool->Set_help("Report through XMS that HMA exists (not necessarily available)"); 03076 03077 Pbool = secprop->Add_bool("hma allow reservation",Property::Changeable::WhenIdle,true); 03078 Pbool->Set_help("Allow TSR and application (anything other than the DOS kernel) to request control of the HMA.\n" 03079 "They will not be able to request control however if the DOS kernel is configured to occupy the HMA (DOS=HIGH)"); 03080 03081 Pint = secprop->Add_int("hard drive data rate limit",Property::Changeable::WhenIdle,-1); 03082 Pint->Set_help("Slow down (limit) hard disk throughput. This setting controls the limit in bytes/second.\n" 03083 "Set to 0 to disable the limit, or -1 to use a reasonable default."); 03084 03085 Pstring = secprop->Add_string("drive z is remote",Property::Changeable::WhenIdle,"auto"); 03086 Pstring->Set_values(truefalseautoopt); 03087 Pstring->Set_help("If set, DOS will report drive Z as remote. If not set, DOS will report drive Z as local.\n" 03088 "If auto (default), DOS will report drive Z as remote or local depending on the program.\n" 03089 "Set this option to true to prevent SCANDISK.EXE from attempting scan and repair drive Z:\n" 03090 "which is impossible since Z: is a virtual drive not backed by a disk filesystem."); 03091 03092 Pint = secprop->Add_int("hma minimum allocation",Property::Changeable::WhenIdle,0); 03093 Pint->Set_help("Minimum allocation size for HMA in bytes (equivalent to /HMAMIN= parameter)."); 03094 03095 Pbool = secprop->Add_bool("ansi.sys",Property::Changeable::WhenIdle,true); 03096 Pbool->Set_help("If set (by default), ANSI.SYS emulation is on. If clear, ANSI.SYS is not emulated and will not appear to be installed.\n" 03097 "NOTE: This option has no effect in PC-98 mode where MS-DOS systems integrate ANSI.SYS into the DOS kernel."); 03098 03099 Pbool = secprop->Add_bool("log console",Property::Changeable::WhenIdle,false); 03100 Pbool->Set_help("If set, log DOS CON output to the log file."); 03101 03102 Pint = secprop->Add_int("dos sda size",Property::Changeable::WhenIdle,0); 03103 Pint->Set_help("SDA (swappable data area) size, in bytes. Set to 0 to use a reasonable default."); 03104 03105 Pint = secprop->Add_int("hma free space",Property::Changeable::WhenIdle,34*1024); /* default 34KB (TODO: How much does MS-DOS 5.0 usually occupy?) */ 03106 Pint->Set_help("Controls the amount of free space available in HMA. This setting is not meaningful unless the\n" 03107 "DOS kernel occupies HMA and the emulated DOS version is at least 5.0."); 03108 03109 Pstring = secprop->Add_string("cpm compatibility mode",Property::Changeable::WhenIdle,"auto"); 03110 Pstring->Set_values(cpm_compat_modes); 03111 Pstring->Set_help( 03112 "This controls how the DOS kernel sets up the CP/M compatibility code in the PSP segment.\n" 03113 "Several options are provided to emulate one of several undocumented behaviors related to the CP/M entry point.\n" 03114 "If set to auto, DOSBox-X will pick the best option to allow it to work properly.\n" 03115 "Unless set to 'off', this option will require the DOS kernel to occupy the first 256 bytes of the HMA memory area\n" 03116 "to prevent crashes when the A20 gate is switched on.\n" 03117 " auto Pick the best option\n" 03118 " off Turn off the CP/M entry point (program will abort if called)\n" 03119 " msdos2 MS-DOS 2.x behavior, offset field also doubles as data segment size\n" 03120 " msdos5 MS-DOS 5.x behavior, entry point becomes one of two fixed addresses\n" 03121 " direct Non-standard behavior, encode the CALL FAR directly to the entry point rather than indirectly"); 03122 03123 Pbool = secprop->Add_bool("share",Property::Changeable::WhenIdle,true); 03124 Pbool->Set_help("Report SHARE.EXE as resident. Does not actually emulate SHARE functions."); 03125 03126 Phex = secprop->Add_hex("minimum dos initial private segment", Property::Changeable::WhenIdle,0); 03127 Phex->Set_help("In non-mainline mapping mode, where DOS structures are allocated from base memory, this sets the\n" 03128 "minimum segment value. Recommended value is 0x70. You may reduce the value down to 0x50 if freeing\n" 03129 "up more memory is important. Set to 0 for default."); 03130 03131 Phex = secprop->Add_hex("minimum mcb segment", Property::Changeable::WhenIdle,0); 03132 Phex->Set_help("Minimum segment value to begin memory allocation from, in hexadecimal. Set to 0 for default.\n" 03133 "You can increase available DOS memory by reducing this value down to as low as 0x51, however\n" 03134 "setting it to low can cause some DOS programs to crash or run erratically, and some DOS games\n" 03135 "and demos to cause intermittent static noises when using Sound Blaster output. DOS programs\n" 03136 "compressed with Microsoft EXEPACK will not run if the minimum MCB segment is below 64KB."); 03137 03138 Phex = secprop->Add_hex("minimum mcb free", Property::Changeable::WhenIdle,0); 03139 Phex->Set_help("Minimum free segment value to leave free. At startup, the DOS kernel will allocate memory\n" 03140 "up to this point. This can be used to deal with EXEPACK issues or DOS programs that cannot\n" 03141 "be loaded too low in memory. This differs from 'minimum mcb segment' in that this affects\n" 03142 "the lowest free block instead of the starting point of the mcb chain."); 03143 03144 // TODO: Enable by default WHEN the 'SD' signature becomes valid, and a valid device list within 03145 // is emulated properly. 03146 Pbool = secprop->Add_bool("enable dummy device mcb",Property::Changeable::OnlyAtStart,false); 03147 Pbool->Set_help("If set (default), allocate a fake device MCB at the base of conventional memory.\n" 03148 "Clearing this option can reclaim a small amount of conventional memory at the expense of\n" 03149 "some minor DOS compatibility."); 03150 03151 Pint = secprop->Add_int("maximum environment block size on exec", Property::Changeable::WhenIdle,-1); 03152 Pint->SetMinMax(-1,65535); 03153 Pint->Set_help("Maximum environment block size to copy for child processes. Set to -1 for default."); 03154 03155 Pint = secprop->Add_int("additional environment block size on exec", Property::Changeable::WhenIdle,-1); 03156 Pint->SetMinMax(-1,65535); 03157 Pint->Set_help("When executing a program, compute the size of the parent block then add this amount to allow for a few additional variables.\n" 03158 "If the subprocesses will never add/modify the environment block, you can free up a few additional bytes by setting this to 0.\n" 03159 "Set to -1 for default setting."); 03160 03161 // DEPRECATED, REMOVE 03162 Pbool = secprop->Add_bool("enable a20 on windows init",Property::Changeable::OnlyAtStart,false); 03163 Pbool->Set_help("If set, DOSBox-X will enable the A20 gate when Windows 3.1/9x broadcasts the INIT message\n" 03164 "at startup. Windows 3.1 appears to make assumptions at some key points on startup about\n" 03165 "A20 that don't quite hold up and cause Windows 3.1 to crash when you set A20 emulation\n" 03166 "to a20=mask as opposed to a20=fast. This option is enabled by default."); 03167 03168 Pbool = secprop->Add_bool("zero memory on xms memory allocation",Property::Changeable::OnlyAtStart,false); 03169 Pbool->Set_help("If set, memory returned by XMS allocation call is zeroed first. This is NOT what\n" 03170 "DOS actually does, but if set, can help certain DOS games and demos cope with problems\n" 03171 "related to uninitialized variables in extended memory. When enabled this option may\n" 03172 "incur a slight to moderate performance penalty."); 03173 03174 Pstring = secprop->Add_string("dosv",Property::Changeable::WhenIdle,"off"); 03175 Pstring->Set_values(dosv_settings); 03176 Pstring->Set_help("Enable DOS/V emulation and specify which version to emulate. This option is intended for\n" 03177 "use with games or software originating from Asia that use the double byte character set\n" 03178 "encodings and the DOS/V extensions to display Japanese, Chinese, or Korean text.\n" 03179 "Note that enabling DOS/V replaces 80x25 text mode (INT 10h mode 3) with a EGA/VGA graphics\n" 03180 "mode that emulates text mode to display the characters and may be incompatible with non-Asian\n" 03181 "software that assumes direct access to the text mode via segment 0xB800.\n" 03182 "WARNING: This option is very experimental at this time."); 03183 03184 Pstring = secprop->Add_string("ems",Property::Changeable::WhenIdle,"true"); 03185 Pstring->Set_values(ems_settings); 03186 Pstring->Set_help("Enable EMS support. The default (=true) provides the best\n" 03187 "compatibility but certain applications may run better with\n" 03188 "other choices, or require EMS support to be disabled (=false)\n" 03189 "to work at all."); 03190 03191 Pbool = secprop->Add_bool("vcpi",Property::Changeable::OnlyAtStart,true); 03192 Pbool->Set_help("If set and expanded memory is enabled, also emulate VCPI."); 03193 03194 Pbool = secprop->Add_bool("unmask timer on disk io",Property::Changeable::OnlyAtStart,false); 03195 Pbool->Set_help("If set, INT 21h emulation will unmask IRQ 0 (timer interrupt) when the application opens/closes/reads/writes files."); 03196 03197 Pbool = secprop->Add_bool("zero int 67h if no ems",Property::Changeable::OnlyAtStart,true); 03198 Pbool->Set_help("If ems=false, leave interrupt vector 67h zeroed out (default true).\n" 03199 "This is a workaround for games or demos that try to detect EMS by whether or not INT 67h is 0000:0000 rather than a proper test.\n" 03200 "This option also affects whether INT 67h is zeroed when booting a guest OS"); 03201 03202 Pbool = secprop->Add_bool("zero unused int 68h",Property::Changeable::OnlyAtStart,false); 03203 Pbool->Set_help("Leave INT 68h zero at startup.\n" 03204 "Set this to true for certain games that use INT 68h in unusual ways that require a zero value.\n" 03205 "Note that the vector is left at zero anyway when machine=cga.\n" 03206 "This is needed to properly run 1988 game 'PopCorn'."); 03207 03208 /* FIXME: The vm86 monitor in src/ints/ems.cpp is not very stable! Option is default OFF until stabilized! */ 03209 Pbool = secprop->Add_bool("emm386 startup active",Property::Changeable::OnlyAtStart,false); 03210 Pbool->Set_help("If set and expanded memory is set to emulate emm386, start the DOS machine with EMM386.EXE active\n" 03211 "(running the 16-bit DOS environment from within Virtual 8086 mode). If you will be running anything\n" 03212 "that involves a DOS extender you will also need to enable the VCPI interface as well."); 03213 03214 Pbool = secprop->Add_bool("zero memory on ems memory allocation",Property::Changeable::OnlyAtStart,false); 03215 Pbool->Set_help("If set, memory returned by EMS allocation call is zeroed first. This is NOT what\n" 03216 "DOS actually does, but if set, can help certain DOS games and demos cope with problems\n" 03217 "related to uninitialized variables in expanded memory. When enabled this option may\n" 03218 "incur a slight to moderate performance penalty."); 03219 03220 Pint = secprop->Add_int("ems system handle memory size",Property::Changeable::WhenIdle,384); 03221 Pint->Set_help("Amount of memory associated with system handle, in KB"); 03222 03223 Pbool = secprop->Add_bool("ems system handle on even megabyte",Property::Changeable::WhenIdle,false); 03224 Pbool->Set_help("If set, try to allocate the EMM system handle on an even megabyte.\n" 03225 "If the DOS game or demo fiddles with the A20 gate while using EMM386.EXE emulation in virtual 8086 mode, setting this option may help prevent crashes.\n" 03226 "However, forcing allocation on an even megabyte will also cause some extended memory fragmentation and reduce the\n" 03227 "overall amount of extended memory available to the DOS game depending on whether it expects large contiguous chunks\n" 03228 "of extended memory."); 03229 03230 Pbool = secprop->Add_bool("umb",Property::Changeable::WhenIdle,true); 03231 Pbool->Set_help("Enable UMB support."); 03232 03233 Phex = secprop->Add_hex("umb start",Property::Changeable::OnlyAtStart,0); /* <- (0=auto) 0xD000 is mainline DOSBox compatible behavior */ 03234 Phex->Set_help("UMB region starting segment"); 03235 03236 Phex = secprop->Add_hex("umb end",Property::Changeable::OnlyAtStart,0); /* <- (0=auto) 0xEFFF is mainline DOSBox compatible (where base=0xD000 and size=0x2000) */ 03237 Phex->Set_help("UMB region last segment"); 03238 03239 Pbool = secprop->Add_bool("kernel allocation in umb",Property::Changeable::OnlyAtStart,false); 03240 Pbool->Set_help("If set, dynamic kernel allocation=1, and private area in umb=1, all kernel structures will be allocated from the private area in UMB.\n" 03241 "If you intend to run Windows 3.1 in DOSBox-X, you must set this option to false else Windows 3.1 will not start."); 03242 03243 Pbool = secprop->Add_bool("keep umb on boot",Property::Changeable::OnlyAtStart,false); 03244 Pbool->Set_help("If emulating UMBs, keep the UMB around after boot (Mainline DOSBox behavior). If clear, UMB is unmapped when you boot an operating system."); 03245 03246 Pbool = secprop->Add_bool("keep private area on boot",Property::Changeable::OnlyAtStart,false); 03247 Pbool->Set_help("If set, keep the DOSBox-X private area around after boot (Mainline DOSBox behavior). If clear, unmap and discard the private area when you boot an operating system."); 03248 03249 Pbool = secprop->Add_bool("private area in umb",Property::Changeable::WhenIdle,true); 03250 Pbool->Set_help("If set, keep private DOS segment in upper memory block, usually segment 0xC800 (Mainline DOSBox behavior)\n" 03251 "If clear, place private DOS segment at the base of system memory (just below the MCB)"); 03252 03253 Pstring = secprop->Add_string("ver",Property::Changeable::WhenIdle,""); 03254 Pstring->Set_help("Set DOS version. Specify as major.minor format. A single number is treated as the major version (compatible with LFN support). Common settings are:\n" 03255 "auto (or unset) Pick a DOS kernel version automatically\n" 03256 "3.3 MS-DOS 3.3 emulation (not tested!)\n" 03257 "5.0 MS-DOS 5.0 emulation (recommended for DOS gaming)\n" 03258 "6.22 MS-DOS 6.22 emulation\n" 03259 "7.0 MS-DOS 7.0 (or Windows 95 pure DOS mode) emulation\n" 03260 "7.1 MS-DOS 7.1 (or Windows 98 pure DOS mode) emulation\n" 03261 "Long filename (LFN) support will be enabled with a reported DOS version of 7.0 or higher with \"lfn=auto\" (default).\n" 03262 "Similarly, FAT32 disk images will be supported with a reported DOS version of 7.1 or higher.\n"); 03263 03264 Pstring = secprop->Add_string("lfn",Property::Changeable::WhenIdle,"auto"); 03265 Pstring->Set_values(lfn_settings); 03266 Pstring->Set_help("Enable long filename support. If set to auto (default), it is enabled if the reported DOS version is at least 7.0.\n" 03267 "If set to autostart, the builtin VER command won't activate/disactivate LFN support according to the reported DOS version."); 03268 03269 Pbool = secprop->Add_bool("automount",Property::Changeable::WhenIdle,true); 03270 Pbool->Set_help("Enable automatic drive mounting in Windows."); 03271 03272 Pbool = secprop->Add_bool("automountall",Property::Changeable::OnlyAtStart,false); 03273 Pbool->Set_help("Automatically mount all available Windows drives at start."); 03274 03275 Pbool = secprop->Add_bool("int33",Property::Changeable::WhenIdle,true); 03276 Pbool->Set_help("Enable INT 33H (mouse) support."); 03277 03278 Pbool = secprop->Add_bool("int33 hide host cursor if interrupt subroutine",Property::Changeable::WhenIdle,true); 03279 Pbool->Set_help("If set, the cursor on the host will be hidden if the DOS application provides it's own\n" 03280 "interrupt subroutine for the mouse driver to call, which is usually an indication that\n" 03281 "the DOS game wishes to draw the cursor with it's own support routines (DeluxePaint II)."); 03282 03283 Pbool = secprop->Add_bool("int33 hide host cursor when polling",Property::Changeable::WhenIdle,false); 03284 Pbool->Set_help("If set, the cursor on the host will be hidden even if the DOS application has also\n" 03285 "hidden the cursor in the guest, as long as the DOS application is polling position\n" 03286 "and button status. This can be useful for DOS programs that draw the cursor on their\n" 03287 "own instead of using the mouse driver, including most games and DeluxePaint II."); 03288 03289 Pbool = secprop->Add_bool("int33 disable cell granularity",Property::Changeable::WhenIdle,false); 03290 Pbool->Set_help("If set, the mouse pointer position is reported at full precision (as if 640x200 coordinates) in all modes.\n" 03291 "If not set, the mouse pointer position is rounded to the top-left corner of a character cell in text modes.\n" 03292 "This option is OFF by default."); 03293 03294 Pbool = secprop->Add_bool("int 13 extensions",Property::Changeable::WhenIdle,true); 03295 Pbool->Set_help("Enable INT 13h extensions (functions 0x40-0x48). You will need this enabled if the virtual hard drive image is 8.4GB or larger."); 03296 03297 Pbool = secprop->Add_bool("biosps2",Property::Changeable::OnlyAtStart,true); 03298 Pbool->Set_help("Emulate BIOS INT 15h PS/2 mouse services\n" 03299 "Note that some OS's like Microsoft Windows neither use INT 33h nor\n" 03300 "probe the AUX port directly and depend on this BIOS interface exclusively\n" 03301 "for PS/2 mouse support. In other cases there is no harm in leaving this enabled"); 03302 03303 /* bugfix for Yodel "mayday" demo */ 03304 /* TODO: Set this option to default to "true" if it turns out most BIOSes unmask the IRQ during INT 15h AH=86 WAIT */ 03305 Pbool = secprop->Add_bool("int15 wait force unmask irq",Property::Changeable::OnlyAtStart,true); 03306 Pbool->Set_help("Some demos or games mistakingly use INT 15h AH=0x86 (WAIT) while leaving the IRQs needed for it masked.\n" 03307 "If this option is set (by default), the necessary IRQs will be unmasked when INT 15 AH=0x86 is used so that the game or demo does not hang."); 03308 03309 Pbool = secprop->Add_bool("int15 mouse callback does not preserve registers",Property::Changeable::OnlyAtStart,false); 03310 Pbool->Set_help("Set to true if the guest OS or DOS program assigns an INT 15h mouse callback,\n" 03311 "but does not properly preserve CPU registers. Diagnostic function only (default off)."); 03312 03313 Pstring = secprop->Add_string("keyboardlayout",Property::Changeable::WhenIdle, "auto"); 03314 Pstring->Set_help("Language code of the keyboard layout (or none)."); 03315 03316 Pbool = secprop->Add_bool("dbcs",Property::Changeable::OnlyAtStart,true); 03317 Pbool->Set_help("Enable DBCS table.\n" 03318 "CAUTION: Some software will crash without the DBCS table, including the Open Watcom installer.\n"); 03319 03320 Pbool = secprop->Add_bool("filenamechar",Property::Changeable::OnlyAtStart,true); 03321 Pbool->Set_help("Enable filename char table"); 03322 03323 Pbool = secprop->Add_bool("collating and uppercase",Property::Changeable::OnlyAtStart,true); 03324 Pbool->Set_help("Enable collating and uppercase table"); 03325 03326 // DEPRECATED, REMOVE 03327 Pbool = secprop->Add_bool("con device use int 16h to detect keyboard input",Property::Changeable::OnlyAtStart,true); 03328 Pbool->Set_help("If set, use INT 16h to detect keyboard input (MS-DOS 6.22 behavior). If clear, detect keyboard input by\n" 03329 "peeking into the BIOS keyboard buffer (Mainline DOSBox behavior). You will need to set this\n" 03330 "option for programs that hook INT 16h to handle keyboard input ahead of the DOS console.\n" 03331 "Microsoft Scandisk needs this option to respond to keyboard input correctly."); 03332 03333 Pbool = secprop->Add_bool("zero memory on int 21h memory allocation",Property::Changeable::OnlyAtStart,false); 03334 Pbool->Set_help("If set, memory returned by the INT 21h allocation call is zeroed first. This is NOT what\n" 03335 "DOS actually does, but if set, can help certain DOS games and demos cope with problems\n" 03336 "related to uninitialized variables in the data or stack segment. If you intend to run a\n" 03337 "game or demo known to have this problem (Second Unreal, for example), set to true, else\n" 03338 "set to false. When enabled this option may incur a slight to moderate performance penalty."); 03339 03340 Pstring = secprop->Add_string("dos clipboard device enable",Property::Changeable::WhenIdle, "false"); 03341 Pstring->Set_help("If enabled, a DOS device will be added for bidirectional communications with the Windows clipboard.\n" 03342 "Setting to \"read\" will only allow read access, and setting to \"write\" will only allow write access.\n" 03343 "Setting to \"full\" or \"true\" enables both; setting to \"dummy\" or \"false\" disables the access or device.\n" 03344 "The default device name is CLIP$, but can be changed with the \"dos clipboard device name\" setting below."); 03345 03346 Pstring = secprop->Add_string("dos clipboard device name",Property::Changeable::WhenIdle, "CLIP$"); 03347 Pstring->Set_help("Set DOS device name (up to 8 characters) for bidirectional communications with the Windows clipboard.\n" 03348 "If unset or invalid, the default name CLIP$ will be used (e.g. \"TYPE CLIP$\" shows the clipboard contents).\n" 03349 "It has no effect if \"dos clipboard device enable\" is false, and it is deactivated if the secure mode is enabled."); 03350 03351 secprop=control->AddSection_prop("ipx",&Null_Init,true); 03352 Pbool = secprop->Add_bool("ipx",Property::Changeable::WhenIdle, false); 03353 Pbool->Set_help("Enable ipx over UDP/IP emulation."); 03354 03355 secprop=control->AddSection_prop("ne2000",&Null_Init,true); 03356 MSG_Add("NE2000_CONFIGFILE_HELP", 03357 "macaddr -- The physical address the emulator will use on your network.\n" 03358 " If you have multiple DOSBoxes running on your network,\n" 03359 " this has to be changed. Modify the last three number blocks.\n" 03360 " I.e. AC:DE:48:88:99:AB.\n" 03361 "realnic -- Specifies which of your network interfaces is used.\n" 03362 " Write \'list\' here to see the list of devices in the\n" 03363 " Status Window. Then make your choice and put either the\n" 03364 " interface number (2 or something) or a part of your adapters\n" 03365 " name, e.g. VIA here.\n" 03366 03367 ); 03368 03369 Pbool = secprop->Add_bool("ne2000", Property::Changeable::WhenIdle, false); 03370 Pbool->Set_help("Enable Ethernet passthrough. Requires [Win]Pcap."); 03371 03372 Phex = secprop->Add_hex("nicbase", Property::Changeable::WhenIdle, 0x300); 03373 Phex->Set_help("The base address of the NE2000 board."); 03374 03375 Pint = secprop->Add_int("nicirq", Property::Changeable::WhenIdle, 3); 03376 Pint->Set_help("The interrupt it uses. Note serial2 uses IRQ3 as default."); 03377 03378 Pstring = secprop->Add_string("macaddr", Property::Changeable::WhenIdle,"AC:DE:48:88:99:AA"); 03379 Pstring->Set_help("The physical address the emulator will use on your network.\n" 03380 "If you have multiple DOSBoxes running on your network,\n" 03381 "this has to be changed for each. AC:DE:48 is an address range reserved for\n" 03382 "private use, so modify the last three number blocks.\n" 03383 "I.e. AC:DE:48:88:99:AB."); 03384 03385 /* TODO: Change default to "nat" and then begin implementing support for emulating 03386 * an ethernet connection with DOSBox-X as a NAT/firewall between the guest 03387 * and the OS. Sort of like "NAT" mode in VirtualBox. When that works, we 03388 * can then compile NE2000 support with and without libpcap/winpcap support. */ 03389 Pstring = secprop->Add_string("realnic", Property::Changeable::WhenIdle,"list"); 03390 Pstring->Set_help("Specifies which of your network interfaces is used.\n" 03391 "Write \'list\' here to see the list of devices in the\n" 03392 "Status Window. Then make your choice and put either the\n" 03393 "interface number (2 or something) or a part of your adapters\n" 03394 "name, e.g. VIA here."); 03395 03396 /* floppy controller emulation options and setup */ 03397 secprop=control->AddSection_prop("fdc, primary",&Null_Init,false); 03398 03399 /* Primary FDC on by default, secondary is not. Most PCs have only one floppy controller. */ 03400 Pbool = secprop->Add_bool("enable",Property::Changeable::OnlyAtStart,false); 03401 Pbool->Set_help("Enable floppy controller interface"); 03402 03403 Pbool = secprop->Add_bool("pnp",Property::Changeable::OnlyAtStart,true); 03404 Pbool->Set_help("List floppy controller in ISA PnP BIOS enumeration"); 03405 03406 Pint = secprop->Add_int("irq",Property::Changeable::WhenIdle,0/*use FDC default*/); 03407 Pint->Set_help("IRQ used by floppy controller. Set to 0 for default.\n" 03408 "WARNING: Setting the IRQ to non-standard values will not work unless the guest OS is using the ISA PnP BIOS to detect the floppy controller.\n" 03409 " Setting the IRQ to one already occupied by another device or IDE controller will trigger \"resource conflict\" errors in Windows 95.\n" 03410 " Normally, floppy controllers use IRQ 6."); 03411 03412 Phex = secprop->Add_hex("io",Property::Changeable::WhenIdle,0/*use FDC default*/); 03413 Phex->Set_help("Base I/O port for floppy controller. Set to 0 for default.\n" 03414 "WARNING: Setting the I/O port to non-standard values will not work unless the guest OS is using the ISA PnP BIOS to detect the IDE controller.\n" 03415 " Standard I/O ports are 3F0 and 370."); 03416 03417 Pint = secprop->Add_int("dma",Property::Changeable::WhenIdle,-1/*use FDC default*/); 03418 Pint->Set_help("DMA channel for floppy controller. Set to -1 for default.\n" 03419 "WARNING: Setting the DMA channel to non-standard values will not work unless the guest OS is using the ISA PnP BIOS to detect the IDE controller.\n" 03420 " Standard DMA channel is 2."); 03421 03422 Pbool = secprop->Add_bool("int13fakev86io",Property::Changeable::WhenIdle,false); 03423 Pbool->Set_help( 03424 "If set, certain INT 13h commands will cause floppy emulation to issue fake CPU I/O\n" 03425 "traps (GPF) in virtual 8086 mode and a fake IRQ signal. You must enable this\n" 03426 "option if you want 32-bit floppy access in Windows 95 to work with DOSBox-X."); 03427 03428 Pbool = secprop->Add_bool("instant mode",Property::Changeable::WhenIdle,false); 03429 Pbool->Set_help( 03430 "If set, all floppy operations are 'instantaneous', they are carried\n" 03431 "out without any delay. Real hardware of course has motor, command\n" 03432 "and data I/O delays and so this option is off by default for realistic\n" 03433 "emulation."); 03434 03435 Pbool = secprop->Add_bool("auto-attach to int 13h",Property::Changeable::WhenIdle,true); 03436 Pbool->Set_help( 03437 "If set, DOSBox-X will automatically attach a disk image as being\n" 03438 "inserted into a floppy drive attached to the controller when imgmount is used\n" 03439 "to mount a disk image to drive 0/1 or A/B. If not set, you must specify\n" 03440 "the -fdc option to imgmount to attach drive A/B to the floppy controller\n" 03441 "manually. You must use the -fdc option regardless if loading floppies into\n" 03442 "drives attached to any other FDC than the primary controller"); 03443 03444 /* FIXME: From http://wiki.osdev.org/Floppy_Disk_Controller#Configure 03445 * 03446 * "The three modes are PC-AT mode, PS/2 mode, and Model 30 mode. The most likely mode ... is model 30 mode. 03447 * You may find some pre-1996 Pentium machines using PS/2 mode. You can ignore PC-AT mode." 03448 * 03449 * What? What the fuck are you talking about? 03450 * 03451 * "AT mode" seems to imply the presense of port 3F7. PS/2 mode seems to imply the presense of 3F0-3F1 and 3F7. 03452 * A Toshiba laptop (Satellite Pro 465CDX) has port 3F7 but not 3F0-3F1. By other documentation I've found, that 03453 * means this laptop (which came out late 1997) is running in AT mode! There's plenty of hardware running in both 03454 * PS/2 and AT mode, even some very old stuff in my pile of junk dating back to 1990! 03455 * 03456 * Somehow I think this information is as correct as their ATAPI programming docs on how to read CD-ROM 03457 * sectors: it's a start but it's mostly wrong. Hopefully DOSLIB will shed light on what the real differences 03458 * are and what is most common. --J.C. */ 03459 Pstring = secprop->Add_string("mode",Property::Changeable::WhenIdle,"ps2"); 03460 Pstring->Set_help( 03461 "Floppy controller mode. What the controller acts like.\n" 03462 " ps2 PS/2 mode (most common)\n" 03463 " ps2_model30 PS/2 model 30\n" 03464 " at AT mode\n" 03465 " xt PC/XT mode"); 03466 03467 /* FIXME: Not yet implemented. Future plans */ 03468 Pstring = secprop->Add_string("chip",Property::Changeable::WhenIdle,"82077aa"); 03469 Pstring->Set_help( 03470 "Floppy controller chipset\n" 03471 " 82077aa Intel 82077AA chipset\n" 03472 " 82072 Intel 82072 chipset\n" 03473 " nec_uPD765 NEC uPD765 chipset\n" 03474 " none No chipset (For PC/XT mode)"); 03475 03476 /* IDE emulation options and setup */ 03477 for (size_t i=0;i < MAX_IDE_CONTROLLERS;i++) { 03478 secprop=control->AddSection_prop(ide_names[i],&Null_Init,false);//done 03479 03480 /* Primary and Secondary are on by default, Teritary and Quaternary are off by default. 03481 * Throughout the life of the IDE interface it was far more common for a PC to have just 03482 * a Primary and Secondary interface */ 03483 Pbool = secprop->Add_bool("enable",Property::Changeable::OnlyAtStart,(i < 2) ? true : false); 03484 if (i == 0) Pbool->Set_help("Enable IDE interface"); 03485 03486 Pbool = secprop->Add_bool("pnp",Property::Changeable::OnlyAtStart,true); 03487 if (i == 0) Pbool->Set_help("List IDE device in ISA PnP BIOS enumeration"); 03488 03489 Pint = secprop->Add_int("irq",Property::Changeable::WhenIdle,0/*use IDE default*/); 03490 if (i == 0) Pint->Set_help("IRQ used by IDE controller. Set to 0 for default.\n" 03491 "WARNING: Setting the IRQ to non-standard values will not work unless the guest OS is using the ISA PnP BIOS to detect the IDE controller.\n" 03492 " Setting the IRQ to one already occupied by another device or IDE controller will trigger \"resource conflict\" errors in Windows 95.\n" 03493 " Using IRQ 9, 12, 13, or IRQ 2-7 may cause problems with MS-DOS CD-ROM drivers."); 03494 03495 Phex = secprop->Add_hex("io",Property::Changeable::WhenIdle,0/*use IDE default*/); 03496 if (i == 0) Phex->Set_help("Base I/O port for IDE controller. Set to 0 for default.\n" 03497 "WARNING: Setting the I/O port to non-standard values will not work unless the guest OS is using the ISA PnP BIOS to detect the IDE controller.\n" 03498 " Using any port other than 1F0, 170, 1E8 or 168 can prevent MS-DOS CD-ROM drivers from detecting the IDE controller."); 03499 03500 Phex = secprop->Add_hex("altio",Property::Changeable::WhenIdle,0/*use IDE default*/); 03501 if (i == 0) Phex->Set_help("Alternate I/O port for IDE controller (alt status, etc). Set to 0 for default.\n" 03502 "WARNING: Setting the I/O port to non-standard values will not work unless the guest OS is using the ISA PnP BIOS to detect the IDE controller.\n" 03503 " For best compatability set this value to io+0x206, for example, io=1F0 altio=3F6.\n" 03504 " The primary IDE controller will not claim port 3F7 if the primary floppy controller is enabled due to I/O port overlap in the 3F0-3F7 range."); 03505 03506 Pbool = secprop->Add_bool("int13fakeio",Property::Changeable::WhenIdle,false); 03507 if (i == 0) Pbool->Set_help( 03508 "If set, force IDE state change on certain INT 13h commands.\n" 03509 "IDE registers will be changed as if BIOS had carried out the action.\n" 03510 "If you are running Windows 3.11 or Windows 3.11 Windows for Workgroups\n" 03511 "you must enable this option (and use -reservecyl 1) if you want 32-bit\n" 03512 "disk access to work correctly in DOSBox-X."); 03513 03514 Pbool = secprop->Add_bool("int13fakev86io",Property::Changeable::WhenIdle,false); 03515 if (i == 0) Pbool->Set_help( 03516 "If set, and int13fakeio is set, certain INT 13h commands will cause IDE emulation to\n" 03517 "issue fake CPU I/O traps (GPF) in virtual 8086 mode and a fake IRQ signal. You must\n" 03518 "enable this option if you want 32-bit disk access in Windows 95 to work with DOSBox-X."); 03519 03520 Pbool = secprop->Add_bool("enable pio32",Property::Changeable::WhenIdle,false); 03521 if (i == 0) Pbool->Set_help( 03522 "If set, 32-bit I/O reads and writes are handled directly (much like PCI IDE implementations)\n" 03523 "If clear, 32-bit I/O will be handled as if two 16-bit I/O (much like ISA IDE implementations)"); 03524 03525 Pbool = secprop->Add_bool("ignore pio32",Property::Changeable::WhenIdle,false); 03526 if (i == 0) Pbool->Set_help( 03527 "If 32-bit I/O is enabled, attempts to read/write 32-bit I/O will be ignored entirely.\n" 03528 "In this way, you can have DOSBox-X emulate one of the strange quirks of 1995-1997 era\n" 03529 "laptop hardware"); 03530 03531 Pint = secprop->Add_int("cd-rom spinup time",Property::Changeable::WhenIdle,0/*use IDE or CD-ROM default*/); 03532 if (i == 0) Pint->Set_help("Emulated CD-ROM time in ms to spin up if CD is stationary.\n" 03533 "Set to 0 to use controller or CD-ROM drive-specific default."); 03534 03535 Pint = secprop->Add_int("cd-rom spindown timeout",Property::Changeable::WhenIdle,0/*use IDE or CD-ROM default*/); 03536 if (i == 0) Pint->Set_help("Emulated CD-ROM time in ms that drive will spin down automatically when not in use\n" 03537 "Set to 0 to use controller or CD-ROM drive-specific default."); 03538 03539 Pint = secprop->Add_int("cd-rom insertion delay",Property::Changeable::WhenIdle,0/*use IDE or CD-ROM default*/); 03540 if (i == 0) Pint->Set_help("Emulated CD-ROM time in ms that drive will report \"medium not present\"\n" 03541 "to emulate the time it takes for someone to take out a CD and insert a new one when\n" 03542 "DOSBox-X is instructed to swap or change CDs.\n" 03543 "When running Windows 95 or higher a delay of 4000ms is recommended to ensure that\n" 03544 "auto-insert notification triggers properly.\n" 03545 "Set to 0 to use controller or CD-ROM drive-specific default."); 03546 } 03547 03548 /* CONFIG.SYS options (stub) */ 03549 secprop=control->AddSection_prop("config",&Null_Init,false); 03550 03551 Pstring = secprop->Add_string("rem",Property::Changeable::OnlyAtStart,"This section is DOS's CONFIG.SYS file, not all CONFIG.SYS options supported"); 03552 Pstring->Set_help("Records comments (remarks)."); 03553 Pstring = secprop->Add_string("break",Property::Changeable::OnlyAtStart,"off"); 03554 Pstring->Set_help("Sets or clears extended CTRL+C checking."); 03555 Pstring->Set_values(ps1opt); 03556 Pstring = secprop->Add_string("numlock",Property::Changeable::OnlyAtStart,""); 03557 Pstring->Set_help("Sets the initial state of the NumLock key."); 03558 Pstring->Set_values(numopt); 03559 Pstring = secprop->Add_string("dos",Property::Changeable::OnlyAtStart,"high, umb"); 03560 Pstring->Set_help("Reports whether DOS occupies HMA and allocates UMB memory (if available)."); 03561 Pint = secprop->Add_int("fcbs",Property::Changeable::OnlyAtStart,100); 03562 Pint->Set_help("Number of FCB handles available to DOS programs (1-255)."); 03563 Pint = secprop->Add_int("files",Property::Changeable::OnlyAtStart,127); 03564 Pint->Set_help("Number of file handles available to DOS programs (8-255)."); 03565 Pint = secprop->Add_int("country",Property::Changeable::OnlyAtStart,1); 03566 Pint->Set_help("Sets the country code for country-specific date/time formats."); 03567 Pstring = secprop->Add_string("lastdrive",Property::Changeable::OnlyAtStart,"a"); 03568 Pstring->Set_help("The maximum drive letter that can be accessed by programs."); 03569 Pstring->Set_values(driveletters); 03570 03571 //TODO ? 03572 control->AddSection_line("autoexec",&Null_Init); 03573 MSG_Add("AUTOEXEC_CONFIGFILE_HELP", 03574 "Lines in this section will be run at startup.\n" 03575 "You can put your MOUNT lines here.\n" 03576 ); 03577 MSG_Add("CONFIGFILE_INTRO", 03578 "# This is the configuration file for DOSBox-X %s. (Please use the latest version of DOSBox-X)\n" 03579 "# Lines starting with a # are comment lines and are ignored by DOSBox-X.\n" 03580 "# They are used to (briefly) document the effect of each option.\n" 03581 "# To write out ALL options, use command 'config -all' with -wc or -writeconf options.\n"); 03582 MSG_Add("CONFIG_SUGGESTED_VALUES", "Possible values"); 03583 } 03584 03585 int utf8_encode(char **ptr, const char *fence, uint32_t code) { 03586 int uchar_size=1; 03587 char *p = *ptr; 03588 03589 if (!p) return UTF8ERR_NO_ROOM; 03590 if (code >= (uint32_t)0x80000000UL) return UTF8ERR_INVALID; 03591 if (p >= fence) return UTF8ERR_NO_ROOM; 03592 03593 if (code >= 0x4000000) uchar_size = 6; 03594 else if (code >= 0x200000) uchar_size = 5; 03595 else if (code >= 0x10000) uchar_size = 4; 03596 else if (code >= 0x800) uchar_size = 3; 03597 else if (code >= 0x80) uchar_size = 2; 03598 03599 if ((p+uchar_size) > fence) return UTF8ERR_NO_ROOM; 03600 03601 switch (uchar_size) { 03602 case 1: *p++ = (char)code; 03603 break; 03604 case 2: *p++ = (char)(0xC0 | (code >> 6)); 03605 *p++ = (char)(0x80 | (code & 0x3F)); 03606 break; 03607 case 3: *p++ = (char)(0xE0 | (code >> 12)); 03608 *p++ = (char)(0x80 | ((code >> 6) & 0x3F)); 03609 *p++ = (char)(0x80 | (code & 0x3F)); 03610 break; 03611 case 4: *p++ = (char)(0xF0 | (code >> 18)); 03612 *p++ = (char)(0x80 | ((code >> 12) & 0x3F)); 03613 *p++ = (char)(0x80 | ((code >> 6) & 0x3F)); 03614 *p++ = (char)(0x80 | (code & 0x3F)); 03615 break; 03616 case 5: *p++ = (char)(0xF8 | (code >> 24)); 03617 *p++ = (char)(0x80 | ((code >> 18) & 0x3F)); 03618 *p++ = (char)(0x80 | ((code >> 12) & 0x3F)); 03619 *p++ = (char)(0x80 | ((code >> 6) & 0x3F)); 03620 *p++ = (char)(0x80 | (code & 0x3F)); 03621 break; 03622 case 6: *p++ = (char)(0xFC | (code >> 30)); 03623 *p++ = (char)(0x80 | ((code >> 24) & 0x3F)); 03624 *p++ = (char)(0x80 | ((code >> 18) & 0x3F)); 03625 *p++ = (char)(0x80 | ((code >> 12) & 0x3F)); 03626 *p++ = (char)(0x80 | ((code >> 6) & 0x3F)); 03627 *p++ = (char)(0x80 | (code & 0x3F)); 03628 break; 03629 } 03630 03631 *ptr = p; 03632 return 0; 03633 } 03634 03635 int utf8_decode(const char **ptr,const char *fence) { 03636 const char *p = *ptr; 03637 int uchar_size=1; 03638 int ret = 0,c; 03639 03640 if (!p) return UTF8ERR_NO_ROOM; 03641 if (p >= fence) return UTF8ERR_NO_ROOM; 03642 03643 ret = (unsigned char)(*p); 03644 if (ret >= 0xFE) { p++; return UTF8ERR_INVALID; } 03645 else if (ret >= 0xFC) uchar_size=6; 03646 else if (ret >= 0xF8) uchar_size=5; 03647 else if (ret >= 0xF0) uchar_size=4; 03648 else if (ret >= 0xE0) uchar_size=3; 03649 else if (ret >= 0xC0) uchar_size=2; 03650 else if (ret >= 0x80) { p++; return UTF8ERR_INVALID; } 03651 03652 if ((p+uchar_size) > fence) 03653 return UTF8ERR_NO_ROOM; 03654 03655 switch (uchar_size) { 03656 case 1: p++; 03657 break; 03658 case 2: ret = (ret&0x1F)<<6; p++; 03659 c = (unsigned char)(*p++); if ((c&0xC0) != 0x80) return UTF8ERR_INVALID; 03660 ret |= c&0x3F; 03661 break; 03662 case 3: ret = (ret&0xF)<<12; p++; 03663 c = (unsigned char)(*p++); if ((c&0xC0) != 0x80) return UTF8ERR_INVALID; 03664 ret |= (c&0x3F)<<6; 03665 c = (unsigned char)(*p++); if ((c&0xC0) != 0x80) return UTF8ERR_INVALID; 03666 ret |= c&0x3F; 03667 break; 03668 case 4: ret = (ret&0x7)<<18; p++; 03669 c = (unsigned char)(*p++); if ((c&0xC0) != 0x80) return UTF8ERR_INVALID; 03670 ret |= (c&0x3F)<<12; 03671 c = (unsigned char)(*p++); if ((c&0xC0) != 0x80) return UTF8ERR_INVALID; 03672 ret |= (c&0x3F)<<6; 03673 c = (unsigned char)(*p++); if ((c&0xC0) != 0x80) return UTF8ERR_INVALID; 03674 ret |= c&0x3F; 03675 break; 03676 case 5: ret = (ret&0x3)<<24; p++; 03677 c = (unsigned char)(*p++); if ((c&0xC0) != 0x80) return UTF8ERR_INVALID; 03678 ret |= (c&0x3F)<<18; 03679 c = (unsigned char)(*p++); if ((c&0xC0) != 0x80) return UTF8ERR_INVALID; 03680 ret |= (c&0x3F)<<12; 03681 c = (unsigned char)(*p++); if ((c&0xC0) != 0x80) return UTF8ERR_INVALID; 03682 ret |= (c&0x3F)<<6; 03683 c = (unsigned char)(*p++); if ((c&0xC0) != 0x80) return UTF8ERR_INVALID; 03684 ret |= c&0x3F; 03685 break; 03686 case 6: ret = (ret&0x1)<<30; p++; 03687 c = (unsigned char)(*p++); if ((c&0xC0) != 0x80) return UTF8ERR_INVALID; 03688 ret |= (c&0x3F)<<24; 03689 c = (unsigned char)(*p++); if ((c&0xC0) != 0x80) return UTF8ERR_INVALID; 03690 ret |= (c&0x3F)<<18; 03691 c = (unsigned char)(*p++); if ((c&0xC0) != 0x80) return UTF8ERR_INVALID; 03692 ret |= (c&0x3F)<<12; 03693 c = (unsigned char)(*p++); if ((c&0xC0) != 0x80) return UTF8ERR_INVALID; 03694 ret |= (c&0x3F)<<6; 03695 c = (unsigned char)(*p++); if ((c&0xC0) != 0x80) return UTF8ERR_INVALID; 03696 ret |= c&0x3F; 03697 break; 03698 } 03699 03700 *ptr = p; 03701 return ret; 03702 } 03703 03704 int utf16le_encode(char **ptr, const char *fence, uint32_t code) { 03705 char *p = *ptr; 03706 03707 if (!p) return UTF8ERR_NO_ROOM; 03708 if (code > 0x10FFFF) return UTF8ERR_INVALID; 03709 if (code > 0xFFFF) { /* UTF-16 surrogate pair */ 03710 uint32_t lo = (code - 0x10000) & 0x3FF; 03711 uint32_t hi = ((code - 0x10000) >> 10) & 0x3FF; 03712 if ((p+2+2) > fence) return UTF8ERR_NO_ROOM; 03713 *p++ = (char)( (hi+0xD800) & 0xFF); 03714 *p++ = (char)(((hi+0xD800) >> 8) & 0xFF); 03715 *p++ = (char)( (lo+0xDC00) & 0xFF); 03716 *p++ = (char)(((lo+0xDC00) >> 8) & 0xFF); 03717 } 03718 else if ((code&0xF800) == 0xD800) { /* do not allow accidental surrogate pairs (0xD800-0xDFFF) */ 03719 return UTF8ERR_INVALID; 03720 } 03721 else { 03722 if ((p+2) > fence) return UTF8ERR_NO_ROOM; 03723 *p++ = (char)( code & 0xFF); 03724 *p++ = (char)((code >> 8) & 0xFF); 03725 } 03726 03727 *ptr = p; 03728 return 0; 03729 } 03730 03731 int utf16le_decode(const char **ptr,const char *fence) { 03732 const char *p = *ptr; 03733 unsigned int ret,b=2; 03734 03735 if (!p) return UTF8ERR_NO_ROOM; 03736 if ((p+1) >= fence) return UTF8ERR_NO_ROOM; 03737 03738 ret = (unsigned char)p[0]; 03739 ret |= ((unsigned int)((unsigned char)p[1])) << 8; 03740 if (ret >= 0xD800U && ret <= 0xDBFFU) 03741 b=4; 03742 else if (ret >= 0xDC00U && ret <= 0xDFFFU) 03743 { p++; return UTF8ERR_INVALID; } 03744 03745 if ((p+b) > fence) 03746 return UTF8ERR_NO_ROOM; 03747 03748 p += 2; 03749 if (ret >= 0xD800U && ret <= 0xDBFFU) { 03750 /* decode surrogate pair */ 03751 unsigned int hi = ret & 0x3FFU; 03752 unsigned int lo = (unsigned char)p[0]; 03753 lo |= ((unsigned int)((unsigned char)p[1])) << 8; 03754 p += 2; 03755 if (lo < 0xDC00U || lo > 0xDFFFU) return UTF8ERR_INVALID; 03756 lo &= 0x3FFU; 03757 ret = ((hi << 10U) | lo) + 0x10000U; 03758 } 03759 03760 *ptr = p; 03761 return (int)ret; 03762 } 03763 03764 extern void POD_Save_Sdlmain( std::ostream& stream ); 03765 extern void POD_Load_Sdlmain( std::istream& stream ); 03766 03767 // save state support 03768 03769 namespace 03770 { 03771 class SerializeDosbox : public SerializeGlobalPOD 03772 { 03773 public: 03774 SerializeDosbox() : SerializeGlobalPOD("Dosbox-x") 03775 {} 03776 03777 private: 03778 virtual void getBytes(std::ostream& stream) 03779 { 03780 03781 //****************************************** 03782 //****************************************** 03783 //****************************************** 03784 03785 SerializeGlobalPOD::getBytes(stream); 03786 03787 //****************************************** 03788 //****************************************** 03789 //****************************************** 03790 03791 POD_Save_Sdlmain(stream); 03792 } 03793 03794 virtual void setBytes(std::istream& stream) 03795 { 03796 03797 //****************************************** 03798 //****************************************** 03799 //****************************************** 03800 03801 SerializeGlobalPOD::setBytes(stream); 03802 03803 //****************************************** 03804 //****************************************** 03805 //****************************************** 03806 03807 POD_Load_Sdlmain(stream); 03808 03809 //******************************************* 03810 //******************************************* 03811 //******************************************* 03812 03813 // Reset any auto cycle guessing for this frame 03814 ticksRemain=5; 03815 ticksLast = GetTicks(); 03816 ticksAdded = 0; 03817 ticksDone = 0; 03818 ticksScheduled = 0; 03819 } 03820 } dummy; 03821 } 03822 03823 #include "zlib.h" 03824 #ifdef WIN32 03825 #include "direct.h" 03826 #endif 03827 #include "cross.h" 03828 #include "logging.h" 03829 #if defined (__APPLE__) 03830 #else 03831 #include <malloc.h> 03832 #endif 03833 #include <cstring> 03834 #include <fstream> 03835 03836 #include <stdio.h> 03837 #include <sys/stat.h> 03838 #include <sys/types.h> 03839 #include <string> 03840 #include <stdlib.h> 03841 #include "SDL.h" 03842 03843 #ifndef WIN32 03844 char* itoa(int value, char* str, int radix) { 03850 // check that the radix if valid 03851 if (radix < 2 || radix > 36) { *str = '\0'; return str; } 03852 03853 char* ptr = str, *ptr1 = str, tmp_char; 03854 int tmp_value; 03855 03856 do { 03857 tmp_value = value; 03858 value /= radix; 03859 *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * radix)]; 03860 } while ( value ); 03861 03862 // Apply negative sign 03863 if (tmp_value < 0) *ptr++ = '-'; 03864 *ptr-- = '\0'; 03865 while(ptr1 < ptr) { 03866 tmp_char = *ptr; 03867 *ptr--= *ptr1; 03868 *ptr1++ = tmp_char; 03869 } 03870 return str; 03871 } 03872 #endif 03873 03874 SaveState& SaveState::instance() { 03875 static SaveState singleton; 03876 return singleton; 03877 } 03878 03879 void SaveState::registerComponent(const std::string& uniqueName, Component& comp) { 03880 components.insert(std::make_pair(uniqueName, CompData(comp))); 03881 } 03882 03883 namespace Util { 03884 std::string compress(const std::string& input) { //throw (SaveState::Error) 03885 if (input.empty()) 03886 return input; 03887 03888 const uLong bufferSize = ::compressBound(input.size()); 03889 03890 std::string output; 03891 output.resize(bufferSize); 03892 03893 uLongf actualSize = bufferSize; 03894 if (::compress2(reinterpret_cast<Bytef*>(&output[0]), &actualSize, 03895 reinterpret_cast<const Bytef*>(input.c_str()), input.size(), Z_BEST_SPEED) != Z_OK) 03896 throw SaveState::Error("Compression failed!"); 03897 03898 output.resize(actualSize); 03899 03900 //save size of uncompressed data 03901 const size_t uncompressedSize = input.size(); //save size of uncompressed data 03902 output.resize(output.size() + sizeof(uncompressedSize)); //won't trigger a reallocation 03903 ::memcpy(&output[0] + output.size() - sizeof(uncompressedSize), &uncompressedSize, sizeof(uncompressedSize)); 03904 03905 return std::string(&output[0], output.size()); //strip reserved space 03906 } 03907 03908 std::string decompress(const std::string& input) { //throw (SaveState::Error) 03909 if (input.empty()) 03910 return input; 03911 03912 //retrieve size of uncompressed data 03913 size_t uncompressedSize = 0; 03914 ::memcpy(&uncompressedSize, &input[0] + input.size() - sizeof(uncompressedSize), sizeof(uncompressedSize)); 03915 03916 std::string output; 03917 output.resize(uncompressedSize); 03918 03919 uLongf actualSize = uncompressedSize; 03920 if (::uncompress(reinterpret_cast<Bytef*>(&output[0]), &actualSize, 03921 reinterpret_cast<const Bytef*>(input.c_str()), input.size() - sizeof(uncompressedSize)) != Z_OK) 03922 throw SaveState::Error("Decompression failed!"); 03923 03924 output.resize(actualSize); //should be superfluous! 03925 03926 return output; 03927 } 03928 } 03929 03930 inline void SaveState::RawBytes::set(const std::string& stream) { 03931 bytes = stream; 03932 isCompressed = false; 03933 dataExists = true; 03934 } 03935 03936 inline std::string SaveState::RawBytes::get() const { //throw (Error){ 03937 if (isCompressed) 03938 (Util::decompress(bytes)).swap(bytes); 03939 isCompressed = false; 03940 return bytes; 03941 } 03942 03943 inline void SaveState::RawBytes::compress() const { //throw (Error) 03944 if (!isCompressed) 03945 (Util::compress(bytes)).swap(bytes); 03946 isCompressed = true; 03947 } 03948 03949 inline bool SaveState::RawBytes::dataAvailable() const { 03950 return dataExists; 03951 } 03952 03953 #define CASESENSITIVITY (0) 03954 #define MAXFILENAME (256) 03955 03956 int mymkdir(const char* dirname) 03957 { 03958 int ret=0; 03959 #ifdef _WIN32 03960 ret = _mkdir(dirname); 03961 #elif unix 03962 ret = mkdir (dirname,0775); 03963 #elif __APPLE__ 03964 ret = mkdir (dirname,0775); 03965 #endif 03966 return ret; 03967 } 03968 03969 int makedir(const char *newdir) 03970 { 03971 char *buffer ; 03972 char *p; 03973 int len = (int)strlen(newdir); 03974 03975 if (len <= 0) 03976 return 0; 03977 03978 buffer = (char*)malloc(len+1); 03979 if (buffer==NULL) 03980 { 03981 printf("Error allocating memory\n"); 03982 return UNZ_INTERNALERROR; 03983 } 03984 strcpy(buffer,newdir); 03985 03986 if (buffer[len-1] == '/') { 03987 buffer[len-1] = '\0'; 03988 } 03989 if (mymkdir(buffer) == 0) 03990 { 03991 free(buffer); 03992 return 1; 03993 } 03994 03995 p = buffer+1; 03996 while (1) 03997 { 03998 char hold; 03999 04000 while(*p && *p != '\\' && *p != '/') 04001 p++; 04002 hold = *p; 04003 *p = 0; 04004 if ((mymkdir(buffer) == -1) && (errno == ENOENT)) 04005 { 04006 printf("couldn't create directory %s\n",buffer); 04007 free(buffer); 04008 return 0; 04009 } 04010 if (hold == 0) 04011 break; 04012 *p++ = hold; 04013 } 04014 free(buffer); 04015 return 1; 04016 } 04017 04018 void change_file_date(const char *filename, uLong dosdate, tm_unz tmu_date) 04019 { 04020 (void)dosdate; 04021 #ifdef _WIN32 04022 HANDLE hFile; 04023 FILETIME ftm,ftLocal,ftCreate,ftLastAcc,ftLastWrite; 04024 04025 hFile = CreateFileA(filename,GENERIC_READ | GENERIC_WRITE, 04026 0,NULL,OPEN_EXISTING,0,NULL); 04027 GetFileTime(hFile,&ftCreate,&ftLastAcc,&ftLastWrite); 04028 DosDateTimeToFileTime((WORD)(dosdate>>16),(WORD)dosdate,&ftLocal); 04029 LocalFileTimeToFileTime(&ftLocal,&ftm); 04030 SetFileTime(hFile,&ftm,&ftLastAcc,&ftm); 04031 CloseHandle(hFile); 04032 #else 04033 #if defined(unix) || defined(__APPLE__) 04034 struct utimbuf ut; 04035 struct tm newdate; 04036 newdate.tm_sec = tmu_date.tm_sec; 04037 newdate.tm_min=tmu_date.tm_min; 04038 newdate.tm_hour=tmu_date.tm_hour; 04039 newdate.tm_mday=tmu_date.tm_mday; 04040 newdate.tm_mon=tmu_date.tm_mon; 04041 if (tmu_date.tm_year > 1900) 04042 newdate.tm_year=tmu_date.tm_year - 1900; 04043 else 04044 newdate.tm_year=tmu_date.tm_year ; 04045 newdate.tm_isdst=-1; 04046 04047 ut.actime=ut.modtime=mktime(&newdate); 04048 utime(filename,&ut); 04049 #endif 04050 #endif 04051 } 04052 04053 int do_extract_currentfile(unzFile uf, const int* popt_extract_without_path, int* popt_overwrite, const char* password) 04054 { 04055 char filename_inzip[256]; 04056 char* filename_withoutpath; 04057 char* p; 04058 int err=UNZ_OK; 04059 FILE *fout=NULL; 04060 void* buf; 04061 uInt size_buf; 04062 04063 unz_file_info64 file_info; 04064 uLong ratio=0; 04065 err = unzGetCurrentFileInfo64(uf,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0); 04066 04067 (void)ratio; 04068 04069 if (err!=UNZ_OK) 04070 { 04071 printf("error %d with zipfile in unzGetCurrentFileInfo\n",err); 04072 return err; 04073 } 04074 04075 size_buf = 8192; 04076 buf = (void*)malloc(size_buf); 04077 if (buf==NULL) 04078 { 04079 printf("Error allocating memory\n"); 04080 return UNZ_INTERNALERROR; 04081 } 04082 04083 p = filename_withoutpath = filename_inzip; 04084 while ((*p) != '\0') 04085 { 04086 if (((*p)=='/') || ((*p)=='\\')) 04087 filename_withoutpath = p+1; 04088 p++; 04089 } 04090 04091 if ((*filename_withoutpath)=='\0') 04092 { 04093 if ((*popt_extract_without_path)==0) 04094 { 04095 printf("creating directory: %s\n",filename_inzip); 04096 mymkdir(filename_inzip); 04097 } 04098 } 04099 else 04100 { 04101 const char* write_filename; 04102 int skip=0; 04103 04104 if ((*popt_extract_without_path)==0) 04105 write_filename = filename_inzip; 04106 else 04107 write_filename = filename_withoutpath; 04108 04109 err = unzOpenCurrentFilePassword(uf,password); 04110 if (err!=UNZ_OK) 04111 { 04112 printf("error %d with zipfile in unzOpenCurrentFilePassword\n",err); 04113 } 04114 04115 if (((*popt_overwrite)==0) && (err==UNZ_OK)) 04116 { 04117 char rep=0; 04118 FILE* ftestexist; 04119 ftestexist = FOPEN_FUNC(write_filename,"rb"); 04120 if (ftestexist!=NULL) 04121 { 04122 fclose(ftestexist); 04123 do 04124 { 04125 char answer[128]; 04126 int ret; 04127 04128 printf("The file %s exists. Overwrite ? [y]es, [n]o, [A]ll: ",write_filename); 04129 ret = scanf("%1s",answer); 04130 if (ret != 1) 04131 { 04132 exit(EXIT_FAILURE); 04133 } 04134 rep = answer[0] ; 04135 if ((rep>='a') && (rep<='z')) 04136 rep -= 0x20; 04137 } 04138 while ((rep!='Y') && (rep!='N') && (rep!='A')); 04139 } 04140 04141 if (rep == 'N') 04142 skip = 1; 04143 04144 if (rep == 'A') 04145 *popt_overwrite=1; 04146 } 04147 04148 if ((skip==0) && (err==UNZ_OK)) 04149 { 04150 fout=FOPEN_FUNC(write_filename,"wb"); 04151 /* some zipfile don't contain directory alone before file */ 04152 if ((fout==NULL) && ((*popt_extract_without_path)==0) && 04153 (filename_withoutpath!=(char*)filename_inzip)) 04154 { 04155 char c=*(filename_withoutpath-1); 04156 *(filename_withoutpath-1)='\0'; 04157 makedir(write_filename); 04158 *(filename_withoutpath-1)=c; 04159 fout=FOPEN_FUNC(write_filename,"wb"); 04160 } 04161 04162 if (fout==NULL) 04163 { 04164 printf("error opening %s\n",write_filename); 04165 } 04166 } 04167 04168 if (fout!=NULL) 04169 { 04170 printf(" extracting: %s\n",write_filename); 04171 04172 do 04173 { 04174 err = unzReadCurrentFile(uf,buf,size_buf); 04175 if (err<0) 04176 { 04177 printf("error %d with zipfile in unzReadCurrentFile\n",err); 04178 break; 04179 } 04180 if (err>0) 04181 if (fwrite(buf,err,1,fout)!=1) 04182 { 04183 printf("error in writing extracted file\n"); 04184 err=UNZ_ERRNO; 04185 break; 04186 } 04187 } 04188 while (err>0); 04189 if (fout) 04190 fclose(fout); 04191 04192 if (err==0) 04193 change_file_date(write_filename,file_info.dosDate, 04194 file_info.tmu_date); 04195 } 04196 04197 if (err==UNZ_OK) 04198 { 04199 err = unzCloseCurrentFile (uf); 04200 if (err!=UNZ_OK) 04201 { 04202 printf("error %d with zipfile in unzCloseCurrentFile\n",err); 04203 } 04204 } 04205 else 04206 unzCloseCurrentFile(uf); /* don't lose the error */ 04207 } 04208 04209 free(buf); 04210 return err; 04211 } 04212 04213 int do_extract(unzFile uf, int opt_extract_without_path, int opt_overwrite, const char* password) 04214 { 04215 uLong i; 04216 unz_global_info64 gi; 04217 int err; 04218 FILE* fout=NULL; 04219 04220 (void)fout; 04221 04222 err = unzGetGlobalInfo64(uf,&gi); 04223 if (err!=UNZ_OK) { 04224 printf("error %d with zipfile in unzGetGlobalInfo \n",err); 04225 return 0; 04226 } 04227 04228 for (i=0;i<gi.number_entry;i++) 04229 { 04230 if (do_extract_currentfile(uf,&opt_extract_without_path, 04231 &opt_overwrite, 04232 password) != UNZ_OK) 04233 break; 04234 04235 if ((i+1)<gi.number_entry) 04236 { 04237 err = unzGoToNextFile(uf); 04238 if (err!=UNZ_OK) 04239 { 04240 printf("error %d with zipfile in unzGoToNextFile\n",err); 04241 break; 04242 } 04243 } 04244 } 04245 04246 return 0; 04247 } 04248 04249 int do_extract_onefile(unzFile uf, const char* filename, int opt_extract_without_path, int opt_overwrite, const char* password) 04250 { 04251 int err = UNZ_OK; 04252 (void)err; 04253 if (unzLocateFile(uf,filename,CASESENSITIVITY)!=UNZ_OK) 04254 { 04255 printf("file %s not found in the zipfile\n",filename); 04256 return 2; 04257 } 04258 04259 if (do_extract_currentfile(uf,&opt_extract_without_path, 04260 &opt_overwrite, 04261 password) == UNZ_OK) 04262 return 0; 04263 else 04264 return 1; 04265 } 04266 04267 int my_miniunz(char ** savefile, const char * savefile2, const char * savedir) { 04268 const char *zipfilename=NULL; 04269 const char *filename_to_extract=NULL; 04270 const char *password=NULL; 04271 char filename_try[MAXFILENAME+16] = ""; 04272 int ret_value=0; 04273 int opt_do_extract=1; 04274 int opt_do_extract_withoutpath=0; 04275 int opt_overwrite=0; 04276 int opt_extractdir=0; 04277 const char *dirname=NULL; 04278 unzFile uf=NULL; 04279 04280 opt_do_extract = opt_do_extract_withoutpath = 1; 04281 opt_overwrite=1; 04282 opt_extractdir=1; 04283 dirname=savedir; 04284 zipfilename = (const char *)savefile; 04285 filename_to_extract = savefile2; 04286 04287 if (zipfilename!=NULL) 04288 { 04289 04290 # ifdef USEWIN32IOAPI 04291 zlib_filefunc64_def ffunc; 04292 # endif 04293 04294 strncpy(filename_try, zipfilename,MAXFILENAME-1); 04295 /* strncpy doesnt append the trailing NULL, of the string is too long. */ 04296 filename_try[ MAXFILENAME ] = '\0'; 04297 04298 # ifdef USEWIN32IOAPI 04299 fill_win32_filefunc64A(&ffunc); 04300 uf = unzOpen2_64(zipfilename,&ffunc); 04301 # else 04302 uf = unzOpen64(zipfilename); 04303 # endif 04304 } 04305 04306 if (uf==NULL) 04307 { 04308 //printf("Cannot open %s\n",zipfilename,zipfilename); 04309 return 1; 04310 } 04311 //printf("%s opened\n",filename_try); 04312 04313 if (opt_do_extract==1) 04314 { 04315 char cCurrentPath[FILENAME_MAX]; 04316 char *ret=getcwd(cCurrentPath, sizeof(cCurrentPath)); 04317 if (opt_extractdir && chdir(dirname)) 04318 { 04319 printf("Error changing into %s, aborting\n", dirname); 04320 exit(-1); 04321 } 04322 04323 if (filename_to_extract == NULL) 04324 ret_value = do_extract(uf, opt_do_extract_withoutpath, opt_overwrite, password); 04325 else 04326 ret_value = do_extract_onefile(uf, filename_to_extract, opt_do_extract_withoutpath, opt_overwrite, password); 04327 if (ret!=NULL) chdir(cCurrentPath); 04328 } 04329 04330 unzClose(uf); 04331 04332 return ret_value; 04333 } 04334 04335 #ifdef _WIN32 04336 uLong filetime(char *f, tm_zip *tmzip, uLong *dt) 04337 { 04338 int ret = 0; 04339 { 04340 FILETIME ftLocal; 04341 HANDLE hFind; 04342 WIN32_FIND_DATAA ff32; 04343 04344 hFind = FindFirstFileA(f,&ff32); 04345 if (hFind != INVALID_HANDLE_VALUE) 04346 { 04347 FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal); 04348 FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0); 04349 FindClose(hFind); 04350 ret = 1; 04351 } 04352 } 04353 return ret; 04354 } 04355 #else 04356 #if defined(unix) || defined(__APPLE__) 04357 uLong filetime(char *f, tm_zip *tmzip, uLong *dt) 04358 { 04359 (void)dt; 04360 int ret=0; 04361 struct stat s; /* results of stat() */ 04362 struct tm* filedate; 04363 time_t tm_t=0; 04364 04365 if (strcmp(f,"-")!=0) 04366 { 04367 char name[MAXFILENAME+1]; 04368 int len = strlen(f); 04369 if (len > MAXFILENAME) 04370 len = MAXFILENAME; 04371 04372 strncpy(name, f,MAXFILENAME-1); 04373 /* strncpy doesnt append the trailing NULL, of the string is too long. */ 04374 name[ MAXFILENAME ] = '\0'; 04375 04376 if (name[len - 1] == '/') 04377 name[len - 1] = '\0'; 04378 /* not all systems allow stat'ing a file with / appended */ 04379 if (stat(name,&s)==0) 04380 { 04381 tm_t = s.st_mtime; 04382 ret = 1; 04383 } 04384 } 04385 filedate = localtime(&tm_t); 04386 04387 tmzip->tm_sec = filedate->tm_sec; 04388 tmzip->tm_min = filedate->tm_min; 04389 tmzip->tm_hour = filedate->tm_hour; 04390 tmzip->tm_mday = filedate->tm_mday; 04391 tmzip->tm_mon = filedate->tm_mon ; 04392 tmzip->tm_year = filedate->tm_year; 04393 04394 return ret; 04395 } 04396 #else 04397 uLong filetime(char *f, tm_zip *tmzip, uLong *dt) 04398 { 04399 return 0; 04400 } 04401 #endif 04402 #endif 04403 04404 #ifdef __APPLE__ 04405 // In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions 04406 #define FOPEN_FUNC(filename, mode) fopen(filename, mode) 04407 #define FTELLO_FUNC(stream) ftello(stream) 04408 #define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin) 04409 #else 04410 #define FOPEN_FUNC(filename, mode) fopen64(filename, mode) 04411 #define FTELLO_FUNC(stream) ftello64(stream) 04412 #define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin) 04413 #endif 04414 04415 int getFileCrc(const char* filenameinzip,void*buf,unsigned long size_buf,unsigned long* result_crc) 04416 { 04417 unsigned long calculate_crc=0; 04418 int err=ZIP_OK; 04419 FILE * fin = FOPEN_FUNC(filenameinzip,"rb"); 04420 04421 unsigned long size_read = 0; 04422 unsigned long total_read = 0; 04423 if (fin==NULL) 04424 err = ZIP_ERRNO; 04425 04426 if (err == ZIP_OK) 04427 do 04428 { 04429 err = ZIP_OK; 04430 size_read = (int)fread(buf,1,size_buf,fin); 04431 if (size_read < size_buf) 04432 if (feof(fin)==0) 04433 { 04434 printf("error in reading %s\n",filenameinzip); 04435 err = ZIP_ERRNO; 04436 } 04437 04438 if (size_read>0) 04439 calculate_crc = crc32(calculate_crc,(const Bytef*)buf,size_read); 04440 total_read += size_read; 04441 04442 } while ((err == ZIP_OK) && (size_read>0)); 04443 04444 if (fin) 04445 fclose(fin); 04446 04447 *result_crc=calculate_crc; 04448 printf("file %s crc %lx\n", filenameinzip, calculate_crc); 04449 return err; 04450 } 04451 04452 int isLargeFile(const char* filename) 04453 { 04454 int largeFile = 0; 04455 ZPOS64_T pos = 0; 04456 FILE* pFile = FOPEN_FUNC(filename, "rb"); 04457 04458 if(pFile != NULL) 04459 { 04460 int n = FSEEKO_FUNC(pFile, 0, SEEK_END); 04461 pos = FTELLO_FUNC(pFile); 04462 (void)n; 04463 04464 printf("File : %s is %lld bytes\n", filename, pos); 04465 04466 if(pos >= 0xffffffff) 04467 largeFile = 1; 04468 04469 fclose(pFile); 04470 } 04471 04472 return largeFile; 04473 } 04474 04475 int my_minizip(char ** savefile, char ** savefile2) { 04476 int opt_overwrite=0; 04477 int opt_compress_level=Z_DEFAULT_COMPRESSION; 04478 int opt_exclude_path=0; 04479 int zipfilenamearg = 0; 04480 (void)zipfilenamearg; 04481 //char filename_try[MAXFILENAME16]; 04482 int err=0; 04483 int size_buf=0; 04484 void* buf=NULL; 04485 const char* password=NULL; 04486 04487 opt_overwrite = 2; 04488 opt_compress_level = 9; 04489 opt_exclude_path = 1; 04490 04491 size_buf = 16384; 04492 buf = (void*)malloc(size_buf); 04493 if (buf==NULL) 04494 { 04495 //printf("Error allocating memory\n"); 04496 return ZIP_INTERNALERROR; 04497 } 04498 04499 { 04500 zipFile zf; 04501 int errclose; 04502 # ifdef USEWIN32IOAPI 04503 zlib_filefunc64_def ffunc; 04504 fill_win32_filefunc64A(&ffunc); 04505 zf = zipOpen2_64(savefile,(opt_overwrite==2) ? 2 : 0,NULL,&ffunc); 04506 # else 04507 zf = zipOpen64(savefile,(opt_overwrite==2) ? 2 : 0); 04508 # endif 04509 04510 if (zf == NULL) 04511 { 04512 //printf("error opening %s\n",savefile); 04513 err= ZIP_ERRNO; 04514 } 04515 else 04516 //printf("creating %s\n",savefile); 04517 04518 { 04519 FILE *fin = NULL; 04520 int size_read; 04521 char* filenameinzip = (char *)savefile2; 04522 const char *savefilenameinzip; 04523 zip_fileinfo zi; 04524 unsigned long crcFile=0; 04525 int zip64 = 0; 04526 04527 zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour = 04528 zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0; 04529 zi.dosDate = 0; 04530 zi.internal_fa = 0; 04531 zi.external_fa = 0; 04532 filetime(filenameinzip,&zi.tmz_date,&zi.dosDate); 04533 04534 if ((password != NULL) && (err==ZIP_OK)) 04535 err = getFileCrc(filenameinzip,buf,size_buf,&crcFile); 04536 04537 zip64 = isLargeFile(filenameinzip); 04538 04539 /* The path name saved, should not include a leading slash. */ 04540 /*if it did, windows/xp and dynazip couldn't read the zip file. */ 04541 savefilenameinzip = filenameinzip; 04542 while( savefilenameinzip[0] == '\\' || savefilenameinzip[0] == '/' ) 04543 { 04544 savefilenameinzip++; 04545 } 04546 04547 /*should the zip file contain any path at all?*/ 04548 if( opt_exclude_path ) 04549 { 04550 const char *tmpptr; 04551 const char *lastslash = 0; 04552 for( tmpptr = savefilenameinzip; *tmpptr; tmpptr++) 04553 { 04554 if( *tmpptr == '\\' || *tmpptr == '/') 04555 { 04556 lastslash = tmpptr; 04557 } 04558 } 04559 if( lastslash != NULL ) 04560 { 04561 savefilenameinzip = lastslash+1; // base filename follows last slash. 04562 } 04563 } 04564 04565 04566 err = zipOpenNewFileInZip3_64(zf,savefilenameinzip,&zi, 04567 NULL,0,NULL,0,NULL /* comment*/, 04568 (opt_compress_level != 0) ? Z_DEFLATED : 0, 04569 opt_compress_level,0, 04570 /* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */ 04571 -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, 04572 password,crcFile, zip64); 04573 04574 if (err != ZIP_OK) { 04575 //printf("error in opening %s in zipfile\n",filenameinzip); 04576 } 04577 else 04578 { 04579 fin = fopen64(filenameinzip,"rb"); 04580 if (fin==NULL) 04581 { 04582 err=ZIP_ERRNO; 04583 //printf("error in opening %s for reading\n",filenameinzip); 04584 } 04585 } 04586 04587 if (err == ZIP_OK) 04588 do 04589 { 04590 err = ZIP_OK; 04591 size_read = (int)fread(buf,1,size_buf,fin); 04592 if (size_read < size_buf) 04593 if (feof(fin)==0) 04594 { 04595 //printf("error in reading %s\n",filenameinzip); 04596 err = ZIP_ERRNO; 04597 } 04598 04599 if (size_read>0) 04600 { 04601 err = zipWriteInFileInZip (zf,buf,size_read); 04602 if (err<0) 04603 { 04604 //printf("error in writing %s in the zipfile\n", 04605 // filenameinzip); 04606 } 04607 04608 } 04609 } while ((err == ZIP_OK) && (size_read>0)); 04610 04611 if (fin) 04612 fclose(fin); 04613 04614 if (err<0) 04615 err=ZIP_ERRNO; 04616 else 04617 { 04618 err = zipCloseFileInZip(zf); 04619 if (err!=ZIP_OK) { 04620 //printf("error in closing %s in the zipfile\n", 04621 // filenameinzip); 04622 } 04623 } 04624 } 04625 errclose = zipClose(zf,NULL); 04626 if (errclose != ZIP_OK) { 04627 //printf("error in closing %s\n",savefile); 04628 } 04629 } 04630 04631 free(buf); 04632 return 0; 04633 } 04634 04635 void SaveState::save(size_t slot) { //throw (Error) 04636 if (slot >= SLOT_COUNT) return; 04637 SDL_PauseAudio(0); 04638 bool save_err=false; 04639 if((MEM_TotalPages()*4096/1024/1024)>1000) { 04640 LOG_MSG("Stopped. 1000 MB is the maximum memory size for saving/loading states."); 04641 #if defined(WIN32) 04642 MessageBox(GetHWND(),"Unsupported memory size.","Error",MB_OK); 04643 #endif 04644 return; 04645 } 04646 bool create_version=false; 04647 bool create_title=false; 04648 bool create_memorysize=false; 04649 extern const char* RunningProgram; 04650 std::string path; 04651 bool Get_Custom_SaveDir(std::string& savedir); 04652 if(Get_Custom_SaveDir(path)) { 04653 path+=CROSS_FILESPLIT; 04654 } else { 04655 extern std::string capturedir; 04656 const size_t last_slash_idx = capturedir.find_last_of("\\/"); 04657 if (std::string::npos != last_slash_idx) { 04658 path = capturedir.substr(0, last_slash_idx); 04659 } else { 04660 path = "."; 04661 } 04662 path+=CROSS_FILESPLIT; 04663 path+="save"; 04664 Cross::CreateDir(path); 04665 path+=CROSS_FILESPLIT; 04666 } 04667 04668 std::string temp, save2; 04669 std::stringstream slotname; 04670 slotname << slot+1; 04671 temp=path; 04672 std::string save=temp+slotname.str()+".sav"; 04673 remove(save.c_str()); 04674 std::ofstream file (save.c_str()); 04675 file << ""; 04676 file.close(); 04677 try { 04678 for (CompEntry::iterator i = components.begin(); i != components.end(); ++i) { 04679 std::ostringstream ss; 04680 i->second.comp.getBytes(ss); 04681 i->second.rawBytes[slot].set(ss.str()); 04682 04683 //LOG_MSG("Component is %s",i->first.c_str()); 04684 04685 if(!create_version) { 04686 std::string tempname = temp+"DOSBox-X_Version"; 04687 std::ofstream emulatorversion (tempname.c_str(), std::ofstream::binary); 04688 emulatorversion << "DOSBox-X " << VERSION << " (" << SDL_STRING << ")" << std::endl << GetPlatform() << std::endl << UPDATED_STR; 04689 create_version=true; 04690 emulatorversion.close(); 04691 } 04692 04693 if(!create_title) { 04694 std::string tempname = temp+"Program_Name"; 04695 std::ofstream programname (tempname.c_str(), std::ofstream::binary); 04696 programname << RunningProgram; 04697 create_title=true; 04698 programname.close(); 04699 } 04700 04701 if(!create_memorysize) { 04702 std::string tempname = temp+"Memory_Size"; 04703 std::ofstream memorysize (tempname.c_str(), std::ofstream::binary); 04704 memorysize << MEM_TotalPages(); 04705 create_memorysize=true; 04706 memorysize.close(); 04707 } 04708 std::string realtemp; 04709 realtemp = temp + i->first; 04710 std::ofstream outfile (realtemp.c_str(), std::ofstream::binary); 04711 outfile << (Util::compress(ss.str())); 04712 //compress all other saved states except position "slot" 04713 //const std::vector<RawBytes>& rb = i->second.rawBytes; 04714 //std::for_each(rb.begin(), rb.begin() + slot, std::mem_fun_ref(&RawBytes::compress)); 04715 //std::for_each(rb.begin() + slot + 1, rb.end(), std::mem_fun_ref(&RawBytes::compress)); 04716 outfile.close(); 04717 ss.clear(); 04718 if(outfile.fail()) { 04719 LOG_MSG("Save failed! - %s", realtemp.c_str()); 04720 save_err=true; 04721 remove(save.c_str()); 04722 goto delete_all; 04723 } 04724 } 04725 } 04726 catch (const std::bad_alloc&) { 04727 LOG_MSG("Save failed! Out of Memory!"); 04728 save_err=true; 04729 remove(save.c_str()); 04730 goto delete_all; 04731 } 04732 04733 for (CompEntry::iterator i = components.begin(); i != components.end(); ++i) { 04734 save2=temp+i->first; 04735 my_minizip((char **)save.c_str(), (char **)save2.c_str()); 04736 } 04737 save2=temp+"DOSBox-X_Version"; 04738 my_minizip((char **)save.c_str(), (char **)save2.c_str()); 04739 save2=temp+"Program_Name"; 04740 my_minizip((char **)save.c_str(), (char **)save2.c_str()); 04741 save2=temp+"Memory_Size"; 04742 my_minizip((char **)save.c_str(), (char **)save2.c_str()); 04743 04744 delete_all: 04745 for (CompEntry::iterator i = components.begin(); i != components.end(); ++i) { 04746 save2=temp+i->first; 04747 remove(save2.c_str()); 04748 } 04749 save2=temp+"DOSBox-X_Version"; 04750 remove(save2.c_str()); 04751 save2=temp+"Program_Name"; 04752 remove(save2.c_str()); 04753 save2=temp+"Memory_Size"; 04754 remove(save2.c_str()); 04755 if (save_err) { 04756 #if defined(WIN32) 04757 MessageBox(GetHWND(),"Failed to save the current state.","Error",MB_OK); 04758 #endif 04759 } else 04760 LOG_MSG("Saved. (Slot %d)",(int)slot+1); 04761 } 04762 04763 void SaveState::load(size_t slot) const { //throw (Error) 04764 // if (isEmpty(slot)) return; 04765 bool load_err=false; 04766 if((MEM_TotalPages()*4096/1024/1024)>1000) { 04767 LOG_MSG("Stopped. 1000 MB is the maximum memory size for saving/loading states."); 04768 #if defined(WIN32) 04769 MessageBox(GetHWND(),"Unsupported memory size.","Error",MB_OK); 04770 #endif 04771 return; 04772 } 04773 SDL_PauseAudio(0); 04774 extern const char* RunningProgram; 04775 bool read_version=false; 04776 bool read_title=false; 04777 bool read_memorysize=false; 04778 std::string path; 04779 bool Get_Custom_SaveDir(std::string& savedir); 04780 if(Get_Custom_SaveDir(path)) { 04781 path+=CROSS_FILESPLIT; 04782 } else { 04783 extern std::string capturedir; 04784 const size_t last_slash_idx = capturedir.find_last_of("\\/"); 04785 if (std::string::npos != last_slash_idx) { 04786 path = capturedir.substr(0, last_slash_idx); 04787 } else { 04788 path = "."; 04789 } 04790 path += CROSS_FILESPLIT; 04791 path +="save"; 04792 path += CROSS_FILESPLIT; 04793 } 04794 std::string temp; 04795 temp = path; 04796 std::stringstream slotname; 04797 slotname << slot+1; 04798 std::string save=temp+slotname.str()+".sav"; 04799 std::ifstream check_slot; 04800 check_slot.open(save.c_str(), std::ifstream::in); 04801 if(check_slot.fail()) { 04802 LOG_MSG("No saved slot - %d (%s)",(int)slot+1,save.c_str()); 04803 #if defined(WIN32) 04804 MessageBox(GetHWND(),"The selected save slot is empty.","Error",MB_OK); 04805 #endif 04806 load_err=true; 04807 return; 04808 } 04809 04810 for (CompEntry::const_iterator i = components.begin(); i != components.end(); ++i) { 04811 std::filebuf * fb; 04812 std::ifstream ss; 04813 std::ifstream check_file; 04814 fb = ss.rdbuf(); 04815 04816 //LOG_MSG("Component is %s",i->first.c_str()); 04817 04818 my_miniunz((char **)save.c_str(),i->first.c_str(),temp.c_str()); 04819 04820 if(!read_version) { 04821 my_miniunz((char **)save.c_str(),"DOSBox-X_Version",temp.c_str()); 04822 std::ifstream check_version; 04823 int length = 8; 04824 04825 std::string tempname = temp+"DOSBox-X_Version"; 04826 check_version.open(tempname.c_str(), std::ifstream::in); 04827 if(check_version.fail()) { 04828 LOG_MSG("Save state corrupted! Program in inconsistent state! - DOSBox-X_Version"); 04829 #if defined(WIN32) 04830 MessageBox(GetHWND(),"Save state corrupted!","Error",MB_OK); 04831 #endif 04832 load_err=true; 04833 goto delete_all; 04834 } 04835 check_version.seekg (0, std::ios::end); 04836 length = check_version.tellg(); 04837 check_version.seekg (0, std::ios::beg); 04838 04839 char * const buffer = (char*)alloca( (length+1) * sizeof(char)); // char buffer[length]; 04840 check_version.read (buffer, length); 04841 check_version.close(); 04842 buffer[length]='\0'; 04843 char *p=strrchr(buffer, '\n'); 04844 if (p!=NULL) *p=0; 04845 std::string emulatorversion = std::string("DOSBox-X ") + VERSION + std::string(" (") + SDL_STRING + std::string(")\n") + GetPlatform(); 04846 if (p==NULL||strcasecmp(buffer,emulatorversion.c_str())) { 04847 #if defined(WIN32) 04848 if(!force_load_state&&MessageBox(GetHWND(),"DOSBox-X version mismatch. Load the state anyway?","Warning",MB_YESNO|MB_DEFBUTTON2)==IDNO) { 04849 #else 04850 if(!force_load_state) { 04851 #endif 04852 LOG_MSG("Aborted. Check your DOSBox-X version: %s",buffer); 04853 load_err=true; 04854 goto delete_all; 04855 } 04856 } 04857 read_version=true; 04858 } 04859 04860 if(!read_title) { 04861 my_miniunz((char **)save.c_str(),"Program_Name",temp.c_str()); 04862 std::ifstream check_title; 04863 int length = 8; 04864 04865 std::string tempname = temp+"Program_Name"; 04866 check_title.open(tempname.c_str(), std::ifstream::in); 04867 if(check_title.fail()) { 04868 LOG_MSG("Save state corrupted! Program in inconsistent state! - Program_Name"); 04869 #if defined(WIN32) 04870 MessageBox(GetHWND(),"Save state corrupted!","Error",MB_OK); 04871 #endif 04872 load_err=true; 04873 goto delete_all; 04874 } 04875 check_title.seekg (0, std::ios::end); 04876 length = check_title.tellg(); 04877 check_title.seekg (0, std::ios::beg); 04878 04879 char * const buffer = (char*)alloca( (length+1) * sizeof(char)); // char buffer[length]; 04880 check_title.read (buffer, length); 04881 check_title.close(); 04882 if (strncmp(buffer,RunningProgram,length)||!length) { 04883 #if defined(WIN32) 04884 if(!force_load_state&&MessageBox(GetHWND(),"Program name mismatch. Load the state anyway?","Warning",MB_YESNO|MB_DEFBUTTON2)==IDNO) { 04885 #else 04886 if(!force_load_state) { 04887 #endif 04888 buffer[length]='\0'; 04889 LOG_MSG("Aborted. Check your program name: %s",buffer); 04890 load_err=true; 04891 goto delete_all; 04892 } 04893 if (length<9) { 04894 static char pname[9]; 04895 if (length) { 04896 strncpy(pname,buffer,length); 04897 pname[length]=0; 04898 } else 04899 strcpy(pname, "DOSBOX-X"); 04900 RunningProgram=pname; 04901 GFX_SetTitle(-1,-1,-1,false); 04902 } 04903 } 04904 read_title=true; 04905 } 04906 04907 if(!read_memorysize) { 04908 my_miniunz((char **)save.c_str(),"Memory_Size",temp.c_str()); 04909 std::fstream check_memorysize; 04910 int length = 8; 04911 04912 std::string tempname = temp+"Memory_Size"; 04913 check_memorysize.open(tempname.c_str(), std::ifstream::in); 04914 if(check_memorysize.fail()) { 04915 LOG_MSG("Save state corrupted! Program in inconsistent state! - Memory_Size"); 04916 load_err=true; 04917 goto delete_all; 04918 } 04919 check_memorysize.seekg (0, std::ios::end); 04920 length = check_memorysize.tellg(); 04921 check_memorysize.seekg (0, std::ios::beg); 04922 04923 char * const buffer = (char*)alloca( (length+1) * sizeof(char)); // char buffer[length]; 04924 check_memorysize.read (buffer, length); 04925 check_memorysize.close(); 04926 char str[10]; 04927 itoa(MEM_TotalPages(), str, 10); 04928 if(strncmp(buffer,str,length)) { 04929 #if defined(WIN32) 04930 if(!force_load_state&&MessageBox(GetHWND(),"Memory size mismatch. Load the state anyway?","Warning",MB_YESNO|MB_DEFBUTTON2)==IDNO) { 04931 #else 04932 if(!force_load_state) { 04933 #endif 04934 buffer[length]='\0'; 04935 LOG_MSG("Aborted. Check your memory size."); 04936 load_err=true; 04937 goto delete_all; 04938 } 04939 } 04940 read_memorysize=true; 04941 } 04942 std::string realtemp; 04943 realtemp = temp + i->first; 04944 check_file.open(realtemp.c_str(), std::ifstream::in); 04945 check_file.close(); 04946 if(check_file.fail()) { 04947 LOG_MSG("Save state corrupted! Program in inconsistent state! - %s",i->first.c_str()); 04948 #if defined(WIN32) 04949 MessageBox(GetHWND(),"Save state corrupted!","Error",MB_OK); 04950 #endif 04951 load_err=true; 04952 goto delete_all; 04953 } 04954 04955 fb->open(realtemp.c_str(),std::ios::in | std::ios::binary); 04956 std::string str((std::istreambuf_iterator<char>(ss)), std::istreambuf_iterator<char>()); 04957 std::stringstream mystream; 04958 mystream << (Util::decompress(str)); 04959 i->second.comp.setBytes(mystream); 04960 if (mystream.rdbuf()->in_avail() != 0 || mystream.eof()) { //basic consistency check 04961 LOG_MSG("Save state corrupted! Program in inconsistent state! - %s",i->first.c_str()); 04962 #if defined(WIN32) 04963 MessageBox(GetHWND(),"Save state corrupted!","Error",MB_OK); 04964 #endif 04965 load_err=true; 04966 goto delete_all; 04967 } 04968 //compress all other saved states except position "slot" 04969 //const std::vector<RawBytes>& rb = i->second.rawBytes; 04970 //std::for_each(rb.begin(), rb.begin() + slot, std::mem_fun_ref(&RawBytes::compress)); 04971 //std::for_each(rb.begin() + slot + 1, rb.end(), std::mem_fun_ref(&RawBytes::compress)); 04972 fb->close(); 04973 mystream.clear(); 04974 } 04975 delete_all: 04976 std::string save2; 04977 for (CompEntry::const_iterator i = components.begin(); i != components.end(); ++i) { 04978 save2=temp+i->first; 04979 remove(save2.c_str()); 04980 } 04981 save2=temp+"DOSBox-X_Version"; 04982 remove(save2.c_str()); 04983 save2=temp+"Program_Name"; 04984 remove(save2.c_str()); 04985 save2=temp+"Memory_Size"; 04986 remove(save2.c_str()); 04987 if (!load_err) LOG_MSG("Loaded. (Slot %d)",(int)slot+1); 04988 } 04989 04990 bool SaveState::isEmpty(size_t slot) const { 04991 if (slot >= SLOT_COUNT) return true; 04992 std::string path; 04993 bool Get_Custom_SaveDir(std::string& savedir); 04994 if(Get_Custom_SaveDir(path)) { 04995 path+=CROSS_FILESPLIT; 04996 } else { 04997 extern std::string capturedir; 04998 const size_t last_slash_idx = capturedir.find_last_of("\\/"); 04999 if (std::string::npos != last_slash_idx) { 05000 path = capturedir.substr(0, last_slash_idx); 05001 } else { 05002 path = "."; 05003 } 05004 path += CROSS_FILESPLIT; 05005 path +="save"; 05006 path += CROSS_FILESPLIT; 05007 } 05008 std::string temp; 05009 temp = path; 05010 std::stringstream slotname; 05011 slotname << slot+1; 05012 std::string save=temp+slotname.str()+".sav"; 05013 std::ifstream check_slot; 05014 check_slot.open(save.c_str(), std::ifstream::in); 05015 return check_slot.fail(); 05016 } 05017 05018 std::string SaveState::getName(size_t slot) const { 05019 if (slot >= SLOT_COUNT) return "[Empty]"; 05020 std::string path; 05021 bool Get_Custom_SaveDir(std::string& savedir); 05022 if(Get_Custom_SaveDir(path)) { 05023 path+=CROSS_FILESPLIT; 05024 } else { 05025 extern std::string capturedir; 05026 const size_t last_slash_idx = capturedir.find_last_of("\\/"); 05027 if (std::string::npos != last_slash_idx) { 05028 path = capturedir.substr(0, last_slash_idx); 05029 } else { 05030 path = "."; 05031 } 05032 path += CROSS_FILESPLIT; 05033 path +="save"; 05034 path += CROSS_FILESPLIT; 05035 } 05036 std::string temp; 05037 temp = path; 05038 std::stringstream slotname; 05039 slotname << slot+1; 05040 std::string save=temp+slotname.str()+".sav"; 05041 std::ifstream check_slot; 05042 check_slot.open(save.c_str(), std::ifstream::in); 05043 if (check_slot.fail()) return "[Empty]"; 05044 my_miniunz((char **)save.c_str(),"Program_Name",temp.c_str()); 05045 std::ifstream check_title; 05046 int length = 8; 05047 std::string tempname = temp+"Program_Name"; 05048 check_title.open(tempname.c_str(), std::ifstream::in); 05049 if (check_title.fail()) { 05050 remove(tempname.c_str()); 05051 return ""; 05052 } 05053 check_title.seekg (0, std::ios::end); 05054 length = check_title.tellg(); 05055 check_title.seekg (0, std::ios::beg); 05056 char * const buffer = (char*)alloca( (length+1) * sizeof(char)); 05057 check_title.read (buffer, length); 05058 check_title.close(); 05059 remove(tempname.c_str()); 05060 buffer[length]='\0'; 05061 return std::string(buffer); 05062 }