Dizzy The Adenturer (CRC: DB99D0CB) runs on the Camerica mapper (mapper 71), which is a very basic mapper.
The game however seems to use some kind of interrupt, which I assume is the Vertical blank NMI, to split the screen close to the top so that the top strip contains the game's status panel, whilst the bottom second contains the game level. As with all Dizzy games (that I know of), the game doesn't use scrolling and instead flips the screen when Dizzy reaches an edge.
In my emulator I am experiencing what seems to be a 1 pixel vertical jitter in the game level, as if the code is alternating the Y scroll value by 1 pixel every other frame.
Does anyone have any idea why this is happening please? I am suspecting some kind of frame timing issue in my own code, but I can't seem to find a solution.
Camerica / mapper 71 games tend to be very anal about timing precision.
I loaded this game up (MD5:
7dc7d65ea289fbbb32cb76cffb2c31c7 *Dizzy The Adventurer (Camerica) (Aladdin) [!].nes) in NO$NES to see how it was doing the screen split -- looks like it might use
sprite 0 to help with this (it's X/Y location is $92/$25, tile $00, and it has the priority bit set). I imagine this is compounded by very precise code.
You're correct that the game doesn't "scroll" in the sense that there's no real-time "panning" of the screen.
Take a look at the game in NO$NES (you'll find Window -> VRAM Viewer and Window -> I/O Map to be quite useful, especially since the registers update in real-time) and in Nintendulator (if you look very carefully in Nintendulator on either the first game screen or after finishing the first puzzle + moving to the next screen, you'll see some of sprite 0's pixels partially visible). Nintendulator tends to have extremely precise PPU emulation. Sadly I don't have this cart to try out on actual hardware to determine what it looks like there.
Is it at all possible to get an animated GIF (should be 2 frames? Maybe 3?) or video or something so we can see what's happening?
Double check your sprite 0 hit, and the timing on when T and V are assigned.
The game isn't timing from an interrupt, it's timing from the sprite 0 hit.
I ended up adding some GIF capture functionality for this.
Here's a capture of the gameplay:
It looks like the level is scrolling up and down by 1 pixel, hence what I called "jitter".
Anyone who's ever worked on a NES emulator knows about scrolling jitter.
According to a quick run of Nintendulator:
First 2006 write happens on scanline 40, beginning at dot 233-243
then there are three more writes: 12 dots later, 321 dots after that, 12 dots after that.
Make sure your $2002 read is getting PPU status from the correct time, at the end of the read instruction, not the beginning of the instruction.
Likewise, make sure your 2006 writes are taking effect at the end of the STX/STY instruction, not the beginning of the instruction.
Thanks for the detailed info Dwedit.
In my emulator I essentially step one instruction at a time, determine the cycles consumed, multiply by 3 to get the corresponding PPU cycles and then step the PPU accordingly. This essentially means that PPU status is determined at the start of the instructions, not the end. I will have to find a way of going around this.
Turned out I had a problem with the NMI delay triggered by the PPU. I set this to 21 PPU cycles (7 CPU cycles) and this solved the jitter.
For all I know it is working as a side effect of this, but I think I had the VBL - NMI timing a bit off anyway.
Games will almost always use 4-cycle instructions (LDx/STx absolute) to read/write from hardware registers, so you can get away with treating reads/writes as happening 12 dots later than the timestamp at the start of the instruction. Of course, this is not accurate if a game decides to use another addressing mode (like (nn,X) or (nn),Y), or uses a read-modify write instruction with dummy read triggering something else entirely.
Dwedit wrote:
Of course, this is not accurate if a game decides to use another addressing mode (like (nn,X) or (nn),Y), or uses a read-modify write instruction with dummy read triggering something else entirely.
The only practical use I can see for this is a test that
uses open bus behavior to tell the difference between Famicom, US front-loading NES, US top-loading NES, and an NES with a PowerPak, or to detect attached controllers. Fill the nametable with known data like $00 and $FF, then read it back at $3F18,X (with X set to $FF) and see which bits ride the open bus from the read from $3F17 (mirror of $2007) to $4017 (controller 2).