Added preliminary support for DASH bankswitching scheme by A. Davie.

This hasn't been tested yet, since no ROMs currently exist.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2895 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2014-06-02 20:41:19 +00:00
parent 8f2123a5bf
commit e81f2b0ffd
9 changed files with 693 additions and 1 deletions

View File

@ -14,6 +14,8 @@
3.9.3 to 4.0: (xxxx xx, 2014)
* Added preliminary support for 'DASH' bankswitching scheme by A. Davie.
* Added 'savesnap' debugger prompt command, and also associated
context menu item to the debugger TIA output area. This saves the
current TIA image to a PNG file.

View File

@ -3199,6 +3199,7 @@ Ms Pac-Man (Stella extended codes):
<tr><td>BFSC </td><td>CPUWIZ 256K + ram</td></tr>
<tr><td>CM &#185;</td><td>Spectravideo CompuMate </td></tr>
<tr><td>CV </td><td>Commavid extra ram </td></tr>
<tr><td>DASH </td><td>Boulder Dash 2 </td></tr>
<tr><td>DF </td><td>CPUWIZ 128K </td></tr>
<tr><td>DFSC </td><td>CPUWIZ 128K + ram</td></tr>
<tr><td>DPC </td><td>Pitfall II </td></tr>

View File

@ -34,6 +34,7 @@
#include "CartCM.hxx"
#include "CartCTY.hxx"
#include "CartCV.hxx"
#include "CartDASH.hxx"
#include "CartDPC.hxx"
#include "CartDPCPlus.hxx"
#include "CartE0.hxx"
@ -199,6 +200,8 @@ Cartridge* Cartridge::create(const uInt8* image, uInt32 size, string& md5,
cartridge = new CartridgeCTY(image, size, osystem);
else if(type == "CV")
cartridge = new CartridgeCV(image, size, settings);
else if(type == "DASH")
cartridge = new CartridgeDASH(image, size, settings);
else if(type == "DPC")
cartridge = new CartridgeDPC(image, size, settings);
else if(type == "DPC+")
@ -579,6 +582,7 @@ bool Cartridge::isProbablySC(const uInt8* image, uInt32 size)
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Cartridge::isProbably4KSC(const uInt8* image, uInt32 size)
{
// We check if the first 256 bytes are identical *and* if there's
@ -595,7 +599,6 @@ bool Cartridge::isProbably4KSC(const uInt8* image, uInt32 size)
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Cartridge::isProbablyARM(const uInt8* image, uInt32 size)
{
@ -696,6 +699,12 @@ bool Cartridge::isProbablyCV(const uInt8* image, uInt32 size)
return searchForBytes(image, size, signature[1], 3, 1);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Cartridge::isProbablyDASH(const uInt8* image, uInt32 size)
{
return false; // TODO - add autodetection
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Cartridge::isProbablyDPCplus(const uInt8* image, uInt32 size)
{

View File

@ -323,6 +323,11 @@ class Cartridge : public Device
*/
static bool isProbablyCV(const uInt8* image, uInt32 size);
/**
Returns true if the image is probably a DASH bankswitching cartridge
*/
static bool isProbablyDASH(const uInt8* image, uInt32 size);
/**
Returns true if the image is probably a DPC+ bankswitching cartridge
*/

366
src/emucore/CartDASH.cxx Normal file
View File

@ -0,0 +1,366 @@
//============================================================================
//
// 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-2014 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 <cassert>
#include <cstring>
#include "System.hxx"
#include "TIA.hxx"
#include "CartDASH.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeDASH::CartridgeDASH(const uInt8* image, uInt32 size, const Settings& settings)
: Cartridge(settings),
mySize(size)
{
// Allocate array for the ROM image
myImage = new uInt8[mySize];
// Copy the ROM image into my buffer
memcpy(myImage, image, mySize);
createCodeAccessBase(mySize + RAM_TOTAL_SIZE);
// This cart can address 4 banks of RAM, each 512 bytes @ 1000, 1200, 1400, 1600
// However, it may not be addressable all the time (it may be swapped out)
// TODO: Stephen -- is this correct for defining 4 separate RAM areas, or can it be done as one block?
registerRamArea(0x1000, RAM_BANK_SIZE, 0x00, RAM_WRITE_OFFSET); // 512 bytes RAM @ 0x1000
registerRamArea(0x1200, RAM_BANK_SIZE, 0x00, RAM_WRITE_OFFSET); // 512 bytes RAM @ 0x1200
registerRamArea(0x1400, RAM_BANK_SIZE, 0x00, RAM_WRITE_OFFSET); // 512 bytes RAM @ 0x1400
registerRamArea(0x1600, RAM_BANK_SIZE, 0x00, RAM_WRITE_OFFSET); // 512 bytes RAM @ 0x1600
// Remember startup bank (0 per spec, rather than last per 3E scheme).
// Set this to go to 3rd 1K Bank.
myStartBank = (3 << BANK_BITS) | 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeDASH::~CartridgeDASH()
{
delete[] myImage;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeDASH::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);
// We'll map the startup bank (0) from the image into the third 1K bank upon reset
bank(myStartBank);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeDASH::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((0x1800 & mask) == 0);
System::PageAccess access(0, 0, 0, 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 << shift))
mySystem->setPageAccess(i >> shift, access);
// 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
access.type = System::PA_READ;
for (uInt32 byte = 0; byte < ROM_BANK_SIZE; byte++)
{
uInt32 address = (0x1000 - ROM_BANK_SIZE) + (byte<<shift); // which byte in last bank of 2600 address space
access.directPeekBase = &myImage[byte]; // from base address 0x0000 in image, so just use 'byte'
access.codeAccessBase = &myCodeAccessBase[byte];
mySystem->setPageAccess(address>>shift, access);
// TODO: Stephen: in this and other implementations we appear to be using "shift" as a system-dependant mangle for
// different access types (byte/int/32bit) on different architectures. I think I understand that much. However,
// I have an issue with how these loops are encoded in all the bank schemes I've seen. The issue being that
// the loop inits set some address (e.g., 0x1800) and then add a shifted value to it every loop. But when
// they want to get the downshifted value, they just shift down the whole value. Which will also shift down that base address
// and that makes no sense at all to me. I don't understand it.
}
// Initialise bank values for the 4x 1K bank areas
// This is used to reverse-lookup from address to bank location
for(uInt32 b = 0; b < 3; b++)
bankInUse[b] = BANK_UNDEFINED; // bank is undefined and inaccessible!
// Install pages for the startup bank into the first segment
bank(myStartBank);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeDASH::peek(uInt16 address)
{
uInt8 value = 0;
uInt32 bank = (address >> 10) & 3; // convert to 1K bank index (0-3)
Int16 imageBank = bankInUse[bank]; // the ROM/RAM bank that's here
if(imageBank <= BANK_UNDEFINED)
{
// accessing invalid bank, so return should be... random?
// TODO: Stephen -- throw some sort of error; looking at undefined data
assert(false);
value = mySystem->randGenerator().next();
}
else if(imageBank < ROM_BANK_COUNT) // accessing ROM
{
Int32 offset = imageBank << ROM_BANK_TO_POWER; // base bank address in image
offset += (address & (ROM_BANK_SIZE-1)); // + byte offset in image bank
value = myImage[offset];
}
else // must be a RAM bank
{
Int32 ramBank = imageBank - ROM_BANK_COUNT;
assert(ramBank < RAM_BANK_COUNT); // would be bad, otherwise
Int32 offset = ramBank << RAM_BANK_TO_POWER; // base bank address in RAM
offset += (address & (RAM_BANK_SIZE-1)); // + byte offset in RAM bank
value = myRAM[offset];
}
return value;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeDASH::poke(uInt16 address, uInt8 value)
{
address &= 0x0FFF; // restrict to 4K address range
// Check for write to 3E (RAM switching) or 3F (ROM switching) and switch
// banks if necessary. There are NO mirrored hotspots.
switch (address)
{
case 0x3F: // a ROM switch
assert(value < ROM_BANK_COUNT);
bank(value);
break;
case 0x3E: // a RAM switch
assert(value < RAM_BANK_COUNT);
bank(ROMRAM|value);
break;
}
// @THOMAS -- well, really we don't need to use 3E and 3F -- we can just use (say) 3E
// and the value determines if we're doing RAM(64+bank) or ROM(bank) writes.
// No need to have two addresses at all, right?
// 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 false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeDASH::bank(uInt16 bank)
{
if(bankLocked())
return false; // TODO: Stephen -- ? no idea
uInt16 shift = mySystem->pageShift();
uInt16 bankNumber = (bank >> BANK_BITS) & 3; // which bank # we are switching TO (BITS D6,D7)
uInt16 bankID = bank & BIT_BANK_MASK; // The actual bank # to switch in (BITS D5-D0)
if(bank & ROMRAM) // switching to a 512 byte RAM bank
{
// Wrap around/restrict to valid range
uInt16 currentBank = (bank & BIT_BANK_MASK) % RAM_BANK_COUNT;
// Record which bank switched in (marked as RAM)
myCurrentBank = bankInUse[bankNumber] = (Int16) (ROM_BANK_COUNT + currentBank);
// Effectively * 512 bytes
uInt32 startCurrentBank = currentBank << RAM_BANK_TO_POWER;
// Setup the page access methods for the current bank
System::PageAccess access(0, 0, 0, this, System::PA_READ);
// Map read-port RAM image into the system
for(uInt32 byte = 0; byte < RAM_BANK_SIZE; byte += (1 << shift))
{
access.directPeekBase = &myRAM[startCurrentBank + byte];
// TODO: Stephen please explain/review the use of mySize as an offset for RAM access here....
access.codeAccessBase = &myCodeAccessBase[mySize + startCurrentBank + byte]; //?eh
mySystem->setPageAccess((startCurrentBank + byte) >> shift, access);
}
access.directPeekBase = 0;
access.type = System::PA_WRITE;
// Map write-port RAM image into the system
for (uInt32 byte = 0; byte < RAM_BANK_SIZE; byte += (1 << shift))
{
access.directPokeBase = &myRAM[startCurrentBank + RAM_WRITE_OFFSET + byte];
access.codeAccessBase = &myCodeAccessBase[mySize + startCurrentBank + RAM_WRITE_OFFSET + byte];
mySystem->setPageAccess((startCurrentBank + byte) >> shift, access);
}
}
else // ROM 1K banks
{
// Map ROM bank image into the system into the correct slot
// Memory map is 1K slots at 0x1000, 0x1400, 0x1800, 0x1C00
// Record which bank switched in (as ROM)
myCurrentBank = bankInUse[bankNumber] = (Int16) bankID;
// Effectively *1K
uInt32 startCurrentBank = bankID << ROM_BANK_TO_POWER;
// Setup the page access methods for the current bank
System::PageAccess access(0, 0, 0, this, System::PA_READ);
uInt32 bankStart = 0x1000 + (bankNumber << ROM_BANK_TO_POWER); // *1K
for (uInt32 byte = 0; byte < ROM_BANK_SIZE; byte += (1 << shift))
{
access.directPeekBase = &myImage[startCurrentBank + byte];
access.codeAccessBase = &myCodeAccessBase[startCurrentBank + byte];
mySystem->setPageAccess((bankStart + byte) >> shift, access);
}
}
return myBankChanged = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeDASH::bank() const
{
// TODO: Stephen -- what to do here? We don't really HAVE a "current bank"; we have 4 banks
// and they are defined in bankInUse[...].
// What I've done is kept track of the last switched bank, and return that. But that doesn't tell us WHERE. :(
return myCurrentBank;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 CartridgeDASH::bankCount() const
{
// Because the RAM banks always start above the ROM banks (see ROM_BANK_COUNT) for value,
// we require the number of ROM banks to be == ROM_BANK_COUNT. Banks are therefore 0-63 ROM 64-127 RAM
// TODO: Stephen -- ROM banks are 1K. RAM banks are 512 bytes. How does this affect what this routine should return?
return ROM_BANK_COUNT + RAM_BANK_COUNT;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeDASH::patch(uInt16 address, uInt8 value)
{
// Patch the cartridge ROM
// TODO: Stephen... I assume this is for some sort of debugger support....?
myBankChanged = true;
uInt32 bankNumber = (address >> 10) & 3; // now 1K bank # (ie: 0-3)
Int32 whichBankIsThere = bankInUse[bankNumber]; // ROM or RAM bank reference
if(whichBankIsThere <= BANK_UNDEFINED)
{
// We're trying to access undefined memory (no bank here yet)
// TODO: Stephen -- what to do here? Fail silently?
// want to throw some sort of Stella error -- trying to patch an unswitched in bank!
assert(false);
myBankChanged = false;
}
else if(whichBankIsThere < ROM_BANK_COUNT) // patching ROM (1K banks)
{
uInt32 byteOffset = address & (ROM_BANK_SIZE-1);
uInt32 baseAddress = (whichBankIsThere << ROM_BANK_TO_POWER) + byteOffset;
myImage[baseAddress] = value; // write to the image
}
else // patching RAM (512 byte banks)
{
uInt32 byteOffset = address & (RAM_BANK_SIZE-1);
uInt32 baseAddress = ((whichBankIsThere - ROM_BANK_COUNT) << RAM_BANK_TO_POWER) + byteOffset;
myRAM[baseAddress] = value; // write to RAM
}
return myBankChanged;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt8* CartridgeDASH::getImage(int& size) const
{
size = mySize;
return myImage;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeDASH::save(Serializer& out) const
{
try
{
out.putString(name());
out.putShort(myCurrentBank);
for(uInt32 bank = 0; bank < 4; bank++)
out.putShort(bankInUse[bank]);
out.putByteArray(myRAM, RAM_TOTAL_SIZE);
}
catch (...)
{
cerr << "ERROR: CartridgeDASH::save" << endl;
return false;
}
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeDASH::load(Serializer& in)
{
try
{
if(in.getString() != name())
return false;
myCurrentBank = in.getShort();
for(uInt32 bank = 0; bank < 4; bank++)
bankInUse[bank] = in.getShort();
in.getByteArray(myRAM, RAM_TOTAL_SIZE);
}
catch (...)
{
cerr << "ERROR: CartridgeDASH::load" << endl;
return false;
}
// Now, go to the current bank
bank(myCurrentBank);
return true;
}

306
src/emucore/CartDASH.hxx Normal file
View File

@ -0,0 +1,306 @@
//============================================================================
//
// 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-2014 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 CARTRIDGEDASH_HXX
#define CARTRIDGEDASH_HXX
class System;
#include "bspf.hxx"
#include "Cart.hxx"
#ifdef DEBUGGER_SUPPORT
class CartridgeDASHWidget;
// #include "CartDASHWidget.hxx"
#endif
/**
Cartridge class for new tiling engine "Boulder Dash" format games with RAM.
Kind of a combination of 3F and 3E, with better switchability.
This code is B.Watson's Cart3E modified to new specs by Andrew Davie.
Note: because a single bank number is used to define both the destination (0-3)
AND the type (ROM/RAM) there are only 5 bits left to indicate the actual bank
number. This sets the limits of 32K ROM and 16K RAM.
D7 is that RAM/ROM flag (1=RAM)
D6D5 indciates the bank number (0-3)
D4D0 indicate the actual # (0-31) from the image/ram
ROM:
In this scheme, the 4K address space is broken into four 1K ROM segments.
living at 0x1000, 0x1400, 0x1800, 0x1C00 (or, same thing, 0xF000... etc.),
and four 512 byte RAM segments, living at 0x1000, 0x1200, 0x1400, 0x1600
with write-mirrors +0x800 of these. The last 1K ROM ($FC00-$FFFF) segment
is initialised to point to the FIRST 1K of the ROM image, but it may be
switched out at any time. Note, this is DIFFERENT to 3E which switches in
the UPPER bank and this bank is fixed. This allows variable sized ROM
without having to detect size. First bank (0) in ROM is the default fixed
bank mapped to $FC00.
The system requires the reset vectors to be valid on a reset, so either the
hardware first switches in the first bank, or the programmer must ensure
that the reset vector is present in ALL ROM banks which might be switched
into the last bank area. Currently the latter (programmer onus) is required,
but it would be nice for the cartridge hardware to auto-switch on reset.
For both ROM (write to 0x3F) and RAM (write to 0x3E) bank switching, the
top two bits indicate the physical address segment which is being switched,
and the low 6 bits indicate the bank number, as per the following ...
ROM switching (write of block+bank number to $3F) upper 2 bits of bank #
indicates the destination segment (0-3, corresponding to $F000, $F400,
$F800, $FC00), and lower 6 bits indicate the 1K bank to switch in. Can
handle 64 x 1K ROM banks (64K total).
BITS ACTION
D7D6 0xxxxx
0 0 -- switch a 1K ROM bank 0xxxxx to $F000
0 1 -- switch a 1K ROM bank 0xxxxx to $F400
1 0 -- switch 1K ROM bank 0xxxxx to $F800
1 1 -- switch 1K ROM bank 0xxxxx to $FC00
can handle 32K ROM maximum
RAM switching (write of segment+bank number to $3E) upper 2 bits of bank #
indicates the destination RAM segment (0-3, corresponding to $F000, $F200,
$F400, $F600). Note that this allows contiguous 2K of RAM to be configured
by setting 4 consecutive RAM segments with consecutive addresses. However,
as the write address of RAM is +0x800, this invalidates ROM access as
described below.
write access uses +$800
can handle 32 x 512 byte RAM banks (16K total)
BITS ACTION
D7D6 1xxxxx
0 0 -- switch a 512 byte RAM bank xxxxx to $F000 with write @ $F800
0 1 -- switch a 512 byte RAM bank xxxxx to $F200 with write @ $FA00
1 0 -- switch a 512 byte RAM bank xxxxx to $F400 with write @ $FC00
1 1 -- switch a 512 byte RAM bank xxxxx to $F600 with write @ $FE00
It is possible to switch multiple RAM banks and ROM banks together
For example,
F000-F1FF RAM bank A (512 byte READ)
F200-F3FF high 512 bytes of ROM bank previously loaded at F000
F400 ROM bank 0 (1K)
F800 RAM bank A (512 byte WRITE)
FA00-FBFF high 512 bytes of ROM bank previously loaded at F400
FC00 ROM bank 1
This example shows 512 bytes of RAM, and 2 1K ROM banks and two 512 byte ROM
bank halves.
Switching RAM blocks (D7D6 of $3E) partially invalidates ROM blocks, as below...
RAM block Invalidates ROM block
0 0 (lower half), 2 (lower half)
1 0 (upper half), 2 (upper half)
2 1 (lower half), 3 (upper half)
3 1 (upper half), 3 (lower half)
For example, RAM block 1 uses address $F200-$F3FF and $FA00-$FBFF
ROM block 0 uses address $F000-$F3FF, and ROM block 2 uses address $F800-$FBFF
Switching in RAM block 1 makes F200-F3FF ROM inaccessible, however F000-F1FF is
still readable. So, care must be paid.
This crazy RAM layout is useful as it allows contiguous RAM to be switched in,
up to 2K in one sequentially accessible block. This means you CAN have 2K of
consecutive RAM. If you don't detect ROM write area, then you would have NO ROM
switched in (don't forget to copy your reset vectors!)
NOTE:
We could consider the 4A50 method where the cart detects read/writes and we
use the same address for reading/writing. magic writes. If we could avoid
the memory doubling for RAM, that would make it easier to code -- use the
same variables for read/write This would then mean that ROM banks 2,3 would
never be bothered by RAM. I like this.
----------------------------------------------------------------------------------------------
This implementation of DASH bankswitching numbers the ROM banks 0 to 63, and
the RAM banks 64 to 127. This is done because the public bankswitching
interface requires us to use one bank number, not one bank number plus the
knowledge of whether it's RAM or ROM.
All 32K of potential RAM is available to a game using this class, even though
real cartridges might not have the full 32K: We have no way to tell how much
RAM the game expects. This may change in the future (we may add a stella.pro
property for this), but for now it shouldn't cause any problems.
(Famous last words...)
@author A. Davie
*/
class CartridgeDASH: public Cartridge
{
friend class CartridgeDASHWidget;
public:
/**
Create a new cartridge using the specified image and size
@param image Pointer to the ROM image
@param size The size of the ROM image
@param settings A reference to the various settings (read-only)
*/
CartridgeDASH(const uInt8* image, uInt32 size, const Settings& settings);
/**
Destructor
*/
virtual ~CartridgeDASH();
public:
/**
Reset device to its power-on state
*/
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
*/
void install(System& system);
/**
Install pages for the specified bank in the system.
@param bank The bank that should be installed in the system
*/
bool bank(uInt16 bank);
/**
Get the current bank.
*/
uInt16 bank() const;
/**
Query the number of banks supported by the cartridge.
*/
uInt16 bankCount() const;
/**
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);
/**
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;
/**
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;
/**
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);
/**
Get a descriptor for the device name (used in error checking).
@return The name of the object
*/
string name() const { 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)
{
return 0;//new CartridgeDASHWidget(boss, lfont, nfont, x, y, w, h, *this);
}
#endif
public:
/**
Get the byte at the specified address
@return The byte at the specified address
*/
uInt8 peek(uInt16 address);
/**
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);
private:
uInt16 myCurrentBank; // whatever the LAST switched bank was...
uInt32 mySize; // Size of the ROM image
uInt8* myImage; // Pointer to a dynamically allocated ROM image of the cartridge
Int16 bankInUse[4]; // bank being used for ROM/RAM (-1 = undefined)
// RAM contents. RAM banks are 512 bytes, and there are a maximum of 64 of them
enum {
BANK_BITS = 5, // # bits for bank
BIT_BANK_MASK = (1 << BANK_BITS) - 1, // mask for those bits
ROMRAM = 0x80, // flags ROM or RAM bank switching (1==RAM)
RAM_BANK_COUNT = 32,
RAM_BANK_TO_POWER = 9, // 2^n = 512
RAM_BANK_SIZE = (1 << RAM_BANK_TO_POWER),
RAM_TOTAL_SIZE = RAM_BANK_COUNT * RAM_BANK_SIZE,
ROM_BANK_TO_POWER = 10, // 2^n = 1024
ROM_BANK_SIZE = (1 << ROM_BANK_TO_POWER),
ROM_BANK_COUNT = 32,
ROM_BANK_MASK = (ROM_BANK_COUNT - 1),
RAM_WRITE_OFFSET = 0x800,
BANK_UNDEFINED = -1 // bank is undefined and inaccessible
};
uInt8 myRAM[RAM_TOTAL_SIZE];
};
#endif

View File

@ -15,6 +15,7 @@ MODULE_OBJS := \
src/emucore/CartCM.o \
src/emucore/CartCTY.o \
src/emucore/CartCV.o \
src/emucore/CartDASH.o \
src/emucore/CartDPC.o \
src/emucore/CartDPCPlus.o \
src/emucore/CartE0.o \

View File

@ -152,6 +152,7 @@ GameInfoDialog::GameInfoDialog(
items.push_back("BFSC (CPUWIZ 256K + ram)", "BFSC" );
items.push_back("CV (Commavid extra ram)", "CV" );
items.push_back("CM (SpectraVideo CompuMate)", "CM" );
items.push_back("DASH (Boulder Dash 2)", "DASH" );
items.push_back("DF (CPUWIZ 128K)", "DF" );
items.push_back("DFSC (CPUWIZ 128K + ram)", "DFSC" );
items.push_back("DPC (Pitfall II)", "DPC" );

View File

@ -83,6 +83,7 @@ GlobalPropsDialog::GlobalPropsDialog(GuiObject* boss, const GUI::Font& font)
items.push_back("BFSC (CPUWIZ 256K + ram)", "BFSC" );
items.push_back("CV (Commavid extra ram)", "CV" );
items.push_back("CM (SpectraVideo CompuMate)", "CM" );
items.push_back("DASH (Boulder Dash 2)", "DASH" );
items.push_back("DF (CPUWIZ 128K)", "DF" );
items.push_back("DFSC (CPUWIZ 128K + ram)", "DFSC" );
items.push_back("DPC (Pitfall II)", "DPC" );