/******************************************************************************
 *
 * Copyright (c) 2003 PalmSource, Inc. All rights reserved.
 *
 * File: AdnDebugMgr.h
 *
 * Release: DebugNub for Palm OS 5.x Native ARM debugging
 *
 * Description:
 *    API used to communicate with the Palm OS 5.x DebugNub.
 *
 *****************************************************************************/

#ifndef __ADNDEBUGMGR_H__
#define __ADNDEBUGMGR_H__

// Uses unsigned shorts and longs to avoid needing PalmTypes.h for UInt32 typedef


/***********************************************************************
 *	Palm OS SWI-related Definitions (largely from future Palm OS PUD.h)
 ***********************************************************************/

// Generic Semihosting SWI op-codes			(non-exhaustive list)
#define kAdnSemihostArmWrite0				0x0004	// Write a C-string to stdout
#define kAdnSemihostArmReportException		0x0018	// Angel SWI reason report exception

// Palm-specific Semihosting SWI op-codes	(non-exhaustive list)
#define kAdnSemihostPUDConnect				0x0101
#define kAdnSemihostPUDProcessCreate		0x0110
#define kAdnSemihostPUDProcessDestroy		0x0111
#define kAdnSemihostPUDThreadCreate			0x0120
#define kAdnSemihostPUDThreadDestroy		0x0121
#define kAdnSemihostPUDModulePostLoad		0x0130
#define kAdnSemihostPUDModulePostUnload		0x0131
#define kAdnSemihostPUDDebugBreak			0x0132
#define kAdnSemihostPUDFaultNotification	0x0133
#define kAdnSemihostPUDModuleTableUpdate	0x0134
#define kAdnSemihostPUDDownloadEvent		0x0140
#define kAdnSemihostPUDProfilerEvent		0x0141

// Palm Adn-specific Semihosting SWI op-codes
#define kAdnSemihostNativeRegister			0x0150
#define kAdnSemihostNativeUnregister		0x0151
#define kAdnSemihostDebugEnableSet			0x0152
#define kAdnSemihostDebugEnableGet			0x0153
#define kAdnSemihostLicenseeSpecific		0x0154
#define kAdnSemihostDebugEnableGetSupported 0x0155


/***********************************************************************
 *	Features to be enabled and disabled
 ***********************************************************************/

#define kAdnEnableMasterSwitch				0x00000001	// [off] Master switch.  Nothing works with this off, except
														// AdnDebugEnableSet/Get() which is used to turn it on.
														//
														// With the master switch turned ON, the nub will:
														//  - Catch (by entering the debugger) fatal (ARM) exceptions
														//    (illegal memory access, undefined instructions).
														//  - Enter the debugger if AdnDebugBreak() is called.  Even
														//    if a debugger is not initially present, one can later
														//    be connected for "after the crash" debugging.
														// [Some nub implementations may also:]
														//  - Catch ErrFatalDisplay() calls.  Note: currently, won't
														//    catch 68K fatal alerts if you've dropped in the 68K
														//    debugger at least once since the last reset.
														//
														// In addition, if the nub has already communicated with a
														// debugger, then additional commands which otherwise required
														// kAdnEnableFullDebugging will also be allowed.

#define kAdnEnableDebugIndicator			0x00000002	// [on]  Enable visual indicator that shows when the debugger
														// nub is performing (or waiting for) serial communications.

#define kAdnEnableFullDebugging				0x00000004	// [off] Allow FULL interactive debugging.
														//  - This MUST be turned ON in order for application calls to
														//    AdnDebugNativeRegister() to be processed correctly
														//    (i.e. sent to the debugger to register loaded PACE Native
														//    Object code for source level debugging).
														//  - If this option is off, then other native debugging calls
														//    (ModulePostLoad, ModulePostUnload, etc.) are also disabled.

#define kAdnEnableShowSafeFatalAlerts		0x00000008	// [off] If on, don't catch calls to ErrFatalDisplay()
														// iff the Reset/Debug/Continue options are displayed
														// and we're pretty sure they'll work. [May not be supported.]

 
/***********************************************************************
 *	Structure Definitions (largely from future Palm OS PUD.h)
 ***********************************************************************/
typedef struct DbgPostLoadParamsType {
	unsigned long		processID;
	unsigned long		moduleID;
	void				*codeAddr;
	void				*dataAddr;
	unsigned long		type;
	unsigned long		creator;
	unsigned long		rsrcType;
	unsigned short		rsrcID;
	unsigned short		reserved;
} DbgPostLoadParamsType;

typedef struct DbgPostUnloadParamsType {
	unsigned long		processID;
	unsigned long		moduleID;
} DbgPostUnloadParamsType;


/***********************************************************************
 *	Semihosting SWI number	(from future Palm OS ARM.h)
 ***********************************************************************/
#define SEMI_SWI_ARM 0x123456L
#define SEMI_SWI_THUMB 0xAB

#ifdef __thumb
	#define SEMI_SWI_NUM SEMI_SWI_THUMB
#else
	#define SEMI_SWI_NUM SEMI_SWI_ARM
#endif


/***********************************************************************
 *	Palm OS SWI-related Prototypes
 ***********************************************************************/

#if !defined(__arm)		// Included in non-ARM build; silently ignore everything

	#define AdnGetNativeCodeBaseAddr() 0
	#define _SemihostOp0(op)			
	#define _SemihostOp0r(op)			
	#define _SemihostOp1(op,p1)			
	#define _SemihostOp3r(op,p1,p2,p3)	
	#define _SemihostWrite0(op, s)		
	#define _SemihostPostLoad(op, p)	
	#define _SemihostPostUnload(op, p)	


#elif defined(__MWERKS__)			// CodeWarrior for Palm OS R9.2 (beta 2 or greater)

	// This function must be defined for the current toolset, to retrieve and/or
	// calculate the base address of our code resource.  This function is called
	// called by AdnDebugNativeRegister() which tells the desktop debugger where
	// exactly in memory the code is located (to enable source level debugging).
	// It would be nice to just reference the startup function, but unfortunately
	// that resolves to zero (it's not automatically relocated at runtime).
	// It may be in a future (release) version of CW 9.2 but it's not in the preview...
	#if 0
		#define AdnGetNativeCodeBaseAddr() __ARMlet_Startup__
	#else
		#pragma thumb off
		static void * AdnGetNativeCodeBaseAddr(void);
		static asm void * AdnGetNativeCodeBaseAddr(void)
		{
			sub		r0, pc, #8						// get real address of this function
			lda		r1, AdnGetNativeCodeBaseAddr	// get zero-based offset to this function
			sub		r0, r0, r1						// subtract to get real base of code
			bx		lr								// and return
		}
		#pragma thumb reset
	#endif

	// These declarations work, but the functions don't get
	// inlined as requested (and thus we need the "bx lr").
	// We could remove the "inline" directive but then we need function prototypes.
	inline __asm void _SemihostOp0(unsigned op)
		{ swi SEMI_SWI_NUM; bx lr; }

	inline __asm unsigned _SemihostOp0r(unsigned op)
		{ swi SEMI_SWI_NUM; bx lr; }

	inline __asm void _SemihostOp1(unsigned op, unsigned param1)
		{ swi SEMI_SWI_NUM; bx lr; }

	inline __asm unsigned _SemihostOp3r(unsigned op, unsigned param1, unsigned param2, unsigned param3)
		{ swi SEMI_SWI_NUM; bx lr; }

	inline __asm void _SemihostWrite0(unsigned op, const char *string)
		{ swi SEMI_SWI_NUM; bx lr; }

	inline __asm void _SemihostPostLoad(unsigned op, const DbgPostLoadParamsType *)
		{ swi SEMI_SWI_NUM; bx lr; }

	inline __asm void _SemihostPostUnload(unsigned op, const DbgPostUnloadParamsType *)
		{ swi SEMI_SWI_NUM; bx lr; }

	// You might think that something like the following would work, but it doesn't.
	// The SWI instruction does get inlined, but the required function parameters
	// do not get properly moved into registers r0, r1, etc.
	//		inline /*asm*/ void _SemihostOp0(unsigned op)
	//			{ asm { swi SEMI_SWI_NUM } }
	

#elif defined(__ARMCC_VERSION)	// ARM ADS

	// Note: In order to debug ADS-generated PACE Native Objects, we must have
	// a valid definition for the AdnGetNativeCodeBaseAddr() [see above].
	
	// Since we don't currently support building in ADS, we force a build error
	// if anyone attempts to call this (as yet undefined) function (which is
	// called by AdnDebugNativeRegister(), below).  If you need to use this in
	// ADS, either fix this, or if you know your base address, you can instead
	// call the AdnDebugNativeRegisterAddr() variation.
	#define AdnGetNativeCodeBaseAddr() AdnThisShouldCauseABuildError()

	__swi(SEMI_SWI_NUM) void	_SemihostOp0		(unsigned op);
	__swi(SEMI_SWI_NUM) unsigned _SemihostOp0r		(unsigned op);
	__swi(SEMI_SWI_NUM) void	_SemihostOp1		(unsigned op, unsigned param1);
	__swi(SEMI_SWI_NUM) unsigned _SemihostOp3r		(unsigned op, unsigned param1, unsigned param2, unsigned param3);
	__swi(SEMI_SWI_NUM) void	_SemihostWrite0		(unsigned op, const char *string);
	__swi(SEMI_SWI_NUM) void	_SemihostPostLoad	(unsigned op, const DbgPostLoadParamsType *);
	__swi(SEMI_SWI_NUM) void	_SemihostPostUnload	(unsigned op, const DbgPostUnloadParamsType *);


#elif defined(__GNUC__)  // gcc
 
        // preprocessor nastiness
        #define WRAP(x) #x
        #define PUT_QUOTES_AROUND(x) WRAP(x)
        #define SWI_NUM_WITH_QUOTES_AROUND_IT PUT_QUOTES_AROUND(SEMI_SWI_NUM)
 
        inline static void _SemihostOp0(unsigned op)
                { asm("swi " SWI_NUM_WITH_QUOTES_AROUND_IT); }
 
        inline static unsigned _SemihostOp0r(unsigned op)
                { asm("swi " SWI_NUM_WITH_QUOTES_AROUND_IT); }
 
        inline static void _SemihostOp1(unsigned op, unsigned param1)
                { asm("swi " SWI_NUM_WITH_QUOTES_AROUND_IT); }
 
        inline static unsigned _SemihostOp3r(unsigned op, unsigned param1, unsigned param2, unsigned param3)
                { asm("swi " SWI_NUM_WITH_QUOTES_AROUND_IT); }
 
        inline static void _SemihostWrite0(unsigned op, const char *string)
                { asm("swi " SWI_NUM_WITH_QUOTES_AROUND_IT); }
 
        inline static void _SemihostPostLoad(unsigned op, const DbgPostLoadParamsType *params)
                { asm("swi " SWI_NUM_WITH_QUOTES_AROUND_IT); }
 
        inline static void _SemihostPostUnload(unsigned op, const DbgPostUnloadParamsType *params)
                { asm("swi " SWI_NUM_WITH_QUOTES_AROUND_IT); }


#else	// Unrecognized ARM compiler; don't know how to do a SWI, so punt safely...

	// This function must be defined for the current toolset, to retrieve and/or
	// calculate the base address of our code resource.  This function is called
	// called by AdnDebugNativeRegister() which tells the desktop debugger where
	// exactly in memory the code is located (to enable source level debugging).
	#define AdnGetNativeCodeBaseAddr() AdnThisShouldCauseABuildError()

	// The preferred solution is to just reference the startup function, but if
	// that isn't relocated at runtime then something like the following can be used.
//	#pragma thumb off
//	static void * AdnGetNativeCodeBaseAddr(void);
//	static asm void * AdnGetNativeCodeBaseAddr(void)
//	{
//		sub		r0, pc, #8						// get real address of this function
//		lda		r1, AdnGetNativeCodeBaseAddr	// get zero-based offset to this function
//		sub		r0, r0, r1						// subtract to get real base of code
//		bx		lr								// and return
//	}
//	#pragma thumb reset

	// To support other compilers, inline SWI calls must be implemented:
	// (The AdnDebugMgr APIs should not be called for non-ARM builds.)
	#define _SemihostOp0(op)			AdnThisShouldCauseABuildError()
	#define _SemihostOp0r(op)			AdnThisShouldCauseABuildError()
	#define _SemihostOp1(op,p1)			AdnThisShouldCauseABuildError()
	#define _SemihostOp3r(op,p1,p2,p3)	AdnThisShouldCauseABuildError()
	#define _SemihostWrite0(op, s)		AdnThisShouldCauseABuildError()
	#define _SemihostPostLoad(op, p)	AdnThisShouldCauseABuildError()
	#define _SemihostPostUnload(op, p)	AdnThisShouldCauseABuildError()

#endif


/***********************************************************************
 * FUNCTION:    AdnDebugEnableSet
 * DESCRIPTION: Enable debugger nub features (kAdnEnable*).
 * PARAMETERS:  Flags indicating which features to enable
 * RETURNED:    nothing
 ***********************************************************************/
#define AdnDebugEnableSet(flags) \
		_SemihostOp1(kAdnSemihostDebugEnableSet, flags)


/***********************************************************************
 * FUNCTION:    AdnDebugEnableGet
 * DESCRIPTION: Get enabled debugger nub features (kAdnEnable*).
 * PARAMETERS:  none
 * RETURNED:    Flags indicating which features are enabled
 ***********************************************************************/
#define AdnDebugEnableGet() \
		_SemihostOp0r(kAdnSemihostDebugEnableGet)


/***********************************************************************
 * FUNCTION:    AdnDebugEnableGetSupported
 * DESCRIPTION: Get supported debugger nub features (kAdnEnable*).
 * PARAMETERS:  none
 * RETURNED:    Flags indicating which features are supported
 ***********************************************************************/
#define AdnDebugEnableGetSupported() \
		_SemihostOp0r(kAdnSemihostDebugEnableGetSupported)


/***********************************************************************
 * FUNCTION:    AdnDebugLicenseeSpecific
 * DESCRIPTION: Make licensee-specific call to ArmDebugNub.
 * PARAMETERS:  oemID    - PalmSource-registered OEM ID (creator code)
 *              selector - Licensee-specific function selector
 *              param    - Function-specific parameter
 * RETURNED:    result   - Function-specific result (-1 == not supported)
 ***********************************************************************/
#define AdnDebugLicenseeSpecific(oemID, selector, param) \
		_SemihostOp3r(kAdnSemihostLicenseeSpecific, oemID, selector, param)



/***********************************************************************
 * FUNCTION:    AdnDebugMessage
 * DESCRIPTION: Display a debug message in the desktop debugger.
 * PARAMETERS:  messageP - pointer to null-terminated string to display
 * RETURNED:    nothing
 ***********************************************************************/
#define AdnDebugMessage(messageP) \
		_SemihostWrite0(kAdnSemihostArmWrite0, messageP)

#define AdnDebugMessageIf(condition, messageP) \
	do {if (condition) AdnDebugMessage(messageP);} while (0)


/***********************************************************************
 * FUNCTION:    AdnDebugBreak
 * DESCRIPTION: Break into the desktop debugger.
 * PARAMETERS:  none
 * RETURNED:    nothing
 ***********************************************************************/
#define AdnDebugBreak() \
		_SemihostOp0(kAdnSemihostPUDDebugBreak)



/***********************************************************************
 * FUNCTION:    AdnDebugUpdateLoadedModules
 * DESCRIPTION: Notify debugger of any recently loaded/unloaded modules.
 * PARAMETERS:  none
 * RETURNED:    nothing
 ***********************************************************************/
#define AdnDebugUpdateLoadedModules() \
		_SemihostOp0(kAdnSemihostPUDModuleTableUpdate)


/***********************************************************************
 * FUNCTION:    AdnDebugNativeRegisterAddr
 * DESCRIPTION: Ask debugger to register PACE Native Object. This is
 *				useful in the case where the code making this call
 *				needs to register Native code that lives elsewhere (e.g.
 *				in a different chunk), and thus AdnGetNativeCodeBaseAddr()
 *				won't retrieve the correct code base address. Generally,
 *				PACE Native Objects which are registering themselves should
 *				use the simpler form, AdnDebugNativeRegister(), below.
 * PARAMETERS:  dbType    - application database type (e.g. 'appl')
 *              dbCreator - application database creator code
 *              rsrcType  - PACE Native Object resource type (e.g. 'ARMC')
 *              rsrcID    - PACE Native Object resource ID
 *              codeAddr  - PACE Native Object code base address
 * RETURNED:    nothing
 ***********************************************************************/
#define AdnDebugNativeRegisterAddr(_dbType, _dbCreator, _rsrcType, _rsrcID, _codeAddr) \
		{																			\
			DbgPostLoadParamsType _postLoadParams;									\
			_postLoadParams.processID = 0;											\
			_postLoadParams.moduleID = (unsigned long)_codeAddr /*sectionCookie*/;	\
			_postLoadParams.codeAddr = _codeAddr;									\
			_postLoadParams.dataAddr = 0;											\
			_postLoadParams.type = _dbType;											\
			_postLoadParams.creator = _dbCreator;									\
			_postLoadParams.rsrcType = _rsrcType;									\
			_postLoadParams.rsrcID = _rsrcID;										\
			_postLoadParams.reserved = 0;											\
			_SemihostPostLoad(kAdnSemihostNativeRegister, &_postLoadParams);		\
		}
		

/***********************************************************************
 * FUNCTION:    AdnDebugNativeRegister
 * DESCRIPTION: Ask debugger to register PACE Native Object.
 *				This should be done after locking the code.  Any
 *				previously unresolved breakpoints will be activated.
 * PARAMETERS:  dbType    - application database type (e.g. 'appl')
 *              dbCreator - application database creator code
 *              rsrcType  - PACE Native Object resource type (e.g. 'ARMC')
 *              rsrcID    - PACE Native Object resource ID
 * RETURNED:    nothing
 ***********************************************************************/
#define AdnDebugNativeRegister(_dbType, _dbCreator, _rsrcType, _rsrcID) \
		AdnDebugNativeRegisterAddr(_dbType, _dbCreator, _rsrcType, _rsrcID, AdnGetNativeCodeBaseAddr());


/***********************************************************************
 * FUNCTION:    AdnDebugNativeUnregisterAddr
 * DESCRIPTION: Ask debugger to unregister PACE Native Object. This is
 *				useful in the case where the code making this call
 *				needs to unregister Native code that lives elsewhere (e.g.
 *				in a different chunk), and thus AdnGetNativeCodeBaseAddr()
 *				won't retrieve the correct code base address. Generally,
 *				PACE Native Objects which are unregistering themselves should
 *				use the simpler form, AdnDebugNativeUnregister(), below.
 * PARAMETERS:  codeAddr  - PACE Native Object code base address
 * RETURNED:    nothing
 ***********************************************************************/
#define AdnDebugNativeUnregisterAddr(_codeAddr)											\
		{																				\
			DbgPostUnloadParamsType _postUnloadParams;									\
			_postUnloadParams.processID = 0;											\
			_postUnloadParams.moduleID = (unsigned long)_codeAddr /*sectionCookie*/;	\
			_SemihostPostUnload(kAdnSemihostNativeUnregister, &_postUnloadParams);		\
		}

/***********************************************************************
 * FUNCTION:    AdnDebugNativeUnregister
 * DESCRIPTION: Ask debugger to unregister PACE Native Object.
 *				This should be done prior to unlocking the code since
 *				breakpoints in the code may need to be removed.
 * PARAMETERS:  none
 * RETURNED:    nothing
 ***********************************************************************/
#define AdnDebugNativeUnregister() \
		AdnDebugNativeUnregisterAddr(AdnGetNativeCodeBaseAddr());


#endif // __ADNDEBUGMGR_H__
