Fredbill wrote: |
---|
I'm currently having trouble deciphering the .nes file format (The creator *had* to make it more complicated than it needed to be). |
It was actually simple initially, but kept getting expanded as more and more games got dumped. They tried to keep it backwards compatible.
Fredbill wrote: |
---|
How am I supposed to extract the data from the flags? |
Bitwise operations, good buddy. I gave a breakdown of how they work in this post:
http://www.cplusplus.com/forum/beginner/72705/#msg387899
Here's a snippit from the nesdev wiki:
http://wiki.nesdev.com/w/index.php/INES#Flags_6
76543210
||||||||
||||+||+- 0xx0: vertical arrangement/horizontal mirroring (CIRAM A10 = PPU A11)
|||| || 0xx1: horizontal arrangement/vertical mirroring (CIRAM A10 = PPU A10)
|||| || 1xxx: four-screen VRAM
|||| |+-- 1: SRAM in CPU $6000-$7FFF, if present, is battery backed
|||| +--- 1: 512-byte trainer at $7000-$71FF (stored before PRG data)
++++----- Lower nybble of mapper number |
(ignore bit 3 for now... I'll explain later)
As this chart illustrates... after we ignore bit 3... we can see that bit 0 selects whether or not to use Horizontal or Vertical mirroring.
So we can just use the AND operator to extract the bit we're interested in. In this case, since we're interested in the lowest bit (bit 0), we AND with 1 (since 1 == 00000001 in binary)
1 2 3 4
|
if( flags1 & 0x01 )
// vertical mirroring
else
// horizontal mirroring
|
likewise, bit 1 (0x02) selects whether or not the SRAM is battery backed (so you can generate .sav files to save the user's game) So to extract that bit, we just AND with 2:
1 2 3 4
|
if( flags1 & 0x02 )
// SRAM is battery backed
else
// SRAM is not battery backed
|
Fredbill wrote: |
---|
What do they mean? |
flags6: bit 0 = selects whether to use Horizontal or Vertical mirroring by default
flags6: bit 1 = indicates that SRAM is battery backed (the cartridge is capable of saving games between plays)
flags6: bit 2 = Ignore this. No games use it. It's a legacy thing for FFE mappers that are long obsolete.
flags6: bit 3 = This bit is only significant for mapper 4. And it is only used in 2 games (Rad Racer 2 and Gauntlet). You can safely ignore it for now.
flags6: bits4-7 = Determine the low 4 bits of the mapper number. Combine this with the bits from flags7 to form an 8-bit mapper number. The mapper number tells you the cartridge type and how the game will swap out PRG/CHR and other cartridge-side hardware info.
flags7: You can ignore all of this except the mapper bits. The low bits are practically never used in the wild.
Everything after flags7 in the header can be ignored, as in-the-wild ROMs don't use them or have them set incorrectly.
A question I anticipate but you have not asked yet wrote: |
---|
So wtf is mirroring and what's the difference between horizontal, vertical, and 4-screen? |
NES graphics work by having 'nametables'. A nametable is basically a 2D grid of tiles. Each tile is 8x8 pixels.
Each nametable consists of 32*30 tiles... effectively forming a full "screen".
A nametable is 0x0400 bytes (1K) in size.
Conceptually, there are 4 nametables on the NES. They reside in PPU memory starting at address $2000 (not to be confused with $2000 in CPU memory).
They're logically laid out like so (remember each NT is a "screen"):
[ $2000 ][ $2400 ]
[ $2800 ][ $2C00 ]
|
So... if the screen is not scrolled at all... the only NT that will be visible will be the $2000 NT. But as the screen scrolls to the right, you'll see more of $2400 and less of $2000. As you scroll down, you'll see more of $2800,$2C00. Etc.
They "wrap"... so as you scroll passed the right of $2400 you will scroll back into the $2000 NT.
This is all fine and good... however the NES does not physically have the memory for 4 nametables. It only has 2K of memory for nametables... so there are only
two physical nametables. I call these nametables NTA and NTB.
Nametable mirroring (aka "mirroring") is the technique used to spread these 2 nametables across all 4 "slots".
The most simple form of mirroring is "1 screen" (not covered in the NES header). "1 screen" simply takes one of the nametables and puts it in all 4 slots. Example:
[ NTA ][ NTA ]
[ NTA ][ NTA ] |
The idea here is that addresses $2000, $2400, $2800, and $2C00 all 'mirror' the same place in memory. Reading from any of those addresses will read the same byte. And writing to any of those addresses will change the value at all of them (ie: they all point to the same place).
In 1-screen, each of the four slots will appear identical.
More common forms of mirroring are horizontal and vertical. These simply arrange the nametables in a different fashion.
Horizontal:
[ NTA ][ NTA ]
[ NTB ][ NTB ] |
Vertical:
[ NTA ][ NTB ]
[ NTA ][ NTB ] |
Games which scroll horizontally (like Super Mario Bros) will tend to use vertical mirroring. Whereas games which scroll vertically (like Ice Climber) will tend to use horizontal mirroring.
"4 screen" mirroring is extremely rare. I'm only aware of 3 games which use it, and one of them is incredibly obscure. Games which use 4-screen use additional memory on the cartridge to provide a full 4 nametables, so that none of the slots have to be mirrors -- they can all be unique.