/* ================================================================================== */
/* Copyright (c) 1998-1999 3Com Corporation or its subsidiaries. All rights reserved. */
/* ================================================================================== */

#ifndef _CPU_REG_H_
#define _CPU_REG_H_

#include "AppPreferences.h"		// AppPreferences::Configuration
#include "Miscellaneous.h"		// DeviceType
#include "Platform.h"			// TByteQueue
#include "Platform_Files.h"		// FileReference
#include "TrapPatches.h"		// CallROMType
#include "PalmHeap.h"			// ChunkInfo

// Types

#pragma mark Types

typedef Bool (*ExceptionHandlerProc)(uae_s32 exceptionNumber, uaecptr oldpc);


// Globals.

#pragma mark Globals

extern Bool			gBreakOnException[];
extern TByteQueue	gKeyQueue;


// Constants.

#pragma mark Constants

enum
{
	kButton_None		= -1,
	kButton_Power		= 0,
	kButton_UpArrow		= 1,
	kButton_DownArrow	= 2,
	kButton_DateBook	= 3,
	kButton_Phone		= 4,
	kButton_ToDo		= 5,
	kButton_Memo		= 6
};


enum
{
	kException_BusErr	= 2,						// 08 / 2
	kException_AddressErr,							// 0C / 3
	kException_IllegalInstr,						// 10 / 4
	kException_DivideByZero,						// 14 / 5
	kException_Chk,									// 18 / 6
	kException_Trap,								// 1C / 7
	kException_Privilege,							// 20 / 8
	kException_Trace,								// 24 / 9
	kException_ATrap,								// 28 / A
	kException_FTrap,								// 2C / B
	kException_Reseved12,							// 30 / C
	kException_Coproc,								// 34 / D
	kException_FormatErr,							// 38 / E
	kException_UninitializedInt,					// 3C / F

	kException_Reserved0,							// 40-5C / 10-17
	kException_Reserved1,
	kException_Reserved2,
	kException_Reserved3,
	kException_Reserved4,
	kException_Reserved5,
	kException_Reserved6,
	kException_Reserved7,

	kException_SpuriousInt,							// 60 / 18
	kException_AutoVec1,							// 64 / 19
	kException_AutoVec2,							// 68 / 1A
	kException_AutoVec3,							// 6C / 1B
	kException_AutoVec4,							// 70 / 1C
	kException_AutoVec5,							// 74 / 1D
	kException_AutoVec6,							// 78 / 1E
	kException_AutoVec7,							// 7C / 1F

	kException_Trap0,								// 80 - BC / 20 - 2F	// For soft breakpoints	
	kException_Trap1,
	kException_Trap2,
	kException_Trap3,
	kException_Trap4,
	kException_Trap5,
	kException_Trap6,
	kException_Trap7,
	kException_Trap8,								// For compiled breakpoints	
	kException_Trap9,
	kException_Trap10,
	kException_Trap11,
	kException_Trap12,
	kException_Trap13,								// ATrap returns (emulator convention)
	kException_Trap14,								// Tail patches (emulator convention)
	kException_Trap15,								// Trap dispatcher

	kException_Unassigned0,							// C0 - FC / 30 - 3F
	kException_Unassigned1,
	kException_Unassigned2,
	kException_Unassigned3,
	kException_Unassigned4,
	kException_Unassigned5,
	kException_Unassigned6,
	kException_Unassigned7,
	kException_Unassigned8,
	kException_Unassigned9,
	kException_Unassigned10,
	kException_Unassigned11,
	kException_Unassigned12,
	kException_Unassigned13,
	kException_Unassigned14,
	kException_Unassigned15,

	kException_LastException
};


// CPU loop exit reasons

enum
{
	kBreak_None				= 0x00,
	kBreak_Exception		= 0x3F,			// An exception has occured
	kBreak_CheckForEvents	= 0x40,			// (Mac) Need to check for and handle events
	kBreak_StopRequest		= 0x80,			// (Windows) Other thread requested halt

	kBreak_All				= 0xFFFFFFFF
};


// Additional flags for regs.spcflags.
// Define these from the top-down to avoid
// overlapping with the UAE-defined flags,
// and avoid using the high bit just for safety.

#define SPCFLAG_SAVE_STATE	(0x40000000)



// Prototypes.

#pragma mark -

#pragma mark Emulator

class SessionFile;

extern Bool	gIsEZDevice;

class Emulator
{
	public:
		static void				Initialize			(const AppPreferences::Configuration& cfg);
		static void				Reset				(void);
		static void				Save				(SessionFile&);
		static void				Load				(SessionFile&);
		static void				Dispose				(void);

		static void				Save				(const FileReference&, Bool updateLastRAMFile, Bool updateMRU, Bool updateDefaultConfiguration);
		static void				Load				(const FileReference&, Bool updateLastRAMFile, Bool updateMRU, Bool updateDefaultConfiguration);

		static long				Execute				(void);
		static void				ExecuteSpecial		(void);
		static void				ExecuteStoppedLoop	(void);
		static long				ExecuteUntilATrap	(void);
		static long				ExecuteUntilBreak	(void);

		static void				HandleCPUBreak		(void);
		static void				InstallCPUBreaks	(void);

		static uae_u32			SetBreakReason		(uae_u32);	// set the given bits; leave others alone
		static uae_u32			SetBreakReasonMask	(uae_u32);	// set the given bits; leave others alone
		static uae_u32			ClearBreakReason	(uae_u32);	// clear the given bits; leave others alone
		static uae_u32			ClearBreakReasonMask(uae_u32);	// clear the given bits; leave others alone

		static Bool				SetBreakOnException	(uae_s32 exceptionNumber,
													 Bool doBreak);

		static DeviceType		GetHardwareDevice	(void);
		static void				SetHardwareDevice	(DeviceType hardwareDevice);
		static Bool				EZMode				(void) { return gIsEZDevice; }
		static Bool				HasFlash			(void);

		static void				HandleDlgButton		(int button, uaecptr startPC);

#if TIME_STARTUP
		static unsigned long	GetInstructionCount	(void);
#endif
		static unsigned long	GetCycleCount	(void);
};


// Little helper stack-based class for altering "break on exception" values

class CBreakOnException
{
	public:
								CBreakOnException (uae_s32 exceptionNumber) :
									fExceptionNumber (exceptionNumber),
									fOldBreakOnException (Emulator::SetBreakOnException (
															exceptionNumber, true))
								{
								}

								~CBreakOnException (void)
								{
									(void) Emulator::SetBreakOnException (	fExceptionNumber,
																			fOldBreakOnException);
								}

	private:
		uae_s32					fExceptionNumber;
		Bool					fOldBreakOnException;
};


#pragma mark Hardware

class Hardware
{
	public:
		static void				Initialize			(void);
		static void				Reset				(void);
		static void				Save				(SessionFile&);
		static void				Load				(SessionFile&);
		static void				Dispose				(void);

		static void				Cycle				(Bool sleeping);
		static void				PenEvent			(Bool penIsDown, uae_s32 penX, uae_s32 penY);
		static void				ButtonEvent			(Bool iButton_IsDown, uae_s32 iButton);
		static void				HotSyncEvent		(Bool iButton_IsDown);
		static void				KeyboardEvent		(uae_u8 iKey);

		static Bool				HavePenEvent		(void);
		static void				SetHavePenEvent		(Bool);
		static Point			PenLocation			(void);
		static Bool				PenIsDown			(void);
};


#pragma mark Screen

class Screen
{
	public:
		static void				Initialize			(void);
		static void				Reset				(void);
		static void				Save				(SessionFile&);
		static void				Load				(SessionFile&);
		static void				Dispose				(void);

		static void				MarkDirty			(uaecptr address, uae_u32 size);
		static void				InvalidateAll		(void);
		
		struct RGBType
		{
			Byte		r;
			Byte		g;
			Byte		b;
		};

		struct BufferInfo
		{
			uaecptr		lcdBuffer;		// Base address of the buffer in emulated space.
			long		lcdDepth;		// Depth (in bpp) of LCD screen
			long		lcdRowBytes;	// Bytes in each row in LCD screen

			uae_u8*		myBuffer;		// Pointer to image buffer.  NULL if LCD is off or if nothing's changed.
			long		myDepth;		// Depth (in bpp) of myBuffer
			long		myRowBytes;		// Bytes in each row in myBuffer
			RGBType*	myCLUT;			// Pointer to CLUT array.

			long		firstLine;		// First changed scanline
			long		lastLine;		// Last changed scanline + 1
			AbsRectType	visibleBounds;	// Bounds of the visible area.  Usually size of the screen, but sometimes offset.
			long		height;			// Height, in pixels
			Bool		backlightOn;	// True if backlighting is on
			Bool		lcdOn;			// True if LCD is on at all (if false, "buffer" is NULL)
		};

		static Bool				GetBits				(BufferInfo&, Bool incremental);
};


#pragma mark StackRange

struct StackRange
{
	StackRange () :
		fBottom (0),
		fTop (0)
		{}
	StackRange (const StackRange& other) :
		fBottom (other.fBottom),
		fTop (other.fTop)
		{}
	StackRange (uaecptr bottom, uaecptr top) :
		fBottom (bottom),
		fTop (top)
		{}

	bool operator==(const StackRange& other) const
		{ return fBottom == other.fBottom; }

	bool operator!=(const StackRange& other) const
		{ return fBottom != other.fBottom; }

	bool operator<(const StackRange& other) const
		{ return fBottom < other.fBottom; }

	bool operator>(const StackRange& other) const
		{ return fBottom > other.fBottom; }

	uaecptr	fBottom;
	uaecptr	fTop;
};

typedef list<StackRange> StackList;


#pragma mark Software

class Software
{
	public:
		static void				Initialize			(void);
		static void				Reset				(void);
		static void				Save				(SessionFile&);
		static void				Load				(SessionFile&);
		static void				Dispose				(void);

		static void				BusError					(void);
		static void				AddressError				(void);
		static void				ProcessException			(uae_s32 iException,
															 uaecptr oldpc,
															 uaecptr curpc);
		static void				ProcessInterrupt			(uae_s32 iInterrupt);
		static void				ProcessIllegalInstruction	(uae_u32 iOpcode);
		static void				InstallExceptionHandler		(uae_s32 exceptionNumber, ExceptionHandlerProc);
		static void				RemoveExceptionHandler		(uae_s32 exceptionNumber);
		static Bool				ProcessJSR					(uaecptr oldpc, uaecptr dest);
		static Bool				ProcessJSR_Ind				(uaecptr oldpc);
		static Bool				ProcessRTS					(void);
		static Bool				ProcessRTE					(uaecptr newpc);
		static Bool				ProcessLINK					(uae_s32 linkSize);
		static Bool				ProcessTrap15				(uae_s32 iException, uaecptr oldpc);

		static Bool				ProcessSystemCall			(uaecptr oldpc);
		static uaecptr			ReportInvalidSystemCall		(uae_u16 trapWord, uaecptr oldpc);

		static void				CheckStackPointer			(int opcodeType, uaecptr basePtr);
		static Bool				RememberStackChunk			(const PalmHeap::ChunkInfo&);
		static void				ForgetStackChunk			(uaecptr);
		static StackList::iterator	FindStackChunk			(uaecptr);
};


#pragma mark LowMem

/*
	Low memory is laid out as follows:

	struct LowMemType
	{
		LowMemHdrType			fixed; 
		{
			M68KExcTableType		vectors;
			FixedGlobalsType		globals;
			{
				... most of the goodies are in here ...
			}
		}
	
		CardInfoType			memCardInfo[hwrNumCardSlots];	
		SlkGlobalsType			slkGlobals;
		DbgGlobalsType			dbgGlobals;
		SysAppInfoType			sysAppInfo;
		Ptr						sysDispatchTable[sysNumTraps];
	}

	Note that those last 5 guys don't need to be addressed directly;
	there are pointers to them in the "globals" section.

		--	memCardInfoP
		--	slkGlobalsP
		--	dbgGlobalsP
		--	sysAppInfoP
		--	sysDispatchTableP
*/

class LowMem
{
	public:
		static void				Initialize			(void);
		static void				Reset				(void);
		static void				Save				(SessionFile&);
		static void				Load				(SessionFile&);
		static void				Dispose				(void);

		static uae_u8			GetEvtMgrIdle		(void);
		static Bool				TrapExists			(uae_u16 iATrap);
		static uaecptr			GetTrapAddress		(uae_u16 iATrap);

	#define LowMem_Location(field)	\
		offsetof (LowMemType, fixed.globals.field)

	#define LowMem_Size(x)						\
		(sizeof (((FixedGlobalsType*) 0)->x))

	#define In_LowMem_Range(x, v)				\
		((v) > LowMem_Location (x) - LowMem_Size (x) &&	\
		 (v) < LowMem_Location (x) + LowMem_Size (x))

	#define LowMem_GetGlobal(x)		\
		((LowMem_Size(x) == 1) ? get_byte (LowMem_Location(x)) :	\
		 (LowMem_Size(x) == 2) ? get_word (LowMem_Location(x)) :	\
								 get_long (LowMem_Location(x)))

	#define LowMem_SetGlobal(x, v)	\
		((LowMem_Size(x) == 1) ? put_byte (LowMem_Location(x), v) :	\
		 (LowMem_Size(x) == 2) ? put_word (LowMem_Location(x), v) :	\
								 put_long (LowMem_Location(x), v))
};


#pragma mark Registers

class Registers
{
	public:
		static void				GetRegisters			(regstruct& oRegisters);
		static void				SetRegisters			(regstruct& iRegisters);
		static void				UpdateSRFromRegisters	(void);
		static void				UpdateRegistersFromSR	(void);
};


#pragma mark HWRegisters

class HWRegisters
{
	public:
		static void				Initialize			(void);
		static void				Reset				(void);
		static void				Save				(SessionFile&);
		static void				Load				(SessionFile&);
		static void				Dispose				(void);

		static void				Cycle				(Bool sleeping);
		static void				CycleSlowly			(Bool sleeping);
		static uae_s32			GetInterruptLevel	(void);
		static uae_s32			GetInterruptBase	(void);
		static void				ButtonEvent			(Bool iButton_IsDown, uae_s32 iButton);
		static void				HotSyncEvent		(Bool iButton_IsDown);
		static int				GetLCDDepth			(void);
		static int				GetLCDRowBytes		(void);
		static int				GetLCDWidth			(void);
		static int				GetLCDHeight		(void);
		static uaecptr			GetLCDStartAddr		(void);
		static void				GetLCDPalette		(Screen::RGBType* thePalette);
		static int				GetLCDOffset		(void);
		static Bool				LCDIsOn				(void);
		static Bool				BacklightIsOn		(void);
		static void				TurnSoundOff		(void);
		static void				UpdateUARTRegisters	(Bool refreshRxData);

		static void				SetCurrentMilliseconds		(uae_u32 t);
		static uae_u32			GetCurrentMilliseconds		(void);
		static Bool				CanStop				(void);
};


#endif	// _CPU_REG_H_
