/*
 *  Copyright (C) 2002-2021  The DOSBox Team
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

/* NTS: Valgrind hunting shows memory leak from C++ new operator somewhere
 *      with the JACK library indirectly invoked by SDL audio. Can we resolve
 *      that too eventually? */

/* NTS: Valgrind hunting also shows one of the section INIT functions (I can't
 *      yet tell which one because the stack trace doesn't show it) is allocating
 *      something and is not freeing it. */

/* NTS: Valgrind hunting has a moderate to high signal-to-noise ratio because
 *      of memory leaks (lazy memory allocation) from other libraries in the
 *      system, including:
 *
 *         ncurses
 *         libSDL
 *         libX11 and libXCB
 *         libasound (ALSA sound library)
 *         PulseAudio library calls
 *         JACK library calls
 *         libdl (the dlopen/dlclose functions allocate something and never free it)
 *         and a whole bunch of unidentified malloc calls without a matching free.
 *
 *      On my dev system, a reported leak of 450KB (77KB possibly lost + 384KB still reachable
 *      according to Valgrind) is normal.
 *
 *      Now you ask: why do I care so much about Valgrind, memory leaks, and cleaning
 *      up the code? The less spurious memory leaks, the easier it is to identify
 *      actual leaks among the noise and to patch them up. Thus, "valgrind hunting" --J.C. */

#include <assert.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <ctime>
#include <unistd.h>
#include "dosbox.h"
#include "debug.h"
#include "cpu.h"
#include "logging.h"
#include "menudef.h"
#include "video.h"
#include "pic.h"
#include "cpu.h"
#include "ide.h"
#include "callback.h"
#include "inout.h"
#include "mixer.h"
#include "timer.h"
#include "dos_inc.h"
#include "setup.h"
#include "control.h"
#include "cross.h"
#include "programs.h"
#include "support.h"
#include "mapper.h"
#include "ints/int10.h"
#include "menu.h"
#include "jfont.h"
#include "render.h"
#include "pci_bus.h"
#include "parport.h"
#include "keyboard.h"
#include "clockdomain.h"

#if __APPLE__ && __MAC_OS_X_VERSION_MIN_REQUIRED < 101200
/* FIX_ME: A workaround to avoid build error. Change version to 101300 if error occurs for Sierra (10.12) */
struct __processor_model {
  unsigned int __cpu_vendor;
  unsigned int __cpu_type;
  unsigned int __cpu_subtype;
  unsigned int __cpu_features[1];
} __cpu_model = {0, 0, 0, {0}};
#endif

#if C_EMSCRIPTEN
# include <emscripten.h>
#endif

#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif

#include <list>

bool int10_vp_use_always = false;
bool int10_vp_use_auto = true;

unsigned int preventcap = PREVCAP_NONE;

#ifndef WDA_NONE
# define WDA_NONE 0x00
#endif

#ifndef WDA_MONITOR
# define WDA_MONITOR 0x01
#endif

#ifndef WDA_EXCLUDEFROMCAPTURE /* NTS: Notice this is a bit field of both Windows 7 WDA_MONITOR and Windows 10 EXCLUDEFROMCAPTURE */
# define WDA_EXCLUDEFROMCAPTURE 0x11
#endif

void ApplyPreventCapMenu(void);

#if defined(MACOSX)
void MacOSEnableWindowCapture(unsigned int enable);
#endif

void ApplyPreventCap(void) {
#if defined(MACOSX)
    MacOSEnableWindowCapture(preventcap == PREVCAP_NONE);
#endif
#ifdef WIN32
	HMODULE usr = (HMODULE)GetModuleHandle("USER32.DLL");
	if (usr) {
		BOOL (WINAPI *__GetWindowDisplayAffinity)(HWND hWnd,DWORD *pdwAffinity) =
			(BOOL (WINAPI*)(HWND, DWORD*))GetProcAddress(usr,"GetWindowDisplayAffinity");
        BOOL (WINAPI * __SetWindowDisplayAffinity)(HWND hWnd, DWORD dwAffinity) =
            (BOOL (WINAPI*)(HWND, DWORD))GetProcAddress(usr, "SetWindowDisplayAffinity");

        if(__GetWindowDisplayAffinity && __SetWindowDisplayAffinity) {
			HWND hwnd = GetHWND();
			DWORD paff = 0,naff = 0;

            __GetWindowDisplayAffinity(hwnd, &paff);

            switch(preventcap) {
                case PREVCAP_BLANK: naff = WDA_MONITOR; break;
                case PREVCAP_INVISIBLE: naff = WDA_EXCLUDEFROMCAPTURE; break;
            }

            /* NTS: Changing from blank to invisible or the other way around doesn't do anything in Windows 11.
                    It can only be done by removing the exclusion then applying the new one. */
            const DWORD chkaff = WDA_MONITOR | WDA_EXCLUDEFROMCAPTURE;
            if(naff != 0 && (paff & chkaff) != (naff & chkaff)) {
                LOG(LOG_MISC, LOG_DEBUG)("Clearing existing affinity to apply new affinity");
                paff = 0; __SetWindowDisplayAffinity(hwnd, paff);
            }

			if (!__SetWindowDisplayAffinity(hwnd,naff)) LOG(LOG_MISC,LOG_DEBUG)("WARNING: SetWindowDisplayAffinity(hwnd,0x%x) failed",(unsigned int)naff);
		}
	}
#endif
}

bool CheckPreventCap(void) {
	unsigned int nv = PREVCAP_NONE;
	bool changed = false;

	Section_prop *video_section = static_cast<Section_prop *>(control->GetSection("video"));
	assert(video_section != NULL);

	{
		const char *s = video_section->Get_string("prevent capture");

		if (!strcmp(s,"blank"))
			nv = PREVCAP_BLANK;
		else if (!strcmp(s,"invisible"))
			nv = PREVCAP_INVISIBLE;
		else
			nv = PREVCAP_NONE;
	}

	if (preventcap != nv) {
		preventcap = nv;
		changed = true;
	}

	return changed;
}

/*===================================TODO: Move to its own file==============================*/
#if defined(__SSE__) && !(defined(_M_AMD64) || defined(__e2k__))
bool sse2_available = false;
bool avx2_available = false;

# if defined(_MSC_VER)
#  define cpuid(func,a,b,c,d)\
    __asm mov eax, func\
    __asm cpuid\
    __asm mov a, eax\
    __asm mov b, ebx\
    __asm mov c, ecx\
    __asm mov d, edx
# endif /* _MSC_VER */

static void CheckX86ExtensionsSupport()
{
#if defined(__GNUC__) && !defined(EMSCRIPTEN)
    sse2_available = __builtin_cpu_supports("sse2");
    avx2_available = __builtin_cpu_supports("avx2");
#elif (_MSC_VER) && !defined(EMSCRIPTEN)
    Bitu a, b, c, d;
    cpuid(1, a, b, c, d);
    sse2_available = ((d >> 26) & 1)?true:false;
    avx2_available = ((b >> 5) & 1)?true:false;
#endif
}
#endif
/*=============================================================================*/

extern void         GFX_SetTitle(int32_t cycles, int frameskip, Bits timing, bool paused);
extern void         AddSaveStateMapper(), AddMessages(), JFONT_Init(), J3_SetType(std::string type, std::string back, std::string text);
extern bool         force_nocachedir;
extern bool         convertimg;
extern bool         wpcolon;
extern bool         lockmount;
extern bool         clearline;

extern Bitu         frames;
extern Bitu         cycle_count;
extern bool         sse2_available;
extern bool         avx2_available;
extern bool         dos_kernel_disabled;
extern bool         dynamic_dos_kernel_alloc;
extern Bitu         DOS_PRIVATE_SEGMENT_Size;
extern bool         VGA_BIOS_dont_duplicate_CGA_first_half;
extern bool         VIDEO_BIOS_always_carry_14_high_font;
extern bool         VIDEO_BIOS_always_carry_16_high_font;
extern bool         VIDEO_BIOS_enable_CGA_8x8_second_half;
extern bool         allow_more_than_640kb, del_flag;
extern bool         sync_time, enableime, tonoime;
extern int          freesizecap;
extern unsigned int page;

uint32_t              guest_msdos_LoL = 0;
uint16_t              guest_msdos_mcb_chain = 0;
uint32_t              guest_msdos_dev_chain = 0;
int                 boothax = BOOTHAX_NONE;
bool                gbk = false;
bool                chinasea = false;
bool                uao = false;
bool                jp_ega = false;
#if !defined(OSFREE)
bool                j3100_start = false;
#endif
bool                want_fm_towns = false;

bool                dos_con_use_int16_to_detect_input = true;

#if !defined(OSFREE)
bool                dbg_zero_on_dos_allocmem = false;
bool                dbg_zero_on_xms_allocmem = false;
bool                dbg_zero_on_ems_allocmem = false;
#endif

/* the exact frequency of the NTSC color subcarrier ~3.579545454...MHz or 315/88 */
/* see: https://en.wikipedia.org/wiki/Colorburst */
#define             NTSC_COLOR_SUBCARRIER_NUM       (315000000ULL)
#define             NTSC_COLOR_SUBCARRIER_DEN       (88ULL)

/* PCI bus clock
 * Usual setting: 100MHz / 3 = 33.333MHz
 *                 90MHz / 3 = 30.000MHz */
ClockDomain         clockdom_PCI_BCLK(100000000,3);     /* MASTER 100MHz / 3 = 33.33333MHz */

/* ISA bus OSC clock (14.31818MHz), using a crystal that is 4x the NTSC subcarrier frequency 3.5795454..MHz */
ClockDomain         clockdom_ISA_OSC(NTSC_COLOR_SUBCARRIER_NUM*4,NTSC_COLOR_SUBCARRIER_DEN);

/* ISA bus clock (varies between 4.77MHz to 8.333MHz)
 * PC/XT: ISA oscillator clock (14.31818MHz / 3) = 4.77MHz
 * Some systems keep CPU synchronous to bus clock: 4.77MHz, 6MHz, 8MHz, 8.333MHz
 * Later systems: 25MHz / 3 = 8.333MHz
 *                33MHz / 4 = 8.333MHz
 * PCI bus systems: PCI bus clock 33MHz / 4 = 8.333MHz (especially Intel chipsets according to PIIX datasheets) */
ClockDomain         clockdom_ISA_BCLK(25000000,3);      /* MASTER 25000000Hz / 3 = 8.333333MHz */

Config*             control;
MachineType         machine;
bool                PS1AudioCard;       // Perhaps have PS1 as a machine type...?
SVGACards           svgaCard;
S3Card              s3Card;
ATICard             atiCard;
HerculesCard        hercCard;
bool                SDLNetInited;
int32_t              ticksDone;
uint32_t              ticksScheduled;
bool                ticksLocked;
bool                mono_cga=false;
bool                ignore_opcode_63 = true;
int                 dynamic_core_cache_block_size = 32;
Bitu                VGA_BIOS_Size_override = 0;
Bitu                VGA_BIOS_SEG = 0xC000;
Bitu                VGA_BIOS_SEG_END = 0xC800;
Bitu                VGA_BIOS_Size = 0x8000;
bool                VGA_BIOS_use_rom = false; // load VGA BIOS from a ROM file rather than make our own
std::string         VGA_BIOS_rom;

uint32_t                  emulator_speed = 100;

static uint32_t           ticksRemain;
static uint32_t           ticksRemainSpeedFrac;
static uint32_t           ticksLast;
static uint32_t           ticksLastFramecounter;
static uint32_t           ticksLastRTcounter;
static double           ticksLastRTtime;
static uint32_t           ticksAdded;
static uint32_t           Ticks = 0;
extern double           rtdelta;
static LoopHandler*     loop;

void increaseticks(), makestdcp950table(), makeseacp951table();

/* The whole load of startups for all the subfunctions */
void                MEM_Init(Section *);
void                ISAPNP_Cfg_Init(Section *);
void                ROMBIOS_Init(Section *);
void                CALLBACK_Init(Section*);
void                PROGRAMS_Init(Section*);
void                RENDER_Init(Section*);
void                VGA_VsyncInit(Section*);
void                VGA_Init(Section*);
void                DOS_Init(Section*);
void                CPU_Init(Section*);
#if C_FPU
void                FPU_Init(Section*);
#endif
void                DMA_Init(Section*);
void                MIXER_Init(Section*);
void                MIDI_Init(Section*);
void                HARDWARE_Init(Section*);
void                PCIBUS_Init(Section*);
void                PCI_Init(Section*);
void                VOODOO_Init(Section*);

void                IDE_Primary_Init(Section*);
void                IDE_Secondary_Init(Section*);
void                IDE_Tertiary_Init(Section*);
void                IDE_Quaternary_Init(Section*);
void                IDE_Quinternary_Init(Section*);
void                IDE_Sexternary_Init(Section*);
void                IDE_Septernary_Init(Section*);
void                IDE_Octernary_Init(Section*);

void                FDC_Primary_Init(Section*);

void                KEYBOARD_Init(Section*);    //TODO This should setup INT 16 too but ok ;)
void                JOYSTICK_Init(Section*);
void                MOUSE_Init(Section*);
void                SBLASTER_Init(Section*);
void                GUS_Init(Section*);
void                MPU401_Init(Section*);
void                PCSPEAKER_Init(Section*);
void                TANDYSOUND_Init(Section*);
void                DISNEY_Init(Section*);
void                PS1SOUND_Init(Section*);
void                INNOVA_Init(Section*);
void                IMFC_Init(Section*);
void                SERIAL_Init(Section*);
void                DONGLE_Init(Section*);
#if C_IPX
void                IPX_Init(Section*);
#endif
void                PIC_Init(Section*);
void                TIMER_Init(Section*);
void                BIOS_Init(Section*);
void                DEBUG_Init(Section*);
void                CMOS_Init(Section*);
void                MSCDEX_Init(Section*);
void                DRIVES_Init(Section*);
void                CDROM_Image_Init(Section*);
void                EMS_Init(Section*);
void                XMS_Init(Section*);
void                DOS_KeyboardLayout_Init(Section*);
void                AUTOEXEC_Init(Section*);
void                INT10_Init(Section*);
#if C_PRINTER
void                PRINTER_Init(Section*);
#endif

signed long long time_to_clockdom(const ClockDomain &src,double t) {
    signed long long lt = (signed long long)t;

    lt *= (signed long long)src.freq;
    lt /= (signed long long)src.freq_div;
    return lt;
}

unsigned long long update_clockdom_from_now(ClockDomain &dst) {
    signed long long s;

    /* PIC_Ticks (if I read the code correctly) is millisecond ticks, units of 1/1000 seconds.
     * PIC_TickIndexND() units of submillisecond time in units of 1/CPU_CycleMax. */
    s  = (signed long long)((unsigned long long)PIC_Ticks * dst.freq);
    s += (signed long long)(((unsigned long long)PIC_TickIndexND() * dst.freq) / (unsigned long long)CPU_CycleMax);
    /* convert down to frequency counts, not freq x 1000 */
    s /= (signed long long)(1000ULL * dst.freq_div);

    /* guard against time going backwards slightly (as PIC_TickIndexND() will do sometimes by tiny amounts) */
    if (dst.counter < (unsigned long long)s) dst.counter = (unsigned long long)s;

    return dst.counter;
}

#include "paging.h"

extern bool rom_bios_vptable_enable;
extern bool rom_bios_8x8_cga_font;
extern bool allow_port_92_reset;
extern bool allow_keyb_reset;
#if defined(USE_TTF)
extern bool ttf_dosv;
#endif

extern bool DOSBox_Paused(), isDBCSCP(), InitCodePage();

//#define DEBUG_CYCLE_OVERRUN_CALLBACK

//For trying other delays
#define wrap_delay(a) SDL_Delay(a)

static Uint32 SDL_ticks_last = 0,SDL_ticks_next = 0;

static Bitu Normal_Loop(void) {
    bool saved_allow = dosbox_allow_nonrecursive_page_fault;
    Bits ret;

    if (!menu.hidecycles || menu.showrt) { /* sdlmain.cpp/render.cpp doesn't even maintain the frames count when hiding cycles! */
        uint32_t ticksNew = GetTicks();
        if (ticksNew >= Ticks) {
            uint32_t interval = ticksNew - ticksLastFramecounter;
            double rtnow = PIC_FullIndex();

            if (interval == 0) interval = 1; // avoid divide by zero

            rtdelta = rtnow - ticksLastRTtime;
            rtdelta = (rtdelta * 1000) / interval;

            ticksLastRTtime = rtnow;
            ticksLastFramecounter = Ticks;
            Ticks = ticksNew + 500;     // next update in 500ms
            frames = (frames * 1000) / interval; // compensate for interval, be more exact (FIXME: so can we adjust for fractional frame rates)
            GFX_SetTitle((int32_t)CPU_CycleMax,-1,-1,false);
            frames = 0;
        }
    }

    if (control->opt_print_ticks) {
        Uint32 now = SDL_GetTicks();

        if (now >= SDL_ticks_next || now < SDL_ticks_last) {
            LOG_MSG("Tick report: SDL=%lu emu=%.6f",(unsigned long)now,(double)PIC_FullIndex());
            SDL_ticks_next = now + 1000;
        }

        SDL_ticks_last = now;
    }

    try {
        while (1) {
            if (PIC_RunQueue()) {
                /* now is the time to check for the NMI (Non-maskable interrupt) */
                CPU_Check_NMI();

                saved_allow = dosbox_allow_nonrecursive_page_fault;
                dosbox_allow_nonrecursive_page_fault = true;
                ret = (*cpudecoder)();
                dosbox_allow_nonrecursive_page_fault = saved_allow;

                if (GCC_UNLIKELY(ret<0))
                    return 1;

                if (ret>0) {
                    if (GCC_UNLIKELY((unsigned int)ret >= CB_MAX))
                        return 0;

                    extern unsigned int last_callback;
                    unsigned int p_last_callback = last_callback;
                    last_callback = (unsigned int)ret;

                    dosbox_allow_nonrecursive_page_fault = false;
                    Bitu blah = (*CallBack_Handlers[ret])();
                    dosbox_allow_nonrecursive_page_fault = saved_allow;

                    last_callback = p_last_callback;

#ifdef DEBUG_CYCLE_OVERRUN_CALLBACK
                    {
                        extern char* CallBack_Description[CB_MAX];

                        /* I/O delay can cause negative CPU_Cycles and PIC event / audio rendering issues */
                        cpu_cycles_count_t overrun = -std::min(CPU_Cycles,(cpu_cycles_count_t)0);

                        if (overrun > (CPU_CycleMax/100))
                            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]);
                    }
#endif

                    if (GCC_UNLIKELY(blah > 0U))
                        return blah;
                }
#if C_DEBUG
                if (DEBUG_ExitLoop())
                    return 0;
#endif
            } else {
                GFX_Events();
                if (DOSBox_Paused() == false && ticksRemain > 0) {
                    TIMER_AddTick();
                    ticksRemain--;
                } else {
                    increaseticks();
                    return 0;
                }
            }
        }
    }
    catch (const GuestPageFaultException& pf) {
        Bitu FillFlags(void);

//      LOG_MSG("Guest page fault %08x code %08x",(unsigned int)pf.lin_addr,(unsigned int)pf.faultcode);

        /* Clear TLB because the guest OS is likely going to update the page tables to resolve the fault.
         * This is REQUIRED for the normal core to run the Linux kernel properly, or else things just get "stuck"
         * when you run commands. */
        PAGING_ClearTLB();

        ret = 0;
        FillFlags();
        paging.cr2=pf.lin_addr;
        dosbox_allow_nonrecursive_page_fault = false;
        CPU_Exception(EXCEPTION_PF, pf.faultcode);
        dosbox_allow_nonrecursive_page_fault = saved_allow;
	}
	catch (const GuestGenFaultException& gpf) {
        (void)gpf;//UNUSED
		Bitu FillFlags(void);

		ret = 0;
		FillFlags();
		dosbox_allow_nonrecursive_page_fault = false;
		CPU_Exception(EXCEPTION_GP, 0);
		dosbox_allow_nonrecursive_page_fault = saved_allow;
	}
	catch (int x) {
		dosbox_allow_nonrecursive_page_fault = saved_allow;
		if (x == 4/*CMOS shutdown*/) {
			ret = 0;
//          LOG_MSG("CMOS shutdown reset acknowledged");
		}
		else {
			throw;
		}
	}
	return 0;
}

void increaseticks() { //Make it return ticksRemain and set it in the function above to remove the global variable.
    static int32_t lastsleepDone = -1;
    static Bitu sleep1count = 0;
    if (GCC_UNLIKELY(ticksLocked)) { // For Fast Forward Mode
        ticksRemainSpeedFrac = 0;
        ticksRemain = 5;
        /* Reset any auto cycle guessing for this frame */
        ticksLast = GetTicks();
        ticksAdded = 0;
        ticksDone = 0;
        ticksScheduled = 0;
        return;
    }
    uint32_t ticksNew = GetTicks();
    ticksScheduled += ticksAdded;

    if (ticksNew <= ticksLast) { //lower should not be possible, only equal.
        ticksAdded = 0;

        if (!CPU_CycleAutoAdjust || CPU_SkipCycleAutoAdjust || sleep1count < 3) {
            wrap_delay(1);
        }
        else {
            /* Certain configurations always give an exact sleepingtime of 1, this causes problems due to the fact that
               DOSBox-X keeps track of full blocks.
               This code introduces some randomness to the time slept, which improves stability on those configurations
             */
            static const uint32_t sleeppattern[] = { 2, 2, 3, 2, 2, 4, 2 };
            static uint32_t sleepindex = 0;
            if (ticksDone != lastsleepDone) sleepindex = 0;
            wrap_delay(sleeppattern[sleepindex++]);
            sleepindex %= sizeof(sleeppattern) / sizeof(sleeppattern[0]);
        }
        int32_t timeslept = (int32_t)(GetTicks() - ticksNew);
        // Count how many times in the current block (of 250 ms) the time slept was 1 ms
        if (CPU_CycleAutoAdjust && !CPU_SkipCycleAutoAdjust && timeslept == 1) sleep1count++;
        lastsleepDone = ticksDone;

        // Update ticksDone with the time spent sleeping
        ticksDone -= timeslept;

        if (ticksDone < 0)
            ticksDone = 0;
        return;
    }

    //ticksNew > ticksLast
    ticksRemain = ticksNew - ticksLast;

    if (emulator_speed != 100u) {
        ticksRemain *= emulator_speed;
        ticksRemain += ticksRemainSpeedFrac;
        ticksRemainSpeedFrac = ticksRemain % 100u;
        ticksRemain /= 100u;
    }
    else {
        ticksRemainSpeedFrac = 0;
    }

    ticksLast = ticksNew;
    ticksDone += (int32_t)ticksRemain;
    if (ticksRemain > 20) {
        ticksRemain = 20;
    }
    ticksAdded = ticksRemain;

    // Is the system in auto cycle mode guessing? If not just exit. (It can be temporarily disabled)
    if (!CPU_CycleAutoAdjust || CPU_SkipCycleAutoAdjust)
        return;

    if (ticksScheduled >= 250 || ticksDone >= 250 || (ticksAdded > 15 && ticksScheduled >= 5)) {
        if (ticksDone < 1) ticksDone = 1; // Protect against div by zero
        /* ratio we are aiming for is around 90% usage*/
        int32_t ratio = (int32_t)((ticksScheduled * (CPU_CyclePercUsed * 90 * 1024 / 100 / 100)) / ticksDone);
        int32_t new_cmax = (int32_t)CPU_CycleMax;
        int64_t cproc = (int64_t)CPU_CycleMax * (int64_t)ticksScheduled;
        if (cproc > 0) {
            /* ignore the cycles added due to the IO delay code in order
               to have smoother auto cycle adjustments */
            double ratioremoved = (double)CPU_IODelayRemoved / (double)cproc;
            if (ratioremoved < 1.0) {
                double ratio_not_removed = 1 - ratioremoved;
                ratio = (int32_t)((double)ratio * ratio_not_removed);
                /* Don't allow very high ratio which can cause us to lock as we don't scale down
                 * for very low ratios. High ratio might result because of timing resolution */
                if (ticksScheduled >= 250 && ticksDone < 10 && ratio > 16384)
                    ratio = 16384;

                // Limit the ratio even more when the cycles are already way above the realmode default.
                if (ticksScheduled >= 250 && ticksDone < 10 && ratio > 5120 && CPU_CycleMax > 50000)
                    ratio = 5120;

                // When downscaling multiple times in a row, ensure a minimum amount of downscaling
                if (ticksAdded > 15 && ticksScheduled >= 5 && ticksScheduled <= 20 && ratio > 800)
                    ratio = 800;

                if (ratio <= 1024) {
                    // ratio_not_removed = 1.0; //enabling this restores the old formula
                    double r = (1.0 + ratio_not_removed) / (ratio_not_removed + 1024.0 / (static_cast<double>(ratio)));
                    new_cmax = 1 + static_cast<int32_t>(CPU_CycleMax * r);
                }
                else {
                    int64_t ratio_with_removed = (int64_t)((((double)ratio - 1024.0) * ratio_not_removed) + 1024.0);
                    int64_t cmax_scaled = (int64_t)CPU_CycleMax * ratio_with_removed;
                    new_cmax = (int32_t)(1 + (CPU_CycleMax >> 1) + cmax_scaled / (int64_t)2048);
                }
            }
        }

        if (new_cmax < CPU_CYCLES_LOWER_LIMIT)
            new_cmax = CPU_CYCLES_LOWER_LIMIT;

        /*
           LOG_MSG("cyclelog: current %6d   cmax %6d   ratio  %5d  done %3d   sched %3d",
           CPU_CycleMax,
           new_cmax,
           ratio,
           ticksDone,
           ticksScheduled);
           */
           /* ratios below 1% are considered to be dropouts due to
              temporary load imbalance, the cycles adjusting is skipped */
        if (ratio > 10) {
            /* ratios below 12% along with a large time since the last update
               has taken place are most likely caused by heavy load through a
               different application, the cycles adjusting is skipped as well */
            if ((ratio > 120) || (ticksDone < 700)) {
                RDTSC_rebase();
                CPU_CycleMax = new_cmax;
                if (CPU_CycleLimit > 0) {
                    if (CPU_CycleMax > CPU_CycleLimit) CPU_CycleMax = CPU_CycleLimit;
                }
                else if (CPU_CycleMax > 2000000) CPU_CycleMax = 2000000; //Hardcoded limit, if no limit was specified.
            }
        }

        //Reset cycleguessing parameters.
        CPU_IODelayRemoved = 0;
        ticksDone = 0;
        ticksScheduled = 0;
        lastsleepDone = -1;
        sleep1count = 0;
    }
    else if (ticksAdded > 15) {
        /* ticksAdded > 15 but ticksScheduled < 5, lower the cycles
           but do not reset the scheduled/done ticks to take them into
           account during the next auto cycle adjustment */
        RDTSC_rebase();
        CPU_CycleMax /= 3;
        if (CPU_CycleMax < CPU_CYCLES_LOWER_LIMIT)
            CPU_CycleMax = CPU_CYCLES_LOWER_LIMIT;
    }
}

LoopHandler *DOSBOX_GetLoop(void) {
    return loop;
}

void DOSBOX_SetLoop(LoopHandler * handler) {
    loop=handler;
}

void DOSBOX_SetNormalLoop() {
    loop=Normal_Loop;
}

//#define DEBUG_RECURSION

#ifdef DEBUG_RECURSION
volatile int runmachine_recursion = 0;
#endif

void DOSBOX_RunMachine(void){
    Bitu ret;

    extern unsigned int last_callback;
    unsigned int p_last_callback = last_callback;
    last_callback = 0;

#ifdef DEBUG_RECURSION
    if (runmachine_recursion++ != 0)
        LOG_MSG("RunMachine recursion");
#endif

    do {
        ret=(*loop)();
    } while (!ret);

#ifdef DEBUG_RECURSION
    if (--runmachine_recursion < 0)
        LOG_MSG("RunMachine recursion leave error");
#endif

    last_callback = p_last_callback;
}

uint32_t turbolasttick = 0;
static void DOSBOX_UnlockSpeed( bool pressed ) {
    static bool autoadjust = false;
    if (pressed) {
        LOG_MSG("Fast Forward ON");
        turbolasttick = GetTicks();
        ticksLocked = true;
        if (CPU_CycleAutoAdjust) {
            RDTSC_rebase();
            autoadjust = true;
            CPU_CycleAutoAdjust = false;
            CPU_CycleMax /= 3;
            if (CPU_CycleMax<1000) CPU_CycleMax=1000;
            GFX_SetTitle((int32_t)CPU_CycleMax,-1,-1,false);
        }
    } else {
        LOG_MSG("Fast Forward OFF");
        ticksLocked = false;
        turbolasttick = 0;
        if (autoadjust) {
            autoadjust = false;
            CPU_CycleAutoAdjust = true;
            GFX_SetTitle((int32_t)CPU_CyclePercUsed,-1,-1,false);
        }
    }
    GFX_SetTitle(-1,-1,-1,false);
}

void DOSBOX_UnlockSpeed2( bool pressed ) {
    if (pressed) {
        ticksLocked = !ticksLocked;
        DOSBOX_UnlockSpeed(ticksLocked?true:false);

        /* make sure the menu item keeps up with our state */
        mainMenu.get_item("mapper_speedlock2").check(ticksLocked).refresh_item(mainMenu);
    }
}

void DOSBOX_NormalSpeed( bool pressed ) {
    if (pressed) {
        /* should also cancel turbo mode */
        if (ticksLocked)
            DOSBOX_UnlockSpeed2(true);

        LOG_MSG("Emulation speed restored to normal (100%%)");

        emulator_speed = 100;
        ticksRemainSpeedFrac = 0;
    }
}

void DOSBOX_SpeedUp( bool pressed ) {
    if (pressed) {
        ticksRemainSpeedFrac = 0;
        if (emulator_speed >= 5)
            emulator_speed += 5;
        else
            emulator_speed = 5;

        LOG_MSG("Emulation speed increased to (%u%%)",(unsigned int)emulator_speed);
    }
}

void DOSBOX_SlowDown( bool pressed ) {
    if (pressed) {
        ticksRemainSpeedFrac = 0;
        if (emulator_speed  > 5)
            emulator_speed -= 5;
        else
            emulator_speed = 1;

        LOG_MSG("Emulation speed decreased to (%u%%)",(unsigned int)emulator_speed);
    }
}


/* TODO: move to utility header */
#ifdef _MSC_VER /* Microsoft C++ does not have strtoull */
# if _MSC_VER < 1800 /* But Visual Studio 2013 apparently does (https://www.vogons.org/viewtopic.php?f=41&t=31881&sid=49ff69ebc0459ed6523f5a250daa4d8c&start=400#p355770) */
unsigned long long strtoull(const char *s,char **endptr,int base) {
    return _strtoui64(s,endptr,base); /* pfff... whatever Microsoft */
}
# endif
#endif

/* utility function. rename as appropriate and move to utility collection */
void parse_busclk_setting_str(ClockDomain *cd,const char *s) {
    const char *d;

    /* we're expecting an integer, a float, or an integer ratio */
    d = strchr(s,'/');
    if (d != NULL) { /* it has a slash therefore an integer ratio */
        unsigned long long num,den;

        while (*d == ' ' || *d == '/') d++;
        num = strtoull(s,NULL,0);
        den = strtoull(d,NULL,0);
        if (num >= 1ULL && den >= 1ULL) cd->set_frequency(num,den);
    }
    else {
        d = strchr(s,'.');
        if (d != NULL) { /* it has a dot, floating point */
            double f = atof(s);
            unsigned long long fi = (unsigned long long)floor((f*1000000)+0.5);
            unsigned long long den = 1000000;

            while (den > 1ULL) {
                if ((fi%10ULL) == 0) {
                    den /= 10ULL;
                    fi /= 10ULL;
                }
                else {
                    break;
                }
            }

            if (fi >= 1ULL) cd->set_frequency(fi,den);
        }
        else {
            unsigned long long f = strtoull(s,NULL,10);
            if (f >= 1ULL) cd->set_frequency(f,1);
        }
    }
}

unsigned int dosbox_shell_env_size = 0;

void Null_Init(Section *sec) {
	(void)sec;
}

extern uint8_t cga_comp;
extern bool new_cga;
extern bool ega200;

bool dpi_aware_enable = true;

std::string dosbox_title;

void DOSBOX_InitTickLoop() {
    LOG(LOG_MISC,LOG_DEBUG)("Initializing tick loop management");
    Section_prop *section = static_cast<Section_prop *>(control->GetSection("cpu"));

    ticksRemain = 0;
    ticksLocked = section->Get_bool("turbo");
    ticksLastRTtime = 0;
    ticksLast = GetTicks();
    ticksLastRTcounter = GetTicks();
    ticksLastFramecounter = GetTicks();
    DOSBOX_SetLoop(&Normal_Loop);
}

void Init_VGABIOS() {
    long rom_sz = 0;
    FILE *rom_fp = NULL;
    Section_prop *video_section = static_cast<Section_prop *>(control->GetSection("video"));
    assert(video_section != NULL);

    if (IS_PC98_ARCH) {
        // There IS no VGA BIOS, this is PC-98 mode!
        VGA_BIOS_SEG = 0xC000;
        VGA_BIOS_SEG_END = 0xC000; // Important: DOS kernel uses this to determine where to place the private area!
        VGA_BIOS_Size = 0;
        return;
    }

    // log
    LOG(LOG_MISC,LOG_DEBUG)("Init_VGABIOS: Initializing VGA BIOS and parsing its settings");

    // mem init must have already happened.
    // We can remove this once the device callout system is in place.
    assert(MemBase != NULL);

    VGA_BIOS_use_rom = video_section->Get_bool("vga bios use rom image");
    VGA_BIOS_rom = video_section->Get_string("vga bios rom image");

    if (VGA_BIOS_rom.empty()) {
        if (IS_VGA_ARCH) {
            if (svgaCard == SVGA_TsengET4K) {
                VGA_BIOS_rom = "et4000.bin"; // Ref: PCem ROMs collection
            }
            else if (svgaCard == SVGA_S3Trio) {
                VGA_BIOS_rom = "TRIO64 (Ver. 1.5-07) [VGA] (S3 Incorporated).bin"; // Ref: PCem ROMs collection
            }
        }
    }

    if (!VGA_BIOS_rom.empty() && VGA_BIOS_use_rom) {
        VGA_BIOS_use_rom = false;
        void ResolvePath(std::string& in);
        ResolvePath(VGA_BIOS_rom);
        std::string path = "", GetDOSBoxXPath(bool withexe=false);
        rom_fp = fopen(VGA_BIOS_rom.c_str(),"rb");
        if (rom_fp == NULL) {
            path = GetDOSBoxXPath();
            if (path.size()) {
                path += VGA_BIOS_rom;
                rom_fp = fopen(path.c_str(),"rb");
            }
        }
        if (rom_fp == NULL) {
            path = "";
            path = Cross::GetPlatformResDir();
            path += VGA_BIOS_rom;
            rom_fp = fopen(path.c_str(),"rb");
        }
        if (rom_fp == NULL) {
            path = "";
            path = Cross::GetPlatformConfigDir();
            path += VGA_BIOS_rom;
            rom_fp = fopen(path.c_str(),"rb");
        }
        if (rom_fp != NULL) {
            fseek(rom_fp,0,SEEK_END);
            long sz = ftell(rom_fp);
            if (sz >= 1024 && sz <= 65536) {
                LOG_MSG("Using VGA BIOS image '%s', %ld bytes\n",VGA_BIOS_rom.c_str(),sz);
                VGA_BIOS_use_rom = true;
                rom_sz = sz;
            }
        }
    }
    else {
        VGA_BIOS_use_rom = false;
    }

    {
        const char *s = video_section->Get_string("int 10h use video parameter table");

        if (!strcmp(s,"true") || !strcmp(s,"1")) {
            int10_vp_use_always = true;
            int10_vp_use_auto = false;
        }
        else if (!strcmp(s,"false") || !strcmp(s,"0")) {
            int10_vp_use_always = false;
            int10_vp_use_auto = false;
        }
        else {
            int10_vp_use_always = false;
            int10_vp_use_auto = true;
        }
    }

    int size_override = video_section->Get_int("vga bios size override");
    if (size_override > 0) VGA_BIOS_Size_override = ((Bitu)size_override+0x7FFU)&(~0xFFFU);

    VGA_BIOS_dont_duplicate_CGA_first_half = video_section->Get_bool("video bios dont duplicate cga first half rom font");
    VIDEO_BIOS_always_carry_14_high_font = video_section->Get_bool("video bios always offer 14-pixel high rom font");
    VIDEO_BIOS_always_carry_16_high_font = video_section->Get_bool("video bios always offer 16-pixel high rom font");
    VIDEO_BIOS_enable_CGA_8x8_second_half = video_section->Get_bool("video bios enable cga second half rom font");
    /* NTS: mainline compatible mapping demands the 8x8 CGA font */
    rom_bios_8x8_cga_font = video_section->Get_bool("rom bios 8x8 CGA font");
    rom_bios_vptable_enable = video_section->Get_bool("rom bios video parameter table");

    /* sanity check */
    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 */
        VGA_BIOS_dont_duplicate_CGA_first_half = false;

    if (size_override <= -512 && size_override >= -65536) // Force size override by a leading minus sign (-)
        VGA_BIOS_Size = -size_override;
    else if (VGA_BIOS_Size_override >= 512 && VGA_BIOS_Size_override <= 65536)
        VGA_BIOS_Size = (VGA_BIOS_Size_override + 0x7FFU) & (~0xFFFU);
    else if (rom_sz != 0) {
        VGA_BIOS_Size = rom_sz;
    }
    else if (IS_VGA_ARCH) {
        if (svgaCard == SVGA_S3Trio)
            VGA_BIOS_Size = 0x4000;
        else
            VGA_BIOS_Size = 0x4000; // FIXME: Why does 0x3800 cause Windows 3.0 386 enhanced mode to hang?
    }
    else if (machine == MCH_EGA) {
        if (jp_ega)
            VGA_BIOS_Size = 0x3500;
        else if (VIDEO_BIOS_always_carry_16_high_font)
            VGA_BIOS_Size = 0x3000;
        else
            VGA_BIOS_Size = 0x2000;
    }
    else {
        if (VIDEO_BIOS_always_carry_16_high_font && VIDEO_BIOS_always_carry_14_high_font)
            VGA_BIOS_Size = 0x3000;
        else if (VIDEO_BIOS_always_carry_16_high_font || VIDEO_BIOS_always_carry_14_high_font)
            VGA_BIOS_Size = 0x2000;
        else
            VGA_BIOS_Size = 0;
    }
    VGA_BIOS_SEG = 0xC000;
    VGA_BIOS_SEG_END = (VGA_BIOS_SEG + (VGA_BIOS_Size >> 4));

    if (rom_fp != NULL && rom_sz != 0) {
        fseek(rom_fp,0,SEEK_SET);
        fread((char*)MemBase+0xC0000,rom_sz,1,rom_fp);
    }
    else {
        /* 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?) */
        if (VGA_BIOS_Size != 0)
            memset((char*)MemBase+0xC0000,0x00,VGA_BIOS_Size);
    }

    if (rom_fp) fclose(rom_fp);
}

void SetCyclesCount_mapper_shortcut_RunInternal(void) {
    GUI_Shortcut(16);
}

void SetCyclesCount_mapper_shortcut_RunEvent(Bitu /*val*/) {
    KEYBOARD_ClrBuffer();   //Clear buffer
    GFX_LosingFocus();      //Release any keys pressed (buffer gets filled again).
    SetCyclesCount_mapper_shortcut_RunInternal();
}

void SetCyclesCount_mapper_shortcut(bool pressed) {
    if (!pressed) return;
    PIC_AddEvent(SetCyclesCount_mapper_shortcut_RunEvent, 0.0001f); //In case mapper deletes the key object that ran it
}

void SetIME() {
#if (defined(WIN32) && !defined(HX_DOS) || defined(LINUX) && C_X11 || defined(MACOSX)) && !defined(C_SDL2) && defined(SDL_DOSBOX_X_SPECIAL)
    if (enableime && !control->opt_silent) {
        dos.im_enable_flag = true;
        SDL_SetIMValues(SDL_IM_ENABLE, 1, NULL);
#if defined(WIN32)
        SDL_EnableUNICODE(1);
#endif
    } else if (!control->opt_silent) {
        dos.im_enable_flag = false;
        SDL_SetIMValues(SDL_IM_ENABLE, 0, NULL);
    }
#elif (defined(WIN32) && !defined(HX_DOS) || defined(LINUX) && C_X11 || defined(MACOSX)) && defined(C_SDL2)
    if (enableime && !control->opt_silent) {
#if !defined(SDL_DOSBOX_X_IME)
        LOG_MSG("Note: The linked SDL 2.x library is not compiled with enhanced IME functions.");
#endif
        dos.im_enable_flag = true;
        SDL_StartTextInput();
#if defined(LINUX)
        SDL_SetHint(SDL_HINT_IME_INTERNAL_EDITING, "1");
#endif
    } else if (!control->opt_silent) {
        dos.im_enable_flag = false;
        SDL_StopTextInput();
    }
#endif
}

unsigned int BeepDuration() {
	Section_prop *section = static_cast<Section_prop *>(control->GetSection("dosbox"));
	unsigned int d = section->Get_int("beep duration");

	if (d == 0) {//default
		if (IS_EGAVGA_ARCH || machine == MCH_TANDY || machine == MCH_AMSTRAD || machine == MCH_MCGA) {
			d = 333; /* DOSBox SVN default */
		}
		else if (IS_PC98_ARCH) {
			d = 300; /* FIXME: Guess */
		}
		else { // MDA, CGA, Hercules, PCjr, anything IBM
			d = 500; /* IBM standard in the 1980s, see BIOS listings to see what I mean */
		}
	}

	return d;
}

void DOSBOX_RealInit() {
    DOSBoxMenu::item *item;

    LOG(LOG_MISC,LOG_DEBUG)("DOSBOX-X RealInit: loading settings and initializing");

    {
        MAPPER_AddHandler(DOSBOX_UnlockSpeed, MK_grave, MMODHOST, "speedlock", "Turbo (fast-forward): burst", &item);
        item->set_description("Burst turbo (fast-forward) emulation speed, to allow running faster than realtime");
        item->set_text("Turbo (fast-forward): burst mode");
    }
    {
        MAPPER_AddHandler(DOSBOX_UnlockSpeed2, MK_rightarrow, MMODHOST, "speedlock2", "Turbo (fast-forward): toggle", &item);
        item->set_description("Toggle turbo (fast-forward) emulation speed, to allow running faster than realtime");
        item->set_text("Turbo (fast-forward)");
    }
    {
        MAPPER_AddHandler(DOSBOX_NormalSpeed, MK_leftarrow, MMODHOST, "speednorm","Normal speed", &item);
        item->set_description("Restore normal emulation speed");
        item->set_text("Normal speed");
    }
    {
        MAPPER_AddHandler(DOSBOX_SpeedUp, MK_rbracket, MMODHOST, "speedup","Speed up", &item);
        item->set_text("Speed up");
    }
    {
        MAPPER_AddHandler(DOSBOX_SlowDown, MK_lbracket, MMODHOST,"slowdown","Slow down", &item);
        item->set_text("Slow down");
    }
	{
		MAPPER_AddHandler(&SetCyclesCount_mapper_shortcut, MK_nothing, 0, "editcycles", "Edit cycles", &item);
		item->set_text("Edit cycles");
	}

    AddSaveStateMapper(); //add support for loading/saving game states

    Section_prop *section = static_cast<Section_prop *>(control->GetSection("dosbox"));
    assert(section != NULL);

    // TODO: allow change at any time. in fact if it were possible for DOSBox-X configuration
    //       schema code to attach event callbacks when a setting changes, we would set one
    //       on the title= setting now to auto-update the titlebar when this changes.
    dosbox_title = section->Get_string("title");

    // TODO: these should be parsed by DOS kernel at startup
    dosbox_shell_env_size = (unsigned int)section->Get_int("shell environment size");

    // TODO: a bit of a challenge: if we put it in the ROM area as mainline DOSBox does then the init
    //       needs to read this from the BIOS where it can map the memory appropriately. if the allocation
    //       is dynamic and the private area is down at the base of memory like real DOS, then the BIOS
    //       should ignore it and the DOS kernel should parse it. If we're going to put it into upper
    //       areas as well, then we should also consider making it look like adapter ROM at startup
    //       so it can be enumerated properly by DOS programs scanning the ROM area.
    /* private area size param in bytes. round up to nearest paragraph */
    DOS_PRIVATE_SEGMENT_Size = (Bitu)((section->Get_int("private area size") + 8) / 16);

    // TODO: these should be parsed by BIOS startup
    allow_more_than_640kb = section->Get_bool("allow more than 640kb base memory");

    sync_time = section->Get_bool("synchronize time");

    // TODO: should be parsed by motherboard emulation
    allow_port_92_reset = section->Get_bool("allow port 92 reset");

    force_nocachedir = section->Get_bool("nocachedir");
    std::string freesizestr = section->Get_string("freesizecap");
    if (freesizestr == "fixed" || freesizestr == "false" || freesizestr == "0") freesizecap = 0;
    else if (freesizestr == "relative" || freesizestr == "2") freesizecap = 2;
    else freesizecap = 1;
    convertimg = section->Get_bool("convertdrivefat");
    wpcolon = section->Get_bool("leading colon write protect image");
    lockmount = section->Get_bool("locking disk image mount");

    // CGA/EGA/VGA-specific
    extern unsigned char vga_p3da_undefined_bits;
    vga_p3da_undefined_bits = (unsigned char)static_cast<Section_prop *>(control->GetSection("video"))->Get_hex("vga 3da undefined bits");

    // TODO: should be parsed by motherboard emulation or lower level equiv..?
    std::string cmd_machine;
    if (control->opt_machine != ""){
        //update value in config (else no matching against suggested values
        section->HandleInputline(std::string("machine=") + control->opt_machine);
    }

    // NTS: svga_s3 means S3 Trio64 emulation to match general DOSBox SVN emulation behavior.

    // TODO: should be parsed by...? perhaps at some point we support machine= for backwards compat
    //       but translate it into two separate params that specify what machine vs what video hardware.
    //       or better yet as envisioned, a possible dosbox-x.conf schema that allows a machine with no
    //       base video of its own, and then to specify an ISA or PCI card attached to the bus that
    //       provides video.
    std::string mtype(section->Get_string("machine"));
    hercCard = HERC_GraphicsCard;
    atiCard = ATI_VGAWonder;
    svgaCard = SVGA_None;
    s3Card = S3_Generic;
    machine = MCH_VGA;
    jp_ega = false;
    int10.vesa_vbe3 = false;
    int10.vesa_nolfb = false;
    int10.vesa_oldvbe = false;
    int10.vesa_oldvbe10 = false;
    if      (mtype == "cga")           { machine = MCH_CGA; mono_cga = false; }
    else if (mtype == "cga_mono")      { machine = MCH_CGA; mono_cga = true; }
    else if (mtype == "cga_rgb")       { machine = MCH_CGA; mono_cga = false; cga_comp = 2; }
    else if (mtype == "cga_composite") { machine = MCH_CGA; mono_cga = false; cga_comp = 1; new_cga = false; }
    else if (mtype == "cga_composite2"){ machine = MCH_CGA; mono_cga = false; cga_comp = 1; new_cga = true; }
    else if (mtype == "mcga")          { machine = MCH_MCGA; }
    else if (mtype == "tandy")         { machine = MCH_TANDY; }
    else if (mtype == "pcjr")          { machine = MCH_PCJR; }
    else if (mtype == "pcjr_composite") { machine = MCH_PCJR; cga_comp = 1; new_cga = false; }
    else if (mtype == "pcjr_composite2"){ machine = MCH_PCJR; cga_comp = 1; new_cga = true; }
    else if (mtype == "hercules")      { machine = MCH_HERC; hercCard = HERC_GraphicsCard; }
    else if (mtype == "hercules_plus") { machine = MCH_HERC; hercCard = HERC_GraphicsCardPlus; }
    else if (mtype == "hercules_incolor") { machine = MCH_HERC; hercCard = HERC_InColor; }
    else if (mtype == "hercules_color") { machine = MCH_CGA; mono_cga = false; new_cga = true; } /* guess */
    else if (mtype == "svga_ati_egavgawonder") { svgaCard = SVGA_ATI; atiCard = ATI_EGAVGAWonder; }
    else if (mtype == "svga_ati_vgawonder") { svgaCard = SVGA_ATI; atiCard = ATI_VGAWonder; }
    else if (mtype == "svga_ati_vgawonderplus") { svgaCard = SVGA_ATI; atiCard = ATI_VGAWonderPlus; }
    else if (mtype == "svga_ati_vgawonderxl") { svgaCard = SVGA_ATI; atiCard = ATI_VGAWonderXL; }
    else if (mtype == "svga_ati_vgawonderxl24") { svgaCard = SVGA_ATI; atiCard = ATI_VGAWonderXL24; }
    else if (mtype == "svga_ati_mach8") { svgaCard = SVGA_ATI; atiCard = ATI_Mach8; }
    else if (mtype == "svga_ati_mach32") { svgaCard = SVGA_ATI; atiCard = ATI_Mach32; }
    else if (mtype == "svga_ati_mach64") { svgaCard = SVGA_ATI; atiCard = ATI_Mach64; }
    else if (mtype == "mda")           { machine = MCH_MDA; }
    else if (mtype == "ega")           { machine = MCH_EGA; ega200 = false; }
    else if (mtype == "ega200")        { machine = MCH_EGA; ega200 = true; }
    else if (mtype == "jega")          { machine = MCH_EGA; jp_ega = true;}
    else if (mtype == "svga_s3")       { svgaCard = SVGA_S3Trio; s3Card = S3_Trio64; } /* DOSBox SVN behavior */
    else if (mtype == "svga_s386c928") { svgaCard = SVGA_S3Trio; s3Card = S3_86C928; }
    else if (mtype == "svga_s3vision864"){svgaCard= SVGA_S3Trio; s3Card = S3_Vision864; }
    else if (mtype == "svga_s3vision868"){svgaCard= SVGA_S3Trio; s3Card = S3_Vision868; }
    else if (mtype == "svga_s3vision964"){svgaCard= SVGA_S3Trio; s3Card = S3_Vision964; }
    else if (mtype == "svga_s3vision968"){svgaCard= SVGA_S3Trio; s3Card = S3_Vision968; }
    else if (mtype == "svga_s3trio32") { svgaCard = SVGA_S3Trio; s3Card = S3_Trio32; }
    else if (mtype == "svga_s3trio64") { svgaCard = SVGA_S3Trio; s3Card = S3_Trio64; }
    else if (mtype == "svga_s3trio64v+"){svgaCard = SVGA_S3Trio; s3Card = S3_Trio64V; }
    else if (mtype == "svga_s3virge")  { svgaCard = SVGA_S3Trio; s3Card = S3_ViRGE; }
    else if (mtype == "svga_s3virgevx"){ svgaCard = SVGA_S3Trio; s3Card = S3_ViRGEVX; }
    else if (mtype == "vesa_nolfb")    { svgaCard = SVGA_S3Trio; s3Card = S3_Trio32; int10.vesa_nolfb = true;}
    else if (mtype == "vesa_oldvbe")   { svgaCard = SVGA_S3Trio; s3Card = S3_Trio32; int10.vesa_oldvbe = true;}
    else if (mtype == "vesa_oldvbe10") { svgaCard = SVGA_S3Trio; s3Card = S3_Trio32; int10.vesa_oldvbe = true; int10.vesa_oldvbe10 = true;}
    else if (mtype == "vesa_vbe3")     { svgaCard = SVGA_S3Trio; s3Card = S3_Trio32; int10.vesa_vbe3 = true;}
    else if (mtype == "svga_et4000")   { svgaCard = SVGA_TsengET4K; }
    else if (mtype == "svga_et3000")   { svgaCard = SVGA_TsengET3K; }
    else if (mtype == "svga_paradise") { svgaCard = SVGA_ParadisePVGA1A; }
    else if (mtype == "vgaonly")       { svgaCard = SVGA_None; }
    else if (mtype == "amstrad")       { machine = MCH_AMSTRAD; }
    else if (mtype == "pc98")          { machine = MCH_PC98; }
    else if (mtype == "pc9801")        { machine = MCH_PC98; } /* Future differentiation */
    else if (mtype == "pc9821")        { machine = MCH_PC98; } /* Future differentiation */

    else if (mtype == "fm_towns")      { machine = MCH_VGA; want_fm_towns = true; /*machine = MCH_FM_TOWNS;*/ }
    else if (mtype == "svga_dosbox")   { machine = MCH_VGA; svgaCard = SVGA_DOSBoxIG; int10.vesa_vbe3 = true; } /* special emulator accelerator graphics adapter */
    else if (mtype == "svga_dosbox_vbe2") { machine = MCH_VGA; svgaCard = SVGA_DOSBoxIG; } /* special emulator accelerator graphics adapter */

    else E_Exit("DOSBOX-X:Unknown machine type %s",mtype.c_str());

#if !defined(OSFREE)
    dos.set_jdosv_enabled = dos.set_kdosv_enabled = dos.set_pdosv_enabled = dos.set_tdosv_enabled = dos.set_j3100_enabled = j3100_start = false;
#endif
#if !defined(OSFREE)
    Section_prop *dosv_section = static_cast<Section_prop *>(control->GetSection("dosv"));
    const char *dosvstr = dosv_section->Get_string("dosv");
    del_flag = dosv_section->Get_bool("del");
    if (!strcasecmp(dosvstr, "jp")) {
        dos.set_jdosv_enabled = true;
        std::string j3100mode = dosv_section->Get_string("j3100");
        std::string j3100type = dosv_section->Get_string("j3100type");
        if(j3100mode != "off" && j3100mode != "0") {
            dos.set_j3100_enabled = true;
            if (j3100mode != "manual") j3100_start = true;
            J3_SetType(j3100type, dosv_section->Get_string("j3100backcolor"), dosv_section->Get_string("j3100textcolor"));
        }
    }
    if (!strcasecmp(dosvstr, "ko")) dos.set_kdosv_enabled = true;
    if (!strcasecmp(dosvstr, "chs")||!strcasecmp(dosvstr, "cn")) dos.set_pdosv_enabled = true;
    if (!strcasecmp(dosvstr, "cht")||!strcasecmp(dosvstr, "tw")) dos.set_tdosv_enabled = true;
#endif
#if !defined(OSFREE)
    if (machine != MCH_VGA || want_fm_towns) {
        LOG_MSG("WARNING: DOS/V is only supported for VGA video cards.");
        dos.set_jdosv_enabled = dos.set_kdosv_enabled = dos.set_pdosv_enabled = dos.set_tdosv_enabled = false;
    }
#endif
#if !defined(OSFREE)
    int cp = dos.loaded_codepage;
    if (!cp) InitCodePage();
#if defined(USE_TTF)
    if (IS_PC98_ARCH) ttf_dosv = false;
#endif
    if (IS_JEGA_ARCH || IS_DOSV || isDBCSCP()) {
        JFONT_Init();  // Load DBCS fonts for JEGA etc
#if defined(USE_TTF)
        if (IS_DOSV || ttf_dosv) DOSV_SetConfig(dosv_section);
#else
        if (IS_DOSV) DOSV_SetConfig(dosv_section);
#endif
    }
#endif
    Section_prop *ttf_section = static_cast<Section_prop *>(control->GetSection("ttf"));
    gbk = ttf_section->Get_bool("gbk");
    chinasea = ttf_section->Get_bool("chinasea");
    uao = ttf_section->Get_bool("uao");
    if (IS_PDOSV || IS_TDOSV || dos.loaded_codepage == 936 || dos.loaded_codepage == 950 || dos.loaded_codepage == 951 || control->opt_langcp) {
        makestdcp950table();
        makeseacp951table();
    }
#if !defined(OSFREE)
    dos.loaded_codepage = cp;
#endif
    if (!tonoime) SetIME();
#if defined(USE_TTF)
    if (IS_PC98_ARCH) ttf.cols = 80; // The number of columns on the screen is apparently fixed to 80 in PC-98 mode at this time
#endif

    // TODO: should be parsed by motherboard emulation
    // FIXME: This re-uses the existing ISA bus delay code for C-BUS in PC-98 mode
    std::string isabclk;

    if (IS_PC98_ARCH)
        isabclk = section->Get_string("cbus bus clock");
    else
        isabclk = section->Get_string("isa bus clock");

    if (isabclk == "std10")
        clockdom_ISA_BCLK.set_frequency(PIT_TICK_RATE_PC98_10MHZ * 4ul,1);          /* 10Mhz (PC-98) */
    else if (isabclk == "std8.3")
        clockdom_ISA_BCLK.set_frequency(25000000,3);    /* 25MHz / 3 = 8.333MHz, early 386 systems did this, became an industry standard "norm" afterwards */
    else if (isabclk == "std8") {
        if (IS_PC98_ARCH)
            clockdom_ISA_BCLK.set_frequency(PIT_TICK_RATE_PC98_8MHZ * 4ul,1);       /* 8Mhz (PC-98) */
        else
            clockdom_ISA_BCLK.set_frequency(8000000,1);                             /* 8Mhz (IBM PC) */
    }
    else if (isabclk == "std6")
        clockdom_ISA_BCLK.set_frequency(6000000,1);     /* 6MHz */
    else if (isabclk == "std5")
        clockdom_ISA_BCLK.set_frequency(PIT_TICK_RATE_PC98_10MHZ * 2ul,1);          /* 5Mhz (PC-98) */
    else if (isabclk == "std4.77")
        clockdom_ISA_BCLK.set_frequency(clockdom_ISA_OSC.freq,clockdom_ISA_OSC.freq_div*3LL); /* 14.31818MHz / 3 = 4.77MHz */
    else if (isabclk == "oc10")
        clockdom_ISA_BCLK.set_frequency(10000000,1);    /* 10MHz */
    else if (isabclk == "oc12")
        clockdom_ISA_BCLK.set_frequency(12000000,1);    /* 12MHz */
    else if (isabclk == "oc15")
        clockdom_ISA_BCLK.set_frequency(15000000,1);    /* 15MHz */
    else if (isabclk == "oc16")
        clockdom_ISA_BCLK.set_frequency(16000000,1);    /* 16MHz */
    else
        parse_busclk_setting_str(&clockdom_ISA_BCLK,isabclk.c_str());

    std::string pcibclk = section->Get_string("pci bus clock");
    if (pcibclk == "std33.3")
        clockdom_PCI_BCLK.set_frequency(100000000,3);   /* 100MHz / 3 = 33.333MHz, VERY common PCI speed */
    else if (pcibclk == "std30")
        clockdom_PCI_BCLK.set_frequency(30000000,1);    /* 30Mhz */
    else if (pcibclk == "std25")
        clockdom_PCI_BCLK.set_frequency(25000000,1);    /* 25MHz */
    else
        parse_busclk_setting_str(&clockdom_PCI_BCLK,pcibclk.c_str());

    LOG_MSG("%s BCLK: %.3fHz (%llu/%llu)",
        IS_PC98_ARCH ? "C-BUS" : "ISA",
        (double)clockdom_ISA_BCLK.freq / clockdom_ISA_BCLK.freq_div,
        clockdom_ISA_BCLK.freq,
        clockdom_ISA_BCLK.freq_div);

    clockdom_ISA_OSC.set_name("ISA OSC");
    clockdom_ISA_BCLK.set_name("ISA BCLK");
    clockdom_PCI_BCLK.set_name("PCI BCLK");

    // FM TOWNS is stub so far. According to sources like Wikipedia though,
    // it boots from DOS in ROM that then loads bootcode from CD-ROM. So
    // for now, allow booting into FM TOWNS mode with a warning. The
    // switch to FM Towns will begin in the BOOT command with a flag to
    // indicate the ISO is intended for FM TOwns.
    if (IS_FM_TOWNS || want_fm_towns) LOG_MSG("FM Towns emulation not yet implemented. It's currently just a stub for future development.");
}

const char *sbGetSectionName(const size_t ci);

void DOSBOX_SetupConfigSections(void) {
    Prop_int* Pint;
    Prop_hex* Phex;
    Prop_bool* Pbool;
    Prop_string* Pstring;
    Prop_double* Pdouble;
    Prop_multival* Pmulti;
    Section_prop * secprop;
    Prop_multival_remain* Pmulti_remain;

    // Some frequently used option sets
    const char* vsyncrate[] = { "%u", nullptr };
    const char* force[] = { "", "forced", "prompt", nullptr };
    const char* cyclest[] = { "auto","fixed","max","%u", nullptr };
    const char* mputypes[] = { "intelligent", "uart", "none", nullptr };
    const char* vsyncmode[] = { "off", "on" ,"force", "host", nullptr };
    const char* captureformats[] = { "default", "avi-zmbv", "mpegts-h264", nullptr };
    const char* blocksizes[] = {"1024", "2048", "4096", "8192", "512", "256", nullptr };
    const char* capturechromaformats[] = { "auto", "4:4:4", "4:2:2", "4:2:0", nullptr };
    const char* controllertypes[] = { "auto", "at", "xt", "pcjr", "pc98", nullptr }; // Future work: Tandy(?) and USB
    const char* auxdevices[] = {"none","2button","3button","intellimouse","intellimouse45",nullptr};
    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", "pentium_ii", "pentium_iii", "experimental", nullptr };
    const char* rates[] = {  "49716", "48000", "44100", "32000","22050", "16000", "11025", "8000", nullptr };
    const char* pcrates[] = {  "65536", "49716", "48000", "44100", "32000","22050", "16000", "11025", "8000", nullptr };
#if C_FLUIDSYNTH || defined(WIN32) && !defined(HX_DOS)
    const char* devices[] = { "default", "win32", "alsa", "oss", "coreaudio", "coremidi", "mt32", "synth", "fluidsynth", "timidity", "none", nullptr };
#else
    const char* devices[] = { "default", "win32", "alsa", "oss", "coreaudio", "coremidi", "mt32", "timidity", "none", nullptr }; // FIXME: add some way to offer the actually available choices.
#endif
    const char* apmpowerbuttonevent[] = { "suspend", "standby", nullptr };
    const char* apmbiosversions[] = { "auto", "1.0", "1.1", "1.2", nullptr };
    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", nullptr };
    const char *mt32models[] = {"cm32l", "mt32", "auto", nullptr};
    const char *mt32partials[] = {"8", "9", "32", "255", "256", nullptr};
    const char *mt32DACModes[] = {"0", "1", "2", "3", nullptr};
    const char *mt32reverbModes[] = {"0", "1", "2", "3", "auto", nullptr};
    const char *mt32reverbTimes[] = {"0", "1", "2", "3", "4", "5", "6", "7", nullptr};
    const char *mt32reverbLevels[] = {"0", "1", "2", "3", "4", "5", "6", "7", nullptr};
    const char* gustypes[] = { "classic", "classic37", "max", "interwave", nullptr };
    const char* sbtypes[] = { "sb1", "sb1.0", "sb1.5", "sb2", "sb2.0", "sb2.01", "sbpro1", "sbpro2", "sb16", "sb16vibra", "gb", "ess688", "ess1688", "reveal_sc400", "none", nullptr };
    const char* cms_settings[] = { "on", "off", "auto", nullptr };
    const char* oplmodes[] = { "auto", "opl2", "dualopl2", "opl3", "opl3gold", "none", "hardware", "hardwaregb", "esfm", nullptr };
    const char* serials[] = { "dummy", "disabled", "modem", "nullmodem", "serialmouse", "directserial", "log", "file", nullptr };
    const char* acpi_rsd_ptr_settings[] = { "auto", "bios", "ebda", nullptr };
    const char* cpm_compat_modes[] = { "auto", "off", "msdos2", "msdos5", "direct", nullptr };
    const char* dosv_settings[] = { "off", "jp", "ko", "chs", "cht", "cn", "tw", nullptr };
    const char* j3100_settings[] = { "off", "on", "auto", "manual", "0", "1", "2", nullptr };
    const char* j3100_types[] = { "default", "gt", "sgt", "gx", "gl", "sl", "sgx", "ss", "gs", "sx", "sxb", "sxw", "sxp", "ez", "zs", "zx", nullptr };
    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", nullptr };
    const char* guspantables[] = { "old", "accurate", "default", nullptr };
    const char *sidbaseno[] = { "240", "220", "260", "280", "2a0", "2c0", "2e0", "300", nullptr };
    const char* joytypes[] = { "auto", "2axis", "4axis", "4axis_2", "fcs", "ch", "none", nullptr};
//    const char* joydeadzone[] = { "0.26", nullptr };
//    const char* joyresponse[] = { "1.0", nullptr };
    const char* iosgus[] = { "240", "220", "260", "280", "2a0", "2c0", "2e0", "300", "210", "230", "250", nullptr };
    const char* mpubases[] = {
        "0",                                                                                    /* Auto */
        "300", "310", "320", "330", "332", "334", "336", "340", "360",                          /* IBM PC */
        "c0d0","c8d0","d0d0","d8d0","e0d0","e8d0","f0d0","f8d0",                                /* NEC PC-98 MPU98 */
        "80d2","80d4","80d6","80d8","80da","80dc","80de",                                       /* NEC PC-98 SB16 */
        nullptr };
    const char* ios[] = {
        "220", "240", "260", "280", "2a0", "2c0", "2e0",            /* IBM PC      (base+port i.e. 220h base, 22Ch is DSP) */
        "d2",  "d4",  "d6",  "d8",  "da",  "dc",  "de",             /* NEC PC-98   (base+(port << 8) i.e. 00D2h base, 2CD2h is DSP) */
        nullptr };
    const char* ems_settings[] = { "true", "emsboard", "emm386", "false", "1", "0", nullptr };
    const char* lfn_settings[] = { "true", "false", "1", "0", "auto", "autostart", nullptr };
    const char* fat32setver_settings[] = { "ask", "auto", "manual", nullptr };
    const char* quit_settings[] = { "true", "false", "1", "0", "auto", "autofile", nullptr };
    const char* autofix_settings[] = { "true", "false", "1", "0", "both", "a20fix", "loadfix", "none", nullptr };
    const char* color_themes[] = { "default", "black", "red", "green", "yellow", "blue", "magenta", "cyan", "white", nullptr };
    const char* color_themes_config[] = {
        "Windows Default", "Arizona", "Black Leather Jacket", "Bordeaux", "Cinnamon", "Designer", "Emerald City",
        "Fluorescent","HotDog Stand", "LCD Default Screen Settings", "LCD Reversed - Dark", "LCD Reversed - Light",
        "Mahogany", "Monochrome", "Ocean", "Pastel", "Patchwork", "Plasma Power Saver", "Rugby", "The Blues",
        "Tweed", "Valentine", "Wingtips", nullptr };
    const char* irqsgus[] = { "5", "3", "7", "9", "10", "11", "12", nullptr };
    const char* irqssb[] = { "7", "5", "3", "9", "10", "11", "12", "0", "-1", nullptr };
    const char* dmasgus[] = { "3", "0", "1", "5", "6", "7", nullptr };
    const char* dmassb[] = { "1", "5", "0", "3", "6", "7", "-1", nullptr };
    const char* oplemus[] = { "default", "compat", "fast", "nuked", "mame", "opl2board", "opl3duoboard", "retrowave_opl3", "esfmu", "cqm", nullptr};
    const char *qualityno[] = { "0", "1", "2", "3", nullptr };
    const char* tandys[] = { "auto", "on", "off", nullptr };
    const char* ps1opt[] = { "on", "off", nullptr };
    const char* numopt[] = { "on", "off", "", nullptr };
    const char* freesizeopt[] = {"true", "false", "fixed", "relative", "cap", "2", "1", "0", nullptr };
    const char* truefalseautoopt[] = { "true", "false", "1", "0", "auto", nullptr };
    const char* truefalsequietopts[] = { "true", "false", "1", "0", "quiet", nullptr };
    const char* pc98fmboards[] = { "auto", "off", "false", "board14", "board26k", "board86", "board86c", nullptr };
    const char* pc98videomodeopt[] = { "", "24khz", "31khz", "15khz", nullptr };
    const char* aspectmodes[] = { "false", "true", "0", "1", "yes", "no", "nearest", "bilinear", nullptr };
    const char *vga_ac_mapping_settings[] = { "", "auto", "4x4", "4low", "first16", nullptr };
    const char* fpu_settings[] = { "true", "false", "1", "0", "auto", "8087", "287", "387", nullptr };
    const char* sb_recording_sources[] = { "silence", "hiss", "1khz tone", "microphone", nullptr };
    const char* int10usevp[] = { "auto", "true", "false", "1", "0", nullptr };

    const char* hostkeys[] = {
        "ctrlalt", "ctrlshift", "altshift", "mapper", nullptr };

    const char* sendkeys[] = {
        "winlogo", "winmenu", "alttab", "ctrlesc", "ctrlbreak", "ctrlaltdel", nullptr };

    const char* irqhandler[] = {
        "", "simple", "cooperative_2nd", nullptr };

    const char* pseopts[] = {
        "auto", "none", "pse", "pse36", "pse40", "true", "false", nullptr };

    const char* exepackopts[] = {
        "none", "a20off", "unpack", nullptr };

    /* Setup all the different modules making up DOSBox-X */
    const char* machines[] = {
        "mda",
        "cga", "cga_mono", "cga_rgb", "cga_composite", "cga_composite2",
        "hercules","hercules_plus","hercules_incolor", "hercules_color",
        "tandy",
        "pcjr", "pcjr_composite", "pcjr_composite2",
        "amstrad",
        "ega",
        "ega200",
        "jega",
        "mcga",
        "vgaonly",
       	"svga_s3",
        "svga_s386c928",
        "svga_s3vision864", "svga_s3vision868",
        "svga_s3vision964", "svga_s3vision968",
        "svga_s3trio32",
        "svga_s3trio64", "svga_s3trio64v+",
        "svga_s3virge", "svga_s3virgevx",
        "svga_et3000", "svga_et4000",
        "svga_paradise",
        "vesa_nolfb", "vesa_oldvbe", "vesa_oldvbe10", "vesa_vbe3",
        "pc98", "pc9801", "pc9821",
	"svga_ati_egavgawonder",
	"svga_ati_vgawonder",
	"svga_ati_vgawonderplus",
	"svga_ati_vgawonderxl",
	"svga_ati_vgawonderxl24",
	"svga_ati_mach8",
	"svga_ati_mach32",
	"svga_ati_mach64",
	"svga_dosbox",
	"svga_dosbox_vbe2",
	"fm_towns", // STUB
        nullptr };

    const char* prevent_capture_opts[] = {
        "", "none", "blank", "invisible",
        nullptr };

    const char* backendopts[] = {
        "pcap", "slirp", "nothing", "auto", "none",
        nullptr };

    const char* workdiropts[] = {
        "autoprompt", "config", "custom", "default", "force", "noprompt", "program", "prompt", "userconfig",
        nullptr };

    const char* resolveopts[] = {
        "true", "false", "dosvar", "tilde", "1", "0",
        nullptr };

    /* Do NOT ifdef these off, even if compiled for a platform that does not support the output mode,
     * so that when the reference config files are made they list all settings. The output code is
     * expected to pick a default or best equivalent when given a setting not supported for the platform. */
    const char* switchoutputs[] = {
        "auto", "surface",
        "opengl", "openglnb", "openglhq", "openglpp",
        "direct3d",
        "direct3d11",
        "metal",
        nullptr };

    const char* scalers[] = {
        "none", "normal2x", "normal3x", "normal4x", "normal5x",
#if RENDER_USE_ADVANCED_SCALERS>2
        "advmame2x", "advmame3x", "advinterp2x", "advinterp3x", "hq2x", "hq3x", "2xsai", "super2xsai", "supereagle",
#endif
#if RENDER_USE_ADVANCED_SCALERS>0
        "tv2x", "tv3x", "rgb2x", "rgb3x", "scan2x", "scan3x", "gray", "gray2x",
#endif
        "hardware_none", "hardware2x", "hardware3x", "hardware4x", "hardware5x",
#if C_XBRZ
        "xbrz", "xbrz_bilinear",
#endif
        nullptr };

    const char* cores[] = { "auto",
#if (C_DYNAMIC_X86) || (C_DYNREC)
        "dynamic",
#endif
#if (C_DYNAMIC_X86)
        "dynamic_x86", "dynamic_nodhfpu",
#endif
#if (C_DYNREC)
        "dynamic_rec",
#endif
        "normal", "full", "simple", nullptr };

    const char* voodoo_settings[] = {
        "false",
        "software",
#if C_OPENGL
        "opengl",
#endif
        "auto",
        nullptr
    };

#if defined(__SSE__) && !(defined(_M_AMD64) || defined(__e2k__)) && !defined(EMSCRIPTEN)
    CheckX86ExtensionsSupport();
#endif
    SDLNetInited = false;

    secprop=control->AddSection_prop("dosbox",&Null_Init);
    Pstring = secprop->Add_path("language",Property::Changeable::WhenIdle,"");
    Pstring->Set_help("Select a language file for DOSBox-X to use. Encoded with either UTF-8 or a DOS code page.\n"
                      "You can set code page either in the language file or with \"country\" setting in [config] section.");
    Pstring->SetBasic(true);

    Pint = secprop->Add_int("beep duration", Property::Changeable::WhenIdle,0);
    Pint->SetMinMax(0,5000);
    Pint->Set_help("If nonzero, set the duration of a beep when DOS or INT 10h is given a BEL character");
    Pint->SetBasic(true);

    Pstring = secprop->Add_string("title",Property::Changeable::Always,"");
    Pstring->Set_help("Additional text to place in the title bar of the window.");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("logo text",Property::Changeable::Always,"");
    Pstring->Set_help("Text to place at the bottom of the screen during the startup logo. Text will line wrap automatically.\n"
                      "To explicitly break to the next line, put \\n in the string.");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("logo",Property::Changeable::Always,"");
    Pstring->Set_help("Location of PNG images to use in place of the DOSBox-X logo at startup.\n"
                      "This is the path of the base file name. For example logo=subdir\\sets\\007\\logo\n"
                      "with machine=vgaonly will use subdir\\sets\\007\\logo224x224.png as the logo.");
    Pstring->SetBasic(true);

    Pbool = secprop->Add_bool("fastbioslogo",Property::Changeable::OnlyAtStart,false);
    Pbool->Set_help("If set, DOSBox-X will skip the BIOS screen by activating fast BIOS logo mode (without 1-second pause).");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("disable graphical splash",Property::Changeable::OnlyAtStart,false);
    Pbool->Set_help("If set, DOSBox-X will always display text-mode BIOS splash screen instead of the graphical one.\n"
                    "The text-mode BIOS screen will automatically be used if the TrueType font (TTF) output is enabled.");

    Pbool = secprop->Add_bool("startbanner",Property::Changeable::OnlyAtStart,true);
    Pbool->Set_help("If set (default), DOSBox-X will display the welcome banner when it starts.");
    Pbool->SetBasic(true);

    Pstring = secprop->Add_string("bannercolortheme",Property::Changeable::OnlyAtStart,"default");
    Pstring->Set_values(color_themes);
    Pstring->Set_help("You can specify a different background color theme for the welcome banner from the default one.");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_path("configuration tool theme", Property::Changeable::WhenIdle, "");
    Pstring->Set_values(color_themes_config);
    Pstring->Set_help(
                      "Theme for the configuration tool.\n"
                      "If not set, host dark mode setting will be followed.\n");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("dpi aware",Property::Changeable::OnlyAtStart,"auto");
    Pstring->Set_values(truefalseautoopt);
    Pstring->Set_help("Set this option (auto by default) to indicate to your OS that DOSBox-X is DPI aware.\n"
            "If it is not set, Windows Vista/7/8/10 and higher may upscale the DOSBox-X window\n"
            "on higher resolution monitors which is probably not what you want.");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("quit warning",Property::Changeable::WhenIdle,"auto");
    Pstring->Set_values(quit_settings);
    Pstring->Set_help("Set this option to indicate whether DOSBox-X should show a warning message when the user tries to close its window.\n"
            "If set to auto (default), DOSBox-X will warn if a DOS program, game or a guest system is currently running.\n"
            "If set to autofile, DOSBox-X will warn if there are open file handles or a guest system is currently running.");
    Pstring->SetBasic(true);

    Pbool = secprop->Add_bool("allow quit after warning",Property::Changeable::OnlyAtStart,true);
    Pbool->Set_help("If set to false, DOSBox-X will disallow the quit option after displaying a warning message.");

    Pstring = secprop->Add_string("working directory option",Property::Changeable::OnlyAtStart,"default");
    Pstring->Set_values(workdiropts);
    Pstring->Set_help("Select an option for DOSBox-X's working directory when it runs.\n"
            "autoprompt: DOSBox-X will auto-decide whether to prompt for a working directory.\n"
            "config: DOSBox-X will use the primary config file directory as the working directory.\n"
            "custom: Specify a working directory via the \"working directory default\" option.\n"
            "default: Similar to autoprompt, but DOSBox-X will ask whether to save the selected folder.\n"
            "force: Similar to \"custom\", while overriding -defaultdir command-line option if used.\n"
            "noprompt: DOSBox-X uses the current directory and never prompts for a working directory.\n"
            "program: DOSBox-X will use the DOSBox-X program directory as the working directory.\n"
            "prompt: DOSBox-X will always ask the user to select a working directory when it runs.\n"
            "userconfig: DOSBox-X will use its user configuration directory as the working directory.");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_path("working directory default",Property::Changeable::OnlyAtStart,"");
    Pstring->Set_help("The default directory to act as DOSBox-X's working directory. See also the setting \"working directory option\".\n"
            "For working directory option=prompt, the specified directory becomes the default directory for the folder selection.");
    Pstring->SetBasic(true);

    Pbool = secprop->Add_bool("show advanced options", Property::Changeable::Always, false);
    Pbool->Set_help("If set, the Configuration Tool will display all config options (including advanced ones) by default.");
    Pbool->SetBasic(true);

    Pstring = secprop->Add_string("resolve config path", Property::Changeable::OnlyAtStart, "true");
    Pstring->Set_help("If set to true, DOSBox-X will resolve options containing paths in the config file (except [autoexec] section).\n"
                      "This includes environment variables (%VAR% [DOS/Windows] or ${VAR} [Linux/macOS] and tilde (~) in Linux/macOS.\n"
                      "If set to dosvar, DOSBox-X forces to resolve DOS-style environment variables (%VAR%) in all platforms (and tilde).\n"
                      "If set to tilde, DOSBox-X will only resolve tilde (~) in Linux/macOS but will not resolve environment variables.");
    Pstring->Set_values(resolveopts);
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("hostkey", Property::Changeable::Always, "mapper");
    Pstring->Set_help("By default, DOSBox-X uses the mapper-defined host key, which defaults to F11 on Windows and F12 on other platforms.\n"
                      "You may alternatively specify a host key with this setting and bypass the host key as defined in the mapper.\n"
                      "This can also be done from the menu (\"Main\" => \"Select host key\").");
    Pstring->Set_values(hostkeys);
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("mapper send key", Property::Changeable::Always, "ctrlaltdel");
    Pstring->Set_help("Select the key the mapper SendKey function will send.");
    Pstring->Set_values(sendkeys);
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("ime",Property::Changeable::OnlyAtStart,"auto");
    Pstring->Set_help("Enables support for the system input methods (IME) for inputting characters in Windows and Linux builds.\n"
                      "If set to auto, this feature is only enabled if DOSBox-X starts with a Chinese/Japanese/Korean code page.");
    Pstring->Set_values(truefalseautoopt);
    Pstring->SetBasic(true);

    Pbool = secprop->Add_bool("synchronize time", Property::Changeable::Always, false);
    Pbool->Set_help("If set, DOSBox-X will try to automatically synchronize time with the host, unless you decide to change the date/time manually.");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("keyboard hook", Property::Changeable::Always, false);
    Pbool->Set_help("Use keyboard hook (currently only on Windows) to catch special keys and synchronize the keyboard LEDs with the host.");

    // STUB OPTION, NOT YET FULLY IMPLEMENTED
    Pbool = secprop->Add_bool("weitek",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("If set, emulate the Weitek coprocessor. This option only has effect if cputype=386 or cputype=486.");

    Pbool = secprop->Add_bool("bochs debug port e9",Property::Changeable::WhenIdle,false);
    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.");

    Pstring = secprop->Add_string("machine",Property::Changeable::OnlyAtStart,"svga_s3");
    Pstring->Set_values(machines);
    Pstring->Set_help("The type of machine DOSBox-X tries to emulate.");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_path("captures",Property::Changeable::Always,"capture");
    Pstring->Set_help("Directory where things like wave, midi, screenshot get captured.");
    Pstring->SetBasic(true);

    Pmulti = secprop->Add_multi("autosave",Property::Changeable::Always," ");
    Pmulti->Set_help("Enable the auto-save state feature. Specify a time interval in seconds, and optionally a save slot or start and end save slots.\n"
            "For example, \"autosave=10 11-20\" will set a 10-second time interval for auto-saving, and the save slots used will be between 11 and 20.\n"
            "You can additionally specify up to 9 programs for this feature, e.g. \"autosave=10 11-20 EDIT:21-30 EDITOR:35\" for \"EDIT\" and \"EDITOR\".\n"
            "Putting a minus sign (-) before the time interval causes the auto-saving function to not be activated at start.");
    Pmulti->SetBasic(true);
    Pstring = Pmulti->GetSection()->Add_string("second",Property::Changeable::WhenIdle,"");
    for (int i=0; i<10; i++) Pmulti->GetSection()->Add_string("arg"+std::to_string(i),Property::Changeable::WhenIdle,"");

    Pint = secprop->Add_int("saveslot", Property::Changeable::WhenIdle,1);
    Pint->SetMinMax(1,100);
    Pint->Set_help("Select the default save slot (1-100) to save/load states.");
    Pint->SetBasic(true);

    Pstring = secprop->Add_path("savefile", Property::Changeable::WhenIdle,"");
    Pstring->Set_help("Select the default save file to save/load states. If specified it will be used instead of the save slot.");
    Pstring->SetBasic(true);

    Pbool = secprop->Add_bool("video debug at startup", Property::Changeable::WhenIdle,false);
    Pbool->Set_help("If set, have video debug displays on by default");

    Pbool = secprop->Add_bool("saveremark", Property::Changeable::WhenIdle,true);
    Pbool->Set_help("If set, the save state feature will ask users to enter remarks when saving a state.");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("forceloadstate", Property::Changeable::WhenIdle,false);
    Pbool->Set_help("If set, DOSBox-X will load a saved state even if it finds there is a mismatch in the DOSBox-X version, machine type, program name and/or the memory size.");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("compresssaveparts", Property::Changeable::WhenIdle,true);
    Pbool->Set_help("If set, DOSBox-X will compress components of saved states to save space.");

    Pbool = secprop->Add_bool("show recorded filename", Property::Changeable::WhenIdle,false);
    Pbool->Set_help("If set, DOSBox-X will show message boxes with recorded filenames when making audio or video captures.");

    /* will change to default true unless this causes compatibility issues with other users or their editing software */
    Pbool = secprop->Add_bool("skip encoding unchanged frames",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("Unchanged frames will not be sent to the video codec as a possible performance and bandwidth optimization.");

    Pstring = secprop->Add_string("capture chroma format", Property::Changeable::OnlyAtStart,"auto");
    Pstring->Set_values(capturechromaformats);
    Pstring->Set_help("Chroma format to use when capturing to H.264. 'auto' picks the best quality option.\n"
            "4:4:4       Chroma is at full resolution. This provides the best quality, however not widely supported by editing software.\n"
            "4:2:2       Chroma is at half horizontal resolution.\n"
            "4:2:0       Chroma is at quarter resolution, which may cause minor color smearing.\n"
            "            However, this chroma format is most likely to be compatible with video editing software.");

    Pstring = secprop->Add_string("capture format", Property::Changeable::OnlyAtStart,"default");
    Pstring->Set_values(captureformats);
    Pstring->Set_help("Capture format to use when capturing video. The availability of the format depends on how DOSBox-X was compiled.\n"
            "default                     Use compiled-in default (avi-zmbv)\n"
            "avi-zmbv                    Use DOSBox-style AVI + ZMBV codec with PCM audio\n"
            "mpegts-h264                 Use MPEG transport stream + H.264 + AAC audio. Resolution & refresh rate changes can be contained\n"
            "                            within one file with this choice, however not all software can support mid-stream format changes.");

    Pint = secprop->Add_int("shell environment size",Property::Changeable::OnlyAtStart,0);
    Pint->SetMinMax(0,65280);
    Pint->Set_help("Size of the initial DOSBox-X shell environment block, in bytes. Setting to 0 implies a default size of 720 bytes as in DOSBox.\n"
                   "You can increase this size to store more environment variables in DOS, although this does not affect the environment block\n"
                   "of sub-processes spawned from the DOS shell. This option has no effect unless the dynamic kernel allocation is enabled.");

    Pbool = secprop->Add_bool("shell permanent", Property::Changeable::OnlyAtStart, false);
    Pbool->Set_help("If enabled, initial DOSBox-X shell will stay permanent (equivalent to /P switch).");

    Pint = secprop->Add_int("private area size",Property::Changeable::OnlyAtStart,32768); // DOSBox mainline compatible 32KB region
    Pint->SetMinMax(16,128*1024);
    Pint->Set_help("Set DOSBox-X private memory area size. This area contains private memory structures used by the DOS kernel.\n"
            "It is discarded when you boot into another OS. Mainline DOSBox uses 32KB. Testing shows that it is possible\n"
            "to run DOSBox with as little as 4KB. If DOSBox-X aborts with error \"not enough memory for internal tables\"\n"
            "then you need to increase this value.");

    Pstring = secprop->Add_string("a20",Property::Changeable::WhenIdle,"mask");
    Pstring->Set_help("A20 gate emulation mode.\n"
              "The on/off/on_fake/off_fake options are intended for testing and debugging DOS development,\n"
              "or to emulate obscure hardware, or to work around potential extended memory problems with DOS programs.\n"
              "on_fake/off_fake are intended to test whether a program carries out a memory test to ensure the A20\n"
              "gate is set as intended (as HIMEM.SYS does). If it goes by the gate bit alone, it WILL crash.\n"
              "This parameter is also changeable from the builtin A20GATE command.\n"
              "  fast                         Emulate A20 gating by remapping the first 64KB @ 1MB boundary (fast, mainline DOSBox behavior)\n"
              "  mask                         Emulate A20 gating by masking memory I/O address (accurate)\n"
              "  off                          Lock A20 gate off (Software/OS cannot enable A20)\n"
              "  on                           Lock A20 gate on (Software/OS cannot disable A20)\n"
              "  off_fake                     Lock A20 gate off but allow bit to toggle (hope your DOS game tests the HMA!)\n"
              "  on_fake                      Lock A20 gate on but allow bit to toggle");
    Pstring->SetBasic(true);

    Pbool = secprop->Add_bool("turn off a20 gate on boot",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("If enabled, A20 gate is switched off when booting a guest OS.\n"
                    "Enabled by default. Recommended for MS-DOS when HIMEM.SYS is not installed in the guest OS.\n"
                    "If disabled, and MS-DOS does not load HIMEM.SYS, programs and features that rely on the 1MB wraparound will fail.");

    Pbool = secprop->Add_bool("pit any read returns status latch",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("If set, and the guest issues a command to read status, any I/O read from any counter will return the status of that counter.\n"
		    "This may be necessary for some games with unusual PIT counter management that requires this.\n"
		    "Required for:\n"
		    " - Descent to Undermountain");

    /* Ref:
     *
     * "Except the first generation, which C-Bus was synchronous with its 5MHz 8086, PC-98s
     *  before the age of SuperIO and PCI use either 10MHz (9.8304MHz) or 8MHz (7.9872MHz)
     *  for its C-Bus.
     *
     *  It's determined by the CPU clock base (2.4756Mhz or 1.9968MHz). For example, on a
     *  16MHz 386, C-Bus runs at 8MHz and on a 25MHz 386, C-Bus runs at 10MHz.
     *
     *  After NEC brought SuperIO and PCI to PC-98, C-Bus clock no longer ties to the CPU
     *  oscillator and got fixed to 10MHz." -Yksoft1
     *
     * Assuming this is true, the selection is given below */

    Pstring = secprop->Add_string("cbus bus clock",Property::Changeable::WhenIdle,"std10");
    Pstring->Set_help("C-BUS BCLK frequency (PC-98), used to emulate I/O delay.\n"
              "WARNING: In future revisions, PCI/motherboard chipset emulation will allow the guest OS/program to alter this value at runtime.\n"
              "  std10                        10MHz (CPU speed multiple of 5MHz or PCI-based)\n"
              "  std8                         8MHz (CPU speed multiple of 4MHz)\n"
              "  std5                         5MHz (older PC-9801)\n"
              "  <integer or float>           Any integer or floating point value will be used as the clock frequency in Hz\n"
              "  <integer/integer ratio>      If a ratio is given (num/den), the ratio will be used as the clock frequency");

    Pstring = secprop->Add_string("isa bus clock",Property::Changeable::WhenIdle,"std8.3");
    Pstring->Set_help("ISA BCLK frequency, used to emulate I/O delay.\n"
              "WARNING: In future revisions, PCI/motherboard chipset emulation will allow the guest OS/program to alter this value at runtime.\n"
              "  std8.3                       8.333MHz (typical 386-class or higher)\n"
              "  std8                         8MHz\n"
              "  std6                         6MHz\n"
              "  std4.77                      4.77MHz (precisely 1/3 x 14.31818MHz). Bus frequency of older PC/XT systems.\n"
              "  oc10                         10MHz\n"
              "  oc12                         12MHz\n"
              "  oc15                         15MHz\n"
              "  oc16                         16MHz\n"
              "  <integer or float>           Any integer or floating point value will be used as the clock frequency in Hz\n"
              "  <integer/integer ratio>      If a ratio is given (num/den), the ratio will be used as the clock frequency");

    Pstring = secprop->Add_string("pci bus clock",Property::Changeable::WhenIdle,"std33.3");
    Pstring->Set_help("PCI bus frequency, used to emulate I/O delay.\n"
              "WARNING: In future revisions, PCI/motherboard chipset emulation will allow the guest OS/program to alter this value at runtime.\n"
              "  std33.3                      33.333MHz (very common setting on motherboards)\n"
              "  std30                        30MHz (some older mid-1990's Pentium systems)\n"
              "  std25                        25MHz\n"
              "  <integer or float>           Any integer or floating point value will be used as the clock frequency in Hz\n"
              "  <integer/integer ratio>      If a ratio is given (num/den), the ratio will be used as the clock frequency");

    Pstring = secprop->Add_string("call binary on reset",Property::Changeable::WhenIdle,"");
    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"
                      "It will be executed before the BIOS POST routine, only ONCE. The binary blob is expected either to IRET or to\n"
                      "jump directly to F000:FFF0 to return control to the BIOS.\n"
                      "This can be used for x86 assembly language experiments and automated testing against the CPU emulation.");

    Pstring = secprop->Add_string("unhandled irq handler",Property::Changeable::WhenIdle,"");
    Pstring->Set_values(irqhandler);
    Pstring->Set_help("Determines how unhandled IRQs are handled. This may help some errant DOS applications.\n"
                      "Leave unset for default behavior (simple).\n"
                      "simple               Acknowledge the IRQ, and the master (if slave IRQ)\n"
                      "mask_isr             Acknowledge IRQs in service on master and slave and mask IRQs still in service, to deal with errant handlers (em-dosbox method)");

    Pstring = secprop->Add_string("call binary on boot",Property::Changeable::WhenIdle,"");
    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"
                      "This can be used for x86 assembly language experiments and automated testing against the CPU emulation.");

    Pstring = secprop->Add_string("ibm rom basic",Property::Changeable::WhenIdle,"");
    Pstring->Set_help("If set, this is the path of a ROM image containing IBM ROM BASIC. This is loaded just below the ROM BIOS.\n"
		      "One recommended file is IBMROMBASIC-F6000h-1982-10-27.ROM, a 32KB ROM BIOS image loaded to segment F600 taken from an IBM 5150.\n");

    Pint = secprop->Add_int("rom bios allocation max",Property::Changeable::OnlyAtStart,0);
    Pint->SetMinMax(0,128);
    Pint->Set_help("Maximum size (top down from 1MB) allowed for ROM BIOS dynamic allocation in KB");

    Pint = secprop->Add_int("rom bios minimum size",Property::Changeable::OnlyAtStart,0);
    Pint->SetMinMax(0,128);
    Pint->Set_help("Once ROM BIOS layout is finalized, trim total region down to a minimum amount in KB");

    Pint = secprop->Add_int("irq delay ns", Property::Changeable::WhenIdle,-1);
    Pint->SetMinMax(-1,100000);
    Pint->Set_help( "IRQ delay in nanoseconds. Set to -1 to use default, 0 to disable.\n"
                    "This is a more precise version of the irqdelay= setting.\n"
                    "There are some old DOS games and demos that have race conditions with IRQs that need a nonzero value here to work properly.");

    Pint = secprop->Add_int("iodelay", Property::Changeable::WhenIdle,-1);
    Pint->SetMinMax(-1,100000);
    Pint->Set_help( "I/O delay in nanoseconds for I/O port access. Set to -1 to use default, 0 to disable.\n"
            "A value of 1000 (1us) is recommended for ISA bus type delays. If your game\n"
            "or demo is not sensitive to I/O port and ISA bus timing, you can turn this option off\n"
            "(set to 0) to increase game performance.");

    Pint = secprop->Add_int("iodelay16", Property::Changeable::WhenIdle,-1);
    Pint->SetMinMax(-1,100000);
    Pint->Set_help( "I/O delay for 16-bit transfers. -1 to use default, 0 to disable.");

    Pint = secprop->Add_int("iodelay32", Property::Changeable::WhenIdle,-1);
    Pint->SetMinMax(-1,100000);
    Pint->Set_help( "I/O delay for 32-bit transfers. -1 to use default, 0 to disable.");

    // STUB OPTION, NOT YET FULLY IMPLEMENTED
    Pstring = secprop->Add_string("acpi", Property::Changeable::OnlyAtStart,"off");
    Pstring->Set_values(acpisettings);
    Pstring->Set_help("ACPI emulation, and what version of the specification to follow.\n"
            "WARNING: This option is very experimental at this time and should not be enabled unless you're willing to accept the consequences.\n"
            "         Intended for use with ACPI-aware OSes including Linux and Windows 98/ME. This option will also slightly reduce available\n"
            "         system memory to make room for the ACPI tables, just as real BIOSes do, and reserve an IRQ for ACPI functions.");

    // STUB OPTION, NOT YET FULLY IMPLEMENTED
    Pstring = secprop->Add_string("acpi rsd ptr location", Property::Changeable::OnlyAtStart,"auto");
    Pstring->Set_values(acpi_rsd_ptr_settings);
    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.");

    // STUB OPTION, NOT YET FULLY IMPLEMENTED
    Pint = secprop->Add_int("acpi sci irq", Property::Changeable::WhenIdle,-1);
    Pint->Set_help("IRQ to assign as ACPI system control interrupt. set to -1 to automatically assign.");

    // STUB OPTION, NOT YET FULLY IMPLEMENTED
    Phex = secprop->Add_hex("acpi iobase",Property::Changeable::WhenIdle,0);
    Phex->Set_help("I/O port base for the ACPI device Power Management registers. Set to 0 for automatic assignment.");

    // STUB OPTION, NOT YET FULLY IMPLEMENTED
    Pint = secprop->Add_int("acpi reserved size", Property::Changeable::WhenIdle,0);
    Pint->Set_help("Amount of memory at top to reserve for ACPI structures and tables. Set to 0 for automatic assignment.");

    // TODO: At some point we are going to REQUIRE the user to set this option to emulate a memsize option beyond
    //       some threshhold, say, 4GB, or probably less, in order not to grind the system to a halt if insufficient
    //       RAM is available. Better yet, require this option if it exceeds 50% of the total RAM installed on the system
    //       (or for Windows, the available RAM allowed by your Windows license limit such as 32-bit Windows only using
    //       3GB of your 4GB).
    //
    //       Normal DOSBox never has to worry about this as most forks limit memsize to 63MB or less, same as DOSBox SVN,
    //       which is nothing on the typical modern desktop.
    //
    //       No tricks! This code will ensure the path is to a FILE, not a directory, block device, or worse.
    Pstring = secprop->Add_path("memory file",Property::Changeable::OnlyAtStart,"");
    Pstring->Set_help("If set, guest memory is memory-mapped from a file on disk, rather than allocated from memory.\n"
                      "This option can help keep DOSBox-X from consuming too much RAM for large values of memsize.\n"
                      "This option is required to emulate 4GB or more of RAM. The file will be created if it does not exist\n"
                      "and it does not require any special maintenance or formatting.");
    Pstring->SetBasic(true);

#if defined(C_EMSCRIPTEN)
    Pint = secprop->Add_int("memsize", Property::Changeable::OnlyAtStart,4);
#else
    Pint = secprop->Add_int("memsize", Property::Changeable::OnlyAtStart,16);
#endif
    Pint->SetMinMax(0,1048576); // 1TB (PSE-40)
    Pint->Set_help(
        "Amount of memory DOSBox-X has in megabytes.\n"
        "This value is best left at its default to avoid problems with some games,\n"
        "although other games and applications may require a higher value.\n"
        "Programs that use 286 protected mode like Windows 3.0 in Standard Mode may crash with more than 15MB.\n"
        "A memory file is required to emulate a memory size of 4GB or more.\n"
        "The maximum value allowed is affected by the memalias setting which affects the maximum amount of memory CPU can access as a power of 2.\n"
        "The maximum value is also affected by the CPU type. See DOSBox-X console and log file for details.\n"
        "The maximum setting 1048576 represents 1TB and requires at least a Pentium II and PSE-40 emulation.");
    Pint->SetBasic(true);

    Pint = secprop->Add_int("memsizekb", Property::Changeable::OnlyAtStart,0);
    Pint->SetMinMax(0,524288);
    Pint->Set_help(
        "Amount of memory DOSBox-X has in kilobytes.\n"
        "This value should normally be set to 0.\n"
        "If nonzero, it is added to the memsize parameter.\n"
        "Finer grained control of total memory may be useful in\n"
        "emulating ancient DOS machines with less than 640KB of\n"
        "RAM or early 386 systems with odd extended memory sizes.\n"
        "For Tandy and PCjr emulation, it is strongly recommended.\n"
        "to specify a size that is a multiple of 32 (kb).\n");

    Pint = secprop->Add_int("dos mem limit", Property::Changeable::WhenIdle,0);
    Pint->SetMinMax(0,1023);
    Pint->Set_help( "Limit DOS conventional memory to this amount. Does not affect extended memory.\n"
            "Setting this option to a value in the range 636-639 can be used to simulate modern BIOSes\n"
            "that maintain an EBDA (Extended BIOS Data Area) at the top of conventional memory.\n"
            "You may also play with this option for diagnostic purposes or to stress test DOS programs in limited memory setups.\n"
            "\n"
            "A few DOS games & demos require this option to be set:\n"
            "     Majic 12 \"Show\": If UMBs are enabled, set this option to 639 to avoid MCB chain corruption error.");

    Pstring = secprop->Add_string("isa memory hole at 512kb",Property::Changeable::WhenIdle,"auto");
    Pstring->Set_values(truefalseautoopt);
    Pstring->Set_help("If set, emulate an ISA memory hole at the 512KB to 640KB area (0x80000-0x9FFFF).");

    Pstring = secprop->Add_string("isa memory hole at 15mb",Property::Changeable::WhenIdle,"auto");
    Pstring->Set_values(truefalseautoopt);
    Pstring->Set_help("If set, emulate an ISA memory hole at the 15MB to 16MB area (0xF00000-0xFFFFFF).\n"
		    "If auto, hole is disabled by default for IBM compatible modes and enabled by default for NEC PC-98 compatible modes.\n"
		    "The reason for this is that the hole is needed for the PC-9821 256-color mode linear framebuffer to work with some DOS games even when memsize >= 16.");

    Pint = secprop->Add_int("reboot delay", Property::Changeable::WhenIdle,-1);
    Pint->SetMinMax(-1,10000);
    Pint->Set_help(
        "Reboot delay. How long to pause at BIOS POST after reboot in milliseconds.\n"
        "This option is provided so that it is possible to see what the guest application\n"
        "or OS might have written to the screen before resetting the system. A value of\n"
        "-1 means to use a reasonable default.");

    Pint = secprop->Add_int("memalias", Property::Changeable::WhenIdle,0);
    Pint->SetMinMax(0,40);
    Pint->Set_help(
        "Memory aliasing emulation, in number of valid address bits.\n"
        "Many 386/486 class motherboards and processors prior to 1995\n"
        "had memory aliases for various technical reasons such as having\n"
	"less than 32 address bits on the CPU die.\n"
        "Recommended values when enabled:\n"
        "    0: Pick a value automatically according to cputype.\n"
        "       NOTE: Changing the cputype after initial startup will not change the auto setting i.e.\n"
        "       starting with cputype=8086 will use a memalias of 20 even if you later change cputype to 386.\n"
        "    24: 16MB aliasing. Common on 386SX systems (CPU had 24 external address bits)\n"
        "        or 386DX and 486 systems where the CPU communicated directly with the ISA bus (A24-A31 tied off)\n"
        "    26: 64MB aliasing. Some 486 clones (and 386EX/CX) had only 26 external address bits, some motherboards tied off A26-A31\n"
        "    32: 4GB aliasing. This is normal for most 486/Pentium and later systems and is the default for most values of cputype.\n"
        "    36: 64GB aliasing. Recommended if you are emulating more than 3.5GB of RAM and Pentium Pro/II Page Size Extensions.\n"
        "    40: 1TB aliasing. Recommended if you are emulating more than 63GB of RAM and Pentium Pro/II Page Size Extensions.");

    Pbool = secprop->Add_bool("nocachedir",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("If set, MOUNT commands will mount with -nocachedir (disable directory caching) by default.");
    Pbool->SetBasic(true);

    Pstring = secprop->Add_string("freesizecap",Property::Changeable::WhenIdle,"cap");
    Pstring->Set_values(freesizeopt);
    Pstring->Set_help("If set to \"cap\" (=\"true\"), the value of MOUNT -freesize will apply only if the actual free size is greater than the specified value.\n"
                    "If set to \"relative\", the value of MOUNT -freesize will change relative to the specified value.\n"
                    "If set to \"fixed\" (=\"false\"), the value of MOUNT -freesize will be a fixed one to be reported all the time.");
    Pstring->SetBasic(true);

    Pbool = secprop->Add_bool("convertdrivefat",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("If set, DOSBox-X will auto-convert mounted non-FAT drives (such as local drives) to FAT format for use with guest systems.");
    Pbool->SetBasic(true);

    Pint = secprop->Add_int("convert fat free space", Property::Changeable::WhenIdle,250);
    Pint->Set_help("If set, auto-converted FAT images will have the specified free space in MB (except PC-98 FAT12/16 HDI) if less than the actual free space.\n"
                   "If set to 0, the converted disk will be read-only; if set to -1, the actual free space on host drive will be used for the converted disk.");

    Pint = secprop->Add_int("convert fat timeout", Property::Changeable::WhenIdle,4);
    Pint->Set_help("If set to a positive integer, the FAT auto-conversion will time out after the specified number of seconds.");

    Pbool = secprop->Add_bool("leading colon write protect image",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("If set, BOOT and IMGMOUNT commands will put an image file name with a leading colon (:) in write-protect mode.");

    Pbool = secprop->Add_bool("locking disk image mount",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("If set, BOOT and IMGMOUNT commands will try to lock the mounted disk image files. As a result, you cannot\n"
                    "mount the same disk image files in read/write mode at the same time as this can cause possible disk corruptions.");

    Pbool = secprop->Add_bool("unmask keyboard on int 16 read",Property::Changeable::OnlyAtStart,true);
    Pbool->Set_help("If set, INT 16h will unmask IRQ 1 (keyboard) when asked to read keyboard input.\n"
                    "It is strongly recommended that you set this option if running Windows 3.11 Windows for Workgroups in DOSBox-X.");

    Pbool = secprop->Add_bool("int16 keyboard polling undocumented cf behavior",Property::Changeable::OnlyAtStart,false);
    Pbool->Set_help("If set, INT 16h function AH=01h will also set/clear the carry flag depending on whether input was available.\n"
                    "There are some old DOS games and demos that rely on this behavior to sense keyboard input, and this behavior\n"
                    "has been verified to occur on some old (early 90s) BIOSes.");

    Pbool = secprop->Add_bool("allow port 92 reset",Property::Changeable::OnlyAtStart,true);
    Pbool->Set_help("If set (default), allow the application to reset the CPU through port 92h");

    Pbool = secprop->Add_bool("enable port 92",Property::Changeable::WhenIdle,true);
    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.");

    Pbool = secprop->Add_bool("enable 1st dma controller",Property::Changeable::WhenIdle,true);
    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)");

    Pbool = secprop->Add_bool("enable 2nd dma controller",Property::Changeable::WhenIdle,true);
    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"
            "Note: mainline DOSBox automatically disables 16-bit DMA when machine=cga or machine=hercules, while DOSBox-X does not.");

    Pbool = secprop->Add_bool("allow dma address decrement",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("If set, allow increment & decrement modes as specified in the 8237 datasheet.\n"
            "If clear, always increment the address (as if to emulate clone 8237 implementations that skipped the inc/dec bit).");

    Pstring = secprop->Add_string("enable 128k capable 16-bit dma", Property::Changeable::OnlyAtStart,"auto");
    Pstring->Set_values(truefalseautoopt);
    Pstring->Set_help("If true, DMA controller emulation models ISA hardware that permits 16-bit DMA to span 128KB.\n"
                    "If false, DMA controller emulation models PCI hardware that limits 16-bit DMA to 64KB boundaries.\n"
                    "If auto, the choice is made according to other factors in hardware emulation");

    Pbool = secprop->Add_bool("enable dma extra page registers",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("If set, emulate the extra page registers (I/O ports 0x80, 0x84-0x86, 0x88, 0x8C-0x8E), like actual hardware.\n"
            "Note that mainline DOSBox behavior is to NOT emulate these registers.");

    Pbool = secprop->Add_bool("dma page registers write-only",Property::Changeable::WhenIdle,false);
    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.");

    Pbool = secprop->Add_bool("cascade interrupt never in service",Property::Changeable::WhenIdle,false);
    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.");

    // TODO: "Special mode" which apparently triggers this alternate behavior and used by default on PC-98, is configurable
    //       by software through the PIC control words, and should control this setting if this is "auto".
    //       It's time for "auto" default setting to end once and for all the running gag that PC-98 games will not run
    //       properly without having to add "cascade interrupt ignore in service=true" to your dosbox-x.conf all the time.
    Pstring = secprop->Add_string("cascade interrupt ignore in service",Property::Changeable::WhenIdle,"auto");
    Pstring->Set_values(truefalseautoopt);
    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"
                    "If false, PIC emulation will consider cascade in-service state when deciding which interrupt to signal (common IBM PC behavior)\n"
                    "If auto, setting is chosen based on machine type and other configuration.");

    Pbool = secprop->Add_bool("enable slave pic",Property::Changeable::WhenIdle,true);
    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.");

    Pbool = secprop->Add_bool("enable pc nmi mask",Property::Changeable::WhenIdle,true);
    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.");

    Pbool = secprop->Add_bool("allow more than 640kb base memory",Property::Changeable::Always,false);
    Pbool->Set_help("If set, and space is available, allow conventional memory to extend past 640KB.\n"
            "For example, if machine=cga, conventional memory can extend out to 0xB800 and provide up to 736KB of RAM.\n"
            "This allows you to emulate PC/XT style memory extensions.\n"
            "For machine=tandy, this enables up to 768KB of memory which is then provided as 640KB to DOS to emulate the Tandy 768KB configuration with no overlap between DOS and video memory");

    Pbool = secprop->Add_bool("enable pci bus",Property::Changeable::OnlyAtStart,true);
    Pbool->Set_help("Enable PCI bus emulation");

    secprop=control->AddSection_prop("render",&Null_Init,true);
    Pint = secprop->Add_int("frameskip",Property::Changeable::Always,0);
    Pint->SetMinMax(0,10);
    Pint->Set_help("How many frames DOSBox-X skips before drawing one.");
    Pint->SetBasic(true);

    Pstring = secprop->Add_string("aspect", Property::Changeable::Always, "false");
    Pstring->Set_values(aspectmodes);
    Pstring->Set_help(
        "Aspect ratio correction mode. Can be set to the following values:\n"
        "  'false' (default):\n"
        "      'direct3d'/opengl outputs: image is simply scaled to full\n"
        "         window/fullscreen size, possibly resulting in dis-\n"
        "         proportional image\n"
        "      'surface' output: it does no aspect ratio correction,\n"
        "         resulting in disproportional images if VGA mode pixel\n"
        "         ratio is not 4:3 (default)\n"
        "  'true':\n"
        "      'direct3d'/opengl outputs: uses output driver functions to\n"
        "         scale / pad image with black bars, correcting output \n"
        "         to proportional 4:3 image\n"
        "         In most cases image degradation should not be noticeable\n"
        "        (it all depends on the video adapter and how much the image\n"
        "         is upscaled).\n"
        "         Should have none to negligible impact on performance,\n"
        "         mostly being done in hardware.\n"
        "         For the pixel-perfect scaling (output=openglpp), it is\n"
        "         recommended to enable this whenever the emulated display\n"
        "         has an aspect ratio of 4:3\n"
        "      'surface' output: inherits old DOSBox aspect ratio correction\n"
        "         method (adjusting rendered image line count to correct\n"
        "         output to 4:3 ratio)\n"
        "         Due to source image manipulation this mode does not mix\n"
        "         well with scalers, i.e. multiline scalers like hq2x/hq3x\n"
        "         will work poorly\n"
        "         Slightly degrades visual image quality. Has a tiny impact\n"
        "         on performance."
#if C_XBRZ
        "\n"
        "         When using xBRZ scaler with 'surface' output, aspect\n"
        "         ratio correction is done by the scaler itself, so none of\n"
        "         the above apply."
#endif
#if C_SURFACE_POSTRENDER_ASPECT
        "\n"
        "  'nearest':\n"
        "      'direct3d'/opengl outputs: not available, fallbacks to 'true'\n"
        "         mode automatically\n"
        "      'surface' output: scaler friendly aspect ratio correction, \n"
        "         works by rescaling rendered image using nearest neighbor\n"
        "         scaler.\n"
        "         Complex scalers work. Image quality is on par with 'true'\n"
        "         mode (and better with scalers). More CPU intensive than\n"
        "         'true' mode\n"
#if C_XBRZ
        "         When using xBRZ scaler with 'surface' output, aspect\n"
        "         ratio correction is done by the scaler itself, so it\n"
        "         falls back to 'true' mode.\n"
#endif
        "  'bilinear':\n"
        "      'direct3d'/opengl outputs: not available, fallbacks to 'true'\n"
        "         mode automatically\n"
        "      'surface' output: scaler friendly aspect ratio correction,\n"
        "         works by rescaling rendered image using bilinear scaler.\n"
        "         Complex scalers work. Image quality is much better,\n"
        "         should be on par with using 'direct3d' output + 'true'\n"
        "         mode. Very CPU intensive, high end CPU may be required."
#if C_XBRZ
        "\n"
        "         When using xBRZ scaler with 'surface' output, aspect\n"
        "         ratio correction is done by the scaler itself, so it\n"
        "         falls back to 'true' mode."
#endif
#endif
    );
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("aspect_ratio",Property::Changeable::Always,"0:0");
    Pstring->Set_help("Set the aspect ratio (e.g. 16:9) in the aspect ratio correction mode. 0:0 means the default ratio of 4:3, and -1:-1 means the original image ratio.");
    Pstring->SetBasic(true);

    Pbool = secprop->Add_bool("char9",Property::Changeable::Always,true);
    Pbool->Set_help("Allow 9-pixel wide text mode fonts instead of 8-pixel wide fonts.");
    Pbool->SetBasic(true);

    Pint = secprop->Add_int("euro",Property::Changeable::Always,-1);
    Pint->Set_help("Display Euro symbol instead of the specified ASCII character (33-255).\n"
            "For example, setting it to 128 allows Euro symbol to be displayed instead of C-cedilla.");
    Pint->SetBasic(true);

    /* NTS: In the original code borrowed from yhkong, this was named "multiscan". All it really does is disable
     *      the doublescan down-rezzing DOSBox normally does with 320x240 graphics so that you get the full rendition of what a VGA output would emit. */
    Pbool = secprop->Add_bool("doublescan",Property::Changeable::Always,true);
    Pbool->Set_help("If set, doublescanned output emits two scanlines for each source line, "
            "in the same manner as the actual VGA output (320x200 is rendered as 640x400 for example).\n"
            "If clear, doublescanned output is rendered at the native source resolution (320x200 as 320x200).\n"
            "This affects the raster PRIOR to the software or hardware scalers.\n"
            "Setting this option may prevent some scalers to work as expected.\n"
            "Try turning this option off in such case.\n"
            "For pixel-perfect scaling (output=openglpp), it is recommended to turn this option off.");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("modeswitch",Property::Changeable::Always,false);
    Pbool->Set_help("Let DOSBox-X determine the resolution of the monitor. "
			"This feature is only available when DOSBox-X is compiled with SDL2 support.");
    Pbool->SetBasic(false);

    Pmulti = secprop->Add_multi("scaler",Property::Changeable::Always," ");
    Pmulti->SetValue("normal2x",/*init*/true);
    Pmulti->Set_help("Scaler used to enlarge/enhance low resolution modes. Add keyword 'forced', "
            "after the name of the scaler to always use the scaler even if the result might not be desired."
            "(e.g. 'normal2x forced')\n"
            "Appending 'prompt' will cause a confirmation message for forcing the scaler.\n"
            "To fit a scaler in the resolution used at full screen may require a border or side bars.\n"
            "To fill the screen entirely, depending on your hardware, a different scaler/fullresolution might work.\n"
            "Scalers should work with most output options, but they are ignored for openglpp and TrueType font outputs.\n"
            "If you are using OpenGL/Direct3D output and a shader that requires it, set to hardware_none or hardware2x.");
    Pmulti->SetBasic(true);
    Pstring = Pmulti->GetSection()->Add_string("type",Property::Changeable::Always,"normal2x");
    Pstring->Set_values(scalers);

    Pstring = Pmulti->GetSection()->Add_string("force",Property::Changeable::Always,"");
    Pstring->Set_values(force);

    Pstring = secprop->Add_path("glshader",Property::Changeable::Always,"none");
    Pstring->Set_help("Path to GLSL shader source to use with OpenGL output (\"none\" to disable, or \"default\" for default shader).\n"
            "Can be either an absolute path, a file in the \"glshaders\" subdirectory of the DOSBox-X configuration directory, "
            "or one of the built-in shaders (e.g. \"sharp\" for the pixel-perfect scaling mode):\n"
            "advinterp2x, advinterp3x, advmame2x, advmame3x, rgb2x, rgb3x, scan2x, scan3x, tv2x, tv3x, sharp.");
    Pstring->SetBasic(true);

    Pmulti = secprop->Add_multi("pixelshader",Property::Changeable::Always," ");
    Pmulti->SetValue("none",/*init*/true);
    Pmulti->Set_help("Set Direct3D pixel shader program (effect file must be in Shaders subdirectory). If 'forced' is appended, "
            "then the pixel shader will be used even if the result might not be desired.");
    Pmulti->SetBasic(true);

    Pstring = Pmulti->GetSection()->Add_string("type",Property::Changeable::Always,"none");
    Pstring = Pmulti->GetSection()->Add_string("force",Property::Changeable::Always,"");

#if C_XBRZ
    Pint = secprop->Add_int("xbrz slice",Property::Changeable::OnlyAtStart,16);
    Pint->SetMinMax(1,1024);
    Pint->Set_help("Number of screen lines to process in single xBRZ scaler taskset task, affects xBRZ performance, 16 is the default");

    Pint = secprop->Add_int("xbrz fixed scale factor",Property::Changeable::OnlyAtStart, 0);
    Pint->SetMinMax(0,6);
    Pint->Set_help("To use fixed xBRZ scale factor (i.e. to attune performance), set it to 2-6, 0 - use automatic calculation (default)");

    Pint = secprop->Add_int("xbrz max scale factor",Property::Changeable::OnlyAtStart, 0);
    Pint->SetMinMax(0,6);
    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)");
#endif

    Pbool = secprop->Add_bool("autofit",Property::Changeable::Always,true);
    Pbool->Set_help(
           "Best fits image to window\n"
           "  Intended for output=direct3d, fullresolution=original, aspect=true");
    Pbool->SetBasic(true);

    Pmulti = secprop->Add_multi("monochrome_pal",Property::Changeable::Always," ");
    Pmulti->SetValue("green",/*init*/true);
    Pmulti->Set_help("Specify the color of monochrome display.\n"
            "Append 'bright' for a brighter look.");
    Pmulti->SetBasic(true);
    Pstring = Pmulti->GetSection()->Add_string("color",Property::Changeable::Always,"green");
    const char* monochrome_pal_colors[]={"green","amber","gray","white",nullptr};
    Pstring->Set_values(monochrome_pal_colors);
    Pstring = Pmulti->GetSection()->Add_string("bright",Property::Changeable::Always,"");
    const char* bright[] = { "", "bright", nullptr };
    Pstring->Set_values(bright);

    secprop=control->AddSection_prop("pc98",&Null_Init);
	Pbool = secprop->Add_bool("pc-98 BIOS copyright string",Property::Changeable::WhenIdle,false);
    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.");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("pc-98 int 1b fdc timer wait",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("If set, INT 1Bh floppy access will wait for the timer to count down before returning.\n"
            "This is needed for Ys II to run without crashing.");

    Pbool = secprop->Add_bool("pc-98 pic init to read isr",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("If set, the programmable interrupt controllers are initialized by default (if PC-98 mode) "
            "so that the in-service interrupt status can be read immediately. There seems to be a common "
            "convention in PC-98 games to program and/or assume this mode for cooperative interrupt handling. "
            "This option is enabled by default for best compatibility with PC-98 games.");

    Pstring = secprop->Add_string("pc-98 fm board",Property::Changeable::Always,"auto");
    Pstring->Set_values(pc98fmboards);
    Pstring->Set_help("In PC-98 mode, selects the FM music board to emulate.");
    Pstring->SetBasic(true);

    Pint = secprop->Add_int("pc-98 fm board irq", Property::Changeable::WhenIdle,0);
    Pint->Set_help("If set, helps to determine the IRQ of the FM board. A setting of zero means to auto-determine the IRQ.");

    Phex = secprop->Add_hex("pc-98 fm board io port", Property::Changeable::WhenIdle,0);
    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.");

    Pbool = secprop->Add_bool("pc-98 time stamp",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("Emulate the time stamp/hardware wait I/O ports at 5Ch and 5Eh. This is recommended.");

    Pbool = secprop->Add_bool("pc-98 sound bios",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("Set Sound BIOS enabled bit in MEMSW 4 for some games that require it.\n"
                    "TODO: Real emulation of PC-9801-26K/86 Sound BIOS");

    Pbool = secprop->Add_bool("pc-98 load sound bios rom file",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("If set, load SOUND.ROM if available and prsent that to the guest instead of trying to emulate directly.\n"
                    "This is strongly recommended, and is default enabled.\n"
                    "SOUND.ROM is a snapshot of the FM board BIOS taken from real PC-98 hardware.");

    Pbool = secprop->Add_bool("pc-98 buffer page flip",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("If set, the game's request to page flip will be delayed to vertical retrace, which can eliminate tearline artifacts.\n"
                    "Note that this is NOT the behavior of actual hardware. This option is provided for the user's preference.");

    Pbool = secprop->Add_bool("pc-98 enable 256-color planar",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("Allow 256-color planar graphics mode if set, disable if not set.\n"
                    "This is a form of memory access in 256-color mode that existed for a short\n"
                    "time before later PC-9821 models removed it. This option must be enabled\n"
                    "to use DOSBox-X with Windows 3.1 and its built-in 256-color driver.");

    Pbool = secprop->Add_bool("pc-98 enable 256-color",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("Allow 256-color graphics mode if set, disable if not set");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("pc-98 enable 16-color",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("Allow 16-color graphics mode if set, disable if not set");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("pc-98 enable grcg",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("Allow GRCG graphics functions if set, disable if not set");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("pc-98 enable egc",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("Allow EGC graphics functions if set, disable if not set");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("pc-98 enable 188 user cg",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("Allow 188+ user-defined CG cells if set");

    Pbool = secprop->Add_bool("pc-98 start gdc at 5mhz",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("Start GDC at 5MHz if set, 2.5MHz if clear. May be required for some games.");

    Pbool = secprop->Add_bool("pc-98 allow scanline effect",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("If set, PC-98 emulation will allow the DOS application to enable the 'scanline effect'\n"
                    "in 200-line graphics modes upconverted to 400-line raster display. When enabled, odd\n"
                    "numbered scanlines are blanked instead of doubled");

    Pbool = secprop->Add_bool("pc-98 bus mouse",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("Enable PC-98 bus mouse emulation. Disabling this option does not disable INT 33h emulation.");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("pc-98 nec mouse function",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("If set, Use NEC mouse function in int 33h.");

    Pstring = secprop->Add_string("pc-98 video mode",Property::Changeable::WhenIdle,"");
    Pstring->Set_values(pc98videomodeopt);
    Pstring->Set_help("Specify the preferred PC-98 video mode.\n"
                      "Valid values are 15, 24, or 31 for each specific horizontal refresh rate on the platform.\n"
                      "24khz is default and best supported at this time.\n"
                      "15khz is not implemented at this time.\n"
                      "31khz is experimental at this time.");

    Pstring = secprop->Add_string("pc-98 timer always cycles",Property::Changeable::WhenIdle,"auto");
    Pstring->Set_values(truefalseautoopt);
    Pstring->Set_help("This controls PIT 1 PC speaker behavior related to turning the output on and off.\n"
                      "Default setting is 'auto' to let the emulator choose for you.\n"
                      "true:  PIT 1 will always cycle whether or not the speaker is on (PC-9801 behavior).\n"
                      "false: PIT 1 will only cycle when the speaker is on (PC-9821 behavior).\n"
                      "Some older games will require the PC-9801 behavior to function properly.");

    Pint = secprop->Add_int("pc-98 timer master frequency", Property::Changeable::WhenIdle,0);
    Pint->SetMinMax(0,2457600);
    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"
                   "If your setting is neither of the below the closest appropriate value will be chosen.\n"
                   "This setting affects the master clock rate that DOS applications must divide down from to program the timer\n"
                   "at the correct rate, which affects timer interrupt, PC speaker, and the COM1 RS-232C serial port baud rate.\n"
                   "8MHz is treated as an alias for 4MHz and 10MHz is treated as an alias for 5MHz.\n"
                   "    0: Use default (auto)\n"
                   "    4: 1.996MHz (as if 4MHz or multiple thereof CPU clock)\n"
                   "    5: 2.457MHz (as if 5MHz or multiple thereof CPU clock)");

    Pint = secprop->Add_int("pc-98 allow 4 display partition graphics", Property::Changeable::WhenIdle,-1);
    Pint->SetMinMax(-1,1);
    Pint->Set_help("According to NEC graphics controller documentation, graphics mode is supposed to support only\n"
                   "2 display partitions. Some games rely on hardware flaws that allowed 4 partitions.\n"
                   "   -1: Default (choose automatically)\n"
                   "    0: Disable\n"
                   "    1: Enable");

    Pstring = secprop->Add_string("pc-98 force ibm keyboard layout",Property::Changeable::WhenIdle,"auto");
    Pstring->Set_values(truefalseautoopt);
    Pstring->Set_help("Force to use a default keyboard layout like IBM US-English for PC-98 emulation.\n"
                    "Will only work with apps and games using BIOS for keyboard.");
    Pstring->SetBasic(true);

    Pbool = secprop->Add_bool("pc-98 force JIS keyboard layout",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("Force to use a default keyboard layout like JIS (JP106) for PC-98 emulation.\n"
                    "Will only work with apps and games using BIOS for keyboard.");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("pc-98 try font rom",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("If enabled, DOSBox-X will first try to load FONT.ROM as generated by T98Tools for PC-98 emulation.");
    Pbool->SetBasic(true);

    Pstring = secprop->Add_string("pc-98 anex86 font",Property::Changeable::WhenIdle,"");
    Pstring->Set_help("Specify an Anex86 compatible font to load as supported by the Anex86 emulator for PC-98 emulation.\n"
                      "By default DOSBox-X tries to load ANEX86.BMP followed by FREECG98.BMP after trying to load FONT.ROM.\n"
                      "If you specify a font here then it will be tried first, perhaps before FONT.ROM (see previous option).");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_path("pc-98 fontx sbcs",Property::Changeable::OnlyAtStart,"");
    Pstring->Set_help("Specifies a FONTX2 file (8x16) to be used in PC-98 mode.\n"
                      "This file has priority over ANEX86.BMP and FREECG98.BMP.");
    Pstring = secprop->Add_path("pc-98 fontx dbcs",Property::Changeable::OnlyAtStart,"");
    Pstring->Set_help("Specifies a FONTX2 file (16x16) to be used in PC-98 mode.\n"
                      "This file has priority over ANEX86.BMP and FREECG98.BMP.");
    Pbool = secprop->Add_bool("pc-98 fontx internal symbol",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("If set, Use the internal data for hankaku symbols instead of the data in the FONTX2 file.");

    /* Explanation: NEC's mouse driver MOUSE.COM enables the graphics layer on startup and when INT 33h AX=0 is called.
     *              Some games by "Orange House" assume this behavior and do not make any effort on their
     *              own to show and enable graphics. Without this option, those games will not show any
     *              graphics. PC-98 systems have been confirmed to boot up with the graphics layer disabled
     *              and set to 640x200 8-color planar mode. This has been confirmed on real hardware.
     *              See also [https://github.com/joncampbell123/dosbox-x/issues/1305] */
    Pbool = secprop->Add_bool("pc-98 show graphics layer on initialize",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("If PC-98 mode and INT 33h emulation is enabled, the graphics layer will be automatically enabled\n"
                    "at driver startup AND when INT 33h AX=0 is called. This is NEC MOUSE.COM behavior and default\n"
                    "enabled. To emulate other drivers like QMOUSE that do not follow this behavior, set to false.");

    Pbool = secprop->Add_bool("pc-98 chargen vsync-limited access",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("If set, reading pixels from the character generator while in Code Access mode (or always, for ANK\n"
                    "characters) will be invalid. Some models (i.e. PC-9821As3) dont seem to have this limitation, but\n"
                    "many others do.\n"
                    "This option is set to false by default, set this option to true if you suffer text glitches.\n"
                    "It is reported that setting this option to true will result in glitches in some titles;"
                    "therefore revert this option to false in such cases.");

    secprop=control->AddSection_prop("dosv",&Null_Init,true);

    Pstring = secprop->Add_string("dosv",Property::Changeable::OnlyAtStart,"off");
    Pstring->Set_values(dosv_settings);
    Pstring->Set_help("Enable DOS/V emulation and specify which version to emulate. This option is intended for use with games or software\n"
                    "originating from East Asia (China, Japan, Korea) that use the double byte character set (DBCS) encodings and DOS/V extensions\n"
                    "to display Japanese (jp), Chinese (chs/cht/cn/tw), or Korean (ko) text. Note that enabling DOS/V replaces 80x25 text mode with\n"
                    "a EGA/VGA graphics mode that emulates text mode to display the characters and may be incompatible with non-Asian software that\n"
                    "assumes direct access to the text mode via segment 0xB800. For a general DOS environment with CJK support please disable DOS/V\n"
                    "emulation and use TrueType font (TTF) output with a CJK code page (932, 936, 949, 950) and TTF font with CJK characters instead.");
    Pstring->SetBasic(true);

    Pbool = secprop->Add_bool("getsysfont",Property::Changeable::OnlyAtStart,true);
    Pbool->Set_help("If enabled, DOSBox-X will try to get and use the system fonts on Windows and Linux platforms for the DOS/V emulation.\n"
                    "If this cannot be done, then DOSBox-X will try to use the internal Japanese DOS/V font, or you can specify a different font.");
    Pbool->SetBasic(true);

    //For loading FONTX CJK fonts
    Pstring = secprop->Add_path("fontxsbcs",Property::Changeable::OnlyAtStart,"");
    Pstring->Set_help("FONTX2 file used to rendering SBCS characters (8x19) in DOS/V or JEGA mode. If not specified, the default one will be used.\n"
                    "Loading the ASC16 and ASCFONT.15 font files (from the UCDOS and ETen Chinese DOS systems) is also supported for the DOS/V mode.");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_path("fontxsbcs16",Property::Changeable::OnlyAtStart,"");
    Pstring->Set_help("FONTX2 file used to rendering SBCS characters (8x16) in DOS/V or JEGA mode. If not specified, the default one will be used.\n"
                    "Loading the ASC16 and ASCFONT.15 font files (from the UCDOS and ETen Chinese DOS systems) is also supported for the DOS/V mode.");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_path("fontxsbcs24",Property::Changeable::OnlyAtStart,"");
    Pstring->Set_help("FONTX2 file used to rendering SBCS characters (12x24) in DOS/V mode (with V-text). If not specified, the default one will be used.\n"
                    "Loading the ASC24 and ASCFONT.24? font files (the latter from the ETen Chinese DOS system) is also supported for the DOS/V mode.");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_path("fontxdbcs",Property::Changeable::OnlyAtStart,"");
    Pstring->Set_help("FONTX2 file used to rendering DBCS characters (16x16) in DOS/V or VGA/JEGA mode. If not specified, the default one will be used.\n"
                    "Alternatively, you can load a BDF or PCF font file (16x16 or 15x15), such as the free bitmap fonts from WenQuanYi (https://wenq.org/).\n"
                    "For Simplified Chinese DOS/V, loading the HZK16 font file (https://github.com/aguegu/BitmapFont/tree/master/font) is also supported.\n"
                    "For Traditional Chinese DOS/V, loading the STDFONT.15 font file from the ETen Chinese DOS system is also supported.");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_path("fontxdbcs14",Property::Changeable::OnlyAtStart,"");
    Pstring->Set_help("FONTX2 file used to rendering DBCS characters (14x14) for Configuration Tool or EGA mode. If not specified, the default one will be used.\n"
                    "Alternatively, you can load a BDF or PCF font file (14x14 or 15x15), such as the free bitmap fonts from WenQuanYi (https://wenq.org/).\n"
                    "For Simplified Chinese DOS/V, loading the HZK14 font file (https://github.com/aguegu/BitmapFont/tree/master/font) is also supported.\n"
                    "For Traditional Chinese DOS/V, loading the STDFONT.15 font file from the ETen Chinese DOS system is also supported.");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_path("fontxdbcs24",Property::Changeable::OnlyAtStart,"");
    Pstring->Set_help("FONTX2 file used to rendering DBCS characters (24x24) in DOS/V mode (with V-text and 24-pixel fonts enabled).\n"
                    "For Simplified Chinese DOS/V, loading the HZK24? font file (https://github.com/aguegu/BitmapFont/tree/master/font) is also supported.\n"
                    "For Traditional Chinese DOS/V, loading the STDFONT.24 font file from the ETen Chinese DOS system is also supported.");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("showdbcsnodosv",Property::Changeable::WhenIdle,"auto");
    Pstring->Set_values(truefalseautoopt);
    Pstring->Set_help("Enables rendering of Chinese/Japanese/Korean characters for DBCS code pages in standard VGA and EGA machine types in non-DOS/V and non-TTF mode.\n"
                    "DOS/V fonts will be used in such cases, which can be adjusted by the above config options (such as fontxdbcs, fontxdbcs14, and fontxdbcs24).\n"
                    "Setting to \"auto\" enables Chinese/Japanese/Korean character rendering if a language file is loaded (or with \"autodbcs\" option set) in such cases.");
    Pstring->SetBasic(true);

    Pbool = secprop->Add_bool("yen",Property::Changeable::OnlyAtStart,false);
    Pbool->Set_help("Enables the Japanese yen symbol at 5ch if it is found at 7fh in a custom SBCS font for the Japanese DOS/V or JEGA emulation.");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("del",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("Maps the undefined del symbol (0x7F) to the next character (0x80) for the Japanese DOS/V and other Japanese mode emulations.");

    const char* fepcontrol_settings[] = { "ias", "mskanji", "both", nullptr };
    Pstring = secprop->Add_path("fepcontrol",Property::Changeable::OnlyAtStart,"both");
    Pstring->Set_values(fepcontrol_settings);
    Pstring->Set_help("FEP control API for the DOS/V emulation.");
    Pstring->SetBasic(true);

    const char* vtext_settings[] = { "xga", "xga24", "sxga", "sxga24", "svga", nullptr };
    Pstring = secprop->Add_path("vtext1",Property::Changeable::WhenIdle,"svga");
    Pstring->Set_values(vtext_settings);
    Pstring->Set_help("V-text screen mode 1 for the DOS/V emulation. Enter command \"VTEXT 1\" for this mode. Note that XGA/SXGA mode is only supported by the svga_s3trio and svga_et4000 machine types.");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_path("vtext2",Property::Changeable::WhenIdle,"xga");
    Pstring->Set_values(vtext_settings);
    Pstring->Set_help("V-text screen mode 2 for the DOS/V emulation. Enter command \"VTEXT 2\" for this mode. Note that XGA/SXGA mode is only supported by the svga_s3trio and svga_et4000 machine types.");
    Pstring->SetBasic(true);

    Pbool = secprop->Add_bool("use20pixelfont",Property::Changeable::OnlyAtStart,false);
    Pbool->Set_help("Enables the 20 pixel font to be used instead of the 24 pixel system font for the Japanese DOS/V emulation (with V-text enabled).");
    Pbool->SetBasic(true);

    Pstring = secprop->Add_string("j3100",Property::Changeable::OnlyAtStart,"off");
    Pstring->Set_values(j3100_settings);
    Pstring->Set_help("With the setting dosv=jp and a non-off value of this option, the Toshiba J-3100 machine will be emulated with DCGA support.\n"
                      "Setting to \"on\" or \"auto\" starts J-3100 automatically, and with the setting \"manual\" you can enter J-3100 mode with DCGA command.");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("j3100type",Property::Changeable::OnlyAtStart,"default");
    Pstring->Set_values(j3100_types);
    Pstring->Set_help("Specifies the Toshiba J-3100 machine type if J-3100 mode is enabled. The color palette will be changed with different machine types.");
    Pstring->SetBasic(true);

    Pbool = secprop->Add_bool("j3100colorscroll",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("Specifies that the color display can be used for scrolling, which is currently incompatible with for example the J-3100 version of the SimCity game.\n"
                    "The VGA version of the Toshiba Windows 3.1 works fine with the \"false\" value of this setting, whereas its CGA/EGA version requires a \"true\" value for this.");
    Pbool->SetBasic(true);

    Pstring = secprop->Add_path("j3100backcolor",Property::Changeable::OnlyAtStart,"");
    Pstring->Set_help("Specifies the background color in J-3100 mode. If not specified, the colors will be those of the display type corresponding to the model specified in j3100type.");

    Pstring = secprop->Add_path("j3100textcolor",Property::Changeable::OnlyAtStart,"");
    Pstring->Set_help("Specifies the text color in J-3100 mode. If not specified, the colors will be those of the display type corresponding to the model specified in j3100type.");

    secprop=control->AddSection_prop("video",&Null_Init);

    Pstring = secprop->Add_string("int 10h use video parameter table",Property::Changeable::OnlyAtStart,"auto");
    Pstring->Set_values(int10usevp);
    Pstring->Set_help("If set, INT 10h will use the video parameter table for standard EGA/VGA modes.\n"
		      "If not set, internal modesetting will be used, same as DOSBox and most forks do.\n"
		      "If auto, the video parameter table will be used if any DOS program redirects the table (usually to override mode setting parameters)");

    Pint = secprop->Add_int("vmemdelay", Property::Changeable::WhenIdle,0);
    Pint->SetMinMax(-1,1000000);
    Pint->Set_help( "VGA Memory I/O delay in nanoseconds. Set to -1 to use default, 0 to disable.\n"
            "Default off. Enable this option (-1 or nonzero) if you are running a game or\n"
            "demo that needs slower VGA memory (like that of older ISA hardware) to work properly.\n"
            "If your game is not sensitive to VGA RAM I/O speed, then turning on this option\n"
            "will do nothing but cause a significant drop in frame rate which is probably not\n"
            "what you want. Recommended values -1, 0 to 2000.");

    Pbool = secprop->Add_bool("lfb vmemdelay",Property::Changeable::OnlyAtStart,false);
    Pbool->Set_help("Set this option to true if you need vmemdelay to apply to SVGA and linear framebuffer video modes as well.\n"
                    "This affects anything in which DOSBox-X emulates as a linear framebuffer including MDA/Hercules and PC-98 LFB.\n"
                    "Note that this option may slightly reduce emulator performance with such modes.");

    // NOTE: This will be revised as I test the DOSLIB code against more VGA/SVGA hardware!
    Pstring = secprop->Add_string("prevent capture",Property::Changeable::WhenIdle,"");
    Pstring->Set_values(prevent_capture_opts);
    Pstring->Set_help(
            "This option allows you to prevent capture of the DOSBox window, if an API is provided by the system to do so.\n"
	    "empty or none: the window is normal and it can be screen captured.\n"
	    "blank: notify the system so that if a screenshot is attempted, the window appears blank.\n"
	    "invisible: notify the system not to include the DOSBox window in screen capture.\n"
	    "\n"
	    "This option may be useful if you would like to prevent your DOS gaming from appearing in the Windows 11 Recall feature");

    Pint = secprop->Add_int("vbememsize", Property::Changeable::WhenIdle,0);
    Pint->SetMinMax(0,128);
    Pint->Set_help(
        "Amount of video memory in kilobytes to report through the VESA BIOS extensions.\n"
        "Set this value to an amount lower than vmemsize to handle DOS programs that cannot handle\n"
        "more than the small amount of video memory they were designed for. This option also affects\n"
        "what video modes are reported through the VBE."
        );
    Pint->SetBasic(true);

    Pint = secprop->Add_int("vbememsizekb", Property::Changeable::WhenIdle,0);
    Pint->SetMinMax(0,1024);
    Pint->Set_help(
        "Amount of video memory to report in kilobytes, in addition to vbememsize.");
    Pint->SetBasic(true);

    Pint = secprop->Add_int("vmemsize", Property::Changeable::WhenIdle,-1);
    Pint->SetMinMax(-1,128);
    Pint->Set_help(
        "Amount of video memory in megabytes.\n"
        "  The maximum resolution and color depth the svga_s3 will be able to display\n"
        "  is determined by this value.\n "
        " -1: auto (vmemsizekb is ignored)\n"
        "  0: 512k (800x600  at 256 colors) if vmemsizekb=0\n"
        "  1: 1024x768  at 256 colors or 800x600  at 64k colors\n"
        "  2: 1600x1200 at 256 colors or 1024x768 at 64k colors or 640x480 at 16M colors\n"
        "  4: 1600x1200 at 64k colors or 1024x768 at 16M colors\n"
        "  8: up to 1600x1200 at 16M colors\n"
	"Larger values are available depending on machine type.\n"
        "For build engine games, use more memory than in the list above so it can\n"
        "use triple buffering and thus won't flicker.\n"
        );
    Pint->SetBasic(true);

    Pint = secprop->Add_int("vmemsizekb", Property::Changeable::WhenIdle,0);
    Pint->SetMinMax(0,1024);
    Pint->Set_help(
        "Amount of video memory in kilobytes, in addition to vmemsize.");
    Pint->SetBasic(true);

    Pint = secprop->Add_int("vbe window granularity", Property::Changeable::WhenIdle,0);
    Pint->SetMinMax(0,128);
    Pint->Set_help("Controls VESA BIOS non-linear framebuffer window granularity in KB. This affects ONLY the VESA BIOS extensions. Set 0 to functional normally.");

    Pint = secprop->Add_int("vbe window size", Property::Changeable::WhenIdle,0);
    Pint->SetMinMax(0,128);
    Pint->Set_help("Controls VESA BIOS non-linear framebuffer window size in KB. This affects ONLY the VESA BIOS extensions. Set 0 to functional normally.");

    Pbool = secprop->Add_bool("vbe protected mode interface",Property::Changeable::OnlyAtStart,true);
    Pbool->Set_help("If set, enable the VBE protected mode interface");

    Pbool = secprop->Add_bool("enable 8-bit dac",Property::Changeable::OnlyAtStart,true);
    Pbool->Set_help("If set, allow VESA BIOS calls in IBM PC mode to set DAC width. Has no effect in PC-98 mode.");

    Pbool = secprop->Add_bool("high intensity blinking",Property::Changeable::OnlyAtStart,true);
    Pbool->Set_help("Set to false if you want to see high-intensity background colors instead of blinking foreground text.\n"
            "This option has no effect in PC-98 and some other video modes.");
    Pbool->SetBasic(true);

    Phex = secprop->Add_hex("svga lfb base", Property::Changeable::OnlyAtStart, 0);
    Phex->Set_help("If nonzero, define the physical memory address of the linear framebuffer.");

    Pbool = secprop->Add_bool("pci vga",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("If set, SVGA is emulated as if a PCI device (when enable pci bus=true).");

    // NOTE: This will be revised as I test the DOSLIB code against more VGA/SVGA hardware!
    Pstring = secprop->Add_string("vga attribute controller mapping",Property::Changeable::WhenIdle,"auto");
    Pstring->Set_values(vga_ac_mapping_settings);
    Pstring->Set_help(
            "This affects how the attribute controller maps colors, especially in 256-color mode.\n"
            "Some SVGA cards handle the attribute controller palette differently than most SVGA cards.\n"
            "  auto                         Automatically pick the mapping based on the SVGA chipset.\n"
            "  4x4                          Split into two 4-bit nibbles, map through AC, recombine. This is standard VGA behavior including clone SVGA cards.\n"
            "  4low                         Split into two 4-bit nibbles, remap only the low 4 bits, recombine. This is standard ET4000 behavior.\n"
            "\n"
            "NOTES:\n"
            "  Demoscene executable 'COPPER.EXE' requires the '4low' behavior in order to display line-fading effects\n"
            "  (including scrolling credits) correctly, else those parts of the demo show up as a blank screen.\n"
            "  \n"
            "  4low behavior is default for ET4000 emulation.");

    Pstring = secprop->Add_string("enable supermegazeux tweakmode", Property::Changeable::OnlyAtStart, "");
    Pstring->Set_values(truefalseautoopt);
    Pstring->Set_help("If set, allow old MegaZeux 256-color text tweakmode aka 'Super MegaZeux mode'. Not all cards support this tweakmode.\n"
		      "The ones that do are not emulated yet by DOSBox-X. It is not known at this time whether S3 chipsets support the hack.\n"
		      "On normal cards the tweakmode does nothing but halve the text mode resolution without any other effects.");

    Pbool = secprop->Add_bool("vga bios use rom image", Property::Changeable::OnlyAtStart, false);
    Pbool->Set_help("If set, load a VGA BIOS from a ROM image file. If clear, provide our own INT 10h emulation as normal.");

    Pstring = secprop->Add_string("vga bios rom image", Property::Changeable::OnlyAtStart, "");
    Pstring->Set_help("If set, load the VGA BIOS from the specified file (must be 1KB to 64KB in size).\n"
                    "If left unset, and DOSBox-X is asked to load a VGA BIOS from a file, a file name\n"
                    "is chosen automatically from the machine type. For example, Tseng ET4000 emulation\n"
                    "(machine=svga_et4000) will look for et4000.bin. VGA BIOS ROM images can be dumped\n"
                    "from real hardware or downloaded from the PCem ROMs collection.\n"
                    "\n"
                    "machine=svga_s3            TRIO64 (Ver. 1.5-07) [VGA] (S3 Incorporated).bin\n"
                    "machine=svga_et4000        et4000.bin");

    Pint = secprop->Add_int("vga bios size override", Property::Changeable::WhenIdle,0);
    Pint->SetMinMax(-65536,65536);
    Pint->Set_help("VGA BIOS size override. Override the size of the VGA BIOS (normally 32KB in compatible or 12KB in non-compatible).");

    Pbool = secprop->Add_bool("video bios dont duplicate cga first half rom font",Property::Changeable::WhenIdle,false);
    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");

    Pbool = secprop->Add_bool("video bios always offer 14-pixel high rom font",Property::Changeable::WhenIdle,false);
    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.");

    Pbool = secprop->Add_bool("video bios always offer 16-pixel high rom font",Property::Changeable::WhenIdle,false);
    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.");

    Pbool = secprop->Add_bool("video bios enable cga second half rom font",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("If set, and emulating CGA/PCjr/Tandy, automatically provide the second half of the 8x8 ROM font.\n"
            "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"
            "NOTE: if you disable the 14 & 16 pixel high font AND the second half when machine=cga, you will disable video bios completely.");

    Pstring = secprop->Add_string("forcerate",Property::Changeable::Always,"");
    Pstring->Set_help("Force the VGA framerate to a specific value(ntsc, pal, or specific hz), no matter what");

    Pbool = secprop->Add_bool("sierra ramdac",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("Whether or not to emulate a Sierra or compatible RAMDAC at port 3C6h-3C9h.\n"
            "Some DOS games expect to access port 3C6h to enable highcolor/truecolor SVGA modes on older chipsets.\n"
            "Disable if you wish to emulate SVGA hardware that lacks a RAMDAC or (depending on the chipset) does\n"
            "not emulate a RAMDAC that is accessible through port 3C6h. This option has no effect for non-VGA video hardware.");

    Pbool = secprop->Add_bool("sierra ramdac lock 565",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("When emulating High Sierra highcolor RAMDAC, assume 5:6:5 at all times if set. Else,\n"
            "bit 6 of the DAC command selects between 5:5:5 and 5:6:5. Set this option for demos or\n"
            "games that got the command byte wrong (MFX Transgression 2) or any other demo that is\n"
            "not rendering highcolor 16bpp correctly.");

    Pbool = secprop->Add_bool("vga fill active memory",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("If set, DOSBox-X will fill inactive video memory regions with RAM rather than mapping them as empty. This allows the ETen Chinese DOS system (e.g. ET16V and ET24VA) to run.");

    Pbool = secprop->Add_bool("page flip debug line",Property::Changeable::Always,false);
    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"
            "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.");

    Pbool = secprop->Add_bool("vertical retrace poll debug line",Property::Changeable::Always,false);
    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"
            "This can be used to help diagnose whether the DOS game is properly waiting for vertical retrace.");

    Pbool = secprop->Add_bool("cgasnow",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("When machine=cga, determines whether or not to emulate CGA snow in 80x25 text mode.\n"
                    "This parameter is also changeable from the builtin CGASNOW command in CGA mode.");

    /* Default changed to 0x04 for "Blues Brothers" at Allofich's request [https://github.com/joncampbell123/dosbox-x/issues/1273] */
    Phex = secprop->Add_hex("vga 3da undefined bits",Property::Changeable::WhenIdle,0x04);
    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"
                   "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.");

    Pbool = secprop->Add_bool("rom bios 8x8 CGA font",Property::Changeable::Always,true);
    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.");

    Pbool = secprop->Add_bool("rom bios video parameter table",Property::Changeable::Always,true);
    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.");

    Pbool = secprop->Add_bool("int 10h points at vga bios",Property::Changeable::Always,true);
    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"
                    "This option is needed for some older DOS applications that make additional checks before detecting EGA/VGA hardware (SuperCalc).");

    Pbool = secprop->Add_bool("unmask timer on int 10 setmode",Property::Changeable::OnlyAtStart,false);
    Pbool->Set_help("If set, INT 10h will unmask IRQ 0 (timer) when setting video modes.");

    Pbool = secprop->Add_bool("vesa bank switching window mirroring",Property::Changeable::Always,false);
    Pbool->Set_help("If set, bank switch (windowed) VESA BIOS modes will ignore the window selection when asked\n"
                    "to bank switch. Requests to control either Window A or Window B will succeed. This is needed\n"
                    "for some demoscene productions with SVGA support that assume Window B is available, without\n"
                    "which graphics do not render properly.\n"
                    "If clear, Window B is presented as not available and attempts to use it will fail. Only Window A\n"
                    "will be available, which is also DOSBox SVN behavior.");

    Pbool = secprop->Add_bool("vesa bank switching window range check",Property::Changeable::Always,true);
    Pbool->Set_help("Controls whether calls to bank switch (set the window number) through the VESA BIOS apply\n"
                    "range checking. If set, out of range window numbers will return with an error code. This\n"
                    "is also DOSBox SVN behavior. If clear, out of range window numbers are silently truncated\n"
                    "to a number within range of available video memory and allowed to succeed.\n"
                    "This is needed for some demoscene productions that rely on the silent truncation to render\n"
                    "correctly without which drawing errors occur (e.g. end credits of Pill by Opiate)");

    Pbool = secprop->Add_bool("vesa zero buffer on get information",Property::Changeable::Always,true);
    Pbool->Set_help("This setting affects VESA BIOS function INT 10h AX=4F00h. If set, the VESA BIOS will zero the\n"
                    "256-byte buffer defined by the standard at ES:DI, then fill in the structure. If clear, only\n"
                    "the structure members will be filled in, and memory outside the initial 20-32 bytes will remain\n"
                    "unmodified. This setting is ON by default. Some very early 1990s DOS games that support VESA\n"
                    "BIOS standards may need this setting turned OFF if the programmer did not provide enough space\n"
                    "for the entire 256 byte structure and the game crashes if it detects VESA BIOS extensions.\n"
                    "Needed for:\n"
                    "  GETSADAM.EXE");

    Pint = secprop->Add_int("vesa set display vsync", Property::Changeable::WhenIdle,-1);
    Pint->SetMinMax(-1,1);
    Pint->Set_help(
        "Whether to wait for vertical retrace if VESA Set Display Address is used to pan the display.\n"
        "The default value -1 will wait if vesa_oldvbe, or not otherwise. 0 means not to wait.\n"
        "1 means always to wait. This affects only subfunction 0x00. Subfunction 0x80 will always wait\n"
        "as specified in the VESA BIOS standard.\n"
        "It is recommended to set this to 1 for VBETEST.EXE so that the panning test and information does not\n"
        "go by too fast.");

    /* should be set to zero unless for very specific demos:
     *  - "Melvindale" by MFX (1996): Set this to 2, the nightmarish visual rendering code appears to draw 2 scanlines
     *    upward from the VESA linear framebuffer base we return, causing DOSBox to emit warnings about illegal read/writes
     *    from 0xBFFFF000-0xBFFFFFFF (just before the base of the framebuffer at 0xC0000000). It also has the effect of
     *    properly centering the picture on the screen. I suppose it's a miracle the demo didn't crash people's computers
     *    writing to undefined areas like that. */
    Pint = secprop->Add_int("vesa lfb base scanline adjust",Property::Changeable::WhenIdle,0);
    Pint->Set_help("If non-zero, the VESA BIOS will report the linear framebuffer offset by this many scanlines.\n"
            "This does not affect the linear framebuffer's location. It only affects the linear framebuffer\n"
            "location reported by the VESA BIOS. Set to nonzero for DOS games with sloppy VESA graphics pointer management.\n"
            "    MFX \"Melvindale\" (1996): Set this option to 2 to center the picture properly.");

    Pint = secprop->Add_int("vesa lfb pel scanline adjust",Property::Changeable::WhenIdle,0);
    Pint->Set_help("If non-zero, the VESA BIOS will report the linear framebuffer offset by this many pixels.\n"
            "This does not affect the linear framebuffer's location. It only affects the linear framebuffer\n"
            "location reported by the VESA BIOS. Set to nonzero for DOS games with sloppy VESA graphics pointer management.\n"
            "    Contract \"Out of Control\" (1997): Set this option to 128 to fix the display.");

    /* If set, all VESA BIOS modes map 128KB of video RAM at A0000-BFFFF even though VESA BIOS emulation
     * reports a 64KB window. Some demos like the 1996 Wired report
     * (ftp.scene.org/pub/parties/1995/wired95/misc/e-w95rep.zip) assume they can write past the window
     * by spilling into B0000 without bank switching. */
    Pbool = secprop->Add_bool("vesa map non-lfb modes to 128kb region",Property::Changeable::Always,false);
    Pbool->Set_help("If set, VESA BIOS SVGA modes will be set to map 128KB of video memory to A0000-BFFFF instead of\n"
                    "64KB at A0000-AFFFF. This does not affect the SVGA window size or granularity.\n"
                    "Some games or demoscene productions assume that they can render into the next SVGA window/bank\n"
                    "by writing to video memory beyond the current SVGA window address and will not appear correctly\n"
                    "without this option.");

    Pbool = secprop->Add_bool("ega per scanline hpel",Property::Changeable::Always,true/*only because DOSBox SVN assumes this for machine=ega*/);
    Pbool->Set_help("If set, EGA emulation allows changing hpel per scanline. This is reportedly the behavior\n"
                    "of IBM EGA hardware according to DOSBox SVN and on by default. If clear, EGA emulation\n"
                    "latches hpel on vertical retrace end (like VGA does), which may have been EGA clone behavior\n"
                    "that some games were written against. Commander Keen episodes 4-6 need this option set to false when machine=ega.\n"
                    "This option affects only EGA emulation. To change VGA hpel behavior, use the 'allow hpel effects' setting instead.");

    Pbool = secprop->Add_bool("allow hpel effects",Property::Changeable::Always,false);
    Pbool->Set_help("If set, allow the DOS demo or program to change the horizontal pel (panning) register per scanline.\n"
            "Some early DOS demos use this to create waving or sinus effects on the picture. Not very many VGA\n"
            "chipsets allow this, so far, only ATI chipsets are known to support this effect. Disabled by default.");

    Pbool = secprop->Add_bool("allow hretrace effects",Property::Changeable::Always,false);
    Pbool->Set_help("If set, allow the DOS demo or program to make the picture wavy by playing with the 'start horizontal"
            "retrace' register of the CRTC during the active picture. Some early DOS demos (Copper by Surprise!"
            "productions) need this option set for some demo effects to work. Disabled by default.");

    Pdouble = secprop->Add_double("hretrace effect weight",Property::Changeable::Always,4.0);
    Pdouble->Set_help("If emulating hretrace effects, this parameter adds 'weight' to the offset to smooth it out.\n"
            "the larger the number, the more averaging is applied. This is intended to emulate the inertia\n"
            "of the electron beam in a CRT monitor");

    Pint = secprop->Add_int("vesa modelist cap",Property::Changeable::Always,0);
    Pint->Set_help("IF nonzero, the VESA modelist is capped so that it contains no more than the specified number of video modes.");

    Pint = secprop->Add_int("vesa modelist width limit",Property::Changeable::Always,1280);
    Pint->Set_help("IF nonzero, VESA modes with horizontal resolution higher than the specified pixel count will not be listed.\n"
            "This is another way the modelist can be capped for DOS applications that have trouble with long modelists.");

    Pint = secprop->Add_int("vesa modelist height limit",Property::Changeable::Always,1024);
    Pint->Set_help("IF nonzero, VESA modes with vertical resolution higher than the specified pixel count will not be listed.\n"
            "This is another way the modelist can be capped for DOS applications that have trouble with long modelists.");

    Pbool = secprop->Add_bool("vesa vbe put modelist in vesa information",Property::Changeable::Always,false);
    Pbool->Set_help("If set, the VESA modelist is placed in the VESA information structure itself when the DOS application\n"
                    "queries information on the VESA BIOS. Setting this option may help with some games, though it limits\n"
                    "the mode list reported to the DOS application.");

    Pstring = secprop->Add_string("vesa vbe 1.2 modes are 32bpp",Property::Changeable::Always,"auto");
    Pstring->Set_values(truefalseautoopt);
    Pstring->Set_help("If set, truecolor (16M color) VESA BIOS modes in the 0x100-0x11F range are 32bpp. If clear, they are 24bpp.\n"
            "Some DOS games and demos assume one bit depth or the other and do not enumerate VESA BIOS modes, which is why this\n"
            "option exists. If set to auto, this is determined by the type of SVGA chipset emulated.");

    Pbool = secprop->Add_bool("allow low resolution vesa modes",Property::Changeable::Always,true);
    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"
            "SVGA hardware with a BIOS that does not support the lowres modes for testing purposes.");

    Pbool = secprop->Add_bool("allow explicit 24bpp vesa modes",Property::Changeable::Always,false);
    Pbool->Set_help("If set, additional 24bpp modes are listed in the modelist regardless whether modes 0x100-0x11F are\n"
                    "configured to be 24bpp or 32bpp. Setting this option can provide the best testing and development\n"
                    "environment for new retro DOS code. If clear, 24bpp will only be available in the 0x100-0x11F range\n"
                    "if the \"vesa vbe 1.2 modes are 32bpp\" is false. Setting to false helps to emulate typical SVGA\n"
                    "hardware in which either 24bpp is supported, or 32bpp is supported, but not both. Disabled by default.");

    Pbool = secprop->Add_bool("allow high definition vesa modes",Property::Changeable::Always,false);
    Pbool->Set_help("If set, offer HD video modes in the VESA modelist (such as 1280x720 aka 720p or 1920x1080 aka 1080p).\n"
                    "This option also offers 4:3 versions (960x720 and 1440x1080) for DOS games that cannot properly handle\n"
                    "a 16:9 aspect ratio, and several other HD modes. The modes enabled by this option are still limited by the\n"
                    "width and height limits and available video memory.\n"
                    "This is unusual for VESA BIOSes to do and is disabled by default.");

    Pbool = secprop->Add_bool("allow unusual vesa modes",Property::Changeable::Always,false);
    Pbool->Set_help("If set, unusual (uncommon) modes are added to the list. The modes reflect uncommon resolutions\n"
                    "added by external drivers (UNIVBE), some VESA BIOSes, some laptop and netbook displays, and\n"
                    "some added by DOSBox-X for additional fun. Disabled by default.");

    Pbool = secprop->Add_bool("allow 32bpp vesa modes",Property::Changeable::Always,true);
    Pbool->Set_help("If the DOS game or demo has problems with 32bpp VESA modes, set to 'false'");

    Pbool = secprop->Add_bool("allow 24bpp vesa modes",Property::Changeable::Always,true);
    Pbool->Set_help("If the DOS game or demo has problems with 24bpp VESA modes, set to 'false'");

    Pbool = secprop->Add_bool("allow 16bpp vesa modes",Property::Changeable::Always,true);
    Pbool->Set_help("If the DOS game or demo has problems with 16bpp VESA modes, set to 'false'");

    Pbool = secprop->Add_bool("allow 15bpp vesa modes",Property::Changeable::Always,true);
    Pbool->Set_help("If the DOS game or demo has problems with 15bpp VESA modes, set to 'false'");

    Pbool = secprop->Add_bool("allow 8bpp vesa modes",Property::Changeable::Always,true);
    Pbool->Set_help("If the DOS game or demo has problems with 8bpp VESA modes, set to 'false'");

    Pbool = secprop->Add_bool("allow 4bpp vesa modes",Property::Changeable::Always,true);
    Pbool->Set_help("If the DOS game or demo has problems with 4bpp VESA modes, set to 'false'.\n"
                    "These modes have the same 16-color planar memory layout as standard VGA, but\n"
                    "at SVGA resolution.");

    Pbool = secprop->Add_bool("allow 4bpp packed vesa modes",Property::Changeable::Always,false);
    Pbool->Set_help("If the DOS game or demo has problems with 4bpp packed VESA modes, set to 'false'.\n"
                    "4bpp (16-color) packed is an unusual novelty mode only seen on specific Chips & Tech 65550\n"
                    "VESA BIOSes such as the one in a Toshiba Libretto laptop. Disabled by default.");

    Pbool = secprop->Add_bool("allow tty vesa modes",Property::Changeable::Always,true);
    Pbool->Set_help("If the DOS game or demo has problems with text VESA modes, set to 'false'");

    Pbool = secprop->Add_bool("double-buffered line compare",Property::Changeable::Always,false);
    Pbool->Set_help("This setting affects the VGA Line Compare register. Set to false (default value) to emulate most VGA behavior\n"
            "Set to true for the value to latch once at the start of the frame.");

    Pbool = secprop->Add_bool("ignore vblank wraparound",Property::Changeable::Always,false);
    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"
            "If the wraparound handling prevents the game from displaying properly, set this to false. Out of bounds vblank values will be ignored.\n");

    Pbool = secprop->Add_bool("ignore extended memory bit",Property::Changeable::Always,false);
    Pbool->Set_help("Some DOS applications use VGA 256-color mode but accidentally clear the extended memory\n"
                    "bit originally defined to indicate whether EGA hardware has more than 64KB of RAM.\n"
                    "Setting this option can correct for that. Needed for Mr. Blobby.");

    Pbool = secprop->Add_bool("enable vga resize delay",Property::Changeable::Always,false);
    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"
            "This adds a delay between VGA mode changes and window updates. It also means that if you are capturing a demo or game,\n"
            "that your capture will also show a few garbled frames at any point mode changes occur, which is why this option is disabled\n"
            "by default. If you intend to run certain DOS games and demos like DoWhackaDo, enable this option.");

    Pbool = secprop->Add_bool("resize only on vga active display width increase",Property::Changeable::Always,false);
    Pbool->Set_help("If set, changes to the Display End register of the CRTC do not trigger DOSBox-X to resize its window\n"
            "IF the value written is less than the current value. Some demos like DoWhackaDo need this option set\n"
            "because of the way its raster effects work. If the DOSBox-X window rapidly changes size during a demo\n"
            "try setting this option. Else, leave it turned off. Changes to other VGA CRTC registers will trigger\n"
            "a DOSBox-X mode change as normal regardless of this setting.");

    Pbool = secprop->Add_bool("vga palette update on full load",Property::Changeable::Always,true);
    Pbool->Set_help("If set, all three bytes of the palette entry must be loaded before taking the color,\n"
                    "which is fairly typical SVGA behavior. If not set, partial changes are allowed.");

    Pbool = secprop->Add_bool("ignore odd-even mode in non-cga modes",Property::Changeable::Always,false);
    Pbool->Set_help("Some demoscene productions use VGA Mode X but accidentally enable odd/even mode.\n"
                    "Setting this option can correct for that and render the demo properly.\n"
                    "This option forces VGA emulation to ignore odd/even mode except in text and CGA modes.");

    Pbool = secprop->Add_bool("ignore sequencer blanking",Property::Changeable::Always,false);
    Pbool->Set_help("If set, ignore attempts to blank the display using the EGA/VGA sequencer registers.\n"
		    "This should not be set except for DOS games with bugs in their display handling code.");

    Pbool = secprop->Add_bool("memory io optimization 1",Property::Changeable::Always,true);
    Pbool->Set_help("Enable one class of EGA/VGA memory I/O optimizations. Default ON (true).\n"
		    "If graphical artifacts or errors occur, try turning this off first. May provide a performance benefit.");
    Pbool->SetBasic(true);

    Pstring = secprop->Add_string("skip render if nothing changed",Property::Changeable::Always,"auto");
    Pstring->Set_values(truefalseautoopt);
    Pstring->Set_help("If set, DOSBox-X will skip rendering entirely unless any change is made to the guest display.\n"
                      "This may provide a performance benefit, especially in SVGA modes. This option has no effect unless render on demand is true or auto.\n"
                      "Normally in DOSBox and DOSBox-X, video is rendered constantly, whether or not anything changed,\n"
                      "and then compared with the previous frame to determine where to update the host display.\n"
                      "In addition to the render on demand option, this option may further break timing dependent effects and/or cause problems with some games.");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("scanline render on demand",Property::Changeable::Always,"auto");
    Pstring->Set_values(truefalseautoopt);
    Pstring->Set_help("Render video output at vsync or when something is changed mid frame, instead of stopping to render every scanline.\n"
                      "This may provide a performance benefit to most DOS games. However this may also break timing-dependent game or Demoscene effects.\n"
                      "Default is auto, which will turn it off for VGA modes and turn it on for SVGA modes.");
    Pstring->SetBasic(true);

    secprop=control->AddSection_prop("script",&Null_Init,true);//done

    Pstring = secprop->Add_string("startup.js",Property::Changeable::WhenIdle,"");
    Pstring->Set_help("script to run at startup");

    secprop=control->AddSection_prop("vsync",&Null_Init,true);//done

    Pstring = secprop->Add_string("vsyncmode",Property::Changeable::WhenIdle,"off");
    Pstring->Set_values(vsyncmode);
    Pstring->Set_help("Synchronize vsync timing to the host display. Requires calibration within DOSBox-X.");
    Pstring->SetBasic(true);
    Pstring = secprop->Add_string("vsyncrate",Property::Changeable::WhenIdle,"75");
    Pstring->Set_values(vsyncrate);
    Pstring->Set_help("Vsync rate used if vsync is enabled. Ignored if vsyncmode is set to host (win32).");
    Pstring->SetBasic(true);

    secprop=control->AddSection_prop("cpu",&Null_Init,true);//done
    Pstring = secprop->Add_string("core",Property::Changeable::WhenIdle,"auto");
    Pstring->Set_values(cores);
    Pstring->Set_help("CPU Core used in emulation. auto will switch to dynamic if available and appropriate.\n"
            "For the dynamic core, both dynamic_x86 and dynamic_rec are supported (dynamic_x86 is preferred).\n"
            "Windows 95 or other preemptive multitasking OSes will not work with the dynamic_rec core.");
    Pstring->SetBasic(true);

    /* I would like "auto" as the default so FPU emulation is enabled for 486 or higher, disabled for 386 and lower.
     * However it is better to always emulate the FPU (default "true") like DOSBox SVN to remain compatible with
     * existing dosbox.conf files. */
    Pstring = secprop->Add_string("fpu",Property::Changeable::Always,"true");
    Pstring->Set_help("Enable FPU emulation");
    Pstring->Set_values(fpu_settings);
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("cpuid string",Property::Changeable::Always,"");
    Pstring->Set_help("If set, changes the string returned by the CPUID instruction. Normally by default the string is 'GenuineIntel'.\n"
		    "CAUTION: Custom strings can interfere with guest code CPU detection");

    Pstring = secprop->Add_string("processor serial number",Property::Changeable::Always,"");
    Pstring->Set_help("For Pentium III emulation, this sets the 96-bit Processor Serial Number returned by CPUID.\n"
            "If not set, then emulation will act as if the PSN has been disabled by the BIOS.\n"
	    "Enter as 4 sets of 16-bit hexadecimal digits XXXX-XXXX-XXXX-XXXX.\n"
	    "Note that the processor info and feature bits form the topmost 32 bits of the PSN and cannot be changed.");

    Pint = secprop->Add_int("rdtsc rate",Property::Changeable::Always,0);
    Pint->SetMinMax(0,0x7FFFFFFE);
    Pint->Set_help("If nonzero, the Pentium RDTSC counter will tick at this rate per millisecond instead of by the cycle count");
    Pint->SetBasic(true);

    Pbool = secprop->Add_bool("segment limits",Property::Changeable::Always,true);
    Pbool->Set_help("Enforce checks for segment limits on 80286 and higher CPU types.");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("lds wraparound",Property::Changeable::Always,true);
    Pbool->Set_help("For LDS/LES instructions, in 16-bit code, check for 64KB wraparound case.");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("double fault",Property::Changeable::Always,true);
    Pbool->Set_help("Emulate double fault exception");

    Pbool = secprop->Add_bool("clear trap flag on unhandled int 1",Property::Changeable::Always,false);
    Pbool->Set_help("If set, the DOS kernel INT 01h handler will clear the trap flag when called.\n"
		    "Normally a DOS program using INT 01h and the trap flag (usually for debugging)\n"
		    "will provide its own INT 01h handler. Some programs need this option set in\n"
		    "order to not crash during startup due to possible bugs or anti debugger tricks\n"
		    "that went terribly wrong.");

    Pbool = secprop->Add_bool("reset on triple fault",Property::Changeable::Always,true);
    Pbool->Set_help("Reset CPU on triple fault condition (failure to handle double fault)");

    Pbool = secprop->Add_bool("always report double fault",Property::Changeable::Always,false);
    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.");

    Pbool = secprop->Add_bool("always report triple fault",Property::Changeable::Always,false);
    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.");

    Pstring = secprop->Add_string("mask stack pointer for enter leave instructions",Property::Changeable::Always,"auto");
    Pstring->Set_values(truefalseautoopt);
    Pstring->Set_help("If set, ENTER will mask the stack pointer by 64KB if the stack segment is 16-bit, even if used in a 32-bit form.\n"
		      "This is not how real Intel processors work, and is intended as a bug fix for certain games");

    Pstring = secprop->Add_string("allow lmsw to exit protected mode",Property::Changeable::Always,"auto");
    Pstring->Set_values(truefalseautoopt);
    Pstring->Set_help("Controls whether the processor will allow the guest to exit protected mode using the 286 LMSW instruction (clear the PE bit)");

    Pbool = secprop->Add_bool("report fdiv bug",Property::Changeable::Always,false);
    Pbool->Set_help("If set, the FDIV bug will be reported with the cputype=pentium setting.");

    Pbool = secprop->Add_bool("enable msr",Property::Changeable::Always,true);
    Pbool->Set_help("Allow RDMSR/WRMSR instructions. This option is only meaningful when cputype=pentium.\n"
            "WARNING: Leaving this option enabled while installing Windows 95/98/ME can cause crashes.");

    Pstring = secprop->Add_string("enable pse",Property::Changeable::Always,"auto");
    Pstring->Set_values(pseopts);
    Pstring->Set_help("Allow PSE (Page Size Extensions) to paging.\n"
                    "none=Do not enable PSE\n"
                    "auto=Controlled by cpu type\n"
                    "pse=Basic PSE\n"
                    "pse36=PSE with 36-bit addressing\n"
                    "pse40=PSE with 40-bit addressing");

    Pbool = secprop->Add_bool("enable cmpxchg8b",Property::Changeable::Always,true);
    Pbool->Set_help("Enable Pentium CMPXCHG8B instruction. Enable this explicitly if using software that uses this instruction.\n"
            "You must enable this option to run Windows ME because portions of the kernel rely on this instruction.");

    Pbool = secprop->Add_bool("enable syscall",Property::Changeable::Always,true);
    Pbool->Set_help("Allow SYSENTER/SYSEXIT instructions. This option is only meaningful when is cputype=pentium_ii or higher.\n");

    Pbool = secprop->Add_bool("ignore undefined msr",Property::Changeable::Always,false);
    Pbool->Set_help("Ignore RDMSR/WRMSR on undefined registers. Normally the CPU will fire an Invalid Opcode exception in that case.\n"
            "This option is off by default, enable if using software or drivers that assumes the presence of\n"
            "certain MSR registers without checking. If you are using certain versions of the 3dfx Glide drivers for MS-DOS\n"
            "you will need to set this to TRUE as 3dfx appears to have coded GLIDE2X.OVL to assume the presence\n"
            "of Pentium Pro/Pentium II MTRR registers.\n"
            "WARNING: Leaving this option enabled while installing Windows 95/98/ME can cause crashes.");

    /* NTS: This setting is honored by all cpu cores except dynamic core */
    Pint = secprop->Add_int("interruptible rep string op",Property::Changeable::Always,-1);
    Pint->SetMinMax(-1,65536);
    Pint->Set_help("If nonzero, REP string instructions (LODS/MOVS/STOS/INS/OUTS) are interruptible (by interrupts or other events).\n"
            "If zero, REP string instructions are carried out in full before processing events and interrupts.\n"
            "Set to -1 for a reasonable default setting based on cpu type and other configuration.\n"
            "A setting of 0 can improve emulation speed at the expense of emulation accuracy.\n"
            "A nonzero setting (1-8) may be needed for DOS games and demos that use the IRQ 0 interrupt to play digitized samples\n"
            "while doing VGA palette animation at the same time (use case of REP OUTS), where the non-interruptible version\n"
            "would cause an audible drop in audio pitch.");

    Pint = secprop->Add_int("dynamic core cache block size",Property::Changeable::Always,32);
    Pint->SetMinMax(1,65536);
    Pint->Set_help("The dynamic core cache block size (the default value is 32). Please change this value carefully.\n"
            "According to forum discussions, setting this to 1 can aid debugging, however doing so also causes\n"
            "problems with 32-bit protected mode DOS games and reduces the performance of the dynamic core.\n");

    Pstring = secprop->Add_string("cputype",Property::Changeable::Always,"auto");
    Pstring->Set_values(cputype_values);
    Pstring->Set_help("CPU Type used in emulation. \"auto\" emulates a 486 which tolerates Pentium instructions.\n"
            "\"experimental\" enables newer instructions not normally found in the CPU types emulated by DOSBox-X, such as FISTTP.");
    Pstring->SetBasic(true);

    Pmulti_remain = secprop->Add_multiremain("cycles",Property::Changeable::Always," ");
    Pmulti_remain->Set_help(
        "Number of instructions DOSBox-X tries to emulate each millisecond.\n"
        "Setting this value too high results in sound dropouts and lags.\n"
        "Cycles can be set in 3 ways:\n"
        "  'auto'          tries to guess what a game needs.\n"
        "                  It usually works, but can fail for certain games.\n"
        "  'fixed #number' will set a fixed number of cycles. This is what you usually\n"
        "                  need if 'auto' fails (Example: fixed 4000).\n"
        "  'max'           will allocate as much cycles as your computer is able to\n"
        "                  handle. Recommended if better performance is desired.");
    Pmulti_remain->SetBasic(true);

    Pstring = Pmulti_remain->GetSection()->Add_string("type",Property::Changeable::Always,"auto");
    Pmulti_remain->SetValue("auto",/*init*/true);
    Pstring->Set_values(cyclest);
    Pstring->SetBasic(true);

    Pmulti_remain->GetSection()->Add_string("parameters",Property::Changeable::Always,"");

    Pint = secprop->Add_int("cycleup",Property::Changeable::Always,10);
    Pint->SetMinMax(1,1000000);
    Pint->Set_help("Amount of cycles to decrease/increase with the mapped keyboard shortcut.");
    Pint->SetBasic(true);

    Pint = secprop->Add_int("cycledown",Property::Changeable::Always,20);
    Pint->SetMinMax(1,1000000);
    Pint->Set_help("Setting it lower than 100 will be a percentage.");
    Pint->SetBasic(true);

    Pint = secprop->Add_int("cycle emulation percentage adjust",Property::Changeable::Always,0);
    Pint->SetMinMax(-50,50);
    Pint->Set_help("The percentage adjustment for use with the \"Emulate CPU speed\" feature. Default is 0 (no adjustment), but you can adjust it (between -25% and 25%) if necessary.");

    Pbool = secprop->Add_bool("turbo",Property::Changeable::Always,false);
    Pbool->Set_help("Enables Turbo (Fast Forward) mode to speed up operations.");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("stop turbo on key",Property::Changeable::Always,true);
    Pbool->Set_help("If set, the Turbo mode will be automatically stopped if a keyboard input is detected.");

    Pint = secprop->Add_int("stop turbo after second",Property::Changeable::Always,0);
    Pint->Set_help("If a positive integer is specified, the Turbo function will last for specific seconds.");

    Pstring = secprop->Add_string("use dynamic core with paging on",Property::Changeable::Always,"auto");
    Pstring->Set_values(truefalseautoopt);
    Pstring->Set_help("Allow dynamic cores (dynamic_x86 and dynamic_rec) to be used with 386 paging enabled.\n"
                    "If the dynamic_x86 core is set, this allows Windows 9x/ME to run properly, but may somewhat decrease the performance.\n"
                    "If the dynamic_rec core is set, this disables the dynamic core if the 386 paging functions are currently enabled.\n"
                    "If set to auto, this option will be enabled depending on if the 386 paging and a guest system are currently active.");

    Pbool = secprop->Add_bool("ignore opcode 63",Property::Changeable::Always,true);
    Pbool->Set_help("When debugging, do not report illegal opcode 0x63.\n"
            "Enable this option to ignore spurious errors while debugging from within Windows 3.1/9x/ME.");

    Pbool = secprop->Add_bool("apmbios",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("Emulate Advanced Power Management (APM) BIOS calls.");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("apmbios pnp",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("If emulating ISA PnP BIOS, announce APM BIOS in PnP enumeration.\n"
            "Warning: this can cause Windows 95 OSR2 and later to enumerate the APM BIOS twice and cause problems.");

    Pstring = secprop->Add_string("apm power button event",Property::Changeable::WhenIdle,"suspend");
    Pstring->Set_values(apmpowerbuttonevent);
    Pstring->Set_help("When the power button event is triggered from the mapper or the menu, and the guest is using the APM BIOS, which APM BIOS event to send");

    Pstring = secprop->Add_string("apmbios version",Property::Changeable::WhenIdle,"auto");
    Pstring->Set_values(apmbiosversions);
    Pstring->Set_help("What version of the APM BIOS specification to emulate.\n"
            "You will need at least APM BIOS v1.1 for emulation to work with Windows 95/98/ME.");

    Pbool = secprop->Add_bool("apmbios allow realmode",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("Allow guest OS to connect from real mode.");

    Pbool = secprop->Add_bool("apmbios allow 16-bit protected mode",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("Allow guest OS to connect from 16-bit protected mode.");

    Pbool = secprop->Add_bool("apmbios allow 32-bit protected mode",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("Allow guest OS to connect from 32-bit protected mode.\n"
            "If you want power management in Windows 95/98/ME (beyond using the APM to shutdown the computer) you MUST enable this option.\n"
            "Windows 95/98/ME does not support the 16-bit real and protected mode APM BIOS entry points.\n"
            "Please note at this time that 32-bit APM is unstable under Windows ME.");

    Pbool = secprop->Add_bool("integration device",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("Enable DOSBox-X's integration I/O device, a way for additional software to talk to DOSBox-X. It is currently experimental.\n"
	    "This can for example be used to return DOSBox-X's current status and by the guest OS to match the mouse pointer position.");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("integration device pnp",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("List DOSBox-X integration I/O device as part of ISA PnP enumeration. This has no purpose yet.");

    Pbool = secprop->Add_bool("isapnpbios",Property::Changeable::WhenIdle,true);
    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"
            "Do not disable if Windows 9x is configured around PnP devices, you will likely confuse it.");
    Pbool->SetBasic(true);

    Pstring = secprop->Add_string("isapnpport",Property::Changeable::WhenIdle,"auto");
    Pstring->Set_help("Emulate ISA Plug & Play I/O ports, which are separate from the PnP BIOS.\n"
	    "ISA Plug & Play devices provide these I/O ports as the means to determine hardware and configure resources.\n"
	    "By default, this setting is 'auto' which enables the PnP I/O ports only if you enable the PnP BIOS.");
    Pstring->Set_values(truefalseautoopt);

    Pbool = secprop->Add_bool("realbig16",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("Allow the B (big) bit in real mode. If set, allow the DOS program to set the B bit,\n"
        "then jump to realmode with B still set (aka Huge Unreal mode). Needed for Project Angel.");

    secprop=control->AddSection_prop("keyboard",&Null_Init);
    Pbool = secprop->Add_bool("aux",Property::Changeable::OnlyAtStart,true);
    Pbool->Set_help("Enable emulation of the 8042 auxiliary port. PS/2 mouse emulation requires this to be enabled.\n"
            "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.");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("allow output port reset",Property::Changeable::OnlyAtStart,true);
    Pbool->Set_help("If set (default), allow the application to reset the CPU through the keyboard controller.\n"
            "This option is required to allow Windows ME to reboot properly, whereas Windows 9x and earlier\n"
            "will reboot without this option using INT 19h");
    Pbool->SetBasic(true);

    Pstring = secprop->Add_string("controllertype",Property::Changeable::OnlyAtStart,"auto");
    Pstring->Set_values(controllertypes);
    Pstring->Set_help("Type of keyboard controller (and keyboard) attached.\n"
                      "auto     Automatically pick according to machine type\n"
                      "at       AT (PS/2) type keyboard\n"
                      "xt       IBM PC/XT type keyboard\n"
                      "pcjr     IBM PCjr type keyboard (only if machine=pcjr)\n"
                      "pc98     PC-98 keyboard emulation (only if machine=pc98)");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("auxdevice",Property::Changeable::OnlyAtStart,"intellimouse");
    Pstring->Set_values(auxdevices);
    Pstring->Set_help("Type of PS/2 mouse attached to the AUX port");
    Pstring->SetBasic(true);

    secprop=control->AddSection_prop("ttf",&Null_Init,true);

	Pstring = secprop->Add_string("font", Property::Changeable::Always, "");
    Pstring->Set_help("Specifies a TrueType font to use for the TTF output. If not specified, the built-in TrueType font will be used.\n"
                    "Either a font name or full font path can be specified. If file ends with the .TTF extension then the extension can be omitted.\n"
                    "For a font name or relative path, directories such as the working directory and default system font directory will be searched.\n"
                    "For example, setting it to \"consola\" or \"consola.ttf\" will use Consola font (included in Windows); similar for other TTF fonts.\n"
                    "Additionally, OTF fonts (e.g. OratorStd.otf), .FON fonts (e.g. vgasys.fon), and .TTC fonts (e.g. msgothic.ttc) are also supported.\n"
                    "To display Chinese/Japanese/Korean text in these code pages, a font with CJK characters is needed (e.g. GNU Unifont or Sarasa Gothic).");
    Pstring->SetBasic(true);

	Pstring = secprop->Add_string("fontbold", Property::Changeable::Always, "");
    Pstring->Set_help("You can optionally specify a bold TrueType font for use with the TTF output that will render the bold text style.\n"
                    "It requires a word processor be set with the wp option, and this actual bold font will be used for the bold style.\n"
                    "For example, setting it to \"consolab\" or \"consolab.ttf\" will use the Consolab font; similar for other TTF fonts.");
    Pstring->SetBasic(true);

	Pstring = secprop->Add_string("fontital", Property::Changeable::Always, "");
    Pstring->Set_help("You can optionally specify an italic TrueType font for use with the TTF output that will render the italic text style.\n"
                    "It requires a word processor be set with the wp option, and this actual italic font will be used for the italic style.\n"
                    "For example, setting it to \"consolai\" or \"consolai.ttf\" will use the Consolai font; similar for other TTF fonts.");
    Pstring->SetBasic(true);

	Pstring = secprop->Add_string("fontboit", Property::Changeable::Always, "");
    Pstring->Set_help("You can optionally specify a bold italic TrueType font for use with the TTF output that will render the bold italic text style.\n"
                    "It requires a word processor be set with the wp option, and this actual bold-italic font will be used for the bold-italic style.\n"
                    "For example, setting it to \"consolaz\" or \"consolaz.ttf\" will use the Consolaz font; similar for other TTF fonts.");
    Pstring->SetBasic(true);

	Pstring = secprop->Add_string("colors", Property::Changeable::Always, "");
    Pstring->Set_help("Specifies a color scheme to use for the TTF output by supply all 16 color values in RGB: (r,g,b) or hexadecimal as in HTML: #RRGGBB\n"
                    "The original DOS colors (0-15): #000000 #0000aa #00aa00 #00aaaa #aa0000 #aa00aa #aa5500 #aaaaaa #555555 #5555ff #55ff55 #55ffff #ff5555 #ff55ff #ffff55 #ffffff\n"
                    "gray scaled color scheme: (0,0,0)  #0e0e0e  (75,75,75) (89,89,89) (38,38,38) (52,52,52) #717171 #c0c0c0 #808080 (28,28,28) (150,150,150) (178,178,178) (76,76,76) (104,104,104) (226,226,226) (255,255,255)\n"
                    "An optional leading \"+\" sign allows the preset color scheme to be used when switching from another output.");
    Pstring->SetBasic(true);

	Pstring = secprop->Add_string("outputswitch", Property::Changeable::Always, "auto");
    Pstring->Set_help("Specifies the output that DOSBox-X should switch to from the TTF output when a graphical mode is requested, or auto for automatic selection.");
    Pstring->Set_values(switchoutputs);
    Pstring->SetBasic(true);

	Pint = secprop->Add_int("winperc", Property::Changeable::Always, 60);
    Pint->Set_help("Specifies the window percentage for the TTF output (100 = full screen). Ignored if the ptsize setting is specified.");
    Pint->SetBasic(true);

    Pbool = secprop->Add_bool("enableWinPercLimit", Property::Changeable::Always, true);
    Pbool->Set_help("If set, a TrueType window size will be limited to 60 percent of the screen.\n"
        "Enabled by default; optionally disable the limit when using more than 25 lines in a TTF window.");
    Pbool->SetBasic(true);

	Pint = secprop->Add_int("ptsize", Property::Changeable::Always, 0);
    Pint->Set_help("Specifies the font point size for the TTF output. If specified (minimum: 9), it will override the winperc setting.");
    Pint->SetBasic(true);

	Pint = secprop->Add_int("lins", Property::Changeable::Always, 0);
    Pint->Set_help("Specifies the number of rows on the screen for the TTF output (0 = default).");
    Pint->SetBasic(true);

	Pint = secprop->Add_int("cols", Property::Changeable::Always, 0);
    Pint->Set_help("Specifies the number of columns on the screen for the TTF output (0 = default).");
    Pint->SetBasic(true);

	Pbool = secprop->Add_bool("righttoleft", Property::Changeable::Always, false);
    Pbool->Set_help("If set, DOSBox-X will display text from right to left instead of left to right on the screen for the TTF output.\n"
                    "This is especially useful for languages which use right-to-left scripts (such as Arabic and Hebrew).");
    Pbool->SetBasic(true);

	Pstring = secprop->Add_string("wp", Property::Changeable::Always, "");
    Pstring->Set_help("You can specify a word processor for the TTF output and optionally also a version number for the word processor.\n"
                    "Supported word processors are WP=WordPerfect, WS=WordStar, XY=XyWrite, FE=FastEdit, and an optional version number.\n"
                    "For example, WP6 will set the word processor as WordPerfect 6, and XY4 will set the word processor as XyWrite 4.\n"
                    "Word processor-specific features like on-screen text styles and 512-character font will be enabled based on this.");
    Pstring->SetBasic(true);

	Pint = secprop->Add_int("wpbg", Property::Changeable::Always, -1);
    Pint->SetMinMax(-1,15);
    Pint->Set_help("You can optionally specify a color to match the background color of the specified word processor for the TTF output.\n"
                   "Use the DOS color number (0-15: 0=Black, 1=Blue, 2=Green, 3=Cyan, 4=Red, 5=Magenta, 6=Yellow, 7=White, etc) for this.");

	Pint = secprop->Add_int("wpfg", Property::Changeable::Always, 7);
    Pint->SetMinMax(-1,7);
    Pint->Set_help("You can optionally specify a color to match the foreground color of the specified word processor for the TTF output.\n"
                   "Use the DOS color number (0-7: 0=Black, 1=Blue, 2=Green, 3=Cyan, 4=Red, 5=Magenta, 6=Yellow, 7=White) for this.");

	Pbool = secprop->Add_bool("bold", Property::Changeable::Always, true);
    Pbool->Set_help("If set, DOSBox-X will display bold text in visually (requires a word processor be set) for the TTF output.\n"
                    "This is done either with the actual bold font specified by the fontbold option, or by making it bold automatically.");
    Pbool->SetBasic(true);

	Pbool = secprop->Add_bool("italic", Property::Changeable::Always, true);
    Pbool->Set_help("If set, DOSBox-X will display italicized text visually (requires a word processor be set) for the TTF output.\n"
                    "This is done either with the actual italic font specified by the fontital option, or by slanting the characters automatically.");
    Pbool->SetBasic(true);

	Pbool = secprop->Add_bool("underline", Property::Changeable::Always, true);
    Pbool->Set_help("If set, DOSBox-X will display underlined text visually (requires a word processor be set) for the TTF output.");
    Pbool->SetBasic(true);

	Pbool = secprop->Add_bool("strikeout", Property::Changeable::Always, false);
    Pbool->Set_help("If set, DOSBox-X will display strikeout text visually (requires a word processor be set) for the TTF output.");
    Pbool->SetBasic(true);

	Pbool = secprop->Add_bool("char512", Property::Changeable::Always, true);
    Pbool->Set_help("If set, DOSBox-X will display the 512-character font if possible (requires a word processor be set) for the TTF output.");

	Pbool = secprop->Add_bool("printfont", Property::Changeable::Always, true);
    Pbool->Set_help("If set, DOSBox-X will force to use the current TrueType font (set via font option) for printing in addition to displaying.");
    Pbool->SetBasic(true);

	Pbool = secprop->Add_bool("autodbcs", Property::Changeable::WhenIdle, true);
    Pbool->Set_help("If set, DOSBox-X enables Chinese/Japanese/Korean DBCS (double-byte) characters when these code pages are active by default.\n"
                    "Only applicable when using a DBCS code page (932: Japanese, 936: Simplified Chinese; 949: Korean; 950: Traditional Chinese)\n"
                    "This applies to both the display and printing of these characters (see the [printer] section for details of the latter).");
    Pbool->SetBasic(true);

	Pbool = secprop->Add_bool("autoboxdraw", Property::Changeable::WhenIdle, true);
    Pbool->Set_help("If set, DOSBox-X will auto-detect ASCII box-drawing characters for CJK (Chinese/Japanese/Korean) support in the TTF output.\n"
                    "Only applicable when using a DBCS code page (932: Japanese, 936: Simplified Chinese; 949: Korean; 950: Traditional Chinese)\n"
                    "This applies to both the display and printing of these characters (see the [printer] section for details of the latter).");

	Pbool = secprop->Add_bool("halfwidthkana", Property::Changeable::WhenIdle, true);
    Pbool->Set_help("If set, DOSBox-X enables half-width Katakana to replace upper ASCII characters for the Japanese code page (932) of a non-PC98 machine type in the TTF output.");

	Pstring = secprop->Add_string("blinkc", Property::Changeable::Always, "true");
    Pstring->Set_help("If set to true, the cursor blinks for the TTF output; setting it to false will turn the blinking off.\n"
                      "You can also change the blinking rate by setting an integer between 1 (fastest) and 7 (slowest), or 0 for no cursor.");
    Pstring->SetBasic(true);

	Pbool = secprop->Add_bool("gbk",Property::Changeable::WhenIdle,false);
	Pbool->Set_help("Enables the GBK extension (in addition to the standard GB2312 charset) for the Simplified Chinese TTF output or DOS/V emulation.");
    Pbool->SetBasic(true);

	Pbool = secprop->Add_bool("chinasea",Property::Changeable::WhenIdle,false);
	Pbool->Set_help("Enables the ChinaSea and Big5-2003 extension (in addition to the standard Big5-1984 charset) for the Traditional Chinese TTF output.\n"
                     "A TTF/OTF font containing such characters (such as the included SarasaGothicFixed TTF font) is needed to correctly render ChinaSea characters.");
    Pbool->SetBasic(true);

	Pbool = secprop->Add_bool("uao",Property::Changeable::WhenIdle,false);
	Pbool->Set_help("Enables the Big5 Unicode-At-On (UAO) extension instead of the Big5 HKSCS extension for the hidden code page 951 of the Traditional Chinese TTF output.");

	Pbool = secprop->Add_bool("dosvfunc", Property::Changeable::OnlyAtStart, false);
    Pbool->Set_help("If set, enables FEP control to function for Japanese DOS/V applications, and changes the blinking of character attributes to high brightness.");
    Pbool->SetBasic(true);

    secprop=control->AddSection_prop("voodoo",&Null_Init,false); //Voodoo

    Pstring = secprop->Add_string("voodoo_card",Property::Changeable::WhenIdle,"auto");
    Pstring->Set_values(voodoo_settings);
    Pstring->Set_help("Enable support for the 3dfx Voodoo card.");
    Pstring->SetBasic(true);
	Pbool = secprop->Add_bool("voodoo_maxmem",Property::Changeable::OnlyAtStart,true);
	Pbool->Set_help("Specify whether to enable maximum memory size for the Voodoo card.\n"
                    "If set (on by default), the memory size will be 12MB (4MB front buffer + 2x4MB texture units)\n"
                    "Otherwise, the memory size will be the standard 4MB (2MB front buffer + 1x2MB texture unit)");
    Pbool->SetBasic(true);

	Pbool = secprop->Add_bool("glide",Property::Changeable::WhenIdle,false);
	Pbool->Set_help("Enable Glide emulation (Glide API passthrough to the host).\n"
                    "Requires a Glide wrapper - glide2x.dll (Windows), libglide2x.so (Linux), or libglide2x.dylib (macOS).");
    Pbool->SetBasic(true);
	//Phex = secprop->Add_hex("grport",Property::Changeable::WhenIdle,0x600);
	//Phex->Set_help("I/O port to use for host communication.");
    const char *lfb[] = {"full","full_noaux","read","read_noaux","write","write_noaux","none",nullptr};
	Pstring = secprop->Add_string("lfb",Property::Changeable::WhenIdle,"full_noaux");
	Pstring->Set_values(lfb);
	Pstring->Set_help("Enable LFB access for Glide. OpenGlide does not support locking aux buffer, please use _noaux modes.");
	Pstring->SetBasic(true);

	Pbool = secprop->Add_bool("splash",Property::Changeable::WhenIdle,true);
	Pbool->Set_help("Show 3dfx splash screen for Glide emulation (Windows; requires 3dfxSpl2.dll).");
    Pbool->SetBasic(true);

    secprop=control->AddSection_prop("mixer",&Null_Init);
    Pbool = secprop->Add_bool("nosound",Property::Changeable::OnlyAtStart,false);
    Pbool->Set_help("Enable silent mode, sound is still emulated though.");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("dc bias correction",Property::Changeable::OnlyAtStart,true);
    Pbool->Set_help("If set, apply DC bias correction to the overall audio mix to prevent distortion when certain DOS games"
		    "play digitized audio where the digitized audio has an overall DC bias that is way off from zero, for example,"
		    "In Extremis. This is enabled by default. The bias correction is applied slowly so that normal audio output"
		    "remains unaffected");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("sample accurate",Property::Changeable::OnlyAtStart,false);
    Pbool->Set_help("Enable sample accurate mixing, at the expense of some emulation performance. Enable this option for DOS games and demos\n"
            "that require such accuracy for correct Tandy/OPL output including digitized speech. This option can also help eliminate\n"
            "minor errors in Gravis Ultrasound emulation that result in random echo/attenuation effects.");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("swapstereo",Property::Changeable::OnlyAtStart,false);
    Pbool->Set_help("Swaps the left and right stereo channels.");
    Pbool->SetBasic(true);

    Pint = secprop->Add_int("rate",Property::Changeable::OnlyAtStart,48000);
    Pint->SetMinMax(8000,192000);
    Pint->Set_help("Mixer sample rate, setting any device's rate higher than this will probably lower their sound quality.");
    Pint->SetBasic(true);

    Pint = secprop->Add_int("blocksize",Property::Changeable::OnlyAtStart,1024);
    Pint->Set_values(blocksizes);
    Pint->Set_help("Mixer block size, larger blocks might help sound stuttering but sound will also be more lagged.");
    Pint->SetBasic(true);

    Pint = secprop->Add_int("prebuffer",Property::Changeable::OnlyAtStart,25);
    Pint->SetMinMax(0,250);
    Pint->Set_help("How many milliseconds of data to keep on top of the blocksize.");
    Pint->SetBasic(true);

    secprop=control->AddSection_prop("midi",&Null_Init,true);//done

    Pbool = secprop->Add_bool("roland gs sysex",Property::Changeable::OnlyAtStart,true);
    Pbool->Set_help("Listen for and handle some Roland GS System Exclusive messages, such as GS Reset and Master Volume.\n"
                    "This is needed for PC-98 games that have hanging/stuck MIDI note problems because they rely on these\n"
                    "messages to reset the synth rather than using standard MIDI commands.");
    Pbool->SetBasic(false);

    Pstring = secprop->Add_string("mpu401",Property::Changeable::WhenIdle,"intelligent");
    Pstring->Set_values(mputypes);
    Pstring->Set_help("Type of MPU-401 to emulate.");
    Pstring->SetBasic(true);

    Phex = secprop->Add_hex("mpubase",Property::Changeable::WhenIdle,0/*default*/);
    Phex->Set_values(mpubases);
    Phex->Set_help("The IO address of the MPU-401.\n"
                   "Set to 0 to use a default I/O address.\n"
                   "300h to 330h are for use with IBM PC mode.\n"
                   "C0D0h to F8D0h (in steps of 800h) are for use with NEC PC-98 mode (MPU98).\n"
                   "80D2h through 80DEh are for use with NEC PC-98 Sound Blaster 16 MPU-401 emulation.\n"
                   "If not assigned (0), 330h is the default for IBM PC and E0D0h is the default for PC-98.");
    Phex->SetBasic(true);

    Pstring = secprop->Add_string("mididevice",Property::Changeable::WhenIdle,"default");
    Pstring->Set_values(devices);
    Pstring->Set_help("Device that will receive the MIDI data from MPU-401.");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("midiconfig",Property::Changeable::WhenIdle,"");
    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\n"
                      "(find the id/name with mixer/listmidi).\n"
                      "Or in the case of coreaudio or synth, you can specify a soundfont here.\n"
                      "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"
                      "In that case, add 'delaysysex', for example: midiconfig=2 delaysysex\n"
                      "See the README/Manual for more details.");
    Pstring->SetBasic(true);

    Pint = secprop->Add_int("samplerate",Property::Changeable::WhenIdle,48000);
    Pint->Set_values(rates);
    Pint->Set_help("Sample rate for MIDI synthesizer, if applicable.");
    Pint->SetBasic(true);

    Pint = secprop->Add_int("mpuirq",Property::Changeable::WhenIdle,-1);
    Pint->SetMinMax(-1,15);
    Pint->Set_help("MPU-401 IRQ. -1 to automatically choose.");
    Pint->SetBasic(true);

    Pstring = secprop->Add_string("mt32.romdir",Property::Changeable::WhenIdle,"");
    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"
        "  Accepted file names are as follows:\n"
        "    MT32_CONTROL.ROM or CM32L_CONTROL.ROM - control ROM file.\n"
        "    MT32_PCM.ROM or CM32L_PCM.ROM - PCM ROM file.");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("mt32.model",Property::Changeable::WhenIdle,"auto");
    Pstring->Set_help("Model of the MT-32 synthesizer to use.");
    Pstring->Set_values(mt32models);
    Pstring->SetBasic(true);

    Pbool = secprop->Add_bool("mt32.reverse.stereo",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("Reverse stereo channels for MT-32 output");

    Pbool = secprop->Add_bool("mt32.verbose",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("MT-32 debug logging");

    Pbool = secprop->Add_bool("mt32.thread",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("MT-32 rendering in separate thread");

    const char *mt32chunk[] = {"2", "3", "16", "99", "100", nullptr };
    Pint = secprop->Add_int("mt32.chunk",Property::Changeable::WhenIdle,16);
    Pint->Set_values(mt32chunk);
    Pint->SetMinMax(2,100);
    Pint->Set_help("Minimum milliseconds of data to render at once. (min 2, max 100)\n"
        "Increasing this value reduces rendering overhead which may improve performance but also increases audio lag.\n"
        "Valid for rendering in separate thread only.");

    const char *mt32prebuffer[] = {"3", "4", "32", "199", "200", nullptr };
    Pint = secprop->Add_int("mt32.prebuffer",Property::Changeable::WhenIdle,32);
    Pint->Set_values(mt32prebuffer);
    Pint->SetMinMax(3,200);
    Pint->Set_help("How many milliseconds of data to render ahead. (min 3, max 200)\n"
        "Increasing this value may help to avoid underruns but also increases audio lag.\n"
        "Cannot be set less than or equal to mt32.chunk value.\n"
        "Valid for rendering in separate thread only.");

    Pint = secprop->Add_int("mt32.partials",Property::Changeable::WhenIdle,32);
    Pint->Set_values(mt32partials);
    Pint->SetMinMax(8,256);
    Pint->Set_help("The maximum number of partials playing simultaneously. (min 8, max 256)");

    Pint = secprop->Add_int("mt32.dac",Property::Changeable::WhenIdle,0);
    Pint->Set_values(mt32DACModes);
    Pint->Set_help("MT-32 DAC input emulation mode\n"
        "Nice = 0 - default\n"
        "Produces samples at double the volume, without tricks.\n"
        "Higher quality than the real devices\n\n"

        "Pure = 1\n"
        "Produces samples that exactly match the bits output from the emulated LA32.\n"
        "Nicer overdrive characteristics than the DAC hacks (it simply clips samples within range)\n"
        "Much less likely to overdrive than any other mode.\n"
        "Half the volume of any of the other modes, meaning its volume relative to the reverb\n"
        "output when mixed together directly will sound wrong. So, reverb level must be lowered.\n"
        "Perfect for developers while debugging :)\n\n"

        "GENERATION1 = 2\n"
        "Re-orders the LA32 output bits as in early generation MT-32s (according to Wikipedia).\n"
        "Bit order at DAC (where each number represents the original LA32 output bit number, and XX means the bit is always low):\n"
        "15 13 12 11 10 09 08 07 06 05 04 03 02 01 00 XX\n\n"

        "GENERATION2 = 3\n"
        "Re-orders the LA32 output bits as in later generations (personally confirmed on my CM-32L - KG).\n"
        "Bit order at DAC (where each number represents the original LA32 output bit number):\n"
        "15 13 12 11 10 09 08 07 06 05 04 03 02 01 00 14");

    const char *mt32analogModes[] = {"0", "1", "2", "3", nullptr };
    Pint = secprop->Add_int("mt32.analog",Property::Changeable::WhenIdle,2);
    Pint->Set_values(mt32analogModes);
    Pint->Set_help("MT-32 analogue output emulation mode\n"
        "Digital = 0\n"
        "Only digital path is emulated. The output samples correspond to the digital output signal appeared at the DAC entrance.\n"
        "Fastest mode.\n\n"

        "Coarse = 1\n"
        "Coarse emulation of LPF circuit. High frequencies are boosted, sample rate remains unchanged.\n"
        "A bit better sounding but also a bit slower.\n\n"

        "Accurate = 2 - default\n"
        "Finer emulation of LPF circuit. Output signal is upsampled to 48 kHz to allow emulation of audible mirror spectra above 16 kHz,\n"
        "which is passed through the LPF circuit without significant attenuation.\n"
        "Sounding is closer to the analog output from real hardware but also slower than the modes 0 and 1.\n\n"

        "Oversampled = 3\n"
        "Same as the default mode 2 but the output signal is 2x oversampled, i.e. the output sample rate is 96 kHz.\n"
        "Even slower than all the other modes but better retains highest frequencies while further resampled in DOSBox-X mixer.");

    Pint = secprop->Add_int("mt32.output.gain", Property::Changeable::WhenIdle, 100);
    Pint->SetMinMax(0,1000);
    Pint->Set_help("Output gain of MT-32 emulation in percent, 100 is the default value, the allowed maximum is 1000.");

    Pstring = secprop->Add_string("mt32.reverb.mode",Property::Changeable::WhenIdle,"auto");
    Pstring->Set_values(mt32reverbModes);
    Pstring->Set_help("MT-32 reverb mode");

    Pint = secprop->Add_int("mt32.reverb.output.gain", Property::Changeable::WhenIdle, 100);
    Pint->SetMinMax(0,1000);
    Pint->Set_help("Reverb output gain of MT-32 emulation in percent, 100 is the default value, the allowed maximum is 1000.");

    Pint = secprop->Add_int("mt32.reverb.time",Property::Changeable::WhenIdle,5);
    Pint->Set_values(mt32reverbTimes);
    Pint->Set_help("MT-32 reverb decaying time");

    Pint = secprop->Add_int("mt32.reverb.level",Property::Changeable::WhenIdle,3);
    Pint->Set_values(mt32reverbLevels);
    Pint->Set_help("MT-32 reverb level");

    Pint = secprop->Add_int("mt32.rate", Property::Changeable::WhenIdle, 48000);
    Pint->Set_values(rates);
    Pint->Set_help("Sample rate of MT-32 emulation.");

    const char *mt32srcQuality[] = {"0", "1", "2", "3", nullptr };
    Pint = secprop->Add_int("mt32.src.quality", Property::Changeable::WhenIdle, 2);
    Pint->Set_values(mt32srcQuality);
    Pint->Set_help("MT-32 sample rate conversion quality\n"
        "Value '0' is for the fastest conversion, value '3' provides for the best conversion quality. Default is 2.");

    Pbool = secprop->Add_bool("mt32.niceampramp", Property::Changeable::WhenIdle, true);
    Pbool->Set_help("Toggles \"Nice Amp Ramp\" mode that improves amplitude ramp for sustaining instruments.\n"
        "Quick changes of volume or expression on a MIDI channel may result in amp jumps on real hardware.\n"
        "When \"Nice Amp Ramp\" mode is enabled (default), amp changes gradually instead.\n"
        "Otherwise, the emulation accuracy is preserved.");
    Pbool = secprop->Add_bool("mt32.engage.channel1", Property::Changeable::WhenIdle, false);
    Pbool->Set_help("Use alternative channel assignment on synth start.\n"
         "By default, MT-32 compatible devices only react on MIDI messages that come on MIDI channels 2-10 ignoring messages\n"
         "on MIDI channel 1. However, some tunes involve MIDI channel 1 yet do not initialise the device accordingly.\n"
         "In such cases, one might fix this by pressing a magic button combination on MT-32 front panel.\n"
         "Enabling this property has the same effect: the device starts recognising messages on MIDI channels 1-8 and 10 instead.\n"
         "Default is false.");

#if C_FLUIDSYNTH || defined(WIN32) && !defined(HX_DOS)
	const char *fluiddrivers[] = {"pulseaudio", "alsa", "oss", "coreaudio", "dsound", "portaudio", "sndman", "jack", "file", "default", nullptr };
	Pstring = secprop->Add_string("fluid.driver",Property::Changeable::WhenIdle,"default");
	Pstring->Set_values(fluiddrivers);
	Pstring->Set_help("Driver to use with Fluidsynth, not needed under Windows. Available drivers depend on what Fluidsynth was compiled with.");
    Pstring->SetBasic(true);

	Pstring = secprop->Add_string("fluid.soundfont",Property::Changeable::WhenIdle,"");
	Pstring->Set_help("Soundfont (.SF2 or .SF3) to use with Fluidsynth. One must be specified (e.g. GeneralUser_GS.sf2).");
    Pstring->SetBasic(true);

	Pstring = secprop->Add_string("fluid.samplerate",Property::Changeable::WhenIdle,"48000");
	Pstring->Set_help("Sample rate to use with Fluidsynth.");

	Pstring = secprop->Add_string("fluid.gain",Property::Changeable::WhenIdle,".2");
	Pstring->Set_help("Fluidsynth gain.");

	Pint = secprop->Add_int("fluid.polyphony",Property::Changeable::WhenIdle,256);
	Pint->Set_help("Fluidsynth polyphony.");

	Pstring = secprop->Add_string("fluid.cores",Property::Changeable::WhenIdle,"default");
	Pstring->Set_help("Fluidsynth CPU cores to use, or default.");

	Pstring = secprop->Add_string("fluid.periods",Property::Changeable::WhenIdle,"default");
	Pstring->Set_help("Fluidsynth periods, or default.");

	Pstring = secprop->Add_string("fluid.periodsize",Property::Changeable::WhenIdle,"default");
	Pstring->Set_help("Fluidsynth period size, or default.");

	const char *fluidreverb[] = {"no", "yes", nullptr };
	Pstring = secprop->Add_string("fluid.reverb",Property::Changeable::WhenIdle,"yes");
	Pstring->Set_values(fluidreverb);
	Pstring->Set_help("Fluidsynth use reverb.");

	const char *fluidchorus[] = {"no", "yes", nullptr };
	Pstring = secprop->Add_string("fluid.chorus",Property::Changeable::WhenIdle,"yes");
	Pstring->Set_values(fluidchorus);
	Pstring->Set_help("Fluidsynth use chorus.");

	Pstring = secprop->Add_string("fluid.reverb.roomsize",Property::Changeable::WhenIdle,".61");
	Pstring->Set_help("Fluidsynth reverb room size.");

	Pstring = secprop->Add_string("fluid.reverb.damping",Property::Changeable::WhenIdle,".23");
	Pstring->Set_help("Fluidsynth reverb damping.");

	Pstring = secprop->Add_string("fluid.reverb.width",Property::Changeable::WhenIdle,".76");
	Pstring->Set_help("Fluidsynth reverb width.");

	Pstring = secprop->Add_string("fluid.reverb.level",Property::Changeable::WhenIdle,".57");
	Pstring->Set_help("Fluidsynth reverb level.");

	Pint = secprop->Add_int("fluid.chorus.number",Property::Changeable::WhenIdle,3);
	Pint->Set_help("Fluidsynth chorus voices");

	Pstring = secprop->Add_string("fluid.chorus.level",Property::Changeable::WhenIdle,"1.2");
	Pstring->Set_help("Fluidsynth chorus level.");

	Pstring = secprop->Add_string("fluid.chorus.speed",Property::Changeable::WhenIdle,".3");
	Pstring->Set_help("Fluidsynth chorus speed.");

	Pstring = secprop->Add_string("fluid.chorus.depth",Property::Changeable::WhenIdle,"8.0");
	Pstring->Set_help("Fluidsynth chorus depth.");

	const char *fluidchorustypes[] = {"0", "1", nullptr };
	Pint = secprop->Add_int("fluid.chorus.type",Property::Changeable::WhenIdle,0);
	Pint->Set_values(fluidchorustypes);
	Pint->Set_help("Fluidsynth chorus type. 0 is sine wave, 1 is triangle wave.");
#endif

	{
		const char *secname;
		const unsigned short int def_sbbase[2] = {0x220,0x260}; /* 0x240 by default is occupied by the GUS */
		const unsigned char def_irq[2] = {7,3}; /* 5 by default occupied by the GUS */
		const unsigned char def_dma[2] = {1,0}; /* 3 by default occupied by the GUS */
		const unsigned char def_hdma[2] = {5,7};
		const char *def_sbtype[2] = {"sb16","none"}; /* second card off by default */
		for (size_t ci=0;(secname=sbGetSectionName(ci))!=NULL;ci++) {
			secprop=control->AddSection_prop(secname,&Null_Init,true);

			Pstring = secprop->Add_string("sbtype",Property::Changeable::WhenIdle,def_sbtype[ci]);//"sb16"
			Pstring->Set_values(sbtypes);
			Pstring->Set_help("Type of Sound Blaster to emulate. 'gb' is Game Blaster.");
			Pstring->SetBasic(true);

			Phex = secprop->Add_hex("sbbase",Property::Changeable::WhenIdle,def_sbbase[ci]);//0x220
			Phex->Set_values(ios);
			Phex->Set_help("The IO address of the Sound Blaster.\n"
					"220h to 2E0h are for use with IBM PC Sound Blaster emulation.\n"
					"D2h to DEh are for use with NEC PC-98 Sound Blaster 16 emulation.");
			Phex->SetBasic(true);

			Pint = secprop->Add_int("irq",Property::Changeable::WhenIdle,def_irq[ci]);//7
			Pint->Set_values(irqssb);
			Pint->Set_help("The IRQ number of the Sound Blaster (usually 5 or 7, depending on the sound card type and the game).\n"
					"Set to 0 for the default setting of the sound card, or set to -1 to start DOSBox-X with the IRQ unassigned.");
			Pint->SetBasic(true);

			Pint = secprop->Add_int("mindma",Property::Changeable::OnlyAtStart,-1);
			Pint->Set_help( "Minimum DMA transfer left to increase attention across DSP blocks, in milliseconds. Set to -1 for default.\n"
					"There are some DOS games/demos that use single-cycle DSP playback in their music tracker and they micromanage\n"
					"the DMA transfer per block poorly in a way that causes popping and artifacts. Setting this option to 0 for\n"
					"such DOS applications may reduce audible popping and artifacts.");

			Pbool = secprop->Add_bool("listen to recording source",Property::Changeable::WhenIdle,false);
			Pbool->Set_help("When the guest records audio from the Sound Blaster card, send the input source to the speakers as well so it can be heard.");
			Pbool->SetBasic(true);

			Pstring = secprop->Add_string("recording source",Property::Changeable::WhenIdle,"silence");
			Pstring->Set_values(sb_recording_sources);
			Pstring->Set_help("Audio source to use when guest is recording audio. Options: silence, hiss, 1khz tone, or microphone (Windows WASAPI input).");
			Pstring->SetBasic(true);

            Pbool = secprop->Add_bool("prefer hfp", Property::Changeable::WhenIdle, false);
            Pbool->Set_help(
                "Prefer Bluetooth HFP (Hands-Free Profile) microphone mode.\n"
                "This allows using the microphone of a BT headset but reduces\n"
                "audio quality (typically 8kHz–16kHz telephone quality).\n"
                "When disabled, higher-quality microphones are preferred."
            );
            Pbool->SetBasic(true);

			/* Sound Blaster IRQ hacks.
			 *
			 * These hacks reduce emulation accuracy but can be set to work around bugs or mistakes in some old
			 * games and demos related to handling the Sound Blaster IRQ.
			 *
			 * - Saga by Dust (1993):
			 *     Sound Blaster support has a fatal flaw in that the Sound Blaster interrupt handler it installs assumes
			 *     DS == CS. It uses the DS register to read local variables needed to manage the Sound Blaster card but
			 *     it makes no attempt to push DS and then load the DS segment value it needs. While the demo may seem to
			 *     run normally at first, eventually the interrupt is fired at just the right time to catch the demo in
			 *     the middle of its graphics routines (DS=A000). Since the ISR uses DS to load the Sound Blaster DSP
			 *     I/O port, it reads some random value from *video RAM* and then hangs in a loop waiting for that I/O
			 *     port to clear bit 7! Setting 'cs_equ_ds' works around that bug by instructing PIC emulation not to
			 *     fire the interrupt unless segment registers CS and DS match. */
			Pstring = secprop->Add_string("irq hack",Property::Changeable::WhenIdle,"none");
			Pstring->Set_help("Specify a hack related to the Sound Blaster IRQ to avoid crashes in a handful of games and demos.\n"
					"    none                   Emulate IRQs normally\n"
					"    cs_equ_ds              Do not fire IRQ unless two CPU segment registers match: CS == DS. Read DOSBox-X Wiki or source code for details.");

			Pint = secprop->Add_int("dma",Property::Changeable::WhenIdle,def_dma[ci]);//1
			Pint->Set_values(dmassb);
			Pint->Set_help("The DMA number of the Sound Blaster. Set to -1 to start DOSBox-X with the DMA unassigned.");
			Pint->SetBasic(true);

			Pint = secprop->Add_int("hdma",Property::Changeable::WhenIdle,def_hdma[ci]);//5
			Pint->Set_values(dmassb);
			Pint->Set_help("The High DMA number of the Sound Blaster. Set to -1 to start DOSBox-X with the High DMA unassigned.");
			Pint->SetBasic(true);

			Pbool = secprop->Add_bool("dsp command aliases",Property::Changeable::WhenIdle,true);
			Pbool->Set_help("If set (on by default), emulation will support known undocumented aliases\n"
					"of common Sound Blaster DSP commands. Some broken DOS games and demos rely on these aliases.\n"
					"For more information: https://www.vogons.org/viewtopic.php?f=62&t=61098&start=280");

			Pbool = secprop->Add_bool("pic unmask irq",Property::Changeable::WhenIdle,false);
			Pbool->Set_help("Start the DOS virtual machine with the Sound Blaster IRQ already unmasked at the PIC.\n"
					"Some early DOS games/demos that support Sound Blaster expect the IRQ to fire but make\n"
					"no attempt to unmask the IRQ. If audio cuts out no matter what IRQ you try, then try\n"
					"setting this option.\n"
					"Option is needed for:\n"
					"   Public NMI \"jump\" demo (1992)");

			Pbool = secprop->Add_bool("enable speaker",Property::Changeable::WhenIdle,false);
			Pbool->Set_help("Start the DOS virtual machine with the Sound Blaster speaker enabled.\n"
					"Sound Blaster Pro and older cards have a speaker disable/enable command.\n"
					"Normally the card boots up with the speaker disabled. If a DOS game or demo\n"
					"attempts to play without enabling the speaker, set this option to true to\n"
					"compensate. This setting has no meaning if emulating a Sound Blaster 16 card.");
			Pbool->SetBasic(true);

			Pbool = secprop->Add_bool("enable asp",Property::Changeable::WhenIdle,false);
			Pbool->Set_help("If set, emulate the presence of the Sound Blaster 16 Advanced Sound Processor/Creative Sound Processor chip.\n"
					"NOTE: This only emulates its presence and the basic DSP commands to communicate with it. Actual ASP/CSP functions are not yet implemented.");

			Pbool = secprop->Add_bool("disable filtering",Property::Changeable::WhenIdle,false);
			Pbool->Set_help("By default DOSBox-X filters Sound Blaster output to emulate lowpass filters and analog output limitations.\n"
					"Set this option to true to disable filtering. Note that doing so disables emulation of the Sound Blaster Pro\n"
					"output filter and ESS AudioDrive lowpass filter.");

			Pbool = secprop->Add_bool("dsp write buffer status must return 0x7f or 0xff",Property::Changeable::WhenIdle,false);
			Pbool->Set_help("If set, force port 22Ch (DSP write buffer status) to return 0x7F or 0xFF. If not set, the port\n"
					"may return 0x7F or 0xFF depending on what type of Sound Blaster is being emulated.\n"
					"Set this option for some early DOS demos that make that assumption about port 22Ch.\n"
					"Option is needed for:\n"
					"   Overload by Hysteria (1992) - Audio will crackle/saturate (8-bit overflow) except when sbtype=sb16");

			Pbool = secprop->Add_bool("pre-set sbpro stereo",Property::Changeable::WhenIdle,false);
			Pbool->Set_help("Start the DOS virtual machine with the Sound Blaster Pro stereo bit set (in the mixer).\n"
					"A few demos support Sound Blaster Pro but forget to set this bit.\n"
					"Option is needed for:\n"
					"   Inconexia by Iguana (1993)");

			Pbool = secprop->Add_bool("sbmixer",Property::Changeable::WhenIdle,true);
			Pbool->Set_help("Allow the Sound Blaster mixer to modify the DOSBox-X mixer.");
			Pbool->SetBasic(true);

			Pstring = secprop->Add_string("cms", Property::Changeable::WhenIdle, ci==0?"auto":"off");
			Pstring->Set_values(cms_settings);
			Pstring->Set_help(
					"Enable CMS emulation ('auto' by default).\n"
					"  off:   Disable CMS emulation (except when the Game Blaster is selected).\n"
					"  on:    Enable CMS emulation on Sound Blaster 1 and 2.\n"
					"  auto:  Auto-enable CMS emulation for Sound Blaster 1 and Game Blaster.");

			Pstring = secprop->Add_string("oplmode",Property::Changeable::WhenIdle, ci==0?"auto":"none");
			Pstring->Set_values(oplmodes);
			Pstring->Set_help("Type of OPL emulation. On 'auto' the mode is determined by the 'sbtype' setting.\n"
					"All OPL modes are AdLib-compatible.");
			Pstring->SetBasic(true);

			Pbool = secprop->Add_bool("adlib pcm boost",Property::Changeable::WhenIdle,false);
			Pbool->Set_help("If set, and Adlib emulation detects that the guest application is playing digitized speech\n"
					"or music through the FM chip, the FM audio will be amplified to make the audio more audible.\n"
					"Audio levels will be reset for any other use including FM music synthesis.");

			Pbool = secprop->Add_bool("adlib force timer overflow on detect",Property::Changeable::WhenIdle,false);
			Pbool->Set_help("If set, Adlib/OPL emulation will signal 'overflow' on timers after 50 I/O reads.\n"
					"This is a temporary hack to work around timing bugs noted in DOSBox-X. Certain\n"
					"games (Wolfenstein 3D) poll the Adlib status port a fixed number of times assuming\n"
					"that the poll loop takes long enough for the Adlib timer to run out. If the game\n"
					"cannot reliably detect Adlib at higher cycles counts, but can reliably detect at\n"
					"lower cycles counts, set this option.");
			/* NTS: The reason I mention Wolfenstein 3D is that it seems coded not to probe for Sound Blaster unless it
			 *      first detects the Adlib at port 0x388. No Adlib, no Sound Blaster. */
			/* ^ NTS: To see what I mean, download Wolf3d source code, look at ID_SD.C line 1585 (Adlib detection routine).
			 *        Note it sets Timer 1, then reads port 388h 100 times before reading status to detect whether the
			 *        timer "overflowed" (fairly typical Adlib detection code).
			 *        Some quick math: 8333333Hz ISA BCLK / 6 cycles per read (3 wait states) = 1388888 reads/second possible
			 *                         100 I/O reads * (1 / 1388888) = 72us */

			Pstring = secprop->Add_string("oplemu",Property::Changeable::WhenIdle,"default");
			Pstring->Set_values(oplemus);
			Pstring->Set_help("Provider for the OPL emulation. 'compat' might provide better quality.\n"
					"'nuked' is the most accurate (but the most CPU-intensive). See oplrate as well.");
			Pstring->SetBasic(true);

			Pint = secprop->Add_int("oplrate",Property::Changeable::WhenIdle,49716);
			Pint->Set_values(rates);
			Pint->Set_help("Sample rate of OPL music emulation. Use 49716 for highest quality (set the mixer rate accordingly).");
			Pint->SetBasic(true);

			Pstring = secprop->Add_string("oplport", Property::Changeable::WhenIdle, "");
			Pstring->Set_help("Serial port of the OPL2 Audio Board when oplemu=opl2board, opl2mode will become 'opl2' automatically.");
			Pstring->SetBasic(true);

			Pstring = secprop->Add_string("retrowave_bus", Property::Changeable::WhenIdle, "serial");
			Pstring->Set_help("Bus of the Retrowave series board (serial/spi). SPI is only supported on Linux.");
			Pstring->SetBasic(true);

			Pstring = secprop->Add_string("retrowave_spi_cs", Property::Changeable::WhenIdle, "0,6");
			Pstring->Set_help("SPI chip select pin of the Retrowave series board. Only supported on Linux.");

			Pstring = secprop->Add_string("retrowave_port", Property::Changeable::WhenIdle, "");
			Pstring->Set_help("Serial port of the Retrowave series board.");
			Pstring->SetBasic(true);

			Phex = secprop->Add_hex("hardwarebase",Property::Changeable::WhenIdle,0x220);
			Phex->Set_help("base address of the real hardware Sound Blaster:\n"\
					"210,220,230,240,250,260,280");
			Phex->SetBasic(true);

			Pbool = secprop->Add_bool("force dsp auto-init",Property::Changeable::WhenIdle,false);
			Pbool->Set_help("Treat all single-cycle DSP commands as auto-init to keep playback going.\n"
					"This option is a workaround for DOS games or demos that use single-cycle DSP playback commands and\n"
					"have problems with missing the Sound Blaster IRQ under load. Do not enable unless you need this workaround.\n"
					"Needed for:\n"
					"  - Extreme \"lunatic\" demo (1993)");

			Pbool = secprop->Add_bool("force goldplay",Property::Changeable::WhenIdle,false);
			Pbool->Set_help("Always render Sound Blaster output sample-at-a-time. Testing option. You probably don't want to enable this.");

			Pbool = secprop->Add_bool("goldplay",Property::Changeable::WhenIdle,true);
			Pbool->Set_help("Enable goldplay emulation.");
			Pbool->SetBasic(true);

			Pbool = secprop->Add_bool("goldplay stereo",Property::Changeable::WhenIdle,true);
			Pbool->Set_help("Enable workaround for goldplay stereo playback. Many DOS demos using this technique\n"
					"don't seem to know they need to double the frequency when programming the DSP time constant for Pro stereo output.\n"
					"If stereo playback seems to have artifacts consider enabling this option. For accurate emulation of Sound Blaster\n"
					"hardware, disable this option.");

			Pstring = secprop->Add_string("dsp require interrupt acknowledge",Property::Changeable::WhenIdle,"auto");
			Pstring->Set_help("If set, the DSP will halt DMA playback until IRQ acknowledgement occurs even in auto-init mode (SB16 behavior).\n"
					"If clear, IRQ acknowledgement will have no effect on auto-init playback (SB Pro and earlier & clone behavior)\n"
					"If set to 'auto' then behavior is determined by sbtype= setting.\n"
					"This is a setting for hardware accuracy in emulation. If audio briefly plays then stops then your DOS game\n"
					"and it's not using IRQ (but using DMA), try setting this option to 'false'");

			Pint = secprop->Add_int("dsp write busy delay",Property::Changeable::WhenIdle,-1);
			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"
					"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"
					"         Setting the value way too high (above 1000000ns) can cause significant lag in DOS games.");

			Pbool = secprop->Add_bool("blaster environment variable",Property::Changeable::WhenIdle,ci == 0 ? true : false);
			Pbool->Set_help("Whether or not to set the BLASTER environment variable automatically at startup");
			Pbool->SetBasic(true);

			Pbool = secprop->Add_bool("sample rate limits",Property::Changeable::WhenIdle,true);
			Pbool->Set_help("If set (default), limit DSP sample rate to what real hardware is limited to");

			/* recommended for:
			 *   1992 demo "overload" (if set, Sound Blaster support can run at 24KHz without causing demo to hang in the IRQ 0 timer)
			 *   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 */
			Pbool = secprop->Add_bool("instant direct dac",Property::Changeable::WhenIdle,false);
			Pbool->Set_help("If set, direct DAC output commands are instantaneous. This option is intended as a quick fix for\n"
					"games or demos that play direct DAC music/sound from the IRQ 0 timer who a) write the DSP command\n"
					"and data without polling the DSP to ensure it's ready or b) can get locked into the IRQ 0 handler\n"
					"waiting for DSP status when instructed to play at or beyond the DSP's maximum direct DAC sample rate.\n"
					"This fix allows broken Sound Blaster code to work and should not be enabled unless necessary.");

			/* accuracy emulation: SB16 does not honor SBPro stereo bit in the mixer */
			Pbool = secprop->Add_bool("stereo control with sbpro only",Property::Changeable::WhenIdle,true);
			Pbool->Set_help("Default on. If set, Sound Blaster Pro stereo is not available when emulating sb16 or sb16vibra.\n"
					"If clear, sb16 emulation will honor the sbpro stereo bit. Note that Creative SB16 cards do not\n"
					"honor the stereo bit, and this option allows DOSBox-X emulate that fact. Accuracy setting.");

			/* NTS: It turns out (SB16 at least) the DSP will periodically set bit 7 (busy) by itself at some
			 *      clock rate even if it's idle. Casual testing on an old Pentium system with a ViBRA shows
			 *      it's possible to see both 0x7F and 0xFF come back if you repeatedly type "i 22c" in DOS
			 *      DEBUG.EXE.  FIXME: At what clock rate and duty cycle does this happen? */
			Pint = secprop->Add_int("dsp busy cycle rate",Property::Changeable::WhenIdle,-1/*default*/);
			Pint->Set_help("Sound Blaster 16 DSP chips appear to go busy periodically at some high clock rate\n"
					"whether the DSP is actually doing anything for the system or not. This is an accuracy\n"
					"option for Sound Blaster emulation. If this option is nonzero, it will be interpreted\n"
					"as the busy cycle rate in Hz. If zero, busy cycle will not be emulated. If -1, sound\n"
					"blaster emulation will automatically choose a setting based on the sbtype= setting");

			Pint = secprop->Add_int("dsp busy cycle always",Property::Changeable::WhenIdle,-1/*default*/);
			Pint->Set_help("If set, the DSP busy cycle always happens. If clear, DSP busy cycle only happens when\n"
					"audio playback is running. Default setting is to pick according to the sound card.");

			Pint = secprop->Add_int("dsp busy cycle duty",Property::Changeable::WhenIdle,-1/*default*/);
			Pint->Set_help("If emulating SB16 busy cycle, this value (0 to 100) controls the duty cycle of the busy cycle.\n"
					"If this option is set to -1, Sound Blaster emulation will choose a value automatically according\n"
					"to sbtype=. If 0, busy cycle emulation is disabled.");

			/* NTS: Confirmed: My Sound Blaster 2.0 (at least) mirrors the DSP on port 22Ch and 22Dh. This option
			 *      will only take effect with sbtype sb1 and sb2, so make it enabled by default. Accuracy setting. */
			Pbool = secprop->Add_bool("io port aliasing",Property::Changeable::WhenIdle,true);
			Pbool->Set_help("If set, Sound Blaster ports alias by not decoding the LSB of the I/O port.\n"
					"This option only applies when sbtype is set to sb1 or sb2 (not SBPro or SB16).\n"
					"This is a hack for the Electromotive Force 'Internal Damage' demo which apparently\n"
					"relies on this behavior for Sound Blaster output and should be enabled for accuracy in emulation.");
		}
	}

    secprop=control->AddSection_prop("gus",&Null_Init,true); //done
    Pbool = secprop->Add_bool("gus",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("Enable the Gravis Ultrasound emulation.");
    Pbool->SetBasic(true);

    Pstring = secprop->Add_string("global register read alias", Property::Changeable::WhenIdle, "auto");
    Pstring->Set_values(truefalseautoopt);
    Pstring->Set_help("If true, all GUS global registers have a read alias at N and N+0x80.\n"
                      "If false, only the voice registers 0x0-0xF have a read alias at 0x80-0x8F as officially documented.\n"
                      "If auto, automatically choose based on other settings such as GUS type.\n"
                      "This setting may be needed for DOS demoscene entries that assume aliasing behavior such as Out of Control by Contract.");
    Pstring->SetBasic(true);

    Pbool = secprop->Add_bool("warn on out of bounds dram access",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("Controls whether attempts to access GUS DRAM beyond the 1MB maximum supported by the card are logged to the log file as a warning.");

    Pbool = secprop->Add_bool("autoamp",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("If set, GF1 output will reduce in volume automatically if the sum of all channels exceeds full volume.\n"
                    "If not set, then loud music will clip to full volume just as it would on real hardware.\n"
                    "Enable this option for loud music if you want a more pleasing rendition without saturation and distortion.");

    Pbool = secprop->Add_bool("unmask dma",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("Start the DOS virtual machine with the DMA channel already unmasked at the controller.\n"
            "Use this for DOS applications that expect to operate the GUS but forget to unmask the DMA channel.");

    Pbool = secprop->Add_bool("ignore channel count while active",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("Ignore writes to the active channel count register when the DAC is enabled (bit 1 of GUS reset)\n"
                    "This is a HACK for demoscene prod 'Ice Fever' without which the music sounds wrong.\n"
                    "According to current testing real hardware does not behave this way.");

    Pbool = secprop->Add_bool("pic unmask irq",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("Start the DOS virtual machine with the GUS IRQ already unmasked at the PIC.");

    Pbool = secprop->Add_bool("startup initialized",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("If set, start the GF1 in a fully initialized state (as if ULTRINIT had been run).\n"
                    "If clear, leave the card in an uninitialized state (as if cold boot).\n"
                    "Some DOS games or demoscene productions will hang or fail to use the Ultrasound hardware\n"
                    "because they assume the card is initialized and their hardware detect does not fully initialize the card.");

    Pbool = secprop->Add_bool("dma enable on dma control polling",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("If set, automatically enable GUS DMA transfer bit in specific cases when the DMA control register is being polled.\n"
                    "THIS IS A HACK. Some games and demoscene productions need this hack to avoid hanging while uploading sample data\n"
                    "to the Gravis Ultrasound due to bugs in their implementation.");

    Pbool = secprop->Add_bool("clear dma tc irq if excess polling",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("If the DOS application is seen polling the IRQ status register rapidly, automatically clear the DMA TC IRQ status.\n"
            "This is a hack that should only be used with DOS applications that need it to avoid bugs in their GUS support code.\n"
            "Needed for:\n"
            "  Warcraft II by Blizzard ............. if using GUS for music and sound, set this option to prevent the game from\n"
            "                                        hanging when you click on the buttons in the main menu.");

    /* some DOS demos, especially where the programmers wrote their own tracker, forget to set "master IRQ enable" on the GUS,
     * and then wonder why music isn't playing. prior to some GUS bugfixes they happen to work anyway because DOSBox also
     * ignored master IRQ enable. you can restore that buggy behavior here.
     *
     * DOS games & demos that need this:
     *   - "Juice" by Psychic Link (writes 0x300 to GUS reset which only enables DAC and takes card out of reset, does not enable IRQ) */
    Pbool = secprop->Add_bool("force master irq enable",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("Set this option if a DOS game or demo initializes the GUS but is unable to play any music.\n"
            "Usually the cause is buggy GUS support that resets the GUS but fails to set the Master IRQ enable bit.");

    Pstring = secprop->Add_string("gus panning table",Property::Changeable::WhenIdle,"default");
    Pstring->Set_values(guspantables);
    Pstring->Set_help("Controls which table or equation is used for the Gravis Ultrasound panning emulation.\n"
            "accurate emulation attempts to better reflect how the actual hardware handles panning,\n"
            "while the old emulation uses a simpler idealistic mapping.");

    Pint = secprop->Add_int("gusrate",Property::Changeable::WhenIdle,48000);
    Pint->Set_values(rates);
    Pint->Set_help("Sample rate of Ultrasound emulation.");
    Pint->SetBasic(true);

    Pbool = secprop->Add_bool("gus fixed render rate",Property::Changeable::WhenIdle,false);
    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"
            "if desired. Else, Gravis Ultrasound emulation will change the sample rate of its output according to the number of active channels, just like real hardware.\n"
            "Note: DOSBox-X defaults to 'false', while mainline DOSBox SVN is currently hardcoded to render as if this setting is 'true'.");

    Pint = secprop->Add_int("gusmemsize",Property::Changeable::WhenIdle,-1);
    Pint->SetMinMax(-1,8192);
    Pint->Set_help("Amount of RAM on the Gravis Ultrasound in KB. Set to -1 for default.");
    Pint->SetBasic(true);

    Pdouble = secprop->Add_double("gus master volume",Property::Changeable::WhenIdle,0);
    Pdouble->SetMinMax(-120.0,6.0);
    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.");
    Pdouble->SetBasic(true);

    Phex = secprop->Add_hex("gusbase",Property::Changeable::WhenIdle,0x240);
    Phex->Set_values(iosgus);
    Phex->Set_help("The IO base address of the Gravis Ultrasound.");
    Phex->SetBasic(true);

    Pint = secprop->Add_int("gusirq",Property::Changeable::WhenIdle,5);
    Pint->Set_values(irqsgus);
    Pint->Set_help("The IRQ number of the Gravis Ultrasound.");
    Pint->SetBasic(true);

    Pint = secprop->Add_int("gusdma",Property::Changeable::WhenIdle,3);
    Pint->Set_values(dmasgus);
    Pint->Set_help("The DMA channel of the Gravis Ultrasound.");
    Pint->SetBasic(true);

    Pstring = secprop->Add_string("irq hack",Property::Changeable::WhenIdle,"none");
    Pstring->Set_help("Specify a hack related to the Gravis Ultrasound IRQ to avoid crashes in a handful of games and demos.\n"
            "    none                   Emulate IRQs normally\n"
            "    cs_equ_ds              Do not fire IRQ unless two CPU segment registers match: CS == DS. Read DOSBox-X Wiki or source code for details.");

    Pstring = secprop->Add_string("gustype",Property::Changeable::WhenIdle,"classic");
    Pstring->Set_values(gustypes);
    Pstring->Set_help(  "Type of Gravis Ultrasound to emulate.\n"
                "classic             Original Gravis Ultrasound chipset\n"
                "classic37           Original Gravis Ultrasound with ICS Mixer (rev 3.7)\n"
                "max                 Gravis Ultrasound MAX emulation (with CS4231 codec)\n"
                "interwave           Gravis Ultrasound Plug & Play (interwave)");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("ultradir",Property::Changeable::WhenIdle,"C:\\ULTRASND");
    Pstring->Set_help(
        "Path to Ultrasound directory. In this directory\n"
        "there should be a MIDI directory that contains\n"
        "the patch files for GUS playback. Patch sets used\n"
        "with Timidity should work fine.");
    Pstring->SetBasic(true);

    secprop = control->AddSection_prop("innova",&Null_Init,true);//done
    Pbool = secprop->Add_bool("innova",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("Enable the Innovation SSI-2001 emulation.");
    Pbool->SetBasic(true);
    Pint = secprop->Add_int("samplerate",Property::Changeable::WhenIdle,22050);
    Pint->Set_values(rates);
    Pint->Set_help("Sample rate of Innovation SSI-2001 emulation");
    Pint->SetBasic(true);
    Phex = secprop->Add_hex("sidbase",Property::Changeable::WhenIdle,0x280);
    Phex->Set_values(sidbaseno);
    Phex->Set_help("SID base port (typically 280h).");
    Phex->SetBasic(true);
    Pint = secprop->Add_int("quality",Property::Changeable::WhenIdle,0);
    Pint->Set_values(qualityno);
    Pint->Set_help("Set SID emulation quality level (0 to 3).");
    Pint->SetBasic(true);

    secprop = control->AddSection_prop("imfc", &Null_Init, Property::Changeable::WhenIdle);
    Pbool = secprop->Add_bool("imfc", Property::Changeable::WhenIdle, false);
    Pbool->Set_help("Enable the IBM Music Feature Card (disabled by default).");
    Phex = secprop->Add_hex("imfc_base", Property::Changeable::WhenIdle, 0x2A20);
    const char* const bases[] = { "2A20", "2A30", nullptr };
    Phex->Set_values(bases);
    Phex->Set_help("The IO base address of the IBM Music Feature Card (2A20 by default).");
    Pint = secprop->Add_int("imfc_irq", Property::Changeable::WhenIdle, 3);
    const char* const irqs[] = { "2", "3", "4", "5", "6", "7", nullptr };
    Pint->Set_values(irqs);
    Pint->Set_help("The IRQ number of the IBM Music Feature Card (3 by default).");
    Pstring = secprop->Add_string("imfc_filter", Property::Changeable::WhenIdle, "on");
    Pstring->Set_help(
        "Filter for the IBM Music Feature Card output:\n"
        "  on:        Filter the output (default).\n"
        "  off:       Don't filter the output.");

    secprop = control->AddSection_prop("speaker",&Null_Init,true);//done
    Pbool = secprop->Add_bool("pcspeaker",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("Enable PC-Speaker emulation.");
    Pbool->SetBasic(true);

    /* added for "baoxiao-sanguozhi" which for some reason uses both port 61h bit 4 (DRAM refresh) and PIT timer 2 (PC speaker)
     * 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
     * bit wasn't set, the game will hang when asking for a password. Setting this option to "true" tells the BIOS to start the
     * system with that bit set so games like that can run. [https://github.com/joncampbell123/dosbox-x/issues/1274].
     *
     * Note that setting clock gate enable will not make audible sound through the PC speaker unless bit 1 (output gate enable)
     * is also set. Setting bits [1:0] = to 01 is a way to cycle PIT timer 2 without making audible noise. */
    Pbool = secprop->Add_bool("pcspeaker clock gate enable at startup",Property::Changeable::WhenIdle,false);
    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"
                    "This option has no effect in PC-98 mode.");

    Pint = secprop->Add_int("initial frequency",Property::Changeable::WhenIdle,-1);
    Pint->Set_help("PC speaker PIT timer is programmed to this frequency on startup. If the DOS game\n"
            "or demo causes a long audible beep at startup (leaving the gate open) try setting\n"
            "this option to 0 to silence the PC speaker until reprogrammed by the demo.\n"
            "Set to 0 for some early Abaddon demos including \"Torso\" and \"Cycling\".");

    Pint = secprop->Add_int("pcrate",Property::Changeable::WhenIdle,65536);
    Pint->Set_values(pcrates);
    Pint->Set_help("Sample rate of the PC-Speaker sound generation.");
    Pint->SetBasic(true);

    Pstring = secprop->Add_string("tandy",Property::Changeable::WhenIdle,"auto");
    Pstring->Set_values(tandys);
    Pstring->Set_help("Enable Tandy Sound System emulation. For 'auto', emulation is present only if machine is set to 'tandy'.");
    Pstring->SetBasic(true);

    Pint = secprop->Add_int("tandyrate",Property::Changeable::WhenIdle,48000);
    Pint->Set_values(rates);
    Pint->Set_help("Sample rate of the Tandy 3-Voice generation.");
    Pint->SetBasic(true);

    Pbool = secprop->Add_bool("disney",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("Enable Disney Sound Source emulation. (Covox Voice Master and Speech Thing compatible).");
    Pbool->SetBasic(true);
    Pstring = secprop->Add_string("ps1audio",Property::Changeable::WhenIdle,"off");
    Pstring->Set_values(ps1opt);
    Pstring->Set_help("Enable PS1 audio emulation.");
    Pstring->SetBasic(true);
    Pint = secprop->Add_int("ps1audiorate",Property::Changeable::OnlyAtStart,22050);
    Pint->Set_values(rates);
    Pint->Set_help("Sample rate of the PS1 audio emulation.");
    Pint->SetBasic(true);

    secprop=control->AddSection_prop("joystick",&Null_Init,false);//done
    Pstring = secprop->Add_string("joysticktype",Property::Changeable::WhenIdle,"auto");
    Pstring->Set_values(joytypes);
    Pstring->Set_help(
        "Type of joystick to emulate: auto (default),\n"
        "none (disables joystick emulation),\n"
        "2axis (supports two joysticks),\n"
        "4axis (supports one joystick, first joystick used),\n"
        "4axis_2 (supports one joystick, second joystick used),\n"
        "fcs (Thrustmaster), ch (CH Flightstick).\n"
        "auto chooses emulation depending on real joystick(s).\n"
        "(Remember to reset DOSBox-X's mapperfile if you saved it earlier)");
    Pstring->SetBasic(true);

    Pbool = secprop->Add_bool("timed",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("enable timed intervals for axis. Experiment with this option, if your joystick drifts (away).");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("autofire",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("continuously fires as long as you keep the button pressed.");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("swap34",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("swap the 3rd and the 4th axis. can be useful for certain joysticks.");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("buttonwrap",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("enable button wrapping at the number of emulated buttons.");
    Pbool->SetBasic(true);

	/*improved joystick
	 * each axis has its own deadzone and response
	 * each axis index can be remapped, e.g. fix poor driver mappings
	 */

	/* logical axes settings*/
	std::vector<int> sticks = { 2, 1 };
	for (auto i = 0u; i < sticks.size(); i++)
	{
		const auto count = sticks[i];
		for (auto j = 0; j < count; j++)
		{
			const auto joy = std::to_string(i + 1);
			const auto stick = std::to_string(j + 1);
			const auto name = "joy" + joy + "deadzone" + stick;
			const auto help = "deadzone for joystick " + joy + " thumbstick " + stick + ".";
			Pdouble = secprop->Add_double(name, Property::Changeable::WhenIdle, 0.25);
			Pdouble->SetMinMax(0.0, 1.0);
			Pdouble->Set_help(help);
		}
	}
	for (auto i = 0u; i < sticks.size(); i++)
	{
		const auto count = sticks[i];
		for (auto j = 0; j < count; j++)
		{
			const auto joy = std::to_string(i + 1);
			const auto stick = std::to_string(j + 1);
			const auto name = "joy" + joy + "response" + stick;
			const auto help = "response for joystick " + joy + " thumbstick " + stick + ".";
			Pdouble = secprop->Add_double(name, Property::Changeable::WhenIdle, 1.0);
			Pdouble->SetMinMax(-5.0, 5.0);
			Pdouble->Set_help(help);
		}
	}

	const auto joysticks = 2;
	const auto axes = 8;
	for (auto i = 0; i < joysticks; i++)
	{
		for (auto j = 0; j < axes; j++)
		{
			const auto joy = std::to_string(i + 1);
			const auto axis = std::to_string(j);
			const auto propname = "joy" + joy + "axis" + axis;
			Pint = secprop->Add_int(propname, Property::Changeable::WhenIdle, j);
			Pint->SetMinMax(0, axes - 1);
			const auto help = "axis for joystick " + joy + " axis " + axis + ".";
			Pint->Set_help(help);
		}
	}
	/*physical axes settings*/
	secprop = control->AddSection_prop("mapper", &Null_Init, true);

	const auto directions = 2;
	for (auto i = 0; i < joysticks; i++)
	{
		for (auto j = 0; j < axes; j++)
		{
			for (auto k = 0; k < directions; k++)
			{
				const auto joy = std::to_string(i + 1);
				const auto axis = std::to_string(j);
				const auto dir = k == 0 ? "-" : "+";
				const auto name = "joy" + joy + "deadzone" + axis + dir;
				Pdouble = secprop->Add_double(name, Property::Changeable::WhenIdle, 0.6);
				Pdouble->SetMinMax(0.0, 1.0);
				const auto help = "deadzone for joystick " + joy + " axis " + axis + dir;
				Pdouble->Set_help(help);
				Pdouble->SetBasic(true);
			}
		}
	}


    secprop=control->AddSection_prop("serial",&Null_Init,true);

    Pmulti_remain = secprop->Add_multiremain("serial1",Property::Changeable::WhenIdle," ");
    Pstring = Pmulti_remain->GetSection()->Add_string("type",Property::Changeable::WhenIdle,"dummy");
    Pmulti_remain->SetValue("dummy",/*init*/true);
    Pstring->Set_values(serials);
    Pmulti_remain->SetBasic(true);
    Pmulti_remain->GetSection()->Add_string("parameters",Property::Changeable::WhenIdle,"");
    Pmulti_remain->Set_help(
        "serial1-9 -- set type of device connected to the serial (COM) port.\n"
        "Can be disabled, dummy, file, modem, nullmodem, directserial.\n"
        "Additional parameters must be in the same line in the form of\n"
        "parameter:value. Parameter for all types is irq (optional).\n"
        "for file: specify an output file\n"
        "Additional parameters:\n"
        "    timeout:<milliseconds> = how long to wait before closing the file on inactivity (default:0),\n"
        "    squote to use single quotes instead of double quotes for quoted program commands.\n"
        "    shellhide to hide the command window when opening programs on the Windows platform.\n"
        "    openwith:<program>: start a program to open the output file.\n"
        "    openerror:<program>: start a program to open the output file if an error had occurred.\n"
        "    multiplier:<x>: Actual baud rate is the programmed rate times X to allow rates higher than 115200.\n"
        "Example: serial1=file file:output1.txt timeout:1000 openwith:notepad\n"
        "for directserial: realport (required), rxdelay (optional).\n"
        "                 (realport:COM1 realport:ttyS0).\n"
        "for modem: listenport (optional).\n"
        "for nullmodem: server, rxdelay, txdelay, telnet, usedtr,\n"
        "               transparent, port, inhsocket, sock, nonlocal (all optional).\n"
        "               connections are limited to localhost unless you specify nonlocal:1\n"
        "               \"sock\" parameter specifies the protocol to be used by both sides\n"
        "               of the connection. 0 for TCP and 1 for ENet reliable UDP.\n"
        "Example: serial1=modem listenport:5000 sock:1\n"
        "Note: COM1-4 are standard COM ports in DOS, whereas COM5-9 are extended COM ports.\n"
        "      You can optionally specify base addresses and IRQs for them with base: and irq: options.\n"
        "      Serial port settings can also be changed via the built-in SERIAL command."
        );
    Pmulti_remain->SetBasic(true);

    Pmulti_remain = secprop->Add_multiremain("serial2",Property::Changeable::WhenIdle," ");
    Pstring = Pmulti_remain->GetSection()->Add_string("type",Property::Changeable::WhenIdle,"dummy");
    Pmulti_remain->SetValue("dummy",/*init*/true);
    Pstring->Set_values(serials);
    Pmulti_remain->SetBasic(true);
    Pmulti_remain->GetSection()->Add_string("parameters",Property::Changeable::WhenIdle,"");
    Pmulti_remain->Set_help("see serial1");
    Pmulti_remain->SetBasic(true);

    Pmulti_remain = secprop->Add_multiremain("serial3",Property::Changeable::WhenIdle," ");
    Pstring = Pmulti_remain->GetSection()->Add_string("type",Property::Changeable::WhenIdle,"disabled");
    Pmulti_remain->SetValue("disabled",/*init*/true);
    Pstring->Set_values(serials);
    Pmulti_remain->SetBasic(true);
    Pmulti_remain->GetSection()->Add_string("parameters",Property::Changeable::WhenIdle,"");
    Pmulti_remain->Set_help("see serial1");
    Pmulti_remain->SetBasic(true);

    Pmulti_remain = secprop->Add_multiremain("serial4",Property::Changeable::WhenIdle," ");
    Pstring = Pmulti_remain->GetSection()->Add_string("type",Property::Changeable::WhenIdle,"disabled");
    Pmulti_remain->SetValue("disabled",/*init*/true);
    Pstring->Set_values(serials);
    Pmulti_remain->SetBasic(true);
    Pmulti_remain->GetSection()->Add_string("parameters",Property::Changeable::WhenIdle,"");
    Pmulti_remain->Set_help("see serial1");
    Pmulti_remain->SetBasic(true);

    Pmulti_remain = secprop->Add_multiremain("serial5",Property::Changeable::WhenIdle," ");
    Pstring = Pmulti_remain->GetSection()->Add_string("type",Property::Changeable::WhenIdle,"disabled");
    Pmulti_remain->SetValue("disabled",/*init*/true);
    Pmulti_remain->SetBasic(true);
    Pstring->Set_values(serials);
    Pmulti_remain->GetSection()->Add_string("parameters",Property::Changeable::WhenIdle,"");
    Pmulti_remain->Set_help("see serial1");
    Pmulti_remain->SetBasic(true);

    Pmulti_remain = secprop->Add_multiremain("serial6",Property::Changeable::WhenIdle," ");
    Pstring = Pmulti_remain->GetSection()->Add_string("type",Property::Changeable::WhenIdle,"disabled");
    Pmulti_remain->SetValue("disabled",/*init*/true);
    Pmulti_remain->SetBasic(true);
    Pstring->Set_values(serials);
    Pmulti_remain->GetSection()->Add_string("parameters",Property::Changeable::WhenIdle,"");
    Pmulti_remain->Set_help("see serial1");
    Pmulti_remain->SetBasic(true);

    Pmulti_remain = secprop->Add_multiremain("serial7",Property::Changeable::WhenIdle," ");
    Pstring = Pmulti_remain->GetSection()->Add_string("type",Property::Changeable::WhenIdle,"disabled");
    Pmulti_remain->SetValue("disabled",/*init*/true);
    Pmulti_remain->SetBasic(true);
    Pstring->Set_values(serials);
    Pmulti_remain->GetSection()->Add_string("parameters",Property::Changeable::WhenIdle,"");
    Pmulti_remain->Set_help("see serial1");
    Pmulti_remain->SetBasic(true);

    Pmulti_remain = secprop->Add_multiremain("serial8",Property::Changeable::WhenIdle," ");
    Pstring = Pmulti_remain->GetSection()->Add_string("type",Property::Changeable::WhenIdle,"disabled");
    Pmulti_remain->SetValue("disabled",/*init*/true);
    Pmulti_remain->SetBasic(true);
    Pstring->Set_values(serials);
    Pmulti_remain->GetSection()->Add_string("parameters",Property::Changeable::WhenIdle,"");
    Pmulti_remain->Set_help("see serial1");
    Pmulti_remain->SetBasic(true);

    Pmulti_remain = secprop->Add_multiremain("serial9",Property::Changeable::WhenIdle," ");
    Pstring = Pmulti_remain->GetSection()->Add_string("type",Property::Changeable::WhenIdle,"disabled");
    Pmulti_remain->SetValue("disabled",/*init*/true);
    Pmulti_remain->SetBasic(true);
    Pstring->Set_values(serials);
    Pmulti_remain->GetSection()->Add_string("parameters",Property::Changeable::WhenIdle,"");
    Pmulti_remain->Set_help("see serial1");
    Pmulti_remain->SetBasic(true);

    Pstring = secprop->Add_path("phonebookfile", Property::Changeable::OnlyAtStart, "phonebook-dosbox-x.txt");
    Pstring->Set_help("File used to map fake phone numbers to addresses.");
    Pstring->SetBasic(true);

    // parallel ports
    secprop=control->AddSection_prop("parallel",&Null_Init,true);
#if C_PRINTER
    Pstring = secprop->Add_string("parallel1",Property::Changeable::WhenIdle,"printer");
#else
    Pstring = secprop->Add_string("parallel1",Property::Changeable::WhenIdle,"disabled");
#endif
    Pstring->Set_help(
            "parallel1-9 -- set type of device connected to the parallel (LPT) port.\n"
            "Can be:\n"
            "   reallpt (direct parallel port passthrough),\n"
            "   file (records data to a file or passes it to a device),\n"
            "   printer (virtual dot-matrix printer, see [printer] section)\n"
            "       disney (attach Disney Sound Source emulation to this port)\n"
            "Additional parameters must be in the same line in the form of\n"
            "parameter:value.\n"
            "  for reallpt:\n"
            "  Windows and DOS:\n"
            "    realbase (the base address of your real parallel port).\n"
            "      Default: 378\n"
            "    ecpbase (address of the ECP Extended Control register, optional).\n"
            "  BSD: same as Windows (requires root access / setuid root).\n"
            "  Linux: same as Windows (requires root access / setuid root) or:\n"
            "    realport (the parallel port device e.g. /dev/parport0).\n"
            "  for file:\n"
            "    dev:<devname> (i.e. dev:lpt1) to forward data to a device,\n"
            "    or append:<file> appends data to the specified file.\n"
            "    Without the above parameters data is written to files in the capture dir.\n"
            "    Additional parameters:\n"
            "    timeout:<milliseconds> = how long to wait before closing the file on inactivity (default:0 or 500),\n"
            "    squote to use single quotes instead of double quotes for quoted program commands.\n"
            "    shellhide to hide the command window when opening programs on the Windows platform.\n"
            "    addFF to add a formfeed when closing, addLF to add a linefeed if the app doesn't.\n"
            "    cp:<codepage number> to perform codepage translation, i.e. cp:437\n"
            "    openps:<program>: start a program to open the file if the print output is detected to be PostScript.\n"
            "    openpcl:<program>: start a program to open the file if the print output is detected to be PCL.\n"
            "    openwith:<program>: start a program to open the file in all other conditions.\n"
            "    openerror:<program>: start a program to open the file if an error had occurred.\n"
            "  Example: parallel1=file file:output1.prn timeout:1000 openpcl:pcl6 openps:gswin32c openwith:notepad\n"
            "  for printer:\n"
            "    printer still has its own configuration section above.\n"
            "Note: LPT1-3 are standard LPT ports in DOS, whereas LPT4-9 are extended LPT ports.\n"
            "      You can optionally specify base addresses and IRQs for them with base: and irq: options.\n"
            "      Parallel port settings can also be changed via the built-in PARALLEL command."
    );
    Pstring->SetBasic(true);
    Pstring = secprop->Add_string("parallel2",Property::Changeable::WhenIdle,"disabled");
    Pstring->Set_help("see parallel1");
    Pstring->SetBasic(true);
    Pstring = secprop->Add_string("parallel3",Property::Changeable::WhenIdle,"disabled");
    Pstring->Set_help("see parallel1");
    Pstring->SetBasic(true);
    Pstring = secprop->Add_string("parallel4",Property::Changeable::WhenIdle,"disabled");
    Pstring->Set_help("see parallel1");
    Pstring->SetBasic(true);
    Pstring = secprop->Add_string("parallel5",Property::Changeable::WhenIdle,"disabled");
    Pstring->Set_help("see parallel1");
    Pstring->SetBasic(true);
    Pstring = secprop->Add_string("parallel6",Property::Changeable::WhenIdle,"disabled");
    Pstring->Set_help("see parallel1");
    Pstring->SetBasic(true);
    Pstring = secprop->Add_string("parallel7",Property::Changeable::WhenIdle,"disabled");
    Pstring->Set_help("see parallel1");
    Pstring->SetBasic(true);
    Pstring = secprop->Add_string("parallel8",Property::Changeable::WhenIdle,"disabled");
    Pstring->Set_help("see parallel1");
    Pstring->SetBasic(true);
    Pstring = secprop->Add_string("parallel9",Property::Changeable::WhenIdle,"disabled");
    Pstring->Set_help("see parallel1");
    Pstring->SetBasic(true);

    Pbool = secprop->Add_bool("dongle",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("Enable dongle");
    Pbool->SetBasic(true);

    // printer redirection parameters
    secprop = control->AddSection_prop("printer", &Null_Init);
    Pbool = secprop->Add_bool("printer", Property::Changeable::WhenIdle, true);
    Pbool->Set_help("Enable printer emulation.");
    Pbool->SetBasic(true);
    //secprop->Add_string("fontpath","%%windir%%\\fonts");
    Pint = secprop->Add_int("dpi", Property::Changeable::WhenIdle, 360);
    Pint->Set_help("Resolution of printer (default 360).");
    Pint->SetBasic(true);
    Pint = secprop->Add_int("width", Property::Changeable::WhenIdle, 85);
    Pint->Set_help("Width of paper in 1/10 inch (default 85 = 8.5'').");
    Pint->SetBasic(true);
    Pint = secprop->Add_int("height", Property::Changeable::WhenIdle, 110);
    Pint->Set_help("Height of paper in 1/10 inch (default 110 = 11.0'').");
    Pint->SetBasic(true);
#if C_PRINTER && 0
    Pstring = secprop->Add_string("printoutput", Property::Changeable::WhenIdle, "printer");
#elif defined(C_LIBPNG)
    Pstring = secprop->Add_string("printoutput", Property::Changeable::WhenIdle, "png");
#else
    Pstring = secprop->Add_string("printoutput", Property::Changeable::WhenIdle, "ps");
#endif
    Pstring->Set_help("Output method for finished pages:\n"
#ifdef C_LIBPNG
        "  png     : Creates PNG images (default)\n"
#endif
        "  ps      : Creates PostScript\n"
        "  bmp     : Creates BMP images (very huge files, not recommended)\n"
        "  printer : Send to an actual printer in Windows (specify a printer, or Print dialog will appear)"
    );
    Pstring->SetBasic(true);

    Pbool = secprop->Add_bool("multipage", Property::Changeable::WhenIdle, false);
    Pbool->Set_help("Adds all pages to one PostScript file or printer job until CTRL-F2 is pressed.");
    Pbool->SetBasic(true);

    Pstring = secprop->Add_string("device", Property::Changeable::WhenIdle, "-");
    Pstring->Set_help("Specify the Windows printer device to use. You can see the list of devices from the Help\n"
        "  menu (\'List printer devices\') or the Status Window. Then make your choice and put either\n"
        "  the printer device number (e.g. 2) or your printer name (e.g. Microsoft Print to PDF).\n"
        "  Leaving it empty will show the Windows Print dialog (or \'-\' for showing once).");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("docpath", Property::Changeable::WhenIdle, ".");
    Pstring->Set_help("The path (directory) where the output files are stored.");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("fontpath", Property::Changeable::WhenIdle, "FONTS");
    Pstring->Set_help("The path (directory) where the printer fonts (courier.ttf, ocra.ttf, roman.ttf, sansserif.ttf, script.ttf) are located.");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("openwith", Property::Changeable::WhenIdle, "");
    Pstring->Set_help("Start the specified program to open the output file.");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("openerror", Property::Changeable::WhenIdle, "");
    Pstring->Set_help("Start the specified program to open the output file if an error had occurred.");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("printdbcs", Property::Changeable::WhenIdle, "auto");
    Pstring->Set_values(truefalseautoopt);
    Pstring->Set_help("Allows DOSBox-X to print Chinese/Japanese/Korean DBCS (double-byte) characters when these code pages are active.\n"
                    "If set to auto (default), this is enabled only for the TrueType font (TTF) output with the DBCS support enabled.\n"
                    "Only applicable when using a DBCS code page (932: Japanese, 936: Simplified Chinese; 949: Korean; 950: Traditional Chinese)");
    Pstring->SetBasic(true);

    Pbool = secprop->Add_bool("shellhide", Property::Changeable::WhenIdle, false);
    Pbool->Set_help("If set, the command window will be hidden for openwith/openerror options on the Windows platform.");
    Pbool->SetBasic(true);

    Pint = secprop->Add_int("timeout", Property::Changeable::WhenIdle, 0);
    Pint->Set_help("(in milliseconds) if nonzero: the time the page will be ejected automatically after when no more data arrives at the printer.");
    Pint->SetBasic(true);

    /* All the DOS Related stuff, which will eventually start up in the shell */
    secprop=control->AddSection_prop("dos",&Null_Init,false);//done
    Pbool = secprop->Add_bool("xms",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("Enable XMS support.");
    Pbool->SetBasic(true);

    /* maybe this will stop the endless "it's broken and it only works once you point out LOADFIX -a" bug reports */
    Pbool = secprop->Add_bool("turn off a20 gate on load if loadfix needed",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("If enabled, and loading a program below the 64kb boundary, turn off the A20 gate.\n"
                    "This can help with any program with startup code that assumes the segment wraparound of the 8086.\n"
                    "Depending on DOS configuration the A20 gate may be re-enabled later such as calling INT 21h.");

    Pbool = secprop->Add_bool("break on int3",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("If set, a breakpoint on INT 3 is automatically set up at startup");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("xms log memmove",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("If set, XMS move/copy operations are logged for debugging purposes.");

    Pbool = secprop->Add_bool("xms memmove causes flat real mode",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("If set, any call to XMS to move/copy memory sets up flat real mode for segment registers DS and ES.");

    Pbool = secprop->Add_bool("xms init causes flat real mode",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("If set, when the DOS kernel initializes XMS it will switch on flat real mode for segment registers DS and ES if appropriate.");

    Pbool = secprop->Add_bool("resized free memory block becomes allocated",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("If set, and the DOS application resizes a freed memory block, that block will be marked as allocated to that program.\n"
		    "MS-DOS behaves in this manner, apparently.");

    Pint = secprop->Add_int("xms handles",Property::Changeable::WhenIdle,0);
    Pint->Set_help("Number of XMS handles available for the DOS environment, or 0 to use a reasonable default");
    Pint->SetBasic(true);

    Pbool = secprop->Add_bool("shell configuration as commands",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("Allow entering dosbox-x.conf configuration parameters as shell commands to get and set settings.\n"
                    "This is disabled by default to avoid conflicts between commands and executables.\n"
                    "It is recommended to get and set dosbox-x.conf settings using the CONFIG command instead.\n"
                    "Compatibility with DOSBox SVN can be improved by enabling this option.");
    Pbool->SetBasic(true);

    Pstring = secprop->Add_string("exepack",Property::Changeable::WhenIdle,"unpack");
    Pstring->Set_values(exepackopts);
    Pstring->Set_help("If loading an EXE file compressed using ExEPACK, what to do.\n"
		      "This setting can help avoid Packed File is Corrupt errors when running such executables.\n"
		      "none = don't do anything\n"
		      "a20off = switch off the A20 gate before running the executable\n"
		      "unpack = decompress the EXE and then run it, rather than run the EXEPACK code (default).");

    Pstring = secprop->Add_string("badcommandhandler",Property::Changeable::WhenIdle,"");
    Pstring->Set_help("Allow to specify a custom error handler command for the internal DOS shell before the \"Bad command or file name\" message shows up.");

    Pstring = secprop->Add_string("mscdex device name",Property::Changeable::WhenIdle,"");
    Pstring->Set_help("If set, use this name as the MSCDEX device name instead of MSCD001");

    Pbool = secprop->Add_bool("hma",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("Report through XMS that HMA exists (not necessarily available)");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("hma allow reservation",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("Allow TSR and application (anything other than the DOS kernel) to request control of the HMA.\n"
            "They will not be able to request control however if the DOS kernel is configured to occupy the HMA (DOS=HIGH)");

    Pbool = secprop->Add_bool("command shell flush keyboard buffer",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("If set, the DOS shell (COMMAND.COM) will flush the keyboard buffer before executing a command, and will flush the keyboard buffer again when the command returns.\n"
            "The purpose of this option is to prevent the program from immediately acting on the Enter key you pressed to run it.");

    Pint = secprop->Add_int("hard drive data rate limit",Property::Changeable::WhenIdle,-1);
    Pint->Set_help("Slow down (limit) hard disk throughput. This setting controls the limit in bytes/second.\n"
                   "Set to 0 to disable the limit, or -1 (default) to use a reasonable limit.\n"
                   "The disk I/O performance as in DOSBox SVN can be achieved by setting this to 0.");
    Pint->SetBasic(true);

    Pint = secprop->Add_int("floppy drive data rate limit", Property::Changeable::WhenIdle, -1);
    Pint->Set_help("Slow down (limit) floppy disk throughput. This setting controls the limit in bytes/second.\n"
                   "Set to 0 to disable the limit, or -1 (default) to use a reasonable limit.\n"
                   "The disk I/O performance as in DOSBox SVN can be achieved by setting this to 0.");
    Pint->SetBasic(true);

    Pstring = secprop->Add_string("special operation file prefix",Property::Changeable::OnlyAtStart,".DB");
    Pstring->Set_help("The file prefix used by DOSBox-X's special operations on mounted local/overlay drives. It is fixed to \"DB\" in mainline DOSBox.");

    Pstring = secprop->Add_string("drive z is remote",Property::Changeable::WhenIdle,"auto");
    Pstring->Set_values(truefalseautoopt);
    Pstring->Set_help("If set, DOS will report drive Z as remote. If not set, DOS will report drive Z as local.\n"
                      "If auto (default), DOS will report drive Z as remote or local depending on the program.\n"
                      "Set this option to true to prevent SCANDISK.EXE from attempting scan and repair drive Z:\n"
                      "which is impossible since Z: is a virtual drive not backed by a disk filesystem.");

    Pbool = secprop->Add_bool("drive z convert fat",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("If set, DOSBox-X will automatically convert the Z drive into disk image as well when \"convertdrivefat\" is set.");

    Pbool = secprop->Add_bool("drive z expand path",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("If set, DOSBox-X will automatically expand the %PATH% environment variable to include the subdirectories on the Z drive.");

    Pstring = secprop->Add_string("drive z hide files",Property::Changeable::OnlyAtStart,"/TEXTUTIL\\25.COM /TEXTUTIL\\28.COM /TEXTUTIL\\50.COM");
    Pstring->Set_help("The files or directories listed here (separated by space) will be either hidden or removed from the Z drive.\n"
                      "Files with leading forward slashes (e.g. \"/DEBUG\\BIOSTEST.COM\") will become hidden files (DIR /A will list them).");

    Pbool = secprop->Add_bool("automount drive directories",Property::Changeable::OnlyAtStart, false);
    Pbool->Set_help("If set, DOSBox-X will automatically mount existing drive directories from C drive to Y drive, e.g. \"DriveC\".\n"
                    "NOTE: This option is only available under Windows.");

    Pbool = secprop->Add_bool("hidenonrepresentable",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("If set, DOSBox-X will hide files on local drives that are non-representative in the current DOS code page.\n"
                    "This may be required for some programs such as Windows 3.x Setup if the drives contain international filenames.");

    Pint = secprop->Add_int("hma minimum allocation",Property::Changeable::WhenIdle,0);
    Pint->Set_help("Minimum allocation size for HMA in bytes (equivalent to /HMAMIN= parameter).");

    Pbool = secprop->Add_bool("ansi.sys",Property::Changeable::WhenIdle,true);
    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"
                    "NOTE: This option has no effect in PC-98 mode where MS-DOS systems integrate ANSI.SYS into the DOS kernel.");
    Pbool->SetBasic(true);

    Pstring = secprop->Add_string("log console",Property::Changeable::WhenIdle,"false");
    Pstring->Set_values(truefalsequietopts);
    Pstring->Set_help("If set, log DOS CON output to the log file. Setting to \"quiet\" will log DOS CON output only (no debugging output).");
    Pstring->SetBasic(true);

    Pint = secprop->Add_int("dos sda size",Property::Changeable::WhenIdle,0);
    Pint->Set_help("SDA (swappable data area) size, in bytes. Set to 0 to use a reasonable default.");

    Pint = secprop->Add_int("hma free space",Property::Changeable::WhenIdle,34*1024); /* default 34KB (TODO: How much does MS-DOS 5.0 usually occupy?) */
    Pint->Set_help("Controls the amount of free space available in HMA. This setting is not meaningful unless the\n"
            "DOS kernel occupies HMA and the emulated DOS version is at least 5.0.");

    Pstring = secprop->Add_string("cpm compatibility mode",Property::Changeable::WhenIdle,"auto");
    Pstring->Set_values(cpm_compat_modes);
    Pstring->Set_help(
            "This controls how the DOS kernel sets up the CP/M compatibility code in the PSP segment.\n"
            "Several options are provided to emulate one of several undocumented behaviors related to the CP/M entry point.\n"
            "If set to auto, DOSBox-X will pick the best option to allow it to work properly.\n"
            "Unless set to 'off', this option will require the DOS kernel to occupy the first 256 bytes of the HMA memory area\n"
            "to prevent crashes when the A20 gate is switched on.\n"
            "   auto      Pick the best option\n"
            "   off       Turn off the CP/M entry point (program will abort if called)\n"
            "   msdos2    MS-DOS 2.x behavior, offset field also doubles as data segment size\n"
            "   msdos5    MS-DOS 5.x behavior, entry point becomes one of two fixed addresses\n"
            "   direct    Non-standard behavior, encode the CALL FAR directly to the entry point rather than indirectly");

    Pbool = secprop->Add_bool("share",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("Reports SHARE.EXE as resident and provides functions such as file-locking and record-locking, although not all SHARE functions are emulated.");
    Pbool->SetBasic(true);

    Pint = secprop->Add_int("file access tries",Property::Changeable::WhenIdle,0);
    Pint->Set_help("If a positive integer is set, DOSBox-X will try to read/write/lock files directly on mounted local drives for the specified number of times without caching before failing on Windows systems.\n"
            "For networked database applications (e.g. dBase, FoxPro, etc), it is strongly recommended to set this to e.g. 3 for correct operations.");
    Pint->SetBasic(true);

    Pbool = secprop->Add_bool("network redirector",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("Report DOS network redirector as resident. This will allow the host name to be returned unless the secure mode is enabled.\n"
            "You can also directly access UNC network paths in the form \\\\MACHINE\\SHARE even if they are not mounted as drives on Windows systems.\n"
            "Set either \"ipx=true\" in [ipx] section or \"ne2000=true\" in [ne2000] section for a full network redirector environment.");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("mcb corruption becomes application free memory",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("If MCB chain corruption occurs following the DOS program PSP segment and the DOS program does anything to cause memory allocation,"
                    "make a new free memory block in it's place instead of halting emulation with an MCB chain error. Some DOS programs are sloppy"
                    "with memory to corrupt the MCB chain after itself in memory. This is apparently real MS-DOS behavior, set to true to enable."
                    "If set to false, all MCB chain corruption will halt emulation as DOSBox forks typically do already.");
    Pbool->SetBasic(true);

    Phex = secprop->Add_hex("minimum dos initial private segment", Property::Changeable::WhenIdle,0);
    Phex->Set_help("In non-mainline mapping mode, where DOS structures are allocated from base memory, this sets the\n"
            "minimum segment value. Recommended value is 0x70. You may reduce the value down to 0x50 if freeing\n"
            "up more memory is important. Set to 0 for default.");

    Phex = secprop->Add_hex("minimum mcb segment", Property::Changeable::WhenIdle,0);
    Phex->Set_help("Minimum segment value to begin memory allocation from, in hexadecimal. Set to 0 for default.\n"
            "You can increase available DOS memory by reducing this value down to as low as 0x51, however\n"
            "setting it to low can cause some DOS programs to crash or run erratically, and some DOS games\n"
            "and demos to cause intermittent static noises when using Sound Blaster output. DOS programs\n"
            "compressed with Microsoft EXEPACK will not run if the minimum MCB segment is below 64KB. This differs\n"
            "from 'minimum mcb free' in that this affects the starting point of the mcb chain instead of the lowest free block.");

    Phex = secprop->Add_hex("minimum mcb free", Property::Changeable::WhenIdle,0);
    Phex->Set_help("Minimum free segment value to leave free. At startup, the DOS kernel will allocate memory\n"
                   "up to this point. This can be used to deal with EXEPACK issues or DOS programs that cannot\n"
                   "be loaded too low in memory. If you want more free conventional memory to be reported,\n"
                   "you can for example set its value to 1.");
    Phex->SetBasic(true);

    // TODO: Enable by default WHEN the 'SD' signature becomes valid, and a valid device list within
    //       is emulated properly.
    Pbool = secprop->Add_bool("enable dummy device mcb",Property::Changeable::OnlyAtStart,false);
    Pbool->Set_help("If set (default), allocate a fake device MCB at the base of conventional memory.\n"
            "Clearing this option can reclaim a small amount of conventional memory at the expense of\n"
            "some minor DOS compatibility.");

    Pint = secprop->Add_int("maximum environment block size on exec", Property::Changeable::WhenIdle,-1);
    Pint->SetMinMax(-1,65535);
    Pint->Set_help("Maximum environment block size to copy for child processes. Set to -1 for default.");

    Pint = secprop->Add_int("additional environment block size on exec", Property::Changeable::WhenIdle,-1);
    Pint->SetMinMax(-1,65535);
    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"
            "If the subprocesses will never add/modify the environment block, you can free up a few additional bytes by setting this to 0.\n"
            "Set to -1 for default setting.");

    // DEPRECATED, REMOVE
    Pbool = secprop->Add_bool("enable a20 on windows init",Property::Changeable::OnlyAtStart,false);
    Pbool->Set_help("If set, DOSBox-X will enable the A20 gate when Windows 3.1/9x broadcasts the INIT message\n"
            "at startup. Windows 3.1 appears to make assumptions at some key points on startup about\n"
            "A20 that don't quite hold up and cause Windows 3.1 to crash when you set A20 emulation\n"
            "to a20=mask as opposed to a20=fast. This option is enabled by default.");

    Pbool = secprop->Add_bool("zero memory on xms memory allocation",Property::Changeable::OnlyAtStart,false);
    Pbool->Set_help("If set, memory returned by XMS allocation call is zeroed first. This is NOT what\n"
            "DOS actually does, but if set, can help certain DOS games and demos cope with problems\n"
            "related to uninitialized variables in extended memory. When enabled this option may\n"
            "incur a slight to moderate performance penalty.");

    Pstring = secprop->Add_string("ems",Property::Changeable::WhenIdle,"true");
    Pstring->Set_values(ems_settings);
    Pstring->Set_help("Enable EMS support. The default (=true) provides the best\n"
        "compatibility but certain applications may run better with\n"
        "other choices, or require EMS support to be disabled (=false)\n"
        "to work at all.");
    Pstring->SetBasic(true);

    Pbool = secprop->Add_bool("vcpi",Property::Changeable::OnlyAtStart,true);
    Pbool->Set_help("If set and expanded memory is enabled, also emulate VCPI.");
    Pstring->SetBasic(true);

    Pbool = secprop->Add_bool("unmask timer on disk io",Property::Changeable::OnlyAtStart,false);
    Pbool->Set_help("If set, INT 21h emulation will unmask IRQ 0 (timer interrupt) when the application opens/closes/reads/writes files.");

    Pbool = secprop->Add_bool("zero int 67h if no ems",Property::Changeable::OnlyAtStart,true);
    Pbool->Set_help("If ems=false, leave interrupt vector 67h zeroed out (default true).\n"
            "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"
            "This option also affects whether INT 67h is zeroed when booting a guest OS.");

    Pbool = secprop->Add_bool("zero unused int 68h",Property::Changeable::OnlyAtStart,false);
    Pbool->Set_help("Leave INT 68h zero at startup.\n"
            "Set this to true for certain games that use INT 68h in unusual ways that require a zero value.\n"
            "Note that the vector is left at zero anyway when machine=cga.\n"
            "This is needed to properly run 1988 game 'PopCorn'.");

    /* FIXME: The vm86 monitor in src/ints/ems.cpp is not very stable! Option is default OFF until stabilized! */
    Pbool = secprop->Add_bool("emm386 startup active",Property::Changeable::OnlyAtStart,false);
    Pbool->Set_help("If set and expanded memory is set to emulate emm386, start the DOS machine with EMM386.EXE active\n"
            "(running the 16-bit DOS environment from within Virtual 8086 mode). If you will be running anything\n"
            "that involves a DOS extender you will also need to enable the VCPI interface as well.");

    Pbool = secprop->Add_bool("zero memory on ems memory allocation",Property::Changeable::OnlyAtStart,false);
    Pbool->Set_help("If set, memory returned by EMS allocation call is zeroed first. This is NOT what\n"
            "DOS actually does, but if set, can help certain DOS games and demos cope with problems\n"
            "related to uninitialized variables in expanded memory. When enabled this option may\n"
            "incur a slight to moderate performance penalty.");

    Pint = secprop->Add_int("ems system handle memory size",Property::Changeable::WhenIdle,384);
    Pint->Set_help("Amount of memory associated with system handle, in KB.");

    Pbool = secprop->Add_bool("ems system handle on even megabyte",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("If set, try to allocate the EMM system handle on an even megabyte.\n"
            "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"
            "However, forcing allocation on an even megabyte will also cause some extended memory fragmentation and reduce the\n"
            "overall amount of extended memory available to the DOS game depending on whether it expects large contiguous chunks\n"
            "of extended memory.");

    Phex = secprop->Add_hex("ems frame",Property::Changeable::OnlyAtStart,0); /* <- Allow (to a limited extent) to control the location of the page frame */
    Phex->Set_help("Segment of the EMS page frame, if set. C000, D000, or E000");

    Pbool = secprop->Add_bool("umb",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("Enable UMB support.");
    Pbool->SetBasic(true);

    Phex = secprop->Add_hex("umb start",Property::Changeable::OnlyAtStart,0); /* <- (0=auto) 0xD000 is mainline DOSBox compatible behavior */
    Phex->Set_help("UMB region starting segment");

    Phex = secprop->Add_hex("umb end",Property::Changeable::OnlyAtStart,0); /* <- (0=auto) 0xEFFF is mainline DOSBox compatible (where base=0xD000 and size=0x2000) */
    Phex->Set_help("UMB region last segment");

    Pbool = secprop->Add_bool("kernel allocation in umb",Property::Changeable::OnlyAtStart,false);
    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"
            "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.");

    Pbool = secprop->Add_bool("keep umb on boot",Property::Changeable::OnlyAtStart,false);
    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.");

    Pstring = secprop->Add_string("keep private area on boot",Property::Changeable::OnlyAtStart,"auto");
    Pstring->Set_values(truefalseautoopt);
    Pstring->Set_help("If set to true, keep the DOSBox-X private area around after boot (Mainline DOSBox behavior). If false, unmap and discard the private area when you boot an operating system.\n"
            "If set to auto, DOSBox-X will unmap and discard the private area while booting to a guest system unless Glide passthrough is enabled (useful for Windows 9x Glide support).\n");

    Pbool = secprop->Add_bool("private area in umb",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("If set, keep private DOS segment in upper memory block, usually segment 0xC800 (Mainline DOSBox behavior)\n"
            "If clear, place private DOS segment at the base of system memory (just below the MCB)");

    Pbool = secprop->Add_bool("private area write protect",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("If set, prevent the guest from writing to the DOSBox private area. The emulator itself can still write to it, of course.\n"
                    "Some DOS games have sloppy video routines that can spill over and corrupt the private area and cause problems.\n"
                    "This option when set can prevent that errant game from causing crashes.");

    Pbool = secprop->Add_bool("quick reboot",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("If set, the DOS restart call will reboot the emulated DOS (integrated DOS or guest DOS) instead of the virtual machine.\n");
    Pbool->SetBasic(true);

    Pstring = secprop->Add_string("ver",Property::Changeable::WhenIdle,"");
    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"
            "auto (or unset)                  Pick DOS kernel version 5.0 (DOSBox default)\n"
            "3.3                              MS-DOS 3.3 emulation (not tested!)\n"
            "5.0                              MS-DOS 5.0 emulation (recommended for DOS gaming)\n"
            "6.22                             MS-DOS 6.22 emulation\n"
            "7.0                              MS-DOS 7.0 (or Windows 95 pure DOS mode) emulation\n"
            "7.1                              MS-DOS 7.1 (or Windows 98 pure DOS mode) emulation\n"
            "Long filename (LFN) support will be enabled with a reported DOS version of 7.0 or higher with \"lfn=auto\" (default).\n"
			"Similarly, FAT32 disk images will be supported with a reported DOS version of 7.1 or higher.\n");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("lfn",Property::Changeable::WhenIdle,"auto");
    Pstring->Set_values(lfn_settings);
    Pstring->Set_help("Enable long filename support. If set to auto (default), LFN support is enabled if the reported DOS version is at least 7.0.\n"
                      "If set to autostart, the built-in VER command won't activate/deactivate LFN support according to the reported DOS version.");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("fat32setversion",Property::Changeable::WhenIdle,"ask");
    Pstring->Set_values(fat32setver_settings);
    Pstring->Set_help("Whether DOSBox-X should automatically set the reported DOS version to 7.0/7.10 when it is less than 7.0/7.10 and mounting LBA/FAT32 disk images is requested.\n"
                      "If set to \"ask\", a popup message will show up to ask whether DOSBox-X should automatically change the reported DOS version in order to mount the disk image.");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("shellhigh",Property::Changeable::OnlyAtStart,"auto");
    Pstring->Set_values(truefalseautoopt);
    Pstring->Set_help("Load the DOSBox-X command shell into the upper memory when the UMB is available.\n"
                      "If set to auto (default), it is enabled if the reported DOS version is at least 7.0.");
    Pstring->SetBasic(true);

    Pbool = secprop->Add_bool("automount",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("Enable automatic drive mounting in Windows.");
    Pbool->SetBasic(true);

    Pstring = secprop->Add_string("automountall",Property::Changeable::WhenIdle,"false");
    Pstring->Set_values(truefalsequietopts);
    Pstring->Set_help("Automatically mount all available Windows drives at start.");
    Pstring->SetBasic(true);

    Pbool = secprop->Add_bool("mountwarning",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("If set, a warning message will be displayed while trying to auto-mount your Windows host drives.");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("autoa20fix",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("If set (default), DOSBox-X will automatically re-run the executable with the A20 gate disabled if it failed with the \"Packed file is corrupt\" error.\n"
                    "If both autoa20fix and autoloadfix are set, then the former will be tried first, and the latter will be tried if the former did not work.");

    Pbool = secprop->Add_bool("autoloadfix",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("If set (default), DOSBox-X will automatically re-run the executable with LOADFIX if it failed with the \"Packed file is corrupt\" error.");

    Pstring = secprop->Add_string("autofixwarning",Property::Changeable::WhenIdle,"false");
    Pstring->Set_values(autofix_settings);
    Pstring->Set_help("If set to true or both, DOSBox-X shows messages while trying to automatically fix the \"Packed file is corrupt\" error.\n"
                      "If set to false or none, DOSBox-X will not show such messages on the screen when the error occurred.\n"
                      "If set to \"a20fix\" or \"loadfix\", DOSBox-X will show the message for the a20fix or the loadfix only.");
    Pstring->SetBasic(true);

    Pbool = secprop->Add_bool("startcmd",Property::Changeable::
#if defined(WIN32) && !defined(HX_DOS)
    WhenIdle
#else
    OnlyAtStart
#endif
    ,false);
    Pbool->Set_help("Enable START command to start programs to run on the host system. On Windows host programs or commands may also be launched directly.");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("starttranspath",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("Specify whether DOSBox-X should automatically translate all paths in the command-line to host system paths when starting programs to run on the host system.");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("startwait",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("Specify whether DOSBox-X should wait for the host system applications after they are started.");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("startquiet",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("If set, before launching host system applications to run on the host DOSBox-X will not show messages like \"Now run it as a Windows application\".");
    Pbool->SetBasic(true);

    Pstring = secprop->Add_string("startincon",Property::Changeable::OnlyAtStart,"assoc attrib chcp copy dir echo for ftype help if set type ver vol xcopy");
    Pstring->Set_help("START command will start these commands (separated by space) in a console and wait for a key press before exiting.");

    Pbool = secprop->Add_bool("startnopause", Property::Changeable::WhenIdle, false);
    Pbool->Set_help("If set, DOSBox-X will not pause after host command execution is completed.");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("vmware",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("Enable VMware interface emulation including guest mouse integration (when used along with e.g. VMware mouse driver for Windows 3.x).");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("int33",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("Enable INT 33H for mouse support.");
    Pbool->SetBasic(true);

    Pint = secprop->Add_int("int33 max x", Property::Changeable::WhenIdle, 0);
    Pint->Set_help("For guest to host cursor integration with DOS games, assume the maximum reported X coordinate has this value, if this is nonzero.\n"
                   "Use this option if the automatic range detection fails to work correctly with the DOS game and the cursor doesn't match the host cursor position.\n"
                   "- Lemmings 2: Use X=640 Y=400");

    Pint = secprop->Add_int("int33 max y", Property::Changeable::WhenIdle, 0);
    Pint->Set_help("For guest to host cursor integration with DOS games, assume the maximum reported Y coordinate has this value, if this is nonzero.\n"
                   "Use this option if the automatic range detection fails to work correctly with the DOS game and the cursor doesn't match the host cursor position.\n"
                   "- See the max X setting for a list of games");

    Pstring = secprop->Add_string("int33 xy adjust",Property::Changeable::OnlyAtStart,"");
    Pstring->Set_help("A list of adjustments to INT 33h position adjustments to help align the guest cursor to the host. name=value, comma separated\n"
                      "x=spec, y=spec\n"
                      "spec:   <number>    position adjust, can be positive or negative\n"
                      "        max-excess  if game sets maximum larger than int33 max x/y, adjust the position forward by the difference");

    Pint = secprop->Add_int("int33 mickey threshold",Property::Changeable::WhenIdle,1);
    Pint->Set_help("The smallest amount of mouse motion that will be reported to the guest. Motion below this amount is buffered until the threshold is met.\n"
                   "Some DOS programs do not properly respond to small mouse movements causing effects like a sluggish cursor or cursor drift.\n"
                   "Increase this option to the smallest value that achieves natural feeling motion.\n"
                   "- Ultima Underworld: Use 2");
    Pint->SetMinMax(1,16);

    Pint = secprop->Add_int("mouse report rate",Property::Changeable::WhenIdle,0);
    Pint->Set_help("Mouse reporting rate, or 0 for auto. This affects how often mouse events are reported to the guest through the mouse interrupt.\n"
		    "Some games including CyClone need a lower reporting rate to function correctly. Auto mode allows the guest to change the report rate through the PS/2 mouse emulation.\n"
		    "This option does not affect any DOS game that uses polling through INT 33h to detect mouse movement.");
    Pint->SetMinMax(0,10000);
    Pint->SetBasic(true);

    Pbool = secprop->Add_bool("int33 hide host cursor if interrupt subroutine",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("If set, the cursor on the host will be hidden if the DOS application provides its own\n"
                    "interrupt subroutine for the mouse driver to call, which is usually an indication that\n"
                    "the DOS game wishes to draw the cursor with its own support routines (DeluxePaint II).");

    Pbool = secprop->Add_bool("int33 hide host cursor when polling",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("If set, the cursor on the host will be hidden even if the DOS application has also\n"
                    "hidden the cursor in the guest, as long as the DOS application is polling position\n"
                    "and button status. This can be useful for DOS programs that draw the cursor on their\n"
                    "own instead of using the mouse driver, including most games and DeluxePaint II.");

    Pbool = secprop->Add_bool("int33 disable cell granularity",Property::Changeable::WhenIdle,false);
    Pbool->Set_help("If set, the mouse pointer position is reported at full precision (as if 640x200 coordinates) in all modes.\n"
                    "If not set, the mouse pointer position is rounded to the top-left corner of a character cell in text modes.\n"
                    "This option is OFF by default.");

    Pbool = secprop->Add_bool("int 13 disk change detect",Property::Changeable::WhenIdle,true);
    Pbool->Set_help("Enable INT 13h disk change detect function (AH=16h)");

    Pbool = secprop->Add_bool("int 13 extensions",Property::Changeable::WhenIdle,true);
    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.");

    Pbool = secprop->Add_bool("int 13 enable 48-bit LBA", Property::Changeable::WhenIdle, true);
    Pbool->Set_help("Enable 48-bit LBA support for INT 13h extensions. Needed for drives larger than 28-bit LBA limit (128GiB).");

    Pbool = secprop->Add_bool("biosps2",Property::Changeable::OnlyAtStart,true);
    Pbool->Set_help("Emulate BIOS INT 15h PS/2 mouse services\n"
        "Note that some OS's like Microsoft Windows neither use INT 33h nor\n"
        "probe the AUX port directly and depend on this BIOS interface exclusively\n"
        "for PS/2 mouse support. In other cases there is no harm in leaving this enabled");

    /* bugfix for Yodel "mayday" demo */
    /* TODO: Set this option to default to "true" if it turns out most BIOSes unmask the IRQ during INT 15h AH=86 WAIT */
    Pbool = secprop->Add_bool("int15 wait force unmask irq",Property::Changeable::OnlyAtStart,true);
    Pbool->Set_help("Some demos or games mistakenly use INT 15h AH=0x86 (WAIT) while leaving the IRQs needed for it masked.\n"
            "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.");

    Pbool = secprop->Add_bool("int15 mouse callback does not preserve registers",Property::Changeable::OnlyAtStart,false);
    Pbool->Set_help("Set to true if the guest OS or DOS program assigns an INT 15h mouse callback,\n"
            "but does not properly preserve CPU registers. Diagnostic function only (default off).");

    Pstring = secprop->Add_string("keyboardlayout",Property::Changeable::WhenIdle, "auto");
    Pstring->Set_help("Language code of the keyboard layout (or none).");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("customcodepage",Property::Changeable::WhenIdle, "");
    Pstring->Set_help("Set a custom code page for CHCP command and specify a SBCS code page file, following the standard SBCS code page format.\n"
                    "Examples of SBCS code pages are available from the Unicode Consortium website: https://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/");
    Pstring->SetBasic(true);

    Pbool = secprop->Add_bool("dbcs",Property::Changeable::OnlyAtStart,true);
    Pbool->Set_help("Enable DBCS table and Chinese, Japanese, Korean support for the TrueType font (TTF) output.\n"
            "CAUTION: Some software will crash without the DBCS table, including the Open Watcom installer.");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("filenamechar",Property::Changeable::OnlyAtStart,true);
    Pbool->Set_help("Enable DOS filename char table.");

    Pbool = secprop->Add_bool("collating and uppercase",Property::Changeable::OnlyAtStart,true);
    Pbool->Set_help("Enable DOS collating and uppercase table.");

    // DEPRECATED, REMOVE
    Pbool = secprop->Add_bool("con device use int 16h to detect keyboard input",Property::Changeable::OnlyAtStart,true);
    Pbool->Set_help("If set, use INT 16h to detect keyboard input (MS-DOS 6.22 behavior). If clear, detect keyboard input by\n"
            "peeking into the BIOS keyboard buffer (Mainline DOSBox behavior). You will need to set this\n"
            "option for programs that hook INT 16h to handle keyboard input ahead of the DOS console.\n"
            "Microsoft SCANDISK needs this option to respond to keyboard input correctly.");

    Pbool = secprop->Add_bool("zero memory on int 21h memory allocation",Property::Changeable::OnlyAtStart,false);
    Pbool->Set_help("If set, memory returned by the INT 21h allocation call is zeroed first. This is NOT what\n"
            "DOS actually does, but if set, can help certain DOS games and demos cope with problems\n"
            "related to uninitialized variables in the data or stack segment. If you intend to run a\n"
            "game or demo known to have this problem (Second Unreal, for example), set to true, else\n"
            "set to false. When enabled this option may incur a slight to moderate performance penalty.");

    Pbool = secprop->Add_bool("pipe temporary device",Property::Changeable::WhenIdle, true);
    Pbool->Set_help("Allows temporary devices to be created for piping operations when a temporary path is unavailable.");

    Pstring = secprop->Add_string("dos clipboard device enable",Property::Changeable::WhenIdle, "false");
    Pstring->Set_help("If enabled, a DOS device will be added for bidirectional communications with the shared clipboard.\n"
			"Setting to \"read\" will only allow read access, and setting to \"write\" will only allow write access.\n"
			"Setting to \"full\" or \"true\" enables both; setting to \"false\" or \"disabled\" disables the access or device.\n"
            "The default device name is CLIP$, but can be changed with the \"dos clipboard device name\" setting below.");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("dos clipboard device name",Property::Changeable::WhenIdle, "CLIP$");
    Pstring->Set_help("Set DOS device name (up to 8 characters) for bidirectional communications with the shared clipboard.\n"
            "If unset or invalid, the default name CLIP$ will be used (e.g. \"TYPE CLIP$\" shows the clipboard contents).\n"
			"It has no effect if \"dos clipboard device enable\" is disabled, and it is deactivated if the secure mode is enabled.");
    Pstring->SetBasic(true);

    Pbool = secprop->Add_bool("dos clipboard api",Property::Changeable::WhenIdle, false);
    Pbool->Set_help("If set, DOS APIs for communications with the Windows clipboard will be enabled for shared clipboard communications.\n"
		    "Caution: Enabling this API may cause some programs to think they are running under Windows");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("dos idle api",Property::Changeable::OnlyAtStart,true);
    Pbool->Set_help("If set, DOSBox-X can lower the host system's CPU load when a supported guest program is idle.");
    Pbool->SetBasic(true);

    secprop=control->AddSection_prop("ipx",&Null_Init,true);
    Pbool = secprop->Add_bool("ipx",Property::Changeable::WhenIdle, false);
    Pbool->Set_help("Enable ipx over UDP/IP emulation.");
    Pbool->SetBasic(true);

    secprop=control->AddSection_prop("ne2000",&Null_Init,true);
    Pbool = secprop->Add_bool("ne2000", Property::Changeable::WhenIdle, false);
    Pbool->Set_help("Enable NE2000 Ethernet emulation. Either pcap or slirp backend can be used, switchable via \"backend\" option.\n"
                    "Settings for the pcap and slirp backends can be found in the [ethernet, pcap] and [ethernet, slirp] sections.\n"
                    "Once properly set, load the NE2000 packet driver inside DOSBox-X with base address and interrupt specified below.");
    Pbool->SetBasic(true);

    Phex = secprop->Add_hex("nicbase", Property::Changeable::WhenIdle, 0x300);
    Phex->Set_help("The base address of the NE2000 board.");
    Phex->SetBasic(true);

    Pint = secprop->Add_int("nicirq", Property::Changeable::WhenIdle, 3);
    Pint->Set_help("The interrupt it uses. Note serial2 uses IRQ3 as default.");
    Pint->SetBasic(true);

    Pstring = secprop->Add_string("macaddr", Property::Changeable::WhenIdle,"random");
    Pstring->Set_help("The MAC address the emulator will use for its network adapter.\n"
        "If you have multiple DOSBox-Xes running on the same network,\n"
        "this has to be changed for each. AC:DE:48 is an address range reserved for\n"
        "private use, so modify the last three number blocks, e.g. AC:DE:48:88:99:AB.\n"
        "Default setting is 'random' which randomly chooses a MAC address.");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("backend", Property::Changeable::WhenIdle, "auto");
    Pstring->Set_help("The backend (either pcap or slirp is supported) used for the NE2000 Ethernet emulation.\n"
        "If set to \"auto\", then \"slirp\" is selected when available, otherwise \"pcap\" is selected when available.\n"
        "NE2000 Ethernet emulation will be disabled if no backend is available (or the specified backend if unavailable).");
    Pstring->Set_values(backendopts);
    Pstring->SetBasic(true);

    secprop = control->AddSection_prop("ethernet, pcap", &Null_Init, true);

    Pstring = secprop->Add_string("realnic", Property::Changeable::WhenIdle,"list");
    Pstring->Set_help("Specifies which of your host network interfaces is used for pcap.\n"
        "Write \'list\' here to see the list of devices from the Help\n"
        "menu (\'List network interfaces\') or from the Status Window.\n"
        "Then make your choice and put either the interface number\n"
        "(e.g. 2) or a part of your adapters name (e.g. VIA here).");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("timeout", Property::Changeable::WhenIdle,"default");
    Pstring->Set_help("Specifies the read timeout for the device in milliseconds for the pcap backend, or the default value will be used.");
    Pstring->SetBasic(true);

    secprop = control->AddSection_prop("ethernet, slirp", &Null_Init, true);

    Pbool = secprop->Add_bool("restricted", Property::Changeable::WhenIdle, false);
    Pbool->Set_help("Disables access to the host from the guest.\n"
        "Services such as libslirp's DHCP server will no longer work.");

    Pbool = secprop->Add_bool("disable_host_loopback", Property::Changeable::WhenIdle, false);
    Pbool->Set_help("Disables guest access to the host's loopback interfaces.");

    Pint = secprop->Add_int("mtu", Property::Changeable::WhenIdle, 0);
    Pint->Set_help("The maximum transmission unit for Ethernet packets transmitted from the guest.\n"
        "Specifying 0 will use libslirp's default MTU.");

    Pint = secprop->Add_int("mru", Property::Changeable::WhenIdle, 0);
    Pint->Set_help("The maximum receive unit for Ethernet packets transmitted to the guest.\n"
        "Specifying 0 will use libslirp's default MRU.");

    Pstring = secprop->Add_string("ipv4_network", Property::Changeable::WhenIdle, "10.0.2.0");
    Pstring->Set_help("The IPv4 network the guest and host services are on.");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("ipv4_netmask", Property::Changeable::WhenIdle, "255.255.255.0");
    Pstring->Set_help("The netmask for the IPv4 network.");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("ipv4_host", Property::Changeable::WhenIdle, "10.0.2.2");
    Pstring->Set_help("The address of the guest on the IPv4 network.");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("ipv4_nameserver", Property::Changeable::WhenIdle, "10.0.2.3");
    Pstring->Set_help("The address of the nameserver service provided by the host on the IPv4 network.");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("ipv4_dhcp_start", Property::Changeable::WhenIdle, "10.0.2.15");
    Pstring->Set_help("The start address used for DHCP by the host services on the IPv4 network.");
    Pstring->SetBasic(true);

    Pstring = secprop->Add_string("tcp_port_forwards", Property::Changeable::WhenIdle, "");
    Pstring->Set_help("Forwards one or more TCP ports from the host into the DOS guest.\n"
	                  "The format is:\n"
	                  "  port1  port2  port3 ... (e.g., 21 80 443)\n"
	                  "  This will forward FTP, HTTP, and HTTPS into the DOS guest.\n"
	                  "If the ports are privileged on the host, a mapping can be used\n"
	                  "  host:guest  ..., (e.g., 8021:21 8080:80)\n"
	                  "  This will forward ports 8021 and 8080 to FTP and HTTP in the guest\n"
	                  "A range of adjacent ports can be abbreviated with a dash:\n"
	                  "  start-end ... (e.g., 27910-27960)\n"
	                  "  This will forward ports 27910 to 27960 into the DOS guest.\n"
	                  "Mappings and ranges can be combined, too:\n"
	                  "  hstart-hend:gstart-gend ..., (e.g, 8040-8080:20-60)\n"
	                  "  This forwards ports 8040 to 8080 into 20 to 60 in the guest\n"
	                  ""
	                  "Notes:\n"
	                  "  - If mapped ranges differ, the shorter range is extended to fit.\n"
	                  "  - If conflicting host ports are given, only the first one is setup.\n"
	                  "  - If conflicting guest ports are given, the latter rule takes precedent.");

	Pstring = secprop->Add_string("udp_port_forwards", Property::Changeable::WhenIdle, "");
	Pstring->Set_help("Forwards one or more UDP ports from the host into the DOS guest.\n"
	                  "The format is the same as for TCP port forwards.");

    /* IDE emulation options and setup */
    for (size_t i=0;i < MAX_IDE_CONTROLLERS;i++) {
        secprop=control->AddSection_prop(ide_names[i],&Null_Init,false);//done

        /* Primary and Secondary are on by default, Tertiary and Quaternary are off by default.
         * Throughout the life of the IDE interface it was far more common for a PC to have just
         * a Primary and Secondary interface */
        Pbool = secprop->Add_bool("enable",Property::Changeable::OnlyAtStart,(i < 2) ? true : false);
        if (i == 0) Pbool->Set_help("Enable IDE interface");
        Pbool->SetBasic(true);

        Pbool = secprop->Add_bool("pnp",Property::Changeable::OnlyAtStart,true);
        if (i == 0) Pbool->Set_help("List IDE device in ISA PnP BIOS enumeration");
        Pbool->SetBasic(true);

        Pint = secprop->Add_int("irq",Property::Changeable::WhenIdle,0/*use IDE default*/);
        if (i == 0) Pint->Set_help("IRQ used by IDE controller. Set to 0 for default.\n"
                "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"
                "         Setting the IRQ to one already occupied by another device or IDE controller will trigger \"resource conflict\" errors in Windows 95.\n"
                "         Using IRQ 9, 12, 13, or IRQ 2-7 may cause problems with MS-DOS CD-ROM drivers.");

        Phex = secprop->Add_hex("io",Property::Changeable::WhenIdle,0/*use IDE default*/);
        if (i == 0) Phex->Set_help("Base I/O port for IDE controller. Set to 0 for default.\n"
                "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"
                "         Using any port other than 1F0, 170, 1E8 or 168 can prevent MS-DOS CD-ROM drivers from detecting the IDE controller.");

        Phex = secprop->Add_hex("altio",Property::Changeable::WhenIdle,0/*use IDE default*/);
        if (i == 0) Phex->Set_help("Alternate I/O port for IDE controller (alt status, etc). Set to 0 for default.\n"
                "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"
                "         For best compatibility set this value to io+0x206, for example, io=1F0 altio=3F6.\n"
                "         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.");

        Pbool = secprop->Add_bool("int13fakeio",Property::Changeable::WhenIdle,false);
        if (i == 0) Pbool->Set_help(
                "If set, force IDE state change on certain INT 13h commands.\n"
                "IDE registers will be changed as if BIOS had carried out the action.\n"
                "If you are running Windows 3.11 or Windows 3.11 Windows for Workgroups\n"
                "you must enable this option (and use -reservecyl 1) if you want 32-bit\n"
                "disk access to work correctly in DOSBox-X.");

        Pbool = secprop->Add_bool("int13fakev86io",Property::Changeable::WhenIdle,false);
        if (i == 0) Pbool->Set_help(
                "If set, and int13fakeio is set, certain INT 13h commands will cause IDE emulation to\n"
                "issue fake CPU I/O traps (GPF) in virtual 8086 mode and a fake IRQ signal. You must\n"
                "enable this option if you want 32-bit disk access in Windows 95 to work with DOSBox-X.");

        Pbool = secprop->Add_bool("enable pio32",Property::Changeable::WhenIdle,false);
        if (i == 0) Pbool->Set_help(
                "If set, 32-bit I/O reads and writes are handled directly (much like PCI IDE implementations)\n"
                "If clear, 32-bit I/O will be handled as if two 16-bit I/O (much like ISA IDE implementations)");

        Pbool = secprop->Add_bool("ignore pio32",Property::Changeable::WhenIdle,false);
        if (i == 0) Pbool->Set_help(
                "If 32-bit I/O is enabled, attempts to read/write 32-bit I/O will be ignored entirely.\n"
                "In this way, you can have DOSBox-X emulate one of the strange quirks of 1995-1997 era\n"
                "laptop hardware");

        Pint = secprop->Add_int("cd-rom spinup time",Property::Changeable::WhenIdle,0/*use IDE or CD-ROM default*/);
        if (i == 0) Pint->Set_help("Emulated CD-ROM time in ms to spin up if CD is stationary.\n"
                "Set to 0 to use controller or CD-ROM drive-specific default.");

        Pint = secprop->Add_int("cd-rom spindown timeout",Property::Changeable::WhenIdle,0/*use IDE or CD-ROM default*/);
        if (i == 0) Pint->Set_help("Emulated CD-ROM time in ms that drive will spin down automatically when not in use\n"
                "Set to 0 to use controller or CD-ROM drive-specific default.");

        Pint = secprop->Add_int("cd-rom insertion delay",Property::Changeable::WhenIdle,0/*use IDE or CD-ROM default*/);
        if (i == 0) Pint->Set_help("Emulated CD-ROM time in ms that drive will report \"medium not present\"\n"
                "to emulate the time it takes for someone to take out a CD and insert a new one when\n"
                "DOSBox-X is instructed to swap or change CDs.\n"
                "When running Windows 95 or higher a delay of 4000ms is recommended to ensure that\n"
                "auto-insert notification triggers properly.\n"
                "Set to 0 to use controller or CD-ROM drive-specific default.");
    }

    /* floppy controller emulation options and setup */
    secprop=control->AddSection_prop("fdc, primary",&Null_Init,false);

    /* Primary FDC on by default, secondary is not. Most PCs have only one floppy controller. */
    Pbool = secprop->Add_bool("enable",Property::Changeable::OnlyAtStart,false);
    Pbool->Set_help("Enable floppy controller interface");
    Pbool->SetBasic(true);

    Pbool = secprop->Add_bool("pnp",Property::Changeable::OnlyAtStart,true);
    Pbool->Set_help("List floppy controller in ISA PnP BIOS enumeration");
    Pbool->SetBasic(true);

    Pint = secprop->Add_int("irq",Property::Changeable::WhenIdle,0/*use FDC default*/);
    Pint->Set_help("IRQ used by floppy controller. Set to 0 for default.\n"
        "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"
        "         Setting the IRQ to one already occupied by another device or IDE controller will trigger \"resource conflict\" errors in Windows 95.\n"
        "         Normally, floppy controllers use IRQ 6.");

    Phex = secprop->Add_hex("io",Property::Changeable::WhenIdle,0/*use FDC default*/);
    Phex->Set_help("Base I/O port for floppy controller. Set to 0 for default.\n"
        "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"
        "         Standard I/O ports are 3F0 and 370.");

    Pint = secprop->Add_int("dma",Property::Changeable::WhenIdle,-1/*use FDC default*/);
    Pint->Set_help("DMA channel for floppy controller. Set to -1 for default.\n"
        "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"
        "         Standard DMA channel is 2.");

    Pbool = secprop->Add_bool("int13fakev86io",Property::Changeable::WhenIdle,false);
    Pbool->Set_help(
        "If set, certain INT 13h commands will cause floppy emulation to issue fake CPU I/O\n"
        "traps (GPF) in virtual 8086 mode and a fake IRQ signal. You must enable this\n"
        "option if you want 32-bit floppy access in Windows 95 to work with DOSBox-X.");

    Pbool = secprop->Add_bool("instant mode",Property::Changeable::WhenIdle,false);
    Pbool->Set_help(
        "If set, all floppy operations are 'instantaneous', they are carried\n"
        "out without any delay. Real hardware of course has motor, command\n"
        "and data I/O delays and so this option is off by default for realistic\n"
        "emulation.");

    Pbool = secprop->Add_bool("auto-attach to int 13h",Property::Changeable::WhenIdle,true);
    Pbool->Set_help(
        "If set, DOSBox-X will automatically attach a disk image as being\n"
        "inserted into a floppy drive attached to the controller when imgmount is used\n"
        "to mount a disk image to drive 0/1 or A/B. If not set, you must specify\n"
        "the -fdc option to imgmount to attach drive A/B to the floppy controller\n"
        "manually. You must use the -fdc option regardless if loading floppies into\n"
        "drives attached to any other FDC than the primary controller");

    /* FIXME: From https://wiki.osdev.org/Floppy_Disk_Controller#Configure
     *
     *    "The three modes are PC-AT mode, PS/2 mode, and Model 30 mode. The most likely mode ... is model 30 mode.
     *    You may find some pre-1996 Pentium machines using PS/2 mode. You can ignore PC-AT mode."
     *
     *    What? What the fuck are you talking about?
     *
     *    "AT mode" seems to imply the presence of port 3F7. PS/2 mode seems to imply the presence of 3F0-3F1 and 3F7.
     *    A Toshiba laptop (Satellite Pro 465CDX) has port 3F7 but not 3F0-3F1. By other documentation I've found, that
     *    means this laptop (which came out late 1997) is running in AT mode! There's plenty of hardware running in both
     *    PS/2 and AT mode, even some very old stuff in my pile of junk dating back to 1990!
     *
     *    Somehow I think this information is as correct as their ATAPI programming docs on how to read CD-ROM
     *    sectors: it's a start but it's mostly wrong. Hopefully DOSLIB will shed light on what the real differences
     *    are and what is most common. --J.C. */
    Pstring = secprop->Add_string("mode",Property::Changeable::WhenIdle,"ps2");
    Pstring->Set_help(
        "Floppy controller mode. What the controller acts like.\n"
        "  ps2                          PS/2 mode (most common)\n"
        "  ps2_model30                  PS/2 model 30\n"
        "  at                           AT mode\n"
        "  xt                           PC/XT mode");
    Pstring->SetBasic(true);

    /* FIXME: Not yet implemented. Future plans */
    Pstring = secprop->Add_string("chip",Property::Changeable::WhenIdle,"82077aa");
    Pstring->Set_help(
        "Floppy controller chipset\n"
        "  82077aa                      Intel 82077AA chipset\n"
        "  82072                        Intel 82072 chipset\n"
        "  nec_uPD765                   NEC uPD765 chipset\n"
        "  none                         No chipset (For PC/XT mode)");

    /* 4DOS.INI options */
    secprop=control->AddSection_prop("4dos",&Null_Init,false);
    Pstring = secprop->Add_string("rem",Property::Changeable::OnlyAtStart,"This section is the 4DOS.INI file, if you use 4DOS as the command shell");
    Pstring->SetBasic(true);

    /* CONFIG.SYS options */
    secprop=control->AddSection_prop("config",&Null_Init,false);

    Pstring = secprop->Add_string("rem",Property::Changeable::OnlyAtStart,"This section is DOS's CONFIG.SYS file, not all CONFIG.SYS options supported");
 	Pstring->Set_help("Records comments (remarks).");
    Pstring->SetBasic(true);
    Pstring = secprop->Add_string("break",Property::Changeable::OnlyAtStart,"off");
	Pstring->Set_help("Sets or clears extended CTRL+C checking.");
    Pstring->Set_values(ps1opt);
    Pstring->SetBasic(true);
    Pstring = secprop->Add_string("numlock",Property::Changeable::OnlyAtStart,"");
	Pstring->Set_help("Sets the initial state of the NumLock key.");
    Pstring->Set_values(numopt);
    Pstring->SetBasic(true);
    Pstring = secprop->Add_string("shell",Property::Changeable::OnlyAtStart,"");
	Pstring->Set_help("Specifies the command shell (COMMAND.COM or 4DOS.COM).");
    Pstring->SetBasic(true);
    Pstring = secprop->Add_string("dos",Property::Changeable::OnlyAtStart,"high, umb");
	Pstring->Set_help("Reports whether DOS occupies HMA and allocates UMB memory (if available).");
    Pstring->SetBasic(true);
    Pint = secprop->Add_int("fcbs",Property::Changeable::OnlyAtStart,0);
    Pint->Set_help("Number of FCB handles available to DOS programs (1-255). Set to 0 to automatically use a reasonable default.");
    Pint->SetBasic(true);
    Pint = secprop->Add_int("files",Property::Changeable::OnlyAtStart,0);
    Pint->Set_help("Number of file handles available to DOS programs (8-255). Set to 0 to automatically use a reasonable default.");
    Pint->SetBasic(true);
    Pstring = secprop->Add_string("country",Property::Changeable::OnlyAtStart,"");
    Pstring->Set_help("Country code for date/time/decimal formats and optionally code page for TTF output and language files.");
    Pstring->SetBasic(true);
    Pstring = secprop->Add_string("lastdrive",Property::Changeable::OnlyAtStart,"a");
	Pstring->Set_help("The maximum drive letter (A-Z) that can be accessed by programs.");
    Pstring->Set_values(driveletters);
    Pstring->SetBasic(true);
    Pbool = secprop->Add_bool("device driver mcb",Property::Changeable::OnlyAtStart,false);
    Pbool->Set_help("If set, allocate a memory block per device driver. If not set, then where possible, the device driver chain is packed together within the DOS kernel without any MCB blocks to cover them, which is normal MS-DOS behavior");
    Pbool->SetBasic(false);

    control->AddSection_line("autoexec",&Null_Init);

    control->AddSection_line("devices",&Null_Init);

    AddMessages();
}

extern void POD_Save_Sdlmain( std::ostream& stream );
extern void POD_Load_Sdlmain( std::istream& stream );

// save state support

namespace
{
class SerializeDosbox : public SerializeGlobalPOD
{
public:
	SerializeDosbox() : SerializeGlobalPOD("Dosbox-x")
	{}

private:
	void getBytes(std::ostream& stream) override
	{

		//******************************************
		//******************************************
		//******************************************

		SerializeGlobalPOD::getBytes(stream);

		//******************************************
		//******************************************
		//******************************************

		POD_Save_Sdlmain(stream);
	}

	void setBytes(std::istream& stream) override
	{

		//******************************************
		//******************************************
		//******************************************

		SerializeGlobalPOD::setBytes(stream);

		//******************************************
		//******************************************
		//******************************************

		POD_Load_Sdlmain(stream);

		//*******************************************
		//*******************************************
		//*******************************************

		// Reset any auto cycle guessing for this frame
		ticksRemain=5;
		ticksLast = GetTicks();
		ticksAdded = 0;
		ticksDone = 0;
		ticksScheduled = 0;
	}
} dummy;
}

#if defined(_WIN32_WINDOWS) && defined(__MINGW64_VERSION_MAJOR) //win9x && mingw-w64 toolchain

//win9x's default msvcrt.dll doesn't have fstat64
//used by libstdc++
#include <sys/stat.h>
#undef _fstat
extern "C" int __cdecl internal_fstat64(int _FileDes,struct _stat64 *_Stat)
{
    struct stat st;
    //memset(&st,0,sizeof(st));
    int ret = fstat(_FileDes, &st);
    if (ret == -1) {
      memset(_Stat,0,sizeof(*_Stat));
      return -1;
    }
    _Stat->st_dev=st.st_dev;
    _Stat->st_ino=st.st_ino;
    _Stat->st_mode=st.st_mode;
    _Stat->st_nlink=st.st_nlink;
    _Stat->st_uid=st.st_uid;
    _Stat->st_gid=st.st_gid;
    _Stat->st_rdev=st.st_rdev;
    _Stat->st_size=(_off_t) st.st_size;
    _Stat->st_atime=st.st_atime;
    _Stat->st_mtime=st.st_mtime;
    _Stat->st_ctime=st.st_ctime;
    return ret;
}
extern "C" int __cdecl (*__MINGW_IMP_SYMBOL(_fstat64))(int,struct _stat64*) = internal_fstat64;

//win9x's default msvcrt.dll doesn't have strtoll/strtoull/strtoi64
//libstdc++ (__USE_MINGW_ANSI_STDIO=1)
//strtoll = _strtoi64
//*scanf -> __mingw_*scanf -> strtoll
extern "C" long long  __cdecl strtoll(const char * __restrict__ str, char ** __restrict ptr, int base)
{
    return strtol(str, ptr, base);
}

extern "C" unsigned long long  __cdecl strtoull(const char * __restrict__ str, char ** __restrict ptr, int base)
{
    return strtoul(str, ptr, base);
}

#endif
