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 "../NstTimer.hpp" 27 #include "NstBoardIremH3001.hpp" 28 29 namespace Nes 30 { 31 namespace Core 32 { 33 namespace Boards 34 { 35 namespace Irem 36 { 37 #ifdef NST_MSVC_OPTIMIZE 38 #pragma optimize("s", on) 39 #endif 40 H3001(const Context & c)41 H3001::H3001(const Context& c) 42 : Board(c), irq(*c.cpu) {} 43 Reset(const bool hard)44 void H3001::Irq::Reset(const bool hard) 45 { 46 if (hard) 47 { 48 enabled = false; 49 count = 0; 50 latch = 0; 51 } 52 } 53 SubReset(const bool hard)54 void H3001::SubReset(const bool hard) 55 { 56 irq.Reset( hard, true ); 57 58 Map( 0x9001U, &H3001::Poke_9001 ); 59 Map( 0x9003U, &H3001::Poke_9003 ); 60 Map( 0x9004U, &H3001::Poke_9004 ); 61 Map( 0x9005U, &H3001::Poke_9005 ); 62 Map( 0x9006U, &H3001::Poke_9006 ); 63 64 Map( 0x8000U, PRG_SWAP_8K_0 ); 65 Map( 0xA000U, PRG_SWAP_8K_1 ); 66 Map( 0xC000U, PRG_SWAP_8K_2 ); 67 Map( 0xB000U, CHR_SWAP_1K_0 ); 68 Map( 0xB001U, CHR_SWAP_1K_1 ); 69 Map( 0xB002U, CHR_SWAP_1K_2 ); 70 Map( 0xB003U, CHR_SWAP_1K_3 ); 71 Map( 0xB004U, CHR_SWAP_1K_4 ); 72 Map( 0xB005U, CHR_SWAP_1K_5 ); 73 Map( 0xB006U, CHR_SWAP_1K_6 ); 74 Map( 0xB007U, CHR_SWAP_1K_7 ); 75 } 76 SubLoad(State::Loader & state,const dword baseChunk)77 void H3001::SubLoad(State::Loader& state,const dword baseChunk) 78 { 79 NST_VERIFY( baseChunk == (AsciiId<'I','H','3'>::V) ); 80 81 if (baseChunk == AsciiId<'I','H','3'>::V) 82 { 83 while (const dword chunk = state.Begin()) 84 { 85 if (chunk == AsciiId<'I','R','Q'>::V) 86 { 87 State::Loader::Data<5> data( state ); 88 89 irq.unit.enabled = data[0] & 0x1; 90 irq.unit.latch = data[1] | data[2] << 8; 91 irq.unit.count = data[3] | data[4] << 8; 92 } 93 94 state.End(); 95 } 96 } 97 } 98 SubSave(State::Saver & state) const99 void H3001::SubSave(State::Saver& state) const 100 { 101 const byte data[5] = 102 { 103 irq.unit.enabled ? 0x1 : 0x0, 104 irq.unit.latch & 0xFF, 105 irq.unit.latch >> 8, 106 irq.unit.count & 0xFF, 107 irq.unit.count >> 8 108 }; 109 110 state.Begin( AsciiId<'I','H','3'>::V ).Begin( AsciiId<'I','R','Q'>::V ).Write( data ).End().End(); 111 } 112 113 #ifdef NST_MSVC_OPTIMIZE 114 #pragma optimize("", on) 115 #endif 116 117 NES_POKE_D(H3001,9001) 118 { 119 ppu.SetMirroring( (data & 0x80) ? Ppu::NMT_H : Ppu::NMT_V ); 120 } 121 122 NES_POKE_D(H3001,9003) 123 { 124 irq.Update(); 125 irq.unit.enabled = data & 0x80; 126 irq.ClearIRQ(); 127 } 128 129 NES_POKE(H3001,9004) 130 { 131 irq.Update(); 132 irq.unit.count = irq.unit.latch; 133 irq.ClearIRQ(); 134 } 135 136 NES_POKE_D(H3001,9005) 137 { 138 irq.Update(); 139 irq.unit.latch = (irq.unit.latch & 0x00FF) | data << 8; 140 } 141 142 NES_POKE_D(H3001,9006) 143 { 144 irq.Update(); 145 irq.unit.latch = (irq.unit.latch & 0xFF00) | data << 0; 146 } 147 Clock()148 bool H3001::Irq::Clock() 149 { 150 if (enabled && count && !--count) 151 { 152 enabled = false; 153 return true; 154 } 155 156 return false; 157 } 158 Sync(Event event,Input::Controllers * controllers)159 void H3001::Sync(Event event,Input::Controllers* controllers) 160 { 161 if (event == EVENT_END_FRAME) 162 irq.VSync(); 163 164 Board::Sync( event, controllers ); 165 } 166 } 167 } 168 } 169 } 170