From 974158842f26aac84605b4e0d5de1a689a302c86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Strohh=C3=A4cker?= Date: Sun, 26 Sep 2010 15:26:46 +0000 Subject: [PATCH] different EMS emulation types (ems board style, emm386 extended compatibility), fixes sound crackling in certain emm386-aware games Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@3642 --- include/dma.h | 2 + src/dosbox.cpp | 11 +++-- src/ints/ems.cpp | 118 ++++++++++++++++++++++++++++++----------------- src/ints/xms.cpp | 5 +- 4 files changed, 90 insertions(+), 46 deletions(-) diff --git a/include/dma.h b/include/dma.h index a12615db..acf724ee 100644 --- a/include/dma.h +++ b/include/dma.h @@ -114,6 +114,8 @@ DmaChannel * GetDMAChannel(Bit8u chan); void CloseSecondDMAController(void); bool SecondDMAControllerAvailable(void); +void DMA_SetWrapping(Bitu wrap); + static Bit32u dma_wrapping = 0xffff; #endif diff --git a/src/dosbox.cpp b/src/dosbox.cpp index a4bf5649..e12c9b79 100644 --- a/src/dosbox.cpp +++ b/src/dosbox.cpp @@ -333,7 +333,7 @@ void DOSBOX_Init(void) { const char* machines[] = { "hercules", "cga", "tandy", "pcjr", "ega", "vgaonly", "svga_s3", "svga_et3000", "svga_et4000", - "svga_paradise", "vesa_nolfb", "vesa_oldvbe", 0 }; + "svga_paradise", "vesa_nolfb", "vesa_oldvbe", 0 }; secprop=control->AddSection_prop("dosbox",&DOSBOX_RealInit); Pstring = secprop->Add_path("language",Property::Changeable::Always,""); Pstring->Set_help("Select another language file."); @@ -654,8 +654,13 @@ void DOSBOX_Init(void) { Pbool->Set_help("Enable XMS support."); secprop->AddInitFunction(&EMS_Init,true);//done - Pbool = secprop->Add_bool("ems",Property::Changeable::WhenIdle,true); - Pbool->Set_help("Enable EMS support."); + const char* ems_settings[] = { "true", "emsboard", "emm386", "false", 0}; + 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."); Pbool = secprop->Add_bool("umb",Property::Changeable::WhenIdle,true); Pbool->Set_help("Enable UMB support."); diff --git a/src/ints/ems.cpp b/src/ints/ems.cpp index a24a4a41..b8f399db 100644 --- a/src/ints/ems.cpp +++ b/src/ints/ems.cpp @@ -32,6 +32,7 @@ #include "setup.h" #include "support.h" #include "cpu.h" +#include "dma.h" #define EMM_PAGEFRAME 0xE000 #define EMM_PAGEFRAME4K ((EMM_PAGEFRAME*16)/4096) @@ -97,7 +98,8 @@ static Bit16u GEMMIS_seg; class device_EMM : public DOS_Device { public: - device_EMM() { + device_EMM(bool is_emm386_avail) { + is_emm386=is_emm386_avail; SetName("EMMXXXX0"); GEMMIS_seg=0; } @@ -113,6 +115,7 @@ public: bool WriteToControlChannel(PhysPt /*bufptr*/,Bit16u /*size*/,Bit16u * /*retcode*/){return true;} private: Bit8u cache; + bool is_emm386; }; bool device_EMM::ReadFromControlChannel(PhysPt bufptr,Bit16u size,Bit16u * retcode) { @@ -125,6 +128,7 @@ bool device_EMM::ReadFromControlChannel(PhysPt bufptr,Bit16u size,Bit16u * retco *retcode=6; return true; case 0x01: { + if (!is_emm386) return false; if (size!=6) return false; if (GEMMIS_seg==0) GEMMIS_seg=DOS_GetMemory(0x20); PhysPt GEMMIS_addr=PhysMake(GEMMIS_seg,0); @@ -181,12 +185,14 @@ bool device_EMM::ReadFromControlChannel(PhysPt bufptr,Bit16u size,Bit16u * retco return true; } case 0x02: + if (!is_emm386) return false; if (size!=2) return false; mem_writeb(bufptr+0x00,EMM_VERSION>>4); // version 4 mem_writeb(bufptr+0x01,EMM_MINOR_VERSION); *retcode=2; return true; case 0x03: + if (!is_emm386) return false; if (EMM_MINOR_VERSION < 0x2d) return false; if (size!=4) return false; mem_writew(bufptr+0x00,(Bit16u)(MEM_TotalPages()*4)); // max size (kb) @@ -1262,18 +1268,37 @@ static Bitu INT4B_Handler() { return CBRET_NONE; } +Bitu GetEMSType(Section_prop * section) { + Bitu rtype = 0; + std::string emstypestr(section->Get_string("ems")); + if (emstypestr=="true") { + rtype = 1; // mixed mode + } else if (emstypestr=="emsboard") { + rtype = 2; + } else if (emstypestr=="emm386") { + rtype = 3; + } else { + rtype = 0; + } + return rtype; +} + class EMS: public Module_base { private: + DOS_Device * emm_device; /* location in protected unfreeable memory where the ems name and callback are * stored 32 bytes.*/ static Bit16u ems_baseseg; RealPt old4b_pointer,old67_pointer; CALLBACK_HandlerObject call_vdma,call_vcpi,call_v86mon; Bitu call_int67; + Bitu ems_type; public: - EMS(Section* configuration):Module_base(configuration){ + EMS(Section* configuration):Module_base(configuration) { + emm_device=NULL; + ems_type=0; /* Virtual DMA interrupt callback */ call_vdma.Install(&INT4B_Handler,CB_IRET,"Int 4b vdma"); @@ -1283,8 +1308,11 @@ public: GEMMIS_seg=0; Section_prop * section=static_cast(configuration); - if (!section->Get_bool("ems")) return; + ems_type=GetEMSType(section); + if (ems_type<=0) return; + if (machine==MCH_PCJR) { + ems_type=0; LOG_MSG("EMS disabled for PCJr machine"); return; } @@ -1302,8 +1330,8 @@ public: /* Register the ems device */ //TODO MAYBE put it in the class. - DOS_Device * newdev = new device_EMM(); - DOS_AddDevice(newdev); + emm_device = new device_EMM(ems_type!=2); + DOS_AddDevice(emm_device); /* Clear handle and page tables */ Bitu i; @@ -1323,61 +1351,67 @@ public: EMM_AllocateSystemHandle(8); // allocate OS-dedicated handle (ems handle zero, 128kb) + if (ems_type==3) { + DMA_SetWrapping(0xffffffff); // emm386-bug that disables dma wrapping + } if (!ENABLE_VCPI) return; - /* Install a callback that handles VCPI-requests in protected mode requests */ - call_vcpi.Install(&VCPI_PM_Handler,CB_IRETD,"VCPI PM"); - vcpi.pm_interface=(call_vcpi.Get_callback())*CB_SIZE; + if (ems_type!=2) { + /* Install a callback that handles VCPI-requests in protected mode requests */ + call_vcpi.Install(&VCPI_PM_Handler,CB_IRETD,"VCPI PM"); + vcpi.pm_interface=(call_vcpi.Get_callback())*CB_SIZE; - /* Initialize private data area and set up descriptor tables */ - SetupVCPI(); + /* Initialize private data area and set up descriptor tables */ + SetupVCPI(); - if (!vcpi.enabled) return; + if (!vcpi.enabled) return; - /* Install v86-callback that handles interrupts occuring - in v86 mode, including protection fault exceptions */ - call_v86mon.Install(&V86_Monitor,CB_IRET,"V86 Monitor"); + /* Install v86-callback that handles interrupts occuring + in v86 mode, including protection fault exceptions */ + call_v86mon.Install(&V86_Monitor,CB_IRET,"V86 Monitor"); - mem_writeb(vcpi.private_area+0x2e00,(Bit8u)0xFE); //GRP 4 - mem_writeb(vcpi.private_area+0x2e01,(Bit8u)0x38); //Extra Callback instruction - mem_writew(vcpi.private_area+0x2e02,call_v86mon.Get_callback()); //The immediate word - mem_writeb(vcpi.private_area+0x2e04,(Bit8u)0x66); - mem_writeb(vcpi.private_area+0x2e05,(Bit8u)0xCF); //A IRETD Instruction + mem_writeb(vcpi.private_area+0x2e00,(Bit8u)0xFE); //GRP 4 + mem_writeb(vcpi.private_area+0x2e01,(Bit8u)0x38); //Extra Callback instruction + mem_writew(vcpi.private_area+0x2e02,call_v86mon.Get_callback()); //The immediate word + mem_writeb(vcpi.private_area+0x2e04,(Bit8u)0x66); + mem_writeb(vcpi.private_area+0x2e05,(Bit8u)0xCF); //A IRETD Instruction - /* Testcode only, starts up dosbox in v86-mode */ - if (ENABLE_V86_STARTUP) { - /* Prepare V86-task */ - CPU_SET_CRX(0, 1); - CPU_LGDT(0xff, vcpi.private_area+0x0000); - CPU_LIDT(0x7ff, vcpi.private_area+0x2000); - if (CPU_LLDT(0x08)) LOG_MSG("VCPI:Could not load LDT"); - if (CPU_LTR(0x10)) LOG_MSG("VCPI:Could not load TR"); + /* Testcode only, starts up dosbox in v86-mode */ + if (ENABLE_V86_STARTUP) { + /* Prepare V86-task */ + CPU_SET_CRX(0, 1); + CPU_LGDT(0xff, vcpi.private_area+0x0000); + CPU_LIDT(0x7ff, vcpi.private_area+0x2000); + if (CPU_LLDT(0x08)) LOG_MSG("VCPI:Could not load LDT"); + if (CPU_LTR(0x10)) LOG_MSG("VCPI:Could not load TR"); - CPU_Push32(SegValue(gs)); - CPU_Push32(SegValue(fs)); - CPU_Push32(SegValue(ds)); - CPU_Push32(SegValue(es)); - CPU_Push32(SegValue(ss)); - CPU_Push32(0x23002); - CPU_Push32(SegValue(cs)); - CPU_Push32(reg_eip&0xffff); - /* Switch to V86-mode */ - cpu.cpl=0; - CPU_IRET(true,0); + CPU_Push32(SegValue(gs)); + CPU_Push32(SegValue(fs)); + CPU_Push32(SegValue(ds)); + CPU_Push32(SegValue(es)); + CPU_Push32(SegValue(ss)); + CPU_Push32(0x23002); + CPU_Push32(SegValue(cs)); + CPU_Push32(reg_eip&0xffff); + /* Switch to V86-mode */ + cpu.cpl=0; + CPU_IRET(true,0); + } } } ~EMS() { - Section_prop * section=static_cast(m_configuration); - if (!section->Get_bool("ems")) return; + if (ems_type<=0) return; /* Undo Biosclearing */ BIOS_ZeroExtendedSize(false); /* Remove ems device */ - device_EMM newdev; - DOS_DelDevice(&newdev); + if (emm_device!=NULL) { + DOS_DelDevice(emm_device); + emm_device=NULL; + } GEMMIS_seg=0; /* Remove the emsname and callback hack */ diff --git a/src/ints/xms.cpp b/src/ints/xms.cpp index 456fab1f..a4349e7e 100644 --- a/src/ints/xms.cpp +++ b/src/ints/xms.cpp @@ -412,6 +412,8 @@ Bitu XMS_Handler(void) { return CBRET_NONE; } +Bitu GetEMSType(Section_prop * section); + class XMS: public Module_base { private: CALLBACK_HandlerObject callbackhandler; @@ -445,7 +447,8 @@ public: /* Set up UMB chain */ umb_available=section->Get_bool("umb"); - DOS_BuildUMBChain(section->Get_bool("umb"),section->Get_bool("ems")); + bool ems_available = GetEMSType(section)>0; + DOS_BuildUMBChain(section->Get_bool("umb"),ems_available); } ~XMS(){