Added support for SB "SUPERbanking" 128k-256k bankswitched games. Thanks

to Fred Quimby (aka Batari) for the code.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1389 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2007-10-12 14:45:10 +00:00
parent 2ad8f1efac
commit 62860e8b81
7 changed files with 501 additions and 33 deletions

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Cart.cxx,v 1.34 2007-06-14 13:47:50 stephena Exp $
// $Id: Cart.cxx,v 1.35 2007-10-12 14:45:10 stephena Exp $
//============================================================================
#include <cassert>
@ -43,6 +43,7 @@
#include "CartMB.hxx"
#include "CartCV.hxx"
#include "CartUA.hxx"
#include "CartSB.hxx"
#include "MD5.hxx"
#include "Props.hxx"
#include "Settings.hxx"
@ -133,6 +134,8 @@ Cartridge* Cartridge::create(const uInt8* image, uInt32 size,
cartridge = new CartridgeUA(image);
else if(type == "0840")
cartridge = new Cartridge0840(image);
else if(type == "SB")
cartridge = new CartridgeSB(image, size);
else
cerr << "ERROR: Invalid cartridge type " << type << " ..." << endl;
@ -250,21 +253,25 @@ string Cartridge::autodetectType(const uInt8* image, uInt32 size)
}
else if(size == 65536) // 64K
{
// TODO - autodetect 4A50
if(isProbably3E(image, size))
type = "3E";
else if(isProbably3F(image, size))
type = "3F";
else if(isProbably4A50(image, size))
type = "4A50";
else
type = "MB";
}
else if(size == 131072) // 128K
{
// TODO - autodetect 4A50
if(isProbably3E(image, size))
type = "3E";
else if(isProbably3F(image, size))
type = "3F";
else if(isProbably4A50(image, size))
type = "4A50";
else if(isProbablySB(image, size))
type = "SB";
else
type = "MC";
}
@ -418,6 +425,20 @@ bool Cartridge::isProbablyUA(const uInt8* image, uInt32 size)
return searchForBytes(image, size, signature, 3, 1);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Cartridge::isProbably4A50(const uInt8* image, uInt32 size)
{
// TODO - add autodetection for this type
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Cartridge::isProbablySB(const uInt8* image, uInt32 size)
{
// TODO - add autodetection for this type
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Cartridge::isProbablyCV(const uInt8* image, uInt32 size)
{

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Cart.hxx,v 1.20 2007-10-03 21:41:17 stephena Exp $
// $Id: Cart.hxx,v 1.21 2007-10-12 14:45:10 stephena Exp $
//============================================================================
#ifndef CARTRIDGE_HXX
@ -34,7 +34,7 @@ class Settings;
game and handles any bankswitching performed by the cartridge.
@author Bradford W. Mott
@version $Id: Cart.hxx,v 1.20 2007-10-03 21:41:17 stephena Exp $
@version $Id: Cart.hxx,v 1.21 2007-10-12 14:45:10 stephena Exp $
*/
class Cartridge : public Device
{
@ -202,6 +202,16 @@ class Cartridge : public Device
*/
static bool isProbablyUA(const uInt8* image, uInt32 size);
/**
Returns true if the image is probably a 4A50 bankswitching cartridge
*/
static bool isProbably4A50(const uInt8* image, uInt32 size);
/**
Returns true if the image is probably a SB bankswitching cartridge
*/
static bool isProbablySB(const uInt8* image, uInt32 size);
/**
Returns true if the image is probably a CV bankswitching cartridge
*/

View File

@ -0,0 +1,279 @@
//============================================================================
//
// 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-2005 by Bradford W. Mott and the Stella team
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: CartSB.cxx,v 1.0 2007/10/11
//============================================================================
#include <cassert>
#include "System.hxx"
#include "CartSB.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeSB::CartridgeSB(const uInt8* image, uInt32 size)
: mySize(size)
{
// Allocate array for the ROM image
myImage = new uInt8[mySize];
// Copy the ROM image into my buffer
for(uInt32 addr = 0; addr < mySize; ++addr)
{
myImage[addr] = image[addr];
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeSB::~CartridgeSB()
{
delete[] myImage;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeSB::reset()
{
// Upon reset we switch to bank 0
bank(0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeSB::install(System& system)
{
mySystem = &system;
uInt16 shift = mySystem->pageShift();
uInt16 mask = mySystem->pageMask();
// Make sure the system we're being installed in has a page size that'll work
assert((0x1000 & mask) == 0);
// Get the page accessing methods for the hot spots since they overlap
// areas within the TIA we'll need to forward requests to the TIA
myHotSpotPageAccess0 = mySystem->getPageAccess(0x0800 >> shift);
myHotSpotPageAccess1 = mySystem->getPageAccess(0x0900 >> shift);
myHotSpotPageAccess2 = mySystem->getPageAccess(0x0A00 >> shift);
myHotSpotPageAccess3 = mySystem->getPageAccess(0x0B00 >> shift);
myHotSpotPageAccess4 = mySystem->getPageAccess(0x0C00 >> shift);
myHotSpotPageAccess5 = mySystem->getPageAccess(0x0D00 >> shift);
myHotSpotPageAccess6 = mySystem->getPageAccess(0x0E00 >> shift);
myHotSpotPageAccess7 = mySystem->getPageAccess(0x0F00 >> shift);
// Set the page accessing methods for the hot spots
System::PageAccess access;
for(uInt32 i = 0x0800; i < 0x0FFF; i += (1 << shift))
{
access.directPeekBase = 0;
access.directPokeBase = 0;
access.device = this;
mySystem->setPageAccess(i >> shift, access);
}
// Install pages for bank 0
bank(0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeSB::peek(uInt16 address)
{
address = address & (0x17FF+(mySize>>12));
// Switch banks if necessary
if ((address & 0x1800) == 0x0800) bank(address & ((mySize>>12)-1));
if(!(address & 0x1000))
{
switch (address & 0x0F00)
{
case 0x0800:
return myHotSpotPageAccess0.device->peek(address);
break;
case 0x0900:
return myHotSpotPageAccess1.device->peek(address);
break;
case 0x0A00:
return myHotSpotPageAccess2.device->peek(address);
break;
case 0x0B00:
return myHotSpotPageAccess3.device->peek(address);
break;
case 0x0C00:
return myHotSpotPageAccess4.device->peek(address);
break;
case 0x0D00:
return myHotSpotPageAccess5.device->peek(address);
break;
case 0x0E00:
return myHotSpotPageAccess6.device->peek(address);
break;
case 0x0F00:
return myHotSpotPageAccess7.device->peek(address);
break;
default:
break;
}
}
else
{
return 0;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeSB::poke(uInt16 address, uInt8 value)
{
address = address & (0x17FF+(mySize>>12));
// Switch banks if necessary
if ((address & 0x1800) == 0x0800) bank(address & ((mySize>>12)-1));
if(!(address & 0x1000))
{
switch (address & 0x0F00)
{
case 0x0800:
return myHotSpotPageAccess0.device->poke(address, value);
break;
case 0x0900:
return myHotSpotPageAccess1.device->poke(address, value);
break;
case 0x0A00:
return myHotSpotPageAccess2.device->poke(address, value);
break;
case 0x0B00:
return myHotSpotPageAccess3.device->poke(address, value);
break;
case 0x0C00:
return myHotSpotPageAccess4.device->poke(address, value);
break;
case 0x0D00:
return myHotSpotPageAccess5.device->poke(address, value);
break;
case 0x0E00:
return myHotSpotPageAccess6.device->poke(address, value);
break;
case 0x0F00:
return myHotSpotPageAccess7.device->poke(address, value);
break;
default:
break;
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeSB::bank(uInt16 bank)
{
if(bankLocked) return;
// Remember what bank we're in
myCurrentBank = bank;
uInt32 offset = myCurrentBank * 4096;
uInt16 shift = mySystem->pageShift();
// uInt16 mask = mySystem->pageMask();
// Setup the page access methods for the current bank
System::PageAccess access;
access.device = this;
access.directPokeBase = 0;
// Map ROM image into the system
for(uInt32 address = 0x1000; address < 0x2000; address += (1 << shift))
{
access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
mySystem->setPageAccess(address >> shift, access);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int CartridgeSB::bank()
{
return myCurrentBank;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int CartridgeSB::bankCount()
{
return mySize>>12;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeSB::patch(uInt16 address, uInt8 value)
{
address &= 0x0fff;
myImage[myCurrentBank * 4096] = value;
bank(myCurrentBank); // TODO: see if this is really necessary
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8* CartridgeSB::getImage(int& size)
{
size = mySize;
return &myImage[0];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeSB::save(Serializer& out) const
{
string cart = name();
try
{
out.putString(cart);
out.putInt(myCurrentBank);
}
catch(char *msg)
{
cerr << msg << endl;
return false;
}
catch(...)
{
cerr << "Unknown error in save state for " << cart << endl;
return false;
}
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeSB::load(Deserializer& in)
{
string cart = name();
try
{
if(in.getString() != cart)
return false;
myCurrentBank = (uInt16)in.getInt();
}
catch(char *msg)
{
cerr << msg << endl;
return false;
}
catch(...)
{
cerr << "Unknown error in load state for " << cart << endl;
return false;
}
// Remember what bank we were in
bank(myCurrentBank);
return true;
}

View File

@ -0,0 +1,156 @@
//============================================================================
//
// 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-2005 by Bradford W. Mott and the Stella team
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: CartSB.hxx,v 1.0 2007/10/11
//============================================================================
#ifndef CARTRIDGESB_HXX
#define CARTRIDGESB_HXX
class System;
#include "bspf.hxx"
#include "Cart.hxx"
/**
Cartridge class used for SB "SUPERbanking" 128k-256k bankswitched games.
There are either 32 or 64 4K banks.
@author Fred X. Quimby
*/
class CartridgeSB : public Cartridge
{
public:
/**
Create a new cartridge using the specified image
@param image Pointer to the ROM image
*/
CartridgeSB(const uInt8* image, uInt32 size);
/**
Destructor
*/
virtual ~CartridgeSB();
public:
/**
Reset device to its power-on state
*/
virtual void reset();
/**
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
*/
virtual void install(System& system);
/**
Install pages for the specified bank in the system.
@param bank The bank that should be installed in the system
*/
virtual void bank(uInt16 bank);
/**
Get the current bank.
@return The current bank, or -1 if bankswitching not supported
*/
virtual int bank();
/**
Query the number of banks supported by the cartridge.
*/
virtual int bankCount();
/**
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
*/
virtual bool patch(uInt16 address, uInt8 value);
/**
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
*/
virtual uInt8* getImage(int& size);
/**
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
*/
virtual bool save(Serializer& out) const;
/**
Load the current state of this cart from the given Deserializer.
@param in The Deserializer object to use
@return False on any errors, else true
*/
virtual bool load(Deserializer& in);
/**
Get a descriptor for the device name (used in error checking).
@return The name of the object
*/
virtual string name() const { return "CartridgeSB"; }
public:
/**
Get the byte at the specified address.
@return The byte at the specified address
*/
virtual uInt8 peek(uInt16 address);
/**
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
*/
virtual void poke(uInt16 address, uInt8 value);
private:
// Indicates which bank is currently active
uInt16 myCurrentBank;
// The 128-256K ROM image and size of the cartridge
uInt8* myImage;
uInt32 mySize;
// Previous Device's page access
System::PageAccess myHotSpotPageAccess0;
System::PageAccess myHotSpotPageAccess1;
System::PageAccess myHotSpotPageAccess2;
System::PageAccess myHotSpotPageAccess3;
System::PageAccess myHotSpotPageAccess4;
System::PageAccess myHotSpotPageAccess5;
System::PageAccess myHotSpotPageAccess6;
System::PageAccess myHotSpotPageAccess7;
};
#endif

View File

@ -24,6 +24,7 @@ MODULE_OBJS := \
src/emucore/CartFE.o \
src/emucore/CartMB.o \
src/emucore/CartMC.o \
src/emucore/CartSB.o \
src/emucore/CartUA.o \
src/emucore/Cart0840.o \
src/emucore/Console.o \

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: GameInfoDialog.cxx,v 1.44 2007-10-09 23:56:57 stephena Exp $
// $Id: GameInfoDialog.cxx,v 1.45 2007-10-12 14:45:10 stephena Exp $
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
@ -116,10 +116,10 @@ GameInfoDialog::GameInfoDialog(
ypos += lineHeight + 3;
new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight,
"Type:", kTextAlignLeft);
pwidth = font.getStringWidth("CV (Commavid extra ram)");
pwidth = font.getStringWidth("SB (128-256k SUPERbanking)");
myType = new PopUpWidget(myTab, font, xpos+lwidth, ypos,
pwidth, lineHeight, "", 0, 0);
for(i = 0; i < 22; ++i)
for(i = 0; i < 23; ++i)
myType->appendEntry(ourCartridgeList[i][0], i+1);
wid.push_back(myType);
@ -681,27 +681,28 @@ const char* GameInfoDialog::ourControllerList[5][2] = {
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* GameInfoDialog::ourCartridgeList[22][2] = {
{ "Auto-detect", "AUTO-DETECT" },
{ "2K (2K Atari)", "2K" },
{ "3E (32K Tigervision)", "3E" },
{ "3F (512K Tigervision)", "3F" },
{ "4A50 (64K 4A50 + ram)", "4A50" },
{ "4K (4K Atari)", "4K" },
{ "AR (Supercharger)", "AR" },
{ "CV (Commavid extra ram)", "CV" },
{ "DPC (Pitfall II)", "DPC" },
{ "E0 (8K Parker Bros)", "E0" },
{ "E7 (16K M-network)", "E7" },
{ "F4 (32K Atari)", "F4" },
{ "F4SC (32K Atari + ram)", "F4SC" },
{ "F6 (16K Atari)", "F6" },
{ "F6SC (16K Atari + ram)", "F6SC" },
{ "F8 (8K Atari)", "F8" },
{ "F8SC (8K Atari + ram)", "F8SC" },
{ "FASC (CBS RAM Plus)", "FASC" },
{ "FE (8K Decathlon)", "FE" },
{ "MB (Dynacom Megaboy)", "MB" },
{ "MC (C. Wilkson Megacart)", "MC" },
{ "UA (8K UA Ltd.)", "UA" }
const char* GameInfoDialog::ourCartridgeList[23][2] = {
{ "Auto-detect", "AUTO-DETECT" },
{ "2K (2K Atari)", "2K" },
{ "3E (32K Tigervision)", "3E" },
{ "3F (512K Tigervision)", "3F" },
{ "4A50 (64K 4A50 + ram)", "4A50" },
{ "4K (4K Atari)", "4K" },
{ "AR (Supercharger)", "AR" },
{ "CV (Commavid extra ram)", "CV" },
{ "DPC (Pitfall II)", "DPC" },
{ "E0 (8K Parker Bros)", "E0" },
{ "E7 (16K M-network)", "E7" },
{ "F4 (32K Atari)", "F4" },
{ "F4SC (32K Atari + ram)", "F4SC" },
{ "F6 (16K Atari)", "F6" },
{ "F6SC (16K Atari + ram)", "F6SC" },
{ "F8 (8K Atari)", "F8" },
{ "F8SC (8K Atari + ram)", "F8SC" },
{ "FASC (CBS RAM Plus)", "FASC" },
{ "FE (8K Decathlon)", "FE" },
{ "MB (Dynacom Megaboy)", "MB" },
{ "MC (C. Wilkson Megacart)", "MC" },
{ "SB (128-256k SUPERbanking)", "SB" },
{ "UA (8K UA Ltd.)", "UA" }
};

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: GameInfoDialog.hxx,v 1.25 2007-10-09 23:56:57 stephena Exp $
// $Id: GameInfoDialog.hxx,v 1.26 2007-10-12 14:45:10 stephena Exp $
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
@ -107,7 +107,7 @@ class GameInfoDialog : public Dialog, public CommandSender
bool myDefaultsSelected;
/** Holds static strings for Cartridge type */
static const char* ourCartridgeList[22][2];
static const char* ourCartridgeList[23][2];
/** Holds static strings for Controller type */
static const char* ourControllerList[5][2];