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 "NstBoardMmc3.hpp" 27 #include "NstBoardSomeriTeam.hpp" 28 29 namespace Nes 30 { 31 namespace Core 32 { 33 namespace Boards 34 { 35 namespace SomeriTeam 36 { 37 #ifdef NST_MSVC_OPTIMIZE 38 #pragma optimize("s", on) 39 #endif 40 Sl12(const Context & c)41 Sl12::Sl12(const Context& c) 42 : 43 Board (c), 44 irq (*c.cpu,*c.ppu,false) 45 {} 46 SubReset(const bool hard)47 void Sl12::SubReset(const bool hard) 48 { 49 irq.Reset( hard ); 50 51 if (hard) 52 { 53 mode = 0; 54 55 vrc2.prg[0] = 0x0; 56 vrc2.prg[1] = 0x1; 57 vrc2.nmt = 0; 58 59 for (uint i=0; i < 8; ++i) 60 vrc2.chr[i] = i; 61 62 mmc3.ctrl = 0; 63 mmc3.nmt = 0; 64 65 mmc3.banks[0] = 0x0; 66 mmc3.banks[1] = 0x1; 67 mmc3.banks[2] = 0x4; 68 mmc3.banks[3] = 0x5; 69 mmc3.banks[4] = 0x6; 70 mmc3.banks[5] = 0x7; 71 72 mmc3.banks[6] = 0x3C; 73 mmc3.banks[7] = 0x3D; 74 mmc3.banks[8] = 0xFE; 75 mmc3.banks[9] = 0xFF; 76 77 mmc1.buffer = 0; 78 mmc1.shifter = 0; 79 80 mmc1.regs[0] = 0x4U|0x8U; 81 mmc1.regs[1] = 0; 82 mmc1.regs[2] = 0; 83 mmc1.regs[3] = 0; 84 } 85 86 for (uint i=0x4100; i < 0x6000; i += 0x200) 87 Map( i + 0x00, i + 0xFF, &Sl12::Poke_4100 ); 88 89 Map( 0x8000U, 0x8FFFU, &Sl12::Poke_8000 ); 90 Map( 0x9000U, 0x9FFFU, &Sl12::Poke_9000 ); 91 Map( 0xA000U, 0xAFFFU, &Sl12::Poke_A000 ); 92 Map( 0xB000U, 0xBFFFU, &Sl12::Poke_B000 ); 93 Map( 0xC000U, 0xCFFFU, &Sl12::Poke_C000 ); 94 Map( 0xD000U, 0xDFFFU, &Sl12::Poke_D000 ); 95 Map( 0xE000U, 0xEFFFU, &Sl12::Poke_E000 ); 96 Map( 0xF000U, 0xFFFFU, &Sl12::Poke_F000 ); 97 98 UpdatePrg(); 99 UpdateNmt(); 100 UpdateChr(); 101 } 102 SubLoad(State::Loader & state,const dword baseChunk)103 void Sl12::SubLoad(State::Loader& state,const dword baseChunk) 104 { 105 NST_VERIFY( baseChunk == (AsciiId<'S','1','2'>::V) ); 106 107 if (baseChunk == AsciiId<'S','1','2'>::V) 108 { 109 while (const dword chunk = state.Begin()) 110 { 111 switch (chunk) 112 { 113 case AsciiId<'R','E','G'>::V: 114 115 mode = state.Read8(); 116 break; 117 118 case AsciiId<'V','R','2'>::V: 119 120 state.Read( vrc2.chr ); 121 state.Read( vrc2.prg ); 122 vrc2.nmt = state.Read8(); 123 break; 124 125 case AsciiId<'M','M','3'>::V: 126 127 state.Read( mmc3.banks ); 128 mmc3.ctrl = state.Read8(); 129 mmc3.nmt = state.Read8(); 130 break; 131 132 case AsciiId<'M','M','1'>::V: 133 134 state.Read( mmc1.regs ); 135 mmc1.buffer = state.Read8(); 136 mmc1.shifter = state.Read8(); 137 break; 138 139 case AsciiId<'I','R','Q'>::V: 140 141 irq.unit.LoadState( state ); 142 break; 143 } 144 145 state.End(); 146 } 147 } 148 149 UpdatePrg(); 150 UpdateNmt(); 151 UpdateChr(); 152 } 153 SubSave(State::Saver & state) const154 void Sl12::SubSave(State::Saver& state) const 155 { 156 state.Begin( AsciiId<'S','1','2'>::V ); 157 state.Begin( AsciiId<'R','E','G'>::V ).Write8( mode ).End(); 158 state.Begin( AsciiId<'V','R','2'>::V ).Write( vrc2.chr ).Write( vrc2.prg ).Write8( vrc2.nmt ).End(); 159 state.Begin( AsciiId<'M','M','3'>::V ).Write( mmc3.banks ).Write8( mmc3.ctrl ).Write8( mmc3.nmt ).End(); 160 state.Begin( AsciiId<'M','M','1'>::V ).Write( mmc1.regs ).Write8( mmc1.buffer ).Write8( mmc1.shifter ).End(); 161 irq.unit.SaveState( state, AsciiId<'I','R','Q'>::V ); 162 state.End(); 163 } 164 165 #ifdef NST_MSVC_OPTIMIZE 166 #pragma optimize("", on) 167 #endif 168 UpdatePrg()169 void Sl12::UpdatePrg() 170 { 171 switch (mode & 0x3) 172 { 173 case 0x0: 174 175 prg.SwapBanks<SIZE_8K,0x0000>( vrc2.prg[0], vrc2.prg[1], 0x1E, 0x1F ); 176 break; 177 178 case 0x1: 179 { 180 const uint i = mmc3.ctrl >> 5 & 0x2U; 181 prg.SwapBanks<SIZE_8K,0x0000>( mmc3.banks[6+i], mmc3.banks[6+1], mmc3.banks[6+(i^2)], mmc3.banks[6+3] ); 182 break; 183 } 184 185 case 0x2: 186 { 187 const uint bank = mmc1.regs[3] & 0xFU; 188 189 if (mmc1.regs[0] & 0x8U) 190 prg.SwapBanks<SIZE_16K,0x0000>( (mmc1.regs[0] & 0x4U) ? bank : 0x0, (mmc1.regs[0] & 0x4U) ? 0xF : bank ); 191 else 192 prg.SwapBank<SIZE_32K,0x0000>( bank >> 1 ); 193 194 break; 195 } 196 } 197 } 198 UpdateChr() const199 void Sl12::UpdateChr() const 200 { 201 const uint base = (mode & 0x4) << 6; 202 203 switch (mode & 0x3) 204 { 205 case 0x0: 206 207 chr.SwapBanks<SIZE_1K,0x0000>( base|vrc2.chr[0], base|vrc2.chr[1], base|vrc2.chr[2], base|vrc2.chr[3], base|vrc2.chr[4], base|vrc2.chr[5], base|vrc2.chr[6], base|vrc2.chr[7] ); 208 break; 209 210 case 0x1: 211 { 212 const uint swap = (mmc3.ctrl & 0x80U) << 5; 213 chr.SwapBanks<SIZE_2K>( 0x0000 ^ swap, base >> 1 | mmc3.banks[0], base >> 1 | mmc3.banks[1] ); 214 chr.SwapBanks<SIZE_1K>( 0x1000 ^ swap, base|mmc3.banks[2], base|mmc3.banks[3], base|mmc3.banks[4], base|mmc3.banks[5] ); 215 break; 216 } 217 218 case 0x2: 219 220 chr.SwapBanks<SIZE_4K,0x0000>( (mmc1.regs[0] & 0x10U) ? mmc1.regs[1] : mmc1.regs[1] & 0x1EU, (mmc1.regs[0] & 0x10U) ? mmc1.regs[2] : mmc1.regs[1] | 0x01U ); 221 break; 222 } 223 } 224 UpdateNmt() const225 void Sl12::UpdateNmt() const 226 { 227 Ppu::NmtMirroring nmtCtrl; 228 229 switch (mode & 0x3) 230 { 231 case 0x0: 232 233 nmtCtrl = (vrc2.nmt & 0x1U) ? Ppu::NMT_H : Ppu::NMT_V; 234 break; 235 236 case 0x1: 237 238 nmtCtrl = (mmc3.nmt & 0x1U) ? Ppu::NMT_H : Ppu::NMT_V; 239 break; 240 241 case 0x2: 242 243 switch (mmc1.regs[0] & 0x3U) 244 { 245 case 0x0: nmtCtrl = Ppu::NMT_0; break; 246 case 0x1: nmtCtrl = Ppu::NMT_1; break; 247 case 0x2: nmtCtrl = Ppu::NMT_V; break; 248 default: nmtCtrl = Ppu::NMT_H; break; 249 } 250 break; 251 252 default: return; 253 } 254 255 ppu.SetMirroring( nmtCtrl ); 256 } 257 Poke_Vrc2_8000(uint address,uint data)258 void Sl12::Poke_Vrc2_8000(uint address,uint data) 259 { 260 NST_ASSERT( (mode & 0x3) == 0 ); 261 262 data &= 0x1F; 263 address = address >> 13 & 0x1; 264 265 if (vrc2.prg[address] != data) 266 { 267 vrc2.prg[address] = data; 268 UpdatePrg(); 269 } 270 } 271 Poke_Vrc2_9000(uint,uint data)272 void Sl12::Poke_Vrc2_9000(uint,uint data) 273 { 274 NST_ASSERT( (mode & 0x3) == 0 ); 275 276 data &= 0x1; 277 278 if (vrc2.nmt != data) 279 { 280 vrc2.nmt = data; 281 UpdateNmt(); 282 } 283 } 284 Poke_Vrc2_B000(uint address,uint data)285 void Sl12::Poke_Vrc2_B000(uint address,uint data) 286 { 287 NST_ASSERT( (mode & 0x3) == 0 ); 288 289 data = (data & 0xF) << (address << 1 & 0x4); 290 address = ((address - 0xB000) >> 11 & 0x6) | (address & 0x1); 291 292 if (vrc2.chr[address] != data) 293 { 294 vrc2.chr[address] = data; 295 ppu.Update(); 296 UpdateChr(); 297 } 298 } 299 Poke_Mmc3_8000(uint address,uint data)300 void Sl12::Poke_Mmc3_8000(uint address,uint data) 301 { 302 NST_ASSERT( (mode & 0x3) == 1 ); 303 304 if (address & 0x1) 305 { 306 address = mmc3.ctrl & 0x7U; 307 308 if (address < 2) 309 data >>= 1; 310 311 if (mmc3.banks[address] != data) 312 { 313 mmc3.banks[address] = data; 314 315 if (address < 6) 316 { 317 ppu.Update(); 318 UpdateChr(); 319 } 320 else 321 { 322 UpdatePrg(); 323 } 324 } 325 } 326 else 327 { 328 address = mmc3.ctrl ^ data; 329 mmc3.ctrl = data; 330 331 if (address & 0x40) 332 UpdatePrg(); 333 334 if (address & (0x80U|0x07U)) 335 { 336 ppu.Update(); 337 UpdateChr(); 338 } 339 } 340 } 341 Poke_Mmc3_A000(uint address,uint data)342 void Sl12::Poke_Mmc3_A000(uint address,uint data) 343 { 344 NST_ASSERT( (mode & 0x3) == 1 ); 345 346 if (!(address & 0x1)) 347 { 348 if (mmc3.nmt != data) 349 { 350 mmc3.nmt = data; 351 UpdateNmt(); 352 } 353 } 354 } 355 Poke_Mmc3_C000(uint address,uint data)356 void Sl12::Poke_Mmc3_C000(uint address,uint data) 357 { 358 NST_ASSERT( (mode & 0x3) == 1 ); 359 360 irq.Update(); 361 362 if (address & 0x1) 363 irq.unit.Reload(); 364 else 365 irq.unit.SetLatch( data ); 366 } 367 Poke_Mmc3_E000(uint address,uint)368 void Sl12::Poke_Mmc3_E000(uint address,uint) 369 { 370 NST_ASSERT( (mode & 0x3) == 1 ); 371 372 irq.Update(); 373 374 if (address & 0x1) 375 irq.unit.Enable(); 376 else 377 irq.unit.Disable( cpu ); 378 } 379 Poke_Mmc1_8000(uint address,uint data)380 void Sl12::Poke_Mmc1_8000(uint address,uint data) 381 { 382 NST_ASSERT( (mode & 0x3) == 2 ); 383 384 if (!(data & 0x80)) 385 { 386 mmc1.buffer |= (data & 0x1) << mmc1.shifter++; 387 388 if (mmc1.shifter != 5) 389 return; 390 391 mmc1.shifter = 0; 392 data = mmc1.buffer; 393 mmc1.buffer = 0; 394 395 address = address >> 13 & 0x3; 396 397 if (mmc1.regs[address] != data) 398 { 399 mmc1.regs[address] = data; 400 401 UpdatePrg(); 402 UpdateNmt(); 403 UpdateChr(); 404 } 405 } 406 else 407 { 408 mmc1.buffer = 0; 409 mmc1.shifter = 0; 410 411 if ((mmc1.regs[0] & (0x4U|0x8U)) != (0x4U|0x8U)) 412 { 413 mmc1.regs[0] |= (0x4U|0x8U); 414 415 UpdatePrg(); 416 UpdateNmt(); 417 UpdateChr(); 418 } 419 } 420 } 421 422 NES_POKE_D(Sl12,4100) 423 { 424 if (mode != data) 425 { 426 mode = data; 427 428 if ((data & 0x3) != 1) 429 irq.unit.Disable( cpu ); 430 431 UpdatePrg(); 432 UpdateNmt(); 433 UpdateChr(); 434 } 435 } 436 437 NES_POKE_AD(Sl12,8000) 438 { 439 switch (mode & 0x3) 440 { 441 case 0x0: Poke_Vrc2_8000( address, data ); break; 442 case 0x1: Poke_Mmc3_8000( address, data ); break; 443 case 0x2: Poke_Mmc1_8000( address, data ); break; 444 } 445 } 446 447 NES_POKE_AD(Sl12,9000) 448 { 449 switch (mode & 0x3) 450 { 451 case 0x0: Poke_Vrc2_9000( address, data ); break; 452 case 0x1: Poke_Mmc3_8000( address, data ); break; 453 case 0x2: Poke_Mmc1_8000( address, data ); break; 454 } 455 } 456 NES_POKE_AD(Sl12,A000)457 NES_POKE_AD(Sl12,A000) 458 { 459 switch (mode & 0x3) 460 { 461 case 0x0: Poke_Vrc2_8000( address, data ); break; 462 case 0x1: Poke_Mmc3_A000( address, data ); break; 463 case 0x2: Poke_Mmc1_8000( address, data ); break; 464 } 465 } 466 NES_POKE_AD(Sl12,B000)467 NES_POKE_AD(Sl12,B000) 468 { 469 switch (mode & 0x3) 470 { 471 case 0x0: Poke_Vrc2_B000( address, data ); break; 472 case 0x1: Poke_Mmc3_A000( address, data ); break; 473 case 0x2: Poke_Mmc1_8000( address, data ); break; 474 } 475 } 476 NES_POKE_AD(Sl12,C000)477 NES_POKE_AD(Sl12,C000) 478 { 479 switch (mode & 0x3) 480 { 481 case 0x0: Poke_Vrc2_B000( address, data ); break; 482 case 0x1: Poke_Mmc3_C000( address, data ); break; 483 case 0x2: Poke_Mmc1_8000( address, data ); break; 484 } 485 } 486 NES_POKE_AD(Sl12,D000)487 NES_POKE_AD(Sl12,D000) 488 { 489 switch (mode & 0x3) 490 { 491 case 0x0: Poke_Vrc2_B000( address, data ); break; 492 case 0x1: Poke_Mmc3_C000( address, data ); break; 493 case 0x2: Poke_Mmc1_8000( address, data ); break; 494 } 495 } 496 NES_POKE_AD(Sl12,E000)497 NES_POKE_AD(Sl12,E000) 498 { 499 switch (mode & 0x3) 500 { 501 case 0x0: Poke_Vrc2_B000( address, data ); break; 502 case 0x1: Poke_Mmc3_E000( address, data ); break; 503 case 0x2: Poke_Mmc1_8000( address, data ); break; 504 } 505 } 506 NES_POKE_AD(Sl12,F000)507 NES_POKE_AD(Sl12,F000) 508 { 509 switch (mode & 0x3) 510 { 511 case 0x0: break; 512 case 0x1: Poke_Mmc3_E000( address, data ); break; 513 case 0x2: Poke_Mmc1_8000( address, data ); break; 514 } 515 } 516 Sync(Event event,Input::Controllers * controllers)517 void Sl12::Sync(Event event,Input::Controllers* controllers) 518 { 519 if (event == EVENT_END_FRAME) 520 irq.VSync(); 521 522 Board::Sync( event, controllers ); 523 } 524 } 525 } 526 } 527 } 528