NES Advantage

Making NES Development Less Hard

Implementing a Timer

The NMI/VBLANK interrupt is the closest thing the NES has to an internal clock, firing sixty times a second (fifty on PAL TVs). Running a timer that counts every tick of the NMI is useful for all sorts of functions, so let's look at how to set one up. Luckily, it's quite straightforward.

Since the timer is going to be written and read constantly, we'll dedicate some zero page RAM to it. Depending on what you need it for, a single byte (counting 0-255 in a loop) might be enough. But since timers are often used to seed random number generation, we'll use two bytes to store a much larger count.

.segment "ZEROPAGE" timer: .res 2

Then, it's simply a matter of adding a little code to your NMI interrupt.

; ... other NMI code INC timer BNE NoSecondByteIncrement INC timer+1 NoSecondByteIncrement: ; ... other NMI code

There's a bit of shorthand in this code, so let's unpack it.

We start by incrementing timer, as defined by the .res statement back in our zero page. But we reserved two bytes at once, and assembly doesn't have any way of knowing they're supposed to represent one big number. When we increment timer, we're actually just incrementing the first of those bytes.

So the second line of code performs a BNE, Branch if Not Equal. BNE it checks the Zero Flag, which is generally used for comparisons (i.e. it would be set if we had just performed a CMP on two equal numbers). But the Zero Flag is also set if we just incremented a byte from 255 back to 0. Thus our BNE says, "If timer didn't just become 0, branch ahead to the NoSecondByteIncrement label, but if it did, also increment the byte at timer+1."

timer+1, of course, is the second byte we reserved. In other words, every time the low byte of our "clock" rolls over from 255 to 0, the high byte ticks up by 1. Pretty cool.

Copyright ©2024 Nathaniel Webb/Nat20 Games