mirror of https://github.com/stella-emu/stella.git
parent
053b79fc3e
commit
5760167f31
|
@ -3453,6 +3453,7 @@ Ms Pac-Man (Stella extended codes):
|
|||
<tr><td>DPC+</td><td>Enhanced DPC </td></tr>
|
||||
<tr><td>E0 </td><td>8K Parker Bros </td></tr>
|
||||
<tr><td>E7 </td><td>16K M-network </td></tr>
|
||||
<tr><td>E78K </td><td>8K M-network </td></tr>
|
||||
<tr><td>EF </td><td>64K Homestar Runner </td></tr>
|
||||
<tr><td>EFSC </td><td>64K Homestar Runner + ram</td></tr>
|
||||
<tr><td>F0 </td><td>Dynacom Megaboy </td></tr>
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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-2017 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 "CartMNetwork.hxx"
|
||||
#include "PopUpWidget.hxx"
|
||||
#include "CartE78KWidget.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
CartridgeE78KWidget::CartridgeE78KWidget(
|
||||
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
|
||||
int x, int y, int w, int h,
|
||||
CartridgeMNetwork& cart)
|
||||
: CartridgeMNetworkWidget(boss, lfont, nfont, x, y, w, h, cart)
|
||||
{
|
||||
ostringstream info;
|
||||
info << "E78K cartridge, 4 2K slices ROM + 2 1K RAM\n"
|
||||
<< "Lower 2K accessible @ $F000 - $F7FF\n"
|
||||
<< " Slice 0 - 2 of ROM (hotspots $FE4 to $FE6)\n"
|
||||
<< " Slice 0 (1K) of RAM (hotspot $FE7)\n"
|
||||
<< " $F400 - $F7FF (R), $F000 - $F3FF (W)\n"
|
||||
<< "256B RAM accessible @ $F800 - $F9FF\n"
|
||||
<< " Hotspots $FE8 - $FEB (256B of RAM slice 1)\n"
|
||||
<< " $F900 - $F9FF (R), $F800 - $F8FF (W)\n"
|
||||
<< "Upper 1.5K ROM accessible @ $FA00 - $FFFF\n"
|
||||
<< " Always points to last 1.5K of ROM\n"
|
||||
<< "Startup slices = " << cart.myStartBank << " / 0\n";
|
||||
|
||||
#if 0
|
||||
// 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" << " = $" << HEX4 << start << "\n";
|
||||
#endif
|
||||
|
||||
initialize(boss, cart, info);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const char* CartridgeE78KWidget::getSpotLower(int idx)
|
||||
{
|
||||
static const char* const spot_lower[] = {
|
||||
"0 - ROM ($FFE4)", "1 - ROM ($FFE5)", "2 - ROM ($FFE6)", "3 - RAM ($FFE7)"
|
||||
};
|
||||
|
||||
return spot_lower[idx];
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const char* CartridgeE78KWidget::getSpotUpper(int idx)
|
||||
{
|
||||
static const char* const spot_upper[] = {
|
||||
"0 - RAM ($FFE8)", "1 - RAM ($FFE9)", "2 - RAM ($FFEA)", "3 - RAM ($FFEB)"
|
||||
};
|
||||
|
||||
return spot_upper[idx];
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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-2017 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 CARTRIDGEE78K_WIDGET_HXX
|
||||
#define CARTRIDGEE78K_WIDGET_HXX
|
||||
|
||||
#include "CartMNetworkWidget.hxx"
|
||||
|
||||
class CartridgeE78KWidget : public CartridgeMNetworkWidget
|
||||
{
|
||||
public:
|
||||
CartridgeE78KWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||
const GUI::Font& nfont,
|
||||
int x, int y, int w, int h,
|
||||
CartridgeMNetwork& cart);
|
||||
virtual ~CartridgeE78KWidget() = default;
|
||||
|
||||
protected:
|
||||
const char* getSpotLower(int idx);
|
||||
const char* getSpotUpper(int idx);
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
CartridgeE78KWidget() = delete;
|
||||
CartridgeE78KWidget(const CartridgeE78KWidget&) = delete;
|
||||
CartridgeE78KWidget(CartridgeE78KWidget&&) = delete;
|
||||
CartridgeE78KWidget& operator=(const CartridgeE78KWidget&) = delete;
|
||||
CartridgeE78KWidget& operator=(CartridgeE78KWidget&&) = delete;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,169 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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-2017 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 "CartE7.hxx"
|
||||
#include "CartMNetwork.hxx"
|
||||
#include "PopUpWidget.hxx"
|
||||
#include "CartMNetworkWidget.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
CartridgeMNetworkWidget::CartridgeMNetworkWidget(
|
||||
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
|
||||
int x, int y, int w, int h,
|
||||
CartridgeMNetwork& cart)
|
||||
: CartDebugWidget(boss, lfont, nfont, x, y, w, h),
|
||||
myCart(cart)
|
||||
{}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeMNetworkWidget::initialize(GuiObject* boss, CartridgeMNetwork& cart, ostringstream& info)
|
||||
{
|
||||
uInt32 size = cart.bankCount() * cart.BANK_SIZE;
|
||||
|
||||
int xpos = 10,
|
||||
ypos = addBaseInformation(size, "M-Network", info.str(), 15) +
|
||||
myLineHeight;
|
||||
|
||||
VariantList items0, items1;
|
||||
for(int i = 0; i < cart.bankCount(); ++i)
|
||||
VarList::push_back(items0, getSpotLower(i));
|
||||
for(int i = 0; i < 4; ++i)
|
||||
VarList::push_back(items1, getSpotUpper(i));
|
||||
|
||||
const int lwidth = _font.getStringWidth("Set slice for upper 256B "),
|
||||
fwidth = _font.getStringWidth("3 - RAM ($FFEB)");
|
||||
myLower2K =
|
||||
new PopUpWidget(boss, _font, xpos, ypos - 2, fwidth, myLineHeight, items0,
|
||||
"Set slice for lower 2K ", lwidth, kLowerChanged);
|
||||
myLower2K->setTarget(this);
|
||||
addFocusWidget(myLower2K);
|
||||
ypos += myLower2K->getHeight() + 4;
|
||||
|
||||
myUpper256B =
|
||||
new PopUpWidget(boss, _font, xpos, ypos - 2, fwidth, myLineHeight, items1,
|
||||
"Set slice for upper 256B ", lwidth, kUpperChanged);
|
||||
myUpper256B->setTarget(this);
|
||||
addFocusWidget(myUpper256B);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeMNetworkWidget::saveOldState()
|
||||
{
|
||||
myOldState.internalram.clear();
|
||||
|
||||
for(uInt32 i = 0; i < this->internalRamSize(); i++)
|
||||
{
|
||||
myOldState.internalram.push_back(myCart.myRAM[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeMNetworkWidget::loadConfig()
|
||||
{
|
||||
myLower2K->setSelectedIndex(myCart.myCurrentSlice[0]);
|
||||
myUpper256B->setSelectedIndex(myCart.myCurrentRAM);
|
||||
|
||||
CartDebugWidget::loadConfig();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeMNetworkWidget::handleCommand(CommandSender* sender,
|
||||
int cmd, int data, int id)
|
||||
{
|
||||
myCart.unlockBank();
|
||||
|
||||
switch(cmd)
|
||||
{
|
||||
case kLowerChanged:
|
||||
myCart.bank(myLower2K->getSelected());
|
||||
break;
|
||||
case kUpperChanged:
|
||||
myCart.bankRAM(myUpper256B->getSelected());
|
||||
break;
|
||||
}
|
||||
|
||||
myCart.lockBank();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string CartridgeMNetworkWidget::bankState()
|
||||
{
|
||||
ostringstream& buf = buffer();
|
||||
|
||||
buf << "Slices: " << std::dec
|
||||
<< getSpotLower(myCart.myCurrentSlice[0]) << " / "
|
||||
<< getSpotUpper(myCart.myCurrentRAM);
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 CartridgeMNetworkWidget::internalRamSize()
|
||||
{
|
||||
return 2048;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 CartridgeMNetworkWidget::internalRamRPort(int start)
|
||||
{
|
||||
return 0x0000 + start;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string CartridgeMNetworkWidget::internalRamDescription()
|
||||
{
|
||||
ostringstream desc;
|
||||
desc << "First 1K accessible via:\n"
|
||||
<< " $F000 - $F3FF used for Write Access\n"
|
||||
<< " $F400 - $F7FF used for Read Access\n"
|
||||
<< "256K of second 1K accessible via:\n"
|
||||
<< " $F800 - $F8FF used for Write Access\n"
|
||||
<< " $F900 - $F9FF used for Read Access";
|
||||
|
||||
return desc.str();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const ByteArray& CartridgeMNetworkWidget::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& CartridgeMNetworkWidget::internalRamCurrent(int start, int count)
|
||||
{
|
||||
myRamCurrent.clear();
|
||||
for(int i = 0; i < count; i++)
|
||||
myRamCurrent.push_back(myCart.myRAM[start + i]);
|
||||
return myRamCurrent;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeMNetworkWidget::internalRamSetValue(int addr, uInt8 value)
|
||||
{
|
||||
myCart.myRAM[addr] = value;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt8 CartridgeMNetworkWidget::internalRamGetValue(int addr)
|
||||
{
|
||||
return myCart.myRAM[addr];
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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-2017 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 CARTRIDGE_MNETWORK_WIDGET_HXX
|
||||
#define CARTRIDGE_MNETWORK_WIDGET_HXX
|
||||
|
||||
class CartridgeMNetwork;
|
||||
class PopUpWidget;
|
||||
|
||||
#include "CartDebugWidget.hxx"
|
||||
|
||||
class CartridgeMNetworkWidget : public CartDebugWidget
|
||||
{
|
||||
public:
|
||||
CartridgeMNetworkWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||
const GUI::Font& nfont,
|
||||
int x, int y, int w, int h,
|
||||
//CartridgeE7& cart);
|
||||
CartridgeMNetwork& cart);
|
||||
virtual ~CartridgeMNetworkWidget() = default;
|
||||
|
||||
protected:
|
||||
PopUpWidget *myLower2K, *myUpper256B;
|
||||
|
||||
//CartridgeE7& myCart;
|
||||
CartridgeMNetwork& myCart;
|
||||
|
||||
struct CartState
|
||||
{
|
||||
ByteArray internalram;
|
||||
};
|
||||
CartState myOldState;
|
||||
|
||||
enum
|
||||
{
|
||||
kLowerChanged = 'lwCH',
|
||||
kUpperChanged = 'upCH'
|
||||
};
|
||||
|
||||
protected:
|
||||
void initialize(GuiObject* boss, CartridgeMNetwork& cart, ostringstream& info);
|
||||
virtual const char* getSpotLower(int idx) = 0;
|
||||
virtual const char* getSpotUpper(int idx) = 0;
|
||||
|
||||
private:
|
||||
void saveOldState() override;
|
||||
void loadConfig() override;
|
||||
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
|
||||
string bankState();
|
||||
// start of functions for Cartridge RAM tab
|
||||
uInt32 internalRamSize() override;
|
||||
uInt32 internalRamRPort(int start) override;
|
||||
string internalRamDescription();
|
||||
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
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
CartridgeMNetworkWidget() = delete;
|
||||
CartridgeMNetworkWidget(const CartridgeMNetworkWidget&) = delete;
|
||||
CartridgeMNetworkWidget(CartridgeMNetworkWidget&&) = delete;
|
||||
CartridgeMNetworkWidget& operator=(const CartridgeMNetworkWidget&) = delete;
|
||||
CartridgeMNetworkWidget& operator=(CartridgeMNetworkWidget&&) = delete;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,47 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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-2017 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 "CartE78K.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
CartridgeE78K::CartridgeE78K(const BytePtr& image, uInt32 size,
|
||||
const Settings& settings)
|
||||
: CartridgeMNetwork(image, size, settings)
|
||||
{
|
||||
initialize(image, size);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeE78K::checkSwitchBank(uInt16 address)
|
||||
{
|
||||
// Switch banks if necessary
|
||||
if((address >= 0x0FE4) && (address <= 0x0FE7))
|
||||
{
|
||||
bank(address & 0x0003);
|
||||
}
|
||||
else if((address >= 0x0FE8) && (address <= 0x0FEB))
|
||||
{
|
||||
bankRAM(address & 0x0003);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt16 CartridgeE78K::bankCount() const
|
||||
{
|
||||
return 4;
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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-2017 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 CARTRIDGE_E78K_HXX
|
||||
#define CARTRIDGE_E78K_HXX
|
||||
|
||||
#include "bspf.hxx"
|
||||
#include "Cart.hxx"
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
#include "CartE78KWidget.hxx"
|
||||
#endif
|
||||
#include "CartMNetwork.hxx"
|
||||
|
||||
/**
|
||||
This is the cartridge class for 8K M-Network bankswitched games.
|
||||
|
||||
@author Bradford W. Mott, Thomas Jentzsch
|
||||
*/
|
||||
class CartridgeE78K : public CartridgeMNetwork
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Create a new cartridge using the specified image
|
||||
|
||||
@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)
|
||||
*/
|
||||
CartridgeE78K(const BytePtr& image, uInt32 size, const Settings& settings);
|
||||
virtual ~CartridgeE78K() = default;
|
||||
|
||||
public:
|
||||
/**
|
||||
Query the number of banks supported by the cartridge.
|
||||
*/
|
||||
uInt16 bankCount() const override;
|
||||
|
||||
/**
|
||||
Get a descriptor for the device name (used in error checking).
|
||||
|
||||
@return The name of the object
|
||||
*/
|
||||
string name() const override { return "CartridgeE78K"; }
|
||||
|
||||
#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 CartridgeE78KWidget(boss, lfont, nfont, x, y, w, h, *this);
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
/**
|
||||
Check hotspots and switch bank if triggered.
|
||||
*/
|
||||
void checkSwitchBank(uInt16 address) override;
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
CartridgeE78K() = delete;
|
||||
CartridgeE78K(const CartridgeE78K&) = delete;
|
||||
CartridgeE78K(CartridgeE78K&&) = delete;
|
||||
CartridgeE78K& operator=(const CartridgeE78K&) = delete;
|
||||
CartridgeE78K& operator=(CartridgeE78K&&) = delete;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,296 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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-2017 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 "CartMNetwork.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
CartridgeMNetwork::CartridgeMNetwork(const BytePtr& image, uInt32 size,
|
||||
const Settings& settings)
|
||||
: Cartridge(settings),
|
||||
myCurrentRAM(0)
|
||||
{}
|
||||
|
||||
void CartridgeMNetwork::initialize(const BytePtr& image, uInt32 size)
|
||||
{
|
||||
// Copy the ROM image into my buffer
|
||||
memcpy(myImage, image.get(), std::min(bankCount() * BANK_SIZE, size));
|
||||
createCodeAccessBase(bankCount() * BANK_SIZE + RAM_SIZE);
|
||||
|
||||
// Remember startup bank
|
||||
myStartBank = 0;
|
||||
myFixedSlice = bankCount() - 1;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeMNetwork::reset()
|
||||
{
|
||||
initializeRAM(myRAM, RAM_SIZE);
|
||||
|
||||
// Install some default banks for the RAM and first segment
|
||||
bankRAM(0);
|
||||
bank(myStartBank);
|
||||
|
||||
myBankChanged = true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeMNetwork::install(System& system)
|
||||
{
|
||||
mySystem = &system;
|
||||
|
||||
System::PageAccess access(this, System::PA_READ);
|
||||
|
||||
// Set the page accessing methods for the hot spots
|
||||
for(uInt16 addr = (0x1FE0 & ~System::PAGE_MASK); addr < 0x2000;
|
||||
addr += System::PAGE_SIZE)
|
||||
{
|
||||
access.codeAccessBase = &myCodeAccessBase[0x1fc0];
|
||||
mySystem->setPageAccess(addr, access);
|
||||
}
|
||||
|
||||
// Setup the second segment to always point to the last ROM slice
|
||||
for(uInt16 addr = 0x1A00; addr < (0x1FE0U & ~System::PAGE_MASK);
|
||||
addr += System::PAGE_SIZE)
|
||||
{
|
||||
access.directPeekBase = &myImage[myFixedSlice * BANK_SIZE + (addr & (BANK_SIZE-1))];
|
||||
access.codeAccessBase = &myCodeAccessBase[myFixedSlice * BANK_SIZE + (addr & (BANK_SIZE-1))];
|
||||
mySystem->setPageAccess(addr, access);
|
||||
}
|
||||
myCurrentSlice[1] = myFixedSlice;
|
||||
|
||||
// Install some default banks for the RAM and first segment
|
||||
bankRAM(0);
|
||||
bank(myStartBank);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt8 CartridgeMNetwork::peek(uInt16 address)
|
||||
{
|
||||
uInt16 peekAddress = address;
|
||||
address &= 0x0FFF;
|
||||
|
||||
// Switch banks if necessary
|
||||
checkSwitchBank(address);
|
||||
|
||||
if((myCurrentSlice[0] == myFixedSlice) && (address < 0x0400))
|
||||
{
|
||||
// Reading from the 1K write port @ $1000 triggers an unwanted write
|
||||
uInt8 value = mySystem->getDataBusState(0xFF);
|
||||
|
||||
if(bankLocked())
|
||||
return value;
|
||||
else
|
||||
{
|
||||
triggerReadFromWritePort(peekAddress);
|
||||
return myRAM[address & 0x03FF] = value;
|
||||
}
|
||||
}
|
||||
else if((address >= 0x0800) && (address <= 0x08FF))
|
||||
{
|
||||
// Reading from the 256B write port @ $1800 triggers an unwanted write
|
||||
uInt8 value = mySystem->getDataBusState(0xFF);
|
||||
|
||||
if(bankLocked())
|
||||
return value;
|
||||
else
|
||||
{
|
||||
triggerReadFromWritePort(peekAddress);
|
||||
return myRAM[1024 + (myCurrentRAM << 8) + (address & 0x00FF)] = value;
|
||||
}
|
||||
}
|
||||
else
|
||||
return myImage[(myCurrentSlice[address >> 11] << 11) + (address & (BANK_SIZE-1))];
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeMNetwork::poke(uInt16 address, uInt8)
|
||||
{
|
||||
address &= 0x0FFF;
|
||||
|
||||
// Switch banks if necessary
|
||||
checkSwitchBank(address);
|
||||
|
||||
// NOTE: This does not handle writing to RAM, however, this
|
||||
// method should never be called for RAM because of the
|
||||
// way page accessing has been setup
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeMNetwork::bankRAM(uInt16 bank)
|
||||
{
|
||||
if(bankLocked()) return;
|
||||
|
||||
// Remember what bank we're in
|
||||
myCurrentRAM = bank;
|
||||
uInt16 offset = bank << 8;
|
||||
|
||||
// Setup the page access methods for the current bank
|
||||
System::PageAccess access(this, System::PA_WRITE);
|
||||
|
||||
// Set the page accessing method for the 256 bytes of RAM writing pages
|
||||
for(uInt16 addr = 0x1800; addr < 0x1900; addr += System::PAGE_SIZE)
|
||||
{
|
||||
access.directPokeBase = &myRAM[1024 + offset + (addr & 0x00FF)];
|
||||
access.codeAccessBase = &myCodeAccessBase[0x2000 + 1024 + offset + (addr & 0x00FF)];
|
||||
mySystem->setPageAccess(addr, access);
|
||||
}
|
||||
|
||||
// Set the page accessing method for the 256 bytes of RAM reading pages
|
||||
access.directPokeBase = nullptr;
|
||||
access.type = System::PA_READ;
|
||||
for(uInt16 addr = 0x1900; addr < 0x1A00; addr += System::PAGE_SIZE)
|
||||
{
|
||||
access.directPeekBase = &myRAM[1024 + offset + (addr & 0x00FF)];
|
||||
access.codeAccessBase = &myCodeAccessBase[0x2000 + 1024 + offset + (addr & 0x00FF)];
|
||||
mySystem->setPageAccess(addr, access);
|
||||
}
|
||||
myBankChanged = true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeMNetwork::bank(uInt16 slice)
|
||||
{
|
||||
if(bankLocked()) return false;
|
||||
|
||||
// Remember what bank we're in
|
||||
myCurrentSlice[0] = slice;
|
||||
uInt16 offset = slice << 11;
|
||||
|
||||
// Setup the page access methods for the current bank
|
||||
if(slice != myFixedSlice)
|
||||
{
|
||||
System::PageAccess access(this, System::PA_READ);
|
||||
|
||||
// Map ROM image into first segment
|
||||
for(uInt16 addr = 0x1000; addr < 0x1800; addr += System::PAGE_SIZE)
|
||||
{
|
||||
access.directPeekBase = &myImage[offset + (addr & (BANK_SIZE-1))];
|
||||
access.codeAccessBase = &myCodeAccessBase[offset + (addr & (BANK_SIZE-1))];
|
||||
mySystem->setPageAccess(addr, access);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
System::PageAccess access(this, System::PA_WRITE);
|
||||
|
||||
// Set the page accessing method for the 1K slice of RAM writing pages
|
||||
for(uInt16 addr = 0x1000; addr < 0x1400; addr += System::PAGE_SIZE)
|
||||
{
|
||||
access.directPokeBase = &myRAM[addr & 0x03FF];
|
||||
access.codeAccessBase = &myCodeAccessBase[0x2000 + (addr & 0x03FF)];
|
||||
mySystem->setPageAccess(addr, access);
|
||||
}
|
||||
|
||||
// Set the page accessing method for the 1K slice of RAM reading pages
|
||||
access.directPokeBase = nullptr;
|
||||
access.type = System::PA_READ;
|
||||
for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE)
|
||||
{
|
||||
access.directPeekBase = &myRAM[addr & 0x03FF];
|
||||
access.codeAccessBase = &myCodeAccessBase[0x2000 + (addr & 0x03FF)];
|
||||
mySystem->setPageAccess(addr, access);
|
||||
}
|
||||
}
|
||||
return myBankChanged = true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt16 CartridgeMNetwork::getBank() const
|
||||
{
|
||||
return myCurrentSlice[0];
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeMNetwork::patch(uInt16 address, uInt8 value)
|
||||
{
|
||||
address = address & 0x0FFF;
|
||||
|
||||
if(address < 0x0800)
|
||||
{
|
||||
if(myCurrentSlice[0] == myFixedSlice)
|
||||
{
|
||||
// Normally, a write to the read port won't do anything
|
||||
// However, the patch command is special in that ignores such
|
||||
// cart restrictions
|
||||
myRAM[address & 0x03FF] = value;
|
||||
}
|
||||
else
|
||||
myImage[(myCurrentSlice[0] << 11) + (address & (BANK_SIZE-1))] = value;
|
||||
}
|
||||
else if(address < 0x0900)
|
||||
{
|
||||
// Normally, a write to the read port won't do anything
|
||||
// However, the patch command is special in that ignores such
|
||||
// cart restrictions
|
||||
myRAM[1024 + (myCurrentRAM << 8) + (address & 0x00FF)] = value;
|
||||
}
|
||||
else
|
||||
myImage[(myCurrentSlice[address >> 11] << 11) + (address & (BANK_SIZE-1))] = value;
|
||||
|
||||
return myBankChanged = true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const uInt8* CartridgeMNetwork::getImage(uInt32& size) const
|
||||
{
|
||||
size = bankCount() * BANK_SIZE;
|
||||
return myImage;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeMNetwork::save(Serializer& out) const
|
||||
{
|
||||
try
|
||||
{
|
||||
out.putString(name());
|
||||
out.putShortArray(myCurrentSlice, 2);
|
||||
out.putShort(myCurrentRAM);
|
||||
out.putByteArray(myRAM, RAM_SIZE);
|
||||
} catch(...)
|
||||
{
|
||||
cerr << "ERROR: " << name() << "::save" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeMNetwork::load(Serializer& in)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(in.getString() != name())
|
||||
return false;
|
||||
|
||||
in.getShortArray(myCurrentSlice, 2);
|
||||
myCurrentRAM = in.getShort();
|
||||
in.getByteArray(myRAM, RAM_SIZE);
|
||||
} catch(...)
|
||||
{
|
||||
cerr << "ERROR: " << name() << "::load" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set up the previously used banks for the RAM and segment
|
||||
bankRAM(myCurrentRAM);
|
||||
bank(myCurrentSlice[0]);
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,202 @@
|
|||
|
||||
//============================================================================
|
||||
//
|
||||
// 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-2017 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 CARTRIDGE_MNETWORK_HXX
|
||||
#define CARTRIDGE_MNETWORK_HXX
|
||||
|
||||
class System;
|
||||
|
||||
#include "bspf.hxx"
|
||||
#include "Cart.hxx"
|
||||
|
||||
/**
|
||||
This is the abstract cartridge class for M-Network
|
||||
bankswitched games.
|
||||
In this bankswitching scheme the 2600's 4K cartridge address
|
||||
space is broken into two 2K segments.
|
||||
|
||||
Kevin Horton describes E7 as follows:
|
||||
|
||||
"Only M-Network used this scheme. This has to be the
|
||||
most complex method used in any cart! :-) It allows
|
||||
for the capability of 2K of RAM; although it doesn't
|
||||
have to be used (in fact, only one cart used it).
|
||||
There are now 8 2K banks, instead of 4. The last 2K
|
||||
in the cart always points to the last 2K of the ROM
|
||||
image, while the first 2K is selectable. You access
|
||||
1FE0 to 1FE6 to select which 2K bank. Note that you
|
||||
cannot select the last 2K of the ROM image into the
|
||||
lower 2K of the cart! Accessing 1FE7 selects 1K of
|
||||
RAM at 1000-17FF instead of ROM! The 2K of RAM is
|
||||
broken up into two 1K sections. One 1K section is
|
||||
mapped in at 1000-17FF if 1FE7 has been accessed.
|
||||
1000-13FF is the write port, while 1400-17FF is the
|
||||
read port. The second 1K of RAM appears at 1800-19FF.
|
||||
1800-18FF is the write port while 1900-19FF is the
|
||||
read port. You select which 256 byte block appears
|
||||
here by accessing 1FE8 to 1FEB.
|
||||
|
||||
This cart reports having 8 banks; 1 for each of the possible 7
|
||||
slices in the lower 2K area, and the last for RAM in the lower
|
||||
2K area."
|
||||
|
||||
There are 8K and 16K variations.
|
||||
|
||||
@author Bradford W. Mott, Thomas Jentzsch
|
||||
*/
|
||||
class CartridgeMNetwork : public Cartridge
|
||||
{
|
||||
friend class CartridgeMNetworkWidget;
|
||||
friend class CartridgeE7Widget;
|
||||
friend class CartridgeE78KWidget;
|
||||
|
||||
public:
|
||||
/**
|
||||
Create a new cartridge using the specified image
|
||||
|
||||
@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)
|
||||
*/
|
||||
CartridgeMNetwork(const BytePtr& image, uInt32 size, const Settings& settings);
|
||||
virtual ~CartridgeMNetwork() = 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;
|
||||
|
||||
/**
|
||||
Install pages for the specified bank in the system.
|
||||
|
||||
@param bank The bank that should be installed in the system
|
||||
*/
|
||||
bool bank(uInt16 bank) override;
|
||||
|
||||
/**
|
||||
Get the current bank.
|
||||
*/
|
||||
uInt16 getBank() const 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(uInt32& 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;
|
||||
|
||||
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;
|
||||
|
||||
protected:
|
||||
/**
|
||||
Class initialization
|
||||
*/
|
||||
void initialize(const BytePtr& image, uInt32 size);
|
||||
|
||||
/**
|
||||
Install pages for the specified 256 byte bank of RAM
|
||||
|
||||
@param bank The bank that should be installed in the system
|
||||
*/
|
||||
void bankRAM(uInt16 bank);
|
||||
|
||||
private:
|
||||
const uInt32 BANK_SIZE = 0x800;
|
||||
const uInt32 RAM_SIZE = 0x800;
|
||||
|
||||
/**
|
||||
Check hotspots and switch bank if triggered.
|
||||
*/
|
||||
virtual void checkSwitchBank(uInt16 address) = 0;
|
||||
|
||||
private:
|
||||
// The 16K ROM image of the cartridge
|
||||
uInt8 myImage[16384];
|
||||
|
||||
// The 2048 bytes of RAM
|
||||
uInt8 myRAM[2048];
|
||||
|
||||
// Indicates which slice is in the segment
|
||||
uInt16 myCurrentSlice[2];
|
||||
|
||||
// Indicates which 256 byte bank of RAM is being used
|
||||
uInt16 myCurrentRAM;
|
||||
|
||||
// The number of the fixed slice (bankCount() - 1)
|
||||
uInt32 myFixedSlice;
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
CartridgeMNetwork() = delete;
|
||||
CartridgeMNetwork(const CartridgeMNetwork&) = delete;
|
||||
CartridgeMNetwork(CartridgeMNetwork&&) = delete;
|
||||
CartridgeMNetwork& operator=(const CartridgeMNetwork&) = delete;
|
||||
CartridgeMNetwork& operator=(CartridgeMNetwork&&) = delete;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue