Updated BUS to new spec

The Harmony/Melody BUS driver is undergoing a major revision to add support for the new JMP FASTJUMP feature.  This update implements the changes, as well as the fast jump feature which isn't yet in the HMdriver.  It also implements the load/save state support as well as the BUS debugger widget.

A few minor updates to CDF were also done.

Note that this update breaks compatibility with the previous BUS demos.
This commit is contained in:
Darrell Spice, Jr 2017-05-07 14:43:54 -05:00
parent e3514a9f80
commit 490724c079
8 changed files with 441 additions and 277 deletions

View File

@ -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 $FF5 to $FFB\n"
<< "BUS registers accessible @ $FFEE - $FFF3\n"
<< "Banks accessible at hotspots $FFFF to $FFFB\n"
<< "Startup bank = " << cart.myStartBank << "\n";
#if 0
@ -49,49 +49,78 @@ CartridgeBUSWidget::CartridgeBUSWidget(
#endif
int xpos = 10,
ypos = addBaseInformation(size, "AtariAge", info.str()) +
ypos = addBaseInformation(size, "AtariAge", info.str(), 4) +
myLineHeight;
VariantList items;
VarList::push_back(items, "0 ($FF5)");
VarList::push_back(items, "1 ($FF6)");
VarList::push_back(items, "2 ($FF7)");
VarList::push_back(items, "3 ($FF8)");
VarList::push_back(items, "4 ($FF9)");
VarList::push_back(items, "5 ($FFA)");
VarList::push_back(items, "6 ($FFB)");
VarList::push_back(items, "0 ($FFF5)");
VarList::push_back(items, "1 ($FFF6)");
VarList::push_back(items, "2 ($FFF7)");
VarList::push_back(items, "3 ($FFF8)");
VarList::push_back(items, "4 ($FFF9)");
VarList::push_back(items, "5 ($FFFA)");
VarList::push_back(items, "6 ($FFFB)");
myBank =
new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($FFx) "),
myLineHeight, items, "Set bank: ",
_font.getStringWidth("Set bank: "), kBankChanged);
myLineHeight, items, "Set bank ",
_font.getStringWidth("Set bank "), kBankChanged);
myBank->setTarget(this);
addFocusWidget(myBank);
int lwidth = _font.getStringWidth("Datastream Increments: "); // get width of the widest label
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();
}

View File

@ -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' };

View File

@ -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;

View File

@ -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;

View File

@ -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(...)
{

View File

@ -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

View File

@ -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

View File

@ -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);