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 "../NstTimer.hpp"
26 #include "NstBoard.hpp"
27 #include "NstBoardKonamiVrc4.hpp"
28 #include "NstBoardUnlWorldHero.hpp"
29 
30 namespace Nes
31 {
32 	namespace Core
33 	{
34 		namespace Boards
35 		{
36 			namespace Unlicensed
37 			{
38 				#ifdef NST_MSVC_OPTIMIZE
39 				#pragma optimize("s", on)
40 				#endif
41 
WorldHero(const Context & c)42 				WorldHero::WorldHero(const Context& c)
43 				: Board(c), irq(*c.cpu) {}
44 
SubReset(const bool hard)45 				void WorldHero::SubReset(const bool hard)
46 				{
47 					if (hard)
48 						prgSwap = 0;
49 
50 					irq.Reset( hard, hard ? false : irq.Connected() );
51 
52 					for (dword i=0x8000; i <= 0xFFFF; ++i)
53 					{
54 						switch (i & 0xF0C3)
55 						{
56 							case 0x8000: Map( i, &WorldHero::Poke_8000 ); break;
57 							case 0x9000: Map( i, NMT_SWAP_VH01         ); break;
58 							case 0x9002:
59 							case 0x9080: Map( i, &WorldHero::Poke_9000 ); break;
60 							case 0xA000: Map( i, PRG_SWAP_8K_1         ); break;
61 							case 0xB000:
62 							case 0xB001:
63 							case 0xB002:
64 							case 0xB003:
65 							case 0xC000:
66 							case 0xC001:
67 							case 0xC002:
68 							case 0xC003:
69 							case 0xD000:
70 							case 0xD001:
71 							case 0xD002:
72 							case 0xD003:
73 							case 0xE000:
74 							case 0xE001:
75 							case 0xE002:
76 							case 0xE003: Map( i, &WorldHero::Poke_B000 ); break;
77 							case 0xF000: Map( i, &WorldHero::Poke_F000 ); break;
78 							case 0xF001: Map( i, &WorldHero::Poke_F001 ); break;
79 							case 0xF002: Map( i, &WorldHero::Poke_F002 ); break;
80 							case 0xF003: Map( i, &WorldHero::Poke_F003 ); break;
81 						}
82 					}
83 				}
84 
SubLoad(State::Loader & state,const dword baseChunk)85 				void WorldHero::SubLoad(State::Loader& state,const dword baseChunk)
86 				{
87 					NST_VERIFY( baseChunk == (AsciiId<'U','W','H'>::V) );
88 
89 					if (baseChunk == AsciiId<'U','W','H'>::V)
90 					{
91 						while (const dword chunk = state.Begin())
92 						{
93 							switch (chunk)
94 							{
95 								case AsciiId<'R','E','G'>::V:
96 
97 									prgSwap = state.Read8() & 0x2;
98 									break;
99 
100 								case AsciiId<'I','R','Q'>::V:
101 
102 									irq.LoadState( state );
103 									break;
104 							}
105 
106 							state.End();
107 						}
108 					}
109 				}
110 
SubSave(State::Saver & state) const111 				void WorldHero::SubSave(State::Saver& state) const
112 				{
113 					state.Begin( AsciiId<'U','W','H'>::V );
114 					state.Begin( AsciiId<'R','E','G'>::V ).Write8( prgSwap ).End();
115 					irq.SaveState( state, AsciiId<'I','R','Q'>::V );
116 					state.End();
117 				}
118 
119 				#ifdef NST_MSVC_OPTIMIZE
120 				#pragma optimize("", on)
121 				#endif
122 
123 				NES_POKE_D(WorldHero,8000)
124 				{
125 					prg.SwapBank<SIZE_8K>( prgSwap << 13, data );
126 				}
127 
128 				NES_POKE_D(WorldHero,9000)
129 				{
130 					data &= 0x2;
131 
132 					if (prgSwap != data)
133 					{
134 						prgSwap = data;
135 
136 						prg.SwapBanks<SIZE_8K,0x0000>
137 						(
138 							prg.GetBank<SIZE_8K,0x4000>(),
139 							prg.GetBank<SIZE_8K,0x0000>()
140 						);
141 					}
142 				}
143 
NES_POKE_AD(WorldHero,B000)144 				NES_POKE_AD(WorldHero,B000)
145 				{
146 					ppu.Update();
147 					const bool part = address & 0x1;
148 					address = ((address - 0xB000) >> 1 & 0x1800) | (address << 9 & 0x0400);
149 					chr.SwapBank<SIZE_1K>( address, (chr.GetBank<SIZE_1K>(address) & (part ? 0x00F : 0xFF0)) | (part ? data << 4 : data & 0xF) );
150 				}
151 
NES_POKE_D(WorldHero,F000)152 				NES_POKE_D(WorldHero,F000)
153 				{
154 					irq.WriteLatch0( data );
155 				}
156 
NES_POKE_D(WorldHero,F001)157 				NES_POKE_D(WorldHero,F001)
158 				{
159 					irq.WriteLatch1( data );
160 				}
161 
NES_POKE_D(WorldHero,F002)162 				NES_POKE_D(WorldHero,F002)
163 				{
164 					irq.Toggle( data );
165 				}
166 
NES_POKE(WorldHero,F003)167 				NES_POKE(WorldHero,F003)
168 				{
169 					irq.Toggle();
170 				}
171 
Sync(Event event,Input::Controllers * controllers)172 				void WorldHero::Sync(Event event,Input::Controllers* controllers)
173 				{
174 					if (event == EVENT_END_FRAME)
175 						irq.VSync();
176 
177 					Board::Sync( event, controllers );
178 				}
179 			}
180 		}
181 	}
182 }
183