summaryrefslogtreecommitdiff
path: root/sid/sidplay-libs-2.1.0/libsidplay/src/psiddrv.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sid/sidplay-libs-2.1.0/libsidplay/src/psiddrv.cpp')
-rw-r--r--sid/sidplay-libs-2.1.0/libsidplay/src/psiddrv.cpp266
1 files changed, 266 insertions, 0 deletions
diff --git a/sid/sidplay-libs-2.1.0/libsidplay/src/psiddrv.cpp b/sid/sidplay-libs-2.1.0/libsidplay/src/psiddrv.cpp
new file mode 100644
index 00000000..5a8cf894
--- /dev/null
+++ b/sid/sidplay-libs-2.1.0/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