aboutsummaryrefslogtreecommitdiff
path: root/SrcShared/EmSubroutine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'SrcShared/EmSubroutine.cpp')
-rw-r--r--SrcShared/EmSubroutine.cpp3113
1 files changed, 3113 insertions, 0 deletions
diff --git a/SrcShared/EmSubroutine.cpp b/SrcShared/EmSubroutine.cpp
new file mode 100644
index 0000000..e378403
--- /dev/null
+++ b/SrcShared/EmSubroutine.cpp
@@ -0,0 +1,3113 @@
+/* -*- 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 "EmSubroutine.h"
+
+#include "Byteswapping.h" // Canonical
+#include "EmBankMapped.h" // EmBankMapped::GetEmulatedAddress
+#include "EmMemory.h" // EmMemPut8, etc.
+#include "EmPalmStructs.h" // EmAlias
+#include "EmStructs.h" // StringList
+#include "Miscellaneous.h" // SeparateList
+#include "Platform.h" // Platform::AllocateMemory
+
+#include <ctype.h> // isspace
+
+
+static EmParamInfo kEmParamInfo [] =
+{
+ // These are the base integral types.
+
+ { "Int8", kEm_SI1, false },
+ { "Int16", kEm_SI2, false },
+ { "Int32", kEm_SI4, false },
+// { "Int64", kEm_SI8, false },
+
+ { "UInt8", kEm_UI1, false },
+ { "UInt16", kEm_UI2, false },
+ { "UInt32", kEm_UI4, false },
+// { "UInt64", kEm_UI8, false },
+
+// { "Float", kEm_FP4, false },
+// { "Double", kEm_FP8, false },
+// { "LongDouble", kEm_FP16, false },
+
+ // These types are synonyms for the simple integral values.
+
+ { "char", kEm_SI1, false },
+ { "short", kEm_SI2, false },
+ { "long", kEm_SI4, false },
+
+ { "Char", kEm_UI1, false },
+ { "WChar", kEm_UI2, false },
+
+ { "Boolean", kEm_UI1, false },
+ { "ClipboardFormatType", kEm_UI1, false },
+ { "DlkSyncStateType", kEm_UI1, false },
+ { "FormObjectKind", kEm_UI1, false },
+ { "LocalIDKind", kEm_UI1, false },
+ { "NetSocketAddrEnum", kEm_UI1, false },
+ { "NetSocketTypeEnum", kEm_UI1, false },
+ { "SystemPreferencesChoice",kEm_UI1, false },
+
+ { "DmResID", kEm_UI2, false },
+ { "Err", kEm_UI2, false },
+ { "HostControlSelectorType",kEm_UI2, false },
+
+ { "Coord", kEm_SI2, false },
+ { "NetSocketRef", kEm_SI2, false },
+
+ { "DmResType", kEm_UI4, false },
+ { "LocalID", kEm_UI4, false },
+ { "NetFDSetType", kEm_UI4, false },
+ { "NetIPAddr", kEm_UI4, false },
+
+ { "HostBoolType", kEm_SI4, false },
+ { "HostClockType", kEm_SI4, false },
+ { "HostErrType", kEm_SI4, false },
+ { "HostIDType", kEm_SI4, false },
+ { "HostPlatformType", kEm_SI4, false },
+ { "HostSignalType", kEm_SI4, false },
+ { "HostSizeType", kEm_SI4, false },
+ { "HostTimeType", kEm_SI4, false },
+
+ // These types are pointer types, but are mostly treated as integral values.
+ // They get pushed onto the stack as a 4-byte value, but the stuff they
+ // point to is not affected or adjusted in any way. Also, when used as a
+ // return type on the 68K, they are treated as pointers, not integers.
+
+ { "DmOpenRef", kEm_Void, true },
+ { "HostFILEType", kEm_Void, true },
+
+ // The void type can be used as a return type ("void foo (int);"), or as an
+ // empty parameter list ("int foo (void);"). It can also be used as a
+ // generic pointer type ("void foo (void*);").
+
+ { "void", kEm_Void, false }
+
+};
+
+
+class EmSubroutineCPU
+{
+ public:
+ EmSubroutineCPU (void);
+ virtual ~EmSubroutineCPU (void);
+
+ virtual long FormatStack (EmParamList&) = 0;
+ virtual Err PrepareStack (Bool forCalling, Bool forStdArg, long stackSize) = 0;
+ virtual Err PrepareStack (emuptr) = 0;
+
+ virtual Err Call (uint16) = 0;
+ virtual Err CallSelector (uint16, uint16) = 0;
+
+ virtual void GetParamVal (EmParam&, int8&);
+ virtual void GetParamVal (EmParam&, int16&);
+ virtual void GetParamVal (EmParam&, int32&);
+ virtual void GetParamVal (EmParam&, int64&);
+ virtual void GetParamVal (EmParam&, uint8&);
+ virtual void GetParamVal (EmParam&, uint16&);
+ virtual void GetParamVal (EmParam&, uint32&);
+ virtual void GetParamVal (EmParam&, uint64&);
+ virtual void GetParamVal (EmParam&, float&);
+ virtual void GetParamVal (EmParam&, double&);
+ virtual void GetParamVal (EmParam&, long double&);
+
+ virtual void SetParamVal (EmParam&, int8);
+ virtual void SetParamVal (EmParam&, int16);
+ virtual void SetParamVal (EmParam&, int32);
+ virtual void SetParamVal (EmParam&, int64);
+ virtual void SetParamVal (EmParam&, uint8);
+ virtual void SetParamVal (EmParam&, uint16);
+ virtual void SetParamVal (EmParam&, uint32);
+ virtual void SetParamVal (EmParam&, uint64);
+ virtual void SetParamVal (EmParam&, float);
+ virtual void SetParamVal (EmParam&, double);
+ virtual void SetParamVal (EmParam&, long double);
+
+ virtual uint32 GetReturnRegInteger (void) = 0;
+ virtual emuptr GetReturnRegPointer (void) = 0;
+
+ virtual void SetReturnRegInteger (uint32) = 0;
+ virtual void SetReturnRegPointer (void*) = 0;
+
+ protected:
+ emuptr fStackPtr;
+};
+
+
+class EmSubroutineCPU68K : public EmSubroutineCPU
+{
+ public:
+ EmSubroutineCPU68K (void);
+ virtual ~EmSubroutineCPU68K (void);
+
+ virtual long FormatStack (EmParamList&);
+ virtual Err PrepareStack (Bool forCalling, Bool forStdArg, long stackSize);
+ virtual Err PrepareStack (emuptr) ;
+
+ virtual Err Call (uint16);
+ virtual Err CallSelector (uint16, uint16);
+
+ virtual uint32 GetReturnRegInteger (void);
+ virtual emuptr GetReturnRegPointer (void);
+
+ virtual void SetReturnRegInteger (uint32);
+ virtual void SetReturnRegPointer (void*);
+
+ private:
+ Err DoCall (uint16 trapWord);
+ char* GetStackBase (void);
+
+ static Bool HandleTrap12 (void);
+
+ enum { kStackSize = 4096 };
+ char fStack[kStackSize + 3];
+
+ uint32 fReturnedA0;
+ uint32 fReturnedD0;
+};
+
+
+class EmSubroutineCPUARM : public EmSubroutineCPU
+{
+ public:
+ EmSubroutineCPUARM (void);
+ virtual ~EmSubroutineCPUARM (void);
+
+ virtual long FormatStack (EmParamList&);
+ virtual Err PrepareStack (Bool forCalling, Bool forStdArg, long stackSize);
+ virtual Err PrepareStack (emuptr) ;
+
+ virtual Err Call (uint16);
+ virtual Err CallSelector (uint16, uint16);
+
+ virtual void GetParamVal (EmParam&, int8&);
+ virtual void GetParamVal (EmParam&, int16&);
+ virtual void GetParamVal (EmParam&, int32&);
+ virtual void GetParamVal (EmParam&, int64&);
+ virtual void GetParamVal (EmParam&, uint8&);
+ virtual void GetParamVal (EmParam&, uint16&);
+ virtual void GetParamVal (EmParam&, uint32&);
+ virtual void GetParamVal (EmParam&, uint64&);
+ virtual void GetParamVal (EmParam&, float&);
+ virtual void GetParamVal (EmParam&, double&);
+ virtual void GetParamVal (EmParam&, long double&);
+
+ virtual void SetParamVal (EmParam&, int8);
+ virtual void SetParamVal (EmParam&, int16);
+ virtual void SetParamVal (EmParam&, int32);
+ virtual void SetParamVal (EmParam&, int64);
+ virtual void SetParamVal (EmParam&, uint8);
+ virtual void SetParamVal (EmParam&, uint16);
+ virtual void SetParamVal (EmParam&, uint32);
+ virtual void SetParamVal (EmParam&, uint64);
+ virtual void SetParamVal (EmParam&, float);
+ virtual void SetParamVal (EmParam&, double);
+ virtual void SetParamVal (EmParam&, long double);
+
+ virtual uint32 GetReturnRegInteger (void);
+ virtual emuptr GetReturnRegPointer (void);
+
+ virtual void SetReturnRegInteger (uint32);
+ virtual void SetReturnRegPointer (void*);
+};
+
+
+#if NDEBUG
+ #define ERROR_CHECKING 0
+#else
+ #define ERROR_CHECKING 1
+#endif
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine constructor
+// ---------------------------------------------------------------------------
+
+EmSubroutine::EmSubroutine (void) :
+ fCPU (NULL),
+ fParams (),
+ fReturnType (),
+ fStackSize (-1)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine destructor
+// ---------------------------------------------------------------------------
+
+EmSubroutine::~EmSubroutine (void)
+{
+ delete fCPU;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::DescribeDecl
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::DescribeDecl (EmParamDecl returnType, EmParamListDecl decl)
+{
+ // Determine the return type.
+
+ Err err = this->ParseParamDecl (returnType, fReturnType);
+#if ERROR_CHECKING
+ if (err)
+ {
+ this->Reset ();
+ return err;
+ }
+#endif
+
+ // Determine the parameter types. Start by breaking up the parameter
+ // list at the commas.
+
+ StringList paramDecls;
+ ::SeparateList (paramDecls, decl, ',');
+
+ // Iterate over all the stuff we found between the commas.
+
+ StringList::iterator iter = paramDecls.begin ();
+ while (iter != paramDecls.end ())
+ {
+ // For each intra-comma chunk, parse it up and determine the
+ // type and name information it specifies.
+
+ err = this->AddParam (iter->c_str ());
+#if ERROR_CHECKING
+ if (err)
+ {
+ this->Reset ();
+ return err;
+ }
+#endif
+
+ ++iter;
+ }
+
+ // After all the parameters have been parsed up, determine where they
+ // should appear on the stack (specified as offsets from the stack
+ // pointer).
+
+ fStackSize = this->GetCPU ()->FormatStack (fParams);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::AddParam
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::AddParam (EmParamDecl decl)
+{
+ EmParam param;
+
+#if ERROR_CHECKING
+ Err err = this->ParseParamDecl (decl, param);
+ if (err)
+ {
+ this->Reset ();
+ return err;
+ }
+#else
+ this->ParseParamDecl (decl, param);
+#endif
+
+ // If it's not just a bare "(void)", push it onto our collection
+ // of parsed parameter information.
+
+ if (param.fByRef || param.fType != kEm_Void)
+ {
+ fParams.push_back (param);
+ }
+
+ // After all the parameters have been parsed up, determine where they
+ // should appear on the stack (specified as offsets from the stack
+ // pointer).
+
+ fStackSize = this->GetCPU ()->FormatStack (fParams);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::PrepareStack
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::PrepareStack (Bool forCalling, Bool forStdArg)
+{
+ return this->GetCPU ()->PrepareStack (forCalling, forStdArg, fStackSize);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::PrepareStack
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::PrepareStack (emuptr stackAddr)
+{
+ return this->GetCPU ()->PrepareStack (stackAddr);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::Reset
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::Reset (void)
+{
+ fParams.clear ();
+ fReturnType = EmParam ();
+
+ delete fCPU;
+ fCPU = NULL;
+
+ fStackSize = -1;
+
+ return errNone;
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::GetParamVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::GetParamVal (EmParamNameArg name, int8& result)
+{
+ EmParamList::iterator iter = this->FindParam (name);
+
+#if ERROR_CHECKING
+ if (iter == fParams.end ())
+ {
+ EmAssert (false);
+ return kEmErrUnknownParameter;
+ }
+
+ if (iter->fType != kEm_SI1)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (iter->fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ fCPU->GetParamVal (*iter, result);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::GetParamVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::GetParamVal (EmParamNameArg name, int16& result)
+{
+ EmParamList::iterator iter = this->FindParam (name);
+
+#if ERROR_CHECKING
+ if (iter == fParams.end ())
+ {
+ EmAssert (false);
+ return kEmErrUnknownParameter;
+ }
+
+ if (iter->fType != kEm_SI2)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (iter->fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ fCPU->GetParamVal (*iter, result);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::GetParamVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::GetParamVal (EmParamNameArg name, int32& result)
+{
+ EmParamList::iterator iter = this->FindParam (name);
+
+#if ERROR_CHECKING
+ if (iter == fParams.end ())
+ {
+ EmAssert (false);
+ return kEmErrUnknownParameter;
+ }
+
+ if (iter->fType != kEm_SI4)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (iter->fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ fCPU->GetParamVal (*iter, result);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::GetParamVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::GetParamVal (EmParamNameArg name, int64& result)
+{
+ EmParamList::iterator iter = this->FindParam (name);
+
+#if ERROR_CHECKING
+ if (iter == fParams.end ())
+ {
+ EmAssert (false);
+ return kEmErrUnknownParameter;
+ }
+
+ if (iter->fType != kEm_SI8)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (iter->fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ fCPU->GetParamVal (*iter, result);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::GetParamVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::GetParamVal (EmParamNameArg name, uint8& result)
+{
+ EmParamList::iterator iter = this->FindParam (name);
+
+#if ERROR_CHECKING
+ if (iter == fParams.end ())
+ {
+ EmAssert (false);
+ return kEmErrUnknownParameter;
+ }
+
+ if (iter->fType != kEm_UI1)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (iter->fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ fCPU->GetParamVal (*iter, result);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::GetParamVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::GetParamVal (EmParamNameArg name, uint16& result)
+{
+ EmParamList::iterator iter = this->FindParam (name);
+
+#if ERROR_CHECKING
+ if (iter == fParams.end ())
+ {
+ EmAssert (false);
+ return kEmErrUnknownParameter;
+ }
+
+ if (iter->fType != kEm_UI2)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (iter->fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ fCPU->GetParamVal (*iter, result);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::GetParamVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::GetParamVal (EmParamNameArg name, uint32& result)
+{
+ EmParamList::iterator iter = this->FindParam (name);
+
+#if ERROR_CHECKING
+ if (iter == fParams.end ())
+ {
+ EmAssert (false);
+ return kEmErrUnknownParameter;
+ }
+
+ if (!iter->fByRef && iter->fType != kEm_UI4)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+// if (iter->fByRef)
+// {
+// EmAssert (false);
+// return kEmErrTypeMismatch;
+// }
+#endif
+
+ fCPU->GetParamVal (*iter, result);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::GetParamVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::GetParamVal (EmParamNameArg name, uint64& result)
+{
+ EmParamList::iterator iter = this->FindParam (name);
+
+#if ERROR_CHECKING
+ if (iter == fParams.end ())
+ {
+ EmAssert (false);
+ return kEmErrUnknownParameter;
+ }
+
+ if (iter->fType != kEm_UI8)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (iter->fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ fCPU->GetParamVal (*iter, result);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::GetParamVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::GetParamVal (EmParamNameArg name, float& result)
+{
+ EmParamList::iterator iter = this->FindParam (name);
+
+#if ERROR_CHECKING
+ if (iter == fParams.end ())
+ {
+ EmAssert (false);
+ return kEmErrUnknownParameter;
+ }
+
+ if (iter->fType != kEm_FP4)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (iter->fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ fCPU->GetParamVal (*iter, result);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::GetParamVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::GetParamVal (EmParamNameArg name, double& result)
+{
+ EmParamList::iterator iter = this->FindParam (name);
+
+#if ERROR_CHECKING
+ if (iter == fParams.end ())
+ {
+ EmAssert (false);
+ return kEmErrUnknownParameter;
+ }
+
+ if (iter->fType != kEm_FP8)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (iter->fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ fCPU->GetParamVal (*iter, result);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::GetParamVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::GetParamVal (EmParamNameArg name, long double& result)
+{
+ EmParamList::iterator iter = this->FindParam (name);
+
+#if ERROR_CHECKING
+ if (iter == fParams.end ())
+ {
+ EmAssert (false);
+ return kEmErrUnknownParameter;
+ }
+
+ if (iter->fType != kEm_FP16)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (iter->fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ fCPU->GetParamVal (*iter, result);
+
+ return errNone;
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::GetReturnVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::GetReturnVal (int8& result)
+{
+#if ERROR_CHECKING
+ if (fReturnType.fType != kEm_SI1)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (fReturnType.fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ uint32 reg = this->GetReturnRegInteger ();
+ result = (int8) reg;
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::GetReturnVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::GetReturnVal (int16& result)
+{
+#if ERROR_CHECKING
+ if (fReturnType.fType != kEm_SI2)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (fReturnType.fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ uint32 reg = this->GetReturnRegInteger ();
+ result = (int16) reg;
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::GetReturnVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::GetReturnVal (int32& result)
+{
+#if ERROR_CHECKING
+ if (fReturnType.fType != kEm_SI4)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (fReturnType.fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ uint32 reg = this->GetReturnRegInteger ();
+ result = (int32) reg;
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::GetReturnVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::GetReturnVal (int64& /*result*/)
+{
+#if ERROR_CHECKING
+ if (fReturnType.fType != kEm_SI8)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (fReturnType.fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ EmAssert (false);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::GetReturnVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::GetReturnVal (uint8& result)
+{
+#if ERROR_CHECKING
+ if (fReturnType.fType != kEm_UI1)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (fReturnType.fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ uint32 reg = this->GetReturnRegInteger ();
+ result = (uint8) reg;
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::GetReturnVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::GetReturnVal (uint16& result)
+{
+#if ERROR_CHECKING
+ if (fReturnType.fType != kEm_UI2)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (fReturnType.fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ uint32 reg = this->GetReturnRegInteger ();
+ result = (uint16) reg;
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::GetReturnVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::GetReturnVal (uint32& result)
+{
+#if ERROR_CHECKING
+ if (!fReturnType.fByRef && fReturnType.fType != kEm_UI4)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+// if (fReturnType.fByRef)
+// {
+// EmAssert (false);
+// return kEmErrTypeMismatch;
+// }
+#endif
+
+ uint32 reg;
+
+ if (fReturnType.fByRef)
+ reg = this->GetReturnRegPointer ();
+ else
+ reg = this->GetReturnRegInteger ();
+
+ result = reg;
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::GetReturnVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::GetReturnVal (uint64& /*result*/)
+{
+#if ERROR_CHECKING
+ if (fReturnType.fType != kEm_UI8)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (fReturnType.fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ EmAssert (false);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::GetReturnVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::GetReturnVal (float& /*result*/)
+{
+#if ERROR_CHECKING
+ if (fReturnType.fType != kEm_FP4)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (fReturnType.fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ EmAssert (false);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::GetReturnVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::GetReturnVal (double& /*result*/)
+{
+#if ERROR_CHECKING
+ if (fReturnType.fType != kEm_FP8)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (fReturnType.fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ EmAssert (false);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::GetReturnVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::GetReturnVal (long double&)
+{
+#if ERROR_CHECKING
+ if (fReturnType.fType != kEm_FP16)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (fReturnType.fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ EmAssert (false);
+
+ return errNone;
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::SetParamVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::SetParamVal (EmParamNameArg name, int8 val)
+{
+ EmParamList::iterator iter = this->FindParam (name);
+
+#if ERROR_CHECKING
+ if (iter == fParams.end ())
+ {
+ EmAssert (false);
+ return kEmErrUnknownParameter;
+ }
+
+ if (iter->fType != kEm_SI1)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (iter->fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ fCPU->SetParamVal (*iter, val);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::SetParamVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::SetParamVal (EmParamNameArg name, int16 val)
+{
+ EmParamList::iterator iter = this->FindParam (name);
+
+#if ERROR_CHECKING
+ if (iter == fParams.end ())
+ {
+ EmAssert (false);
+ return kEmErrUnknownParameter;
+ }
+
+ if (iter->fType != kEm_SI2)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (iter->fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ fCPU->SetParamVal (*iter, val);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::SetParamVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::SetParamVal (EmParamNameArg name, int32 val)
+{
+ EmParamList::iterator iter = this->FindParam (name);
+
+#if ERROR_CHECKING
+ if (iter == fParams.end ())
+ {
+ EmAssert (false);
+ return kEmErrUnknownParameter;
+ }
+
+ if (iter->fType != kEm_SI4)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (iter->fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ fCPU->SetParamVal (*iter, val);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::SetParamVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::SetParamVal (EmParamNameArg name, int64 val)
+{
+ EmParamList::iterator iter = this->FindParam (name);
+
+#if ERROR_CHECKING
+ if (iter == fParams.end ())
+ {
+ EmAssert (false);
+ return kEmErrUnknownParameter;
+ }
+
+ if (iter->fType != kEm_SI8)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (iter->fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ fCPU->SetParamVal (*iter, val);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::SetParamVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::SetParamVal (EmParamNameArg name, uint8 val)
+{
+ EmParamList::iterator iter = this->FindParam (name);
+
+#if ERROR_CHECKING
+ if (iter == fParams.end ())
+ {
+ EmAssert (false);
+ return kEmErrUnknownParameter;
+ }
+
+ if (iter->fType != kEm_UI1)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (iter->fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ fCPU->SetParamVal (*iter, val);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::SetParamVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::SetParamVal (EmParamNameArg name, uint16 val)
+{
+ EmParamList::iterator iter = this->FindParam (name);
+
+#if ERROR_CHECKING
+ if (iter == fParams.end ())
+ {
+ EmAssert (false);
+ return kEmErrUnknownParameter;
+ }
+
+ if (iter->fType != kEm_UI2)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (iter->fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ fCPU->SetParamVal (*iter, val);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::SetParamVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::SetParamVal (EmParamNameArg name, uint32 val)
+{
+ EmParamList::iterator iter = this->FindParam (name);
+
+#if ERROR_CHECKING
+ if (iter == fParams.end ())
+ {
+ EmAssert (false);
+ return kEmErrUnknownParameter;
+ }
+
+ if (!iter->fByRef && iter->fType != kEm_UI4)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+// if (iter->fByRef)
+// {
+// EmAssert (false);
+// return kEmErrTypeMismatch;
+// }
+#endif
+
+ fCPU->SetParamVal (*iter, val);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::SetParamVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::SetParamVal (EmParamNameArg name, uint64 val)
+{
+ EmParamList::iterator iter = this->FindParam (name);
+
+#if ERROR_CHECKING
+ if (iter == fParams.end ())
+ {
+ EmAssert (false);
+ return kEmErrUnknownParameter;
+ }
+
+ if (iter->fType != kEm_UI8)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (iter->fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ fCPU->SetParamVal (*iter, val);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::SetParamVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::SetParamVal (EmParamNameArg name, float val)
+{
+ EmParamList::iterator iter = this->FindParam (name);
+
+#if ERROR_CHECKING
+ if (iter == fParams.end ())
+ {
+ EmAssert (false);
+ return kEmErrUnknownParameter;
+ }
+
+ if (iter->fType != kEm_FP4)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (iter->fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ fCPU->SetParamVal (*iter, val);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::SetParamVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::SetParamVal (EmParamNameArg name, double val)
+{
+ EmParamList::iterator iter = this->FindParam (name);
+
+#if ERROR_CHECKING
+ if (iter == fParams.end ())
+ {
+ EmAssert (false);
+ return kEmErrUnknownParameter;
+ }
+
+ if (iter->fType != kEm_FP8)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (iter->fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ fCPU->SetParamVal (*iter, val);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::SetParamVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::SetParamVal (EmParamNameArg name, long double val)
+{
+ EmParamList::iterator iter = this->FindParam (name);
+
+#if ERROR_CHECKING
+ if (iter == fParams.end ())
+ {
+ EmAssert (false);
+ return kEmErrUnknownParameter;
+ }
+
+ if (iter->fType != kEm_FP16)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (iter->fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ fCPU->SetParamVal (*iter, val);
+
+ return errNone;
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::SetReturnVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::SetReturnVal (int8 val)
+{
+#if ERROR_CHECKING
+ if (fReturnType.fType != kEm_SI1)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (fReturnType.fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ this->SetReturnRegInteger ((uint32)(uint8) val);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::SetReturnVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::SetReturnVal (int16 val)
+{
+#if ERROR_CHECKING
+ if (fReturnType.fType != kEm_SI2)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (fReturnType.fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ this->SetReturnRegInteger ((uint32)(uint16) val);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::SetReturnVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::SetReturnVal (int32 val)
+{
+#if ERROR_CHECKING
+ if (fReturnType.fType != kEm_SI4)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (fReturnType.fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ this->SetReturnRegInteger ((uint32) val);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::SetReturnVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::SetReturnVal (int64)
+{
+#if ERROR_CHECKING
+ if (fReturnType.fType != kEm_SI8)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (fReturnType.fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+// this->SetReturnRegInteger ((uint32) val);
+ EmAssert (false);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::SetReturnVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::SetReturnVal (uint8 val)
+{
+#if ERROR_CHECKING
+ if (fReturnType.fType != kEm_UI1)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (fReturnType.fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ this->SetReturnRegInteger (val);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::SetReturnVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::SetReturnVal (uint16 val)
+{
+#if ERROR_CHECKING
+ if (fReturnType.fType != kEm_UI2)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (fReturnType.fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+ this->SetReturnRegInteger (val);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::SetReturnVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::SetReturnVal (uint32 val)
+{
+#if ERROR_CHECKING
+ if (!fReturnType.fByRef && fReturnType.fType != kEm_UI4)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+// if (fReturnType.fByRef)
+// {
+// EmAssert (false);
+// return kEmErrTypeMismatch;
+// }
+#endif
+
+ if (fReturnType.fByRef)
+ this->SetReturnRegPointer ((void*) val);
+ else
+ this->SetReturnRegInteger (val);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::SetReturnVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::SetReturnVal (uint64)
+{
+#if ERROR_CHECKING
+ if (fReturnType.fType != kEm_UI8)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (fReturnType.fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+// this->SetReturnRegInteger (val);
+ EmAssert (false);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::SetReturnVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::SetReturnVal (float)
+{
+#if ERROR_CHECKING
+ if (fReturnType.fType != kEm_FP4)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (fReturnType.fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+// this->SetReturnRegInteger (val);
+ EmAssert (false);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::SetReturnVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::SetReturnVal (double)
+{
+#if ERROR_CHECKING
+ if (fReturnType.fType != kEm_FP8)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (fReturnType.fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+// this->SetReturnRegInteger (val);
+ EmAssert (false);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::SetReturnVal
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::SetReturnVal (long double)
+{
+#if ERROR_CHECKING
+ if (fReturnType.fType != kEm_FP16)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+
+ if (fReturnType.fByRef)
+ {
+ EmAssert (false);
+ return kEmErrTypeMismatch;
+ }
+#endif
+
+// this->SetReturnRegInteger (val);
+ EmAssert (false);
+
+ return errNone;
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::Call
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::Call (uint16 trapWord)
+{
+ return this->GetCPU ()->Call (trapWord);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::CallSelector
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::CallSelector (uint16 trapWord, uint16 selector)
+{
+ return this->GetCPU ()->CallSelector (trapWord, selector);
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::GetReturnRegInteger
+// ---------------------------------------------------------------------------
+
+uint32 EmSubroutine::GetReturnRegInteger (void)
+{
+ return this->GetCPU ()->GetReturnRegInteger ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::GetReturnRegPointer
+// ---------------------------------------------------------------------------
+
+emuptr EmSubroutine::GetReturnRegPointer (void)
+{
+ return this->GetCPU ()->GetReturnRegPointer ();
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::SetReturnRegInteger
+// ---------------------------------------------------------------------------
+
+void EmSubroutine::SetReturnRegInteger (uint32 val)
+{
+ this->GetCPU ()->SetReturnRegInteger (val);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::SetReturnRegPointer
+// ---------------------------------------------------------------------------
+
+void EmSubroutine::SetReturnRegPointer (void* val)
+{
+ this->GetCPU ()->SetReturnRegPointer (val);
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::GetCPU
+// ---------------------------------------------------------------------------
+
+EmSubroutineCPU* EmSubroutine::GetCPU (void)
+{
+ if (fCPU == NULL)
+ {
+ if (this->Is68K ())
+ fCPU = new EmSubroutineCPU68K;
+ else if (this->IsARM ())
+ fCPU = new EmSubroutineCPUARM;
+ else
+ EmAssert (false);
+ }
+
+ return fCPU;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::Is68K
+// ---------------------------------------------------------------------------
+
+Bool EmSubroutine::Is68K (void)
+{
+ return true;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::IsARM
+// ---------------------------------------------------------------------------
+
+Bool EmSubroutine::IsARM (void)
+{
+ return false;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::ParseParamDecl
+// ---------------------------------------------------------------------------
+
+Err EmSubroutine::ParseParamDecl (EmParamDecl decl, EmParam& result)
+{
+ string token;
+ string::size_type offset = 0;
+
+ // Get the type.
+
+ token = this->GetToken (decl, offset);
+
+ // See if we recognize it.
+
+ size_t ii;
+ for (ii = 0; ii < countof (kEmParamInfo); ++ii)
+ {
+ if (token == kEmParamInfo[ii].fTypeName)
+ {
+ result.fType = kEmParamInfo[ii].fType;
+ result.fByRef = kEmParamInfo[ii].fByRef;
+ break;
+ }
+ }
+
+ // If not, try some default processing.
+
+ if (ii >= countof (kEmParamInfo))
+ {
+ // Set it up as an unknown type. Hopefully, it will be
+ // followed by a "*", so that we can treat it as a pointer type.
+
+ result.fType = kEm_Unknown;
+ result.fByRef = false;
+
+ // Check the name to see if it ends in "Ptr" or "Handle. If so,
+ // treat it as a pointer type.
+
+ if (::EndsWith (token.c_str (), "Ptr") ||
+ ::EndsWith (token.c_str (), "Handle"))
+ {
+ result.fByRef = true;
+ }
+ }
+
+ // Get what follows the type. This is either the parameter name,
+ // or a "*" to indicate a reference parameter.
+
+ token = this->GetToken (decl, offset);
+
+ if (token == "*")
+ {
+ result.fByRef = true;
+
+ // OK, *now* get the parameter name.
+
+ token = this->GetToken (decl, offset);
+
+ // Whoops...it's another "*". So make the param a ptr to a ptr.
+
+ while (token == "*")
+ {
+ result.fType = kEm_Void;
+
+ // OK, *now* get the parameter name.
+
+ token = this->GetToken (decl, offset);
+ }
+ }
+
+ result.fName = token;
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::GetToken
+// ---------------------------------------------------------------------------
+
+string EmSubroutine::GetToken (EmParamDecl decl, string::size_type& offset)
+{
+ string result;
+
+ // Get a C++ string so that we can use the STL routines.
+
+ string str (decl);
+
+ do
+ {
+ // Skip whitespace.
+
+ while (isspace (str[offset]))
+ ++offset;
+
+ // Nothing but whitespace. This could happen if the
+ // declaration has a type but no name.
+
+ if (offset >= str.size ())
+ {
+ result.erase ();
+ }
+
+ // If this is a "*", return it.
+
+ else if (str[offset] == '*')
+ {
+ ++offset;
+ result = "*";
+ }
+
+ // Otherwise, scoop of the identifer
+
+ else
+ {
+ string::size_type begin = offset;
+
+ while (isalnum (str[offset]) || str[offset] == '_')
+ ++offset;
+
+ result = str.substr (begin, offset - begin);
+ }
+
+ // If it's "const", "signed" or "unsigned", filter it out.
+ }
+ while (result == "const" || result == "signed" || result == "unsigned");
+
+ return result;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutine::FindParam
+// ---------------------------------------------------------------------------
+
+EmParamList::iterator EmSubroutine::FindParam (EmParamNameArg name)
+{
+ EmParamList::iterator iter = fParams.begin ();
+
+ while (iter != fParams.end ())
+ {
+ if (iter->fName == name)
+ {
+ break;
+ }
+
+ ++iter;
+ }
+
+ return iter;
+}
+
+
+#pragma mark ------------------------------
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU::EmSubroutineCPU
+// ---------------------------------------------------------------------------
+
+EmSubroutineCPU::EmSubroutineCPU (void) :
+ fStackPtr (EmMemNULL)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU::~EmSubroutineCPU
+// ---------------------------------------------------------------------------
+
+EmSubroutineCPU::~EmSubroutineCPU (void)
+{
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU::GetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPU::GetParamVal (EmParam& param, int8& result)
+{
+#if ERROR_CHECKING
+ EmAssert (fStackPtr);
+ EmAssert (param.fStackOffset >= 0);
+#endif
+
+ result = EmMemGet8 (fStackPtr + param.fStackOffset);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU::GetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPU::GetParamVal (EmParam& param, int16& result)
+{
+#if ERROR_CHECKING
+ EmAssert (fStackPtr);
+ EmAssert (param.fStackOffset >= 0);
+#endif
+
+ result = EmMemGet16 (fStackPtr + param.fStackOffset);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU::GetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPU::GetParamVal (EmParam& param, int32& result)
+{
+#if ERROR_CHECKING
+ EmAssert (fStackPtr);
+ EmAssert (param.fStackOffset >= 0);
+#endif
+
+ result = EmMemGet32 (fStackPtr + param.fStackOffset);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU::GetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPU::GetParamVal (EmParam& param, int64& /*result*/)
+{
+#if ERROR_CHECKING
+ EmAssert (fStackPtr);
+ EmAssert (param.fStackOffset >= 0);
+#endif
+
+ EmAssert (false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU::GetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPU::GetParamVal (EmParam& param, uint8& result)
+{
+#if ERROR_CHECKING
+ EmAssert (fStackPtr);
+ EmAssert (param.fStackOffset >= 0);
+#endif
+
+ result = EmMemGet8 (fStackPtr + param.fStackOffset);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU::GetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPU::GetParamVal (EmParam& param, uint16& result)
+{
+#if ERROR_CHECKING
+ EmAssert (fStackPtr);
+ EmAssert (param.fStackOffset >= 0);
+#endif
+
+ result = EmMemGet16 (fStackPtr + param.fStackOffset);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU::GetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPU::GetParamVal (EmParam& param, uint32& result)
+{
+#if ERROR_CHECKING
+ EmAssert (fStackPtr);
+ EmAssert (param.fStackOffset >= 0);
+#endif
+
+ result = EmMemGet32 (fStackPtr + param.fStackOffset);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU::GetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPU::GetParamVal (EmParam& param, uint64& /*result*/)
+{
+#if ERROR_CHECKING
+ EmAssert (fStackPtr);
+ EmAssert (param.fStackOffset >= 0);
+#endif
+
+ EmAssert (false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU::GetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPU::GetParamVal (EmParam& param, float& /*result*/)
+{
+#if ERROR_CHECKING
+ EmAssert (fStackPtr);
+ EmAssert (param.fStackOffset >= 0);
+#endif
+
+ EmAssert (false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU::GetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPU::GetParamVal (EmParam& param, double& /*result*/)
+{
+#if ERROR_CHECKING
+ EmAssert (fStackPtr);
+ EmAssert (param.fStackOffset >= 0);
+#endif
+
+ EmAssert (false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU::GetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPU::GetParamVal (EmParam& param, long double& /*result*/)
+{
+#if ERROR_CHECKING
+ EmAssert (fStackPtr);
+ EmAssert (param.fStackOffset >= 0);
+#endif
+
+ EmAssert (false);
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU::SetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPU::SetParamVal (EmParam& param, int8 val)
+{
+#if ERROR_CHECKING
+ EmAssert (fStackPtr);
+ EmAssert (param.fStackOffset >= 0);
+#endif
+
+ EmMemPut8 (fStackPtr + param.fStackOffset, val);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU::SetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPU::SetParamVal (EmParam& param, int16 val)
+{
+#if ERROR_CHECKING
+ EmAssert (fStackPtr);
+ EmAssert (param.fStackOffset >= 0);
+#endif
+
+ EmMemPut16 (fStackPtr + param.fStackOffset, val);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU::SetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPU::SetParamVal (EmParam& param, int32 val)
+{
+#if ERROR_CHECKING
+ EmAssert (fStackPtr);
+ EmAssert (param.fStackOffset >= 0);
+#endif
+
+ EmMemPut32 (fStackPtr + param.fStackOffset, val);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU::SetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPU::SetParamVal (EmParam& param, int64 /*val*/)
+{
+#if ERROR_CHECKING
+ EmAssert (fStackPtr);
+ EmAssert (param.fStackOffset >= 0);
+#endif
+
+ EmAssert (false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU::SetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPU::SetParamVal (EmParam& param, uint8 val)
+{
+#if ERROR_CHECKING
+ EmAssert (fStackPtr);
+ EmAssert (param.fStackOffset >= 0);
+#endif
+
+ EmMemPut8 (fStackPtr + param.fStackOffset, val);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU::SetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPU::SetParamVal (EmParam& param, uint16 val)
+{
+#if ERROR_CHECKING
+ EmAssert (fStackPtr);
+ EmAssert (param.fStackOffset >= 0);
+#endif
+
+ EmMemPut16 (fStackPtr + param.fStackOffset, val);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU::SetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPU::SetParamVal (EmParam& param, uint32 val)
+{
+#if ERROR_CHECKING
+ EmAssert (fStackPtr);
+ EmAssert (param.fStackOffset >= 0);
+#endif
+
+ EmMemPut32 (fStackPtr + param.fStackOffset, val);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU::SetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPU::SetParamVal (EmParam& param, uint64 /*val*/)
+{
+#if ERROR_CHECKING
+ EmAssert (fStackPtr);
+ EmAssert (param.fStackOffset >= 0);
+#endif
+
+ EmAssert (false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU::SetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPU::SetParamVal (EmParam& param, float /*val*/)
+{
+#if ERROR_CHECKING
+ EmAssert (fStackPtr);
+ EmAssert (param.fStackOffset >= 0);
+#endif
+
+ EmAssert (false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU::SetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPU::SetParamVal (EmParam& param, double /*val*/)
+{
+#if ERROR_CHECKING
+ EmAssert (fStackPtr);
+ EmAssert (param.fStackOffset >= 0);
+#endif
+
+ EmAssert (false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU::SetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPU::SetParamVal (EmParam& param, long double /*val*/)
+{
+#if ERROR_CHECKING
+ EmAssert (fStackPtr);
+ EmAssert (param.fStackOffset >= 0);
+#endif
+
+ EmAssert (false);
+}
+
+
+#pragma mark ------------------------------
+
+#include "EmCPU68K.h" // GetRegisters
+#include "EmException.h" // EmExceptionReset
+#include "EmPalmOS.h" // StackRange, RememberStackRange, ForgetStack
+#include "EmSession.h" // gSession
+#include "Profiling.h" // StDisableAllProfiling
+#include "UAE.h" // m68k_dreg, etc.
+
+const uint16 kOpcode_ROMCall = m68kTrapInstr + sysDispatchTrapNum;
+const uint16 kOpcode_ATrapReturn = m68kTrapInstr + kATrapReturnTrapNum;
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU68K::EmSubroutineCPU68K
+// ---------------------------------------------------------------------------
+
+EmSubroutineCPU68K::EmSubroutineCPU68K (void) :
+ fReturnedA0 (0),
+ fReturnedD0 (0)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU68K::~EmSubroutineCPU68K
+// ---------------------------------------------------------------------------
+
+EmSubroutineCPU68K::~EmSubroutineCPU68K (void)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU68K::FormatStack
+// ---------------------------------------------------------------------------
+
+long EmSubroutineCPU68K::FormatStack (EmParamList& params)
+{
+ long offset = 0;
+
+ EmParamList::iterator iter = params.begin ();
+ while (iter != params.end ())
+ {
+ iter->fStackOffset = offset;
+
+ if (iter->fByRef)
+ {
+ offset += 4;
+ }
+ else
+ {
+ switch (iter->fType)
+ {
+ case kEm_SI1:
+ case kEm_SI2:
+ case kEm_UI1:
+ case kEm_UI2:
+ offset += 2;
+ break;
+
+ case kEm_SI4:
+ case kEm_UI4:
+ offset += 4;
+ break;
+
+ default:
+ EmAssert (false);
+ }
+ }
+
+ ++iter;
+ }
+
+ return offset;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU68K::PrepareStack
+// ---------------------------------------------------------------------------
+
+Err EmSubroutineCPU68K::PrepareStack (Bool forCalling, Bool /*forStdArg*/, long stackSize)
+{
+ if (forCalling)
+ {
+ // Give ourselves our own private stack. We'll want this in case
+ // we're in the debugger and the stack pointer is hosed.
+
+ EmBankMapped::MapPhysicalMemory (this->GetStackBase (), kStackSize);
+
+ char* stackBase = this->GetStackBase ();
+ char* stackTop = &stackBase[kStackSize - 4];
+ emuptr eStackTop = EmBankMapped::GetEmulatedAddress (stackTop);
+
+ fStackPtr = eStackTop - stackSize;
+ }
+ else
+ {
+ fStackPtr = m68k_areg (regs, 7);
+
+ // Get these values, in case the EmSubroutine object is used
+ // when tailpatching a function and we need to examine the
+ // value being returned by the original version.
+
+ fReturnedA0 = m68k_areg (regs, 0);
+ fReturnedD0 = m68k_dreg (regs, 0);
+ }
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU68K::PrepareStack
+// ---------------------------------------------------------------------------
+
+Err EmSubroutineCPU68K::PrepareStack (emuptr stackAddr)
+{
+ fStackPtr = stackAddr;
+
+ // Get these values, in case the EmSubroutine object is used
+ // when tailpatching a function and we need to examine the
+ // value being returned by the original version.
+
+ fReturnedA0 = m68k_areg (regs, 0);
+ fReturnedD0 = m68k_dreg (regs, 0);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU68K::Call
+// ---------------------------------------------------------------------------
+
+Err EmSubroutineCPU68K::Call (uint16 trapWord)
+{
+ Err err = errNone;
+
+ // Save the current state.
+
+ regstruct oldRegs;
+ gCPU68K->GetRegisters (oldRegs);
+
+ // Make sure the CPU is not stopped. I suppose that we could force the CPU
+ // to no longer be stopped, but I'd rather that the Palm OS itself woke up
+ // first before we try making calls into it. Therefore, anything making
+ // an out-of-the-blue Palm OS call via this class (that is, a call outside
+ // of the context of a Palm OS function head- or tailpatch) should first
+ // bring the CPU to a halt by calling EmSession::SuspendThread (kStopOnSysCall)
+ // first (usually by using EmSessionStopper (kStopOnSysCall)).
+
+ EmAssert (oldRegs.stopped == 0);
+
+ // Remember this as a stack so that our stack sniffer won't complain.
+ // Do this *before* changing the stack pointer, or else CheckSP won't
+ // be able to determine the stack we've switched into.
+
+ char* stackBase = this->GetStackBase ();
+ StackRange range ( EmBankMapped::GetEmulatedAddress (&stackBase[0]),
+ EmBankMapped::GetEmulatedAddress (&stackBase[kStackSize - 4]));
+ EmPalmOS::RememberStackRange (range);
+
+ // Point us to the business end of our private stack.
+ //
+ // Make sure we do this using SetRegisters (instead of just slamming
+ // regs[SP]) so that we can record the switch to the new stack (for
+ // our stack access monitoring code).
+
+ regstruct newRegs = oldRegs;
+
+ m68k_areg (newRegs, 7) = fStackPtr;
+ gCPU68K->SetRegisters (newRegs);
+
+ // Call the Palm OS function.
+
+ err = this->DoCall (trapWord);
+
+ // Save the result.
+
+ fReturnedA0 = m68k_areg (regs, 0);
+ fReturnedD0 = m68k_dreg (regs, 0);
+
+ // Restore the original state.
+
+ EmPalmOS::ForgetStack (EmBankMapped::GetEmulatedAddress (this->GetStackBase ()));
+
+ EmAssert (gCPU68K);
+ gCPU68K->SetRegisters (oldRegs);
+
+ // Unmap the stack that got mapped in PrepareStack.
+
+ EmBankMapped::UnmapPhysicalMemory (this->GetStackBase ());
+
+ // Check to see if anything interesting was registered while we
+ // were making the Palm OS subroutine call. The "check after end
+ // of cycle" bit may have gotten cleared when restoring the old
+ // registers, so set it on the off chance that it was. Doing this
+ // is harmless if there really aren't any scheduled tasks.
+
+ EmAssert (gSession);
+ gCPU68K->CheckAfterCycle ();
+
+ return err;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU68K::CallSelector
+// ---------------------------------------------------------------------------
+
+Err EmSubroutineCPU68K::CallSelector (uint16 trapWord, uint16 selector)
+{
+ Err err = errNone;
+
+ // Save the current state.
+
+ regstruct oldRegs;
+ gCPU68K->GetRegisters (oldRegs);
+
+ // Set up the selector.
+
+ regstruct newRegs = oldRegs;
+
+ m68k_dreg (newRegs, 2) = selector;
+ gCPU68K->SetRegisters (newRegs);
+
+ // Call the function.
+
+ err = this->Call (trapWord);
+
+ // Restore the original state.
+
+ EmAssert (gCPU68K);
+ gCPU68K->SetRegisters (oldRegs);
+
+ return err;
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU68K::GetReturnRegInteger
+// ---------------------------------------------------------------------------
+
+uint32 EmSubroutineCPU68K::GetReturnRegInteger (void)
+{
+ return fReturnedD0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU68K::GetReturnRegPointer
+// ---------------------------------------------------------------------------
+
+emuptr EmSubroutineCPU68K::GetReturnRegPointer (void)
+{
+ return fReturnedA0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU68K::SetReturnRegInteger
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPU68K::SetReturnRegInteger (uint32 val)
+{
+ fReturnedD0 = val;
+ m68k_dreg (regs, 0) = val;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU68K::SetReturnRegPointer
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPU68K::SetReturnRegPointer (void* val)
+{
+ fReturnedA0 = (uae_u32) val;
+ m68k_areg (regs, 0) = (uae_u32) val;
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU68K::DoCall
+// ---------------------------------------------------------------------------
+
+Err EmSubroutineCPU68K::DoCall (uint16 trapWord)
+{
+ Err err = errNone;
+
+ // Stop all profiling activities. Stop cycle counting and stop the
+ // recording of function entries and exits. We want our calls to
+ // ROM functions to be as transparent as possible.
+
+ StDisableAllProfiling stopper;
+
+
+ // Assert that the function we're trying to call is implemented.
+ //
+ // Oops...bad test...this doesn't work when we're calling a library.
+ // Instead, since we now invoke ROM functions by creating a TRAP $F
+ // sequence, we'll let our TRAP $F handler deal with validating the
+ // function call (it does that anyway).
+
+// EmAssert (LowMem::GetTrapAddress (trapWord));
+
+ // We call the ROM function by dummying up a sequence of 68xxx instructions
+ // for it. The sequence of instructions is:
+ //
+ // TRAP $F
+ // DC.W <dispatch number>
+ // TRAP $C
+ //
+ // The first two words invoke the function (calling any head- or tailpatches
+ // along the way). The third word allows the emulator to regain control
+ // after the function has returned.
+ //
+ // Note: this gets a little ugly on little-endian machines. The following
+ // instructions are stored on the emulator's stack. This memory is mapped
+ // into the emulated address space in such a fashion that no byteswapping of
+ // word or long values occurs. Thus, we have to put the data into Big Endian
+ // format when putting it into the array.
+ //
+ // However, opcodes are a special case. They are optimized in the emulator
+ // for fast access. Opcodes are *always* fetched a word at a time in host-
+ // endian order. Thus, the opcodes below have to be stored in host-endian
+ // order. That's why there's no call to Canonical to put them into Big
+ // Endian order.
+
+ uint16 code[] = { kOpcode_ROMCall, trapWord, kOpcode_ATrapReturn };
+
+ // Oh, OK, we do have to byteswap the trapWord. Opcodes are fetched with
+ // EmMemDoGet16, which always gets the value in host byte order. The
+ // trapWord is fetched with EmMemGet16, which gets values according to the
+ // rules of the memory bank. For the dummy bank, the defined byte order
+ // is Big Endian.
+
+ Canonical (code[1]);
+
+ // Map in the code stub so that the emulation code can access it.
+
+ StMemoryMapper mapper (code, sizeof (code));
+
+ // Prepare to handle the TRAP 12 exception.
+
+ EmAssert (gCPU68K);
+ gCPU68K->InstallHookException (kException_ATrapReturn,
+ (Hook68KException) HandleTrap12);
+
+ // Point the PC to our code.
+
+ emuptr newPC = EmBankMapped::GetEmulatedAddress (code);
+ m68k_setpc (newPC);
+
+ // Execute until the next break.
+
+ try
+ {
+ EmAssert (gSession);
+ gSession->ExecuteSubroutine ();
+ }
+ catch (EmExceptionReset& e)
+ {
+ e.SetTrapWord (trapWord);
+
+ // Remove the TRAP 12 exception handler.
+
+ EmAssert (gCPU68K);
+ gCPU68K->RemoveHookException (kException_ATrapReturn,
+ (Hook68KException) HandleTrap12);
+
+ throw;
+ }
+
+ // Remove the TRAP 12 exception handler.
+
+ EmAssert (gCPU68K);
+ gCPU68K->RemoveHookException (kException_ATrapReturn,
+ (Hook68KException) HandleTrap12);
+
+ return err;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU68K::HandleTrap12
+// ---------------------------------------------------------------------------
+// This function really takes an ExceptionNumber as a parameter. However,
+// we don't use/need it, and omitting it helps our forward declarations.
+
+Bool EmSubroutineCPU68K::HandleTrap12 (void)
+{
+ EmAssert (gSession);
+ gSession->ScheduleSuspendSubroutineReturn ();
+
+ return true;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU68K::GetStackBase
+// ---------------------------------------------------------------------------
+
+char* EmSubroutineCPU68K::GetStackBase ()
+{
+ // Ensure that the stack is aligned to a longword address.
+
+ uint32 stackBase = (uint32) fStack;
+
+ stackBase += 3;
+ stackBase &= ~3;
+
+ return (char*) stackBase;
+}
+
+
+#pragma mark ------------------------------
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::EmSubroutineCPUARM
+// ---------------------------------------------------------------------------
+
+EmSubroutineCPUARM::EmSubroutineCPUARM (void)
+{
+ EmAssert (false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::~EmSubroutineCPUARM
+// ---------------------------------------------------------------------------
+
+EmSubroutineCPUARM::~EmSubroutineCPUARM (void)
+{
+ EmAssert (false);
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::FormatStack
+// ---------------------------------------------------------------------------
+
+long EmSubroutineCPUARM::FormatStack (EmParamList& /*params*/)
+{
+ EmAssert (false);
+ return 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::PrepareStack
+// ---------------------------------------------------------------------------
+
+Err EmSubroutineCPUARM::PrepareStack (Bool /*forCalling*/, Bool /*forStdArg*/, long /*stackSize*/)
+{
+ EmAssert (false);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::PrepareStack
+// ---------------------------------------------------------------------------
+
+Err EmSubroutineCPUARM::PrepareStack (emuptr /*stackAddr*/)
+{
+ EmAssert (false);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::Call
+// ---------------------------------------------------------------------------
+
+Err EmSubroutineCPUARM::Call (uint16 /*trapWord*/)
+{
+ EmAssert (false);
+
+ return errNone;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPU68K::CallSelector
+// ---------------------------------------------------------------------------
+
+Err EmSubroutineCPUARM::CallSelector (uint16 /*trapWord*/, uint16 /*selector*/)
+{
+ EmAssert (false);
+
+ return errNone;
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::GetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPUARM::GetParamVal (EmParam& /*param*/, int8& /*result*/)
+{
+ EmAssert (false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::GetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPUARM::GetParamVal (EmParam& /*param*/, int16& /*result*/)
+{
+ EmAssert (false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::GetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPUARM::GetParamVal (EmParam& /*param*/, int32& /*result*/)
+{
+ EmAssert (false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::GetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPUARM::GetParamVal (EmParam& /*param*/, int64& /*result*/)
+{
+ EmAssert (false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::GetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPUARM::GetParamVal (EmParam& /*param*/, uint8& /*result*/)
+{
+ EmAssert (false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::GetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPUARM::GetParamVal (EmParam& /*param*/, uint16& /*result*/)
+{
+ EmAssert (false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::GetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPUARM::GetParamVal (EmParam& /*param*/, uint32& /*result*/)
+{
+ EmAssert (false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::GetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPUARM::GetParamVal (EmParam& /*param*/, uint64& /*result*/)
+{
+ EmAssert (false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::GetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPUARM::GetParamVal (EmParam& /*param*/, float& /*result*/)
+{
+ EmAssert (false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::GetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPUARM::GetParamVal (EmParam& /*param*/, double& /*result*/)
+{
+ EmAssert (false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::GetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPUARM::GetParamVal (EmParam& /*param*/, long double& /*result*/)
+{
+ EmAssert (false);
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::SetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPUARM::SetParamVal (EmParam& /*param*/, int8 /*val*/)
+{
+ EmAssert (false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::SetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPUARM::SetParamVal (EmParam& /*param*/, int16 /*val*/)
+{
+ EmAssert (false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::SetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPUARM::SetParamVal (EmParam& /*param*/, int32 /*val*/)
+{
+ EmAssert (false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::SetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPUARM::SetParamVal (EmParam& /*param*/, int64 /*val*/)
+{
+ EmAssert (false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::SetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPUARM::SetParamVal (EmParam& /*param*/, uint8 /*val*/)
+{
+ EmAssert (false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::SetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPUARM::SetParamVal (EmParam& /*param*/, uint16 /*val*/)
+{
+ EmAssert (false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::SetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPUARM::SetParamVal (EmParam& /*param*/, uint32 /*val*/)
+{
+ EmAssert (false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::SetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPUARM::SetParamVal (EmParam& /*param*/, uint64 /*val*/)
+{
+ EmAssert (false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::SetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPUARM::SetParamVal (EmParam& /*param*/, float /*val*/)
+{
+ EmAssert (false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::SetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPUARM::SetParamVal (EmParam& /*param*/, double /*val*/)
+{
+ EmAssert (false);
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::SetParamVal
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPUARM::SetParamVal (EmParam& /*param*/, long double /*val*/)
+{
+ EmAssert (false);
+}
+
+
+#pragma mark -
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::GetReturnRegInteger
+// ---------------------------------------------------------------------------
+
+uint32 EmSubroutineCPUARM::GetReturnRegInteger (void)
+{
+ return 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::GetReturnRegPointer
+// ---------------------------------------------------------------------------
+
+emuptr EmSubroutineCPUARM::GetReturnRegPointer (void)
+{
+ return 0;
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::SetReturnRegInteger
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPUARM::SetReturnRegInteger (uint32)
+{
+}
+
+
+// ---------------------------------------------------------------------------
+// ¥ EmSubroutineCPUARM::SetReturnRegPointer
+// ---------------------------------------------------------------------------
+
+void EmSubroutineCPUARM::SetReturnRegPointer (void*)
+{
+}