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