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 "NstBoardMmc3.hpp"
27 #include "NstBoardSomeriTeam.hpp"
28 
29 namespace Nes
30 {
31 	namespace Core
32 	{
33 		namespace Boards
34 		{
35 			namespace SomeriTeam
36 			{
37 				#ifdef NST_MSVC_OPTIMIZE
38 				#pragma optimize("s", on)
39 				#endif
40 
Sl12(const Context & c)41 				Sl12::Sl12(const Context& c)
42 				:
43 				Board (c),
44 				irq   (*c.cpu,*c.ppu,false)
45 				{}
46 
SubReset(const bool hard)47 				void Sl12::SubReset(const bool hard)
48 				{
49 					irq.Reset( hard );
50 
51 					if (hard)
52 					{
53 						mode = 0;
54 
55 						vrc2.prg[0] = 0x0;
56 						vrc2.prg[1] = 0x1;
57 						vrc2.nmt = 0;
58 
59 						for (uint i=0; i < 8; ++i)
60 							vrc2.chr[i] = i;
61 
62 						mmc3.ctrl = 0;
63 						mmc3.nmt = 0;
64 
65 						mmc3.banks[0] = 0x0;
66 						mmc3.banks[1] = 0x1;
67 						mmc3.banks[2] = 0x4;
68 						mmc3.banks[3] = 0x5;
69 						mmc3.banks[4] = 0x6;
70 						mmc3.banks[5] = 0x7;
71 
72 						mmc3.banks[6] = 0x3C;
73 						mmc3.banks[7] = 0x3D;
74 						mmc3.banks[8] = 0xFE;
75 						mmc3.banks[9] = 0xFF;
76 
77 						mmc1.buffer = 0;
78 						mmc1.shifter = 0;
79 
80 						mmc1.regs[0] = 0x4U|0x8U;
81 						mmc1.regs[1] = 0;
82 						mmc1.regs[2] = 0;
83 						mmc1.regs[3] = 0;
84 					}
85 
86 					for (uint i=0x4100; i < 0x6000; i += 0x200)
87 						Map( i + 0x00, i + 0xFF, &Sl12::Poke_4100 );
88 
89 					Map( 0x8000U, 0x8FFFU, &Sl12::Poke_8000 );
90 					Map( 0x9000U, 0x9FFFU, &Sl12::Poke_9000 );
91 					Map( 0xA000U, 0xAFFFU, &Sl12::Poke_A000 );
92 					Map( 0xB000U, 0xBFFFU, &Sl12::Poke_B000 );
93 					Map( 0xC000U, 0xCFFFU, &Sl12::Poke_C000 );
94 					Map( 0xD000U, 0xDFFFU, &Sl12::Poke_D000 );
95 					Map( 0xE000U, 0xEFFFU, &Sl12::Poke_E000 );
96 					Map( 0xF000U, 0xFFFFU, &Sl12::Poke_F000 );
97 
98 					UpdatePrg();
99 					UpdateNmt();
100 					UpdateChr();
101 				}
102 
SubLoad(State::Loader & state,const dword baseChunk)103 				void Sl12::SubLoad(State::Loader& state,const dword baseChunk)
104 				{
105 					NST_VERIFY( baseChunk == (AsciiId<'S','1','2'>::V) );
106 
107 					if (baseChunk == AsciiId<'S','1','2'>::V)
108 					{
109 						while (const dword chunk = state.Begin())
110 						{
111 							switch (chunk)
112 							{
113 								case AsciiId<'R','E','G'>::V:
114 
115 									mode = state.Read8();
116 									break;
117 
118 								case AsciiId<'V','R','2'>::V:
119 
120 									state.Read( vrc2.chr );
121 									state.Read( vrc2.prg );
122 									vrc2.nmt = state.Read8();
123 									break;
124 
125 								case AsciiId<'M','M','3'>::V:
126 
127 									state.Read( mmc3.banks );
128 									mmc3.ctrl = state.Read8();
129 									mmc3.nmt = state.Read8();
130 									break;
131 
132 								case AsciiId<'M','M','1'>::V:
133 
134 									state.Read( mmc1.regs );
135 									mmc1.buffer = state.Read8();
136 									mmc1.shifter = state.Read8();
137 									break;
138 
139 								case AsciiId<'I','R','Q'>::V:
140 
141 									irq.unit.LoadState( state );
142 									break;
143 							}
144 
145 							state.End();
146 						}
147 					}
148 
149 					UpdatePrg();
150 					UpdateNmt();
151 					UpdateChr();
152 				}
153 
SubSave(State::Saver & state) const154 				void Sl12::SubSave(State::Saver& state) const
155 				{
156 					state.Begin( AsciiId<'S','1','2'>::V );
157 					state.Begin( AsciiId<'R','E','G'>::V ).Write8( mode ).End();
158 					state.Begin( AsciiId<'V','R','2'>::V ).Write( vrc2.chr ).Write( vrc2.prg ).Write8( vrc2.nmt ).End();
159 					state.Begin( AsciiId<'M','M','3'>::V ).Write( mmc3.banks ).Write8( mmc3.ctrl ).Write8( mmc3.nmt ).End();
160 					state.Begin( AsciiId<'M','M','1'>::V ).Write( mmc1.regs ).Write8( mmc1.buffer ).Write8( mmc1.shifter ).End();
161 					irq.unit.SaveState( state, AsciiId<'I','R','Q'>::V );
162 					state.End();
163 				}
164 
165 				#ifdef NST_MSVC_OPTIMIZE
166 				#pragma optimize("", on)
167 				#endif
168 
UpdatePrg()169 				void Sl12::UpdatePrg()
170 				{
171 					switch (mode & 0x3)
172 					{
173 						case 0x0:
174 
175 							prg.SwapBanks<SIZE_8K,0x0000>( vrc2.prg[0], vrc2.prg[1], 0x1E, 0x1F );
176 							break;
177 
178 						case 0x1:
179 						{
180 							const uint i = mmc3.ctrl >> 5 & 0x2U;
181 							prg.SwapBanks<SIZE_8K,0x0000>( mmc3.banks[6+i], mmc3.banks[6+1], mmc3.banks[6+(i^2)], mmc3.banks[6+3] );
182 							break;
183 						}
184 
185 						case 0x2:
186 						{
187 							const uint bank = mmc1.regs[3] & 0xFU;
188 
189 							if (mmc1.regs[0] & 0x8U)
190 								prg.SwapBanks<SIZE_16K,0x0000>( (mmc1.regs[0] & 0x4U) ? bank : 0x0, (mmc1.regs[0] & 0x4U) ? 0xF : bank );
191 							else
192 								prg.SwapBank<SIZE_32K,0x0000>( bank >> 1 );
193 
194 							break;
195 						}
196 					}
197 				}
198 
UpdateChr() const199 				void Sl12::UpdateChr() const
200 				{
201 					const uint base = (mode & 0x4) << 6;
202 
203 					switch (mode & 0x3)
204 					{
205 						case 0x0:
206 
207 							chr.SwapBanks<SIZE_1K,0x0000>( base|vrc2.chr[0], base|vrc2.chr[1], base|vrc2.chr[2], base|vrc2.chr[3], base|vrc2.chr[4], base|vrc2.chr[5], base|vrc2.chr[6], base|vrc2.chr[7] );
208 							break;
209 
210 						case 0x1:
211 						{
212 							const uint swap = (mmc3.ctrl & 0x80U) << 5;
213 							chr.SwapBanks<SIZE_2K>( 0x0000 ^ swap, base >> 1 | mmc3.banks[0], base >> 1 | mmc3.banks[1] );
214 							chr.SwapBanks<SIZE_1K>( 0x1000 ^ swap, base|mmc3.banks[2], base|mmc3.banks[3], base|mmc3.banks[4], base|mmc3.banks[5] );
215 							break;
216 						}
217 
218 						case 0x2:
219 
220 							chr.SwapBanks<SIZE_4K,0x0000>( (mmc1.regs[0] & 0x10U) ? mmc1.regs[1] : mmc1.regs[1] & 0x1EU, (mmc1.regs[0] & 0x10U) ? mmc1.regs[2] : mmc1.regs[1] | 0x01U );
221 							break;
222 					}
223 				}
224 
UpdateNmt() const225 				void Sl12::UpdateNmt() const
226 				{
227 					Ppu::NmtMirroring nmtCtrl;
228 
229 					switch (mode & 0x3)
230 					{
231 						case 0x0:
232 
233 							nmtCtrl = (vrc2.nmt & 0x1U) ? Ppu::NMT_H : Ppu::NMT_V;
234 							break;
235 
236 						case 0x1:
237 
238 							nmtCtrl = (mmc3.nmt & 0x1U) ? Ppu::NMT_H : Ppu::NMT_V;
239 							break;
240 
241 						case 0x2:
242 
243 							switch (mmc1.regs[0] & 0x3U)
244 							{
245 								case 0x0: nmtCtrl = Ppu::NMT_0; break;
246 								case 0x1: nmtCtrl = Ppu::NMT_1; break;
247 								case 0x2: nmtCtrl = Ppu::NMT_V; break;
248 								default:  nmtCtrl = Ppu::NMT_H; break;
249 							}
250 							break;
251 
252 						default: return;
253 					}
254 
255 					ppu.SetMirroring( nmtCtrl );
256 				}
257 
Poke_Vrc2_8000(uint address,uint data)258 				void Sl12::Poke_Vrc2_8000(uint address,uint data)
259 				{
260 					NST_ASSERT( (mode & 0x3) == 0 );
261 
262 					data &= 0x1F;
263 					address = address >> 13 & 0x1;
264 
265 					if (vrc2.prg[address] != data)
266 					{
267 						vrc2.prg[address] = data;
268 						UpdatePrg();
269 					}
270 				}
271 
Poke_Vrc2_9000(uint,uint data)272 				void Sl12::Poke_Vrc2_9000(uint,uint data)
273 				{
274 					NST_ASSERT( (mode & 0x3) == 0 );
275 
276 					data &= 0x1;
277 
278 					if (vrc2.nmt != data)
279 					{
280 						vrc2.nmt = data;
281 						UpdateNmt();
282 					}
283 				}
284 
Poke_Vrc2_B000(uint address,uint data)285 				void Sl12::Poke_Vrc2_B000(uint address,uint data)
286 				{
287 					NST_ASSERT( (mode & 0x3) == 0 );
288 
289 					data = (data & 0xF) << (address << 1 & 0x4);
290 					address = ((address - 0xB000) >> 11 & 0x6) | (address & 0x1);
291 
292 					if (vrc2.chr[address] != data)
293 					{
294 						vrc2.chr[address] = data;
295 						ppu.Update();
296 						UpdateChr();
297 					}
298 				}
299 
Poke_Mmc3_8000(uint address,uint data)300 				void Sl12::Poke_Mmc3_8000(uint address,uint data)
301 				{
302 					NST_ASSERT( (mode & 0x3) == 1 );
303 
304 					if (address & 0x1)
305 					{
306 						address = mmc3.ctrl & 0x7U;
307 
308 						if (address < 2)
309 							data >>= 1;
310 
311 						if (mmc3.banks[address] != data)
312 						{
313 							mmc3.banks[address] = data;
314 
315 							if (address < 6)
316 							{
317 								ppu.Update();
318 								UpdateChr();
319 							}
320 							else
321 							{
322 								UpdatePrg();
323 							}
324 						}
325 					}
326 					else
327 					{
328 						address = mmc3.ctrl ^ data;
329 						mmc3.ctrl = data;
330 
331 						if (address & 0x40)
332 							UpdatePrg();
333 
334 						if (address & (0x80U|0x07U))
335 						{
336 							ppu.Update();
337 							UpdateChr();
338 						}
339 					}
340 				}
341 
Poke_Mmc3_A000(uint address,uint data)342 				void Sl12::Poke_Mmc3_A000(uint address,uint data)
343 				{
344 					NST_ASSERT( (mode & 0x3) == 1 );
345 
346 					if (!(address & 0x1))
347 					{
348 						if (mmc3.nmt != data)
349 						{
350 							mmc3.nmt = data;
351 							UpdateNmt();
352 						}
353 					}
354 				}
355 
Poke_Mmc3_C000(uint address,uint data)356 				void Sl12::Poke_Mmc3_C000(uint address,uint data)
357 				{
358 					NST_ASSERT( (mode & 0x3) == 1 );
359 
360 					irq.Update();
361 
362 					if (address & 0x1)
363 						irq.unit.Reload();
364 					else
365 						irq.unit.SetLatch( data );
366 				}
367 
Poke_Mmc3_E000(uint address,uint)368 				void Sl12::Poke_Mmc3_E000(uint address,uint)
369 				{
370 					NST_ASSERT( (mode & 0x3) == 1 );
371 
372 					irq.Update();
373 
374 					if (address & 0x1)
375 						irq.unit.Enable();
376 					else
377 						irq.unit.Disable( cpu );
378 				}
379 
Poke_Mmc1_8000(uint address,uint data)380 				void Sl12::Poke_Mmc1_8000(uint address,uint data)
381 				{
382 					NST_ASSERT( (mode & 0x3) == 2 );
383 
384 					if (!(data & 0x80))
385 					{
386 						mmc1.buffer |= (data & 0x1) << mmc1.shifter++;
387 
388 						if (mmc1.shifter != 5)
389 							return;
390 
391 						mmc1.shifter = 0;
392 						data = mmc1.buffer;
393 						mmc1.buffer = 0;
394 
395 						address = address >> 13 & 0x3;
396 
397 						if (mmc1.regs[address] != data)
398 						{
399 							mmc1.regs[address] = data;
400 
401 							UpdatePrg();
402 							UpdateNmt();
403 							UpdateChr();
404 						}
405 					}
406 					else
407 					{
408 						mmc1.buffer = 0;
409 						mmc1.shifter = 0;
410 
411 						if ((mmc1.regs[0] & (0x4U|0x8U)) != (0x4U|0x8U))
412 						{
413 							mmc1.regs[0] |= (0x4U|0x8U);
414 
415 							UpdatePrg();
416 							UpdateNmt();
417 							UpdateChr();
418 						}
419 					}
420 				}
421 
422 				NES_POKE_D(Sl12,4100)
423 				{
424 					if (mode != data)
425 					{
426 						mode = data;
427 
428 						if ((data & 0x3) != 1)
429 							irq.unit.Disable( cpu );
430 
431 						UpdatePrg();
432 						UpdateNmt();
433 						UpdateChr();
434 					}
435 				}
436 
437 				NES_POKE_AD(Sl12,8000)
438 				{
439 					switch (mode & 0x3)
440 					{
441 						case 0x0: Poke_Vrc2_8000( address, data ); break;
442 						case 0x1: Poke_Mmc3_8000( address, data ); break;
443 						case 0x2: Poke_Mmc1_8000( address, data ); break;
444 					}
445 				}
446 
447 				NES_POKE_AD(Sl12,9000)
448 				{
449 					switch (mode & 0x3)
450 					{
451 						case 0x0: Poke_Vrc2_9000( address, data ); break;
452 						case 0x1: Poke_Mmc3_8000( address, data ); break;
453 						case 0x2: Poke_Mmc1_8000( address, data ); break;
454 					}
455 				}
456 
NES_POKE_AD(Sl12,A000)457 				NES_POKE_AD(Sl12,A000)
458 				{
459 					switch (mode & 0x3)
460 					{
461 						case 0x0: Poke_Vrc2_8000( address, data ); break;
462 						case 0x1: Poke_Mmc3_A000( address, data ); break;
463 						case 0x2: Poke_Mmc1_8000( address, data ); break;
464 					}
465 				}
466 
NES_POKE_AD(Sl12,B000)467 				NES_POKE_AD(Sl12,B000)
468 				{
469 					switch (mode & 0x3)
470 					{
471 						case 0x0: Poke_Vrc2_B000( address, data ); break;
472 						case 0x1: Poke_Mmc3_A000( address, data ); break;
473 						case 0x2: Poke_Mmc1_8000( address, data ); break;
474 					}
475 				}
476 
NES_POKE_AD(Sl12,C000)477 				NES_POKE_AD(Sl12,C000)
478 				{
479 					switch (mode & 0x3)
480 					{
481 						case 0x0: Poke_Vrc2_B000( address, data ); break;
482 						case 0x1: Poke_Mmc3_C000( address, data ); break;
483 						case 0x2: Poke_Mmc1_8000( address, data ); break;
484 					}
485 				}
486 
NES_POKE_AD(Sl12,D000)487 				NES_POKE_AD(Sl12,D000)
488 				{
489 					switch (mode & 0x3)
490 					{
491 						case 0x0: Poke_Vrc2_B000( address, data ); break;
492 						case 0x1: Poke_Mmc3_C000( address, data ); break;
493 						case 0x2: Poke_Mmc1_8000( address, data ); break;
494 					}
495 				}
496 
NES_POKE_AD(Sl12,E000)497 				NES_POKE_AD(Sl12,E000)
498 				{
499 					switch (mode & 0x3)
500 					{
501 						case 0x0: Poke_Vrc2_B000( address, data ); break;
502 						case 0x1: Poke_Mmc3_E000( address, data ); break;
503 						case 0x2: Poke_Mmc1_8000( address, data ); break;
504 					}
505 				}
506 
NES_POKE_AD(Sl12,F000)507 				NES_POKE_AD(Sl12,F000)
508 				{
509 					switch (mode & 0x3)
510 					{
511 						case 0x0: break;
512 						case 0x1: Poke_Mmc3_E000( address, data ); break;
513 						case 0x2: Poke_Mmc1_8000( address, data ); break;
514 					}
515 				}
516 
Sync(Event event,Input::Controllers * controllers)517 				void Sl12::Sync(Event event,Input::Controllers* controllers)
518 				{
519 					if (event == EVENT_END_FRAME)
520 						irq.VSync();
521 
522 					Board::Sync( event, controllers );
523 				}
524 			}
525 		}
526 	}
527 }
528