mirror of
https://github.com/holub/mame
synced 2025-06-04 03:46:29 +03:00

- Created new central header "emu.h"; this should be included by pretty much any driver or device as the first include. This file in turn includes pretty much everything a driver or device will need, minus any other devices it references. Note that emu.h should *never* be included by another header file. - Updated all files in the core (src/emu) to use emu.h. - Removed a ton of redundant and poorly-tracked header includes from within other header files. - Temporarily changed driver.h to map to emu.h until we update files outside of the core. Added class wrapper around tagmap so it can be directly included and accessed within objects that need it. Updated all users to embed tagmap objects and changed them to call through the class. Added nicer functions for finding devices, ports, and regions in a machine: machine->device("tag") -- return the named device, or NULL machine->port("tag") -- return the named port, or NULL machine->region("tag"[, &length[, &flags]]) -- return the named region and optionally its length and flags Made the device tag an astring. This required touching a lot of code that printed the device to explicitly fetch the C-string from it. (Thank you gcc for flagging that issue!)
418 lines
11 KiB
C
418 lines
11 KiB
C
/***************************************************************************
|
|
|
|
drccache.h
|
|
|
|
Universal dynamic recompiler cache management.
|
|
|
|
Copyright Aaron Giles
|
|
Released for general non-commercial use under the MAME license
|
|
Visit http://mamedev.org for licensing and usage restrictions.
|
|
|
|
***************************************************************************/
|
|
|
|
#include "emu.h"
|
|
#include "drccache.h"
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
CONSTANTS
|
|
***************************************************************************/
|
|
|
|
/* largest block of code that can be generated at once */
|
|
#define CODEGEN_MAX_BYTES 65536
|
|
|
|
/* minimum alignment, in bytes (must be power of 2) */
|
|
#define CACHE_ALIGNMENT 8
|
|
|
|
/* largest permanent allocation we allow */
|
|
#define MAX_PERMANENT_ALLOC 1024
|
|
|
|
/* size of "near" area at the base of the cache */
|
|
#define NEAR_CACHE_SIZE 65536
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
MACROS
|
|
***************************************************************************/
|
|
|
|
/* ensure that all memory allocated is aligned to an 8-byte boundary */
|
|
#define ALIGN_PTR_UP(p) ((void *)(((FPTR)(p) + (CACHE_ALIGNMENT - 1)) & ~(CACHE_ALIGNMENT - 1)))
|
|
#define ALIGN_PTR_DOWN(p) ((void *)((FPTR)(p) & ~(CACHE_ALIGNMENT - 1)))
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
TYPE DEFINITIONS
|
|
***************************************************************************/
|
|
|
|
/* out-of-bounds codegen handlers */
|
|
typedef struct _oob_handler oob_handler;
|
|
struct _oob_handler
|
|
{
|
|
oob_handler * next; /* next handler */
|
|
drccache_oob_func callback; /* callback function */
|
|
void * param1; /* 1st pointer parameter */
|
|
void * param2; /* 2nd pointer parameter */
|
|
void * param3; /* 3rd pointer parameter */
|
|
};
|
|
|
|
|
|
/* a linked list of free items */
|
|
typedef struct _free_link free_link;
|
|
struct _free_link
|
|
{
|
|
free_link * next; /* pointer to the next guy */
|
|
};
|
|
|
|
|
|
/* cache state */
|
|
struct _drccache
|
|
{
|
|
/* core parameters */
|
|
drccodeptr near; /* pointer to the near part of the cache */
|
|
drccodeptr neartop; /* top of the near part of the cache */
|
|
drccodeptr base; /* base pointer to the compiler cache */
|
|
drccodeptr top; /* current top of cache */
|
|
drccodeptr end; /* end of cache memory */
|
|
drccodeptr codegen; /* start of generated code */
|
|
size_t size; /* size of the cache in bytes */
|
|
|
|
/* oob management */
|
|
oob_handler * ooblist; /* list of oob handlers */
|
|
oob_handler ** oobtail; /* pointer to tail oob pointer */
|
|
|
|
/* free lists */
|
|
free_link * free[MAX_PERMANENT_ALLOC / CACHE_ALIGNMENT];
|
|
free_link * nearfree[MAX_PERMANENT_ALLOC / CACHE_ALIGNMENT];
|
|
};
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
INITIALIZATION/TEARDOWN
|
|
***************************************************************************/
|
|
|
|
/*-------------------------------------------------
|
|
drccache_alloc - allocate the cache itself
|
|
-------------------------------------------------*/
|
|
|
|
drccache *drccache_alloc(size_t bytes)
|
|
{
|
|
drccache cache, *cacheptr;
|
|
|
|
assert(bytes >= sizeof(cache) + NEAR_CACHE_SIZE);
|
|
|
|
/* build a local structure first */
|
|
memset(&cache, 0, sizeof(cache));
|
|
cache.near = (drccodeptr)osd_alloc_executable(bytes);
|
|
cache.neartop = cache.near;
|
|
cache.base = cache.near + NEAR_CACHE_SIZE;
|
|
cache.top = cache.base;
|
|
cache.end = cache.near + bytes;
|
|
cache.size = bytes;
|
|
|
|
/* now allocate the cache structure itself from that */
|
|
cacheptr = (drccache *)drccache_memory_alloc(&cache, sizeof(cache));
|
|
*cacheptr = cache;
|
|
|
|
/* return the allocated result */
|
|
return cacheptr;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
drccache_free - free the cache
|
|
-------------------------------------------------*/
|
|
|
|
void drccache_free(drccache *cache)
|
|
{
|
|
/* release the memory; this includes the cache object itself */
|
|
osd_free_executable(cache->near, cache->size);
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
CACHE INFORMATION
|
|
***************************************************************************/
|
|
|
|
/*-------------------------------------------------
|
|
drccache_contains_pointer - return true if a
|
|
pointer is within the cache
|
|
-------------------------------------------------*/
|
|
|
|
int drccache_contains_pointer(drccache *cache, const void *ptr)
|
|
{
|
|
return ((const drccodeptr)ptr >= cache->near && (const drccodeptr)ptr < cache->near + cache->size);
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
drccache_contains_near_pointer - return true
|
|
if a pointer is within the cache
|
|
-------------------------------------------------*/
|
|
|
|
int drccache_contains_near_pointer(drccache *cache, const void *ptr)
|
|
{
|
|
return ((const drccodeptr)ptr >= cache->near && (const drccodeptr)ptr < cache->neartop);
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
drccache_near - return a pointer to the near
|
|
part of the cache
|
|
-------------------------------------------------*/
|
|
|
|
drccodeptr drccache_near(drccache *cache)
|
|
{
|
|
return cache->near;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
drccache_base - return a pointer to the base
|
|
of the cache
|
|
-------------------------------------------------*/
|
|
|
|
drccodeptr drccache_base(drccache *cache)
|
|
{
|
|
return cache->base;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
drccache_top - return the current top of the
|
|
cache
|
|
-------------------------------------------------*/
|
|
|
|
drccodeptr drccache_top(drccache *cache)
|
|
{
|
|
return cache->top;
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
MEMORY MANAGEMENT
|
|
***************************************************************************/
|
|
|
|
/*-------------------------------------------------
|
|
drccache_flush - flush the cache contents
|
|
-------------------------------------------------*/
|
|
|
|
void drccache_flush(drccache *cache)
|
|
{
|
|
/* can't flush in the middle of codegen */
|
|
assert(cache->codegen == NULL);
|
|
|
|
/* just reset the top back to the base and re-seed */
|
|
cache->top = cache->base;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
drccache_memory_alloc - allocate permanent
|
|
memory from the cache
|
|
-------------------------------------------------*/
|
|
|
|
void *drccache_memory_alloc(drccache *cache, size_t bytes)
|
|
{
|
|
drccodeptr ptr;
|
|
|
|
assert(bytes > 0);
|
|
|
|
/* pick first from the free list */
|
|
if (bytes < MAX_PERMANENT_ALLOC)
|
|
{
|
|
free_link **linkptr = &cache->free[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT];
|
|
free_link *link = *linkptr;
|
|
if (link != NULL)
|
|
{
|
|
*linkptr = link->next;
|
|
return link;
|
|
}
|
|
}
|
|
|
|
/* if no space, we just fail */
|
|
ptr = (drccodeptr)ALIGN_PTR_DOWN(cache->end - bytes);
|
|
if (cache->top > ptr)
|
|
return NULL;
|
|
|
|
/* otherwise update the end of the cache */
|
|
cache->end = ptr;
|
|
return ptr;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
drccache_memory_alloc_near - allocate
|
|
permanent memory from the near part of the
|
|
cache
|
|
-------------------------------------------------*/
|
|
|
|
void *drccache_memory_alloc_near(drccache *cache, size_t bytes)
|
|
{
|
|
drccodeptr ptr;
|
|
|
|
assert(bytes > 0);
|
|
|
|
/* pick first from the free list */
|
|
if (bytes < MAX_PERMANENT_ALLOC)
|
|
{
|
|
free_link **linkptr = &cache->nearfree[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT];
|
|
free_link *link = *linkptr;
|
|
if (link != NULL)
|
|
{
|
|
*linkptr = link->next;
|
|
return link;
|
|
}
|
|
}
|
|
|
|
/* if no space, we just fail */
|
|
ptr = (drccodeptr)ALIGN_PTR_UP(cache->neartop);
|
|
if (ptr + bytes > cache->base)
|
|
return NULL;
|
|
|
|
/* otherwise update the top of the near part of the cache */
|
|
cache->neartop = ptr + bytes;
|
|
return ptr;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
drccache_memory_free - release permanent
|
|
memory allocated from the cache
|
|
-------------------------------------------------*/
|
|
|
|
void drccache_memory_free(drccache *cache, void *memory, size_t bytes)
|
|
{
|
|
free_link **linkptr;
|
|
free_link *link = (free_link *)memory;
|
|
|
|
assert(bytes < MAX_PERMANENT_ALLOC);
|
|
assert(((drccodeptr)memory >= cache->near && (drccodeptr)memory < cache->base) || ((drccodeptr)memory >= cache->end && (drccodeptr)memory < cache->near + cache->size));
|
|
|
|
/* determine which free list to add to */
|
|
if ((drccodeptr)memory < cache->base)
|
|
linkptr = &cache->nearfree[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT];
|
|
else
|
|
linkptr = &cache->free[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT];
|
|
|
|
/* link is into the free list for our size */
|
|
link->next = *linkptr;
|
|
*linkptr = link;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
drccache_memory_alloc_temporary - allocate
|
|
temporary memory from the cache
|
|
-------------------------------------------------*/
|
|
|
|
void *drccache_memory_alloc_temporary(drccache *cache, size_t bytes)
|
|
{
|
|
drccodeptr ptr = cache->top;
|
|
|
|
/* can't allocate in the middle of codegen */
|
|
assert(cache->codegen == NULL);
|
|
|
|
/* if no space, we just fail */
|
|
if (ptr + bytes >= cache->end)
|
|
return NULL;
|
|
|
|
/* otherwise, update the cache top */
|
|
cache->top = (drccodeptr)ALIGN_PTR_UP(ptr + bytes);
|
|
return ptr;
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
CODE GENERATION
|
|
***************************************************************************/
|
|
|
|
/*-------------------------------------------------
|
|
drccache_begin_codegen - begin code
|
|
generation
|
|
-------------------------------------------------*/
|
|
|
|
drccodeptr *drccache_begin_codegen(drccache *cache, UINT32 reserve_bytes)
|
|
{
|
|
drccodeptr ptr = cache->top;
|
|
|
|
/* can't restart in the middle of codegen */
|
|
assert(cache->codegen == NULL);
|
|
assert(cache->ooblist == NULL);
|
|
|
|
/* if still no space, we just fail */
|
|
if (ptr + reserve_bytes >= cache->end)
|
|
return NULL;
|
|
|
|
/* otherwise, return a pointer to the cache top */
|
|
cache->codegen = cache->top;
|
|
cache->oobtail = &cache->ooblist;
|
|
return &cache->top;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
drccache_end_codegen - complete code
|
|
generation
|
|
-------------------------------------------------*/
|
|
|
|
drccodeptr drccache_end_codegen(drccache *cache)
|
|
{
|
|
drccodeptr result = cache->codegen;
|
|
|
|
/* run the OOB handlers */
|
|
while (cache->ooblist != NULL)
|
|
{
|
|
/* remove us from the list */
|
|
oob_handler *oob = cache->ooblist;
|
|
cache->ooblist = oob->next;
|
|
|
|
/* call the callback */
|
|
(*oob->callback)(&cache->top, oob->param1, oob->param2, oob->param3);
|
|
assert(cache->top - cache->codegen < CODEGEN_MAX_BYTES);
|
|
|
|
/* release our memory */
|
|
drccache_memory_free(cache, oob, sizeof(*oob));
|
|
}
|
|
|
|
/* update the cache top */
|
|
cache->top = (drccodeptr)ALIGN_PTR_UP(cache->top);
|
|
cache->codegen = NULL;
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
drccache_request_oob_codegen - request
|
|
callback for out-of-band codegen
|
|
-------------------------------------------------*/
|
|
|
|
void drccache_request_oob_codegen(drccache *cache, drccache_oob_func callback, void *param1, void *param2, void *param3)
|
|
{
|
|
oob_handler *oob;
|
|
|
|
assert(cache->codegen != NULL);
|
|
|
|
/* pull an item from the free list */
|
|
oob = (oob_handler *)drccache_memory_alloc(cache, sizeof(*oob));
|
|
assert(oob != NULL);
|
|
|
|
/* fill it in */
|
|
oob->next = NULL;
|
|
oob->callback = callback;
|
|
oob->param1 = param1;
|
|
oob->param2 = param2;
|
|
oob->param3 = param3;
|
|
|
|
/* add to the tail */
|
|
*cache->oobtail = oob;
|
|
cache->oobtail = &oob->next;
|
|
}
|