summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/cpu/drccache.c
diff options
context:
space:
mode:
author Aaron Giles <aaron@aarongiles.com>2011-01-05 16:33:00 +0000
committer Aaron Giles <aaron@aarongiles.com>2011-01-05 16:33:00 +0000
commitc12dd417cdd53a2fde51879cebf681b9fcecf97c (patch)
treea6776f6130eabda2f8e46d639a3891c46b731f6f /src/emu/cpu/drccache.c
parent7c15acffe225d87bd3387bc94c5a6a50d3215c43 (diff)
Convert drccache to C++
Diffstat (limited to 'src/emu/cpu/drccache.c')
-rw-r--r--src/emu/cpu/drccache.c465
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);
}