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