From 10022676e9a3dda62e7c3f1619c5b17828c62bcf Mon Sep 17 00:00:00 2001 From: stephena Date: Sun, 18 Apr 2010 15:01:38 +0000 Subject: [PATCH] Updated DPC+ code to latest version from Spiceware. Hopefully we can get final support for this completed before the 3.1 release next week. git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2015 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba --- src/emucore/CartDPCPlus.cxx | 250 +++++++++++++----------------------- src/emucore/CartDPCPlus.hxx | 13 +- 2 files changed, 95 insertions(+), 168 deletions(-) diff --git a/src/emucore/CartDPCPlus.cxx b/src/emucore/CartDPCPlus.cxx index a8343ae0a..b15e4c85d 100644 --- a/src/emucore/CartDPCPlus.cxx +++ b/src/emucore/CartDPCPlus.cxx @@ -1,8 +1,8 @@ //============================================================================ // -// SSSS tt lll lll -// SS SS tt ll ll -// SS tttttt eeee ll ll aaaa +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa @@ -28,7 +28,6 @@ CartridgeDPCPlus::CartridgeDPCPlus(const uInt8* image, uInt32 size) : myFastFetch(false), myLDAimmediate(false), mySelectByte(0), - myMusicVolume(0), mySystemCycles(0), myFractionalClocks(0.0) { @@ -41,7 +40,7 @@ CartridgeDPCPlus::CartridgeDPCPlus(const uInt8* image, uInt32 size) // Copy the display ROM image into my buffer memcpy(myDisplayImage, image + 4096 * 6, 4096); - + // Copy the Frequency ROM image into my buffer memcpy(myFrequencyImage, image + 4096 * 6 + 4096, 1024); @@ -49,8 +48,8 @@ CartridgeDPCPlus::CartridgeDPCPlus(const uInt8* image, uInt32 size) for(uInt16 i = 0; i < 8; ++i) myTops[i] = myBottoms[i] = myCounters[i] = myFlags[i] = myFractionalIncrements[i] = 0; - // Set waveforms to square waves - myMusicWaveforms[0] = myMusicWaveforms[1] = myMusicWaveforms[2] = 0xAAAAAAAA; + // Set waveforms to first waveform entry + myMusicWaveforms[0] = myMusicWaveforms[1] = myMusicWaveforms[2] = 0; // Initialize the DPC's random number generator register (must be non-zero) myRandomNumber = 0x2B435044; // "DPC+" @@ -91,10 +90,10 @@ void CartridgeDPCPlus::install(System& system) mySystem = &system; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); - + // Make sure the system we're being installed in has a page size that'll work assert(((0x1080 & mask) == 0) && ((0x1100 & mask) == 0)); - + // Map all of the accesses to call peek and poke System::PageAccess access; access.directPeekBase = 0; @@ -103,7 +102,7 @@ void CartridgeDPCPlus::install(System& system) access.type = System::PA_READ; for(uInt32 i = 0x1000; i < 0x2000; i += (1 << shift)) mySystem->setPageAccess(i >> shift, access); - + // Install pages for the startup bank bank(myStartBank); } @@ -128,23 +127,21 @@ inline void CartridgeDPCPlus::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 = 5; x <= 7; ++x) + for(int x = 0; x <= 2; ++x) { - myMusicCounters[x - 5] += myMusicFrequencies[x - 5]; - if (myMusicFrequencies[x-5]>myMusicCounters[x-5]) - myMusicWaveforms[x-5] = (myMusicWaveforms[x-5]>>1)|(myMusicWaveforms[x-5]<<31); + myMusicCounters[x] += myMusicFrequencies[x]; } } @@ -153,66 +150,7 @@ inline void CartridgeDPCPlus::writeByte(uInt8 value) { switch (mySelectByte & 0x7F) { - case 0x00: - { - myMusicWaveforms[0] = (myMusicWaveforms[0] & 0xFFFFFF00) | value; - break; - } - case 0x01: - { - myMusicWaveforms[0] = (myMusicWaveforms[0] & 0xFFFF00FF) | (value<<8); - break; - } - case 0x02: - { - myMusicWaveforms[0] = (myMusicWaveforms[0] & 0xFF00FFFF) | (value<<16); - break; - } - case 0x03: - { - myMusicWaveforms[0] = (myMusicWaveforms[0] & 0x00FFFFFF) | (value<<24); - break; - } - case 0x04: - { - myMusicWaveforms[1] = (myMusicWaveforms[1] & 0xFFFFFF00) | value; - break; - } - case 0x05: - { - myMusicWaveforms[1] = (myMusicWaveforms[1] & 0xFFFF00FF) | (value<<8); - break; - } - case 0x06: - { - myMusicWaveforms[1] = (myMusicWaveforms[1] & 0xFF00FFFF) | (value<<16); - break; - } - case 0x07: - { - myMusicWaveforms[1] = (myMusicWaveforms[1] & 0x00FFFFFF) | (value<<24); - break; - } - case 0x08: - { - myMusicWaveforms[2] = (myMusicWaveforms[2] & 0xFFFFFF00) | value; - break; - } - case 0x09: - { - myMusicWaveforms[2] = (myMusicWaveforms[2] & 0xFFFF00FF) | (value<<8); - break; - } - case 0x0A: - { - myMusicWaveforms[2] = (myMusicWaveforms[2] & 0xFF00FFFF) | (value<<16); - break; - } - case 0x0B: - { - myMusicWaveforms[2] = (myMusicWaveforms[2] & 0x00FFFFFF) | (value<<24); - break; - } + // reserved } if (mySelectByte & 0x80) @@ -225,7 +163,7 @@ uInt8 CartridgeDPCPlus::peek(uInt16 address) address &= 0x0FFF; uInt8 peekvalue = myProgramImage[(myCurrentBank << 12) + address]; - + // In debugger/bank-locked mode, we ignore all hotspots and in general // anything that can change the internal state of the cart if(bankLocked()) @@ -235,19 +173,19 @@ uInt8 CartridgeDPCPlus::peek(uInt16 address) if(myFastFetch && myLDAimmediate) { if(peekvalue < 0x0028) - // if #value is a read-register then we want to use that as the address + // if #value is a read-register then we want to use that as the address address = peekvalue; } myLDAimmediate = false; - + if(address < 0x0028) { uInt8 result = 0; - + // Get the index of the data fetcher that's being accessed uInt32 index = address & 0x07; uInt32 function = (address >> 3) & 0x07; - + // Update flag register for selected data fetcher if((myCounters[index] & 0x00ff) == ((myTops[index]+1) & 0xff)) { @@ -257,7 +195,7 @@ uInt8 CartridgeDPCPlus::peek(uInt16 address) { myFlags[index] = 0x00; } - + switch(function) { case 0x00: @@ -268,36 +206,37 @@ uInt8 CartridgeDPCPlus::peek(uInt16 address) clockRandomNumberGenerator(); result = myRandomNumber & 0xFF; break; - + case 0x01: // RANDOM0PRIOR - return to prior and return byte 0 of random priorClockRandomNumberGenerator(); result = myRandomNumber & 0xFF; break; - + case 0x02: // RANDOM1 result = (myRandomNumber>>8) & 0xFF; break; - + case 0x03: // RANDOM2 result = (myRandomNumber>>16) & 0xFF; break; - + case 0x04: // RANDOM3 result = (myRandomNumber>>24) & 0xFF; break; - + case 0x05: // AMPLITUDE { // Update the music data fetchers (counter & flag) updateMusicModeDataFetchers(); - - uInt32 i = myMusicVolume + - (((myMusicWaveforms[0] >> 31) & 1) ? (myMusicVolume >> 12): 0) + - (((myMusicWaveforms[1] >> 31) & 1) ? (myMusicVolume >> 16): 0) + - (((myMusicWaveforms[2] >> 31) & 1) ? (myMusicVolume >> 24): 0); - + + // using myImageCopy[] instead of myDisplayImage[] because waveforms + // could also be in the 1K Frequency table. + uInt32 i = myImageCopy[6*4096 + (myMusicWaveforms[0] << 5) + (myMusicCounters[0] >> 27)] + + myImageCopy[6*4096 + (myMusicWaveforms[1] << 5) + (myMusicCounters[1] >> 27)] + + myImageCopy[6*4096 + (myMusicWaveforms[2] << 5) + (myMusicCounters[2] >> 27)]; + result = (uInt8)i; - break; + break; } case 0x06: // reserved @@ -306,30 +245,30 @@ uInt8 CartridgeDPCPlus::peek(uInt16 address) } break; } - + // DFxDATA - display data read case 0x01: { result = myDisplayImage[myCounters[index]]; - myCounters[index] = (myCounters[index] + 0x1) & 0x0fff; + myCounters[index] = (myCounters[index] + 0x1) & 0x0fff; break; } - + // DFxDATAW - display data read AND'd w/flag ("windowed") case 0x02: { result = myDisplayImage[myCounters[index]] & myFlags[index]; - myCounters[index] = (myCounters[index] + 0x1) & 0x0fff; + myCounters[index] = (myCounters[index] + 0x1) & 0x0fff; break; - } - + } + // DFxFRACDATA - display data read w/fractional increment case 0x03: { result = myDisplayImage[myFractionalCounters[index] >> 8]; - myFractionalCounters[index] = (myFractionalCounters[index] + myFractionalIncrements[index]) & 0x0fffff; + myFractionalCounters[index] = (myFractionalCounters[index] + myFractionalIncrements[index]) & 0x0fffff; break; - } + } case 0x04: { @@ -349,15 +288,15 @@ uInt8 CartridgeDPCPlus::peek(uInt16 address) case 0x07: // reserved break; } - break; + break; } - + default: { result = 0; } } - + return result; } else @@ -369,36 +308,36 @@ uInt8 CartridgeDPCPlus::peek(uInt16 address) // Set the current bank to the first 4k bank bank(0); break; - + case 0x0FF7: // Set the current bank to the second 4k bank bank(1); break; - + case 0x0FF8: // Set the current bank to the third 4k bank bank(2); break; - + case 0x0FF9: // Set the current bank to the fourth 4k bank bank(3); break; - + case 0x0FFA: // Set the current bank to the fifth 4k bank bank(4); break; - + case 0x0FFB: // Set the current bank to the last 4k bank bank(5); break; - + default: break; } - + if(myFastFetch) myLDAimmediate = (peekvalue == 0xA9); @@ -410,25 +349,25 @@ uInt8 CartridgeDPCPlus::peek(uInt16 address) bool CartridgeDPCPlus::poke(uInt16 address, uInt8 value) { address &= 0x0FFF; - - if((address >= 0x0028) && (address < 0x0080)) + + if((address >= 0x0028) && (address < 0x0080)) { // Get the index of the data fetcher that's being accessed - uInt32 index = address & 0x07; + uInt32 index = address & 0x07; uInt32 function = ((address - 0x28) >> 3) & 0x0f; - + switch(function) { //DFxFRACLOW - fractional data pointer low byte case 0x00: myFractionalCounters[index] = (myFractionalCounters[index] & 0x0F0000) | ((uInt16)value << 8); break; - + // DFxFRACHI - fractional data pointer high byte case 0x01: myFractionalCounters[index] = (((uInt16)value & 0x0F) << 16) | (myFractionalCounters[index] & 0x00ffff); break; - + //DFxFRACINC - Fractional Increment amount case 0x02: myFractionalIncrements[index] = value; @@ -440,17 +379,17 @@ bool CartridgeDPCPlus::poke(uInt16 address, uInt8 value) myTops[index] = value; myFlags[index] = 0x00; break; - + // DFxBOT - set bottom of window (for reads of DFxDATAW) case 0x04: myBottoms[index] = value; break; - + // DFxLOW - data pointer low byte case 0x05: myCounters[index] = (myCounters[index] & 0x0F00) | value ; break; - + // Control registers case 0x06: switch (index) @@ -471,18 +410,15 @@ bool CartridgeDPCPlus::poke(uInt16 address, uInt8 value) case 0x04: // reserved break; - case 0x05: // VOLUME0 - myMusicVolume = (myMusicVolume & 0xFFFF00FF) | ((value & 0x0F)<<12); + case 0x05: // WAVEFORM0 + case 0x06: // WAVEFORM1 + case 0x07: // WAVEFORM2 + // make sure index isn't beyond the 29K cartridge space + // not sure how the Harmony handles it (most likely uses the ARM code), + // but we want to make sure an invalid memory access doesn't crash Stella. + if (value >=159) value = 0; + myMusicWaveforms[index - 5] = value; break; - - case 0x06: // VOLUME1 - myMusicVolume = (myMusicVolume & 0xFF00FFFF) | ((value & 0x0F)<<16); - break; - - case 0x07: // VOLUME2 - myMusicVolume = (myMusicVolume & 0x00FFFFFF) | ((value & 0x0F)<<24); - break; - } break; @@ -493,14 +429,14 @@ bool CartridgeDPCPlus::poke(uInt16 address, uInt8 value) myDisplayImage[myCounters[index]] = value; break; } - + // DFxHI - data pointer high byte case 0x08: { myCounters[index] = (((uInt16)value & 0x0F) << 8) | (myCounters[index] & 0x00ff); break; - } - + } + case 0x09: { switch (index) @@ -533,7 +469,7 @@ bool CartridgeDPCPlus::poke(uInt16 address, uInt8 value) case 0x05: // NOTE0 case 0x06: // NOTE1 case 0x07: // NOTE2 - { + { myMusicFrequencies[index-5] = myFrequencyImage[(value<<2)] + (myFrequencyImage[(value<<2)+1]<<8) + (myFrequencyImage[(value<<2)+2]<<16) + @@ -545,7 +481,7 @@ bool CartridgeDPCPlus::poke(uInt16 address, uInt8 value) } break; } - + // DFxWRITE - write into data bank case 0x0a: { @@ -553,12 +489,12 @@ bool CartridgeDPCPlus::poke(uInt16 address, uInt8 value) myCounters[index] = (myCounters[index] + 0x1) & 0x0fff; break; } - + default: { break; } - } + } } else { @@ -569,32 +505,32 @@ bool CartridgeDPCPlus::poke(uInt16 address, uInt8 value) // Set the current bank to the first 4k bank bank(0); break; - + case 0x0FF7: // Set the current bank to the second 4k bank bank(1); break; - + case 0x0FF8: // Set the current bank to the third 4k bank bank(2); break; - + case 0x0FF9: // Set the current bank to the fourth 4k bank bank(3); break; - + case 0x0FFA: // Set the current bank to the fifth 4k bank bank(4); break; - + case 0x0FFB: // Set the current bank to the last 4k bank bank(5); break; - + default: break; } @@ -604,7 +540,7 @@ bool CartridgeDPCPlus::poke(uInt16 address, uInt8 value) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDPCPlus::bank(uInt16 bank) -{ +{ if(bankLocked()) return; // Remember what bank we're in @@ -638,12 +574,12 @@ bool CartridgeDPCPlus::patch(uInt16 address, uInt8 value) } else return false; -} +} // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeDPCPlus::getImage(int& size) const { - size = 4096 * 6 + 4096 + 255; + size = 4096 * 6 + 4096 + 1024 + 255; return myImageCopy; } @@ -675,7 +611,7 @@ bool CartridgeDPCPlus::save(Serializer& out) const out.putInt(8); for(i = 0; i < 8; ++i) out.putInt(myCounters[i]); - + // The counter registers for the fractional data fetchers out.putInt(8); for(i = 0; i < 8; ++i) @@ -698,13 +634,10 @@ bool CartridgeDPCPlus::save(Serializer& out) const // Control Byte to update out.putByte((char) mySelectByte); - // The music volume - out.putInt(myMusicVolume); - // The music counters out.putInt(3); for(i = 0; i < 3; ++i) - out.putInt(myMusicCounters[i]); + out.putInt(myMusicCounters[i]); // The music frequencies out.putInt(3); @@ -783,23 +716,20 @@ bool CartridgeDPCPlus::load(Serializer& in) // Control Byte to update mySelectByte = (uInt8) in.getByte(); - // The music volume - myMusicVolume = (uInt32) in.getInt(); - // The music mode counters for the data fetchers limit = (uInt32) in.getInt(); for(i = 0; i < limit; ++i) - myMusicCounters[i] = (uInt32) in.getInt(); + myMusicCounters[i] = (uInt32) in.getInt(); // The music mode frequency addends for the data fetchers limit = (uInt32) in.getInt(); for(i = 0; i < limit; ++i) - myMusicFrequencies[i] = (uInt32) in.getInt(); + myMusicFrequencies[i] = (uInt32) in.getInt(); // The music waveforms limit = (uInt32) in.getInt(); for(i = 0; i < limit; ++i) - myMusicWaveforms[i] = (uInt32) in.getInt(); + myMusicWaveforms[i] = (uInt16) in.getInt(); // The random number generator register myRandomNumber = (uInt32) in.getInt(); diff --git a/src/emucore/CartDPCPlus.hxx b/src/emucore/CartDPCPlus.hxx index 696c8fc24..399adc3df 100644 --- a/src/emucore/CartDPCPlus.hxx +++ b/src/emucore/CartDPCPlus.hxx @@ -26,9 +26,9 @@ class System; #include "Cart.hxx" /** - Cartridge class used for DPC+. There are six 4K program banks, a - 4K display bank, and the DPC chip. For complete details on the DPC chip - see David P. Crane's United States Patent Number 4,644,495. + Cartridge class used for DPC+. There are six 4K program banks, a 4K + display bank, 1K frequency table and the DPC chip. For complete details on + the DPC chip see David P. Crane's United States Patent Number 4,644,495. @author Darrell Spice Jr, Fred Quimby, Stephen Anthony @version $Id$ @@ -208,9 +208,6 @@ class CartridgeDPCPlus : public Cartridge // Control Byte to update uInt8 mySelectByte; - // The music volume - uInt32 myMusicVolume; - // The music mode counters uInt32 myMusicCounters[3]; @@ -218,8 +215,8 @@ class CartridgeDPCPlus : public Cartridge uInt32 myMusicFrequencies[3]; // The music waveforms - uInt32 myMusicWaveforms[3]; - + uInt16 myMusicWaveforms[3]; + // The random number generator register uInt32 myRandomNumber;