diff options
author | Benjamin Barenblat <bbarenblat@gmail.com> | 2021-11-23 23:13:26 -0500 |
---|---|---|
committer | Benjamin Barenblat <bbarenblat@gmail.com> | 2021-11-23 23:13:26 -0500 |
commit | e5df1aafb6d1346207343ccb858fa373e6b86301 (patch) | |
tree | fb26f0091dda7dd69d48d6b06169ea618332b99e /SrcShared/Hardware |
Check in the Palm OS Emulator, version 3.5 (2001). These files come from
the tarball present in the Debian archives [1]. The SHA-256 digest of
the tarball, c5e0d23424e88525bfba0ecdf0a432a8d93c885d04740df06a9eeee44e5f25e4,
matches the digest preserved in the FreeBSD ports tree [2], giving
further confidence that these files are as distributed by upstream.
[1] http://archive.debian.org/debian/pool/contrib/p/pose/
[2] https://svnweb.freebsd.org/ports/head/palm/pose/distinfo?revision=271305&view=markup&pathrev=282162
Diffstat (limited to 'SrcShared/Hardware')
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 = ®s.pc_p; + register uint8** pc_meta_oldp_p = ®s.pc_meta_oldp; + register uint8** pc_oldp_p = ®s.pc_oldp; + register uint32* spcflags_p = ®s.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(¶ms); + DiskIO.StartRead(¶ms); +} + +// --------------------------------------------------------------------------- +// ¥ EmRegsCFAta::CmdWriteSectors +// --------------------------------------------------------------------------- +void EmRegsCFAta::CmdWriteSectors(void) +{ + DiskIOParams params; + + GetDiskIOParams(¶ms); + DiskIO.StartWrite(¶ms); +} + +// --------------------------------------------------------------------------- +// ¥ 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 |