Feeds:
Posts
Comments

Posts Tagged ‘assembly’

When you think about it, the original Nintendo was an amazing system. That to this day millions of people still love the games on that old system says something about its staying power. Yet even compared to personal computers of the day, it was seriously underpowered. This of course was an attempt to keep the Nintendo low in price and accessible to a larger audience. It was an obvious success not only business-wise, but also technically.

The Nintendo had a 6502 processor, an extraordinarily common processor found in many computers at the time, running at a measly 1.79 MHz. It had a 16-bit memory address bus, which means it could only access up to 64KB of RAM at a time without special hardware. It had a whole 2KB of built-in RAM. This really isn’t a whole lot to work with. So how did such awesome games come from just that?

First, the Nintendo had a few tricks up its sleeve:

  • It had a custom-made graphics processor. Most game players these days have heard of GPUs — this was similar, though it was called a PPU (Picture Processing Unit). It was optimized to display tile-mapped backgrounds and sprites on the screen. It refreshed the screen at a consistent 60 frames per second for American (NTSC) TV’s (beat that Crysis!). With this single-mindedness, it was able to perform some amazing feats using very little data.
  • Various types of cartridges expanded the hardware capabilities of the system. It wasn’t uncommon for cartridges to include additional RAM — up to around 64kb (a lot better than 2kb!). On occasion it was battery-backed, so it could be used as save RAM. Some cartridges even expanded the graphics and sound capabilities to the system — adding interrupts, additional graphics memory, even more colors and sound channels!
  • Cartridge ROM was usually mapped to two different 16kb areas of addressable memory. For a 32kb game, that’s all you need. However, since it’s really hard to do much with 32kb for an entire game, most cartridges contained many banks and allowed you to switch between them at runtime. This allowed for a theoretically limitless cartridge size.

OK, cool, so the Nintendo was made for games, and it could be expanded on a per-game basis. But how could it pack so much into such a small amount of space? Most games these days require several gigabytes of data, so how could games fit in such small amounts of ROM?

Case in point: Metroid. The Metroid Database (thanks Ian) has a ton of information about Metroid, including some cool technical details. These guys have disassembled the ROM and commented it and added labels and symbols! Furthermore, they have a detailed page describing the level data in Metroid. Here’s a summary:

  1. Screens are divided into 8×8 tiles. Each pixel in the tile is represented by a 2-bit index into that tile’s palette (yes, each tile can only have 4 unique colors), which means that each tile takes 16 bytes. There can be up to 256 tiles loaded at a time, and they’re hard to swap out individually, so there are typically only 256 tiles per area. The whole thing takes about 4kb. The screen resolution is 256×240, which means there are 32×30 tiles on the screen. Each tile is given a 1-byte ID (since there are only 256 tiles available), so the screen map takes just under 1kb. There is some additional data needed to specify 4-color palettes assigned to each tile, which brings the total up to exactly 1kb. All of this is handled by Nintendo’s fancy PPU.
  2. Metroid further groups 2×2 tiles together, making a 16×16 meta tile. There are only 16×15 meta tiles in a screen, which cuts the map size to 1/4th (just under 256 bytes as-is).
  3. Metroid goes even further and defines arbitrary groups of meta tiles, which the author calls “structures”. They can be any rectangular-shaped areas of meta tiles that can be placed around the screen at specific points. Now screens are made up of collections of 3-byte structure identifiers.
  4. All levels in the game are divided into “rooms”, which are one screen in size. There are less than 256 different rooms in each area — some of them are repeated several times! Since there are less than 256, you can give each room type a unique 1-byte ID.
  5. The overall level structure is defined in a 32×32 map, where each entry in the map is a single byte corresponding to the room ID that should be displayed there. This takes a total of 1kb.

This is a rather insane amount of compression. With this setup, all of Brinstar (the starting area) takes up:

  • 32 bytes for the palette
  • 94 bytes for room pointers
  • 100 bytes for structure pointers
  • 2115 bytes for room data
  • 620 bytes for structure data
  • Around 4096 bytes for tile data

…adding up to 7027 bytes to encode all of the background graphics for the entire Brinstar area! For comparison, a 50×50 24-bit color Windows BMP file (without the header) is larger than this. Hell, the text in this post is almost that size! Yet it was a huge area that would take hours to fight your way through, and you would have fun doing it.

Obviously there’s more to the game than the background graphics. With its haunting music, immersive exploration, fun gameplay, and a twist at the end, Metroid is a classic among classics. Yet you got all of this with a ROM that weighed in at less than 128kb. You can fit 10 Metroids in a standard 3.5″ floppy.

It’s amazing what software engineers can do given limited constraints.

Read Full Post »