diff --git a/src/drivers/Qt/iNesHeaderEditor.cpp b/src/drivers/Qt/iNesHeaderEditor.cpp index 47b435b6..0dcb93e1 100644 --- a/src/drivers/Qt/iNesHeaderEditor.cpp +++ b/src/drivers/Qt/iNesHeaderEditor.cpp @@ -1197,7 +1197,7 @@ void iNesHeaderEditor_t::setHeaderData(iNES_HEADER* header) } // Input Device: - int input = header->reserved[1] & 0x3F; + int input = header->expansion & 0x3F; for (i=0; icount(); i++) { if ( inputDevBox->itemData(i).toInt() == input ) @@ -1207,7 +1207,7 @@ void iNesHeaderEditor_t::setHeaderData(iNES_HEADER* header) } // Miscellaneous ROM Area(s) - sprintf(buf, "%d", header->reserved[0] & 3); + sprintf(buf, "%d", header->misc_roms & 3); miscRomsEdit->setText( tr(buf) ); // Trainer @@ -1920,7 +1920,7 @@ bool iNesHeaderEditor_t::WriteHeaderData(iNES_HEADER* header) int input = inputDevBox->itemData(idx).toInt(); if (input <= 0x3F) { - _header.reserved[1] |= input & 0x3F; + _header.expansion |= input & 0x3F; } else { @@ -1944,7 +1944,7 @@ bool iNesHeaderEditor_t::WriteHeaderData(iNES_HEADER* header) showErrorMsgWindow("Miscellaneous ROM(s) count has exceeded the limit of iNES 2.0 (3)"); return false; } - _header.reserved[0] |= misc_roms & 3; + _header.misc_roms |= misc_roms & 3; } // iNES 1.0 unofficial properties @@ -2022,7 +2022,7 @@ void iNesHeaderEditor_t::printHeader(iNES_HEADER* _header) printf("%02X ", _header->VRAM_size); printf("%02X ", _header->TV_system); printf("%02X ", _header->VS_hardware); - printf("%02X ", _header->reserved[0]); - printf("%02X\n", _header->reserved[1]); + printf("%02X ", _header->misc_roms); + printf("%02X\n", _header->expansion); } //---------------------------------------------------------------------------- diff --git a/src/drivers/Qt/main.h b/src/drivers/Qt/main.h index 35d5026d..b2e12911 100644 --- a/src/drivers/Qt/main.h +++ b/src/drivers/Qt/main.h @@ -29,12 +29,12 @@ extern int eoptions; #define EO_SUBASE 2 #define EO_CLIPSIDES 8 #define EO_SNAPNAME 16 -#define EO_FOURSCORE 32 #define EO_NOTHROTTLE 64 #define EO_GAMEGENIE 128 #define EO_PAL 256 #define EO_LOWPASS 512 #define EO_AUTOHIDE 1024 +#define EO_FOURSCORE 32768 // for compatibility with non-Qt extern int _sound; extern long soundrate; diff --git a/src/drivers/win/header_editor.cpp b/src/drivers/win/header_editor.cpp index 168a6170..aa2dce44 100644 --- a/src/drivers/win/header_editor.cpp +++ b/src/drivers/win/header_editor.cpp @@ -525,7 +525,7 @@ INT_PTR CALLBACK HeaderEditorProc(HWND hDlg, UINT uMsg, WPARAM wP, LPARAM lP) SetDlgItemText(hDlg, IDC_ROM_FILE_EDIT, LoadedRomFName); char textHeader[16 * 3]; - sprintf(textHeader, "%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", header->ID[0], header->ID[1], header->ID[2], header->ID[3], header->ROM_size, header->VROM_size, header->ROM_size, header->ROM_type2, header->ROM_type3, header->Upper_ROM_VROM_size, header->RAM_size, header->VRAM_size, header->TV_system, header->VS_hardware, header->reserved[0], header->reserved[1]); + sprintf(textHeader, "%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", header->ID[0], header->ID[1], header->ID[2], header->ID[3], header->ROM_size, header->VROM_size, header->ROM_size, header->ROM_type2, header->ROM_type3, header->Upper_ROM_VROM_size, header->RAM_size, header->VRAM_size, header->TV_system, header->VS_hardware, header->misc_roms, header->expansion); SetDlgItemText(hDlg, IDC_HEX_HEADER_EDIT, textHeader); hFont = (HFONT)SendMessage(hDlg, WM_GETFONT, 0, 0); @@ -602,7 +602,7 @@ INT_PTR CALLBACK HeaderEditorProc(HWND hDlg, UINT uMsg, WPARAM wP, LPARAM lP) case IDC_RESTORE_BUTTON: SetHeaderData(hDlg, header); char textHeader[16 * 3]; - sprintf(textHeader, "%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", header->ID[0], header->ID[1], header->ID[2], header->ID[3], header->ROM_size, header->VROM_size, header->ROM_size, header->ROM_type2, header->ROM_type3, header->Upper_ROM_VROM_size, header->RAM_size, header->VRAM_size, header->TV_system, header->VS_hardware, header->reserved[0], header->reserved[1]); + sprintf(textHeader, "%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", header->ID[0], header->ID[1], header->ID[2], header->ID[3], header->ROM_size, header->VROM_size, header->ROM_size, header->ROM_type2, header->ROM_type3, header->Upper_ROM_VROM_size, header->RAM_size, header->VRAM_size, header->TV_system, header->VS_hardware, header->misc_roms, header->expansion); SetDlgItemText(hDlg, IDC_HEX_HEADER_EDIT, textHeader); break; case IDSAVE: @@ -915,7 +915,7 @@ void SetHeaderData(HWND hwnd, iNES_HEADER* header) { } // Input Device: - int input = header->reserved[1] & 0x3F; + int input = header->expansion & 0x3F; if (SendDlgItemMessage(hwnd, IDC_INPUT_DEVICE_COMBO, CB_SETCURSEL, input, 0) == CB_ERR) { sprintf(buf, "$%02X", input); @@ -923,7 +923,7 @@ void SetHeaderData(HWND hwnd, iNES_HEADER* header) { } // Miscellaneous ROM Area(s) - sprintf(buf, "%d", header->reserved[0] & 3); + sprintf(buf, "%d", header->misc_roms & 3); SetDlgItemText(hwnd, IDC_MISCELLANEOUS_ROMS_EDIT, buf); // Trainer @@ -1578,7 +1578,7 @@ bool WriteHeaderData(HWND hwnd, iNES_HEADER* header) { int input; if (GetComboBoxListItemData(hwnd, IDC_INPUT_DEVICE_COMBO, &input, buf, header) && input <= 0x3F) - _header.reserved[1] |= input & 0x3F; + _header.expansion |= input & 0x3F; else { if (header) @@ -1625,7 +1625,7 @@ bool WriteHeaderData(HWND hwnd, iNES_HEADER* header) return false; } - _header.reserved[0] |= misc_roms & 3; + _header.misc_roms |= misc_roms & 3; } // iNES 1.0 unofficial properties @@ -1673,7 +1673,7 @@ bool WriteHeaderData(HWND hwnd, iNES_HEADER* header) memcpy(header, &_header, sizeof(iNES_HEADER)); else { - sprintf(buf, "%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", _header.ID[0], _header.ID[1], _header.ID[2], _header.ID[3], _header.ROM_size, _header.VROM_size, _header.ROM_type, _header.ROM_type2, _header.ROM_type3, _header.Upper_ROM_VROM_size, _header.RAM_size, _header.VRAM_size, _header.TV_system, _header.VS_hardware, _header.reserved[0], _header.reserved[1]); + sprintf(buf, "%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", _header.ID[0], _header.ID[1], _header.ID[2], _header.ID[3], _header.ROM_size, _header.VROM_size, _header.ROM_type, _header.ROM_type2, _header.ROM_type3, _header.Upper_ROM_VROM_size, _header.RAM_size, _header.VRAM_size, _header.TV_system, _header.VS_hardware, _header.misc_roms, _header.expansion); SetDlgItemText(hwnd, IDC_HEX_HEADER_EDIT, buf); } @@ -1834,7 +1834,7 @@ bool ShowINESFileBox(HWND parent, char* buf, iNES_HEADER* header) strcpy(filename, _filename); } char header_str[32]; - sprintf(header_str, " [%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X].nes", header->ROM_size, header->VROM_size, header->ROM_size, header->ROM_type2, header->ROM_type3, header->Upper_ROM_VROM_size, header->RAM_size, header->VRAM_size, header->TV_system, header->VS_hardware, header->reserved[0], header->reserved[1]); + sprintf(header_str, " [%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X].nes", header->ROM_size, header->VROM_size, header->ROM_size, header->ROM_type2, header->ROM_type3, header->Upper_ROM_VROM_size, header->RAM_size, header->VRAM_size, header->TV_system, header->VS_hardware, header->misc_roms, header->expansion); strcat(filename, header_str); strcpy(path, GetRomPath(true).c_str()); } diff --git a/src/git.h b/src/git.h index 6eca186d..b324fc3f 100644 --- a/src/git.h +++ b/src/git.h @@ -16,12 +16,34 @@ enum EGIV GIV_USER = 2, //What was set by FCEUI_SetVidSys(). }; +enum EGIPPU +{ + GIPPU_USER = 0, + GIPPU_RP2C04_0001 = 1, + GIPPU_RP2C04_0002 = 2, + GIPPU_RP2C04_0003 = 3, + GIPPU_RP2C04_0004 = 4, + GIPPU_RC2C03B = 5, + GIPPU_RC2C05_01 = 6, + GIPPU_RC2C05_02 = 7, + GIPPU_RC2C05_03 = 8, + GIPPU_RC2C05_04 = 9, +}; + +enum EGIVS +{ + EGIVS_NORMAL = 0, + EGIVS_RBI = 1, // RBI Baseball protection + EGIVS_TKO = 2, // TKO Boxing protection + EGIVS_XEVIOUS = 3, // Super Xevious protection +}; + enum ESIS { SIS_NONE = 0, SIS_DATACH = 1, SIS_NWC = 2, - SIS_VSUNISYSTEM = 3, + SIS_VSUNISYSTEM = 3, // Is it used? SIS_NSF = 4, }; @@ -44,6 +66,8 @@ enum ESI SI_COUNT = SI_LCDCOMP_ZAPPER }; + + inline const char* ESI_Name(ESI esi) { static const char * const names[] = @@ -137,6 +161,9 @@ struct FCEUGI ESI input[2]; //Desired input for emulated input ports 1 and 2; -1 for unknown desired input. ESIFC inputfc; //Desired Famicom expansion port device. -1 for unknown desired input. ESIS cspecial; //Special cart expansion: DIP switches, barcode reader, etc. + EGIPPU vs_ppu; //PPU type for Vs. System + EGIVS vs_type; //Vs. System type + uint8 vs_cswitch; // Switch first and second controllers for Vs. System MD5DATA MD5; diff --git a/src/ines.cpp b/src/ines.cpp index 5c74bf7b..23ee3aa2 100644 --- a/src/ines.cpp +++ b/src/ines.cpp @@ -37,6 +37,7 @@ #include "cheat.h" #include "vsuni.h" #include "driver.h" +#include "input.h" #include #include @@ -143,6 +144,9 @@ struct INPSEL { ESIFC inputfc; }; +/* +* Function to set input controllers based on CRC +*/ static void SetInput(void) { static struct INPSEL moo[] = { @@ -155,9 +159,9 @@ static void SetInput(void) { {0x48ca0ee1, SI_GAMEPAD, SI_GAMEPAD, SIFC_BWORLD }, // Barcode World {0x4318a2f8, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Barker Bill's Trick Shooting {0x6cca1c1f, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, // Dai Undoukai - {0x24598791, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Duck Hunt + {0x24598791, SI_GAMEPAD, SI_ZAPPER, SIFC_NONE }, // Duck Hunt {0xd5d6eac4, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Edu (As) - {0xe9a7fe9e, SI_UNSET, SI_MOUSE, SIFC_NONE }, // Educational Computer 2000 + {0xe9a7fe9e, SI_UNSET, SI_MOUSE, SIFC_SUBORKB }, // Educational Computer 2000 {0x8f7b1669, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // FP BASIC 3.3 by maxzhou88 {0xf7606810, SI_UNSET, SI_UNSET, SIFC_FKB }, // Family BASIC 2.0A {0x895037bc, SI_UNSET, SI_UNSET, SIFC_FKB }, // Family BASIC 2.1a @@ -217,6 +221,7 @@ static void SetInput(void) { {0x67b126b9, SI_GAMEPAD, SI_GAMEPAD, SIFC_FAMINETSYS }, // Famicom Network System {0x00000000, SI_UNSET, SI_UNSET, SIFC_UNSET } }; + int x = 0; while (moo[x].input1 >= 0 || moo[x].input2 >= 0 || moo[x].inputfc >= 0) { @@ -230,6 +235,63 @@ static void SetInput(void) { } } +struct INPSEL_NES20 { + uint8 expansion_id; + ESI input1; + ESI input2; + ESIFC inputfc; +}; + +/* +* Function to set input controllers based on NES 2.0 header +*/ +extern int eoptions; +static void SetInputNes20(uint8 expansion) { + static struct INPSEL_NES20 moo[] = + { + {0x01, SI_GAMEPAD, SI_GAMEPAD, SIFC_UNSET }, // Standard NES/Famicom controllers + {0x02, SI_GAMEPAD, SI_GAMEPAD, SIFC_NONE }, // NES Four Score/Satellite with two additional standard controllers + {0x03, SI_GAMEPAD, SI_GAMEPAD, SIFC_4PLAYER }, // Famicom Four Players Adapter with two additional standard controllers using the "simple" protocol + {0x04, SI_GAMEPAD, SI_GAMEPAD, SIFC_NONE }, // Vs. System (1P via $4016) + {0x05, SI_GAMEPAD, SI_GAMEPAD, SIFC_NONE }, // Vs. System (1P via $4017) + {0x07, SI_ZAPPER, SI_NONE, SIFC_NONE }, // Vs. Zapper + {0x08, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Zapper ($4017) + {0x0A, SI_UNSET, SI_UNSET, SIFC_SHADOW }, // Bandai Hyper Shot Lightgun + {0x0B, SI_UNSET, SI_POWERPADA, SIFC_UNSET }, // Power Pad Side A + {0x0C, SI_UNSET, SI_POWERPADB, SIFC_UNSET }, // Power Pad Side B + {0x0D, SI_UNSET, SI_UNSET, SIFC_FTRAINERA }, // Family Trainer Side A + {0x0E, SI_UNSET, SI_UNSET, SIFC_FTRAINERB }, // Family Trainer Side B + {0x0F, SI_UNSET, SI_ARKANOID, SIFC_UNSET }, // Arkanoid Vaus Controller (NES) + {0x10, SI_UNSET, SI_UNSET, SIFC_ARKANOID }, // Arkanoid Vaus Controller (Famicom) + {0x12, SI_UNSET, SI_UNSET, SIFC_HYPERSHOT }, // Konami Hyper Shot Controller + {0x15, SI_UNSET, SI_UNSET, SIFC_MAHJONG }, // Jissen Mahjong Controller + {0x17, SI_UNSET, SI_UNSET, SIFC_OEKAKIDS }, // Oeka Kids Tablet + {0x18, SI_UNSET, SI_UNSET, SIFC_BWORLD }, // Sunsoft Barcode Battler + {0x1B, SI_UNSET, SI_UNSET, SIFC_TOPRIDER }, // Top Rider (Inflatable Bicycle) + {0x23, SI_UNSET, SI_UNSET, SIFC_FKB }, // Family BASIC Keyboard plus Famicom Data Recorder + {0x24, SI_UNSET, SI_UNSET, SIFC_PEC586KB }, // Dongda PEC-586 Keyboard + {0x26, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Subor Keyboard + //{0x27, SI_UNSET, SI_MOUSE, SIFC_SUBORKB }, // Subor Keyboard plus mouse (3x8-bit protocol) + {0x28, SI_UNSET, SI_MOUSE, SIFC_SUBORKB }, // Subor Keyboard plus mouse (24-bit protocol) + {0x29, SI_UNSET, SI_SNES_MOUSE, SIFC_UNSET }, // SNES Mouse + {0, SI_UNSET, SI_UNSET, SIFC_UNSET } + }; + + int x = 0; + + if (expansion == 0x02) eoptions |= 32768; // dirty hack to enable Four-Score + GameInfo->vs_cswitch = expansion == 0x05; + + while (moo[x].expansion_id) { + if (moo[x].expansion_id == expansion) { + GameInfo->input[0] = moo[x].input1; + GameInfo->input[1] = moo[x].input2; + GameInfo->inputfc = moo[x].inputfc; + break; } + x++; + } +} + #define INESB_INCOMPLETE 1 #define INESB_CORRUPT 2 #define INESB_HACKED 4 @@ -278,7 +340,7 @@ static const TMasterRomInfo sMasterRomInfo[] = { const TMasterRomInfo* MasterRomInfo; TMasterRomInfoParams MasterRomInfoParams; -static void CheckHInfo(void) { +static void CheckHInfo(uint64 partialmd5) { /* ROM images that have the battery-backed bit set in the header that really don't have battery-backed RAM is not that big of a problem, so I'll treat this differently by only listing games that should have battery-backed RAM. @@ -329,11 +391,6 @@ static void CheckHInfo(void) { #include "ines-correct.h" }; int32 tofix = 0, x, mask; - uint64 partialmd5 = 0; - - for (x = 0; x < 8; x++) - partialmd5 |= (uint64)iNESCart.MD5[15 - x] << (x * 8); - CheckBad(partialmd5); MasterRomInfo = NULL; for (int i = 0; i < ARRAY_SIZE(sMasterRomInfo); i++) { @@ -741,8 +798,6 @@ BMAPPINGLocal bmap[] = { }; int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) { - struct md5_context md5; - if (FCEU_fread(&head, 1, 16, fp) != 16 || memcmp(&head, "NES\x1A", 4)) return LOADER_INVALID_FORMAT; @@ -824,6 +879,56 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) { memset(VROM, 0xFF, VROM_size << 13); } + // Set Vs. System flag if need + if (!iNES2) { + GameInfo->type = !(head.ROM_type2 & 1) ? GIT_CART : GIT_VSUNI; + } + else { + switch (!(head.ROM_type2 & 2) ? (head.ROM_type2 & 3) : (head.VS_hardware & 0xF)) { + case 0: + GameInfo->type = GIT_CART; + break; + case 1: + GameInfo->type = GIT_VSUNI; + break; + default: + FCEU_PrintError("Game type is not supported at all.", MapperNo); + goto init_error; + } + } + + // Set Vs. System PPU type if need + if (GameInfo->type == GIT_VSUNI && !(head.ROM_type2 & 2)) { + switch (head.VS_hardware & 0xF) { + case 0x0: GameInfo->vs_ppu = GIPPU_RC2C03B; break; + //case 0x1: GameInfo->vs_ppu = GIPPU_RPC2C03C; break; + case 0x2: GameInfo->vs_ppu = GIPPU_RP2C04_0001; break; + case 0x3: GameInfo->vs_ppu = GIPPU_RP2C04_0002; break; + case 0x4: GameInfo->vs_ppu = GIPPU_RP2C04_0003; break; + case 0x5: GameInfo->vs_ppu = GIPPU_RP2C04_0004; break; + case 0x6: GameInfo->vs_ppu = GIPPU_RC2C03B; break; + //case 0x7: GameInfo->ppu = GIPPU_RPC2C03C; break; + case 0x8: GameInfo->vs_ppu = GIPPU_RC2C05_01; break; + case 0x9: GameInfo->vs_ppu = GIPPU_RC2C05_02; break; + case 0xA: GameInfo->vs_ppu = GIPPU_RC2C05_03; break; + case 0xB: GameInfo->vs_ppu = GIPPU_RC2C05_04; break; + //case 0xC: GameInfo->ppu = GIPPU_RPC2C05_05; break; + default: + FCEU_PrintError("Vs. System PPU type is not supported at all."); + goto init_error; + } + + switch (head.VS_hardware >> 4) { + case 0x0: GameInfo->vs_type = EGIVS_NORMAL; break; + case 0x1: GameInfo->vs_type = EGIVS_RBI; break; + case 0x2: GameInfo->vs_type = EGIVS_TKO; break; + case 0x3: GameInfo->vs_type = EGIVS_XEVIOUS; break; + default: + FCEU_PrintError("Vs. System type is not supported at all."); + goto init_error; + } + } + if (head.ROM_type & 4) { /* Trainer */ trainerpoo = (uint8*)FCEU_gmalloc(512); FCEU_fread(trainerpoo, 512, 1, fp); @@ -839,7 +944,9 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) { if (VROM_size) FCEU_fread(VROM, 0x2000, VROM_size, fp); - md5_starts(&md5); + struct md5_context md5; + uint64 partialmd5 = 0; + md5_starts(&md5); md5_update(&md5, ROM, ROM_size << 14); iNESGameCRC32 = CalcCRC32(0, ROM, ROM_size << 14); @@ -850,6 +957,8 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) { } md5_finish(&md5, iNESCart.MD5); memcpy(&GameInfo->MD5, &iNESCart.MD5, sizeof(iNESCart.MD5)); + for (int x = 0; x < 8; x++) + partialmd5 |= (uint64)iNESCart.MD5[7 - x] << (x * 8); iNESCart.CRC32 = iNESGameCRC32; @@ -892,17 +1001,12 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) { } SetInput(); - CheckHInfo(); - { - int x; - uint64 partialmd5 = 0; + // Input can be overriden by NES 2.0 header + if (iNES2) SetInputNes20(head.expansion); + CheckHInfo(partialmd5); + FCEU_VSUniCheck(partialmd5, &MapperNo, &Mirroring); + CheckBad(partialmd5); - for (x = 0; x < 8; x++) { - partialmd5 |= (uint64)iNESCart.MD5[7 - x] << (x * 8); - } - - FCEU_VSUniCheck(partialmd5, &MapperNo, &Mirroring); - } /* Must remain here because above functions might change value of VROM_size and free(VROM). */ @@ -933,6 +1037,8 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) { FCEU_PrintError("Unable to allocate CHR-RAM."); break; } + +init_error: if (ROM) free(ROM); if (VROM) free(VROM); if (trainerpoo) free(trainerpoo); diff --git a/src/ines.h b/src/ines.h index cf2e0765..3e2cb82c 100644 --- a/src/ines.h +++ b/src/ines.h @@ -54,18 +54,19 @@ extern TMasterRomInfoParams MasterRomInfoParams; //mbg merge 7/19/06 changed to c++ decl format struct iNES_HEADER { - char ID[4]; /*NES^Z*/ // 0-3 - uint8 ROM_size; // 4 - uint8 VROM_size; // 5 - uint8 ROM_type; // 6 - uint8 ROM_type2; // 7 - uint8 ROM_type3; // 8 - uint8 Upper_ROM_VROM_size; // 9 - uint8 RAM_size; // 10 - uint8 VRAM_size; // 11 - uint8 TV_system; // 12 - uint8 VS_hardware; // 13 - uint8 reserved[2]; // 14, 15 + char ID[4]; /*NES^Z*/ // 0-3 + uint8 ROM_size; // 4 + uint8 VROM_size; // 5 + uint8 ROM_type; // 6 + uint8 ROM_type2; // 7 + uint8 ROM_type3; // 8 + uint8 Upper_ROM_VROM_size; // 9 + uint8 RAM_size; // 10 + uint8 VRAM_size; // 11 + uint8 TV_system; // 12 + uint8 VS_hardware; // 13 + uint8 misc_roms; // 14 + uint8 expansion; // 15 void cleanup() { diff --git a/src/vsuni.cpp b/src/vsuni.cpp index c2e64766..ea6c173b 100644 --- a/src/vsuni.cpp +++ b/src/vsuni.cpp @@ -26,31 +26,17 @@ #include "vsuni.h" #include "state.h" #include "driver.h" +#include "cart.h" +#include "ines.h" #include #include -#define IOPTION_GUN 0x1 -#define IOPTION_SWAPDIRAB 0x2 - -#define IOPTION_PREDIP 0x10 -typedef struct { - const char *name; - uint64 md5partial; - int mapper; - int mirroring; - int ppu; - int ioption; - int predip; -} VSUNIENTRY; - -VSUNIENTRY *curvs; - -static uint8 DIPS = 0; +static uint8 show_dips = 0; uint8 vsdip = 0; void FCEUI_VSUniToggleDIPView(void) { - DIPS = !DIPS; + show_dips = !show_dips; } void FCEU_VSUniToggleDIP(int w) { @@ -66,20 +52,19 @@ uint8 FCEUI_VSUniGetDIPs(void) { return(vsdip); } -static uint8 secdata[2][32] = +static uint8 secdata_tko[32] = { - { - 0xff, 0xbf, 0xb7, 0x97, 0x97, 0x17, 0x57, 0x4f, - 0x6f, 0x6b, 0xeb, 0xa9, 0xb1, 0x90, 0x94, 0x14, - 0x56, 0x4e, 0x6f, 0x6b, 0xeb, 0xa9, 0xb1, 0x90, - 0xd4, 0x5c, 0x3e, 0x26, 0x87, 0x83, 0x13, 0x00 - }, - { - 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, - 0x00, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x94, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - } + 0xff, 0xbf, 0xb7, 0x97, 0x97, 0x17, 0x57, 0x4f, + 0x6f, 0x6b, 0xeb, 0xa9, 0xb1, 0x90, 0x94, 0x14, + 0x56, 0x4e, 0x6f, 0x6b, 0xeb, 0xa9, 0xb1, 0x90, + 0xd4, 0x5c, 0x3e, 0x26, 0x87, 0x83, 0x13, 0x00 +}; +static uint8 secdata_rbi[32] = +{ + 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, + 0x00, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x94, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static uint8 *secptr; @@ -99,19 +84,6 @@ void FCEU_VSUniCoin(void) { coinon = 6; } -static int curppu; -static int64 curmd5; - -#define RP2C04_001 1 -#define RP2C04_002 2 -#define RP2C04_003 3 -#define RP2C05_004 4 -#define RCP2C03B 5 -#define RC2C05_01 6 -#define RC2C05_02 7 -#define RC2C05_03 8 -#define RC2C05_04 9 - static readfunc OldReadPPU; static writefunc OldWritePPU[2]; @@ -126,10 +98,10 @@ static DECLFR(A2002_Topgun) { static DECLFR(A2002_MBJ) { // Mighty Bomb Jack return((OldReadPPU(A) & ~0x3F) | 0x3D); } - static DECLFW(B2000_2001_2C05) { OldWritePPU[(A & 1) ^ 1](A ^ 1, V); } + static uint8 xevselect = 0; static DECLFR(XevRead) { if (A == 0x54FF) { @@ -146,7 +118,7 @@ static DECLFR(XevRead) { } void FCEU_VSUniSwap(uint8 *j0, uint8 *j1) { - if (curvs->ioption & IOPTION_SWAPDIRAB) { + if (GameInfo->vs_cswitch) { uint16 t = *j0; *j0 = (*j0 & 0xC) | (*j1 & 0xF3); *j1 = (*j1 & 0xC) | (t & 0xF3); @@ -160,22 +132,30 @@ void FCEU_VSUniPower(void) { if (secptr) SetReadHandler(0x5e00, 0x5e01, VSSecRead); - if (curppu == RC2C05_04) { + switch (GameInfo->vs_ppu) { + case GIPPU_RP2C04_0001: + case GIPPU_RP2C04_0002: + case GIPPU_RP2C04_0003: + case GIPPU_RP2C04_0004: + default_palette_selection = GameInfo->vs_ppu; + break; + } + if (GameInfo->vs_ppu == GIPPU_RC2C05_04) { OldReadPPU = GetReadHandler(0x2002); SetReadHandler(0x2002, 0x2002, A2002_Topgun); - } else if (curppu == RC2C05_03) { + } else if (GameInfo->vs_ppu == GIPPU_RC2C05_03) { OldReadPPU = GetReadHandler(0x2002); SetReadHandler(0x2002, 0x2002, A2002_Gumshoe); - } else if (curppu == RC2C05_02) { + } else if (GameInfo->vs_ppu == GIPPU_RC2C05_02) { OldReadPPU = GetReadHandler(0x2002); SetReadHandler(0x2002, 0x2002, A2002_MBJ); } - if (curppu == RC2C05_04 || curppu == RC2C05_01 || curppu == RC2C05_03 || curppu == RC2C05_02) { + if (GameInfo->vs_ppu == GameInfo->vs_ppu == GIPPU_RC2C05_01 || GameInfo->vs_ppu == GIPPU_RC2C05_02 || GameInfo->vs_ppu == GIPPU_RC2C05_03 || GameInfo->vs_ppu == GIPPU_RC2C05_04) { OldWritePPU[0] = GetWriteHandler(0x2000); OldWritePPU[1] = GetWriteHandler(0x2001); SetWriteHandler(0x2000, 0x2001, B2000_2001_2C05); } - if (curmd5 == 0x2d396247cf58f9faLL) { /* Super Xevious */ + if (GameInfo->vs_type == EGIVS_XEVIOUS) { /* Super Xevious */ SetReadHandler(0x5400, 0x57FF, XevRead); } } @@ -252,47 +232,47 @@ RC2C05-04: VSUNIENTRY VSUniGames[] = { - { "Baseball", 0x691d4200ea42be45ULL, 99, 2, RP2C04_001, 0 }, - { "Battle City", 0x8540949d74c4d0ebULL, 99, 2, RP2C04_001, 0 }, - { "Battle City(Bootleg)", 0x8093cbe7137ac031ULL, 99, 2, RP2C04_001, 0 }, + { "Baseball", 0x691d4200ea42be45ULL, 99, 2, GIPPU_RP2C04_0001, 0, 0, EGIVS_NORMAL }, + { "Battle City", 0x8540949d74c4d0ebULL, 99, 2, GIPPU_RP2C04_0001, 0, 0, EGIVS_NORMAL }, + { "Battle City(Bootleg)", 0x8093cbe7137ac031ULL, 99, 2, GIPPU_RP2C04_0001, 0, 0, EGIVS_NORMAL }, - { "Clu Clu Land", 0x1b8123218f62b1eeULL, 99, 2, RP2C05_004, IOPTION_SWAPDIRAB }, - { "Dr Mario", 0xe1af09c477dc0081ULL, 1, 0, RP2C04_003, IOPTION_SWAPDIRAB }, - { "Duck Hunt", 0x47735d1e5f1205bbULL, 99, 2, RCP2C03B, IOPTION_GUN }, - { "Excitebike", 0x3dcd1401bcafde77ULL, 99, 2, RP2C04_003, 0 }, - { "Excitebike (J)", 0x7ea51c9d007375f0ULL, 99, 2, RP2C05_004, 0 }, - { "Freedom Force", 0xed96436bd1b5e688ULL, 4, 0, RP2C04_001, IOPTION_GUN }, /* Wrong color in game select screen? */ - { "Stroke and Match Golf", 0x612325606e82bc66ULL, 99, 2, RP2C04_002, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x01 }, + { "Clu Clu Land", 0x1b8123218f62b1eeULL, 99, 2, GIPPU_RP2C04_0004, VS_OPTION_SWAPDIRAB, 0, EGIVS_NORMAL }, + { "Dr Mario", 0xe1af09c477dc0081ULL, 1, 0, GIPPU_RP2C04_0003, VS_OPTION_SWAPDIRAB, 0, EGIVS_NORMAL }, + { "Duck Hunt", 0x47735d1e5f1205bbULL, 99, 2, GIPPU_RC2C03B, VS_OPTION_GUN, 0, EGIVS_NORMAL }, + { "Excitebike", 0x3dcd1401bcafde77ULL, 99, 2, GIPPU_RP2C04_0003, 0, 0, EGIVS_NORMAL }, + { "Excitebike (J)", 0x7ea51c9d007375f0ULL, 99, 2, GIPPU_RP2C04_0004, 0, 0, EGIVS_NORMAL }, + { "Freedom Force", 0xed96436bd1b5e688ULL, 4, 0, GIPPU_RP2C04_0001, VS_OPTION_GUN, 0, EGIVS_NORMAL }, /* Wrong color in game select screen? */ + { "Stroke and Match Golf", 0x612325606e82bc66ULL, 99, 2, GIPPU_RP2C04_0002, VS_OPTION_SWAPDIRAB | VS_OPTION_PREDIP, 0x01, EGIVS_NORMAL }, - { "Goonies", 0xb4032d694e1d2733ULL, 151, 1, RP2C04_003, 0 }, - { "Gradius", 0x50687ae63bdad976ULL, 151, 1, RP2C04_001, IOPTION_SWAPDIRAB }, - { "Gumshoe", 0x87161f8ee37758d3ULL, 99, 2, RC2C05_03, IOPTION_GUN }, - { "Gumshoe", 0xb8500780bf69ce29ULL, 99, 2, RC2C05_03, IOPTION_GUN }, - { "Hogan's Alley", 0xd78b7f0bb621fb45ULL, 99, 2, RP2C04_001, IOPTION_GUN }, - { "Ice Climber", 0xd21e999513435e2aULL, 99, 2, RP2C05_004, IOPTION_SWAPDIRAB }, - { "Ladies Golf", 0x781b24be57ef6785ULL, 99, 2, RP2C04_002, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x1 }, + { "Goonies", 0xb4032d694e1d2733ULL, 151, 1, GIPPU_RP2C04_0003, 0, 0, EGIVS_NORMAL }, + { "Gradius", 0x50687ae63bdad976ULL, 151, 1, GIPPU_RP2C04_0001, VS_OPTION_SWAPDIRAB, 0, EGIVS_NORMAL }, + { "Gumshoe", 0x87161f8ee37758d3ULL, 99, 2, GIPPU_RC2C05_03, VS_OPTION_GUN, 0, EGIVS_NORMAL }, + { "Gumshoe", 0xb8500780bf69ce29ULL, 99, 2, GIPPU_RC2C05_03, VS_OPTION_GUN, 0, EGIVS_NORMAL }, + { "Hogan's Alley", 0xd78b7f0bb621fb45ULL, 99, 2, GIPPU_RP2C04_0001, VS_OPTION_GUN, 0, EGIVS_NORMAL }, + { "Ice Climber", 0xd21e999513435e2aULL, 99, 2, GIPPU_RP2C04_0004, VS_OPTION_SWAPDIRAB, 0, EGIVS_NORMAL }, + { "Ladies Golf", 0x781b24be57ef6785ULL, 99, 2, GIPPU_RP2C04_0002, VS_OPTION_SWAPDIRAB | VS_OPTION_PREDIP, 0x1, EGIVS_NORMAL }, - { "Mach Rider", 0x015672618af06441ULL, 99, 2, RP2C04_002, 0 }, - { "Mach Rider (J)", 0xa625afb399811a8aULL, 99, 2, RP2C04_001, 0 }, - { "Mighty Bomb Jack", 0xe6a89f4873fac37bULL, 0, 2, RC2C05_02, 0 }, - { "Ninja Jajamaru Kun", 0xb26a2c31474099c0ULL, 99, 2, RC2C05_01, IOPTION_SWAPDIRAB }, - { "Pinball", 0xc5f49d3de7f2e9b8ULL, 99, 2, RP2C04_001, IOPTION_PREDIP, 0x01 }, - { "Pinball (J)", 0x66ab1a3828cc901cULL, 99, 2, RCP2C03B, IOPTION_PREDIP, 0x1 }, - { "Platoon", 0x160f237351c19f1fULL, 68, 1, RP2C04_001, 0 }, - { "RBI Baseball", 0x6a02d345812938afULL, 4, 1, RP2C04_001, IOPTION_SWAPDIRAB }, - { "Soccer", 0xd4e7a9058780eda3ULL, 99, 2, RP2C04_003, IOPTION_SWAPDIRAB }, - { "Star Luster", 0x8360e134b316d94cULL, 99, 2, RCP2C03B, 0 }, - { "Stroke and Match Golf (J)", 0x869bb83e02509747ULL, 99, 2, RCP2C03B, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x1 }, - { "Super Sky Kid", 0x78d04c1dd4ec0101ULL, 4, 1, RCP2C03B, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x20 }, + { "Mach Rider", 0x015672618af06441ULL, 99, 2, GIPPU_RP2C04_0002, 0, 0, EGIVS_NORMAL }, + { "Mach Rider (J)", 0xa625afb399811a8aULL, 99, 2, GIPPU_RP2C04_0001, 0, 0, EGIVS_NORMAL }, + { "Mighty Bomb Jack", 0xe6a89f4873fac37bULL, 0, 2, GIPPU_RC2C05_02, 0, 0, EGIVS_NORMAL }, + { "Ninja Jajamaru Kun", 0xb26a2c31474099c0ULL, 99, 2, GIPPU_RC2C05_01, VS_OPTION_SWAPDIRAB, 0, EGIVS_NORMAL }, + { "Pinball", 0xc5f49d3def2e9b8ULL, 99, 2, GIPPU_RP2C04_0001, VS_OPTION_PREDIP, 0x01, EGIVS_NORMAL }, + { "Pinball (J)", 0x66ab1a3828cc901cULL, 99, 2, GIPPU_RC2C03B, VS_OPTION_PREDIP, 0x01, EGIVS_NORMAL }, + { "Platoon", 0x160f237351c19f1fULL, 68, 1, GIPPU_RP2C04_0001, 0, 0, EGIVS_NORMAL }, + { "RBI Baseball", 0x6a02d345812938afULL, 4, 1, GIPPU_RP2C04_0001, VS_OPTION_SWAPDIRAB, 0, EGIVS_RBI }, + { "Soccer", 0xd4e7a9058780eda3ULL, 99, 2, GIPPU_RP2C04_0003, VS_OPTION_SWAPDIRAB, 0, EGIVS_NORMAL }, + { "Star Luster", 0x8360e134b316d94cULL, 99, 2, GIPPU_RC2C03B, 0, 0, EGIVS_NORMAL }, + { "Stroke and Match Golf (J)", 0x869bb83e02509747ULL, 99, 2, GIPPU_RC2C03B, VS_OPTION_SWAPDIRAB | VS_OPTION_PREDIP, 0x01, EGIVS_NORMAL }, + { "Super Sky Kid", 0x78d04c1dd4ec0101ULL, 4, 1, GIPPU_RC2C03B, VS_OPTION_SWAPDIRAB | VS_OPTION_PREDIP, 0x20, EGIVS_NORMAL }, - { "Super Xevious", 0x2d396247cf58f9faULL, 206, 0, RP2C04_001, 0 }, - { "Tetris", 0x531a5e8eea4ce157ULL, 99, 2, RCP2C03B, IOPTION_PREDIP, 0x20 }, - { "Top Gun", 0xf1dea36e6a7b531dULL, 2, 0, RC2C05_04, 0 }, - { "VS Castlevania", 0x92fd6909c81305b9ULL, 2, 1, RP2C04_002, 0 }, - { "VS Slalom", 0x4889b5a50a623215ULL, 0, 1, RP2C04_002, 0 }, - { "VS Super Mario Bros", 0x39d8cfa788e20b6cULL, 99, 2, RP2C05_004, 0 }, - { "VS Super Mario Bros [a1]", 0xfc182e5aefbce14dULL, 99, 2, RP2C05_004, 0 }, - { "VS TKO Boxing", 0x6e1ee06171d8ce3aULL, 4, 1, RP2C04_003, IOPTION_PREDIP, 0x00 }, + { "Super Xevious", 0x2d396247cf58f9faULL, 206, 0, GIPPU_RP2C04_0001, 0, 0, EGIVS_XEVIOUS }, + { "Tetris", 0x531a5e8eea4ce157ULL, 99, 2, GIPPU_RC2C03B, VS_OPTION_PREDIP, 0x20, EGIVS_NORMAL }, + { "Top Gun", 0xf1dea36e6a7b531dULL, 2, 0, GIPPU_RC2C05_04, 0, 0, EGIVS_NORMAL }, + { "VS Castlevania", 0x92fd6909c81305b9ULL, 2, 1, GIPPU_RP2C04_0002, 0, 0, EGIVS_NORMAL }, + { "VS Slalom", 0x4889b5a50a623215ULL, 0, 1, GIPPU_RP2C04_0002, 0, 0, EGIVS_NORMAL }, + { "VS Super Mario Bros", 0x39d8cfa788e20b6cULL, 99, 2, GIPPU_RP2C04_0004, 0, 0, EGIVS_NORMAL }, + { "VS Super Mario Bros [a1]", 0xfc182e5aefbce14dULL, 99, 2, GIPPU_RP2C04_0004, 0, 0, EGIVS_NORMAL }, + { "VS TKO Boxing", 0x6e1ee06171d8ce3aULL, 4, 1, GIPPU_RP2C04_0003, VS_OPTION_PREDIP, 0x00, EGIVS_TKO }, { 0 } }; @@ -301,36 +281,82 @@ void FCEU_VSUniCheck(uint64 md5partial, int *MapperNo, uint8 *Mirroring) { while (vs->name) { if (md5partial == vs->md5partial) { - if (vs->ppu < RCP2C03B) default_palette_selection = vs->ppu; - *MapperNo = vs->mapper; - *Mirroring = vs->mirroring; - GameInfo->type = GIT_VSUNI; - GameInfo->cspecial = SIS_VSUNISYSTEM; - GameInfo->inputfc = SIFC_NONE; - curppu = vs->ppu; - curmd5 = md5partial; + int32 tofix = 0; + if (*MapperNo != vs->mapper) { + tofix |= 1; + *MapperNo = vs->mapper; + } + if (*Mirroring != vs->mirroring) { + tofix |= 2; + *Mirroring = vs->mirroring; + } + if (GameInfo->type != GIT_VSUNI) { + tofix |= 4; + GameInfo->type = GIT_VSUNI; + } + if (GameInfo->vs_type != vs->type) { + tofix |= 8; + GameInfo->vs_type = vs->type; + } + if (vs->ppu && (GameInfo->vs_ppu != vs->ppu)) { + tofix |= 16; + GameInfo->vs_ppu = vs->ppu; + } secptr = 0; - + switch (GameInfo->vs_type) { - static int64 tko = 0x6e1ee06171d8ce3aULL, rbi = 0x6a02d345812938afULL; - if (md5partial == tko) - secptr = secdata[0]; - if (md5partial == rbi) - secptr = secdata[1]; + case EGIVS_RBI: secptr = secdata_rbi; break; + case EGIVS_TKO: secptr = secdata_tko; break; + default: secptr = 0; break; } vsdip = 0x0; - if (vs->ioption & IOPTION_PREDIP) { + if (vs->ioption & VS_OPTION_PREDIP) { vsdip = vs->predip; } - if (vs->ioption & IOPTION_GUN) { + if ((vs->ioption & VS_OPTION_GUN) && !head.expansion) { + tofix |= 32; GameInfo->input[0] = SI_ZAPPER; GameInfo->input[1] = SI_NONE; - } else { + } + else if (!head.expansion == 0) { GameInfo->input[0] = GameInfo->input[1] = SI_GAMEPAD; } - curvs = vs; + if ((vs->ioption & VS_OPTION_SWAPDIRAB) && !GameInfo->vs_cswitch) { + tofix |= 64; + GameInfo->vs_cswitch = 1; + } + + if (tofix) { + char gigastr[768]; + strcpy(gigastr, "The iNES header contains incorrect information. For now, the information will be corrected in RAM. "); + if (tofix & 4) { + sprintf(gigastr + strlen(gigastr), "Game type should be set to Vs. System. "); + } + if (tofix & 1) + sprintf(gigastr + strlen(gigastr), "The mapper number should be set to %d. ", *MapperNo); + if (tofix & 2) { + const char* mstr[3] = { "Horizontal", "Vertical", "Four-screen" }; + sprintf(gigastr + strlen(gigastr), "Mirroring should be set to \"%s\". ", mstr[vs->mirroring & 3]); + } + if (tofix & 8) { + const char* mstr[4] = { "Normal", "RBI Baseball protection", "TKO Boxing protection", "Super Xevious protection"}; + sprintf(gigastr + strlen(gigastr), "Vs. System type should be set to \"%s\". ", mstr[vs->type]); + } + if (tofix & 16) + { + const char* mstr[10] = { "Default", "RP2C04-0001", "RP2C04-0002", "RP2C04-0003", "RP2C04-0004", "RC2C03B", "RC2C05-01", "RC2C05-02" , "RC2C05-03" , "RC2C05-04" }; + sprintf(gigastr + strlen(gigastr), "Vs. System PPU should be set to \"%s\". ", mstr[vs->ppu]); + } + if (tofix & 32) + sprintf(gigastr + strlen(gigastr), "The controller type should be set to zapper. ", MapperNo); + if (tofix & 64) + sprintf(gigastr + strlen(gigastr), "The controllers should be swapped. ", MapperNo); + strcat(gigastr, "\n"); + FCEU_printf("%s", gigastr); + } + return; } vs++; @@ -341,7 +367,7 @@ void FCEU_VSUniDraw(uint8 *XBuf) { uint32 *dest; int y, x; - if (!DIPS) return; + if (!show_dips) return; dest = (uint32*)(XBuf + 256 * 12 + 164); for (y = 24; y; y--, dest += (256 - 72) >> 2) { diff --git a/src/vsuni.h b/src/vsuni.h index 14fb715f..6e60d48e 100644 --- a/src/vsuni.h +++ b/src/vsuni.h @@ -1,3 +1,20 @@ +enum IOPTION { + VS_OPTION_GUN = 0x1, + VS_OPTION_SWAPDIRAB = 0x2, + VS_OPTION_PREDIP = 0x10, +}; + +typedef struct { + const char* name; + uint64 md5partial; + int mapper; + int mirroring; + EGIPPU ppu; + int ioption; + int predip; + EGIVS type; +} VSUNIENTRY; + void FCEU_VSUniPower(void); void FCEU_VSUniCheck(uint64 md5partial, int *, uint8 *); void FCEU_VSUniDraw(uint8 *XBuf);