aboutsummaryrefslogtreecommitdiff
path: root/SrcShared/Hardware/EmRegs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'SrcShared/Hardware/EmRegs.cpp')
-rw-r--r--SrcShared/Hardware/EmRegs.cpp499
1 files changed, 499 insertions, 0 deletions
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).
+}