Applied all mainline PCem commits;
Added experimental NVidia Riva TNT2 emulation (patch from MoochMcGee); ASUS P/I-P54TP4XE, ASUS P/I-P55T2P4, and ASUS P/I-P55TVP4 are back; National Semiconductor PC87306 Super I/O chip now correctly reenables devices after a chip power cycle; Several FDC improvements and the behavior is now a bit closer to real hardware (based on actual tests); Added MR Intel Advanced/ATX with Microid Research BIOS with support for 4 floppy drives and up to 4 IDE controllers; Added floppy drives 3 and 4, bringing the maximum to 4; You can now connect hard disks to the tertiary IDE controller; Correct undocumented behavior of the LEA instruction with register is back on 286 and later CPU's; Pentium-rea models with Intel chipsets now have port 92 (with alternate reset and alternate A20 toggle); Overhauled DMA channel read and write routines and fixed cascading; Improved IMG detection of a bad BPB (or complete lack of a BPB); Added preliminary emulation of PS/2 1.44 MB and PC-98 1.25 MB 3-mode drives (both have an inverted DENSEL pin); Removed the incorrect Amstrad mouse patch from TheCollector1995; Fixed ATAPI CD-ROM disk change detection; Windows IOCTL CD-ROM handler now tries to use direct SCSI passthrough for more things, including obtaining CD-ROM capacity; The Diamond Stealth32 (ET4000/W32p) now also works correctly on the two Award SiS 496/497 boxes; The (S)VGA handler now converts 6-bit RAMDAC RGB channels to standard 8-bit RGB using a lookup table generated at emulator start, calculated using the correct intensity conversion method and treating intensity 64 as equivalent to 63; Moved a few options from the Configuration dialog box to the menu; SIO, PIIX, and PIIX3 now have the reset control register on port CF9 as they should; Several bugfixes.
This commit is contained in:
450
src/dma.c
450
src/dma.c
@@ -86,7 +86,7 @@ void dma_write(uint16_t addr, uint8_t val, void *priv)
|
||||
dma.wp ^= 1;
|
||||
if (dma.wp) dma.ab[(addr >> 1) & 3] = (dma.ab[(addr >> 1) & 3] & 0xff00) | val;
|
||||
else dma.ab[(addr >> 1) & 3] = (dma.ab[(addr >> 1) & 3] & 0x00ff) | (val << 8);
|
||||
dma.ac[(addr >> 1) & 3] = dma.ab[(addr >> 1) & 3];
|
||||
dma.ac[(addr >> 1) & 3] = dma.ab[(addr >> 1) & 3] & 0xffff;
|
||||
dmaon[(addr >> 1) & 3] = 1;
|
||||
return;
|
||||
|
||||
@@ -94,7 +94,8 @@ void dma_write(uint16_t addr, uint8_t val, void *priv)
|
||||
dma.wp ^= 1;
|
||||
if (dma.wp) dma.cb[(addr >> 1) & 3] = (dma.cb[(addr >> 1) & 3] & 0xff00) | val;
|
||||
else dma.cb[(addr >> 1) & 3] = (dma.cb[(addr >> 1) & 3] & 0x00ff) | (val << 8);
|
||||
dma.cc[(addr >> 1) & 3] = dma.cb[(addr >> 1) & 3];
|
||||
dma.cc[(addr >> 1) & 3] = dma.cb[(addr >> 1) & 3] & 0xffff;
|
||||
// pclog("DMA count for channel %i now: %02X\n", (addr >> 1) & 3, dma.cc[(addr >> 1) & 3]);
|
||||
dmaon[(addr >> 1) & 3] = 1;
|
||||
return;
|
||||
|
||||
@@ -169,7 +170,7 @@ void dma16_write(uint16_t addr, uint8_t val, void *priv)
|
||||
dma16.wp ^= 1;
|
||||
if (dma16.wp) dma16.ab[(addr >> 1) & 3] = (dma16.ab[(addr >> 1) & 3] & 0xff00) | val;
|
||||
else dma16.ab[(addr >> 1) & 3] = (dma16.ab[(addr >> 1) & 3] & 0x00ff) | (val << 8);
|
||||
dma16.ac[(addr >> 1) & 3] = dma16.ab[(addr >> 1) & 3];
|
||||
dma16.ac[(addr >> 1) & 3] = dma16.ab[(addr >> 1) & 3] & 0xffff;
|
||||
dma16on[(addr >> 1) & 3] = 1;
|
||||
return;
|
||||
|
||||
@@ -177,7 +178,7 @@ void dma16_write(uint16_t addr, uint8_t val, void *priv)
|
||||
dma16.wp ^= 1;
|
||||
if (dma16.wp) dma16.cb[(addr >> 1) & 3] = (dma16.cb[(addr >> 1) & 3] & 0xff00) | val;
|
||||
else dma16.cb[(addr >> 1) & 3] = (dma16.cb[(addr >> 1) & 3] & 0x00ff) | (val << 8);
|
||||
dma16.cc[(addr >> 1) & 3] = dma16.cb[(addr >> 1) & 3];
|
||||
dma16.cc[(addr >> 1) & 3] = dma16.cb[(addr >> 1) & 3] & 0xffff;
|
||||
dma16on[(addr >> 1) & 3] = 1;
|
||||
return;
|
||||
|
||||
@@ -263,6 +264,24 @@ void dma16_init()
|
||||
io_sethandler(0x0088, 0x0008, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
void dma_alias_set()
|
||||
{
|
||||
io_sethandler(0x0090, 0x0010, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
void dma_alias_remove()
|
||||
{
|
||||
io_removehandler(0x0090, 0x0010, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
void dma_alias_remove_piix()
|
||||
{
|
||||
io_removehandler(0x0090, 0x0001, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL);
|
||||
io_removehandler(0x0094, 0x0003, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL);
|
||||
io_removehandler(0x0098, 0x0001, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL);
|
||||
io_removehandler(0x009C, 0x0003, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
uint8_t _dma_read(uint32_t addr)
|
||||
{
|
||||
@@ -286,184 +305,309 @@ void _dma_writew(uint32_t addr, uint16_t val)
|
||||
mem_invalidate_range(addr, addr + 1);
|
||||
}
|
||||
|
||||
int dma_is_masked(int channel)
|
||||
{
|
||||
if (channel < 4)
|
||||
{
|
||||
if (dma.m & (1 << channel))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (AT)
|
||||
{
|
||||
if (dma16.m & 1)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
channel &= 3;
|
||||
if (dma16.m & (1 << channel))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dma_channel_mode(int channel)
|
||||
{
|
||||
if (channel < 4)
|
||||
{
|
||||
return (dma.mode[channel] & 0xC) >> 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
channel &= 3;
|
||||
return (dma16.mode[channel] & 0xC) >> 2;
|
||||
}
|
||||
}
|
||||
|
||||
DMA * get_dma_controller(int channel)
|
||||
{
|
||||
if (channel < 4)
|
||||
{
|
||||
return &dma;
|
||||
}
|
||||
else
|
||||
{
|
||||
return &dma16;
|
||||
}
|
||||
}
|
||||
|
||||
int dma_channel_read(int channel)
|
||||
{
|
||||
uint16_t temp;
|
||||
int tc = 0;
|
||||
|
||||
if (dma.command & 0x04)
|
||||
|
||||
int cmode = 0;
|
||||
int real_channel = channel & 3;
|
||||
|
||||
int mem_over = 0;
|
||||
|
||||
DMA *dma_controller;
|
||||
|
||||
cmode = dma_channel_mode(channel);
|
||||
|
||||
channel &= 7;
|
||||
|
||||
if ((channel >= 4) && !AT)
|
||||
{
|
||||
// pclog ("DMA read - channel is 4 or higher on a non-AT machine\n");
|
||||
return DMA_NODATA;
|
||||
|
||||
}
|
||||
|
||||
dma_controller = get_dma_controller(channel);
|
||||
|
||||
if (dma_controller->command & 0x04)
|
||||
{
|
||||
// pclog ("DMA read - channel bit 2 of control bit is set\n");
|
||||
return DMA_NODATA;
|
||||
}
|
||||
|
||||
if (!AT)
|
||||
refreshread();
|
||||
|
||||
if (channel < 4)
|
||||
{
|
||||
if (dma.m & (1 << channel))
|
||||
return DMA_NODATA;
|
||||
if ((dma.mode[channel] & 0xC) != 8)
|
||||
return DMA_NODATA;
|
||||
|
||||
temp = _dma_read(dma.ac[channel] + (dma.page[channel] << 16)); //ram[(dma.ac[2]+(dma.page[2]<<16))&rammask];
|
||||
|
||||
if (dma.mode[channel] & 0x20) dma.ac[channel]--;
|
||||
else dma.ac[channel]++;
|
||||
dma.cc[channel]--;
|
||||
if (dma.cc[channel] < 0)
|
||||
{
|
||||
tc = 1;
|
||||
if (dma.mode[channel] & 0x10) /*Auto-init*/
|
||||
{
|
||||
dma.cc[channel] = dma.cb[channel];
|
||||
dma.ac[channel] = dma.ab[channel];
|
||||
}
|
||||
else
|
||||
dma.m |= (1 << channel);
|
||||
dma.stat |= (1 << channel);
|
||||
}
|
||||
|
||||
if (tc)
|
||||
return temp | DMA_OVER;
|
||||
return temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
channel &= 3;
|
||||
if ((dma16.m & (1 << channel)) || (dma16.m & 1))
|
||||
return DMA_NODATA;
|
||||
if ((dma16.mode[channel] & 0xC) != 8)
|
||||
return DMA_NODATA;
|
||||
|
||||
#if 0
|
||||
temp = _dma_read((dma16.ac[channel] << 1) + ((dma16.page[channel] & ~1) << 16)) |
|
||||
(_dma_read((dma16.ac[channel] << 1) + ((dma16.page[channel] & ~1) << 16) + 1) << 8);
|
||||
#endif
|
||||
|
||||
temp = _dma_readw((dma16.ac[channel] << 1) + ((dma16.page[channel] & ~1) << 16));
|
||||
|
||||
if (dma16.mode[channel] & 0x20) dma16.ac[channel]--;
|
||||
else dma16.ac[channel]++;
|
||||
dma16.cc[channel]--;
|
||||
if (dma16.cc[channel] < 0)
|
||||
{
|
||||
tc = 1;
|
||||
if (dma16.mode[channel] & 0x10) /*Auto-init*/
|
||||
{
|
||||
dma16.cc[channel] = dma16.cb[channel];
|
||||
dma16.ac[channel] = dma16.ab[channel];
|
||||
}
|
||||
else
|
||||
{
|
||||
dma16.m |= (1 << channel);
|
||||
if (!channel)
|
||||
{
|
||||
dma16.m |= 0xf;
|
||||
}
|
||||
}
|
||||
dma16.stat |= (1 << channel);
|
||||
}
|
||||
|
||||
if (tc)
|
||||
return temp | DMA_OVER;
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
|
||||
void dma_channel_dump()
|
||||
{
|
||||
int i = 0;
|
||||
FILE *f;
|
||||
f = fopen("dma.dmp", "wb");
|
||||
for (i = 0; i < (21 * 512); i++)
|
||||
if ((channel == 4) || dma_is_masked(channel))
|
||||
{
|
||||
fputc(mem_readb_phys((dma.page[2] << 16) + dma16.ac[2] + i), f);
|
||||
// pclog ("DMA read - channel is 4 or masked\n");
|
||||
return DMA_NODATA;
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
if (cmode)
|
||||
{
|
||||
if (cmode != 2)
|
||||
{
|
||||
// pclog ("DMA read - transfer mode (%i) is 1 or 3\n", cmode);
|
||||
return DMA_NODATA;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (channel < 4)
|
||||
{
|
||||
temp = _dma_read(dma_controller->ac[real_channel] + (dma_controller->page[real_channel] << 16));
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = _dma_readw((dma_controller->ac[real_channel] << 1) + ((dma_controller->page[real_channel] & ~1) << 16));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dma_controller->mode[real_channel] & 0x20)
|
||||
{
|
||||
if (dma_controller->ac[real_channel] == 0)
|
||||
{
|
||||
mem_over = 1;
|
||||
}
|
||||
dma_controller->ac[real_channel]--;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dma_controller->ac[real_channel] == 0xFFFF)
|
||||
{
|
||||
mem_over = 1;
|
||||
}
|
||||
dma_controller->ac[real_channel]++;
|
||||
}
|
||||
dma_controller->ac[real_channel] &= 0xffff;
|
||||
|
||||
dma_controller->cc[real_channel]--;
|
||||
if ((dma_controller->cc[real_channel] < 0) || mem_over)
|
||||
{
|
||||
tc = 1;
|
||||
if (dma_controller->mode[real_channel] & 0x10) /*Auto-init*/
|
||||
{
|
||||
// pclog("DMA read auto-init\n");
|
||||
dma_controller->cc[real_channel] = dma_controller->cb[real_channel] & 0xffff;
|
||||
dma_controller->ac[real_channel] = dma_controller->ab[real_channel] & 0xffff;
|
||||
}
|
||||
else
|
||||
{
|
||||
dma_controller->cc[real_channel] &= 0xffff;
|
||||
dma_controller->m |= (1 << real_channel);
|
||||
}
|
||||
dma_controller->stat |= (1 << real_channel);
|
||||
}
|
||||
|
||||
if (tc)
|
||||
{
|
||||
// pclog("DMA read over in transfer mode %i (value %04X)!\n", cmode, temp);
|
||||
return temp | DMA_OVER;
|
||||
}
|
||||
|
||||
// pclog("DMA read success (value %04X)\n", temp);
|
||||
return temp;
|
||||
}
|
||||
|
||||
int dma_channel_write(int channel, uint16_t val)
|
||||
{
|
||||
if (dma.command & 0x04)
|
||||
int tc = 0;
|
||||
|
||||
int cmode = 0;
|
||||
int real_channel = channel & 3;
|
||||
|
||||
int mem_over = 0;
|
||||
|
||||
DMA *dma_controller;
|
||||
|
||||
cmode = dma_channel_mode(channel);
|
||||
|
||||
channel &= 7;
|
||||
|
||||
if ((channel >= 4) && !AT)
|
||||
{
|
||||
// pclog ("DMA write - channel is 4 or higher on a non-AT machine\n");
|
||||
return DMA_NODATA;
|
||||
}
|
||||
|
||||
dma_controller = get_dma_controller(channel);
|
||||
|
||||
if (dma_controller->command & 0x04)
|
||||
{
|
||||
// pclog ("DMA write - channel bit 2 of control bit is set\n");
|
||||
return DMA_NODATA;
|
||||
}
|
||||
|
||||
if (!AT)
|
||||
refreshread();
|
||||
|
||||
if (channel < 4)
|
||||
{
|
||||
if (dma.m & (1 << channel))
|
||||
return DMA_NODATA;
|
||||
if ((dma.mode[channel] & 0xC) != 4)
|
||||
if ((channel == 4) || dma_is_masked(channel))
|
||||
{
|
||||
// pclog ("DMA write - channel is 4 or masked\n");
|
||||
return DMA_NODATA;
|
||||
}
|
||||
|
||||
if (cmode)
|
||||
{
|
||||
if (cmode != 1)
|
||||
{
|
||||
// pclog ("DMA write - transfer mode (%i) is 2 or 3\n", cmode);
|
||||
return DMA_NODATA;
|
||||
}
|
||||
|
||||
_dma_write(dma.ac[channel] + (dma.page[channel] << 16), val);
|
||||
if (channel < 4)
|
||||
{
|
||||
_dma_write(dma_controller->ac[real_channel] + (dma_controller->page[real_channel] << 16), val);
|
||||
}
|
||||
else
|
||||
{
|
||||
_dma_writew((dma_controller->ac[real_channel] << 1) + ((dma_controller->page[real_channel] & ~1) << 16), val);
|
||||
}
|
||||
}
|
||||
|
||||
if (dma.mode[channel]&0x20) dma.ac[channel]--;
|
||||
else dma.ac[channel]++;
|
||||
dma.cc[channel]--;
|
||||
if (dma.cc[channel] < 0)
|
||||
{
|
||||
if (dma.mode[channel] & 0x10) /*Auto-init*/
|
||||
{
|
||||
dma.cc[channel] = dma.cb[channel];
|
||||
dma.ac[channel] = dma.ab[channel];
|
||||
}
|
||||
else
|
||||
dma.m |= (1 << channel);
|
||||
dma.stat |= (1 << channel);
|
||||
}
|
||||
if (dma_controller->mode[real_channel] & 0x20)
|
||||
{
|
||||
if (dma_controller->ac[real_channel] == 0)
|
||||
{
|
||||
mem_over = 1;
|
||||
}
|
||||
dma_controller->ac[real_channel]--;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dma_controller->ac[real_channel] == 0xFFFF)
|
||||
{
|
||||
mem_over = 1;
|
||||
}
|
||||
dma_controller->ac[real_channel]++;
|
||||
}
|
||||
dma_controller->ac[real_channel] &= 0xffff;
|
||||
|
||||
if (dma.m & (1 << channel))
|
||||
return DMA_OVER;
|
||||
}
|
||||
else
|
||||
{
|
||||
channel &= 3;
|
||||
if ((dma16.m & (1 << channel)) || (dma16.m & 1))
|
||||
return DMA_NODATA;
|
||||
if ((dma16.mode[channel] & 0xC) != 4)
|
||||
return DMA_NODATA;
|
||||
dma_controller->cc[real_channel]--;
|
||||
if ((dma_controller->cc[real_channel] < 0) || mem_over)
|
||||
{
|
||||
tc = 1;
|
||||
if (dma_controller->mode[real_channel] & 0x10) /*Auto-init*/
|
||||
{
|
||||
// pclog("DMA write auto-init\n");
|
||||
dma_controller->cc[real_channel] = dma_controller->cb[real_channel] & 0xffff;
|
||||
dma_controller->ac[real_channel] = dma_controller->ab[real_channel] & 0xffff;
|
||||
}
|
||||
else
|
||||
{
|
||||
dma_controller->cc[real_channel] &= 0xffff;
|
||||
dma_controller->m |= (1 << real_channel);
|
||||
}
|
||||
dma_controller->stat |= (1 << real_channel);
|
||||
}
|
||||
|
||||
#if 0
|
||||
_dma_write((dma16.ac[channel] << 1) + ((dma16.page[channel] & ~1) << 16), val);
|
||||
_dma_write((dma16.ac[channel] << 1) + ((dma16.page[channel] & ~1) << 16) + 1, val >> 8);
|
||||
#endif
|
||||
// if (dma_is_masked(channel))
|
||||
if (tc)
|
||||
{
|
||||
// pclog("DMA write over in transfer mode %i (value %04X)\n", cmode, val);
|
||||
return DMA_OVER;
|
||||
}
|
||||
|
||||
_dma_writew((dma16.ac[channel] << 1) + ((dma16.page[channel] & ~1) << 16), val);
|
||||
|
||||
if (dma16.mode[channel]&0x20) dma16.ac[channel]--;
|
||||
else dma16.ac[channel]++;
|
||||
dma16.cc[channel]--;
|
||||
if (dma16.cc[channel] < 0)
|
||||
{
|
||||
if (dma16.mode[channel] & 0x10) /*Auto-init*/
|
||||
{
|
||||
dma16.cc[channel] = dma16.cb[channel] + 1;
|
||||
dma16.ac[channel] = dma16.ab[channel];
|
||||
}
|
||||
dma16.m |= (1 << channel);
|
||||
if (!channel)
|
||||
{
|
||||
dma16.m |= 0xf;
|
||||
}
|
||||
dma16.stat |= (1 << channel);
|
||||
}
|
||||
|
||||
if ((dma.m & (1 << channel)) || (dma.m & 1))
|
||||
return DMA_OVER;
|
||||
}
|
||||
return 0;
|
||||
// pclog("DMA write success (value %04X)\n", val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t PageLengthReadWrite(uint32_t Address, size_t TotalSize)
|
||||
static size_t PageLengthReadWrite(uint32_t PhysAddress, size_t TotalSize)
|
||||
{
|
||||
size_t l;
|
||||
size_t LengthSize;
|
||||
uint32_t Page;
|
||||
|
||||
Page = Address & 4095;
|
||||
l = (Page + 4096) - Address;
|
||||
if (l > TotalSize)
|
||||
l = TotalSize;
|
||||
Page = PhysAddress & 4095;
|
||||
LengthSize = (Page + 4096) - PhysAddress;
|
||||
if (LengthSize > TotalSize)
|
||||
LengthSize = TotalSize;
|
||||
|
||||
return l;
|
||||
return LengthSize;
|
||||
}
|
||||
|
||||
//DMA Bus Master Page Read/Write
|
||||
void DMAPageRead(uint32_t PhysAddress, void *DataRead, size_t TotalSize)
|
||||
{
|
||||
uint32_t PageLen = PageLengthReadWrite(PhysAddress, TotalSize);
|
||||
memcpy(DataRead, &ram[PhysAddress], PageLen);
|
||||
DataRead -= PageLen;
|
||||
PageLen -= TotalSize;
|
||||
}
|
||||
|
||||
void DMAPageWrite(uint32_t PhysAddress, const void *DataWrite, size_t TotalSize)
|
||||
{
|
||||
uint32_t PageLen = PageLengthReadWrite(PhysAddress, TotalSize);
|
||||
memcpy(&ram[PhysAddress], DataWrite, PageLen);
|
||||
DataWrite -= PageLen;
|
||||
PageLen -= TotalSize;
|
||||
}
|
||||
|
||||
int dma_mode(int channel)
|
||||
{
|
||||
if (channel < 4)
|
||||
{
|
||||
return dma.mode[channel];
|
||||
}
|
||||
else
|
||||
{
|
||||
return dma16.mode[channel & 3];
|
||||
}
|
||||
}
|
||||
|
||||
/* void dma_c2_mode()
|
||||
{
|
||||
printf("DMA Channel 2 mode: %02X\n", dma.mode[2]);
|
||||
} */
|
||||
|
||||
Reference in New Issue
Block a user