diff --git a/src/emucore/Cart.cxx b/src/emucore/Cart.cxx index 2cbf28f97..b4aa9ca1b 100644 --- a/src/emucore/Cart.cxx +++ b/src/emucore/Cart.cxx @@ -17,6 +17,7 @@ #include "Settings.hxx" #include "System.hxx" +#include "MD5.hxx" #ifdef DEBUGGER_SUPPORT #include "Debugger.hxx" #include "CartDebug.hxx" @@ -32,6 +33,7 @@ Cartridge::Cartridge(const Settings& settings) myStartBank(0), myBankLocked(false) { + std::fill(myRWPRandomValues, myRWPRandomValues + 256, 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -77,6 +79,20 @@ void Cartridge::triggerReadFromWritePort(uInt16 address) #endif } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Cartridge::createReadFromWritePortValues(const uInt8* image, uInt32 size) +{ + Random rand(MD5::hashToInt(image, size)); + for(uInt32 i = 0; i < 256; ++i) + myRWPRandomValues[i] = rand.next(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt8 Cartridge::randomReadFromWritePortValue(uInt16 address) const +{ + return myRWPRandomValues[address & 0xFF]; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge::createCodeAccessBase(uInt32 size) { diff --git a/src/emucore/Cart.hxx b/src/emucore/Cart.hxx index 504da93a3..850673dc3 100644 --- a/src/emucore/Cart.hxx +++ b/src/emucore/Cart.hxx @@ -195,6 +195,28 @@ class Cartridge : public Device */ void triggerReadFromWritePort(uInt16 address); + /** + Creates an array of semi-random values to use for returning when a + read from the write port happens. Currently, these values are based in + part on the md5sum of the ROM, so this method needs to be called to + calculate that information. If the method isn't called, then the values + used will be 0. + + @param image The cart ROM data + @param size The size of ROM data + */ + void createReadFromWritePortValues(const uInt8* image, uInt32 size); + + /** + Return a random value to use when a read from the write port happens. + This functionality is placed in a method, so we can change + implementations as required. + + @param address The address of the illegal read + @return A random value somehow associated with the given address + */ + uInt8 randomReadFromWritePortValue(uInt16 address) const; + /** Create an array that holds code-access information for every byte of the ROM (indicated by 'size'). Note that this is only used by @@ -260,6 +282,9 @@ class Cartridge : public Device // by the debugger, when disassembling/dumping ROM. bool myBankLocked; + // Semi-random values to use when a read from write port occurs + uInt8 myRWPRandomValues[256]; + // Contains various info about this cartridge // This needs to be stored separately from child classes, since // sometimes the information in both do not match diff --git a/src/emucore/CartF8SC.cxx b/src/emucore/CartF8SC.cxx index c809d3e7d..0a9e60908 100644 --- a/src/emucore/CartF8SC.cxx +++ b/src/emucore/CartF8SC.cxx @@ -27,6 +27,7 @@ CartridgeF8SC::CartridgeF8SC(const BytePtr& image, uInt32 size, // Copy the ROM image into my buffer memcpy(myImage, image.get(), std::min(8192u, size)); createCodeAccessBase(8192); + createReadFromWritePortValues(myImage, 8192); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -95,7 +96,7 @@ uInt8 CartridgeF8SC::peek(uInt16 address) if(address < 0x0080) // Write port is at 0xF000 - 0xF07F (128 bytes) { // Reading from the write port triggers an unwanted write - uInt8 value = mySystem->getDataBusState(0xFF); + uInt8 value = randomReadFromWritePortValue(address); if(bankLocked()) return value; diff --git a/src/emucore/MD5.cxx b/src/emucore/MD5.cxx index 92dda5f0e..fc7dcebeb 100644 --- a/src/emucore/MD5.cxx +++ b/src/emucore/MD5.cxx @@ -351,4 +351,21 @@ string hash(const FilesystemNode& node) return md5; } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt32 hashToInt(const uInt8* buffer, uInt32 length) +{ + MD5_CTX context; + uInt8 md5[16]; + + MD5Init(&context); + MD5Update(&context, buffer, length); + MD5Final(md5, &context); + + auto toInt = [](uInt8* arr, uInt32 i) { + return uInt32((arr[i] << 24) + (arr[i+1] << 16) + (arr[i+2] << 8) + arr[i+3]); + }; + + return toInt(md5, 0) ^ toInt(md5, 4) ^ toInt(md5, 8) ^ toInt(md5, 12); +} + } // Namespace MD5 diff --git a/src/emucore/MD5.hxx b/src/emucore/MD5.hxx index 7f05805e6..a0d4bb6e0 100644 --- a/src/emucore/MD5.hxx +++ b/src/emucore/MD5.hxx @@ -44,6 +44,18 @@ string hash(const uInt8* buffer, uInt32 length); */ string hash(const FilesystemNode& node); +/** + Get the MD5 Message-Digest of the specified message with the + given length. The digest consists of 32 hexadecimal digits, + but here we will get the 4 32-bit integers that make up the + digest and XOR them, resulting in one 32-bit value. + + @param buffer The message to compute the digest of + @param length The length of the message + @return The 32-bit integer representing the digest +*/ +uInt32 hashToInt(const uInt8* buffer, uInt32 length); + } // Namespace MD5 #endif