diff --git a/include/dma.h b/include/dma.h index f5f4b08ee..0d4dffacf 100644 --- a/include/dma.h +++ b/include/dma.h @@ -40,6 +40,8 @@ public: Bit16u currcnt; Bit8u channum; Bit8u pagenum; + Bit8u DMA16_PAGESHIFT; + Bit32u DMA16_ADDRMASK; Bit8u DMA16; bool increment; bool autoinit; @@ -57,6 +59,16 @@ public: masked=_mask; DoCallBack(masked ? DMA_MASKED : DMA_UNMASKED); } + void Set128KMode(bool en) { + // 128KB mode (legacy ISA) (en=true): + // page shift = 1 (discard bit 0 of page register) + // addr mask = 0x1FFFF (all bits 0-15 become bits 1-16, bit 15 of addr takes the place of page register bit 0) + // 64KB mode (modern PCI including Intel chipsets) (en=false): + // page shift = 0 (all 8 bits of page register are used) + // addr mask = 0xFFFF (discard bit 15, bits 0-14 become bits 1-15 on ISA bus) + DMA16_PAGESHIFT = (en && DMA16) ? 0x1 : 0x0; // nonzero if we're to discard bit 0 of page register + DMA16_ADDRMASK = (1UL << ((en && DMA16) ? 17UL : 16UL)) - 1UL; // nonzero if (addrreg << 1) to cover 128KB, zero if (addrreg << 1) to discard MSB, limit to 64KB + } void Register_Callback(DMA_CallBack _cb) { callback = _cb; SetMask(masked); @@ -69,7 +81,7 @@ public: } void SetPage(Bit8u val) { pagenum=val; - pagebase=(pagenum >> DMA16) << (16+DMA16); + pagebase=(pagenum >> DMA16_PAGESHIFT) << (16+DMA16_PAGESHIFT); } void Raise_Request(void) { request=true; diff --git a/src/dosbox.cpp b/src/dosbox.cpp index f71e012e8..87fb1f1d6 100644 --- a/src/dosbox.cpp +++ b/src/dosbox.cpp @@ -843,6 +843,7 @@ void DOSBOX_SetupConfigSections(void) { const char *qualityno[] = { "0", "1", "2", "3", 0 }; const char* tandys[] = { "auto", "on", "off", 0}; const char* ps1opt[] = { "on", "off", 0}; + const char* truefalseautoopt[] = { "true", "false", "1", "0", "auto", 0}; const char* irqssbhack[] = { "none", "cs_equ_ds", 0 @@ -1157,6 +1158,12 @@ void DOSBOX_SetupConfigSections(void) { 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."); diff --git a/src/hardware/dma.cpp b/src/hardware/dma.cpp index a3d959857..048b83cc8 100644 --- a/src/hardware/dma.cpp +++ b/src/hardware/dma.cpp @@ -27,6 +27,8 @@ #include "setup.h" #include "control.h" +bool has_pcibus_enable(void); + DmaController *DmaControllers[2]={NULL}; unsigned char dma_extra_page_registers[16]={0}; /* 0x80-0x8F */ bool enable_dma_extra_page_registers = true; @@ -40,6 +42,7 @@ static Bit32u dma_wrapping = 0xffff; bool enable_1st_dma = true; bool enable_2nd_dma = true; bool allow_decrement_mode = true; +int isadma128k = -1; static void UpdateEMSMapping(void) { /* if EMS is not present, this will result in a 1:1 mapping */ @@ -50,12 +53,12 @@ static void UpdateEMSMapping(void) { } /* read a block from physical memory */ -static void DMA_BlockRead(PhysPt spage,PhysPt offset,void * data,Bitu size,Bit8u dma16) { +static void DMA_BlockRead(PhysPt spage,PhysPt offset,void * data,Bitu size,Bit8u dma16,const Bit32u DMA16_ADDRMASK) { Bit8u * write=(Bit8u *) data; Bitu highpart_addr_page = spage>>12; size <<= dma16; offset <<= dma16; - Bit32u dma_wrap = ((0xffff<> 12); @@ -73,13 +76,13 @@ static void DMA_BlockRead(PhysPt spage,PhysPt offset,void * data,Bitu size,Bit8u * NTS: Don't forget, from 8237 datasheet: The DMA chip transfers a byte (or word if 16-bit) of data, * and THEN increments or decrements the address. So in decrement mode, "address" is still the * first byte before decrementing. */ -static void DMA_BlockReadBackwards(PhysPt spage,PhysPt offset,void * data,Bitu size,Bit8u dma16) { +static void DMA_BlockReadBackwards(PhysPt spage,PhysPt offset,void * data,Bitu size,Bit8u dma16,const Bit32u DMA16_ADDRMASK) { Bit8u * write=(Bit8u *) data; Bitu highpart_addr_page = spage>>12; size <<= dma16; offset <<= dma16; - Bit32u dma_wrap = ((0xffff<>12; size <<= dma16; offset <<= dma16; - Bit32u dma_wrap = ((0xffff<(dma_wrapping<= 0) + Set128KMode(isadma128k > 0); // user's choice + else + Set128KMode(has_pcibus_enable()); // auto, based on whether PCI bus is present + + LOG(LOG_DMACONTROL,LOG_DEBUG)("DMA channel %u. DMA16_PAGESHIFT=%u DMA16_ADDRMASK=0x%lx", + (unsigned int)channum,(unsigned int)DMA16_PAGESHIFT,(unsigned long)DMA16_ADDRMASK); + pagenum = 0; pagebase = 0; baseaddr = 0; curraddr = 0; @@ -368,11 +379,11 @@ again: Bitu left=(currcnt+1); if (wantGet_bool("dma page registers write-only"); allow_decrement_mode = section->Get_bool("allow dma address decrement"); + { + std::string s = section->Get_string("enable 128k capable 16-bit dma"); + + if (s == "true" || s == "1") + isadma128k = 1; + else if (s == "false" || s == "0") + isadma128k = 0; + else + isadma128k = -1; + } + if (enable_1st_dma) DmaControllers[0] = new DmaController(0); else diff --git a/src/hardware/pci_bus.cpp b/src/hardware/pci_bus.cpp index 02995f450..3e9921b0e 100644 --- a/src/hardware/pci_bus.cpp +++ b/src/hardware/pci_bus.cpp @@ -34,6 +34,10 @@ bool pcibus_enable = false; bool log_pci = false; +bool has_pcibus_enable(void) { + return pcibus_enable; +} + static Bit32u pci_caddress=0; // current PCI addressing static PCI_Device* pci_devices[PCI_MAX_PCIBUSSES][PCI_MAX_PCIDEVICES]={{NULL}}; // registered PCI devices