Since the first computers were put together, one of their basic functions has been to keep time: to coordinate actions according to timers. Even the simplest of games has an element of time to it: Pong, for example, needs to move the ball across the screen at a particular rate. In order to handle these timing issues, every games console has some form of timer to allow for things to happen at a given moment, or at a specific rate.
The GameBoy is no exception to this rule, and contains a set of registers which automatically increment based on a programmable schedule. In this part of the series, I'll be investigating the structure and operation of the timer, and how it can be used to seed pseudo-random number generators, such as the one contained in Tetris and its various clones. One example of a Tetris clone which uses the timer, to pick random pieces for the game, is demonstrated below.
The GameBoy's CPU, as described in the first part of this series, runs on a 4,194,304Hz clock, with two internal measures of the time taken to execute each instruction: the T-clock, which increments with each clock step, and the M-clock, which increments at a quarter of the speed (1,048,576Hz). These clocks are used as the source of the timer, which counts up, in turn, at a quarter of the rate of the M-clock: 262,144Hz. In this article, I'll refer to this final value as the timer's "base speed".
The GameBoy's timer hardware offers two separate timer registers: the system works by incrementing the value in each of these registers at a pre-determined rate. The "divider" timer is permanently set to increment at 16384Hz, one sixteenth of the base speed; since it's only an eight-bit register, its value will go back to zero after it reaches 255. The "counter" timer is more programmable: it can be set to one of four speeds (the base divided by 1, 4, 16 or 64), and it can be set to go back to a value that isn't zero when it overflows past 255. In addition, the timer hardware will send an interrupt to the CPU, as described in part 8, whenever the "counter" timer does overflow.
There are four registers used by the timer; these are made available for use by the system as part of the I/O page, just like the graphics and interrupt registers:
|0xFF04||Divider||Counts up at a fixed 16384Hz;|
reset to 0 whenever written to
|0xFF05||Counter||Counts up at the specified rate|
Triggers INT 0x50 when going 255->0
|0xFF06||Modulo||When Counter overflows to 0,|
it's reset to start at Modulo
Since the "counter" timer triggers an interrupt when it overflows, it can be especially useful if a game requires something to happen at a regular interval. However, a Gameboy game can generally use the vertical blank to much the same effect, since it occurs at a regular pace of almost 60Hz; the vertical blanking handler can be used not only to refresh the screen contents, but to check the keypad and update the game state. Therefore, there's little call for use of the timer in traditional Gameboy games, though it can be used to greater effect in graphic demos.
Implementing the timer emulation
The emulation developed in this article series uses the CPU's clock as the basic unit of time. For that reason, it's simplest to maintain a clock for the timer that runs in step with the CPU clock, and is updated by the dispatch function. It's convenient at this stage to keep the DIV register as a separate entity to the controllable timer, incremented at 1/16th the rate again of the fastest timer step:
Timer.js: Clock increment
From here, the controllable timer is made up of varying divisions of the base speed, making it relatively simple to check whether the timer values need to be stepped up, and to provide the registers as part of the memory I/O page. The interface between the following section of code and the MMU I/O page handler, is left as an exercise for the reader.
Timer.js: Register check and update
Seeding a pseudo-random number generator
A major component of many games is unpredictability: Tetris, for instance, will throw an unknown pattern of pieces down the well, and the game consists of building rows using these pieces. Ideally, a computer provides unpredictability by generating random numbers, but this runs contrary to the methodical nature of a computer; it's not possible for a computer to provide a truly random pattern of numbers. Various algorithms exist to produce sequences of numbers that look superficially like they're random, and these are called pseudo-random number generation (PRNG) algorithms.
A PRNG is generally implemented as a formula that, given a particular input number, will produce another number with almost no relation to the input. For Tetris, nothing so complicated is required; instead, the following code is used to produce a seemingly random block.
Tetris.asm: Select new block
The basis of the Tetris block selector is the DIV register: since the selection routine is only run once every few seconds, the register will have an unknown value on any given run, and it thus makes a fair approximation of a random number source. With the timer system having been emulated, Tetris and its clones can be emulated to full functionality, as shown in Figure 1.
Coming up: Sound
Imran Nazar <email@example.com>, Feb 2011.
Article dated: 25th Feb 2011