As shown below, my emulator makes it to the Stage 1 - 1 screen, the player can control the sprayer (left, right and fire works) and the music and sound effects work. But, the Stage 1 - 1 message never vanishes and no enemies ever appear.
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:
On odd cycles, it does this:
Those pieces of code execute while oamTransferCompleted is false. n, m and s are initialized to 0. secondaryOamWritesEnabled is initialized to true. spriteBottomOffset is either 8 or 16 depending on sprite size mode.
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.
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:
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)];
spriteY = primaryOAM[0xFF & (address + m)];
spriteT = primaryOAM[0xFF & (address + m + 1)];
spriteA = primaryOAM[0xFF & (address + m + 2)];
spriteX = primaryOAM[0xFF & (address + m + 3)];
On odd cycles, it does this:
Code:
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;
}
}
}
}
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;
}
}
}
}
Those pieces of code execute while oamTransferCompleted is false. n, m and s are initialized to 0. secondaryOamWritesEnabled is initialized to true. spriteBottomOffset is either 8 or 16 depending on sprite size mode.
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.