aboutsummaryrefslogtreecommitdiff
path: root/SrcShared/Hardware
diff options
context:
space:
mode:
Diffstat (limited to 'SrcShared/Hardware')
-rw-r--r--SrcShared/Hardware/EmBankDRAM.cpp686
-rw-r--r--SrcShared/Hardware/EmBankDRAM.h49
-rw-r--r--SrcShared/Hardware/EmBankDummy.cpp326
-rw-r--r--SrcShared/Hardware/EmBankDummy.h47
-rw-r--r--SrcShared/Hardware/EmBankMapped.cpp723
-rw-r--r--SrcShared/Hardware/EmBankMapped.h55
-rw-r--r--SrcShared/Hardware/EmBankROM.cpp1617
-rw-r--r--SrcShared/Hardware/EmBankROM.h81
-rw-r--r--SrcShared/Hardware/EmBankRegs.cpp694
-rw-r--r--SrcShared/Hardware/EmBankRegs.h56
-rw-r--r--SrcShared/Hardware/EmBankSRAM.cpp640
-rw-r--r--SrcShared/Hardware/EmBankSRAM.h58
-rw-r--r--SrcShared/Hardware/EmCPU.cpp68
-rw-r--r--SrcShared/Hardware/EmCPU.h69
-rw-r--r--SrcShared/Hardware/EmCPU68K.cpp1849
-rw-r--r--SrcShared/Hardware/EmCPU68K.h334
-rw-r--r--SrcShared/Hardware/EmCPUARM.cpp398
-rw-r--r--SrcShared/Hardware/EmCPUARM.h731
-rw-r--r--SrcShared/Hardware/EmHAL.cpp939
-rw-r--r--SrcShared/Hardware/EmHAL.h164
-rw-r--r--SrcShared/Hardware/EmMemory.cpp1342
-rw-r--r--SrcShared/Hardware/EmMemory.h457
-rw-r--r--SrcShared/Hardware/EmRegs.cpp499
-rw-r--r--SrcShared/Hardware/EmRegs.h77
-rw-r--r--SrcShared/Hardware/EmRegs328.cpp2803
-rw-r--r--SrcShared/Hardware/EmRegs328.h146
-rw-r--r--SrcShared/Hardware/EmRegs328PalmIII.h21
-rw-r--r--SrcShared/Hardware/EmRegs328PalmPilot.cpp82
-rw-r--r--SrcShared/Hardware/EmRegs328PalmPilot.h30
-rw-r--r--SrcShared/Hardware/EmRegs328PalmVII.h21
-rw-r--r--SrcShared/Hardware/EmRegs328Pilot.h21
-rw-r--r--SrcShared/Hardware/EmRegs328Prv.h45
-rw-r--r--SrcShared/Hardware/EmRegs328Symbol1700.cpp121
-rw-r--r--SrcShared/Hardware/EmRegs328Symbol1700.h26
-rw-r--r--SrcShared/Hardware/EmRegsASICSymbol1700.cpp168
-rw-r--r--SrcShared/Hardware/EmRegsASICSymbol1700.h44
-rw-r--r--SrcShared/Hardware/EmRegsEZ.cpp2655
-rw-r--r--SrcShared/Hardware/EmRegsEZ.h143
-rw-r--r--SrcShared/Hardware/EmRegsEZPalmIIIc.cpp222
-rw-r--r--SrcShared/Hardware/EmRegsEZPalmIIIc.h48
-rw-r--r--SrcShared/Hardware/EmRegsEZPalmIIIe.h21
-rw-r--r--SrcShared/Hardware/EmRegsEZPalmIIIx.h21
-rw-r--r--SrcShared/Hardware/EmRegsEZPalmM100.cpp247
-rw-r--r--SrcShared/Hardware/EmRegsEZPalmM100.h41
-rw-r--r--SrcShared/Hardware/EmRegsEZPalmV.cpp179
-rw-r--r--SrcShared/Hardware/EmRegsEZPalmV.h42
-rw-r--r--SrcShared/Hardware/EmRegsEZPalmVII.cpp41
-rw-r--r--SrcShared/Hardware/EmRegsEZPalmVII.h26
-rw-r--r--SrcShared/Hardware/EmRegsEZPalmVIIx.cpp192
-rw-r--r--SrcShared/Hardware/EmRegsEZPalmVIIx.h41
-rw-r--r--SrcShared/Hardware/EmRegsEZPalmVx.h21
-rw-r--r--SrcShared/Hardware/EmRegsEZPrv.h45
-rw-r--r--SrcShared/Hardware/EmRegsEZTRGpro.cpp251
-rw-r--r--SrcShared/Hardware/EmRegsEZTRGpro.h76
-rw-r--r--SrcShared/Hardware/EmRegsEZTemp.cpp18
-rw-r--r--SrcShared/Hardware/EmRegsEZTemp.h18
-rw-r--r--SrcShared/Hardware/EmRegsEZVisor.cpp243
-rw-r--r--SrcShared/Hardware/EmRegsEZVisor.h131
-rw-r--r--SrcShared/Hardware/EmRegsFrameBuffer.cpp241
-rw-r--r--SrcShared/Hardware/EmRegsFrameBuffer.h52
-rw-r--r--SrcShared/Hardware/EmRegsMediaQ11xx.cpp4791
-rw-r--r--SrcShared/Hardware/EmRegsMediaQ11xx.h351
-rw-r--r--SrcShared/Hardware/EmRegsPLDPalmVIIEZ.cpp210
-rw-r--r--SrcShared/Hardware/EmRegsPLDPalmVIIEZ.h51
-rw-r--r--SrcShared/Hardware/EmRegsPrv.h37
-rw-r--r--SrcShared/Hardware/EmRegsSED1375.cpp506
-rw-r--r--SrcShared/Hardware/EmRegsSED1375.h70
-rw-r--r--SrcShared/Hardware/EmRegsSED1376.cpp860
-rw-r--r--SrcShared/Hardware/EmRegsSED1376.h106
-rw-r--r--SrcShared/Hardware/EmRegsSZ.cpp17
-rw-r--r--SrcShared/Hardware/EmRegsSZ.h18
-rw-r--r--SrcShared/Hardware/EmRegsSZPrv.h19
-rw-r--r--SrcShared/Hardware/EmRegsSZTemp.cpp17
-rw-r--r--SrcShared/Hardware/EmRegsSZTemp.h20
-rw-r--r--SrcShared/Hardware/EmRegsUSBPhilipsPDIUSBD12.cpp154
-rw-r--r--SrcShared/Hardware/EmRegsUSBPhilipsPDIUSBD12.h42
-rw-r--r--SrcShared/Hardware/EmRegsUSBVisor.cpp164
-rw-r--r--SrcShared/Hardware/EmRegsUSBVisor.h44
-rw-r--r--SrcShared/Hardware/EmRegsVZ.cpp3116
-rw-r--r--SrcShared/Hardware/EmRegsVZ.h145
-rw-r--r--SrcShared/Hardware/EmRegsVZHandEra330.cpp608
-rw-r--r--SrcShared/Hardware/EmRegsVZHandEra330.h142
-rw-r--r--SrcShared/Hardware/EmRegsVZPalmM500.cpp259
-rw-r--r--SrcShared/Hardware/EmRegsVZPalmM500.h44
-rw-r--r--SrcShared/Hardware/EmRegsVZPalmM505.cpp151
-rw-r--r--SrcShared/Hardware/EmRegsVZPalmM505.h36
-rw-r--r--SrcShared/Hardware/EmRegsVZPrv.h45
-rw-r--r--SrcShared/Hardware/EmRegsVZTemp.cpp848
-rw-r--r--SrcShared/Hardware/EmRegsVZTemp.h130
-rw-r--r--SrcShared/Hardware/EmRegsVZVisorEdge.cpp166
-rw-r--r--SrcShared/Hardware/EmRegsVZVisorEdge.h30
-rw-r--r--SrcShared/Hardware/EmRegsVZVisorPlatinum.cpp262
-rw-r--r--SrcShared/Hardware/EmRegsVZVisorPlatinum.h43
-rw-r--r--SrcShared/Hardware/EmRegsVZVisorPrism.cpp393
-rw-r--r--SrcShared/Hardware/EmRegsVZVisorPrism.h37
-rw-r--r--SrcShared/Hardware/EmSPISlave.cpp51
-rw-r--r--SrcShared/Hardware/EmSPISlave.h28
-rw-r--r--SrcShared/Hardware/EmSPISlaveADS784x.cpp428
-rw-r--r--SrcShared/Hardware/EmSPISlaveADS784x.h97
-rw-r--r--SrcShared/Hardware/EmUAEGlue.cpp166
-rw-r--r--SrcShared/Hardware/EmUAEGlue.h17
-rw-r--r--SrcShared/Hardware/EmUARTDragonball.cpp936
-rw-r--r--SrcShared/Hardware/EmUARTDragonball.h149
-rw-r--r--SrcShared/Hardware/TRG/EmHandEra330Defs.h40
-rw-r--r--SrcShared/Hardware/TRG/EmHandEraCFBus.h28
-rw-r--r--SrcShared/Hardware/TRG/EmHandEraSDBus.h22
-rw-r--r--SrcShared/Hardware/TRG/EmRegs330CPLD.cpp263
-rw-r--r--SrcShared/Hardware/TRG/EmRegs330CPLD.h144
-rw-r--r--SrcShared/Hardware/TRG/EmSPISlave330Current.cpp189
-rw-r--r--SrcShared/Hardware/TRG/EmSPISlave330Current.h51
-rw-r--r--SrcShared/Hardware/TRG/EmTRG.cpp57
-rw-r--r--SrcShared/Hardware/TRG/EmTRG.h23
-rw-r--r--SrcShared/Hardware/TRG/EmTRGATA.cpp471
-rw-r--r--SrcShared/Hardware/TRG/EmTRGATA.h63
-rw-r--r--SrcShared/Hardware/TRG/EmTRGCF.cpp305
-rw-r--r--SrcShared/Hardware/TRG/EmTRGCF.h58
-rw-r--r--SrcShared/Hardware/TRG/EmTRGCFDefs.h187
-rw-r--r--SrcShared/Hardware/TRG/EmTRGCFIO.cpp236
-rw-r--r--SrcShared/Hardware/TRG/EmTRGCFIO.h90
-rw-r--r--SrcShared/Hardware/TRG/EmTRGCFMem.cpp349
-rw-r--r--SrcShared/Hardware/TRG/EmTRGCFMem.h66
-rw-r--r--SrcShared/Hardware/TRG/EmTRGDiskIO.cpp174
-rw-r--r--SrcShared/Hardware/TRG/EmTRGDiskIO.h53
-rw-r--r--SrcShared/Hardware/TRG/EmTRGDiskType.cpp511
-rw-r--r--SrcShared/Hardware/TRG/EmTRGDiskType.h65
-rw-r--r--SrcShared/Hardware/TRG/EmTRGSD.cpp321
-rw-r--r--SrcShared/Hardware/TRG/EmTRGSD.h64
127 files changed, 40136 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);
+ }
+}
diff --git a/SrcShared/Hardware/EmBankDRAM.h b/SrcShared/Hardware/EmBankDRAM.h
new file mode 100644
index 0000000..c247649
--- /dev/null
+++ b/SrcShared/Hardware/EmBankDRAM.h
@@ -0,0 +1,49 @@
+/* -*- 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.
+\* ===================================================================== */
+
+#ifndef EmBankDRAM_h
+#define EmBankDRAM_h
+
+
+class SessionFile;
+
+class EmBankDRAM
+{
+ public:
+ static void Initialize (void);
+ static void Reset (Bool hardwareReset);
+ static void Save (SessionFile&);
+ static void Load (SessionFile&);
+ static void Dispose (void);
+
+ static void SetBankHandlers (void);
+
+ static uint32 GetLong (emuptr address);
+ static uint32 GetWord (emuptr address);
+ static uint32 GetByte (emuptr address);
+ static void SetLong (emuptr address, uint32 value);
+ static void SetWord (emuptr address, uint32 value);
+ static void SetByte (emuptr address, uint32 value);
+ static int ValidAddress (emuptr address, uint32 size);
+ static uint8* GetRealAddress (emuptr address);
+ static uint8* GetMetaAddress (emuptr address);
+ static void AddOpcodeCycles (void);
+
+ private:
+ static void AddressError (emuptr address, long size, Bool forRead);
+ static void InvalidAccess (emuptr address, long size, Bool forRead);
+ static void ProbableCause (emuptr address, long size, Bool forRead);
+};
+
+
+#endif /* EmBankDRAM_h */
diff --git a/SrcShared/Hardware/EmBankDummy.cpp b/SrcShared/Hardware/EmBankDummy.cpp
new file mode 100644
index 0000000..356b542
--- /dev/null
+++ b/SrcShared/Hardware/EmBankDummy.cpp
@@ -0,0 +1,326 @@
+/* -*- 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 "EmBankDummy.h"
+
+#include "EmBankDRAM.h" // EmBankDRAM::ValidAddress
+#include "EmBankSRAM.h" // EmBankSRAM::GetMemoryStart
+#include "EmCPU68K.h" // gCPU68K
+#include "EmPalmHeap.h" // EmPalmHeap::GetHeapByPtr
+#include "EmMemory.h" // Memory::InitializeBanks
+
+
+// ===========================================================================
+// ¥ Dummy Bank Accessors
+// ===========================================================================
+// Dummy banks are non-existent blocks of memory. Dummy bank accessors do
+// not do anything.
+
+static EmAddressBank gAddressBank =
+{
+ EmBankDummy::GetLong,
+ EmBankDummy::GetWord,
+ EmBankDummy::GetByte,
+ EmBankDummy::SetLong,
+ EmBankDummy::SetWord,
+ EmBankDummy::SetByte,
+ EmBankDummy::GetRealAddress,
+ EmBankDummy::ValidAddress,
+ EmBankDummy::GetMetaAddress,
+ EmBankDummy::AddOpcodeCycles
+};
+
+
+inline Bool HackForHwrGetRAMSize (emuptr address)
+{
+// if ((address & 0xFF000000) == EmBankSRAM::GetMemoryStart ())
+ if (address == EmBankSRAM::GetMemoryStart () + gRAMBank_Size)
+ return true;
+
+ return false;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankDummy::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 EmBankDummy::Initialize (void)
+{
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankDummy::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 EmBankDummy::Reset (Bool /*hardwareReset*/)
+{
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankDummy::Save
+ *
+ * DESCRIPTION: Standard save function. Saves any sub-system state to
+ * the given session file.
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void EmBankDummy::Save (SessionFile&)
+{
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankDummy::Load
+ *
+ * DESCRIPTION: Standard load function. Loads any sub-system state
+ * from the given session file.
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void EmBankDummy::Load (SessionFile&)
+{
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankDummy::Dispose
+ *
+ * DESCRIPTION: Standard dispose function. Completely release any
+ * resources acquired or allocated in Initialize and/or
+ * Load.
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void EmBankDummy::Dispose (void)
+{
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankDummy::SetBankHandlers
+ *
+ * DESCRIPTION: Set the bank handlers UAE uses to dispatch memory
+ * access operations.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmBankDummy::SetBankHandlers (void)
+{
+ Memory::InitializeBanks (gAddressBank, 0, 0xFFFF);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankDummy::GetLong
+// ---------------------------------------------------------------------------
+
+uint32 EmBankDummy::GetLong (emuptr address)
+{
+ // Hack to keep HwrGetRAMSize working: it runs off
+ // the end of RAM while testing it.
+
+ if (HackForHwrGetRAMSize (address))
+ return 0;
+
+ InvalidAccess (address, sizeof (uint32), true);
+ return ~0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankDummy::GetWord
+// ---------------------------------------------------------------------------
+
+uint32 EmBankDummy::GetWord (emuptr address)
+{
+ // Hack to keep HwrGetRAMSize working: it runs off
+ // the end of RAM while testing it.
+
+ if (HackForHwrGetRAMSize (address))
+ return 0;
+
+ InvalidAccess (address, sizeof (uint16), true);
+ return ~0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankDummy::GetByte
+// ---------------------------------------------------------------------------
+
+uint32 EmBankDummy::GetByte (emuptr address)
+{
+ // Hack to keep HwrGetRAMSize working: it runs off
+ // the end of RAM while testing it.
+
+ if (HackForHwrGetRAMSize (address))
+ return 0;
+
+ InvalidAccess (address, sizeof (uint8), true);
+ return ~0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankDummy::SetLong
+// ---------------------------------------------------------------------------
+
+void EmBankDummy::SetLong (emuptr address, uint32)
+{
+ // Hack to keep HwrGetRAMSize working: it runs off
+ // the end of RAM while testing it.
+
+ if (HackForHwrGetRAMSize (address))
+ return;
+
+ InvalidAccess (address, sizeof (uint32), true);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankDummy::SetWord
+// ---------------------------------------------------------------------------
+
+void EmBankDummy::SetWord (emuptr address, uint32)
+{
+ // Hack to keep HwrGetRAMSize working: it runs off
+ // the end of RAM while testing it.
+
+ if (HackForHwrGetRAMSize (address))
+ return;
+
+ InvalidAccess (address, sizeof (uint16), true);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankDummy::SetByte
+// ---------------------------------------------------------------------------
+
+void EmBankDummy::SetByte (emuptr address, uint32)
+{
+ // Hack to keep HwrGetRAMSize working: it runs off
+ // the end of RAM while testing it.
+
+ if (HackForHwrGetRAMSize (address))
+ return;
+
+ InvalidAccess (address, sizeof (uint8), true);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankDummy::ValidAddress
+// ---------------------------------------------------------------------------
+
+int EmBankDummy::ValidAddress (emuptr, uint32)
+{
+ int result = false;
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankDummy::GetRealAddress
+// ---------------------------------------------------------------------------
+
+uint8* EmBankDummy::GetRealAddress (emuptr address)
+{
+ return (uint8*) address;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankDummy::GetMetaAddress
+// ---------------------------------------------------------------------------
+
+uint8* EmBankDummy::GetMetaAddress (emuptr address)
+{
+ UNUSED_PARAM(address)
+
+ static uint8 dummyBits[4] = {0, 0, 0, 0};
+
+ return dummyBits;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankDummy::AddOpcodeCycles
+// ---------------------------------------------------------------------------
+
+void EmBankDummy::AddOpcodeCycles (void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankDummy::InvalidAccess
+// ---------------------------------------------------------------------------
+
+void EmBankDummy::InvalidAccess (emuptr address, long size, Bool forRead)
+{
+ if (CEnableFullAccess::AccessOK ())
+ return;
+
+ EmAssert (gCPU68K);
+ gCPU68K->BusError (address, size, forRead);
+}
diff --git a/SrcShared/Hardware/EmBankDummy.h b/SrcShared/Hardware/EmBankDummy.h
new file mode 100644
index 0000000..a6ed0de
--- /dev/null
+++ b/SrcShared/Hardware/EmBankDummy.h
@@ -0,0 +1,47 @@
+/* -*- 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.
+\* ===================================================================== */
+
+#ifndef EmBankDummy_h
+#define EmBankDummy_h
+
+
+class SessionFile;
+
+class EmBankDummy
+{
+ public:
+ static void Initialize (void);
+ static void Reset (Bool hardwareReset);
+ static void Save (SessionFile&);
+ static void Load (SessionFile&);
+ static void Dispose (void);
+
+ static void SetBankHandlers (void);
+
+ static uint32 GetLong (emuptr address);
+ static uint32 GetWord (emuptr address);
+ static uint32 GetByte (emuptr address);
+ static void SetLong (emuptr address, uint32 value);
+ static void SetWord (emuptr address, uint32 value);
+ static void SetByte (emuptr address, uint32 value);
+ static int ValidAddress (emuptr address, uint32 size);
+ static uint8* GetRealAddress (emuptr address);
+ static uint8* GetMetaAddress (emuptr address);
+ static void AddOpcodeCycles (void);
+
+ private:
+ static void InvalidAccess (emuptr address, long size, Bool forRead);
+};
+
+
+#endif /* EmBankDummy_h */
diff --git a/SrcShared/Hardware/EmBankMapped.cpp b/SrcShared/Hardware/EmBankMapped.cpp
new file mode 100644
index 0000000..8ae284a
--- /dev/null
+++ b/SrcShared/Hardware/EmBankMapped.cpp
@@ -0,0 +1,723 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmBankMapped.h"
+
+#include "EmCPU68K.h" // gCPU68K
+#include "EmMemory.h" // Memory::InitializeBanks
+#include "Profiling.h" // WAITSTATES_DUMMYBANK
+
+#include <vector>
+
+
+// ===========================================================================
+// ¥ Dummy Bank Accessors
+// ===========================================================================
+// Dummy banks are non-existent blocks of memory. Dummy bank accessors do
+// not do anything.
+
+static EmAddressBank gAddressBank =
+{
+ EmBankMapped::GetLong,
+ EmBankMapped::GetWord,
+ EmBankMapped::GetByte,
+ EmBankMapped::SetLong,
+ EmBankMapped::SetWord,
+ EmBankMapped::SetByte,
+ EmBankMapped::GetRealAddress,
+ EmBankMapped::ValidAddress,
+ EmBankMapped::GetMetaAddress,
+ EmBankMapped::AddOpcodeCycles
+};
+
+struct MapRange
+{
+ Bool Contains (const void* addr)
+ {
+ const char* begin = (const char*) this->realAddress;
+ const char* end = begin + this->size;
+
+ return ((addr >= begin) && (addr < end));
+ }
+
+ Bool Contains (emuptr addr)
+ {
+ emuptr begin = this->mappedAddress;
+ emuptr end = begin + this->size;
+
+ return ((addr >= begin) && (addr < end));
+ }
+
+ const void* realAddress; // Address in host's space
+ emuptr mappedAddress; // Address that emulated code sees
+ uint32 size;
+};
+typedef vector<MapRange> MapRangeList;
+
+static MapRangeList gMappedRanges;
+static MapRangeList::iterator gLastIter;
+
+// Map in blocks starting at this address. I used to have it way out of
+// the way at 0x60000000. However, there's a check in SysGetAppInfo to
+// make sure that certain addresses are less than 0x20000000. So set
+// kMemoryStart lower than that.
+//
+// OK...Let's try again. I had changed this to manage 0x18000000 to
+// 0x1FFFFFFF. However, the SED 1375 is mapped to 0x1F000000. So let's
+// make sure we stay out of that range, too.
+//
+// Urm...TRG is mapping some stuff into 0x18000000. Now we have to stay
+// out of its way, too.
+
+const emuptr kMemoryStart = 0x13000000;
+const emuptr kMemoryFinish = 0x18000000;
+const int32 kMemorySize = kMemoryFinish - kMemoryStart; // 80MB
+
+static MapRangeList::iterator PrvGetMappingInfo (const void* addr);
+static MapRangeList::iterator PrvGetMappingInfo (emuptr addr);
+static emuptr PrvEnsureAligned (emuptr candidate, const void* addr);
+static void PrvInvalidateCache (void);
+static void PrvCheckRanges (void);
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankMapped::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 EmBankMapped::Initialize (void)
+{
+ gMappedRanges.clear ();
+ ::PrvInvalidateCache ();
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankMapped::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 EmBankMapped::Reset (Bool /*hardwareReset*/)
+{
+ // Note: I used to clear out the mapped ranges in this function.
+ // However, this didn't work out too well. While manually resetting
+ // the device (as occurs at the end of a debugging session), there
+ // would be several StMemoryMapper objects instantiated. After the
+ // reset process, these StMemoryMappers would try to destruct
+ // themselves, calling EmBankMapped::UnmapPhysicalMemory in the
+ // process. But since the mapped ranges had been cleared, that
+ // function would throw an assert. So....I can't think of a reason
+ // for clearing out the ranges en masse, so let's no do that anymore.
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankMapped::Save
+ *
+ * DESCRIPTION: Standard save function. Saves any sub-system state to
+ * the given session file.
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void EmBankMapped::Save (SessionFile&)
+{
+ // The only state we have to save is in gMappedRanges. We shouldn't
+ // have to actually save this because there shouldn't be anything in
+ // there at the moment when we save files. We map in memory ranges
+ // at the following times:
+ //
+ // * Calling system functions
+ // * Loading .prc, etc., files
+ // * Mapping in environment strings
+ //
+ // The first two should not be in "effect" at the time we save a file.
+ // The last one we'll leave up to the HostControl system to re-establish.
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankMapped::Load
+ *
+ * DESCRIPTION: Standard load function. Loads any sub-system state
+ * from the given session file.
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void EmBankMapped::Load (SessionFile&)
+{
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankMapped::Dispose
+ *
+ * DESCRIPTION: Standard dispose function. Completely release any
+ * resources acquired or allocated in Initialize and/or
+ * Load.
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void EmBankMapped::Dispose (void)
+{
+ gMappedRanges.clear ();
+ ::PrvInvalidateCache ();
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankMapped::SetBankHandlers
+ *
+ * DESCRIPTION: Set the bank handlers UAE uses to dispatch memory
+ * access operations.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmBankMapped::SetBankHandlers (void)
+{
+ Memory::InitializeBanks (gAddressBank, EmMemBankIndex (kMemoryStart), kMemorySize >> 16);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankMapped::GetLong
+// ---------------------------------------------------------------------------
+
+uint32 EmBankMapped::GetLong (emuptr address)
+{
+ if (CHECK_FOR_ADDRESS_ERROR && (address & 1) != 0)
+ {
+ AddressError (address, sizeof (uint32), true);
+ }
+
+#if HAS_PROFILING
+ CYCLE_GETLONG (WAITSTATES_DUMMYBANK);
+#endif
+
+ uint8* p = GetRealAddress (address);
+
+ if (p == NULL)
+ {
+ return ~0;
+ }
+
+ return (((uint32) p[0]) << 24) | (((uint32) p[1]) << 16) | (((uint32) p[2]) << 8) | p[3];
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankMapped::GetWord
+// ---------------------------------------------------------------------------
+
+uint32 EmBankMapped::GetWord (emuptr address)
+{
+ if (CHECK_FOR_ADDRESS_ERROR && (address & 1) != 0)
+ {
+ AddressError (address, sizeof (uint16), true);
+ }
+
+#if HAS_PROFILING
+ CYCLE_GETWORD (WAITSTATES_DUMMYBANK);
+#endif
+
+ uint8* p = GetRealAddress (address);
+
+ if (p == NULL)
+ {
+ return ~0;
+ }
+
+ return (((uint32) p[0]) << 8) | p[1];
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankMapped::GetByte
+// ---------------------------------------------------------------------------
+
+uint32 EmBankMapped::GetByte (emuptr address)
+{
+#if HAS_PROFILING
+ CYCLE_GETBYTE (WAITSTATES_DUMMYBANK);
+#endif
+
+ uint8* p = GetRealAddress (address);
+
+ if (p == NULL)
+ {
+ return ~0;
+ }
+
+ return p[0];
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankMapped::SetLong
+// ---------------------------------------------------------------------------
+
+void EmBankMapped::SetLong (emuptr address, uint32 value)
+{
+ if (CHECK_FOR_ADDRESS_ERROR && (address & 1) != 0)
+ {
+ AddressError (address, sizeof (uint32), false);
+ }
+
+#if HAS_PROFILING
+ CYCLE_PUTLONG (WAITSTATES_DUMMYBANK);
+#endif
+
+ uint8* p = GetRealAddress (address);
+
+ if (p == NULL)
+ {
+ return;
+ }
+
+ p[0] = (uint8) (value >> 24);
+ p[1] = (uint8) (value >> 16);
+ p[2] = (uint8) (value >> 8);
+ p[3] = (uint8) (value >> 0);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankMapped::SetWord
+// ---------------------------------------------------------------------------
+
+void EmBankMapped::SetWord (emuptr address, uint32 value)
+{
+ if (CHECK_FOR_ADDRESS_ERROR && (address & 1) != 0)
+ {
+ AddressError (address, sizeof (uint16), false);
+ }
+
+#if HAS_PROFILING
+ CYCLE_PUTWORD (WAITSTATES_DUMMYBANK);
+#endif
+
+ uint8* p = GetRealAddress (address);
+
+ if (p == NULL)
+ {
+ return;
+ }
+
+ p[0] = (uint8) (value >> 8);
+ p[1] = (uint8) (value >> 0);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankMapped::SetByte
+// ---------------------------------------------------------------------------
+
+void EmBankMapped::SetByte (emuptr address, uint32 value)
+{
+#if HAS_PROFILING
+ CYCLE_PUTBYTE (WAITSTATES_DUMMYBANK);
+#endif
+
+ uint8* p = GetRealAddress (address);
+
+ if (p == NULL)
+ {
+ return;
+ }
+
+ p[0] = (uint8) (value >> 0);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankMapped::ValidAddress
+// ---------------------------------------------------------------------------
+
+int EmBankMapped::ValidAddress (emuptr address, uint32)
+{
+ uint8* realAddress = GetRealAddress (address);
+ int result = realAddress != NULL;
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankMapped::GetRealAddress
+// ---------------------------------------------------------------------------
+
+uint8* EmBankMapped::GetRealAddress (emuptr address)
+{
+ MapRangeList::iterator iter = ::PrvGetMappingInfo (address);
+
+ if (iter == gMappedRanges.end ())
+ return NULL;
+
+ return ((uint8*) iter->realAddress) + (address - iter->mappedAddress);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankMapped::GetMetaAddress
+// ---------------------------------------------------------------------------
+
+uint8* EmBankMapped::GetMetaAddress (emuptr address)
+{
+ UNUSED_PARAM(address)
+
+ static uint8 dummyBits[4] = {0, 0, 0, 0};
+
+ return dummyBits;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankMapped::GetEmulatedAddress
+// ---------------------------------------------------------------------------
+
+emuptr EmBankMapped::GetEmulatedAddress (const void* address)
+{
+ MapRangeList::iterator iter = ::PrvGetMappingInfo (address);
+
+ if (iter == gMappedRanges.end ())
+ {
+ EmAssert (false);
+ return EmMemNULL;
+ }
+
+ return iter->mappedAddress + ((char*) address - (char*) iter->realAddress);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankMapped::AddOpcodeCycles
+// ---------------------------------------------------------------------------
+
+void EmBankMapped::AddOpcodeCycles (void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankMapped::AddressError
+// ---------------------------------------------------------------------------
+
+void EmBankMapped::AddressError (emuptr address, long size, Bool forRead)
+{
+ EmAssert (gCPU68K);
+ gCPU68K->AddressError (address, size, forRead);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankMapped::InvalidAccess
+// ---------------------------------------------------------------------------
+
+void EmBankMapped::InvalidAccess (emuptr address, long size, Bool forRead)
+{
+ EmAssert (gCPU68K);
+ gCPU68K->BusError (address, size, forRead);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankMapped::MapPhysicalMemory
+// ---------------------------------------------------------------------------
+// Maps a range of physical memory to appear at the same location of the
+// emulated Palm OS's virtual memory.
+
+void EmBankMapped::MapPhysicalMemory (const void* addr, uint32 size)
+{
+ if (addr == NULL)
+ return;
+
+ emuptr candidate = ::PrvEnsureAligned (kMemoryStart, addr);
+
+ // If the list is empty, add the item
+
+ if (gMappedRanges.size () == 0)
+ {
+ MapRange range;
+
+ range.realAddress = addr;
+ range.mappedAddress = candidate;
+ range.size = size;
+
+ gLastIter = gMappedRanges.insert (gMappedRanges.begin (), range);
+ ::PrvCheckRanges ();
+
+// ::PrvInvalidateCache ();
+
+ return;
+ }
+
+ // Find an available space for the range.
+
+ MapRangeList::iterator iter = gMappedRanges.begin ();
+
+ while (iter != gMappedRanges.end ())
+ {
+ // If there's room in front of the current block...
+
+ if (iter->mappedAddress >= candidate + size)
+ {
+ // ...insert a map record in front of the current block.
+
+ MapRange range;
+
+ range.realAddress = addr;
+ range.mappedAddress = candidate;
+ range.size = size;
+
+ gLastIter = gMappedRanges.insert (iter, range);
+ ::PrvCheckRanges ();
+
+// ::PrvInvalidateCache ();
+
+ return;
+ }
+
+ // No room at the inn...move onto the next block.
+
+ candidate = ::PrvEnsureAligned (iter->mappedAddress + iter->size, addr);
+ ++iter;
+ }
+
+ // Couldn't find room at the beginning or the middle of the list. Add to the end.
+
+ MapRangeList::iterator last = gMappedRanges.end ();
+ iter = last - 1;
+
+ MapRange range;
+
+ range.realAddress = addr;
+ range.mappedAddress = ::PrvEnsureAligned (iter->mappedAddress + iter->size, addr);
+ range.size = size;
+
+ gLastIter = gMappedRanges.insert (last, range);
+ ::PrvCheckRanges ();
+
+// ::PrvInvalidateCache ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankMapped::UnmapPhysicalMemory
+// ---------------------------------------------------------------------------
+// Unmaps a range of physical memory from appearing at the same location of
+// the emulated Palm OS's virtual memory.
+
+void EmBankMapped::UnmapPhysicalMemory (const void* addr)
+{
+ if (addr == NULL)
+ return;
+
+ MapRangeList::iterator iter = ::PrvGetMappingInfo (addr);
+
+ // Take out this assert. Without it, it's possible to unmap ranges
+ // of memory that we may not have actually mapped in. Being able to
+ // do that makes things like Reset and Dispose methods easier to write.
+// EmAssert (iter != gMappedRanges.end ());
+
+ if (iter != gMappedRanges.end ())
+ {
+ gMappedRanges.erase (iter);
+ ::PrvCheckRanges ();
+
+ ::PrvInvalidateCache ();
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankMapped::GetMappingInfo
+// ---------------------------------------------------------------------------
+
+void EmBankMapped::GetMappingInfo (emuptr addr, void** start, uint32* len)
+{
+ MapRangeList::iterator iter = ::PrvGetMappingInfo (addr);
+
+ if (iter != gMappedRanges.end ())
+ {
+ if (start)
+ *start = (void*) iter->realAddress;
+
+ if (len)
+ *len = iter->size;
+ }
+ else
+ {
+ if (start)
+ *start = NULL;
+
+ if (len)
+ *len = 0;
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ PrvGetMappingInfo
+// ---------------------------------------------------------------------------
+
+MapRangeList::iterator PrvGetMappingInfo (const void* addr)
+{
+ if (gLastIter != gMappedRanges.end () && gLastIter->Contains (addr))
+ return gLastIter;
+
+ MapRangeList::iterator iter = gMappedRanges.begin ();
+ while (iter != gMappedRanges.end ())
+ {
+ if (iter->Contains (addr))
+ break;
+
+ ++iter;
+ }
+
+ gLastIter = iter;
+
+ return iter;
+}
+
+
+MapRangeList::iterator PrvGetMappingInfo (emuptr addr)
+{
+ if (gLastIter != gMappedRanges.end () && gLastIter->Contains (addr))
+ return gLastIter;
+
+ MapRangeList::iterator iter = gMappedRanges.begin ();
+ while (iter != gMappedRanges.end ())
+ {
+ if (iter->Contains (addr))
+ break;
+
+ ++iter;
+ }
+
+ gLastIter = iter;
+
+ return iter;
+}
+
+
+emuptr PrvEnsureAligned (emuptr candidate, const void* addr)
+{
+ // Make sure that "candidate" -- which is the candidate
+ // mapped address -- maintains the same alignment as
+ // the incoming address.
+
+ while ((candidate & 0x03) != ((uint32) addr & 0x03))
+ ++candidate;
+
+ return candidate;
+}
+
+void PrvInvalidateCache (void)
+{
+ gLastIter = gMappedRanges.end ();
+}
+
+void PrvCheckRanges (void)
+{
+#if _DEBUG
+ /*
+ Check for overlaps. We iterate over the container with
+ two iterators: outerIter and innerIter. These two iterators
+ will allow us to compare all possible combinations of
+ elements in the container.
+
+ When checking for overlaps, there are six cases to consider:
+
+ *-----------* Segment A
+
+ *---* Possible segment B's.
+ *----------*
+ *---------------------------*
+ *---*
+ *---------------*
+ *---*
+
+ An overlap occurs if any part of segment B crosses segment A.
+ From the drawing, we can see that the first and last possible
+ segments B's are OK; the others overlap with segment A in
+ some fashion. Thus, Segment B is OK if it's end is less than
+ Segment A's start, or its start is greater than segment A's end.
+ */
+
+ MapRangeList::iterator outerIter = gMappedRanges.begin ();
+ while (outerIter != gMappedRanges.end ())
+ {
+ MapRangeList::iterator innerIter = outerIter + 1;
+ while (innerIter != gMappedRanges.end ())
+ {
+ char* outerStart = (char*) outerIter->realAddress;
+ char* innerStart = (char*) innerIter->realAddress;
+
+ char* outerEnd = outerStart + outerIter->size;
+ char* innerEnd = innerStart + innerIter->size;
+
+ if (innerEnd > outerStart && innerStart < outerEnd)
+ {
+ EmAssert (false);
+ }
+
+ ++innerIter;
+ }
+
+ ++outerIter;
+ }
+#endif
+}
+
diff --git a/SrcShared/Hardware/EmBankMapped.h b/SrcShared/Hardware/EmBankMapped.h
new file mode 100644
index 0000000..033c749
--- /dev/null
+++ b/SrcShared/Hardware/EmBankMapped.h
@@ -0,0 +1,55 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmBankMapped_h
+#define EmBankMapped_h
+
+
+class SessionFile;
+
+class EmBankMapped
+{
+ public:
+ static void Initialize (void);
+ static void Reset (Bool hardwareReset);
+ static void Save (SessionFile&);
+ static void Load (SessionFile&);
+ static void Dispose (void);
+
+ static void SetBankHandlers (void);
+
+ static uint32 GetLong (emuptr address);
+ static uint32 GetWord (emuptr address);
+ static uint32 GetByte (emuptr address);
+ static void SetLong (emuptr address, uint32 value);
+ static void SetWord (emuptr address, uint32 value);
+ static void SetByte (emuptr address, uint32 value);
+ static int ValidAddress (emuptr address, uint32 size);
+ static uint8* GetRealAddress (emuptr address);
+ static uint8* GetMetaAddress (emuptr address);
+ static emuptr GetEmulatedAddress (const void* address);
+ static void AddOpcodeCycles (void);
+
+ static void MapPhysicalMemory (const void*, uint32);
+ static void UnmapPhysicalMemory (const void*);
+
+ static void GetMappingInfo (emuptr addr, void** start, uint32* len);
+
+
+ private:
+ static void AddressError (emuptr address, long size, Bool forRead);
+ static void InvalidAccess (emuptr address, long size, Bool forRead);
+};
+
+
+#endif /* EmBankMapped_h */
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;
+}
diff --git a/SrcShared/Hardware/EmBankROM.h b/SrcShared/Hardware/EmBankROM.h
new file mode 100644
index 0000000..f29572b
--- /dev/null
+++ b/SrcShared/Hardware/EmBankROM.h
@@ -0,0 +1,81 @@
+/* -*- 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.
+\* ===================================================================== */
+
+#ifndef EmBankROM_h
+#define EmBankROM_h
+
+class EmStream;
+class SessionFile;
+
+const emuptr kDefaultROMMemoryStart = 0x10C00000;
+
+class EmBankROM
+{
+ public:
+ static void Initialize (EmStream& hROM);
+ static void Reset (Bool hardwareReset);
+ static void Save (SessionFile&);
+ static void Load (SessionFile&);
+ static void Dispose (void);
+
+ static void SetBankHandlers (void);
+
+ static uint32 GetLong (emuptr address);
+ static uint32 GetWord (emuptr address);
+ static uint32 GetByte (emuptr address);
+ static void SetLong (emuptr address, uint32 value);
+ static void SetWord (emuptr address, uint32 value);
+ static void SetByte (emuptr address, uint32 value);
+ static int ValidAddress (emuptr address, uint32 size);
+ static uint8* GetRealAddress (emuptr address);
+ static uint8* GetMetaAddress (emuptr address);
+ static void AddOpcodeCycles (void);
+
+ static emuptr GetMemoryStart (void) { return gROMMemoryStart; }
+
+ private:
+ static void AddressError (emuptr address, long size, Bool forRead);
+ static void InvalidAccess (emuptr address, long size, Bool forRead);
+ static void LoadROM (EmStream& hROM);
+
+ static emuptr gROMMemoryStart;
+};
+
+
+class EmBankFlash
+{
+ public:
+ static void Initialize (void);
+ static void Reset (Bool hardwareReset);
+ static void Save (SessionFile&);
+ static void Load (SessionFile&);
+ static void Dispose (void);
+
+ static void SetBankHandlers (void);
+
+ static uint32 GetLong (emuptr address);
+ static uint32 GetWord (emuptr address);
+ static uint32 GetByte (emuptr address);
+ static void SetLong (emuptr address, uint32 value);
+ static void SetWord (emuptr address, uint32 value);
+ static void SetByte (emuptr address, uint32 value);
+ static int ValidAddress (emuptr address, uint32 size);
+ static uint8* GetRealAddress (emuptr address);
+ static uint8* GetMetaAddress (emuptr address);
+ static void AddOpcodeCycles (void);
+
+ static emuptr GetMemoryStart (void) { return kDefaultROMMemoryStart; }
+};
+
+
+#endif /* EmBankROM_h */
diff --git a/SrcShared/Hardware/EmBankRegs.cpp b/SrcShared/Hardware/EmBankRegs.cpp
new file mode 100644
index 0000000..c03deb3
--- /dev/null
+++ b/SrcShared/Hardware/EmBankRegs.cpp
@@ -0,0 +1,694 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmBankRegs.h"
+
+#include "DebugMgr.h" // Debug::CheckStepSpy
+#include "EmCPU.h" // GetPC
+#include "EmCPU68K.h" // gCPU68K
+#include "EmMemory.h" // gMemAccessFlags, EmMemory::IsPCInRAM
+#include "EmSession.h" // GetDevice, ScheduleDeferredError
+#include "ErrorHandling.h" // Errors::ReportErrHardwareRegisters
+#include "MetaMemory.h" // MetaMemory::InRAMOSComponent
+#include "Profiling.h" // WAITSTATES_PLD
+
+
+/*
+ When emulating memory, UAE divides up the 4GB address space into
+ 65,536 banks, each of which is 64K long. For more details, see the
+ comments in EmMemory.cpp.
+
+ For our purposes, we sometimes need to divide up each 64K bank in a
+ similar fashion. For instance, in order to support accesses to each
+ of the Dragonball registers, we'd like to assign a handler to each
+ byte, word, or long of memory in the bank that contains the
+ Dragonball registers.
+
+ This module supports that further subdivision. EmBankRegs is a bank
+ handler -- just like the RAM and ROM bank handlers -- in that it is
+ responsible for memory accesses to one or more 64K banks of memory.
+ It divides up each 64K bank by making use of instances of EmRegs
+ subclasses.
+
+ EmRegs subclasses are the moral equivalent of EmBanks, except on a
+ smaller scale. They are responsible for byte, word, and long memory
+ accesses to a small range of memory completely contained within a
+ 64K bank.
+
+ Many such EmRegs instances can be created and installed into the
+ EmBankRegs object. EmBankRegs stores these EmRegs in a list. When
+ in comes time for the EmBanks to register which 64K banks they are
+ responsible for, EmBankRegs iterates over all the EmRegs objects
+ registered with it, and takes responsibility for each 64K bank that
+ contains the EmRegs object memory range (an EmRegs object can be
+ queried as to the memory start and length it is responsible for).
+
+ Later, when a memory access is made to any of the 64K banks
+ EmBankRegs registered for, it again iterates over the EmRegs objects
+ installed into it, looking for one that takes responsibility for the
+ memory address being accessed. When it finds one, it passes off the
+ request to that object. Otherwise, it signals a bus error.
+*/
+
+
+static EmAddressBank gAddressBank =
+{
+ EmBankRegs::GetLong,
+ EmBankRegs::GetWord,
+ EmBankRegs::GetByte,
+ EmBankRegs::SetLong,
+ EmBankRegs::SetWord,
+ EmBankRegs::SetByte,
+ EmBankRegs::GetRealAddress,
+ EmBankRegs::ValidAddress,
+ NULL,
+ NULL
+};
+
+
+EmRegsList EmBankRegs::fgSubBanks;
+EmRegsList EmBankRegs::fgDisabledSubBanks;
+
+static EmRegs* gLastSubBank;
+static uint64 gLastStart;
+static uint32 gLastRange;
+
+static void PrvSwitchBanks (EmRegsList& fromList, EmRegsList& toList, emuptr address);
+
+#pragma mark -
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankRegs::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 EmBankRegs::Initialize (void)
+{
+ EmAssert (gSession);
+ gSession->GetDevice ().CreateRegs ();
+
+ EmRegsList::iterator iter = fgSubBanks.begin ();
+ while (iter != fgSubBanks.end ())
+ {
+ (*iter)->Initialize ();
+ ++iter;
+ }
+
+ // Install the handlers for each affected bank.
+
+ EmBankRegs::SetBankHandlers ();
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankRegs::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 EmBankRegs::Reset (Bool hardwareReset)
+{
+ EmRegsList::iterator iter = fgSubBanks.begin ();
+ while (iter != fgSubBanks.end ())
+ {
+ (*iter)->Reset (hardwareReset);
+ ++iter;
+ }
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankRegs::Save
+ *
+ * DESCRIPTION: Standard save function. Saves any sub-system state to
+ * the given session file.
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void EmBankRegs::Save (SessionFile& f)
+{
+ EmRegsList::iterator iter = fgSubBanks.begin ();
+ while (iter != fgSubBanks.end ())
+ {
+ (*iter)->Save (f);
+ ++iter;
+ }
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankRegs::Load
+ *
+ * DESCRIPTION: Standard load function. Loads any sub-system state
+ * from the given session file.
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void EmBankRegs::Load (SessionFile& f)
+{
+ EmRegsList::iterator iter = fgSubBanks.begin ();
+ while (iter != fgSubBanks.end ())
+ {
+ (*iter)->Load (f);
+ ++iter;
+ }
+
+ gLastSubBank = NULL;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankRegs::Dispose
+ *
+ * DESCRIPTION: Standard dispose function. Completely release any
+ * resources acquired or allocated in Initialize and/or
+ * Load.
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void EmBankRegs::Dispose (void)
+{
+ EmRegsList::iterator iter = fgSubBanks.begin ();
+ while (iter != fgSubBanks.end ())
+ {
+ (*iter)->Dispose ();
+ ++iter;
+ }
+
+ while (fgSubBanks.size () > 0)
+ {
+ EmRegs* bank = fgSubBanks[0];
+ fgSubBanks.erase (fgSubBanks.begin ());
+ delete bank;
+ }
+
+ gLastSubBank = NULL;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankRegs::SetBankHandlers
+ *
+ * DESCRIPTION: Set the bank handlers UAE uses to dispatch memory
+ * access operations.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmBankRegs::SetBankHandlers (void)
+{
+ EmRegsList::iterator iter = fgSubBanks.begin ();
+ while (iter != fgSubBanks.end ())
+ {
+ (*iter)->SetBankHandlers (gAddressBank);
+ ++iter;
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankRegs::GetLong
+// ---------------------------------------------------------------------------
+
+uint32 EmBankRegs::GetLong (emuptr address)
+{
+#if (CHECK_FOR_ADDRESS_ERROR)
+ if ((address & 1) != 0)
+ {
+ AddressError (address, sizeof (uint32), true);
+ }
+#endif
+
+#if (PREVENT_USER_REGISTER_GET)
+ if (gMemAccessFlags.fProtect_RegisterGet && EmMemory::IsPCInRAM () && !MetaMemory::InRAMOSComponent (gCPU->GetPC ()))
+ {
+ EmBankRegs::PreventedAccess (address, sizeof (uint32), true);
+ }
+#endif
+
+#if (VALIDATE_REGISTER_GET)
+ if (gMemAccessFlags.fValidate_RegisterGet && !ValidAddress (address, sizeof (uint32)))
+ {
+ EmBankRegs::InvalidAccess (address, sizeof (uint32), true);
+ }
+#endif
+
+#if HAS_PROFILING
+ CYCLE_GETLONG (WAITSTATES_PLD);
+#endif
+
+ EmRegs* bank = EmBankRegs::GetSubBank (address, sizeof (uint32));
+
+ if (bank)
+ {
+ return bank->GetLong (address);
+ }
+
+ EmBankRegs::InvalidAccess (address, sizeof (uint32), true);
+ return ~0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankRegs::GetWord
+// ---------------------------------------------------------------------------
+
+uint32 EmBankRegs::GetWord (emuptr address)
+{
+#if (CHECK_FOR_ADDRESS_ERROR)
+ if ((address & 1) != 0)
+ {
+ AddressError (address, sizeof (uint16), true);
+ }
+#endif
+
+#if (PREVENT_USER_REGISTER_GET)
+ if (gMemAccessFlags.fProtect_RegisterGet && EmMemory::IsPCInRAM () && !MetaMemory::InRAMOSComponent (gCPU->GetPC ()))
+ {
+ EmBankRegs::PreventedAccess (address, sizeof (uint16), true);
+ }
+#endif
+
+#if (VALIDATE_REGISTER_GET)
+ if (gMemAccessFlags.fValidate_RegisterGet && !ValidAddress (address, sizeof (uint16)))
+ {
+ EmBankRegs::InvalidAccess (address, sizeof (uint16), true);
+ }
+#endif
+
+#if HAS_PROFILING
+ CYCLE_GETWORD (WAITSTATES_PLD);
+#endif
+
+ EmRegs* bank = EmBankRegs::GetSubBank (address, sizeof (uint16));
+
+ if (bank)
+ {
+ return bank->GetWord (address);
+ }
+
+ EmBankRegs::InvalidAccess (address, sizeof (uint16), true);
+ return ~0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankRegs::GetByte
+// ---------------------------------------------------------------------------
+
+uint32 EmBankRegs::GetByte (emuptr address)
+{
+#if (PREVENT_USER_REGISTER_GET)
+ if (gMemAccessFlags.fProtect_RegisterGet && EmMemory::IsPCInRAM () && !MetaMemory::InRAMOSComponent (gCPU->GetPC ()))
+ {
+ EmBankRegs::PreventedAccess (address, sizeof (uint8), true);
+ }
+#endif
+
+#if (VALIDATE_REGISTER_GET)
+ if (gMemAccessFlags.fValidate_RegisterGet && !ValidAddress (address, sizeof (uint8)))
+ {
+ EmBankRegs::InvalidAccess (address, sizeof (uint8), true);
+ }
+#endif
+
+#if HAS_PROFILING
+ CYCLE_GETBYTE (WAITSTATES_PLD);
+#endif
+
+ EmRegs* bank = EmBankRegs::GetSubBank (address, sizeof (uint8));
+
+ if (bank)
+ {
+ return bank->GetByte (address);
+ }
+
+ EmBankRegs::InvalidAccess (address, sizeof (uint8), true);
+ return ~0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankRegs::SetLong
+// ---------------------------------------------------------------------------
+
+void EmBankRegs::SetLong (emuptr address, uint32 value)
+{
+#if PROFILE_MEMORY
+ gMemoryAccess[kPLDLongWrite]++;
+ if (address & 2)
+ gMemoryAccess[kPLDLongWrite2]++;
+#endif
+
+#if (CHECK_FOR_ADDRESS_ERROR)
+ if ((address & 1) != 0)
+ {
+ AddressError (address, sizeof (uint32), false);
+ }
+#endif
+
+#if (PREVENT_USER_REGISTER_SET)
+ if (gMemAccessFlags.fProtect_RegisterSet && EmMemory::IsPCInRAM () && !MetaMemory::InRAMOSComponent (gCPU->GetPC ()))
+ {
+ EmBankRegs::PreventedAccess (address, sizeof (uint32), false);
+ }
+#endif
+
+#if (VALIDATE_REGISTER_SET)
+ if (gMemAccessFlags.fValidate_RegisterSet && !ValidAddress (address, sizeof (uint32)))
+ {
+ EmBankRegs::InvalidAccess (address, sizeof (uint32), false);
+ }
+#endif
+
+#if HAS_PROFILING
+ CYCLE_PUTLONG (WAITSTATES_PLD);
+#endif
+
+ EmRegs* bank = EmBankRegs::GetSubBank (address, sizeof (uint32));
+
+ if (bank)
+ {
+ bank->SetLong (address, value);
+
+ // See if any interesting memory locations have changed. If so,
+ // CheckStepSpy will report it.
+
+ Debug::CheckStepSpy (address, sizeof (uint32));
+
+ return;
+ }
+
+ EmBankRegs::InvalidAccess (address, sizeof (uint32), false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankRegs::SetWord
+// ---------------------------------------------------------------------------
+
+void EmBankRegs::SetWord (emuptr address, uint32 value)
+{
+#if (CHECK_FOR_ADDRESS_ERROR)
+ if ((address & 1) != 0)
+ {
+ AddressError (address, sizeof (uint16), false);
+ }
+#endif
+
+#if (PREVENT_USER_REGISTER_SET)
+ if (gMemAccessFlags.fProtect_RegisterSet && EmMemory::IsPCInRAM () && !MetaMemory::InRAMOSComponent (gCPU->GetPC ()))
+ {
+ EmBankRegs::PreventedAccess (address, sizeof (uint16), false);
+ }
+#endif
+
+#if (VALIDATE_REGISTER_SET)
+ if (gMemAccessFlags.fValidate_RegisterSet && !ValidAddress (address, sizeof (uint16)))
+ {
+ EmBankRegs::InvalidAccess (address, sizeof (uint16), false);
+ }
+#endif
+
+#if HAS_PROFILING
+ CYCLE_PUTWORD (WAITSTATES_PLD);
+#endif
+
+ EmRegs* bank = EmBankRegs::GetSubBank (address, sizeof (uint16));
+
+ if (bank)
+ {
+ bank->SetWord (address, value);
+
+ // See if any interesting memory locations have changed. If so,
+ // CheckStepSpy will report it.
+
+ Debug::CheckStepSpy (address, sizeof (uint16));
+
+ return;
+ }
+
+ EmBankRegs::InvalidAccess (address, sizeof (uint16), false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankRegs::SetByte
+// ---------------------------------------------------------------------------
+
+void EmBankRegs::SetByte (emuptr address, uint32 value)
+{
+#if (PREVENT_USER_REGISTER_SET)
+ if (gMemAccessFlags.fProtect_RegisterSet && EmMemory::IsPCInRAM () && !MetaMemory::InRAMOSComponent (gCPU->GetPC ()))
+ {
+ EmBankRegs::PreventedAccess (address, sizeof (uint8), false);
+ }
+#endif
+
+#if (VALIDATE_REGISTER_SET)
+ if (gMemAccessFlags.fValidate_RegisterSet && !ValidAddress (address, sizeof (uint8)))
+ {
+ EmBankRegs::InvalidAccess (address, sizeof (uint8), false);
+ }
+#endif
+
+#if HAS_PROFILING
+ CYCLE_PUTBYTE (WAITSTATES_PLD);
+#endif
+
+ EmRegs* bank = EmBankRegs::GetSubBank (address, sizeof (uint8));
+
+ if (bank)
+ {
+ bank->SetByte (address, value);
+
+ // See if any interesting memory locations have changed. If so,
+ // CheckStepSpy will report it.
+
+ Debug::CheckStepSpy (address, sizeof (uint8));
+
+ return;
+ }
+
+ EmBankRegs::InvalidAccess (address, sizeof (uint8), false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankRegs::ValidAddress
+// ---------------------------------------------------------------------------
+
+int EmBankRegs::ValidAddress (emuptr address, uint32 size)
+{
+ EmRegs* bank = EmBankRegs::GetSubBank (address, size);
+
+ if (bank)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankRegs::GetRealAddress
+// ---------------------------------------------------------------------------
+
+uint8* EmBankRegs::GetRealAddress (emuptr address)
+{
+ EmRegs* bank = EmBankRegs::GetSubBank (address, 0);
+
+ if (bank)
+ {
+ return bank->GetRealAddress (address);
+ }
+
+ return NULL;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankRegs::AddSubBank
+// ---------------------------------------------------------------------------
+
+void EmBankRegs::AddSubBank (EmRegs* bank)
+{
+ fgSubBanks.push_back (bank);
+ gLastSubBank = NULL;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankRegs::EnableSubBank
+// ---------------------------------------------------------------------------
+
+void EmBankRegs::EnableSubBank (emuptr address)
+{
+ PrvSwitchBanks (fgDisabledSubBanks, fgSubBanks, address);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankRegs::DisableSubBank
+// ---------------------------------------------------------------------------
+
+void EmBankRegs::DisableSubBank (emuptr address)
+{
+ PrvSwitchBanks (fgSubBanks, fgDisabledSubBanks, address);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankRegs::GetSubBank
+// ---------------------------------------------------------------------------
+
+EmRegs* EmBankRegs::GetSubBank (emuptr address, long size)
+{
+ // Cast address to a 64-bit value in case address + size == 0x1 0000 0000.
+
+ uint64 addrStart64 = address;
+ uint64 addrEnd64 = addrStart64 + size;
+
+ // This cache is a big win. When emulating a Palm IIIc (which uses
+ // three EmRegs-based objects: EmRegsEZPalmIIIc, EmRegsSED1375, and
+ // EmRegsFrameBuffer) and doing a Gremlins run, the cache was hit
+ // 2,356,670 times and missed 19456 times. When doing the same run
+ // on a Palm V, the cache was missed only the first time.
+
+ if (gLastSubBank &&
+ (addrStart64 >= gLastStart) &&
+ (addrEnd64 <= gLastStart + gLastRange))
+ {
+ return gLastSubBank;
+ }
+
+ EmRegsList::iterator iter = fgSubBanks.begin ();
+ while (iter != fgSubBanks.end ())
+ {
+ uint64 start = (*iter)->GetAddressStart ();
+ uint32 range = (*iter)->GetAddressRange ();
+
+ if ((addrStart64 >= start) && (addrEnd64 <= start + range))
+ {
+ gLastSubBank = *iter;
+ gLastStart = start;
+ gLastRange = range;
+
+ return *iter;
+ }
+
+ ++iter;
+ }
+
+ return NULL;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankRegs::AddressError
+// ---------------------------------------------------------------------------
+
+void EmBankRegs::AddressError (emuptr address, long size, Bool forRead)
+{
+ EmAssert (gCPU68K);
+ gCPU68K->AddressError (address, size, forRead);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankRegs::InvalidAccess
+// ---------------------------------------------------------------------------
+
+void EmBankRegs::InvalidAccess (emuptr address, long size, Bool forRead)
+{
+ EmAssert (gCPU68K);
+ gCPU68K->BusError (address, size, forRead);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankRegs::PreventedAccess
+// ---------------------------------------------------------------------------
+
+void EmBankRegs::PreventedAccess (emuptr address, long size, Bool forRead)
+{
+ EmAssert (gSession);
+ gSession->ScheduleDeferredError (new EmDeferredErrHardwareRegisters (address, size, forRead));
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ PrvSwitchBanks
+// ---------------------------------------------------------------------------
+
+void PrvSwitchBanks (EmRegsList& fromList, EmRegsList& toList, emuptr address)
+{
+ EmRegsList::iterator iter = fromList.begin ();
+ while (iter != fromList.end ())
+ {
+ uint64 start = (*iter)->GetAddressStart ();
+ uint32 range = (*iter)->GetAddressRange ();
+
+ if ((address >= start) && (address <= start + range))
+ {
+ toList.push_back (*iter);
+ fromList.erase (iter);
+ return;
+ }
+
+ ++iter;
+ }
+}
diff --git a/SrcShared/Hardware/EmBankRegs.h b/SrcShared/Hardware/EmBankRegs.h
new file mode 100644
index 0000000..284fe4a
--- /dev/null
+++ b/SrcShared/Hardware/EmBankRegs.h
@@ -0,0 +1,56 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmBankRegs_h
+#define EmBankRegs_h
+
+#include "EmRegs.h" // EmRegsList
+
+class EmBankRegs
+{
+ public:
+ static void Initialize (void);
+ static void Reset (Bool hardwareReset);
+ static void Save (SessionFile&);
+ static void Load (SessionFile&);
+ static void Dispose (void);
+
+ static void SetBankHandlers (void);
+
+ static uint32 GetLong (emuptr address);
+ static uint32 GetWord (emuptr address);
+ static uint32 GetByte (emuptr address);
+ static void SetLong (emuptr address, uint32 value);
+ static void SetWord (emuptr address, uint32 value);
+ static void SetByte (emuptr address, uint32 value);
+ static int ValidAddress (emuptr address, uint32 size);
+ static uint8* GetRealAddress (emuptr address);
+
+ static void AddSubBank (EmRegs*);
+
+ static void EnableSubBank (emuptr address);
+ static void DisableSubBank (emuptr address);
+
+ private:
+ static EmRegs* GetSubBank (emuptr address, long size);
+ static void AddressError (emuptr address, long size, Bool forRead);
+ static void InvalidAccess (emuptr address, long size, Bool forRead);
+ static void PreventedAccess (emuptr address, long size, Bool forRead);
+
+ static EmRegsList fgSubBanks;
+ static EmRegsList fgDisabledSubBanks;
+
+ friend class EmRegs; // EmBankRegs::InvalidAccess
+};
+
+#endif /* EmBankRegs_h */
diff --git a/SrcShared/Hardware/EmBankSRAM.cpp b/SrcShared/Hardware/EmBankSRAM.cpp
new file mode 100644
index 0000000..4553131
--- /dev/null
+++ b/SrcShared/Hardware/EmBankSRAM.cpp
@@ -0,0 +1,640 @@
+/* -*- 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 "EmBankSRAM.h"
+
+#include "Byteswapping.h" // ByteswapWords
+#include "DebugMgr.h" // Debug::CheckStepSpy
+#include "EmCPU68K.h" // gCPU68K
+#include "EmMemory.h" // gRAMBank_Size, gRAM_Memory, gMemoryAccess
+#include "EmScreen.h" // EmScreen::MarkDirty
+#include "EmSession.h" // GetDevice
+#include "MetaMemory.h" // MetaMemory::
+#include "Miscellaneous.h" // StWordSwapper
+#include "Profiling.h" // WAITSTATES_SRAM
+#include "SessionFile.h" // WriteRAMImage
+
+
+// ===========================================================================
+// ¥ SRAM Bank Accessors
+// ===========================================================================
+// These functions provide fetch and store access to the emulator's random
+// access memory.
+
+static EmAddressBank gAddressBank =
+{
+ EmBankSRAM::GetLong,
+ EmBankSRAM::GetWord,
+ EmBankSRAM::GetByte,
+ EmBankSRAM::SetLong,
+ EmBankSRAM::SetWord,
+ EmBankSRAM::SetByte,
+ EmBankSRAM::GetRealAddress,
+ EmBankSRAM::ValidAddress,
+ EmBankSRAM::GetMetaAddress,
+ EmBankSRAM::AddOpcodeCycles
+};
+
+ // Note: I'd've used hwrCardBase0 here, except that that
+ // changes on different hardware. It's 0x10000000 in some
+ // cases, 0x00000000 in others.
+
+static const emuptr kMemoryStart = 0x10000000;
+static const emuptr kMemoryStartEZ = 0x00000000;
+static const emuptr kMemoryStartVZ = 0x00000000;
+
+emuptr gMemoryStart;
+
+uint32 gRAMBank_Size;
+uint32 gRAMBank_Mask;
+uint8* gRAM_Memory;
+uint8* gRAM_MetaMemory;
+
+#if defined (_DEBUG)
+
+ // In debug mode, define a global variable that points to the
+ // Palm ROM's low-memory globals. That makes it easier to find
+ // out what's going wrong when something goes wrong.
+ //
+ // Keep in mind that on Windows, all values are "wordswapped"
+ // (each pair of bytes is byteswapped).
+
+ LowMemHdrType* gLowMemory;
+
+#endif
+
+
+static inline uint8* InlineGetMetaAddress (emuptr address)
+{
+ return (uint8*) &(gRAM_MetaMemory[address]);
+}
+
+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);
+ }
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankSRAM::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 EmBankSRAM::Initialize (RAMSizeType ramSize)
+{
+ EmAssert (gRAM_Memory == NULL);
+ EmAssert (gRAM_MetaMemory == NULL);
+
+ if (ramSize > 0)
+ {
+ gRAMBank_Size = ramSize * 1024;
+ gRAMBank_Mask = gRAMBank_Size - 1;
+ gRAM_Memory = (uint8*) Platform::AllocateMemoryClear (gRAMBank_Size);
+ gRAM_MetaMemory = (uint8*) Platform::AllocateMemoryClear (gRAMBank_Size);
+
+#if defined (_DEBUG)
+ // In debug mode, define a global variable that points to the
+ // Palm ROM's low-memory globals. That makes it easier to find
+ // out what's going wrong when something goes wrong.
+
+ gLowMemory = (LowMemHdrType*) gRAM_Memory;
+#endif
+ }
+
+ EmAssert (gSession);
+
+ if (gSession->GetDevice ().Supports68EZ328 ())
+ {
+ gMemoryStart = kMemoryStartEZ;
+ }
+ else if (gSession->GetDevice ().Supports68VZ328 ())
+ {
+ gMemoryStart = kMemoryStartVZ;
+ }
+ else
+ {
+ gMemoryStart = kMemoryStart;
+ }
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankSRAM::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 EmBankSRAM::Reset (Bool /*hardwareReset*/)
+{
+ memset (gRAM_MetaMemory, 0, gRAMBank_Size);
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankSRAM::Save
+ *
+ * DESCRIPTION: Standard save function. Saves any sub-system state to
+ * the given session file.
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void EmBankSRAM::Save (SessionFile& f)
+{
+ StWordSwapper swapper1 (gRAM_Memory, gRAMBank_Size);
+ f.WriteRAMImage (gRAM_Memory, gRAMBank_Size);
+
+ StWordSwapper swapper2 (gRAM_MetaMemory, gRAMBank_Size);
+ f.WriteMetaRAMImage (gRAM_MetaMemory, gRAMBank_Size);
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankSRAM::Load
+ *
+ * DESCRIPTION: Standard load function. Loads any sub-system state
+ * from the given session file.
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void EmBankSRAM::Load (SessionFile& f)
+{
+ EmAssert (gRAM_Memory);
+ EmAssert (gRAM_MetaMemory);
+
+ if (f.ReadRAMImage (gRAM_Memory))
+ {
+ ByteswapWords (gRAM_Memory, gRAMBank_Size);
+ }
+ else
+ {
+ f.SetCanReload (false);
+ }
+
+ if (f.ReadMetaRAMImage (gRAM_MetaMemory))
+ {
+ ByteswapWords (gRAM_MetaMemory, gRAMBank_Size);
+ }
+ else
+ {
+ f.SetCanReload (false);
+ }
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankSRAM::Dispose
+ *
+ * DESCRIPTION: Standard dispose function. Completely release any
+ * resources acquired or allocated in Initialize and/or
+ * Load.
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void EmBankSRAM::Dispose (void)
+{
+ Platform::DisposeMemory (gRAM_Memory);
+ Platform::DisposeMemory (gRAM_MetaMemory);
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmBankSRAM::SetBankHandlers
+ *
+ * DESCRIPTION: Set the bank handlers UAE uses to dispatch memory
+ * access operations.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmBankSRAM::SetBankHandlers (void)
+{
+ // Memory banks 0x1000 to <mumble> are managed by the functions
+ // in EmBankSRAM. <mumble> is based on the amount of RAM being emulated.
+
+ long numBanks = EmMemBankIndex (gMemoryStart + gRAMBank_Size - 1) -
+ EmMemBankIndex (gMemoryStart) + 1;
+ Memory::InitializeBanks (gAddressBank, EmMemBankIndex (gMemoryStart), numBanks);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankSRAM::GetLong
+// ---------------------------------------------------------------------------
+
+uint32 EmBankSRAM::GetLong (emuptr address)
+{
+#if PROFILE_MEMORY
+ gMemoryAccess[kSRAMLongRead]++;
+ if (address & 2)
+ gMemoryAccess[kSRAMLongRead2]++;
+#endif
+
+#if (CHECK_FOR_ADDRESS_ERROR)
+ if ((address & 1) != 0)
+ {
+ AddressError (address, sizeof (uint32), true);
+ }
+#endif
+
+#if (PREVENT_USER_SRAM_GET)
+ if (gMemAccessFlags.fProtect_SRAMGet)
+ {
+ ProtectedAccess (address, sizeof (uint32), true);
+ }
+#endif
+
+#if (VALIDATE_SRAM_GET)
+ if (gMemAccessFlags.fValidate_SRAMGet && !ValidAddress (address, sizeof (uint32)))
+ {
+ InvalidAccess (address, sizeof (uint32), true);
+ }
+#endif
+
+#if HAS_PROFILING
+ CYCLE_GETLONG (WAITSTATES_SRAM);
+#endif
+
+ address &= gRAMBank_Mask;
+
+ return EmMemDoGet32 (gRAM_Memory + address);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankSRAM::GetWord
+// ---------------------------------------------------------------------------
+
+uint32 EmBankSRAM::GetWord (emuptr address)
+{
+#if PROFILE_MEMORY
+ gMemoryAccess[kSRAMWordRead]++;
+#endif
+
+#if (CHECK_FOR_ADDRESS_ERROR)
+ if ((address & 1) != 0)
+ {
+ AddressError (address, sizeof (uint16), true);
+ }
+#endif
+
+#if (PREVENT_USER_SRAM_GET)
+ if (gMemAccessFlags.fProtect_SRAMGet)
+ {
+ ProtectedAccess (address, sizeof (uint16), true);
+ }
+#endif
+
+#if (VALIDATE_SRAM_GET)
+ if (gMemAccessFlags.fValidate_SRAMGet && !ValidAddress (address, sizeof (uint16)))
+ {
+ InvalidAccess (address, sizeof (uint16), true);
+ }
+#endif
+
+#if HAS_PROFILING
+ CYCLE_GETWORD (WAITSTATES_SRAM);
+#endif
+
+ address &= gRAMBank_Mask;
+
+ return EmMemDoGet16 (gRAM_Memory + address);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankSRAM::GetByte
+// ---------------------------------------------------------------------------
+
+uint32 EmBankSRAM::GetByte (emuptr address)
+{
+#if PROFILE_MEMORY
+ gMemoryAccess[kSRAMByteRead]++;
+#endif
+
+#if (PREVENT_USER_SRAM_GET)
+ if (gMemAccessFlags.fProtect_SRAMGet)
+ {
+ ProtectedAccess (address, sizeof (uint8), true);
+ }
+#endif
+
+#if (VALIDATE_SRAM_GET)
+ if (gMemAccessFlags.fValidate_SRAMGet && !ValidAddress (address, sizeof (uint8)))
+ {
+ InvalidAccess (address, sizeof (uint8), true);
+ }
+#endif
+
+#if HAS_PROFILING
+ CYCLE_GETBYTE (WAITSTATES_SRAM);
+#endif
+
+ address &= gRAMBank_Mask;
+
+ return EmMemDoGet8 (gRAM_Memory + address);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankSRAM::SetLong
+// ---------------------------------------------------------------------------
+
+void EmBankSRAM::SetLong (emuptr address, uint32 value)
+{
+#if PROFILE_MEMORY
+ gMemoryAccess[kSRAMLongWrite]++;
+ if (address & 2)
+ gMemoryAccess[kSRAMLongWrite2]++;
+#endif
+
+#if (CHECK_FOR_ADDRESS_ERROR)
+ if ((address & 1) != 0)
+ {
+ AddressError (address, sizeof (uint32), false);
+ }
+#endif
+
+#if (PREVENT_USER_SRAM_SET)
+ if (gMemAccessFlags.fProtect_SRAMSet)
+ {
+ ProtectedAccess (address, sizeof (uint32), false);
+ }
+#endif
+
+#if (VALIDATE_SRAM_SET)
+ if (gMemAccessFlags.fValidate_SRAMSet && !ValidAddress (address, sizeof (uint32)))
+ {
+ InvalidAccess (address, sizeof (uint32), false);
+ }
+#endif
+
+#if HAS_PROFILING
+ CYCLE_PUTLONG (WAITSTATES_SRAM);
+#endif
+
+ emuptr phyAddress = address;
+ phyAddress &= gRAMBank_Mask;
+
+ register uint8* metaAddress = InlineGetMetaAddress (phyAddress);
+// META_CHECK (metaAddress, address, SetLong, uint32, false);
+ ::PrvScreenCheck (metaAddress, address, sizeof (uint32));
+
+ EmMemDoPut32 (gRAM_Memory + phyAddress, value);
+
+ // See if any interesting memory locations have changed. If so,
+ // CheckStepSpy will report it.
+
+ Debug::CheckStepSpy (address, sizeof (uint32));
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankSRAM::SetWord
+// ---------------------------------------------------------------------------
+
+void EmBankSRAM::SetWord (emuptr address, uint32 value)
+{
+#if PROFILE_MEMORY
+ gMemoryAccess[kSRAMWordWrite]++;
+#endif
+
+#if (CHECK_FOR_ADDRESS_ERROR)
+ if ((address & 1) != 0)
+ {
+ AddressError (address, sizeof (uint16), false);
+ }
+#endif
+
+#if (PREVENT_USER_SRAM_SET)
+ if (gMemAccessFlags.fProtect_SRAMSet)
+ {
+ ProtectedAccess (address, sizeof (uint16), false);
+ }
+#endif
+
+#if (VALIDATE_SRAM_SET)
+ if (gMemAccessFlags.fValidate_SRAMSet && !ValidAddress (address, sizeof (uint16)))
+ {
+ InvalidAccess (address, sizeof (uint16), false);
+ }
+#endif
+
+#if HAS_PROFILING
+ CYCLE_PUTWORD (WAITSTATES_SRAM);
+#endif
+
+ emuptr phyAddress = address;
+ phyAddress &= gRAMBank_Mask;
+
+ register uint8* metaAddress = InlineGetMetaAddress (phyAddress);
+// META_CHECK (metaAddress, address, SetLong, uint16, false);
+ ::PrvScreenCheck (metaAddress, address, sizeof (uint16));
+
+ EmMemDoPut16 (gRAM_Memory + phyAddress, value);
+
+ // See if any interesting memory locations have changed. If so,
+ // CheckStepSpy will report it.
+
+ Debug::CheckStepSpy (address, sizeof (uint16));
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankSRAM::SetByte
+// ---------------------------------------------------------------------------
+
+void EmBankSRAM::SetByte (emuptr address, uint32 value)
+{
+#if PROFILE_MEMORY
+ gMemoryAccess[kSRAMByteWrite]++;
+#endif
+
+#if (PREVENT_USER_SRAM_SET)
+ if (gMemAccessFlags.fProtect_SRAMSet)
+ {
+ ProtectedAccess (address, sizeof (uint8), false);
+ }
+#endif
+
+#if (VALIDATE_SRAM_SET)
+ if (gMemAccessFlags.fValidate_SRAMSet && !ValidAddress (address, sizeof (uint8)))
+ {
+ InvalidAccess (address, sizeof (uint8), false);
+ }
+#endif
+
+#if HAS_PROFILING
+ CYCLE_PUTBYTE (WAITSTATES_SRAM);
+#endif
+
+ emuptr phyAddress = address;
+ phyAddress &= gRAMBank_Mask;
+
+ register uint8* metaAddress = InlineGetMetaAddress (phyAddress);
+// META_CHECK (metaAddress, address, SetLong, uint8, false);
+ ::PrvScreenCheck (metaAddress, address, sizeof (uint8));
+
+ EmMemDoPut8 (gRAM_Memory + phyAddress, value);
+
+ // See if any interesting memory locations have changed. If so,
+ // CheckStepSpy will report it.
+
+ Debug::CheckStepSpy (address, sizeof (uint8));
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankSRAM::ValidAddress
+// ---------------------------------------------------------------------------
+
+int EmBankSRAM::ValidAddress (emuptr address, uint32 size)
+{
+ address -= gMemoryStart;
+ int result = (address + size) <= (gMemoryStart + gRAMBank_Size);
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankSRAM::GetRealAddress
+// ---------------------------------------------------------------------------
+
+uint8* EmBankSRAM::GetRealAddress (emuptr address)
+{
+ // Strip the uppermost bit of the address.
+
+ address &= gRAMBank_Mask;
+
+ return (uint8*) &(gRAM_Memory[address]);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankSRAM::GetMetaAddress
+// ---------------------------------------------------------------------------
+
+uint8* EmBankSRAM::GetMetaAddress (emuptr address)
+{
+ // Strip the uppermost bit of the address.
+
+ address &= gRAMBank_Mask;
+
+ return (uint8*) &(gRAM_MetaMemory[address]);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankSRAM::AddOpcodeCycles
+// ---------------------------------------------------------------------------
+
+void EmBankSRAM::AddOpcodeCycles (void)
+{
+#if (HAS_PROFILING)
+ CYCLE_GETWORD (WAITSTATES_SRAM);
+#endif
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankSRAM::AddressError
+// ---------------------------------------------------------------------------
+
+void EmBankSRAM::AddressError (emuptr address, long size, Bool forRead)
+{
+ EmAssert (gCPU68K);
+ gCPU68K->AddressError (address, size, forRead);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankSRAM::InvalidAccess
+// ---------------------------------------------------------------------------
+
+void EmBankSRAM::InvalidAccess (emuptr address, long size, Bool forRead)
+{
+ EmAssert (gCPU68K);
+ gCPU68K->BusError (address, size, forRead);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmBankSRAM::ProtectedAccess
+// ---------------------------------------------------------------------------
+
+void EmBankSRAM::ProtectedAccess (emuptr address, long size, Bool forRead)
+{
+ EmAssert (gCPU68K);
+ gCPU68K->BusError (address, size, forRead);
+}
+
diff --git a/SrcShared/Hardware/EmBankSRAM.h b/SrcShared/Hardware/EmBankSRAM.h
new file mode 100644
index 0000000..8f5cb23
--- /dev/null
+++ b/SrcShared/Hardware/EmBankSRAM.h
@@ -0,0 +1,58 @@
+/* -*- 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.
+\* ===================================================================== */
+
+#ifndef EmBankSRAM_h
+#define EmBankSRAM_h
+
+class SessionFile;
+
+extern emuptr gMemoryStart;
+
+ // These are also accessed by the DRAMBank functions.
+extern uint32 gRAMBank_Size;
+extern uint32 gRAMBank_Mask;
+extern uint8* gRAM_Memory;
+extern uint8* gRAM_MetaMemory;
+
+
+class EmBankSRAM
+{
+ public:
+ static void Initialize (RAMSizeType ramSize);
+ static void Reset (Bool hardwareReset);
+ static void Save (SessionFile&);
+ static void Load (SessionFile&);
+ static void Dispose (void);
+
+ static void SetBankHandlers (void);
+
+ static uint32 GetLong (emuptr address);
+ static uint32 GetWord (emuptr address);
+ static uint32 GetByte (emuptr address);
+ static void SetLong (emuptr address, uint32 value);
+ static void SetWord (emuptr address, uint32 value);
+ static void SetByte (emuptr address, uint32 value);
+ static int ValidAddress (emuptr address, uint32 size);
+ static uint8* GetRealAddress (emuptr address);
+ static uint8* GetMetaAddress (emuptr address);
+ static void AddOpcodeCycles (void);
+
+ static emuptr GetMemoryStart (void) { return gMemoryStart; }
+
+ private:
+ static void AddressError (emuptr address, long size, Bool forRead);
+ static void InvalidAccess (emuptr address, long size, Bool forRead);
+ static void ProtectedAccess (emuptr address, long size, Bool forRead);
+};
+
+#endif /* EmBankSRAM_h */
diff --git a/SrcShared/Hardware/EmCPU.cpp b/SrcShared/Hardware/EmCPU.cpp
new file mode 100644
index 0000000..22c1031
--- /dev/null
+++ b/SrcShared/Hardware/EmCPU.cpp
@@ -0,0 +1,68 @@
+/* -*- 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 "EmCPU.h"
+
+
+EmCPU* gCPU;
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU::EmCPU
+// ---------------------------------------------------------------------------
+
+EmCPU::EmCPU (EmSession* session) :
+ fSession (session)
+{
+ EmAssert (gCPU == NULL);
+ gCPU = this;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU::~EmCPU
+// ---------------------------------------------------------------------------
+
+EmCPU::~EmCPU (void)
+{
+ EmAssert (gCPU == this);
+ gCPU = NULL;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU::Reset
+// ---------------------------------------------------------------------------
+
+void EmCPU::Reset (Bool /*hardwareReset*/)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU::Save
+// ---------------------------------------------------------------------------
+
+void EmCPU::Save (SessionFile&)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU::Load
+// ---------------------------------------------------------------------------
+
+void EmCPU::Load (SessionFile&)
+{
+}
diff --git a/SrcShared/Hardware/EmCPU.h b/SrcShared/Hardware/EmCPU.h
new file mode 100644
index 0000000..a884026
--- /dev/null
+++ b/SrcShared/Hardware/EmCPU.h
@@ -0,0 +1,69 @@
+/* -*- 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.
+\* ===================================================================== */
+
+#ifndef EmCPU_h
+#define EmCPU_h
+
+class EmSession;
+class SessionFile;
+
+class EmCPU;
+extern EmCPU* gCPU;
+
+class EmCPU
+{
+ public:
+ // -----------------------------------------------------------------------------
+ // constructor / destructor
+ // -----------------------------------------------------------------------------
+
+ EmCPU (EmSession*);
+ virtual ~EmCPU (void);
+
+ // -----------------------------------------------------------------------------
+ // public methods
+ // -----------------------------------------------------------------------------
+
+ // Standard sub-system methods:
+ // Reset: Resets the state. Called on hardware resets or on
+ // calls to SysReset. Also called from constructor.
+ // Save: Saves the state to the given file.
+ // Load: Loads the state from the given file. Can assume that
+ // Reset has been called first.
+
+ virtual void Reset (Bool hardwareReset);
+ virtual void Save (SessionFile&);
+ virtual void Load (SessionFile&);
+
+ // Execute the main CPU loop until asked to stop.
+
+ virtual void Execute (void) = 0;
+ virtual void CheckAfterCycle (void) = 0;
+
+ // Low-level access to CPU state.
+
+ virtual emuptr GetPC (void) = 0;
+ virtual emuptr GetSP (void) = 0;
+ virtual uint32 GetRegister (int) = 0;
+
+ virtual void SetPC (emuptr) = 0;
+ virtual void SetSP (emuptr) = 0;
+ virtual void SetRegister (int, uint32) = 0;
+
+ virtual Bool Stopped (void) = 0;
+
+ protected:
+ EmSession* fSession;
+};
+
+#endif /* EmCPU_h */
diff --git a/SrcShared/Hardware/EmCPU68K.cpp b/SrcShared/Hardware/EmCPU68K.cpp
new file mode 100644
index 0000000..e3f00e2
--- /dev/null
+++ b/SrcShared/Hardware/EmCPU68K.cpp
@@ -0,0 +1,1849 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmCPU68K.h"
+
+#include "Byteswapping.h" // Canonical
+#include "DebugMgr.h" // gExceptionAddress, gExceptionSize, gExceptionForRead
+#include "EmBankROM.h" // EmBankROM::GetMemoryStart
+#include "EmEventPlayback.h" // EmEventPlayback::ReplayingEvents
+#include "EmHAL.h" // EmHAL::GetInterruptLevel
+#include "EmMemory.h" // CEnableFullAccess
+#include "EmMinimize.h" // IsOn
+#include "EmSession.h" // HandleInstructionBreak
+#include "Logging.h" // LogAppendMsg
+#include "MetaMemory.h" // IsCPUBreak
+#include "Platform.h" // GetMilliseconds
+#include "SessionFile.h" // WriteDBallRegs, etc.
+#include "StringData.h" // kExceptionNames
+#include "UAE.h" // cpuop_func, etc.
+
+#include <algorithm> // find
+
+#if __profile__
+#include <Profiler.h>
+#endif
+
+#if defined (macintosh) && defined (_DEBUG) && 0
+ #define HAS_DEAD_MANS_SWITCH 1
+#else
+ #define HAS_DEAD_MANS_SWITCH 0
+#endif
+
+// !!! Why is this here? Shouldn't it be in Profiling.h?
+#if HAS_PROFILING
+perfRec perftbl[65536];
+#endif
+
+// Define our own flags for regs.spcflag. Please do not let these
+// overlap with UAE-defined flags (should not fall below 0x0002000)
+// and avoid using the high bit just for safety.
+
+#define SPCFLAG_END_OF_CYCLE (0x40000000)
+
+
+// Data needed by UAE.
+
+int areg_byteinc[] = { 1,1,1,1,1,1,1,2 }; // (normally in newcpu.c)
+int imm8_table[] = { 8,1,2,3,4,5,6,7 }; // (normally in newcpu.c)
+
+int movem_index1[256]; // (normally in newcpu.c)
+int movem_index2[256]; // (normally in newcpu.c)
+int movem_next[256]; // (normally in newcpu.c)
+
+cpuop_func* cpufunctbl[65536]; // (normally in newcpu.c)
+
+uint16 last_op_for_exception_3; /* Opcode of faulting instruction */
+emuptr last_addr_for_exception_3; /* PC at fault time */
+emuptr last_fault_for_exception_3; /* Address that generated the exception */
+
+struct regstruct regs; // (normally in newcpu.c)
+struct flag_struct regflags; // (normally in support.c)
+
+
+// These variables should strictly be in a sub-system that implements
+// the stack overflow checking, etc. However, for performance reasons,
+// we need to expose them to UAE (see the CHECK_STACK_POINTER_ASSIGNMENT,
+// et al macros), so define them here.
+//
+// Similar comments for the CheckKernelStack function.
+
+uae_u32 gStackHigh;
+uae_u32 gStackLowWarn;
+uae_u32 gStackLow;
+uae_u32 gKernelStackOverflowed;
+
+
+// Definitions of the stack frames used in EmCPU68K::ProcessException.
+
+#include "PalmPack.h"
+
+struct ExceptionStackFrame1
+{
+ uint16 statusRegister;
+ uint32 programCounter;
+};
+
+struct ExceptionStackFrame2
+{
+ uint16 functionCode;
+ uint32 accessAddress;
+ uint16 instructionRegister;
+ uint16 statusRegister;
+ uint32 programCounter;
+};
+
+#include "PalmPackPop.h"
+
+
+EmCPU68K* gCPU68K;
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::Cycle
+// ---------------------------------------------------------------------------
+
+// this guy is a macro instead of an inline function so that "counter" can
+// be declared as a variable local to the calling function. The resulting
+// code can be more efficient if "counter" can be cached in a register
+// instead of being a static or global variable.
+
+#define CYCLE(sleeping) \
+{ \
+ /* Don't do anything if we're in the middle of an ATrap call. We don't */ \
+ /* need interrupts firing or tmr counters incrementing. */ \
+ \
+ EmAssert (session); \
+ if (!session->IsNested ()) \
+ { \
+ /* Perform CPU-specific idling. */ \
+ \
+ EmHAL::Cycle (sleeping); \
+ \
+ /* Perform expensive operations. */ \
+ \
+ if (sleeping || ((++counter & 0x7FFF) == 0)) \
+ { \
+ this->CycleSlowly (sleeping); \
+ } \
+ } \
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::EmCPU68K
+// ---------------------------------------------------------------------------
+
+EmCPU68K::EmCPU68K (EmSession* session) :
+ EmCPU (session),
+ fLastTraceAddress (EmMemNULL),
+ fCycleCount (0),
+// fExceptionHandlers (),
+ fHookJSR (),
+ fHookJSR_Ind (),
+ fHookLINK (),
+ fHookRTE (),
+ fHookRTS (),
+ fHookNewPC (),
+ fHookNewSP ()
+#if REGISTER_HISTORY
+ , fRegHistoryIndex (0)
+// , fRegHistory ()
+#endif
+#if EXCEPTION_HISTORY
+ , fExceptionHistoryIndex (0)
+// , fExceptionHistory ()
+#endif
+{
+ this->InitializeUAETables ();
+
+ EmAssert (gCPU68K == NULL);
+ gCPU68K = this;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::~EmCPU68K
+// ---------------------------------------------------------------------------
+
+EmCPU68K::~EmCPU68K (void)
+{
+ EmAssert (gCPU68K == this);
+ gCPU68K = NULL;
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::Reset
+// ---------------------------------------------------------------------------
+
+void EmCPU68K::Reset (Bool hardwareReset)
+{
+ fLastTraceAddress = EmMemNULL;
+ fCycleCount = 0;
+
+#if REGISTER_HISTORY
+ fRegHistoryIndex = 0;
+#endif
+
+#if EXCEPTION_HISTORY
+ fExceptionHistoryIndex = 0;
+#endif
+
+ gStackHigh = EmMemEOM;
+ gStackLowWarn = EmMemNULL;
+ gStackLow = EmMemNULL;
+ gKernelStackOverflowed = false;
+
+ if (hardwareReset)
+ {
+ // (taken from m68k_reset in newcpu.c)
+
+ // !!! I think that we really need to emulate ROM appearing at NULL.
+ // That would break our dependency on EmBankROM.
+
+ emuptr romStart = EmBankROM::GetMemoryStart ();
+ m68k_areg (regs, 7) = EmMemGet32 (romStart);
+ m68k_setpc (EmMemGet32 (romStart + 4));
+
+ // Note, on the 68K, the t0 and m flags must always be zero.
+
+ regs.prefetch = 0x0000;
+ regs.kick_mask = 0xF80000; // (not a 68K register)
+ regs.s = 1; // supervisor/user state
+ regs.m = 0; // master/interrupt state
+ regs.stopped = 0; // (not a 68K register)
+ regs.t1 = 0; // 1 = trace on any instruction
+ regs.t0 = 0; // 1 = trace on change of flow
+ SET_ZFLG (0);
+ SET_XFLG (0);
+ SET_CFLG (0);
+ SET_VFLG (0);
+ SET_NFLG (0);
+ regs.spcflags = 0; // (not a 68K register)
+ regs.intmask = 7; // disable all interrupts
+ regs.vbr = regs.sfc = regs.dfc = 0;
+ regs.fpcr = regs.fpsr = regs.fpiar = 0;
+ }
+
+ Memory::CheckNewPC (m68k_getpc ());
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::Save
+// ---------------------------------------------------------------------------
+
+void EmCPU68K::Save (SessionFile& f)
+{
+ // Write out the CPU Registers
+
+ regstruct tempRegs;
+ this->GetRegisters (tempRegs);
+
+ Canonical (tempRegs);
+ f.WriteDBallRegs (tempRegs);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::Load
+// ---------------------------------------------------------------------------
+
+void EmCPU68K::Load (SessionFile& f)
+{
+ // Read in the CPU Registers.
+
+ regstruct tempRegs;
+ f.ReadDBallRegs (tempRegs);
+
+ Canonical (tempRegs);
+ this->SetRegisters (tempRegs);
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::Execute
+// ---------------------------------------------------------------------------
+
+void EmCPU68K::Execute (void)
+{
+ // This function is the bottleneck for all 68K emulation. It's
+ // important that it run as quickly as possible. To that end,
+ // fine tune register allocation as much as we can by hand.
+
+#if defined(__powerc) || defined(powerc) || \
+ defined(__powerpc) || defined(powerpc) || \
+ defined(__ppc__) || defined(ppc)
+
+ register int counter = 0;
+ register cpuop_func** functable = cpufunctbl;
+
+ register uint8** pc_p_p = &regs.pc_p;
+ register uint8** pc_meta_oldp_p = &regs.pc_meta_oldp;
+ register uint8** pc_oldp_p = &regs.pc_oldp;
+ register uint32* spcflags_p = &regs.spcflags;
+ register EmSession* session = fSession;
+
+ #define pc_p (*pc_p_p)
+ #define pc_meta_oldp (*pc_meta_oldp_p)
+ #define pc_oldp (*pc_oldp_p)
+ #define spcflags (*spcflags_p)
+
+#elif defined(_MSC_VER) && defined(_M_IX86)
+
+ register int counter = 0;
+ register cpuop_func** functable = cpufunctbl;
+
+ #define pc_p (regs.pc_p)
+ #define pc_meta_oldp (regs.pc_meta_oldp)
+ #define pc_oldp (regs.pc_oldp)
+ #define spcflags (regs.spcflags)
+ #define session (fSession)
+
+#else
+
+ register int counter = 0;
+ register cpuop_func** functable = cpufunctbl;
+
+ #define pc_p (regs.pc_p)
+ #define pc_meta_oldp (regs.pc_meta_oldp)
+ #define pc_oldp (regs.pc_oldp)
+ #define spcflags (regs.spcflags)
+ #define session (fSession)
+
+#endif
+
+#if HAS_PROFILING_DEBUG
+ UInt64 readCyclesSaved = 0;
+ UInt64 writeCyclesSaved = 0;
+ UInt64 clockCyclesSaved = 0;
+#endif
+
+#if HAS_DEAD_MANS_SWITCH
+ // -----------------------------------------------------------------------
+ // Put in a little dead-man's switch. If this function doesn't exit for a
+ // long time, let us get into the debugger.
+ // -----------------------------------------------------------------------
+
+ uint32 deadManNow;
+ uint32 deadManStart = Platform::GetMilliseconds ();
+#endif
+
+ // -----------------------------------------------------------------------
+ // Check for the stopped flag before entering the "execute an opcode"
+ // section. It could be that we last exited the loop while still in stop
+ // mode, and we need to wind our way back down to that spot.
+ // -----------------------------------------------------------------------
+
+ if ((spcflags & SPCFLAG_STOP) != 0)
+ goto StoppedLoop;
+
+ while (1)
+ {
+#if REGISTER_HISTORY
+ // -----------------------------------------------------------------------
+ // Save the registers for the post-mortem, but don't record the
+ // instructions we generate when calling the ROM as a subroutine. We want
+ // those to be as transparent as possible. In particular, we don't want
+ // any functions that we call as part of figuring out why a problem
+ // occurred to knock the problem-causing registers off of our array.
+ // -----------------------------------------------------------------------
+
+// if (!session->IsNested ())
+ {
+ ++fRegHistoryIndex;
+ fRegHistory[fRegHistoryIndex & (kRegHistorySize - 1)] = regs;
+ }
+#endif
+
+#if HAS_DEAD_MANS_SWITCH
+ // -----------------------------------------------------------------------
+ // Put in a little dead-man's switch. If this function doesn't exit for a
+ // long time, let us get into the debugger.
+ // -----------------------------------------------------------------------
+
+ deadManNow = Platform::GetMilliseconds ();
+ if ((deadManNow - deadManStart) > 5000)
+ {
+ Platform::Debugger ();
+ }
+#endif
+
+ // -----------------------------------------------------------------------
+ // See if we need to halt CPU execution at this location. We could need
+ // to do this for several reasons, including hitting soft breakpoints or
+ // needing to execute tailpatches.
+ // -----------------------------------------------------------------------
+
+ if (MetaMemory::IsCPUBreak (pc_meta_oldp + (pc_p - pc_oldp)))
+ {
+ EmAssert (session);
+ session->HandleInstructionBreak ();
+ }
+
+#if HAS_PROFILING
+ emuptr pcStart;
+ pcStart = m68k_getpc ();
+
+ if (gProfilingEnabled)
+ {
+ // If detailed, log instruction here
+
+ if (gProfilingDetailed)
+ {
+ ProfileInstructionEnter (pcStart);
+ }
+
+#if HAS_PROFILING_DEBUG
+ readCyclesSaved = gReadCycles;
+ writeCyclesSaved = gWriteCycles;
+ clockCyclesSaved = gClockCycles;
+#endif
+
+ // Turn gProfilingCounted on here so the opcode fetch below is counted.
+
+ gProfilingCounted = true;
+ }
+#endif
+
+ // =======================================================================
+ // Execute the opcode.
+ // -----------------------------------------------------------------------
+ // Interestingly, defining "opcode" as an EmOpcode68K (which is a uint32)
+ // instead of a uint16 (which is all you need to hold the opcode), makes
+ // a big difference in performance (at least, on Intel). The former
+ // generates:
+ //
+ // mov edx, DWORD PTR _regs+92
+ // xor eax, eax
+ // mov ax, WORD PTR [edx]
+ // push eax
+ // call DWORD PTR [edi+eax*4]
+ //
+ // while the latter generates:
+ //
+ // mov edx, DWORD PTR _regs+92
+ // mov ax, WORD PTR [edx]
+ // and eax, 65535 ; 0000ffffH
+ // push eax
+ // call DWORD PTR [edi+eax*4]
+ //
+ // This results in an amazing 5% performance difference. What makes it
+ // even more amazing is that similar optimizations elsewhere don't seem
+ // to help. For instance, in EmCPU68K::Cycle, there's the expression:
+ //
+ // ((++gCounter) & 0x7FFF == 0)
+ //
+ // Changing gCounter to a uint16, or changing the expression to:
+ //
+ // ((uint16) ++gCounter) == 0)
+ //
+ // both result in the period doubling, but also in better code
+ // generation. However, neither gives better performance. Additionally,
+ // I tried like heck to optimize the call to IsCPUBreak above. I added
+ // a preflight check that would skip 70% of the calls to IsCPUBreak (as
+ // well as the calculation of the parameter passed to it) and re-
+ // organized the code so that branch prediction would work. However,
+ // none of that resulted in better performance.
+ // -----------------------------------------------------------------------
+ EmOpcode68K opcode;
+ // opcode = get_iword (0);
+#if HAS_PROFILING
+ if (gProfilingEnabled)
+ get_word(regs.pc + ((char*) pc_p - (char*) pc_oldp));
+#endif
+ opcode = do_get_mem_word (pc_p);
+ fCycleCount += (functable[opcode]) (opcode);
+ // =======================================================================
+
+#if HAS_PROFILING
+ if (gProfilingEnabled)
+ {
+ // Add in the extra time taken to execute the instruction.
+
+ ProfileIncrementClock (perftbl[opcode].extraCycles);
+
+ // Detail (instruction level) profiling support
+
+ if (gProfilingDetailed)
+ {
+ ProfileInstructionExit (pcStart);
+ }
+
+#if HAS_PROFILING_DEBUG
+ // Validity check on EmMemory stuff.
+
+ Boolean tryAgain = false;
+
+ if (perftbl[opcode].readCycles != 0xFF &&
+ gReadCycles - readCyclesSaved != perftbl[opcode].readCycles)
+ {
+ gReadMismatch += gReadCycles - readCyclesSaved - perftbl[opcode].readCycles;
+ }
+
+ if (perftbl[opcode].writeCycles != 0xFF &&
+ gWriteCycles - writeCyclesSaved != perftbl[opcode].writeCycles)
+ {
+ gWriteMismatch += gWriteCycles - writeCyclesSaved - perftbl[opcode].writeCycles;
+ }
+
+ if (tryAgain)
+ {
+ (functable[opcode]) (opcode);
+ }
+#endif
+ }
+#endif
+
+ // Perform periodic tasks.
+
+ CYCLE (false);
+
+StoppedLoop:
+
+ // -----------------------------------------------------------------------
+ // Handle special conditions. NB: the code reached by calling
+ // EmCPU68K::ExecuteSpecial used to be inline in this function. Moving it
+ // out (thus simplifying both EmCPU68K::Execute and EmCPU68K::ExecuteSpecial)
+ // sped up the CPU loop by 9%!
+ // -----------------------------------------------------------------------
+
+ if (spcflags)
+ {
+ if (this->ExecuteSpecial ())
+ break;
+ }
+
+#if HAS_PROFILING
+ gProfilingCounted = false;
+#endif
+ } // while (1)
+
+#undef pc_p
+#undef pc_meta_oldp
+#undef pc_oldp
+#undef spcflags
+#undef session
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::ExecuteSimple
+// ---------------------------------------------------------------------------
+
+/*
+ This is the same loop with the following removed:
+
+ * Comments
+ * Profiling code
+ * Profiling debugging code
+ * Dead mans's check on Mac
+ * Register history recording
+
+ It's essentially what we get in Release/Non-profile builds.
+*/
+
+#if 0
+
+void EmCPU68K::ExecuteSimple (void)
+{
+ if ((regs.spcflags & SPCFLAG_STOP) != 0)
+ goto StoppedLoop;
+
+ while (1)
+ {
+ if (MetaMemory::IsCPUBreak (regs.pc_meta_oldp + (regs.pc_p - regs.pc_oldp)))
+ {
+ this->HandleInstructionBreak ();
+ }
+
+ EmOpcode68K opcode;
+ opcode = get_iword (0);
+ fCycleCount += cpufunctbl[opcode] (opcode);
+
+ this->Cycle (false);
+
+StoppedLoop:
+ if (regs.spcflags)
+ {
+ if (this->ExecuteSpecial ())
+ break;
+ }
+ }
+}
+
+#endif
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::ExecuteSpecial
+// ---------------------------------------------------------------------------
+
+Bool EmCPU68K::ExecuteSpecial (void)
+{
+ // If we're making subroutine calls, then all we process are requests
+ // to break from the CPU loop. We don't want interrupts, tracing, etc.
+ // getting in the way.
+
+ EmAssert (fSession);
+ if (fSession->IsNested () != 0)
+ {
+ return this->CheckForBreak ();
+ }
+
+ // Check for Reset first. If this is set, don't do anything else.
+
+ if ((regs.spcflags & SPCFLAG_END_OF_CYCLE))
+ {
+ if (fSession->ExecuteSpecial (true))
+ return true;
+ }
+
+ // Execute UAE spcflags-handling code (from do_specialties in newcpu.c).
+
+ // If we're tracing, execute the trace vector.
+ //
+ // The check for SPCFLAG_STOP was added in Poser. It's needed
+ // if we're re-entering ExecuteStopped loop on the Mac after
+ // exiting in order to handle events.
+
+ if ((regs.spcflags & SPCFLAG_DOTRACE) && !(regs.spcflags & SPCFLAG_STOP))
+ {
+ this->ProcessException (kException_Trace);
+ }
+
+ if (regs.spcflags & SPCFLAG_STOP)
+ {
+ if (this->ExecuteStoppedLoop ())
+ {
+ regs.spcflags &= ~SPCFLAG_BRK;
+ return true;
+ }
+ }
+
+ // Do trace-mode stuff (do_trace from newcpu.c does more,
+ // but it's only needed for CPU_LEVEL > 0)
+
+ if (regs.spcflags & SPCFLAG_TRACE)
+ {
+ if (regs.t1)
+ {
+ fLastTraceAddress = m68k_getpc ();
+ regs.spcflags &= ~SPCFLAG_TRACE;
+ regs.spcflags |= SPCFLAG_DOTRACE;
+ }
+ }
+
+ if ((regs.spcflags & SPCFLAG_DOINT) && !gKernelStackOverflowed)
+ {
+ int32 interruptLevel = EmHAL::GetInterruptLevel ();
+ regs.spcflags &= ~SPCFLAG_DOINT; // was ~(SPCFLAG_INT | SPCFLAG_DOINT) in Greg and Craig, but the latest UAE has this
+ if ((interruptLevel != -1) && (interruptLevel > regs.intmask))
+ {
+ this->ProcessInterrupt (interruptLevel);
+ regs.stopped = 0;
+ }
+ }
+
+ if (regs.spcflags & SPCFLAG_INT)
+ {
+ regs.spcflags &= ~SPCFLAG_INT;
+ regs.spcflags |= SPCFLAG_DOINT;
+ }
+
+ // Check for Poser end-of-cycle operations. This is inserted
+ // before the standard UAE check of the SPCFLAG_BRK flag.
+
+ if ((regs.spcflags & SPCFLAG_END_OF_CYCLE))
+ {
+ regs.spcflags &= ~SPCFLAG_END_OF_CYCLE;
+
+ if (fSession->ExecuteSpecial (false))
+ return true;
+ }
+
+ return this->CheckForBreak ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::ExecuteStoppedLoop
+// ---------------------------------------------------------------------------
+
+Bool EmCPU68K::ExecuteStoppedLoop (void)
+{
+ register EmSession* session = fSession;
+
+ EmAssert (session);
+ EmAssert (!session->IsNested ());
+ EmAssert (regs.intmask < 7);
+
+ // If we're running Gremlins and the device goes to sleep (as opposed
+ // to just dozing), pretend the user clicked on the Power button).
+
+ if (EmHAL::GetAsleep () && !session->HasButtonEvent ())
+ {
+ // Turns Hordes off for a moment, as pen events are rejected
+ // when it's running!
+
+ Bool hordesWasOn = false;
+ Bool playbackWasOn = false;
+ Bool minimizationWasOn = false;
+
+ if (Hordes::IsOn ())
+ {
+ Hordes::TurnOn (false);
+ hordesWasOn = true;
+ }
+
+ if (EmEventPlayback::ReplayingEvents ())
+ {
+ EmEventPlayback::ReplayEvents (false);
+ playbackWasOn = true;
+ }
+
+ if (EmMinimize::IsOn ())
+ {
+ EmMinimize::TurnOn (false);
+ minimizationWasOn = true;
+ }
+
+ /*
+ When posting the button down event for the Power button, include
+ a flag that causes the event to be posted to the hardware NOW.
+ Normally, EmSession employs a throttling mechanism that prevents
+ button events from showing up in the hardware too quickly. This
+ throttling allows the time for the OS to wakeup and respond to
+ the hardware interrupt.
+
+ However, the throttling also leads to an incredibly subtle bug
+ if it's used unconditionally. Consider the following sequence
+ of events:
+
+ * Gremlins creates a vchrAutoOff event
+ * The system responds to it and goes to sleep.
+ * Poser notices the device is asleep while running a Gremlin,
+ and posts Power button down/up events.
+ * It's been more than 100msec since the last button event, so
+ the button event is given to the hardware immediately.
+ * The system wakes up, notices that the Power key is down, and
+ sets the flag that says it should stay awake.
+ * Gremlins starts posting events again.
+ * Within 100msecs, Gremlins generates another vchrAutoOff event.
+ * The devices goes to sleep again. Somewhere in the process of
+ dealing with the vchrAutoOff event, the Power-button up event
+ is popped off and handled.
+ * Poser posts Power button down/up events again.
+ * Because it's been within 100msecs of the last time a button
+ event was popped off the queue, these events are held in the
+ queue for a while.
+ * An RTC interrupt occurs.
+ * The device wakes up, notices that the Power is not down, and
+ does NOT set the bit that says to stay awake.
+ * The devices goes back to sleep after processing the RTC
+ interrupt. Note that there are still two Power-button events
+ in EmSession's button queue.
+ * Poser notices that the device is off, and posts *another*
+ pair of Power-button down/up events.
+ * At this point, Poser is in a weird state, where there are too
+ many events in the queue. In fact, the situation will get
+ worse, with more and more events piling up and the system
+ deals with turning itself on and off in response to the pending
+ button events. The result is that the user sees the device
+ flashing on and off.
+
+ In order to avoid this problem, have the Power button posted to
+ the hardware registers immediately, before an interrupt can get
+ in the way.
+
+ Note that there is another potential bug here. We avoid it for
+ now, but be careful not to introduce it later. By passing "true"
+ to PostButtonEvent, we can make the button event available to
+ the hardware immediately. However, the event is not forced onto
+ the hardware. Instead, the hardware polls for any pending button
+ events at some reasonable rate. That is, even if EmSession is
+ prepared to say that there is a pending button event, EmCPU may
+ not pick up on it until some time later based on its checking
+ frequency.
+
+ We avoid this problem for now because the hardware checks for
+ button events in EmHAL::CycleSlowly, which is called
+ unconditionally when the processor is moved out of the "stopped"
+ state.
+ */
+
+ if (hordesWasOn || playbackWasOn || minimizationWasOn)
+ {
+ EmButtonEvent event (kElement_PowerButton, true);
+ session->PostButtonEvent (event, true);
+
+ event.fButtonIsDown = false;
+ session->PostButtonEvent (event);
+ }
+
+ if (hordesWasOn)
+ {
+ Hordes::TurnOn (true);
+ }
+
+ if (playbackWasOn)
+ {
+ EmEventPlayback::ReplayEvents (true);
+ }
+
+ if (minimizationWasOn)
+ {
+ EmMinimize::TurnOn (true);
+ }
+ }
+
+ int counter = 0;
+
+ // While the CPU is stopped (because a STOP instruction was
+ // executed) do some idle tasks.
+
+#if HAS_DEAD_MANS_SWITCH
+ // -----------------------------------------------------------------------
+ // Put in a little dead-man's switch. If this function doesn't
+ // exit for a long time, let us get into the debugger.
+ // -----------------------------------------------------------------------
+
+ uint32 deadManStart = Platform::GetMilliseconds ();
+#endif
+
+ do {
+#if HAS_DEAD_MANS_SWITCH
+ // -----------------------------------------------------------------------
+ // Put in a little dead-man's switch. If this function doesn't
+ // exit for a long time, let us get into the debugger.
+ // -----------------------------------------------------------------------
+
+ uint32 deadManNow = Platform::GetMilliseconds ();
+ if ((deadManNow - deadManStart) > 5000)
+ {
+ Platform::Debugger ();
+ }
+#endif
+
+ // -----------------------------------------------------------------------
+ // Slow down processing so that the timer used
+ // to increment the tickcount doesn't run too quickly.
+ // -----------------------------------------------------------------------
+
+#if __profile__
+ short oldStatus = ProfilerGetStatus ();
+ ProfilerSetStatus (false);
+#endif
+
+ Platform::Delay ();
+
+#if __profile__
+ ProfilerSetStatus (oldStatus);
+#endif
+
+ // Perform periodic tasks.
+
+ CYCLE (true);
+
+ // Process an interrupt (see if it's time to wake up).
+
+ if (regs.spcflags & (SPCFLAG_INT | SPCFLAG_DOINT))
+ {
+ int32 interruptLevel = EmHAL::GetInterruptLevel ();
+
+ regs.spcflags &= ~(SPCFLAG_INT | SPCFLAG_DOINT);
+
+ if ((interruptLevel != -1) && (interruptLevel > regs.intmask))
+ {
+ this->ProcessInterrupt (interruptLevel);
+ regs.stopped = 0;
+ regs.spcflags &= ~SPCFLAG_STOP;
+ }
+ }
+
+ if (this->CheckForBreak ())
+ {
+ return true;
+ }
+ } while (regs.spcflags & SPCFLAG_STOP);
+
+ return false;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::CycleSlowly
+// ---------------------------------------------------------------------------
+
+void EmCPU68K::CycleSlowly (Bool sleeping)
+{
+ EmHAL::CycleSlowly (sleeping);
+
+ // Do some platform-specific stuff.
+
+ Platform::CycleSlowly ();
+
+#if HAS_OMNI_THREAD
+ // Check to see if some external thread has asked us to quit.
+
+ EmAssert (fSession);
+ omni_mutex_lock lock (fSession->fSharedLock);
+
+ if (fSession->fSuspendState.fAllCounters)
+ {
+ this->CheckAfterCycle ();
+ }
+#endif
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::CheckAfterCycle
+// ---------------------------------------------------------------------------
+
+void EmCPU68K::CheckAfterCycle (void)
+{
+ regs.spcflags |= SPCFLAG_END_OF_CYCLE;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::GetPC
+// ---------------------------------------------------------------------------
+
+emuptr EmCPU68K::GetPC (void)
+{
+// return this->GetRegister (e68KRegID_PC);
+ return m68k_getpc ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::GetSP
+// ---------------------------------------------------------------------------
+
+emuptr EmCPU68K::GetSP (void)
+{
+// return this->GetRegister (e68KRegID_SSP);
+ return m68k_areg (regs, 7);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::GetRegister
+// ---------------------------------------------------------------------------
+
+uint32 EmCPU68K::GetRegister (int index)
+{
+ uint32 result = 0;
+
+ switch (index)
+ {
+ case e68KRegID_D0: result = m68k_dreg (regs, 0); break;
+ case e68KRegID_D1: result = m68k_dreg (regs, 1); break;
+ case e68KRegID_D2: result = m68k_dreg (regs, 2); break;
+ case e68KRegID_D3: result = m68k_dreg (regs, 3); break;
+ case e68KRegID_D4: result = m68k_dreg (regs, 4); break;
+ case e68KRegID_D5: result = m68k_dreg (regs, 5); break;
+ case e68KRegID_D6: result = m68k_dreg (regs, 6); break;
+ case e68KRegID_D7: result = m68k_dreg (regs, 7); break;
+ case e68KRegID_A0: result = m68k_areg (regs, 0); break;
+ case e68KRegID_A1: result = m68k_areg (regs, 1); break;
+ case e68KRegID_A2: result = m68k_areg (regs, 2); break;
+ case e68KRegID_A3: result = m68k_areg (regs, 3); break;
+ case e68KRegID_A4: result = m68k_areg (regs, 4); break;
+ case e68KRegID_A5: result = m68k_areg (regs, 5); break;
+ case e68KRegID_A6: result = m68k_areg (regs, 6); break;
+ case e68KRegID_USP: result = m68k_areg (regs, 7); break;
+ case e68KRegID_SSP: result = m68k_areg (regs, 7); break;
+ case e68KRegID_PC: result = m68k_getpc (); break;
+ case e68KRegID_SR:
+ this->UpdateSRFromRegisters ();
+ result = regs.sr;
+ break;
+
+ default:
+ EmAssert (false);
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::SetPC
+// ---------------------------------------------------------------------------
+
+void EmCPU68K::SetPC (emuptr newPC)
+{
+ this->SetRegister (e68KRegID_PC, newPC);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::SetSP
+// ---------------------------------------------------------------------------
+
+void EmCPU68K::SetSP (emuptr newPC)
+{
+ this->SetRegister (e68KRegID_SSP, newPC);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::SetRegister
+// ---------------------------------------------------------------------------
+
+void EmCPU68K::SetRegister (int index, uint32 val)
+{
+ switch (index)
+ {
+ case e68KRegID_D0: m68k_dreg (regs, 0) = val; break;
+ case e68KRegID_D1: m68k_dreg (regs, 1) = val; break;
+ case e68KRegID_D2: m68k_dreg (regs, 2) = val; break;
+ case e68KRegID_D3: m68k_dreg (regs, 3) = val; break;
+ case e68KRegID_D4: m68k_dreg (regs, 4) = val; break;
+ case e68KRegID_D5: m68k_dreg (regs, 5) = val; break;
+ case e68KRegID_D6: m68k_dreg (regs, 6) = val; break;
+ case e68KRegID_D7: m68k_dreg (regs, 7) = val; break;
+ case e68KRegID_A0: m68k_areg (regs, 0) = val; break;
+ case e68KRegID_A1: m68k_areg (regs, 1) = val; break;
+ case e68KRegID_A2: m68k_areg (regs, 2) = val; break;
+ case e68KRegID_A3: m68k_areg (regs, 3) = val; break;
+ case e68KRegID_A4: m68k_areg (regs, 4) = val; break;
+ case e68KRegID_A5: m68k_areg (regs, 5) = val; break;
+ case e68KRegID_A6: m68k_areg (regs, 6) = val; break;
+ case e68KRegID_USP: m68k_areg (regs, 7) = val; break;
+ case e68KRegID_SSP: m68k_areg (regs, 7) = val; break;
+ case e68KRegID_PC: m68k_setpc (val); break;
+ case e68KRegID_SR:
+ regs.sr = val;
+ this->UpdateRegistersFromSR ();
+ break;
+
+ default:
+ EmAssert (false);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::Stopped
+// ---------------------------------------------------------------------------
+// Return whether or not the CPU itself is halted. This is seperate from
+// whether or not the session (that is, the thread emulating the CPU) is
+// halted.
+
+Bool EmCPU68K::Stopped (void)
+{
+ return regs.stopped;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::CheckForBreak
+// ---------------------------------------------------------------------------
+// Check to see if the conditions tell us to break from the CPU Execute loop.
+
+Bool EmCPU68K::CheckForBreak (void)
+{
+ if ((regs.spcflags & SPCFLAG_BRK) != 0)
+ {
+ regs.spcflags &= ~SPCFLAG_BRK;
+ return true;
+ }
+
+ EmAssert (fSession);
+ return fSession->CheckForBreak ();
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::ProcessInterrupt
+// ---------------------------------------------------------------------------
+
+void EmCPU68K::ProcessInterrupt (int32 interrupt)
+{
+ this->ProcessException ((ExceptionNumber) (EmHAL::GetInterruptBase () + interrupt));
+
+ regs.intmask = interrupt;
+ regs.spcflags |= SPCFLAG_INT; // Check for higher-level interrupts
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::ProcessException
+// ---------------------------------------------------------------------------
+
+void EmCPU68K::ProcessException (ExceptionNumber exception)
+{
+ // Make sure the Status Register is up-to-date.
+
+ this->UpdateSRFromRegisters ();
+
+#if EXCEPTION_HISTORY
+ // Save the exception for the post-mortem
+
+ fExceptionHistoryIndex++;
+
+ long index = fExceptionHistoryIndex & (kExceptionHistorySize - 1);
+ fExceptionHistory[index].name = kExceptionNames[exception];
+
+ fExceptionHistory[index].pc = m68k_getpc ();
+ fExceptionHistory[index].sp = m68k_areg (regs, 7);
+#endif
+
+#if HAS_PROFILING
+ // Don't count cycles spent in exception handlers against functions.
+
+ // Get and remember the current PC here. This is important to make the
+ // profiling routines come out right. If Poser decides to completely
+ // handle the exception and profiling is on, then the handler will return
+ // true (setting "handled" to true), and adjust the program counter.
+ // Since "handled" is true, Poser calls ProfileInterruptExit, this time
+ // with the current PC. ProfileInterruptExit sees the adjusted PC, and
+ // determines that the funky TRAP $F thing is going on, resulting in it
+ // pushing a new function-call record on its stack. However, since Poser
+ // has completely handled the interrupt, we don't want that to happen.
+ // All we want is to remove the entry recorded by ProfileInterruptEnter.
+ // By saving the current PC value here and passing it to ProfileInterruptExit
+ // later, we achieve that affect. ProfileInterruptExit will record an
+ // "interrupt mismatch", but I can live with that...
+
+ emuptr curpc = m68k_getpc ();
+
+ if (gProfilingEnabled)
+ {
+ ProfileInterruptEnter (exception, curpc);
+ }
+#endif
+
+ // Let any custom exception handler have a go at it. If it returns
+ // true, it handled it completely, and we don't have anything else to do.
+ //
+ // By "handled it completely", we could mean one of two things. (1)
+ // that Poser completely replaced the system function and the ROM
+ // function was skipped, or (2) Poser dealt with the trap dispatch
+ // process, setting the PC to the function entry point.
+ //
+ // If profiling is on, (2) never occurs because we want to profile the
+ // trap dispatcher itself. Therefore, only (1) is possible.
+
+ Bool handled = false;
+ Hook68KExceptionList& fns = fExceptionHandlers[exception];
+ Hook68KExceptionList::iterator iter = fns.begin ();
+ while (iter != fns.end ())
+ {
+ if ((*iter) (exception))
+ {
+ handled = true;
+ }
+
+ ++iter;
+ }
+
+ if (handled)
+ {
+#if HAS_PROFILING
+ if (gProfilingEnabled)
+ {
+ ProfileInterruptExit (curpc);
+ }
+#endif
+ return;
+ }
+
+ // The following is vaguely modelled after Exception() from newcpu.c
+ // (The call to MakeSR appears at the start of this method).
+
+ // If not in supervisor mode, set the usp, restore A7 from the isp,
+ // and transfer to supervisor mode.
+
+ if (!regs.s)
+ {
+ regs.usp = m68k_areg (regs, 7);
+ m68k_areg (regs, 7) = regs.isp;
+ regs.s = 1;
+ }
+
+ // Set up the stack frame.
+ // !!! If we're handling a trace exception, I think that fLastTraceAddress
+ // comes into play here instead of m68k_getpc.
+ // !!! Manage this with EmPalmStructs...
+
+ if (exception == kException_BusErr || exception == kException_AddressErr)
+ {
+ COMPILE_TIME_ASSERT (sizeof (ExceptionStackFrame2) == 14);
+ m68k_areg (regs, 7) -= sizeof (ExceptionStackFrame2);
+ CHECK_STACK_POINTER_DECREMENT ();
+
+ emuptr frame = m68k_areg (regs, 7);
+
+ // Eh...Palm OS doesn't use these 3 anyway...
+ EmMemPut16 (frame + offsetof (ExceptionStackFrame2, functionCode), 0);
+ EmMemPut32 (frame + offsetof (ExceptionStackFrame2, accessAddress), 0);
+ EmMemPut16 (frame + offsetof (ExceptionStackFrame2, instructionRegister), 0);
+
+ EmMemPut16 (frame + offsetof (ExceptionStackFrame2, statusRegister), regs.sr);
+ EmMemPut32 (frame + offsetof (ExceptionStackFrame2, programCounter), m68k_getpc ());
+ }
+ else
+ {
+ COMPILE_TIME_ASSERT (sizeof (ExceptionStackFrame1) == 6);
+ m68k_areg (regs, 7) -= sizeof (ExceptionStackFrame1);
+ CHECK_STACK_POINTER_DECREMENT ();
+
+ emuptr frame = m68k_areg (regs, 7);
+
+ EmMemPut16 (frame + offsetof (ExceptionStackFrame1, statusRegister), regs.sr);
+ EmMemPut32 (frame + offsetof (ExceptionStackFrame1, programCounter), m68k_getpc ());
+ }
+
+ emuptr newpc;
+ {
+ CEnableFullAccess munge; // Remove blocks on memory access.
+
+ // Get the exception handler address.
+ newpc = EmMemGet32 (regs.vbr + 4 * exception);
+ }
+
+ // Check the exception handler address and jam it into the PC.
+
+ this->CheckNewPC (newpc);
+ m68k_setpc (newpc);
+
+ // Turn tracing off.
+
+ regs.t1 = regs.t0 = regs.m = 0;
+ regs.spcflags &= ~(SPCFLAG_TRACE | SPCFLAG_DOTRACE);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::ProcessIllegalInstruction
+// ---------------------------------------------------------------------------
+
+void EmCPU68K::ProcessIllegalInstruction (EmOpcode68K opcode)
+{
+ // This function is loosely based on op_illg in newcpu.c
+
+ // Process an FTrap.
+
+ if ((opcode & 0xF000) == 0xF000)
+ {
+ this->ProcessException (kException_FTrap);
+ }
+
+ // Process an ATrap.
+
+ else if ((opcode & 0xF000) == 0xA000)
+ {
+ this->ProcessException (kException_ATrap);
+ }
+
+ // Process all other opcodes.
+
+ else
+ {
+ this->ProcessException (kException_IllegalInstr);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::ProcessJSR
+// ---------------------------------------------------------------------------
+
+int EmCPU68K::ProcessJSR (emuptr oldPC, emuptr dest)
+{
+ int handled = false;
+
+ Hook68KJSRList::iterator iter = fHookJSR.begin ();
+ while (iter != fHookJSR.end ())
+ {
+ if ((*iter) (oldPC, dest))
+ {
+ handled = true;
+ }
+
+ ++iter;
+ }
+
+ return handled;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::ProcessJSR_Ind
+// ---------------------------------------------------------------------------
+
+int EmCPU68K::ProcessJSR_Ind (emuptr oldPC, emuptr dest)
+{
+ int handled = false;
+
+ Hook68KJSR_IndList::iterator iter = fHookJSR_Ind.begin ();
+ while (iter != fHookJSR_Ind.end ())
+ {
+ if ((*iter) (oldPC, dest))
+ {
+ handled = true;
+ }
+
+ ++iter;
+ }
+
+ return handled;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::ProcessLINK
+// ---------------------------------------------------------------------------
+
+void EmCPU68K::ProcessLINK (int linkSize)
+{
+ Hook68KLINKList::iterator iter = fHookLINK.begin ();
+ while (iter != fHookLINK.end ())
+ {
+ (*iter) (linkSize);
+
+ ++iter;
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::ProcessRTE
+// ---------------------------------------------------------------------------
+
+int EmCPU68K::ProcessRTE (emuptr dest)
+{
+ int handled = false;
+
+ Hook68KRTEList::iterator iter = fHookRTE.begin ();
+ while (iter != fHookRTE.end ())
+ {
+ if ((*iter) (dest))
+ {
+ handled = true;
+ }
+
+ ++iter;
+ }
+
+ return handled;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::ProcessRTS
+// ---------------------------------------------------------------------------
+
+int EmCPU68K::ProcessRTS (emuptr dest)
+{
+ int handled = false;
+
+ Hook68KRTSList::iterator iter = fHookRTS.begin ();
+ while (iter != fHookRTS.end ())
+ {
+ if ((*iter) (dest))
+ {
+ handled = true;
+ }
+
+ ++iter;
+ }
+
+ return handled;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::CheckNewPC
+// ---------------------------------------------------------------------------
+
+void EmCPU68K::CheckNewPC (emuptr dest)
+{
+ Hook68KNewPCList::iterator iter = fHookNewPC.begin ();
+ while (iter != fHookNewPC.end ())
+ {
+ (*iter) (dest);
+
+ ++iter;
+ }
+
+ EmMemory::CheckNewPC (dest);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::CheckNewSP
+// ---------------------------------------------------------------------------
+
+void EmCPU68K::CheckNewSP (EmStackChangeType type)
+{
+ Hook68KNewSPList::iterator iter = fHookNewSP.begin ();
+ while (iter != fHookNewSP.end ())
+ {
+ (*iter) (type);
+
+ ++iter;
+ }
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::InstallHookException
+// ¥ EmCPU68K::InstallHookJSR
+// ¥ EmCPU68K::InstallHookJSR_Ind
+// ¥ EmCPU68K::InstallHookLINK
+// ¥ EmCPU68K::InstallHookRTE
+// ¥ EmCPU68K::InstallHookRTS
+// ¥ EmCPU68K::InstallHookNewPC
+// ¥ EmCPU68K::InstallHookNewSP
+// ---------------------------------------------------------------------------
+
+void EmCPU68K::InstallHookException (ExceptionNumber exceptionNumber,
+ Hook68KException fn)
+{
+ fExceptionHandlers[exceptionNumber].push_back (fn);
+}
+
+
+void EmCPU68K::InstallHookJSR (Hook68KJSR fn)
+{
+ fHookJSR.push_back (fn);
+}
+
+
+void EmCPU68K::InstallHookJSR_Ind (Hook68KJSR_Ind fn)
+{
+ fHookJSR_Ind.push_back (fn);
+}
+
+
+void EmCPU68K::InstallHookLINK (Hook68KLINK fn)
+{
+ fHookLINK.push_back (fn);
+}
+
+
+void EmCPU68K::InstallHookRTE (Hook68KRTE fn)
+{
+ fHookRTE.push_back (fn);
+}
+
+
+void EmCPU68K::InstallHookRTS (Hook68KRTS fn)
+{
+ fHookRTS.push_back (fn);
+}
+
+
+void EmCPU68K::InstallHookNewPC (Hook68KNewPC fn)
+{
+ fHookNewPC.push_back (fn);
+}
+
+
+void EmCPU68K::InstallHookNewSP (Hook68KNewSP fn)
+{
+ fHookNewSP.push_back (fn);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::RemoveHookException
+// ¥ EmCPU68K::RemoveHookJSR
+// ¥ EmCPU68K::RemoveHookJSR_Ind
+// ¥ EmCPU68K::RemoveHookLINK
+// ¥ EmCPU68K::RemoveHookRTE
+// ¥ EmCPU68K::RemoveHookRTS
+// ¥ EmCPU68K::RemoveHookNewPC
+// ¥ EmCPU68K::RemoveHookNewSP
+// ---------------------------------------------------------------------------
+
+void EmCPU68K::RemoveHookException (ExceptionNumber exceptionNumber,
+ Hook68KException fn)
+{
+ Hook68KExceptionList::iterator iter = find (
+ fExceptionHandlers[exceptionNumber].begin (),
+ fExceptionHandlers[exceptionNumber].end (),
+ fn);
+
+ if (iter != fExceptionHandlers[exceptionNumber].end ())
+ {
+ fExceptionHandlers[exceptionNumber].erase (iter);
+ }
+}
+
+
+void EmCPU68K::RemoveHookJSR (Hook68KJSR fn)
+{
+ Hook68KJSRList::iterator iter = find (fHookJSR.begin (), fHookJSR.end (), fn);
+
+ if (iter != fHookJSR.end ())
+ {
+ fHookJSR.erase (iter);
+ }
+}
+
+
+void EmCPU68K::RemoveHookJSR_Ind (Hook68KJSR_Ind fn)
+{
+ Hook68KJSR_IndList::iterator iter = find (fHookJSR_Ind.begin (), fHookJSR_Ind.end (), fn);
+
+ if (iter != fHookJSR_Ind.end ())
+ {
+ fHookJSR_Ind.erase (iter);
+ }
+}
+
+
+void EmCPU68K::RemoveHookLINK (Hook68KLINK fn)
+{
+ Hook68KLINKList::iterator iter = find (fHookLINK.begin (), fHookLINK.end (), fn);
+
+ if (iter != fHookLINK.end ())
+ {
+ fHookLINK.erase (iter);
+ }
+}
+
+
+void EmCPU68K::RemoveHookRTE (Hook68KRTE fn)
+{
+ Hook68KRTEList::iterator iter = find (fHookRTE.begin (), fHookRTE.end (), fn);
+
+ if (iter != fHookRTE.end ())
+ {
+ fHookRTE.erase (iter);
+ }
+}
+
+
+void EmCPU68K::RemoveHookRTS (Hook68KRTS fn)
+{
+ Hook68KRTSList::iterator iter = find (fHookRTS.begin (), fHookRTS.end (), fn);
+
+ if (iter != fHookRTS.end ())
+ {
+ fHookRTS.erase (iter);
+ }
+}
+
+
+void EmCPU68K::RemoveHookNewPC (Hook68KNewPC fn)
+{
+ Hook68KNewPCList::iterator iter = find (fHookNewPC.begin (), fHookNewPC.end (), fn);
+
+ if (iter != fHookNewPC.end ())
+ {
+ fHookNewPC.erase (iter);
+ }
+}
+
+
+void EmCPU68K::RemoveHookNewSP (Hook68KNewSP fn)
+{
+ Hook68KNewSPList::iterator iter = find (fHookNewSP.begin (), fHookNewSP.end (), fn);
+
+ if (iter != fHookNewSP.end ())
+ {
+ fHookNewSP.erase (iter);
+ }
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::GetRegisters
+// ---------------------------------------------------------------------------
+
+void EmCPU68K::GetRegisters (regstruct& registers)
+{
+ this->UpdateSRFromRegisters ();
+
+ registers = regs;
+ registers.pc = m68k_getpc ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::SetRegisters
+// ---------------------------------------------------------------------------
+
+void EmCPU68K::SetRegisters (regstruct& registers)
+{
+ regs = registers;
+ this->UpdateRegistersFromSR ();
+
+ m68k_setpc (registers.pc);
+
+ this->CheckNewSP (kStackPointerChanged);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::UpdateSRFromRegisters
+// ---------------------------------------------------------------------------
+// Create a 16-bit status register value from the broken out fields. In
+// general, we keep the various fields separate for speed of access. However,
+// there are times when we need the packed 16-bit field.
+//
+// This function is called any time the 16-bit representation of the SR is
+// needed:
+//
+// on EORSR
+// on ORSR
+// on ANDSR
+// on MVSR2
+// on MV2SR
+// on RTR
+// when processing exceptions (EmCPU68K::ProcessException)
+//
+// SystemPacket::GetRegs
+// EmCPU68K::GetRegisters
+
+void EmCPU68K::UpdateSRFromRegisters (void)
+{
+ // (taken from MakeSR in newcpu.c)
+
+ regs.sr = ((regs.t1 << 15) | (regs.t0 << 14)
+ | (regs.s << 13) | (regs.m << 12) | (regs.intmask << 8)
+ | (GET_XFLG << 4) | (GET_NFLG << 3) | (GET_ZFLG << 2) | (GET_VFLG << 1)
+ | GET_CFLG);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::UpdateRegistersFromSR
+// ---------------------------------------------------------------------------
+// Break out all of the fields from the 16-bit status register into their own
+// separate variables.
+//
+// This function is called any time the SR has been update and needs to be
+// re-expanded:
+//
+// on EORSR
+// on ORSR
+// on ANDSR
+// on MV2SR
+// on STOP
+// on RTE
+// on RTR
+//
+// SystemPacket::SetRegs
+// EmCPU68K::SetRegisters
+
+void EmCPU68K::UpdateRegistersFromSR (void)
+{
+ // (taken from MakeFromSR in newcpu.c)
+
+// int oldm = regs.m;
+ int olds = regs.s;
+
+ regs.t1 = (regs.sr >> 15) & 1;
+ regs.t0 = (regs.sr >> 14) & 1;
+ regs.s = (regs.sr >> 13) & 1;
+ regs.m = (regs.sr >> 12) & 1;
+ regs.intmask = (regs.sr >> 8) & 7;
+
+ SET_XFLG ((regs.sr >> 4) & 1);
+ SET_NFLG ((regs.sr >> 3) & 1);
+ SET_ZFLG ((regs.sr >> 2) & 1);
+ SET_VFLG ((regs.sr >> 1) & 1);
+ SET_CFLG (regs.sr & 1);
+
+ if (olds != regs.s)
+ {
+ if (olds)
+ {
+ regs.isp = m68k_areg(regs, 7);
+ m68k_areg(regs, 7) = regs.usp;
+ }
+ else
+ {
+ regs.usp = m68k_areg(regs, 7);
+ m68k_areg(regs, 7) = regs.isp;
+ }
+ }
+
+ regs.spcflags |= SPCFLAG_INT;
+
+ if (regs.t1 || regs.t0)
+ {
+ regs.spcflags |= SPCFLAG_TRACE;
+ }
+ else
+ {
+ regs.spcflags &= ~(SPCFLAG_TRACE | SPCFLAG_DOTRACE);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::GetCycleCount
+// ---------------------------------------------------------------------------
+
+uint32 EmCPU68K::GetCycleCount (void)
+{
+ return fCycleCount;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::BusError
+// ---------------------------------------------------------------------------
+
+void EmCPU68K::BusError (emuptr address, long size, Bool forRead)
+{
+ gExceptionAddress = address;
+ gExceptionSize = size;
+ gExceptionForRead = forRead;
+
+ this->ProcessException (kException_BusErr);
+
+ EmAssert (false); // Should never get this far.
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::AddressError
+// ---------------------------------------------------------------------------
+
+void EmCPU68K::AddressError (emuptr address, long size, Bool forRead)
+{
+ gExceptionAddress = address;
+ gExceptionSize = size;
+ gExceptionForRead = forRead;
+
+ this->ProcessException (kException_AddressErr);
+
+ EmAssert (false); // Should never get this far.
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPU68K::InitializeUAETables
+// ---------------------------------------------------------------------------
+
+void EmCPU68K::InitializeUAETables (void)
+{
+ static int initialized;
+
+ // All of the stuff in this function needs to be done only once;
+ // it doesn't need to be executed every time we create a new CPU.
+
+ if (initialized)
+ return;
+
+ initialized = true;
+
+ // Initialize some CPU-related tables
+ // (This initialization code is taken from init_m68k in newcpu.c)
+
+ int i, j;
+
+ for (i = 0 ; i < 256 ; i++)
+ {
+ for (j = 0 ; j < 8 ; j++)
+ {
+ if (i & (1 << j))
+ {
+ break;
+ }
+ }
+
+ movem_index1[i] = j;
+ movem_index2[i] = 7-j;
+ movem_next[i] = i & (~(1 << j));
+ }
+
+ read_table68k ();
+ do_merges ();
+
+ // The rest of this code is based on build_cpufunctbl in newcpu.c.
+
+ unsigned long opcode;
+ struct cputbl* tbl = op_smalltbl_3;
+
+ for (opcode = 0; opcode < 65536; opcode++)
+ {
+ cpufunctbl[opcode] = op_illg;
+ }
+
+ for (i = 0; tbl[i].handler != NULL; i++)
+ {
+ if (!tbl[i].specific)
+ {
+ cpufunctbl[tbl[i].opcode] = tbl[i].handler;
+#if HAS_PROFILING
+ perftbl[tbl[i].opcode] = tbl[i].perf;
+#endif
+ }
+ }
+
+ for (opcode = 0; opcode < 65536; opcode++)
+ {
+ cpuop_func* f;
+
+ if (table68k[opcode].mnemo == i_ILLG || table68k[opcode].clev > 0)
+ {
+ continue;
+ }
+
+ if (table68k[opcode].handler != -1)
+ {
+ f = cpufunctbl[table68k[opcode].handler];
+ if (f == op_illg)
+ {
+ abort ();
+ }
+
+ cpufunctbl[opcode] = f;
+#if HAS_PROFILING
+ perftbl[opcode] = perftbl[table68k[opcode].handler];
+#endif
+
+ }
+ }
+
+ for (i = 0; tbl[i].handler != NULL; i++)
+ {
+ if (tbl[i].specific)
+ {
+ cpufunctbl[tbl[i].opcode] = tbl[i].handler;
+#if HAS_PROFILING
+ perftbl[tbl[i].opcode] = tbl[i].perf;
+#endif
+ }
+ }
+
+ // (hey readcpu doesn't free this guy!)
+
+ Platform::DisposeMemory (table68k);
+}
diff --git a/SrcShared/Hardware/EmCPU68K.h b/SrcShared/Hardware/EmCPU68K.h
new file mode 100644
index 0000000..1cdfa08
--- /dev/null
+++ b/SrcShared/Hardware/EmCPU68K.h
@@ -0,0 +1,334 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmCPU68K_h
+#define EmCPU68K_h
+
+#include "EmCPU.h" // EmCPU
+
+#include <vector> // vector
+
+#if REGISTER_HISTORY
+#include "UAE.h" // regstruct
+#else
+struct regstruct;
+#endif
+
+const uint16 kATrapReturnTrapNum = 0x0C;
+
+/*---------------------------------------------------------------------
+ * Register numbering for 68K. Each register must have a unique
+ * non-zero register number.
+ *--------------------------------------------------------------------*/
+enum EmCPU68KRegID
+{
+ e68KRegID_Invalid = 0, /* Zero is an invalid register number */
+ e68KRegID_D0 = 1,
+ e68KRegID_D1 = 2,
+ e68KRegID_D2 = 3,
+ e68KRegID_D3 = 4,
+ e68KRegID_D4 = 5,
+ e68KRegID_D5 = 6,
+ e68KRegID_D6 = 7,
+ e68KRegID_D7 = 8,
+ e68KRegID_A0 = 9,
+ e68KRegID_A1 = 10,
+ e68KRegID_A2 = 11,
+ e68KRegID_A3 = 12,
+ e68KRegID_A4 = 13,
+ e68KRegID_A5 = 14,
+ e68KRegID_A6 = 15,
+ e68KRegID_USP = 16,
+ e68KRegID_SSP = 17,
+ e68KRegID_PC = 18,
+ e68KRegID_SR = 19
+};
+
+
+enum ExceptionNumber
+{
+ kException_BusErr = 2, // 08 / 2
+ kException_AddressErr, // 0C / 3
+ kException_IllegalInstr, // 10 / 4
+ kException_DivideByZero, // 14 / 5
+ kException_Chk, // 18 / 6
+ kException_Trap, // 1C / 7
+ kException_Privilege, // 20 / 8
+ kException_Trace, // 24 / 9
+ kException_ATrap, // 28 / A
+ kException_FTrap, // 2C / B
+ kException_Reseved12, // 30 / C
+ kException_Coproc, // 34 / D
+ kException_FormatErr, // 38 / E
+ kException_UninitializedInt, // 3C / F
+
+ kException_Reserved0, // 40-5C / 10-17
+ kException_Reserved1,
+ kException_Reserved2,
+ kException_Reserved3,
+ kException_Reserved4,
+ kException_Reserved5,
+ kException_Reserved6,
+ kException_Reserved7,
+
+ kException_SpuriousInt, // 60 / 18
+ kException_AutoVec1, // 64 / 19
+ kException_AutoVec2, // 68 / 1A
+ kException_AutoVec3, // 6C / 1B
+ kException_AutoVec4, // 70 / 1C
+ kException_AutoVec5, // 74 / 1D
+ kException_AutoVec6, // 78 / 1E
+ kException_AutoVec7, // 7C / 1F
+
+ kException_Trap0, // 80 - BC / 20 - 2F // For soft breakpoints
+ kException_Trap1,
+ kException_Trap2,
+ kException_Trap3,
+ kException_Trap4,
+ kException_Trap5,
+ kException_Trap6,
+ kException_Trap7,
+ kException_Trap8, // For compiled breakpoints
+ kException_Trap9,
+ kException_Trap10,
+ kException_Trap11,
+ kException_Trap12,
+ kException_Trap13, // ATrap returns (emulator convention)
+ kException_Trap14,
+ kException_Trap15, // Trap dispatcher
+
+ kException_Unassigned0, // C0 - FC / 30 - 3F
+ kException_Unassigned1,
+ kException_Unassigned2,
+ kException_Unassigned3,
+ kException_Unassigned4,
+ kException_Unassigned5,
+ kException_Unassigned6,
+ kException_Unassigned7,
+ kException_Unassigned8,
+ kException_Unassigned9,
+ kException_Unassigned10,
+ kException_Unassigned11,
+ kException_Unassigned12,
+ kException_Unassigned13,
+ kException_Unassigned14,
+ kException_Unassigned15,
+
+ kException_LastException,
+
+ kException_SoftBreak = kException_Trap0 + sysDbgBreakpointTrapNum,
+ kException_HardBreak = kException_Trap0 + sysDbgTrapNum,
+ kException_SysCall = kException_Trap0 + sysDispatchTrapNum,
+ kException_ATrapReturn = kException_Trap0 + kATrapReturnTrapNum
+};
+
+/*
+ Grr...this function doesn't appear to be "seen" by VC++. Even in its
+ presence, an expression involving an ExceptionNumber and an int
+ results in the message "error C2440: 'initializing' : cannot convert
+ from 'const int' to 'const enum ExceptionNumber'"
+
+inline ExceptionNumber operator+ (ExceptionNumber left, int right)
+{
+ // NB: cast "left" to an integer, or this routine will recurse!
+ return (ExceptionNumber) ((int) left + right);
+}
+*/
+
+#if EXCEPTION_HISTORY
+
+struct ExceptionHistoryType
+{
+ const char* name;
+ uint32 pc;
+ uint32 sp;
+};
+
+#endif
+
+// Using uint32 instead of uint16 generates slightly better code.
+typedef uint32 EmOpcode68K;
+
+enum EmStackChangeType
+{
+ kStackPointerChanged,
+ kStackPointerIncremented,
+ kStackPointerDecremented,
+ kStackPointerKernelStackHack
+};
+
+class EmCPU68K;
+typedef Bool (*Hook68KException) (ExceptionNumber);
+typedef Bool (*Hook68KJSR) (emuptr oldPC, emuptr dest);
+typedef Bool (*Hook68KJSR_Ind) (emuptr oldPC, emuptr dest);
+typedef void (*Hook68KLINK) (int linkSize);
+typedef Bool (*Hook68KRTE) (emuptr dest);
+typedef Bool (*Hook68KRTS) (emuptr dest);
+typedef void (*Hook68KNewPC) (emuptr dest);
+typedef void (*Hook68KNewSP) (EmStackChangeType);
+
+typedef vector<Hook68KException> Hook68KExceptionList;
+typedef vector<Hook68KJSR> Hook68KJSRList;
+typedef vector<Hook68KJSR_Ind> Hook68KJSR_IndList;
+typedef vector<Hook68KLINK> Hook68KLINKList;
+typedef vector<Hook68KRTE> Hook68KRTEList;
+typedef vector<Hook68KRTS> Hook68KRTSList;
+typedef vector<Hook68KNewPC> Hook68KNewPCList;
+typedef vector<Hook68KNewSP> Hook68KNewSPList;
+
+class EmCPU68K;
+extern EmCPU68K* gCPU68K;
+
+// These variables should strictly be in a sub-system that implements
+// the stack overflow checking, etc. However, for performance reasons,
+// we need to expose them to UAE (see the CHECK_STACK_POINTER_ASSIGNMENT,
+// et al macros), so define them here.
+//
+// Similar comments for the CheckKernelStack function.
+
+extern "C" uint32 gStackHigh;
+extern "C" uint32 gStackLowWarn;
+extern "C" uint32 gStackLow;
+extern "C" uint32 gKernelStackOverflowed;
+
+
+class EmCPU68K : public EmCPU
+{
+ public:
+ // -----------------------------------------------------------------------------
+ // constructor / destructor
+ // -----------------------------------------------------------------------------
+
+ EmCPU68K (EmSession*);
+ virtual ~EmCPU68K (void);
+
+ // -----------------------------------------------------------------------------
+ // public methods
+ // -----------------------------------------------------------------------------
+
+ // Standard sub-system methods:
+ // Reset: Resets the state. Called on hardware resets or on
+ // calls to SysReset. Also called from constructor.
+ // Save: Saves the state to the given file.
+ // Load: Loads the state from the given file. Can assume that
+ // Reset has been called first.
+
+ virtual void Reset (Bool hardwareReset);
+ virtual void Save (SessionFile&);
+ virtual void Load (SessionFile&);
+
+ // Execute the main CPU loop until asked to stop.
+
+ virtual void Execute (void);
+ virtual void CheckAfterCycle (void);
+
+ // Low-level access to CPU state.
+
+ virtual emuptr GetPC (void);
+ virtual emuptr GetSP (void);
+ virtual uint32 GetRegister (int);
+
+ virtual void SetPC (emuptr);
+ virtual void SetSP (emuptr);
+ virtual void SetRegister (int, uint32);
+
+ virtual Bool Stopped (void);
+
+ // Called from routines in EmUAEGlue.cpp
+
+ void ProcessException (ExceptionNumber);
+ void ProcessIllegalInstruction (EmOpcode68K opcode);
+ int ProcessJSR (emuptr oldPC, emuptr dest);
+ int ProcessJSR_Ind (emuptr oldPC, emuptr dest);
+ void ProcessLINK (int linkSize);
+ int ProcessRTE (emuptr dest);
+ int ProcessRTS (emuptr dest);
+ void CheckNewPC (emuptr dest);
+ void CheckNewSP (EmStackChangeType);
+
+ // Called by CPU clients who need to be notified when certain
+ // actions occur.
+
+ void InstallHookException (ExceptionNumber,
+ Hook68KException);
+
+ void InstallHookJSR (Hook68KJSR);
+ void InstallHookJSR_Ind (Hook68KJSR_Ind);
+ void InstallHookLINK (Hook68KLINK);
+ void InstallHookRTS (Hook68KRTE);
+ void InstallHookRTE (Hook68KRTS);
+ void InstallHookNewPC (Hook68KNewPC);
+ void InstallHookNewSP (Hook68KNewSP);
+
+ void RemoveHookException (ExceptionNumber,
+ Hook68KException);
+
+ void RemoveHookJSR (Hook68KJSR);
+ void RemoveHookJSR_Ind (Hook68KJSR_Ind);
+ void RemoveHookLINK (Hook68KLINK);
+ void RemoveHookRTS (Hook68KRTE);
+ void RemoveHookRTE (Hook68KRTS);
+ void RemoveHookNewPC (Hook68KNewPC);
+ void RemoveHookNewSP (Hook68KNewSP);
+
+ // Register management. Clients should call Get/SetRegisters for
+ // the most part. UpdateXFromY are here so that MakeSR and
+ // MakeFromSR (UAE glue functions) can call them.
+
+ void GetRegisters (regstruct& registers);
+ void SetRegisters (regstruct& registers);
+ void UpdateSRFromRegisters (void);
+ void UpdateRegistersFromSR (void);
+
+ uint32 GetCycleCount (void);
+
+ void BusError (emuptr address, long size, Bool forRead);
+ void AddressError (emuptr address, long size, Bool forRead);
+
+ private:
+ Bool ExecuteSpecial (void);
+ Bool ExecuteStoppedLoop (void);
+
+ void CycleSlowly (Bool sleeping);
+ Bool CheckForBreak (void);
+
+ void ProcessInterrupt (int32 interrupt);
+
+ void InitializeUAETables (void);
+
+ private:
+ emuptr fLastTraceAddress;
+ uint32 fCycleCount;
+ Hook68KExceptionList fExceptionHandlers[kException_LastException];
+ Hook68KJSRList fHookJSR;
+ Hook68KJSR_IndList fHookJSR_Ind;
+ Hook68KLINKList fHookLINK;
+ Hook68KRTEList fHookRTE;
+ Hook68KRTSList fHookRTS;
+ Hook68KNewPCList fHookNewPC;
+ Hook68KNewSPList fHookNewSP;
+
+#if REGISTER_HISTORY
+ #define kRegHistorySize 512
+ long fRegHistoryIndex;
+ struct regstruct fRegHistory[kRegHistorySize];
+#endif
+
+#if EXCEPTION_HISTORY
+ #define kExceptionHistorySize 512
+ long fExceptionHistoryIndex;
+ struct ExceptionHistoryType fExceptionHistory[kExceptionHistorySize];
+#endif
+};
+
+#endif // EmCPU68K_h
diff --git a/SrcShared/Hardware/EmCPUARM.cpp b/SrcShared/Hardware/EmCPUARM.cpp
new file mode 100644
index 0000000..3d57510
--- /dev/null
+++ b/SrcShared/Hardware/EmCPUARM.cpp
@@ -0,0 +1,398 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 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 "EmCPUARM.h"
+
+#include "EmSession.h" // ExecuteSpecial
+
+/*
+ This file interfaces between the Palm OS Emulator and the embedded
+ instance of the ARMulator.
+
+ This version of the ARMulator comes from gdb 5.0, which in turn was
+ derived from the ARM6 ARMulator from ARM, Inc. ARM apparently no
+ longer makes public source-code to their version of ARMulator
+ available, so the version here is probably just a distant cousin
+ of that version.
+
+ The ARMulator here comes with the following files:
+
+ * armcopro.c
+
+ ARM coprocessor emulation
+
+ * armemu.c
+
+ Main ARM processor emulation. It can be compiled for either
+ 26-bit or 32-bit modes.
+
+ * arminit.c
+
+ Contains routines to perform one-time initialization of
+ ARMulator, create an emulator instance, select a processor,
+ reset a processor, run one or more instructions, or trigger
+ an abort.
+
+ * armos.c
+
+ (Something to do with knowledge of an ARM-based OS)
+
+ * armrdi.c
+
+ Implements the ARM RDI (Remote Debugger Interface). All
+ functions are exported via an RDI 1.0 RDIProcVec table
+ (armul_rdi).
+
+ * armsupp.c
+
+ Support routines for common actions like determining addressing
+ modes, reading and writing bytes, reading and writing registers, etc.
+
+ * armvirt.c
+
+ A simple memory emulator that maps in RAM pages on demand.
+
+ * bag.c
+
+ A simple dictionary data structure. Used by kid.c to manage
+ breakpoints. (!!!Why are they managed there and not in armrdi?)
+
+ * communicate.c
+
+ Utility routines to read and write bytes, words, and strings
+ over a socket.
+
+ * gdbhost.c
+
+ Interface routines between gdb and ARMulator. ARMulator calls
+ these functions to invoke gdb console facilities.
+
+ * kid.c
+
+ Infinite loops that listens on a socket for ADP packets. It
+ reads these and invokes the appropriate RDI functions in armrdi.c.
+
+ * main.c
+
+ Front-end application that sits between gdb and ARMulator, intercepting
+ packets and passing them on. (!!! It's not clear to me why this
+ intermediary -- implemented in parent.c -- is required.)
+
+ * parent.c
+
+ Implements the loop that listens for packets from either gdb
+ or ARMulator and forwards them on to the other.
+
+ * thumbemu.c
+
+ Emulator of the Thumb sub-cell. Translates Thumb opcodes into
+ ARM opcodes, and then invokes the ARM opcode emulator.
+
+ * wrapper.c
+
+ ARMulator wrapper that allows it to be incorporated into the gdb
+ Simulator system. This includes implementing functions that
+ respond to the gdb set of remote debugger commands.
+
+ When incorporated into the gdb Simulator system, only the files armcopro.c,
+ armemu.c, arminit.c, armos.c, armsupp.c, armvirt.c, bag.c thumbemu.c, and
+ wrapper.c seem to be used. (!!! Why bag.c, when it's only used by kid.c?)
+*/
+
+#if 0
+
+extern "C"
+{
+#include "armdefs.h"
+#include "armemu.h"
+#include "arm/dbg_rdi.h" // RDIProcVec
+#include "arm/dbg_hif.h" // Dbg_HostosInterface (struct)
+#include "arm/dbg_conf.h" // Dbg_ConfigBlock, Dbg_HostosInterface (typdef)
+}
+
+extern "C"
+{
+
+int stop_simulator; // Referenced in ARMul_Emulate32 loop
+
+int mumkid[2] = {1, 2}; // Referenced in kid.c
+int kidmum[2] = {3, 4}; // Referenced in kid.c, armrdi.c
+
+/* RDI interface */
+extern const struct RDIProcVec armul_rdi;
+
+void ARMul_CheckAfterCycle (void);
+void ARMul_SetSession (void* session);
+
+void EmCPUARM_CheckAfterCycle (void* session)
+{
+ ((EmSession*) session)->ExecuteSpecial (false);
+}
+
+
+/***************************************************************************\
+* Time for the Operating System to initialise itself. *
+\***************************************************************************/
+
+// Referenced in RDI_open in armrdi.c
+
+unsigned
+ARMul_OSInit (ARMul_State * state)
+{
+ return (TRUE);
+}
+
+// Referenced in RDI_close in armrdi.c
+
+void
+ARMul_OSExit (ARMul_State * state)
+{
+}
+
+/***************************************************************************\
+* Return the last Operating System Error. *
+\***************************************************************************/
+
+// Referenced in RDI_info in armrdi.c
+
+ARMword ARMul_OSLastErrorP (ARMul_State * state)
+{
+ return 0;
+}
+
+/***************************************************************************\
+* The emulator calls this routine when a SWI instruction is encuntered. The *
+* parameter passed is the SWI number (lower 24 bits of the instruction). *
+\***************************************************************************/
+
+// Referenced in "case 0x7f" of ARMul_Emulate32 in armemu.c
+// Referenced in "case 0xf0..0xff" of ARMul_Emulate32 in armemu.c
+
+unsigned
+ARMul_OSHandleSWI (ARMul_State * state, ARMword number)
+{
+ return (FALSE);
+}
+
+/***************************************************************************\
+* The emulator calls this routine when an Exception occurs. The second *
+* parameter is the address of the relevant exception vector. Returning *
+* FALSE from this routine causes the trap to be taken, TRUE causes it to *
+* be ignored (so set state->Emulate to FALSE!). *
+\***************************************************************************/
+
+// Referenced in ARMul_Abort in arminit.c
+
+unsigned
+ARMul_OSException (ARMul_State * state, ARMword vector, ARMword pc)
+{
+ return (FALSE);
+}
+
+}
+
+#endif
+
+
+#pragma mark -
+
+EmCPUARM* gCPUARM;
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPUARM::EmCPUARM
+// ---------------------------------------------------------------------------
+
+EmCPUARM::EmCPUARM (EmSession* session) :
+ EmCPU (session)
+{
+ this->DoReset (true);
+
+ EmAssert (gCPUARM == NULL);
+ gCPUARM = this;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPUARM::~EmCPUARM
+// ---------------------------------------------------------------------------
+
+EmCPUARM::~EmCPUARM (void)
+{
+#if 0
+ /* int i = */ armul_rdi.close ();
+#endif
+
+ EmAssert (gCPUARM == this);
+ gCPUARM = NULL;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPUARM::Reset
+// ---------------------------------------------------------------------------
+
+void EmCPUARM::Reset (Bool hardwareReset)
+{
+ if (hardwareReset)
+ {
+ this->DoReset (false);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPUARM::Save
+// ---------------------------------------------------------------------------
+
+void EmCPUARM::Save (SessionFile&)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPUARM::Load
+// ---------------------------------------------------------------------------
+
+void EmCPUARM::Load (SessionFile&)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPUARM::Execute
+// ---------------------------------------------------------------------------
+
+void EmCPUARM::Execute (void)
+{
+#if 0
+ PointHandle point;
+ /* int i = */ armul_rdi.execute (&point);
+#endif
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPUARM::CheckAfterCycle
+// ---------------------------------------------------------------------------
+
+void EmCPUARM::CheckAfterCycle (void)
+{
+#if 0
+ ARMul_CheckAfterCycle ();
+#endif
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPUARM::GetPC
+// ---------------------------------------------------------------------------
+
+emuptr EmCPUARM::GetPC (void)
+{
+ return EmMemNULL;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPUARM::GetSP
+// ---------------------------------------------------------------------------
+
+emuptr EmCPUARM::GetSP (void)
+{
+ return EmMemNULL;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPUARM::GetRegister
+// ---------------------------------------------------------------------------
+
+uint32 EmCPUARM::GetRegister (int /*index*/)
+{
+ return 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPUARM::SetPC
+// ---------------------------------------------------------------------------
+
+void EmCPUARM::SetPC (emuptr /*newPC*/)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPUARM::SetSP
+// ---------------------------------------------------------------------------
+
+void EmCPUARM::SetSP (emuptr /*newPC*/)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPUARM::SetRegister
+// ---------------------------------------------------------------------------
+
+void EmCPUARM::SetRegister (int /*index*/, uint32 /*val*/)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPUARM::Stopped
+// ---------------------------------------------------------------------------
+// Return whether or not the CPU itself is halted. This is seperate from
+// whether or not the session (that is, the thread emulating the CPU) is
+// halted.
+
+Bool EmCPUARM::Stopped (void)
+{
+ return false;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCPUARM::DoReset
+// ---------------------------------------------------------------------------
+
+void EmCPUARM::DoReset (Bool /*cold*/)
+{
+#if 0
+ // Taken from RDP_Start in kid.c
+
+ Dbg_ConfigBlock config;
+ config.processor = 0;
+ config.memorysize = 1024 * 1024L;
+ config.bytesex = RDISex_Little;
+
+ Dbg_HostosInterface hostif;
+
+ hostif.dbgprint = NULL; // myprint; // Called in ARMul_DebugPrint, ARMul_DebugPrint_i, which are called only if RDI_VERBOSE is defined.
+ hostif.dbgpause = NULL; // mypause; // Called in ARMul_DebugPause, which in turn is not called.
+ hostif.dbgarg = NULL; // stdout; // Passed to dbgprint and dbgpause.
+ hostif.writec = NULL; // mywritec;// Not called
+ hostif.readc = NULL; // myreadc; // Not called
+ hostif.write = NULL; // mywrite; // Not called
+ hostif.gets = NULL; // mygets; // Not called
+ hostif.hostosarg = NULL; // Not referenced
+ hostif.reset = NULL; // mypause; // Not referenced
+ hostif.resetarg = NULL; // Not referenced
+
+ /* int i = */ armul_rdi.open (cold ? 0 : 1, &config, &hostif, NULL);
+
+ ARMul_SetSession (fSession);
+#endif
+}
diff --git a/SrcShared/Hardware/EmCPUARM.h b/SrcShared/Hardware/EmCPUARM.h
new file mode 100644
index 0000000..73c8304
--- /dev/null
+++ b/SrcShared/Hardware/EmCPUARM.h
@@ -0,0 +1,731 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 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.
+\* ===================================================================== */
+
+#ifndef EmCPUARM_h
+#define EmCPUARM_h
+
+#include "EmCPU.h" // EmCPU
+
+/*---------------------------------------------------------------------
+ * ARM Register IDs. All register IDs must be unique even if registers
+ * are in a different group such as FPU registers.
+ *--------------------------------------------------------------------*/
+enum EmCPUARMRegID
+{
+ eARMRegID_Invalid = 0, /* Zero is an invalid register number */
+
+ /*-----------------------------------------------------------
+ // User mode registers
+ //----------------------------------------------------------*/
+ eARMRegID_R0 = 1,
+ eARMRegID_R1,
+ eARMRegID_R2,
+ eARMRegID_R3,
+ eARMRegID_R4,
+ eARMRegID_R5,
+ eARMRegID_R6,
+ eARMRegID_R7,
+ eARMRegID_R8,
+ eARMRegID_R9,
+ eARMRegID_R10,
+ eARMRegID_R11,
+ eARMRegID_R12,
+ eARMRegID_SP, eARMRegID_R13 = eARMRegID_SP,
+ eARMRegID_LR, eARMRegID_R14 = eARMRegID_LR,
+ eARMRegID_PC, eARMRegID_R15 = eARMRegID_PC,
+ eARMRegID_CPSR,
+
+ /*-----------------------------------------------------------
+ // FIQ mode registers
+ //----------------------------------------------------------*/
+ eARMRegID_R8_fiq,
+ eARMRegID_R9_fiq,
+ eARMRegID_R10_fiq,
+ eARMRegID_R11_fiq,
+ eARMRegID_R12_fiq,
+ eARMRegID_R13_fiq,
+ eARMRegID_R14_fiq,
+ eARMRegID_SPSR_fiq,
+
+ /*-----------------------------------------------------------
+ // IRQ mode registers
+ //----------------------------------------------------------*/
+ eARMRegID_R13_irq,
+ eARMRegID_R14_irq,
+ eARMRegID_SPSR_irq,
+
+ /*-----------------------------------------------------------
+ // Supervisor mode registers
+ //----------------------------------------------------------*/
+ eARMRegID_R13_svc,
+ eARMRegID_R14_svc,
+ eARMRegID_SPSR_svc,
+
+ /*-----------------------------------------------------------
+ // Abort mode registers
+ //----------------------------------------------------------*/
+ eARMRegID_R13_abt,
+ eARMRegID_R14_abt,
+ eARMRegID_SPSR_abt,
+
+
+ /*-----------------------------------------------------------
+ // Undefined mode registers
+ //----------------------------------------------------------*/
+ eARMRegID_R13_und,
+ eARMRegID_R14_und,
+ eARMRegID_SPSR_und,
+
+ /*-----------------------------------------------------------
+ // SB register (static base).
+ //
+ // Any references to R9 can be remapped (in debugger plugin
+ // preferences) to access this SB register which can be
+ // described by an expression in the preferences. The
+ // expression should not contain any references to R9 (since
+ // this will create an infinite loop (since R9 has been
+ // remapped to SB)). Any need for the actual value of R9 in
+ // the SB expression should use the "genreg_gp1" (which means
+ // "General Register Global Pointer 1") opcode which
+ // will actually read R9.
+ //----------------------------------------------------------*/
+ eARMRegID_SB,
+
+ /*-----------------------------------------------------------
+ // Coprocessor 0 registers
+ //----------------------------------------------------------*/
+ eARMRegID_CP0_R0,
+ eARMRegID_CP0_R1,
+ eARMRegID_CP0_R2,
+ eARMRegID_CP0_R3,
+ eARMRegID_CP0_R4,
+ eARMRegID_CP0_R5,
+ eARMRegID_CP0_R6,
+ eARMRegID_CP0_R7,
+ eARMRegID_CP0_R8,
+ eARMRegID_CP0_R9,
+ eARMRegID_CP0_R10,
+ eARMRegID_CP0_R11,
+ eARMRegID_CP0_R12,
+ eARMRegID_CP0_R13,
+ eARMRegID_CP0_R14,
+ eARMRegID_CP0_R15,
+ eARMRegID_CP0_R16,
+ eARMRegID_CP0_R17,
+ eARMRegID_CP0_R18,
+ eARMRegID_CP0_R19,
+ eARMRegID_CP0_R20,
+ eARMRegID_CP0_R21,
+ eARMRegID_CP0_R22,
+ eARMRegID_CP0_R23,
+ eARMRegID_CP0_R24,
+ eARMRegID_CP0_R25,
+ eARMRegID_CP0_R26,
+ eARMRegID_CP0_R27,
+ eARMRegID_CP0_R28,
+ eARMRegID_CP0_R29,
+ eARMRegID_CP0_R30,
+ eARMRegID_CP0_R31,
+
+ /*-----------------------------------------------------------
+ // Coprocessor 1 registers
+ //----------------------------------------------------------*/
+ eARMRegID_CP1_R0,
+ eARMRegID_CP1_R1,
+ eARMRegID_CP1_R2,
+ eARMRegID_CP1_R3,
+ eARMRegID_CP1_R4,
+ eARMRegID_CP1_R5,
+ eARMRegID_CP1_R6,
+ eARMRegID_CP1_R7,
+ eARMRegID_CP1_R8,
+ eARMRegID_CP1_R9,
+ eARMRegID_CP1_R10,
+ eARMRegID_CP1_R11,
+ eARMRegID_CP1_R12,
+ eARMRegID_CP1_R13,
+ eARMRegID_CP1_R14,
+ eARMRegID_CP1_R15,
+ eARMRegID_CP1_R16,
+ eARMRegID_CP1_R17,
+ eARMRegID_CP1_R18,
+ eARMRegID_CP1_R19,
+ eARMRegID_CP1_R20,
+ eARMRegID_CP1_R21,
+ eARMRegID_CP1_R22,
+ eARMRegID_CP1_R23,
+ eARMRegID_CP1_R24,
+ eARMRegID_CP1_R25,
+ eARMRegID_CP1_R26,
+ eARMRegID_CP1_R27,
+ eARMRegID_CP1_R28,
+ eARMRegID_CP1_R29,
+ eARMRegID_CP1_R30,
+ eARMRegID_CP1_R31,
+
+ /*-----------------------------------------------------------
+ // Coprocessor 2 registers
+ //----------------------------------------------------------*/
+ eARMRegID_CP2_R0,
+ eARMRegID_CP2_R1,
+ eARMRegID_CP2_R2,
+ eARMRegID_CP2_R3,
+ eARMRegID_CP2_R4,
+ eARMRegID_CP2_R5,
+ eARMRegID_CP2_R6,
+ eARMRegID_CP2_R7,
+ eARMRegID_CP2_R8,
+ eARMRegID_CP2_R9,
+ eARMRegID_CP2_R10,
+ eARMRegID_CP2_R11,
+ eARMRegID_CP2_R12,
+ eARMRegID_CP2_R13,
+ eARMRegID_CP2_R14,
+ eARMRegID_CP2_R15,
+ eARMRegID_CP2_R16,
+ eARMRegID_CP2_R17,
+ eARMRegID_CP2_R18,
+ eARMRegID_CP2_R19,
+ eARMRegID_CP2_R20,
+ eARMRegID_CP2_R21,
+ eARMRegID_CP2_R22,
+ eARMRegID_CP2_R23,
+ eARMRegID_CP2_R24,
+ eARMRegID_CP2_R25,
+ eARMRegID_CP2_R26,
+ eARMRegID_CP2_R27,
+ eARMRegID_CP2_R28,
+ eARMRegID_CP2_R29,
+ eARMRegID_CP2_R30,
+ eARMRegID_CP2_R31,
+
+ /*-----------------------------------------------------------
+ // Coprocessor 3 registers
+ //----------------------------------------------------------*/
+ eARMRegID_CP3_R0,
+ eARMRegID_CP3_R1,
+ eARMRegID_CP3_R2,
+ eARMRegID_CP3_R3,
+ eARMRegID_CP3_R4,
+ eARMRegID_CP3_R5,
+ eARMRegID_CP3_R6,
+ eARMRegID_CP3_R7,
+ eARMRegID_CP3_R8,
+ eARMRegID_CP3_R9,
+ eARMRegID_CP3_R10,
+ eARMRegID_CP3_R11,
+ eARMRegID_CP3_R12,
+ eARMRegID_CP3_R13,
+ eARMRegID_CP3_R14,
+ eARMRegID_CP3_R15,
+ eARMRegID_CP3_R16,
+ eARMRegID_CP3_R17,
+ eARMRegID_CP3_R18,
+ eARMRegID_CP3_R19,
+ eARMRegID_CP3_R20,
+ eARMRegID_CP3_R21,
+ eARMRegID_CP3_R22,
+ eARMRegID_CP3_R23,
+ eARMRegID_CP3_R24,
+ eARMRegID_CP3_R25,
+ eARMRegID_CP3_R26,
+ eARMRegID_CP3_R27,
+ eARMRegID_CP3_R28,
+ eARMRegID_CP3_R29,
+ eARMRegID_CP3_R30,
+ eARMRegID_CP3_R31,
+
+ /*-----------------------------------------------------------
+ // Coprocessor 4 registers
+ //----------------------------------------------------------*/
+ eARMRegID_CP4_R0,
+ eARMRegID_CP4_R1,
+ eARMRegID_CP4_R2,
+ eARMRegID_CP4_R3,
+ eARMRegID_CP4_R4,
+ eARMRegID_CP4_R5,
+ eARMRegID_CP4_R6,
+ eARMRegID_CP4_R7,
+ eARMRegID_CP4_R8,
+ eARMRegID_CP4_R9,
+ eARMRegID_CP4_R10,
+ eARMRegID_CP4_R11,
+ eARMRegID_CP4_R12,
+ eARMRegID_CP4_R13,
+ eARMRegID_CP4_R14,
+ eARMRegID_CP4_R15,
+ eARMRegID_CP4_R16,
+ eARMRegID_CP4_R17,
+ eARMRegID_CP4_R18,
+ eARMRegID_CP4_R19,
+ eARMRegID_CP4_R20,
+ eARMRegID_CP4_R21,
+ eARMRegID_CP4_R22,
+ eARMRegID_CP4_R23,
+ eARMRegID_CP4_R24,
+ eARMRegID_CP4_R25,
+ eARMRegID_CP4_R26,
+ eARMRegID_CP4_R27,
+ eARMRegID_CP4_R28,
+ eARMRegID_CP4_R29,
+ eARMRegID_CP4_R30,
+ eARMRegID_CP4_R31,
+
+ /*-----------------------------------------------------------
+ // Coprocessor 5 registers
+ //----------------------------------------------------------*/
+ eARMRegID_CP5_R0,
+ eARMRegID_CP5_R1,
+ eARMRegID_CP5_R2,
+ eARMRegID_CP5_R3,
+ eARMRegID_CP5_R4,
+ eARMRegID_CP5_R5,
+ eARMRegID_CP5_R6,
+ eARMRegID_CP5_R7,
+ eARMRegID_CP5_R8,
+ eARMRegID_CP5_R9,
+ eARMRegID_CP5_R10,
+ eARMRegID_CP5_R11,
+ eARMRegID_CP5_R12,
+ eARMRegID_CP5_R13,
+ eARMRegID_CP5_R14,
+ eARMRegID_CP5_R15,
+ eARMRegID_CP5_R16,
+ eARMRegID_CP5_R17,
+ eARMRegID_CP5_R18,
+ eARMRegID_CP5_R19,
+ eARMRegID_CP5_R20,
+ eARMRegID_CP5_R21,
+ eARMRegID_CP5_R22,
+ eARMRegID_CP5_R23,
+ eARMRegID_CP5_R24,
+ eARMRegID_CP5_R25,
+ eARMRegID_CP5_R26,
+ eARMRegID_CP5_R27,
+ eARMRegID_CP5_R28,
+ eARMRegID_CP5_R29,
+ eARMRegID_CP5_R30,
+ eARMRegID_CP5_R31,
+
+ /*-----------------------------------------------------------
+ // Coprocessor 6 registers
+ //----------------------------------------------------------*/
+ eARMRegID_CP6_R0,
+ eARMRegID_CP6_R1,
+ eARMRegID_CP6_R2,
+ eARMRegID_CP6_R3,
+ eARMRegID_CP6_R4,
+ eARMRegID_CP6_R5,
+ eARMRegID_CP6_R6,
+ eARMRegID_CP6_R7,
+ eARMRegID_CP6_R8,
+ eARMRegID_CP6_R9,
+ eARMRegID_CP6_R10,
+ eARMRegID_CP6_R11,
+ eARMRegID_CP6_R12,
+ eARMRegID_CP6_R13,
+ eARMRegID_CP6_R14,
+ eARMRegID_CP6_R15,
+ eARMRegID_CP6_R16,
+ eARMRegID_CP6_R17,
+ eARMRegID_CP6_R18,
+ eARMRegID_CP6_R19,
+ eARMRegID_CP6_R20,
+ eARMRegID_CP6_R21,
+ eARMRegID_CP6_R22,
+ eARMRegID_CP6_R23,
+ eARMRegID_CP6_R24,
+ eARMRegID_CP6_R25,
+ eARMRegID_CP6_R26,
+ eARMRegID_CP6_R27,
+ eARMRegID_CP6_R28,
+ eARMRegID_CP6_R29,
+ eARMRegID_CP6_R30,
+ eARMRegID_CP6_R31,
+
+ /*-----------------------------------------------------------
+ // Coprocessor 7 registers
+ //----------------------------------------------------------*/
+ eARMRegID_CP7_R0,
+ eARMRegID_CP7_R1,
+ eARMRegID_CP7_R2,
+ eARMRegID_CP7_R3,
+ eARMRegID_CP7_R4,
+ eARMRegID_CP7_R5,
+ eARMRegID_CP7_R6,
+ eARMRegID_CP7_R7,
+ eARMRegID_CP7_R8,
+ eARMRegID_CP7_R9,
+ eARMRegID_CP7_R10,
+ eARMRegID_CP7_R11,
+ eARMRegID_CP7_R12,
+ eARMRegID_CP7_R13,
+ eARMRegID_CP7_R14,
+ eARMRegID_CP7_R15,
+ eARMRegID_CP7_R16,
+ eARMRegID_CP7_R17,
+ eARMRegID_CP7_R18,
+ eARMRegID_CP7_R19,
+ eARMRegID_CP7_R20,
+ eARMRegID_CP7_R21,
+ eARMRegID_CP7_R22,
+ eARMRegID_CP7_R23,
+ eARMRegID_CP7_R24,
+ eARMRegID_CP7_R25,
+ eARMRegID_CP7_R26,
+ eARMRegID_CP7_R27,
+ eARMRegID_CP7_R28,
+ eARMRegID_CP7_R29,
+ eARMRegID_CP7_R30,
+ eARMRegID_CP7_R31,
+
+ /*-----------------------------------------------------------
+ // Coprocessor 8 registers
+ //----------------------------------------------------------*/
+ eARMRegID_CP8_R0,
+ eARMRegID_CP8_R1,
+ eARMRegID_CP8_R2,
+ eARMRegID_CP8_R3,
+ eARMRegID_CP8_R4,
+ eARMRegID_CP8_R5,
+ eARMRegID_CP8_R6,
+ eARMRegID_CP8_R7,
+ eARMRegID_CP8_R8,
+ eARMRegID_CP8_R9,
+ eARMRegID_CP8_R10,
+ eARMRegID_CP8_R11,
+ eARMRegID_CP8_R12,
+ eARMRegID_CP8_R13,
+ eARMRegID_CP8_R14,
+ eARMRegID_CP8_R15,
+ eARMRegID_CP8_R16,
+ eARMRegID_CP8_R17,
+ eARMRegID_CP8_R18,
+ eARMRegID_CP8_R19,
+ eARMRegID_CP8_R20,
+ eARMRegID_CP8_R21,
+ eARMRegID_CP8_R22,
+ eARMRegID_CP8_R23,
+ eARMRegID_CP8_R24,
+ eARMRegID_CP8_R25,
+ eARMRegID_CP8_R26,
+ eARMRegID_CP8_R27,
+ eARMRegID_CP8_R28,
+ eARMRegID_CP8_R29,
+ eARMRegID_CP8_R30,
+ eARMRegID_CP8_R31,
+
+ /*-----------------------------------------------------------
+ // Coprocessor 9 registers
+ //----------------------------------------------------------*/
+ eARMRegID_CP9_R0,
+ eARMRegID_CP9_R1,
+ eARMRegID_CP9_R2,
+ eARMRegID_CP9_R3,
+ eARMRegID_CP9_R4,
+ eARMRegID_CP9_R5,
+ eARMRegID_CP9_R6,
+ eARMRegID_CP9_R7,
+ eARMRegID_CP9_R8,
+ eARMRegID_CP9_R9,
+ eARMRegID_CP9_R10,
+ eARMRegID_CP9_R11,
+ eARMRegID_CP9_R12,
+ eARMRegID_CP9_R13,
+ eARMRegID_CP9_R14,
+ eARMRegID_CP9_R15,
+ eARMRegID_CP9_R16,
+ eARMRegID_CP9_R17,
+ eARMRegID_CP9_R18,
+ eARMRegID_CP9_R19,
+ eARMRegID_CP9_R20,
+ eARMRegID_CP9_R21,
+ eARMRegID_CP9_R22,
+ eARMRegID_CP9_R23,
+ eARMRegID_CP9_R24,
+ eARMRegID_CP9_R25,
+ eARMRegID_CP9_R26,
+ eARMRegID_CP9_R27,
+ eARMRegID_CP9_R28,
+ eARMRegID_CP9_R29,
+ eARMRegID_CP9_R30,
+ eARMRegID_CP9_R31,
+
+ /*-----------------------------------------------------------
+ // Coprocessor 10 registers
+ //----------------------------------------------------------*/
+ eARMRegID_CP10_R0,
+ eARMRegID_CP10_R1,
+ eARMRegID_CP10_R2,
+ eARMRegID_CP10_R3,
+ eARMRegID_CP10_R4,
+ eARMRegID_CP10_R5,
+ eARMRegID_CP10_R6,
+ eARMRegID_CP10_R7,
+ eARMRegID_CP10_R8,
+ eARMRegID_CP10_R9,
+ eARMRegID_CP10_R10,
+ eARMRegID_CP10_R11,
+ eARMRegID_CP10_R12,
+ eARMRegID_CP10_R13,
+ eARMRegID_CP10_R14,
+ eARMRegID_CP10_R15,
+ eARMRegID_CP10_R16,
+ eARMRegID_CP10_R17,
+ eARMRegID_CP10_R18,
+ eARMRegID_CP10_R19,
+ eARMRegID_CP10_R20,
+ eARMRegID_CP10_R21,
+ eARMRegID_CP10_R22,
+ eARMRegID_CP10_R23,
+ eARMRegID_CP10_R24,
+ eARMRegID_CP10_R25,
+ eARMRegID_CP10_R26,
+ eARMRegID_CP10_R27,
+ eARMRegID_CP10_R28,
+ eARMRegID_CP10_R29,
+ eARMRegID_CP10_R30,
+ eARMRegID_CP10_R31,
+
+ /*-----------------------------------------------------------
+ // Coprocessor 11 registers
+ //----------------------------------------------------------*/
+ eARMRegID_CP11_R0,
+ eARMRegID_CP11_R1,
+ eARMRegID_CP11_R2,
+ eARMRegID_CP11_R3,
+ eARMRegID_CP11_R4,
+ eARMRegID_CP11_R5,
+ eARMRegID_CP11_R6,
+ eARMRegID_CP11_R7,
+ eARMRegID_CP11_R8,
+ eARMRegID_CP11_R9,
+ eARMRegID_CP11_R10,
+ eARMRegID_CP11_R11,
+ eARMRegID_CP11_R12,
+ eARMRegID_CP11_R13,
+ eARMRegID_CP11_R14,
+ eARMRegID_CP11_R15,
+ eARMRegID_CP11_R16,
+ eARMRegID_CP11_R17,
+ eARMRegID_CP11_R18,
+ eARMRegID_CP11_R19,
+ eARMRegID_CP11_R20,
+ eARMRegID_CP11_R21,
+ eARMRegID_CP11_R22,
+ eARMRegID_CP11_R23,
+ eARMRegID_CP11_R24,
+ eARMRegID_CP11_R25,
+ eARMRegID_CP11_R26,
+ eARMRegID_CP11_R27,
+ eARMRegID_CP11_R28,
+ eARMRegID_CP11_R29,
+ eARMRegID_CP11_R30,
+ eARMRegID_CP11_R31,
+
+ /*-----------------------------------------------------------
+ // Coprocessor 12 registers
+ //----------------------------------------------------------*/
+ eARMRegID_CP12_R0,
+ eARMRegID_CP12_R1,
+ eARMRegID_CP12_R2,
+ eARMRegID_CP12_R3,
+ eARMRegID_CP12_R4,
+ eARMRegID_CP12_R5,
+ eARMRegID_CP12_R6,
+ eARMRegID_CP12_R7,
+ eARMRegID_CP12_R8,
+ eARMRegID_CP12_R9,
+ eARMRegID_CP12_R10,
+ eARMRegID_CP12_R11,
+ eARMRegID_CP12_R12,
+ eARMRegID_CP12_R13,
+ eARMRegID_CP12_R14,
+ eARMRegID_CP12_R15,
+ eARMRegID_CP12_R16,
+ eARMRegID_CP12_R17,
+ eARMRegID_CP12_R18,
+ eARMRegID_CP12_R19,
+ eARMRegID_CP12_R20,
+ eARMRegID_CP12_R21,
+ eARMRegID_CP12_R22,
+ eARMRegID_CP12_R23,
+ eARMRegID_CP12_R24,
+ eARMRegID_CP12_R25,
+ eARMRegID_CP12_R26,
+ eARMRegID_CP12_R27,
+ eARMRegID_CP12_R28,
+ eARMRegID_CP12_R29,
+ eARMRegID_CP12_R30,
+ eARMRegID_CP12_R31,
+
+ /*-----------------------------------------------------------
+ // Coprocessor 13 registers
+ //----------------------------------------------------------*/
+ eARMRegID_CP13_R0,
+ eARMRegID_CP13_R1,
+ eARMRegID_CP13_R2,
+ eARMRegID_CP13_R3,
+ eARMRegID_CP13_R4,
+ eARMRegID_CP13_R5,
+ eARMRegID_CP13_R6,
+ eARMRegID_CP13_R7,
+ eARMRegID_CP13_R8,
+ eARMRegID_CP13_R9,
+ eARMRegID_CP13_R10,
+ eARMRegID_CP13_R11,
+ eARMRegID_CP13_R12,
+ eARMRegID_CP13_R13,
+ eARMRegID_CP13_R14,
+ eARMRegID_CP13_R15,
+ eARMRegID_CP13_R16,
+ eARMRegID_CP13_R17,
+ eARMRegID_CP13_R18,
+ eARMRegID_CP13_R19,
+ eARMRegID_CP13_R20,
+ eARMRegID_CP13_R21,
+ eARMRegID_CP13_R22,
+ eARMRegID_CP13_R23,
+ eARMRegID_CP13_R24,
+ eARMRegID_CP13_R25,
+ eARMRegID_CP13_R26,
+ eARMRegID_CP13_R27,
+ eARMRegID_CP13_R28,
+ eARMRegID_CP13_R29,
+ eARMRegID_CP13_R30,
+ eARMRegID_CP13_R31,
+
+ /*-----------------------------------------------------------
+ // Coprocessor 14 registers
+ //----------------------------------------------------------*/
+ eARMRegID_CP14_R0,
+ eARMRegID_CP14_R1,
+ eARMRegID_CP14_R2,
+ eARMRegID_CP14_R3,
+ eARMRegID_CP14_R4,
+ eARMRegID_CP14_R5,
+ eARMRegID_CP14_R6,
+ eARMRegID_CP14_R7,
+ eARMRegID_CP14_R8,
+ eARMRegID_CP14_R9,
+ eARMRegID_CP14_R10,
+ eARMRegID_CP14_R11,
+ eARMRegID_CP14_R12,
+ eARMRegID_CP14_R13,
+ eARMRegID_CP14_R14,
+ eARMRegID_CP14_R15,
+ eARMRegID_CP14_R16,
+ eARMRegID_CP14_R17,
+ eARMRegID_CP14_R18,
+ eARMRegID_CP14_R19,
+ eARMRegID_CP14_R20,
+ eARMRegID_CP14_R21,
+ eARMRegID_CP14_R22,
+ eARMRegID_CP14_R23,
+ eARMRegID_CP14_R24,
+ eARMRegID_CP14_R25,
+ eARMRegID_CP14_R26,
+ eARMRegID_CP14_R27,
+ eARMRegID_CP14_R28,
+ eARMRegID_CP14_R29,
+ eARMRegID_CP14_R30,
+ eARMRegID_CP14_R31,
+
+ /*-----------------------------------------------------------
+ // Coprocessor 15 registers
+ //----------------------------------------------------------*/
+ eARMRegID_CP15_R0,
+ eARMRegID_CP15_R1,
+ eARMRegID_CP15_R2,
+ eARMRegID_CP15_R3,
+ eARMRegID_CP15_R4,
+ eARMRegID_CP15_R5,
+ eARMRegID_CP15_R6,
+ eARMRegID_CP15_R7,
+ eARMRegID_CP15_R8,
+ eARMRegID_CP15_R9,
+ eARMRegID_CP15_R10,
+ eARMRegID_CP15_R11,
+ eARMRegID_CP15_R12,
+ eARMRegID_CP15_R13,
+ eARMRegID_CP15_R14,
+ eARMRegID_CP15_R15,
+ eARMRegID_CP15_R16,
+ eARMRegID_CP15_R17,
+ eARMRegID_CP15_R18,
+ eARMRegID_CP15_R19,
+ eARMRegID_CP15_R20,
+ eARMRegID_CP15_R21,
+ eARMRegID_CP15_R22,
+ eARMRegID_CP15_R23,
+ eARMRegID_CP15_R24,
+ eARMRegID_CP15_R25,
+ eARMRegID_CP15_R26,
+ eARMRegID_CP15_R27,
+ eARMRegID_CP15_R28,
+ eARMRegID_CP15_R29,
+ eARMRegID_CP15_R30,
+ eARMRegID_CP15_R31
+};
+
+
+class EmCPUARM;
+extern EmCPUARM* gCPUARM;
+
+class EmCPUARM : public EmCPU
+{
+ public:
+ // -----------------------------------------------------------------------------
+ // constructor / destructor
+ // -----------------------------------------------------------------------------
+
+ EmCPUARM (EmSession*);
+ virtual ~EmCPUARM (void);
+
+ // -----------------------------------------------------------------------------
+ // public methods
+ // -----------------------------------------------------------------------------
+
+ // Standard sub-system methods:
+ // Reset: Resets the state. Called on hardware resets or on
+ // calls to SysReset. Also called from constructor.
+ // Save: Saves the state to the given file.
+ // Load: Loads the state from the given file. Can assume that
+ // Reset has been called first.
+
+ virtual void Reset (Bool hardwareReset);
+ virtual void Save (SessionFile&);
+ virtual void Load (SessionFile&);
+
+ // Execute the main CPU loop until asked to stop.
+
+ virtual void Execute (void);
+ virtual void CheckAfterCycle (void);
+
+ // Low-level access to CPU state.
+
+ virtual emuptr GetPC (void);
+ virtual emuptr GetSP (void);
+ virtual uint32 GetRegister (int);
+
+ virtual void SetPC (emuptr);
+ virtual void SetSP (emuptr);
+ virtual void SetRegister (int, uint32);
+
+ virtual Bool Stopped (void);
+
+ private:
+ void DoReset (Bool cold);
+};
+
+#endif // EmCPUARM_h
diff --git a/SrcShared/Hardware/EmHAL.cpp b/SrcShared/Hardware/EmHAL.cpp
new file mode 100644
index 0000000..a4b0030
--- /dev/null
+++ b/SrcShared/Hardware/EmHAL.cpp
@@ -0,0 +1,939 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmHAL.h"
+
+#include "EmTransportSerial.h" // EmTransportSerial
+#include "ErrorHandling.h" // Errors::ReportErrCommPort
+#include "PreferenceMgr.h" // gEmuPrefs
+
+#include "Logging.h"
+
+
+EmHALHandler* EmHAL::fgRootHandler;
+
+#define PRINTF if (!0) ; else LogAppendMsg
+
+static void PrvHandlePortOpenErrors (ErrCode err, string errString);
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::AddHandler
+// ---------------------------------------------------------------------------
+
+void EmHAL::AddHandler (EmHALHandler* handler)
+{
+ EmAssert (handler->fNextHandler == NULL);
+ EmAssert (handler->fPrevHandler == NULL);
+ EmAssert (fgRootHandler == NULL || fgRootHandler->fPrevHandler == NULL);
+
+ if (fgRootHandler != NULL)
+ {
+ fgRootHandler->fPrevHandler = handler;
+ handler->fNextHandler = fgRootHandler;
+ }
+
+ fgRootHandler = handler;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::RemoveHandler
+// ---------------------------------------------------------------------------
+
+void EmHAL::RemoveHandler (EmHALHandler* handler)
+{
+ if (handler->fNextHandler)
+ {
+ handler->fNextHandler->fPrevHandler = handler->fPrevHandler;
+ }
+
+ if (handler->fPrevHandler)
+ {
+ handler->fPrevHandler->fNextHandler = handler->fNextHandler;
+ }
+ else
+ {
+ fgRootHandler = handler->fNextHandler;
+ }
+
+ handler->fNextHandler = NULL;
+ handler->fPrevHandler = NULL;
+
+ EmAssert (handler->fNextHandler == NULL);
+ EmAssert (handler->fPrevHandler == NULL);
+ EmAssert (fgRootHandler == NULL || fgRootHandler->fPrevHandler == NULL);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::RemoveHandler
+// ---------------------------------------------------------------------------
+
+void EmHAL::EnsureCoverage (void)
+{
+#if 0
+ // Rats...can't get this work...
+
+ Bool isHandled[20];
+ EmHALHandler* thisHandler = fgRootHandler;
+ EmHALHandler baseHandler;
+
+ while (thisHandler)
+ {
+ typedef void (EmHALHandler::*CycleHandler)(Bool);
+ CycleHandler p1 = (thisHandler->Cycle);
+ CycleHandler p2 = (baseHandler.Cycle);
+
+ if (p1 != p2)
+ {
+ isHandled[0] = true;
+ }
+
+ thisHandler = thisHandler->fNextHandler;
+ }
+
+ for (int ii = 0; ii < sizeof (isHandled); ++ii)
+ {
+ EmAssert (isHandled[ii]);
+ }
+#endif
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::Cycle
+// ---------------------------------------------------------------------------
+
+#if 0 // It's inline
+void EmHAL::Cycle (Bool sleeping)
+{
+ EmAssert (EmHAL::GetRootHandler());
+ EmHAL::GetRootHandler()->Cycle (sleeping);
+}
+#endif
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::CycleSlowly
+// ---------------------------------------------------------------------------
+
+void EmHAL::CycleSlowly (Bool sleeping)
+{
+ EmAssert (EmHAL::GetRootHandler());
+ EmHAL::GetRootHandler()->CycleSlowly (sleeping);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::ButtonEvent
+// ---------------------------------------------------------------------------
+
+void EmHAL::ButtonEvent (SkinElementType button, Bool buttonIsDown)
+{
+ EmAssert (EmHAL::GetRootHandler());
+ EmHAL::GetRootHandler()->ButtonEvent (button, buttonIsDown);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::TurnSoundOff
+// ---------------------------------------------------------------------------
+
+void EmHAL::TurnSoundOff (void)
+{
+ EmAssert (EmHAL::GetRootHandler());
+ EmHAL::GetRootHandler()->TurnSoundOff ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::ResetTimer
+// ---------------------------------------------------------------------------
+
+void EmHAL::ResetTimer (void)
+{
+ EmAssert (EmHAL::GetRootHandler());
+ EmHAL::GetRootHandler()->ResetTimer ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::ResetRTC
+// ---------------------------------------------------------------------------
+
+void EmHAL::ResetRTC (void)
+{
+ EmAssert (EmHAL::GetRootHandler());
+ EmHAL::GetRootHandler()->ResetRTC ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::GetInterruptLevel
+// ---------------------------------------------------------------------------
+
+int32 EmHAL::GetInterruptLevel (void)
+{
+ EmAssert (EmHAL::GetRootHandler());
+ return EmHAL::GetRootHandler()->GetInterruptLevel ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::GetInterruptBase
+// ---------------------------------------------------------------------------
+
+int32 EmHAL::GetInterruptBase (void)
+{
+ EmAssert (EmHAL::GetRootHandler());
+ return EmHAL::GetRootHandler()->GetInterruptBase ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::GetLCDScreenOn
+// ---------------------------------------------------------------------------
+// Called in various portXDataWrite methods to determine if Screen::InvalidateAll
+// needs to be called. Typically implemented in the EmRegs<Product> or
+// EmRegs<LCDDriver> subclass.
+
+Bool EmHAL::GetLCDScreenOn (void)
+{
+ EmAssert (EmHAL::GetRootHandler());
+ return EmHAL::GetRootHandler()->GetLCDScreenOn ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::GetLCDBacklightOn
+// ---------------------------------------------------------------------------
+// Called in various portXDataWrite methods to determine if Screen::InvalidateAll
+// needs to be called. Typically implemented in the EmRegs<Product> or
+// EmRegs<LCDDriver> subclass.
+
+Bool EmHAL::GetLCDBacklightOn (void)
+{
+ EmAssert (EmHAL::GetRootHandler());
+ return EmHAL::GetRootHandler()->GetLCDBacklightOn ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::GetLCDHasFrame
+// ---------------------------------------------------------------------------
+// Called by host LCD code to know if it needs to draw a 2-pixel white frame.
+// Typically implemented in the EmRegs<Processor> or EmRegs<LCDDriver> subclass.
+
+Bool EmHAL::GetLCDHasFrame (void)
+{
+ EmAssert (EmHAL::GetRootHandler());
+ return EmHAL::GetRootHandler()->GetLCDHasFrame ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::GetLCDBeginEnd
+// ---------------------------------------------------------------------------
+// Called by Screen class in order to mark the memory used for the framebuffer.
+// Typically implemented in the EmRegs<Processor> or EmRegs<LCDDriver> subclass.
+
+void EmHAL::GetLCDBeginEnd (emuptr& begin, emuptr& end)
+{
+ EmAssert (EmHAL::GetRootHandler());
+ EmHAL::GetRootHandler()->GetLCDBeginEnd (begin, end);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::GetLCDScanlines
+// ---------------------------------------------------------------------------
+// Fill in the output fields of EmScreenUpdateInfo. Typically implemented in
+// the EmRegs<Processor> or EmRegs<LCDDriver> subclass.
+
+void EmHAL::GetLCDScanlines (EmScreenUpdateInfo& info)
+{
+ EmAssert (EmHAL::GetRootHandler());
+ EmHAL::GetRootHandler()->GetLCDScanlines (info);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::GetDynamicHeapSize
+// ---------------------------------------------------------------------------
+
+int32 EmHAL::GetDynamicHeapSize (void)
+{
+ EmAssert (EmHAL::GetRootHandler());
+ return EmHAL::GetRootHandler()->GetDynamicHeapSize ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::GetROMSize
+// ---------------------------------------------------------------------------
+
+int32 EmHAL::GetROMSize (void)
+{
+ EmAssert (EmHAL::GetRootHandler());
+ return EmHAL::GetRootHandler()->GetROMSize ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::GetROMBaseAddress
+// ---------------------------------------------------------------------------
+
+emuptr EmHAL::GetROMBaseAddress (void)
+{
+ EmAssert (EmHAL::GetRootHandler());
+ return EmHAL::GetRootHandler()->GetROMBaseAddress ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::ChipSelectsConfigured
+// ---------------------------------------------------------------------------
+
+Bool EmHAL::ChipSelectsConfigured (void)
+{
+ EmAssert (EmHAL::GetRootHandler());
+ return EmHAL::GetRootHandler()->ChipSelectsConfigured ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::GetSystemClockFrequency
+// ---------------------------------------------------------------------------
+
+int32 EmHAL::GetSystemClockFrequency (void)
+{
+ EmAssert (EmHAL::GetRootHandler());
+ return EmHAL::GetRootHandler()->GetSystemClockFrequency ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::GetCanStop
+// ---------------------------------------------------------------------------
+
+Bool EmHAL::GetCanStop (void)
+{
+ EmAssert (EmHAL::GetRootHandler());
+ return EmHAL::GetRootHandler()->GetCanStop ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::GetAsleep
+// ---------------------------------------------------------------------------
+
+Bool EmHAL::GetAsleep (void)
+{
+ EmAssert (EmHAL::GetRootHandler());
+ return EmHAL::GetRootHandler()->GetAsleep ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::GetPortInputValue
+// ---------------------------------------------------------------------------
+
+uint8 EmHAL::GetPortInputValue (int port)
+{
+ EmAssert (EmHAL::GetRootHandler());
+ return EmHAL::GetRootHandler()->GetPortInputValue (port);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::GetPortInternalValue
+// ---------------------------------------------------------------------------
+
+uint8 EmHAL::GetPortInternalValue (int port)
+{
+ EmAssert (EmHAL::GetRootHandler());
+ return EmHAL::GetRootHandler()->GetPortInternalValue (port);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::PortDataChanged
+// ---------------------------------------------------------------------------
+
+void EmHAL::PortDataChanged (int port, uint8 oldVal, uint8 newVal)
+{
+ EmAssert (EmHAL::GetRootHandler());
+ EmHAL::GetRootHandler()->PortDataChanged (port, oldVal, newVal);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::GetKeyInfo
+// ---------------------------------------------------------------------------
+
+void EmHAL::GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows)
+{
+ EmAssert (EmHAL::GetRootHandler());
+ EmHAL::GetRootHandler()->GetKeyInfo (numRows, numCols, keyMap, rows);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::LineDriverChanged
+// ---------------------------------------------------------------------------
+// Open or close the transports in response to their line drivers being
+// enabled or disabled.
+
+void EmHAL::LineDriverChanged (EmUARTDeviceType type)
+{
+ ErrCode err = errNone;
+ EmTransport* transport = gEmuPrefs->GetTransportForDevice (type);
+
+ if (transport)
+ {
+ if (EmHAL::GetLineDriverState (type))
+ {
+ err = transport->Open ();
+ }
+ else
+ {
+ /* err = */ transport->Close ();
+ }
+
+ if (err != errNone)
+ {
+ string errString (transport->GetSpecificName ());
+ ::PrvHandlePortOpenErrors (err, errString);
+ }
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::GetLineDriverState
+// ---------------------------------------------------------------------------
+// Return whether or not the line drivers for the given object are open or
+// closed.
+
+Bool EmHAL::GetLineDriverState (EmUARTDeviceType type)
+{
+ EmAssert (EmHAL::GetRootHandler());
+ return EmHAL::GetRootHandler()->GetLineDriverState (type);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::GetUARTDevice
+// ---------------------------------------------------------------------------
+// Return what sort of device is hooked up to the given UART.
+
+EmUARTDeviceType EmHAL::GetUARTDevice (int uartNum)
+{
+ EmAssert (EmHAL::GetRootHandler());
+ return EmHAL::GetRootHandler()->GetUARTDevice (uartNum);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::GetLineDriverStates
+// ---------------------------------------------------------------------------
+// Collect all the states of all the driver types we know about. Pass in to
+// this routine a variable of type Bool[kUARTEnd].
+
+void EmHAL::GetLineDriverStates (Bool* states)
+{
+ for (EmUARTDeviceType ii = kUARTBegin; ii < kUARTEnd; ++ii)
+ {
+ states[ii] = EmHAL::GetLineDriverState (ii);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::CompareLineDriverStates
+// ---------------------------------------------------------------------------
+// Collect the current state of all the line drivers, and compare them to
+// a previously-saved snapshot. For any differences, call LineDriverChanged.
+
+void EmHAL::CompareLineDriverStates (const Bool* oldStates)
+{
+ Bool newStates[kUARTEnd];
+ EmHAL::GetLineDriverStates (newStates);
+
+ for (EmUARTDeviceType ii = kUARTBegin; ii < kUARTEnd; ++ii)
+ {
+ if (newStates[ii] != oldStates[ii])
+ {
+ EmHAL::LineDriverChanged (ii);
+ }
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::GetDTR
+// ---------------------------------------------------------------------------
+// DTR is "Data Terminal Ready". In the same way that the RTS signal is
+// typically hooked up to the external device's CTS signal, our DTR pin is
+// hooked up to the external device's DSR pin. It can be modified in order
+// to tell the external device if we can accept any data.
+
+Bool EmHAL::GetDTR (int uartNum)
+{
+ EmAssert (EmHAL::GetRootHandler());
+ return EmHAL::GetRootHandler()->GetDTR (uartNum);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::DTRChanged
+// ---------------------------------------------------------------------------
+// Called when the Palm OS changes the setting of the DTR pin. We respond
+// to this change by reflecting the setting in the host's DTR pin.
+
+void EmHAL::DTRChanged (int uartNum)
+{
+ EmUARTDeviceType type = EmHAL::GetUARTDevice (uartNum);
+ EmTransport* transport = gEmuPrefs->GetTransportForDevice (type);
+ EmTransportSerial* serTransport = dynamic_cast<EmTransportSerial*> (transport);
+
+ if (serTransport)
+ {
+ Bool state = EmHAL::GetDTR (uartNum);
+ PRINTF ("EmHAL::DTRChanged: DTR changed in emulated port to %d.", (int) state);
+ serTransport->SetDTR (state);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::GetVibrateOn
+// ---------------------------------------------------------------------------
+
+Bool EmHAL::GetVibrateOn (void)
+{
+ EmAssert (EmHAL::GetRootHandler());
+ return EmHAL::GetRootHandler()->GetVibrateOn ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHAL::GetLEDState
+// ---------------------------------------------------------------------------
+
+uint16 EmHAL::GetLEDState (void)
+{
+ EmAssert (EmHAL::GetRootHandler());
+ return EmHAL::GetRootHandler()->GetLEDState ();
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// ¥ EmHALHandler::EmHALHandler
+// ---------------------------------------------------------------------------
+
+EmHALHandler::EmHALHandler (void) :
+ fNextHandler (NULL),
+ fPrevHandler (NULL)
+{
+ EmHAL::AddHandler (this);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHALHandler::~EmHALHandler
+// ---------------------------------------------------------------------------
+
+EmHALHandler::~EmHALHandler (void)
+{
+ EmHAL::RemoveHandler (this);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHALHandler::Cycle
+// ---------------------------------------------------------------------------
+
+void EmHALHandler::Cycle (Bool sleeping)
+{
+ EmAssert (this->GetNextHandler());
+ this->GetNextHandler()->Cycle (sleeping);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHALHandler::CycleSlowly
+// ---------------------------------------------------------------------------
+
+void EmHALHandler::CycleSlowly (Bool sleeping)
+{
+ EmAssert (this->GetNextHandler());
+ this->GetNextHandler()->CycleSlowly (sleeping);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHALHandler::ButtonEvent
+// ---------------------------------------------------------------------------
+
+void EmHALHandler::ButtonEvent (SkinElementType button, Bool buttonIsDown)
+{
+ EmAssert (this->GetNextHandler());
+ this->GetNextHandler()->ButtonEvent (button, buttonIsDown);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHALHandler::TurnSoundOff
+// ---------------------------------------------------------------------------
+
+void EmHALHandler::TurnSoundOff (void)
+{
+ EmAssert (this->GetNextHandler());
+ this->GetNextHandler()->TurnSoundOff ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHALHandler::ResetTimer
+// ---------------------------------------------------------------------------
+
+void EmHALHandler::ResetTimer (void)
+{
+ EmAssert (this->GetNextHandler());
+ this->GetNextHandler()->ResetTimer ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHALHandler::ResetRTC
+// ---------------------------------------------------------------------------
+
+void EmHALHandler::ResetRTC (void)
+{
+ EmAssert (this->GetNextHandler());
+ this->GetNextHandler()->ResetRTC ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHALHandler::GetInterruptLevel
+// ---------------------------------------------------------------------------
+
+int32 EmHALHandler::GetInterruptLevel (void)
+{
+ EmAssert (this->GetNextHandler());
+ return this->GetNextHandler()->GetInterruptLevel ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHALHandler::GetInterruptBase
+// ---------------------------------------------------------------------------
+
+int32 EmHALHandler::GetInterruptBase (void)
+{
+ EmAssert (this->GetNextHandler());
+ return this->GetNextHandler()->GetInterruptBase ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHALHandler::GetLCDScreenOn
+// ---------------------------------------------------------------------------
+
+Bool EmHALHandler::GetLCDScreenOn (void)
+{
+ EmAssert (this->GetNextHandler());
+ return this->GetNextHandler()->GetLCDScreenOn ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHALHandler::GetLCDBacklightOn
+// ---------------------------------------------------------------------------
+
+Bool EmHALHandler::GetLCDBacklightOn (void)
+{
+ EmAssert (this->GetNextHandler());
+ return this->GetNextHandler()->GetLCDBacklightOn ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHALHandler::GetLCDHasFrame
+// ---------------------------------------------------------------------------
+
+Bool EmHALHandler::GetLCDHasFrame (void)
+{
+ EmAssert (this->GetNextHandler());
+ return this->GetNextHandler()->GetLCDHasFrame ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHALHandler::GetLCDBeginEnd
+// ---------------------------------------------------------------------------
+
+void EmHALHandler::GetLCDBeginEnd (emuptr& begin, emuptr& end)
+{
+ EmAssert (this->GetNextHandler());
+ this->GetNextHandler()->GetLCDBeginEnd (begin, end);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHALHandler::GetLCDScanlines
+// ---------------------------------------------------------------------------
+
+void EmHALHandler::GetLCDScanlines (EmScreenUpdateInfo& info)
+{
+ EmAssert (this->GetNextHandler());
+ this->GetNextHandler()->GetLCDScanlines (info);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHALHandler::GetDynamicHeapSize
+// ---------------------------------------------------------------------------
+
+int32 EmHALHandler::GetDynamicHeapSize (void)
+{
+ EmAssert (this->GetNextHandler());
+ return this->GetNextHandler()->GetDynamicHeapSize ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHALHandler::GetROMSize
+// ---------------------------------------------------------------------------
+
+int32 EmHALHandler::GetROMSize (void)
+{
+ EmAssert (this->GetNextHandler());
+ return this->GetNextHandler()->GetROMSize ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHALHandler::GetROMBaseAddress
+// ---------------------------------------------------------------------------
+
+emuptr EmHALHandler::GetROMBaseAddress (void)
+{
+ EmAssert (this->GetNextHandler());
+ return this->GetNextHandler()->GetROMBaseAddress ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHALHandler::ChipSelectsConfigured
+// ---------------------------------------------------------------------------
+
+Bool EmHALHandler::ChipSelectsConfigured (void)
+{
+ EmAssert (this->GetNextHandler());
+ return this->GetNextHandler()->ChipSelectsConfigured ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHALHandler::GetSystemClockFrequency
+// ---------------------------------------------------------------------------
+
+int32 EmHALHandler::GetSystemClockFrequency (void)
+{
+ EmAssert (this->GetNextHandler());
+ return this->GetNextHandler()->GetSystemClockFrequency ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHALHandler::GetCanStop
+// ---------------------------------------------------------------------------
+
+Bool EmHALHandler::GetCanStop (void)
+{
+ EmAssert (this->GetNextHandler());
+ return this->GetNextHandler()->GetCanStop ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHALHandler::GetAsleep
+// ---------------------------------------------------------------------------
+
+Bool EmHALHandler::GetAsleep (void)
+{
+ EmAssert (this->GetNextHandler());
+ return this->GetNextHandler()->GetAsleep ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHALHandler::GetPortInputValue
+// ---------------------------------------------------------------------------
+
+uint8 EmHALHandler::GetPortInputValue (int port)
+{
+ EmAssert (this->GetNextHandler());
+ return this->GetNextHandler()->GetPortInputValue (port);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHALHandler::GetPortInternalValue
+// ---------------------------------------------------------------------------
+
+uint8 EmHALHandler::GetPortInternalValue (int port)
+{
+ EmAssert (this->GetNextHandler());
+ return this->GetNextHandler()->GetPortInternalValue (port);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHALHandler::PortDataChanged
+// ---------------------------------------------------------------------------
+
+void EmHALHandler::PortDataChanged (int port, uint8 oldVal, uint8 newVal)
+{
+ EmAssert (this->GetNextHandler());
+ this->GetNextHandler()->PortDataChanged (port, oldVal, newVal);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHALHandler::GetKeyInfo
+// ---------------------------------------------------------------------------
+
+void EmHALHandler::GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows)
+{
+ EmAssert (this->GetNextHandler());
+ this->GetNextHandler()->GetKeyInfo (numRows, numCols, keyMap, rows);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHALHandler::GetLineDriverState
+// ---------------------------------------------------------------------------
+// Return whether or not the line drivers for the given object are open or
+// closed.
+
+Bool EmHALHandler::GetLineDriverState (EmUARTDeviceType type)
+{
+ if (EmHALHandler::GetNextHandler())
+ {
+ return EmHALHandler::GetNextHandler()->GetLineDriverState (type);
+ }
+
+ return false;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHALHandler::GetUARTDevice
+// ---------------------------------------------------------------------------
+// Return what sort of device is hooked up to the given UART.
+
+EmUARTDeviceType EmHALHandler::GetUARTDevice (int uartNum)
+{
+ if (EmHALHandler::GetNextHandler())
+ {
+ return EmHALHandler::GetNextHandler()->GetUARTDevice (uartNum);
+ }
+
+ return kUARTNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHALHandler::GetDTR
+// ---------------------------------------------------------------------------
+// DTR is "Data Terminal Ready". In the same way that the RTS signal is
+// typically hooked up to the external device's CTS signal, our DTR pin is
+// hooked up to the external device's DSR pin. It can be modified in order
+// to tell the external device if we can accept any data.
+
+Bool EmHALHandler::GetDTR (int uartNum)
+{
+ if (EmHALHandler::GetNextHandler())
+ {
+ return EmHALHandler::GetNextHandler()->GetDTR (uartNum);
+ }
+
+ return false;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHALHandler::GetVibrateOn
+// ---------------------------------------------------------------------------
+
+Bool EmHALHandler::GetVibrateOn (void)
+{
+ if (!this->GetNextHandler())
+ return false;
+
+ EmAssert (this->GetNextHandler());
+ return this->GetNextHandler()->GetVibrateOn ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmHALHandler::GetLEDState
+// ---------------------------------------------------------------------------
+
+uint16 EmHALHandler::GetLEDState (void)
+{
+ if (!this->GetNextHandler())
+ return 0;
+
+ EmAssert (this->GetNextHandler());
+ return this->GetNextHandler()->GetLEDState ();
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: PrvHandlePortOpenErrors
+ *
+ * DESCRIPTION: .
+ *
+ * PARAMETERS: none.
+ *
+ * RETURNED: nothing, but displays one of two warnings if its cases
+ * are tripped.
+ *
+ ***********************************************************************/
+
+void PrvHandlePortOpenErrors (ErrCode err, string errString)
+{
+ switch (err)
+ {
+ // access denied, comm port, on Win32
+ case 5:
+ Errors::ReportErrCommPort (errString);
+ break;
+
+ // comm port error on Mac
+ case -97:
+ Errors::ReportErrCommPort (errString);
+ break;
+ }
+}
diff --git a/SrcShared/Hardware/EmHAL.h b/SrcShared/Hardware/EmHAL.h
new file mode 100644
index 0000000..4f01752
--- /dev/null
+++ b/SrcShared/Hardware/EmHAL.h
@@ -0,0 +1,164 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmHAL_h
+#define EmHAL_h
+
+#include "Skins.h" // SkinElementType
+
+class EmHAL;
+class EmPixMap;
+class EmScreenUpdateInfo;
+
+enum
+{
+ kLEDOff = 0x00,
+ kLEDGreen = 0x01,
+ kLEDRed = 0x02
+};
+
+enum EmUARTDeviceType
+{
+ kUARTBegin = 0,
+
+ kUARTSerial = kUARTBegin,
+ kUARTIR,
+ kUARTBluetooth,
+ kUARTMystery,
+ kUARTNone,
+
+ kUARTEnd
+};
+
+DEFINE_SCALAR_MODIFIERS (EmUARTDeviceType)
+
+class EmHALHandler
+{
+ public:
+ EmHALHandler (void);
+ virtual ~EmHALHandler (void);
+
+ virtual void Cycle (Bool sleeping);
+ virtual void CycleSlowly (Bool sleeping);
+
+ virtual void ButtonEvent (SkinElementType, Bool buttonIsDown);
+ virtual void TurnSoundOff (void);
+ virtual void ResetTimer (void);
+ virtual void ResetRTC (void);
+
+ virtual int32 GetInterruptLevel (void);
+ virtual int32 GetInterruptBase (void);
+
+ virtual Bool GetLCDScreenOn (void);
+ virtual Bool GetLCDBacklightOn (void);
+ virtual Bool GetLCDHasFrame (void);
+ virtual void GetLCDBeginEnd (emuptr&, emuptr&);
+ virtual void GetLCDScanlines (EmScreenUpdateInfo& info);
+
+ virtual int32 GetDynamicHeapSize (void);
+ virtual int32 GetROMSize (void);
+ virtual emuptr GetROMBaseAddress (void);
+ virtual Bool ChipSelectsConfigured (void);
+ virtual int32 GetSystemClockFrequency (void);
+ virtual Bool GetCanStop (void);
+ virtual Bool GetAsleep (void);
+
+ virtual uint8 GetPortInputValue (int);
+ virtual uint8 GetPortInternalValue (int);
+ virtual void PortDataChanged (int, uint8, uint8);
+ virtual void GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows);
+
+ virtual Bool GetLineDriverState (EmUARTDeviceType);
+ virtual EmUARTDeviceType GetUARTDevice (int uartNum);
+
+ virtual Bool GetDTR (int uartNum);
+
+ virtual Bool GetVibrateOn (void);
+ virtual uint16 GetLEDState (void);
+
+ protected:
+ EmHALHandler* GetNextHandler (void) { return fNextHandler; }
+
+ private:
+ EmHALHandler* fNextHandler;
+ EmHALHandler* fPrevHandler;
+
+ friend class EmHAL;
+};
+
+
+class EmHAL
+{
+ public:
+ static void AddHandler (EmHALHandler*);
+ static void RemoveHandler (EmHALHandler*);
+ static void EnsureCoverage (void);
+
+ static void Cycle (Bool sleeping);
+ static void CycleSlowly (Bool sleeping);
+
+ static void ButtonEvent (SkinElementType, Bool buttonIsDown);
+ static void TurnSoundOff (void);
+ static void ResetTimer (void);
+ static void ResetRTC (void);
+
+ static int32 GetInterruptLevel (void);
+ static int32 GetInterruptBase (void);
+
+ static Bool GetLCDScreenOn (void);
+ static Bool GetLCDBacklightOn (void);
+ static Bool GetLCDHasFrame (void);
+ static void GetLCDBeginEnd (emuptr&, emuptr&);
+ static void GetLCDScanlines (EmScreenUpdateInfo& info);
+
+ static int32 GetDynamicHeapSize (void);
+ static int32 GetROMSize (void);
+ static emuptr GetROMBaseAddress (void);
+ static Bool ChipSelectsConfigured (void);
+ static int32 GetSystemClockFrequency (void);
+ static Bool GetCanStop (void);
+ static Bool GetAsleep (void);
+
+ static uint8 GetPortInputValue (int);
+ static uint8 GetPortInternalValue (int);
+ static void PortDataChanged (int, uint8, uint8);
+ static void GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows);
+
+ static void LineDriverChanged (EmUARTDeviceType);
+ static Bool GetLineDriverState (EmUARTDeviceType);
+ static EmUARTDeviceType GetUARTDevice (int uartNum);
+
+ static void GetLineDriverStates (Bool* states);
+ static void CompareLineDriverStates (const Bool* oldStates);
+
+ static Bool GetDTR (int uartNum);
+ static void DTRChanged (int uartNum);
+
+ static Bool GetVibrateOn (void);
+ static uint16 GetLEDState (void);
+
+ private:
+ static EmHALHandler* GetRootHandler (void) { return fgRootHandler; }
+ static EmHALHandler* fgRootHandler;
+};
+
+inline void EmHAL::Cycle (Bool sleeping)
+{
+ EmAssert (EmHAL::GetRootHandler());
+ EmHAL::GetRootHandler()->Cycle (sleeping);
+}
+
+
+#endif /* EmHAL_h */
diff --git a/SrcShared/Hardware/EmMemory.cpp b/SrcShared/Hardware/EmMemory.cpp
new file mode 100644
index 0000000..90051ac
--- /dev/null
+++ b/SrcShared/Hardware/EmMemory.cpp
@@ -0,0 +1,1342 @@
+/* -*- 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 "EmMemory.h"
+
+#include "EmBankDRAM.h" // EmBankDRAM::Initialize
+#include "EmBankDummy.h" // EmBankDummy::Initialize
+#include "EmBankMapped.h" // EmBankMapped::Initialize
+#include "EmBankRegs.h" // EmBankRegs::Initialize
+#include "EmBankROM.h" // EmBankROM::Initialize
+#include "EmBankSRAM.h" // EmBankSRAM::Initialize
+#include "EmSession.h" // gSession, GetDevice
+#include "MetaMemory.h" // MetaMemory::Initialize
+
+
+#if HAS_PROFILING
+#include "Profiling.h" // gProfilingCounted
+#endif
+
+
+/*
+ Hitchhiker's Guide To Accessing Memory
+
+ When emulating CPU instructions, all memory access must be emulated as
+ well. Additionally, the memory location that the emulated instruction
+ is accessing is not necessarily the same as the memory location in the
+ emulator's address space. That is, memory location 0x00001234 in the
+ emulated process's address space is not the same as memory location
+ 0x00001234 in the emulator's address space. Instead, the emulated
+ 0x00001234 is actually 0x00001234 bytes into some buffer that we've
+ allocate for the purpose of holding the emulated address space's contents.
+
+ There are several ranges of Palm OS memory that we need to emulate:
+
+ - Low-memory RAM (for the dynamic heap)
+ - High-memory RAM (for the storage heap)
+ - ROM
+ - Dragonball and other memory-mapped registers
+ - Everything else
+
+ Each of these ranges (except for the last one) is managed by a set of
+ functions for reading from and writing to that memory and a chunk of
+ memory that we allocate as a "backing store" for that memory.
+
+ Thus, for each of these ranges, we need to quickly determine what set of
+ functions need to be called. The method for doing this is to divide the
+ entire 4GB address space into 64K banks, each 64K long.
+
+ Each 64K bank is managed by a set of functions. These functions handle
+ reading from and writing to that 64K bank, handling 1-byte, 2-byte, and
+ 4-byte accesses. They also manage mapping from the emulated addres space
+ to the physical space as viewed by the emulator, and validate memory
+ addresses.
+
+ Because there are 64K of these 64K banks, the functions that manage each
+ bank are stored in an array of 64K elements. When we need to invoke a
+ function for a particular bank, the upper word of the prospective memory
+ address is used as a "bank index" into this array. From that, the right
+ set of functions is found, and the desired function from that set of
+ functions is called.
+
+ This 64K array is very sparse. There are one to four entries for managing
+ the dynamic heap (depending on whether the dynamic heap is 64K, 96K, 128K,
+ or 256K), 2 to 128 entries for the storage heap (depending on whether the
+ storage heap is 128K to 8Meg), 8 to 32 entries for the ROM (again,
+ depending on its size), and 1 for the Dragonball registers. That leaves
+ the remaining 64K - 12 entries to be managed by a set of functions that do
+ little but signal an address error if the memory they manage is being
+ accessed.
+
+ Pictorally, it looks like this:
+
+ Emulated 4G space: Memory function array Address Bank functions
+
+ 0x00000000 +--------------+ +--------------------------------+
+ | 64K |<---| Ptr to fns that mng this range |------+
+ 0x00010000 +--------------+ +--------------------------------+ |
+ | 64K |<---| Ptr to fns that mng this range |------+
+ 0x00020000 +--------------+ +--------------------------------+ |
+ | 64K | +-----> EmBankDRAM::GetLong, EmBankDRAM::SetLong
+ \/\/\/\/\/\/\/\/ EmBankDRAM::GetWord, EmBankDRAM::SetWord
+ \/\/\/\/\/\/\/\/ EmBankDRAM::GetByte, EmBankDRAM::SetByte
+ | 64K | etc.
+ 0x10000000 +--------------+ +--------------------------------+
+ | 64K |<---| Ptr to fns that mng this range |------+
+ 0x10010000 +--------------+ +--------------------------------+ |
+ | 64K |<---| Ptr to fns that mng this range |------+
+ 0x10020000 +--------------+ +--------------------------------+ |
+ | 64K | +-----> EmBankSRAM::GetLong, EmBankSRAM::SetLong
+ \/\/\/\/\/\/\/\/ EmBankSRAM::GetWord, EmBankSRAM::SetWord
+ \/\/\/\/\/\/\/\/ EmBankSRAM::GetByte, EmBankSRAM::SetByte
+ | 64K | etc.
+ 0x10C00000 +--------------+ +--------------------------------+
+ | 64K |<---| Ptr to fns that mng this range |------+
+ 0x10C10000 +--------------+ +--------------------------------+ |
+ | 64K |<---| Ptr to fns that mng this range |------+
+ 0x10C20000 +--------------+ +--------------------------------+ |
+ | 64K | +-----> EmBankROM::GetLong, EmBankROM::SetLong
+ \/\/\/\/\/\/\/\/ EmBankROM::GetWord, EmBankROM::SetWord
+ \/\/\/\/\/\/\/\/ EmBankROM::GetByte, EmBankROM::SetByte
+ | 64K | etc.
+ 0xFFFE0000 +--------------+ +--------------------------------+
+ | 64K |<---| Ptr to fns that mng this range |
+ 0xFFFF0000 +--------------+ +--------------------------------+
+ | 64K |<---| Ptr to fns that mng this range |------+
+ 0xFFFFFFFF +--------------+ +--------------------------------+ |
+ +-----> EmRegs::GetLong, EmRegs::SetLong
+ EmRegs::GetWord, EmRegs::SetWord
+ EmRegs::GetByte, EmRegs::SetByte
+ etc.
+
+ All of the remaining memory function array entries are initialized with
+ pointers to the EmBankDummy::GetLong, EmBankDummy::SetLong, etc., set of
+ functions.
+
+ Using EmBankMapped accessors, we also have the facility for mapping memory
+ from the emulator's address space directly into the emulated address
+ space. This memory appears as additional RAM that magically appears out
+ of nowhere. This mechanism makes it easy for us to "inject" data into the
+ emulated address space. It also makes it easier to call emulated ROM
+ functions as subroutines. Some ROM functions take as parameters pointers
+ to memory locations that are to receive values (for example, pointers to
+ local variables). For those functions, we just map the emulator's stack
+ into the emulated address space. After that's done, we can pass pointers
+ to stack-based variables with impunity.
+
+ A 64K bank can be further sub-divided into 1, 2, or 4 byte chunks
+ spanning any range of the 64K chunk. EmBankRegs manages a collection
+ of EmRegs objects. The EmRegs abstract base class is sub-classed into
+ classes that specify the sub-range of the 64K for which they are
+ responsible and dispatch memory accesses to individual functions
+ that handle accesses at more-or-less a byte level.
+
+ Mapping from emulated addresses to "real" addresses (that is, the
+ corresponding memory locations within the buffers we've allocated to
+ "stand in" for the emulated memory) is performed via macros and inline
+ functions, described below.
+
+ Executive summary:
+
+ - use EmMemGetFoo if you want the address checked for even/oddness.
+ - use EmMemDoGetFoo to actually get the value using a physical address.
+
+ EmMemGet32, EmMemGet16, EmMemGet8
+ EmMemPut32, EmMemPut16, EmMemPut8
+ Inline functions that dispatch to the right bank of functions
+ using EmMemCallGetFunc, EmMemGetBank, and EmMemBankIndex.
+
+ EmMemBankIndex
+ Returns a bank index for the given address.
+
+ EmMemGetBank
+ Gets the right EmAddressBank object.
+
+ EmMemCallGetFunc
+ Merely calls the given function through the EmAddressBank fn ptr.
+
+ EmMemDoGet32, EmMemDoGet16, EmMemDoGet8
+ EmMemDoPut32, EmMemDoPut16, EmMemDoPut8
+ Very low-level memory access. They return the value at the
+ given physical location, byte-swapping if needed.
+*/
+
+// Types.
+
+#pragma mark Types
+
+// Globals.
+
+#pragma mark Globals
+
+EmAddressBank* gEmMemBanks[65536]; // (normally defined in memory.c)
+
+Bool gPCInRAM;
+Bool gPCInROM;
+
+MemAccessFlags gMemAccessFlags =
+{
+ MASTER_RUNTIME_VALIDATE_SWITCH,
+ MASTER_RUNTIME_VALIDATE_SWITCH,
+ MASTER_RUNTIME_VALIDATE_SWITCH,
+ MASTER_RUNTIME_VALIDATE_SWITCH,
+ MASTER_RUNTIME_VALIDATE_SWITCH,
+ MASTER_RUNTIME_VALIDATE_SWITCH,
+ MASTER_RUNTIME_VALIDATE_SWITCH,
+ MASTER_RUNTIME_VALIDATE_SWITCH,
+ MASTER_RUNTIME_VALIDATE_SWITCH,
+ MASTER_RUNTIME_VALIDATE_SWITCH,
+
+ // User prevention flags.
+
+// MASTER_RUNTIME_PREVENT_SWITCH,
+// MASTER_RUNTIME_PREVENT_SWITCH,
+// MASTER_RUNTIME_PREVENT_SWITCH,
+// MASTER_RUNTIME_PREVENT_SWITCH,
+// MASTER_RUNTIME_PREVENT_SWITCH,
+// MASTER_RUNTIME_PREVENT_SWITCH,
+ false, // SRAM-get
+ true, // SRAM-set
+ false, // ROM-get
+ true, // ROM-set (HACK: We really want it to be true!)
+ MASTER_RUNTIME_PREVENT_SWITCH,
+ MASTER_RUNTIME_PREVENT_SWITCH,
+
+// false, // fCheck_UserChunkGet
+// false, // fCheck_UserChunkSet
+// false, // fCheck_SysChunkGet
+// false, // fCheck_SysChunkSet
+
+ // System prevention flags.
+
+// MASTER_RUNTIME_PREVENT_SWITCH,
+// MASTER_RUNTIME_PREVENT_SWITCH,
+// MASTER_RUNTIME_PREVENT_SWITCH,
+// MASTER_RUNTIME_PREVENT_SWITCH,
+// MASTER_RUNTIME_PREVENT_SWITCH,
+// MASTER_RUNTIME_PREVENT_SWITCH,
+// false, // SRAM-get
+// true, // SRAM-set
+ false, // ROM-get
+ true, // ROM-set (HACK: We really want it to be true!)
+// MASTER_RUNTIME_PREVENT_SWITCH,
+// MASTER_RUNTIME_PREVENT_SWITCH
+};
+
+MemAccessFlags kZeroMemAccessFlags;
+
+
+#if PROFILE_MEMORY
+/*
+ After 12 Million instructions executed...
+
+ kDRAMLongRead, // 2,797,111
+ kDRAMLongRead2, //
+ kDRAMWordRead, // 1,334,295
+ kDRAMByteRead, // 427,936
+
+ kDRAMLongWrite, // 1,960,933
+ kDRAMLongWrite2, //
+ kDRAMWordWrite, // 800,780
+ kDRAMByteWrite, // 213,029
+
+ kSRAMLongRead, // 4,167
+ kSRAMLongRead2, // 4,167
+ kSRAMWordRead, // 10,768
+ kSRAMByteRead, // 6,295 (jumped WAY up (5-fold) after playing with Address Book / 20 Million instructions)
+
+ kSRAMLongWrite, // 516,246 (stable after boot?)
+ kSRAMLongWrite2, //
+ kSRAMWordWrite, // 5,112
+ kSRAMByteWrite, // 2,183
+
+ kROMLongRead, // 10,156
+ kROMLongRead2, //
+ kROMWordRead, // 557,062
+ kROMByteRead, // 15,516
+
+ kROMLongWrite, // 0
+ kROMLongWrite2, //
+ kROMWordWrite, // 0
+ kROMByteWrite, // 0
+
+ kREGLongRead, // 16,638
+ kREGLongRead2, //
+ kREGWordRead, // 30,477
+ kREGByteRead, // 3,553
+
+ kREGLongWrite, // 9,472
+ kREGLongWrite2, //
+ kREGWordWrite, // 20,709
+ kREGByteWrite, // 12,656
+
+
+ After 32,439,154 instructions:
+
+ kDRAMLongRead, // 6,466,064
+ kDRAMWordRead, // 3,342,826
+ kDRAMByteRead, // 940,345
+
+ kDRAMLongWrite, // 4,136,635
+ kDRAMWordWrite, // 1,462,995
+ kDRAMByteWrite, // 509,189
+
+ kSRAMLongRead, // 24,355
+ kSRAMWordRead, // 32,190
+ kSRAMByteRead, // 75,917
+
+ kSRAMLongWrite, // 2,074,137 (8-Meg ROM)
+ kSRAMWordWrite, // 42,050
+ kSRAMByteWrite, // 11,292
+
+ kROMLongRead, // 25,806
+ kROMWordRead, // 1,302,897
+ kROMByteRead, // 63,590
+
+ kROMLongWrite, // 0
+ kROMWordWrite, // 0
+ kROMByteWrite, // 0
+
+ kREGLongRead, // 32,037
+ kREGWordRead, // 74,299
+ kREGByteRead, // 91,930
+
+ kREGLongWrite, // 20,358
+ kREGWordWrite, // 57,879
+ kREGByteWrite, // 22,592
+*/
+
+long gMemoryAccess[kLastEnum];
+#endif
+
+
+#pragma mark -
+
+
+// ===========================================================================
+// ¥ Memory
+// ===========================================================================
+
+
+// ---------------------------------------------------------------------------
+// ¥ Memory::Initialize
+// ---------------------------------------------------------------------------
+// Initializes the RAM, ROM, and special memory areas of the emulator. Takes
+// a stream handle to the ROM.
+
+void Memory::Initialize ( EmStream& hROM,
+ RAMSizeType ramSize)
+{
+ // Clear everything out.
+
+ memset (gEmMemBanks, 0, sizeof (gEmMemBanks));
+
+ // Initialize the valid memory banks.
+
+ EmBankDummy::Initialize ();
+
+ // Initialize the Hardware registers memory bank. Do this
+ // *before* initializing the other RAM banks so that we
+ // know how memory is laid out from the chip selects.
+
+ EmBankRegs::Initialize ();
+
+ // Initialize EmBankDRAM after initializing the EmBankSRAM. The order is
+ // important for DragonballEZ. On Dragonball devices, DRAM is
+ // at 0x00000000, and SRAM is at 0x10000000. But on EZ devices,
+ // both start at 0x00000000. By calling EmBankDRAM::Initialize
+ // second, we allow it to overwrite the EmAddressBank handlers
+ // for the part of memory where they overlap.
+
+ EmBankSRAM::Initialize (ramSize);
+ EmBankDRAM::Initialize ();
+
+ EmBankROM::Initialize (hROM);
+
+ EmBankMapped::Initialize ();
+
+ EmAssert (gSession);
+ if (gSession->GetDevice ().HasFlash ())
+ EmBankFlash::Initialize ();
+
+ MetaMemory::Initialize ();
+
+// Memory::ResetBankHandlers (); // Can't do this yet. We can't set the
+ // bank handlers until we know how memory
+ // is laid out, and that information isn't
+ // determined until reset.
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: Memory::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 Memory::Reset (Bool hardwareReset)
+{
+ EmBankDummy::Reset (hardwareReset);
+ EmBankRegs::Reset (hardwareReset);
+ EmBankSRAM::Reset (hardwareReset);
+ EmBankDRAM::Reset (hardwareReset);
+ EmBankROM::Reset (hardwareReset);
+ EmBankMapped::Reset (hardwareReset);
+
+ EmAssert (gSession);
+ if (gSession->GetDevice ().HasFlash ())
+ EmBankFlash::Reset (hardwareReset);
+
+ Memory::ResetBankHandlers ();
+
+ MetaMemory::Reset ();
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: Memory::Save
+ *
+ * DESCRIPTION: Standard save function. Saves any sub-system state to
+ * the given session file.
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void Memory::Save (SessionFile& f)
+{
+ EmBankDummy::Save (f);
+ EmBankRegs::Save (f);
+ EmBankSRAM::Save (f);
+ EmBankDRAM::Save (f);
+ EmBankROM::Save (f);
+ EmBankMapped::Save (f);
+
+ EmAssert (gSession);
+ if (gSession->GetDevice ().HasFlash ())
+ EmBankFlash::Save (f);
+
+ MetaMemory::Save (f);
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: Memory::Load
+ *
+ * DESCRIPTION: Standard load function. Loads any sub-system state
+ * from the given session file.
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void Memory::Load (SessionFile& f)
+{
+ EmBankDummy::Load (f);
+ EmBankRegs::Load (f);
+ EmBankSRAM::Load (f);
+ EmBankDRAM::Load (f);
+ EmBankROM::Load (f);
+ EmBankMapped::Load (f);
+
+ EmAssert (gSession);
+ if (gSession->GetDevice ().HasFlash ())
+ EmBankFlash::Load (f);
+
+ MetaMemory::Load (f);
+
+ Memory::ResetBankHandlers ();
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: Memory::Dispose
+ *
+ * DESCRIPTION: Standard dispose function. Completely release any
+ * resources acquired or allocated in Initialize and/or
+ * Load.
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void Memory::Dispose (void)
+{
+ EmBankDummy::Dispose ();
+ EmBankRegs::Dispose ();
+ EmBankSRAM::Dispose ();
+ EmBankDRAM::Dispose ();
+ EmBankROM::Dispose ();
+ EmBankMapped::Dispose ();
+
+ // We can't reliably call GetDevice here. That's because the
+ // session may not have been initialized (we could be disposing
+ // of everything because an error condition occurred), and so
+ // there may be no assigned device yet. So we can't ask that
+ // device if there's flash. However, EmBankFlash::Dispose
+ // doesn't do anything, so we don'thave to worry about it
+ // being called.
+
+// EmAssert (gSession);
+// if (gSession->GetDevice ().HasFlash ())
+// EmBankFlash::Dispose ();
+
+ MetaMemory::Dispose ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ Memory::InitializeBanks
+// ---------------------------------------------------------------------------
+// Initializes the specified memory banks with the given data.
+
+void Memory::InitializeBanks ( EmAddressBank& iBankInitializer,
+ int32 iStartingBankIndex,
+ int32 iNumberOfBanks)
+{
+ for (int32 aBankIndex = iStartingBankIndex;
+ aBankIndex < iStartingBankIndex + iNumberOfBanks;
+ aBankIndex++)
+ {
+ gEmMemBanks[aBankIndex] = &iBankInitializer;
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ Memory::ResetBankHandlers
+// ---------------------------------------------------------------------------
+// Reset the memory bank handlers in response to the chip selects changing.
+// Also called on Initialize, Reset, and Load, just to make sure everything's
+// nailed down.
+
+void Memory::ResetBankHandlers (void)
+{
+ EmBankDummy::SetBankHandlers ();
+ EmBankRegs::SetBankHandlers ();
+ EmBankSRAM::SetBankHandlers ();
+ EmBankDRAM::SetBankHandlers ();
+ EmBankROM::SetBankHandlers ();
+ EmBankMapped::SetBankHandlers ();
+
+ if (gSession->GetDevice ().HardwareID () == 0x0a /*halModelIDVisorPrism*/)
+ {
+ // Run this one again. Visor Prism has this thing where the USB
+ // controller is at 0x10800000, but it sets up the ROM chip select
+ // for 0x10000000 to 0x10FFFFFF. In order to not have EmBankROM
+ // take control over the USB chip, have EmBankRegs install *after*
+ // EmBankROM.
+ EmBankRegs::SetBankHandlers ();
+ }
+
+ EmAssert (gSession);
+ if (gSession->GetDevice ().HasFlash ())
+ EmBankFlash::SetBankHandlers ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ Memory::MapPhysicalMemory
+// ---------------------------------------------------------------------------
+// Maps a range of physical memory to appear at the same location of the
+// emulated Palm OS's virtual memory.
+
+void Memory::MapPhysicalMemory (const void* addr, uint32 size)
+{
+ EmBankMapped::MapPhysicalMemory (addr, size);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ Memory::UnmapPhysicalMemory
+// ---------------------------------------------------------------------------
+// Unmaps a range of physical memory from appearing at the same location of
+// the emulated Palm OS's virtual memory.
+
+void Memory::UnmapPhysicalMemory (const void* addr)
+{
+ EmBankMapped::UnmapPhysicalMemory (addr);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ Memory::GetMappingInfo
+// ---------------------------------------------------------------------------
+
+void Memory::GetMappingInfo (emuptr addr, void** start, uint32* len)
+{
+ EmBankMapped::GetMappingInfo (addr, start, len);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ Memory::CheckNewPC
+// ---------------------------------------------------------------------------
+
+void Memory::CheckNewPC (emuptr newPC)
+{
+ gPCInRAM = newPC < EmBankROM::GetMemoryStart ();
+ gPCInROM = newPC >= EmBankROM::GetMemoryStart ();
+}
+
+
+#pragma mark -
+
+// ===========================================================================
+// ¥ CEnableFullAccess
+// ===========================================================================
+
+long CEnableFullAccess::fgAccessCount = 0;
+
+
+// ---------------------------------------------------------------------------
+// ¥ CEnableFullAccess::CEnableFullAccess
+// ---------------------------------------------------------------------------
+
+CEnableFullAccess::CEnableFullAccess (void) :
+ fOldMemAccessFlags (gMemAccessFlags)
+#if HAS_PROFILING
+ , fOldProfilingCounted (gProfilingCounted)
+#endif
+{
+ gMemAccessFlags = kZeroMemAccessFlags;
+
+#if HAS_PROFILING
+ gProfilingCounted = false;
+#endif
+
+ ++fgAccessCount;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ CEnableFullAccess::~CEnableFullAccess
+// ---------------------------------------------------------------------------
+
+CEnableFullAccess::~CEnableFullAccess (void)
+{
+ gMemAccessFlags = fOldMemAccessFlags;
+
+#if HAS_PROFILING
+ gProfilingCounted = fOldProfilingCounted;
+#endif
+
+ --fgAccessCount;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ CEnableFullAccess::AccessOK
+// ---------------------------------------------------------------------------
+
+Bool CEnableFullAccess::AccessOK (void)
+{
+ return fgAccessCount > 0;
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// These functions with two kinds of "pointers": emuptr's
+// and void*'s. Accessing memory for each kind of pointer is different.
+// Since the functions are template functions, we can't know at the time we
+// write the function what kind of pointer we'll be dealing with, so we can't
+// hard-code the memory-accessing method. Instead, we provide all of these
+// inline accessors and let the compiler sort it out.
+// ---------------------------------------------------------------------------
+
+inline char _get_byte(const void* p)
+{
+ return *(char*) p;
+}
+
+inline char _get_byte(emuptr p)
+{
+ return (char) EmMemGet8(p);
+}
+
+inline void _put_byte(void* p, const uint8 v)
+{
+ *(uint8*) p = v;
+}
+
+inline void _put_byte(emuptr p, const uint8 v)
+{
+ EmMemPut8(p, v);
+}
+
+inline uint16 _get_word(const void* p)
+{
+ return *(uint16*) p;
+}
+
+inline uint16 _get_word(emuptr p)
+{
+ return (uint16) EmMemGet16(p);
+}
+
+inline void _put_word(void* p, const uint16 v)
+{
+ *(uint16*) p = v;
+}
+
+inline void _put_word(emuptr p, const uint16 v)
+{
+ EmMemPut16(p, v);
+}
+
+inline uint32 _get_long(const void* p)
+{
+ return *(uint32*) p;
+}
+
+inline uint32 _get_long(emuptr p)
+{
+ return (uint32) EmMemGet32(p);
+}
+
+inline void _put_long(void* p, const uint32 v)
+{
+ *(uint32*) p = v;
+}
+
+inline void _put_long(emuptr p, const uint32 v)
+{
+ EmMemPut32(p, v);
+}
+
+inline const void* _get_real_address(const void* p)
+{
+ return p;
+}
+
+inline const void* _get_real_address(emuptr p)
+{
+ return EmMemGetRealAddress(p);
+}
+
+template <class T>
+inline void _add_delta (T*& v, long delta)
+{
+ v = (T*) (((char*) v) + delta);
+}
+
+inline void _add_delta (emuptr& v, long delta)
+{
+ v += delta;
+}
+
+template <class T>
+inline void _increment (T& v)
+{
+ _add_delta (v, 1);
+}
+
+template <class T>
+inline void _decrement (T& v)
+{
+ _add_delta (v, -1);
+}
+
+
+#pragma mark -
+
+/***********************************************************************
+ *
+ * FUNCTION: EmMem_memset
+ *
+ * DESCRIPTION: Same as Std C Library memset function.
+ *
+ * PARAMETERS: Same as Std C Library memset function.
+ *
+ * RETURNED: Same as Std C Library memset function.
+ *
+ ***********************************************************************/
+
+emuptr EmMem_memset(emuptr dst, int val, size_t len)
+{
+ emuptr q = dst;
+
+ uint32 longVal = val;
+ longVal |= (longVal << 8);
+ longVal |= (longVal << 16);
+
+ EmMemPutFunc longPutter = EmMemGetBank(dst).lput;
+ EmMemPutFunc bytePutter = EmMemGetBank(dst).bput;
+
+ while ((q & 3) && len > 0) // while there are leading bytes
+ {
+ bytePutter(q, val);
+ q += sizeof (char);
+ len -= sizeof (char);
+ }
+
+ while (len >= sizeof (long)) // while there are middle longs
+ {
+ longPutter(q, longVal);
+ q += sizeof (long);
+ len -= sizeof (long);
+ }
+
+ while (len > 0) // while there are trailing bytes
+ {
+ bytePutter(q, val);
+ q += sizeof (char);
+ len -= sizeof (char);
+ }
+
+ return dst;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmMem_memchr
+ *
+ * DESCRIPTION: Same as Std C Library memchr function.
+ *
+ * PARAMETERS: Same as Std C Library memchr function.
+ *
+ * RETURNED: Same as Std C Library memchr function.
+ *
+ ***********************************************************************/
+
+emuptr EmMem_memchr(emuptr src, int val, size_t len)
+{
+ emuptr p = src;
+
+ ++len;
+
+ while (--len)
+ {
+ if (_get_byte (p) == val)
+ return p;
+
+ _increment (p);
+ }
+
+ return EmMemNULL;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmMem_memcmp
+ *
+ * DESCRIPTION: Same as Std C Library memcmp function.
+ *
+ * PARAMETERS: Same as Std C Library memcmp function.
+ *
+ * RETURNED: Same as Std C Library memcmp function.
+ *
+ ***********************************************************************/
+
+template <class T1, class T2>
+int EmMem_memcmp(T1 src1, T2 src2, size_t len)
+{
+ T1 p1 = src1;
+ T2 p2 = src2;
+
+ ++len;
+
+ while (--len)
+ {
+ unsigned char ch1 = _get_byte (p1);
+ unsigned char ch2 = _get_byte (p2);
+
+ if (ch1 != ch2)
+ return (ch1 < ch2) ? -1 : 1;
+
+ _increment (p1);
+ _increment (p2);
+ }
+
+ return 0;
+}
+
+ // Instantiate EmMem_memcmp's that work with:
+ //
+ // dest source
+ // ------ ------
+ // void* emuptr
+ // const void* emuptr
+ // emuptr void*
+ // emuptr const void*
+ // emuptr emuptr
+
+template int EmMem_memcmp<void*, emuptr> (void* dst, emuptr src, size_t len);
+template int EmMem_memcmp<const void*, emuptr> (const void* dst, emuptr src, size_t len);
+template int EmMem_memcmp<emuptr, void*> (emuptr dst, void* src, size_t len);
+template int EmMem_memcmp<emuptr, const void*> (emuptr dst, const void* src, size_t len);
+template int EmMem_memcmp<emuptr, emuptr> (emuptr dst, emuptr src, size_t len);
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmMem_memcpy
+ *
+ * DESCRIPTION: Same as Std C Library memcpy function.
+ *
+ * PARAMETERS: Same as Std C Library memcpy function.
+ *
+ * RETURNED: Same as Std C Library memcpy function.
+ *
+ ***********************************************************************/
+
+template <class T1, class T2>
+T1 EmMem_memcpy (T1 dst, T2 src, size_t len)
+{
+ T1 q = dst;
+ T2 p = src;
+
+ while (len--)
+ {
+ _put_byte(q, _get_byte(p));
+ _increment (q);
+ _increment (p);
+ }
+
+ return dst;
+}
+
+ // Instantiate EmMem_memcpy's that work with:
+ //
+ // dest source
+ // ------ ------
+ // void* emuptr
+ // emuptr void*
+ // emuptr const void*
+ // emuptr emuptr
+
+template void* EmMem_memcpy<void*, emuptr> (void* dst, emuptr src, size_t len);
+template emuptr EmMem_memcpy<emuptr, void*> (emuptr dst, void* src, size_t len);
+template emuptr EmMem_memcpy<emuptr, const void*> (emuptr dst, const void* src, size_t len);
+template emuptr EmMem_memcpy<emuptr, emuptr> (emuptr dst, emuptr src, size_t len);
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmMem_memmove
+ *
+ * DESCRIPTION: Same as Std C Library memmove function.
+ *
+ * PARAMETERS: Same as Std C Library memmove function.
+ *
+ * RETURNED: Same as Std C Library memmove function.
+ *
+ ***********************************************************************/
+
+template <class T1, class T2>
+T1 EmMem_memmove (T1 dst, T2 src, size_t len)
+{
+ T1 q = dst;
+ T2 p = src;
+
+ Bool backward = _get_real_address(dst) <= _get_real_address(src);
+
+ if (backward)
+ {
+ while (len--)
+ {
+ _put_byte(q, _get_byte(p));
+ _increment (q);
+ _increment (p);
+ }
+ }
+ else
+ {
+ _add_delta (q, len);
+ _add_delta (p, len);
+
+ while (len--)
+ {
+ _decrement (q);
+ _decrement (p);
+ _put_byte(q, _get_byte(p));
+ }
+ }
+
+ return dst;
+}
+
+ // Instantiate EmMem_memmove's that work with:
+ //
+ // dest source
+ // ------ ------
+ // void* emuptr
+ // emuptr void*
+ // emuptr const void*
+ // emuptr emuptr
+
+template void* EmMem_memmove<void*, emuptr> (void* dst, emuptr src, size_t len);
+template emuptr EmMem_memmove<emuptr, void*> (emuptr dst, void* src, size_t len);
+template emuptr EmMem_memmove<emuptr, const void*> (emuptr dst, const void* src, size_t len);
+template emuptr EmMem_memmove<emuptr, emuptr> (emuptr dst, emuptr src, size_t len);
+
+
+#pragma mark -
+
+/***********************************************************************
+ *
+ * FUNCTION: EmMem_strlen
+ *
+ * DESCRIPTION: Same as Std C Library strlen function.
+ *
+ * PARAMETERS: Same as Std C Library strlen function.
+ *
+ * RETURNED: Same as Std C Library strlen function.
+ *
+ ***********************************************************************/
+
+size_t EmMem_strlen(emuptr str)
+{
+ emuptr eos = str;
+
+ while (_get_byte(eos))
+ _increment (eos);
+
+ return ((size_t) (eos - str));
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmMem_strcpy
+ *
+ * DESCRIPTION: Same as Std C Library strcpy function.
+ *
+ * PARAMETERS: Same as Std C Library strcpy function.
+ *
+ * RETURNED: Same as Std C Library strcpy function.
+ *
+ ***********************************************************************/
+
+template <class T1, class T2>
+T1 EmMem_strcpy(T1 dst, T2 src)
+{
+ T1 q = dst;
+ T2 p = src;
+ char ch;
+
+ do {
+ ch = _get_byte (p);
+ _increment (p);
+ _put_byte (q, ch);
+ _increment (q);
+ } while (ch);
+
+ return dst;
+}
+
+ // Instantiate EmMem_strcpy's that work with:
+ //
+ // dest source
+ // ------ ------
+ // char* emuptr
+ // emuptr char*
+ // emuptr const char*
+ // emuptr emuptr
+
+template char* EmMem_strcpy<char*, emuptr> (char* dst, emuptr src);
+template emuptr EmMem_strcpy<emuptr, char*> (emuptr dst, char* src);
+template emuptr EmMem_strcpy<emuptr, const char*> (emuptr dst, const char* src);
+template emuptr EmMem_strcpy<emuptr, emuptr> (emuptr dst, emuptr src);
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmMem_strncpy
+ *
+ * DESCRIPTION: Same as Std C Library strncpy function.
+ *
+ * PARAMETERS: Same as Std C Library strncpy function.
+ *
+ * RETURNED: Same as Std C Library strncpy function.
+ *
+ ***********************************************************************/
+
+template <class T1, class T2>
+T1 EmMem_strncpy(T1 dst, T2 src, size_t len)
+{
+ T1 q = dst;
+ T2 p = src;
+
+ ++len;
+
+ while (--len)
+ {
+ char ch = _get_byte(p);
+ _increment (p);
+
+ _put_byte (q, ch);
+ _increment (q);
+
+ if (!ch)
+ {
+ while (--len)
+ {
+ _put_byte (q, 0);
+ _increment (q);
+ }
+
+ break;
+ }
+ }
+
+ return dst;
+}
+
+ // Instantiate EmMem_strncpy's that work with:
+ //
+ // dest source
+ // ------ ------
+ // char* emuptr
+ // emuptr char*
+ // emuptr const char*
+ // emuptr emuptr
+
+template char* EmMem_strncpy<char*, emuptr> (char* dst, emuptr src, size_t len);
+template emuptr EmMem_strncpy<emuptr, char*> (emuptr dst, char* src, size_t len);
+template emuptr EmMem_strncpy<emuptr, const char*> (emuptr dst, const char* src, size_t len);
+template emuptr EmMem_strncpy<emuptr, emuptr> (emuptr dst, emuptr src, size_t len);
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmMem_strcat
+ *
+ * DESCRIPTION: Same as Std C Library strcat function.
+ *
+ * PARAMETERS: Same as Std C Library strcat function.
+ *
+ * RETURNED: Same as Std C Library strcat function.
+ *
+ ***********************************************************************/
+
+template <class T1, class T2>
+T1 EmMem_strcat(T1 dst, T2 src)
+{
+ T1 q = dst;
+ T2 p = src;
+
+ while (_get_byte (q))
+ _increment(q);
+
+ while (_get_byte (p))
+ {
+ _put_byte (q, _get_byte (p));
+ _increment(q);
+ _increment(p);
+ }
+
+ _put_byte (q, 0);
+
+ return dst;
+}
+
+ // Instantiate EmMem_strcat's that work with:
+ //
+ // dest source
+ // ------ ------
+ // char* emuptr
+ // emuptr char*
+ // emuptr const char*
+ // emuptr emuptr
+
+template char* EmMem_strcat<char*, emuptr> (char* dst, emuptr src);
+template emuptr EmMem_strcat<emuptr, char*> (emuptr dst, char* src);
+template emuptr EmMem_strcat<emuptr, const char*> (emuptr dst, const char* src);
+template emuptr EmMem_strcat<emuptr, emuptr> (emuptr dst, emuptr src);
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmMem_strncat
+ *
+ * DESCRIPTION: Same as Std C Library strncat function.
+ *
+ * PARAMETERS: Same as Std C Library strncat function.
+ *
+ * RETURNED: Same as Std C Library strncat function.
+ *
+ ***********************************************************************/
+
+template <class T1, class T2>
+T1 EmMem_strncat(T1 dst, T2 src, size_t len)
+{
+ T1 q = dst;
+ T2 p = src;
+
+ while (_get_byte (q))
+ _increment (q);
+
+ ++len;
+
+ while (--len)
+ {
+ char ch = _get_byte(p);
+ _increment (p);
+
+ _put_byte (q, ch);
+ _increment (q);
+
+ if (!ch)
+ return dst;
+ }
+
+ _put_byte (q, 0);
+
+ return dst;
+}
+
+ // Instantiate EmMem_strncat's that work with:
+ //
+ // dest source
+ // ------ ------
+ // char* emuptr
+ // emuptr char*
+ // emuptr const char*
+ // emuptr emuptr
+
+template char* EmMem_strncat<char*, emuptr> (char* dst, emuptr src, size_t len);
+template emuptr EmMem_strncat<emuptr, char*> (emuptr dst, char* src, size_t len);
+template emuptr EmMem_strncat<emuptr, const char*> (emuptr dst, const char* src, size_t len);
+template emuptr EmMem_strncat<emuptr, emuptr> (emuptr dst, emuptr src, size_t len);
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmMem_strcmp
+ *
+ * DESCRIPTION: Same as Std C Library strcmp function.
+ *
+ * PARAMETERS: Same as Std C Library strcmp function.
+ *
+ * RETURNED: Same as Std C Library strcmp function.
+ *
+ ***********************************************************************/
+
+template <class T1, class T2>
+int EmMem_strcmp(T1 dst, T2 src)
+{
+ T1 p1 = dst;
+ T2 p2 = src;
+
+ while (1)
+ {
+ unsigned char c1 = _get_byte (p1);
+ unsigned char c2 = _get_byte (p2);
+
+ if (c1 != c2)
+ return (c1 - c2);
+ else if (!c1)
+ break;
+
+ _increment (p1);
+ _increment (p2);
+ }
+
+ return 0;
+}
+
+ // Instantiate EmMem_strcmp's that work with:
+ //
+ // dest source
+ // ------ ------
+ // char* emuptr
+ // const char* emuptr
+ // emuptr char*
+ // emuptr const char*
+ // emuptr emuptr
+
+template int EmMem_strcmp<char*, emuptr> (char* dst, emuptr src);
+template int EmMem_strcmp<const char*, emuptr> (const char* dst, emuptr src);
+template int EmMem_strcmp<emuptr, char*> (emuptr dst, char* src);
+template int EmMem_strcmp<emuptr, const char*> (emuptr dst, const char* src);
+template int EmMem_strcmp<emuptr, emuptr> (emuptr dst, emuptr src);
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmMem_strncmp
+ *
+ * DESCRIPTION: Same as Std C Library strncmp function.
+ *
+ * PARAMETERS: Same as Std C Library strncmp function.
+ *
+ * RETURNED: Same as Std C Library strncmp function.
+ *
+ ***********************************************************************/
+
+template <class T1, class T2>
+int EmMem_strncmp(T1 dst, T2 src, size_t len)
+{
+ T1 p1 = dst;
+ T2 p2 = src;
+
+ ++len;
+
+ while (--len)
+ {
+ unsigned char c1 = _get_byte (p1);
+ unsigned char c2 = _get_byte (p2);
+
+ if (c1 != c2)
+ return (c1 - c2);
+ else if (!c1)
+ break;
+
+ _increment (p1);
+ _increment (p2);
+ }
+
+ return 0;
+}
+
+ // Instantiate EmMem_strncmp's that work with:
+ //
+ // dest source
+ // ------ ------
+ // char* emuptr
+ // const char* emuptr
+ // emuptr char*
+ // emuptr const char*
+ // emuptr emuptr
+
+template int EmMem_strncmp<char*, emuptr> (char* dst, emuptr src, size_t len);
+template int EmMem_strncmp<const char*, emuptr> (const char* dst, emuptr src, size_t len);
+template int EmMem_strncmp<emuptr, char*> (emuptr dst, char* src, size_t len);
+template int EmMem_strncmp<emuptr, const char*> (emuptr dst, const char* src, size_t len);
+template int EmMem_strncmp<emuptr, emuptr> (emuptr dst, emuptr src, size_t len);
diff --git a/SrcShared/Hardware/EmMemory.h b/SrcShared/Hardware/EmMemory.h
new file mode 100644
index 0000000..f10b749
--- /dev/null
+++ b/SrcShared/Hardware/EmMemory.h
@@ -0,0 +1,457 @@
+/* -*- 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.
+\* ===================================================================== */
+
+#ifndef EmMemory_h
+#define EmMemory_h
+
+// Normally, I'd assume that these includes were pulled in
+// by EmCommon.h. However, EmMemory.h gets included by UAE,
+// which doesn't pull in EmCommon.h. So I have to explicitly
+// make sure they're included.
+
+#include "Switches.h" // WORDSWAP_MEMORY, UNALIGNED_LONG_ACCESS
+#include "EmTypes.h" // uint32, etc.
+#include "EmAssert.h" // EmAssert
+
+#include "sysconfig.h" // STATIC_INLINE
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// ---------------------------------------------------------------------------
+// ¥ EmAddressBank
+// ---------------------------------------------------------------------------
+
+typedef uint32 (*EmMemGetFunc) (emuptr);
+typedef void (*EmMemPutFunc) (emuptr, uint32);
+typedef uint8* (*EmMemTranslateFunc) (emuptr);
+typedef int (*EmMemCheckFunc) (emuptr, uint32);
+typedef void (*EmMemCycleFunc) (void);
+typedef uint8* (*EmMemTranslateMetaFunc) (emuptr);
+
+typedef struct EmAddressBank
+{
+ /* These ones should be self-explanatory... */
+ EmMemGetFunc lget, wget, bget;
+ EmMemPutFunc lput, wput, bput;
+
+ /* Use xlateaddr to translate an Amiga address to a uae_u8 * that can
+ * be used to address memory without calling the wget/wput functions.
+ * This doesn't work for all memory banks, so this function may call
+ * abort(). */
+ EmMemTranslateFunc xlateaddr;
+
+ /* To prevent calls to abort(), use check before calling xlateaddr.
+ * It checks not only that the memory bank can do xlateaddr, but also
+ * that the pointer points to an area of at least the specified size.
+ * This is used for example to translate bitplane pointers in custom.c */
+ EmMemCheckFunc checkaddr;
+
+ EmMemTranslateMetaFunc xlatemetaaddr;
+ EmMemCycleFunc EmMemAddOpcodeCycles;
+} EmAddressBank;
+
+
+#ifndef ECM_DYNAMIC_PATCH
+
+ extern EmAddressBank* gEmMemBanks[65536];
+
+#else // ECM_DYNAMIC_PATCH
+
+ extern EmAddressBank** gDynEmMemBanksP;
+
+#endif // ECM_DYNAMIC_PATCH
+
+
+// ---------------------------------------------------------------------------
+// ¥ Support macros
+// ---------------------------------------------------------------------------
+
+#ifndef ECM_DYNAMIC_PATCH
+
+ #define EmMemBankIndex(addr) (((emuptr)(addr)) >> 16)
+
+ #define EmMemGetBank(addr) (*gEmMemBanks[EmMemBankIndex(addr)])
+ #define EmMemPutBank(addr, b) (gEmMemBanks[EmMemBankIndex(addr)] = (b))
+
+#else // ECM_DYNAMIC_PATCH
+
+ #define EmMemBankIndex(addr) (((unsigned long)(addr)) >> 16)
+
+ #define EmMemGetBank(addr) (*((gDynEmMemBanksP)[EmMemBankIndex(addr)]))
+ #define EmMemPutBank(addr, b) ((gDynEmMemBanksP)[EmMemBankIndex(addr)] = (b))
+
+#endif // ECM_DYNAMIC_PATCH
+
+#define EmMemCallGetFunc(func, addr) ((*EmMemGetBank(addr).func)(addr))
+#define EmMemCallPutFunc(func, addr, v) ((*EmMemGetBank(addr).func)(addr, v))
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmMemGet32
+// ---------------------------------------------------------------------------
+
+STATIC_INLINE uint32 EmMemGet32(emuptr addr)
+{
+ return EmMemCallGetFunc(lget, addr);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmMemGet16
+// ---------------------------------------------------------------------------
+
+STATIC_INLINE uint32 EmMemGet16(emuptr addr)
+{
+ return EmMemCallGetFunc(wget, addr);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmMemGet8
+// ---------------------------------------------------------------------------
+
+STATIC_INLINE uint32 EmMemGet8(emuptr addr)
+{
+ return EmMemCallGetFunc(bget, addr);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmMemPut32
+// ---------------------------------------------------------------------------
+
+STATIC_INLINE void EmMemPut32(emuptr addr, uint32 l)
+{
+ EmMemCallPutFunc(lput, addr, l);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmMemPut16
+// ---------------------------------------------------------------------------
+
+STATIC_INLINE void EmMemPut16(emuptr addr, uint32 w)
+{
+ EmMemCallPutFunc(wput, addr, w);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmMemPut8
+// ---------------------------------------------------------------------------
+
+STATIC_INLINE void EmMemPut8(emuptr addr, uint32 b)
+{
+ EmMemCallPutFunc(bput, addr, b);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmMemGetRealAddress
+// ---------------------------------------------------------------------------
+
+STATIC_INLINE uint8* EmMemGetRealAddress(emuptr addr)
+{
+ return EmMemGetBank(addr).xlateaddr(addr);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmMemCheckAddress
+// ---------------------------------------------------------------------------
+
+STATIC_INLINE int EmMemCheckAddress(emuptr addr, uint32 size)
+{
+ return EmMemGetBank(addr).checkaddr(addr, size);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmMemAddOpcodeCycles
+// ---------------------------------------------------------------------------
+
+STATIC_INLINE void EmMemAddOpcodeCycles(emuptr addr)
+{
+ EmAssert (EmMemGetBank(addr).EmMemAddOpcodeCycles);
+ EmMemGetBank(addr).EmMemAddOpcodeCycles();
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmMemGetMetaAddress
+// ---------------------------------------------------------------------------
+
+STATIC_INLINE uint8* EmMemGetMetaAddress(emuptr addr)
+{
+ EmAssert(EmMemGetBank(addr).xlatemetaaddr);
+ return EmMemGetBank(addr).xlatemetaaddr(addr);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmMemDoGet32
+// ---------------------------------------------------------------------------
+
+STATIC_INLINE uint32 EmMemDoGet32 (void* a)
+{
+#if WORDSWAP_MEMORY || !UNALIGNED_LONG_ACCESS
+ return (((uint32) *(((uint16*) a) + 0)) << 16) |
+ (((uint32) *(((uint16*) a) + 1)));
+#else
+ return *(uint32*) a;
+#endif
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmMemDoGet16
+// ---------------------------------------------------------------------------
+
+STATIC_INLINE uint16 EmMemDoGet16 (void* a)
+{
+ return *(uint16*) a;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmMemDoGet8
+// ---------------------------------------------------------------------------
+
+STATIC_INLINE uint8 EmMemDoGet8 (void* a)
+{
+#if WORDSWAP_MEMORY
+ return *(uint8*) ((long) a ^ 1);
+#else
+ return *(uint8*) a;
+#endif
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmMemDoPut32
+// ---------------------------------------------------------------------------
+
+STATIC_INLINE void EmMemDoPut32 (void* a, uint32 v)
+{
+#if WORDSWAP_MEMORY || !UNALIGNED_LONG_ACCESS
+ *(((uint16*) a) + 0) = (uint16) (v >> 16);
+ *(((uint16*) a) + 1) = (uint16) (v);
+#else
+ *(uint32*) a = v;
+#endif
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmMemDoPut16
+// ---------------------------------------------------------------------------
+
+STATIC_INLINE void EmMemDoPut16 (void* a, uint16 v)
+{
+ *(uint16*) a = v;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmMemDoPut8
+// ---------------------------------------------------------------------------
+
+STATIC_INLINE void EmMemDoPut8 (void* a, uint8 v)
+{
+#if WORDSWAP_MEMORY
+ *(uint8*) ((long) a ^ 1) = v;
+#else
+ *(uint8*) a = v;
+#endif
+}
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#ifdef __cplusplus
+
+class EmStream;
+
+
+// Types.
+
+// This struct is used to control access to memory. The first set of fields
+// are booleans which, when set to true, turn on address validation for the
+// various ranges of memory. The second second set of fields are booleans
+// which, when set to true, prevent access by user applications to the various
+// ranges of memory.
+
+struct MemAccessFlags
+{
+ Bool fValidate_DummyGet;
+ Bool fValidate_DummySet;
+ Bool fValidate_RegisterGet;
+ Bool fValidate_RegisterSet;
+ Bool fValidate_DRAMGet;
+ Bool fValidate_DRAMSet;
+ Bool fValidate_SRAMGet;
+ Bool fValidate_SRAMSet;
+ Bool fValidate_ROMGet;
+ Bool fValidate_ROMSet;
+
+// Bool fProtect_LowMemGet;
+// Bool fProtect_LowMemSet;
+// Bool fProtect_GlobalGet;
+// Bool fProtect_GlobalSet;
+// Bool fProtect_ScreenGet;
+// Bool fProtect_ScreenSet;
+ Bool fProtect_SRAMGet;
+ Bool fProtect_SRAMSet;
+ Bool fProtect_ROMGet;
+ Bool fProtect_ROMSet;
+ Bool fProtect_RegisterGet;
+ Bool fProtect_RegisterSet;
+
+// Bool fCheck_UserChunkGet;
+// Bool fCheck_UserChunkSet;
+// Bool fCheck_SysChunkGet;
+// Bool fCheck_SysChunkSet;
+
+// Bool fProtect_SysLowMemGet;
+// Bool fProtect_SysLowMemSet;
+// Bool fProtect_SysGlobalGet;
+// Bool fProtect_SysGlobalSet;
+// Bool fProtect_SysScreenGet;
+// Bool fProtect_SysScreenSet;
+// Bool fProtect_SysSRAMGet;
+// Bool fProtect_SysSRAMSet;
+ Bool fProtect_SysROMGet;
+ Bool fProtect_SysROMSet;
+// Bool fProtect_SysRegisterGet;
+// Bool fProtect_SysRegisterSet;
+};
+
+
+// Globals.
+
+extern MemAccessFlags gMemAccessFlags;
+extern Bool gPCInRAM;
+extern Bool gPCInROM;
+
+#if PROFILE_MEMORY
+enum
+{
+ kDRAMLongRead, kDRAMLongRead2, kDRAMWordRead, kDRAMByteRead,
+ kDRAMLongWrite, kDRAMLongWrite2, kDRAMWordWrite, kDRAMByteWrite,
+ kSRAMLongRead, kSRAMLongRead2, kSRAMWordRead, kSRAMByteRead,
+ kSRAMLongWrite, kSRAMLongWrite2, kSRAMWordWrite, kSRAMByteWrite,
+ kROMLongRead, kROMLongRead2, kROMWordRead, kROMByteRead,
+ kROMLongWrite, kROMLongWrite2, kROMWordWrite, kROMByteWrite,
+ kREGLongRead, kREGLongRead2, kREGWordRead, kREGByteRead,
+ kREGLongWrite, kREGLongWrite2, kREGWordWrite, kREGByteWrite,
+
+ kSED1375LongRead, kSED1375LongRead2, kSED1375WordRead, kSED1375ByteRead,
+ kSED1375LongWrite, kSED1375LongWrite2, kSED1375WordWrite, kSED1375ByteWrite,
+
+ kLastEnum
+};
+extern long gMemoryAccess[];
+#endif
+
+struct EmAddressBank;
+class SessionFile;
+
+// Function prototypes.
+
+class Memory
+{
+ public:
+ static void Initialize (EmStream& hROM,
+ RAMSizeType ramSize);
+ static void Reset (Bool hardwareReset);
+ static void Save (SessionFile&);
+ static void Load (SessionFile&);
+ static void Dispose (void);
+
+ static void InitializeBanks (EmAddressBank& iBankInitializer,
+ int32 iStartingBankIndex,
+ int32 iNumberOfBanks);
+
+ static void ResetBankHandlers (void);
+
+ static void MapPhysicalMemory (const void*, uint32);
+ static void UnmapPhysicalMemory (const void*);
+ static void GetMappingInfo (emuptr, void**, uint32*);
+
+ static void CheckNewPC (emuptr newPC);
+ static int IsPCInRAM (void) { return gPCInRAM; }
+ static int IsPCInROM (void) { return gPCInROM; }
+};
+
+typedef Memory EmMemory;
+
+
+// There are places within the emulator where we'd like to access low-memory
+// and/or Dragonball registers. If the PC happens to be in RAM, then
+// the checks implied by the above booleans and switches will flag our
+// access as an error. Before making such accesses, create an instance
+// of CEnableFullAccess to suspend and restore the checks.
+//
+// Since such accesses are typically "meta" accesses where the emulator is
+// accessing memory outside the normal execution of an opcode, we also
+// turn off the profiling variable that controls whether or not cycles
+// spent accessing memory are counted.
+
+class CEnableFullAccess
+{
+ public:
+ CEnableFullAccess (void);
+ ~CEnableFullAccess (void);
+
+ static Bool AccessOK (void);
+
+ private:
+ MemAccessFlags fOldMemAccessFlags;
+
+#if HAS_PROFILING
+ Bool fOldProfilingCounted;
+#endif
+
+ static long fgAccessCount;
+};
+
+
+// Std C Library-ish routines for manipulating data
+// in emulated memory.
+
+emuptr EmMem_memset(emuptr dst, int val, size_t len);
+
+emuptr EmMem_memchr(emuptr src, int val, size_t len);
+
+template <class T1, class T2>
+int EmMem_memcmp(T1 src1, T2 src2, size_t len);
+
+template <class T1, class T2>
+T1 EmMem_memcpy (T1 dst, T2 src, size_t len);
+
+template <class T1, class T2>
+T1 EmMem_memmove (T1 dst, T2 src, size_t len);
+
+size_t EmMem_strlen(emuptr str);
+
+template <class T1, class T2>
+T1 EmMem_strcpy(T1 dst, T2 src);
+
+template <class T1, class T2>
+T1 EmMem_strncpy(T1 dst, T2 src, size_t len);
+
+template <class T1, class T2>
+T1 EmMem_strcat(T1 dst, T2 src);
+
+template <class T1, class T2>
+T1 EmMem_strncat(T1 dst, T2 src, size_t len);
+
+template <class T1, class T2>
+int EmMem_strcmp(T1 dst, T2 src);
+
+template <class T1, class T2>
+int EmMem_strncmp(T1 dst, T2 src, size_t len);
+
+#endif // __cplusplus
+
+#endif /* EmMemory_h */
diff --git a/SrcShared/Hardware/EmRegs.cpp b/SrcShared/Hardware/EmRegs.cpp
new file mode 100644
index 0000000..bd1c50a
--- /dev/null
+++ b/SrcShared/Hardware/EmRegs.cpp
@@ -0,0 +1,499 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmRegs.h"
+
+#include "Byteswapping.h" // Canonical
+#include "EmBankRegs.h" // EmBankRegs::InvalidAccess
+#include "EmMemory.h" // Memory::InitializeBanks, EmMemBankIndex
+
+/*
+ EmRegs is a base class for subclasses that manage the accessing of
+ emulated memory at a byte, word, or long level. See comments in
+ EmRegsBank.cpp for a description on how EmRegs objects are managed,
+ and EmMemory for how memory in general is emulated.
+
+ EmRegs subclasses are suited for managing hardware registers, such
+ as the Dragonball [EZ | VZ] hardware registers, the USB registers
+ in the Handspring Visor, or the special PLD registers in some of the
+ Palm VII devices.
+
+ To create a new EmRegs subclass that can handle accesses to a special
+ range of memory, do the following:
+
+ * Create a subclass of EmRegs
+
+ * Provide implementations for the pure virtual functions:
+
+ * SetSubBankHandlers: this method needs to call EmRegs::SetHandler
+ to install a read and write function for each memory location
+ that can be accessed. It should also first call the base
+ class SetSubBankHandlers in order to install default handlers
+ for all memory locations in the memory range the subclass manages.
+
+ * GetRealAddress: given an address in emulated space, this function
+ returns the real address from the point of view of the emulator.
+ For instance, if your EmRegs subclass manages the memory range
+ 0x17000000 to 0x17001000, and you have created a 4K buffer to
+ represent this memory range, then GetRealAddress would be like:
+
+ return &fMyBuffer[address - 0x17000000];
+
+ * GetAddressStart: returns the base address of the memory range
+ managed by this class. In the example above, this method would
+ return 0x17000000.
+
+ * GetAddressRange: returns the range of memory managed by this
+ class. In the example above, this method would return 0x1000.
+
+ * Define read and write function handlers for each memory location
+ in the managed range. These functions handlers are installed in
+ your SetSubBankHandlers override. EmBankRegs will call these
+ handlers as appropriate.
+
+ * Optionally implement Initialize, Reset, Save, Load, and Dispose
+ overrides. You will usually override Initialize to create any
+ buffers required to hold your data, and correspondingly dispose
+ of those resources in a Dispose override. Most subclasses will
+ need to override Reset in order to initialize their emulated
+ registers. And override Save and Load if you want to save and
+ restore your registers to the session (.psf) file.
+
+ * In the appropriate case statement in EmDevice::CreateRegs, create
+ an instance of your EmRegs class and install it by calling
+ EmBankRegs::AddSubBank.
+*/
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs::EmRegs
+// ---------------------------------------------------------------------------
+
+EmRegs::EmRegs (void) :
+ fReadFunctions (),
+ fWriteFunctions ()
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs::~EmRegs
+// ---------------------------------------------------------------------------
+
+EmRegs::~EmRegs (void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs::Initialize
+// ---------------------------------------------------------------------------
+
+void EmRegs::Initialize (void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs::Reset
+// ---------------------------------------------------------------------------
+
+void EmRegs::Reset (Bool /*hardwareReset*/)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs::Save
+// ---------------------------------------------------------------------------
+
+void EmRegs::Save (SessionFile&)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs::Load
+// ---------------------------------------------------------------------------
+
+void EmRegs::Load (SessionFile&)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs::Dispose
+// ---------------------------------------------------------------------------
+
+void EmRegs::Dispose (void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs::SetBankHandlers
+// ---------------------------------------------------------------------------
+
+void EmRegs::SetBankHandlers (EmAddressBank& bank)
+{
+ emuptr address = this->GetAddressStart ();
+ uint32 range = this->GetAddressRange ();
+ uint32 numBanks = EmMemBankIndex (address + range - 1) - EmMemBankIndex (address) + 1;
+
+ Memory::InitializeBanks (bank, EmMemBankIndex (address), numBanks);
+
+ this->SetSubBankHandlers ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs::SetSubBankHandlers
+// ---------------------------------------------------------------------------
+
+void EmRegs::SetSubBankHandlers (void)
+{
+ this->SetHandler (&EmRegs::UnsupportedRead, &EmRegs::UnsupportedWrite,
+ this->GetAddressStart (), this->GetAddressRange ());
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs::GetLong
+// ---------------------------------------------------------------------------
+
+uint32 EmRegs::GetLong (emuptr address)
+{
+// EmAssert (this->ValidAddress (address, 4));
+
+ long offset = address - this->GetAddressStart ();
+ ReadFunction fn = fReadFunctions [offset];
+ EmAssert (fn);
+
+ return (this->*fn) (address, 4);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs::GetWord
+// ---------------------------------------------------------------------------
+
+uint32 EmRegs::GetWord (emuptr address)
+{
+// EmAssert (this->ValidAddress (address, 2));
+
+ long offset = address - this->GetAddressStart ();
+ ReadFunction fn = fReadFunctions [offset];
+ EmAssert (fn);
+
+ return (this->*fn) (address, 2);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs::GetByte
+// ---------------------------------------------------------------------------
+
+uint32 EmRegs::GetByte (emuptr address)
+{
+// EmAssert (this->ValidAddress (address, 1));
+
+ long offset = address - this->GetAddressStart ();
+ ReadFunction fn = fReadFunctions [offset];
+ EmAssert (fn);
+
+ return (this->*fn) (address, 1);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs::SetLong
+// ---------------------------------------------------------------------------
+
+void EmRegs::SetLong (emuptr address, uint32 value)
+{
+// EmAssert (this->ValidAddress (address, 4));
+
+ long offset = address - this->GetAddressStart ();
+ WriteFunction fn = fWriteFunctions [offset];
+ EmAssert (fn);
+
+ (this->*fn) (address, 4, value);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs::SetWord
+// ---------------------------------------------------------------------------
+
+void EmRegs::SetWord (emuptr address, uint32 value)
+{
+// EmAssert (this->ValidAddress (address, 2));
+
+ long offset = address - this->GetAddressStart ();
+ WriteFunction fn = fWriteFunctions [offset];
+ EmAssert (fn);
+
+ (this->*fn) (address, 2, value);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs::SetByte
+// ---------------------------------------------------------------------------
+
+void EmRegs::SetByte (emuptr address, uint32 value)
+{
+// EmAssert (this->ValidAddress (address, 1));
+
+ long offset = address - this->GetAddressStart ();
+ WriteFunction fn = fWriteFunctions [offset];
+ EmAssert (fn);
+
+ (this->*fn) (address, 1, value);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs::ValidAddress
+// ---------------------------------------------------------------------------
+
+int EmRegs::ValidAddress (emuptr address, uint32 size)
+{
+ UNUSED_PARAM (size);
+
+ int result = false;
+ unsigned long offset = address - this->GetAddressStart ();
+
+ if (offset < fReadFunctions.size ())
+ {
+ ReadFunction fn = fReadFunctions [offset];
+ result = (fn != &EmRegs::UnsupportedRead);
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs::GetRealAddress
+// ---------------------------------------------------------------------------
+
+uint8* EmRegs::GetRealAddress (emuptr address)
+{
+ UNUSED_PARAM (address);
+
+ // Sub-class's responsibility.
+
+ return NULL;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs::SetHandler
+// ---------------------------------------------------------------------------
+
+void EmRegs::SetHandler (ReadFunction read, WriteFunction write,
+ uint32 start, int count)
+{
+ if (fReadFunctions.size () == 0)
+ {
+ uint32 range = this->GetAddressRange ();
+
+ fReadFunctions.resize (range, &EmRegs::UnsupportedRead);
+ fWriteFunctions.resize (range, &EmRegs::UnsupportedWrite);
+ }
+
+ int index = start - this->GetAddressStart ();
+
+ EmAssert (index >= 0);
+ EmAssert (index < (long) fReadFunctions.size ());
+
+ for (int ii = 0; ii < count; ++ii, ++index)
+ {
+ fReadFunctions[index] = read;
+ fWriteFunctions[index] = write;
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs::UnsupportedRead
+// ---------------------------------------------------------------------------
+
+uint32 EmRegs::UnsupportedRead (emuptr address, int size)
+{
+ if (!CEnableFullAccess::AccessOK ())
+ {
+ EmBankRegs::PreventedAccess (address, size, true);
+ }
+
+ return ~0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs::UnsupportedWrite
+// ---------------------------------------------------------------------------
+
+void EmRegs::UnsupportedWrite (emuptr address, int size, uint32 value)
+{
+ UNUSED_PARAM(value)
+
+ if (!CEnableFullAccess::AccessOK ())
+ {
+ EmBankRegs::PreventedAccess (address, size, false);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs::StdReadBE
+// ---------------------------------------------------------------------------
+// Read registers in a strict Big Endian fashion.
+
+uint32 EmRegs::StdReadBE (emuptr address, int size)
+{
+ uint8* realAddr = this->GetRealAddress (address);
+
+ if (size == 1)
+ return *(uint8*) realAddr;
+
+ if (size == 2)
+ {
+ uint16 result16 = *(uint16*) realAddr;
+ Canonical (result16);
+ return result16;
+ }
+
+#if UNALIGNED_LONG_ACCESS
+
+ uint32 result32 = *(uint32*) realAddr;
+ Canonical (result32);
+ return result32;
+
+#else
+
+ return (realAddr[0] << 24) |
+ (realAddr[1] << 16) |
+ (realAddr[2] << 8) |
+ (realAddr[3] << 0);
+
+#endif
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs::StdWriteBE
+// ---------------------------------------------------------------------------
+// Write registers in a strict Big Endian fashion.
+
+void EmRegs::StdWriteBE (emuptr address, int size, uint32 value)
+{
+ uint8* realAddr = this->GetRealAddress (address);
+
+ if (size == 1)
+ {
+ *(uint8*) realAddr = value;
+ }
+
+ else if (size == 2)
+ {
+ uint16 value16 = value;
+ Canonical (value16);
+ *(uint16*) realAddr = value16;
+ }
+
+ else if (size == 4)
+ {
+#if UNALIGNED_LONG_ACCESS
+
+ Canonical (value);
+ *(uint32*) realAddr = value;
+
+#else
+
+ realAddr[0] = (uint8) (value >> 24);
+ realAddr[1] = (uint8) (value >> 16);
+ realAddr[2] = (uint8) (value >> 8);
+ realAddr[3] = (uint8) (value >> 0);
+
+#endif
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs::StdRead
+// ---------------------------------------------------------------------------
+// Read registers using the routines in maccess.h
+
+uint32 EmRegs::StdRead (emuptr address, int size)
+{
+ uint8* realAddr = this->GetRealAddress (address);
+
+ if (size == 1)
+ return EmMemDoGet8 (realAddr);
+
+ if (size == 2)
+ return EmMemDoGet16 (realAddr);
+
+ return EmMemDoGet32 (realAddr);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs::StdWrite
+// ---------------------------------------------------------------------------
+// Write registers using the routines in maccess.h
+
+void EmRegs::StdWrite (emuptr address, int size, uint32 value)
+{
+ uint8* realAddr = this->GetRealAddress (address);
+
+ if (size == 1)
+ EmMemDoPut8 (realAddr, value);
+
+ else if (size == 2)
+ EmMemDoPut16 (realAddr, value);
+
+ else
+ EmMemDoPut32 (realAddr, value);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs::ZeroRead
+// ---------------------------------------------------------------------------
+
+uint32 EmRegs::ZeroRead (emuptr address, int size)
+{
+ UNUSED_PARAM(address)
+ UNUSED_PARAM(size)
+
+ return 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs::NullWrite
+// ---------------------------------------------------------------------------
+
+void EmRegs::NullWrite (emuptr address, int size, uint32 value)
+{
+ UNUSED_PARAM(address)
+ UNUSED_PARAM(size)
+ UNUSED_PARAM(value)
+
+ // Do nothing (for read-only registers).
+}
diff --git a/SrcShared/Hardware/EmRegs.h b/SrcShared/Hardware/EmRegs.h
new file mode 100644
index 0000000..1a48907
--- /dev/null
+++ b/SrcShared/Hardware/EmRegs.h
@@ -0,0 +1,77 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegs_h
+#define EmRegs_h
+
+#include <vector>
+
+class SessionFile;
+struct EmAddressBank;
+
+class EmRegs
+{
+ public:
+ EmRegs (void);
+ virtual ~EmRegs (void);
+
+ virtual void Initialize (void);
+ virtual void Reset (Bool hardwareReset);
+ virtual void Save (SessionFile&);
+ virtual void Load (SessionFile&);
+ virtual void Dispose (void);
+
+ void SetBankHandlers (EmAddressBank&);
+ virtual void SetSubBankHandlers (void) = 0;
+
+ virtual uint32 GetLong (emuptr address);
+ virtual uint32 GetWord (emuptr address);
+ virtual uint32 GetByte (emuptr address);
+ virtual void SetLong (emuptr address, uint32 value);
+ virtual void SetWord (emuptr address, uint32 value);
+ virtual void SetByte (emuptr address, uint32 value);
+ virtual int ValidAddress (emuptr address, uint32 size);
+ virtual uint8* GetRealAddress (emuptr address) = 0;
+ virtual emuptr GetAddressStart (void) = 0;
+ virtual uint32 GetAddressRange (void) = 0;
+
+ protected:
+ typedef uint32 (EmRegs::*ReadFunction) (emuptr address, int size);
+ typedef void (EmRegs::*WriteFunction) (emuptr address, int size, uint32 value);
+
+ void SetHandler (ReadFunction read,
+ WriteFunction write,
+ uint32 start, int count);
+
+ uint32 UnsupportedRead (emuptr address, int size);
+ uint32 StdRead (emuptr address, int size);
+ uint32 StdReadBE (emuptr address, int size);
+ uint32 ZeroRead (emuptr address, int size);
+
+ void UnsupportedWrite (emuptr address, int size, uint32 value);
+ void StdWrite (emuptr address, int size, uint32 value);
+ void StdWriteBE (emuptr address, int size, uint32 value);
+ void NullWrite (emuptr address, int size, uint32 value);
+
+ private:
+ typedef vector<ReadFunction> ReadFunctionList;
+ typedef vector<WriteFunction> WriteFunctionList;
+
+ ReadFunctionList fReadFunctions;
+ WriteFunctionList fWriteFunctions;
+};
+
+
+typedef vector<EmRegs*> EmRegsList;
+
+#endif /* EmRegs_h */
diff --git a/SrcShared/Hardware/EmRegs328.cpp b/SrcShared/Hardware/EmRegs328.cpp
new file mode 100644
index 0000000..0f33398
--- /dev/null
+++ b/SrcShared/Hardware/EmRegs328.cpp
@@ -0,0 +1,2803 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmRegs328.h"
+#include "EmRegs328Prv.h"
+
+#include "Byteswapping.h" // Canonical
+#include "EmHAL.h" // EmHAL
+#include "EmMemory.h" // gMemAccessFlags, EmMem_memcpy
+#include "EmPixMap.h" // SetSize, SetRowBytes, etc.
+#include "EmScreen.h" // EmScreenUpdateInfo
+#include "EmSession.h" // GetDevice
+#include "Hordes.h" // Hordes::IsOn
+#include "Logging.h" // LogAppendMsg
+#include "Miscellaneous.h" // GetHostTime
+#include "PreferenceMgr.h" // Preference
+#include "SessionFile.h" // WriteHwrDBallType, etc.
+#include "UAE.h" // regs, SPCFLAG_INT
+
+#include "PalmPack.h"
+#define NON_PORTABLE
+ #include "HwrMiscFlags.h" // hwrMiscFlagID1
+
+ // Some platform-specific -- yet fairly portable -- defines.
+ #define hwrTD1PortENoBacklight 0x80 // (H) high if no backlight present
+
+#undef NON_PORTABLE
+#include "PalmPackPop.h"
+
+/*
+ This file controls the emulation of the Dragonball registers.
+
+ As a subclass of EmRegs, EmRegs328 registers with EmBankRegs
+ for control of the memory range 0xFFFFF000 to 0xFFFFFB14. If
+ an application accesses a memory location in that range,
+ EmBankRegs calls on of the Set/GetLong/Word/Byte methods of
+ this class.
+
+ EmRegs328 provides handlers when particular memory addresses
+ are accessed. For instance, if the UART TX register is written
+ to, EmRegs328 will arrange for any data byte to be sent out
+ the host computer's serial port. If the UART RX register is
+ read, EmRegs328 will respond with any byte in the buffer that
+ contains data received from the host computer's serial port.
+
+ Not all Dragonball registers are emulated the same way as on
+ an actual device. Some registers control hardware that exists
+ on the device only, there being no analog on the host computer.
+ For those registers, simple handlers are installed that write
+ the specified value to the register and return that value later
+ when the register is read.
+
+ Other registers require extensive support. The UART registers
+ are examples of that, as the above text indicates.
+
+ In the Palm OS source code, the Dragonball registers are
+ represented by th HwrM68328Type data type. We use this same type
+ in Poser to provide the "backing memory" for the registers. That
+ is, if some emulated code writes to a Dragonball register, we
+ store that value in a variable of type HwrM68328Type.
+
+ (Note that there's really no guarantee that the compiler used to
+ build Poser will lay out the fields of HwrM68328Type in the same
+ way expected by the Palm OS. Poser has a mechanism for creating
+ buffers with fields that have the same layout as Palm OS-defined
+ structs (see EmPalmStructs.h). However, using that mechanism in
+ this module is deadly to performance. In particular, the Cycle
+ method is called after every opcode is executed, and making that
+ method go through the indirection and byteswapping required by
+ the EmPalmStructs facilities totally kills performance. In one
+ test, a Gremlins run increased from 1m 24s to 1m 56s, or by about
+ 30%. With targetted caching of the fields used in Cycle, we can
+ regain most of that performance. However, not all the performance
+ is regained, and the resulting code is not very maintainable.)
+*/
+
+ #define hwr328chipID328 0x33
+ #define hwr328maskID1H58B 0x30
+
+static const uint32 ADDRESS_MASK = 0x0000FFF0;
+
+#define PRINTF if (1) ; else LogAppendMsg
+
+// Values used to initialize the DragonBall registers.
+
+const HwrM68328Type kInitial68328RegisterValues =
+{
+ 0x0C, // Byte scr; // $000: System Control Register
+ { 0 }, // Byte ___filler0[0x004-0x001];
+
+ // The following ID stuff is not present on earlier chips (before ??)
+ hwr328chipID328, // Byte chipID; // $004: Chip ID Register
+ hwr328maskID1H58B, // Byte maskID; // $005: Mask ID Register
+ 0x00, // Word swID; // $006: Software ID Register
+ { 0 }, // Byte ___filler1[0x100-0x008];
+
+ 0x0000, // Word csAGroupBase; // $100: Chip Select Group A Base Register
+ 0x0000, // Word csBGroupBase; // $102: Chip Select Group B Base Register
+ 0x0000, // Word csCGroupBase; // $104: Chip Select Group C Base Register
+ 0x0000, // Word csDGroupBase; // $106: Chip Select Group D Base Register
+
+ 0x0000, // Word csAGroupMask; // $108: Chip Select Group A Mask Register
+ 0x0000, // Word csBGroupMask; // $10A: Chip Select Group B Mask Register
+ 0x0000, // Word csCGroupMask; // $10C: Chip Select Group C Mask Register
+ 0x0000, // Word csDGroupMask; // $10E: Chip Select Group D Mask Register
+
+ 0x00010006, // DWord csASelect0; // $110: Group A Chip Select 0 Register
+ 0x00010006, // DWord csASelect1; // $114: Group A Chip Select 1 Register
+ 0x00010006, // DWord csASelect2; // $118: Group A Chip Select 2 Register
+ 0x00010006, // DWord csASelect3; // $11C: Group A Chip Select 3 Register
+
+ 0x00000000, // DWord csBSelect0; // $120: Group B Chip Select 0 Register
+ 0x00000000, // DWord csBSelect1; // $124: Group B Chip Select 1 Register
+ 0x00000000, // DWord csBSelect2; // $128: Group B Chip Select 2 Register
+ 0x00000000, // DWord csBSelect3; // $12C: Group B Chip Select 3 Register
+
+ 0x00010006, // DWord csCSelect0; // $130: Group C Chip Select 0 Register
+ 0x00010006, // DWord csCSelect1; // $134: Group C Chip Select 1 Register
+ 0x00010006, // DWord csCSelect2; // $138: Group C Chip Select 2 Register
+ 0x00010006, // DWord csCSelect3; // $13C: Group C Chip Select 3 Register
+
+ 0x00000000, // DWord csDSelect0; // $140: Group D Chip Select 0 Register
+ 0x00000000, // DWord csDSelect1; // $144: Group D Chip Select 1 Register
+ 0x00000000, // DWord csDSelect2; // $148: Group D Chip Select 2 Register
+ 0x00000000, // DWord csDSelect3; // $14C: Group D Chip Select 3 Register
+
+ 0x0000, // Word csDebug; // $150: Chip Select debug register
+ { 0 }, // Byte ___filler2[0x200-0x152];
+
+ 0x2400, // Word pllControl; // $200: PLL Control Register
+ 0x0123, // Word pllFreqSel; // $202: PLL Frequency Select Register
+ 0x0000, // Word pllTest; // $204: PLL Test Register
+ { 0 }, // Byte __filler44;
+ 0x1F, // Byte pwrControl; // $207: Power Control Register
+
+ { 0 }, // Byte ___filler3[0x300-0x208];
+
+ 0x00, // Byte intVector; // $300: Interrupt Vector Register
+ { 0 }, // Byte ___filler4;
+ 0x0000, // Word intControl; // $302: Interrupt Control Register
+ 0x00FF, // Word intMaskHi; // $304: Interrupt Mask Register/HIGH word
+ 0xFFFF, // Word intMaskLo; // $306: Interrupt Mask Register/LOW word
+ 0x00FF, // Word intWakeupEnHi; // $308: Interrupt Wakeup Enable Register
+ 0xFFFF, // Word intWakeupEnLo; // $30A: Interrupt Wakeup Enable Register
+ 0x0000, // Word intStatusHi; // $30C: Interrupt Status Register/HIGH word
+ 0x0000, // Word intStatusLo; // $30E: Interrupt Status Register/LOW word
+ 0x0000, // Word intPendingHi; // $310: Interrupt Pending Register
+ 0x0000, // Word intPendingLo; // $312: Interrupt Pending Register
+
+ { 0 }, // Byte ___filler4a[0x400-0x314];
+
+ 0x00, // Byte portADir; // $400: Port A Direction Register
+ 0x00, // Byte portAData; // $401: Port A Data Register
+ { 0 }, // Byte ___filler5;
+ 0x00, // Byte portASelect; // $403: Port A Select Register
+
+ { 0 }, // Byte ___filler6[4];
+
+ 0x00, // Byte portBDir; // $408: Port B Direction Register
+ 0x00, // Byte portBData; // $409: Port B Data Register
+ { 0 }, // Byte ___filler7;
+ 0x00, // Byte portBSelect; // $40B: Port B Select Register
+
+ { 0 }, // Byte ___filler8[4];
+
+ 0x00, // Byte portCDir; // $410: Port C Direction Register
+ 0x00, // Byte portCData; // $411: Port C Data Register
+ { 0 }, // Byte ___filler9;
+ 0x00, // Byte portCSelect; // $413: Port C Select Register
+
+ { 0 }, // Byte ___filler10[4];
+
+ 0x00, // Byte portDDir; // $418: Port D Direction Register
+ 0x00, // Byte portDData; // $419: Port D Data Register
+ 0xFF, // Byte portDPullupEn; // $41A: Port D Pull-up Enable
+ { 0 }, // Byte ___filler11;
+ 0x00, // Byte portDPolarity; // $41C: Port D Polarity Register
+ 0x00, // Byte portDIntReqEn; // $41D: Port D Interrupt Request Enable
+ { 0 }, // Byte ___filler12;
+ 0x00, // Byte portDIntEdge; // $41F: Port D IRQ Edge Register
+
+ 0x00, // Byte portEDir; // $420: Port E Direction Register
+ 0x00, // Byte portEData; // $421: Port E Data Register
+ 0x80, // Byte portEPullupEn; // $422: Port E Pull-up Enable
+ 0x80, // Byte portESelect; // $423: Port E Select Register
+
+ { 0 }, // Byte ___filler14[4];
+
+ 0x00, // Byte portFDir; // $428: Port F Direction Register
+ 0x00, // Byte portFData; // $429: Port F Data Register
+ 0xFF, // Byte portFPullupEn; // $42A: Port F Pull-up Enable
+ 0xFF, // Byte portFSelect; // $42B: Port F Select Register
+
+ { 0 }, // Byte ___filler16[4];
+
+ 0x00, // Byte portGDir; // $430: Port G Direction Register
+ 0x00, // Byte portGData; // $431: Port G Data Register
+ 0xFF, // Byte portGPullupEn; // $432: Port G Pull-up Enable
+ 0xFF, // Byte portGSelect; // $433: Port G Select Register
+
+ { 0 }, // Byte ___filler18[4];
+
+ 0x00, // Byte portJDir; // $438: Port J Direction Register
+ 0x00, // Byte portJData; // $439: Port J Data Register
+ { 0 }, // Byte ___filler19;
+ 0x00, // Byte portJSelect; // $43B: Port J Select Register
+
+ { 0 }, // Byte ___filler19a[4];
+
+ 0x00, // Byte portKDir; // $440: Port K Direction Register
+ 0x00, // Byte portKData; // $441: Port K Data Register
+ 0x3F, // Byte portKPullupEn; // $442: Port K Pull-up Enable
+ 0x3F, // Byte portKSelect; // $443: Port K Select Register
+
+ { 0 }, // Byte ___filler21[4];
+
+ 0x00, // Byte portMDir; // $448: Port M Direction Register
+ 0x00, // Byte portMData; // $449: Port M Data Register
+ 0xFF, // Byte portMPullupEn; // $44A: Port M Pull-up Enable Register
+ 0x02, // Byte portMSelect; // $44B: Port M Select Register
+
+ { 0 }, // Byte ___filler22[4];
+
+ { 0 }, // Byte ___filler23[0x500-0x450];
+
+ 0x0000, // Word pwmControl; // $500: PWM Control Register
+ 0x0000, // Word pwmPeriod; // $502: PWM Period Register
+ 0x0000, // Word pwmWidth; // $504: PWM Width Register
+ 0x0000, // Word pwmCounter; // $506: PWM Counter
+
+ { 0 }, // Byte ___filler24[0x600-0x508];
+
+ 0x0000, // Word tmr1Control; // $600: Timer 1 Control Register
+ 0x0000, // Word tmr1Prescaler; // $602: Timer 1 Prescaler Register
+ 0xFFFF, // Word tmr1Compare; // $604: Timer 1 Compare Register
+ 0x0000, // Word tmr1Capture; // $606: Timer 1 Capture Register
+ 0x0000, // Word tmr1Counter; // $608: Timer 1 Counter Register
+ 0x0000, // Word tmr1Status; // $60A: Timer 1 Status Register
+
+ 0x0000, // Word tmr2Control; // $60C: Timer 2 Control Register
+ 0x0000, // Word tmr2Prescaler; // $60E: Timer 2 Prescaler Register
+ 0xFFFF, // Word tmr2Compare; // $610: Timer 2 Compare Register
+ 0x0000, // Word tmr2Capture; // $612: Timer 2 Capture Register
+ 0x0000, // Word tmr2Counter; // $614: Timer 2 Counter Register
+ 0x0000, // Word tmr2Status; // $616: Timer 2 Status Register
+
+ 0x0000, // Word wdControl; // $618: Watchdog Control Register
+ 0x0000, // Word wdReference; // $61A: Watchdog Reference Register
+ 0x0000, // Word wdCounter; // $61C: Watchdog Counter
+
+ { 0 }, // Byte ___filler25[0x700-0x61E];
+
+ 0x0000, // Word spiSlave; // $700: SPI Slave Register
+
+ { 0 }, // Byte ___filler26[0x800-0x702];
+
+ 0x0000, // Word spiMasterData; // $800: SPI Master Data Register
+ 0x0000, // Word spiMasterControl; // $802: SPI Master Control Register
+
+ { 0 }, // Byte ___filler27[0x900-0x804];
+
+ 0x0000, // Word uControl; // $900: Uart Control Register
+ 0x003F, // Word uBaud; // $902: Uart Baud Control Register
+ 0x0000, // Word uReceive; // $904: Uart Receive Register
+ 0x0000, // Word uTransmit; // $906: Uart Transmit Register
+ 0x0000, // Word uMisc; // $908: Uart Miscellaneous Register
+
+ { 0 }, // Byte ___filler28[0xA00-0x90A];
+
+ 0x00000000, // DWord lcdStartAddr; // $A00: Screen Starting Address Register
+ { 0 }, // Byte ___filler29;
+ 0xFF, // Byte lcdPageWidth; // $A05: Virtual Page Width Register
+ { 0 }, // Byte ___filler30[2];
+ 0x03FF, // Word lcdScreenWidth; // $A08: Screen Width Register
+ 0x01FF, // Word lcdScreenHeight; // $A0A: Screen Height Register
+ { 0 }, // Byte ___filler31[0xA18-0xA0C];
+ 0x0000, // Word lcdCursorXPos; // $A18: Cursor X Position
+ 0x0000, // Word lcdCursorYPos; // $A1A: Cursor Y Position
+ 0x0101, // Word lcdCursorWidthHeight; // $A1C: Cursor Width and Height
+ { 0 }, // Byte ___filler32;
+ 0x7F, // Byte lcdBlinkControl; // $A1F: Blink Control Register
+ 0x00, // Byte lcdPanelControl; // $A20: Panel Interface Control Register
+ 0x00, // Byte lcdPolarity; // $A21: Polarity Config Register
+ 0x00, // Byte ___filler33;
+ 0x00, // Byte lcdACDRate; // $A23: ACD (M) Rate Control Register
+ 0x00, // Byte ___filler34;
+ 0x00, // Byte lcdPixelClock; // $A25: Pixel Clock Divider Register
+ 0x00, // Byte ___filler35;
+ 0x40, // Byte lcdClockControl; // $A27: Clocking Control Register
+ 0x00, // Byte ___filler36;
+ 0x3E, // Byte lcdLastBufferAddr; // $A29: Last Buffer Address Register
+ 0x00, // Byte ___filler37;
+ 0x3F, // Byte lcdOctetTermCount; // $A2B: Octet Terminal Count Register
+ 0x00, // Byte ___filler38;
+ 0x00, // Byte lcdPanningOffset; // $A2D: Panning Offset Register
+ { 0 }, // Byte ___filler39[3];
+ 0xB9, // Byte lcdFrameRate; // $A31: Frame Rate Control Modulation Register
+ 0x1073, // Word lcdGrayPalette; // $A32: Gray Palette Mapping Register
+ 0x00, // Byte lcdReserved; // $A34: Reserved
+
+ { 0 }, // Byte ___filler40[0xB00-0xA35];
+
+ 0x00000000, // DWord rtcHourMinSec; // $B00: RTC Hours, Minutes, Seconds Register
+ 0x00000000, // DWord rtcAlarm; // $B04: RTC Alarm Register
+ 0x00000000, // DWord rtcReserved; // $B08: RTC Reserved
+ 0x0000, // Word rtcControl; // $B0C: RTC Control Register
+ 0x0000, // Word rtcIntStatus; // $B0E: RTC Interrupt Status Register
+ 0x0000, // Word rtcIntEnable; // $B10: RTC Interrupt Enable Register
+ 0x0000 // Word stopWatch; // $B12: Stopwatch Minutes
+};
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::EmRegs328
+// ---------------------------------------------------------------------------
+
+EmRegs328::EmRegs328 (void) :
+ EmRegs (),
+ f68328Regs (),
+ fHotSyncButtonDown (0),
+ fTmr2CurrentMilliseconds (0),
+ fTmr2StartMilliseconds (0),
+ fKeyBits (0),
+ fLastTmr1Status (0),
+ fLastTmr2Status (0),
+ fPortDEdge (0),
+ fPortDDataCount (0),
+ fHour (0),
+ fMin (0),
+ fSec (0),
+ fTick (0),
+ fCycle (0),
+ fUART (NULL)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::~EmRegs328
+// ---------------------------------------------------------------------------
+
+EmRegs328::~EmRegs328 (void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::Initialize
+// ---------------------------------------------------------------------------
+
+void EmRegs328::Initialize (void)
+{
+ EmRegs::Initialize ();
+
+ fUART = new EmUARTDragonball (EmUARTDragonball::kUART_Dragonball, 0);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::Reset
+// ---------------------------------------------------------------------------
+
+void EmRegs328::Reset (Bool hardwareReset)
+{
+ EmRegs::Reset (hardwareReset);
+
+ if (hardwareReset)
+ {
+ f68328Regs = kInitial68328RegisterValues;
+
+ // Byteswap all the words in the Dragonball registers (if necessary).
+
+ Canonical (f68328Regs);
+ ByteswapWords (&f68328Regs, sizeof(f68328Regs));
+
+ fKeyBits = 0;
+ fLastTmr1Status = 0;
+ fLastTmr2Status = 0;
+ fPortDEdge = 0;
+ fPortDDataCount = 0;
+
+ // React to the new data in the UART registers.
+
+ Bool sendTxData = false;
+ EmRegs328::UARTStateChanged (sendTxData);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::Save
+// ---------------------------------------------------------------------------
+
+void EmRegs328::Save (SessionFile& f)
+{
+ EmRegs::Save (f);
+
+ StWordSwapper swapper1 (&f68328Regs, sizeof(f68328Regs));
+ f.WriteHwrDBallType (f68328Regs);
+ f.FixBug (SessionFile::kBugByteswappedStructs);
+
+ const long kCurrentVersion = 4;
+
+ Chunk chunk;
+ EmStreamChunk s (chunk);
+
+ s << kCurrentVersion;
+ s << fHotSyncButtonDown;
+ s << fLastTmr1Status;
+ s << fLastTmr2Status;
+ s << fPortDEdge;
+
+ // Added in version 2.
+
+ s << fKeyBits;
+
+ // Added in version 3.
+
+ s << fHour;
+ s << fMin;
+ s << fSec;
+ s << fTick;
+ s << fCycle;
+
+ // Added in version 4.
+
+ s << fPortDDataCount;
+
+ f.WriteDBallState (chunk);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::Load
+// ---------------------------------------------------------------------------
+
+void EmRegs328::Load (SessionFile& f)
+{
+ EmRegs::Load (f);
+
+ if (f.ReadHwrDBallType (f68328Regs))
+ {
+ // The Windows version of Poser 2.1d29 and earlier did not write
+ // out structs in the correct format. The fields of the struct
+ // were written out in Little-Endian format, not Big-Endian. To
+ // address this problem, the bug has been fixed, and a new field
+ // is added to the file format indicating that the bug has been
+ // fixed. With the new field (the "bug bit"), Poser can identify
+ // old files from new files and read them in accordingly.
+ //
+ // With the bug fixed, the .psf files should now be interchangeable
+ // across platforms (modulo other bugs...).
+
+ if (!f.IncludesBugFix (SessionFile::kBugByteswappedStructs))
+ {
+ Canonical (f68328Regs);
+ }
+ ByteswapWords (&f68328Regs, sizeof(f68328Regs));
+
+ // React to the new data in the UART registers.
+
+ Bool sendTxData = false;
+ EmRegs328::UARTStateChanged (sendTxData);
+
+ // Reset gMemAccessFlags.fProtect_SRAMSet
+
+ gMemAccessFlags.fProtect_SRAMSet = (READ_REGISTER (csASelect1) & 0x0008) != 0;
+ }
+ else
+ {
+ f.SetCanReload (false);
+ }
+
+ Chunk chunk;
+ if (f.ReadDBallState (chunk))
+ {
+ long version;
+ EmStreamChunk s (chunk);
+
+ s >> version;
+
+ if (version >= 1)
+ {
+ s >> fHotSyncButtonDown;
+ s >> fTmr2CurrentMilliseconds;
+ s >> fTmr2StartMilliseconds;
+ s >> fLastTmr1Status;
+ s >> fLastTmr2Status;
+ s >> fPortDEdge;
+ }
+
+ if (version >= 2)
+ {
+ s >> fKeyBits;
+ }
+
+ if (version >= 3)
+ {
+ s >> fHour;
+ s >> fMin;
+ s >> fSec;
+ s >> fTick;
+ s >> fCycle;
+ }
+
+ if (version >= 4)
+ {
+ s >> fPortDDataCount;
+ }
+ }
+ else
+ {
+ f.SetCanReload (false);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::Dispose
+// ---------------------------------------------------------------------------
+
+void EmRegs328::Dispose (void)
+{
+ delete fUART;
+ fUART = NULL;
+
+ EmRegs::Dispose ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::SetSubBankHandlers
+// ---------------------------------------------------------------------------
+
+void EmRegs328::SetSubBankHandlers (void)
+{
+ // Install base handlers.
+
+ EmRegs::SetSubBankHandlers ();
+
+ // Now add standard/specialized handers for the defined registers.
+
+ INSTALL_HANDLER (StdRead, StdWrite, scr);
+
+ INSTALL_HANDLER (StdRead, NullWrite, chipID);
+ INSTALL_HANDLER (StdRead, NullWrite, maskID);
+ INSTALL_HANDLER (StdRead, NullWrite, swID);
+
+ INSTALL_HANDLER (StdRead, StdWrite, csAGroupBase);
+ INSTALL_HANDLER (StdRead, StdWrite, csBGroupBase);
+ INSTALL_HANDLER (StdRead, StdWrite, csCGroupBase);
+ INSTALL_HANDLER (StdRead, StdWrite, csDGroupBase);
+
+ INSTALL_HANDLER (StdRead, StdWrite, csAGroupMask);
+ INSTALL_HANDLER (StdRead, StdWrite, csBGroupMask);
+ INSTALL_HANDLER (StdRead, StdWrite, csCGroupMask);
+ INSTALL_HANDLER (StdRead, StdWrite, csDGroupMask);
+
+ INSTALL_HANDLER (StdRead, StdWrite, csASelect0);
+ INSTALL_HANDLER (StdRead, csASelect1Write, csASelect1);
+ INSTALL_HANDLER (StdRead, StdWrite, csASelect2);
+ INSTALL_HANDLER (StdRead, StdWrite, csASelect3);
+
+ INSTALL_HANDLER (StdRead, StdWrite, csBSelect0);
+ INSTALL_HANDLER (StdRead, StdWrite, csBSelect1);
+ INSTALL_HANDLER (StdRead, StdWrite, csBSelect2);
+ INSTALL_HANDLER (StdRead, StdWrite, csBSelect3);
+
+ INSTALL_HANDLER (StdRead, csCSelect0Write, csCSelect0);
+ INSTALL_HANDLER (StdRead, csCSelect1Write, csCSelect1);
+ INSTALL_HANDLER (StdRead, StdWrite, csCSelect2);
+ INSTALL_HANDLER (StdRead, StdWrite, csCSelect3);
+
+ INSTALL_HANDLER (StdRead, StdWrite, csDSelect0);
+ INSTALL_HANDLER (StdRead, StdWrite, csDSelect1);
+ INSTALL_HANDLER (StdRead, StdWrite, csDSelect2);
+ INSTALL_HANDLER (StdRead, StdWrite, csDSelect3);
+ INSTALL_HANDLER (StdRead, StdWrite, csDebug);
+
+ INSTALL_HANDLER (StdRead, StdWrite, pllControl);
+ INSTALL_HANDLER (pllFreqSelRead, StdWrite, pllFreqSel);
+ INSTALL_HANDLER (StdRead, StdWrite, pllTest);
+ INSTALL_HANDLER (StdRead, StdWrite, pwrControl);
+
+ INSTALL_HANDLER (StdRead, StdWrite, intVector);
+ INSTALL_HANDLER (StdRead, StdWrite, intControl);
+ INSTALL_HANDLER (StdRead, intMaskHiWrite, intMaskHi);
+ INSTALL_HANDLER (StdRead, intMaskLoWrite, intMaskLo);
+ INSTALL_HANDLER (StdRead, StdWrite, intWakeupEnHi);
+ INSTALL_HANDLER (StdRead, StdWrite, intWakeupEnLo);
+ INSTALL_HANDLER (StdRead, intStatusHiWrite, intStatusHi);
+ INSTALL_HANDLER (StdRead, NullWrite, intStatusLo);
+ INSTALL_HANDLER (StdRead, NullWrite, intPendingHi);
+ INSTALL_HANDLER (StdRead, NullWrite, intPendingLo);
+
+ INSTALL_HANDLER (StdRead, StdWrite, portADir);
+ INSTALL_HANDLER (portXDataRead, portXDataWrite, portAData);
+ INSTALL_HANDLER (StdRead, StdWrite, portASelect);
+
+ INSTALL_HANDLER (StdRead, StdWrite, portBDir);
+ INSTALL_HANDLER (portXDataRead, portXDataWrite, portBData);
+ INSTALL_HANDLER (StdRead, StdWrite, portBSelect);
+
+ INSTALL_HANDLER (StdRead, StdWrite, portCDir);
+ INSTALL_HANDLER (portXDataRead, portXDataWrite, portCData);
+ INSTALL_HANDLER (StdRead, StdWrite, portCSelect);
+
+ INSTALL_HANDLER (StdRead, StdWrite, portDDir);
+ INSTALL_HANDLER (portXDataRead, portXDataWrite, portDData);
+ INSTALL_HANDLER (StdRead, StdWrite, portDPullupEn);
+ INSTALL_HANDLER (StdRead, StdWrite, portDPolarity);
+ INSTALL_HANDLER (StdRead, portDIntReqEnWrite, portDIntReqEn);
+ INSTALL_HANDLER (StdRead, StdWrite, portDIntEdge);
+
+ INSTALL_HANDLER (StdRead, StdWrite, portEDir);
+ INSTALL_HANDLER (portXDataRead, portXDataWrite, portEData);
+ INSTALL_HANDLER (StdRead, StdWrite, portEPullupEn);
+ INSTALL_HANDLER (StdRead, StdWrite, portESelect);
+
+ INSTALL_HANDLER (StdRead, StdWrite, portFDir);
+ INSTALL_HANDLER (portXDataRead, portXDataWrite, portFData);
+ INSTALL_HANDLER (StdRead, StdWrite, portFPullupEn);
+ INSTALL_HANDLER (StdRead, StdWrite, portFSelect);
+
+ INSTALL_HANDLER (StdRead, StdWrite, portGDir);
+ INSTALL_HANDLER (portXDataRead, portXDataWrite, portGData);
+ INSTALL_HANDLER (StdRead, StdWrite, portGPullupEn);
+ INSTALL_HANDLER (StdRead, StdWrite, portGSelect);
+
+ INSTALL_HANDLER (StdRead, StdWrite, portJDir);
+ INSTALL_HANDLER (portXDataRead, portXDataWrite, portJData);
+ INSTALL_HANDLER (StdRead, StdWrite, portJSelect);
+
+ INSTALL_HANDLER (StdRead, StdWrite, portKDir);
+ INSTALL_HANDLER (portXDataRead, portXDataWrite, portKData);
+ INSTALL_HANDLER (StdRead, StdWrite, portKPullupEn);
+ INSTALL_HANDLER (StdRead, StdWrite, portKSelect);
+
+ INSTALL_HANDLER (StdRead, StdWrite, portMDir);
+ INSTALL_HANDLER (portXDataRead, portXDataWrite, portMData);
+ INSTALL_HANDLER (StdRead, StdWrite, portMPullupEn);
+ INSTALL_HANDLER (StdRead, StdWrite, portMSelect);
+
+ INSTALL_HANDLER (StdRead, StdWrite, pwmControl);
+ INSTALL_HANDLER (StdRead, StdWrite, pwmPeriod);
+ INSTALL_HANDLER (StdRead, StdWrite, pwmWidth);
+ INSTALL_HANDLER (StdRead, NullWrite, pwmCounter);
+
+ INSTALL_HANDLER (StdRead, StdWrite, tmr1Control);
+ INSTALL_HANDLER (StdRead, StdWrite, tmr1Prescaler);
+ INSTALL_HANDLER (StdRead, StdWrite, tmr1Compare);
+ INSTALL_HANDLER (StdRead, StdWrite, tmr1Capture);
+ INSTALL_HANDLER (StdRead, NullWrite, tmr1Counter);
+ INSTALL_HANDLER (tmr1StatusRead, tmr1StatusWrite, tmr1Status);
+
+ INSTALL_HANDLER (StdRead, StdWrite, tmr2Control);
+ INSTALL_HANDLER (StdRead, StdWrite, tmr2Prescaler);
+ INSTALL_HANDLER (StdRead, StdWrite, tmr2Compare);
+ INSTALL_HANDLER (StdRead, StdWrite, tmr2Capture);
+ INSTALL_HANDLER (StdRead, NullWrite, tmr2Counter);
+ INSTALL_HANDLER (tmr2StatusRead, tmr2StatusWrite, tmr2Status);
+
+ INSTALL_HANDLER (StdRead, StdWrite, wdControl);
+ INSTALL_HANDLER (StdRead, StdWrite, wdReference);
+ INSTALL_HANDLER (StdRead, wdCounterWrite, wdCounter);
+
+ INSTALL_HANDLER (StdRead, StdWrite, spiSlave);
+ INSTALL_HANDLER (StdRead, StdWrite, spiMasterData);
+ INSTALL_HANDLER (StdRead, spiMasterControlWrite, spiMasterControl);
+
+ INSTALL_HANDLER (uartRead, uartWrite, uControl);
+ INSTALL_HANDLER (uartRead, uartWrite, uBaud);
+ INSTALL_HANDLER (uartRead, uartWrite, uReceive);
+ INSTALL_HANDLER (uartRead, uartWrite, uTransmit);
+ INSTALL_HANDLER (uartRead, uartWrite, uMisc);
+
+ INSTALL_HANDLER (StdRead, lcdRegisterWrite, lcdStartAddr);
+ INSTALL_HANDLER (StdRead, lcdRegisterWrite, lcdPageWidth);
+ INSTALL_HANDLER (StdRead, lcdRegisterWrite, lcdScreenWidth);
+ INSTALL_HANDLER (StdRead, lcdRegisterWrite, lcdScreenHeight);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdCursorXPos);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdCursorYPos);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdCursorWidthHeight);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdBlinkControl);
+ INSTALL_HANDLER (StdRead, lcdRegisterWrite, lcdPanelControl);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdPolarity);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdACDRate);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdPixelClock);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdClockControl);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdLastBufferAddr);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdOctetTermCount);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdPanningOffset);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdFrameRate);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdGrayPalette);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdReserved);
+
+ INSTALL_HANDLER (rtcHourMinSecRead, StdWrite, rtcHourMinSec);
+ INSTALL_HANDLER (StdRead, StdWrite, rtcAlarm);
+ INSTALL_HANDLER (StdRead, StdWrite, rtcReserved);
+ INSTALL_HANDLER (StdRead, rtcControlWrite, rtcControl);
+ INSTALL_HANDLER (StdRead, rtcIntStatusWrite, rtcIntStatus);
+ INSTALL_HANDLER (StdRead, rtcIntEnableWrite, rtcIntEnable);
+ INSTALL_HANDLER (StdRead, StdWrite, stopWatch);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::GetRealAddress
+// ---------------------------------------------------------------------------
+
+uint8* EmRegs328::GetRealAddress (emuptr address)
+{
+ uint8* loc = ((uint8*) &f68328Regs) + (address - kMemoryStart);
+
+ return loc;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::GetAddressStart
+// ---------------------------------------------------------------------------
+
+emuptr EmRegs328::GetAddressStart (void)
+{
+ return kMemoryStart;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::GetAddressRange
+// ---------------------------------------------------------------------------
+
+uint32 EmRegs328::GetAddressRange (void)
+{
+ COMPILE_TIME_ASSERT (kMemorySize == 0x0B14);
+
+ return kMemorySize;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::Cycle
+// ---------------------------------------------------------------------------
+// Handles periodic events that need to occur when the processor cycles (like
+// updating timer registers). This function is called in two places from
+// Emulator::Execute. Interestingly, the loop runs 3% FASTER if this function
+// is in its own separate function instead of being inline.
+
+#if 0
+static int calibrated;
+static int increment;
+static int timesCalled;
+static uint32 startingTime;
+
+static void PrvCalibrate (uint16 tmrCompare)
+{
+ // Calibrate the the value by which we increment the counter.
+ // The counter is set up so that it times out after 10 milliseconds
+ // so that it can increment the Palm OS's tick counter 100 times
+ // a second. We would like tmrCounter to surpass tmrCompare
+ // after 10 milliseconds. So figure out by how much we need to
+ // increment it in order for that to happen.
+
+ // If timer is disabled; reset calibration.
+
+ if (tmrCompare == 0xFFFF)
+ {
+ startingTime = 0;
+ }
+
+ // If timer is enabled, restart calibration.
+
+ else if (startingTime == 0)
+ {
+ startingTime = Platform::GetMilliseconds();
+ timesCalled = 0;
+ increment = 1;
+ }
+
+ // If calibration is started, continue it.
+
+ else
+ {
+ timesCalled++;
+
+ uint32 now = Platform::GetMilliseconds();
+ if (now - startingTime > 100)
+ {
+ calibrated = true;
+ increment = tmrCompare / (timesCalled / 10);
+ }
+ }
+}
+#endif
+
+void EmRegs328::Cycle (Bool sleeping)
+{
+#if 0
+ // Cycle is *very* sensitive to timing issue. With this section
+ // of code, a Gremlins run can slow down by 5%.
+ if (!calibrated)
+ {
+ ::PrvCalibrate (READ_REGISTER (tmr2Compare));
+ }
+#else
+ #if _DEBUG
+ #define increment 20
+ #else
+ #define increment 4
+ #endif
+#endif
+
+ // Determine whether timer 2 is enabled.
+
+ if ((READ_REGISTER (tmr2Control) & hwr328TmrControlEnable) != 0)
+ {
+ // If so, increment the timer.
+
+ WRITE_REGISTER (tmr2Counter, READ_REGISTER (tmr2Counter) + (sleeping ? 1 : increment));
+
+ // Determine whether the timer has reached the specified count.
+
+ if (sleeping || READ_REGISTER (tmr2Counter) > READ_REGISTER (tmr2Compare))
+ {
+ // Flag the occurrence of the successful comparison.
+
+ WRITE_REGISTER (tmr2Status, READ_REGISTER (tmr2Status) | hwr328TmrStatusCompare);
+
+ // If the Free Run/Restart flag is not set, clear the counter.
+
+ if ((READ_REGISTER (tmr2Control) & hwr328TmrControlFreeRun) == 0)
+ {
+ WRITE_REGISTER (tmr2Counter, 0);
+ }
+
+ // If the timer interrupt is enabled, post an interrupt.
+
+ if ((READ_REGISTER (tmr2Control) & hwr328TmrControlEnInterrupt) != 0)
+ {
+ WRITE_REGISTER (intPendingLo, READ_REGISTER (intPendingLo) | hwr328IntLoTimer2);
+ EmRegs328::UpdateInterrupts ();
+ }
+ }
+ }
+
+ if ((fCycle += increment) > READ_REGISTER (tmr2Compare))
+ {
+ fCycle = 0;
+
+ if (++fTick >= 100)
+ {
+ fTick = 0;
+
+ if (++fSec >= 60)
+ {
+ fSec = 0;
+
+ if (++fMin >= 60)
+ {
+ fMin = 0;
+
+ if (++fHour >= 24)
+ {
+ fHour = 0;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::CycleSlowly
+// ---------------------------------------------------------------------------
+// Handles periodic events that need to occur when the processor cycles (like
+// updating timer registers). This function is called in two places from
+// Emulator::Execute. Interestingly, the loop runs 3% FASTER if this function
+// is in its own separate function instead of being inline.
+
+void EmRegs328::CycleSlowly (Bool sleeping)
+{
+ UNUSED_PARAM(sleeping)
+
+ // See if a hard button is pressed.
+
+ EmAssert (gSession);
+ if (gSession->HasButtonEvent ())
+ {
+ EmButtonEvent event = gSession->GetButtonEvent ();
+ if (event.fButton == kElement_CradleButton)
+ {
+ EmRegs328::HotSyncEvent (event.fButtonIsDown);
+ }
+ else
+ {
+ EmRegs328::ButtonEvent (event.fButton, event.fButtonIsDown);
+ }
+ }
+
+ // See if there's anything new ("Put the data on the bus")
+
+ EmRegs328::UpdateUARTState (false);
+
+ // Check to see if the RTC alarm is ready to go off. First see
+ // if the RTC is enabled, and that the alarm event isn't already
+ // registered (the latter check is just an optimization).
+
+ if ((READ_REGISTER (rtcIntEnable) & hwr328RTCIntEnableAlarm) != 0 &&
+ (READ_REGISTER (rtcIntStatus) & hwr328RTCIntStatusAlarm) == 0)
+ {
+ uint32 rtcAlarm = READ_REGISTER (rtcAlarm);
+
+ long almHour = (rtcAlarm & hwr328RTCAlarmHoursMask) >> hwr328RTCAlarmHoursOffset;
+ long almMin = (rtcAlarm & hwr328RTCAlarmMinutesMask) >> hwr328RTCAlarmMinutesOffset;
+ long almSec = (rtcAlarm & hwr328RTCAlarmSecondsMask) >> hwr328RTCAlarmSecondsOffset;
+ long almInSeconds = (almHour * 60 * 60) + (almMin * 60) + almSec;
+
+ long nowHour;
+ long nowMin;
+ long nowSec;
+ ::GetHostTime (&nowHour, &nowMin, &nowSec);
+ long nowInSeconds = (nowHour * 60 * 60) + (nowMin * 60) + nowSec;
+
+ if (almInSeconds <= nowInSeconds)
+ {
+ WRITE_REGISTER (rtcIntStatus, READ_REGISTER (rtcIntStatus) | hwr328RTCIntStatusAlarm);
+ EmRegs328::UpdateRTCInterrupts ();
+ }
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::TurnSoundOff
+// ---------------------------------------------------------------------------
+
+void EmRegs328::TurnSoundOff (void)
+{
+ uint16 pwmControl = READ_REGISTER (pwmControl);
+ WRITE_REGISTER (pwmControl, pwmControl & ~hwr328PWMControlEnable);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::ResetTimer
+// ---------------------------------------------------------------------------
+
+void EmRegs328::ResetTimer (void)
+{
+ WRITE_REGISTER (tmr2Counter, 0);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::ResetRTC
+// ---------------------------------------------------------------------------
+
+void EmRegs328::ResetRTC (void)
+{
+ fHour = 15;
+ fMin = 0;
+ fSec = 0;
+ fTick = 0;
+ fCycle = 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::GetInterruptLevel
+// ---------------------------------------------------------------------------
+
+int32 EmRegs328::GetInterruptLevel (void)
+{
+ uint16 intStatusHi = READ_REGISTER (intStatusHi);
+ uint16 intStatusLo = READ_REGISTER (intStatusLo);
+
+ // Level 7 = IRQ7.
+
+ if ((intStatusHi & hwr328IntHiNMI) != 0)
+ return 7;
+
+ // Level 6 = SPIS, TMR1, IRQ6.
+
+ if ((intStatusHi & (hwr328IntHiTimer1 | hwr328IntHiSPIS | hwr328IntHiIRQ6)) != 0)
+ return 6;
+
+ // Level 5 = PEN.
+
+ if ((intStatusHi & hwr328IntHiPen) != 0)
+ return 5;
+
+ // Level 4 = SPIM, TMR2, UART, WDT, RTC, KB, PWM, INT0 - INT7.
+
+ if ((intStatusLo & ( hwr328IntLoAllKeys |
+ hwr328IntLoPWM |
+ hwr328IntLoKbd |
+ // hwr328IntLoLCDC |
+ hwr328IntLoRTC |
+ hwr328IntLoWDT |
+ hwr328IntLoTimer2 |
+ hwr328IntLoSPIM)) != 0)
+ return 4;
+
+ // Level 3 = IRQ3.
+
+ if ((intStatusHi & hwr328IntHiIRQ3) != 0)
+ return 3;
+
+ // Level 2 = IRQ2.
+
+ if ((intStatusHi & hwr328IntHiIRQ2) != 0)
+ return 2;
+
+ // Level 1 = IRQ1.
+
+ if ((intStatusHi & hwr328IntHiIRQ1) != 0)
+ return 1;
+
+ // Level 0.
+
+ return -1;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::GetInterruptBase
+// ---------------------------------------------------------------------------
+
+int32 EmRegs328::GetInterruptBase (void)
+{
+ return READ_REGISTER (intVector) & 0xF8;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::GetLCDHasFrame
+// ---------------------------------------------------------------------------
+
+Bool EmRegs328::GetLCDHasFrame (void)
+{
+ return false;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::GetLCDBeginEnd
+// ---------------------------------------------------------------------------
+
+void EmRegs328::GetLCDBeginEnd (emuptr& begin, emuptr& end)
+{
+ emuptr baseAddr = READ_REGISTER (lcdStartAddr);
+ int rowBytes = READ_REGISTER (lcdPageWidth) * 2;
+ int height = READ_REGISTER (lcdScreenHeight) + 1;
+
+ begin = baseAddr;
+ end = baseAddr + rowBytes * height;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::GetLCDScanlines
+// ---------------------------------------------------------------------------
+
+void EmRegs328::GetLCDScanlines (EmScreenUpdateInfo& info)
+{
+ // Get the screen metrics.
+
+ int32 bpp = 1 << (READ_REGISTER (lcdPanelControl) & 0x01);
+ int32 width = READ_REGISTER (lcdScreenWidth) + 1;
+ int32 height = READ_REGISTER (lcdScreenHeight) + 1;
+ int32 rowBytes = READ_REGISTER (lcdPageWidth) * 2;
+ emuptr baseAddr = READ_REGISTER (lcdStartAddr);
+
+ info.fLeftMargin = READ_REGISTER (lcdPanningOffset) & 0x0F;
+
+ EmPixMapFormat format = bpp == 1 ? kPixMapFormat1 :
+ bpp == 2 ? kPixMapFormat2 :
+ bpp == 4 ? kPixMapFormat4 :
+ kPixMapFormat8;
+
+ RGBList colorTable;
+ this->PrvGetPalette (colorTable);
+
+ // Set format, size, and color table of EmPixMap.
+
+ info.fImage.SetSize (EmPoint (width, height));
+ info.fImage.SetFormat (format);
+ info.fImage.SetRowBytes (rowBytes);
+ info.fImage.SetColorTable (colorTable);
+
+ // Determine first and last scanlines to fetch, and fetch them.
+
+ info.fFirstLine = (info.fScreenLow - baseAddr) / rowBytes;
+ info.fLastLine = (info.fScreenHigh - baseAddr - 1) / rowBytes + 1;
+
+ long firstLineOffset = info.fFirstLine * rowBytes;
+ long lastLineOffset = info.fLastLine * rowBytes;
+
+ EmMem_memcpy (
+ (void*) ((uint8*) info.fImage.GetBits () + firstLineOffset),
+ baseAddr + firstLineOffset,
+ lastLineOffset - firstLineOffset);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::GetUARTDevice
+// ---------------------------------------------------------------------------
+// Return what sort of device is hooked up to the given UART.
+
+EmUARTDeviceType EmRegs328::GetUARTDevice (int /*uartNum*/)
+{
+ Bool serEnabled = this->GetLineDriverState (kUARTSerial);
+ Bool irEnabled = this->GetLineDriverState (kUARTIR);
+
+ // It's probably an error to have them both enabled at the same
+ // time. !!! TBD: make this an error message.
+
+ EmAssert (!(serEnabled && irEnabled));
+
+ if (serEnabled)
+ return kUARTSerial;
+
+ if (irEnabled)
+ return kUARTIR;
+
+ return kUARTNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::GetDynamicHeapSize
+// ---------------------------------------------------------------------------
+
+int32 EmRegs328::GetDynamicHeapSize (void)
+{
+ uint32 result = 0;
+
+ uint32 csCSelect0 = READ_REGISTER (csCSelect0) & ADDRESS_MASK;
+ uint32 csCSelect1 = READ_REGISTER (csCSelect1) & ADDRESS_MASK;
+
+ if (csCSelect0 == 0x0000 && csCSelect1 == 0x0000)
+ {
+ result = 0 * 1024L;
+ }
+ else if (csCSelect0 == 0x0070 && csCSelect1 == 0x0000)
+ {
+ result = 32 * 1024L;
+ }
+ else if (csCSelect0 == 0x00F0 && csCSelect1 == 0x0000)
+ {
+ result = 64 * 1024L;
+ }
+ else if (csCSelect0 == 0x0070 && csCSelect1 == 0x0070)
+ {
+ // This one's odd, but the Symbol seems to (temporarily)
+ // set up this configuration when running with 2Meg of RAM.
+ result = 96 * 1024L;
+ }
+ else if (csCSelect0 == 0x00F0 && csCSelect1 == 0x0070)
+ {
+ result = 96 * 1024L;
+ }
+ else if (csCSelect0 == 0x01F0 && csCSelect1 == 0x0000)
+ {
+ result = 128 * 1024L;
+ }
+ else if (csCSelect0 == 0x03F0 && csCSelect1 == 0x0000)
+ {
+ result = 256 * 1024L;
+ }
+ else
+ {
+ EmAssert (false);
+ }
+
+ if (!ChipSelectsConfigured())
+ {
+ result = 16 * 1024L * 1024L;
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::GetROMSize
+// ---------------------------------------------------------------------------
+
+int32 EmRegs328::GetROMSize (void)
+{
+ uint32 result = 2 * 1024L * 1024L;
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::GetROMBaseAddress
+// ---------------------------------------------------------------------------
+
+emuptr EmRegs328::GetROMBaseAddress (void)
+{
+ if (!this->ChipSelectsConfigured())
+ {
+ return 0xFFFFFFFF;
+ }
+
+ return 0x10C00000; // use known value
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::ChipSelectsConfigured
+// ---------------------------------------------------------------------------
+
+Bool EmRegs328::ChipSelectsConfigured (void)
+{
+ return READ_REGISTER (csAGroupBase) & 0x0001;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::GetSystemClockFrequency
+// ---------------------------------------------------------------------------
+
+int32 EmRegs328::GetSystemClockFrequency (void)
+{
+ uint16 pllControl = READ_REGISTER (pllControl);
+ uint16 pllFreqSel = READ_REGISTER (pllFreqSel);
+
+ uint16 PC = (pllFreqSel & 0x00FF);
+ uint16 QC = (pllFreqSel & 0x0F00) >> 8;
+
+ uint32 result = 32768L * (14 * (PC + 1) + QC + 1);
+
+ // Divide by the system clock scaler, if needed.
+
+ switch (pllControl & 0x0F00)
+ {
+ case hwr328PLLControlSysVCODiv2:
+ result /= 2;
+ break;
+
+ case hwr328PLLControlSysVCODiv4:
+ result /= 4;
+ break;
+
+ case hwr328PLLControlSysVCODiv8:
+ result /= 8;
+ break;
+
+ case hwr328PLLControlSysVCODiv16:
+ result /= 16;
+ break;
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::GetCanStop
+// ---------------------------------------------------------------------------
+
+Bool EmRegs328::GetCanStop (void)
+{
+ // Make sure Timer 2 is enabled or the RTC interrupt is enabled.
+
+ if ((READ_REGISTER (tmr2Control) & hwr328TmrControlEnable) != 0)
+ return true;
+
+ if ((READ_REGISTER (rtcIntEnable) & hwr328RTCIntEnableAlarm) != 0)
+ return true;
+
+ return false;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::GetAsleep
+// ---------------------------------------------------------------------------
+
+Bool EmRegs328::GetAsleep (void)
+{
+ return ((READ_REGISTER (pllControl) & hwr328PLLControlDisable) != 0);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::GetPortInputValue
+// ---------------------------------------------------------------------------
+// Return the GPIO values for the pins on the port. These values are used
+// if the select pins are high.
+
+uint8 EmRegs328::GetPortInputValue (int port)
+{
+ uint8 result = 0;
+
+ if (port == 'D')
+ {
+ result = this->GetPortInternalValue (port);
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::GetPortInternalValue
+// ---------------------------------------------------------------------------
+// Return the dedicated values for the pins on the port. These values are
+// used if the select pins are low.
+
+uint8 EmRegs328::GetPortInternalValue (int port)
+{
+ uint8 result = 0;
+
+ if (port == 'C')
+ {
+ // This makes the power on key work. If the signal is not asserted, the
+ // unit will not transition between asleep and awake (cf. HwrSleep, HwrWake).
+
+ result |= hwr328PortCNMI;
+ }
+
+ else if (port == 'D')
+ {
+ // If the ID_DETECT pin is asserted, load the data lines with the
+ // hardware ID.
+
+ if (EmRegs328::IDDetectAsserted ())
+ {
+ result |= EmRegs328::GetHardwareID ();
+ }
+
+ // Otherwise, load the lines with keyboard information.
+
+ else
+ {
+ // Get the INT bits that need to be set.
+
+ result |= this->GetKeyBits ();
+ }
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::PortDataChanged
+// ---------------------------------------------------------------------------
+
+void EmRegs328::PortDataChanged (int port, uint8, uint8 newValue)
+{
+ if (port == 'D')
+ {
+ // Clear the interrupt bits that are having a 1 written to them.
+ // Only clear them if they're configured as edge-senstive.
+
+ uint8 portDIntEdge = READ_REGISTER (portDIntEdge);
+
+ PRINTF ("EmRegs328::PortDataChanged (D): fPortDEdge = 0x%02lX", (uint32) (uint8) fPortDEdge);
+ PRINTF ("EmRegs328::PortDataChanged (D): portDIntEdge = 0x%02lX", (uint32) (uint8) portDIntEdge);
+ PRINTF ("EmRegs328::PortDataChanged (D): newValue = 0x%02lX", (uint32) (uint8) newValue);
+
+ fPortDEdge &= ~(newValue & portDIntEdge);
+
+ PRINTF ("EmRegs328::PortDataChanged (D): fPortDEdge = 0x%02lX", (uint32) (uint8) fPortDEdge);
+
+ // Set the new interrupt state.
+
+ EmRegs328::UpdatePortDInterrupts ();
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::pllFreqSelRead
+// ---------------------------------------------------------------------------
+
+uint32 EmRegs328::pllFreqSelRead (emuptr address, int size)
+{
+ // Simulate the rising and falling of the CLK32 signal so that functions
+ // like HwrPreRAMInit, HwrShutDownPLL, PrvSetPLL, and PrvShutDownPLL
+ // won't hang.
+
+ uint16 pllFreqSel = READ_REGISTER (pllFreqSel) ^ 0x8000;
+ WRITE_REGISTER (pllFreqSel, pllFreqSel);
+
+ // Finish up by doing a standard read.
+
+ return EmRegs328::StdRead (address, size);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::portXDataRead
+// ---------------------------------------------------------------------------
+
+uint32 EmRegs328::portXDataRead (emuptr address, int)
+{
+ // The value read can come from three different places:
+ //
+ // - the value what was written to the data register
+ // - any dedicated inputs
+ // - any GPIO inputs
+ //
+ // The value returned depends on the settings of the SEL and DIR
+ // registers. So let's get those settings, the values from the three
+ // input sources, and build up a return value based on those.
+
+ int port = GetPort (address);
+
+ uint8 sel = StdRead (address + 2, 1);
+ uint8 dir = StdRead (address - 1, 1);
+ uint8 output = StdRead (address + 0, 1);
+ uint8 input = EmHAL::GetPortInputValue (port);
+ uint8 intFn = EmHAL::GetPortInternalValue (port);
+
+ uint8 xsel = sel;
+ uint8 xdir = dir;
+ uint8 xoutput = output;
+ uint8 xinput = input;
+ uint8 xintFn = intFn;
+
+ if (port == 'D')
+ {
+ sel = 0xFF; // No "select" bit in low nybble, so set for IO values.
+
+ // The system will poll portD twice in KeyBootKeys to see
+ // if any keys are down. Wait at least that long before
+ // letting up any boot keys maintained by the session. When we
+ // do call ReleaseBootKeys, set our counter to -1 as a flag not
+ // to call it any more.
+
+ if (fPortDDataCount != 0xFFFFFFFF && ++fPortDDataCount >= 2 * 2)
+ {
+ fPortDDataCount = 0xFFFFFFFF;
+ gSession->ReleaseBootKeys ();
+ }
+ }
+
+ // Use the internal chip function bits if the "sel" bits are zero.
+
+ intFn &= ~sel;
+
+ // Otherwise, use the I/O bits.
+
+ output &= sel & dir; // Use the output bits if the "dir" is one.
+ input &= sel & ~dir; // Use the input bits if the "dir" is zero.
+
+ // Assert that there are no overlaps.
+
+ EmAssert ((output & input) == 0);
+ EmAssert ((output & intFn) == 0);
+ EmAssert ((input & intFn) == 0);
+
+ // Mush everything together.
+
+ uint8 result = output | input | intFn;
+
+ // If this is port D, flip the bits if the POLARITY register says to.
+ // (!!! Does this inversion apply only to input bits? That is, the
+ // bits where the "dir" register has 0 bits?)
+
+ if (0 && port == 'D')
+ {
+ uint8 polarity = READ_REGISTER (portDPolarity);
+ PRINTF ("EmRegs328::portXDataRead: polarity = 0x%02lX", (uint32) polarity);
+ result ^= polarity;
+ }
+
+ PRINTF ("EmRegs328::port%cDataRead: sel dir output input intFn result", (char) port);
+ PRINTF ("EmRegs328::port%cDataRead: 0x%02lX 0x%02lX 0x%02lX 0x%02lX 0x%02lX 0x%02lX",
+ (char) port, (uint32) xsel, (uint32) xdir, (uint32) xoutput, (uint32) xinput, (uint32) xintFn, (uint32) result);
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::tmr1StatusRead
+// ---------------------------------------------------------------------------
+
+uint32 EmRegs328::tmr1StatusRead (emuptr address, int size)
+{
+ uint16 tmr1Counter = READ_REGISTER (tmr1Counter) + 16;
+ uint16 tmr1Compare = READ_REGISTER (tmr1Compare);
+ uint16 tmr1Control = READ_REGISTER (tmr1Control);
+
+ // Increment the timer.
+
+ WRITE_REGISTER (tmr1Counter, tmr1Counter);
+
+ // If the timer has passed the specified value...
+
+ if ( (tmr1Counter - tmr1Compare) < 16 )
+ {
+ // Set the flag saying the timer timed out.
+
+ uint16 tmr1Status = READ_REGISTER (tmr1Status) | hwr328TmrStatusCompare;
+ WRITE_REGISTER (tmr1Status, tmr1Status);
+
+ // If it's not a free-running timer, reset it to zero.
+
+ if ((tmr1Control & hwr328TmrControlFreeRun) == 0)
+ {
+ WRITE_REGISTER (tmr1Counter, 0);
+ }
+ }
+
+ // Remember this guy for later (see EmRegs328::tmr1StatusWrite())
+
+ fLastTmr1Status |= READ_REGISTER (tmr1Status);
+
+ // Finish up by doing a standard read.
+
+ return EmRegs328::StdRead (address, size);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::tmr2StatusRead
+// ---------------------------------------------------------------------------
+
+uint32 EmRegs328::tmr2StatusRead (emuptr address, int size)
+{
+#if 0 // (Greg doesn't do this for Timer 2...I wonder why)
+
+ /*
+ ram_rom.cpp: DBReg::tmr2StatusRead: Hmm, I don't update the TMR2 count
+ value. As with everything else that's missing in my DragonBall
+ emulation, it's probably because I never found anything that needed it.
+ If you know otherwise, by all means implement it. Also, the magic value
+ of 16 counts per status read seemed to be about right for the programmed
+ timer 1 frequency. It isn't likely to be right for timer 2.
+
+ -- Greg
+ */
+
+ uint16 tmr2Counter = READ_REGISTER (tmr2Counter) + 16;
+ uint16 tmr2Compare = READ_REGISTER (tmr2Compare);
+ uint16 tmr2Control = READ_REGISTER (tmr2Control);
+
+ // Increment the timer.
+
+ WRITE_REGISTER (tmr2Counter, tmr2Counter);
+
+ // If the timer has passed the specified value...
+
+ if ( (tmr2Counter - tmr2Compare) < 16 )
+ {
+ // Set the flag saying the timer timed out.
+
+ uint16 tmr2Status = READ_REGISTER (tmr1Status) | hwr328TmrStatusCompare;
+ WRITE_REGISTER (tmr2Status, tmr2Status);
+
+ // If it's not a free-running timer, reset it to zero.
+
+ if ( (tmr2Control & hwr328TmrControlFreeRun) == 0 )
+ WRITE_REGISTER (tmr2Counter, 0);
+ }
+#endif
+
+ fLastTmr2Status |= READ_REGISTER (tmr2Status); // remember this guy for later (see EmRegs328::tmr2StatusWrite())
+
+ // Finish up by doing a standard read.
+
+ return EmRegs328::StdRead (address, size);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::uartRead
+// ---------------------------------------------------------------------------
+
+uint32 EmRegs328::uartRead (emuptr address, int size)
+{
+ // If this is a full read, get the next byte from the FIFO.
+
+ Bool refreshRxData = (address == addressof (uReceive)) && (size == 2);
+
+ // See if there's anything new ("Put the data on the bus")
+
+ EmRegs328::UpdateUARTState (refreshRxData);
+
+ // Finish up by doing a standard read.
+
+ return EmRegs328::StdRead (address, size);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::rtcHourMinSecRead
+// ---------------------------------------------------------------------------
+
+uint32 EmRegs328::rtcHourMinSecRead (emuptr address, int size)
+{
+ // Get the desktop machine's time.
+
+ long hour, min, sec;
+
+ if (Hordes::IsOn ())
+ {
+ hour = fHour;
+ min = fMin;
+ sec = fSec;
+ }
+ else
+ {
+ ::GetHostTime (&hour, &min, &sec);
+ }
+
+ // Update the register.
+
+ WRITE_REGISTER (rtcHourMinSec, (hour << hwr328RTCHourMinSecHoursOffset)
+ | (min << hwr328RTCHourMinSecMinutesOffset)
+ | (sec << hwr328RTCHourMinSecSecondsOffset));
+
+ // Finish up by doing a standard read.
+
+ return EmRegs328::StdRead (address, size);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::csASelect1Write
+// ---------------------------------------------------------------------------
+
+void EmRegs328::csASelect1Write (emuptr address, int size, uint32 value)
+{
+ // Do a standard update of the register.
+
+ EmRegs328::StdWrite (address, size, value);
+
+ // Check its new state and update our ram-protect flag.
+
+ gMemAccessFlags.fProtect_SRAMSet = (READ_REGISTER (csASelect1) & 0x0008) != 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::csCSelect0Write
+// ---------------------------------------------------------------------------
+
+void EmRegs328::csCSelect0Write (emuptr address, int size, uint32 value)
+{
+ uint32 csCSelect0 = READ_REGISTER (csCSelect0);
+
+ // Do a standard update of the register.
+
+ EmRegs328::StdWrite (address, size, value);
+
+ // Check to see if the unprotected memory range changed.
+
+ if ((csCSelect0 & ADDRESS_MASK) != (READ_REGISTER (csCSelect0) & ADDRESS_MASK))
+ {
+ EmAssert (gSession);
+ gSession->ScheduleResetBanks ();
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::csCSelect1Write
+// ---------------------------------------------------------------------------
+
+void EmRegs328::csCSelect1Write (emuptr address, int size, uint32 value)
+{
+ uint32 csCSelect1 = READ_REGISTER (csCSelect1);
+
+ // Do a standard update of the register.
+
+ EmRegs328::StdWrite (address, size, value);
+
+ // Check to see if the unprotected memory range changed.
+
+ if ((csCSelect1 & ADDRESS_MASK) != (READ_REGISTER (csCSelect1) & ADDRESS_MASK))
+ {
+ EmAssert (gSession);
+ gSession->ScheduleResetBanks ();
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::intMaskHiWrite
+// ---------------------------------------------------------------------------
+
+void EmRegs328::intMaskHiWrite (emuptr address, int size, uint32 value)
+{
+ // Do a standard update of the register.
+
+ EmRegs328::StdWrite (address, size, value);
+
+ // Respond to the new interrupt state.
+
+ EmRegs328::UpdateInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::intMaskLoWrite
+// ---------------------------------------------------------------------------
+
+void EmRegs328::intMaskLoWrite (emuptr address, int size, uint32 value)
+{
+ // Do a standard update of the register.
+
+ EmRegs328::StdWrite (address, size, value);
+
+ // Respond to the new interrupt state.
+
+ EmRegs328::UpdateInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::intStatusHiWrite
+// ---------------------------------------------------------------------------
+
+void EmRegs328::intStatusHiWrite (emuptr address, int size, uint32 value)
+{
+ // IRQ1, IRQ2, IRQ3, IRQ6 and IRQ7 are cleared by writing to their
+ // respective status bits. We handle those there. Since there are
+ // no interrupt status bits like this in intStatusLo, we don't need
+ // a handler for that register; we only handle intStatusHi.
+
+ // Even though this is a 16-bit register as defined by the Palm headers,
+ // it's a 32-bit register according to Dragonball docs, and is in fact
+ // accessed that way in the kernal files (cf. HwrIRQ4Handler). In those
+ // cases, we're still only interested in access to the IRQ# bits, so we
+ // can turn 4-byte accesses into 2-byte accesses.
+
+ if (size == 4)
+ value >>= 16;
+
+ // Take into account the possibility of 1-byte accesses, too. If we're
+ // accessing the upper byte, just return. If we're accessing the lower
+ // byte, we can treat it as a 2-byte access.
+
+ else if (size == 1 && address == addressof (intStatusHi))
+ return;
+
+ // Now we can treat the rest of this function as a word-write to intStatusHi.
+
+ uint16 intPendingHi = READ_REGISTER (intPendingHi);
+
+ // For each interrupt:
+ // If we're writing to that interrupt's status bit and its edge bit is set:
+ // - clear the interrupt's pending bit
+ // - respond to the new interrupt state.
+
+ #undef CLEAR_PENDING_INTERRUPT
+ #define CLEAR_PENDING_INTERRUPT(edge, irq) \
+ if ( (READ_REGISTER (intControl) & edge) && (value & (irq)) ) \
+ { \
+ intPendingHi &= ~(irq); \
+ }
+
+ CLEAR_PENDING_INTERRUPT (hwr328IntCtlEdge1, hwr328IntHiIRQ1);
+ CLEAR_PENDING_INTERRUPT (hwr328IntCtlEdge2, hwr328IntHiIRQ2);
+ CLEAR_PENDING_INTERRUPT (hwr328IntCtlEdge3, hwr328IntHiIRQ3);
+ CLEAR_PENDING_INTERRUPT (hwr328IntCtlEdge6, hwr328IntHiIRQ6);
+
+ // IRQ7 is not edge-programmable, so clear it if we're merely writing to it.
+
+ if (value & hwr328IntHiNMI)
+ {
+ intPendingHi &= ~(hwr328IntHiNMI);
+ }
+
+ // If we're emulating the user pressing the hotsync button, make sure the
+ // interrupt stays asserted. (!!! Should we use the same technique for
+ // other buttons, too? It doesn't seem to be needed right now, but doing
+ // that may more closely mirror the hardware.)
+
+ if (fHotSyncButtonDown)
+ {
+ intPendingHi |= hwr328IntHiIRQ1;
+ }
+ else
+ {
+ intPendingHi &= ~hwr328IntHiIRQ1;
+ }
+
+ WRITE_REGISTER (intPendingHi, intPendingHi);
+ EmRegs328::UpdateInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::portXDataWrite
+// ---------------------------------------------------------------------------
+
+void EmRegs328::portXDataWrite (emuptr address, int size, uint32 value)
+{
+ // Get the old value before updating it.
+
+ uint8 oldValue = StdRead (address, size);
+
+ // Take a snapshot of the line driver states.
+
+ Bool driverStates[kUARTEnd];
+ EmHAL::GetLineDriverStates (driverStates);
+
+ // Now update the value with a standard write.
+
+ StdWrite (address, size, value);
+
+ // Let anyone know that it's changed.
+
+ int port = GetPort (address);
+ PRINTF ("EmRegs328::port%cDataWrite: oldValue = 0x%02lX", (char) port, (uint32) (uint8) oldValue);
+ PRINTF ("EmRegs328::port%cDataWrite: newValue = 0x%02lX", (char) port, (uint32) (uint8) value);
+
+ EmHAL::PortDataChanged (port, oldValue, value);
+
+ // Respond to any changes in the line driver states.
+
+ EmHAL::CompareLineDriverStates (driverStates);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::portDIntReqEnWrite
+// ---------------------------------------------------------------------------
+
+void EmRegs328::portDIntReqEnWrite (emuptr address, int size, uint32 value)
+{
+ // Do a standard update of the register.
+
+ EmRegs328::StdWrite (address, size, value);
+
+ // Set the new interrupt state.
+
+ EmRegs328::UpdatePortDInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::tmr1StatusWrite
+// ---------------------------------------------------------------------------
+
+void EmRegs328::tmr1StatusWrite (emuptr address, int size, uint32 value)
+{
+ UNUSED_PARAM(address)
+ UNUSED_PARAM(size)
+
+ EmAssert (size == 2); // This function's a hell of a lot easier to write if
+ // we assume only full-register access.
+
+ // Get the current value.
+
+ uint16 tmr1Status = READ_REGISTER (tmr1Status);
+
+ // If the user had previously read the status bits while they
+ // were set, then it's OK for them to be clear now. Otherwise,
+ // we have to merge any set status bits back in.
+
+ tmr1Status &= value | ~fLastTmr1Status; // fLastTmr1Status was set in EmRegs328::tmr1StatusRead()
+
+ WRITE_REGISTER (tmr1Status, tmr1Status);
+
+ fLastTmr1Status = 0;
+ if ((tmr1Status & hwr328TmrStatusCompare) == 0)
+ {
+ uint16 intPendingHi = READ_REGISTER (intPendingHi) & ~hwr328IntHiTimer1;
+ WRITE_REGISTER (intPendingHi, intPendingHi);
+
+ // Respond to the new interrupt state.
+
+ EmRegs328::UpdateInterrupts ();
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::tmr2StatusWrite
+// ---------------------------------------------------------------------------
+
+void EmRegs328::tmr2StatusWrite (emuptr address, int size, uint32 value)
+{
+ UNUSED_PARAM(address)
+ UNUSED_PARAM(size)
+
+ EmAssert (size == 2); // This function's a hell of a lot easier to write if
+ // we assume only full-register access.
+
+ // Get the current value.
+
+ uint16 tmr2Status = READ_REGISTER (tmr2Status);
+
+ // If the user had previously read the status bits while they
+ // were set, then it's OK for them to be clear now. Otherwise,
+ // we have to merge any set status bits back in.
+
+ tmr2Status &= value | ~fLastTmr2Status; // fLastTmr2Status was set in EmRegs328::tmr2StatusRead()
+
+ WRITE_REGISTER (tmr2Status, tmr2Status);
+
+ fLastTmr2Status = 0;
+ if ( (tmr2Status & hwr328TmrStatusCompare) == 0 )
+ {
+ uint16 intPendingLo = READ_REGISTER (intPendingLo) & ~hwr328IntLoTimer2;
+ WRITE_REGISTER (intPendingLo, intPendingLo);
+
+ // Respond to the new interrupt state.
+
+ EmRegs328::UpdateInterrupts ();
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::wdCounterWrite
+// ---------------------------------------------------------------------------
+
+void EmRegs328::wdCounterWrite (emuptr address, int size, uint32 value)
+{
+ UNUSED_PARAM(address)
+ UNUSED_PARAM(size)
+ UNUSED_PARAM(value)
+
+ // Always set it to zero (a write to this register always resets it).
+
+ WRITE_REGISTER (wdCounter, 0);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::spiMasterControlWrite
+// ---------------------------------------------------------------------------
+
+void EmRegs328::spiMasterControlWrite (emuptr address, int size, uint32 value)
+{
+ // Do a standard update of the register.
+
+ EmRegs328::StdWrite (address, size, value);
+
+ // Get the current value.
+
+ uint16 spiMasterControl = READ_REGISTER (spiMasterControl);
+
+ // Check to see if data exchange and interrupts are enabled.
+
+ #define BIT_MASK (hwr328SPIMControlExchange | hwr328SPIMControlIntEnable)
+ if ((spiMasterControl & BIT_MASK) != 0)
+ {
+ // If so, assert the interrupt and clear the exchange bit.
+
+ spiMasterControl |= hwr328SPIMControlIntStatus;
+ spiMasterControl &= ~hwr328SPIMControlExchange;
+
+ WRITE_REGISTER (spiMasterControl, spiMasterControl);
+
+/*
+ // If we wanted digitizer data, load it into the SPIM data register.
+
+ switch (READ_REGISTER (portFData) & hwrTD1PortFPanelMask)
+ {
+ case (hwrTD1PortFPanelCfgXMeas):
+ WRITE_REGISTER (spiMasterData, (0xFF - Hardware::fgPen_HorzLocation) * 2);
+ break;
+
+ case (hwrTD1PortFPanelCfgYMeas):
+ WRITE_REGISTER (spiMasterData, (0xFF - Hardware::fgPen_VertLocation) * 2);
+ break;
+ }
+*/
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::uartWrite
+// ---------------------------------------------------------------------------
+
+void EmRegs328::uartWrite(emuptr address, int size, uint32 value)
+{
+ // Do a standard update of the register.
+
+ EmRegs328::StdWrite (address, size, value);
+
+ // If this write included the TX_DATA field, signal that it needs to
+ // be transmitted.
+
+ Bool sendTxData =
+ ((address == addressof (uTransmit)) && (size == 2)) ||
+ ((address == addressof (uTransmit) + 1) && (size == 1));
+
+ // React to any changes.
+
+ EmRegs328::UARTStateChanged (sendTxData);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::lcdRegisterWrite
+// ---------------------------------------------------------------------------
+
+void EmRegs328::lcdRegisterWrite(emuptr address, int size, uint32 value)
+{
+ // First, get the old value in case we need to see what changed.
+
+ uint32 oldValue = EmRegs328::StdRead (address, size);
+
+ // Do a standard update of the register.
+
+ EmRegs328::StdWrite (address, size, value);
+
+ // Note what changed.
+
+ if (address == addressof (lcdScreenWidth))
+ {
+ EmScreen::InvalidateAll ();
+ }
+ else if (address == addressof (lcdScreenHeight))
+ {
+ EmScreen::InvalidateAll ();
+ }
+ else if (address == addressof (lcdPanelControl))
+ {
+ if (((value ^ oldValue) & hwr328LcdPanelControlGrayScale) != 0)
+ {
+ EmScreen::InvalidateAll ();
+ }
+ }
+ else if (address == addressof (lcdStartAddr))
+ {
+ // Make sure the low-bit is always zero.
+
+ uint32 lcdStartAddr = READ_REGISTER (lcdStartAddr) & 0xFFFFFFFE;
+ WRITE_REGISTER (lcdStartAddr, lcdStartAddr);
+
+ EmScreen::InvalidateAll ();
+ }
+ else if (address == addressof (lcdPageWidth))
+ {
+ if (value != oldValue)
+ {
+ EmScreen::InvalidateAll ();
+ }
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::rtcControlWrite
+// ---------------------------------------------------------------------------
+
+void EmRegs328::rtcControlWrite(emuptr address, int size, uint32 value)
+{
+ // Do a standard update of the register.
+
+ EmRegs328::StdWrite (address, size, value);
+
+ // Respond to the new interrupt state.
+
+ EmRegs328::UpdateRTCInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::rtcIntStatusWrite
+// ---------------------------------------------------------------------------
+
+void EmRegs328::rtcIntStatusWrite(emuptr address, int size, uint32 value)
+{
+ // Status bits are cleared by writing ones to them.
+
+ // If we're doing a byte-write to the upper byte, shift the byte
+ // so that we can treat the operation as a word write. If we're
+ // doing a byte-write to the lower byte, this extension will happen
+ // automatically.
+
+ if (address == addressof (rtcIntStatus) && size == 1)
+ value <<= 8;
+
+ // Get the current value.
+
+ uint16 rtcIntStatus = READ_REGISTER (rtcIntStatus);
+
+ // Clear the requested bits.
+
+ rtcIntStatus &= ~value;
+
+ // Update the register.
+
+ WRITE_REGISTER (rtcIntStatus, rtcIntStatus);
+
+ // Respond to the new interrupt state.
+
+ EmRegs328::UpdateRTCInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::rtcIntEnableWrite
+// ---------------------------------------------------------------------------
+
+void EmRegs328::rtcIntEnableWrite(emuptr address, int size, uint32 value)
+{
+ // Do a standard update of the register.
+
+ EmRegs328::StdWrite (address, size, value);
+
+ // Respond to the new interrupt state.
+
+ EmRegs328::UpdateRTCInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::ButtonEvent
+// ---------------------------------------------------------------------------
+// Handles a Palm device button event by updating the appropriate registers.
+
+void EmRegs328::ButtonEvent (SkinElementType button, Bool buttonIsDown)
+{
+ uint16 bitNumber = this->ButtonToBits (button);
+
+ // Get the bits that should have been set with the previous set
+ // of pressed keys. We use this old value to update the port D interrupts.
+
+ uint8 oldBits = this->GetKeyBits ();
+
+ // Update the set of keys that are currently pressed.
+
+ if (buttonIsDown)
+ {
+ fKeyBits |= bitNumber; // Remember the key bit
+ }
+ else
+ {
+ fKeyBits &= ~bitNumber; // Forget the key bit
+ }
+
+ // Now get the new set of bits that should be set.
+
+ uint8 newBits = this->GetKeyBits ();
+
+ PRINTF ("EmRegs328::ButtonEvent: fKeyBits = 0x%04lX", (uint32) fKeyBits);
+ PRINTF ("EmRegs328::ButtonEvent: oldBits = 0x%02lX", (uint32) oldBits);
+ PRINTF ("EmRegs328::ButtonEvent: newBits = 0x%02lX", (uint32) newBits);
+
+ // Set the interrupt bits for the bits that went from off to on.
+ // These get cleared when portDData is written to.
+
+ fPortDEdge |= newBits & ~oldBits;
+
+ PRINTF ("EmRegs328::ButtonEvent: fPortDEdge = 0x%02lX", (uint32) fPortDEdge);
+
+ // Set the new interrupt state.
+
+ EmRegs328::UpdatePortDInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::HotSyncEvent
+// ---------------------------------------------------------------------------
+// Handles a HotSync button event by updating the appropriate registers.
+
+void EmRegs328::HotSyncEvent (Bool iButton_IsDown)
+{
+ // If the button changes state, set or clear the HotSync interrupt.
+
+ uint16 intPendingHi = READ_REGISTER (intPendingHi);
+
+ if (iButton_IsDown)
+ {
+ intPendingHi |= hwr328IntHiIRQ1;
+ fHotSyncButtonDown = true;
+ }
+ else
+ {
+ intPendingHi &= ~hwr328IntHiIRQ1;
+ fHotSyncButtonDown = false;
+ }
+
+ WRITE_REGISTER (intPendingHi, intPendingHi);
+
+ EmRegs328::UpdateInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::GetKeyBits
+// ---------------------------------------------------------------------------
+
+uint8 EmRegs328::GetKeyBits (void)
+{
+ // Return the key bits
+
+ uint8 portDPullupEn = READ_REGISTER (portDPullupEn); // Interested where bits are one
+ uint8 keyBits = portDPullupEn & fKeyBits;
+
+ PRINTF ("EmRegs328::GetKeyBits: keyBits = 0x%02lX", (uint32) keyBits);
+
+ return keyBits;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::ButtonToBits
+// ---------------------------------------------------------------------------
+
+uint16 EmRegs328::ButtonToBits (SkinElementType button)
+{
+ uint16 bitNumber = 0;
+ switch (button)
+ {
+ case kElement_None: break;
+
+ case kElement_PowerButton: bitNumber = keyBitPower; break;
+ case kElement_UpButton: bitNumber = keyBitPageUp; break;
+ case kElement_DownButton: bitNumber = keyBitPageDown; break;
+ case kElement_App1Button: bitNumber = keyBitHard1; break;
+ case kElement_App2Button: bitNumber = keyBitHard2; break;
+ case kElement_App3Button: bitNumber = keyBitHard3; break;
+ case kElement_App4Button: bitNumber = keyBitHard4; break;
+ case kElement_CradleButton: bitNumber = keyBitCradle; break;
+ case kElement_Antenna: bitNumber = keyBitAntenna; break;
+ case kElement_ContrastButton: bitNumber = keyBitContrast; break;
+
+/*
+ // Symbol-specific
+ case kElement_TriggerLeft: bitNumber = keyBitTrigLeft; break;
+ case kElement_TriggerCenter: bitNumber = keyBitTrigCenter; break;
+ case kElement_TriggerRight: bitNumber = keyBitTrigRight; break;
+ case kElement_UpButtonLeft: bitNumber = keyBitPageUpLeft; break;
+ case kElement_UpButtonRight: bitNumber = keyBitPageUpRight; break;
+ case kElement_DownButtonLeft: bitNumber = keyBitPageDownLeft; break;
+ case kElement_DownButtonRight: bitNumber = keyBitPageDownRight; break;
+*/
+ default: EmAssert (false);
+ }
+
+ return bitNumber;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::UpdateInterrupts
+// ---------------------------------------------------------------------------
+// Determines whether an interrupt has occurred by copying the Interrupt
+// Pending Register to the Interrupt Status Register.
+
+void EmRegs328::UpdateInterrupts (void)
+{
+ // Copy the Interrupt Pending Register to the Interrupt Status
+ // Register, but ignore interrupts that are being masked.
+
+ // Note: this function is not sensitive to the byte ordering of the registers,
+ // so their contents don't need to be accessed via READ_REGISTER or WRITE_REGISTER.
+
+ f68328Regs.intStatusHi = f68328Regs.intPendingHi & ~f68328Regs.intMaskHi;
+ f68328Regs.intStatusLo = f68328Regs.intPendingLo & ~f68328Regs.intMaskLo;
+
+ PRINTF ("EmRegs328::UpdateInterrupts: intMask = 0x%04lX %04lX",
+ (uint32) f68328Regs.intMaskHi, (uint32) f68328Regs.intMaskLo);
+
+ PRINTF ("EmRegs328::UpdateInterrupts: intPending = 0x%04lX %04lX",
+ (uint32) f68328Regs.intPendingHi, (uint32) f68328Regs.intPendingLo);
+
+ // If the Interrupt Status Register isn't clear, flag an interrupt.
+
+ if (f68328Regs.intStatusHi || f68328Regs.intStatusLo)
+ {
+ regs.spcflags |= SPCFLAG_INT;
+
+ PRINTF ("EmRegs328::UpdateInterrupts: intStatus = 0x%04lX %04lX",
+ (uint32) f68328Regs.intStatusHi, (uint32) f68328Regs.intStatusLo);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::UpdatePortDInterrupts
+// ---------------------------------------------------------------------------
+// Determine what interrupts need to be generated based on the current
+// settings in portDData and fPortDEdge.
+
+void EmRegs328::UpdatePortDInterrupts (void)
+{
+ // Update INT0-INT7 of the Interrupt-Pending register (bits 8-15 of the low word).
+
+ // First, get those bits and clear them out.
+
+ uint16 intPendingLo = READ_REGISTER (intPendingLo) & ~hwr328IntLoAllKeys;
+
+
+ // Initialize the variable to hold the new interrupt settings.
+
+ uint8 newBits = 0;
+
+
+ // Get some other values we're going to need:
+
+ uint8 portDDir = READ_REGISTER (portDDir); // Interrupt on inputs only (when pin is low)
+ uint8 portDData = EmHAL::GetPortInputValue ('D');
+ uint8 portDPolarity = READ_REGISTER (portDPolarity);
+ uint8 portDIntReqEn = READ_REGISTER (portDIntReqEn);
+ uint8 portDIntEdge = READ_REGISTER (portDIntEdge);
+
+
+ // We have a line-level interrupt if:
+ //
+ // - line-level interrupts are requested
+ // - the GPIO bit matches the polarity bit
+
+ newBits |= ~portDIntEdge & portDData & portDPolarity;
+ newBits |= ~portDIntEdge & ~portDData & ~portDPolarity;
+
+
+ // We have an edge interrupt if:
+ //
+ // - edge interrupts are requested
+ // - an edge has been recorded
+ //
+ // Note that we should distinguish between rising and falling edges.
+ // For historical reasons, that's not done, and the Palm OS doesn't
+ // look for them, so it's OK for now.
+
+ newBits |= portDIntEdge & fPortDEdge & portDPolarity;
+ newBits |= portDIntEdge & 0 & ~portDPolarity;
+
+
+ // Only have interrupts if they're enabled and the pin is configured for input.
+
+ newBits &= portDIntReqEn & ~portDDir;
+
+ PRINTF ("EmRegs328::UpdatePortDInterrupts: Dir Data Pol Req Edg PDE bits");
+ PRINTF ("EmRegs328::UpdatePortDInterrupts: 0x%02lX 0x%02lX 0x%02lX 0x%02lX 0x%02lX 0x%02lX 0x%02lX",
+ (uint32) portDDir, (uint32) portDData, (uint32) portDPolarity, (uint32) portDIntReqEn, (uint32) portDIntEdge,
+ (uint32) fPortDEdge, (uint32) newBits);
+
+
+ // Merge in the new values and write out the result.
+
+ intPendingLo |= (((uint16) newBits) << 8) & hwr328IntLoAllKeys;
+ WRITE_REGISTER (intPendingLo, intPendingLo);
+
+
+ // Respond to the new interrupt state.
+
+ EmRegs328::UpdateInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::UpdateRTCInterrupts
+// ---------------------------------------------------------------------------
+// Determine whether to set or clear the RTC bit in the interrupt pending
+// register based on the current RTC register values.
+
+void EmRegs328::UpdateRTCInterrupts (void)
+{
+ // See if the RTC is enabled.
+
+ Bool rtcEnabled = (READ_REGISTER (rtcControl) & hwr328RTCControlRTCEnable) != 0;
+
+ // See if there are any RTC events that need to trigger an interrupt.
+
+#define BITS_TO_CHECK ( \
+ hwr328RTCIntEnableSec | \
+ hwr328RTCIntEnable24Hr | \
+ hwr328RTCIntEnableAlarm | \
+ hwr328RTCIntEnableMinute | \
+ hwr328RTCIntEnableStopWatch )
+
+ uint16 rtcIntStatus = READ_REGISTER (rtcIntStatus);
+ uint16 rtcIntEnable = READ_REGISTER (rtcIntEnable);
+ uint16 rtcIntPending = rtcIntStatus & rtcIntEnable & BITS_TO_CHECK;
+
+ Bool havePendingEvents = rtcIntPending != 0;
+
+ // If the RTC is enabled and there are pending events, set the interrupt.
+ // Otherwise, clear the interrupt.
+
+ uint16 intPendingLo = READ_REGISTER (intPendingLo);
+
+ if (rtcEnabled && havePendingEvents)
+ {
+ intPendingLo |= hwr328IntLoRTC; // have events, so set interrupt
+ }
+ else
+ {
+ intPendingLo &= ~hwr328IntLoRTC; // no events, so clear interrupt
+ }
+
+ // Update the interrupt pending register.
+
+ WRITE_REGISTER (intPendingLo, intPendingLo);
+
+ // Respond to the new interrupt state.
+
+ EmRegs328::UpdateInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::IDDetectAsserted
+// ---------------------------------------------------------------------------
+// cf. HwrIdentifyFeatures and HwrPreRAMInit.
+
+Bool EmRegs328::IDDetectAsserted (void)
+{
+ uint8 portEDir = READ_REGISTER (portEDir);
+ uint8 portEData = READ_REGISTER (portEData);
+ uint8 portEPullupEn = READ_REGISTER (portEPullupEn);
+ const uint8 kMask = hwrTD1PortENoBacklight;
+
+ return (portEDir & kMask) == kMask &&
+ (portEData & kMask) == 0 &&
+ (portEPullupEn & kMask) == 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::GetHardwareID
+// ---------------------------------------------------------------------------
+
+UInt8 EmRegs328::GetHardwareID (void)
+{
+ // Determine the hardware ID.
+
+ // Note: Because of a Poser bug, I don't think any of the following actually
+ // gets executed. 328 ROMs first check to see if they're on a PalmPilot
+ // by executing the following:
+ //
+ // if (!(baseP->portEData & hwrTD1PortENoBacklight)) {
+ // ...on PalmPilot...
+ // } else {
+ // ...execute ID DETECT...
+ // }
+ //
+ // In Poser, hwrTD1PortENoBacklight is always zero (that's the bug), and
+ // so we always think we're on a PalmPilot, regardless of what 328 device
+ // we selected.
+
+ EmAssert (gSession);
+
+ EmDevice device = gSession->GetDevice ();
+ long miscFlags = device.HardwareID ();
+
+ // Reverse map the following:
+// GHwrMiscFlags = 0;
+// if ( (keyState & keyBitHard1) == 0) GHwrMiscFlags |= hwrMiscFlagID1;
+// if ( (keyState & keyBitHard2) == 0) GHwrMiscFlags |= hwrMiscFlagID2;
+// if ( (keyState & keyBitHard3) == 0) GHwrMiscFlags |= hwrMiscFlagID3;
+// if ( (keyState & keyBitHard4) == 0) GHwrMiscFlags |= hwrMiscFlagID4;
+
+ uint8 keyState = ~0;
+
+ if ((miscFlags & hwrMiscFlagID1) != 0) keyState &= ~keyBitHard1;
+ if ((miscFlags & hwrMiscFlagID2) != 0) keyState &= ~keyBitHard2;
+ if ((miscFlags & hwrMiscFlagID3) != 0) keyState &= ~keyBitHard3;
+ if ((miscFlags & hwrMiscFlagID4) != 0) keyState &= ~keyBitHard4;
+
+ return keyState;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::UARTStateChanged
+// ---------------------------------------------------------------------------
+
+void EmRegs328::UARTStateChanged (Bool sendTxData)
+{
+ EmUARTDragonball::State state (EmUARTDragonball::kUART_Dragonball);
+
+ EmRegs328::MarshalUARTState (state);
+ fUART->StateChanged (state, sendTxData);
+ EmRegs328::UnmarshalUARTState (state);
+
+ EmRegs328::UpdateUARTInterrupts (state);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::UpdateUARTState
+// ---------------------------------------------------------------------------
+
+void EmRegs328::UpdateUARTState (Bool refreshRxData)
+{
+ EmUARTDragonball::State state (EmUARTDragonball::kUART_Dragonball);
+
+ EmRegs328::MarshalUARTState (state);
+ fUART->UpdateState (state, refreshRxData);
+ UnmarshalUARTState (state);
+
+ EmRegs328::UpdateUARTInterrupts (state);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::UpdateUARTInterrupts
+// ---------------------------------------------------------------------------
+
+void EmRegs328::UpdateUARTInterrupts (const EmUARTDragonball::State& state)
+{
+ // Generate the appropriate interrupts.
+
+ if (state.RX_FULL_ENABLE && state.RX_FIFO_FULL ||
+ state.RX_HALF_ENABLE && state.RX_FIFO_HALF ||
+ state.RX_RDY_ENABLE && state.DATA_READY ||
+ state.TX_EMPTY_ENABLE && state.TX_FIFO_EMPTY ||
+ state.TX_HALF_ENABLE && state.TX_FIFO_HALF ||
+ state.TX_AVAIL_ENABLE && state.TX_AVAIL)
+ {
+ // Set the UART interrupt.
+
+ WRITE_REGISTER (intPendingLo, READ_REGISTER (intPendingLo) | hwr328IntLoUART);
+ }
+ else
+ {
+ // Clear the UART interrupt.
+
+ WRITE_REGISTER (intPendingLo, READ_REGISTER (intPendingLo) & ~hwr328IntLoUART);
+ }
+
+ // Respond to the new interrupt state.
+
+ EmRegs328::UpdateInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::MarshalUARTState
+// ---------------------------------------------------------------------------
+
+void EmRegs328::MarshalUARTState (EmUARTDragonball::State& state)
+{
+ uint16 uControl = READ_REGISTER (uControl);
+ uint16 uBaud = READ_REGISTER (uBaud);
+ uint16 uReceive = READ_REGISTER (uReceive);
+ uint16 uTransmit = READ_REGISTER (uTransmit);
+ uint16 uMisc = READ_REGISTER (uMisc);
+
+ state.UART_ENABLE = (uControl & hwr328UControlUARTEnable) != 0;
+ state.RX_ENABLE = (uControl & hwr328UControlRxEnable) != 0;
+ state.TX_ENABLE = (uControl & hwr328UControlTxEnable) != 0;
+ state.RX_CLK_CONT = (uControl & hwr328UControlRxClock1x) != 0;
+ state.PARITY_EN = (uControl & hwr328UControlParityEn) != 0;
+ state.ODD_EVEN = (uControl & hwr328UControlParityOdd) != 0;
+ state.STOP_BITS = (uControl & hwr328UControlStopBits2) != 0;
+ state.CHAR8_7 = (uControl & hwr328UControlDataBits8) != 0;
+ state.GPIO_DELTA_ENABLE = (uControl & hwr328UControlGPIODeltaEn) != 0; // 68328 only
+// state.OLD_ENABLE = (uControl & hwrEZ328UControlOldDataEn) != 0; // 68EZ328 only
+ state.CTS_DELTA_ENABLE = (uControl & hwr328UControlCTSDeltaEn) != 0;
+ state.RX_FULL_ENABLE = (uControl & hwr328UControlRxFullEn) != 0;
+ state.RX_HALF_ENABLE = (uControl & hwr328UControlRxHalfEn) != 0;
+ state.RX_RDY_ENABLE = (uControl & hwr328UControlRxRdyEn) != 0;
+ state.TX_EMPTY_ENABLE = (uControl & hwr328UControlTxEmptyEn) != 0;
+ state.TX_HALF_ENABLE = (uControl & hwr328UControlTxHalfEn) != 0;
+ state.TX_AVAIL_ENABLE = (uControl & hwr328UControlTxAvailEn) != 0;
+
+ // Baud control register bits
+ // These are all values the user sets; we just look at them.
+
+ state.GPIO_DELTA = (uBaud & hwr328UBaudGPIODelta) != 0; // 68328 only
+ state.GPIO = (uBaud & hwr328UBaudGPIOData) != 0; // 68328 only
+ state.GPIO_DIR = (uBaud & hwr328UBaudGPIODirOut) != 0; // 68328 only
+ state.GPIO_SRC = (uBaud & hwr328UBaudGPIOSrcBaudGen) != 0; // 68328 only
+// state.UCLK_DIR = (uBaud & hwrEZ328UBaudUCLKDirOut) != 0; // 68EZ328 only
+ state.BAUD_SRC = (uBaud & hwr328UBaudBaudSrcGPIO) != 0;
+ state.DIVIDE = (uBaud & hwr328UBaudDivider) >> hwr328UBaudDivideBitOffset;
+ state.PRESCALER = (uBaud & hwr328UBaudPrescaler);
+
+ // Receive register bits
+ // These are all input bits; we set them, not the user.
+
+ state.RX_FIFO_FULL = (uReceive & hwr328UReceiveFIFOFull) != 0;
+ state.RX_FIFO_HALF = (uReceive & hwr328UReceiveFIFOHalf) != 0;
+ state.DATA_READY = (uReceive & hwr328UReceiveDataRdy) != 0;
+// state.OLD_DATA = (uReceive & hwrEZ328UReceiveOldData) != 0; // 68EZ328 only
+ state.OVRUN = (uReceive & hwr328UReceiveOverrunErr) != 0;
+ state.FRAME_ERROR = (uReceive & hwr328UReceiveFrameErr) != 0;
+ state.BREAK = (uReceive & hwr328UReceiveBreakErr) != 0;
+ state.PARITY_ERROR = (uReceive & hwr328UReceiveParityErr) != 0;
+ state.RX_DATA = (uReceive & hwr328UReceiveData);
+
+ // Transmitter register bits
+ // We set everything except TX_DATA; the user sets that
+ // value and ONLY that value.
+
+ state.TX_FIFO_EMPTY = (uTransmit & hwr328UTransmitFIFOEmpty) != 0;
+ state.TX_FIFO_HALF = (uTransmit & hwr328UTransmitFIFOHalf) != 0;
+ state.TX_AVAIL = (uTransmit & hwr328UTransmitTxAvail) != 0;
+ state.SEND_BREAK = (uTransmit & hwr328UTransmitSendBreak) != 0;
+ state.IGNORE_CTS = (uTransmit & hwr328UTransmitIgnoreCTS) != 0;
+// state.BUSY = (uTransmit & hwrEZ328UTransmitBusy) != 0; // 68EZ328 only
+ state.CTS_STATUS = (uTransmit & hwr328UTransmitCTSStatus) != 0;
+ state.CTS_DELTA = (uTransmit & hwr328UTransmitCTSDelta) != 0;
+ state.TX_DATA = (uTransmit & hwr328UTransmitData);
+
+ // Misc register bits
+ // These are all values the user sets; we just look at them.
+
+// state.BAUD_TEST = (uMisc & hwrEZ328UMiscBaudTest) != 0; // 68EZ328 only
+ state.CLK_SRC = (uMisc & hwr328UMiscClkSrcGPIO) != 0;
+ state.FORCE_PERR = (uMisc & hwr328UMiscForceParityErr) != 0;
+ state.LOOP = (uMisc & hwr328UMiscLoopback) != 0;
+// state.BAUD_RESET = (uMisc & hwrEZ328UMiscBaudReset) != 0; // 68EZ328 only
+// state.IR_TEST = (uMisc & hwrEZ328UMiscIRTestEn) != 0; // 68EZ328 only
+ state.RTS_CONT = (uMisc & hwr328UMiscRTSThruFIFO) != 0;
+ state.RTS = (uMisc & hwr328UMiscRTSOut) != 0;
+ state.IRDA_ENABLE = (uMisc & hwr328UMiscIRDAEn) != 0;
+ state.IRDA_LOOP = (uMisc & hwr328UMiscLoopIRDA) != 0;
+// state.RX_POL = (uMisc & hwrEZ328UMiscRXPolarityInv) != 0; // 68EZ328 only
+// state.TX_POL = (uMisc & hwrEZ328UMiscTXPolarityInv) != 0; // 68EZ328 only
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::UnmarshalUARTState
+// ---------------------------------------------------------------------------
+
+void EmRegs328::UnmarshalUARTState (const EmUARTDragonball::State& state)
+{
+ uint16 uControl = 0;
+ uint16 uBaud = 0;
+ uint16 uReceive = 0;
+ uint16 uTransmit = 0;
+ uint16 uMisc = 0;
+
+ if (state.UART_ENABLE) uControl |= hwr328UControlUARTEnable;
+ if (state.RX_ENABLE) uControl |= hwr328UControlRxEnable;
+ if (state.TX_ENABLE) uControl |= hwr328UControlTxEnable;
+ if (state.RX_CLK_CONT) uControl |= hwr328UControlRxClock1x;
+ if (state.PARITY_EN) uControl |= hwr328UControlParityEn;
+ if (state.ODD_EVEN) uControl |= hwr328UControlParityOdd;
+ if (state.STOP_BITS) uControl |= hwr328UControlStopBits2;
+ if (state.CHAR8_7) uControl |= hwr328UControlDataBits8;
+ if (state.GPIO_DELTA_ENABLE)uControl |= hwr328UControlGPIODeltaEn; // 68328 only
+// if (state.OLD_ENABLE) uControl |= hwrEZ328UControlOldDataEn; // 68EZ328 only
+ if (state.CTS_DELTA_ENABLE) uControl |= hwr328UControlCTSDeltaEn;
+ if (state.RX_FULL_ENABLE) uControl |= hwr328UControlRxFullEn;
+ if (state.RX_HALF_ENABLE) uControl |= hwr328UControlRxHalfEn;
+ if (state.RX_RDY_ENABLE) uControl |= hwr328UControlRxRdyEn;
+ if (state.TX_EMPTY_ENABLE) uControl |= hwr328UControlTxEmptyEn;
+ if (state.TX_HALF_ENABLE) uControl |= hwr328UControlTxHalfEn;
+ if (state.TX_AVAIL_ENABLE) uControl |= hwr328UControlTxAvailEn;
+
+ // Baud control register bits
+ // These are all values the user sets; we just look at them.
+
+ if (state.GPIO_DELTA) uBaud |= hwr328UBaudGPIODelta; // 68328 only
+ if (state.GPIO) uBaud |= hwr328UBaudGPIOData; // 68328 only
+ if (state.GPIO_DIR) uBaud |= hwr328UBaudGPIODirOut; // 68328 only
+ if (state.GPIO_SRC) uBaud |= hwr328UBaudGPIOSrcBaudGen; // 68328 only
+// if (state.UCLK_DIR) uBaud |= hwrEZ328UBaudUCLKDirOut; // 68EZ328 only
+ if (state.BAUD_SRC) uBaud |= hwr328UBaudBaudSrcGPIO;
+
+ uBaud |= (state.DIVIDE << hwr328UBaudDivideBitOffset) & hwr328UBaudDivider;
+ uBaud |= (state.PRESCALER) & hwr328UBaudPrescaler;
+
+ // Receive register bits
+ // These are all input bits; we set them, not the user.
+
+ if (state.RX_FIFO_FULL) uReceive |= hwr328UReceiveFIFOFull;
+ if (state.RX_FIFO_HALF) uReceive |= hwr328UReceiveFIFOHalf;
+ if (state.DATA_READY) uReceive |= hwr328UReceiveDataRdy;
+// if (state.OLD_DATA) uReceive |= hwrEZ328UReceiveOldData; // 68EZ328 only
+ if (state.OVRUN) uReceive |= hwr328UReceiveOverrunErr;
+ if (state.FRAME_ERROR) uReceive |= hwr328UReceiveFrameErr;
+ if (state.BREAK) uReceive |= hwr328UReceiveBreakErr;
+ if (state.PARITY_ERROR) uReceive |= hwr328UReceiveParityErr;
+
+ uReceive |= (state.RX_DATA) & hwr328UReceiveData;
+
+ // Transmitter register bits
+ // We set everything except TX_DATA; the user sets that
+ // value and ONLY that value.
+
+ if (state.TX_FIFO_EMPTY) uTransmit |= hwr328UTransmitFIFOEmpty;
+ if (state.TX_FIFO_HALF) uTransmit |= hwr328UTransmitFIFOHalf;
+ if (state.TX_AVAIL) uTransmit |= hwr328UTransmitTxAvail;
+ if (state.SEND_BREAK) uTransmit |= hwr328UTransmitSendBreak;
+ if (state.IGNORE_CTS) uTransmit |= hwr328UTransmitIgnoreCTS;
+// if (state.BUSY) uTransmit |= hwrEZ328UTransmitBusy; // 68EZ328 only
+ if (state.CTS_STATUS) uTransmit |= hwr328UTransmitCTSStatus;
+ if (state.CTS_DELTA) uTransmit |= hwr328UTransmitCTSDelta;
+
+ uTransmit |= (state.TX_DATA) & hwr328UTransmitData;
+
+ // Misc register bits
+ // These are all values the user sets; we just look at them.
+
+// if (state.BAUD_TEST) uMisc |= hwrEZ328UMiscBaudTest; // 68EZ328 only
+ if (state.CLK_SRC) uMisc |= hwr328UMiscClkSrcGPIO;
+ if (state.FORCE_PERR) uMisc |= hwr328UMiscForceParityErr;
+ if (state.LOOP) uMisc |= hwr328UMiscLoopback;
+// if (state.BAUD_RESET) uMisc |= hwrEZ328UMiscBaudReset; // 68EZ328 only
+// if (state.IR_TEST) uMisc |= hwrEZ328UMiscIRTestEn; // 68EZ328 only
+ if (state.RTS_CONT) uMisc |= hwr328UMiscRTSThruFIFO;
+ if (state.RTS) uMisc |= hwr328UMiscRTSOut;
+ if (state.IRDA_ENABLE) uMisc |= hwr328UMiscIRDAEn;
+ if (state.IRDA_LOOP) uMisc |= hwr328UMiscLoopIRDA;
+// if (state.RX_POL) uMisc |= hwrEZ328UMiscRXPolarityInv; // 68EZ328 only
+// if (state.TX_POL) uMisc |= hwrEZ328UMiscTXPolarityInv; // 68EZ328 only
+
+ WRITE_REGISTER (uControl, uControl);
+ WRITE_REGISTER (uBaud, uBaud);
+ WRITE_REGISTER (uReceive, uReceive);
+ WRITE_REGISTER (uTransmit, uTransmit);
+ WRITE_REGISTER (uMisc, uMisc);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::GetPort
+// ---------------------------------------------------------------------------
+// Given an address, return a value indicating what port it is associated with.
+
+int EmRegs328::GetPort (emuptr address)
+{
+ const long MASK = 0x00000FF8;
+
+ switch (address & MASK)
+ {
+ case 0x0400: return 'A';
+ case 0x0408: return 'B';
+ case 0x0410: return 'C';
+ case 0x0418: return 'D';
+ case 0x0420: return 'E';
+ case 0x0428: return 'F';
+ case 0x0430: return 'G';
+ case 0x0438: return 'J';
+ case 0x0440: return 'K';
+ case 0x0448: return 'M';
+ }
+
+ EmAssert (false);
+ return 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328::PrvGetPalette
+// ---------------------------------------------------------------------------
+
+void EmRegs328::PrvGetPalette (RGBList& thePalette)
+{
+ // !!! TBD
+ Preference<RGBType> pref1 (kPrefKeyBackgroundColor);
+ Preference<RGBType> pref2 (kPrefKeyHighlightColor);
+
+ RGBType foreground (0, 0, 0);
+ RGBType background;
+
+ if (this->GetLCDBacklightOn ())
+ {
+ if (pref2.Loaded ())
+ background = *pref2;
+ else
+ background = ::SkinGetHighlightColor ();
+ }
+ else
+ {
+ if (pref1.Loaded ())
+ background = *pref1;
+ else
+ background = ::SkinGetBackgroundColor ();
+ }
+
+ long br = ((long) background.fRed);
+ long bg = ((long) background.fGreen);
+ long bb = ((long) background.fBlue);
+
+ long dr = ((long) foreground.fRed) - ((long) background.fRed);
+ long dg = ((long) foreground.fGreen) - ((long) background.fGreen);
+ long db = ((long) foreground.fBlue) - ((long) background.fBlue);
+
+ int32 bpp = 1 << (READ_REGISTER (lcdPanelControl) & 0x01);
+ int32 numColors = 1 << bpp;
+ thePalette.resize (numColors);
+
+ for (int color = 0; color < numColors; ++color)
+ {
+ thePalette[color].fRed = (UInt8) (br + dr * color / (numColors - 1));
+ thePalette[color].fGreen = (UInt8) (bg + dg * color / (numColors - 1));
+ thePalette[color].fBlue = (UInt8) (bb + db * color / (numColors - 1));
+ }
+}
+
+
diff --git a/SrcShared/Hardware/EmRegs328.h b/SrcShared/Hardware/EmRegs328.h
new file mode 100644
index 0000000..2ea7011
--- /dev/null
+++ b/SrcShared/Hardware/EmRegs328.h
@@ -0,0 +1,146 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegs328_h
+#define EmRegs328_h
+
+#include "EmHAL.h" // EmHALHandler
+#include "EmRegs.h" // EmRegs
+#include "EmStructs.h" // RGBList
+#include "EmUARTDragonball.h" // EmUARTDragonball::State
+
+class EmScreenUpdateInfo;
+
+
+class EmRegs328 : public EmRegs, public EmHALHandler
+{
+ public:
+ EmRegs328 (void);
+ virtual ~EmRegs328 (void);
+
+ // EmRegs overrides
+ virtual void Initialize (void);
+ virtual void Reset (Bool hardwareReset);
+ virtual void Save (SessionFile&);
+ virtual void Load (SessionFile&);
+ virtual void Dispose (void);
+
+ virtual void SetSubBankHandlers (void);
+ virtual uint8* GetRealAddress (emuptr address);
+ virtual emuptr GetAddressStart (void);
+ virtual uint32 GetAddressRange (void);
+
+ // EmHALHandler overrides
+ virtual void Cycle (Bool sleeping);
+ virtual void CycleSlowly (Bool sleeping);
+
+ virtual void ButtonEvent (SkinElementType, Bool buttonIsDown);
+ virtual void TurnSoundOff (void);
+ virtual void ResetTimer (void);
+ virtual void ResetRTC (void);
+
+ virtual int32 GetInterruptLevel (void);
+ virtual int32 GetInterruptBase (void);
+
+ virtual Bool GetLCDScreenOn (void) = 0;
+ virtual Bool GetLCDBacklightOn (void) = 0;
+ virtual Bool GetLCDHasFrame (void);
+ virtual void GetLCDBeginEnd (emuptr&, emuptr&);
+ virtual void GetLCDScanlines (EmScreenUpdateInfo& info);
+
+ virtual EmUARTDeviceType GetUARTDevice (int uartNum);
+ virtual int32 GetDynamicHeapSize (void);
+ virtual int32 GetROMSize (void);
+ virtual emuptr GetROMBaseAddress (void);
+ virtual Bool ChipSelectsConfigured (void);
+ virtual int32 GetSystemClockFrequency (void);
+ virtual Bool GetCanStop (void);
+ virtual Bool GetAsleep (void);
+
+ virtual uint8 GetPortInputValue (int);
+ virtual uint8 GetPortInternalValue (int);
+ virtual void PortDataChanged (int, uint8, uint8);
+
+ private:
+ uint32 pllFreqSelRead (emuptr address, int size);
+ uint32 portXDataRead (emuptr address, int size);
+ uint32 tmr1StatusRead (emuptr address, int size);
+ uint32 tmr2StatusRead (emuptr address, int size);
+ uint32 uartRead (emuptr address, int size);
+ uint32 rtcHourMinSecRead (emuptr address, int size);
+
+ void csASelect1Write (emuptr address, int size, uint32 value);
+ void csCSelect0Write (emuptr address, int size, uint32 value);
+ void csCSelect1Write (emuptr address, int size, uint32 value);
+ void intMaskHiWrite (emuptr address, int size, uint32 value);
+ void intMaskLoWrite (emuptr address, int size, uint32 value);
+ void intStatusHiWrite (emuptr address, int size, uint32 value);
+ void portXDataWrite (emuptr address, int size, uint32 value);
+ void portDIntReqEnWrite (emuptr address, int size, uint32 value);
+ void tmr1StatusWrite (emuptr address, int size, uint32 value);
+ void tmr2StatusWrite (emuptr address, int size, uint32 value);
+ void wdCounterWrite (emuptr address, int size, uint32 value);
+ void spiMasterControlWrite (emuptr address, int size, uint32 value);
+ void uartWrite (emuptr address, int size, uint32 value);
+ void lcdRegisterWrite (emuptr address, int size, uint32 value);
+ void rtcControlWrite (emuptr address, int size, uint32 value);
+ void rtcIntStatusWrite (emuptr address, int size, uint32 value);
+ void rtcIntEnableWrite (emuptr address, int size, uint32 value);
+
+ protected:
+ void HotSyncEvent (Bool buttonIsDown);
+
+ virtual uint8 GetKeyBits (void);
+ virtual uint16 ButtonToBits (SkinElementType);
+
+ protected:
+ void UpdateInterrupts (void);
+ void UpdatePortDInterrupts (void);
+ void UpdateRTCInterrupts (void);
+
+ protected:
+ Bool IDDetectAsserted (void);
+ UInt8 GetHardwareID (void);
+
+ protected:
+ void UARTStateChanged (Bool sendTxData);
+ void UpdateUARTState (Bool refreshRxData);
+ void UpdateUARTInterrupts (const EmUARTDragonball::State& state);
+ void MarshalUARTState (EmUARTDragonball::State& state);
+ void UnmarshalUARTState (const EmUARTDragonball::State& state);
+
+ protected:
+ int GetPort (emuptr address);
+ void PrvGetPalette (RGBList& thePalette);
+
+ protected:
+ HwrM68328Type f68328Regs;
+ bool fHotSyncButtonDown;
+ uint32 fTmr2CurrentMilliseconds;
+ uint32 fTmr2StartMilliseconds;
+ uint16 fKeyBits;
+ uint16 fLastTmr1Status;
+ uint16 fLastTmr2Status;
+ uint8 fPortDEdge;
+ uint32 fPortDDataCount;
+
+ uint32 fHour;
+ uint32 fMin;
+ uint32 fSec;
+ uint32 fTick;
+ uint32 fCycle;
+
+ EmUARTDragonball* fUART;
+};
+
+#endif /* EmRegs328_h */
diff --git a/SrcShared/Hardware/EmRegs328PalmIII.h b/SrcShared/Hardware/EmRegs328PalmIII.h
new file mode 100644
index 0000000..67e39b0
--- /dev/null
+++ b/SrcShared/Hardware/EmRegs328PalmIII.h
@@ -0,0 +1,21 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegs328PalmIII_h
+#define EmRegs328PalmIII_h
+
+#include "EmRegs328PalmPilot.h" // EmRegs328PalmPilot
+
+typedef EmRegs328PalmPilot EmRegs328PalmIII;
+
+#endif /* EmRegs328PalmIII_h */
diff --git a/SrcShared/Hardware/EmRegs328PalmPilot.cpp b/SrcShared/Hardware/EmRegs328PalmPilot.cpp
new file mode 100644
index 0000000..25ce276
--- /dev/null
+++ b/SrcShared/Hardware/EmRegs328PalmPilot.cpp
@@ -0,0 +1,82 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmRegs328PalmPilot.h"
+#include "EmRegs328Prv.h"
+
+#include "PalmPack.h"
+#define NON_PORTABLE
+ #include "328Jerry/IncsPrv/HardwareTD1.h" // hwrTD1PortFLCDEnableOn, etc.
+#undef NON_PORTABLE
+#include "PalmPackPop.h"
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328PalmPilot::GetLCDScreenOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegs328PalmPilot::GetLCDScreenOn (void)
+{
+ return (READ_REGISTER (portFData) & hwrTD1PortFLCDEnableOn) != 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328PalmPilot::GetLCDBacklightOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegs328PalmPilot::GetLCDBacklightOn (void)
+{
+ return (READ_REGISTER (portGData) & hwrTD1PortGBacklightOn) != 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328PalmPilot::GetLineDriverState
+// ---------------------------------------------------------------------------
+// Return whether or not the line drivers for the given object are open or
+// closed.
+
+Bool EmRegs328PalmPilot::GetLineDriverState (EmUARTDeviceType type)
+{
+ if (type == kUARTSerial)
+ return (READ_REGISTER (portGData) & hwrTD1PortGSerialOn) != 0;
+
+ if (type == kUARTIR)
+ return (READ_REGISTER (portJData) & hwrTD1PortJIrOn) == 0;
+
+ return false;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328PalmPilot::GetPortInputValue
+// ---------------------------------------------------------------------------
+// Return the GPIO values for the pins on the port. These values are used
+// if the select pins are high.
+
+uint8 EmRegs328PalmPilot::GetPortInputValue (int port)
+{
+ uint8 result = EmRegs328::GetPortInputValue (port);
+
+ if (port == 'M')
+ {
+ // Ensure that bit hwrTD1PortMDockIn is set. If it's clear, HotSync
+ // will sync via the modem instead of the serial port.
+
+ result |= hwrTD1PortMDockIn;
+ }
+
+ return result;
+}
diff --git a/SrcShared/Hardware/EmRegs328PalmPilot.h b/SrcShared/Hardware/EmRegs328PalmPilot.h
new file mode 100644
index 0000000..00d2e75
--- /dev/null
+++ b/SrcShared/Hardware/EmRegs328PalmPilot.h
@@ -0,0 +1,30 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegs328PalmPilot_h
+#define EmRegs328PalmPilot_h
+
+#include "EmRegs328.h" // EmRegs328
+
+
+class EmRegs328PalmPilot : public EmRegs328
+{
+ public:
+ virtual Bool GetLCDScreenOn (void);
+ virtual Bool GetLCDBacklightOn (void);
+ virtual Bool GetLineDriverState (EmUARTDeviceType);
+
+ virtual uint8 GetPortInputValue (int);
+};
+
+#endif /* EmRegs328PalmPilot_h */
diff --git a/SrcShared/Hardware/EmRegs328PalmVII.h b/SrcShared/Hardware/EmRegs328PalmVII.h
new file mode 100644
index 0000000..4763967
--- /dev/null
+++ b/SrcShared/Hardware/EmRegs328PalmVII.h
@@ -0,0 +1,21 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegs328PalmVII_h
+#define EmRegs328PalmVII_h
+
+#include "EmRegs328PalmPilot.h" // EmRegs328PalmPilot
+
+typedef EmRegs328PalmPilot EmRegs328PalmVII;
+
+#endif /* EmRegs328PalmVII_h */
diff --git a/SrcShared/Hardware/EmRegs328Pilot.h b/SrcShared/Hardware/EmRegs328Pilot.h
new file mode 100644
index 0000000..d380978
--- /dev/null
+++ b/SrcShared/Hardware/EmRegs328Pilot.h
@@ -0,0 +1,21 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegs328Pilot_h
+#define EmRegs328Pilot_h
+
+#include "EmRegs328PalmPilot.h" // EmRegs328PalmPilot
+
+typedef EmRegs328PalmPilot EmRegs328Pilot;
+
+#endif /* EmRegs328Pilot_h */
diff --git a/SrcShared/Hardware/EmRegs328Prv.h b/SrcShared/Hardware/EmRegs328Prv.h
new file mode 100644
index 0000000..8b09f33
--- /dev/null
+++ b/SrcShared/Hardware/EmRegs328Prv.h
@@ -0,0 +1,45 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegs328Prv_h
+#define EmRegs328Prv_h
+
+#include "EmRegsPrv.h"
+
+// Location and range of registers
+
+const uint32 kMemoryStart = 0xFFFFF000;
+const uint32 kMemorySize = sizeof (HwrM68328Type);
+
+
+// Macro to return the Dragonball address of the specified register
+
+#define addressof(x) (kMemoryStart + offsetof(HwrM68328Type, x))
+
+
+// Macros for reading/writing Dragonball registers.
+
+#define READ_REGISTER(reg) \
+ _get_reg (&f68328Regs.reg)
+
+#define WRITE_REGISTER(reg, value) \
+ _put_reg (&f68328Regs.reg, value)
+
+
+// Macro for installing Dragonball register handlers
+
+#define INSTALL_HANDLER(read, write, reg) \
+ this->SetHandler ((ReadFunction) &EmRegs328::read, (WriteFunction) &EmRegs328::write, addressof (reg), sizeof (f68328Regs.reg))
+
+
+#endif /* EmRegs328Prv_h */
diff --git a/SrcShared/Hardware/EmRegs328Symbol1700.cpp b/SrcShared/Hardware/EmRegs328Symbol1700.cpp
new file mode 100644
index 0000000..0b5a305
--- /dev/null
+++ b/SrcShared/Hardware/EmRegs328Symbol1700.cpp
@@ -0,0 +1,121 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmRegs328Symbol1700.h"
+#include "EmRegs328Prv.h"
+
+#define keyBitTrigLeft 0x0400
+#define keyBitTrigCenter 0x0800
+#define keyBitTrigRight 0x1000
+#define keyBitPageUpLeft keyBitPageUp
+#define keyBitPageUpRight keyBitPageDown
+#define keyBitPageDownLeft 0x2000
+#define keyBitPageDownRight 0x4000
+
+
+#define keyBitMask 0x0F // Which bits in port D we use for keys
+
+#define portDKbdCols 0xF0
+#define portDKbdRows 0x0F
+
+#define portDKbdCol0 0x10
+#define portDKbdCol1 0x20
+#define portDKbdCol2 0x40
+#define portDKbdCol3 0x80
+
+#define portDKbdRow0 0x01
+#define portDKbdRow1 0x02
+#define portDKbdRow2 0x04
+#define portDKbdRow3 0x08
+
+
+const int kNumButtonRows = 4;
+const int kNumButtonCols = 4;
+
+const uint16 kButtonMap[kNumButtonRows][kNumButtonCols] =
+{
+ { keyBitPower, keyBitTrigLeft, keyBitTrigCenter, keyBitTrigRight },
+ { keyBitHard1, keyBitHard2, keyBitHard3, keyBitHard4 },
+ { keyBitPageUpLeft, keyBitPageUpRight, keyBitPageDownLeft, keyBitPageDownRight },
+ { keyBitContrast, 0, 0, 0 }
+};
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328Symbol1700::GetKeyBits
+// ---------------------------------------------------------------------------
+
+uint8 EmRegs328Symbol1700::GetKeyBits (void)
+{
+ uint8 portDData = READ_REGISTER (portDData);
+
+ Bool cols[4];
+ cols[0] = (portDData & portDKbdCol0) == 0;
+ cols[1] = (portDData & portDKbdCol1) == 0;
+ cols[2] = (portDData & portDKbdCol2) == 0;
+ cols[3] = (portDData & portDKbdCol3) == 0;
+
+ uint8 keyData = 0;
+
+ // Walk the columns, looking for one that is requested.
+
+ for (int col = 0; col < kNumButtonCols; ++col)
+ {
+ if (cols[col])
+ {
+ // Walk the rows.
+
+ for (int row = 0; row < kNumButtonRows; ++row)
+ {
+ // Get the key corresponding to this row and column.
+ // If we've recorded (in fgKeyBits) that this key is
+ // pressed, then set its row bit.
+
+ if ((fKeyBits & kButtonMap[row][col]) != 0)
+ {
+ keyData |= 1 << (col + 4);
+ keyData |= 1 << row;
+ }
+ }
+ }
+ }
+
+ return keyData;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs328Symbol1700::ButtonToBits
+// ---------------------------------------------------------------------------
+
+uint16 EmRegs328Symbol1700::ButtonToBits (SkinElementType button)
+{
+ uint16 bitNumber = 0;
+ switch (button)
+ {
+ default:
+ bitNumber = EmRegs328PalmPilot::ButtonToBits (button);
+ break;
+
+ case kElement_TriggerLeft: bitNumber = keyBitTrigLeft; break;
+ case kElement_TriggerCenter: bitNumber = keyBitTrigCenter; break;
+ case kElement_TriggerRight: bitNumber = keyBitTrigRight; break;
+ case kElement_UpButtonLeft: bitNumber = keyBitPageUpLeft; break;
+ case kElement_UpButtonRight: bitNumber = keyBitPageUpRight; break;
+ case kElement_DownButtonLeft: bitNumber = keyBitPageDownLeft; break;
+ case kElement_DownButtonRight: bitNumber = keyBitPageDownRight; break;
+ }
+
+ return bitNumber;
+}
diff --git a/SrcShared/Hardware/EmRegs328Symbol1700.h b/SrcShared/Hardware/EmRegs328Symbol1700.h
new file mode 100644
index 0000000..8690c80
--- /dev/null
+++ b/SrcShared/Hardware/EmRegs328Symbol1700.h
@@ -0,0 +1,26 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegs328Symbol1700_h
+#define EmRegs328Symbol1700_h
+
+#include "EmRegs328PalmPilot.h" // EmRegs328PalmPilot
+
+class EmRegs328Symbol1700 : public EmRegs328PalmPilot
+{
+ public:
+ virtual uint8 GetKeyBits (void);
+ virtual uint16 ButtonToBits (SkinElementType);
+};
+
+#endif /* EmRegs328Symbol1700_h */
diff --git a/SrcShared/Hardware/EmRegsASICSymbol1700.cpp b/SrcShared/Hardware/EmRegsASICSymbol1700.cpp
new file mode 100644
index 0000000..ff2ab2f
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsASICSymbol1700.cpp
@@ -0,0 +1,168 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmRegsASICSymbol1700.h"
+
+// Given a register (specified by its field name), return its address
+// in emulated space.
+
+#define addressof(reg) \
+ (this->GetAddressStart () + fRegs.offsetof_##reg ())
+
+
+// Macro to help the installation of handlers for a register.
+
+#define INSTALL_HANDLER(read, write, reg) \
+ this->SetHandler ( (ReadFunction) &EmRegsASICSymbol1700::read, \
+ (WriteFunction) &EmRegsASICSymbol1700::write, \
+ addressof (reg), \
+ fRegs.reg.GetSize ())
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsASICSymbol1700::EmRegsASICSymbol1700
+// ---------------------------------------------------------------------------
+
+EmRegsASICSymbol1700::EmRegsASICSymbol1700 (void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsASICSymbol1700::~EmRegsASICSymbol1700
+// ---------------------------------------------------------------------------
+
+EmRegsASICSymbol1700::~EmRegsASICSymbol1700 (void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsASICSymbol1700::Initialize
+// ---------------------------------------------------------------------------
+
+void EmRegsASICSymbol1700::Initialize (void)
+{
+ EmRegs::Initialize ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsASICSymbol1700::Reset
+// ---------------------------------------------------------------------------
+
+void EmRegsASICSymbol1700::Reset (Bool hardwareReset)
+{
+ EmRegs::Reset (hardwareReset);
+
+ memset (fRegs.GetPtr (), 0, fRegs.GetSize ());
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsASICSymbol1700::Save
+// ---------------------------------------------------------------------------
+
+void EmRegsASICSymbol1700::Save (SessionFile& f)
+{
+ EmRegs::Save (f);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsASICSymbol1700::Load
+// ---------------------------------------------------------------------------
+
+void EmRegsASICSymbol1700::Load (SessionFile& f)
+{
+ EmRegs::Load (f);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsASICSymbol1700::Dispose
+// ---------------------------------------------------------------------------
+
+void EmRegsASICSymbol1700::Dispose (void)
+{
+ EmRegs::Dispose ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsASICSymbol1700::SetSubBankHandlers
+// ---------------------------------------------------------------------------
+
+void EmRegsASICSymbol1700::SetSubBankHandlers (void)
+{
+ // Install base handlers.
+
+ EmRegs::SetSubBankHandlers ();
+
+ // Now add standard/specialized handers for the defined registers.
+
+ // Install the first three by hand instead of using our
+ // INSTALL_HANDLER macro. That macro doesn't support the
+ // installation of a field that's an array.
+ this->SetHandler ( (ReadFunction) &EmRegsASICSymbol1700::StdReadBE, \
+ (WriteFunction) &EmRegsASICSymbol1700::StdWriteBE, \
+ addressof (S24IO), \
+ 64);
+ this->SetHandler ( (ReadFunction) &EmRegsASICSymbol1700::StdReadBE, \
+ (WriteFunction) &EmRegsASICSymbol1700::StdWriteBE, \
+ addressof (S24Attribute), \
+ 32);
+ this->SetHandler ( (ReadFunction) &EmRegsASICSymbol1700::StdReadBE, \
+ (WriteFunction) &EmRegsASICSymbol1700::StdWriteBE, \
+ addressof (UART8251MacroSelect),\
+ 4);
+
+// INSTALL_HANDLER (StdReadBE, StdWriteBE, S24IO);
+// INSTALL_HANDLER (StdReadBE, StdWriteBE, S24Attribute);
+// INSTALL_HANDLER (StdReadBE, StdWriteBE, UART8251MacroSelect);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, ScannerDecoderControl);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, Control);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, GPIOData);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, GPIODirection);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsASICSymbol1700::GetRealAddress
+// ---------------------------------------------------------------------------
+
+uint8* EmRegsASICSymbol1700::GetRealAddress (emuptr address)
+{
+ return (uint8*) fRegs.GetPtr () + address - this->GetAddressStart ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsASICSymbol1700::GetAddressStart
+// ---------------------------------------------------------------------------
+
+emuptr EmRegsASICSymbol1700::GetAddressStart (void)
+{
+ return 0x11000000;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsASICSymbol1700::GetAddressRange
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsASICSymbol1700::GetAddressRange (void)
+{
+ return fRegs.GetSize ();
+}
diff --git a/SrcShared/Hardware/EmRegsASICSymbol1700.h b/SrcShared/Hardware/EmRegsASICSymbol1700.h
new file mode 100644
index 0000000..6b15d33
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsASICSymbol1700.h
@@ -0,0 +1,44 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegsASICSymbol1700_h
+#define EmRegsASICSymbol1700_h
+
+#include "EmPalmStructs.h"
+#include "EmRegs.h"
+
+class SessionFile;
+
+
+class EmRegsASICSymbol1700 : public EmRegs
+{
+ public:
+ EmRegsASICSymbol1700 (void);
+ virtual ~EmRegsASICSymbol1700 (void);
+
+ virtual void Initialize (void);
+ virtual void Reset (Bool hardwareReset);
+ virtual void Save (SessionFile&);
+ virtual void Load (SessionFile&);
+ virtual void Dispose (void);
+
+ virtual void SetSubBankHandlers (void);
+ virtual uint8* GetRealAddress (emuptr address);
+ virtual emuptr GetAddressStart (void);
+ virtual uint32 GetAddressRange (void);
+
+ private:
+ EmProxyHwrSymbolASICType fRegs;
+};
+
+#endif /* EmRegsASICSymbol1700_h */
diff --git a/SrcShared/Hardware/EmRegsEZ.cpp b/SrcShared/Hardware/EmRegsEZ.cpp
new file mode 100644
index 0000000..f56144d
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsEZ.cpp
@@ -0,0 +1,2655 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmRegsEZ.h"
+#include "EmRegsEZPrv.h"
+
+#include "Byteswapping.h" // Canonical
+#include "EmHAL.h" // EmHAL
+#include "EmMemory.h" // gMemAccessFlags, EmMem_memcpy
+#include "EmPixMap.h" // SetSize, SetRowBytes, etc.
+#include "EmScreen.h" // EmScreenUpdateInfo
+#include "EmSession.h" // GetDevice
+#include "EmSPISlave.h" // DoExchange
+#include "Hordes.h" // Hordes::IsOn
+#include "Logging.h" // LogAppendMsg
+#include "Miscellaneous.h" // GetHostTime
+#include "PreferenceMgr.h" // Preference
+#include "SessionFile.h" // WriteHwrDBallEZType, etc.
+#include "UAE.h" // regs, SPCFLAG_INT
+
+#include "PalmPack.h"
+#define NON_PORTABLE
+ #include "HwrMiscFlags.h" // hwrMiscFlagID1
+
+ #define hwrEZ328maskID1J83G 0x05
+
+ // Some platform-specific -- yet fairly portable -- defines.
+ #define hwrEZPortGIDDetect 0x04 // (L) ID select (drives kbd)
+ #define hwrEZPortDKbdCol0 0x01 // (H) Keyboard Column 0 (aka INT0)
+ #define hwrEZPortDKbdCol1 0x02 // (H) Keyboard Column 1 (aka INT1)
+ #define hwrEZPortDKbdCol2 0x04 // (H) Keyboard Column 2 (aka INT2)
+ #define hwrEZPortDKbdCol3 0x08 // (H) Keyboard Column 3 (aka INT3)
+ #define hwrEZPortDKeyBits 0x0F // (H) All Keyboard Columns
+
+#undef NON_PORTABLE
+#include "PalmPackPop.h"
+
+static const uint16 UPSIZ = 0x1800; // Mask to get the unprotected memory size from csDSelect.
+static const uint16 SIZ = 0x000E; // Mask to get the memory size from csASelect.
+static const uint16 EN = 0x0001; // Mask to get the enable bit from csASelect.
+
+static const uint16 gBaseAddressShift = 13; // Shift to get base address from CSGBx register value
+
+#define PRINTF if (1) ; else LogAppendMsg
+
+// Values used to initialize the DragonBallEZ registers.
+
+static const HwrM68EZ328Type kInitial68EZ328RegisterValues =
+{
+ 0x1C, // Byte scr; // $000: System Control Register
+ { 0 }, // Byte ___filler0[0x004-0x001];
+ hwrEZ328chipIDEZ, // Byte chipID; // $004: Chip ID Register
+ hwrEZ328maskID1J83G, // Byte maskID; // $005: Mask ID Register
+ 0x00, // Word swID; // $006: Software ID Register
+ { 0 }, // Byte ___filler1[0x100-0x008];
+
+ 0x0000, // Word csAGroupBase; // $100: Chip Select Group A Base Register
+ 0x0000, // Word csBGroupBase; // $102: Chip Select Group B Base Register
+ 0x0000, // Word csCGroupBase; // $104: Chip Select Group C Base Register
+ 0x0000, // Word csDGroupBase; // $106: Chip Select Group D Base Register
+
+ { 0 }, // Byte ___filler6[0x110-0x108];
+
+ 0x00E0, // Word csASelect; // $110: Group A Chip Select Register
+ 0x0000, // Word csBSelect; // $112: Group B Chip Select Register
+ 0x0000, // Word csCSelect; // $114: Group C Chip Select Register
+ 0x0000, // Word csDSelect; // $116: Group D Chip Select Register
+
+ 0x0060, // Word emuCS; // $118: EMU Chip Select Register
+
+ { 0 }, // Byte ___filler2[0x200-0x11A];
+
+ 0x2430, // Word pllControl; // $200: PLL Control Register
+ 0x0123, // Word pllFreqSel; // $202: PLL Frequency Select Register
+ 0, // !!! ---> Marked as reserved in 1.4 Word pllTest; // $204: PLL Test Register (do not access)
+ { 0 }, // Byte ___filler44;
+ 0x1F, // Byte pwrControl; // $207: Power Control Register
+
+ { 0 }, // Byte ___filler3[0x300-0x208];
+
+ 0x00, // Byte intVector; // $300: Interrupt Vector Register
+ { 0 }, // Byte ___filler4;
+ 0x0000, // Word intControl; // $302: Interrupt Control Register
+ 0x00FF, // Word intMaskHi; // $304: Interrupt Mask Register/HIGH word
+ 0xFFFF, // Word intMaskLo; // $306: Interrupt Mask Register/LOW word
+ { 0 }, // Byte ___filler7[0x30c-0x308];
+ 0x0000, // Word intStatusHi; // $30C: Interrupt Status Register/HIGH word
+ 0x0000, // Word intStatusLo; // $30E: Interrupt Status Register/LOW word
+ 0x0000, // Word intPendingHi; // $310: Interrupt Pending Register
+ 0x0000, // Word intPendingLo; // $312: Interrupt Pending Register
+
+ { 0 }, // Byte ___filler4a[0x400-0x314];
+
+ 0x00, // Byte portADir; // $400: Port A Direction Register
+ 0x00, // Byte portAData; // $401: Port A Data Register
+ 0xFF, // Byte portAPullupEn; // $402: Port A Pullup Enable (similar to Select on DB)
+ { 0 }, // Byte ___filler8[5];
+
+ 0x00, // Byte portBDir; // $408: Port B Direction Register
+ 0x00, // Byte portBData; // $409: Port B Data Register
+ 0xFF, // Byte portBPullupEn; // $40A: Port B Pullup Enable
+ 0xFF, // Byte portBSelect; // $40B: Port B Select Register
+
+ { 0 }, // Byte ___filler9[4];
+
+ 0x00, // Byte portCDir; // $410: Port C Direction Register
+ 0x00, // Byte portCData; // $411: Port C Data Register
+ 0xFF, // Byte portCPulldnEn; // $412: Port C Pulldown Enable
+ 0xFF, // Byte portCSelect; // $413: Port C Select Register
+
+ { 0 }, // Byte ___filler10[4];
+
+ 0x00, // Byte portDDir; // $418: Port D Direction Register
+ 0x00, // Byte portDData; // $419: Port D Data Register
+ 0xFF, // Byte portDPullupEn; // $41A: Port D Pull-up Enable
+ 0xF0, // Byte portDSelect; // $41B: Port D Select Register
+ 0x00, // Byte portDPolarity; // $41C: Port D Polarity Register
+ 0x00, // Byte portDIntReqEn; // $41D: Port D Interrupt Request Enable
+ 0x00, // Byte portDKbdIntEn; // $41E: Port D Keyboard Interrupt Enable
+ 0x00, // Byte portDIntEdge; // $41F: Port D IRQ Edge Register
+
+ 0x00, // Byte portEDir; // $420: Port E Direction Register
+ 0x00, // Byte portEData; // $421: Port E Data Register
+ 0xFF, // Byte portEPullupEn; // $422: Port E Pull-up Enable
+ 0xFF, // Byte portESelect; // $423: Port E Select Register
+
+ { 0 }, // Byte ___filler14[4];
+
+ 0x00, // Byte portFDir; // $428: Port F Direction Register
+ 0x00, // Byte portFData; // $429: Port F Data Register
+ 0xFF, // Byte portFPullupdnEn; // $42A: Port F Pull-up/down Enable
+ 0x00, // Byte portFSelect; // $42B: Port F Select Register
+
+ { 0 }, // Byte ___filler16[4];
+
+ 0x00, // Byte portGDir; // $430: Port G Direction Register
+ 0x00, // Byte portGData; // $431: Port G Data Register
+ 0x3D, // Byte portGPullupEn; // $432: Port G Pull-up Enable
+ 0x08, // Byte portGSelect; // $433: Port G Select Register
+
+ { 0 }, // Byte ___filler2000[0x500-0x434];
+
+ 0x0020, // Word pwmControl; // $500: PWM Control Register
+ 0x00, // Byte pwmSampleHi; // $502: PWM Sample - high byte
+ 0x00, // Byte pwmSampleLo; // $503: PWM Sample - low byte
+ 0xFE, // Byte pwmPeriod; // $504: PWM Period
+ 0x00, // Byte pwmCounter; // $505: PWM Counter
+
+ { 0 }, // Byte ___filler24[0x600-0x506];
+
+ 0x0000, // Word tmr1Control; // $600: Timer 1 Control Register
+ 0x0000, // Word tmr1Prescaler; // $602: Timer 1 Prescaler Register
+ 0xFFFF, // Word tmr1Compare; // $604: Timer 1 Compare Register
+ 0x0000, // Word tmr1Capture; // $606: Timer 1 Capture Register
+ 0x0000, // Word tmr1Counter; // $608: Timer 1 Counter Register
+ 0x0000, // Word tmr1Status; // $60A: Timer 1 Status Register
+
+ { 0 }, // Byte ___filler25[0x800-0x61E];
+
+ 0x0000, // Word spiMasterData; // $800: SPI Master Data Register
+ 0x0000, // Word spiMasterControl; // $802: SPI Master Control Register
+
+ { 0 }, // Byte ___filler27[0x900-0x804];
+
+ 0x0000, // Word uControl; // $900: Uart Control Register
+ 0x003F, // Word uBaud; // $902: Uart Baud Control Register
+ 0x0000, // Word uReceive; // $904: Uart Receive Register
+ 0x0000, // Word uTransmit; // $906: Uart Transmit Register
+ 0x0000, // Word uMisc; // $908: Uart Miscellaneous Register
+ 0x0000, // Word uNonIntPresc; // $90A: Uart IRDA Non-Integer Prescaler
+
+ { 0 }, // Byte ___filler28[0xA00-0x90C];
+
+ 0x00000000, // DWord lcdStartAddr; // $A00: Screen Starting Address Register
+ { 0 }, // Byte ___filler29;
+ 0xFF, // Byte lcdPageWidth; // $A05: Virtual Page Width Register
+ { 0 }, // Byte ___filler30[2];
+ 0x03FF, // Word lcdScreenWidth; // $A08: Screen Width Register
+ 0x01FF, // Word lcdScreenHeight; // $A0A: Screen Height Register
+ { 0 }, // Byte ___filler31[0xA18-0xA0C];
+ 0x0000, // Word lcdCursorXPos; // $A18: Cursor X Position
+ 0x0000, // Word lcdCursorYPos; // $A1A: Cursor Y Position
+ 0x0101, // Word lcdCursorWidthHeight; // $A1C: Cursor Width and Height
+ { 0 }, // Byte ___filler32;
+ 0x7F, // Byte lcdBlinkControl; // $A1F: Blink Control Register
+ 0x00, // Byte lcdPanelControl; // $A20: Panel Interface Control Register
+ 0x00, // Byte lcdPolarity; // $A21: Polarity Config Register
+ { 0 }, // Byte ___filler33;
+ 0x00, // Byte lcdACDRate; // $A23: ACD (M) Rate Control Register
+ { 0 }, // Byte ___filler34;
+ 0x00, // Byte lcdPixelClock; // $A25: Pixel Clock Divider Register
+ { 0 }, // Byte ___filler35;
+ 0x40, // Byte lcdClockControl; // $A27: Clocking Control Register
+ { 0 }, // Byte ___filler36;
+ 0xFF, // Byte lcdRefreshRateAdj; // $A29: Refresh Rate Adjustment Register
+ { 0 }, // Byte ___filler2003[0xA2D-0xA2A];
+ 0x00, // Byte lcdPanningOffset; // $A2D: Panning Offset Register
+
+ { 0 }, // Byte ___filler37[0xA31-0xA2E];
+
+ 0xB9, // Byte lcdFrameRate; // $A31: Frame Rate Control Modulation Register
+ { 0 }, // Byte ___filler2004;
+ 0x84, // Byte lcdGrayPalette; // $A33: Gray Palette Mapping Register
+ 0x00, // Byte lcdReserved; // $A34: Reserved
+ { 0 }, // Byte ___filler2005;
+ 0x0000, // Word lcdContrastControlPWM; // $A36: Contrast Control
+
+ { 0 }, // Byte ___filler40[0xB00-0xA38];
+
+ 0x00000000, // DWord rtcHourMinSec; // $B00: RTC Hours, Minutes, Seconds Register
+ 0x00000000, // DWord rtcAlarm; // $B04: RTC Alarm Register
+ { 0 }, // Byte ___filler2001[0xB0A-0xB08];
+ 0x0001, // Word rtcWatchDog; // $B0A: RTC Watchdog Timer
+ 0x00, // Word rtcControl; // $B0C: RTC Control Register
+ 0x00, // Word rtcIntStatus; // $B0E: RTC Interrupt Status Register
+ 0x00, // Word rtcIntEnable; // $B10: RTC Interrupt Enable Register
+ 0x00, // Word stopWatch; // $B12: Stopwatch Minutes
+ { 0 }, // Byte ___filler2002[0xB1A-0xB14];
+ 0x0000, // Word rtcDay; // $B1A: RTC Day
+ 0x0000, // Word rtcDayAlarm; // $B1C: RTC Day Alarm
+
+ { 0 }, // Byte ___filler41[0xC00-0xB1E];
+
+ 0x0000, // Word dramConfig; // $C00: DRAM Memory Config Register
+ 0x0000, // Word dramControl; // $C02: DRAM Control Register
+
+ { 0 }, // Byte ___filler42[0xD00-0xC04];
+
+ 0x00000000, // DWord emuAddrCompare; // $D00: Emulation Address Compare Register
+ 0x00000000, // DWord emuAddrMask; // $D04: Emulation Address Mask Register
+ 0x0000, // Word emuControlCompare; // $D08: Emulation Control Compare Register
+ 0x0000, // Word emuControlMask; // $D0A: Emulation Control Mask Register
+ 0x0000, // Word emuControl; // $DOC: Emulation Control Register
+ 0x0000 // Word emuStatus; // $D0E: Emulation Status Register
+};
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::EmRegsEZ
+// ---------------------------------------------------------------------------
+
+EmRegsEZ::EmRegsEZ (void) :
+ EmRegs (),
+ f68EZ328Regs (),
+ fHotSyncButtonDown (0),
+ fKeyBits (0),
+ fLastTmr1Status (0),
+ fPortDEdge (0),
+ fPortDDataCount (0),
+ fHour (0),
+ fMin (0),
+ fSec (0),
+ fTick (0),
+ fCycle (0),
+ fUART (NULL)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::~EmRegsEZ
+// ---------------------------------------------------------------------------
+
+EmRegsEZ::~EmRegsEZ (void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::Initialize
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::Initialize (void)
+{
+ EmRegs::Initialize ();
+
+ fUART = new EmUARTDragonball (EmUARTDragonball::kUART_DragonballEZ, 0);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::Reset
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::Reset (Bool hardwareReset)
+{
+ EmRegs::Reset (hardwareReset);
+
+ if (hardwareReset)
+ {
+ f68EZ328Regs = kInitial68EZ328RegisterValues;
+
+ // Byteswap all the words in the DragonballEZ registers (if necessary).
+
+ Canonical (f68EZ328Regs);
+ ByteswapWords (&f68EZ328Regs, sizeof(f68EZ328Regs));
+
+ fKeyBits = 0;
+ fLastTmr1Status = 0;
+ fPortDEdge = 0;
+ fPortDDataCount = 0;
+
+ // React to the new data in the UART registers.
+
+ Bool sendTxData = false;
+ EmRegsEZ::UARTStateChanged (sendTxData);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::Save
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::Save (SessionFile& f)
+{
+ EmRegs::Save (f);
+
+ StWordSwapper swapper1 (&f68EZ328Regs, sizeof(f68EZ328Regs));
+// StCanonical<HwrM68EZ328Type> swapper2 (f68EZ328Regs);
+ f.WriteHwrDBallEZType (f68EZ328Regs);
+ f.FixBug (SessionFile::kBugByteswappedStructs);
+
+ const long kCurrentVersion = 3;
+
+ Chunk chunk;
+ EmStreamChunk s (chunk);
+
+ s << kCurrentVersion;
+
+ s << fHotSyncButtonDown;
+ s << fKeyBits;
+ s << fLastTmr1Status;
+ s << fPortDEdge;
+
+
+ // Added in version 2.
+
+ s << fHour;
+ s << fMin;
+ s << fSec;
+ s << fTick;
+ s << fCycle;
+
+ // Added in version 3.
+
+ s << fPortDDataCount;
+
+ f.WriteDBallEZState (chunk);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::Load
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::Load (SessionFile& f)
+{
+ EmRegs::Load (f);
+
+ if (f.ReadHwrDBallEZType (f68EZ328Regs))
+ {
+ // The Windows version of Poser 2.1d29 and earlier did not write
+ // out structs in the correct format. The fields of the struct
+ // were written out in Little-Endian format, not Big-Endian. To
+ // address this problem, the bug has been fixed, and a new field
+ // is added to the file format indicating that the bug has been
+ // fixed. With the new field (the "bug bit"), Poser can identify
+ // old files from new files and read them in accordingly.
+ //
+ // With the bug fixed, the .psf files should now be interchangeable
+ // across platforms (modulo other bugs...).
+
+ if (!f.IncludesBugFix (SessionFile::kBugByteswappedStructs))
+ {
+ Canonical (f68EZ328Regs);
+ }
+ ByteswapWords (&f68EZ328Regs, sizeof(f68EZ328Regs));
+
+ // React to the new data in the UART registers.
+
+ Bool sendTxData = false;
+ EmRegsEZ::UARTStateChanged (sendTxData);
+
+ // Reset gMemAccessFlags.fProtect_SRAMSet
+
+ gMemAccessFlags.fProtect_SRAMSet = (READ_REGISTER (csDSelect) & 0x2000) != 0;
+ }
+ else
+ {
+ f.SetCanReload (false);
+ }
+
+ Chunk chunk;
+ if (f.ReadDBallEZState (chunk))
+ {
+ long version;
+ EmStreamChunk s (chunk);
+
+ s >> version;
+
+ if (version >= 1)
+ {
+ s >> fHotSyncButtonDown;
+ s >> fKeyBits;
+ s >> fLastTmr1Status;
+ s >> fPortDEdge;
+ }
+
+ if (version >= 2)
+ {
+ s >> fHour;
+ s >> fMin;
+ s >> fSec;
+ s >> fTick;
+ s >> fCycle;
+ }
+
+ if (version >= 3)
+ {
+ s >> fPortDDataCount;
+ }
+ }
+ else
+ {
+ f.SetCanReload (false);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::Dispose
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::Dispose (void)
+{
+ delete fUART;
+ fUART = NULL;
+
+ EmRegs::Dispose ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::SetSubBankHandlers
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::SetSubBankHandlers (void)
+{
+ // Install base handlers.
+
+ EmRegs::SetSubBankHandlers ();
+
+ // Now add standard/specialized handers for the defined registers.
+
+ INSTALL_HANDLER (StdRead, StdWrite, scr);
+
+ INSTALL_HANDLER (StdRead, NullWrite, chipID);
+ INSTALL_HANDLER (StdRead, NullWrite, maskID);
+ INSTALL_HANDLER (StdRead, NullWrite, swID);
+
+ INSTALL_HANDLER (StdRead, StdWrite, csAGroupBase);
+ INSTALL_HANDLER (StdRead, StdWrite, csBGroupBase);
+ INSTALL_HANDLER (StdRead, StdWrite, csCGroupBase);
+ INSTALL_HANDLER (StdRead, StdWrite, csDGroupBase);
+
+ INSTALL_HANDLER (StdRead, csASelectWrite, csASelect);
+ INSTALL_HANDLER (StdRead, StdWrite, csBSelect);
+ INSTALL_HANDLER (StdRead, StdWrite, csCSelect);
+ INSTALL_HANDLER (StdRead, csDSelectWrite, csDSelect);
+
+ INSTALL_HANDLER (StdRead, StdWrite, emuCS);
+
+ INSTALL_HANDLER (StdRead, StdWrite, pllControl);
+ INSTALL_HANDLER (pllFreqSelRead, StdWrite, pllFreqSel);
+ INSTALL_HANDLER (StdRead, StdWrite, pllTest);
+ INSTALL_HANDLER (StdRead, StdWrite, pwrControl);
+
+ INSTALL_HANDLER (StdRead, StdWrite, intVector);
+ INSTALL_HANDLER (StdRead, StdWrite, intControl);
+ INSTALL_HANDLER (StdRead, intMaskHiWrite, intMaskHi);
+ INSTALL_HANDLER (StdRead, intMaskLoWrite, intMaskLo);
+ INSTALL_HANDLER (StdRead, intStatusHiWrite, intStatusHi);
+ INSTALL_HANDLER (StdRead, NullWrite, intStatusLo);
+ INSTALL_HANDLER (StdRead, NullWrite, intPendingHi);
+ INSTALL_HANDLER (StdRead, NullWrite, intPendingLo);
+
+ INSTALL_HANDLER (StdRead, StdWrite, portADir);
+ INSTALL_HANDLER (portXDataRead, portXDataWrite, portAData);
+ INSTALL_HANDLER (StdRead, StdWrite, portAPullupEn);
+
+ INSTALL_HANDLER (StdRead, StdWrite, portBDir);
+ INSTALL_HANDLER (portXDataRead, portXDataWrite, portBData);
+ INSTALL_HANDLER (StdRead, StdWrite, portBPullupEn);
+ INSTALL_HANDLER (StdRead, StdWrite, portBSelect);
+
+ INSTALL_HANDLER (StdRead, StdWrite, portCDir);
+ INSTALL_HANDLER (portXDataRead, portXDataWrite, portCData);
+ INSTALL_HANDLER (StdRead, StdWrite, portCPulldnEn);
+ INSTALL_HANDLER (StdRead, StdWrite, portCSelect);
+
+ INSTALL_HANDLER (StdRead, StdWrite, portDDir);
+ INSTALL_HANDLER (portXDataRead, portXDataWrite, portDData);
+ INSTALL_HANDLER (StdRead, StdWrite, portDPullupEn);
+ INSTALL_HANDLER (StdRead, StdWrite, portDSelect);
+ INSTALL_HANDLER (StdRead, StdWrite, portDPolarity);
+ INSTALL_HANDLER (StdRead, portDIntReqEnWrite, portDIntReqEn);
+ INSTALL_HANDLER (StdRead, StdWrite, portDKbdIntEn);
+ INSTALL_HANDLER (StdRead, StdWrite, portDIntEdge);
+
+ INSTALL_HANDLER (StdRead, StdWrite, portEDir);
+ INSTALL_HANDLER (portXDataRead, portXDataWrite, portEData);
+ INSTALL_HANDLER (StdRead, StdWrite, portEPullupEn);
+ INSTALL_HANDLER (StdRead, StdWrite, portESelect);
+
+ INSTALL_HANDLER (StdRead, StdWrite, portFDir);
+ INSTALL_HANDLER (portXDataRead, portXDataWrite, portFData);
+ INSTALL_HANDLER (StdRead, StdWrite, portFPullupdnEn);
+ INSTALL_HANDLER (StdRead, StdWrite, portFSelect);
+
+ INSTALL_HANDLER (StdRead, StdWrite, portGDir);
+ INSTALL_HANDLER (portXDataRead, portXDataWrite, portGData);
+ INSTALL_HANDLER (StdRead, StdWrite, portGPullupEn);
+ INSTALL_HANDLER (StdRead, StdWrite, portGSelect);
+
+ INSTALL_HANDLER (StdRead, StdWrite, pwmControl);
+ INSTALL_HANDLER (StdRead, StdWrite, pwmSampleHi);
+ INSTALL_HANDLER (StdRead, StdWrite, pwmSampleLo);
+ INSTALL_HANDLER (StdRead, StdWrite, pwmPeriod);
+ INSTALL_HANDLER (StdRead, NullWrite, pwmCounter);
+
+ INSTALL_HANDLER (StdRead, StdWrite, tmr1Control);
+ INSTALL_HANDLER (StdRead, StdWrite, tmr1Prescaler);
+ INSTALL_HANDLER (StdRead, StdWrite, tmr1Compare);
+ INSTALL_HANDLER (StdRead, StdWrite, tmr1Capture);
+ INSTALL_HANDLER (StdRead, NullWrite, tmr1Counter);
+ INSTALL_HANDLER (tmr1StatusRead, tmr1StatusWrite, tmr1Status);
+
+ INSTALL_HANDLER (StdRead, StdWrite, spiMasterData);
+ INSTALL_HANDLER (StdRead, spiMasterControlWrite, spiMasterControl);
+
+ INSTALL_HANDLER (uartRead, uartWrite, uControl);
+ INSTALL_HANDLER (uartRead, uartWrite, uBaud);
+ INSTALL_HANDLER (uartRead, uartWrite, uReceive);
+ INSTALL_HANDLER (uartRead, uartWrite, uTransmit);
+ INSTALL_HANDLER (uartRead, uartWrite, uMisc);
+ INSTALL_HANDLER (uartRead, uartWrite, uNonIntPresc);
+
+ INSTALL_HANDLER (StdRead, lcdRegisterWrite, lcdStartAddr);
+ INSTALL_HANDLER (StdRead, lcdRegisterWrite, lcdPageWidth);
+ INSTALL_HANDLER (StdRead, lcdRegisterWrite, lcdScreenWidth);
+ INSTALL_HANDLER (StdRead, lcdRegisterWrite, lcdScreenHeight);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdCursorXPos);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdCursorYPos);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdCursorWidthHeight);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdBlinkControl);
+ INSTALL_HANDLER (StdRead, lcdRegisterWrite, lcdPanelControl);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdPolarity);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdACDRate);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdPixelClock);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdClockControl);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdRefreshRateAdj);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdPanningOffset);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdFrameRate);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdGrayPalette);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdContrastControlPWM);
+ INSTALL_HANDLER (rtcHourMinSecRead, StdWrite, rtcHourMinSec);
+
+ INSTALL_HANDLER (StdRead, StdWrite, rtcAlarm);
+ INSTALL_HANDLER (StdRead, StdWrite, rtcWatchDog);
+ INSTALL_HANDLER (StdRead, rtcControlWrite, rtcControl);
+ INSTALL_HANDLER (StdRead, rtcIntStatusWrite, rtcIntStatus);
+ INSTALL_HANDLER (StdRead, rtcIntEnableWrite, rtcIntEnable);
+ INSTALL_HANDLER (StdRead, StdWrite, stopWatch);
+ INSTALL_HANDLER (StdRead, StdWrite, rtcDay);
+ INSTALL_HANDLER (StdRead, StdWrite, rtcDayAlarm);
+
+ INSTALL_HANDLER (StdRead, StdWrite, dramConfig);
+ INSTALL_HANDLER (StdRead, StdWrite, dramControl);
+
+ INSTALL_HANDLER (StdRead, StdWrite, emuAddrCompare);
+ INSTALL_HANDLER (StdRead, StdWrite, emuAddrMask);
+ INSTALL_HANDLER (StdRead, StdWrite, emuControlCompare);
+ INSTALL_HANDLER (StdRead, StdWrite, emuControlMask);
+ INSTALL_HANDLER (StdRead, StdWrite, emuControl);
+ INSTALL_HANDLER (StdRead, StdWrite, emuStatus);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::GetRealAddress
+// ---------------------------------------------------------------------------
+
+uint8* EmRegsEZ::GetRealAddress (emuptr address)
+{
+ uint8* loc = ((uint8*) &f68EZ328Regs) + (address - kMemoryStart);
+
+ return loc;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::GetAddressStart
+// ---------------------------------------------------------------------------
+
+emuptr EmRegsEZ::GetAddressStart (void)
+{
+ return kMemoryStart;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::GetAddressRange
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsEZ::GetAddressRange (void)
+{
+ return kMemorySize;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::Cycle
+// ---------------------------------------------------------------------------
+// Handles periodic events that need to occur when the processor cycles (like
+// updating timer registers). This function is called in two places from
+// Emulator::Execute. Interestingly, the loop runs 3% FASTER if this function
+// is in its own separate function instead of being inline.
+
+void EmRegsEZ::Cycle (Bool sleeping)
+{
+#if _DEBUG
+ #define increment 20
+#else
+ #define increment 4
+#endif
+
+ // Determine whether timer is enabled.
+
+ if ((READ_REGISTER (tmr1Control) & hwrEZ328TmrControlEnable) != 0)
+ {
+ // If so, increment the timer.
+
+ WRITE_REGISTER (tmr1Counter, READ_REGISTER (tmr1Counter) + (sleeping ? 1 : increment));
+
+ // Determine whether the timer has reached the specified count.
+
+ if (sleeping || READ_REGISTER (tmr1Counter) > READ_REGISTER (tmr1Compare))
+ {
+ // Flag the occurrence of the successful comparison.
+
+ WRITE_REGISTER (tmr1Status, READ_REGISTER (tmr1Status) | hwrEZ328TmrStatusCompare);
+
+ // If the Free Run/Restart flag is not set, clear the counter.
+
+ if ((READ_REGISTER (tmr1Control) & hwrEZ328TmrControlFreeRun) == 0)
+ {
+ WRITE_REGISTER (tmr1Counter, 0);
+ }
+
+ // If the timer interrupt is enabled, post an interrupt.
+
+ if ((READ_REGISTER (tmr1Control) & hwrEZ328TmrControlEnInterrupt) != 0)
+ {
+ WRITE_REGISTER (intPendingLo, READ_REGISTER (intPendingLo) | hwrEZ328IntLoTimer);
+ EmRegsEZ::UpdateInterrupts ();
+ }
+ }
+ }
+
+ if ((fCycle += increment) > READ_REGISTER (tmr1Compare))
+ {
+ fCycle = 0;
+
+ if (++fTick >= 100)
+ {
+ fTick = 0;
+
+ if (++fSec >= 60)
+ {
+ fSec = 0;
+
+ if (++fMin >= 60)
+ {
+ fMin = 0;
+
+ if (++fHour >= 24)
+ {
+ fHour = 0;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::CycleSlowly
+// ---------------------------------------------------------------------------
+// Handles periodic events that need to occur when the processor cycles (like
+// updating timer registers). This function is called in two places from
+// Emulator::Execute. Interestingly, the loop runs 3% FASTER if this function
+// is in its own separate function instead of being inline.
+
+void EmRegsEZ::CycleSlowly (Bool sleeping)
+{
+ UNUSED_PARAM(sleeping)
+
+ // See if a hard button is pressed.
+
+
+ EmAssert (gSession);
+ if (gSession->HasButtonEvent ())
+ {
+ EmButtonEvent event = gSession->GetButtonEvent ();
+ if (event.fButton == kElement_CradleButton)
+ {
+ EmRegsEZ::HotSyncEvent (event.fButtonIsDown);
+ }
+ else
+ {
+ EmRegsEZ::ButtonEvent (event.fButton, event.fButtonIsDown);
+ }
+ }
+
+ // See if there's anything new ("Put the data on the bus")
+
+ EmRegsEZ::UpdateUARTState (false);
+
+ // Check to see if the RTC alarm is ready to go off. First see
+ // if the RTC is enabled, and that the alarm event isn't already
+ // registered (the latter check is just an optimization).
+
+ if ((READ_REGISTER (rtcIntEnable) & hwrEZ328RTCIntEnableAlarm) != 0 &&
+ (READ_REGISTER (rtcIntStatus) & hwrEZ328RTCIntStatusAlarm) == 0)
+ {
+ uint32 rtcAlarm = READ_REGISTER (rtcAlarm);
+
+ long almHour = (rtcAlarm & hwrEZ328RTCAlarmHoursMask) >> hwrEZ328RTCAlarmHoursOffset;
+ long almMin = (rtcAlarm & hwrEZ328RTCAlarmMinutesMask) >> hwrEZ328RTCAlarmMinutesOffset;
+ long almSec = (rtcAlarm & hwrEZ328RTCAlarmSecondsMask) >> hwrEZ328RTCAlarmSecondsOffset;
+ long almInSeconds = (almHour * 60 * 60) + (almMin * 60) + almSec;
+
+ long nowHour;
+ long nowMin;
+ long nowSec;
+ ::GetHostTime (&nowHour, &nowMin, &nowSec);
+ long nowInSeconds = (nowHour * 60 * 60) + (nowMin * 60) + nowSec;
+
+ if (almInSeconds <= nowInSeconds)
+ {
+ WRITE_REGISTER (rtcIntStatus, READ_REGISTER (rtcIntStatus) | hwrEZ328RTCIntStatusAlarm);
+ EmRegsEZ::UpdateRTCInterrupts ();
+ }
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::TurnSoundOff
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::TurnSoundOff (void)
+{
+ uint16 pwmControl = READ_REGISTER (pwmControl);
+ WRITE_REGISTER (pwmControl, pwmControl & ~hwrEZ328PWMControlEnable);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::ResetTimer
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::ResetTimer (void)
+{
+ WRITE_REGISTER (tmr1Counter, 0);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::ResetRTC
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::ResetRTC (void)
+{
+ fHour = 15;
+ fMin = 0;
+ fSec = 0;
+ fTick = 0;
+ fCycle = 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::GetInterruptLevel
+// ---------------------------------------------------------------------------
+
+int32 EmRegsEZ::GetInterruptLevel (void)
+{
+ uint16 intStatusHi = READ_REGISTER (intStatusHi);
+ uint16 intStatusLo = READ_REGISTER (intStatusLo);
+
+ // Level 7 = EMUIRQ.
+
+ if ((intStatusHi & hwrEZ328IntHiEMU) != 0)
+ return 7;
+
+ // Level 6 = IRQ6, TMR, PWM.
+
+ if ((intStatusHi & (hwrEZ328IntHiIRQ6)) != 0)
+ return 6;
+
+ if ((intStatusLo & (hwrEZ328IntLoTimer | hwrEZ328IntLoPWM)) != 0)
+ return 6;
+
+ // Level 5 = PEN.
+
+ if ((intStatusHi & hwrEZ328IntHiPen) != 0)
+ return 5;
+
+ // Level 4 = SPIM, UART, WDT, RTC, RTC Sample, KB, INT0 - INT3.
+
+ if ((intStatusLo & ( hwrEZ328IntLoSPIM |
+ hwrEZ328IntLoUART |
+ hwrEZ328IntLoWDT |
+ hwrEZ328IntLoRTC |
+ hwrEZ328IntLoKbd |
+ hwrEZ328IntLoInt3 |
+ hwrEZ328IntLoInt2 |
+ hwrEZ328IntLoInt1 |
+ hwrEZ328IntLoInt0)) != 0)
+ return 4;
+
+ if ((intStatusHi & hwrEZ328IntHiSampleTimer) != 0)
+ return 4;
+
+ // Level 3 = IRQ3.
+
+ if ((intStatusHi & hwrEZ328IntHiIRQ3) != 0)
+ return 3;
+
+ // Level 2 = IRQ2.
+
+ if ((intStatusHi & hwrEZ328IntHiIRQ2) != 0)
+ return 2;
+
+ // Level 1 = IRQ1.
+
+ if ((intStatusHi & hwrEZ328IntHiIRQ1) != 0)
+ return 1;
+
+ // Level 0.
+
+ return -1;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::GetInterruptBase
+// ---------------------------------------------------------------------------
+
+int32 EmRegsEZ::GetInterruptBase (void)
+{
+ return READ_REGISTER (intVector) & 0xF8;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::GetLCDHasFrame
+// ---------------------------------------------------------------------------
+
+Bool EmRegsEZ::GetLCDHasFrame (void)
+{
+ return false;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::GetLCDBeginEnd
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::GetLCDBeginEnd (emuptr& begin, emuptr& end)
+{
+ emuptr baseAddr = READ_REGISTER (lcdStartAddr);
+ int rowBytes = READ_REGISTER (lcdPageWidth) * 2;
+ int height = READ_REGISTER (lcdScreenHeight) + 1;
+
+ begin = baseAddr;
+ end = baseAddr + rowBytes * height;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::GetLCDScanlines
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::GetLCDScanlines (EmScreenUpdateInfo& info)
+{
+ // Get the screen metrics.
+
+ int32 bpp = 1 << (READ_REGISTER (lcdPanelControl) & 0x03);
+ int32 width = READ_REGISTER (lcdScreenWidth);
+ int32 height = READ_REGISTER (lcdScreenHeight) + 1;
+ int32 rowBytes = READ_REGISTER (lcdPageWidth) * 2;
+ emuptr baseAddr = READ_REGISTER (lcdStartAddr);
+
+ info.fLeftMargin = READ_REGISTER (lcdPanningOffset) & 0x0F;
+
+ EmPixMapFormat format = bpp == 1 ? kPixMapFormat1 :
+ bpp == 2 ? kPixMapFormat2 :
+ bpp == 4 ? kPixMapFormat4 :
+ kPixMapFormat8;
+
+ RGBList colorTable;
+ this->PrvGetPalette (colorTable);
+
+ // Set format, size, and color table of EmPixMap.
+
+ info.fImage.SetSize (EmPoint (width, height));
+ info.fImage.SetFormat (format);
+ info.fImage.SetRowBytes (rowBytes);
+ info.fImage.SetColorTable (colorTable);
+
+ // Determine first and last scanlines to fetch, and fetch them.
+
+ info.fFirstLine = (info.fScreenLow - baseAddr) / rowBytes;
+ info.fLastLine = (info.fScreenHigh - baseAddr - 1) / rowBytes + 1;
+
+ emuptr firstLineAddr = baseAddr + (info.fFirstLine * rowBytes);
+ emuptr lastLineAddr = baseAddr + (info.fLastLine * rowBytes);
+
+ // TODO: probably move to <M68EZ328Hwr.h>
+ const long hwrEZ328LcdPageSize = 0x00020000; // 128K
+ const long hwrEZ328LcdPageMask = 0xFFFE0000;
+
+ uint8* dst = ((uint8*) info.fImage.GetBits () + firstLineAddr - baseAddr);
+ emuptr boundaryAddr = ((baseAddr & hwrEZ328LcdPageMask) + hwrEZ328LcdPageSize);
+
+ if (lastLineAddr <= boundaryAddr)
+ {
+ // Bits don't cross the 128K boundary
+ }
+ else if (firstLineAddr >= boundaryAddr)
+ {
+ // Bits are all beyond the 128K boundary
+
+ firstLineAddr -= hwrEZ328LcdPageSize; // wrap around
+ lastLineAddr -= hwrEZ328LcdPageSize;
+ }
+ else
+ {
+ // Bits straddle the 128K boundary;
+ // copy the first part here, the wrapped part below
+
+ EmMem_memcpy ((void*) dst, firstLineAddr, boundaryAddr - firstLineAddr);
+ dst += (boundaryAddr - firstLineAddr);
+
+ firstLineAddr = boundaryAddr - hwrEZ328LcdPageSize;
+ lastLineAddr -= hwrEZ328LcdPageSize; // wrap around
+ }
+
+ EmMem_memcpy ((void*) dst, firstLineAddr, lastLineAddr - firstLineAddr);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::GetUARTDevice
+// ---------------------------------------------------------------------------
+// Return what sort of device is hooked up to the given UART.
+
+EmUARTDeviceType EmRegsEZ::GetUARTDevice (int /*uartNum*/)
+{
+ Bool serEnabled = this->GetLineDriverState (kUARTSerial);
+ Bool irEnabled = this->GetLineDriverState (kUARTIR);
+
+ // It's probably an error to have them both enabled at the same
+ // time. !!! TBD: make this an error message.
+
+ EmAssert (!(serEnabled && irEnabled));
+
+ if (serEnabled)
+ return kUARTSerial;
+
+ if (irEnabled)
+ return kUARTIR;
+
+ return kUARTNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::GetDynamicHeapSize
+// ---------------------------------------------------------------------------
+
+int32 EmRegsEZ::GetDynamicHeapSize (void)
+{
+ int32 result = 0;
+
+ uint16 csDSelect = READ_REGISTER (csDSelect);
+
+ switch (csDSelect & UPSIZ)
+ {
+ case 0x0000:
+ result = 32 * 1024L;
+ break;
+
+ case 0x0800:
+ result = 64 * 1024L;
+ break;
+
+ case 0x1000:
+ result = 128 * 1024L;
+ break;
+
+ case 0x1800:
+ result = 256 * 1024L;
+ break;
+
+ default:
+ EmAssert (false);
+ break;
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::GetROMSize
+// ---------------------------------------------------------------------------
+
+int32 EmRegsEZ::GetROMSize (void)
+{
+ /*
+ SIZ Chip-Select Size
+
+ This field determines the memory range of the chip-select. For CSA
+ and CSB, chip-select size is between 128K and 16M. For CSC and CSD,
+ chip-select size is between 32K and 4M.
+
+ 000 = 128K (32K for CSC and CSD).
+ 001 = 256K (64K for CSC and CSD).
+ 010 = 512K (128K for CSC and CSD).
+ 011 = 1M (256K for CSC and CSD).
+ 100 = 2M (512K for CSC and CSD).
+ 101 = 4M (1M for CSC and CSD).
+ 110 = 8M (2M for CSC and CSD).
+ 111 = 16M (4M for CSC and CSD).
+ */
+
+ uint16 csASelect = READ_REGISTER (csASelect);
+ uint32 result = (128 * 1024L) << ((csASelect & SIZ) >> 1);
+
+ if ((csASelect & EN) == 0)
+ {
+ result = 16 * 1024L * 1024L;
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::GetROMBaseAddress
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsEZ::GetROMBaseAddress (void)
+{
+ /*
+ csAGroupBase: Chip-select Group Base Address register
+
+ The csAGroupBase register stores the base address (bits 14-28 of
+ the address) in the top 15 bits. The low bit is always zero.
+ Shifting this value by 13 gives the ROM base address.
+
+ E.g: If the base address is 0x10C00000, then csAGroupBase will
+ contain 0x10C00000 >> 13 (base 10) = 0x8600.
+
+ If the enable bit of the CSA register is low, the chip selects
+ have not yet been set up. In this case, return an invalid value.
+ */
+
+ if (!this->ChipSelectsConfigured())
+ {
+ return 0xFFFFFFFF;
+ }
+
+ uint16 csAGroupBase = READ_REGISTER (csAGroupBase);
+ uint32 result = csAGroupBase << gBaseAddressShift;
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::ChipSelectsConfigured
+// ---------------------------------------------------------------------------
+
+Bool EmRegsEZ::ChipSelectsConfigured (void)
+{
+ return READ_REGISTER (csASelect) & EN;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::GetSystemClockFrequency
+// ---------------------------------------------------------------------------
+
+int32 EmRegsEZ::GetSystemClockFrequency (void)
+{
+ uint16 pllControl = READ_REGISTER (pllControl);
+ uint16 pllFreqSel = READ_REGISTER (pllFreqSel);
+
+ // Convert the 32.768KHz clock (CLK32) into the PLLCLK frequency.
+
+ uint16 PC = (pllFreqSel & 0x00FF);
+ uint16 QC = (pllFreqSel & 0x0F00) >> 8;
+
+ uint32 result = 32768L * (14 * (PC + 1) + QC + 1);
+
+ // Divide by the prescaler, if needed.
+
+ if ((pllControl & 0x0020) != 0)
+ {
+ result /= 2;
+ }
+
+ // Divide by the system clock scaler, if needed.
+
+ switch (pllControl & 0x0F00)
+ {
+ case hwrEZ328PLLControlSysDMADiv2:
+ result /= 2;
+ break;
+
+ case hwrEZ328PLLControlSysDMADiv4:
+ result /= 4;
+ break;
+
+ case hwrEZ328PLLControlSysDMADiv8:
+ result /= 8;
+ break;
+
+ case hwrEZ328PLLControlSysDMADiv16:
+ result /= 16;
+ break;
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::GetCanStop
+// ---------------------------------------------------------------------------
+
+Bool EmRegsEZ::GetCanStop (void)
+{
+ // Make sure Timer is enabled or the RTC interrupt is enabled.
+
+ if ((READ_REGISTER (tmr1Control) & hwrEZ328TmrControlEnable) != 0)
+ return true;
+
+ if ((READ_REGISTER (rtcIntEnable) & hwrEZ328RTCIntEnableAlarm) != 0)
+ return true;
+
+ return false;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::GetAsleep
+// ---------------------------------------------------------------------------
+
+Bool EmRegsEZ::GetAsleep (void)
+{
+ return ((READ_REGISTER (pllControl) & hwrEZ328PLLControlDisable) != 0);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::GetPortInputValue
+// ---------------------------------------------------------------------------
+// Return the GPIO values for the pins on the port. These values are used
+// if the select pins are high.
+
+uint8 EmRegsEZ::GetPortInputValue (int port)
+{
+ uint8 result = 0;
+
+ if (port == 'D')
+ {
+ result = this->GetPortInternalValue (port);
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::GetPortInternalValue
+// ---------------------------------------------------------------------------
+// Return the dedicated values for the pins on the port. These values are
+// used if the select pins are low.
+
+uint8 EmRegsEZ::GetPortInternalValue (int port)
+{
+ uint8 result = 0;
+
+ if (port == 'D')
+ {
+ // If the ID_DETECT pin is asserted, load the data lines with the
+ // hardware ID.
+
+ if (EmRegsEZ::IDDetectAsserted ())
+ {
+ result = EmRegsEZ::GetHardwareID ();
+ }
+
+ // Otherwise, load the lines with keyboard information.
+
+ else
+ {
+ // Get the INT bits that need to be set.
+
+ result = this->GetKeyBits ();
+ }
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::PortDataChanged
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::PortDataChanged (int port, uint8, uint8 newValue)
+{
+ if (port == 'D')
+ {
+ // Clear the interrupt bits that are having a 1 written to them.
+ // Only clear them if they're configured as edge-senstive.
+
+ uint8 portDIntEdge = READ_REGISTER (portDIntEdge);
+
+ PRINTF ("EmRegsEZ::PortDataChanged (D): fPortDEdge = 0x%02lX", (uint32) (uint8) fPortDEdge);
+ PRINTF ("EmRegsEZ::PortDataChanged (D): portDIntEdge = 0x%02lX", (uint32) (uint8) portDIntEdge);
+ PRINTF ("EmRegsEZ::PortDataChanged (D): newValue = 0x%02lX", (uint32) (uint8) newValue);
+
+ fPortDEdge &= ~(newValue & portDIntEdge);
+
+ PRINTF ("EmRegsEZ::PortDataChanged (D): fPortDEdge = 0x%02lX", (uint32) (uint8) fPortDEdge);
+
+ // Set the new interrupt state.
+
+ EmRegsEZ::UpdatePortDInterrupts ();
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::pllFreqSelRead
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsEZ::pllFreqSelRead (emuptr address, int size)
+{
+ // Simulate the rising and falling of the CLK32 signal so that functions
+ // like HwrPreRAMInit, HwrShutDownPLL, PrvSetPLL, and PrvShutDownPLL
+ // won't hang.
+
+ uint16 pllFreqSel = READ_REGISTER (pllFreqSel) ^ 0x8000;
+ WRITE_REGISTER (pllFreqSel, pllFreqSel);
+
+ // Finish up by doing a standard read.
+
+ return EmRegsEZ::StdRead (address, size);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::portXDataRead
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsEZ::portXDataRead (emuptr address, int)
+{
+ // The value read can come from three different places:
+ //
+ // - the value what was written to the data register
+ // - any dedicated inputs
+ // - any GPIO inputs
+ //
+ // The value returned depends on the settings of the SEL and DIR
+ // registers. So let's get those settings, the values from the three
+ // input sources, and build up a return value based on those.
+
+ int port = GetPort (address);
+
+ uint8 sel = StdRead (address + 2, 1);
+ uint8 dir = StdRead (address - 1, 1);
+ uint8 output = StdRead (address + 0, 1);
+ uint8 input = EmHAL::GetPortInputValue (port);
+ uint8 intFn = EmHAL::GetPortInternalValue (port);
+
+ if (port == 'D')
+ {
+ sel |= 0x0F; // No "select" bit in low nybble, so set for IO values.
+
+ // The system will poll portD 18 times in KeyBootKeys to see
+ // if any keys are down. Wait at least that long before
+ // letting up any boot keys maintained by the session. When we
+ // do call ReleaseBootKeys, set our counter to -1 as a flag not
+ // to call it any more.
+
+ if (fPortDDataCount != 0xFFFFFFFF && ++fPortDDataCount >= 18 * 2)
+ {
+ fPortDDataCount = 0xFFFFFFFF;
+ gSession->ReleaseBootKeys ();
+ }
+ }
+
+ // Use the internal chip function bits if the "sel" bits are zero.
+
+ intFn &= ~sel;
+
+ // Otherwise, use the I/O bits.
+
+ output &= sel & dir; // Use the output bits if the "dir" is one.
+ input &= sel & ~dir; // Use the input bits if the "dir" is zero.
+
+ // Assert that there are no overlaps.
+
+ EmAssert ((output & input) == 0);
+ EmAssert ((output & intFn) == 0);
+ EmAssert ((input & intFn) == 0);
+
+ // Mush everything together.
+
+ uint8 result = output | input | intFn;
+
+ // If this is port D, flip the bits if the POLARITY register says to.
+ // (!!! Does this inversion apply only to input bits? That is, the
+ // bits where the "dir" register has 0 bits?)
+
+ if (0 && port == 'D')
+ {
+ uint8 polarity = READ_REGISTER (portDPolarity);
+ PRINTF ("EmRegsEZ::portXDataRead: polarity = 0x%02lX", (uint32) polarity);
+ result ^= polarity;
+ }
+
+ PRINTF ("EmRegsEZ::port%cDataRead: sel dir output input intFn result", (char) port);
+ PRINTF ("EmRegsEZ::port%cDataRead: 0x%02lX 0x%02lX 0x%02lX 0x%02lX 0x%02lX 0x%02lX",
+ (char) port, (uint32) sel, (uint32) dir, (uint32) output, (uint32) input, (uint32) intFn, (uint32) result);
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::tmr1StatusRead
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsEZ::tmr1StatusRead (emuptr address, int size)
+{
+ uint16 tmr1Counter = READ_REGISTER (tmr1Counter) + 16;
+ uint16 tmr1Compare = READ_REGISTER (tmr1Compare);
+ uint16 tmr1Control = READ_REGISTER (tmr1Control);
+
+ // Increment the timer.
+
+ WRITE_REGISTER (tmr1Counter, tmr1Counter);
+
+ // If the timer has passed the specified value...
+
+ if ((tmr1Counter - tmr1Compare) < 16)
+ {
+ // Set the flag saying the timer timed out.
+
+ uint16 tmr1Status = READ_REGISTER (tmr1Status) | hwrEZ328TmrStatusCompare;
+ WRITE_REGISTER (tmr1Status, tmr1Status);
+
+ // If it's not a free-running timer, reset it to zero.
+
+ if ((tmr1Control & hwrEZ328TmrControlFreeRun) == 0)
+ {
+ WRITE_REGISTER (tmr1Counter, 0);
+ }
+ }
+
+ // Remember this guy for later (see EmRegsEZ::tmr1StatusWrite())
+
+ fLastTmr1Status |= READ_REGISTER (tmr1Status);
+
+ // Finish up by doing a standard read.
+
+ return EmRegsEZ::StdRead (address, size);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::uartRead
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsEZ::uartRead (emuptr address, int size)
+{
+ // If this is a full read, get the next byte from the FIFO.
+
+ Bool refreshRxData = (address == addressof (uReceive)) && (size == 2);
+
+ // See if there's anything new ("Put the data on the bus")
+
+ EmRegsEZ::UpdateUARTState (refreshRxData);
+
+ // Finish up by doing a standard read.
+
+ return EmRegsEZ::StdRead (address, size);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::rtcHourMinSecRead
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsEZ::rtcHourMinSecRead (emuptr address, int size)
+{
+ // Get the desktop machine's time.
+
+ long hour, min, sec;
+
+ if (Hordes::IsOn ())
+ {
+ hour = fHour;
+ min = fMin;
+ sec = fSec;
+ }
+ else
+ {
+ ::GetHostTime (&hour, &min, &sec);
+ }
+
+ // Update the register.
+
+ WRITE_REGISTER (rtcHourMinSec, (hour << hwrEZ328RTCHourMinSecHoursOffset)
+ | (min << hwrEZ328RTCHourMinSecMinutesOffset)
+ | (sec << hwrEZ328RTCHourMinSecSecondsOffset));
+
+ // Finish up by doing a standard read.
+
+ return EmRegsEZ::StdRead (address, size);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::csASelectWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::csASelectWrite (emuptr address, int size, uint32 value)
+{
+ // Get the current value.
+
+ uint16 csASelect = READ_REGISTER (csASelect);
+
+ // Do a standard update of the register.
+
+ EmRegsEZ::StdWrite (address, size, value);
+
+ // Check to see if the unprotected memory range changed.
+
+ if ((csASelect & SIZ) != (READ_REGISTER (csASelect) & SIZ))
+ {
+ EmAssert (gSession);
+ gSession->ScheduleResetBanks ();
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::csDSelectWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::csDSelectWrite (emuptr address, int size, uint32 value)
+{
+ // Get the current value.
+
+ uint16 csDSelect = READ_REGISTER (csDSelect);
+
+ // Do a standard update of the register.
+
+ EmRegsEZ::StdWrite (address, size, value);
+
+ // Check its new state and update our ram-protect flag.
+
+ gMemAccessFlags.fProtect_SRAMSet = (READ_REGISTER (csDSelect) & 0x2000) != 0;
+
+ // Check to see if the unprotected memory range changed.
+
+ if ((csDSelect & UPSIZ) != (READ_REGISTER (csDSelect) & UPSIZ))
+ {
+ EmAssert (gSession);
+ gSession->ScheduleResetBanks ();
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::intMaskHiWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::intMaskHiWrite (emuptr address, int size, uint32 value)
+{
+ // Do a standard update of the register.
+
+ EmRegsEZ::StdWrite (address, size, value);
+
+ // Respond to the new interrupt state.
+
+ EmRegsEZ::UpdateInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::intMaskLoWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::intMaskLoWrite (emuptr address, int size, uint32 value)
+{
+ // Do a standard update of the register.
+
+ EmRegsEZ::StdWrite (address, size, value);
+
+ // Respond to the new interrupt state.
+
+ EmRegsEZ::UpdateInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::intStatusHiWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::intStatusHiWrite (emuptr address, int size, uint32 value)
+{
+ // IRQ1, IRQ2, IRQ3, IRQ6 and IRQ7 are cleared by writing to their
+ // respective status bits. We handle those there. Since there are
+ // no interrupt status bits like this in intStatusLo, we don't need
+ // a handler for that register; we only handle intStatusHi.
+
+ // Even though this is a 16-bit register as defined by the Palm headers,
+ // it's a 32-bit register according to DragonballEZ docs, and is in fact
+ // accessed that way in the kernal files (cf. HwrIRQ4Handler). In those
+ // cases, we're still only interested in access to the IRQ# bits, so we
+ // can turn 4-byte accesses into 2-byte accesses.
+
+ if (size == 4)
+ value >>= 16;
+
+ // Take into account the possibility of 1-byte accesses, too. If we're
+ // accessing the upper byte, just return. If we're accessing the lower
+ // byte, we can treat it as a 2-byte access.
+
+ else if (size == 1 && address == addressof (intStatusHi))
+ return;
+
+ // Now we can treat the rest of this function as a word-write to intStatusHi.
+
+ uint16 intPendingHi = READ_REGISTER (intPendingHi);
+
+ // For each interrupt:
+ // If we're writing to that interrupt's status bit and its edge bit is set:
+ // - clear the interrupt's pending bit
+ // - respond to the new interrupt state.
+
+ #undef CLEAR_PENDING_INTERRUPT
+ #define CLEAR_PENDING_INTERRUPT(edge, irq) \
+ if ((READ_REGISTER (intControl) & edge) && (value & (irq))) \
+ { \
+ intPendingHi &= ~(irq); \
+ }
+
+ CLEAR_PENDING_INTERRUPT (hwrEZ328IntCtlEdge1, hwrEZ328IntHiIRQ1);
+ CLEAR_PENDING_INTERRUPT (hwrEZ328IntCtlEdge2, hwrEZ328IntHiIRQ2);
+ CLEAR_PENDING_INTERRUPT (hwrEZ328IntCtlEdge3, hwrEZ328IntHiIRQ3);
+ CLEAR_PENDING_INTERRUPT (hwrEZ328IntCtlEdge6, hwrEZ328IntHiIRQ6);
+
+ // IRQ7 is not edge-programmable, so clear it if we're merely writing to it.
+ // !!! Double check this for EZ!
+
+ if (value & hwrEZ328IntHiEMU)
+ {
+ intPendingHi &= ~(hwrEZ328IntHiEMU);
+ }
+
+ // If we're emulating the user pressing the hotsync button, make sure the
+ // interrupt stays asserted. (!!! Should we use the same technique for
+ // other buttons, too? It doesn't seem to be needed right now, but doing
+ // that may more closely mirror the hardware.)
+
+ if (fHotSyncButtonDown)
+ {
+ intPendingHi |= hwrEZ328IntHiIRQ1;
+ }
+ else
+ {
+ intPendingHi &= ~hwrEZ328IntHiIRQ1;
+ }
+
+ // This makes the power on key work. If the signal is asserted, the
+ // unit will not transition between asleep and awake (cf. HwrSleep, HwrWake).
+
+ intPendingHi &= ~hwrEZ328IntHiIRQ6;
+
+ WRITE_REGISTER (intPendingHi, intPendingHi);
+ EmRegsEZ::UpdateInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::portXDataWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::portXDataWrite (emuptr address, int size, uint32 value)
+{
+ // Get the old value before updating it.
+
+ uint8 oldValue = StdRead (address, size);
+
+ // Take a snapshot of the line driver states.
+
+ Bool driverStates[kUARTEnd];
+ EmHAL::GetLineDriverStates (driverStates);
+
+ // Now update the value with a standard write.
+
+ StdWrite (address, size, value);
+
+ // Let anyone know that it's changed.
+
+ int port = GetPort (address);
+ PRINTF ("EmRegsEZ::port%cDataWrite: oldValue = 0x%02lX", (char) port, (uint32) (uint8) oldValue);
+ PRINTF ("EmRegsEZ::port%cDataWrite: newValue = 0x%02lX", (char) port, (uint32) (uint8) value);
+
+ EmHAL::PortDataChanged (port, oldValue, value);
+
+ // Respond to any changes in the line driver states.
+
+ EmHAL::CompareLineDriverStates (driverStates);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::portDIntReqEnWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::portDIntReqEnWrite (emuptr address, int size, uint32 value)
+{
+ // Do a standard update of the register.
+
+ EmRegsEZ::StdWrite (address, size, value);
+
+ // Set the new interrupt state.
+
+ EmRegsEZ::UpdatePortDInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::tmr1StatusWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::tmr1StatusWrite (emuptr address, int size, uint32 value)
+{
+ UNUSED_PARAM(address)
+ UNUSED_PARAM(size)
+
+ EmAssert (size == 2); // This function's a hell of a lot easier to write if
+ // we assume only full-register access.
+
+ // Get the current value.
+
+ uint16 tmr1Status = READ_REGISTER (tmr1Status);
+
+ // If the user had previously read the status bits while they
+ // were set, then it's OK for them to be clear now. Otherwise,
+ // we have to merge any set status bits back in.
+
+ tmr1Status &= value | ~fLastTmr1Status; // fLastTmr1Status was set in EmRegsEZ::tmr1StatusRead()
+
+ WRITE_REGISTER (tmr1Status, tmr1Status);
+
+ fLastTmr1Status = 0;
+ if ((tmr1Status & hwrEZ328TmrStatusCompare) == 0)
+ {
+ uint16 intPendingLo = READ_REGISTER (intPendingLo) & ~hwrEZ328IntLoTimer;
+ WRITE_REGISTER (intPendingLo, intPendingLo);
+
+ // Respond to the new interrupt state.
+
+ EmRegsEZ::UpdateInterrupts ();
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::spiMasterControlWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::spiMasterControlWrite (emuptr address, int size, uint32 value)
+{
+ // Do a standard update of the register.
+
+ EmRegsEZ::StdWrite (address, size, value);
+
+ // Get the current value.
+
+ uint16 spiMasterData = READ_REGISTER (spiMasterData);
+ uint16 spiMasterControl = READ_REGISTER (spiMasterControl);
+
+ // Check to see if data exchange and interrupts are enabled.
+
+ #define BIT_MASK (hwrEZ328SPIMControlExchange | hwrEZ328SPIMControlEnable)
+ if ((spiMasterControl & BIT_MASK) == BIT_MASK)
+ {
+ // If the SPI is hooked up to something, talk with it.
+
+ EmSPISlave* spiSlave = this->GetSPISlave ();
+ if (spiSlave)
+ {
+ // Write out the old data, read in the new data.
+
+ uint16 newData = spiSlave->DoExchange (spiMasterControl, spiMasterData);
+
+ // Shift in the new data.
+
+ uint16 numBits = (spiMasterControl & hwrEZ328SPIMControlBitsMask) + 1;
+
+ uint16 oldBitsMask = ~0 << numBits;
+ uint16 newBitsMask = ~oldBitsMask;
+
+ spiMasterData = /*((spiMasterData << numBits) & oldBitsMask) | */
+ (newData & newBitsMask);
+
+ WRITE_REGISTER (spiMasterData, spiMasterData);
+ }
+
+ // Assert the interrupt and clear the exchange bit.
+
+ spiMasterControl |= hwrEZ328SPIMControlIntStatus;
+ spiMasterControl &= ~hwrEZ328SPIMControlExchange;
+
+ WRITE_REGISTER (spiMasterControl, spiMasterControl);
+
+ // If hwrEZ328SPIMControlIntEnable is set, trigger an interrupt.
+
+ if ((spiMasterControl & hwrEZ328SPIMControlIntEnable) != 0)
+ {
+ uint16 intPendingLo = READ_REGISTER (intPendingLo);
+ intPendingLo |= hwrEZ328IntLoSPIM;
+ WRITE_REGISTER (intPendingLo, intPendingLo);
+ this->UpdateInterrupts ();
+ }
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::uartWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::uartWrite(emuptr address, int size, uint32 value)
+{
+ // Do a standard update of the register.
+
+ EmRegsEZ::StdWrite (address, size, value);
+
+ // If this write included the TX_DATA field, signal that it needs to
+ // be transmitted.
+
+ Bool sendTxData =
+ ((address == addressof (uTransmit)) && (size == 2)) ||
+ ((address == addressof (uTransmit) + 1) && (size == 1));
+
+ // React to any changes.
+
+ EmRegsEZ::UARTStateChanged (sendTxData);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::lcdRegisterWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::lcdRegisterWrite (emuptr address, int size, uint32 value)
+{
+ // First, get the old value in case we need to see what changed.
+
+ uint32 oldValue = EmRegsEZ::StdRead (address, size);
+
+ // Do a standard update of the register.
+
+ EmRegsEZ::StdWrite (address, size, value);
+
+ // Note what changed.
+
+ if (address == addressof (lcdScreenWidth))
+ {
+ EmScreen::InvalidateAll ();
+ }
+ else if (address == addressof (lcdScreenHeight))
+ {
+ EmScreen::InvalidateAll ();
+ }
+ else if (address == addressof (lcdPanelControl))
+ {
+ // hwrEZ328LcdPanelControlGrayScale is incorrectly defined as 0x01,
+ // so use the hard-coded value of 0x03 here.
+
+// if (((value ^ oldValue) & hwrEZ328LcdPanelControlGrayScale) != 0)
+ if (((value ^ oldValue) & 0x03) != 0)
+ {
+ EmScreen::InvalidateAll ();
+ }
+ }
+ else if (address == addressof (lcdStartAddr))
+ {
+ // Make sure the low-bit is always zero.
+ // Make sure bits 31-29 are always zero.
+
+ uint32 lcdStartAddr = READ_REGISTER (lcdStartAddr) & 0x1FFFFFFE;
+ WRITE_REGISTER (lcdStartAddr, lcdStartAddr);
+
+ EmScreen::InvalidateAll ();
+ }
+ else if (address == addressof (lcdPageWidth))
+ {
+ if (value != oldValue)
+ {
+ EmScreen::InvalidateAll ();
+ }
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::rtcControlWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::rtcControlWrite (emuptr address, int size, uint32 value)
+{
+ // Do a standard update of the register.
+
+ EmRegsEZ::StdWrite (address, size, value);
+
+ // Respond to the new interrupt state.
+
+ EmRegsEZ::UpdateRTCInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::rtcIntStatusWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::rtcIntStatusWrite (emuptr address, int size, uint32 value)
+{
+ // Status bits are cleared by writing ones to them.
+
+ // If we're doing a byte-write to the upper byte, shift the byte
+ // so that we can treat the operation as a word write. If we're
+ // doing a byte-write to the lower byte, this extension will happen
+ // automatically.
+
+ if (address == addressof (rtcIntStatus) && size == 1)
+ value <<= 8;
+
+ // Get the current value.
+
+ uint16 rtcIntStatus = READ_REGISTER (rtcIntStatus);
+
+ // Clear the requested bits.
+
+ rtcIntStatus &= ~value;
+
+ // Update the register.
+
+ WRITE_REGISTER (rtcIntStatus, rtcIntStatus);
+
+ // Respond to the new interrupt state.
+
+ EmRegsEZ::UpdateRTCInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::rtcIntEnableWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::rtcIntEnableWrite (emuptr address, int size, uint32 value)
+{
+ // Do a standard update of the register.
+
+ EmRegsEZ::StdWrite (address, size, value);
+
+ // Respond to the new interrupt state.
+
+ EmRegsEZ::UpdateRTCInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::ButtonEvent
+// ---------------------------------------------------------------------------
+// Handles a Palm device button event by updating the appropriate registers.
+
+void EmRegsEZ::ButtonEvent (SkinElementType button, Bool buttonIsDown)
+{
+ uint16 bitNumber = this->ButtonToBits (button);
+
+ // Get the bits that should have been set with the previous set
+ // of pressed keys. We use this old value to update the port D interrupts.
+
+ uint8 oldBits = this->GetKeyBits ();
+
+ // Update the set of keys that are currently pressed.
+
+ if (buttonIsDown)
+ {
+ fKeyBits |= bitNumber; // Remember the key bit
+ }
+ else
+ {
+ fKeyBits &= ~bitNumber; // Forget the key bit
+ }
+
+ // Now get the new set of bits that should be set.
+
+ uint8 newBits = this->GetKeyBits ();
+
+ PRINTF ("EmRegsEZ::ButtonEvent: fKeyBits = 0x%04lX", (uint32) fKeyBits);
+ PRINTF ("EmRegsEZ::ButtonEvent: oldBits = 0x%02lX", (uint32) oldBits);
+ PRINTF ("EmRegsEZ::ButtonEvent: newBits = 0x%02lX", (uint32) newBits);
+
+ // Set the interrupt bits for the bits that went from off to on.
+ // These get cleared when portDData is written to.
+
+ fPortDEdge |= newBits & ~oldBits;
+
+ PRINTF ("EmRegsEZ::ButtonEvent: fPortDEdge = 0x%02lX", (uint32) fPortDEdge);
+
+ // Set the new interrupt state.
+
+ EmRegsEZ::UpdatePortDInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::HotSyncEvent
+// ---------------------------------------------------------------------------
+// Handles a HotSync button event by updating the appropriate registers.
+
+void EmRegsEZ::HotSyncEvent (Bool buttonIsDown)
+{
+ // If the button changes state, set or clear the HotSync interrupt.
+
+ uint16 intPendingHi = READ_REGISTER (intPendingHi);
+
+ if (buttonIsDown)
+ {
+ intPendingHi |= hwrEZ328IntHiIRQ1;
+ fHotSyncButtonDown = true;
+ }
+ else
+ {
+ intPendingHi &= ~hwrEZ328IntHiIRQ1;
+ fHotSyncButtonDown = false;
+ }
+
+ WRITE_REGISTER (intPendingHi, intPendingHi);
+
+ EmRegsEZ::UpdateInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::GetKeyBits
+// ---------------------------------------------------------------------------
+
+uint8 EmRegsEZ::GetKeyBits (void)
+{
+ // "Keys" (that is, buttons) are read from the Port D Data register.
+ // There are 7 or 8 keys that can be pressed, but only 4 bits are
+ // available in the Port D Data register for reporting pressed keys.
+ // Therefore, the keys are organized into a matrix, one row or which
+ // can be requested and reported at a time. This function determines
+ // what row is being requested, and sets the appropriate Port D Data
+ // bits for the keys are are currently pressed.
+
+ int numRows;
+ int numCols;
+ uint16 keyMap[16];
+ Bool rows[4];
+
+ this->GetKeyInfo (&numRows, &numCols, keyMap, rows);
+
+ uint8 keyData = 0;
+
+ // Walk the rows, looking for one that is requested.
+
+ for (int row = 0; row < numRows; ++row)
+ {
+ if (rows[row])
+ {
+ // Walk the columns, looking for ones that have a pressed key.
+
+ for (int col = 0; col < numCols; ++col)
+ {
+ // Get the key corresponding to this row and column.
+ // If we've recorded (in fKeyBits) that this key is
+ // pressed, then set its column bit.
+
+ uint16 key = keyMap[row * numCols + col];
+ if ((key & fKeyBits) != 0)
+ {
+ keyData |= (1 << col);
+ }
+ }
+ }
+ }
+
+ UInt8 portFDir = READ_REGISTER (portFDir);
+ UInt8 portFData = READ_REGISTER (portFData);
+
+ PRINTF ("EmRegsEZ::GetKeyBits: numRows = %d, numCols = %d", numRows, numCols);
+ PRINTF ("EmRegsEZ::GetKeyBits: portFDir = 0x%02lX, portFData = 0x%02lX", (uint32) portFDir, (uint32) portFData);
+ PRINTF ("EmRegsEZ::GetKeyBits: rows[0] = %d, [1] = %d, [2] = %d, [3] = %d", rows[0], rows[1], rows[2], rows[3]);
+// PRINTF ("EmRegsEZ::GetKeyBits: keyMap[0] = %2d, [1] = %2d, [2] = %2d, [3] = %2d", keyMap[0], keyMap[1], keyMap[2], keyMap[3]);
+// PRINTF ("EmRegsEZ::GetKeyBits: keyMap[4] = %2d, [5] = %2d, [6] = %2d, [7] = %2d", keyMap[4], keyMap[5], keyMap[6], keyMap[7]);
+// PRINTF ("EmRegsEZ::GetKeyBits: keyMap[8] = %2d, [9] = %2d, [A] = %2d, [B] = %2d", keyMap[8], keyMap[9], keyMap[10], keyMap[11]);
+// PRINTF ("EmRegsEZ::GetKeyBits: keyMap[C] = %2d, [D] = %2d, [E] = %2d, [F] = %2d", keyMap[12], keyMap[13], keyMap[14], keyMap[15]);
+ PRINTF ("EmRegsEZ::GetKeyBits: fKeyBits = 0x%04lX", (uint32) fKeyBits);
+ PRINTF ("EmRegsEZ::GetKeyBits: keyData = 0x%02lX", (uint32) keyData);
+
+ return keyData;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::ButtonToBits
+// ---------------------------------------------------------------------------
+
+uint16 EmRegsEZ::ButtonToBits (SkinElementType button)
+{
+ uint16 bitNumber = 0;
+ switch (button)
+ {
+ case kElement_None: break;
+
+ case kElement_PowerButton: bitNumber = keyBitPower; break;
+ case kElement_UpButton: bitNumber = keyBitPageUp; break;
+ case kElement_DownButton: bitNumber = keyBitPageDown; break;
+ case kElement_App1Button: bitNumber = keyBitHard1; break;
+ case kElement_App2Button: bitNumber = keyBitHard2; break;
+ case kElement_App3Button: bitNumber = keyBitHard3; break;
+ case kElement_App4Button: bitNumber = keyBitHard4; break;
+ case kElement_CradleButton: bitNumber = keyBitCradle; break;
+ case kElement_Antenna: bitNumber = keyBitAntenna; break;
+ case kElement_ContrastButton: bitNumber = keyBitContrast; break;
+
+ default: EmAssert (false);
+ }
+
+ return bitNumber;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::GetSPISlave
+// ---------------------------------------------------------------------------
+
+EmSPISlave* EmRegsEZ::GetSPISlave (void)
+{
+ return NULL;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::UpdateInterrupts
+// ---------------------------------------------------------------------------
+// Determines whether an interrupt has occurred by copying the Interrupt
+// Pending Register to the Interrupt Status Register.
+
+void EmRegsEZ::UpdateInterrupts (void)
+{
+ // Copy the Interrupt Pending Register to the Interrupt Status
+ // Register, but ignore interrupts that are being masked.
+
+ // Note: this function is not sensitive to the byte ordering of the registers,
+ // so their contents don't need to be accessed via READ_REGISTER or WRITE_REGISTER.
+
+ f68EZ328Regs.intStatusHi = f68EZ328Regs.intPendingHi & ~f68EZ328Regs.intMaskHi;
+ f68EZ328Regs.intStatusLo = f68EZ328Regs.intPendingLo & ~f68EZ328Regs.intMaskLo;
+
+ PRINTF ("EmRegsEZ::UpdateInterrupts: intMask = 0x%04lX %04lX",
+ (uint32) f68EZ328Regs.intMaskHi, (uint32) f68EZ328Regs.intMaskLo);
+
+ PRINTF ("EmRegsEZ::UpdateInterrupts: intPending = 0x%04lX %04lX",
+ (uint32) f68EZ328Regs.intPendingHi, (uint32) f68EZ328Regs.intPendingLo);
+
+ // If the Interrupt Status Register isn't clear, flag an interrupt.
+
+ if (f68EZ328Regs.intStatusHi || f68EZ328Regs.intStatusLo)
+ {
+ regs.spcflags |= SPCFLAG_INT;
+
+ PRINTF ("EmRegsEZ::UpdateInterrupts: intStatus = 0x%04lX %04lX",
+ (uint32) f68EZ328Regs.intStatusHi, (uint32) f68EZ328Regs.intStatusLo);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::UpdatePortDInterrupts
+// ---------------------------------------------------------------------------
+// Determine what interrupts need to be generated based on the current
+// settings in portDData and fPortDEdge.
+
+void EmRegsEZ::UpdatePortDInterrupts (void)
+{
+ // Update INT0-INT3 of the Interrupt-Pending register (bits 8-11 of the low word).
+
+ PRINTF ("EmRegsEZ::UpdatePortDInterrupts:");
+
+ // First, get those bits and clear them out.
+
+ uint16 intPendingLo = READ_REGISTER (intPendingLo) & ~hwrEZ328IntLoAllKeys;
+
+
+ // Initialize the variable to hold the new interrupt settings.
+
+ uint8 newBits = 0;
+
+
+ // Get some other values we're going to need:
+
+ uint8 portDDir = READ_REGISTER (portDDir); // Interrupt on inputs only (when pin is low)
+ uint8 portDData = EmHAL::GetPortInputValue ('D');
+ uint8 portDPolarity = READ_REGISTER (portDPolarity);
+ uint8 portDIntReqEn = READ_REGISTER (portDIntReqEn);
+ uint8 portDKbdIntEn = READ_REGISTER (portDKbdIntEn);
+ uint8 portDIntEdge = READ_REGISTER (portDIntEdge);
+
+ // We have a line-level interrupt if:
+ //
+ // - line-level interrupts are requested
+ // - the GPIO bit matches the polarity bit
+
+ newBits |= ~portDIntEdge & portDData & portDPolarity;
+ newBits |= ~portDIntEdge & ~portDData & ~portDPolarity;
+
+
+ // We have an edge interrupt if:
+ //
+ // - edge interrupts are requested
+ // - an edge has been recorded
+ //
+ // Note that we should distinguish between rising and falling edges.
+ // For historical reasons, that's not done, and the Palm OS doesn't
+ // look for them, so it's OK for now.
+ //
+ // Edge interrupts on INT[3:0] should not wake up a sleeping device.
+
+ uint16 pllControl = READ_REGISTER (pllControl);
+
+ if (pllControl & hwrEZ328PLLControlDisable)
+ {
+ newBits |= portDIntEdge & fPortDEdge & portDPolarity & 0xF0;
+ newBits |= portDIntEdge & 0 & ~portDPolarity & 0xF0;
+ }
+ else
+ {
+ newBits |= portDIntEdge & fPortDEdge & portDPolarity;
+ newBits |= portDIntEdge & 0 & ~portDPolarity;
+ }
+
+
+ // Only have interrupts if they're enabled and the pin is configured for input.
+
+ newBits &= portDIntReqEn & ~portDDir;
+
+ PRINTF ("EmRegsEZ::UpdatePortDInterrupts: Dir Data Pol Req Edg PDE bits");
+ PRINTF ("EmRegsEZ::UpdatePortDInterrupts: 0x%02lX 0x%02lX 0x%02lX 0x%02lX 0x%02lX 0x%02lX 0x%02lX",
+ (uint32) portDDir, (uint32) portDData, (uint32) portDPolarity, (uint32) portDIntReqEn, (uint32) portDIntEdge,
+ (uint32) fPortDEdge, (uint32) newBits);
+
+
+ // Determine if the KB interrupt needs to be asserted. It is if:
+ //
+ // A Port D Data bit is on.
+ // The bit is configured for input (?)
+ // The bit is configured to be OR'd into the interrupt.
+
+ uint8 KB = portDData & ~portDDir & portDKbdIntEn;
+
+ if (KB)
+ intPendingLo |= hwrEZ328IntLoKbd;
+ else
+ intPendingLo &= ~hwrEZ328IntLoKbd;
+
+
+ // Merge in the new values and write out the result.
+
+ intPendingLo |= (((uint16) newBits) << hwrEZ328IntLoInt0Bit) & hwrEZ328IntLoAllKeys;
+ WRITE_REGISTER (intPendingLo, intPendingLo);
+
+
+ // Respond to the new interrupt state.
+
+ EmRegsEZ::UpdateInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::UpdateRTCInterrupts
+// ---------------------------------------------------------------------------
+// Determine whether to set or clear the RTC bit in the interrupt pending
+// register based on the current RTC register values.
+
+void EmRegsEZ::UpdateRTCInterrupts (void)
+{
+ // See if the RTC is enabled.
+
+ Bool rtcEnabled = (READ_REGISTER (rtcControl) & hwrEZ328RTCControlRTCEnable) != 0;
+
+ // See if there are any RTC events that need to trigger an interrupt.
+
+#define BITS_TO_CHECK ( \
+ hwrEZ328RTCIntEnableSec | \
+ hwrEZ328RTCIntEnable24Hr | \
+ hwrEZ328RTCIntEnableAlarm | \
+ hwrEZ328RTCIntEnableMinute | \
+ hwrEZ328RTCIntEnableStopWatch )
+
+ uint16 rtcIntStatus = READ_REGISTER (rtcIntStatus);
+ uint16 rtcIntEnable = READ_REGISTER (rtcIntEnable);
+ uint16 rtcIntPending = rtcIntStatus & rtcIntEnable & BITS_TO_CHECK;
+
+ Bool havePendingEvents = rtcIntPending != 0;
+
+ // If the RTC is enabled and there are pending events, set the interrupt.
+ // Otherwise, clear the interrupt.
+
+ uint16 intPendingLo = READ_REGISTER (intPendingLo);
+
+ if (rtcEnabled && havePendingEvents)
+ {
+ intPendingLo |= hwrEZ328IntLoRTC; // have events, so set interrupt
+ }
+ else
+ {
+ intPendingLo &= ~hwrEZ328IntLoRTC; // no events, so clear interrupt
+ }
+
+ // Update the interrupt pending register.
+
+ WRITE_REGISTER (intPendingLo, intPendingLo);
+
+ // Respond to the new interrupt state.
+
+ EmRegsEZ::UpdateInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::IDDetectAsserted
+// ---------------------------------------------------------------------------
+// cf. HwrIdentifyFeatures and HwrPreRAMInit.
+
+Bool EmRegsEZ::IDDetectAsserted (void)
+{
+ uint8 portGDir = READ_REGISTER(portGDir);
+ uint8 portGData = READ_REGISTER(portGData);
+ uint8 portGPullupEn = READ_REGISTER(portGPullupEn);
+ uint8 portGSelect = READ_REGISTER(portGSelect);
+ const uint8 kMask = hwrEZPortGIDDetect;
+
+ return (portGDir & kMask) == kMask &&
+ (portGData & kMask) == 0 &&
+ (portGPullupEn & kMask) == 0 &&
+ (portGSelect & kMask) == kMask;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::GetHardwareID
+// ---------------------------------------------------------------------------
+
+UInt8 EmRegsEZ::GetHardwareID (void)
+{
+ // Determine the hardware ID.
+
+ EmAssert (gSession);
+
+ EmDevice device = gSession->GetDevice ();
+ long miscFlags = device.HardwareID ();
+
+ // Reverse map the following:
+
+// GHwrMiscFlags = 0;
+// if ((keyState & hwrEZPortDKbdCol0) == 0) GHwrMiscFlags |= hwrMiscFlagID1;
+// if ((keyState & hwrEZPortDKbdCol1) == 0) GHwrMiscFlags |= hwrMiscFlagID2;
+// if ((keyState & hwrEZPortDKbdCol2) == 0) GHwrMiscFlags |= hwrMiscFlagID3;
+// if ((keyState & hwrEZPortDKbdCol3) == 0) GHwrMiscFlags |= hwrMiscFlagID4;
+
+ UInt8 keyState = ~0;
+
+ if ((miscFlags & hwrMiscFlagID1) != 0) keyState &= ~hwrEZPortDKbdCol0;
+ if ((miscFlags & hwrMiscFlagID2) != 0) keyState &= ~hwrEZPortDKbdCol1;
+ if ((miscFlags & hwrMiscFlagID3) != 0) keyState &= ~hwrEZPortDKbdCol2;
+ if ((miscFlags & hwrMiscFlagID4) != 0) keyState &= ~hwrEZPortDKbdCol3;
+
+ return keyState;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::UARTStateChanged
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::UARTStateChanged (Bool sendTxData)
+{
+ EmUARTDragonball::State state (EmUARTDragonball::kUART_DragonballEZ);
+
+ EmRegsEZ::MarshalUARTState (state);
+ fUART->StateChanged (state, sendTxData);
+ EmRegsEZ::UnmarshalUARTState (state);
+
+ EmRegsEZ::UpdateUARTInterrupts (state);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::UpdateUARTState
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::UpdateUARTState (Bool refreshRxData)
+{
+ EmUARTDragonball::State state (EmUARTDragonball::kUART_DragonballEZ);
+
+ EmRegsEZ::MarshalUARTState (state);
+ fUART->UpdateState (state, refreshRxData);
+ EmRegsEZ::UnmarshalUARTState (state);
+
+ EmRegsEZ::UpdateUARTInterrupts (state);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::UpdateUARTInterrupts
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::UpdateUARTInterrupts (const EmUARTDragonball::State& state)
+{
+ // Generate the appropriate interrupts.
+
+ if (state.RX_FULL_ENABLE && state.RX_FIFO_FULL ||
+ state.RX_HALF_ENABLE && state.RX_FIFO_HALF ||
+ state.RX_RDY_ENABLE && state.DATA_READY ||
+ state.TX_EMPTY_ENABLE && state.TX_FIFO_EMPTY ||
+ state.TX_HALF_ENABLE && state.TX_FIFO_HALF ||
+ state.TX_AVAIL_ENABLE && state.TX_AVAIL)
+ {
+ // Set the UART interrupt.
+
+ WRITE_REGISTER (intPendingLo, READ_REGISTER (intPendingLo) | hwrEZ328IntLoUART);
+ }
+ else
+ {
+ // Clear the UART interrupt.
+
+ WRITE_REGISTER (intPendingLo, READ_REGISTER (intPendingLo) & ~hwrEZ328IntLoUART);
+ }
+
+ // Respond to the new interrupt state.
+
+ EmRegsEZ::UpdateInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::MarshalUARTState
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::MarshalUARTState (EmUARTDragonball::State& state)
+{
+ uint16 uControl = READ_REGISTER (uControl);
+ uint16 uBaud = READ_REGISTER (uBaud);
+ uint16 uReceive = READ_REGISTER (uReceive);
+ uint16 uTransmit = READ_REGISTER (uTransmit);
+ uint16 uMisc = READ_REGISTER (uMisc);
+
+ state.UART_ENABLE = (uControl & hwrEZ328UControlUARTEnable) != 0;
+ state.RX_ENABLE = (uControl & hwrEZ328UControlRxEnable) != 0;
+ state.TX_ENABLE = (uControl & hwrEZ328UControlTxEnable) != 0;
+ state.RX_CLK_CONT = (uControl & hwrEZ328UControlRxClock1xSync) != 0;
+ state.PARITY_EN = (uControl & hwrEZ328UControlParityEn) != 0;
+ state.ODD_EVEN = (uControl & hwrEZ328UControlParityOdd) != 0;
+ state.STOP_BITS = (uControl & hwrEZ328UControlStopBits2) != 0;
+ state.CHAR8_7 = (uControl & hwrEZ328UControlDataBits8) != 0;
+// state.GPIO_DELTA_ENABLE = (uControl & hwr328UControlGPIODeltaEn) != 0; // 68328 only
+ state.OLD_ENABLE = (uControl & hwrEZ328UControlOldDataEn) != 0; // 68EZ328 only
+ state.CTS_DELTA_ENABLE = (uControl & hwrEZ328UControlCTSDeltaEn) != 0;
+ state.RX_FULL_ENABLE = (uControl & hwrEZ328UControlRxFullEn) != 0;
+ state.RX_HALF_ENABLE = (uControl & hwrEZ328UControlRxHalfEn) != 0;
+ state.RX_RDY_ENABLE = (uControl & hwrEZ328UControlRxRdyEn) != 0;
+ state.TX_EMPTY_ENABLE = (uControl & hwrEZ328UControlTxEmptyEn) != 0;
+ state.TX_HALF_ENABLE = (uControl & hwrEZ328UControlTxHalfEn) != 0;
+ state.TX_AVAIL_ENABLE = (uControl & hwrEZ328UControlTxAvailEn) != 0;
+
+ // Baud control register bits
+ // These are all values the user sets; we just look at them.
+
+// state.GPIO_DELTA = (uBaud & hwr328UBaudGPIODelta) != 0; // 68328 only
+// state.GPIO = (uBaud & hwr328UBaudGPIOData) != 0; // 68328 only
+// state.GPIO_DIR = (uBaud & hwr328UBaudGPIODirOut) != 0; // 68328 only
+// state.GPIO_SRC = (uBaud & hwrEZ328UBaudGPIOSrcBaudGen) != 0; // 68328 only
+ state.UCLK_DIR = (uBaud & hwrEZ328UBaudUCLKDirOut) != 0; // 68EZ328 only
+ state.BAUD_SRC = (uBaud & hwrEZ328UBaudBaudSrcUCLK) != 0;
+ state.DIVIDE = (uBaud & hwrEZ328UBaudDivider) >> hwrEZ328UBaudDivideBitOffset;
+ state.PRESCALER = (uBaud & hwrEZ328UBaudPrescaler);
+
+ // Receive register bits
+ // These are all input bits; we set them, not the user.
+
+ state.RX_FIFO_FULL = (uReceive & hwrEZ328UReceiveFIFOFull) != 0;
+ state.RX_FIFO_HALF = (uReceive & hwrEZ328UReceiveFIFOHalf) != 0;
+ state.DATA_READY = (uReceive & hwrEZ328UReceiveDataRdy) != 0;
+ state.OLD_DATA = (uReceive & hwrEZ328UReceiveOldData) != 0; // 68EZ328 only
+ state.OVRUN = (uReceive & hwrEZ328UReceiveOverrunErr) != 0;
+ state.FRAME_ERROR = (uReceive & hwrEZ328UReceiveFrameErr) != 0;
+ state.BREAK = (uReceive & hwrEZ328UReceiveBreakErr) != 0;
+ state.PARITY_ERROR = (uReceive & hwrEZ328UReceiveParityErr) != 0;
+ state.RX_DATA = (uReceive & hwrEZ328UReceiveData);
+
+ // Transmitter register bits
+ // We set everything except TX_DATA; the user sets that
+ // value and ONLY that value.
+
+ state.TX_FIFO_EMPTY = (uTransmit & hwrEZ328UTransmitFIFOEmpty) != 0;
+ state.TX_FIFO_HALF = (uTransmit & hwrEZ328UTransmitFIFOHalf) != 0;
+ state.TX_AVAIL = (uTransmit & hwrEZ328UTransmitTxAvail) != 0;
+ state.SEND_BREAK = (uTransmit & hwrEZ328UTransmitSendBreak) != 0;
+ state.IGNORE_CTS = (uTransmit & hwrEZ328UTransmitIgnoreCTS) != 0;
+ state.BUSY = (uTransmit & hwrEZ328UTransmitBusy) != 0; // 68EZ328 only
+ state.CTS_STATUS = (uTransmit & hwrEZ328UTransmitCTSStatus) != 0;
+ state.CTS_DELTA = (uTransmit & hwrEZ328UTransmitCTSDelta) != 0;
+ state.TX_DATA = (uTransmit & hwrEZ328UTransmitData);
+
+ // Misc register bits
+ // These are all values the user sets; we just look at them.
+
+ state.BAUD_TEST = (uMisc & hwrEZ328UMiscBaudTest) != 0; // 68EZ328 only
+ state.CLK_SRC = (uMisc & hwrEZ328UMiscClkSrcUCLK) != 0;
+ state.FORCE_PERR = (uMisc & hwrEZ328UMiscForceParityErr) != 0;
+ state.LOOP = (uMisc & hwrEZ328UMiscLoopback) != 0;
+ state.BAUD_RESET = (uMisc & hwrEZ328UMiscBaudReset) != 0; // 68EZ328 only
+ state.IR_TEST = (uMisc & hwrEZ328UMiscIRTestEn) != 0; // 68EZ328 only
+ state.RTS_CONT = (uMisc & hwrEZ328UMiscRTSThruFIFO) != 0;
+ state.RTS = (uMisc & hwrEZ328UMiscRTSOut) != 0;
+ state.IRDA_ENABLE = (uMisc & hwrEZ328UMiscIRDAEn) != 0;
+ state.IRDA_LOOP = (uMisc & hwrEZ328UMiscLoopIRDA) != 0;
+ state.RX_POL = (uMisc & hwrEZ328UMiscRXPolarityInv) != 0; // 68EZ328 only
+ state.TX_POL = (uMisc & hwrEZ328UMiscTXPolarityInv) != 0; // 68EZ328 only
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::UnmarshalUARTState
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::UnmarshalUARTState (const EmUARTDragonball::State& state)
+{
+ uint16 uControl = 0;
+ uint16 uBaud = 0;
+ uint16 uReceive = 0;
+ uint16 uTransmit = 0;
+ uint16 uMisc = 0;
+
+ if (state.UART_ENABLE) uControl |= hwrEZ328UControlUARTEnable;
+ if (state.RX_ENABLE) uControl |= hwrEZ328UControlRxEnable;
+ if (state.TX_ENABLE) uControl |= hwrEZ328UControlTxEnable;
+ if (state.RX_CLK_CONT) uControl |= hwrEZ328UControlRxClock1xSync;
+ if (state.PARITY_EN) uControl |= hwrEZ328UControlParityEn;
+ if (state.ODD_EVEN) uControl |= hwrEZ328UControlParityOdd;
+ if (state.STOP_BITS) uControl |= hwrEZ328UControlStopBits2;
+ if (state.CHAR8_7) uControl |= hwrEZ328UControlDataBits8;
+// if (state.GPIO_DELTA_ENABLE)uControl |= hwr328UControlGPIODeltaEn; // 68328 only
+ if (state.OLD_ENABLE) uControl |= hwrEZ328UControlOldDataEn; // 68EZ328 only
+ if (state.CTS_DELTA_ENABLE) uControl |= hwrEZ328UControlCTSDeltaEn;
+ if (state.RX_FULL_ENABLE) uControl |= hwrEZ328UControlRxFullEn;
+ if (state.RX_HALF_ENABLE) uControl |= hwrEZ328UControlRxHalfEn;
+ if (state.RX_RDY_ENABLE) uControl |= hwrEZ328UControlRxRdyEn;
+ if (state.TX_EMPTY_ENABLE) uControl |= hwrEZ328UControlTxEmptyEn;
+ if (state.TX_HALF_ENABLE) uControl |= hwrEZ328UControlTxHalfEn;
+ if (state.TX_AVAIL_ENABLE) uControl |= hwrEZ328UControlTxAvailEn;
+
+ // Baud control register bits
+ // These are all values the user sets; we just look at them.
+
+// if (state.GPIO_DELTA) uBaud |= hwr328UBaudGPIODelta; // 68328 only
+// if (state.GPIO) uBaud |= hwr328UBaudGPIOData; // 68328 only
+// if (state.GPIO_DIR) uBaud |= hwr328UBaudGPIODirOut; // 68328 only
+// if (state.GPIO_SRC) uBaud |= hwr328UBaudGPIOSrcBaudGen; // 68328 only
+ if (state.UCLK_DIR) uBaud |= hwrEZ328UBaudUCLKDirOut; // 68EZ328 only
+ if (state.BAUD_SRC) uBaud |= hwrEZ328UBaudBaudSrcUCLK;
+
+ uBaud |= (state.DIVIDE << hwrEZ328UBaudDivideBitOffset) & hwrEZ328UBaudDivider;
+ uBaud |= (state.PRESCALER) & hwrEZ328UBaudPrescaler;
+
+ // Receive register bits
+ // These are all input bits; we set them, not the user.
+
+ if (state.RX_FIFO_FULL) uReceive |= hwrEZ328UReceiveFIFOFull;
+ if (state.RX_FIFO_HALF) uReceive |= hwrEZ328UReceiveFIFOHalf;
+ if (state.DATA_READY) uReceive |= hwrEZ328UReceiveDataRdy;
+ if (state.OLD_DATA) uReceive |= hwrEZ328UReceiveOldData; // 68EZ328 only
+ if (state.OVRUN) uReceive |= hwrEZ328UReceiveOverrunErr;
+ if (state.FRAME_ERROR) uReceive |= hwrEZ328UReceiveFrameErr;
+ if (state.BREAK) uReceive |= hwrEZ328UReceiveBreakErr;
+ if (state.PARITY_ERROR) uReceive |= hwrEZ328UReceiveParityErr;
+
+ uReceive |= (state.RX_DATA) & hwrEZ328UReceiveData;
+
+ // Transmitter register bits
+ // We set everything except TX_DATA; the user sets that
+ // value and ONLY that value.
+
+ if (state.TX_FIFO_EMPTY) uTransmit |= hwrEZ328UTransmitFIFOEmpty;
+ if (state.TX_FIFO_HALF) uTransmit |= hwrEZ328UTransmitFIFOHalf;
+ if (state.TX_AVAIL) uTransmit |= hwrEZ328UTransmitTxAvail;
+ if (state.SEND_BREAK) uTransmit |= hwrEZ328UTransmitSendBreak;
+ if (state.IGNORE_CTS) uTransmit |= hwrEZ328UTransmitIgnoreCTS;
+ if (state.BUSY) uTransmit |= hwrEZ328UTransmitBusy; // 68EZ328 only
+ if (state.CTS_STATUS) uTransmit |= hwrEZ328UTransmitCTSStatus;
+ if (state.CTS_DELTA) uTransmit |= hwrEZ328UTransmitCTSDelta;
+
+ uTransmit |= (state.TX_DATA) & hwrEZ328UTransmitData;
+
+ // Misc register bits
+ // These are all values the user sets; we just look at them.
+
+ if (state.BAUD_TEST) uMisc |= hwrEZ328UMiscBaudTest; // 68EZ328 only
+ if (state.CLK_SRC) uMisc |= hwrEZ328UMiscClkSrcUCLK;
+ if (state.FORCE_PERR) uMisc |= hwrEZ328UMiscForceParityErr;
+ if (state.LOOP) uMisc |= hwrEZ328UMiscLoopback;
+ if (state.BAUD_RESET) uMisc |= hwrEZ328UMiscBaudReset; // 68EZ328 only
+ if (state.IR_TEST) uMisc |= hwrEZ328UMiscIRTestEn; // 68EZ328 only
+ if (state.RTS_CONT) uMisc |= hwrEZ328UMiscRTSThruFIFO;
+ if (state.RTS) uMisc |= hwrEZ328UMiscRTSOut;
+ if (state.IRDA_ENABLE) uMisc |= hwrEZ328UMiscIRDAEn;
+ if (state.IRDA_LOOP) uMisc |= hwrEZ328UMiscLoopIRDA;
+ if (state.RX_POL) uMisc |= hwrEZ328UMiscRXPolarityInv; // 68EZ328 only
+ if (state.TX_POL) uMisc |= hwrEZ328UMiscTXPolarityInv; // 68EZ328 only
+
+ WRITE_REGISTER (uControl, uControl);
+ WRITE_REGISTER (uBaud, uBaud);
+ WRITE_REGISTER (uReceive, uReceive);
+ WRITE_REGISTER (uTransmit, uTransmit);
+ WRITE_REGISTER (uMisc, uMisc);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::GetPort
+// ---------------------------------------------------------------------------
+// Given an address, return a value indicating what port it is associated with.
+
+int EmRegsEZ::GetPort (emuptr address)
+{
+ const long MASK = 0x00000FF8;
+
+ switch (address & MASK)
+ {
+ case 0x0400: return 'A';
+ case 0x0408: return 'B';
+ case 0x0410: return 'C';
+ case 0x0418: return 'D';
+ case 0x0420: return 'E';
+ case 0x0428: return 'F';
+ case 0x0430: return 'G';
+ }
+
+ EmAssert (false);
+ return 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZ::PrvGetPalette
+// ---------------------------------------------------------------------------
+
+void EmRegsEZ::PrvGetPalette (RGBList& thePalette)
+{
+ // !!! TBD
+ Preference<RGBType> pref1 (kPrefKeyBackgroundColor);
+ Preference<RGBType> pref2 (kPrefKeyHighlightColor);
+
+ RGBType foreground (0, 0, 0);
+ RGBType background;
+
+ if (this->GetLCDBacklightOn ())
+ {
+ if (pref2.Loaded ())
+ background = *pref2;
+ else
+ background = ::SkinGetHighlightColor ();
+ }
+ else
+ {
+ if (pref1.Loaded ())
+ background = *pref1;
+ else
+ background = ::SkinGetBackgroundColor ();
+ }
+
+ long br = ((long) background.fRed);
+ long bg = ((long) background.fGreen);
+ long bb = ((long) background.fBlue);
+
+ long dr = ((long) foreground.fRed) - ((long) background.fRed);
+ long dg = ((long) foreground.fGreen) - ((long) background.fGreen);
+ long db = ((long) foreground.fBlue) - ((long) background.fBlue);
+
+ int32 bpp = 1 << (READ_REGISTER (lcdPanelControl) & 0x03);
+ int32 numColors = 1 << bpp;
+ thePalette.resize (numColors);
+
+ for (int color = 0; color < numColors; ++color)
+ {
+ thePalette[color].fRed = (UInt8) (br + dr * color / (numColors - 1));
+ thePalette[color].fGreen = (UInt8) (bg + dg * color / (numColors - 1));
+ thePalette[color].fBlue = (UInt8) (bb + db * color / (numColors - 1));
+ }
+}
diff --git a/SrcShared/Hardware/EmRegsEZ.h b/SrcShared/Hardware/EmRegsEZ.h
new file mode 100644
index 0000000..d9c69b2
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsEZ.h
@@ -0,0 +1,143 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegsEZ_h
+#define EmRegsEZ_h
+
+#include "EmHAL.h" // EmHALHandler
+#include "EmRegs.h" // EmRegs
+#include "EmStructs.h" // RGBList
+#include "EmUARTDragonball.h" // EmUARTDragonball::State
+
+class EmScreenUpdateInfo;
+class EmSPISlave;
+
+
+class EmRegsEZ : public EmRegs, public EmHALHandler
+{
+ public:
+ EmRegsEZ (void);
+ virtual ~EmRegsEZ (void);
+
+ // EmRegs overrides
+ virtual void Initialize (void);
+ virtual void Reset (Bool hardwareReset);
+ virtual void Save (SessionFile&);
+ virtual void Load (SessionFile&);
+ virtual void Dispose (void);
+
+ virtual void SetSubBankHandlers (void);
+ virtual uint8* GetRealAddress (emuptr address);
+ virtual emuptr GetAddressStart (void);
+ virtual uint32 GetAddressRange (void);
+
+ // EmHALHandler overrides
+ virtual void Cycle (Bool sleeping);
+ virtual void CycleSlowly (Bool sleeping);
+
+ virtual void ButtonEvent (SkinElementType, Bool buttonIsDown);
+ virtual void TurnSoundOff (void);
+ virtual void ResetTimer (void);
+ virtual void ResetRTC (void);
+
+ virtual int32 GetInterruptLevel (void);
+ virtual int32 GetInterruptBase (void);
+
+ virtual Bool GetLCDScreenOn (void) = 0;
+ virtual Bool GetLCDBacklightOn (void) = 0;
+ virtual Bool GetLCDHasFrame (void);
+ virtual void GetLCDBeginEnd (emuptr&, emuptr&);
+ virtual void GetLCDScanlines (EmScreenUpdateInfo& info);
+
+ virtual EmUARTDeviceType GetUARTDevice (int uartNum);
+ virtual int32 GetDynamicHeapSize (void);
+ virtual int32 GetROMSize (void);
+ virtual emuptr GetROMBaseAddress (void);
+ virtual Bool ChipSelectsConfigured (void);
+ virtual int32 GetSystemClockFrequency (void);
+ virtual Bool GetCanStop (void);
+ virtual Bool GetAsleep (void);
+
+ virtual uint8 GetPortInputValue (int);
+ virtual uint8 GetPortInternalValue (int);
+ virtual void PortDataChanged (int, uint8, uint8);
+ virtual void GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows) = 0;
+
+ protected:
+ uint32 pllFreqSelRead (emuptr address, int size);
+ uint32 portXDataRead (emuptr address, int size);
+ uint32 tmr1StatusRead (emuptr address, int size);
+ uint32 uartRead (emuptr address, int size);
+ uint32 rtcHourMinSecRead (emuptr address, int size);
+
+ void csASelectWrite (emuptr address, int size, uint32 value);
+ void csDSelectWrite (emuptr address, int size, uint32 value);
+ void intMaskHiWrite (emuptr address, int size, uint32 value);
+ void intMaskLoWrite (emuptr address, int size, uint32 value);
+ void intStatusHiWrite (emuptr address, int size, uint32 value);
+ void portXDataWrite (emuptr address, int size, uint32 value);
+ void portDIntReqEnWrite (emuptr address, int size, uint32 value);
+ void tmr1StatusWrite (emuptr address, int size, uint32 value);
+ void spiMasterControlWrite (emuptr address, int size, uint32 value);
+ void uartWrite (emuptr address, int size, uint32 value);
+ void lcdRegisterWrite (emuptr address, int size, uint32 value);
+ void rtcControlWrite (emuptr address, int size, uint32 value);
+ void rtcIntStatusWrite (emuptr address, int size, uint32 value);
+ void rtcIntEnableWrite (emuptr address, int size, uint32 value);
+
+ protected:
+ void HotSyncEvent (Bool buttonIsDown);
+
+ virtual uint8 GetKeyBits (void);
+ virtual uint16 ButtonToBits (SkinElementType);
+ virtual EmSPISlave* GetSPISlave (void);
+
+ protected:
+ void UpdateInterrupts (void);
+ void UpdatePortDInterrupts (void);
+ void UpdateRTCInterrupts (void);
+
+ protected:
+ Bool IDDetectAsserted (void);
+ UInt8 GetHardwareID (void);
+
+ protected:
+ void UARTStateChanged (Bool sendTxData);
+ void UpdateUARTState (Bool refreshRxData);
+ void UpdateUARTInterrupts (const EmUARTDragonball::State& state);
+ void MarshalUARTState (EmUARTDragonball::State& state);
+ void UnmarshalUARTState (const EmUARTDragonball::State& state);
+
+ protected:
+ int GetPort (emuptr address);
+ void PrvGetPalette (RGBList& thePalette);
+
+ protected:
+ HwrM68EZ328Type f68EZ328Regs;
+ bool fHotSyncButtonDown;
+ uint16 fKeyBits;
+ uint16 fLastTmr1Status;
+ uint8 fPortDEdge;
+ uint32 fPortDDataCount;
+
+ uint32 fHour;
+ uint32 fMin;
+ uint32 fSec;
+ uint32 fTick;
+ uint32 fCycle;
+
+ EmUARTDragonball* fUART;
+};
+
+#endif /* EmRegsEZ_h */
diff --git a/SrcShared/Hardware/EmRegsEZPalmIIIc.cpp b/SrcShared/Hardware/EmRegsEZPalmIIIc.cpp
new file mode 100644
index 0000000..bc4744e
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsEZPalmIIIc.cpp
@@ -0,0 +1,222 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmRegsEZPalmIIIc.h"
+#include "EmRegsEZPrv.h"
+
+#include "EmSPISlaveADS784x.h" // EmSPISlaveADS784x
+
+#include "PalmPack.h"
+#define NON_PORTABLE
+ #include "EZAustin/IncsPrv/HardwareAustin.h" // hwrEZPortCKbdRow0, hwrEZPortBRS232Enable, etc.
+#undef NON_PORTABLE
+#include "PalmPackPop.h"
+
+const int kNumButtonRows = 3;
+const int kNumButtonCols = 4;
+
+const uint16 kButtonMap[kNumButtonRows][kNumButtonCols] =
+{
+ { keyBitHard1, keyBitHard2, keyBitHard3, keyBitHard4 },
+ { keyBitPageUp, keyBitPageDown, 0, 0 },
+ { keyBitPower, keyBitContrast, keyBitHard2, 0 }
+};
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmIIIc::EmRegsEZPalmIIIc
+// ---------------------------------------------------------------------------
+
+EmRegsEZPalmIIIc::EmRegsEZPalmIIIc (void) :
+ EmRegsEZ (),
+ fSPISlaveADC (new EmSPISlaveADS784x (kChannelSet2))
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmIIIc::~EmRegsEZPalmIIIc
+// ---------------------------------------------------------------------------
+
+EmRegsEZPalmIIIc::~EmRegsEZPalmIIIc (void)
+{
+ delete fSPISlaveADC;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmIIIc::GetLCDScreenOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsEZPalmIIIc::GetLCDScreenOn (void)
+{
+ // Override the Dragonball version and let the SED 1375 handle it.
+
+ return EmHALHandler::GetLCDScreenOn ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmIIIc::GetLCDBacklightOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsEZPalmIIIc::GetLCDBacklightOn (void)
+{
+ // Override the Dragonball version and let the SED 1375 handle it.
+
+ return EmHALHandler::GetLCDBacklightOn ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmIIIc::GetLCDHasFrame
+// ---------------------------------------------------------------------------
+
+Bool EmRegsEZPalmIIIc::GetLCDHasFrame (void)
+{
+ // Override the Dragonball version and let the SED 1375 handle it.
+
+ return EmHALHandler::GetLCDHasFrame ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmIIIc::GetLCDBeginEnd
+// ---------------------------------------------------------------------------
+
+void EmRegsEZPalmIIIc::GetLCDBeginEnd (emuptr& begin, emuptr& end)
+{
+ // Override the Dragonball version and let the SED 1375 handle it.
+
+ EmHALHandler::GetLCDBeginEnd (begin, end);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmIIIc::GetLCDScanlines
+// ---------------------------------------------------------------------------
+
+void EmRegsEZPalmIIIc::GetLCDScanlines (EmScreenUpdateInfo& info)
+{
+ // Override the Dragonball version and let the SED 1375 handle it.
+
+ EmHALHandler::GetLCDScanlines (info);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmIIIc::GetLineDriverState
+// ---------------------------------------------------------------------------
+// Return whether or not the line drivers for the given object are open or
+// closed.
+
+Bool EmRegsEZPalmIIIc::GetLineDriverState (EmUARTDeviceType type)
+{
+ if (type == kUARTSerial)
+ return (READ_REGISTER (portBData) & hwrEZPortBRS232Enable) != 0;
+
+ if (type == kUARTIR)
+ return (READ_REGISTER (portGData) & hwrEZPortGIRShutdown) == 0;
+
+ return false;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmIIIc::GetPortInputValue
+// ---------------------------------------------------------------------------
+// Return the GPIO values for the pins on the port. These values are used
+// if the select pins are high.
+
+uint8 EmRegsEZPalmIIIc::GetPortInputValue (int port)
+{
+ uint8 result = EmRegsEZ::GetPortInputValue (port);
+
+ if (port == 'F')
+ {
+ // Ensure that bit hwrEZPortFIXTRNL2 is set. If it's clear, HotSync
+ // will sync via the modem instead of the serial port.
+
+ // Make sure hwrEZPortFLCDPowered is always set, or HwrDisplayWake will hang
+
+ result |= hwrEZPortFIXTRNL2 | hwrEZPortFLCDPowered;
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmIIIc::GetPortInternalValue
+// ---------------------------------------------------------------------------
+// Return the dedicated values for the pins on the port. These values are
+// used if the select pins are low.
+
+uint8 EmRegsEZPalmIIIc::GetPortInternalValue (int port)
+{
+ uint8 result = EmRegsEZ::GetPortInternalValue (port);
+
+ if (port == 'D')
+ {
+ // Make sure that hwrEZPortDPowerFail is set. If it's clear,
+ // the battery code will make the device go to sleep immediately.
+
+ result |= hwrEZPortDPowerFail;
+
+ // Make sure hwrEZPortDAdapterInstalled is set, or the dock-status routines
+ // will report that we're powered (even if we aren't docked!).
+
+ result |= hwrEZPortDAdapterInstalled;
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmIIIc::GetKeyInfo
+// ---------------------------------------------------------------------------
+
+void EmRegsEZPalmIIIc::GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows)
+{
+ *numRows = kNumButtonRows;
+ *numCols = kNumButtonCols;
+
+ memcpy (keyMap, kButtonMap, sizeof (kButtonMap));
+
+ // Determine what row is being asked for.
+
+ UInt8 portCDir = READ_REGISTER (portCDir);
+ UInt8 portCData = READ_REGISTER (portCData);
+
+ rows[0] = (portCDir & hwrEZPortCKbdRow0) != 0 && (portCData & hwrEZPortCKbdRow0) == 0;
+ rows[1] = (portCDir & hwrEZPortCKbdRow1) != 0 && (portCData & hwrEZPortCKbdRow1) == 0;
+ rows[2] = (portCDir & hwrEZPortCKbdRow2) != 0 && (portCData & hwrEZPortCKbdRow2) == 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmIIIc::GetSPISlave
+// ---------------------------------------------------------------------------
+
+EmSPISlave* EmRegsEZPalmIIIc::GetSPISlave (void)
+{
+ if ((READ_REGISTER (portBData) & hwrEZPortBCS_ADC) == 0)
+ {
+ return fSPISlaveADC;
+ }
+
+ return NULL;
+}
diff --git a/SrcShared/Hardware/EmRegsEZPalmIIIc.h b/SrcShared/Hardware/EmRegsEZPalmIIIc.h
new file mode 100644
index 0000000..704f8a0
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsEZPalmIIIc.h
@@ -0,0 +1,48 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegsEZPalmIIIc_h
+#define EmRegsEZPalmIIIc_h
+
+#include "EmRegsEZ.h"
+
+class EmScreenUpdateInfo;
+
+
+class EmRegsEZPalmIIIc : public EmRegsEZ
+{
+ public:
+ EmRegsEZPalmIIIc (void);
+ virtual ~EmRegsEZPalmIIIc (void);
+
+ virtual Bool GetLCDScreenOn (void);
+ virtual Bool GetLCDBacklightOn (void);
+ virtual Bool GetLCDHasFrame (void);
+ virtual void GetLCDBeginEnd (emuptr&, emuptr&);
+ virtual void GetLCDScanlines (EmScreenUpdateInfo& info);
+
+ virtual Bool GetLineDriverState (EmUARTDeviceType type);
+
+ virtual uint8 GetPortInputValue (int);
+ virtual uint8 GetPortInternalValue (int);
+ virtual void GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows);
+
+ protected:
+ virtual EmSPISlave* GetSPISlave (void);
+
+ private:
+ EmSPISlave* fSPISlaveADC;
+};
+
+#endif /* EmRegsEZPalmIIIc_h */
diff --git a/SrcShared/Hardware/EmRegsEZPalmIIIe.h b/SrcShared/Hardware/EmRegsEZPalmIIIe.h
new file mode 100644
index 0000000..a0f356d
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsEZPalmIIIe.h
@@ -0,0 +1,21 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegsEZPalmIIIe_h
+#define EmRegsEZPalmIIIe_h
+
+#include "EmRegsEZPalmV.h"
+
+typedef EmRegsEZPalmV EmRegsEZPalmIIIe;
+
+#endif /* EmRegsEZPalmIIIe_h */
diff --git a/SrcShared/Hardware/EmRegsEZPalmIIIx.h b/SrcShared/Hardware/EmRegsEZPalmIIIx.h
new file mode 100644
index 0000000..7ab02de
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsEZPalmIIIx.h
@@ -0,0 +1,21 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegsEZPalmIIIx_h
+#define EmRegsEZPalmIIIx_h
+
+#include "EmRegsEZPalmV.h"
+
+typedef EmRegsEZPalmV EmRegsEZPalmIIIx;
+
+#endif /* EmRegsEZPalmIIIx_h */
diff --git a/SrcShared/Hardware/EmRegsEZPalmM100.cpp b/SrcShared/Hardware/EmRegsEZPalmM100.cpp
new file mode 100644
index 0000000..684d0ee
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsEZPalmM100.cpp
@@ -0,0 +1,247 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmRegsEZPalmM100.h"
+#include "EmRegsEZPrv.h"
+
+#include "EmSession.h" // GetDevice
+#include "EmSPISlaveADS784x.h" // EmSPISlaveADS784x
+
+
+// The following are taken from the m100 version of HardwareEZ.h.
+
+/************************************************************************
+ * Port B Bit settings
+ ************************************************************************/
+#define hwrEZPortBKbdRow0 0x01
+#define hwrEZPortBLCDVccOff 0x02 // (L) LCD Vcc On
+#define hwrEZPortBKbdRow1 0x08
+#define hwrEZPortBKbdRow2 0x40
+#define hwrEZPortBKbdRows 0x49
+
+#define hwrEZPortBLCDAdjOn 0x40 // (L) LCD Contrast Adjust On (Brad Rev 0)
+
+
+/************************************************************************
+ * Port C Bit settings
+ ************************************************************************/
+#define hwrEZPortCLCDEnableOn 0x80 // (H) LCD Enable
+
+
+/************************************************************************
+ * Port D Bit settings
+ ************************************************************************/
+#define hwrEZPortDKbdCol0 0x01 // (H) Keyboard Column 0 (aka INT0)
+#define hwrEZPortDKbdCol1 0x02 // (H) Keyboard Column 1 (aka INT1)
+#define hwrEZPortDKbdCol2 0x04 // (H) Keyboard Column 2 (aka INT2)
+#define hwrEZPortDKbdCol3 0x08 // (H) Keyboard Column 3 (aka INT3)
+#define hwrEZPortDKeyBits 0x0F // (H) All Keyboard Columns
+#define hwrEZPortDDockButton 0x10 // (L) Dock Button (aka IRQ1) (edge, negative)
+#define hwrEZPortD232Enable 0x20 // (L) Serial Shutdown on Sumo Rev 1 (aka IRQ2)
+#define hwrEZPortDLCDBiasOn 0x40 // (H) LCD Bias on
+#define hwrEZPortDPowerFail 0x80 // (L) Power Fail Interrupt (aka IRQ6) (level, low)
+
+#define hwrEZPortDDataMaskBeforeWrite (~(hwrEZPortDKeyBits)) // Don't write ones to these bits!
+#define hwrEZPortDKeyOffset 0x0 // bits to shift to put Col 0 in msb
+
+
+/************************************************************************
+ * Port E Bit settings
+ ************************************************************************/
+#define hwrEZPortESpiTxD 0x01 // (L) SPI TXD (Internal)
+#define hwrEZPortESpiRxD 0x02 // (L) SPI RXD (Internal)
+#define hwrEZPortESpiClk 0x04 // SPI Clock
+#define hwrEZPortESpiBits 0x07 // all the SPI bits
+#define hwrEZPortERXD 0x10 // external RXD
+#define hwrEZPortETXD 0x20 // external TXD
+#define hwrEZPortECTS 0x80 // external CTS
+
+/************************************************************************
+ * Port F Bit settings
+ ************************************************************************/
+#define hwrEZPortFLCDBiasData 0x01 // LCD Bias data
+#define hwrEZPortFPenIO 0x02 // (L) Pen Interrupt,Pen I/O
+#define hwrEZPortFLCDBiasStrb 0x04 // LCD Bias strobe
+#define hwrEZPortFBacklightOn 0x20 // (H) Backlight on
+#define hwrEZPortFLCDDispOn 0x40 // (H) LCD display on
+#define hwrEZPortFLCDBiasClk 0x80 // LCD Bias clock
+
+#define hwrEZPortFLCDAdjOn 0x01 // (L) LCD Contrast Adjust On (Brad Rev 1)
+#define hwrEZPortF232Enable 0x04 // (L) Shutdown Serial
+#define hwrEZPortFContrastPWM 0x01 // (L) PWM output for LCD contrast
+
+
+/************************************************************************
+ * Port G Bit settings
+ ************************************************************************/
+#define hwrEZPortGDTACK 0x01 // (L) DTACK
+#define hwrEZPortGFree1 0x02 // (-) FREE5
+#define hwrEZPortGIDDetect 0x04 // (L) ID select (drives kbd)
+#define hwrEZPortGLiIonVoltReadDis 0x08 // (L) Enable A/D Voltage Divider
+#define hwrEZPortGIRShutdown 0x10 // (H) Shutdown IRDA
+#define hwrEZPortGADCOff 0x20 // (L) A/D Select
+
+
+const int kNumButtonRows = 3;
+const int kNumButtonCols = 4;
+
+const uint16 kButtonMap[kNumButtonRows][kNumButtonCols] =
+{
+ { keyBitHard1, keyBitHard2, keyBitHard3, keyBitHard4 },
+ { 0, keyBitPageDown, 0, 0 },
+ { keyBitPower, keyBitPageUp, keyBitHard2, 0 }
+};
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmM100::EmRegsEZPalmM100
+// ---------------------------------------------------------------------------
+
+EmRegsEZPalmM100::EmRegsEZPalmM100 (void) :
+ EmRegsEZ (),
+ fSPISlaveADC (new EmSPISlaveADS784x (kChannelSet2))
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmM100::~EmRegsEZPalmM100
+// ---------------------------------------------------------------------------
+
+EmRegsEZPalmM100::~EmRegsEZPalmM100 (void)
+{
+ delete fSPISlaveADC;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmM100::GetLCDScreenOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsEZPalmM100::GetLCDScreenOn (void)
+{
+ return (READ_REGISTER (portFData) & hwrEZPortFLCDDispOn) != 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmM100::GetLCDBacklightOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsEZPalmM100::GetLCDBacklightOn (void)
+{
+ return (READ_REGISTER (portFData) & hwrEZPortFBacklightOn) != 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmM100::GetLineDriverState
+// ---------------------------------------------------------------------------
+// Return whether or not the line drivers for the given object are open or
+// closed.
+
+Bool EmRegsEZPalmM100::GetLineDriverState (EmUARTDeviceType type)
+{
+ if (type == kUARTSerial)
+ return (READ_REGISTER (portDData) & hwrEZPortD232Enable) != 0;
+
+ if (type == kUARTIR)
+ return (READ_REGISTER (portGData) & hwrEZPortGIRShutdown) == 0;
+
+ return false;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmM100::GetPortInputValue
+// ---------------------------------------------------------------------------
+// Return the GPIO values for the pins on the port. These values are used
+// if the select pins are high.
+
+uint8 EmRegsEZPalmM100::GetPortInputValue (int port)
+{
+ uint8 result = EmRegsEZ::GetPortInputValue (port);
+
+ if (port == 'E')
+ {
+ // Return the hardware sub-ID.
+
+ EmAssert (gSession);
+
+ EmDevice device = gSession->GetDevice ();
+ result |= ~device.HardwareSubID ();
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmM100::GetPortInternalValue
+// ---------------------------------------------------------------------------
+// Return the dedicated values for the pins on the port. These values are
+// used if the select pins are low.
+
+uint8 EmRegsEZPalmM100::GetPortInternalValue (int port)
+{
+ uint8 result = EmRegsEZ::GetPortInternalValue (port);
+
+ if (port == 'D')
+ {
+ // Make sure that hwrEZPortDPowerFail is set. If it's clear,
+ // the battery code will make the device go to sleep immediately.
+
+ result |= hwrEZPortDPowerFail;
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmM100::GetKeyInfo
+// ---------------------------------------------------------------------------
+
+void EmRegsEZPalmM100::GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows)
+{
+ *numRows = kNumButtonRows;
+ *numCols = kNumButtonCols;
+
+ memcpy (keyMap, kButtonMap, sizeof (kButtonMap));
+
+ // Determine what row is being asked for.
+
+ UInt8 portBDir = READ_REGISTER (portBDir);
+ UInt8 portBData = READ_REGISTER (portBData);
+
+ rows[0] = (portBDir & hwrEZPortBKbdRow0) != 0 && (portBData & hwrEZPortBKbdRow0) == 0;
+ rows[1] = (portBDir & hwrEZPortBKbdRow1) != 0 && (portBData & hwrEZPortBKbdRow1) == 0;
+ rows[2] = (portBDir & hwrEZPortBKbdRow2) != 0 && (portBData & hwrEZPortBKbdRow2) == 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmM100::GetSPISlave
+// ---------------------------------------------------------------------------
+
+EmSPISlave* EmRegsEZPalmM100::GetSPISlave (void)
+{
+ if ((READ_REGISTER (portGData) & hwrEZPortGADCOff) == 0)
+ {
+ return fSPISlaveADC;
+ }
+
+ return NULL;
+}
diff --git a/SrcShared/Hardware/EmRegsEZPalmM100.h b/SrcShared/Hardware/EmRegsEZPalmM100.h
new file mode 100644
index 0000000..6b32d36
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsEZPalmM100.h
@@ -0,0 +1,41 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegsEZm100_h
+#define EmRegsEZm100_h
+
+#include "EmRegsEZ.h"
+
+class EmRegsEZPalmM100 : public EmRegsEZ
+{
+ public:
+ EmRegsEZPalmM100 (void);
+ virtual ~EmRegsEZPalmM100 (void);
+
+ virtual Bool GetLCDScreenOn (void);
+ virtual Bool GetLCDBacklightOn (void);
+ virtual Bool GetLineDriverState (EmUARTDeviceType type);
+
+ virtual uint8 GetPortInputValue (int);
+ virtual uint8 GetPortInternalValue (int);
+ virtual void GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows);
+
+ protected:
+ virtual EmSPISlave* GetSPISlave (void);
+
+ private:
+ EmSPISlave* fSPISlaveADC;
+};
+
+#endif /* EmRegsEZm100_h */
diff --git a/SrcShared/Hardware/EmRegsEZPalmV.cpp b/SrcShared/Hardware/EmRegsEZPalmV.cpp
new file mode 100644
index 0000000..ad59040
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsEZPalmV.cpp
@@ -0,0 +1,179 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmRegsEZPalmV.h"
+#include "EmRegsEZPrv.h"
+
+#include "EmDevice.h" // HardwareSubID
+#include "EmSession.h" // GetDevice
+#include "EmSPISlaveADS784x.h" // EmSPISlaveADS784x
+
+#include "PalmPack.h"
+#define NON_PORTABLE
+ #include "EZSumo/IncsPrv/HardwareEZ.h" // hwrEZPortCLCDEnableOn, etc.
+#undef NON_PORTABLE
+#include "PalmPackPop.h"
+
+const int kNumButtonRows = 3;
+const int kNumButtonCols = 4;
+
+const uint16 kButtonMap[kNumButtonRows][kNumButtonCols] =
+{
+ { keyBitHard1, keyBitHard2, keyBitHard3, keyBitHard4 },
+ { keyBitPageUp, keyBitPageDown, 0, 0 },
+ { keyBitPower, keyBitContrast, keyBitHard2, 0 }
+};
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmV::EmRegsEZPalmV
+// ---------------------------------------------------------------------------
+
+EmRegsEZPalmV::EmRegsEZPalmV (void) :
+ EmRegsEZ (),
+ fSPISlaveADC (new EmSPISlaveADS784x (kChannelSet2))
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmV::~EmRegsEZPalmV
+// ---------------------------------------------------------------------------
+
+EmRegsEZPalmV::~EmRegsEZPalmV (void)
+{
+ delete fSPISlaveADC;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmV::GetLCDScreenOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsEZPalmV::GetLCDScreenOn (void)
+{
+ return (READ_REGISTER (portCData) & hwrEZPortCLCDEnableOn) != 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmV::GetLCDBacklightOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsEZPalmV::GetLCDBacklightOn (void)
+{
+ return (READ_REGISTER (portFData) & hwrEZPortFBacklightOn) != 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmV::GetLineDriverState
+// ---------------------------------------------------------------------------
+// Return whether or not the line drivers for the given object are open or
+// closed.
+
+Bool EmRegsEZPalmV::GetLineDriverState (EmUARTDeviceType type)
+{
+ if (type == kUARTSerial)
+ return (READ_REGISTER (portDData) & hwrEZPortD232Enable) != 0;
+
+ if (type == kUARTIR)
+ return (READ_REGISTER (portGData) & hwrEZPortGIRShutdown) == 0;
+
+ return false;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmV::GetPortInputValue
+// ---------------------------------------------------------------------------
+// Return the GPIO values for the pins on the port. These values are used
+// if the select pins are high.
+
+uint8 EmRegsEZPalmV::GetPortInputValue (int port)
+{
+ uint8 result = EmRegsEZ::GetPortInputValue (port);
+
+ if (port == 'E')
+ {
+ // Return the hardware sub-ID.
+
+ EmAssert (gSession);
+
+ EmDevice device = gSession->GetDevice ();
+ result |= ~device.HardwareSubID ();
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmV::GetPortInternalValue
+// ---------------------------------------------------------------------------
+// Return the dedicated values for the pins on the port. These values are
+// used if the select pins are low.
+
+uint8 EmRegsEZPalmV::GetPortInternalValue (int port)
+{
+ uint8 result = EmRegsEZ::GetPortInternalValue (port);
+
+ if (port == 'D')
+ {
+ // Make sure that hwrEZPortDPowerFail is set. If it's clear,
+ // the battery code will make the device go to sleep immediately.
+
+ result |= hwrEZPortDPowerFail;
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmV::GetKeyInfo
+// ---------------------------------------------------------------------------
+
+void EmRegsEZPalmV::GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows)
+{
+ *numRows = kNumButtonRows;
+ *numCols = kNumButtonCols;
+
+ memcpy (keyMap, kButtonMap, sizeof (kButtonMap));
+
+ // Determine what row is being asked for.
+
+ UInt8 portFDir = READ_REGISTER (portFDir);
+ UInt8 portFData = READ_REGISTER (portFData);
+
+ rows[0] = (portFDir & hwrEZPortFKbdRow0) != 0 && (portFData & hwrEZPortFKbdRow0) == 0;
+ rows[1] = (portFDir & hwrEZPortFKbdRow1) != 0 && (portFData & hwrEZPortFKbdRow1) == 0;
+ rows[2] = (portFDir & hwrEZPortFKbdRow2) != 0 && (portFData & hwrEZPortFKbdRow2) == 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmV::GetSPISlave
+// ---------------------------------------------------------------------------
+
+EmSPISlave* EmRegsEZPalmV::GetSPISlave (void)
+{
+ if ((READ_REGISTER (portGData) & hwrEZPortGADCOff) == 0)
+ {
+ return fSPISlaveADC;
+ }
+
+ return NULL;
+}
diff --git a/SrcShared/Hardware/EmRegsEZPalmV.h b/SrcShared/Hardware/EmRegsEZPalmV.h
new file mode 100644
index 0000000..16dc0e0
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsEZPalmV.h
@@ -0,0 +1,42 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegsEZPalmV_h
+#define EmRegsEZPalmV_h
+
+#include "EmRegsEZ.h"
+
+
+class EmRegsEZPalmV : public EmRegsEZ
+{
+ public:
+ EmRegsEZPalmV (void);
+ virtual ~EmRegsEZPalmV (void);
+
+ virtual Bool GetLCDScreenOn (void);
+ virtual Bool GetLCDBacklightOn (void);
+ virtual Bool GetLineDriverState (EmUARTDeviceType type);
+
+ virtual uint8 GetPortInputValue (int);
+ virtual uint8 GetPortInternalValue (int);
+ virtual void GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows);
+
+ protected:
+ virtual EmSPISlave* GetSPISlave (void);
+
+ private:
+ EmSPISlave* fSPISlaveADC;
+};
+
+#endif /* EmRegsEZPalmV_h */
diff --git a/SrcShared/Hardware/EmRegsEZPalmVII.cpp b/SrcShared/Hardware/EmRegsEZPalmVII.cpp
new file mode 100644
index 0000000..edc6da7
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsEZPalmVII.cpp
@@ -0,0 +1,41 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmRegsEZPalmVII.h"
+#include "EmRegsEZPrv.h"
+
+#include "PalmPack.h"
+#define NON_PORTABLE
+ #include "EZSumo/IncsPrv/HardwareEZ.h" // hwrEZPortGIRShutdown
+#undef NON_PORTABLE
+#include "PalmPackPop.h"
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmVII::GetLineDriverState
+// ---------------------------------------------------------------------------
+// Return whether or not the line drivers for the given object are open or
+// closed.
+
+Bool EmRegsEZPalmVII::GetLineDriverState (EmUARTDeviceType type)
+{
+ if (type == kUARTSerial)
+ // Pass this on to the PLD handler.
+ return EmHALHandler::GetLineDriverState (type);
+
+ if (type == kUARTIR)
+ return (READ_REGISTER (portGData) & hwrEZPortGIRShutdown) == 0;
+
+ return false;
+}
diff --git a/SrcShared/Hardware/EmRegsEZPalmVII.h b/SrcShared/Hardware/EmRegsEZPalmVII.h
new file mode 100644
index 0000000..d5a4386
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsEZPalmVII.h
@@ -0,0 +1,26 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegsEZPalmVII_h
+#define EmRegsEZPalmVII_h
+
+#include "EmRegsEZPalmV.h"
+
+
+class EmRegsEZPalmVII : public EmRegsEZPalmV
+{
+ public:
+ virtual Bool GetLineDriverState (EmUARTDeviceType type);
+};
+
+#endif /* EmRegsEZPalmVII_h */
diff --git a/SrcShared/Hardware/EmRegsEZPalmVIIx.cpp b/SrcShared/Hardware/EmRegsEZPalmVIIx.cpp
new file mode 100644
index 0000000..1659dcc
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsEZPalmVIIx.cpp
@@ -0,0 +1,192 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmRegsEZPalmVIIx.h"
+#include "EmRegsEZPrv.h"
+
+#include "EmDevice.h" // HardwareSubID
+#include "EmSession.h" // GetDevice
+#include "EmSPISlaveADS784x.h" // EmSPISlaveADS784x
+
+#include "PalmPack.h"
+#define NON_PORTABLE
+ #include "EZSumo/IncsPrv/HardwareEZ.h" // hwrEZPortCLCDEnableOn, etc.
+#undef NON_PORTABLE
+#include "PalmPackPop.h"
+
+// As near as I can tell, PalmVIIx uses the same hardware defs as
+// a Sumo, but with this one bit difference. Actually, there are
+// other Port F and G differences, but they aren't (currently)
+// relevent to Poser.
+
+#undef hwrEZPortFKbdRow0
+#define hwrEZPortFKbdRow0 0x01 // (L) Keyboard Row 0
+
+
+const int kNumButtonRows = 3;
+const int kNumButtonCols = 4;
+
+
+// ============================== PalmVIIx ==============================
+
+const uint16 kButtonMap[kNumButtonRows][kNumButtonCols] =
+{
+ { keyBitHard1, keyBitHard2, keyBitHard3, keyBitHard4 },
+ { keyBitPageUp, keyBitPageDown, 0, 0 },
+ { keyBitPower, keyBitContrast, keyBitHard2, 0 }
+};
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmVIIx::EmRegsEZPalmVIIx
+// ---------------------------------------------------------------------------
+
+EmRegsEZPalmVIIx::EmRegsEZPalmVIIx (void) :
+ EmRegsEZ (),
+ fSPISlaveADC (new EmSPISlaveADS784x (kChannelSet2))
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmVIIx::~EmRegsEZPalmVIIx
+// ---------------------------------------------------------------------------
+
+EmRegsEZPalmVIIx::~EmRegsEZPalmVIIx (void)
+{
+ delete fSPISlaveADC;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmVIIx::GetLCDScreenOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsEZPalmVIIx::GetLCDScreenOn (void)
+{
+ return (READ_REGISTER (portCData) & hwrEZPortCLCDEnableOn) != 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmVIIx::GetLCDBacklightOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsEZPalmVIIx::GetLCDBacklightOn (void)
+{
+ return (READ_REGISTER (portFData) & hwrEZPortFBacklightOn) != 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmVIIx::GetLineDriverState
+// ---------------------------------------------------------------------------
+// Return whether or not the line drivers for the given object are open or
+// closed.
+
+Bool EmRegsEZPalmVIIx::GetLineDriverState (EmUARTDeviceType type)
+{
+ if (type == kUARTSerial)
+ // Pass this on to the PLD handler.
+ return EmHALHandler::GetLineDriverState (type);
+
+ if (type == kUARTIR)
+ return (READ_REGISTER (portGData) & hwrEZPortGIRShutdown) == 0;
+
+ return false;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmVIIx::GetPortInputValue
+// ---------------------------------------------------------------------------
+// Return the GPIO values for the pins on the port. These values are used
+// if the select pins are high.
+
+uint8 EmRegsEZPalmVIIx::GetPortInputValue (int port)
+{
+ uint8 result = EmRegsEZ::GetPortInputValue (port);
+
+ if (port == 'E')
+ {
+ // Return the hardware sub-ID.
+
+ EmAssert (gSession);
+
+ EmDevice device = gSession->GetDevice ();
+ result |= ~device.HardwareSubID ();
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmVIIx::GetPortInternalValue
+// ---------------------------------------------------------------------------
+// Return the dedicated values for the pins on the port. These values are
+// used if the select pins are low.
+
+uint8 EmRegsEZPalmVIIx::GetPortInternalValue (int port)
+{
+ uint8 result = EmRegsEZ::GetPortInternalValue (port);
+
+ if (port == 'D')
+ {
+ // Make sure that hwrEZPortDPowerFail is set. If it's clear,
+ // the battery code will make the device go to sleep immediately.
+
+ result |= hwrEZPortDPowerFail;
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmVIIx::GetKeyInfo
+// ---------------------------------------------------------------------------
+
+void EmRegsEZPalmVIIx::GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows)
+{
+ *numRows = kNumButtonRows;
+ *numCols = kNumButtonCols;
+
+ memcpy (keyMap, kButtonMap, sizeof (kButtonMap));
+
+ // Determine what row is being asked for.
+
+ UInt8 portFDir = READ_REGISTER (portFDir);
+ UInt8 portFData = READ_REGISTER (portFData);
+
+ rows[0] = (portFDir & hwrEZPortFKbdRow0) != 0 && (portFData & hwrEZPortFKbdRow0) == 0;
+ rows[1] = (portFDir & hwrEZPortFKbdRow1) != 0 && (portFData & hwrEZPortFKbdRow1) == 0;
+ rows[2] = (portFDir & hwrEZPortFKbdRow2) != 0 && (portFData & hwrEZPortFKbdRow2) == 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZPalmVIIx::GetSPISlave
+// ---------------------------------------------------------------------------
+
+EmSPISlave* EmRegsEZPalmVIIx::GetSPISlave (void)
+{
+ if ((READ_REGISTER (portGData) & hwrEZPortGADCOff) == 0)
+ {
+ return fSPISlaveADC;
+ }
+
+ return NULL;
+}
diff --git a/SrcShared/Hardware/EmRegsEZPalmVIIx.h b/SrcShared/Hardware/EmRegsEZPalmVIIx.h
new file mode 100644
index 0000000..57f8faa
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsEZPalmVIIx.h
@@ -0,0 +1,41 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegsEZPalmVIIx_h
+#define EmRegsEZPalmVIIx_h
+
+#include "EmRegsEZ.h"
+
+class EmRegsEZPalmVIIx : public EmRegsEZ
+{
+ public:
+ EmRegsEZPalmVIIx (void);
+ virtual ~EmRegsEZPalmVIIx (void);
+
+ virtual Bool GetLCDScreenOn (void);
+ virtual Bool GetLCDBacklightOn (void);
+ virtual Bool GetLineDriverState (EmUARTDeviceType type);
+
+ virtual uint8 GetPortInputValue (int);
+ virtual uint8 GetPortInternalValue (int);
+ virtual void GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows);
+
+ protected:
+ virtual EmSPISlave* GetSPISlave (void);
+
+ private:
+ EmSPISlave* fSPISlaveADC;
+};
+
+#endif /* EmRegsEZPalmVIIx_h */
diff --git a/SrcShared/Hardware/EmRegsEZPalmVx.h b/SrcShared/Hardware/EmRegsEZPalmVx.h
new file mode 100644
index 0000000..b348bb3
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsEZPalmVx.h
@@ -0,0 +1,21 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegsEZPalmVx_h
+#define EmRegsEZPalmVx_h
+
+#include "EmRegsEZPalmV.h"
+
+typedef EmRegsEZPalmV EmRegsEZPalmVx;
+
+#endif /* EmRegsEZPalmVx_h */
diff --git a/SrcShared/Hardware/EmRegsEZPrv.h b/SrcShared/Hardware/EmRegsEZPrv.h
new file mode 100644
index 0000000..660ea30
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsEZPrv.h
@@ -0,0 +1,45 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegsEZPrv_h
+#define EmRegsEZPrv_h
+
+#include "EmRegsPrv.h"
+
+// Location and range of registers
+
+const uint32 kMemoryStart = 0xFFFFF000;
+const uint32 kMemorySize = sizeof (HwrM68EZ328Type);
+
+
+// Macro to return the DragonballEZ address of the specified register
+
+#define addressof(x) (kMemoryStart + offsetof(HwrM68EZ328Type, x))
+
+
+// Macros for reading/writing DragonballEZ registers.
+
+#define READ_REGISTER(reg) \
+ _get_reg (&f68EZ328Regs.reg)
+
+#define WRITE_REGISTER(reg, value) \
+ _put_reg (&f68EZ328Regs.reg, value)
+
+
+// Macro for installing DragonballEZ register handlers
+
+#define INSTALL_HANDLER(read, write, reg) \
+ this->SetHandler ((ReadFunction) &EmRegsEZ::read, (WriteFunction) &EmRegsEZ::write, addressof (reg), sizeof (f68EZ328Regs.reg))
+
+
+#endif /* EmRegsEZPrv_h */
diff --git a/SrcShared/Hardware/EmRegsEZTRGpro.cpp b/SrcShared/Hardware/EmRegsEZTRGpro.cpp
new file mode 100644
index 0000000..cd7926f
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsEZTRGpro.cpp
@@ -0,0 +1,251 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+// This file provides emulation at the register level for TRG's
+// TRGpro handheld computer, which uses the EZ processor
+
+
+#include "EmCommon.h"
+#include "EmRegsEZTRGpro.h"
+#include "EmRegsEZPrv.h"
+
+#include "EmSPISlaveADS784x.h" // EmSPISlaveADS784x
+
+#include "PalmPack.h"
+#define NON_PORTABLE
+ #include "EZSumo/IncsPrv/HardwareEZ.h" // hwrEZPortCLCDEnableOn, etc.
+#undef NON_PORTABLE
+#include "PalmPackPop.h"
+
+// TRGpro Defines
+#define hwrEZPortDCFInit 0x40
+#define hwrEZPortGDO_LATCH 0x08 // SPI DO_LATCH enable
+#define hwrEZPortBLCDVccOff 0x02 // LCD VCC off
+#define hwrEZPortD232EnableTRGpro 0x20 // RS 232 enable
+
+const int kNumButtonRows = 3;
+const int kNumButtonCols = 4;
+
+const uint16 kButtonMap[kNumButtonRows][kNumButtonCols] =
+{
+ { keyBitHard1, keyBitHard2, keyBitHard3, keyBitHard4 },
+ { keyBitPageUp, keyBitPageDown, 0, 0 },
+ { keyBitPower, keyBitContrast, keyBitHard2, 0 }
+};
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZTRGpro::EmRegsEZTRGpro
+// ---------------------------------------------------------------------------
+
+EmRegsEZTRGpro::EmRegsEZTRGpro (CFBusManager ** fBusMgr) :
+ EmRegsEZ (),
+ fSPISlaveADC (new EmSPISlaveADS784x (kChannelSet2))
+{
+ *fBusMgr = &CFBus;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZTRGpro::~EmRegsEZTRGpro
+// ---------------------------------------------------------------------------
+
+EmRegsEZTRGpro::~EmRegsEZTRGpro (void)
+{
+ delete fSPISlaveADC;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZTRGpro::Initialize
+// ---------------------------------------------------------------------------
+
+void EmRegsEZTRGpro::Initialize(void)
+{
+ bBacklightOn = false;
+ CFBus.bEnabled = false;
+ CFBus.Width = kCFBusWidth16;
+ CFBus.bSwapped = false;
+ EmRegsEZ::Initialize();
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZTRGpro::GetLCDScreenOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsEZTRGpro::GetLCDScreenOn (void)
+{
+ return (READ_REGISTER (portCData) & hwrEZPortCLCDEnableOn) != 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZTRGpro::GetLCDBacklightOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsEZTRGpro::GetLCDBacklightOn (void)
+{
+ return (bBacklightOn);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZTRGpro::GetLineDriverState
+// ---------------------------------------------------------------------------
+// Return whether or not the line drivers for the given object are open or
+// closed.
+
+Bool EmRegsEZTRGpro::GetLineDriverState (EmUARTDeviceType type)
+{
+ if (type == kUARTSerial)
+ return (READ_REGISTER (portDData) & hwrEZPortD232EnableTRGpro) != 0;
+
+ if (type == kUARTIR)
+ return (READ_REGISTER (portGData) & 0x10) == 0;
+
+ return false;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZTRGpro::GetPortInputValue
+// ---------------------------------------------------------------------------
+// Return the GPIO values for the pins on the port. These values are used
+// if the select pins are high.
+
+uint8 EmRegsEZTRGpro::GetPortInputValue (int port)
+{
+ uint8 result = EmRegsEZ::GetPortInputValue (port);
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZTRGpro::GetPortInternalValue
+// ---------------------------------------------------------------------------
+// Return the dedicated values for the pins on the port. These values are
+// used if the select pins are low.
+
+uint8 EmRegsEZTRGpro::GetPortInternalValue (int port)
+{
+ uint8 result = EmRegsEZ::GetPortInternalValue (port);
+
+ if (port == 'D')
+ {
+ // Make sure that hwrEZPortDPowerFail is set. If it's clear,
+ // the battery code will make the device go to sleep immediately.
+
+ result |= (hwrEZPortDCFInit | hwrEZPortDPowerFail);
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZTRGpro::GetKeyInfo
+// ---------------------------------------------------------------------------
+
+void EmRegsEZTRGpro::GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows)
+{
+// KeyRowsType keyRows;
+
+ *numRows = kNumButtonRows;
+ *numCols = kNumButtonCols;
+
+ memcpy (keyMap, kButtonMap, sizeof (kButtonMap));
+
+ // Determine what row is being asked for.
+ rows[0] = Keys.Row[0];
+ rows[1] = Keys.Row[1];
+ rows[2] = Keys.Row[2];
+}
+
+void EmRegsEZTRGpro::LatchSpi(void)
+{
+ uint16 latched = spiUnlatchedVal;
+
+ bBacklightOn = ((latched & SPIBacklightOn) != 0);
+ CFBus.bEnabled = ((latched & (SPICardBufferOff |
+ SPICardSlotPwrOff)) == 0);
+ CFBus.bSwapped = ((latched & SPIBusSwapOff) == 0);
+ if (latched & SPIBusWidth8)
+ CFBus.Width = kCFBusWidth8;
+ else
+ CFBus.Width = kCFBusWidth16;
+ Keys.Row[0] = !(latched & SPIKeyRow0);
+ Keys.Row[1] = !(latched & SPIKeyRow1);
+ Keys.Row[2] = !(latched & SPIKeyRow2);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZTRGpro::GetKeyInfo
+// ---------------------------------------------------------------------------
+
+void EmRegsEZTRGpro::PortDataChanged (int port, uint8 oldValue, uint8 newValue)
+{
+ if (port == 'G')
+ {
+ // If the the DO_LATCH bit is set, then the recent value
+ // written to the SPI controller is for us, and not
+ // the touchscreen
+
+ if (newValue & hwrEZPortGDO_LATCH)
+ LatchSpi();
+ }
+
+ EmRegsEZ::PortDataChanged(port, oldValue, newValue);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZTRGpro::spiWrite
+//
+// We need to share SPI writes with the touchscreen ...
+// ---------------------------------------------------------------------------
+
+void EmRegsEZTRGpro::spiWrite(emuptr address, int size, uint32 value)
+{
+ spiUnlatchedVal = value;
+ EmRegsEZ::spiMasterControlWrite (address, size, value);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZTRGpro::SetSubBankHandlers
+// ---------------------------------------------------------------------------
+
+void EmRegsEZTRGpro::SetSubBankHandlers(void)
+{
+ EmRegsEZ::SetSubBankHandlers();
+ this->SetHandler((ReadFunction)&EmRegs::StdRead,
+ (WriteFunction)&EmRegsEZTRGpro::spiWrite,
+ addressof(spiMasterData),
+ sizeof(f68EZ328Regs.spiMasterData));
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZTRGpro::GetSPISlave
+// ---------------------------------------------------------------------------
+
+EmSPISlave* EmRegsEZTRGpro::GetSPISlave (void)
+{
+ if ((READ_REGISTER (portGData) & hwrEZPortGADCOff) == 0)
+ {
+ return fSPISlaveADC;
+ }
+
+ return NULL;
+}
diff --git a/SrcShared/Hardware/EmRegsEZTRGpro.h b/SrcShared/Hardware/EmRegsEZTRGpro.h
new file mode 100644
index 0000000..25f5c7e
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsEZTRGpro.h
@@ -0,0 +1,76 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegsEZTRGpro_h
+#define EmRegsEZTRGpro_h
+
+#include "EmRegsEZ.h"
+#include "EmHandEraCFBus.h"
+
+// --------------------------------------------------------------------------
+// This file is used to emulate the SPI controller ... the SPI performs
+// double duty for the TRGpro ... normally, it controls the touch screen ...
+// however, if a latch bit is set on Port D, it will use the SPI to
+// control the keypad and bus-state
+// --------------------------------------------------------------------------
+
+#define SPIKeyRow0 0x01
+#define SPIKeyRow1 0x02
+#define SPIKeyRow2 0x04
+#define SPIBusSwapOff 0x08
+#define SPIBacklightOn 0x10
+#define SPICardBufferOff 0x20
+#define SPICardSlotPwrOff 0x40
+#define SPIBusWidth8 0x80
+
+#define TRGPRO_NUM_KEY_ROWS 3
+
+typedef struct {
+ uint16 Row[TRGPRO_NUM_KEY_ROWS];
+} TrgProKeys;
+
+
+class EmRegsEZTRGpro : public EmRegsEZ
+{
+ public:
+ EmRegsEZTRGpro (CFBusManager ** fBusManager);
+ virtual ~EmRegsEZTRGpro (void);
+
+ virtual void Initialize (void);
+ virtual Bool GetLCDScreenOn (void);
+ virtual Bool GetLCDBacklightOn (void);
+ virtual Bool GetLineDriverState (EmUARTDeviceType type);
+
+ virtual uint8 GetPortInputValue (int);
+ virtual uint8 GetPortInternalValue (int);
+ virtual void GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows);
+ virtual void PortDataChanged (int, uint8, uint8);
+ void SetSubBankHandlers(void);
+ private:
+ void spiWrite(emuptr address, int size, uint32 value);
+ uint16 spiLatchedVal, spiUnlatchedVal;
+ void LatchSpi(void);
+
+
+ protected:
+ virtual EmSPISlave* GetSPISlave (void);
+
+ private:
+ EmSPISlave* fSPISlaveADC;
+ CFBusManager CFBus;
+ TrgProKeys Keys;
+ int bBacklightOn;
+};
+
+#endif /* EmRegsEZTRGpro_h */
diff --git a/SrcShared/Hardware/EmRegsEZTemp.cpp b/SrcShared/Hardware/EmRegsEZTemp.cpp
new file mode 100644
index 0000000..a0725f5
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsEZTemp.cpp
@@ -0,0 +1,18 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmRegsEZTemp.h"
+#include "EmRegsEZPrv.h"
+
+
diff --git a/SrcShared/Hardware/EmRegsEZTemp.h b/SrcShared/Hardware/EmRegsEZTemp.h
new file mode 100644
index 0000000..7818645
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsEZTemp.h
@@ -0,0 +1,18 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegsEZTemp_h
+#define EmRegsEZTemp_h
+
+
+#endif /* EmRegsEZTemp_h */
diff --git a/SrcShared/Hardware/EmRegsEZVisor.cpp b/SrcShared/Hardware/EmRegsEZVisor.cpp
new file mode 100644
index 0000000..166158c
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsEZVisor.cpp
@@ -0,0 +1,243 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmRegsEZVisor.h"
+#include "EmRegsEZPrv.h"
+
+#include "EmDevice.h" // HardwareID
+#include "EmSession.h" // GetDevice
+#include "EmSPISlaveADS784x.h" // EmSPISlaveADS784x
+
+
+const uint16 kVisorButtonMap[kNumButtonRows][kNumButtonCols] =
+{
+ { keyBitHard1, keyBitHard2, keyBitHard3 },
+ { keyBitPageUp, keyBitPageDown, 0 },
+ { keyBitPower, keyBitHard4, 0 }
+};
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZVisor::EmRegsEZVisor
+// ---------------------------------------------------------------------------
+
+EmRegsEZVisor::EmRegsEZVisor (void) :
+ EmRegsEZ (),
+ fSPISlaveADC (new EmSPISlaveADS784x (kChannelSet2))
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZVisor::~EmRegsEZVisor
+// ---------------------------------------------------------------------------
+
+EmRegsEZVisor::~EmRegsEZVisor (void)
+{
+ delete fSPISlaveADC;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZVisor::GetLCDScreenOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsEZVisor::GetLCDScreenOn (void)
+{
+ return (READ_REGISTER (portCData) & hwrLegoPortCLCDEnableOn) != 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZVisor::GetLCDBacklightOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsEZVisor::GetLCDBacklightOn (void)
+{
+ return (READ_REGISTER (portGData) & hwrLegoPortGBacklightOff) == 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZVisor::GetLineDriverState
+// ---------------------------------------------------------------------------
+// Return whether or not the line drivers for the given object are open or
+// closed.
+
+Bool EmRegsEZVisor::GetLineDriverState (EmUARTDeviceType type)
+{
+ if (type == kUARTSerial)
+ {
+ uint16 uControl = READ_REGISTER (uControl);
+ uint16 uMisc = READ_REGISTER (uMisc);
+
+ return (uControl & hwrEZ328UControlUARTEnable) != 0 &&
+ (uMisc & hwrEZ328UMiscIRDAEn) == 0;
+ }
+
+ if (type == kUARTIR)
+ {
+ uint16 uControl = READ_REGISTER (uControl);
+ uint16 uMisc = READ_REGISTER (uMisc);
+
+ return (uControl & hwrEZ328UControlUARTEnable) != 0 &&
+ (uMisc & hwrEZ328UMiscIRDAEn) != 0;
+ }
+
+ return false;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZVisor::GetPortInputValue
+// ---------------------------------------------------------------------------
+// Return the GPIO values for the pins on the port. These values are used
+// if the select pins are high.
+
+uint8 EmRegsEZVisor::GetPortInputValue (int port)
+{
+ uint8 result = EmRegsEZ::GetPortInputValue (port);
+
+ if (port == 'E')
+ {
+ /*
+ Support the Visor model ID. From Bob Petersen at Handspring:
+
+ The Visor ROM only works with 1 device so far. But, the Visor does have
+ model detect pins so that future ROMs can work on multiple platforms. The
+ model input pins are connected to port E, bits 0-2 (E[0-2]). To read them,
+ you have to drive port G bit 2 low and enable the pullups on port E.
+ */
+
+#define modelOutPin 0x04 // EMUIRQ (IRQ7)
+#define modelInPins 0x07 // SPI pins on Visor
+
+ UInt8 portGData = READ_REGISTER (portGData);
+ UInt8 portGDir = READ_REGISTER (portGDir);
+ UInt8 portGSelect = READ_REGISTER (portGSelect);
+
+ if (((portGData & modelOutPin) == 0) &&
+ ((portGDir & modelOutPin) == modelOutPin) &&
+ ((portGSelect & modelOutPin) == modelOutPin))
+ {
+ EmAssert (gSession);
+
+ EmDevice device = gSession->GetDevice ();
+ result |= (~device.HardwareID ()) & modelInPins; // <chg 24-Apr-2000 BP> expects inverse output
+ }
+ else
+ {
+ // The pin for detecting "in cradle" is hwrLegoPortEDock2Off. It should be low
+ // if in the serial cradle. If it is high, we assume USB.
+ // -- Bob Petersen
+
+ result &= ~hwrLegoPortEDock2Off;
+ }
+ }
+ else if (port == 'G')
+ {
+ // Make sure that hwrLegoPortGPowerFailIrqOff is set. If it's clear,
+ // the battery code will make the device go to sleep immediately.
+
+ result |= hwrLegoPortGPowerFailIrqOff;
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZVisor::GetPortInternalValue
+// ---------------------------------------------------------------------------
+// Return the dedicated values for the pins on the port. These values are
+// used if the select pins are low.
+
+uint8 EmRegsEZVisor::GetPortInternalValue (int port)
+{
+ uint8 result = EmRegsEZ::GetPortInternalValue (port);
+
+ if (port == 'D')
+ {
+ // Always set the high bit, indicating that there's no memory module
+ // installed. From Bob Petersen at Handspring:
+ //
+ // This is a probe into the module memory, to check for a replacement ROM on a
+ // card that is plugged in. The card is mapped to 0x20000000 and the card's
+ // ROM is at 0x28000000. If it finds the card header (FEEDBEEF) and the card
+ // is plugged in that has a non-zero reset vector, the chip selects are changed
+ // so B0 addresses 10c00000, and then we jump to the reset vector and boot off
+ // the card.
+ //
+ // This part of the boot code should only be called if it is detected that a
+ // card is currently plugged in (bit 7 of port D) and we aren't currently
+ // booting from the card.
+
+ result |= hwrLegoPortDCardInstIrqOff;
+
+ // Ensure that bit hwrLegoPortDDock1IrqOff is set. If it's clear, HotSync
+ // will sync via the modem instead of the serial port.
+
+ result |= hwrLegoPortDDock1IrqOff;
+ }
+ else if (port == 'G')
+ {
+ // Make sure that hwrLegoPortGPowerFailIrqOff is set. If it's clear,
+ // the battery code will make the device go to sleep immediately.
+
+ result |= hwrLegoPortGPowerFailIrqOff;
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZVisor::GetKeyInfo
+// ---------------------------------------------------------------------------
+
+void EmRegsEZVisor::GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows)
+{
+ *numRows = kNumButtonRows;
+ *numCols = kNumButtonCols;
+
+ memcpy (keyMap, kVisorButtonMap, sizeof (kVisorButtonMap));
+
+ // Determine what row is being asked for.
+
+ UInt8 portDDir = READ_REGISTER (portDDir);
+ UInt8 portDData = READ_REGISTER (portDData);
+
+ UInt8 portGDir = READ_REGISTER (portGDir);
+ UInt8 portGData = READ_REGISTER (portGData);
+
+ rows[0] = (portGDir & hwrLegoPortGKbdRow0) != 0 && (portGData & hwrLegoPortGKbdRow0) == 0;
+ rows[1] = (portGDir & hwrLegoPortGKbdRow1) != 0 && (portGData & hwrLegoPortGKbdRow1) == 0;
+ rows[2] = (portDDir & hwrLegoPortDKbdRow2) != 0 && (portDData & hwrLegoPortDKbdRow2) == 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZVisor::GetSPISlave
+// ---------------------------------------------------------------------------
+
+EmSPISlave* EmRegsEZVisor::GetSPISlave (void)
+{
+ if ((READ_REGISTER (portGData) & hwrLegoPortGAdcCsOff) == 0)
+ {
+ return fSPISlaveADC;
+ }
+
+ return NULL;
+}
diff --git a/SrcShared/Hardware/EmRegsEZVisor.h b/SrcShared/Hardware/EmRegsEZVisor.h
new file mode 100644
index 0000000..d71c711
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsEZVisor.h
@@ -0,0 +1,131 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegsEZVisor_h
+#define EmRegsEZVisor_h
+
+#include "EmRegsEZ.h"
+
+// Handspring modelID defines
+// DOLATER BP: move the general Handspring-specific stuff to another include file
+#define halModelChipIDEZ 0x00 // 0000 0
+#define halModelChipIDVZ 0x08 // 0000 1
+//#define halModelChipIDXZ 0x10 // 0001 0 placeholder
+
+#define halModelEZIndexLego 0x00 // 000
+
+#define halModelVZIndexVisorPlatinum 0x00 // 000
+#define halModelVZIndexVisorPrism 0x02 // 010
+#define halModelVZIndexVisorEdge 0x01 // 001
+
+
+// Model IDs (combinations of the above)...
+// ----------------------------------------
+#define halModelIDLego (halModelChipIDEZ | halModelEZIndexLego) // Lego (Visor)
+#define halModelIDVisorPlatinum (halModelChipIDVZ | halModelVZIndexVisorPlatinum)
+#define halModelIDVisorPrism (halModelChipIDVZ | halModelVZIndexVisorPrism)
+#define halModelIDVisorEdge (halModelChipIDVZ | halModelVZIndexVisorEdge)
+
+
+// Visor pin definitions from Handspring. Mostly the same as a Palm V,
+// but with some pins changed and moved around.
+
+
+/************************************************************************
+ * Port B Bit settings
+ ************************************************************************/
+#define hwrLegoPortBLCDVccOff 0x08 // (L) LCD Vcc
+#define hwrLegoPortBLCDAdjOn 0x40 // (H) LCD Contrast Voltage
+
+
+/************************************************************************
+ * Port C Bit settings
+ ************************************************************************/
+#define hwrLegoPortCLCDEnableOn 0x80 // (H) LCD Enable
+
+
+/************************************************************************
+ * Port D Bit settings
+ ************************************************************************/
+#define hwrLegoPortDKbdCol0On 0x01 // (H) Keyboard Column 0
+#define hwrLegoPortDKbdCol1On 0x02 // (H) Keyboard Column 1
+#define hwrLegoPortDKbdCol2On 0x04 // (H) Keyboard Column 2
+
+#define hwrLegoPortDKbdRow2 0x08 // (H) Keyboard Row 2
+
+#define hwrLegoPortDDock1IrqOff 0x10 // (L) Dock1 interrupt
+#define hwrLegoPortDSlotIrqOff 0x20 // (L) Slot Interrupt
+#define hwrLegoPortDUsbIrqOff 0x40 // (L) USB Interrupt
+#define hwrLegoPortDCardInstIrqOff 0x80 // (L) Card Installed Interrupt
+
+#define hwrLegoPortDKeyBits 0x07 // (H) All Keyboard Columns
+
+
+
+/************************************************************************
+ * Port E Bit settings
+ ************************************************************************/
+#define hwrLegoPortESerialTxD 0x20 // ( ) Serial transmit line
+#define hwrLegoPortESlotResetOff 0x40 // (L) Slot reset
+#define hwrLegoPortEDock2Off 0x80 // (L) Dock2 input
+
+
+/************************************************************************
+ * Port F Bit settings
+ ************************************************************************/
+#define hwrLegoPortFContrast 0x01 // ( ) LCD Contrast PWM output
+#define hwrLegoPortFIREnableOff 0x04 // (L) Shutdown IR
+#define hwrLegoPortFUsbCsOff 0x80 // (L) USB chip select
+
+
+/************************************************************************
+ * Port G Bit settings
+ ************************************************************************/
+#define hwrLegoPortGBacklightOff 0x01 // (L) Backlight on/off
+#define hwrLegoPortGUSBSuspend 0x02 // (X) USB Suspend bit - Output low for active
+ // - Input for suspend
+#define hwrLegoPortGPowerFailIrqOff 0x04 // (L) Power Fail IRQ
+#define hwrLegoPortGKbdRow0 0x08 // (H) Keyboard Row 0
+#define hwrLegoPortGKbdRow1 0x10 // (H) Keyboard Row 1
+#define hwrLegoPortGAdcCsOff 0x20 // (L) A/D Select
+
+
+const int kNumButtonRows = 3;
+const int kNumButtonCols = 3;
+
+extern const uint16 kVisorButtonMap[kNumButtonRows][kNumButtonCols];
+
+
+class EmRegsEZVisor : public EmRegsEZ
+{
+ public:
+ EmRegsEZVisor (void);
+ virtual ~EmRegsEZVisor (void);
+
+ virtual Bool GetLCDScreenOn (void);
+ virtual Bool GetLCDBacklightOn (void);
+ virtual Bool GetLineDriverState (EmUARTDeviceType type);
+
+ virtual uint8 GetPortInputValue (int);
+ virtual uint8 GetPortInternalValue (int);
+ virtual void GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows);
+
+ protected:
+ virtual EmSPISlave* GetSPISlave (void);
+
+ private:
+ EmSPISlave* fSPISlaveADC;
+};
+
+#endif /* EmRegsEZVisor_h */
diff --git a/SrcShared/Hardware/EmRegsFrameBuffer.cpp b/SrcShared/Hardware/EmRegsFrameBuffer.cpp
new file mode 100644
index 0000000..cb436fd
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsFrameBuffer.cpp
@@ -0,0 +1,241 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmRegsFrameBuffer.h"
+
+#include "Byteswapping.h" // ByteswapWords
+#include "EmMemory.h" // EmMemDoGet32
+#include "EmScreen.h" // EmScreen::MarkDirty
+#include "Miscellaneous.h" // StWordSwapper
+#include "Platform.h" // Platform::AllocateMemoryClear
+#include "SessionFile.h" // SessionFile
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsFrameBuffer::EmRegsFrameBuffer
+// ---------------------------------------------------------------------------
+
+EmRegsFrameBuffer::EmRegsFrameBuffer (emuptr baseAddr, int32 size) :
+ fBaseAddr (baseAddr),
+ fSize (size),
+ fVideoMem (NULL)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsFrameBuffer::~EmRegsFrameBuffer
+// ---------------------------------------------------------------------------
+
+EmRegsFrameBuffer::~EmRegsFrameBuffer (void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsFrameBuffer::Initialize
+// ---------------------------------------------------------------------------
+
+void EmRegsFrameBuffer::Initialize (void)
+{
+ EmRegs::Initialize ();
+
+ // Allocate a chunk of memory for the VRAM space.
+
+ if (!fVideoMem)
+ {
+ fVideoMem = Platform::AllocateMemoryClear (fSize);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsFrameBuffer::Reset
+// ---------------------------------------------------------------------------
+
+void EmRegsFrameBuffer::Reset (Bool hardwareReset)
+{
+ EmRegs::Reset (hardwareReset);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsFrameBuffer::Save
+// ---------------------------------------------------------------------------
+
+void EmRegsFrameBuffer::Save (SessionFile& f)
+{
+ EmRegs::Save (f);
+
+ StWordSwapper swapper (fVideoMem, fSize);
+ f.WriteSED1375Image (fVideoMem, fSize);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsFrameBuffer::Load
+// ---------------------------------------------------------------------------
+
+void EmRegsFrameBuffer::Load (SessionFile& f)
+{
+ EmRegs::Load (f);
+
+ // Read in the LCD image, and then byteswap it.
+
+ if (f.ReadSED1375Image (fVideoMem))
+ {
+ ByteswapWords (fVideoMem, fSize);
+ }
+ else
+ {
+ f.SetCanReload (false);
+ }
+
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsFrameBuffer::Dispose
+// ---------------------------------------------------------------------------
+
+void EmRegsFrameBuffer::Dispose (void)
+{
+ EmRegs::Dispose ();
+
+ Platform::DisposeMemory (fVideoMem);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsFrameBuffer::GetLong
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsFrameBuffer::GetLong (emuptr address)
+{
+ uint32 offset = address - fBaseAddr;
+ return EmMemDoGet32 (((uint8*) fVideoMem) + offset);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsFrameBuffer::GetWord
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsFrameBuffer::GetWord (emuptr address)
+{
+ uint32 offset = address - fBaseAddr;
+ return EmMemDoGet16 (((uint8*) fVideoMem) + offset);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsFrameBuffer::GetByte
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsFrameBuffer::GetByte (emuptr address)
+{
+ uint32 offset = address - fBaseAddr;
+ return EmMemDoGet8 (((uint8*) fVideoMem) + offset);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsFrameBuffer::SetLong
+// ---------------------------------------------------------------------------
+
+void EmRegsFrameBuffer::SetLong (emuptr address, uint32 value)
+{
+ uint32 offset = address - fBaseAddr;
+ EmMemDoPut32 (((uint8*) fVideoMem) + offset, value);
+ EmScreen::MarkDirty (address, 4);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsFrameBuffer::SetWord
+// ---------------------------------------------------------------------------
+
+void EmRegsFrameBuffer::SetWord (emuptr address, uint32 value)
+{
+ uint32 offset = address - fBaseAddr;
+ EmMemDoPut16 (((uint8*) fVideoMem) + offset, value);
+ EmScreen::MarkDirty (address, 2);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsFrameBuffer::SetByte
+// ---------------------------------------------------------------------------
+
+void EmRegsFrameBuffer::SetByte (emuptr address, uint32 value)
+{
+ uint32 offset = address - fBaseAddr;
+ EmMemDoPut8 (((uint8*) fVideoMem) + offset, value);
+ EmScreen::MarkDirty (address, 1);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsFrameBuffer::ValidAddress
+// ---------------------------------------------------------------------------
+
+int EmRegsFrameBuffer::ValidAddress (emuptr address, uint32 size)
+{
+ UNUSED_PARAM (address);
+ UNUSED_PARAM (size);
+
+ return true;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsFrameBuffer::SetSubBankHandlers
+// ---------------------------------------------------------------------------
+
+void EmRegsFrameBuffer::SetSubBankHandlers (void)
+{
+ // We don't have handlers for each byte of memory, so there's nothing
+ // to install here.
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsFrameBuffer::GetRealAddress
+// ---------------------------------------------------------------------------
+
+uint8* EmRegsFrameBuffer::GetRealAddress (emuptr address)
+{
+ uint32 offset = address - fBaseAddr;
+ return (uint8*) fVideoMem + offset;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsFrameBuffer::GetAddressStart
+// ---------------------------------------------------------------------------
+
+emuptr EmRegsFrameBuffer::GetAddressStart (void)
+{
+ return fBaseAddr;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsFrameBuffer::GetAddressRange
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsFrameBuffer::GetAddressRange (void)
+{
+ return fSize;
+}
diff --git a/SrcShared/Hardware/EmRegsFrameBuffer.h b/SrcShared/Hardware/EmRegsFrameBuffer.h
new file mode 100644
index 0000000..e2d4741
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsFrameBuffer.h
@@ -0,0 +1,52 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegsFrameBuffer_h
+#define EmRegsFrameBuffer_h
+
+#include "EmRegs.h"
+
+class SessionFile;
+
+
+class EmRegsFrameBuffer : public EmRegs
+{
+ public:
+ EmRegsFrameBuffer (emuptr baseAddr, int32 size);
+ virtual ~EmRegsFrameBuffer (void);
+
+ virtual void Initialize (void);
+ virtual void Reset (Bool hardwareReset);
+ virtual void Save (SessionFile&);
+ virtual void Load (SessionFile&);
+ virtual void Dispose (void);
+
+ virtual uint32 GetLong (emuptr address);
+ virtual uint32 GetWord (emuptr address);
+ virtual uint32 GetByte (emuptr address);
+ virtual void SetLong (emuptr address, uint32 value);
+ virtual void SetWord (emuptr address, uint32 value);
+ virtual void SetByte (emuptr address, uint32 value);
+ virtual int ValidAddress (emuptr address, uint32 size);
+ virtual void SetSubBankHandlers (void);
+ virtual uint8* GetRealAddress (emuptr address);
+ virtual emuptr GetAddressStart (void);
+ virtual uint32 GetAddressRange (void);
+
+ private:
+ emuptr fBaseAddr;
+ int32 fSize;
+ void* fVideoMem;
+};
+
+#endif /* EmRegsFrameBuffer_h */
diff --git a/SrcShared/Hardware/EmRegsMediaQ11xx.cpp b/SrcShared/Hardware/EmRegsMediaQ11xx.cpp
new file mode 100644
index 0000000..19506b0
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsMediaQ11xx.cpp
@@ -0,0 +1,4791 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 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 "EmRegsMediaQ11xx.h"
+
+#include "EmCPU68K.h" // gCPU68K
+#include "EmPixMap.h" // EmPixMap::GetLCDScanlines
+#include "EmScreen.h" // EmScreen::InvalidateAll
+#include "SessionFile.h" //
+
+#include "Logging.h" // LogAppendMsg
+
+#include <algorithm> // swap
+
+
+#define LOG_LINE 0
+#define PRINTF_LINE if (!LOG_LINE) ; else LogAppendMsg
+
+#define LOG_BLIT 0
+#define PRINTF_BLIT if (!LOG_BLIT) ; else LogAppendMsg
+
+
+/* --------------------------------------------------------------------------- *\
+ MediaQ Graphics Engine overview and description
+ -----------------------------------------------
+
+ The MediaQ 1100/1132 chip contains a graphics engine used for accelerating
+ graphics drawing operations. It has the following features:
+
+ * Line drawing
+ * Rectangle operations (fill, scroll, and BLT)
+ * Arbitrary transfer operations (using Windows ROP definitions)
+ * Monochrome and color source data
+ * Monochrome pattern data
+ * Colorization of monochrome source and pattern data
+ * Transparency support
+ * Clipping support
+ * Automatic screen flipping
+
+ There are 20 registers reserved for the graphics accelerator. The MediaQ
+ client generally works by storing necessary values in a subset of those
+ registers, and then kicks off the drawing process by updating the register
+ that receives the drawing command. This register (GE00R) is the master
+ control register. It contains all of the top-level information about what
+ is to be drawn and how. As needed, other registers are queried for
+ additional values needed for the operation. Registers not required for
+ the drawing operation need not be updated before the drawing command is
+ issued. The drawing operation takes place asynchronously, freeing up the
+ MediaQ client for other tasks.
+
+ The graphics chip makes use of two FIFOs: a command FIFO and a source data
+ FIFO. The command FIFO is used to make sure that registers are not
+ updated and changed out from under a drawing operation currently in
+ progress. That is, any write access to a register really results in an
+ entry being added to the command FIFO. Entries are then popped off and
+ used to update the registers. If the command register is written to, the
+ drawing operation commences. Any subsequent writes to registers will
+ still be added to the FIFO, but will stay there until the drawing
+ operation has completed. If the FIFO is full (it has room only for 16
+ commands), the main CPU will stall if it tries to add any more commands.
+
+ Sometimes the drawing operation requires "source data", that is, data from
+ main memory. The MediaQ chip doesn't have direct access to main RAM, and
+ so data from there needs to be fed in through a source FIFO. After a
+ drawing command has been started that requires source data, the MediaQ
+ client must go into a loop and ensure that this source data FIFO is filled
+ with the necessary data. Note that this source FIFO contains 16 64-bit
+ slots. Therefore, the client needs to make sure that information written
+ to the FIFO occurs in multiples of 64-bits (or 8 bytes).
+
+ GEState
+ -------
+
+ This Poser-defined structure is a mirror of the registers used by the
+ MediaQ graphics acceleration engine. It breaks out all of the pieces of
+ information packed into those registers, and stores each piece into its
+ own field for easy access. This unpacking takes place as needed,
+ generally when a graphics drawing command is issued.
+
+ Following is a description of all the registers and the fields within
+ those registers. After that are included some notes on how those
+ registers fit into the bigger picture.
+
+ **************************************************************************
+ ==========================================================================
+ GE00R
+ ==========================================================================
+
+ GE00R[7:0] rasterOperation
+ -----------------------------------------------
+ Specifies the transfer mode. That is, it defines the way in which the
+ source data, destination data, and pattern data are combined to
+ produce the final destination or output data. The values that can be
+ used here are the same that Microsoft has defined for GDI.
+
+ This register can contain either the ternary ROP codes or the binary
+ ROP2 codes, depending on the setting of rop2Select (GE00R[25]).
+
+ GE00R[10:8] commandType
+ -----------------------------------------------
+ Specifies the drawing command. Can be one of three values:
+
+ 0 = NOP
+ 2 = BitBLT
+ 4 = Line
+
+ All other values are either reserved or undefined.
+
+ Note that BitBLT is used for drawing filled rectangles, scrolling
+ images in the screen memory, or copy images from main memory to the
+ screen memory. Monochrome and color source data and patterns are
+ supported.
+
+ GE00R[11] xDirection
+ GE00R[12] yDirection
+ -----------------------------------------------
+ Defines the direction in which a BitBLT or line drawing operation
+ occurs. Values of zero indicate the positive (right or down)
+ direction; values of one indicate the negative (left or up) direction.
+ When drawing a line, note that these fields are used only if the
+ useXY field is set.
+
+ GE00R[13] systemMemory
+ -----------------------------------------------
+ If true, specifies that any source data comes from the source FIFO.
+ Otherwise, the data comes from display memory, and xSrc (GE03R[11:0])
+ and ySrc (GE03R[27:16]) need to be programmed.
+
+ GE00R[14] monoSource
+ -----------------------------------------------
+ Specifies whether the source data is a monochrome (aka, bitonal)
+ bitmap where each pixel is represented by a single bit, or that the
+ source data is in color format, where each pixel is defined by an 8 or
+ 16 bit value, depending on the setting of colorDepth (GE0AR[31:30]).
+
+ GE00R[15] monoPattern
+ -----------------------------------------------
+ Specifies whether the pattern data is a monochrome (aka, bitonal)
+ bitmap where each pixel is represented by a single bit, or that the
+ pattern data is in color format, where each pixel is defined by an 8
+ or 16 bit value. Note that in the current chip, this bit *MUST* be
+ set to 1, indicating a monochrome pattern. There doesn't appear to be
+ any support or any way to specify a color pattern.
+
+ GE00R[16] colorTransEnable
+ -----------------------------------------------
+ Setting this bit enables transparent BitBLT operations when the source
+ data is in color format. It works in conjunction with
+ destTransPolarity, colorTransCmpSrc, and destTransColor to determine
+ if the destination pixel is updated or stays the same.
+
+ GE00R[17] destTransPolarity
+ -----------------------------------------------
+ If color transparency is enabled (that is, colorTransEnable is set),
+ determines how transparency is achieved. Depending on the setting of
+ colorTransCmpSrc, either the source data or the dest data is compared
+ to destTransColor. If destTransPolarity is zero, then the destination
+ pixel is updated if the result of the comparison is not equal. If
+ destTransPolarity is one, then the destination pixel is update if the
+ result is equal.
+
+ GE00R[18] monoTransEnable
+ -----------------------------------------------
+ Setting this bit enables transparent BitBLT operations when the source
+ data is in monochrome format. It works in conjunction with
+ monoTransPolarity to determine if the destination pixel is updated or
+ stays the same.
+
+ GE00R[19] monoTransPolarity
+ -----------------------------------------------
+ If monochrome transparency is enabled (that is, monoTransEnable is
+ set), determines how transparency is achieved. If this value is zero,
+ then background (that is, zero) bits in the source are treated as
+ transparent and don't update the destination. If this value is one,
+ then foreground (that is, one) bits in the source data are treated as
+ transparent.
+
+ GE00R[20] memToScreen
+ -----------------------------------------------
+ Specifies LINED (memToScreen == 0) or PACKED (memToScreen == 1) blit
+ transfer mode. PACKED Mode allows bitmaps that are compact to be
+ transferred more efficiently. LINE Mode requires each line of bitmap
+ to be aligned at 64-bit and thus could require padding and realignment
+ if each line of bitmap to be transfer is non-64-bit aligned.
+
+ GE00R[23] solidSourceColor
+ -----------------------------------------------
+ If set, the actual color source data is effectively ignored, and
+ instead treated as if it were all fgColorMonoSrc.
+
+ GE00R[24] srcEqualDestStride
+ -----------------------------------------------
+ Specifies whether or not the dest and source have the same "strides"
+ (that is, "rowBytes" in other terminologies). If the source is the
+ display, then the source will always be the same as the dest. But if
+ the source is main memory, then the data comes in through the source
+ FIFO, and I'm not sure how stride comes in to play there.
+
+ GE00R[25] rop2Select
+ -----------------------------------------------
+ Causes the value in rasterOperation (GE00R[7:0]) to be treated as a
+ binary ROP2 value instead of a ternary ROP value. The documentation
+ says that "[3:0] is duplicated to [7:4]". However, it's not clear to
+ me is the programmer is required to write the register in this
+ duplicated fashion, or if the hardware aliases the low values into the
+ high values in some way. In either case, I'm not sure why the
+ hardware cares. Why wouldn't it just look at the low 4 bits and
+ ignore the upper 4 bits. My guess is that the hardware performs this
+ aliasing on its own, and that the result when looking at all 8 bits
+ has the result of acting like a binary ROP2 code (that is, the any
+ source data will be ignored -- see comments in PrvUsesSource on how
+ the ROP value can be examined to see if the pattern, source or
+ destination have any role in determining the final output value).
+
+ GE00R[26] clipEnable
+ -----------------------------------------------
+ Enable clipping according to the clipLeft, clipTop, clipRight, and
+ clipBottom fields (registers GE05R and GE06R).
+
+ GE00R[27] autoExecute
+ -----------------------------------------------
+ Setting this bit enables auto-execution of the command after the
+ destination XY register (GE02R) is written. If it's clear, the
+ graphics engine command execution starts the command register (GE00R)
+ is written.
+
+ GE00R[30] solidPattern
+ -----------------------------------------------
+ If set, then all pattern data is forced to the value of the pattern
+ foreground color register (GE12R).
+
+ GE00R[31] colorTransCmpSrc
+ -----------------------------------------------
+ Used in conjunction with the transparency-enable bits, determines if
+ the color to be compared comes from the source or destination.
+ Compare to the source data if it's zero, destination if it's one.
+
+ ==========================================================================
+ GE01R
+ ==========================================================================
+
+ GE01R[11:0] (BitBLT) width
+ GE01R[27:16] (BitBLT) height
+ -----------------------------------------------
+ When a BitBLT operation has been specified, these fields contain the
+ dimensions (in pixels) of the operation. It is used for both the
+ source and destination.
+
+ GE01R[31] (BitBLT) xyConversion
+ -----------------------------------------------
+ When a BitBLT operation has been specified, this field controls how
+ the starting x/y values are interpreted. If this bit is clear, then
+ the specified x/y values are the first pixel updated. If this bit is
+ set, then the specified x/y values are the top/left corner of the
+ rectangle that's updated.
+
+ GE01R[16:0] (Line) gamma
+ -----------------------------------------------
+ When a line drawing operation has been specified, contains a value
+ identified as "gamma". This is defined in the documentation as
+ "either -(dm >> 1) - 1 or -(dm >> 1), depending on the quadrant",
+ where "dm" is the major axis delta. However, there's no mention of
+ which value is used in what situations. As well, our source code
+ writes to this field a value that has the same magnitude of dm. That
+ is dm gets written to its designated field, and -dm gets written to
+ gamma.
+
+ GE01R[28:17] (Line) majorLength
+ -----------------------------------------------
+ When a line drawing operation has been specified, contains the length
+ along the major axis.
+
+ GE01R[29] (Line) yIsMajor
+ -----------------------------------------------
+ When a line drawing operation has been specified, specifies which axis
+ is the major axis (that is, the "long" axis -- a "mostly horizontal"
+ line has X as the major axis, while a "mostly vertical" line has Y as
+ the major axis, and a diagonal line can have either defines as its
+ major axis). If set, Y is the major axis. Otherwise, X is the major
+ axis. Note that this field is used only if the useXY field is set.
+
+ GE01R[30] (Line) drawLastPixel
+ -----------------------------------------------
+ When a line drawing operation has been specified, specifies whether or
+ not the last pixel in the rasterization process is drawn.
+
+ GE01R[31] (Line) useXY
+ -----------------------------------------------
+ When a line drawing operation has been specified, specifies the method
+ used to determine in which direction the line should be drawn. If
+ this field is set, then the information about direction and slope is
+ taken from the xDirection, yDirection, and yIsMajor fields. If this
+ field is clear, then the information is taken from the quadrant field.
+
+ ==========================================================================
+ GE02R
+ ==========================================================================
+
+ GE02R[11:0] (BitBLT) xDest
+ GE02R[27:16] (BitBLT) yDest
+ -----------------------------------------------
+ When a BitBLT operation has been specified, these fields contain the
+ initial x,y location to receive the blitted data. Note that these
+ values are always the topLeft of the destination area, regardless of
+ xDirection and yDirection.
+
+ GE02R[15:13] (BitBLT) monoPatternXOffset
+ GE02R[31:29] (BitBLT) monoPatternYOffset
+ -----------------------------------------------
+ When a BitBLT operation has been specified, these fields contain the
+ initial x,y offsets into the monochrome pattern being used.
+
+ GE02R[11:0] (Line) xStart
+ -----------------------------------------------
+ When a line drawing operation has been specified, specifies starting X
+ position of the line.
+
+ GE02R[28:12] (Line) deltaMajor
+ -----------------------------------------------
+ When a line drawing operation has been specified, specifies the length
+ of the line along the major axis. See yIsMajor for a definition of
+ "major axis".
+
+ GE02R[31:29] (Line) quadrant
+ -----------------------------------------------
+ When a line drawing operation has been specified, specifies the
+ direction and angle in which the line is drawn. This is used only
+ when the useXY field is clear, and replaces the same information
+ provided by xDirection, yDirection, and yIsMajor. The field contains
+ a value from 0 to 7, indicating one of the following 8 quadrants:
+
+ Quadrant 0 (x-major, positive x and y directions)
+ Quadrant 1 (y-major, positive x and y directions)
+ Quadrant 2 (y-major, negative x and positive y directions)
+ Quadrant 3 (x-major, negative x and positive y directions)
+ Quadrant 4 (x-major, negative x and y directions)
+ Quadrant 5 (y-major, negative x and y directions)
+ Quadrant 6 (y-major, positive x and negative y directions)
+ Quadrant 7 (x-major, positive x and negative y directions)
+
+ ==========================================================================
+ GE03R
+ ==========================================================================
+
+ GE03R[11:0] (BitBLT) xSrc
+ GE03R[27:16] (BitBLT) ySrc
+ -----------------------------------------------
+ When a BitBLT operation has been specified, these fields contain the
+ initial x,y location from which to read the source data. Only used
+ when the source data is coming from display memory and not the source
+ FIFO. That is, used in scrolling operations. Note that these values
+ are always the topLeft of the source area, regardless of xDirection
+ and yDirection.
+
+ GE03R[11:0] (Line) yStart
+ -----------------------------------------------
+ When a line drawing operation has been specified, specifies starting Y
+ position of the line.
+
+ GE03R[28:12] (Line) deltaMinor
+ -----------------------------------------------
+ When a line drawing operation has been specified, specifies the length
+ of the line along the minor axis. The "minor axis" is the X or Y axis
+ that is not designated as the major axis. See yIsMajor for a
+ definition of "major axis".
+
+ ==========================================================================
+ GE04R
+ ==========================================================================
+
+ GE04R[15:0] destTransColor
+ -----------------------------------------------
+ When color transparency has been enabled by setting the
+ colorTransEnable field, specifies the color that should be compared
+ against.
+
+ ==========================================================================
+ GE05R/GE06R
+ ==========================================================================
+
+ GE05R[10:0] clipLeft
+ GE05R[25:16] clipTop
+ GE06R[10:0] clipRight
+ GE06R[25:16] clipBottom
+ -----------------------------------------------
+ When the clippingEnable bit is set, these four fields specify the
+ clipping boundary. Pixels outside this rectangle are not written.
+
+ ==========================================================================
+ GE07R/GE08R
+ ==========================================================================
+
+ GE07R[15:0] fgColorMonoSrc
+ GE08R[15:0] bgColorMonoSrc
+ -----------------------------------------------
+ When a monochrome source is being used, these two fields contain the
+ fore- and background colors that should be applied to the bits
+ representing the pixels. Any 1 bit is replace with fgColorMonoSrc,
+ and any 0 bit is replaces with bgColorMonoSrc.
+
+ ==========================================================================
+ GE09R
+ ==========================================================================
+
+ GE09R[9:0] (Lined) srcLineStride
+ -----------------------------------------------
+ When Lined mode is being used (see memToScreen (GE00R[20])) and
+ srcEqualDestStride is false, contains the number of bytes in a line
+ of source data.
+
+ GE09R[27:25] (Lined) srcBitOffset
+ -----------------------------------------------
+ When Lined mode is being used (see memToScreen (GE00R[20])), contains
+ the bit offset into the byte containing the leftmost pixel. Makes
+ sense only with a monochrome source.
+
+ GE09R[30:28] (Lined) srcByteOffset
+ -----------------------------------------------
+ When Lined mode is being used (see memToScreen (GE00R[20])), contains
+ the byte offset of the byte containing the leftmost pixel.
+
+ GE09R[2:0] (Packed) srcLeadingBits
+ -----------------------------------------------
+ When Packed mode is being used (see memToScreen (GE00R[20])), contains
+ the bit offset into the byte containing the leftmost pixel. Makes
+ sense only with a monochrome source.
+
+ GE09R[5:3] (Packed) srcLeadingBytes
+ -----------------------------------------------
+ When Packed mode is being used (see memToScreen (GE00R[20])), contains
+ the byte offset of the byte containing the leftmost pixel.
+
+ GE09R[15:6] (Packed) srcNumBytes
+ -----------------------------------------------
+ When Packed mode is being used (see memToScreen (GE00R[20])), described
+ in the manual as: Number of 8 bytes amount that MIU needs to fetch from
+ frame buffer. For off-screen to on-screen packed mode, these 10 bits
+ represent the number of 8 bytes needed to be fetched by the MIU; the
+ maximum amount it can address is 16 Kbyte, which is the off screen
+ monochrome font or monochrome image graphics engine can support for
+ packed mode.
+
+ GE09R[27:25] (Packed) srcTrailingBits
+ -----------------------------------------------
+ When Packed mode is being used (see memToScreen (GE00R[20])), contains
+ the number of unused trailing bits in the last byte containing pixel
+ data. Makes sense only in monochrome mode.
+
+ GE09R[31:28] (Packed) srcTrailingBytes
+ -----------------------------------------------
+ When Packed mode is being used (see memToScreen (GE00R[20])), contains
+ the number of unused trailing bytes.
+
+ ==========================================================================
+ GE0AR
+ ==========================================================================
+
+ GE0AR[9:0] destLineStride
+ -----------------------------------------------
+ Specifies the stride (or rowBytes) of the destination bitmap. The
+ stride is the number of bytes between the first pixel of one line and
+ the first pixel of the following lines. This information duplicates
+ that stored in the graphic controller, but presumably is stored here
+ as well because the controller and accelerator are separate modules.
+
+ GE0AR[28] monoSrcBitSwap
+ -----------------------------------------------
+ Determines the interpretation of the bits in a monochrome pattern or
+ source bitmap. If this bit is clear, then bit 7 of a byte is the
+ leftmost pixel and bit 0 is the rightmost pixel. If this bit is set,
+ then bit 0 is the leftmost pixel and bit 7 is the rightmost. Having
+ this bit clear is consistent with Windows CE and Palm, and having it
+ set is consistent with EPOC.
+
+ GE0AR[29] rotate90
+ -----------------------------------------------
+ If set, rotates all drawing operation 90 degrees clockwise.
+
+ GE0AR[31:30] colorDepth
+ -----------------------------------------------
+ Determines the number of bits per pixel. If zero, BPP == 8. If one,
+ BPP == 16. All other settings are undefined. This information
+ duplicates that stored in the graphic controller, but presumably is
+ stored here as well because the controller and accelerator are
+ separate modules.
+
+ ==========================================================================
+ GE0BR
+ ==========================================================================
+
+ GE0BR[19:0] baseAddr
+ -----------------------------------------------
+ Determines the base address of the frame buffer, relative to the start
+ of the buffer. That is, a value of 0x00000 indicates the beginning of
+ the buffer, not the beginning of RAM. This information duplicates
+ that stored in the graphic controller, but presumably is stored here
+ as well because the controller and accelerator are separate modules.
+
+ GE0BR[29] testModeEnable
+ GE0BR[31:30] testModeControl
+ -----------------------------------------------
+ Test enable and control bits. Unsupported in Poser.
+
+ ==========================================================================
+ GE0CR
+ ==========================================================================
+
+ GE0CR[9:0] cmdLineStart
+ GE0CR[21:12] cmdLineEnd
+ -----------------------------------------------
+ Specifies the beginning and end of the "command start window".
+ However, there is no explanation of what this window is.
+
+ GE0CR[24] cmdLineControl
+ -----------------------------------------------
+ Controls whether or not the graphics engine needs to check with
+ graphics controller before starting a command. However, there's no
+ explanation of how the graphics controller decides whether or not a
+ command should be started.
+
+ GE0CR[27:26] gc1SwitchControl
+ -----------------------------------------------
+ Controls automatics switching between the main and alternate windows
+ in the graphic controller. A value of 0 or 2 means that no switching
+ is performed. A value of 1 means to switch to the main window after
+ the current drawing command is done. A value of 3 means to switch to
+ the alternate window when the command is done.
+
+ ==========================================================================
+ GE0FR
+ ==========================================================================
+
+ GE0FR[31:0]
+ -----------------------------------------------
+ If testModeEnable is on, this field receives various values, as
+ defined by testModeControl.
+
+ ==========================================================================
+ GE10R/GE11R
+ ==========================================================================
+
+ GE10R[31:0] monoPattern1
+ GE11R[31:0] monoPattern2
+ -----------------------------------------------
+ Together, these fields specify 64 bits of an 8x8 monochrome pattern.
+ The low-order byte of monoPattern1 contains the 8 bits for the first
+ line, the next-order byte of monoPattern1 contains the 8 bits for the
+ next line, etc., all the way up to the high-order byte of monoPattern2
+ containing the 8 bits for the last line.
+
+ ==========================================================================
+ GE12R/GE13R
+ ==========================================================================
+
+ GE12R[15:0] fgColorMonoPat
+ GE13R[15:0] bgColorMonoPat
+ -----------------------------------------------
+ When a monochrome pattern is being used, these two fields contain the
+ fore- and background colors that should be applied to the bits
+ representing the pixels. Any 1 bit is replace with fgColorMonoPat,
+ and any 0 bit is replaces with bgColorMonoPat.
+
+ **************************************************************************
+
+ Notes:
+ -----------------------------------------------
+ Transparency
+ -----------------------------------------------
+ Use destTransPolarity, colorTransCmpSrc, and destTransColor to
+ determine if the destination needs to be updated. All told, it should
+ lay out like this:
+
+ destTransPolarity == 0
+ colorTransCmpSrc == 0
+ Compare destTransColor to the source pixel.
+ If ==, do not update the destination.
+
+ That is, treat all destTransColor colored pixels
+ in the source as transparent.
+
+ colorTransCmpSrc == 1
+ Compare destTransColor to the destination pixel.
+ If ==, do not update the destination.
+
+ That is, leave all destTransColor colored pixels
+ in the destination alone.
+
+ destTransPolarity == 1
+ colorTransCmpSrc == 0
+ Compare destTransColor to the source pixel.
+ If !=, do not update the destination.
+
+ That is, transfer all destTransColor colored pixels
+ from the source to the destination.
+
+ colorTransCmpSrc == 1
+ Compare destTransColor to the destination pixel.
+ If !=, do not update the destination.
+
+ That is, update all destTransColor colored pixels
+ in the destination with source pixels.
+
+ ROPs
+ -----------------------------------------------
+ Take the pattern, source, and destination, and consider each value one
+ bit at a time. The three bits from the three values can form eight
+ combinations. The raster opcode is a bitfield containing the desired
+ output from each of the combinations. Thus:
+
+ P S D O (output)
+ --- --- --- ---
+ 0 0 0 b0
+ 0 0 1 b1
+ 0 1 0 b2
+ 0 1 1 b3
+ 1 0 0 b4
+ 1 0 1 b5
+ 1 1 0 b6
+ 1 1 1 b7
+
+ The output is the byte <b7><b6><b5><b4><b3><b2><b1><b0>. And this
+ output value is what becomes the raster opcode. Thus, if the raster
+ opcode is, for example, 0xCC, the table would be:
+
+ P S D O (output)
+ --- --- --- ---
+ 0 0 0 0
+ 0 0 1 0
+ 0 1 0 1
+ 0 1 1 1
+ 1 0 0 0
+ 1 0 1 0
+ 1 1 0 1
+ 1 1 1 1
+
+ So, the we look at three bits from the source and they're all zero,
+ then the output is zero. If they're all one, then the output is one.
+ If the pattern is one and the source and destination are zero, then
+ the output is zero. Overall,
+
+ Output[x] = ROP[P[x],S[x],D[x]]
+
+ where "x" is 0..7, and "P[x],S[x],D[x]" is a bitfield composed of the
+ given bits.
+
+\* --------------------------------------------------------------------------- */
+
+// Given a register (specified by its field name), return its address
+// in emulated space.
+
+#define addressof(x) ( \
+ ((emuptr) fRegs.x.GetPtr ()) - \
+ ((emuptr) fRegs.GetPtr ()) + \
+ ((emuptr) this->GetAddressStart ()) \
+ )
+
+
+// Macro to help the installation of handlers for a register.
+
+#define INSTALL_HANDLER(read, write, reg) \
+ this->SetHandler ( (ReadFunction) &EmRegsMediaQ11xx::read, \
+ (WriteFunction) &EmRegsMediaQ11xx::write, \
+ addressof (reg), 4)
+
+// Private inline function for reading a LE register.
+
+static inline
+uint32 PrvReadRegister(uint8* p)
+{
+#if EM_HOST_BYTE_ORDER == EM_LITTLE_ENDIAN
+
+ return *(uint32*) p;
+
+#else
+
+ return
+ (((UInt32) p[0]) << 0) +
+ (((UInt32) p[1]) << 8) +
+ (((UInt32) p[2]) << 16) +
+ (((UInt32) p[3]) << 24);
+
+#endif
+}
+
+// Private inline function for writing a LE register
+
+static inline
+void PrvWriteRegister(uint8* p, uint32 value)
+{
+#if EM_HOST_BYTE_ORDER == EM_LITTLE_ENDIAN
+
+ *(uint32*) p = value;
+
+#else
+
+ p[0] = value >> 0;
+ p[1] = value >> 8;
+ p[2] = value >> 16;
+ p[3] = value >> 24;
+
+#endif
+}
+
+
+// Macros to make calling PrvReadRegister and PrvWriteRegister easier.
+
+#define READ_REGISTER(reg) ::PrvReadRegister ((uint8*) (fRegs.reg.GetPtr ()))
+#define WRITE_REGISTER(reg, value) ::PrvWriteRegister ((uint8*) (fRegs.reg.GetPtr ()), value)
+
+
+// ROP values
+
+#define ROP_SRCCOPY 0xcc
+#define ROP_SRCAND 0x88
+//#define ROP_SRCANDNOT 0x77
+#define ROP_SRCANDNOT 0x22
+#define ROP_SRCXOR 0x66
+#define ROP_SRCOR 0xee
+#define ROP_SRCCOPYNOT 0x33
+#define ROP_SRCORNOT 0xbb
+#define ROP_SRCXORNOT 0x99
+
+#define ROP_PATCOPY 0xf0
+#define ROP_PATAND 0xa0
+//#define ROP_PATANDNOT 0x5f
+#define ROP_PATANDNOT 0x0a
+#define ROP_PATXOR 0x5a
+#define ROP_PATOR 0xfa
+#define ROP_PATCOPYNOT 0x0f
+#define ROP_PATORNOT 0xaf
+#define ROP_PATXORNOT 0xa5
+
+#define ROP_BLACKNESS 0x00
+
+
+
+#define CMD_FIFO_MASK (0x0000001F)
+#define CMD_FIFO_EMPTY (0x00000010)
+#define CMD_SRC_MASK (0x00001F00)
+#define CMD_SRC_EMPTY (0x00001000)
+#define GE_BUSY_H (0x00010000)
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Graphics Controller Registers
+//
+#define GC_CONTROL (0x00) // Graphics Controll Control Reg
+#define GC_PWR_SEQ_CONTROL (0x01) // Power Sequencing Control register
+#define GC_HTOTAL_HEND (0x02) // Horizontal Display Total & End
+#define GC_VTOTAL_VEND (0x03) // Vertical Display Total and End
+#define GC_HSYNC (0x04) // Horizontal Sync Start and End
+#define GC_VSYNC (0x05) // Vertical Sync Start and End
+#define GC_HWINDOW (0x08) // Horizontal Window Start & End
+#define GC_VWINDOW (0x09) // Vertical Window Start & End
+#define GC_LINE_CLOCK (0x0B) // Line Clock Control
+#define GC_START_ADDR (0x0C) // Image Window Start Address
+#define GC_ALTWIN_START_ADDR (0x0D) // Alt Image Window Start Address
+#define GC_STRIDE (0x0E) // (Alt) Image Window Stride
+#define GC_FRAME_CLOCK (0x1A) // Frame Clock Control
+#define GC_SIGNALS (0x1B) // Miscellaneous signal register (read only)
+#define GC_HPARAM (0x1C) // Horizontal parameter register (read only)
+#define GC_VPARAM (0x1D) // Vertical parameter register (read only)
+
+
+// GC_CONTROL register bit definition
+
+#define GC_ENABLE (1UL << 0) // Controll enabled
+#define GC_H_PIX_DBLNG (1UL << 14) // Enable Horizontal Pixel Doubling
+#define GC_V_PIX_DBLNG (1UL << 15) // Enable Vertical Scan Line Doubling
+#define GC_PIX_DBLNG_MASK (GC_H_PIX_DBLNG | GC_V_PIX_DBLNG)
+
+
+// Palette masks
+
+#define RED_MASK 0x0000000FC
+#define GREEN_MASK 0x00000FC00
+#define BLUE_MASK 0x000FC0000
+
+
+#define kColorDepth8 0
+#define kColorDepth16 1
+
+#define kCommandNOP 0
+#define kCommandBitBLT 2
+#define kCommandLine 4
+
+#define kAllRegisters -1
+
+static const char* kCommands[] =
+{
+ "NOP",
+ "Undefined",
+ "BitBLT",
+ "Reserved",
+ "Line Draw",
+ "Reserved",
+ "Undefined",
+ "Reserved",
+};
+
+static const char* kDirections[] =
+{
+ "Positive",
+ "Negative"
+};
+
+const struct
+{
+ uint16 yIsMajor; // 0 = x is major, 1 = y is major
+ uint16 xDirection; // 0 = x is positive, 1 = x is negative
+ uint16 yDirection; // 0 = y is positive, 1 = y is negative
+ const char* text; // Description for debugging.
+} kQuadrantDecode[] =
+{
+ { 0, 0, 0, "x-major, positive x and y directions" },
+ { 1, 0, 0, "y-major, positive x and y directions" },
+ { 1, 1, 0, "y-major, negative x and positive y directions" },
+ { 0, 1, 0, "x-major, negative x and positive y directions" },
+ { 0, 1, 1, "x-major, negative x and y directions" },
+ { 1, 1, 1, "y-major, negative x and y directions" },
+ { 1, 0, 1, "y-major, positive x and negative y directions" },
+ { 0, 0, 1, "x-major, positive x and negative y directions" }
+};
+
+static char* kROPs[] =
+{
+ "0 BLACKNESS", "DPSoon", "DPSona", "PSon",
+ "SDPona", "DPon", "PDSxnon", "PDSaon",
+ "SDPnaa", "PDSxon", "DPna", "PSDnaon",
+ "SPna", "PDSnaon", "PDSonon", "Pn",
+ "PDSona", "DSon NOTSRCERASE", "SDPxnon", "SDPaon",
+ "DPSxnon", "DPSaon", "PSDPSanaxx", "SSPxDSxaxn",
+ "SPxPDxa", "SDPSanaxn", "PDSPaox", "SDPSxaxn",
+ "PSDPaox", "DSPDxaxn", "PDSox", "PDSoan",
+ "DPSnaa", "SDPxon", "DSna", "SPDnaon",
+ "SPxDSxa", "PDSPanaxn", "SDPSaox", "SDPSxnox",
+ "DPSxa", "PSDPSaoxxn", "DPSana", "SSPxPDxaxn",
+ "SPDSoax", "PSDnox", "PSDPxox", "PSDnoan",
+ "PSna", "SDPnaon", "SDPSoox", "Sn NOTSRCCOPY",
+ "SPDSaox", "SPDSxnox", "SDPox", "SDPoan",
+ "PSDPoax", "SPDnox", "SPDSxox", "SPDnoan",
+ "PSx", "SPDSonox", "SPDSnaox", "PSan",
+ "PSDnaa", "DPSxon", "SDxPDxa", "SPDSanaxn",
+ "SDna SRCERASE", "DPSnaon", "DSPDaox", "PSDPxaxn",
+ "SDPxa", "PDSPDaoxxn", "DPSDoax", "PDSnox",
+ "SDPana", "SSPxDSxoxn", "PDSPxox", "PDSnoan",
+ "PDna", "DSPnaon", "DPSDaox", "SPDSxaxn",
+ "DPSonon", "Dn DSTINVERT", "DPSox", "DPSoan",
+ "PDSPoax", "DPSnox", "DPx PATINVERT", "DPSDonox",
+ "DPSDxox", "DPSnoan", "DPSDnaox", "DPan",
+ "PDSxa", "DSPDSaoxxn", "DSPDoax", "SDPnox",
+ "SDPSoax", "DSPnox", "DSx SRCINVERT", "SDPSonox",
+ "DSPDSonoxxn", "PDSxxn", "DPSax", "PSDPSoaxxn",
+ "SDPax", "PDSPDoaxxn", "SDPSnoax", "PDSxnan",
+ "PDSana", "SSDxPDxaxn", "SDPSxox", "SDPnoan",
+ "DSPDxox", "DSPnoan", "SDPSnaox", "DSan",
+ "PDSax", "DSPDSoaxxn", "DPSDnoax", "SDPxnan",
+ "SPDSnoax", "DPSxnan", "SPxDSxo", "DPSaan",
+ "DPSaa", "SPxDSxon", "DPSxna", "SPDSnoaxn",
+ "SDPxna", "PDSPnoaxn", "DSPDSoaxx", "PDSaxn",
+ "DSa SRCAND", "SDPSnaoxn", "DSPnoa", "DSPDxoxn",
+ "SDPnoa", "SDPSxoxn", "SSDxPDxax", "PDSanan",
+ "PDSxna", "SDPSnoaxn", "DPSDPoaxx", "SPDaxn",
+ "PSDPSoaxx", "DPSaxn", "DPSxx", "PSDPSonoxx",
+ "SDPSonoxn", "DSxn", "DPSnax", "SDPSoaxn",
+ "SPDnax", "DSPDoaxn", "DSPDSaoxx", "PDSxan",
+ "DPa", "PDSPnaoxn", "DPSnoa", "DPSDxoxn",
+ "PDSPonoxn", "PDxn", "DSPnax", "PDSPoaxn",
+ "DPSoa", "DPSoxn", "D", "DPSono",
+ "SPDSxax", "DPSDaoxn", "DSPnao", "DPno",
+ "PDSnoa", "PDSPxoxn", "SSPxDSxox", "SDPanan",
+ "PSDnax", "DPSDoaxn", "DPSDPaoxx", "SDPxan",
+ "PSDPxax", "DSPDaoxn", "DPSnao", "DSno MERGEPAINT",
+ "SPDSanax", "SDxPDxan", "DPSxo", "DPSano",
+ "PSa MERGECOPY", "SPDSnaoxn", "SPDSonoxn", "PSxn",
+ "SPDnoa", "SPDSxoxn", "SDPnax", "PSDPoaxn",
+ "SDPoa", "SPDoxn", "DPSDxax", "SPDSaoxn",
+ "S SRCCOPY", "SDPono", "SDPnao", "SPno",
+ "PSDnoa", "PSDPxoxn", "PDSnax", "SPDSoaxn",
+ "SSPxPDxax", "DPSanan", "PSDPSaoxx", "DPSxan",
+ "PDSPxax", "SDPSaoxn", "DPSDanax", "SPxDSxan",
+ "SPDnao", "SDno", "SDPxo", "SDPano",
+ "PDSoa", "PDSoxn", "DSPDxax", "PSDPaoxn",
+ "SDPSxax", "PDSPaoxn", "SDPSanax", "SPxPDxan",
+ "SSPxDSxax", "DSPDSanaxxn", "DPSao", "DPSxno",
+ "SDPao", "SDPxno", "DSo SRCPAINT", "SDPnoo",
+ "P PATCOPY", "PDSono", "PDSnao", "PSno",
+ "PSDnao", "PDno", "PDSxo", "PDSano",
+ "PDSao", "PDSxno", "DPo", "DPSnoo PATPAINT",
+ "PSo", "PSDnoo", "DPSoo", "1 WHITENESS"
+};
+
+
+// Inline functions.
+
+inline uint32 EmRegsMediaQ11xx::PrvGetBPP (void)
+{
+ return 1 << ((READ_REGISTER (gcREG[GC_CONTROL]) & 0x00000070) >> 4);
+}
+
+inline uint32 EmRegsMediaQ11xx::PrvGetWidth (void)
+{
+ return (READ_REGISTER (gcREG[GC_HWINDOW]) >> 16) + 1;
+}
+
+inline uint32 EmRegsMediaQ11xx::PrvGetHeight (void)
+{
+ return (READ_REGISTER (gcREG[GC_VWINDOW]) >> 16) + 1;
+}
+
+inline uint32 EmRegsMediaQ11xx::PrvGetRowBytes (void)
+{
+ return READ_REGISTER (gcREG[GC_STRIDE]) & 0x0000FFFF;
+}
+
+inline uint32 EmRegsMediaQ11xx::PrvGetVideoOffset (void)
+{
+ return READ_REGISTER (gcREG[GC_START_ADDR]) & 0x0003FFFF;
+}
+
+inline emuptr EmRegsMediaQ11xx::PrvGetVideoBase (void)
+{
+ return fBaseVideoAddr;
+}
+
+inline emuptr EmRegsMediaQ11xx::PrvGetFrameBuffer (void)
+{
+ return this->PrvGetVideoBase () + this->PrvGetVideoOffset ();
+}
+
+inline Bool EmRegsMediaQ11xx::PrvGetXDoubling (void)
+{
+ return (READ_REGISTER (gcREG[GC_CONTROL]) & GC_H_PIX_DBLNG) != 0;
+}
+
+inline Bool EmRegsMediaQ11xx::PrvGetYDoubling (void)
+{
+ return (READ_REGISTER (gcREG[GC_CONTROL]) & GC_V_PIX_DBLNG) != 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::EmRegsMediaQ11xx
+// ---------------------------------------------------------------------------
+
+EmRegsMediaQ11xx::EmRegsMediaQ11xx (emuptr baseRegsAddr, emuptr baseVideoAddr) :
+ fBaseRegsAddr (baseRegsAddr),
+ fBaseVideoAddr (baseVideoAddr),
+ fRegs (),
+/* fState (), */
+/* fByteLanes (), */
+ fLastAddress (EmMemNULL),
+ fLastSize (0),
+ fSourceFifo (),
+ fBlitInProgress (false),
+ fCurXOffset (0),
+ fCurYOffset (0),
+ fUsesPattern (false),
+ fUsesSource (false),
+ fLeadingSourcePixels (0),
+ fTrailingSourcePixels (0),
+/* fPatternPipe (), */
+ fXPattern (0),
+ fYPattern (0),
+/* fSourcePipe (), */
+ fSourcePipeIndex (0),
+ fSourcePipeMax (0),
+ fSourcePipeSkip (0),
+ fXSrc (0),
+ fYSrc (0),
+ fXDest (0),
+ fYDest (0)
+{
+#if LOG_LINE || LOG_BLIT
+ LogGetStdLog ()->SetLogSize (32 * 1024L * 1024L);
+#endif
+
+ COMPILE_TIME_ASSERT(countof (kCommands) == 8);
+ COMPILE_TIME_ASSERT(countof (kDirections) == 2);
+ COMPILE_TIME_ASSERT(countof (kQuadrantDecode) == 8);
+ COMPILE_TIME_ASSERT(countof (kROPs) == 256);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::~EmRegsMediaQ11xx
+// ---------------------------------------------------------------------------
+
+EmRegsMediaQ11xx::~EmRegsMediaQ11xx (void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::Initialize
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::Initialize (void)
+{
+ EmRegs::Initialize ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::Reset
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::Reset (Bool hardwareReset)
+{
+ EmRegs::Reset (hardwareReset);
+
+ if (hardwareReset)
+ {
+ WRITE_REGISTER (ccREG[0x00], 0x00000000);
+ WRITE_REGISTER (ccREG[0x01], 0x00000000);
+ WRITE_REGISTER (ccREG[0x02], 0x00000000);
+ WRITE_REGISTER (ccREG[0x03], 0x00000000);
+ WRITE_REGISTER (ccREG[0x04], 0x00000000);
+
+ WRITE_REGISTER (mmREG[0x00], 0x00000000); // (Low nybble only)
+ WRITE_REGISTER (mmREG[0x01], 0x00000000); // (Low nybble only)
+ WRITE_REGISTER (mmREG[0x02], 0x00000000); // (Low nybble only)
+
+ WRITE_REGISTER (inREG[0x00], 0x00000000);
+ WRITE_REGISTER (inREG[0x01], 0x00000000);
+ WRITE_REGISTER (inREG[0x02], 0x00000000);
+ WRITE_REGISTER (inREG[0x03], 0x00000000);
+
+ WRITE_REGISTER (gcREG[0x00], 0x00000000);
+ WRITE_REGISTER (gcREG[0x01], 0x00000000); // (Low byte only)
+ WRITE_REGISTER (gcREG[0x06], 0x00000000); // (Low word only)
+ WRITE_REGISTER (gcREG[0x07], 0x00000000); // (Low word only)
+
+ // GC_CONTROL (0x00) // Graphics Controll Control Reg
+ // GC_PWR_SEQ_CONTROL (0x01) // Power Sequencing Control register
+ // GC_HTOTAL_HEND (0x02) // Horizontal Display Total & End
+ // GC_VTOTAL_VEND (0x03) // Vertical Display Total and End
+ // GC_HSYNC (0x04) // Horizontal Sync Start and End
+ // GC_VSYNC (0x05) // Vertical Sync Start and End
+ // GC_HWINDOW (0x08) // Horizontal Window Start & End
+ // GC_VWINDOW (0x09) // Vertical Window Start & End
+ // GC_LINE_CLOCK (0x0B) // Line Clock Control
+ // GC_START_ADDR (0x0C) // Image Window Start Address
+ // GC_ALTWIN_START_ADDR (0x0D) // Alt Image Window Start Address
+ // GC_STRIDE (0x0E) // (Alt) Image Window Stride
+ // GC_FRAME_CLOCK (0x1A) // Frame Clock Control
+
+ // For now, let's initialize all the graphics controller registers to 0.
+ for (int i = 0x00; i < 0x20; i++)
+ {
+ WRITE_REGISTER (gcREG[i], 0x00000000);
+ }
+
+ WRITE_REGISTER (geREG[0x00], 0x00000000);
+ WRITE_REGISTER (geREG[0x0C], 0x00000000);
+
+ WRITE_REGISTER (ssREG[0x00], 0x00000000);
+ WRITE_REGISTER (ssREG[0x01], 0x00000000);
+ WRITE_REGISTER (ssREG[0x04], 0x00000000); // (Low nybble only)
+ WRITE_REGISTER (ssREG[0x08], 0x00000000); // (Low byte only)
+ WRITE_REGISTER (ssREG[0x09], 0x00000000); // (Low byte only)
+ WRITE_REGISTER (ssREG[0x0A], 0x00000000); // (Low byte only)
+ WRITE_REGISTER (ssREG[0x0B], 0x00000000); // (Low byte only)
+ WRITE_REGISTER (ssREG[0x10], 0x00000000);
+ WRITE_REGISTER (ssREG[0x11], 0x00000000);
+ WRITE_REGISTER (ssREG[0x13], 0x00000000);
+
+ WRITE_REGISTER (spREG[0x00], 0x00000000);
+ WRITE_REGISTER (spREG[0x01], 0xF0000000);
+ WRITE_REGISTER (spREG[0x02], 0x00000000);
+ WRITE_REGISTER (spREG[0x03], 0x00000000);
+ WRITE_REGISTER (spREG[0x04], 0x00000000);
+ WRITE_REGISTER (spREG[0x05], 0x00000000);
+ WRITE_REGISTER (spREG[0x06], 0x00000000);
+ WRITE_REGISTER (spREG[0x07], 0x00000000);
+ WRITE_REGISTER (spREG[0x08], 0x00000000);
+
+ WRITE_REGISTER (dcREG[0x00], 0x00000000);
+ WRITE_REGISTER (dcREG[0x01], 0xF0000000);
+ WRITE_REGISTER (dcREG[0x02], 0x00000000);
+ WRITE_REGISTER (dcREG[0x03], 0x00000000);
+ WRITE_REGISTER (dcREG[0x04], 0x00000000);
+ WRITE_REGISTER (dcREG[0x05], 0x00000000);
+ WRITE_REGISTER (dcREG[0x06], 0x00000000);
+ WRITE_REGISTER (dcREG[0x07], 0x00000000);
+
+ WRITE_REGISTER (pcREG[0x00], 0x01204D51);
+ WRITE_REGISTER (pcREG[0x01], 0x02800000);
+ WRITE_REGISTER (pcREG[0x02], 0x03800000);
+ WRITE_REGISTER (pcREG[0x03], 0x00000000);
+ WRITE_REGISTER (pcREG[0x0B], 0x00000100);
+ WRITE_REGISTER (pcREG[0x0F], 0x00000100);
+
+ WRITE_REGISTER (uhREG[0x00], 0x00000010); // (Low byte only)
+ WRITE_REGISTER (uhREG[0x01], 0x00000000);
+ WRITE_REGISTER (uhREG[0x02], 0x00000000);
+ WRITE_REGISTER (uhREG[0x03], 0x00000000);
+ WRITE_REGISTER (uhREG[0x04], 0x00000000);
+ WRITE_REGISTER (uhREG[0x05], 0x00000000);
+ WRITE_REGISTER (uhREG[0x06], 0x00000000);
+ WRITE_REGISTER (uhREG[0x07], 0x00000000);
+ WRITE_REGISTER (uhREG[0x08], 0x00000000);
+ WRITE_REGISTER (uhREG[0x09], 0x00000000);
+ WRITE_REGISTER (uhREG[0x0A], 0x00000000);
+ WRITE_REGISTER (uhREG[0x0B], 0x00000000);
+ WRITE_REGISTER (uhREG[0x0C], 0x00000000);
+ WRITE_REGISTER (uhREG[0x0D], 0x00002EDF);
+ WRITE_REGISTER (uhREG[0x0E], 0x00000000);
+ WRITE_REGISTER (uhREG[0x0F], 0x00000000);
+ WRITE_REGISTER (uhREG[0x10], 0x00000000); // (Low word only)
+ WRITE_REGISTER (uhREG[0x11], 0x00000628);
+ WRITE_REGISTER (uhREG[0x12], 0x00001102);
+ WRITE_REGISTER (uhREG[0x13], 0x00000000);
+ WRITE_REGISTER (uhREG[0x14], 0x00000000);
+ WRITE_REGISTER (uhREG[0x15], 0x00000000);
+ WRITE_REGISTER (uhREG[0x16], 0x00000000);
+
+ WRITE_REGISTER (fpREG[0x00], 0x00000000);
+ WRITE_REGISTER (fpREG[0x01], 0x00000000);
+ WRITE_REGISTER (fpREG[0x02], 0x0FFCFCFF);
+ WRITE_REGISTER (fpREG[0x03], 0x00000000);
+ WRITE_REGISTER (fpREG[0x04], 0x00000000);
+ WRITE_REGISTER (fpREG[0x05], 0x00000000);
+ WRITE_REGISTER (fpREG[0x06], 0x00000000);
+ WRITE_REGISTER (fpREG[0x07], 0x00000000);
+ WRITE_REGISTER (fpREG[0x0A], 0xF0030000);
+ WRITE_REGISTER (fpREG[0x0B], 0x00000000); // (Low 12-bits only)
+ WRITE_REGISTER (fpREG[0x0E], 0x00000000); // (Low byte only)
+ WRITE_REGISTER (fpREG[0x0F], 0x00000000);
+
+ // (No reset values for color palette and source FIFO)
+
+ WRITE_REGISTER (udREG[0x00], 0x00000000);
+ WRITE_REGISTER (udREG[0x01], 0x00000000);
+ WRITE_REGISTER (udREG[0x02], 0x00000000);
+ WRITE_REGISTER (udREG[0x03], 0x00000000);
+ WRITE_REGISTER (udREG[0x04], 0x00000000);
+ WRITE_REGISTER (udREG[0x05], 0x00000000);
+ WRITE_REGISTER (udREG[0x06], 0x00000000);
+ WRITE_REGISTER (udREG[0x07], 0x00000000);
+ WRITE_REGISTER (udREG[0x08], 0x00000000);
+ WRITE_REGISTER (udREG[0x09], 0x00000000);
+ WRITE_REGISTER (udREG[0x0A], 0x00000000);
+ WRITE_REGISTER (udREG[0x0B], 0x00000000); // (Low byte only)
+ WRITE_REGISTER (udREG[0x0C], 0x00000000);
+ WRITE_REGISTER (udREG[0x0D], 0x00000000);
+ WRITE_REGISTER (udREG[0x0E], 0x00000000);
+ WRITE_REGISTER (udREG[0x0F], 0x00000000);
+ WRITE_REGISTER (udREG[0x00], 0x00000000);
+ WRITE_REGISTER (udREG[0x01], 0x00000000);
+ WRITE_REGISTER (udREG[0x02], 0x00000000);
+
+ // Because DC00R is reset to zero, establish the
+ // byteswapping lanes corresponding to that.
+
+ this->PrvUpdateByteLanes ();
+
+ fLastAddress = EmMemNULL;
+ fLastSize = 0;
+
+ fBlitInProgress = false;
+
+ this->PrvGetGEState (kAllRegisters);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::Save
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::Save (SessionFile& f)
+{
+ const long kCurrentMediaQVersion = 1;
+
+ EmRegs::Save (f);
+
+ Chunk chunk;
+ EmStreamChunk s (chunk);
+
+ s << kCurrentMediaQVersion;
+
+ s.PutBytes (fRegs.GetPtr (), fRegs.GetSize ());
+
+ f.WriteMediaQRegsType (chunk);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::Load
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::Load (SessionFile& f)
+{
+ EmRegs::Load (f);
+
+ Chunk chunk;
+
+ if (!f.ReadMediaQRegsType (chunk))
+ {
+ f.SetCanReload (false);
+ }
+ else
+ {
+ long version;
+
+ EmStreamChunk s (chunk);
+
+ s >> version;
+
+ if (version >= 1)
+ {
+ s.GetBytes (fRegs.GetPtr (), fRegs.GetSize ());
+ }
+ }
+
+ this->PrvUpdateByteLanes ();
+
+ // !!! Save and restore these?
+
+ fLastAddress = EmMemNULL;
+ fLastSize = 0;
+
+ fBlitInProgress = false;
+
+ this->PrvGetGEState (kAllRegisters);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::Dispose
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::Dispose (void)
+{
+ EmRegs::Dispose ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::SetSubBankHandlers
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::SetSubBankHandlers (void)
+{
+ // Install base handlers.
+
+ EmRegs::SetSubBankHandlers ();
+
+ // Now add standard/specialized handers for the defined registers.
+
+ INSTALL_HANDLER (MQRead, MQWrite, ccREG[0x00]);
+ INSTALL_HANDLER (CC01Read, MQWrite, ccREG[0x01]);
+ INSTALL_HANDLER (MQRead, MQWrite, ccREG[0x02]);
+ INSTALL_HANDLER (MQRead, MQWrite, ccREG[0x03]);
+ INSTALL_HANDLER (MQRead, MQWrite, ccREG[0x04]);
+
+ INSTALL_HANDLER (MQRead, MQWrite, mmREG[0x00]);
+ INSTALL_HANDLER (MQRead, MQWrite, mmREG[0x01]);
+ INSTALL_HANDLER (MQRead, MQWrite, mmREG[0x02]);
+ INSTALL_HANDLER (MQRead, MQWrite, mmREG[0x03]);
+ INSTALL_HANDLER (MQRead, MQWrite, mmREG[0x04]);
+
+ INSTALL_HANDLER (MQRead, MQWrite, inREG[0x00]);
+ INSTALL_HANDLER (MQRead, MQWrite, inREG[0x01]);
+ INSTALL_HANDLER (MQRead, MQWrite, inREG[0x02]);
+ INSTALL_HANDLER (MQRead, MQWrite, inREG[0x03]);
+
+ INSTALL_HANDLER (MQRead, invalidateWrite, gcREG[0x00]); // BPP (et al)
+ INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x01]);
+ INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x02]);
+ INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x03]);
+ INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x04]);
+ INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x05]);
+ INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x06]);
+ INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x07]);
+ INSTALL_HANDLER (MQRead, invalidateWrite, gcREG[0x08]); // Width
+ INSTALL_HANDLER (MQRead, invalidateWrite, gcREG[0x09]); // Height
+ INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x0A]);
+ INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x0B]);
+ INSTALL_HANDLER (MQRead, invalidateWrite, gcREG[0x0C]); // Base Address
+ INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x0D]);
+ INSTALL_HANDLER (MQRead, invalidateWrite, gcREG[0x0E]); // Stride
+ INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x0F]);
+ INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x10]);
+ INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x11]);
+ INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x12]);
+ INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x13]);
+ INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x14]);
+ INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x15]);
+ INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x16]);
+ INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x17]);
+ INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x18]);
+ INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x19]);
+ INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x1A]);
+ INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x1B]);
+ INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x1C]);
+ INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x1D]);
+ INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x1E]);
+ INSTALL_HANDLER (MQRead, MQWrite, gcREG[0x1F]);
+
+ INSTALL_HANDLER (MQRead, GE00Write, geREG[0x00]);
+ INSTALL_HANDLER (MQRead, MQWrite, geREG[0x01]);
+ INSTALL_HANDLER (MQRead, GE02Write, geREG[0x02]);
+ INSTALL_HANDLER (MQRead, MQWrite, geREG[0x03]);
+ INSTALL_HANDLER (MQRead, MQWrite, geREG[0x04]);
+ INSTALL_HANDLER (MQRead, MQWrite, geREG[0x05]);
+ INSTALL_HANDLER (MQRead, MQWrite, geREG[0x06]);
+ INSTALL_HANDLER (MQRead, MQWrite, geREG[0x07]);
+ INSTALL_HANDLER (MQRead, MQWrite, geREG[0x08]);
+ INSTALL_HANDLER (MQRead, MQWrite, geREG[0x09]);
+ INSTALL_HANDLER (MQRead, MQWrite, geREG[0x0A]);
+ INSTALL_HANDLER (MQRead, MQWrite, geREG[0x0B]);
+ INSTALL_HANDLER (MQRead, MQWrite, geREG[0x0C]);
+ INSTALL_HANDLER (MQRead, MQWrite, geREG[0x0D]);
+ INSTALL_HANDLER (MQRead, MQWrite, geREG[0x0E]);
+ INSTALL_HANDLER (MQRead, MQWrite, geREG[0x0F]);
+ INSTALL_HANDLER (MQRead, MQWrite, geREG[0x10]);
+ INSTALL_HANDLER (MQRead, MQWrite, geREG[0x11]);
+ INSTALL_HANDLER (MQRead, MQWrite, geREG[0x12]);
+ INSTALL_HANDLER (MQRead, MQWrite, geREG[0x13]);
+
+ INSTALL_HANDLER (MQRead, MQWrite, ssREG[0x00]);
+ INSTALL_HANDLER (MQRead, MQWrite, ssREG[0x01]);
+ INSTALL_HANDLER (MQRead, MQWrite, ssREG[0x04]); // Skip some here
+ INSTALL_HANDLER (MQRead, MQWrite, ssREG[0x08]); // Skip some here
+ INSTALL_HANDLER (MQRead, MQWrite, ssREG[0x09]);
+ INSTALL_HANDLER (MQRead, MQWrite, ssREG[0x0A]);
+ INSTALL_HANDLER (MQRead, MQWrite, ssREG[0x0B]);
+ INSTALL_HANDLER (MQRead, MQWrite, ssREG[0x0C]);
+ INSTALL_HANDLER (MQRead, MQWrite, ssREG[0x0D]);
+ INSTALL_HANDLER (MQRead, MQWrite, ssREG[0x10]); // Skip some here
+ INSTALL_HANDLER (MQRead, MQWrite, ssREG[0x11]);
+ INSTALL_HANDLER (MQRead, MQWrite, ssREG[0x12]);
+ INSTALL_HANDLER (MQRead, MQWrite, ssREG[0x13]);
+ INSTALL_HANDLER (MQRead, MQWrite, ssREG[0x14]);
+ INSTALL_HANDLER (MQRead, MQWrite, ssREG[0x15]);
+
+ INSTALL_HANDLER (MQRead, MQWrite, spREG[0x00]);
+ INSTALL_HANDLER (MQRead, MQWrite, spREG[0x01]);
+ INSTALL_HANDLER (MQRead, MQWrite, spREG[0x02]);
+ INSTALL_HANDLER (MQRead, MQWrite, spREG[0x03]);
+ INSTALL_HANDLER (MQRead, MQWrite, spREG[0x04]);
+ INSTALL_HANDLER (MQRead, MQWrite, spREG[0x05]);
+ INSTALL_HANDLER (MQRead, MQWrite, spREG[0x06]);
+ INSTALL_HANDLER (MQRead, MQWrite, spREG[0x07]);
+ INSTALL_HANDLER (MQRead, MQWrite, spREG[0x08]);
+
+ INSTALL_HANDLER (MQRead, DC00Write, dcREG[0x00]);
+ INSTALL_HANDLER (MQRead, MQWrite, dcREG[0x01]);
+ INSTALL_HANDLER (MQRead, MQWrite, dcREG[0x02]);
+ INSTALL_HANDLER (MQRead, MQWrite, dcREG[0x03]);
+ INSTALL_HANDLER (MQRead, MQWrite, dcREG[0x04]);
+ INSTALL_HANDLER (MQRead, MQWrite, dcREG[0x05]);
+ INSTALL_HANDLER (MQRead, MQWrite, dcREG[0x06]);
+ INSTALL_HANDLER (MQRead, MQWrite, dcREG[0x07]);
+
+ INSTALL_HANDLER (MQRead, MQWrite, pcREG[0x00]);
+ INSTALL_HANDLER (MQRead, MQWrite, pcREG[0x01]);
+ INSTALL_HANDLER (MQRead, MQWrite, pcREG[0x02]);
+ INSTALL_HANDLER (MQRead, MQWrite, pcREG[0x03]);
+ INSTALL_HANDLER (MQRead, MQWrite, pcREG[0x04]);
+ INSTALL_HANDLER (MQRead, MQWrite, pcREG[0x05]);
+ INSTALL_HANDLER (MQRead, MQWrite, pcREG[0x0B]); // Skip some here
+ INSTALL_HANDLER (MQRead, MQWrite, pcREG[0x0F]); // Skip some here
+
+ INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x00]);
+ INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x01]);
+ INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x02]);
+ INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x03]);
+ INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x04]);
+ INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x05]);
+ INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x06]);
+ INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x07]);
+ INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x08]);
+ INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x09]);
+ INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x0A]);
+ INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x0B]);
+ INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x0C]);
+ INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x0D]);
+ INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x0E]);
+ INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x0F]);
+ INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x10]);
+ INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x11]);
+ INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x12]);
+ INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x13]);
+ INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x14]);
+ INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x15]);
+ INSTALL_HANDLER (MQRead, MQWrite, uhREG[0x16]);
+
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x00]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x01]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x02]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x03]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x04]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x05]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x06]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x07]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x08]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x09]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x0A]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x0B]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x0E]); // Skip some here
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x0F]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x10]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x11]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x12]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x13]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x14]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x15]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x16]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x17]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x18]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x19]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x1A]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x1B]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x1C]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x1D]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x1E]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x1F]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x20]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x21]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x22]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x23]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x24]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x25]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x26]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x27]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x28]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x29]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x2A]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x2B]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x2C]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x2D]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x2E]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x2F]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x30]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x31]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x32]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x33]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x34]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x35]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x36]);
+ INSTALL_HANDLER (MQRead, MQWrite, fpREG[0x37]);
+
+ this->SetHandler ( (ReadFunction) &EmRegsMediaQ11xx::MQRead,
+ (WriteFunction) &EmRegsMediaQ11xx::invalidateWrite,
+ addressof (cpREG), 0x0400);
+
+ this->SetHandler ( (ReadFunction) &EmRegsMediaQ11xx::MQRead,
+ (WriteFunction) &EmRegsMediaQ11xx::SourceFifoWrite,
+ addressof (sfREG), 0x0400);
+
+ INSTALL_HANDLER (MQRead, MQWrite, udREG[0x00]);
+ INSTALL_HANDLER (MQRead, MQWrite, udREG[0x01]);
+ INSTALL_HANDLER (MQRead, MQWrite, udREG[0x02]);
+ INSTALL_HANDLER (MQRead, MQWrite, udREG[0x03]);
+ INSTALL_HANDLER (MQRead, MQWrite, udREG[0x04]);
+ INSTALL_HANDLER (MQRead, MQWrite, udREG[0x05]);
+ INSTALL_HANDLER (MQRead, MQWrite, udREG[0x06]);
+ INSTALL_HANDLER (MQRead, MQWrite, udREG[0x07]);
+ INSTALL_HANDLER (MQRead, MQWrite, udREG[0x08]);
+ INSTALL_HANDLER (MQRead, MQWrite, udREG[0x09]);
+ INSTALL_HANDLER (MQRead, MQWrite, udREG[0x0A]);
+ INSTALL_HANDLER (MQRead, MQWrite, udREG[0x0B]);
+ INSTALL_HANDLER (MQRead, MQWrite, udREG[0x0C]);
+ INSTALL_HANDLER (MQRead, MQWrite, udREG[0x0D]);
+ INSTALL_HANDLER (MQRead, MQWrite, udREG[0x0E]);
+ INSTALL_HANDLER (MQRead, MQWrite, udREG[0x0F]);
+ INSTALL_HANDLER (MQRead, MQWrite, udREG[0x10]);
+ INSTALL_HANDLER (MQRead, MQWrite, udREG[0x11]);
+ INSTALL_HANDLER (MQRead, MQWrite, udREG[0x12]);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::GetRealAddress
+// ---------------------------------------------------------------------------
+
+uint8* EmRegsMediaQ11xx::GetRealAddress (emuptr address)
+{
+ return (uint8*) fRegs.GetPtr () + (address - this->GetAddressStart ());
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::GetAddressStart
+// ---------------------------------------------------------------------------
+
+emuptr EmRegsMediaQ11xx::GetAddressStart (void)
+{
+ return fBaseRegsAddr;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::GetAddressRange
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsMediaQ11xx::GetAddressRange (void)
+{
+ return fRegs.GetSize ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::GetLCDScreenOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsMediaQ11xx::GetLCDScreenOn (void)
+{
+ return ((READ_REGISTER (gcREG[GC_CONTROL]) & GC_ENABLE) != 0);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::GetLCDBacklightOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsMediaQ11xx::GetLCDBacklightOn (void)
+{
+ return true;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::GetLCDHasFrame
+// ---------------------------------------------------------------------------
+
+Bool EmRegsMediaQ11xx::GetLCDHasFrame (void)
+{
+ return true;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::GetLCDBeginEnd
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::GetLCDBeginEnd (emuptr& begin, emuptr& end)
+{
+ int32 height = this->PrvGetHeight ();
+ int32 rowBytes = this->PrvGetRowBytes ();
+ emuptr baseAddr = this->PrvGetFrameBuffer ();
+
+ begin = baseAddr;
+ end = baseAddr + rowBytes * height;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::GetLCDScanlines
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::GetLCDScanlines (EmScreenUpdateInfo& info)
+{
+ // Get the screen metrics.
+ int32 bpp = this->PrvGetBPP ();
+ int32 width = this->PrvGetWidth ();
+ int32 height = this->PrvGetHeight ();
+ int32 rowBytes = this->PrvGetRowBytes ();
+ emuptr baseAddr = this->PrvGetFrameBuffer ();
+
+#ifdef _DEBUG
+ Bool xDoubling = this->PrvGetXDoubling ();
+ Bool yDoubling = this->PrvGetYDoubling ();
+
+ EmAssert (xDoubling == 0 && yDoubling == 0);
+#endif
+
+ info.fLeftMargin = 0;
+
+ if (bpp <= 8)
+ {
+ EmPixMapFormat format = bpp == 1 ? kPixMapFormat1 :
+ bpp == 2 ? kPixMapFormat2 :
+ bpp == 4 ? kPixMapFormat4 :
+ kPixMapFormat8;
+
+ RGBList colorTable;
+ this->PrvGetPalette (colorTable);
+
+ // Set format, size, and color table of EmPixMap.
+
+ info.fImage.SetSize (EmPoint (width, height));
+ info.fImage.SetFormat (format);
+ info.fImage.SetRowBytes (rowBytes);
+ info.fImage.SetColorTable (colorTable);
+
+ // Determine first and last scanlines to fetch, and fetch them.
+
+ info.fFirstLine = (info.fScreenLow - baseAddr) / rowBytes;
+ info.fLastLine = (info.fScreenHigh - baseAddr - 1) / rowBytes + 1;
+
+ long firstLineOffset = info.fFirstLine * rowBytes;
+ long lastLineOffset = info.fLastLine * rowBytes;
+
+ EmMem_memcpy (
+ (void*) ((uint8*) info.fImage.GetBits () + firstLineOffset),
+ baseAddr + firstLineOffset,
+ lastLineOffset - firstLineOffset);
+ }
+ else
+ {
+ // Set depth, size, and color table of EmPixMap.
+
+ info.fImage.SetSize (EmPoint (width, height));
+ info.fImage.SetFormat (kPixMapFormat24RGB);
+
+ // Determine first and last scanlines to fetch.
+
+ info.fFirstLine = (info.fScreenLow - baseAddr) / rowBytes;
+ info.fLastLine = (info.fScreenHigh - baseAddr - 1) / rowBytes + 1;
+
+ // Get location and rowBytes of source bytes.
+
+ uint8* srcStart = EmMemGetRealAddress (baseAddr);
+ int32 srcRowBytes = rowBytes;
+ uint8* srcPtr = srcStart + srcRowBytes * info.fFirstLine;
+ uint8* srcPtr0 = srcPtr;
+
+ // Get location and rowBytes of destination bytes.
+
+ uint8* destStart = (uint8*) info.fImage.GetBits ();
+ int32 destRowBytes = info.fImage.GetRowBytes ();
+ uint8* destPtr = destStart + destRowBytes * info.fFirstLine;
+ uint8* destPtr0 = destPtr;
+
+ // Get height of range to copy.
+
+ int32 height = info.fLastLine - info.fFirstLine;
+
+ // Copy the pixels from source to dest.
+
+ for (int yy = 0; yy < height; ++yy)
+ {
+ for (int xx = 0; xx < width; ++xx)
+ {
+ uint8 p1 = EmMemDoGet8 (srcPtr++); // GGGBBBBB
+ uint8 p2 = EmMemDoGet8 (srcPtr++); // RRRRRGGG
+
+ // Merge the two together so that we get RRRRRGGG GGGBBBBB
+
+ uint16 p;
+
+ p = (p1 << 8) | p2;
+
+ // Shift the bits around, forming RRRRRrrr, GGGGGGgg, and
+ // BBBBBbbb values, where the lower-case bits are copies of
+ // the least significant bits in the upper-case bits.
+ //
+ // Note that all of this could also be done with three 64K
+ // lookup tables. If speed is an issue, we might want to
+ // investigate that.
+
+ if (bpp == 1)
+ {
+ uint8 green = ((p >> 3) & 0xFC) | ((p >> 5) & 0x03);
+ *destPtr++ = green;
+ *destPtr++ = green;
+ *destPtr++ = green;
+ }
+ else
+ {
+ *destPtr++ = ((p >> 8) & 0xF8) | ((p >> 11) & 0x07);
+ *destPtr++ = ((p >> 3) & 0xFC) | ((p >> 5) & 0x03);
+ *destPtr++ = ((p << 3) & 0xF8) | ((p >> 0) & 0x07);
+ }
+ }
+
+ srcPtr = srcPtr0 += srcRowBytes;
+ destPtr = destPtr0 += destRowBytes;
+ }
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::MQRead
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsMediaQ11xx::MQRead (emuptr address, int size)
+{
+ // Determine the offset from the beginning of the register memory range
+ // to the location we want to read.
+
+ uint32 offset = address - this->GetAddressStart ();
+
+ EmAssert (offset < this->GetAddressRange ());
+
+ // Determine the index for the register being read (treating the entire
+ // memory range as an array of 32-bit values), and determine the delta
+ // into the register.
+
+ int index = offset / 4;
+ int delta = offset - (index * 4);
+
+ EmAssert (delta >= 0);
+ EmAssert (delta < 4);
+
+ // Get the pointer to the register to read from.
+
+ UInt32 value;
+ UInt8* p = (UInt8*) fRegs.ccREG[index].GetPtr ();
+
+ if (size == 4)
+ {
+ // Make sure we're reading the whole register.
+
+ if ((delta & 3) != 0)
+ this->AddressError (address, size, true);
+
+ // Get a pointer to the "bytelanes" array that will sort out
+ // any 32-bit or 16-bit byteswapping for us.
+
+ int* bytelanes = &this->fBytelanes[delta];
+
+ // Read the value a byte at a time, reconstructing it according
+ // to the byteswapping rules.
+
+ value =
+ (((UInt32) p[bytelanes[0]]) << 24) |
+ (((UInt32) p[bytelanes[1]]) << 16) |
+ (((UInt32) p[bytelanes[2]]) << 8) |
+ (((UInt32) p[bytelanes[3]]) << 0);
+ }
+ else if (size == 2)
+ {
+ // Make sure we're reading from an even address.
+ // !!! This is really a characteristic of the host
+ // CPU and bus, not the MediaQ chip.
+
+ if ((delta & 1) != 0)
+ this->AddressError (address, size, true);
+
+ // Get a pointer to the "bytelanes" array that will sort out
+ // any 32-bit or 16-bit byteswapping for us.
+
+ int* bytelanes = &this->fBytelanes[delta];
+
+ // Read the value a byte at a time, reconstructing it according
+ // to the byteswapping rules.
+
+ value =
+ (((UInt32) p[bytelanes[0]]) << 8) |
+ (((UInt32) p[bytelanes[1]]) << 0);
+ }
+ else if (size == 1)
+ {
+ // Get a pointer to the "bytelanes" array that will sort out
+ // any 32-bit or 16-bit byteswapping for us.
+
+ int* bytelanes = &this->fBytelanes[delta];
+
+ // Read the value a byte at a time, reconstructing it according
+ // to the byteswapping rules.
+
+ value =
+ (((UInt32) p[bytelanes[0]]) << 0);
+ }
+ else
+ {
+ EmAssert (false);
+ value = 0;
+ }
+
+ return value;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::MQWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::MQWrite (emuptr address, int size, uint32 value)
+{
+ // Determine the offset from the beginning of the register memory range
+ // to the location we want to update.
+
+ uint32 offset = address - this->GetAddressStart ();
+
+ EmAssert (offset < this->GetAddressRange ());
+
+ // Determine the index for the register being updated (treating the entire
+ // memory range as an array of 32-bit values), and determine the delta
+ // into the register.
+
+ int index = offset / 4;
+ int delta = offset - (index * 4);
+
+ EmAssert (delta >= 0);
+ EmAssert (delta < 4);
+
+ // Get the pointer to the register to update.
+
+ UInt8* p = (UInt8*) fRegs.ccREG[index].GetPtr ();
+
+ if (size == 4)
+ {
+ // Make sure we're updating the whole register.
+
+ if ((delta & 3) != 0)
+ this->AddressError (address, size, false);
+
+ // Get a pointer to the "bytelanes" array that will sort out
+ // any 32-bit or 16-bit byteswapping for us.
+
+ int* bytelanes = &this->fBytelanes[delta];
+
+ // Write the value a byte at a time, using the bytelanes array
+ // to sort out the byteswapping for us.
+
+ p[bytelanes[0]] = value >> 24;
+ p[bytelanes[1]] = value >> 16;
+ p[bytelanes[2]] = value >> 8;
+ p[bytelanes[3]] = value >> 0;
+ }
+ else if (size == 2)
+ {
+ // Make sure we're updating to an even address.
+ // !!! This is really a characteristic of the host
+ // CPU and bus, not the MediaQ chip.
+
+ if ((delta & 1) != 0)
+ this->AddressError (address, size, false);
+
+ // Get a pointer to the "bytelanes" array that will sort out
+ // any 32-bit or 16-bit byteswapping for us.
+
+ int* bytelanes = &this->fBytelanes[delta];
+
+ // Write the value a byte at a time, using the bytelanes array
+ // to sort out the byteswapping for us.
+
+ p[bytelanes[0]] = value >> 8;
+ p[bytelanes[1]] = value >> 0;
+ }
+ else if (size == 1)
+ {
+ // Get a pointer to the "bytelanes" array that will sort out
+ // any 32-bit or 16-bit byteswapping for us.
+
+ int* bytelanes = &this->fBytelanes[delta];
+
+ // Write the value a byte at a time, using the bytelanes array
+ // to sort out the byteswapping for us.
+
+ p[bytelanes[0]] = value >> 0;
+ }
+ else
+ {
+ EmAssert (false);
+ }
+
+ fLastAddress = address;
+ fLastSize = size;
+
+ if (index >= 0x080 && index <= 0x093)
+ {
+ this->PrvGetGEState (index - 0x080);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::CC01Read
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsMediaQ11xx::CC01Read (emuptr address, int size)
+{
+ // Update the Command FIFO size.
+ // Update the Source FIFO size.
+ // Also make sure the busy bit is clear.
+
+ uint32 CC01 = READ_REGISTER (ccREG[0x01]);
+
+ CC01 = (CC01 & ~CMD_FIFO_MASK) | (CMD_FIFO_EMPTY & CMD_FIFO_MASK);
+ CC01 = (CC01 & ~CMD_SRC_MASK) | (CMD_SRC_EMPTY & CMD_SRC_MASK);
+ CC01 = CC01 & ~GE_BUSY_H;
+
+ WRITE_REGISTER (ccREG[0x01], CC01);
+
+ // Perform a standard read.
+
+ uint32 result = MQRead (address, size);
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::DC00Write
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::DC00Write (emuptr address, int size, uint32 value)
+{
+ // Perform a standard update.
+
+ this->MQWrite (address, size, value);
+
+ this->PrvUpdateByteLanes ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::GE00Write
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::GE00Write (emuptr address, int size, uint32 value)
+{
+ emuptr lastAddress = this->fLastAddress;
+ int lastSize = this->fLastSize;
+
+ // Perform a standard update.
+
+ this->MQWrite (address, size, value);
+
+ // If a command was issued, execute it (if autoExecute is false).
+
+ uint32 reg = READ_REGISTER (geREG[0]);
+
+ if ((reg & (1 << 27)) == 0)
+ {
+ if (size == 4)
+ {
+ this->PrvDoCommand ();
+ }
+ else if (size == 2 && lastSize == 2 && address == (lastAddress + 2))
+ {
+ this->PrvDoCommand ();
+ }
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::GE02Write
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::GE02Write (emuptr address, int size, uint32 value)
+{
+ emuptr lastAddress = this->fLastAddress;
+ int lastSize = this->fLastSize;
+
+ // Perform a standard update.
+
+ this->MQWrite (address, size, value);
+
+ // If a command was issued, execute it (if autoExecute is true).
+
+ uint32 reg = READ_REGISTER (geREG[0]);
+
+ if ((reg & (1 << 27)) != 0)
+ {
+ if (size == 4)
+ {
+ this->PrvDoCommand ();
+ }
+ else if (size == 2 && lastSize == 2 && address == (lastAddress + 2))
+ {
+ this->PrvDoCommand ();
+ }
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::SourceFifoWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::SourceFifoWrite (emuptr address, int size, uint32 value)
+{
+ emuptr lastAddress = this->fLastAddress;
+ int lastSize = this->fLastSize;
+
+ // Perform a standard update.
+
+ this->MQWrite (address, size, value);
+
+ // If a complete entry was added, push it onto the FIFO, and give the
+ // blitter a chance to run.
+
+ if (size == 4)
+ {
+ value = READ_REGISTER (sfREG[(address >> 2) & 0x0FF]);
+ fSourceFifo.push_back (value);
+ this->PrvIncBlitterRun ();
+ }
+ else if (size == 2 && lastSize == 2 && address == (lastAddress + 2))
+ {
+ value = READ_REGISTER (sfREG[(address >> 2) & 0x0FF]);
+ fSourceFifo.push_back (value);
+ this->PrvIncBlitterRun ();
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::invalidateWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::invalidateWrite (emuptr address, int size, uint32 value)
+{
+ // Perform a standard update.
+
+ this->MQWrite (address, size, value);
+
+ // Invalidate the entire LCD area so that it can get redrawn with
+ // the new palette information.
+
+ EmScreen::InvalidateAll ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::AddressError
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::AddressError (emuptr address, long size, Bool forRead)
+{
+ EmAssert (false);
+ EmAssert (gCPU68K);
+ gCPU68K->AddressError (address, size, forRead);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvGetPalette
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::PrvGetPalette (RGBList& thePalette)
+{
+ int32 bpp = this->PrvGetBPP ();
+ int32 numColors = 1 << bpp;
+
+ thePalette.resize (numColors);
+
+ for (int ii = 0; ii < numColors; ++ii)
+ {
+ uint32 reg = READ_REGISTER (cpREG[ii]);
+
+ thePalette[ii].fRed = (reg & RED_MASK) >> 0;
+ thePalette[ii].fGreen = (reg & GREEN_MASK) >> 8;
+ thePalette[ii].fBlue = (reg & BLUE_MASK) >> 16;
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvUpdateByteLanes
+// ---------------------------------------------------------------------------
+/*
+ Figuring out byteswapping:
+
+ Our source code has the following function for writing data to registers:
+
+ void sREGW (volatile UCHAR* addr, ULONG data)
+ {
+ UInt16 _data16;
+ UInt16* dc00R = (UInt16*) (MMIO_BASE + DC_BASE);
+
+ if (*dc00R & 1) // no need to swap data (16BPP mode) within word16
+ {
+ *((UInt16*) addr) = (UInt16) data; // write without swap
+ *((UInt16*) (addr + 2)) = (UInt16) __rol (data, 16); // get next word16
+ }
+ else
+ {
+ _data16 = (UInt16) (data);
+ _data16 = __rol (_data16, 8); // bswap for Big Endian
+ *((UInt16*) addr) = _data16;
+
+ _data16 = (UInt16) __rol (data, 16); // get next word16
+ _data16 = __rol (_data16, 8); // bswap for Big Endian
+ *((UInt16 *)(addr + 2)) = _data16;
+ }
+ }
+
+ My assumption here is that we want to take a data pattern like 0x01234567
+ and end up with it stored in the register as 67 45 23 01. Working from
+ the code above, if byteswapping is off, we execute the following:
+
+ *((UInt16*) addr) = (UInt16) data; // write without swap
+ *((UInt16*) (addr + 2)) = (UInt16) __rol (data, 16); // get next word16
+
+ or:
+
+ *((UInt16*) addr) = 0x4567; // write without swap
+ *((UInt16*) (addr + 2)) = 0x0123; // get next word16
+
+ In order for this to result in the right bytes getting written to the
+ right places in memory, 16-bit byteswapping must be on at the hardware
+ level. Confirming with the code in the "else" statement:
+
+ _data16 = (UInt16) (data);
+ _data16 = __rol (_data16, 8); // bswap for Big Endian
+ *((UInt16*) addr) = _data16;
+
+ _data16 = (UInt16) __rol (data, 16); // get next word16
+ _data16 = __rol (_data16, 8); // bswap for Big Endian
+ *((UInt16 *)(addr + 2)) = _data16;
+
+ or:
+
+ _data16 = 0x4567;
+ _data16 = 0x6745; // bswap for Big Endian
+ *((UInt16*) addr) = 0x6745;
+
+ _data16 = 0x0123; // get next word16
+ _data16 = 0x2301; // bswap for Big Endian
+ *((UInt16 *)(addr + 2)) = 0x2301;
+
+ In this case, if 16-bit byteswapping is turned on in the device
+ configuration register, then that will counteract the byteswapping
+ performed by the hardware. If, however, 32-bit byteswapping is
+ enabled in the device configuration register, I'm not sure what
+ will happen.
+
+ Let's take a look at another example. Registers are often written
+ using the geREG16 macro. This macro is called twice in order to
+ update the whole 32-bit register:
+
+ geREG16( GE_WIDTH_L, width );
+ geREG16( GE_HEIGHT_H, height );
+
+ Where:
+
+ #define GE_WIDTH_L (GE_WIDTH_HEIGHT) // 40204h
+ #define GE_HEIGHT_H (GE_WIDTH_HEIGHT + 2) // 40206h
+
+ There is also a geREG macro used to update the whole 32-bit register
+ at once:
+
+ geREG( GE_DEST_XY, dstAddr );
+
+ I find a number of definitions of these macros. The two sets that
+ appear most likely to be the ones used in our ROM are as follows:
+
+ # mqgeHAL.h
+
+ #define geREG16(id, data) *(pGE16 + (id)) = (UInt16)(data)
+ #define geREG(id, data) *(pGE + (id)) = (UInt32)(data)
+
+ # mqge.h
+
+ #define geREG16(id, data) *((UInt16 *)(pGE + id)) = __rol( data, 8 )
+ #define geREG(id, data) \
+ { \
+ register UInt32 _data32; \
+ _data32 = (data); \
+ geREG16(id, (UInt16)_data32); \
+ geREG16((id + 2), (UInt16)(_data32 >> 16) ); \
+ }
+
+ The second set appears to be more consistant with our first
+ study case, so let's assume that it represents what's going
+ on in our ROM.
+
+ What's left unclear is what really happens when writing a 32-bit
+ value to a 32-bit register, and how the 64-bit source data FIFO
+ is handled.
+*/
+
+void EmRegsMediaQ11xx::PrvUpdateByteLanes (void)
+{
+ // Read the register.
+
+ uint32 reg = READ_REGISTER (dcREG[0x00]);
+
+ // Adjust the bytelanes array to reflect the byteswapping options.
+ // Without any other adjustments, it appears that the CPU bytelanes
+ // are set up to swap 16-bit values with the MediaQ chip.
+
+ this->fBytelanes[0] = 1;
+ this->fBytelanes[1] = 0;
+ this->fBytelanes[2] = 3;
+ this->fBytelanes[3] = 2;
+
+ if ((reg & 1) == 1)
+ {
+ // Enable little endian mode. Byte swapping is not performed on data.
+
+ }
+ else if ((reg & 2) == 2)
+ {
+ // Enable 32-bit byte swapping for big endian to little endian conversion.
+ // byte0 <-> byte3, byte1 <-> byte2
+
+ std::swap (this->fBytelanes[0], this->fBytelanes[3]);
+ std::swap (this->fBytelanes[1], this->fBytelanes[2]);
+ }
+ else
+ {
+ // Enable 16-bit Byte swapping for big endian to little endian conversion.
+ // byte0 <-> byte1, byte2 <-> byte3
+
+ std::swap (this->fBytelanes[0], this->fBytelanes[1]);
+ std::swap (this->fBytelanes[2], this->fBytelanes[3]);
+ }
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvGetGEState
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::PrvGetGEState (int regNum)
+{
+ uint32 reg;
+
+ // ==================== GE00R ====================
+
+ if (regNum == kAllRegisters || regNum == 0)
+ {
+ reg = READ_REGISTER (geREG[0x00]);
+
+ fState.rasterOperation = (reg >> 0) & 0x000000FF;
+ fState.commandType = (reg >> 8) & 0x00000007;
+ fState.xDirection = (reg >> 11) & 0x00000001;
+ fState.yDirection = (reg >> 12) & 0x00000001;
+ fState.systemMemory = (reg >> 13) & 0x00000001;
+ fState.monoSource = (reg >> 14) & 0x00000001;
+ fState.monoPattern = (reg >> 15) & 0x00000001;
+ fState.colorTransEnable = (reg >> 16) & 0x00000001;
+ fState.destTransPolarity = (reg >> 17) & 0x00000001;
+ fState.monoTransEnable = (reg >> 18) & 0x00000001;
+ fState.monoTransPolarity = (reg >> 19) & 0x00000001;
+ fState.memToScreen = (reg >> 20) & 0x00000001;
+ fState.solidSourceColor = (reg >> 23) & 0x00000001;
+ fState.srcEqualDestStride = (reg >> 24) & 0x00000001;
+ fState.rop2Select = (reg >> 25) & 0x00000001;
+ fState.clipEnable = (reg >> 26) & 0x00000001;
+ fState.autoExecute = (reg >> 27) & 0x00000001;
+ fState.solidPattern = (reg >> 30) & 0x00000001;
+ fState.colorTransCmpSrc = (reg >> 31) & 0x00000001;
+ }
+
+ // ==================== GE01R ====================
+
+ if (regNum == kAllRegisters || regNum == 1)
+ {
+ reg = READ_REGISTER (geREG[0x01]);
+
+ // BitBLT
+
+ fState.width = (reg >> 0) & 0x00000FFF;
+ fState.height = (reg >> 16) & 0x00000FFF;
+ fState.xyConversion = (reg >> 31) & 0x00000001;
+
+ // Line
+
+ fState.gamma = (reg >> 0) & 0x0001FFFF; fState.gamma |= 0xFFFE0000;
+ fState.majorLength = (reg >> 17) & 0x00000FFF;
+ fState.yIsMajor = (reg >> 29) & 0x00000001;
+ fState.drawLastPixel = (reg >> 30) & 0x00000001;
+ fState.useXY = (reg >> 31) & 0x00000001;
+ }
+
+ // ==================== GE02R ====================
+
+ if (regNum == kAllRegisters || regNum == 2)
+ {
+ reg = READ_REGISTER (geREG[0x02]);
+
+ // BitBLT
+
+ fState.xDest = (reg >> 0) & 0x00000FFF;
+ fState.monoPatternXOffset = (reg >> 13) & 0x00000007;
+ fState.yDest = (reg >> 16) & 0x00000FFF;
+ fState.monoPatternYOffset = (reg >> 29) & 0x00000007;
+
+ // Line
+
+ fState.xStart = (reg >> 0) & 0x00000FFF;
+ fState.deltaMajor = (reg >> 12) & 0x0001FFFF;
+ fState.quadrant = (reg >> 29) & 0x00000007;
+ }
+
+ // ==================== GE03R ====================
+
+ if (regNum == kAllRegisters || regNum == 3)
+ {
+ reg = READ_REGISTER (geREG[0x03]);
+
+ // BitBLT
+
+ fState.xSrc = (reg >> 0) & 0x00000FFF;
+ fState.ySrc = (reg >> 16) & 0x00000FFF;
+
+ // Line
+
+ fState.yStart = (reg >> 0) & 0x00000FFF;
+ fState.deltaMinor = (reg >> 12) & 0x0001FFFF;
+ }
+
+ // ==================== GE04R ====================
+
+ if (regNum == kAllRegisters || regNum == 4)
+ {
+ reg = READ_REGISTER (geREG[0x04]);
+
+ fState.destTransColor = (reg >> 0) & 0x0000FFFF;
+ }
+
+ // ==================== GE05R ====================
+
+ if (regNum == kAllRegisters || regNum == 5)
+ {
+ reg = READ_REGISTER (geREG[0x05]);
+
+ fState.clipLeft = (reg >> 0) & 0x000007FF;
+ fState.clipTop = (reg >> 16) & 0x000003FF;
+ }
+
+ // ==================== GE06R ====================
+
+ if (regNum == kAllRegisters || regNum == 6)
+ {
+ reg = READ_REGISTER (geREG[0x06]);
+
+ fState.clipRight = (reg >> 0) & 0x000007FF;
+ fState.clipBottom = (reg >> 16) & 0x000003FF;
+ }
+
+ // ==================== GE07R ====================
+
+ if (regNum == kAllRegisters || regNum == 7)
+ {
+ reg = READ_REGISTER (geREG[0x07]);
+
+ fState.fgColorMonoSrc = (reg >> 0) & 0x0000FFFF;
+ }
+
+ // ==================== GE08R ====================
+
+ if (regNum == kAllRegisters || regNum == 8)
+ {
+ reg = READ_REGISTER (geREG[0x08]);
+
+ fState.bgColorMonoSrc = (reg >> 0) & 0x0000FFFF;
+ }
+
+ // ==================== GE09R ====================
+
+ if (regNum == kAllRegisters || regNum == 9)
+ {
+ reg = READ_REGISTER (geREG[0x09]);
+
+ // Lined Mode
+
+ fState.srcLineStride = (reg >> 0) & 0x000003FF;
+ fState.srcBitOffset = (reg >> 25) & 0x00000007;
+ fState.srcByteOffset = (reg >> 28) & 0x00000007;
+
+ // Packed Mode
+
+ fState.srcLeadingBits = (reg >> 0) & 0x00000007;
+ fState.srcLeadingBytes = (reg >> 3) & 0x00000007;
+ fState.srcNumBytes = (reg >> 6) & 0x000003FF;
+ fState.srcTrailingBits = (reg >> 25) & 0x00000007;
+ fState.srcTrailingBytes = (reg >> 28) & 0x0000000F;
+ }
+
+ // ==================== GE0AR ====================
+
+ if (regNum == kAllRegisters || regNum == 10)
+ {
+ reg = READ_REGISTER (geREG[0x0A]);
+
+ fState.destLineStride = (reg >> 0) & 0x000003FF;
+ fState.monoSrcBitSwap = (reg >> 28) & 0x00000001;
+ fState.rotate90 = (reg >> 29) & 0x00000001;
+ fState.colorDepth = (reg >> 30) & 0x00000003;
+ }
+
+ // ==================== GE0BR ====================
+
+ if (regNum == kAllRegisters || regNum == 11)
+ {
+ reg = READ_REGISTER (geREG[0x0B]);
+
+ fState.baseAddr = (reg >> 0) & 0x000FFFFF;
+ }
+
+ // ==================== GE0CR ====================
+
+ if (regNum == kAllRegisters || regNum == 12)
+ {
+ reg = READ_REGISTER (geREG[0x0C]);
+
+ fState.cmdLineStart = (reg >> 0) & 0x000003FF;
+ fState.cmdLineEnd = (reg >> 12) & 0x000003FF;
+ fState.cmdLineControl = (reg >> 24) & 0x00000001;
+ fState.gc1SwitchControl = (reg >> 26) & 0x00000003;
+ }
+
+ // ==================== GE0FR ====================
+
+ // ==================== GE10R ====================
+
+ if (regNum == kAllRegisters || regNum == 16)
+ {
+ reg = READ_REGISTER (geREG[0x10]);
+
+ fState.monoPattern1 = (reg >> 0) & 0xFFFFFFFF;
+ }
+
+ // ==================== GE11R ====================
+
+ if (regNum == kAllRegisters || regNum == 17)
+ {
+ reg = READ_REGISTER (geREG[0x11]);
+
+ fState.monoPattern2 = (reg >> 0) & 0xFFFFFFFF;
+ }
+
+ // ==================== GE12R ====================
+
+ if (regNum == kAllRegisters || regNum == 18)
+ {
+ reg = READ_REGISTER (geREG[0x12]);
+
+ fState.fgColorMonoPat = (reg >> 0) & 0x0000FFFF;
+ }
+
+ // ==================== GE13R ====================
+
+ if (regNum == kAllRegisters || regNum == 19)
+ {
+ reg = READ_REGISTER (geREG[0x13]);
+
+ fState.bgColorMonoPat = (reg >> 0) & 0x0000FFFF;
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvLogGEState
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::PrvLogGEState (void)
+{
+ LogAppendMsg ("========================================");
+
+ // ==================== GE00R ====================
+
+ LogAppendMsg ("GC00R:");
+ LogAppendMsg (" xDoubling %s", this->PrvGetXDoubling () ? "TRUE" : "FALSE");
+ LogAppendMsg (" yDoubling %s", this->PrvGetYDoubling () ? "TRUE" : "FALSE");
+ LogAppendMsg ("");
+
+ // ==================== GE00R ====================
+
+ LogAppendMsg ("GE00R:");
+ LogAppendMsg (" rasterOperation 0x%02X (%s)", fState.rasterOperation, kROPs[fState.rasterOperation]);
+ LogAppendMsg (" commandType %u (%s)", fState.commandType, kCommands[fState.commandType]);
+ LogAppendMsg (" xDirection %u (%s)", fState.xDirection, kDirections[fState.xDirection]);
+ LogAppendMsg (" yDirection %u (%s)", fState.yDirection, kDirections[fState.yDirection]);
+ LogAppendMsg (" systemMemory %u", fState.systemMemory);
+ LogAppendMsg (" monoSource %u", fState.monoSource);
+ LogAppendMsg (" monoPattern %u", fState.monoPattern);
+ LogAppendMsg (" colorTransEnable %u", fState.colorTransEnable);
+ LogAppendMsg (" destTransPolarity %u (Transparent if pixel is %s to test color)", fState.destTransPolarity, fState.destTransPolarity ? "NOT equal" : "equal");
+ LogAppendMsg (" monoTransEnable %u", fState.monoTransEnable);
+ LogAppendMsg (" monoTransPolarity %u", fState.monoTransPolarity);
+ LogAppendMsg (" memToScreen %u (%s)", fState.memToScreen, fState.memToScreen ? "PACKED" : "LINED");
+ LogAppendMsg (" solidSourceColor %u", fState.solidSourceColor);
+ LogAppendMsg (" srcEqualDestStride %u", fState.srcEqualDestStride);
+ LogAppendMsg (" rop2Select %u", fState.rop2Select);
+ LogAppendMsg (" clipEnable %u", fState.clipEnable);
+ LogAppendMsg (" autoExecute %u", fState.autoExecute);
+ LogAppendMsg (" solidPattern %u", fState.solidPattern);
+ LogAppendMsg (" colorTransCmpSrc %u (Compare to %s)", fState.colorTransCmpSrc, fState.colorTransCmpSrc ? "Destination" : "Source");
+ LogAppendMsg ("");
+
+ // ==================== GE01R ====================
+
+ // BitBLT
+
+ if (fState.commandType == kCommandBitBLT)
+ {
+ LogAppendMsg ("GE01R (BitBLT):");
+ LogAppendMsg (" width %u", fState.width);
+ LogAppendMsg (" height %u", fState.height);
+ LogAppendMsg (" xyConversion %u", fState.xyConversion);
+ LogAppendMsg ("");
+ }
+
+ // Line
+
+ if (fState.commandType == kCommandLine)
+ {
+ LogAppendMsg ("GE01R (Line):");
+ LogAppendMsg (" gamma %d", fState.gamma);
+ LogAppendMsg (" majorLength %u", fState.majorLength);
+ LogAppendMsg (" yIsMajor %u", fState.yIsMajor);
+ LogAppendMsg (" drawLastPixel %u", fState.drawLastPixel);
+ LogAppendMsg (" useXY %u", fState.useXY);
+ LogAppendMsg ("");
+ }
+
+ // ==================== GE02R ====================
+
+ // BitBLT
+
+ if (fState.commandType == kCommandBitBLT)
+ {
+ LogAppendMsg ("GE02R (BitBLT):");
+ LogAppendMsg (" xDest %u", fState.xDest);
+ LogAppendMsg (" yDest %u", fState.yDest);
+ LogAppendMsg (" monoPatternXOffset %u", fState.monoPatternXOffset);
+ LogAppendMsg (" monoPatternYOffset %u", fState.monoPatternYOffset);
+ LogAppendMsg ("");
+ }
+
+ // Line
+
+ if (fState.commandType == kCommandLine)
+ {
+ LogAppendMsg ("GE02R (Line):");
+ LogAppendMsg (" xStart %u", fState.xStart);
+ LogAppendMsg (" deltaMajor %u", fState.deltaMajor);
+ LogAppendMsg (" quadrant %u (%s)", fState.quadrant, kQuadrantDecode[fState.quadrant].text);
+ LogAppendMsg ("");
+ }
+
+ // ==================== GE03R ====================
+
+ // BitBLT
+
+ if (fState.commandType == kCommandBitBLT)
+ {
+ LogAppendMsg ("GE03R (BitBLT):");
+ LogAppendMsg (" xSrc %u", fState.xSrc);
+ LogAppendMsg (" ySrc %u", fState.ySrc);
+ LogAppendMsg ("");
+ }
+
+ // Line
+
+ if (fState.commandType == kCommandLine)
+ {
+ LogAppendMsg ("GE03R (Line):");
+ LogAppendMsg (" yStart %u", fState.yStart);
+ LogAppendMsg (" deltaMinor %u", fState.deltaMinor);
+ LogAppendMsg ("");
+ }
+
+ // ==================== GE04R ====================
+
+ if (fState.colorTransEnable)
+ {
+ LogAppendMsg ("GE04R:");
+ LogAppendMsg (" destTransColor 0x%04X", fState.destTransColor);
+ LogAppendMsg ("");
+ }
+
+ // ==================== GE05R/GE06R ====================
+
+ if (fState.clipEnable)
+ {
+ LogAppendMsg ("GE05R/GE06R:");
+ LogAppendMsg (" clipLeft %u", fState.clipLeft);
+ LogAppendMsg (" clipTop %u", fState.clipTop);
+ LogAppendMsg (" clipRight %u", fState.clipRight);
+ LogAppendMsg (" clipBottom %u", fState.clipBottom);
+ LogAppendMsg ("");
+ }
+
+ // ==================== GE07R/GE08R ====================
+
+ if (fState.monoSource)
+ {
+ LogAppendMsg ("GE07R/GE08R:");
+ LogAppendMsg (" fgColorMonoSrc 0x%04X", fState.fgColorMonoSrc);
+ LogAppendMsg (" bgColorMonoSrc 0x%04X", fState.bgColorMonoSrc);
+ LogAppendMsg ("");
+ }
+
+ // ==================== GE09R ====================
+
+ // Lined Mode
+
+ if (fState.memToScreen == 0)
+ {
+ LogAppendMsg ("GE09R (Lined):");
+ LogAppendMsg (" srcLineStride %u", fState.srcLineStride);
+ LogAppendMsg (" srcBitOffset %u", fState.srcBitOffset);
+ LogAppendMsg (" srcByteOffset %u", fState.srcByteOffset);
+ LogAppendMsg ("");
+ }
+
+ // Packed Mode
+
+ if (fState.memToScreen == 1)
+ {
+ LogAppendMsg ("GE09R (Packed):");
+ LogAppendMsg (" srcLeadingBits %u", fState.srcLeadingBits);
+ LogAppendMsg (" srcLeadingBytes %u", fState.srcLeadingBytes);
+ LogAppendMsg (" srcNumBytes %u", fState.srcNumBytes);
+ LogAppendMsg (" srcTrailingBits %u", fState.srcTrailingBits);
+ LogAppendMsg (" srcTrailingBytes %u", fState.srcTrailingBytes);
+ LogAppendMsg ("");
+ }
+
+ // ==================== GE0AR ====================
+
+ LogAppendMsg ("GE0AR:");
+ LogAppendMsg (" destLineStride %u", fState.destLineStride);
+ LogAppendMsg (" monoSrcBitSwap %u", fState.monoSrcBitSwap);
+ LogAppendMsg (" rotate90 %u", fState.rotate90);
+ LogAppendMsg (" colorDepth %u", fState.colorDepth);
+ LogAppendMsg ("");
+
+ // ==================== GE0BR ====================
+
+ LogAppendMsg ("GE0AR:");
+ LogAppendMsg (" baseAddr 0x%08X", fState.baseAddr);
+ LogAppendMsg ("");
+
+ // ==================== GE0CR ====================
+
+ LogAppendMsg ("GE0CR:");
+ LogAppendMsg (" cmdLineStart %u", fState.cmdLineStart);
+ LogAppendMsg (" cmdLineEnd %u", fState.cmdLineEnd);
+ LogAppendMsg (" cmdLineControl %u", fState.cmdLineControl);
+ LogAppendMsg (" gc1SwitchControl %u", fState.gc1SwitchControl);
+ LogAppendMsg ("");
+
+ // ==================== GE0FR ====================
+
+ // ==================== GE10R/GE11R ====================
+
+ if (fState.monoPattern)
+ {
+ LogAppendMsg ("GE10R/GE11R:");
+ LogAppendMsg (" monoPattern1 0x%08X", fState.monoPattern1);
+ LogAppendMsg (" monoPattern2 0x%08X", fState.monoPattern2);
+ LogAppendMsg ("");
+ }
+
+ // ==================== GE12R/GE13R ====================
+
+ if (fState.monoPattern)
+ {
+ LogAppendMsg ("GE12R/GE13R:");
+ LogAppendMsg (" fgColorMonoPat 0x%04X", fState.fgColorMonoPat);
+ LogAppendMsg (" bgColorMonoPat 0x%04X", fState.bgColorMonoPat);
+ }
+
+ LogAppendMsg ("========================================");
+
+ if (fState.commandType == kCommandBitBLT)
+ {
+ EmAssert (!(
+ (fState.width == 25) &&
+ (fState.height == 19) &&
+ (fState.xDest == 0) &&
+ (fState.yDest == 320) &&
+ (fState.xSrc == 0) &&
+ (fState.ySrc == 320) &&
+ 1));
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvDoCommand
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::PrvDoCommand (void)
+{
+ switch (fState.commandType)
+ {
+ case kCommandNOP:
+ // NOP command -- do nothing
+ break;
+
+ case kCommandBitBLT:
+ this->PrvDoBitBLT ();
+ break;
+
+ case kCommandLine:
+ this->PrvDoLine ();
+ break;
+
+ default:
+ this->PrvIllegalCommand ();
+ break;
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvDoBitBLT
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::PrvDoBitBLT (void)
+{
+ this->PrvIncBlitterInit ();
+ this->PrvIncBlitterRun ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvDoLine
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::PrvDoLine (void)
+{
+ PRINTF_LINE (" PrvDoLine: &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
+
+#if LOG_LINE
+ this->PrvLogGEState ();
+#endif
+
+ // Draw a line using the information in the GE registers,
+ // using a Bresenham line drawing algorithm. For a good
+ // tutorial on this algorithm, see:
+ //
+ // <http://www.gamedev.net/reference/articles/article1275.asp>
+
+ // Figure out our starting and ending points. The starting
+ // point is in the registers. The ending point needs to
+ // be determined by looking at deltaMajor, deltaMinor, the
+ // flag that says if the major is the X or Y access, and the
+ // X and Y directions.
+
+ uint16 yIsMajor; // 0 = x is major, 1 = y is major
+ uint16 xDirection; // 0 = x is positive, 1 = x is negative
+ uint16 yDirection; // 0 = y is positive, 1 = y is negative
+
+ if (fState.useXY)
+ {
+ yIsMajor = fState.yIsMajor;
+ xDirection = fState.xDirection;
+ yDirection = fState.yDirection;
+ }
+ else
+ {
+ yIsMajor = kQuadrantDecode[fState.quadrant].yIsMajor;
+ xDirection = kQuadrantDecode[fState.quadrant].xDirection;
+ yDirection = kQuadrantDecode[fState.quadrant].yDirection;
+ }
+
+ PRINTF_LINE (" yIsMajor: %d", yIsMajor);
+ PRINTF_LINE (" xDirection: %d", xDirection);
+ PRINTF_LINE (" yDirection: %d", yDirection);
+
+ // Get the starting x,y position. We'll be updating these
+ // variables as we draw the line.
+
+ uint16 x = fState.xStart;
+ uint16 y = fState.yStart;
+
+ PRINTF_LINE (" x: %d", x);
+ PRINTF_LINE (" y: %d", y);
+
+ // Get the direction in which the x,y coordinates needs to
+ // be updated.
+
+ int xAdjust = xDirection ? -1 : 1;
+ int yAdjust = yDirection ? -1 : 1;
+
+ PRINTF_LINE (" xAdjust: %d", xAdjust);
+ PRINTF_LINE (" yAdjust: %d", yAdjust);
+
+ // Based on which axis is the major axis, get pointers to
+ // the major and minor coordinates and the values that will
+ // be used to update them.
+
+ uint16* major;
+ uint16* minor;
+
+ int majorAdjust;
+ int minorAdjust;
+
+ if (yIsMajor)
+ {
+ major = &y;
+ minor = &x;
+
+ majorAdjust = yAdjust;
+ minorAdjust = xAdjust;
+ }
+ else
+ {
+ major = &x;
+ minor = &y;
+
+ majorAdjust = xAdjust;
+ minorAdjust = yAdjust;
+ }
+
+ PRINTF_LINE (" major: %d", *major);
+ PRINTF_LINE (" minor: %d", *minor);
+
+ PRINTF_LINE (" majorAdjust: %d", majorAdjust);
+ PRINTF_LINE (" minorAdjust: %d", minorAdjust);
+
+ PRINTF_LINE (" gamma: %d", fState.gamma);
+ PRINTF_LINE (" majorLength: %d", fState.majorLength);
+ PRINTF_LINE (" deltaMajor: %d", fState.deltaMajor);
+
+ PRINTF_LINE (" ...................");
+
+ // Initialize "error" (which is used to determine when we
+ // need to increment the minor axis coordinate) and "count"
+ // (which is used to iterate over the major axis).
+
+ int error = 0;
+ uint16 count = 0;
+
+ // Iterate over all the points along the major axis.
+
+ while (count < fState.majorLength)
+ {
+ PRINTF_LINE (" count: %d", count);
+ PRINTF_LINE (" major: %d", *major);
+ PRINTF_LINE (" minor: %d", *minor);
+
+ // Plot a point.
+
+ uint16 src = 0; // Dummy value. The ROP had better not be one that makes use of a source pixel!
+ uint16 pen = fState.fgColorMonoPat;
+ uint16 dest = this->PrvGetPixel (x, y);
+
+ uint16 output = this->PrvAdjustPixel (pen, src, dest, fState.rasterOperation);
+
+ this->PrvSetPixel (output, x, y);
+
+ // Update the major axis coordinate and adjust the error factor.
+
+ *major += majorAdjust;
+ error += 2 * fState.deltaMinor;
+
+ // See if it's time to update the minor access coordinate.
+
+ if (error > fState.deltaMajor)
+ {
+ // Update the minor axis coordinate and adjust the error factor.
+
+ *minor += minorAdjust;
+ error -= 2 * fState.deltaMajor;
+ }
+
+ // Keep track of how many points we've plotted.
+
+ count += 1;
+ }
+
+ PRINTF_LINE (" ...................");
+
+ // If we need to draw the last pixel, then do it.
+
+ if (fState.drawLastPixel)
+ {
+ PRINTF_LINE (" count: %d", count);
+ PRINTF_LINE (" major: %d", *major);
+ PRINTF_LINE (" minor: %d", *minor);
+
+ PRINTF_LINE (" ...................");
+
+ uint16 src = 0; // Dummy value. The ROP had better not be one that makes use of a source pixel!
+ uint16 pen = fState.fgColorMonoPat;
+ uint16 dest = this->PrvGetPixel (x, y);
+
+ uint16 output = this->PrvAdjustPixel (pen, src, dest, fState.rasterOperation);
+
+ this->PrvSetPixel (output, x, y);
+ }
+
+ PRINTF_LINE (" PrvDoLine: &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvIllegalCommand
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::PrvIllegalCommand (void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvSrcFifoFilledSlots
+// ---------------------------------------------------------------------------
+
+int EmRegsMediaQ11xx::PrvSrcFifoFilledSlots (void)
+{
+ return fSourceFifo.size () / 2;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvGetSrcFifoSlot
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::PrvGetSrcFifoSlot (uint32& a, uint32& b)
+{
+ a = fSourceFifo[0];
+ fSourceFifo.erase (fSourceFifo.begin ());
+
+ b = fSourceFifo[0];
+ fSourceFifo.erase (fSourceFifo.begin ());
+}
+
+
+// ---------------------------------------------------------------------------
+// Drawing Functions
+// ---------------------------------------------------------------------------
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvAdjustPixel
+// ---------------------------------------------------------------------------
+
+uint16 EmRegsMediaQ11xx::PrvAdjustPixel (uint16 pen, uint16 dest, uint8 rOpCode)
+{
+ uint16 result;
+
+ /*
+ (From MSDN)
+
+ Each raster-operation code represents a Boolean operation in which the
+ values of the pixels in the selected pen and the destination bitmap are
+ combined. The following are the two operands used in these operations.
+
+ Operand Meaning
+ ------- -------
+ P Selected pen
+ D Destination bitmap
+
+ The Boolean operators used in these operations follow.
+
+ Operator Meaning
+ -------- -------
+ a Bitwise AND
+ n Bitwise NOT (inverse)
+ o Bitwise OR
+ x Bitwise exclusive OR (XOR)
+
+ All Boolean operations are presented in reverse Polish notation. For
+ example, the following operation replaces the values of the pixels in
+ the destination bitmap with a combination of the pixel values of the
+ pen and the selected brush:
+
+ DPo
+
+ Each raster-operation code is a 32-bit integer whose high-order word
+ is a Boolean operation index and whose low-order word is the operation
+ code. The 16-bit operation index is a zero-extended 8-bit value that
+ represents all possible outcomes resulting from the Boolean operation
+ on two parameters (in this case, the pen and destination values). For
+ example, the operation indexes for the DPo and DPan operations are shown
+ in the following list.
+
+ P D DPo Dpan
+ 0 0 0 1
+ 0 1 1 1
+ 1 0 1 1
+ 1 1 1 0
+
+ The following list outlines the drawing modes and the Boolean operations
+ that they represent.
+
+ Raster operation Boolean operation
+ ---------------- -----------------
+ R2_BLACK 0
+ R2_COPYPEN P
+ R2_MASKNOTPEN DPna
+ R2_MASKPEN DPa
+ R2_MASKPENNOT PDna
+ R2_MERGENOTPEN DPno
+ R2_MERGEPEN DPo
+ R2_MERGEPENNOT PDno
+ R2_NOP D
+ R2_NOT Dn
+ R2_NOTCOPYPEN Pn
+ R2_NOTMASKPEN DPan
+ R2_NOTMERGEPEN DPon
+ R2_NOTXORPEN DPxn
+ R2_WHITE 1
+ R2_XORPEN DPx
+ */
+
+ switch (rOpCode)
+ {
+ case 0: /* 0 */
+ result = 0;
+ break;
+
+ case 1: /* DPon */
+ result = ~(dest | pen);
+ break;
+
+ case 2: /* DPna */
+ result = dest & ~pen;
+ break;
+
+ case 3: /* PN */
+ result = ~pen;
+ break;
+
+ case 4: /* PDna */
+ result = pen & ~dest;
+ break;
+
+ case 5: /* Dn */
+ result = ~dest;
+ break;
+
+ case 6: /* DPx */
+ result = dest ^ pen;
+ break;
+
+ case 7: /* DPan */
+ result = ~(dest & pen);
+ break;
+
+ case 8: /* DPa */
+ result = dest & pen;
+ break;
+
+ case 9: /* DPxn */
+ result = ~(dest ^ pen);
+ break;
+
+ case 10: /* D */
+ result = dest;
+ break;
+
+ case 11: /* DPno */
+ result = dest | ~pen;
+ break;
+
+ case 12: /* P */
+ result = pen;
+ break;
+
+ case 13: /* PDno */
+ result = pen & ~dest;
+ break;
+
+ case 14: /* DPo */
+ result = dest | pen;
+ break;
+
+ case 15: /* 1 */
+ result = ~0;
+ break;
+
+ default:
+ EmAssert (false);
+ result = 0;
+ break;
+ }
+
+#ifdef _DEBUG
+ // Double-check the special cases with the generalized code.
+
+ {
+ const int kNumBits = 8 * sizeof (result);
+
+ uint16 result2 = 0;
+
+ for (int bitNumber = 0; bitNumber < kNumBits; ++bitNumber)
+ {
+ uint8 index = (((pen >> bitNumber) & 1) << 1) |
+ (((dest >> bitNumber) & 1) << 0);
+
+ result2 |= (((rOpCode >> index) & 1) << bitNumber);
+ }
+
+ EmAssert (result == result2);
+ }
+#endif
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvAdjustPixel
+// ---------------------------------------------------------------------------
+
+uint16 EmRegsMediaQ11xx::PrvAdjustPixel (uint16 pattern, uint16 src, uint16 dest, uint8 rOpCode)
+{
+ uint16 result;
+
+ /*
+ (From MSDN)
+
+ Each raster-operation code represents a Boolean operation in which
+ the values of the pixels in the source, the selected brush, and the
+ destination are combined. The following are the three operands used
+ in these operations.
+
+ Operand Meaning
+ ------- -------
+ D Destination bitmap
+ P Selected brush (also called pattern)
+ S Source bitmap
+
+ Boolean operators used in these operations follow.
+
+ Operator Meaning
+ -------- -------
+ a Bitwise AND
+ n Bitwise NOT (inverse)
+ o Bitwise OR
+ x Bitwise exclusive OR (XOR)
+
+ ---------------------------------------------------------------------
+
+ (From Keith)
+
+ Here's another way to think about it: take the pattern, source, and
+ destination, and consider each value one bit at a time. The three
+ bits from the three values can form eight combinations. The raster
+ opcode is a bitfield containing the desired output from each of the
+ combinations. Thus:
+
+ P S D O (output)
+ --- --- --- ---
+ 0 0 0 b0
+ 0 0 1 b1
+ 0 1 0 b2
+ 0 1 1 b3
+ 1 0 0 b4
+ 1 0 1 b5
+ 1 1 0 b6
+ 1 1 1 b7
+
+ The output is the byte <b7><b6><b5><b4><b3><b2><b1><b0>. And this
+ output value is what becomes the raster opcode. Thus, if the raster
+ opcode is, for example, 0xCC, the table would be:
+
+ P S D O (output)
+ --- --- --- ---
+ 0 0 0 0
+ 0 0 1 0
+ 0 1 0 1
+ 0 1 1 1
+ 1 0 0 0
+ 1 0 1 0
+ 1 1 0 1
+ 1 1 1 1
+
+ So, the we look at three bits from the source and they're all zero,
+ then the output is zero. If they're all one, then the output is
+ one. If the pattern is one and the source and destination are zero,
+ then the output is zero. Overall,
+
+ Output[x] = ROP[P[x],S[x],D[x]]
+
+ where "x" is 0..7, and "P[x],S[x],D[x]" is a bitfield composed of
+ the given bits.
+
+ We will use this generalization for the default case. However, for
+ the most common raster ops, we can manipulate all bits of all the
+ incumbant values simultaneously. We special-case those opcodes.
+ */
+
+ switch (rOpCode)
+ {
+ case 0x00: // 00000042 0 BLACKNESS
+ result = 0;
+ break;
+
+ // case 0x01: // 00010289 DPSoon –
+ // case 0x02: // 00020C89 DPSona –
+ // case 0x03: // 000300AA PSon –
+ // case 0x04: // 00040C88 SDPona –
+ // case 0x05: // 000500A9 DPon –
+ // case 0x06: // 00060865 PDSxnon –
+ // case 0x07: // 000702C5 PDSaon –
+ // case 0x08: // 00080F08 SDPnaa –
+ // case 0x09: // 00090245 PDSxon –
+ case 0x0A: // 000A0329 DPna –
+ result = dest & ~pattern;
+ break;
+
+ // case 0x0B: // 000B0B2A PSDnaon –
+ // case 0x0C: // 000C0324 SPna –
+ // case 0x0D: // 000D0B25 PDSnaon –
+ // case 0x0E: // 000E08A5 PDSonon –
+ case 0x0F: // 000F0001 Pn –
+ result = ~pattern;
+ break;
+
+ // case 0x10: // 00100C85 PDSona –
+ case 0x11: // 001100A6 DSon NOTSRCERASE
+ result = ~(dest | src);
+ break;
+
+ // case 0x12: // 00120868 SDPxnon –
+ // case 0x13: // 001302C8 SDPaon –
+ // case 0x14: // 00140869 DPSxnon –
+ // case 0x15: // 001502C9 DPSaon –
+ // case 0x16: // 00165CCA PSDPSanaxx –
+ // case 0x17: // 00171D54 SSPxDSxaxn –
+ // case 0x18: // 00180D59 SPxPDxa –
+ // case 0x19: // 00191CC8 SDPSanaxn –
+ // case 0x1A: // 001A06C5 PDSPaox –
+ // case 0x1B: // 001B0768 SDPSxaxn –
+ // case 0x1C: // 001C06CA PSDPaox –
+ // case 0x1D: // 001D0766 DSPDxaxn –
+ // case 0x1E: // 001E01A5 PDSox –
+ // case 0x1F: // 001F0385 PDSoan –
+ // case 0x20: // 00200F09 DPSnaa –
+ // case 0x21: // 00210248 SDPxon –
+ case 0x22: // 00220326 DSna –
+ result = dest & ~src;
+ break;
+
+ // case 0x23: // 00230B24 SPDnaon –
+ // case 0x24: // 00240D55 SPxDSxa –
+ // case 0x25: // 00251CC5 PDSPanaxn –
+ // case 0x26: // 002606C8 SDPSaox –
+ // case 0x27: // 00271868 SDPSxnox –
+ // case 0x28: // 00280369 DPSxa –
+ // case 0x29: // 002916CA PSDPSaoxxn –
+ // case 0x2A: // 002A0CC9 DPSana –
+ // case 0x2B: // 002B1D58 SSPxPDxaxn –
+ // case 0x2C: // 002C0784 SPDSoax –
+ // case 0x2D: // 002D060A PSDnox –
+ // case 0x2E: // 002E064A PSDPxox –
+ // case 0x2F: // 002F0E2A PSDnoan –
+ // case 0x30: // 0030032A PSna –
+ // case 0x31: // 00310B28 SDPnaon –
+ // case 0x32: // 00320688 SDPSoox –
+ case 0x33: // 00330008 Sn NOTSRCCOPY
+ result = ~src;
+ break;
+
+ // case 0x34: // 003406C4 SPDSaox –
+ // case 0x35: // 00351864 SPDSxnox –
+ // case 0x36: // 003601A8 SDPox –
+ // case 0x37: // 00370388 SDPoan –
+ // case 0x38: // 0038078A PSDPoax –
+ // case 0x39: // 00390604 SPDnox –
+ // case 0x3A: // 003A0644 SPDSxox –
+ // case 0x3B: // 003B0E24 SPDnoan –
+ // case 0x3C: // 003C004A PSx –
+ // case 0x3D: // 003D18A4 SPDSonox –
+ // case 0x3E: // 003E1B24 SPDSnaox –
+ // case 0x3F: // 003F00EA PSan –
+ // case 0x40: // 00400F0A PSDnaa –
+ // case 0x41: // 00410249 DPSxon –
+ // case 0x42: // 00420D5D SDxPDxa –
+ // case 0x43: // 00431CC4 SPDSanaxn –
+ case 0x44: // 00440328 SDna SRCERASE
+ result = src & ~dest;
+ break;
+
+ // case 0x45: // 00450B29 DPSnaon –
+ // case 0x46: // 004606C6 DSPDaox –
+ // case 0x47: // 0047076A PSDPxaxn –
+ // case 0x48: // 00480368 SDPxa –
+ // case 0x49: // 004916C5 PDSPDaoxxn –
+ // case 0x4A: // 004A0789 DPSDoax –
+ // case 0x4B: // 004B0605 PDSnox –
+ // case 0x4C: // 004C0CC8 SDPana –
+ // case 0x4D: // 004D1954 SSPxDSxoxn –
+ // case 0x4E: // 004E0645 PDSPxox –
+ // case 0x4F: // 004F0E25 PDSnoan –
+ // case 0x50: // 00500325 PDna –
+ // case 0x51: // 00510B26 DSPnaon –
+ // case 0x52: // 005206C9 DPSDaox –
+ // case 0x53: // 00530764 SPDSxaxn –
+ // case 0x54: // 005408A9 DPSonon –
+ case 0x55: // 00550009 Dn DSTINVERT
+ result = ~dest;
+ break;
+
+ // case 0x56: // 005601A9 DPSox –
+ // case 0x57: // 00570389 DPSoan –
+ // case 0x58: // 00580785 PDSPoax –
+ // case 0x59: // 00590609 DPSnox –
+ case 0x5A: // 005A0049 DPx PATINVERT
+ result = dest ^ pattern;
+ break;
+
+ // case 0x5B: // 005B18A9 DPSDonox –
+ // case 0x5C: // 005C0649 DPSDxox –
+ // case 0x5D: // 005D0E29 DPSnoan –
+ // case 0x5E: // 005E1B29 DPSDnaox –
+ case 0x5F: // 005F00E9 DPan –
+ result = ~(dest & pattern);
+ break;
+
+ // case 0x60: // 00600365 PDSxa –
+ // case 0x61: // 006116C6 DSPDSaoxxn –
+ // case 0x62: // 00620786 DSPDoax –
+ // case 0x63: // 00630608 SDPnox –
+ // case 0x64: // 00640788 SDPSoax –
+ // case 0x65: // 00650606 DSPnox –
+ case 0x66: // 00660046 DSx SRCINVERT
+ result = dest ^ src;
+ break;
+
+ // case 0x67: // 006718A8 SDPSonox –
+ // case 0x68: // 006858A6 DSPDSonoxxn –
+ // case 0x69: // 00690145 PDSxxn –
+ // case 0x6A: // 006A01E9 DPSax –
+ // case 0x6B: // 006B178A PSDPSoaxxn –
+ // case 0x6C: // 006C01E8 SDPax –
+ // case 0x6D: // 006D1785 PDSPDoaxxn –
+ // case 0x6E: // 006E1E28 SDPSnoax –
+ // case 0x6F: // 006F0C65 PDSxnan –
+ // case 0x70: // 00700CC5 PDSana –
+ // case 0x71: // 00711D5C SSDxPDxaxn –
+ // case 0x72: // 00720648 SDPSxox –
+ // case 0x73: // 00730E28 SDPnoan –
+ // case 0x74: // 00740646 DSPDxox –
+ // case 0x75: // 00750E26 DSPnoan –
+ // case 0x76: // 00761B28 SDPSnaox –
+ case 0x77: // 007700E6 DSan –
+ result = ~(dest & src);
+ break;
+
+ // case 0x78: // 007801E5 PDSax –
+ // case 0x79: // 00791786 DSPDSoaxxn –
+ // case 0x7A: // 007A1E29 DPSDnoax –
+ // case 0x7B: // 007B0C68 SDPxnan –
+ // case 0x7C: // 007C1E24 SPDSnoax –
+ // case 0x7D: // 007D0C69 DPSxnan –
+ // case 0x7E: // 007E0955 SPxDSxo –
+ // case 0x7F: // 007F03C9 DPSaan –
+ // case 0x80: // 008003E9 DPSaa –
+ // case 0x81: // 00810975 SPxDSxon –
+ // case 0x82: // 00820C49 DPSxna –
+ // case 0x83: // 00831E04 SPDSnoaxn –
+ // case 0x84: // 00840C48 SDPxna –
+ // case 0x85: // 00851E05 PDSPnoaxn –
+ // case 0x86: // 008617A6 DSPDSoaxx –
+ // case 0x87: // 008701C5 PDSaxn –
+ case 0x88: // 008800C6 DSa SRCAND
+ result = dest & src;
+ break;
+
+ // case 0x89: // 00891B08 SDPSnaoxn –
+ // case 0x8A: // 008A0E06 DSPnoa –
+ // case 0x8B: // 008B0666 DSPDxoxn –
+ // case 0x8C: // 008C0E08 SDPnoa –
+ // case 0x8D: // 008D0668 SDPSxoxn –
+ // case 0x8E: // 008E1D7C SSDxPDxax –
+ // case 0x8F: // 008F0CE5 PDSanan –
+ // case 0x90: // 00900C45 PDSxna –
+ // case 0x91: // 00911E08 SDPSnoaxn –
+ // case 0x92: // 009217A9 DPSDPoaxx –
+ // case 0x93: // 009301C4 SPDaxn –
+ // case 0x94: // 009417AA PSDPSoaxx –
+ // case 0x95: // 009501C9 DPSaxn –
+ // case 0x96: // 00960169 DPSxx –
+ // case 0x97: // 0097588A PSDPSonoxx –
+ // case 0x98: // 00981888 SDPSonoxn –
+ case 0x99: // 00990066 DSxn –
+ result = ~(dest ^ src);
+ break;
+
+ // case 0x9A: // 009A0709 DPSnax –
+ // case 0x9B: // 009B07A8 SDPSoaxn –
+ // case 0x9C: // 009C0704 SPDnax –
+ // case 0x9D: // 009D07A6 DSPDoaxn –
+ // case 0x9E: // 009E16E6 DSPDSaoxx –
+ // case 0x9F: // 009F0345 PDSxan –
+ case 0xA0: // 00A000C9 DPa –
+ result = dest & pattern;
+ break;
+
+ // case 0xA1: // 00A11B05 PDSPnaoxn –
+ // case 0xA2: // 00A20E09 DPSnoa –
+ // case 0xA3: // 00A30669 DPSDxoxn –
+ // case 0xA4: // 00A41885 PDSPonoxn –
+ case 0xA5: // 00A50065 PDxn –
+ result = ~(pattern ^ dest);
+ break;
+
+ // case 0xA6: // 00A60706 DSPnax –
+ // case 0xA7: // 00A707A5 PDSPoaxn –
+ // case 0xA8: // 00A803A9 DPSoa –
+ // case 0xA9: // 00A90189 DPSoxn –
+ // case 0xAA: // 00AA0029 D –
+ // case 0xAB: // 00AB0889 DPSono –
+ // case 0xAC: // 00AC0744 SPDSxax –
+ // case 0xAD: // 00AD06E9 DPSDaoxn –
+ // case 0xAE: // 00AE0B06 DSPnao –
+ case 0xAF: // 00AF0229 DPno –
+ result = dest | ~pattern;
+ break;
+
+ // case 0xB0: // 00B00E05 PDSnoa –
+ // case 0xB1: // 00B10665 PDSPxoxn –
+ // case 0xB2: // 00B21974 SSPxDSxox –
+ // case 0xB3: // 00B30CE8 SDPanan –
+ // case 0xB4: // 00B4070A PSDnax –
+ // case 0xB5: // 00B507A9 DPSDoaxn –
+ // case 0xB6: // 00B616E9 DPSDPaoxx –
+ // case 0xB7: // 00B70348 SDPxan –
+ // case 0xB8: // 00B8074A PSDPxax –
+ // case 0xB9: // 00B906E6 DSPDaoxn –
+ // case 0xBA: // 00BA0B09 DPSnao –
+ case 0xBB: // 00BB0226 DSno MERGEPAINT
+ result = dest | ~src;
+ break;
+
+ // case 0xBC: // 00BC1CE4 SPDSanax –
+ // case 0xBD: // 00BD0D7D SDxPDxan –
+ // case 0xBE: // 00BE0269 DPSxo –
+ // case 0xBF: // 00BF08C9 DPSano –
+ case 0xC0: // 00C000CA PSa MERGECOPY
+ result = pattern & src;
+ break;
+
+ // case 0xC1: // 00C11B04 SPDSnaoxn –
+ // case 0xC2: // 00C21884 SPDSonoxn –
+ // case 0xC3: // 00C3006A PSxn –
+ // case 0xC4: // 00C40E04 SPDnoa –
+ // case 0xC5: // 00C50664 SPDSxoxn –
+ // case 0xC6: // 00C60708 SDPnax –
+ // case 0xC7: // 00C707AA PSDPoaxn –
+ // case 0xC8: // 00C803A8 SDPoa –
+ // case 0xC9: // 00C90184 SPDoxn –
+ // case 0xCA: // 00CA0749 DPSDxax –
+ // case 0xCB: // 00CB06E4 SPDSaoxn –
+ case 0xCC: // 00CC0020 S SRCCOPY
+ result = src;
+ break;
+
+ // case 0xCD: // 00CD0888 SDPono –
+ // case 0xCE: // 00CE0B08 SDPnao –
+ // case 0xCF: // 00CF0224 SPno –
+ // case 0xD0: // 00D00E0A PSDnoa –
+ // case 0xD1: // 00D1066A PSDPxoxn –
+ // case 0xD2: // 00D20705 PDSnax –
+ // case 0xD3: // 00D307A4 SPDSoaxn –
+ // case 0xD4: // 00D41D78 SSPxPDxax –
+ // case 0xD5: // 00D50CE9 DPSanan –
+ // case 0xD6: // 00D616EA PSDPSaoxx –
+ // case 0xD7: // 00D70349 DPSxan –
+ // case 0xD8: // 00D80745 PDSPxax –
+ // case 0xD9: // 00D906E8 SDPSaoxn –
+ // case 0xDA: // 00DA1CE9 DPSDanax –
+ // case 0xDB: // 00DB0D75 SPxDSxan –
+ // case 0xDC: // 00DC0B04 SPDnao –
+ // case 0xDD: // 00DD0228 SDno –
+ // case 0xDE: // 00DE0268 SDPxo –
+ // case 0xDF: // 00DF08C8 SDPano –
+ // case 0xE0: // 00E003A5 PDSoa –
+ // case 0xE1: // 00E10185 PDSoxn –
+ // case 0xE2: // 00E20746 DSPDxax –
+ // case 0xE3: // 00E306EA PSDPaoxn –
+ // case 0xE4: // 00E40748 SDPSxax –
+ // case 0xE5: // 00E506E5 PDSPaoxn –
+ // case 0xE6: // 00E61CE8 SDPSanax –
+ // case 0xE7: // 00E70D79 SPxPDxan –
+ // case 0xE8: // 00E81D74 SSPxDSxax –
+ // case 0xE9: // 00E95CE6 DSPDSanaxxn –
+ // case 0xEA: // 00EA02E9 DPSao –
+ // case 0xEB: // 00EB0849 DPSxno –
+ // case 0xEC: // 00EC02E8 SDPao –
+ // case 0xED: // 00ED0848 SDPxno –
+ case 0xEE: // 00EE0086 DSo SRCPAINT
+ result = dest | src;
+ break;
+
+ // case 0xEF: // 00EF0A08 SDPnoo –
+ case 0xF0: // 00F00021 P PATCOPY
+ result = pattern;
+ break;
+
+ // case 0xF1: // 00F10885 PDSono –
+ // case 0xF2: // 00F20B05 PDSnao –
+ // case 0xF3: // 00F3022A PSno –
+ // case 0xF4: // 00F40B0A PSDnao –
+ // case 0xF5: // 00F50225 PDno –
+ // case 0xF6: // 00F60265 PDSxo –
+ // case 0xF7: // 00F708C5 PDSano –
+ // case 0xF8: // 00F802E5 PDSao –
+ // case 0xF9: // 00F90845 PDSxno –
+ case 0xFA: // 00FA0089 DPo –
+ result = dest | pattern;
+ break;
+
+ case 0xFB: // 00FB0A09 DPSnoo PATPAINT
+ result = dest | (pattern | ~src);
+ break;
+
+ // case 0xFC: // 00FC008A PSo –
+ // case 0xFD: // 00FD0A0A PSDnoo –
+ // case 0xFE: // 00FE02A9 DPSoo –
+ case 0xFF: // 00FF0062 1 WHITENESS
+ result = ~0;
+ break;
+
+ default:
+ {
+ const int kNumBits = 8 * sizeof (result);
+
+ result = 0;
+
+ for (int bitNumber = 0; bitNumber < kNumBits; ++bitNumber)
+ {
+ uint8 index = (((pattern >> bitNumber) & 1) << 2) |
+ (((src >> bitNumber) & 1) << 1) |
+ (((dest >> bitNumber) & 1) << 0);
+
+ result |= (((rOpCode >> index) & 1) << bitNumber);
+ }
+ }
+ break;
+ }
+
+#ifdef _DEBUG
+ // Double-check the special cases with the generalized code.
+
+ {
+ const int kNumBits = 8 * sizeof (result);
+
+ uint16 result2 = 0;
+
+ for (int bitNumber = 0; bitNumber < kNumBits; ++bitNumber)
+ {
+ uint8 index = (((pattern >> bitNumber) & 1) << 2) |
+ (((src >> bitNumber) & 1) << 1) |
+ (((dest >> bitNumber) & 1) << 0);
+
+ result2 |= (((rOpCode >> index) & 1) << bitNumber);
+ }
+
+ EmAssert (result == result2);
+ }
+#endif
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvSetPixel
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::PrvSetPixel (uint16 pixel, uint16 x, uint16 y)
+{
+ emuptr pixelLocation = this->PrvGetPixelLocation (x, y);
+
+ switch (fState.colorDepth)
+ {
+ case kColorDepth8:
+ EmMemPut8 (pixelLocation, pixel);
+ break;
+
+ case kColorDepth16:
+ EmAssert (::IsEven (pixelLocation));
+ EmMemPut16 (pixelLocation, pixel);
+ break;
+
+ default:
+ EmAssert (false);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvGetPixel
+// ---------------------------------------------------------------------------
+
+uint16 EmRegsMediaQ11xx::PrvGetPixel (uint16 x, uint16 y)
+{
+ uint16 result;
+ emuptr pixelLocation = this->PrvGetPixelLocation (x, y);
+
+ switch (fState.colorDepth)
+ {
+ case kColorDepth8:
+ result = EmMemGet8 (pixelLocation);
+ break;
+
+ case kColorDepth16:
+ EmAssert (::IsEven (pixelLocation));
+ result = EmMemGet16 (pixelLocation);
+ break;
+
+ default:
+ EmAssert (false);
+ result = 0;
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvGetPixelLocation
+// ---------------------------------------------------------------------------
+
+emuptr EmRegsMediaQ11xx::PrvGetPixelLocation (uint16 x, uint16 y)
+{
+ int bytesPerPixel;
+
+ switch (fState.colorDepth)
+ {
+ case kColorDepth8:
+ bytesPerPixel = 1;
+ break;
+
+ case kColorDepth16:
+ bytesPerPixel = 2;
+ break;
+
+ default:
+ EmAssert (false);
+ return 0;
+ }
+
+ if (fState.rotate90)
+ {
+ // Rotate 90 deg clockwise.
+
+ /*
+ -----x y--
+ |+--------------------+|
+ || ||
+ y| 1 ||
+ | 2 |x
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------------------+
+
+ Point 1 is the original point.
+ Point 2 is the rotated point.
+ */
+
+ int16 newX = fState.destLineStride * bytesPerPixel - y;
+ int16 newY = x;
+
+ x = newX;
+ y = newY;
+ }
+
+ emuptr frameBuffer = this->PrvGetVideoBase () + fState.baseAddr;
+ emuptr scanLine = frameBuffer + (y * fState.destLineStride);
+ emuptr scanByte = scanLine + (x * bytesPerPixel);
+
+ EmAssert (scanByte >= fBaseVideoAddr);
+ EmAssert (scanByte + bytesPerPixel <= fBaseVideoAddr + MMIO_OFFSET);
+
+ return scanByte;
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvIncBlitterInit
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::PrvIncBlitterInit (void)
+{
+ PRINTF_BLIT (" PrvIncBlitterInit: &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
+
+#if LOG_BLIT
+ this->PrvLogGEState ();
+#endif
+
+ fBlitInProgress = true;
+
+ fCurXOffset = 0;
+ fCurYOffset = 0;
+
+ fUsesPattern = this->PrvUsesPattern ();
+ fUsesSource = this->PrvUsesSource ();
+
+ if (!fUsesPattern)
+ PRINTF_BLIT (" PrvIncBlitterInit: pattern not used...");
+
+ if (!fUsesSource)
+ PRINTF_BLIT (" PrvIncBlitterInit: source data not used...");
+
+ if (fState.monoSource)
+ {
+ if (fState.monoTransEnable)
+ {
+ if (fState.monoTransPolarity)
+ {
+ PRINTF_BLIT (" PrvIncBlitterInit: Foreground is transparent...");
+ }
+ else
+ {
+ PRINTF_BLIT (" PrvIncBlitterInit: Background is transparent...");
+ }
+ }
+ }
+ else if (fState.colorTransEnable)
+ {
+ if (fState.destTransPolarity == 0)
+ {
+ if (fState.colorTransCmpSrc == 0)
+ {
+ PRINTF_BLIT (" PrvIncBlitterInit: Treat all destTransColor pixels in the source as transparent...");
+ }
+ else
+ {
+ PRINTF_BLIT (" PrvIncBlitterInit: Leave all destTransColor pixels in the destination alone...");
+ }
+ }
+ else
+ {
+ if (fState.colorTransCmpSrc == 0)
+ {
+ PRINTF_BLIT (" PrvIncBlitterInit: Transfer only destTransColor pixels from the source to the destination...");
+ }
+ else
+ {
+ PRINTF_BLIT (" PrvIncBlitterInit: Update only destTransColor pixels in the destination with source pixels...");
+ }
+ }
+ }
+
+ this->PrvPatternPipeInit ();
+ this->PrvSrcPipeInit ();
+ this->PrvDestPipeInit ();
+
+ PRINTF_BLIT (" PrvIncBlitterInit: &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvIncBlitterRun
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::PrvIncBlitterRun (void)
+{
+ if (!fBlitInProgress)
+ return;
+
+ static long counter = 0;
+
+ PRINTF_BLIT (" PrvIncBlitterRun: **************************************************");
+ PRINTF_BLIT (" PrvIncBlitterRun: counter: %u", ++counter);
+ PRINTF_BLIT (" PrvIncBlitterRun: **************************************************");
+
+ while (fBlitInProgress)
+ {
+ Bool stalled;
+
+ // Get the relevent pixel values.
+
+ uint16 source = this->PrvSrcPipeNextPixel (stalled);
+
+ // If the source FIFO stalled (no more input data for now),
+ // return false, indicating that the BLT operation is still
+ // in progress.
+
+ if (stalled)
+ {
+ PRINTF_BLIT (" PrvIncBlitterRun: stalled...");
+ break;
+ }
+
+ // Continue getting more pixel values.
+
+ uint16 pattern = this->PrvPatternPipeNextPixel ();
+ uint16 dest = this->PrvDestPipeNextPixel ();
+ uint16 output = this->PrvAdjustPixel (pattern, source, dest,
+ fState.rasterOperation);
+
+ PRINTF_BLIT (" PrvIncBlitterRun: pattern: 0x%04X", pattern);
+ PRINTF_BLIT (" PrvIncBlitterRun: source: 0x%04X", source);
+ PRINTF_BLIT (" PrvIncBlitterRun: dest: 0x%04X", dest);
+ PRINTF_BLIT (" PrvIncBlitterRun: output: 0x%04X", output);
+
+ // Write this pixel as long as it's not transparent or clipped out.
+
+ if (!this->PrvTransparent (source, dest, pattern) && !this->PrvClipped ())
+ {
+ PRINTF_BLIT (" PrvIncBlitterRun: setting...");
+
+ this->PrvSetPixel (output, fXDest, fYDest);
+ }
+ else
+ {
+ PRINTF_BLIT (" PrvIncBlitterRun: skipping...");
+ }
+
+ // Move to the next X/Y position.
+
+ fBlitInProgress = this->PrvNextXY ();
+
+ if (!fBlitInProgress)
+ {
+ EmAssert (this->PrvSrcFifoFilledSlots () == 0);
+ PRINTF_BLIT (" PrvIncBlitterRun: Completed!");
+ }
+ }
+
+ PRINTF_BLIT (" PrvIncBlitterRun: **************************************************");
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvPatternPipeInit
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::PrvPatternPipeInit (void)
+{
+ fXPattern = fState.monoPatternXOffset;
+ fYPattern = fState.monoPatternYOffset;
+
+ PRINTF_BLIT (" PrvPatternPipeInit: fXPattern: %u", fXPattern);
+ PRINTF_BLIT (" PrvPatternPipeInit: fYPattern: %u", fYPattern);
+
+ // Expand the specified pattern into a pixel array.
+
+ if (fUsesPattern)
+ {
+ // Force the pattern data to be a solid color, if specified.
+
+ if (fState.solidPattern)
+ {
+ PRINTF_BLIT (" PrvPatternPipeInit: filling with: 0x%04X",
+ fState.fgColorMonoPat);
+
+ for (int ii = 0; ii < 64; ++ii)
+ {
+ fPatternPipe [ii] = fState.fgColorMonoPat;
+ }
+ }
+
+ // If the pattern is specified as a 64-bit array, expand it
+ // into a 64-byte array with the fore- and background colors set.
+
+ else if (fState.monoPattern)
+ {
+ /*
+ A pattern is an 8x8 structure, for a total of 64 bits.
+ This is represented on the Palm as an 8 element array
+ of 8-bit bytes. When translated into MediaQ terms, they
+ are transferred to the registers with:
+
+ gePAT16( GE_MONO_PAT0_L, *patPtr++ );
+ gePAT16( GE_MONO_PAT0_H, *patPtr++ );
+ gePAT16( GE_MONO_PAT1_L, *patPtr++ );
+ gePAT16( GE_MONO_PAT1_H, *patPtr );
+
+ where "patPtr" is a UInt16*. Thus, when read back out
+ as two DWORDs, the LSB of monoPattern1 contains the first
+ byte of the pattern, the next LSB contains the second
+ byte, all the way up to where the MSB of monoPattern2
+ contains the last byte.
+ */
+
+ PRINTF_BLIT (" PrvPatternPipeInit: expanding: 0x%08X 0x%08X",
+ fState.monoPattern1, fState.monoPattern2);
+
+ this->PrvExpandMono32 (fState.monoPattern1, &fPatternPipe [0],
+ fState.fgColorMonoPat, fState.bgColorMonoPat);
+
+ this->PrvExpandMono32 (fState.monoPattern2, &fPatternPipe [32],
+ fState.fgColorMonoPat, fState.bgColorMonoPat);
+
+ uint16* p = fPatternPipe;
+ UNUSED_PARAM(p);
+
+ PRINTF_BLIT (" PrvPatternPipeInit: 0: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X",
+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
+ PRINTF_BLIT (" PrvPatternPipeInit: 1: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X",
+ p[8+0], p[8+1], p[8+2], p[8+3], p[8+4], p[8+5], p[8+6], p[8+7]);
+ PRINTF_BLIT (" PrvPatternPipeInit: 2: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X",
+ p[16+0], p[16+1], p[16+2], p[16+3], p[16+4], p[16+5], p[16+6], p[16+7]);
+ PRINTF_BLIT (" PrvPatternPipeInit: 3: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X",
+ p[24+0], p[24+1], p[24+2], p[24+3], p[24+4], p[24+5], p[24+6], p[24+7]);
+ PRINTF_BLIT (" PrvPatternPipeInit: 4: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X",
+ p[32+0], p[32+1], p[32+2], p[32+3], p[32+4], p[32+5], p[32+6], p[32+7]);
+ PRINTF_BLIT (" PrvPatternPipeInit: 5: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X",
+ p[40+0], p[40+1], p[40+2], p[40+3], p[40+4], p[40+5], p[40+6], p[40+7]);
+ PRINTF_BLIT (" PrvPatternPipeInit: 6: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X",
+ p[48+0], p[48+1], p[48+2], p[48+3], p[48+4], p[48+5], p[48+6], p[48+7]);
+ PRINTF_BLIT (" PrvPatternPipeInit: 7: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X",
+ p[56+0], p[56+1], p[56+2], p[56+3], p[56+4], p[56+5], p[56+6], p[56+7]);
+ }
+ else
+ {
+ // The monoPattern bit MUST be programmed to 1, according to
+ // the docs. Color patterns don't appear to be supported.
+
+ EmAssert (false);
+ }
+ }
+
+ // We're not making use of any pattern data.
+
+ else
+ {
+ // Do nothing. The pattern array will be garbage, but the theory
+ // here is that it's not going to be used.
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvPatternPipeNextPixel
+// ---------------------------------------------------------------------------
+
+uint16 EmRegsMediaQ11xx::PrvPatternPipeNextPixel (void)
+{
+ uint16 result = fPatternPipe [fXPattern + fYPattern * 8];
+
+ PRINTF_BLIT (" PrvPatternPipeNextPixel: fXPattern: %u", fXPattern);
+ PRINTF_BLIT (" PrvPatternPipeNextPixel: fYPattern: %u", fYPattern);
+ PRINTF_BLIT (" PrvPatternPipeNextPixel: result: 0x%04X", result);
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvPatternPipeNextX
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::PrvPatternPipeNextX (void)
+{
+ ++fXPattern;
+
+ if (fXPattern == 8)
+ {
+ fXPattern = 0;
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvPatternPipeNextY
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::PrvPatternPipeNextY (void)
+{
+ ++fYPattern;
+ fXPattern = fState.monoPatternXOffset;
+
+ if (fYPattern == 8)
+ {
+ fYPattern = 0;
+ }
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvSrcPipeInit
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::PrvSrcPipeInit (void)
+{
+ fXSrc = fState.xSrc;
+ fYSrc = fState.ySrc;
+
+ if (fState.xyConversion)
+ {
+ if (fState.xDirection)
+ fXSrc += fState.width - 1;
+
+ if (fState.yDirection)
+ fYSrc += fState.height - 1;
+ }
+
+ if (fUsesSource && !fState.solidSourceColor && fState.systemMemory)
+ {
+ fLeadingSourcePixels = this->PrvLeadingPixels ();
+ fTrailingSourcePixels = this->PrvTrailingPixels ();
+
+ PRINTF_BLIT (" PrvSrcPipeInit: fLeadingSourcePixels: %u", fLeadingSourcePixels);
+ PRINTF_BLIT (" PrvSrcPipeInit: fTrailingSourcePixels: %u", fTrailingSourcePixels);
+ }
+
+ // Setting both of these variables to the same value will force the
+ // source pipe to fill itself from the source data FIFO the first
+ // time we access it (assuming that that's where the source data is
+ // coming from).
+
+ fSourcePipeIndex = 0;
+ fSourcePipeMax = 0;
+
+ fSourcePipeSkip = fLeadingSourcePixels;
+
+ PRINTF_BLIT (" PrvSrcPipeInit: fXSrc: %u", fXSrc);
+ PRINTF_BLIT (" PrvSrcPipeInit: fYSrc: %u", fYSrc);
+ PRINTF_BLIT (" PrvSrcPipeInit: fSourcePipeSkip: %u", fSourcePipeSkip);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvSrcPipeNextPixel
+// ---------------------------------------------------------------------------
+
+uint16 EmRegsMediaQ11xx::PrvSrcPipeNextPixel (Bool& stalled)
+{
+ stalled = false;
+
+ if (!fUsesSource)
+ {
+ // Return a dummy value. The theory here is that it's not
+ // going to be used.
+
+ PRINTF_BLIT (" PrvSrcPipeNextPixel: result: <dummy>");
+
+ return 0;
+ }
+
+ // Force the source data to be a solid color, if specified.
+
+ if (fState.solidSourceColor)
+ {
+ PRINTF_BLIT (" PrvSrcPipeNextPixel: result: 0x%04X (solid)", fState.fgColorMonoSrc);
+
+ return fState.fgColorMonoSrc;
+ }
+
+ // If we're getting source data from system memory, then read
+ // the data from the source FIFO.
+
+ if (fState.systemMemory)
+ {
+ uint16 result;
+
+ // Loop getting source pixels. Normally, we'll just return
+ // the first pixel, but we may need to skip some in case we're
+ // in the part of the scanline before the first valid pixel
+ // or after the last one.
+
+ while (1)
+ {
+ if (fSourcePipeIndex == fSourcePipeMax)
+ {
+ this->PrvSrcPipeFill (stalled);
+
+ if (stalled)
+ return 0; // Return a dummy value
+
+ fSourcePipeIndex = 0;
+ }
+
+ result = fSourcePipe [fSourcePipeIndex++];
+
+ if (fSourcePipeSkip == 0)
+ {
+ break;
+ }
+
+ PRINTF_BLIT (" PrvSrcPipeNextPixel: skipping... %u", fSourcePipeSkip);
+
+ --fSourcePipeSkip;
+ }
+
+ PRINTF_BLIT (" PrvSrcPipeNextPixel: result: 0x%04X", result);
+
+ return result;
+ }
+
+ // We're getting the source pixel value from the display memory.
+
+ uint16 result = this->PrvGetPixel (fXSrc, fYSrc);
+
+ PRINTF_BLIT (" PrvSrcPipeNextPixel: fXSrc: %u", fXSrc);
+ PRINTF_BLIT (" PrvSrcPipeNextPixel: fYSrc: %u", fYSrc);
+ PRINTF_BLIT (" PrvSrcPipeNextPixel: result: 0x%04X", result);
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvSrcPipeNextX
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::PrvSrcPipeNextX (void)
+{
+ fXSrc += (fState.xDirection == 0) ? 1 : -1;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvSrcPipeNextY
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::PrvSrcPipeNextY (void)
+{
+ fYSrc += (fState.yDirection == 0) ? 1 : -1;
+ fXSrc = fState.xSrc;
+
+ if (fState.xyConversion)
+ {
+ if (fState.xDirection)
+ fXSrc += fState.width - 1;
+ }
+
+ fSourcePipeSkip = fTrailingSourcePixels/* + fLeadingSourcePixels*/;
+
+ PRINTF_BLIT (" PrvSrcPipeNextY: fXSrc: %u", fXSrc);
+ PRINTF_BLIT (" PrvSrcPipeNextY: fYSrc: %u", fYSrc);
+ PRINTF_BLIT (" PrvSrcPipeNextY: fSourcePipeSkip: %u", fSourcePipeSkip);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvSrcPipeFill
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::PrvSrcPipeFill (Bool& stalled)
+{
+ // If there's no data in the FIFO, bail out.
+
+ if (this->PrvSrcFifoFilledSlots () == 0)
+ {
+ PRINTF_BLIT (" PrvSrcPipeFill: stalled...");
+
+ stalled = true;
+ return;
+ }
+
+ uint16* p = fSourcePipe;
+ UNUSED_PARAM(p);
+
+ uint32 source1;
+ uint32 source2;
+
+ this->PrvGetSrcFifoSlot (source1, source2);
+
+ // If the source is monochrome, then expand it.
+
+ if (fState.monoSource)
+ {
+ fSourcePipeMax = 64;
+
+ PRINTF_BLIT (" PrvSrcPipeFill: expanding: 0x%08X 0x%08X",
+ source1, source2);
+
+ this->PrvExpandMono32 (source1, &fSourcePipe[0],
+ fState.fgColorMonoSrc, fState.bgColorMonoSrc);
+
+ this->PrvExpandMono32 (source2, &fSourcePipe[32],
+ fState.fgColorMonoSrc, fState.bgColorMonoSrc);
+
+ PRINTF_BLIT (" PrvSrcPipeFill: 0: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X",
+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
+ PRINTF_BLIT (" PrvSrcPipeFill: 1: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X",
+ p[8+0], p[8+1], p[8+2], p[8+3], p[8+4], p[8+5], p[8+6], p[8+7]);
+ PRINTF_BLIT (" PrvSrcPipeFill: 2: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X",
+ p[16+0], p[16+1], p[16+2], p[16+3], p[16+4], p[16+5], p[16+6], p[16+7]);
+ PRINTF_BLIT (" PrvSrcPipeFill: 3: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X",
+ p[24+0], p[24+1], p[24+2], p[24+3], p[24+4], p[24+5], p[24+6], p[24+7]);
+ PRINTF_BLIT (" PrvSrcPipeFill: 4: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X",
+ p[32+0], p[32+1], p[32+2], p[32+3], p[32+4], p[32+5], p[32+6], p[32+7]);
+ PRINTF_BLIT (" PrvSrcPipeFill: 5: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X",
+ p[40+0], p[40+1], p[40+2], p[40+3], p[40+4], p[40+5], p[40+6], p[40+7]);
+ PRINTF_BLIT (" PrvSrcPipeFill: 6: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X",
+ p[48+0], p[48+1], p[48+2], p[48+3], p[48+4], p[48+5], p[48+6], p[48+7]);
+ PRINTF_BLIT (" PrvSrcPipeFill: 7: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X",
+ p[54+0], p[54+1], p[54+2], p[54+3], p[54+4], p[54+5], p[54+6], p[54+7]);
+ }
+
+ // If the source is in color, then break apart the 64-bit
+ // value we read into individual pixels. We'll get either
+ // 4 or 8 pixels, depending on the source depth.
+
+ else if (fState.colorDepth == kColorDepth8)
+ {
+ fSourcePipeMax = 8;
+
+ fSourcePipe[0] = (source1 >> 0) & 0x000000FF;
+ fSourcePipe[1] = (source1 >> 8) & 0x000000FF;
+ fSourcePipe[2] = (source1 >> 16) & 0x000000FF;
+ fSourcePipe[3] = (source1 >> 24) & 0x000000FF;
+
+ fSourcePipe[4] = (source2 >> 0) & 0x000000FF;
+ fSourcePipe[5] = (source2 >> 8) & 0x000000FF;
+ fSourcePipe[6] = (source2 >> 16) & 0x000000FF;
+ fSourcePipe[7] = (source2 >> 24) & 0x000000FF;
+
+ PRINTF_BLIT (" PrvSrcPipeFill: 0: 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X",
+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
+ }
+ else if (fState.colorDepth == kColorDepth16)
+ {
+ fSourcePipeMax = 4;
+
+ fSourcePipe[0] = (source1 >> 0) & 0x0000FFFF;
+ fSourcePipe[1] = (source1 >> 16) & 0x0000FFFF;
+
+ fSourcePipe[2] = (source2 >> 0) & 0x0000FFFF;
+ fSourcePipe[3] = (source2 >> 16) & 0x0000FFFF;
+
+ PRINTF_BLIT (" PrvSrcPipeFill: 0: 0x%04X 0x%04X 0x%04X 0x%04X",
+ p[0], p[1], p[2], p[3]);
+ }
+ else
+ {
+ EmAssert (false);
+ }
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvDestPipeInit
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::PrvDestPipeInit (void)
+{
+ fXDest = fState.xDest;
+ fYDest = fState.yDest;
+
+ if (fState.xyConversion)
+ {
+ if (fState.xDirection)
+ fXDest += fState.width - 1;
+
+ if (fState.yDirection)
+ fYDest += fState.height - 1;
+ }
+
+ PRINTF_BLIT (" PrvDestPipeInit: fXDest: %u", fXDest);
+ PRINTF_BLIT (" PrvDestPipeInit: fYDest: %u", fYDest);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvDestPipeNextPixel
+// ---------------------------------------------------------------------------
+
+uint16 EmRegsMediaQ11xx::PrvDestPipeNextPixel (void)
+{
+ uint16 result = this->PrvGetPixel (fXDest, fYDest);
+
+ PRINTF_BLIT (" PrvDestPipeNextPixel: fXDest: %u", fXDest);
+ PRINTF_BLIT (" PrvDestPipeNextPixel: fYDest: %u", fYDest);
+ PRINTF_BLIT (" PrvDestPipeNextPixel: result: 0x%04X", result);
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvDestPipeNextX
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::PrvDestPipeNextX (void)
+{
+ fXDest += (fState.xDirection == 0) ? 1 : -1;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvDestPipeNextY
+// ---------------------------------------------------------------------------
+
+void EmRegsMediaQ11xx::PrvDestPipeNextY (void)
+{
+ fYDest += (fState.yDirection == 0) ? 1 : -1;
+ fXDest = fState.xDest;
+
+ if (fState.xyConversion)
+ {
+ if (fState.xDirection)
+ fXDest += fState.width - 1;
+ }
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvNextXY
+// ---------------------------------------------------------------------------
+// Increment our X and Y counters. If we we're done, return false. If we've
+// moved to the next line, inform the various pipes that we've done that. If
+// we've merely moved to the next pixel on the same line, inform the pipes
+// that we've done that.
+
+Bool EmRegsMediaQ11xx::PrvNextXY (void)
+{
+ fCurXOffset += 1;
+
+ if (fCurXOffset == fState.width)
+ {
+ fCurXOffset = 0;
+ fCurYOffset += 1;
+
+ if (fCurYOffset == fState.height)
+ {
+ return false;
+ }
+
+ this->PrvPatternPipeNextY ();
+ this->PrvSrcPipeNextY ();
+ this->PrvDestPipeNextY ();
+ }
+ else
+ {
+ this->PrvPatternPipeNextX ();
+ this->PrvSrcPipeNextX ();
+ this->PrvDestPipeNextX ();
+ }
+
+ return true;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvTransparent
+// ---------------------------------------------------------------------------
+
+Bool EmRegsMediaQ11xx::PrvTransparent (uint16 source, uint16 dest, uint16 pattern)
+{
+ if (fState.monoTransEnable)
+ {
+ if (fState.monoSource)
+ {
+ if (fState.monoTransPolarity == 0)
+ {
+ // Source background is transparent.
+
+ if (source == fState.bgColorMonoSrc)
+ {
+ PRINTF_BLIT (" PrvTransparent: source == fState.bgColorMonoSrc...");
+ return true;
+ }
+ }
+ else
+ {
+ // Source foreground is transparent.
+
+ if (source == fState.fgColorMonoSrc)
+ {
+ PRINTF_BLIT (" PrvTransparent: source == fState.fgColorMonoSrc...");
+ return true;
+ }
+ }
+ }
+
+ if (fState.monoPattern)
+ {
+ if (fState.monoTransPolarity == 0)
+ {
+ // Source background is transparent.
+
+ if (pattern == fState.bgColorMonoPat)
+ {
+ PRINTF_BLIT (" PrvTransparent: pattern == fState.bgColorMonoPat...");
+ return true;
+ }
+ }
+ else
+ {
+ // Source foreground is transparent.
+
+ if (pattern == fState.fgColorMonoPat)
+ {
+ PRINTF_BLIT (" PrvTransparent: pattern == fState.fgColorMonoPat...");
+ return true;
+ }
+ }
+ }
+ }
+
+ if (fState.colorTransEnable)
+ {
+ // Compare to source data.
+
+ if (fState.colorTransCmpSrc == 0)
+ {
+ if (!fState.monoSource)
+ {
+ // Transparent if source is the same as the test color.
+
+ if (fState.destTransPolarity == 0)
+ {
+ if (source == fState.destTransColor)
+ {
+ PRINTF_BLIT (" PrvTransparent: source == fState.destTransColor...");
+ return true;
+ }
+ }
+
+ // Transparent if source is different from the test color.
+
+ else
+ {
+ if (source != fState.destTransColor)
+ {
+ PRINTF_BLIT (" PrvTransparent: source != fState.destTransColor...");
+ return true;
+ }
+ }
+ }
+ }
+
+ // Compare to destination data.
+
+ else
+ {
+ // Transparent if dest is the same as the test color.
+
+ if (fState.destTransPolarity == 0)
+ {
+ if (dest == fState.destTransColor)
+ {
+ PRINTF_BLIT (" PrvTransparent: dest == fState.destTransColor...");
+ return true;
+ }
+ }
+
+ // Transparent if dest is different from the test color.
+
+ else
+ {
+ if (dest != fState.destTransColor)
+ {
+ PRINTF_BLIT (" PrvTransparent: dest != fState.destTransColor...");
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvClipped
+// ---------------------------------------------------------------------------
+
+Bool EmRegsMediaQ11xx::PrvClipped (void)
+{
+ if (fState.clipEnable)
+ {
+ if (fXDest < fState.clipLeft || fXDest >= fState.clipRight ||
+ fYDest < fState.clipTop || fYDest >= fState.clipBottom)
+ {
+ PRINTF_BLIT (" PrvWriteIt: clipped out...");
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvLeadingPixels
+// ---------------------------------------------------------------------------
+
+uint16 EmRegsMediaQ11xx::PrvLeadingPixels (void)
+{
+ uint16 result;
+
+ if (fState.memToScreen)
+ {
+ // Packed Mode
+
+ if (fState.monoSource)
+ {
+ result = fState.srcLeadingBits + 8 * fState.srcLeadingBytes;
+ }
+ else if (fState.colorDepth == kColorDepth8)
+ {
+ result = fState.srcLeadingBytes;
+ }
+ else if (fState.colorDepth == kColorDepth16)
+ {
+ EmAssert (::IsEven (fState.srcLeadingBytes));
+ result = fState.srcLeadingBytes / 2;
+ }
+ else
+ {
+ EmAssert (false);
+ result = 0;
+ }
+ }
+ else
+ {
+ // Lined Mode
+
+ if (fState.monoSource)
+ {
+ result = fState.srcBitOffset + 8 * fState.srcByteOffset;
+ }
+ else if (fState.colorDepth == kColorDepth8)
+ {
+ result = fState.srcByteOffset;
+ }
+ else if (fState.colorDepth == kColorDepth16)
+ {
+ EmAssert (::IsEven (fState.srcByteOffset));
+ result = fState.srcByteOffset / 2;
+ }
+ else
+ {
+ EmAssert (false);
+ result = 0;
+ }
+ }
+
+ EmAssert (result < 64);
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvTrailingPixels
+// ---------------------------------------------------------------------------
+
+uint16 EmRegsMediaQ11xx::PrvTrailingPixels (void)
+{
+ uint16 result;
+
+ if (fState.memToScreen)
+ {
+ // Packed Mode
+
+ if (fState.monoSource)
+ {
+ result = fState.srcTrailingBits + 8 * fState.srcTrailingBytes;
+ }
+ else if (fState.colorDepth == kColorDepth8)
+ {
+ result = fState.srcTrailingBytes;
+ }
+ else if (fState.colorDepth == kColorDepth16)
+ {
+ EmAssert (::IsEven (fState.srcTrailingBytes));
+ result = fState.srcTrailingBytes / 2;
+ }
+ else
+ {
+ EmAssert (false);
+ result = 0;
+ }
+ }
+ else
+ {
+ // Lined Mode
+
+ uint16 bytesPerLine;
+
+ if (!fState.systemMemory || fState.srcEqualDestStride)
+ {
+ bytesPerLine = fState.destLineStride;
+ }
+ else
+ {
+ bytesPerLine = fState.srcLineStride;
+ }
+
+ uint16 pixelsPerLine;
+
+ if (fState.monoSource)
+ {
+ pixelsPerLine = bytesPerLine * 8;
+ }
+ else if (fState.colorDepth == kColorDepth8)
+ {
+ pixelsPerLine = bytesPerLine;
+ }
+ else if (fState.colorDepth == kColorDepth16)
+ {
+ EmAssert (::IsEven (bytesPerLine));
+ pixelsPerLine = bytesPerLine / 2;
+ }
+ else
+ {
+ EmAssert (false);
+ pixelsPerLine = 0;
+ }
+
+ result = pixelsPerLine - (fState.width + fLeadingSourcePixels);
+ }
+
+ EmAssert (result < 64);
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvUsesPattern
+// ---------------------------------------------------------------------------
+// Return whether or not the specified rasterOperation will require the use
+// of a "pattern" value (that is, a pixel value from the pattern registers).
+//
+// To see if P is used in the output, consider the P, S, D combination
+// table again:
+//
+// P S D O (output)
+// --- --- --- ---
+// 0 0 0 b0
+// 0 0 1 b1
+// 0 1 0 b2
+// 0 1 1 b3
+// 1 0 0 b4
+// 1 0 1 b5
+// 1 1 0 b6
+// 1 1 1 b7
+//
+// If b0 == b4, b1 == b5, b2 == b6, and b3 == b7, then P has not figured into
+// the result at all. That is, for any S & D combination, we got the same
+// output regardless of what P was. Therefore, we can compare those bits to
+// see if P is relevent to the outcome or not.
+//
+// We can quickly compare the bits by taking the ROP:
+//
+// b7 b6 b5 b4 b3 b2 b1 b0
+//
+// Making a copy of it:
+//
+// b7 b6 b5 b4 b3 b2 b1 b0
+// b7 b6 b5 b4 b3 b2 b1 b0
+//
+// Shifting the copy:
+//
+// b7 b6 b5 b4 b3 b2 b1 b0
+// 0 0 0 0 b7 b6 b5 b4
+//
+// XORing the two:
+//
+// (b7^0) (b6^0) (b5^0) (b4^0) (b3^b7) (b2^b6) (b1^b5) (b0^b4)
+//
+// And then masking out bits 4, 5, 6, and 7, as they don't include
+// results that we want:
+//
+// 0 0 0 0 (b3^b7) (b2^b6) (b1^b5) (b0^b4)
+//
+// Here, we have a bitfield containing the results of comparing the bits
+// that we're interested in. We can test the whole result to see if it's
+// zero or non-zero.
+
+Bool EmRegsMediaQ11xx::PrvUsesPattern (void)
+{
+ uint8 rop = fState.rasterOperation;
+ uint8 shifted = rop >> 4;
+ uint8 xored = rop ^ shifted;
+ uint8 masked = xored & 0x0F;
+
+ return masked != 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvUsesSource
+// ---------------------------------------------------------------------------
+// Return whether or not the specified rasterOperation will require the use
+// of a "source" value (that is, a pixel value from a source buffer).
+//
+// To see if S is used in the output, consider the P, S, D combination
+// table again:
+//
+// P S D O (output)
+// --- --- --- ---
+// 0 0 0 b0
+// 0 0 1 b1
+// 0 1 0 b2
+// 0 1 1 b3
+// 1 0 0 b4
+// 1 0 1 b5
+// 1 1 0 b6
+// 1 1 1 b7
+//
+// If b0 == b2, b1 == b3, b4 == b6, and b5 == b7, then S has not figured into
+// the result at all. That is, for any P & D combination, we got the same
+// output regardless of what S was. Therefore, we can compare those bits to
+// see if S is relevent to the outcome or not.
+//
+// We can quickly compare the bits by taking the ROP:
+//
+// b7 b6 b5 b4 b3 b2 b1 b0
+//
+// Making a copy of it:
+//
+// b7 b6 b5 b4 b3 b2 b1 b0
+// b7 b6 b5 b4 b3 b2 b1 b0
+//
+// Shifting the copy:
+//
+// b7 b6 b5 b4 b3 b2 b1 b0
+// 0 0 b7 b6 b5 b4 b3 b2
+//
+// XORing the two:
+//
+// (b7^0) (b6^0) (b5^b7) (b4^b6) (b3^b5) (b2^b4) (b1^b3) (b0^b2)
+//
+// And then masking out bits 2, 3, 6, and 7, as they don't include
+// results that we want:
+//
+// 0 0 (b5^b7) (b4^b6) 0 0 (b1^b3) (b0^b2)
+//
+// Here, we have a bitfield containing the results of comparing the bits
+// that we're interested in. We can test the whole result to see if it's
+// zero or non-zero.
+
+Bool EmRegsMediaQ11xx::PrvUsesSource (void)
+{
+ uint8 rop = fState.rasterOperation;
+ uint8 shifted = rop >> 2;
+ uint8 xored = rop ^ shifted;
+ uint8 masked = xored & 0x33;
+
+ return masked != 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvExpandMono8
+// ---------------------------------------------------------------------------
+// Take a bit pattern, and expand it into an array of color values, where
+// elements of the array are set to the foreground color if the bit in the
+// pattern is one, and the background color if the bit is zero.
+
+void EmRegsMediaQ11xx::PrvExpandMono8 (uint8 bits, uint16* results,
+ uint16 fgColor, uint16 bgColor)
+{
+ if (fState.monoSrcBitSwap)
+ {
+ for (int ii = 0; ii < 8; ++ii)
+ {
+ if ((bits & (1 << ii)) != 0)
+ {
+ results[ii] = fgColor;
+ }
+ else
+ {
+ results[ii] = bgColor;
+ }
+ }
+ }
+ else
+ {
+ for (int ii = 0; ii < 8; ++ii)
+ {
+ if ((bits & (0x080 >> ii)) != 0)
+ {
+ results[ii] = fgColor;
+ }
+ else
+ {
+ results[ii] = bgColor;
+ }
+ }
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsMediaQ11xx::PrvExpandMono32
+// ---------------------------------------------------------------------------
+// Wrapper to perform the expansion of 4 8-bit bitfields in a DWORD.
+
+void EmRegsMediaQ11xx::PrvExpandMono32 (uint32 bits, uint16* results,
+ uint16 fgColor, uint16 bgColor)
+{
+ this->PrvExpandMono8 (bits >> 0, &results[ 0], fgColor, bgColor);
+ this->PrvExpandMono8 (bits >> 8, &results[ 8], fgColor, bgColor);
+ this->PrvExpandMono8 (bits >> 16, &results[16], fgColor, bgColor);
+ this->PrvExpandMono8 (bits >> 24, &results[24], fgColor, bgColor);
+}
diff --git a/SrcShared/Hardware/EmRegsMediaQ11xx.h b/SrcShared/Hardware/EmRegsMediaQ11xx.h
new file mode 100644
index 0000000..2a6a69a
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsMediaQ11xx.h
@@ -0,0 +1,351 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 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.
+\* ===================================================================== */
+
+#ifndef EmRegsMediaQ11xx_h
+#define EmRegsMediaQ11xx_h
+
+#include "EmHAL.h" // EmHALHandler
+#include "EmRegs.h" // EmRegs
+#include "EmPalmStructs.h" // EmProxyHwrMediaQ11xType
+
+#include <vector> // vector
+
+
+#define T_BASE 0x1F000000L //68KVZ for Palm platform
+#define MMIO_OFFSET 0x40000 // starts at 256K address
+#define MMIO_BASE (T_BASE + MMIO_OFFSET)
+
+// This struct is a mirror of the MediaQ graphics enginer registers. As
+// the registers are updated, this struct is updated so that we have
+// easy access to the values in the registers without having to unpack
+// them all the time.
+
+struct GEState
+{
+ // * means that I've completely accounted for that field
+ // and don't have to think about it any more.
+ //
+ // - means that I'm not going to support that field and
+ // so don't ever have to think about it.
+ //
+ // ? means that I don't know what this field is for.
+
+ // ==================== GE00R ====================
+
+ uint8 rasterOperation; // [7:0]*
+ uint8 commandType; // [10:8]*
+ uint8 xDirection; // [11]*
+ uint8 yDirection; // [12]*
+ uint8 systemMemory; // [13]*
+ uint8 monoSource; // [14]*
+ uint8 monoPattern; // [15]*
+ uint8 colorTransEnable; // [16]*
+ uint8 destTransPolarity; // [17]*
+ uint8 monoTransEnable; // [18]*
+ uint8 monoTransPolarity; // [19]*
+ uint8 memToScreen; // [20]*
+ uint8 solidSourceColor; // [23]*
+ uint8 srcEqualDestStride; // [24]*
+ uint8 rop2Select; // [25]?
+ uint8 clipEnable; // [26]*
+ uint8 autoExecute; // [27]*
+ uint8 solidPattern; // [30]*
+ uint8 colorTransCmpSrc; // [31]*
+
+ // ==================== GE01R ====================
+
+ // BitBLT
+
+ uint16 width; // [11:0]*
+ uint16 height; // [27:16]*
+ uint8 xyConversion; // [31]*
+
+ // Line
+
+ int32 gamma; // [16:0]?
+ uint16 majorLength; // [28:17]*
+ uint8 yIsMajor; // [29]*
+ uint8 drawLastPixel; // [30]*
+ uint8 useXY; // [31]*
+
+ // ==================== GE02R ====================
+
+ // BitBLT
+
+ uint16 xDest; // [11:0]*
+ uint8 monoPatternXOffset; // [15:13]*
+ uint16 yDest; // [27:16]*
+ uint8 monoPatternYOffset; // [31:29]*
+
+ // Line
+
+ uint16 xStart; // [11:0]*
+ uint16 deltaMajor; // [28:12]*
+ uint16 quadrant; // [31:29]*
+
+ // ==================== GE03R ====================
+
+ // BitBLT
+
+ uint16 xSrc; // [11:0]*
+ uint16 ySrc; // [27:16]*
+
+ // Line
+
+ uint16 yStart; // [11:0]*
+ uint16 deltaMinor; // [28:12]*
+
+ // ==================== GE04R ====================
+
+ uint16 destTransColor; // [15:0]*
+
+ // ==================== GE05R ====================
+
+ uint16 clipLeft; // [10:0]*
+ uint16 clipTop; // [25:16]*
+
+ // ==================== GE06R ====================
+
+ uint16 clipRight; // [10:0]*
+ uint16 clipBottom; // [25:16]*
+
+ // ==================== GE07R ====================
+
+ uint16 fgColorMonoSrc; // [15:0]*
+
+ // ==================== GE08R ====================
+
+ uint16 bgColorMonoSrc; // [15:0]*
+
+ // ==================== GE09R ====================
+
+ // Lined Mode
+
+ uint16 srcLineStride; // [9:0]*
+ uint8 srcBitOffset; // [27:25]*
+ uint8 srcByteOffset; // [30:28]*
+
+ // Packed Mode
+
+ uint8 srcLeadingBits; // [2:0]*
+ uint8 srcLeadingBytes; // [5:3]*
+ uint16 srcNumBytes; // [15:6]*
+ uint8 srcTrailingBits; // [27:25]*
+ uint8 srcTrailingBytes; // [31:28]*
+
+ // ==================== GE0AR ====================
+
+ uint16 destLineStride; // [9:0]*
+ uint8 monoSrcBitSwap; // [28]*
+ uint8 rotate90; // [29]*
+ uint8 colorDepth; // [31:30]*
+
+ // ==================== GE0BR ====================
+
+ uint32 baseAddr; // [19:0]*
+ uint8 testModeEnable; // [29]-
+ uint8 testModeControl; // [31:30]-
+
+ // ==================== GE0CR ====================
+
+ uint16 cmdLineStart; // [9:0]-
+ uint16 cmdLineEnd; // [21:12]-
+ uint8 cmdLineControl; // [24]-
+ uint8 gc1SwitchControl; // [27:26]-
+
+ // ==================== GE0FR ====================
+
+ // Test register
+
+ // ==================== GE10R ====================
+
+ uint32 monoPattern1; // [31:0]*
+
+ // ==================== GE11R ====================
+
+ uint32 monoPattern2; // [31:0]*
+
+ // ==================== GE12R ====================
+
+ uint16 fgColorMonoPat; // [15:0]*
+
+ // ==================== GE13R ====================
+
+ uint16 bgColorMonoPat; // [15:0]*
+};
+
+
+class EmRegsMediaQ11xx : public EmRegs, public EmHALHandler
+{
+ public:
+ EmRegsMediaQ11xx (emuptr baseRegsAddr,
+ emuptr baseVideoAddr);
+ virtual ~EmRegsMediaQ11xx (void);
+
+ // EmRegs overrides
+ virtual void Initialize (void);
+ virtual void Reset (Bool hardwareReset);
+ virtual void Save (SessionFile&);
+ virtual void Load (SessionFile&);
+ virtual void Dispose (void);
+
+ virtual void SetSubBankHandlers (void);
+ virtual uint8* GetRealAddress (emuptr address);
+ virtual emuptr GetAddressStart (void);
+ virtual uint32 GetAddressRange (void);
+
+ // EmHAL overrides
+ virtual Bool GetLCDScreenOn (void);
+ virtual Bool GetLCDBacklightOn (void);
+ virtual Bool GetLCDHasFrame (void);
+ virtual void GetLCDBeginEnd (emuptr& begin, emuptr& end);
+ virtual void GetLCDScanlines (EmScreenUpdateInfo& info);
+
+ protected:
+ uint32 MQRead (emuptr address, int size);
+ void MQWrite (emuptr address, int size, uint32 value);
+
+ private:
+ uint32 CC01Read (emuptr address, int size);
+
+ void DC00Write (emuptr address, int size, uint32 value);
+ void GE00Write (emuptr address, int size, uint32 value);
+ void GE02Write (emuptr address, int size, uint32 value);
+ void SourceFifoWrite (emuptr address, int size, uint32 value);
+ void invalidateWrite (emuptr address, int size, uint32 value);
+
+ private:
+ void AddressError (emuptr address, long size, Bool forRead);
+ void PrvGetPalette (RGBList& thePalette);
+ void PrvUpdateByteLanes (void);
+
+ uint32 PrvGetBPP (void);
+ uint32 PrvGetWidth (void);
+ uint32 PrvGetHeight (void);
+ uint32 PrvGetRowBytes (void);
+ uint32 PrvGetVideoOffset (void);
+ uint32 PrvGetVideoBase (void);
+ uint32 PrvGetFrameBuffer (void);
+ Bool PrvGetXDoubling (void);
+ Bool PrvGetYDoubling (void);
+
+ void PrvGetGEState (int regNum);
+ void PrvLogGEState ();
+
+ void PrvDoCommand (void);
+ void PrvDoBitBLT (void);
+ void PrvDoLine (void);
+ void PrvIllegalCommand (void);
+
+ int PrvSrcFifoFilledSlots (void);
+ void PrvGetSrcFifoSlot (uint32&, uint32&);
+
+ // Drawing related functions
+ uint16 PrvAdjustPixel (uint16 pen,
+ uint16 dest,
+ uint8 rOpCode);
+ uint16 PrvAdjustPixel (uint16 pattern,
+ uint16 src,
+ uint16 dest,
+ uint8 rOpCode);
+
+ void PrvSetPixel (uint16 pixel,
+ uint16 x, uint16 y);
+ uint16 PrvGetPixel (uint16 x, uint16 y);
+ emuptr PrvGetPixelLocation (uint16 x, uint16 y);
+
+ void PrvIncBlitterInit (void);
+ void PrvIncBlitterRun (void);
+
+ void PrvPatternPipeInit (void);
+ uint16 PrvPatternPipeNextPixel (void);
+ void PrvPatternPipeNextX (void);
+ void PrvPatternPipeNextY (void);
+
+ void PrvSrcPipeInit (void);
+ uint16 PrvSrcPipeNextPixel (Bool& stalled);
+ void PrvSrcPipeNextX (void);
+ void PrvSrcPipeNextY (void);
+ void PrvSrcPipeFill (Bool& stalled);
+
+ void PrvDestPipeInit (void);
+ uint16 PrvDestPipeNextPixel (void);
+ void PrvDestPipeNextX (void);
+ void PrvDestPipeNextY (void);
+
+ Bool PrvNextXY (void);
+ Bool PrvTransparent (uint16 source, uint16 dest, uint16 pattern);
+ Bool PrvClipped (void);
+ uint16 PrvLeadingPixels (void);
+ uint16 PrvTrailingPixels (void);
+
+ Bool PrvUsesPattern (void);
+ Bool PrvUsesSource (void);
+ void PrvExpandMono8 (uint8 bits, uint16* results,
+ uint16 fgColor, uint16 bgColor);
+ void PrvExpandMono32 (uint32 bits, uint16* results,
+ uint16 fgColor, uint16 bgColor);
+
+ private:
+ emuptr fBaseRegsAddr;
+ emuptr fBaseVideoAddr;
+ EmProxyHwrMediaQ11xxType fRegs;
+ GEState fState;
+
+ int fBytelanes[4];
+ emuptr fLastAddress;
+ int fLastSize;
+
+ vector<uint32> fSourceFifo;
+
+ // Values used while incrementally blitting.
+
+ Bool fBlitInProgress;
+
+ uint16 fCurXOffset;
+ uint16 fCurYOffset;
+
+ // Some values cached for speed. These are calculated once
+ // for each blit operation and saved, as they don't vary once
+ // the blit has started. However, there's no evidence that
+ // any such caching is needed -- no timing experiments have
+ // bee performed.
+
+ Bool fUsesPattern;
+ Bool fUsesSource;
+
+ uint16 fLeadingSourcePixels;
+ uint16 fTrailingSourcePixels;
+
+ // Pattern pipe data
+
+ uint16 fPatternPipe[64];
+ uint16 fXPattern;
+ uint16 fYPattern;
+
+ // Source pipe data
+
+ uint16 fSourcePipe[64];
+ uint16 fSourcePipeIndex;
+ uint16 fSourcePipeMax;
+ uint16 fSourcePipeSkip;
+ uint16 fXSrc;
+ uint16 fYSrc;
+
+ // Dest pipe data
+
+ uint16 fXDest;
+ uint16 fYDest;
+};
+
+#endif // EmRegsMediaQ11xx_h
diff --git a/SrcShared/Hardware/EmRegsPLDPalmVIIEZ.cpp b/SrcShared/Hardware/EmRegsPLDPalmVIIEZ.cpp
new file mode 100644
index 0000000..6f0bc8b
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsPLDPalmVIIEZ.cpp
@@ -0,0 +1,210 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmRegsPLDPalmVIIEZ.h"
+
+#include "EmHAL.h" // EmHAL::GetSerialPortOn
+
+#define NON_PORTABLE
+#include "EZSumo/IncsPrv/HardwareEZ.h" // hwrJerryPldBase, hwrJerryPld232Enable
+#undef NON_PORTABLE
+
+// Given a register (specified by its field name), return its address
+// in emulated space.
+
+#define addressof(reg) \
+ (this->GetAddressStart () + fRegs.offsetof_##reg ())
+
+
+// Macro to help the installation of handlers for a register.
+
+#define INSTALL_HANDLER(read, write, reg) \
+ this->SetHandler ( (ReadFunction) &EmRegsPLDPalmVIIEZ::read, \
+ (WriteFunction) &EmRegsPLDPalmVIIEZ::write, \
+ addressof (reg), \
+ fRegs.reg.GetSize ())
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsPLDPalmVIIEZ::EmRegsPLDPalmVIIEZ
+// ---------------------------------------------------------------------------
+
+EmRegsPLDPalmVIIEZ::EmRegsPLDPalmVIIEZ (void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsPLDPalmVIIEZ::~EmRegsPLDPalmVIIEZ
+// ---------------------------------------------------------------------------
+
+EmRegsPLDPalmVIIEZ::~EmRegsPLDPalmVIIEZ (void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsPLDPalmVIIEZ::Initialize
+// ---------------------------------------------------------------------------
+
+void EmRegsPLDPalmVIIEZ::Initialize (void)
+{
+ EmRegs::Initialize ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsPLDPalmVIIEZ::Reset
+// ---------------------------------------------------------------------------
+
+void EmRegsPLDPalmVIIEZ::Reset (Bool hardwareReset)
+{
+ EmRegs::Reset (hardwareReset);
+
+ if (hardwareReset)
+ {
+ memset (fRegs.GetPtr (), 0, fRegs.GetSize ());
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsPLDPalmVIIEZ::Save
+// ---------------------------------------------------------------------------
+
+void EmRegsPLDPalmVIIEZ::Save (SessionFile& f)
+{
+ EmRegs::Save (f);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsPLDPalmVIIEZ::Load
+// ---------------------------------------------------------------------------
+
+void EmRegsPLDPalmVIIEZ::Load (SessionFile& f)
+{
+ EmRegs::Load (f);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsPLDPalmVIIEZ::Dispose
+// ---------------------------------------------------------------------------
+
+void EmRegsPLDPalmVIIEZ::Dispose (void)
+{
+ EmRegs::Dispose ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsPLDPalmVIIEZ::GetSerialPortOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsPLDPalmVIIEZ::GetSerialPortOn (int /*uartNum*/)
+{
+ return (fRegs.rs232Shdn & hwrJerryPld232Enable) != 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsPLDPalmVIIEZ::SetSubBankHandlers
+// ---------------------------------------------------------------------------
+
+void EmRegsPLDPalmVIIEZ::SetSubBankHandlers (void)
+{
+ // Install base handlers.
+
+ EmRegs::SetSubBankHandlers ();
+
+ // Now add standard/specialized handers for the defined registers.
+
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, dspOn);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, chargeOn);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, refOn);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, pipaBiasEnable);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, dspReset);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, ezToDsl);
+ INSTALL_HANDLER (StdReadBE, rs232ShdnWrite, rs232Shdn);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, spareOut);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, dTo3Sln);
+ INSTALL_HANDLER (iXtrnl2Read, StdWriteBE, iXtrnl2);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsPLDPalmVIIEZ::GetRealAddress
+// ---------------------------------------------------------------------------
+
+uint8* EmRegsPLDPalmVIIEZ::GetRealAddress (emuptr address)
+{
+ return (uint8*) fRegs.GetPtr () + address - this->GetAddressStart ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsPLDPalmVIIEZ::GetAddressStart
+// ---------------------------------------------------------------------------
+
+emuptr EmRegsPLDPalmVIIEZ::GetAddressStart (void)
+{
+ return hwrJerryPldBase;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsPLDPalmVIIEZ::GetAddressRange
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsPLDPalmVIIEZ::GetAddressRange (void)
+{
+ return fRegs.GetSize ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsPLDPalmVIIEZ::rs232ShdnWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsPLDPalmVIIEZ::rs232ShdnWrite (emuptr address, int size, uint32 value)
+{
+ // Take a snapshot of the line driver states.
+
+ Bool driverStates[kUARTEnd];
+ EmHAL::GetLineDriverStates (driverStates);
+
+ StdWriteBE (address, size, value);
+
+ // Respond to any changes in the line driver states.
+
+ EmHAL::CompareLineDriverStates (driverStates);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsPLDPalmVIIEZ::iXtrnl2Read
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsPLDPalmVIIEZ::iXtrnl2Read (emuptr address, int size)
+{
+ uint32 result = StdReadBE (address, size);
+
+ // Ensure that bit 0x0080 is set. If it's clear, HotSync
+ // will sync via the modem instead of the serial port.
+
+ result |= 0x0080;
+
+ return result;
+}
diff --git a/SrcShared/Hardware/EmRegsPLDPalmVIIEZ.h b/SrcShared/Hardware/EmRegsPLDPalmVIIEZ.h
new file mode 100644
index 0000000..92085f8
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsPLDPalmVIIEZ.h
@@ -0,0 +1,51 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegsPLDPalmVIIEZ_h
+#define EmRegsPLDPalmVIIEZ_h
+
+#include "EmHAL.h" // EmHALHandler
+#include "EmPalmStructs.h" // EmProxyHwrJerryPLDType
+#include "EmRegs.h" // EmRegs
+
+class SessionFile;
+
+
+class EmRegsPLDPalmVIIEZ : public EmRegs, public EmHALHandler
+{
+ public:
+ EmRegsPLDPalmVIIEZ (void);
+ virtual ~EmRegsPLDPalmVIIEZ (void);
+
+ virtual void Initialize (void);
+ virtual void Reset (Bool hardwareReset);
+ virtual void Save (SessionFile&);
+ virtual void Load (SessionFile&);
+ virtual void Dispose (void);
+
+ virtual Bool GetSerialPortOn (int uartNum);
+
+ virtual void SetSubBankHandlers (void);
+ virtual uint8* GetRealAddress (emuptr address);
+ virtual emuptr GetAddressStart (void);
+ virtual uint32 GetAddressRange (void);
+
+ protected:
+ void rs232ShdnWrite (emuptr address, int size, uint32 value);
+ uint32 iXtrnl2Read (emuptr address, int size);
+
+ private:
+ EmProxyHwrJerryPLDType fRegs;
+};
+
+#endif /* EmRegsPLDPalmVIIEZ_h */
diff --git a/SrcShared/Hardware/EmRegsPrv.h b/SrcShared/Hardware/EmRegsPrv.h
new file mode 100644
index 0000000..d436c47
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsPrv.h
@@ -0,0 +1,37 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegsPrv_h
+#define EmRegsPrv_h
+
+#include "EmMemory.h" // EmMemDoGet8, EmMemDoPut8, etc.
+
+// Inline functions for reading/writing registers.
+
+inline int8 _get_reg (int8* a) { return EmMemDoGet8 (a); }
+inline int16 _get_reg (int16* a) { return EmMemDoGet16 (a); }
+inline int32 _get_reg (int32* a) { return EmMemDoGet32 (a); }
+
+inline uint8 _get_reg (uint8* a) { return EmMemDoGet8 (a); }
+inline uint16 _get_reg (uint16* a) { return EmMemDoGet16 (a); }
+inline uint32 _get_reg (uint32* a) { return EmMemDoGet32 (a); }
+
+inline void _put_reg (int8* a, int8 v) { EmMemDoPut8 (a, v); }
+inline void _put_reg (int16* a, int16 v) { EmMemDoPut16 (a, v); }
+inline void _put_reg (int32* a, int32 v) { EmMemDoPut32 (a, v); }
+
+inline void _put_reg (uint8* a, uint8 v) { EmMemDoPut8 (a, v); }
+inline void _put_reg (uint16* a, uint16 v) { EmMemDoPut16 (a, v); }
+inline void _put_reg (uint32* a, uint32 v) { EmMemDoPut32 (a, v); }
+
+#endif // EmRegsPrv_h
diff --git a/SrcShared/Hardware/EmRegsSED1375.cpp b/SrcShared/Hardware/EmRegsSED1375.cpp
new file mode 100644
index 0000000..ea9831b
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsSED1375.cpp
@@ -0,0 +1,506 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmRegsSED1375.h"
+
+#include "Byteswapping.h" // Canonical
+#include "EmMemory.h" // EmMem_memcpy
+#include "EmPixMap.h" // SetSize, SetRowBytes, etc.
+#include "EmScreen.h" // EmScreen::InvalidateAll
+#include "Miscellaneous.h" // StWordSwapper
+#include "SessionFile.h" // WriteSED1375RegsType
+
+
+// Given a register (specified by its field name), return its address
+// in emulated space.
+
+#define addressof(reg) \
+ (this->GetAddressStart () + fRegs.offsetof_##reg ())
+
+
+// Macro to help the installation of handlers for a register.
+
+#define INSTALL_HANDLER(read, write, reg) \
+ this->SetHandler ( (ReadFunction) &EmRegsSED1375::read, \
+ (WriteFunction) &EmRegsSED1375::write, \
+ addressof (reg), \
+ fRegs.reg.GetSize ())
+
+
+#define kCLUTColorIndexMask 0xf000
+#define kCLUTColorsMask 0x0fff
+
+#define kCLUTRedMask 0x0f00
+#define kCLUTGreenMask 0x00f0
+#define kCLUTBlueMask 0x000f
+
+#define kCLUTIndexRed 0x4000
+#define kCLUTIndexGreen 0x2000
+#define kCLUTIndexBlue 0x1000
+
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1375::EmRegsSED1375
+// ---------------------------------------------------------------------------
+
+EmRegsSED1375::EmRegsSED1375 (emuptr baseRegsAddr, emuptr baseVideoAddr) :
+ fBaseRegsAddr (baseRegsAddr),
+ fBaseVideoAddr (baseVideoAddr),
+ fRegs ()
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1375::~EmRegsSED1375
+// ---------------------------------------------------------------------------
+
+EmRegsSED1375::~EmRegsSED1375 (void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1375::Initialize
+// ---------------------------------------------------------------------------
+
+void EmRegsSED1375::Initialize (void)
+{
+ EmRegs::Initialize ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1375::Reset
+// ---------------------------------------------------------------------------
+
+void EmRegsSED1375::Reset (Bool hardwareReset)
+{
+ EmRegs::Reset (hardwareReset);
+
+ if (hardwareReset)
+ {
+ memset (fRegs.GetPtr (), 0, fRegs.GetSize ());
+
+// EmAssert ((sed1375ProductCodeExpected | sed1375RevisionCodeExpected) == 0x24);
+ fRegs.productRevisionCode = 0x24;
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1375::Save
+// ---------------------------------------------------------------------------
+
+void EmRegsSED1375::Save (SessionFile& f)
+{
+ EmRegs::Save (f);
+
+ f.WriteSED1375RegsType (*(SED1375RegsType*) fRegs.GetPtr ());
+ f.FixBug (SessionFile::kBugByteswappedStructs);
+
+ StWordSwapper swapper1 (fClutData, sizeof (fClutData));
+ f.WriteSED1375Palette (fClutData);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1375::Load
+// ---------------------------------------------------------------------------
+
+void EmRegsSED1375::Load (SessionFile& f)
+{
+ EmRegs::Load (f);
+
+ // Read in the SED registers.
+
+ if (f.ReadSED1375RegsType (*(SED1375RegsType*) fRegs.GetPtr ()))
+ {
+ // The Windows version of Poser 2.1d29 and earlier did not write
+ // out structs in the correct format. The fields of the struct
+ // were written out in Little-Endian format, not Big-Endian. To
+ // address this problem, the bug has been fixed, and a new field
+ // is added to the file format indicating that the bug has been
+ // fixed. With the new field (the "bug bit"), Poser can identify
+ // old files from new files and read them in accordingly.
+ //
+ // With the bug fixed, the .psf files should now be interchangeable
+ // across platforms (modulo other bugs...).
+
+ if (!f.IncludesBugFix (SessionFile::kBugByteswappedStructs))
+ {
+ Canonical (*(SED1375RegsType*) fRegs.GetPtr ());
+ }
+ }
+ else
+ {
+ f.SetCanReload (false);
+ }
+
+ // Read in the LCD palette, and then byteswap it.
+
+ if (f.ReadSED1375Palette (fClutData))
+ {
+ ::ByteswapWords (fClutData, sizeof (fClutData));
+ }
+ else
+ {
+ f.SetCanReload (false);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1375::Dispose
+// ---------------------------------------------------------------------------
+
+void EmRegsSED1375::Dispose (void)
+{
+ EmRegs::Dispose ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1375::SetSubBankHandlers
+// ---------------------------------------------------------------------------
+
+void EmRegsSED1375::SetSubBankHandlers (void)
+{
+ // Install base handlers.
+
+ EmRegs::SetSubBankHandlers ();
+
+ // Now add standard/specialized handers for the defined registers.
+
+ INSTALL_HANDLER (StdReadBE, NullWrite, productRevisionCode);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, mode0);
+ INSTALL_HANDLER (StdReadBE, invalidateWrite, mode1);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, mode2);
+ INSTALL_HANDLER (StdReadBE, invalidateWrite, horizontalPanelSize);
+ INSTALL_HANDLER (StdReadBE, invalidateWrite, verticalPanelSizeLSB);
+ INSTALL_HANDLER (StdReadBE, invalidateWrite, verticalPanelSizeMSB);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, FPLineStartPosition);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, horizontalNonDisplayPeriod);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, FPFRAMEStartPosition);
+ INSTALL_HANDLER (vertNonDisplayRead, StdWriteBE, verticalNonDisplayPeriod);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, MODRate);
+ INSTALL_HANDLER (StdReadBE, invalidateWrite, screen1StartAddressLSB);
+ INSTALL_HANDLER (StdReadBE, invalidateWrite, screen1StartAddressMSB);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, screen2StartAddressLSB);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, screen2StartAddressMSB);
+ INSTALL_HANDLER (StdReadBE, invalidateWrite, screen1StartAddressMSBit);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, memoryAddressOffset);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, screen1VerticalSizeLSB);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, screen1VerticalSizeMSB);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, unused1);
+ INSTALL_HANDLER (StdReadBE, lookUpTableAddressWrite, lookUpTableAddress);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, unused2);
+ INSTALL_HANDLER (lookUpTableDataRead, lookUpTableDataWrite, lookUpTableData);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, GPIOConfigurationControl);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, GPIOStatusControl);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, scratchPad);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, portraitMode);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, lineByteCountRegister);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, unused3);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, unused4);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, unused5);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1375::GetRealAddress
+// ---------------------------------------------------------------------------
+
+uint8* EmRegsSED1375::GetRealAddress (emuptr address)
+{
+ return (uint8*) fRegs.GetPtr () + address - this->GetAddressStart ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1375::GetAddressStart
+// ---------------------------------------------------------------------------
+
+emuptr EmRegsSED1375::GetAddressStart (void)
+{
+ return fBaseRegsAddr;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1375::GetAddressRange
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsSED1375::GetAddressRange (void)
+{
+ return fRegs.GetSize ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1375::GetLCDScreenOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsSED1375::GetLCDScreenOn (void)
+{
+ return ((fRegs.mode1) & sed1375DisplayBlank) == 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1375::GetLCDBacklightOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsSED1375::GetLCDBacklightOn (void)
+{
+ return true; // The Backlight is always on for these units.
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1375::GetLCDHasFrame
+// ---------------------------------------------------------------------------
+
+Bool EmRegsSED1375::GetLCDHasFrame (void)
+{
+ return true;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1375::GetLCDBeginEnd
+// ---------------------------------------------------------------------------
+
+void EmRegsSED1375::GetLCDBeginEnd (emuptr& begin, emuptr& end)
+{
+ // Get the screen metrics.
+
+ int32 bpp = 1 << ((fRegs.mode1 & sed1375BPPMask) >> sed1375BPPShift);
+ int32 height = ((fRegs.verticalPanelSizeMSB << 8) | fRegs.verticalPanelSizeLSB) + 1;
+ int32 rowBytes = (fRegs.horizontalPanelSize + 1) * bpp;
+ uint32 offset = (fRegs.screen1StartAddressMSBit << 17) |
+ (fRegs.screen1StartAddressMSB << 9) |
+ (fRegs.screen1StartAddressLSB << 1);
+ emuptr baseAddr = fBaseVideoAddr + offset;
+
+ begin = baseAddr;
+ end = baseAddr + rowBytes * height;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1375::GetLCDScanlines
+// ---------------------------------------------------------------------------
+
+void EmRegsSED1375::GetLCDScanlines (EmScreenUpdateInfo& info)
+{
+ // Get the screen metrics.
+
+ int32 bpp = 1 << ((fRegs.mode1 & sed1375BPPMask) >> sed1375BPPShift);
+ int32 width = (fRegs.horizontalPanelSize + 1) * 8;
+ int32 height = ((fRegs.verticalPanelSizeMSB << 8) | fRegs.verticalPanelSizeLSB) + 1;
+ int32 rowBytes = (fRegs.horizontalPanelSize + 1) * bpp;
+ uint32 offset = (fRegs.screen1StartAddressMSBit << 17) |
+ (fRegs.screen1StartAddressMSB << 9) |
+ (fRegs.screen1StartAddressLSB << 1);
+ emuptr baseAddr = fBaseVideoAddr + offset;
+
+ info.fLeftMargin = 0;
+
+ EmPixMapFormat format = bpp == 1 ? kPixMapFormat1 :
+ bpp == 2 ? kPixMapFormat2 :
+ bpp == 4 ? kPixMapFormat4 :
+ kPixMapFormat8;
+
+ RGBList colorTable;
+ this->PrvGetPalette (colorTable);
+
+ // Set format, size, and color table of EmPixMap.
+
+ info.fImage.SetSize (EmPoint (width, height));
+ info.fImage.SetFormat (format);
+ info.fImage.SetRowBytes (rowBytes);
+ info.fImage.SetColorTable (colorTable);
+
+ // Determine first and last scanlines to fetch, and fetch them.
+
+ info.fFirstLine = (info.fScreenLow - baseAddr) / rowBytes;
+ info.fLastLine = (info.fScreenHigh - baseAddr - 1) / rowBytes + 1;
+
+ long firstLineOffset = info.fFirstLine * rowBytes;
+ long lastLineOffset = info.fLastLine * rowBytes;
+
+ EmMem_memcpy (
+ (void*) ((uint8*) info.fImage.GetBits () + firstLineOffset),
+ baseAddr + firstLineOffset,
+ lastLineOffset - firstLineOffset);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1375::invalidateWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsSED1375::invalidateWrite (emuptr address, int size, uint32 value)
+{
+ this->StdWriteBE (address, size, value);
+ EmScreen::InvalidateAll ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1375::vertNonDisplayRead
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsSED1375::vertNonDisplayRead (emuptr address, int size)
+{
+ UNUSED_PARAM(address)
+ UNUSED_PARAM(size)
+
+ // Always set the vertical non-display status high since in the real
+ // hardware, the ROM will check this flag in order to write the CLUT
+ // registers.
+
+ return (fRegs.verticalNonDisplayPeriod) | sed1375VerticalNonDisplayStatus;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1375::lookUpTableAddressWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsSED1375::lookUpTableAddressWrite (emuptr address, int size, uint32 value)
+{
+ this->StdWriteBE (address, size, value);
+
+ value &= 0x0FF;
+
+ fClutData[value] &= kCLUTColorsMask; // Update the rgb index
+ fClutData[value] |= kCLUTIndexRed;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1375::lookUpTableDataRead
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsSED1375::lookUpTableDataRead (emuptr address, int size)
+{
+ EmAssert (size == 1);
+
+ if (size != 1)
+ return 0; // Error case.
+
+ uint8 clutIndex = (fRegs.lookUpTableAddress); // Get the LUT Addr.
+ uint16 clutEntry = fClutData[clutIndex]; // Get the entry.
+ uint8 colorData;
+
+ if ((clutEntry & kCLUTIndexRed) != 0)
+ {
+ colorData = (uint8) ((clutEntry & kCLUTRedMask) >> 4); // Get the 4 bits of red.
+
+ fClutData[clutIndex] = // Update the next rgb index
+ (fClutData[clutIndex] & kCLUTColorsMask) | kCLUTIndexGreen;
+ }
+ else if ((clutEntry & kCLUTIndexGreen) != 0)
+ {
+ colorData = (uint8) (clutEntry & kCLUTGreenMask); // Get the 4 bits of green
+
+ fClutData[clutIndex] = // Update the next rgb index
+ (fClutData[clutIndex] & kCLUTColorsMask) | kCLUTIndexBlue;
+ }
+ else
+ {
+ colorData = (uint8) ((clutEntry & kCLUTBlueMask) << 4); // Get the 4 bits of blue.
+
+ address = (emuptr) (addressof (lookUpTableAddress));
+ EmRegsSED1375::lookUpTableAddressWrite (address, 1, (clutIndex + 1) & 0xFF);
+ }
+
+ return colorData;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1375::lookUpTableDataWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsSED1375::lookUpTableDataWrite (emuptr address, int size, uint32 value)
+{
+ EmAssert (size == 1);
+
+ if (size != 1)
+ return; // Error case.
+
+ uint8 clutIndex = (fRegs.lookUpTableAddress); // Get the LUT Addr.
+ uint16 clutEntry = fClutData[clutIndex]; // Get the entry.
+
+ uint8 newColor = (uint8) (value & 0x00F0);
+
+ if (clutEntry & kCLUTIndexRed)
+ {
+ fClutData[clutIndex] &= ~kCLUTRedMask; // Clear out old red bits.
+ fClutData[clutIndex] |= newColor << 4; // Save in new red bits.
+
+ fClutData[clutIndex] = // Update the rgb index
+ (fClutData[clutIndex] & kCLUTColorsMask) | kCLUTIndexGreen;
+ }
+ else if (clutEntry & kCLUTIndexGreen)
+ {
+ fClutData[clutIndex] &= ~kCLUTGreenMask; // Clear out old red bits.
+ fClutData[clutIndex] |= newColor; // Save in new green bits.
+
+ fClutData[clutIndex] = // Update the rgb index
+ (fClutData[clutIndex] & kCLUTColorsMask) | kCLUTIndexBlue;
+ }
+ else
+ {
+ fClutData[clutIndex] &= ~kCLUTBlueMask; // Clear out old red bits.
+ fClutData[clutIndex] |= newColor >> 4; // Save in new blue bits.
+
+ address = (emuptr) (addressof (lookUpTableAddress));
+ EmRegsSED1375::lookUpTableAddressWrite (address, 1, (clutIndex + 1) & 0xFF);
+ }
+
+ EmScreen::InvalidateAll ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1375::PrvGetPalette
+// ---------------------------------------------------------------------------
+
+void EmRegsSED1375::PrvGetPalette (RGBList& thePalette)
+{
+ int32 bpp = 1 << ((fRegs.mode1 & sed1375BPPMask) >> sed1375BPPShift);
+ int32 numColors = 1 << bpp;
+
+ thePalette.resize (numColors);
+
+ for (int ii = 0; ii < numColors; ++ii)
+ {
+ uint16 curEntry = fClutData[ii];
+ uint8 color;
+
+ color = (uint8) ((curEntry & kCLUTRedMask) >> 4);
+ thePalette[ii].fRed = color + (color >> 4);
+
+ color = (uint8) ((curEntry & kCLUTGreenMask) >> 0);
+ thePalette[ii].fGreen = color + (color >> 4);
+
+ color = (uint8) ((curEntry & kCLUTBlueMask) << 4);
+ thePalette[ii].fBlue = color + (color >> 4);
+ }
+}
diff --git a/SrcShared/Hardware/EmRegsSED1375.h b/SrcShared/Hardware/EmRegsSED1375.h
new file mode 100644
index 0000000..7a0e5b5
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsSED1375.h
@@ -0,0 +1,70 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegsSED1375_h
+#define EmRegsSED1375_h
+
+#include "EmHAL.h" // EmHALHandler
+#include "EmPalmStructs.h"
+#include "EmRegs.h"
+#include "EmStructs.h" // RGBList
+
+class SessionFile;
+class EmScreenUpdateInfo;
+
+
+class EmRegsSED1375 : public EmRegs, public EmHALHandler
+{
+ public:
+ EmRegsSED1375 (emuptr baseRegsAddr,
+ emuptr baseVideoAddr);
+ virtual ~EmRegsSED1375 (void);
+
+ // EmRegs overrides
+ virtual void Initialize (void);
+ virtual void Reset (Bool hardwareReset);
+ virtual void Save (SessionFile&);
+ virtual void Load (SessionFile&);
+ virtual void Dispose (void);
+
+ virtual void SetSubBankHandlers (void);
+ virtual uint8* GetRealAddress (emuptr address);
+ virtual emuptr GetAddressStart (void);
+ virtual uint32 GetAddressRange (void);
+
+ // EmHAL overrides
+ virtual Bool GetLCDScreenOn (void);
+ virtual Bool GetLCDBacklightOn (void);
+ virtual Bool GetLCDHasFrame (void);
+ virtual void GetLCDBeginEnd (emuptr& begin, emuptr& end);
+ virtual void GetLCDScanlines (EmScreenUpdateInfo& info);
+
+ private:
+ uint32 vertNonDisplayRead (emuptr address, int size);
+ uint32 lookUpTableDataRead (emuptr address, int size);
+
+ void invalidateWrite (emuptr address, int size, uint32 value);
+ void lookUpTableAddressWrite (emuptr address, int size, uint32 value);
+ void lookUpTableDataWrite (emuptr address, int size, uint32 value);
+
+ private:
+ void PrvGetPalette (RGBList& thePalette);
+
+ private:
+ emuptr fBaseRegsAddr;
+ emuptr fBaseVideoAddr;
+ EmProxySED1375RegsType fRegs;
+ uint16 fClutData[256];
+};
+
+#endif /* EmRegsSED1375_h */
diff --git a/SrcShared/Hardware/EmRegsSED1376.cpp b/SrcShared/Hardware/EmRegsSED1376.cpp
new file mode 100644
index 0000000..223c24a
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsSED1376.cpp
@@ -0,0 +1,860 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmRegsSED1376.h"
+
+#include "EmMemory.h" // EmMem_memcpy
+#include "EmScreen.h" // EmScreen::InvalidateAll
+#include "EmPixMap.h" // EmPixMap::GetLCDScanlines
+#include "SessionFile.h" // WriteSED1376RegsType
+
+
+// Given a register (specified by its field name), return its address
+// in emulated space.
+
+#define addressof(reg) \
+ (this->GetAddressStart () + fRegs.offsetof_##reg ())
+
+
+// Macro to help the installation of handlers for a register.
+
+#define INSTALL_HANDLER(read, write, reg) \
+ this->SetHandler ( (ReadFunction) &EmRegsSED1376::read, \
+ (WriteFunction) &EmRegsSED1376::write, \
+ addressof (reg), \
+ fRegs.reg.GetSize ())
+
+// Panel type register [10h]
+#define sed1376MonoMask 0x40
+
+// Display mode register [70h]
+#define sed1376DisplayBlankMask 0x80
+#define sed1376BPPMask 0x07
+#define sed1376BPPShift 0x00
+
+// REG[0x70] displayMode register
+// (Same as previous set, but with Handspring names for their contributed code)
+#define sed1376DisplayModeBlank 0x80
+#define sed1376DisplayModeDitherOff 0x40
+#define sed1376DisplayModeHwInvert 0x20
+#define sed1376DisplayModeSwInvert 0x10
+#define sed1376DisplayModeDepthMask 0x07
+#define sed1376DisplayModeDepth16 0x04
+#define sed1376DisplayModeDepth8 0x03
+#define sed1376DisplayModeDepth4 0x02
+#define sed1376DisplayModeDepth2 0x01
+#define sed1376DisplayModeDepth1 0x00
+
+// Special effects register [71h]
+#define sed1376WordSwapMask 0x80
+#define sed1376ByteSwapMask 0x40
+#define sed1376SubWindowEnableMask 0x10
+
+#define hwrDisplayGPIOPCI 0x08 // in GPIOStatusControl0
+#define hwrDisplayGPIOEL_ON 0x10 // in GPIOStatusControl0
+#define hwrDisplayGPIOLCD_ON 0x20 // in GPIOStatusControl0
+#define hwrDisplayGPIOMOD 0x40 // in GPIOStatusControl0
+
+// The current SED1376 driver code is completely whacked. It's initialized to use
+// the main display for drawing (see HwrDisplayInit in HwrDisplayBootSED1376.c), but
+// if you change the base address, it (a) always returns the base of the embedded
+// SRAM buffer as the old base address, and (b) stores the new base address in
+// ovlyStartAddress (see PrvDisplayBaseAddr in HwrDisplaySED1376.c). Also, the
+// splash screen appears to be drawn relative to ovlyStartAddress. Finally,
+// there appears to be code to draw a border in the main screen around the
+// overlay screen (see PrvDisplayBorder in HwrDisplayBootSED1376.c), however,
+// the mainStartAddress registers are never changed to point to this border.
+// On top of that, the border is only programmed on the left and right of the
+// of the overlay screen, not on the top and bottom.
+
+#define OVERLAY_IS_MAIN 1
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1376::EmRegsSED1376
+// ---------------------------------------------------------------------------
+
+EmRegsSED1376::EmRegsSED1376 (emuptr baseRegsAddr, emuptr baseVideoAddr) :
+ fBaseRegsAddr (baseRegsAddr),
+ fBaseVideoAddr (baseVideoAddr),
+ fRegs ()
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1376::~EmRegsSED1376
+// ---------------------------------------------------------------------------
+
+EmRegsSED1376::~EmRegsSED1376 (void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1376::Initialize
+// ---------------------------------------------------------------------------
+
+void EmRegsSED1376::Initialize (void)
+{
+ EmRegs::Initialize ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1376::Reset
+// ---------------------------------------------------------------------------
+
+void EmRegsSED1376::Reset (Bool hardwareReset)
+{
+ EmRegs::Reset (hardwareReset);
+
+ if (hardwareReset)
+ {
+ memset (fRegs.GetPtr (), 0, fRegs.GetSize ());
+
+// EmAssert ((sed1376ProductCodeExpected | sed1376RevisionCodeExpected) == 0x28);
+ fRegs.productRevisionCode = 0x28;
+ fRegs.displayBufferSize = 20; // 80K / 4K
+ fRegs.configurationReadback = 0;
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1376::Save
+// ---------------------------------------------------------------------------
+
+void EmRegsSED1376::Save (SessionFile& f)
+{
+ EmRegs::Save (f);
+
+ f.WriteSED1376RegsType (*(SED1376RegsType*) fRegs.GetPtr ());
+ f.WriteSED1376Palette (fClutData);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1376::Load
+// ---------------------------------------------------------------------------
+
+void EmRegsSED1376::Load (SessionFile& f)
+{
+ EmRegs::Load (f);
+
+ // Read in the SED registers.
+
+ if (!f.ReadSED1376RegsType (*(SED1376RegsType*) fRegs.GetPtr ()))
+ {
+ f.SetCanReload (false);
+ }
+
+ // Read in the LCD palette.
+
+ if (!f.ReadSED1376Palette (fClutData))
+ {
+ f.SetCanReload (false);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1376::Dispose
+// ---------------------------------------------------------------------------
+
+void EmRegsSED1376::Dispose (void)
+{
+ EmRegs::Dispose ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1376::SetSubBankHandlers
+// ---------------------------------------------------------------------------
+
+void EmRegsSED1376::SetSubBankHandlers (void)
+{
+ // Install base handlers.
+
+ EmRegs::SetSubBankHandlers ();
+
+ // Now add standard/specialized handers for the defined registers.
+
+ INSTALL_HANDLER (StdReadBE, NullWrite, productRevisionCode);
+ INSTALL_HANDLER (StdReadBE, NullWrite, displayBufferSize);
+ INSTALL_HANDLER (StdReadBE, NullWrite, configurationReadback);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, memoryClockConfiguration);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, pixelClockConfiguration);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, lutWriteBlue);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, lutWriteGreen);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, lutWriteRed);
+ INSTALL_HANDLER (ZeroRead, lutWriteAddressWrite, lutWriteAddress);
+ INSTALL_HANDLER (StdReadBE, NullWrite, lutReadBlue);
+ INSTALL_HANDLER (StdReadBE, NullWrite, lutReadGreen);
+ INSTALL_HANDLER (StdReadBE, NullWrite, lutReadRed);
+ INSTALL_HANDLER (ZeroRead, lutReadAddressWrite, lutReadAddress);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, panelType);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, MODRate);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, horizontalTotal);
+ INSTALL_HANDLER (StdReadBE, invalidateWrite, horizontalPeriod);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, horizontalPeriodStart0);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, horizontalPeriodStart1);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, verticalTotal0);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, verticalTotal1);
+ INSTALL_HANDLER (StdReadBE, invalidateWrite, verticalPeriod0);
+ INSTALL_HANDLER (StdReadBE, invalidateWrite, verticalPeriod1);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, verticalPeriodStart0);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, verticalPeriodStart1);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, FPLINEPulseWidth);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, FPLINEPulseStart0);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, FPLINEPulseStart1);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, FPFRAMEPulseWidth);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, FPFRAMEPulseStart0);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, FPFRAMEPulseStart1);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, DTFD_GCPIndex);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, DTFD_GCPData);
+ INSTALL_HANDLER (StdReadBE, invalidateWrite, displayMode);
+ INSTALL_HANDLER (StdReadBE, invalidateWrite, specialEffects);
+ INSTALL_HANDLER (StdReadBE, invalidateWrite, mainStartAddress0);
+ INSTALL_HANDLER (StdReadBE, invalidateWrite, mainStartAddress1);
+ INSTALL_HANDLER (StdReadBE, invalidateWrite, mainStartAddress2);
+ INSTALL_HANDLER (StdReadBE, invalidateWrite, mainLineAddressOffset0);
+ INSTALL_HANDLER (StdReadBE, invalidateWrite, mainLineAddressOffset1);
+ INSTALL_HANDLER (StdReadBE, invalidateWrite, ovlyStartAddress0);
+ INSTALL_HANDLER (StdReadBE, invalidateWrite, ovlyStartAddress1);
+ INSTALL_HANDLER (StdReadBE, invalidateWrite, ovlyStartAddress2);
+ INSTALL_HANDLER (StdReadBE, invalidateWrite, ovlyLineAddressOffset0);
+ INSTALL_HANDLER (StdReadBE, invalidateWrite, ovlyLineAddressOffset1);
+ INSTALL_HANDLER (StdReadBE, invalidateWrite, ovlyStartXPosition0);
+ INSTALL_HANDLER (StdReadBE, invalidateWrite, ovlyStartXPosition1);
+ INSTALL_HANDLER (StdReadBE, invalidateWrite, ovlyStartYPosition0);
+ INSTALL_HANDLER (StdReadBE, invalidateWrite, ovlyStartYPosition1);
+ INSTALL_HANDLER (StdReadBE, invalidateWrite, ovlyEndXPosition0);
+ INSTALL_HANDLER (StdReadBE, invalidateWrite, ovlyEndXPosition1);
+ INSTALL_HANDLER (StdReadBE, invalidateWrite, ovlyEndYPosition0);
+ INSTALL_HANDLER (StdReadBE, invalidateWrite, ovlyEndYPosition1);
+ INSTALL_HANDLER (powerSaveConfigurationRead, StdWriteBE, powerSaveConfiguration);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, SoftwareReset);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, scratchPad0);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, scratchPad1);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, GPIOConfiguration0);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, GPIOConfiguration1);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, GPIOStatusControl0);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, GPIOStatusControl1);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, PWMClockCVPulseControl);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, PWMClockCVPulseConfig);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, CVPulseBurstLength);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, PWMOutDutyCycle);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1376::GetRealAddress
+// ---------------------------------------------------------------------------
+
+uint8* EmRegsSED1376::GetRealAddress (emuptr address)
+{
+ return (uint8*) fRegs.GetPtr () + address - this->GetAddressStart ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1376::GetAddressStart
+// ---------------------------------------------------------------------------
+
+emuptr EmRegsSED1376::GetAddressStart (void)
+{
+ return fBaseRegsAddr;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1376::GetAddressRange
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsSED1376::GetAddressRange (void)
+{
+ return fRegs.GetSize ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1376::GetLCDScreenOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsSED1376::GetLCDScreenOn (void)
+{
+// return ((fRegs.displayMode) & sed1376DisplayBlankMask) == 0;
+ return ((fRegs.GPIOStatusControl0) & hwrDisplayGPIOLCD_ON) != 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1376::GetLCDBacklightOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsSED1376::GetLCDBacklightOn (void)
+{
+ return ((fRegs.GPIOStatusControl0) & hwrDisplayGPIOEL_ON) != 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1376::GetLCDHasFrame
+// ---------------------------------------------------------------------------
+
+Bool EmRegsSED1376::GetLCDHasFrame (void)
+{
+ return true;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1376::invalidateWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsSED1376::invalidateWrite (emuptr address, int size, uint32 value)
+{
+ this->StdWriteBE (address, size, value);
+ EmScreen::InvalidateAll ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1376::powerSaveConfigurationRead
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsSED1376::powerSaveConfigurationRead (emuptr address, int size)
+{
+ UNUSED_PARAM(address)
+ UNUSED_PARAM(size)
+
+ // Always set the vertical non-display status high since in the real
+ // hardware, the ROM will check this flag in order to write the CLUT
+ // registers.
+
+ return (fRegs.powerSaveConfiguration) | 0x80;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1376::lutWriteAddressWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsSED1376::lutWriteAddressWrite (emuptr address, int size, uint32 value)
+{
+ UNUSED_PARAM(address)
+ UNUSED_PARAM(size)
+
+ value &= 0x0FF;
+
+ uint8 red = fRegs.lutWriteRed;
+ uint8 green = fRegs.lutWriteGreen;
+ uint8 blue = fRegs.lutWriteBlue;
+
+ fClutData[value] = RGBType ((red & 0xFC) | (red >> 6),
+ (green & 0xFC) | (green >> 6),
+ (blue & 0xFC) | (blue >> 6));
+
+ EmScreen::InvalidateAll ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1376::lutReadAddressWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsSED1376::lutReadAddressWrite (emuptr address, int size, uint32 value)
+{
+ UNUSED_PARAM(address)
+ UNUSED_PARAM(size)
+
+ value &= 0x0FF;
+
+ RGBType rgb = fClutData[value];
+
+ fRegs.lutReadRed = rgb.fRed & 0xFC;
+ fRegs.lutReadGreen = rgb.fGreen & 0xFC;
+ fRegs.lutReadBlue = rgb.fBlue & 0xFC;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1376::PrvGetPalette
+// ---------------------------------------------------------------------------
+
+void EmRegsSED1376::PrvGetPalette (RGBList& thePalette)
+{
+ Bool mono = (fRegs.displayMode & sed1376MonoMask) != 0;
+ int32 bpp = 1 << ((fRegs.displayMode & sed1376BPPMask) >> sed1376BPPShift);
+ int32 numColors = 1 << bpp;
+
+ thePalette.resize (numColors);
+
+ for (int ii = 0; ii < numColors; ++ii)
+ {
+ if (mono)
+ {
+ uint8 green = fClutData[ii].fGreen;
+ thePalette[ii].fRed = green;
+ thePalette[ii].fGreen = green;
+ thePalette[ii].fBlue = green;
+ }
+ else
+ {
+ thePalette[ii] = fClutData[ii];
+ }
+ }
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1376VisorPrism::EmRegsSED1376VisorPrism
+// ---------------------------------------------------------------------------
+
+EmRegsSED1376VisorPrism::EmRegsSED1376VisorPrism (emuptr baseRegsAddr,
+ emuptr baseVideoAddr) :
+ EmRegsSED1376 (baseRegsAddr, baseVideoAddr)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1376VisorPrism::~EmRegsSED1376VisorPrism
+// ---------------------------------------------------------------------------
+
+EmRegsSED1376VisorPrism::~EmRegsSED1376VisorPrism (void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1376VisorPrism::SetSubBankHandlers
+// ---------------------------------------------------------------------------
+
+void EmRegsSED1376VisorPrism::SetSubBankHandlers (void)
+{
+ // Install base handlers.
+
+ EmRegsSED1376::SetSubBankHandlers ();
+
+ // Now add standard/specialized handers for the defined registers.
+
+#undef INSTALL_HANDLER
+#define INSTALL_HANDLER(read, write, reg) \
+ this->SetHandler ( (ReadFunction) &EmRegsSED1376VisorPrism::read, \
+ (WriteFunction) &EmRegsSED1376VisorPrism::write, \
+ addressof (reg), \
+ fRegs.reg.GetSize ())
+
+ INSTALL_HANDLER (StdReadBE, reservedWrite, reserved);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1376VisorPrism::GetLCDBeginEnd
+// ---------------------------------------------------------------------------
+
+void EmRegsSED1376VisorPrism::GetLCDBeginEnd (emuptr& begin, emuptr& end)
+{
+ // Get the screen metrics.
+
+ // The hardware is written to in reverse, so the mainStartOffsetX registers
+ // report the END of the frame buffer, not the beginning.
+ emuptr baseAddr = fBaseVideoAddr;
+
+ int32 width = ((fRegs.horizontalPeriod + 1) * 8);
+ int32 height = ((fRegs.verticalPeriod1 << 8) | fRegs.verticalPeriod0) + 1;
+ int32 rowBytes = ((width * this->PrvGetLCDDepth ()) / 8);
+
+ begin = baseAddr;
+ end = baseAddr + rowBytes * height;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1376VisorPrism::GetLCDScanlines
+// ---------------------------------------------------------------------------
+
+void EmRegsSED1376VisorPrism::GetLCDScanlines (EmScreenUpdateInfo& info)
+{
+ // Get the screen metrics.
+
+ Bool byteSwapped = (fRegs.specialEffects & sed1376ByteSwapMask) != 0;
+ Bool mono = (fRegs.displayMode & sed1376MonoMask) != 0;
+ int32 bpp = 1 << ((fRegs.displayMode & sed1376BPPMask) >> sed1376BPPShift);
+
+ // The hardware is written to in reverse, so the mainStartOffsetX registers
+ // report the END of the frame buffer, not the beginning.
+ emuptr baseAddr = fBaseVideoAddr;
+
+ int32 width = ((fRegs.horizontalPeriod + 1) * 8);
+ int32 height = ((fRegs.verticalPeriod1 << 8) | fRegs.verticalPeriod0) + 1;
+ int32 rowBytes = ((width * this->PrvGetLCDDepth ()) / 8);
+
+ info.fLeftMargin = 0;
+
+ if (bpp <= 8)
+ {
+ EmPixMapFormat format = bpp == 1 ? kPixMapFormat1 :
+ bpp == 2 ? kPixMapFormat2 :
+ bpp == 4 ? kPixMapFormat4 :
+ kPixMapFormat8;
+
+ RGBList colorTable;
+ this->PrvGetPalette (colorTable);
+
+ // Set format, size, and color table of EmPixMap.
+
+ info.fImage.SetSize (EmPoint (width, height));
+ info.fImage.SetFormat (format);
+ info.fImage.SetRowBytes (rowBytes);
+ info.fImage.SetColorTable (colorTable);
+
+ // Determine first and last scanlines to fetch, and fetch them.
+
+ info.fFirstLine = (info.fScreenLow - baseAddr) / rowBytes;
+ info.fLastLine = (info.fScreenHigh - baseAddr - 1) / rowBytes + 1;
+
+ long firstLineOffset = info.fFirstLine * rowBytes;
+ long lastLineOffset = info.fLastLine * rowBytes;
+
+ EmMem_memcpy (
+ (void*) ((uint8*) info.fImage.GetBits () + firstLineOffset),
+ baseAddr + firstLineOffset,
+ lastLineOffset - firstLineOffset);
+ }
+ else
+ {
+ // Set depth, size, and color table of EmPixMap.
+
+ info.fImage.SetSize (EmPoint (width, height));
+ info.fImage.SetFormat (kPixMapFormat24RGB);
+
+ // Determine first and last scanlines to fetch.
+
+ info.fFirstLine = (info.fScreenLow - baseAddr) / rowBytes;
+ info.fLastLine = (info.fScreenHigh - baseAddr - 1) / rowBytes + 1;
+
+ // Get location and rowBytes of source bytes.
+
+ uint8* srcStart = EmMemGetRealAddress (baseAddr);
+ int32 srcRowBytes = rowBytes;
+ uint8* srcPtr = srcStart + srcRowBytes * info.fFirstLine;
+ uint8* srcPtr0 = srcPtr;
+
+ // Get location and rowBytes of destination bytes.
+
+ uint8* destStart = (uint8*) info.fImage.GetBits ();
+ int32 destRowBytes = info.fImage.GetRowBytes ();
+ uint8* destPtr = destStart + destRowBytes * info.fFirstLine;
+ uint8* destPtr0 = destPtr;
+
+ // Get height of range to copy.
+
+ int32 height = info.fLastLine - info.fFirstLine;
+
+ // Copy the pixels from source to dest.
+
+ for (int yy = 0; yy < height; ++yy)
+ {
+ for (int xx = 0; xx < width; ++xx)
+ {
+ uint8 p1 = EmMemDoGet8 (srcPtr++); // GGGBBBBB
+ uint8 p2 = EmMemDoGet8 (srcPtr++); // RRRRRGGG
+
+ // Merge the two together so that we get RRRRRGGG GGGBBBBB
+
+ uint16 p;
+
+ if (!byteSwapped)
+ p = (p2 << 8) | p1;
+ else
+ p = (p1 << 8) | p2;
+
+ // Shift the bits around, forming RRRRRrrr, GGGGGGgg, and
+ // BBBBBbbb values, where the lower-case bits are copies of
+ // the least significant bits in the upper-case bits.
+ //
+ // Note that all of this could also be done with three 64K
+ // lookup tables. If speed is an issue, we might want to
+ // investigate that.
+
+ if (mono)
+ {
+ uint8 green = ((p >> 3) & 0xFC) | ((p >> 5) & 0x03);
+ *destPtr++ = green;
+ *destPtr++ = green;
+ *destPtr++ = green;
+ }
+ else
+ {
+ *destPtr++ = ((p >> 8) & 0xF8) | ((p >> 11) & 0x07);
+ *destPtr++ = ((p >> 3) & 0xFC) | ((p >> 5) & 0x03);
+ *destPtr++ = ((p << 3) & 0xF8) | ((p >> 0) & 0x07);
+ }
+ }
+
+ srcPtr = srcPtr0 += srcRowBytes;
+ destPtr = destPtr0 += destRowBytes;
+ }
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1376VisorPrism::PrvGetLCDDepth
+// ---------------------------------------------------------------------------
+
+int32 EmRegsSED1376VisorPrism::PrvGetLCDDepth (void)
+{
+ UInt8 depth = fRegs.displayMode;
+
+ depth &= sed1376DisplayModeDepthMask;
+
+ switch (depth)
+ {
+ case sed1376DisplayModeDepth16: return 16;
+ case sed1376DisplayModeDepth8: return 8;
+ case sed1376DisplayModeDepth4: return 4;
+ case sed1376DisplayModeDepth2: return 2;
+ case sed1376DisplayModeDepth1: return 1;
+ default: EmAssert (false);
+ }
+
+ return 8;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1376VisorPrism::reservedWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsSED1376VisorPrism::reservedWrite (emuptr address, int size, uint32 value)
+{
+ UNUSED_PARAM (address);
+ UNUSED_PARAM (size);
+ UNUSED_PARAM (value);
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1376PalmGeneric::EmRegsSED1376PalmGeneric
+// ---------------------------------------------------------------------------
+
+EmRegsSED1376PalmGeneric::EmRegsSED1376PalmGeneric (emuptr baseRegsAddr,
+ emuptr baseVideoAddr) :
+ EmRegsSED1376 (baseRegsAddr, baseVideoAddr)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1376PalmGeneric::~EmRegsSED1376PalmGeneric
+// ---------------------------------------------------------------------------
+
+EmRegsSED1376PalmGeneric::~EmRegsSED1376PalmGeneric (void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1376PalmGeneric::GetLCDBeginEnd
+// ---------------------------------------------------------------------------
+
+void EmRegsSED1376PalmGeneric::GetLCDBeginEnd (emuptr& begin, emuptr& end)
+{
+ // Get the screen metrics.
+
+// Bool wordSwapped = (fRegs.specialEffects & sed1376WordSwapMask) != 0;
+// Bool byteSwapped = (fRegs.specialEffects & sed1376ByteSwapMask) != 0;
+// int32 bpp = 1 << ((fRegs.displayMode & sed1376BPPMask) >> sed1376BPPShift);
+#if !OVERLAY_IS_MAIN
+// int32 width = ((fRegs.horizontalPeriod + 1) * 8);
+ int32 height = ((fRegs.verticalPeriod1 << 8) | fRegs.verticalPeriod0) + 1;
+ int32 rowBytes = ((fRegs.mainLineAddressOffset1 << 8) | fRegs.mainLineAddressOffset0) * 4;
+ uint32 offset = (fRegs.mainStartAddress2 << 18) |
+ (fRegs.mainStartAddress1 << 10) |
+ (fRegs.mainStartAddress0 << 2);
+#else
+// int32 left = ((fRegs.ovlyStartXPosition1 << 8) | fRegs.ovlyStartXPosition0) * 32 / bpp;
+// int32 right = ((fRegs.ovlyEndXPosition1 << 8) | fRegs.ovlyEndXPosition0) * 32 / bpp;
+ int32 top = ((fRegs.ovlyStartYPosition1 << 8) | fRegs.ovlyStartYPosition0);
+ int32 bottom = ((fRegs.ovlyEndYPosition1 << 8) | fRegs.ovlyEndYPosition0);
+
+// int32 width = right - left + (32 / bpp);
+ int32 height = bottom - top + 1;
+ int32 rowBytes = ((fRegs.ovlyLineAddressOffset1 << 8) | fRegs.ovlyLineAddressOffset0) * 4;
+ uint32 offset = (fRegs.ovlyStartAddress2 << 18) |
+ (fRegs.ovlyStartAddress1 << 10) |
+ (fRegs.ovlyStartAddress0 << 2);
+#endif
+ emuptr baseAddr = fBaseVideoAddr + offset;
+
+ begin = baseAddr;
+ end = baseAddr + rowBytes * height;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsSED1376PalmGeneric::GetLCDScanlines
+// ---------------------------------------------------------------------------
+
+void EmRegsSED1376PalmGeneric::GetLCDScanlines (EmScreenUpdateInfo& info)
+{
+ // Get the screen metrics.
+
+// Bool wordSwapped = (fRegs.specialEffects & sed1376WordSwapMask) != 0;
+ Bool byteSwapped = (fRegs.specialEffects & sed1376ByteSwapMask) != 0;
+ Bool mono = (fRegs.displayMode & sed1376MonoMask) != 0;
+ int32 bpp = 1 << ((fRegs.displayMode & sed1376BPPMask) >> sed1376BPPShift);
+#if !OVERLAY_IS_MAIN
+ int32 width = ((fRegs.horizontalPeriod + 1) * 8);
+ int32 height = ((fRegs.verticalPeriod1 << 8) | fRegs.verticalPeriod0) + 1;
+ int32 rowBytes = ((fRegs.mainLineAddressOffset1 << 8) | fRegs.mainLineAddressOffset0) * 4;
+ uint32 offset = (fRegs.mainStartAddress2 << 18) |
+ (fRegs.mainStartAddress1 << 10) |
+ (fRegs.mainStartAddress0 << 2);
+#else
+ int32 left = ((fRegs.ovlyStartXPosition1 << 8) | fRegs.ovlyStartXPosition0) * 32 / bpp;
+ int32 right = ((fRegs.ovlyEndXPosition1 << 8) | fRegs.ovlyEndXPosition0) * 32 / bpp;
+ int32 top = ((fRegs.ovlyStartYPosition1 << 8) | fRegs.ovlyStartYPosition0);
+ int32 bottom = ((fRegs.ovlyEndYPosition1 << 8) | fRegs.ovlyEndYPosition0);
+
+ int32 width = right - left + (32 / bpp);
+ int32 height = bottom - top + 1;
+ int32 rowBytes = ((fRegs.ovlyLineAddressOffset1 << 8) | fRegs.ovlyLineAddressOffset0) * 4;
+ uint32 offset = (fRegs.ovlyStartAddress2 << 18) |
+ (fRegs.ovlyStartAddress1 << 10) |
+ (fRegs.ovlyStartAddress0 << 2);
+#endif
+ emuptr baseAddr = fBaseVideoAddr + offset;
+
+ info.fLeftMargin = 0;
+
+ if (bpp <= 8)
+ {
+ EmPixMapFormat format = bpp == 1 ? kPixMapFormat1 :
+ bpp == 2 ? kPixMapFormat2 :
+ bpp == 4 ? kPixMapFormat4 :
+ kPixMapFormat8;
+
+ RGBList colorTable;
+ this->PrvGetPalette (colorTable);
+
+ // Set format, size, and color table of EmPixMap.
+
+ info.fImage.SetSize (EmPoint (width, height));
+ info.fImage.SetFormat (format);
+ info.fImage.SetRowBytes (rowBytes);
+ info.fImage.SetColorTable (colorTable);
+
+ // Determine first and last scanlines to fetch, and fetch them.
+
+ info.fFirstLine = (info.fScreenLow - baseAddr) / rowBytes;
+ info.fLastLine = (info.fScreenHigh - baseAddr - 1) / rowBytes + 1;
+
+ long firstLineOffset = info.fFirstLine * rowBytes;
+ long lastLineOffset = info.fLastLine * rowBytes;
+
+ EmMem_memcpy (
+ (void*) ((uint8*) info.fImage.GetBits () + firstLineOffset),
+ baseAddr + firstLineOffset,
+ lastLineOffset - firstLineOffset);
+ }
+ else
+ {
+ // Set depth, size, and color table of EmPixMap.
+
+ info.fImage.SetSize (EmPoint (width, height));
+ info.fImage.SetFormat (kPixMapFormat24RGB);
+
+ // Determine first and last scanlines to fetch.
+
+ info.fFirstLine = (info.fScreenLow - baseAddr) / rowBytes;
+ info.fLastLine = (info.fScreenHigh - baseAddr - 1) / rowBytes + 1;
+
+ // Get location and rowBytes of source bytes.
+
+ uint8* srcStart = EmMemGetRealAddress (baseAddr);
+ int32 srcRowBytes = rowBytes;
+ uint8* srcPtr = srcStart + srcRowBytes * info.fFirstLine;
+ uint8* srcPtr0 = srcPtr;
+
+ // Get location and rowBytes of destination bytes.
+
+ uint8* destStart = (uint8*) info.fImage.GetBits ();
+ int32 destRowBytes = info.fImage.GetRowBytes ();
+ uint8* destPtr = destStart + destRowBytes * info.fFirstLine;
+ uint8* destPtr0 = destPtr;
+
+ // Get height of range to copy.
+
+ int32 height = info.fLastLine - info.fFirstLine;
+
+ // Copy the pixels from source to dest.
+
+ for (int yy = 0; yy < height; ++yy)
+ {
+ for (int xx = 0; xx < width; ++xx)
+ {
+ uint8 p1 = EmMemDoGet8 (srcPtr++); // GGGBBBBB
+ uint8 p2 = EmMemDoGet8 (srcPtr++); // RRRRRGGG
+
+ // Merge the two together so that we get RRRRRGGG GGGBBBBB
+
+ uint16 p;
+
+ if (!byteSwapped)
+ p = (p2 << 8) | p1;
+ else
+ p = (p1 << 8) | p2;
+
+ // Shift the bits around, forming RRRRRrrr, GGGGGGgg, and
+ // BBBBBbbb values, where the lower-case bits are copies of
+ // the least significant bits in the upper-case bits.
+ //
+ // Note that all of this could also be done with three 64K
+ // lookup tables. If speed is an issue, we might want to
+ // investigate that.
+
+ if (mono)
+ {
+ uint8 green = ((p >> 3) & 0xFC) | ((p >> 5) & 0x03);
+ *destPtr++ = green;
+ *destPtr++ = green;
+ *destPtr++ = green;
+ }
+ else
+ {
+ *destPtr++ = ((p >> 8) & 0xF8) | ((p >> 11) & 0x07);
+ *destPtr++ = ((p >> 3) & 0xFC) | ((p >> 5) & 0x03);
+ *destPtr++ = ((p << 3) & 0xF8) | ((p >> 0) & 0x07);
+ }
+ }
+
+ srcPtr = srcPtr0 += srcRowBytes;
+ destPtr = destPtr0 += destRowBytes;
+ }
+ }
+
+ if (!this->GetLCDBacklightOn ())
+ {
+ info.fImage.ChangeTone (-10, info.fFirstLine, info.fLastLine);
+ }
+}
diff --git a/SrcShared/Hardware/EmRegsSED1376.h b/SrcShared/Hardware/EmRegsSED1376.h
new file mode 100644
index 0000000..62a1c56
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsSED1376.h
@@ -0,0 +1,106 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegsSED1376_h
+#define EmRegsSED1376_h
+
+#include "EmHAL.h" // EmHALHandler
+#include "EmPalmStructs.h"
+#include "EmRegs.h"
+#include "EmStructs.h" // RGBList
+
+class SessionFile;
+class EmScreenUpdateInfo;
+
+
+#define sed1376RegsAddr (0x1FF80000)
+#define sed1376VideoMemStart (0x1FFA0000)
+#define sed1376VideoMemSize (80 * 1024L)
+
+
+class EmRegsSED1376 : public EmRegs, public EmHALHandler
+{
+ public:
+ EmRegsSED1376 (emuptr baseRegsAddr,
+ emuptr baseVideoAddr);
+ virtual ~EmRegsSED1376 (void);
+
+ // EmRegs overrides
+ virtual void Initialize (void);
+ virtual void Reset (Bool hardwareReset);
+ virtual void Save (SessionFile&);
+ virtual void Load (SessionFile&);
+ virtual void Dispose (void);
+
+ virtual void SetSubBankHandlers (void);
+ virtual uint8* GetRealAddress (emuptr address);
+ virtual emuptr GetAddressStart (void);
+ virtual uint32 GetAddressRange (void);
+
+ // EmHAL overrides
+ virtual Bool GetLCDScreenOn (void);
+ virtual Bool GetLCDBacklightOn (void);
+ virtual Bool GetLCDHasFrame (void);
+ virtual void GetLCDBeginEnd (emuptr& begin, emuptr& end) = 0;
+ virtual void GetLCDScanlines (EmScreenUpdateInfo& info) = 0;
+
+ private:
+ uint32 powerSaveConfigurationRead (emuptr address, int size);
+
+ void invalidateWrite (emuptr address, int size, uint32 value);
+ void lutWriteAddressWrite (emuptr address, int size, uint32 value);
+ void lutReadAddressWrite (emuptr address, int size, uint32 value);
+
+ protected:
+ void PrvGetPalette (RGBList& thePalette);
+
+ protected:
+ emuptr fBaseRegsAddr;
+ emuptr fBaseVideoAddr;
+ EmProxySED1376RegsType fRegs;
+ RGBType fClutData[256];
+};
+
+
+class EmRegsSED1376VisorPrism : public EmRegsSED1376
+{
+ public:
+ EmRegsSED1376VisorPrism (emuptr baseRegsAddr,
+ emuptr baseVideoAddr);
+ virtual ~EmRegsSED1376VisorPrism (void);
+
+ virtual void SetSubBankHandlers (void);
+
+ virtual void GetLCDBeginEnd (emuptr& begin, emuptr& end);
+ virtual void GetLCDScanlines (EmScreenUpdateInfo& info);
+
+ private:
+ void reservedWrite (emuptr address, int size, uint32 value);
+
+ private:
+ int32 PrvGetLCDDepth (void);
+};
+
+
+class EmRegsSED1376PalmGeneric : public EmRegsSED1376
+{
+ public:
+ EmRegsSED1376PalmGeneric (emuptr baseRegsAddr,
+ emuptr baseVideoAddr);
+ virtual ~EmRegsSED1376PalmGeneric (void);
+
+ virtual void GetLCDBeginEnd (emuptr& begin, emuptr& end);
+ virtual void GetLCDScanlines (EmScreenUpdateInfo& info);
+};
+
+#endif /* EmRegsSED1376_h */
diff --git a/SrcShared/Hardware/EmRegsSZ.cpp b/SrcShared/Hardware/EmRegsSZ.cpp
new file mode 100644
index 0000000..b6b0a96
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsSZ.cpp
@@ -0,0 +1,17 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmRegsSZ.h"
+#include "EmRegsSZPrv.h"
+
diff --git a/SrcShared/Hardware/EmRegsSZ.h b/SrcShared/Hardware/EmRegsSZ.h
new file mode 100644
index 0000000..bc4f3b3
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsSZ.h
@@ -0,0 +1,18 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegsSZ_h
+#define EmRegsSZ_h
+
+
+#endif /* EmRegsSZ_h */
diff --git a/SrcShared/Hardware/EmRegsSZPrv.h b/SrcShared/Hardware/EmRegsSZPrv.h
new file mode 100644
index 0000000..4c9aaa7
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsSZPrv.h
@@ -0,0 +1,19 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegsSZPrv_h
+#define EmRegsSZPrv_h
+
+
+
+#endif /* EmRegsSZPrv_h */
diff --git a/SrcShared/Hardware/EmRegsSZTemp.cpp b/SrcShared/Hardware/EmRegsSZTemp.cpp
new file mode 100644
index 0000000..7a621bf
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsSZTemp.cpp
@@ -0,0 +1,17 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmRegsSZTemp.h"
+#include "EmRegsSZPrv.h"
+
diff --git a/SrcShared/Hardware/EmRegsSZTemp.h b/SrcShared/Hardware/EmRegsSZTemp.h
new file mode 100644
index 0000000..7905540
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsSZTemp.h
@@ -0,0 +1,20 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegsSZTemp_h
+#define EmRegsSZTemp_h
+
+#include "EmRegsSZ.h"
+
+
+#endif /* EmRegsSZTemp_h */
diff --git a/SrcShared/Hardware/EmRegsUSBPhilipsPDIUSBD12.cpp b/SrcShared/Hardware/EmRegsUSBPhilipsPDIUSBD12.cpp
new file mode 100644
index 0000000..20df6e1
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsUSBPhilipsPDIUSBD12.cpp
@@ -0,0 +1,154 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmRegsUSBPhilipsPDIUSBD12.h"
+
+
+// Given a register (specified by its field name), return its address
+// in emulated space.
+
+#undef addressof
+#define addressof(reg) \
+ (this->GetAddressStart () + fRegs.offsetof_##reg ())
+
+
+// Macro to help the installation of handlers for a register.
+
+#undef INSTALL_HANDLER
+#define INSTALL_HANDLER(read, write, reg) \
+ this->SetHandler ( (ReadFunction) &EmRegsUSBPhilipsPDIUSBD12::read, \
+ (WriteFunction) &EmRegsUSBPhilipsPDIUSBD12::write, \
+ addressof (reg), \
+ fRegs.reg.GetSize ())
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsUSBPhilipsPDIUSBD12::EmRegsUSBPhilipsPDIUSBD12
+// ---------------------------------------------------------------------------
+
+EmRegsUSBPhilipsPDIUSBD12::EmRegsUSBPhilipsPDIUSBD12 (emuptr baseAddr) :
+ fBaseAddr (baseAddr)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsUSBPhilipsPDIUSBD12::~EmRegsUSBPhilipsPDIUSBD12
+// ---------------------------------------------------------------------------
+
+EmRegsUSBPhilipsPDIUSBD12::~EmRegsUSBPhilipsPDIUSBD12 (void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsUSBPhilipsPDIUSBD12::Initialize
+// ---------------------------------------------------------------------------
+
+void EmRegsUSBPhilipsPDIUSBD12::Initialize (void)
+{
+ EmRegs::Initialize ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsUSBPhilipsPDIUSBD12::Reset
+// ---------------------------------------------------------------------------
+
+void EmRegsUSBPhilipsPDIUSBD12::Reset (Bool hardwareReset)
+{
+ EmRegs::Reset (hardwareReset);
+
+ if (hardwareReset)
+ {
+ memset (fRegs.GetPtr (), 0, fRegs.GetSize ());
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsUSBPhilipsPDIUSBD12::Save
+// ---------------------------------------------------------------------------
+
+void EmRegsUSBPhilipsPDIUSBD12::Save (SessionFile& f)
+{
+ EmRegs::Save (f);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsUSBPhilipsPDIUSBD12::Load
+// ---------------------------------------------------------------------------
+
+void EmRegsUSBPhilipsPDIUSBD12::Load (SessionFile& f)
+{
+ EmRegs::Load (f);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsUSBPhilipsPDIUSBD12::Dispose
+// ---------------------------------------------------------------------------
+
+void EmRegsUSBPhilipsPDIUSBD12::Dispose (void)
+{
+ EmRegs::Dispose ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsUSBPhilipsPDIUSBD12::SetSubBankHandlers
+// ---------------------------------------------------------------------------
+
+void EmRegsUSBPhilipsPDIUSBD12::SetSubBankHandlers (void)
+{
+ // Install base handlers.
+
+ EmRegs::SetSubBankHandlers ();
+
+ // Now add standard/specialized handers for the defined registers.
+
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, data);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, command);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsUSBPhilipsPDIUSBD12::GetRealAddress
+// ---------------------------------------------------------------------------
+
+uint8* EmRegsUSBPhilipsPDIUSBD12::GetRealAddress (emuptr address)
+{
+ return (uint8*) fRegs.GetPtr () + address - this->GetAddressStart ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsUSBPhilipsPDIUSBD12::GetAddressStart
+// ---------------------------------------------------------------------------
+
+emuptr EmRegsUSBPhilipsPDIUSBD12::GetAddressStart (void)
+{
+ return fBaseAddr;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsUSBPhilipsPDIUSBD12::GetAddressRange
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsUSBPhilipsPDIUSBD12::GetAddressRange (void)
+{
+ return fRegs.GetSize ();
+}
diff --git a/SrcShared/Hardware/EmRegsUSBPhilipsPDIUSBD12.h b/SrcShared/Hardware/EmRegsUSBPhilipsPDIUSBD12.h
new file mode 100644
index 0000000..71e0b34
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsUSBPhilipsPDIUSBD12.h
@@ -0,0 +1,42 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegsUSBPhilipsPDIUSBD12_h
+#define EmRegsUSBPhilipsPDIUSBD12_h
+
+#include "EmRegs.h"
+#include "EmPalmStructs.h" // EmProxyUsbHwrType
+
+class EmRegsUSBPhilipsPDIUSBD12 : public EmRegs
+{
+ public:
+ EmRegsUSBPhilipsPDIUSBD12 (emuptr);
+ virtual ~EmRegsUSBPhilipsPDIUSBD12 (void);
+
+ virtual void Initialize (void);
+ virtual void Reset (Bool hardwareReset);
+ virtual void Save (SessionFile&);
+ virtual void Load (SessionFile&);
+ virtual void Dispose (void);
+
+ virtual void SetSubBankHandlers (void);
+ virtual uint8* GetRealAddress (emuptr address);
+ virtual emuptr GetAddressStart (void);
+ virtual uint32 GetAddressRange (void);
+
+ private:
+ emuptr fBaseAddr;
+ EmProxyUsbHwrType fRegs;
+};
+
+#endif /* EmRegsUSBPhilipsPDIUSBD12_h */
diff --git a/SrcShared/Hardware/EmRegsUSBVisor.cpp b/SrcShared/Hardware/EmRegsUSBVisor.cpp
new file mode 100644
index 0000000..ccd4c6e
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsUSBVisor.cpp
@@ -0,0 +1,164 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmRegsUSBVisor.h"
+
+#include "EmSession.h" // GetDevice
+#include "EmHAL.h" // EmHAL::GetROMSize
+#include "EmBankROM.h" // EmBankROM::GetMemoryStart
+
+
+// Given a register (specified by its field name), return its address
+// in emulated space.
+
+#define addressof(reg) \
+ (this->GetAddressStart () + fRegs.offsetof_##reg ())
+
+
+// Macro to help the installation of handlers for a register.
+
+#define INSTALL_HANDLER(read, write, reg) \
+ this->SetHandler ( (ReadFunction) &EmRegsUSBVisor::read, \
+ (WriteFunction) &EmRegsUSBVisor::write, \
+ addressof (reg), \
+ fRegs.reg.GetSize ())
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsUSBVisor::EmRegsUSBVisor
+// ---------------------------------------------------------------------------
+
+EmRegsUSBVisor::EmRegsUSBVisor (void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsUSBVisor::~EmRegsUSBVisor
+// ---------------------------------------------------------------------------
+
+EmRegsUSBVisor::~EmRegsUSBVisor (void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsUSBVisor::Initialize
+// ---------------------------------------------------------------------------
+
+void EmRegsUSBVisor::Initialize (void)
+{
+ EmRegs::Initialize ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsUSBVisor::Reset
+// ---------------------------------------------------------------------------
+
+void EmRegsUSBVisor::Reset (Bool hardwareReset)
+{
+ EmRegs::Reset (hardwareReset);
+
+ if (hardwareReset)
+ {
+ memset (fRegs.GetPtr (), 0, fRegs.GetSize ());
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsUSBVisor::Save
+// ---------------------------------------------------------------------------
+
+void EmRegsUSBVisor::Save (SessionFile& f)
+{
+ EmRegs::Save (f);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsUSBVisor::Load
+// ---------------------------------------------------------------------------
+
+void EmRegsUSBVisor::Load (SessionFile& f)
+{
+ EmRegs::Load (f);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsUSBVisor::Dispose
+// ---------------------------------------------------------------------------
+
+void EmRegsUSBVisor::Dispose (void)
+{
+ EmRegs::Dispose ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsUSBVisor::SetSubBankHandlers
+// ---------------------------------------------------------------------------
+
+void EmRegsUSBVisor::SetSubBankHandlers (void)
+{
+ // Install base handlers.
+
+ EmRegs::SetSubBankHandlers ();
+
+ // Now add standard/specialized handers for the defined registers.
+
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, data);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, command);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsUSBVisor::GetRealAddress
+// ---------------------------------------------------------------------------
+
+uint8* EmRegsUSBVisor::GetRealAddress (emuptr address)
+{
+ return (uint8*) fRegs.GetPtr () + address - this->GetAddressStart ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsUSBVisor::GetAddressStart
+// ---------------------------------------------------------------------------
+
+emuptr EmRegsUSBVisor::GetAddressStart (void)
+{
+ /*
+ Auto-detect USB hardware base address. In the Visor, the USB hardware
+ is at CSA1, which resides just after the ROM (CSA0) in memory.
+ */
+
+ EmDevice device = gSession->GetDevice ();
+ if (device.HardwareID () == 0x0a /*halModelIDVisorPrism*/) // in Prism it is not at CSA1
+ return (emuptr) 0x10800000L;
+
+ return EmBankROM::GetMemoryStart() + EmHAL::GetROMSize ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsUSBVisor::GetAddressRange
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsUSBVisor::GetAddressRange (void)
+{
+ return fRegs.GetSize ();
+}
diff --git a/SrcShared/Hardware/EmRegsUSBVisor.h b/SrcShared/Hardware/EmRegsUSBVisor.h
new file mode 100644
index 0000000..0468f39
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsUSBVisor.h
@@ -0,0 +1,44 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegsUSBVisor_h
+#define EmRegsUSBVisor_h
+
+#include "EmPalmStructs.h"
+#include "EmRegs.h"
+
+class SessionFile;
+
+
+class EmRegsUSBVisor : public EmRegs
+{
+ public:
+ EmRegsUSBVisor (void);
+ virtual ~EmRegsUSBVisor (void);
+
+ virtual void Initialize (void);
+ virtual void Reset (Bool hardwareReset);
+ virtual void Save (SessionFile&);
+ virtual void Load (SessionFile&);
+ virtual void Dispose (void);
+
+ virtual void SetSubBankHandlers (void);
+ virtual uint8* GetRealAddress (emuptr address);
+ virtual emuptr GetAddressStart (void);
+ virtual uint32 GetAddressRange (void);
+
+ private:
+ EmProxyUsbHwrType fRegs;
+};
+
+#endif /* EmRegsUSBVisor_h */
diff --git a/SrcShared/Hardware/EmRegsVZ.cpp b/SrcShared/Hardware/EmRegsVZ.cpp
new file mode 100644
index 0000000..f646b5b
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsVZ.cpp
@@ -0,0 +1,3116 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmRegsVZ.h"
+#include "EmRegsVZPrv.h"
+
+#include "Byteswapping.h" // Canonical
+#include "EmDevice.h"
+#include "EmHAL.h" // EmHAL
+#include "EmMemory.h" // gMemAccessFlags, EmMem_memcpy
+#include "EmPixMap.h" // SetSize, SetRowBytes, etc.
+#include "EmScreen.h" // EmScreenUpdateInfo
+#include "EmSession.h" // gSession
+#include "EmSPISlave.h" // DoExchange
+#include "Hordes.h" // Hordes::IsOn
+#include "Logging.h" // LogAppendMsg
+#include "Miscellaneous.h" // GetHostTime
+#include "PreferenceMgr.h" // Preference
+#include "SessionFile.h" // WriteHwrDBallVZType, etc.
+#include "UAE.h" // regs, SPCFLAG_INT
+
+#include "PalmPack.h"
+#define NON_PORTABLE
+ #include "HwrMiscFlags.h" // hwrMiscFlagID1
+
+ // Some platform-specific -- yet fairly portable -- defines.
+ #define hwrVZPortDKbdCol0 0x01 // (H) Keyboard Column 0 (aka INT0)
+ #define hwrVZPortDKbdCol1 0x02 // (H) Keyboard Column 1 (aka INT1)
+ #define hwrVZPortDKbdCol2 0x04 // (H) Keyboard Column 2 (aka INT2)
+ #define hwrVZPortDKbdCol3 0x08 // (H) Keyboard Column 3 (aka INT3)
+ #define hwrVZPortDKeyBits 0x0F // All Keyboard Columns
+
+#undef NON_PORTABLE
+#include "PalmPackPop.h"
+
+
+static const uint16 UPSIZMask = 0x1800; // Mask to get the unprotected memory size from csDSelect.
+static const uint16 DRAMMask = 0x0200;
+static const uint16 SIZMask = 0x000E; // Mask to get the memory size from csASelect.
+static const uint16 ENMask = 0x0001; // Mask to get the enable bit from csASelect.
+
+static const int UPSIZShift = 11;
+static const int SIZShift = 1;
+static const int ENShift = 0;
+
+static const uint16 BUPS2Mask = 0x0001;
+static const uint16 CUPS2Mask = 0x0004;
+static const uint16 DUPS2Mask = 0x0010;
+static const uint16 DSIZ3Mask = 0x0040;
+static const uint16 EUPENMask = 0x4000;
+
+static const int BUPS2Shift = 0;
+static const int CUPS2Shift = 2;
+static const int DUPS2Shift = 4;
+
+static const int kBaseAddressShift = 13; // Shift to get base address from CSGBx register value
+
+#define PRINTF if (1) ; else LogAppendMsg
+
+// Values used to initialize the DragonBallVZ registers.
+
+static const HwrM68VZ328Type kInitial68VZ328RegisterValues =
+{
+ 0x1C, // UInt8 scr; // $000: System Control Register
+
+ { 0 }, // UInt8 ___filler0[0x003-0x001];
+
+ 0x00, // UInt8 pcr; // $003: Peripheral Control Register
+ 0x56, // UInt8 chipID; // $004: Chip ID Register
+ 0x01, // UInt8 maskID; // $005: Mask ID Register
+ 0x0000, // UInt16 swID; // $006: Software ID Register
+ 0x1FFF, // UInt16 ioDriveControl; // $008: I/O Drive Control Register
+
+ { 0 }, // UInt8 ___filler1[0x100-0x00A];
+
+ 0x0000, // UInt16 csAGroupBase; // $100: Chip Select Group A Base Register
+ 0x0000, // UInt16 csBGroupBase; // $102: Chip Select Group B Base Register
+ 0x0000, // UInt16 csCGroupBase; // $104: Chip Select Group C Base Register
+ 0x0000, // UInt16 csDGroupBase; // $106: Chip Select Group D Base Register
+
+ 0x0000, // UInt16 csUGroupBase; // $108: Chip Select Upper Group Base Register
+
+ 0x0000, // UInt16 csControl1; // $10A: Chip Select Control Register
+ 0x0000, // UInt16 csControl2; // $10C: Chip Select Control Register
+
+ { 0 }, // UInt8 ___filler2[0x110-0x10c];
+
+ 0x00B0, // UInt16 csASelect; // $110: Group A Chip Select Register
+ 0x0000, // UInt16 csBSelect; // $112: Group B Chip Select Register
+ 0x0000, // UInt16 csCSelect; // $114: Group C Chip Select Register
+ 0x0200, // UInt16 csDSelect; // $116: Group D Chip Select Register
+
+ 0x0060, // UInt16 emuCS; // $118: EMU Chip Select Register
+
+ { 0 }, // UInt8 ___filler3[0x200-0x11A];
+
+ 0x0000, // UInt16 csControl3; // $150: Chip Select Control Register
+
+ { 0 }, // UInt8 ___filler3[0x200-0x11A];
+
+ 0x24B3, // UInt16 pllControl; // $200: PLL Control Register
+ 0x0123, // UInt16 pllFreqSel; // $202: CGM Frequency Select Register
+
+ { 0 }, // UInt8 ___filler4[0x207-0x204];
+
+ 0x1F, // UInt8 pwrControl; // $207: Power Control Register
+
+ { 0 }, // UInt8 ___filler5[0x300-0x208];
+
+ 0x00, // UInt8 intVector; // $300: Interrupt Vector Register
+ 0x00, // UInt8 ___filler6;
+ 0x0000, // UInt16 intControl; // $302: Interrupt Control Register
+ 0x00FF, // UInt16 intMaskHi; // $304: Interrupt Mask Register/HIGH word
+ 0xFFFF, // UInt16 intMaskLo; // $306: Interrupt Mask Register/LOW word
+ { 0 }, // UInt8 ___filler7[0x30c-0x308];
+ 0x0000, // UInt16 intStatusHi; // $30C: Interrupt Status Register/HIGH word
+ 0x0000, // UInt16 intStatusLo; // $30E: Interrupt Status Register/LOW word
+ 0x0000, // UInt16 intPendingHi; // $310: Interrupt Pending Register/HIGH word
+ 0x0000, // UInt16 intPendingLo; // $312: Interrupt Pending Register/LOW word
+ 0x6533, // UInt16 intLevelControl; // $314: Interrupt Level Control Register
+
+ { 0 }, // UInt8 ___filler4a[0x400-0x316];
+
+ 0x00, // UInt8 portADir; // $400: Port A Direction Register
+ 0x00, // UInt8 portAData; // $401: Port A Data Register
+ 0xFF, // UInt8 portAPullupEn; // $402: Port A Pullup Enable
+
+ { 0 }, // UInt8 ___filler8[5];
+
+ 0x00, // UInt8 portBDir; // $408: Port B Direction Register
+ 0x00, // UInt8 portBData; // $409: Port B Data Register
+ 0xFF, // UInt8 portBPullupEn; // $40A: Port B Pullup Enable
+ 0xFF, // UInt8 portBSelect; // $40B: Port B Select Register
+
+ { 0 }, // UInt8 ___filler9[4];
+
+ 0x00, // UInt8 portCDir; // $410: Port C Direction Register
+ 0x00, // UInt8 portCData; // $411: Port C Data Register
+ 0xFF, // UInt8 portCPulldnEn; // $412: Port C Pulldown Enable
+ 0xFF, // UInt8 portCSelect; // $413: Port C Select Register
+
+ { 0 }, // UInt8 ___filler10[4];
+
+ 0x00, // UInt8 portDDir; // $418: Port D Direction Register
+ 0x00, // UInt8 portDData; // $419: Port D Data Register
+ 0xFF, // UInt8 portDPullupEn; // $41A: Port D Pull-up Enable
+ 0xFF, // UInt8 portDSelect; // $41B: Port D Select Register
+ 0x00, // UInt8 portDPolarity; // $41C: Port D Polarity Register
+ 0x00, // UInt8 portDIntReqEn; // $41D: Port D Interrupt Request Enable
+ 0x00, // UInt8 portDKbdIntEn; // $41E: Port D Keyboard Interrupt Enable
+ 0x00, // UInt8 portDIntEdge; // $41F: Port D IRQ Edge Register
+
+ 0x00, // UInt8 portEDir; // $420: Port E Direction Register
+ 0x00, // UInt8 portEData; // $421: Port E Data Register
+ 0xFF, // UInt8 portEPullupEn; // $422: Port E Pull-up Enable
+ 0xFF, // UInt8 portESelect; // $423: Port E Select Register
+
+ { 0 }, // UInt8 ___filler14[4];
+
+ 0x00, // UInt8 portFDir; // $428: Port F Direction Register
+ 0x00, // UInt8 portFData; // $429: Port F Data Register
+ 0xFF, // UInt8 portFPullupdnEn; // $42A: Port F Pull-up/down Enable
+ 0x8F, // UInt8 portFSelect; // $42B: Port F Select Register
+
+ { 0 }, // UInt8 ___filler16[4];
+
+ 0x00, // UInt8 portGDir; // $430: Port G Direction Register
+ 0x00, // UInt8 portGData; // $431: Port G Data Register
+ 0x3D, // UInt8 portGPullupEn; // $432: Port G Pull-up Enable
+ 0x08, // UInt8 portGSelect; // $433: Port G Select Register
+
+ { 0 }, // UInt8 ___filler17[0x438-0x434];
+
+ 0x00, // UInt8 portJDir; // $438: Port J Direction Register
+ 0x00, // UInt8 portJData; // $439: Port J Data Register
+ 0xFF, // UInt8 portJPullupEn; // $43A: Port J Pull-up Enable
+ 0xEF, // UInt8 portJSelect; // $43B: Port J Select Register
+
+ { 0 }, // UInt8 ___filler18[0x440-0x43C];
+
+ 0x00, // UInt8 portKDir; // $440: Port K Direction Register
+ 0x00, // UInt8 portKData; // $441: Port K Data Register
+ 0xFF, // UInt8 portKPullupdnEn; // $442: Port K Pull-up/down Enable
+ 0xFF, // UInt8 portKSelect; // $443: Port K Select Register
+
+ { 0 }, // UInt8 ___filler19[0x448-0x444];
+
+ 0x00, // UInt8 portMDir; // $448: Port M Direction Register
+ 0x00, // UInt8 portMData; // $449: Port M Data Register
+ 0x3F, // UInt8 portMPullupdnEn; // $44A: Port M Pull-up/down Enable
+ 0x3F, // UInt8 portMSelect; // $44B: Port M Select Register
+
+ { 0 }, // UInt8 ___filler20[0x500-0x44C];
+
+ 0x0020, // UInt16 pwmControl; // $500: PWM 1 Control Register (PWM 1 is the same as the single PWM in EZ)
+ 0x00, // UInt8 pwmSampleHi; // $502: PWM 1 Sample - high byte
+ 0x00, // UInt8 pwmSampleLo; // $503: PWM 1 Sample - low byte
+ 0xFE, // UInt8 pwmPeriod; // $504: PWM 1 Period
+ 0x00, // UInt8 pwmCounter; // $505: PWM 1 Counter
+
+ { 0 }, // UInt8 ___filler22[0x510-0x506];
+
+ 0x0000, // UInt16 pwm2Control; // $510: PWM 2 Control Register
+ 0x0000, // UInt16 pwm2Period; // $512: PWM 2 Period
+ 0x0000, // UInt16 pwm2Width; // $514: PWM 2 Width
+ 0x0000, // UInt16 pwm2Counter; // $516: PWM 2 Counter
+
+ { 0 }, // UInt8 ___filler23[0x600-0x518];
+
+ 0x0000, // UInt16 tmr1Control; // $600: Timer 1 Control Register
+ 0x0000, // UInt16 tmr1Prescaler; // $602: Timer 1 Prescaler Register
+ 0xFFFF, // UInt16 tmr1Compare; // $604: Timer 1 Compare Register
+ 0x0000, // UInt16 tmr1Capture; // $606: Timer 1 Capture Register
+ 0x0000, // UInt16 tmr1Counter; // $608: Timer 1 Counter Register
+ 0x0000, // UInt16 tmr1Status; // $60A: Timer 1 Status Register
+
+ { 0 }, // UInt8 ___filler24[0x610-0x60C];
+
+ 0x0000, // UInt16 tmr2Control; // $610: Timer 2 Control Register
+ 0x0000, // UInt16 tmr2Prescaler; // $612: Timer 2 Prescaler Register
+ 0xFFFF, // UInt16 tmr2Compare; // $614: Timer 2 Compare Register
+ 0x0000, // UInt16 tmr2Capture; // $616: Timer 2 Capture Register
+ 0x0000, // UInt16 tmr2Counter; // $618: Timer 2 Counter Register
+ 0x0000, // UInt16 tmr2Status; // $61A: Timer 2 Status Register
+
+ { 0 }, // UInt8 ___filler25[0x700-0x61C];
+
+ 0x0000, // UInt16 spiRxD; // $700: SPI Unit 1 Receive Data Register
+ 0x0000, // UInt16 spiTxD; // $702: SPI Unit 1 Transmit Data Register
+ 0x0000, // UInt16 spiCont1; // $704: SPI Unit 1 Control/Status Register
+ 0x0000, // UInt16 spiIntCS; // $706: SPI Unit 1 Interrupt control/Status Register
+ 0x0000, // UInt16 spiTest; // $708: SPI Unit 1 Test Register
+ 0x0000, // UInt16 spiSpc; // $70A: SPI Unit 1 Sample period counter register
+
+ { 0 }, // UInt8 ___filler26[0x800-0x706];
+
+ 0x0000, // UInt16 spiMasterData; // $800: SPI Unit 2 Data Register (SPI 2 is the same as the single SPI Master in EZ)
+ 0x0000, // UInt16 spiMasterControl; // $802: SPI Unit 2 Control/Status Register
+
+ { 0 }, // UInt8 ___filler27[0x900-0x804];
+
+ 0x0000, // UInt16 uControl; // $900: Uart 1 Status/Control Register (Uart 1 is the same as the single Uart in EZ)
+ 0x003F, // UInt16 uBaud; // $902: Uart 1 Baud Control Register
+ 0x0000, // UInt16 uReceive; // $904: Uart 1 Receive Register
+ 0x0000, // UInt16 uTransmit; // $906: Uart 1 Transmit Register
+ 0x0000, // UInt16 uMisc; // $908: Uart 1 Miscellaneous Register
+ 0x0000, // UInt16 uNonIntPresc; // $90A: Uart 1 Non-Integer Prescaler
+
+ { 0 }, // UInt8 ___filler28[0x910-0x90C];
+
+ 0x0000, // UInt16 u2Control; // $910: Uart 2 Status/Control Register
+ 0x003F, // UInt16 u2Baud; // $912: Uart 2 Baud Control Register
+ 0x0000, // UInt16 u2Receive; // $914: Uart 2 Receiver Register
+ 0x0000, // UInt16 u2Transmit; // $916: Uart 2 Transmitter Register
+ 0x0000, // UInt16 u2Misc; // $918: Uart 2 Miscellaneous Register
+ 0x0000, // UInt16 u2NonIntPresc; // $91A: Uart 2 Non-Integer Prescaler
+ 0x0000, // UInt16 u2FIFOHMark; // $91C: Uart 2 Half Mark FIFO Register
+
+ { 0 }, // UInt8 ___filler28a[0xA00-0x91E];
+
+ 0x00000000, // UInt32 lcdStartAddr; // $A00: Screen Starting Address Register
+ { 0 }, // UInt8 ___filler29;
+ 0xFF, // UInt8 lcdPageWidth; // $A05: Virtual Page Width Register
+ { 0 }, // UInt8 ___filler30[2];
+ 0x03F0, // UInt16 lcdScreenWidth; // $A08: Screen Width Register
+ 0x01FF, // UInt16 lcdScreenHeight; // $A0A: Screen Height Register
+ { 0 }, // UInt8 ___filler31[0xA18-0xA0C];
+ 0x0000, // UInt16 lcdCursorXPos; // $A18: Cursor X Position
+ 0x0000, // UInt16 lcdCursorYPos; // $A1A: Cursor Y Position
+ 0x0101, // UInt16 lcdCursorWidthHeight; // $A1C: Cursor Width and Height
+ { 0 }, // UInt8 ___filler32;
+ 0x7F, // UInt8 lcdBlinkControl; // $A1F: Blink Control Register
+ 0x00, // UInt8 lcdPanelControl; // $A20: Panel Interface Configuration Register
+ 0x00, // UInt8 lcdPolarity; // $A21: Polarity Config Register
+ { 0 }, // UInt8 ___filler33;
+ 0x00, // UInt8 lcdACDRate; // $A23: ACD (M) Rate Control Register
+ { 0 }, // UInt8 ___filler34;
+ 0x00, // UInt8 lcdPixelClock; // $A25: Pixel Clock Divider Register
+ { 0 }, // UInt8 ___filler35;
+ 0x00, // UInt8 lcdClockControl; // $A27: Clocking Control Register
+ 0x00FF, // UInt16 lcdRefreshRateAdj; // $A28: Refresh Rate Adjustment Register
+ { 0 }, // UInt8 ___filler37;
+ 0x00, // UInt8 lcdReserved1; // $A2B: Reserved
+ { 0 }, // UInt8 ___filler38;
+ 0x00, // UInt8 lcdPanningOffset; // $A2D: Panning Offset Register
+
+ { 0 }, // UInt8 ___filler39[0xA31-0xA2E];
+
+ 0x00, // UInt8 lcdFrameRate; // $A31: Frame Rate Control Modulation Register
+ { 0 }, // UInt8 ___filler2004;
+ 0x84, // UInt8 lcdGrayPalette; // $A33: Gray Palette Mapping Register
+ 0x00, // UInt8 lcdReserved2; // $A34: Reserved
+ { 0 }, // UInt8 ___filler2005;
+ 0x0000, // UInt16 lcdContrastControlPWM; // $A36: Contrast Control
+ 0x00, // UInt8 lcdRefreshModeControl; // $A38: Refresh Mode Control Register
+ 0x62, // UInt8 lcdDMAControl; // $A39: DMA Control Register
+
+ { 0 }, // UInt8 ___filler40[0xB00-0xA3a];
+
+ 0x00000000, // UInt32 rtcHourMinSec; // $B00: RTC Hours, Minutes, Seconds Register
+ 0x00000000, // UInt32 rtcAlarm; // $B04: RTC Alarm Register
+ { 0 }, // UInt8 ___filler2001[0xB0A-0xB08];
+ 0x0001, // UInt16 rtcWatchDog; // $B0A: RTC Watchdog Timer
+ 0x0080, // UInt16 rtcControl; // $B0C: RTC Control Register
+ 0x0000, // UInt16 rtcIntStatus; // $B0E: RTC Interrupt Status Register
+ 0x0000, // UInt16 rtcIntEnable; // $B10: RTC Interrupt Enable Register
+ 0x003F, // UInt16 stopWatch; // $B12: Stopwatch Minutes
+ { 0 }, // UInt8 ___filler2002[0xB1A-0xB14];
+ 0x0000, // UInt16 rtcDay; // $B1A: RTC Day
+ 0x0000, // UInt16 rtcDayAlarm; // $B1C: RTC Day Alarm
+
+ { 0 }, // UInt8 ___filler41[0xC00-0xB1E];
+
+ 0x0000, // UInt16 dramConfig; // $C00: DRAM Memory Config Register
+ 0x003C, // UInt16 dramControl; // $C02: DRAM Control Register
+ 0x0000, // UInt16 sdramControl; // $C04: SDRAM Control Register
+ 0x0000, // UInt16 sdramPwDn; // $C06: SDRAM Power Down Register
+
+ { 0 }, // UInt8 ___filler42[0xD00-0xC08];
+
+ 0x00000000, // UInt32 emuAddrCompare; // $D00: Emulation Address Compare Register
+ 0x00000000, // UInt32 emuAddrMask; // $D04: Emulation Address Mask Register
+ 0x0000, // UInt16 emuControlCompare; // $D08: Emulation Control Compare Register
+ 0x0000, // UInt16 emuControlMask; // $D0A: Emulation Control Mask Register
+ 0x0000, // UInt16 emuControl; // $DOC: Emulation Control Register
+ 0x0000 // UInt16 emuStatus; // $D0E: Emulation Status Register
+};
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::EmRegsVZ
+// ---------------------------------------------------------------------------
+
+EmRegsVZ::EmRegsVZ (void) :
+ EmRegs (),
+ f68VZ328Regs (),
+ fHotSyncButtonDown (0),
+ fKeyBits (0),
+ fLastTmr1Status (0),
+ fLastTmr2Status (0),
+ fPortDEdge (0),
+ fPortDDataCount (0),
+ fHour (0),
+ fMin (0),
+ fSec (0),
+ fTick (0),
+ fCycle (0)
+{
+ fUART[0] = NULL;
+ fUART[1] = NULL;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::~EmRegsVZ
+// ---------------------------------------------------------------------------
+
+EmRegsVZ::~EmRegsVZ (void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::Initialize
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::Initialize (void)
+{
+ EmRegs::Initialize ();
+
+ fUART[0] = new EmUARTDragonball (EmUARTDragonball::kUART_DragonballVZ, 0);
+ fUART[1] = new EmUARTDragonball (EmUARTDragonball::kUART_DragonballVZ, 1);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::Reset
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::Reset (Bool hardwareReset)
+{
+ EmRegs::Reset (hardwareReset);
+ if (hardwareReset)
+ {
+
+ f68VZ328Regs = kInitial68VZ328RegisterValues;
+
+ // Byteswap all the words in the DragonballVZ registers (if necessary).
+
+ Canonical (f68VZ328Regs);
+ ByteswapWords (&f68VZ328Regs, sizeof(f68VZ328Regs));
+
+ fKeyBits = 0;
+ fLastTmr1Status = 0;
+ fLastTmr2Status = 0;
+ fPortDEdge = 0;
+ fPortDDataCount = 0;
+
+ // React to the new data in the UART registers.
+
+ Bool sendTxData = false;
+ EmRegsVZ::UARTStateChanged (sendTxData, 0);
+ EmRegsVZ::UARTStateChanged (sendTxData, 1);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::Save
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::Save (SessionFile& f)
+{
+ EmRegs::Save (f);
+
+ StWordSwapper swapper (&f68VZ328Regs, sizeof(f68VZ328Regs));
+ f.WriteHwrDBallVZType (f68VZ328Regs);
+ f.FixBug (SessionFile::kBugByteswappedStructs);
+
+ const long kCurrentVersion = 3;
+
+ Chunk chunk;
+ EmStreamChunk s (chunk);
+
+ s << kCurrentVersion;
+
+ s << fHotSyncButtonDown;
+ s << fKeyBits;
+ s << fLastTmr1Status;
+ s << fLastTmr2Status;
+ s << fPortDEdge;
+
+
+ // Added in version 2.
+
+ s << fHour;
+ s << fMin;
+ s << fSec;
+ s << fTick;
+ s << fCycle;
+
+ // Added in version 3.
+
+ s << fPortDDataCount;
+
+ f.WriteDBallVZState (chunk);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::Load
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::Load (SessionFile& f)
+{
+ EmRegs::Load (f);
+
+ if (f.ReadHwrDBallVZType (f68VZ328Regs))
+ {
+ // The Windows version of Poser 2.1d29 and earlier did not write
+ // out structs in the correct format. The fields of the struct
+ // were written out in Little-Endian format, not Big-Endian. To
+ // address this problem, the bug has been fixed, and a new field
+ // is added to the file format indicating that the bug has been
+ // fixed. With the new field (the "bug bit"), Poser can identify
+ // old files from new files and read them in accordingly.
+ //
+ // With the bug fixed, the .psf files should now be interchangeable
+ // across platforms (modulo other bugs...).
+
+ if (!f.IncludesBugFix (SessionFile::kBugByteswappedStructs))
+ {
+ Canonical (f68VZ328Regs);
+ }
+ ByteswapWords (&f68VZ328Regs, sizeof(f68VZ328Regs));
+
+ // React to the new data in the UART registers.
+
+ Bool sendTxData = false;
+ EmRegsVZ::UARTStateChanged (sendTxData, 0);
+ EmRegsVZ::UARTStateChanged (sendTxData, 1);
+
+ // Reset gMemAccessFlags.fProtect_SRAMSet
+
+ gMemAccessFlags.fProtect_SRAMSet = (READ_REGISTER (csDSelect) & 0x2000) != 0;
+ }
+ else
+ {
+ f.SetCanReload (false);
+ }
+
+ Chunk chunk;
+ if (f.ReadDBallVZState (chunk))
+ {
+ long version;
+ EmStreamChunk s (chunk);
+
+ s >> version;
+
+ if (version >= 1)
+ {
+ s >> fHotSyncButtonDown;
+ s >> fKeyBits;
+ s >> fLastTmr1Status;
+ s >> fLastTmr2Status;
+ s >> fPortDEdge;
+ }
+
+ if (version >= 2)
+ {
+ s >> fHour;
+ s >> fMin;
+ s >> fSec;
+ s >> fTick;
+ s >> fCycle;
+ }
+
+ if (version >= 3)
+ {
+ s >> fPortDDataCount;
+ }
+ }
+ else
+ {
+ f.SetCanReload (false);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::Dispose
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::Dispose (void)
+{
+ delete fUART[0]; fUART[0] = NULL;
+ delete fUART[1]; fUART[1] = NULL;
+
+ EmRegs::Dispose ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::SetSubBankHandlers
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::SetSubBankHandlers (void)
+{
+ // Install base handlers.
+
+ EmRegs::SetSubBankHandlers ();
+
+ // Now add standard/specialized handers for the defined registers.
+
+ INSTALL_HANDLER (StdRead, StdWrite, scr);
+
+ INSTALL_HANDLER (StdRead, StdWrite, pcr);
+ INSTALL_HANDLER (StdRead, NullWrite, chipID);
+ INSTALL_HANDLER (StdRead, NullWrite, maskID);
+ INSTALL_HANDLER (StdRead, NullWrite, swID);
+ INSTALL_HANDLER (StdRead, StdWrite, ioDriveControl);
+
+ INSTALL_HANDLER (StdRead, StdWrite, csAGroupBase);
+ INSTALL_HANDLER (StdRead, StdWrite, csBGroupBase);
+ INSTALL_HANDLER (StdRead, StdWrite, csCGroupBase);
+ INSTALL_HANDLER (StdRead, StdWrite, csDGroupBase);
+
+ INSTALL_HANDLER (StdRead, StdWrite, csUGroupBase);
+
+ INSTALL_HANDLER (StdRead, csControl1Write, csControl1);
+ INSTALL_HANDLER (StdRead, StdWrite, csControl2);
+ INSTALL_HANDLER (StdRead, StdWrite, csControl3);
+
+ INSTALL_HANDLER (StdRead, csASelectWrite, csASelect);
+ INSTALL_HANDLER (StdRead, StdWrite, csBSelect);
+ INSTALL_HANDLER (StdRead, StdWrite, csCSelect);
+ INSTALL_HANDLER (StdRead, csDSelectWrite, csDSelect);
+
+ INSTALL_HANDLER (StdRead, StdWrite, emuCS);
+
+ INSTALL_HANDLER (StdRead, StdWrite, pllControl);
+ INSTALL_HANDLER (pllFreqSelRead, StdWrite, pllFreqSel);
+ INSTALL_HANDLER (StdRead, StdWrite, pwrControl);
+
+ INSTALL_HANDLER (StdRead, StdWrite, intVector);
+ INSTALL_HANDLER (StdRead, StdWrite, intControl);
+ INSTALL_HANDLER (StdRead, intMaskHiWrite, intMaskHi);
+ INSTALL_HANDLER (StdRead, intMaskLoWrite, intMaskLo);
+ INSTALL_HANDLER (StdRead, intStatusHiWrite, intStatusHi);
+ INSTALL_HANDLER (StdRead, NullWrite, intStatusLo);
+ INSTALL_HANDLER (StdRead, NullWrite, intPendingHi);
+ INSTALL_HANDLER (StdRead, NullWrite, intPendingLo);
+ INSTALL_HANDLER (StdRead, StdWrite, intLevelControl);
+
+ INSTALL_HANDLER (StdRead, StdWrite, portADir);
+ INSTALL_HANDLER (portXDataRead, portXDataWrite, portAData);
+ INSTALL_HANDLER (StdRead, StdWrite, portAPullupEn);
+
+ INSTALL_HANDLER (StdRead, StdWrite, portBDir);
+ INSTALL_HANDLER (portXDataRead, portXDataWrite, portBData);
+ INSTALL_HANDLER (StdRead, StdWrite, portBPullupEn);
+ INSTALL_HANDLER (StdRead, StdWrite, portBSelect);
+
+ INSTALL_HANDLER (StdRead, StdWrite, portCDir);
+ INSTALL_HANDLER (portXDataRead, portXDataWrite, portCData);
+ INSTALL_HANDLER (StdRead, StdWrite, portCPulldnEn);
+ INSTALL_HANDLER (StdRead, StdWrite, portCSelect);
+
+ INSTALL_HANDLER (StdRead, StdWrite, portDDir);
+ INSTALL_HANDLER (portXDataRead, portXDataWrite, portDData);
+ INSTALL_HANDLER (StdRead, StdWrite, portDPullupEn);
+ INSTALL_HANDLER (StdRead, StdWrite, portDSelect);
+ INSTALL_HANDLER (StdRead, StdWrite, portDPolarity);
+ INSTALL_HANDLER (StdRead, portDIntReqEnWrite, portDIntReqEn);
+ INSTALL_HANDLER (StdRead, StdWrite, portDKbdIntEn);
+ INSTALL_HANDLER (StdRead, StdWrite, portDIntEdge);
+
+ INSTALL_HANDLER (StdRead, StdWrite, portEDir);
+ INSTALL_HANDLER (portXDataRead, portXDataWrite, portEData);
+ INSTALL_HANDLER (StdRead, StdWrite, portEPullupEn);
+ INSTALL_HANDLER (StdRead, StdWrite, portESelect);
+
+ INSTALL_HANDLER (StdRead, StdWrite, portFDir);
+ INSTALL_HANDLER (portXDataRead, portXDataWrite, portFData);
+ INSTALL_HANDLER (StdRead, StdWrite, portFPullupdnEn);
+ INSTALL_HANDLER (StdRead, StdWrite, portFSelect);
+
+ INSTALL_HANDLER (StdRead, StdWrite, portGDir);
+ INSTALL_HANDLER (portXDataRead, portXDataWrite, portGData);
+ INSTALL_HANDLER (StdRead, StdWrite, portGPullupEn);
+ INSTALL_HANDLER (StdRead, StdWrite, portGSelect);
+
+ INSTALL_HANDLER (StdRead, StdWrite, portJDir);
+ INSTALL_HANDLER (portXDataRead, portXDataWrite, portJData);
+ INSTALL_HANDLER (StdRead, StdWrite, portJPullupEn);
+ INSTALL_HANDLER (StdRead, StdWrite, portJSelect);
+
+ INSTALL_HANDLER (StdRead, StdWrite, portKDir);
+ INSTALL_HANDLER (portXDataRead, portXDataWrite, portKData);
+ INSTALL_HANDLER (StdRead, StdWrite, portKPullupdnEn);
+ INSTALL_HANDLER (StdRead, StdWrite, portKSelect);
+
+ INSTALL_HANDLER (StdRead, StdWrite, portMDir);
+ INSTALL_HANDLER (portXDataRead, portXDataWrite, portMData);
+ INSTALL_HANDLER (StdRead, StdWrite, portMPullupdnEn);
+ INSTALL_HANDLER (StdRead, StdWrite, portMSelect);
+
+ INSTALL_HANDLER (StdRead, StdWrite, pwmControl);
+ INSTALL_HANDLER (StdRead, StdWrite, pwmSampleHi);
+ INSTALL_HANDLER (StdRead, StdWrite, pwmSampleLo);
+ INSTALL_HANDLER (StdRead, StdWrite, pwmPeriod);
+ INSTALL_HANDLER (StdRead, NullWrite, pwmCounter);
+
+ INSTALL_HANDLER (StdRead, StdWrite, pwm2Control);
+ INSTALL_HANDLER (StdRead, StdWrite, pwm2Period);
+ INSTALL_HANDLER (StdRead, StdWrite, pwm2Width);
+ INSTALL_HANDLER (StdRead, NullWrite, pwm2Counter);
+
+ INSTALL_HANDLER (StdRead, StdWrite, tmr1Control);
+ INSTALL_HANDLER (StdRead, StdWrite, tmr1Prescaler);
+ INSTALL_HANDLER (StdRead, StdWrite, tmr1Compare);
+ INSTALL_HANDLER (StdRead, StdWrite, tmr1Capture);
+ INSTALL_HANDLER (StdRead, NullWrite, tmr1Counter);
+ INSTALL_HANDLER (tmr1StatusRead, tmr1StatusWrite, tmr1Status);
+
+ INSTALL_HANDLER (StdRead, StdWrite, tmr2Control);
+ INSTALL_HANDLER (StdRead, StdWrite, tmr2Prescaler);
+ INSTALL_HANDLER (StdRead, StdWrite, tmr2Compare);
+ INSTALL_HANDLER (StdRead, StdWrite, tmr2Capture);
+ INSTALL_HANDLER (StdRead, NullWrite, tmr2Counter);
+ INSTALL_HANDLER (tmr2StatusRead, tmr2StatusWrite, tmr2Status);
+
+ INSTALL_HANDLER (StdRead, StdWrite, spiRxD);
+ INSTALL_HANDLER (StdRead, StdWrite, spiTxD);
+ INSTALL_HANDLER (StdRead, spiCont1Write, spiCont1);
+ INSTALL_HANDLER (StdRead, StdWrite, spiIntCS);
+ INSTALL_HANDLER (StdRead, StdWrite, spiTest);
+ INSTALL_HANDLER (StdRead, StdWrite, spiSpc);
+
+ INSTALL_HANDLER (StdRead, StdWrite, spiMasterData);
+ INSTALL_HANDLER (StdRead, spiMasterControlWrite, spiMasterControl);
+
+ INSTALL_HANDLER (uart1Read, uart1Write, uControl);
+ INSTALL_HANDLER (uart1Read, uart1Write, uBaud);
+ INSTALL_HANDLER (uart1Read, uart1Write, uReceive);
+ INSTALL_HANDLER (uart1Read, uart1Write, uTransmit);
+ INSTALL_HANDLER (uart1Read, uart1Write, uMisc);
+ INSTALL_HANDLER (uart1Read, uart1Write, uNonIntPresc);
+
+ INSTALL_HANDLER (uart2Read, uart2Write, u2Control);
+ INSTALL_HANDLER (uart2Read, uart2Write, u2Baud);
+ INSTALL_HANDLER (uart2Read, uart2Write, u2Receive);
+ INSTALL_HANDLER (uart2Read, uart2Write, u2Transmit);
+ INSTALL_HANDLER (uart2Read, uart2Write, u2Misc);
+ INSTALL_HANDLER (uart2Read, uart2Write, u2NonIntPresc);
+ INSTALL_HANDLER (uart2Read, uart2Write, u2FIFOHMark);
+
+ INSTALL_HANDLER (StdRead, lcdRegisterWrite, lcdStartAddr);
+ INSTALL_HANDLER (StdRead, lcdRegisterWrite, lcdPageWidth);
+ INSTALL_HANDLER (StdRead, lcdRegisterWrite, lcdScreenWidth);
+ INSTALL_HANDLER (StdRead, lcdRegisterWrite, lcdScreenHeight);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdCursorXPos);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdCursorYPos);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdCursorWidthHeight);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdBlinkControl);
+ INSTALL_HANDLER (StdRead, lcdRegisterWrite, lcdPanelControl);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdPolarity);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdACDRate);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdPixelClock);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdClockControl);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdRefreshRateAdj);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdPanningOffset);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdFrameRate);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdGrayPalette);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdContrastControlPWM);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdRefreshModeControl);
+ INSTALL_HANDLER (StdRead, StdWrite, lcdDMAControl);
+
+ INSTALL_HANDLER (rtcHourMinSecRead, StdWrite, rtcHourMinSec);
+ INSTALL_HANDLER (StdRead, StdWrite, rtcAlarm);
+ INSTALL_HANDLER (StdRead, StdWrite, rtcWatchDog);
+ INSTALL_HANDLER (StdRead, rtcControlWrite, rtcControl);
+ INSTALL_HANDLER (StdRead, rtcIntStatusWrite, rtcIntStatus);
+ INSTALL_HANDLER (StdRead, rtcIntEnableWrite, rtcIntEnable);
+ INSTALL_HANDLER (StdRead, StdWrite, stopWatch);
+ INSTALL_HANDLER (StdRead, StdWrite, rtcDay);
+ INSTALL_HANDLER (StdRead, StdWrite, rtcDayAlarm);
+
+ INSTALL_HANDLER (StdRead, StdWrite, dramConfig);
+ INSTALL_HANDLER (StdRead, StdWrite, dramControl);
+ INSTALL_HANDLER (StdRead, StdWrite, sdramControl);
+ INSTALL_HANDLER (StdRead, StdWrite, sdramPwDn);
+
+ INSTALL_HANDLER (StdRead, StdWrite, emuAddrCompare);
+ INSTALL_HANDLER (StdRead, StdWrite, emuAddrMask);
+ INSTALL_HANDLER (StdRead, StdWrite, emuControlCompare);
+ INSTALL_HANDLER (StdRead, StdWrite, emuControlMask);
+ INSTALL_HANDLER (StdRead, StdWrite, emuControl);
+ INSTALL_HANDLER (StdRead, StdWrite, emuStatus);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::GetRealAddress
+// ---------------------------------------------------------------------------
+
+uint8* EmRegsVZ::GetRealAddress (emuptr address)
+{
+ uint8* loc = ((uint8*) &f68VZ328Regs) + (address - kMemoryStart);
+
+ return loc;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::GetAddressStart
+// ---------------------------------------------------------------------------
+
+emuptr EmRegsVZ::GetAddressStart (void)
+{
+ return kMemoryStart;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::GetAddressRange
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsVZ::GetAddressRange (void)
+{
+ return kMemorySize;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::Cycle
+// ---------------------------------------------------------------------------
+// Handles periodic events that need to occur when the processor cycles (like
+// updating timer registers). This function is called in two places from
+// Emulator::Execute. Interestingly, the loop runs 3% FASTER if this function
+// is in its own separate function instead of being inline.
+
+void EmRegsVZ::Cycle (Bool sleeping)
+{
+#if _DEBUG
+ #define increment 20
+#else
+ #define increment 4
+#endif
+
+ // ===== Handle Timer 1 =====
+
+ // Determine whether timer is enabled.
+
+ if ((READ_REGISTER (tmr1Control) & hwrVZ328TmrControlEnable) != 0)
+ {
+ // If so, increment the timer.
+
+ WRITE_REGISTER (tmr1Counter, READ_REGISTER (tmr1Counter) + (sleeping ? 1 : increment));
+
+ // Determine whether the timer has reached the specified count.
+
+ if (sleeping || READ_REGISTER (tmr1Counter) > READ_REGISTER (tmr1Compare))
+ {
+ // Flag the occurrence of the successful comparison.
+
+ WRITE_REGISTER (tmr1Status, READ_REGISTER (tmr1Status) | hwrVZ328TmrStatusCompare);
+
+ // If the Free Run/Restart flag is not set, clear the counter.
+
+ if ((READ_REGISTER (tmr1Control) & hwrVZ328TmrControlFreeRun) == 0)
+ {
+ WRITE_REGISTER (tmr1Counter, 0);
+ }
+
+ // If the timer interrupt is enabled, post an interrupt.
+
+ if ((READ_REGISTER (tmr1Control) & hwrVZ328TmrControlEnInterrupt) != 0)
+ {
+ WRITE_REGISTER (intPendingLo, READ_REGISTER (intPendingLo) | hwrVZ328IntLoTimer);
+ EmRegsVZ::UpdateInterrupts ();
+ }
+ }
+ }
+
+ // ===== Handle Timer 2 =====
+ // ===== (Same code, just the name have been changed) =====
+
+ // Determine whether timer is enabled.
+
+#if 1
+ if ((READ_REGISTER (tmr2Control) & hwrVZ328TmrControlEnable) != 0)
+ {
+ // Divide by the prescale amount. We do this by decrementing
+ // a prescaler counter. Only when this counter reaches zero
+ // do we increment the timer counter.
+
+ static int prescaleCounter;
+
+ if ((prescaleCounter -= (sleeping ? (increment * 1024) : increment)) <= 0)
+ {
+ prescaleCounter = READ_REGISTER (tmr2Prescaler) * 1024;
+
+ // If so, increment the timer.
+
+ WRITE_REGISTER (tmr2Counter, READ_REGISTER (tmr2Counter) + (sleeping ? 1 : increment));
+
+ // Determine whether the timer has reached the specified count.
+
+ if (sleeping || READ_REGISTER (tmr2Counter) > READ_REGISTER (tmr2Compare))
+ {
+ // Flag the occurrence of the successful comparison.
+
+ WRITE_REGISTER (tmr2Status, READ_REGISTER (tmr2Status) | hwrVZ328TmrStatusCompare);
+
+ // If the Free Run/Restart flag is not set, clear the counter.
+
+ if ((READ_REGISTER (tmr2Control) & hwrVZ328TmrControlFreeRun) == 0)
+ {
+ WRITE_REGISTER (tmr2Counter, 0);
+ }
+
+ // If the timer interrupt is enabled, post an interrupt.
+
+ if ((READ_REGISTER (tmr2Control) & hwrVZ328TmrControlEnInterrupt) != 0)
+ {
+ WRITE_REGISTER (intPendingLo, READ_REGISTER (intPendingLo) | hwrVZ328IntLoTimer2);
+ EmRegsVZ::UpdateInterrupts ();
+ }
+ }
+ }
+ }
+#endif
+
+ // ===== Handle time increment (used when running Gremlins) =====
+
+ if ((fCycle += increment) > READ_REGISTER (tmr1Compare))
+ {
+ fCycle = 0;
+
+ if (++fTick >= 100)
+ {
+ fTick = 0;
+
+ if (++fSec >= 60)
+ {
+ fSec = 0;
+
+ if (++fMin >= 60)
+ {
+ fMin = 0;
+
+ if (++fHour >= 24)
+ {
+ fHour = 0;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::CycleSlowly
+// ---------------------------------------------------------------------------
+// Handles periodic events that need to occur when the processor cycles (like
+// updating timer registers). This function is called in two places from
+// Emulator::Execute. Interestingly, the loop runs 3% FASTER if this function
+// is in its own separate function instead of being inline.
+
+void EmRegsVZ::CycleSlowly (Bool sleeping)
+{
+ UNUSED_PARAM(sleeping)
+
+ // See if a hard button is pressed.
+
+ EmAssert (gSession);
+ if (gSession->HasButtonEvent ())
+ {
+ EmButtonEvent event = gSession->GetButtonEvent ();
+ if (event.fButton == kElement_CradleButton)
+ {
+ EmRegsVZ::HotSyncEvent (event.fButtonIsDown);
+ }
+ else
+ {
+ EmRegsVZ::ButtonEvent (event.fButton, event.fButtonIsDown);
+ }
+ }
+
+ // See if there's anything new ("Put the data on the bus")
+
+ EmRegsVZ::UpdateUARTState (false, 0);
+ EmRegsVZ::UpdateUARTState (false, 1);
+
+ // Check to see if the RTC alarm is ready to go off. First see
+ // if the RTC is enabled, and that the alarm event isn't already
+ // registered (the latter check is just an optimization).
+
+ if ((READ_REGISTER (rtcIntEnable) & hwrVZ328RTCIntEnableAlarm) != 0 &&
+ (READ_REGISTER (rtcIntStatus) & hwrVZ328RTCIntStatusAlarm) == 0)
+ {
+ uint32 rtcAlarm = READ_REGISTER (rtcAlarm);
+
+ long almHour = (rtcAlarm & hwrVZ328RTCAlarmHoursMask) >> hwrVZ328RTCAlarmHoursOffset;
+ long almMin = (rtcAlarm & hwrVZ328RTCAlarmMinutesMask) >> hwrVZ328RTCAlarmMinutesOffset;
+ long almSec = (rtcAlarm & hwrVZ328RTCAlarmSecondsMask) >> hwrVZ328RTCAlarmSecondsOffset;
+ long almInSeconds = (almHour * 60 * 60) + (almMin * 60) + almSec;
+
+ long nowHour;
+ long nowMin;
+ long nowSec;
+ ::GetHostTime (&nowHour, &nowMin, &nowSec);
+ long nowInSeconds = (nowHour * 60 * 60) + (nowMin * 60) + nowSec;
+
+ if (almInSeconds <= nowInSeconds)
+ {
+ WRITE_REGISTER (rtcIntStatus, READ_REGISTER (rtcIntStatus) | hwrVZ328RTCIntStatusAlarm);
+ EmRegsVZ::UpdateRTCInterrupts ();
+ }
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::TurnSoundOff
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::TurnSoundOff (void)
+{
+ uint16 pwmControl = READ_REGISTER (pwmControl);
+ WRITE_REGISTER (pwmControl, pwmControl & ~hwrVZ328PWMControlEnable);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::ResetTimer
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::ResetTimer (void)
+{
+ WRITE_REGISTER (tmr1Counter, 0);
+ WRITE_REGISTER (tmr2Counter, 0);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::ResetRTC
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::ResetRTC (void)
+{
+ fHour = 15;
+ fMin = 0;
+ fSec = 0;
+ fTick = 0;
+ fCycle = 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::GetInterruptLevel
+// ---------------------------------------------------------------------------
+
+int32 EmRegsVZ::GetInterruptLevel (void)
+{
+ /*
+ From the DragonBall VZ manual, Chapter 9:
+
+ * EMUIRQ or hardware breakpoint interrupt (level 7)
+
+ * IRQ6 external interrupt (level 6)
+ * Timer unit 1 (level 6)
+ * Timer unit 2 (configurable from level 1 to 6)
+ * Pulse-width modulator unit 1 (level 6)
+ * Pulse-width modulator unit 2 (configurable from level 1 to 6)
+
+ * IRQ5 external interrupt-pen (level 5)
+
+ * Serial peripheral interface unit 1 (configurable from level 1 to 6)
+ * Serial peripheral interface unit 2 (level 4)
+ * UART unit 1 (level 4)
+ * UART unit 2 (configurable from level 1 to 6)
+ * Software watchdog timer interrupt (level 4)
+ * Real-time clock (level 4)
+ * Real-time interrupt (level 4)
+ * Keyboard interrupt (level 4)
+ * General-purpose interrupt INT[3:0] (level 4)-these pins can be
+ used as keyboard interrupts
+
+ * IRQ3 external interrupt (level 3)
+ * IRQ2 external interrupt (level 2)
+ * IRQ1 external interrupt (level 1)
+ */
+
+ static int8 intLevel[32] =
+ {
+ 4, // 0x00 - hwrVZ328IntLoSPIM
+ 6, // 0x01 - hwrVZ328IntLoTimer
+ 4, // 0x02 - hwrVZ328IntLoUART
+ 4, // 0x03 - hwrVZ328IntLoWDT
+ 4, // 0x04 - hwrVZ328IntLoRTC
+ 0, // 0x05 - hwrVZ328IntLoTimer2 (configurable - 3 by default, reprogrammed to level 6)
+ 4, // 0x06 - hwrVZ328IntLoKbd
+ 6, // 0x07 - hwrVZ328IntLoPWM
+
+ 4, // 0x08 - hwrVZ328IntLoInt0
+ 4, // 0x09 - hwrVZ328IntLoInt1
+ 4, // 0x0A - hwrVZ328IntLoInt2
+ 4, // 0x0B - hwrVZ328IntLoInt3
+ 0, // 0x0C - hwrVZ328IntLoUART2 (configurable - 5 by default, reprogrammed to level 4)
+ 0, // 0x0D - PWM2 (configurable - 3 by default)
+ -2, // 0x0E - <Unused>
+ -2, // 0x0F - <Unused>
+
+ 1, // 0x10 - hwrVZ328IntHiIRQ1
+ 2, // 0x11 - hwrVZ328IntHiIRQ2
+ 3, // 0x12 - hwrVZ328IntHiIRQ3
+ 6, // 0x13 - hwrVZ328IntHiIRQ6
+ 5, // 0x14 - hwrVZ328IntHiPen
+ 0, // 0x15 - SPI1 (configurable - 6 by default)
+ 4, // 0x16 - hwrVZ328IntHiSampleTimer
+ 7, // 0x17 - hwrVZ328IntHiEMU
+
+ -2, // 0x18 - <Unused>
+ -2, // 0x19 - <Unused>
+ -2, // 0x1A - <Unused>
+ -2, // 0x1B - <Unused>
+ -2, // 0x1C - <Unused>
+ -2, // 0x1D - <Unused>
+ -2, // 0x1E - <Unused>
+ -2 // 0x1F - <Unused>
+ };
+
+ // Load in the configurable interrupt levels.
+
+ uint16 intLevelControl = READ_REGISTER (intLevelControl);
+
+ intLevel[0x15] = (intLevelControl >> 12) & 0x000F;
+ intLevel[0x0C] = (intLevelControl >> 8) & 0x000F;
+ intLevel[0x0D] = (intLevelControl >> 4) & 0x000F;
+ intLevel[0x05] = (intLevelControl >> 0) & 0x000F;
+
+ // !!! HACK: Skywalker sets the interrupt level to zero in order
+ // to clear it out before setting it to six. Zero is not allowed,
+ // so mask the problem by replacing it with six.
+
+ if (intLevel[0x05] == 0)
+ intLevel[0x05] = 6;
+
+#ifndef NDEBUG
+ for (int ii = 0; ii < 32; ++ii)
+ {
+ EmAssert (intLevel[ii] != 0);
+ EmAssert (intLevel[ii] != 7 || ii == 0x17);
+ }
+#endif
+
+ // Find the highest interrupt level.
+
+ int8 result = -1;
+ int index = 0;
+
+ uint16 intStatusHi = READ_REGISTER (intStatusHi);
+ uint16 intStatusLo = READ_REGISTER (intStatusLo);
+ uint32 intStatus = (((uint32) intStatusHi) << 16) | intStatusLo;
+
+ while (intStatus)
+ {
+ if (intStatus & 1)
+ {
+ // Make sure no undefined bits are set.
+ EmAssert (intLevel[index] >= 0);
+
+ if (result < intLevel[index])
+ {
+ result = intLevel[index];
+ }
+ }
+
+ intStatus >>= 1;
+ index++;
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::GetInterruptBase
+// ---------------------------------------------------------------------------
+
+int32 EmRegsVZ::GetInterruptBase (void)
+{
+ return READ_REGISTER (intVector) & 0xF8;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::GetLCDHasFrame
+// ---------------------------------------------------------------------------
+
+Bool EmRegsVZ::GetLCDHasFrame (void)
+{
+ return false;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::GetLCDBeginEnd
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::GetLCDBeginEnd (emuptr& begin, emuptr& end)
+{
+ emuptr baseAddr = READ_REGISTER (lcdStartAddr);
+ int rowBytes = READ_REGISTER (lcdPageWidth) * 2;
+ int height = READ_REGISTER (lcdScreenHeight) + 1;
+
+ begin = baseAddr;
+ end = baseAddr + rowBytes * height;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::GetLCDScanlines
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::GetLCDScanlines (EmScreenUpdateInfo& info)
+{
+ // Get the screen metrics.
+
+ int32 bpp = 1 << (READ_REGISTER (lcdPanelControl) & 0x03);
+ int32 width = READ_REGISTER (lcdScreenWidth);
+ int32 height = READ_REGISTER (lcdScreenHeight) + 1;
+ int32 rowBytes = READ_REGISTER (lcdPageWidth) * 2;
+ emuptr baseAddr = READ_REGISTER (lcdStartAddr);
+
+ info.fLeftMargin = READ_REGISTER (lcdPanningOffset) & 0x0F;
+
+ EmPixMapFormat format = bpp == 1 ? kPixMapFormat1 :
+ bpp == 2 ? kPixMapFormat2 :
+ bpp == 4 ? kPixMapFormat4 :
+ kPixMapFormat8;
+
+ RGBList colorTable;
+ this->PrvGetPalette (colorTable);
+
+ // Set format, size, and color table of EmPixMap.
+
+ info.fImage.SetSize (EmPoint (width, height));
+ info.fImage.SetFormat (format);
+ info.fImage.SetRowBytes (rowBytes);
+ info.fImage.SetColorTable (colorTable);
+
+ // Determine first and last scanlines to fetch, and fetch them.
+
+ info.fFirstLine = (info.fScreenLow - baseAddr) / rowBytes;
+ info.fLastLine = (info.fScreenHigh - baseAddr - 1) / rowBytes + 1;
+
+ long firstLineOffset = info.fFirstLine * rowBytes;
+ long lastLineOffset = info.fLastLine * rowBytes;
+
+ EmMem_memcpy (
+ (void*) ((uint8*) info.fImage.GetBits () + firstLineOffset),
+ baseAddr + firstLineOffset,
+ lastLineOffset - firstLineOffset);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::GetDynamicHeapSize
+// ---------------------------------------------------------------------------
+
+int32 EmRegsVZ::GetDynamicHeapSize (void)
+{
+ int32 result = 0;
+
+ uint16 csControl = READ_REGISTER (csControl1);
+ uint16 csDSelect = READ_REGISTER (csDSelect);
+
+ uint16 csDUPSIZ = (csDSelect & UPSIZMask) >> UPSIZShift;
+ uint16 csDSIZ = (csDSelect & SIZMask) >> SIZShift;
+
+ if ((csControl & EUPENMask) != 0)
+ {
+ // Unprotected size = Chip-select Size/2^(7-upsize)
+
+ // Determine upsize.
+
+ // Merge in the extended bit. UPSIZ contains [1:0]. The bit
+ // in DUPS2 extends this to [2:0].
+
+ csDUPSIZ |= ((csControl & DUPS2Mask) >> DUPS2Shift) << 2;
+
+ // Determine Chip-select Size.
+
+ long chip_select_size = (32 * 1024L) << csDSIZ;
+
+ if ((csControl & DSIZ3Mask) != 0 &&
+ (csDSelect & DRAMMask) != 0 &&
+ csDSIZ <= 0x01)
+ {
+ chip_select_size = (8 * 1024L * 1024L) << csDSIZ;
+ }
+
+ result = chip_select_size / (1 << (7 - csDUPSIZ));
+ }
+ else
+ {
+ result = (32 * 1024L) << csDUPSIZ;
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::GetROMSize
+// ---------------------------------------------------------------------------
+
+int32 EmRegsVZ::GetROMSize (void)
+{
+ /*
+ SIZ Chip-Select Size
+
+ This field determines the memory range of the chip-select. For CSA
+ and CSB, chip-select size is between 128K and 16M. For CSC and CSD,
+ chip-select size is between 32K and 4M.
+
+ 000 = 128K (32K for CSC and CSD).
+ 001 = 256K (64K for CSC and CSD).
+ 010 = 512K (128K for CSC and CSD).
+ 011 = 1M (256K for CSC and CSD).
+ 100 = 2M (512K for CSC and CSD).
+ 101 = 4M (1M for CSC and CSD).
+ 110 = 8M (2M for CSC and CSD).
+ 111 = 16M (4M for CSC and CSD).
+ */
+
+ uint16 csASelect = READ_REGISTER (csASelect);
+ uint32 result = (128 * 1024L) << ((csASelect & SIZMask) >> SIZShift);
+
+ if ((csASelect & ENMask) == 0)
+ {
+ result = 16 * 1024L * 1024L;
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::GetROMBaseAddress
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsVZ::GetROMBaseAddress (void)
+{
+ /*
+ csAGroupBase: Chip-select Group Base Address register
+
+ The csAGroupBase register stores the base address (bits 14-28 of
+ the address) in the top 15 bits. The low bit is always zero.
+ Shifting this value by 13 gives the ROM base address.
+
+ E.g: If the base address is 0x10C00000, then csAGroupBase will
+ contain 0x10C00000 >> 13 (base 10) = 0x8600.
+
+ If the enable bit of the CSA register is low, the chip selects
+ have not yet been set up. In this case, return an invalid value.
+ */
+
+ if (!this->ChipSelectsConfigured())
+ {
+ return 0xFFFFFFFF;
+ }
+
+ uint16 csAGroupBase = READ_REGISTER (csAGroupBase);
+ uint32 result = csAGroupBase << kBaseAddressShift;
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::ChipSelectsConfigured
+// ---------------------------------------------------------------------------
+
+Bool EmRegsVZ::ChipSelectsConfigured (void)
+{
+ return READ_REGISTER (csASelect) & ENMask;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::GetSystemClockFrequency
+// ---------------------------------------------------------------------------
+
+int32 EmRegsVZ::GetSystemClockFrequency (void)
+{
+ uint16 pllControl = READ_REGISTER (pllControl);
+ uint16 pllFreqSel = READ_REGISTER (pllFreqSel);
+
+ // Convert the 32.768KHz clock (CLK32) into the PLLCLK frequency.
+
+ uint16 PC = (pllFreqSel & 0x00FF);
+ uint16 QC = (pllFreqSel & 0x0F00) >> 8;
+
+ uint32 result = 32768L * 2 * (14 * (PC + 1) + QC + 1);
+
+ // Divide by the first prescaler, if needed.
+
+ if ((pllControl & hwrVZ328PLLControlPreSc1Div2) != 0)
+ {
+ result /= 2;
+ }
+
+ // Divide by the second prescaler, if needed.
+
+ if ((pllControl & hwrVZ328PLLControlPreSc2Div2) != 0)
+ {
+ result /= 2;
+ }
+
+ // Divide by the system clock scaler, if needed.
+
+ switch (pllControl & 0x0F00)
+ {
+ case hwrVZ328PLLControlSysDMADiv2:
+ result /= 2;
+ break;
+
+ case hwrVZ328PLLControlSysDMADiv4:
+ result /= 4;
+ break;
+
+ case hwrVZ328PLLControlSysDMADiv8:
+ result /= 8;
+ break;
+
+ case hwrVZ328PLLControlSysDMADiv16:
+ result /= 16;
+ break;
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::GetCanStop
+// ---------------------------------------------------------------------------
+
+Bool EmRegsVZ::GetCanStop (void)
+{
+ // Make sure Timer is enabled or the RTC interrupt is enabled.
+
+ if ((READ_REGISTER (tmr1Control) & hwrVZ328TmrControlEnable) != 0)
+ return true;
+
+ if ((READ_REGISTER (tmr2Control) & hwrVZ328TmrControlEnable) != 0)
+ return true;
+
+ if ((READ_REGISTER (rtcIntEnable) & hwrVZ328RTCIntEnableAlarm) != 0)
+ return true;
+
+ return false;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::GetAsleep
+// ---------------------------------------------------------------------------
+
+Bool EmRegsVZ::GetAsleep (void)
+{
+ return ((READ_REGISTER (pllControl) & hwrVZ328PLLControlDisable) != 0);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::GetPortInputValue
+// ---------------------------------------------------------------------------
+// Return the GPIO values for the pins on the port. These values are used
+// if the select pins are high.
+
+uint8 EmRegsVZ::GetPortInputValue (int port)
+{
+ uint8 result = 0;
+
+ if (port == 'D')
+ {
+ result = this->GetPortInternalValue (port);
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::GetPortInternalValue
+// ---------------------------------------------------------------------------
+// Return the dedicated values for the pins on the port. These values are
+// used if the select pins are low.
+
+uint8 EmRegsVZ::GetPortInternalValue (int port)
+{
+ uint8 result = 0;
+
+ if (port == 'D')
+ {
+ // Get the INT bits that need to be set.
+
+ result = this->GetKeyBits ();
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::PortDataChanged
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::PortDataChanged (int port, uint8, uint8 newValue)
+{
+ if (port == 'D')
+ {
+ // Clear the interrupt bits that are having a 1 written to them.
+ // Only clear them if they're configured as edge-senstive.
+
+ uint8 portDIntEdge = READ_REGISTER (portDIntEdge);
+
+ PRINTF ("EmRegsVZ::PortDataChanged (D): fPortDEdge = 0x%02lX", (uint32) (uint8) fPortDEdge);
+ PRINTF ("EmRegsVZ::PortDataChanged (D): portDIntEdge = 0x%02lX", (uint32) (uint8) portDIntEdge);
+ PRINTF ("EmRegsVZ::PortDataChanged (D): newValue = 0x%02lX", (uint32) (uint8) newValue);
+
+ fPortDEdge &= ~(newValue & portDIntEdge);
+
+ PRINTF ("EmRegsVZ::PortDataChanged (D): fPortDEdge = 0x%02lX", (uint32) (uint8) fPortDEdge);
+
+ // Set the new interrupt state.
+
+ EmRegsVZ::UpdatePortDInterrupts ();
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::pllFreqSelRead
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsVZ::pllFreqSelRead (emuptr address, int size)
+{
+ // Simulate the rising and falling of the CLK32 signal so that functions
+ // like HwrPreRAMInit, HwrShutDownPLL, PrvSetPLL, and PrvShutDownPLL
+ // won't hang.
+
+ uint16 pllFreqSel = READ_REGISTER (pllFreqSel) ^ 0x8000;
+ WRITE_REGISTER (pllFreqSel, pllFreqSel);
+
+ // Finish up by doing a standard read.
+
+ return EmRegsVZ::StdRead (address, size);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::portXDataRead
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsVZ::portXDataRead (emuptr address, int)
+{
+ // The value read can come from three different places:
+ //
+ // - the value what was written to the data register
+ // - any dedicated inputs
+ // - any GPIO inputs
+ //
+ // The value returned depends on the settings of the SEL and DIR
+ // registers. So let's get those settings, the values from the three
+ // input sources, and build up a return value based on those.
+
+ int port = GetPort (address);
+
+ uint8 sel = StdRead (address + 2, 1);
+ uint8 dir = StdRead (address - 1, 1);
+ uint8 output = StdRead (address + 0, 1);
+ uint8 input = EmHAL::GetPortInputValue (port);
+ uint8 intFn = EmHAL::GetPortInternalValue (port);
+
+ if (port == 'D')
+ {
+ sel |= 0x0F; // No "select" bit in low nybble, so set for IO values.
+
+ // The system will poll portD 18 times in KeyBootKeys to see
+ // if any keys are down. Wait at least that long before
+ // letting up any boot keys maintained by the session. When we
+ // do call ReleaseBootKeys, set our counter to -1 as a flag not
+ // to call it any more.
+
+ if (fPortDDataCount != 0xFFFFFFFF && ++fPortDDataCount >= 18 * 2)
+ {
+ fPortDDataCount = 0xFFFFFFFF;
+ gSession->ReleaseBootKeys ();
+ }
+ }
+
+ // Use the internal chip function bits if the "sel" bits are zero.
+
+ intFn &= ~sel;
+
+ // Otherwise, use the I/O bits.
+
+ output &= sel & dir; // Use the output bits if the "dir" is one.
+ input &= sel & ~dir; // Use the input bits if the "dir" is zero.
+
+ // Assert that there are no overlaps.
+
+ EmAssert ((output & input) == 0);
+ EmAssert ((output & intFn) == 0);
+ EmAssert ((input & intFn) == 0);
+
+ // Mush everything together.
+
+ uint8 result = output | input | intFn;
+
+ // If this is port D, flip the bits if the POLARITY register says to.
+ // (!!! Does this inversion apply only to input bits? That is, the
+ // bits where the "dir" register has 0 bits?)
+
+ if (0 && port == 'D')
+ {
+ uint8 polarity = READ_REGISTER (portDPolarity);
+ PRINTF ("EmRegsVZ::portXDataRead: polarity = 0x%02lX", (uint32) polarity);
+ result ^= polarity;
+ }
+
+ PRINTF ("EmRegsVZ::port%cDataRead: sel dir output input intFn result", (char) port);
+ PRINTF ("EmRegsVZ::port%cDataRead: 0x%02lX 0x%02lX 0x%02lX 0x%02lX 0x%02lX 0x%02lX",
+ (char) port, (uint32) sel, (uint32) dir, (uint32) output, (uint32) input, (uint32) intFn, (uint32) result);
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::tmr1StatusRead
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsVZ::tmr1StatusRead (emuptr address, int size)
+{
+ uint16 tmr1Counter = READ_REGISTER (tmr1Counter) + 16;
+ uint16 tmr1Compare = READ_REGISTER (tmr1Compare);
+ uint16 tmr1Control = READ_REGISTER (tmr1Control);
+
+ // Increment the timer.
+
+ WRITE_REGISTER (tmr1Counter, tmr1Counter);
+
+ // If the timer has passed the specified value...
+
+ if ((tmr1Counter - tmr1Compare) < 16)
+ {
+ // Set the flag saying the timer timed out.
+
+ uint16 tmr1Status = READ_REGISTER (tmr1Status) | hwrVZ328TmrStatusCompare;
+ WRITE_REGISTER (tmr1Status, tmr1Status);
+
+ // If it's not a free-running timer, reset it to zero.
+
+ if ((tmr1Control & hwrVZ328TmrControlFreeRun) == 0)
+ {
+ WRITE_REGISTER (tmr1Counter, 0);
+ }
+ }
+
+ // Remember this guy for later (see EmRegsVZ::tmr1StatusWrite())
+
+ fLastTmr1Status |= READ_REGISTER (tmr1Status);
+
+ // Finish up by doing a standard read.
+
+ return EmRegsVZ::StdRead (address, size);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::tmr2StatusRead
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsVZ::tmr2StatusRead (emuptr address, int size)
+{
+ uint16 tmr2Counter = READ_REGISTER (tmr2Counter) + 16;
+ uint16 tmr2Compare = READ_REGISTER (tmr2Compare);
+ uint16 tmr2Control = READ_REGISTER (tmr2Control);
+
+ // Increment the timer.
+
+ WRITE_REGISTER (tmr2Counter, tmr2Counter);
+
+ // If the timer has passed the specified value...
+
+ if ((tmr2Counter - tmr2Compare) < 16)
+ {
+ // Set the flag saying the timer timed out.
+
+ uint16 tmr2Status = READ_REGISTER (tmr2Status) | hwrVZ328TmrStatusCompare;
+ WRITE_REGISTER (tmr2Status, tmr2Status);
+
+ // If it's not a free-running timer, reset it to zero.
+
+ if ((tmr2Control & hwrVZ328TmrControlFreeRun) == 0)
+ {
+ WRITE_REGISTER (tmr2Counter, 0);
+ }
+ }
+
+ // Remember this guy for later (see EmRegsVZ::tmr2StatusWrite())
+
+ fLastTmr2Status |= READ_REGISTER (tmr2Status);
+
+ // Finish up by doing a standard read.
+
+ return EmRegsVZ::StdRead (address, size);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::uart1Read
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsVZ::uart1Read (emuptr address, int size)
+{
+ // If this is a full read, get the next byte from the FIFO.
+
+ Bool refreshRxData = (address == addressof (uReceive)) && (size == 2);
+
+ // See if there's anything new ("Put the data on the bus")
+
+ EmRegsVZ::UpdateUARTState (refreshRxData, 0);
+
+ // Finish up by doing a standard read.
+
+ return EmRegsVZ::StdRead (address, size);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::uart2Read
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsVZ::uart2Read (emuptr address, int size)
+{
+ // If this is a full read, get the next byte from the FIFO.
+
+ Bool refreshRxData = (address == addressof (u2Receive)) && (size == 2);
+
+ // See if there's anything new ("Put the data on the bus")
+
+ EmRegsVZ::UpdateUARTState (refreshRxData, 1);
+
+ // Finish up by doing a standard read.
+
+ return EmRegsVZ::StdRead (address, size);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::rtcHourMinSecRead
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsVZ::rtcHourMinSecRead (emuptr address, int size)
+{
+ // Get the desktop machine's time.
+
+ long hour, min, sec;
+
+ if (Hordes::IsOn ())
+ {
+ hour = fHour;
+ min = fMin;
+ sec = fSec;
+ }
+ else
+ {
+ ::GetHostTime (&hour, &min, &sec);
+ }
+
+ // Update the register.
+
+ WRITE_REGISTER (rtcHourMinSec, (hour << hwrVZ328RTCHourMinSecHoursOffset)
+ | (min << hwrVZ328RTCHourMinSecMinutesOffset)
+ | (sec << hwrVZ328RTCHourMinSecSecondsOffset));
+
+ // Finish up by doing a standard read.
+
+ return EmRegsVZ::StdRead (address, size);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::csControl1Write
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::csControl1Write (emuptr address, int size, uint32 value)
+{
+ // Get the current value.
+
+ uint16 csControl = READ_REGISTER (csControl1);
+
+ // Do a standard update of the register.
+
+ EmRegsVZ::StdWrite (address, size, value);
+
+ // Check to see if the unprotected memory range changed.
+
+ const uint16 bits = EUPENMask | DSIZ3Mask | DUPS2Mask;
+
+ if ((csControl & bits) != (READ_REGISTER (csControl1) & bits))
+ {
+ EmAssert (gSession);
+
+ gSession->ScheduleResetBanks ();
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::csASelectWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::csASelectWrite (emuptr address, int size, uint32 value)
+{
+ // Get the current value.
+
+ uint16 csASelect = READ_REGISTER (csASelect);
+
+ // Do a standard update of the register.
+
+ EmRegsVZ::StdWrite (address, size, value);
+
+ // Check to see if the unprotected memory range changed.
+
+ if ((csASelect & SIZMask) != (READ_REGISTER (csASelect) & SIZMask))
+ {
+ EmAssert (gSession);
+
+ gSession->ScheduleResetBanks ();
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::csDSelectWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::csDSelectWrite (emuptr address, int size, uint32 value)
+{
+ // Get the current value.
+
+ uint16 csDSelect = READ_REGISTER (csDSelect);
+
+ // Do a standard update of the register.
+
+ EmRegsVZ::StdWrite (address, size, value);
+
+ // Check its new state and update our ram-protect flag.
+
+ gMemAccessFlags.fProtect_SRAMSet = (READ_REGISTER (csDSelect) & 0x2000) != 0;
+
+ // Check to see if the unprotected memory range changed.
+
+ if ((csDSelect & UPSIZMask) != (READ_REGISTER (csDSelect) & UPSIZMask))
+ {
+ EmAssert (gSession);
+
+ gSession->ScheduleResetBanks ();
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::intMaskHiWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::intMaskHiWrite (emuptr address, int size, uint32 value)
+{
+ // Do a standard update of the register.
+
+ EmRegsVZ::StdWrite (address, size, value);
+
+ // Respond to the new interrupt state.
+
+ EmRegsVZ::UpdateInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::intMaskLoWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::intMaskLoWrite (emuptr address, int size, uint32 value)
+{
+ // Do a standard update of the register.
+
+ EmRegsVZ::StdWrite (address, size, value);
+
+ // Respond to the new interrupt state.
+
+ EmRegsVZ::UpdateInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::intStatusHiWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::intStatusHiWrite (emuptr address, int size, uint32 value)
+{
+ // IRQ1, IRQ2, IRQ3, IRQ6 and IRQ7 are cleared by writing to their
+ // respective status bits. We handle those there. Since there are
+ // no interrupt status bits like this in intStatusLo, we don't need
+ // a handler for that register; we only handle intStatusHi.
+
+ // Even though this is a 16-bit register as defined by the Palm headers,
+ // it's a 32-bit register according to DragonballVZ docs, and is in fact
+ // accessed that way in the kernal files (cf. HwrIRQ4Handler). In those
+ // cases, we're still only interested in access to the IRQ# bits, so we
+ // can turn 4-byte accesses into 2-byte accesses.
+
+ if (size == 4)
+ value >>= 16;
+
+ // Take into account the possibility of 1-byte accesses, too. If we're
+ // accessing the upper byte, just return. If we're accessing the lower
+ // byte, we can treat it as a 2-byte access.
+
+ else if (size == 1 && address == addressof (intStatusHi))
+ return;
+
+ // Now we can treat the rest of this function as a word-write to intStatusHi.
+
+ uint16 intPendingHi = READ_REGISTER (intPendingHi);
+
+ // For each interrupt:
+ // If we're writing to that interrupt's status bit and its edge bit is set:
+ // - clear the interrupt's pending bit
+ // - respond to the new interrupt state.
+
+ #undef CLEAR_PENDING_INTERRUPT
+ #define CLEAR_PENDING_INTERRUPT(edge, irq) \
+ if ((READ_REGISTER (intControl) & edge) && (value & (irq))) \
+ { \
+ intPendingHi &= ~(irq); \
+ }
+
+ CLEAR_PENDING_INTERRUPT (hwrVZ328IntCtlEdge1, hwrVZ328IntHiIRQ1);
+ CLEAR_PENDING_INTERRUPT (hwrVZ328IntCtlEdge2, hwrVZ328IntHiIRQ2);
+ CLEAR_PENDING_INTERRUPT (hwrVZ328IntCtlEdge3, hwrVZ328IntHiIRQ3);
+ CLEAR_PENDING_INTERRUPT (hwrVZ328IntCtlEdge6, hwrVZ328IntHiIRQ6);
+
+ // IRQ7 is not edge-programmable, so clear it if we're merely writing to it.
+ // !!! Double check this for VZ!
+
+ if (value & hwrVZ328IntHiEMU)
+ {
+ intPendingHi &= ~(hwrVZ328IntHiEMU);
+ }
+
+ // If we're emulating the user pressing the hotsync button, make sure the
+ // interrupt stays asserted. (!!! Should we use the same technique for
+ // other buttons, too? It doesn't seem to be needed right now, but doing
+ // that may more closely mirror the hardware.)
+
+ if (fHotSyncButtonDown)
+ {
+ intPendingHi |= hwrVZ328IntHiIRQ1;
+ }
+ else
+ {
+ intPendingHi &= ~hwrVZ328IntHiIRQ1;
+ }
+
+ // This makes the power on key work. If the signal is asserted, the
+ // unit will not transition between asleep and awake (cf. HwrSleep, HwrWake).
+
+ intPendingHi &= ~hwrVZ328IntHiIRQ6;
+
+ WRITE_REGISTER (intPendingHi, intPendingHi);
+ EmRegsVZ::UpdateInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::portXDataWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::portXDataWrite (emuptr address, int size, uint32 value)
+{
+ // Get the old value before updating it.
+
+ uint8 oldValue = StdRead (address, size);
+
+ // Take a snapshot of the line driver states.
+
+ Bool driverStates[kUARTEnd];
+ EmHAL::GetLineDriverStates (driverStates);
+
+ // Take a snapshot of the DTR pin.
+
+ Bool dtrOn = EmHAL::GetDTR (1);
+
+ // Now update the value with a standard write.
+
+ StdWrite (address, size, value);
+
+ // Let anyone know that it's changed.
+
+ int port = GetPort (address);
+ PRINTF ("EmRegsVZ::port%cDataWrite: oldValue = 0x%02lX", (char) port, (uint32) (uint8) oldValue);
+ PRINTF ("EmRegsVZ::port%cDataWrite: newValue = 0x%02lX", (char) port, (uint32) (uint8) value);
+
+ EmHAL::PortDataChanged (port, oldValue, value);
+
+ // Respond to any changes in the line driver states.
+
+ EmHAL::CompareLineDriverStates (driverStates);
+
+ // Respond to any change in the DTR pin.
+
+ if (EmHAL::GetDTR (1) != dtrOn)
+ {
+ EmHAL::DTRChanged (1);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::portDIntReqEnWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::portDIntReqEnWrite (emuptr address, int size, uint32 value)
+{
+ // Do a standard update of the register.
+
+ EmRegsVZ::StdWrite (address, size, value);
+
+ // Set the new interrupt state.
+
+ EmRegsVZ::UpdatePortDInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::tmr1StatusWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::tmr1StatusWrite (emuptr address, int size, uint32 value)
+{
+ UNUSED_PARAM(address)
+ UNUSED_PARAM(size)
+
+ EmAssert (size == 2); // This function's a hell of a lot easier to write if
+ // we assume only full-register access.
+
+ // Get the current value.
+
+ uint16 tmr1Status = READ_REGISTER (tmr1Status);
+
+ // If the user had previously read the status bits while they
+ // were set, then it's OK for them to be clear now. Otherwise,
+ // we have to merge any set status bits back in.
+
+ tmr1Status &= value | ~fLastTmr1Status; // fLastTmr1Status was set in EmRegsVZ::tmr1StatusRead()
+
+ WRITE_REGISTER (tmr1Status, tmr1Status);
+
+ fLastTmr1Status = 0;
+ if ((tmr1Status & hwrVZ328TmrStatusCompare) == 0)
+ {
+ uint16 intPendingLo = READ_REGISTER (intPendingLo) & ~hwrVZ328IntLoTimer;
+ WRITE_REGISTER (intPendingLo, intPendingLo);
+
+ // Respond to the new interrupt state.
+
+ EmRegsVZ::UpdateInterrupts ();
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::tmr2StatusWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::tmr2StatusWrite (emuptr address, int size, uint32 value)
+{
+ UNUSED_PARAM(address)
+ UNUSED_PARAM(size)
+
+ EmAssert (size == 2); // This function's a hell of a lot easier to write if
+ // we assume only full-register access.
+
+ // Get the current value.
+
+ uint16 tmr2Status = READ_REGISTER (tmr2Status);
+
+ // If the user had previously read the status bits while they
+ // were set, then it's OK for them to be clear now. Otherwise,
+ // we have to merge any set status bits back in.
+
+ tmr2Status &= value | ~fLastTmr2Status; // fLastTmr2Status was set in EmRegsVZ::tmr2StatusRead()
+
+ WRITE_REGISTER (tmr2Status, tmr2Status);
+
+ fLastTmr2Status = 0;
+ if ((tmr2Status & hwrVZ328TmrStatusCompare) == 0)
+ {
+ uint16 intPendingLo = READ_REGISTER (intPendingLo) & ~hwrVZ328IntLoTimer2;
+ WRITE_REGISTER (intPendingLo, intPendingLo);
+
+ // Respond to the new interrupt state.
+
+ EmRegsVZ::UpdateInterrupts ();
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::spiCont1Write
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::spiCont1Write (emuptr address, int size, uint32 value)
+{
+ // Do a standard update of the register.
+
+ EmRegsVZ::StdWrite (address, size, value);
+
+ // Get the current value.
+
+ uint16 spiCont1 = READ_REGISTER (spiCont1);
+
+ // Check to see if data exchange and enable are enabled.
+
+ #define BIT_MASK (hwrVZ328SPIMControlExchange | hwrVZ328SPIMControlEnable)
+ if ((spiCont1 & BIT_MASK) == BIT_MASK)
+ {
+ // Clear the exchange bit.
+
+ spiCont1 &= ~hwrVZ328SPIMControlExchange;
+
+ WRITE_REGISTER (spiCont1, spiCont1);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::spiMasterControlWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::spiMasterControlWrite (emuptr address, int size, uint32 value)
+{
+ // Do a standard update of the register.
+
+ EmRegsVZ::StdWrite (address, size, value);
+
+ // Get the current value.
+
+ uint16 spiMasterData = READ_REGISTER (spiMasterData);
+ uint16 spiMasterControl = READ_REGISTER (spiMasterControl);
+
+ // Check to see if data exchange and enable are enabled.
+
+ #define BIT_MASK (hwrVZ328SPIMControlExchange | hwrVZ328SPIMControlEnable)
+ if ((spiMasterControl & BIT_MASK) == BIT_MASK)
+ {
+ // If the SPI is hooked up to something, talk with it.
+
+ EmSPISlave* spiSlave = this->GetSPISlave ();
+ if (spiSlave)
+ {
+ // Write out the old data, read in the new data.
+
+ uint16 newData = spiSlave->DoExchange (spiMasterControl, spiMasterData);
+
+ // Shift in the new data.
+
+ uint16 numBits = (spiMasterControl & hwrVZ328SPIMControlBitsMask) + 1;
+
+ uint16 oldBitsMask = ~0 << numBits;
+ uint16 newBitsMask = ~oldBitsMask;
+
+ spiMasterData = /*((spiMasterData << numBits) & oldBitsMask) | */
+ (newData & newBitsMask);
+
+ WRITE_REGISTER (spiMasterData, spiMasterData);
+ }
+
+ // Assert the interrupt and clear the exchange bit.
+
+ spiMasterControl |= hwrVZ328SPIMControlIntStatus;
+ spiMasterControl &= ~hwrVZ328SPIMControlExchange;
+
+ WRITE_REGISTER (spiMasterControl, spiMasterControl);
+
+ // If hwrVZ328SPIMControlIntEnable is set, trigger an interrupt.
+
+ if ((spiMasterControl & hwrVZ328SPIMControlIntEnable) != 0)
+ {
+ uint16 intPendingLo = READ_REGISTER (intPendingLo);
+ intPendingLo |= hwrVZ328IntLoSPIM;
+ WRITE_REGISTER (intPendingLo, intPendingLo);
+ this->UpdateInterrupts ();
+ }
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::uart1Write
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::uart1Write(emuptr address, int size, uint32 value)
+{
+ // Do a standard update of the register.
+
+ EmRegsVZ::StdWrite (address, size, value);
+
+ // If this write included the TX_DATA field, signal that it needs to
+ // be transmitted.
+
+ Bool sendTxData =
+ ((address == addressof (uTransmit)) && (size == 2)) ||
+ ((address == addressof (uTransmit) + 1) && (size == 1));
+
+ // React to any changes.
+
+ EmRegsVZ::UARTStateChanged (sendTxData, 0);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::uart2Write
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::uart2Write(emuptr address, int size, uint32 value)
+{
+ // Do a standard update of the register.
+
+ EmRegsVZ::StdWrite (address, size, value);
+
+ // If this write included the TX_DATA field, signal that it needs to
+ // be transmitted.
+
+ Bool sendTxData =
+ ((address == addressof (u2Transmit)) && (size == 2)) ||
+ ((address == addressof (u2Transmit) + 1) && (size == 1));
+
+ // React to any changes.
+
+ EmRegsVZ::UARTStateChanged (sendTxData, 1);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::lcdRegisterWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::lcdRegisterWrite (emuptr address, int size, uint32 value)
+{
+ // First, get the old value in case we need to see what changed.
+
+ uint32 oldValue = EmRegsVZ::StdRead (address, size);
+
+ // Do a standard update of the register.
+
+ EmRegsVZ::StdWrite (address, size, value);
+
+ // Note what changed.
+
+ if (address == addressof (lcdScreenWidth))
+ {
+ EmScreen::InvalidateAll ();
+ }
+ else if (address == addressof (lcdScreenHeight))
+ {
+ EmScreen::InvalidateAll ();
+ }
+ else if (address == addressof (lcdPanelControl))
+ {
+ // hwrVZ328LcdPanelControlGrayScale is incorrectly defined as 0x01,
+ // so use the hard-coded value of 0x03 here.
+
+// if (((value ^ oldValue) & hwrVZ328LcdPanelControlGrayScale) != 0)
+ if (((value ^ oldValue) & 0x03) != 0)
+ {
+ EmScreen::InvalidateAll ();
+ }
+ }
+ else if (address == addressof (lcdStartAddr))
+ {
+ // Make sure the low-bit is always zero.
+ // Make sure bits 31-29 are always zero.
+
+ uint32 lcdStartAddr = READ_REGISTER (lcdStartAddr) & 0x1FFFFFFE;
+ WRITE_REGISTER (lcdStartAddr, lcdStartAddr);
+
+ EmScreen::InvalidateAll ();
+ }
+ else if (address == addressof (lcdPageWidth))
+ {
+ if (value != oldValue)
+ {
+ EmScreen::InvalidateAll ();
+ }
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::rtcControlWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::rtcControlWrite (emuptr address, int size, uint32 value)
+{
+ // Do a standard update of the register.
+
+ EmRegsVZ::StdWrite (address, size, value);
+
+ // Respond to the new interrupt state.
+
+ EmRegsVZ::UpdateRTCInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::rtcIntStatusWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::rtcIntStatusWrite (emuptr address, int size, uint32 value)
+{
+ // Status bits are cleared by writing ones to them.
+
+ // If we're doing a byte-write to the upper byte, shift the byte
+ // so that we can treat the operation as a word write. If we're
+ // doing a byte-write to the lower byte, this extension will happen
+ // automatically.
+
+ if (address == addressof (rtcIntStatus) && size == 1)
+ value <<= 8;
+
+ // Get the current value.
+
+ uint16 rtcIntStatus = READ_REGISTER (rtcIntStatus);
+
+ // Clear the requested bits.
+
+ rtcIntStatus &= ~value;
+
+ // Update the register.
+
+ WRITE_REGISTER (rtcIntStatus, rtcIntStatus);
+
+ // Respond to the new interrupt state.
+
+ EmRegsVZ::UpdateRTCInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::rtcIntEnableWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::rtcIntEnableWrite (emuptr address, int size, uint32 value)
+{
+ // Do a standard update of the register.
+
+ EmRegsVZ::StdWrite (address, size, value);
+
+ // Respond to the new interrupt state.
+
+ EmRegsVZ::UpdateRTCInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::ButtonEvent
+// ---------------------------------------------------------------------------
+// Handles a Palm device button event by updating the appropriate registers.
+
+void EmRegsVZ::ButtonEvent (SkinElementType button, Bool buttonIsDown)
+{
+ uint16 bitNumber = this->ButtonToBits (button);
+
+ // Get the bits that should have been set with the previous set
+ // of pressed keys. We use this old value to update the port D interrupts.
+
+ uint8 oldBits = this->GetKeyBits ();
+
+ // Update the set of keys that are currently pressed.
+
+ if (buttonIsDown)
+ {
+ fKeyBits |= bitNumber; // Remember the key bit
+ }
+ else
+ {
+ fKeyBits &= ~bitNumber; // Forget the key bit
+ }
+
+ // Now get the new set of bits that should be set.
+
+ uint8 newBits = this->GetKeyBits ();
+
+ PRINTF ("EmRegsVZ::ButtonEvent: fKeyBits = 0x%04lX", (uint32) fKeyBits);
+ PRINTF ("EmRegsVZ::ButtonEvent: oldBits = 0x%02lX", (uint32) oldBits);
+ PRINTF ("EmRegsVZ::ButtonEvent: newBits = 0x%02lX", (uint32) newBits);
+
+ // Set the interrupt bits for the bits that went from off to on.
+ // These get cleared when portDData is written to.
+
+ fPortDEdge |= newBits & ~oldBits;
+
+ PRINTF ("EmRegsVZ::ButtonEvent: fPortDEdge = 0x%02lX", (uint32) fPortDEdge);
+
+ // Set the new interrupt state.
+
+ EmRegsVZ::UpdatePortDInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::HotSyncEvent
+// ---------------------------------------------------------------------------
+// Handles a HotSync button event by updating the appropriate registers.
+
+void EmRegsVZ::HotSyncEvent (Bool buttonIsDown)
+{
+ // If the button changes state, set or clear the HotSync interrupt.
+
+ uint16 intPendingHi = READ_REGISTER (intPendingHi);
+
+ if (buttonIsDown)
+ {
+ intPendingHi |= hwrVZ328IntHiIRQ1;
+ fHotSyncButtonDown = true;
+ }
+ else
+ {
+ intPendingHi &= ~hwrVZ328IntHiIRQ1;
+ fHotSyncButtonDown = false;
+ }
+
+ WRITE_REGISTER (intPendingHi, intPendingHi);
+
+ EmRegsVZ::UpdateInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::GetKeyBits
+// ---------------------------------------------------------------------------
+
+uint8 EmRegsVZ::GetKeyBits (void)
+{
+ // "Keys" (that is, buttons) are read from the Port D Data register.
+ // There are 7 or 8 keys that can be pressed, but only 4 bits are
+ // available in the Port D Data register for reporting pressed keys.
+ // Therefore, the keys are organized into a matrix, one row or which
+ // can be requested and reported at a time. This function determines
+ // what row is being requested, and sets the appropriate Port D Data
+ // bits for the keys are are currently pressed.
+
+ int numRows;
+ int numCols;
+ uint16 keyMap[16];
+ Bool rows[4];
+
+ this->GetKeyInfo (&numRows, &numCols, keyMap, rows);
+
+ uint8 keyData = 0;
+
+ // Walk the rows, looking for one that is requested.
+
+ for (int row = 0; row < numRows; ++row)
+ {
+ if (rows[row])
+ {
+ // Walk the columns, looking for ones that have a pressed key.
+
+ for (int col = 0; col < numCols; ++col)
+ {
+ // Get the key corresponding to this row and column.
+ // If we've recorded (in fKeyBits) that this key is
+ // pressed, then set its column bit.
+
+ uint16 key = keyMap[row * numCols + col];
+ if ((key & fKeyBits) != 0)
+ {
+ keyData |= (1 << col);
+ }
+ }
+ }
+ }
+
+ return keyData;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::ButtonToBits
+// ---------------------------------------------------------------------------
+
+uint16 EmRegsVZ::ButtonToBits (SkinElementType button)
+{
+ uint16 bitNumber = 0;
+ switch (button)
+ {
+ case kElement_None: break;
+
+ case kElement_PowerButton: bitNumber = keyBitPower; break;
+ case kElement_UpButton: bitNumber = keyBitPageUp; break;
+ case kElement_DownButton: bitNumber = keyBitPageDown; break;
+ case kElement_App1Button: bitNumber = keyBitHard1; break;
+ case kElement_App2Button: bitNumber = keyBitHard2; break;
+ case kElement_App3Button: bitNumber = keyBitHard3; break;
+ case kElement_App4Button: bitNumber = keyBitHard4; break;
+ case kElement_CradleButton: bitNumber = keyBitCradle; break;
+ case kElement_Antenna: bitNumber = keyBitAntenna; break;
+ case kElement_ContrastButton: bitNumber = keyBitContrast; break;
+
+ default: EmAssert (false);
+ }
+
+ return bitNumber;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::GetSPISlave
+// ---------------------------------------------------------------------------
+
+EmSPISlave* EmRegsVZ::GetSPISlave (void)
+{
+ return NULL;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::UpdateInterrupts
+// ---------------------------------------------------------------------------
+// Determines whether an interrupt has occurred by copying the Interrupt
+// Pending Register to the Interrupt Status Register.
+
+void EmRegsVZ::UpdateInterrupts (void)
+{
+ // Copy the Interrupt Pending Register to the Interrupt Status
+ // Register, but ignore interrupts that are being masked.
+
+ // Note: this function is not sensitive to the byte ordering of the registers,
+ // so their contents don't need to be accessed via READ_REGISTER or WRITE_REGISTER.
+
+ f68VZ328Regs.intStatusHi = f68VZ328Regs.intPendingHi & ~f68VZ328Regs.intMaskHi;
+ f68VZ328Regs.intStatusLo = f68VZ328Regs.intPendingLo & ~f68VZ328Regs.intMaskLo;
+
+ PRINTF ("EmRegsVZ::UpdateInterrupts: intMask = 0x%04lX %04lX",
+ (uint32) f68VZ328Regs.intMaskHi, (uint32) f68VZ328Regs.intMaskLo);
+
+ PRINTF ("EmRegsVZ::UpdateInterrupts: intPending = 0x%04lX %04lX",
+ (uint32) f68VZ328Regs.intPendingHi, (uint32) f68VZ328Regs.intPendingLo);
+
+ // If the Interrupt Status Register isn't clear, flag an interrupt.
+
+ if (f68VZ328Regs.intStatusHi || f68VZ328Regs.intStatusLo)
+ {
+ regs.spcflags |= SPCFLAG_INT;
+
+ PRINTF ("EmRegsVZ::UpdateInterrupts: intStatus = 0x%04lX %04lX",
+ (uint32) f68VZ328Regs.intStatusHi, (uint32) f68VZ328Regs.intStatusLo);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::UpdatePortDInterrupts
+// ---------------------------------------------------------------------------
+// Determine what interrupts need to be generated based on the current
+// settings in portDData and fPortDEdge.
+
+void EmRegsVZ::UpdatePortDInterrupts (void)
+{
+ // Update INT0-INT3 of the Interrupt-Pending register (bits 8-11 of the low word).
+
+ // First, get those bits and clear them out.
+
+ uint16 intPendingLo = READ_REGISTER (intPendingLo) & ~hwrVZ328IntLoAllKeys;
+
+
+ // Initialize the variable to hold the new interrupt settings.
+
+ uint8 newBits = 0;
+
+
+ // Get some other values we're going to need:
+
+ uint8 portDDir = READ_REGISTER (portDDir); // Interrupt on inputs only (when pin is low)
+ uint8 portDData = EmHAL::GetPortInputValue ('D');
+ uint8 portDPolarity = READ_REGISTER (portDPolarity);
+ uint8 portDIntReqEn = READ_REGISTER (portDIntReqEn);
+ uint8 portDKbdIntEn = READ_REGISTER (portDKbdIntEn);
+ uint8 portDIntEdge = READ_REGISTER (portDIntEdge);
+
+ // We have a line-level interrupt if:
+ //
+ // - line-level interrupts are requested
+ // - the GPIO bit matches the polarity bit
+
+ newBits |= ~portDIntEdge & portDData & portDPolarity;
+ newBits |= ~portDIntEdge & ~portDData & ~portDPolarity;
+
+
+ // We have an edge interrupt if:
+ //
+ // - edge interrupts are requested
+ // - an edge has been recorded
+ //
+ // Note that we should distinguish between rising and falling edges.
+ // For historical reasons, that's not done, and the Palm OS doesn't
+ // look for them, so it's OK for now.
+ //
+ // Edge interrupts on INT[3:0] should not wake up a sleeping device.
+
+ uint16 pllControl = READ_REGISTER (pllControl);
+
+#if 0
+ if ((pllControl & hwrVZ328PLLControlDisable) && !(gSession->GetDevice ().EdgeHack ()))
+ {
+ newBits |= portDIntEdge & fPortDEdge & portDPolarity & 0xF0;
+ newBits |= portDIntEdge & 0 & ~portDPolarity & 0xF0;
+ }
+ else
+#endif
+ {
+ newBits |= portDIntEdge & fPortDEdge & portDPolarity;
+ newBits |= portDIntEdge & 0 & ~portDPolarity;
+ }
+
+
+ // Only have interrupts if they're enabled and the pin is configured for input.
+
+ newBits &= portDIntReqEn & ~portDDir;
+
+ PRINTF ("EmRegsVZ::UpdatePortDInterrupts: Dir Data Pol Req Edg PDE bits");
+ PRINTF ("EmRegsVZ::UpdatePortDInterrupts: 0x%02lX 0x%02lX 0x%02lX 0x%02lX 0x%02lX 0x%02lX 0x%02lX",
+ (uint32) portDDir, (uint32) portDData, (uint32) portDPolarity, (uint32) portDIntReqEn, (uint32) portDIntEdge,
+ (uint32) fPortDEdge, (uint32) newBits);
+
+
+ // Determine if the KB interrupt needs to be asserted. It is if:
+ //
+ // A Port D Data bit is on.
+ // The bit is configured for input (?)
+ // The bit is configured to be OR'd into the interrupt.
+
+ if (!gSession->GetDevice ().EdgeHack ())
+ {
+ uint8 KB = portDData & ~portDDir & portDKbdIntEn;
+
+ if (KB)
+ intPendingLo |= hwrVZ328IntLoKbd;
+ else
+ intPendingLo &= ~hwrVZ328IntLoKbd;
+ }
+
+
+ // Merge in the new values and write out the result.
+
+ intPendingLo |= (((uint16) newBits) << hwrVZ328IntLoInt0Bit) & hwrVZ328IntLoAllKeys;
+ WRITE_REGISTER (intPendingLo, intPendingLo);
+
+
+ // Respond to the new interrupt state.
+
+ EmRegsVZ::UpdateInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::UpdateRTCInterrupts
+// ---------------------------------------------------------------------------
+// Determine whether to set or clear the RTC bit in the interrupt pending
+// register based on the current RTC register values.
+
+void EmRegsVZ::UpdateRTCInterrupts (void)
+{
+ // See if the RTC is enabled.
+
+ Bool rtcEnabled = (READ_REGISTER (rtcControl) & hwrVZ328RTCControlRTCEnable) != 0;
+
+ // See if there are any RTC events that need to trigger an interrupt.
+
+#define BITS_TO_CHECK ( \
+ hwrVZ328RTCIntEnableSec | \
+ hwrVZ328RTCIntEnable24Hr | \
+ hwrVZ328RTCIntEnableAlarm | \
+ hwrVZ328RTCIntEnableMinute | \
+ hwrVZ328RTCIntEnableStopWatch )
+
+ uint16 rtcIntStatus = READ_REGISTER (rtcIntStatus);
+ uint16 rtcIntEnable = READ_REGISTER (rtcIntEnable);
+ uint16 rtcIntPending = rtcIntStatus & rtcIntEnable & BITS_TO_CHECK;
+
+ Bool havePendingEvents = rtcIntPending != 0;
+
+ // If the RTC is enabled and there are pending events, set the interrupt.
+ // Otherwise, clear the interrupt.
+
+ uint16 intPendingLo = READ_REGISTER (intPendingLo);
+
+ if (rtcEnabled && havePendingEvents)
+ {
+ intPendingLo |= hwrVZ328IntLoRTC; // have events, so set interrupt
+ }
+ else
+ {
+ intPendingLo &= ~hwrVZ328IntLoRTC; // no events, so clear interrupt
+ }
+
+ // Update the interrupt pending register.
+
+ WRITE_REGISTER (intPendingLo, intPendingLo);
+
+ // Respond to the new interrupt state.
+
+ EmRegsVZ::UpdateInterrupts ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::UARTStateChanged
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::UARTStateChanged (Bool sendTxData, int uartNum)
+{
+ EmUARTDragonball::State state (EmUARTDragonball::kUART_DragonballVZ);
+
+ EmRegsVZ::MarshalUARTState (state, uartNum);
+
+ fUART[uartNum]->StateChanged (state, sendTxData);
+
+ EmRegsVZ::UnmarshalUARTState (state, uartNum);
+
+ EmRegsVZ::UpdateUARTInterrupts (state, uartNum);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::UpdateUARTState
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::UpdateUARTState (Bool refreshRxData, int uartNum)
+{
+ EmUARTDragonball::State state (EmUARTDragonball::kUART_DragonballVZ);
+
+ EmRegsVZ::MarshalUARTState (state, uartNum);
+
+ fUART[uartNum]->UpdateState (state, refreshRxData);
+
+ EmRegsVZ::UnmarshalUARTState (state, uartNum);
+
+ EmRegsVZ::UpdateUARTInterrupts (state, uartNum);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::UpdateUARTInterrupts
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::UpdateUARTInterrupts (const EmUARTDragonball::State& state, int uartNum)
+{
+ // Generate the appropriate interrupts.
+
+ uint16 whichBit = uartNum == 0 ? hwrVZ328IntLoUART : hwrVZ328IntLoUART2;
+
+#if 0
+ LogAppendMsg ("UpdateUARTInterrupts for UART %d.", uartNum + 1);
+
+ if (uartNum == 1)
+ {
+ LogAppendMsg ("RX_FIFO_FULL: %s RX_FIFO_HALF: %s DATA_READY: %s",
+ state.RX_FIFO_FULL ? "ON " : "off",
+ state.RX_FIFO_HALF ? "ON " : "off",
+ state.DATA_READY ? "ON " : "off");
+
+ LogAppendMsg ("RX_FULL_ENABLE: %s RX_HALF_ENABLE: %s RX_RDY_ENABLE: %s",
+ state.RX_FULL_ENABLE ? "ON " : "off",
+ state.RX_HALF_ENABLE ? "ON " : "off",
+ state.RX_RDY_ENABLE ? "ON " : "off");
+
+ LogAppendMsg ("TX_FIFO_EMPTY: %s TX_FIFO_HALF: %s TX_AVAIL: %s",
+ state.TX_FIFO_EMPTY ? "ON " : "off",
+ state.TX_FIFO_HALF ? "ON " : "off",
+ state.TX_AVAIL ? "ON " : "off");
+
+ LogAppendMsg ("TX_EMPTY_ENABLE: %s TX_HALF_ENABLE: %s TX_AVAIL_ENABLE: %s",
+ state.TX_EMPTY_ENABLE ? "ON " : "off",
+ state.TX_HALF_ENABLE ? "ON " : "off",
+ state.TX_AVAIL_ENABLE ? "ON " : "off");
+ }
+#endif
+
+ if (state.RX_FULL_ENABLE && state.RX_FIFO_FULL ||
+ state.RX_HALF_ENABLE && state.RX_FIFO_HALF ||
+ state.RX_RDY_ENABLE && state.DATA_READY ||
+ state.TX_EMPTY_ENABLE && state.TX_FIFO_EMPTY ||
+ state.TX_HALF_ENABLE && state.TX_FIFO_HALF ||
+ state.TX_AVAIL_ENABLE && state.TX_AVAIL)
+ {
+ // Set the UART interrupt.
+
+ WRITE_REGISTER (intPendingLo, READ_REGISTER (intPendingLo) | whichBit);
+#if 0
+ if (uartNum == 1)
+ {
+ LogAppendMsg ("Setting UART %d interrupt.", uartNum + 1);
+ }
+#endif
+ }
+ else
+ {
+ // Clear the UART interrupt.
+
+ WRITE_REGISTER (intPendingLo, READ_REGISTER (intPendingLo) & ~whichBit);
+#if 0
+ if (uartNum == 1)
+ {
+ LogAppendMsg ("Clearing UART %d interrupt.", uartNum + 1);
+ }
+#endif
+ }
+
+ // Respond to the new interrupt state.
+
+ EmRegsVZ::UpdateInterrupts ();
+
+#if 0
+ if (uartNum == 1)
+ {
+ LogAppendMsg ("intPending = 0x%04lX %04lX",
+ (uint32) f68VZ328Regs.intPendingHi,
+ (uint32) f68VZ328Regs.intPendingLo);
+
+ LogAppendMsg ("intMask = 0x%04lX %04lX",
+ (uint32) f68VZ328Regs.intMaskHi,
+ (uint32) f68VZ328Regs.intMaskLo);
+
+ LogAppendMsg ("intStatus = 0x%04lX %04lX",
+ (uint32) f68VZ328Regs.intStatusHi,
+ (uint32) f68VZ328Regs.intStatusLo);
+ }
+#endif
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::MarshalUARTState
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::MarshalUARTState (EmUARTDragonball::State& state, int uartNum)
+{
+ uint16 uControl;
+ uint16 uBaud;
+ uint16 uReceive;
+ uint16 uTransmit;
+ uint16 uMisc;
+ uint16 uLevel;
+
+ if (uartNum == 0)
+ {
+ uControl = READ_REGISTER (uControl);
+ uBaud = READ_REGISTER (uBaud);
+ uReceive = READ_REGISTER (uReceive);
+ uTransmit = READ_REGISTER (uTransmit);
+ uMisc = READ_REGISTER (uMisc);
+ uLevel = 0;
+ }
+ else
+ {
+ uControl = READ_REGISTER (u2Control);
+ uBaud = READ_REGISTER (u2Baud);
+ uReceive = READ_REGISTER (u2Receive);
+ uTransmit = READ_REGISTER (u2Transmit);
+ uMisc = READ_REGISTER (u2Misc);
+ uLevel = READ_REGISTER (u2FIFOHMark);
+ }
+
+ state.UART_ENABLE = (uControl & hwrVZ328UControlUARTEnable) != 0;
+ state.RX_ENABLE = (uControl & hwrVZ328UControlRxEnable) != 0;
+ state.TX_ENABLE = (uControl & hwrVZ328UControlTxEnable) != 0;
+ state.RX_CLK_CONT = (uControl & hwrVZ328UControlRxClock1xSync) != 0;
+ state.PARITY_EN = (uControl & hwrVZ328UControlParityEn) != 0;
+ state.ODD_EVEN = (uControl & hwrVZ328UControlParityOdd) != 0;
+ state.STOP_BITS = (uControl & hwrVZ328UControlStopBits2) != 0;
+ state.CHAR8_7 = (uControl & hwrVZ328UControlDataBits8) != 0;
+// state.GPIO_DELTA_ENABLE = (uControl & hwr328UControlGPIODeltaEn) != 0; // 68328 only
+ state.OLD_ENABLE = (uControl & hwrVZ328UControlOldDataEn) != 0; // 68VZ328 only
+ state.CTS_DELTA_ENABLE = (uControl & hwrVZ328UControlCTSDeltaEn) != 0;
+ state.RX_FULL_ENABLE = (uControl & hwrVZ328UControlRxFullEn) != 0;
+ state.RX_HALF_ENABLE = (uControl & hwrVZ328UControlRxHalfEn) != 0;
+ state.RX_RDY_ENABLE = (uControl & hwrVZ328UControlRxRdyEn) != 0;
+ state.TX_EMPTY_ENABLE = (uControl & hwrVZ328UControlTxEmptyEn) != 0;
+ state.TX_HALF_ENABLE = (uControl & hwrVZ328UControlTxHalfEn) != 0;
+ state.TX_AVAIL_ENABLE = (uControl & hwrVZ328UControlTxAvailEn) != 0;
+
+ // Baud control register bits
+ // These are all values the user sets; we just look at them.
+
+// state.GPIO_DELTA = (uBaud & hwr328UBaudGPIODelta) != 0; // 68328 only
+// state.GPIO = (uBaud & hwr328UBaudGPIOData) != 0; // 68328 only
+// state.GPIO_DIR = (uBaud & hwr328UBaudGPIODirOut) != 0; // 68328 only
+// state.GPIO_SRC = (uBaud & hwrVZ328UBaudGPIOSrcBaudGen) != 0; // 68328 only
+ state.UCLK_DIR = (uBaud & hwrVZ328UBaudUCLKDirOut) != 0; // 68VZ328 only
+ state.BAUD_SRC = (uBaud & hwrVZ328UBaudBaudSrcUCLK) != 0;
+ state.DIVIDE = (uBaud & hwrVZ328UBaudDivider) >> hwrVZ328UBaudDivideBitOffset;
+ state.PRESCALER = (uBaud & hwrVZ328UBaudPrescaler);
+
+ // Receive register bits
+ // These are all input bits; we set them, not the user.
+
+ state.RX_FIFO_FULL = (uReceive & hwrVZ328UReceiveFIFOFull) != 0;
+ state.RX_FIFO_HALF = (uReceive & hwrVZ328UReceiveFIFOHalf) != 0;
+ state.DATA_READY = (uReceive & hwrVZ328UReceiveDataRdy) != 0;
+ state.OLD_DATA = (uReceive & hwrVZ328UReceiveOldData) != 0; // 68VZ328 only
+ state.OVRUN = (uReceive & hwrVZ328UReceiveOverrunErr) != 0;
+ state.FRAME_ERROR = (uReceive & hwrVZ328UReceiveFrameErr) != 0;
+ state.BREAK = (uReceive & hwrVZ328UReceiveBreakErr) != 0;
+ state.PARITY_ERROR = (uReceive & hwrVZ328UReceiveParityErr) != 0;
+ state.RX_DATA = (uReceive & hwrVZ328UReceiveData);
+
+ // Transmitter register bits
+ // We set everything except TX_DATA; the user sets that
+ // value and ONLY that value.
+
+ state.TX_FIFO_EMPTY = (uTransmit & hwrVZ328UTransmitFIFOEmpty) != 0;
+ state.TX_FIFO_HALF = (uTransmit & hwrVZ328UTransmitFIFOHalf) != 0;
+ state.TX_AVAIL = (uTransmit & hwrVZ328UTransmitTxAvail) != 0;
+ state.SEND_BREAK = (uTransmit & hwrVZ328UTransmitSendBreak) != 0;
+ state.IGNORE_CTS = (uTransmit & hwrVZ328UTransmitIgnoreCTS) != 0;
+ state.BUSY = (uTransmit & hwrVZ328UTransmitBusy) != 0; // 68VZ328 only
+ state.CTS_STATUS = (uTransmit & hwrVZ328UTransmitCTSStatus) != 0;
+ state.CTS_DELTA = (uTransmit & hwrVZ328UTransmitCTSDelta) != 0;
+ state.TX_DATA = (uTransmit & hwrVZ328UTransmitData);
+
+ // Misc register bits
+ // These are all values the user sets; we just look at them.
+
+ state.BAUD_TEST = (uMisc & hwrVZ328UMiscBaudTest) != 0; // 68VZ328 only
+ state.CLK_SRC = (uMisc & hwrVZ328UMiscClkSrcUCLK) != 0;
+ state.FORCE_PERR = (uMisc & hwrVZ328UMiscForceParityErr) != 0;
+ state.LOOP = (uMisc & hwrVZ328UMiscLoopback) != 0;
+ state.BAUD_RESET = (uMisc & hwrVZ328UMiscBaudReset) != 0; // 68VZ328 only
+ state.IR_TEST = (uMisc & hwrVZ328UMiscIRTestEn) != 0; // 68VZ328 only
+ state.RTS_CONT = (uMisc & hwrVZ328UMiscRTSThruFIFO) != 0;
+ state.RTS = (uMisc & hwrVZ328UMiscRTSOut) != 0;
+ state.IRDA_ENABLE = (uMisc & hwrVZ328UMiscIRDAEn) != 0;
+ state.IRDA_LOOP = (uMisc & hwrVZ328UMiscLoopIRDA) != 0;
+ state.RX_POL = (uMisc & hwrVZ328UMiscRXPolarityInv) != 0; // 68VZ328 only
+ state.TX_POL = (uMisc & hwrVZ328UMiscTXPolarityInv) != 0; // 68VZ328 only
+
+ // Level Marker Interrupt
+
+ state.TXFIFO_LEVEL_MARKER = ((uLevel >> 8) & 0x0F); // 68VZ328 only
+ state.RXFIFO_LEVEL_MARKER = ((uLevel >> 0) & 0x0F); // 68VZ328 only
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::UnmarshalUARTState
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::UnmarshalUARTState (const EmUARTDragonball::State& state, int uartNum)
+{
+ uint16 uControl = 0;
+ uint16 uBaud = 0;
+ uint16 uReceive = 0;
+ uint16 uTransmit = 0;
+ uint16 uMisc = 0;
+ uint16 uLevel = 0;
+
+ if (state.UART_ENABLE) uControl |= hwrVZ328UControlUARTEnable;
+ if (state.RX_ENABLE) uControl |= hwrVZ328UControlRxEnable;
+ if (state.TX_ENABLE) uControl |= hwrVZ328UControlTxEnable;
+ if (state.RX_CLK_CONT) uControl |= hwrVZ328UControlRxClock1xSync;
+ if (state.PARITY_EN) uControl |= hwrVZ328UControlParityEn;
+ if (state.ODD_EVEN) uControl |= hwrVZ328UControlParityOdd;
+ if (state.STOP_BITS) uControl |= hwrVZ328UControlStopBits2;
+ if (state.CHAR8_7) uControl |= hwrVZ328UControlDataBits8;
+// if (state.GPIO_DELTA_ENABLE)uControl |= hwr328UControlGPIODeltaEn; // 68328 only
+ if (state.OLD_ENABLE) uControl |= hwrVZ328UControlOldDataEn; // 68VZ328 only
+ if (state.CTS_DELTA_ENABLE) uControl |= hwrVZ328UControlCTSDeltaEn;
+ if (state.RX_FULL_ENABLE) uControl |= hwrVZ328UControlRxFullEn;
+ if (state.RX_HALF_ENABLE) uControl |= hwrVZ328UControlRxHalfEn;
+ if (state.RX_RDY_ENABLE) uControl |= hwrVZ328UControlRxRdyEn;
+ if (state.TX_EMPTY_ENABLE) uControl |= hwrVZ328UControlTxEmptyEn;
+ if (state.TX_HALF_ENABLE) uControl |= hwrVZ328UControlTxHalfEn;
+ if (state.TX_AVAIL_ENABLE) uControl |= hwrVZ328UControlTxAvailEn;
+
+ // Baud control register bits
+ // These are all values the user sets; we just look at them.
+
+// if (state.GPIO_DELTA) uBaud |= hwr328UBaudGPIODelta; // 68328 only
+// if (state.GPIO) uBaud |= hwr328UBaudGPIOData; // 68328 only
+// if (state.GPIO_DIR) uBaud |= hwr328UBaudGPIODirOut; // 68328 only
+// if (state.GPIO_SRC) uBaud |= hwr328UBaudGPIOSrcBaudGen; // 68328 only
+ if (state.UCLK_DIR) uBaud |= hwrVZ328UBaudUCLKDirOut; // 68VZ328 only
+ if (state.BAUD_SRC) uBaud |= hwrVZ328UBaudBaudSrcUCLK;
+
+ uBaud |= (state.DIVIDE << hwrVZ328UBaudDivideBitOffset) & hwrVZ328UBaudDivider;
+ uBaud |= (state.PRESCALER) & hwrVZ328UBaudPrescaler;
+
+ // Receive register bits
+ // These are all input bits; we set them, not the user.
+
+ if (state.RX_FIFO_FULL) uReceive |= hwrVZ328UReceiveFIFOFull;
+ if (state.RX_FIFO_HALF) uReceive |= hwrVZ328UReceiveFIFOHalf;
+ if (state.DATA_READY) uReceive |= hwrVZ328UReceiveDataRdy;
+ if (state.OLD_DATA) uReceive |= hwrVZ328UReceiveOldData; // 68VZ328 only
+ if (state.OVRUN) uReceive |= hwrVZ328UReceiveOverrunErr;
+ if (state.FRAME_ERROR) uReceive |= hwrVZ328UReceiveFrameErr;
+ if (state.BREAK) uReceive |= hwrVZ328UReceiveBreakErr;
+ if (state.PARITY_ERROR) uReceive |= hwrVZ328UReceiveParityErr;
+
+ uReceive |= (state.RX_DATA) & hwrVZ328UReceiveData;
+
+ // Transmitter register bits
+ // We set everything except TX_DATA; the user sets that
+ // value and ONLY that value.
+
+ if (state.TX_FIFO_EMPTY) uTransmit |= hwrVZ328UTransmitFIFOEmpty;
+ if (state.TX_FIFO_HALF) uTransmit |= hwrVZ328UTransmitFIFOHalf;
+ if (state.TX_AVAIL) uTransmit |= hwrVZ328UTransmitTxAvail;
+ if (state.SEND_BREAK) uTransmit |= hwrVZ328UTransmitSendBreak;
+ if (state.IGNORE_CTS) uTransmit |= hwrVZ328UTransmitIgnoreCTS;
+ if (state.BUSY) uTransmit |= hwrVZ328UTransmitBusy; // 68VZ328 only
+ if (state.CTS_STATUS) uTransmit |= hwrVZ328UTransmitCTSStatus;
+ if (state.CTS_DELTA) uTransmit |= hwrVZ328UTransmitCTSDelta;
+
+ uTransmit |= (state.TX_DATA) & hwrVZ328UTransmitData;
+
+ // Misc register bits
+ // These are all values the user sets; we just look at them.
+
+ if (state.BAUD_TEST) uMisc |= hwrVZ328UMiscBaudTest; // 68VZ328 only
+ if (state.CLK_SRC) uMisc |= hwrVZ328UMiscClkSrcUCLK;
+ if (state.FORCE_PERR) uMisc |= hwrVZ328UMiscForceParityErr;
+ if (state.LOOP) uMisc |= hwrVZ328UMiscLoopback;
+ if (state.BAUD_RESET) uMisc |= hwrVZ328UMiscBaudReset; // 68VZ328 only
+ if (state.IR_TEST) uMisc |= hwrVZ328UMiscIRTestEn; // 68VZ328 only
+ if (state.RTS_CONT) uMisc |= hwrVZ328UMiscRTSThruFIFO;
+ if (state.RTS) uMisc |= hwrVZ328UMiscRTSOut;
+ if (state.IRDA_ENABLE) uMisc |= hwrVZ328UMiscIRDAEn;
+ if (state.IRDA_LOOP) uMisc |= hwrVZ328UMiscLoopIRDA;
+ if (state.RX_POL) uMisc |= hwrVZ328UMiscRXPolarityInv; // 68VZ328 only
+ if (state.TX_POL) uMisc |= hwrVZ328UMiscTXPolarityInv; // 68VZ328 only
+
+ // Level Marker Interrupt
+
+ uLevel |= (state.TXFIFO_LEVEL_MARKER) << 8;
+ uLevel |= (state.RXFIFO_LEVEL_MARKER) << 0;
+
+ if (uartNum == 0)
+ {
+ WRITE_REGISTER (uControl, uControl);
+ WRITE_REGISTER (uBaud, uBaud);
+ WRITE_REGISTER (uReceive, uReceive);
+ WRITE_REGISTER (uTransmit, uTransmit);
+ WRITE_REGISTER (uMisc, uMisc);
+ }
+ else
+ {
+ WRITE_REGISTER (u2Control, uControl);
+ WRITE_REGISTER (u2Baud, uBaud);
+ WRITE_REGISTER (u2Receive, uReceive);
+ WRITE_REGISTER (u2Transmit, uTransmit);
+ WRITE_REGISTER (u2Misc, uMisc);
+ WRITE_REGISTER (u2FIFOHMark, uLevel);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::GetPort
+// ---------------------------------------------------------------------------
+// Given an address, return a value indicating what port it is associated with.
+
+int EmRegsVZ::GetPort (emuptr address)
+{
+ const long MASK = 0x00000FF8;
+
+ switch (address & MASK)
+ {
+ case 0x0400: return 'A';
+ case 0x0408: return 'B';
+ case 0x0410: return 'C';
+ case 0x0418: return 'D';
+ case 0x0420: return 'E';
+ case 0x0428: return 'F';
+ case 0x0430: return 'G';
+ case 0x0438: return 'J';
+ case 0x0440: return 'K';
+ case 0x0448: return 'M';
+ }
+
+ EmAssert (false);
+ return 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::PrvGetPalette
+// ---------------------------------------------------------------------------
+
+void EmRegsVZ::PrvGetPalette (RGBList& thePalette)
+{
+ // !!! TBD
+ Preference<RGBType> pref1 (kPrefKeyBackgroundColor);
+ Preference<RGBType> pref2 (kPrefKeyHighlightColor);
+
+ RGBType foreground (0, 0, 0);
+ RGBType background;
+
+ if (this->GetLCDBacklightOn ())
+ {
+ if (pref2.Loaded ())
+ background = *pref2;
+ else
+ background = ::SkinGetHighlightColor ();
+ }
+ else
+ {
+ if (pref1.Loaded ())
+ background = *pref1;
+ else
+ background = ::SkinGetBackgroundColor ();
+ }
+
+ long br = ((long) background.fRed);
+ long bg = ((long) background.fGreen);
+ long bb = ((long) background.fBlue);
+
+ long dr = ((long) foreground.fRed) - ((long) background.fRed);
+ long dg = ((long) foreground.fGreen) - ((long) background.fGreen);
+ long db = ((long) foreground.fBlue) - ((long) background.fBlue);
+
+ int32 bpp = 1 << (READ_REGISTER (lcdPanelControl) & 0x03);
+ int32 numColors = 1 << bpp;
+ thePalette.resize (numColors);
+
+ for (int color = 0; color < numColors; ++color)
+ {
+ thePalette[color].fRed = (UInt8) (br + dr * color / (numColors - 1));
+ thePalette[color].fGreen = (UInt8) (bg + dg * color / (numColors - 1));
+ thePalette[color].fBlue = (UInt8) (bb + db * color / (numColors - 1));
+ }
+}
diff --git a/SrcShared/Hardware/EmRegsVZ.h b/SrcShared/Hardware/EmRegsVZ.h
new file mode 100644
index 0000000..42ad360
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsVZ.h
@@ -0,0 +1,145 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegsVZ_h
+#define EmRegsVZ_h
+
+#include "EmHAL.h" // EmHALHandler
+#include "EmRegs.h" // EmRegs
+#include "EmStructs.h" // RGBList
+#include "EmUARTDragonball.h" // EmUARTDragonball::State
+
+class EmScreenUpdateInfo;
+class EmSPISlave;
+
+
+class EmRegsVZ : public EmRegs, public EmHALHandler
+{
+ public:
+ EmRegsVZ (void);
+ virtual ~EmRegsVZ (void);
+
+ // EmRegs overrides
+ virtual void Initialize (void);
+ virtual void Reset (Bool hardwareReset);
+ virtual void Save (SessionFile&);
+ virtual void Load (SessionFile&);
+ virtual void Dispose (void);
+
+ virtual void SetSubBankHandlers (void);
+ virtual uint8* GetRealAddress (emuptr address);
+ virtual emuptr GetAddressStart (void);
+ virtual uint32 GetAddressRange (void);
+
+ // EmHALHandler overrides
+ virtual void Cycle (Bool sleeping);
+ virtual void CycleSlowly (Bool sleeping);
+
+ virtual void ButtonEvent (SkinElementType, Bool buttonIsDown);
+ virtual void TurnSoundOff (void);
+ virtual void ResetTimer (void);
+ virtual void ResetRTC (void);
+
+ virtual int32 GetInterruptLevel (void);
+ virtual int32 GetInterruptBase (void);
+
+ virtual Bool GetLCDScreenOn (void) = 0;
+ virtual Bool GetLCDBacklightOn (void) = 0;
+ virtual Bool GetLCDHasFrame (void);
+ virtual void GetLCDBeginEnd (emuptr&, emuptr&);
+ virtual void GetLCDScanlines (EmScreenUpdateInfo& info);
+
+ virtual int32 GetDynamicHeapSize (void);
+ virtual int32 GetROMSize (void);
+ virtual emuptr GetROMBaseAddress (void);
+ virtual Bool ChipSelectsConfigured (void);
+ virtual int32 GetSystemClockFrequency (void);
+ virtual Bool GetCanStop (void);
+ virtual Bool GetAsleep (void);
+
+ virtual uint8 GetPortInputValue (int);
+ virtual uint8 GetPortInternalValue (int);
+ virtual void PortDataChanged (int, uint8, uint8);
+ virtual void GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows) = 0;
+
+ private:
+ uint32 pllFreqSelRead (emuptr address, int size);
+ uint32 portXDataRead (emuptr address, int size);
+ uint32 tmr1StatusRead (emuptr address, int size);
+ uint32 tmr2StatusRead (emuptr address, int size);
+ uint32 uart1Read (emuptr address, int size);
+ uint32 uart2Read (emuptr address, int size);
+ uint32 rtcHourMinSecRead (emuptr address, int size);
+
+ void csControl1Write (emuptr address, int size, uint32 value);
+ void csASelectWrite (emuptr address, int size, uint32 value);
+ void csDSelectWrite (emuptr address, int size, uint32 value);
+ void intMaskHiWrite (emuptr address, int size, uint32 value);
+ void intMaskLoWrite (emuptr address, int size, uint32 value);
+ void intStatusHiWrite (emuptr address, int size, uint32 value);
+ void portXDataWrite (emuptr address, int size, uint32 value);
+ void portDIntReqEnWrite (emuptr address, int size, uint32 value);
+ void tmr1StatusWrite (emuptr address, int size, uint32 value);
+ void tmr2StatusWrite (emuptr address, int size, uint32 value);
+ void spiCont1Write (emuptr address, int size, uint32 value);
+ void spiMasterControlWrite (emuptr address, int size, uint32 value);
+ void uart1Write (emuptr address, int size, uint32 value);
+ void uart2Write (emuptr address, int size, uint32 value);
+ void lcdRegisterWrite (emuptr address, int size, uint32 value);
+ void rtcControlWrite (emuptr address, int size, uint32 value);
+ void rtcIntStatusWrite (emuptr address, int size, uint32 value);
+ void rtcIntEnableWrite (emuptr address, int size, uint32 value);
+
+ protected:
+ void HotSyncEvent (Bool buttonIsDown);
+
+ virtual uint8 GetKeyBits (void);
+ virtual uint16 ButtonToBits (SkinElementType);
+ virtual EmSPISlave* GetSPISlave (void);
+
+ protected:
+ void UpdateInterrupts (void);
+ void UpdatePortDInterrupts (void);
+ void UpdateRTCInterrupts (void);
+
+ protected:
+ void UARTStateChanged (Bool sendTxData, int uartNum);
+ void UpdateUARTState (Bool refreshRxData, int uartNum);
+ void UpdateUARTInterrupts (const EmUARTDragonball::State& state, int uartNum);
+ void MarshalUARTState (EmUARTDragonball::State& state, int uartNum);
+ void UnmarshalUARTState (const EmUARTDragonball::State& state, int uartNum);
+
+ protected:
+ int GetPort (emuptr address);
+ void PrvGetPalette (RGBList& thePalette);
+
+ protected:
+ HwrM68VZ328Type f68VZ328Regs;
+ bool fHotSyncButtonDown;
+ uint16 fKeyBits;
+ uint16 fLastTmr1Status;
+ uint16 fLastTmr2Status;
+ uint8 fPortDEdge;
+ uint32 fPortDDataCount;
+
+ uint32 fHour;
+ uint32 fMin;
+ uint32 fSec;
+ uint32 fTick;
+ uint32 fCycle;
+
+ EmUARTDragonball* fUART[2];
+};
+
+#endif /* EmRegsVZ_h */
diff --git a/SrcShared/Hardware/EmRegsVZHandEra330.cpp b/SrcShared/Hardware/EmRegsVZHandEra330.cpp
new file mode 100644
index 0000000..598320e
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsVZHandEra330.cpp
@@ -0,0 +1,608 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmRegsVZTemp.h"
+#include "EmRegsVZPrv.h"
+#include "EmTRGSD.h"
+#include "EmRegsVZHandEra330.h"
+#include "EmRegs330CPLD.h"
+#include "EmBankRegs.h" // EmBankRegs::DisableSubBank
+#include "EmSPISlaveADS784x.h" // EmSPISlaveADS784x
+#include "EmSPISlave330Current.h"
+#include "EmScreen.h" // EmScreenUpdateInfo
+#include "EmDlg.h" // EmDlg::DoCommonDialog
+
+
+#pragma mark -
+
+const int kNumButtonRows = 4;
+const int kNumButtonCols = 4;
+
+const uint16 kButtonMap[kNumButtonRows][kNumButtonCols] =
+{
+ { keyBitHard1, keyBitHard2, keyBitHard3, keyBitHard4 },
+ { keyBitPageUp, keyBitPageDown, 0, keyBitThumbDown},
+ { keyBitPower, 0, keyBitContrast, keyBitThumbPush},
+ { 0, 0, 0, keyBitThumbUp},
+};
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZHandEra330::EmRegsVZHandEra330
+// ---------------------------------------------------------------------------
+
+EmRegsVZHandEra330::EmRegsVZHandEra330 (HandEra330PortManager ** fPortManager) :
+ EmRegsVZ (),
+ fSPISlaveADC (new EmSPISlaveADS784x (kChannelSet2)),
+ fSPISlaveCurrent (new EmSPISlave330Current ())
+{
+ PortD = PortD_DOCK_BTN |
+ PortD_CD_IRQ |
+ PortD_CF_IRQ |
+ PortD_POWER_FAIL;
+ PortF = PortF_PEN_IO |
+ PortF_CPLD_CS_F;
+ PortG = PortG_DTACK |
+ PortG_A0 |
+ PortG_Unused |
+ // PortG_LION |
+ PortG_Unused2;
+ PortJ = PortJ_AD_CS;
+ PortK = PortK_LED_GREEN |
+ PortK_LED_RED |
+ PortK_CPLD_TDO |
+ PortK_CPLD_TCK;
+ PortM = PortM_CPLD_TDI;
+ *fPortManager = &PortMgr;
+ PortMgr.Keys.Row[0] = 1;
+ PortMgr.Keys.Row[1] = 1;
+ PortMgr.Keys.Row[2] = 1;
+ PortMgr.Keys.Row[3] = 1;
+ PortMgr.LCDOn = false;
+ PortMgr.BacklightOn = false;
+ PortMgr.IRPortOn = false;
+ PortMgr.CFBus.bEnabled = false;
+ PortMgr.CFBus.Width = kCFBusWidth16;
+ PortMgr.CFBus.bSwapped = false;
+ PortMgr.CFInserted = true;
+ PortMgr.SDInserted = true;
+ PortMgr.pendingIRQ2 = false;
+ PortMgr.SDChipSelect = false;
+ PortMgr.PowerConnected = false;
+
+ // make sure SPI1 fifos are empty
+ rxHead = rxTail = txHead = txTail = 0;
+ txFifoEmpty = true;
+ rxFifoEmpty = true;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZHandEra330::~EmRegsVZHandEra330
+// ---------------------------------------------------------------------------
+
+EmRegsVZHandEra330::~EmRegsVZHandEra330 (void)
+{
+ delete fSPISlaveADC;
+}
+
+void EmRegsVZHandEra330::Initialize(void)
+{
+ EmRegsVZ::Initialize();
+
+ SD.Initialize();
+}
+
+void EmRegsVZHandEra330::Dispose (void)
+{
+ EmRegsVZ::Dispose();
+
+ SD.Dispose();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZHandEra330::GetLCDScreenOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsVZHandEra330::GetLCDScreenOn (void)
+{
+ // TRG LCD on is determined by LCD contrast on in the CPLD
+ return PortMgr.LCDOn;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZHandEra330::GetLCDBacklightOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsVZHandEra330::GetLCDBacklightOn (void)
+{
+ // TRG CPLD controls the backlight
+ return PortMgr.BacklightOn;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZHandEra330::GetLineDriverState
+// ---------------------------------------------------------------------------
+// Return whether or not the line drivers for the given object are open or
+// closed.
+
+Bool EmRegsVZHandEra330::GetLineDriverState (EmUARTDeviceType type)
+{
+ if (type == kUARTSerial)
+ return (READ_REGISTER (portBData) & PortB_RS232_ON) != 0;
+
+ if (type == kUARTIR)
+ return PortMgr.IRPortOn;
+
+ return false;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZHandEra330::GetUARTDevice
+// ---------------------------------------------------------------------------
+// Return what sort of device is hooked up to the given UART.
+
+EmUARTDeviceType EmRegsVZHandEra330::GetUARTDevice (int /*uartNum*/)
+{
+ Bool serEnabled = this->GetLineDriverState (kUARTSerial);
+ Bool irEnabled = this->GetLineDriverState (kUARTIR);
+
+ // It's probably an error to have them both enabled at the same
+ // time. !!! TBD: make this an error message.
+
+ EmAssert (!(serEnabled && irEnabled));
+
+ // !!! Which UART are they using?
+
+// if (uartNum == ???)
+ {
+ if (serEnabled)
+ return kUARTSerial;
+
+ if (irEnabled)
+ return kUARTIR;
+ }
+
+ return kUARTNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZHandEra330::GetVibrateOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsVZHandEra330::GetVibrateOn (void)
+{
+ return false;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZHandEra330::GetInterruptLevel
+// ---------------------------------------------------------------------------
+
+int32 EmRegsVZHandEra330::GetInterruptLevel (void)
+{
+ int32 retval;
+
+ retval = EmRegsVZ::GetInterruptLevel ();
+
+ if (PortMgr.pendingIRQ2 && (retval < 2))
+ retval = 2;
+
+ return retval;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZHandEra330::GetLEDState
+// ---------------------------------------------------------------------------
+
+uint16 EmRegsVZHandEra330::GetLEDState (void)
+{
+ uint16 result = kLEDOff;
+ uint8 portKData = READ_REGISTER (portKData);
+
+ if ((portKData & PortK_LED_GREEN) == 0)
+ result |= kLEDGreen;
+
+ if ((portKData & PortK_LED_RED) == 0)
+ result |= kLEDRed;
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZHandEra330::GetPortD
+// ---------------------------------------------------------------------------
+
+uint8 EmRegsVZHandEra330::GetPortD (uint8 result)
+{
+ return result |
+ PortD_DOCK_BTN |
+ PortD_CD_IRQ |
+ PortD_CF_IRQ |
+ PortD_POWER_FAIL;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZHandEra330::GetPortInputValue
+// ---------------------------------------------------------------------------
+// Return the GPIO values for the pins on the port. These values are used
+// if the select pins are high.
+
+uint8 EmRegsVZHandEra330::GetPortInputValue (int port)
+{
+ uint8 result = EmRegsVZ::GetPortInputValue (port);
+
+ switch (port)
+ {
+ case 'D' :
+ result = GetPortD (result);
+ break;
+ case 'F' :
+ result = PortF;
+ break;
+ case 'G' :
+ result = PortG;
+ break;
+ case 'J' :
+ result = PortJ;
+ break;
+ case 'K' :
+ result = PortK;
+ break;
+ case 'M' :
+ result = PortM;
+ break;
+
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZHandEra330::GetPortInternalValue
+// ---------------------------------------------------------------------------
+// Return the dedicated values for the pins on the port. These values are
+// used if the select pins are low.
+
+uint8 EmRegsVZHandEra330::GetPortInternalValue (int port)
+{
+ uint8 result = EmRegsVZ::GetPortInternalValue (port);
+
+ switch (port)
+ {
+ case 'D' :
+ result = GetPortD(result);
+ break;
+ case 'F' :
+ result = PortF;
+ break;
+ case 'G' :
+ result = PortG;
+ break;
+ case 'J' :
+ result = PortJ;
+ break;
+ case 'K' :
+ result = PortK;
+ break;
+ case 'M' :
+ result = PortM;
+ break;
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZHandEra330::GetKeyInfo
+// ---------------------------------------------------------------------------
+
+void EmRegsVZHandEra330::GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows)
+{
+ *numRows = kNumButtonRows;
+ *numCols = kNumButtonCols;
+
+ memcpy (keyMap, kButtonMap, sizeof (kButtonMap));
+
+ // Determine what row is being asked for.
+ rows[0] = PortMgr.Keys.Row[0];
+ rows[1] = PortMgr.Keys.Row[1];
+ rows[2] = PortMgr.Keys.Row[2];
+ rows[3] = PortMgr.Keys.Row[3];
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZHandEra330::GetSPISlave
+// ---------------------------------------------------------------------------
+
+EmSPISlave* EmRegsVZHandEra330::GetSPISlave (void)
+{
+ if ((READ_REGISTER (portJData) & PortJ_AD_CS) == 0)
+ {
+ if (PortMgr.SenseCurrent)
+ return fSPISlaveCurrent;
+ else
+ return fSPISlaveADC;
+ }
+
+ return NULL;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZHandEra330::GetROMSize
+// ---------------------------------------------------------------------------
+
+int32 EmRegsVZHandEra330::GetROMSize (void)
+{
+ return (2 * 1024 * 1024);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZHandEra330::ButtonToBits
+// ---------------------------------------------------------------------------
+
+uint16 EmRegsVZHandEra330::ButtonToBits (SkinElementType button)
+{
+ uint16 bitNumber = 0;
+ static Bool CF_button_pushed = false;
+ static Bool SD_button_pushed = false;
+ static Bool power_button_pushed = false;
+
+ switch (button)
+ {
+ default:
+ bitNumber = EmRegsVZ::ButtonToBits (button);
+ break;
+
+ // Borrow some skin elements from Symbol for our Thumb wheel
+ // NOTE: Borrowed Palm's contrast for our aux, so above case already handles it.
+ case kElement_TriggerLeft :
+ bitNumber = keyBitThumbUp; break;
+ case kElement_TriggerCenter :
+ bitNumber = keyBitThumbPush; break;
+ case kElement_TriggerRight :
+ bitNumber = keyBitThumbDown; break;
+
+ // Borrow some additional skin elements to trigger a CF removal or insert.
+ case kElement_DownButtonLeft :
+ bitNumber = 0;
+ // we get called twice here, don't handle the event on the button release
+ if(!CF_button_pushed)
+ {
+ PortMgr.CFInserted = !PortMgr.CFInserted;
+
+ if (PortMgr.CFInserted)
+ EmDlg::DoCommonDialog("The CF card has been installed.", kDlgFlags_OK);
+ else
+ EmDlg::DoCommonDialog("The CF card has been removed.", kDlgFlags_OK);
+
+ PortMgr.pendingIRQ2 = true;
+ CF_button_pushed = true;
+ }
+ else
+ CF_button_pushed = false;
+ break;
+
+ // SD
+ case kElement_DownButtonRight :
+ bitNumber = 0;
+ if (!SD_button_pushed)
+ {
+ PortMgr.SDInserted = !PortMgr.SDInserted;
+
+ if (PortMgr.SDInserted)
+ EmDlg::DoCommonDialog("The SD card has been installed.\n\nIt will take a second for the OS to mount it.",
+ kDlgFlags_OK);
+ else
+ EmDlg::DoCommonDialog("The SD card has been removed.", kDlgFlags_OK);
+
+ PortMgr.pendingIRQ2 = true;
+ SD_button_pushed = true;
+ }
+ else
+ SD_button_pushed = false;
+ break;
+
+ // power
+ case kElement_UpButtonLeft :
+ bitNumber = 0;
+ if (!power_button_pushed)
+ {
+ if (!PortMgr.PowerConnected)
+ {
+ if (PortG & PortG_LION)
+ PortG &= ~PortG_LION;
+ else
+ PortG |= PortG_LION;
+ }
+ PortMgr.PowerConnected = !PortMgr.PowerConnected;
+ PortMgr.pendingIRQ2 = true;
+ ((EmSPISlave330Current *)fSPISlaveCurrent)->SetMode(PortMgr.PowerConnected);
+
+ power_button_pushed = true;
+ }
+ else
+ power_button_pushed = false;
+ break;
+ }
+
+ return bitNumber;
+}
+
+
+/**********************************************************************************
+ * SD support:
+ * HandEra 330 SD is attached to the DragonballVZ SPI1 which is otherwise unused.
+ **********************************************************************************/
+uint32 EmRegsVZHandEra330::spiRxDRead(emuptr /* address */, int /* size */)
+{
+ uint32 retval;
+
+ // there is an 8 word fifo here, read back the first in.
+
+ if ((rxHead == rxTail) && rxFifoEmpty)
+ {
+ // invalid read, fifo empty
+ return 0;
+ }
+
+ retval = rxFifo[rxTail++];
+ if (rxTail == 8)
+ rxTail = 0;
+ if (rxTail == rxHead)
+ txFifoEmpty = true;
+ return retval;
+}
+
+void EmRegsVZHandEra330::spiTxDWrite(emuptr address, int size, uint32 value)
+{
+ // Do a standard update of the register. (so reading the last value back works)
+ EmRegsVZ::StdWrite (address, size, value);
+
+ if (!txFifoEmpty && (txHead == txTail))
+ {
+ // fifo full, do nothing
+ return;
+ }
+
+ txFifoEmpty = false;
+
+ // there is an 8 word fifo here.
+ txFifo[txHead++] = value;
+ if (txHead == 8)
+ txHead = 0;
+}
+
+void EmRegsVZHandEra330::spiCont1Write(emuptr address, int size, uint32 value)
+{
+ // if we were not enabled before, flush fifos
+ if ((value & hwrVZ328SPIMControlEnable)==0)
+ {
+ txTail = txHead;
+ rxTail = rxHead;
+ txFifoEmpty = rxFifoEmpty = true;
+ }
+
+ // Do a standard update of the register.
+ EmRegsVZ::StdWrite (address, size, value);
+
+ // Get the current value.
+ uint16 spiCont1 = READ_REGISTER (spiCont1);
+
+ // Check to see if data exchange and enable are enabled.
+ #define BIT_MASK (hwrVZ328SPIMControlExchange | hwrVZ328SPIMControlEnable)
+ if ((spiCont1 & BIT_MASK) == BIT_MASK)
+ {
+ // do the exchange
+ if (!txFifoEmpty)
+ {
+ // is SD chip selected?
+ if (PortMgr.SDChipSelect)
+ {
+ uint16 rxData, txData;
+
+ do
+ {
+ txData = txFifo[txTail++];
+ if (txTail == 8)
+ txTail = 0;
+ SD.ExchangeBits(txData, &rxData, (spiCont1 & 0x000f)+1);
+ rxFifo[rxHead++] = rxData;
+ if (rxHead == 8)
+ rxHead = 0;
+ } while (txTail != txHead);
+ txFifoEmpty = true;
+ rxFifoEmpty = false;
+ }
+ else
+ {
+ // nothing else is connected here, just stuff the rx fifo and flush the tx fifo
+ do
+ {
+ txTail++;
+ if (txTail == 8)
+ txTail = 0;
+ rxFifo[rxHead++] = 0xff;
+ if (rxHead == 8)
+ rxHead = 0;
+ } while (txTail != txHead);
+ rxFifoEmpty = false;
+ txFifoEmpty = true;
+ }
+ }
+
+ // Clear the exchange bit.
+ spiCont1 &= ~hwrVZ328SPIMControlExchange;
+ WRITE_REGISTER (spiCont1, spiCont1);
+ }
+}
+
+uint32 EmRegsVZHandEra330::spiCont1Read(emuptr /* address */, int /* size */)
+{
+ return 0;
+}
+
+void EmRegsVZHandEra330::spiIntCSWrite(emuptr /* address */, int /* size */, uint32 /* value */)
+{
+}
+
+uint32 EmRegsVZHandEra330::spiIntCSRead(emuptr /* address */, int /* size */)
+{
+ return 0;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZHandEra330::SetSubBankHandlers
+// ---------------------------------------------------------------------------
+
+void EmRegsVZHandEra330::SetSubBankHandlers(void)
+{
+ //HwrM68VZ328Type regs;
+
+ EmRegsVZ::SetSubBankHandlers();
+
+ // SD support
+ this->SetHandler((ReadFunction)&EmRegsVZHandEra330::spiRxDRead,
+ (WriteFunction)&EmRegsVZ::StdWrite,
+ addressof(spiRxD),
+ sizeof(UInt16));
+ this->SetHandler((ReadFunction)&EmRegsVZ::StdRead,
+ (WriteFunction)&EmRegsVZHandEra330::spiTxDWrite,
+ addressof(spiTxD),
+ sizeof(UInt16));
+ this->SetHandler((ReadFunction)&EmRegsVZ::StdRead,
+ (WriteFunction)&EmRegsVZHandEra330::spiCont1Write,
+ addressof(spiCont1),
+ sizeof(UInt16));
+/*
+ this->SetHandler((ReadFunction)&EmRegsVZHandEra330::spiIntCSRead,
+ (WriteFunction)&EmRegsVZHandEra330::spiIntCSWrite,
+ addressof(spiIntCS),
+ sizeof(regs.spiIntCS));
+*/
+}
diff --git a/SrcShared/Hardware/EmRegsVZHandEra330.h b/SrcShared/Hardware/EmRegsVZHandEra330.h
new file mode 100644
index 0000000..154ad23
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsVZHandEra330.h
@@ -0,0 +1,142 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegsVZHandEra330_h
+#define EmRegsVZHandEra330_h
+
+#include "EmRegsVZ.h"
+#include "EmHandEra330Defs.h"
+#include "EmPalmStructs.h"
+#include "EmTRGSD.h"
+
+#define keyBitThumbDown 0x1000
+#define keyBitThumbUp 0x2000
+#define keyBitThumbPush 0x4000
+
+#define PortB_CF_CS 0x0001
+#define PortB_RS232_ON 0x0040
+
+#define PortD_KBD_COL0 0x0001
+#define PortD_KBD_COL1 0x0002
+#define PortD_KBD_COL2 0x0004
+#define PortD_KBD_COL3 0x0008
+#define PortD_DOCK_BTN 0x0010
+#define PortD_CD_IRQ 0x0020
+#define PortD_CF_IRQ 0x0040
+#define PortD_POWER_FAIL 0x0080
+
+#define PortF_LCD_PWM 0x0001
+#define PortF_PEN_IO 0x0002
+#define PortF_CLK_OUT 0x0004
+#define PortF_A20 0x0008
+#define PortF_A21 0x0010
+#define PortF_A22 0x0020
+#define PortF_A23 0x0040
+#define PortF_CPLD_CS_F 0x0080
+
+#define PortG_DTACK 0x0001
+#define PortG_A0 0x0002
+#define PortG_Unused 0x0004
+#define PortG_CPLD_TMS 0x0008
+#define PortG_LION 0x0010
+#define PortG_Unused2 0x0020
+
+#define PortJ_SPI_TX 0x0001
+#define PortJ_SPI_RX 0x0002
+#define PortJ_SPI_CLK 0x0004
+#define PortJ_AD_CS 0x0008
+#define PortJ_232_RX2 0x0010
+#define PortJ_232_TX2 0x0020
+#define PortJ_232_RTS2 0x0040
+#define PortJ_232_CTS2 0x0080
+
+#define PortK_VOL_PWM 0x0001
+#define PortK_GP_IN_F 0x0002
+#define PortK_LED_GREEN 0x0004
+#define PortK_LED_RED 0x0008
+#define PortK_CPLD_TDO 0x0010
+#define PortK_Unused 0x0020
+#define PortK_CPLD_TCK 0x0040
+#define PortK_Unused2 0x0020
+
+#define PortM_SD_CLK 0x0001
+#define PortM_SD_CE 0x0002
+#define PortM_SD_DQMH 0x0004
+#define PortM_SD_DQML 0x0008
+#define PortM_SD_A10 0x0010
+#define PortM_CPLD_TDI 0x0020
+
+class EmRegsVZHandEra330 : public EmRegsVZ
+{
+ public:
+ EmRegsVZHandEra330 (HandEra330PortManager ** fPortManager);
+ virtual ~EmRegsVZHandEra330 (void);
+
+ virtual void Initialize (void);
+ virtual void Dispose (void);
+
+ virtual Bool GetLCDScreenOn (void);
+ virtual Bool GetLCDBacklightOn (void);
+ virtual Bool GetLineDriverState (EmUARTDeviceType type);
+ virtual EmUARTDeviceType GetUARTDevice (int uartNum);
+ virtual Bool GetVibrateOn (void);
+ virtual uint16 GetLEDState (void);
+ int32 GetROMSize (void);
+
+ virtual uint8 GetPortInputValue (int);
+ virtual uint8 GetPortInternalValue (int);
+ virtual void GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows);
+ virtual int32 GetInterruptLevel (void);
+ void SetSubBankHandlers (void);
+
+ protected:
+ virtual EmSPISlave* GetSPISlave (void);
+ virtual uint16 ButtonToBits (SkinElementType button);
+
+ private:
+ uint8 GetPortD(uint8 result);
+ UInt16 PortD;
+ UInt16 PortF;
+ UInt16 PortG;
+ UInt16 PortJ;
+ UInt16 PortK;
+ UInt16 PortM;
+ EmSPISlave* fSPISlaveADC;
+ EmSPISlave* fSPISlaveCurrent;
+ HandEra330PortManager PortMgr;
+ EmTRGSD SD;
+
+ uint16 rxFifo[8];
+ bool rxFifoEmpty;
+ int rxHead;
+ int rxTail;
+ uint16 txFifo[8];
+ bool txFifoEmpty;
+ int txHead;
+ int txTail;
+
+ void spiRxDWrite (emuptr address, int size, uint32 value);
+ uint32 spiRxDRead (emuptr address, int size);
+ void spiTxDWrite (emuptr address, int size, uint32 value);
+ uint32 spiTxDRead (emuptr address, int size);
+ void spiCont1Write (emuptr address, int size, uint32 value);
+ uint32 spiCont1Read (emuptr address, int size);
+ void spiIntCSWrite (emuptr address, int size, uint32 value);
+ uint32 spiIntCSRead (emuptr address, int size);
+};
+
+
+
+#endif /* EmRegsVZTemp_h */
+
diff --git a/SrcShared/Hardware/EmRegsVZPalmM500.cpp b/SrcShared/Hardware/EmRegsVZPalmM500.cpp
new file mode 100644
index 0000000..420de8b
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsVZPalmM500.cpp
@@ -0,0 +1,259 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmRegsVZPalmM500.h"
+#include "EmRegsVZPrv.h"
+
+#include "EmSPISlaveADS784x.h" // EmSPISlaveADS784x
+
+#define hwrVZPortBALARM_LED 0x40 // (L) Alarm LED
+
+#define hwrVZPortDSpi1Card 0x20 // (-) SPI #1, slot 0, SD/MMC Card Detect EOR Wake EOR Ready (aka IRQ2)
+#define hwrVZPortDPowerFail 0x80 // (L) Power Fail interrupt (aka IRQ6)
+
+#define hwrVZPortGEL_ON 0x02 // (L) EL_ON
+#define hwrVZPortGADC_CS_N 0x04 // (H) ADC_CS#
+#define hwrVZPortG232_SHDN_N 0x08 // (L) 232_SHDN#
+
+#define hwrVZPortKLCDOn 0x02 // (-) LCD_DISP_ON (RW#)
+#define hwrVZPortKAC_PWR_N 0x04 // (-) AC_PWR# (LDS#)
+#define hwrVZPortKVibeEn 0x10 // (-) VIBE_EN
+#define hwrVZPortKKbdRow0 0x20 // (H) Keyboard Row 0
+#define hwrVZPortKKbdRow1 0x40 // (H) Keyboard Row 1
+#define hwrVZPortKKbdRow2 0x80 // (H) Keyboard Row 2
+
+#define hwrVZPortMIR_SD 0x20 // (L) Infrared Shut-down
+
+
+const int kNumButtonRows = 3;
+const int kNumButtonCols = 4;
+
+const uint16 kGenericMonoMap[kNumButtonRows][kNumButtonCols] =
+{
+ { keyBitHard1, keyBitHard2, keyBitHard3, keyBitHard4 },
+ { keyBitPageUp, keyBitPageDown, 0, 0 },
+ { keyBitPower, keyBitContrast, keyBitHard2, 0 }
+};
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM500::EmRegsVZPalmM500
+// ---------------------------------------------------------------------------
+
+EmRegsVZPalmM500::EmRegsVZPalmM500 (void) :
+ EmRegsVZ (),
+ fSPISlaveADC (new EmSPISlaveADS784x (kChannelSet1))
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM500::~EmRegsVZPalmM500
+// ---------------------------------------------------------------------------
+
+EmRegsVZPalmM500::~EmRegsVZPalmM500 (void)
+{
+ delete fSPISlaveADC;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM500::GetLCDScreenOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsVZPalmM500::GetLCDScreenOn (void)
+{
+ return (READ_REGISTER (portKData) & hwrVZPortKLCDOn) != 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM500::GetLCDBacklightOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsVZPalmM500::GetLCDBacklightOn (void)
+{
+ return (READ_REGISTER (portGData) & hwrVZPortGEL_ON) != 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM500::GetLineDriverState
+// ---------------------------------------------------------------------------
+// Return whether or not the line drivers for the given object are open or
+// closed.
+
+Bool EmRegsVZPalmM500::GetLineDriverState (EmUARTDeviceType type)
+{
+ if (type == kUARTSerial)
+ return (READ_REGISTER (portGData) & hwrVZPortG232_SHDN_N) != 0;
+
+ if (type == kUARTIR)
+ return (READ_REGISTER (portMData) & hwrVZPortMIR_SD) == 0;
+
+ if (type == kUARTMystery)
+ return true;
+
+ return false;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM500::GetUARTDevice
+// ---------------------------------------------------------------------------
+// Return what sort of device is hooked up to the given UART.
+
+EmUARTDeviceType EmRegsVZPalmM500::GetUARTDevice (int uartNum)
+{
+ Bool serEnabled = this->GetLineDriverState (kUARTSerial);
+ Bool irEnabled = this->GetLineDriverState (kUARTIR);
+
+ // It's probably an error to have them both enabled at the same
+ // time. !!! TBD: make this an error message.
+
+ EmAssert (!(serEnabled && irEnabled));
+
+ /*
+ From Michael Cortopassi:
+
+ UART 1 for IRda
+ UART 2 for hotsync
+ */
+
+ if (uartNum == 0)
+ {
+ if (irEnabled)
+ return kUARTIR;
+ }
+ else if (uartNum == 1)
+ {
+ if (serEnabled)
+ return kUARTSerial;
+ }
+
+ return kUARTNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM500::GetVibrateOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsVZPalmM500::GetVibrateOn (void)
+{
+ return (READ_REGISTER (portKData) & hwrVZPortKVibeEn) != 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM500::GetLEDState
+// ---------------------------------------------------------------------------
+
+uint16 EmRegsVZPalmM500::GetLEDState (void)
+{
+ uint16 result = kLEDOff;
+ UInt8 portBData = READ_REGISTER (portBData);
+
+ if (portBData & hwrVZPortBALARM_LED)
+ result |= kLEDGreen;
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM500::GetPortInputValue
+// ---------------------------------------------------------------------------
+// Return the GPIO values for the pins on the port. These values are used
+// if the select pins are high.
+
+uint8 EmRegsVZPalmM500::GetPortInputValue (int port)
+{
+ uint8 result = EmRegsVZ::GetPortInputValue (port);
+
+ if (port == 'K')
+ {
+ // Make sure hwrVZPortKAC_PWR_N is set, or the dock-status routines
+ // will report that we're powered (even if we aren't docked!).
+
+ result |= hwrVZPortKAC_PWR_N;
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM500::GetPortInternalValue
+// ---------------------------------------------------------------------------
+// Return the dedicated values for the pins on the port. These values are
+// used if the select pins are low.
+
+uint8 EmRegsVZPalmM500::GetPortInternalValue (int port)
+{
+ uint8 result = EmRegsVZ::GetPortInternalValue (port);
+
+ if (port == 'D')
+ {
+ // Make sure that hwrVZPortDPowerFail is set. If it's clear,
+ // the battery code will make the device go to sleep immediately.
+ //
+ // Also make sure that hwrVZPortDSpi1Card is set. If it's clear,
+ // the slot driver will think there's a card installed and will try querying it.
+
+ result |= hwrVZPortDPowerFail | hwrVZPortDSpi1Card;
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM500::GetKeyInfo
+// ---------------------------------------------------------------------------
+
+void EmRegsVZPalmM500::GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows)
+{
+ *numRows = kNumButtonRows;
+ *numCols = kNumButtonCols;
+
+ memcpy (keyMap, kGenericMonoMap, sizeof (kGenericMonoMap));
+
+ // Determine what row is being asked for.
+
+ UInt8 portKDir = READ_REGISTER (portKDir);
+ UInt8 portKData = READ_REGISTER (portKData);
+
+ rows[0] = (portKDir & hwrVZPortKKbdRow0) != 0 && (portKData & hwrVZPortKKbdRow0) == 0;
+ rows[1] = (portKDir & hwrVZPortKKbdRow1) != 0 && (portKData & hwrVZPortKKbdRow1) == 0;
+ rows[2] = (portKDir & hwrVZPortKKbdRow2) != 0 && (portKData & hwrVZPortKKbdRow2) == 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM500::GetSPISlave
+// ---------------------------------------------------------------------------
+
+EmSPISlave* EmRegsVZPalmM500::GetSPISlave (void)
+{
+ if ((READ_REGISTER (portGData) & hwrVZPortGADC_CS_N) == 0)
+ {
+ return fSPISlaveADC;
+ }
+
+ return NULL;
+}
+
+
diff --git a/SrcShared/Hardware/EmRegsVZPalmM500.h b/SrcShared/Hardware/EmRegsVZPalmM500.h
new file mode 100644
index 0000000..81fe5b4
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsVZPalmM500.h
@@ -0,0 +1,44 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegsVZPalmM500_h
+#define EmRegsVZPalmM500_h
+
+#include "EmRegsVZ.h"
+
+class EmRegsVZPalmM500 : public EmRegsVZ
+{
+ public:
+ EmRegsVZPalmM500 (void);
+ virtual ~EmRegsVZPalmM500 (void);
+
+ virtual Bool GetLCDScreenOn (void);
+ virtual Bool GetLCDBacklightOn (void);
+ virtual Bool GetLineDriverState (EmUARTDeviceType type);
+ virtual EmUARTDeviceType GetUARTDevice (int uartNum);
+ virtual Bool GetVibrateOn (void);
+ virtual uint16 GetLEDState (void);
+
+ virtual uint8 GetPortInputValue (int);
+ virtual uint8 GetPortInternalValue (int);
+ virtual void GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows);
+
+ protected:
+ virtual EmSPISlave* GetSPISlave (void);
+
+ private:
+ EmSPISlave* fSPISlaveADC;
+};
+
+#endif /* EmRegsVZPalmM500_h */
diff --git a/SrcShared/Hardware/EmRegsVZPalmM505.cpp b/SrcShared/Hardware/EmRegsVZPalmM505.cpp
new file mode 100644
index 0000000..938a4e6
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsVZPalmM505.cpp
@@ -0,0 +1,151 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmRegsVZPalmM505.h"
+#include "EmRegsVZPrv.h"
+
+#include "EmBankRegs.h" // EmBankRegs::DisableSubBank
+#include "EmRegsSED1376.h" // sed1376RegsAddr
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM505::EmRegsVZPalmM505
+// ---------------------------------------------------------------------------
+
+EmRegsVZPalmM505::EmRegsVZPalmM505 (void) :
+ EmRegsVZPalmM500 ()
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM505::~EmRegsVZPalmM505
+// ---------------------------------------------------------------------------
+
+EmRegsVZPalmM505::~EmRegsVZPalmM505 (void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM505::SetSubBankHandlers
+// ---------------------------------------------------------------------------
+
+void EmRegsVZPalmM505::SetSubBankHandlers (void)
+{
+ // Install base handlers.
+
+ EmRegsVZ::SetSubBankHandlers ();
+
+ // Now add standard/specialized handers for the defined registers.
+
+ this->SetHandler ((ReadFunction) &EmRegsVZ::StdRead,
+ (WriteFunction) &EmRegsVZPalmM505::portFSelectWrite,
+ addressof (portFSelect), sizeof (f68VZ328Regs.portFSelect));
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZ::portFSelectWrite
+// ---------------------------------------------------------------------------
+
+void EmRegsVZPalmM505::portFSelectWrite (emuptr address, int size, uint32 value)
+{
+ uint8 oldPortFSelect = READ_REGISTER (portFSelect);
+
+ // Do a standard update of the register.
+
+ EmRegsVZ::StdWrite (address, size, value);
+
+ uint8 portFSelect = READ_REGISTER (portFSelect);
+
+#define hwrVZPortFBusClock 0x04 // (P) Bus Clock
+
+ if (((portFSelect ^ oldPortFSelect) & hwrVZPortFBusClock) != 0)
+ {
+ if ((portFSelect & hwrVZPortFBusClock) != 0)
+ {
+ EmBankRegs::DisableSubBank (sed1376RegsAddr);
+ EmBankRegs::DisableSubBank (sed1376VideoMemStart);
+ }
+ else
+ {
+ EmBankRegs::EnableSubBank (sed1376RegsAddr);
+ EmBankRegs::EnableSubBank (sed1376VideoMemStart);
+ }
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM505::GetLCDScreenOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsVZPalmM505::GetLCDScreenOn (void)
+{
+ // Override the Dragonball version and let the SED 1376 handle it.
+
+ return EmHALHandler::GetLCDScreenOn ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM505::GetLCDBacklightOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsVZPalmM505::GetLCDBacklightOn (void)
+{
+ // Override the Dragonball version and let the SED 1376 handle it.
+
+ return EmHALHandler::GetLCDBacklightOn ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM505::GetLCDHasFrame
+// ---------------------------------------------------------------------------
+
+Bool EmRegsVZPalmM505::GetLCDHasFrame (void)
+{
+ // Override the Dragonball version and let the SED 1376 handle it.
+
+ return EmHALHandler::GetLCDHasFrame ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM505::GetLCDBeginEnd
+// ---------------------------------------------------------------------------
+
+void EmRegsVZPalmM505::GetLCDBeginEnd (emuptr& begin, emuptr& end)
+{
+ // Override the Dragonball version and let the SED 1376 handle it.
+
+ EmHALHandler::GetLCDBeginEnd (begin, end);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM505::GetLCDScanlines
+// ---------------------------------------------------------------------------
+
+void EmRegsVZPalmM505::GetLCDScanlines (EmScreenUpdateInfo& info)
+{
+ // Override the Dragonball version and let the SED 1376 handle it.
+
+ EmHALHandler::GetLCDScanlines (info);
+}
+
+
+
diff --git a/SrcShared/Hardware/EmRegsVZPalmM505.h b/SrcShared/Hardware/EmRegsVZPalmM505.h
new file mode 100644
index 0000000..7488855
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsVZPalmM505.h
@@ -0,0 +1,36 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegsVZPalmM505_h
+#define EmRegsVZPalmM505_h
+
+#include "EmRegsVZPalmM500.h"
+
+class EmRegsVZPalmM505 : public EmRegsVZPalmM500
+{
+ public:
+ EmRegsVZPalmM505 (void);
+ virtual ~EmRegsVZPalmM505 (void);
+
+ virtual void SetSubBankHandlers (void);
+
+ virtual Bool GetLCDScreenOn (void);
+ virtual Bool GetLCDBacklightOn (void);
+ virtual Bool GetLCDHasFrame (void);
+ virtual void GetLCDBeginEnd (emuptr& begin, emuptr& end);
+ virtual void GetLCDScanlines (EmScreenUpdateInfo& info);
+
+ void portFSelectWrite (emuptr address, int size, uint32 value);
+};
+
+#endif /* EmRegsVZPalmM505_h */
diff --git a/SrcShared/Hardware/EmRegsVZPrv.h b/SrcShared/Hardware/EmRegsVZPrv.h
new file mode 100644
index 0000000..02e9779
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsVZPrv.h
@@ -0,0 +1,45 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegsVZPrv_h
+#define EmRegsVZPrv_h
+
+#include "EmRegsPrv.h"
+
+// Location and range of registers
+
+const uint32 kMemoryStart = 0xFFFFF000;
+const uint32 kMemorySize = sizeof (HwrM68VZ328Type);
+
+
+// Macro to return the DragonballVZ address of the specified register
+
+#define addressof(x) (kMemoryStart + offsetof(HwrM68VZ328Type, x))
+
+
+// Macros for reading/writing DragonballVZ registers.
+
+#define READ_REGISTER(reg) \
+ _get_reg (&f68VZ328Regs.reg)
+
+#define WRITE_REGISTER(reg, value) \
+ _put_reg (&f68VZ328Regs.reg, value)
+
+
+// Macro for installing DragonballVZ register handlers
+
+#define INSTALL_HANDLER(read, write, reg) \
+ this->SetHandler ((ReadFunction) &EmRegsVZ::read, (WriteFunction) &EmRegsVZ::write, addressof (reg), sizeof (f68VZ328Regs.reg))
+
+
+#endif /* EmRegsVZPrv_h */
diff --git a/SrcShared/Hardware/EmRegsVZTemp.cpp b/SrcShared/Hardware/EmRegsVZTemp.cpp
new file mode 100644
index 0000000..36a8521
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsVZTemp.cpp
@@ -0,0 +1,848 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmRegsVZTemp.h"
+#include "EmRegsVZPrv.h"
+
+#include "EmSPISlaveADS784x.h" // EmSPISlaveADS784x
+#include "EmTransportSerial.h" // EmTransportSerial
+
+
+const int kNumButtonRows = 3;
+const int kNumButtonCols = 4;
+
+const uint16 kButtonMap[kNumButtonRows][kNumButtonCols] =
+{
+ { keyBitHard1, keyBitHard2, keyBitHard3, keyBitHard4 },
+ { keyBitPageUp, keyBitPageDown, 0, 0 },
+ { keyBitPower, keyBitContrast, keyBitHard2, 0 }
+};
+
+
+
+#pragma mark -
+#define hwrVZPortBRADIO_DTR 0x40 // (L) Radio DTR
+#define hwrVZPortKRADIO_DSR 0x02 // Radio DTR
+
+#define hwrVZPalmI705PortDTWISTIRQ 0x20 // Twister IRQ (IRQ2)
+#define hwrVZPalmI705PortDPowerFail 0x80 // (L) Power Fail interrupt (aka IRQ6)
+
+#define hwrVZPalmI705PortGEL_ON 0x02 // (L) EL_ON
+#define hwrVZPalmI705PortGLCD_DISP_ON 0x04 // (H) LCD_DISP_ON
+#define hwrVZPalmI705PortG232_SHDN_N 0x08 // (L) 232_SHDN#
+#define hwrVZPalmI705PortGADC_CS_N 0x20 // (H) ADC_CS#
+
+#define hwrVZPalmI705PortKVIB_EN 0x10 // vibarator enable/disable
+#define hwrVZPalmI705PortKKbdRow0 0x20 // (H) Keyboard Row 0
+#define hwrVZPalmI705PortKKbdRow1 0x40 // (H) Keyboard Row 1
+#define hwrVZPalmI705PortKKbdRow2 0x80 // (H) Keyboard Row 2
+
+#define hwrVZPalmI705PortMIR_SD 0x20 // (L) Infrared Shut-down (UART 2)
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmI705::EmRegsVZPalmI705
+// ---------------------------------------------------------------------------
+
+EmRegsVZPalmI705::EmRegsVZPalmI705 (void) :
+ EmRegsVZ (),
+ fSPISlaveADC (new EmSPISlaveADS784x (kChannelSet1))
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmI705::~EmRegsVZPalmI705
+// ---------------------------------------------------------------------------
+
+EmRegsVZPalmI705::~EmRegsVZPalmI705 (void)
+{
+ delete fSPISlaveADC;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmI705::GetLCDScreenOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsVZPalmI705::GetLCDScreenOn (void)
+{
+ return (READ_REGISTER (portGData) & hwrVZPalmI705PortGLCD_DISP_ON) != 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmI705::GetLCDBacklightOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsVZPalmI705::GetLCDBacklightOn (void)
+{
+ return (READ_REGISTER (portGData) & hwrVZPalmI705PortGEL_ON) != 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmI705::GetLineDriverState
+// ---------------------------------------------------------------------------
+// Return whether or not the line drivers for the given object are open or
+// closed.
+
+Bool EmRegsVZPalmI705::GetLineDriverState (EmUARTDeviceType type)
+{
+ if (type == kUARTSerial)
+ return (READ_REGISTER (portGData) & hwrVZPalmI705PortG232_SHDN_N) != 0;
+
+ if (type == kUARTIR)
+ return (READ_REGISTER (portMData) & hwrVZPalmI705PortMIR_SD) == 0;
+
+ return false;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmI705::GetUARTDevice
+// ---------------------------------------------------------------------------
+// Return what sort of device is hooked up to the given UART.
+
+EmUARTDeviceType EmRegsVZPalmI705::GetUARTDevice (int uartNum)
+{
+ Bool serEnabled = this->GetLineDriverState (kUARTSerial);
+ Bool irEnabled = this->GetLineDriverState (kUARTIR);
+
+ // It's probably an error to have them both enabled at the same
+ // time. !!! TBD: make this an error message.
+
+ EmAssert (!(serEnabled && irEnabled));
+
+ /*
+ From Van Oler:
+
+ UART #2 is used for serial (rs-232) and IR. The rs-232 receiver
+ and the IR receiver are tristate outouts with individual enables
+ to control which one drives the RXD2 input.
+
+ UART1 is not used; only the pins are used for GPIO.
+
+ The Master SPI (on PE0,1,2) is used for data to and from the
+ touchscreen A/D and the radio DSP. Each has individual selects.
+
+ The Master/Slave SPI (on PJ0,1,2) is used for the MMC/SD card slot.
+
+ There is a separate USB chip, the same as tornado.
+ */
+
+ if (uartNum == 1)
+ {
+ if (serEnabled)
+ return kUARTSerial;
+
+ if (irEnabled)
+ return kUARTIR;
+ }
+
+ return kUARTNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmI705::GetVibrateOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsVZPalmI705::GetVibrateOn (void)
+{
+ return (READ_REGISTER (portKData) & hwrVZPalmI705PortKVIB_EN) != 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmI705::GetPortInputValue
+// ---------------------------------------------------------------------------
+// Return the GPIO values for the pins on the port. These values are used
+// if the select pins are high.
+
+uint8 EmRegsVZPalmI705::GetPortInputValue (int port)
+{
+ uint8 result = EmRegsVZ::GetPortInputValue (port);
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmI705::GetPortInternalValue
+// ---------------------------------------------------------------------------
+// Return the dedicated values for the pins on the port. These values are
+// used if the select pins are low.
+
+uint8 EmRegsVZPalmI705::GetPortInternalValue (int port)
+{
+ uint8 result = EmRegsVZ::GetPortInternalValue (port);
+
+ if (port == 'D')
+ {
+ // Make sure that hwrVZPortDPowerFail is set. If it's clear,
+ // the battery code will make the device go to sleep immediately.
+ //
+ // Also make sure that hwrVZPalmI705PortDTWISTIRQ is set. If it's clear,
+ // the slot driver will think there's a card installed and will try querying it.
+
+ result |= hwrVZPalmI705PortDPowerFail | hwrVZPalmI705PortDTWISTIRQ;
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmI705::GetKeyInfo
+// ---------------------------------------------------------------------------
+
+void EmRegsVZPalmI705::GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows)
+{
+ *numRows = kNumButtonRows;
+ *numCols = kNumButtonCols;
+
+ memcpy (keyMap, kButtonMap, sizeof (kButtonMap));
+
+ // Determine what row is being asked for.
+
+ UInt8 portKDir = READ_REGISTER (portKDir);
+ UInt8 portKData = READ_REGISTER (portKData);
+
+ rows[0] = (portKDir & hwrVZPalmI705PortKKbdRow0) != 0 && (portKData & hwrVZPalmI705PortKKbdRow0) == 0;
+ rows[1] = (portKDir & hwrVZPalmI705PortKKbdRow1) != 0 && (portKData & hwrVZPalmI705PortKKbdRow1) == 0;
+ rows[2] = (portKDir & hwrVZPalmI705PortKKbdRow2) != 0 && (portKData & hwrVZPalmI705PortKKbdRow2) == 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmI705::GetSPISlave
+// ---------------------------------------------------------------------------
+
+EmSPISlave* EmRegsVZPalmI705::GetSPISlave (void)
+{
+ if ((READ_REGISTER (portGData) & hwrVZPalmI705PortGADC_CS_N) == 0)
+ {
+ return fSPISlaveADC;
+ }
+
+ return NULL;
+}
+
+
+
+
+#pragma mark -
+
+#define hwrVZPalmM125PortDTWISTIRQ 0x20 // Twister IRQ (IRQ2)
+#define hwrVZPalmM125PortDPowerFail 0x80 // (L) Power Fail interrupt (aka IRQ6)
+
+#define hwrVZPalmM125PortGEL_ON 0x02 // (L) EL_ON
+#define hwrVZPalmM125PortGLCD_DISP_ON 0x04 // (H) LCD_DISP_ON
+#define hwrVZPalmM125PortG232_SHDN_N 0x08 // (L) 232_SHDN#
+#define hwrVZPalmM125PortGADC_CS_N 0x20 // (H) ADC_CS#
+
+#define hwrVZPalmM125PortKIRShutdown 0x04 // (-) IR_SHDN
+#define hwrVZPalmM125PortKVIB_EN 0x10 // vibarator enable/disable
+#define hwrVZPalmM125PortKKbdRow0 0x20 // (H) Keyboard Row 0
+#define hwrVZPalmM125PortKKbdRow1 0x40 // (H) Keyboard Row 1
+#define hwrVZPalmM125PortKKbdRow2 0x80 // (H) Keyboard Row 2
+
+const uint16 kButtonMapPalmM125[kNumButtonRows][kNumButtonCols] =
+{
+ { keyBitHard1, keyBitHard2, keyBitHard3, keyBitHard4 },
+ { 0, keyBitPageDown, 0, 0 },
+ { keyBitPower, keyBitPageUp, 0, 0 }
+};
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM125::EmRegsVZPalmM125
+// ---------------------------------------------------------------------------
+
+EmRegsVZPalmM125::EmRegsVZPalmM125 (void) :
+ EmRegsVZ (),
+ fSPISlaveADC (new EmSPISlaveADS784x (kChannelSet3))
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM125::~EmRegsVZPalmM125
+// ---------------------------------------------------------------------------
+
+EmRegsVZPalmM125::~EmRegsVZPalmM125 (void)
+{
+ delete fSPISlaveADC;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM125::GetLCDScreenOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsVZPalmM125::GetLCDScreenOn (void)
+{
+ return (READ_REGISTER (portKData) & 0x02) != 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM125::GetLCDBacklightOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsVZPalmM125::GetLCDBacklightOn (void)
+{
+ return (READ_REGISTER (portFData) & 0x10) != 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM125::GetLineDriverState
+// ---------------------------------------------------------------------------
+// Return whether or not the line drivers for the given object are open or
+// closed.
+
+Bool EmRegsVZPalmM125::GetLineDriverState (EmUARTDeviceType type)
+{
+ if (type == kUARTSerial)
+ return (READ_REGISTER (portEData) & 0x40) != 0;
+
+ if (type == kUARTIR)
+ return (READ_REGISTER (portKData) & hwrVZPalmM125PortKIRShutdown) == 0;
+
+ return false;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM125::GetUARTDevice
+// ---------------------------------------------------------------------------
+// Return what sort of device is hooked up to the given UART.
+
+EmUARTDeviceType EmRegsVZPalmM125::GetUARTDevice (int uartNum)
+{
+ Bool serEnabled = this->GetLineDriverState (kUARTSerial);
+ Bool irEnabled = this->GetLineDriverState (kUARTIR);
+
+ // It's probably an error to have them both enabled at the same
+ // time. !!! TBD: make this an error message.
+
+ EmAssert (!(serEnabled && irEnabled));
+
+ if (uartNum == 0)
+ {
+ if (irEnabled)
+ return kUARTIR;
+ }
+ else if (uartNum == 1)
+ {
+ if (serEnabled)
+ return kUARTSerial;
+ }
+
+ return kUARTNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM125::GetPortInputValue
+// ---------------------------------------------------------------------------
+// Return the GPIO values for the pins on the port. These values are used
+// if the select pins are high.
+
+uint8 EmRegsVZPalmM125::GetPortInputValue (int port)
+{
+ uint8 result = EmRegsVZ::GetPortInputValue (port);
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM125::GetPortInternalValue
+// ---------------------------------------------------------------------------
+// Return the dedicated values for the pins on the port. These values are
+// used if the select pins are low.
+
+uint8 EmRegsVZPalmM125::GetPortInternalValue (int port)
+{
+ uint8 result = EmRegsVZ::GetPortInternalValue (port);
+
+ if (port == 'D')
+ {
+ // Make sure that hwrVZPortDPowerFail is set. If it's clear,
+ // the battery code will make the device go to sleep immediately.
+ //
+ // Also make sure that hwrVZPalmM125PortDTWISTIRQ is set. If it's clear,
+ // the slot driver will think there's a card installed and will try querying it.
+
+ result |= hwrVZPalmM125PortDPowerFail | hwrVZPalmM125PortDTWISTIRQ;
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM125::GetKeyInfo
+// ---------------------------------------------------------------------------
+
+void EmRegsVZPalmM125::GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows)
+{
+ *numRows = kNumButtonRows;
+ *numCols = kNumButtonCols;
+
+ memcpy (keyMap, kButtonMapPalmM125, sizeof (kButtonMapPalmM125));
+
+ // Determine what row is being asked for.
+
+ UInt8 portKDir = READ_REGISTER (portKDir);
+ UInt8 portKData = READ_REGISTER (portKData);
+
+ rows[0] = (portKDir & hwrVZPalmM125PortKKbdRow0) != 0 && (portKData & hwrVZPalmM125PortKKbdRow0) == 0;
+ rows[1] = (portKDir & hwrVZPalmM125PortKKbdRow1) != 0 && (portKData & hwrVZPalmM125PortKKbdRow1) == 0;
+ rows[2] = (portKDir & hwrVZPalmM125PortKKbdRow2) != 0 && (portKData & hwrVZPalmM125PortKKbdRow2) == 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM125::GetSPISlave
+// ---------------------------------------------------------------------------
+
+EmSPISlave* EmRegsVZPalmM125::GetSPISlave (void)
+{
+ if ((READ_REGISTER (portGData) & hwrVZPalmM125PortGADC_CS_N) == 0)
+ {
+ return fSPISlaveADC;
+ }
+
+ return NULL;
+}
+
+
+#pragma mark -
+
+#define hwrVZPalmM130PortDTWISTIRQ 0x20 // Twister IRQ (IRQ2)
+#define hwrVZPalmM130PortDPowerFail 0x80 // (L) Power Fail interrupt (aka IRQ6)
+
+#define hwrVZPalmM130PortGEL_ON 0x02 // (L) EL_ON
+#define hwrVZPalmM130PortGLCD_DISP_ON 0x04 // (H) LCD_DISP_ON
+#define hwrVZPalmM130PortG232_SHDN_N 0x08 // (L) 232_SHDN#
+#define hwrVZPalmM130PortGADC_CS_N 0x20 // (H) ADC_CS#
+
+#define hwrVZPalmM130PortKIRShutdown 0x04 // (-) IR_SHDN
+#define hwrVZPalmM130PortKVIB_EN 0x10 // vibarator enable/disable
+#define hwrVZPalmM130PortKKbdRow0 0x20 // (H) Keyboard Row 0
+#define hwrVZPalmM130PortKKbdRow1 0x40 // (H) Keyboard Row 1
+#define hwrVZPalmM130PortKKbdRow2 0x80 // (H) Keyboard Row 2
+
+const uint16 kButtonMapPalmM130[kNumButtonRows][kNumButtonCols] =
+{
+ { keyBitHard1, keyBitHard2, keyBitHard3, keyBitHard4 },
+ { 0, keyBitPageDown, 0, 0 },
+ { keyBitPower, keyBitPageUp, 0, 0 }
+};
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM130::EmRegsVZPalmM130
+// ---------------------------------------------------------------------------
+
+EmRegsVZPalmM130::EmRegsVZPalmM130 (void) :
+ EmRegsVZ (),
+ fSPISlaveADC (new EmSPISlaveADS784x (kChannelSet1))
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM130::~EmRegsVZPalmM130
+// ---------------------------------------------------------------------------
+
+EmRegsVZPalmM130::~EmRegsVZPalmM130 (void)
+{
+ delete fSPISlaveADC;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM130::GetLCDScreenOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsVZPalmM130::GetLCDScreenOn (void)
+{
+ return (READ_REGISTER (portKData) & 0x02) != 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM130::GetLCDBacklightOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsVZPalmM130::GetLCDBacklightOn (void)
+{
+ return (READ_REGISTER (portFData) & 0x10) != 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM130::GetLineDriverState
+// ---------------------------------------------------------------------------
+// Return whether or not the line drivers for the given object are open or
+// closed.
+
+Bool EmRegsVZPalmM130::GetLineDriverState (EmUARTDeviceType type)
+{
+ if (type == kUARTSerial)
+ return (READ_REGISTER (portEData) & 0x40) != 0;
+
+ if (type == kUARTIR)
+ return (READ_REGISTER (portKData) & hwrVZPalmM130PortKIRShutdown) == 0;
+
+ return false;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM130::GetUARTDevice
+// ---------------------------------------------------------------------------
+// Return what sort of device is hooked up to the given UART.
+
+EmUARTDeviceType EmRegsVZPalmM130::GetUARTDevice (int uartNum)
+{
+ Bool serEnabled = this->GetLineDriverState (kUARTSerial);
+ Bool irEnabled = this->GetLineDriverState (kUARTIR);
+
+ // It's probably an error to have them both enabled at the same
+ // time. !!! TBD: make this an error message.
+
+ EmAssert (!(serEnabled && irEnabled));
+
+ if (uartNum == 0)
+ {
+ if (irEnabled)
+ return kUARTIR;
+ }
+ else if (uartNum == 1)
+ {
+ if (serEnabled)
+ return kUARTSerial;
+ }
+
+ return kUARTNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM130::GetPortInputValue
+// ---------------------------------------------------------------------------
+// Return the GPIO values for the pins on the port. These values are used
+// if the select pins are high.
+
+uint8 EmRegsVZPalmM130::GetPortInputValue (int port)
+{
+ uint8 result = EmRegsVZ::GetPortInputValue (port);
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM130::GetPortInternalValue
+// ---------------------------------------------------------------------------
+// Return the dedicated values for the pins on the port. These values are
+// used if the select pins are low.
+
+uint8 EmRegsVZPalmM130::GetPortInternalValue (int port)
+{
+ uint8 result = EmRegsVZ::GetPortInternalValue (port);
+
+ if (port == 'D')
+ {
+ // Make sure that hwrVZPortDPowerFail is set. If it's clear,
+ // the battery code will make the device go to sleep immediately.
+ //
+ // Also make sure that hwrVZPalmM130PortDTWISTIRQ is set. If it's clear,
+ // the slot driver will think there's a card installed and will try querying it.
+
+ result |= hwrVZPalmM130PortDPowerFail | hwrVZPalmM130PortDTWISTIRQ;
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM130::GetKeyInfo
+// ---------------------------------------------------------------------------
+
+void EmRegsVZPalmM130::GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows)
+{
+ *numRows = kNumButtonRows;
+ *numCols = kNumButtonCols;
+
+ memcpy (keyMap, kButtonMapPalmM130, sizeof (kButtonMapPalmM130));
+
+ // Determine what row is being asked for.
+
+ UInt8 portKDir = READ_REGISTER (portKDir);
+ UInt8 portKData = READ_REGISTER (portKData);
+
+ rows[0] = (portKDir & hwrVZPalmM130PortKKbdRow0) != 0 && (portKData & hwrVZPalmM130PortKKbdRow0) == 0;
+ rows[1] = (portKDir & hwrVZPalmM130PortKKbdRow1) != 0 && (portKData & hwrVZPalmM130PortKKbdRow1) == 0;
+ rows[2] = (portKDir & hwrVZPalmM130PortKKbdRow2) != 0 && (portKData & hwrVZPalmM130PortKKbdRow2) == 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZPalmM130::GetSPISlave
+// ---------------------------------------------------------------------------
+
+EmSPISlave* EmRegsVZPalmM130::GetSPISlave (void)
+{
+ if ((READ_REGISTER (portGData) & hwrVZPalmM130PortGADC_CS_N) == 0)
+ {
+ return fSPISlaveADC;
+ }
+
+ return NULL;
+}
+
+
+#pragma mark -
+
+// Given a register (specified by its field name), return its address
+// in emulated space.
+
+#undef addressof
+#define addressof(reg) \
+ (this->GetAddressStart () + fRegs.offsetof_##reg ())
+
+
+// Macro to help the installation of handlers for a register.
+
+#undef INSTALL_HANDLER
+#define INSTALL_HANDLER(read, write, reg) \
+ this->SetHandler ( (ReadFunction) &EmRegsPLDPalmI705::read, \
+ (WriteFunction) &EmRegsPLDPalmI705::write, \
+ addressof (reg), \
+ fRegs.reg.GetSize ())
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsPLDPalmI705::EmRegsPLDPalmI705
+// ---------------------------------------------------------------------------
+
+EmRegsPLDPalmI705::EmRegsPLDPalmI705 (emuptr baseAddr) :
+ fBaseAddr (baseAddr)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsPLDPalmI705::~EmRegsPLDPalmI705
+// ---------------------------------------------------------------------------
+
+EmRegsPLDPalmI705::~EmRegsPLDPalmI705 (void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsPLDPalmI705::Initialize
+// ---------------------------------------------------------------------------
+
+void EmRegsPLDPalmI705::Initialize (void)
+{
+ EmRegs::Initialize ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsPLDPalmI705::Reset
+// ---------------------------------------------------------------------------
+
+void EmRegsPLDPalmI705::Reset (Bool hardwareReset)
+{
+ EmRegs::Reset (hardwareReset);
+
+ if (hardwareReset)
+ {
+ memset (fRegs.GetPtr (), 0, fRegs.GetSize ());
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsPLDPalmI705::Save
+// ---------------------------------------------------------------------------
+
+void EmRegsPLDPalmI705::Save (SessionFile& f)
+{
+ EmRegs::Save (f);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsPLDPalmI705::Load
+// ---------------------------------------------------------------------------
+
+void EmRegsPLDPalmI705::Load (SessionFile& f)
+{
+ EmRegs::Load (f);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsPLDPalmI705::Dispose
+// ---------------------------------------------------------------------------
+
+void EmRegsPLDPalmI705::Dispose (void)
+{
+ EmRegs::Dispose ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsPLDPalmI705::GetLEDState
+// ---------------------------------------------------------------------------
+
+uint16 EmRegsPLDPalmI705::GetLEDState (void)
+{
+ uint16 result = kLEDOff;
+
+ if (fRegs.green_led)
+ result |= kLEDGreen;
+
+ if (fRegs.red_led)
+ result |= kLEDRed;
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsPLDPalmI705::SetSubBankHandlers
+// ---------------------------------------------------------------------------
+
+void EmRegsPLDPalmI705::SetSubBankHandlers (void)
+{
+ // Install base handlers.
+
+ EmRegs::SetSubBankHandlers ();
+
+ // Now add standard/specialized handers for the defined registers.
+
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, todsln3);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, green_led);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, pin_notify_enable);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, red_led);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, acpr);
+ INSTALL_HANDLER (low_battRead, StdWriteBE, low_batt);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, dto3svc_irq);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, dsp_irq_enable);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, dsp_irq_polarity);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, charging_in_progress);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, charging_in_prog2);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, charging_in_prog_OE);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, twister_irq_wake);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, low_batt_mask);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, acpr_mask);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, acpr_polarity);
+ INSTALL_HANDLER (usb_intRead, StdWriteBE, usb_int);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, usb_int_mask);
+ INSTALL_HANDLER (bullet_detRead, StdWriteBE, bullet_det);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, bullet_det_mask);
+ INSTALL_HANDLER (StdReadBE, StdWriteBE, bullet_det_pol);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsPLDPalmI705::GetRealAddress
+// ---------------------------------------------------------------------------
+
+uint8* EmRegsPLDPalmI705::GetRealAddress (emuptr address)
+{
+ return (uint8*) fRegs.GetPtr () + address - this->GetAddressStart ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsPLDPalmI705::GetAddressStart
+// ---------------------------------------------------------------------------
+
+emuptr EmRegsPLDPalmI705::GetAddressStart (void)
+{
+ return fBaseAddr;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsPLDPalmI705::GetAddressRange
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsPLDPalmI705::GetAddressRange (void)
+{
+ return fRegs.GetSize ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsPLDPalmI705::low_battRead
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsPLDPalmI705::low_battRead (emuptr address, int size)
+{
+ uint32 reg = StdReadBE (address, size);
+
+#define hwrPLDlow_battOn 0 //this is inverted!
+#define hwrPLDlow_battOff 0x80
+
+ // If we're reading the whole register, or if we're reading the second
+ // byte, then set the bit that says that the low-battery condition is off.
+
+ if ((size == 2) || ((size == 1) && ((address & 1) == 1)))
+ {
+ reg |= hwrPLDlow_battOff;
+ }
+
+ return reg;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsPLDPalmI705::usb_intRead
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsPLDPalmI705::usb_intRead (emuptr /*address*/, int /*size*/)
+{
+ // this bit is low-asserted
+
+ return ~0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsPLDPalmI705::bullet_detRead
+// ---------------------------------------------------------------------------
+
+uint32 EmRegsPLDPalmI705::bullet_detRead (emuptr /*address*/, int /*size*/)
+{
+ // 1 = undocked, 0 = docked
+
+ return ~0;
+}
+
+
diff --git a/SrcShared/Hardware/EmRegsVZTemp.h b/SrcShared/Hardware/EmRegsVZTemp.h
new file mode 100644
index 0000000..3864ca7
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsVZTemp.h
@@ -0,0 +1,130 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmRegsVZTemp_h
+#define EmRegsVZTemp_h
+
+#include "EmRegsVZ.h"
+
+#include "EmPalmStructs.h" // EmProxyHwrPalmI705PLDType
+
+
+
+class EmRegsVZPalmI705 : public EmRegsVZ
+{
+ public:
+ EmRegsVZPalmI705 (void);
+ virtual ~EmRegsVZPalmI705 (void);
+
+ virtual Bool GetLCDScreenOn (void);
+ virtual Bool GetLCDBacklightOn (void);
+ virtual Bool GetLineDriverState (EmUARTDeviceType type);
+ virtual EmUARTDeviceType GetUARTDevice (int uartNum);
+ virtual Bool GetVibrateOn (void);
+
+ virtual uint8 GetPortInputValue (int);
+ virtual uint8 GetPortInternalValue (int);
+ virtual void GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows);
+
+ protected:
+ virtual EmSPISlave* GetSPISlave (void);
+
+ private:
+ EmSPISlave* fSPISlaveADC;
+};
+
+
+
+
+class EmRegsVZPalmM125 : public EmRegsVZ
+{
+ public:
+ EmRegsVZPalmM125 (void);
+ virtual ~EmRegsVZPalmM125 (void);
+
+ virtual Bool GetLCDScreenOn (void);
+ virtual Bool GetLCDBacklightOn (void);
+ virtual Bool GetLineDriverState (EmUARTDeviceType type);
+ virtual EmUARTDeviceType GetUARTDevice (int uartNum);
+
+ virtual uint8 GetPortInputValue (int);
+ virtual uint8 GetPortInternalValue (int);
+ virtual void GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows);
+
+ protected:
+ virtual EmSPISlave* GetSPISlave (void);
+
+ private:
+ EmSPISlave* fSPISlaveADC;
+};
+
+
+class EmRegsVZPalmM130 : public EmRegsVZ
+{
+ public:
+ EmRegsVZPalmM130 (void);
+ virtual ~EmRegsVZPalmM130 (void);
+
+ virtual Bool GetLCDScreenOn (void);
+ virtual Bool GetLCDBacklightOn (void);
+ virtual Bool GetLineDriverState (EmUARTDeviceType type);
+ virtual EmUARTDeviceType GetUARTDevice (int uartNum);
+
+ virtual uint8 GetPortInputValue (int);
+ virtual uint8 GetPortInternalValue (int);
+ virtual void GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows);
+
+ protected:
+ virtual EmSPISlave* GetSPISlave (void);
+
+ private:
+ EmSPISlave* fSPISlaveADC;
+};
+
+
+class EmRegsPLDPalmI705 : public EmRegs, public EmHALHandler
+{
+ public:
+ EmRegsPLDPalmI705 (emuptr);
+ virtual ~EmRegsPLDPalmI705 (void);
+
+ virtual void Initialize (void);
+ virtual void Reset (Bool hardwareReset);
+ virtual void Save (SessionFile&);
+ virtual void Load (SessionFile&);
+ virtual void Dispose (void);
+
+ virtual uint16 GetLEDState (void);
+
+ virtual void SetSubBankHandlers (void);
+ virtual uint8* GetRealAddress (emuptr address);
+ virtual emuptr GetAddressStart (void);
+ virtual uint32 GetAddressRange (void);
+
+ private:
+ uint32 low_battRead (emuptr address, int size);
+ uint32 usb_intRead (emuptr address, int size);
+ uint32 bullet_detRead (emuptr address, int size);
+
+ emuptr fBaseAddr;
+ EmProxyHwrPalmI705PLDType fRegs;
+};
+
+typedef EmRegsPLDPalmI705 EmRegsPLDJabba;
+
+
+
+#endif /* EmRegsVZTemp_h */
diff --git a/SrcShared/Hardware/EmRegsVZVisorEdge.cpp b/SrcShared/Hardware/EmRegsVZVisorEdge.cpp
new file mode 100644
index 0000000..2717990
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsVZVisorEdge.cpp
@@ -0,0 +1,166 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 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 "EmRegsEZVisor.h"
+#include "EmRegsVZVisorEdge.h"
+#include "EmRegsVZPrv.h"
+
+
+// Implementation of register-handling for Visor Edge. Visor Edge is derived
+// from Visor Platinum with the following differences:
+// - key setup is identical to Visor Prism
+// - "LCD Enable On" pin is in a different location
+// - backlight pin is active high and in different place
+
+
+/************************************************************************
+ * Port B Bit settings
+ ************************************************************************/
+#define hwrVisorEdgePortBLCDVccOff 0x08 // (L) LCD Vcc
+#define hwrVisorEdgePortBLCDAdjOn 0x40 // (H) LCD Contrast Voltage
+
+
+/************************************************************************
+ * Port C Bit settings
+ ************************************************************************/
+
+
+/************************************************************************
+ * Port D Bit settings
+ ************************************************************************/
+#define hwrVisorEdgePortDKbdCol0On 0x01 // (H) Keyboard Column 0
+#define hwrVisorEdgePortDKbdCol1On 0x02 // (H) Keyboard Column 1
+#define hwrVisorEdgePortDKbdCol2On 0x04 // (H) Keyboard Column 2
+
+#define hwrVisorEdgePortDExtPowerOn 0x08 // (H) External power indicator
+
+#define hwrVisorEdgePortDDock1IrqOff 0x10 // (L) Dock1 interrupt
+#define hwrVisorEdgePortDSlotIrqOff 0x20 // (L) Slot Interrupt
+#define hwrVisorEdgePortDUsbIrqOff 0x40 // (L) USB Interrupt
+#define hwrVisorEdgePortDCardInstIrqOff 0x80 // (L) Card Installed Interrupt
+
+#define hwrVisorEdgePortDKeyBits 0x07 // (H) All Keyboard Columns
+
+
+/************************************************************************
+ * Port E Bit settings
+ ************************************************************************/
+#define hwrVisorEdgePortESerialTxD 0x20 // ( ) Serial transmit line
+#define hwrVisorEdgePortESlotResetOff 0x40 // (L) Slot reset
+#define hwrVisorEdgePortEDock2Off 0x80 // (L) Dock2 input
+
+
+/************************************************************************
+ * Port F Bit settings
+ ************************************************************************/
+#define hwrVisorEdgePortFContrast 0x01 // ( ) LCD Contrast PWM output
+#define hwrVisorEdgePortFIREnableOff 0x04 // (L) Shutdown IR
+#define hwrVisorEdgePortFUsbCsOff 0x80 // (L) USB chip select
+
+
+/************************************************************************
+ * Port G Bit settings
+ ************************************************************************/
+#define hwrVisorEdgePortGUnused0 0x01 // ( ) unused GPIO (after reset)
+#define hwrVisorEdgePortGUsbSuspend 0x02 // (X) USB Suspend bit - Output low for active
+ // - Input for suspend
+#define hwrVisorEdgePortGPowerFailIrqOff 0x04 // (L) Power Fail IRQ
+#define hwrVisorEdgePortGKbdRow0 0x08 // (H) Keyboard Row 0
+#define hwrVisorEdgePortGKbdRow1 0x10 // (H) Keyboard Row 1
+#define hwrVisorEdgePortGAdcCsOff 0x20 // (L) A/D Select
+
+
+/************************************************************************
+ * Port J Bit settings
+ ************************************************************************/
+#define hwrVisorEdgePortJUnused0 0x01 // (X) unused GPIO
+#define hwrVisorEdgePortJUnused1 0x02 // (X) unused GPIO
+#define hwrVisorEdgePortJUnused2 0x04 // (X) unused GPIO
+#define hwrVisorEdgePortJUnused3 0x08 // (X) unused GPIO
+#define hwrVisorEdgePortJSerial2RxD 0x10 // ( ) Serial (UART2) recieve line
+#define hwrVisorEdgePortJSerial2TxD 0x20 // ( ) Serial (UART2) transmit line
+#define hwrVisorEdgePortJSerial2Rts 0x40 // ( ) Serial (UART2) RTS
+#define hwrVisorEdgePortJSerial2Cts 0x80 // ( ) Serial (UART2) CTS
+
+
+/************************************************************************
+ * Port K Bit settings
+ ************************************************************************/
+#define hwrVisorEdgePortKUnused0 0x01 // (X) unused GPIO
+#define hwrVisorEdgePortKKbdRow2 0x02 // (H) Keyboard Row 2
+#define hwrVisorEdgePortKUnused2 0x04 // (X) unused GPIO
+#define hwrVisorEdgePortKUnused3 0x08 // (X) unused GPIO
+
+#define hwrVisorEdgePortKLedOn 0x10 // (L) Turn on LED
+#define hwrVisorEdgePortKLCDEnableOn 0x20 // (L) Shutdown IR
+#define hwrVisorEdgePortKBacklightOn 0x40 // (H) Backlight on/off
+#define hwrVisorEdgePortKUsbResetOff 0x80 // (L) USB reset
+
+
+/************************************************************************
+ * Port M Bit settings
+ ************************************************************************/
+
+#define hwrVisorEdgePortMChargerOff 0x01 // (L) Assert (drive low) to enable
+ // charger. Deassert for 1ms
+ // to restart charger
+#define hwrVisorEdgePortMChargerOn 0x04 // (H) Assert (drive high) to enable
+ // charger. Deassert for 1ms
+ // to restart charger
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZVisorEdge::GetLCDScreenOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsVZVisorEdge::GetLCDScreenOn (void)
+{
+ return (READ_REGISTER (portKData) & hwrVisorEdgePortKLCDEnableOn) != 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZVisorEdge::GetLCDBacklightOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsVZVisorEdge::GetLCDBacklightOn (void)
+{
+ return (READ_REGISTER (portKData) & hwrVisorEdgePortKBacklightOn) != 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZVisorEdge::GetKeyInfo
+// ---------------------------------------------------------------------------
+
+void EmRegsVZVisorEdge::GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows)
+{
+ *numRows = kNumButtonRows;
+ *numCols = kNumButtonCols;
+
+ memcpy (keyMap, kVisorButtonMap, sizeof (kVisorButtonMap));
+
+ // Determine what row is being asked for.
+
+ UInt8 portKDir = READ_REGISTER (portKDir);
+ UInt8 portKData = READ_REGISTER (portKData);
+
+ UInt8 portGDir = READ_REGISTER (portGDir);
+ UInt8 portGData = READ_REGISTER (portGData);
+
+ rows[0] = (portGDir & hwrVisorEdgePortGKbdRow0) != 0 && (portGData & hwrVisorEdgePortGKbdRow0) == 0;
+ rows[1] = (portGDir & hwrVisorEdgePortGKbdRow1) != 0 && (portGData & hwrVisorEdgePortGKbdRow1) == 0;
+ rows[2] = (portKDir & hwrVisorEdgePortKKbdRow2) != 0 && (portKData & hwrVisorEdgePortKKbdRow2) == 0;
+}
diff --git a/SrcShared/Hardware/EmRegsVZVisorEdge.h b/SrcShared/Hardware/EmRegsVZVisorEdge.h
new file mode 100644
index 0000000..49cb53e
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsVZVisorEdge.h
@@ -0,0 +1,30 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 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.
+\* ===================================================================== */
+
+#ifndef EmRegsVZVisorVisorEdge_h
+#define EmRegsVZVisorVisorEdge_h
+
+#include "EmRegsVZ.h"
+#include "EmRegsVZVisorPlatinum.h"
+
+class EmRegsVZVisorEdge: public EmRegsVZVisorPlatinum
+{
+ public:
+ virtual Bool GetLCDScreenOn (void);
+ virtual Bool GetLCDBacklightOn (void);
+ virtual void GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows);
+
+};
+
+#endif /* EmRegsVZVisorVisorEdge_h */
diff --git a/SrcShared/Hardware/EmRegsVZVisorPlatinum.cpp b/SrcShared/Hardware/EmRegsVZVisorPlatinum.cpp
new file mode 100644
index 0000000..c6ebb5a
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsVZVisorPlatinum.cpp
@@ -0,0 +1,262 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 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 "EmRegsVZVisorPlatinum.h"
+#include "EmRegsEZVisor.h"
+#include "EmRegsVZPrv.h"
+
+#include "EmSession.h" // GetDevice
+#include "EmDevice.h" // HardwareID
+#include "EmSPISlaveADS784x.h" // EmSPISlaveADS784x
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZVisor::EmRegsEZVisor
+// ---------------------------------------------------------------------------
+
+EmRegsVZVisorPlatinum::EmRegsVZVisorPlatinum (void) :
+ EmRegsVZ (),
+ fSPISlaveADC (new EmSPISlaveADS784x (kChannelSet2))
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsEZVisor::~EmRegsEZVisor
+// ---------------------------------------------------------------------------
+
+EmRegsVZVisorPlatinum::~EmRegsVZVisorPlatinum (void)
+{
+ delete fSPISlaveADC;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZVisorPlatinum::GetLCDScreenOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsVZVisorPlatinum::GetLCDScreenOn (void)
+{
+ return (READ_REGISTER (portCData) & hwrLegoPortCLCDEnableOn) != 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZVisorPlatinum::GetLCDBacklightOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsVZVisorPlatinum::GetLCDBacklightOn (void)
+{
+ return (READ_REGISTER (portGData) & hwrLegoPortGBacklightOff) == 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZVisorPlatinum::GetLineDriverState
+// ---------------------------------------------------------------------------
+// Return whether or not the line drivers for the given object are open or
+// closed.
+
+Bool EmRegsVZVisorPlatinum::GetLineDriverState (EmUARTDeviceType type)
+{
+ if (type == kUARTSerial)
+ {
+ uint16 uControl = READ_REGISTER (uControl);
+ uint16 uMisc = READ_REGISTER (uMisc);
+
+ return (uControl & hwrEZ328UControlUARTEnable) != 0 &&
+ (uMisc & hwrEZ328UMiscIRDAEn) == 0;
+ }
+
+ if (type == kUARTIR)
+ {
+ uint16 uControl = READ_REGISTER (uControl);
+ uint16 uMisc = READ_REGISTER (uMisc);
+
+ return (uControl & hwrEZ328UControlUARTEnable) != 0 &&
+ (uMisc & hwrEZ328UMiscIRDAEn) != 0;
+ }
+
+ return false;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZVisorPlatinum::GetUARTDevice
+// ---------------------------------------------------------------------------
+// Return what sort of device is hooked up to the given UART.
+
+EmUARTDeviceType EmRegsVZVisorPlatinum::GetUARTDevice (int /*uartNum*/)
+{
+ Bool serEnabled = this->GetLineDriverState (kUARTSerial);
+ Bool irEnabled = this->GetLineDriverState (kUARTIR);
+
+ // It's probably an error to have them both enabled at the same
+ // time. !!! TBD: make this an error message.
+
+ EmAssert (!(serEnabled && irEnabled));
+
+ // !!! Which UART are they using?
+
+// if (uartNum == ???)
+ {
+ if (serEnabled)
+ return kUARTSerial;
+
+ if (irEnabled)
+ return kUARTIR;
+ }
+
+ return kUARTNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZVisorPlatinum::GetPortInputValue
+// ---------------------------------------------------------------------------
+
+uint8 EmRegsVZVisorPlatinum::GetPortInputValue (int port)
+{
+ uint8 result = EmRegsVZ::GetPortInputValue (port);
+
+ if (port == 'E')
+ {
+ /*
+ Support the Visor model ID. From Bob Petersen at Handspring:
+
+ The Visor ROM only works with 1 device so far. But, the Visor does have
+ model detect pins so that future ROMs can work on multiple platforms. The
+ model input pins are connected to port E, bits 0-2 (E[0-2]). To read them,
+ you have to drive port G bit 2 low and enable the pullups on port E.
+ */
+
+#define modelOutPin 0x04 // EMUIRQ (IRQ7)
+#define modelInPins 0x07 // SPI pins on Visor
+
+ UInt8 portGData = READ_REGISTER (portGData);
+ UInt8 portGDir = READ_REGISTER (portGDir);
+ UInt8 portGSelect = READ_REGISTER (portGSelect);
+
+ if (((portGData & modelOutPin) == 0) &&
+ ((portGDir & modelOutPin) == modelOutPin) &&
+ ((portGSelect & modelOutPin) == modelOutPin))
+ {
+ EmDevice device = gSession->GetDevice ();
+ result |= (~device.HardwareID ()) & modelInPins; // <chg 24-Apr-2000 BP> expects inverse output
+ }
+ else
+ {
+ // The pin for detecting "in cradle" is hwrLegoPortEDock2Off. It should be low
+ // if in the serial cradle. If it is high, we assume USB.
+ // -- Bob Petersen
+
+ result &= ~hwrLegoPortEDock2Off;
+ }
+ }
+ else if (port == 'G')
+ {
+ // Make sure that hwrLegoPortGPowerFailIrqOff is set. If it's clear,
+ // the battery code will make the device go to sleep immediately.
+
+ result |= hwrLegoPortGPowerFailIrqOff;
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZVisorPlatinum::GetPortInternalValue
+// ---------------------------------------------------------------------------
+
+uint8 EmRegsVZVisorPlatinum::GetPortInternalValue (int port)
+{
+ uint8 result = EmRegsVZ::GetPortInternalValue (port);
+
+ if (port == 'D')
+ {
+ // Always set the high bit, indicating that there's no memory module
+ // installed. From Bob Petersen at Handspring:
+ //
+ // This is a probe into the module memory, to check for a replacement ROM on a
+ // card that is plugged in. The card is mapped to 0x20000000 and the card's
+ // ROM is at 0x28000000. If it finds the card header (FEEDBEEF) and the card
+ // is plugged in that has a non-zero reset vector, the chip selects are changed
+ // so B0 addresses 10c00000, and then we jump to the reset vector and boot off
+ // the card.
+ //
+ // This part of the boot code should only be called if it is detected that a
+ // card is currently plugged in (bit 7 of port D) and we aren't currently
+ // booting from the card.
+
+ result |= hwrLegoPortDCardInstIrqOff;
+
+ // Ensure that bit hwrLegoPortDDock1IrqOff is set. If it's clear, HotSync
+ // will sync via the modem instead of the serial port.
+
+ result |= hwrLegoPortDDock1IrqOff;
+ }
+ else if (port == 'G')
+ {
+ // Make sure that hwrLegoPortGPowerFailIrqOff is set. If it's clear,
+ // the battery code will make the device go to sleep immediately.
+
+ result |= hwrLegoPortGPowerFailIrqOff;
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZVisorPlatinum::GetKeyInfo
+// ---------------------------------------------------------------------------
+
+void EmRegsVZVisorPlatinum::GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows)
+{
+ *numRows = kNumButtonRows;
+ *numCols = kNumButtonCols;
+
+ memcpy (keyMap, kVisorButtonMap, sizeof (kVisorButtonMap));
+
+ // Determine what row is being asked for.
+
+ UInt8 portDDir = READ_REGISTER (portDDir);
+ UInt8 portDData = READ_REGISTER (portDData);
+
+ UInt8 portGDir = READ_REGISTER (portGDir);
+ UInt8 portGData = READ_REGISTER (portGData);
+
+ rows[0] = (portGDir & hwrLegoPortGKbdRow0) != 0 && (portGData & hwrLegoPortGKbdRow0) == 0;
+ rows[1] = (portGDir & hwrLegoPortGKbdRow1) != 0 && (portGData & hwrLegoPortGKbdRow1) == 0;
+ rows[2] = (portDDir & hwrLegoPortDKbdRow2) != 0 && (portDData & hwrLegoPortDKbdRow2) == 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZVisorPlatinum::GetSPISlave
+// ---------------------------------------------------------------------------
+
+EmSPISlave* EmRegsVZVisorPlatinum::GetSPISlave (void)
+{
+ if ((READ_REGISTER (portGData) & hwrLegoPortGAdcCsOff) == 0)
+ {
+ return fSPISlaveADC;
+ }
+
+ return NULL;
+}
+
+
diff --git a/SrcShared/Hardware/EmRegsVZVisorPlatinum.h b/SrcShared/Hardware/EmRegsVZVisorPlatinum.h
new file mode 100644
index 0000000..b2aafa9
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsVZVisorPlatinum.h
@@ -0,0 +1,43 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 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.
+\* ===================================================================== */
+
+#ifndef EmRegsVZVisorPlatinum_h
+#define EmRegsVZVisorPlatinum_h
+
+#include "EmRegsVZ.h"
+
+
+class EmRegsVZVisorPlatinum : public EmRegsVZ
+{
+ public:
+ EmRegsVZVisorPlatinum ();
+ ~EmRegsVZVisorPlatinum ();
+
+ virtual Bool GetLCDScreenOn (void);
+ virtual Bool GetLCDBacklightOn (void);
+ virtual Bool GetLineDriverState (EmUARTDeviceType type);
+ virtual EmUARTDeviceType GetUARTDevice (int uartNum);
+
+ virtual uint8 GetPortInputValue (int);
+ virtual uint8 GetPortInternalValue (int);
+ virtual void GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows);
+
+ protected:
+ virtual EmSPISlave* GetSPISlave (void);
+
+ private:
+ EmSPISlave* fSPISlaveADC;
+};
+
+#endif /* EmRegsVZVisorPlatinum_h */
diff --git a/SrcShared/Hardware/EmRegsVZVisorPrism.cpp b/SrcShared/Hardware/EmRegsVZVisorPrism.cpp
new file mode 100644
index 0000000..6c73779
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsVZVisorPrism.cpp
@@ -0,0 +1,393 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 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 "EmRegsVZVisorPrism.h"
+#include "EmRegsVZPrv.h"
+
+#include "EmRegsSED1376.h" // SED1376 video controller register access
+
+#include "EmSession.h" // GetDevice
+#include "EmDevice.h" // HardwareID
+
+
+// Prism pin definitions from Handspring. Mostly the same as a Palm V,
+// but with some pins changed and moved around.
+
+
+/************************************************************************
+ * Port B Bit settings
+ ************************************************************************/
+#define hwrVisorPrismPortBLCDVccOff 0x08 // (L) LCD Vcc
+#define hwrVisorPrismPortBLCDAdjOn 0x40 // (H) LCD Contrast Voltage
+
+
+/************************************************************************
+ * Port C Bit settings
+ ************************************************************************/
+#define hwrVisorPrismPortCLCDEnableOn 0x80 // (H) LCD Enable
+
+
+/************************************************************************
+ * Port D Bit settings
+ ************************************************************************/
+#define hwrVisorPrismPortDKbdCol0On 0x01 // (H) Keyboard Column 0
+#define hwrVisorPrismPortDKbdCol1On 0x02 // (H) Keyboard Column 1
+#define hwrVisorPrismPortDKbdCol2On 0x04 // (H) Keyboard Column 2
+
+// Not here! See hwrVisorPrismPortKKbdRow2
+// #define hwrVisorPrismPortDKbdRow2 0x08 // (H) Keyboard Row 2
+
+#define hwrVisorPrismPortDDock1IrqOff 0x10 // (L) Dock1 interrupt
+#define hwrVisorPrismPortDSlotIrqOff 0x20 // (L) Slot Interrupt
+#define hwrVisorPrismPortDUsbIrqOff 0x40 // (L) USB Interrupt
+#define hwrVisorPrismPortDCardInstIrqOff 0x80 // (L) Card Installed Interrupt
+
+#define hwrVisorPrismPortDKeyBits 0x07 // (H) All Keyboard Columns
+
+
+
+/************************************************************************
+ * Port E Bit settings
+ ************************************************************************/
+#define hwrVisorPrismPortESerialTxD 0x20 // ( ) Serial transmit line
+#define hwrVisorPrismPortESlotResetOff 0x40 // (L) Slot reset
+#define hwrVisorPrismPortEDock2Off 0x80 // (L) Dock2 input
+
+
+/************************************************************************
+ * Port F Bit settings
+ ************************************************************************/
+#define hwrVisorPrismPortFContrast 0x01 // ( ) LCD Contrast PWM output
+#define hwrVisorPrismPortFIREnableOff 0x04 // (L) Shutdown IR
+#define hwrVisorPrismPortFUsbCsOff 0x80 // (L) USB chip select
+
+
+/************************************************************************
+ * Port G Bit settings
+ ************************************************************************/
+#define hwrVisorPrismPortGBacklightOff 0x01 // (L) Backlight on/off
+#define hwrVisorPrismPortGUSBSuspend 0x02 // (X) USB Suspend bit - Output low for active
+ // - Input for suspend
+#define hwrVisorPrismPortGPowerFailIrqOff 0x04 // (L) Power Fail IRQ
+#define hwrVisorPrismPortGKbdRow0 0x08 // (H) Keyboard Row 0
+#define hwrVisorPrismPortGKbdRow1 0x10 // (H) Keyboard Row 1
+#define hwrVisorPrismPortGAdcCsOff 0x20 // (L) A/D Select
+
+
+/************************************************************************
+ * Port J Bit settings
+ ************************************************************************/
+#define hwrVisorPrismPortJEepromDi 0x01 // (H) EEPROM Data in
+#define hwrVisorPrismPortJEepromDo 0x02 // ( ) EEPROM Data out
+#define hwrVisorPrismPortJEepromSkOn 0x04 // (H) EEPROM Clock
+#define hwrVisorPrismPortJEepromCsOn 0x08 // (H) EEPROM Chip Select
+#define hwrVisorPrismPortJUnused4 0x10 // (H) unused GPIO
+#define hwrVisorPrismPortJUnused5 0x20 // (H) unused GPIO
+#define hwrVisorPrismPortJUnused6 0x40 // (H) unused GPIO
+#define hwrVisorPrismPortJUnused7 0x80 // (H) unused GPIO
+
+
+/************************************************************************
+ * Port K Bit settings
+ ************************************************************************/
+#define hwrVisorPrismPortKBrightnessPWMOff 0x01 // (L) Brightness PWM output
+#define hwrVisorPrismPortKKbdRow2 0x02 // (H) Keyboard Row 2
+#define hwrVisorPrismPortKUnused2 0x04 // (X) unused GPIO
+#define hwrVisorPrismPortKIREnableBOff 0x08 // (L) Shutdown IR on DVT and later
+
+#define hwrVisorPrismPortKLcdResetOff 0x10 // (L) LCD reset
+#define hwrVisorPrismPortKIREnableAOff 0x20 // (L) Shutdown IR on pre-DVT
+#define hwrVisorPrismPortKUnused6 0x40 // (H) unused GPIO
+#define hwrVisorPrismPortKUsbResetOff 0x80 // (L) USB reset
+
+
+/************************************************************************
+ * Port M Bit settings
+ ************************************************************************/
+
+
+
+/************************************************************************
+ * Hard key settings
+ ************************************************************************/
+
+const int kNumButtonRows = 3;
+const int kNumButtonCols = 3;
+
+const uint16 kButtonMap[kNumButtonRows][kNumButtonCols] =
+{
+ { keyBitHard1, keyBitHard2, keyBitHard3 },
+ { keyBitPageUp, keyBitPageDown, 0 },
+ { keyBitPower, keyBitHard4, 0 }
+};
+
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZVisorPrism::GetLCDScreenOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsVZVisorPrism::GetLCDScreenOn (void)
+{
+ // Override the Dragonball version and let the SED 1376 handle it.
+
+ return EmHALHandler::GetLCDScreenOn ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZVisorPrism::GetLCDBacklightOn
+// ---------------------------------------------------------------------------
+
+Bool EmRegsVZVisorPrism::GetLCDBacklightOn (void)
+{
+ // Override the Dragonball version and let the SED 1376 handle it.
+
+ return EmHALHandler::GetLCDBacklightOn ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZVisorPrism::GetLCDHasFrame
+// ---------------------------------------------------------------------------
+
+Bool EmRegsVZVisorPrism::GetLCDHasFrame (void)
+{
+ // Override the Dragonball version and let the SED 1376 handle it.
+
+ return EmHALHandler::GetLCDHasFrame ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZVisorPrism::GetLCDBeginEnd
+// ---------------------------------------------------------------------------
+
+void EmRegsVZVisorPrism::GetLCDBeginEnd (emuptr& begin, emuptr& end)
+{
+ // Override the Dragonball version and let the SED 1376 handle it.
+
+ EmHALHandler::GetLCDBeginEnd (begin, end);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZVisorPrism::GetLCDScanlines
+// ---------------------------------------------------------------------------
+
+void EmRegsVZVisorPrism::GetLCDScanlines (EmScreenUpdateInfo& info)
+{
+ // Override the Dragonball version and let the SED 1376 handle it.
+
+ EmHALHandler::GetLCDScanlines (info);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZVisorPrism::GetLineDriverState
+// ---------------------------------------------------------------------------
+// Return whether or not the line drivers for the given object are open or
+// closed.
+//
+// DOLATER BP: this way of detecting SerialPortOn may be wrong.
+// See PalmIIIc or PalmV. It may impact Visor emulation as well
+
+Bool EmRegsVZVisorPrism::GetLineDriverState (EmUARTDeviceType type)
+{
+ if (type == kUARTSerial)
+ {
+ uint16 uControl = READ_REGISTER (uControl);
+ uint16 uMisc = READ_REGISTER (uMisc);
+
+ return (uControl & hwrEZ328UControlUARTEnable) != 0 &&
+ (uMisc & hwrEZ328UMiscIRDAEn) == 0;
+ }
+
+ if (type == kUARTIR)
+ {
+ uint16 uControl = READ_REGISTER (uControl);
+ uint16 uMisc = READ_REGISTER (uMisc);
+
+ return (uControl & hwrEZ328UControlUARTEnable) != 0 &&
+ (uMisc & hwrEZ328UMiscIRDAEn) != 0;
+ }
+
+ return false;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZVisorPrism::GetUARTDevice
+// ---------------------------------------------------------------------------
+// Return what sort of device is hooked up to the given UART.
+
+EmUARTDeviceType EmRegsVZVisorPrism::GetUARTDevice (int /*uartNum*/)
+{
+ Bool serEnabled = this->GetLineDriverState (kUARTSerial);
+ Bool irEnabled = this->GetLineDriverState (kUARTIR);
+
+ // It's probably an error to have them both enabled at the same
+ // time. !!! TBD: make this an error message.
+
+ EmAssert (!(serEnabled && irEnabled));
+
+ // !!! Which UART are they using?
+
+// if (uartNum == ???)
+ {
+ if (serEnabled)
+ return kUARTSerial;
+
+ if (irEnabled)
+ return kUARTIR;
+ }
+
+ return kUARTNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZVisorPrism::GetPortInputValue
+//
+// Returns the GPIO value of the given port.
+// ---------------------------------------------------------------------------
+
+uint8 EmRegsVZVisorPrism::GetPortInputValue (int port)
+{
+ uint8 result = EmRegsVZ::GetPortInputValue (port);
+
+ if (port == 'E')
+ {
+ /*
+ Support the Visor model ID. From Bob Petersen at Handspring:
+
+ The Visor ROM only works with 1 device so far. But, the Visor does have
+ model detect pins so that future ROMs can work on multiple platforms. The
+ model input pins are connected to port E, bits 0-2 (E[0-2]). To read them,
+ you have to drive port G bit 2 low and enable the pullups on port E.
+ */
+
+#define modelOutPin 0x04 // EMUIRQ (IRQ7)
+#define modelInPins 0x07 // SPI pins on Visor
+
+ UInt8 portGData = READ_REGISTER (portGData);
+ UInt8 portGDir = READ_REGISTER (portGDir);
+ UInt8 portGSelect = READ_REGISTER (portGSelect);
+
+ if (((portGData & modelOutPin) == 0) &&
+ ((portGDir & modelOutPin) == modelOutPin) &&
+ ((portGSelect & modelOutPin) == modelOutPin))
+ {
+ EmDevice device = gSession->GetDevice ();
+ result |= (~device.HardwareID ()) & modelInPins; // <chg 24-Apr-2000 BP> expects inverse output
+ }
+ else
+ {
+ // The pin for detecting "in cradle" is hwrVisorPrismPortEDock2Off. It should be low
+ // if in the serial cradle. If it is high, we assume USB.
+ // -- Bob Petersen
+
+ result &= ~hwrVisorPrismPortEDock2Off;
+ }
+ }
+ else if (port == 'G')
+ {
+ // Make sure that hwrVisorPrismPortGPowerFailIrqOff is set. If it's clear,
+ // the battery code will make the device go to sleep immediately.
+
+ result |= hwrVisorPrismPortGPowerFailIrqOff;
+ }
+
+ else if (port == 'J')
+ {
+ // Make sure this bit is set, which means the EEPROM has finished being read.
+ // Otherwise we will loop indefinitely as the OS polls this port.
+
+ result |= hwrVisorPrismPortJEepromDo;
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZVisorPrism::GetPortInternalValue
+//
+// Returns the "dedicated" pin value of the given port.
+// ---------------------------------------------------------------------------
+
+uint8 EmRegsVZVisorPrism::GetPortInternalValue (int port)
+{
+ uint8 result = EmRegsVZ::GetPortInternalValue (port);
+
+ if (port == 'D')
+ {
+ // Always set the high bit, indicating that there's no memory module
+ // installed. From Bob Petersen at Handspring:
+ //
+ // This is a probe into the module memory, to check for a replacement ROM on a
+ // card that is plugged in. The card is mapped to 0x20000000 and the card's
+ // ROM is at 0x28000000. If it finds the card header (FEEDBEEF) and the card
+ // is plugged in that has a non-zero reset vector, the chip selects are changed
+ // so B0 addresses 10c00000, and then we jump to the reset vector and boot off
+ // the card.
+ //
+ // This part of the boot code should only be called if it is detected that a
+ // card is currently plugged in (bit 7 of port D) and we aren't currently
+ // booting from the card.
+
+ result |= hwrVisorPrismPortDCardInstIrqOff;
+
+ // Ensure that bit hwrVisorPrismPortDDock1IrqOff is set. If it's clear, HotSync
+ // will sync via the modem instead of the serial port.
+
+ result |= hwrVisorPrismPortDDock1IrqOff;
+ }
+ else if (port == 'G')
+ {
+ // Make sure that hwrVisorPrismPortGPowerFailIrqOff is set. If it's clear,
+ // the battery code will make the device go to sleep immediately.
+
+ result |= hwrVisorPrismPortGPowerFailIrqOff;
+ }
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsVZVisorPrism::GetKeyInfo
+// ---------------------------------------------------------------------------
+
+void EmRegsVZVisorPrism::GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows)
+{
+ *numRows = kNumButtonRows;
+ *numCols = kNumButtonCols;
+
+ memcpy (keyMap, kButtonMap, sizeof (kButtonMap));
+
+ // Determine what row is being asked for.
+
+ UInt8 portKDirVZ = READ_REGISTER (portKDir);
+ UInt8 portKDataVZ = READ_REGISTER (portKData);
+
+ UInt8 portGDir = READ_REGISTER (portGDir);
+ UInt8 portGData = READ_REGISTER (portGData);
+
+ rows[0] = (portGDir & hwrVisorPrismPortGKbdRow0) != 0 && (portGData & hwrVisorPrismPortGKbdRow0) == 0;
+ rows[1] = (portGDir & hwrVisorPrismPortGKbdRow1) != 0 && (portGData & hwrVisorPrismPortGKbdRow1) == 0;
+ rows[2] = (portKDirVZ & hwrVisorPrismPortKKbdRow2) != 0 && (portKDataVZ & hwrVisorPrismPortKKbdRow2) == 0;
+}
+
diff --git a/SrcShared/Hardware/EmRegsVZVisorPrism.h b/SrcShared/Hardware/EmRegsVZVisorPrism.h
new file mode 100644
index 0000000..4d9eaf0
--- /dev/null
+++ b/SrcShared/Hardware/EmRegsVZVisorPrism.h
@@ -0,0 +1,37 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 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.
+\* ===================================================================== */
+
+#ifndef EmRegsVZVisorPrism_h
+#define EmRegsVZVisorPrism_h
+
+#include "EmRegsVZ.h"
+
+
+class EmRegsVZVisorPrism : public EmRegsVZ
+{
+ public:
+ virtual Bool GetLCDScreenOn (void);
+ virtual Bool GetLCDBacklightOn (void);
+ virtual Bool GetLCDHasFrame (void);
+ virtual void GetLCDBeginEnd (emuptr& begin, emuptr& end);
+ virtual void GetLCDScanlines (EmScreenUpdateInfo& info);
+ virtual Bool GetLineDriverState (EmUARTDeviceType type);
+ virtual EmUARTDeviceType GetUARTDevice (int uartNum);
+
+ virtual uint8 GetPortInputValue (int);
+ virtual uint8 GetPortInternalValue (int);
+ virtual void GetKeyInfo (int* numRows, int* numCols,
+ uint16* keyMap, Bool* rows);
+};
+
+#endif /* EmRegsVZVisorPrism_h */
diff --git a/SrcShared/Hardware/EmSPISlave.cpp b/SrcShared/Hardware/EmSPISlave.cpp
new file mode 100644
index 0000000..9dc7ff6
--- /dev/null
+++ b/SrcShared/Hardware/EmSPISlave.cpp
@@ -0,0 +1,51 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmSPISlave.h"
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSPISlave::EmSPISlave
+// ---------------------------------------------------------------------------
+
+EmSPISlave::EmSPISlave (void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSPISlave::~EmSPISlave
+// ---------------------------------------------------------------------------
+
+EmSPISlave::~EmSPISlave (void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSPISlave::Enable
+// ---------------------------------------------------------------------------
+
+void EmSPISlave::Enable (void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSPISlave::Disable
+// ---------------------------------------------------------------------------
+
+void EmSPISlave::Disable (void)
+{
+}
diff --git a/SrcShared/Hardware/EmSPISlave.h b/SrcShared/Hardware/EmSPISlave.h
new file mode 100644
index 0000000..1fcb2dd
--- /dev/null
+++ b/SrcShared/Hardware/EmSPISlave.h
@@ -0,0 +1,28 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmSPISlave_h
+#define EmSPISlave_h
+
+class EmSPISlave
+{
+ public:
+ EmSPISlave (void);
+ virtual ~EmSPISlave (void);
+
+ virtual uint16 DoExchange (uint16 control, uint16 data) = 0;
+ virtual void Enable (void);
+ virtual void Disable (void);
+};
+
+#endif // EmSPISlave_h
diff --git a/SrcShared/Hardware/EmSPISlaveADS784x.cpp b/SrcShared/Hardware/EmSPISlaveADS784x.cpp
new file mode 100644
index 0000000..51960e0
--- /dev/null
+++ b/SrcShared/Hardware/EmSPISlaveADS784x.cpp
@@ -0,0 +1,428 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmSPISlaveADS784x.h"
+
+#include "EmLowMem.h" // EmLowMem_GetGlobal
+#include "EmMemory.h" // CEnableFullAccess
+#include "EmPalmStructs.h" // EmAliasSysBatteryDataStruct
+
+#include "Logging.h"
+#define PRINTF if (1) ; else LogAppendMsg
+
+/********************************************************************
+ * Single-Ended Mode Channel Constants (adcSERDFR = 1)
+ ********************************************************************/
+#define adcSERTemp0 0x04 // Temperature 0
+#define adcSERYPos 0x14 // Y-Position
+#define adcSERBat 0x24 // Battery
+#define adcSERZ1Pos 0x34 // Z1-Position
+#define adcSERZ2Pos 0x44 // Z2-Position
+#define adcSERXPos 0x54 // X-Position
+#define adcSERAux 0x64 // Auxilliary
+#define adcSERTemp1 0x74 // Temperature 1
+
+/********************************************************************
+ * Differential Mode Channel Constants (adcSERDFR = 0)
+ ********************************************************************/
+#define adcDFRYPos 0x10 // Y-Position
+#define adcDFRZ1Pos 0x30 // Z1-Position
+#define adcDFRZ2Pos 0x40 // Z2-Position
+#define adcDFRXPos 0x50 // X-Position
+
+/********************************************************************
+ * Conversion Mode Resolution
+ ********************************************************************/
+#define adcMode12Bit 0x00 // 12-bit conversion
+#define adcMode8Bit 0x08 // 8-bit conversion
+
+/********************************************************************
+ * Power Down Bit Use (for Burr-Brown ADS7846)
+ ********************************************************************/
+#define adcPDADCOn 0x01 // If set, turn on the ADC converter
+#define adcPDReferenceOn 0x02 // If set, the internal Vref reference is turned on
+
+#define kChannelBits 0x70
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSPISlaveADS784x::EmSPISlaveADS784x
+// ---------------------------------------------------------------------------
+
+EmSPISlaveADS784x::EmSPISlaveADS784x ( EmADSChannelType ch0,
+ EmADSChannelType ch1,
+ EmADSChannelType ch2,
+ EmADSChannelType ch3,
+ EmADSChannelType ch4,
+ EmADSChannelType ch5,
+ EmADSChannelType ch6,
+ EmADSChannelType ch7) :
+ EmSPISlave (),
+ fBitBufferIn (0),
+ fBitBufferOut (0),
+ fNumBitsIn (0),
+ fPendingResult (0),
+ fHavePending (false),
+ fCommandBitsSeen (0)
+{
+ fChannelUse[0] = ch0;
+ fChannelUse[1] = ch1;
+ fChannelUse[2] = ch2;
+ fChannelUse[3] = ch3;
+ fChannelUse[4] = ch4;
+ fChannelUse[5] = ch5;
+ fChannelUse[6] = ch6;
+ fChannelUse[7] = ch7;
+
+ // If there's a 7846-style battery, it *must* be on channel 2.
+
+ for (int ii = 0; ii < 8; ++ii)
+ {
+ if (fChannelUse[ii] == kChannelBattery7846)
+ {
+ EmAssert (ii == 2);
+ }
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSPISlaveADS784x::~EmSPISlaveADS784x
+// ---------------------------------------------------------------------------
+
+EmSPISlaveADS784x::~EmSPISlaveADS784x (void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSPISlaveADS784x::DoExchange
+// ---------------------------------------------------------------------------
+
+uint16 EmSPISlaveADS784x::DoExchange (uint16 control, uint16 data)
+{
+ PRINTF ("");
+ PRINTF ("EmSPISlaveADS784x::DoExchange");
+ PRINTF ("control = 0x%04X, data = 0x%04X", control, data);
+
+ // -----------------------------------------------------------------------
+ // Merge the incoming bits with our current buffer.
+ // -----------------------------------------------------------------------
+
+ uint16 numBits = (control & hwrVZ328SPIMControlBitsMask) + 1;
+ uint32 oldBitsMask = ~0 << numBits;
+ uint32 newBitsMask = ~oldBitsMask;
+
+ PRINTF ("Before merging input: fBitBufferIn = 0x%04X, fNumBitsIn = 0x%04X", fBitBufferIn, fNumBitsIn);
+
+ fBitBufferIn = ((fBitBufferIn << numBits) & oldBitsMask) | (data & newBitsMask);
+ fNumBitsIn += numBits;
+
+ PRINTF ("After merging input: fBitBufferIn = 0x%04X, fNumBitsIn = 0x%04X", fBitBufferIn, fNumBitsIn);
+
+ // -----------------------------------------------------------------------
+ // Start processing the command bits.
+ // -----------------------------------------------------------------------
+
+ EmAssert (fNumBitsIn - fCommandBitsSeen - 1 >= 0);
+
+ uint16 result = 0;
+ uint32 mask = 1 << (fNumBitsIn - fCommandBitsSeen - 1);
+
+ while (mask)
+ {
+ // Shift out a bit.
+
+ {
+ result = (result << 1) | (fBitBufferOut >> 15);
+ fBitBufferOut <<= 1;
+ }
+
+ // If we haven't seen the Start bit yet, look for it.
+
+ if (fCommandBitsSeen == 0)
+ {
+ // If we found the Start bit, start counting the
+ // number of command bits as we stream through them.
+
+ if ((mask & fBitBufferIn) != 0)
+ {
+ fCommandBitsSeen++;
+ }
+
+ // Otherwise, adjust fNumBitsIn so that when we *do*
+ // find the Start bit, we know where it is.
+
+ else
+ {
+ fNumBitsIn--;
+ }
+
+ // If there's a pending conversion, load it into the
+ // output shift register after receiving the first
+ // bit after the last bit of the previous command.
+
+ this->LoadPendingConversion ();
+ }
+ else
+ {
+ fCommandBitsSeen++;
+
+ // If we've seen 8 bits, process the command, and then
+ // prepare for the next one.
+
+ if (fCommandBitsSeen == 8)
+ {
+ fNumBitsIn -= 8;
+ fCommandBitsSeen = 0;
+
+ uint8 command = fBitBufferIn >> fNumBitsIn;
+ this->ProcessCommand (command);
+
+ PRINTF ("After ProcessCommand: fPendingResult = 0x%04X", fPendingResult);
+ }
+ }
+
+ mask >>= 1;
+ }
+
+
+ // ----------------------------------------------------------------------
+ // Return the result.
+ // ----------------------------------------------------------------------
+
+ PRINTF ("result = 0x%04X", result);
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSPISlaveADS784x::ProcessCommand
+// ---------------------------------------------------------------------------
+
+void EmSPISlaveADS784x::ProcessCommand (uint8 command)
+{
+ uint16 result = 0;
+
+ /*
+ Command format is:
+
+ +-----+-----+-----+-----+-----+-----+-----+-----+
+ | S | A2 | A1 | A0 | M | Ref | PD1 | PD0 |
+ +-----+-----+-----+-----+-----+-----+-----+-----+
+
+ S = Start Bit. Must be 1.
+ A2:0 = Channel select bits
+ M = 12/8 bit mode (1 = 8-bit)
+ Ref = Single-ended/Differential reference select bit
+ PD1:0 = Power down mode select bits.
+
+ We care about the A2:0 bits, since they tell us what data
+ is being asked for. We also care about the M bit, as that
+ determines how many bits we load into fBitBufferOut.
+ */
+
+ int channel = (command & kChannelBits) >> 4;
+
+ EmAssert (channel >= 0 && channel <= 7);
+
+ switch (fChannelUse [channel])
+ {
+ case kChannelPenX:
+ case kChannelPenY:
+ {
+ result = 0;
+ break;
+ }
+
+ case kChannelBattery7843:
+ case kChannelBattery7846:
+ {
+ /*
+ The current batterly level is read with the following:
+
+ currentLevel = PrvAverageBattery ( );
+
+ PrvAverageBattery() reads the ADC battery value and then
+ uses a 7/8 averaging method to merge the new value into
+ previously averaged values.
+
+ "currentLevel" is then used to determine "batteryLevel"
+ as follows:
+
+ batteryLevel = (((UInt16)currentLevel + (battDataP->sysBattVoltageStepOffset))
+ * 100 + (battDataP->sysBattStepsPerVolt)/2)
+ / (battDataP->sysBattStepsPerVolt);
+
+ "batteryLevel" is then used to search through the sysBattVoltageCurve
+ array to determine the percent charge.
+
+ Thus, in order to determine the "currentLevel" for a desired
+ "batteryLevel", we solve for it, getting:
+
+ currentLevel = (batteryLevel * battDataP->sysBattStepsPerVolt + 50) / 100 -
+ battDataP->sysBattVoltageStepOffset;
+
+ We can then get the "batteryLevel" from the voltage curve
+ array in the battery table. For example, for a 100% charge,
+ read sysBattVoltageCurve[10].
+ */
+
+ CEnableFullAccess munge;
+
+ // Get a pointer to the system battery globals and determine
+ // what version table we're using.
+
+ emuptr sysBatteryDataP = EmLowMem_GetGlobal (sysBatteryDataP);
+
+ if (sysBatteryDataP)
+ {
+ EmAliasSysBatteryDataStructV1<PAS> sysBatteryData (sysBatteryDataP);
+
+ UInt16 sysBattDataStructVersion = sysBatteryData.sysBattDataStructVersion;
+
+ if (sysBattDataStructVersion <= 3)
+ {
+ UInt16 voltageCurve = 0;
+ UInt16 sysBattStepsPerVolt = 0;
+ Int16 sysBattVoltageStepOffset = 0;
+
+ // Fill out the above variables from the system battery globals,
+ // sorting out table version differences.
+
+ if (sysBattDataStructVersion == 1)
+ {
+ EmAliasSysBatteryDataStructV1<PAS> sysBatteryDataV1 (sysBatteryDataP);
+
+ voltageCurve = sysBatteryDataV1.sysBattVoltageCurve[10];
+ sysBattStepsPerVolt = sysBatteryDataV1.sysBattStepsPerVolt;
+ sysBattVoltageStepOffset = sysBatteryDataV1.sysBattVoltageStepOffset;
+ }
+ else if (sysBattDataStructVersion == 2)
+ {
+ EmAliasSysBatteryDataStructV2<PAS> sysBatteryDataV2 (sysBatteryDataP);
+
+ voltageCurve = sysBatteryDataV2.sysBattVoltageCurve[10];
+ sysBattStepsPerVolt = sysBatteryDataV2.sysBattStepsPerVolt;
+ sysBattVoltageStepOffset = sysBatteryDataV2.sysBattVoltageStepOffset;
+ }
+ else if (sysBattDataStructVersion == 3)
+ {
+ EmAliasSysBatteryDataStructV3<PAS> sysBatteryDataV3 (sysBatteryDataP);
+
+ voltageCurve = sysBatteryDataV3.sysBattVoltageCurve[10];
+ sysBattStepsPerVolt = sysBatteryDataV3.sysBattStepsPerVolt;
+ sysBattVoltageStepOffset = sysBatteryDataV3.sysBattVoltageStepOffset;
+ }
+ else
+ {
+ EmAssert (false);
+ }
+
+ PRINTF ("voltageCurve = %d", voltageCurve);
+ PRINTF ("sysBattStepsPerVolt = %d", sysBattStepsPerVolt);
+ PRINTF ("sysBattVoltageStepOffset = %d", sysBattVoltageStepOffset);
+
+ // Determine the result based on the formula in the comments above.
+
+ result = (voltageCurve *
+ sysBattStepsPerVolt + 50) / 100 -
+ sysBattVoltageStepOffset;
+
+ // Turn this into a 12 bit result.
+
+ result <<= 4;
+
+ if (fChannelUse [channel] == kChannelBattery7846)
+ {
+ result *= 2; // Account for the fact that the Palm OS battery
+ // tables assume a 5.0V reference voltage, while
+ // the 7846 uses 2.5V. (?)
+ result /= 4; // Account for 1:4 voltage divider
+ }
+ }
+ else
+ {
+ result = 0x0FFF;
+ }
+ }
+ else
+ {
+ result = 0x0FFF;
+ }
+
+ PRINTF ("result = 0x%04X", result);
+ break;
+ }
+
+ case kChannelDockSerial:
+ {
+ // Say that we're undocked.
+
+ result = 0x0000;
+ break;
+ }
+
+ case kChannelDockTwister:
+ {
+ // Say that we're undocked.
+
+ result = 0x0FFF;
+ break;
+ }
+
+ case kChannelTemp0:
+ {
+ result = 0x0FFF; // !!! Dummy value; need to determine real value
+ break;
+ }
+
+ case kChannelTemp1:
+ {
+ result = 0x0FFF; // !!! Dummy value; need to determine real value
+ break;
+ }
+
+ default:
+ EmAssert (false);
+ break;
+ }
+
+ fPendingResult = result << 4;
+ fHavePending = true;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSPISlaveADS784x::LoadPendingConversion
+// ---------------------------------------------------------------------------
+
+void EmSPISlaveADS784x::LoadPendingConversion (void)
+{
+ // -----------------------------------------------------------------------
+ // If there's a pending conversion, move it into the output shift register.
+ // -----------------------------------------------------------------------
+
+ if (fHavePending)
+ {
+ PRINTF ("Before merging pending: fBitBufferOut = 0x%04X", fBitBufferOut);
+
+ fHavePending = false;
+ fBitBufferOut = fPendingResult;
+
+ PRINTF ("After merging pending: fBitBufferOut = 0x%04X", fBitBufferOut);
+ }
+}
+
diff --git a/SrcShared/Hardware/EmSPISlaveADS784x.h b/SrcShared/Hardware/EmSPISlaveADS784x.h
new file mode 100644
index 0000000..318e44c
--- /dev/null
+++ b/SrcShared/Hardware/EmSPISlaveADS784x.h
@@ -0,0 +1,97 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmSPISlaveADS784x_h
+#define EmSPISlaveADS784x_h
+
+#include "EmSPISlave.h" // EmSPISlave
+
+enum EmADSChannelType
+{
+ kChannelUnused,
+ kChannelPenX,
+ kChannelPenY,
+ kChannelBattery7843,
+ kChannelBattery7846,
+ kChannelDockSerial,
+ kChannelDockTwister,
+ kChannelTemp0,
+ kChannelTemp1
+};
+
+
+#define kChannelSet1 \
+ kChannelTemp0, \
+ kChannelPenY, \
+ kChannelBattery7846, \
+ kChannelUnused, \
+ kChannelUnused, \
+ kChannelPenX, \
+ kChannelDockTwister, \
+ kChannelTemp1
+
+
+#define kChannelSet2 \
+ kChannelUnused, \
+ kChannelPenY, \
+ kChannelBattery7843, \
+ kChannelUnused, \
+ kChannelUnused, \
+ kChannelPenX, \
+ kChannelDockSerial, \
+ kChannelUnused
+
+
+#define kChannelSet3 \
+ kChannelUnused, \
+ kChannelPenY, \
+ kChannelBattery7843, \
+ kChannelUnused, \
+ kChannelUnused, \
+ kChannelPenX, \
+ kChannelDockTwister, \
+ kChannelUnused
+
+
+class EmSPISlaveADS784x : public EmSPISlave
+{
+ public:
+ EmSPISlaveADS784x (EmADSChannelType ch0,
+ EmADSChannelType ch1,
+ EmADSChannelType ch2,
+ EmADSChannelType ch3,
+ EmADSChannelType ch4,
+ EmADSChannelType ch5,
+ EmADSChannelType ch6,
+ EmADSChannelType ch7);
+ virtual ~EmSPISlaveADS784x (void);
+
+ virtual uint16 DoExchange (uint16 control, uint16 data);
+
+ protected:
+ void ProcessCommand (uint8);
+ void LoadPendingConversion (void);
+
+ private:
+ EmADSChannelType fChannelUse[8];
+
+ uint32 fBitBufferIn;
+ uint16 fBitBufferOut;
+ int fNumBitsIn;
+ uint16 fPendingResult;
+ Bool fHavePending;
+
+ int fCommandBitsSeen;
+};
+
+#endif // EmSPISlaveADS784x_h
diff --git a/SrcShared/Hardware/EmUAEGlue.cpp b/SrcShared/Hardware/EmUAEGlue.cpp
new file mode 100644
index 0000000..351fa43
--- /dev/null
+++ b/SrcShared/Hardware/EmUAEGlue.cpp
@@ -0,0 +1,166 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 1999-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 "EmUAEGlue.h"
+
+#include "EmCPU68K.h" // ProcessException, etc.
+#include "EmSession.h" // gSession->Reset
+#include "Platform.h" // AllocateMemory
+#include "UAE.h" // MakeSR, uae_s32, etc.
+
+
+// ---------------------------------------------------------------------------
+// Glue functions to bridge from UAE-generated code to the implemenations
+// we define.
+// ---------------------------------------------------------------------------
+
+void customreset (void)
+{
+ EmAssert (gSession);
+
+ gSession->ScheduleReset (kResetSoft);
+}
+
+
+void Exception (int nr, emuptr /*oldpc*/)
+{
+ EmAssert (gCPU68K);
+
+ gCPU68K->ProcessException ((ExceptionNumber) nr);
+}
+
+
+unsigned long op_illg (uint32 iOpcode)
+{
+ EmAssert (gCPU68K);
+
+ gCPU68K->ProcessIllegalInstruction (iOpcode);
+ return 0;
+}
+
+
+void Software_ProcessLINK (int32 linkSize)
+{
+ EmAssert (gCPU68K);
+
+ gCPU68K->ProcessLINK (linkSize);
+}
+
+
+int Software_ProcessRTS (emuptr dest)
+{
+ EmAssert (gCPU68K);
+
+ gCPU68K->CheckNewPC (dest);
+ return gCPU68K->ProcessRTS (dest);
+}
+
+
+int Software_ProcessRTE (emuptr dest)
+{
+ EmAssert (gCPU68K);
+
+ gCPU68K->CheckNewPC (dest);
+ return gCPU68K->ProcessRTE (dest);
+}
+
+
+int Software_ProcessJSR (emuptr oldpc, emuptr dest)
+{
+ EmAssert (gCPU68K);
+
+ gCPU68K->CheckNewPC (dest);
+ return gCPU68K->ProcessJSR (oldpc, dest);
+}
+
+
+int Software_ProcessJSR_Ind (emuptr oldpc, emuptr dest)
+{
+ EmAssert (gCPU68K);
+
+ return gCPU68K->ProcessJSR_Ind (oldpc, dest);
+}
+
+
+void Software_CheckNewPC (emuptr dest)
+{
+ EmAssert (gCPU68K);
+
+ gCPU68K->CheckNewPC (dest);
+}
+
+
+void Software_CheckStackPointerAssignment ()
+{
+ EmAssert (gCPU68K);
+
+ gCPU68K->CheckNewSP (kStackPointerChanged);
+}
+
+
+void Software_CheckStackPointerDecrement ()
+{
+ EmAssert (gCPU68K);
+
+ gCPU68K->CheckNewSP (kStackPointerDecremented);
+}
+
+
+void Software_CheckStackPointerIncrement ()
+{
+ EmAssert (gCPU68K);
+
+ gCPU68K->CheckNewSP (kStackPointerIncremented);
+}
+
+
+void Software_CheckKernelStack ()
+{
+ EmAssert (gCPU68K);
+
+ gCPU68K->CheckNewSP (kStackPointerKernelStackHack);
+}
+
+
+void MakeSR (void)
+{
+ EmAssert (gCPU68K);
+
+ gCPU68K->UpdateSRFromRegisters ();
+}
+
+
+void MakeFromSR (void)
+{
+ EmAssert (gCPU68K);
+
+ gCPU68K->UpdateRegistersFromSR ();
+}
+
+
+void* xmalloc (size_t size)
+{
+ return Platform::AllocateMemory (size);
+}
+
+uint32 get_disp_ea_000 (uint32 base, uint32 dp)
+{
+ int reg = (dp >> 12) & 15;
+ uae_s32 regd = regs.regs[reg];
+
+ if ((dp & 0x800) == 0)
+ regd = (uae_s32)(uae_s16)regd;
+
+ return base + (uae_s8)dp + regd;
+}
diff --git a/SrcShared/Hardware/EmUAEGlue.h b/SrcShared/Hardware/EmUAEGlue.h
new file mode 100644
index 0000000..cef39b8
--- /dev/null
+++ b/SrcShared/Hardware/EmUAEGlue.h
@@ -0,0 +1,17 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 1999-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.
+\* ===================================================================== */
+
+#ifndef EmUAEGlue_h
+#define EmUAEGlue_h
+
+#endif /* EmUAEGlue_h */
diff --git a/SrcShared/Hardware/EmUARTDragonball.cpp b/SrcShared/Hardware/EmUARTDragonball.cpp
new file mode 100644
index 0000000..40d6ac3
--- /dev/null
+++ b/SrcShared/Hardware/EmUARTDragonball.cpp
@@ -0,0 +1,936 @@
+/* -*- 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 "EmUARTDragonball.h"
+
+#include "EmHAL.h" // EmHAL, EmUARTDeviceType
+#include "EmTransportSerial.h" // EmTransportSerial
+#include "Logging.h" // LogAppendMsg
+#include "Preferences.h" // gEmuPrefs
+#include "ErrorHandling.h" // ReportErrCommPort
+
+
+/*
+ This module contains the routines for handling serial I/O. It
+ is responsible for responding to changes in state enacted by
+ software (from either the OS or user), and for dealing with
+ the actual transmission and reception of serial data.
+
+ There are four ways in which serial activity could occur: something
+ could write to a UART register, something could read from a UART
+ register, a byte could be received from the host serial port, or
+ a byte could be sent out the host serial port. Here is what
+ happens on each of those events.
+
+ Something reads a UART register:
+ - If the register is the RX_DATA register, clear the DATA_READY bit
+ - Make sure the state is up-to-date (including interrupts)
+ - Return the register contents
+
+ Something writes to a UART register:
+ - Update the writable parts of the register
+ - React to any changes
+ - Make sure the state is up-to-date (including interrupts)
+
+ Data appears at the host serial port:
+ - Post the byte to the RX FIFO (if there is room)
+ - Make sure the state is up-to-date (including interrupts)
+
+ Data needs to be sent to the host serial port:
+ - Send the first byte in the TX FIFO
+ - Make sure the state is up-to-date (including interrupts)
+*/
+
+
+// ======================================================================
+// Private functions
+// ======================================================================
+
+static const int kMaxFifoSize = 64;
+
+static Bool PrvPinBaud (EmTransportSerial::Baud& newBaud);
+static Bool PrvPinBaud (EmTransportSerial::Baud& newBaud,
+ EmTransportSerial::Baud testBaud);
+
+#define PRINTF if (!LogSerial ()) ; else LogAppendMsg
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmUARTDragonball::EmUARTDragonball
+ *
+ * DESCRIPTION: .
+ *
+ * PARAMETERS: type - the type of UART to emulate. The Dragonball
+ * and DragonballEZ UARTs are similar enough that we
+ * can handle them both here with just a few tests in
+ * the places where they differ.
+ *
+ * RETURNED: nothing
+ *
+ ***********************************************************************/
+
+EmUARTDragonball::EmUARTDragonball (UART_Type type, int uartNum) :
+ fUARTNum (uartNum),
+ fState (type),
+ fRxFIFO (this->PrvFIFOSize (true)),
+ fTxFIFO (this->PrvFIFOSize (false))
+{
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmUARTDragonball::~EmUARTDragonball
+ *
+ * DESCRIPTION: .
+ *
+ * PARAMETERS: none.
+ *
+ * RETURNED: nothing
+ *
+ ***********************************************************************/
+
+EmUARTDragonball::~EmUARTDragonball (void)
+{
+ // All line drivers are effectively disabled, so close the transports.
+
+ for (EmUARTDeviceType ii = kUARTBegin; ii < kUARTEnd; ++ii)
+ {
+ EmTransport* transport = gEmuPrefs->GetTransportForDevice (ii);
+
+ if (transport)
+ {
+ transport->Close ();
+ }
+ }
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmUARTDragonball::StateChanged
+ *
+ * DESCRIPTION: .
+ *
+ * PARAMETERS: none.
+ *
+ * RETURNED: nothing
+ *
+ ***********************************************************************/
+
+void EmUARTDragonball::StateChanged (State& newState, Bool sendTxData)
+{
+ EmAssert (fState.UART_TYPE == newState.UART_TYPE);
+
+ // (Changing the configuration is the only place where we assume that
+ // the transport we're using is a serial transport.)
+
+ EmTransportSerial::ConfigSerial config;
+ EmTransport* transport = this->GetTransport ();
+ EmTransportSerial* serTransport = dynamic_cast<EmTransportSerial*> (transport);
+
+ if (serTransport)
+ {
+ serTransport->GetConfig (config);
+ }
+
+
+ // ========== RX_ENABLE ==========
+ //
+ // This bit enables the receiver block. While this bit is low, the receiver is disabled and the
+ // receive FIFO is flushed. This bit resets to 0.
+
+ if (fState.RX_ENABLE != newState.RX_ENABLE)
+ {
+ if (newState.RX_ENABLE == 0)
+ {
+ fRxFIFO.Clear ();
+ }
+ }
+
+
+ // ========== TX_ENABLE ==========
+ //
+ // This bit enables the transmitter block. While this bit is low, the transmitter is disabled and
+ // the transmit FIFO is flushed. This bit resets to 0.
+
+ if (fState.TX_ENABLE != newState.TX_ENABLE)
+ {
+ if (newState.TX_ENABLE == 0)
+ {
+ fTxFIFO.Clear ();
+ }
+ }
+
+
+ // ========== PARITY_EN ==========
+ //
+ // This bit controls the parity generator in the transmitter and parity checker in the receiver.
+ // When this bit is high, they are enabled. When it is low, they are disabled.
+ //
+ // ========== ODD_EVEN ==========
+ //
+ // This bit controls the sense of the parity generator and checker. When this bit is high, odd
+ // parity is generated and expected. When this bit is low, even parity is generated and
+ // expected. This bit has no function if PARITY EN is low.
+
+ if (newState.PARITY_EN == 0)
+ {
+ config.fParity = EmTransportSerial::kNoParity;
+ }
+ else if (newState.ODD_EVEN)
+ {
+ config.fParity = EmTransportSerial::kOddParity;
+ }
+ else
+ {
+ config.fParity = EmTransportSerial::kEvenParity;
+ }
+
+
+ // ========== STOP_BITS =========
+ //
+ // This bit controls the number of stop bits transmitted after a character. When this bit is high,
+ // two stop bits are sent. When this bit is low, one stop bit is sent. This bit has no effect on the
+ // receiver, which expects one or more stop bits.
+
+ config.fStopBits = newState.STOP_BITS ? 2 : 1;
+
+
+ // ========== CHAR8_7 ==========
+ //
+ // This bit controls the character length. While high, the transmitter and receiver are in 8-bit
+ // mode. While low, they are in 7-bit mode. The transmitter then ignores B7 and the receiver
+ // sets B7 to 0.
+
+ config.fDataBits = newState.CHAR8_7 ? 8 : 7;
+
+
+ // ========== DIVIDE ==========
+ //
+ // These bits control the clock frequency produced by the baud rate generator.
+ //
+ // 000 = Divide by 1.
+ // 001 = Divide by 2.
+ // 010 = Divide by 4.
+ // 011 = Divide by 8.
+ // 100 = Divide by 16.
+ // 101 = Divide by 32.
+ // 110 = Divide by 64.
+ // 111 = Divide by 128.
+ //
+ // ========== PRESCALER ==========
+ //
+ // These bits control the division value of the baud generator prescaler. The division value is
+ // determined by the following formula:
+ //
+ // Prescaler division value = 65 (decimal) - PRESCALER
+
+ // Baud rate is sysClockFreq / preScaler / divider / 16
+ //
+ // (Using sysClockFreq / (preScaler * divider * 16) might get closer to the
+ // intended baud (as would using floating point), but does it mirror what
+ // the hardware actually does?)
+
+ int32 sysClockFreq = EmHAL::GetSystemClockFrequency ();
+ config.fBaud = sysClockFreq / (65 - newState.PRESCALER) / (1 << newState.DIVIDE) / 16;
+
+ // "newRate" is only approximate to within 0.1%. Pin the value to an
+ // exact value.
+ //
+ // !!! What to do if we can't pin to a valid value?
+
+ (void) PrvPinBaud (config.fBaud);
+
+
+ // ========== IGNORE_CTS ==========
+ //
+ // When this bit is high, it forces the CTS signal that is presented to the transmitter to always
+ // be asserted, which effectively ignores the external pin.
+
+ config.fHwrHandshake = newState.IGNORE_CTS == 0;
+
+
+ // ========== RTS_CONT ==========
+ //
+ // This bit selects the function of the RTS pin.
+ //
+ // 0 = RTS pin is controlled by the RTS bit.
+ // 1 = RTS pin is controlled by the receiver FIFO. When the FIFO is full (one slot is
+ // remaining), RTS is negated.
+ //
+ // ========== RTS ==========
+ //
+ // This bit controls the RTS pin while the RTS CONT bit is 0.
+ //
+ // 0 = RTS pin is 1.
+ // 1 = RTS pin is 0.
+
+ if (fState.RTS_CONT != newState.RTS_CONT ||
+ fState.RTS != newState.RTS)
+ {
+ if (serTransport)
+ {
+ if (newState.RTS_CONT)
+ {
+ serTransport->SetRTS (EmTransportSerial::kRTSAuto);
+ }
+ else
+ {
+ if (newState.RTS)
+ {
+ serTransport->SetRTS (EmTransportSerial::kRTSOn);
+ }
+ else
+ {
+ serTransport->SetRTS (EmTransportSerial::kRTSOff);
+ }
+ }
+ }
+ }
+
+
+ // ========== UART_ENABLE ==========
+ //
+ // This bit enables the UART module. When this bit is low, the UART module is disabled and
+ // in low-power mode. While this bit is high, the UART module is active. This bit resets to 0.
+
+ // ========== IRDA_ENABLE ==========
+ //
+ // This bit enables the IrDA interface.
+ //
+ // 0 = Normal NRZ operation.
+ // 1 = IRDA operation.
+
+ if (fState.UART_ENABLE != newState.UART_ENABLE ||
+ fState.IRDA_ENABLE != newState.IRDA_ENABLE)
+ {
+ // Nothing to do here.
+ }
+
+ // Establish the new settings. Do this only when the UART is
+ // enabled, to help reduce the thrashing on the host serial port,
+ // and to help prevent the installation of invalid settings (which
+ // could appear in the UART registers as it's being configured).
+
+ if (newState.UART_ENABLE)
+ {
+ if (serTransport)
+ {
+ serTransport->SetConfig (config);
+ }
+ }
+
+ // ========== SEND_BREAK ==========
+ //
+ // This bit forces the transmitter to immediately send continuous zeros creating a break
+ // character.
+
+ if (fState.SEND_BREAK != newState.SEND_BREAK)
+ {
+ if (serTransport)
+ {
+ serTransport->SetBreak (newState.SEND_BREAK);
+ }
+ }
+
+
+ // ========== TX_DATA ==========
+ //
+ // These bits are the parallel transmit-data inputs. In 7-bit mode, D7 is ignored and in 8-bit
+ // mode, all of the bits are used. Data is transmitted LSB first. A new character is transmitted
+ // when these bits are written and have passed through the FIFO.
+
+ // ========== LOOP ==========
+ //
+ // This bit controls loopback for system testing purposes. When this bit is high, the receiver
+ // input is internally connected to the transmitter and ignores the RXD pin. The TXD pin is
+ // unaffected by this bit.
+
+ if (sendTxData && newState.UART_ENABLE && newState.TX_ENABLE)
+ {
+ if (newState.LOOP == 0)
+ {
+ if (transport && transport->CanWrite ()) // The host serial port is open
+ {
+ // With or without hardware handshaking, we'll put data
+ // in the FIFO, and let the host's handshaking take care
+ // of when the data is removed from the FIFO.
+
+ if (fTxFIFO.GetFree () > 0) // There's room in the FIFO
+ {
+ fTxFIFO.Put (newState.TX_DATA); // so add the data
+
+ // Call TransmitTxFIFO here to send the data we
+ // just queued up. Doing this is important on the Mac in
+ // order to send out the data quickly instead of later at
+ // idle time.
+
+ this->TransmitTxFIFO (transport);
+ }
+ }
+ else // The host serial port is NOT open
+ {
+ if (config.fHwrHandshake) // Reflects the state of the IGNORE_CTS bit.
+ {
+ // With hardware handshaking, data is sent only when CTS
+ // is asserted. With no host serial port, we define that
+ // CTS is never asserted, so the data clogs up the FIFO.
+
+ if (fTxFIFO.GetFree () > 0) // There's room in the FIFO
+ {
+ fTxFIFO.Put (newState.TX_DATA); // so add the data
+
+ // Serial port is closed, so don't call Platform::TransmitTxFIFO.
+ }
+ }
+ else
+ {
+ // With no hardware handshaking, data is sent whenever it's
+ // ready. With nowhere to go, we can drop it on the floor.
+ }
+ }
+ }
+ else // We're in loopback mode.
+ {
+ if (fRxFIFO.GetFree () > 0)
+ {
+ fRxFIFO.Put (newState.TX_DATA);
+ }
+ }
+ }
+
+
+ // Update the state in case any of the above operations have side-effects.
+
+ UpdateState (newState, false);
+
+
+ // Remember this for next time.
+
+ fState = newState;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmUARTDragonball::UpdateState
+ *
+ * DESCRIPTION: Receive any data, and update the FIFO state registers.
+ *
+ * PARAMETERS: none.
+ *
+ * RETURNED: nothing
+ *
+ ***********************************************************************/
+
+void EmUARTDragonball::UpdateState (State& state, Bool refreshRxData)
+{
+ EmAssert (fState.UART_TYPE == state.UART_TYPE);
+
+ // Update the RxFIFO if there's been any buffered data.
+
+ EmTransport* transport = this->GetTransport ();
+ if (transport)
+ {
+ this->ReceiveRxFIFO (transport);
+ }
+
+ // === RX_FIFO_FULL ===
+ //
+ // This read-only bit indicates that the receiver FIFO is full and may generate an overrun. This
+ // bit generates a maskable interrupt.
+ //
+ // Further, from the overview section of the manual:
+ //
+ // If your software has a short interrupt
+ // latency time, the FIFO FULL interrupt in the Receiver register can be enabled. The FIFO has
+ // one remaining space available when this interrupt is generated.
+
+ state.RX_FIFO_FULL = fRxFIFO.GetFree () == 0;
+
+
+ // === RX_FIFO_HALF ===
+ //
+ // This read-only bit indicates that the receiver FIFO has four or fewer slots remaining in the
+ // FIFO. This bit generates a maskable interrupt.
+
+ state.RX_FIFO_HALF = fRxFIFO.GetFree () <= this->PrvLevelMarker (true);
+
+
+ // === DATA_READY ===
+ //
+ // This read-only bit indicates that at least one byte is present in the receive FIFO. The
+ // character bits are valid only while this bit is set. This bit generates a maskable interrupt.
+
+ state.DATA_READY = fRxFIFO.GetUsed () > 0;
+
+
+ // === OLD_DATA === // non-68328 only
+ //
+ // This read-only bit indicates that data in the FIFO is older than 30 bit times. It is useful in
+ // situations where the FIFO FULL or FIFO HALF interrupts are used. If there is data in the
+ // FIFO, but below the interrupt threshold, a maskable interrupt can be generated to alert the
+ // software that unread data is present. This bit clears when the character bits are read.
+
+ // Not supported right now.
+
+
+ // === OVRUN ===
+ //
+ // When this read-only bit is high, it indicates that the receiver overwrote data in the FIFO. The
+ // character with this bit set is valid, but at least one previous character was lost. In normal
+ // circumstances, this bit should never be set. It indicates that your software is not keeping up
+ // with the incoming data rate. This bit is updated and valid for each received character.
+
+ // !!! TBD
+
+
+ // === FRAME_ERROR ===
+ //
+ // While high, this read-only bit indicates that the current character had a framing error
+ // (missing stop bit), indicating the possibility of corrupted data. This bit is updated for each
+ // character read from the FIFO.
+
+ // !!! TBD
+
+
+ // === BREAK ===
+ //
+ // When this read-only bit is high, it indicates that the current character was detected as a
+ // BREAK. The data bits are all 0 and the stop bit was also 0. The FRAME ERROR bit will
+ // always be set when this bit is set. If odd parity is selected, PARITY ERROR will also be set
+ // along with this bit. This bit is updated and valid with each character read from the FIFO.
+
+ // !!! TBD
+
+ // === PARITY_ERROR ===
+ //
+ // When this read-only bit is high, it indicates that the current character was detected with a
+ // parity error, indicating the possibility of corrupted data. This bit is updated and valid with
+ // each character read from the FIFO. While parity is disabled, this bit always reads zero.
+
+ // !!! TBD
+
+ // === RX_DATA ===
+ //
+ // These read-only bits are the top receive character in the FIFO. They have no meaning if the
+ // DATA READY bit is 0. In 7-bit mode, the MSB is forced to 0 and in 8-bit mode, all bits are
+ // active.
+
+ if (state.DATA_READY && state.UART_ENABLE && state.RX_ENABLE && refreshRxData)
+ {
+ state.RX_DATA = fRxFIFO.Get ();
+
+ if (state.CHAR8_7 == 0)
+ {
+ state.RX_DATA &= 0x07F;
+ }
+
+ PRINTF ("UART: Put 0x%02X into RX_DATA.", (uint32) (uint8) state.RX_DATA);
+ }
+
+
+ // === TX_FIFO_EMPTY ===
+ //
+ // This read-only bit indicates that the transmit FIFO is empty. This bit generates a maskable
+ // interrupt.
+
+ state.TX_FIFO_EMPTY = fTxFIFO.GetUsed () == 0;
+
+
+ // === TX_FIFO_HALF ===
+ //
+ // This read-only bit indicates that the transmit FIFO is less than half full. This bit generates a
+ // maskable interrupt.
+
+ state.TX_FIFO_HALF = fTxFIFO.GetUsed () < this->PrvLevelMarker (false);
+
+
+ // === TX_AVAIL ===
+ //
+ // This read-only bit indicates that the transmit FIFO has at least one slot available for data.
+ // This bit generates a maskable interrupt.
+
+ state.TX_AVAIL = fTxFIFO.GetFree () > 0;
+
+
+ // === BUSY === // non-68328 only
+ //
+ // When this bit is high, it indicates that the transmitter is busy sending a character. This signal
+ // is asserted while the transmitter state machine is not idle or the FIFO has data in it.
+
+ state.BUSY = !state.TX_FIFO_EMPTY;
+
+
+ // === CTS_STATUS ===
+ //
+ // This bit indicates the current status of the CTS pin. A "snapshot" of the pin is taken
+ // immediately before this bit is presented to the data bus. While the IGNORE CTS bit is high,
+ // this bit can serve as a general-purpose input.
+ //
+ // Note that this pin is ACTIVE LOW! That's why the Boolean expression is negated below.
+ //
+ // For now, say that it's clear to send if the FIFO is empty
+ //
+ // !!! TBD - could be better?
+
+ state.CTS_STATUS = !(fTxFIFO.GetUsed () == 0);
+
+
+ // === CTS_DELTA ===
+ //
+ // When this bit is high, it indicates that the CTS pin changed state and generates a maskable
+ // interrupt. The current state of the CTS pin is available on the CTS STATUS bit. You can
+ // generate an immediate interrupt by setting this bit high. The CTS interrupt is cleared by
+ // writing 0 to this bit.
+
+ // Not supported right now.
+
+
+ // Remember this for next time.
+
+ fState = state;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmUARTDragonball::TransmitTxFIFO
+ *
+ * DESCRIPTION: Transmit any bytes in the TX FIFO out the serial port.
+ * Assumes that the serial port is open.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmUARTDragonball::TransmitTxFIFO (EmTransport* transport)
+{
+ EmAssert (transport);
+
+ if (transport->CanWrite ())
+ {
+ // Write out any outgoing bytes.
+
+ ErrCode err = errNone;
+ char buffer[kMaxFifoSize];
+ long spaceInTxFIFO = fTxFIFO.GetUsed ();
+
+ if (spaceInTxFIFO > 0)
+ {
+ for (long ii = 0; ii < spaceInTxFIFO; ++ii)
+ {
+ buffer[ii] = fTxFIFO.Get ();
+ }
+
+ if (LogSerialData ())
+ LogAppendData (buffer, spaceInTxFIFO, "UART: Transmitted data:");
+ else
+ PRINTF ("UART: Transmitted %ld serial bytes.", spaceInTxFIFO);
+
+ err = transport->Write (spaceInTxFIFO, buffer);
+ }
+ }
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmUARTDragonball::ReceiveRxFIFO
+ *
+ * DESCRIPTION: Fills up the RX FIFO with as many bytes as it can from
+ * the host serial port. Assumes that the serial port is
+ * open.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmUARTDragonball::ReceiveRxFIFO (EmTransport* transport)
+{
+ EmAssert (transport);
+
+ if (transport->CanRead ())
+ {
+ // Buffer up any incoming bytes.
+
+ ErrCode err = errNone;
+ char buffer[kMaxFifoSize];
+ long spaceInRxFIFO = fRxFIFO.GetFree ();
+
+ // See how many bytes are waiting.
+
+ long bytesToBuffer = transport->BytesInBuffer (fRxFIFO.GetMaxSize ());
+
+ // See if we have that much room in the FIFO. If not, limit our read
+ // to that many bytes.
+
+ if (bytesToBuffer > spaceInRxFIFO)
+ {
+ bytesToBuffer = spaceInRxFIFO;
+ }
+
+ // If there is data waiting in the wings, and the hardware says it's
+ // OK to receive data, and there's room in the RxFIFO, then receive it.
+ //
+ // It's OK to receive data if RTS_CONT is 1. That means that the FIFO
+ // controls whether or not it's OK to receive data, and that check
+ // is taken care of with "bytesToBuffer > 0".
+ //
+ // If RTS_CONT is zero, then it's OK to receive data if RTS is 1. That
+ // mean that the /RTS pin is zero, which means OK to receive.
+
+ if (bytesToBuffer > 0 && (fState.RTS_CONT == 1 || fState.RTS == 1))
+ {
+ // If there are still bytes to be read, read them in and insert them
+ // into the RX FIFO. If the buffer was previously empty, Hardware::Cycle
+ // will notice that there are now bytes in there and update the
+ // UART registers.
+ //
+ // !!! TBD: Hardware::Cycle is called after every opcode execution.
+ // Since it is very rare that serial bytes are coming in, the overhead
+ // incurred for checking to see if there are serial bytes does not pay
+ // off. We may want to figure out a way to update the UART registers
+ // here, and take the check out of Hardware::Cycle. I'd do that here,
+ // but (a) Hardware::Cycle takes a "sleeping" parameter that I'd have
+ // to determine here, and (b) the similar solution on Windows is more
+ // difficult, as I'd have to stop the CPU thread, update the registers,
+ // and restart the thread.
+
+ err = transport->Read (bytesToBuffer, buffer);
+
+ if (err == errNone)
+ {
+ // not quite the correct phrase for IR over serial (over TCP)
+ if (LogSerialData ())
+ LogAppendData (buffer, bytesToBuffer, "UART: Received data:");
+ else
+ PRINTF ("UART: Received %ld serial bytes.", bytesToBuffer);
+
+ for (long ii = 0; ii < bytesToBuffer; ++ii)
+ {
+ fRxFIFO.Put (buffer[ii]);
+ } // end loop that puts bytes into FIFO
+ } // end no-error-from-EmTransport::Read
+ } // end BytesInBuffer-returned-non-zero
+ } // end is-serial-port-open
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmUARTDragonball::GetTransport
+ *
+ * DESCRIPTION: .
+ *
+ * PARAMETERS: .
+ *
+ * RETURNED: .
+ *
+ ***********************************************************************/
+
+EmTransport* EmUARTDragonball::GetTransport (void)
+{
+ EmUARTDeviceType type = EmHAL::GetUARTDevice (fUARTNum);
+ EmTransport* transport = gEmuPrefs->GetTransportForDevice (type);
+
+ return transport;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmUARTDragonball::PrvFIFOSize
+ *
+ * DESCRIPTION: .
+ *
+ * PARAMETERS: .
+ *
+ * RETURNED: .
+ *
+ ***********************************************************************/
+
+int EmUARTDragonball::PrvFIFOSize (Bool forRX)
+{
+ int size;
+
+ switch (fState.UART_TYPE)
+ {
+ case kUART_Dragonball:
+ size = 8;
+ break;
+
+ case kUART_DragonballEZ:
+ if (forRX)
+ {
+ size = 12;
+ }
+ else
+ {
+ size = 8;
+ }
+ break;
+
+ case kUART_DragonballVZ:
+ if (this->fUARTNum == 0)
+ {
+ if (forRX)
+ {
+ size = 12;
+ }
+ else
+ {
+ size = 8;
+ }
+ }
+ else
+ {
+ size = 64;
+ }
+ break;
+
+ default:
+ EmAssert (false);
+ size = 8;
+ break;
+ }
+
+ return size;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmUARTDragonball::PrvLevelMarker
+ *
+ * DESCRIPTION: .
+ *
+ * PARAMETERS: .
+ *
+ * RETURNED: .
+ *
+ ***********************************************************************/
+
+int EmUARTDragonball::PrvLevelMarker (Bool forRX)
+{
+ int level = (forRX ? fRxFIFO.GetMaxSize () : fTxFIFO.GetMaxSize ()) / 2;
+
+ switch (fState.UART_TYPE)
+ {
+ case kUART_Dragonball:
+ break;
+
+ case kUART_DragonballEZ:
+ break;
+
+ case kUART_DragonballVZ:
+ if (this->fUARTNum == 1)
+ {
+ int marker = forRX ? fState.TXFIFO_LEVEL_MARKER : fState.RXFIFO_LEVEL_MARKER;
+
+ if (marker != 0)
+ {
+ level = marker * 4;
+ }
+ }
+ break;
+
+ default:
+ EmAssert (false);
+ break;
+ }
+
+ return level;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: PrvPinBaud
+ *
+ * DESCRIPTION: Pins the given baud value to the test baud value if the
+ * former is sufficiently close to the latter.
+ *
+ * PARAMETERS: newBaud - the value to possibly alter.
+ *
+ * testBaud - the value to pin to.
+ *
+ * RETURNED: newBaud is changed in place. If it is changed, the
+ * function returns true. Otherwise, it returns false.
+ *
+ ***********************************************************************/
+
+Bool PrvPinBaud (EmTransportSerial::Baud& newBaud)
+{
+ Bool pinned = false;
+
+ if (!pinned) pinned = PrvPinBaud (newBaud, 150);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 300);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 600);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 1200);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 1800);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 2400);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 3600);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 4800);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 7200);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 9600);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 14400);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 19200);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 28800);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 38400);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 57600);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 115200);
+ if (!pinned) pinned = PrvPinBaud (newBaud, 230400);
+
+ return pinned;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: PrvPinBaud
+ *
+ * DESCRIPTION: Pins the given baud value to the test baud value if the
+ * former is sufficiently close to the latter.
+ *
+ * PARAMETERS: newBaud - the value to possibly alter.
+ *
+ * testBaud - the value to pin to.
+ *
+ * RETURNED: newBaud is changed in place. If it is changed, the
+ * function returns true. Otherwise, it returns false.
+ *
+ ***********************************************************************/
+
+Bool PrvPinBaud (EmTransportSerial::Baud& newBaud, EmTransportSerial::Baud testBaud)
+{
+ // Pin to within 2%. The Dragonball reference says that the uBaud
+ // register should be accurate to within 0.1%, but let's give it
+ // some slop.
+
+ if (newBaud > (testBaud - (testBaud / 50)) &&
+ newBaud < (testBaud + (testBaud / 50)))
+ {
+ newBaud = testBaud;
+ return true;
+ }
+
+ return false;
+}
diff --git a/SrcShared/Hardware/EmUARTDragonball.h b/SrcShared/Hardware/EmUARTDragonball.h
new file mode 100644
index 0000000..8c777be
--- /dev/null
+++ b/SrcShared/Hardware/EmUARTDragonball.h
@@ -0,0 +1,149 @@
+/* -*- 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.
+\* ===================================================================== */
+
+#ifndef EmUARTDragonball_h
+#define EmUARTDragonball_h
+
+#include "EmThreadSafeQueue.h" // EmByteQueue
+
+class EmTransport;
+class SessionFile;
+
+
+class EmUARTDragonball
+{
+ public:
+ enum UART_Type
+ {
+ kUART_Dragonball,
+ kUART_DragonballEZ,
+ kUART_DragonballVZ,
+ kUART_DragonballSZ
+ };
+
+ struct State
+ {
+ State (UART_Type type) { UART_TYPE = type; }
+
+ UART_Type UART_TYPE;
+
+ // + = Supported
+ // = Unsupported
+ // -> = Input value
+ // <- = Output value
+
+ // UART control register bits
+ // These are all values the user sets; we just look at them.
+
+ /* + -> */ unsigned int UART_ENABLE:1;
+ /* + -> */ unsigned int RX_ENABLE:1;
+ /* + -> */ unsigned int TX_ENABLE:1;
+ /* -> */ unsigned int RX_CLK_CONT:1;
+ /* + -> */ unsigned int PARITY_EN:1;
+ /* + -> */ unsigned int ODD_EVEN:1;
+ /* + -> */ unsigned int STOP_BITS:1;
+ /* + -> */ unsigned int CHAR8_7:1;
+ /* -> */ unsigned int GPIO_DELTA_ENABLE:1; // 68328 only
+ /* -> */ unsigned int OLD_ENABLE:1; // 68EZ328 only
+ /* -> */ unsigned int CTS_DELTA_ENABLE:1;
+ /* + -> */ unsigned int RX_FULL_ENABLE:1;
+ /* + -> */ unsigned int RX_HALF_ENABLE:1;
+ /* + -> */ unsigned int RX_RDY_ENABLE:1;
+ /* + -> */ unsigned int TX_EMPTY_ENABLE:1;
+ /* + -> */ unsigned int TX_HALF_ENABLE:1;
+ /* + -> */ unsigned int TX_AVAIL_ENABLE:1;
+
+ // Baud control register bits
+ // These are all values the user sets; we just look at them.
+
+ /* -> */ unsigned int GPIO_DELTA:1; // 68328 only
+ /* -> */ unsigned int GPIO:1; // 68328 only
+ /* -> */ unsigned int GPIO_DIR:1; // 68328 only
+ /* -> */ unsigned int GPIO_SRC:1; // 68328 only
+ /* -> */ unsigned int UCLK_DIR:1; // 68EZ328 only
+ /* -> */ unsigned int BAUD_SRC:1;
+ /* + -> */ unsigned int DIVIDE;
+ /* + -> */ unsigned int PRESCALER;
+
+ // Receive register bits
+ // These are all input bits; we set them, not the user.
+
+ /* + <- */ unsigned int RX_FIFO_FULL:1;
+ /* + <- */ unsigned int RX_FIFO_HALF:1;
+ /* + <- */ unsigned int DATA_READY:1;
+ /* <- */ unsigned int OLD_DATA:1; // 68EZ328 only
+ /* <- */ unsigned int OVRUN:1;
+ /* <- */ unsigned int FRAME_ERROR:1;
+ /* <- */ unsigned int BREAK:1;
+ /* <- */ unsigned int PARITY_ERROR:1;
+ /* + <- */ unsigned int RX_DATA;
+
+ // Transmitter register bits
+ // The user sets TX_DATA, IGNORE_CTS, and SEND_BREAK.
+ // We set the rest.
+
+ /* + <- */ unsigned int TX_FIFO_EMPTY:1;
+ /* + <- */ unsigned int TX_FIFO_HALF:1;
+ /* + <- */ unsigned int TX_AVAIL:1;
+ /* -> */ unsigned int SEND_BREAK:1;
+ /* + -> */ unsigned int IGNORE_CTS:1;
+ /* + <- */ unsigned int BUSY:1; // 68EZ328 only
+ /* + <- */ unsigned int CTS_STATUS:1;
+ /* <- */ unsigned int CTS_DELTA:1;
+ /* + -> */ unsigned int TX_DATA;
+
+ // Misc register bits
+ // These are all values the user sets; we just look at them.
+
+ /* -> */ unsigned int BAUD_TEST:1; // 68EZ328 only
+ /* -> */ unsigned int CLK_SRC:1;
+ /* -> */ unsigned int FORCE_PERR:1;
+ /* + -> */ unsigned int LOOP:1;
+ /* -> */ unsigned int BAUD_RESET:1; // 68EZ328 only
+ /* -> */ unsigned int IR_TEST:1; // 68EZ328 only
+ /* + -> */ unsigned int RTS_CONT:1;
+ /* + -> */ unsigned int RTS:1;
+ /* + -> */ unsigned int IRDA_ENABLE:1;
+ /* -> */ unsigned int IRDA_LOOP:1;
+ /* -> */ unsigned int RX_POL:1; // 68EZ328 only
+ /* -> */ unsigned int TX_POL:1; // 68EZ328 only
+
+ // Level Marker Interrupt
+
+ /* + -> */ unsigned int TXFIFO_LEVEL_MARKER:4; // 68SZ328 only
+ /* + -> */ unsigned int RXFIFO_LEVEL_MARKER:4; // 68SZ328 only
+ };
+
+ EmUARTDragonball (UART_Type, int uartNum);
+ ~EmUARTDragonball (void);
+
+ void StateChanged (State&, Bool sendRxData);
+ void UpdateState (State&, Bool refreshRxData);
+
+ void TransmitTxFIFO (EmTransport*);
+ void ReceiveRxFIFO (EmTransport*);
+
+ EmTransport* GetTransport (void);
+
+ private:
+ int PrvFIFOSize (Bool forRX);
+ int PrvLevelMarker (Bool forRX);
+
+ private:
+ int fUARTNum;
+ State fState;
+ EmByteQueue fRxFIFO;
+ EmByteQueue fTxFIFO;
+};
+
+#endif /* EmUARTDragonball_h */
diff --git a/SrcShared/Hardware/TRG/EmHandEra330Defs.h b/SrcShared/Hardware/TRG/EmHandEra330Defs.h
new file mode 100644
index 0000000..4b2e3a5
--- /dev/null
+++ b/SrcShared/Hardware/TRG/EmHandEra330Defs.h
@@ -0,0 +1,40 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+#ifndef EmHandEra330Defs_h
+#define EmHandEra330Defs_h
+
+#include "EmHandEraCFBus.h"
+#include "EmHandEraSDBus.h"
+
+#define HE330_NUM_KEY_ROWS 4
+
+typedef struct {
+ uint16 Row[HE330_NUM_KEY_ROWS];
+} HandEra330Keys;
+
+typedef struct {
+ HandEra330Keys Keys;
+ CFBusManager CFBus;
+ SDBusManager SDBus;
+ Bool LCDOn;
+ Bool BacklightOn;
+ Bool IRPortOn;
+ Bool SenseCurrent;
+ Bool pendingIRQ2;
+ Bool CFInserted;
+ Bool SDInserted;
+ Bool PowerConnected;
+ Bool SDChipSelect;
+} HandEra330PortManager;
+
+#endif // EmHandEra330Defs_h
diff --git a/SrcShared/Hardware/TRG/EmHandEraCFBus.h b/SrcShared/Hardware/TRG/EmHandEraCFBus.h
new file mode 100644
index 0000000..8a1fadd
--- /dev/null
+++ b/SrcShared/Hardware/TRG/EmHandEraCFBus.h
@@ -0,0 +1,28 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmHandEraCFBus_h
+#define EmHandEraCFBus_h
+
+enum CFBusWidth {
+ kCFBusWidth8,
+ kCFBusWidth16
+};
+
+typedef struct {
+ int bEnabled;
+ enum CFBusWidth Width;
+ int bSwapped;
+} CFBusManager;
+
+#endif // EmHandEraBusDefs_h
diff --git a/SrcShared/Hardware/TRG/EmHandEraSDBus.h b/SrcShared/Hardware/TRG/EmHandEraSDBus.h
new file mode 100644
index 0000000..6853244
--- /dev/null
+++ b/SrcShared/Hardware/TRG/EmHandEraSDBus.h
@@ -0,0 +1,22 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmHandEraSDBus_h
+#define EmHandEraSDBus_h
+
+typedef struct {
+ int bEnabled;
+ int bSwapped;
+} SDBusManager;
+
+#endif // EmHandEraBusDefs_h
diff --git a/SrcShared/Hardware/TRG/EmRegs330CPLD.cpp b/SrcShared/Hardware/TRG/EmRegs330CPLD.cpp
new file mode 100644
index 0000000..bc1ed57
--- /dev/null
+++ b/SrcShared/Hardware/TRG/EmRegs330CPLD.cpp
@@ -0,0 +1,263 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmRegs330CPLD.h"
+
+#include "EmHAL.h" // EmHAL::LineDriverChanged
+#include "EmHandEra330Defs.h"
+#include "EmMemory.h"
+#include "EmScreen.h" // EmScreenUpdateInfo
+
+/*****************************************************************************
+ * The HandEra 330 uses a CPLD for additional GPIO
+ * This includes:
+ * CF & SD bus control, keyboard row drivers, LCD control, Backlight, IRDA,
+ * RS232 DTR signal, current vs voltage sense, and audio control.
+ *
+ * POSE needs to know about LCD, backlight, keyboard, and current sense so these
+ * are stored in an external HandEra330PortManager class that the EmRegsVZHandEra330
+ * class can get the values from.
+ ****************************************************************************/
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs330CPLD::EmRegs330CPLD
+// ---------------------------------------------------------------------------
+EmRegs330CPLD::EmRegs330CPLD (HandEra330PortManager * fPortManager)
+{
+ Reg0 = Cpld0Edo;
+ Reg2 = Cpld2CfDetect |
+ Cpld2NoSdDetect |
+ Cpld2NoExPwrDetect |
+ Cpld2SdUnwriteProt |
+ Cpld2SdPowerOff |
+ Cpld2Kbd3Inactive |
+ Cpld2Kbd2Inactive |
+ Cpld2Kbd1Inactive |
+ Cpld2Kbd0Inactive |
+ Cpld2NoReset |
+ Cpld2CfBufsOff |
+ Cpld2SwapOff |
+ Cpld2CfPowerOff |
+ Cpld2BusWidth16;
+ Reg4 = Cpld4LcdBiasOff |
+ Cpld4LcdVccOn |
+ Cpld4LcdOff |
+ Cpld4BlPdOff |
+ Cpld4DtrOff |
+ Cpld4MmcCsOn |
+ Cpld4FiltSdOff |
+ Cpld4Rs232Off |
+ Cpld4IrdaOff |
+ Cpld4MicOff |
+ Cpld4SenseVoltage;
+ fPortMgr = fPortManager;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs330CPLD::~EmRegs330CPLD
+// ---------------------------------------------------------------------------
+
+EmRegs330CPLD::~EmRegs330CPLD (void)
+{
+}
+
+void EmRegs330CPLD::Reset(Bool /*hardwareReset*/)
+{
+ fPortMgr->Keys.Row[0] = 1;
+ fPortMgr->Keys.Row[1] = 1;
+ fPortMgr->Keys.Row[2] = 1;
+ fPortMgr->Keys.Row[3] = 1;
+ fPortMgr->LCDOn = false;
+ fPortMgr->BacklightOn = false;
+ fPortMgr->IRPortOn = false;
+ fPortMgr->CFBus.bEnabled = false;
+ fPortMgr->CFBus.Width = kCFBusWidth16;
+ fPortMgr->CFBus.bSwapped = false;
+ fPortMgr->pendingIRQ2 = false;
+ fPortMgr->SDChipSelect = false;
+ fPortMgr->PowerConnected = false;
+}
+
+// -------------------------------------------------------------------------
+// ¥ EmRegs330CPLD::SetSubBankHandlers
+// ---------------------------------------------------------------------------
+void EmRegs330CPLD::SetSubBankHandlers (void)
+{
+ // Install base handlers.
+
+ EmRegs::SetSubBankHandlers();
+ // Now add standard/specialized handers for the defined registers.
+ this->SetHandler((ReadFunction)&EmRegs330CPLD::Read,
+ (WriteFunction)&EmRegs330CPLD::Write,
+ kMemoryStartCPLD,
+ kMemorySizeCPLD);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs330CPLD::GetRealAddress
+// ---------------------------------------------------------------------------
+uint8 * EmRegs330CPLD::GetRealAddress (emuptr address)
+{
+ return (address-kMemoryStartCPLD) + Buffer;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs330CPLD::GetWord
+// ---------------------------------------------------------------------------
+uint32 EmRegs330CPLD::GetWord (emuptr address)
+{
+ uint32 offset = address - kMemoryStartCPLD;
+
+ switch (offset)
+ {
+ case CpldReg00 :
+ return Cpld0Edo;
+
+ case CpldReg02 :
+ if (fPortMgr->CFInserted)
+ Reg2 &= ~Cpld2NoCfDetect;
+ else
+ Reg2 |= Cpld2NoCfDetect;
+ if (fPortMgr->SDInserted)
+ Reg2 &= ~Cpld2NoSdDetect;
+ else
+ Reg2 |= Cpld2NoSdDetect;
+ if (fPortMgr->PowerConnected)
+ Reg2 &= ~Cpld2NoExPwrDetect;
+ else
+ Reg2 |= Cpld2NoExPwrDetect;
+ return (Reg2);
+
+ case CpldReg04 :
+ return (Reg4);
+
+ default :
+ return 0;
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs330CPLD::SetWord
+// ---------------------------------------------------------------------------
+void EmRegs330CPLD::SetWord (emuptr address, uint32 val)
+{
+ uint32 offset = address - kMemoryStartCPLD;
+
+ switch (offset)
+ {
+ case CpldReg00 :
+ fPortMgr->pendingIRQ2 = false;
+ break;
+
+ case CpldReg02 :
+ Reg2 = (val & 0x0fff) | (Reg2 & 0xf000); // top 4 bits are read only.
+
+ // keys:
+ fPortMgr->Keys.Row[3] = (Reg2 & Cpld2Kbd3Inactive) ? 0 : 1;
+ fPortMgr->Keys.Row[2] = (Reg2 & Cpld2Kbd2Inactive) ? 0 : 1;
+ fPortMgr->Keys.Row[1] = (Reg2 & Cpld2Kbd1Inactive) ? 0 : 1;
+ fPortMgr->Keys.Row[0] = (Reg2 & Cpld2Kbd0Inactive) ? 0 : 1;
+
+ // CF:
+ fPortMgr->CFBus.bEnabled = (Reg2 & Cpld2CfBufsOn);
+ if (Reg2 & Cpld2BusWidth8)
+ {
+ fPortMgr->CFBus.Width = kCFBusWidth8;
+
+ // HandEra330 byte swapping is not the same as the TRGpro when
+ // in byte mode. On the TRGpro it must be enabled to access bytes
+ // correctly, on the 330 it will work either way...
+ // Fudge it here to be the same as TRGpro so code can be shared.
+ fPortMgr->CFBus.bSwapped = true;
+ }
+ else
+ {
+ fPortMgr->CFBus.Width = kCFBusWidth16;
+ fPortMgr->CFBus.bSwapped = (Reg2 & Cpld2SwapOn);
+ }
+
+ break;
+
+ case CpldReg04 :
+ Bool backlightWasOn = fPortMgr->BacklightOn;
+ Bool lcdWasOn = fPortMgr->LCDOn;
+ Bool irWasOn = fPortMgr->IRPortOn;
+
+ Reg4 = val;
+
+ fPortMgr->LCDOn = (Reg4 & Cpld4LcdBiasOn);
+ fPortMgr->BacklightOn = (Reg4 & Cpld4BlPdOn);
+ fPortMgr->IRPortOn = (Reg4 & Cpld4IrdaOff) == 0;
+ fPortMgr->SenseCurrent = (Reg4 & Cpld4SenseCurrent);
+ fPortMgr->SDChipSelect = ((Reg4 & Cpld4MmcCsOn) == 0);
+
+ if ((fPortMgr->LCDOn != lcdWasOn) || (fPortMgr->BacklightOn != backlightWasOn))
+ EmScreen::InvalidateAll ();
+
+ if (irWasOn != fPortMgr->IRPortOn)
+ EmHAL::LineDriverChanged (kUARTIR);
+
+ break;
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs330CPLD::GetAddressStart
+// ---------------------------------------------------------------------------
+emuptr EmRegs330CPLD::GetAddressStart (void)
+{
+ return (kMemoryStartCPLD);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs330CPLD::GetAddressRange
+// ---------------------------------------------------------------------------
+uint32 EmRegs330CPLD::GetAddressRange (void)
+{
+ return kMemorySizeCPLD;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs330CPLD::Read
+// ---------------------------------------------------------------------------
+uint32 EmRegs330CPLD::Read(emuptr address, int size)
+{
+ switch(size)
+ {
+// case sizeof(uint8) :
+// return(GetByte(address));
+ case sizeof(uint16) :
+ return(GetWord(address));
+ }
+ return 0;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegs330CPLD::Write
+// ---------------------------------------------------------------------------
+void EmRegs330CPLD::Write(emuptr address, int size, uint32 val)
+{
+ switch(size)
+ {
+// case sizeof(uint8) :
+// SetByte(address, val);
+// break;
+ case sizeof(uint16) :
+ SetWord(address, val);
+ break;
+ }
+}
+
diff --git a/SrcShared/Hardware/TRG/EmRegs330CPLD.h b/SrcShared/Hardware/TRG/EmRegs330CPLD.h
new file mode 100644
index 0000000..08487aa
--- /dev/null
+++ b/SrcShared/Hardware/TRG/EmRegs330CPLD.h
@@ -0,0 +1,144 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+#ifndef EmRegs330CPLD_h
+#define EmRegs330CPLD_h
+
+#include "EmRegs.h"
+#include "EmHandEra330Defs.h"
+
+#define CpldReg00 0x0000
+// CPLD Register 0x0000 Bit Definitions
+// -------------------------------------
+ #define Cpld0Edo 0x0002
+ #define Cpld0Sdram 0x0000
+
+#define CpldReg02 0x0002
+// CPLD Register 0x0002 Bit Definitions
+// -------------------------------------
+ #define Cpld2NoCfDetect 0x8000
+ #define Cpld2CfDetect 0x0000
+
+ #define Cpld2NoSdDetect 0x4000
+ #define Cpld2SdDetect 0x0000
+
+ #define Cpld2NoExPwrDetect 0x2000
+ #define Cpld2ExPwrDetect 0x0000
+
+ #define Cpld2SdUnwriteProt 0x0000
+ #define Cpld2SdWriteProt 0x1000
+
+ #define Cpld2SdPowerOn 0x0000
+ #define Cpld2SdPowerOff 0x0200
+
+ #define Cpld2Kbd3Active 0x0000
+ #define Cpld2Kbd3Inactive 0x0100
+
+ #define Cpld2Kbd2Active 0x0000
+ #define Cpld2Kbd2Inactive 0x0080
+
+ #define Cpld2Kbd1Active 0x0000
+ #define Cpld2Kbd1Inactive 0x0040
+
+ #define Cpld2Kbd0Active 0x0000
+ #define Cpld2Kbd0Inactive 0x0020
+
+ #define Cpld2NoReset 0x0000
+ #define Cpld2Reset 0x0010
+
+ #define Cpld2CfBufsOff 0x0000
+ #define Cpld2CfBufsOn 0x0008
+
+ #define Cpld2SwapOff 0x0000
+ #define Cpld2SwapOn 0x0004
+
+ #define Cpld2CfPowerOn 0x0000
+ #define Cpld2CfPowerOff 0x0002
+
+ #define Cpld2BusWidth16 0x0000
+ #define Cpld2BusWidth8 0x0001
+
+#define CpldReg04 0x0004
+// CPLD Register 0x0004 Bit Definitions
+// -------------------------------------
+ #define Cpld4LcdBiasOff 0x0000
+ #define Cpld4LcdBiasOn 0x0400
+
+ #define Cpld4LcdVccOn 0x0000
+ #define Cpld4LcdVccOff 0x0200
+
+ #define Cpld4LcdOff 0x0000
+ #define Cpld4LcdON 0x0100
+
+ #define Cpld4BlPdOff 0x0000
+ #define Cpld4BlPdOn 0x0080
+
+ #define Cpld4DtrOn 0x0000
+ #define Cpld4DtrOff 0x0040
+
+ #define Cpld4MmcCsOff 0x0000
+ #define Cpld4MmcCsOn 0x0020
+
+ #define Cpld4FiltSdOff 0x0000
+ #define Cpld4FiltSdOn 0x0010
+
+ #define Cpld4Rs232Off 0x0000
+ #define Cpld4Rs232On 0x0008
+
+ #define Cpld4IrdaOn 0x0000
+ #define Cpld4IrdaOff 0x0004
+
+ #define Cpld4MicOn 0x0000
+ #define Cpld4MicOff 0x0002
+
+ #define Cpld4SenseVoltage 0x0000
+ #define Cpld4SenseCurrent 0x0001
+
+
+const uint32 kMemoryStartCPLD = 0x10E00000;
+const uint32 kMemorySizeCPLD = 0x100;
+
+class EmRegs330CPLD : public EmRegs
+{
+ public:
+ EmRegs330CPLD (HandEra330PortManager * fPortManager);
+ virtual ~EmRegs330CPLD (void);
+
+ virtual void Reset (Bool hardwareReset);
+
+ uint8* GetRealAddress (emuptr address);
+ void SetSubBankHandlers (void);
+ emuptr GetAddressStart (void);
+ uint32 GetAddressRange (void);
+
+ uint32 GetWord (emuptr iAddress);
+ void SetWord (emuptr iAddress, uint32 iWordValue);
+
+ // only word access is allowed to the CPLD
+// uint32 GetLong (emuptr iAddress) { return 0;}
+// uint32 GetByte (emuptr iAddress) { return 0;}
+// void SetLong (emuptr iAddress, uint32 iLongValue) {}
+// void SetByte (emuptr iAddress, uint32 iByteValue) {}
+private:
+ uint16 Reg0;
+ uint16 Reg2;
+ uint16 Reg4;
+ uint8 Buffer[kMemorySizeCPLD];
+ uint32 Read (emuptr address, int size);
+ void Write (emuptr address, int size, uint32 value);
+// void SetReg02(uint16 val);
+// void SetReg04(uint16 val);
+ HandEra330PortManager * fPortMgr;
+};
+
+#endif // EmTRGCFDefs_h
+
diff --git a/SrcShared/Hardware/TRG/EmSPISlave330Current.cpp b/SrcShared/Hardware/TRG/EmSPISlave330Current.cpp
new file mode 100644
index 0000000..43fd47b
--- /dev/null
+++ b/SrcShared/Hardware/TRG/EmSPISlave330Current.cpp
@@ -0,0 +1,189 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmSPISlave330Current.h"
+
+#include "Logging.h"
+#define PRINTF if (1) ; else LogAppendMsg
+
+
+/*****************************************************************************
+ * The HandEra 330 includes a battery current sense. It is switched in and
+ * out of channel 2 of the ADC.
+ ****************************************************************************/
+
+// ---------------------------------------------------------------------------
+// ¥ EmSPISlave330Current::EmSPISlave330Current
+// ---------------------------------------------------------------------------
+
+EmSPISlave330Current::EmSPISlave330Current () :
+ EmSPISlave (),
+ fBitBufferIn (0),
+ fBitBufferOut (0),
+ fNumBitsIn (0),
+ fPendingResult (0),
+ fHavePending (false),
+ fCommandBitsSeen (0),
+ fPowerConnected(false)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSPISlave330Current::~EmSPISlave330Current
+// ---------------------------------------------------------------------------
+
+EmSPISlave330Current::~EmSPISlave330Current (void)
+{
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmSPISlave330Current::DoExchange
+// ---------------------------------------------------------------------------
+
+uint16 EmSPISlave330Current::DoExchange (uint16 control, uint16 data)
+{
+ PRINTF ("");
+ PRINTF ("EmSPISlave330Current::DoExchange");
+ PRINTF ("control = 0x%04X, data = 0x%04X", control, data);
+
+ // -----------------------------------------------------------------------
+ // Merge the incoming bits with our current buffer.
+ // -----------------------------------------------------------------------
+
+ uint16 numBits = (control & hwrVZ328SPIMControlBitsMask) + 1;
+ uint32 oldBitsMask = ~0 << numBits;
+ uint32 newBitsMask = ~oldBitsMask;
+
+ PRINTF ("Before merging input: fBitBufferIn = 0x%04X, fNumBitsIn = 0x%04X", fBitBufferIn, fNumBitsIn);
+
+ fBitBufferIn = ((fBitBufferIn << numBits) & oldBitsMask) | (data & newBitsMask);
+ fNumBitsIn += numBits;
+
+ PRINTF ("After merging input: fBitBufferIn = 0x%04X, fNumBitsIn = 0x%04X", fBitBufferIn, fNumBitsIn);
+
+ // -----------------------------------------------------------------------
+ // Start processing the command bits.
+ // -----------------------------------------------------------------------
+
+ EmAssert (fNumBitsIn - fCommandBitsSeen - 1 >= 0);
+
+ uint16 result = 0;
+ uint32 mask = 1 << (fNumBitsIn - fCommandBitsSeen - 1);
+
+ while (mask)
+ {
+ // Shift out a bit.
+
+ {
+ result = (result << 1) | (fBitBufferOut >> 15);
+ fBitBufferOut <<= 1;
+ }
+
+ // If we haven't seen the Start bit yet, look for it.
+
+ if (fCommandBitsSeen == 0)
+ {
+ // If we found the Start bit, start counting the
+ // number of command bits as we stream through them.
+
+ if ((mask & fBitBufferIn) != 0)
+ {
+ fCommandBitsSeen++;
+ }
+
+ // Otherwise, adjust fNumBitsIn so that when we *do*
+ // find the Start bit, we know where it is.
+
+ else
+ {
+ fNumBitsIn--;
+ }
+
+ // If there's a pending conversion, load it into the
+ // output shift register after receiving the first
+ // bit after the last bit of the previous command.
+
+ this->LoadPendingConversion ();
+ }
+ else
+ {
+ fCommandBitsSeen++;
+
+ // If we've seen 8 bits, process the command, and then
+ // prepare for the next one.
+
+ if (fCommandBitsSeen == 8)
+ {
+ fNumBitsIn -= 8;
+ fCommandBitsSeen = 0;
+
+ uint8 command = fBitBufferIn >> fNumBitsIn;
+ this->ProcessCommand (command);
+
+ PRINTF ("After ProcessCommand: fPendingResult = 0x%04X", fPendingResult);
+ }
+ }
+
+ mask >>= 1;
+ }
+
+
+ // ----------------------------------------------------------------------
+ // Return the result.
+ // ----------------------------------------------------------------------
+
+ PRINTF ("result = 0x%04X", result);
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSPISlave330Current::ProcessCommand
+// ---------------------------------------------------------------------------
+
+void EmSPISlave330Current::ProcessCommand (uint8 command)
+{
+ uint16 result = 0;
+
+ // we should only get here for channel 2
+ EmAssert (((command & kChannelBits) >> 4) == 2);
+
+ if (fPowerConnected)
+ result = 0; // no battery current with ext power connected.
+ else
+ result = 0x60; // just hard code some current for now.
+
+ fPendingResult = result << 4;
+ fHavePending = true;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSPISlave330Current::LoadPendingConversion
+// ---------------------------------------------------------------------------
+
+void EmSPISlave330Current::LoadPendingConversion (void)
+{
+ // -----------------------------------------------------------------------
+ // If there's a pending conversion, move it into the output shift register.
+ // -----------------------------------------------------------------------
+ if (fHavePending)
+ {
+ fHavePending = false;
+ fBitBufferOut = fPendingResult;
+ }
+}
+
diff --git a/SrcShared/Hardware/TRG/EmSPISlave330Current.h b/SrcShared/Hardware/TRG/EmSPISlave330Current.h
new file mode 100644
index 0000000..c514250
--- /dev/null
+++ b/SrcShared/Hardware/TRG/EmSPISlave330Current.h
@@ -0,0 +1,51 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmSPISlave330Current_h
+#define EmSPISlave330Current_h
+
+#include "EmSPISlave.h" // EmSPISlave
+
+#define kChannelBits 0x70
+
+/*--------------------------------------------------------------------
+ * HandEra 330 has an analog switch which switches between voltage and
+ * current sense on channel 2. Need to cobble together something so
+ * it can sense some battery current and not think we are always on
+ * external power.
+ *-------------------------------------------------------------------*/
+class EmSPISlave330Current : public EmSPISlave
+{
+ public:
+ EmSPISlave330Current ();
+ virtual ~EmSPISlave330Current (void);
+
+ virtual uint16 DoExchange (uint16 control, uint16 data);
+ void SetMode (Bool powerConnected) { fPowerConnected = powerConnected; }
+
+ protected:
+ void ProcessCommand (uint8);
+ void LoadPendingConversion (void);
+
+ private:
+ uint32 fBitBufferIn;
+ uint16 fBitBufferOut;
+ int fNumBitsIn;
+ uint16 fPendingResult;
+ Bool fHavePending;
+ int fCommandBitsSeen;
+
+ Bool fPowerConnected;
+};
+
+#endif \ No newline at end of file
diff --git a/SrcShared/Hardware/TRG/EmTRG.cpp b/SrcShared/Hardware/TRG/EmTRG.cpp
new file mode 100644
index 0000000..f079538
--- /dev/null
+++ b/SrcShared/Hardware/TRG/EmTRG.cpp
@@ -0,0 +1,57 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmTRG.h"
+
+#include "EmBankRegs.h"
+#include "EmRegsEZTRGpro.h"
+#include "EmRegs330CPLD.h"
+#include "EmRegsVZHandEra330.h"
+#include "EmHandEraCFBus.h"
+#include "EmHandEraSDBus.h"
+#include "EmTRGCF.h"
+#include "EmTRGSD.h"
+
+
+/***********************************************************************
+ *
+ * FUNCTION: OEMCreateTRGRegObjs
+ *
+ * DESCRIPTION: This function is called by EmDevice::CreateRegs for TRG
+ * devices
+ *
+ * PARAMETERS: 'fHardwareSubID' specifies the device
+ *
+ * RETURNED: None
+ *
+ ***********************************************************************/
+void OEMCreateTRGRegObjs(long hardwareSubID)
+{
+ CFBusManager * fCFBus;
+ HandEra330PortManager * fPortMgr;
+
+ switch (hardwareSubID)
+ {
+ case hwrTRGproID :
+ default :
+ EmBankRegs::AddSubBank (new EmRegsEZTRGpro(&fCFBus));
+ EmBankRegs::AddSubBank (new EmRegsCFMemCard(fCFBus));
+ break;
+ case hwrTRGproID + 1 :
+ EmBankRegs::AddSubBank (new EmRegsVZHandEra330(&fPortMgr));
+ EmBankRegs::AddSubBank (new EmRegs330CPLD(fPortMgr));
+ EmBankRegs::AddSubBank (new EmRegsCFMemCard(&fPortMgr->CFBus));
+ break;
+ }
+}
diff --git a/SrcShared/Hardware/TRG/EmTRG.h b/SrcShared/Hardware/TRG/EmTRG.h
new file mode 100644
index 0000000..21d14d5
--- /dev/null
+++ b/SrcShared/Hardware/TRG/EmTRG.h
@@ -0,0 +1,23 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmTRG_h
+#define EmTRG_h
+
+#define TRGPRO_MANUF "TRG Products"
+#define hwrOEMDeviceIDTRGpro 1
+#define hwrTRGproID 0
+
+void OEMCreateTRGRegObjs(long hardwareSubID);
+
+#endif // EmTRG_h
diff --git a/SrcShared/Hardware/TRG/EmTRGATA.cpp b/SrcShared/Hardware/TRG/EmTRGATA.cpp
new file mode 100644
index 0000000..fcff3e6
--- /dev/null
+++ b/SrcShared/Hardware/TRG/EmTRGATA.cpp
@@ -0,0 +1,471 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmTRGATA.h"
+
+// ------------------------------------------------------------------------
+// This file emulates the ATA Registers on the CF Memory Card.
+//
+// Address Description
+// --------------------- --------------------
+// 0x18001000-0x1800100F ATA Registers
+// 0x18001010-0x180013FF Mirror of the ATA Registers
+// 0x18001400-0x18001FFF Equivalent to the Data-Even/Data-Odd Registers
+// ------------------------------------------------------------------------
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFAta::EmRegsCFAta
+// ---------------------------------------------------------------------------
+EmRegsCFAta::EmRegsCFAta(void)
+{
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFAta::~EmRegsCFATA
+// ---------------------------------------------------------------------------
+EmRegsCFAta::~EmRegsCFAta(void)
+{
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFAta::Initialize
+// ---------------------------------------------------------------------------
+void EmRegsCFAta::Initialize(EmDiskTypeID DiskTypeID)
+{
+ int i;
+
+ AtaMode = MODE_DISK_IO;
+ DiskIO.Initialize(DiskTypeID);
+ for (i=0; i<NUM_IDE_REGS; i++)
+ RegMem[i] = i;
+ RegMem[6] = 0xA0;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFAta::Reset
+// ---------------------------------------------------------------------------
+void EmRegsCFAta::Reset(void)
+{
+ DiskIO.Reset();
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFAta::Dispose
+// ---------------------------------------------------------------------------
+void EmRegsCFAta::Dispose(void)
+{
+ DiskIO.Dispose();
+}
+
+//----------------------------------------------------------------------------
+// Status and Alternate Status Registers Offsets 7h and Eh
+//
+// These registers return the CompactFlash Storage Card status when read by
+// the host. Reading the Status register does clear a pending interrupt while
+// reading the Auxiliary Status register does not. The status bits are
+// described as follows:
+//
+// D7 D6 D5 D4 D3 D2 D1 D0
+// --- --- --- --- --- --- --- ---
+// BSY RDY DWF DSC DRQ CRR 0 ERR
+//
+// Bit 7 (BUSY): the busy bit is set when the CompactFlash Storage Card has
+// access to the command buffer and registers and the host is locked out
+// from accessing the command register and buffer. No other bits in this
+// register are valid when this bit is set to a 1.
+// Bit 6 (RDY): RDY indicates whether the device is capable of performing
+// CompactFlash Storage Card operations. This bit is cleared at power up
+// and remains cleared until the CompactFlash Storage Card is ready to
+// accept a command.
+// Bit 5 (DWF): This bit, if set, indicates a write fault has occurred.
+// Bit 4 (DSC): This bit is set when the CompactFlash Storage Card is ready.
+// Bit 3 (DRQ): The Data Request is set when the CompactFlash Storage Card
+// requires that information be transferred either to or from the host
+// through the Data register.
+// Bit 2 (CORR): This bit is set when a Correctable data error has been
+// encountered and the data has been corrected. This condition does not
+// terminate a multi-sector read operation.
+// Bit 1 (IDX): This bit is always set to 0.
+// Bit 0 (ERR): This bit is set when the previous command has ended in
+// some type of error. The bits in the Error register contain additional
+// information describing the error. It is recommended that media access
+// commands (such as Read Sectors and Write Sectors) that end with an
+// error condition should have the address of the first sector in error
+// in the command block registers.
+//----------------------------------------------------------------------------
+uint8 EmRegsCFAta::RegReadStatus(Boolean /*is_alt_reg*/)
+{
+ uint8 retVal;
+ DiskIOStatus status;
+ DiskDataStatus dataStatus;
+
+ DiskIO.GetStatus(&status, &dataStatus);
+ if (status == DIO_SUCCESS)
+ {
+ retVal = (IDE_STS_RDY|IDE_STS_DSC);
+ if (dataStatus == DIO_MORE_DATA)
+ {
+ retVal |= IDE_STS_DRQ;
+ }
+ else
+ {
+ DiskParams.Lba += DiskParams.SectorCnt;
+ RegMem[IDE_REG_5_LBA_23_16] = (uint8)(DiskParams.Lba >> 16);
+ RegMem[IDE_REG_4_LBA_15_8] = (uint8)(DiskParams.Lba >> 8);
+ RegMem[IDE_REG_3_LBA_7_0] = (uint8)DiskParams.Lba;
+ }
+ }
+ else
+ {
+ retVal = (IDE_STS_RDY|IDE_STS_DSC|IDE_STS_ERR);
+ }
+ return(retVal);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFAta::GetDiskIOParams
+// ---------------------------------------------------------------------------
+void EmRegsCFAta::GetDiskIOParams(DiskIOParams * Params)
+{
+ Params->DriveNum = 0;
+ Params->Lba =
+ (((uint32)RegMem[IDE_REG_6_DRV_HEAD] & 0x0F) << 24) +
+ ((uint32)RegMem[IDE_REG_5_LBA_23_16] << 16) +
+ ((uint32)RegMem[IDE_REG_4_LBA_15_8] << 8) +
+ (uint32)RegMem[IDE_REG_3_LBA_7_0];
+ Params->SectorCnt = (uint32)RegMem[IDE_REG_2_SECTOR_CNT];
+ if (Params->SectorCnt == 0)
+ Params->SectorCnt = 256;
+
+ DiskParams = *Params;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFAta::CmdIdentifyDrive
+// ---------------------------------------------------------------------------
+void EmRegsCFAta::CmdIdentifyDrive(void)
+{
+ DiskIO.StartDriveID();
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFAta::CmdReadSectors
+// ---------------------------------------------------------------------------
+void EmRegsCFAta::CmdReadSectors(void)
+{
+ DiskIOParams params;
+
+ GetDiskIOParams(&params);
+ DiskIO.StartRead(&params);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFAta::CmdWriteSectors
+// ---------------------------------------------------------------------------
+void EmRegsCFAta::CmdWriteSectors(void)
+{
+ DiskIOParams params;
+
+ GetDiskIOParams(&params);
+ DiskIO.StartWrite(&params);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFAta::CmdDriveDiagnostic
+// ---------------------------------------------------------------------------
+void EmRegsCFAta::CmdDriveDiagnostic(void)
+{
+ AtaMode = MODE_DRIVE_DIAGNOSTICS;
+}
+
+//----------------------------------------------------------------------------
+// Data Register Offset 0 (8-bit) and 8-9 (16-bit)
+//
+// The Data Register is a 16-bit register, and it is used to transfer data
+// blocks between the CompactFlash Storage Card data buffer and the Host.
+// This register overlaps the Error Register. The table below describes the
+// combinations of data register access and is provided to assist in
+// understanding the overlapped Data Register and Error/Feature Register
+// rather than to attempt to define general PCMCIA word and byte access
+// modes and operations. See the PCMCIA PC Card Standard Release 2.0 for
+// definitions of the Card Accessing Modes for I/O and Memory cycles.
+// Note: Because of the overlapped registers, access to the 1F1h, 171h or
+// offset 1 are not defined for word (-CE2 = 0 and -CE1 = 0) operations.
+// These accesses are treated as accesses to the Word Data Register.
+// The duplicated registers at offsets 8, 9 and Dh have no restrictions on
+// the operations that can be performed by the socket.
+//----------------------------------------------------------------------------
+uint8 EmRegsCFAta::Reg0ReadData(void)
+{
+ DiskIO.ReadNextDataByte(&RegMem[IDE_REG_0_DATA]);
+ return(RegMem[IDE_REG_0_DATA]);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFAta::Reg0WriteData
+// ---------------------------------------------------------------------------
+void EmRegsCFAta::Reg0WriteData(void)
+{
+ DiskIO.WriteNextDataByte(RegMem[IDE_REG_0_DATA]);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFAta::Reg8ReadDataEven
+// ---------------------------------------------------------------------------
+uint8 EmRegsCFAta::Reg8ReadDataEven(void)
+{
+ DiskIO.ReadNextDataByte(&RegMem[IDE_REG_8_DATA_EVEN]);
+ return(RegMem[IDE_REG_8_DATA_EVEN]);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFAta::Reg8WriteDataEven
+// ---------------------------------------------------------------------------
+void EmRegsCFAta::Reg8WriteDataEven(void)
+{
+ DiskIO.WriteNextDataByte(RegMem[IDE_REG_8_DATA_EVEN]);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFAta::Reg9ReadDataOdd
+// ---------------------------------------------------------------------------
+uint8 EmRegsCFAta::Reg9ReadDataOdd(void)
+{
+ DiskIO.ReadNextDataByte(&RegMem[IDE_REG_9_DATA_ODD]);
+ return(RegMem[IDE_REG_9_DATA_ODD]);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFAta::Reg9WriteDataOdd
+// ---------------------------------------------------------------------------
+void EmRegsCFAta::Reg9WriteDataOdd(void)
+{
+ DiskIO.WriteNextDataByte(RegMem[IDE_REG_9_DATA_ODD]);
+}
+
+//----------------------------------------------------------------------------
+// Error Register -- Offset 1h and Dh (read-only)
+//
+// This register contains additional information about the source of
+// an error when an error is indicated in bit 0 of the Status register.
+// The bits are defined as follows:
+//
+// Error Register
+// This register is also accessed on data bits D15-D8 during a write
+// operation to offset 0 with -CE2 low and -CE1 high.
+//
+// Bit 7 (BBK): this bit is set when a Bad Block is detected.
+// Bit 6 (UNC): this bit is set when an Uncorrectable Error is encountered.
+// Bit 5: this bit is 0.
+// Bit 4 (IDNF): the requested sector ID is in error or cannot be found.
+// Bit 3: this bit is 0.
+// Bit 2 (Abort) This bit is set if the command has been aborted because of
+// a CompactFlash Storage Card status condition: (Not Ready, Write Fault,
+// etc.) or when an invalid command has been issued.
+// Bit 1 This bit is 0.
+// Bit 0 (AMNF) This bit is set in case of a general error.
+//----------------------------------------------------------------------------
+uint8 EmRegsCFAta::RegReadError(Boolean /*is_alt_reg*/)
+{
+ if (AtaMode == MODE_DRIVE_DIAGNOSTICS)
+ return(IDE_DIA_01_NO_ERROR);
+ else
+ return DiskIO.GetError();
+}
+
+
+//----------------------------------------------------------------------------
+// Sector Count Register (Offset 2h)
+//
+// This register contains the numbers of sectors of data requested to be
+// transferred on a read or write operation between the host and the
+// CompactFlash Storage Card. If the value in this register is zero,
+// a count of 256 sectors is specified. If the command was successful,
+// this register is zero at command completion. If not successfully completed,
+// the register contains the number of sectors that need to be transferred
+// in order to complete the request.
+//----------------------------------------------------------------------------
+uint8 EmRegsCFAta::Reg2ReadSectorCount(void)
+{
+ uint32 cnt;
+
+ cnt = DiskIO.GetSectorCount();
+ if (cnt > 0xFF)
+ cnt = 0x0;
+ return(cnt);
+}
+
+//----------------------------------------------------------------------------
+// Device Control Register -- Offset Eh
+// This register is used to control the CompactFlash Storage Card interrupt
+// request and to issue an ATA soft reset to the card. This register can
+// be written even if the device is BUSY. The bits are defined as follows:
+//
+// D7 D6 D5 D4 D3 D2 D1 D0
+// --- --- --- --- --- ------ ---- ---
+// X X X X 1 SW Rst -IEn 0
+//
+// Bit 7: this bit is an X (don't care).
+// Bit 6: this bit is an X (don't care).
+// Bit 5: this bit is an X (don't care).
+// Bit 4: this bit is an X (don't care).
+// Bit 3: this bit is ignored by the CompactFlash Storage Card.
+// Bit 2 (SW Rst): this bit is set to 1 in order to force the CompactFlash
+// Storage Card to perform an AT Disk controller Soft Reset operation.
+// This does not change the PCMCIA Card Configuration Registers (4.3.2
+// to 4.3.5) as a hardware Reset does. The Card remains in Reset until this
+// bit is reset to 0.
+// Bit 1 (-IEn): the Interrupt Enable bit enables interrupts when the bit is
+// 0. When the bit is 1, interrupts from the CompactFlash Storage Card are
+// disabled. This bit also controls the Int bit in the Configuration and
+// Status Register. This bit is set to 0 at power on and Reset.
+// Bit 0: this bit is ignored by the CompactFlash Storage Card.
+//----------------------------------------------------------------------------
+void EmRegsCFAta::RegEWriteDeviceControl(void)
+{
+ DiskIO.Reset();
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFAta::Reg7WriteCmd
+// ---------------------------------------------------------------------------
+void EmRegsCFAta::Reg7WriteCmd(void)
+{
+ AtaMode = MODE_DISK_IO;
+ DiskIO.ClearError();
+ switch(RegMem[IDE_REG_7_COMMAND])
+ {
+ case IDE_CMD_EC_IDENTIFY_DRIVE :
+ CmdIdentifyDrive();
+ break;
+
+ case IDE_CMD_20_READ_SECTORS :
+ case IDE_CMD_21_READ_SECTORS :
+ CmdReadSectors();
+ break;
+
+ case IDE_CMD_30_WRITE_SECTORS :
+ case IDE_CMD_31_WRITE_SECTORS :
+ CmdWriteSectors();
+ break;
+
+ case IDE_CMD_90_EXEC_DRIVE_DIAGNOSTIC :
+ CmdDriveDiagnostic();
+ break;
+
+ case IDE_CMD_C6_SET_MULTIPLE_MODE :
+ DiskIO.SetError(IDE_ERR_04_ABORT);
+ break;
+
+ default :
+ break;
+ }
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFAta::ReadByte
+// ---------------------------------------------------------------------------
+void EmRegsCFAta::ReadByte(uint32 offset,
+ uint8 * val)
+{
+ *val = 0;
+ switch(offset)
+ {
+ case IDE_REG_0_DATA :
+ *val = Reg0ReadData();
+ break;
+ case IDE_REG_1_ERROR :
+ *val = RegReadError(IS_BASE_REG);
+ break;
+ case IDE_REG_D_ERROR :
+ *val = RegReadError(IS_ALT_REG);
+ break;
+ case IDE_REG_2_SECTOR_CNT :
+ *val = Reg2ReadSectorCount();
+ break;
+ case IDE_REG_7_STATUS :
+ *val = RegReadStatus(IS_BASE_REG);
+ break;
+ case IDE_REG_E_ALT_STATUS :
+ *val = RegReadStatus(IS_ALT_REG);
+ break;
+ case IDE_REG_8_DATA_EVEN :
+ *val = Reg8ReadDataEven();
+ break;
+ case IDE_REG_9_DATA_ODD :
+ *val = Reg9ReadDataOdd();
+ break;
+ default :
+ if (offset < NUM_IDE_REGS)
+ *val = RegMem[offset];
+ else
+ *val = 0;
+ break;
+ }
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFAta::WriteByte
+// ---------------------------------------------------------------------------
+void EmRegsCFAta::WriteByte(uint32 offset, uint8 val)
+{
+ RegMem[offset] = val;
+ switch(offset)
+ {
+ case IDE_REG_0_DATA :
+ Reg0WriteData();
+ break;
+ case IDE_REG_7_COMMAND :
+ Reg7WriteCmd();
+ break;
+ case IDE_REG_8_DATA_EVEN :
+ Reg8WriteDataEven();
+ break;
+ case IDE_REG_9_DATA_ODD :
+ Reg9WriteDataOdd();
+ break;
+ case IDE_REG_E_DEVICE_CONTROL :
+ RegEWriteDeviceControl();
+ break;
+ }
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFAta::ReadWord
+// ---------------------------------------------------------------------------
+void EmRegsCFAta::ReadWord(uint32 offset,
+ _Word * val)
+{
+ // 16-bit reads of Register 0 are NOT equivalent to 2 8-bit reads
+ // of Register 0 and 1 ... instead it reads the Even & Odd Data
+ // bytes, so we change the register to be 8
+ if (offset == IDE_REG_0_DATA)
+ offset = IDE_REG_8_DATA_EVEN;
+ ReadByte(offset, &val->Bytes[0]);
+ ReadByte(offset+1, &val->Bytes[1]);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFAta::WriteWord
+// ---------------------------------------------------------------------------
+void EmRegsCFAta::WriteWord(uint32 offset, _Word val)
+{
+ // 16-bit writes of Register 0 are NOT equivalent to 2 8-bit writes
+ // of Register 0 and 1 ... instead it writes the Even & Odd Data
+ // bytes, so we change the register to be 8
+ if (offset == IDE_REG_0_DATA)
+ offset = IDE_REG_8_DATA_EVEN;
+ WriteByte(offset, val.Bytes[0]);
+ WriteByte(offset+1, val.Bytes[1]);
+}
diff --git a/SrcShared/Hardware/TRG/EmTRGATA.h b/SrcShared/Hardware/TRG/EmTRGATA.h
new file mode 100644
index 0000000..4b743cb
--- /dev/null
+++ b/SrcShared/Hardware/TRG/EmTRGATA.h
@@ -0,0 +1,63 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmTRGATA_h
+#define EmTRGATA_h
+
+#include "EmRegs.h"
+#include "EmTRGCFDefs.h"
+#include "EmTRGCFIO.h"
+
+#define IS_ALT_REG true
+#define IS_BASE_REG false
+
+typedef enum {MODE_DISK_IO=0, MODE_DRIVE_DIAGNOSTICS=1} AtaModeType;
+
+class EmRegsCFAta
+{
+ public:
+ EmRegsCFAta(void);
+ virtual ~EmRegsCFAta(void);
+
+ void Initialize(EmDiskTypeID DiskTypeID);
+ void Reset (void);
+ void Dispose (void);
+ void ReadByte(uint32 offset, uint8 * val);
+ void WriteByte(uint32 offset, uint8 val);
+ void ReadWord(uint32 offset, _Word * val);
+ void WriteWord(uint32 offset, _Word val);
+ private:
+ uint8 RegMem[NUM_IDE_REGS];
+ AtaModeType AtaMode;
+ DiskIOParams DiskParams;
+ void GetDiskIOParams(DiskIOParams * params);
+ uint8 Reg0ReadData(void);
+ uint8 RegReadError(Boolean is_alt_reg);
+ uint8 Reg2ReadSectorCount(void);
+ void Reg0WriteData(void);
+ void Reg7WriteCmd(void);
+ uint8 RegReadStatus(Boolean is_alt_reg);
+ uint8 Reg8ReadDataEven(void);
+ void Reg8WriteDataEven(void);
+ uint8 Reg9ReadDataOdd(void);
+ void Reg9WriteDataOdd(void);
+ void RegEWriteDeviceControl(void);
+ EmCFIO DiskIO;
+ uint8 ConvertStatus(void);
+ void CmdIdentifyDrive(void);
+ void CmdWriteSectors(void);
+ void CmdReadSectors(void);
+ void CmdDriveDiagnostic(void);
+};
+
+#endif // EmTRGATA_h
diff --git a/SrcShared/Hardware/TRG/EmTRGCF.cpp b/SrcShared/Hardware/TRG/EmTRGCF.cpp
new file mode 100644
index 0000000..3a62a17
--- /dev/null
+++ b/SrcShared/Hardware/TRG/EmTRGCF.cpp
@@ -0,0 +1,305 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmTRGCF.h"
+
+#include "EmMemory.h"
+
+
+
+//-------------------------------------------------------------------------
+// This file contains the class EmRegsCFMemCard, which emulates a
+// CompactFlash memory card. The bulk of this class is a series of
+// routines to dispatch calls to the appropriate section of a memory
+// card ... either its Tuple memory, its Configuration Registers, or its
+// ATA registers. This class also handles all decisions about how to
+// emulate the effect of the current bus state (8-bit vs. 16-bit, swap vs.
+// no swap) on the data.
+//-------------------------------------------------------------------------
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFMemCard::EmRegsCFMemCard
+// ---------------------------------------------------------------------------
+
+EmRegsCFMemCard::EmRegsCFMemCard (CFBusManager * fBusManager)
+{
+ fBusMgr = fBusManager;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFMemCard::~EmRegsCFMemCard
+// ---------------------------------------------------------------------------
+
+EmRegsCFMemCard::~EmRegsCFMemCard (void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFMemCard::Initialize
+// ---------------------------------------------------------------------------
+
+void EmRegsCFMemCard::Initialize (void)
+{
+ DiskTypeID = EM_DISK_GENERIC_8MB;
+
+ Ata.Initialize(DiskTypeID);
+ Config.Initialize(DiskTypeID);
+ Tuple.Initialize(DiskTypeID);
+ CFReset.Initialize(DiskTypeID);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFMemCard::Reset
+// ---------------------------------------------------------------------------
+void EmRegsCFMemCard::Reset (Bool /*hardwareReset*/)
+{
+ Ata.Reset();
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFMemCard::Save
+// ---------------------------------------------------------------------------
+void EmRegsCFMemCard::Save (SessionFile& /*f*/)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFMemCard::Load
+// ---------------------------------------------------------------------------
+void EmRegsCFMemCard::Load (SessionFile& /*f*/)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFMemCard::Dispose
+// ---------------------------------------------------------------------------
+void EmRegsCFMemCard::Dispose (void)
+{
+ Ata.Dispose();
+}
+
+// -------------------------------------------------------------------------
+// ¥ EmRegsCFMemCard::SetSubBankHandlers
+// ---------------------------------------------------------------------------
+void EmRegsCFMemCard::SetSubBankHandlers (void)
+{
+ // Install base handlers.
+
+ EmRegs::SetSubBankHandlers();
+ // Now add standard/specialized handers for the defined registers.
+ this->SetHandler((ReadFunction)&EmRegsCFMemCard::Read,
+ (WriteFunction)&EmRegsCFMemCard::Write,
+ kMemoryStartCF,
+ kMemorySizeCF);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFMemCard::GetRealAddress
+// ---------------------------------------------------------------------------
+uint8 * EmRegsCFMemCard::GetRealAddress (emuptr address)
+{
+ return (address-kMemoryStartCF) + Buffer;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFMemCard::GetLong
+// ---------------------------------------------------------------------------
+uint32 EmRegsCFMemCard::GetLong (emuptr /*address*/)
+{
+ return (0);
+}
+
+#define INVALID_READ 0x3F
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFMemCard::GetByte
+// ---------------------------------------------------------------------------
+uint32 EmRegsCFMemCard::GetByte(emuptr address)
+{
+ uint8 retVal = 0;
+ uint32 offset;
+
+ if (!fBusMgr->bEnabled)
+ return(INVALID_READ);
+
+ if ((fBusMgr->Width == kCFBusWidth8) && (!fBusMgr->bSwapped))
+ return(INVALID_READ);
+
+ offset = address-kMemoryStartCF;
+ if (offset < kMemoryOffsetCFConfig)
+ Tuple.ReadByte(offset-kMemoryOffsetCFTuple, &retVal);
+ else if (offset < kMemoryOffsetCFAta)
+ Config.ReadByte(offset-kMemoryOffsetCFConfig, &retVal);
+ else if (offset < kMemoryOffsetCFReset)
+ Ata.ReadByte(offset-kMemoryOffsetCFAta, &retVal);
+ else
+ CFReset.ReadByte(offset-kMemoryOffsetCFReset, &retVal);
+
+ return((uint32)retVal);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFMemCard::GetWord
+// ---------------------------------------------------------------------------
+uint32 EmRegsCFMemCard::GetWord (emuptr address)
+{
+ _Word val;
+ uint32 retval;
+ int msb, lsb;
+ uint32 offset;
+
+ if (!fBusMgr->bEnabled)
+ return(INVALID_READ);
+ if ((fBusMgr->Width == kCFBusWidth8) && (!fBusMgr->bSwapped))
+ return(INVALID_READ);
+ offset = address-kMemoryStartCF;
+
+ if (offset < kMemoryOffsetCFConfig)
+ Tuple.ReadWord(offset-kMemoryOffsetCFTuple, &val);
+ else if (offset < kMemoryOffsetCFAta)
+ Config.ReadWord(offset-kMemoryOffsetCFConfig, &val);
+ else if (offset < kMemoryOffsetCFReset)
+ Ata.ReadWord(offset-kMemoryOffsetCFAta, &val);
+ else
+ CFReset.ReadWord(offset-kMemoryOffsetCFReset, &val);
+
+ if (fBusMgr->bSwapped)
+ {
+ msb = 0;
+ lsb = 1;
+ }
+ else
+ {
+ msb = 1;
+ lsb = 0;
+ }
+ retval = ((uint32)(val.Bytes[msb]) << 8) | (uint32)val.Bytes[lsb];
+ return (retval);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFMemCard::SetLong
+// ---------------------------------------------------------------------------
+void EmRegsCFMemCard::SetLong (emuptr /*address*/, uint32 /*value*/)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFMemCard::SetWord
+// ---------------------------------------------------------------------------
+void EmRegsCFMemCard::SetWord (emuptr address, uint32 val)
+{
+ _Word setVal;
+ int msb, lsb;
+
+ if (!fBusMgr->bEnabled)
+ return;
+
+ if (fBusMgr->bSwapped)
+ {
+ msb = 0;
+ lsb = 1;
+ }
+ else
+ {
+ msb = 1;
+ lsb = 0;
+ }
+ setVal.Bytes[msb] = (uint8)((val & 0xFF00) >> 8);
+ setVal.Bytes[lsb] = (uint8)(val & 0x00FF);
+
+ if (address < kMemoryStartCFConfig)
+ Tuple.WriteWord(address-kMemoryStartCFTuple, setVal);
+ else if (address < kMemoryStartCFAta)
+ Config.WriteWord(address-kMemoryStartCFConfig, setVal);
+ else if (address < kMemoryStartCFReset)
+ Ata.WriteWord(address-kMemoryStartCFAta, setVal);
+ else
+ CFReset.WriteWord(address-kMemoryStartCFReset, setVal);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFMemCard::SetByte
+// ---------------------------------------------------------------------------
+void EmRegsCFMemCard::SetByte (emuptr address, uint32 value)
+{
+ uint8 setVal = 0;
+
+ if (!fBusMgr->bEnabled)
+ return;
+
+ setVal = (uint8)value;
+ if (address < kMemoryStartCFConfig)
+ Tuple.WriteByte(address-kMemoryStartCFTuple, setVal);
+ else if (address < kMemoryStartCFAta)
+ Config.WriteByte(address-kMemoryStartCFConfig, setVal);
+ else if (address < kMemoryStartCFReset)
+ Ata.WriteByte(address-kMemoryStartCFAta, setVal);
+ else
+ CFReset.WriteByte(address-kMemoryStartCFReset, setVal);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFMemCard::GetAddressStart
+// ---------------------------------------------------------------------------
+emuptr EmRegsCFMemCard::GetAddressStart (void)
+{
+ return (kMemoryStartCF);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFMemCard::GetAddressRange
+// ---------------------------------------------------------------------------
+uint32 EmRegsCFMemCard::GetAddressRange (void)
+{
+ return kMemorySizeCF;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFMemCard::Read
+// ---------------------------------------------------------------------------
+uint32 EmRegsCFMemCard::Read(emuptr address, int size)
+{
+ switch(size)
+ {
+ case sizeof(uint8) :
+ return(GetByte(address));
+ case sizeof(uint16) :
+ return(GetWord(address));
+ }
+ return 0;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFMemCard::Write
+// ---------------------------------------------------------------------------
+void EmRegsCFMemCard::Write(emuptr address, int size, uint32 val)
+{
+ switch(size)
+ {
+ case sizeof(uint8) :
+ SetByte(address, val);
+ break;
+ case sizeof(uint16) :
+ SetWord(address, val);
+ break;
+ }
+}
diff --git a/SrcShared/Hardware/TRG/EmTRGCF.h b/SrcShared/Hardware/TRG/EmTRGCF.h
new file mode 100644
index 0000000..a3eb969
--- /dev/null
+++ b/SrcShared/Hardware/TRG/EmTRGCF.h
@@ -0,0 +1,58 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmTRGCF_h
+#define EmTRGCF_h
+
+#include "EmRegs.h"
+#include "EmTRGCFDefs.h"
+#include "EmTRGATA.h"
+#include "EmTRGCFMem.h"
+
+class EmRegsCFMemCard : public EmRegs
+{
+ public:
+ EmRegsCFMemCard (CFBusManager * fCFBusManager);
+ virtual ~EmRegsCFMemCard (void);
+
+ // EmRegs overrides
+ virtual void Initialize (void);
+ virtual void Reset (Bool hardwareReset);
+ virtual void Save (SessionFile&);
+ virtual void Load (SessionFile&);
+ virtual void Dispose (void);
+
+ uint8* GetRealAddress (emuptr address);
+ void SetSubBankHandlers (void);
+ emuptr GetAddressStart (void);
+ uint32 GetAddressRange (void);
+
+ uint32 GetLong (emuptr iAddress);
+ uint32 GetWord (emuptr iAddress);
+ uint32 GetByte (emuptr iAddress);
+ void SetLong (emuptr iAddress, uint32 iLongValue);
+ void SetWord (emuptr iAddress, uint32 iWordValue);
+ void SetByte (emuptr iAddress, uint32 iByteValue);
+private:
+ uint8 Buffer[kMemorySizeCF];
+ uint32 Read (emuptr address, int size);
+ void Write (emuptr address, int size, uint32 value);
+ EmDiskTypeID DiskTypeID;
+ EmRegsCFAta Ata;
+ EmRegsCFTuple Tuple;
+ EmRegsCFConfig Config;
+ EmRegsCFReset CFReset;
+ CFBusManager * fBusMgr;
+};
+
+#endif /* EmTRGCF_h */
diff --git a/SrcShared/Hardware/TRG/EmTRGCFDefs.h b/SrcShared/Hardware/TRG/EmTRGCFDefs.h
new file mode 100644
index 0000000..aa5274b
--- /dev/null
+++ b/SrcShared/Hardware/TRG/EmTRGCFDefs.h
@@ -0,0 +1,187 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmTRGCFDefs_h
+#define EmTRGCFDefs_h
+
+#define IDE_REG_0_DATA 0x0
+#define IDE_REG_1_ERROR 0x1
+#define IDE_REG_1_FEATURES 0x1
+#define IDE_REG_2_SECTOR_CNT 0x2
+#define IDE_REG_3_LBA_7_0 0x3
+#define IDE_REG_4_LBA_15_8 0x4
+#define IDE_REG_5_LBA_23_16 0x5
+#define IDE_REG_6_DRV_HEAD 0x6
+#define IDE_REG_7_STATUS 0x7
+#define IDE_REG_7_COMMAND 0x7
+#define IDE_REG_8_DATA_EVEN 0x8
+#define IDE_REG_9_DATA_ODD 0x9
+#define IDE_REG_A_UNUSED 0xA
+#define IDE_REG_B_UNUSED 0xB
+#define IDE_REG_C_UNUSED 0xC
+#define IDE_REG_D_ERROR 0xD
+#define IDE_REG_E_ALT_STATUS 0xE
+#define IDE_REG_E_DEVICE_CONTROL 0xE
+#define IDE_REG_F_DRIVE_ADDR 0xF
+
+#define NUM_IDE_REGS (IDE_REG_F_DRIVE_ADDR + 1)
+
+#define SECTOR_SIZE 512
+
+#define IDE_CMD_03_REQUEST_SENSE 0x03
+#define IDE_CMD_10_RECALIBRATE 0x10
+#define IDE_CMD_11_RECALIBRATE 0x11
+#define IDE_CMD_12_RECALIBRATE 0x12
+#define IDE_CMD_13_RECALIBRATE 0x13
+#define IDE_CMD_14_RECALIBRATE 0x14
+#define IDE_CMD_15_RECALIBRATE 0x15
+#define IDE_CMD_16_RECALIBRATE 0x16
+#define IDE_CMD_17_RECALIBRATE 0x17
+#define IDE_CMD_18_RECALIBRATE 0x18
+#define IDE_CMD_19_RECALIBRATE 0x19
+#define IDE_CMD_1A_RECALIBRATE 0x1A
+#define IDE_CMD_1B_RECALIBRATE 0x1B
+#define IDE_CMD_1C_RECALIBRATE 0x1C
+#define IDE_CMD_1D_RECALIBRATE 0x1D
+#define IDE_CMD_1E_RECALIBRATE 0x1E
+#define IDE_CMD_1F_RECALIBRATE 0x1F
+#define IDE_CMD_20_READ_SECTORS 0x20
+#define IDE_CMD_21_READ_SECTORS 0x21
+#define IDE_CMD_22_READ_LONG_SECTOR 0x22
+#define IDE_CMD_23_READ_LONG_SECTOR 0x23
+#define IDE_CMD_30_WRITE_SECTORS 0x30
+#define IDE_CMD_31_WRITE_SECTORS 0x31
+#define IDE_CMD_32_WRITE_LONG_SECTOR 0x32
+#define IDE_CMD_33_WRITE_LONG_SECTOR 0x33
+#define IDE_CMD_38_WRITE_SECTORS_WO_ERASE 0x38
+#define IDE_CMD_3C_WRITE_VERIFY 0x3C
+#define IDE_CMD_40_READ_VERIFY_SECTORS 0x40
+#define IDE_CMD_41_READ_VERIFY_SECTORS 0x41
+#define IDE_CMD_50_FORMAT_TRACK 0x50
+#define IDE_CMD_70_SEEK 0x70
+#define IDE_CMD_71_SEEK 0x71
+#define IDE_CMD_72_SEEK 0x72
+#define IDE_CMD_73_SEEK 0x73
+#define IDE_CMD_74_SEEK 0x74
+#define IDE_CMD_75_SEEK 0x75
+#define IDE_CMD_76_SEEK 0x76
+#define IDE_CMD_77_SEEK 0x77
+#define IDE_CMD_78_SEEK 0x78
+#define IDE_CMD_79_SEEK 0x79
+#define IDE_CMD_7A_SEEK 0x7A
+#define IDE_CMD_7B_SEEK 0x7B
+#define IDE_CMD_7C_SEEK 0x7C
+#define IDE_CMD_7D_SEEK 0x7D
+#define IDE_CMD_7E_SEEK 0x7E
+#define IDE_CMD_7F_SEEK 0x7F
+#define IDE_CMD_87_TRANSLATE_SECTOR 0x87
+#define IDE_CMD_90_EXEC_DRIVE_DIAGNOSTIC 0x90
+#define IDE_CMD_91_INIT_DRIVE_PARAMS 0x91
+#define IDE_CMD_94_STANDBY_IMMEDIATE 0x94
+#define IDE_CMD_95_IDLE_IMMEDIATE 0x95
+#define IDE_CMD_96_STANDBY 0x96
+#define IDE_CMD_97_IDLE 0x97
+#define IDE_CMD_98_CHECK_POWER_MODE 0x98
+#define IDE_CMD_99_SET_SLEEP_MODE 0x99
+#define IDE_CMD_C0_ERASE_SECTOR 0xC0
+#define IDE_CMD_C4_READ_MULTIPLE 0xC4
+#define IDE_CMD_C6_SET_MULTIPLE_MODE 0xC6
+#define IDE_CMD_CD_WRITE_MULT_WO_ERASE 0xCD
+#define IDE_CMD_E0_STANDBY_IMMEDIATE 0xE0
+#define IDE_CMD_E1_IDLE_IMMEDIATE 0xE1
+#define IDE_CMD_E2_STANDBY 0xE2
+#define IDE_CMD_E3_IDLE 0xE3
+#define IDE_CMD_E4_READ_BUFFER 0xE4
+#define IDE_CMD_E5_CHECK_POWER_MODE 0xE5
+#define IDE_CMD_E6_SET_SLEEP_MODE 0xE6
+#define IDE_CMD_E8_WRITE_BUFFER 0xE8
+#define IDE_CMD_EC_IDENTIFY_DRIVE 0xEC
+#define IDE_CMD_EF_SET_FEATURES 0xEF
+#define IDE_CMD_F1_SECUR_SET_PASSWORD 0xF1
+#define IDE_CMD_F2_SECUR_UNLOCK 0xF2
+#define IDE_CMD_F3_SECUR_ERASE_PREPARE 0xF3
+#define IDE_CMD_F4_SECUR_ERASE_UNIT 0xF4
+#define IDE_CMD_F5_SECUR_FREEZE_LOCK 0xF5
+#define IDE_CMD_F6_SECUR_DISABLE_PASSWORD 0xF6
+
+#define IDE_STS_BUSY 0x80
+#define IDE_STS_RDY 0x40
+#define IDE_STS_DWF 0x20
+#define IDE_STS_DSC 0x10
+#define IDE_STS_DRQ 0x08
+#define IDE_STS_CORR 0x04
+#define IDE_STS_IDX 0x02
+#define IDE_STS_ERR 0x01
+
+#define IDE_ERR_10_SECTOR_NOT_FOUND 0x10
+#define IDE_ERR_04_ABORT 0x04
+#define IDE_ERR_01_GENERAL_ERROR 0x01
+#define IDE_ERR_00_NONE 0x00
+
+#define IDE_DIA_80_SLAVE_ERR 0x80
+#define IDE_DIA_05_CPU_ERR 0x05
+#define IDE_DIA_04_ECC_CIRCUITRY_ERR 0x04
+#define IDE_DIA_03_SECTOR_BUFFER_ERR 0x03
+#define IDE_DIA_02_FORMAT_ERR 0x02
+#define IDE_DIA_01_NO_ERROR 0x01
+
+typedef struct {
+ uint8 Bytes[SECTOR_SIZE];
+} EmSector;
+
+typedef uint8 DiskStatus;
+typedef uint32 LogicalBlockAddr;
+
+typedef enum {
+ EM_DISK_GENERIC_8MB
+} EmDiskTypeID;
+
+class SessionFile;
+
+typedef struct {
+ uint8 Bytes[2];
+} _Word;
+
+typedef enum {
+ CF_MEM_TUPLE,
+ CF_MEM_CONFIG,
+ CF_MEM_ATA,
+ CF_MEM_RESET
+} CFMemSection;
+
+
+const uint32 kMemoryStartCF = 0x18000000;
+
+const uint32 kMemoryOffsetCFTuple = 0;
+const uint32 kMemoryStartCFTuple = kMemoryStartCF + kMemoryOffsetCFTuple;
+const uint32 kMemorySizeCFTuple = 0x200;
+
+const uint32 kMemoryOffsetCFConfig = kMemoryOffsetCFTuple + kMemorySizeCFTuple;
+const uint32 kMemoryStartCFConfig = kMemoryStartCF + kMemoryOffsetCFConfig;
+const uint32 kMemorySizeCFConfig = 0xE00;
+
+const uint32 kMemoryOffsetCFAta = kMemoryOffsetCFConfig + kMemorySizeCFConfig;
+const uint32 kMemoryStartCFAta = kMemoryStartCF + kMemoryOffsetCFAta;
+const uint32 kMemorySizeCFAta = 0x1000;
+
+const uint32 kMemoryOffsetCFReset = kMemoryOffsetCFAta + kMemorySizeCFAta;
+const uint32 kMemoryStartCFReset = kMemoryStartCF + kMemoryOffsetCFReset;
+const uint32 kMemorySizeCFReset = 0x200;
+
+const uint32 kMemorySizeCF = kMemoryOffsetCFReset + kMemorySizeCFReset;
+
+#include "EmRegs.h"
+#include "EmHandEraCFBus.h"
+
+
+#endif // EmTRGCFDefs_h
diff --git a/SrcShared/Hardware/TRG/EmTRGCFIO.cpp b/SrcShared/Hardware/TRG/EmTRGCFIO.cpp
new file mode 100644
index 0000000..d1ec47e
--- /dev/null
+++ b/SrcShared/Hardware/TRG/EmTRGCFIO.cpp
@@ -0,0 +1,236 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmTRGCFIO.h"
+
+
+//-------------------------------------------------------------------------
+// This file implements card I/O emulation by performing read and write
+// operations on a file on the PC. Note that this file doesn't know
+// anything about ATA registers ... it's more of a state machine for
+// a continuous series of reads and writes
+//
+// These functions will create a disk file on the PC ... if one doesn't
+// exist, it will create it in a formatted state.
+//
+// The code should work even if the disk file is replaced by an image
+// from a real card ... there is no additional info stored with the card
+// however, the tuple info won't agree with the card
+//---------------------------------------------------------------------------
+
+// ---------------------------------------------------------------------------
+// ¥ EmCFIO::EmCFIO
+// ---------------------------------------------------------------------------
+EmCFIO::EmCFIO (void)
+{
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmCFIO::~EmCFIO
+// ---------------------------------------------------------------------------
+EmCFIO::~EmCFIO (void)
+{
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmCFIO::~EmCFIO
+// ---------------------------------------------------------------------------
+void EmCFIO::Reset(void)
+{
+ State.NumSectorsRequested = 0;
+ State.NumSectorsCompleted = 0;
+ State.SectorIndex = 0;
+ State.Status = DIO_SUCCESS;
+ State.Error = 0;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmCFIO::Initialize
+// ---------------------------------------------------------------------------
+void EmCFIO::Initialize (EmDiskTypeID ID)
+{
+ DiskTypeID = ID;
+ DiskIO.Initialize(ID, CF_DRIVE);
+ Reset();
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmCFIO::Dispose
+// ---------------------------------------------------------------------------
+void EmCFIO::Dispose (void)
+{
+ DiskIO.Dispose();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCFIO::ReadSector
+// ---------------------------------------------------------------------------
+DiskIOStatus EmCFIO::ReadSector(void)
+{
+ if ((DiskIO.ReadSector(State.Lba, (char *)State.Sector.Bytes)) != 0)
+ return DIO_ERROR;
+
+ return DIO_SUCCESS;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmCFIO::WriteSector
+// ---------------------------------------------------------------------------
+DiskIOStatus EmCFIO::WriteSector(void)
+{
+ if ((DiskIO.WriteSector(State.Lba, (char *)State.Sector.Bytes)) != 0)
+ return DIO_ERROR;
+
+ return DIO_SUCCESS;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmCFIO::ReadNextDataByte
+// ---------------------------------------------------------------------------
+void EmCFIO::ReadNextDataByte(uint8 * val)
+{
+ // this first statement will likely not be called except when someone's
+ // dumping memory at our address range
+ if (State.NumSectorsCompleted >= State.NumSectorsRequested)
+ *val = 0;
+ else
+ {
+ *val = State.Sector.Bytes[State.SectorIndex++];
+ if (State.SectorIndex >= SECTOR_SIZE)
+ {
+ if (++State.NumSectorsCompleted < State.NumSectorsRequested)
+ {
+ State.Lba++;
+ State.SectorIndex = 0;
+ State.Status = ReadSector();
+ }
+ }
+ }
+ if (State.Status != DIO_SUCCESS)
+ State.Error = IDE_ERR_01_GENERAL_ERROR;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmCFIO::WriteNextDataByte
+// ---------------------------------------------------------------------------
+void EmCFIO::WriteNextDataByte(uint8 val)
+{
+ State.Status = DIO_SUCCESS;
+ if (State.NumSectorsCompleted < State.NumSectorsRequested)
+ {
+ State.Sector.Bytes[State.SectorIndex++] = val;
+ if (State.SectorIndex >= SECTOR_SIZE)
+ {
+ if (WriteSector() == DIO_ERROR)
+ State.Status = DIO_ERROR;
+ else if (++State.NumSectorsCompleted < State.NumSectorsRequested)
+ {
+ State.Status = DIO_SUCCESS;
+ State.Lba++;
+ State.SectorIndex = 0;
+ }
+ }
+ }
+ if (State.Status != DIO_SUCCESS)
+ State.Error = IDE_ERR_01_GENERAL_ERROR;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmCFIO::GetSectorCount
+// ---------------------------------------------------------------------------
+uint32 EmCFIO::GetSectorCount(void)
+{
+ return State.NumSectorsCompleted;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmCFIO::StartDriveID
+// ---------------------------------------------------------------------------
+void EmCFIO::StartDriveID(void)
+{
+ CurrDisk.GetDriveID(DiskTypeID,
+ &State.Sector);
+ State.NumSectorsRequested = 1;
+ State.NumSectorsCompleted = 0;
+ State.SectorIndex = 0;
+ State.Status = DIO_SUCCESS;
+ State.Error = 0;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmCFIO::StartRead
+// ---------------------------------------------------------------------------
+void EmCFIO::StartRead(DiskIOParams * params)
+{
+ State.Lba = params->Lba;
+ State.NumSectorsRequested = params->SectorCnt;
+ State.NumSectorsCompleted = 0;
+ State.SectorIndex = 0;
+ State.Error = 0;
+ State.Status = ReadSector();
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmCFIO::StartWrite
+// ---------------------------------------------------------------------------
+void EmCFIO::StartWrite(DiskIOParams * params)
+{
+ State.Lba = params->Lba;
+ State.NumSectorsRequested = params->SectorCnt;
+ State.NumSectorsCompleted = 0;
+ State.SectorIndex = 0;
+ State.Status = DIO_SUCCESS;
+ State.Error = 0;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmCFIO::GetStatus
+// ---------------------------------------------------------------------------
+void EmCFIO::GetStatus(DiskIOStatus * status,
+ DiskDataStatus * dataStatus)
+{
+ *status = State.Status;
+ if (State.NumSectorsCompleted == State.NumSectorsRequested)
+ *dataStatus = DIO_DATA_COMPLETE;
+ else
+ *dataStatus = DIO_MORE_DATA;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmCFIO::GetError
+// ---------------------------------------------------------------------------
+DiskIOError EmCFIO::GetError(void)
+{
+ if (State.Status == DIO_SUCCESS)
+ return(0);
+ else
+ // at this point, all errors are pretty much the same ... we can't
+ // create our emulation file ... we probably will need to include
+ // some more refined error codes at some point
+ return(State.Error);
+}
+
+
+void EmCFIO::SetError(DiskIOError error)
+{
+ State.Status = DIO_ERROR;
+ State.Error = error;
+}
+
+void EmCFIO::ClearError(void)
+{
+ State.Status = DIO_SUCCESS;
+ State.Error = 0;
+}
diff --git a/SrcShared/Hardware/TRG/EmTRGCFIO.h b/SrcShared/Hardware/TRG/EmTRGCFIO.h
new file mode 100644
index 0000000..5ce0974
--- /dev/null
+++ b/SrcShared/Hardware/TRG/EmTRGCFIO.h
@@ -0,0 +1,90 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmTRGCFIO_h
+#define EmTRGCFIO_h
+
+#include "EmTRGCFDefs.h"
+#include "EmTRGDiskType.h"
+#include "EmTRGDiskIO.h"
+
+#include <stdio.h> // FILE
+
+#define DISKFILE_NAME "trgdrv.dat"
+
+typedef struct {
+ uint32 DriveNum;
+ LogicalBlockAddr Lba;
+ uint32 SectorCnt;
+} DiskIOParams;
+
+typedef enum {
+ DIO_SUCCESS = 0,
+ DIO_ERROR = 1
+} DiskIOStatus;
+
+typedef enum {
+ DIO_DATA_COMPLETE = 0,
+ DIO_MORE_DATA = 1
+} DiskDataStatus;
+
+//typedef enum {
+// DIO_ERR_NONE = 0,
+// DIO_ERR_GENERIC = 1
+//} DiskIOError;
+typedef uint8 DiskIOError;
+
+typedef struct {
+ LogicalBlockAddr Lba;
+ uint32 NumSectorsRequested;
+ uint32 NumSectorsCompleted;
+ EmSector Sector;
+ int SectorIndex;
+ DiskIOStatus Status;
+ DiskIOError Error;
+} DiskIOState;
+
+class EmCFIO
+{
+public:
+ EmCFIO (void);
+ virtual ~EmCFIO (void);
+
+ // EmRegs overrides
+ void Initialize(EmDiskTypeID DiskTypeID);
+ void Dispose(void);
+ void Reset(void);
+ void StartDriveID(void);
+ void ReadNextDataByte(uint8 * val);
+ void WriteNextDataByte(uint8 val);
+ uint32 GetSectorCount(void);
+ void StartRead(DiskIOParams * params);
+ void StartWrite(DiskIOParams * params);
+ void GetStatus(DiskIOStatus * status,
+ DiskDataStatus * dataStatus);
+ DiskIOError GetError(void);
+ void SetError(DiskIOError error);
+ void ClearError(void);
+
+private:
+ EmDiskTypeID DiskTypeID;
+ EmCurrDiskType CurrDisk;
+ DiskIOStatus WriteSector(void);
+ DiskIOStatus ReadSector(void);
+ void CloseFile(void);
+ DiskIOState State;
+
+ EmTRGDiskIO DiskIO;
+};
+
+#endif /* EmTRGCFIO_h */
diff --git a/SrcShared/Hardware/TRG/EmTRGCFMem.cpp b/SrcShared/Hardware/TRG/EmTRGCFMem.cpp
new file mode 100644
index 0000000..3d9a169
--- /dev/null
+++ b/SrcShared/Hardware/TRG/EmTRGCFMem.cpp
@@ -0,0 +1,349 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmTRGCFMem.h"
+
+// ------------------------------------------------------------------------
+// This file emulates the Registers on the CF Memory Card aside from the
+// ATA registers (they are handled in a different source file).
+//
+// Address Description Class
+// --------------------- -------------------- ---------------------
+// 0x18000000-0x180001FF Card Tuple EmRegsCFTuple
+// 0x18000200-0x18000FFF Configuration Regs EmRegsCFConfig
+// 0x18001000-0x18001FFF ATA Registers
+// 0x18002000 CF Reset EmRegsCFReset
+// ------------------------------------------------------------------------
+
+//----------------------------------------------------------------------------
+// Configuration Option Register (Base + 00h in Attribute Memory)
+//
+// The Configuration Option Register is used to configure the cards interface,
+// address decoding and interrupt and to issue a soft reset to the CompactFlash
+// Storage Card or CF+ Card.
+//
+// D7 D6 D5 D4 D3 D2 D1 D0
+// R/W SRESET LevlREQ Conf5 Conf4 Conf3 Conf2 Conf1 Conf0
+//
+// SRESET - Soft Reset: setting this bit to one (1), waiting the minimum reset
+// width time and returning to zero (0) places the CompactFlash Storage Card
+// or CF+ Card in the Reset state. Setting this bit to one (1) is equivalent
+// to assertion of the +RESET signal except that the SRESET bit is not cleared.
+// Returning this bit to zero (0) leaves the CompactFlash Storage
+// Card or CF+ Card in the same un-configured, Reset state as following
+// power-up and hardware reset. This bit is set to zero (0) by power-up and
+// hardware reset. For CompactFlash Storage Cards, using the PCMCIA Soft
+// Reset is considered a hard Reset by the ATA Commands. Contrast with Soft
+// Reset in the Device Control Register.
+//
+// LevlREQ: this bit is set to one (1) when Level Mode Interrupt is selected,
+// and zero (0) when Pulse Mode is selected. Set to zero (0) by Reset.
+//
+// Conf5 - Conf0 - Configuration Index: set to zero (0) by reset. It is used
+// to select operation mode of the CompactFlash Storage Card or CF+ Card
+// as shown below.
+/// Note: Conf5 and Conf4 are reserved for CompactFlash Storage cards and
+// must be written as zero (0) These bits are vendor defined for CF+ Cards.
+//
+// CompactFlash Storage Card Configurations
+// Conf5 Conf4 Conf3 Conf2 Conf1 Conf0 Disk Card Mode
+// 0 0 0 0 0 0 Memory Mapped
+// 0 0 0 0 0 1 I/O Mapped, Any 16 byte system
+// decoded boundary
+// 0 0 0 0 1 0 I/O Mapped, 1F0h-1F7h/3F6h-3F7h
+// 0 0 0 0 1 1 I/O Mapped, 170h-177h/376h-377h
+//
+// CF+ Card Configurations
+// Conf5 Conf4 Conf3 Conf2 Conf1 Conf0 CF+ Card Mode
+// 0 0 0 0 0 0 Memory Mapped, I/O cycles are ignored
+// X X X X X X Any non-zero value, vendor defined
+//
+// On Multiple Function CF+ Cards, bits in this field enable the following
+// functionality:
+//
+// Bit 0 Enable Function - If this bit is reset to zero (0), the function is
+// disabled. If this bit is set to one (1), the function is enabled.
+//
+// Bit 1 Enable Base and Limit Registers - If this bit is reset to zero (0)
+// and Bit 0 is set to one (1), all I/O addresses on the host system are
+// passed to the function. If this is set to one (1) and Bit 0 is set to one
+// (1), only I/O addresses that are qualified by the Base and Limit registers
+// are passed to the function. If Bit 0 is reset to zero (0), this bit is
+// undefined.
+//
+// Bit 2 Enable IREQ# Routing - If this bit is reset to zero (0) and Bit 0
+// is set to one (1), this function shall not generate interrupt requests
+// on the CF+ Card's IREQ# line. If this is set to one (1) and
+// Bit 0 is set to one (1), this function shall generate interrupt requests
+// on the CF+ Card's IREQ# line. If Bit 0 is reset to zero (0), this bit is
+// undefined.
+//
+// Bit 3..5 Reserved for vendor implementation.
+//----------------------------------------------------------------------------
+
+//----------------------------------------------------------------------------
+// Card Configuration and Status Register (Base + 02h in Attribute Memory)
+// The Card Configuration and Status Register contains information about the
+// Card's condition.
+//
+// Operation D7 D6 D5 D4 D3 D2 D1 D0
+// ---------- ------- ------ ------- ------- ------- ------ ------ ------
+// Read Changed SigChg IOis8 -XE Audio PwrDwn Int 0
+// Write 0 SigChg IOis8 -XE Audio PwrDwn 0 0
+//
+// Changed: indicates that one or both of the Pin Replacement register CRdy,
+// or CWProt bits are set to one (1). When the Changed bit is set,
+// -STSCHG Pin 46 is held low if the SigChg bit is a One (1) and the
+// CompactFlash Storage Card or CF+ Card is configured for the I/O interface.
+//
+// SigChg: this bit is set and reset by the host to enable and disable a
+// state-change signal from the Status Register, the Changed bit control
+// pin 46 the Changed Status signal. If no state change signal is desired,
+// this bit should be set to zero (0) and pin 46 (-STSCHG) signal will
+// be held high while the CompactFlash Storage Card or CF+ Card is configured
+// for I/O.
+//
+// IOis8: the host sets this bit to a one (1) if the CompactFlash Storage
+// Card or CF+ Card is to be configured in an 8 bit I/O Mode. The
+// CompactFlash Storage Card is always configured for both 8- and 16-bit I/O,
+// so this bit is ignored. Some CF+ cards can be configured for either 8-
+// bit I/O mode or 16-bit I/O mode, so CF+ cards may respond to this bit.
+//
+// -XE: this bit is set and reset by the host to disable and enable Power
+// Level 1 commands in CF+ cards. If the value is 0, Power Level 1 commands
+// are enabled; if it is 1, Power Level 1 commands are disabled. Default
+// value at power on or after reset is 0. The host may read the value of
+// this bit to determine whether Power Level 1 commands are currently enabled.
+// For CompactFlash Storage cards (which must not support Power Level 1),
+// this bit has value 0 and is not writeable.
+//
+// Audio: this bit is set and reset by the host to enable and disable
+// audio information on SPKR# when the CF+ card is configured. This bit
+// should always be zero for CompactFlash Storage cards.
+//
+// PwrDwn: this bit indicates whether the host requests the CompactFlash
+// Storage Card or CF+ Card to be in the power saving or active mode. When
+// the bit is one (1), the CompactFlash Storage Card or CF+ Card enters a
+// power down mode. When zero (0), the host is requesting the CompactFlash
+// Storage Card or CF+ Card to enter the active mode. The PCMCIA Rdy/-Bsy
+// value becomes BUSY when this bit is changed. Rdy/-Bsy will not become
+// Ready until the power state requested has been entered. The CompactFlash
+// Storage Card automatically powers down when it is idle and powers back up
+// when it receives a command.
+//
+// Int: this bit represents the internal state of the interrupt request.
+// This value is available whether or not I/O interface has been configured.
+// This signal remains true until the condition which caused the interrupt
+// request has been serviced. If interrupts are disabled by the -IEN bit in
+// the Device Control Register, this bit is a zero (0).
+//----------------------------------------------------------------------------
+
+//----------------------------------------------------------------------------
+// Pin Replacement Register (Base + 04h in Attribute Memory)
+//
+// Operation D7 D6 D5 D4 D3 D2 D1 D0
+// --------- ------ ------ --------- ------ ------ ------ -------- ------
+// Read 0 0 CRdy/-Bsy CWProt 1 1 Rdy/-Bsy WProt
+// Write 0 0 CRdy/-Bsy CWProt 0 0 MRdy/-Bsy MWProt
+//
+// CRdy/-Bsy: this bit is set to one (1) when the bit RRdy/-Bsy changes state.
+// This bit can also be written by the host.
+//
+// CWProt: this bit is set to one (1) when the RWprot changes state.
+// This bit may also be written by the host.
+//
+// Rdy/-Bsy: this bit is used to determine the internal state of the Rdy/-Bsy
+// signal. This bit may be used to determine the state of the Ready/-Busy as
+// this pin has been reallocated for use as Interrupt Request on an I/O card.
+// When written, this bit acts as a mask for writing the corresponding bit
+// CRdy/-Bsy.
+//
+// Wprot: this bit is always zero (0) since the CompactFlash Storage Card or
+// CF+ Card does not have a Write Protect switch. When written, this bit acts
+// as a mask for writing the corresponding bit CWProt.
+//
+// MRdy/-Bsy: this bit acts as a mask for writing the corresponding bit
+// CRdy/-Bsy.
+//
+// MWProt: this bit when written acts as a mask for writing the corresponding
+// bit CWProt.
+//
+// Pin Replacement Changed Bit/Mask Bit Values
+//
+// Initial Value | Written by Host | Final | Comments
+// of (C) Status | C-Bit M-Bit | C-Bit |
+// ------------- | --------------- | ----- | ----------
+// 0 | X 0 | 0 | Unchanged
+// 1 | X 0 | 1 | Unchanged
+// X | 0 1 | 0 | Cleared by Host
+// X | 1 1 | 1 | Set by Host
+//----------------------------------------------------------------------------
+
+//----------------------------------------------------------------------------
+// Socket and Copy Register (Base + 06h in Attribute Memory)
+//
+// This register contains additional configuration information. This register
+// is always written by the system before writing the card's Configuration
+// Index Register. This register is not required for CF+ Cards.
+//
+// Operation D7 D6 D5 D4 D3 D2 D1 D0
+// --------- ------ ------ ------ ------ ------ ------ ------ ------
+// Read Resrvd 0 0 Drive# 0 0 0 0
+// Write 0 0 0 Drive# X X X X
+//
+// Reserved: this bit is reserved for future standardization. This bit must
+// be set to zero (0) by the software when the register is written.
+//
+// Drive #: this bit indicates the drive number of the card for twin card
+// configuration.
+//
+// X: the socket number is ignored by the CompactFlash Storage Card.
+//----------------------------------------------------------------------------
+static uint8 CFRegMem[] = {
+ 0x00, 0x00, 0x00, 0x80, 0x00, 0x2E, 0x00, 0x00,
+};
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFConfig::InRange
+// ---------------------------------------------------------------------------
+Boolean EmRegsCFConfig::InRange(uint32 offset)
+{
+ if (offset < sizeof(CFRegMem))
+ return(true);
+ else
+ return(false);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFConfig::Initialize
+// ---------------------------------------------------------------------------
+void EmRegsCFConfig::Initialize(EmDiskTypeID /*ID*/)
+{
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFConfig::ReadByte
+// ---------------------------------------------------------------------------
+void EmRegsCFConfig::ReadByte(uint32 offset, uint8 * val)
+{
+ if (InRange(offset))
+ *val = CFRegMem[offset];
+ else
+ *val = 0;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFConfig::WriteByte
+// ---------------------------------------------------------------------------
+void EmRegsCFConfig::WriteByte(uint32 /*offset*/, uint8 /*val*/)
+{
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFConfig::ReadWord
+// ---------------------------------------------------------------------------
+void EmRegsCFConfig::ReadWord(uint32 offset, _Word * val)
+{
+ ReadByte(offset, &val->Bytes[0]);
+ ReadByte(offset+1, &val->Bytes[1]);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFConfig::WriteWord
+// ---------------------------------------------------------------------------
+void EmRegsCFConfig::WriteWord(uint32 /*offset*/, _Word /*val*/)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFReset::Initialize
+// ---------------------------------------------------------------------------
+void EmRegsCFReset::Initialize(EmDiskTypeID /*ID*/)
+{
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFReset::ReadByte
+// ---------------------------------------------------------------------------
+void EmRegsCFReset::ReadByte(uint32 /*offset*/, uint8 * val)
+{
+ *val = 0;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFReset::WriteByte
+// ---------------------------------------------------------------------------
+void EmRegsCFReset::WriteByte(uint32 /*offset*/, uint8 /*val*/)
+{
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFReset::ReadWord
+// ---------------------------------------------------------------------------
+void EmRegsCFReset::ReadWord(uint32 /*offset*/, _Word * val)
+{
+ val->Bytes[0] = val->Bytes[1] = 0;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFReset::WriteWord
+// ---------------------------------------------------------------------------
+void EmRegsCFReset::WriteWord(uint32 /*offset*/, _Word /*val*/)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFTuple::Initialize
+// ---------------------------------------------------------------------------
+void EmRegsCFTuple::Initialize(EmDiskTypeID DiskTypeID)
+{
+ CurrDisk.GetTuple(DiskTypeID,
+ &tuple);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFTuple::ReadByte
+// ---------------------------------------------------------------------------
+void EmRegsCFTuple::ReadByte(uint32 offset, uint8 * val)
+{
+ if (offset < sizeof(EmSector))
+ *val = tuple.Bytes[offset];
+ else
+ *val = 0;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFTuple::WriteByte
+// ---------------------------------------------------------------------------
+void EmRegsCFTuple::WriteByte(uint32 /*offset*/, uint8 /*val*/)
+{
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFTuple::ReadWord
+// ---------------------------------------------------------------------------
+void EmRegsCFTuple::ReadWord(uint32 offset, _Word * val)
+{
+ ReadByte(offset, &val->Bytes[0]);
+ ReadByte(offset+1, &val->Bytes[1]);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmRegsCFTuple::WriteWord
+// ---------------------------------------------------------------------------
+void EmRegsCFTuple::WriteWord(uint32 /*offset*/, _Word /*val*/)
+{
+}
diff --git a/SrcShared/Hardware/TRG/EmTRGCFMem.h b/SrcShared/Hardware/TRG/EmTRGCFMem.h
new file mode 100644
index 0000000..699daf1
--- /dev/null
+++ b/SrcShared/Hardware/TRG/EmTRGCFMem.h
@@ -0,0 +1,66 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+/****************************************************************************************
+** File: Bank_CF_Config.h
+** Date: 6/14/00
+** Project: POSE
+** Author: Dan Kolz
+** Notes: This class is an emulation of the config area on a CF card.
+** It takes its information from a hardcoded array in the source code.
+****************************************************************************************/
+
+#ifndef EmTRGCFMem_h
+#define EmTRGCFMem_h
+
+#include "EmRegs.h"
+#include "EmTRGCFDefs.h"
+#include "EmTRGDiskType.h"
+
+class EmRegsCFConfig
+{
+ public:
+ void Initialize(EmDiskTypeID ID);
+ void ReadByte(uint32 offset, uint8 * val);
+ void WriteByte(uint32 offset, uint8 val);
+ void ReadWord(uint32 offset, _Word * val);
+ void WriteWord(uint32 offset, _Word val);
+ private:
+ Boolean InRange(uint32 offset);
+};
+
+class EmRegsCFReset
+{
+ public:
+ void Initialize(EmDiskTypeID ID);
+ void ReadByte(uint32 offset, uint8 * val);
+ void WriteByte(uint32 offset, uint8 val);
+ void ReadWord(uint32 offset, _Word * val);
+ void WriteWord(uint32 offset, _Word val);
+ private:
+};
+
+class EmRegsCFTuple
+{
+ public:
+ void Initialize(EmDiskTypeID DiskTypeID);
+ void ReadByte(uint32 offset, uint8 * val);
+ void WriteByte(uint32 offset, uint8 val);
+ void ReadWord(uint32 offset, _Word * val);
+ void WriteWord(uint32 offset, _Word val);
+ private:
+ EmCurrDiskType CurrDisk;
+ EmSector tuple;
+};
+
+#endif // EmTRGCFMem_h
diff --git a/SrcShared/Hardware/TRG/EmTRGDiskIO.cpp b/SrcShared/Hardware/TRG/EmTRGDiskIO.cpp
new file mode 100644
index 0000000..9b43582
--- /dev/null
+++ b/SrcShared/Hardware/TRG/EmTRGDiskIO.cpp
@@ -0,0 +1,174 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmTRGDiskIO.h"
+
+/************************************************************************
+ * This class handles the generic low level disk access.
+ ************************************************************************/
+#include <stdio.h>
+
+#include "EmCommon.h"
+#include "EmTRGDiskIO.h"
+
+#define CFFILE_NAME "trgdrv.dat"
+#define SDFILE_NAME "trgdrvsd.dat"
+
+#define SECTOR_SIZE 512
+
+
+EmTRGDiskIO::EmTRGDiskIO()
+{
+ m_driveNo = UNKNOWN_DRIVE;
+}
+
+
+EmTRGDiskIO::~EmTRGDiskIO()
+{
+}
+
+
+char * EmTRGDiskIO::GetFilePath(int driveNo)
+{
+#if PLATFORM_WINDOWS
+ static char tmp[MAX_PATH];
+
+ if (driveNo == CF_DRIVE)
+ _snprintf(tmp, sizeof(tmp), "%s\\%s", getenv("WINDIR"), CFFILE_NAME);
+ else
+ _snprintf(tmp, sizeof(tmp), "%s\\%s", getenv("WINDIR"), SDFILE_NAME);
+ return(tmp);
+#else
+ if (driveNo == CF_DRIVE)
+ return CFFILE_NAME;
+ else
+ return SDFILE_NAME;
+#endif
+}
+
+int EmTRGDiskIO::Format(void)
+{
+ EmSector *buffer;
+ uint32 num, lba;
+ FILE *fp;
+
+ fp = fopen(GetFilePath(m_driveNo), "wb");
+ if (fp == NULL)
+ return -1;
+
+ buffer = new EmSector;
+ num = m_currDisk.GetNumSectors(m_diskTypeID);
+ for (lba=0; lba<num; lba++)
+ {
+ m_currDisk.GetSector(m_diskTypeID, lba, buffer);
+
+ // The most probable error condition is
+ // attempting to write to a full drive ... it could also
+ // be write-protected, or on a disconnected network drive.
+ if (fwrite(buffer, SECTOR_SIZE, 1, fp) == 0)
+ {
+ delete buffer;
+ fclose(fp);
+ return -1;
+ }
+ }
+ delete buffer;
+
+ return 0;
+}
+
+int EmTRGDiskIO::Read(uint32 sectorNum, void *buffer)
+{
+ FILE *fp;
+
+ if ((fp = fopen(GetFilePath(m_driveNo), "rb")) == NULL)
+ return -1;
+
+ if (fseek(fp, sectorNum * SECTOR_SIZE, SEEK_SET) == -1)
+ {
+ fclose(fp);
+ return -1;
+ }
+
+ if (fread(buffer, SECTOR_SIZE, 1, fp) != 1)
+ {
+ fclose(fp);
+ return -1;
+ }
+ fclose(fp);
+
+ return 0;
+}
+
+int EmTRGDiskIO::Write(uint32 sectorNum, void *buffer)
+{
+ FILE *fp;
+
+ if ((fp = fopen(GetFilePath(m_driveNo), "r+b")) == NULL)
+ return -1;
+
+ if (fseek(fp, sectorNum * SECTOR_SIZE, SEEK_SET) == -1)
+ {
+ fclose(fp);
+ return -1;
+ }
+
+ if (fwrite(buffer, SECTOR_SIZE, 1, fp) != 1)
+ {
+ fclose(fp);
+ return -1;
+ }
+ fclose(fp);
+
+ return 0;
+}
+
+
+void EmTRGDiskIO::Initialize(EmDiskTypeID DiskTypeID, int driveNo)
+{
+ m_diskTypeID = DiskTypeID;
+ m_driveNo = driveNo;
+}
+
+void EmTRGDiskIO::Dispose(void)
+{
+}
+
+int EmTRGDiskIO::ReadSector(uint32 sectorNum, void *buffer)
+{
+ int retval;
+
+ if ((retval = Read(sectorNum, buffer)) != 0)
+ {
+ Format();
+ retval = Read(sectorNum, buffer);
+ }
+
+ return retval;
+}
+
+
+
+int EmTRGDiskIO::WriteSector(uint32 sectorNum, void *buffer)
+{
+ int retval;
+
+ if ((retval = Write(sectorNum, buffer)) != 0)
+ {
+ Format();
+ retval = Write(sectorNum, buffer);
+ }
+
+ return retval;
+}
diff --git a/SrcShared/Hardware/TRG/EmTRGDiskIO.h b/SrcShared/Hardware/TRG/EmTRGDiskIO.h
new file mode 100644
index 0000000..74bca58
--- /dev/null
+++ b/SrcShared/Hardware/TRG/EmTRGDiskIO.h
@@ -0,0 +1,53 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmTRGDiskIO_h
+#define EmTRGDiskIO_h
+
+/************************************************************************
+ * This class handles the generic low level disk access.
+ ************************************************************************/
+#include "EmTRGCFDefs.h"
+#include "EmTRGDiskType.h"
+
+#define UNKNOWN_DRIVE 0
+#define CF_DRIVE 1
+#define SD_DRIVE 2
+
+#define SECTOR_SIZE 512
+
+class EmTRGDiskIO
+{
+private:
+ int m_driveNo;
+ EmDiskTypeID m_diskTypeID;
+ EmCurrDiskType m_currDisk;
+
+ int Format(void);
+ char *GetFilePath(int driveNo);
+
+ int Read(uint32 sectorNum, void *buffer);
+ int Write(uint32 sectorNum, void *buffer);
+
+public:
+ EmTRGDiskIO(void);
+ ~EmTRGDiskIO();
+
+ void Initialize(EmDiskTypeID DiskTypeID, int driveNo);
+ void Dispose(void);
+
+ int ReadSector(uint32 sectorNum, void *buffer);
+ int WriteSector(uint32 sectorNum, void *buffer);
+};
+
+#endif /* EmTRGDiskIO_h */
diff --git a/SrcShared/Hardware/TRG/EmTRGDiskType.cpp b/SrcShared/Hardware/TRG/EmTRGDiskType.cpp
new file mode 100644
index 0000000..571571f
--- /dev/null
+++ b/SrcShared/Hardware/TRG/EmTRGDiskType.cpp
@@ -0,0 +1,511 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmTRGDiskType.h"
+
+
+//---------------------------------------------------------------------------
+// This file is used to determine what sort of memory card is being
+// emulated ... so far, the only supported type is a generic 8MB card.
+// Card emulation requires having a copy of the Tuple, Drive ID, and
+// format sectors for a particular card
+//---------------------------------------------------------------------------
+
+#define B(x) x, 0
+
+static const EmSector _8MBTuple = {{
+ B(0x01), B(0x04), B(0xdf), B(0x4a), B(0x01), B(0xff), B(0x1c), B(0x04),
+ B(0x02), B(0xd9), B(0x01), B(0xff), B(0x18), B(0x02), B(0xdf), B(0x01),
+ B(0x20), B(0x04), B(0x07), B(0x00), B(0x00), B(0x00), B(0x15), B(0x15),
+ B(0x04), B(0x01), B(0x55), B(0x4e), B(0x49), B(0x54), B(0x59), B(0x20),
+ B(0x44), B(0x49), B(0x47), B(0x49), B(0x54), B(0x41), B(0x4c), B(0x00),
+ B(0x33), B(0x2e), B(0x30), B(0x00), B(0xff), B(0x21), B(0x02), B(0x04),
+ B(0x01), B(0x22), B(0x02), B(0x01), B(0x01), B(0x22), B(0x03), B(0x02),
+ B(0x0c), B(0x0f), B(0x1a), B(0x05), B(0x01), B(0x03), B(0x00), B(0x02),
+ B(0x0f), B(0x1b), B(0x08), B(0xc0), B(0xc0), B(0xa1), B(0x01), B(0x55),
+ B(0x08), B(0x00), B(0x20), B(0x1b), B(0x06), B(0x00), B(0x01), B(0x21),
+ B(0xb5), B(0x1e), B(0x4d), B(0x1b), B(0x0a), B(0xc1), B(0x41), B(0x99),
+ B(0x01), B(0x55), B(0x64), B(0xf0), B(0xff), B(0xff), B(0x20), B(0x1b),
+ B(0x06), B(0x01), B(0x01), B(0x21), B(0xb5), B(0x1e), B(0x4d), B(0x1b),
+ B(0x0f), B(0xc2), B(0x41), B(0x99), B(0x01), B(0x55), B(0xea), B(0x61),
+ B(0xf0), B(0x01), B(0x07), B(0xf6), B(0x03), B(0x01), B(0xee), B(0x20),
+ B(0x1b), B(0x06), B(0x02), B(0x01), B(0x21), B(0xb5), B(0x1e), B(0x4d),
+ B(0x1b), B(0x0f), B(0xc3), B(0x41), B(0x99), B(0x01), B(0x55), B(0xea),
+ B(0x61), B(0x70), B(0x01), B(0x07), B(0x76), B(0x03), B(0x01), B(0xee),
+ B(0x20), B(0x1b), B(0x06), B(0x03), B(0x01), B(0x21), B(0xb5), B(0x1e),
+ B(0x4d), B(0x14), B(0x00), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff),
+ B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff),
+ B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff),
+ B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff),
+ B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff),
+ B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff),
+ B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff),
+ B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff),
+ B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff),
+ B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff),
+ B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff),
+ B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff),
+ B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff), B(0xff),
+}};
+
+static const uint8 _8MBSD_CID[] = {
+ 0x00, 0x00, 0x02, 0x53, 0x44, 0x4D, 0x42, 0x2D,
+ 0x38, 0x00, 0x20, 0x06, 0x3A, 0x12, 0x32, 0x35
+};
+
+static const uint8 _8MBSD_CSD[] = {
+ 0x44, 0x26, 0x00, 0x2A, 0x1F, 0xF9, 0x81, 0xE9,
+ 0xE4, 0xB4, 0x83, 0xFF, 0x92, 0x40, 0x40, 0x81
+};
+
+#define W(x, y) x, y
+
+static const EmSector _8MBDriveID =
+{{
+ W(0x8A, 0x84), W(0xF6, 0x00), W(0x00, 0x00), W(0x02, 0x00), W(0x00, 0x00), W(0x00, 0x02), W(0x20, 0x00), W(0x00, 0x00),
+ W(0x80, 0x3D), W(0x00, 0x00), W(0x20, 0x20), W(0x20, 0x20), W(0x20, 0x20), W(0x20, 0x20), W(0x20, 0x20), W(0x20, 0x20),
+ W(0x20, 0x20), W(0x20, 0x20), W(0x20, 0x20), W(0x20, 0x20), W(0x02, 0x00), W(0x02, 0x00), W(0x04, 0x00), W(0x65, 0x52),
+ W(0x20, 0x76), W(0x2E, 0x31), W(0x32, 0x30), W(0x69, 0x48), W(0x61, 0x74), W(0x68, 0x63), W(0x20, 0x69), W(0x56, 0x43),
+ W(0x36, 0x20), W(0x31, 0x2E), W(0x32, 0x2E), W(0x20, 0x20), W(0x20, 0x20), W(0x20, 0x20), W(0x20, 0x20), W(0x20, 0x20),
+ W(0x20, 0x20), W(0x20, 0x20), W(0x20, 0x20), W(0x20, 0x20), W(0x20, 0x20), W(0x20, 0x20), W(0x20, 0x20), W(0x01, 0x00),
+ W(0x00, 0x00), W(0x00, 0x02), W(0x00, 0x00), W(0x00, 0x01), W(0x00, 0x00), W(0x01, 0x00), W(0xF6, 0x00), W(0x02, 0x00),
+ W(0x20, 0x00), W(0x80, 0x3D), W(0x00, 0x00), W(0x00, 0x01), W(0x80, 0x3D), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00),
+ W(0x20, 0x00), W(0x80, 0x3D), W(0x00, 0x00), W(0x00, 0x01), W(0x80, 0x3D), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00),
+ W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00),
+ W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00),
+ W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00),
+ W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00),
+ W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00),
+ W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00),
+ W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00),
+ W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00),
+ W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00),
+ W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00),
+ W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00),
+ W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00),
+ W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00),
+ W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00),
+ W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00),
+ W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00),
+ W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00),
+ W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00),
+ W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00),
+ W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00),
+ W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00),
+ W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00),
+ W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00), W(0x00, 0x00)
+}};
+
+static const EmSector _8MBMasterBootRecord =
+{{
+0xFA, 0x33, 0xC0, 0x8E, 0xD0, 0xBC, 0x00, 0x7C, 0x8B, 0xF4, 0x50, 0x07, 0x50, 0x1F, 0xFB, 0xFC,
+0xBF, 0x00, 0x06, 0xB9, 0x00, 0x01, 0xF2, 0xA5, 0xEA, 0x1D, 0x06, 0x00, 0x00, 0xBE, 0xBE, 0x07,
+0xB3, 0x04, 0x80, 0x3C, 0x80, 0x74, 0x0E, 0x80, 0x3C, 0x00, 0x75, 0x1C, 0x83, 0xC6, 0x10, 0xFE,
+0xCB, 0x75, 0xEF, 0xCD, 0x18, 0x8B, 0x14, 0x8B, 0x4C, 0x02, 0x8B, 0xEE, 0x83, 0xC6, 0x10, 0xFE,
+0xCB, 0x74, 0x1A, 0x80, 0x3C, 0x00, 0x74, 0xF4, 0xBE, 0x8B, 0x06, 0xAC, 0x3C, 0x00, 0x74, 0x0B,
+0x56, 0xBB, 0x07, 0x00, 0xB4, 0x0E, 0xCD, 0x10, 0x5E, 0xEB, 0xF0, 0xEB, 0xFE, 0xBF, 0x05, 0x00,
+0x4F, 0x75, 0xED, 0xBE, 0xA3, 0x06, 0xEB, 0xD3, 0xBE, 0xC2, 0x06, 0xBF, 0xFE, 0x7D, 0x81, 0x3D,
+0x55, 0xAA, 0x75, 0xC7, 0x8B, 0xF5, 0xEA, 0x00, 0x7C, 0x00, 0x00, 0x49, 0x6E, 0x76, 0x61, 0x6C,
+0x69, 0x64, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x74, 0x61, 0x62,
+0x6C, 0x65, 0x00, 0x45, 0x72, 0x72, 0x6F, 0x72, 0x20, 0x6C, 0x6F, 0x61, 0x64, 0x69, 0x6E, 0x67,
+0x20, 0x6F, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65,
+0x6D, 0x00, 0x4D, 0x69, 0x73, 0x73, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x70, 0x65, 0x72, 0x61, 0x74,
+0x69, 0x6E, 0x67, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x89, 0x70, 0x61, 0x72, 0x74, 0x5F,
+0x62, 0x6F, 0x6F, 0x74, 0x00, 0x00, 0xEB, 0x3C, 0x90, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01,
+0x01, 0x00, 0x01, 0x01, 0x20, 0xF4, 0x20, 0x00, 0x00, 0x00, 0x20, 0x3D, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA
+}};
+
+static const EmSector _8MBBootRecord =
+{{
+0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x08, 0x01, 0x00,
+0x02, 0x00, 0x02, 0x20, 0x3D, 0xF8, 0x06, 0x00, 0x20, 0x00, 0x02, 0x00, 0x20, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x29, 0x0D, 0x0B, 0x00, 0x00, 0x53, 0x41, 0x4E, 0x56, 0x4F,
+0x4C, 0x20, 0x20, 0x20, 0x20, 0x20, 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x8E,
+0xC0, 0x8E, 0xD8, 0xFB, 0xFC, 0xBE, 0x6A, 0x00, 0x81, 0xC6, 0x00, 0x7C, 0xAC, 0x0A, 0xC0, 0x74,
+0x0A, 0xB4, 0x0E, 0xB7, 0x00, 0xB3, 0x07, 0xCD, 0x10, 0xEB, 0xF1, 0x33, 0xC0, 0xCD, 0x16, 0xCD,
+0x19, 0xBE, 0xB3, 0x00, 0x81, 0xC6, 0x00, 0x7C, 0xEB, 0xE2, 0x0D, 0x0A, 0x4E, 0x6F, 0x6E, 0x2D,
+0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x20, 0x64, 0x69, 0x73, 0x6B, 0x20, 0x6F, 0x72, 0x20, 0x64,
+0x69, 0x73, 0x6B, 0x20, 0x65, 0x72, 0x72, 0x6F, 0x72, 0x0D, 0x0A, 0x52, 0x65, 0x70, 0x6C, 0x61,
+0x63, 0x65, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6B, 0x65, 0x20, 0x61, 0x6E,
+0x79, 0x20, 0x6B, 0x65, 0x79, 0x20, 0x77, 0x68, 0x65, 0x6E, 0x20, 0x72, 0x65, 0x61, 0x64, 0x79,
+0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x44, 0x69, 0x73, 0x6B, 0x20, 0x42, 0x6F, 0x6F, 0x74, 0x20, 0x66,
+0x61, 0x69, 0x6C, 0x75, 0x72, 0x65, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA
+}};
+
+static const EmSector _8MBFat =
+{{
+0xF8, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+}};
+
+static const EmSector _8MBRootDir =
+{{
+0xE5, 0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87, 'V', '?', 0x28, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x86, 0x54, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ '8', 'M', 'B', '_', 'C', 'A', 'R', 'D', ' ', ' ', 0x20, 0x28, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x86, 0x54, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+}};
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmGeneric8MB::EmGeneric8MB
+// ---------------------------------------------------------------------------
+EmGeneric8MB::EmGeneric8MB(void)
+{
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmGeneric8MB::~EmGeneric8MB
+// ---------------------------------------------------------------------------
+EmGeneric8MB::~EmGeneric8MB(void)
+{
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmGeneric8MB::GetTuple
+// ---------------------------------------------------------------------------
+EmSector * EmGeneric8MB::GetTuple(void)
+{
+ return((EmSector *)&_8MBTuple);
+}
+
+uint8 * EmGeneric8MB::GetSD_CSD(void)
+{
+ return ((uint8 *)&_8MBSD_CSD);
+}
+
+uint8 * EmGeneric8MB::GetSD_CID(void)
+{
+ return ((uint8 *)&_8MBSD_CID);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmGeneric8MB::GetDriveID
+// ---------------------------------------------------------------------------
+EmSector * EmGeneric8MB::GetDriveID(void)
+{
+ return((EmSector *)&_8MBDriveID);
+}
+
+#define _8MB_NUM_SECTORS 16384
+
+// ---------------------------------------------------------------------------
+// ¥ EmGeneric8MB::GetNumSectors
+// ---------------------------------------------------------------------------
+uint32 EmGeneric8MB::GetNumSectors(void)
+{
+ return _8MB_NUM_SECTORS;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmGeneric8MB::GetSector
+// ---------------------------------------------------------------------------
+EmSector * EmGeneric8MB::GetSector(LogicalBlockAddr lba)
+{
+ switch(lba)
+ {
+ case 0 :
+ return((EmSector *)&_8MBMasterBootRecord);
+ case 32 :
+ return((EmSector *)&_8MBBootRecord);
+ case 33 :
+ case 39 :
+ return((EmSector *)&_8MBFat);
+ case 45 :
+ return((EmSector *)&_8MBRootDir);
+ default :
+ return(EmDiskType::GetEmptySector());
+ }
+}
+
+static const EmSector DummySector =
+{{
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+}};
+
+// ---------------------------------------------------------------------------
+// ¥ EmDiskType::EmDiskType
+// ---------------------------------------------------------------------------
+EmDiskType::EmDiskType(void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmDiskType::~EmDiskType
+// ---------------------------------------------------------------------------
+EmDiskType::~EmDiskType(void)
+{
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmDiskType::GetTuple
+// ---------------------------------------------------------------------------
+EmSector * EmDiskType::GetTuple(void)
+{
+ return (EmSector *)&DummySector;
+}
+
+uint8 * EmDiskType::GetSD_CSD(void)
+{
+ return ((uint8 *)&DummySector);
+}
+
+uint8 * EmDiskType::GetSD_CID(void)
+{
+ return ((uint8 *)&DummySector);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmDiskType::GetDriveID
+// ---------------------------------------------------------------------------
+EmSector * EmDiskType::GetDriveID(void)
+{
+ return (EmSector *)&DummySector;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmDiskType::GetEmptySector
+// ---------------------------------------------------------------------------
+EmSector * EmDiskType::GetEmptySector(void)
+{
+ return (EmSector *)&DummySector;
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmCurrDiskType::EmCurrDiskType
+// ---------------------------------------------------------------------------
+EmCurrDiskType::EmCurrDiskType (void)
+{
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmCurrDiskType::~EmCurrDiskType
+// ---------------------------------------------------------------------------
+EmCurrDiskType::~EmCurrDiskType(void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCurrDiskType::GetTuple
+// ---------------------------------------------------------------------------
+void EmCurrDiskType::GetTuple(EmDiskTypeID ID,
+ EmSector * s)
+{
+ switch(ID)
+ {
+ case EM_DISK_GENERIC_8MB :
+ *s = *Generic8MB.GetTuple();
+ break;
+ default :
+ *s = *UnknownDisk.GetTuple();
+ break;
+ }
+}
+
+uint8 *EmCurrDiskType::GetSD_CSD(EmDiskTypeID ID)
+{
+ switch(ID)
+ {
+ case EM_DISK_GENERIC_8MB :
+ return Generic8MB.GetSD_CSD();
+ break;
+ default :
+ return UnknownDisk.GetSD_CSD();
+ break;
+ }
+}
+
+uint8 *EmCurrDiskType::GetSD_CID(EmDiskTypeID ID)
+{
+ switch(ID)
+ {
+ case EM_DISK_GENERIC_8MB :
+ return Generic8MB.GetSD_CID();
+ break;
+ default :
+ return UnknownDisk.GetSD_CID();
+ break;
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmCurrDiskType::GetDriveID
+// ---------------------------------------------------------------------------
+void EmCurrDiskType::GetDriveID(EmDiskTypeID ID,
+ EmSector * s)
+{
+ switch(ID)
+ {
+ case EM_DISK_GENERIC_8MB :
+ *s = *Generic8MB.GetDriveID();
+ break;
+ default :
+ *s = *UnknownDisk.GetDriveID();
+ break;
+ }
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmCurrDiskType::GetNumSectors
+// ---------------------------------------------------------------------------
+uint32 EmCurrDiskType::GetNumSectors(EmDiskTypeID ID)
+{
+ switch(ID)
+ {
+ case EM_DISK_GENERIC_8MB :
+ return Generic8MB.GetNumSectors();
+ default :
+ return 0;
+ }
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmCurrDiskType::GetSector
+// ---------------------------------------------------------------------------
+void EmCurrDiskType::GetSector(EmDiskTypeID ID,
+ LogicalBlockAddr lba,
+ EmSector * s)
+{
+ switch(ID)
+ {
+ case EM_DISK_GENERIC_8MB :
+ *s = *Generic8MB.GetSector(lba);
+ break;
+ default :
+ *s = *UnknownDisk.GetEmptySector();
+ break;
+ }
+}
diff --git a/SrcShared/Hardware/TRG/EmTRGDiskType.h b/SrcShared/Hardware/TRG/EmTRGDiskType.h
new file mode 100644
index 0000000..ac88a4d
--- /dev/null
+++ b/SrcShared/Hardware/TRG/EmTRGDiskType.h
@@ -0,0 +1,65 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+
+#ifndef EmTRGDiskType_h
+#define EmTRGDiskType_h
+
+#include "EmTRGCFDefs.h"
+
+class EmDiskType
+{
+public:
+ EmDiskType (void);
+ virtual ~EmDiskType (void);
+
+ EmSector * GetTuple(void);
+ uint8 * GetSD_CSD(void);
+ uint8 * GetSD_CID(void);
+ EmSector * GetDriveID(void);
+ EmSector * GetEmptySector(void);
+
+};
+
+class EmGeneric8MB : public EmDiskType
+{
+public:
+ EmGeneric8MB(void);
+ virtual ~EmGeneric8MB(void);
+
+ EmSector * GetTuple(void);
+ uint8 * GetSD_CSD(void);
+ uint8 * GetSD_CID(void);
+ EmSector * GetDriveID(void);
+ uint32 GetNumSectors(void);
+ EmSector * GetSector(LogicalBlockAddr lba);
+};
+
+class EmCurrDiskType
+{
+private:
+ EmDiskType UnknownDisk;
+ EmGeneric8MB Generic8MB;
+
+public:
+ EmCurrDiskType (void);
+ virtual ~EmCurrDiskType (void);
+
+ void GetTuple(EmDiskTypeID ID, EmSector * s);
+ uint8 * GetSD_CSD(EmDiskTypeID ID);
+ uint8 * GetSD_CID(EmDiskTypeID ID);
+ void GetDriveID(EmDiskTypeID ID, EmSector * s);
+ uint32 GetNumSectors(EmDiskTypeID ID);
+ void GetSector(EmDiskTypeID ID, LogicalBlockAddr lba, EmSector * s);
+};
+
+#endif /* EmTRGDiskType_h */
diff --git a/SrcShared/Hardware/TRG/EmTRGSD.cpp b/SrcShared/Hardware/TRG/EmTRGSD.cpp
new file mode 100644
index 0000000..ad84526
--- /dev/null
+++ b/SrcShared/Hardware/TRG/EmTRGSD.cpp
@@ -0,0 +1,321 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmTRGSD.h"
+
+/************************************************************************
+ * This class handles the SPI SD controller interface used in the
+ * HandEra 330.
+ ************************************************************************/
+
+// SPI SD commands
+#define SD_CMD0_GO_IDLE 0
+#define SD_CMD1_GO_OPERATIONAL 1
+#define SD_CMD9_SEND_CSD 9
+#define SD_CMD10_SEND_CID 10
+#define SD_CMD12_STOP_TRANS 12 // not supported
+#define SD_CMD13_SEND_STATUS 13
+#define SD_CMD16_SET_BLOCKLEN 16 // not supported
+#define SD_CMD17_READ_SECTOR 17
+#define SD_CMD18_READ_MULTI 18 // not supported
+#define SD_CMD24_WRITE_SECTOR 24
+#define SD_CMD25_WRITE_MULTI 25 // not supported
+#define SD_CMD27_PROGRAM_CSD 27 // not supported
+#define SD_CMD28_SET_WRITE_PROT 28 // not supported
+#define SD_CMD29_CLR_WRITE_PROT 29 // not supported
+#define SD_CMD30_SEND_WRITE_PROT 30 // not supported
+#define SD_CMD32_ERASE_WR_BLK_START 32 // not supported
+#define SD_CMD33_ERASE_WR_BLK_END 33 // not supported
+#define SD_CMD38_ERASE 38 // not supported
+#define SD_CMD42_LOCK_UNLOCK 42 // not supported
+#define SD_CMD55_APP_CMD 55 // not supported
+#define SD_CMD56_GEN_CMD 56 // not supported
+#define SD_CMD58_READ_OCR 58 // not supported
+#define SD_CMD59_CRC_ON_OFF 59 // not supported
+
+#define SD_CMD_SIZE 6 // in bytes
+#define SD_CSD_SIZE 16
+#define SD_CID_SIZE 16
+
+#define SD_R1_OP_STATE 0x00
+#define SD_R1_IDLE_STATE 0x01
+#define SD_R1_ILLEGAL_CMD 0x04
+
+#define SD_STATUS_OK 0x00
+#define SD_DATA_START 0xFE
+
+#define SD_DATA_OK 0xE5
+
+// ---------------------------------------------------------------------------
+// ¥ EmTRGSD::EmTRGSD
+// ---------------------------------------------------------------------------
+EmTRGSD::EmTRGSD()
+{
+ cmdIndex = 0;
+ sdBusState = sdBusGetCmdState;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmTRGSD::~EmTRGSD
+// ---------------------------------------------------------------------------
+EmTRGSD::~EmTRGSD()
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmTRGSD::Initialize
+// ---------------------------------------------------------------------------
+void EmTRGSD::Initialize(void)
+{
+ DiskIO.Initialize(EM_DISK_GENERIC_8MB, SD_DRIVE);
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmTRGSD::Dispose
+// ---------------------------------------------------------------------------
+void EmTRGSD::Dispose(void)
+{
+ DiskIO.Dispose();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmTRGSD::CompleteCommand
+// complete command processing now that we have the data for it too
+// ---------------------------------------------------------------------------
+void EmTRGSD::CompleteCommand(void)
+{
+ cmdIndex = 0;
+ dataIndex = 0;
+ sdBusState = sdBusSendResponseState;
+ sdBusNextState = sdBusGetCmdState;
+ responseIndex = 0;
+
+ switch (cmdBuffer[0] & 0x3f)
+ {
+ case SD_CMD24_WRITE_SECTOR :
+ DiskIO.WriteSector(sectorNum, &dataBuffer[1]);
+
+ // send data OK response
+ responseBuffer[0] = SD_DATA_OK;
+ responseSize = 1;
+ break;
+
+ default :
+ // unimplemented, should never get here
+ EmAssert(false);
+ sdBusState = sdBusGetCmdState;
+ break;
+ }
+}
+
+// ---------------------------------------------------------------------------
+// ¥ EmTRGSD::ProcessCommand
+// process the command we just received
+// ---------------------------------------------------------------------------
+void EmTRGSD::ProcessCommand(void)
+{
+ // clear command buffer
+ cmdIndex = 0;
+ sdBusState = sdBusSendResponseState;
+ sdBusNextState = sdBusGetCmdState;
+ responseIndex = 0;
+ dataIndex = 0;
+ dataSize = 0;
+
+ switch (cmdBuffer[0] & 0x3f)
+ {
+ case SD_CMD0_GO_IDLE :
+ responseBuffer[0] = SD_R1_IDLE_STATE;
+ responseSize = 1;
+ break;
+
+ case SD_CMD1_GO_OPERATIONAL :
+ responseBuffer[0] = SD_R1_OP_STATE;
+ responseSize = 1;
+ break;
+
+ case SD_CMD9_SEND_CSD :
+ responseBuffer[0] = SD_R1_OP_STATE;
+ responseSize = 1;
+
+ sdBusNextState = sdBusSendDataState;
+ dataBuffer[0] = SD_DATA_START;
+ memcpy(&dataBuffer[1], m_currDisk.GetSD_CSD(EM_DISK_GENERIC_8MB), SD_CSD_SIZE);
+ dataBuffer[SD_CSD_SIZE+2] = 0x00; // 16bit crc (unused)
+ dataBuffer[SD_CSD_SIZE+3] = 0x00;
+ dataSize = SD_CSD_SIZE+4;
+ break;
+
+ case SD_CMD10_SEND_CID :
+ responseBuffer[0] = SD_R1_OP_STATE;
+ responseSize = 1;
+
+ sdBusNextState = sdBusSendDataState;
+ dataBuffer[0] = SD_DATA_START;
+ memcpy(&dataBuffer[1], m_currDisk.GetSD_CID(EM_DISK_GENERIC_8MB), SD_CID_SIZE);
+ dataBuffer[SD_CID_SIZE+1] = 0x00; // 16bit crc (unused)
+ dataBuffer[SD_CID_SIZE+2] = 0x00;
+ dataSize = SD_CID_SIZE+3;
+ break;
+
+ case SD_CMD13_SEND_STATUS :
+ responseBuffer[0] = SD_R1_OP_STATE;
+ responseBuffer[1] = SD_STATUS_OK;
+ responseSize = 2;
+ break;
+
+ case SD_CMD17_READ_SECTOR :
+ responseBuffer[0] = SD_R1_OP_STATE;
+ responseSize = 1;
+
+ sdBusNextState = sdBusSendDataState;
+ dataBuffer[0] = SD_DATA_START;
+ sectorNum = ((cmdBuffer[1] << 24) | (cmdBuffer[2] << 16) | (cmdBuffer[3] << 8) | cmdBuffer[4]);
+ // SD sector number is really a byte address...
+ sectorNum /= SECTOR_SIZE;
+ DiskIO.ReadSector(sectorNum, &dataBuffer[1]);
+ dataBuffer[SECTOR_SIZE+1] = 0x00; // 16 bit crc (unused)
+ dataBuffer[SECTOR_SIZE+2] = 0x00;
+ dataSize = SECTOR_SIZE+3;
+ break;
+
+ case SD_CMD24_WRITE_SECTOR :
+ responseBuffer[0] = SD_R1_OP_STATE;
+ responseSize = 1;
+ sectorNum = ((cmdBuffer[1] << 24) | (cmdBuffer[2] << 16) | (cmdBuffer[3] << 8) | cmdBuffer[4]);
+ // SD sector number is really a byte address...
+ sectorNum /= SECTOR_SIZE;
+
+ sdBusNextState = sdBusGetDataState;
+ dataSize = SECTOR_SIZE+3;
+ break;
+
+ default: // unimplemented
+ responseBuffer[0] = SD_R1_ILLEGAL_CMD;
+ responseSize = 1;
+ break;
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmTRGSD::ExchangeBits
+// ---------------------------------------------------------------------------
+void EmTRGSD::ExchangeBits(uint16 txData, uint16 *rxData, uint16 bits)
+{
+ switch (bits)
+ {
+ case 8 :
+ switch (sdBusState)
+ {
+ case sdBusGetCmdState :
+ // all SPI commands start first two bits 0, 1
+ if ((cmdIndex != 0) || ((txData & 0xC0) == 0x40))
+ {
+ cmdBuffer[cmdIndex] = txData;
+ cmdIndex++;
+ if (cmdIndex == SD_CMD_SIZE)
+ ProcessCommand();
+ }
+ *rxData = 0xffff;
+ break;
+
+ case sdBusSendResponseState :
+ *rxData = responseBuffer[responseIndex++];
+ if (responseIndex == responseSize)
+ sdBusState = sdBusNextState;
+ break;
+
+ case sdBusGetDataState :
+ // all data blocks start with SD_DATA_START
+ if ((dataIndex != 0) || (txData == SD_DATA_START))
+ {
+ dataBuffer[dataIndex++] = txData;
+ if (dataIndex == dataSize)
+ {
+ // finish processing command waiting for this data...
+ CompleteCommand();
+ }
+ }
+ *rxData = 0xffff;
+ break;
+
+ case sdBusSendDataState :
+ *rxData = dataBuffer[dataIndex++];
+ if (dataIndex == dataSize)
+ sdBusState = sdBusGetCmdState;
+ break;
+
+ default :
+ break;
+ }
+ break;
+
+ case 16 :
+ switch (sdBusState)
+ {
+ case sdBusGetCmdState :
+ // all SPI commands start first two bits 0, 1
+ if ((cmdIndex != 0) || ((txData & 0xC000) == 0x4000))
+ {
+ cmdBuffer[cmdIndex++] = (txData & 0xff00) >> 8;
+ cmdBuffer[cmdIndex++] = (txData & 0x00ff);
+ if (cmdIndex >= SD_CMD_SIZE)
+ ProcessCommand();
+ }
+ *rxData = 0xffff;
+ break;
+
+ case sdBusSendResponseState :
+ *rxData = responseBuffer[responseIndex++] << 8;
+ *rxData |= responseBuffer[responseIndex++];
+ if (responseIndex >= responseSize)
+ sdBusState = sdBusNextState;
+ break;
+
+ case sdBusGetDataState :
+ dataBuffer[dataIndex++] = (txData & 0xff00) >> 8;
+ dataBuffer[dataIndex++] = (txData & 0x00ff);
+ if (dataIndex >= dataSize)
+ {
+ // finish processing command waiting for this data...
+ CompleteCommand();
+
+ sdBusState = sdBusGetCmdState;
+ }
+ *rxData = 0xffff;
+ break;
+
+ case sdBusSendDataState :
+ *rxData = dataBuffer[dataIndex++] << 8;
+ *rxData |= dataBuffer[dataIndex++];
+ if (dataIndex >= dataSize)
+ sdBusState = sdBusGetCmdState;
+ break;
+
+ default :
+ break;
+ }
+ break;
+
+ default :
+ // not supported...
+ EmAssert(false);
+ break;
+ }
+}
+
diff --git a/SrcShared/Hardware/TRG/EmTRGSD.h b/SrcShared/Hardware/TRG/EmTRGSD.h
new file mode 100644
index 0000000..bc5afd4
--- /dev/null
+++ b/SrcShared/Hardware/TRG/EmTRGSD.h
@@ -0,0 +1,64 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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.
+\* ===================================================================== */
+#ifndef _EmTRGSD_h_
+#define _EmTRGSD_h_
+
+#include "EmTRGDiskIO.h"
+
+/************************************************************************
+ * This class handles the SPI SD controller interface used in the
+ * HandEra 330.
+ ************************************************************************/
+
+
+typedef enum
+{
+ sdBusGetCmdState,
+ sdBusSendResponseState,
+ sdBusGetDataState,
+ sdBusSendDataState
+} sdBusStateType;
+
+
+class EmTRGSD
+{
+ private:
+ uint8 cmdBuffer[6];
+ int cmdIndex;
+ uint8 responseBuffer[2];
+ int responseIndex;
+ int responseSize;
+ uint8 dataBuffer[520];
+ int dataIndex;
+ int dataSize;
+ uint32 sectorNum;
+ sdBusStateType sdBusState;
+ sdBusStateType sdBusNextState; // next state after sending response
+
+ EmTRGDiskIO DiskIO;
+ EmCurrDiskType m_currDisk;
+
+ void ProcessCommand(void);
+ void CompleteCommand(void);
+
+ public :
+ EmTRGSD();
+ ~EmTRGSD();
+
+ void Initialize(void);
+ void Dispose(void);
+
+ void ExchangeBits(uint16 txData, uint16 *rxData, uint16 Bits);
+};
+
+#endif \ No newline at end of file