C++-ified drcfe and the associated frontends. You now create a

frontend by deriving from drc_frontend and implementing the
describe method.

RB, if you send me your latest SH4 WIP, I'll convert it for you
if this makes you cranky. :)
This commit is contained in:
Aaron Giles 2011-01-04 15:54:16 +00:00
parent 68ebcf0254
commit 9e5207ce91
14 changed files with 2422 additions and 2379 deletions

View File

@ -4,9 +4,36 @@
Generic dynamic recompiler frontend structures and utilities.
****************************************************************************
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.
****************************************************************************
@ -21,219 +48,120 @@
#include "drcfe.h"
/***************************************************************************
CONSTANTS
***************************************************************************/
//**************************************************************************
// CONSTANTS
//**************************************************************************
#define MAX_STACK_DEPTH 100
const UINT32 MAX_STACK_DEPTH = 100;
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
/* an entry that maps branches for our code walking */
typedef struct _pc_stack_entry pc_stack_entry;
struct _pc_stack_entry
// an entry that maps branches for our code walking
struct pc_stack_entry
{
offs_t targetpc;
offs_t srcpc;
};
/* internal state */
struct _drcfe_state
//**************************************************************************
// DRC FRONTEND
//**************************************************************************
//-------------------------------------------------
// drc_frontend - constructor
//-------------------------------------------------
drc_frontend::drc_frontend(device_t &cpu, UINT32 window_start, UINT32 window_end, UINT32 max_sequence)
: m_window_start(window_start),
m_window_end(window_end),
m_max_sequence(max_sequence),
m_cpudevice(downcast<cpu_device &>(cpu)),
m_program(m_cpudevice.space(AS_PROGRAM)),
m_pageshift(m_cpudevice.space_config(AS_PROGRAM)->m_page_shift),
m_desc_live_list(cpu.machine->m_respool),
m_desc_allocator(cpu.machine->m_respool),
m_desc_array(auto_alloc_array_clear(cpu.machine, opcode_desc *, window_end + window_start + 2))
{
/* configuration parameters */
UINT32 window_start; /* code window start offset = startpc - window_start */
UINT32 window_end; /* code window end offset = startpc + window_end */
UINT32 max_sequence; /* maximum instructions to include in a sequence */
drcfe_describe_func describe; /* callback to describe a single instruction */
void * param; /* parameter for the callback */
/* CPU parameters */
cpu_device * cpudevice; /* CPU device object */
address_space *program; /* program address space for this CPU */
offs_t pageshift; /* shift to convert address to a page index */
/* opcode descriptor arrays */
opcode_desc * desc_live_list; /* head of list of live descriptions */
opcode_desc * desc_free_list; /* head of list of free descriptions */
opcode_desc ** desc_array; /* array of descriptions in PC order */
UINT32 desc_array_size; /* size of the array */
};
/***************************************************************************
FUNCTION PROTOTYPES
***************************************************************************/
static opcode_desc *describe_one(drcfe_state *drcfe, offs_t curpc, const opcode_desc *prevdesc);
static opcode_desc **build_sequence(drcfe_state *drcfe, opcode_desc **tailptr, int start, int end, UINT32 endflag);
static void accumulate_required_backwards(opcode_desc *desc, UINT32 *reqmask);
static void release_descriptions(drcfe_state *drcfe, opcode_desc *desc);
/***************************************************************************
INLINE FUNCTIONS
***************************************************************************/
/*-------------------------------------------------
desc_alloc - allocate a new opcode description
-------------------------------------------------*/
INLINE opcode_desc *desc_alloc(drcfe_state *drcfe)
{
opcode_desc *desc = drcfe->desc_free_list;
/* pull a description off of the free list or allocate a new one */
if (desc != NULL)
drcfe->desc_free_list = desc->next;
else
desc = auto_alloc(drcfe->cpudevice->machine, opcode_desc);
return desc;
}
/*-------------------------------------------------
desc_free - free an opcode description
-------------------------------------------------*/
//-------------------------------------------------
// ~drc_frontend - destructor
//-------------------------------------------------
INLINE void desc_free(drcfe_state *drcfe, opcode_desc *desc)
drc_frontend::~drc_frontend()
{
/* just put ourselves on the free list */
desc->next = drcfe->desc_free_list;
drcfe->desc_free_list = desc;
// release any descriptions we've accumulated
release_descriptions();
// free the description array
auto_free(m_cpudevice.machine, m_desc_array);
}
//-------------------------------------------------
// describe_code - describe a sequence of code
// that falls within the configured window
// relative to the specified startpc
//-------------------------------------------------
/***************************************************************************
CORE IMPLEMENTATION
***************************************************************************/
/*-------------------------------------------------
drcfe_init - initializate the drcfe state
-------------------------------------------------*/
drcfe_state *drcfe_init(device_t *cpu, const drcfe_config *config, void *param)
const opcode_desc *drc_frontend::describe_code(offs_t startpc)
{
drcfe_state *drcfe;
// release any descriptions we've accumulated
release_descriptions();
/* allocate some memory to hold the state */
drcfe = auto_alloc_clear(cpu->machine, drcfe_state);
/* allocate the description array */
drcfe->desc_array = auto_alloc_array_clear(cpu->machine, opcode_desc *, config->window_end + config->window_start + 2);
/* copy in configuration information */
drcfe->window_start = config->window_start;
drcfe->window_end = config->window_end;
drcfe->max_sequence = config->max_sequence;
drcfe->describe = config->describe;
drcfe->param = param;
/* initialize the state */
drcfe->cpudevice = downcast<cpu_device *>(cpu);
drcfe->program = drcfe->cpudevice->space(AS_PROGRAM);
drcfe->pageshift = drcfe->cpudevice->space_config(AS_PROGRAM)->m_page_shift;
return drcfe;
}
/*-------------------------------------------------
drcfe_exit - clean up after ourselves
-------------------------------------------------*/
void drcfe_exit(drcfe_state *drcfe)
{
/* release any descriptions we've accumulated */
release_descriptions(drcfe, drcfe->desc_live_list);
/* free our free list of descriptions */
while (drcfe->desc_free_list != NULL)
{
opcode_desc *freeme = drcfe->desc_free_list;
drcfe->desc_free_list = drcfe->desc_free_list->next;
auto_free(drcfe->cpudevice->machine, freeme);
}
/* free the description array */
auto_free(drcfe->cpudevice->machine, drcfe->desc_array);
/* free the object itself */
auto_free(drcfe->cpudevice->machine, drcfe);
}
/*-------------------------------------------------
drcfe_describe_code - describe a sequence of
code that falls within the configured window
relative to the specified startpc
-------------------------------------------------*/
const opcode_desc *drcfe_describe_code(drcfe_state *drcfe, offs_t startpc)
{
offs_t minpc = startpc - MIN(drcfe->window_start, startpc);
offs_t maxpc = startpc + MIN(drcfe->window_end, 0xffffffff - startpc);
// add the initial PC to the stack
pc_stack_entry pcstack[MAX_STACK_DEPTH];
pc_stack_entry *pcstackptr = &pcstack[0];
opcode_desc **tailptr;
/* release any descriptions we've accumulated */
release_descriptions(drcfe, drcfe->desc_live_list);
drcfe->desc_live_list = NULL;
/* add the initial PC to the stack */
pcstackptr->srcpc = 0;
pcstackptr->targetpc = startpc;
pcstackptr++;
/* loop while we still have a stack */
// loop while we still have a stack
offs_t minpc = startpc - MIN(m_window_start, startpc);
offs_t maxpc = startpc + MIN(m_window_end, 0xffffffff - startpc);
while (pcstackptr != &pcstack[0])
{
// if we've already hit this PC, just mark it a branch target and continue
pc_stack_entry *curstack = --pcstackptr;
opcode_desc *curdesc;
offs_t curpc;
/* if we've already hit this PC, just mark it a branch target and continue */
curdesc = drcfe->desc_array[curstack->targetpc - minpc];
opcode_desc *curdesc = m_desc_array[curstack->targetpc - minpc];
if (curdesc != NULL)
{
curdesc->flags |= OPFLAG_IS_BRANCH_TARGET;
/* if the branch crosses a page boundary, mark the target as needing to revalidate */
if (drcfe->pageshift != 0 && ((curstack->srcpc ^ curdesc->pc) >> drcfe->pageshift) != 0)
// if the branch crosses a page boundary, mark the target as needing to revalidate
if (m_pageshift != 0 && ((curstack->srcpc ^ curdesc->pc) >> m_pageshift) != 0)
curdesc->flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION;
/* continue processing */
// continue processing
continue;
}
/* loop until we exit the block */
for (curpc = curstack->targetpc; curpc >= minpc && curpc < maxpc && drcfe->desc_array[curpc - minpc] == NULL; curpc += drcfe->desc_array[curpc - minpc]->length)
// loop until we exit the block
for (offs_t curpc = curstack->targetpc; curpc >= minpc && curpc < maxpc && m_desc_array[curpc - minpc] == NULL; curpc += m_desc_array[curpc - minpc]->length)
{
/* allocate a new description and describe this instruction */
drcfe->desc_array[curpc - minpc] = curdesc = describe_one(drcfe, curpc, curdesc);
// allocate a new description and describe this instruction
m_desc_array[curpc - minpc] = curdesc = describe_one(curpc, curdesc);
/* first instruction in a sequence is always a branch target */
// first instruction in a sequence is always a branch target
if (curpc == curstack->targetpc)
curdesc->flags |= OPFLAG_IS_BRANCH_TARGET;
/* stop if we hit a page fault */
// stop if we hit a page fault
if (curdesc->flags & OPFLAG_COMPILER_PAGE_FAULT)
break;
/* if we are the first instruction in the whole window, we must validate the TLB */
if (curpc == startpc && drcfe->pageshift != 0)
// if we are the first instruction in the whole window, we must validate the TLB
if (curpc == startpc && m_pageshift != 0)
curdesc->flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION;
/* if we are a branch within the block range, add the branch target to our stack */
// if we are a branch within the block range, add the branch target to our stack
if ((curdesc->flags & OPFLAG_IS_BRANCH) && curdesc->targetpc >= minpc && curdesc->targetpc < maxpc && pcstackptr < &pcstack[MAX_STACK_DEPTH])
{
curdesc->flags |= OPFLAG_INTRABLOCK_BRANCH;
@ -242,131 +170,113 @@ const opcode_desc *drcfe_describe_code(drcfe_state *drcfe, offs_t startpc)
pcstackptr++;
}
/* if we're done, we're done */
// if we're done, we're done
if (curdesc->flags & OPFLAG_END_SEQUENCE)
break;
}
}
/* now build the list of descriptions in order */
/* first from startpc -> maxpc, then from minpc -> startpc */
tailptr = build_sequence(drcfe, &drcfe->desc_live_list, startpc - minpc, maxpc - minpc, OPFLAG_REDISPATCH);
tailptr = build_sequence(drcfe, tailptr, minpc - minpc, startpc - minpc, OPFLAG_RETURN_TO_START);
return drcfe->desc_live_list;
// now build the list of descriptions in order
// first from startpc -> maxpc, then from minpc -> startpc
build_sequence(startpc - minpc, maxpc - minpc, OPFLAG_REDISPATCH);
build_sequence(minpc - minpc, startpc - minpc, OPFLAG_RETURN_TO_START);
return m_desc_live_list.first();
}
//-------------------------------------------------
// describe_one - describe a single instruction,
// recursively describing opcodes in delay
// slots of branches as well
//-------------------------------------------------
/***************************************************************************
INTERNAL HELPERS
***************************************************************************/
/*-------------------------------------------------
describe_one - describe a single instruction,
recursively describing opcodes in delay
slots of branches as well
-------------------------------------------------*/
static opcode_desc *describe_one(drcfe_state *drcfe, offs_t curpc, const opcode_desc *prevdesc)
opcode_desc *drc_frontend::describe_one(offs_t curpc, const opcode_desc *prevdesc)
{
opcode_desc *desc = desc_alloc(drcfe);
/* initialize the description */
// initialize the description
opcode_desc *desc = m_desc_allocator.alloc();
memset(desc, 0, sizeof(*desc));
desc->pc = curpc;
desc->physpc = curpc;
desc->targetpc = BRANCH_TARGET_DYNAMIC;
/* call the callback to describe an instruction */
if (!(*drcfe->describe)(drcfe->param, desc, prevdesc))
// call the callback to describe an instruction
if (!describe(*desc, prevdesc))
{
desc->flags |= OPFLAG_WILL_CAUSE_EXCEPTION | OPFLAG_INVALID_OPCODE;
return desc;
}
/* validate the TLB if we are exactly at the start of a page, or if we cross a page boundary */
if (drcfe->pageshift != 0 && (((curpc - 1) ^ (curpc + desc->length - 1)) >> drcfe->pageshift) != 0)
// validate the TLB if we are exactly at the start of a page, or if we cross a page boundary
if (m_pageshift != 0 && (((curpc - 1) ^ (curpc + desc->length - 1)) >> m_pageshift) != 0)
desc->flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION;
/* validate stuff */
// validate stuff
assert(desc->length > 0 || (desc->flags & OPFLAG_VIRTUAL_NOOP) != 0);
/* if we are a branch with delay slots, recursively walk those */
// if we are a branch with delay slots, recursively walk those
if (desc->flags & OPFLAG_IS_BRANCH)
{
opcode_desc **tailptr = &desc->delay;
// iterate over slots and describe them
offs_t delaypc = curpc + desc->length;
opcode_desc *prev = desc;
UINT8 slotnum;
/* iterate over slots and describe them */
for (slotnum = 0; slotnum < desc->delayslots; slotnum++)
for (UINT8 slotnum = 0; slotnum < desc->delayslots; slotnum++)
{
/* recursively describe the next instruction */
*tailptr = describe_one(drcfe, delaypc, prev);
if (*tailptr == NULL)
// recursively describe the next instruction
opcode_desc *delaydesc = describe_one(delaypc, prev);
if (delaydesc == NULL)
break;
desc->delay.append(*delaydesc);
prev = desc;
// set the delay slot flag and a pointer back to the original branch
delaydesc->flags |= OPFLAG_IN_DELAY_SLOT;
delaydesc->branch = desc;
// stop if we hit a page fault
if (delaydesc->flags & OPFLAG_COMPILER_PAGE_FAULT)
break;
/* set the delay slot flag and a pointer back to the original branch */
(*tailptr)->flags |= OPFLAG_IN_DELAY_SLOT;
(*tailptr)->branch = desc;
(*tailptr)->prev = prev;
prev = *tailptr;
/* stop if we hit a page fault */
if ((*tailptr)->flags & OPFLAG_COMPILER_PAGE_FAULT)
break;
/* otherwise, advance */
delaypc += (*tailptr)->length;
tailptr = &(*tailptr)->next;
// otherwise, advance
delaypc += delaydesc->length;
}
}
return desc;
}
/*-------------------------------------------------
build_sequence - build an ordered sequence
of instructions
-------------------------------------------------*/
//-------------------------------------------------
// build_sequence - build an ordered sequence
// of instructions
//-------------------------------------------------
static opcode_desc **build_sequence(drcfe_state *drcfe, opcode_desc **tailptr, int start, int end, UINT32 endflag)
void drc_frontend::build_sequence(int start, int end, UINT32 endflag)
{
opcode_desc *prev = NULL;
// iterate in order from start to end, picking up all non-NULL instructions
int consecutive = 0;
int seqstart = -1;
int skipsleft = 0;
int descnum;
/* iterate in order from start to end, picking up all non-NULL instructions */
for (descnum = start; descnum < end; descnum++)
if (drcfe->desc_array[descnum] != NULL)
for (int descnum = start; descnum < end; descnum++)
if (m_desc_array[descnum] != NULL)
{
opcode_desc *curdesc = drcfe->desc_array[descnum];
opcode_desc *nextdesc = NULL;
int nextdescnum;
UINT8 skipnum;
/* determine the next instruction, taking skips into account */
nextdescnum = descnum + curdesc->length;
nextdesc = (nextdescnum < end) ? drcfe->desc_array[nextdescnum] : NULL;
for (skipnum = 0; skipnum < curdesc->skipslots && nextdesc != NULL; skipnum++)
// determine the next instruction, taking skips into account
opcode_desc *curdesc = m_desc_array[descnum];
int nextdescnum = descnum + curdesc->length;
opcode_desc *nextdesc = (nextdescnum < end) ? m_desc_array[nextdescnum] : NULL;
for (UINT8 skipnum = 0; skipnum < curdesc->skipslots && nextdesc != NULL; skipnum++)
{
nextdescnum = nextdescnum + nextdesc->length;
nextdesc = (nextdescnum < end) ? drcfe->desc_array[nextdescnum] : NULL;
nextdesc = (nextdescnum < end) ? m_desc_array[nextdescnum] : NULL;
}
/* start a new sequence if we aren't already in the middle of one */
// start a new sequence if we aren't already in the middle of one
if (seqstart == -1 && skipsleft == 0)
{
/* tag all start-of-sequence instructions as needing TLB verification */
// tag all start-of-sequence instructions as needing TLB verification
curdesc->flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION;
seqstart = descnum;
}
/* if we are the last instruction, indicate end-of-sequence and redispatch */
// if we are the last instruction, indicate end-of-sequence and redispatch
if (nextdesc == NULL)
{
curdesc->flags |= OPFLAG_END_SEQUENCE;
@ -374,134 +284,118 @@ static opcode_desc **build_sequence(drcfe_state *drcfe, opcode_desc **tailptr, i
curdesc->flags |= endflag;
}
/* otherwise, do some analysis based on the next instruction */
// otherwise, do some analysis based on the next instruction
else
{
opcode_desc *scandesc = NULL;
// if there are instructions between us and the next instruction, we must end our sequence here
int scandescnum;
/* if there are instructions between us and the next instruction, we must end our sequence here */
opcode_desc *scandesc = NULL;
for (scandescnum = descnum + 1; scandescnum < end; scandescnum++)
{
scandesc = drcfe->desc_array[scandescnum];
scandesc = m_desc_array[scandescnum];
if (scandesc != NULL || scandesc == nextdesc)
break;
}
if (scandesc != nextdesc)
curdesc->flags |= OPFLAG_END_SEQUENCE;
/* if the next instruction is a branch target, mark this instruction as end of sequence */
// if the next instruction is a branch target, mark this instruction as end of sequence
if (nextdesc->flags & OPFLAG_IS_BRANCH_TARGET)
curdesc->flags |= OPFLAG_END_SEQUENCE;
}
/* if we exceed the maximum consecutive count, cut off the sequence */
if (++consecutive >= drcfe->max_sequence)
// if we exceed the maximum consecutive count, cut off the sequence
if (++consecutive >= m_max_sequence)
curdesc->flags |= OPFLAG_END_SEQUENCE;
if (curdesc->flags & OPFLAG_END_SEQUENCE)
consecutive = 0;
/* if this is the end of a sequence, work backwards */
// if this is the end of a sequence, work backwards
if (curdesc->flags & OPFLAG_END_SEQUENCE)
{
// figure out which registers we *must* generate, assuming at the end all must be
UINT32 reqmask[4] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff };
int backdesc;
/* figure out which registers we *must* generate, assuming at the end all must be */
if (seqstart != -1)
for (backdesc = descnum; backdesc != seqstart - 1; backdesc--)
if (drcfe->desc_array[backdesc] != NULL)
accumulate_required_backwards(drcfe->desc_array[backdesc], reqmask);
for (int backdesc = descnum; backdesc != seqstart - 1; backdesc--)
if (m_desc_array[backdesc] != NULL)
accumulate_required_backwards(*m_desc_array[backdesc], reqmask);
/* reset the register states */
// reset the register states
seqstart = -1;
}
/* if we have instructions remaining to be skipped, and this instruction is a branch target */
/* belay the skip order */
// if we have instructions remaining to be skipped, and this instruction is a branch target
// belay the skip order
if (skipsleft > 0 && (curdesc->flags & OPFLAG_IS_BRANCH_TARGET))
skipsleft = 0;
/* if we're not getting skipped, add us to the end of the list and clear our array slot */
// if we're not getting skipped, add us to the end of the list and clear our array slot
if (skipsleft == 0)
{
*tailptr = curdesc;
tailptr = &curdesc->next;
curdesc->prev = prev;
prev = curdesc;
}
m_desc_live_list.append(*curdesc);
else
desc_free(drcfe, curdesc);
m_desc_allocator.reclaim(*curdesc);
/* if the current instruction starts skipping, reset our skip count */
/* otherwise, just decrement */
// if the current instruction starts skipping, reset our skip count
// otherwise, just decrement
if (curdesc->skipslots > 0)
skipsleft = curdesc->skipslots;
else if (skipsleft > 0)
skipsleft--;
}
/* zap the array */
memset(&drcfe->desc_array[start], 0, (end - start) * sizeof(drcfe->desc_array[0]));
/* return the final tailptr */
return tailptr;
// zap the array
memset(&m_desc_array[start], 0, (end - start) * sizeof(m_desc_array[0]));
}
/*-------------------------------------------------
accumulate_required_backwards - recursively
accumulate live register liveness information
walking in a backwards direction
-------------------------------------------------*/
//-------------------------------------------------
// accumulate_required_backwards - recursively
// accumulate live register liveness information
// walking in a backwards direction
//-------------------------------------------------
static void accumulate_required_backwards(opcode_desc *desc, UINT32 *reqmask)
void drc_frontend::accumulate_required_backwards(opcode_desc &desc, UINT32 *reqmask)
{
/* recursively handle delay slots */
if (desc->delay != NULL)
accumulate_required_backwards(desc->delay, reqmask);
// recursively handle delay slots
if (desc.delay.first() != NULL)
accumulate_required_backwards(*desc.delay.first(), reqmask);
/* if this is a branch, we have to reset our requests */
if (desc->flags & OPFLAG_IS_BRANCH)
// if this is a branch, we have to reset our requests
if (desc.flags & OPFLAG_IS_BRANCH)
reqmask[0] = reqmask[1] = reqmask[2] = reqmask[3] = 0xffffffff;
/* determine the required registers */
desc->regreq[0] = desc->regout[0] & reqmask[0];
desc->regreq[1] = desc->regout[1] & reqmask[1];
desc->regreq[2] = desc->regout[2] & reqmask[2];
desc->regreq[3] = desc->regout[3] & reqmask[3];
// determine the required registers
desc.regreq[0] = desc.regout[0] & reqmask[0];
desc.regreq[1] = desc.regout[1] & reqmask[1];
desc.regreq[2] = desc.regout[2] & reqmask[2];
desc.regreq[3] = desc.regout[3] & reqmask[3];
/* any registers modified by this instruction aren't required upstream until referenced */
reqmask[0] &= ~desc->regout[0];
reqmask[1] &= ~desc->regout[1];
reqmask[2] &= ~desc->regout[2];
reqmask[3] &= ~desc->regout[3];
// any registers modified by this instruction aren't required upstream until referenced
reqmask[0] &= ~desc.regout[0];
reqmask[1] &= ~desc.regout[1];
reqmask[2] &= ~desc.regout[2];
reqmask[3] &= ~desc.regout[3];
/* any registers required by this instruction now get marked required */
reqmask[0] |= desc->regin[0];
reqmask[1] |= desc->regin[1];
reqmask[2] |= desc->regin[2];
reqmask[3] |= desc->regin[3];
// any registers required by this instruction now get marked required
reqmask[0] |= desc.regin[0];
reqmask[1] |= desc.regin[1];
reqmask[2] |= desc.regin[2];
reqmask[3] |= desc.regin[3];
}
/*-------------------------------------------------
release_descriptions - release any
descriptions we've allocated back to the
free list
------------------------------------------------*/
//-------------------------------------------------
// release_descriptions - release any
// descriptions we've allocated back to the
// free list
//------------------------------------------------
static void release_descriptions(drcfe_state *drcfe, opcode_desc *desc)
void drc_frontend::release_descriptions()
{
/* loop while we still have valid entries */
while (desc != NULL)
{
opcode_desc *freeme = desc;
// release all delay slots first
for (opcode_desc *curdesc = m_desc_live_list.first(); curdesc != NULL; curdesc = curdesc->next())
m_desc_allocator.reclaim_all(curdesc->delay);
/* recursively release delay slots */
if (desc->delay != NULL)
release_descriptions(drcfe, desc->delay);
desc = desc->next;
desc_free(drcfe, freeme);
}
// reclaim all the descriptors
m_desc_allocator.reclaim_all(m_desc_live_list);
}

View File

@ -4,9 +4,36 @@
Generic dynamic recompiler frontend structures and utilities.
****************************************************************************
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.
****************************************************************************
@ -37,125 +64,130 @@
#define __DRCFE_H__
/***************************************************************************
CONSTANTS
***************************************************************************/
//**************************************************************************
// CONSTANTS
//**************************************************************************
/* this defines a branch targetpc that is dynamic at runtime */
#define BRANCH_TARGET_DYNAMIC (~0)
// this defines a branch targetpc that is dynamic at runtime
const offs_t BRANCH_TARGET_DYNAMIC = ~0;
/* opcode branch flags */
#define OPFLAG_IS_UNCONDITIONAL_BRANCH 0x00000001 /* instruction is unconditional branch */
#define OPFLAG_IS_CONDITIONAL_BRANCH 0x00000002 /* instruction is conditional branch */
#define OPFLAG_IS_BRANCH (OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_IS_CONDITIONAL_BRANCH)
#define OPFLAG_IS_BRANCH_TARGET 0x00000004 /* instruction is the target of a branch */
#define OPFLAG_IN_DELAY_SLOT 0x00000008 /* instruction is in the delay slot of a branch */
#define OPFLAG_INTRABLOCK_BRANCH 0x00000010 /* instruction branches within the block */
// opcode branch flags
const UINT32 OPFLAG_IS_UNCONDITIONAL_BRANCH = 0x00000001; // instruction is unconditional branch
const UINT32 OPFLAG_IS_CONDITIONAL_BRANCH = 0x00000002; // instruction is conditional branch
const UINT32 OPFLAG_IS_BRANCH = (OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_IS_CONDITIONAL_BRANCH);
const UINT32 OPFLAG_IS_BRANCH_TARGET = 0x00000004; // instruction is the target of a branch
const UINT32 OPFLAG_IN_DELAY_SLOT = 0x00000008; // instruction is in the delay slot of a branch
const UINT32 OPFLAG_INTRABLOCK_BRANCH = 0x00000010; // instruction branches within the block
/* opcode exception flags */
#define OPFLAG_CAN_TRIGGER_SW_INT 0x00000020 /* instruction can trigger a software interrupt */
#define OPFLAG_CAN_EXPOSE_EXTERNAL_INT 0x00000040 /* instruction can expose an external interrupt */
#define OPFLAG_CAN_CAUSE_EXCEPTION 0x00000080 /* instruction may generate exception */
#define OPFLAG_WILL_CAUSE_EXCEPTION 0x00000100 /* instruction will generate exception */
#define OPFLAG_PRIVILEGED 0x00000200 /* instruction is privileged */
// opcode exception flags
const UINT32 OPFLAG_CAN_TRIGGER_SW_INT = 0x00000020; // instruction can trigger a software interrupt
const UINT32 OPFLAG_CAN_EXPOSE_EXTERNAL_INT = 0x00000040; // instruction can expose an external interrupt
const UINT32 OPFLAG_CAN_CAUSE_EXCEPTION = 0x00000080; // instruction may generate exception
const UINT32 OPFLAG_WILL_CAUSE_EXCEPTION = 0x00000100; // instruction will generate exception
const UINT32 OPFLAG_PRIVILEGED = 0x00000200; // instruction is privileged
/* opcode virtual->physical translation flags */
#define OPFLAG_VALIDATE_TLB 0x00000400 /* instruction must validate TLB before execution */
#define OPFLAG_MODIFIES_TRANSLATION 0x00000800 /* instruction modifies the TLB */
#define OPFLAG_COMPILER_PAGE_FAULT 0x00001000 /* compiler hit a page fault when parsing */
#define OPFLAG_COMPILER_UNMAPPED 0x00002000 /* compiler hit unmapped memory when parsing */
// opcode virtual->physical translation flags
const UINT32 OPFLAG_VALIDATE_TLB = 0x00000400; // instruction must validate TLB before execution
const UINT32 OPFLAG_MODIFIES_TRANSLATION = 0x00000800; // instruction modifies the TLB
const UINT32 OPFLAG_COMPILER_PAGE_FAULT = 0x00001000; // compiler hit a page fault when parsing
const UINT32 OPFLAG_COMPILER_UNMAPPED = 0x00002000; // compiler hit unmapped memory when parsing
/* opcode flags */
#define OPFLAG_INVALID_OPCODE 0x00004000 /* instruction is invalid */
#define OPFLAG_VIRTUAL_NOOP 0x00008000 /* instruction is a virtual no-op */
// opcode flags
const UINT32 OPFLAG_INVALID_OPCODE = 0x00004000; // instruction is invalid
const UINT32 OPFLAG_VIRTUAL_NOOP = 0x00008000; // instruction is a virtual no-op
/* opcode sequence flow flags */
#define OPFLAG_REDISPATCH 0x00010000 /* instruction must redispatch after completion */
#define OPFLAG_RETURN_TO_START 0x00020000 /* instruction must jump back to the beginning after completion */
#define OPFLAG_END_SEQUENCE 0x00040000 /* this is the last instruction in a sequence */
#define OPFLAG_CAN_CHANGE_MODES 0x00080000 /* instruction can change modes */
// opcode sequence flow flags
const UINT32 OPFLAG_REDISPATCH = 0x00010000; // instruction must redispatch after completion
const UINT32 OPFLAG_RETURN_TO_START = 0x00020000; // instruction must jump back to the beginning after completion
const UINT32 OPFLAG_END_SEQUENCE = 0x00040000; // this is the last instruction in a sequence
const UINT32 OPFLAG_CAN_CHANGE_MODES = 0x00080000; // instruction can change modes
/* execution semantics */
#define OPFLAG_READS_MEMORY 0x00100000 /* instruction reads memory */
#define OPFLAG_WRITES_MEMORY 0x00200000 /* instruction writes memory */
// execution semantics
const UINT32 OPFLAG_READS_MEMORY = 0x00100000; // instruction reads memory
const UINT32 OPFLAG_WRITES_MEMORY = 0x00200000; // instruction writes memory
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
/* opaque internal state */
typedef struct _drcfe_state drcfe_state;
/* description of a given opcode */
typedef struct _opcode_desc opcode_desc;
struct _opcode_desc
// description of a given opcode
struct opcode_desc
{
/* links to other descriptions */
opcode_desc * next; /* pointer to next description */
opcode_desc * prev; /* pointer to previous description */
opcode_desc * branch; /* pointer back to branch description for delay slots */
opcode_desc * delay; /* pointer to delay slot description */
opcode_desc *next() const { return m_next; }
/* information about the current PC */
offs_t pc; /* PC of this opcode */
offs_t physpc; /* physical PC of this opcode */
offs_t targetpc; /* target PC if we are a branch, or BRANCH_TARGET_DYNAMIC */
// links to other descriptions
opcode_desc * m_next; // pointer to next description
opcode_desc * branch; // pointer back to branch description for delay slots
simple_list<opcode_desc> delay; // pointer to delay slot description
/* copy of up to 16 bytes of opcode */
// information about the current PC
offs_t pc; // PC of this opcode
offs_t physpc; // physical PC of this opcode
offs_t targetpc; // target PC if we are a branch, or BRANCH_TARGET_DYNAMIC
// copy of up to 16 bytes of opcode
union
{
UINT8 b[16];
UINT16 w[8];
UINT32 l[4];
UINT64 q[2];
} opptr; /* pointer to opcode memory */
} opptr; // pointer to opcode memory
/* information about this instruction's execution */
UINT8 length; /* length in bytes of this opcode */
UINT8 delayslots; /* number of delay slots (for branches) */
UINT8 skipslots; /* number of skip slots (for branches) */
UINT32 flags; /* OPFLAG_* opcode flags */
UINT32 cycles; /* number of cycles needed to execute */
// information about this instruction's execution
UINT8 length; // length in bytes of this opcode
UINT8 delayslots; // number of delay slots (for branches)
UINT8 skipslots; // number of skip slots (for branches)
UINT32 flags; // OPFLAG_* opcode flags
UINT32 cycles; // number of cycles needed to execute
/* register usage information */
UINT32 regin[4]; /* input registers */
UINT32 regout[4]; /* output registers */
UINT32 regreq[4]; /* required output registers */
// register usage information
UINT32 regin[4]; // input registers
UINT32 regout[4]; // output registers
UINT32 regreq[4]; // required output registers
};
/* callback function that is used to describe a single opcode */
typedef int (*drcfe_describe_func)(void *param, opcode_desc *desc, const opcode_desc *prev);
/* description of a given opcode */
typedef struct _drcfe_config drcfe_config;
struct _drcfe_config
// DRC frontend state
class drc_frontend
{
UINT32 window_start; /* code window start offset = startpc - window_start */
UINT32 window_end; /* code window end offset = startpc + window_end */
UINT32 max_sequence; /* maximum instructions to include in a sequence */
drcfe_describe_func describe; /* callback to describe a single instruction */
public:
// construction/destruction
drc_frontend(device_t &cpu, UINT32 window_start, UINT32 window_end, UINT32 max_sequence);
virtual ~drc_frontend();
// describe a block
const opcode_desc *describe_code(offs_t startpc);
protected:
// required overrides
virtual bool describe(opcode_desc &desc, const opcode_desc *prev) = 0;
private:
// internal helpers
opcode_desc *describe_one(offs_t curpc, const opcode_desc *prevdesc);
void build_sequence(int start, int end, UINT32 endflag);
void accumulate_required_backwards(opcode_desc &desc, UINT32 *reqmask);
void release_descriptions();
// configuration parameters
UINT32 m_window_start; // code window start offset = startpc - window_start
UINT32 m_window_end; // code window end offset = startpc + window_end
UINT32 m_max_sequence; // maximum instructions to include in a sequence
// CPU parameters
cpu_device & m_cpudevice; // CPU device object
address_space * m_program; // program address space for this CPU
offs_t m_pageshift; // shift to convert address to a page index
// opcode descriptor arrays
simple_list<opcode_desc> m_desc_live_list; // list of live descriptions
fixed_allocator<opcode_desc> m_desc_allocator; // fixed allocator for descriptions
opcode_desc ** m_desc_array; // array of descriptions in PC order
};
/***************************************************************************
FUNCTION PROTOTYPES
***************************************************************************/
/* initializate the drcfe state */
drcfe_state *drcfe_init(device_t *cpu, const drcfe_config *config, void *param);
/* clean up after ourselves */
void drcfe_exit(drcfe_state *drcfe);
/* describe a sequence of code that falls within the configured window relative to the specified startpc */
const opcode_desc *drcfe_describe_code(drcfe_state *drcfe, offs_t startpc);
#endif /* __DRCFE_H__ */

View File

@ -4,9 +4,36 @@
Universal machine language-based MIPS III/IV emulator.
****************************************************************************
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.
****************************************************************************
@ -159,7 +186,7 @@ struct _mips3imp_state
/* core state */
drccache * cache; /* pointer to the DRC code cache */
drcuml_state * drcuml; /* DRC UML generator state */
drcfe_state * drcfe; /* pointer to the DRC front-end state */
mips3_frontend * drcfe; /* pointer to the DRC front-end state */
UINT32 drcoptions; /* configurable DRC options */
/* internal stuff */
@ -360,13 +387,6 @@ INLINE void save_fast_iregs(mips3_state *mips3, drcuml_block *block)
static void mips3_init(mips3_flavor flavor, int bigendian, legacy_cpu_device *device, device_irq_callback irqcallback)
{
drcfe_config feconfig =
{
COMPILE_BACKWARDS_BYTES, /* code window start offset = startpc - window_start */
COMPILE_FORWARDS_BYTES, /* code window end offset = startpc + window_end */
COMPILE_MAX_SEQUENCE, /* maximum instructions to include in a sequence */
mips3fe_describe /* callback to describe a single instruction */
};
mips3_state *mips3;
drccache *cache;
drcbe_info beinfo;
@ -445,9 +465,7 @@ static void mips3_init(mips3_flavor flavor, int bigendian, legacy_cpu_device *de
drcuml_symbol_add(mips3->impstate->drcuml, &mips3->impstate->fpmode, sizeof(mips3->impstate->fpmode), "fpmode");
/* initialize the front-end helper */
if (SINGLE_INSTRUCTION_MODE)
feconfig.max_sequence = 1;
mips3->impstate->drcfe = drcfe_init(device, &feconfig, mips3);
mips3->impstate->drcfe = auto_alloc(device->machine, mips3_frontend(*mips3, COMPILE_BACKWARDS_BYTES, COMPILE_FORWARDS_BYTES, SINGLE_INSTRUCTION_MODE ? 1 : COMPILE_MAX_SEQUENCE));
/* allocate memory for cache-local state and initialize it */
memcpy(mips3->impstate->fpmode, fpmode_source, sizeof(fpmode_source));
@ -546,7 +564,7 @@ static CPU_EXIT( mips3 )
mips3com_exit(mips3);
/* clean up the DRC */
drcfe_exit(mips3->impstate->drcfe);
auto_free(device->machine, mips3->impstate->drcfe);
drcuml_free(mips3->impstate->drcuml);
drccache_free(mips3->impstate->cache);
}
@ -745,7 +763,7 @@ static void code_compile_block(mips3_state *mips3, UINT8 mode, offs_t pc)
g_profiler.start(PROFILER_DRC_COMPILE);
/* get a description of this sequence */
desclist = drcfe_describe_code(mips3->impstate->drcfe, pc);
desclist = mips3->impstate->drcfe->describe_code(pc);
if (LOG_UML || LOG_NATIVE)
log_opcode_desc(drcuml, desclist, 0);
@ -757,7 +775,7 @@ static void code_compile_block(mips3_state *mips3, UINT8 mode, offs_t pc)
block = drcuml_block_begin(drcuml, 4096, &errorbuf);
/* loop until we get through all instruction sequences */
for (seqhead = desclist; seqhead != NULL; seqhead = seqlast->next)
for (seqhead = desclist; seqhead != NULL; seqhead = seqlast->next())
{
const opcode_desc *curdesc;
UINT32 nextpc;
@ -767,7 +785,7 @@ static void code_compile_block(mips3_state *mips3, UINT8 mode, offs_t pc)
UML_COMMENT(block, "-------------------------"); // comment
/* determine the last instruction in this sequence */
for (seqlast = seqhead; seqlast != NULL; seqlast = seqlast->next)
for (seqlast = seqhead; seqlast != NULL; seqlast = seqlast->next())
if (seqlast->flags & OPFLAG_END_SEQUENCE)
break;
assert(seqlast != NULL);
@ -802,7 +820,7 @@ static void code_compile_block(mips3_state *mips3, UINT8 mode, offs_t pc)
UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc | 0x80000000
/* iterate over instructions in the sequence and compile them */
for (curdesc = seqhead; curdesc != seqlast->next; curdesc = curdesc->next)
for (curdesc = seqhead; curdesc != seqlast->next(); curdesc = curdesc->next())
generate_sequence_instruction(mips3, block, &compiler, curdesc);
/* if we need to return to the start, do it */
@ -820,7 +838,7 @@ static void code_compile_block(mips3_state *mips3, UINT8 mode, offs_t pc)
if (seqlast->flags & OPFLAG_CAN_CHANGE_MODES)
UML_HASHJMP(block, MEM(&mips3->impstate->mode), IMM(nextpc), mips3->impstate->nocode);
// hashjmp <mode>,nextpc,nocode
else if (seqlast->next == NULL || seqlast->next->pc != nextpc)
else if (seqlast->next() == NULL || seqlast->next()->pc != nextpc)
UML_HASHJMP(block, IMM(mips3->impstate->mode), IMM(nextpc), mips3->impstate->nocode);
// hashjmp <mode>,nextpc,nocode
}
@ -1521,7 +1539,7 @@ static void generate_checksum_block(mips3_state *mips3, drcuml_block *block, com
UML_COMMENT(block, "[Validation for %08X]", seqhead->pc); // comment
/* loose verify or single instruction: just compare and fail */
if (!(mips3->impstate->drcoptions & MIPS3DRC_STRICT_VERIFY) || seqhead->next == NULL)
if (!(mips3->impstate->drcoptions & MIPS3DRC_STRICT_VERIFY) || seqhead->next() == NULL)
{
if (!(seqhead->flags & OPFLAG_VIRTUAL_NOOP))
{
@ -1536,7 +1554,7 @@ static void generate_checksum_block(mips3_state *mips3, drcuml_block *block, com
else
{
#if 0
for (curdesc = seqhead->next; curdesc != seqlast->next; curdesc = curdesc->next)
for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next())
if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP))
{
void *base = mips3->direct->read_decrypted_ptr(seqhead->physpc);
@ -1549,7 +1567,7 @@ static void generate_checksum_block(mips3_state *mips3, drcuml_block *block, com
void *base = mips3->direct->read_decrypted_ptr(seqhead->physpc);
UML_LOAD(block, IREG(0), base, IMM(0), DWORD); // load i0,base,0,dword
sum += seqhead->opptr.l[0];
for (curdesc = seqhead->next; curdesc != seqlast->next; curdesc = curdesc->next)
for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next())
if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP))
{
base = mips3->direct->read_decrypted_ptr(curdesc->physpc);
@ -1557,12 +1575,12 @@ static void generate_checksum_block(mips3_state *mips3, drcuml_block *block, com
UML_ADD(block, IREG(0), IREG(0), IREG(1)); // add i0,i0,i1
sum += curdesc->opptr.l[0];
if (curdesc->delay != NULL && (curdesc == seqlast || (curdesc->next != NULL && curdesc->next->physpc != curdesc->delay->physpc)))
if (curdesc->delay.first() != NULL && (curdesc == seqlast || (curdesc->next() != NULL && curdesc->next()->physpc != curdesc->delay.first()->physpc)))
{
base = mips3->direct->read_decrypted_ptr(curdesc->delay->physpc);
base = mips3->direct->read_decrypted_ptr(curdesc->delay.first()->physpc);
UML_LOAD(block, IREG(1), base, IMM(0), DWORD); // load i1,base,dword
UML_ADD(block, IREG(0), IREG(0), IREG(1)); // add i0,i0,i1
sum += curdesc->delay->opptr.l[0];
sum += curdesc->delay.first()->opptr.l[0];
}
}
UML_CMP(block, IREG(0), IMM(sum)); // cmp i0,sum
@ -1710,8 +1728,8 @@ static void generate_delay_slot_and_branch(mips3_state *mips3, drcuml_block *blo
UML_DMOV(block, R64(linkreg), IMM((INT32)(desc->pc + 8))); // dmov <linkreg>,desc->pc + 8
/* compile the delay slot using temporary compiler state */
assert(desc->delay != NULL);
generate_sequence_instruction(mips3, block, &compiler_temp, desc->delay); // <next instruction>
assert(desc->delay.first() != NULL);
generate_sequence_instruction(mips3, block, &compiler_temp, desc->delay.first()); // <next instruction>
/* update the cycles and jump through the hash table to the target */
if (desc->targetpc != BRANCH_TARGET_DYNAMIC)
@ -3648,7 +3666,7 @@ static void log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, i
drcuml_log_printf(drcuml, "\nDescriptor list @ %08X\n", desclist->pc);
/* output each descriptor */
for ( ; desclist != NULL; desclist = desclist->next)
for ( ; desclist != NULL; desclist = desclist->next())
{
char buffer[100];
@ -3669,8 +3687,8 @@ static void log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, i
drcuml_log_printf(drcuml, "\n");
/* if we have a delay slot, output it recursively */
if (desclist->delay != NULL)
log_opcode_desc(drcuml, desclist->delay, indent + 1);
if (desclist->delay.first() != NULL)
log_opcode_desc(drcuml, desclist->delay.first(), indent + 1);
/* at the end of a sequence add a dividing line */
if (desclist->flags & OPFLAG_END_SEQUENCE)

File diff suppressed because it is too large Load Diff

View File

@ -4,9 +4,36 @@
Front-end for MIPS3 recompiler
****************************************************************************
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,30 +42,54 @@
#ifndef __MIPS3FE_H__
#define __MIPS3FE_H__
#include "mips3com.h"
#include "cpu/drcfe.h"
/***************************************************************************
CONSTANTS
***************************************************************************/
//**************************************************************************
// MACROS
//**************************************************************************
/* register flags 0 */
// register flags 0
#define REGFLAG_R(n) (((n) == 0) ? 0 : (1 << (n)))
/* register flags 1 */
// register flags 1
#define REGFLAG_CPR1(n) (1 << (n))
/* register flags 2 */
// register flags 2
#define REGFLAG_LO (1 << 0)
#define REGFLAG_HI (1 << 1)
#define REGFLAG_FCC (1 << 2)
/***************************************************************************
FUNCTION PROTOTYPES
***************************************************************************/
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
class mips3_frontend : public drc_frontend
{
public:
// construction/destruction
mips3_frontend(mips3_state &state, UINT32 window_start, UINT32 window_end, UINT32 max_sequence);
protected:
// required overrides
virtual bool describe(opcode_desc &desc, const opcode_desc *prev);
private:
// internal helpers
bool describe_special(UINT32 op, opcode_desc &desc);
bool describe_regimm(UINT32 op, opcode_desc &desc);
bool describe_idt(UINT32 op, opcode_desc &desc);
bool describe_cop0(UINT32 op, opcode_desc &desc);
bool describe_cop1(UINT32 op, opcode_desc &desc);
bool describe_cop1x(UINT32 op, opcode_desc &desc);
bool describe_cop2(UINT32 op, opcode_desc &desc);
// internal state
mips3_state &m_context;
};
int mips3fe_describe(void *param, opcode_desc *desc, const opcode_desc *prev);
#endif /* __MIPS3FE_H__ */

View File

@ -165,7 +165,7 @@ struct _ppcimp_state
/* core state */
drccache * cache; /* pointer to the DRC code cache */
drcuml_state * drcuml; /* DRC UML generator state */
drcfe_state * drcfe; /* pointer to the DRC front-end state */
ppc_frontend * drcfe; /* pointer to the DRC front-end state */
UINT32 drcoptions; /* configurable DRC options */
/* parameters for subroutines */
@ -548,13 +548,6 @@ INLINE UINT32 compute_spr(UINT32 spr)
static void ppcdrc_init(powerpc_flavor flavor, UINT8 cap, int tb_divisor, legacy_cpu_device *device, device_irq_callback irqcallback)
{
drcfe_config feconfig =
{
COMPILE_BACKWARDS_BYTES, /* code window start offset = startpc - window_start */
COMPILE_FORWARDS_BYTES, /* code window end offset = startpc + window_end */
COMPILE_MAX_SEQUENCE, /* maximum instructions to include in a sequence */
ppcfe_describe /* callback to describe a single instruction */
};
powerpc_state *ppc;
drcbe_info beinfo;
UINT32 flags = 0;
@ -633,9 +626,7 @@ static void ppcdrc_init(powerpc_flavor flavor, UINT8 cap, int tb_divisor, legacy
drcuml_symbol_add(ppc->impstate->drcuml, &ppc->impstate->fcmp_cr_table, sizeof(ppc->impstate->fcmp_cr_table), "fcmp_cr_table");
/* initialize the front-end helper */
if (SINGLE_INSTRUCTION_MODE)
feconfig.max_sequence = 1;
ppc->impstate->drcfe = drcfe_init(device, &feconfig, ppc);
ppc->impstate->drcfe = auto_alloc(device->machine, ppc_frontend(*ppc, COMPILE_BACKWARDS_BYTES, COMPILE_FORWARDS_BYTES, SINGLE_INSTRUCTION_MODE ? 1 : COMPILE_MAX_SEQUENCE));
/* initialize the implementation state tables */
memcpy(ppc->impstate->fpmode, fpmode_source, sizeof(fpmode_source));
@ -738,7 +729,7 @@ static CPU_EXIT( ppcdrc )
ppccom_exit(ppc);
/* clean up the DRC */
drcfe_exit(ppc->impstate->drcfe);
auto_free(device->machine, ppc->impstate->drcfe);
drcuml_free(ppc->impstate->drcuml);
drccache_free(ppc->impstate->cache);
}
@ -950,7 +941,7 @@ static void code_compile_block(powerpc_state *ppc, UINT8 mode, offs_t pc)
g_profiler.start(PROFILER_DRC_COMPILE);
/* get a description of this sequence */
desclist = drcfe_describe_code(ppc->impstate->drcfe, pc);
desclist = ppc->impstate->drcfe->describe_code(pc);
if (LOG_UML || LOG_NATIVE)
log_opcode_desc(drcuml, desclist, 0);
@ -962,7 +953,7 @@ static void code_compile_block(powerpc_state *ppc, UINT8 mode, offs_t pc)
block = drcuml_block_begin(drcuml, 4096, &errorbuf);
/* loop until we get through all instruction sequences */
for (seqhead = desclist; seqhead != NULL; seqhead = seqlast->next)
for (seqhead = desclist; seqhead != NULL; seqhead = seqlast->next())
{
const opcode_desc *curdesc;
UINT32 nextpc;
@ -972,7 +963,7 @@ static void code_compile_block(powerpc_state *ppc, UINT8 mode, offs_t pc)
UML_COMMENT(block, "-------------------------"); // comment
/* determine the last instruction in this sequence */
for (seqlast = seqhead; seqlast != NULL; seqlast = seqlast->next)
for (seqlast = seqhead; seqlast != NULL; seqlast = seqlast->next())
if (seqlast->flags & OPFLAG_END_SEQUENCE)
break;
assert(seqlast != NULL);
@ -1007,7 +998,7 @@ static void code_compile_block(powerpc_state *ppc, UINT8 mode, offs_t pc)
UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc | 0x80000000
/* iterate over instructions in the sequence and compile them */
for (curdesc = seqhead; curdesc != seqlast->next; curdesc = curdesc->next)
for (curdesc = seqhead; curdesc != seqlast->next(); curdesc = curdesc->next())
generate_sequence_instruction(ppc, block, &compiler, curdesc); // <instruction>
/* if we need to return to the start, do it */
@ -1024,7 +1015,7 @@ static void code_compile_block(powerpc_state *ppc, UINT8 mode, offs_t pc)
/* if the last instruction can change modes, use a variable mode; otherwise, assume the same mode */
if (seqlast->flags & OPFLAG_CAN_CHANGE_MODES)
UML_HASHJMP(block, MEM(&ppc->impstate->mode), IMM(nextpc), ppc->impstate->nocode);// hashjmp <mode>,nextpc,nocode
else if (seqlast->next == NULL || seqlast->next->pc != nextpc)
else if (seqlast->next() == NULL || seqlast->next()->pc != nextpc)
UML_HASHJMP(block, IMM(ppc->impstate->mode), IMM(nextpc), ppc->impstate->nocode);// hashjmp <mode>,nextpc,nocode
}
@ -2093,7 +2084,7 @@ static void generate_checksum_block(powerpc_state *ppc, drcuml_block *block, com
UML_COMMENT(block, "[Validation for %08X]", seqhead->pc); // comment
/* loose verify or single instruction: just compare and fail */
if (!(ppc->impstate->drcoptions & PPCDRC_STRICT_VERIFY) || seqhead->next == NULL)
if (!(ppc->impstate->drcoptions & PPCDRC_STRICT_VERIFY) || seqhead->next() == NULL)
{
if (!(seqhead->flags & OPFLAG_VIRTUAL_NOOP))
{
@ -2108,7 +2099,7 @@ static void generate_checksum_block(powerpc_state *ppc, drcuml_block *block, com
else
{
#if 0
for (curdesc = seqhead->next; curdesc != seqlast->next; curdesc = curdesc->next)
for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next())
if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP))
{
void *base = ppc->direct->read_decrypted_ptr(seqhead->physpc, ppc->codexor);
@ -2121,7 +2112,7 @@ static void generate_checksum_block(powerpc_state *ppc, drcuml_block *block, com
void *base = ppc->direct->read_decrypted_ptr(seqhead->physpc, ppc->codexor);
UML_LOAD(block, IREG(0), base, IMM(0), DWORD); // load i0,base,dword
sum += seqhead->opptr.l[0];
for (curdesc = seqhead->next; curdesc != seqlast->next; curdesc = curdesc->next)
for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next())
if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP))
{
base = ppc->direct->read_decrypted_ptr(curdesc->physpc, ppc->codexor);
@ -4240,7 +4231,7 @@ static void log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, i
drcuml_log_printf(drcuml, "\nDescriptor list @ %08X\n", desclist->pc);
/* output each descriptor */
for ( ; desclist != NULL; desclist = desclist->next)
for ( ; desclist != NULL; desclist = desclist->next())
{
char buffer[100];
@ -4263,8 +4254,8 @@ static void log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, i
drcuml_log_printf(drcuml, "\n");
/* if we have a delay slot, output it recursively */
if (desclist->delay != NULL)
log_opcode_desc(drcuml, desclist->delay, indent + 1);
if (desclist->delay.first() != NULL)
log_opcode_desc(drcuml, desclist->delay.first(), indent + 1);
/* at the end of a sequence add a dividing line */
if (desclist->flags & OPFLAG_END_SEQUENCE)

File diff suppressed because it is too large Load Diff

View File

@ -4,34 +4,62 @@
Front-end for PowerPC recompiler
****************************************************************************
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.
***************************************************************************/
#ifndef __PPCFE_H__
#define __PPCFE_H__
#include "ppccom.h"
#include "cpu/drcfe.h"
/***************************************************************************
CONSTANTS
***************************************************************************/
//**************************************************************************
// MACROS
//**************************************************************************
/* register flags 0 */
// register flags 0
#define REGFLAG_R(n) (1 << (n))
#define REGFLAG_RZ(n) (((n) == 0) ? 0 : REGFLAG_R(n))
/* register flags 1 */
// register flags 1
#define REGFLAG_FR(n) (1 << (n))
/* register flags 2 */
// register flags 2
#define REGFLAG_CR(n) (0xf0000000 >> (4 * (n)))
#define REGFLAG_CR_BIT(n) (0x80000000 >> (n))
/* register flags 3 */
// register flags 3
#define REGFLAG_XER_CA (1 << 0)
#define REGFLAG_XER_OV (1 << 1)
#define REGFLAG_XER_SO (1 << 2)
@ -42,10 +70,37 @@
/***************************************************************************
FUNCTION PROTOTYPES
***************************************************************************/
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
class ppc_frontend : public drc_frontend
{
public:
// construction/destruction
ppc_frontend(powerpc_state &state, UINT32 window_start, UINT32 window_end, UINT32 max_sequence);
protected:
// required overrides
virtual bool describe(opcode_desc &desc, const opcode_desc *prev);
private:
// inlines
UINT32 compute_spr(UINT32 spr) const { return ((spr >> 5) | (spr << 5)) & 0x3ff; }
bool is_403_class() const { return (m_context.flavor == PPC_MODEL_403GA || m_context.flavor == PPC_MODEL_403GB || m_context.flavor == PPC_MODEL_403GC || m_context.flavor == PPC_MODEL_403GCX || m_context.flavor == PPC_MODEL_405GP); }
bool is_601_class() const { return (m_context.flavor == PPC_MODEL_601); }
bool is_602_class() const { return (m_context.flavor == PPC_MODEL_602); }
bool is_603_class() const { return (m_context.flavor == PPC_MODEL_603 || m_context.flavor == PPC_MODEL_603E || m_context.flavor == PPC_MODEL_603EV || m_context.flavor == PPC_MODEL_603R); }
// internal helpers
bool describe_13(UINT32 op, opcode_desc &desc, const opcode_desc *prev);
bool describe_1f(UINT32 op, opcode_desc &desc, const opcode_desc *prev);
bool describe_3b(UINT32 op, opcode_desc &desc, const opcode_desc *prev);
bool describe_3f(UINT32 op, opcode_desc &desc, const opcode_desc *prev);
// internal state
powerpc_state &m_context;
};
int ppcfe_describe(void *param, opcode_desc *desc, const opcode_desc *prev);
#endif /* __PPCFE_H__ */

View File

@ -106,7 +106,7 @@ struct _rspimp_state
/* core state */
drccache * cache; /* pointer to the DRC code cache */
drcuml_state * drcuml; /* DRC UML generator state */
drcfe_state * drcfe; /* pointer to the DRC front-end state */
rsp_frontend * drcfe; /* pointer to the DRC front-end state */
UINT32 drcoptions; /* configurable DRC options */
/* internal stuff */
@ -603,13 +603,6 @@ static void rspcom_init(rsp_state *rsp, legacy_cpu_device *device, device_irq_ca
static CPU_INIT( rsp )
{
drcfe_config feconfig =
{
COMPILE_BACKWARDS_BYTES, /* code window start offset = startpc - window_start */
COMPILE_FORWARDS_BYTES, /* code window end offset = startpc + window_end */
COMPILE_MAX_SEQUENCE, /* maximum instructions to include in a sequence */
rspfe_describe /* callback to describe a single instruction */
};
rsp_state *rsp;
drccache *cache;
UINT32 flags = 0;
@ -669,11 +662,7 @@ static CPU_INIT( rsp )
drcuml_symbol_add(rsp->impstate->drcuml, &rsp->impstate->numcycles, sizeof(rsp->impstate->numcycles), "numcycles");
/* initialize the front-end helper */
if (SINGLE_INSTRUCTION_MODE)
{
feconfig.max_sequence = 1;
}
rsp->impstate->drcfe = drcfe_init(device, &feconfig, rsp);
rsp->impstate->drcfe = auto_alloc(device->machine, rsp_frontend(*rsp, COMPILE_BACKWARDS_BYTES, COMPILE_FORWARDS_BYTES, SINGLE_INSTRUCTION_MODE ? 1 : COMPILE_MAX_SEQUENCE));
/* compute the register parameters */
for (regnum = 0; regnum < 32; regnum++)
@ -721,7 +710,7 @@ static CPU_EXIT( rsp )
rsp_state *rsp = get_safe_token(device);
/* clean up the DRC */
drcfe_exit(rsp->impstate->drcfe);
auto_free(device->machine, rsp->impstate->drcfe);
drcuml_free(rsp->impstate->drcuml);
drccache_free(rsp->impstate->cache);
}
@ -3479,7 +3468,7 @@ static void code_compile_block(rsp_state *rsp, offs_t pc)
g_profiler.start(PROFILER_DRC_COMPILE);
/* get a description of this sequence */
desclist = drcfe_describe_code(rsp->impstate->drcfe, pc);
desclist = rsp->impstate->drcfe->describe_code(pc);
/* if we get an error back, flush the cache and try again */
if (setjmp(errorbuf) != 0)
@ -3491,7 +3480,7 @@ static void code_compile_block(rsp_state *rsp, offs_t pc)
block = drcuml_block_begin(drcuml, 8192, &errorbuf);
/* loop until we get through all instruction sequences */
for (seqhead = desclist; seqhead != NULL; seqhead = seqlast->next)
for (seqhead = desclist; seqhead != NULL; seqhead = seqlast->next())
{
const opcode_desc *curdesc;
UINT32 nextpc;
@ -3501,7 +3490,7 @@ static void code_compile_block(rsp_state *rsp, offs_t pc)
UML_COMMENT(block, "-------------------------"); // comment
/* determine the last instruction in this sequence */
for (seqlast = seqhead; seqlast != NULL; seqlast = seqlast->next)
for (seqlast = seqhead; seqlast != NULL; seqlast = seqlast->next())
if (seqlast->flags & OPFLAG_END_SEQUENCE)
break;
assert(seqlast != NULL);
@ -3536,7 +3525,7 @@ static void code_compile_block(rsp_state *rsp, offs_t pc)
UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc
/* iterate over instructions in the sequence and compile them */
for (curdesc = seqhead; curdesc != seqlast->next; curdesc = curdesc->next)
for (curdesc = seqhead; curdesc != seqlast->next(); curdesc = curdesc->next())
generate_sequence_instruction(rsp, block, &compiler, curdesc);
/* if we need to return to the start, do it */
@ -3551,7 +3540,7 @@ static void code_compile_block(rsp_state *rsp, offs_t pc)
generate_update_cycles(rsp, block, &compiler, IMM(nextpc), TRUE); // <subtract cycles>
/* if the last instruction can change modes, use a variable mode; otherwise, assume the same mode */
if (seqlast->next == NULL || seqlast->next->pc != nextpc)
if (seqlast->next() == NULL || seqlast->next()->pc != nextpc)
UML_HASHJMP(block, IMM(0), IMM(nextpc), rsp->impstate->nocode); // hashjmp <mode>,nextpc,nocode
}
@ -3800,7 +3789,7 @@ static void generate_checksum_block(rsp_state *rsp, drcuml_block *block, compile
UML_COMMENT(block, "[Validation for %08X]", seqhead->pc | 0x1000); // comment
}
/* loose verify or single instruction: just compare and fail */
if (!(rsp->impstate->drcoptions & RSPDRC_STRICT_VERIFY) || seqhead->next == NULL)
if (!(rsp->impstate->drcoptions & RSPDRC_STRICT_VERIFY) || seqhead->next() == NULL)
{
if (!(seqhead->flags & OPFLAG_VIRTUAL_NOOP))
{
@ -3818,7 +3807,7 @@ static void generate_checksum_block(rsp_state *rsp, drcuml_block *block, compile
void *base = rsp->direct->read_decrypted_ptr(seqhead->physpc | 0x1000);
UML_LOAD(block, IREG(0), base, IMM(0), DWORD); // load i0,base,0,dword
sum += seqhead->opptr.l[0];
for (curdesc = seqhead->next; curdesc != seqlast->next; curdesc = curdesc->next)
for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next())
if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP))
{
base = rsp->direct->read_decrypted_ptr(curdesc->physpc | 0x1000);
@ -3910,7 +3899,7 @@ static void generate_delay_slot_and_branch(rsp_state *rsp, drcuml_block *block,
/* compile the delay slot using temporary compiler state */
assert(desc->delay != NULL);
generate_sequence_instruction(rsp, block, &compiler_temp, desc->delay); // <next instruction>
generate_sequence_instruction(rsp, block, &compiler_temp, desc->delay.first()); // <next instruction>
/* update the cycles and jump through the hash table to the target */
if (desc->targetpc != BRANCH_TARGET_DYNAMIC)

View File

@ -1,4 +1,4 @@
/***************************************************************************
/***************************************************************************
rspfe.c
@ -14,294 +14,291 @@
#include "rspfe.h"
#include "rsp.h"
/***************************************************************************
FUNCTION PROTOTYPES
***************************************************************************/
//**************************************************************************
// RSP FRONTEND
//**************************************************************************
static int describe_instruction_special(rsp_state *rsp, UINT32 op, opcode_desc *desc);
static int describe_instruction_regimm(rsp_state *rsp, UINT32 op, opcode_desc *desc);
static int describe_instruction_cop0(rsp_state *rsp, UINT32 op, opcode_desc *desc);
static int describe_instruction_cop2(rsp_state *rsp, UINT32 op, opcode_desc *desc);
//-------------------------------------------------
// rsp_frontend - constructor
//-------------------------------------------------
/***************************************************************************
INSTRUCTION PARSERS
***************************************************************************/
/*-------------------------------------------------
describe_instruction - build a description
of a single instruction
-------------------------------------------------*/
int rspfe_describe(void *param, opcode_desc *desc, const opcode_desc *prev)
rsp_frontend::rsp_frontend(rsp_state &state, UINT32 window_start, UINT32 window_end, UINT32 max_sequence)
: drc_frontend(*state.device, window_start, window_end, max_sequence),
m_context(state)
{
}
//-------------------------------------------------
// describe - build a description of a single
// instruction
//-------------------------------------------------
bool rsp_frontend::describe(opcode_desc &desc, const opcode_desc *prev)
{
rsp_state *rsp = (rsp_state *)param;
UINT32 op, opswitch;
/* fetch the opcode */
op = desc->opptr.l[0] = rsp->direct->read_decrypted_dword(desc->physpc | 0x1000);
// fetch the opcode
op = desc.opptr.l[0] = m_context.direct->read_decrypted_dword(desc.physpc | 0x1000);
/* all instructions are 4 bytes and default to a single cycle each */
desc->length = 4;
desc->cycles = 1;
// all instructions are 4 bytes and default to a single cycle each
desc.length = 4;
desc.cycles = 1;
/* parse the instruction */
// parse the instruction
opswitch = op >> 26;
switch (opswitch)
{
case 0x00: /* SPECIAL */
return describe_instruction_special(rsp, op, desc);
case 0x00: // SPECIAL
return describe_special(op, desc);
case 0x01: /* REGIMM */
return describe_instruction_regimm(rsp, op, desc);
case 0x01: // REGIMM
return describe_regimm(op, desc);
case 0x10: /* COP0 */
return describe_instruction_cop0(rsp, op, desc);
case 0x10: // COP0
return describe_cop0(op, desc);
case 0x12: /* COP2 */
return describe_instruction_cop2(rsp, op, desc);
case 0x12: // COP2
return describe_cop2(op, desc);
case 0x02: /* J */
desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
desc->targetpc = ((LIMMVAL << 2) & 0x00000fff) | 0x1000;
desc->delayslots = 1;
return TRUE;
case 0x02: // J
desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
desc.targetpc = ((LIMMVAL << 2) & 0x00000fff) | 0x1000;
desc.delayslots = 1;
return true;
case 0x03: /* JAL */
desc->regout[0] |= REGFLAG_R(31);
desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
desc->targetpc = ((LIMMVAL << 2) & 0x00000fff) | 0x1000;
desc->delayslots = 1;
return TRUE;
case 0x03: // JAL
desc.regout[0] |= REGFLAG_R(31);
desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
desc.targetpc = ((LIMMVAL << 2) & 0x00000fff) | 0x1000;
desc.delayslots = 1;
return true;
case 0x04: /* BEQ */
case 0x05: /* BNE */
case 0x04: // BEQ
case 0x05: // BNE
if ((opswitch == 0x04 || opswitch == 0x14) && RSREG == RTREG)
desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
else
{
desc->regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG);
desc->flags |= OPFLAG_IS_CONDITIONAL_BRANCH;
desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG);
desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH;
}
desc->targetpc = ((desc->pc + 4 + (SIMMVAL << 2)) & 0x00000fff) | 0x1000;
desc->delayslots = 1;
desc->skipslots = (opswitch & 0x10) ? 1 : 0;
return TRUE;
desc.targetpc = ((desc.pc + 4 + (SIMMVAL << 2)) & 0x00000fff) | 0x1000;
desc.delayslots = 1;
desc.skipslots = (opswitch & 0x10) ? 1 : 0;
return true;
case 0x06: /* BLEZ */
case 0x07: /* BGTZ */
case 0x06: // BLEZ
case 0x07: // BGTZ
if ((opswitch == 0x06 || opswitch == 0x16) && RSREG == 0)
desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
else
{
desc->regin[0] |= REGFLAG_R(RSREG);
desc->flags |= OPFLAG_IS_CONDITIONAL_BRANCH;
desc.regin[0] |= REGFLAG_R(RSREG);
desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH;
}
desc->targetpc = ((desc->pc + 4 + (SIMMVAL << 2)) & 0x00000fff) | 0x1000;
desc->delayslots = 1;
desc->skipslots = (opswitch & 0x10) ? 1 : 0;
return TRUE;
desc.targetpc = ((desc.pc + 4 + (SIMMVAL << 2)) & 0x00000fff) | 0x1000;
desc.delayslots = 1;
desc.skipslots = (opswitch & 0x10) ? 1 : 0;
return true;
case 0x08: /* ADDI */
desc->regin[0] |= REGFLAG_R(RSREG);
desc->regout[0] |= REGFLAG_R(RTREG);
return TRUE;
case 0x08: // ADDI
desc.regin[0] |= REGFLAG_R(RSREG);
desc.regout[0] |= REGFLAG_R(RTREG);
return true;
case 0x09: /* ADDIU */
case 0x0a: /* SLTI */
case 0x0b: /* SLTIU */
case 0x0c: /* ANDI */
case 0x0d: /* ORI */
case 0x0e: /* XORI */
desc->regin[0] |= REGFLAG_R(RSREG);
desc->regout[0] |= REGFLAG_R(RTREG);
return TRUE;
case 0x09: // ADDIU
case 0x0a: // SLTI
case 0x0b: // SLTIU
case 0x0c: // ANDI
case 0x0d: // ORI
case 0x0e: // XORI
desc.regin[0] |= REGFLAG_R(RSREG);
desc.regout[0] |= REGFLAG_R(RTREG);
return true;
case 0x0f: /* LUI */
desc->regout[0] |= REGFLAG_R(RTREG);
return TRUE;
case 0x0f: // LUI
desc.regout[0] |= REGFLAG_R(RTREG);
return true;
case 0x20: /* LB */
case 0x21: /* LH */
case 0x23: /* LW */
case 0x24: /* LBU */
case 0x25: /* LHU */
case 0x27: /* LWU */
desc->regin[0] |= REGFLAG_R(RSREG);
desc->regout[0] |= REGFLAG_R(RTREG);
desc->flags |= OPFLAG_READS_MEMORY;
return TRUE;
case 0x20: // LB
case 0x21: // LH
case 0x23: // LW
case 0x24: // LBU
case 0x25: // LHU
case 0x27: // LWU
desc.regin[0] |= REGFLAG_R(RSREG);
desc.regout[0] |= REGFLAG_R(RTREG);
desc.flags |= OPFLAG_READS_MEMORY;
return true;
case 0x28: /* SB */
case 0x29: /* SH */
case 0x2b: /* SW */
desc->regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG);
desc->flags |= OPFLAG_WRITES_MEMORY;
return TRUE;
case 0x28: // SB
case 0x29: // SH
case 0x2b: // SW
desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG);
desc.flags |= OPFLAG_WRITES_MEMORY;
return true;
case 0x32: /* LWC2 */
desc->regin[0] |= REGFLAG_R(RSREG);
desc->flags |= OPFLAG_READS_MEMORY;
return TRUE;
case 0x32: // LWC2
desc.regin[0] |= REGFLAG_R(RSREG);
desc.flags |= OPFLAG_READS_MEMORY;
return true;
case 0x3a: /* SWC2 */
desc->regin[0] |= REGFLAG_R(RSREG);
desc->flags |= OPFLAG_WRITES_MEMORY;
return TRUE;
case 0x3a: // SWC2
desc.regin[0] |= REGFLAG_R(RSREG);
desc.flags |= OPFLAG_WRITES_MEMORY;
return true;
}
return FALSE;
return false;
}
/*-------------------------------------------------
describe_instruction_special - build a
description of a single instruction in the
'special' group
-------------------------------------------------*/
//-------------------------------------------------
// describe_special - build a description of a
// single instruction in the 'special' group
//-------------------------------------------------
static int describe_instruction_special(rsp_state *rsp, UINT32 op, opcode_desc *desc)
bool rsp_frontend::describe_special(UINT32 op, opcode_desc &desc)
{
switch (op & 63)
{
case 0x00: /* SLL */
case 0x02: /* SRL */
case 0x03: /* SRA */
desc->regin[0] |= REGFLAG_R(RTREG);
desc->regout[0] |= REGFLAG_R(RDREG);
return TRUE;
case 0x00: // SLL
case 0x02: // SRL
case 0x03: // SRA
desc.regin[0] |= REGFLAG_R(RTREG);
desc.regout[0] |= REGFLAG_R(RDREG);
return true;
case 0x04: /* SLLV */
case 0x06: /* SRLV */
case 0x07: /* SRAV */
case 0x21: /* ADDU */
case 0x23: /* SUBU */
case 0x24: /* AND */
case 0x25: /* OR */
case 0x26: /* XOR */
case 0x27: /* NOR */
case 0x2a: /* SLT */
case 0x2b: /* SLTU */
desc->regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG);
desc->regout[0] |= REGFLAG_R(RDREG);
return TRUE;
case 0x04: // SLLV
case 0x06: // SRLV
case 0x07: // SRAV
case 0x21: // ADDU
case 0x23: // SUBU
case 0x24: // AND
case 0x25: // OR
case 0x26: // XOR
case 0x27: // NOR
case 0x2a: // SLT
case 0x2b: // SLTU
desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG);
desc.regout[0] |= REGFLAG_R(RDREG);
return true;
case 0x20: /* ADD */
case 0x22: /* SUB */
desc->regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG);
desc->regout[0] |= REGFLAG_R(RDREG);
return TRUE;
case 0x20: // ADD
case 0x22: // SUB
desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG);
desc.regout[0] |= REGFLAG_R(RDREG);
return true;
case 0x08: /* JR */
desc->regin[0] |= REGFLAG_R(RSREG);
desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
desc->targetpc = BRANCH_TARGET_DYNAMIC;
desc->delayslots = 1;
return TRUE;
case 0x08: // JR
desc.regin[0] |= REGFLAG_R(RSREG);
desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
desc.targetpc = BRANCH_TARGET_DYNAMIC;
desc.delayslots = 1;
return true;
case 0x09: /* JALR */
desc->regin[0] |= REGFLAG_R(RSREG);
desc->regout[0] |= REGFLAG_R(RDREG);
desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
desc->targetpc = BRANCH_TARGET_DYNAMIC;
desc->delayslots = 1;
return TRUE;
case 0x09: // JALR
desc.regin[0] |= REGFLAG_R(RSREG);
desc.regout[0] |= REGFLAG_R(RDREG);
desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
desc.targetpc = BRANCH_TARGET_DYNAMIC;
desc.delayslots = 1;
return true;
case 0x0d: /* BREAK */
desc->flags |= OPFLAG_END_SEQUENCE;
desc->targetpc = BRANCH_TARGET_DYNAMIC;
return TRUE;
case 0x0d: // BREAK
desc.flags |= OPFLAG_END_SEQUENCE;
desc.targetpc = BRANCH_TARGET_DYNAMIC;
return true;
}
return FALSE;
return false;
}
/*-------------------------------------------------
describe_instruction_regimm - build a
description of a single instruction in the
'regimm' group
-------------------------------------------------*/
//-------------------------------------------------
// describe_regimm - build a description of a
// single instruction in the 'regimm' group
//-------------------------------------------------
static int describe_instruction_regimm(rsp_state *rsp, UINT32 op, opcode_desc *desc)
bool rsp_frontend::describe_regimm(UINT32 op, opcode_desc &desc)
{
switch (RTREG)
{
case 0x00: /* BLTZ */
case 0x01: /* BGEZ */
case 0x00: // BLTZ
case 0x01: // BGEZ
if (RTREG == 0x01 && RSREG == 0)
desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
else
{
desc->regin[0] |= REGFLAG_R(RSREG);
desc->flags |= OPFLAG_IS_CONDITIONAL_BRANCH;
desc.regin[0] |= REGFLAG_R(RSREG);
desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH;
}
desc->targetpc = ((desc->pc + 4 + (SIMMVAL << 2)) & 0x00000fff) | 0x1000;
desc->delayslots = 1;
desc->skipslots = (RTREG & 0x02) ? 1 : 0;
return TRUE;
desc.targetpc = ((desc.pc + 4 + (SIMMVAL << 2)) & 0x00000fff) | 0x1000;
desc.delayslots = 1;
desc.skipslots = (RTREG & 0x02) ? 1 : 0;
return true;
case 0x10: /* BLTZAL */
case 0x11: /* BGEZAL */
case 0x10: // BLTZAL
case 0x11: // BGEZAL
if (RTREG == 0x11 && RSREG == 0)
desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
else
{
desc->regin[0] |= REGFLAG_R(RSREG);
desc->flags |= OPFLAG_IS_CONDITIONAL_BRANCH;
desc.regin[0] |= REGFLAG_R(RSREG);
desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH;
}
desc->regout[0] |= REGFLAG_R(31);
desc->targetpc = ((desc->pc + 4 + (SIMMVAL << 2)) & 0x00000fff) | 0x1000;
desc->delayslots = 1;
desc->skipslots = (RTREG & 0x02) ? 1 : 0;
return TRUE;
desc.regout[0] |= REGFLAG_R(31);
desc.targetpc = ((desc.pc + 4 + (SIMMVAL << 2)) & 0x00000fff) | 0x1000;
desc.delayslots = 1;
desc.skipslots = (RTREG & 0x02) ? 1 : 0;
return true;
}
return FALSE;
return false;
}
/*-------------------------------------------------
describe_instruction_cop0 - build a
description of a single instruction in the
COP0 group
-------------------------------------------------*/
//-------------------------------------------------
// describe_cop0 - build a description of a
// single instruction in the COP0 group
//-------------------------------------------------
static int describe_instruction_cop0(rsp_state *rsp, UINT32 op, opcode_desc *desc)
bool rsp_frontend::describe_cop0(UINT32 op, opcode_desc &desc)
{
switch (RSREG)
{
case 0x00: /* MFCz */
desc->regout[0] |= REGFLAG_R(RTREG);
return TRUE;
case 0x00: // MFCz
desc.regout[0] |= REGFLAG_R(RTREG);
return true;
case 0x04: /* MTCz */
desc->regin[0] |= REGFLAG_R(RTREG);
return TRUE;
case 0x04: // MTCz
desc.regin[0] |= REGFLAG_R(RTREG);
return true;
}
return FALSE;
return false;
}
/*-------------------------------------------------
describe_instruction_cop2 - build a
description of a single instruction in the
COP2 group
-------------------------------------------------*/
//-------------------------------------------------
// describe_cop2 - build a description of a
// single instruction in the COP2 group
//-------------------------------------------------
static int describe_instruction_cop2(rsp_state *rsp, UINT32 op, opcode_desc *desc)
bool rsp_frontend::describe_cop2(UINT32 op, opcode_desc &desc)
{
switch (RSREG)
{
case 0x00: /* MFCz */
case 0x02: /* CFCz */
desc->regout[0] |= REGFLAG_R(RTREG);
return TRUE;
case 0x00: // MFCz
case 0x02: // CFCz
desc.regout[0] |= REGFLAG_R(RTREG);
return true;
case 0x04: /* MTCz */
case 0x06: /* CTCz */
desc->regin[0] |= REGFLAG_R(RTREG);
return TRUE;
case 0x04: // MTCz
case 0x06: // CTCz
desc.regin[0] |= REGFLAG_R(RTREG);
return true;
}
return FALSE;
return false;
}

View File

@ -15,20 +15,44 @@
#ifndef __RSPFE_H__
#define __RSPFE_H__
#include "rsp.h"
#include "cpu/drcfe.h"
/***************************************************************************
CONSTANTS
***************************************************************************/
//**************************************************************************
// CONSTANTS
//**************************************************************************
/* register flags 0 */
// register flags 0
#define REGFLAG_R(n) (((n) == 0) ? 0 : (1 << (n)))
/***************************************************************************
FUNCTION PROTOTYPES
***************************************************************************/
int rspfe_describe(void *param, opcode_desc *desc, const opcode_desc *prev);
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
class rsp_frontend : public drc_frontend
{
public:
// construction/destruction
rsp_frontend(rsp_state &state, UINT32 window_start, UINT32 window_end, UINT32 max_sequence);
protected:
// required overrides
virtual bool describe(opcode_desc &desc, const opcode_desc *prev);
private:
// internal helpers
bool describe_special(UINT32 op, opcode_desc &desc);
bool describe_regimm(UINT32 op, opcode_desc &desc);
bool describe_cop0(UINT32 op, opcode_desc &desc);
bool describe_cop2(UINT32 op, opcode_desc &desc);
// internal state
rsp_state &m_context;
};
#endif /* __RSPFE_H__ */

View File

@ -21,6 +21,7 @@
#include "cpu/drcfe.h"
#include "cpu/drcuml.h"
#include "cpu/drcumlsh.h"
class sh2_frontend;
#endif
#define SH2_CODE_XOR(a) ((a) ^ NATIVE_ENDIAN_VALUE_LE_BE(2,0))
@ -155,7 +156,7 @@ typedef struct
#ifdef USE_SH2DRC
drccache * cache; /* pointer to the DRC code cache */
drcuml_state * drcuml; /* DRC UML generator state */
drcfe_state * drcfe; /* pointer to the DRC front-end state */
sh2_frontend * drcfe; /* pointer to the DRC front-end state */
UINT32 drcoptions; /* configurable DRC options */
/* internal stuff */
@ -184,6 +185,28 @@ typedef struct
#endif
} sh2_state;
#ifdef USE_SH2DRC
class sh2_frontend : public drc_frontend
{
public:
sh2_frontend(sh2_state &state, UINT32 window_start, UINT32 window_end, UINT32 max_sequence);
protected:
virtual bool describe(opcode_desc &desc, const opcode_desc *prev);
private:
bool describe_group_0(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode);
bool describe_group_2(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode);
bool describe_group_3(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode);
bool describe_group_4(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode);
bool describe_group_6(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode);
bool describe_group_8(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode);
bool describe_group_12(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode);
sh2_state &m_context;
};
#endif
void sh2_common_init(sh2_state *sh2, legacy_cpu_device *device, device_irq_callback irqcallback);
void sh2_recalc_irq(sh2_state *sh2);
void sh2_set_irq_line(sh2_state *sh2, int irqline, int state);

View File

@ -674,13 +674,6 @@ static void cfunc_SUBV(void *param)
static CPU_INIT( sh2 )
{
drcfe_config feconfig =
{
COMPILE_BACKWARDS_BYTES, /* code window start offset = startpc - window_start */
COMPILE_FORWARDS_BYTES, /* code window end offset = startpc + window_end */
COMPILE_MAX_SEQUENCE, /* maximum instructions to include in a sequence */
sh2_describe /* callback to describe a single instruction */
};
sh2_state *sh2 = get_safe_token(device);
drccache *cache;
drcbe_info beinfo;
@ -733,9 +726,7 @@ static CPU_INIT( sh2 )
drcuml_symbol_add(sh2->drcuml, &sh2->mach, sizeof(sh2->macl), "mach");
/* initialize the front-end helper */
if (SINGLE_INSTRUCTION_MODE)
feconfig.max_sequence = 1;
sh2->drcfe = drcfe_init(device, &feconfig, sh2);
sh2->drcfe = auto_alloc(device->machine, sh2_frontend(*sh2, COMPILE_BACKWARDS_BYTES, COMPILE_FORWARDS_BYTES, SINGLE_INSTRUCTION_MODE ? 1 : COMPILE_MAX_SEQUENCE));
/* compute the register parameters */
for (regnum = 0; regnum < 16; regnum++)
@ -779,7 +770,7 @@ static CPU_EXIT( sh2 )
sh2_state *sh2 = get_safe_token(device);
/* clean up the DRC */
drcfe_exit(sh2->drcfe);
auto_free(device->machine, sh2->drcfe);
drcuml_free(sh2->drcuml);
drccache_free(sh2->cache);
}
@ -941,7 +932,7 @@ static void code_compile_block(sh2_state *sh2, UINT8 mode, offs_t pc)
g_profiler.start(PROFILER_DRC_COMPILE);
/* get a description of this sequence */
desclist = drcfe_describe_code(sh2->drcfe, pc);
desclist = sh2->drcfe->describe_code(pc);
if (LOG_UML || LOG_NATIVE)
log_opcode_desc(drcuml, desclist, 0);
@ -953,7 +944,7 @@ static void code_compile_block(sh2_state *sh2, UINT8 mode, offs_t pc)
block = drcuml_block_begin(drcuml, 4096, &errorbuf);
/* loop until we get through all instruction sequences */
for (seqhead = desclist; seqhead != NULL; seqhead = seqlast->next)
for (seqhead = desclist; seqhead != NULL; seqhead = seqlast->next())
{
const opcode_desc *curdesc;
UINT32 nextpc;
@ -963,7 +954,7 @@ static void code_compile_block(sh2_state *sh2, UINT8 mode, offs_t pc)
UML_COMMENT(block, "-------------------------"); // comment
/* determine the last instruction in this sequence */
for (seqlast = seqhead; seqlast != NULL; seqlast = seqlast->next)
for (seqlast = seqhead; seqlast != NULL; seqlast = seqlast->next())
if (seqlast->flags & OPFLAG_END_SEQUENCE)
break;
assert(seqlast != NULL);
@ -1000,7 +991,7 @@ static void code_compile_block(sh2_state *sh2, UINT8 mode, offs_t pc)
}
/* iterate over instructions in the sequence and compile them */
for (curdesc = seqhead; curdesc != seqlast->next; curdesc = curdesc->next)
for (curdesc = seqhead; curdesc != seqlast->next(); curdesc = curdesc->next())
{
generate_sequence_instruction(sh2, block, &compiler, curdesc, 0xffffffff);
}
@ -1020,7 +1011,7 @@ static void code_compile_block(sh2_state *sh2, UINT8 mode, offs_t pc)
generate_update_cycles(sh2, block, &compiler, IMM(nextpc), TRUE); // <subtract cycles>
/* SH2 has no modes */
if (seqlast->next == NULL || seqlast->next->pc != nextpc)
if (seqlast->next() == NULL || seqlast->next()->pc != nextpc)
{
UML_HASHJMP(block, IMM(0), IMM(nextpc), sh2->nocode);
}
@ -1390,7 +1381,7 @@ static void log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, i
drcuml_log_printf(drcuml, "\nDescriptor list @ %08X\n", desclist->pc);
/* output each descriptor */
for ( ; desclist != NULL; desclist = desclist->next)
for ( ; desclist != NULL; desclist = desclist->next())
{
char buffer[100];
@ -1411,8 +1402,8 @@ static void log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, i
drcuml_log_printf(drcuml, "\n");
/* if we have a delay slot, output it recursively */
if (desclist->delay != NULL)
log_opcode_desc(drcuml, desclist->delay, indent + 1);
if (desclist->delay.first() != NULL)
log_opcode_desc(drcuml, desclist->delay.first(), indent + 1);
/* at the end of a sequence add a dividing line */
if (desclist->flags & OPFLAG_END_SEQUENCE)
@ -1524,7 +1515,7 @@ static void generate_checksum_block(sh2_state *sh2, drcuml_block *block, compile
UML_COMMENT(block, "[Validation for %08X]", seqhead->pc); // comment
/* loose verify or single instruction: just compare and fail */
if (!(sh2->drcoptions & SH2DRC_STRICT_VERIFY) || seqhead->next == NULL)
if (!(sh2->drcoptions & SH2DRC_STRICT_VERIFY) || seqhead->next() == NULL)
{
if (!(seqhead->flags & OPFLAG_VIRTUAL_NOOP))
{
@ -1539,7 +1530,7 @@ static void generate_checksum_block(sh2_state *sh2, drcuml_block *block, compile
else
{
#if 0
for (curdesc = seqhead->next; curdesc != seqlast->next; curdesc = curdesc->next)
for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next())
if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP))
{
base = sh2->direct->read_decrypted_ptr(curdesc->physpc, SH2_CODE_XOR(0));
@ -1552,7 +1543,7 @@ static void generate_checksum_block(sh2_state *sh2, drcuml_block *block, compile
void *base = sh2->direct->read_decrypted_ptr(seqhead->physpc, SH2_CODE_XOR(0));
UML_LOAD(block, IREG(0), base, IMM(0), WORD); // load i0,base,word
sum += seqhead->opptr.w[0];
for (curdesc = seqhead->next; curdesc != seqlast->next; curdesc = curdesc->next)
for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next())
if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP))
{
base = sh2->direct->read_decrypted_ptr(curdesc->physpc, SH2_CODE_XOR(0));
@ -1662,7 +1653,7 @@ static void generate_delay_slot(sh2_state *sh2, drcuml_block *block, compiler_st
/* compile the delay slot using temporary compiler state */
assert(desc->delay != NULL);
generate_sequence_instruction(sh2, block, &compiler_temp, desc->delay, ovrpc); // <next instruction>
generate_sequence_instruction(sh2, block, &compiler_temp, desc->delay.first(), ovrpc); // <next instruction>
/* update the label */
compiler->labelnum = compiler_temp.labelnum;

File diff suppressed because it is too large Load Diff