1 //////////////////////////////////////////////////////////////////////////////////////// 2 // 3 // Nestopia - NES/Famicom emulator written in C++ 4 // 5 // Copyright (C) 2003-2008 Martin Freij 6 // 7 // This file is part of Nestopia. 8 // 9 // Nestopia is free software; you can redistribute it and/or modify 10 // it under the terms of the GNU General Public License as published by 11 // the Free Software Foundation; either version 2 of the License, or 12 // (at your option) any later version. 13 // 14 // Nestopia is distributed in the hope that it will be useful, 15 // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 // GNU General Public License for more details. 18 // 19 // You should have received a copy of the GNU General Public License 20 // along with Nestopia; if not, write to the Free Software 21 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 // 23 //////////////////////////////////////////////////////////////////////////////////////// 24 25 #include "../NstLog.hpp" 26 #include "../NstCpu.hpp" 27 #include "../NstPpu.hpp" 28 #include "../NstState.hpp" 29 #include "NstVsSystem.hpp" 30 #include "NstVsRbiBaseball.hpp" 31 #include "NstVsTkoBoxing.hpp" 32 #include "NstVsSuperXevious.hpp" 33 34 namespace Nes 35 { 36 namespace Core 37 { 38 #ifdef NST_MSVC_OPTIMIZE 39 #pragma optimize("s", on) 40 #endif 41 42 class Cartridge::VsSystem::Dip 43 { 44 class Proxy; 45 46 struct Setting 47 { 48 uint data; 49 cstring name; 50 }; 51 52 Setting* settings; 53 uint size; 54 uint selection; 55 uint mask; 56 cstring name; 57 58 public: 59 60 struct Value 61 { 62 cstring const name; 63 const uint data; 64 const uint selection; 65 ValueNes::Core::Cartridge::VsSystem::Dip::Value66 Value(cstring n,uint d,uint s=0) 67 : name(n), data(d), selection(s) {} 68 }; 69 70 void operator = (const Value&); 71 72 private: 73 74 class Proxy 75 { 76 Dip& dip; 77 const uint index; 78 79 public: 80 Proxy(Dip & d,uint i)81 Proxy(Dip& d,uint i) 82 : dip(d), index(i) {} 83 operator =(const Value & value)84 void operator = (const Value& value) 85 { 86 dip.settings[index].data = value.data; 87 dip.settings[index].name = value.name; 88 } 89 operator uint() const90 operator uint() const 91 { 92 return dip.settings[index].data; 93 } 94 Name() const95 cstring Name() const 96 { 97 return dip.settings[index].name; 98 } 99 }; 100 101 public: 102 Dip()103 Dip() 104 : settings(NULL) {} 105 ~Dip()106 ~Dip() 107 { 108 delete [] settings; 109 } 110 Size() const111 uint Size() const 112 { 113 return size; 114 } 115 Select(uint i)116 void Select(uint i) 117 { 118 NST_ASSERT( i < size ); 119 selection = i; 120 } 121 Selection() const122 uint Selection() const 123 { 124 return selection; 125 } 126 operator [](uint i)127 Proxy operator [] (uint i) 128 { 129 NST_ASSERT( i < size ); 130 return Proxy(*this,i); 131 } 132 Name() const133 cstring Name() const 134 { 135 return name; 136 } 137 }; 138 operator =(const Value & value)139 void Cartridge::VsSystem::Dip::operator = (const Value& value) 140 { 141 NST_ASSERT( settings == NULL && value.data && value.selection < value.data ); 142 143 name = value.name; 144 size = value.data; 145 selection = value.selection; 146 settings = new Setting [size]; 147 } 148 VsDipSwitches(Dip * & old,uint n)149 Cartridge::VsSystem::VsDipSwitches::VsDipSwitches(Dip*& old,uint n) 150 : table(old), size(n) 151 { 152 old = NULL; 153 154 regs[0] = 0; 155 regs[1] = 0; 156 157 for (uint i=0; i < n; ++i) 158 { 159 regs[0] |= (table[i][table[i].Selection()] & DIPSWITCH_4016_MASK) << DIPSWITCH_4016_SHIFT; 160 regs[1] |= (table[i][table[i].Selection()] & DIPSWITCH_4017_MASK) << DIPSWITCH_4017_SHIFT; 161 } 162 } 163 ~VsDipSwitches()164 Cartridge::VsSystem::VsDipSwitches::~VsDipSwitches() 165 { 166 delete [] table; 167 } 168 Reset()169 inline void Cartridge::VsSystem::VsDipSwitches::Reset() 170 { 171 coinTimer = 0; 172 regs[0] &= ~uint(COIN); 173 } 174 Reg(uint i) const175 inline uint Cartridge::VsSystem::VsDipSwitches::Reg(uint i) const 176 { 177 return regs[i]; 178 } 179 NumDips() const180 uint Cartridge::VsSystem::VsDipSwitches::NumDips() const 181 { 182 return size; 183 } 184 NumValues(uint dip) const185 uint Cartridge::VsSystem::VsDipSwitches::NumValues(uint dip) const 186 { 187 NST_ASSERT( dip < size ); 188 return table[dip].Size(); 189 } 190 GetDipName(uint dip) const191 cstring Cartridge::VsSystem::VsDipSwitches::GetDipName(uint dip) const 192 { 193 NST_ASSERT( dip < size ); 194 return table[dip].Name(); 195 } 196 GetValueName(uint dip,uint value) const197 cstring Cartridge::VsSystem::VsDipSwitches::GetValueName(uint dip,uint value) const 198 { 199 NST_ASSERT( dip < size && value < table[dip].Size() ); 200 return table[dip][value].Name(); 201 } 202 GetValue(uint dip) const203 uint Cartridge::VsSystem::VsDipSwitches::GetValue(uint dip) const 204 { 205 NST_ASSERT( dip < size ); 206 return table[dip].Selection(); 207 } 208 SetValue(uint dip,uint value)209 void Cartridge::VsSystem::VsDipSwitches::SetValue(uint dip,uint value) 210 { 211 NST_ASSERT( dip < size && value < table[dip].Size() ); 212 213 const uint old = table[dip].Selection(); 214 215 regs[0] &= ~((table[dip][old] & DIPSWITCH_4016_MASK) << DIPSWITCH_4016_SHIFT); 216 regs[1] &= ~((table[dip][old] & DIPSWITCH_4017_MASK) << DIPSWITCH_4017_SHIFT); 217 218 table[dip].Select( value ); 219 220 regs[0] |= (table[dip][value] & DIPSWITCH_4016_MASK) << DIPSWITCH_4016_SHIFT; 221 regs[1] |= (table[dip][value] & DIPSWITCH_4017_MASK) << DIPSWITCH_4017_SHIFT; 222 } 223 224 #ifdef NST_MSVC_OPTIMIZE 225 #pragma optimize("", on) 226 #endif 227 BeginFrame(Input::Controllers * const input)228 void Cartridge::VsSystem::VsDipSwitches::BeginFrame(Input::Controllers* const input) 229 { 230 if (!coinTimer) 231 { 232 if (input) 233 { 234 Input::Controllers::VsSystem::callback( input->vsSystem ); 235 236 if (input->vsSystem.insertCoin & COIN) 237 { 238 regs[0] |= input->vsSystem.insertCoin & COIN; 239 coinTimer = 20; 240 } 241 } 242 } 243 else if (--coinTimer == 15) 244 { 245 regs[0] &= ~uint(COIN); 246 } 247 } 248 249 #ifdef NST_MSVC_OPTIMIZE 250 #pragma optimize("s", on) 251 #endif 252 253 struct Cartridge::VsSystem::Context 254 { 255 Dip* dips; 256 uint numDips; 257 Cpu& cpu; 258 Ppu& ppu; 259 PpuModel ppuModel; 260 Mode mode; 261 InputMapper::Type inputMapper; 262 ContextNes::Core::Cartridge::VsSystem::Context263 Context(Cpu& c,Ppu& p) 264 : 265 dips (NULL), 266 numDips (0), 267 cpu (c), 268 ppu (p), 269 ppuModel (PPU_RP2C03B), 270 mode (MODE_STD), 271 inputMapper (InputMapper::TYPE_NONE) 272 { 273 } 274 SetDipsNes::Core::Cartridge::VsSystem::Context275 void SetDips(uint n) 276 { 277 numDips = n; 278 dips = new Dip [n]; 279 } 280 }; 281 Create(Cpu & cpu,Ppu & ppu,const PpuModel ppuModel,const dword prgCrc)282 Cartridge::VsSystem* Cartridge::VsSystem::Create 283 ( 284 Cpu& cpu, 285 Ppu& ppu, 286 const PpuModel ppuModel, 287 const dword prgCrc 288 ) 289 { 290 switch (prgCrc) 291 { 292 // VS. Dual-System Games are unsupported 293 294 case 0xB90497AA: // Tennis 295 case 0x2A909613: // Tennis (alt) 296 case 0xBC202DB6: // Tennis P2 297 case 0x008A9C16: // Wrecking Crew P1 298 case 0x30C42B1E: // Wrecking Crew P2 299 case 0xAD407F52: // Balloon Fight P1 300 case 0x6AD67502: // Balloon Fight P2 301 case 0x18A93B7B: // Mahjong (J) 302 case 0xA2AD7D61: // Mahjong (J) (alt) 303 case 0xA9A4A6C5: // Mahjong (J) P1 304 case 0x78D1D213: // Mahjong (J) P2 305 case 0x13A91937: // Baseball P1 306 case 0xC4DD2523: // Baseball P1 (alt 1) 307 case 0xB5853830: // Baseball P1 (alt 2) 308 case 0x968A6E9D: // Baseball P2 309 case 0xF64D7252: // Baseball P2 (alt 1) 310 case 0xF5DEBF88: // Baseball P2 (alt 2) 311 case 0xF42DAB14: // Ice Climber P1 312 case 0x7D6B764F: // Ice Climber P2 313 314 throw RESULT_ERR_UNSUPPORTED_VSSYSTEM; 315 } 316 317 Context context( cpu, ppu ); 318 319 try 320 { 321 // Credit to the MAME devs for much of the DIP switch info. 322 323 switch (prgCrc) 324 { 325 case 0xEB2DBA63: // TKO Boxing 326 327 context.SetDips(7); 328 context.dips[0] = Dip::Value( "Coinage", 4, 0 ); 329 context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); 330 context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x01 ); 331 context.dips[0][2] = Dip::Value( "2 Coins / 1 Credit", 0x02 ); 332 context.dips[0][3] = Dip::Value( "3 Coins / 1 Credit", 0x03 ); 333 context.dips[1] = Dip::Value( "Unknown/Unused", 2, 0 ); 334 context.dips[1][0] = Dip::Value( "Off", 0x00 ); 335 context.dips[1][1] = Dip::Value( "On", 0x04 ); 336 context.dips[2] = Dip::Value( "Unknown/Unused", 2, 0 ); 337 context.dips[2][0] = Dip::Value( "Off", 0x00 ); 338 context.dips[2][1] = Dip::Value( "On", 0x08 ); 339 context.dips[3] = Dip::Value( "Unknown/Unused", 2, 0 ); 340 context.dips[3][0] = Dip::Value( "Off", 0x00 ); 341 context.dips[3][1] = Dip::Value( "On", 0x10 ); 342 context.dips[4] = Dip::Value( "Palette Color", 2, 1 ); 343 context.dips[4][0] = Dip::Value( "Black", 0x00 ); 344 context.dips[4][1] = Dip::Value( "White", 0x20 ); 345 context.dips[5] = Dip::Value( "Unknown/Unused", 2, 0 ); 346 context.dips[5][0] = Dip::Value( "Off", 0x00 ); 347 context.dips[5][1] = Dip::Value( "On", 0x40 ); 348 context.dips[6] = Dip::Value( "Unknown/Unused", 2, 0 ); 349 context.dips[6][0] = Dip::Value( "Off", 0x00 ); 350 context.dips[6][1] = Dip::Value( "On", 0x80 ); 351 352 context.inputMapper = InputMapper::TYPE_1; 353 context.mode = MODE_TKO; 354 break; 355 356 case 0x135ADF7C: // RBI Baseball 357 358 context.SetDips(4); 359 context.dips[0] = Dip::Value( "Coinage", 4, 0 ); 360 context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); 361 context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x01 ); 362 context.dips[0][2] = Dip::Value( "2 Coins / 1 Credit", 0x02 ); 363 context.dips[0][3] = Dip::Value( "3 Coins / 1 Credit", 0x03 ); 364 context.dips[1] = Dip::Value( "Max. 1p/in, 2p/in, Min", 4, 1 ); 365 context.dips[1][0] = Dip::Value( "2, 1, 3", 0x04 ); 366 context.dips[1][1] = Dip::Value( "2, 2, 4", 0x0C ); 367 context.dips[1][2] = Dip::Value( "3, 2, 6", 0x00 ); 368 context.dips[1][3] = Dip::Value( "4, 3, 7", 0x08 ); 369 context.dips[2] = Dip::Value( "Demo Sounds", 2, 1 ); 370 context.dips[2][0] = Dip::Value( "Off", 0x00 ); 371 context.dips[2][1] = Dip::Value( "On", 0x10 ); 372 context.dips[3] = Dip::Value( "PPU", 5, 0 ); 373 context.dips[3][0] = Dip::Value( "RP2C03", 0x20 ); 374 context.dips[3][1] = Dip::Value( "RP2C04-0001", 0x00 ); 375 context.dips[3][2] = Dip::Value( "RP2C04-0002", 0x40 ); 376 context.dips[3][3] = Dip::Value( "RP2C04-0003", 0x80 ); 377 context.dips[3][4] = Dip::Value( "RP2C04-0004", 0xC0 ); 378 379 context.inputMapper = InputMapper::TYPE_2; 380 context.mode = MODE_RBI; 381 break; 382 383 case 0xED588F00: // Duck Hunt 384 385 context.SetDips(4); 386 context.dips[0] = Dip::Value( "Coinage", 8, 0 ); 387 context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); 388 context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); 389 context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); 390 context.dips[0][3] = Dip::Value( "2 Coins / 1 Credit", 0x06 ); 391 context.dips[0][4] = Dip::Value( "3 Coins / 1 Credit", 0x01 ); 392 context.dips[0][5] = Dip::Value( "4 Coins / 1 Credit", 0x05 ); 393 context.dips[0][6] = Dip::Value( "5 Coins / 1 Credit", 0x03 ); 394 context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); 395 context.dips[1] = Dip::Value( "Difficulty", 4, 1 ); 396 context.dips[1][0] = Dip::Value( "Easy", 0x00 ); 397 context.dips[1][1] = Dip::Value( "Normal", 0x08 ); 398 context.dips[1][2] = Dip::Value( "Hard", 0x10 ); 399 context.dips[1][3] = Dip::Value( "Very Hard", 0x18 ); 400 context.dips[2] = Dip::Value( "Misses per Game", 2, 1 ); 401 context.dips[2][0] = Dip::Value( "3", 0x00 ); 402 context.dips[2][1] = Dip::Value( "5", 0x20 ); 403 context.dips[3] = Dip::Value( "Bonus Life", 4, 0 ); 404 context.dips[3][0] = Dip::Value( "30000", 0x00 ); 405 context.dips[3][1] = Dip::Value( "50000", 0x40 ); 406 context.dips[3][2] = Dip::Value( "80000", 0x80 ); 407 context.dips[3][3] = Dip::Value( "100000", 0xC0 ); 408 409 break; 410 411 case 0x16D3F469: // Ninja Jajamaru Kun (J) 412 413 context.SetDips(5); 414 context.dips[0] = Dip::Value( "Coinage", 8, 0 ); 415 context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); 416 context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); 417 context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); 418 context.dips[0][3] = Dip::Value( "1 Coin / 4 Credits", 0x06 ); 419 context.dips[0][4] = Dip::Value( "2 Coins / 1 Credit", 0x01 ); 420 context.dips[0][5] = Dip::Value( "3 Coins / 1 Credit", 0x05 ); 421 context.dips[0][6] = Dip::Value( "4 Coins / 1 Credit", 0x03 ); 422 context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); 423 context.dips[1] = Dip::Value( "Lives", 3, 0 ); 424 context.dips[1][0] = Dip::Value( "3", 0x00 ); 425 context.dips[1][1] = Dip::Value( "4", 0x10 ); 426 context.dips[1][2] = Dip::Value( "5", 0x08 ); 427 context.dips[2] = Dip::Value( "Unknown/Unused", 2, 0 ); 428 context.dips[2][0] = Dip::Value( "Off", 0x00 ); 429 context.dips[2][1] = Dip::Value( "On", 0x20 ); 430 context.dips[3] = Dip::Value( "Unknown/Unused", 2, 0 ); 431 context.dips[3][0] = Dip::Value( "Off", 0x00 ); 432 context.dips[3][1] = Dip::Value( "On", 0x40 ); 433 context.dips[4] = Dip::Value( "Demo Sounds", 2, 1 ); 434 context.dips[4][0] = Dip::Value( "Off", 0x00 ); 435 context.dips[4][1] = Dip::Value( "On", 0x80 ); 436 437 context.ppuModel = PPU_RC2C05_01; 438 context.inputMapper = InputMapper::TYPE_3; 439 break; 440 441 case 0x8850924B: // Tetris 442 443 context.SetDips(6); 444 context.dips[0] = Dip::Value( "Coinage", 4, 0 ); 445 context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); 446 context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x02 ); 447 context.dips[0][2] = Dip::Value( "2 Coins / 1 Credit", 0x01 ); 448 context.dips[0][3] = Dip::Value( "3 Coins / 1 Credit", 0x03 ); 449 context.dips[1] = Dip::Value( "Unknown/Unused", 2, 0 ); 450 context.dips[1][0] = Dip::Value( "Off", 0x00 ); 451 context.dips[1][1] = Dip::Value( "On", 0x04 ); 452 context.dips[2] = Dip::Value( "Unknown/Unused", 2, 0 ); 453 context.dips[2][0] = Dip::Value( "Off", 0x00 ); 454 context.dips[2][1] = Dip::Value( "On", 0x08 ); 455 context.dips[3] = Dip::Value( "Unknown/Unused", 2, 0 ); 456 context.dips[3][0] = Dip::Value( "Off", 0x00 ); 457 context.dips[3][1] = Dip::Value( "On", 0x10 ); 458 context.dips[4] = Dip::Value( "Palette Color", 3, 2 ); 459 context.dips[4][0] = Dip::Value( "Black", 0x40 ); 460 context.dips[4][1] = Dip::Value( "Green", 0x20 ); 461 context.dips[4][2] = Dip::Value( "Grey", 0x60 ); 462 context.dips[5] = Dip::Value( "Unknown/Unused", 2, 0 ); 463 context.dips[5][0] = Dip::Value( "Off", 0x00 ); 464 context.dips[5][1] = Dip::Value( "On", 0x80 ); 465 466 context.inputMapper = InputMapper::TYPE_2; 467 break; 468 469 case 0x8C0C2DF5: // Top Gun 470 471 context.SetDips(5); 472 context.dips[0] = Dip::Value( "Coinage", 8, 0 ); 473 context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); 474 context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); 475 context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); 476 context.dips[0][3] = Dip::Value( "2 Coins / 1 Credit", 0x06 ); 477 context.dips[0][4] = Dip::Value( "3 Coins / 1 Credit", 0x01 ); 478 context.dips[0][5] = Dip::Value( "4 Coins / 1 Credit", 0x05 ); 479 context.dips[0][6] = Dip::Value( "5 Coins / 1 Credit", 0x03 ); 480 context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); 481 context.dips[1] = Dip::Value( "Lives per Coin", 2, 0 ); 482 context.dips[1][0] = Dip::Value( "3 - 12 Max", 0x00 ); 483 context.dips[1][1] = Dip::Value( "2 - 9 Max", 0x08 ); 484 context.dips[2] = Dip::Value( "Bonus", 4, 0 ); 485 context.dips[2][0] = Dip::Value( "30k and every 50k", 0x00 ); 486 context.dips[2][1] = Dip::Value( "50k and every 100k", 0x20 ); 487 context.dips[2][2] = Dip::Value( "100k and every 150k", 0x10 ); 488 context.dips[2][3] = Dip::Value( "200k and every 200k", 0x30 ); 489 context.dips[3] = Dip::Value( "Difficulty", 2, 0 ); 490 context.dips[3][0] = Dip::Value( "Normal", 0x00 ); 491 context.dips[3][1] = Dip::Value( "Hard", 0x40 ); 492 context.dips[4] = Dip::Value( "Demo Sounds", 2, 1 ); 493 context.dips[4][0] = Dip::Value( "Off", 0x00 ); 494 context.dips[4][1] = Dip::Value( "On", 0x80 ); 495 496 context.ppuModel = PPU_RC2C05_04; 497 context.inputMapper = InputMapper::TYPE_1; 498 break; 499 500 case 0x70901B25: // Slalom 501 502 context.SetDips(5); 503 context.dips[0] = Dip::Value( "Coinage", 8, 0 ); 504 context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); 505 context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); 506 context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); 507 context.dips[0][3] = Dip::Value( "2 Coins / 1 Credit", 0x06 ); 508 context.dips[0][4] = Dip::Value( "3 Coins / 1 Credit", 0x01 ); 509 context.dips[0][5] = Dip::Value( "4 Coins / 1 Credit", 0x05 ); 510 context.dips[0][6] = Dip::Value( "5 Coins / 1 Credit", 0x03 ); 511 context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); 512 context.dips[1] = Dip::Value( "Freestyle Points", 2, 0 ); 513 context.dips[1][0] = Dip::Value( "Left / Right", 0x00 ); 514 context.dips[1][1] = Dip::Value( "Hold Time", 0x08 ); 515 context.dips[2] = Dip::Value( "Difficulty", 4, 1 ); 516 context.dips[2][0] = Dip::Value( "Easy", 0x00 ); 517 context.dips[2][1] = Dip::Value( "Normal", 0x10 ); 518 context.dips[2][2] = Dip::Value( "Hard", 0x20 ); 519 context.dips[2][3] = Dip::Value( "Hardest", 0x30 ); 520 context.dips[3] = Dip::Value( "Allow Continue", 2, 1 ); 521 context.dips[3][0] = Dip::Value( "No", 0x40 ); 522 context.dips[3][1] = Dip::Value( "Yes", 0x00 ); 523 context.dips[4] = Dip::Value( "Inverted input", 2, 0 ); 524 context.dips[4][0] = Dip::Value( "Off", 0x00 ); 525 context.dips[4][1] = Dip::Value( "On", 0x80 ); 526 527 context.ppuModel = PPU_RP2C04_0002; 528 context.inputMapper = InputMapper::TYPE_1; 529 break; 530 531 case 0xCF36261E: // Super Sky Kid 532 533 context.SetDips(5); 534 context.dips[0] = Dip::Value( "Unknown/Unused", 2, 0 ); 535 context.dips[0][0] = Dip::Value( "Off", 0x00 ); 536 context.dips[0][1] = Dip::Value( "On", 0x01 ); 537 context.dips[1] = Dip::Value( "Unknown/Unused", 2, 0 ); 538 context.dips[1][0] = Dip::Value( "Off", 0x00 ); 539 context.dips[1][1] = Dip::Value( "On", 0x02 ); 540 context.dips[2] = Dip::Value( "Lives", 2, 0 ); 541 context.dips[2][0] = Dip::Value( "2", 0x00 ); 542 context.dips[2][1] = Dip::Value( "3", 0x04 ); 543 context.dips[3] = Dip::Value( "Coinage", 4, 0 ); 544 context.dips[3][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); 545 context.dips[3][1] = Dip::Value( "1 Coin / 2 Credits", 0x08 ); 546 context.dips[3][2] = Dip::Value( "2 Coins / 1 Credit", 0x10 ); 547 context.dips[3][3] = Dip::Value( "3 Coins / 1 Credit", 0x18 ); 548 context.dips[4] = Dip::Value( "PPU", 5, 0 ); 549 context.dips[4][0] = Dip::Value( "RP2C03", 0x20 ); 550 context.dips[4][1] = Dip::Value( "RP2C04-0001", 0x00 ); 551 context.dips[4][2] = Dip::Value( "RP2C04-0002", 0x40 ); 552 context.dips[4][3] = Dip::Value( "RP2C04-0003", 0x80 ); 553 context.dips[4][4] = Dip::Value( "RP2C04-0004", 0xC0 ); 554 555 context.inputMapper = InputMapper::TYPE_3; 556 break; 557 558 case 0xE1AA8214: // Star Luster 559 560 context.SetDips(6); 561 context.dips[0] = Dip::Value( "Coinage", 4, 0 ); 562 context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); 563 context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x02 ); 564 context.dips[0][2] = Dip::Value( "2 Coins / 1 Credit", 0x01 ); 565 context.dips[0][3] = Dip::Value( "3 Coins / 1 Credit", 0x03 ); 566 context.dips[1] = Dip::Value( "Unknown/Unused", 2, 0 ); 567 context.dips[1][0] = Dip::Value( "Off", 0x00 ); 568 context.dips[1][1] = Dip::Value( "On", 0x04 ); 569 context.dips[2] = Dip::Value( "Unknown/Unused", 2, 0 ); 570 context.dips[2][0] = Dip::Value( "Off", 0x00 ); 571 context.dips[2][1] = Dip::Value( "On", 0x08 ); 572 context.dips[3] = Dip::Value( "Unknown/Unused", 2, 0 ); 573 context.dips[3][0] = Dip::Value( "Off", 0x00 ); 574 context.dips[3][1] = Dip::Value( "On", 0x10 ); 575 context.dips[4] = Dip::Value( "Palette Color", 3, 0 ); 576 context.dips[4][0] = Dip::Value( "Black", 0x40 ); 577 context.dips[4][1] = Dip::Value( "Green", 0x20 ); 578 context.dips[4][2] = Dip::Value( "Grey", 0x60 ); 579 context.dips[5] = Dip::Value( "Unknown/Unused", 2, 0 ); 580 context.dips[5][0] = Dip::Value( "Off", 0x00 ); 581 context.dips[5][1] = Dip::Value( "On", 0x80 ); 582 583 context.inputMapper = InputMapper::TYPE_1; 584 break; 585 586 case 0xD5D7EAC4: // Dr. Mario 587 588 context.SetDips(5); 589 context.dips[0] = Dip::Value( "Drop Rate Increases After", 4, 0 ); 590 context.dips[0][0] = Dip::Value( "7 Pills", 0x00 ); 591 context.dips[0][1] = Dip::Value( "8 Pills", 0x01 ); 592 context.dips[0][2] = Dip::Value( "9 Pills", 0x02 ); 593 context.dips[0][3] = Dip::Value( "10 Pills", 0x03 ); 594 context.dips[1] = Dip::Value( "Virus Level", 4, 0 ); 595 context.dips[1][0] = Dip::Value( "1", 0x00 ); 596 context.dips[1][1] = Dip::Value( "3", 0x04 ); 597 context.dips[1][2] = Dip::Value( "5", 0x08 ); 598 context.dips[1][3] = Dip::Value( "7", 0x0C ); 599 context.dips[2] = Dip::Value( "Drop Speed Up", 4, 0 ); 600 context.dips[2][0] = Dip::Value( "Slow", 0x00 ); 601 context.dips[2][1] = Dip::Value( "Medium", 0x10 ); 602 context.dips[2][2] = Dip::Value( "Fast", 0x20 ); 603 context.dips[2][3] = Dip::Value( "Fastest", 0x30 ); 604 context.dips[3] = Dip::Value( "Free Play", 2, 0 ); 605 context.dips[3][0] = Dip::Value( "Off", 0x00 ); 606 context.dips[3][1] = Dip::Value( "On", 0x40 ); 607 context.dips[4] = Dip::Value( "Demo Sounds", 2, 1 ); 608 context.dips[4][0] = Dip::Value( "Off", 0x00 ); 609 context.dips[4][1] = Dip::Value( "On", 0x80 ); 610 611 context.ppuModel = PPU_RP2C04_0003; 612 context.inputMapper = InputMapper::TYPE_2; 613 break; 614 615 case 0xFFBEF374: // Castlevania 616 617 context.SetDips(4); 618 context.dips[0] = Dip::Value( "Coinage", 8, 0 ); 619 context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); 620 context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); 621 context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); 622 context.dips[0][3] = Dip::Value( "2 Coins / 1 Credit", 0x06 ); 623 context.dips[0][4] = Dip::Value( "3 Coins / 1 Credit", 0x01 ); 624 context.dips[0][5] = Dip::Value( "4 Coins / 1 Credit", 0x05 ); 625 context.dips[0][6] = Dip::Value( "5 Coins / 1 Credit", 0x03 ); 626 context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); 627 context.dips[1] = Dip::Value( "Lives", 2, 1 ); 628 context.dips[1][0] = Dip::Value( "2", 0x08 ); 629 context.dips[1][1] = Dip::Value( "3", 0x00 ); 630 context.dips[2] = Dip::Value( "Bonus", 4, 0 ); 631 context.dips[2][0] = Dip::Value( "100k", 0x00 ); 632 context.dips[2][1] = Dip::Value( "200k", 0x20 ); 633 context.dips[2][2] = Dip::Value( "300k", 0x10 ); 634 context.dips[2][3] = Dip::Value( "400k", 0x30 ); 635 context.dips[3] = Dip::Value( "Difficulty", 2, 0 ); 636 context.dips[3][0] = Dip::Value( "Normal", 0x00 ); 637 context.dips[3][1] = Dip::Value( "Hard", 0x40 ); 638 639 context.ppuModel = PPU_RP2C04_0002; 640 context.inputMapper = InputMapper::TYPE_1; 641 break; 642 643 case 0xE2C0A2BE: // Platoon 644 645 context.SetDips(6); 646 context.dips[0] = Dip::Value( "Unknown/Unused", 2, 0 ); 647 context.dips[0][0] = Dip::Value( "Off", 0x00 ); 648 context.dips[0][1] = Dip::Value( "On", 0x01 ); 649 context.dips[1] = Dip::Value( "Unknown/Unused", 2, 0 ); 650 context.dips[1][0] = Dip::Value( "Off", 0x00 ); 651 context.dips[1][1] = Dip::Value( "On", 0x02 ); 652 context.dips[2] = Dip::Value( "Demo Sounds", 2, 1 ); 653 context.dips[2][0] = Dip::Value( "Off", 0x00 ); 654 context.dips[2][1] = Dip::Value( "On", 0x04 ); 655 context.dips[3] = Dip::Value( "Unknown/Unused", 2, 0 ); 656 context.dips[3][0] = Dip::Value( "Off", 0x00 ); 657 context.dips[3][1] = Dip::Value( "On", 0x08 ); 658 context.dips[4] = Dip::Value( "Unknown/Unused", 2, 0 ); 659 context.dips[4][0] = Dip::Value( "Off", 0x00 ); 660 context.dips[4][1] = Dip::Value( "On", 0x10 ); 661 context.dips[5] = Dip::Value( "Coinage", 8, 0 ); 662 context.dips[5][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); 663 context.dips[5][1] = Dip::Value( "1 Coin / 2 Credits", 0x20 ); 664 context.dips[5][2] = Dip::Value( "1 Coin / 3 Credits", 0x40 ); 665 context.dips[5][3] = Dip::Value( "2 Coins / 1 Credit", 0x60 ); 666 context.dips[5][4] = Dip::Value( "3 Coins / 1 Credit", 0x80 ); 667 context.dips[5][5] = Dip::Value( "4 Coins / 1 Credit", 0xA0 ); 668 context.dips[5][6] = Dip::Value( "5 Coins / 1 Credit", 0xC0 ); 669 context.dips[5][7] = Dip::Value( "Free Play", 0xE0 ); 670 671 context.ppuModel = PPU_RP2C04_0001; 672 context.inputMapper = InputMapper::TYPE_1; 673 break; 674 675 case 0xCBE85490: // Excitebike 676 case 0x29155E0C: // Excitebike (alt) 677 678 context.SetDips(4); 679 context.dips[0] = Dip::Value( "Coinage", 8, 0 ); 680 context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); 681 context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); 682 context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); 683 context.dips[0][3] = Dip::Value( "1 Coin / 4 Credits", 0x06 ); 684 context.dips[0][4] = Dip::Value( "2 Coins / 1 Credit", 0x01 ); 685 context.dips[0][5] = Dip::Value( "3 Coins / 1 Credit", 0x05 ); 686 context.dips[0][6] = Dip::Value( "4 Coins / 1 Credit", 0x03 ); 687 context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); 688 context.dips[1] = Dip::Value( "Bonus", 4, 0 ); 689 context.dips[1][0] = Dip::Value( "100k and Every 50k", 0x00 ); 690 context.dips[1][1] = Dip::Value( "Every 100k", 0x10 ); 691 context.dips[1][2] = Dip::Value( "100k Only", 0x08 ); 692 context.dips[1][3] = Dip::Value( "None", 0x18 ); 693 context.dips[2] = Dip::Value( "1st Half Qualifying Time", 2, 0 ); 694 context.dips[2][0] = Dip::Value( "Normal", 0x00 ); 695 context.dips[2][1] = Dip::Value( "Hard", 0x20 ); 696 context.dips[3] = Dip::Value( "2nd Half Qualifying Time", 2, 0 ); 697 context.dips[3][0] = Dip::Value( "Normal", 0x00 ); 698 context.dips[3][1] = Dip::Value( "Hard", 0x40 ); 699 700 if (prgCrc == 0x29155E0C) 701 context.ppuModel = PPU_RP2C04_0004; 702 else 703 context.ppuModel = PPU_RP2C04_0003; 704 705 context.inputMapper = InputMapper::TYPE_1; 706 break; 707 708 case 0x07138C06: // Clu Clu Land 709 710 context.SetDips(5); 711 context.dips[0] = Dip::Value( "Coinage", 8, 0 ); 712 context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); 713 context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); 714 context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); 715 context.dips[0][3] = Dip::Value( "1 Coin / 4 Credits", 0x06 ); 716 context.dips[0][4] = Dip::Value( "2 Coins / 1 Credit", 0x01 ); 717 context.dips[0][5] = Dip::Value( "3 Coins / 1 Credit", 0x05 ); 718 context.dips[0][6] = Dip::Value( "4 Coins / 1 Credit", 0x03 ); 719 context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); 720 context.dips[1] = Dip::Value( "Unknown/Unused", 2, 0 ); 721 context.dips[1][0] = Dip::Value( "Off", 0x00 ); 722 context.dips[1][1] = Dip::Value( "On", 0x08 ); 723 context.dips[2] = Dip::Value( "Unknown/Unused", 2, 0 ); 724 context.dips[2][0] = Dip::Value( "Off", 0x00 ); 725 context.dips[2][1] = Dip::Value( "On", 0x10 ); 726 context.dips[3] = Dip::Value( "Lives", 4, 1 ); 727 context.dips[3][0] = Dip::Value( "2", 0x60 ); 728 context.dips[3][1] = Dip::Value( "3", 0x00 ); 729 context.dips[3][2] = Dip::Value( "4", 0x40 ); 730 context.dips[3][3] = Dip::Value( "5", 0x20 ); 731 context.dips[4] = Dip::Value( "Unknown/Unused", 2, 0 ); 732 context.dips[4][0] = Dip::Value( "Off", 0x00 ); 733 context.dips[4][1] = Dip::Value( "On", 0x80 ); 734 735 context.ppuModel = PPU_RP2C04_0004; 736 context.inputMapper = InputMapper::TYPE_2; 737 break; 738 739 case 0x43A357EF: // Ice Climber 740 case 0xD4EB5923: // -||- 741 742 context.SetDips(4); 743 context.dips[0] = Dip::Value( "Coinage", 8, 0 ); 744 context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); 745 context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); 746 context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); 747 context.dips[0][3] = Dip::Value( "1 Coin / 4 Credits", 0x06 ); 748 context.dips[0][4] = Dip::Value( "2 Coins / 1 Credit", 0x01 ); 749 context.dips[0][5] = Dip::Value( "3 Coins / 1 Credit", 0x05 ); 750 context.dips[0][6] = Dip::Value( "4 Coins / 1 Credit", 0x03 ); 751 context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); 752 context.dips[1] = Dip::Value( "Lives", 4, 0 ); 753 context.dips[1][0] = Dip::Value( "3", 0x00 ); 754 context.dips[1][1] = Dip::Value( "4", 0x10 ); 755 context.dips[1][2] = Dip::Value( "5", 0x08 ); 756 context.dips[1][3] = Dip::Value( "7", 0x18 ); 757 context.dips[2] = Dip::Value( "Difficulty", 2, 0 ); 758 context.dips[2][0] = Dip::Value( "Normal", 0x00 ); 759 context.dips[2][1] = Dip::Value( "Hard", 0x20 ); 760 context.dips[3] = Dip::Value( "Time before the bear", 2, 0 ); 761 context.dips[3][0] = Dip::Value( "Long", 0x00 ); 762 context.dips[3][1] = Dip::Value( "Short", 0x40 ); 763 764 context.ppuModel = PPU_RP2C04_0004; 765 766 if (prgCrc == 0x43A357EF) 767 context.inputMapper = InputMapper::TYPE_2; 768 else 769 context.inputMapper = InputMapper::TYPE_4; 770 771 break; 772 773 case 0x737DD1BF: // Super Mario Bros 774 case 0x4BF3972D: // -||- 775 case 0x8B60CC58: // -||- 776 case 0x8192C804: // -||- 777 778 context.SetDips(5); 779 context.dips[0] = Dip::Value( "Coinage", 8, 0 ); 780 context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); 781 context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x06 ); 782 context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x01 ); 783 context.dips[0][3] = Dip::Value( "1 Coin / 4 Credits", 0x05 ); 784 context.dips[0][4] = Dip::Value( "1 Coin / 5 Credits", 0x03 ); 785 context.dips[0][5] = Dip::Value( "2 Coins / 1 Credit", 0x04 ); 786 context.dips[0][6] = Dip::Value( "3 Coins / 1 Credit", 0x02 ); 787 context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); 788 context.dips[1] = Dip::Value( "Lives", 2, 1 ); 789 context.dips[1][0] = Dip::Value( "2", 0x08 ); 790 context.dips[1][1] = Dip::Value( "3", 0x00 ); 791 context.dips[2] = Dip::Value( "Bonus Life", 4, 0 ); 792 context.dips[2][0] = Dip::Value( "100", 0x00 ); 793 context.dips[2][1] = Dip::Value( "150", 0x20 ); 794 context.dips[2][2] = Dip::Value( "200", 0x10 ); 795 context.dips[2][3] = Dip::Value( "250", 0x30 ); 796 context.dips[3] = Dip::Value( "Timer", 2, 0 ); 797 context.dips[3][0] = Dip::Value( "Normal", 0x00 ); 798 context.dips[3][1] = Dip::Value( "Fast", 0x40 ); 799 context.dips[4] = Dip::Value( "Continue Lives", 2, 0 ); 800 context.dips[4][0] = Dip::Value( "3", 0x80 ); 801 context.dips[4][1] = Dip::Value( "4", 0x00 ); 802 803 context.ppuModel = PPU_RP2C04_0004; 804 context.inputMapper = InputMapper::TYPE_1; 805 break; 806 807 case 0xEC461DB9: // Pinball 808 case 0xE528F651: // -||- (alt) 809 810 context.SetDips(5); 811 context.dips[0] = Dip::Value( "Coinage", 8, 0 ); 812 context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x01 ); 813 context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x06 ); 814 context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); 815 context.dips[0][3] = Dip::Value( "1 Coin / 4 Credits", 0x04 ); 816 context.dips[0][4] = Dip::Value( "2 Coins / 1 Credit", 0x05 ); 817 context.dips[0][5] = Dip::Value( "3 Coins / 1 Credit", 0x03 ); 818 context.dips[0][6] = Dip::Value( "4 Coins / 1 Credit", 0x07 ); 819 context.dips[0][7] = Dip::Value( "Free Play", 0x00 ); 820 context.dips[1] = Dip::Value( "Unknown/Unused", 2, 0 ); 821 context.dips[1][0] = Dip::Value( "Off", 0x00 ); 822 context.dips[1][1] = Dip::Value( "On", 0x08 ); 823 context.dips[2] = Dip::Value( "Unknown/Unused", 2, 0 ); 824 context.dips[2][0] = Dip::Value( "Off", 0x00 ); 825 context.dips[2][1] = Dip::Value( "On", 0x10 ); 826 context.dips[3] = Dip::Value( "Balls", 4, 1 ); 827 context.dips[3][0] = Dip::Value( "2", 0x60 ); 828 context.dips[3][1] = Dip::Value( "3", 0x00 ); 829 context.dips[3][2] = Dip::Value( "4", 0x40 ); 830 context.dips[3][3] = Dip::Value( "5", 0x20 ); 831 context.dips[4] = Dip::Value( "Ball Speed", 2, 0 ); 832 context.dips[4][0] = Dip::Value( "Normal", 0x00 ); 833 context.dips[4][1] = Dip::Value( "Fast", 0x80 ); 834 835 if (prgCrc == 0xEC461DB9) 836 { 837 context.ppuModel = PPU_RP2C04_0001; 838 context.inputMapper = InputMapper::TYPE_1; 839 } 840 else 841 { 842 context.inputMapper = InputMapper::TYPE_5; 843 } 844 break; 845 846 case 0xAE8063EF: // Mach Rider - Fighting Course 847 848 context.SetDips(5); 849 context.dips[0] = Dip::Value( "Coinage", 8, 0 ); 850 context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); 851 context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); 852 context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); 853 context.dips[0][3] = Dip::Value( "1 Coin / 4 Credits", 0x06 ); 854 context.dips[0][4] = Dip::Value( "2 Coins / 1 Credit", 0x01 ); 855 context.dips[0][5] = Dip::Value( "3 Coins / 1 Credit", 0x05 ); 856 context.dips[0][6] = Dip::Value( "4 Coins / 1 Credit", 0x03 ); 857 context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); 858 context.dips[1] = Dip::Value( "Km 1st Race", 2, 0 ); 859 context.dips[1][0] = Dip::Value( "12", 0x00 ); 860 context.dips[1][1] = Dip::Value( "15", 0x10 ); 861 context.dips[2] = Dip::Value( "Unknown/Unused", 2, 0 ); 862 context.dips[2][0] = Dip::Value( "Off", 0x00 ); 863 context.dips[2][1] = Dip::Value( "On", 0x20 ); 864 context.dips[3] = Dip::Value( "Unknown/Unused", 2, 0 ); 865 context.dips[3][0] = Dip::Value( "Off", 0x00 ); 866 context.dips[3][1] = Dip::Value( "On", 0x40 ); 867 context.dips[4] = Dip::Value( "Unknown/Unused", 2, 0 ); 868 context.dips[4][0] = Dip::Value( "Off", 0x00 ); 869 context.dips[4][1] = Dip::Value( "On", 0x80 ); 870 871 context.ppuModel = PPU_RP2C04_0001; 872 context.inputMapper = InputMapper::TYPE_1; 873 break; 874 875 case 0x0B65A917: // Mach Rider 876 case 0x8A6A9848: // -||- 877 878 context.SetDips(5); 879 context.dips[0] = Dip::Value( "Coinage", 8, 0 ); 880 context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); 881 context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); 882 context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); 883 context.dips[0][3] = Dip::Value( "1 Coin / 4 Credits", 0x06 ); 884 context.dips[0][4] = Dip::Value( "2 Coins / 1 Credit", 0x01 ); 885 context.dips[0][5] = Dip::Value( "3 Coins / 1 Credit", 0x05 ); 886 context.dips[0][6] = Dip::Value( "4 Coins / 1 Credit", 0x03 ); 887 context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); 888 context.dips[1] = Dip::Value( "Time", 4, 0 ); 889 context.dips[1][0] = Dip::Value( "280", 0x00 ); 890 context.dips[1][1] = Dip::Value( "250", 0x10 ); 891 context.dips[1][2] = Dip::Value( "220", 0x08 ); 892 context.dips[1][3] = Dip::Value( "200", 0x18 ); 893 context.dips[2] = Dip::Value( "Unknown/Unused", 2, 0 ); 894 context.dips[2][0] = Dip::Value( "Off", 0x00 ); 895 context.dips[2][1] = Dip::Value( "On", 0x20 ); 896 context.dips[3] = Dip::Value( "Unknown/Unused", 2, 0 ); 897 context.dips[3][0] = Dip::Value( "Off", 0x00 ); 898 context.dips[3][1] = Dip::Value( "On", 0x40 ); 899 context.dips[4] = Dip::Value( "Unknown/Unused", 2, 0 ); 900 context.dips[4][0] = Dip::Value( "Off", 0x00 ); 901 context.dips[4][1] = Dip::Value( "On", 0x80 ); 902 903 context.ppuModel = PPU_RP2C04_0002; 904 context.inputMapper = InputMapper::TYPE_1; 905 break; 906 907 case 0x46914E3E: // Soccer 908 909 context.SetDips(3); 910 context.dips[0] = Dip::Value( "Coinage", 8, 0 ); 911 context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); 912 context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); 913 context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); 914 context.dips[0][3] = Dip::Value( "1 Coin / 4 Credits", 0x06 ); 915 context.dips[0][4] = Dip::Value( "2 Coins / 1 Credit", 0x01 ); 916 context.dips[0][5] = Dip::Value( "3 Coins / 1 Credit", 0x05 ); 917 context.dips[0][6] = Dip::Value( "4 Coins / 1 Credit", 0x03 ); 918 context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); 919 context.dips[1] = Dip::Value( "Points Timer", 4, 2 ); 920 context.dips[1][0] = Dip::Value( "600 Pts", 0x00 ); 921 context.dips[1][1] = Dip::Value( "800 Pts", 0x10 ); 922 context.dips[1][2] = Dip::Value( "1000 Pts", 0x08 ); 923 context.dips[1][3] = Dip::Value( "1200 Pts", 0x18 ); 924 context.dips[2] = Dip::Value( "Difficulty", 4, 1 ); 925 context.dips[2][0] = Dip::Value( "Easy", 0x00 ); 926 context.dips[2][1] = Dip::Value( "Normal", 0x40 ); 927 context.dips[2][2] = Dip::Value( "Hard", 0x20 ); 928 context.dips[2][3] = Dip::Value( "Very Hard", 0x60 ); 929 930 context.ppuModel = PPU_RP2C04_0003; 931 context.inputMapper = InputMapper::TYPE_2; 932 break; 933 934 case 0x70433F2C: // Battle City 935 936 context.SetDips(7); 937 context.dips[0] = Dip::Value( "Credits for 2 Players", 2, 1 ); 938 context.dips[0][0] = Dip::Value( "1", 0x00 ); 939 context.dips[0][1] = Dip::Value( "2", 0x01 ); 940 context.dips[1] = Dip::Value( "Lives", 2, 0 ); 941 context.dips[1][0] = Dip::Value( "3", 0x00 ); 942 context.dips[1][1] = Dip::Value( "5", 0x02 ); 943 context.dips[2] = Dip::Value( "Demo Sounds", 2, 1 ); 944 context.dips[2][0] = Dip::Value( "Off", 0x00 ); 945 context.dips[2][1] = Dip::Value( "On", 0x04 ); 946 context.dips[3] = Dip::Value( "Unknown/Unused", 2, 0 ); 947 context.dips[3][0] = Dip::Value( "Off", 0x00 ); 948 context.dips[3][1] = Dip::Value( "On", 0x08 ); 949 context.dips[4] = Dip::Value( "Unknown/Unused", 2, 0 ); 950 context.dips[4][0] = Dip::Value( "Off", 0x00 ); 951 context.dips[4][1] = Dip::Value( "On", 0x10 ); 952 context.dips[5] = Dip::Value( "Unknown/Unused", 2, 0 ); 953 context.dips[5][0] = Dip::Value( "Off", 0x00 ); 954 context.dips[5][1] = Dip::Value( "On", 0x20 ); 955 context.dips[6] = Dip::Value( "PPU", 4, 0 ); 956 context.dips[6][0] = Dip::Value( "RP2C04-0001", 0x00 ); 957 context.dips[6][1] = Dip::Value( "RP2C04-0002", 0x40 ); 958 context.dips[6][2] = Dip::Value( "RP2C04-0003", 0x80 ); 959 context.dips[6][3] = Dip::Value( "RP2C04-0004", 0xC0 ); 960 961 context.ppuModel = PPU_RP2C04_0001; 962 context.inputMapper = InputMapper::TYPE_2; 963 break; 964 965 case 0xD99A2087: // Gradius 966 967 context.SetDips(5); 968 context.dips[0] = Dip::Value( "Coinage", 8, 0 ); 969 context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); 970 context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); 971 context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); 972 context.dips[0][3] = Dip::Value( "2 Coins / 1 Credit", 0x06 ); 973 context.dips[0][4] = Dip::Value( "3 Coins / 1 Credit", 0x01 ); 974 context.dips[0][5] = Dip::Value( "4 Coins / 1 Credit", 0x05 ); 975 context.dips[0][6] = Dip::Value( "5 Coins / 1 Credit", 0x03 ); 976 context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); 977 context.dips[1] = Dip::Value( "Lives", 2, 0 ); 978 context.dips[1][0] = Dip::Value( "3", 0x08 ); 979 context.dips[1][1] = Dip::Value( "4", 0x00 ); 980 context.dips[2] = Dip::Value( "Bonus", 4, 0 ); 981 context.dips[2][0] = Dip::Value( "100k", 0x00 ); 982 context.dips[2][1] = Dip::Value( "200k", 0x20 ); 983 context.dips[2][2] = Dip::Value( "300k", 0x10 ); 984 context.dips[2][3] = Dip::Value( "400k", 0x30 ); 985 context.dips[3] = Dip::Value( "Difficulty", 2, 0 ); 986 context.dips[3][0] = Dip::Value( "Normal", 0x00 ); 987 context.dips[3][1] = Dip::Value( "Hard", 0x40 ); 988 context.dips[4] = Dip::Value( "Demo Sounds", 2, 1 ); 989 context.dips[4][0] = Dip::Value( "Off", 0x00 ); 990 context.dips[4][1] = Dip::Value( "On", 0x80 ); 991 992 context.ppuModel = PPU_RP2C04_0001; 993 context.inputMapper = InputMapper::TYPE_2; 994 break; 995 996 case 0x1E438D52: // Goonies 997 998 context.SetDips(6); 999 context.dips[0] = Dip::Value( "Coinage", 8, 0 ); 1000 context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); 1001 context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); 1002 context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); 1003 context.dips[0][3] = Dip::Value( "2 Coins / 1 Credit", 0x06 ); 1004 context.dips[0][4] = Dip::Value( "3 Coins / 1 Credit", 0x01 ); 1005 context.dips[0][5] = Dip::Value( "4 Coins / 1 Credit", 0x05 ); 1006 context.dips[0][6] = Dip::Value( "5 Coins / 1 Credit", 0x03 ); 1007 context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); 1008 context.dips[1] = Dip::Value( "Lives", 2, 0 ); 1009 context.dips[1][0] = Dip::Value( "3", 0x00 ); 1010 context.dips[1][1] = Dip::Value( "2", 0x08 ); 1011 context.dips[2] = Dip::Value( "Unknown/Unused", 2, 0 ); 1012 context.dips[2][0] = Dip::Value( "Off", 0x00 ); 1013 context.dips[2][1] = Dip::Value( "On", 0x10 ); 1014 context.dips[3] = Dip::Value( "Unknown/Unused", 2, 0 ); 1015 context.dips[3][0] = Dip::Value( "Off", 0x00 ); 1016 context.dips[3][1] = Dip::Value( "On", 0x20 ); 1017 context.dips[4] = Dip::Value( "Timer", 2, 0 ); 1018 context.dips[4][0] = Dip::Value( "Normal", 0x00 ); 1019 context.dips[4][1] = Dip::Value( "Fast", 0x40 ); 1020 context.dips[5] = Dip::Value( "Demo Sounds", 2, 1 ); 1021 context.dips[5][0] = Dip::Value( "Off", 0x00 ); 1022 context.dips[5][1] = Dip::Value( "On", 0x80 ); 1023 1024 context.ppuModel = PPU_RP2C04_0003; 1025 context.inputMapper = InputMapper::TYPE_1; 1026 break; 1027 1028 case 0xFF5135A3: // Hogan's Alley 1029 1030 context.SetDips(4); 1031 context.dips[0] = Dip::Value( "Coinage", 8, 0 ); 1032 context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); 1033 context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); 1034 context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); 1035 context.dips[0][3] = Dip::Value( "2 Coins / 1 Credit", 0x06 ); 1036 context.dips[0][4] = Dip::Value( "3 Coins / 1 Credit", 0x01 ); 1037 context.dips[0][5] = Dip::Value( "4 Coins / 1 Credit", 0x05 ); 1038 context.dips[0][6] = Dip::Value( "5 Coins / 1 Credit", 0x03 ); 1039 context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); 1040 context.dips[1] = Dip::Value( "Difficulty", 4, 1 ); 1041 context.dips[1][0] = Dip::Value( "Easy", 0x00 ); 1042 context.dips[1][1] = Dip::Value( "Normal", 0x08 ); 1043 context.dips[1][2] = Dip::Value( "Hard", 0x10 ); 1044 context.dips[1][3] = Dip::Value( "Very Hard", 0x18 ); 1045 context.dips[2] = Dip::Value( "Misses per Game", 2, 1 ); 1046 context.dips[2][0] = Dip::Value( "3", 0x00 ); 1047 context.dips[2][1] = Dip::Value( "5", 0x20 ); 1048 context.dips[3] = Dip::Value( "Bonus Life", 4, 0 ); 1049 context.dips[3][0] = Dip::Value( "30000", 0x00 ); 1050 context.dips[3][1] = Dip::Value( "50000", 0x40 ); 1051 context.dips[3][2] = Dip::Value( "80000", 0x80 ); 1052 context.dips[3][3] = Dip::Value( "100000", 0xC0 ); 1053 1054 context.ppuModel = PPU_RP2C04_0001; 1055 break; 1056 1057 case 0x17AE56BE: // Freedom Force 1058 1059 context.SetDips(6); 1060 context.dips[0] = Dip::Value( "Coinage", 8, 0 ); 1061 context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); 1062 context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); 1063 context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); 1064 context.dips[0][3] = Dip::Value( "2 Coins / 1 Credit", 0x06 ); 1065 context.dips[0][4] = Dip::Value( "3 Coins / 1 Credit", 0x01 ); 1066 context.dips[0][5] = Dip::Value( "4 Coins / 1 Credit", 0x05 ); 1067 context.dips[0][6] = Dip::Value( "5 Coins / 1 Credit", 0x03 ); 1068 context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); 1069 context.dips[1] = Dip::Value( "Unknown/Unused", 2, 0 ); 1070 context.dips[1][0] = Dip::Value( "Off", 0x00 ); 1071 context.dips[1][1] = Dip::Value( "On", 0x08 ); 1072 context.dips[2] = Dip::Value( "Unknown/Unused", 2, 0 ); 1073 context.dips[2][0] = Dip::Value( "Off", 0x00 ); 1074 context.dips[2][1] = Dip::Value( "On", 0x10 ); 1075 context.dips[3] = Dip::Value( "Unknown/Unused", 2, 0 ); 1076 context.dips[3][0] = Dip::Value( "Off", 0x00 ); 1077 context.dips[3][1] = Dip::Value( "On", 0x20 ); 1078 context.dips[4] = Dip::Value( "Unknown/Unused", 2, 0 ); 1079 context.dips[4][0] = Dip::Value( "Off", 0x00 ); 1080 context.dips[4][1] = Dip::Value( "On", 0x40 ); 1081 context.dips[5] = Dip::Value( "Unknown/Unused", 2, 0 ); 1082 context.dips[5][0] = Dip::Value( "Off", 0x00 ); 1083 context.dips[5][1] = Dip::Value( "On", 0x80 ); 1084 1085 context.ppuModel = PPU_RP2C04_0001; 1086 break; 1087 1088 case 0xC99EC059: // Raid on Bungeling Bay 1089 1090 context.SetDips(6); 1091 context.dips[0] = Dip::Value( "Coinage", 8, 0 ); 1092 context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); 1093 context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); 1094 context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); 1095 context.dips[0][3] = Dip::Value( "1 Coin / 4 Credits", 0x06 ); 1096 context.dips[0][4] = Dip::Value( "2 Coins / 1 Credit", 0x01 ); 1097 context.dips[0][5] = Dip::Value( "3 Coins / 1 Credit", 0x05 ); 1098 context.dips[0][6] = Dip::Value( "4 Coins / 1 Credit", 0x03 ); 1099 context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); 1100 context.dips[1] = Dip::Value( "Lives", 2, 0 ); 1101 context.dips[1][0] = Dip::Value( "2", 0x00 ); 1102 context.dips[1][1] = Dip::Value( "3", 0x08 ); 1103 context.dips[2] = Dip::Value( "Unknown/Unused", 2, 0 ); 1104 context.dips[2][0] = Dip::Value( "Off", 0x00 ); 1105 context.dips[2][1] = Dip::Value( "On", 0x10 ); 1106 context.dips[3] = Dip::Value( "Unknown/Unused", 2, 0 ); 1107 context.dips[3][0] = Dip::Value( "Off", 0x00 ); 1108 context.dips[3][1] = Dip::Value( "On", 0x20 ); 1109 context.dips[4] = Dip::Value( "Unknown/Unused", 2, 0 ); 1110 context.dips[4][0] = Dip::Value( "Off", 0x00 ); 1111 context.dips[4][1] = Dip::Value( "On", 0x40 ); 1112 context.dips[5] = Dip::Value( "Unknown/Unused", 2, 0 ); 1113 context.dips[5][0] = Dip::Value( "Off", 0x00 ); 1114 context.dips[5][1] = Dip::Value( "On", 0x80 ); 1115 1116 context.ppuModel = PPU_RP2C04_0002; 1117 context.inputMapper = InputMapper::TYPE_4; 1118 break; 1119 1120 case 0xF9D3B0A3: // Super Xevious 1121 case 0x66BB838F: // -||- 1122 case 0x9924980A: // -||- 1123 1124 context.SetDips(6); 1125 context.dips[0] = Dip::Value( "Unknown/Unused", 2, 0 ); 1126 context.dips[0][0] = Dip::Value( "Off", 0x00 ); 1127 context.dips[0][1] = Dip::Value( "On", 0x01 ); 1128 context.dips[1] = Dip::Value( "Unknown/Unused", 2, 0 ); 1129 context.dips[1][0] = Dip::Value( "Off", 0x00 ); 1130 context.dips[1][1] = Dip::Value( "On", 0x02 ); 1131 context.dips[2] = Dip::Value( "Unknown/Unused", 2, 0 ); 1132 context.dips[2][0] = Dip::Value( "Off", 0x00 ); 1133 context.dips[2][1] = Dip::Value( "On", 0x04 ); 1134 context.dips[3] = Dip::Value( "Unknown/Unused", 2, 0 ); 1135 context.dips[3][0] = Dip::Value( "Off", 0x00 ); 1136 context.dips[3][1] = Dip::Value( "On", 0x08 ); 1137 context.dips[4] = Dip::Value( "Coinage", 4, 0 ); 1138 context.dips[4][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); 1139 context.dips[4][1] = Dip::Value( "1 Coin / 2 Credits", 0x10 ); 1140 context.dips[4][2] = Dip::Value( "2 Coins / 1 Credit", 0x20 ); 1141 context.dips[4][3] = Dip::Value( "3 Coins / 1 Credit", 0x30 ); 1142 context.dips[5] = Dip::Value( "PPU", 4, 0 ); 1143 context.dips[5][0] = Dip::Value( "RP2C04-0001", 0x00 ); 1144 context.dips[5][1] = Dip::Value( "RP2C04-0002", 0x40 ); 1145 context.dips[5][2] = Dip::Value( "RP2C04-0003", 0x80 ); 1146 context.dips[5][3] = Dip::Value( "RP2C04-0004", 0xC0 ); 1147 1148 context.inputMapper = InputMapper::TYPE_1; 1149 context.ppuModel = PPU_RP2C04_0001; 1150 context.mode = MODE_XEV; 1151 break; 1152 1153 case 0xCC2C4B5D: // Golf (J) 1154 case 0x86167220: // Lady Golf 1155 1156 context.ppuModel = PPU_RP2C04_0002; 1157 1158 case 0xA93A5AEE: // Golf 1159 1160 context.SetDips(5); 1161 context.dips[0] = Dip::Value( "Coinage", 8, 0 ); 1162 context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x01 ); 1163 context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x06 ); 1164 context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); 1165 context.dips[0][3] = Dip::Value( "1 Coin / 4 Credits", 0x04 ); 1166 context.dips[0][4] = Dip::Value( "2 Coins / 1 Credit", 0x05 ); 1167 context.dips[0][5] = Dip::Value( "3 Coins / 1 Credit", 0x03 ); 1168 context.dips[0][6] = Dip::Value( "4 Coins / 1 Credit", 0x07 ); 1169 context.dips[0][7] = Dip::Value( "Free Play", 0x00 ); 1170 context.dips[1] = Dip::Value( "Hole Size", 2, 0 ); 1171 context.dips[1][0] = Dip::Value( "Large", 0x00 ); 1172 context.dips[1][1] = Dip::Value( "Small", 0x08 ); 1173 context.dips[2] = Dip::Value( "Points per Stroke", 2, 0 ); 1174 context.dips[2][0] = Dip::Value( "Easier", 0x00 ); 1175 context.dips[2][1] = Dip::Value( "Harder", 0x10 ); 1176 context.dips[3] = Dip::Value( "Starting Points", 4, 0 ); 1177 context.dips[3][0] = Dip::Value( "10", 0x00 ); 1178 context.dips[3][1] = Dip::Value( "13", 0x40 ); 1179 context.dips[3][2] = Dip::Value( "16", 0x20 ); 1180 context.dips[3][3] = Dip::Value( "20", 0x60 ); 1181 context.dips[4] = Dip::Value( "Difficulty Vs. Computer", 2, 0 ); 1182 context.dips[4][0] = Dip::Value( "Easy", 0x00 ); 1183 context.dips[4][1] = Dip::Value( "Hard", 0x80 ); 1184 1185 context.inputMapper = InputMapper::TYPE_2; 1186 break; 1187 1188 case 0xCA85E56D: // Mighty Bomb Jack 1189 1190 context.SetDips(5); 1191 context.dips[0] = Dip::Value( "Coinage", 8, 0 ); 1192 context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); 1193 context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); 1194 context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); 1195 context.dips[0][3] = Dip::Value( "1 Coin / 4 Credits", 0x06 ); 1196 context.dips[0][4] = Dip::Value( "2 Coins / 1 Credit", 0x01 ); 1197 context.dips[0][5] = Dip::Value( "3 Coins / 1 Credit", 0x05 ); 1198 context.dips[0][6] = Dip::Value( "4 Coins / 1 Credit", 0x03 ); 1199 context.dips[0][7] = Dip::Value( "5 Coins / 1 Credit", 0x07 ); 1200 context.dips[1] = Dip::Value( "Lives", 4, 0 ); 1201 context.dips[1][0] = Dip::Value( "2", 0x10 ); 1202 context.dips[1][1] = Dip::Value( "3", 0x00 ); 1203 context.dips[1][2] = Dip::Value( "4", 0x08 ); 1204 context.dips[1][3] = Dip::Value( "5", 0x18 ); 1205 context.dips[2] = Dip::Value( "Unknown/Unused", 2, 0 ); 1206 context.dips[2][0] = Dip::Value( "Off", 0x00 ); 1207 context.dips[2][1] = Dip::Value( "On", 0x20 ); 1208 context.dips[3] = Dip::Value( "Unknown/Unused", 2, 0 ); 1209 context.dips[3][0] = Dip::Value( "Off", 0x00 ); 1210 context.dips[3][1] = Dip::Value( "On", 0x40 ); 1211 context.dips[4] = Dip::Value( "Unknown/Unused", 2, 0 ); 1212 context.dips[4][0] = Dip::Value( "Off", 0x00 ); 1213 context.dips[4][1] = Dip::Value( "On", 0x80 ); 1214 1215 context.ppuModel = PPU_RC2C05_02; 1216 context.inputMapper = InputMapper::TYPE_1; 1217 break; 1218 1219 case 0xFE446787: // Gumshoe 1220 1221 context.SetDips(5); 1222 context.dips[0] = Dip::Value( "Coinage", 8, 0 ); 1223 context.dips[0][0] = Dip::Value( "1 Coin / 1 Credit", 0x00 ); 1224 context.dips[0][1] = Dip::Value( "1 Coin / 2 Credits", 0x04 ); 1225 context.dips[0][2] = Dip::Value( "1 Coin / 3 Credits", 0x02 ); 1226 context.dips[0][3] = Dip::Value( "2 Coins / 1 Credit", 0x06 ); 1227 context.dips[0][4] = Dip::Value( "3 Coins / 1 Credit", 0x01 ); 1228 context.dips[0][5] = Dip::Value( "4 Coins / 1 Credit", 0x05 ); 1229 context.dips[0][6] = Dip::Value( "5 Coins / 1 Credit", 0x03 ); 1230 context.dips[0][7] = Dip::Value( "Free Play", 0x07 ); 1231 context.dips[1] = Dip::Value( "Difficulty", 4, 1 ); 1232 context.dips[1][0] = Dip::Value( "Easy", 0x00 ); 1233 context.dips[1][1] = Dip::Value( "Normal", 0x08 ); 1234 context.dips[1][2] = Dip::Value( "Hard", 0x10 ); 1235 context.dips[1][3] = Dip::Value( "Very Hard", 0x18 ); 1236 context.dips[2] = Dip::Value( "Lives", 2, 1 ); 1237 context.dips[2][0] = Dip::Value( "3", 0x10 ); 1238 context.dips[2][1] = Dip::Value( "5", 0x00 ); 1239 context.dips[3] = Dip::Value( "Bullets per Balloon", 2, 1 ); 1240 context.dips[3][0] = Dip::Value( "2", 0x40 ); 1241 context.dips[3][1] = Dip::Value( "3", 0x00 ); 1242 context.dips[4] = Dip::Value( "Bonus Life", 2, 0 ); 1243 context.dips[4][0] = Dip::Value( "80000", 0x00 ); 1244 context.dips[4][1] = Dip::Value( "100000", 0x80 ); 1245 1246 context.ppuModel = PPU_RC2C05_03; 1247 break; 1248 1249 default: 1250 1251 context.SetDips(8); 1252 1253 for (uint i=0; i < 8; ++i) 1254 { 1255 context.dips[i] = Dip::Value( "Unknown", 2, 0 ); 1256 context.dips[i][0] = Dip::Value( "Off", 0x00 ); 1257 context.dips[i][1] = Dip::Value( "On", 1U << i ); 1258 } 1259 1260 if (ppuModel != PPU_RP2C02) 1261 context.ppuModel = ppuModel; 1262 1263 break; 1264 } 1265 1266 switch (context.mode) 1267 { 1268 case MODE_RBI: return new RbiBaseball ( context ); 1269 case MODE_TKO: return new TkoBoxing ( context ); 1270 case MODE_XEV: return new SuperXevious ( context ); 1271 default: return new VsSystem ( context ); 1272 } 1273 } 1274 catch (...) 1275 { 1276 delete [] context.dips; 1277 throw; 1278 } 1279 } 1280 Destroy(Cartridge::VsSystem * vsSystem)1281 void Cartridge::VsSystem::Destroy(Cartridge::VsSystem* vsSystem) 1282 { 1283 delete vsSystem; 1284 } 1285 1286 #ifdef NST_MSVC_OPTIMIZE 1287 #pragma optimize("", on) 1288 #endif 1289 1290 struct Cartridge::VsSystem::InputMapper::Type1 : InputMapper 1291 { FixNes::Core::Cartridge::VsSystem::InputMapper::Type11292 void Fix(Pad (&pads)[4],const uint (&ports)[2]) const 1293 { 1294 const uint p[2] = { ports[0] < 4 ? pads[ports[0]].buttons : 0, ports[1] < 4 ? pads[ports[1]].buttons : 0 }; 1295 1296 for (uint i=2; i--; ) 1297 { 1298 if (ports[i] < 4) 1299 pads[ports[i]].buttons = (p[i] & ~uint(Pad::SELECT|Pad::START)) | ((p[i] & Pad::SELECT) << 1) | ((p[i] & Pad::START) >> 1); 1300 } 1301 } 1302 }; 1303 1304 struct Cartridge::VsSystem::InputMapper::Type2 : InputMapper 1305 { FixNes::Core::Cartridge::VsSystem::InputMapper::Type21306 void Fix(Pad (&pads)[4],const uint (&ports)[2]) const 1307 { 1308 const uint p[2] = { ports[0] < 4 ? pads[ports[0]].buttons : 0, ports[1] < 4 ? pads[ports[1]].buttons : 0 }; 1309 1310 for (uint i=2; i--; ) 1311 { 1312 if (ports[i] < 4) 1313 pads[ports[i]].buttons = (p[i^1] & ~uint(Pad::SELECT|Pad::START)) | ((p[i^0] & Pad::SELECT) << 1) | ((p[i^0] & Pad::START) >> 1); 1314 } 1315 } 1316 }; 1317 1318 struct Cartridge::VsSystem::InputMapper::Type3 : InputMapper 1319 { FixNes::Core::Cartridge::VsSystem::InputMapper::Type31320 void Fix(Pad (&pads)[4],const uint (&ports)[2]) const 1321 { 1322 const uint p[2] = { ports[0] < 4 ? pads[ports[0]].buttons : 0, ports[1] < 4 ? pads[ports[1]].buttons : 0 }; 1323 1324 if (ports[1] < 4) 1325 pads[ports[1]].buttons = p[0] & ~uint(Pad::SELECT|Pad::START); 1326 1327 if (ports[0] < 4) 1328 pads[ports[0]].buttons = (p[1] & ~uint(Pad::SELECT|Pad::START)) | ((p[0] & Pad::START) >> 1) | (p[1] & Pad::START); 1329 } 1330 }; 1331 1332 struct Cartridge::VsSystem::InputMapper::Type4 : InputMapper 1333 { FixNes::Core::Cartridge::VsSystem::InputMapper::Type41334 void Fix(Pad (&pads)[4],const uint (&ports)[2]) const 1335 { 1336 const uint p[2] = { ports[0] < 4 ? pads[ports[0]].buttons : 0, ports[1] < 4 ? pads[ports[1]].buttons : 0 }; 1337 1338 for (uint i=2; i--; ) 1339 { 1340 if (ports[i] < 4) 1341 pads[ports[i]].buttons = (p[i^1] & ~uint(Pad::SELECT|Pad::START)) | (((p[i^0] & Pad::SELECT) ^ Pad::SELECT) << 1) | ((p[i^0] & Pad::START) >> 1); 1342 } 1343 } 1344 }; 1345 1346 struct Cartridge::VsSystem::InputMapper::Type5 : InputMapper 1347 { FixNes::Core::Cartridge::VsSystem::InputMapper::Type51348 void Fix(Pad (&pads)[4],const uint (&ports)[2]) const 1349 { 1350 const uint p[2] = { ports[0] < 4 ? pads[ports[0]].buttons : 0, ports[1] < 4 ? pads[ports[1]].buttons : 0 }; 1351 1352 if (ports[1] < 4) 1353 pads[ports[1]].buttons = (p[1] & ~uint(Pad::A|Pad::SELECT|Pad::START)) | ((p[0] & Pad::B) >> 1) | ((p[1] & Pad::SELECT) << 1) | ((p[1] & Pad::START) >> 1); 1354 1355 if (ports[0] < 4) 1356 pads[ports[0]].buttons = (p[0] & ~uint(Pad::B|Pad::SELECT|Pad::START)) | ((p[1] & Pad::A) << 1) | ((p[0] & Pad::SELECT) << 1) | ((p[0] & Pad::START) >> 1); 1357 } 1358 }; 1359 Begin(const Api::Input input,Input::Controllers * const controllers)1360 void Cartridge::VsSystem::InputMapper::Begin(const Api::Input input,Input::Controllers* const controllers) 1361 { 1362 Input::Controllers::Pad::callback.Get( userCallback, userData ); 1363 1364 if (controllers) 1365 { 1366 uint ports[2]; 1367 1368 for (uint i=0; i < 2; ++i) 1369 { 1370 ports[i] = input.GetConnectedController(i) - Api::Input::PAD1; 1371 1372 if (ports[i] < 4) 1373 Input::Controllers::Pad::callback( controllers->pad[ports[i]], ports[i] ); 1374 } 1375 1376 Input::Controllers::Pad::callback.Set( NULL, NULL ); 1377 1378 Fix( controllers->pad, ports ); 1379 } 1380 } 1381 End() const1382 void Cartridge::VsSystem::InputMapper::End() const 1383 { 1384 Input::Controllers::Pad::callback.Set( userCallback, userData ); 1385 } 1386 1387 #ifdef NST_MSVC_OPTIMIZE 1388 #pragma optimize("s", on) 1389 #endif 1390 Create(Type type)1391 Cartridge::VsSystem::InputMapper* Cartridge::VsSystem::InputMapper::Create(Type type) 1392 { 1393 switch (type) 1394 { 1395 case TYPE_1: return new Type1; 1396 case TYPE_2: return new Type2; 1397 case TYPE_3: return new Type3; 1398 case TYPE_4: return new Type4; 1399 case TYPE_5: return new Type5; 1400 case TYPE_NONE: default: break; 1401 } 1402 1403 return NULL; 1404 } 1405 VsSystem(Context & context)1406 Cartridge::VsSystem::VsSystem(Context& context) 1407 : 1408 cpu (context.cpu), 1409 ppu (context.ppu), 1410 inputMapper (InputMapper::Create( context.inputMapper )), 1411 dips (context.dips,context.numDips), 1412 ppuModel (context.ppuModel) 1413 { 1414 } 1415 ~VsSystem()1416 Cartridge::VsSystem::~VsSystem() 1417 { 1418 delete inputMapper; 1419 } 1420 Reset(bool)1421 void Cartridge::VsSystem::Reset(bool) 1422 { 1423 dips.Reset(); 1424 1425 coin = 0; 1426 1427 p4016 = cpu.Map( 0x4016 ); 1428 p4017 = cpu.Map( 0x4017 ); 1429 1430 cpu.Map( 0x4016 ).Set( this, &VsSystem::Peek_4016, &VsSystem::Poke_4016 ); 1431 cpu.Map( 0x4017 ).Set( this, &VsSystem::Peek_4017, &VsSystem::Poke_4017 ); 1432 cpu.Map( 0x4020 ).Set( this, &VsSystem::Peek_4020, &VsSystem::Poke_4020 ); 1433 1434 cpu.Map( 0x5000, 0x5FFF ).Set( this, &VsSystem::Peek_Nop, &VsSystem::Poke_Nop ); 1435 1436 Reset(); 1437 } 1438 SaveState(State::Saver & state,const dword baseChunk) const1439 void Cartridge::VsSystem::SaveState(State::Saver& state,const dword baseChunk) const 1440 { 1441 state.Begin( baseChunk ); 1442 1443 state.Write8( coin ); 1444 SubSave( state ); 1445 1446 state.End(); 1447 } 1448 LoadState(State::Loader & state)1449 void Cartridge::VsSystem::LoadState(State::Loader& state) 1450 { 1451 coin = state.Read8(); 1452 1453 while (const dword chunk = state.Begin()) 1454 { 1455 SubLoad( state, chunk ); 1456 state.End(); 1457 } 1458 } 1459 1460 #ifdef NST_MSVC_OPTIMIZE 1461 #pragma optimize("", on) 1462 #endif 1463 NES_PEEK_A(Cartridge::VsSystem,Nop)1464 NES_PEEK_A(Cartridge::VsSystem,Nop) 1465 { 1466 return address >> 8; 1467 } 1468 NES_POKE(Cartridge::VsSystem,Nop)1469 NES_POKE(Cartridge::VsSystem,Nop) 1470 { 1471 } 1472 1473 NES_PEEK_A(Cartridge::VsSystem,4016) 1474 { 1475 return dips.Reg(0) | (p4016.Peek( address ) & (STATUS_4016_MASK^0xFFU)); 1476 } 1477 1478 NES_POKE_AD(Cartridge::VsSystem,4016) 1479 { 1480 p4016.Poke( address, data ); 1481 } 1482 1483 NES_PEEK_A(Cartridge::VsSystem,4017) 1484 { 1485 return dips.Reg(1) | (p4017.Peek( address ) & (STATUS_4017_MASK^0xFFU)); 1486 } 1487 1488 NES_POKE_AD(Cartridge::VsSystem,4017) 1489 { 1490 p4017.Poke( address, data ); 1491 } 1492 1493 NES_PEEK(Cartridge::VsSystem,4020) 1494 { 1495 return coin; 1496 } 1497 1498 NES_POKE_D(Cartridge::VsSystem,4020) 1499 { 1500 coin = data; 1501 } 1502 } 1503 } 1504