aboutsummaryrefslogtreecommitdiff
path: root/SrcShared/Hardware/EmBankDRAM.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'SrcShared/Hardware/EmBankDRAM.cpp')
-rw-r--r--SrcShared/Hardware/EmBankDRAM.cpp686
1 files changed, 686 insertions, 0 deletions
diff --git a/SrcShared/Hardware/EmBankDRAM.cpp b/SrcShared/Hardware/EmBankDRAM.cpp
new file mode 100644
index 0000000..50b6d18
--- /dev/null
+++ b/SrcShared/Hardware/EmBankDRAM.cpp
@@ -0,0 +1,686 @@
+/* -*- 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.
+\* ===================================================================== */
+
+// ---------------------------------------------------------------------------
+#pragma mark ===== Includes
+// ---------------------------------------------------------------------------
+
+#include "EmCommon.h"
+#include "EmBankDRAM.h"
+
+#include "DebugMgr.h" // Debug::CheckStepSpy
+#include "EmBankSRAM.h" // gRAMBank_Size, gRAM_Memory, gMemoryAccess
+#include "EmCPU.h" // GetSP
+#include "EmCPU68K.h" // gCPU68K
+#include "EmHAL.h" // EmHAL
+#include "EmMemory.h" // Memory::InitializeBanks, IsPCInRAM (implicitly, through META_CHECK)
+#include "EmPalmFunction.h" // InSysLaunch
+#include "EmPalmOS.h" // EmPalmOS::GetBootStack
+#include "EmPatchState.h" // META_CHECK calls EmPatchState::IsPCInMemMgr
+#include "EmScreen.h" // EmScreen::MarkDirty
+#include "EmSession.h" // gSession
+#include "MetaMemory.h" // MetaMemory
+#include "Profiling.h" // WAITSTATES_DRAM
+
+
+// ---------------------------------------------------------------------------
+#pragma mark ===== Types
+// ---------------------------------------------------------------------------
+
+// ---------------------------------------------------------------------------
+#pragma mark ===== Functions
+// ---------------------------------------------------------------------------
+
+// ---------------------------------------------------------------------------
+#pragma mark ===== Constants
+// ---------------------------------------------------------------------------
+
+const uint32 kMemoryStart = 0x00000000;
+const emuptr kGlobalStart = offsetof (LowMemHdrType, globals);
+
+
+// ---------------------------------------------------------------------------
+#pragma mark ===== Variables
+// ---------------------------------------------------------------------------
+
+// ----- Saved variables -----------------------------------------------------
+
+static uint32 gDynamicHeapSize;
+
+
+// ----- UnSaved variables ---------------------------------------------------
+
+static EmAddressBank gAddressBank =
+{
+ EmBankDRAM::GetLong,
+ EmBankDRAM::GetWord,
+ EmBankDRAM::GetByte,
+ EmBankDRAM::SetLong,
+ EmBankDRAM::SetWord,
+ EmBankDRAM::SetByte,
+ EmBankDRAM::GetRealAddress,
+ EmBankDRAM::ValidAddress,
+ EmBankDRAM::GetMetaAddress,
+ EmBankDRAM::AddOpcodeCycles
+};
+
+
+// ---------------------------------------------------------------------------
+#pragma mark ===== Inlines
+// ---------------------------------------------------------------------------
+
+static inline int InlineValidAddress (emuptr address, size_t size)
+{
+ int result = (address + size) <= gRAMBank_Size;
+
+ return result;
+}
+
+
+static inline uint8* InlineGetRealAddress (emuptr address)
+{
+ return (uint8*) &(gRAM_Memory[address]);
+}
+
+
+static inline uint8* InlineGetMetaAddress (emuptr address)
+{
+ return (uint8*) &(gRAM_MetaMemory[address]);
+}
+
+
+static void PrvReportBelowStackPointerAccess (emuptr address, size_t size, Bool forRead)
+{
+ // Can be NULL during bootup.
+
+ if (gStackLow == EmMemNULL)
+ return;
+
+ // SysLaunch clears out as much RAM as it can, including the area
+ // below the stack pointer.
+
+ if (::InSysLaunch ())
+ return;
+
+ // We can look in the stack for CJ_TAGFENCE, etc.
+
+ if (CEnableFullAccess::AccessOK ())
+ return;
+
+ // If the access is in the boot stack, allow it. There's a lot of memory
+ // allocation going on below the stack pointer, such that it's not too
+ // clear where the current "low end" of stack should be.
+
+ StackRange bootStack = EmPalmOS::GetBootStack ();
+ if (address >= bootStack.fBottom && address < bootStack.fTop)
+ return;
+
+ gSession->ScheduleDeferredError (new EmDeferredErrLowStack (
+ gStackLow, gCPU->GetSP (), gStackHigh,
+ address, size, forRead));
+}
+
+
+static inline void PrvCheckBelowStackPointerAccess (emuptr address, size_t size, Bool forRead)
+{
+#if 1
+ if (address < gCPU->GetSP () && address >= gStackLow)
+ {
+ ::PrvReportBelowStackPointerAccess (address, size, forRead);
+ }
+#endif
+}
+
+
+static inline void PrvScreenCheck (uint8* metaAddress, emuptr address, size_t size)
+{
+#if defined (macintosh)
+
+ if (size == 1 && !MetaMemory::IsScreenBuffer8 (metaAddress))
+ return;
+
+ if (size == 2 && !MetaMemory::IsScreenBuffer16 (metaAddress))
+ return;
+
+ if (size == 4 && !MetaMemory::IsScreenBuffer32 (metaAddress))
+ return;
+
+#else
+
+ if (MetaMemory::IsScreenBuffer (metaAddress, size))
+
+#endif
+
+ {
+ EmScreen::MarkDirty (address, size);
+ }
+}
+
+
+#pragma mark -
+
+// ===========================================================================
+// ¥ DRAM Bank Accessors
+// ===========================================================================
+// These functions provide fetch and store access to the emulator's random
+// access memory.
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankDRAM::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 EmBankDRAM::Initialize (void)
+{
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankDRAM::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 EmBankDRAM::Reset (Bool /*hardwareReset*/)
+{
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankDRAM::Save
+ *
+ * DESCRIPTION: Standard save function. Saves any sub-system state to
+ * the given session file.
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void EmBankDRAM::Save (SessionFile&)
+{
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankDRAM::Load
+ *
+ * DESCRIPTION: Standard load function. Loads any sub-system state
+ * from the given session file.
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void EmBankDRAM::Load (SessionFile&)
+{
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankDRAM::Dispose
+ *
+ * DESCRIPTION: Standard dispose function. Completely release any
+ * resources acquired or allocated in Initialize and/or
+ * Load.
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void EmBankDRAM::Dispose (void)
+{
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankDRAM::SetBankHandlers
+ *
+ * DESCRIPTION: Set the bank handlers UAE uses to dispatch memory
+ * access operations.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmBankDRAM::SetBankHandlers (void)
+{
+ // First few memory banks are managed by the functions in EmBankDRAM.
+
+ gDynamicHeapSize = EmHAL::GetDynamicHeapSize ();
+
+ if (gDynamicHeapSize > gRAMBank_Size)
+ gDynamicHeapSize = gRAMBank_Size;
+
+ uint32 sixtyFourK = 64 * 1024L;
+ uint32 numBanks = (gDynamicHeapSize + sixtyFourK - 1) / sixtyFourK;
+
+ Memory::InitializeBanks ( gAddressBank,
+ EmMemBankIndex (kMemoryStart),
+ numBanks);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankDRAM::GetLong
+// ---------------------------------------------------------------------------
+
+uint32 EmBankDRAM::GetLong (emuptr address)
+{
+ if (address > gDynamicHeapSize)
+ return EmBankSRAM::GetLong (address);
+
+#if (PROFILE_MEMORY)
+ gMemoryAccess[kDRAMLongRead]++;
+ if (address & 2)
+ gMemoryAccess[kDRAMLongRead2]++;
+#endif
+
+ if (CHECK_FOR_ADDRESS_ERROR && (address & 1) != 0)
+ {
+ AddressError (address, sizeof (uint32), true);
+ }
+
+ register uint8* metaAddress = InlineGetMetaAddress (address);
+ META_CHECK (metaAddress, address, GetLong, uint32, true);
+
+ ::PrvCheckBelowStackPointerAccess (address, sizeof (uint32), true);
+
+ if (VALIDATE_DRAM_GET &&
+ gMemAccessFlags.fValidate_DRAMGet &&
+ !InlineValidAddress (address, sizeof (uint32)))
+ {
+ InvalidAccess (address, sizeof (uint32), true);
+ }
+
+#if (HAS_PROFILING)
+ CYCLE_GETLONG (WAITSTATES_DRAM);
+#endif
+
+ return EmMemDoGet32 (gRAM_Memory + address);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankDRAM::GetWord
+// ---------------------------------------------------------------------------
+
+uint32 EmBankDRAM::GetWord (emuptr address)
+{
+ if (address > gDynamicHeapSize)
+ return EmBankSRAM::GetWord (address);
+
+#if (PROFILE_MEMORY)
+ gMemoryAccess[kDRAMWordRead]++;
+#endif
+
+ if (CHECK_FOR_ADDRESS_ERROR && (address & 1) != 0)
+ {
+ AddressError (address, sizeof (uint16), true);
+ }
+
+ register uint8* metaAddress = InlineGetMetaAddress (address);
+ META_CHECK (metaAddress, address, GetWord, uint16, true);
+
+ ::PrvCheckBelowStackPointerAccess (address, sizeof (uint16), true);
+
+ if (VALIDATE_DRAM_GET &&
+ gMemAccessFlags.fValidate_DRAMGet &&
+ !InlineValidAddress (address, sizeof (uint16)))
+ {
+ InvalidAccess (address, sizeof (uint16), true);
+ }
+
+#if (HAS_PROFILING)
+ CYCLE_GETWORD (WAITSTATES_DRAM);
+#endif
+
+ return EmMemDoGet16 (gRAM_Memory + address);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankDRAM::GetByte
+// ---------------------------------------------------------------------------
+
+uint32 EmBankDRAM::GetByte (emuptr address)
+{
+ if (address > gDynamicHeapSize)
+ return EmBankSRAM::GetByte (address);
+
+#if (PROFILE_MEMORY)
+ gMemoryAccess[kDRAMByteRead]++;
+#endif
+
+ register uint8* metaAddress = InlineGetMetaAddress (address);
+ META_CHECK (metaAddress, address, GetByte, uint8, true);
+
+ ::PrvCheckBelowStackPointerAccess (address, sizeof (uint8), true);
+
+ if (VALIDATE_DRAM_GET &&
+ gMemAccessFlags.fValidate_DRAMGet &&
+ !InlineValidAddress (address, sizeof (uint8)))
+ {
+ InvalidAccess (address, sizeof (uint8), true);
+ }
+
+#if (HAS_PROFILING)
+ CYCLE_GETBYTE (WAITSTATES_DRAM);
+#endif
+
+ return EmMemDoGet8 (gRAM_Memory + address);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankDRAM::SetLong
+// ---------------------------------------------------------------------------
+
+void EmBankDRAM::SetLong (emuptr address, uint32 value)
+{
+ if (address > gDynamicHeapSize)
+ {
+ EmBankSRAM::SetLong (address, value);
+ return;
+ }
+
+#if (PROFILE_MEMORY)
+ gMemoryAccess[kDRAMLongWrite]++;
+ if (address & 2)
+ gMemoryAccess[kDRAMLongWrite2]++;
+#endif
+
+ if (CHECK_FOR_ADDRESS_ERROR && (address & 1) != 0)
+ {
+ AddressError (address, sizeof (uint32), false);
+ }
+
+ register uint8* metaAddress = InlineGetMetaAddress (address);
+ META_CHECK (metaAddress, address, SetLong, uint32, false);
+
+ ::PrvCheckBelowStackPointerAccess (address, sizeof (uint32), false);
+
+ if (VALIDATE_DRAM_SET &&
+ gMemAccessFlags.fValidate_DRAMSet &&
+ !InlineValidAddress (address, sizeof (uint32)))
+ {
+ InvalidAccess (address, sizeof (uint32), false);
+ }
+
+ ::PrvScreenCheck (metaAddress, address, sizeof (uint32));
+
+#if (HAS_PROFILING)
+ CYCLE_PUTLONG (WAITSTATES_DRAM);
+#endif
+
+ EmMemDoPut32 (gRAM_Memory + address, value);
+
+#if FOR_LATER
+ // Mark that this memory location can now be read from.
+
+ MetaMemory::MarkLongInitialized (address);
+#endif
+
+ // See if any interesting memory locations have changed. If so,
+ // CheckStepSpy will report it.
+
+ Debug::CheckStepSpy (address, sizeof (uint32));
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankDRAM::SetWord
+// ---------------------------------------------------------------------------
+
+void EmBankDRAM::SetWord (emuptr address, uint32 value)
+{
+ if (address > gDynamicHeapSize)
+ {
+ EmBankSRAM::SetWord (address, value);
+ return;
+ }
+
+#if (PROFILE_MEMORY)
+ gMemoryAccess[kDRAMWordWrite]++;
+#endif
+
+ if (CHECK_FOR_ADDRESS_ERROR && (address & 1) != 0)
+ {
+ AddressError (address, sizeof (uint16), false);
+ }
+
+ register uint8* metaAddress = InlineGetMetaAddress (address);
+ META_CHECK (metaAddress, address, SetWord, uint16, false);
+
+ ::PrvCheckBelowStackPointerAccess (address, sizeof (uint16), false);
+
+ if (VALIDATE_DRAM_SET &&
+ gMemAccessFlags.fValidate_DRAMSet &&
+ !InlineValidAddress (address, sizeof (uint16)))
+ {
+ InvalidAccess (address, sizeof (uint16), false);
+ }
+
+ ::PrvScreenCheck (metaAddress, address, sizeof (uint16));
+
+#if (HAS_PROFILING)
+ CYCLE_PUTWORD (WAITSTATES_DRAM);
+#endif
+
+ EmMemDoPut16 (gRAM_Memory + address, value);
+
+#if FOR_LATER
+ // Mark that this memory location can now be read from.
+
+ MetaMemory::MarkWordInitialized (address);
+#endif
+
+ // See if any interesting memory locations have changed. If so,
+ // CheckStepSpy will report it.
+
+ Debug::CheckStepSpy (address, sizeof (uint16));
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankDRAM::SetByte
+// ---------------------------------------------------------------------------
+
+void EmBankDRAM::SetByte (emuptr address, uint32 value)
+{
+ if (address > gDynamicHeapSize)
+ {
+ EmBankSRAM::SetByte (address, value);
+ return;
+ }
+
+#if (PROFILE_MEMORY)
+ gMemoryAccess[kDRAMByteWrite]++;
+#endif
+
+ register uint8* metaAddress = InlineGetMetaAddress (address);
+ META_CHECK (metaAddress, address, SetByte, uint8, false);
+
+ ::PrvCheckBelowStackPointerAccess (address, sizeof (uint8), false);
+
+ if (VALIDATE_DRAM_SET &&
+ gMemAccessFlags.fValidate_DRAMSet &&
+ !InlineValidAddress (address, sizeof (uint8)))
+ {
+ InvalidAccess (address, sizeof (uint8), false);
+ }
+
+ ::PrvScreenCheck (metaAddress, address, sizeof (uint8));
+
+#if (HAS_PROFILING)
+ CYCLE_PUTBYTE (WAITSTATES_DRAM);
+#endif
+
+ EmMemDoPut8 (gRAM_Memory + address, value);
+
+#if FOR_LATER
+ // Mark that this memory location can now be read from.
+
+ MetaMemory::MarkByteInitialized (address);
+#endif
+
+ // See if any interesting memory locations have changed. If so,
+ // CheckStepSpy will report it.
+
+ Debug::CheckStepSpy (address, sizeof (uint8));
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankDRAM::ValidAddress
+// ---------------------------------------------------------------------------
+
+int EmBankDRAM::ValidAddress (emuptr address, uint32 size)
+{
+ int result = InlineValidAddress (address, size);
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankDRAM::GetRealAddress
+// ---------------------------------------------------------------------------
+
+uint8* EmBankDRAM::GetRealAddress (emuptr address)
+{
+ return InlineGetRealAddress (address);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankDRAM::GetMetaAddress
+// ---------------------------------------------------------------------------
+
+uint8* EmBankDRAM::GetMetaAddress (emuptr address)
+{
+ return InlineGetMetaAddress (address);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankDRAM::AddOpcodeCycles
+// ---------------------------------------------------------------------------
+
+void EmBankDRAM::AddOpcodeCycles (void)
+{
+#if (HAS_PROFILING)
+ CYCLE_GETWORD (WAITSTATES_DRAM);
+#endif
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankDRAM::AddressError
+// ---------------------------------------------------------------------------
+
+void EmBankDRAM::AddressError (emuptr address, long size, Bool forRead)
+{
+ EmAssert (gCPU68K);
+ gCPU68K->AddressError (address, size, forRead);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankDRAM::InvalidAccess
+// ---------------------------------------------------------------------------
+
+void EmBankDRAM::InvalidAccess (emuptr address, long size, Bool forRead)
+{
+ EmAssert (gCPU68K);
+ gCPU68K->BusError (address, size, forRead);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankDRAM::ProbableCause
+// ---------------------------------------------------------------------------
+
+void EmBankDRAM::ProbableCause (emuptr address, long size, Bool forRead)
+{
+ EmAssert (gSession);
+
+ Errors::EAccessType whatHappened = MetaMemory::GetWhatHappened (address, size, forRead);
+
+ switch (whatHappened)
+ {
+ case Errors::kOKAccess:
+ break;
+
+ case Errors::kLowMemAccess:
+ gSession->ScheduleDeferredError (new EmDeferredErrLowMemory (address, size, forRead));
+ break;
+
+ case Errors::kGlobalVarAccess:
+ gSession->ScheduleDeferredError (new EmDeferredErrSystemGlobals (address, size, forRead));
+ break;
+
+ case Errors::kScreenAccess:
+ gSession->ScheduleDeferredError (new EmDeferredErrScreen (address, size, forRead));
+ break;
+
+ case Errors::kMemMgrAccess:
+ gSession->ScheduleDeferredError (new EmDeferredErrMemMgrStructures (address, size, forRead));
+ break;
+
+ case Errors::kFreeChunkAccess:
+ gSession->ScheduleDeferredError (new EmDeferredErrFreeChunk (address, size, forRead));
+ break;
+
+ case Errors::kUnlockedChunkAccess:
+ gSession->ScheduleDeferredError (new EmDeferredErrUnlockedChunk (address, size, forRead));
+ break;
+
+ case Errors::kUnknownAccess:
+ case Errors::kLowStackAccess:
+ EmAssert (false);
+ MetaMemory::GetWhatHappened (address, size, forRead);
+ }
+}