namespace Heuristics { struct Famicom { Famicom(vector& data, string location); explicit operator bool() const; auto manifest() const -> string; private: vector& data; string location; }; Famicom::Famicom(vector& data, string location) : data(data), location(location) { } Famicom::operator bool() const { if(data.size() < 16) return false; if(data[0] != 'N') return false; if(data[1] != 'E') return false; if(data[2] != 'S') return false; if(data[3] != 26) return false; return true; } auto Famicom::manifest() const -> string { if(!operator bool()) return {}; uint mapper = ((data[7] >> 4) << 4) | (data[6] >> 4); uint mirror = ((data[6] & 0x08) >> 2) | (data[6] & 0x01); uint prgrom = data[4] * 0x4000; uint chrrom = data[5] * 0x2000; uint prgram = 0u; uint chrram = chrrom == 0u ? 8192u : 0u; string output; output.append("game\n"); output.append(" sha256: ", Hash::SHA256({&data[16], data.size() - 16}).digest(), "\n"); output.append(" label: ", Location::prefix(location), "\n"); output.append(" name: ", Location::prefix(location), "\n"); switch(mapper) { default: output.append(" board: NES-NROM-256\n"); output.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n"); break; case 1: output.append(" board: NES-SXROM\n"); output.append(" chip type=MMC1B2\n"); prgram = 8192; break; case 2: output.append(" board: NES-UOROM\n"); output.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n"); break; case 3: output.append(" board: NES-CNROM\n"); output.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n"); break; case 4: //MMC3 output.append(" board: NES-TLROM\n"); output.append(" chip type=MMC3B\n"); prgram = 8192; //MMC6 //output.append(" board: NES-HKROM\n"); //output.append(" chip type=MMC6\n"); //prgram = 1024; break; case 5: output.append(" board: NES-ELROM\n"); output.append(" chip type=MMC5\n"); prgram = 65536; break; case 7: output.append(" board: NES-AOROM\n"); break; case 9: output.append(" board: NES-PNROM\n"); output.append(" chip type=MMC2\n"); prgram = 8192; break; case 10: output.append(" board: NES-FKROM\n"); output.append(" chip type=MMC4\n"); prgram = 8192; break; case 16: output.append(" board: BANDAI-FCG\n"); output.append(" chip type=LZ93D50\n"); break; case 21: case 23: case 25: //VRC4 output.append(" board: KONAMI-VRC-4\n"); output.append(" chip type=VRC4\n"); output.append(" pinout a0=1 a1=0\n"); prgram = 8192; break; case 22: //VRC2 output.append(" board: KONAMI-VRC-2\n"); output.append(" chip type=VRC2\n"); output.append(" pinout a0=0 a1=1\n"); break; case 24: output.append(" board: KONAMI-VRC-6\n"); output.append(" chip type=VRC6\n"); break; case 26: output.append(" board: KONAMI-VRC-6\n"); output.append(" chip type=VRC6\n"); prgram = 8192; break; case 34: output.append(" board: NES-BNROM\n"); output.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n"); break; case 66: output.append(" board: NES-GNROM\n"); output.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n"); break; case 69: output.append(" board: SUNSOFT-5B\n"); output.append(" chip type=5B\n"); prgram = 8192; break; case 73: output.append(" board: KONAMI-VRC-3\n"); output.append(" chip type=VRC3\n"); output.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n"); prgram = 8192; break; case 75: output.append(" board: KONAMI-VRC-1\n"); output.append(" chip type=VRC1\n"); break; case 85: output.append(" board: KONAMI-VRC-7\n"); output.append(" chip type=VRC7\n"); prgram = 8192; break; } if(prgrom) output.append(Memory{}.type("ROM").size(prgrom).content("Program").text()); if(prgram) output.append(Memory{}.type("RAM").size(prgram).content("Save").text()); if(chrrom) output.append(Memory{}.type("ROM").size(chrrom).content("Character").text()); if(chrram) output.append(Memory{}.type("RAM").size(chrram).content("Character").isVolatile().text()); return output; } }