diff options
Diffstat (limited to 'plugins/sid/sidplay-libs/libsidplay/src/player.cpp')
-rw-r--r-- | plugins/sid/sidplay-libs/libsidplay/src/player.cpp | 945 |
1 files changed, 945 insertions, 0 deletions
diff --git a/plugins/sid/sidplay-libs/libsidplay/src/player.cpp b/plugins/sid/sidplay-libs/libsidplay/src/player.cpp new file mode 100644 index 00000000..38b612c0 --- /dev/null +++ b/plugins/sid/sidplay-libs/libsidplay/src/player.cpp @@ -0,0 +1,945 @@ +/*************************************************************************** + player.cpp - Main Library Code + ------------------- + begin : Fri Jun 9 2000 + copyright : (C) 2000 by Simon White + email : s_a_white@email.com + ***************************************************************************/ +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +/*************************************************************************** + * $Log: player.cpp,v $ + * Revision 1.57 2002/12/14 10:10:30 s_a_white + * Kernal Mod: Bypass screen clear as we don't have a screen. Fix setting + * of PAL/NTSC flag for real c64 mode. + * + * Revision 1.56 2002/12/13 22:01:54 s_a_white + * Kernel mods: Memory now bypassed by upping the start address so the + * end or ram is found instantly. Basic cold/warm start address points to a + * busy loop to prevent undersiable side effects (this may change later). + * + * Revision 1.55 2002/11/27 00:16:51 s_a_white + * Make sure driver info gets reset and exported properly. + * + * Revision 1.54 2002/11/25 21:09:41 s_a_white + * Reset address for old sidplay1 modes now directly passed to the CPU. This + * prevents tune corruption and banking issues for the different modes. + * + * Revision 1.53 2002/11/21 19:53:58 s_a_white + * CPU nolonger a special case. It now uses the event scheduler like all the + * other components. + * + * Revision 1.52 2002/11/20 21:44:03 s_a_white + * Fix fake IRQ to properly obtain next address. + * + * Revision 1.51 2002/11/19 22:55:18 s_a_white + * Sidplay1 modes modified to make them nolonger require the psid driver. + * Full c64 kernal supported in real c64 mode. + * + * Revision 1.50 2002/11/01 17:36:01 s_a_white + * Frame based support for old sidplay1 modes. + * + * Revision 1.49 2002/10/20 08:58:36 s_a_white + * Modify IO map so psiddrv can detect special cases. + * + * Revision 1.48 2002/10/15 18:20:54 s_a_white + * Make all addresses from ea31 to ea7d valid IRQ exit points. This + * approximates the functionality of a real C64. + * + * Revision 1.47 2002/10/02 19:43:47 s_a_white + * RSID support. + * + * Revision 1.46 2002/09/17 17:02:41 s_a_white + * Fixed location of kernel IRQ exit code. + * + * Revision 1.45 2002/09/12 21:01:30 s_a_white + * Added support for simulating the random delay before the user loads a + * program on a real C64. + * + * Revision 1.44 2002/09/09 18:01:30 s_a_white + * Prevent m_info driver details getting modified when C64 crashes. + * + * Revision 1.43 2002/08/20 23:21:41 s_a_white + * Setup default sample format. + * + * Revision 1.42 2002/04/14 21:46:50 s_a_white + * PlaySID reads fixed to come from RAM only. + * + * Revision 1.41 2002/03/12 18:43:59 s_a_white + * Tidy up handling of envReset on illegal CPU instructions. + * + * Revision 1.40 2002/03/11 18:01:30 s_a_white + * Prevent lockup if config call fails with existing and old configurations. + * + * Revision 1.39 2002/03/03 22:01:58 s_a_white + * New clock speed & sid model interface. + * + * Revision 1.38 2002/02/17 16:33:02 s_a_white + * New reset interface for sidbuilders. + * + * Revision 1.37 2002/02/17 12:42:45 s_a_white + * envReset now sets playerStopped indicators. This means the player + * nolonger locks up when a HLT instruction is encountered. + * + * Revision 1.36 2002/02/06 20:12:03 s_a_white + * Added sidplay1 random extension for vic reads. + * + * Revision 1.35 2002/01/29 21:50:33 s_a_white + * Auto switching to a better emulation mode. m_tuneInfo reloaded after a + * config. Initial code added to support more than two sids. + * + * Revision 1.34 2002/01/14 23:16:27 s_a_white + * Prevent multiple initialisations if already stopped. + * + * Revision 1.33 2001/12/13 08:28:08 s_a_white + * Added namespace support to fix problems with xsidplay. + * + * Revision 1.32 2001/11/16 19:25:33 s_a_white + * Removed m_context as where getting mixed with parent class. + * + * Revision 1.31 2001/10/18 22:33:40 s_a_white + * Initialisation order fixes. + * + * Revision 1.30 2001/10/02 18:26:36 s_a_white + * Removed ReSID support and updated for new scheduler. + * + * Revision 1.29 2001/09/17 19:02:38 s_a_white + * Now uses fixed point maths for sample output and rtc. + * + * Revision 1.28 2001/09/04 18:50:57 s_a_white + * Fake CIA address now masked. + * + * Revision 1.27 2001/09/01 11:15:46 s_a_white + * Fixes sidplay1 environment modes. + * + * Revision 1.26 2001/08/10 20:04:46 s_a_white + * Initialise requires rtc reset for correct use with stop operation. + * + * Revision 1.25 2001/07/27 12:51:55 s_a_white + * Removed warning. + * + * Revision 1.24 2001/07/25 17:01:13 s_a_white + * Support for new configuration interface. + * + * Revision 1.23 2001/07/14 16:46:16 s_a_white + * Sync with sidbuilder class project. + * + * Revision 1.22 2001/07/14 12:56:15 s_a_white + * SID caching no longer needed. IC components now run using event + * generation (based on VICE). Handling of IRQs now more effecient. All + * sidplay1 hacks either removed or moved to sid6510. Fixed PAL/NTSC + * speeding fixing. Now uses new component and sidbuilder classes. + * + * Revision 1.21 2001/04/23 17:09:56 s_a_white + * Fixed video speed selection using unforced/forced and NTSC clockSpeeds. + * + * Revision 1.20 2001/03/26 21:46:43 s_a_white + * Removed unused #include. + * + * Revision 1.19 2001/03/25 19:48:13 s_a_white + * xsid.reset added. + * + * Revision 1.18 2001/03/22 22:45:20 s_a_white + * Re-ordered initialisations to match defintions. + * + * Revision 1.17 2001/03/21 22:32:34 s_a_white + * Filter redefinition support. VIC & NMI support added. Moved fake interrupts + * to sid6510 class. + * + * Revision 1.16 2001/03/09 22:26:36 s_a_white + * Support for updated C64 player. + * + * Revision 1.15 2001/03/08 22:46:42 s_a_white + * playAddr = 0xffff now better supported. + * + * Revision 1.14 2001/03/01 23:46:37 s_a_white + * Support for sample mode to be selected at runtime. + * + * Revision 1.13 2001/02/28 18:55:27 s_a_white + * Removed initBank* related stuff. IRQ terminating ROM jumps at 0xea31, + * 0xea7e and 0xea81 now handled. + * + * Revision 1.12 2001/02/21 21:43:10 s_a_white + * Now use VSID code and this handles interrupts much better! The whole + * initialise sequence has been modified to support this. + * + * Revision 1.11 2001/02/13 21:01:14 s_a_white + * Support for real interrupts. C64 Initialisation routine now run from Player::play + * instead of Player::initialise. Prevents lockups if init routine does not return. + * + * Revision 1.10 2001/02/08 17:21:14 s_a_white + * Initial SID volumes not being stored in cache. Fixes Dulcedo Cogitationis. + * + * Revision 1.9 2001/02/07 20:56:46 s_a_white + * Samples now delayed until end of simulated frame. + * + * Revision 1.8 2001/01/23 21:26:28 s_a_white + * Only way to load a tune now is by passing in a sidtune object. This is + * required for songlength database support. + * + * Revision 1.7 2001/01/07 15:13:39 s_a_white + * Hardsid update to mute sids when program exits. + * + * Revision 1.6 2000/12/21 22:48:27 s_a_white + * Re-order voices for mono to stereo conversion to match sidplay1. + * + * Revision 1.5 2000/12/14 23:53:36 s_a_white + * Small optimisation update, and comment revision. + * + * Revision 1.4 2000/12/13 17:56:24 s_a_white + * Interrupt vector address changed from 0x315 to 0x314. + * + * Revision 1.3 2000/12/13 12:00:25 mschwendt + * Corrected order of members in member initializer-list. + * + * Revision 1.2 2000/12/12 22:50:15 s_a_white + * Bug Fix #122033. + * + ***************************************************************************/ + +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include "config.h" +#include "sidendian.h" +#include "player.h" + +#ifdef HAVE_EXCEPTIONS +# include <new> +#endif + +static const uint8_t kernal[] = { +#include "kernal.bin" +}; + +SIDPLAY2_NAMESPACE_START + +const double Player::CLOCK_FREQ_NTSC = 1022727.14; +const double Player::CLOCK_FREQ_PAL = 985248.4; +const double Player::VIC_FREQ_PAL = 50.0; +const double Player::VIC_FREQ_NTSC = 60.0; + +// These texts are used to override the sidtune settings. +const char *Player::TXT_PAL_VBI = "50 Hz VBI (PAL)"; +const char *Player::TXT_PAL_VBI_FIXED = "60 Hz VBI (PAL FIXED)"; +const char *Player::TXT_PAL_CIA = "CIA (PAL)"; +const char *Player::TXT_PAL_UNKNOWN = "UNKNOWN (PAL)"; +const char *Player::TXT_NTSC_VBI = "60 Hz VBI (NTSC)"; +const char *Player::TXT_NTSC_VBI_FIXED = "50 Hz VBI (NTSC FIXED)"; +const char *Player::TXT_NTSC_CIA = "CIA (NTSC)"; +const char *Player::TXT_NTSC_UNKNOWN = "UNKNOWN (NTSC)"; +const char *Player::TXT_NA = "NA"; + +// Error Strings +const char *Player::ERR_CONF_WHILST_ACTIVE = "SIDPLAYER ERROR: Trying to configure player whilst active."; +const char *Player::ERR_UNSUPPORTED_FREQ = "SIDPLAYER ERROR: Unsupported sampling frequency."; +const char *Player::ERR_UNSUPPORTED_PRECISION = "SIDPLAYER ERROR: Unsupported sample precision."; +const char *Player::ERR_MEM_ALLOC = "SIDPLAYER ERROR: Memory Allocation Failure."; +const char *Player::ERR_UNSUPPORTED_MODE = "SIDPLAYER ERROR: Unsupported Environment Mode (Coming Soon)."; + +const char *Player::credit[]; + + +// Set the ICs environment variable to point to +// this player +Player::Player (void) +// Set default settings for system +:c64env (&m_scheduler), + m_scheduler ("SIDPlay 2"), + sid6510 (&m_scheduler), + mos6510 (&m_scheduler), + cpu (&sid6510), + xsid (this, &nullsid), + cia (this), + cia2 (this), + sid6526 (this), + vic (this), + mixerEvent (this), + rtc (&m_scheduler), + m_tune (NULL), + m_ram (NULL), + m_rom (NULL), + m_errorString (TXT_NA), + m_fastForwardFactor (1.0), + m_mileage (0), + m_playerState (sid2_stopped), + m_running (false), + m_sampleCount (0) +{ + srand ((uint) ::time(NULL)); + m_rand = (uint_least32_t) rand (); + + // Set the ICs to use this environment + sid6510.setEnvironment (this); + mos6510.setEnvironment (this); + + // SID Initialise + for (int i = 0; i < SID2_MAX_SIDS; i++) + sid[i] = &nullsid; + xsid.emulation(sid[0]); + sid[0] = &xsid; + + // Setup exported info + m_info.credits = credit; + m_info.channels = 1; + m_info.driverAddr = 0; + m_info.driverLength = 0; + m_info.name = PACKAGE; + m_info.tuneInfo = NULL; + m_info.version = VERSION; + m_info.eventContext = &context(); + // Number of SIDs support by this library + m_info.maxsids = SID2_MAX_SIDS; + m_info.environment = sid2_envR; + + // Configure default settings + m_cfg.clockDefault = SID2_CLOCK_CORRECT; + m_cfg.clockForced = false; + m_cfg.clockSpeed = SID2_CLOCK_CORRECT; + m_cfg.environment = m_info.environment; + m_cfg.forceDualSids = false; + m_cfg.frequency = SID2_DEFAULT_SAMPLING_FREQ; + m_cfg.optimisation = SID2_DEFAULT_OPTIMISATION; + m_cfg.playback = sid2_mono; + m_cfg.precision = SID2_DEFAULT_PRECISION; + m_cfg.sidDefault = SID2_MODEL_CORRECT; + m_cfg.sidEmulation = NULL; + m_cfg.sidModel = SID2_MODEL_CORRECT; + m_cfg.sidSamples = true; + m_cfg.leftVolume = 255; + m_cfg.rightVolume = 255; + m_cfg.sampleFormat = SID2_LITTLE_SIGNED; + + // Configured by default for Sound Blaster (compatibles) + if (SID2_DEFAULT_PRECISION == 8) + m_cfg.sampleFormat = SID2_LITTLE_UNSIGNED; + config (m_cfg); + + // Get component credits + credit[0] = PACKAGE " V" VERSION " Engine:\0\tCopyright (C) 2000 Simon White <sidplay2@email.com>\0"; + credit[1] = xsid.credits (); + credit[2] = "*MOS6510 (CPU) Emulation:\0\tCopyright (C) 2000 Simon White <sidplay2@email.com>\0"; + credit[3] = cia.credits (); + credit[4] = vic.credits (); + credit[5] = NULL; +} + +// Makes the next sequence of notes available. For sidplay compatibility +// this function should be called from interrupt event +void Player::fakeIRQ (void) +{ // Check to see if the play address has been provided or whether + // we should pick it up from an IRQ vector + uint_least16_t playAddr = m_tuneInfo.playAddr; + + // We have to reload the new play address + if (playAddr) + evalBankSelect (m_playBank); + else + { + if (isKernal) + { // Setup the entry point from hardware IRQ + playAddr = endian_little16 (&m_ram[0x0314]); + } + else + { // Setup the entry point from software IRQ + playAddr = endian_little16 (&m_ram[0xFFFF]); + } + } + + // Setup the entry point and restart the cpu + cpu->triggerIRQ (); + sid6510.reset (playAddr, 0, 0, 0); +} + +int Player::fastForward (uint percent) +{ + if (percent > 3200) + { + m_errorString = "SIDPLAYER ERROR: Percentage value out of range"; + return -1; + } + { + float64_t fastForwardFactor; + fastForwardFactor = (float64_t) percent / 100.0; + // Conversion to fixed point 8.24 + m_samplePeriod = (event_clock_t) ((float64_t) m_samplePeriod / + m_fastForwardFactor * fastForwardFactor); + m_fastForwardFactor = fastForwardFactor; + } + return 0; +} + +int Player::initialise () +{ // Fix the mileage counter if just finished another song. + mileageCorrect (); + m_mileage += time (); + + reset (); + if (psidDrvInstall (m_tuneInfo, m_info) < 0) + return -1; + + // The Basic ROM sets these values on loading a file. + { // Program start address + uint_least16_t addr = m_tuneInfo.loadAddr; + endian_little16 (&m_ram[0x2b], addr); + // Program end address + 1 + addr += m_tuneInfo.c64dataLen; + endian_little16 (&m_ram[0x2d], addr); + } + + if (!m_tune->placeSidTuneInC64mem (m_ram)) + { // Rev 1.6 (saw) - Allow loop through errors + m_errorString = m_tuneInfo.statusString; + return -1; + } + + rtc.reset (); + envReset (false); + return 0; +} + +int Player::load (SidTune *tune) +{ + m_tune = tune; + if (!tune) + { // Unload tune + m_info.tuneInfo = NULL; + return 0; + } + m_info.tuneInfo = &m_tuneInfo; + + // Un-mute all voices + xsid.mute (false); + + for (int i = 0; i < SID2_MAX_SIDS; i++) + { + uint_least8_t v = 3; + while (v--) + sid[i]->voice (v, 0, false); + } + + { // Must re-configure on fly for stereo support! + int ret = config (m_cfg); + // Failed configuration with new tune, reject it + if (ret < 0) + { + m_tune = NULL; + return -1; + } + } + return 0; +} + +void Player::mileageCorrect (void) +{ // If just finished a song, round samples to correct mileage + if (m_sampleCount >= (m_cfg.frequency / 2)) + m_mileage++; + m_sampleCount = 0; +} + +void Player::pause (void) +{ + if (m_running) + { + m_playerState = sid2_paused; + m_running = false; + } +} + +uint_least32_t Player::play (void *buffer, uint_least32_t length) +{ + // Make sure a _tune is loaded + if (!m_tune) + return 0; + + // Setup Sample Information + m_sampleIndex = 0; + m_sampleCount = length; + m_sampleBuffer = (char *) buffer; + + // Start the player loop + m_playerState = sid2_playing; + m_running = true; + + while (m_running) + m_scheduler.clock (); + + if (m_playerState == sid2_stopped) + initialise (); + return m_sampleIndex; +} + +void Player::stop (void) +{ // Re-start song + if (m_tune && (m_playerState != sid2_stopped)) + { + if (!m_running) + initialise (); + else + { + m_playerState = sid2_stopped; + m_running = false; + } + } +} + + +//------------------------------------------------------------------------- +// Temporary hack till real bank switching code added + +// Input: A 16-bit effective address +// Output: A default bank-select value for $01. +uint8_t Player::iomap (uint_least16_t addr) +{ + if (m_info.environment != sid2_envPS) + { // Force Real C64 Compatibility + if (m_tuneInfo.compatibility == SIDTUNE_COMPATIBILITY_R64) + return 0; // Special case, converted to 0x37 later + + if (addr == 0) + return 0; // Special case, converted to 0x37 later + if (addr < 0xa000) + return 0x37; // Basic-ROM, Kernal-ROM, I/O + if (addr < 0xd000) + return 0x36; // Kernal-ROM, I/O + if (addr >= 0xe000) + return 0x35; // I/O only + } + return 0x34; // RAM only (special I/O in PlaySID mode) +} + +void Player::evalBankSelect (uint8_t data) +{ // Determine new memory configuration. + isBasic = ((data & 3) == 3); + isIO = ((data & 7) > 4); + isKernal = ((data & 2) != 0); + m_bankReg = data; +} + +uint8_t Player::readMemByte_player (uint_least16_t addr) +{ + if (m_info.environment == sid2_envR) + return readMemByte_sidplaybs (addr); + return readMemByte_plain (addr); +} + +uint8_t Player::readMemByte_plain (uint_least16_t addr) +{ // Bank Select Register Value DOES NOT get to ram + if (addr == 0x0001) + return m_bankReg; + return m_ram[addr]; +} + +uint8_t Player::readMemByte_io (uint_least16_t addr) +{ + uint_least16_t tempAddr = (addr & 0xfc1f); + + // Not SID ? + if (( tempAddr & 0xff00 ) != 0xd400 ) + { + if (m_info.environment == sid2_envR) + { + switch (endian_16hi8 (addr)) + { + case 0: + return readMemByte_plain (addr); + case 0xdc: + return cia.read (addr&0x0f); + case 0xdd: + return cia2.read (addr&0x0f); + case 0xd0: + return vic.read (addr&0x3f); + default: + return m_rom[addr]; + } + } + else + { + switch (endian_16hi8 (addr)) + { + case 0: + return readMemByte_plain (addr); + // Sidplay1 Random Extension CIA + case 0xdc: + return sid6526.read (addr&0x0f); + // Sidplay1 Random Extension VIC + case 0xd0: + switch (addr & 0x3f) + { + case 0x11: + case 0x12: + return sid6526.read ((addr-13)&0x0f); + } + // Deliberate run on + default: + return m_rom[addr]; + } + } + } + + // Read real sid for these + if ((addr & 0xff00) == m_sidAddress[1]) + return sid[1]->read ((uint8_t) addr); + return sid[0]->read ((uint8_t) tempAddr); +} + +uint8_t Player::readMemByte_sidplaytp(uint_least16_t addr) +{ + if (addr < 0xD000) + return readMemByte_plain (addr); + else + { + // Get high-nibble of address. + switch (addr >> 12) + { + case 0xd: + if (isIO) + return readMemByte_io (addr); + else + return m_ram[addr]; + break; + case 0xe: + case 0xf: + default: // <-- just to please the compiler + return m_ram[addr]; + } + } +} + +uint8_t Player::readMemByte_sidplaybs (uint_least16_t addr) +{ + if (addr < 0xA000) + return readMemByte_plain (addr); + else + { + // Get high-nibble of address. + switch (addr >> 12) + { + case 0xa: + case 0xb: + if (isBasic) + return m_rom[addr]; + else + return m_ram[addr]; + break; + case 0xc: + return m_ram[addr]; + break; + case 0xd: + if (isIO) + return readMemByte_io (addr); + else + return m_ram[addr]; + break; + case 0xe: + case 0xf: + default: // <-- just to please the compiler + if (isKernal) + return m_rom[addr]; + else + return m_ram[addr]; + } + } +} + +void Player::writeMemByte_plain (uint_least16_t addr, uint8_t data) +{ + if (addr == 0x0001) + { // Determine new memory configuration. + evalBankSelect (data); + return; + } + m_ram[addr] = data; +} + +void Player::writeMemByte_playsid (uint_least16_t addr, uint8_t data) +{ + uint_least16_t tempAddr = (addr & 0xfc1f); + + // Not SID ? + if (( tempAddr & 0xff00 ) != 0xd400 ) + { + if (m_info.environment == sid2_envR) + { + switch (endian_16hi8 (addr)) + { + case 0: + writeMemByte_plain (addr, data); + return; + case 0xdc: + cia.write (addr&0x0f, data); + return; + case 0xdd: + cia2.write (addr&0x0f, data); + return; + case 0xd0: + vic.write (addr&0x3f, data); + return; + default: + m_rom[addr] = data; + return; + } + } + else + { + switch (endian_16hi8 (addr)) + { + case 0: + writeMemByte_plain (addr, data); + return; + case 0xdc: // Sidplay1 CIA + sid6526.write (addr&0x0f, data); + return; + default: + m_rom[addr] = data; + return; + } + } + } + + // $D41D/1E/1F, $D43D/3E/3F, ... + // Map to real address to support PlaySID + // Extended SID Chip Registers. + if (( tempAddr & 0x00ff ) >= 0x001d ) + xsid.write16 (addr & 0x01ff, data); + else // Mirrored SID. + { // SID. + // Convert address to that acceptable by resid + // Support dual sid + if ((addr & 0xff00) == m_sidAddress[1]) + { + sid[1]->write (addr & 0xff, data); + // Prevent sid write accessing other sid + // if not doing mono to stereo conversion. + if (m_sidAddress[1] != m_sidAddress[0]) + return; + } + sid[0]->write (tempAddr & 0xff, data); + } +} + +void Player::writeMemByte_sidplay (uint_least16_t addr, uint8_t data) +{ + if (addr < 0xA000) + writeMemByte_plain (addr, data); + else + { + // Get high-nibble of address. + switch (addr >> 12) + { + case 0xa: + case 0xb: + case 0xc: + m_ram[addr] = data; + break; + case 0xd: + if (isIO) + writeMemByte_playsid (addr, data); + else + m_ram[addr] = data; + break; + case 0xe: + case 0xf: + default: // <-- just to please the compiler + m_ram[addr] = data; + } + } +} + +// -------------------------------------------------- +// These must be available for use: +void Player::reset (void) +{ + int i; + + m_playerState = sid2_stopped; + m_running = false; + + // Select Sidplay1 compatible CPU or real thing + cpu = &sid6510; + sid6510.environment (m_info.environment); + + m_scheduler.reset (); + for (i = 0; i < SID2_MAX_SIDS; i++) + sid[i]->reset (0x0f); + + if (m_info.environment == sid2_envR) + { + cia.reset (); + cia2.reset (); + vic.reset (); + } + else + { + sid6526.reset (); + sid6526.write (0x0e, 1); // Start timer + if (m_tuneInfo.songSpeed == SIDTUNE_SPEED_VBI) + sid6526.lock (); + } + + // Initalise Memory + memset (m_ram, 0, 0x10000); + memset (m_rom, 0, 0x10000); + if (m_info.environment != sid2_envPS) + memset (m_rom + 0xA000, RTSn, 0x2000); + + if (m_info.environment == sid2_envR) + { + memcpy (&m_rom[0xe000], kernal, sizeof (kernal)); + // Since we don't yet run the kernal power up + // routines, set somethings here. + endian_little16 (&m_ram[0x028f], 0xEB48); // keyboard poll + m_rom[0xfd69] = 0x9f; // Bypass memory check + m_rom[0xe55f] = 0x00; // Bypass screen clear + endian_little16 (&m_rom[0xa000], 0xA004); + endian_little16 (&m_rom[0xa002], 0xA004); + m_rom[0xa004] = JMPw; + endian_little16 (&m_rom[0xa005], 0xA004); + } + else // !sid2_envR + { + memset (m_rom + 0xE000, RTSn, 0x2000); + // fake VBI-interrupts that do $D019, BMI ... + m_rom[0x0d019] = 0xff; + if (m_info.environment == sid2_envPS) + { + m_ram[0xff48] = JMPi; + endian_little16 (&m_ram[0xff49], 0x0314); + } + + // Software vectors + endian_little16 (&m_ram[0x0314], 0xEA31); // IRQ + endian_little16 (&m_ram[0x0316], 0xFE66); // BRK + endian_little16 (&m_ram[0x0318], 0xFE47); // NMI + // Hardware vectors + if (m_info.environment == sid2_envPS) + endian_little16 (&m_rom[0xfffa], 0xFFFA); // NMI + else + endian_little16 (&m_rom[0xfffa], 0xFE43); // NMI + endian_little16 (&m_rom[0xfffc], 0xFCE2); // RESET + endian_little16 (&m_rom[0xfffe], 0xFF48); // IRQ + memcpy (&m_ram[0xfffa], &m_rom[0xfffa], 6); + } + + // Will get done later if can't now + if (m_tuneInfo.clockSpeed == SIDTUNE_CLOCK_PAL) + m_ram[0x02a6] = 1; + else // SIDTUNE_CLOCK_NTSC + m_ram[0x02a6] = 0; +} + +// This resets the cpu once the program is loaded to begin +// running. Also called when the emulation crashes +void Player::envReset (bool safe) +{ + if (safe) + { // Emulation crashed so run in safe mode + uint8_t prg[] = {LDAb, 0x7f, STAa, 0x0d, 0xdc, RTSn}; + sid2_info_t info; + SidTuneInfo tuneInfo; + // Install driver + tuneInfo.relocStartPage = 0x09; + tuneInfo.relocPages = 0x20; + tuneInfo.initAddr = 0x0800; + tuneInfo.songSpeed = SIDTUNE_SPEED_CIA_1A; + info.environment = m_info.environment; + psidDrvInstall (tuneInfo, info); + // Install prg + memcpy (&m_ram[0x0800], prg, sizeof (prg)); + + // Make sids silent + for (int i = 0; i < SID2_MAX_SIDS; i++) + sid[i]->reset (0); + } + + m_ram[0] = 0x2F; + evalBankSelect (0x37); + // defaults: Basic-ROM on, Kernal-ROM on, I/O on + if (m_info.environment != sid2_envR) + { + uint8_t song = m_tuneInfo.currentSong - 1; + uint8_t bank = iomap (m_tuneInfo.initAddr); + if (bank == 0) + bank = 0x37; + evalBankSelect (bank); + m_playBank = iomap (m_tuneInfo.playAddr); + if (m_info.environment != sid2_envPS) + sid6510.reset (m_tuneInfo.initAddr, song, 0, 0); + else + sid6510.reset (m_tuneInfo.initAddr, song, song, song); + } + else + cpu->reset (); + + mixerReset (); + xsid.suppress (true); +} + +uint8_t Player::envReadMemByte (uint_least16_t addr) +{ // Read from plain only to prevent execution of rom code + return (this->*(m_readMemByte)) (addr); +} + +void Player::envWriteMemByte (uint_least16_t addr, uint8_t data) +{ // Writes must be passed to env version. + (this->*(m_writeMemByte)) (addr, data); +} + +uint8_t Player::envReadMemDataByte (uint_least16_t addr) +{ // Read from plain only to prevent execution of rom code + return (this->*(m_readMemDataByte)) (addr); +} + +bool Player::envCheckBankJump (uint_least16_t addr) +{ + switch (m_info.environment) + { + case sid2_envBS: + if (addr >= 0xA000) + { + // Get high-nibble of address. + switch (addr >> 12) + { + case 0xa: + case 0xb: + if (isBasic) + return false; + break; + + case 0xc: + break; + + case 0xd: + if (isIO) + return false; + break; + + case 0xe: + case 0xf: + default: // <-- just to please the compiler + if (isKernal) + return false; + break; + } + } + break; + + case sid2_envTP: + if ((addr >= 0xd000) && isKernal) + return false; + break; + + default: + break; + } + + return true; +} + +SIDPLAY2_NAMESPACE_STOP |