diff options
Diffstat (limited to 'src/emu/cpu/drccache.c')
-rw-r--r-- | src/emu/cpu/drccache.c | 465 |
1 files changed, 165 insertions, 300 deletions
diff --git a/src/emu/cpu/drccache.c b/src/emu/cpu/drccache.c index fbb424b15ed..462ab48ff5d 100644 --- a/src/emu/cpu/drccache.c +++ b/src/emu/cpu/drccache.c @@ -1,12 +1,39 @@ /*************************************************************************** - drccache.h + drccache.c 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. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name 'MAME' nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. ***************************************************************************/ @@ -15,403 +42,241 @@ -/*************************************************************************** - 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 -***************************************************************************/ +//************************************************************************** +// MACROS +//************************************************************************** -/* ensure that all memory allocated is aligned to an 8-byte boundary */ +// 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); -} - +//************************************************************************** +// DRC CACHE +//************************************************************************** -/*------------------------------------------------- - drccache_contains_near_pointer - return true - if a pointer is within the cache --------------------------------------------------*/ +//------------------------------------------------- +// drc_cache - constructor +//------------------------------------------------- -int drccache_contains_near_pointer(drccache *cache, const void *ptr) +drc_cache::drc_cache(size_t bytes) + : m_near((drccodeptr)osd_alloc_executable(bytes)), + m_neartop(m_near), + m_base(m_near + NEAR_CACHE_SIZE), + m_top(m_base), + m_end(m_near + bytes), + m_codegen(0), + m_size(bytes) { - return ((const drccodeptr)ptr >= cache->near && (const drccodeptr)ptr < cache->neartop); + memset(m_free, 0, sizeof(m_free)); + memset(m_nearfree, 0, sizeof(m_nearfree)); } -/*------------------------------------------------- - drccache_near - return a pointer to the near - part of the cache --------------------------------------------------*/ +//------------------------------------------------- +// ~drc_cache - destructor +//------------------------------------------------- -drccodeptr drccache_near(drccache *cache) +drc_cache::~drc_cache() { - return cache->near; + // release the memory + osd_free_executable(m_near, m_size); } -/*------------------------------------------------- - drccache_base - return a pointer to the base - of the cache --------------------------------------------------*/ - -drccodeptr drccache_base(drccache *cache) -{ - return cache->base; -} +//------------------------------------------------- +// flush - flush the cache contents +//------------------------------------------------- -/*------------------------------------------------- - drccache_top - return the current top of the - cache --------------------------------------------------*/ - -drccodeptr drccache_top(drccache *cache) +void drc_cache::flush() { - return cache->top; -} - + // can't flush in the middle of codegen + assert(m_codegen == NULL); - -/*************************************************************************** - 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; + // just reset the top back to the base and re-seed + m_top = m_base; } -/*------------------------------------------------- - drccache_memory_alloc - allocate permanent - memory from the cache --------------------------------------------------*/ +//------------------------------------------------- +// alloc - allocate permanent memory from the +// cache +//------------------------------------------------- -void *drccache_memory_alloc(drccache *cache, size_t bytes) +void *drc_cache::alloc(size_t bytes) { - drccodeptr ptr; - assert(bytes > 0); - /* pick first from the free list */ + // pick first from the free list if (bytes < MAX_PERMANENT_ALLOC) { - free_link **linkptr = &cache->free[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT]; + free_link **linkptr = &m_free[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT]; free_link *link = *linkptr; if (link != NULL) { - *linkptr = link->next; + *linkptr = link->m_next; return link; } } - /* if no space, we just fail */ - ptr = (drccodeptr)ALIGN_PTR_DOWN(cache->end - bytes); - if (cache->top > ptr) + // if no space, we just fail + drccodeptr ptr = (drccodeptr)ALIGN_PTR_DOWN(m_end - bytes); + if (m_top > ptr) return NULL; - /* otherwise update the end of the cache */ - cache->end = ptr; + // otherwise update the end of the cache + m_end = ptr; return ptr; } -/*------------------------------------------------- - drccache_memory_alloc_near - allocate - permanent memory from the near part of the - cache --------------------------------------------------*/ +//------------------------------------------------- +// alloc_near - allocate permanent memory from +// the near part of the cache +//------------------------------------------------- -void *drccache_memory_alloc_near(drccache *cache, size_t bytes) +void *drc_cache::alloc_near(size_t bytes) { - drccodeptr ptr; - assert(bytes > 0); - /* pick first from the free list */ + // pick first from the free list if (bytes < MAX_PERMANENT_ALLOC) { - free_link **linkptr = &cache->nearfree[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT]; + free_link **linkptr = &m_nearfree[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT]; free_link *link = *linkptr; if (link != NULL) { - *linkptr = link->next; + *linkptr = link->m_next; return link; } } - /* if no space, we just fail */ - ptr = (drccodeptr)ALIGN_PTR_UP(cache->neartop); - if (ptr + bytes > cache->base) + // if no space, we just fail + drccodeptr ptr = (drccodeptr)ALIGN_PTR_UP(m_neartop); + if (ptr + bytes > m_base) return NULL; - /* otherwise update the top of the near part of the cache */ - cache->neartop = ptr + bytes; + // otherwise update the top of the near part of the cache + m_neartop = ptr + bytes; return ptr; } -/*------------------------------------------------- - drccache_memory_free - release permanent - memory allocated from the cache --------------------------------------------------*/ +//------------------------------------------------- +// alloc_temporary - allocate temporary memory +// from the cache +//------------------------------------------------- -void drccache_memory_free(drccache *cache, void *memory, size_t bytes) +void *drc_cache::alloc_temporary(size_t bytes) { - free_link **linkptr; - free_link *link = (free_link *)memory; + // can't allocate in the middle of codegen + assert(m_codegen == NULL); - 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]; + // if no space, we just fail + drccodeptr ptr = m_top; + if (ptr + bytes >= m_end) + return NULL; - /* link is into the free list for our size */ - link->next = *linkptr; - *linkptr = link; + // otherwise, update the cache top + m_top = (drccodeptr)ALIGN_PTR_UP(ptr + bytes); + return ptr; } -/*------------------------------------------------- - drccache_memory_alloc_temporary - allocate - temporary memory from the cache --------------------------------------------------*/ +//------------------------------------------------- +// free - release permanent memory allocated from +// the cache +//------------------------------------------------- -void *drccache_memory_alloc_temporary(drccache *cache, size_t bytes) +void drc_cache::dealloc(void *memory, size_t bytes) { - drccodeptr ptr = cache->top; - - /* can't allocate in the middle of codegen */ - assert(cache->codegen == NULL); + assert(bytes < MAX_PERMANENT_ALLOC); + assert(((drccodeptr)memory >= m_near && (drccodeptr)memory < m_base) || ((drccodeptr)memory >= m_end && (drccodeptr)memory < m_near + m_size)); - /* if no space, we just fail */ - if (ptr + bytes >= cache->end) - return NULL; + // determine which free list to add to + free_link **linkptr; + if ((drccodeptr)memory < m_base) + linkptr = &m_nearfree[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT]; + else + linkptr = &m_free[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT]; - /* otherwise, update the cache top */ - cache->top = (drccodeptr)ALIGN_PTR_UP(ptr + bytes); - return ptr; + // link is into the free list for our size + free_link *link = (free_link *)memory; + link->m_next = *linkptr; + *linkptr = link; } +//------------------------------------------------- +// begin_codegen - begin code generation +//------------------------------------------------- -/*************************************************************************** - CODE GENERATION -***************************************************************************/ - -/*------------------------------------------------- - drccache_begin_codegen - begin code - generation --------------------------------------------------*/ - -drccodeptr *drccache_begin_codegen(drccache *cache, UINT32 reserve_bytes) +drccodeptr *drc_cache::begin_codegen(UINT32 reserve_bytes) { - drccodeptr ptr = cache->top; + // can't restart in the middle of codegen + assert(m_codegen == NULL); + assert(m_ooblist == NULL); - /* 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) + // if still no space, we just fail + drccodeptr ptr = m_top; + if (ptr + reserve_bytes >= m_end) return NULL; - /* otherwise, return a pointer to the cache top */ - cache->codegen = cache->top; - cache->oobtail = &cache->ooblist; - return &cache->top; + // otherwise, return a pointer to the cache top + m_codegen = m_top; + return &m_top; } -/*------------------------------------------------- - drccache_end_codegen - complete code - generation --------------------------------------------------*/ +//------------------------------------------------- +// end_codegen - complete code generation +//------------------------------------------------- -drccodeptr drccache_end_codegen(drccache *cache) +drccodeptr drc_cache::end_codegen() { - drccodeptr result = cache->codegen; + drccodeptr result = m_codegen; - /* run the OOB handlers */ - while (cache->ooblist != NULL) + // run the OOB handlers + oob_handler *oob; + while ((oob = m_ooblist.detach_head()) != 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); + // call the callback + (*oob->m_callback)(&m_top, oob->m_param1, oob->m_param2, oob->m_param3); + assert(m_top - m_codegen < CODEGEN_MAX_BYTES); - /* release our memory */ - drccache_memory_free(cache, oob, sizeof(*oob)); + // release our memory + dealloc(oob, sizeof(*oob)); } - /* update the cache top */ - cache->top = (drccodeptr)ALIGN_PTR_UP(cache->top); - cache->codegen = NULL; + // update the cache top + m_top = (drccodeptr)ALIGN_PTR_UP(m_top); + m_codegen = NULL; return result; } -/*------------------------------------------------- - drccache_request_oob_codegen - request - callback for out-of-band codegen --------------------------------------------------*/ +//------------------------------------------------- +// 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) +void drc_cache::request_oob_codegen(oob_func callback, void *param1, void *param2, void *param3) { - oob_handler *oob; - - assert(cache->codegen != NULL); + assert(m_codegen != NULL); - /* pull an item from the free list */ - oob = (oob_handler *)drccache_memory_alloc(cache, sizeof(*oob)); + // pull an item from the free list + oob_handler *oob = (oob_handler *)alloc(sizeof(*oob)); assert(oob != NULL); - /* fill it in */ - oob->next = NULL; - oob->callback = callback; - oob->param1 = param1; - oob->param2 = param2; - oob->param3 = param3; + // fill it in + oob->m_callback = callback; + oob->m_param1 = param1; + oob->m_param2 = param2; + oob->m_param3 = param3; - /* add to the tail */ - *cache->oobtail = oob; - cache->oobtail = &oob->next; + // add to the tail + m_ooblist.append(*oob); } |