Hi,
I'm currently trying to wrap my brain around the PPU sprite evaluation behaviour reading the details here: http://wiki.nesdev.com/w/index.php/PPU_ ... evaluation
However, I don't understand how cycles 65-256 are performed. The evaluation is done on all 64 OAMs meaning it would take (256-64)/64 = 3 cycles per sprite evaluation. (If it should cover all cycles)
The wiki states that odd cycles are read operations from the OAM, and even are writes to secondary OAM. However, there are two loops happening within this time.
First is the evaluation to find out what gets copied to the secondary OAM, and then there's the other loop for the (broken) overflow flag update.
How is this done? Are the loops done in parallel or sequentially? Does anyone have a more detailed description on how this is done per cycle?
-Eicar
PPU sprite evaluation details
Moderator: Moderators
Re: PPU sprite evaluation details
Each access takes 2 cycles, and there are one access per sprite and three additional accesses per in-range sprite.Eicar wrote:I don't understand how cycles 65-256 are performed. The evaluation is done on all 64 OAMs meaning it would take (256-64)/64 = 3 cycles per sprite evaluation.
It's a state machine. For each cycle of the pixel loop, the loop to evaluate sprites for the next line runs one step. So it's done in parallel with the background and sprite rendering.The wiki states that odd cycles are read operations from the OAM, and even are writes to secondary OAM. However, there are two loops happening within this time.
First is the evaluation to find out what gets copied to the secondary OAM, and then there's the other loop for the (broken) overflow flag update.
How is this done? Are the loops done in parallel or sequentially?
What other programming languages do you know? If you know C or C++, the following may make sense:Does anyone have a more detailed description on how this is done per cycle?
Code: Select all
size_t soam_index, i;
for (soam_index = 0; soam_index < 32; ++soam_index) {
rest_1_cycle(); // 1 cycle
secondary_oam[soam_index] = 0xFF; // 1 cycle
}
for (i = 0, soam_index = 0; i < 256 && soam_index < 32; i += 4) {
unsigned char y = oam[i]; // 1 cycle
if (soam_index < 32) { // 1 cycle
secondary_oam[soam_index] = y;
if (y_in_range(y)) {
unsigned char tmp = oam[i + 1]; // 1 cycle
secondary_oam[++soam_index] = tmp; // 1 cycle
tmp = oam[i + 2]; // 1 cycle
secondary_oam[++soam_index] = tmp; // 1 cycle
tmp = oam[i + 3]; // 1 cycle
secondary_oam[++soam_index] = tmp; // 1 cycle
++soam_index;
}
}
}
// Broken overflow flag stuff omitted; this stuff can be
// addressed later when getting Codemasters games working
Re: PPU sprite evaluation details
It takes 2 cycles to process a sprite that's not in range, and 8 cycles to process a sprite that is in range (of which there can be up to 9 - 8 to display, and 1 to trigger overflow).
Thus, sprite evaluation for a single scanline can take anywhere from 128 to 182 cycles out of the 192 cycles available - the remaining time is spent rescanning the early sprites and ignoring them as if they were out of range.
Thus, sprite evaluation for a single scanline can take anywhere from 128 to 182 cycles out of the 192 cycles available - the remaining time is spent rescanning the early sprites and ignoring them as if they were out of range.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
P.S. If you don't get this note, let me know and I'll write you another.
Re: PPU sprite evaluation details
Thanks for the reply guys, that's certainly appreciated!
Still it's not all clear to me....
1. I guess 128 to 182 cycles is only accurate when the OAMADDR ($2003) is zero at the beginning of the pre-render scanline? Does this mean that the OAMADDR is latched at the very beginning
of the pre-render scanline, and that this latched value is used for all scanlines? (So that any accidental changes to OAMADDR during rendering will not affect the evaluation?)
2. http://wiki.nesdev.com/w/index.php/PPU_ ... evaluation claims under point 2.1 that n starts with zero. However, doesn't n start with the content of OAMADDR ?
3. If so, then all sprites on lower offset than OAMADDR will never be evaluated? (and never displayed?)
4. http://wiki.nesdev.com/w/index.php/PPU_ ... evaluation under point 2.2.2c: Should there be a "go to 3" at the end of this line?
-Eicar
Still it's not all clear to me....
1. I guess 128 to 182 cycles is only accurate when the OAMADDR ($2003) is zero at the beginning of the pre-render scanline? Does this mean that the OAMADDR is latched at the very beginning
of the pre-render scanline, and that this latched value is used for all scanlines? (So that any accidental changes to OAMADDR during rendering will not affect the evaluation?)
2. http://wiki.nesdev.com/w/index.php/PPU_ ... evaluation claims under point 2.1 that n starts with zero. However, doesn't n start with the content of OAMADDR ?
3. If so, then all sprites on lower offset than OAMADDR will never be evaluated? (and never displayed?)
4. http://wiki.nesdev.com/w/index.php/PPU_ ... evaluation under point 2.2.2c: Should there be a "go to 3" at the end of this line?
-Eicar
Re: PPU sprite evaluation details
OAMADDR is reset to zero at the beginning of rendering and at the end of evaluation of each scanline of sprites. The special note there about "if OAMADDR is not zero when evaluation starts" is basically only relevant if you turn on rendering at specific times in the middle of the scanline.