1 module nes.ines; 2 3 import std.stdio; 4 5 import nes.cartridge; 6 7 enum iNESFileMagic = 0x1a53454e; 8 9 align(1) struct iNESFileHeader { 10 uint magic; // iNES magic number 11 ubyte numPRG; // number of PRG-ROM banks (16KB each) 12 ubyte numCHR; // number of CHR-ROM banks (8KB each) 13 ubyte control1; // control bits 14 ubyte control2; // control bits 15 ubyte numRAM; // PRG-RAM size (x 8KB) 16 ubyte[7] padding; // unused padding 17 } 18 19 class NesFileException : Exception 20 { 21 import std.exception : basicExceptionCtors; 22 23 mixin basicExceptionCtors; 24 } 25 26 // LoadNESFile reads an iNES file (.nes) and returns a Cartridge on success. 27 // http://wiki.nesdev.com/w/index.php/INES 28 // http://nesdev.com/NESDoc.pdf (page 28) 29 Cartridge LoadNESFile(string path) { 30 // open file 31 auto file = File(path); 32 33 // read file header 34 iNESFileHeader[1] headers; 35 file.rawRead(headers); 36 37 // verify header magic number 38 if (headers[0].magic != iNESFileMagic) { 39 throw new NesFileException("invalid .nes file"); 40 } 41 42 // mapper type 43 auto mapper1 = cast(ubyte)(headers[0].control1 >> 4); 44 auto mapper2 = cast(ubyte)(headers[0].control2 >> 4); 45 auto mapper = cast(ubyte)(mapper1 | mapper2 << 4); 46 47 // mirroring type 48 auto mirror1 = cast(ubyte)(headers[0].control1 & 1); 49 auto mirror2 = cast(ubyte)((headers[0].control1 >> 3) & 1); 50 auto mirror = cast(ubyte)(mirror1 | mirror2 << 1); 51 52 // battery-backed RAM 53 auto battery = cast(ubyte)((headers[0].control1 >> 1) & 1); 54 55 // read trainer if present (unused) 56 if ((headers[0].control1 & 4) == 4) { 57 auto trainer = new ubyte[512]; 58 file.rawRead(trainer); 59 } 60 61 // read prg-rom bank(s) 62 auto prg = new ubyte[cast(int)headers[0].numPRG * 16384]; 63 file.rawRead(prg); 64 65 // read chr-rom bank(s) 66 bool chrRAM; 67 ubyte[] chr; 68 69 if (headers[0].numCHR > 0) { 70 chr = new ubyte[cast(int)headers[0].numCHR * 8192]; 71 file.rawRead(chr); 72 } else { 73 // provide chr-ram if not in file 74 chr = new ubyte[8192]; 75 chrRAM = true; 76 } 77 78 // success 79 return new Cartridge(prg, chr, mapper, mirror, battery, chrRAM); 80 }