DEV9: Don't fake the FIFO

This commit is contained in:
TheLastRar 2024-10-15 17:19:31 +01:00 committed by Ty
parent 1f2d9ab4e5
commit 1bdd53a6c5
4 changed files with 240 additions and 94 deletions

View File

@ -167,8 +167,8 @@ public:
void Async(u32 cycles);
void ATAreadDMA8Mem(u8* pMem, int size);
void ATAwriteDMA8Mem(u8* pMem, int size);
int ReadDMAToFIFO(u8* buffer, int space);
int WriteDMAFromFIFO(u8* buffer, int available);
u16 ATAreadPIO();
//ATAwritePIO;

View File

@ -10,7 +10,7 @@ void ATA::DRQCmdDMADataToHost()
regStatus &= ~ATA_STAT_BUSY;
regStatus |= ATA_STAT_DRQ;
dmaReady = true;
_DEV9irq(SPD_INTR_ATA_FIFO_DATA, 1);
DEV9runFIFO();
//PCSX2 will Start DMA
}
void ATA::PostCmdDMADataToHost()
@ -22,11 +22,9 @@ void ATA::PostCmdDMADataToHost()
regStatus &= ~ATA_STAT_BUSY;
dmaReady = false;
dev9.irqcause &= ~SPD_INTR_ATA_FIFO_DATA;
pendingInterrupt = true;
if (regControlEnableIRQ)
_DEV9irq(ATA_INTR_INTRQ, 1);
//PCSX2 Will Start DMA
}
void ATA::DRQCmdDMADataFromHost()
@ -44,7 +42,7 @@ void ATA::DRQCmdDMADataFromHost()
regStatus &= ~ATA_STAT_BUSY;
regStatus |= ATA_STAT_DRQ;
dmaReady = true;
_DEV9irq(SPD_INTR_ATA_FIFO_DATA, 1);
DEV9runFIFO();
//PCSX2 will Start DMA
}
void ATA::PostCmdDMADataFromHost()
@ -62,8 +60,6 @@ void ATA::PostCmdDMADataFromHost()
regStatus &= ~ATA_STAT_DRQ;
dmaReady = false;
dev9.irqcause &= ~SPD_INTR_ATA_FIFO_DATA;
if (fetWriteCacheEnabled)
{
regStatus &= ~ATA_STAT_BUSY;
@ -77,18 +73,16 @@ void ATA::PostCmdDMADataFromHost()
Async(-1);
}
void ATA::ATAreadDMA8Mem(u8* pMem, int size)
int ATA::ReadDMAToFIFO(u8* buffer, int space)
{
if ((udmaMode >= 0 || mdmaMode >= 0) &&
(dev9.if_ctrl & SPD_IF_ATA_DMAEN) != 0)
if (udmaMode >= 0 || mdmaMode >= 0)
{
if (size == 0 || nsector == -1)
return;
DevCon.WriteLn("DEV9: DMA read, size %i, transferred %i, total size %i", size, rdTransferred, nsector * 512);
if (space == 0 || nsector == -1)
return 0;
//read
size = std::min(size, nsector * 512 - rdTransferred);
memcpy(pMem, &readBuffer[rdTransferred], size);
// Read to FIFO
const int size = std::min(space, nsector * 512 - rdTransferred);
memcpy(buffer, &readBuffer[rdTransferred], size);
rdTransferred += size;
@ -100,21 +94,22 @@ void ATA::ATAreadDMA8Mem(u8* pMem, int size)
rdTransferred = 0;
PostCmdDMADataToHost();
}
return size;
}
return 0;
}
void ATA::ATAwriteDMA8Mem(u8* pMem, int size)
int ATA::WriteDMAFromFIFO(u8* buffer, int available)
{
if ((udmaMode >= 0 || mdmaMode >= 0) &&
(dev9.if_ctrl & SPD_IF_ATA_DMAEN) != 0)
if (udmaMode >= 0 || mdmaMode >= 0)
{
if (nsector == -1)
return;
DevCon.WriteLn("DEV9: DMA write, size %i, transferred %i, total size %i", size, wrTransferred, nsector * 512);
if (available == 0 || nsector == -1)
return 0;
//write
size = std::min(size, nsector * 512 - wrTransferred);
memcpy(&currentWrite[wrTransferred], pMem, size);
// Write to FIFO
const int size = std::min(available, nsector * 512 - wrTransferred);
memcpy(&currentWrite[wrTransferred], buffer, size);
wrTransferred += size;
@ -126,7 +121,10 @@ void ATA::ATAwriteDMA8Mem(u8* pMem, int size)
wrTransferred = 0;
PostCmdDMADataFromHost();
}
return size;
}
return 0;
}
//GENRAL FEATURE SET

View File

@ -202,6 +202,7 @@ void DEV9close()
{
DevCon.WriteLn("DEV9: DEV9close");
dev9.dma_iop_ptr = nullptr;
dev9.ata->Close();
TermNet();
isRunning = false;
@ -228,49 +229,124 @@ void _DEV9irq(int cause, int cycles)
dev9Irq(cycles);
}
//Fakes SPEED FIFO
// SPEED <-> HDD FIFO
void HDDWriteFIFO()
{
if (dev9.ata->dmaReady && (dev9.if_ctrl & SPD_IF_ATA_DMAEN))
{
const int unread = (dev9.fifo_bytes_write - dev9.fifo_bytes_read);
const int spaceSectors = (SPD_DBUF_AVAIL_MAX * 512 - unread) / 512;
if (spaceSectors < 0)
{
Console.Error("DEV9: No Space on SPEED FIFO");
pxAssert(false);
abort();
}
pxAssert(dev9.ata->dmaReady && (dev9.if_ctrl & SPD_IF_ATA_DMAEN));
pxAssert((dev9.if_ctrl & SPD_IF_READ));
const int readSectors = dev9.ata->nsectorLeft < spaceSectors ? dev9.ata->nsectorLeft : spaceSectors;
dev9.fifo_bytes_write += readSectors * 512;
dev9.ata->nsectorLeft -= readSectors;
const int unread = (dev9.fifo_bytes_write - dev9.fifo_bytes_read);
const int space = (SPD_DBUF_AVAIL_MAX * 512 - unread);
const int base = dev9.fifo_bytes_write % (SPD_DBUF_AVAIL_MAX * 512);
pxAssert(unread <= SPD_DBUF_AVAIL_MAX * 512);
int read;
if (base + space > SPD_DBUF_AVAIL_MAX * 512)
{
const int was = SPD_DBUF_AVAIL_MAX * 512 - base;
read = dev9.ata->ReadDMAToFIFO(dev9.fifo + base, was);
if (read == was)
read += dev9.ata->ReadDMAToFIFO(dev9.fifo, space - was);
}
//FIFOIntr();
else
{
read = dev9.ata->ReadDMAToFIFO(dev9.fifo + base, space);
}
dev9.fifo_bytes_write += read;
}
void HDDReadFIFO()
{
if (dev9.ata->dmaReady && (dev9.if_ctrl & SPD_IF_ATA_DMAEN))
pxAssert(dev9.ata->dmaReady && (dev9.if_ctrl & SPD_IF_ATA_DMAEN));
pxAssert((dev9.if_ctrl & SPD_IF_READ) == 0);
const int unread = (dev9.fifo_bytes_write - dev9.fifo_bytes_read);
const int base = dev9.fifo_bytes_read % (SPD_DBUF_AVAIL_MAX * 512);
pxAssert(unread <= SPD_DBUF_AVAIL_MAX * 512);
int write;
if (base + unread > SPD_DBUF_AVAIL_MAX * 512)
{
const int writeSectors = (dev9.fifo_bytes_write - dev9.fifo_bytes_read) / 512;
dev9.fifo_bytes_read += writeSectors * 512;
dev9.ata->nsectorLeft -= writeSectors;
const int was = SPD_DBUF_AVAIL_MAX * 512 - base;
write = dev9.ata->WriteDMAFromFIFO(dev9.fifo + base, was);
if (write == was)
write += dev9.ata->WriteDMAFromFIFO(dev9.fifo, unread - was);
}
//FIFOIntr();
else
{
write = dev9.ata->WriteDMAFromFIFO(dev9.fifo + base, unread);
}
dev9.fifo_bytes_read += write;
}
void IOPReadFIFO(int bytes)
void IOPReadFIFO()
{
dev9.fifo_bytes_read += bytes;
pxAssert((dev9.dma_iop_ptr != nullptr) && (dev9.xfr_ctrl & SPD_XFR_DMAEN));
pxAssert((dev9.xfr_ctrl & SPD_XFR_WRITE) == 0);
const int unread = (dev9.fifo_bytes_write - dev9.fifo_bytes_read);
const int base = dev9.fifo_bytes_read % (SPD_DBUF_AVAIL_MAX * 512);
const int remain = dev9.dma_iop_size - dev9.dma_iop_transfered;
const int read = std::min(remain, unread);
pxAssert(unread <= SPD_DBUF_AVAIL_MAX * 512);
if (read == 0)
return;
if (base + read > SPD_DBUF_AVAIL_MAX * 512)
{
const int was = SPD_DBUF_AVAIL_MAX * 512 - base;
std::memcpy(dev9.dma_iop_ptr + dev9.dma_iop_transfered, dev9.fifo + base, was);
std::memcpy(dev9.dma_iop_ptr + dev9.dma_iop_transfered + was, dev9.fifo, read - was);
}
else
{
std::memcpy(dev9.dma_iop_ptr + dev9.dma_iop_transfered, dev9.fifo + base, read);
}
dev9.dma_iop_transfered += read;
dev9.fifo_bytes_read += read;
if (dev9.fifo_bytes_read > dev9.fifo_bytes_write)
Console.Error("DEV9: UNDERFLOW BY IOP");
//FIFOIntr();
}
void IOPWriteFIFO(int bytes)
void IOPWriteFIFO()
{
dev9.fifo_bytes_write += bytes;
if (dev9.fifo_bytes_write - SPD_DBUF_AVAIL_MAX * 512 > dev9.fifo_bytes_read)
pxAssert((dev9.dma_iop_ptr != nullptr) && (dev9.xfr_ctrl & SPD_XFR_DMAEN));
pxAssert(dev9.xfr_ctrl & SPD_XFR_WRITE);
const int unread = (dev9.fifo_bytes_write - dev9.fifo_bytes_read);
const int space = (SPD_DBUF_AVAIL_MAX * 512 - unread);
const int base = dev9.fifo_bytes_write % (SPD_DBUF_AVAIL_MAX * 512);
const int remain = dev9.dma_iop_size - dev9.dma_iop_transfered;
const int write = std::min(remain, space);
pxAssert(unread <= SPD_DBUF_AVAIL_MAX * 512);
if (write == 0)
return;
if (base + write > SPD_DBUF_AVAIL_MAX * 512)
{
const int was = SPD_DBUF_AVAIL_MAX * 512 - base;
std::memcpy(dev9.fifo + base, dev9.dma_iop_ptr + dev9.dma_iop_transfered, was);
std::memcpy(dev9.fifo + base, dev9.dma_iop_ptr + dev9.dma_iop_transfered + was, write - was);
}
else
{
std::memcpy(dev9.fifo + base, dev9.dma_iop_ptr + dev9.dma_iop_transfered, write);
}
dev9.dma_iop_transfered += write;
dev9.fifo_bytes_write += write;
if ((dev9.fifo_bytes_write - dev9.fifo_bytes_read) > SPD_DBUF_AVAIL_MAX * 512)
Console.Error("DEV9: OVERFLOW BY IOP");
//FIFOIntr();
}
void FIFOIntr()
{
@ -279,14 +355,83 @@ void FIFOIntr()
if (unread == 0)
{
dev9.irqcause &= ~SPD_INTR_ATA_FIFO_DATA;
if ((dev9.irqcause & SPD_INTR_ATA_FIFO_EMPTY) == 0)
_DEV9irq(SPD_INTR_ATA_FIFO_EMPTY, 1);
}
else
{
dev9.irqcause &= ~SPD_INTR_ATA_FIFO_EMPTY;
if ((dev9.irqcause & SPD_INTR_ATA_FIFO_DATA) == 0)
_DEV9irq(SPD_INTR_ATA_FIFO_DATA, 1);
}
if (unread == SPD_DBUF_AVAIL_MAX * 512)
{
//Log_Error("FIFO Full");
//INTR Full?
if ((dev9.irqcause & SPD_INTR_ATA_FIFO_FULL) == 0)
_DEV9irq(SPD_INTR_ATA_FIFO_FULL, 1);
}
else
{
dev9.irqcause &= ~SPD_INTR_ATA_FIFO_FULL;
}
// is DMA finished
if ((dev9.dma_iop_ptr != nullptr) &&
(dev9.dma_iop_transfered == dev9.dma_iop_size))
{
dev9.dma_iop_ptr = nullptr;
psxDMA8Interrupt();
}
}
// FIFO counters operate based on the direction set in SPD_R_XFR_CTRL
// Both might have to set to the same direction for (SPEED <-> HDD) to work
void DEV9runFIFO()
{
const bool iopWrite = dev9.xfr_ctrl & SPD_XFR_WRITE; // IOP writes to FIFO
const bool hddRead = dev9.if_ctrl & SPD_IF_READ; // HDD writes to FIFO
const bool iopXfer = (dev9.dma_iop_ptr != nullptr) && (dev9.xfr_ctrl & SPD_XFR_DMAEN);
const bool hddXfer = dev9.ata->dmaReady && (dev9.if_ctrl & SPD_IF_ATA_DMAEN);
// Order operations based on iopWrite to ensure DMA has data/space to work with.
if (iopWrite)
{
// Perform DMA from IOP.
if (iopXfer)
IOPWriteFIFO();
// Drain the FIFO
if (hddXfer && !hddRead)
{
HDDReadFIFO();
}
}
else
{
// Ensure FIFO has data.
if (hddXfer && hddRead)
{
HDDWriteFIFO();
}
if (iopXfer)
{
// Perform DMA to IOP.
IOPReadFIFO();
// Refill FIFO after DMA.
// Need to recheck dmaReady incase prior
// HDDWriteFIFO competed the transfer from HDD
if (hddXfer && hddRead && dev9.ata->dmaReady)
{
HDDWriteFIFO();
}
}
}
FIFOIntr();
}
u16 SpeedRead(u32 addr, int width)
@ -359,18 +504,8 @@ u16 SpeedRead(u32 addr, int width)
return dev9.xfr_ctrl;
case SPD_R_DBUF_STAT:
{
if (dev9.if_ctrl & SPD_IF_READ) // Semi async
{
HDDWriteFIFO(); // Yes this is not a typo
}
else
{
HDDReadFIFO();
}
FIFOIntr();
const u8 count = static_cast<u8>((dev9.fifo_bytes_write - dev9.fifo_bytes_read) / 512);
if (dev9.xfr_ctrl & SPD_XFR_WRITE) // or ifRead?
if (dev9.xfr_ctrl & SPD_XFR_WRITE)
{
hard = static_cast<u8>(SPD_DBUF_AVAIL_MAX - count);
hard |= (count == 0) ? SPD_DBUF_STAT_1 : static_cast<u16>(0);
@ -518,9 +653,14 @@ void SpeedWrite(u32 addr, u16 value, int width)
break;
case SPD_R_XFR_CTRL:
{
//DevCon.WriteLn("DEV9: SPD_R_XFR_CTRL %dbit write %x", width, value);
const u16 oldValue = dev9.xfr_ctrl;
dev9.xfr_ctrl = value;
if ((value & SPD_XFR_WRITE) != (oldValue & SPD_XFR_WRITE))
DEV9runFIFO();
//if (value & SPD_XFR_WRITE)
// DevCon.WriteLn("DEV9: SPD_R_XFR_CTRL Set Write");
//else
@ -532,8 +672,11 @@ void SpeedWrite(u32 addr, u16 value, int width)
//if ((value & (1 << 2)) != 0)
// DevCon.WriteLn("DEV9: SPD_R_XFR_CTRL Unknown Bit 2");
//if (value & SPD_XFR_DMAEN)
// DevCon.WriteLn("DEV9: SPD_R_XFR_CTRL For DMA Enabled");
if (value & SPD_XFR_DMAEN)
{
//DevCon.WriteLn("DEV9: SPD_R_XFR_CTRL For DMA Enabled");
DEV9runFIFO();
}
//else
// DevCon.WriteLn("DEV9: SPD_R_XFR_CTRL For DMA Disabled");
@ -541,6 +684,7 @@ void SpeedWrite(u32 addr, u16 value, int width)
Console.Error("DEV9: SPD_R_XFR_CTRL Unknown value written %x", value);
break;
}
case SPD_R_DBUF_STAT:
//DevCon.WriteLn("DEV9: SPD_R_DBUF_STAT %dbit write %x", width, value);
@ -560,13 +704,19 @@ void SpeedWrite(u32 addr, u16 value, int width)
break;
case SPD_R_IF_CTRL:
{
//DevCon.WriteLn("DEV9: SPD_R_IF_CTRL %dbit write %x", width, value);
const u16 oldValue = dev9.if_ctrl;
dev9.if_ctrl = value;
//if (value & SPD_IF_UDMA)
// DevCon.WriteLn("DEV9: IF_CTRL UDMA Enabled");
//else
// DevCon.WriteLn("DEV9: IF_CTRL UDMA Disabled");
if ((value & SPD_IF_READ) != (oldValue & SPD_IF_READ))
DEV9runFIFO();
//if (value & SPD_IF_READ)
// DevCon.WriteLn("DEV9: IF_CTRL DMA Is ATA Read");
//else
@ -575,15 +725,7 @@ void SpeedWrite(u32 addr, u16 value, int width)
if (value & SPD_IF_ATA_DMAEN)
{
//DevCon.WriteLn("DEV9: IF_CTRL ATA DMA Enabled");
if (value & SPD_IF_READ) //Semi async
{
HDDWriteFIFO(); //Yes this is not a typo
}
else
{
HDDReadFIFO();
}
FIFOIntr();
DEV9runFIFO();
}
//else
// DevCon.WriteLn("DEV9: IF_CTRL ATA DMA Disabled");
@ -617,6 +759,7 @@ void SpeedWrite(u32 addr, u16 value, int width)
Console.Error("DEV9: IF_CTRL Unknown Bit(s) %x", (value & 0xFF00));
break;
}
case SPD_R_PIO_MODE: //ATA only? or includes EEPROM?
//DevCon.WriteLn("DEV9: SPD_R_PIO_MODE 16bit %dbit write %x", width, value);
dev9.pio_mode = value;
@ -924,14 +1067,14 @@ void DEV9readDMA8Mem(u32* pMem, int size)
}
else
{
if (dev9.xfr_ctrl & SPD_XFR_DMAEN &&
!(dev9.xfr_ctrl & SPD_XFR_WRITE))
if (!(dev9.xfr_ctrl & SPD_XFR_WRITE))
{
HDDWriteFIFO();
IOPReadFIFO(size);
dev9.ata->ATAreadDMA8Mem((u8*)pMem, size);
FIFOIntr();
psxDMA8Interrupt();
pxAssert(size <= SPD_DBUF_AVAIL_MAX * 512);
dev9.dma_iop_ptr = reinterpret_cast<u8*>(pMem);
dev9.dma_iop_size = size;
dev9.dma_iop_transfered = 0;
DEV9runFIFO();
}
}
@ -954,18 +1097,16 @@ void DEV9writeDMA8Mem(u32* pMem, int size)
}
else
{
if (dev9.xfr_ctrl & SPD_XFR_DMAEN &&
dev9.xfr_ctrl & SPD_XFR_WRITE)
if (dev9.xfr_ctrl & SPD_XFR_WRITE)
{
IOPWriteFIFO(size);
HDDReadFIFO();
dev9.ata->ATAwriteDMA8Mem((u8*)pMem, size);
FIFOIntr();
psxDMA8Interrupt();
pxAssert(size <= SPD_DBUF_AVAIL_MAX * 512);
dev9.dma_iop_ptr = reinterpret_cast<u8*>(pMem);
dev9.dma_iop_size = size;
dev9.dma_iop_transfered = 0;
DEV9runFIFO();
}
}
//TODO, track if write was successful
}
void DEV9async(u32 cycles)

View File

@ -69,9 +69,15 @@ typedef struct
u16 mdma_mode;
u16 udma_mode;
//Non-Regs
// FIFO
int fifo_bytes_read;
int fifo_bytes_write;
u8 fifo[16 * 512];
// DMA
u8* dma_iop_ptr;
int dma_iop_transfered;
int dma_iop_size;
} dev9Struct;
//EEPROM states
@ -672,6 +678,7 @@ void FLASHwrite32(u32 addr, u32 value, int size);
void _DEV9irq(int cause, int cycles);
int DEV9irqHandler(void);
void DEV9async(u32 cycles);
void DEV9runFIFO();
void DEV9writeDMA8Mem(u32* pMem, int size);
void DEV9readDMA8Mem(u32* pMem, int size);
u8 DEV9read8(u32 addr);