From 4148655796b9571111d6990b9f79087357bc735d Mon Sep 17 00:00:00 2001 From: finalpatch Date: Thu, 2 Feb 2023 22:17:15 +1100 Subject: [PATCH 1/5] Support DPMI idle (INT 2FH Function 1680H) and DOS idle (INT 28H) --- src/dos/dev_con.h | 20 +++++++++++++++++++- src/dos/dos.cpp | 11 ++++++++++- src/dos/dos_misc.cpp | 4 +++- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/dos/dev_con.h b/src/dos/dev_con.h index 03a1a85a2..f5d223600 100644 --- a/src/dos/dev_con.h +++ b/src/dos/dev_con.h @@ -721,7 +721,25 @@ bool device_CON::Read(uint8_t * data,uint16_t * size) { continue; } - reg_ah=(IS_EGAVGA_ARCH)?0x10:0x0; + const uint8_t int16_poll_function=(IS_EGAVGA_ARCH)?0x11:0x1; + const uint8_t int16_read_function=(IS_EGAVGA_ARCH)?0x10:0x0; + // Poll the keyboard until there is a key-press ready to read. If there + // is no input (ZF=0) then call INT 28h to release the rest of our + // timeslice to host system. + while (true) { + reg_ah=int16_poll_function; + if (IS_PC98_ARCH) + INT16_Handler_Wrap(); + else + CALLBACK_RunRealInt(0x16); + if ((reg_flags & FLAG_ZF) == 0) { + break; + } else { + CALLBACK_RunRealInt(0x28); + } + } + + reg_ah=int16_read_function; /* FIXME: PC-98 emulation should eventually use CONIO emulation that * better emulates the actual platform. The purpose of this diff --git a/src/dos/dos.cpp b/src/dos/dos.cpp index d4608f3bf..c8f88a42c 100644 --- a/src/dos/dos.cpp +++ b/src/dos/dos.cpp @@ -3148,6 +3148,15 @@ static Bitu DOS_27Handler(void) { return CBRET_NONE; } +static Bitu DOS_28Handler(void) { + // Called by DOS keyboard input service (eg. when reading command-line + // input). In theory disk I/O should also call this while waiting for data + // from the device. But emulated disk is so fast this is probably not worth + // it. + CPU_Cycles = -1; + return CBRET_NONE; +} + static uint16_t DOS_SectorAccess(bool read) { fatDrive * drive = (fatDrive *)Drives[reg_al]; uint16_t bufferSeg = SegValue(ds); @@ -4262,7 +4271,7 @@ public: callback[4].Install(DOS_27Handler,CB_IRET,"DOS Int 27"); callback[4].Set_RealVec(0x27); - callback[5].Install(NULL,CB_IRET/*CB_INT28*/,"DOS idle"); + callback[5].Install(DOS_28Handler,CB_IRET/*CB_INT28*/,"DOS idle"); callback[5].Set_RealVec(0x28); if (IS_PC98_ARCH) { diff --git a/src/dos/dos_misc.cpp b/src/dos/dos_misc.cpp index 999a4b65e..3a89d83df 100644 --- a/src/dos/dos_misc.cpp +++ b/src/dos/dos_misc.cpp @@ -25,6 +25,7 @@ #include "dos_inc.h" #include "control.h" #include "support.h" +#include "cpu.h" #include #include @@ -396,7 +397,8 @@ static bool DOS_MultiplexFunctions(void) { return false; } case 0x1680: /* RELEASE CURRENT VIRTUAL MACHINE TIME-SLICE */ - //TODO Maybe do some idling but could screw up other systems :) + CPU_Cycles = -1; + reg_al = 0; return true; //So no warning in the debugger anymore case 0x1689: /* Kernel IDLE CALL */ case 0x168f: /* Close awareness crap */ From 2b7dceca058daaa2b38c84c967c132a36e5c3670 Mon Sep 17 00:00:00 2001 From: finalpatch Date: Sun, 5 Feb 2023 18:56:33 +1100 Subject: [PATCH 2/5] move cycles to iodelayremoved --- src/dos/dos.cpp | 3 ++- src/dos/dos_misc.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/dos/dos.cpp b/src/dos/dos.cpp index c8f88a42c..24a2e46e2 100644 --- a/src/dos/dos.cpp +++ b/src/dos/dos.cpp @@ -3153,7 +3153,8 @@ static Bitu DOS_28Handler(void) { // input). In theory disk I/O should also call this while waiting for data // from the device. But emulated disk is so fast this is probably not worth // it. - CPU_Cycles = -1; + CPU_IODelayRemoved += CPU_Cycles; + CPU_Cycles = 0; return CBRET_NONE; } diff --git a/src/dos/dos_misc.cpp b/src/dos/dos_misc.cpp index 3a89d83df..1aba6b837 100644 --- a/src/dos/dos_misc.cpp +++ b/src/dos/dos_misc.cpp @@ -397,7 +397,8 @@ static bool DOS_MultiplexFunctions(void) { return false; } case 0x1680: /* RELEASE CURRENT VIRTUAL MACHINE TIME-SLICE */ - CPU_Cycles = -1; + CPU_IODelayRemoved += CPU_Cycles; + CPU_Cycles = 0; reg_al = 0; return true; //So no warning in the debugger anymore case 0x1689: /* Kernel IDLE CALL */ From 52886edc2aeccda24dee170ef9aa566461a38c80 Mon Sep 17 00:00:00 2001 From: finalpatch Date: Sun, 5 Feb 2023 19:53:03 +1100 Subject: [PATCH 3/5] Restore the original INT 28H handler code --- include/callback.h | 2 +- src/cpu/callback.cpp | 4 ++-- src/dos/dos.cpp | 12 +----------- src/dos/dos_misc.cpp | 6 +++--- 4 files changed, 7 insertions(+), 17 deletions(-) diff --git a/include/callback.h b/include/callback.h index fddbf1ac3..8924f75df 100644 --- a/include/callback.h +++ b/include/callback.h @@ -27,7 +27,7 @@ extern CallBack_Handler CallBack_Handlers[]; enum { CB_RETN,CB_RETF,CB_RETF8,CB_IRET,CB_IRETD,CB_IRET_STI,CB_IRET_EOI_PIC1, CB_IRQ0,CB_IRQ1,CB_IRQ1_BREAK,CB_IRQ9,CB_IRQ12,CB_IRQ12_RET,CB_MOUSE, - /*CB_INT28,*/CB_INT29,CB_INT16,CB_HOOKABLE,CB_TDE_IRET,CB_IPXESR,CB_IPXESR_RET, + CB_INT28,CB_INT29,CB_INT16,CB_HOOKABLE,CB_TDE_IRET,CB_IPXESR,CB_IPXESR_RET, CB_INT21,CB_INT13,CB_VESA_WAIT,CB_VESA_PM,CB_IRET_EOI_PIC2,CB_CPM, CB_RETF_STI,CB_RETF_CLI,CB_INT6F_ATOK}; diff --git a/src/cpu/callback.cpp b/src/cpu/callback.cpp index 7725cec15..c371dc8ad 100644 --- a/src/cpu/callback.cpp +++ b/src/cpu/callback.cpp @@ -569,11 +569,11 @@ Bitu CALLBACK_SetupExtra(Bitu callback, Bitu type, PhysPt physAddress, bool use_ for (uint8_t i=0;i<=0x0b;i++) phys_writeb(physAddress+0x02+i,0x90); phys_writew(physAddress+0x0e,(uint16_t)0xedeb); //jmp callback return (use_cb?0x10:0x0c); - /*case CB_INT28: // DOS idle + case CB_INT28: // DOS idle phys_writeb(physAddress+0x00,(uint8_t)0xFB); // STI phys_writeb(physAddress+0x01,(uint8_t)0xF4); // HLT phys_writeb(physAddress+0x02,(uint8_t)0xcf); // An IRET Instruction - return (0x04);*/ + return (0x04); case CB_INT29: // fast console output if (IS_PC98_ARCH) LOG_MSG("WARNING: CB_INT29 callback setup not appropriate for PC-98 mode (INT 10h no longer BIOS call)"); if (use_cb) { diff --git a/src/dos/dos.cpp b/src/dos/dos.cpp index 24a2e46e2..aafc00436 100644 --- a/src/dos/dos.cpp +++ b/src/dos/dos.cpp @@ -3148,16 +3148,6 @@ static Bitu DOS_27Handler(void) { return CBRET_NONE; } -static Bitu DOS_28Handler(void) { - // Called by DOS keyboard input service (eg. when reading command-line - // input). In theory disk I/O should also call this while waiting for data - // from the device. But emulated disk is so fast this is probably not worth - // it. - CPU_IODelayRemoved += CPU_Cycles; - CPU_Cycles = 0; - return CBRET_NONE; -} - static uint16_t DOS_SectorAccess(bool read) { fatDrive * drive = (fatDrive *)Drives[reg_al]; uint16_t bufferSeg = SegValue(ds); @@ -4272,7 +4262,7 @@ public: callback[4].Install(DOS_27Handler,CB_IRET,"DOS Int 27"); callback[4].Set_RealVec(0x27); - callback[5].Install(DOS_28Handler,CB_IRET/*CB_INT28*/,"DOS idle"); + callback[5].Install(NULL,CB_INT28,"DOS idle"); callback[5].Set_RealVec(0x28); if (IS_PC98_ARCH) { diff --git a/src/dos/dos_misc.cpp b/src/dos/dos_misc.cpp index 1aba6b837..f29f376c9 100644 --- a/src/dos/dos_misc.cpp +++ b/src/dos/dos_misc.cpp @@ -397,10 +397,10 @@ static bool DOS_MultiplexFunctions(void) { return false; } case 0x1680: /* RELEASE CURRENT VIRTUAL MACHINE TIME-SLICE */ - CPU_IODelayRemoved += CPU_Cycles; - CPU_Cycles = 0; + CPU_STI(); + CPU_HLT(reg_eip); reg_al = 0; - return true; //So no warning in the debugger anymore + return true; case 0x1689: /* Kernel IDLE CALL */ case 0x168f: /* Close awareness crap */ /* Removing warning */ From d0768d6540fe6709d75d5701c18387fb0f43da80 Mon Sep 17 00:00:00 2001 From: finalpatch Date: Sun, 5 Feb 2023 20:00:47 +1100 Subject: [PATCH 4/5] use accessor --- src/dos/dev_con.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dos/dev_con.h b/src/dos/dev_con.h index f5d223600..29f66198b 100644 --- a/src/dos/dev_con.h +++ b/src/dos/dev_con.h @@ -732,7 +732,7 @@ bool device_CON::Read(uint8_t * data,uint16_t * size) { INT16_Handler_Wrap(); else CALLBACK_RunRealInt(0x16); - if ((reg_flags & FLAG_ZF) == 0) { + if (GETFLAG(ZF) == 0) { break; } else { CALLBACK_RunRealInt(0x28); From 7e875101f8cbaefb2e95c35323b2e5da431bb972 Mon Sep 17 00:00:00 2001 From: finalpatch Date: Sun, 5 Feb 2023 23:37:00 +1100 Subject: [PATCH 5/5] Add config option "dos/dos idle api" --- src/dos/dev_con.h | 30 +++++++++++++++++------------- src/dos/dos.cpp | 6 +++++- src/dos/dos_misc.cpp | 11 ++++++++--- src/dosbox.cpp | 4 ++++ 4 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/dos/dev_con.h b/src/dos/dev_con.h index 29f66198b..1cd56265c 100644 --- a/src/dos/dev_con.h +++ b/src/dos/dev_con.h @@ -723,19 +723,23 @@ bool device_CON::Read(uint8_t * data,uint16_t * size) { const uint8_t int16_poll_function=(IS_EGAVGA_ARCH)?0x11:0x1; const uint8_t int16_read_function=(IS_EGAVGA_ARCH)?0x10:0x0; - // Poll the keyboard until there is a key-press ready to read. If there - // is no input (ZF=0) then call INT 28h to release the rest of our - // timeslice to host system. - while (true) { - reg_ah=int16_poll_function; - if (IS_PC98_ARCH) - INT16_Handler_Wrap(); - else - CALLBACK_RunRealInt(0x16); - if (GETFLAG(ZF) == 0) { - break; - } else { - CALLBACK_RunRealInt(0x28); + + static const bool idle_enabled = ((Section_prop*)control->GetSection("dos"))->Get_bool("dos idle api"); + if (idle_enabled) { + // Poll the keyboard until there is a key-press ready to read. If there + // is no input (ZF=0) then call INT 28h to release the rest of our + // timeslice to host system. + while (true) { + reg_ah=int16_poll_function; + if (IS_PC98_ARCH) + INT16_Handler_Wrap(); + else + CALLBACK_RunRealInt(0x16); + if (GETFLAG(ZF) == 0) { + break; + } else { + CALLBACK_RunRealInt(0x28); + } } } diff --git a/src/dos/dos.cpp b/src/dos/dos.cpp index aafc00436..ab80c2e24 100644 --- a/src/dos/dos.cpp +++ b/src/dos/dos.cpp @@ -4262,7 +4262,11 @@ public: callback[4].Install(DOS_27Handler,CB_IRET,"DOS Int 27"); callback[4].Set_RealVec(0x27); - callback[5].Install(NULL,CB_INT28,"DOS idle"); + if (section->Get_bool("dos idle api")) { + callback[5].Install(NULL,CB_INT28,"DOS idle"); + } else { + callback[5].Install(NULL,CB_IRET,"DOS idle"); + } callback[5].Set_RealVec(0x28); if (IS_PC98_ARCH) { diff --git a/src/dos/dos_misc.cpp b/src/dos/dos_misc.cpp index f29f376c9..5239a4370 100644 --- a/src/dos/dos_misc.cpp +++ b/src/dos/dos_misc.cpp @@ -397,10 +397,15 @@ static bool DOS_MultiplexFunctions(void) { return false; } case 0x1680: /* RELEASE CURRENT VIRTUAL MACHINE TIME-SLICE */ - CPU_STI(); - CPU_HLT(reg_eip); - reg_al = 0; + { + static const bool idle_enabled = ((Section_prop*)control->GetSection("dos"))->Get_bool("dos idle api"); + if (idle_enabled) { + CPU_STI(); + CPU_HLT(reg_eip); + reg_al = 0; + } return true; + } case 0x1689: /* Kernel IDLE CALL */ case 0x168f: /* Close awareness crap */ /* Removing warning */ diff --git a/src/dosbox.cpp b/src/dosbox.cpp index 45d5abd9d..c21bd996d 100644 --- a/src/dosbox.cpp +++ b/src/dosbox.cpp @@ -4503,6 +4503,10 @@ void DOSBOX_SetupConfigSections(void) { Pbool->Set_help("If set, DOS APIs for communications with the Windows clipboard will be enabled for shared clipboard communications."); 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.");