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 "NstBoardBenshengBs5.hpp" 27 #include "../NstCrc32.hpp" 28 #include "../NstDipSwitches.hpp" 29 30 namespace Nes 31 { 32 namespace Core 33 { 34 namespace Boards 35 { 36 namespace Bensheng 37 { 38 #ifdef NST_MSVC_OPTIMIZE 39 #pragma optimize("s", on) 40 #endif 41 42 class Bs5::CartSwitches : public DipSwitches 43 { 44 enum Type 45 { 46 CRC_4_IN_1_A = 0x01E54556, 47 CRC_4_IN_1_B = 0x6DCE148C, 48 CRC_4_IN_1_C = 0x13E55C4C 49 }; 50 51 uint mode; 52 const Type type; 53 CartSwitches(Type t)54 explicit CartSwitches(Type t) 55 : mode(0), type(t) {} 56 57 public: 58 Create(const Context & c)59 static CartSwitches* Create(const Context& c) 60 { 61 switch (const dword crc = Crc32::Compute(c.prg.Mem(),c.prg.Size())) 62 { 63 case CRC_4_IN_1_A: 64 case CRC_4_IN_1_B: 65 case CRC_4_IN_1_C: 66 67 return new CartSwitches( static_cast<Type>(crc) ); 68 } 69 70 return NULL; 71 } 72 SetMode(uint value)73 void SetMode(uint value) 74 { 75 mode = value & 0x3; 76 } 77 GetMode() const78 uint GetMode() const 79 { 80 return mode; 81 } 82 83 private: 84 GetValue(uint) const85 uint GetValue(uint) const 86 { 87 return mode; 88 } 89 SetValue(uint,uint value)90 void SetValue(uint,uint value) 91 { 92 mode = value; 93 } 94 NumValues(uint) const95 uint NumValues(uint) const 96 { 97 return 4; 98 } 99 NumDips() const100 uint NumDips() const 101 { 102 return 1; 103 } 104 GetDipName(uint) const105 cstring GetDipName(uint) const 106 { 107 return "Mode"; 108 } 109 GetValueName(uint,uint i) const110 cstring GetValueName(uint,uint i) const 111 { 112 switch (type) 113 { 114 case CRC_4_IN_1_A: 115 { 116 static const char names[4][9] = 117 { 118 "4-in-1", 119 "23-in-1", 120 "53-in-1", 121 "163-in-1" 122 }; 123 124 return names[i]; 125 } 126 127 case CRC_4_IN_1_B: 128 { 129 static const char names[4][9] = 130 { 131 "4-in-1", 132 "32-in-1", 133 "64-in-1", 134 "128-in-1" 135 }; 136 137 return names[i]; 138 } 139 140 case CRC_4_IN_1_C: 141 { 142 static const char names[4][9] = 143 { 144 "4-in-1", 145 "21-in-1", 146 "81-in-1", 147 "151-in-1" 148 }; 149 150 return names[i]; 151 } 152 } 153 154 return NULL; 155 } 156 }; 157 Bs5(const Context & c)158 Bs5::Bs5(const Context& c) 159 : Board(c), cartSwitches(CartSwitches::Create(c)) {} 160 ~Bs5()161 Bs5::~Bs5() 162 { 163 delete cartSwitches; 164 } 165 SubReset(const bool hard)166 void Bs5::SubReset(const bool hard) 167 { 168 if (hard) 169 prg.SwapBanks<SIZE_8K,0x0000>( ~0U, ~0U, ~0U, ~0U ); 170 171 Map( 0x8000U, 0x8FFFU, &Bs5::Poke_8000 ); 172 Map( 0xA000U, 0xAFFFU, &Bs5::Poke_A000 ); 173 } 174 QueryDevice(DeviceType type)175 Bs5::Device Bs5::QueryDevice(DeviceType type) 176 { 177 if (type == DEVICE_DIP_SWITCHES) 178 return cartSwitches; 179 else 180 return Board::QueryDevice( type ); 181 } 182 SubLoad(State::Loader & state,const dword baseChunk)183 void Bs5::SubLoad(State::Loader& state,const dword baseChunk) 184 { 185 NST_VERIFY( (baseChunk == AsciiId<'B','S','5'>::V) ); 186 187 if (baseChunk == AsciiId<'B','S','5'>::V) 188 { 189 while (const dword chunk = state.Begin()) 190 { 191 if (chunk == AsciiId<'D','I','P'>::V) 192 { 193 NST_VERIFY( cartSwitches ); 194 195 if (cartSwitches) 196 cartSwitches->SetMode( state.Read8() ); 197 } 198 199 state.End(); 200 } 201 } 202 } 203 SubSave(State::Saver & state) const204 void Bs5::SubSave(State::Saver& state) const 205 { 206 if (cartSwitches) 207 state.Begin( AsciiId<'B','S','5'>::V ).Begin( AsciiId<'D','I','P'>::V ).Write8( cartSwitches->GetMode() ).End().End(); 208 } 209 210 #ifdef NST_MSVC_OPTIMIZE 211 #pragma optimize("", on) 212 #endif 213 214 NES_POKE_A(Bs5,8000) 215 { 216 ppu.Update(); 217 chr.SwapBank<SIZE_2K>( address << 1 & 0x1800, address & 0x1F ); 218 219 } 220 NES_POKE_A(Bs5,A000)221 NES_POKE_A(Bs5,A000) 222 { 223 if (address & (0x10U << (cartSwitches ? cartSwitches->GetMode() : 0))) 224 prg.SwapBank<SIZE_8K>( address << 3 & 0x6000, address & 0xF ); 225 } 226 } 227 } 228 } 229 } 230