mirror of https://github.com/stella-emu/stella.git
Added 3E+ bankswitching scheme by Thomas Jentzsch.
git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@3311 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
parent
1ecfee71e7
commit
087d382280
|
@ -14,6 +14,9 @@
|
|||
|
||||
4.7.2 to 4.8: (xxx. xx, 2016)
|
||||
|
||||
* Added preliminary support for the 3E+ bankswitching scheme, developed
|
||||
by Thomas Jentzsch.
|
||||
|
||||
* Fixed HMOVE positioning bug that occurred under certain circumstances.
|
||||
Thanks to Omegamatrix of AtariAge for the bug report and patch to fix
|
||||
the issue.
|
||||
|
|
|
@ -92,7 +92,7 @@ class PNGLibrary
|
|||
// The following data remains between invocations of allocateStorage,
|
||||
// and is only changed when absolutely necessary.
|
||||
struct ReadInfoType {
|
||||
unique_ptr<uInt8[]> buffer;
|
||||
BytePtr buffer;
|
||||
unique_ptr<png_bytep[]> row_pointers;
|
||||
png_uint_32 width, height, pitch;
|
||||
uInt32 buffer_size, row_size;
|
||||
|
|
|
@ -0,0 +1,336 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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-2016 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.
|
||||
//
|
||||
// $Id$
|
||||
//============================================================================
|
||||
|
||||
#include "Cart3EPlus.hxx"
|
||||
#include "PopUpWidget.hxx"
|
||||
#include "Cart3EPlusWidget.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Cartridge3EPlusWidget::Cartridge3EPlusWidget(
|
||||
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
|
||||
int x, int y, int w, int h, Cartridge3EPlus& cart)
|
||||
: CartDebugWidget(boss, lfont, nfont, x, y, w, h),
|
||||
myCart(cart)
|
||||
{
|
||||
uInt32 size = cart.mySize;
|
||||
|
||||
ostringstream info;
|
||||
info << "3EPlus 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"
|
||||
" Lower 512B of bank x (R)\n"
|
||||
" Upper 512B of bank x (+$200) (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 = 10,
|
||||
ypos = addBaseInformation(size, "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(), kTextAlignLeft);
|
||||
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(), kTextAlignLeft);
|
||||
|
||||
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);
|
||||
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(), kTextAlignLeft);
|
||||
|
||||
myBankState[2*i+1] = new EditTextWidget(boss, _font, xoffset, ypos_s,
|
||||
w - xoffset - 10, myLineHeight, "");
|
||||
myBankState[2*i+1]->setEditable(false);
|
||||
|
||||
xpos = 10;
|
||||
ypos+= 2 * myLineHeight;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Cartridge3EPlusWidget::saveOldState()
|
||||
{
|
||||
myOldState.internalram.clear();
|
||||
|
||||
for(uInt32 i = 0; i < this->internalRamSize();i++)
|
||||
myOldState.internalram.push_back(myCart.myRAM[i]);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Cartridge3EPlusWidget::loadConfig()
|
||||
{
|
||||
updateUIState();
|
||||
CartDebugWidget::loadConfig();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Cartridge3EPlusWidget::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;
|
||||
}
|
||||
|
||||
// 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 Cartridge3EPlusWidget::bankState()
|
||||
{
|
||||
ostringstream& buf = buffer();
|
||||
|
||||
// In this scheme, consecutive 512b segments are either both ROM or both RAM;
|
||||
// we only need to look at the lower segment to determine what the 1K bank is
|
||||
for(int i = 0; i < 4; ++i)
|
||||
{
|
||||
uInt16 bank = myCart.bankInUse[i*2];
|
||||
|
||||
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?
|
||||
buf << " RAM " << bankno;
|
||||
else
|
||||
buf << " ROM " << bankno;
|
||||
}
|
||||
if(i < 3)
|
||||
buf << " /";
|
||||
}
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Cartridge3EPlusWidget::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 char* 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 Cartridge3EPlusWidget::internalRamSize()
|
||||
{
|
||||
return 32*1024;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 Cartridge3EPlusWidget::internalRamRPort(int start)
|
||||
{
|
||||
return 0x0000 + start;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string Cartridge3EPlusWidget::internalRamDescription()
|
||||
{
|
||||
ostringstream desc;
|
||||
desc << "Accessible 512b at a time via:\n"
|
||||
<< " $F000/$F400/$F800/etc used for Read Access\n"
|
||||
<< " $F200/$F600/$FA00/etc used for Write Access (+$200)";
|
||||
|
||||
return desc.str();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const ByteArray& Cartridge3EPlusWidget::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& Cartridge3EPlusWidget::internalRamCurrent(int start, int count)
|
||||
{
|
||||
myRamCurrent.clear();
|
||||
for(int i = 0; i < count; i++)
|
||||
myRamCurrent.push_back(myCart.myRAM[start + i]);
|
||||
return myRamCurrent;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Cartridge3EPlusWidget::internalRamSetValue(int addr, uInt8 value)
|
||||
{
|
||||
myCart.myRAM[addr] = value;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt8 Cartridge3EPlusWidget::internalRamGetValue(int addr)
|
||||
{
|
||||
return myCart.myRAM[addr];
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const Cartridge3EPlusWidget::BankID Cartridge3EPlusWidget::bankEnum[4] = {
|
||||
kBank0Changed, kBank1Changed, kBank2Changed, kBank3Changed
|
||||
};
|
|
@ -0,0 +1,87 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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-2016 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.
|
||||
//
|
||||
// $Id$
|
||||
//============================================================================
|
||||
|
||||
#ifndef CARTRIDGE3EPLUS_WIDGET_HXX
|
||||
#define CARTRIDGE3EPLUS_WIDGET_HXX
|
||||
|
||||
class Cartridge3EPlus;
|
||||
class ButtonWidget;
|
||||
class PopUpWidget;
|
||||
|
||||
#include "CartDebugWidget.hxx"
|
||||
|
||||
class Cartridge3EPlusWidget : public CartDebugWidget
|
||||
{
|
||||
public:
|
||||
Cartridge3EPlusWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||
const GUI::Font& nfont,
|
||||
int x, int y, int w, int h,
|
||||
Cartridge3EPlus& cart);
|
||||
virtual ~Cartridge3EPlusWidget() = default;
|
||||
|
||||
private:
|
||||
void updateUIState();
|
||||
|
||||
private:
|
||||
Cartridge3EPlus& myCart;
|
||||
|
||||
PopUpWidget* myBankNumber[4];
|
||||
PopUpWidget* myBankType[4];
|
||||
ButtonWidget* myBankCommit[4];
|
||||
EditTextWidget* myBankState[8];
|
||||
|
||||
struct CartState {
|
||||
ByteArray internalram;
|
||||
};
|
||||
CartState myOldState;
|
||||
|
||||
enum BankID {
|
||||
kBank0Changed = 'b0CH',
|
||||
kBank1Changed = 'b1CH',
|
||||
kBank2Changed = 'b2CH',
|
||||
kBank3Changed = 'b3CH'
|
||||
};
|
||||
static const BankID bankEnum[4];
|
||||
|
||||
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
|
||||
Cartridge3EPlusWidget() = delete;
|
||||
Cartridge3EPlusWidget(const Cartridge3EPlusWidget&) = delete;
|
||||
Cartridge3EPlusWidget(Cartridge3EPlusWidget&&) = delete;
|
||||
Cartridge3EPlusWidget& operator=(const Cartridge3EPlusWidget&) = delete;
|
||||
Cartridge3EPlusWidget& operator=(Cartridge3EPlusWidget&&) = delete;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -25,6 +25,7 @@ MODULE_OBJS := \
|
|||
src/debugger/gui/Cart0840Widget.o \
|
||||
src/debugger/gui/Cart2KWidget.o \
|
||||
src/debugger/gui/Cart3EWidget.o \
|
||||
src/debugger/gui/Cart3EPlusWidget.o \
|
||||
src/debugger/gui/Cart3FWidget.o \
|
||||
src/debugger/gui/Cart4A50Widget.o \
|
||||
src/debugger/gui/Cart4KWidget.o \
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "Cart0840.hxx"
|
||||
#include "Cart2K.hxx"
|
||||
#include "Cart3E.hxx"
|
||||
#include "Cart3EPlus.hxx"
|
||||
#include "Cart3F.hxx"
|
||||
#include "Cart4A50.hxx"
|
||||
#include "Cart4K.hxx"
|
||||
|
@ -190,6 +191,8 @@ unique_ptr<Cartridge> Cartridge::create(const BytePtr& img, uInt32 size,
|
|||
cartridge = make_ptr<Cartridge2K>(image, size, settings);
|
||||
else if(type == "3E")
|
||||
cartridge = make_ptr<Cartridge3E>(image, size, settings);
|
||||
else if(type == "3E+")
|
||||
cartridge = make_ptr<Cartridge3EPlus>(image, size, settings);
|
||||
else if(type == "3F")
|
||||
cartridge = make_ptr<Cartridge3F>(image, size, settings);
|
||||
else if(type == "4A50")
|
||||
|
@ -527,6 +530,8 @@ string Cartridge::autodetectType(const uInt8* image, uInt32 size)
|
|||
// Variable sized ROM formats are independent of image size and come last
|
||||
if(isProbablyDASH(image, size))
|
||||
type = "DASH";
|
||||
else if(isProbably3EPlus(image, size))
|
||||
type = "3E+";
|
||||
else if(isProbablyMDM(image, size))
|
||||
type = "MDM";
|
||||
|
||||
|
@ -647,6 +652,14 @@ bool Cartridge::isProbably3E(const uInt8* image, uInt32 size)
|
|||
return searchForBytes(image, size, signature, 4, 1);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Cartridge::isProbably3EPlus(const uInt8* image, uInt32 size)
|
||||
{
|
||||
// 3E+ cart is identified key 'TJ3E' in the ROM
|
||||
uInt8 signature[] = { 'T', 'J', '3', 'E' };
|
||||
return searchForBytes(image, size, signature, 4, 1);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Cartridge::isProbably3F(const uInt8* image, uInt32 size)
|
||||
{
|
||||
|
@ -974,6 +987,7 @@ Cartridge::BankswitchType Cartridge::ourBSList[ourNumBSTypes] = {
|
|||
{ "128IN1", "128IN1 Multicart (256/512K)" },
|
||||
{ "2K", "2K (64-2048 bytes Atari)" },
|
||||
{ "3E", "3E (32K Tigervision)" },
|
||||
{ "3E+", "3E+ (TJ modified DASH)" },
|
||||
{ "3F", "3F (512K Tigervision)" },
|
||||
{ "4A50", "4A50 (64K 4A50 + ram)" },
|
||||
{ "4K", "4K (4K Atari)" },
|
||||
|
|
|
@ -190,7 +190,7 @@ class Cartridge : public Device
|
|||
const char* type;
|
||||
const char* desc;
|
||||
};
|
||||
enum { ourNumBSTypes = 47 };
|
||||
enum { ourNumBSTypes = 48 };
|
||||
static BankswitchType ourBSList[ourNumBSTypes];
|
||||
|
||||
protected:
|
||||
|
@ -276,6 +276,11 @@ class Cartridge : public Device
|
|||
*/
|
||||
static bool isProbably3E(const uInt8* image, uInt32 size);
|
||||
|
||||
/**
|
||||
Returns true if the image is probably a 3E+ bankswitching cartridge
|
||||
*/
|
||||
static bool isProbably3EPlus(const uInt8* image, uInt32 size);
|
||||
|
||||
/**
|
||||
Returns true if the image is probably a 3F bankswitching cartridge
|
||||
*/
|
||||
|
@ -383,7 +388,7 @@ class Cartridge : public Device
|
|||
|
||||
// The array containing information about every byte of ROM indicating
|
||||
// whether it is used as code.
|
||||
unique_ptr<uInt8[]> myCodeAccessBase;
|
||||
BytePtr myCodeAccessBase;
|
||||
|
||||
private:
|
||||
// If myBankLocked is true, ignore attempts at bankswitching. This is used
|
||||
|
|
|
@ -136,7 +136,7 @@ class Cartridge2K : public Cartridge
|
|||
|
||||
private:
|
||||
// Pointer to a dynamically allocated ROM image of the cartridge
|
||||
unique_ptr<uInt8[]> myImage;
|
||||
BytePtr myImage;
|
||||
|
||||
// Size of the ROM image
|
||||
uInt32 mySize;
|
||||
|
|
|
@ -181,7 +181,7 @@ class Cartridge3E : public Cartridge
|
|||
|
||||
private:
|
||||
// Pointer to a dynamically allocated ROM image of the cartridge
|
||||
unique_ptr<uInt8[]> myImage;
|
||||
BytePtr myImage;
|
||||
|
||||
// RAM contents. For now every ROM gets all 32K of potential RAM
|
||||
uInt8 myRAM[32 * 1024];
|
||||
|
|
|
@ -0,0 +1,359 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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-2016 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.
|
||||
//
|
||||
// $Id$
|
||||
//============================================================================
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "System.hxx"
|
||||
#include "TIA.hxx"
|
||||
#include "Cart3EPlus.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Cartridge3EPlus::Cartridge3EPlus(const uInt8* image, uInt32 size, const Settings& settings)
|
||||
: Cartridge(settings),
|
||||
mySize(size)
|
||||
{
|
||||
// Allocate array for the ROM image
|
||||
myImage = make_ptr<uInt8[]>(mySize);
|
||||
|
||||
// Copy the ROM image into my buffer
|
||||
memcpy(myImage.get(), image, mySize);
|
||||
createCodeAccessBase(mySize + RAM_TOTAL_SIZE);
|
||||
|
||||
// Remember startup bank (0 per spec, rather than last per 3E scheme).
|
||||
// Set this to go to 3rd 1K Bank.
|
||||
myStartBank = 0;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Cartridge3EPlus::reset()
|
||||
{
|
||||
// Initialize RAM
|
||||
if (mySettings.getBool("ramrandom"))
|
||||
for (uInt32 i = 0; i < RAM_TOTAL_SIZE; ++i)
|
||||
myRAM[i] = mySystem->randGenerator().next();
|
||||
else
|
||||
memset(myRAM, 0, RAM_TOTAL_SIZE);
|
||||
|
||||
// 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 Cartridge3EPlus::install(System& system)
|
||||
{
|
||||
mySystem = &system;
|
||||
|
||||
System::PageAccess access(this, System::PA_READWRITE);
|
||||
|
||||
// Set the page accessing methods for the hot spots (for 100% emulation
|
||||
// we need to chain any accesses below 0x40 to the TIA. Our poke() method
|
||||
// does this via mySystem->tiaPoke(...), at least until we come up with a
|
||||
// cleaner way to do it).
|
||||
for (uInt32 i = 0x00; i < 0x40; i += (1 << System::PAGE_SHIFT))
|
||||
mySystem->setPageAccess(i >> System::PAGE_SHIFT, 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 Cartridge3EPlus::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
|
||||
{
|
||||
// Reading from the write port triggers an unwanted write
|
||||
value = mySystem->getDataBusState(0xFF);
|
||||
|
||||
if(bankLocked())
|
||||
return value;
|
||||
else
|
||||
{
|
||||
triggerReadFromWritePort(peekAddress);
|
||||
|
||||
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 myRAM[offset] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Cartridge3EPlus::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);
|
||||
|
||||
// Pass the poke through to the TIA. In a real Atari, both the cart and the
|
||||
// TIA see the address lines, and both react accordingly. In Stella, each
|
||||
// 64-byte chunk of address space is "owned" by only one device. If we
|
||||
// don't chain the poke to the TIA, then the TIA can't see it...
|
||||
mySystem->tia().poke(address, value);
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Cartridge3EPlus::bankRAM(uInt8 bank)
|
||||
{
|
||||
if (bankLocked()) // debugger can lock RAM
|
||||
return false;
|
||||
|
||||
// Each RAM bank uses two slots, separated by 0x200 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 Cartridge3EPlus::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
|
||||
cerr << "raw bank=" << std::dec << currentBank << endl
|
||||
<< "startCurrentBank=$" << std::hex << startCurrentBank << endl;
|
||||
// Setup the page access methods for the current bank
|
||||
System::PageAccess access(this, System::PA_READ);
|
||||
|
||||
if(upper) // We're mapping the write port
|
||||
{
|
||||
bankInUse[bankNumber * 2 + 1] = Int16(bank);
|
||||
access.type = System::PA_WRITE;
|
||||
}
|
||||
else // We're mapping the read port
|
||||
{
|
||||
bankInUse[bankNumber * 2] = Int16(bank);
|
||||
access.type = System::PA_READ;
|
||||
}
|
||||
|
||||
uInt32 start = 0x1000 + (bankNumber << (RAM_BANK_TO_POWER+1)) + (upper ? RAM_WRITE_OFFSET : 0);
|
||||
uInt32 end = start + RAM_BANK_SIZE - 1;
|
||||
|
||||
cerr << "bank RAM: " << bankNumber << " -> " << (bankNumber * 2 + (upper ? 1 : 0)) << (upper ? " (W)" : " (R)") << endl
|
||||
<< "start=" << std::hex << start << ", end=" << end << endl << endl;
|
||||
for (uInt32 address = start; address <= end; address += (1 << System::PAGE_SHIFT))
|
||||
{
|
||||
if(upper)
|
||||
access.directPokeBase = &myRAM[startCurrentBank + (address & (RAM_BANK_SIZE - 1))];
|
||||
else
|
||||
access.directPeekBase = &myRAM[startCurrentBank + (address & (RAM_BANK_SIZE - 1))];
|
||||
|
||||
access.codeAccessBase = &myCodeAccessBase[mySize + startCurrentBank + (address & (RAM_BANK_SIZE - 1))];
|
||||
mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Cartridge3EPlus::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 Cartridge3EPlus::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::PA_READ);
|
||||
|
||||
uInt32 start = 0x1000 + (bankNumber << ROM_BANK_TO_POWER) + (upper ? ROM_BANK_SIZE / 2 : 0);
|
||||
uInt32 end = start + ROM_BANK_SIZE / 2 - 1;
|
||||
|
||||
for (uInt32 address = start; address <= end; address += (1 << System::PAGE_SHIFT))
|
||||
{
|
||||
access.directPeekBase = &myImage[startCurrentBank + (address & (ROM_BANK_SIZE - 1))];
|
||||
access.codeAccessBase = &myCodeAccessBase[startCurrentBank + (address & (ROM_BANK_SIZE - 1))];
|
||||
mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Cartridge3EPlus::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::PA_READ);
|
||||
uInt32 start = 0x1000 + (b << RAM_BANK_TO_POWER);
|
||||
uInt32 end = start + RAM_BANK_SIZE - 1;
|
||||
for (uInt32 address = start; address <= end; address += (1 << System::PAGE_SHIFT))
|
||||
mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
|
||||
}
|
||||
else if (bankInUse[b] & BITMASK_ROMRAM)
|
||||
bankRAMSlot(bankInUse[b]);
|
||||
else
|
||||
bankROMSlot(bankInUse[b]);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Cartridge3EPlus::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* Cartridge3EPlus::getImage(int& size) const
|
||||
{
|
||||
size = mySize;
|
||||
return myImage.get();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Cartridge3EPlus::save(Serializer& out) const
|
||||
{
|
||||
try
|
||||
{
|
||||
out.putString(name());
|
||||
out.putShortArray(bankInUse, 8);
|
||||
out.putShortArray(segmentInUse, 4);
|
||||
out.putByteArray(myRAM, RAM_TOTAL_SIZE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
cerr << "ERROR: Cartridge3EPlus::save" << endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Cartridge3EPlus::load(Serializer& in)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (in.getString() != name())
|
||||
return false;
|
||||
in.getShortArray(bankInUse, 8);
|
||||
in.getShortArray(segmentInUse, 4);
|
||||
in.getByteArray(myRAM, RAM_TOTAL_SIZE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
cerr << "ERROR: Cartridge3EPlus::load" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
initializeBankState();
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,195 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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-2016 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.
|
||||
//
|
||||
// $Id$
|
||||
//============================================================================
|
||||
|
||||
#ifndef CARTRIDGE_3EPLUS_HXX
|
||||
#define CARTRIDGE_3EPLUS_HXX
|
||||
|
||||
class System;
|
||||
|
||||
#include "bspf.hxx"
|
||||
#include "Cart.hxx"
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
class Cartridge3EPlusWidget;
|
||||
#include "Cart3EPlusWidget.hxx"
|
||||
#endif
|
||||
|
||||
/**
|
||||
Cartridge class from Thomas Jentzsch, mostly based on the 'DASH' scheme
|
||||
with the following changes:
|
||||
|
||||
RAM areas:
|
||||
- read $x000, write $x200
|
||||
- read $x400, write $x600
|
||||
- read $x800, write $xa00
|
||||
- read $xc00, write $xe00
|
||||
|
||||
@author Thomas Jentzsch and Stephen Anthony
|
||||
*/
|
||||
|
||||
class Cartridge3EPlus: public Cartridge
|
||||
{
|
||||
friend class Cartridge3EPlusWidget;
|
||||
|
||||
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 settings A reference to the various settings (read-only)
|
||||
*/
|
||||
Cartridge3EPlus(const uInt8* image, uInt32 size, const Settings& settings);
|
||||
virtual ~Cartridge3EPlus() = 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(int& 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 "Cartridge3E+"; }
|
||||
|
||||
#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 Cartridge3EPlusWidget(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
|
||||
uInt16 bankInUse[8]; // bank being used for ROM/RAM (eight 512 byte areas)
|
||||
uInt16 segmentInUse[4]; // 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 = 0x200;
|
||||
|
||||
BytePtr myImage; // Pointer to a dynamically allocated ROM image of the cartridge
|
||||
uInt32 mySize; // Size of the ROM image
|
||||
uInt8 myRAM[RAM_TOTAL_SIZE];
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
Cartridge3EPlus() = delete;
|
||||
Cartridge3EPlus(const Cartridge3EPlus&) = delete;
|
||||
Cartridge3EPlus(Cartridge3EPlus&&) = delete;
|
||||
Cartridge3EPlus& operator=(const Cartridge3EPlus&) = delete;
|
||||
Cartridge3EPlus& operator=(Cartridge3EPlus&&) = delete;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -158,7 +158,7 @@ class Cartridge3F : public Cartridge
|
|||
|
||||
private:
|
||||
// Pointer to a dynamically allocated ROM image of the cartridge
|
||||
unique_ptr<uInt8[]> myImage;
|
||||
BytePtr myImage;
|
||||
|
||||
// Size of the ROM image
|
||||
uInt32 mySize;
|
||||
|
|
|
@ -198,7 +198,7 @@ class CartridgeAR : public Cartridge
|
|||
uInt32 mySize;
|
||||
|
||||
// All of the 8448 byte loads associated with the game
|
||||
unique_ptr<uInt8[]> myLoadImages;
|
||||
BytePtr myLoadImages;
|
||||
|
||||
// Indicates how many 8448 loads there are
|
||||
uInt8 myNumberOfLoadImages;
|
||||
|
|
|
@ -139,7 +139,7 @@ class CartridgeCV : public Cartridge
|
|||
private:
|
||||
// Pointer to the initial RAM data from the cart
|
||||
// This doesn't always exist, so we don't pre-allocate it
|
||||
unique_ptr<uInt8[]> myInitialRAM;
|
||||
BytePtr myInitialRAM;
|
||||
|
||||
// Initial size of the cart data
|
||||
uInt32 mySize;
|
||||
|
|
|
@ -165,7 +165,7 @@ class CartridgeCVPlus : public Cartridge
|
|||
|
||||
private:
|
||||
// Pointer to a dynamically allocated ROM image of the cartridge
|
||||
unique_ptr<uInt8[]> myImage;
|
||||
BytePtr myImage;
|
||||
|
||||
// The 1024 bytes of RAM
|
||||
uInt8 myRAM[1024];
|
||||
|
|
|
@ -26,8 +26,7 @@
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
CartridgeDASH::CartridgeDASH(const uInt8* image, uInt32 size, const Settings& settings)
|
||||
: Cartridge(settings),
|
||||
mySize(size),
|
||||
myImage(nullptr)
|
||||
mySize(size)
|
||||
{
|
||||
// Allocate array for the ROM image
|
||||
myImage = make_ptr<uInt8[]>(mySize);
|
||||
|
@ -42,8 +41,8 @@ CartridgeDASH::CartridgeDASH(const uInt8* image, uInt32 size, const Settings& se
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeDASH::reset() {
|
||||
|
||||
void CartridgeDASH::reset()
|
||||
{
|
||||
// Initialize RAM
|
||||
if (mySettings.getBool("ramrandom"))
|
||||
for (uInt32 i = 0; i < RAM_TOTAL_SIZE; ++i)
|
||||
|
@ -66,8 +65,8 @@ void CartridgeDASH::reset() {
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeDASH::install(System& system) {
|
||||
|
||||
void CartridgeDASH::install(System& system)
|
||||
{
|
||||
mySystem = &system;
|
||||
|
||||
System::PageAccess access(this, System::PA_READWRITE);
|
||||
|
@ -95,22 +94,23 @@ void CartridgeDASH::install(System& system) {
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt8 CartridgeDASH::peek(uInt16 address) {
|
||||
|
||||
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?
|
||||
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
|
||||
|
||||
}
|
||||
else if (imageBank & BITMASK_ROMRAM) // a RAM bank
|
||||
{
|
||||
// Reading from the write port triggers an unwanted write
|
||||
value = mySystem->getDataBusState(0xFF);
|
||||
|
||||
|
@ -131,8 +131,8 @@ uInt8 CartridgeDASH::peek(uInt16 address) {
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeDASH::poke(uInt16 address, uInt8 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'
|
||||
|
@ -154,8 +154,8 @@ bool CartridgeDASH::poke(uInt16 address, uInt8 value) {
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeDASH::bankRAM(uInt8 bank) {
|
||||
|
||||
bool CartridgeDASH::bankRAM(uInt8 bank)
|
||||
{
|
||||
if (bankLocked()) // debugger can lock RAM
|
||||
return false;
|
||||
|
||||
|
@ -170,8 +170,8 @@ bool CartridgeDASH::bankRAM(uInt8 bank) {
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeDASH::bankRAMSlot(uInt16 bank) {
|
||||
|
||||
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
|
||||
|
@ -181,35 +181,35 @@ void CartridgeDASH::bankRAMSlot(uInt16 bank) {
|
|||
// Setup the page access methods for the current bank
|
||||
System::PageAccess access(this, System::PA_READ);
|
||||
|
||||
if (upper) { // We're mapping the write port
|
||||
|
||||
if(upper) // We're mapping the write port
|
||||
{
|
||||
bankInUse[bankNumber + 4] = Int16(bank);
|
||||
access.type = System::PA_WRITE;
|
||||
|
||||
} else { // We're mapping the read port
|
||||
|
||||
}
|
||||
else // We're mapping the read port
|
||||
{
|
||||
bankInUse[bankNumber] = Int16(bank);
|
||||
access.type = System::PA_READ;
|
||||
|
||||
}
|
||||
|
||||
uInt32 start = 0x1000 + (bankNumber << RAM_BANK_TO_POWER) + (upper ? RAM_WRITE_OFFSET : 0);
|
||||
uInt32 end = start + RAM_BANK_SIZE - 1;
|
||||
|
||||
for (uInt32 address = start; address <= end; address += (1 << System::PAGE_SHIFT)) {
|
||||
for (uInt32 address = start; address <= end; address += (1 << System::PAGE_SHIFT))
|
||||
{
|
||||
if(upper)
|
||||
access.directPokeBase = &myRAM[startCurrentBank + (address & (RAM_BANK_SIZE - 1))];
|
||||
else
|
||||
access.directPeekBase = &myRAM[startCurrentBank + (address & (RAM_BANK_SIZE - 1))];
|
||||
|
||||
access.codeAccessBase = &myCodeAccessBase[mySize + startCurrentBank + (address & (RAM_BANK_SIZE - 1))];
|
||||
mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeDASH::bankROM(uInt8 bank) {
|
||||
|
||||
bool CartridgeDASH::bankROM(uInt8 bank)
|
||||
{
|
||||
if (bankLocked()) // debugger can lock ROM
|
||||
return false;
|
||||
|
||||
|
@ -226,8 +226,8 @@ bool CartridgeDASH::bankROM(uInt8 bank) {
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeDASH::bankROMSlot(uInt16 bank) {
|
||||
|
||||
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
|
||||
|
@ -242,7 +242,8 @@ void CartridgeDASH::bankROMSlot(uInt16 bank) {
|
|||
uInt32 start = 0x1000 + (bankNumber << ROM_BANK_TO_POWER) + (upper ? ROM_BANK_SIZE / 2 : 0);
|
||||
uInt32 end = start + ROM_BANK_SIZE / 2 - 1;
|
||||
|
||||
for (uInt32 address = start; address <= end; address += (1 << System::PAGE_SHIFT)) {
|
||||
for (uInt32 address = start; address <= end; address += (1 << System::PAGE_SHIFT))
|
||||
{
|
||||
access.directPeekBase = &myImage[startCurrentBank + (address & (ROM_BANK_SIZE - 1))];
|
||||
access.codeAccessBase = &myCodeAccessBase[startCurrentBank + (address & (ROM_BANK_SIZE - 1))];
|
||||
mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
|
||||
|
@ -250,19 +251,19 @@ void CartridgeDASH::bankROMSlot(uInt16 bank) {
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeDASH::initializeBankState() {
|
||||
|
||||
void CartridgeDASH::initializeBankState()
|
||||
{
|
||||
// Switch in each 512b slot
|
||||
for (uInt32 b = 0; b < 8; b++) {
|
||||
if (bankInUse[b] == BANK_UNDEFINED) {
|
||||
|
||||
for(uInt32 b = 0; b < 8; b++)
|
||||
{
|
||||
if(bankInUse[b] == BANK_UNDEFINED)
|
||||
{
|
||||
// All accesses point to peek/poke above
|
||||
System::PageAccess access(this, System::PA_READ);
|
||||
uInt32 start = 0x1000 + (b << RAM_BANK_TO_POWER);
|
||||
uInt32 end = start + RAM_BANK_SIZE - 1;
|
||||
for (uInt32 address = start; address <= end; address += (1 << System::PAGE_SHIFT))
|
||||
mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
|
||||
|
||||
}
|
||||
else if (bankInUse[b] & BITMASK_ROMRAM)
|
||||
bankRAMSlot(bankInUse[b]);
|
||||
|
@ -272,7 +273,8 @@ void CartridgeDASH::initializeBankState() {
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeDASH::patch(uInt16 address, uInt8 value) {
|
||||
bool CartridgeDASH::patch(uInt16 address, uInt8 value)
|
||||
{
|
||||
#if 0
|
||||
// Patch the cartridge ROM (for debugger)
|
||||
|
||||
|
@ -308,20 +310,24 @@ bool CartridgeDASH::patch(uInt16 address, uInt8 value) {
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const uInt8* CartridgeDASH::getImage(int& size) const {
|
||||
const uInt8* CartridgeDASH::getImage(int& size) const
|
||||
{
|
||||
size = mySize;
|
||||
return myImage.get();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeDASH::save(Serializer& out) const {
|
||||
|
||||
try {
|
||||
bool CartridgeDASH::save(Serializer& out) const
|
||||
{
|
||||
try
|
||||
{
|
||||
out.putString(name());
|
||||
out.putShortArray(bankInUse, 8);
|
||||
out.putShortArray(segmentInUse, 4);
|
||||
out.putByteArray(myRAM, RAM_TOTAL_SIZE);
|
||||
} catch (...) {
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
cerr << "ERROR: CartridgeDASH::save" << endl;
|
||||
return false;
|
||||
}
|
||||
|
@ -329,15 +335,18 @@ bool CartridgeDASH::save(Serializer& out) const {
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeDASH::load(Serializer& in) {
|
||||
|
||||
try {
|
||||
bool CartridgeDASH::load(Serializer& in)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (in.getString() != name())
|
||||
return false;
|
||||
in.getShortArray(bankInUse, 8);
|
||||
in.getShortArray(segmentInUse, 4);
|
||||
in.getByteArray(myRAM, RAM_TOTAL_SIZE);
|
||||
} catch (...) {
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
cerr << "ERROR: CartridgeDASH::load" << endl;
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -125,147 +125,145 @@ class CartridgeDASHWidget;
|
|||
@author Andrew Davie
|
||||
*/
|
||||
|
||||
class CartridgeDASH: public Cartridge {
|
||||
class CartridgeDASH: public Cartridge
|
||||
{
|
||||
friend class CartridgeDASHWidget;
|
||||
|
||||
public:
|
||||
/**
|
||||
Create a new cartridge using the specified image and size
|
||||
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 settings A reference to the various settings (read-only)
|
||||
*/
|
||||
CartridgeDASH(const uInt8* image, uInt32 size, const Settings& settings);
|
||||
virtual ~CartridgeDASH() = default;
|
||||
@param image Pointer to the ROM image
|
||||
@param size The size of the ROM image
|
||||
@param settings A reference to the various settings (read-only)
|
||||
*/
|
||||
CartridgeDASH(const uInt8* image, uInt32 size, const Settings& settings);
|
||||
virtual ~CartridgeDASH() = default;
|
||||
|
||||
public:
|
||||
/**
|
||||
Reset device to its power-on state
|
||||
*/
|
||||
void reset() override;
|
||||
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.
|
||||
/**
|
||||
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;
|
||||
@param system The system the device should install itself in
|
||||
*/
|
||||
void install(System& system) override;
|
||||
|
||||
/**
|
||||
Patch the cartridge ROM.
|
||||
/**
|
||||
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;
|
||||
@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.
|
||||
/**
|
||||
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(int& size) const override;
|
||||
@param size Set to the size of the internal ROM image data
|
||||
@return A pointer to the internal ROM image data
|
||||
*/
|
||||
const uInt8* getImage(int& size) const override;
|
||||
|
||||
/**
|
||||
Save the current state of this cart to the given Serializer.
|
||||
/**
|
||||
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;
|
||||
@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.
|
||||
/**
|
||||
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;
|
||||
@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).
|
||||
/**
|
||||
Get a descriptor for the device name (used in error checking).
|
||||
|
||||
@return The name of the object
|
||||
*/
|
||||
string name() const override { return "CartridgeDASH"; }
|
||||
@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
|
||||
#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
|
||||
public:
|
||||
/**
|
||||
Get the byte at the specified address
|
||||
|
||||
@return The byte at the specified address
|
||||
*/
|
||||
uInt8 peek(uInt16 address) override;
|
||||
@return The byte at the specified address
|
||||
*/
|
||||
uInt8 peek(uInt16 address) override;
|
||||
|
||||
/**
|
||||
Change the byte at the specified address to the given value
|
||||
/**
|
||||
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;
|
||||
@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:
|
||||
private:
|
||||
bool bankRAM(uInt8 bank); // switch a RAM bank
|
||||
bool bankROM(uInt8 bank); // switch a ROM bank
|
||||
|
||||
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 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
|
||||
|
||||
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.
|
||||
|
||||
// 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
|
||||
uInt16 bankInUse[8]; // bank being used for ROM/RAM (eight 512 byte areas)
|
||||
uInt16 segmentInUse[4]; // set by bank methods, to know which hotspot was accessed
|
||||
|
||||
static constexpr uInt16 BANK_UNDEFINED = 0x8000; // bank is undefined and inaccessible
|
||||
uInt16 bankInUse[8]; // bank being used for ROM/RAM (eight 512 byte areas)
|
||||
uInt16 segmentInUse[4]; // 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 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 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 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_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 ROM_BANK_COUNT = 64;
|
||||
static constexpr uInt16 RAM_WRITE_OFFSET = 0x800;
|
||||
|
||||
static constexpr uInt16 RAM_WRITE_OFFSET = 0x800;
|
||||
|
||||
uInt32 mySize; // Size of the ROM image
|
||||
unique_ptr<uInt8[]> myImage; // Pointer to a dynamically allocated ROM image of the cartridge
|
||||
uInt8 myRAM[RAM_TOTAL_SIZE];
|
||||
BytePtr myImage; // Pointer to a dynamically allocated ROM image of the cartridge
|
||||
uInt32 mySize; // Size of the ROM image
|
||||
uInt8 myRAM[RAM_TOTAL_SIZE];
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
|
|
|
@ -195,7 +195,7 @@ class CartridgeDPCPlus : public Cartridge
|
|||
|
||||
private:
|
||||
// The ROM image and size
|
||||
unique_ptr<uInt8[]> myImage;
|
||||
BytePtr myImage;
|
||||
uInt32 mySize;
|
||||
|
||||
// Pointer to the 24K program ROM image of the cartridge
|
||||
|
|
|
@ -163,7 +163,7 @@ class CartridgeMDM : public Cartridge
|
|||
|
||||
private:
|
||||
// Pointer to a dynamically allocated ROM image of the cartridge
|
||||
unique_ptr<uInt8[]> myImage;
|
||||
BytePtr myImage;
|
||||
|
||||
// Size of the ROM image
|
||||
uInt32 mySize;
|
||||
|
|
|
@ -152,7 +152,7 @@ class CartridgeSB : public Cartridge
|
|||
|
||||
private:
|
||||
// The 128-256K ROM image and size of the cartridge
|
||||
unique_ptr<uInt8[]> myImage;
|
||||
BytePtr myImage;
|
||||
uInt32 mySize;
|
||||
|
||||
// Indicates which bank is currently active
|
||||
|
|
|
@ -408,10 +408,10 @@ class TIA : public Device
|
|||
Settings& mySettings;
|
||||
|
||||
// Pointer to the current frame buffer
|
||||
unique_ptr<uInt8[]> myCurrentFrameBuffer;
|
||||
BytePtr myCurrentFrameBuffer;
|
||||
|
||||
// Pointer to the previous frame buffer
|
||||
unique_ptr<uInt8[]> myPreviousFrameBuffer;
|
||||
BytePtr myPreviousFrameBuffer;
|
||||
|
||||
// Pointer to the next pixel that will be drawn in the current frame buffer
|
||||
uInt8* myFramePointer;
|
||||
|
|
|
@ -7,6 +7,7 @@ MODULE_OBJS := \
|
|||
src/emucore/Cart0840.o \
|
||||
src/emucore/Cart2K.o \
|
||||
src/emucore/Cart3E.o \
|
||||
src/emucore/Cart3EPlus.o \
|
||||
src/emucore/Cart3F.o \
|
||||
src/emucore/Cart4A50.o \
|
||||
src/emucore/Cart4K.o \
|
||||
|
|
Loading…
Reference in New Issue