Page 1 of 1

PPU sprite evaluation details

Posted: Fri Apr 28, 2017 7:19 am
by Eicar
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

Re: PPU sprite evaluation details

Posted: Fri Apr 28, 2017 7:38 am
by tepples
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.
Each access takes 2 cycles, and there are one access per sprite and three additional accesses per in-range sprite.
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?
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.
Does anyone have a more detailed description on how this is done per cycle?
What other programming languages do you know? If you know C or C++, the following may make sense:

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

Posted: Sat Apr 29, 2017 7:44 am
by Quietust
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.

Re: PPU sprite evaluation details

Posted: Mon May 01, 2017 11:52 am
by Eicar
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

Re: PPU sprite evaluation details

Posted: Mon May 01, 2017 11:57 am
by lidnariq
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.