diff --git a/Config/Games.xml b/Config/Games.xml index b279e6e..e6fcdc5 100644 --- a/Config/Games.xml +++ b/Config/Games.xml @@ -19,6 +19,7 @@ Sega Model 3 1.0 + MPC106 @@ -86,6 +87,7 @@ Sega Model 3 1.0 + MPC106 @@ -110,6 +112,7 @@ Sega Model 3 1.0 + MPC106 @@ -141,6 +144,7 @@ Sega Model 3 2.1 DSB2 + 24 @@ -320,6 +324,7 @@ Sega Model 3 2.1 DSB2 + 0x16C311DB @@ -392,6 +397,7 @@ Sega Model 3 2.1 DSB2 + 0x16C311DB @@ -426,6 +432,7 @@ Sega Model 3 2.1 DSB2 + 0x16C311DB @@ -460,6 +467,7 @@ Sega Model 3 2.1 DSB2 + 0x16C311DB @@ -686,6 +694,7 @@ Sega Model 3 2.0 + 24 @@ -763,6 +772,7 @@ Sega Model 3 2.0 + 24 @@ -891,6 +901,7 @@ Sega Model 3 2.1 + 0x16C311DB @@ -1150,6 +1161,7 @@ Sega Model 3 2.1 + 0x16C311DB @@ -1508,6 +1520,7 @@ Sega Model 3 1.5 DSB1 + MPC106 @@ -2078,10 +2091,14 @@ 1998 + Sega Model 3 2.0 - DSB2 + 48 @@ -2544,6 +2561,7 @@ Sega Model 3 2.0 + 0x16C311DB @@ -2619,6 +2637,7 @@ Sega Model 3 2.0 + 0x16C311DB @@ -2645,6 +2664,7 @@ Sega Model 3 2.0 + 0x16C311DB @@ -2671,6 +2691,7 @@ Sega Model 3 2.0 + 0x16C311DB @@ -2771,6 +2792,7 @@ Sega Model 3 1.5 + MPC106 @@ -2798,6 +2820,7 @@ Sega Model 3 1.5 + MPC106 @@ -2912,6 +2935,7 @@ Sega Model 3 1.5 + MPC106 @@ -3041,6 +3065,7 @@ Sega Model 3 1.5 + MPC106 diff --git a/Src/Game.h b/Src/Game.h index bb173c9..4cc3fbb 100644 --- a/Src/Game.h +++ b/Src/Game.h @@ -14,6 +14,9 @@ struct Game unsigned year = 0; std::string stepping; std::string mpeg_board; + std::string pci_bridge; // overrides default PCI bridge type for stepping (empty string for default) + uint32_t real3d_pci_id = 0; // overrides default Real3D PCI ID for stepping (0 for default) + float real3d_status_bit_set_percent_of_frame = 0; // overrides default status bit timing (0 for default) uint32_t encryption_key = 0; enum Inputs { diff --git a/Src/GameLoader.cpp b/Src/GameLoader.cpp index c094f0b..32a591a 100644 --- a/Src/GameLoader.cpp +++ b/Src/GameLoader.cpp @@ -197,6 +197,9 @@ static void PopulateGameInfo(Game *game, const Util::Config::Node &game_node) game->year = game_node["identity/year"].ValueAsDefault(0); game->stepping = game_node["hardware/stepping"].ValueAsDefault(""); game->mpeg_board = game_node["hardware/mpeg_board"].ValueAsDefault(""); + game->pci_bridge = game_node["hardware/pci_bridge"].ValueAsDefault(""); + game->real3d_pci_id = game_node["hardware/real3d_pci_id"].ValueAsDefault(0); + game->real3d_status_bit_set_percent_of_frame = game_node["hardware/real3d_status_bit_set_percent_of_frame"].ValueAsDefault(0); game->encryption_key = game_node["hardware/encryption_key"].ValueAsDefault(0); std::map input_flags { diff --git a/Src/Model3/MPC10x.cpp b/Src/Model3/MPC10x.cpp index 2a3398d..102bf02 100644 --- a/Src/Model3/MPC10x.cpp +++ b/Src/Model3/MPC10x.cpp @@ -1,7 +1,7 @@ /** ** Supermodel ** A Sega Model 3 Arcade Emulator. - ** Copyright 2011 Bart Trzynadlowski, Nik Henson + ** Copyright 2011-2019 Bart Trzynadlowski, Nik Henson, Ian Curtis ** ** This file is part of Supermodel. ** @@ -319,6 +319,16 @@ void CMPC10x::SetModel(int modelNum) DebugLog("MPC10x set to MPC%X\n", model); } +/* + * CMPC10x::GetModel(): + * + * Returns the model number. + */ +int CMPC10x::GetModel() const +{ + return model; +} + /* * CMPC10x::Init(): * diff --git a/Src/Model3/MPC10x.h b/Src/Model3/MPC10x.h index 8104d9e..526a1ea 100644 --- a/Src/Model3/MPC10x.h +++ b/Src/Model3/MPC10x.h @@ -146,6 +146,14 @@ public: * to MPC105 if unrecognized. */ void SetModel(int modelNum); + + /* + * GetModel(void): + * + * Returns: + * The PCI bridge model number, either 0x105 or 0x106. + */ + int GetModel() const; /* * Init(void): diff --git a/Src/Model3/Model3.cpp b/Src/Model3/Model3.cpp index b6ad0a5..bdae065 100644 --- a/Src/Model3/Model3.cpp +++ b/Src/Model3/Model3.cpp @@ -1,7 +1,7 @@ /** ** Supermodel ** A Sega Model 3 Arcade Emulator. - ** Copyright 2011-2016 Bart Trzynadlowski, Nik Henson + ** Copyright 2011-2019 Bart Trzynadlowski, Nik Henson, Ian Curtis ** ** This file is part of Supermodel. ** @@ -553,12 +553,20 @@ UINT8 CModel3::ReadInputs(unsigned reg) adc[1] = (UINT8)Inputs->analogGunX[1]->value; adc[3] = (UINT8)Inputs->analogGunY[1]->value; - if (m_game.name == "lostwsga" || m_game.name == "lostwsgo") { // to do, not a string compare + /* + // Unclear why this is necessary or how to cleanly fix it, so I'm + // disabling it but leaving it here for future reference. The proper fix is + // probably to allow users to define inverted controls for this game only, + // which means the input system must support loading per-game config (not + // all analog_gun games require axis inversion to be playable). + if (m_game.name == "lostwsga" || m_game.name == "lostwsgo") + { // to do, not a string compare adc[0] = (UINT8)Inputs->analogGunX[0]->value; // order is different for some reason in lost world adc[1] = 255 - (UINT8)Inputs->analogGunY[0]->value; // why are values inverted? is this the wrong place to fix this adc[2] = (UINT8)Inputs->analogGunX[1]->value; adc[3] = 255 - (UINT8)Inputs->analogGunY[1]->value; } + */ } if ((m_game.inputs & Game::INPUT_SKI)) @@ -2205,32 +2213,29 @@ void CModel3::RunMainBoardFrame(void) unsigned vblCycles = (unsigned)((float) frameCycles * 2.5f/100.0f); // 2.5% vblank (ridiculously short and wrong but bigger values cause flicker in Daytona) unsigned dispCycles = frameCycles - vblCycles; - // Scale PPC timer ratio according to speed at which the PowerPC is being emulated so that the observed running frequency of the PPC timer - // registers is more or less correct. This is needed to get the Virtua Striker 2 series of games running at the right speed (they are - // too slow otherwise). Other games appear to not be affected by this ratio so much as their running speed depends more on the timing of - // the Real3D status bit below. - ppc_set_timer_ratio(ppc_get_bus_freq_multipler() * 2 * ppcCycles / ppc_get_cycles_per_sec()); + // For some reason, some Step 2.x games require completely different timings. The defaults can be overriden in the ROM set XML file. + float real3DStatusBitSetAsPercentOfFrame = m_game.real3d_status_bit_set_percent_of_frame; + if (real3DStatusBitSetAsPercentOfFrame <= 0) + { + if (m_game.stepping == "2.0" || m_game.stepping == "2.1") + real3DStatusBitSetAsPercentOfFrame = 9.12f; + else if (m_game.stepping == "1.5") + real3DStatusBitSetAsPercentOfFrame = 5.5f; + else + real3DStatusBitSetAsPercentOfFrame = 48.0f; + } // Compute timing of the Real3D status bit. This value directly affects the speed at which all the games except Virtua Stiker 2 run. // Currently it is not known exactly what this bit represents nor why such wildly varying values are needed for the different step models. // The values below were arrived at by trial and error and clearly more investigation is required. If it turns out that the status bit is // connected to the end of VBlank then the code below should be removed and the timing handled via GPU.VBlankEnd() instead. - unsigned statusCycles; - if (m_game.stepping == "2.0" || m_game.stepping == "2.1") - { - // For some reason, Fighting Vipers 2 and Daytona USA 2 require completely different timing to the rest of the step 2.x games - if (m_game.name == "daytona2" || (m_game.stepping == "2.0" && (m_game.name == "fvipers2" || m_game.name == "fvipers2o"))) - statusCycles = (unsigned)((float)frameCycles * 24.0f/100.0f); - // Spindizzi notes : this little hack timing allow srally2x to run full speed (for test purpose only) - else if (m_game.name == "srally2x") // need ppc=100 also (edit ini or add option in command line) - statusCycles = (unsigned)((float)frameCycles * 48.0f / 100.0f); - else - statusCycles = (unsigned)((float)frameCycles * 9.12f/100.0f); - } - else if (m_game.stepping == "1.5") - statusCycles = (unsigned)((float)frameCycles * 5.5f/100.0f); - else - statusCycles = (unsigned)((float)frameCycles * 48.0f/100.0f); + unsigned statusCycles = (unsigned) ((float) frameCycles * (real3DStatusBitSetAsPercentOfFrame * 1e-2f)); + + // Scale PPC timer ratio according to speed at which the PowerPC is being emulated so that the observed running frequency of the PPC timer + // registers is more or less correct. This is needed to get the Virtua Striker 2 series of games running at the right speed (they are + // too slow otherwise). Other games appear to not be affected by this ratio so much as their running speed depends more on the timing of + // the Real3D status bit below. + ppc_set_timer_ratio(ppc_get_bus_freq_multipler() * 2 * ppcCycles / ppc_get_cycles_per_sec()); // VBlank if (gpusReady) @@ -3089,44 +3094,46 @@ bool CModel3::LoadGame(const Game &game, const ROMSet &rom_set) Util::FlipEndian16(soundROM, 512*1024); Util::FlipEndian16(sampleROM, 16*0x100000); - // Initialize CPU + // Configure CPU and PCI bridge PPC_CONFIG ppc_config; if (game.stepping == "2.0" || game.stepping == "2.1") { - ppc_config.pvr = PPC_MODEL_603R; // 166 MHz + ppc_config.pvr = PPC_MODEL_603R; // 166 MHz ppc_config.bus_frequency = BUS_FREQUENCY_66MHZ; ppc_config.bus_frequency_multiplier = 0x25; // 2.5X multiplier PCIBridge.SetModel(0x106); // MPC106 } else if (game.stepping == "1.5") { - ppc_config.pvr = PPC_MODEL_603E; // 100 MHz + ppc_config.pvr = PPC_MODEL_603E; // 100 MHz ppc_config.bus_frequency = BUS_FREQUENCY_66MHZ; ppc_config.bus_frequency_multiplier = 0x15; // 1.5X multiplier - if (game.name == "scudplusa" - || game.name == "vs215" || game.name == "vs215o" - || game.name == "vs29815" || game.name == "vs29915" - ) - PCIBridge.SetModel(0x106); // some Step 1.x games use MPC106 - else - PCIBridge.SetModel(0x105); // MPC105 + PCIBridge.SetModel(0x105); // MPC105 } else if (game.stepping == "1.0") { - ppc_config.pvr = PPC_MODEL_603R; // 66 MHz + ppc_config.pvr = PPC_MODEL_603R; // 66 MHz ppc_config.bus_frequency = BUS_FREQUENCY_66MHZ; ppc_config.bus_frequency_multiplier = 0x10; // 1X multiplier - if (game.name == "bass" || game.name == "bassdx" || game.name == "getbass") - - PCIBridge.SetModel(0x106); // some Step 1.x games use MPC106 - else - PCIBridge.SetModel(0x105); // MPC105 + PCIBridge.SetModel(0x105); // MPC105 } else { ErrorLog("Cannot configure Model 3 because game uses unrecognized stepping (%s).", game.stepping.c_str()); return FAIL; } + + if (!game.pci_bridge.empty()) + { + if (game.pci_bridge == "MPC105") + PCIBridge.SetModel(0x105); + else if (game.pci_bridge == "MPC106") + PCIBridge.SetModel(0x106); + else + ErrorLog("Unknown PCI bridge specified in ROM set definition file (%s). Defaulting to MPC%X.", game.pci_bridge.c_str(), PCIBridge.GetModel()); + } + + // Initialize CPU ppc_init(&ppc_config); ppc_attach_bus(this); PPCFetchRegions[0].start = 0; @@ -3141,18 +3148,13 @@ bool CModel3::LoadGame(const Game &game, const ROMSet &rom_set) ppc_set_fetch(PPCFetchRegions); // Initialize Real3D - int stepping = ((game.stepping[0] - '0') << 4) | (game.stepping[2] - '0'); - // Some step 2+ games need the older PCI ID (obvious symptom: - // vbl is enabled briefly then disabled so the game hangs) - bool step20_with_old_real3d; - if (game.name == "von2" || game.name == "von2a" || game.name == "von254g" || game.name == "von2o" - || game.name == "dirtdvls" || game.name == "dirtdvlsa" || game.name == "dirtdvlsj" || game.name == "dirtdvlsg" - || game.name == "magtruck" || game.name == "lamachin" - ) - step20_with_old_real3d = true; - else - step20_with_old_real3d = false; - GPU.SetStepping(stepping, step20_with_old_real3d); + int stepping = ((game.stepping[0] - '0') << 4) | (game.stepping[2] - '0'); + uint32_t real3DPCIID = game.real3d_pci_id; + if (0 == real3DPCIID) + { + real3DPCIID = stepping >= 0x20 ? CReal3D::PCIID::Step2x : CReal3D::PCIID::Step1x; + } + GPU.SetStepping(stepping, real3DPCIID); // MPEG board (if present) if (rom_set.get_rom("mpeg_program").size) diff --git a/Src/Model3/Real3D.cpp b/Src/Model3/Real3D.cpp index 9e19592..f6993fe 100644 --- a/Src/Model3/Real3D.cpp +++ b/Src/Model3/Real3D.cpp @@ -883,7 +883,7 @@ uint32_t CReal3D::GetASICIDCode(ASIC asic) const return it == m_asicID.end() ? 0 : it->second; } -void CReal3D::SetStepping(int stepping, bool step20_with_old_real3d) +void CReal3D::SetStepping(int stepping, uint32_t pciIDValue) { step = stepping; @@ -894,12 +894,7 @@ void CReal3D::SetStepping(int stepping, bool step20_with_old_real3d) } // Set PCI ID - // Some step 2+ games need the older PCI ID (obvious symptom: - // vbl is enabled briefly then disabled so the game hangs) - if ((step < 0x20) || step20_with_old_real3d) - pciID = 0x16C311DB; // vendor 0x11DB = Sega - else - pciID = 0x178611DB; + pciID = pciIDValue; // Pass to renderer if (Render3D != NULL) diff --git a/Src/Model3/Real3D.h b/Src/Model3/Real3D.h index e511700..cf86460 100644 --- a/Src/Model3/Real3D.h +++ b/Src/Model3/Real3D.h @@ -59,6 +59,22 @@ struct QueuedUploadTextures class CReal3D: public IPCIDevice { public: + /* + * PCI IDs + * + * The CReal3D object must be configured with the desired ID. Some Step 2.x + * appear to defy this and expect the 1.x ID. The symptom of this is that + * VBL is enabled briefly then disabled. This should be investigated further. + * Perhaps a different ASIC's PCI ID is being read in these situations? + * + * The vendor ID code 0x11db is Sega's. + */ + enum PCIID: uint32_t + { + Step1x = 0x16C311DB, // Step 1.x + Step2x = 0x178611DB // Step 2.x + }; + /* * ASIC Names * @@ -352,17 +368,22 @@ public: uint32_t GetASICIDCode(ASIC asic) const; /* - * SetStepping(stepping): + * SetStepping(stepping, pciIDValue): * * Sets the Model 3 hardware stepping, which also determines the Real3D * functionality. The default is Step 1.0. This should be called prior to * any other emulation functions and after Init(). * * Parameters: - * stepping 0x10 for Step 1.0, 0x15 for Step 1.5, 0x20 for Step 2.0, or - * 0x21 for Step 2.1. Anything else defaults to 1.0. + * stepping 0x10 for Step 1.0, 0x15 for Step 1.5, 0x20 for Step 2.0, or + * 0x21 for Step 2.1. Anything else defaults to 1.0. + * pciIDValue The PCI ID code to return. This should be one of the PCIID + * enum values otherwise games may fail to boot. Although the + * PCI ID depends on stepping, there are a few games that + * have to be explicitly configured with an older ID code, + * which is why this parameter is exposed. */ - void SetStepping(int stepping, bool step20_with_old_real3d); + void SetStepping(int stepping, uint32_t pciIDValue); /* diff --git a/Src/OSD/SDL/Main.cpp b/Src/OSD/SDL/Main.cpp index d286db9..39e60f5 100644 --- a/Src/OSD/SDL/Main.cpp +++ b/Src/OSD/SDL/Main.cpp @@ -1365,7 +1365,7 @@ static Util::Config::Node DefaultConfig() static void Title(void) { puts("Supermodel: A Sega Model 3 Arcade Emulator (Version " SUPERMODEL_VERSION ")"); - puts("Copyright 2011-2018 by Bart Trzynadlowski, Nik Henson, Ian Curtis,"); + puts("Copyright 2011-2019 by Bart Trzynadlowski, Nik Henson, Ian Curtis,"); puts(" Harry Tuttle, and Spindizzi\n"); }