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

    drcbeut.h

    Utility functions for dynamic recompiling backends.

    Copyright Aaron Giles
    Released for general non-commercial use under the MAME license
    Visit http://mamedev.org for licensing and usage restrictions.

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

#pragma once

#ifndef __DRCBEUT_H__
#define __DRCBEUT_H__

#include "drcuml.h"


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

/* callback function for forward-referenced labels */
typedef void (*drclabel_fixup_func)(void *parameter, drccodeptr labelcodeptr);


/* opaque structure representing a managed list of labels */
typedef struct _drclabel_list drclabel_list;


/* opaque structure representing a managed code map */
typedef struct _drcmap_state drcmap_state;


/* information about the hash tables used by the UML and backend */
typedef struct _drchash_state drchash_state;
struct _drchash_state
{
	drccache *		cache;				/* cache where allocations come from */
	int				modes;				/* number of modes supported */

	drccodeptr		nocodeptr;			/* pointer to code which will handle missing entries */

	UINT8			l1bits;				/* bits worth of entries in l1 hash tables */
	UINT8			l1shift;			/* shift to apply to the PC to get the l1 hash entry */
	offs_t			l1mask;				/* mask to apply after shifting */
	UINT8			l2bits;				/* bits worth of entries in l2 hash tables */
	UINT8			l2shift;			/* shift to apply to the PC to get the l2 hash entry */
	offs_t			l2mask;				/* mask to apply after shifting */

	drccodeptr **	emptyl1;			/* pointer to empty l1 hash table */
	drccodeptr *	emptyl2;			/* pointer to empty l2 hash table */

	drccodeptr **	base[1];			/* pointer to the l1 table for each mode */
};



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

/* ----- hash table management ----- */

/* allocate memory in the cache for the hash table tracker (it auto-frees with the cache) */
drchash_state *drchash_alloc(drccache *cache, int modes, int addrbits, int ignorebits);

/* flush existing hash tables and create new ones */
int drchash_reset(drchash_state *drchash);

/* note the beginning of a block */
void drchash_block_begin(drchash_state *drchash, drcuml_block *block, const drcuml_instruction *instlist, UINT32 numinst);

/* note the end of a block */
void drchash_block_end(drchash_state *drchash, drcuml_block *block);

/* set the default codeptr for any empty hash entries (defaults to NULL) */
void drchash_set_default_codeptr(drchash_state *drchash, drccodeptr code);

/* set the codeptr for the given mode/pc */
int drchash_set_codeptr(drchash_state *drchash, UINT32 mode, UINT32 pc, drccodeptr code);



/* ----- code map management ----- */

/* allocate memory in the cache for the code mapper (it auto-frees with the cache) */
drcmap_state *drcmap_alloc(drccache *cache, UINT64 uniquevalue);

/* note the beginning of a block */
void drcmap_block_begin(drcmap_state *drcmap, drcuml_block *block);

/* note the end of a block */
void drcmap_block_end(drcmap_state *drcmap, drcuml_block *block);

/* set a map value for the given code pointer */
void drcmap_set_value(drcmap_state *drcmap, drccodeptr codebase, UINT32 mapvar, UINT32 newvalue);

/* return a map value for the given code pointer */
UINT32 drcmap_get_value(drcmap_state *drcmap, drccodeptr codebase, UINT32 mapvar);

/* return the most recently set map value */
UINT32 drcmap_get_last_value(drcmap_state *drcmap, UINT32 mapvar);



/* ----- label management ----- */

/* allocate a label list within the cache (it auto-frees with the cache) */
drclabel_list *drclabel_list_alloc(drccache *cache);

/* note the beginning of a block */
void drclabel_block_begin(drclabel_list *drcmap, drcuml_block *block);

/* note the end of a block */
void drclabel_block_end(drclabel_list *drcmap, drcuml_block *block);

/* find or allocate a new label; returns NULL and requests an OOB callback if undefined */
drccodeptr drclabel_get_codeptr(drclabel_list *list, drcuml_codelabel label, drclabel_fixup_func fixup, void *param);

/* set the pointer to a new label */
void drclabel_set_codeptr(drclabel_list *list, drcuml_codelabel label, drccodeptr codeptr);



/***************************************************************************
    INLINE FUNCTIONS
***************************************************************************/

/*-------------------------------------------------
    drchash_get_codeptr - return the codeptr
    allocated for the given mode/pc
-------------------------------------------------*/

INLINE drccodeptr drchash_get_codeptr(drchash_state *drchash, UINT32 mode, UINT32 pc)
{
	assert(mode < drchash->modes);
	return drchash->base[mode][(pc >> drchash->l1shift) & drchash->l1mask][(pc >> drchash->l2shift) & drchash->l2mask];
}


/*-------------------------------------------------
    drchash_code_exists - return TRUE if there is
    a matching hash entry for the given mode/pc
-------------------------------------------------*/

INLINE int drchash_code_exists(drchash_state *drchash, UINT32 mode, UINT32 pc)
{
	return (drchash_get_codeptr(drchash, mode, pc) != drchash->nocodeptr);
}


#endif /* __DRCBEUT_H__ */
