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 <cstring> 26 #include "NstLog.hpp" 27 #include "NstFds.hpp" 28 #include "board/NstBoard.hpp" 29 #include "board/NstBoardMmc5.hpp" 30 #include "board/NstBoardKonami.hpp" 31 #include "board/NstBoardNamcot.hpp" 32 #include "board/NstBoardSunsoft.hpp" 33 #include "api/NstApiNsf.hpp" 34 #include "NstNsf.hpp" 35 36 namespace Nes 37 { 38 namespace Core 39 { 40 #ifdef NST_MSVC_OPTIMIZE 41 #pragma optimize("s", on) 42 #endif 43 44 class Nsf::Chips : Apu::Channel 45 { 46 struct Mmc5 : Boards::Mmc5::Sound 47 { 48 uint mul[2]; 49 byte exRam[SIZE_1K]; 50 Mmc5Nes::Core::Nsf::Chips::Mmc551 explicit Mmc5(Apu& a) 52 : Sound(a,false) {} 53 54 void Reset(); 55 void ClearExRam(); 56 57 using Sound::UpdateSettings; 58 using Sound::GetSample; 59 using Sound::Clock; 60 }; 61 62 struct Fds : Core::Fds::Sound 63 { 64 byte ram[SIZE_8K+SIZE_32K]; 65 FdsNes::Core::Nsf::Chips::Fds66 explicit Fds(Apu& a) 67 : Sound(a,false) {} 68 69 void Reset(); 70 void SwapBank(const Prg&,uint,uint); 71 72 using Sound::UpdateSettings; 73 using Sound::GetSample; 74 using Sound::Clock; 75 }; 76 77 struct N163 : Boards::Namcot::N163::Sound 78 { N163Nes::Core::Nsf::Chips::N16379 explicit N163(Apu& a) 80 : Sound(a,false) {} 81 82 using Sound::Reset; 83 using Sound::UpdateSettings; 84 using Sound::GetSample; 85 }; 86 87 struct Vrc6 : Boards::Konami::Vrc6::Sound 88 { Vrc6Nes::Core::Nsf::Chips::Vrc689 explicit Vrc6(Apu& a) 90 : Sound(a,false) {} 91 92 using Sound::Reset; 93 using Sound::UpdateSettings; 94 using Sound::GetSample; 95 }; 96 97 struct Vrc7 : Boards::Konami::Vrc7::Sound 98 { Vrc7Nes::Core::Nsf::Chips::Vrc799 explicit Vrc7(Apu& a) 100 : Sound(a,false) {} 101 102 using Sound::Reset; 103 using Sound::UpdateSettings; 104 using Sound::GetSample; 105 }; 106 107 struct S5b : Boards::Sunsoft::S5b::Sound 108 { S5bNes::Core::Nsf::Chips::S5b109 explicit S5b(Apu& a) 110 : Sound(a,false) {} 111 112 using Sound::Reset; 113 using Sound::UpdateSettings; 114 using Sound::GetSample; 115 }; 116 117 template<typename T> 118 struct Chip : Pointer<T> 119 { ChipNes::Core::Nsf::Chips::Chip120 Chip(Apu& a,uint t) 121 : Pointer<T>(t ? new T(a) : NULL) {} 122 }; 123 124 struct Clocks 125 { 126 void Reset(bool,bool); 127 128 Cycle next; 129 Cycle mmc5; 130 Cycle fds; 131 }; 132 133 void Reset(); 134 bool UpdateSettings(); 135 Sample GetSample(); 136 Cycle Clock(Cycle,Cycle,Cycle); 137 138 Clocks clocks; 139 140 public: 141 142 Chips(uint,Apu&); 143 144 Chip<Mmc5> mmc5; 145 Chip<Vrc6> vrc6; 146 Chip<Vrc7> vrc7; 147 Chip<Fds> fds; 148 Chip<S5b> s5b; 149 Chip<N163> n163; 150 }; 151 ClearExRam()152 void Nsf::Chips::Mmc5::ClearExRam() 153 { 154 std::memset( exRam, 0, sizeof(exRam) ); 155 } 156 Reset()157 void Nsf::Chips::Mmc5::Reset() 158 { 159 mul[0] = 0; 160 mul[1] = 0; 161 162 ClearExRam(); 163 164 Sound::Reset(); 165 } 166 Reset()167 void Nsf::Chips::Fds::Reset() 168 { 169 std::memset( ram, 0, sizeof(ram) ); 170 171 Sound::Reset(); 172 } 173 SwapBank(const Prg & prg,uint page,uint bank)174 void Nsf::Chips::Fds::SwapBank(const Prg& prg,uint page,uint bank) 175 { 176 std::memcpy( ram + SIZE_4K * page, prg.Source().Mem(bank * SIZE_4K), SIZE_4K ); 177 } 178 Chips(const uint types,Apu & apu)179 Nsf::Chips::Chips(const uint types,Apu& apu) 180 : 181 Channel ( apu ), 182 mmc5 ( apu, types & Api::Nsf::CHIP_MMC5 ), 183 vrc6 ( apu, types & Api::Nsf::CHIP_VRC6 ), 184 vrc7 ( apu, types & Api::Nsf::CHIP_VRC7 ), 185 fds ( apu, types & Api::Nsf::CHIP_FDS ), 186 s5b ( apu, types & Api::Nsf::CHIP_S5B ), 187 n163 ( apu, types & Api::Nsf::CHIP_N163 ) 188 { 189 Connect( UpdateSettings() ); 190 } 191 Reset(bool mmc5Chip,bool fdsChip)192 void Nsf::Chips::Clocks::Reset(bool mmc5Chip,bool fdsChip) 193 { 194 next = (mmc5Chip || fdsChip ? 0UL : Cpu::CYCLE_MAX); 195 mmc5 = (mmc5Chip ? 0UL : Cpu::CYCLE_MAX); 196 fds = (fdsChip ? 0UL : Cpu::CYCLE_MAX); 197 } 198 Reset()199 void Nsf::Chips::Reset() 200 { 201 clocks.Reset( mmc5, fds ); 202 203 if ( mmc5 ) mmc5->Reset(); 204 if ( vrc6 ) vrc6->Reset(); 205 if ( vrc7 ) vrc7->Reset(); 206 if ( fds ) fds->Reset(); 207 if ( s5b ) s5b->Reset(); 208 if ( n163 ) n163->Reset(); 209 } 210 UpdateSettings()211 bool Nsf::Chips::UpdateSettings() 212 { 213 clocks.Reset( mmc5, fds ); 214 215 return 216 ( 217 ( mmc5 ? mmc5->UpdateSettings() : 0U ) | 218 ( vrc6 ? vrc6->UpdateSettings() : 0U ) | 219 ( vrc7 ? vrc7->UpdateSettings() : 0U ) | 220 ( fds ? fds->UpdateSettings() : 0U ) | 221 ( s5b ? s5b->UpdateSettings() : 0U ) | 222 ( n163 ? n163->UpdateSettings() : 0U ) 223 ); 224 } 225 Nsf(Context & context)226 Nsf::Nsf(Context& context) 227 : 228 Image (SOUND), 229 cpu (context.cpu), 230 apu (context.apu), 231 chips (NULL), 232 favoredSystem (context.favoredSystem), 233 tuneMode (Api::Nsf::TUNE_MODE_NTSC) 234 { 235 if (context.patch && context.patchResult) 236 *context.patchResult = RESULT_ERR_UNSUPPORTED; 237 238 Stream::In stream( &context.stream ); 239 240 uint version; 241 242 { 243 byte data[5+1+2+6]; 244 stream.Read( data ); 245 246 if 247 ( 248 data[0] != Ascii<'N'>::V || 249 data[1] != Ascii<'E'>::V || 250 data[2] != Ascii<'S'>::V || 251 data[3] != Ascii<'M'>::V || 252 data[4] != 0x1A 253 ) 254 throw RESULT_ERR_INVALID_FILE; 255 256 if (!data[6] || data[9] < 0x60 || data[11] < 0x60 || data[13] < 0x60) 257 throw RESULT_ERR_CORRUPT_FILE; 258 259 songs.count = data[6]; 260 songs.start = data[7] >= 1 && data[7] <= data[6] ? data[7] - 1 : 0; 261 262 addressing.load = data[8] | uint( data[9] ) << 8; 263 addressing.init = data[10] | uint( data[11] ) << 8; 264 addressing.play = data[12] | uint( data[13] ) << 8; 265 266 version = data[5]; 267 } 268 269 stream.Read( songs.info.name, 32 ); 270 stream.Read( songs.info.artist, 32 ); 271 stream.Read( songs.info.copyright, 32 ); 272 273 songs.info.name[31] = '\0'; 274 songs.info.artist[31] = '\0'; 275 songs.info.copyright[31] = '\0'; 276 277 speed.ntsc = stream.Read16(); 278 stream.Read( banks ); 279 280 addressing.bankSwitched = 0 != 281 ( 282 uint( banks[0] ) | 283 uint( banks[1] ) | 284 uint( banks[2] ) | 285 uint( banks[3] ) | 286 uint( banks[4] ) | 287 uint( banks[5] ) | 288 uint( banks[6] ) | 289 uint( banks[7] ) 290 ); 291 292 speed.pal = stream.Read16(); 293 songs.current = songs.start; 294 295 switch (stream.Read8() & 0x3) 296 { 297 case 0x0: tuneMode = Api::Nsf::TUNE_MODE_NTSC; break; 298 case 0x1: tuneMode = Api::Nsf::TUNE_MODE_PAL; break; 299 default: tuneMode = Api::Nsf::TUNE_MODE_BOTH; break; 300 } 301 302 uint types = stream.Read8(); 303 304 if (!(types & Api::Nsf::CHIP_FDS) && addressing.load < 0x8000) 305 throw RESULT_ERR_CORRUPT_FILE; 306 307 dword length = 0; 308 309 while (length < SIZE_4096K && stream.SafeRead8() <= 0xFF) 310 ++length; 311 312 if (length <= HEADER_RESERVED_LENGTH) 313 throw RESULT_ERR_CORRUPT_FILE; 314 315 length -= HEADER_RESERVED_LENGTH; 316 stream.Seek( -idword(length) ); 317 318 { 319 const uint offset = addressing.load & 0xFFFU; 320 321 prg.Source().Set( Ram::ROM, true, false, offset + length ); 322 prg.Source().Fill( JAM ); 323 stream.Read( prg.Source().Mem() + offset, length ); 324 } 325 326 if (types & Api::Nsf::CHIP_ALL) 327 chips = new Chips (types,apu); 328 329 if (Log::Available()) 330 { 331 Log log; 332 333 log << "Nsf: version " << version; 334 335 if (*songs.info.name) 336 log << NST_LINEBREAK "Nsf: name: " << songs.info.name; 337 338 if (*songs.info.artist) 339 log << NST_LINEBREAK "Nsf: artist: " << songs.info.artist; 340 341 if (*songs.info.copyright) 342 log << NST_LINEBREAK "Nsf: copyright: " << songs.info.copyright; 343 344 log << NST_LINEBREAK "Nsf: starting song " 345 << (songs.start+1U) 346 << " of " 347 << songs.count 348 << 349 ( 350 tuneMode == Api::Nsf::TUNE_MODE_NTSC ? NST_LINEBREAK "Nsf: NTSC mode" : 351 tuneMode == Api::Nsf::TUNE_MODE_PAL ? NST_LINEBREAK "Nsf: PAL mode" : 352 NST_LINEBREAK "Nsf: PAL/NTSC mode" 353 ) 354 << NST_LINEBREAK "Nsf: " 355 << (length / SIZE_1K) 356 << (addressing.bankSwitched ? "k bank-switched " : "k flat ") 357 << ((types & Api::Nsf::CHIP_FDS) ? "PRG-RAM" : "PRG-ROM") 358 << NST_LINEBREAK "Nsf: load address - " << Log::Hex( 16, addressing.load ) 359 << NST_LINEBREAK "Nsf: init address - " << Log::Hex( 16, addressing.init ) 360 << NST_LINEBREAK "Nsf: play address - " << Log::Hex( 16, addressing.play ) 361 << NST_LINEBREAK; 362 363 if (types & Api::Nsf::CHIP_ALL) 364 { 365 if ( chips->mmc5 ) log << "Nsf: MMC5 sound chip present" NST_LINEBREAK; 366 if ( chips->vrc6 ) log << "Nsf: VRC6 sound chip present" NST_LINEBREAK; 367 if ( chips->vrc7 ) log << "Nsf: VRC7 sound chip present" NST_LINEBREAK; 368 if ( chips->fds ) log << "Nsf: FDS sound chip present" NST_LINEBREAK; 369 if ( chips->s5b ) log << "Nsf: Sunsoft5B sound chip present" NST_LINEBREAK; 370 if ( chips->n163 ) log << "Nsf: N163 sound chip present" NST_LINEBREAK; 371 } 372 } 373 } 374 ~Nsf()375 Nsf::~Nsf() 376 { 377 delete chips; 378 } 379 GetDesiredRegion() const380 Region Nsf::GetDesiredRegion() const 381 { 382 return tuneMode == Api::Nsf::TUNE_MODE_PAL ? REGION_PAL : REGION_NTSC; 383 } 384 GetDesiredSystem(Region region,CpuModel * cpu,PpuModel * ppu) const385 System Nsf::GetDesiredSystem(Region region,CpuModel* cpu,PpuModel* ppu) const 386 { 387 if ((region == REGION_PAL) && (favoredSystem == FAVORED_DENDY)) 388 { 389 if (cpu) 390 *cpu = CPU_DENDY; 391 392 if (ppu) 393 *ppu = PPU_DENDY; 394 395 return SYSTEM_DENDY; 396 } 397 else 398 { 399 return Image::GetDesiredSystem( region, cpu, ppu ); 400 } 401 } 402 GetChips() const403 uint Nsf::GetChips() const 404 { 405 uint types = 0; 406 407 if (chips) 408 { 409 if ( chips->vrc6 ) types |= Api::Nsf::CHIP_VRC6; 410 if ( chips->vrc7 ) types |= Api::Nsf::CHIP_VRC7; 411 if ( chips->fds ) types |= Api::Nsf::CHIP_FDS; 412 if ( chips->mmc5 ) types |= Api::Nsf::CHIP_MMC5; 413 if ( chips->n163 ) types |= Api::Nsf::CHIP_N163; 414 if ( chips->s5b ) types |= Api::Nsf::CHIP_S5B; 415 } 416 417 return types; 418 } 419 Reset(bool)420 void Nsf::Reset(bool) 421 { 422 cpu.Map( 0x38EC ).Set( this, &Nsf::Peek_38EC, &Nsf::Poke_Nop ); 423 cpu.Map( 0x38ED ).Set( this, &Nsf::Peek_38ED, &Nsf::Poke_Nop ); 424 cpu.Map( 0x38EE ).Set( this, &Nsf::Peek_38EE, &Nsf::Poke_Nop ); 425 cpu.Map( 0x38EF ).Set( this, &Nsf::Peek_38EF, &Nsf::Poke_Nop ); 426 cpu.Map( 0x38F0 ).Set( this, &Nsf::Peek_38F0, &Nsf::Poke_Nop ); 427 cpu.Map( 0x38F1 ).Set( this, &Nsf::Peek_38F1, &Nsf::Poke_Nop ); 428 cpu.Map( 0x38F2 ).Set( this, &Nsf::Peek_38F2, &Nsf::Poke_Nop ); 429 cpu.Map( 0x38F3 ).Set( this, &Nsf::Peek_38F3, &Nsf::Poke_Nop ); 430 cpu.Map( 0x38F4 ).Set( this, &Nsf::Peek_38F4, &Nsf::Poke_Nop ); 431 cpu.Map( 0x38F5 ).Set( this, &Nsf::Peek_38F5, &Nsf::Poke_Nop ); 432 cpu.Map( 0x38F6 ).Set( this, &Nsf::Peek_38F6, &Nsf::Poke_Nop ); 433 cpu.Map( 0x38F7 ).Set( this, &Nsf::Peek_38F7, &Nsf::Poke_Nop ); 434 cpu.Map( 0x38F8 ).Set( this, &Nsf::Peek_38F8, &Nsf::Poke_Nop ); 435 cpu.Map( 0x38F9 ).Set( this, &Nsf::Peek_38F9, &Nsf::Poke_Nop ); 436 cpu.Map( 0x38FA ).Set( this, &Nsf::Peek_38FA, &Nsf::Poke_Nop ); 437 cpu.Map( 0x38FB ).Set( this, &Nsf::Peek_38FB, &Nsf::Poke_Nop ); 438 cpu.Map( 0x38FC ).Set( this, &Nsf::Peek_38FC, &Nsf::Poke_Nop ); 439 cpu.Map( 0x38FD ).Set( this, &Nsf::Peek_38FD, &Nsf::Poke_Nop ); 440 cpu.Map( 0x38FE ).Set( this, &Nsf::Peek_38FE, &Nsf::Poke_Nop ); 441 cpu.Map( 0x38FF ).Set( this, &Nsf::Peek_38FF, &Nsf::Poke_Nop ); 442 443 cpu.Map( 0x4017 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_4017 ); 444 445 const bool fds = chips && chips->fds; 446 447 if (addressing.bankSwitched) 448 { 449 if (fds) 450 { 451 cpu.Map( 0x5FF6 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Fds_5FF6 ); 452 cpu.Map( 0x5FF7 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Fds_5FF7 ); 453 } 454 455 cpu.Map( 0x5FF8 ).Set( this, &Nsf::Peek_Nop, fds ? &Nsf::Poke_Fds_5FF8 : &Nsf::Poke_5FF8 ); 456 cpu.Map( 0x5FF9 ).Set( this, &Nsf::Peek_Nop, fds ? &Nsf::Poke_Fds_5FF9 : &Nsf::Poke_5FF9 ); 457 cpu.Map( 0x5FFA ).Set( this, &Nsf::Peek_Nop, fds ? &Nsf::Poke_Fds_5FFA : &Nsf::Poke_5FFA ); 458 cpu.Map( 0x5FFB ).Set( this, &Nsf::Peek_Nop, fds ? &Nsf::Poke_Fds_5FFB : &Nsf::Poke_5FFB ); 459 cpu.Map( 0x5FFC ).Set( this, &Nsf::Peek_Nop, fds ? &Nsf::Poke_Fds_5FFC : &Nsf::Poke_5FFC ); 460 cpu.Map( 0x5FFD ).Set( this, &Nsf::Peek_Nop, fds ? &Nsf::Poke_Fds_5FFD : &Nsf::Poke_5FFD ); 461 cpu.Map( 0x5FFE ).Set( this, &Nsf::Peek_Nop, fds ? &Nsf::Poke_Fds_5FFE : &Nsf::Poke_5FFE ); 462 cpu.Map( 0x5FFF ).Set( this, &Nsf::Peek_Nop, fds ? &Nsf::Poke_Fds_5FFF : &Nsf::Poke_5FFF ); 463 } 464 else if (!fds) 465 { 466 for (dword i=0x8000, j=0; i < 0x10000; j += (i >= (addressing.load & 0xF000U)), i += 0x1000) 467 prg.SwapBank<SIZE_4K>( i-0x8000, j ); 468 } 469 470 if (fds) 471 { 472 cpu.Map( 0x4040, 0x407F ).Set( this, &Nsf::Peek_Fds_4040, &Nsf::Poke_Fds_4040 ); 473 cpu.Map( 0x4080 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Fds_4080 ); 474 cpu.Map( 0x4082 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Fds_4082 ); 475 cpu.Map( 0x4083 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Fds_4083 ); 476 cpu.Map( 0x4084 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Fds_4084 ); 477 cpu.Map( 0x4085 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Fds_4085 ); 478 cpu.Map( 0x4086 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Fds_4086 ); 479 cpu.Map( 0x4087 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Fds_4087 ); 480 cpu.Map( 0x4088 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Fds_4088 ); 481 cpu.Map( 0x4089 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Fds_4089 ); 482 cpu.Map( 0x408A ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Fds_408A ); 483 cpu.Map( 0x4090 ).Set( this, &Nsf::Peek_Fds_4090, &Nsf::Poke_Nop ); 484 cpu.Map( 0x4092 ).Set( this, &Nsf::Peek_Fds_4092, &Nsf::Poke_Nop ); 485 cpu.Map( 0x6000, 0xFFFF ).Set( this, &Nsf::Peek_Fds_Ram, &Nsf::Poke_Fds_Ram ); 486 } 487 else 488 { 489 cpu.Map( 0x6000, 0x7FFF ).Set( this, &Nsf::Peek_Wrk, &Nsf::Poke_Wrk ); 490 cpu.Map( 0x8000, 0x8FFF ).Set( this, &Nsf::Peek_Prg_8, &Nsf::Poke_Nop ); 491 cpu.Map( 0x9000, 0x9FFF ).Set( this, &Nsf::Peek_Prg_9, &Nsf::Poke_Nop ); 492 cpu.Map( 0xA000, 0xAFFF ).Set( this, &Nsf::Peek_Prg_A, &Nsf::Poke_Nop ); 493 cpu.Map( 0xB000, 0xBFFF ).Set( this, &Nsf::Peek_Prg_B, &Nsf::Poke_Nop ); 494 cpu.Map( 0xC000, 0xCFFF ).Set( this, &Nsf::Peek_Prg_C, &Nsf::Poke_Nop ); 495 cpu.Map( 0xD000, 0xDFFF ).Set( this, &Nsf::Peek_Prg_D, &Nsf::Poke_Nop ); 496 cpu.Map( 0xE000, 0xEFFF ).Set( this, &Nsf::Peek_Prg_E, &Nsf::Poke_Nop ); 497 cpu.Map( 0xF000, 0xFFFF ).Set( this, &Nsf::Peek_Prg_F, &Nsf::Poke_Nop ); 498 } 499 500 if (chips) 501 { 502 if (chips->mmc5) 503 { 504 cpu.Map( 0x5000 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Mmc5_5000 ); 505 cpu.Map( 0x5002 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Mmc5_5002 ); 506 cpu.Map( 0x5003 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Mmc5_5003 ); 507 cpu.Map( 0x5004 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Mmc5_5004 ); 508 cpu.Map( 0x5006 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Mmc5_5006 ); 509 cpu.Map( 0x5007 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Mmc5_5007 ); 510 cpu.Map( 0x5010 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Mmc5_5010 ); 511 cpu.Map( 0x5011 ).Set( this, &Nsf::Peek_Nop, &Nsf::Poke_Mmc5_5011 ); 512 cpu.Map( 0x5015 ).Set( this, &Nsf::Peek_Mmc5_5015, &Nsf::Poke_Mmc5_5015 ); 513 cpu.Map( 0x5205 ).Set( this, &Nsf::Peek_Mmc5_5205, &Nsf::Poke_Mmc5_5205 ); 514 cpu.Map( 0x5206 ).Set( this, &Nsf::Peek_Mmc5_5206, &Nsf::Poke_Mmc5_5206 ); 515 cpu.Map( 0x5C00, 0x5FF5 ).Set( this, &Nsf::Peek_Mmc5_5C00, &Nsf::Poke_Mmc5_5C00 ); 516 } 517 518 if (chips->vrc6) 519 { 520 cpu.Map( 0x9000 ).Set( &Nsf::Poke_Vrc6_9000 ); 521 cpu.Map( 0x9001 ).Set( &Nsf::Poke_Vrc6_9001 ); 522 cpu.Map( 0x9002 ).Set( &Nsf::Poke_Vrc6_9002 ); 523 cpu.Map( 0xA000 ).Set( &Nsf::Poke_Vrc6_A000 ); 524 cpu.Map( 0xA001 ).Set( &Nsf::Poke_Vrc6_A001 ); 525 cpu.Map( 0xA002 ).Set( &Nsf::Poke_Vrc6_A002 ); 526 cpu.Map( 0xB000 ).Set( &Nsf::Poke_Vrc6_B000 ); 527 cpu.Map( 0xB001 ).Set( &Nsf::Poke_Vrc6_B001 ); 528 cpu.Map( 0xB002 ).Set( &Nsf::Poke_Vrc6_B002 ); 529 } 530 531 if (chips->vrc7) 532 { 533 cpu.Map( 0x9010 ).Set( &Nsf::Poke_Vrc7_9010 ); 534 cpu.Map( 0x9030 ).Set( &Nsf::Poke_Vrc7_9030 ); 535 } 536 537 if (chips->n163) 538 { 539 cpu.Map( 0x4800 ).Set( this, &Nsf::Peek_N163_48, &Nsf::Poke_N163_48 ); 540 cpu.Map( 0xF800 ).Set( &Nsf::Poke_N163_F8 ); 541 } 542 543 if (chips->s5b) 544 { 545 cpu.Map( 0xC000 ).Set( &Nsf::Poke_S5b_C ); 546 cpu.Map( 0xE000 ).Set( &Nsf::Poke_S5b_E ); 547 } 548 } 549 550 cpu.Map( 0xFFFA ).Set( &Nsf::Peek_FFFA ); 551 cpu.Map( 0xFFFB ).Set( &Nsf::Peek_FFFB ); 552 cpu.Map( 0xFFFC ).Set( &Nsf::Peek_FFFC ); 553 cpu.Map( 0xFFFD ).Set( &Nsf::Peek_FFFD ); 554 555 routine.reset = Routine::RESET; 556 routine.nmi = Routine::NMI; 557 558 cpu.SetFrameCycles( cpu.GetModel() == CPU_RP2A03 ? PPU_RP2C02_HVSYNC : cpu.GetModel() == CPU_RP2A07 ? PPU_RP2C07_HVSYNC : PPU_DENDY_HVSYNC ); 559 } 560 PowerOff()561 bool Nsf::PowerOff() 562 { 563 StopSong(); 564 return true; 565 } 566 SelectSong(const uint song)567 Result Nsf::SelectSong(const uint song) 568 { 569 if (song < songs.count) 570 { 571 if (songs.current != song) 572 { 573 songs.current = song; 574 575 if (routine.playing) 576 { 577 routine.nmi = Routine::NMI; 578 apu.ClearBuffers(); 579 } 580 581 Api::Nsf::eventCallback( Api::Nsf::EVENT_SELECT_SONG ); 582 583 return RESULT_OK; 584 } 585 586 return RESULT_NOP; 587 } 588 589 return RESULT_ERR_INVALID_PARAM; 590 } 591 PlaySong()592 Result Nsf::PlaySong() 593 { 594 if (!routine.playing) 595 { 596 routine.nmi = Routine::NMI; 597 routine.playing = true; 598 599 Api::Nsf::eventCallback( Api::Nsf::EVENT_PLAY_SONG ); 600 601 return RESULT_OK; 602 } 603 604 return RESULT_NOP; 605 } 606 StopSong()607 Result Nsf::StopSong() 608 { 609 if (routine.playing) 610 { 611 routine.playing = false; 612 routine.nmi = Routine::NMI; 613 apu.ClearBuffers(); 614 615 Api::Nsf::eventCallback( Api::Nsf::EVENT_STOP_SONG ); 616 617 return RESULT_OK; 618 } 619 620 return RESULT_NOP; 621 } 622 InitSong()623 void Nsf::InitSong() 624 { 625 std::memset( wrk, 0x00, SIZE_8K ); 626 627 if (chips && chips->mmc5) 628 chips->mmc5->ClearExRam(); 629 630 const bool fds = chips && chips->fds; 631 632 if (addressing.bankSwitched) 633 { 634 if (fds) 635 { 636 for (uint i=0; i < 2; ++i) 637 cpu.Poke( 0x5FF6+i, banks[6+i] ); 638 } 639 640 for (uint i=0; i < 8; ++i) 641 cpu.Poke( 0x5FF8+i, banks[i] ); 642 } 643 else if (fds) 644 { 645 for (dword i=0x6000, j=0; i < 0x10000; j += (i >= (addressing.load & 0xF000U)), i += 0x1000) 646 std::memcpy( chips->fds->ram + (i-0x6000), prg.Source().Mem(j * 0x1000), 0x1000 ); 647 } 648 649 if (fds) 650 { 651 cpu.Poke( 0x4089, 0x80 ); 652 cpu.Poke( 0x408A, 0xE8 ); 653 } 654 655 apu.ClearBuffers(); 656 std::memset( cpu.GetRam(), 0x00, Cpu::RAM_SIZE ); 657 658 for (uint i=0x4000; i <= 0x4013; ++i) 659 cpu.Poke( i, 0x00 ); 660 661 cpu.Poke( 0x4015, 0x0F ); 662 cpu.Poke( 0x4017, 0xC0 ); 663 } 664 665 #ifdef NST_MSVC_OPTIMIZE 666 #pragma optimize("", on) 667 #endif 668 BeginFrame()669 void Nsf::BeginFrame() 670 { 671 routine.jmp = (routine.playing ? 0xFA : 0xFD); 672 673 if (routine.nmi) 674 cpu.DoNMI(0); 675 } 676 Clock(Cycle rateCycles,Cycle rateClock,const Cycle targetCycles)677 Cycle Nsf::Chips::Clock(Cycle rateCycles,Cycle rateClock,const Cycle targetCycles) 678 { 679 if (clocks.next != Cpu::CYCLE_MAX) 680 { 681 NST_ASSERT( (mmc5 || fds) && (clocks.mmc5 != Cpu::CYCLE_MAX || clocks.fds != Cpu::CYCLE_MAX) ); 682 683 if (clocks.mmc5 == clocks.next) 684 clocks.mmc5 = mmc5->Clock( rateCycles, rateClock, targetCycles ) - rateCycles; 685 686 if (clocks.fds == clocks.next) 687 clocks.fds = fds->Clock( rateCycles, rateClock, targetCycles ) - rateCycles; 688 689 clocks.next = NST_MIN(clocks.mmc5,clocks.fds); 690 691 rateCycles += clocks.next; 692 693 return rateCycles; 694 } 695 else 696 { 697 NST_ASSERT( !mmc5 && !fds ); 698 699 return Channel::Clock( rateCycles, rateClock, targetCycles ); 700 } 701 } 702 GetSample()703 Nsf::Chips::Sample Nsf::Chips::GetSample() 704 { 705 return 706 ( 707 (mmc5 ? mmc5->GetSample() : 0) + 708 (vrc6 ? vrc6->GetSample() : 0) + 709 (vrc7 ? vrc7->GetSample() : 0) + 710 (fds ? fds->GetSample() : 0) + 711 (s5b ? s5b->GetSample() : 0) + 712 (n163 ? n163->GetSample() : 0) 713 ); 714 } 715 FetchLast(uint offset) const716 inline uint Nsf::FetchLast(uint offset) const 717 { 718 NST_ASSERT( offset <= 0xFFF ); 719 return offset[chips && chips->fds ? chips->fds->ram + (sizeof(array(chips->fds->ram))-SIZE_4K) : prg[7]]; 720 } 721 NES_PEEK(Nsf,FFFA)722 NES_PEEK(Nsf,FFFA) 723 { 724 return routine.nmi ? routine.nmi &= Routine::NMI_B, routine.playing ? 0xEC : 0xFD : FetchLast(0xFFA); 725 } 726 NES_PEEK(Nsf,FFFB)727 NES_PEEK(Nsf,FFFB) 728 { 729 return routine.nmi ? routine.nmi &= Routine::NMI_A, 0x38 : FetchLast(0xFFB); 730 } 731 NES_PEEK(Nsf,FFFC)732 NES_PEEK(Nsf,FFFC) 733 { 734 return routine.reset ? routine.reset &= Routine::RESET_B, 0xFD : FetchLast(0xFFC); 735 } 736 NES_PEEK(Nsf,FFFD)737 NES_PEEK(Nsf,FFFD) 738 { 739 return routine.reset ? routine.reset &= Routine::RESET_A, 0x38 : FetchLast(0xFFD); 740 } 741 742 NES_PEEK(Nsf,38EC) 743 { 744 NST_VERIFY( routine.playing ); 745 746 InitSong(); 747 return LDA; 748 } 749 750 NES_PEEK(Nsf,38ED) 751 { 752 NST_VERIFY( routine.playing ); 753 return songs.current; 754 } 755 756 NES_PEEK(Nsf,38EE) 757 { 758 NST_VERIFY( routine.playing ); 759 return LDX; 760 } 761 762 NES_PEEK(Nsf,38EF) 763 { 764 NST_VERIFY( routine.playing ); 765 return 0xFC; 766 } 767 768 NES_PEEK(Nsf,38F0) 769 { 770 NST_VERIFY( routine.playing ); 771 return TXS; 772 } 773 774 NES_PEEK(Nsf,38F1) 775 { 776 NST_VERIFY( routine.playing ); 777 return LDX; 778 } 779 780 NES_PEEK(Nsf,38F2) 781 { 782 NST_VERIFY( routine.playing ); 783 return cpu.GetModel() == CPU_RP2A07; 784 } 785 786 NES_PEEK(Nsf,38F3) 787 { 788 NST_VERIFY( routine.playing ); 789 return JSR; 790 } 791 792 NES_PEEK(Nsf,38F4) 793 { 794 NST_VERIFY( routine.playing ); 795 return addressing.init & 0xFFU; 796 } 797 798 NES_PEEK(Nsf,38F5) 799 { 800 NST_VERIFY( routine.playing ); 801 return addressing.init >> 8; 802 } 803 804 NES_PEEK(Nsf,38F6) 805 { 806 NST_VERIFY( routine.playing ); 807 return SEI; 808 } 809 810 NES_PEEK(Nsf,38F7) 811 { 812 NST_VERIFY( routine.playing ); 813 routine.jmp = 0xFD; 814 return JMP; 815 } 816 817 NES_PEEK(Nsf,38F8) 818 { 819 NST_VERIFY( routine.playing ); 820 return 0xFD; 821 } 822 823 NES_PEEK(Nsf,38F9) 824 { 825 NST_VERIFY( routine.playing ); 826 return 0x38; 827 } 828 829 NES_PEEK(Nsf,38FA) 830 { 831 NST_VERIFY( routine.playing ); 832 routine.jmp = 0xFD; 833 return JSR; 834 } 835 836 NES_PEEK(Nsf,38FB) 837 { 838 NST_VERIFY( routine.playing ); 839 return addressing.play & 0xFFU; 840 } 841 842 NES_PEEK(Nsf,38FC) 843 { 844 NST_VERIFY( routine.playing ); 845 return addressing.play >> 8; 846 } 847 848 NES_PEEK(Nsf,38FD) 849 { 850 return JMP; 851 } 852 853 NES_PEEK(Nsf,38FE) 854 { 855 return routine.jmp; 856 } 857 858 NES_PEEK(Nsf,38FF) 859 { 860 return 0x38; 861 } 862 863 NES_POKE_D(Nsf,4017) 864 { 865 apu.WriteFrameCtrl( data ); 866 } 867 NES_PEEK_A(Nsf,Nop)868 NES_PEEK_A (Nsf,Nop) { return address >> 8; } NES_POKE(Nsf,Nop)869 NES_POKE (Nsf,Nop) {} 870 NES_PEEK_A(Nsf,Prg_8)871 NES_PEEK_A (Nsf,Prg_8) { return prg[0][address - 0x8000]; } NES_PEEK_A(Nsf,Prg_9)872 NES_PEEK_A (Nsf,Prg_9) { return prg[1][address - 0x9000]; } NES_PEEK_A(Nsf,Prg_A)873 NES_PEEK_A (Nsf,Prg_A) { return prg[2][address - 0xA000]; } NES_PEEK_A(Nsf,Prg_B)874 NES_PEEK_A (Nsf,Prg_B) { return prg[3][address - 0xB000]; } NES_PEEK_A(Nsf,Prg_C)875 NES_PEEK_A (Nsf,Prg_C) { return prg[4][address - 0xC000]; } NES_PEEK_A(Nsf,Prg_D)876 NES_PEEK_A (Nsf,Prg_D) { return prg[5][address - 0xD000]; } NES_PEEK_A(Nsf,Prg_E)877 NES_PEEK_A (Nsf,Prg_E) { return prg[6][address - 0xE000]; } NES_PEEK_A(Nsf,Prg_F)878 NES_PEEK_A (Nsf,Prg_F) { return prg[7][address - 0xF000]; } 879 NES_PEEK_A(Nsf,Wrk)880 NES_PEEK_A (Nsf,Wrk) { return wrk[address - 0x6000]; } NES_POKE_AD(Nsf,Wrk)881 NES_POKE_AD (Nsf,Wrk) { wrk[address - 0x6000] = data; } 882 883 NES_POKE_D (Nsf,5FF8) { prg.SwapBank<SIZE_4K,0x0000>( data ); } 884 NES_POKE_D (Nsf,5FF9) { prg.SwapBank<SIZE_4K,0x1000>( data ); } 885 NES_POKE_D (Nsf,5FFA) { prg.SwapBank<SIZE_4K,0x2000>( data ); } 886 NES_POKE_D (Nsf,5FFB) { prg.SwapBank<SIZE_4K,0x3000>( data ); } 887 NES_POKE_D (Nsf,5FFC) { prg.SwapBank<SIZE_4K,0x4000>( data ); } 888 NES_POKE_D (Nsf,5FFD) { prg.SwapBank<SIZE_4K,0x5000>( data ); } 889 NES_POKE_D (Nsf,5FFE) { prg.SwapBank<SIZE_4K,0x6000>( data ); } 890 NES_POKE_D (Nsf,5FFF) { prg.SwapBank<SIZE_4K,0x7000>( data ); } 891 NES_PEEK_A(Nsf,Fds_4040)892 NES_PEEK_A (Nsf,Fds_4040) { return chips->fds->ReadWaveData( address ); } NES_POKE_AD(Nsf,Fds_4040)893 NES_POKE_AD (Nsf,Fds_4040) { chips->fds->WriteWaveData( address, data ); } NES_POKE_D(Nsf,Fds_4080)894 NES_POKE_D (Nsf,Fds_4080) { chips->fds->WriteReg0( data ); } NES_POKE_D(Nsf,Fds_4082)895 NES_POKE_D (Nsf,Fds_4082) { chips->fds->WriteReg1( data ); } NES_POKE_D(Nsf,Fds_4083)896 NES_POKE_D (Nsf,Fds_4083) { chips->fds->WriteReg2( data ); } NES_POKE_D(Nsf,Fds_4084)897 NES_POKE_D (Nsf,Fds_4084) { chips->fds->WriteReg3( data ); } NES_POKE_D(Nsf,Fds_4085)898 NES_POKE_D (Nsf,Fds_4085) { chips->fds->WriteReg4( data ); } NES_POKE_D(Nsf,Fds_4086)899 NES_POKE_D (Nsf,Fds_4086) { chips->fds->WriteReg5( data ); } NES_POKE_D(Nsf,Fds_4087)900 NES_POKE_D (Nsf,Fds_4087) { chips->fds->WriteReg6( data ); } NES_POKE_D(Nsf,Fds_4088)901 NES_POKE_D (Nsf,Fds_4088) { chips->fds->WriteReg7( data ); } NES_POKE_D(Nsf,Fds_4089)902 NES_POKE_D (Nsf,Fds_4089) { chips->fds->WriteReg8( data ); } NES_POKE_D(Nsf,Fds_408A)903 NES_POKE_D (Nsf,Fds_408A) { chips->fds->WriteReg9( data ); } NES_PEEK(Nsf,Fds_4090)904 NES_PEEK (Nsf,Fds_4090) { return chips->fds->ReadVolumeGain(); } NES_PEEK(Nsf,Fds_4092)905 NES_PEEK (Nsf,Fds_4092) { return chips->fds->ReadSweepGain(); } NES_POKE_D(Nsf,Fds_5FF6)906 NES_POKE_D (Nsf,Fds_5FF6) { chips->fds->SwapBank( prg, 0, data ); } NES_POKE_D(Nsf,Fds_5FF7)907 NES_POKE_D (Nsf,Fds_5FF7) { chips->fds->SwapBank( prg, 1, data ); } NES_POKE_D(Nsf,Fds_5FF8)908 NES_POKE_D (Nsf,Fds_5FF8) { chips->fds->SwapBank( prg, 2, data ); } NES_POKE_D(Nsf,Fds_5FF9)909 NES_POKE_D (Nsf,Fds_5FF9) { chips->fds->SwapBank( prg, 3, data ); } NES_POKE_D(Nsf,Fds_5FFA)910 NES_POKE_D (Nsf,Fds_5FFA) { chips->fds->SwapBank( prg, 4, data ); } NES_POKE_D(Nsf,Fds_5FFB)911 NES_POKE_D (Nsf,Fds_5FFB) { chips->fds->SwapBank( prg, 5, data ); } NES_POKE_D(Nsf,Fds_5FFC)912 NES_POKE_D (Nsf,Fds_5FFC) { chips->fds->SwapBank( prg, 6, data ); } NES_POKE_D(Nsf,Fds_5FFD)913 NES_POKE_D (Nsf,Fds_5FFD) { chips->fds->SwapBank( prg, 7, data ); } NES_POKE_D(Nsf,Fds_5FFE)914 NES_POKE_D (Nsf,Fds_5FFE) { chips->fds->SwapBank( prg, 8, data ); } NES_POKE_D(Nsf,Fds_5FFF)915 NES_POKE_D (Nsf,Fds_5FFF) { chips->fds->SwapBank( prg, 9, data ); } NES_PEEK_A(Nsf,Fds_Ram)916 NES_PEEK_A (Nsf,Fds_Ram) { return chips->fds->ram[address - 0x6000]; } NES_POKE_AD(Nsf,Fds_Ram)917 NES_POKE_AD (Nsf,Fds_Ram) { chips->fds->ram[address - 0x6000] = data; } 918 NES_POKE_D(Nsf,Mmc5_5000)919 NES_POKE_D (Nsf,Mmc5_5000) { chips->mmc5->WriteSquareReg0( 0, data ); } NES_POKE_D(Nsf,Mmc5_5002)920 NES_POKE_D (Nsf,Mmc5_5002) { chips->mmc5->WriteSquareReg1( 0, data ); } NES_POKE_D(Nsf,Mmc5_5003)921 NES_POKE_D (Nsf,Mmc5_5003) { chips->mmc5->WriteSquareReg2( 0, data ); } NES_POKE_D(Nsf,Mmc5_5004)922 NES_POKE_D (Nsf,Mmc5_5004) { chips->mmc5->WriteSquareReg0( 1, data ); } NES_POKE_D(Nsf,Mmc5_5006)923 NES_POKE_D (Nsf,Mmc5_5006) { chips->mmc5->WriteSquareReg1( 1, data ); } NES_POKE_D(Nsf,Mmc5_5007)924 NES_POKE_D (Nsf,Mmc5_5007) { chips->mmc5->WriteSquareReg2( 1, data ); } NES_POKE_D(Nsf,Mmc5_5010)925 NES_POKE_D (Nsf,Mmc5_5010) { chips->mmc5->WritePcmReg0( data ); } NES_POKE_D(Nsf,Mmc5_5011)926 NES_POKE_D (Nsf,Mmc5_5011) { chips->mmc5->WritePcmReg1( data ); } NES_POKE_D(Nsf,Mmc5_5015)927 NES_POKE_D (Nsf,Mmc5_5015) { chips->mmc5->WriteCtrl( data ); } NES_PEEK(Nsf,Mmc5_5015)928 NES_PEEK (Nsf,Mmc5_5015) { return chips->mmc5->ReadCtrl(); } NES_PEEK(Nsf,Mmc5_5205)929 NES_PEEK (Nsf,Mmc5_5205) { return (chips->mmc5->mul[0] * chips->mmc5->mul[1]) >> 0 & 0xFF; } NES_PEEK(Nsf,Mmc5_5206)930 NES_PEEK (Nsf,Mmc5_5206) { return (chips->mmc5->mul[0] * chips->mmc5->mul[1]) >> 8 & 0xFF; } NES_POKE_D(Nsf,Mmc5_5205)931 NES_POKE_D (Nsf,Mmc5_5205) { chips->mmc5->mul[0] = data; } NES_POKE_D(Nsf,Mmc5_5206)932 NES_POKE_D (Nsf,Mmc5_5206) { chips->mmc5->mul[1] = data; } NES_PEEK_A(Nsf,Mmc5_5C00)933 NES_PEEK_A (Nsf,Mmc5_5C00) { return chips->mmc5->exRam[address - 0x5C00]; } NES_POKE_AD(Nsf,Mmc5_5C00)934 NES_POKE_AD (Nsf,Mmc5_5C00) { chips->mmc5->exRam[address - 0x5C00] = data; } 935 NES_POKE_D(Nsf,Vrc6_9000)936 NES_POKE_D (Nsf,Vrc6_9000) { chips->vrc6->WriteSquareReg0( 0, data ); } NES_POKE_D(Nsf,Vrc6_9001)937 NES_POKE_D (Nsf,Vrc6_9001) { chips->vrc6->WriteSquareReg1( 0, data ); } NES_POKE_D(Nsf,Vrc6_9002)938 NES_POKE_D (Nsf,Vrc6_9002) { chips->vrc6->WriteSquareReg2( 0, data ); } NES_POKE_D(Nsf,Vrc6_A000)939 NES_POKE_D (Nsf,Vrc6_A000) { chips->vrc6->WriteSquareReg0( 1, data ); } NES_POKE_D(Nsf,Vrc6_A001)940 NES_POKE_D (Nsf,Vrc6_A001) { chips->vrc6->WriteSquareReg1( 1, data ); } NES_POKE_D(Nsf,Vrc6_A002)941 NES_POKE_D (Nsf,Vrc6_A002) { chips->vrc6->WriteSquareReg2( 1, data ); } NES_POKE_D(Nsf,Vrc6_B000)942 NES_POKE_D (Nsf,Vrc6_B000) { chips->vrc6->WriteSawReg0( data ); } NES_POKE_D(Nsf,Vrc6_B001)943 NES_POKE_D (Nsf,Vrc6_B001) { chips->vrc6->WriteSawReg1( data ); } NES_POKE_D(Nsf,Vrc6_B002)944 NES_POKE_D (Nsf,Vrc6_B002) { chips->vrc6->WriteSawReg2( data ); } 945 NES_POKE_D(Nsf,Vrc7_9010)946 NES_POKE_D (Nsf,Vrc7_9010) { chips->vrc7->SelectReg( data ); } NES_POKE_D(Nsf,Vrc7_9030)947 NES_POKE_D (Nsf,Vrc7_9030) { chips->vrc7->WriteReg( data ); } 948 NES_POKE_D(Nsf,S5b_C)949 NES_POKE_D (Nsf,S5b_C) { chips->s5b->SelectReg( data ); } NES_POKE_D(Nsf,S5b_E)950 NES_POKE_D (Nsf,S5b_E) { chips->s5b->WriteReg( data ); } 951 NES_PEEK(Nsf,N163_48)952 NES_PEEK (Nsf,N163_48) { return chips->n163->ReadData(); } NES_POKE_D(Nsf,N163_48)953 NES_POKE_D (Nsf,N163_48) { chips->n163->WriteData( data ); } NES_POKE_D(Nsf,N163_F8)954 NES_POKE_D (Nsf,N163_F8) { chips->n163->WriteAddress( data ); } 955 } 956 } 957