mirror of
https://github.com/StrikerX3/StrikeBox.git
synced 2024-06-23 14:53:22 -04:00
Fix double INTRQ assertion on certain occasions involving DMA transfers and ATAPI commands
Still doesn't fix broken DMA transfer for the READ DVD STRUCTURE
This commit is contained in:
parent
bd501ac359
commit
84f6dd48bc
|
@ -158,6 +158,7 @@ void ATAChannel::ReadData(uint32_t *value, uint8_t size) {
|
|||
// Read data for the command and clear it if finished
|
||||
m_currentCommand->ReadData((uint8_t*)value, size);
|
||||
if (m_currentCommand->IsFinished()) {
|
||||
log_spew("ATAChannel::ReadData: Finished processing command for channel %d\n", m_channel);
|
||||
delete m_currentCommand;
|
||||
m_currentCommand = nullptr;
|
||||
}
|
||||
|
@ -181,6 +182,7 @@ void ATAChannel::WriteData(uint32_t value, uint8_t size) {
|
|||
// Write data for the command and clear it if finished
|
||||
m_currentCommand->WriteData((uint8_t*)&value, size);
|
||||
if (m_currentCommand->IsFinished()) {
|
||||
//log_spew("ATAChannel::WriteData: Finished processing command for channel %d\n", m_channel);
|
||||
delete m_currentCommand;
|
||||
m_currentCommand = nullptr;
|
||||
}
|
||||
|
@ -220,6 +222,7 @@ void ATAChannel::WriteCommand(uint8_t value) {
|
|||
{
|
||||
m_currentCommand->Execute();
|
||||
if (m_currentCommand->IsFinished()) {
|
||||
//log_spew("ATAChannel::WriteCommand: Finished processing command 0x%x for channel %d, device %d\n", cmd, m_channel, devIndex);
|
||||
delete m_currentCommand;
|
||||
m_currentCommand = nullptr;
|
||||
}
|
||||
|
@ -237,6 +240,7 @@ DMATransferResult ATAChannel::ReadDMA(uint8_t *dstBuffer, uint32_t readLen) {
|
|||
// Read data for the command and clear it if finished
|
||||
m_currentCommand->ReadData(dstBuffer, readLen);
|
||||
if (m_currentCommand->IsFinished()) {
|
||||
log_spew("ATAChannel::ReadDMA: Finished processing command for channel %d\n", m_channel);
|
||||
delete m_currentCommand;
|
||||
m_currentCommand = nullptr;
|
||||
return DMATransferEnd;
|
||||
|
@ -256,6 +260,7 @@ DMATransferResult ATAChannel::WriteDMA(uint8_t *srcBuffer, uint32_t writeLen) {
|
|||
// Write data for the command and clear it if finished
|
||||
m_currentCommand->WriteData(srcBuffer, writeLen);
|
||||
if (m_currentCommand->IsFinished()) {
|
||||
log_spew("ATAChannel::WriteDMA: Finished processing command for channel %d\n", m_channel);
|
||||
delete m_currentCommand;
|
||||
m_currentCommand = nullptr;
|
||||
return DMATransferEnd;
|
||||
|
@ -266,7 +271,11 @@ DMATransferResult ATAChannel::WriteDMA(uint8_t *srcBuffer, uint32_t writeLen) {
|
|||
|
||||
void ATAChannel::SetInterrupt(bool asserted) {
|
||||
if (asserted != m_interrupt && m_regs.AreInterruptsEnabled()) {
|
||||
log_spew("ATAChannel::SetInterrupt: %s interrupt for channel %d\n", (asserted ? "asserting" : "negating"), m_channel);
|
||||
m_interrupt = asserted;
|
||||
for (auto it = m_intrHooks.begin(); it != m_intrHooks.end(); it++) {
|
||||
(*it)->OnChange(asserted);
|
||||
}
|
||||
m_irqHandler.HandleIRQ(m_irqNum, m_interrupt);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
#include "vixen/cpu.h"
|
||||
#include "../basic/irq.h"
|
||||
#include "../basic/interrupt_trigger.h"
|
||||
#include "../basic/interrupt.h"
|
||||
#include "ata_device.h"
|
||||
#include "ata_common.h"
|
||||
|
||||
|
@ -81,6 +81,7 @@ public:
|
|||
|
||||
bool AreInterruptsEnabled() { return m_regs.AreInterruptsEnabled(); }
|
||||
InterruptTrigger& GetInterruptTrigger() { return m_intrTrigger; }
|
||||
void RegisterInterruptHook(InterruptHook *hook) { m_intrHooks.push_back(hook); }
|
||||
|
||||
private:
|
||||
friend class ATA;
|
||||
|
@ -121,6 +122,8 @@ private:
|
|||
IRQHandler& m_irqHandler;
|
||||
uint8_t m_irqNum;
|
||||
|
||||
std::vector<InterruptHook *> m_intrHooks;
|
||||
|
||||
// ----- Command port operations ------------------------------------------
|
||||
|
||||
void ReadData(uint32_t *value, uint8_t size);
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include <cstdint>
|
||||
|
||||
#include "../ata/ata_defs.h"
|
||||
#include "../basic/interrupt_trigger.h"
|
||||
#include "../basic/interrupt.h"
|
||||
#include "ata_common.h"
|
||||
#include "drvs/ata_device_driver.h"
|
||||
#include "drvs/drv_null.h"
|
||||
|
|
|
@ -138,7 +138,7 @@ void DMAProtocolCommand::ReadData(uint8_t *value, uint32_t size) {
|
|||
if (m_currentByte >= m_endingByte) {
|
||||
FinishTransfer();
|
||||
m_regs.status &= ~(StBusy | StDataRequest);
|
||||
// INTRQ will be asserted in BMIDEChannel::RunWorker()
|
||||
m_interrupt.Assert();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -189,7 +189,7 @@ void DMAProtocolCommand::WriteData(uint8_t *value, uint32_t size) {
|
|||
if (m_currentByte >= m_endingByte) {
|
||||
FinishTransfer();
|
||||
m_regs.status &= ~(StBusy | StDataRequest);
|
||||
// INTRQ will be asserted in BMIDEChannel::RunWorker()
|
||||
m_interrupt.Assert();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,8 @@ PacketProtocolCommand::PacketProtocolCommand(ATADevice& device)
|
|||
: IATACommand(device)
|
||||
, m_packetCmdBuffer(nullptr)
|
||||
, m_packetDataBuffer(nullptr)
|
||||
, m_packetDataPos(0)
|
||||
, m_packetDataSize(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -145,6 +145,8 @@ bool ImageDVDDriveATADeviceDriver::ProcessATAPIPacketDataRead(PacketInformation&
|
|||
if (!m_transfer) {
|
||||
m_currentByte = lba * kDVDSectorSize;
|
||||
m_lastByte = m_currentByte + transferLength * kDVDSectorSize;
|
||||
m_transfer = true;
|
||||
log_spew("ImageDVDDriveATADeviceDriver::ProcessATAPIPacketDataRead: Starting transfer: 0x%llx to 0x%llx\n", m_currentByte, m_lastByte);
|
||||
}
|
||||
|
||||
// TODO: maybe handle caching? Could improve performance if accessing real media on supported drives
|
||||
|
@ -160,6 +162,7 @@ bool ImageDVDDriveATADeviceDriver::ProcessATAPIPacketDataRead(PacketInformation&
|
|||
// Update position
|
||||
m_currentByte += *packetDataSize;
|
||||
if (m_currentByte >= m_lastByte || *packetDataSize < readLen) {
|
||||
log_spew("ImageDVDDriveATADeviceDriver::ProcessATAPIPacketDataRead: Transfer finished\n");
|
||||
m_transfer = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,5 +9,10 @@ public:
|
|||
virtual void Negate() = 0;
|
||||
};
|
||||
|
||||
class InterruptHook {
|
||||
public:
|
||||
virtual void OnChange(bool asserted) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
|
@ -10,6 +10,8 @@
|
|||
#include "vixen/thread.h"
|
||||
|
||||
namespace vixen {
|
||||
namespace hw {
|
||||
namespace bmide {
|
||||
|
||||
using namespace hw::bmide;
|
||||
using namespace hw::ata;
|
||||
|
@ -81,3 +83,5 @@ void BMIDEDevice::PCIIOWrite(int barIndex, uint32_t port, uint32_t value, uint8_
|
|||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#include "vixen/hw/ata/ata.h"
|
||||
|
||||
namespace vixen {
|
||||
namespace hw {
|
||||
namespace bmide {
|
||||
|
||||
class BMIDEDevice : public PCIDevice {
|
||||
public:
|
||||
|
@ -35,3 +37,5 @@ private:
|
|||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include "vixen/thread.h"
|
||||
|
||||
namespace vixen {
|
||||
namespace hw {
|
||||
namespace bmide {
|
||||
|
||||
using namespace hw;
|
||||
using namespace hw::bmide;
|
||||
|
@ -20,7 +22,9 @@ BMIDEChannel::BMIDEChannel(Channel channel, ATAChannel& ataChannel, uint8_t *ram
|
|||
, m_ataChannel(ataChannel)
|
||||
, m_ram(ram)
|
||||
, m_ramSize(ramSize)
|
||||
, m_intrHook(IntrHook(*this))
|
||||
{
|
||||
ataChannel.RegisterInterruptHook(&m_intrHook);
|
||||
m_worker_running = true;
|
||||
m_job_running = false;
|
||||
m_job_cancel = false;
|
||||
|
@ -243,11 +247,6 @@ void BMIDEChannel::RunWorker() {
|
|||
|
||||
// Set Interrupt flag if the ATA device triggered an interrupt
|
||||
if (result == DMATransferEnd) {
|
||||
if (m_ataChannel.AreInterruptsEnabled()) {
|
||||
m_status |= StInterrupt;
|
||||
m_ataChannel.GetInterruptTrigger().Assert();
|
||||
//log_spew("BM IDE channel %d: Interrupt asserted\n", m_channel);
|
||||
}
|
||||
//log_spew("BM IDE channel %d: Transfer ended\n", m_channel);
|
||||
m_job_running = false;
|
||||
}
|
||||
|
@ -269,3 +268,5 @@ void BMIDEChannel::RunWorker() {
|
|||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#include "vixen/hw/ata/ata.h"
|
||||
|
||||
namespace vixen {
|
||||
namespace hw {
|
||||
namespace bmide {
|
||||
|
||||
class BMIDEChannel {
|
||||
public:
|
||||
|
@ -61,6 +63,32 @@ private:
|
|||
|
||||
void StartWork();
|
||||
void StopWork();
|
||||
|
||||
// ----- Interrupt hook ---------------------------------------------------
|
||||
|
||||
class IntrHook : public hw::InterruptHook {
|
||||
private:
|
||||
IntrHook(BMIDEChannel& channel)
|
||||
: m_channel(channel)
|
||||
{
|
||||
}
|
||||
|
||||
void OnChange(bool asserted) override {
|
||||
if (asserted) {
|
||||
m_channel.m_status |= StInterrupt;
|
||||
log_spew("BM IDE channel %d: Interrupt asserted\n", m_channel.m_channel);
|
||||
}
|
||||
}
|
||||
|
||||
BMIDEChannel& m_channel;
|
||||
|
||||
friend class BMIDEChannel;
|
||||
};
|
||||
friend class IntrHook;
|
||||
|
||||
IntrHook m_intrHook;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -462,7 +462,7 @@ EmulatorStatus Xbox::InitHardware() {
|
|||
m_NVAPU = new NVAPUDevice();
|
||||
m_AC97 = new AC97Device();
|
||||
m_PCIBridge = new PCIBridgeDevice();
|
||||
m_BMIDE = new BMIDEDevice(m_ram, m_ramSize, *m_ATA);
|
||||
m_BMIDE = new hw::bmide::BMIDEDevice(m_ram, m_ramSize, *m_ATA);
|
||||
m_AGPBridge = new AGPBridgeDevice();
|
||||
m_NV2A = new NV2ADevice(m_ram, m_ramSize, *m_i8259);
|
||||
|
||||
|
|
|
@ -141,7 +141,7 @@ protected:
|
|||
NVAPUDevice *m_NVAPU;
|
||||
AC97Device *m_AC97;
|
||||
PCIBridgeDevice *m_PCIBridge;
|
||||
BMIDEDevice *m_BMIDE;
|
||||
hw::bmide::BMIDEDevice *m_BMIDE;
|
||||
AGPBridgeDevice *m_AGPBridge;
|
||||
NV2ADevice *m_NV2A;
|
||||
|
||||
|
|
Loading…
Reference in a new issue