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 "NstBoardNanjing.hpp"
27 
28 namespace Nes
29 {
30 	namespace Core
31 	{
32 		namespace Boards
33 		{
34 			namespace Nanjing
35 			{
36 				#ifdef NST_MSVC_OPTIMIZE
37 				#pragma optimize("s", on)
38 				#endif
39 
SubReset(bool)40 				void Standard::SubReset(bool)
41 				{
42 					strobe = 0xFF;
43 					regs[0] = 0xFF;
44 					regs[1] = 0x00;
45 					trigger = 0x00;
46 					security = 0x00;
47 
48 					ppu.SetHBlankHook( Hook(this,&Standard::Hook_HBlank) );
49 
50 					for (uint i=0x5000; i < 0x6000; i += 0x800)
51 					{
52 						Map( i + 0x000, i + 0x0FF, &Standard::Peek_5000 );
53 						Map( i + 0x100, i + 0x1FF, &Standard::Peek_5100 );
54 						Map( i + 0x200, i + 0x4FF, &Standard::Peek_5000 );
55 						Map( i + 0x500, i + 0x5FF, &Standard::Peek_5500 );
56 						Map( i + 0x600, i + 0x7FF, &Standard::Peek_5000 );
57 					}
58 
59 					Map( 0x5100U, &Standard::Poke_5100 );
60 					Map( 0x5101U, &Standard::Poke_5101 );
61 
62 					for (uint i=0x5000; i < 0x6000; i += 0x400)
63 					{
64 						Map( i + 0x000, i + 0x0FF, &Standard::Poke_5000 );
65 						Map( i + 0x200, i + 0x2FF, &Standard::Poke_5000 );
66 						Map( i + 0x300, i + 0x3FF, &Standard::Poke_5300 );
67 					}
68 				}
69 
SubLoad(State::Loader & state,const dword baseChunk)70 				void Standard::SubLoad(State::Loader& state,const dword baseChunk)
71 				{
72 					NST_VERIFY( baseChunk == (AsciiId<'N','J','N'>::V) );
73 
74 					if (baseChunk == AsciiId<'N','J','N'>::V)
75 					{
76 						while (const dword chunk = state.Begin())
77 						{
78 							switch (chunk)
79 							{
80 								case AsciiId<'R','E','G'>::V:
81 								{
82 									State::Loader::Data<2> data( state );
83 
84 									regs[0] = data[0];
85 									regs[1] = data[1];
86 									break;
87 								}
88 
89 								case AsciiId<'S','E','C'>::V:
90 								{
91 									State::Loader::Data<3> data( state );
92 
93 									strobe = data[0];
94 									trigger = (data[1] & 0x1) ? 0xFF : 0x00;
95 									security = data[2];
96 									break;
97 								}
98 							}
99 
100 							state.End();
101 						}
102 					}
103 				}
104 
SubSave(State::Saver & state) const105 				void Standard::SubSave(State::Saver& state) const
106 				{
107 					state.Begin( AsciiId<'N','J','N'>::V );
108 
109 					{
110 						const byte data[2] = { regs[0], regs[1] };
111 						state.Begin( AsciiId<'R','E','G'>::V ).Write( data ).End();
112 					}
113 
114 					{
115 						const byte data[3] = { strobe, trigger ? 0x1 : 0x0, security };
116 						state.Begin( AsciiId<'S','E','C'>::V ).Write( data ).End();
117 					}
118 
119 					state.End();
120 				}
121 
122 				#ifdef NST_MSVC_OPTIMIZE
123 				#pragma optimize("", on)
124 				#endif
125 
126 				NES_PEEK(Standard,5000)
127 				{
128 					return 0x4;
129 				}
130 
131 				NES_POKE_AD(Standard,5000)
132 				{
133 					regs[address >> 9 & 0x1] = data;
134 					prg.SwapBank<SIZE_32K,0x0000>( (regs[0] & 0xFU) | (regs[1] << 4) );
135 
136 					if (!((address & 0x0300) | (regs[0] & 0x80U)))
137 					{
138 						ppu.Update();
139 
140 						if (ppu.GetScanline() <= 127)
141 							chr.SwapBank<SIZE_8K,0x0000>(0);
142 					}
143 				}
144 
145 				NES_PEEK(Standard,5100)
146 				{
147 					return security;
148 				}
149 
150 				NES_POKE_D(Standard,5100)
151 				{
152 					if (data == 0x6)
153 						prg.SwapBank<SIZE_32K,0x0000>( 0x3 );
154 				}
155 
156 				NES_POKE_D(Standard,5101)
157 				{
158 					const uint address = strobe;
159 					strobe = data;
160 
161 					if (address && !data)
162 						trigger ^= 0xFFU;
163 				}
164 
165 				NES_POKE_D(Standard,5300)
166 				{
167 					security = data;
168 				}
169 
170 				NES_PEEK(Standard,5500)
171 				{
172 					return security & trigger;
173 				}
174 
NES_HOOK(Standard,HBlank)175 				NES_HOOK(Standard,HBlank)
176 				{
177 					if ((regs[0] & 0x80U) && ppu.IsEnabled())
178 					{
179 						switch (const int scanline=ppu.GetScanline())
180 						{
181 							case 127:
182 							case 239:
183 
184 								chr.SwapBanks<SIZE_4K,0x0000>( scanline == 127, scanline == 127 );
185 								break;
186 						}
187 					}
188 				}
189 			}
190 		}
191 	}
192 }
193