This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

CPU - PPU clock alignment

CPU - PPU clock alignment
by on (#58517)
I want someone to confirm my troughs...

NTSC : 1 CPU Cycle = 3 PPU Cycles, so there is 1 * 3 = 3 possible alignments on reset

PAL : 5 CPU Cycles = 16 PPU Cycles, so there is 5 * 16 = 80 possible alignments on reset

Is this right ? I just got surprised that a program I wrote using raster effects behaves differently depending on resets and I want to understand why.

by on (#58523)
Nope, there are four for NTSC. Here are some notes I made a while back:

After power/reset, PPU is randomly in one of four synchronizations with CPU. This synchronization cannot be changed without resetting/powering down. Trials of 50-60 power/resets were done to determine likelihoods. The third synchronization is the preferred one for emulators and test ROMs, due to the least special cases, and highest likelihood.
Code:
NMI     VBL         Hit             Overflow    Likelihood
        Reset   Reset   Set     Reset   Set
                6819+   7502+   6819+   7290+   Power   Reset
-------------------------------------------------------------
-1      -1      -1      0       -1      -1      27%     26%
0       -1      0       0       0       0       15%     22%
0       0       0       0       0       0       31%     30%
0       0       0       +1      0       0       27%     22%

Why four instead of three? It's due to the PPU and CPU using separate dividers. The CPU divides the master clock by 12, the PPU by 4. Thus, the CPU has four possible positions it can be in relative to the PPU:
Code:
PPU   X---X---X---X---X---X---X---X---X---X---X-...
CPU 1 X-----------X-----------X-----------X-----...
CPU 2 -X-----------X-----------X-----------X----...
CPU 3 --X-----------X-----------X-----------X---...
CPU 4 ---X-----------X-----------X-----------X--...

I expect the same for the PAL system. The CPU divides the master clock by 16, the PPU by 5.
Code:
PPU X----X----X----X----X----X----X----X----X----X----X----X----X----X----X----X----X--...
CPU X---------------X---------------X---------------X---------------X---------------X--...

Look at that, there is only ONE overall synchronization for PAL. The CPU hits all five sub-synchronizations from one clock to the next, though. That makes it both easier and harder for emulation of all the PAL special cases. It's easier in that there's only one to research, and no choice of which to emulate, but harder in that all 5 sub-synchronizations must be checked for different effects.

by on (#58536)
Mmh... Thank you very much for your diagrams, they clarify things a lot.

So I really don't understand why my program using a raster effect has a line who seems to sometimes flicker, and sometimes be solid depending on resets on my PAL NES. I didn't mean it to be a test demo or anything - I just want to understand what is happening.

I synchronize from VBlank NMI for the effect, so I don't see how this can be an issue (but maybe it can ?).

by on (#58546)
Interesting. Can you remove unncessary bits from your code until you're left with a very small amount which still displays different stable behavior depending on some power-up state? Or wait, we didn't examine the possible CPU synchronizations with respect to VBL. Basically consider all the possible number of PPU clocks between two VBL settings, and see if any are multiples of 5. Let's say the PPU frame length was 160000 (just some made-up value). That's a multiple of 16, so VBL would fall on the same relative CPU position every frame. It could be something like this going on.
wow
by on (#58563)
blargg wrote:
After power/reset, PPU is randomly in one of four synchronizations with CPU. This synchronization cannot be changed without resetting/powering down. Trials of 50-60 power/resets were done to determine likelihoods. The third synchronization is the preferred one for emulators and test ROMs, due to the least special cases, and highest likelihood.

Holy cow Blargg, you are frigin hard core with this RE'ing stuff. Haha, that is awesome. I'll tuck this post away for a much later date when I get to the point of fine tuning my emulator and so I can add an option to randomize these power up states to make it as close to the original as possible. THANKS! :)

by on (#58576)
Bregalad, have you tested to be sure there really is some state that can only be changed by resetting/powering down and then up? That is, you power up, run your program many times, get one particular visual effect, then reset, run your program, and consistently get a different effect, then reset, and get another effect consistently (or maybe the first again)?

by on (#58578)
There's the effect of the PPU ignoring writes to half its registers for the first frame after reset.

by on (#58579)
Synchronized to vblank from NMI? Maybe do some timed OAMDATA reads, then execute some instructions to get the timing into a narrower range.

by on (#58644)
blargg wrote:
Bregalad, have you tested to be sure there really is some state that can only be changed by resetting/powering down and then up? That is, you power up, run your program many times, get one particular visual effect, then reset, run your program, and consistently get a different effect, then reset, and get another effect consistently (or maybe the first again)?

Yes I am sure, it's like you said.
I did originally not meant to release it as a standalone, but anyway it is for the good of NESdev, so I uploaded it [url="http://jonathan.microclub.ch/dummy/logo%20%28E%29.nes"]here[/url].
The last line of the logo sometimes flicker, and is sometimes solid depending on resets. (note : I think the flickering is due to the second $2006 writes being sometimes slightly past cc 256, and as a result the adress loaded is incorrect). It seems it never flickers on power on, and other lines show fine.

PS : Note that the point of this thread is NOT to solve the flickering issue (which I know how to deal with) but to understand why timing depends on resets.

by on (#58653)
It could still be that the initial timing it's started at is what determines this flicker, rather than something in hardware. The source code would help.

by on (#58669)
Okay, I uploaded it.

by on (#62253)
Been doing some PAL testing today (some info already known, just verifying). 312 scanlines per frame, 341 PPU clocks per scanline. 3.2 CPU clocks per PPU clock/0.3125 PPU clocks per CPU clock. Every frame is 312*341 PPU clocks, regardless of rendering being enabled; there's no skipped clock on odd rendered frames as on NTSC. This means that every frame is 33247.5 CPU clocks. It also means that there are eight PPU-CPU synchronizations that it can power up/reset into! There are so many partly because of the lack of a short frame as on NTSC. There are 16 different positions a PPU clock can fall within a CPU clock, and since the frame length ends in half a CPU clock, this is halved to 8, as it toggles between two synchronizations every frame.

by on (#62272)
Quote:
It also means that there are eight PPU-CPU synchronizations that it can power up/reset into!

You lost me there. You told me before there was only one. Altough I definitely confirm a demo of mine, along with another old OAM reading demo, acted differently between resets, so you last theory seems much more realist to me.

I still don't understand why there is 8 alignements.

by on (#62273)
Yeah, I'm still trying to get my head around this.

OK, there is one CPU clock every 16 master clocks. Therefore, VBL can begin at 16 different positions within a CPU clock. VBL occurs every 312*341 PPU clocks. There are 5 master clocks in a PPU clock, so VBL occurs every 312*341*5=531960 master clocks. This is a multiple of 8, but not 16, so VBL's position within a CPU clock will alternate between two points, each a half CPU clock apart. For a given power/reset, it will never fall on anything other than these two points in a CPU cycle. Since there are 16 points available, 16/2=8 possible states it could power/reset into.

The above was from the CPU's point of view, which would be relevant for things like NMI. From the PPU's point of view, CPU reads/writes can occur in one of 5 positions within a PPU clock, which the CPU constantly cycles through every 5 CPU clocks. Every successive CPU clock begins one master clock (1/5 PPU clock) later within a PPU clock. This would suggest that the state at power/reset is irrelevant from the PPU's view, but PPU clocks aren't the only regular event in the PPU: there's also VBL. As above, after a power/reset, a CPU clock can begin in only two possible positions relative to VBL, each 8 master clocks apart.

I've been working on tests which are able to show how many different power/reset states it can be in, by being able to have it print which one it's on, and never print anything different except after another power/reset.

by on (#62287)
I just confirmed that there are 8 distinct PPU-CPU synchronizations a PAL NES can power up/reset into, as predicted. Whatever one it uses (at random) doesn't change until you reset/power again. Lovely.

by on (#62349)
I finally had time to go over your program. You're doing PPU writes during rendering. If you're doing a write within a small window, a small timing change could cause it to fall outside it and cause a graphical glitch. Your code doesn't seem to synchronize with the PPU very precisely, so it'd be easy for this to happen.

Your code runs off NMI, with a simple HERE: JMP HERE loop running between NMIs. So you already have a variation of 3*16-1=47 master clocks when your NMI is called. You do sprite DMA during the NMI, which can take one extra CPU clock, so that adds another 16 master clocks of variance, totaling 63 master clocks. Divide by 5 and you get 12.6 PPU clocks.

But, depending on the timing of the NMI routine and power/reset synchronization, it might not vary over this full 12.6 PPU clock range; after some powers/resets it may vary by less, and thus not flicker, while others it may vary by the full 12.6 PPU clocks. Analyzing this could be very complex, because the timing of every execution of NMI is relevant; the number of clocks until it RTIs determines when the JMP HERE loop resumes, and thus affects when the next NMI occurs relative to VBL.

I wrote a simple test program that puts up a vertical line in a nametable, then does some $2006 writes mid-frame which have a major glitch only after some powers/resets.

pal_flicker_sometimes.zip

Normally it causes a slight flickering glitch to the right on one scanline (left image), but after some powers/resets, the whole vertical bar below flickers to the right every few frames (right image).

Image

After setting up the nametable and enabling NMI and rendering, the code is very simple:
Code:
wait:   jmp wait


nmi:    ; Do sprite DMA and reset PPUADDR to 0
        bit PPUSTATUS
        lda #0
        sta SPRADDR
        sta SPRDMA
        sta PPUADDR
        sta PPUADDR
       
        delay 15012
       
        ; Set PPUADDR to $2121 mid-frame
        lda #$21
        sta PPUADDR
        sta PPUADDR
       
        rti

So, the conclusion is that yes, PAL has multiple PPU-CPU synchronizations, and that it's very easy to have code that works fine after some powers/resets, but not others.