Need help with CPU vs PPU timing

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Need help with CPU vs PPU timing
by on (#223741)
Hi All,

I am really stuck on my CPU vs PPU timings in my Swift NES emulator and was wondering if someone could have a quick parse of my step() function in my Emulator class. The step() function is called 60 times per second. It calculates a target number of cycles it needs the CPU to execute (usually 29830). Inside the loop I then call the step function on each of the CPU, PPU, and APU instances. CPU should have no bugs and matches output of a test log from the wiki, APU is currently empty, and PPU step function calls PPU tick function 3 times. In the tick function the tickCount is incremented every time, this is only for debug purposes. Also inside the tick function a cycle variable is incremented (x pos) and scalene is incremented when cycle reaches 340, the frame is incremented when scaling reaches 262. These numbers may be off by 1, haven't checked them yet.

My issue is that I expect the stepUntil() function to execute 29830 cycles on the CPU and a full 89,000 PPU ticks. I am only getting around 22,000 PPU ticks before the loop exits as the CPU has executed all of its cycles.

I don't think my bug is in the PPU, I think it is in my understanding of CPU cycles vs PPU ticks. Can anyone see what I have wrong here?

Code:
    func stepUntil( secondsElapsed seconds:TimeInterval)
    {
        guard state != .stopped else { return }

        var elapsedCycles : UInt16 = 0

        let targetCycles = Int(TimeInterval(cpu.frequencyHz) * seconds)

        ppu.tickCount = 0

        repeat
        {
            let (cont, instructionInfo) = cpu.step()
            ppu.step()
            apu.step()

            elapsedCycles += instructionInfo.cycles

            if cont == false
            {
                state = .stopped
            }

        } while state != .stopped && elapsedCycles < targetCycles

        print("Cycles: \(elapsedCycles) PPU:\(ppu.tickCount) frame:\(ppu.frame) scanline:\(ppu.scanline)")
    }

    @objc func step()
    {
        print("FPS:\(round(1.0/(displayLink.targetTimestamp - displayLink.timestamp)))")

        stepUntil( secondsElapsed:1.0/60.0)
    }


The output of this code is:
Code:
Cycles: 29830 PPU:22674 frame:4 scanline:240
Cycles: 29829 PPU:22068 frame:5 scanline:42
Cycles: 29834 PPU:22668 frame:5 scanline:109
Cycles: 29830 PPU:22674 frame:5 scanline:175
Cycles: 29859 PPU:22407 frame:5 scanline:241
Cycles: 29829 PPU:22161 frame:6 scanline:44


As you can see it takes 4 device Frames to output a single frame (Frame 5 here). My emulator step function gets called 60 FPS consistently and is not dropping frames (I have triple checked). My PPU is only getting to execute 22,000 ticks instead of 89,000.

Cheers,
Brett
Re: Need help with CPU vs PPU timing
by on (#223746)
It looks like you're only running the PPU and APU once per CPU instruction, not once per CPU cycle - put ppu.step() and apu.step() inside a loop that runs for instructionInfo.cycles iterations and you'll probably be a bit closer to desired behavior, though you might still have some extremely minor issues regarding reads and writes being bunched together at the end of CPU instructions (i.e. instead of being done during each instruction cycle).
Re: Need help with CPU vs PPU timing
by on (#223748)
OMG Quietust you are absolutely right, have been staring at this for a few days but couldn't see what I got wrong. Clear as day once it is pointed out.

Thanks heaps,
Brett
Re: Need help with CPU vs PPU timing
by on (#223875)
Meanwhile, I'm just doing the hack where you make events happen 12 ticks before they actually do for the purposes of polling.