mirror of https://github.com/stella-emu/stella.git
removed DASH type (incl. doc update)
This commit is contained in:
parent
a823fad32c
commit
9d12378cff
|
@ -30,7 +30,7 @@
|
|||
|
||||
* Restored 'cfg' directory for Distella config files.
|
||||
|
||||
* Removed unused CV+ bank switching type.
|
||||
* Removed unused CV+ and DASH bank switching types.
|
||||
|
||||
-Have fun!
|
||||
|
||||
|
|
|
@ -3781,7 +3781,7 @@ Ms Pac-Man (Stella extended codes):
|
|||
<tr><td>128IN1 ¹</td><td>256/512K Multicart </td><td>.128, .128N1 </td></tr>
|
||||
<tr><td>2K </td><td>32-2048 byte Atari </td><td>.2K </td></tr>
|
||||
<tr><td>3E </td><td>32K Tigervision </td><td>.3E </td></tr>
|
||||
<tr><td>3E+ </td><td>3E+ (TJ modified DASH) </td><td>.3EP, .3E+ </td></tr>
|
||||
<tr><td>3E+ </td><td>3E+ (TJ modified 3E) </td><td>.3EP, .3E+ </td></tr>
|
||||
<tr><td>3F </td><td>512K Tigervision </td><td>.3F </td></tr>
|
||||
<tr><td>4A50 ²</td><td>64K 4A50 + RAM </td><td>.4A5, .4A50 </td></tr>
|
||||
<tr><td>4K </td><td>4K Atari </td><td>.4K </td></tr>
|
||||
|
@ -3794,7 +3794,6 @@ Ms Pac-Man (Stella extended codes):
|
|||
<tr><td>CM ¹</td><td>Spectravideo CompuMate </td><td>.CM </td></tr>
|
||||
<tr><td>CTY ²</td><td>CDW - Chetiry </td><td>.CTY </td></tr>
|
||||
<tr><td>CV </td><td>CommaVid extra RAM </td><td>.CV </td></tr>
|
||||
<tr><td>DASH </td><td>Boulder Dash 2 </td><td>.DAS, .DASH </td></tr>
|
||||
<tr><td>DF </td><td>CPUWIZ 128K </td><td>.DF </td></tr>
|
||||
<tr><td>DFSC </td><td>CPUWIZ 128K + RAM</td><td>.DFS, .DFSC </td></tr>
|
||||
<tr><td>DPC </td><td>Pitfall II </td><td>.DPC </td></tr>
|
||||
|
|
|
@ -1,371 +0,0 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#include "CartDASH.hxx"
|
||||
#include "EditTextWidget.hxx"
|
||||
#include "PopUpWidget.hxx"
|
||||
#include "CartDASHWidget.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
CartridgeDASHWidget::CartridgeDASHWidget(
|
||||
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
|
||||
int x, int y, int w, int h, CartridgeDASH& cart)
|
||||
: CartDebugWidget(boss, lfont, nfont, x, y, w, h),
|
||||
myCart(cart)
|
||||
{
|
||||
size_t size = cart.mySize;
|
||||
|
||||
ostringstream info;
|
||||
info << "DASH cartridge - (64K ROM + RAM)\n"
|
||||
<< " 4-64K ROM (1K banks), 32K RAM (512b banks)\n"
|
||||
<< "Each 1K ROM selected by writing to $3F\n"
|
||||
"Each 512b RAM selected by writing to $3E\n"
|
||||
" First 512B of bank x (R)\n"
|
||||
" First 512B of bank x+4 (+$800) (W)\n"
|
||||
<< "Startup bank = 0/-1/-1/0 (ROM)\n";
|
||||
|
||||
// Eventually, we should query this from the debugger/disassembler
|
||||
uInt16 start = (cart.myImage[size-3] << 8) | cart.myImage[size-4];
|
||||
start -= start % 0x1000;
|
||||
info << "Bank RORG" << " = $" << Common::Base::HEX4 << start << "\n";
|
||||
|
||||
int xpos = 2,
|
||||
ypos = addBaseInformation(size, "A. Davie & T. Jentzsch", info.str()) +
|
||||
myLineHeight;
|
||||
|
||||
VariantList bankno;
|
||||
for(uInt32 i = 0; i < myCart.ROM_BANK_COUNT; ++i)
|
||||
VarList::push_back(bankno, i, i);
|
||||
|
||||
VariantList banktype;
|
||||
VarList::push_back(banktype, "ROM", "ROM");
|
||||
VarList::push_back(banktype, "RAM", "RAM");
|
||||
|
||||
for(uInt32 i = 0; i < 4; ++i)
|
||||
{
|
||||
int xpos_s, ypos_s = ypos;
|
||||
|
||||
ostringstream label;
|
||||
label << "Set segment " << i << " as: ";
|
||||
|
||||
new StaticTextWidget(boss, _font, xpos, ypos, _font.getStringWidth(label.str()),
|
||||
myFontHeight, label.str(), TextAlign::Left);
|
||||
ypos += myLineHeight + 8;
|
||||
|
||||
xpos += 20;
|
||||
myBankNumber[i] =
|
||||
new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("Slot "),
|
||||
myLineHeight, bankno, "Slot ",
|
||||
6*_font.getMaxCharWidth());
|
||||
addFocusWidget(myBankNumber[i]);
|
||||
|
||||
xpos += myBankNumber[i]->getWidth();
|
||||
myBankType[i] =
|
||||
new PopUpWidget(boss, _font, xpos, ypos-2, 5*_font.getMaxCharWidth(),
|
||||
myLineHeight, banktype, " of ", _font.getStringWidth(" of "));
|
||||
addFocusWidget(myBankType[i]);
|
||||
|
||||
xpos += myBankType[i]->getWidth() + 10;
|
||||
|
||||
myBankCommit[i] = new ButtonWidget(boss, _font, xpos, ypos-4,
|
||||
_font.getStringWidth(" Commit "), myButtonHeight,
|
||||
"Commit", bankEnum[i]);
|
||||
myBankCommit[i]->setTarget(this);
|
||||
addFocusWidget(myBankCommit[i]);
|
||||
|
||||
xpos_s = xpos + myBankCommit[i]->getWidth() + 20;
|
||||
|
||||
StaticTextWidget* t;
|
||||
int addr1 = start + (i*0x400), addr2 = addr1 + 0x1FF;
|
||||
|
||||
label.str("");
|
||||
label << Common::Base::HEX4 << addr1 << "-" << Common::Base::HEX4 << addr2;
|
||||
t = new StaticTextWidget(boss, _font, xpos_s, ypos_s+2,
|
||||
_font.getStringWidth(label.str()), myFontHeight, label.str(), TextAlign::Left);
|
||||
|
||||
int xoffset = xpos_s+t->getWidth() + 10;
|
||||
myBankState[2*i] = new EditTextWidget(boss, _font, xoffset, ypos_s,
|
||||
w - xoffset - 10, myLineHeight, "");
|
||||
myBankState[2*i]->setEditable(false, true);
|
||||
ypos_s += myLineHeight + 4;
|
||||
|
||||
label.str("");
|
||||
label << Common::Base::HEX4 << (addr2 + 1) << "-" << Common::Base::HEX4 << (addr2 + 1 + 0x1FF);
|
||||
new StaticTextWidget(boss, _font, xpos_s, ypos_s+2,
|
||||
_font.getStringWidth(label.str()), myFontHeight, label.str(), TextAlign::Left);
|
||||
|
||||
myBankState[2*i+1] = new EditTextWidget(boss, _font, xoffset, ypos_s,
|
||||
w - xoffset - 10, myLineHeight, "");
|
||||
myBankState[2*i+1]->setEditable(false, true);
|
||||
|
||||
xpos = 10;
|
||||
ypos+= 2 * myLineHeight;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeDASHWidget::saveOldState()
|
||||
{
|
||||
myOldState.internalram.clear();
|
||||
|
||||
for(uInt32 i = 0; i < internalRamSize(); ++i)
|
||||
myOldState.internalram.push_back(myCart.myRAM[i]);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeDASHWidget::loadConfig()
|
||||
{
|
||||
updateUIState();
|
||||
CartDebugWidget::loadConfig();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeDASHWidget::handleCommand(CommandSender* sender,
|
||||
int cmd, int data, int id)
|
||||
{
|
||||
uInt16 segment = 0;
|
||||
switch(cmd)
|
||||
{
|
||||
case kBank0Changed:
|
||||
segment = 0;
|
||||
break;
|
||||
case kBank1Changed:
|
||||
segment = 1;
|
||||
break;
|
||||
case kBank2Changed:
|
||||
segment = 2;
|
||||
break;
|
||||
case kBank3Changed:
|
||||
segment = 3;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Ignore bank if either number or type hasn't been selected
|
||||
if(myBankNumber[segment]->getSelected() < 0 ||
|
||||
myBankType[segment]->getSelected() < 0)
|
||||
return;
|
||||
|
||||
uInt8 bank = (segment << myCart.BANK_BITS) |
|
||||
(myBankNumber[segment]->getSelected() & myCart.BIT_BANK_MASK);
|
||||
|
||||
myCart.unlockBank();
|
||||
|
||||
if(myBankType[segment]->getSelectedTag() == "ROM")
|
||||
myCart.bankROM(bank);
|
||||
else
|
||||
myCart.bankRAM(bank);
|
||||
|
||||
myCart.lockBank();
|
||||
invalidate();
|
||||
updateUIState();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string CartridgeDASHWidget::bankState()
|
||||
{
|
||||
ostringstream& buf = buffer();
|
||||
int lastROMBank = -1;
|
||||
bool lastSlotRAM = false;
|
||||
|
||||
for(int i = 0; i < 8; ++i)
|
||||
{
|
||||
uInt16 bank = myCart.bankInUse[i];
|
||||
|
||||
if(bank == myCart.BANK_UNDEFINED) // never accessed
|
||||
{
|
||||
buf << " U!";
|
||||
}
|
||||
else
|
||||
{
|
||||
int bankno = bank & myCart.BIT_BANK_MASK;
|
||||
|
||||
if(bank & myCart.BITMASK_ROMRAM) // was RAM mapped here?
|
||||
{
|
||||
// RAM will always need a '+' placed somewhere, since it always
|
||||
// consists of 512B segments
|
||||
bool inFirstSlot = (i % 2 == 0);
|
||||
if(!(inFirstSlot || lastSlotRAM))
|
||||
{
|
||||
lastSlotRAM = false;
|
||||
buf << " +";
|
||||
}
|
||||
|
||||
if(bank & myCart.BITMASK_LOWERUPPER) // upper is write port
|
||||
buf << " RAM " << bankno << "W";
|
||||
else
|
||||
buf << " RAM " << bankno << "R";
|
||||
|
||||
if(inFirstSlot)
|
||||
{
|
||||
buf << " +";
|
||||
lastSlotRAM = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// ROM can be contiguous, since 2 512B segments can form a single
|
||||
// 1K bank; in this case we only show the info once
|
||||
bool highBankSame = (i % 2 == 1) && (bankno == lastROMBank);
|
||||
if(!highBankSame)
|
||||
{
|
||||
buf << " ROM " << bankno;
|
||||
lastROMBank = bankno;
|
||||
}
|
||||
else
|
||||
lastROMBank = -1;
|
||||
|
||||
lastSlotRAM = false;
|
||||
}
|
||||
}
|
||||
|
||||
if((i+1) % 2 == 0 && i < 7)
|
||||
buf << " /";
|
||||
}
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeDASHWidget::updateUIState()
|
||||
{
|
||||
// Set contents for actual banks number and type
|
||||
for(int i = 0; i < 4; ++i)
|
||||
{
|
||||
uInt16 segment = myCart.segmentInUse[i];
|
||||
|
||||
if(segment == myCart.BANK_UNDEFINED)
|
||||
{
|
||||
myBankNumber[i]->clearSelection();
|
||||
myBankType[i]->clearSelection();
|
||||
}
|
||||
else
|
||||
{
|
||||
int bankno = segment & myCart.BIT_BANK_MASK;
|
||||
const string& banktype = (segment & myCart.BITMASK_ROMRAM) ? "RAM" : "ROM";
|
||||
|
||||
myBankNumber[i]->setSelected(bankno);
|
||||
myBankType[i]->setSelected(banktype);
|
||||
}
|
||||
}
|
||||
|
||||
// Set description for each 512b bank state
|
||||
for(int i = 0; i < 8; ++i)
|
||||
{
|
||||
uInt16 bank = myCart.bankInUse[i];
|
||||
|
||||
if(bank == myCart.BANK_UNDEFINED) // never accessed
|
||||
{
|
||||
myBankState[i]->setText("Undefined");
|
||||
}
|
||||
else
|
||||
{
|
||||
ostringstream buf;
|
||||
int bankno = bank & myCart.BIT_BANK_MASK;
|
||||
|
||||
if(bank & myCart.BITMASK_ROMRAM) // was RAM mapped here?
|
||||
{
|
||||
if(bank & myCart.BITMASK_LOWERUPPER) // upper is write port
|
||||
{
|
||||
buf << "RAM " << bankno << " @ $" << Common::Base::HEX4
|
||||
<< (bankno << myCart.RAM_BANK_TO_POWER) << " (W)";
|
||||
myBankState[i]->setText(buf.str());
|
||||
}
|
||||
else
|
||||
{
|
||||
buf << "RAM " << bankno << " @ $" << Common::Base::HEX4
|
||||
<< (bankno << myCart.RAM_BANK_TO_POWER) << " (R)";
|
||||
myBankState[i]->setText(buf.str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(bank & myCart.BITMASK_LOWERUPPER) // upper is high 512b
|
||||
{
|
||||
buf << "ROM " << bankno << " @ $" << Common::Base::HEX4
|
||||
<< ((bankno << myCart.RAM_BANK_TO_POWER) + myCart.RAM_BANK_SIZE);
|
||||
myBankState[i]->setText(buf.str());
|
||||
}
|
||||
else
|
||||
{
|
||||
buf << "ROM " << bankno << " @ $" << Common::Base::HEX4
|
||||
<< (bankno << myCart.RAM_BANK_TO_POWER);
|
||||
myBankState[i]->setText(buf.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 CartridgeDASHWidget::internalRamSize()
|
||||
{
|
||||
return 32*1024;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 CartridgeDASHWidget::internalRamRPort(int start)
|
||||
{
|
||||
return 0x0000 + start;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string CartridgeDASHWidget::internalRamDescription()
|
||||
{
|
||||
ostringstream desc;
|
||||
desc << "Accessible 512b at a time via:\n"
|
||||
<< " $F000/$F200/$F400/etc used for Read Access\n"
|
||||
<< " $F800/$FA00/$FC00/etc used for Write Access (+$800)";
|
||||
|
||||
return desc.str();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const ByteArray& CartridgeDASHWidget::internalRamOld(int start, int count)
|
||||
{
|
||||
myRamOld.clear();
|
||||
for(int i = 0; i < count; i++)
|
||||
myRamOld.push_back(myOldState.internalram[start + i]);
|
||||
return myRamOld;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const ByteArray& CartridgeDASHWidget::internalRamCurrent(int start, int count)
|
||||
{
|
||||
myRamCurrent.clear();
|
||||
for(int i = 0; i < count; i++)
|
||||
myRamCurrent.push_back(myCart.myRAM[start + i]);
|
||||
return myRamCurrent;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeDASHWidget::internalRamSetValue(int addr, uInt8 value)
|
||||
{
|
||||
myCart.myRAM[addr] = value;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt8 CartridgeDASHWidget::internalRamGetValue(int addr)
|
||||
{
|
||||
return myCart.myRAM[addr];
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const std::array<CartridgeDASHWidget::BankID, 4> CartridgeDASHWidget::bankEnum = {
|
||||
kBank0Changed, kBank1Changed, kBank2Changed, kBank3Changed
|
||||
};
|
|
@ -1,86 +0,0 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#ifndef CARTRIDGEDASH_WIDGET_HXX
|
||||
#define CARTRIDGEDASH_WIDGET_HXX
|
||||
|
||||
class CartridgeDASH;
|
||||
class ButtonWidget;
|
||||
class EditTextWidget;
|
||||
class PopUpWidget;
|
||||
|
||||
#include "CartDebugWidget.hxx"
|
||||
|
||||
class CartridgeDASHWidget : public CartDebugWidget
|
||||
{
|
||||
public:
|
||||
CartridgeDASHWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||
const GUI::Font& nfont,
|
||||
int x, int y, int w, int h,
|
||||
CartridgeDASH& cart);
|
||||
virtual ~CartridgeDASHWidget() = default;
|
||||
|
||||
private:
|
||||
void updateUIState();
|
||||
|
||||
private:
|
||||
CartridgeDASH& myCart;
|
||||
|
||||
std::array<PopUpWidget*, 4> myBankNumber{nullptr};
|
||||
std::array<PopUpWidget*, 4> myBankType{nullptr};
|
||||
std::array<ButtonWidget*, 4> myBankCommit{nullptr};
|
||||
std::array<EditTextWidget*, 8> myBankState{nullptr};
|
||||
|
||||
struct CartState {
|
||||
ByteArray internalram;
|
||||
};
|
||||
CartState myOldState;
|
||||
|
||||
enum BankID {
|
||||
kBank0Changed = 'b0CH',
|
||||
kBank1Changed = 'b1CH',
|
||||
kBank2Changed = 'b2CH',
|
||||
kBank3Changed = 'b3CH'
|
||||
};
|
||||
static const std::array<BankID, 4> bankEnum;
|
||||
|
||||
private:
|
||||
void saveOldState() override;
|
||||
void loadConfig() override;
|
||||
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
|
||||
|
||||
string bankState() override;
|
||||
|
||||
// start of functions for Cartridge RAM tab
|
||||
uInt32 internalRamSize() override;
|
||||
uInt32 internalRamRPort(int start) override;
|
||||
string internalRamDescription() override;
|
||||
const ByteArray& internalRamOld(int start, int count) override;
|
||||
const ByteArray& internalRamCurrent(int start, int count) override;
|
||||
void internalRamSetValue(int addr, uInt8 value) override;
|
||||
uInt8 internalRamGetValue(int addr) override;
|
||||
// end of functions for Cartridge RAM tab
|
||||
|
||||
// Following constructors and assignment operators not supported
|
||||
CartridgeDASHWidget() = delete;
|
||||
CartridgeDASHWidget(const CartridgeDASHWidget&) = delete;
|
||||
CartridgeDASHWidget(CartridgeDASHWidget&&) = delete;
|
||||
CartridgeDASHWidget& operator=(const CartridgeDASHWidget&) = delete;
|
||||
CartridgeDASHWidget& operator=(CartridgeDASHWidget&&) = delete;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -23,7 +23,6 @@ MODULE_OBJS := \
|
|||
src/debugger/gui/CartCMWidget.o \
|
||||
src/debugger/gui/CartCTYWidget.o \
|
||||
src/debugger/gui/CartCVWidget.o \
|
||||
src/debugger/gui/CartDASHWidget.o \
|
||||
src/debugger/gui/CartDFSCWidget.o \
|
||||
src/debugger/gui/CartDFWidget.o \
|
||||
src/debugger/gui/CartDPCPlusWidget.o \
|
||||
|
|
|
@ -118,7 +118,6 @@ Bankswitch::BSList = {{
|
|||
{ "CM" , "CM (SpectraVideo CompuMate)" },
|
||||
{ "CTY" , "CTY (CDW - Chetiry)" },
|
||||
{ "CV" , "CV (Commavid extra RAM)" },
|
||||
{ "DASH" , "DASH (Experimental)" },
|
||||
{ "DF" , "DF (CPUWIZ 128K)" },
|
||||
{ "DFSC" , "DFSC (CPUWIZ 128K + RAM)" },
|
||||
{ "DPC" , "DPC (Pitfall II)" },
|
||||
|
@ -196,8 +195,6 @@ Bankswitch::ExtensionMap Bankswitch::ourExtensions = {
|
|||
{ "CM" , Bankswitch::Type::_CM },
|
||||
{ "CTY" , Bankswitch::Type::_CTY },
|
||||
{ "CV" , Bankswitch::Type::_CV },
|
||||
{ "DAS" , Bankswitch::Type::_DASH },
|
||||
{ "DASH" , Bankswitch::Type::_DASH },
|
||||
{ "DF" , Bankswitch::Type::_DF },
|
||||
{ "DFS" , Bankswitch::Type::_DFSC },
|
||||
{ "DFSC" , Bankswitch::Type::_DFSC },
|
||||
|
@ -260,7 +257,6 @@ Bankswitch::NameToTypeMap Bankswitch::ourNameToTypes = {
|
|||
{ "CM" , Bankswitch::Type::_CM },
|
||||
{ "CTY" , Bankswitch::Type::_CTY },
|
||||
{ "CV" , Bankswitch::Type::_CV },
|
||||
{ "DASH" , Bankswitch::Type::_DASH },
|
||||
{ "DF" , Bankswitch::Type::_DF },
|
||||
{ "DFSC" , Bankswitch::Type::_DFSC },
|
||||
{ "DPC" , Bankswitch::Type::_DPC },
|
||||
|
|
|
@ -41,11 +41,11 @@ class Bankswitch
|
|||
_AUTO, _0840, _2IN1, _4IN1, _8IN1, _16IN1, _32IN1,
|
||||
_64IN1, _128IN1, _2K, _3E, _3EP, _3F, _4A50,
|
||||
_4K, _4KSC, _AR, _BF, _BFSC, _BUS, _CDF,
|
||||
_CM, _CTY, _CV, _DASH, _DF, _DFSC, _DPC,
|
||||
_DPCP, _E0, _E7, _E78K, _EF, _EFSC, _F0,
|
||||
_F4, _F4SC, _F6, _F6SC, _F8, _F8SC, _FA,
|
||||
_FA2, _FC, _FE, _MDM, _SB, _UA, _UASW,
|
||||
_WD, _WDSW, _X07,
|
||||
_CM, _CTY, _CV, _DF, _DFSC, _DPC, _DPCP,
|
||||
_E0, _E7, _E78K, _EF, _EFSC, _F0, _F4,
|
||||
_F4SC, _F6, _F6SC, _F8, _F8SC, _FA, _FA2,
|
||||
_FC, _FE, _MDM, _SB, _UA, _UASW, _WD,
|
||||
_WDSW, _X07,
|
||||
#ifdef CUSTOM_ARM
|
||||
_CUSTOM,
|
||||
#endif
|
||||
|
|
|
@ -1,355 +0,0 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#include "System.hxx"
|
||||
#include "TIA.hxx"
|
||||
#include "CartDASH.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
CartridgeDASH::CartridgeDASH(const ByteBuffer& image, size_t size,
|
||||
const string& md5, const Settings& settings)
|
||||
: Cartridge(settings, md5),
|
||||
mySize(size)
|
||||
{
|
||||
// Allocate array for the ROM image
|
||||
myImage = make_unique<uInt8[]>(mySize);
|
||||
|
||||
// Copy the ROM image into my buffer
|
||||
std::copy_n(image.get(), mySize, myImage.get());
|
||||
createRomAccessArrays(mySize + myRAM.size());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeDASH::reset()
|
||||
{
|
||||
initializeRAM(myRAM.data(), myRAM.size());
|
||||
|
||||
// Remember startup bank (0 per spec, rather than last per 3E scheme).
|
||||
// Set this to go to 3rd 1K Bank.
|
||||
initializeStartBank(0);
|
||||
|
||||
// Initialise bank values for all ROM/RAM access
|
||||
// This is used to reverse-lookup from address to bank location
|
||||
for(uInt32 b = 0; b < 8; ++b)
|
||||
{
|
||||
bankInUse[b] = BANK_UNDEFINED; // bank is undefined and inaccessible!
|
||||
segmentInUse[b/2] = BANK_UNDEFINED;
|
||||
}
|
||||
initializeBankState();
|
||||
|
||||
// We'll map the startup banks 0 and 3 from the image into the third 1K bank upon reset
|
||||
bankROM((0 << BANK_BITS) | 0);
|
||||
bankROM((3 << BANK_BITS) | 0);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeDASH::install(System& system)
|
||||
{
|
||||
mySystem = &system;
|
||||
|
||||
System::PageAccess access(this, System::PageAccessType::READWRITE);
|
||||
|
||||
// The hotspots are in TIA address space, so we claim it here
|
||||
for (uInt16 addr = 0x00; addr < 0x40; addr += System::PAGE_SIZE)
|
||||
mySystem->setPageAccess(addr, access);
|
||||
|
||||
// Initialise bank values for all ROM/RAM access
|
||||
// This is used to reverse-lookup from address to bank location
|
||||
for (uInt32 b = 0; b < 8; ++b)
|
||||
{
|
||||
bankInUse[b] = BANK_UNDEFINED; // bank is undefined and inaccessible!
|
||||
segmentInUse[b/2] = BANK_UNDEFINED;
|
||||
}
|
||||
initializeBankState();
|
||||
|
||||
// Setup the last segment (of 4, each 1K) to point to the first ROM slice
|
||||
// Actually we DO NOT want "always". It's just on bootup, and can be out switched later
|
||||
bankROM((0 << BANK_BITS) | 0);
|
||||
bankROM((3 << BANK_BITS) | 0);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt8 CartridgeDASH::peek(uInt16 address)
|
||||
{
|
||||
uInt16 peekAddress = address;
|
||||
address &= 0x0FFF; // restrict to 4K address range
|
||||
|
||||
uInt8 value = 0;
|
||||
uInt32 bank = (address >> (ROM_BANK_TO_POWER - 1)) & 7; // convert to 512 byte bank index (0-7)
|
||||
uInt16 imageBank = bankInUse[bank]; // the ROM/RAM bank that's here
|
||||
|
||||
if(imageBank == BANK_UNDEFINED) // an uninitialised bank?
|
||||
{
|
||||
// accessing invalid bank, so return should be... random?
|
||||
value = mySystem->randGenerator().next();
|
||||
|
||||
}
|
||||
else if(imageBank & BITMASK_ROMRAM) // a RAM bank
|
||||
{
|
||||
Int32 ramBank = imageBank & BIT_BANK_MASK; // discard irrelevant bits
|
||||
Int32 offset = ramBank << RAM_BANK_TO_POWER; // base bank address in RAM
|
||||
offset += (address & BITMASK_RAM_BANK); // + byte offset in RAM bank
|
||||
|
||||
return peekRAM(myRAM[offset], peekAddress);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeDASH::poke(uInt16 address, uInt8 value)
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
// Check for write to the bank switch address. RAM/ROM and bank # are encoded in 'value'
|
||||
// There are NO mirrored hotspots.
|
||||
|
||||
if (address == BANK_SWITCH_HOTSPOT_RAM)
|
||||
changed = bankRAM(value);
|
||||
else if (address == BANK_SWITCH_HOTSPOT_ROM)
|
||||
changed = bankROM(value);
|
||||
|
||||
if(!(address & 0x1000))
|
||||
{
|
||||
// Handle TIA space that we claimed above
|
||||
changed = changed || mySystem->tia().poke(address, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
uInt32 bankNumber = (address >> RAM_BANK_TO_POWER) & 7; // now 512 byte bank # (ie: 0-7)
|
||||
Int16 whichBankIsThere = bankInUse[bankNumber]; // ROM or RAM bank reference
|
||||
|
||||
if(whichBankIsThere & BITMASK_ROMRAM)
|
||||
{
|
||||
if(address & RAM_BANK_SIZE)
|
||||
{
|
||||
uInt32 byteOffset = address & BITMASK_RAM_BANK;
|
||||
uInt32 baseAddress = ((whichBankIsThere & BIT_BANK_MASK) << RAM_BANK_TO_POWER) + byteOffset;
|
||||
pokeRAM(myRAM[baseAddress], address, value);
|
||||
changed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Writing to the read port should be ignored, but trigger a break if option enabled
|
||||
uInt8 dummy;
|
||||
|
||||
pokeRAM(dummy, address, value);
|
||||
myRamWriteAccess = address;
|
||||
changed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeDASH::bankRAM(uInt8 bank)
|
||||
{
|
||||
if (bankLocked()) // debugger can lock RAM
|
||||
return false;
|
||||
|
||||
// Each RAM bank uses two slots, separated by 0x800 in memory -- one read, one write.
|
||||
bankRAMSlot(bank | BITMASK_ROMRAM | 0);
|
||||
bankRAMSlot(bank | BITMASK_ROMRAM | BITMASK_LOWERUPPER);
|
||||
|
||||
// Remember that this hotspot was accessed for RAM
|
||||
segmentInUse[(bank >> BANK_BITS) & 3] = bank | BITMASK_ROMRAM;
|
||||
|
||||
return myBankChanged = true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeDASH::bankRAMSlot(uInt16 bank)
|
||||
{
|
||||
uInt16 bankNumber = (bank >> BANK_BITS) & 3; // which bank # we are switching TO (BITS D6,D7) to 512 byte block
|
||||
uInt16 currentBank = bank & BIT_BANK_MASK; // Wrap around/restrict to valid range
|
||||
bool upper = bank & BITMASK_LOWERUPPER; // is this the read or write port
|
||||
|
||||
uInt32 startCurrentBank = currentBank << RAM_BANK_TO_POWER; // Effectively * 512 bytes
|
||||
|
||||
// Setup the page access methods for the current bank
|
||||
System::PageAccess access(this, System::PageAccessType::READ);
|
||||
|
||||
if(upper) // We're mapping the write port
|
||||
{
|
||||
bankInUse[bankNumber + 4] = Int16(bank);
|
||||
access.type = System::PageAccessType::WRITE;
|
||||
}
|
||||
else // We're mapping the read port
|
||||
{
|
||||
bankInUse[bankNumber] = Int16(bank);
|
||||
access.type = System::PageAccessType::READ;
|
||||
}
|
||||
|
||||
uInt16 start = 0x1000 + (bankNumber << RAM_BANK_TO_POWER) + (upper ? RAM_WRITE_OFFSET : 0);
|
||||
uInt16 end = start + RAM_BANK_SIZE - 1;
|
||||
|
||||
for (uInt16 addr = start; addr <= end; addr += System::PAGE_SIZE)
|
||||
{
|
||||
if(!upper)
|
||||
access.directPeekBase = &myRAM[startCurrentBank + (addr & (RAM_BANK_SIZE - 1))];
|
||||
|
||||
access.romAccessBase = &myRomAccessBase[mySize + startCurrentBank + (addr & (RAM_BANK_SIZE - 1))];
|
||||
mySystem->setPageAccess(addr, access);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeDASH::bankROM(uInt8 bank)
|
||||
{
|
||||
if (bankLocked()) // debugger can lock ROM
|
||||
return false;
|
||||
|
||||
// Map ROM bank image into the system into the correct slot
|
||||
// Memory map is 1K slots at 0x1000, 0x1400, 0x1800, 0x1C00
|
||||
// Each ROM uses 2 consecutive 512 byte slots
|
||||
bankROMSlot(bank | 0);
|
||||
bankROMSlot(bank | BITMASK_LOWERUPPER);
|
||||
|
||||
// Remember that this hotspot was accessed for ROM
|
||||
segmentInUse[(bank >> BANK_BITS) & 3] = bank;
|
||||
|
||||
return myBankChanged = true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeDASH::bankROMSlot(uInt16 bank)
|
||||
{
|
||||
uInt16 bankNumber = (bank >> BANK_BITS) & 3; // which bank # we are switching TO (BITS D6,D7)
|
||||
uInt16 currentBank = bank & BIT_BANK_MASK; // Wrap around/restrict to valid range
|
||||
bool upper = bank & BITMASK_LOWERUPPER; // is this the lower or upper 512b
|
||||
|
||||
bankInUse[bankNumber * 2 + (upper ? 1 : 0)] = Int16(bank); // Record which bank switched in (as ROM)
|
||||
|
||||
uInt32 startCurrentBank = currentBank << ROM_BANK_TO_POWER; // Effectively *1K
|
||||
|
||||
// Setup the page access methods for the current bank
|
||||
System::PageAccess access(this, System::PageAccessType::READ);
|
||||
|
||||
uInt16 start = 0x1000 + (bankNumber << ROM_BANK_TO_POWER) + (upper ? ROM_BANK_SIZE / 2 : 0);
|
||||
uInt16 end = start + ROM_BANK_SIZE / 2 - 1;
|
||||
|
||||
for (uInt16 addr = start; addr <= end; addr += System::PAGE_SIZE)
|
||||
{
|
||||
access.directPeekBase = &myImage[startCurrentBank + (addr & (ROM_BANK_SIZE - 1))];
|
||||
access.romAccessBase = &myRomAccessBase[startCurrentBank + (addr & (ROM_BANK_SIZE - 1))];
|
||||
mySystem->setPageAccess(addr, access);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeDASH::initializeBankState()
|
||||
{
|
||||
// Switch in each 512b slot
|
||||
for(uInt32 b = 0; b < 8; ++b)
|
||||
{
|
||||
if(bankInUse[b] == BANK_UNDEFINED)
|
||||
{
|
||||
// All accesses point to peek/poke above
|
||||
System::PageAccess access(this, System::PageAccessType::READ);
|
||||
uInt16 start = 0x1000 + (b << RAM_BANK_TO_POWER);
|
||||
uInt16 end = start + RAM_BANK_SIZE - 1;
|
||||
for (uInt16 addr = start; addr <= end; addr += System::PAGE_SIZE)
|
||||
mySystem->setPageAccess(addr, access);
|
||||
}
|
||||
else if (bankInUse[b] & BITMASK_ROMRAM)
|
||||
bankRAMSlot(bankInUse[b]);
|
||||
else
|
||||
bankROMSlot(bankInUse[b]);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeDASH::patch(uInt16 address, uInt8 value)
|
||||
{
|
||||
#if 0
|
||||
// Patch the cartridge ROM (for debugger)
|
||||
|
||||
myBankChanged = true;
|
||||
|
||||
uInt32 bankNumber = (address >> RAM_BANK_TO_POWER) & 7; // now 512 byte bank # (ie: 0-7)
|
||||
Int16 whichBankIsThere = bankInUse[bankNumber]; // ROM or RAM bank reference
|
||||
|
||||
if (whichBankIsThere == BANK_UNDEFINED) {
|
||||
|
||||
// We're trying to access undefined memory (no bank here yet). Fail!
|
||||
myBankChanged = false;
|
||||
|
||||
} else if (whichBankIsThere & BITMASK_ROMRAM) { // patching RAM (512 byte banks)
|
||||
|
||||
uInt32 byteOffset = address & BITMASK_RAM_BANK;
|
||||
uInt32 baseAddress = ((whichBankIsThere & BIT_BANK_MASK) << RAM_BANK_TO_POWER) + byteOffset;
|
||||
myRAM[baseAddress] = value; // write to RAM
|
||||
|
||||
// TODO: Stephen -- should we set 'myBankChanged' true when there's a RAM write?
|
||||
|
||||
} else { // patching ROM (1K banks)
|
||||
|
||||
uInt32 byteOffset = address & BITMASK_ROM_BANK;
|
||||
uInt32 baseAddress = (whichBankIsThere << ROM_BANK_TO_POWER) + byteOffset;
|
||||
myImage[baseAddress] = value; // write to the image
|
||||
}
|
||||
|
||||
return myBankChanged;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const uInt8* CartridgeDASH::getImage(size_t& size) const
|
||||
{
|
||||
size = mySize;
|
||||
return myImage.get();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeDASH::save(Serializer& out) const
|
||||
{
|
||||
try
|
||||
{
|
||||
out.putShortArray(bankInUse.data(), bankInUse.size());
|
||||
out.putShortArray(segmentInUse.data(), segmentInUse.size());
|
||||
out.putByteArray(myRAM.data(), myRAM.size());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
cerr << "ERROR: CartridgeDASH::save" << endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeDASH::load(Serializer& in)
|
||||
{
|
||||
try
|
||||
{
|
||||
in.getShortArray(bankInUse.data(), bankInUse.size());
|
||||
in.getShortArray(segmentInUse.data(), segmentInUse.size());
|
||||
in.getByteArray(myRAM.data(), myRAM.size());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
cerr << "ERROR: CartridgeDASH::load" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
initializeBankState();
|
||||
return true;
|
||||
}
|
|
@ -1,277 +0,0 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#ifndef CARTRIDGEDASH_HXX
|
||||
#define CARTRIDGEDASH_HXX
|
||||
|
||||
class System;
|
||||
|
||||
#include "bspf.hxx"
|
||||
#include "Cart.hxx"
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
class CartridgeDASHWidget;
|
||||
#include "CartDASHWidget.hxx"
|
||||
#endif
|
||||
|
||||
/**
|
||||
Cartridge class for new tiling engine "Boulder Dash" format games with RAM.
|
||||
Kind of a combination of 3F and 3E, with better switchability.
|
||||
B.Watson's Cart3E was used as a template for building this implementation.
|
||||
|
||||
The destination bank (0-3) is held in the top bits of the value written to
|
||||
$3E (for RAM switching) or $3F (for ROM switching). The low 6 bits give
|
||||
the actual bank number (0-63) corresponding to 512 byte blocks for RAM and
|
||||
1024 byte blocks for ROM. The maximum size is therefore 32K RAM and 64K ROM.
|
||||
|
||||
D7D6 indicate the bank number (0-3)
|
||||
D5D4D3D2D1D0 indicate the actual # (0-63) from the image/ram
|
||||
|
||||
ROM:
|
||||
|
||||
Note: in descriptions $F000 is equivalent to $1000 -- that is, we only deal
|
||||
with the low 13 bits of addressing. Stella code uses $1000, I'm used to $F000
|
||||
So, mask with top bits clear :) when reading this document.
|
||||
|
||||
In this scheme, the 4K address space is broken into four 1K ROM segments.
|
||||
living at 0x1000, 0x1400, 0x1800, 0x1C00 (or, same thing, 0xF000... etc.),
|
||||
and four 512 byte RAM segments, living at 0x1000, 0x1200, 0x1400, 0x1600
|
||||
with write-mirrors +0x800 of these. The last 1K ROM ($FC00-$FFFF) segment
|
||||
in the 6502 address space (ie: $1C00-$1FFF) is initialised to point to the
|
||||
FIRST 1K of the ROM image, so the reset vectors must be placed at the
|
||||
end of the first 1K in the ROM image. Note, this is DIFFERENT to 3E which
|
||||
switches in the UPPER bank and this bank is fixed. This allows variable sized
|
||||
ROM without having to detect size. First bank (0) in ROM is the default fixed
|
||||
bank mapped to $FC00.
|
||||
|
||||
The system requires the reset vectors to be valid on a reset, so either the
|
||||
hardware first switches in the first bank, or the programmer must ensure
|
||||
that the reset vector is present in ALL ROM banks which might be switched
|
||||
into the last bank area. Currently the latter (programmer onus) is required,
|
||||
but it would be nice for the cartridge hardware to auto-switch on reset.
|
||||
|
||||
ROM switching (write of block+bank number to $3F) D7D6 upper 2 bits of bank #
|
||||
indicates the destination segment (0-3, corresponding to $F000, $F400, $F800,
|
||||
$FC00), and lower 6 bits indicate the 1K bank to switch in. Can handle 64
|
||||
x 1K ROM banks (64K total).
|
||||
|
||||
D7 D6 D5D4D3D2D1D0
|
||||
0 0 x x x x x x switch a 1K ROM bank xxxxx to $F000
|
||||
0 1 switch a 1K ROM bank xxxxx to $F400
|
||||
1 0 switch a 1K ROM bank xxxxx to $F800
|
||||
1 1 switch a 1K ROM bank xxxxx to $FC00
|
||||
|
||||
RAM switching (write of segment+bank number to $3E) with D7D6 upper 2 bits of
|
||||
bank # indicates the destination RAM segment (0-3, corresponding to $F000,
|
||||
$F200, $F400, $F600). Note that this allows contiguous 2K of RAM to be
|
||||
configured by setting 4 consecutive RAM segments each 512 bytes with
|
||||
consecutive addresses. However, as the write address of RAM is +0x800, this
|
||||
invalidates ROM access as described below.
|
||||
|
||||
can handle 64 x 512 byte RAM banks (32K total)
|
||||
|
||||
D7 D6 D5D4D3D2D1D0
|
||||
0 0 x x x x x x switch a 512 byte RAM bank xxxxx to $F000 with write @ $F800
|
||||
0 1 switch a 512 byte RAM bank xxxxx to $F200 with write @ $FA00
|
||||
1 0 switch a 512 byte RAM bank xxxxx to $F400 with write @ $FC00
|
||||
1 1 switch a 512 byte RAM bank xxxxx to $F600 with write @ $FE00
|
||||
|
||||
It is possible to switch multiple RAM banks and ROM banks together
|
||||
|
||||
For example,
|
||||
F000-F1FF RAM bank A (512 byte READ)
|
||||
F200-F3FF high 512 bytes of ROM bank previously loaded at F000
|
||||
F400 ROM bank 0 (1K)
|
||||
F800 RAM bank A (512 byte WRITE)
|
||||
FA00-FBFF high 512 bytes of ROM bank previously loaded at F400
|
||||
FC00 ROM bank 1
|
||||
|
||||
This example shows 512 bytes of RAM, and 2 1K ROM banks and two 512 byte ROM
|
||||
bank halves.
|
||||
|
||||
Switching RAM blocks (D7D6 of $3E) partially invalidates ROM blocks, as below...
|
||||
|
||||
RAM block Invalidates ROM block
|
||||
0 0 (lower half), 2 (lower half)
|
||||
1 0 (upper half), 2 (upper half)
|
||||
2 1 (lower half), 3 (upper half)
|
||||
3 1 (upper half), 3 (lower half)
|
||||
|
||||
For example, RAM block 1 uses address $F200-$F3FF and $FA00-$FBFF
|
||||
ROM block 0 uses address $F000-$F3FF, and ROM block 2 uses address $F800-$FBFF
|
||||
Switching in RAM block 1 makes F200-F3FF ROM inaccessible, however F000-F1FF is
|
||||
still readable. So, care must be paid.
|
||||
|
||||
This crazy RAM layout is useful as it allows contiguous RAM to be switched in,
|
||||
up to 2K in one sequentially accessible block. This means you CAN have 2K of
|
||||
consecutive RAM (don't forget to copy your reset vectors!)
|
||||
|
||||
@author Andrew Davie
|
||||
*/
|
||||
|
||||
class CartridgeDASH: public Cartridge
|
||||
{
|
||||
friend class CartridgeDASHWidget;
|
||||
|
||||
public:
|
||||
/**
|
||||
Create a new cartridge using the specified image and size
|
||||
|
||||
@param image Pointer to the ROM image
|
||||
@param size The size of the ROM image
|
||||
@param md5 The md5sum of the ROM image
|
||||
@param settings A reference to the various settings (read-only)
|
||||
*/
|
||||
CartridgeDASH(const ByteBuffer& image, size_t size, const string& md5,
|
||||
const Settings& settings);
|
||||
virtual ~CartridgeDASH() = default;
|
||||
|
||||
public:
|
||||
/** Reset device to its power-on state */
|
||||
void reset() override;
|
||||
|
||||
/**
|
||||
Install cartridge in the specified system. Invoked by the system
|
||||
when the cartridge is attached to it.
|
||||
|
||||
@param system The system the device should install itself in
|
||||
*/
|
||||
void install(System& system) override;
|
||||
|
||||
/**
|
||||
Patch the cartridge ROM.
|
||||
|
||||
@param address The ROM address to patch
|
||||
@param value The value to place into the address
|
||||
@return Success or failure of the patch operation
|
||||
*/
|
||||
bool patch(uInt16 address, uInt8 value) override;
|
||||
|
||||
/**
|
||||
Access the internal ROM image for this cartridge.
|
||||
|
||||
@param size Set to the size of the internal ROM image data
|
||||
@return A pointer to the internal ROM image data
|
||||
*/
|
||||
const uInt8* getImage(size_t& size) const override;
|
||||
|
||||
/**
|
||||
Save the current state of this cart to the given Serializer.
|
||||
|
||||
@param out The Serializer object to use
|
||||
@return False on any errors, else true
|
||||
*/
|
||||
bool save(Serializer& out) const override;
|
||||
|
||||
/**
|
||||
Load the current state of this cart from the given Serializer.
|
||||
|
||||
@param in The Serializer object to use
|
||||
@return False on any errors, else true
|
||||
*/
|
||||
bool load(Serializer& in) override;
|
||||
|
||||
/**
|
||||
Get a descriptor for the device name (used in error checking).
|
||||
|
||||
@return The name of the object
|
||||
*/
|
||||
string name() const override { return "CartridgeDASH"; }
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
/**
|
||||
Get debugger widget responsible for accessing the inner workings
|
||||
of the cart.
|
||||
*/
|
||||
CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||
const GUI::Font& nfont, int x, int y, int w, int h) override
|
||||
{
|
||||
return new CartridgeDASHWidget(boss, lfont, nfont, x, y, w, h, *this);
|
||||
}
|
||||
#endif
|
||||
|
||||
public:
|
||||
/**
|
||||
Get the byte at the specified address
|
||||
|
||||
@return The byte at the specified address
|
||||
*/
|
||||
uInt8 peek(uInt16 address) override;
|
||||
|
||||
/**
|
||||
Change the byte at the specified address to the given value
|
||||
|
||||
@param address The address where the value should be stored
|
||||
@param value The value to be stored at the address
|
||||
@return True if the poke changed the device address space, else false
|
||||
*/
|
||||
bool poke(uInt16 address, uInt8 value) override;
|
||||
|
||||
private:
|
||||
bool bankRAM(uInt8 bank); // switch a RAM bank
|
||||
bool bankROM(uInt8 bank); // switch a ROM bank
|
||||
|
||||
void bankRAMSlot(uInt16 bank); // switch in a 512b RAM slot (lower or upper 1/2 bank)
|
||||
void bankROMSlot(uInt16 bank); // switch in a 512b RAM slot (read or write port)
|
||||
|
||||
void initializeBankState(); // set all banks according to current bankInUse state
|
||||
|
||||
// We have an array that indicates for each of the 8 512 byte areas of the address space, which ROM/RAM
|
||||
// bank is used in that area. ROM switches 1K so occupies 2 successive entries for each switch. RAM occupies
|
||||
// two as well, one 512 byte for read and one for write. The RAM locations are +0x800 apart, and the ROM
|
||||
// are consecutive. This allows us to determine on a read/write exactly where the data is.
|
||||
|
||||
static constexpr uInt16 BANK_UNDEFINED = 0x8000; // bank is undefined and inaccessible
|
||||
std::array<uInt16, 8> bankInUse; // bank being used for ROM/RAM (eight 512 byte areas)
|
||||
std::array<uInt16, 4> segmentInUse; // set by bank methods, to know which hotspot was accessed
|
||||
|
||||
static constexpr uInt16 BANK_SWITCH_HOTSPOT_RAM = 0x3E; // writes to this address cause bankswitching
|
||||
static constexpr uInt16 BANK_SWITCH_HOTSPOT_ROM = 0x3F; // writes to this address cause bankswitching
|
||||
|
||||
static constexpr uInt8 BANK_BITS = 6; // # bits for bank
|
||||
static constexpr uInt8 BIT_BANK_MASK = (1 << BANK_BITS) - 1; // mask for those bits
|
||||
static constexpr uInt16 BITMASK_LOWERUPPER = 0x100; // flags lower or upper section of bank (1==upper)
|
||||
static constexpr uInt16 BITMASK_ROMRAM = 0x200; // flags ROM or RAM bank switching (1==RAM)
|
||||
|
||||
static constexpr uInt16 MAXIMUM_BANK_COUNT = (1 << BANK_BITS);
|
||||
static constexpr uInt16 RAM_BANK_TO_POWER = 9; // 2^n = 512
|
||||
static constexpr uInt16 RAM_BANK_SIZE = (1 << RAM_BANK_TO_POWER);
|
||||
static constexpr uInt16 BITMASK_RAM_BANK = (RAM_BANK_SIZE - 1);
|
||||
static constexpr uInt32 RAM_TOTAL_SIZE = MAXIMUM_BANK_COUNT * RAM_BANK_SIZE;
|
||||
|
||||
static constexpr uInt16 ROM_BANK_TO_POWER = 10; // 2^n = 1024
|
||||
static constexpr uInt16 ROM_BANK_SIZE = (1 << ROM_BANK_TO_POWER);
|
||||
static constexpr uInt16 BITMASK_ROM_BANK = (ROM_BANK_SIZE - 1);
|
||||
|
||||
static constexpr uInt16 ROM_BANK_COUNT = 64;
|
||||
|
||||
static constexpr uInt16 RAM_WRITE_OFFSET = 0x800;
|
||||
|
||||
ByteBuffer myImage; // Pointer to a dynamically allocated ROM image of the cartridge
|
||||
size_t mySize{0}; // Size of the ROM image
|
||||
std::array<uInt8, RAM_TOTAL_SIZE> myRAM;
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
CartridgeDASH() = delete;
|
||||
CartridgeDASH(const CartridgeDASH&) = delete;
|
||||
CartridgeDASH(CartridgeDASH&&) = delete;
|
||||
CartridgeDASH& operator=(const CartridgeDASH&) = delete;
|
||||
CartridgeDASH& operator=(CartridgeDASH&&) = delete;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -33,7 +33,6 @@
|
|||
#include "CartCM.hxx"
|
||||
#include "CartCTY.hxx"
|
||||
#include "CartCV.hxx"
|
||||
#include "CartDASH.hxx"
|
||||
#include "CartDF.hxx"
|
||||
#include "CartDFSC.hxx"
|
||||
#include "CartDPC.hxx"
|
||||
|
@ -277,8 +276,6 @@ CartDetector::createFromImage(const ByteBuffer& image, size_t size, Bankswitch::
|
|||
return make_unique<CartridgeCTY>(image, size, md5, settings);
|
||||
case Bankswitch::Type::_CV:
|
||||
return make_unique<CartridgeCV>(image, size, md5, settings);
|
||||
case Bankswitch::Type::_DASH:
|
||||
return make_unique<CartridgeDASH>(image, size, md5, settings);
|
||||
case Bankswitch::Type::_DF:
|
||||
return make_unique<CartridgeDF>(image, size, md5, settings);
|
||||
case Bankswitch::Type::_DFSC:
|
||||
|
@ -522,9 +519,7 @@ Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t si
|
|||
}
|
||||
|
||||
// Variable sized ROM formats are independent of image size and come last
|
||||
if(isProbablyDASH(image, size))
|
||||
type = Bankswitch::Type::_DASH;
|
||||
else if(isProbably3EPlus(image, size))
|
||||
if(isProbably3EPlus(image, size))
|
||||
type = Bankswitch::Type::_3EP;
|
||||
else if(isProbablyMDM(image, size))
|
||||
type = Bankswitch::Type::_MDM;
|
||||
|
@ -750,14 +745,6 @@ bool CartDetector::isProbablyCV(const ByteBuffer& image, size_t size)
|
|||
return searchForBytes(image.get(), size, signature[1], 3, 1);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartDetector::isProbablyDASH(const ByteBuffer& image, size_t size)
|
||||
{
|
||||
// DASH cart is identified key 'TJAD' in the ROM
|
||||
uInt8 tjad[] = { 'T', 'J', 'A', 'D' };
|
||||
return searchForBytes(image.get(), size, tjad, 4, 1);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartDetector::isProbablyDF(const ByteBuffer& image, size_t size,
|
||||
Bankswitch::Type& type)
|
||||
|
|
|
@ -175,11 +175,6 @@ class CartDetector
|
|||
*/
|
||||
static bool isProbablyCV(const ByteBuffer& image, size_t size);
|
||||
|
||||
/**
|
||||
Returns true if the image is probably a DASH bankswitching cartridge
|
||||
*/
|
||||
static bool isProbablyDASH(const ByteBuffer& image, size_t size);
|
||||
|
||||
/**
|
||||
Returns true if the image is probably a DF/DFSC bankswitching cartridge
|
||||
*/
|
||||
|
|
|
@ -21,7 +21,6 @@ MODULE_OBJS := \
|
|||
src/emucore/CartCM.o \
|
||||
src/emucore/CartCTY.o \
|
||||
src/emucore/CartCV.o \
|
||||
src/emucore/CartDASH.o \
|
||||
src/emucore/CartDPC.o \
|
||||
src/emucore/CartDPCPlus.o \
|
||||
src/emucore/CartE0.o \
|
||||
|
|
|
@ -588,9 +588,6 @@
|
|||
<ClCompile Include="..\debugger\gui\CartCVWidget.cxx">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug-NoDebugger|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\debugger\gui\CartDASHWidget.cxx">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug-NoDebugger|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\debugger\gui\CartDebugWidget.cxx">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug-NoDebugger|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
@ -721,7 +718,6 @@
|
|||
<ClCompile Include="..\emucore\CartCDF.cxx" />
|
||||
<ClCompile Include="..\emucore\CartCM.cxx" />
|
||||
<ClCompile Include="..\emucore\CartCTY.cxx" />
|
||||
<ClCompile Include="..\emucore\CartDASH.cxx" />
|
||||
<ClCompile Include="..\emucore\CartDetector.cxx" />
|
||||
<ClCompile Include="..\emucore\CartDF.cxx" />
|
||||
<ClCompile Include="..\emucore\CartDFSC.cxx" />
|
||||
|
@ -1595,9 +1591,6 @@
|
|||
<ClInclude Include="..\debugger\gui\CartCVWidget.hxx">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug-NoDebugger|x64'">true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\debugger\gui\CartDASHWidget.hxx">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug-NoDebugger|x64'">true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\debugger\gui\CartDebugWidget.hxx">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug-NoDebugger|x64'">true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
|
@ -1740,7 +1733,6 @@
|
|||
<ClInclude Include="..\emucore\CartCDF.hxx" />
|
||||
<ClInclude Include="..\emucore\CartCM.hxx" />
|
||||
<ClInclude Include="..\emucore\CartCTY.hxx" />
|
||||
<ClInclude Include="..\emucore\CartDASH.hxx" />
|
||||
<ClInclude Include="..\emucore\CartDetector.hxx" />
|
||||
<ClInclude Include="..\emucore\CartDF.hxx" />
|
||||
<ClInclude Include="..\emucore\CartDFSC.hxx" />
|
||||
|
|
|
@ -723,9 +723,6 @@
|
|||
<ClCompile Include="..\emucore\TIASurface.cxx">
|
||||
<Filter>Source Files\emucore</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\emucore\CartDASH.cxx">
|
||||
<Filter>Source Files\emucore</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\debugger\gui\CartRamWidget.cxx">
|
||||
<Filter>Source Files\debugger</Filter>
|
||||
</ClCompile>
|
||||
|
@ -735,9 +732,6 @@
|
|||
<ClCompile Include="..\debugger\gui\SaveKeyWidget.cxx">
|
||||
<Filter>Source Files\debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\debugger\gui\CartDASHWidget.cxx">
|
||||
<Filter>Source Files\debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\emucore\CartMDM.cxx">
|
||||
<Filter>Source Files\emucore</Filter>
|
||||
</ClCompile>
|
||||
|
@ -1703,9 +1697,6 @@
|
|||
<ClInclude Include="..\emucore\TIASurface.hxx">
|
||||
<Filter>Header Files\emucore</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\emucore\CartDASH.hxx">
|
||||
<Filter>Header Files\emucore</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\debugger\gui\CartRamWidget.hxx">
|
||||
<Filter>Header Files\debugger</Filter>
|
||||
</ClInclude>
|
||||
|
@ -1715,9 +1706,6 @@
|
|||
<ClInclude Include="..\debugger\gui\SaveKeyWidget.hxx">
|
||||
<Filter>Header Files\debugger</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\debugger\gui\CartDASHWidget.hxx">
|
||||
<Filter>Header Files\debugger</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\emucore\CartMDM.hxx">
|
||||
<Filter>Header Files\emucore</Filter>
|
||||
</ClInclude>
|
||||
|
|
Loading…
Reference in New Issue