mirror of https://github.com/stella-emu/stella.git
First attempt to backport relevant BS schemes to R77 branch.
- There are 8 new BS schemes since version 3.9.3 has been released - CDF is probably the most wanted, but I will consider the others as time permits
This commit is contained in:
parent
4f9470968b
commit
e09bc90d17
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
#define STELLA_VERSION "3.9.3"
|
#define STELLA_VERSION "3.9.4"
|
||||||
#define STELLA_BUILD atoi("$Rev: 2838 $" + 6)
|
#define STELLA_BUILD atoi("$Rev: 2838 $" + 6)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -26,18 +26,24 @@
|
||||||
#include "Cart0840.hxx"
|
#include "Cart0840.hxx"
|
||||||
#include "Cart2K.hxx"
|
#include "Cart2K.hxx"
|
||||||
#include "Cart3E.hxx"
|
#include "Cart3E.hxx"
|
||||||
|
// #include "Cart3EPlus.hxx"
|
||||||
#include "Cart3F.hxx"
|
#include "Cart3F.hxx"
|
||||||
#include "Cart4A50.hxx"
|
#include "Cart4A50.hxx"
|
||||||
#include "Cart4K.hxx"
|
#include "Cart4K.hxx"
|
||||||
#include "Cart4KSC.hxx"
|
#include "Cart4KSC.hxx"
|
||||||
#include "CartAR.hxx"
|
#include "CartAR.hxx"
|
||||||
|
// #include "CartBUS.hxx"
|
||||||
|
// #include "CartCDF.hxx"
|
||||||
#include "CartCM.hxx"
|
#include "CartCM.hxx"
|
||||||
#include "CartCTY.hxx"
|
#include "CartCTY.hxx"
|
||||||
#include "CartCV.hxx"
|
#include "CartCV.hxx"
|
||||||
|
// #include "CartCVPlus.hxx"
|
||||||
|
// #include "CartDASH.hxx"
|
||||||
#include "CartDPC.hxx"
|
#include "CartDPC.hxx"
|
||||||
#include "CartDPCPlus.hxx"
|
#include "CartDPCPlus.hxx"
|
||||||
#include "CartE0.hxx"
|
#include "CartE0.hxx"
|
||||||
#include "CartE7.hxx"
|
#include "CartE7.hxx"
|
||||||
|
// #include "CartE78K.hxx"
|
||||||
#include "CartEF.hxx"
|
#include "CartEF.hxx"
|
||||||
#include "CartEFSC.hxx"
|
#include "CartEFSC.hxx"
|
||||||
#include "CartBF.hxx"
|
#include "CartBF.hxx"
|
||||||
|
@ -54,9 +60,10 @@
|
||||||
#include "CartFA.hxx"
|
#include "CartFA.hxx"
|
||||||
#include "CartFA2.hxx"
|
#include "CartFA2.hxx"
|
||||||
#include "CartFE.hxx"
|
#include "CartFE.hxx"
|
||||||
#include "CartMC.hxx"
|
// #include "CartMDM.hxx"
|
||||||
#include "CartSB.hxx"
|
#include "CartSB.hxx"
|
||||||
#include "CartUA.hxx"
|
#include "CartUA.hxx"
|
||||||
|
// #include "CartWD.hxx"
|
||||||
#include "CartX07.hxx"
|
#include "CartX07.hxx"
|
||||||
#include "MD5.hxx"
|
#include "MD5.hxx"
|
||||||
#include "Props.hxx"
|
#include "Props.hxx"
|
||||||
|
@ -183,6 +190,8 @@ Cartridge* Cartridge::create(const uInt8* image, uInt32 size, string& md5,
|
||||||
cartridge = new Cartridge2K(image, size, settings);
|
cartridge = new Cartridge2K(image, size, settings);
|
||||||
else if(type == "3E")
|
else if(type == "3E")
|
||||||
cartridge = new Cartridge3E(image, size, settings);
|
cartridge = new Cartridge3E(image, size, settings);
|
||||||
|
// else if(type == "3EP")
|
||||||
|
// cartridge = new Cartridge3EPlus(image, size, settings);
|
||||||
else if(type == "3F")
|
else if(type == "3F")
|
||||||
cartridge = new Cartridge3F(image, size, settings);
|
cartridge = new Cartridge3F(image, size, settings);
|
||||||
else if(type == "4A50")
|
else if(type == "4A50")
|
||||||
|
@ -193,33 +202,43 @@ Cartridge* Cartridge::create(const uInt8* image, uInt32 size, string& md5,
|
||||||
cartridge = new Cartridge4KSC(image, size, settings);
|
cartridge = new Cartridge4KSC(image, size, settings);
|
||||||
else if(type == "AR")
|
else if(type == "AR")
|
||||||
cartridge = new CartridgeAR(image, size, settings);
|
cartridge = new CartridgeAR(image, size, settings);
|
||||||
|
else if(type == "BF")
|
||||||
|
cartridge = new CartridgeBF(image, size, settings);
|
||||||
|
else if(type == "BFSC")
|
||||||
|
cartridge = new CartridgeBFSC(image, size, settings);
|
||||||
|
// else if(type == "BUS")
|
||||||
|
// cartridge = new CartridgeBUS(image, size, settings);
|
||||||
|
// else if(type == "CDF")
|
||||||
|
// cartridge = new CartridgeCDF(image, size, settings);
|
||||||
else if(type == "CM")
|
else if(type == "CM")
|
||||||
cartridge = new CartridgeCM(image, size, settings);
|
cartridge = new CartridgeCM(image, size, settings);
|
||||||
else if(type == "CTY")
|
else if(type == "CTY")
|
||||||
cartridge = new CartridgeCTY(image, size, osystem);
|
cartridge = new CartridgeCTY(image, size, osystem);
|
||||||
else if(type == "CV")
|
else if(type == "CV")
|
||||||
cartridge = new CartridgeCV(image, size, settings);
|
cartridge = new CartridgeCV(image, size, settings);
|
||||||
|
// else if(type == "CVP")
|
||||||
|
// cartridge = new CartridgeCVPlus(image, size, settings);
|
||||||
|
// else if(type == "DASH")
|
||||||
|
// cartridge = new CartridgeDASH(image, size, settings);
|
||||||
|
else if(type == "DF")
|
||||||
|
cartridge = new CartridgeDF(image, size, settings);
|
||||||
|
else if(type == "DFSC")
|
||||||
|
cartridge = new CartridgeDFSC(image, size, settings);
|
||||||
else if(type == "DPC")
|
else if(type == "DPC")
|
||||||
cartridge = new CartridgeDPC(image, size, settings);
|
cartridge = new CartridgeDPC(image, size, settings);
|
||||||
else if(type == "DPC+")
|
else if(type == "DPCP")
|
||||||
cartridge = new CartridgeDPCPlus(image, size, settings);
|
cartridge = new CartridgeDPCPlus(image, size, settings);
|
||||||
else if(type == "E0")
|
else if(type == "E0")
|
||||||
cartridge = new CartridgeE0(image, size, settings);
|
cartridge = new CartridgeE0(image, size, settings);
|
||||||
else if(type == "E7")
|
else if(type == "E7")
|
||||||
cartridge = new CartridgeE7(image, size, settings);
|
cartridge = new CartridgeE7(image, size, settings);
|
||||||
|
// else if(type == "E78K")
|
||||||
|
// cartridge = new CartridgeE78K(image, size, settings);
|
||||||
else if(type == "EF")
|
else if(type == "EF")
|
||||||
cartridge = new CartridgeEF(image, size, settings);
|
cartridge = new CartridgeEF(image, size, settings);
|
||||||
else if(type == "EFSC")
|
else if(type == "EFSC")
|
||||||
cartridge = new CartridgeEFSC(image, size, settings);
|
cartridge = new CartridgeEFSC(image, size, settings);
|
||||||
else if(type == "BF")
|
else if(type == "F0")
|
||||||
cartridge = new CartridgeBF(image, size, settings);
|
|
||||||
else if(type == "BFSC")
|
|
||||||
cartridge = new CartridgeBFSC(image, size, settings);
|
|
||||||
else if(type == "DF")
|
|
||||||
cartridge = new CartridgeDF(image, size, settings);
|
|
||||||
else if(type == "DFSC")
|
|
||||||
cartridge = new CartridgeDFSC(image, size, settings);
|
|
||||||
else if(type == "F0" || type == "MB")
|
|
||||||
cartridge = new CartridgeF0(image, size, settings);
|
cartridge = new CartridgeF0(image, size, settings);
|
||||||
else if(type == "F4")
|
else if(type == "F4")
|
||||||
cartridge = new CartridgeF4(image, size, settings);
|
cartridge = new CartridgeF4(image, size, settings);
|
||||||
|
@ -233,18 +252,20 @@ Cartridge* Cartridge::create(const uInt8* image, uInt32 size, string& md5,
|
||||||
cartridge = new CartridgeF8(image, size, md5, settings);
|
cartridge = new CartridgeF8(image, size, md5, settings);
|
||||||
else if(type == "F8SC")
|
else if(type == "F8SC")
|
||||||
cartridge = new CartridgeF8SC(image, size, settings);
|
cartridge = new CartridgeF8SC(image, size, settings);
|
||||||
else if(type == "FA" || type == "FASC")
|
else if(type == "FA")
|
||||||
cartridge = new CartridgeFA(image, size, settings);
|
cartridge = new CartridgeFA(image, size, settings);
|
||||||
else if(type == "FA2")
|
else if(type == "FA2")
|
||||||
cartridge = new CartridgeFA2(image, size, osystem);
|
cartridge = new CartridgeFA2(image, size, osystem);
|
||||||
else if(type == "FE")
|
else if(type == "FE")
|
||||||
cartridge = new CartridgeFE(image, size, settings);
|
cartridge = new CartridgeFE(image, size, settings);
|
||||||
else if(type == "MC")
|
// else if(type == "MDM")
|
||||||
cartridge = new CartridgeMC(image, size, settings);
|
// cartridge = new CartridgeMDM(image, size, settings);
|
||||||
else if(type == "UA")
|
else if(type == "UA")
|
||||||
cartridge = new CartridgeUA(image, size, settings);
|
cartridge = new CartridgeUA(image, size, settings);
|
||||||
else if(type == "SB")
|
else if(type == "SB")
|
||||||
cartridge = new CartridgeSB(image, size, settings);
|
cartridge = new CartridgeSB(image, size, settings);
|
||||||
|
// else if(type == "WD")
|
||||||
|
// cartridge = new CartridgeWD(image, size, settings);
|
||||||
else if(type == "X07")
|
else if(type == "X07")
|
||||||
cartridge = new CartridgeX07(image, size, settings);
|
cartridge = new CartridgeX07(image, size, settings);
|
||||||
else if(dtype == "WRONG_SIZE")
|
else if(dtype == "WRONG_SIZE")
|
||||||
|
@ -380,7 +401,11 @@ string Cartridge::autodetectType(const uInt8* image, uInt32 size)
|
||||||
// Guess type based on size
|
// Guess type based on size
|
||||||
const char* type = 0;
|
const char* type = 0;
|
||||||
|
|
||||||
if((size % 8448) == 0 || size == 6144)
|
if(isProbablyCVPlus(image,size))
|
||||||
|
{
|
||||||
|
type = "CVP";
|
||||||
|
}
|
||||||
|
else if((size % 8448) == 0 || size == 6144)
|
||||||
{
|
{
|
||||||
type = "AR";
|
type = "AR";
|
||||||
}
|
}
|
||||||
|
@ -395,9 +420,9 @@ string Cartridge::autodetectType(const uInt8* image, uInt32 size)
|
||||||
}
|
}
|
||||||
else if(size == 4096)
|
else if(size == 4096)
|
||||||
{
|
{
|
||||||
if(isProbablyCV(image,size))
|
if(isProbablyCV(image, size))
|
||||||
type = "CV";
|
type = "CV";
|
||||||
else if(isProbably4KSC(image,size))
|
else if(isProbably4KSC(image, size))
|
||||||
type = "4KSC";
|
type = "4KSC";
|
||||||
else
|
else
|
||||||
type = "4K";
|
type = "4K";
|
||||||
|
@ -424,9 +449,15 @@ string Cartridge::autodetectType(const uInt8* image, uInt32 size)
|
||||||
type = "FE";
|
type = "FE";
|
||||||
else if(isProbably0840(image, size))
|
else if(isProbably0840(image, size))
|
||||||
type = "0840";
|
type = "0840";
|
||||||
|
else if(isProbablyE78K(image, size))
|
||||||
|
type = "E78K";
|
||||||
else
|
else
|
||||||
type = "F8";
|
type = "F8";
|
||||||
}
|
}
|
||||||
|
else if(size == 8*1024 + 3) // 8195 bytes (Experimental)
|
||||||
|
{
|
||||||
|
type = "WD";
|
||||||
|
}
|
||||||
else if(size >= 10240 && size <= 10496) // ~10K - Pitfall2
|
else if(size >= 10240 && size <= 10496) // ~10K - Pitfall2
|
||||||
{
|
{
|
||||||
type = "DPC";
|
type = "DPC";
|
||||||
|
@ -459,25 +490,36 @@ string Cartridge::autodetectType(const uInt8* image, uInt32 size)
|
||||||
if(isProbablyARM(image, size))
|
if(isProbablyARM(image, size))
|
||||||
type = "FA2";
|
type = "FA2";
|
||||||
else /*if(isProbablyDPCplus(image, size))*/
|
else /*if(isProbablyDPCplus(image, size))*/
|
||||||
type = "DPC+";
|
type = "DPCP";
|
||||||
}
|
}
|
||||||
else if(size == 32*1024) // 32K
|
else if(size == 32*1024) // 32K
|
||||||
{
|
{
|
||||||
if(isProbablySC(image, size))
|
if (isProbablyCTY(image, size))
|
||||||
|
type = "CTY";
|
||||||
|
else if(isProbablySC(image, size))
|
||||||
type = "F4SC";
|
type = "F4SC";
|
||||||
else if(isProbably3E(image, size))
|
else if(isProbably3E(image, size))
|
||||||
type = "3E";
|
type = "3E";
|
||||||
else if(isProbably3F(image, size))
|
else if(isProbably3F(image, size))
|
||||||
type = "3F";
|
type = "3F";
|
||||||
|
else if (isProbablyBUS(image, size))
|
||||||
|
type = "BUS";
|
||||||
|
else if (isProbablyCDF(image, size))
|
||||||
|
type = "CDF";
|
||||||
else if(isProbablyDPCplus(image, size))
|
else if(isProbablyDPCplus(image, size))
|
||||||
type = "DPC+";
|
type = "DPCP";
|
||||||
else if(isProbablyCTY(image, size))
|
|
||||||
type = "CTY";
|
|
||||||
else if(isProbablyFA2(image, size))
|
else if(isProbablyFA2(image, size))
|
||||||
type = "FA2";
|
type = "FA2";
|
||||||
else
|
else
|
||||||
type = "F4";
|
type = "F4";
|
||||||
}
|
}
|
||||||
|
else if(size == 60*1024) // 60K
|
||||||
|
{
|
||||||
|
if(isProbablyCTY(image, size))
|
||||||
|
type = "CTY";
|
||||||
|
else
|
||||||
|
type = "F4";
|
||||||
|
}
|
||||||
else if(size == 64*1024) // 64K
|
else if(size == 64*1024) // 64K
|
||||||
{
|
{
|
||||||
if(isProbably3E(image, size))
|
if(isProbably3E(image, size))
|
||||||
|
@ -505,8 +547,6 @@ string Cartridge::autodetectType(const uInt8* image, uInt32 size)
|
||||||
type = "4A50";
|
type = "4A50";
|
||||||
else if(isProbablySB(image, size))
|
else if(isProbablySB(image, size))
|
||||||
type = "SB";
|
type = "SB";
|
||||||
else
|
|
||||||
type = "MC";
|
|
||||||
}
|
}
|
||||||
else if(size == 256*1024) // 256K
|
else if(size == 256*1024) // 256K
|
||||||
{
|
{
|
||||||
|
@ -529,13 +569,22 @@ string Cartridge::autodetectType(const uInt8* image, uInt32 size)
|
||||||
type = "4K"; // Most common bankswitching type
|
type = "4K"; // Most common bankswitching type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Variable sized ROM formats are independent of image size and come last
|
||||||
|
if(isProbablyDASH(image, size))
|
||||||
|
type = "DASH";
|
||||||
|
else if(isProbably3EPlus(image, size))
|
||||||
|
type = "3EP";
|
||||||
|
else if(isProbablyMDM(image, size))
|
||||||
|
type = "MDM";
|
||||||
|
|
||||||
|
cerr << type << endl;
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool Cartridge::searchForBytes(const uInt8* image, uInt32 imagesize,
|
bool Cartridge::searchForBytes(const uInt8* image, uInt32 imagesize,
|
||||||
const uInt8* signature, uInt32 sigsize,
|
const uInt8* signature, uInt32 sigsize,
|
||||||
uInt32 minhits)
|
uInt32 minhits)
|
||||||
{
|
{
|
||||||
uInt32 count = 0;
|
uInt32 count = 0;
|
||||||
for(uInt32 i = 0; i < imagesize - sigsize; ++i)
|
for(uInt32 i = 0; i < imagesize - sigsize; ++i)
|
||||||
|
@ -563,22 +612,21 @@ bool Cartridge::searchForBytes(const uInt8* image, uInt32 imagesize,
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool Cartridge::isProbablySC(const uInt8* image, uInt32 size)
|
bool Cartridge::isProbablySC(const uInt8* image, uInt32 size)
|
||||||
{
|
{
|
||||||
// We assume a Superchip cart contains the same bytes for its entire
|
// We assume a Superchip cart repeats the first 128 bytes for the second
|
||||||
// RAM area; obviously this test will fail if it doesn't
|
// 128 bytes in the RAM area, which is the first 256 bytes of each 4K bank
|
||||||
// The RAM area will be the first 256 bytes of each 4K bank
|
const uInt8* ptr = image;
|
||||||
uInt32 banks = size / 4096;
|
while(size)
|
||||||
for(uInt32 i = 0; i < banks; ++i)
|
|
||||||
{
|
{
|
||||||
uInt8 first = image[i*4096];
|
if(memcmp(ptr, ptr + 128, 128) != 0)
|
||||||
for(uInt32 j = 0; j < 256; ++j)
|
return false;
|
||||||
{
|
|
||||||
if(image[i*4096+j] != first)
|
ptr += 4096;
|
||||||
return false;
|
size -= 4096;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool Cartridge::isProbably4KSC(const uInt8* image, uInt32 size)
|
bool Cartridge::isProbably4KSC(const uInt8* image, uInt32 size)
|
||||||
{
|
{
|
||||||
// We check if the first 256 bytes are identical *and* if there's
|
// We check if the first 256 bytes are identical *and* if there's
|
||||||
|
@ -595,7 +643,6 @@ bool Cartridge::isProbably4KSC(const uInt8* image, uInt32 size)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool Cartridge::isProbablyARM(const uInt8* image, uInt32 size)
|
bool Cartridge::isProbablyARM(const uInt8* image, uInt32 size)
|
||||||
{
|
{
|
||||||
|
@ -605,10 +652,10 @@ bool Cartridge::isProbablyARM(const uInt8* image, uInt32 size)
|
||||||
{ 0xA0, 0xC1, 0x1F, 0xE0 },
|
{ 0xA0, 0xC1, 0x1F, 0xE0 },
|
||||||
{ 0x00, 0x80, 0x02, 0xE0 }
|
{ 0x00, 0x80, 0x02, 0xE0 }
|
||||||
};
|
};
|
||||||
if(searchForBytes(image, 1024, signature[0], 4, 1))
|
if(searchForBytes(image, std::min(size, 1024u), signature[0], 4, 1))
|
||||||
return true;
|
return true;
|
||||||
else
|
else
|
||||||
return searchForBytes(image, 1024, signature[1], 4, 1);
|
return searchForBytes(image, std::min(size, 1024u), signature[1], 4, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -646,6 +693,14 @@ bool Cartridge::isProbably3E(const uInt8* image, uInt32 size)
|
||||||
return searchForBytes(image, size, signature, 4, 1);
|
return searchForBytes(image, size, signature, 4, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
bool Cartridge::isProbably3EPlus(const uInt8* image, uInt32 size)
|
||||||
|
{
|
||||||
|
// 3E+ cart is identified key 'TJ3E' in the ROM
|
||||||
|
uInt8 signature[] = { 'T', 'J', '3', 'E' };
|
||||||
|
return searchForBytes(image, size, signature, 4, 1);
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool Cartridge::isProbably3F(const uInt8* image, uInt32 size)
|
bool Cartridge::isProbably3F(const uInt8* image, uInt32 size)
|
||||||
{
|
{
|
||||||
|
@ -678,7 +733,8 @@ bool Cartridge::isProbably4A50(const uInt8* image, uInt32 size)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool Cartridge::isProbablyCTY(const uInt8* image, uInt32 size)
|
bool Cartridge::isProbablyCTY(const uInt8* image, uInt32 size)
|
||||||
{
|
{
|
||||||
return false; // TODO - add autodetection
|
uInt8 signature[] = { 'L', 'E', 'N', 'I', 'N' };
|
||||||
|
return searchForBytes(image, size, signature, 5, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -696,10 +752,30 @@ bool Cartridge::isProbablyCV(const uInt8* image, uInt32 size)
|
||||||
return searchForBytes(image, size, signature[1], 3, 1);
|
return searchForBytes(image, size, signature[1], 3, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
bool Cartridge::isProbablyCVPlus(const uInt8* image, uInt32)
|
||||||
|
{
|
||||||
|
// CV+ cart is identified key 'commavidplus' @ $04 in the ROM
|
||||||
|
// We inspect only this area to speed up the search
|
||||||
|
uInt8 signature[12] = { 'c', 'o', 'm', 'm', 'a', 'v', 'i', 'd',
|
||||||
|
'p', 'l', 'u', 's' };
|
||||||
|
return searchForBytes(image+4, 24, signature, 12, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
bool Cartridge::isProbablyDASH(const uInt8* image, uInt32 size)
|
||||||
|
{
|
||||||
|
// DASH cart is identified key 'TJAD' in the ROM
|
||||||
|
uInt8 signature[] = { 'T', 'J', 'A', 'D' };
|
||||||
|
return searchForBytes(image, size, signature, 4, 1);
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool Cartridge::isProbablyDPCplus(const uInt8* image, uInt32 size)
|
bool Cartridge::isProbablyDPCplus(const uInt8* image, uInt32 size)
|
||||||
{
|
{
|
||||||
// DPC+ ARM code has 2 occurrences of the string DPC+
|
// DPC+ ARM code has 2 occurrences of the string DPC+
|
||||||
|
// Note: all Harmony/Melody custom drivers also contain the value
|
||||||
|
// 0x10adab1e (LOADABLE) if needed for future improvement
|
||||||
uInt8 signature[] = { 'D', 'P', 'C', '+' };
|
uInt8 signature[] = { 'D', 'P', 'C', '+' };
|
||||||
return searchForBytes(image, size, signature, 4, 2);
|
return searchForBytes(image, size, signature, 4, 2);
|
||||||
}
|
}
|
||||||
|
@ -714,14 +790,14 @@ bool Cartridge::isProbablyE0(const uInt8* image, uInt32 size)
|
||||||
// Thanks to "stella@casperkitty.com" for this advice
|
// Thanks to "stella@casperkitty.com" for this advice
|
||||||
// These signatures are attributed to the MESS project
|
// These signatures are attributed to the MESS project
|
||||||
uInt8 signature[8][3] = {
|
uInt8 signature[8][3] = {
|
||||||
{ 0x8D, 0xE0, 0x1F }, // STA $1FE0
|
{ 0x8D, 0xE0, 0x1F }, // STA $1FE0
|
||||||
{ 0x8D, 0xE0, 0x5F }, // STA $5FE0
|
{ 0x8D, 0xE0, 0x5F }, // STA $5FE0
|
||||||
{ 0x8D, 0xE9, 0xFF }, // STA $FFE9
|
{ 0x8D, 0xE9, 0xFF }, // STA $FFE9
|
||||||
{ 0x0C, 0xE0, 0x1F }, // NOP $1FE0
|
{ 0x0C, 0xE0, 0x1F }, // NOP $1FE0
|
||||||
{ 0xAD, 0xE0, 0x1F }, // LDA $1FE0
|
{ 0xAD, 0xE0, 0x1F }, // LDA $1FE0
|
||||||
{ 0xAD, 0xE9, 0xFF }, // LDA $FFE9
|
{ 0xAD, 0xE9, 0xFF }, // LDA $FFE9
|
||||||
{ 0xAD, 0xED, 0xFF }, // LDA $FFED
|
{ 0xAD, 0xED, 0xFF }, // LDA $FFED
|
||||||
{ 0xAD, 0xF3, 0xBF } // LDA $BFF3
|
{ 0xAD, 0xF3, 0xBF } // LDA $BFF3
|
||||||
};
|
};
|
||||||
for(uInt32 i = 0; i < 8; ++i)
|
for(uInt32 i = 0; i < 8; ++i)
|
||||||
if(searchForBytes(image, size, signature[i], 3, 1))
|
if(searchForBytes(image, size, signature[i], 3, 1))
|
||||||
|
@ -740,13 +816,13 @@ bool Cartridge::isProbablyE7(const uInt8* image, uInt32 size)
|
||||||
// Thanks to "stella@casperkitty.com" for this advice
|
// Thanks to "stella@casperkitty.com" for this advice
|
||||||
// These signatures are attributed to the MESS project
|
// These signatures are attributed to the MESS project
|
||||||
uInt8 signature[7][3] = {
|
uInt8 signature[7][3] = {
|
||||||
{ 0xAD, 0xE2, 0xFF }, // LDA $FFE2
|
{ 0xAD, 0xE2, 0xFF }, // LDA $FFE2
|
||||||
{ 0xAD, 0xE5, 0xFF }, // LDA $FFE5
|
{ 0xAD, 0xE5, 0xFF }, // LDA $FFE5
|
||||||
{ 0xAD, 0xE5, 0x1F }, // LDA $1FE5
|
{ 0xAD, 0xE5, 0x1F }, // LDA $1FE5
|
||||||
{ 0xAD, 0xE7, 0x1F }, // LDA $1FE7
|
{ 0xAD, 0xE7, 0x1F }, // LDA $1FE7
|
||||||
{ 0x0C, 0xE7, 0x1F }, // NOP $1FE7
|
{ 0x0C, 0xE7, 0x1F }, // NOP $1FE7
|
||||||
{ 0x8D, 0xE7, 0xFF }, // STA $FFE7
|
{ 0x8D, 0xE7, 0xFF }, // STA $FFE7
|
||||||
{ 0x8D, 0xE7, 0x1F } // STA $1FE7
|
{ 0x8D, 0xE7, 0x1F } // STA $1FE7
|
||||||
};
|
};
|
||||||
for(uInt32 i = 0; i < 7; ++i)
|
for(uInt32 i = 0; i < 7; ++i)
|
||||||
if(searchForBytes(image, size, signature[i], 3, 1))
|
if(searchForBytes(image, size, signature[i], 3, 1))
|
||||||
|
@ -755,6 +831,25 @@ bool Cartridge::isProbablyE7(const uInt8* image, uInt32 size)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
bool Cartridge::isProbablyE78K(const uInt8* image, uInt32 size)
|
||||||
|
{
|
||||||
|
// E78K cart bankswitching is triggered by accessing addresses
|
||||||
|
// $FE4 to $FE6 using absolute non-indexed addressing
|
||||||
|
// To eliminate false positives (and speed up processing), we
|
||||||
|
// search for only certain known signatures
|
||||||
|
uInt8 signature[3][3] = {
|
||||||
|
{ 0xAD, 0xE4, 0xFF }, // LDA $FFE4
|
||||||
|
{ 0xAD, 0xE5, 0xFF }, // LDA $FFE5
|
||||||
|
{ 0xAD, 0xE6, 0xFF }, // LDA $FFE6
|
||||||
|
};
|
||||||
|
for(uInt32 i = 0; i < 3; ++i)
|
||||||
|
if(searchForBytes(image, size, signature[i], 3, 1))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool Cartridge::isProbablyEF(const uInt8* image, uInt32 size, const char*& type)
|
bool Cartridge::isProbablyEF(const uInt8* image, uInt32 size, const char*& type)
|
||||||
{
|
{
|
||||||
|
@ -763,7 +858,7 @@ bool Cartridge::isProbablyEF(const uInt8* image, uInt32 size, const char*& type)
|
||||||
uInt8 efef[] = { 'E', 'F', 'E', 'F' };
|
uInt8 efef[] = { 'E', 'F', 'E', 'F' };
|
||||||
uInt8 efsc[] = { 'E', 'F', 'S', 'C' };
|
uInt8 efsc[] = { 'E', 'F', 'S', 'C' };
|
||||||
if(searchForBytes(image+size-8, 8, efef, 4, 1))
|
if(searchForBytes(image+size-8, 8, efef, 4, 1))
|
||||||
{
|
{
|
||||||
type = "EF";
|
type = "EF";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -808,7 +903,7 @@ bool Cartridge::isProbablyBF(const uInt8* image, uInt32 size, const char*& type)
|
||||||
{
|
{
|
||||||
// BF carts store strings 'BFBF' and 'BFSC' starting at address $FFF8
|
// BF carts store strings 'BFBF' and 'BFSC' starting at address $FFF8
|
||||||
// This signature is attributed to "RevEng" of AtariAge
|
// This signature is attributed to "RevEng" of AtariAge
|
||||||
uInt8 bf[] = { 'B', 'F', 'B', 'F' };
|
uInt8 bf[] = { 'B', 'F', 'B', 'F' };
|
||||||
uInt8 bfsc[] = { 'B', 'F', 'S', 'C' };
|
uInt8 bfsc[] = { 'B', 'F', 'S', 'C' };
|
||||||
if(searchForBytes(image+size-8, 8, bf, 4, 1))
|
if(searchForBytes(image+size-8, 8, bf, 4, 1))
|
||||||
{
|
{
|
||||||
|
@ -824,18 +919,38 @@ bool Cartridge::isProbablyBF(const uInt8* image, uInt32 size, const char*& type)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
bool Cartridge::isProbablyBUS(const uInt8* image, uInt32 size)
|
||||||
|
{
|
||||||
|
// BUS ARM code has 2 occurrences of the string BUS
|
||||||
|
// Note: all Harmony/Melody custom drivers also contain the value
|
||||||
|
// 0x10adab1e (LOADABLE) if needed for future improvement
|
||||||
|
uInt8 bus[] = { 'B', 'U', 'S'};
|
||||||
|
return searchForBytes(image, size, bus, 3, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
bool Cartridge::isProbablyCDF(const uInt8* image, uInt32 size)
|
||||||
|
{
|
||||||
|
// CDF ARM code has 3 occurrences of the string DPC+
|
||||||
|
// Note: all Harmony/Melody custom drivers also contain the value
|
||||||
|
// 0x10adab1e (LOADABLE) if needed for future improvement
|
||||||
|
uInt8 signature[] = { 'C', 'D', 'F' };
|
||||||
|
return searchForBytes(image, size, signature, 3, 3);
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool Cartridge::isProbablyDF(const uInt8* image, uInt32 size, const char*& type)
|
bool Cartridge::isProbablyDF(const uInt8* image, uInt32 size, const char*& type)
|
||||||
{
|
{
|
||||||
|
|
||||||
// BF carts store strings 'DFDF' and 'DFSC' starting at address $FFF8
|
// BF carts store strings 'DFDF' and 'DFSC' starting at address $FFF8
|
||||||
// This signature is attributed to "RevEng" of AtariAge
|
// This signature is attributed to "RevEng" of AtariAge
|
||||||
uInt8 df[] = { 'D', 'F', 'D', 'F' };
|
uInt8 df[] = { 'D', 'F', 'D', 'F' };
|
||||||
uInt8 dfsc[] = { 'D', 'F', 'S', 'C' };
|
uInt8 dfsc[] = { 'D', 'F', 'S', 'C' };
|
||||||
if(searchForBytes(image+size-8, 8, df, 4, 1))
|
if(searchForBytes(image+size-8, 8, df, 4, 1))
|
||||||
{
|
{
|
||||||
type = "DF";
|
type = "DF";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if(searchForBytes(image+size-8, 8, dfsc, 4, 1))
|
else if(searchForBytes(image+size-8, 8, dfsc, 4, 1))
|
||||||
{
|
{
|
||||||
|
@ -846,9 +961,8 @@ bool Cartridge::isProbablyDF(const uInt8* image, uInt32 size, const char*& type)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool Cartridge::isProbablyFA2(const uInt8* image, uInt32 size)
|
bool Cartridge::isProbablyFA2(const uInt8* image, uInt32)
|
||||||
{
|
{
|
||||||
// This currently tests only the 32K version of FA2; the 24 and 28K
|
// This currently tests only the 32K version of FA2; the 24 and 28K
|
||||||
// versions are easy, in that they're the only possibility with those
|
// versions are easy, in that they're the only possibility with those
|
||||||
|
@ -881,6 +995,14 @@ bool Cartridge::isProbablyFE(const uInt8* image, uInt32 size)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
bool Cartridge::isProbablyMDM(const uInt8* image, uInt32 size)
|
||||||
|
{
|
||||||
|
// MDM cart is identified key 'MDMC' in the first 8K of ROM
|
||||||
|
uInt8 signature[] = { 'M', 'D', 'M', 'C' };
|
||||||
|
return searchForBytes(image, std::min(size, 8192u), signature, 4, 1);
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool Cartridge::isProbablySB(const uInt8* image, uInt32 size)
|
bool Cartridge::isProbablySB(const uInt8* image, uInt32 size)
|
||||||
{
|
{
|
||||||
|
|
|
@ -202,6 +202,13 @@ class Cartridge : public Device
|
||||||
*/
|
*/
|
||||||
virtual void setRomName(const string& name) { }
|
virtual void setRomName(const string& name) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
Thumbulator only supports 16-bit ARM code. Some Harmony/Melody drivers,
|
||||||
|
such as BUS and CDF, feature 32-bit ARM code subroutines. This is used
|
||||||
|
to pass values back to the cartridge class to emulate those subroutines.
|
||||||
|
*/
|
||||||
|
virtual uInt32 thumbCallback(uInt8 function, uInt32 value1, uInt32 value2) { return 0; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Get debugger widget responsible for accessing the inner workings
|
Get debugger widget responsible for accessing the inner workings
|
||||||
of the cart. This will need to be overridden and implemented by
|
of the cart. This will need to be overridden and implemented by
|
||||||
|
@ -279,12 +286,13 @@ class Cartridge : public Device
|
||||||
uInt32 minhits);
|
uInt32 minhits);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns true if the image is probably a SuperChip (256 bytes RAM)
|
Returns true if the image is probably a SuperChip (128 bytes RAM)
|
||||||
|
Note: should be called only on ROMs with size multiple of 4K
|
||||||
*/
|
*/
|
||||||
static bool isProbablySC(const uInt8* image, uInt32 size);
|
static bool isProbablySC(const uInt8* image, uInt32 size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns true if the image is probably a 4K SuperChip (256 bytes RAM)
|
Returns true if the image is probably a 4K SuperChip (128 bytes RAM)
|
||||||
*/
|
*/
|
||||||
static bool isProbably4KSC(const uInt8* image, uInt32 size);
|
static bool isProbably4KSC(const uInt8* image, uInt32 size);
|
||||||
|
|
||||||
|
@ -303,6 +311,11 @@ class Cartridge : public Device
|
||||||
*/
|
*/
|
||||||
static bool isProbably3E(const uInt8* image, uInt32 size);
|
static bool isProbably3E(const uInt8* image, uInt32 size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns true if the image is probably a 3E+ bankswitching cartridge
|
||||||
|
*/
|
||||||
|
static bool isProbably3EPlus(const uInt8* image, uInt32 size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns true if the image is probably a 3F bankswitching cartridge
|
Returns true if the image is probably a 3F bankswitching cartridge
|
||||||
*/
|
*/
|
||||||
|
@ -313,6 +326,21 @@ class Cartridge : public Device
|
||||||
*/
|
*/
|
||||||
static bool isProbably4A50(const uInt8* image, uInt32 size);
|
static bool isProbably4A50(const uInt8* image, uInt32 size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns true if the image is probably a BF/BFSC bankswitching cartridge
|
||||||
|
*/
|
||||||
|
static bool isProbablyBF(const uInt8* image, uInt32 size, const char*& type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns true if the image is probably a BUS bankswitching cartridge
|
||||||
|
*/
|
||||||
|
static bool isProbablyBUS(const uInt8* image, uInt32 size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns true if the image is probably a CDF bankswitching cartridge
|
||||||
|
*/
|
||||||
|
static bool isProbablyCDF(const uInt8* image, uInt32 size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns true if the image is probably a CTY bankswitching cartridge
|
Returns true if the image is probably a CTY bankswitching cartridge
|
||||||
*/
|
*/
|
||||||
|
@ -323,6 +351,21 @@ class Cartridge : public Device
|
||||||
*/
|
*/
|
||||||
static bool isProbablyCV(const uInt8* image, uInt32 size);
|
static bool isProbablyCV(const uInt8* image, uInt32 size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns true if the image is probably a CV+ bankswitching cartridge
|
||||||
|
*/
|
||||||
|
static bool isProbablyCVPlus(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 DF/DFSC bankswitching cartridge
|
||||||
|
*/
|
||||||
|
static bool isProbablyDF(const uInt8* image, uInt32 size, const char*& type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns true if the image is probably a DPC+ bankswitching cartridge
|
Returns true if the image is probably a DPC+ bankswitching cartridge
|
||||||
*/
|
*/
|
||||||
|
@ -338,24 +381,20 @@ class Cartridge : public Device
|
||||||
*/
|
*/
|
||||||
static bool isProbablyE7(const uInt8* image, uInt32 size);
|
static bool isProbablyE7(const uInt8* image, uInt32 size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns true if the image is probably a E78K bankswitching cartridge
|
||||||
|
*/
|
||||||
|
static bool isProbablyE78K(const uInt8* image, uInt32 size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns true if the image is probably an EF/EFSC bankswitching cartridge
|
Returns true if the image is probably an EF/EFSC bankswitching cartridge
|
||||||
*/
|
*/
|
||||||
static bool isProbablyEF(const uInt8* image, uInt32 size, const char*& type);
|
static bool isProbablyEF(const uInt8* image, uInt32 size, const char*& type);
|
||||||
|
|
||||||
/**
|
|
||||||
Returns true if the image is probably a BF/BFSC bankswitching cartridge
|
|
||||||
*/
|
|
||||||
static bool isProbablyBF(const uInt8* image, uInt32 size, const char*& type);
|
|
||||||
/**
|
|
||||||
Returns true if the image is probably a DF/DFSC bankswitching cartridge
|
|
||||||
*/
|
|
||||||
static bool isProbablyDF(const uInt8* image, uInt32 size, const char*& type);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns true if the image is probably an F6 bankswitching cartridge
|
Returns true if the image is probably an F6 bankswitching cartridge
|
||||||
*/
|
*/
|
||||||
static bool isProbablyF6(const uInt8* image, uInt32 size);
|
//static bool isProbablyF6(const uInt8* image, uInt32 size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns true if the image is probably an FA2 bankswitching cartridge
|
Returns true if the image is probably an FA2 bankswitching cartridge
|
||||||
|
@ -367,6 +406,11 @@ class Cartridge : public Device
|
||||||
*/
|
*/
|
||||||
static bool isProbablyFE(const uInt8* image, uInt32 size);
|
static bool isProbablyFE(const uInt8* image, uInt32 size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns true if the image is probably a MDM bankswitching cartridge
|
||||||
|
*/
|
||||||
|
static bool isProbablyMDM(const uInt8* image, uInt32 size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns true if the image is probably a SB bankswitching cartridge
|
Returns true if the image is probably a SB bankswitching cartridge
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -459,7 +459,7 @@ void CartridgeCTY::loadTune(uInt8 index)
|
||||||
void CartridgeCTY::loadScore(uInt8 index)
|
void CartridgeCTY::loadScore(uInt8 index)
|
||||||
{
|
{
|
||||||
Serializer serializer(myEEPROMFile, true);
|
Serializer serializer(myEEPROMFile, true);
|
||||||
if(serializer.isValid())
|
if(serializer)
|
||||||
{
|
{
|
||||||
uInt8 scoreRAM[256];
|
uInt8 scoreRAM[256];
|
||||||
try
|
try
|
||||||
|
@ -479,7 +479,7 @@ void CartridgeCTY::loadScore(uInt8 index)
|
||||||
void CartridgeCTY::saveScore(uInt8 index)
|
void CartridgeCTY::saveScore(uInt8 index)
|
||||||
{
|
{
|
||||||
Serializer serializer(myEEPROMFile);
|
Serializer serializer(myEEPROMFile);
|
||||||
if(serializer.isValid())
|
if(serializer)
|
||||||
{
|
{
|
||||||
// Load score RAM
|
// Load score RAM
|
||||||
uInt8 scoreRAM[256];
|
uInt8 scoreRAM[256];
|
||||||
|
@ -496,7 +496,7 @@ void CartridgeCTY::saveScore(uInt8 index)
|
||||||
memcpy(scoreRAM + (index << 6) + 4, myRAM+4, 60);
|
memcpy(scoreRAM + (index << 6) + 4, myRAM+4, 60);
|
||||||
|
|
||||||
// Save score RAM
|
// Save score RAM
|
||||||
serializer.reset();
|
serializer.rewind();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
serializer.putByteArray(scoreRAM, 256);
|
serializer.putByteArray(scoreRAM, 256);
|
||||||
|
@ -513,7 +513,7 @@ void CartridgeCTY::saveScore(uInt8 index)
|
||||||
void CartridgeCTY::wipeAllScores()
|
void CartridgeCTY::wipeAllScores()
|
||||||
{
|
{
|
||||||
Serializer serializer(myEEPROMFile);
|
Serializer serializer(myEEPROMFile);
|
||||||
if(serializer.isValid())
|
if(serializer)
|
||||||
{
|
{
|
||||||
// Erase score RAM
|
// Erase score RAM
|
||||||
uInt8 scoreRAM[256];
|
uInt8 scoreRAM[256];
|
||||||
|
|
|
@ -31,21 +31,24 @@
|
||||||
CartridgeDPCPlus::CartridgeDPCPlus(const uInt8* image, uInt32 size,
|
CartridgeDPCPlus::CartridgeDPCPlus(const uInt8* image, uInt32 size,
|
||||||
const Settings& settings)
|
const Settings& settings)
|
||||||
: Cartridge(settings),
|
: Cartridge(settings),
|
||||||
|
mySize(std::min(size, 32768u)),
|
||||||
myFastFetch(false),
|
myFastFetch(false),
|
||||||
myLDAimmediate(false),
|
myLDAimmediate(false),
|
||||||
myParameterPointer(0),
|
myParameterPointer(0),
|
||||||
mySystemCycles(0),
|
myAudioCycles(0),
|
||||||
myFractionalClocks(0.0)
|
myARMCycles(0),
|
||||||
|
myFractionalClocks(0.0),
|
||||||
|
myBankOffset(0)
|
||||||
{
|
{
|
||||||
// Store image, making sure it's at least 29KB
|
// Image is always 32K, but in the case of ROM > 29K, the image is
|
||||||
uInt32 minsize = 4096 * 6 + 4096 + 1024 + 255;
|
// copied to the end of the buffer
|
||||||
mySize = BSPF_max(minsize, size);
|
if(mySize < 32768u)
|
||||||
myImage = new uInt8[mySize];
|
memset(myImage, 0, 32768);
|
||||||
memcpy(myImage, image, size);
|
memcpy(myImage + (32768u - mySize), image, size);
|
||||||
createCodeAccessBase(4096 * 6);
|
createCodeAccessBase(4096 * 6);
|
||||||
|
|
||||||
// Pointer to the program ROM (24K @ 0 byte offset)
|
// Pointer to the program ROM (24K @ 3072 byte offset; ignore first 3K)
|
||||||
myProgramImage = myImage;
|
myProgramImage = myImage + 0xC00;
|
||||||
|
|
||||||
// Pointer to the display RAM
|
// Pointer to the display RAM
|
||||||
myDisplayImage = myDPCRAM + 0xC00;
|
myDisplayImage = myDPCRAM + 0xC00;
|
||||||
|
@ -53,16 +56,14 @@ CartridgeDPCPlus::CartridgeDPCPlus(const uInt8* image, uInt32 size,
|
||||||
// Pointer to the Frequency RAM
|
// Pointer to the Frequency RAM
|
||||||
myFrequencyImage = myDisplayImage + 0x1000;
|
myFrequencyImage = myDisplayImage + 0x1000;
|
||||||
|
|
||||||
// If the image is larger than 29K, we assume any excess at the
|
|
||||||
// beginning is ARM code, and skip over it
|
|
||||||
if(size > 29 * 1024)
|
|
||||||
myProgramImage += (size - 29 * 1024);
|
|
||||||
|
|
||||||
#ifdef THUMB_SUPPORT
|
#ifdef THUMB_SUPPORT
|
||||||
// Create Thumbulator ARM emulator
|
// Create Thumbulator ARM emulator
|
||||||
myThumbEmulator = new Thumbulator((uInt16*)(myProgramImage-0xC00),
|
myThumbEmulator = make_unique<Thumbulator>
|
||||||
(uInt16*)myDPCRAM,
|
(reinterpret_cast<uInt16*>(myImage),
|
||||||
settings.getBool("thumb.trapfatal"));
|
reinterpret_cast<uInt16*>(myDPCRAM),
|
||||||
|
settings.getBool("thumb.trapfatal"),
|
||||||
|
Thumbulator::ConfigureFor::DPCplus,
|
||||||
|
this);
|
||||||
#endif
|
#endif
|
||||||
setInitialState();
|
setInitialState();
|
||||||
|
|
||||||
|
@ -70,21 +71,11 @@ CartridgeDPCPlus::CartridgeDPCPlus(const uInt8* image, uInt32 size,
|
||||||
myStartBank = 5;
|
myStartBank = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
CartridgeDPCPlus::~CartridgeDPCPlus()
|
|
||||||
{
|
|
||||||
delete[] myImage;
|
|
||||||
|
|
||||||
#ifdef THUMB_SUPPORT
|
|
||||||
delete myThumbEmulator;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void CartridgeDPCPlus::reset()
|
void CartridgeDPCPlus::reset()
|
||||||
{
|
{
|
||||||
// Update cycles to the current system cycles
|
// Update cycles to the current system cycles
|
||||||
mySystemCycles = mySystem->cycles();
|
myAudioCycles = myARMCycles = mySystem->cycles();
|
||||||
myFractionalClocks = 0.0;
|
myFractionalClocks = 0.0;
|
||||||
|
|
||||||
setInitialState();
|
setInitialState();
|
||||||
|
@ -104,8 +95,11 @@ void CartridgeDPCPlus::setInitialState()
|
||||||
|
|
||||||
// Initialize the DPC data fetcher registers
|
// Initialize the DPC data fetcher registers
|
||||||
for(int i = 0; i < 8; ++i)
|
for(int i = 0; i < 8; ++i)
|
||||||
myTops[i] = myBottoms[i] = myCounters[i] = myFractionalIncrements[i] =
|
{
|
||||||
|
myTops[i] = myBottoms[i] = myFractionalIncrements[i] = 0;
|
||||||
myFractionalCounters[i] = 0;
|
myFractionalCounters[i] = 0;
|
||||||
|
myCounters[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Set waveforms to first waveform entry
|
// Set waveforms to first waveform entry
|
||||||
myMusicWaveforms[0] = myMusicWaveforms[1] = myMusicWaveforms[2] = 0;
|
myMusicWaveforms[0] = myMusicWaveforms[1] = myMusicWaveforms[2] = 0;
|
||||||
|
@ -121,7 +115,8 @@ void CartridgeDPCPlus::systemCyclesReset()
|
||||||
uInt32 cycles = mySystem->cycles();
|
uInt32 cycles = mySystem->cycles();
|
||||||
|
|
||||||
// Adjust the cycle counter so that it reflects the new value
|
// Adjust the cycle counter so that it reflects the new value
|
||||||
mySystemCycles -= cycles;
|
myAudioCycles -= cycles;
|
||||||
|
myARMCycles -= cycles;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -156,7 +151,7 @@ inline void CartridgeDPCPlus::clockRandomNumberGenerator()
|
||||||
inline void CartridgeDPCPlus::priorClockRandomNumberGenerator()
|
inline void CartridgeDPCPlus::priorClockRandomNumberGenerator()
|
||||||
{
|
{
|
||||||
// Update random number generator (32-bit LFSR, reversed)
|
// Update random number generator (32-bit LFSR, reversed)
|
||||||
myRandomNumber = ((myRandomNumber & (1<<31)) ?
|
myRandomNumber = ((myRandomNumber & (1u<<31)) ?
|
||||||
((0x10adab1e^myRandomNumber) << 11) | ((0x10adab1e^myRandomNumber) >> 21) :
|
((0x10adab1e^myRandomNumber) << 11) | ((0x10adab1e^myRandomNumber) >> 21) :
|
||||||
(myRandomNumber << 11) | (myRandomNumber >> 21));
|
(myRandomNumber << 11) | (myRandomNumber >> 21));
|
||||||
}
|
}
|
||||||
|
@ -165,24 +160,18 @@ inline void CartridgeDPCPlus::priorClockRandomNumberGenerator()
|
||||||
inline void CartridgeDPCPlus::updateMusicModeDataFetchers()
|
inline void CartridgeDPCPlus::updateMusicModeDataFetchers()
|
||||||
{
|
{
|
||||||
// Calculate the number of cycles since the last update
|
// Calculate the number of cycles since the last update
|
||||||
Int32 cycles = mySystem->cycles() - mySystemCycles;
|
uInt32 cycles = uInt32(mySystem->cycles() - myAudioCycles);
|
||||||
mySystemCycles = mySystem->cycles();
|
myAudioCycles = mySystem->cycles();
|
||||||
|
|
||||||
// Calculate the number of DPC OSC clocks since the last update
|
// Calculate the number of DPC+ OSC clocks since the last update
|
||||||
double clocks = ((20000.0 * cycles) / 1193191.66666667) + myFractionalClocks;
|
double clocks = ((20000.0 * cycles) / 1193191.66666667) + myFractionalClocks;
|
||||||
Int32 wholeClocks = (Int32)clocks;
|
uInt32 wholeClocks = uInt32(clocks);
|
||||||
myFractionalClocks = clocks - (double)wholeClocks;
|
myFractionalClocks = clocks - double(wholeClocks);
|
||||||
|
|
||||||
if(wholeClocks <= 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Let's update counters and flags of the music mode data fetchers
|
// Let's update counters and flags of the music mode data fetchers
|
||||||
for(int x = 0; x <= 2; ++x)
|
if(wholeClocks > 0)
|
||||||
{
|
for(int x = 0; x <= 2; ++x)
|
||||||
myMusicCounters[x] += myMusicFrequencies[x];
|
myMusicCounters[x] += myMusicFrequencies[x] * wholeClocks;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -206,19 +195,23 @@ inline void CartridgeDPCPlus::callFunction(uInt8 value)
|
||||||
myParameterPointer = 0;
|
myParameterPointer = 0;
|
||||||
break;
|
break;
|
||||||
#ifdef THUMB_SUPPORT
|
#ifdef THUMB_SUPPORT
|
||||||
case 254:
|
case 254: // call with IRQ driven audio, no special handling needed at this
|
||||||
case 255:
|
// time for Stella as ARM code "runs in zero 6507 cycles".
|
||||||
|
case 255: // call without IRQ driven audio
|
||||||
// Call user written ARM code (most likely be C compiled for ARM)
|
// Call user written ARM code (most likely be C compiled for ARM)
|
||||||
try {
|
try {
|
||||||
myThumbEmulator->run();
|
Int32 cycles = Int32(mySystem->cycles() - myARMCycles);
|
||||||
|
myARMCycles = mySystem->cycles();
|
||||||
|
|
||||||
|
myThumbEmulator->run(cycles);
|
||||||
}
|
}
|
||||||
catch(const string& error) {
|
catch(const runtime_error& e) {
|
||||||
if(!mySystem->autodetectMode())
|
if(!mySystem->autodetectMode())
|
||||||
{
|
{
|
||||||
#ifdef DEBUGGER_SUPPORT
|
#ifdef DEBUGGER_SUPPORT
|
||||||
Debugger::debugger().startWithFatalError(error);
|
Debugger::debugger().startWithFatalError(e.what());
|
||||||
#else
|
#else
|
||||||
cout << error << endl;
|
cout << e.what() << endl;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -233,7 +226,7 @@ uInt8 CartridgeDPCPlus::peek(uInt16 address)
|
||||||
{
|
{
|
||||||
address &= 0x0FFF;
|
address &= 0x0FFF;
|
||||||
|
|
||||||
uInt8 peekvalue = myProgramImage[(myCurrentBank << 12) + address];
|
uInt8 peekvalue = myProgramImage[myBankOffset + address];
|
||||||
uInt8 flag;
|
uInt8 flag;
|
||||||
|
|
||||||
// In debugger/bank-locked mode, we ignore all hotspots and in general
|
// In debugger/bank-locked mode, we ignore all hotspots and in general
|
||||||
|
@ -300,7 +293,7 @@ uInt8 CartridgeDPCPlus::peek(uInt16 address)
|
||||||
myDisplayImage[(myMusicWaveforms[1] << 5) + (myMusicCounters[1] >> 27)] +
|
myDisplayImage[(myMusicWaveforms[1] << 5) + (myMusicCounters[1] >> 27)] +
|
||||||
myDisplayImage[(myMusicWaveforms[2] << 5) + (myMusicCounters[2] >> 27)];
|
myDisplayImage[(myMusicWaveforms[2] << 5) + (myMusicCounters[2] >> 27)];
|
||||||
|
|
||||||
result = (uInt8)i;
|
result = uInt8(i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -425,12 +418,12 @@ bool CartridgeDPCPlus::poke(uInt16 address, uInt8 value)
|
||||||
{
|
{
|
||||||
//DFxFRACLOW - fractional data pointer low byte
|
//DFxFRACLOW - fractional data pointer low byte
|
||||||
case 0x00:
|
case 0x00:
|
||||||
myFractionalCounters[index] = (myFractionalCounters[index] & 0x0F0000) | ((uInt16)value << 8);
|
myFractionalCounters[index] = (myFractionalCounters[index] & 0x0F00FF) | (uInt16(value) << 8);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// DFxFRACHI - fractional data pointer high byte
|
// DFxFRACHI - fractional data pointer high byte
|
||||||
case 0x01:
|
case 0x01:
|
||||||
myFractionalCounters[index] = (((uInt16)value & 0x0F) << 16) | (myFractionalCounters[index] & 0x00ffff);
|
myFractionalCounters[index] = ((uInt16(value) & 0x0F) << 16) | (myFractionalCounters[index] & 0x00ffff);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//DFxFRACINC - Fractional Increment amount
|
//DFxFRACINC - Fractional Increment amount
|
||||||
|
@ -494,7 +487,7 @@ bool CartridgeDPCPlus::poke(uInt16 address, uInt8 value)
|
||||||
// DFxHI - data pointer high byte
|
// DFxHI - data pointer high byte
|
||||||
case 0x08:
|
case 0x08:
|
||||||
{
|
{
|
||||||
myCounters[index] = (((uInt16)value & 0x0F) << 8) | (myCounters[index] & 0x00ff);
|
myCounters[index] = ((uInt16(value) & 0x0F) << 8) | (myCounters[index] & 0x00ff);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -605,17 +598,16 @@ bool CartridgeDPCPlus::bank(uInt16 bank)
|
||||||
if(bankLocked()) return false;
|
if(bankLocked()) return false;
|
||||||
|
|
||||||
// Remember what bank we're in
|
// Remember what bank we're in
|
||||||
myCurrentBank = bank;
|
myBankOffset = bank << 12;
|
||||||
uInt16 offset = myCurrentBank << 12;
|
|
||||||
uInt16 shift = mySystem->pageShift();
|
uInt16 shift = mySystem->pageShift();
|
||||||
|
|
||||||
// Setup the page access methods for the current bank
|
// Setup the page access methods for the current bank
|
||||||
System::PageAccess access(0, 0, 0, this, System::PA_READ);
|
System::PageAccess access(0, 0, 0, this, System::PA_READ);
|
||||||
|
|
||||||
// Map Program ROM image into the system
|
// Map Program ROM image into the system
|
||||||
for(uInt32 address = 0x1080; address < 0x2000; address += (1 << shift))
|
for(uInt16 address = 0x1080; address < 0x2000; address += (1 << shift))
|
||||||
{
|
{
|
||||||
access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
|
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (address & 0x0FFF)];
|
||||||
mySystem->setPageAccess(address >> shift, access);
|
mySystem->setPageAccess(address >> shift, access);
|
||||||
}
|
}
|
||||||
return myBankChanged = true;
|
return myBankChanged = true;
|
||||||
|
@ -624,7 +616,7 @@ bool CartridgeDPCPlus::bank(uInt16 bank)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
uInt16 CartridgeDPCPlus::bank() const
|
uInt16 CartridgeDPCPlus::bank() const
|
||||||
{
|
{
|
||||||
return myCurrentBank;
|
return myBankOffset >> 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -641,7 +633,7 @@ bool CartridgeDPCPlus::patch(uInt16 address, uInt8 value)
|
||||||
// For now, we ignore attempts to patch the DPC address space
|
// For now, we ignore attempts to patch the DPC address space
|
||||||
if(address >= 0x0080)
|
if(address >= 0x0080)
|
||||||
{
|
{
|
||||||
myProgramImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value;
|
myProgramImage[myBankOffset + (address & 0x0FFF)] = value;
|
||||||
return myBankChanged = true;
|
return myBankChanged = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -652,7 +644,7 @@ bool CartridgeDPCPlus::patch(uInt16 address, uInt8 value)
|
||||||
const uInt8* CartridgeDPCPlus::getImage(int& size) const
|
const uInt8* CartridgeDPCPlus::getImage(int& size) const
|
||||||
{
|
{
|
||||||
size = mySize;
|
size = mySize;
|
||||||
return myImage;
|
return myImage + (32768u - mySize);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -660,10 +652,8 @@ bool CartridgeDPCPlus::save(Serializer& out) const
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
out.putString(name());
|
|
||||||
|
|
||||||
// Indicates which bank is currently active
|
// Indicates which bank is currently active
|
||||||
out.putShort(myCurrentBank);
|
out.putShort(myBankOffset);
|
||||||
|
|
||||||
// Harmony RAM
|
// Harmony RAM
|
||||||
out.putByteArray(myDPCRAM, 8192);
|
out.putByteArray(myDPCRAM, 8192);
|
||||||
|
@ -702,8 +692,12 @@ bool CartridgeDPCPlus::save(Serializer& out) const
|
||||||
// The random number generator register
|
// The random number generator register
|
||||||
out.putInt(myRandomNumber);
|
out.putInt(myRandomNumber);
|
||||||
|
|
||||||
out.putInt(mySystemCycles);
|
// Get system cycles and fractional clocks
|
||||||
out.putInt((uInt32)(myFractionalClocks * 100000000.0));
|
out.putLong(myAudioCycles);
|
||||||
|
out.putDouble(myFractionalClocks);
|
||||||
|
|
||||||
|
// Clock info for Thumbulator
|
||||||
|
out.putLong(myARMCycles);
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
|
@ -719,11 +713,8 @@ bool CartridgeDPCPlus::load(Serializer& in)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if(in.getString() != name())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Indicates which bank is currently active
|
// Indicates which bank is currently active
|
||||||
myCurrentBank = in.getShort();
|
myBankOffset = in.getShort();
|
||||||
|
|
||||||
// Harmony RAM
|
// Harmony RAM
|
||||||
in.getByteArray(myDPCRAM, 8192);
|
in.getByteArray(myDPCRAM, 8192);
|
||||||
|
@ -762,9 +753,12 @@ bool CartridgeDPCPlus::load(Serializer& in)
|
||||||
// The random number generator register
|
// The random number generator register
|
||||||
myRandomNumber = in.getInt();
|
myRandomNumber = in.getInt();
|
||||||
|
|
||||||
// Get system cycles and fractional clocks
|
// Get audio cycles and fractional clocks
|
||||||
mySystemCycles = (Int32)in.getInt();
|
myAudioCycles = in.getLong();
|
||||||
myFractionalClocks = (double)in.getInt() / 100000000.0;
|
myFractionalClocks = in.getDouble();
|
||||||
|
|
||||||
|
// Clock info for Thumbulator
|
||||||
|
myARMCycles = in.getLong();
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
|
@ -773,7 +767,7 @@ bool CartridgeDPCPlus::load(Serializer& in)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now, go to the current bank
|
// Now, go to the current bank
|
||||||
bank(myCurrentBank);
|
bank(myBankOffset >> 12);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,11 +56,7 @@ class CartridgeDPCPlus : public Cartridge
|
||||||
@param settings A reference to the various settings (read-only)
|
@param settings A reference to the various settings (read-only)
|
||||||
*/
|
*/
|
||||||
CartridgeDPCPlus(const uInt8* image, uInt32 size, const Settings& settings);
|
CartridgeDPCPlus(const uInt8* image, uInt32 size, const Settings& settings);
|
||||||
|
virtual ~CartridgeDPCPlus() = default;
|
||||||
/**
|
|
||||||
Destructor
|
|
||||||
*/
|
|
||||||
virtual ~CartridgeDPCPlus();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
@ -198,7 +194,7 @@ class CartridgeDPCPlus : public Cartridge
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// The ROM image and size
|
// The ROM image and size
|
||||||
uInt8* myImage;
|
uInt8 myImage[32768];
|
||||||
uInt32 mySize;
|
uInt32 mySize;
|
||||||
|
|
||||||
// Pointer to the 24K program ROM image of the cartridge
|
// Pointer to the 24K program ROM image of the cartridge
|
||||||
|
@ -207,20 +203,20 @@ class CartridgeDPCPlus : public Cartridge
|
||||||
// Pointer to the 4K display ROM image of the cartridge
|
// Pointer to the 4K display ROM image of the cartridge
|
||||||
uInt8* myDisplayImage;
|
uInt8* myDisplayImage;
|
||||||
|
|
||||||
// The DPC 8k RAM image
|
// The DPC 8k RAM image, used as:
|
||||||
|
// 3K DPC+ driver
|
||||||
|
// 4K Display Data
|
||||||
|
// 1K Frequency Data
|
||||||
uInt8 myDPCRAM[8192];
|
uInt8 myDPCRAM[8192];
|
||||||
|
|
||||||
#ifdef THUMB_SUPPORT
|
#ifdef THUMB_SUPPORT
|
||||||
// Pointer to the Thumb ARM emulator object
|
// Pointer to the Thumb ARM emulator object
|
||||||
Thumbulator* myThumbEmulator;
|
unique_ptr<Thumbulator> myThumbEmulator;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Pointer to the 1K frequency table
|
// Pointer to the 1K frequency table
|
||||||
uInt8* myFrequencyImage;
|
uInt8* myFrequencyImage;
|
||||||
|
|
||||||
// Indicates which bank is currently active
|
|
||||||
uInt16 myCurrentBank;
|
|
||||||
|
|
||||||
// The top registers for the data fetchers
|
// The top registers for the data fetchers
|
||||||
uInt8 myTops[8];
|
uInt8 myTops[8];
|
||||||
|
|
||||||
|
@ -261,10 +257,16 @@ class CartridgeDPCPlus : public Cartridge
|
||||||
uInt32 myRandomNumber;
|
uInt32 myRandomNumber;
|
||||||
|
|
||||||
// System cycle count when the last update to music data fetchers occurred
|
// System cycle count when the last update to music data fetchers occurred
|
||||||
Int32 mySystemCycles;
|
uInt64 myAudioCycles;
|
||||||
|
|
||||||
|
// System cycle count when the last Thumbulator::run() occurred
|
||||||
|
uInt64 myARMCycles;
|
||||||
|
|
||||||
// Fractional DPC music OSC clocks unused during the last update
|
// Fractional DPC music OSC clocks unused during the last update
|
||||||
double myFractionalClocks;
|
double myFractionalClocks;
|
||||||
|
|
||||||
|
// Indicates the offset into the ROM image (aligns to current bank)
|
||||||
|
uInt16 myBankOffset;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -385,7 +385,7 @@ uInt8 CartridgeFA2::ramReadWrite()
|
||||||
// We go ahead and do the access now, and only return when a sufficient
|
// We go ahead and do the access now, and only return when a sufficient
|
||||||
// amount of time has passed
|
// amount of time has passed
|
||||||
Serializer serializer(myFlashFile);
|
Serializer serializer(myFlashFile);
|
||||||
if(serializer.isValid())
|
if(serializer)
|
||||||
{
|
{
|
||||||
if(myRAM[255] == 1) // read
|
if(myRAM[255] == 1) // read
|
||||||
{
|
{
|
||||||
|
@ -437,7 +437,7 @@ uInt8 CartridgeFA2::ramReadWrite()
|
||||||
void CartridgeFA2::flash(uInt8 operation)
|
void CartridgeFA2::flash(uInt8 operation)
|
||||||
{
|
{
|
||||||
Serializer serializer(myFlashFile);
|
Serializer serializer(myFlashFile);
|
||||||
if(serializer.isValid())
|
if(serializer)
|
||||||
{
|
{
|
||||||
if(operation == 0) // erase
|
if(operation == 0) // erase
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,290 +0,0 @@
|
||||||
//============================================================================
|
|
||||||
//
|
|
||||||
// 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: CartMC.cxx 2838 2014-01-17 23:34:03Z stephena $
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
#include "System.hxx"
|
|
||||||
#include "CartMC.hxx"
|
|
||||||
|
|
||||||
// TODO - much more testing of this scheme is required
|
|
||||||
// No test ROMs exist as of 2009-11-08, so we can't be sure how
|
|
||||||
// accurate the emulation is
|
|
||||||
// Bankchange and RAM modification cannot be completed until
|
|
||||||
// adequate test ROMs are available
|
|
||||||
// TODO (2010-10-03) - support CodeAccessBase functionality somehow
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
CartridgeMC::CartridgeMC(const uInt8* image, uInt32 size,
|
|
||||||
const Settings& settings)
|
|
||||||
: Cartridge(settings),
|
|
||||||
mySlot3Locked(false)
|
|
||||||
{
|
|
||||||
// Make sure size is reasonable
|
|
||||||
assert(size <= 131072);
|
|
||||||
|
|
||||||
// Set the contents of the entire ROM to 0
|
|
||||||
memset(myImage, 0, 131072);
|
|
||||||
|
|
||||||
// Copy the ROM image to the end of the ROM buffer
|
|
||||||
memcpy(myImage + 131072 - size, image, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
CartridgeMC::~CartridgeMC()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
void CartridgeMC::reset()
|
|
||||||
{
|
|
||||||
// Initialize RAM
|
|
||||||
if(mySettings.getBool("ramrandom"))
|
|
||||||
for(uInt32 i = 0; i < 32768; ++i)
|
|
||||||
myRAM[i] = mySystem->randGenerator().next();
|
|
||||||
else
|
|
||||||
memset(myRAM, 0, 32768);
|
|
||||||
|
|
||||||
myBankChanged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
void CartridgeMC::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) && ((0x1400 & mask) == 0) &&
|
|
||||||
((0x1800 & mask) == 0) && ((0x1C00 & mask) == 0));
|
|
||||||
|
|
||||||
// Set the page accessing methods for the hot spots in the TIA. For
|
|
||||||
// correct emulation I would need to chain any accesses below 0x40 to
|
|
||||||
// the TIA but for now I'll just forget about them.
|
|
||||||
//
|
|
||||||
// TODO: These TIA accesses may need to be chained, however, at this
|
|
||||||
// point Chris isn't sure if the hardware will allow it or not
|
|
||||||
//
|
|
||||||
System::PageAccess access(0, 0, 0, this, System::PA_READWRITE);
|
|
||||||
|
|
||||||
for(uInt32 i = 0x00; i < 0x40; i += (1 << shift))
|
|
||||||
mySystem->setPageAccess(i >> shift, access);
|
|
||||||
|
|
||||||
// Map the cartridge into the system
|
|
||||||
access.type = System::PA_READ; // We don't yet indicate RAM areas
|
|
||||||
for(uInt32 j = 0x1000; j < 0x2000; j += (1 << shift))
|
|
||||||
mySystem->setPageAccess(j >> shift, access);
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
uInt8 CartridgeMC::peek(uInt16 address)
|
|
||||||
{
|
|
||||||
uInt16 peekAddress = address;
|
|
||||||
address &= 0x1FFF;
|
|
||||||
|
|
||||||
// Accessing the RESET vector so lets handle the powerup special case
|
|
||||||
if((address == 0x1FFC) || (address == 0x1FFD))
|
|
||||||
{
|
|
||||||
// Indicate that slot 3 is locked for now
|
|
||||||
mySlot3Locked = true;
|
|
||||||
}
|
|
||||||
// Should we unlock slot 3?
|
|
||||||
else if(mySlot3Locked && (address >= 0x1000) && (address <= 0x1BFF))
|
|
||||||
{
|
|
||||||
// Indicate that slot 3 is unlocked now
|
|
||||||
mySlot3Locked = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle reads made to the TIA addresses
|
|
||||||
if(address < 0x1000)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
uInt8 block;
|
|
||||||
|
|
||||||
if(mySlot3Locked && ((address & 0x0C00) == 0x0C00))
|
|
||||||
{
|
|
||||||
block = 0xFF;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
block = myCurrentBlock[(address & 0x0C00) >> 10];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is this a RAM or a ROM access
|
|
||||||
if(block & 0x80)
|
|
||||||
{
|
|
||||||
// ROM access
|
|
||||||
return myImage[(uInt32)((block & 0x7F) << 10) + (address & 0x03FF)];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// This is a RAM access, however, is it to the read or write port?
|
|
||||||
if(address & 0x0200)
|
|
||||||
{
|
|
||||||
// Reading from the read port of the RAM block
|
|
||||||
return myRAM[(uInt32)((block & 0x3F) << 9) + (address & 0x01FF)];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Oops, reading from the write port of the RAM block!
|
|
||||||
// Reading from the write port triggers an unwanted write
|
|
||||||
uInt8 value = mySystem->getDataBusState(0xFF);
|
|
||||||
|
|
||||||
if(bankLocked())
|
|
||||||
return value;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
triggerReadFromWritePort(peekAddress);
|
|
||||||
return myRAM[(uInt32)((block & 0x3F) << 9) + (address & 0x01FF)] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
bool CartridgeMC::poke(uInt16 address, uInt8 value)
|
|
||||||
{
|
|
||||||
address &= 0x1FFF;
|
|
||||||
|
|
||||||
// Accessing the RESET vector so lets handle the powerup special case
|
|
||||||
if((address == 0x1FFC) || (address == 0x1FFD))
|
|
||||||
{
|
|
||||||
// Indicate that slot 3 is locked for now
|
|
||||||
mySlot3Locked = true;
|
|
||||||
}
|
|
||||||
// Should we unlock slot 3?
|
|
||||||
else if(mySlot3Locked && (address >= 0x1000) && (address <= 0x1BFF))
|
|
||||||
{
|
|
||||||
// Indicate that slot 3 is unlocked now
|
|
||||||
mySlot3Locked = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle bank-switching writes
|
|
||||||
if((address >= 0x003C) && (address <= 0x003F))
|
|
||||||
{
|
|
||||||
myCurrentBlock[address - 0x003C] = value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
uInt8 block;
|
|
||||||
|
|
||||||
if(mySlot3Locked && ((address & 0x0C00) == 0x0C00))
|
|
||||||
{
|
|
||||||
block = 0xFF;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
block = myCurrentBlock[(address & 0x0C00) >> 10];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is this a RAM write access
|
|
||||||
if(!(block & 0x80) && !(address & 0x0200))
|
|
||||||
{
|
|
||||||
// Handle the write to RAM
|
|
||||||
myRAM[(uInt32)((block & 0x3F) << 9) + (address & 0x01FF)] = value;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
bool CartridgeMC::bank(uInt16 b)
|
|
||||||
{
|
|
||||||
// Doesn't support bankswitching in the normal sense
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
uInt16 CartridgeMC::bank() const
|
|
||||||
{
|
|
||||||
// TODO - add support for debugger
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
uInt16 CartridgeMC::bankCount() const
|
|
||||||
{
|
|
||||||
// TODO - add support for debugger
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
bool CartridgeMC::patch(uInt16 address, uInt8 value)
|
|
||||||
{
|
|
||||||
// TODO - add support for debugger
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
const uInt8* CartridgeMC::getImage(int& size) const
|
|
||||||
{
|
|
||||||
size = 128 * 1024;
|
|
||||||
return myImage;
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
bool CartridgeMC::save(Serializer& out) const
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
out.putString(name());
|
|
||||||
|
|
||||||
// The currentBlock array
|
|
||||||
out.putByteArray(myCurrentBlock, 4);
|
|
||||||
|
|
||||||
// The 32K of RAM
|
|
||||||
out.putByteArray(myRAM, 32 * 1024);
|
|
||||||
}
|
|
||||||
catch(...)
|
|
||||||
{
|
|
||||||
cerr << "ERROR: CartridgeMC::save" << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
bool CartridgeMC::load(Serializer& in)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if(in.getString() != name())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// The currentBlock array
|
|
||||||
in.getByteArray(myCurrentBlock, 4);
|
|
||||||
|
|
||||||
// The 32K of RAM
|
|
||||||
in.getByteArray(myRAM, 32 * 1024);
|
|
||||||
}
|
|
||||||
catch(...)
|
|
||||||
{
|
|
||||||
cerr << "ERROR: CartridgeMC::load" << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
|
@ -1,277 +0,0 @@
|
||||||
//============================================================================
|
|
||||||
//
|
|
||||||
// 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: CartMC.hxx 2838 2014-01-17 23:34:03Z stephena $
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
#ifndef CARTRIDGEMC_HXX
|
|
||||||
#define CARTRIDGEMC_HXX
|
|
||||||
|
|
||||||
class System;
|
|
||||||
|
|
||||||
#include "bspf.hxx"
|
|
||||||
#include "Cart.hxx"
|
|
||||||
#ifdef DEBUGGER_SUPPORT
|
|
||||||
#include "CartMCWidget.hxx"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
This is the cartridge class for Chris Wilkson's Megacart. It does not
|
|
||||||
handle battery-backed RAM at this time and the code could use some serious
|
|
||||||
speed improvements. It is based on the following Megacart specification:
|
|
||||||
|
|
||||||
|
|
||||||
Megacart Specification, Rev1.1
|
|
||||||
(c) 1997 Chris Wilkson
|
|
||||||
cwilkson@mit.edu
|
|
||||||
|
|
||||||
Description
|
|
||||||
-----------
|
|
||||||
|
|
||||||
The Megacart is an external memory cartridge for the Atari 2600 and compatible
|
|
||||||
home video game consoles. It plugs into the standard cartridge port, and
|
|
||||||
contains a total of 128K bytes of ROM storage and 32K bytes of battery-backed
|
|
||||||
RAM storage.
|
|
||||||
|
|
||||||
General Operation
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
The Megacart uses "bank switching" to fit the 160K bytes of physical memory
|
|
||||||
into the console's available 4K address space. Physical memory is divided
|
|
||||||
into 64 RAM blocks of 512 bytes each, and 128 ROM blocks of 1K bytes each.
|
|
||||||
RAM blocks are numbered $00 through $3F, and ROM blocks are numbered $80
|
|
||||||
through $FF.
|
|
||||||
|
|
||||||
The console's address space is divided into 4 slots of 1K each. Any physical
|
|
||||||
memory block can be switched into any memory slot by writing its block number
|
|
||||||
to the "hot address" for the desired slot. Memory locations $3C through $3F
|
|
||||||
serve as "hot addresses" for memory slots 0 through 3, respectively.
|
|
||||||
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
To make ROM addresses $1A400-$1A7FF (block $E9) available to the console at
|
|
||||||
memory locations $F800-$FBFF (slot 2), write $E9 to memory location $3e.
|
|
||||||
|
|
||||||
Caution:
|
|
||||||
|
|
||||||
Note that these memory locations are write only. Trying to read the contents
|
|
||||||
of memory locations $3C through $3F will not only return invalid data, but
|
|
||||||
will also corrupt the contents causing the software to crash. Reading these
|
|
||||||
addresses should not be attempted.
|
|
||||||
|
|
||||||
Special Case - RAM
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
RAM blocks differ from ROM blocks in that one of the console's address lines,
|
|
||||||
A9 in this case, must be used as a read/write select. Because of this, RAM
|
|
||||||
blocks are limited to 512 bytes each, yet still occupy an entire 1K slot.
|
|
||||||
To store a value A9 must be low. To retrieve a value A9 must high.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
First, let's set slot 0 (console addresses $F000-$F3FF) to point to RAM
|
|
||||||
block $9 (RAM $1200-$13ff). To do this, write $9 to console address $3c.
|
|
||||||
To store the value $69 in RAM location $1234, write $69 to console address
|
|
||||||
$F034 (A9=0). To retrieve the value of RAM location $1234, read from console
|
|
||||||
address $F234 (A9=1).
|
|
||||||
|
|
||||||
Special Case - Powerup
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
Because the console's memory is randomized at powerup, there is no way to
|
|
||||||
predict the data initially contained in the "hot addresses". Therefore,
|
|
||||||
hardware will force slot 3 to always point to ROM block $FF immediately
|
|
||||||
after any read or write to the RESET vector at $FFFC-$FFFD. Block $FF
|
|
||||||
must contain code to initialize the 4 memory slots to point to the desired
|
|
||||||
physical memory blocks before any other code can be executed. After program
|
|
||||||
execution jumps out of the boot code, the hardware will release slot 3 and
|
|
||||||
it will function just like any other slot.
|
|
||||||
|
|
||||||
Example (the first column is the physical ROM address):
|
|
||||||
|
|
||||||
$00C00 JUNK ... ; random code and data
|
|
||||||
...
|
|
||||||
...
|
|
||||||
...
|
|
||||||
...
|
|
||||||
$1F400 START ... ; program starts here
|
|
||||||
... ; slot 3 now points to rom block $83
|
|
||||||
...
|
|
||||||
...
|
|
||||||
...
|
|
||||||
$1FFDD BOOT SEI ; disable interrupts
|
|
||||||
$1FFDE CLD ; set hexadecimal arithmetic mode
|
|
||||||
$1FFDF LDX #$FF ;
|
|
||||||
$1FFE1 TXS ; set stack pointer to $ff
|
|
||||||
$1FFE2 LDA #$00
|
|
||||||
$1FFE4 ZERO STA 00,X ; clear RIOT and TIA -BEFORE- setting
|
|
||||||
$1FFE6 DEX ; up banks
|
|
||||||
$1FFE7 BNE ZERO
|
|
||||||
$1FFE9 BANKS LDA #$00 ; ram block 0 ($0000-$01ff)
|
|
||||||
$1FFEB STA SLOT0 ; slot 0 points to ram block 0
|
|
||||||
$1FFED LDA #$34 ; ram block $34 ($6800-$69ff)
|
|
||||||
$1FFEF STA SLOT1 ; slot 1 points to ram block $34
|
|
||||||
$1FFF1 LDA #$FD ; rom block $fd ($1f400-$1f7ff)
|
|
||||||
$1FFF3 STA SLOT2 ; slot 2 points to rom block $fd
|
|
||||||
$1FFF5 LDA #$83 ; rom block $83 ($00C00-$01000)
|
|
||||||
$1FFF7 STA SLOT3 ; slot 3 points to bootcode
|
|
||||||
; (rom block $ff)
|
|
||||||
; until jumping out of slot 3
|
|
||||||
$1FFF9 JMP $F800 ; jump to slot 2
|
|
||||||
$1FFFC RESET .WORD $FFDD ; powerup reset vector
|
|
||||||
$1FFFE SWI .WORD $FFDD ; software interrupt vector (BRK)
|
|
||||||
|
|
||||||
|
|
||||||
@author Bradford W. Mott
|
|
||||||
@version $Id: CartMC.hxx 2838 2014-01-17 23:34:03Z stephena $
|
|
||||||
*/
|
|
||||||
class CartridgeMC : public Cartridge
|
|
||||||
{
|
|
||||||
friend class CartridgeMCWidget;
|
|
||||||
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
Create a new cartridge using the specified image and size. If the
|
|
||||||
size of the image is less than 128K then the cartridge will pad the
|
|
||||||
beginning of the 128K ROM with zeros.
|
|
||||||
|
|
||||||
@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)
|
|
||||||
*/
|
|
||||||
CartridgeMC(const uInt8* image, uInt32 size, const Settings& settings);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Destructor
|
|
||||||
*/
|
|
||||||
virtual ~CartridgeMC();
|
|
||||||
|
|
||||||
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 "CartridgeMC"; }
|
|
||||||
|
|
||||||
#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 new CartridgeMCWidget(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:
|
|
||||||
// The 128K ROM image for the cartridge
|
|
||||||
uInt8 myImage[131072];
|
|
||||||
|
|
||||||
// The 32K of RAM for the cartridge
|
|
||||||
uInt8 myRAM[32768];
|
|
||||||
|
|
||||||
// Indicates which block is currently active for the four segments
|
|
||||||
uInt8 myCurrentBlock[4];
|
|
||||||
|
|
||||||
// Indicates if slot 3 is locked to block $FF or not
|
|
||||||
bool mySlot3Locked;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// 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-2018 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 CONSOLE_TIMING_HXX
|
||||||
|
#define CONSOLE_TIMING_HXX
|
||||||
|
|
||||||
|
/**
|
||||||
|
Contains timing information about the specified console.
|
||||||
|
*/
|
||||||
|
enum class ConsoleTiming
|
||||||
|
{
|
||||||
|
ntsc, // console with CPU running at 1.193182 MHz, NTSC colours
|
||||||
|
pal, // console with CPU running at 1.182298 MHz, PAL colours
|
||||||
|
secam // console with CPU running at 1.187500 MHz, SECAM colours
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CONSOLE_TIMING_HXX
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
class System;
|
class System;
|
||||||
|
|
||||||
|
#include "ConsoleTiming.hxx"
|
||||||
#include "Serializable.hxx"
|
#include "Serializable.hxx"
|
||||||
#include "bspf.hxx"
|
#include "bspf.hxx"
|
||||||
|
|
||||||
|
@ -55,6 +56,15 @@ class Device : public Serializable
|
||||||
*/
|
*/
|
||||||
virtual void reset() = 0;
|
virtual void reset() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Notification method invoked by the system when the console type
|
||||||
|
has changed. It may be necessary to override this method for
|
||||||
|
devices that want to know about console changes.
|
||||||
|
|
||||||
|
@param timing Enum representing the new console type
|
||||||
|
*/
|
||||||
|
virtual void consoleChanged(ConsoleTiming timing) { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Notification method invoked by the system right before the
|
Notification method invoked by the system right before the
|
||||||
system resets its cycle counter to zero. It may be necessary
|
system resets its cycle counter to zero. It may be necessary
|
||||||
|
|
|
@ -8,13 +8,11 @@
|
||||||
// SS SS tt ee ll ll aa aa
|
// SS SS tt ee ll ll aa aa
|
||||||
// SSSS ttt eeeee llll llll aaaaa
|
// SSSS ttt eeeee llll llll aaaaa
|
||||||
//
|
//
|
||||||
// Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony
|
// Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony
|
||||||
// and the Stella Team
|
// and the Stella Team
|
||||||
//
|
//
|
||||||
// See the file "License.txt" for information on usage and redistribution of
|
// See the file "License.txt" for information on usage and redistribution of
|
||||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||||
//
|
|
||||||
// $Id: Serializer.cxx 2838 2014-01-17 23:34:03Z stephena $
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
@ -23,25 +21,25 @@
|
||||||
#include "FSNode.hxx"
|
#include "FSNode.hxx"
|
||||||
#include "Serializer.hxx"
|
#include "Serializer.hxx"
|
||||||
|
|
||||||
|
using std::ios;
|
||||||
|
using std::ios_base;
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
Serializer::Serializer(const string& filename, bool readonly)
|
Serializer::Serializer(const string& filename, bool readonly)
|
||||||
: myStream(NULL),
|
: myStream(nullptr)
|
||||||
myUseFilestream(true)
|
|
||||||
{
|
{
|
||||||
if(readonly)
|
if(readonly)
|
||||||
{
|
{
|
||||||
FilesystemNode node(filename);
|
FilesystemNode node(filename);
|
||||||
if(node.isFile() && node.isReadable())
|
if(node.isFile() && node.isReadable())
|
||||||
{
|
{
|
||||||
fstream* str = new fstream(filename.c_str(), ios::in | ios::binary);
|
unique_ptr<fstream> str = make_unique<fstream>(filename, ios::in | ios::binary);
|
||||||
if(str && str->is_open())
|
if(str && str->is_open())
|
||||||
{
|
{
|
||||||
myStream = str;
|
myStream = std::move(str);
|
||||||
myStream->exceptions( ios_base::failbit | ios_base::badbit | ios_base::eofbit );
|
myStream->exceptions( ios_base::failbit | ios_base::badbit | ios_base::eofbit );
|
||||||
reset();
|
rewind();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
delete str;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -53,27 +51,24 @@ Serializer::Serializer(const string& filename, bool readonly)
|
||||||
// So we open in write and append mode - the write creates the file
|
// So we open in write and append mode - the write creates the file
|
||||||
// when necessary, and the append doesn't delete any data if it
|
// when necessary, and the append doesn't delete any data if it
|
||||||
// already exists
|
// already exists
|
||||||
fstream temp(filename.c_str(), ios::out | ios::app);
|
fstream temp(filename, ios::out | ios::app);
|
||||||
temp.close();
|
temp.close();
|
||||||
|
|
||||||
fstream* str = new fstream(filename.c_str(), ios::in | ios::out | ios::binary);
|
unique_ptr<fstream> str = make_unique<fstream>(filename, ios::in | ios::out | ios::binary);
|
||||||
if(str && str->is_open())
|
if(str && str->is_open())
|
||||||
{
|
{
|
||||||
myStream = str;
|
myStream = std::move(str);
|
||||||
myStream->exceptions( ios_base::failbit | ios_base::badbit | ios_base::eofbit );
|
myStream->exceptions( ios_base::failbit | ios_base::badbit | ios_base::eofbit );
|
||||||
reset();
|
rewind();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
delete str;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
Serializer::Serializer(void)
|
Serializer::Serializer()
|
||||||
: myStream(NULL),
|
: myStream(nullptr)
|
||||||
myUseFilestream(false)
|
|
||||||
{
|
{
|
||||||
myStream = new stringstream(ios::in | ios::out | ios::binary);
|
myStream = make_unique<stringstream>(ios::in | ios::out | ios::binary);
|
||||||
|
|
||||||
// For some reason, Windows and possibly OSX needs to store something in
|
// For some reason, Windows and possibly OSX needs to store something in
|
||||||
// the stream before it is used for the first time
|
// the stream before it is used for the first time
|
||||||
|
@ -81,31 +76,12 @@ Serializer::Serializer(void)
|
||||||
{
|
{
|
||||||
myStream->exceptions( ios_base::failbit | ios_base::badbit | ios_base::eofbit );
|
myStream->exceptions( ios_base::failbit | ios_base::badbit | ios_base::eofbit );
|
||||||
putBool(true);
|
putBool(true);
|
||||||
reset();
|
rewind();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
Serializer::~Serializer(void)
|
void Serializer::rewind()
|
||||||
{
|
|
||||||
if(myStream != NULL)
|
|
||||||
{
|
|
||||||
if(myUseFilestream)
|
|
||||||
((fstream*)myStream)->close();
|
|
||||||
|
|
||||||
delete myStream;
|
|
||||||
myStream = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
bool Serializer::isValid(void)
|
|
||||||
{
|
|
||||||
return myStream != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
void Serializer::reset(void)
|
|
||||||
{
|
{
|
||||||
myStream->clear();
|
myStream->clear();
|
||||||
myStream->seekg(ios_base::beg);
|
myStream->seekg(ios_base::beg);
|
||||||
|
@ -113,7 +89,7 @@ void Serializer::reset(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
uInt8 Serializer::getByte(void)
|
uInt8 Serializer::getByte() const
|
||||||
{
|
{
|
||||||
char buf;
|
char buf;
|
||||||
myStream->read(&buf, 1);
|
myStream->read(&buf, 1);
|
||||||
|
@ -122,43 +98,61 @@ uInt8 Serializer::getByte(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void Serializer::getByteArray(uInt8* array, uInt32 size)
|
void Serializer::getByteArray(uInt8* array, uInt32 size) const
|
||||||
{
|
{
|
||||||
myStream->read((char*)array, size);
|
myStream->read(reinterpret_cast<char*>(array), size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
uInt16 Serializer::getShort(void)
|
uInt16 Serializer::getShort() const
|
||||||
{
|
{
|
||||||
uInt16 val = 0;
|
uInt16 val = 0;
|
||||||
myStream->read((char*)&val, sizeof(uInt16));
|
myStream->read(reinterpret_cast<char*>(&val), sizeof(uInt16));
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void Serializer::getShortArray(uInt16* array, uInt32 size)
|
void Serializer::getShortArray(uInt16* array, uInt32 size) const
|
||||||
{
|
{
|
||||||
myStream->read((char*)array, sizeof(uInt16)*size);
|
myStream->read(reinterpret_cast<char*>(array), sizeof(uInt16)*size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
uInt32 Serializer::getInt(void)
|
uInt32 Serializer::getInt() const
|
||||||
{
|
{
|
||||||
uInt32 val = 0;
|
uInt32 val = 0;
|
||||||
myStream->read((char*)&val, sizeof(uInt32));
|
myStream->read(reinterpret_cast<char*>(&val), sizeof(uInt32));
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void Serializer::getIntArray(uInt32* array, uInt32 size)
|
void Serializer::getIntArray(uInt32* array, uInt32 size) const
|
||||||
{
|
{
|
||||||
myStream->read((char*)array, sizeof(uInt32)*size);
|
myStream->read(reinterpret_cast<char*>(array), sizeof(uInt32)*size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
string Serializer::getString(void)
|
uInt64 Serializer::getLong() const
|
||||||
|
{
|
||||||
|
uInt64 val = 0;
|
||||||
|
myStream->read(reinterpret_cast<char*>(&val), sizeof(uInt64));
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
double Serializer::getDouble() const
|
||||||
|
{
|
||||||
|
double val = 0.0;
|
||||||
|
myStream->read(reinterpret_cast<char*>(&val), sizeof(double));
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
string Serializer::getString() const
|
||||||
{
|
{
|
||||||
int len = getInt();
|
int len = getInt();
|
||||||
string str;
|
string str;
|
||||||
|
@ -169,7 +163,7 @@ string Serializer::getString(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool Serializer::getBool(void)
|
bool Serializer::getBool() const
|
||||||
{
|
{
|
||||||
return getByte() == TruePattern;
|
return getByte() == TruePattern;
|
||||||
}
|
}
|
||||||
|
@ -177,43 +171,55 @@ bool Serializer::getBool(void)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void Serializer::putByte(uInt8 value)
|
void Serializer::putByte(uInt8 value)
|
||||||
{
|
{
|
||||||
myStream->write((char*)&value, 1);
|
myStream->write(reinterpret_cast<char*>(&value), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void Serializer::putByteArray(const uInt8* array, uInt32 size)
|
void Serializer::putByteArray(const uInt8* array, uInt32 size)
|
||||||
{
|
{
|
||||||
myStream->write((char*)array, size);
|
myStream->write(reinterpret_cast<const char*>(array), size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void Serializer::putShort(uInt16 value)
|
void Serializer::putShort(uInt16 value)
|
||||||
{
|
{
|
||||||
myStream->write((char*)&value, sizeof(uInt16));
|
myStream->write(reinterpret_cast<char*>(&value), sizeof(uInt16));
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void Serializer::putShortArray(const uInt16* array, uInt32 size)
|
void Serializer::putShortArray(const uInt16* array, uInt32 size)
|
||||||
{
|
{
|
||||||
myStream->write((char*)array, sizeof(uInt16)*size);
|
myStream->write(reinterpret_cast<const char*>(array), sizeof(uInt16)*size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void Serializer::putInt(uInt32 value)
|
void Serializer::putInt(uInt32 value)
|
||||||
{
|
{
|
||||||
myStream->write((char*)&value, sizeof(uInt32));
|
myStream->write(reinterpret_cast<char*>(&value), sizeof(uInt32));
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void Serializer::putIntArray(const uInt32* array, uInt32 size)
|
void Serializer::putIntArray(const uInt32* array, uInt32 size)
|
||||||
{
|
{
|
||||||
myStream->write((char*)array, sizeof(uInt32)*size);
|
myStream->write(reinterpret_cast<const char*>(array), sizeof(uInt32)*size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void Serializer::putLong(uInt64 value)
|
||||||
|
{
|
||||||
|
myStream->write(reinterpret_cast<char*>(&value), sizeof(uInt64));
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void Serializer::putDouble(double value)
|
||||||
|
{
|
||||||
|
myStream->write(reinterpret_cast<char*>(&value), sizeof(double));
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void Serializer::putString(const string& str)
|
void Serializer::putString(const string& str)
|
||||||
{
|
{
|
||||||
int len = str.length();
|
int len = int(str.length());
|
||||||
putInt(len);
|
putInt(len);
|
||||||
myStream->write(str.data(), len);
|
myStream->write(str.data(), len);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,19 +8,16 @@
|
||||||
// SS SS tt ee ll ll aa aa
|
// SS SS tt ee ll ll aa aa
|
||||||
// SSSS ttt eeeee llll llll aaaaa
|
// SSSS ttt eeeee llll llll aaaaa
|
||||||
//
|
//
|
||||||
// Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony
|
// Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony
|
||||||
// and the Stella Team
|
// and the Stella Team
|
||||||
//
|
//
|
||||||
// See the file "License.txt" for information on usage and redistribution of
|
// See the file "License.txt" for information on usage and redistribution of
|
||||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||||
//
|
|
||||||
// $Id: Serializer.hxx 2838 2014-01-17 23:34:03Z stephena $
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
#ifndef SERIALIZER_HXX
|
#ifndef SERIALIZER_HXX
|
||||||
#define SERIALIZER_HXX
|
#define SERIALIZER_HXX
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include "bspf.hxx"
|
#include "bspf.hxx"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,15 +26,11 @@
|
||||||
stream can be either an actual file, or an in-memory structure.
|
stream can be either an actual file, or an in-memory structure.
|
||||||
|
|
||||||
Bytes are written as characters, shorts as 2 characters (16-bits),
|
Bytes are written as characters, shorts as 2 characters (16-bits),
|
||||||
integers as 4 characters (32-bits), strings are written as characters
|
integers as 4 characters (32-bits), long integers as 8 bytes (64-bits),
|
||||||
prepended by the length of the string, boolean values are written using
|
strings are written as characters prepended by the length of the string,
|
||||||
a special character pattern.
|
boolean values are written using a special character pattern.
|
||||||
|
|
||||||
All bytes, shorts and ints should be cast to their appropriate data type upon
|
|
||||||
method return.
|
|
||||||
|
|
||||||
@author Stephen Anthony
|
@author Stephen Anthony
|
||||||
@version $Id: Serializer.hxx 2838 2014-01-17 23:34:03Z stephena $
|
|
||||||
*/
|
*/
|
||||||
class Serializer
|
class Serializer
|
||||||
{
|
{
|
||||||
|
@ -50,35 +43,30 @@ class Serializer
|
||||||
|
|
||||||
If a file is opened readonly, we can never write to it.
|
If a file is opened readonly, we can never write to it.
|
||||||
|
|
||||||
The isValid() method must immediately be called to verify the stream
|
The valid() method must immediately be called to verify the stream
|
||||||
was correctly initialized.
|
was correctly initialized.
|
||||||
*/
|
*/
|
||||||
Serializer(const string& filename, bool readonly = false);
|
Serializer(const string& filename, bool readonly = false);
|
||||||
Serializer(void);
|
Serializer();
|
||||||
|
|
||||||
/**
|
|
||||||
Destructor
|
|
||||||
*/
|
|
||||||
virtual ~Serializer(void);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
Answers whether the serializer is currently initialized for reading
|
Answers whether the serializer is currently initialized for reading
|
||||||
and writing.
|
and writing.
|
||||||
*/
|
*/
|
||||||
bool isValid(void);
|
explicit operator bool() const { return myStream != nullptr; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Resets the read/write location to the beginning of the stream.
|
Resets the read/write location to the beginning of the stream.
|
||||||
*/
|
*/
|
||||||
void reset(void);
|
void rewind();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Reads a byte value (unsigned 8-bit) from the current input stream.
|
Reads a byte value (unsigned 8-bit) from the current input stream.
|
||||||
|
|
||||||
@result The byte value which has been read from the stream.
|
@result The byte value which has been read from the stream.
|
||||||
*/
|
*/
|
||||||
uInt8 getByte(void);
|
uInt8 getByte() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Reads a byte array (unsigned 8-bit) from the current input stream.
|
Reads a byte array (unsigned 8-bit) from the current input stream.
|
||||||
|
@ -86,15 +74,14 @@ class Serializer
|
||||||
@param array The location to store the bytes read
|
@param array The location to store the bytes read
|
||||||
@param size The size of the array (number of bytes to read)
|
@param size The size of the array (number of bytes to read)
|
||||||
*/
|
*/
|
||||||
void getByteArray(uInt8* array, uInt32 size);
|
void getByteArray(uInt8* array, uInt32 size) const;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Reads a short value (unsigned 16-bit) from the current input stream.
|
Reads a short value (unsigned 16-bit) from the current input stream.
|
||||||
|
|
||||||
@result The short value which has been read from the stream.
|
@result The short value which has been read from the stream.
|
||||||
*/
|
*/
|
||||||
uInt16 getShort(void);
|
uInt16 getShort() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Reads a short array (unsigned 16-bit) from the current input stream.
|
Reads a short array (unsigned 16-bit) from the current input stream.
|
||||||
|
@ -102,14 +89,14 @@ class Serializer
|
||||||
@param array The location to store the shorts read
|
@param array The location to store the shorts read
|
||||||
@param size The size of the array (number of shorts to read)
|
@param size The size of the array (number of shorts to read)
|
||||||
*/
|
*/
|
||||||
void getShortArray(uInt16* array, uInt32 size);
|
void getShortArray(uInt16* array, uInt32 size) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Reads an int value (unsigned 32-bit) from the current input stream.
|
Reads an int value (unsigned 32-bit) from the current input stream.
|
||||||
|
|
||||||
@result The int value which has been read from the stream.
|
@result The int value which has been read from the stream.
|
||||||
*/
|
*/
|
||||||
uInt32 getInt(void);
|
uInt32 getInt() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Reads an integer array (unsigned 32-bit) from the current input stream.
|
Reads an integer array (unsigned 32-bit) from the current input stream.
|
||||||
|
@ -117,21 +104,35 @@ class Serializer
|
||||||
@param array The location to store the integers read
|
@param array The location to store the integers read
|
||||||
@param size The size of the array (number of integers to read)
|
@param size The size of the array (number of integers to read)
|
||||||
*/
|
*/
|
||||||
void getIntArray(uInt32* array, uInt32 size);
|
void getIntArray(uInt32* array, uInt32 size) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Reads a long int value (unsigned 64-bit) from the current input stream.
|
||||||
|
|
||||||
|
@result The long int value which has been read from the stream.
|
||||||
|
*/
|
||||||
|
uInt64 getLong() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Reads a double value (signed 64-bit) from the current input stream.
|
||||||
|
|
||||||
|
@result The double value which has been read from the stream.
|
||||||
|
*/
|
||||||
|
double getDouble() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Reads a string from the current input stream.
|
Reads a string from the current input stream.
|
||||||
|
|
||||||
@result The string which has been read from the stream.
|
@result The string which has been read from the stream.
|
||||||
*/
|
*/
|
||||||
string getString(void);
|
string getString() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Reads a boolean value from the current input stream.
|
Reads a boolean value from the current input stream.
|
||||||
|
|
||||||
@result The boolean value which has been read from the stream.
|
@result The boolean value which has been read from the stream.
|
||||||
*/
|
*/
|
||||||
bool getBool(void);
|
bool getBool() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Writes an byte value (unsigned 8-bit) to the current output stream.
|
Writes an byte value (unsigned 8-bit) to the current output stream.
|
||||||
|
@ -178,6 +179,20 @@ class Serializer
|
||||||
*/
|
*/
|
||||||
void putIntArray(const uInt32* array, uInt32 size);
|
void putIntArray(const uInt32* array, uInt32 size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Writes a long int value (unsigned 64-bit) to the current output stream.
|
||||||
|
|
||||||
|
@param value The long int value to write to the output stream.
|
||||||
|
*/
|
||||||
|
void putLong(uInt64 value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Writes a double value (signed 64-bit) to the current output stream.
|
||||||
|
|
||||||
|
@param value The double value to write to the output stream.
|
||||||
|
*/
|
||||||
|
void putDouble(double value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Writes a string to the current output stream.
|
Writes a string to the current output stream.
|
||||||
|
|
||||||
|
@ -194,13 +209,19 @@ class Serializer
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// The stream to send the serialized data to.
|
// The stream to send the serialized data to.
|
||||||
iostream* myStream;
|
unique_ptr<iostream> myStream;
|
||||||
bool myUseFilestream;
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
TruePattern = 0xfe,
|
TruePattern = 0xfe,
|
||||||
FalsePattern = 0x01
|
FalsePattern = 0x01
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Following constructors and assignment operators not supported
|
||||||
|
Serializer(const Serializer&) = delete;
|
||||||
|
Serializer(Serializer&&) = delete;
|
||||||
|
Serializer& operator=(const Serializer&) = delete;
|
||||||
|
Serializer& operator=(Serializer&&) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
|
|
||||||
#include "StateManager.hxx"
|
#include "StateManager.hxx"
|
||||||
|
|
||||||
#define STATE_HEADER "03090100state"
|
#define STATE_HEADER "03090400state"
|
||||||
#define MOVIE_HEADER "03030000movie"
|
#define MOVIE_HEADER "03030000movie"
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -186,7 +186,7 @@ void StateManager::loadState(int slot)
|
||||||
|
|
||||||
// Make sure the file can be opened in read-only mode
|
// Make sure the file can be opened in read-only mode
|
||||||
Serializer in(buf.str(), true);
|
Serializer in(buf.str(), true);
|
||||||
if(!in.isValid())
|
if(!in)
|
||||||
{
|
{
|
||||||
buf.str("");
|
buf.str("");
|
||||||
#if !defined(RETRON77)
|
#if !defined(RETRON77)
|
||||||
|
@ -251,7 +251,7 @@ void StateManager::saveState(int slot)
|
||||||
|
|
||||||
// Make sure the file can be opened for writing
|
// Make sure the file can be opened for writing
|
||||||
Serializer out(buf.str());
|
Serializer out(buf.str());
|
||||||
if(!out.isValid())
|
if(!out)
|
||||||
{
|
{
|
||||||
buf.str("");
|
buf.str("");
|
||||||
buf << "Can't open/save to state file " << " " << myOSystem->stateDir() << name << ".st" << slot;
|
buf << "Can't open/save to state file " << " " << myOSystem->stateDir() << name << ".st" << slot;
|
||||||
|
@ -309,7 +309,7 @@ bool StateManager::loadState(Serializer& in)
|
||||||
if(&myOSystem->console())
|
if(&myOSystem->console())
|
||||||
{
|
{
|
||||||
// Make sure the file can be opened for reading
|
// Make sure the file can be opened for reading
|
||||||
if(in.isValid())
|
if(in)
|
||||||
{
|
{
|
||||||
// First test if we have a valid header and cart type
|
// First test if we have a valid header and cart type
|
||||||
// If so, do a complete state load using the Console
|
// If so, do a complete state load using the Console
|
||||||
|
@ -329,7 +329,7 @@ bool StateManager::saveState(Serializer& out)
|
||||||
if(&myOSystem->console())
|
if(&myOSystem->console())
|
||||||
{
|
{
|
||||||
// Make sure the file can be opened for writing
|
// Make sure the file can be opened for writing
|
||||||
if(out.isValid())
|
if(out)
|
||||||
{
|
{
|
||||||
// Add header so that if the state format changes in the future,
|
// Add header so that if the state format changes in the future,
|
||||||
// we'll know right away, without having to parse the rest of the file
|
// we'll know right away, without having to parse the rest of the file
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -8,13 +8,11 @@
|
||||||
// SS SS tt ee ll ll aa aa
|
// SS SS tt ee ll ll aa aa
|
||||||
// SSSS ttt eeeee llll llll aaaaa
|
// SSSS ttt eeeee llll llll aaaaa
|
||||||
//
|
//
|
||||||
// Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony
|
// Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony
|
||||||
// and the Stella Team
|
// and the Stella Team
|
||||||
//
|
//
|
||||||
// See the file "License.txt" for information on usage and redistribution of
|
// See the file "License.txt" for information on usage and redistribution of
|
||||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||||
//
|
|
||||||
// $Id: Thumbulator.hxx 2838 2014-01-17 23:34:03Z stephena $
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
@ -24,9 +22,13 @@
|
||||||
// Code is public domain and used with the author's consent
|
// Code is public domain and used with the author's consent
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
#ifdef THUMB_SUPPORT
|
#ifndef THUMBULATOR_HXX
|
||||||
|
#define THUMBULATOR_HXX
|
||||||
|
|
||||||
|
class Cartridge;
|
||||||
|
|
||||||
#include "bspf.hxx"
|
#include "bspf.hxx"
|
||||||
|
#include "Console.hxx"
|
||||||
|
|
||||||
#define ROMADDMASK 0x7FFF
|
#define ROMADDMASK 0x7FFF
|
||||||
#define RAMADDMASK 0x1FFF
|
#define RAMADDMASK 0x1FFF
|
||||||
|
@ -34,39 +36,28 @@
|
||||||
#define ROMSIZE (ROMADDMASK+1)
|
#define ROMSIZE (ROMADDMASK+1)
|
||||||
#define RAMSIZE (RAMADDMASK+1)
|
#define RAMSIZE (RAMADDMASK+1)
|
||||||
|
|
||||||
//0b10000 User PC, R14 to R0, CPSR
|
#define CPSR_N (1u<<31)
|
||||||
//0b10001 FIQ PC, R14_fiq to R8_fiq, R7 to R0, CPSR, SPSR_fiq
|
#define CPSR_Z (1u<<30)
|
||||||
//0b10010 IRQ PC, R14_irq, R13_irq, R12 to R0, CPSR, SPSR_irq
|
#define CPSR_C (1u<<29)
|
||||||
//0b10011 Supervisor PC, R14_svc, R13_svc, R12 to R0, CPSR, SPSR_svc
|
#define CPSR_V (1u<<28)
|
||||||
//0b10111 Abort PC, R14_abt, R13_abt, R12 to R0, CPSR, SPSR_abt
|
|
||||||
//0b11011 Undefined PC, R14_und, R13_und, R12 to R0, CPSR, SPSR_und
|
|
||||||
//0b11111 System
|
|
||||||
|
|
||||||
#define MODE_USR 0x10
|
|
||||||
#define MODE_FIQ 0x11
|
|
||||||
#define MODE_IRQ 0x12
|
|
||||||
#define MODE_SVC 0x13
|
|
||||||
#define MODE_ABT 0x17
|
|
||||||
#define MODE_UND 0x1B
|
|
||||||
#define MODE_SYS 0x1F
|
|
||||||
|
|
||||||
#define CPSR_T (1<<5)
|
|
||||||
#define CPSR_F (1<<6)
|
|
||||||
#define CPSR_I (1<<7)
|
|
||||||
#define CPSR_N (1<<31)
|
|
||||||
#define CPSR_Z (1<<30)
|
|
||||||
#define CPSR_C (1<<29)
|
|
||||||
#define CPSR_V (1<<28)
|
|
||||||
#define CPSR_Q (1<<27)
|
|
||||||
|
|
||||||
class Thumbulator
|
class Thumbulator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Thumbulator(const uInt16* rom, uInt16* ram, bool traponfatal);
|
// control cartridge specific features of the Thumbulator class,
|
||||||
~Thumbulator();
|
// such as the start location for calling custom code
|
||||||
|
enum ConfigureFor {
|
||||||
|
BUS, // cartridges of type BUS
|
||||||
|
CDF, // cartridges of type CDF
|
||||||
|
CDF1, // cartridges of type CDF version 1
|
||||||
|
DPCplus // cartridges of type DPC+
|
||||||
|
};
|
||||||
|
|
||||||
|
Thumbulator(const uInt16* rom, uInt16* ram, bool traponfatal,
|
||||||
|
Thumbulator::ConfigureFor configurefor, Cartridge* cartridge);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Run the ARM code, and return when finished. A string exception is
|
Run the ARM code, and return when finished. A runtime_error exception is
|
||||||
thrown in case of any fatal errors/aborts (if enabled), containing the
|
thrown in case of any fatal errors/aborts (if enabled), containing the
|
||||||
actual error, and the contents of the registers at that point in time.
|
actual error, and the contents of the registers at that point in time.
|
||||||
|
|
||||||
|
@ -74,6 +65,7 @@ class Thumbulator
|
||||||
otherwise an empty string
|
otherwise an empty string
|
||||||
*/
|
*/
|
||||||
string run();
|
string run();
|
||||||
|
string run(uInt32 cycles);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Normally when a fatal error is encountered, the ARM emulation
|
Normally when a fatal error is encountered, the ARM emulation
|
||||||
|
@ -89,59 +81,75 @@ class Thumbulator
|
||||||
*/
|
*/
|
||||||
static void trapFatalErrors(bool enable) { trapOnFatal = enable; }
|
static void trapFatalErrors(bool enable) { trapOnFatal = enable; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
Inform the Thumbulator class about the console currently in use,
|
||||||
|
which is used to accurately determine how many 6507 cycles have
|
||||||
|
passed while ARM code is being executed.
|
||||||
|
*/
|
||||||
|
void setConsoleTiming(ConsoleTiming timing);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uInt32 read_register ( uInt32 reg );
|
uInt32 read_register(uInt32 reg);
|
||||||
uInt32 write_register ( uInt32 reg, uInt32 data );
|
void write_register(uInt32 reg, uInt32 data);
|
||||||
uInt32 fetch16 ( uInt32 addr );
|
uInt32 fetch16(uInt32 addr);
|
||||||
uInt32 fetch32 ( uInt32 addr );
|
uInt32 fetch32(uInt32 addr);
|
||||||
uInt32 read16 ( uInt32 addr );
|
uInt32 read16(uInt32 addr);
|
||||||
uInt32 read32 ( uInt32 );
|
uInt32 read32(uInt32 addr);
|
||||||
void write16 ( uInt32 addr, uInt32 data );
|
bool isProtected(uInt32 addr);
|
||||||
void write32 ( uInt32 addr, uInt32 data );
|
void write16(uInt32 addr, uInt32 data);
|
||||||
|
void write32(uInt32 addr, uInt32 data);
|
||||||
|
void updateTimer(uInt32 cycles);
|
||||||
|
|
||||||
void do_zflag ( uInt32 x );
|
void do_zflag(uInt32 x);
|
||||||
void do_nflag ( uInt32 x );
|
void do_nflag(uInt32 x);
|
||||||
void do_cflag ( uInt32 a, uInt32 b, uInt32 c );
|
void do_cflag(uInt32 a, uInt32 b, uInt32 c);
|
||||||
void do_sub_vflag ( uInt32 a, uInt32 b, uInt32 c );
|
void do_vflag(uInt32 a, uInt32 b, uInt32 c);
|
||||||
void do_add_vflag ( uInt32 a, uInt32 b, uInt32 c );
|
void do_cflag_bit(uInt32 x);
|
||||||
void do_cflag_bit ( uInt32 x );
|
void do_vflag_bit(uInt32 x);
|
||||||
void do_vflag_bit ( uInt32 x );
|
|
||||||
|
|
||||||
// Throw a string exception containing an error referencing the given
|
// Throw a runtime_error exception containing an error referencing the
|
||||||
// message and variables
|
// given message and variables
|
||||||
// Note that the return value is never used in these methods
|
// Note that the return value is never used in these methods
|
||||||
int fatalError(const char* opcode, uInt32 v1, const char* msg);
|
int fatalError(const char* opcode, uInt32 v1, const char* msg);
|
||||||
int fatalError(const char* opcode, uInt32 v1, uInt32 v2, const char* msg);
|
int fatalError(const char* opcode, uInt32 v1, uInt32 v2, const char* msg);
|
||||||
|
|
||||||
void dump_counters ( void );
|
void dump_counters();
|
||||||
void dump_regs( void );
|
void dump_regs();
|
||||||
int execute ( void );
|
int execute();
|
||||||
int reset ( void );
|
int reset();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const uInt16* rom;
|
const uInt16* rom;
|
||||||
uInt16* ram;
|
uInt16* ram;
|
||||||
//Int32 copydata;
|
|
||||||
|
|
||||||
uInt32 halfadd;
|
uInt32 reg_norm[16]; // normal execution mode, do not have a thread mode
|
||||||
uInt32 cpsr;
|
uInt32 cpsr, mamcr;
|
||||||
//uInt32 reg_usr[16]; //User mode
|
bool handler_mode;
|
||||||
uInt32 reg_sys[16]; //System mode
|
uInt32 systick_ctrl, systick_reload, systick_count, systick_calibrate;
|
||||||
uInt32 reg_svc[16]; //Supervisor mode
|
uInt64 instructions, fetches, reads, writes, systick_ints;
|
||||||
//uInt32 reg_abt[16]; //Abort mode
|
|
||||||
//uInt32 reg_und[16]; //Undefined mode
|
|
||||||
//uInt32 reg_irq[16]; //Interrupt mode
|
|
||||||
//uInt32 reg_fiq[16]; //Fast Interrupt mode
|
|
||||||
uInt32 mamcr;
|
|
||||||
|
|
||||||
uInt64 instructions;
|
// For emulation of LPC2103's timer 1, used for NTSC/PAL/SECAM detection.
|
||||||
uInt64 fetches;
|
// Register names from documentation:
|
||||||
uInt64 reads;
|
// http://www.nxp.com/documents/user_manual/UM10161.pdf
|
||||||
uInt64 writes;
|
uInt32 T1TCR; // Timer 1 Timer Control Register
|
||||||
|
uInt32 T1TC; // Timer 1 Timer Counter
|
||||||
|
double timing_factor;
|
||||||
|
|
||||||
ostringstream statusMsg;
|
ostringstream statusMsg;
|
||||||
|
|
||||||
static bool trapOnFatal;
|
static bool trapOnFatal;
|
||||||
|
|
||||||
|
ConfigureFor configuration;
|
||||||
|
|
||||||
|
Cartridge* myCartridge;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Following constructors and assignment operators not supported
|
||||||
|
Thumbulator() = delete;
|
||||||
|
Thumbulator(const Thumbulator&) = delete;
|
||||||
|
Thumbulator(Thumbulator&&) = delete;
|
||||||
|
Thumbulator& operator=(const Thumbulator&) = delete;
|
||||||
|
Thumbulator& operator=(Thumbulator&&) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif // THUMBULATOR_HXX
|
||||||
|
|
|
@ -35,7 +35,6 @@ MODULE_OBJS := \
|
||||||
src/emucore/CartFA.o \
|
src/emucore/CartFA.o \
|
||||||
src/emucore/CartFA2.o \
|
src/emucore/CartFA2.o \
|
||||||
src/emucore/CartFE.o \
|
src/emucore/CartFE.o \
|
||||||
src/emucore/CartMC.o \
|
|
||||||
src/emucore/CartSB.o \
|
src/emucore/CartSB.o \
|
||||||
src/emucore/CartUA.o \
|
src/emucore/CartUA.o \
|
||||||
src/emucore/CartX07.o \
|
src/emucore/CartX07.o \
|
||||||
|
|
Loading…
Reference in New Issue