mirror of
https://github.com/joncampbell123/dosbox-x.git
synced 2025-05-09 11:51:09 +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;
|
Bit16u currcnt;
|
||||||
Bit8u channum;
|
Bit8u channum;
|
||||||
Bit8u pagenum;
|
Bit8u pagenum;
|
||||||
|
Bit8u DMA16_PAGESHIFT;
|
||||||
|
Bit32u DMA16_ADDRMASK;
|
||||||
Bit8u DMA16;
|
Bit8u DMA16;
|
||||||
bool increment;
|
bool increment;
|
||||||
bool autoinit;
|
bool autoinit;
|
||||||
@ -57,6 +59,16 @@ public:
|
|||||||
masked=_mask;
|
masked=_mask;
|
||||||
DoCallBack(masked ? DMA_MASKED : DMA_UNMASKED);
|
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) {
|
void Register_Callback(DMA_CallBack _cb) {
|
||||||
callback = _cb;
|
callback = _cb;
|
||||||
SetMask(masked);
|
SetMask(masked);
|
||||||
@ -69,7 +81,7 @@ public:
|
|||||||
}
|
}
|
||||||
void SetPage(Bit8u val) {
|
void SetPage(Bit8u val) {
|
||||||
pagenum=val;
|
pagenum=val;
|
||||||
pagebase=(pagenum >> DMA16) << (16+DMA16);
|
pagebase=(pagenum >> DMA16_PAGESHIFT) << (16+DMA16_PAGESHIFT);
|
||||||
}
|
}
|
||||||
void Raise_Request(void) {
|
void Raise_Request(void) {
|
||||||
request=true;
|
request=true;
|
||||||
|
@ -843,6 +843,7 @@ void DOSBOX_SetupConfigSections(void) {
|
|||||||
const char *qualityno[] = { "0", "1", "2", "3", 0 };
|
const char *qualityno[] = { "0", "1", "2", "3", 0 };
|
||||||
const char* tandys[] = { "auto", "on", "off", 0};
|
const char* tandys[] = { "auto", "on", "off", 0};
|
||||||
const char* ps1opt[] = { "on", "off", 0};
|
const char* ps1opt[] = { "on", "off", 0};
|
||||||
|
const char* truefalseautoopt[] = { "true", "false", "1", "0", "auto", 0};
|
||||||
|
|
||||||
const char* irqssbhack[] = {
|
const char* irqssbhack[] = {
|
||||||
"none", "cs_equ_ds", 0
|
"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"
|
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).");
|
"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 = 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"
|
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.");
|
"Note that mainline DOSBox behavior is to NOT emulate these registers.");
|
||||||
|
@ -27,6 +27,8 @@
|
|||||||
#include "setup.h"
|
#include "setup.h"
|
||||||
#include "control.h"
|
#include "control.h"
|
||||||
|
|
||||||
|
bool has_pcibus_enable(void);
|
||||||
|
|
||||||
DmaController *DmaControllers[2]={NULL};
|
DmaController *DmaControllers[2]={NULL};
|
||||||
unsigned char dma_extra_page_registers[16]={0}; /* 0x80-0x8F */
|
unsigned char dma_extra_page_registers[16]={0}; /* 0x80-0x8F */
|
||||||
bool enable_dma_extra_page_registers = true;
|
bool enable_dma_extra_page_registers = true;
|
||||||
@ -40,6 +42,7 @@ static Bit32u dma_wrapping = 0xffff;
|
|||||||
bool enable_1st_dma = true;
|
bool enable_1st_dma = true;
|
||||||
bool enable_2nd_dma = true;
|
bool enable_2nd_dma = true;
|
||||||
bool allow_decrement_mode = true;
|
bool allow_decrement_mode = true;
|
||||||
|
int isadma128k = -1;
|
||||||
|
|
||||||
static void UpdateEMSMapping(void) {
|
static void UpdateEMSMapping(void) {
|
||||||
/* if EMS is not present, this will result in a 1:1 mapping */
|
/* 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 */
|
/* 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;
|
Bit8u * write=(Bit8u *) data;
|
||||||
Bitu highpart_addr_page = spage>>12;
|
Bitu highpart_addr_page = spage>>12;
|
||||||
size <<= dma16;
|
size <<= dma16;
|
||||||
offset <<= 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++) {
|
for ( ; size ; size--, offset++) {
|
||||||
offset &= dma_wrap;
|
offset &= dma_wrap;
|
||||||
Bitu page = highpart_addr_page+(offset >> 12);
|
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,
|
* 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
|
* and THEN increments or decrements the address. So in decrement mode, "address" is still the
|
||||||
* first byte before decrementing. */
|
* 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;
|
Bit8u * write=(Bit8u *) data;
|
||||||
Bitu highpart_addr_page = spage>>12;
|
Bitu highpart_addr_page = spage>>12;
|
||||||
|
|
||||||
size <<= dma16;
|
size <<= dma16;
|
||||||
offset <<= dma16;
|
offset <<= dma16;
|
||||||
Bit32u dma_wrap = ((0xffff<<dma16)+dma16) | dma_wrapping;
|
Bit32u dma_wrap = (((0xffff<<dma16)+dma16)&DMA16_ADDRMASK) | dma_wrapping;
|
||||||
|
|
||||||
if (dma16) {
|
if (dma16) {
|
||||||
/* I'm going to assume by how ISA DMA works that you can't just copy bytes backwards,
|
/* 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 */
|
/* 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;
|
Bit8u * read=(Bit8u *) data;
|
||||||
Bitu highpart_addr_page = spage>>12;
|
Bitu highpart_addr_page = spage>>12;
|
||||||
size <<= dma16;
|
size <<= dma16;
|
||||||
offset <<= 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++) {
|
for ( ; size ; size--, offset++) {
|
||||||
if (offset>(dma_wrapping<<dma16)) {
|
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);
|
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;
|
if(num == 4) return;
|
||||||
channum = num;
|
channum = num;
|
||||||
DMA16 = dma16 ? 0x1 : 0x0;
|
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;
|
pagebase = 0;
|
||||||
baseaddr = 0;
|
baseaddr = 0;
|
||||||
curraddr = 0;
|
curraddr = 0;
|
||||||
@ -368,11 +379,11 @@ again:
|
|||||||
Bitu left=(currcnt+1);
|
Bitu left=(currcnt+1);
|
||||||
if (want<left) {
|
if (want<left) {
|
||||||
if (increment) {
|
if (increment) {
|
||||||
DMA_BlockRead(pagebase,curraddr,buffer,want,DMA16);
|
DMA_BlockRead(pagebase,curraddr,buffer,want,DMA16,DMA16_ADDRMASK);
|
||||||
curraddr+=want;
|
curraddr+=want;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
DMA_BlockReadBackwards(pagebase,curraddr,buffer,want,DMA16);
|
DMA_BlockReadBackwards(pagebase,curraddr,buffer,want,DMA16,DMA16_ADDRMASK);
|
||||||
curraddr-=want;
|
curraddr-=want;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,9 +391,9 @@ again:
|
|||||||
done+=want;
|
done+=want;
|
||||||
} else {
|
} else {
|
||||||
if (increment)
|
if (increment)
|
||||||
DMA_BlockRead(pagebase,curraddr,buffer,want,DMA16);
|
DMA_BlockRead(pagebase,curraddr,buffer,want,DMA16,DMA16_ADDRMASK);
|
||||||
else
|
else
|
||||||
DMA_BlockReadBackwards(pagebase,curraddr,buffer,want,DMA16);
|
DMA_BlockReadBackwards(pagebase,curraddr,buffer,want,DMA16,DMA16_ADDRMASK);
|
||||||
|
|
||||||
buffer+=left << DMA16;
|
buffer+=left << DMA16;
|
||||||
want-=left;
|
want-=left;
|
||||||
@ -425,12 +436,12 @@ Bitu DmaChannel::Write(Bitu want, Bit8u * buffer) {
|
|||||||
again:
|
again:
|
||||||
Bitu left=(currcnt+1);
|
Bitu left=(currcnt+1);
|
||||||
if (want<left) {
|
if (want<left) {
|
||||||
DMA_BlockWrite(pagebase,curraddr,buffer,want,DMA16);
|
DMA_BlockWrite(pagebase,curraddr,buffer,want,DMA16,DMA16_ADDRMASK);
|
||||||
done+=want;
|
done+=want;
|
||||||
curraddr+=want;
|
curraddr+=want;
|
||||||
currcnt-=want;
|
currcnt-=want;
|
||||||
} else {
|
} else {
|
||||||
DMA_BlockWrite(pagebase,curraddr,buffer,left,DMA16);
|
DMA_BlockWrite(pagebase,curraddr,buffer,left,DMA16,DMA16_ADDRMASK);
|
||||||
buffer+=left << DMA16;
|
buffer+=left << DMA16;
|
||||||
want-=left;
|
want-=left;
|
||||||
done+=left;
|
done+=left;
|
||||||
@ -491,6 +502,17 @@ void DMA_Reset(Section* /*sec*/) {
|
|||||||
dma_page_register_writeonly = section->Get_bool("dma page registers write-only");
|
dma_page_register_writeonly = section->Get_bool("dma page registers write-only");
|
||||||
allow_decrement_mode = section->Get_bool("allow dma address decrement");
|
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)
|
if (enable_1st_dma)
|
||||||
DmaControllers[0] = new DmaController(0);
|
DmaControllers[0] = new DmaController(0);
|
||||||
else
|
else
|
||||||
|
@ -34,6 +34,10 @@
|
|||||||
bool pcibus_enable = false;
|
bool pcibus_enable = false;
|
||||||
bool log_pci = false;
|
bool log_pci = false;
|
||||||
|
|
||||||
|
bool has_pcibus_enable(void) {
|
||||||
|
return pcibus_enable;
|
||||||
|
}
|
||||||
|
|
||||||
static Bit32u pci_caddress=0; // current PCI addressing
|
static Bit32u pci_caddress=0; // current PCI addressing
|
||||||
|
|
||||||
static PCI_Device* pci_devices[PCI_MAX_PCIBUSSES][PCI_MAX_PCIDEVICES]={{NULL}}; // registered PCI devices
|
static PCI_Device* pci_devices[PCI_MAX_PCIBUSSES][PCI_MAX_PCIDEVICES]={{NULL}}; // registered PCI devices
|
||||||
|
Loading…
x
Reference in New Issue
Block a user