
I carefully implemented the PPU sprite evaluation incorporating the ideas from these links: Obscure details of OAMADDR and Where to start DMA. But, that was not enough.
On even cycles (65--256), my code does this:
Code: Select all
int address = (n + oamAddress) << 2;
spriteY = primaryOAM[0xFF & (address + m)];
spriteT = primaryOAM[0xFF & (address + m + 1)];
spriteA = primaryOAM[0xFF & (address + m + 2)];
spriteX = primaryOAM[0xFF & (address + m + 3)];Code: Select all
if (secondaryOamWritesEnabled) {
int address = s << 2;
secondaryOAM[address] = spriteY;
if (!(spriteY > scanline
|| spriteY + spriteBottomOffset < scanline)) {
if (n == 0) {
sprite0Used = true;
}
secondaryOAM[address + 1] = spriteT;
secondaryOAM[address + 2] = spriteA;
secondaryOAM[address + 3] = spriteX;
if (++s == 8) {
secondaryOamWritesEnabled = false;
}
}
n = 0x3F & (n + 1);
if (n == 0) {
oamTransferCompleted = true;
}
} else {
if (!(spriteY > scanline
|| spriteY + spriteBottomOffset < scanline)) {
spriteOverflowDetected = true;
for(int k = 0; k < 4; k++) {
m = 0x03 & (m + 1);
if (m == 0) {
n = 0x3F & (n + 1);
if (n == 0) {
oamTransferCompleted = true;
break;
}
}
}
} else {
m = 0x03 & (m + 1);
n = 0x3F & (n + 1);
if (n == 0) {
oamTransferCompleted = true;
}
}
}
}oamAddress is set to 0 during each of ticks 257--320 (the sprite tile loading interval) of the pre-render and visible scanlines.
At cycle 257, the PPU status register ($2002) is updated with the value of spriteOverflowDetected. I found that if the code updates the status register during cycles 65--256, some games had issues. For instance, in Battletoads level 2, the player could not injure the yellow venus fly trap creatures and vice versa; the player and the enemy would pass through each other.