mirror of
https://github.com/holub/mame
synced 2025-07-03 17:08:39 +03:00
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:
parent
68ebcf0254
commit
9e5207ce91
@ -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);
|
||||
}
|
||||
|
@ -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__ */
|
||||
|
@ -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
@ -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__ */
|
||||
|
@ -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
@ -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__ */
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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__ */
|
||||
|
@ -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);
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user