Feedback wanted on SVG PPU frame timing diagram

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

User avatar
ulfalizer
Posts: 349
Joined: Fri Mar 08, 2013 9:55 pm
Location: Linköping, Sweden

Feedback wanted on SVG PPU frame timing diagram

Post by ulfalizer » Fri Mar 08, 2013 10:44 pm

Hello,

I'm new to the forums but have been lurking in #nesdev for a few months. Making yet another emulator. ;)

The information on PPU frame events and timing on the wiki felt a bit scattered (and is contradictory in a few spots :/), so I put together an SVG diagram in Inkscape to get an overview and help my own understanding. I think it might be useful to other people too, so I'm putting it here. Tell me what you think. :)

Link to SVG file: https://www.dropbox.com/s/84k9ypwct3zwomu/ppu.svg

Edit: Rearranged things slightly for better clarity.
Attachments
ppu.png
Last edited by ulfalizer on Sat Mar 09, 2013 7:28 am, edited 2 times in total.

User avatar
ulfalizer
Posts: 349
Joined: Fri Mar 08, 2013 9:55 pm
Location: Linköping, Sweden

Re: Feedback wanted on SVG PPU frame timing diagram

Post by ulfalizer » Fri Mar 08, 2013 11:30 pm

Here's a few questions that came up while I was drawing it btw:

1. http://wiki.nesdev.com/w/index.php/Skinny says that the horizontal position in v is incremented at dot 256:
If rendering is enabled, the PPU increments the horizontal position in v many times across the scanline, it begins at dots 328 and 336, and will continue through the next scanline at 8, 16, 24... 240, 248, 256 (every 8 dots across the scanline until 256).
Is that a typo, or are both the vertical and the horizontal position updated at dot 256? Doesn't matter that much since the horizontal bits are reloaded at dot 257 anyway, but might as well get it right.

2. When is the secondary OAM cleared? Only at the beginning of the visible scanlines?

3. How are the two-cycle VRAM fetches split up? What addresses appear on the bus during each cycle? (I think it has to do with loading the VRAM address in two steps, but not sure.)

User avatar
Quietust
Posts: 1598
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: Feedback wanted on SVG PPU frame timing diagram

Post by Quietust » Sat Mar 09, 2013 10:22 am

Some of the information on that page predates analysis of Visual2C02, so there are actually some minor differences:

1. The visible scanlines are 0-239, VBLANK is scanlines 241-260, the prerender scanline is 261, and the postrender scanline is 240.
2. The fetches are actually offset by 1 cycle: 0 is idle, 1-2 is NT byte, 3-4 is AT byte, 5-6 is low BG tile, 7-8 is high BG tile (and the H increment happens during 8), etc. The last 2 fetches in the scanline happen at 321-328 (with H increment during 328) and 329-336 (with H inc at 336), and two garbage fetches at 337-338 and 339-340 (and an idle cycle at 0 where all it does is pulse the Address Latch Enable output).

Regarding your questions:
1. Yes, that is correct - cycle 256 increment both H and V, and cycle 257 reloads H.
2. Secondary OAM is cleared during cycles 1-64 of every scanline where "rendering" fetches are done (including the pre-render scanline), evaluation occurs during cycles 65-256, and then the fetches happen at 257-264 (with the first 4 cycles being reads from secondary OAM and the second 4 cycles being the tile reads from VRAM), 265-272, 273-280, 281-288, 289-296, 297-304, 305-312, and 313-320.
3. For VRAM reads during rendering, during the 1st cycle the PPU outputs the address it's going to read and raises the ALE (Address Latch Enable) line for the first half of the cycle, and during the 2nd cycle it pulls /RD low for the entire cycle and performs the read. Reading or writing $2007 is notably different - after your $2007 access finishes, it waits 1 full cycle, then it outputs the address and raises ALE for one full cycle, then lowers it for one full cycle, then spends a 3rd cycle performing the read or write (with /RD or /WR pulled low for the entire cycle).
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.

User avatar
ulfalizer
Posts: 349
Joined: Fri Mar 08, 2013 9:55 pm
Location: Linköping, Sweden

Re: Feedback wanted on SVG PPU frame timing diagram

Post by ulfalizer » Sat Mar 09, 2013 10:49 am

Before I update the diagram: Where does the skipped tick occur? On the first pixel of the first scanline?

User avatar
ulfalizer
Posts: 349
Joined: Fri Mar 08, 2013 9:55 pm
Location: Linköping, Sweden

Re: Feedback wanted on SVG PPU frame timing diagram

Post by ulfalizer » Sun Mar 10, 2013 12:28 am

Here's an updated version based on the new information. Tell me if you spot any errors.

The linked SVG file has been updated as well.
Attachments
ppu.png

User avatar
ulfalizer
Posts: 349
Joined: Fri Mar 08, 2013 9:55 pm
Location: Linköping, Sweden

Re: Feedback wanted on SVG PPU frame timing diagram

Post by ulfalizer » Sun Mar 10, 2013 12:45 am

Should be an idle cycle at the beginning of sprite evaluation (I lump secondary OAM clear in with it ATM). Fixed.
Attachments
ppu.png

User avatar
ulfalizer
Posts: 349
Joined: Fri Mar 08, 2013 9:55 pm
Location: Linköping, Sweden

Re: Feedback wanted on SVG PPU frame timing diagram

Post by ulfalizer » Sun Mar 10, 2013 1:04 am

I'll separate secondary OAM clear and sprite evaluation, but I have a question first:

Is sprite evaluation done at all on the prerender scanline, or just the OAM clear? If it's done, then what prevents it from finding sprites on the first visible scanline?

User avatar
ulfalizer
Posts: 349
Joined: Fri Mar 08, 2013 9:55 pm
Location: Linköping, Sweden

Re: Feedback wanted on SVG PPU frame timing diagram

Post by ulfalizer » Sun Mar 10, 2013 1:40 am

Beannaich noted that the two dummy nametable fetches are both proper nametable fetches (since they're the same fetch as at the beginning of the next scanline), so the last one shouldn't be labeled "AT". Fixed.
Attachments
ppu.png

WedNESday
Posts: 1236
Joined: Thu Sep 15, 2005 9:23 am
Location: Berlin, Germany
Contact:

Re: Feedback wanted on SVG PPU frame timing diagram

Post by WedNESday » Sun Mar 10, 2013 2:57 am

Should VBLANK be before or after the main 240 scanlines (I know that it doesn't really matter).

User avatar
ulfalizer
Posts: 349
Joined: Fri Mar 08, 2013 9:55 pm
Location: Linköping, Sweden

Re: Feedback wanted on SVG PPU frame timing diagram

Post by ulfalizer » Sun Mar 10, 2013 3:17 am

From Quietust's post it looks like the visible scanlines should be first, so the numbering is still off in that respect in my diagram. I'm guessing that's based on how the PPU counts scanlines internally.

As far as I've understood, the proper NTSC vblank is 22 scanlines long and includes the prerender and postrender scanlines by the way.

User avatar
ulfalizer
Posts: 349
Joined: Fri Mar 08, 2013 9:55 pm
Location: Linköping, Sweden

Re: Feedback wanted on SVG PPU frame timing diagram

Post by ulfalizer » Sun Mar 10, 2013 4:01 am

Did some tracing with beannich in visual2c02, and it looks like the vblank flag goes high on v/h:241/1 (note: h = 1, not 0), and low on v/h:261/1 (exactly 20 scanlines later).

Here's a trace around the beginning of v:241 (cycle, hpos, vpos, various stuff, and then vbl_flag at the end):
330088 000 0f1 0000 0802 1e 1 0 1 1 1 0802 0 02 0
330088 000 0f1 0000 0802 1e 1 0 1 1 1 0802 0 02 0
330089 000 0f1 0000 0802 1e 1 0 1 1 1 0802 0 02 0
330089 000 0f1 0000 0802 1e 1 0 1 1 1 0802 0 02 0
330090 000 0f1 0000 0802 1e 1 0 1 1 1 0802 0 02 0
330090 000 0f1 0000 0802 1e 1 0 1 1 1 0802 0 02 0
330091 000 0f1 0000 0802 1e 1 0 1 1 1 0802 0 02 0
330091 000 0f1 0000 0802 1e 1 0 1 1 1 0802 0 02 0
330092 001 0f1 0000 0802 1e 1 0 1 1 1 0802 0 02 1
330092 001 0f1 0000 0802 1e 1 0 1 1 1 0802 0 02 1
330093 001 0f1 0000 0802 1e 1 0 1 1 1 0802 0 02 1
330093 001 0f1 0000 0802 1e 1 0 1 1 1 0802 0 02 1
330094 001 0f1 0000 0802 1e 1 0 1 1 1 0802 0 02 1
330094 001 0f1 0000 0802 1e 1 0 1 1 1 0802 0 02 1
330095 001 0f1 0000 0802 1e 1 0 1 1 1 0802 0 02 1
330095 001 0f1 0000 0802 1e 1 0 1 1 1 0802 0 02 1
By the way (since this seems undocumented):
Additional node names (like vbl_flag in this case) can be found in http://www.qmtpro.com/~nes/chipimages/v ... denames.js. These can then be added to 'Trace these too:' (or searched for using 'Find:'). The simulation can be sped up a lot by disabling animations and logging. (Still takes 1h+ to simulate an entire frame though.)

User avatar
ulfalizer
Posts: 349
Joined: Fri Mar 08, 2013 9:55 pm
Location: Linköping, Sweden

Re: Feedback wanted on SVG PPU frame timing diagram

Post by ulfalizer » Sun Mar 10, 2013 7:47 am

Did more tracing in visual 2c02 and figured out some more stuff:

- The starting frame is an even frame, with the prerender scanline being 341 ticks long. (The simulation starts on the prerender scanline - the last line of the frame.)
- The next frame is an odd frame, with the skipped tick being at the end of the prerender scanline. Pixel: 339 jumps to Pixel: 0 instead of from 340 to 0 like on even frames.
- The sprite overflow flag is cleared on the same tick as the VBL flag, as expected.

I should've logged vbl_flag on the odd frame as well to see that it gets cleared one tick earlier as expected, but forgot. >:|

beannaich
Posts: 207
Joined: Wed Mar 31, 2010 12:40 pm

Re: Feedback wanted on SVG PPU frame timing diagram

Post by beannaich » Sun Mar 10, 2013 2:33 pm

ulfalizer wrote:Did more tracing in visual 2c02 and figured out some more stuff:

- The starting frame is an even frame, with the prerender scanline being 341 ticks long. (The simulation starts on the prerender scanline - the last line of the frame.)
- The next frame is an odd frame, with the skipped tick being at the end of the prerender scanline. Pixel: 339 jumps to Pixel: 0 instead of from 340 to 0 like on even frames.
- The sprite overflow flag is cleared on the same tick as the VBL flag, as expected.

I should've logged vbl_flag on the odd frame as well to see that it gets cleared one tick earlier as expected, but forgot. >:|
The cycle could still be skipped at the beginning depending on how visual 2C02 calculates the pixel value for the UI. If vbl_flag is cleared on dot 0 instead of dot 1, that'll prove that.

EDIT: Ran another frame of simulation, this time with vbl_flag logged, here are the results:

Code: Select all

Cycle  H   V   VBL

357368 000 105 1 
357368 000 105 1 
357369 000 105 1 
357369 000 105 1 
357370 000 105 1 
357370 000 105 1 
357371 000 105 1 
357371 000 105 1 
357372 001 105 0 <- VBL still cleared on dot 1..
357372 001 105 0 
357373 001 105 0 
357373 001 105 0 
357374 001 105 0 
357374 001 105 0 
357375 001 105 0 
357375 001 105 0 

Cycle  H   V   VBL

358724 153 105 0 
358724 153 105 0 
358725 153 105 0 
358725 153 105 0 
358726 153 105 0 
358726 153 105 0 
358727 153 105 0 
358727 153 105 0 
358728 000 000 0 <- Skipped clock
358728 000 000 0 
358729 000 000 0 
358729 000 000 0 
358730 000 000 0 
358730 000 000 0 
358731 000 000 0 
358731 000 000 0 

Cycle  H   V   VBL

  1356 153 105 0 
  1356 153 105 0 
  1357 153 105 0 
  1357 153 105 0 
  1358 153 105 0 
  1358 153 105 0 
  1359 153 105 0 
  1359 153 105 0 
  1360 154 105 0 <- Non-skipped clock
  1360 154 105 0 
  1361 154 105 0 
  1361 154 105 0 
  1362 154 105 0 
  1362 154 105 0 
  1363 154 105 0 
  1363 154 105 0 
  1364 000 000 0 
  1364 000 000 0 
  1365 000 000 0 
  1365 000 000 0 
  1366 000 000 0 
  1366 000 000 0 
  1367 000 000 0 
  1367 000 000 0 
It's pretty odd. Does this mean that a nametable fetch is dropped on shortened pre-render lines?

User avatar
ulfalizer
Posts: 349
Joined: Fri Mar 08, 2013 9:55 pm
Location: Linköping, Sweden

Re: Feedback wanted on SVG PPU frame timing diagram

Post by ulfalizer » Mon Mar 11, 2013 12:07 am

Here's a log around the end of the prerender line on even frames (no skipped tick):

Code: Select all

hpos    vpos    vramaddr_t  vramaddr_v  io_db   io_ab   io_rw   io_ce   rd  wr  ab   ale db  vbl_flag spr0_hit spr_overflow
153     105     0000        0002        1e      1       0       1       1   1   2002 1   02  0   0   0
153     105     0000        0002        1e      1       0       1       1   1   2002 1   02  0   0   0
153     105     0000        0002        1e      1       0       1       1   1   2002 1   02  0   0   0
153     105     0000        0002        1e      1       0       1       1   1   2002 1   02  0   0   0
153     105     0000        0002        1e      1       0       1       1   1   2002 0   02  0   0   0
153     105     0000        0002        1e      1       0       1       1   1   2002 0   02  0   0   0
153     105     0000        0002        1e      1       0       1       1   1   2002 0   02  0   0   0
153     105     0000        0002        1e      1       0       1       1   1   2002 0   02  0   0   0
154     105     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
154     105     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
154     105     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
154     105     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
154     105     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
154     105     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
154     105     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
154     105     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
000     000     0000        0002        1e      1       0       1       1   1   1000 1   00  0   0   0
000     000     0000        0002        1e      1       0       1       1   1   1000 1   00  0   0   0
000     000     0000        0002        1e      1       0       1       1   1   1000 1   00  0   0   0
000     000     0000        0002        1e      1       0       1       1   1   1000 1   00  0   0   0
000     000     0000        0002        1e      1       0       1       1   1   1000 0   00  0   0   0
000     000     0000        0002        1e      1       0       1       1   1   1000 0   00  0   0   0
000     000     0000        0002        1e      1       0       1       1   1   1000 0   00  0   0   0
000     000     0000        0002        1e      1       0       1       1   1   1000 0   00  0   0   0
001     000     0000        0002        1e      1       0       1       1   1   2002 1   02  0   0   0
001     000     0000        0002        1e      1       0       1       1   1   2002 1   02  0   0   0
001     000     0000        0002        1e      1       0       1       1   1   2002 1   02  0   0   0
001     000     0000        0002        1e      1       0       1       1   1   2002 1   02  0   0   0
001     000     0000        0002        1e      1       0       1       1   1   2002 0   02  0   0   0
001     000     0000        0002        1e      1       0       1       1   1   2002 0   02  0   0   0
001     000     0000        0002        1e      1       0       1       1   1   2002 0   02  0   0   0
001     000     0000        0002        1e      1       0       1       1   1   2002 0   02  0   0   0
002     000     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
002     000     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
002     000     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
002     000     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
002     000     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
002     000     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
002     000     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
002     000     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
Here's the same area for odd frames:

Code: Select all

hpos    vpos    vramaddr_t  vramaddr_v  io_db   io_ab   io_rw   io_ce   rd  wr  ab   ale db  vbl_flag spr0_hit spr_overflow
153     105     0000        0002        1e      1       0       1       1   1   2002 1   02  0   0   0
153     105     0000        0002        1e      1       0       1       1   1   2002 1   02  0   0   0
153     105     0000        0002        1e      1       0       1       1   1   2002 1   02  0   0   0
153     105     0000        0002        1e      1       0       1       1   1   2002 1   02  0   0   0
153     105     0000        0002        1e      1       0       1       1   1   2002 0   02  0   0   0
153     105     0000        0002        1e      1       0       1       1   1   2002 0   02  0   0   0
153     105     0000        0002        1e      1       0       1       1   1   2002 0   02  0   0   0
153     105     0000        0002        1e      1       0       1       1   1   2002 0   02  0   0   0
000     000     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
000     000     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
000     000     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
000     000     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
000     000     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
000     000     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
000     000     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
000     000     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
001     000     0000        0002        1e      1       0       1       1   1   2002 1   02  0   0   0
001     000     0000        0002        1e      1       0       1       1   1   2002 1   02  0   0   0
001     000     0000        0002        1e      1       0       1       1   1   2002 1   02  0   0   0
001     000     0000        0002        1e      1       0       1       1   1   2002 1   02  0   0   0
001     000     0000        0002        1e      1       0       1       1   1   2002 0   02  0   0   0
001     000     0000        0002        1e      1       0       1       1   1   2002 0   02  0   0   0
001     000     0000        0002        1e      1       0       1       1   1   2002 0   02  0   0   0
001     000     0000        0002        1e      1       0       1       1   1   2002 0   02  0   0   0
002     000     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
002     000     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
002     000     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
002     000     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
002     000     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
002     000     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
002     000     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
002     000     0000        0002        1e      1       0       1       0   1   2000 0   00  0   0   0
It looks you go from v/h=261/339 to v/h=0/0 on odd frames instead of from v/h=261/340 to v/h=0/0 like on even frames. It also looks like the last tick of the last dummy nametable fetch "moves down" to fill the idle tick at the beginning of the first visible scanline.

I guess a reasonably close way to represent that in the diagram would be to say that the idle tick at the beginning of the first visible scanline is optional. (I messed up pretty bad in the last version of the diagram. The skipped tick is off by an entire scanline. I hate +-1 errors :P.)

Attaching a diff.
Attachments
evenodd.png

beannaich
Posts: 207
Joined: Wed Mar 31, 2010 12:40 pm

Re: Feedback wanted on SVG PPU frame timing diagram

Post by beannaich » Mon Mar 11, 2013 1:12 am

Makes sense. Instead of the last cycle of pre-render, the first cycle of raster 0 can be skipped. I noticed some possible Visual2C02 bugginess, if you look at the AB for the tile fetches at the end of pre-render (happens on all lines, though):

Code: Select all

321: $2000 <- name 1/2
322: $2000 <- name 2/2

..

329: $2001 <- name 1/2
330: $2000 <- name 2/2

the same occurs for the two dummy fetches:

337: $2002
338: $2000 <-+ why does the address go back to $2000 during the second cycle of nametable fetch?
339: $2002   |
340: $2000 <-+

The same thing seems to happen with attributes:

323: $23C0 <- attr 1/2
324: $2300 <- attr 2/2
I'm chalking that up to bugginess for now.

Post Reply