/*
	File:		MixedMode.h

	Contains:	Headers and interfaces for the Mixed Mode mechanism

	Written by:	Bruce Jones

	Copyright:	© 1992 by Apple Computer, Inc., all rights reserved.

	Change History (most recent first):

		 <1>	 12/7/92	DRF		first checked in
		<18>	11/13/92	DRF		Fix a bug in BuildRoutineDescriptor macro. We were building
									kLoadAndExecute RDs and not kExecute types! Of course,
									CodeFragMgrDispatch and MixedModeDispatch were the only two
									users of this macro, so nobody knew it was broken.
		<17>	 11/8/92	BKJ		Rolled back
	   <13+>	10/26/92	SP		Adding definition for m68KRegisterSizePhase
		<13>	10/22/92	DRF		Added inline 68K trap glue for NewRoutineDescriptor and
									DisposeRoutineDescriptor
		<12>	10/19/92	DRF		Changed declaration of NewRoutineDescriptor and
									DisposeRoutineDescriptor to match SeanŐs clearer syntax.
		<11>	10/13/92	SP		Changing all m68k's to m68K
		<10>	10/08/92	SP		Adding phase and offset enum for the parameters.
		 <9>	 10/4/92	BKJ		Current version is 1
		 <8>	 10/1/92	jrg		Made smaller enum blocks and changed typedef for InterfaceTool
		 <7>	 9/29/92	BKJ		Fix bug in BuildRoutineDescriptor macro.
		 <6>	 9/28/92	stb		add special cases as used by the rest of the public interfaces
		 <5>	 9/18/92	LC		changing kGoMixedMode to 0xFEED0000
		 <4>	 9/10/92	EPT		Added (long) typecasts to enum constants. Changed constants to
									conform to new procInfo definition.
		 <3>	  9/9/92	LC		Added Macro "BuildRoutineDescriptor, which allows static
									declaration of a routine descriptor at compile time.  In order
									to have this macro, many private declarations had to be brought
									over from MixedModeApplePrivate.h, including kGoMixedMode, and
									kMixedModeMagicCookie.
		 <2>	  9/2/92	BKJ		Get rid of numParams parameter to BuildProcInfo &
									CallRoutineDescriptor calls.
		 <1>	  9/1/92	BKJ		first checked in
		 		 8/28/92	BKJ		change to reflect latest ERS
				  6/5/92	BKJ		Continued Development
				 4/17/92	BKJ		Created

*/



#ifndef __MIXEDMODE__
#define __MIXEDMODE__

#ifndef __TYPES__
#include <Types.h>
#endif

#define	kGoMixedMode 0xFEED0000

#define	kMixedModeMagicCookie 0x4B4F4348

#define PARAMETER_SIZE(size) \
	(((size) == 4) ? 3 : (((size) == 2) ? 1 : (((size) == 1) ? 2 : 0)))
	
enum {
	kResultPhase = 4,			/* bit offset for result field */
	kParameterPhase = 6,
	kParameterOffset = 2,
	m68KRegisterOffset = 6,
	m68KRegisterOut = 0x20,
	m68KRegisterIn = 0x10,
	m68KRegisterParameterPhase = 2,
	m68KRegisterA0 = 0,
	m68KRegisterA1 = 1,
	m68KRegisterD0 = 2,
	m68KRegisterD1 = 3
};


enum {
	kPStackBased = 0, 
	kCStackBased = 1, 
	kRegisterBased = 2, 
	kD0DispStackBased = 8,
	kD1DispStackBased = 12,
	kStackDispStackBased = 14,
	kStackDispRegisterBased = 10,
	kSpecialCaseProcInfoType = 5
	};
typedef short CallingConventionType;


enum {
	// the Mixed Mode error codes
	mmInternalError = -2526,
	kMMErr2 = -2527,
	kMMErr3 = -2528,
	kMMErr4 = -2529,
	kMMErr5 = -2530,
	kMMErr6 = -2531,
	kMMErr7 = -2532,
	kMMErr8 = -2533,
	kMMErr9 = -2534,
	kMMErr10 = -2535
};
typedef short MMErrType;

enum {
	kRegisterD0 = 0,
	kRegisterD1,
	kRegisterD2,
	kRegisterD3,
	kRegisterD4,
	kRegisterD5,
	kRegisterD6,
	kRegisterD7,
	kRegisterA0,
	kRegisterA1,
	kRegisterA2,
	kRegisterA3,
	kRegisterA4,
	kRegisterA5,
	kRegisterA6,
	kRegisterA7
};
typedef short RegisterSelectorType;

enum {kLoadAndExecute = 0, kExecute, kReturnFrom};
typedef short SelectorType;

enum {kCodeTypeUnknown = -1, kCodeTypeCurrentWorld, kCodeType68K, kCodeTypePower};
typedef long CodeType;

typedef long ProcInfoType;

typedef struct private_RoutineDescriptor* RoutineDescriptor;


/* ProcInfo selectors for each of the parameters */

/* Pascal and C Stack based parameter constants */
/* Stack-based dispatched uses these, but only P2 and up */
enum {
	m68KStackP1Byte = (long)0x00000080,
	m68KStackP1Word = (long)0x00000040,
	m68KStackP1Long = (long)0x000000C0,
	m68KStackP2Byte = (long)0x00000200,
	m68KStackP2Word = (long)0x00000100,
	m68KStackP2Long = (long)0x00000300,
	m68KStackP3Byte = (long)0x00000800,
	m68KStackP3Word = (long)0x00000400,
	m68KStackP3Long = (long)0x00000C00,
	m68KStackP4Byte = (long)0x00002000,
	m68KStackP4Word = (long)0x00001000,
	m68KStackP4Long = (long)0x00003000,
	m68KStackP5Byte = (long)0x00008000,
	m68KStackP5Word = (long)0x00004000,
	m68KStackP5Long = (long)0x0000C000,
	m68KStackP6Byte = (long)0x00020000,
	m68KStackP6Word = (long)0x00010000,
	m68KStackP6Long = (long)0x00030000,
	m68KStackP7Byte = (long)0x00080000,
	m68KStackP7Word = (long)0x00040000,
	m68KStackP7Long = (long)0x000C0000,
	m68KStackP8Byte = (long)0x00200000,
	m68KStackP8Word = (long)0x00100000,
	m68KStackP8Long = (long)0x00300000,
	m68KStackP9Byte = (long)0x00800000,
	m68KStackP9Word = (long)0x00400000,
	m68KStackP9Long = (long)0x00C00000,
	m68KStackP10Byte = (long)0x02000000,
	m68KStackP10Word = (long)0x01000000,
	m68KStackP10Long = (long)0x03000000,
	m68KStackP11Byte = (long)0x08000000,
	m68KStackP11Word = (long)0x04000000,
	m68KStackP11Long = (long)0x0C000000,
	m68KStackP12Byte = (long)0x20000000,
	m68KStackP12Word = (long)0x10000000,
	m68KStackP12Long = (long)0x30000000,
	m68KStackP13Byte = (long)0x80000000,
	m68KStackP13Word = (long)0x40000000,
	m68KStackP13Long = (long)0xC0000000
};

enum {
/* Register based parameter constants */
/* Also used for register-based dispatching */
	m68KRegisterP1In 	= (long)0x00000400,
	m68KRegisterP1Out 	= (long)0x00000800,
	m68KRegisterP1InOut = (long)0x00000C00,
	m68KRegisterP2In 	= (long)0x00010000,
	m68KRegisterP2Out 	= (long)0x00020000,
	m68KRegisterP2InOut = (long)0x00030000,
	m68KRegisterP3In 	= (long)0x00400000,
	m68KRegisterP3Out 	= (long)0x00800000,
	m68KRegisterP3InOut = (long)0x00C00000,
	m68KRegisterP4In 	= (long)0x10000000,
	m68KRegisterP4Out 	= (long)0x20000000,
	m68KRegisterP4InOut = (long)0x30000000
};

enum {
	m68KRegisterP1Byte = (long)0x00000200,
	m68KRegisterP1Word = (long)0x00000100,
	m68KRegisterP1Long = (long)0x00000300,
	m68KRegisterP2Byte = (long)0x00008000,
	m68KRegisterP2Word = (long)0x00004000,
	m68KRegisterP2Long = (long)0x0000C000,
	m68KRegisterP3Byte = (long)0x00200000,
	m68KRegisterP3Word = (long)0x00100000,
	m68KRegisterP3Long = (long)0x00300000,
	m68KRegisterP4Byte = (long)0x08000000,
	m68KRegisterP4Word = (long)0x04000000,
	m68KRegisterP4Long = (long)0x0C000000
};

enum {
	m68KRegisterP1A0 = (long)0x00000000,
	m68KRegisterP1A1 = (long)0x00000040,
	m68KRegisterP1D0 = (long)0x00000080,
	m68KRegisterP1D1 = (long)0x000000C0,
	m68KRegisterP2A0 = (long)0x00000000,
	m68KRegisterP2A1 = (long)0x00001000,
	m68KRegisterP2D0 = (long)0x00002000,
	m68KRegisterP2D1 = (long)0x00003000,
	m68KRegisterP3A0 = (long)0x00000000,
	m68KRegisterP3A1 = (long)0x00040000,
	m68KRegisterP3D0 = (long)0x00080000,
	m68KRegisterP3D1 = (long)0x000C0000,
	m68KRegisterP4A0 = (long)0x00000000,
	m68KRegisterP4A1 = (long)0x01000000,
	m68KRegisterP4D0 = (long)0x02000000,
	m68KRegisterP4D1 = (long)0x03000000
};

enum {

/* Dispatched constants for kStackDispRegisterBased type (selector on stack) */
	m68KStackSelectorByte = (long)0x00000020,
	m68KStackSelectorWord = (long)0x00000010,
	m68KStackSelectorLong = (long)0x00000030,

/* Dispatched constants for all dispatched stack-based types */
	m68KRegSelectorByte = (long)0x00000080,
	m68KRegSelectorWord = (long)0x00000040,
	m68KRegSelectorLong = (long)0x000000C0,

/* Selectors for the ProcInfo result size fields */
	kNoReturnValue = (long)0x00000000,
	k68KByteReturned = (long)0x00000020,
	k68KWordReturned = (long)0x00000010,		/* 68K word - two bytes */
	k68KLongReturned = (long)0x00000030			/* 68K long - four bytes */
};

/* all of the special cases enumerated */
enum {
	kSpecialCaseHighHook = 0x0100,
	kSpecialCaseCaretHook = 0x0100,
	kSpecialCaseEOLHook = 0x0200,
	kSpecialCaseWidthHook = 0x0300,
	kSpecialCaseNWidthHook = 0x0400,
	kSpecialCaseTextWidthHook = 0x0500,
	kSpecialCaseDrawHook = 0x0600,
	kSpecialCaseHitTestHook = 0x0700,
	kSpecialCaseTEFindWord = 0x0800,
	kSpecialCaseADBRoutines = 0x0900,
	kSpecialCaseProtocolHandler = 0x0A00,
	kSpecialCaseSocketListener = 0x0B00
};
/*
	Explanation of special cases:
	*****************************
	1 = C calling conventions, Rect on stack, pointer in A3, no return value
	2 = Register-based; inputs in D0, A3, A4; output is Z flag of 
		status register (see VI-15-26)
	3 = Register-based; inputs in D0, D1, A0, A3, A4; output in D1 (see VI-15-27)
	4 = Register-based; inputs in D0, D1, D2, A0, A2, A3, A4; output in D1 
		(see VI-15-27)
	5 = Register-based; inputs in D0, D1, A0, A3, A4; output in D1 (see VI-15-28)
	6 = Register-based; inputs in D0, D1, A0, A3, A4; no output (see VI-15-28)
	7 = Register-based; inputs in D0, D1, D21, A0, A3, A4; outputs in
		D0, D1, D2 (See VI-15-29)
	8 = Register-based; inputs in D0, D2, A3, A4; outputs in D0, D1 (see VI-15-30)
	9 = Register-based; inputs in A0, A1, A2, D0; no outputs (see V-371)
	A = Register-based; inputs in A0, A1, A2, A3, A4, D1.w; output in Z (see II-326)
	B = Register-based; inputs in A0, A1, A2, A3, A4, D0.b, D1.w; output in Z 
		(see II-329)

*/

RoutineDescriptor
NewRoutineDescriptor(ProcPtr theProc, 
						ProcInfoType procInfo, 
						CodeType typeOfCode)
	= {0x303C,0x0000,0xAA59};	/* <13> */

void
DisposeRoutineDescriptor (RoutineDescriptor theDescriptor)
	= {0x303C,0x0001,0xAA59};	/* <13> */

long
CallRoutineDescriptor (RoutineDescriptor theRoutine,
						ProcInfoType procInfo,
						...);
CodeType
GetCodeType (RoutineDescriptor theDescriptor);

OSErr
SetCodeType (RoutineDescriptor theDescriptor,
			CodeType newCodeType);

ProcInfoType
BuildProcInfo(CallingConventionType callingConvention, 
				short resultSize, 
				...);

ProcInfoType
GetProcInfo (RoutineDescriptor theDescriptor);

OSErr
SetProcInfo (RoutineDescriptor theDescriptor, 
			ProcInfoType newProcInfo);

ProcPtr
GetTheProc (RoutineDescriptor theDescriptor);

OSErr
SetTheProc (RoutineDescriptor theDescriptor, 
			ProcPtr newProc);

long
GetEmulatorRegister (RegisterSelectorType registerSelector);

long
SetEmulatorRegister (RegisterSelectorType registerSelector,
					long newValue);


enum {kRoutineDescriptorVersion = 1};

struct private_RoutineDescriptor {
	long				goMixedMode;			// unused 68K instruction						 0
	long				magicCookie;			// unique identifier							 4
	SelectorType		selector;				// mixed mode selector							 8
	short				version;				// 0 for now, increment as needed				10
	ProcInfoType		procInfo;				// calling conventions							12
	ProcPtr				customParamProc;		// Procedure to convert params					16
	CodeType			executionMode;			// to different types of code					20
	ProcPtr				procDescriptor;			// Descriptor of routine we are going to call	24
	long				unused;					// must be 0									28
};

typedef struct private_RoutineDescriptor private_RoutineDescriptor;
typedef private_RoutineDescriptor *private_RoutineDescriptorPtr, **private_RoutineDescriptorHandle;

/* a macro which creates a static instance of a routine descriptor */
#define BuildRoutineDescriptor(procInfo, procedure) 				\
	{																\
		kGoMixedMode,				/* GoMixedMode instruction */	\
		kMixedModeMagicCookie,		/* Mixed Mode magic cookie */	\
		kExecute,					/* selector <18> */				\
		kRoutineDescriptorVersion,	/* version */					\
		(procInfo),					/* ProcInfo */					\
		0,							/* custom param proc */			\
		kCodeTypePower,				/* execution mode */			\
		(void *) (procedure),		/* theProc */					\
		0,							/* list terminator */			\
	}


#endif