1 ////////////////////////////////////////////////////////////////////////////////////////
2 //
3 // Nestopia - NES/Famicom emulator written in C++
4 //
5 // Copyright (C) 2003-2008 Martin Freij
6 // Copyright (C) 2021 Rupert Carmichael
7 //
8 // This file is part of Nestopia.
9 //
10 // Nestopia is free software; you can redistribute it and/or modify
11 // it under the terms of the GNU General Public License as published by
12 // the Free Software Foundation; either version 2 of the License, or
13 // (at your option) any later version.
14 //
15 // Nestopia is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Nestopia; if not, write to the Free Software
22 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 //
24 ////////////////////////////////////////////////////////////////////////////////////////
25 
26 #include "../NstTimer.hpp"
27 #include "NstBoard.hpp"
28 #include "NstBoardKaiser.hpp"
29 
30 namespace Nes
31 {
32 	namespace Core
33 	{
34 		namespace Boards
35 		{
36 			namespace Kaiser
37 			{
38 				#ifdef NST_MSVC_OPTIMIZE
39 				#pragma optimize("s", on)
40 				#endif
41 
Ks202(const Context & c)42 				Ks202::Ks202(const Context& c)
43 				: Board(c), irq(*c.cpu) {}
44 
Reset(const bool hard)45 				void Ks202::Irq::Reset(const bool hard)
46 				{
47 					if (hard)
48 					{
49 						count = 0;
50 						latch = 0;
51 						ctrl = 0;
52 					}
53 				}
54 
SubReset(const bool hard)55 				void Ks202::SubReset(const bool hard)
56 				{
57 					Map( 0x8000U, 0x8FFFU, &Ks202::Poke_8000 );
58 					Map( 0x9000U, 0x9FFFU, &Ks202::Poke_9000 );
59 					Map( 0xA000U, 0xAFFFU, &Ks202::Poke_A000 );
60 					Map( 0xB000U, 0xBFFFU, &Ks202::Poke_B000 );
61 					Map( 0xC000U, 0xCFFFU, &Ks202::Poke_C000 );
62 					Map( 0xD000U, 0xDFFFU, &Ks202::Poke_D000 );
63 					Map( 0xE000U, 0xEFFFU, &Ks202::Poke_E000 );
64 					Map( 0xF000U, 0xFFFFU, &Ks202::Poke_F000 );
65 
66 					if (hard)
67 						ctrl = 0;
68 
69 					irq.Reset( hard, hard ? false : irq.Connected() );
70 				}
71 
SubReset(const bool hard)72 				void Ks7010::SubReset(const bool hard)
73 				{
74 					prg.SwapBank<SIZE_16K>( 0x0000, 0x5 );
75 					prg.SwapBank<SIZE_16K>( 0x4000, 0x3 );
76 
77 					// At the time of writing, the true mask for bankswitching is unknown
78 					Map( 0x6000U, 0x7FFFU, &Ks7010::Peek_6000 );
79 					Map( 0xCAB6U, 0xCAD6U, &Ks7010::Peek_FFFC );
80 					Map( 0xEBE2U, 0xEBE3U, &Ks7010::Peek_FFFC );
81 					Map( 0xEE32U, &Ks7010::Peek_FFFC );
82 					Map( 0xFFFCU, &Ks7010::Peek_FFFC );
83 
84 					reg = 0;
85 				}
86 
SubReset(const bool hard)87 				void Ks7013b::SubReset(const bool hard)
88 				{
89 					prg.SwapBank<SIZE_16K>( 0x4000, 0x7 );
90 
91 					Map( 0x6000U, 0x7FFFU, &Ks7013b::Poke_6000 );
92 					Map( 0x8000U, 0xFFFFU, &Ks7013b::Poke_8000 );
93 				}
94 
SubReset(const bool hard)95 				void Ks7016::SubReset(const bool hard)
96 				{
97 					reg = 8;
98 
99 					prg.SwapBank<SIZE_32K>( 0x0000, 0x3 );
100 
101 					Map( 0x6000U, 0x7FFFU, &Ks7016::Peek_6000 );
102 					Map( 0x8000U, 0xFFFFU, &Ks7016::Poke_8000 );
103 				}
104 
SubReset(const bool hard)105 				void Ks7022::SubReset(const bool hard)
106 				{
107 					reg = 0;
108 
109 					if (hard)
110 						prg.SwapBanks<SIZE_16K,0x0000>( 0, 0 );
111 
112 					Map( 0x8000, &Ks7022::Poke_8000 );
113 					Map( 0xA000, &Ks7022::Poke_A000 );
114 					Map( 0xFFFC, &Ks7022::Peek_FFFC );
115 				}
116 
SubReset(const bool hard)117 				void Ks7031::SubReset(const bool hard)
118 				{
119 					Map( 0x6000U, 0xFFFEU, &Ks7031::Peek_6000 );
120 					Map( 0x8000U, 0xFFFFU, &Ks7031::Poke_8000 );
121 
122 					regs[0] = 0;
123 					regs[1] = 0;
124 					regs[2] = 0;
125 					regs[3] = 0;
126 				}
127 
SubReset(const bool hard)128 				void Ks7032::SubReset(const bool hard)
129 				{
130 					Ks202::SubReset( hard );
131 					Map( 0x6000U, 0x7FFFU, &Ks7032::Peek_6000 );
132 				}
133 
SubReset(const bool hard)134 				void Ks7037::SubReset(const bool hard)
135 				{
136 					if (hard)
137 					{
138 						regNum = 0;
139 
140 						for (uint i = 0; i < 8; ++i)
141 							regs[i] = 0;
142 					}
143 
144 					Map( 0x6000U, 0x6FFFU, &Ks7037::Peek_6000 );
145 					Map( 0x6000U, 0x6FFFU, &Ks7037::Poke_6000 );
146 
147 					Map( 0x7000U, 0x7FFFU, &Ks7037::Peek_7000 );
148 					Map( 0x8000U, 0x9FFFU, &Ks7037::Peek_8000 );
149 
150 					for (uint i = 0x0000; i < 0x2000; i += 0x2)
151 					{
152 						Map( 0x8000 + i, &Ks7037::Poke_8000 );
153 						Map( 0x8001 + i, &Ks7037::Poke_8001 );
154 					}
155 
156 					Map( 0xA000U, 0xAFFFU, &Ks7037::Peek_A000 );
157 
158 					Map( 0xB000U, 0xBFFFU, &Ks7037::Peek_B000 );
159 					Map( 0xB000U, 0xBFFFU, &Ks7037::Poke_B000 );
160 
161 					Map( 0xC000U, 0xDFFFU, &Ks7037::Peek_C000 );
162 					Map( 0xE000U, 0xEFFFU, &Ks7037::Peek_E000 );
163 				}
164 
SubReset(const bool hard)165 				void Ks7057::SubReset(const bool hard)
166 				{
167 					prg.SwapBank<SIZE_8K>( 0x2000, 0xD );
168 					prg.SwapBank<SIZE_16K>( 0x4000, 0x7 );
169 
170 					Map( 0x6000U, 0x9FFFU, &Ks7057::Peek_6000 );
171 					Map( 0x8000U, 0x9FFFU, &Ks7057::Poke_8000 );
172 					Map( 0xB000U, 0xE003U, &Ks7057::Poke_B000 );
173 
174 					if (hard)
175 					{
176 						for (uint i = 0; i < 8; ++i)
177 							regs[i] = 0;
178 					}
179 				}
180 
SubReset(bool)181 				void Ks7058::SubReset(bool)
182 				{
183 					for (uint i=0x000; i < 0x1000; i += 0x100)
184 					{
185 						Map( 0xF000+i, 0xF07F+i, CHR_SWAP_4K_0 );
186 						Map( 0xF080+i, 0xF0FF+i, CHR_SWAP_4K_1 );
187 					}
188 				}
189 
SubLoad(State::Loader & state,const dword baseChunk)190 				void Ks202::SubLoad(State::Loader& state,const dword baseChunk)
191 				{
192 					NST_VERIFY( (baseChunk == AsciiId<'K','0','2'>::V) );
193 
194 					if (baseChunk == AsciiId<'K','0','2'>::V)
195 					{
196 						while (const dword chunk = state.Begin())
197 						{
198 							switch (chunk)
199 							{
200 								case AsciiId<'R','E','G'>::V:
201 
202 									ctrl = state.Read8();
203 									break;
204 
205 								case AsciiId<'I','R','Q'>::V:
206 								{
207 									State::Loader::Data<5> data( state );
208 
209 									irq.unit.ctrl = data[0];
210 									irq.unit.count = data[1] | data[2] << 8;
211 									irq.unit.latch = data[3] | data[4] << 8;
212 									irq.Connect( data[0] & 0xF );
213 
214 									break;
215 								}
216 							}
217 
218 							state.End();
219 						}
220 					}
221 				}
222 
SubLoad(State::Loader & state,const dword baseChunk)223 				void Ks7010::SubLoad(State::Loader& state,const dword baseChunk)
224 				{
225 					NST_VERIFY( (baseChunk == AsciiId<'K','7','0'>::V) );
226 
227 					if (baseChunk == AsciiId<'K','7','0'>::V)
228 					{
229 						while (const dword chunk = state.Begin())
230 						{
231 							if (chunk == AsciiId<'R','E','G'>::V)
232 								reg = state.Read8();
233 
234 							state.End();
235 						}
236 					}
237 				}
238 
SubLoad(State::Loader & state,const dword baseChunk)239 				void Ks7016::SubLoad(State::Loader& state,const dword baseChunk)
240 				{
241 					NST_VERIFY( (baseChunk == AsciiId<'K','7','6'>::V) );
242 
243 					if (baseChunk == AsciiId<'K','7','6'>::V)
244 					{
245 						while (const dword chunk = state.Begin())
246 						{
247 							if (chunk == AsciiId<'R','E','G'>::V)
248 								reg = state.Read8();
249 
250 							state.End();
251 						}
252 					}
253 				}
254 
SubLoad(State::Loader & state,const dword baseChunk)255 				void Ks7022::SubLoad(State::Loader& state,const dword baseChunk)
256 				{
257 					NST_VERIFY( (baseChunk == AsciiId<'K','7','2'>::V) );
258 
259 					if (baseChunk == AsciiId<'K','7','2'>::V)
260 					{
261 						while (const dword chunk = state.Begin())
262 						{
263 							if (chunk == AsciiId<'R','E','G'>::V)
264 								reg = state.Read8();
265 
266 							state.End();
267 						}
268 					}
269 				}
270 
SubLoad(State::Loader & state,const dword baseChunk)271 				void Ks7031::SubLoad(State::Loader& state,const dword baseChunk)
272 				{
273 					NST_VERIFY( (baseChunk == AsciiId<'K','7','1'>::V) );
274 
275 					if (baseChunk == AsciiId<'K','7','1'>::V)
276 					{
277 						while (const dword chunk = state.Begin())
278 						{
279 							if (chunk == AsciiId<'R','E','G'>::V)
280 							{
281 								State::Loader::Data<4> data( state );
282 
283 								regs[0] = data[0];
284 								regs[1] = data[1];
285 								regs[2] = data[2];
286 								regs[3] = data[3];
287 							}
288 
289 							state.End();
290 						}
291 					}
292 				}
293 
SubLoad(State::Loader & state,const dword baseChunk)294 				void Ks7037::SubLoad(State::Loader& state,const dword baseChunk)
295 				{
296 					NST_VERIFY( (baseChunk == AsciiId<'K','7','7'>::V) );
297 
298 					if (baseChunk == AsciiId<'K','7','7'>::V)
299 					{
300 						while (const dword chunk = state.Begin())
301 						{
302 							if (chunk == AsciiId<'R','E','G'>::V)
303 							{
304 								State::Loader::Data<9> data( state );
305 
306 								regs[0] = data[0];
307 								regs[1] = data[1];
308 								regs[2] = data[2];
309 								regs[3] = data[3];
310 								regs[4] = data[4];
311 								regs[5] = data[5];
312 								regs[6] = data[6];
313 								regs[7] = data[7];
314 								regNum = data[8];
315 							}
316 
317 							state.End();
318 						}
319 					}
320 				}
321 
SubLoad(State::Loader & state,const dword baseChunk)322 				void Ks7057::SubLoad(State::Loader& state,const dword baseChunk)
323 				{
324 					NST_VERIFY( (baseChunk == AsciiId<'K','5','7'>::V) );
325 
326 					if (baseChunk == AsciiId<'K','5','7'>::V)
327 					{
328 						while (const dword chunk = state.Begin())
329 						{
330 							if (chunk == AsciiId<'R','E','G'>::V)
331 							{
332 								State::Loader::Data<8> data( state );
333 
334 								regs[0] = data[0];
335 								regs[1] = data[1];
336 								regs[2] = data[2];
337 								regs[3] = data[3];
338 								regs[4] = data[4];
339 								regs[5] = data[5];
340 								regs[6] = data[6];
341 								regs[7] = data[7];
342 							}
343 
344 							state.End();
345 						}
346 					}
347 				}
348 
SubSave(State::Saver & state) const349 				void Ks202::SubSave(State::Saver& state) const
350 				{
351 					state.Begin( AsciiId<'K','0','2'>::V );
352 					state.Begin( AsciiId<'R','E','G'>::V ).Write8( ctrl ).End();
353 
354 					const byte data[5] =
355 					{
356 						irq.unit.ctrl,
357 						irq.unit.count & 0xFF,
358 						irq.unit.count >> 8,
359 						irq.unit.latch & 0xFF,
360 						irq.unit.latch >> 8
361 					};
362 
363 					state.Begin( AsciiId<'I','R','Q'>::V ).Write( data ).End();
364 					state.End();
365 				}
366 
SubSave(State::Saver & state) const367 				void Ks7010::SubSave(State::Saver& state) const
368 				{
369 					state.Begin( AsciiId<'K','7','0'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( reg ).End().End();
370 				}
371 
SubSave(State::Saver & state) const372 				void Ks7016::SubSave(State::Saver& state) const
373 				{
374 					state.Begin( AsciiId<'K','7','6'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( reg ).End().End();
375 				}
376 
SubSave(State::Saver & state) const377 				void Ks7022::SubSave(State::Saver& state) const
378 				{
379 					state.Begin( AsciiId<'K','7','2'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( reg ).End().End();
380 				}
381 
SubSave(State::Saver & state) const382 				void Ks7031::SubSave(State::Saver& state) const
383 				{
384 					state.Begin( AsciiId<'K','7','1'>::V );
385 
386 					state.Begin( AsciiId<'R','E','G'>::V ).Write( regs ).End();
387 					state.End();
388 				}
389 
SubSave(State::Saver & state) const390 				void Ks7037::SubSave(State::Saver& state) const
391 				{
392 					state.Begin( AsciiId<'K','7','7'>::V );
393 
394 					const byte data[9] =
395 					{
396 						regs[0], regs[1], regs[2], regs[3],
397 						regs[4], regs[5], regs[6], regs[7],
398 						regNum
399 					};
400 
401 					state.Begin( AsciiId<'R','E','G'>::V ).Write( data ).End();
402 					state.End();
403 				}
404 
SubSave(State::Saver & state) const405 				void Ks7057::SubSave(State::Saver& state) const
406 				{
407 					state.Begin( AsciiId<'K','5','7'>::V );
408 
409 					const byte data[8] =
410 					{
411 						regs[0], regs[1], regs[2], regs[3],
412 						regs[4], regs[5], regs[6], regs[7]
413 					};
414 
415 					state.Begin( AsciiId<'R','E','G'>::V ).Write( data ).End();
416 					state.End();
417 				}
418 
419 				#ifdef NST_MSVC_OPTIMIZE
420 				#pragma optimize("", on)
421 				#endif
422 
423 				NES_POKE_D(Ks202,8000)
424 				{
425 					irq.Update();
426 					irq.unit.latch = (irq.unit.latch & 0xFFF0) | (data & 0xF) << 0;
427 				}
428 
429 				NES_POKE_D(Ks202,9000)
430 				{
431 					irq.Update();
432 					irq.unit.latch = (irq.unit.latch & 0xFF0F) | (data & 0xF) << 4;
433 				}
434 
NES_POKE_D(Ks202,A000)435 				NES_POKE_D(Ks202,A000)
436 				{
437 					irq.Update();
438 					irq.unit.latch = (irq.unit.latch & 0xF0FF) | (data & 0xF) << 8;
439 				}
440 
NES_POKE_D(Ks202,B000)441 				NES_POKE_D(Ks202,B000)
442 				{
443 					irq.Update();
444 					irq.unit.latch = (irq.unit.latch & 0x0FFF) | (data & 0xF) << 12;
445 				}
446 
NES_POKE_D(Ks202,C000)447 				NES_POKE_D(Ks202,C000)
448 				{
449 					irq.Update();
450 
451 					irq.unit.ctrl = data;
452 
453 					if (irq.Connect( data & 0xF ))
454 						irq.unit.count = irq.unit.latch;
455 
456 					irq.ClearIRQ();
457 				}
458 
NES_POKE(Ks202,D000)459 				NES_POKE(Ks202,D000)
460 				{
461 					irq.Update();
462 					irq.ClearIRQ();
463 				}
464 
NES_POKE_D(Ks202,E000)465 				NES_POKE_D(Ks202,E000)
466 				{
467 					ctrl = data;
468 				}
469 
NES_POKE_AD(Ks202,F000)470 				NES_POKE_AD(Ks202,F000)
471 				{
472 					{
473 						uint offset = (ctrl & 0xF) - 1;
474 
475 						if (offset < 3)
476 						{
477 							offset <<= 13;
478 							prg.SwapBank<SIZE_8K>( offset, (data & 0x0F) | (prg.GetBank<SIZE_8K>(offset) & 0x10) );
479 						}
480 						else if (offset < 4)
481 						{
482 							wrk.SwapBank<SIZE_8K,0x0000>( data );
483 						}
484 					}
485 
486 					switch (address & 0xC00)
487 					{
488 						case 0x000:
489 
490 							address &= 0x3;
491 
492 							if (address < 3)
493 							{
494 								address <<= 13;
495 								prg.SwapBank<SIZE_8K>( address, (prg.GetBank<SIZE_8K>(address) & 0x0F) | (data & 0x10) );
496 							}
497 							break;
498 
499 						case 0x800:
500 
501 							ppu.SetMirroring( (data & 0x1) ? Ppu::NMT_V : Ppu::NMT_H );
502 							break;
503 
504 						case 0xC00:
505 
506 							ppu.Update();
507 							chr.SwapBank<SIZE_1K>( (address & 0x7) << 10, data );
508 							break;
509 					}
510 				}
511 
Clock()512 				bool Ks202::Irq::Clock()
513 				{
514 					return (count++ == 0xFFFF) ? (count=latch, true) : false;
515 				}
516 
Sync(Event event,Input::Controllers * controllers)517 				void Ks202::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 				NES_PEEK_A(Ks7010,6000)
526 				{
527 					return *(prg.Source().Mem(reg * SIZE_8K) + (address & 0x1FFF));
528 				}
529 
NES_PEEK_A(Ks7010,FFFC)530 				NES_PEEK_A(Ks7010,FFFC)
531 				{
532 					reg = (address >> 2) & 0xF;
533 					chr.SwapBank<SIZE_8K,0x0000>( reg );
534 					ppu.Update();
535 
536 					return prg.Peek(address & 0x7FFF);
537 				}
538 
539 				NES_POKE_D(Ks7013b,6000)
540 				{
541 					prg.SwapBank<SIZE_16K>( 0x0000, data & 0x7 );
542 				}
543 
544 				NES_POKE_D(Ks7013b,8000)
545 				{
546 					ppu.SetMirroring( (data & 0x1) ? Ppu::NMT_H : Ppu::NMT_V );
547 				}
548 
549 				NES_PEEK_A(Ks7016,6000)
550 				{
551 					return *(prg.Source().Mem(reg * SIZE_8K) + (address & 0x1FFF));
552 				}
553 
554 				NES_POKE_A(Ks7016,8000)
555 				{
556 					bool mode = (address & 0x30) == 0x30;
557 
558 					switch(address & 0xD943) {
559 						case 0xD943:
560 							reg = mode ? 0xB : (address >> 2) & 0xF;
561 							break;
562 
563 						case 0xD903:
564 							reg = mode ? 0x8 | ((address >> 2) & 0x3) : reg = 0xB;
565 							break;
566 					}
567 				}
568 
569 				NES_POKE_D(Ks7022,8000)
570 				{
571 					ppu.SetMirroring( (data & 0x4) ? Ppu::NMT_H : Ppu::NMT_V );
572 				}
573 
NES_POKE_D(Ks7022,A000)574 				NES_POKE_D(Ks7022,A000)
575 				{
576 					reg = data & 0xF;
577 				}
578 
NES_PEEK(Ks7022,FFFC)579 				NES_PEEK(Ks7022,FFFC)
580 				{
581 					ppu.Update();
582 					chr.SwapBank<SIZE_8K,0x0000>( reg );
583 					prg.SwapBanks<SIZE_16K,0x0000>( reg, reg );
584 
585 					return prg.Peek(0x7FFC);
586 				}
587 
588 				NES_POKE_AD(Ks7031,8000)
589 				{
590 					regs[(address >> 11) & 0x03] = data;
591 				}
592 
593 				NES_PEEK_A(Ks7031,6000)
594 				{
595 					int bank, new_addr;
596 
597 					if (address < 0x8000)
598 						bank = regs[(address >> 11) & 0x03];
599 					else
600 						bank = 0x0f - ((address >> 11) & 0x0f);
601 
602 					new_addr = ((bank << 11) % prg.Source(0).Size()) | (address & 0x07ff);
603 
604 					return prg[0][new_addr];
605 				}
606 
607 				NES_PEEK_A(Ks7032,6000)
608 				{
609 					return wrk[0][address - 0x6000];
610 				}
611 
612 				NES_PEEK_A(Ks7037,6000)
613 				{
614 					NST_VERIFY( wrk.Readable(0) );
615 					return wrk.Readable(0) ? wrk[0][address - 0x6000] : (address >> 8);
616 				}
617 
618 				NES_POKE_AD(Ks7037,6000)
619 				{
620 					NST_VERIFY( wrk.Writable(0) );
621 
622 					if (wrk.Writable(0))
623 						wrk[0][address- 0x6000] = data;
624 				}
625 
626 				NES_PEEK_A(Ks7037,7000)
627 				{
628 					return *(prg.Source().Mem(SIZE_4K * 15) + (address & 0xFFF));
629 				}
630 
631 				NES_PEEK_A(Ks7037,8000)
632 				{
633 					return *(prg.Source().Mem(regs[6] * SIZE_8K) + (address & 0x1FFF));
634 				}
635 
636 				NES_POKE_D(Ks7037,8000)
637 				{
638 					regNum = data & 0x7U;
639 					byte mirror[4] = { regs[2], regs[4], regs[3], regs[5] };
640 					ppu.SetMirroring(mirror);
641 				}
642 
643 				NES_POKE_D(Ks7037,8001)
644 				{
645 					regs[regNum] = data;
646 				}
647 
NES_PEEK_A(Ks7037,A000)648 				NES_PEEK_A(Ks7037,A000)
649 				{
650 					return *(prg.Source().Mem(SIZE_4K * 28) + (address & 0xFFF));
651 				}
652 
NES_PEEK_A(Ks7037,B000)653 				NES_PEEK_A(Ks7037,B000)
654 				{
655 					NST_VERIFY( wrk.Readable(0) );
656 					return wrk.Readable(0) ? wrk[0][address - 0xA000] : (address >> 8);
657 				}
658 
NES_POKE_AD(Ks7037,B000)659 				NES_POKE_AD(Ks7037,B000)
660 				{
661 					NST_VERIFY( wrk.Writable(0) );
662 
663 					if (wrk.Writable(0))
664 						wrk[0][address- 0xA000] = data;
665 				}
666 
NES_PEEK_A(Ks7037,C000)667 				NES_PEEK_A(Ks7037,C000)
668 				{
669 					return *(prg.Source().Mem(regs[7] * SIZE_8K) + (address & 0x1FFF));
670 				}
671 
NES_PEEK_A(Ks7037,E000)672 				NES_PEEK_A(Ks7037,E000)
673 				{
674 					return *(prg.Source().Mem(SIZE_8K * 15) + (address & 0x1FFF));
675 				}
676 
677 				NES_PEEK_A(Ks7057,6000)
678 				{
679 					return *(prg.Source().Mem(regs[(address >> 11) - 0xC] * SIZE_2K) + (address & 0x7FF));
680 				}
681 
682 				NES_POKE_D(Ks7057,8000)
683 				{
684 					ppu.SetMirroring( (data & 0x1) ? Ppu::NMT_V : Ppu::NMT_H );
685 				}
686 
NES_POKE_AD(Ks7057,B000)687 				NES_POKE_AD(Ks7057,B000)
688 				{
689 					switch(address & 0xF003)
690 					{
691 						case 0xB000: regs[4] = (regs[4] & 0xF0) | (data & 0xF); break;
692 						case 0xB001: regs[4] = (regs[4] & 0xF) | (data << 4); break;
693 						case 0xB002: regs[5] = (regs[5] & 0xF0) | (data & 0xF); break;
694 						case 0xB003: regs[5] = (regs[5] & 0xF) | (data << 4); break;
695 						case 0xC000: regs[6] = (regs[6] & 0xF0) | (data & 0xF); break;
696 						case 0xC001: regs[6] = (regs[6] & 0xF) | (data << 4); break;
697 						case 0xC002: regs[7] = (regs[7] & 0xF0) | (data & 0xF); break;
698 						case 0xC003: regs[7] = (regs[7] & 0xF) | (data << 4); break;
699 						case 0xD000: regs[0] = (regs[0] & 0xF0) | (data & 0xF); break;
700 						case 0xD001: regs[0] = (regs[0] & 0xF) | (data << 4); break;
701 						case 0xD002: regs[1] = (regs[1] & 0xF0) | (data & 0xF); break;
702 						case 0xD003: regs[1] = (regs[1] & 0xF) | (data << 4); break;
703 						case 0xE000: regs[2] = (regs[2] & 0xF0) | (data & 0xF); break;
704 						case 0xE001: regs[2] = (regs[2] & 0xF) | (data << 4); break;
705 						case 0xE002: regs[3] = (regs[3] & 0xF0) | (data & 0xF); break;
706 						case 0xE003: regs[3] = (regs[3] & 0xF) | (data << 4); break;
707 					}
708 				}
709 			}
710 		}
711 	}
712 }
713