/***************************************************************************************** NES MMC Emulation - UNIF boards Very preliminary support for UNIF boards TODO: - properly support WRAM, etc. ****************************************************************************************/ /* Set to generate prg & chr files when the cart is loaded */ #define SPLIT_PRG 0 #define SPLIT_CHR 0 /************************************************************* unif_list Supported UNIF boards and corresponding handlers *************************************************************/ struct unif { const char *board; /* UNIF board */ int nvwram; int wram; int chrram; int board_idx; }; /* CHRRAM sizes */ enum { CHRRAM_0 = 0, CHRRAM_1, CHRRAM_2, CHRRAM_4, CHRRAM_6, CHRRAM_8, CHRRAM_16, CHRRAM_32 }; static const unif unif_list[] = { /* UNIF NVW WRAM CRAM IDX*/ { "DREAMTECH01", 0, 0, CHRRAM_8, DREAMTECH_BOARD}, //UNIF only! { "NES-ANROM", 0, 0, CHRRAM_8, STD_AXROM}, { "NES-AOROM", 0, 0, CHRRAM_8, STD_AXROM}, { "NES-CNROM", 0, 0, CHRRAM_0, STD_CNROM}, { "NES-NROM", 0, 0, CHRRAM_0, STD_NROM}, { "NES-NROM-128", 0, 0, CHRRAM_0, STD_NROM}, { "NES-NROM-256", 0, 0, CHRRAM_0, STD_NROM}, { "NES-NTBROM", 8, 0, CHRRAM_0, SUNSOFT_DCS}, { "NES-SLROM", 0, 0, CHRRAM_0, STD_SXROM}, { "NES-TBROM", 0, 0, CHRRAM_0, STD_TXROM}, { "NES-TFROM", 0, 0, CHRRAM_0, STD_TXROM}, { "NES-TKROM", 8, 0, CHRRAM_0, STD_TXROM}, { "NES-TLROM", 0, 0, CHRRAM_0, STD_TXROM}, { "NES-UOROM", 0, 0, CHRRAM_8, STD_UXROM}, { "UNL-22211", 0, 0, CHRRAM_0, TXC_22211}, // mapper 172 & 173 are variant of this one... no UNIF? { "UNL-KOF97", 0, 0, CHRRAM_0, UNL_KOF97}, { "UNL-SA-NROM", 0, 0, CHRRAM_0, SACHEN_TCA01}, { "UNL-VRC7", 0, 0, CHRRAM_0, KONAMI_VRC7}, { "UNL-T-230", 0, 0, CHRRAM_8, UNL_T230}, { "UNL-CC-21", 0, 0, CHRRAM_0, UNL_CC21}, { "UNL-AX5705", 0, 0, CHRRAM_0, UNL_AX5705}, { "UNL-SMB2J", 8, 8, CHRRAM_0, UNL_SMB2J}, { "UNL-8237", 0, 0, CHRRAM_0, UNL_8237}, { "UNL-SL1632", 0, 0, CHRRAM_0, REXSOFT_SL1632}, { "UNL-SACHEN-74LS374N", 0, 0, CHRRAM_0, SACHEN_74LS374}, // mapper 243 variant exists! how to distinguish?!? mapper243_l_w, NULL, NULL, NULL, NULL, NULL, NULL (also uses NT_VERT!) { "UNL-TC-U01-1.5M", 0, 0, CHRRAM_0, SACHEN_TCU01}, { "UNL-SACHEN-8259C", 0, 0, CHRRAM_0, SACHEN_8259C}, { "UNL-SA-016-1M", 0, 0, CHRRAM_0, AVE_NINA06}, // actually this is Mapper 146, but works like 79! { "UNL-SACHEN-8259D", 0, 0, CHRRAM_0, SACHEN_8259D}, { "UNL-SA-72007", 0, 0, CHRRAM_0, SACHEN_SA72007}, { "UNL-SA-72008", 0, 0, CHRRAM_0, SACHEN_SA72008}, { "UNL-SA-0037", 0, 0, CHRRAM_0, SACHEN_SA0037}, { "UNL-SA-0036", 0, 0, CHRRAM_0, SACHEN_SA0036}, { "UNL-SA-9602B", 0, 0, CHRRAM_0, SACHEN_SA9602B}, { "UNL-SACHEN-8259A", 0, 0, CHRRAM_0, SACHEN_8259A}, { "UNL-SACHEN-8259B", 0, 0, CHRRAM_0, SACHEN_8259B}, { "BMC-190IN1", 0, 0, CHRRAM_0, BMC_190IN1}, { "BMC-64IN1NOREPEAT", 0, 0, CHRRAM_0, BMC_64IN1NR}, //UNIF only! { "BMC-A65AS", 0, 0, CHRRAM_8, BMC_A65AS}, //UNIF only! { "BMC-GS-2004", 0, 0, CHRRAM_8, RCM_GS2004}, //UNIF only! { "BMC-GS-2013", 0, 0, CHRRAM_8, RCM_GS2013}, //UNIF only! { "BMC-NOVELDIAMOND9999999IN1", 0, 0, CHRRAM_0, BMC_NOVEL1}, { "BMC-SUPER24IN1SC03", 8, 0, CHRRAM_8, BMC_S24IN1SC03}, { "BMC-SUPERHIK8IN1", 8, 0, CHRRAM_0, BMC_HIK8IN1}, { "BMC-T-262", 0, 0, CHRRAM_8, BMC_T262}, //UNIF only! { "BMC-WS", 0, 0, CHRRAM_0, BMC_WS}, //UNIF only! { "BMC-N625092", 0, 0, CHRRAM_0, UNL_N625092}, // below are boards which are not yet supported, but are used by some UNIF files. they are here as a reminder to what is missing to be added { "UNL-TEK90", 0, 0, CHRRAM_0, JYCOMPANY_A}, // JY Company A (is TEK90 the real PCB name?) { "UNL-KS7017", 0, 0, CHRRAM_0, KAISER_KS7017}, { "UNL-KS7032", 0, 0, CHRRAM_0, KAISER_KS7032}, // mapper 142 { "UNL-603-5052", 0, 0, CHRRAM_0, UNL_603_5052}, // mapper 238? { "UNL-EDU2000", 32, 0, CHRRAM_8, UNL_EDU2K}, { "UNL-H2288", 0, 0, CHRRAM_0, UNL_H2288}, // mapper 123 { "UNL-SHERO", 0, 0, CHRRAM_8, SACHEN_SHERO}, { "UNL-YOKO", 0, 0, CHRRAM_0, YOKO_BOARD}, // similar to mapper 83, but not the same { "UNL-FS304", 0, 8, CHRRAM_8, WAIXING_FS304}, // used in Zelda 3 by Waixing { "UNL-43272", 0, 0, CHRRAM_0, UNL_43272}, // used in Gaau Hok Gwong Cheung { "BTL-MARIO1-MALEE2", 0, 0, CHRRAM_0, UNL_MMALEE}, // mapper 55? { "BMC-FK23C", 0, 0, CHRRAM_0, BMC_FK23C}, { "BMC-FK23CA", 0, 0, CHRRAM_0, BMC_FK23CA}, { "BMC-GHOSTBUSTERS63IN1", 0, 0, CHRRAM_8, BMC_G63IN1 }, { "BMC-BS-5", 0, 0, CHRRAM_0, BMC_BENSHIENG}, { "BMC-810544-C-A1", 0, 0, CHRRAM_0, BMC_810544}, { "BMC-411120-C", 0, 0, CHRRAM_0, BMC_411120C}, { "BMC-8157", 0, 0, CHRRAM_8, BMC_8157}, { "BMC-830118C", 0, 0, CHRRAM_0, BMC_830118C}, { "BMC-D1038", 0, 0, CHRRAM_0, BMC_VT5201}, // mapper 60? { "BMC-SUPERVISION16IN1", 0, 0, CHRRAM_0, SVISION16_BOARD}, // mapper 53 { "BMC-NTD-03", 0, 0, CHRRAM_0, BMC_NTD_03}, { "UNL-AC08", 0, 0, CHRRAM_0, UNL_AC08}, { "UNL-BB", 0, 0, CHRRAM_0, UNL_BB}, { "UNL-LH32", 0, 0, CHRRAM_0, UNL_LH32}, { "UNL-LH53", 0, 0, CHRRAM_0, UNL_LH53}, { "BMC-G-146", 0, 0, CHRRAM_0, BMC_G146}, { "BMC-11160", 0, 0, CHRRAM_0, BMC_11160}, { "UNL-MALISB", 0, 0, CHRRAM_0, UNL_MALISB}, { "UNL-TF1201", 0, 0, CHRRAM_0, UNL_TF1201}, { "BMC-12-IN-1", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, { "BMC-70IN1", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // mapper 236? { "BMC-70IN1B", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // mapper 236? { "BMC-42IN1RESETSWITCH", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // mapper 60? { "PEC-586", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, { "UNL-DANCE", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, { "UNL-DRIPGAME", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // [by Quietust - we need more info] { "UNL-CITYFIGHT", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, { "UNL-OneBus", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, { "UNL-DANCE2000", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD} }; const unif *nes_unif_lookup( const char *board ) { int i; for (i = 0; i < ARRAY_LENGTH(unif_list); i++) { if (!mame_stricmp(unif_list[i].board, board)) return &unif_list[i]; } return NULL; } /************************************************************* unif_mapr_setup setup the board specific variables (wram, nvwram, pcb_id etc.) for a given board (after reading the MAPR chunk of the UNIF file) *************************************************************/ void unif_mapr_setup( const char *board, int *pcb_id, int *battery, int *prgram, int *vram_chunks ) { const unif *unif_board = nes_unif_lookup(board); if (unif_board == NULL) fatalerror("Unknown UNIF board %s.\n", board); *pcb_id = unif_board->board_idx; *battery = unif_board->nvwram; // we should implement battery banks based on the size of this... *prgram = unif_board->wram; // we should implement WRAM banks based on the size of this... if (unif_board->chrram <= CHRRAM_8) *vram_chunks = 1; else if (unif_board->chrram == CHRRAM_16) *vram_chunks = 2; else if (unif_board->chrram == CHRRAM_32) *vram_chunks = 4; } /************************************************************* call_load_unif *************************************************************/ void nes_cart_slot_device::call_load_unif() { UINT32 vram_size = 0, prgram_size = 0, battery_size = 0, mapper_sram_size = 0; // SETUP step 1: running through the file and getting PRG, VROM sizes UINT32 unif_ver = 0, chunk_length = 0, read_length = 0x20; UINT32 prg_start = 0, chr_start = 0; UINT32 size = length(), prg_size = 0, vrom_size = 0; UINT8 buffer[4], mirror = 0; char magic2[4]; char unif_mapr[32]; // here we should store MAPR chunks bool mapr_chunk_found = FALSE, small_prg = FALSE; // allocate space to temporarily store PRG & CHR banks UINT8 *temp_prg = auto_alloc_array(machine(), UINT8, 256 * 0x4000); UINT8 *temp_chr = auto_alloc_array(machine(), UINT8, 256 * 0x2000); UINT8 temp_byte = 0; fseek(4, SEEK_SET); fread(&buffer, 4); unif_ver = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); logerror("Loaded game in UNIF format, version %d\n", unif_ver); do { fseek(read_length, SEEK_SET); memset(magic2, '\0', sizeof(magic2)); fread(&magic2, 4); /* We first run through the whole image to find a [MAPR] chunk. This is needed because, unfortunately, the MAPR chunk is not always the first chunk (see Super 24-in-1). When such a chunk is found, we set mapr_chunk_found=1 and we go back to load other chunks! */ if (!mapr_chunk_found) { if ((magic2[0] == 'M') && (magic2[1] == 'A') && (magic2[2] == 'P') && (magic2[3] == 'R')) { mapr_chunk_found = TRUE; logerror("[MAPR] chunk found: "); fread(&buffer, 4); chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); if (chunk_length <= 0x20) fread(&unif_mapr, chunk_length); logerror("%s\n", unif_mapr); /* now that we found the MAPR chunk, we can go back to load other chunks */ fseek(0x20, SEEK_SET); read_length = 0x20; } else { logerror("Skip this chunk. We need a [MAPR] chunk before anything else.\n"); fread(&buffer, 4); chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); read_length += (chunk_length + 8); } } else { /* What kind of chunk do we have here? */ if ((magic2[0] == 'M') && (magic2[1] == 'A') && (magic2[2] == 'P') && (magic2[3] == 'R')) { /* The [MAPR] chunk has already been read, so we skip it */ /* TO DO: it would be nice to check if more than one MAPR chunk is present */ logerror("[MAPR] chunk found (in the 2nd run). Already loaded.\n"); fread(&buffer, 4); chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); read_length += (chunk_length + 8); } else if ((magic2[0] == 'R') && (magic2[1] == 'E') && (magic2[2] == 'A') && (magic2[3] == 'D')) { logerror("[READ] chunk found. No support yet.\n"); fread(&buffer, 4); chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); read_length += (chunk_length + 8); } else if ((magic2[0] == 'N') && (magic2[1] == 'A') && (magic2[2] == 'M') && (magic2[3] == 'E')) { logerror("[NAME] chunk found. No support yet.\n"); fread(&buffer, 4); chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); read_length += (chunk_length + 8); } else if ((magic2[0] == 'W') && (magic2[1] == 'R') && (magic2[2] == 'T') && (magic2[3] == 'R')) { logerror("[WRTR] chunk found. No support yet.\n"); fread(&buffer, 4); chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); read_length += (chunk_length + 8); } else if ((magic2[0] == 'T') && (magic2[1] == 'V') && (magic2[2] == 'C') && (magic2[3] == 'I')) { logerror("[TVCI] chunk found.\n"); fread(&buffer, 4); chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); fread(&temp_byte, 1); logerror("Television Standard : %s\n", (temp_byte == 0) ? "NTSC" : (temp_byte == 1) ? "PAL" : "Does not matter"); read_length += (chunk_length + 8); } else if ((magic2[0] == 'T') && (magic2[1] == 'V') && (magic2[2] == 'S') && (magic2[3] == 'C')) // is this the same as TVCI?? { logerror("[TVSC] chunk found. No support yet.\n"); fread(&buffer, 4); chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); read_length += (chunk_length + 8); } else if ((magic2[0] == 'D') && (magic2[1] == 'I') && (magic2[2] == 'N') && (magic2[3] == 'F')) { logerror("[DINF] chunk found. No support yet.\n"); fread(&buffer, 4); chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); read_length += (chunk_length + 8); } else if ((magic2[0] == 'C') && (magic2[1] == 'T') && (magic2[2] == 'R') && (magic2[3] == 'L')) { logerror("[CTRL] chunk found. No support yet.\n"); fread(&buffer, 4); chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); read_length += (chunk_length + 8); } else if ((magic2[0] == 'B') && (magic2[1] == 'A') && (magic2[2] == 'T') && (magic2[3] == 'R')) { logerror("[BATR] chunk found. No support yet.\n"); fread(&buffer, 4); chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); read_length += (chunk_length + 8); } else if ((magic2[0] == 'V') && (magic2[1] == 'R') && (magic2[2] == 'O') && (magic2[3] == 'R')) { logerror("[VROR] chunk found. No support yet.\n"); fread(&buffer, 4); chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); read_length += (chunk_length + 8); } else if ((magic2[0] == 'M') && (magic2[1] == 'I') && (magic2[2] == 'R') && (magic2[3] == 'R')) { logerror("[MIRR] chunk found.\n"); fread(&buffer, 4); chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); fread(&mirror, 1); read_length += (chunk_length + 8); } else if ((magic2[0] == 'P') && (magic2[1] == 'C') && (magic2[2] == 'K')) { logerror("[PCK%c] chunk found. No support yet.\n", magic2[3]); fread(&buffer, 4); chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); read_length += (chunk_length + 8); } else if ((magic2[0] == 'C') && (magic2[1] == 'C') && (magic2[2] == 'K')) { logerror("[CCK%c] chunk found. No support yet.\n", magic2[3]); fread(&buffer, 4); chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); read_length += (chunk_length + 8); } else if ((magic2[0] == 'P') && (magic2[1] == 'R') && (magic2[2] == 'G')) { logerror("[PRG%c] chunk found. ", magic2[3]); fread(&buffer, 4); chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); prg_size += chunk_length; if (chunk_length / 0x4000) logerror("It consists of %d 16K-blocks.\n", chunk_length / 0x4000); else { small_prg = TRUE; logerror("This chunk is smaller than 16K: the emulation might have issues. Please report this file to the MESS forums.\n"); } /* Read in the program chunks */ fread(&temp_prg[prg_start], chunk_length); prg_start += chunk_length; read_length += (chunk_length + 8); } else if ((magic2[0] == 'C') && (magic2[1] == 'H') && (magic2[2] == 'R')) { logerror("[CHR%c] chunk found. ", magic2[3]); fread(&buffer, 4); chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); vrom_size += chunk_length; logerror("It consists of %d 8K-blocks.\n", chunk_length / 0x2000); /* Read in the vrom chunks */ fread(&temp_chr[chr_start], chunk_length); chr_start += chunk_length; read_length += (chunk_length + 8); } else { logerror("Unsupported UNIF chunk or corrupted header. Please report the problem at MESS Board.\n"); read_length = size; } } } while (size > read_length); if (!mapr_chunk_found) { auto_free(machine(), temp_prg); auto_free(machine(), temp_chr); fatalerror("UNIF should have a [MAPR] chunk to work. Check if your image has been corrupted\n"); } if (!prg_start) { auto_free(machine(), temp_prg); auto_free(machine(), temp_chr); fatalerror("No PRG found. Please report the problem at MESS Board.\n"); } // SETUP step 2: getting PCB and other settings int pcb_id = 0, battery = 0, prgram = 0, vram_chunks = 0; unif_mapr_setup(unif_mapr, &pcb_id, &battery, &prgram, &vram_chunks); // SETUP step 3: storing the info needed for emulation m_pcb_id = pcb_id; if (battery) battery_size = NES_BATTERY_SIZE; // we should allow for smaller battery! prgram_size = prgram * 0x2000; vram_size = vram_chunks * 0x2000; m_cart->set_four_screen_vram(FALSE); switch (mirror) { case 0: // Horizontal Mirroring (Hard Wired) m_cart->set_mirroring(PPU_MIRROR_HORZ); break; case 1: // Vertical Mirroring (Hard Wired) m_cart->set_mirroring(PPU_MIRROR_VERT); break; case 2: // Mirror All Pages From $2000 (Hard Wired) m_cart->set_mirroring(PPU_MIRROR_LOW); break; case 3: // Mirror All Pages From $2400 (Hard Wired) m_cart->set_mirroring(PPU_MIRROR_HIGH); break; case 4: // Four Screens of VRAM (Hard Wired) m_cart->set_four_screen_vram(TRUE); m_cart->set_mirroring(PPU_MIRROR_4SCREEN); break; case 5: // Mirroring Controlled By Mapper Hardware logerror("Mirroring handled by the board hardware.\n"); // default to horizontal at start m_cart->set_mirroring(PPU_MIRROR_HORZ); break; default: logerror("Undocumented mirroring value.\n"); // default to horizontal m_cart->set_mirroring(PPU_MIRROR_HORZ); break; } // SETUP step 4: logging what we have found logerror("-- Board %s\n", unif_mapr); logerror("-- PRG 0x%x (%d x 16k chunks)\n", prg_size, prg_size / 0x4000); logerror("-- VROM 0x%x (%d x 8k chunks)\n", vrom_size, vrom_size / 0x2000); logerror("-- VRAM 0x%x (%d x 8k chunks)\n", vram_size, vram_size / 0x2000); // SETUP steps 5/6: allocate pointers for PRG/VROM and load the data! if (prg_size == 0x4000) { m_cart->prg_alloc(machine(), 0x8000); memcpy(m_cart->get_prg_base(), temp_prg, 0x4000); memcpy(m_cart->get_prg_base() + 0x4000, m_cart->get_prg_base(), 0x4000); } else { m_cart->prg_alloc(machine(), prg_size); memcpy(m_cart->get_prg_base(), temp_prg, prg_size); } if (small_prg) // This is not supported yet, so warn users about this mame_printf_error("Loaded UNIF file with non-16k PRG chunk. This is not supported in MESS yet."); if (vrom_size) { m_cart->vrom_alloc(machine(), vrom_size); memcpy(m_cart->get_vrom_base(), temp_chr, vrom_size); } #if SPLIT_PRG { FILE *prgout; char outname[255]; sprintf(outname, "%s.prg", filename()); prgout = fopen(outname, "wb"); if (prgout) { fwrite(m_cart->get_prg_base(), 1, 0x4000 * m_cart->get_prg_size(), prgout); mame_printf_error("Created PRG chunk\n"); } fclose(prgout); } #endif #if SPLIT_CHR if (state->m_chr_chunks > 0) { FILE *chrout; char outname[255]; sprintf(outname, "%s.chr", filename()); chrout= fopen(outname, "wb"); if (chrout) { fwrite(m_cart->get_vrom_base(), 1, m_cart->get_vrom_size(), chrout); mame_printf_error("Created CHR chunk\n"); } fclose(chrout); } #endif // free the temporary copy of PRG/CHR auto_free(machine(), temp_prg); auto_free(machine(), temp_chr); // SETUP steps 7: allocate the remaining pointer, when needed if (vram_size) m_cart->vram_alloc(machine(), vram_size); if (prgram_size) m_cart->prgram_alloc(machine(), prgram_size); // Attempt to load a battery file for this ROM // A few boards have internal RAM with a battery (MMC6, Taito X1-005 & X1-017, etc.) if (battery_size || mapper_sram_size) { UINT32 tot_size = battery_size + mapper_sram_size; UINT8 *temp_nvram = auto_alloc_array(machine(), UINT8, tot_size); battery_load(temp_nvram, tot_size, 0x00); if (battery_size) { m_cart->battery_alloc(machine(), battery_size); memcpy(m_cart->get_battery_base(), temp_nvram, battery_size); } if (mapper_sram_size) memcpy(m_cart->get_mapper_sram_base(), temp_nvram + battery_size, mapper_sram_size); if (temp_nvram) auto_free(machine(), temp_nvram); } logerror("UNIF support is only very preliminary.\n"); } const char * nes_cart_slot_device::get_default_card_unif(UINT8 *ROM, UINT32 len) { UINT32 chunk_length = 0, read_length = 0x20; int pcb_id = 0, battery = 0, prgram = 0, vram_chunks = 0; char unif_mapr[32]; do { if ((ROM[read_length + 0] == 'M') && (ROM[read_length + 1] == 'A') && (ROM[read_length + 2] == 'P') && (ROM[read_length + 3] == 'R')) { chunk_length = ROM[read_length + 4] | (ROM[read_length + 5] << 8) | (ROM[read_length + 6] << 16) | (ROM[read_length + 7] << 24); if (chunk_length <= 0x20) memcpy(unif_mapr, ROM + read_length + 8, chunk_length); read_length += (chunk_length + 8); } else { chunk_length = ROM[read_length + 4] | (ROM[read_length + 5] << 8) | (ROM[read_length + 6] << 16) | (ROM[read_length + 7] << 24); read_length += (chunk_length + 8); } } while (len > read_length); unif_mapr_setup(unif_mapr, &pcb_id, &battery, &prgram, &vram_chunks); return nes_get_slot(pcb_id); }