mirror of
https://github.com/joncampbell123/dosbox-x.git
synced 2025-05-09 03:41:10 +08:00
here begins the big question: what do motherboards do with the address
register and page register when carrying out 16-bit DMA? this change updates the code to allow either one method that allows 128KB boundaries for 16-bit DMA (which DOSBox has already been doing anyway) and the other method that limits 16-bit DMA to 64KB boundaries but preserves all bits of the page register (which is said to be the way PCI-based motherboard do it). You can choose which one from dosbox.conf now, or let DOSBox-X decide based on your hardware configuration (which is currently based on whether or not the VM has PCI emulation enabled).
This commit is contained in:
parent
014b5f9930
commit
82cd1b54ad
@ -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;
|
||||
|
@ -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.");
|
||||
|
@ -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<<dma16)+dma16) | dma_wrapping;
|
||||
Bit32u dma_wrap = (((0xffff<<dma16)+dma16)&DMA16_ADDRMASK) | dma_wrapping;
|
||||
for ( ; size ; size--, offset++) {
|
||||
offset &= dma_wrap;
|
||||
Bitu page = highpart_addr_page+(offset >> 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<<dma16)+dma16) | dma_wrapping;
|
||||
Bit32u dma_wrap = (((0xffff<<dma16)+dma16)&DMA16_ADDRMASK) | dma_wrapping;
|
||||
|
||||
if (dma16) {
|
||||
/* I'm going to assume by how ISA DMA works that you can't just copy bytes backwards,
|
||||
@ -114,12 +117,12 @@ static void DMA_BlockReadBackwards(PhysPt spage,PhysPt offset,void * data,Bitu s
|
||||
}
|
||||
|
||||
/* write a block into physical memory */
|
||||
static void DMA_BlockWrite(PhysPt spage,PhysPt offset,void * data,Bitu size,Bit8u dma16) {
|
||||
static void DMA_BlockWrite(PhysPt spage,PhysPt offset,void * data,Bitu size,Bit8u dma16,const Bit32u DMA16_ADDRMASK) {
|
||||
Bit8u * read=(Bit8u *) data;
|
||||
Bitu highpart_addr_page = spage>>12;
|
||||
size <<= dma16;
|
||||
offset <<= dma16;
|
||||
Bit32u dma_wrap = ((0xffff<<dma16)+dma16) | dma_wrapping;
|
||||
Bit32u dma_wrap = (((0xffff<<dma16)+dma16)&DMA16_ADDRMASK) | dma_wrapping;
|
||||
for ( ; size ; size--, offset++) {
|
||||
if (offset>(dma_wrapping<<dma16)) {
|
||||
LOG_MSG("DMA segbound wrapping (write): %x:%x size %x [%x] wrap %x",(int)spage,(int)offset,(int)size,dma16,(int)dma_wrapping);
|
||||
@ -342,7 +345,15 @@ DmaChannel::DmaChannel(Bit8u num, bool dma16) {
|
||||
if(num == 4) return;
|
||||
channum = num;
|
||||
DMA16 = dma16 ? 0x1 : 0x0;
|
||||
pagenum = 0;
|
||||
|
||||
if (isadma128k >= 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 (want<left) {
|
||||
if (increment) {
|
||||
DMA_BlockRead(pagebase,curraddr,buffer,want,DMA16);
|
||||
DMA_BlockRead(pagebase,curraddr,buffer,want,DMA16,DMA16_ADDRMASK);
|
||||
curraddr+=want;
|
||||
}
|
||||
else {
|
||||
DMA_BlockReadBackwards(pagebase,curraddr,buffer,want,DMA16);
|
||||
DMA_BlockReadBackwards(pagebase,curraddr,buffer,want,DMA16,DMA16_ADDRMASK);
|
||||
curraddr-=want;
|
||||
}
|
||||
|
||||
@ -380,9 +391,9 @@ again:
|
||||
done+=want;
|
||||
} else {
|
||||
if (increment)
|
||||
DMA_BlockRead(pagebase,curraddr,buffer,want,DMA16);
|
||||
DMA_BlockRead(pagebase,curraddr,buffer,want,DMA16,DMA16_ADDRMASK);
|
||||
else
|
||||
DMA_BlockReadBackwards(pagebase,curraddr,buffer,want,DMA16);
|
||||
DMA_BlockReadBackwards(pagebase,curraddr,buffer,want,DMA16,DMA16_ADDRMASK);
|
||||
|
||||
buffer+=left << DMA16;
|
||||
want-=left;
|
||||
@ -425,12 +436,12 @@ Bitu DmaChannel::Write(Bitu want, Bit8u * buffer) {
|
||||
again:
|
||||
Bitu left=(currcnt+1);
|
||||
if (want<left) {
|
||||
DMA_BlockWrite(pagebase,curraddr,buffer,want,DMA16);
|
||||
DMA_BlockWrite(pagebase,curraddr,buffer,want,DMA16,DMA16_ADDRMASK);
|
||||
done+=want;
|
||||
curraddr+=want;
|
||||
currcnt-=want;
|
||||
} else {
|
||||
DMA_BlockWrite(pagebase,curraddr,buffer,left,DMA16);
|
||||
DMA_BlockWrite(pagebase,curraddr,buffer,left,DMA16,DMA16_ADDRMASK);
|
||||
buffer+=left << DMA16;
|
||||
want-=left;
|
||||
done+=left;
|
||||
@ -491,6 +502,17 @@ void DMA_Reset(Section* /*sec*/) {
|
||||
dma_page_register_writeonly = section->Get_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
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user