mirror of https://github.com/stella-emu/stella.git
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
This commit is contained in:
parent
3a2865981a
commit
93deeecadf
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue