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 "NstBoardBtlSmb3.hpp" 28 29 namespace Nes 30 { 31 namespace Core 32 { 33 namespace Boards 34 { 35 namespace Btl 36 { 37 #ifdef NST_MSVC_OPTIMIZE 38 #pragma optimize("s", on) 39 #endif 40 Smb3(const Context & c)41 Smb3::Smb3(const Context& c) 42 : Board(c), irq(*c.cpu) {} 43 Reset(const bool hard)44 void Smb3::Irq::Reset(const bool hard) 45 { 46 if (hard) 47 { 48 enabled = false; 49 count = 0; 50 } 51 } 52 SubReset(const bool hard)53 void Smb3::SubReset(const bool hard) 54 { 55 irq.Reset( hard, true ); 56 57 for (uint i=0x0000; i < 0x8000; i += 0x10) 58 { 59 Map( i + 0x8000U, &Smb3::Poke_8000 ); 60 Map( i + 0x8001U, &Smb3::Poke_8001 ); 61 Map( i + 0x8002U, &Smb3::Poke_8000 ); 62 Map( i + 0x8003U, &Smb3::Poke_8001 ); 63 Map( i + 0x8004U, i + 0x8007U, &Smb3::Poke_8004 ); 64 Map( i + 0x8008U, i + 0x800BU, &Smb3::Poke_8008 ); 65 Map( i + 0x800CU, &Smb3::Poke_800C ); 66 Map( i + 0x800DU, &Smb3::Poke_800D ); 67 Map( i + 0x800EU, &Smb3::Poke_800E ); 68 Map( i + 0x800FU, &Smb3::Poke_800F ); 69 } 70 } 71 SubLoad(State::Loader & state,const dword baseChunk)72 void Smb3::SubLoad(State::Loader& state,const dword baseChunk) 73 { 74 NST_VERIFY( (baseChunk == AsciiId<'B','S','3'>::V) ); 75 76 if (baseChunk == AsciiId<'B','S','3'>::V) 77 { 78 while (const dword chunk = state.Begin()) 79 { 80 if (chunk == AsciiId<'I','R','Q'>::V) 81 { 82 State::Loader::Data<3> data( state ); 83 84 irq.unit.enabled = data[0] & 0x1; 85 irq.unit.count = data[1] | data[2] << 8; 86 } 87 88 state.End(); 89 } 90 } 91 } 92 SubSave(State::Saver & state) const93 void Smb3::SubSave(State::Saver& state) const 94 { 95 const byte data[3] = 96 { 97 irq.unit.enabled ? 0x1 : 0x0, 98 irq.unit.count & 0xFF, 99 irq.unit.count >> 8 100 }; 101 102 state.Begin( AsciiId<'B','S','3'>::V ).Begin( AsciiId<'I','R','Q'>::V ).Write( data ).End().End(); 103 } 104 105 #ifdef NST_MSVC_OPTIMIZE 106 #pragma optimize("", on) 107 #endif 108 UpdateChr(uint address,uint data) const109 void Smb3::UpdateChr(uint address,uint data) const 110 { 111 ppu.Update(); 112 chr.SwapBank<SIZE_1K>( address << 10 & 0x1C00, data ); 113 } 114 115 NES_POKE_AD(Smb3,8000) 116 { 117 UpdateChr( address, data & 0xFE ); 118 } 119 120 NES_POKE_AD(Smb3,8001) 121 { 122 UpdateChr( address, data | 0x01 ); 123 } 124 125 NES_POKE_AD(Smb3,8004) 126 { 127 UpdateChr( address, data ); 128 } 129 130 NES_POKE_AD(Smb3,8008) 131 { 132 address = address << 13 & 0x6000; 133 prg.SwapBank<SIZE_8K>( address, data | (address == 0x0000 || address == 0x6000 ? 0x10 : 0x00) ); 134 } 135 136 NES_POKE_D(Smb3,800C) 137 { 138 ppu.SetMirroring( (data & 0x1) ? Ppu::NMT_H : Ppu::NMT_V ); 139 } 140 141 NES_POKE_D(Smb3,800D) 142 { 143 irq.Update(); 144 irq.unit.count = 0; 145 irq.unit.enabled = false; 146 irq.ClearIRQ(); 147 } 148 149 NES_POKE_D(Smb3,800E) 150 { 151 irq.Update(); 152 irq.unit.count = (irq.unit.count & 0xFF00) | (data << 0); 153 } 154 155 NES_POKE_D(Smb3,800F) 156 { 157 irq.Update(); 158 irq.unit.count = (irq.unit.count & 0x00FF) | (data << 8); 159 irq.unit.enabled = true; 160 } 161 Clock()162 bool Smb3::Irq::Clock() 163 { 164 return enabled && (count = (count + 1) & 0xFFFF) == 0x0000 ? (enabled=false, true) : false; 165 } 166 Sync(Event event,Input::Controllers * controllers)167 void Smb3::Sync(Event event,Input::Controllers* controllers) 168 { 169 if (event == EVENT_END_FRAME) 170 irq.VSync(); 171 172 Board::Sync( event, controllers ); 173 } 174 } 175 } 176 } 177 } 178