diff --git a/src/debugger/gui/CartBUSWidget.cxx b/src/debugger/gui/CartBUSWidget.cxx index 6ce333815..88e230aa2 100644 --- a/src/debugger/gui/CartBUSWidget.cxx +++ b/src/debugger/gui/CartBUSWidget.cxx @@ -33,8 +33,8 @@ CartridgeBUSWidget::CartridgeBUSWidget( info << "BUS Stuffing cartridge\n" << "32K ROM, seven 4K banks are accessible to 2600\n" << "8K BUS RAM\n" - << "BUS registers accessible @ $F000 - $F03F\n" - << "Banks accessible at hotspots $FFF5 to $FFFB\n" + << "BUS registers accessible @ $FFEE - $FFF3\n" + << "Banks accessible at hotspots $FFFF to $FFFB\n" << "Startup bank = " << cart.myStartBank << "\n"; #if 0 @@ -49,7 +49,7 @@ CartridgeBUSWidget::CartridgeBUSWidget( #endif int xpos = 10, - ypos = addBaseInformation(size, "AtariAge", info.str()) + + ypos = addBaseInformation(size, "AtariAge", info.str(), 4) + myLineHeight; VariantList items; @@ -70,28 +70,57 @@ CartridgeBUSWidget::CartridgeBUSWidget( int lwidth = _font.getStringWidth("Datastream Increments "); // get width of the widest label // Datastream Pointers - xpos = 0; ypos += myLineHeight + 4; +#define DS_X 30 + xpos = DS_X; + ypos += myLineHeight + 4; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, - myFontHeight, "Datastream Pointers ", kTextAlignLeft); + myFontHeight, "Datastream Pointers", kTextAlignLeft); xpos += lwidth; - myDatastreamPointers = new DataGridWidget(boss, _nfont, 0, ypos+myLineHeight-2, 4, 4, 6, 32, Common::Base::F_16_3_2); + myDatastreamPointers = new DataGridWidget(boss, _nfont, DS_X, ypos+myLineHeight-2, 4, 4, 6, 32, Common::Base::F_16_3_2); myDatastreamPointers->setTarget(this); myDatastreamPointers->setEditable(false); + + myDatastreamPointers2 = new DataGridWidget(boss, _nfont, DS_X + myDatastreamPointers->getWidth() * 3 / 4, ypos+myLineHeight-2 + 4*myLineHeight, 1, 2, 6, 32, Common::Base::F_16_3_2); + myDatastreamPointers2->setTarget(this); + myDatastreamPointers2->setEditable(false); + + uInt32 row; + for(row = 0; row < 4; ++row) + { + myDatastreamLabels[row] = + new StaticTextWidget(_boss, _font, DS_X - _font.getStringWidth("xx "), + ypos+myLineHeight-2 + row*myLineHeight + 2, + myFontWidth*2, myFontHeight, "", kTextAlignLeft); + myDatastreamLabels[row]->setLabel(Common::Base::toString(row * 4, Common::Base::F_16_2)); + } + lwidth = _font.getStringWidth("Write Data (stream 16)"); + myDatastreamLabels[4] = + new StaticTextWidget(_boss, _font, DS_X - _font.getStringWidth("xx "), + ypos+myLineHeight-2 + 4*myLineHeight + 2, + lwidth, myFontHeight, "Write Data (stream 16)", kTextAlignLeft); + myDatastreamLabels[5] = + new StaticTextWidget(_boss, _font, DS_X - _font.getStringWidth("xx "), + ypos+myLineHeight-2 + 5*myLineHeight + 2, + lwidth, myFontHeight, "Jump Data (stream 17)", kTextAlignLeft); // Datastream Increments - xpos = 0 + myDatastreamPointers->getWidth(); + xpos = DS_X + myDatastreamPointers->getWidth() + 20; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, - myFontHeight, "Datastream Increments ", kTextAlignLeft); + myFontHeight, "Datastream Increments", kTextAlignLeft); myDatastreamIncrements = new DataGridWidget(boss, _nfont, xpos, ypos+myLineHeight-2, 4, 4, 5, 32, Common::Base::F_16_2_2); myDatastreamIncrements->setTarget(this); myDatastreamIncrements->setEditable(false); + + myDatastreamIncrements2 = new DataGridWidget(boss, _nfont, xpos, ypos+myLineHeight-2 + 4*myLineHeight, 1, 2, 5, 32, Common::Base::F_16_2_2); + myDatastreamIncrements2->setTarget(this); + myDatastreamIncrements2->setEditable(false); // Datastream Maps - xpos = 0; ypos += myLineHeight*5 + 4; + xpos = 0; ypos += myLineHeight*7 + 4; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, - myFontHeight, "Address Maps ", kTextAlignLeft); + myFontHeight, "Address Maps", kTextAlignLeft); myAddressMaps = new DataGridWidget(boss, _nfont, 0, ypos+myLineHeight-2, 8, 5, 8, 32, Common::Base::F_16_8); myAddressMaps->setTarget(this); @@ -100,7 +129,7 @@ CartridgeBUSWidget::CartridgeBUSWidget( // Music counters xpos = 10; ypos += myLineHeight*6 + 4; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, - myFontHeight, "Music Counters ", kTextAlignLeft); + myFontHeight, "Music Counters", kTextAlignLeft); xpos += lwidth; myMusicCounters = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 8, 32, Common::Base::F_16_8); @@ -110,7 +139,7 @@ CartridgeBUSWidget::CartridgeBUSWidget( // Music frequencies xpos = 10; ypos += myLineHeight + 4; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, - myFontHeight, "Music Frequencies ", kTextAlignLeft); + myFontHeight, "Music Frequencies", kTextAlignLeft); xpos += lwidth; myMusicFrequencies = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 8, 32, Common::Base::F_16_8); @@ -120,17 +149,26 @@ CartridgeBUSWidget::CartridgeBUSWidget( // Music waveforms xpos = 10; ypos += myLineHeight + 4; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, - myFontHeight, "Music Waveforms ", kTextAlignLeft); + myFontHeight, "Music Waveforms", kTextAlignLeft); xpos += lwidth; myMusicWaveforms = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 4, 16, Common::Base::F_16_2); myMusicWaveforms->setTarget(this); myMusicWaveforms->setEditable(false); + + int xpossp = xpos + myMusicWaveforms->getWidth() + 20; + int lwidth2 = _font.getStringWidth("Sample Pointer "); + new StaticTextWidget(boss, _font, xpossp, ypos, lwidth2, + myFontHeight, "Sample Pointer ", kTextAlignLeft); + + mySamplePointer = new DataGridWidget(boss, _nfont, xpossp + lwidth2, ypos-2, 1, 1, 8, 32, Common::Base::F_16_8); + mySamplePointer->setTarget(this); + mySamplePointer->setEditable(false); // Music waveform sizes xpos = 10; ypos += myLineHeight + 4; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, - myFontHeight, "Music Waveform Sizes ", kTextAlignLeft); + myFontHeight, "Music Waveform Sizes", kTextAlignLeft); xpos += lwidth; myMusicWaveformSizes = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 4, 16, Common::Base::F_16_2); @@ -138,15 +176,15 @@ CartridgeBUSWidget::CartridgeBUSWidget( myMusicWaveformSizes->setEditable(false); - // BUS stuff and ZP STY flags + // BUS stuff and Digital Audio flags xpos = 10; ypos += myLineHeight + 4; myBusOverdrive = new CheckboxWidget(boss, _font, xpos, ypos, "BUS Overdrive enabled"); myBusOverdrive->setTarget(this); myBusOverdrive->setEditable(false); - xpos = _font.getStringWidth("CHECKBOX BUS Overdrive enabled"); - myZPSTY = new CheckboxWidget(boss, _font, xpos, ypos, "Zero Page STY"); - myZPSTY->setTarget(this); - myZPSTY->setEditable(false); + + myDigitalSample = new CheckboxWidget(boss, _font, xpossp, ypos, "Digital Sample mode"); + myDigitalSample->setTarget(this); + myDigitalSample->setEditable(false); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -162,8 +200,9 @@ void CartridgeBUSWidget::saveOldState() myOldState.mwaves.clear(); myOldState.mwavesizes.clear(); myOldState.internalram.clear(); + myOldState.samplepointer.clear(); - for(uInt32 i = 0; i < 16; i++) + for(uInt32 i = 0; i < 18; i++) { // Pointers are stored as: // PPPFF--- @@ -176,13 +215,21 @@ void CartridgeBUSWidget::saveOldState() // F = Fractional myOldState.datastreampointers.push_back(myCart.getDatastreamPointer(i)>>12); - myOldState.datastreamincrements.push_back(myCart.getDatastreamIncrement(i)); + if (i < 16) + myOldState.datastreamincrements.push_back(myCart.getDatastreamIncrement(i)); + else + myOldState.datastreamincrements.push_back(0x100); } - for(uInt32 i = 0; i < 40; i++) + for(uInt32 i = 0; i < 37; i++) // only 37 map values { myOldState.addressmaps.push_back(myCart.getAddressMap(i)); } + + for(uInt32 i = 37; i < 40; i++) // but need 40 for the grid + { + myOldState.addressmaps.push_back(0); + } for(uInt32 i = 0; i < 3; ++i) { @@ -198,6 +245,8 @@ void CartridgeBUSWidget::saveOldState() for(uInt32 i = 0; i < internalRamSize(); ++i) myOldState.internalram.push_back(myCart.myBUSRAM[i]); + + myOldState.samplepointer.push_back(myCart.getSample()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -228,7 +277,16 @@ void CartridgeBUSWidget::loadConfig() changed.push_back(pointervalue != myOldState.datastreampointers[i]); } myDatastreamPointers->setList(alist, vlist, changed); - + + alist.clear(); vlist.clear(); changed.clear(); + for(int i = 16; i < 18; ++i) + { + Int32 pointervalue = myCart.getDatastreamPointer(i) >> 12; + alist.push_back(0); vlist.push_back(pointervalue); + changed.push_back(pointervalue != myOldState.datastreampointers[i]); + } + myDatastreamPointers2->setList(alist, vlist, changed); + alist.clear(); vlist.clear(); changed.clear(); for(int i = 0; i < 16; ++i) { @@ -237,14 +295,29 @@ void CartridgeBUSWidget::loadConfig() changed.push_back(incrementvalue != myOldState.datastreamincrements[i]); } myDatastreamIncrements->setList(alist, vlist, changed); + + alist.clear(); vlist.clear(); changed.clear(); + for(int i = 16; i < 18; ++i) + { + Int32 incrementvalue = 0x100; + alist.push_back(0); vlist.push_back(incrementvalue); + changed.push_back(incrementvalue != myOldState.datastreamincrements[i]); + } + myDatastreamIncrements2->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); - for(int i = 0; i < 40; ++i) + for(int i = 0; i < 37; ++i) // only 37 map values { Int32 mapvalue = myCart.getAddressMap(i); alist.push_back(0); vlist.push_back(mapvalue); changed.push_back(mapvalue != myOldState.addressmaps[i]); } + for(int i = 37; i < 40; ++i) // but need 40 for the grid + { + Int32 mapvalue = 0; + alist.push_back(0); vlist.push_back(mapvalue); + changed.push_back(mapvalue != myOldState.addressmaps[i]); + } myAddressMaps->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); @@ -279,8 +352,26 @@ void CartridgeBUSWidget::loadConfig() } myMusicWaveformSizes->setList(alist, vlist, changed); -// myBusOverdrive->setState(myCart.getBusStuffFlag()); -// myZPSTY->setState(myCart.mySTYZeroPage); + alist.clear(); vlist.clear(); changed.clear(); + alist.push_back(0); vlist.push_back(myCart.getSample()); + changed.push_back((myCart.getSample()) != uInt32(myOldState.samplepointer[0])); + mySamplePointer->setList(alist, vlist, changed); + + myBusOverdrive->setState((myCart.myMode & 0x0f) == 0); + myDigitalSample->setState((myCart.myMode & 0xf0) == 0); + + if ((myCart.myMode & 0xf0) == 0) + { + myMusicWaveforms->setCrossed(true); + myMusicWaveformSizes->setCrossed(true); + mySamplePointer->setCrossed(false); + } + else + { + myMusicWaveforms->setCrossed(false); + myMusicWaveformSizes->setCrossed(false); + mySamplePointer->setCrossed(true); + } CartDebugWidget::loadConfig(); } diff --git a/src/debugger/gui/CartBUSWidget.hxx b/src/debugger/gui/CartBUSWidget.hxx index c236ffdbc..3fe552b51 100644 --- a/src/debugger/gui/CartBUSWidget.hxx +++ b/src/debugger/gui/CartBUSWidget.hxx @@ -45,6 +45,7 @@ class CartridgeBUSWidget : public CartDebugWidget IntArray mfreqs; IntArray mwaves; IntArray mwavesizes; + IntArray samplepointer; uInt32 random; ByteArray internalram; }; @@ -54,13 +55,17 @@ class CartridgeBUSWidget : public CartDebugWidget DataGridWidget* myDatastreamPointers; DataGridWidget* myDatastreamIncrements; + DataGridWidget* myDatastreamPointers2; + DataGridWidget* myDatastreamIncrements2; DataGridWidget* myAddressMaps; DataGridWidget* myMusicCounters; DataGridWidget* myMusicFrequencies; DataGridWidget* myMusicWaveforms; DataGridWidget* myMusicWaveformSizes; + DataGridWidget* mySamplePointer; + StaticTextWidget* myDatastreamLabels[6]; CheckboxWidget* myBusOverdrive; - CheckboxWidget* myZPSTY; + CheckboxWidget* myDigitalSample; CartState myOldState; enum { kBankChanged = 'bkCH' }; diff --git a/src/debugger/gui/CartCDFWidget.cxx b/src/debugger/gui/CartCDFWidget.cxx index 67adb6d5b..b97a478c1 100644 --- a/src/debugger/gui/CartCDFWidget.cxx +++ b/src/debugger/gui/CartCDFWidget.cxx @@ -96,16 +96,14 @@ CartridgeCDFWidget::CartridgeCDFWidget( myDatastreamLabels[row]->setLabel(Common::Base::toString(row * 4, Common::Base::F_16_2)); } lwidth = _font.getStringWidth("Write Data (stream 20)"); - myDatastreamLabels[row] = + myDatastreamLabels[8] = new StaticTextWidget(_boss, _font, DS_X - _font.getStringWidth("xx "), ypos+myLineHeight-2 + 8*myLineHeight + 2, lwidth, myFontHeight, "Write Data (stream 20)", kTextAlignLeft); -// myDatastreamLabels[row]->setLabel(Common::Base::toString(row * 4, Common::Base::F_16_2)); - myDatastreamLabels[row] = + myDatastreamLabels[9] = new StaticTextWidget(_boss, _font, DS_X - _font.getStringWidth("xx "), ypos+myLineHeight-2 + 9*myLineHeight + 2, lwidth, myFontHeight, "Jump Data (stream 21)", kTextAlignLeft); -// myDatastreamLabels[row]->setLabel(Common::Base::toString(row * 4, Common::Base::F_16_2)); // Datastream Increments xpos = DS_X + myDatastreamPointers->getWidth() + 20; diff --git a/src/debugger/gui/CartCDFWidget.hxx b/src/debugger/gui/CartCDFWidget.hxx index 028cbad59..57f342f80 100644 --- a/src/debugger/gui/CartCDFWidget.hxx +++ b/src/debugger/gui/CartCDFWidget.hxx @@ -65,7 +65,6 @@ class CartridgeCDFWidget : public CartDebugWidget DataGridWidget* mySamplePointer; StaticTextWidget* myDatastreamLabels[10]; - // done differently than in DPC+, need to rethink debugger support CheckboxWidget* myFastFetch; CheckboxWidget* myDigitalSample; CartState myOldState; diff --git a/src/emucore/CartBUS.cxx b/src/emucore/CartBUS.cxx index 698488772..e5be69d76 100644 --- a/src/emucore/CartBUS.cxx +++ b/src/emucore/CartBUS.cxx @@ -27,12 +27,15 @@ #include "CartBUS.hxx" // Location of data within the RAM copy of the BUS Driver. -#define DSxPTR 0x06E0 +#define DSxPTR 0x06D8 #define DSxINC 0x0720 #define DSMAPS 0x0760 #define WAVEFORM 0x07F4 #define DSRAM 0x0800 +#define COMMSTREAM 0x10 +#define JUMPSTREAM 0x11 + #define BUS_STUFF_ON ((myMode & 0x0F) == 0) #define DIGITAL_AUDIO_ON ((myMode & 0xF0) == 0) @@ -41,6 +44,7 @@ CartridgeBUS::CartridgeBUS(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings), mySystemCycles(0), + myARMCycles(0), myFractionalClocks(0.0) { // Copy the ROM image into my buffer @@ -78,6 +82,7 @@ void CartridgeBUS::reset() // Update cycles to the current system cycles mySystemCycles = mySystem->cycles(); + myARMCycles = mySystem->cycles(); myFractionalClocks = 0.0; setInitialState(); @@ -116,6 +121,7 @@ void CartridgeBUS::systemCyclesReset() { // Adjust the cycle counter so that it reflects the new value mySystemCycles -= mySystem->cycles(); + myARMCycles -= mySystem->cycles(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -172,7 +178,10 @@ inline void CartridgeBUS::callFunction(uInt8 value) // time for Stella as ARM code "runs in zero 6507 cycles". case 255: // call without IRQ driven audio try { - myThumbEmulator->run(); + Int32 cycles = mySystem->cycles() - myARMCycles; + myARMCycles = mySystem->cycles(); + + myThumbEmulator->run(cycles); } catch(const runtime_error& e) { if(!mySystem->autodetectMode()) @@ -211,6 +220,32 @@ uInt8 CartridgeBUS::peek(uInt16 address) // anything that can change the internal state of the cart if(bankLocked()) return peekvalue; + + // implement JMP FASTJMP which fetches the destination address from stream 33 + if (myFastJumpActive) + { + uInt32 pointer; + uInt8 value; + + myFastJumpActive--; + + pointer = getDatastreamPointer(JUMPSTREAM); + value = myDisplayImage[ pointer >> 20 ]; + pointer += 0x100000; // always increment by 1 + setDatastreamPointer(JUMPSTREAM, pointer); + + return value; + } + + // test for JMP FASTJUMP where FASTJUMP = $0000 + if (BUS_STUFF_ON + && peekvalue == 0x4C + && myProgramImage[(myCurrentBank << 12) + address+1] == 0 + && myProgramImage[(myCurrentBank << 12) + address+2] == 0) + { + myFastJumpActive = 2; // return next two peeks from datastream 31 + return peekvalue; + } // save the STY's zero page address if (BUS_STUFF_ON && mySTYZeroPageAddress == address) @@ -218,120 +253,90 @@ uInt8 CartridgeBUS::peek(uInt16 address) mySTYZeroPageAddress = 0; - if(address < 0x20) + switch(address) { - uInt8 result = 0; - - // Get the index of the data fetcher that's being accessed - uInt32 index = address & 0x0f; - uInt32 function = (address >> 4) & 0x01; - - switch(function) - { - case 0x00: // read from a datastream + case 0xFEE: // AMPLITUDE + + // Update the music data fetchers (counter & flag) + updateMusicModeDataFetchers(); + + if DIGITAL_AUDIO_ON { - result = readFromDatastream(index); - break; + // retrieve packed sample (max size is 2K, or 4K of unpacked data) + peekvalue = myImage[getSample() + (myMusicCounters[0] >> 21)]; + + // + if ((myMusicCounters[0] & (1<<20)) == 0) + peekvalue >>= 4; + peekvalue &= 0x0f; } - case 0x01: // misc read registers + else { - switch(index) - { - // the following are POKE ONLY - case 0x00: // 0x10 DF0WRITE - case 0x01: // 0x11 DF1WRITE - case 0x02: // 0x12 DF2WRITE - case 0x03: // 0x13 DF3WRITE - case 0x04: // 0x14 DF0PTR - case 0x05: // 0x15 DF1PTR - case 0x06: // 0x16 DF2PTR - case 0x07: // 0x17 DF3PTR - case 0x09: // 0x19 STUFFMODE - case 0x0a: // 0x1A CALLFN - break; - - case 0x08: // 0x18 = AMPLITUDE - // Update the music data fetchers (counter & flag) - updateMusicModeDataFetchers(); - - if DIGITAL_AUDIO_ON - { - // retrieve packed sample (max size is 2K, or 4K of unpacked data) - result = myImage[getSample() + (myMusicCounters[0] >> 21)]; - - // - if ((myMusicCounters[0] & (1<<20)) == 0) - result >>= 4; - result &= 0x0f; - } - else - { - // using myDisplayImage[] instead of myProgramImage[] because waveforms - // can be modified during runtime. - uInt32 i = myDisplayImage[(getWaveform(0) ) + (myMusicCounters[0] >> myMusicWaveformSize[0])] + - myDisplayImage[(getWaveform(1) ) + (myMusicCounters[1] >> myMusicWaveformSize[1])] + - myDisplayImage[(getWaveform(2) ) + (myMusicCounters[2] >> myMusicWaveformSize[2])]; - - result = uInt8(i); - } - break; - } - break; + // using myDisplayImage[] instead of myProgramImage[] because waveforms + // can be modified during runtime. + uInt32 i = myDisplayImage[(getWaveform(0) ) + (myMusicCounters[0] >> myMusicWaveformSize[0])] + + myDisplayImage[(getWaveform(1) ) + (myMusicCounters[1] >> myMusicWaveformSize[1])] + + myDisplayImage[(getWaveform(2) ) + (myMusicCounters[2] >> myMusicWaveformSize[2])]; + + peekvalue = uInt8(i); } - } - - return result; - } - else - { - // Switch banks if necessary - switch(address) - { - case 0xFF5: - // Set the current bank to the first 4k bank - bank(0); - break; - - case 0x0FF6: - // Set the current bank to the second 4k bank - bank(1); - break; - - case 0x0FF7: - // Set the current bank to the third 4k bank - bank(2); - break; - - case 0x0FF8: - // Set the current bank to the fourth 4k bank - bank(3); - break; - - case 0x0FF9: - // Set the current bank to the fifth 4k bank - bank(4); - break; - - case 0x0FFA: - // Set the current bank to the sixth 4k bank - bank(5); - break; - - case 0x0FFB: - // Set the current bank to the last 4k bank - bank(6); - break; - - default: - break; - } - - // this might not work right for STY $84 - if (BUS_STUFF_ON && peekvalue == 0x84) - mySTYZeroPageAddress = address + 1; - - return peekvalue; + break; + + case 0xFEF: // DSREAD + peekvalue = readFromDatastream(COMMSTREAM); + break; + + case 0xFF0: // DSWRITE + case 0xFF1: // DSPTR + case 0xFF2: // SETMODE + case 0xFF3: // CALLFN + // these are write-only + break; + + case 0xFF5: + // Set the current bank to the first 4k bank + bank(0); + break; + + case 0x0FF6: + // Set the current bank to the second 4k bank + bank(1); + break; + + case 0x0FF7: + // Set the current bank to the third 4k bank + bank(2); + break; + + case 0x0FF8: + // Set the current bank to the fourth 4k bank + bank(3); + break; + + case 0x0FF9: + // Set the current bank to the fifth 4k bank + bank(4); + break; + + case 0x0FFA: + // Set the current bank to the sixth 4k bank + bank(5); + break; + + case 0x0FFB: + // Set the current bank to the last 4k bank + bank(6); + break; + + default: + break; } + + // this might not work right for STY $84 + if (BUS_STUFF_ON && peekvalue == 0x84) + mySTYZeroPageAddress = address + 1; + + return peekvalue; } return 0; // make compiler happy @@ -353,102 +358,77 @@ bool CartridgeBUS::poke(uInt16 address, uInt8 value) } else { + uInt32 pointer; + address &= 0x0FFF; - if ((address >= 0x10) && (address <= 0x1F)) + switch(address) { - // Get the index of the data fetcher that's being accessed - uInt32 index = address & 0x0f; - uInt32 pointer; - - switch (index) - { - case 0x00: // DS0WRITE - case 0x01: // DS1WRITE - case 0x02: // DS2WRITE - case 0x03: // DS3WRITE - // Pointers are stored as: - // PPPFF--- - // - // P = Pointer - // F = Fractional - - pointer = getDatastreamPointer(index); - myDisplayImage[ pointer >> 20 ] = value; - pointer += 0x100000; // always increment by 1 when writing - setDatastreamPointer(index, pointer); - break; - - case 0x04: // 0x14 DS0PTR - case 0x05: // 0x15 DS1PTR - case 0x06: // 0x16 DS2PTR - case 0x07: // 0x17 DS3PTR - // Pointers are stored as: - // PPPFF--- - // - // P = Pointer - // F = Fractional - - index &= 0x03; - pointer = getDatastreamPointer(index); - pointer <<=8; - pointer &= 0xf0000000; - pointer |= (value << 20); - setDatastreamPointer(index, pointer); - break; - - case 0x09: // 0x19 SETMODE - myMode = value; - break; - - case 0x0A: // 0x1A CALLFUNCTION - callFunction(value); - break; - } - } - else - { - // Switch banks if necessary - switch(address) - { - case 0xFF5: - // Set the current bank to the first 4k bank - bank(0); - break; - - case 0x0FF6: - // Set the current bank to the second 4k bank - bank(1); - break; - - case 0x0FF7: - // Set the current bank to the third 4k bank - bank(2); - break; - - case 0x0FF8: - // Set the current bank to the fourth 4k bank - bank(3); - break; - - case 0x0FF9: - // Set the current bank to the fifth 4k bank - bank(4); - break; - - case 0x0FFA: - // Set the current bank to the sixth 4k bank - bank(5); - break; - - case 0x0FFB: - // Set the current bank to the last 4k bank - bank(6); - break; - - default: - break; - } + case 0xFEE: // AMPLITUDE + case 0xFEF: // DSREAD + // these are read-only + break; + + case 0xFF0: // DSWRITE + pointer = getDatastreamPointer(COMMSTREAM); + myDisplayImage[ pointer >> 20 ] = value; + pointer += 0x100000; // always increment by 1 when writing + setDatastreamPointer(COMMSTREAM, pointer); + break; + + case 0xFF1: // DSPTR + pointer = getDatastreamPointer(COMMSTREAM); + pointer <<=8; + pointer &= 0xf0000000; + pointer |= (value << 20); + setDatastreamPointer(COMMSTREAM, pointer); + break; + + case 0xFF2: // SETMODE + myMode = value; + break; + + case 0xFF3: // CALLFN + callFunction(value); + break; + + case 0xFF5: + // Set the current bank to the first 4k bank + bank(0); + break; + + case 0x0FF6: + // Set the current bank to the second 4k bank + bank(1); + break; + + case 0x0FF7: + // Set the current bank to the third 4k bank + bank(2); + break; + + case 0x0FF8: + // Set the current bank to the fourth 4k bank + bank(3); + break; + + case 0x0FF9: + // Set the current bank to the fifth 4k bank + bank(4); + break; + + case 0x0FFA: + // Set the current bank to the sixth 4k bank + bank(5); + break; + + case 0x0FFB: + // Set the current bank to the last 4k bank + bank(6); + break; + + default: + break; } } @@ -516,12 +496,6 @@ uInt8 CartridgeBUS::busOverdrive(uInt16 address) { uInt8 overdrive = 0xff; - // Not sure how to do this, check with stephena. - // - // Per discussion with cd-w, have this routine check that the Y register has a - // value of 0xFF. Of it doesn't then "crash the emulation". - - // only overdrive if the address matches if (address == myBusOverdriveAddress) { @@ -536,8 +510,6 @@ uInt8 CartridgeBUS::busOverdrive(uInt16 address) alldatastreams >>= 4; alldatastreams |= (datastream << 28); setAddressMap(map, alldatastreams); - - // overdrive |= 0x7c; // breaks bus stuffing to match hobo's system } } @@ -588,9 +560,26 @@ bool CartridgeBUS::save(Serializer& out) const // Harmony RAM out.putByteArray(myBUSRAM, 8192); - + + // Addresses for bus override logic + out.putShort(myBusOverdriveAddress); + out.putShort(mySTYZeroPageAddress); + + // Save cycles and clocks out.putInt(mySystemCycles); out.putInt((uInt32)(myFractionalClocks * 100000000.0)); + out.putInt(myARMCycles); + + // Audio info + out.putIntArray(myMusicCounters, 3); + out.putIntArray(myMusicFrequencies, 3); + out.putByteArray(myMusicWaveformSize, 3); + + // Indicates current mode + out.putByte(myMode); + + // Indicates if in the middle of a fast jump + out.putByte(myFastJumpActive); } catch(...) { @@ -614,10 +603,26 @@ bool CartridgeBUS::load(Serializer& in) // Harmony RAM in.getByteArray(myBUSRAM, 8192); + + // Addresses for bus override logic + myBusOverdriveAddress = in.getShort(); + mySTYZeroPageAddress = in.getShort(); // Get system cycles and fractional clocks mySystemCycles = (Int32)in.getInt(); myFractionalClocks = (double)in.getInt() / 100000000.0; + myARMCycles = (Int32)in.getInt(); + + // Audio info + in.getIntArray(myMusicCounters, 3); + in.getIntArray(myMusicFrequencies, 3); + in.getByteArray(myMusicWaveformSize, 3); + + // Indicates current mode + myMode = in.getByte(); + + // Indicates if in the middle of a fast jump + myFastJumpActive = in.getByte(); } catch(...) { diff --git a/src/emucore/CartBUS.hxx b/src/emucore/CartBUS.hxx index 5e071c584..a7cca2e2d 100644 --- a/src/emucore/CartBUS.hxx +++ b/src/emucore/CartBUS.hxx @@ -249,8 +249,9 @@ class CartridgeBUS : public Cartridge // System cycle count when the last update to music data fetchers occurred Int32 mySystemCycles; - - uInt8 mySetAddress; + + // ARM cycle count from when the last callFunction() occurred + Int32 myARMCycles; // The music mode counters uInt32 myMusicCounters[3]; @@ -270,6 +271,8 @@ class CartridgeBUS : public Cartridge // 0- = Packed Digital Sample // F- = 3 Voice Music uInt8 myMode; + + uInt8 myFastJumpActive; private: // Following constructors and assignment operators not supported diff --git a/src/emucore/CartCDF.cxx b/src/emucore/CartCDF.cxx index b246533fb..5a2556e9e 100644 --- a/src/emucore/CartCDF.cxx +++ b/src/emucore/CartCDF.cxx @@ -32,7 +32,7 @@ #define WAVEFORM 0x07F0 #define DSRAM 0x0800 -#define WRITESTREAM 0x20 +#define COMMSTREAM 0x20 #define JUMPSTREAM 0x21 #define AMPLITUDE 0x22 @@ -228,11 +228,15 @@ uInt8 CartridgeCDF::peek(uInt16 address) return peekvalue; } - // Check if we're in Fast Fetch mode and the prior byte was an A9 (LDA #value) + // Do a FAST FETCH LDA# if: + // 1) in Fast Fetch mode + // 2) peeking the operand of an LDA # instruction + // 3) peek value is 0-34 if(FAST_FETCH_ON && myLDAimmediateOperandAddress == address && peekvalue <= AMPLITUDE) { + myLDAimmediateOperandAddress = 0; if (peekvalue == AMPLITUDE) { updateMusicModeDataFetchers(); @@ -318,22 +322,21 @@ bool CartridgeCDF::poke(uInt16 address, uInt8 value) address &= 0x0FFF; - // Switch banks if necessary switch(address) { case 0xFF0: // DSWRITE - pointer = getDatastreamPointer(WRITESTREAM); + pointer = getDatastreamPointer(COMMSTREAM); myDisplayImage[ pointer >> 20 ] = value; pointer += 0x100000; // always increment by 1 when writing - setDatastreamPointer(WRITESTREAM, pointer); + setDatastreamPointer(COMMSTREAM, pointer); break; case 0xFF1: // DSPTR - pointer = getDatastreamPointer(WRITESTREAM); + pointer = getDatastreamPointer(COMMSTREAM); pointer <<=8; pointer &= 0xf0000000; pointer |= (value << 20); - setDatastreamPointer(WRITESTREAM, pointer); + setDatastreamPointer(COMMSTREAM, pointer); break; case 0xFF2: // SETMODE diff --git a/src/emucore/Thumbulator.cxx b/src/emucore/Thumbulator.cxx index b8106841f..3dd9112ff 100644 --- a/src/emucore/Thumbulator.cxx +++ b/src/emucore/Thumbulator.cxx @@ -1076,29 +1076,28 @@ int Thumbulator::execute() switch(configuration) { case ConfigureFor::BUS: - case ConfigureFor::CDF: - // this subroutine interface is used in BUS and CDF drivers, - // and starts at address 0x000006e0 in both. + // this subroutine interface is used in the BUS driver, + // it starts at address 0x000006d8 // _SetNote: // ldr r4, =NoteStore - // bx r4 // bx instruction at 0x000006e2 + // bx r4 // bx instruction at 0x000006da // _ResetWave: // ldr r4, =ResetWaveStore - // bx r4 // bx instruction at 0x000006e6 + // bx r4 // bx instruction at 0x000006de // _GetWavePtr: // ldr r4, =WavePtrFetch - // bx r4 // bx instruction at 0x000006ea + // bx r4 // bx instruction at 0x000006e2 // _SetWaveSize: // ldr r4, =WaveSizeStore - // bx r4 // bx instruction at 0x000006ee - + // bx r4 // bx instruction at 0x000006e6 + // address to test for is + 4 due to pipelining - - #define BUS_SetNote (0x000006e2 + 4) - #define BUS_ResetWave (0x000006e6 + 4) - #define BUS_GetWavePtr (0x000006ea + 4) - #define BUS_SetWaveSize (0x000006ee + 4) - + +#define BUS_SetNote (0x000006da + 4) +#define BUS_ResetWave (0x000006de + 4) +#define BUS_GetWavePtr (0x000006e2 + 4) +#define BUS_SetWaveSize (0x000006e6 + 4) + if (pc == BUS_SetNote) { myCartridge->thumbCallback(0, read_register(2), read_register(3)); @@ -1125,6 +1124,67 @@ int Thumbulator::execute() } else { +#if 0 // uncomment this for testing + uInt32 r0 = read_register(0); + uInt32 r1 = read_register(1); + uInt32 r2 = read_register(2); + uInt32 r3 = read_register(3); + uInt32 r4 = read_register(4); +#endif + myCartridge->thumbCallback(255, 0, 0); + } + + break; + + case ConfigureFor::CDF: + // this subroutine interface is used in the CDF driver, + // it starts at address 0x000006e0 + // _SetNote: + // ldr r4, =NoteStore + // bx r4 // bx instruction at 0x000006e2 + // _ResetWave: + // ldr r4, =ResetWaveStore + // bx r4 // bx instruction at 0x000006e6 + // _GetWavePtr: + // ldr r4, =WavePtrFetch + // bx r4 // bx instruction at 0x000006ea + // _SetWaveSize: + // ldr r4, =WaveSizeStore + // bx r4 // bx instruction at 0x000006ee + + // address to test for is + 4 due to pipelining + + #define CDF_SetNote (0x000006e2 + 4) + #define CDF_ResetWave (0x000006e6 + 4) + #define CDF_GetWavePtr (0x000006ea + 4) + #define CDF_SetWaveSize (0x000006ee + 4) + + if (pc == CDF_SetNote) + { + myCartridge->thumbCallback(0, read_register(2), read_register(3)); + handled = true; + } + else if (pc == CDF_ResetWave) + { + myCartridge->thumbCallback(1, read_register(2), 0); + handled = true; + } + else if (pc == CDF_GetWavePtr) + { + write_register(2, myCartridge->thumbCallback(2, read_register(2), 0)); + handled = true; + } + else if (pc == CDF_SetWaveSize) + { + myCartridge->thumbCallback(3, read_register(2), read_register(3)); + handled = true; + } + else if (pc == 0x0000083a) + { + // exiting Custom ARM code, returning to BUS Driver control + } + else + { #if 0 // uncomment this for testing uInt32 r0 = read_register(0); uInt32 r1 = read_register(1);