diff options
Diffstat (limited to 'plugins/sid/sidplay-libs/libsidplay/src/psiddrv.cpp')
-rw-r--r-- | plugins/sid/sidplay-libs/libsidplay/src/psiddrv.cpp | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/plugins/sid/sidplay-libs/libsidplay/src/psiddrv.cpp b/plugins/sid/sidplay-libs/libsidplay/src/psiddrv.cpp new file mode 100644 index 00000000..5a8cf894 --- /dev/null +++ b/plugins/sid/sidplay-libs/libsidplay/src/psiddrv.cpp @@ -0,0 +1,266 @@ +/*************************************************************************** + psiddrv.cpp - PSID Driver Installtion + ------------------- + begin : Fri Jul 27 2001 + copyright : (C) 2001 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: psiddrv.cpp,v $ + * Revision 1.25 2002/12/13 22:07:29 s_a_white + * C64 code fixed so a theres no decrement before checking the random value. + * + * Revision 1.24 2002/11/27 00:16:51 s_a_white + * Make sure driver info gets reset and exported properly. + * + * Revision 1.23 2002/11/25 21:09:42 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.22 2002/11/19 22:53:23 s_a_white + * Sidplay1 modes modified to make them nolonger require the psid driver. + * + * Revision 1.21 2002/11/01 19:11:21 s_a_white + * Export random delay used in song. + * + * Revision 1.20 2002/11/01 17:36:02 s_a_white + * Frame based support for old sidplay1 modes. + * + * Revision 1.19 2002/10/02 19:42:59 s_a_white + * RSID support. + * + * Revision 1.18 2002/09/12 21:01:32 s_a_white + * Added support for simulating the random delay before the user loads a + * program on a real C64. + * + * Revision 1.17 2002/09/09 18:01:30 s_a_white + * Prevent m_info driver details getting modified when C64 crashes. + * + * Revision 1.16 2002/07/21 19:39:40 s_a_white + * Proper error handling of reloc info overlapping load image. + * + * Revision 1.15 2002/07/18 18:37:42 s_a_white + * Buffer overflow fixes for tunes providing bad reloc information. + * + * Revision 1.14 2002/07/17 21:48:10 s_a_white + * PSIDv2NG reloc exclude region extension. + * + * Revision 1.13 2002/03/12 18:43:59 s_a_white + * Tidy up handling of envReset on illegal CPU instructions. + * + * Revision 1.12 2002/03/03 22:02:36 s_a_white + * Sidplay2 PSID driver length now exported. + * + * Revision 1.11 2002/02/17 12:41:18 s_a_white + * Fixed to not so easily break when C64 code is modified. + * + * Revision 1.10 2002/02/04 23:50:48 s_a_white + * Improved compatibilty with older sidplay1 modes. + * + * Revision 1.9 2002/01/29 21:50:33 s_a_white + * Auto switching to a better emulation mode. tuneInfo reloaded after a + * config. Initial code added to support more than two sids. + * + * Revision 1.8 2001/12/21 21:54:14 s_a_white + * Improved compatibility if Sidplay1 bankswitching mode. + * + * Revision 1.7 2001/12/13 08:28:08 s_a_white + * Added namespace support to fix problems with xsidplay. + * + * Revision 1.6 2001/11/16 19:23:18 s_a_white + * Fixed sign of buf for reloc65 call. + * + * Revision 1.5 2001/10/28 21:28:35 s_a_white + * For none real mode if play != 0 we now always jump to irqjob instead of + * playAddr. + * + * Revision 1.4 2001/10/02 18:31:24 s_a_white + * No longer dies if relocStartPages != 0 byr relocPages == 0. For none real + * evironment modes, play is always followed even if interrupt handlers are + * installed. + * + * Revision 1.3 2001/09/01 11:13:18 s_a_white + * Fixes sidplay1 environment modes. + * + * Revision 1.2 2001/07/27 12:52:12 s_a_white + * Removed warning. + * + * Revision 1.1 2001/07/27 12:12:23 s_a_white + * Initial release. + * + ***************************************************************************/ + +// -------------------------------------------------------- +// The code here is use to support the PSID Version 2NG +// (proposal B) file format for player relocation support. +// -------------------------------------------------------- +#include "sidendian.h" +#include "player.h" + +#define PSIDDRV_MAX_PAGE 0xff + +SIDPLAY2_NAMESPACE_START + +const char *Player::ERR_PSIDDRV_NO_SPACE = "ERROR: No space to install psid driver in C64 ram"; +const char *Player::ERR_PSIDDRV_RELOC = "ERROR: Failed whilst relocating psid driver"; + +extern "C" int reloc65(unsigned char** buf, int* fsize, int addr); + +int Player::psidDrvInstall (SidTuneInfo &tuneInfo, sid2_info_t &info) +{ + uint_least16_t relocAddr; + int startlp = tuneInfo.loadAddr >> 8; + int endlp = (tuneInfo.loadAddr + (tuneInfo.c64dataLen - 1)) >> 8; + + if (info.environment != sid2_envR) + { // Sidplay1 modes require no psid driver + info.driverAddr = 0; + info.driverLength = 0; + info.rnddelay = 0; + return 0; + } + + // Check for free space in tune + if (tuneInfo.relocStartPage == PSIDDRV_MAX_PAGE) + tuneInfo.relocPages = 0; + // Check if we need to find the reloc addr + else if (tuneInfo.relocStartPage == 0) + { // Tune is clean so find some free ram around the + // load image + psidRelocAddr (tuneInfo, startlp, endlp); + } + else + { // Check reloc information mode + int startrp = tuneInfo.relocStartPage; + int endrp = startrp + (tuneInfo.relocPages - 1); + + // New relocation implementation (exclude region) + // to complement existing method rejected as being + // unnecessary. From tests in most cases this + // method increases memory availibility. + /************************************************* + if ((startrp <= startlp) && (endrp >= endlp)) + { // Is describing used space so find some free + // ram outside this range + psidRelocAddr (tuneInfo, startrp, endrp); + } + *************************************************/ + } + + if (tuneInfo.relocPages < 1) + { + m_errorString = ERR_PSIDDRV_NO_SPACE; + return -1; + } + + relocAddr = tuneInfo.relocStartPage << 8; + + { // Place psid driver into ram + uint8_t psid_driver[] = { +# include "psiddrv.bin" + }; + uint8_t *reloc_driver = psid_driver; + int reloc_size = sizeof (psid_driver); + + if (!reloc65 (&reloc_driver, &reloc_size, relocAddr - 13)) + { + m_errorString = ERR_PSIDDRV_RELOC; + return -1; + } + + // Adjust size to not included initialisation data. + reloc_size -= 13; + info.driverAddr = relocAddr; + info.driverLength = (uint_least16_t) reloc_size; + // Round length to end of page + info.driverLength += 0xff; + info.driverLength &= 0xff00; + + m_ram[0x310] = JMPw; + memcpy (&m_ram[0x0311], &reloc_driver[4], 9); + memcpy (&m_rom[0xfffc], &reloc_driver[0], 2); /* RESET */ + + { // Experimental exit to basic support + uint_least16_t addr; + addr = endian_little16(&reloc_driver[2]); + m_rom[0xa7ae] = JMPw; + endian_little16 (&m_rom[0xa7af], 0xffe1); + endian_little16 (&m_ram[0x0328], addr); + } + memcpy (&m_ram[relocAddr], &reloc_driver[13], reloc_size); + } + + { // Setup the Initial entry point + uint_least16_t playAddr = tuneInfo.playAddr; + uint_least16_t addr = relocAddr; + + // Tell C64 about song + m_ram[addr++] = (uint8_t) tuneInfo.currentSong; + if (tuneInfo.songSpeed == SIDTUNE_SPEED_VBI) + m_ram[addr] = 0; + else // SIDTUNE_SPEED_CIA_1A + m_ram[addr] = 1; + + addr++; + endian_little16 (&m_ram[addr], tuneInfo.initAddr); + addr += 2; + endian_little16 (&m_ram[addr], playAddr); + addr += 2; + // Below we limit the delay to something sensible. + info.rnddelay = (uint_least16_t) (m_rand >> 3) & 0x0FFF; + endian_little16 (&m_ram[addr], m_info.rnddelay); + addr += 2; + m_rand = m_rand * 13 + 1; + m_ram[addr++] = iomap (m_tuneInfo.initAddr); + m_ram[addr++] = iomap (m_tuneInfo.playAddr); + } + return 0; +} + + +void Player::psidRelocAddr (SidTuneInfo &tuneInfo, int startp, int endp) +{ // Used memory ranges. + bool pages[256]; + int used[] = {0x00, 0x03, + 0xa0, 0xbf, + 0xd0, 0xff, + startp, endp}; + + // Mark used pages in table. + memset(pages, false, sizeof(pages)); + for (size_t i = 0; i < sizeof(used)/sizeof(*used); i += 2) + { + for (int page = used[i]; page <= used[i + 1]; page++) + pages[page] = true; + } + + { // Find largest free range. + int relocPages, lastPage = 0; + tuneInfo.relocPages = 0; + for (size_t page = 0; page < sizeof(pages)/sizeof(*pages); page++) + { + if (pages[page] == false) + continue; + relocPages = page - lastPage; + if (relocPages > tuneInfo.relocPages) + { + tuneInfo.relocStartPage = lastPage; + tuneInfo.relocPages = relocPages; + } + lastPage = page + 1; + } + } + + if (tuneInfo.relocPages == 0) + tuneInfo.relocStartPage = PSIDDRV_MAX_PAGE; +} + +SIDPLAY2_NAMESPACE_STOP |