diff --git a/src/boards/unrom512.c b/src/boards/unrom512.c index 59ac51d..5e703b0 100644 --- a/src/boards/unrom512.c +++ b/src/boards/unrom512.c @@ -217,9 +217,9 @@ void UNROM512_Init(CartInfo *info) { flash_bank = 0; flash_save = info->battery; - if (info->vram_size == 8192) + if (info->chrRam == 8192) chrram_mask = 0; - else if (info->vram_size == 16384) + else if (info->chrRam == 16384) chrram_mask = 0x20; else chrram_mask = 0x60; @@ -236,7 +236,7 @@ void UNROM512_Init(CartInfo *info) { SetupCartMirroring(MI_0, 0, NULL); break; case 3: /* hard four screen, last 8k of 32k RAM (flags: 4-screen + vertical) */ - SetupCartMirroring(4, 1, VROM + (info->vram_size - 8192)); + SetupCartMirroring(4, 1, VROM + (info->chrRam - 8192)); break; } bus_conflict = !info->battery; diff --git a/src/cart.h b/src/cart.h index 16ab243..66f3e83 100644 --- a/src/cart.h +++ b/src/cart.h @@ -10,6 +10,7 @@ typedef struct { uint32 SaveGameLen[4]; /* How much memory to save/load. */ /* Set by iNES/UNIF loading code. */ + int iNES2; /* iNES version */ int mapper; /* mapper used */ int submapper; /* submapper used */ /* TODO: */ int mirror; /* As set in the header or chunk. @@ -19,7 +20,12 @@ typedef struct { * set to mapper 4. */ int battery; /* Presence of an actual battery. */ - int vram_size; + int prgRam; /* prg ram size (volatile) */ + int chrRam; /* chr ram size (volatile) */ + int prgRam_battery; /* prg ram size (non-volatile or battery backed) */ + int chrRam_battery; /* chr ram size (non-volatile or battery backed) */ + int region; /* video system timing (ntsc, pal, dendy */ + uint8 MD5[16]; uint32 CRC32; /* Should be set by the iNES/UNIF loading * code, used by mapper/board code, maybe diff --git a/src/ines.c b/src/ines.c index 656337a..68371f2 100644 --- a/src/ines.c +++ b/src/ines.c @@ -57,7 +57,9 @@ uint32 VROM_size = 0; static int CHRRAMSize = -1; static int iNES_Init(int num); +static int iNES2 = 0; static int MapperNo = 0; +static int subMapper = 0; static DECLFR(TrainerRead) { return(trainerpoo[A & 0x1FF]); @@ -376,7 +378,7 @@ static void CheckHInfo(void) { if (tofix & 8) strcat(gigastr, "This game should not have any CHR ROM. "); strcat(gigastr, "\n"); - FCEU_printf("%s", gigastr); + FCEU_printf("%s\n", gigastr); } } @@ -661,14 +663,19 @@ static BMAPPINGLocal bmap[] = { int iNESLoad(const char *name, FCEUFILE *fp) { struct md5_context md5; - char* mappername; - uint32 mappertest; + char* mappername = NULL; + uint32 filesize = fp->fp->size; + uint32 mappertest = 0; + uint32 prgRom = 0; + uint32 chrRom = 0; if (FCEU_fread(&head, 1, 16, fp) != 16) return 0; + filesize -= 16; /* remove header size from total size */ + if (memcmp(&head, "NES\x1a", 4)) { - FCEU_PrintError("Missing header or invalid iNES format file!\n"); + FCEU_PrintError("Not an iNES file!\n"); return 0; } @@ -689,20 +696,51 @@ int iNESLoad(const char *name, FCEUFILE *fp) { memset((char*)(&head) + 0xA, 0, 0x6); } - MapperNo = (head.ROM_type >> 4); - MapperNo |= (head.ROM_type2 & 0xF0); - if (head.ROM_type & 8) { - Mirroring = 2; - } else - Mirroring = (head.ROM_type & 1); + Mirroring = 0; + ROM_size = 0; + VROM_size = 0; + iNES2 = 0; + MapperNo = 0; + subMapper = 0; - if (!head.ROM_size) - ROM_size = 256; - else - ROM_size = uppow2(head.ROM_size); + MapperNo = (head.ROM_type >> 4) | (head.ROM_type2 & 0xF0); + Mirroring = (head.ROM_type & 8) ? 2 : (head.ROM_type & 1); + prgRom = head.ROM_size; + chrRom = head.VROM_size; - VROM_size = uppow2(head.VROM_size); + if ((head.ROM_type2 & 0x0C) == 0x08) { + iNES2 = 1; + MapperNo |= ((uint32)head.ROM_type3 << 8) & 0xF00; + prgRom |= ((uint32)head.upper_PRG_CHR_size << 8) & 0xF00; + chrRom |= ((uint32)head.upper_PRG_CHR_size << 4) & 0xF00; + subMapper = head.ROM_type3 >> 4 & 0x0F; + iNESCart.prgRam = (head.PRGRAM_size & 0x0F) ? (64 << (head.PRGRAM_size & 0x0F)) : 0; + iNESCart.chrRam = (head.CHRRAM_size & 0x0F) ? (64 << (head.CHRRAM_size & 0x0F)) : 0; + iNESCart.prgRam_battery = (head.PRGRAM_size & 0xF0) ? (64 << ((head.PRGRAM_size & 0xF0) >> 4)) : 0; + iNESCart.chrRam_battery = (head.CHRRAM_size & 0xF0) ? (64 << ((head.CHRRAM_size & 0xF0) >> 4)) : 0; + iNESCart.region = head.Region; + } else { + if (!prgRom) + prgRom = 256; + } + + if (head.ROM_type & 4) { /* Trainer */ + trainerpoo = (uint8*)FCEU_gmalloc(512); + FCEU_fread(trainerpoo, 512, 1, fp); + filesize -= 512; + } + + if (((prgRom * 0x4000) + (chrRom * 0x2000)) > filesize) { + FCEU_PrintError(" File length is too short to contain all data reported from header by %llu\n", ((prgRom * 0x4000) + (chrRom * 0x2000)) - filesize); + return 0; + } else if (((prgRom * 0x4000) + (chrRom * 0x2000)) < filesize) + FCEU_PrintError(" File contains %llu bytes of unused data\n", filesize - ((prgRom * 0x4000) + (chrRom * 0x2000))); + + ROM_size = uppow2(prgRom); + + if (chrRom) + VROM_size = uppow2(chrRom); if ((ROM = (uint8*)FCEU_malloc(ROM_size << 14)) == NULL) return 0; @@ -717,36 +755,23 @@ int iNESLoad(const char *name, FCEUFILE *fp) { memset(VROM, 0xFF, VROM_size << 13); } - if (head.ROM_type & 4) { /* Trainer */ - trainerpoo = (uint8*)FCEU_gmalloc(512); - FCEU_fread(trainerpoo, 512, 1, fp); - } - ResetCartMapping(); ResetExState(0, 0); SetupCartPRGMapping(0, ROM, ROM_size << 14, 0); - if (head.ROM_size) - FCEU_fread(ROM, 0x4000, head.ROM_size, fp); - else - FCEU_fread(ROM, 0x4000, ROM_size, fp); + FCEU_fread(ROM, 0x4000, prgRom, fp); if (VROM_size) - FCEU_fread(VROM, 0x2000, VROM_size, fp); + FCEU_fread(VROM, 0x2000, chrRom, fp); md5_starts(&md5); - if (head.ROM_size) { - md5_update(&md5, ROM, head.ROM_size << 14); - iNESGameCRC32 = CalcCRC32(0, ROM, head.ROM_size << 14); - } else { - md5_update(&md5, ROM, ROM_size << 14); - iNESGameCRC32 = CalcCRC32(0, ROM, ROM_size << 14); - } + md5_update(&md5, ROM, prgRom << 14); + iNESGameCRC32 = CalcCRC32(0, ROM, prgRom << 14); if (VROM_size) { - iNESGameCRC32 = CalcCRC32(iNESGameCRC32, VROM, VROM_size << 13); - md5_update(&md5, VROM, VROM_size << 13); + iNESGameCRC32 = CalcCRC32(iNESGameCRC32, VROM, chrRom << 13); + md5_update(&md5, VROM, chrRom << 13); } md5_finish(&md5, iNESCart.MD5); memcpy(&GameInfo->MD5, &iNESCart.MD5, sizeof(iNESCart.MD5)); @@ -755,14 +780,7 @@ int iNESLoad(const char *name, FCEUFILE *fp) { SetInput(); CheckHInfo(); - mappername = "Not Listed"; - for (mappertest = 0; mappertest < (sizeof bmap / sizeof bmap[0]) - 1; mappertest++) { - if (bmap[mappertest].number == MapperNo) { - mappername = (char*)bmap[mappertest].name; - break; - } - } { int x; uint64 partialmd5 = 0; @@ -787,43 +805,92 @@ int iNESLoad(const char *name, FCEUFILE *fp) { else SetupCartMirroring(Mirroring & 1, (Mirroring & 4) >> 2, 0); + iNESCart.iNES2 = iNES2; + iNESCart.mapper = MapperNo; + iNESCart.submapper = subMapper; iNESCart.battery = (head.ROM_type & 2) ? 1 : 0; iNESCart.mirror = Mirroring; + mappername = "Not Listed"; + + for (mappertest = 0; mappertest < (sizeof bmap / sizeof bmap[0]) - 1; mappertest++) { + if (bmap[mappertest].number == MapperNo) { + mappername = (char*)bmap[mappertest].name; + break; + } + } + + if (iNES2) FCEU_printf(" NES 2.0 extended iNES.\n"); FCEU_printf(" ROM CRC32: 0x%08lx\n", iNESGameCRC32); FCEU_printf(" ROM MD5: 0x%s\n", md5_asciistr(iNESCart.MD5)); - FCEU_printf(" PRG ROM: %3d x 16KiB\n", head.ROM_size ? head.ROM_size : 256); - FCEU_printf(" CHR ROM: %3d x 8KiB\n", head.VROM_size); + FCEU_printf(" PRG ROM: %3d x 16KiB\n", prgRom); + FCEU_printf(" CHR ROM: %3d x 8KiB\n", chrRom); - if (!iNES_Init(MapperNo)) - FCEU_PrintError("iNES mapper #%d is not supported at all.", MapperNo); - iNESCart.mapper = MapperNo; + if (iNES2) { + const char *tv_region[] = { "NTSC", "PAL", "Multi-region", "Dendy" }; + unsigned PRGRAM = iNESCart.prgRam + iNESCart.prgRam_battery; + unsigned CHRRAM = iNESCart.chrRam + iNESCart.chrRam_battery; - FCEU_printf(" \n"); - FCEU_printf(" Mapper #: %3d\n", MapperNo); - FCEU_printf(" Mapper name: %s\n", mappername); - FCEU_printf(" Mirroring: %s\n", Mirroring == 2 ? "None (Four-screen)" : Mirroring ? "Vertical" : "Horizontal"); - FCEU_printf(" Battery-backed: %s\n", (head.ROM_type & 2) ? "Yes" : "No"); - FCEU_printf(" Trained: %s\n", (head.ROM_type & 4) ? "Yes" : "No"); + FCEU_printf(" Mapper #: %3d\n", MapperNo); + FCEU_printf(" Sub Mapper #: %3d\n", subMapper); + FCEU_printf(" Mapper name: %s\n", mappername); + if (PRGRAM || CHRRAM) { + FCEU_printf(" PRG RAM: %d KiB\n", PRGRAM / 1024); + FCEU_printf(" CHR RAM: %d KiB\n", CHRRAM / 1024); + if (head.ROM_type & 0x02) { + FCEU_printf(" PRG RAM backed by battery: %d KiB\n", iNESCart.prgRam_battery / 1024); + FCEU_printf(" CHR RAM backed by battery: %d KiB\n", iNESCart.chrRam_battery / 1024); + } + } + FCEU_printf(" Mirroring: %s\n", Mirroring == 2 ? "None (Four-screen)" : Mirroring ? "Vertical" : "Horizontal"); + FCEU_printf(" System: %s\n", tv_region[(iNESCart.region & 3)]); + FCEU_printf(" Trained: %s\n", (head.ROM_type & 4) ? "Yes" : "No"); + } else { + FCEU_printf(" Mapper #: %3d\n", MapperNo); + FCEU_printf(" Mapper name: %s\n", mappername); + FCEU_printf(" Mirroring: %s\n", Mirroring == 2 ? "None (Four-screen)" : Mirroring ? "Vertical" : "Horizontal"); + FCEU_printf(" Battery-backed: %s\n", (head.ROM_type & 2) ? "Yes" : "No"); + FCEU_printf(" Trained: %s\n", (head.ROM_type & 4) ? "Yes" : "No"); + } + + if (!iNES_Init(MapperNo)) { + FCEU_printf("\n"); + FCEU_PrintError(" iNES mapper #%d is not supported at all.\n", MapperNo); + return 0; + } GameInterface = iNESGI; - FCEU_printf("\n"); - if (strstr(name, "(E)") || strstr(name, "(e)") - || strstr(name, "(Europe)") || strstr(name, "(PAL)") - || strstr(name, "(F)") || strstr(name, "(f)") - || strstr(name, "(G)") || strstr(name, "(g)") - || strstr(name, "(I)") || strstr(name, "(i)") - || strstr(name, "(S)") || strstr(name, "(s)") - || strstr(name, "(France)") || strstr(name, "(Germany)") - || strstr(name, "(Italy)") || strstr(name, "(Spain)") - || strstr(name, "(Sweden)") || strstr(name, "(Sw)") - || strstr(name, "(Australia)") || strstr(name, "(A)") - || strstr(name, "(a)")) { - FCEUI_SetVidSystem(1); + if (iNES2) { + switch (iNESCart.region & 0x03) { + /* 0: RP2C02 ("NTSC NES") + * 1: RP2C07 ("Licensed PAL NES") + * 2: Multiple-region + * 3: UMC 6527P ("Dendy") + */ + case 0: case 2: FCEUI_SetVidSystem(0); break; + case 1: FCEUI_SetVidSystem(1); break; + case 3: dendy = 1; FCEUI_SetVidSystem(0); break; + } + } else { + if (strstr(name, "(E)") || strstr(name, "(e)") || + strstr(name, "(Europe)") || strstr(name, "(PAL)") || + strstr(name, "(F)") || strstr(name, "(f)") || + strstr(name, "(G)") || strstr(name, "(g)") || + strstr(name, "(I)") || strstr(name, "(i)") || + strstr(name, "(S)") || strstr(name, "(s)") || + strstr(name, "(France)") || strstr(name, "(Germany)") || + strstr(name, "(Italy)") || strstr(name, "(Spain)") || + strstr(name, "(Sweden)") || strstr(name, "(Sw)") || + strstr(name, "(Australia)") || strstr(name, "(A)") || + strstr(name, "(a)")) { + iNESCart.region = 1; + FCEUI_SetVidSystem(1); + } else { + iNESCart.region = 0; + FCEUI_SetVidSystem(0); + } } - else - FCEUI_SetVidSystem(0); return 1; } @@ -840,24 +907,30 @@ static int iNES_Init(int num) { if (num == tmp->number) { UNIFchrrama = 0; /* need here for compatibility with UNIF mapper code */ if (!VROM_size) { - switch (num) { /* FIXME, mapper or game data base with the board parameters and ROM/RAM sizes */ - case 13: CHRRAMSize = 16 * 1024; break; - case 6: - case 28: - case 29: - case 30: - case 45: - case 96: CHRRAMSize = 32 * 1024; break; - case 176: CHRRAMSize = 128 * 1024; break; - default: CHRRAMSize = 8 * 1024; break; + if (iNESCart.iNES2) { + CHRRAMSize = iNESCart.chrRam + iNESCart.chrRam_battery; + } else { + switch (num) { /* FIXME, mapper or game data base with the board parameters and ROM/RAM sizes */ + case 13: CHRRAMSize = 16 * 1024; break; + case 6: + case 28: + case 29: + case 30: + case 45: + case 96: CHRRAMSize = 32 * 1024; break; + case 176: CHRRAMSize = 128 * 1024; break; + default: CHRRAMSize = 8 * 1024; break; + } + iNESCart.chrRam = CHRRAMSize; + FCEU_printf(" CHR-RAM: %3d KiB\n", CHRRAMSize / 1024); + } + if (CHRRAMSize) { /* TODO: CHR-RAM are sometimes handled in mappers e.g. MMC1 using submapper 1/2/4 and CHR-RAM can be zero here */ + if ((VROM = (uint8*)malloc(CHRRAMSize)) == NULL) return 0; + FCEU_MemoryRand(VROM, CHRRAMSize); + UNIFchrrama = VROM; + SetupCartCHRMapping(0, VROM, CHRRAMSize, 1); + AddExState(VROM, CHRRAMSize, 0, "CHRR"); } - iNESCart.vram_size = CHRRAMSize; - if ((VROM = (uint8*)malloc(CHRRAMSize)) == NULL) return 0; - FCEU_MemoryRand(VROM, CHRRAMSize); - UNIFchrrama = VROM; - SetupCartCHRMapping(0, VROM, CHRRAMSize, 1); - AddExState(VROM, CHRRAMSize, 0, "CHRR"); - FCEU_printf(" CHR RAM: %3d x 1KiB\n", CHRRAMSize / 1024); } if (head.ROM_type & 8) AddExState(ExtraNTARAM, 2048, 0, "EXNR"); diff --git a/src/ines.h b/src/ines.h index 1d6dee7..2b29b29 100644 --- a/src/ines.h +++ b/src/ines.h @@ -28,7 +28,14 @@ typedef struct { uint8 VROM_size; uint8 ROM_type; uint8 ROM_type2; - uint8 reserve[8]; + uint8 ROM_type3; + uint8 upper_PRG_CHR_size; + uint8 PRGRAM_size; + uint8 CHRRAM_size; + uint8 Region; + uint8 VS_hardware; + uint8 MiscRoms; + uint8 ExpDevice; } iNES_HEADER; extern uint8 *ROM; diff --git a/src/unif.c b/src/unif.c index 6072129..ce3c61a 100644 --- a/src/unif.c +++ b/src/unif.c @@ -353,7 +353,7 @@ static void CheckHashInfo(void) { FCEU_PrintError(" For now, the information will be corrected in RAM.\n"); if (unif_db[x].boardname != NULL && strcmp((char*)unif_db[x].boardname, (char*)sboardname) != 0) { FCEU_printf(" Boardname should be set to %s\n", unif_db[x].boardname); - sboardname = unif_db[x].boardname; + sboardname = (uint8*)unif_db[x].boardname; } if (unif_db[x].submapper >= 0 && unif_db[x].submapper != submapper) { FCEU_PrintError(" Submapper should be set to %d\n", unif_db[x].submapper);