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 "NstBoard.hpp"
26 #include "NstBoardBenshengBs5.hpp"
27 #include "../NstCrc32.hpp"
28 #include "../NstDipSwitches.hpp"
29 
30 namespace Nes
31 {
32 	namespace Core
33 	{
34 		namespace Boards
35 		{
36 			namespace Bensheng
37 			{
38 				#ifdef NST_MSVC_OPTIMIZE
39 				#pragma optimize("s", on)
40 				#endif
41 
42 				class Bs5::CartSwitches : public DipSwitches
43 				{
44 					enum Type
45 					{
46 						CRC_4_IN_1_A = 0x01E54556,
47 						CRC_4_IN_1_B = 0x6DCE148C,
48 						CRC_4_IN_1_C = 0x13E55C4C
49 					};
50 
51 					uint mode;
52 					const Type type;
53 
CartSwitches(Type t)54 					explicit CartSwitches(Type t)
55 					: mode(0), type(t) {}
56 
57 				public:
58 
Create(const Context & c)59 					static CartSwitches* Create(const Context& c)
60 					{
61 						switch (const dword crc = Crc32::Compute(c.prg.Mem(),c.prg.Size()))
62 						{
63 							case CRC_4_IN_1_A:
64 							case CRC_4_IN_1_B:
65 							case CRC_4_IN_1_C:
66 
67 								return new CartSwitches( static_cast<Type>(crc) );
68 						}
69 
70 						return NULL;
71 					}
72 
SetMode(uint value)73 					void SetMode(uint value)
74 					{
75 						mode = value & 0x3;
76 					}
77 
GetMode() const78 					uint GetMode() const
79 					{
80 						return mode;
81 					}
82 
83 				private:
84 
GetValue(uint) const85 					uint GetValue(uint) const
86 					{
87 						return mode;
88 					}
89 
SetValue(uint,uint value)90 					void SetValue(uint,uint value)
91 					{
92 						mode = value;
93 					}
94 
NumValues(uint) const95 					uint NumValues(uint) const
96 					{
97 						return 4;
98 					}
99 
NumDips() const100 					uint NumDips() const
101 					{
102 						return 1;
103 					}
104 
GetDipName(uint) const105 					cstring GetDipName(uint) const
106 					{
107 						return "Mode";
108 					}
109 
GetValueName(uint,uint i) const110 					cstring GetValueName(uint,uint i) const
111 					{
112 						switch (type)
113 						{
114 							case CRC_4_IN_1_A:
115 							{
116 								static const char names[4][9] =
117 								{
118 									"4-in-1",
119 									"23-in-1",
120 									"53-in-1",
121 									"163-in-1"
122 								};
123 
124 								return names[i];
125 							}
126 
127 							case CRC_4_IN_1_B:
128 							{
129 								static const char names[4][9] =
130 								{
131 									"4-in-1",
132 									"32-in-1",
133 									"64-in-1",
134 									"128-in-1"
135 								};
136 
137 								return names[i];
138 							}
139 
140 							case CRC_4_IN_1_C:
141 							{
142 								static const char names[4][9] =
143 								{
144 									"4-in-1",
145 									"21-in-1",
146 									"81-in-1",
147 									"151-in-1"
148 								};
149 
150 								return names[i];
151 							}
152 						}
153 
154 						return NULL;
155 					}
156 				};
157 
Bs5(const Context & c)158 				Bs5::Bs5(const Context& c)
159 				: Board(c), cartSwitches(CartSwitches::Create(c)) {}
160 
~Bs5()161 				Bs5::~Bs5()
162 				{
163 					delete cartSwitches;
164 				}
165 
SubReset(const bool hard)166 				void Bs5::SubReset(const bool hard)
167 				{
168 					if (hard)
169 						prg.SwapBanks<SIZE_8K,0x0000>( ~0U, ~0U, ~0U, ~0U );
170 
171 					Map( 0x8000U, 0x8FFFU, &Bs5::Poke_8000 );
172 					Map( 0xA000U, 0xAFFFU, &Bs5::Poke_A000 );
173 				}
174 
QueryDevice(DeviceType type)175 				Bs5::Device Bs5::QueryDevice(DeviceType type)
176 				{
177 					if (type == DEVICE_DIP_SWITCHES)
178 						return cartSwitches;
179 					else
180 						return Board::QueryDevice( type );
181 				}
182 
SubLoad(State::Loader & state,const dword baseChunk)183 				void Bs5::SubLoad(State::Loader& state,const dword baseChunk)
184 				{
185 					NST_VERIFY( (baseChunk == AsciiId<'B','S','5'>::V) );
186 
187 					if (baseChunk == AsciiId<'B','S','5'>::V)
188 					{
189 						while (const dword chunk = state.Begin())
190 						{
191 							if (chunk == AsciiId<'D','I','P'>::V)
192 							{
193 								NST_VERIFY( cartSwitches );
194 
195 								if (cartSwitches)
196 									cartSwitches->SetMode( state.Read8() );
197 							}
198 
199 							state.End();
200 						}
201 					}
202 				}
203 
SubSave(State::Saver & state) const204 				void Bs5::SubSave(State::Saver& state) const
205 				{
206 					if (cartSwitches)
207 						state.Begin( AsciiId<'B','S','5'>::V ).Begin( AsciiId<'D','I','P'>::V ).Write8( cartSwitches->GetMode() ).End().End();
208 				}
209 
210 				#ifdef NST_MSVC_OPTIMIZE
211 				#pragma optimize("", on)
212 				#endif
213 
214 				NES_POKE_A(Bs5,8000)
215 				{
216 					ppu.Update();
217 					chr.SwapBank<SIZE_2K>( address << 1 & 0x1800, address & 0x1F );
218 
219 				}
220 
NES_POKE_A(Bs5,A000)221 				NES_POKE_A(Bs5,A000)
222 				{
223 					if (address & (0x10U << (cartSwitches ? cartSwitches->GetMode() : 0)))
224 						prg.SwapBank<SIZE_8K>( address << 3 & 0x6000, address & 0xF );
225 				}
226 			}
227 		}
228 	}
229 }
230