/***************************************************************************

    x86drc.h

    x86 Dynamic recompiler support routines.

    Copyright Nicola Salmoria and the MAME Team.
    Visit http://mamedev.org for licensing and usage restrictions.

***************************************************************************/

#pragma once

#ifndef __X86DRC_H__
#define __X86DRC_H__

#include "cpuintrf.h"
#include "x86emit.h"


/***************************************************************************
    TYPE DEFINITIONS
***************************************************************************/

/* PC and pointer pair */
typedef struct _pc_ptr_pair pc_ptr_pair;
struct _pc_ptr_pair
{
	UINT32		pc;
	x86code *	target;
};


/* core interface structure for the drc common code */
typedef struct _drc_core drc_core;
struct _drc_core
{
	UINT8 *		cache_base;				/* base pointer to the compiler cache */
	UINT8 *		cache_top;				/* current top of cache */
	UINT8 *		cache_danger;			/* high water mark for the end */
	UINT8 *		cache_end;				/* end of cache memory */
	size_t		cache_size;				/* cache allocated size */
	UINT8		cache_allocated;		/* did the DRC core allocate the cache? */

	x86code ***	lookup_l1;				/* level 1 lookup */
	x86code **	lookup_l2_recompile;	/* level 2 lookup populated with recompile pointers */
	UINT8		l1bits;					/* number of bits in level 1 lookup */
	UINT8		l2bits;					/* number of bits in level 2 lookup */
	UINT8		l1shift;				/* shift to go from PC to level 1 lookup */
	UINT32		l2mask;					/* mask to go from PC to level 2 lookup */
	UINT8		l2scale;				/* scale to get from masked PC value to final level 2 lookup */

	void 		(*entry_point)(void);	/* pointer to asm entry point */
	x86code *	out_of_cycles;			/* pointer to out of cycles jump point */
	x86code *	recompile;				/* pointer to recompile jump point */
	x86code *	dispatch;				/* pointer to dispatch jump point */
	x86code *	flush;					/* pointer to flush jump point */

	UINT32 *	pcptr;					/* pointer to where the PC is stored */
	UINT32 *	icountptr;				/* pointer to where the icount is stored */
	UINT32 *	esiptr;					/* pointer to where the volatile data in ESI is stored */
	UINT8		pc_in_memory;			/* true if the PC is stored in memory */
	UINT8		icount_in_memory;		/* true if the icount is stored in memory */

	UINT8		uses_fp;				/* true if we need the FP unit */
	UINT8		uses_sse;				/* true if we need the SSE unit */
	UINT16		fpcw_curr;				/* current FPU control word */
	UINT32		mxcsr_curr;				/* current SSE control word */
	UINT16		fpcw_save;				/* saved FPU control word */
	UINT32		mxcsr_save;				/* saved SSE control word */

	pc_ptr_pair *sequence_list;			/* PC/pointer sets for the current instruction sequence */
	UINT32		sequence_count;			/* number of instructions in the current sequence */
	UINT32		sequence_count_max;		/* max number of instructions in the current sequence */
	pc_ptr_pair *tentative_list;		/* PC/pointer sets for tentative branches */
	UINT32		tentative_count;		/* number of tentative branches */
	UINT32		tentative_count_max;	/* max number of tentative branches */

	void 		(*cb_reset)(struct _drc_core *drc);		/* callback when the cache is reset */
	void 		(*cb_recompile)(struct _drc_core *drc);	/* callback when code needs to be recompiled */
	void 		(*cb_entrygen)(struct _drc_core *drc);	/* callback before generating the dispatcher on entry */
};


/* configuration structure for the drc common code */
typedef struct _drc_config drc_config;
struct _drc_config
{
	UINT8 *		cache_base;				/* base pointer to the compiler cache */
	UINT32		cache_size;				/* size of cache to allocate */
	UINT32		max_instructions;		/* maximum instructions per sequence */
	UINT8		address_bits;			/* number of live address bits in the PC */
	UINT8		lsbs_to_ignore;			/* number of LSBs to ignore on the PC */
	UINT8		uses_fp;				/* true if we need the FP unit */
	UINT8		uses_sse;				/* true if we need the SSE unit */
	UINT8		pc_in_memory;			/* true if the PC is stored in memory */
	UINT8		icount_in_memory;		/* true if the icount is stored in memory */

	UINT32 *	pcptr;					/* pointer to where the PC is stored */
	UINT32 *	icountptr;				/* pointer to where the icount is stored */
	UINT32 *	esiptr;					/* pointer to where the volatile data in ESI is stored */

	void 		(*cb_reset)(drc_core *drc);		/* callback when the cache is reset */
	void 		(*cb_recompile)(drc_core *drc);	/* callback when code needs to be recompiled */
	void 		(*cb_entrygen)(drc_core *drc);	/* callback before generating the dispatcher on entry */
};


/* structure to hold link data to be filled in later */
typedef struct _link_info link_info;
struct _link_info
{
	UINT8 		size;
	UINT8 *		target;
};



/***************************************************************************
    MACROS
***************************************************************************/

/* use this macro in emit_* instructions to make them shorter */
#define DRCTOP					&drc->cache_top



/***************************************************************************
    HELPER MACROS
***************************************************************************/

/* useful macros for accessing hi/lo portions of 64-bit values */
#define LO(x)		(&(((UINT32 *)(UINT32)(x))[0]))
#define HI(x)		(&(((UINT32 *)(UINT32)(x))[1]))



/***************************************************************************
    CONSTANTS
***************************************************************************/

/* features */
#define CPUID_FEATURES_MMX		(1 << 23)
#define CPUID_FEATURES_SSE		(1 << 26)
#define CPUID_FEATURES_SSE2		(1 << 25)
#define CPUID_FEATURES_CMOV		(1 << 15)
#define CPUID_FEATURES_TSC		(1 << 4)



/***************************************************************************
    FUNCTION PROTOTYPES
***************************************************************************/

/* init/shutdown */
drc_core *drc_init(UINT8 cpunum, drc_config *config);
void *drc_alloc(drc_core *drc, size_t amount);
void drc_cache_reset(drc_core *drc);
void drc_execute(drc_core *drc);
void drc_exit(drc_core *drc);

/* code management */
void drc_begin_sequence(drc_core *drc, UINT32 pc);
void drc_end_sequence(drc_core *drc);
void drc_register_code_at_cache_top(drc_core *drc, UINT32 pc);
void *drc_get_code_at_pc(drc_core *drc, UINT32 pc);

/* standard appendages */
void drc_append_dispatcher(drc_core *drc);
void drc_append_fixed_dispatcher(drc_core *drc, UINT32 newpc);
void drc_append_tentative_fixed_dispatcher(drc_core *drc, UINT32 newpc);
void drc_append_call_debugger(drc_core *drc);
void drc_append_standard_epilogue(drc_core *drc, INT32 cycles, INT32 pcdelta, int allow_exit);
void drc_append_save_volatiles(drc_core *drc);
void drc_append_restore_volatiles(drc_core *drc);
void drc_append_save_call_restore(drc_core *drc, x86code *target, UINT32 stackadj);
void drc_append_verify_code(drc_core *drc, void *code, UINT8 length);

void drc_append_set_fp_rounding(drc_core *drc, UINT8 regindex);
void drc_append_set_temp_fp_rounding(drc_core *drc, UINT8 rounding);
void drc_append_restore_fp_rounding(drc_core *drc);

void drc_append_set_sse_rounding(drc_core *drc, UINT8 regindex);
void drc_append_set_temp_sse_rounding(drc_core *drc, UINT8 rounding);
void drc_append_restore_sse_rounding(drc_core *drc);

/* disassembling drc code */
void drc_dasm(FILE *f, const void *begin, const void *end);

/* x86 CPU features */
UINT32 drc_x86_get_features(void);


#endif	/* __X86DRC_H__ */
