SIF: Correct junk data behaviour. Fixes True Crime Streets of LA

This commit is contained in:
refractionpcsx2 2023-05-11 02:29:57 +01:00
parent 2695ddc9fc
commit 72f9bf83fd
2 changed files with 59 additions and 20 deletions

View File

@ -50,12 +50,6 @@ struct sifFifo
if ((FIFO_SIF_W - size) < words)
DevCon.Warning("Not enough space in SIF0 FIFO!\n");
if (size < 4)
{
u32 amt = std::min(4 - size, words);
memcpy(&junk[size], from, amt << 2);
}
const int wP0 = std::min((FIFO_SIF_W - writePos), words);
const int wP1 = words - wP0;
@ -68,22 +62,66 @@ struct sifFifo
SIF_LOG(" SIF + %d = %d (pos=%d)", words, size, writePos);
}
// Junk data writing
//
// If there is not enough data produced from the IOP, it will always use the previous full quad word to
// fill in the missing data.
// One thing to note, when the IOP transfers the EE tag, it transfers a whole QW of data, which will include
// the EE Tag and the next IOP tag, since the EE reads 1QW of data for DMA tags.
//
// So the data used will be as follows:
// Less than 1QW = Junk data is made up of the EE tag + address (64 bits) and the following IOP tag (64 bits).
// More than 1QW = Junk data is made up of the last complete QW of data that was transferred in this packet.
//
// Data is always offset in to the junk by the amount the IOP actually transferred, so if it sent 2 words
// it will read words 3 and 4 out of the junk to fill the space.
//
// PS2 test results:
//
// Example of less than 1QW being sent with the only data being set being 0x69
//
// addr 0x1500a0 value 0x69 <-- actual data (junk behind this would be the EE tag)
// addr 0x1500a4 value 0x1500a0 <-- EE address
// addr 0x1500a8 value 0x8001a170 <-- following IOP tag
// addr 0x1500ac value 0x10 <-- following IOP tag word count
//
// Example of more than 1QW being sent with the data going from 0x20 to 0x25
//
// addr 0x150080 value 0x21 <-- start of previously completed QW
// addr 0x150084 value 0x22
// addr 0x150088 value 0x23
// addr 0x15008c value 0x24 <-- end of previously completed QW
// addr 0x150090 value 0x25 <-- end of recorded data
// addr 0x150094 value 0x22 <-- from position 2 of the previously completed quadword
// addr 0x150098 value 0x23 <-- from position 3 of the previously completed quadword
// addr 0x15009c value 0x24 <-- from position 4 of the previously completed quadword
void writeJunk(int words)
{
if (words > 0)
{
if ((FIFO_SIF_W - size) < words)
DevCon.Warning("Not enough Junk space in SIF0 FIFO!\n");
// Get the start position of the previously completed whole QW.
// Position is in word (32bit) units.
const int transferredWords = 4 - words;
const int prevQWPos = (writePos - (4 + transferredWords)) & (FIFO_SIF_W - 1);
// Read the old data in to our junk array in case of wrapping.
const int rP0 = std::min((FIFO_SIF_W - prevQWPos), 4);
const int rP1 = 4 - rP0;
memcpy(&junk[0], &data[prevQWPos], rP0 << 2);
memcpy(&junk[rP0], &data[0], rP1 << 2);
// Fill the missing words to fill the QW.
const int wP0 = std::min((FIFO_SIF_W - writePos), words);
const int wP1 = words - wP0;
memcpy(&data[writePos], &junk[4-words], wP0 << 2);
memcpy(&data[0], &junk[(4 - words)+wP0], wP1 << 2);
memcpy(&data[writePos], &junk[4- wP0], wP0 << 2);
memcpy(&data[0], &junk[wP0], wP1 << 2);
writePos = (writePos + words) & (FIFO_SIF_W - 1);
size += words;
SIF_LOG(" SIF + %d = %d Junk (pos=%d)", words, size, writePos);
}
SIF_LOG(" SIF + %d = %d (pos=%d)", words, size, writePos);
}
void read(u32 *to, int words)

View File

@ -95,7 +95,7 @@ static __fi bool ProcessEETag()
alignas(16) static u32 tag[4];
tDMA_TAG& ptag(*(tDMA_TAG*)tag);
sif0.fifo.read((u32*)&tag[0], 2); // Tag
sif0.fifo.read((u32*)&tag[0], 4); // Tag
SIF_LOG("SIF0 EE read tag: %x %x %x %x", tag[0], tag[1], tag[2], tag[3]);
sif0ch.unsafeTransfer(&ptag);
@ -133,14 +133,13 @@ static __fi bool ProcessIOPTag()
sif0.iop.data = *(sifData *)iopPhysMem(hw_dma9.tadr);
sif0.iop.data.words = sif0.iop.data.words;
// send the EE's side of the DMAtag. The tag is only 64 bits, with the upper 64 bits
// ignored by the EE.
// send the EE's side of the DMAtag. The tag is only 64 bits, with the upper 64 bits being the next IOP tag
// ignored by the EE, however required for alignment and used as junk data in small packets.
sif0.fifo.write((u32*)iopPhysMem(hw_dma9.tadr + 8), 4);
sif0.fifo.write((u32*)iopPhysMem(hw_dma9.tadr + 8), 2);
//sif0.fifo.writePos = (sif0.fifo.writePos + 2) & (FIFO_SIF_W - 1); // iggy on the upper 64.
//sif0.fifo.size += 2;
hw_dma9.tadr += 16; ///hw_dma9.madr + 16 + sif0.sifData.words << 2;
// I know we just sent 1QW, because of the size of the EE read, but only 64bits was valid
// so we advance by 64bits after the EE tag to get the next IOP tag.
hw_dma9.tadr += 16;
// We're only copying the first 24 bits. Bits 30 and 31 (checked below) are Stop/IRQ bits.
hw_dma9.madr = sif0data & 0xFFFFFF;
@ -148,7 +147,9 @@ static __fi bool ProcessIOPTag()
//Maximum transfer amount 1mb-16 also masking out top part which is a "Mode" cache stuff, we don't care :)
sif0.iop.counter = sif0words & 0xFFFFF;
// Save the number of words we need to write to make up 1QW from this packet. (See "Junk data writing" in Sif.h)
sif0.iop.writeJunk = (sif0.iop.counter & 0x3) ? (4 - sif0.iop.counter & 0x3) : 0;
// IOP tags have an IRQ bit and an End of Transfer bit:
if (sif0tag.IRQ || (sif0tag.ID & 4)) sif0.iop.end = true;
SIF_LOG("SIF0 IOP Tag: madr=%lx, tadr=%lx, counter=%lx (%08X_%08X) Junk %d", hw_dma9.madr, hw_dma9.tadr, sif0.iop.counter, sif0words, sif0data, sif0.iop.writeJunk);