Skip to content

Instantly share code, notes, and snippets.

@Qix-
Created January 2, 2016 03:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Qix-/8b651c93fbf05a904fee to your computer and use it in GitHub Desktop.
Save Qix-/8b651c93fbf05a904fee to your computer and use it in GitHub Desktop.
NES Header Checker
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ines-header.h"
#define max(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; })
static const char magic[4] = { 0x4E, 0x45, 0x53, 0x1A };
const char * toBool(unsigned char val) {
return val ? "Yes" : "No";
}
const char * getArrangement(unsigned char low, unsigned char high) {
char val = (high << 1) | low;
switch (val) {
case 0: return "Vertical Arrangement / Horizontal Mirroring";
case 1: return "Horizontal Arrangement / Vertical Mirroring";
case 2: return "2x2 (4 Page) Grid (No Mirroring)";
default: return "UNKNOWN (Bad Value)";
}
}
const char getMapper(unsigned char low, unsigned char high) {
return (high << 4) | low;
}
const char * getTVSystem(unsigned char system) {
return system ? "PAL" : "NTSC";
}
int main(int argc, const char **argv) {
if (argc != 2) {
fprintf(stderr, "usage: %s <.NES rom or header binary>\n", argv[0]);
return 1;
}
FILE *file = fopen(argv[1], "rb");
if (!file) {
fprintf(stderr, "could not open file");
return 1;
}
INESHeader header;
size_t count = fread(&header, 1, sizeof(header), file);
if (count != sizeof(header)) {
fclose(file);
fprintf(stderr, "could not read file; is it 16 bytes long?\n");
return 2;
}
fclose(file);
if (memcmp(&header.magic, &magic, 4) != 0) {
fprintf(stderr, "given file has an invalid magic number\n");
return 3;
}
printf(
"Mapper:\t\t%03d\n"
"TV System:\t%s\n"
"PRG ROM size:\t%dKb (%d 16Kb banks)\n"
"PRG RAM size:\t%dKb (%d 8Kb banks)\n"
"CHR ROM size:\t%dKb (%d 8Kb banks)\n"
"Arrangement:\t%s\n"
"Trainer?:\t%s\n"
"Battery RAM?\t%s\n"
"iNES2 Header?\t%s\n"
"Playchoice-10?\t%s\n"
"VSUnisystem?\t%s\n",
getMapper(header.mapperLow, header.mapperHigh),
getTVSystem(header.tvSystem),
header.prgRomSize * 16, header.prgRomSize,
max(1, header.prgRamSize) * 8, max(1, header.prgRamSize),
header.chrRomSize * 8, header.chrRomSize,
getArrangement(header.arrangementLow, header.arrangementHigh),
toBool(header.hasTrainer),
toBool(header.hasBatteryRam),
toBool(header.ines2Header),
toBool(header.playchoice10),
toBool(header.vsUnisystem));
return 0;
}
typedef struct __attribute__((packed)) {
unsigned char magic[4];
unsigned char prgRomSize;
unsigned char chrRomSize;
unsigned char arrangementLow : 1;
unsigned char hasBatteryRam : 1;
unsigned char hasTrainer : 1;
unsigned char arrangementHigh : 1;
unsigned char mapperLow : 4;
unsigned char vsUnisystem : 1;
unsigned char playchoice10 : 1;
unsigned char ines2Header : 2;
unsigned char mapperHigh : 4;
unsigned char prgRamSize;
unsigned char tvSystem : 1;
unsigned char reserved : 7;
unsigned char reservedZeroFill[6];
} INESHeader;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment