diff --git a/src/emucore/CartDASH.cxx b/src/emucore/CartDASH.cxx index 6e3587ada..460dc8ab9 100644 --- a/src/emucore/CartDASH.cxx +++ b/src/emucore/CartDASH.cxx @@ -24,11 +24,9 @@ #include "TIA.hxx" #include "CartDASH.hxx" -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -CartridgeDASH::CartridgeDASH(const uInt8* image, uInt32 size, const Settings& settings) - : Cartridge(settings), - mySize(size) -{ +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +CartridgeDASH::CartridgeDASH(const uInt8* image, uInt32 size, const Settings& settings) : + Cartridge(settings), mySize(size) { // Allocate array for the ROM image myImage = new uInt8[mySize]; @@ -46,20 +44,20 @@ CartridgeDASH::CartridgeDASH(const uInt8* image, uInt32 size, const Settings& se 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 + myCurrentBank = -1; // nothing switched + // 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() -{ +CartridgeDASH::~CartridgeDASH() { delete[] myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeDASH::reset() -{ +void CartridgeDASH::reset() { // Initialize RAM if (mySettings.getBool("ramrandom")) for (uInt32 i = 0; i < RAM_TOTAL_SIZE; ++i) @@ -73,8 +71,7 @@ void CartridgeDASH::reset() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeDASH::install(System& system) -{ +void CartridgeDASH::install(System& system) { mySystem = &system; uInt16 shift = mySystem->pageShift(); @@ -95,12 +92,11 @@ void CartridgeDASH::install(System& system) // 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<setPageAccess(address>>shift, access); + 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, @@ -112,7 +108,7 @@ void CartridgeDASH::install(System& system) // 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++) + 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 @@ -120,31 +116,29 @@ void CartridgeDASH::install(System& system) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 CartridgeDASH::peek(uInt16 address) -{ +uInt8 CartridgeDASH::peek(uInt16 address) { uInt8 value = 0; uInt32 bank = (address >> ROM_BANK_TO_POWER) & 3; // convert to 1K bank index (0-3) Int16 imageBank = bankInUse[bank]; // the ROM/RAM bank that's here - if(imageBank == BANK_UNDEFINED) // an uninitialised bank? - { + if (imageBank == BANK_UNDEFINED) { // an uninitialised bank? + // 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 & ROMRAM) // a RAM bank - { - Int32 ramBank = imageBank & BIT_BANK_MASK; // discard irrelevant bits - Int32 offset = ramBank << RAM_BANK_TO_POWER; // base bank address in RAM - offset += (address & (RAM_BANK_SIZE-1)); // + byte offset in RAM bank - value = myRAM[offset]; - } - else // accessing ROM - { + + } else if (imageBank & BITMASK_ROMRAM) { // a RAM bank + + Int32 ramBank = imageBank & BIT_BANK_MASK; // discard irrelevant bits + Int32 offset = ramBank << RAM_BANK_TO_POWER; // base bank address in RAM + offset += (address & BITMASK_RAM_BANK); // + byte offset in RAM bank + value = myRAM[offset]; + + } else { // 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 + offset += (address & BITMASK_ROM_BANK); // + byte offset in image bank value = myImage[offset]; } @@ -152,15 +146,14 @@ uInt8 CartridgeDASH::peek(uInt16 address) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeDASH::poke(uInt16 address, uInt8 value) -{ +bool CartridgeDASH::poke(uInt16 address, uInt8 value) { address &= 0x0FFF; // restrict to 4K address range // 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) - bank(value); + if (address == BANK_SWITCH_HOTSPOT) + bank(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 @@ -172,9 +165,8 @@ bool CartridgeDASH::poke(uInt16 address, uInt8 value) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeDASH::bank(uInt16 bank) -{ - if(bankLocked()) +bool CartridgeDASH::bank(uInt16 bank) { + if (bankLocked()) return false; // TODO: Stephen -- ? no idea uInt16 shift = mySystem->pageShift(); @@ -182,12 +174,12 @@ bool CartridgeDASH::bank(uInt16 bank) 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 - { + if (bank & BITMASK_ROMRAM) { // switching to a 512 byte RAM bank + // Wrap around/restrict to valid range - uInt16 currentBank = (bank & BIT_BANK_MASK) % RAM_BANK_COUNT; + uInt16 currentBank = bank & BIT_BANK_MASK; // Record which bank switched in (marked as RAM) - myCurrentBank = bankInUse[bankNumber] = (Int16) (ROM_BANK_COUNT + currentBank); + myCurrentBank = bankInUse[bankNumber] = (Int16) (BITMASK_ROMRAM | currentBank); // Effectively * 512 bytes uInt32 startCurrentBank = currentBank << RAM_BANK_TO_POWER; @@ -195,8 +187,7 @@ bool CartridgeDASH::bank(uInt16 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)) - { + 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.... @@ -209,14 +200,12 @@ bool CartridgeDASH::bank(uInt16 bank) access.type = System::PA_WRITE; // Map write-port RAM image into the system - for (uInt32 byte = 0; byte < RAM_BANK_SIZE; byte += (1 << shift)) - { + 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 + } 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 @@ -231,8 +220,7 @@ bool CartridgeDASH::bank(uInt16 bank) uInt32 bankStart = 0x1000 + (bankNumber << ROM_BANK_TO_POWER); // *1K - for (uInt32 byte = 0; byte < ROM_BANK_SIZE; byte += (1 << shift)) - { + 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); @@ -243,8 +231,7 @@ bool CartridgeDASH::bank(uInt16 bank) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 CartridgeDASH::bank() const -{ +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. :( @@ -253,27 +240,26 @@ uInt16 CartridgeDASH::bank() const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -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? +uInt16 CartridgeDASH::bankCount() const { + + // We have a constant # banks for this scheme; 32 ROM and 32 RAM (or, at least, RAM_BANK_COUNT and ROM_BANK_COUNT) + // See usage of bank bits. + // TODO: Stephen -- What should this return, given the mangled bank value? return ROM_BANK_COUNT + RAM_BANK_COUNT; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeDASH::patch(uInt16 address, uInt8 value) -{ +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) + uInt32 bankNumber = (address >> ROM_BANK_TO_POWER) & 3; // now 1K bank # (ie: 0-3) Int32 whichBankIsThere = bankInUse[bankNumber]; // ROM or RAM bank reference - if(whichBankIsThere <= BANK_UNDEFINED) - { + if (whichBankIsThere == BANK_UNDEFINED) { + // We're trying to access undefined memory (no bank here yet) // TODO: Stephen -- what to do here? Fail silently? @@ -281,64 +267,58 @@ bool CartridgeDASH::patch(uInt16 address, uInt8 value) assert(false); myBankChanged = false; - } - else if(whichBankIsThere < ROM_BANK_COUNT) // patching ROM (1K banks) - { - uInt32 byteOffset = address & (ROM_BANK_SIZE-1); + + } 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 + + } 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 } - 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 -{ +const uInt8* CartridgeDASH::getImage(int& size) const { size = mySize; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeDASH::save(Serializer& out) const -{ - try - { +bool CartridgeDASH::save(Serializer& out) const { + try { out.putString(name()); out.putShort(myCurrentBank); - for(uInt32 bank = 0; bank < 4; bank++) + for (uInt32 bank = 0; bank < 4; bank++) out.putShort(bankInUse[bank]); out.putByteArray(myRAM, RAM_TOTAL_SIZE); - } - catch (...) - { + } catch (...) { cerr << "ERROR: CartridgeDASH::save" << endl; - return false; - } + { - return true; + return false; + } + + return true; + } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeDASH::load(Serializer& in) -{ - try - { - if(in.getString() != name()) +bool CartridgeDASH::load(Serializer& in) { + try { + if (in.getString() != name()) return false; myCurrentBank = in.getShort(); - for(uInt32 bank = 0; bank < 4; bank++) + for (uInt32 bank = 0; bank < 4; bank++) bankInUse[bank] = in.getShort(); in.getByteArray(myRAM, RAM_TOTAL_SIZE); - } - catch (...) - { + } catch (...) { cerr << "ERROR: CartridgeDASH::load" << endl; return false; } diff --git a/src/emucore/CartDASH.hxx b/src/emucore/CartDASH.hxx index 31fcf87f6..cd1c0a826 100644 --- a/src/emucore/CartDASH.hxx +++ b/src/emucore/CartDASH.hxx @@ -26,252 +26,255 @@ class System; #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT - class CartridgeDASHWidget; +class CartridgeDASHWidget; // #include "CartDASHWidget.hxx" #endif /** - Cartridge class for new tiling engine "Boulder Dash" format games with RAM. - Kind of a combination of 3F and 3E, with better switchability. - B.Watson's Cart3E was used as a template for building this implementation. + Cartridge class for new tiling engine "Boulder Dash" format games with RAM. + Kind of a combination of 3F and 3E, with better switchability. + B.Watson's Cart3E was used as a template for building this implementation. - 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. + 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 RAM/ROM flag (1=RAM) - D6D5 indicate the bank number (0-3) - D4D3D2D1D0 indicate the actual # (0-31) from the image/ram + D7 RAM/ROM flag (1=RAM) + D6D5 indicate the bank number (0-3) + D4D3D2D1D0 indicate the actual # (0-31) from the image/ram - Hotspot 0x3F is used for bank-switching, with the encoded bank # as above. + Hotspot 0x3F is used for bank-switching, with the encoded bank # as above. - ROM: + 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. + 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. + The system requires the reset vectors to be valid on a reset, so either the + hardware first switches in the first bank, or the programmer must ensure + that the reset vector is present in ALL ROM banks which might be switched + into the last bank area. Currently the latter (programmer onus) is required, + but it would be nice for the cartridge hardware to auto-switch on reset. - ROM switching (write of block+bank number to $3F) D7=0 and D6D5 upper 2 bits of bank # - indicates the destination segment (0-3, corresponding to $F000, $F400, $F800, $FC00), - and lower 5 bits indicate the 1K bank to switch in. Can handle 32 x 1K ROM banks (32K total). + ROM switching (write of block+bank number to $3F) D7=0 and D6D5 upper 2 bits of bank # + indicates the destination segment (0-3, corresponding to $F000, $F400, $F800, $FC00), + and lower 5 bits indicate the 1K bank to switch in. Can handle 32 x 1K ROM banks (32K total). - D7 D6 D5 D4D3D2D1D0 - 0 0 0 x x x x x switch a 1K ROM bank xxxxx to $F000 - 0 0 1 switch a 1K ROM bank xxxxx to $F400 - 0 1 0 switch a 1K ROM bank xxxxx to $F800 - 0 1 1 switch a 1K ROM bank xxxxx to $FC00 + D7 D6 D5 D4D3D2D1D0 + 0 0 0 x x x x x switch a 1K ROM bank xxxxx to $F000 + 0 0 1 switch a 1K ROM bank xxxxx to $F400 + 0 1 0 switch a 1K ROM bank xxxxx to $F800 + 0 1 1 switch a 1K ROM bank xxxxx to $FC00 - RAM switching (write of segment+bank number to $3F) with D7=1 and D6D5 upper 2 bits of bank # - indicates the destination RAM segment (0-3, corresponding to $F000, $F200, $F400, $F600). - Note that this allows contiguous 2K of RAM to be configured by setting 4 consecutive RAM segments - each 512 bytes with consecutive addresses. However, as the write address of RAM is +0x800, this - invalidates ROM access as described below. + RAM switching (write of segment+bank number to $3F) with D7=1 and D6D5 upper 2 bits of bank # + indicates the destination RAM segment (0-3, corresponding to $F000, $F200, $F400, $F600). + Note that this allows contiguous 2K of RAM to be configured by setting 4 consecutive RAM segments + each 512 bytes with consecutive addresses. However, as the write address of RAM is +0x800, this + invalidates ROM access as described below. - can handle 32 x 512 byte RAM banks (16K total) + can handle 32 x 512 byte RAM banks (16K total) - D7 D6 D5 D4D3D2D1D0 - 1 0 0 x x x x x switch a 512 byte RAM bank xxxxx to $F000 with write @ $F800 - 0 1 switch a 512 byte RAM bank xxxxx to $F200 with write @ $FA00 - 1 0 switch a 512 byte RAM bank xxxxx to $F400 with write @ $FC00 - 1 1 switch a 512 byte RAM bank xxxxx to $F600 with write @ $FE00 + D7 D6 D5 D4D3D2D1D0 + 1 0 0 x x x x x switch a 512 byte RAM bank xxxxx to $F000 with write @ $F800 + 0 1 switch a 512 byte RAM bank xxxxx to $F200 with write @ $FA00 + 1 0 switch a 512 byte RAM bank xxxxx to $F400 with write @ $FC00 + 1 1 switch a 512 byte RAM bank xxxxx to $F600 with write @ $FE00 - It is possible to switch multiple RAM banks and ROM banks together + 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 + 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. + 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... + 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) + 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. + 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. - TODO: THe partial reading of ROM blocks switched out by RAM is not yet implemented!! + TODO: THe partial reading of ROM blocks switched out by RAM is not yet implemented!! - 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!) + 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!) - @author Andrew Davie -*/ + @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); + @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(); + /** + Destructor + */ + virtual ~CartridgeDASH(); - public: - /** - Reset device to its power-on state - */ - void reset(); +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. + /** + 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); + @param system The system the device should install itself in + */ + void install(System& system); - /** - Install pages for the specified bank in the 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); + @param bank The bank that should be installed in the system + */ + bool bank(uInt16 bank); - /** - Get the current bank. - */ - uInt16 bank() const; + /** + Get the current bank. + */ + uInt16 bank() const; - /** - Query the number of banks supported by the cartridge. - */ - uInt16 bankCount() const; + /** + Query the number of banks supported by the cartridge. + */ + uInt16 bankCount() const; - /** - 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); + @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. + /** + 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; + @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. + /** + 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; + @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. + /** + 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); + @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). + /** + Get a descriptor for the device name (used in error checking). - @return The name of the object - */ - string name() const { return "CartridgeDASH"; } + @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); - } + /** + 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 +public: + /** + Get the byte at the specified address - @return The byte at the specified address - */ - uInt8 peek(uInt16 address); + @return The byte at the specified address + */ + uInt8 peek(uInt16 address); - /** - 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); + @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... +private: + Int16 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 + 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) + Int16 bankInUse[4]; // bank being used for ROM/RAM (-1 = undefined) - static const uInt16 BANK_SWITCH_HOTSPOT = 0x3F; // writes to this address cause bankswitching + static const uInt16 BANK_SWITCH_HOTSPOT = 0x3F; // writes to this address cause bankswitching - static const uInt8 BANK_BITS = 5; // # bits for bank - static const uInt8 BIT_BANK_MASK = (1 << BANK_BITS) - 1; // mask for those bits - static const uInt8 ROMRAM = 0x80; // flags ROM or RAM bank switching (1==RAM) + static const uInt8 BANK_BITS = 5; // # bits for bank + static const uInt8 BIT_BANK_MASK = (1 << BANK_BITS) - 1; // mask for those bits + static const uInt8 BITMASK_ROMRAM = 0x80; // flags ROM or RAM bank switching (1==RAM) - static const uInt16 RAM_BANK_COUNT = 32; - static const uInt16 RAM_BANK_TO_POWER = 9; // 2^n = 512 - static const uInt16 RAM_BANK_SIZE = (1 << RAM_BANK_TO_POWER); - static const uInt32 RAM_TOTAL_SIZE = RAM_BANK_COUNT * RAM_BANK_SIZE; + static const uInt16 RAM_BANK_COUNT = 32; + static const uInt16 RAM_BANK_TO_POWER = 9; // 2^n = 512 + static const uInt16 RAM_BANK_SIZE = (1 << RAM_BANK_TO_POWER); + static const uInt16 BITMASK_RAM_BANK = (RAM_BANK_SIZE - 1); + static const uInt32 RAM_TOTAL_SIZE = RAM_BANK_COUNT * RAM_BANK_SIZE; - static const uInt16 ROM_BANK_TO_POWER = 10; // 2^n = 1024 - static const uInt16 ROM_BANK_SIZE = (1 << ROM_BANK_TO_POWER); + static const uInt16 ROM_BANK_TO_POWER = 10; // 2^n = 1024 + static const uInt16 ROM_BANK_SIZE = (1 << ROM_BANK_TO_POWER); + static const uInt16 BITMASK_ROM_BANK = (ROM_BANK_SIZE -1); - static const uInt16 ROM_BANK_COUNT = 32; - static const uInt16 ROM_BANK_MASK = (ROM_BANK_COUNT - 1); + static const uInt16 ROM_BANK_COUNT = 32; + static const uInt16 BITMASK_ROM_BANK = (ROM_BANK_COUNT - 1); - static const uInt16 RAM_WRITE_OFFSET = 0x800; + static const uInt16 RAM_WRITE_OFFSET = 0x800; - static const Int16 BANK_UNDEFINED = -1; // bank is undefined and inaccessible + static const Int16 BANK_UNDEFINED = -1; // bank is undefined and inaccessible - uInt8 myRAM[RAM_TOTAL_SIZE]; + uInt8 myRAM[RAM_TOTAL_SIZE]; }; #endif