From 93deeecadfb3694c4c7059a2585ab8d32516fab3 Mon Sep 17 00:00:00 2001 From: stephena Date: Thu, 24 May 2012 21:41:54 +0000 Subject: [PATCH] More work on Chetiry bankswitch scheme. I may not get it finished before the release tomorrow (since I'm not entirely sure how it works), but I'm going to give it the old college try. git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2497 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba --- src/emucore/CartCTY.cxx | 99 ++++++++++++++++++++++++++++++------ src/emucore/CartCTY.hxx | 31 +++++++++-- src/emucore/CartCTYTunes.hxx | 21 ++++++++ 3 files changed, 133 insertions(+), 18 deletions(-) diff --git a/src/emucore/CartCTY.cxx b/src/emucore/CartCTY.cxx index 2d2b22f9e..7f8321c97 100644 --- a/src/emucore/CartCTY.cxx +++ b/src/emucore/CartCTY.cxx @@ -31,8 +31,12 @@ CartridgeCTY::CartridgeCTY(const uInt8* image, uInt32 size, const OSystem& osyst : Cartridge(osystem.settings()), myOSystem(osystem), myOperationType(0), + myCounter(0), myLDAimmediate(false), - myRamAccessTimeout(0) + myRandomNumber(0x2B435044), + myRamAccessTimeout(0), + mySystemCycles(0), + myFractionalClocks(0.0) { // Copy the ROM image into my buffer memcpy(myImage, image, BSPF_min(32768u, size)); @@ -41,6 +45,9 @@ CartridgeCTY::CartridgeCTY(const uInt8* image, uInt32 size, const OSystem& osyst // This cart contains 64 bytes extended RAM @ 0x1000 registerRamArea(0x1000, 64, 0x40, 0x00); + // Point to the first tune + myFrequencyImage = CartCTYTunes; + // Remember startup bank (not bank 0, since that's ARM code) myStartBank = 1; } @@ -62,10 +69,21 @@ void CartridgeCTY::reset() myRAM[0] = myRAM[1] = myRAM[2] = myRAM[3] = 0xFF; + // Update cycles to the current system cycles + mySystemCycles = mySystem->cycles(); + myFractionalClocks = 0.0; + // Upon reset we switch to the startup bank bank(myStartBank); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void CartridgeCTY::systemCyclesReset() +{ + // Adjust the cycle counter so that it reflects the new value + mySystemCycles -= mySystem->cycles(); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCTY::install(System& system) { @@ -101,6 +119,18 @@ uInt8 CartridgeCTY::peek(uInt16 address) if(myLDAimmediate && peekValue == 0xF2) { myLDAimmediate = false; + + // Update the music data fetchers (counter & flag) + updateMusicModeDataFetchers(); + +#if 0 + // using myDisplayImage[] instead of myProgramImage[] because waveforms + // can be modified during runtime. + uInt32 i = myDisplayImage[(myMusicWaveforms[0] << 5) + (myMusicCounters[0] >> 27)] + + myDisplayImage[(myMusicWaveforms[1] << 5) + (myMusicCounters[1] >> 27)] + + myDisplayImage[(myMusicWaveforms[2] << 5) + (myMusicCounters[2] >> 27)]; + return = (uInt8)i; +#endif return 0xF2; // FIXME - return frequency value here } else @@ -122,19 +152,18 @@ uInt8 CartridgeCTY::peek(uInt16 address) else if(address < 0x0080) // Read port is at $1040 - $107F (64 bytes) { address -= 0x40; - switch(address) // FIXME for actual return values (0-3) + switch(address) { case 0x00: // Error code after operation return myRAM[0]; case 0x01: // Get next Random Number (8-bit LFSR) - cerr << "Get next Random Number (8-bit LFSR)\n"; - return 0xFF; + myRandomNumber = ((myRandomNumber & (1<<10)) ? 0x10adab1e: 0x00) ^ + ((myRandomNumber >> 11) | (myRandomNumber << 21)); + return myRandomNumber & 0xFF; case 0x02: // Get Tune position (low byte) - cerr << "Get Tune position (low byte)\n"; - return 0x00; + return myCounter & 0xFF; case 0x03: // Get Tune position (high byte) - cerr << "Get Tune position (high byte)\n"; - return 0x00; + return (myCounter >> 8) & 0xFF; default: return myRAM[address]; } @@ -180,14 +209,14 @@ bool CartridgeCTY::poke(uInt16 address, uInt8 value) case 0x00: // Operation type for $1FF4 myOperationType = value; break; - case 0x01: // Set Random seed value - cerr << "Set random seed value = " << HEX2 << (int)value << endl; + case 0x01: // Set Random seed value (reset) + myRandomNumber = 0x2B435044; break; case 0x02: // Reset fetcher to beginning of tune - cerr << "Reset fetcher to beginning of tune\n"; + myCounter = 0; break; case 0x03: // Advance fetcher to next tune position - cerr << "Advance fetcher to next tune position\n"; + myCounter = (myCounter + 3) & 0x0fff; break; default: myRAM[address] = value; @@ -282,8 +311,15 @@ bool CartridgeCTY::save(Serializer& out) const { out.putString(name()); out.putShort(bank()); - out.putByte(myOperationType); out.putByteArray(myRAM, 64); + + out.putByte(myOperationType); + out.putShort(myCounter); + out.putBool(myLDAimmediate); + out.putInt(myRandomNumber); + out.putInt(mySystemCycles); + out.putInt((uInt32)(myFractionalClocks * 100000000.0)); + } catch(const char* msg) { @@ -304,9 +340,14 @@ bool CartridgeCTY::load(Serializer& in) // Remember what bank we were in bank(in.getShort()); + in.getByteArray(myRAM, 64); myOperationType = in.getByte(); - in.getByteArray(myRAM, 64); + myCounter = in.getShort(); + myLDAimmediate = in.getBool(); + myRandomNumber = in.getInt(); + mySystemCycles = (Int32)in.getInt(); + myFractionalClocks = (double)in.getInt() / 100000000.0; } catch(const char* msg) { @@ -405,7 +446,13 @@ uInt8 CartridgeCTY::ramReadWrite() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCTY::loadTune(uInt8 index) { - cerr << "load tune " << (int)index << endl; + // Each tune is offset by 4096 bytes + // Instead of copying non-modifiable data around (as would happen on the + // Harmony), we simply point to the appropriate tune + myFrequencyImage = CartCTYTunes + (index << 12); + + // Reset to beginning of tune + myCounter = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -482,3 +529,25 @@ void CartridgeCTY::wipeAllScores() } } } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +inline void CartridgeCTY::updateMusicModeDataFetchers() +{ + // Calculate the number of cycles since the last update + Int32 cycles = mySystem->cycles() - mySystemCycles; + mySystemCycles = mySystem->cycles(); + + // Calculate the number of DPC OSC clocks since the last update + double clocks = ((20000.0 * cycles) / 1193191.66666667) + myFractionalClocks; + Int32 wholeClocks = (Int32)clocks; + myFractionalClocks = clocks - (double)wholeClocks; + + if(wholeClocks <= 0) + return; + + // Let's update counters and flags of the music mode data fetchers + for(int x = 0; x <= 2; ++x) + { +// myMusicCounters[x] += myMusicFrequencies[x]; + } +} diff --git a/src/emucore/CartCTY.hxx b/src/emucore/CartCTY.hxx index e59768fa2..175cd3047 100644 --- a/src/emucore/CartCTY.hxx +++ b/src/emucore/CartCTY.hxx @@ -130,6 +130,13 @@ class CartridgeCTY : public Cartridge */ void reset(); + /** + Notification method invoked by the system right before the + system resets its cycle counter to zero. It may be necessary + to override this method for devices that remember cycle counts. + */ + void systemCyclesReset(); + /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @@ -238,6 +245,12 @@ class CartridgeCTY : public Cartridge void saveScore(uInt8 index); void wipeAllScores(); + /** + Updates any data fetchers in music mode based on the number of + CPU cycles which have passed since the last update. + */ + void updateMusicModeDataFetchers(); + private: // OSsytem currently in use const OSystem& myOSystem; @@ -254,13 +267,19 @@ class CartridgeCTY : public Cartridge // Operation type (written to $1000, used by hotspot $1FF4) uInt8 myOperationType; - // The 8K Harmony RAM (used for tune data) - // Data is accessed from Harmony EEPROM - uInt8 myTuneRAM[8192]; + // Pointer to the 28K frequency table (points to the start of one + // of seven 4K tunes in CartCTYTunes) + const uInt8* myFrequencyImage; + + // The counter register for the data fetcher + uInt16 myCounter; // Flags that last byte peeked was A9 (LDA #) bool myLDAimmediate; + // The random number generator register + uInt32 myRandomNumber; + // The time after which the first request of a load/save operation // will actually be completed // Due to Harmony EEPROM constraints, a read/write isn't instantaneous, @@ -270,6 +289,12 @@ class CartridgeCTY : public Cartridge // Full pathname of the file to use when emulating load/save // of internal RAM to Harmony cart EEPROM string myEEPROMFile; + + // System cycle count when the last update to music data fetchers occurred + Int32 mySystemCycles; + + // Fractional DPC music OSC clocks unused during the last update + double myFractionalClocks; }; #endif diff --git a/src/emucore/CartCTYTunes.hxx b/src/emucore/CartCTYTunes.hxx index 10b875d55..76ae10b30 100644 --- a/src/emucore/CartCTYTunes.hxx +++ b/src/emucore/CartCTYTunes.hxx @@ -28,6 +28,9 @@ #define CHETIRY_TUNES_SIZE 7 * 4096 static const uInt8 CartCTYTunes[CHETIRY_TUNES_SIZE] = { + /////////////////////////// + // Tune 1 + /////////////////////////// 0x25, 0x20, 0x02, 0x00, 0x00, 0x00, 0x25, 0x20, 0x00, 0x00, 0x00, 0x00, 0x25, 0x20, 0x00, 0x00, 0x00, 0x00, 0x25, 0x20, 0x00, 0x00, 0x00, 0x00, 0x23, 0x25, 0x00, 0x00, 0x00, 0x00, 0x22, 0x27, 0x00, 0x00, 0x00, 0x00, 0x20, 0x29, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x2a, 0x00, 0x00, 0x00, 0x00, @@ -284,6 +287,9 @@ static const uInt8 CartCTYTunes[CHETIRY_TUNES_SIZE] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /////////////////////////// + // Tune 2 + /////////////////////////// 0x2e, 0x29, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x29, 0x26, 0x0a, 0x00, 0x00, 0x00, 0x2a, 0x27, 0x16, 0x00, 0x00, 0x00, 0x2c, 0x29, 0x0a, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x16, 0x2c, 0x00, 0x00, 0x2a, 0x27, 0x0a, 0x00, 0x00, 0x00, 0x29, 0x25, 0x16, 0x00, 0x00, 0x00, @@ -540,6 +546,9 @@ static const uInt8 CartCTYTunes[CHETIRY_TUNES_SIZE] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /////////////////////////// + // Tune 3 + /////////////////////////// 0x02, 0x16, 0x02, 0x00, 0x02, 0x00, 0x00, 0x16, 0x00, 0x00, 0x16, 0x00, 0x00, 0x11, 0x00, 0x00, 0x02, 0x00, 0x00, 0x11, 0x00, 0x00, 0x02, 0x00, 0x00, 0x16, 0x00, 0x00, 0x02, 0x00, 0x00, 0x16, 0x00, 0x00, 0x16, 0x00, 0x00, 0x11, 0x00, 0x00, 0x02, 0x00, 0x00, 0x11, 0x00, 0x00, 0x02, 0x00, @@ -796,6 +805,9 @@ static const uInt8 CartCTYTunes[CHETIRY_TUNES_SIZE] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /////////////////////////// + // Tune 4 + /////////////////////////// 0x27, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x2f, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x1b, 0x00, 0x00, 0x00, @@ -1052,6 +1064,9 @@ static const uInt8 CartCTYTunes[CHETIRY_TUNES_SIZE] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /////////////////////////// + // Tune 5 + /////////////////////////// 0x1e, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1308,6 +1323,9 @@ static const uInt8 CartCTYTunes[CHETIRY_TUNES_SIZE] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /////////////////////////// + // Tune 6 + /////////////////////////// 0x29, 0x02, 0x16, 0x00, 0x00, 0x00, 0x29, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x11, 0x29, 0x00, 0x00, 0x27, 0x1d, 0x19, 0x2a, 0x00, 0x00, 0x29, 0x02, 0x18, 0x00, 0x00, 0x00, 0x27, 0x1e, 0x1b, 0x00, 0x00, 0x00, 0x25, 0x02, 0x12, 0x00, 0x00, 0x00, 0x27, 0x1e, 0x0f, 0x00, 0x00, 0x00, @@ -1564,6 +1582,9 @@ static const uInt8 CartCTYTunes[CHETIRY_TUNES_SIZE] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /////////////////////////// + // Tune 7 + /////////////////////////// 0x27, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x1b, 0x16, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00,