Don't think I've screwed up anywhere, but would be nice to have some third-party verification. beannaich?
spr0_hit and vid_ are good nodes to watch.
Code: Select all
======== (1) ======== This starts, stops, and resets the simulation. The 'Scanline:' and 'Pixel:' status displays are based on internal PPU counters and should be self-explanatory. The starting state to use when resetting the simulation can be selected with the radio buttons near (5). ======== (2) ======== This is a list of register accesses to be carried out, going in sequence from top to bottom. The simulated 2C02 isn't attached to any other simulated devices, and the way to access registers is by adding them to this list. For example, 'W 1 1e' decodes as 'write $1E to $2001'. Reads can be significant for some registers, which is why they're included. (Note that you don't get any value "back" for reads though.) Register accesses can be removed by clicking on the '-' and added by clicking on the '+'. A '-' in the R/W colum means 'no-op' (use the numpad to input the '-'). The '*' is just to show the current access. You can click on it to jump to that point in the sequence. ======== (3) ======== Memory display. Can also be used to modify memory. - 3F00-3F1F is the palettes. Some of the cells are mirrors. - S000-S11F is OAM. For example, S000 would be the y position for sprite 0. * S000-S0FF is the primary OAM. * S100-S11F the secondary OAM (normally not directly accessible). - 0000-03FF is the pattern tables. This 1KB segment is mirrored eight times to fill out the entire CHR space. - 2000-23FF is nametables. The simulation uses a kind of "one-screen low" mirroring, and the data here is mirrored to fill out the entire nametable space. ======== (4) ======== This is a video output waveform display. It's based on the vid_ node. If you run the simulation without changing anything first, you will just see some level changes and squiggly stuff here near the end of each scanline, which is the NTSC hsync/colorburst, etc. ======== (5) ======== Pretty self-explanatory. Node numbers or node names (e.g. "spr0_hit") can be entered in the Find: box to locate them in the diagram. (This won't be used here.) ======== (6) ======== Tracing stuff. Additional nodes to trace can be added in the "Trace these too:" box as a space-separated list (e.g. "spr0_hit tile_l vid_"). The cycle column is based on the master clock, which the PPU divides by four. Each line in the trace is actually a half-cycle, so there's 4*2 = 8 lines per PPU tick. ======== Finding nodes to trace ======= A list of nodes can be found in http://www.qmtpro.com/~nes/chipimages/visual2c02/nodenames.js . For nodes that have many bits, e.g. finex0, finex1, finex2, you can trace all of them at once by using 'finex' as the node name. ======== Performance hint ======== Turning off tracing and unticking "Animate during simulation" and "Show sprite RAM contents" can massively speed up the simulation. ======== Tutorial: Outputting some pixels ======= 1. Put 81 at pattern table address 0000. This will make the palette index for each pixel of the first row of the first tile, in order, '10000001'. (Putting 81 at 0008 as well would make it '30000003', etc.) (Since the nametables are initialized to 0 by default, this is the tile that will be used for all the background tiles by default.) 2. Change the value of 3F01, which is the BG palette entry that will be used. 20 seems to work fine. 3. Run the simulation (and note the Performance section). The first line is the pre-render line, so nothing will be seen here. At scanline 1, you should see some pixels being output in the waveform display corresponding to the 81 pattern. ======== Some things to look out for ======== - Note that the default register writes might move around sprite 0 and do other stuff, so you might have to remove some of them or manually modify memory later to get the state you want. - There's a bunch of sprites sitting at (0,0). If sprites are enabled and all use a black tile, this means you will see black for the first 8 pixels of scanlines 1-8 (sprites don't start drawing until scanline 1 at the earliest since the y OAM coordinate is one less than the actual position).
Edit 2: s/2000-23F0/2000-23FF/
Edit 3: Clarify register access column
Edit 4: Clarify cycles in the trace window
I'll be confirming a lot of this information as I begin implementing this into my emulator.ulfalizer wrote:Don't think I've screwed up anywhere, but would be nice to have some third-party verification. beannaich?
Edit: Delete a "not".
I could never get low level rendering to work until I had a firm grasp on high level operation. That should be the natural progression of any emulator, start at high level, slowly convert things to low level. Anyone using the PPU diagram when writing a new emulator, especially with no previous experience, all I have to say is "Good luck".ulfalizer wrote:After some discussion in #nesdev I felt a little bad about maybe making basic emulator implementation seem way trickier than it really is, so I added a note to the diagram.
The pattern of behavior for the PPU is basically the following:
dots: 0-64 = clear S-OAM
dots: 65-256 = fill S-OAM with data for next scanline.
at the same time:
dots 0-256 = render background and sprite pixels for the current scanline.
But, as far as I understand that means that there is a possible conflict if this is done naively. If sprite 0's x position is say 32 pixels into the scanline, that means that its data will be overwritten with $FFs well before it is rendered, making it end up as garbage!
My hypothesis is that the 4 pixel delay for rendering is enough to allow an algorithm (which I have not thought of the specifics yet) to avoid this conflict.
- The normal display list, 64 entries, written with $2003/$2004/$4014
- Next line OAM, 8 entries, for sprites on the next scanline
- Counters and shifters
Code: Select all
You are right.tepples wrote:An array of 90,000 function pointers would kill your cache.
I need another way to organize my ppu code, it is a big list of if statements.