aboutsummaryrefslogtreecommitdiff
path: root/SrcShared/Hardware/EmBankROM.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'SrcShared/Hardware/EmBankROM.cpp')
-rw-r--r--SrcShared/Hardware/EmBankROM.cpp1617
1 files changed, 1617 insertions, 0 deletions
diff --git a/SrcShared/Hardware/EmBankROM.cpp b/SrcShared/Hardware/EmBankROM.cpp
new file mode 100644
index 0000000..67cb46e
--- /dev/null
+++ b/SrcShared/Hardware/EmBankROM.cpp
@@ -0,0 +1,1617 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 1998-2001 Palm, Inc. or its subsidiaries.
+ All rights reserved.
+
+ This file is part of the Palm OS Emulator.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+\* ===================================================================== */
+
+#include "EmCommon.h"
+#include "EmBankROM.h"
+
+#include "Byteswapping.h" // ByteswapWords
+#include "EmCPU68K.h" // gCPU68K
+#include "EmErrCodes.h" // kError_UnsupportedROM
+#include "EmHAL.h" // EmHAL
+#include "EmMemory.h" // Memory::InitializeBanks, EmMem_memset
+#include "EmPalmStructs.h" // EmProxyCardHeaderType
+#include "EmSession.h" // GetDevice, ScheduleDeferredError
+#include "ErrorHandling.h" // Errors::Throw
+#include "Miscellaneous.h" // StWordSwapper, NextPowerOf2
+#include "Profiling.h" // WAITSTATES_ROM
+#include "SessionFile.h" // WriteROMFileReference
+#include "Strings.r.h" // kStr_BadChecksum
+
+
+// Private function declarations
+
+
+class Card
+{
+ public:
+ static Bool CheckCardHeader (const EmProxyCardHeaderType& cardHdr);
+ static Bool CheckChecksum (const void* p, uint32 romLength);
+ static Bool Supports328 (const EmAliasCardHeaderType<LAS>& cardHdr);
+ static Bool SupportsEZ (const EmAliasCardHeaderType<LAS>& cardHdr);
+ static Bool SupportsVZ (const EmAliasCardHeaderType<LAS>& cardHdr);
+ static Bool SupportsSZ (const EmAliasCardHeaderType<LAS>& cardHdr);
+};
+
+
+// static member initialization
+
+emuptr EmBankROM::gROMMemoryStart = kDefaultROMMemoryStart;
+
+// ===========================================================================
+// ¥ ROM Bank Accessors
+// ===========================================================================
+// These functions provide fetch and store access to the emulator's read only
+// memory.
+
+static EmAddressBank gROMAddressBank =
+{
+ EmBankROM::GetLong,
+ EmBankROM::GetWord,
+ EmBankROM::GetByte,
+ EmBankROM::SetLong,
+ EmBankROM::SetWord,
+ EmBankROM::SetByte,
+ EmBankROM::GetRealAddress,
+ EmBankROM::ValidAddress,
+ EmBankROM::GetMetaAddress,
+ EmBankROM::AddOpcodeCycles
+};
+
+static uint32 gROMBank_Size;
+static uint32 gManagedROMSize;
+static uint32 gROMImage_Size;
+static uint32 gROMBank_Mask;
+static uint8* gROM_Memory;
+static uint8* gROM_MetaMemory;
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankROM::Initialize
+ *
+ * DESCRIPTION: Standard initialization function. Responsible for
+ * initializing this sub-system when a new session is
+ * created. Will be followed by at least one call to
+ * Reset or Load.
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void EmBankROM::Initialize (EmStream& romStream)
+{
+ // When creating a new session, Initialize is called followed by
+ // Reset. When loading a session, Initialize is called by Load.
+ // So it makes sense to load the ROM image here. However, when
+ // reloading a session as part of a Gremlin Horde, only Load is
+ // called, so it is critical that all parts of a horde use the
+ // same ROM image.
+
+ EmBankROM::LoadROM (romStream);
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankROM::Reset
+ *
+ * DESCRIPTION: Standard reset function. Sets the sub-system to a
+ * default state. This occurs not only on a Reset (as
+ * from the menu item), but also when the sub-system
+ * is first initialized (Reset is called after Initialize)
+ * as well as when the system is re-loaded from an
+ * insufficient session file.
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void EmBankROM::Reset (Bool /*hardwareReset*/)
+{
+ memset (gROM_MetaMemory, 0, gROMImage_Size);
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankROM::Save
+ *
+ * DESCRIPTION: Standard save function. Saves any sub-system state to
+ * the given session file.
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void EmBankROM::Save (SessionFile& f)
+{
+ EmAssert (gSession);
+ Configuration cfg = gSession->GetConfiguration ();
+ f.WriteROMFileReference (cfg.fROMFile);
+
+ StWordSwapper swapper1 (gROM_MetaMemory, gROMImage_Size);
+ f.WriteMetaROMImage (gROM_MetaMemory, gROMImage_Size);
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankROM::Load
+ *
+ * DESCRIPTION: Standard load function. Loads any sub-system state
+ * from the given session file.
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void EmBankROM::Load (SessionFile& f)
+{
+ // ROM reference was read when the basic configuration was read
+ // and passed to EmSession::Initialize, which then called
+ // EmBankROM::Initialize, which then called EmBankROM::LoadROM.
+
+ EmAssert (gROM_MetaMemory != NULL);
+
+ if (f.ReadMetaROMImage (gROM_MetaMemory))
+ {
+ ByteswapWords (gROM_MetaMemory, gROMImage_Size);
+ }
+ else
+ {
+ f.SetCanReload (false);
+ }
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankROM::Dispose
+ *
+ * DESCRIPTION: Standard dispose function. Completely release any
+ * resources acquired or allocated in Initialize and/or
+ * Load.
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void EmBankROM::Dispose (void)
+{
+ Platform::DisposeMemory (gROM_Memory);
+ Platform::DisposeMemory (gROM_MetaMemory);
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankROM::SetBankHandlers
+ *
+ * DESCRIPTION: Set the bank handlers UAE uses to dispatch memory
+ * access operations.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmBankROM::SetBankHandlers (void)
+{
+ if (EmHAL::ChipSelectsConfigured ())
+ {
+ gROMMemoryStart = EmHAL::GetROMBaseAddress ();
+ }
+
+ gManagedROMSize = EmHAL::GetROMSize ();
+
+ // Memory banks gROMMemoryStart to <mumble> are managed by the functions
+ // in EmBankROM. <mumble> is based on the amount of ROM being emulated.
+
+ uint32 first_bank = EmMemBankIndex (EmBankROM::GetMemoryStart ());
+ uint32 last_bank = EmMemBankIndex (EmBankROM::GetMemoryStart () + gManagedROMSize - 1);
+
+ Memory::InitializeBanks ( gROMAddressBank, first_bank,
+ last_bank - first_bank + 1);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankROM::GetLong
+// ---------------------------------------------------------------------------
+
+uint32 EmBankROM::GetLong (emuptr address)
+{
+#if PROFILE_MEMORY
+ gMemoryAccess[kROMLongRead]++;
+ if (address & 2)
+ gMemoryAccess[kROMLongRead2]++;
+#endif
+
+#if (CHECK_FOR_ADDRESS_ERROR)
+ if ((address & 1) != 0)
+ {
+ AddressError (address, sizeof (uint32), true);
+ }
+#endif
+
+#if (VALIDATE_ROM_GET)
+ if (gMemAccessFlags.fValidate_ROMGet && !ValidAddress (address, sizeof (uint32)))
+ {
+ InvalidAccess (address, sizeof (uint32), true);
+ }
+#endif
+
+#if (PREVENT_USER_ROM_GET || PREVENT_SYSTEM_ROM_GET)
+ if (EmMemory::IsPCInRAM ())
+ {
+ if (PREVENT_USER_ROM_GET && gMemAccessFlags.fProtect_ROMGet)
+ {
+ InvalidAccess (address, sizeof (uint32), true);
+ }
+ }
+ else
+ {
+ if (PREVENT_SYSTEM_ROM_GET && gMemAccessFlags.fProtect_SysROMGet)
+ {
+ InvalidAccess (address, sizeof (uint32), true);
+ }
+ }
+#endif
+
+#if HAS_PROFILING
+ CYCLE_GETLONG (WAITSTATES_ROM);
+#endif
+
+ address &= gROMBank_Mask;
+
+ return EmMemDoGet32 (gROM_Memory + address);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankROM::GetWord
+// ---------------------------------------------------------------------------
+
+uint32 EmBankROM::GetWord (emuptr address)
+{
+#if PROFILE_MEMORY
+ gMemoryAccess[kROMWordRead]++;
+#endif
+
+#if (CHECK_FOR_ADDRESS_ERROR)
+ if ((address & 1) != 0)
+ {
+ AddressError (address, sizeof (uint16), true);
+ }
+#endif
+
+#if (VALIDATE_ROM_GET)
+ if (gMemAccessFlags.fValidate_ROMGet && !ValidAddress (address, sizeof (uint16)))
+ {
+ InvalidAccess (address, sizeof (uint16), true);
+ }
+#endif
+
+#if (PREVENT_USER_ROM_GET || PREVENT_SYSTEM_ROM_GET)
+ if (EmMemory::IsPCInRAM ())
+ {
+ if (PREVENT_USER_ROM_GET && gMemAccessFlags.fProtect_ROMGet)
+ {
+ InvalidAccess (address, sizeof (uint16), true);
+ }
+ }
+ else
+ {
+ if (PREVENT_SYSTEM_ROM_GET && gMemAccessFlags.fProtect_SysROMGet)
+ {
+ InvalidAccess (address, sizeof (uint16), true);
+ }
+ }
+#endif
+
+#if HAS_PROFILING
+ CYCLE_GETWORD (WAITSTATES_ROM);
+#endif
+
+ address &= gROMBank_Mask;
+
+ return EmMemDoGet16 (gROM_Memory + address);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankROM::GetByte
+// ---------------------------------------------------------------------------
+
+uint32 EmBankROM::GetByte (emuptr address)
+{
+#if PROFILE_MEMORY
+ gMemoryAccess[kROMByteRead]++;
+#endif
+
+#if (VALIDATE_ROM_GET)
+ if (gMemAccessFlags.fValidate_ROMGet && !ValidAddress (address, sizeof (uint8)))
+ {
+ InvalidAccess (address, sizeof (uint8), true);
+ }
+#endif
+
+#if (PREVENT_USER_ROM_GET || PREVENT_SYSTEM_ROM_GET)
+ if (EmMemory::IsPCInRAM ())
+ {
+ if (PREVENT_USER_ROM_GET && gMemAccessFlags.fProtect_ROMGet)
+ {
+ InvalidAccess (address, sizeof (uint8), true);
+ }
+ }
+ else
+ {
+ if (PREVENT_SYSTEM_ROM_GET && gMemAccessFlags.fProtect_SysROMGet)
+ {
+ InvalidAccess (address, sizeof (uint8), true);
+ }
+ }
+#endif
+
+#if HAS_PROFILING
+ CYCLE_GETBYTE (WAITSTATES_ROM);
+#endif
+
+ address &= gROMBank_Mask;
+
+ return EmMemDoGet8 (gROM_Memory + address);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankROM::SetLong
+// ---------------------------------------------------------------------------
+
+void EmBankROM::SetLong (emuptr address, uint32 value)
+{
+#if PROFILE_MEMORY
+ gMemoryAccess[kROMLongWrite]++;
+ if (address & 2)
+ gMemoryAccess[kROMLongWrite2]++;
+#endif
+
+#if (CHECK_FOR_ADDRESS_ERROR)
+ if ((address & 1) != 0)
+ {
+ AddressError (address, sizeof (uint32), false);
+ }
+#endif
+
+ EmAssert (ValidAddress (address, sizeof (uint32)));
+
+#if (PREVENT_USER_ROM_SET || PREVENT_SYSTEM_ROM_SET)
+ if (EmMemory::IsPCInRAM ())
+ {
+ if (PREVENT_USER_ROM_SET && gMemAccessFlags.fProtect_ROMSet)
+ {
+ InvalidAccess (address, sizeof (uint32), false);
+ return;
+ }
+ }
+ else
+ {
+ if (PREVENT_SYSTEM_ROM_SET && gMemAccessFlags.fProtect_SysROMSet)
+ {
+ InvalidAccess (address, sizeof (uint32), false);
+ return;
+ }
+ }
+#endif
+
+#if HAS_PROFILING
+ // writing to ROM?? don't know what to make of this
+ CYCLE_PUTLONG (WAITSTATES_ROM);
+#endif
+
+ address &= gROMBank_Mask;
+
+ EmMemDoPut32 (gROM_Memory + address, value);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankROM::SetWord
+// ---------------------------------------------------------------------------
+
+void EmBankROM::SetWord (emuptr address, uint32 value)
+{
+#if PROFILE_MEMORY
+ gMemoryAccess[kROMWordWrite]++;
+#endif
+
+#if (CHECK_FOR_ADDRESS_ERROR)
+ if ((address & 1) != 0)
+ {
+ AddressError (address, sizeof (uint16), false);
+ }
+#endif
+
+ EmAssert (ValidAddress (address, sizeof (uint16)));
+
+#if (PREVENT_USER_ROM_SET || PREVENT_SYSTEM_ROM_SET)
+ if (EmMemory::IsPCInRAM ())
+ {
+ if (PREVENT_USER_ROM_SET && gMemAccessFlags.fProtect_ROMSet)
+ {
+ InvalidAccess (address, sizeof (uint16), false);
+ return;
+ }
+ }
+ else
+ {
+ if (PREVENT_SYSTEM_ROM_SET && gMemAccessFlags.fProtect_SysROMSet)
+ {
+ InvalidAccess (address, sizeof (uint16), false);
+ return;
+ }
+ }
+#endif
+
+#if HAS_PROFILING
+ // writing to ROM?? don't know what to make of this
+ CYCLE_PUTWORD (WAITSTATES_ROM);
+#endif
+
+ address &= gROMBank_Mask;
+
+ EmMemDoPut16 (gROM_Memory + address, value);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankROM::SetByte
+// ---------------------------------------------------------------------------
+
+void EmBankROM::SetByte (emuptr address, uint32 value)
+{
+#if PROFILE_MEMORY
+ gMemoryAccess[kROMByteWrite]++;
+#endif
+
+ EmAssert (ValidAddress (address, sizeof (uint8)));
+
+#if (PREVENT_USER_ROM_SET || PREVENT_SYSTEM_ROM_SET)
+ if (EmMemory::IsPCInRAM ())
+ {
+ if (PREVENT_USER_ROM_SET && gMemAccessFlags.fProtect_ROMSet)
+ {
+ InvalidAccess (address, sizeof (uint8), false);
+ return;
+ }
+ }
+ else
+ {
+ if (PREVENT_SYSTEM_ROM_SET && gMemAccessFlags.fProtect_SysROMSet)
+ {
+ InvalidAccess (address, sizeof (uint8), false);
+ return;
+ }
+ }
+#endif
+
+#if HAS_PROFILING
+ // writing to ROM?? don't know what to make of this
+ CYCLE_PUTBYTE (WAITSTATES_ROM);
+#endif
+
+ address &= gROMBank_Mask;
+
+ EmMemDoPut8 (gROM_Memory + address, value);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankROM::ValidAddress
+// ---------------------------------------------------------------------------
+
+int EmBankROM::ValidAddress (emuptr address, uint32 size)
+{
+ address -= gROMMemoryStart;
+ int result = (address + size) <= (gROMMemoryStart + gROMBank_Size);
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankROM::GetRealAddress
+// ---------------------------------------------------------------------------
+
+uint8* EmBankROM::GetRealAddress (emuptr address)
+{
+ // Strip the uppermost bit of the address.
+
+ address &= gROMBank_Mask;
+
+ return (uint8*) &gROM_Memory[address];
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankROM::GetMetaAddress
+// ---------------------------------------------------------------------------
+
+uint8* EmBankROM::GetMetaAddress (emuptr address)
+{
+ // Strip the uppermost bit of the address.
+
+ address &= gROMBank_Mask;
+
+ return (uint8*) &(gROM_MetaMemory[address]);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankROM::AddOpcodeCycles
+// ---------------------------------------------------------------------------
+
+void EmBankROM::AddOpcodeCycles (void)
+{
+#if (HAS_PROFILING)
+ CYCLE_GETWORD (WAITSTATES_ROM);
+#endif
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankROM::AddressError
+// ---------------------------------------------------------------------------
+
+void EmBankROM::AddressError (emuptr address, long size, Bool forRead)
+{
+ EmAssert (gCPU68K);
+ gCPU68K->AddressError (address, size, forRead);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankROM::InvalidAccess
+// ---------------------------------------------------------------------------
+
+void EmBankROM::InvalidAccess (emuptr address, long size, Bool forRead)
+{
+ EmAssert (gSession);
+ gSession->ScheduleDeferredError (new EmDeferredErrROM (address, size, forRead));
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankROM::LoadROM
+ *
+ * DESCRIPTION: Does the work of actually loading (and validating a ROM
+ * from a stream.
+ *
+ * PARAMETERS: EmStream hROM
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmBankROM::LoadROM (EmStream& hROM)
+{
+ // Make sure the file is big enough to have a card header.
+
+ if (hROM.GetLength() < (long) EmProxyCardHeaderType::GetSize ())
+ Errors::Throw (kError_BadROM);
+
+ // Read the card header.
+
+ EmProxyCardHeaderType cardHeader;
+ hROM.GetBytes (cardHeader.GetPtr (), cardHeader.GetSize ());
+
+ // Validate the card header.
+
+ if (!Card::CheckCardHeader (cardHeader))
+ Errors::Throw (kError_BadROM);
+
+ // The ROM is made up of two parts: a Big ROM and a Small ROM. ROM image
+ // files can contain both parts or just the Big ROM part. If it contains
+ // both parts, then everything is just fine, and we can use it no problem.
+ // If the Small ROM part is missing, we have to detect that, dummy up a
+ // small ROM for correct operation, and relocate the Big ROM higher in memory.
+
+ // Both the Big ROM and Small ROM start off with a CardHeaderType struct.
+ // We just read in one of them. Let's look at where the Big ROM _should_
+ // be to see if there's another CardHeader there. If so, we have both parts.
+ // If not, we have just the Big ROM.
+
+ int32 bigROMOffset;
+
+ if (cardHeader.hdrVersion == 1)
+ {
+ bigROMOffset = 0x3000;
+ }
+ else
+ {
+ // Version 2 CardHeaders contain a "bigROMOffset" field that contains the
+ // offset from the beginning of the card to where the ROM should
+ // appear in memory. Normally the card appears at 0x10000000 (which
+ // would make bigROMOffset something like 0x00C08000), but that
+ // isn't always the case. The problem is, we don't always know
+ // where the card beginning will be. For now, we'll assume that
+ // the ROM wants to live at 0x10C00000, and that the Big ROM will
+ // want to begin somewhere soon after that. This means we can get by
+ // with using only the lower bits of bigROMOffset.
+
+ bigROMOffset = cardHeader.bigROMOffset;
+ bigROMOffset &= 0x000FFFFF; // Allows for 1 Meg offset.
+ }
+
+ // Make sure the file is big enough to have a Big ROM.
+
+ if (hROM.GetLength() < bigROMOffset)
+ Errors::Throw (kError_BadROM);
+
+ // We'll use bigROMOffset for later to get to some Big ROM data.
+ // But we'll also need a value when we read the ROM image into
+ // memory. This value will be used as an offset into a buffer
+ // where we'll be reading the ROM image. If we have a Small ROM,
+ // the offset will be zero. If we have only a Big ROM, the offset
+ // will be the same value as bigROMOffset.
+
+ uint32 bufferOffset = bigROMOffset;
+
+ // See if there's a card header there, too.
+
+ EmProxyCardHeaderType cardHeader2;
+ hROM.SetMarker (bigROMOffset, kStreamFromStart);
+ hROM.GetBytes (cardHeader2.GetPtr (), cardHeader2.GetSize ());
+
+ if (Card::CheckCardHeader (cardHeader2))
+ {
+ // Looks like, so we don't have to relocate the ROM image.
+
+ bufferOffset = 0;
+ }
+
+ // The ROM size is now the size of the file plus any offset for
+ // any small ROM that we have to add and dummy up.
+
+ gROMImage_Size = hROM.GetLength() + bufferOffset;
+ gROMBank_Size = ::NextPowerOf2 (gROMImage_Size);
+
+ // Read in the ROM image.
+
+ StMemory romImage (gROMImage_Size);
+ StMemory romMetaImage (gROMImage_Size);
+
+ hROM.SetMarker (0, kStreamFromStart);
+ hROM.GetBytes (romImage.Get () + bufferOffset, hROM.GetLength());
+
+
+
+ // See if the big ROM checksum looks OK.
+
+ Card::CheckChecksum (romImage.Get () + bigROMOffset, gROMImage_Size - bigROMOffset);
+
+ // If we only had a Big ROM, dummy up the Small ROM. All we really
+ // need to do here is copy the Big ROM's card header to the Small
+ // ROM area.
+ //
+ // Also, clear out this area to 0xFF to look like new Flash RAM.
+
+ if (bufferOffset)
+ {
+ memset (romImage, 0xFF, bigROMOffset);
+ memcpy (romImage.Get (), romImage.Get () + bigROMOffset, EmProxyCardHeaderType::GetSize ());
+ }
+ else
+ {
+ // See if the small ROM checksum looks OK.
+ // Note that checksumBytes is invalid for v1 card headers,
+ // but in those cases, it's not really used anyway.
+
+ EmAliasCardHeaderType<LAS> cardHdr (romImage.Get ());
+ uint32 smallROMSize = cardHdr.checksumBytes;
+ Card::CheckChecksum (romImage.Get (), smallROMSize);
+ }
+
+
+ // Check that the ROM we just loaded can be run on this device.
+
+ EmAliasCardHeaderType<LAS> cardHdr (romImage.Get ());
+
+ EmAssert (gSession);
+ if (Card::SupportsEZ (cardHdr))
+ {
+ if (!gSession->GetDevice ().Supports68EZ328 ())
+ {
+ /* Make a hack for the Prism, Platinum and Edge below since
+ Handspring seems to report the EZ bit in their ROMs. */
+
+ if (!gSession->GetDevice ().PrismPlatinumEdgeHack ())
+ {
+ Errors::Throw (kError_WrongROMForType);
+ }
+ }
+ }
+ else if (Card::SupportsVZ (cardHdr))
+ {
+ if (!gSession->GetDevice ().Supports68VZ328 ())
+ {
+ Errors::Throw (kError_WrongROMForType);
+ }
+ }
+ else if (Card::SupportsSZ (cardHdr))
+ {
+ if (!gSession->GetDevice ().Supports68SZ328 ())
+ {
+ Errors::Throw (kError_WrongROMForType);
+ }
+ }
+ else
+ {
+ if (!gSession->GetDevice ().Supports68328 ())
+ {
+ Errors::Throw (kError_WrongROMForType);
+ }
+ }
+
+ // Byteswap all the words in the ROM (if necessary). Most accesses
+ // are 16-bit accesses, so we optimize for that case.
+
+ ByteswapWords (romImage.Get (), gROMImage_Size);
+
+ // Everything seems to be OK. Save the ROM data in some global
+ // variables for the CPU emulator to access. Make sure that
+ // gROMBank_Size is a power-of-2. The EmBankROM memory routines
+ // require this.
+
+ EmAssert (gROM_Memory == NULL);
+ EmAssert (gROM_MetaMemory == NULL);
+
+ gROM_Memory = (uint8*) romImage.Release ();
+ gROM_MetaMemory = (uint8*) romMetaImage.Release ();
+ gROMBank_Mask = gROMBank_Size - 1;
+
+ // Guess the default ROM base address.
+ // This will be used until the chip selects are set up.
+ //
+ // (I tried just setting this to zero, but the Palm OS 3.0
+ // startup code probes at 0x10c00008 and 0x10d00008 to see if
+ // it can find signatures there. If we map the ROM to zero,
+ // then we'll get bus errors when those accesses are made.)
+
+ gROMMemoryStart = cardHeader.resetVector & 0xFFF00000;
+
+}
+
+
+#pragma mark -
+
+// ===========================================================================
+// ¥ Flash Bank Accessors
+// ===========================================================================
+// These functions provide fetch and store access to the emulator's read only
+// memory.
+
+/*
+ There are five types of flash that our flash manager routines identify:
+ Mitsubishi, Hitachi, Intel, AMD, and Fujitsu. Of these, only the last
+ two are really supported right now. Unfortunately, they are the hardest
+ to emulate. :-(
+
+ To identify the kind of flash being used, our ROM routines:
+
+ - Read a word from FLASHBASE
+ - Write 0x00FF to FLASHBASE
+ - Read a word from FLASHBASE
+ - Write 0x0090 to FLASHBASE
+ - Read a manufacturer ID (word) from FLASHBASE
+ - Read a device ID (word) from FLASHBASE + 2
+ - Write 0x00FF to FLASHBASE
+
+ Mitsubishi: manufacturer == 0x001C, device == 0x005E
+ Hitachi: manufacturer == 0x0007, device == 0x0086
+ Intel: manufacturer == 0x0089, device == 0x0091
+
+ If the flash is not one of those, our ROM routines:
+
+ - Read a word from FLASHBASE
+ - Write 0x00F0 to FLASHBASE
+ - Write 0x00AA to FLASHBASE + 0xAAAA
+ - Write 0x0055 to FLASHBASE + 0x5554
+ - Write 0x0090 to FLASHBASE + 0xAAAA
+ - Read a manufacturer ID (word) from FLASHBASE
+ - Read a device ID (word) from FLASHBASE + 2
+ - Write 0x00F0 to FLASHBASE
+
+ AMD: manufacturer == 0x0001, device == 0x0049
+ Fujitsu: manufacturer == 0x0004, device == 0x0049
+
+
+ To erase a word of flash, our ROM routines:
+
+ AMD, Fujitsu:
+
+ - Read a word from FLASHBASE
+ - Write 0x00F0 to FLASHBASE
+ - Write 0x00AA to FLASHBASE + 0xAAAA
+ - Write 0x0055 to FLASHBASE + 0x5554
+ - Write 0x0080 to FLASHBASE + 0xAAAA
+ - Write 0x00AA to FLASHBASE + 0xAAAA
+ - Write 0x0055 to FLASHBASE + 0x5554
+ - Write 0x0030 to location to be erased
+ - Check erase location for 0x0080
+ - Read from FLASHBASE
+ - Write 0x00F0 to FLASHBASE
+
+ Mitsubishi, Hitachi:
+
+ - Read a word from FLASHBASE
+ - Write 0x00FF to FLASHBASE
+ - Write 0x0020 to FLASHBASE
+ - Write 0x00D0 to location to be erased
+ - Check erase location for 0x0080
+ -- If 0x0020 is also set, an error occurred
+ - Read from FLASHBASE
+ - Write 0x00FF to FLASHBASE
+
+ Intel
+
+ - Not supported
+
+ To program a block of flash:
+
+ AMD, Fujitsu:
+
+ - Read a word from FLASHBASE
+ - Write 0x00F0 to FLASHBASE
+ - For each word to write
+ - If the word is already there, continue
+ - Write 0x00AA to FLASHBASE + 0xAAAA
+ - Write 0x0055 to FLASHBASE + 0x5554
+ - Write 0x00A0 to FLASHBASE + 0xAAAA
+ - Write the word to the dest location
+ - Check write location for 0x0080
+ - Read from FLASHBASE
+ - Write 0x00F0 to FLASHBASE
+
+ Mitsubishi, Hitachi, Intel:
+
+ - Not supported
+*/
+
+
+enum
+{
+ kAMDState_Normal, // Read-only mode. Acts like a normal ROM.
+ // Almost any write of 0x00F0 to any address will get us here.
+ // Also enter here automatically after Erase or Program operation.
+ // A write of 0x00AA to 0xAAAA will put us in kAMDState_Unlocked1.
+
+ kAMDState_Unlocked1, // After first unlock cycle (0x00AA written to 0xAAAA)
+ // Looking for the second unlock cycle (0x0055 written to 0x5554);
+ // If we find one, go to kAMDState_Unlocked2.
+ // ??? What happens on other operations?
+
+ kAMDState_Unlocked2, // After second unlock cycle (0x0055 written to 0x5554)
+ // Now looking for a command to be written to 0xAAAA
+ // If we find 0x0090, go to kAMDState_Autoselect.
+ // If we find 0x0080, set gEraseIsSetup and go to kAMDState_Normal. ??? When should gEraseIsSetup get cleared?
+ // If we find 0x0030, if gEraseIsSetup erase the sector and go to kAMDState_EraseDone.
+ // If we fine 0x00A0, go to kAMDState_Program.
+ // ??? What happens on other operations?
+
+ kAMDState_Autoselect, // After a write of 0x0090 to 0x5555.
+ // A read of 0x0000 returns 0x0001 (manufacturer ID).
+ // A read of 0x0002 returns 0x0049 (device ID).
+ // A write of 0x00F0 to any address returns us to kAMDState_Normal.
+ // ??? What happens on other operations?
+
+ kAMDState_Program, // After a program sequence was entered.
+ // Accept any write operation and go to kAMDState_ProgramDone.
+ // ??? What happens on other operations?
+
+ kAMDState_EraseDone, // After a Erase operation.
+ // On the next read, return successful operation and return to kAMDState_Normal
+ // ??? What happens on other operations?
+
+ kAMDState_ProgramDone, // After a Program operation.
+ // On the next read, return successful operation and return to kAMDState_Normal
+ // ??? What happens on other operations?
+ kAMDState_Dummy
+};
+
+
+static EmAddressBank gFlashAddressBank =
+{
+ EmBankFlash::GetLong,
+ EmBankFlash::GetWord,
+ EmBankFlash::GetByte,
+ EmBankFlash::SetLong,
+ EmBankFlash::SetWord,
+ EmBankFlash::SetByte,
+ EmBankFlash::GetRealAddress,
+ EmBankFlash::ValidAddress,
+ EmBankFlash::GetMetaAddress,
+ EmBankFlash::AddOpcodeCycles
+};
+
+#define FLASHBASE (EmBankROM::GetMemoryStart ())
+
+static int gState = kAMDState_Normal;
+static Bool gEraseIsSetup;
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankFlash::Initialize
+ *
+ * DESCRIPTION: Standard initialization function. Responsible for
+ * initializing this sub-system when a new session is
+ * created. Will be followed by at least one call to
+ * Reset or Load.
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void EmBankFlash::Initialize (void)
+{
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankFlash::Reset
+ *
+ * DESCRIPTION: Standard reset function. Sets the sub-system to a
+ * default state. This occurs not only on a Reset (as
+ * from the menu item), but also when the sub-system
+ * is first initialized (Reset is called after Initialize)
+ * as well as when the system is re-loaded from an
+ * insufficient session file.
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void EmBankFlash::Reset (Bool hardwareReset)
+{
+ if (hardwareReset)
+ {
+ gState = kAMDState_Normal;
+ }
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankFlash::Save
+ *
+ * DESCRIPTION: Standard save function. Saves any sub-system state to
+ * the given session file.
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void EmBankFlash::Save (SessionFile&)
+{
+ // !!! Save gState && gEraseIsSetup?
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankFlash::Load
+ *
+ * DESCRIPTION: Standard load function. Loads any sub-system state
+ * from the given session file.
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void EmBankFlash::Load (SessionFile&)
+{
+ // !!! Load gState && gEraseIsSetup?
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankFlash::Dispose
+ *
+ * DESCRIPTION: Standard dispose function. Completely release any
+ * resources acquired or allocated in Initialize and/or
+ * Load.
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void EmBankFlash::Dispose (void)
+{
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankFlash::SetBankHandlers
+ *
+ * DESCRIPTION: Set the bank handlers UAE uses to dispatch memory
+ * access operations.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmBankFlash::SetBankHandlers (void)
+{
+ gManagedROMSize = EmHAL::GetROMSize ();
+
+ // Memory banks gROMMemoryStart to <mumble> are managed by the functions
+ // in EmBankROM. <mumble> is based on the amount of ROM being emulated.
+
+ uint32 first_bank = EmMemBankIndex (EmBankROM::GetMemoryStart ());
+ uint32 last_bank = EmMemBankIndex (EmBankROM::GetMemoryStart () + gManagedROMSize - 1);
+
+ Memory::InitializeBanks ( gFlashAddressBank, first_bank,
+ last_bank - first_bank + 1);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankFlash::GetLong
+// ---------------------------------------------------------------------------
+
+uint32 EmBankFlash::GetLong (emuptr address)
+{
+ return EmBankROM::GetLong (address);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankFlash::GetWord
+// ---------------------------------------------------------------------------
+
+uint32 EmBankFlash::GetWord (emuptr address)
+{
+ switch (gState)
+ {
+ case kAMDState_Normal:
+ // Read-only mode. Acts like a normal ROM.
+ // Almost any write of 0x00F0 to any address will get us here.
+ // Also enter here automatically after Erase or Program operation.
+ // A write of 0x00AA to 0xAAAA will put us in kAMDState_Unlocked1.
+
+ break;
+
+ case kAMDState_Unlocked1:
+ // After first unlock cycle (0x00AA written to 0xAAAA)
+ // Looking for the second unlock cycle (0x0055 written to 0x5554);
+ // If we find one, go to kAMDState_Unlocked2.
+ // ??? What happens on other operations?
+
+ break;
+
+ case kAMDState_Unlocked2:
+ // After second unlock cycle (0x0055 written to 0x5554)
+ // Now looking for a command to be written to 0xAAAA
+ // If we find 0x0090, go to kAMDState_Autoselect.
+ // If we find 0x0080, set gEraseIsSetup and go to kAMDState_Normal. ??? When should gEraseIsSetup get cleared?
+ // If we find 0x0030, if gEraseIsSetup erase the sector and go to kAMDState_ProgramDone.
+ // If we fine 0x00A0, go to kAMDState_Program.
+ // ??? What happens on other operations?
+
+ break;
+
+ case kAMDState_Autoselect:
+ // After a write of 0x0090 to 0x5555.
+ // A read of 0x0000 returns 0x0001 (manufacturer ID).
+ // A read of 0x0002 returns 0x0049 (device ID).
+ // A write of 0x00F0 to any address returns us to kAMDState_Normal.
+ // ??? What happens on other operations?
+
+ if (address == FLASHBASE)
+ {
+ return 0x0001;
+ }
+ else if (address == FLASHBASE + 2)
+ {
+ return 0x0049;
+ }
+ break;
+
+ case kAMDState_Program:
+ // After a program sequence was entered.
+ // Accept any write operation and go to kAMDState_ProgramDone.
+ // ??? What happens on other operations?
+
+ break;
+
+ case kAMDState_EraseDone:
+ // After a Program or Erase operation.
+ // On the next read, return successful operation and return to kAMDState_Normal
+ // ??? What happens on other operations?
+
+ // !!! We should really check that address is the same as the
+ // one specified in the Erase command.
+
+ gState = kAMDState_Normal;
+ return 0x0080;
+
+ case kAMDState_ProgramDone:
+ // After a Program or Erase operation.
+ // On the next read, return successful operation and return to kAMDState_Normal
+ // ??? What happens on other operations?
+
+ // !!! We should really check that address is the same as the
+ // one specified in the Program command.
+
+ gState = kAMDState_Normal;
+ return 0x0080 & EmBankROM::GetWord (address);
+ }
+
+ return EmBankROM::GetWord (address);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankFlash::GetByte
+// ---------------------------------------------------------------------------
+
+uint32 EmBankFlash::GetByte (emuptr address)
+{
+ return EmBankROM::GetByte (address);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankFlash::SetLong
+// ---------------------------------------------------------------------------
+
+void EmBankFlash::SetLong (emuptr address, uint32 value)
+{
+ EmBankROM::SetLong (address, value);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankFlash::SetWord
+// ---------------------------------------------------------------------------
+
+void EmBankFlash::SetWord (emuptr address, uint32 value)
+{
+ switch (gState)
+ {
+ case kAMDState_Normal:
+ // Read-only mode. Acts like a normal ROM.
+ // Almost any write of 0x00F0 to any address will get us here.
+ // Also enter here automatically after Erase or Program operation.
+ // A write of 0x00AA to 0xAAAA will put us in kAMDState_Unlocked1.
+
+ if (address == FLASHBASE + 0xAAAA && value == 0x00AA)
+ {
+ gState = kAMDState_Unlocked1;
+ return;
+ }
+
+ // Allow these. PrvIdentifyFlashCode probes with these values
+ // to determine what Flash part we've got.
+
+ if (address == FLASHBASE && (value == 0x00FF || value == 0x00F0 || value == 0x0090))
+ {
+ return;
+ }
+ break;
+
+ case kAMDState_Unlocked1:
+ // After first unlock cycle (0x00AA written to 0xAAAA)
+ // Looking for the second unlock cycle (0x0055 written to 0x5554);
+ // If we find one, go to kAMDState_Unlocked2.
+ // ??? What happens on other operations?
+
+ if (value == 0x00F0)
+ {
+ gState = kAMDState_Normal;
+ return;
+ }
+ else if (address == FLASHBASE + 0x5554 && value == 0x0055)
+ {
+ gState = kAMDState_Unlocked2;
+ return;
+ }
+ break;
+
+ case kAMDState_Unlocked2:
+ // After second unlock cycle (0x0055 written to 0x5554)
+ // Now looking for a command to be written to 0xAAAA
+ // If we find 0x0090, go to kAMDState_Autoselect.
+ // If we find 0x0080, set gEraseIsSetup and go to kAMDState_Normal. ??? When should gEraseIsSetup get cleared?
+ // If we find 0x0030, if gEraseIsSetup erase the sector and go to kAMDState_EraseDone.
+ // If we fine 0x00A0, go to kAMDState_Program.
+ // ??? What happens on other operations?
+
+ if (value == 0x00F0)
+ {
+ gState = kAMDState_Normal;
+ return;
+ }
+ else if (value == 0x0030 && gEraseIsSetup)
+ {
+ const int kEraseValue = 0xFF;
+#if 0
+ DWord readWriteParmsOffset = EmMemGet32 (0x10C00000 + offsetof (CardHeaderType, readWriteParmsOffset));
+ DWord readWriteParmsSize = EmMemGet32 (0x10C00000 + offsetof (CardHeaderType, readWriteParmsSize));
+ DWord readOnlyParmsOffset = EmMemGet32 (0x10C00000 + offsetof (CardHeaderType, readOnlyParmsOffset));
+ DWord readOnlyParmsSize = 0x00002000;
+ DWord readWriteWorkingOffset = EmMemGet32 (0x10C00000 + offsetof (CardHeaderType, readWriteWorkingOffset));
+ DWord readWriteWorkingSize = EmMemGet32 (0x10C00000 + offsetof (CardHeaderType, readWriteWorkingSize));
+
+ if (address >= 0x10000000 + readWriteParmsOffset &&
+ address < 0x10000000 + readWriteParmsOffset + readWriteParmsSize)
+ {
+ EmMem_memset (0x10000000 + readWriteParmsOffset, kEraseValue, readWriteParmsSize);
+ }
+ else if (address >= 0x10000000 + readOnlyParmsOffset &&
+ address < 0x10000000 + readOnlyParmsOffset + readOnlyParmsSize)
+ {
+ EmMem_memset (0x10000000 + readOnlyParmsOffset, kEraseValue, readOnlyParmsSize);
+ }
+ else if (address >= 0x10000000 + readWriteWorkingOffset &&
+ address < 0x10000000 + readWriteWorkingOffset + readWriteWorkingSize)
+ {
+ EmMem_memset (0x10000000 + readWriteWorkingOffset, kEraseValue, readWriteWorkingSize);
+ }
+#endif
+
+ const unsigned long kSector1Start = 0x10C00000;
+ const unsigned long kSector1Size = 0x00004000;
+ const unsigned long kSector2Start = 0x10C04000;
+ const unsigned long kSector2Size = 0x00002000;
+ const unsigned long kSector3Start = 0x10C06000;
+ const unsigned long kSector3Size = 0x00002000;
+ const unsigned long kSector4Start = 0x10C08000;
+ const unsigned long kSector4Size = 0x00008000;
+
+ CEnableFullAccess munge;
+
+ if (address == kSector1Start)
+ {
+ EmMem_memset (kSector1Start, kEraseValue, kSector1Size);
+ }
+ else if (address == kSector2Start)
+ {
+ EmMem_memset (kSector2Start, kEraseValue, kSector2Size);
+ }
+ else if (address == kSector3Start)
+ {
+ EmMem_memset (kSector3Start, kEraseValue, kSector3Size);
+ }
+ else if (address == kSector4Start)
+ {
+ EmMem_memset (kSector4Start, kEraseValue, kSector4Size);
+ }
+
+ gState = kAMDState_EraseDone;
+ return;
+ }
+ else if (address == FLASHBASE + 0xAAAA)
+ {
+ if (value == 0x0090)
+ {
+ gState = kAMDState_Autoselect;
+ return;
+ }
+ else if (value == 0x0080)
+ {
+ gEraseIsSetup = true;
+ gState = kAMDState_Normal;
+ return;
+ }
+ else if (value == 0x00A0)
+ {
+ gState = kAMDState_Program;
+ return;
+ }
+ }
+ break;
+
+ case kAMDState_Autoselect:
+ // After a write of 0x0090 to 0x5555.
+ // A read of 0x0000 returns 0x0001 (manufacturer ID).
+ // A read of 0x0002 returns 0x0049 (device ID).
+ // A write of 0x00F0 to any address returns us to kAMDState_Normal.
+ // ??? What happens on other operations?
+
+ if (value == 0x00F0)
+ {
+ gState = kAMDState_Normal;
+ return;
+ }
+ break;
+
+ case kAMDState_Program:
+ // After a program sequence was entered.
+ // Accept any write operation and go to kAMDState_ProgramDone.
+ // ??? What happens on other operations?
+
+ address &= gROMBank_Mask;
+ EmMemDoPut16 (gROM_Memory + address, value);
+
+ gState = kAMDState_ProgramDone;
+ return;
+
+ case kAMDState_EraseDone:
+ // After a Program or Erase operation.
+ // On the next read, return successful operation and return to kAMDState_Normal
+ // ??? What happens on other operations?
+
+ return;
+
+ case kAMDState_ProgramDone:
+ // After a Program or Erase operation.
+ // On the next read, return successful operation and return to kAMDState_Normal
+ // ??? What happens on other operations?
+
+ return;
+ }
+
+ EmBankROM::SetWord (address, value);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankFlash::SetByte
+// ---------------------------------------------------------------------------
+
+void EmBankFlash::SetByte (emuptr address, uint32 value)
+{
+ EmBankROM::SetByte (address, value);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankFlash::ValidAddress
+// ---------------------------------------------------------------------------
+
+int EmBankFlash::ValidAddress (emuptr address, uint32 size)
+{
+ return EmBankROM::ValidAddress (address, size);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankFlash::GetRealAddress
+// ---------------------------------------------------------------------------
+
+uint8* EmBankFlash::GetRealAddress (emuptr address)
+{
+ // Strip the uppermost bit of the address.
+
+ address &= gROMBank_Mask;
+
+ return (uint8*) &gROM_Memory[address];
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankFlash::GetMetaAddress
+// ---------------------------------------------------------------------------
+
+uint8* EmBankFlash::GetMetaAddress (emuptr address)
+{
+ // Strip the uppermost bit of the address.
+
+ address &= gROMBank_Mask;
+
+ return (uint8*) &(gROM_MetaMemory[address]);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankFlash::AddOpcodeCycles
+// ---------------------------------------------------------------------------
+
+void EmBankFlash::AddOpcodeCycles (void)
+{
+#if (HAS_PROFILING)
+ CYCLE_GETWORD (WAITSTATES_ROM);
+#endif
+}
+
+
+#pragma mark -
+
+// ===========================================================================
+// ¥ Card
+// ===========================================================================
+
+// ---------------------------------------------------------------------------
+// ¥ Card::CheckCardHeader
+// ---------------------------------------------------------------------------
+// Determines if the memory pointed to looks like a card header.
+
+Bool Card::CheckCardHeader (const EmProxyCardHeaderType& cardHdr)
+{
+ // Make sure the stack size isn't something ludicrous.
+
+ if (cardHdr.initStack == 0 || cardHdr.initStack > 0x000FFFFF) // 1 Meg
+ return false;
+
+ // Make sure the signature is right.
+
+ if (cardHdr.signature != sysCardSignature)
+ return false;
+
+ // Make sure the header version isn't ludicrous.
+
+ if (cardHdr.hdrVersion == 0 || cardHdr.hdrVersion > 255) // arbitrary value
+ return false;
+
+ // Make sure this isn't a "RAM only" card.
+
+ if (cardHdr.flags & memCardHeaderFlagRAMOnly)
+ return false;
+
+ return true;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ Card::CheckChecksum
+// ---------------------------------------------------------------------------
+// Determines if the memory pointed to looks like a card header.
+
+Bool Card::CheckChecksum (const void* p, uint32 fileLength)
+{
+ EmAliasCardHeaderType<LAS> cardHdr ((void*) p);
+
+ if (cardHdr.hdrVersion == 1)
+ {
+ static const UInt16 kDebug20 = 0x9BED;
+
+ UInt16 checksumValue = Crc16CalcBigBlock ((/*non-const*/ void*) p, fileLength, 0);
+
+ // Special hack for 2.0 Debug ROMs. The version with this checksum was
+ // bogus, so let's make sure we never load it.
+
+ if (checksumValue == kDebug20)
+ {
+ // Throw a special error for this one.
+
+ Errors::Throw (kError_UnsupportedROM);
+ }
+
+ return true;
+ }
+ else
+ {
+ // The checksum is the cumulative checksum of the ROM image before
+ // the stored checksum value and the ROM image following the checksum
+ // value. First, calculate the first part.
+
+ UInt32 chunkSize = cardHdr.offsetof_checksumValue ();
+ UInt16 checksumValue = Crc16CalcBigBlock (
+ (/*non-const*/ void*) p, chunkSize, 0);
+
+ // Now calculate the second part.
+
+ UInt32 skipSize = chunkSize + cardHdr.checksumValue.GetSize ();
+ checksumValue = Crc16CalcBigBlock (
+ ((char*) p) + skipSize,
+ cardHdr.checksumBytes - skipSize,
+ checksumValue);
+
+ if (checksumValue == cardHdr.checksumValue)
+ {
+ return true;
+ }
+ }
+
+ Errors::DoDialog (kStr_BadChecksum, kDlgFlags_OK);
+
+ return false;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ Card::Supports328
+// ---------------------------------------------------------------------------
+
+Bool Card::Supports328 (const EmAliasCardHeaderType<LAS>& cardHdr)
+{
+ Bool dbMode = false;
+
+ if (cardHdr.hdrVersion < 3 || (cardHdr.flags & memCardHeaderFlag328))
+ {
+ dbMode = true;
+ }
+
+ return dbMode;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ Card::SupportsEZ
+// ---------------------------------------------------------------------------
+
+Bool Card::SupportsEZ (const EmAliasCardHeaderType<LAS>& cardHdr)
+{
+ Bool ezMode = false;
+
+ if (cardHdr.hdrVersion >= 3 && (cardHdr.flags & memCardHeaderFlagEZ))
+ {
+ ezMode = true;
+ }
+
+ return ezMode;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ Card::SupportsVZ
+// ---------------------------------------------------------------------------
+#define memCardHeaderFlagVZ 0x0040 // ROM Supports 68VZ328 processor
+
+Bool Card::SupportsVZ (const EmAliasCardHeaderType<LAS>& cardHdr)
+{
+ Bool vzMode = false;
+
+ if (cardHdr.hdrVersion >= 3 && (cardHdr.flags & memCardHeaderFlagVZ))
+ {
+ vzMode = true;
+ }
+
+ return vzMode;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ Card::SupportsSZ
+// ---------------------------------------------------------------------------
+#define memCardHeaderFlagSZ 0x0080 // ROM Supports 68SZ328 processor
+
+Bool Card::SupportsSZ (const EmAliasCardHeaderType<LAS>& cardHdr)
+{
+ Bool szMode = false;
+
+ if (cardHdr.hdrVersion >= 3 && (cardHdr.flags & memCardHeaderFlagSZ))
+ {
+ szMode = true;
+ }
+
+ return szMode;
+}