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 <new>
26 #include "../NstMachine.hpp"
27 #include "../NstImage.hpp"
28 #include "../NstState.hpp"
29 #include "NstApiMachine.hpp"
30 
31 namespace Nes
32 {
33 	namespace Api
34 	{
35 		Machine::EventCaller Machine::eventCallback;
36 
Is(uint a) const37 		uint Machine::Is(uint a) const throw()
38 		{
39 			return emulator.Is( a );
40 		}
41 
Is(uint a,uint b) const42 		bool Machine::Is(uint a,uint b) const throw()
43 		{
44 			return emulator.Is( a, b );
45 		}
46 
IsLocked() const47 		bool Machine::IsLocked() const
48 		{
49 			return emulator.tracker.IsLocked();
50 		}
51 
52 		#ifdef NST_MSVC_OPTIMIZE
53 		#pragma optimize("s", on)
54 		#endif
55 
Load(std::istream & stream,FavoredSystem system,AskProfile ask,Patch * patch,uint type)56 		Result Machine::Load(std::istream& stream,FavoredSystem system,AskProfile ask,Patch* patch,uint type)
57 		{
58 			Result result;
59 
60 			const bool on = Is(ON);
61 
62 			try
63 			{
64 				result = emulator.Load
65 				(
66 					stream,
67 					static_cast<Core::FavoredSystem>(system),
68 					ask == ASK_PROFILE,
69 					patch ? &patch->stream : NULL,
70 					patch ? patch->bypassChecksum : false,
71 					patch ? &patch->result : NULL,
72 					type
73 				);
74 			}
75 			catch (Result r)
76 			{
77 				return r;
78 			}
79 			catch (const std::bad_alloc&)
80 			{
81 				return RESULT_ERR_OUT_OF_MEMORY;
82 			}
83 			catch (...)
84 			{
85 				return RESULT_ERR_GENERIC;
86 			}
87 
88 			if (on)
89 				Power( true );
90 
91 			return result;
92 		}
93 
Load(std::istream & stream,FavoredSystem system,AskProfile ask)94 		Result Machine::Load(std::istream& stream,FavoredSystem system,AskProfile ask) throw()
95 		{
96 			return Load( stream, system, ask, NULL, Core::Image::UNKNOWN );
97 		}
98 
Load(std::istream & stream,FavoredSystem system,Patch & patch,AskProfile ask)99 		Result Machine::Load(std::istream& stream,FavoredSystem system,Patch& patch,AskProfile ask) throw()
100 		{
101 			return Load( stream, system, ask, &patch, Core::Image::UNKNOWN );
102 		}
103 
LoadCartridge(std::istream & stream,FavoredSystem system,AskProfile ask)104 		Result Machine::LoadCartridge(std::istream& stream,FavoredSystem system,AskProfile ask) throw()
105 		{
106 			return Load( stream, system, ask, NULL, Core::Image::CARTRIDGE );
107 		}
108 
LoadCartridge(std::istream & stream,FavoredSystem system,Patch & patch,AskProfile ask)109 		Result Machine::LoadCartridge(std::istream& stream,FavoredSystem system,Patch& patch,AskProfile ask) throw()
110 		{
111 			return Load( stream, system, ask, &patch, Core::Image::CARTRIDGE );
112 		}
113 
LoadDisk(std::istream & stream,FavoredSystem system)114 		Result Machine::LoadDisk(std::istream& stream,FavoredSystem system) throw()
115 		{
116 			return Load( stream, system, DONT_ASK_PROFILE, NULL, Core::Image::DISK );
117 		}
118 
LoadSound(std::istream & stream,FavoredSystem system)119 		Result Machine::LoadSound(std::istream& stream,FavoredSystem system) throw()
120 		{
121 			return Load( stream, system, DONT_ASK_PROFILE, NULL, Core::Image::SOUND );
122 		}
123 
Unload()124 		Result Machine::Unload() throw()
125 		{
126 			if (!Is(IMAGE))
127 				return RESULT_NOP;
128 
129 			return emulator.Unload();
130 		}
131 
Power(const bool on)132 		Result Machine::Power(const bool on) throw()
133 		{
134 			if (on == bool(Is(ON)))
135 				return RESULT_NOP;
136 
137 			if (on)
138 			{
139 				try
140 				{
141 					emulator.Reset( true );
142 				}
143 				catch (Result result)
144 				{
145 					return result;
146 				}
147 				catch (const std::bad_alloc&)
148 				{
149 					return RESULT_ERR_OUT_OF_MEMORY;
150 				}
151 				catch (...)
152 				{
153 					return RESULT_ERR_GENERIC;
154 				}
155 
156 				return RESULT_OK;
157 			}
158 			else
159 			{
160 				return emulator.PowerOff();
161 			}
162 		}
163 
Reset(const bool hard)164 		Result Machine::Reset(const bool hard) throw()
165 		{
166 			if (!Is(ON) || IsLocked())
167 				return RESULT_ERR_NOT_READY;
168 
169 			try
170 			{
171 				emulator.Reset( hard );
172 			}
173 			catch (Result result)
174 			{
175 				return result;
176 			}
177 			catch (const std::bad_alloc&)
178 			{
179 				return RESULT_ERR_OUT_OF_MEMORY;
180 			}
181 			catch (...)
182 			{
183 				return RESULT_ERR_GENERIC;
184 			}
185 
186 			return RESULT_OK;
187 		}
188 
SetRamPowerState(const uint state)189 		Result Machine::SetRamPowerState(const uint state) throw()
190 		{
191 			emulator.SetRamPowerState(state);
192 			return RESULT_OK;
193 		}
194 
GetMode() const195 		Machine::Mode Machine::GetMode() const throw()
196 		{
197 			return static_cast<Mode>(Is(NTSC|PAL));
198 		}
199 
GetDesiredMode() const200 		Machine::Mode Machine::GetDesiredMode() const throw()
201 		{
202 			return (!emulator.image || emulator.image->GetDesiredRegion() == Core::REGION_NTSC) ? NTSC : PAL;
203 		}
204 
SetMode(const Mode mode)205 		Result Machine::SetMode(const Mode mode) throw()
206 		{
207 			if (mode == GetMode())
208 				return RESULT_NOP;
209 
210 			Result result = Power( false );
211 
212 			if (NES_SUCCEEDED(result))
213 			{
214 				emulator.SwitchMode();
215 
216 				if (result != RESULT_NOP)
217 					result = Power( true );
218 			}
219 
220 			return result;
221 		}
222 
LoadState(std::istream & stream)223 		Result Machine::LoadState(std::istream& stream) throw()
224 		{
225 			if (!Is(GAME,ON) || IsLocked())
226 				return RESULT_ERR_NOT_READY;
227 
228 			try
229 			{
230 				emulator.tracker.Resync();
231 				Core::State::Loader loader( &stream, true );
232 
233 				if (emulator.LoadState( loader, true ))
234 					return RESULT_OK;
235 				else
236 					return RESULT_ERR_INVALID_CRC;
237 			}
238 			catch (Result result)
239 			{
240 				return result;
241 			}
242 			catch (const std::bad_alloc&)
243 			{
244 				return RESULT_ERR_OUT_OF_MEMORY;
245 			}
246 			catch (...)
247 			{
248 				return RESULT_ERR_GENERIC;
249 			}
250 		}
251 
SaveState(std::ostream & stream,Compression compression) const252 		Result Machine::SaveState(std::ostream& stream,Compression compression) const throw()
253 		{
254 			if (!Is(GAME,ON))
255 				return RESULT_ERR_NOT_READY;
256 
257 			try
258 			{
259 				Core::State::Saver saver( &stream, compression != NO_COMPRESSION, false );
260 				emulator.SaveState( saver );
261 			}
262 			catch (Result result)
263 			{
264 				return result;
265 			}
266 			catch (const std::bad_alloc&)
267 			{
268 				return RESULT_ERR_OUT_OF_MEMORY;
269 			}
270 			catch (...)
271 			{
272 				return RESULT_ERR_GENERIC;
273 			}
274 
275 			return RESULT_OK;
276 		}
277 
278 		#ifdef NST_MSVC_OPTIMIZE
279 		#pragma optimize("", on)
280 		#endif
281 	}
282 }
283