Nintendo 64 Part 19: Developing for Multiple Regions
PAL users deserve a larger framebuffer. What do I mean by that?
NTSC and PAL
The two most common standards for analogue terrestrial TV were NTSC and PAL. The reasons for their differences are steeped in history and make for good reading on Wikipedia, but the parts I care about are:
- NTSC displays about 59.94 fields per second, and PAL displays 50 fields per second.
- NTSC display about 480 lines on the screen, and PAL displays about 576.
PAL variants of the Nintendo 64 produce the full 576i signal you would expect, and there are three ways that your Nintendo 64 program can make that happen.
- You can keep you 320×240 pixel framebuffer and put black bars at the top and bottom of the screen. Your game will look equally sharp on NTSC and PAL systems, but it will not fill the screen on PAL, and the image will not have a square aspect ratio on PAL.
- You can keep the 320×240 framebuffer and stretch the image out on PAL systems. The VI will interpolate between lines in the framebuffer to make this work (by default, the VI does this already which makes the image a little soft but reduces flicker). Your game will look mostly the same on NTSC and PAL systems, but it will be a little softer on PAL systems and it won’t use the resolution available to PAL.
- You can use a 320×288 framebuffer on PAL systems. This mode mode is called “FPAL” in the Nintendo 64 documentation. Your game will look equally sharp on both NTSC and PAL systems and will use the full screen on both, but the aspect ratio will be different and you may need different 2D assets for the PAL version.
Real games often used options #1 or #2 because they’re easy.
My thoughts are this: if the PAL systems are running at a slower framerate and you have 20% extra time per frame (1/50 s versus 1/60 s), but the framebuffer is also exactly 20% larger (288 lines versus 240 lines), then isn’t that just perfect?
Option #3 it is.
Practical Considerations
3D is easy. All I have to do is set the correct aspect ratio in the projection matrix, and 3D graphics will appear on-screen with the correct proportions.
2D may require some additional thought. Images which appear on-screen may need to be stretched to match the different pixel aspect ratio that the Nintendo 64 “FPAL” (full-screen PAL) mode uses. I figure that some user interface elements can just look a little different on NTSC and PAL systems, but that that doesn’t apply to things like character portraits, which shouldn’t get squashed.
Memory could also be a problem, since the FPAL mode uses a 20% larger framebuffer. My plan is to allocate memory for an FPAL framebuffer in all game builds. This way, I won’t accidentally use the memory while testing on NTSC systems and then later discover that the PAL build is broken.
Building and Testing PAL
Hardware
I can’t test on PAL hardware because I don’t have a PAL Nintendo 64.
In a hardware system, the system type (NTSC, PAL, or Brazil’s PAL-M) is
fixed, and can be checked at run-time by examining the osTvType
variable exposed by LibUltra.
CEN64
CEN64 is similar. The system type is fixed by the choice of PIF ROM, which is passed as an argument to the emulator. I had some difficulty acquiring the PAL versions of the PIF ROM. To make this easier for you, here are the checksums (MD5, SHA-1, and SHA-256) of the NTSC and PAL variants of the PIF ROM:
NTSC PIF ROM
- MD5:
4921d5f2165dee6e2496f4388c4c81da
- SHA-1:
9174eadc0f0ea2654c95fd941406ab46b9dc9bdd
- SHA-256:
da51cbdac91c8b0048b203911af69faeebd64f363b0613c1aa4cf10b9749b5e3
PAL PIF ROM
- MD5:
2b6eec586faa43f3462333b844834554
- SHA-1:
46cae59d31f9298b93f3380879454fcef54ee6cc
- SHA-256:
d512fb4c1aa9203a1d8c6851af7b2db873487b359b4ef26e8dde2135bc0cb5f3
Other Emulators
Mupen64Plus (and I suspect, many other emulators) automatically choose the
system type based on the ROM header, which contains region information
at offset 0x3c
.
From the En64: ROM
page, I can see a list of region codes:
Code | Region |
---|---|
7 | Beta |
A | Asian (NTSC) |
B | Brazilian |
C | Chinese |
D | German |
E | North America |
F | French |
G | Gateway 64 (NTSC) |
H | Dutch |
I | Italian |
J | Japanese |
K | Korean |
L | Gateway 64 (PAL) |
N | Canadian |
P | European (basic spec.) |
S | Spanish |
U | Australian |
W | Scandinavian |
X | European |
Y | European |
I examined the header of an arbitrary PAL game for the Nintendo 64, and saw that it used the “P” region code, so I picked “P” for PAL. (Maybe “P” stands for PAL in the first place? Or does it stand for euroPe?) My NTSC build will use the “E” code for North America.
Mode Setting
In the end, I have two ROMs: an NTSC “E” region ROM and a PAL “P” region ROM. The two ROMs have identical code. The code is only compiled once, but copied into two ROM images with different headers.
The ROMs choose the mode by checking the osTvType
variable:
OSViMode *mode;
switch (osTvType) {
case OS_TV_PAL:
mode = &osViModeFpalLpn1;
break;
default:
case OS_TV_NTSC:
mode = &osViModeNtscLpn1;
break;
case OS_TV_MPAL:
mode = &osViModeMpalLpn1;
break;
}
osViSetMode(mode);
I can figure out any potential differences with 2D assets later. For now, the ROMs are also given the exact same data. The main benefit—for the moment—is that I can run the PAL ROM in Mupen64Plus and it will automatically choose the correct region from the ROM header.
Test Program
I wrote a test program to see how emulators detect region.
One ROM has the “E” region for NTSC, and the other has the “P” region for PAL. Here is what they look like when run in Mupen64Plus:
The test program draws a rectangle which is an equal number of pixels high and wide—this will show up as square on NTSC systems because the Nintendo 64 has a 1:1 pixel aspect ratio in NTSC video modes, and it will show up as a 1.2:1 ratio rectangle on PAL systems due to the increased vertical resolution.
These programs still detect the TV type using osTvType
.