Method for timing PPU with CPU

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

User avatar
rainwarrior
Posts: 8735
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Method for timing PPU with CPU

Post by rainwarrior »

I think "PPU runs prior to CPU" is a rather ambiguous statement.

What I think this is getting at is that you get a subtly different timing result if CPU writes begin to affect the PPU on the following clock, or on the same clock.

The truth of it is that CPU instructions take multiple clocks, and different things happen on each clock of the instruction. I believe writes usually happen on the last clock of an instruction (don't take my word for this, look it up), but there are some exceptions.
User avatar
Zepper
Formerly Fx3
Posts: 3262
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Re: Method for timing PPU with CPU

Post by Zepper »

rainwarrior wrote:I think "PPU runs prior to CPU" is a rather ambiguous statement.
Not in terms of emulation. Like run_cpu() then run_ppu() 3 times (NTSC). Look back. :wink:
What I think this is getting at is that you get a subtly different timing result if CPU writes begin to affect the PPU on the following clock, or on the same clock.
Exactly!
The truth of it is that CPU instructions take multiple clocks, and different things happen on each clock of the instruction. I believe writes usually happen on the last clock of an instruction (don't take my word for this, look it up), but there are some exceptions.
Yup. 8-)
User avatar
Aliasmk
Posts: 21
Joined: Wed Aug 26, 2015 8:24 am
Location: Ontario, Canada
Contact:

Re: Method for timing PPU with CPU

Post by Aliasmk »

I was looking online at examples of what other emulator authors did to create their cycles and I think I've found a method that compromises between rainwarrior's catch-up method and the CPU/PPU/PPU/PPU loop method.

The CPU step method returns the number of cycles an instruction takes, and then the main loop runs the PPU for 3*cpuCycles cycles.

Thoughts?

Code: Select all

//Modified from Go to C++
int cpuCycles = CPU.Step()
int ppuCycles = cpuCycles * 3
for(i := 0; i < ppuCycles; i++) {
	PPU.Step()
}
Source: https://github.com/fogleman/nes/
Aliasmk- GitHub :: Twitter :: Website
Current ALIAneS Emulator Progress: CPU complete, PPU indev - we have graphics and sprites!
User avatar
zeroone
Posts: 939
Joined: Mon Dec 29, 2014 1:46 pm
Location: New York, NY
Contact:

Re: Method for timing PPU with CPU

Post by zeroone »

Nintendulator's CPU executes each instruction as a sequence of microintructions. Each microinstruction takes 1 CPU cycle. And, every microinstruction triggers a main memory read or write. Within the read and write routines, the PPU is advanced. For NTSC, it is advanced by 3 PPU cycles. For PAL, it is normally advanced by 3 PPU cycles and by 4 PPU cycles every 5 advances, producing an average rate of 3.2 PPU cycles per CPU cycle.

The CPU and PPU will always be slightly out of sync. Nintendulator compensates by slightly adjusting the PPU rendering timings.
Post Reply