Definitely getting somewhere with the SPU2.STATX - starting to see the IOP waiting for the spu to finish reciving data in a timing loop.

This commit is contained in:
Marco Satti 2017-06-22 22:22:25 +08:00
parent 6999a7772a
commit e937f2ec11
7 changed files with 40 additions and 33 deletions

View file

@ -72,12 +72,12 @@ void BitfieldRegister16_t::registerField(const int fieldIndex, const char* field
u16 BitfieldRegister16_t::getFieldValue(const Context_t context, const int fieldIndex)
{
return MathUtil::extractMaskedValue16(readHword(context), mFields[fieldIndex].mStartPosition, mFields[fieldIndex].mLength);
return MathUtil::extractMaskedValue16(UH, mFields[fieldIndex].mStartPosition, mFields[fieldIndex].mLength);
}
void BitfieldRegister16_t::setFieldValue(const Context_t context, const int fieldIndex, const u16 value)
{
writeHword(context, MathUtil::insertMaskedValue16(readHword(context), value, mFields[fieldIndex].mStartPosition, mFields[fieldIndex].mLength));
writeHword(context, MathUtil::insertMaskedValue16(UH, value, mFields[fieldIndex].mStartPosition, mFields[fieldIndex].mLength));
}
void BitfieldRegister16_t::logDebugAllFields() const

View file

@ -94,17 +94,16 @@ void BitfieldRegister32_t::registerField(const int fieldIndex, const char* field
u32 BitfieldRegister32_t::getFieldValue(const Context_t context, const int fieldIndex)
{
return MathUtil::extractMaskedValue32(readWord(context), mFields[fieldIndex].mStartPosition, mFields[fieldIndex].mLength);
return MathUtil::extractMaskedValue32(UW, mFields[fieldIndex].mStartPosition, mFields[fieldIndex].mLength);
}
void BitfieldRegister32_t::setFieldValue(const Context_t context, const int fieldIndex, const u32 value)
{
writeWord(context, MathUtil::insertMaskedValue32(readWord(context), value, mFields[fieldIndex].mStartPosition, mFields[fieldIndex].mLength));
writeWord(context, MathUtil::insertMaskedValue32(UW, value, mFields[fieldIndex].mStartPosition, mFields[fieldIndex].mLength));
}
void BitfieldRegister32_t::logDebugAllFields() const
{
// Using UW directly is OK here - we are not modifying anything, and it can only ever be called from within a VM "context" (ie: always called from get/setFieldValue()).
for (auto& field : mFields)
{
#if DEBUG_LOG_VALUE_AS_HEX

View file

@ -88,5 +88,5 @@ void SPU2CoreRegister_ATTR_t::writeHword(const Context_t context, const u16 valu
SPU2CoreRegister_STATX_t::SPU2CoreRegister_STATX_t(const char* mnemonic, const bool debugReads, const bool debugWrites) :
BitfieldRegister16_t(mnemonic, debugReads, debugWrites)
{
registerField(Fields::NeedData, "NeedData", 7, 1, 1);
registerField(Fields::NeedData, "NeedData", 7, 1, 0);
}

View file

@ -134,9 +134,8 @@ public:
/*
The SPU2 Core STATX register.
TODO: I don't fully understand this, the PCSX2 code is hard to read. Seems to be related to a "need data for processing" thing.
Set to 0x80 on "need data", set to 0 otherwise?
Might actually be a "ready" flag - IOPCore loops on reading this register if set to 0x80...
It is set to 0x80 when the SPU2 DMA requires data (to write), cleared otherwise.
TODO: Check this is true for SPU2 DMA reading, it is unhandled for now.
*/
class SPU2CoreRegister_STATX_t : public BitfieldRegister16_t
{

View file

@ -164,7 +164,7 @@ SPU2Core_C0_t::SPU2Core_C0_t(const std::shared_ptr<FIFOQueue_t> & fifoQueue) :
VMIXER0 = std::make_shared<SPU2CoreRegister_CHAN0_t>("SPU2 C0 VMIXER0", false, false);
VMIXER1 = std::make_shared<SPU2CoreRegister_CHAN1_t>("SPU2 C0 VMIXER1", false, false);
MMIX = std::make_shared<SPU2CoreRegister_MMIX_t>("SPU2 C0 MMIX", false, false);
ATTR = std::make_shared<SPU2CoreRegister_ATTR_t>("SPU2 C0 ATTR", false, true);
ATTR = std::make_shared<SPU2CoreRegister_ATTR_t>("SPU2 C0 ATTR", false, false);
IRQAH = std::make_shared<Register16_t>("SPU2 C0 IRQAH", false, true);
IRQAL = std::make_shared<PairRegister16_t>("SPU2 C0 IRQAL", false, true, IRQAH);
KON0 = std::make_shared<SPU2CoreRegister_CHAN0_t>("SPU2 C0 KON0", false, false);
@ -226,7 +226,7 @@ SPU2Core_C0_t::SPU2Core_C0_t(const std::shared_ptr<FIFOQueue_t> & fifoQueue) :
EEAL = std::make_shared<Register16_t>("SPU2 C0 EEAL", false, false);
ENDX0 = std::make_shared<Register16_t>("SPU2 C0 ENDX0", false, false);
ENDX1 = std::make_shared<Register16_t>("SPU2 C0 ENDX1", false, false);
STATX = std::make_shared<SPU2CoreRegister_STATX_t>("SPU2 C0 STATX", false, false);
STATX = std::make_shared<SPU2CoreRegister_STATX_t>("SPU2 C0 STATX", true, false);
MVOLL = std::make_shared<SPU2CoreRegister_VOL_t>("SPU2 C0 MVOLL", false, false);
MVOLR = std::make_shared<SPU2CoreRegister_VOL_t>("SPU2 C0 MVOLR", false, false);
EVOLL = std::make_shared<Register16_t>("SPU2 C0 EVOLL", false, false);
@ -313,7 +313,7 @@ SPU2Core_C1_t::SPU2Core_C1_t(const std::shared_ptr<FIFOQueue_t> & fifoQueue):
VMIXER0 = std::make_shared<SPU2CoreRegister_CHAN0_t>("SPU2 C1 VMIXER0", false, false);
VMIXER1 = std::make_shared<SPU2CoreRegister_CHAN1_t>("SPU2 C1 VMIXER1", false, false);
MMIX = std::make_shared<SPU2CoreRegister_MMIX_t>("SPU2 C1 MMIX", false, false);
ATTR = std::make_shared<SPU2CoreRegister_ATTR_t>("SPU2 C1 ATTR", false, true);
ATTR = std::make_shared<SPU2CoreRegister_ATTR_t>("SPU2 C1 ATTR", false, false);
IRQAH = std::make_shared<Register16_t>("SPU2 C1 IRQAH", false, true);
IRQAL = std::make_shared<PairRegister16_t>("SPU2 C1 IRQAL", false, true, IRQAH);
KON0 = std::make_shared<SPU2CoreRegister_CHAN0_t>("SPU2 C1 KON0", false, false);
@ -375,7 +375,7 @@ SPU2Core_C1_t::SPU2Core_C1_t(const std::shared_ptr<FIFOQueue_t> & fifoQueue):
EEAL = std::make_shared<Register16_t>("SPU2 C1 EEAL", false, false);
ENDX0 = std::make_shared<Register16_t>("SPU2 C1 ENDX0", false, false);
ENDX1 = std::make_shared<Register16_t>("SPU2 C1 ENDX1", false, false);
STATX = std::make_shared<SPU2CoreRegister_STATX_t>("SPU2 C1 STATX", false, false);
STATX = std::make_shared<SPU2CoreRegister_STATX_t>("SPU2 C1 STATX", true, false);
MVOLL = std::make_shared<SPU2CoreRegister_VOL_t>("SPU2 C1 MVOLL", false, false);
MVOLR = std::make_shared<SPU2CoreRegister_VOL_t>("SPU2 C1 MVOLR", false, false);
EVOLL = std::make_shared<Register16_t>("SPU2 C1 EVOLL", false, false);

View file

@ -47,7 +47,7 @@ int IOPCoreInterpreter_s::step(const Event_t & event)
mIOPCoreInstruction = IOPCoreInstruction_t(mByteMMU->readWord(getContext(), physicalAddress));
#if defined(BUILD_DEBUG)
static u64 DEBUG_LOOP_BREAKPOINT = 0x100000998269;
static u64 DEBUG_LOOP_BREAKPOINT = 0x100000437406;
static u32 DEBUG_PC_BREAKPOINT = 0x0;
static u32 DEBUG_INST_VAL_BREAKPOINT = 0x42000010; // COP0 RFE

View file

@ -29,7 +29,6 @@ SPU2_s::SPU2_s(VM * vm) :
void SPU2_s::initialise()
{
}
int SPU2_s::step(const Event_t & event)
@ -82,29 +81,57 @@ bool SPU2_s::handleDMATransfer()
throw std::runtime_error("SPU2 ATTR DMABits field set to non-zero. What is this for?");
int dmaCount = 0;
bool updateSTATX = false;
switch (mCore->ATTR->getFieldValue(getContext(), SPU2CoreRegister_ATTR_t::Fields::DMAMode))
{
case 0:
{
// Auto DMA write mode.
if (mCore->isADMAEnabled(getContext()))
{
dmaCount = transferData_ADMA_Write();
updateSTATX = true;
}
break;
}
case 1:
{
// Auto DMA read mode.
if (mCore->isADMAEnabled(getContext()))
{
dmaCount = transferData_ADMA_Read();
updateSTATX = true;
}
break;
}
case 2:
{
// Manual DMA write mode.
dmaCount = transferData_MDMA_Write();
updateSTATX = true;
break;
}
case 3:
{
// Manual DMA read mode.
dmaCount = transferData_MDMA_Read();
updateSTATX = true;
break;
}
default:
{
throw std::runtime_error("SPU2 could not determine DMA mode. Please fix.");
}
}
// Update STATX only if DMA attemped to run, and if there was FIFO data available.
if (updateSTATX)
{
if (mCore->FIFOQueue->getReadAvailable() > 0)
mCore->STATX->setFieldValue(getContext(), SPU2CoreRegister_STATX_t::Fields::NeedData, 0);
else
mCore->STATX->setFieldValue(getContext(), SPU2CoreRegister_STATX_t::Fields::NeedData, 1);
}
return (dmaCount > 0);
}
@ -114,19 +141,6 @@ bool SPU2_s::handleSoundGeneration()
// Check if core is enabled and do sound generation.
if (mCore->ATTR->getFieldValue(getContext(), SPU2CoreRegister_ATTR_t::Fields::CoreEnable))
{
// Check if we are running out of data - that the end of data is less than 0x200 hwords away. Set STATX on this condition and send an interrupt (or clear it otherwise).
// TODO: Check the logic and implement. Might need to set the IOP DMAC interrupt bit for the current core (a bit weird)? See SPU2-X/ReadInput.cpp (V_Core::ReadInput()).
static int hackCount = 0;
if ((++hackCount) % 2000 < 1000)
{
mCore->STATX->setFieldValue(getContext(), SPU2CoreRegister_STATX_t::Fields::NeedData, 1);
// mDMAC->ICR{0,1}->setFieldValue(getContext(), IOPDmacRegister_ICR{0,1}_t::Fields::TCI{...}, 1);
}
else
{
mCore->STATX->setFieldValue(getContext(), SPU2CoreRegister_STATX_t::Fields::NeedData, 0);
}
return false;
}
else
@ -196,12 +210,7 @@ int SPU2_s::transferData_MDMA_Write() const
// Check for incoming data and read it in, otherwise exit early as theres nothing to do.
u16 data;
if (!mCore->FIFOQueue->read(getContext(), reinterpret_cast<u8*>(&data), Constants::NUMBER_BYTES_IN_HWORD))
{
// TODO: check this especially!!!
// Need to also clear the STATX.NeedData bit when out of data.
mCore->STATX->setFieldValue(getContext(), SPU2CoreRegister_STATX_t::Fields::NeedData, 0);
return 0;
}
// Calculate write address. Make sure address is not outside 2MB limit (remember, we are addressing by hwords).
u32 address = (mCore->TSAL->readPairWord(getContext()) + mCore->ATTR->mDMAOffset) % 0x100000;