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

frontend by deriving from drc_frontend and implementing the
describe method.

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

View File

@ -4,9 +4,36 @@
Generic dynamic recompiler frontend structures and utilities. Generic dynamic recompiler frontend structures and utilities.
****************************************************************************
Copyright Aaron Giles Copyright Aaron Giles
Released for general non-commercial use under the MAME license All rights reserved.
Visit http://mamedev.org for licensing and usage restrictions.
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" #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 */ // an entry that maps branches for our code walking
typedef struct _pc_stack_entry pc_stack_entry; struct pc_stack_entry
struct _pc_stack_entry
{ {
offs_t targetpc; offs_t targetpc;
offs_t srcpc; 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 */ // release any descriptions we've accumulated
desc->next = drcfe->desc_free_list; release_descriptions();
drcfe->desc_free_list = desc;
// 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
//-------------------------------------------------
/*************************************************************************** const opcode_desc *drc_frontend::describe_code(offs_t startpc)
CORE IMPLEMENTATION
***************************************************************************/
/*-------------------------------------------------
drcfe_init - initializate the drcfe state
-------------------------------------------------*/
drcfe_state *drcfe_init(device_t *cpu, const drcfe_config *config, void *param)
{ {
drcfe_state *drcfe; // release any descriptions we've accumulated
release_descriptions();
/* allocate some memory to hold the state */ // add the initial PC to the stack
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);
pc_stack_entry pcstack[MAX_STACK_DEPTH]; pc_stack_entry pcstack[MAX_STACK_DEPTH];
pc_stack_entry *pcstackptr = &pcstack[0]; 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->srcpc = 0;
pcstackptr->targetpc = startpc; pcstackptr->targetpc = startpc;
pcstackptr++; 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]) while (pcstackptr != &pcstack[0])
{ {
// if we've already hit this PC, just mark it a branch target and continue
pc_stack_entry *curstack = --pcstackptr; pc_stack_entry *curstack = --pcstackptr;
opcode_desc *curdesc; opcode_desc *curdesc = m_desc_array[curstack->targetpc - minpc];
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];
if (curdesc != NULL) if (curdesc != NULL)
{ {
curdesc->flags |= OPFLAG_IS_BRANCH_TARGET; curdesc->flags |= OPFLAG_IS_BRANCH_TARGET;
/* if the branch crosses a page boundary, mark the target as needing to revalidate */ // 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 (m_pageshift != 0 && ((curstack->srcpc ^ curdesc->pc) >> m_pageshift) != 0)
curdesc->flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION; curdesc->flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION;
/* continue processing */ // continue processing
continue; continue;
} }
/* loop until we exit the block */ // 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) 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 */ // allocate a new description and describe this instruction
drcfe->desc_array[curpc - minpc] = curdesc = describe_one(drcfe, curpc, curdesc); 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) if (curpc == curstack->targetpc)
curdesc->flags |= OPFLAG_IS_BRANCH_TARGET; 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) if (curdesc->flags & OPFLAG_COMPILER_PAGE_FAULT)
break; break;
/* if we are the first instruction in the whole window, we must validate the TLB */ // if we are the first instruction in the whole window, we must validate the TLB
if (curpc == startpc && drcfe->pageshift != 0) if (curpc == startpc && m_pageshift != 0)
curdesc->flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION; 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]) if ((curdesc->flags & OPFLAG_IS_BRANCH) && curdesc->targetpc >= minpc && curdesc->targetpc < maxpc && pcstackptr < &pcstack[MAX_STACK_DEPTH])
{ {
curdesc->flags |= OPFLAG_INTRABLOCK_BRANCH; curdesc->flags |= OPFLAG_INTRABLOCK_BRANCH;
@ -242,131 +170,113 @@ const opcode_desc *drcfe_describe_code(drcfe_state *drcfe, offs_t startpc)
pcstackptr++; pcstackptr++;
} }
/* if we're done, we're done */ // if we're done, we're done
if (curdesc->flags & OPFLAG_END_SEQUENCE) if (curdesc->flags & OPFLAG_END_SEQUENCE)
break; break;
} }
} }
/* now build the list of descriptions in order */ // now build the list of descriptions in order
/* first from startpc -> maxpc, then from minpc -> startpc */ // first from startpc -> maxpc, then from minpc -> startpc
tailptr = build_sequence(drcfe, &drcfe->desc_live_list, startpc - minpc, maxpc - minpc, OPFLAG_REDISPATCH); build_sequence(startpc - minpc, maxpc - minpc, OPFLAG_REDISPATCH);
tailptr = build_sequence(drcfe, tailptr, minpc - minpc, startpc - minpc, OPFLAG_RETURN_TO_START); build_sequence(minpc - minpc, startpc - minpc, OPFLAG_RETURN_TO_START);
return drcfe->desc_live_list; return m_desc_live_list.first();
} }
//-------------------------------------------------
// describe_one - describe a single instruction,
// recursively describing opcodes in delay
// slots of branches as well
//-------------------------------------------------
/*************************************************************************** opcode_desc *drc_frontend::describe_one(offs_t curpc, const opcode_desc *prevdesc)
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 *desc = desc_alloc(drcfe); // initialize the description
opcode_desc *desc = m_desc_allocator.alloc();
/* initialize the description */
memset(desc, 0, sizeof(*desc)); memset(desc, 0, sizeof(*desc));
desc->pc = curpc; desc->pc = curpc;
desc->physpc = curpc; desc->physpc = curpc;
desc->targetpc = BRANCH_TARGET_DYNAMIC; desc->targetpc = BRANCH_TARGET_DYNAMIC;
/* call the callback to describe an instruction */ // call the callback to describe an instruction
if (!(*drcfe->describe)(drcfe->param, desc, prevdesc)) if (!describe(*desc, prevdesc))
{ {
desc->flags |= OPFLAG_WILL_CAUSE_EXCEPTION | OPFLAG_INVALID_OPCODE; desc->flags |= OPFLAG_WILL_CAUSE_EXCEPTION | OPFLAG_INVALID_OPCODE;
return desc; return desc;
} }
/* validate the TLB if we are exactly at the start of a page, or if we cross a page boundary */ // 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) if (m_pageshift != 0 && (((curpc - 1) ^ (curpc + desc->length - 1)) >> m_pageshift) != 0)
desc->flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION; desc->flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION;
/* validate stuff */ // validate stuff
assert(desc->length > 0 || (desc->flags & OPFLAG_VIRTUAL_NOOP) != 0); 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) if (desc->flags & OPFLAG_IS_BRANCH)
{ {
opcode_desc **tailptr = &desc->delay; // iterate over slots and describe them
offs_t delaypc = curpc + desc->length; offs_t delaypc = curpc + desc->length;
opcode_desc *prev = desc; opcode_desc *prev = desc;
UINT8 slotnum; for (UINT8 slotnum = 0; slotnum < desc->delayslots; slotnum++)
/* iterate over slots and describe them */
for (slotnum = 0; slotnum < desc->delayslots; slotnum++)
{ {
/* recursively describe the next instruction */ // recursively describe the next instruction
*tailptr = describe_one(drcfe, delaypc, prev); opcode_desc *delaydesc = describe_one(delaypc, prev);
if (*tailptr == NULL) 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; break;
/* set the delay slot flag and a pointer back to the original branch */ // otherwise, advance
(*tailptr)->flags |= OPFLAG_IN_DELAY_SLOT; delaypc += delaydesc->length;
(*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;
} }
} }
return desc; return desc;
} }
/*------------------------------------------------- //-------------------------------------------------
build_sequence - build an ordered sequence // build_sequence - build an ordered sequence
of instructions // 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 consecutive = 0;
int seqstart = -1; int seqstart = -1;
int skipsleft = 0; int skipsleft = 0;
int descnum; for (int descnum = start; descnum < end; descnum++)
if (m_desc_array[descnum] != NULL)
/* 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)
{ {
opcode_desc *curdesc = drcfe->desc_array[descnum]; // determine the next instruction, taking skips into account
opcode_desc *nextdesc = NULL; opcode_desc *curdesc = m_desc_array[descnum];
int nextdescnum; int nextdescnum = descnum + curdesc->length;
UINT8 skipnum; opcode_desc *nextdesc = (nextdescnum < end) ? m_desc_array[nextdescnum] : NULL;
for (UINT8 skipnum = 0; skipnum < curdesc->skipslots && nextdesc != NULL; 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++)
{ {
nextdescnum = nextdescnum + nextdesc->length; 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) 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; curdesc->flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION;
seqstart = descnum; 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) if (nextdesc == NULL)
{ {
curdesc->flags |= OPFLAG_END_SEQUENCE; curdesc->flags |= OPFLAG_END_SEQUENCE;
@ -374,134 +284,118 @@ static opcode_desc **build_sequence(drcfe_state *drcfe, opcode_desc **tailptr, i
curdesc->flags |= endflag; curdesc->flags |= endflag;
} }
/* otherwise, do some analysis based on the next instruction */ // otherwise, do some analysis based on the next instruction
else else
{ {
opcode_desc *scandesc = NULL; // if there are instructions between us and the next instruction, we must end our sequence here
int scandescnum; int scandescnum;
opcode_desc *scandesc = NULL;
/* if there are instructions between us and the next instruction, we must end our sequence here */
for (scandescnum = descnum + 1; scandescnum < end; scandescnum++) for (scandescnum = descnum + 1; scandescnum < end; scandescnum++)
{ {
scandesc = drcfe->desc_array[scandescnum]; scandesc = m_desc_array[scandescnum];
if (scandesc != NULL || scandesc == nextdesc) if (scandesc != NULL || scandesc == nextdesc)
break; break;
} }
if (scandesc != nextdesc) if (scandesc != nextdesc)
curdesc->flags |= OPFLAG_END_SEQUENCE; 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) if (nextdesc->flags & OPFLAG_IS_BRANCH_TARGET)
curdesc->flags |= OPFLAG_END_SEQUENCE; curdesc->flags |= OPFLAG_END_SEQUENCE;
} }
/* if we exceed the maximum consecutive count, cut off the sequence */ // if we exceed the maximum consecutive count, cut off the sequence
if (++consecutive >= drcfe->max_sequence) if (++consecutive >= m_max_sequence)
curdesc->flags |= OPFLAG_END_SEQUENCE; curdesc->flags |= OPFLAG_END_SEQUENCE;
if (curdesc->flags & OPFLAG_END_SEQUENCE) if (curdesc->flags & OPFLAG_END_SEQUENCE)
consecutive = 0; 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) 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 }; 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) if (seqstart != -1)
for (backdesc = descnum; backdesc != seqstart - 1; backdesc--) for (int backdesc = descnum; backdesc != seqstart - 1; backdesc--)
if (drcfe->desc_array[backdesc] != NULL) if (m_desc_array[backdesc] != NULL)
accumulate_required_backwards(drcfe->desc_array[backdesc], reqmask); accumulate_required_backwards(*m_desc_array[backdesc], reqmask);
/* reset the register states */ // reset the register states
seqstart = -1; seqstart = -1;
} }
/* if we have instructions remaining to be skipped, and this instruction is a branch target */ // if we have instructions remaining to be skipped, and this instruction is a branch target
/* belay the skip order */ // belay the skip order
if (skipsleft > 0 && (curdesc->flags & OPFLAG_IS_BRANCH_TARGET)) if (skipsleft > 0 && (curdesc->flags & OPFLAG_IS_BRANCH_TARGET))
skipsleft = 0; 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) if (skipsleft == 0)
{ m_desc_live_list.append(*curdesc);
*tailptr = curdesc;
tailptr = &curdesc->next;
curdesc->prev = prev;
prev = curdesc;
}
else else
desc_free(drcfe, curdesc); m_desc_allocator.reclaim(*curdesc);
/* if the current instruction starts skipping, reset our skip count */ // if the current instruction starts skipping, reset our skip count
/* otherwise, just decrement */ // otherwise, just decrement
if (curdesc->skipslots > 0) if (curdesc->skipslots > 0)
skipsleft = curdesc->skipslots; skipsleft = curdesc->skipslots;
else if (skipsleft > 0) else if (skipsleft > 0)
skipsleft--; skipsleft--;
} }
/* zap the array */ // zap the array
memset(&drcfe->desc_array[start], 0, (end - start) * sizeof(drcfe->desc_array[0])); memset(&m_desc_array[start], 0, (end - start) * sizeof(m_desc_array[0]));
/* return the final tailptr */
return tailptr;
} }
/*------------------------------------------------- //-------------------------------------------------
accumulate_required_backwards - recursively // accumulate_required_backwards - recursively
accumulate live register liveness information // accumulate live register liveness information
walking in a backwards direction // 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 */ // recursively handle delay slots
if (desc->delay != NULL) if (desc.delay.first() != NULL)
accumulate_required_backwards(desc->delay, reqmask); accumulate_required_backwards(*desc.delay.first(), reqmask);
/* if this is a branch, we have to reset our requests */ // if this is a branch, we have to reset our requests
if (desc->flags & OPFLAG_IS_BRANCH) if (desc.flags & OPFLAG_IS_BRANCH)
reqmask[0] = reqmask[1] = reqmask[2] = reqmask[3] = 0xffffffff; reqmask[0] = reqmask[1] = reqmask[2] = reqmask[3] = 0xffffffff;
/* determine the required registers */ // determine the required registers
desc->regreq[0] = desc->regout[0] & reqmask[0]; desc.regreq[0] = desc.regout[0] & reqmask[0];
desc->regreq[1] = desc->regout[1] & reqmask[1]; desc.regreq[1] = desc.regout[1] & reqmask[1];
desc->regreq[2] = desc->regout[2] & reqmask[2]; desc.regreq[2] = desc.regout[2] & reqmask[2];
desc->regreq[3] = desc->regout[3] & reqmask[3]; desc.regreq[3] = desc.regout[3] & reqmask[3];
/* any registers modified by this instruction aren't required upstream until referenced */ // any registers modified by this instruction aren't required upstream until referenced
reqmask[0] &= ~desc->regout[0]; reqmask[0] &= ~desc.regout[0];
reqmask[1] &= ~desc->regout[1]; reqmask[1] &= ~desc.regout[1];
reqmask[2] &= ~desc->regout[2]; reqmask[2] &= ~desc.regout[2];
reqmask[3] &= ~desc->regout[3]; reqmask[3] &= ~desc.regout[3];
/* any registers required by this instruction now get marked required */ // any registers required by this instruction now get marked required
reqmask[0] |= desc->regin[0]; reqmask[0] |= desc.regin[0];
reqmask[1] |= desc->regin[1]; reqmask[1] |= desc.regin[1];
reqmask[2] |= desc->regin[2]; reqmask[2] |= desc.regin[2];
reqmask[3] |= desc->regin[3]; reqmask[3] |= desc.regin[3];
} }
/*------------------------------------------------- //-------------------------------------------------
release_descriptions - release any // release_descriptions - release any
descriptions we've allocated back to the // descriptions we've allocated back to the
free list // free list
------------------------------------------------*/ //------------------------------------------------
static void release_descriptions(drcfe_state *drcfe, opcode_desc *desc) void drc_frontend::release_descriptions()
{ {
/* loop while we still have valid entries */ // release all delay slots first
while (desc != NULL) for (opcode_desc *curdesc = m_desc_live_list.first(); curdesc != NULL; curdesc = curdesc->next())
{ m_desc_allocator.reclaim_all(curdesc->delay);
opcode_desc *freeme = desc;
// reclaim all the descriptors
/* recursively release delay slots */ m_desc_allocator.reclaim_all(m_desc_live_list);
if (desc->delay != NULL)
release_descriptions(drcfe, desc->delay);
desc = desc->next;
desc_free(drcfe, freeme);
}
} }

View File

@ -4,9 +4,36 @@
Generic dynamic recompiler frontend structures and utilities. Generic dynamic recompiler frontend structures and utilities.
****************************************************************************
Copyright Aaron Giles Copyright Aaron Giles
Released for general non-commercial use under the MAME license All rights reserved.
Visit http://mamedev.org for licensing and usage restrictions.
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__ #define __DRCFE_H__
/*************************************************************************** //**************************************************************************
CONSTANTS // CONSTANTS
***************************************************************************/ //**************************************************************************
/* this defines a branch targetpc that is dynamic at runtime */ // this defines a branch targetpc that is dynamic at runtime
#define BRANCH_TARGET_DYNAMIC (~0) const offs_t BRANCH_TARGET_DYNAMIC = ~0;
/* opcode branch flags */ // opcode branch flags
#define OPFLAG_IS_UNCONDITIONAL_BRANCH 0x00000001 /* instruction is unconditional branch */ const UINT32 OPFLAG_IS_UNCONDITIONAL_BRANCH = 0x00000001; // instruction is unconditional branch
#define OPFLAG_IS_CONDITIONAL_BRANCH 0x00000002 /* instruction is conditional branch */ const UINT32 OPFLAG_IS_CONDITIONAL_BRANCH = 0x00000002; // instruction is conditional branch
#define OPFLAG_IS_BRANCH (OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_IS_CONDITIONAL_BRANCH) const UINT32 OPFLAG_IS_BRANCH = (OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_IS_CONDITIONAL_BRANCH);
#define OPFLAG_IS_BRANCH_TARGET 0x00000004 /* instruction is the target of a branch */ const UINT32 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 */ const UINT32 OPFLAG_IN_DELAY_SLOT = 0x00000008; // instruction is in the delay slot of a branch
#define OPFLAG_INTRABLOCK_BRANCH 0x00000010 /* instruction branches within the block */ const UINT32 OPFLAG_INTRABLOCK_BRANCH = 0x00000010; // instruction branches within the block
/* opcode exception flags */ // opcode exception flags
#define OPFLAG_CAN_TRIGGER_SW_INT 0x00000020 /* instruction can trigger a software interrupt */ const UINT32 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 */ const UINT32 OPFLAG_CAN_EXPOSE_EXTERNAL_INT = 0x00000040; // instruction can expose an external interrupt
#define OPFLAG_CAN_CAUSE_EXCEPTION 0x00000080 /* instruction may generate exception */ const UINT32 OPFLAG_CAN_CAUSE_EXCEPTION = 0x00000080; // instruction may generate exception
#define OPFLAG_WILL_CAUSE_EXCEPTION 0x00000100 /* instruction will generate exception */ const UINT32 OPFLAG_WILL_CAUSE_EXCEPTION = 0x00000100; // instruction will generate exception
#define OPFLAG_PRIVILEGED 0x00000200 /* instruction is privileged */ const UINT32 OPFLAG_PRIVILEGED = 0x00000200; // instruction is privileged
/* opcode virtual->physical translation flags */ // opcode virtual->physical translation flags
#define OPFLAG_VALIDATE_TLB 0x00000400 /* instruction must validate TLB before execution */ const UINT32 OPFLAG_VALIDATE_TLB = 0x00000400; // instruction must validate TLB before execution
#define OPFLAG_MODIFIES_TRANSLATION 0x00000800 /* instruction modifies the TLB */ const UINT32 OPFLAG_MODIFIES_TRANSLATION = 0x00000800; // instruction modifies the TLB
#define OPFLAG_COMPILER_PAGE_FAULT 0x00001000 /* compiler hit a page fault when parsing */ const UINT32 OPFLAG_COMPILER_PAGE_FAULT = 0x00001000; // compiler hit a page fault when parsing
#define OPFLAG_COMPILER_UNMAPPED 0x00002000 /* compiler hit unmapped memory when parsing */ const UINT32 OPFLAG_COMPILER_UNMAPPED = 0x00002000; // compiler hit unmapped memory when parsing
/* opcode flags */ // opcode flags
#define OPFLAG_INVALID_OPCODE 0x00004000 /* instruction is invalid */ const UINT32 OPFLAG_INVALID_OPCODE = 0x00004000; // instruction is invalid
#define OPFLAG_VIRTUAL_NOOP 0x00008000 /* instruction is a virtual no-op */ const UINT32 OPFLAG_VIRTUAL_NOOP = 0x00008000; // instruction is a virtual no-op
/* opcode sequence flow flags */ // opcode sequence flow flags
#define OPFLAG_REDISPATCH 0x00010000 /* instruction must redispatch after completion */ const UINT32 OPFLAG_REDISPATCH = 0x00010000; // instruction must redispatch after completion
#define OPFLAG_RETURN_TO_START 0x00020000 /* instruction must jump back to the beginning after completion */ const UINT32 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 */ const UINT32 OPFLAG_END_SEQUENCE = 0x00040000; // this is the last instruction in a sequence
#define OPFLAG_CAN_CHANGE_MODES 0x00080000 /* instruction can change modes */ const UINT32 OPFLAG_CAN_CHANGE_MODES = 0x00080000; // instruction can change modes
/* execution semantics */ // execution semantics
#define OPFLAG_READS_MEMORY 0x00100000 /* instruction reads memory */ const UINT32 OPFLAG_READS_MEMORY = 0x00100000; // instruction reads memory
#define OPFLAG_WRITES_MEMORY 0x00200000 /* instruction writes memory */ const UINT32 OPFLAG_WRITES_MEMORY = 0x00200000; // instruction writes memory
/*************************************************************************** //**************************************************************************
TYPE DEFINITIONS // TYPE DEFINITIONS
***************************************************************************/ //**************************************************************************
/* opaque internal state */ // description of a given opcode
typedef struct _drcfe_state drcfe_state; struct opcode_desc
/* description of a given opcode */
typedef struct _opcode_desc opcode_desc;
struct _opcode_desc
{ {
/* links to other descriptions */ opcode_desc *next() const { return m_next; }
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 */
/* information about the current PC */ // links to other descriptions
offs_t pc; /* PC of this opcode */ opcode_desc * m_next; // pointer to next description
offs_t physpc; /* physical PC of this opcode */ opcode_desc * branch; // pointer back to branch description for delay slots
offs_t targetpc; /* target PC if we are a branch, or BRANCH_TARGET_DYNAMIC */ 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 union
{ {
UINT8 b[16]; UINT8 b[16];
UINT16 w[8]; UINT16 w[8];
UINT32 l[4]; UINT32 l[4];
UINT64 q[2]; UINT64 q[2];
} opptr; /* pointer to opcode memory */ } opptr; // pointer to opcode memory
/* information about this instruction's execution */ // information about this instruction's execution
UINT8 length; /* length in bytes of this opcode */ UINT8 length; // length in bytes of this opcode
UINT8 delayslots; /* number of delay slots (for branches) */ UINT8 delayslots; // number of delay slots (for branches)
UINT8 skipslots; /* number of skip slots (for branches) */ UINT8 skipslots; // number of skip slots (for branches)
UINT32 flags; /* OPFLAG_* opcode flags */ UINT32 flags; // OPFLAG_* opcode flags
UINT32 cycles; /* number of cycles needed to execute */ UINT32 cycles; // number of cycles needed to execute
/* register usage information */ // register usage information
UINT32 regin[4]; /* input registers */ UINT32 regin[4]; // input registers
UINT32 regout[4]; /* output registers */ UINT32 regout[4]; // output registers
UINT32 regreq[4]; /* required output registers */ UINT32 regreq[4]; // required output registers
}; };
/* callback function that is used to describe a single opcode */ // DRC frontend state
typedef int (*drcfe_describe_func)(void *param, opcode_desc *desc, const opcode_desc *prev); class drc_frontend
/* description of a given opcode */
typedef struct _drcfe_config drcfe_config;
struct _drcfe_config
{ {
UINT32 window_start; /* code window start offset = startpc - window_start */ public:
UINT32 window_end; /* code window end offset = startpc + window_end */ // construction/destruction
UINT32 max_sequence; /* maximum instructions to include in a sequence */ drc_frontend(device_t &cpu, UINT32 window_start, UINT32 window_end, UINT32 max_sequence);
drcfe_describe_func describe; /* callback to describe a single instruction */ 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__ */ #endif /* __DRCFE_H__ */

View File

@ -4,9 +4,36 @@
Universal machine language-based MIPS III/IV emulator. Universal machine language-based MIPS III/IV emulator.
****************************************************************************
Copyright Aaron Giles Copyright Aaron Giles
Released for general non-commercial use under the MAME license All rights reserved.
Visit http://mamedev.org for licensing and usage restrictions.
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 */ /* core state */
drccache * cache; /* pointer to the DRC code cache */ drccache * cache; /* pointer to the DRC code cache */
drcuml_state * drcuml; /* DRC UML generator state */ 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 */ UINT32 drcoptions; /* configurable DRC options */
/* internal stuff */ /* 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) 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; mips3_state *mips3;
drccache *cache; drccache *cache;
drcbe_info beinfo; 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"); drcuml_symbol_add(mips3->impstate->drcuml, &mips3->impstate->fpmode, sizeof(mips3->impstate->fpmode), "fpmode");
/* initialize the front-end helper */ /* initialize the front-end helper */
if (SINGLE_INSTRUCTION_MODE) mips3->impstate->drcfe = auto_alloc(device->machine, mips3_frontend(*mips3, COMPILE_BACKWARDS_BYTES, COMPILE_FORWARDS_BYTES, SINGLE_INSTRUCTION_MODE ? 1 : COMPILE_MAX_SEQUENCE));
feconfig.max_sequence = 1;
mips3->impstate->drcfe = drcfe_init(device, &feconfig, mips3);
/* allocate memory for cache-local state and initialize it */ /* allocate memory for cache-local state and initialize it */
memcpy(mips3->impstate->fpmode, fpmode_source, sizeof(fpmode_source)); memcpy(mips3->impstate->fpmode, fpmode_source, sizeof(fpmode_source));
@ -546,7 +564,7 @@ static CPU_EXIT( mips3 )
mips3com_exit(mips3); mips3com_exit(mips3);
/* clean up the DRC */ /* clean up the DRC */
drcfe_exit(mips3->impstate->drcfe); auto_free(device->machine, mips3->impstate->drcfe);
drcuml_free(mips3->impstate->drcuml); drcuml_free(mips3->impstate->drcuml);
drccache_free(mips3->impstate->cache); 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); g_profiler.start(PROFILER_DRC_COMPILE);
/* get a description of this sequence */ /* 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) if (LOG_UML || LOG_NATIVE)
log_opcode_desc(drcuml, desclist, 0); 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); block = drcuml_block_begin(drcuml, 4096, &errorbuf);
/* loop until we get through all instruction sequences */ /* 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; const opcode_desc *curdesc;
UINT32 nextpc; UINT32 nextpc;
@ -767,7 +785,7 @@ static void code_compile_block(mips3_state *mips3, UINT8 mode, offs_t pc)
UML_COMMENT(block, "-------------------------"); // comment UML_COMMENT(block, "-------------------------"); // comment
/* determine the last instruction in this sequence */ /* 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) if (seqlast->flags & OPFLAG_END_SEQUENCE)
break; break;
assert(seqlast != NULL); 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 UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc | 0x80000000
/* iterate over instructions in the sequence and compile them */ /* 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); generate_sequence_instruction(mips3, block, &compiler, curdesc);
/* if we need to return to the start, do it */ /* 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) if (seqlast->flags & OPFLAG_CAN_CHANGE_MODES)
UML_HASHJMP(block, MEM(&mips3->impstate->mode), IMM(nextpc), mips3->impstate->nocode); UML_HASHJMP(block, MEM(&mips3->impstate->mode), IMM(nextpc), mips3->impstate->nocode);
// hashjmp <mode>,nextpc,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); UML_HASHJMP(block, IMM(mips3->impstate->mode), IMM(nextpc), mips3->impstate->nocode);
// hashjmp <mode>,nextpc,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 UML_COMMENT(block, "[Validation for %08X]", seqhead->pc); // comment
/* loose verify or single instruction: just compare and fail */ /* 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)) if (!(seqhead->flags & OPFLAG_VIRTUAL_NOOP))
{ {
@ -1536,7 +1554,7 @@ static void generate_checksum_block(mips3_state *mips3, drcuml_block *block, com
else else
{ {
#if 0 #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)) if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP))
{ {
void *base = mips3->direct->read_decrypted_ptr(seqhead->physpc); 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); void *base = mips3->direct->read_decrypted_ptr(seqhead->physpc);
UML_LOAD(block, IREG(0), base, IMM(0), DWORD); // load i0,base,0,dword UML_LOAD(block, IREG(0), base, IMM(0), DWORD); // load i0,base,0,dword
sum += seqhead->opptr.l[0]; 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)) if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP))
{ {
base = mips3->direct->read_decrypted_ptr(curdesc->physpc); 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 UML_ADD(block, IREG(0), IREG(0), IREG(1)); // add i0,i0,i1
sum += curdesc->opptr.l[0]; 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_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 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 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 UML_DMOV(block, R64(linkreg), IMM((INT32)(desc->pc + 8))); // dmov <linkreg>,desc->pc + 8
/* compile the delay slot using temporary compiler state */ /* compile the delay slot using temporary compiler state */
assert(desc->delay != NULL); assert(desc->delay.first() != NULL);
generate_sequence_instruction(mips3, block, &compiler_temp, desc->delay); // <next instruction> generate_sequence_instruction(mips3, block, &compiler_temp, desc->delay.first()); // <next instruction>
/* update the cycles and jump through the hash table to the target */ /* update the cycles and jump through the hash table to the target */
if (desc->targetpc != BRANCH_TARGET_DYNAMIC) 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); drcuml_log_printf(drcuml, "\nDescriptor list @ %08X\n", desclist->pc);
/* output each descriptor */ /* output each descriptor */
for ( ; desclist != NULL; desclist = desclist->next) for ( ; desclist != NULL; desclist = desclist->next())
{ {
char buffer[100]; 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"); drcuml_log_printf(drcuml, "\n");
/* if we have a delay slot, output it recursively */ /* if we have a delay slot, output it recursively */
if (desclist->delay != NULL) if (desclist->delay.first() != NULL)
log_opcode_desc(drcuml, desclist->delay, indent + 1); log_opcode_desc(drcuml, desclist->delay.first(), indent + 1);
/* at the end of a sequence add a dividing line */ /* at the end of a sequence add a dividing line */
if (desclist->flags & OPFLAG_END_SEQUENCE) if (desclist->flags & OPFLAG_END_SEQUENCE)

File diff suppressed because it is too large Load Diff

View File

@ -4,9 +4,36 @@
Front-end for MIPS3 recompiler Front-end for MIPS3 recompiler
****************************************************************************
Copyright Aaron Giles Copyright Aaron Giles
Released for general non-commercial use under the MAME license All rights reserved.
Visit http://mamedev.org for licensing and usage restrictions.
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__ #ifndef __MIPS3FE_H__
#define __MIPS3FE_H__ #define __MIPS3FE_H__
#include "mips3com.h"
#include "cpu/drcfe.h" #include "cpu/drcfe.h"
/*************************************************************************** //**************************************************************************
CONSTANTS // MACROS
***************************************************************************/ //**************************************************************************
/* register flags 0 */ // register flags 0
#define REGFLAG_R(n) (((n) == 0) ? 0 : (1 << (n))) #define REGFLAG_R(n) (((n) == 0) ? 0 : (1 << (n)))
/* register flags 1 */ // register flags 1
#define REGFLAG_CPR1(n) (1 << (n)) #define REGFLAG_CPR1(n) (1 << (n))
/* register flags 2 */ // register flags 2
#define REGFLAG_LO (1 << 0) #define REGFLAG_LO (1 << 0)
#define REGFLAG_HI (1 << 1) #define REGFLAG_HI (1 << 1)
#define REGFLAG_FCC (1 << 2) #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__ */ #endif /* __MIPS3FE_H__ */

View File

@ -165,7 +165,7 @@ struct _ppcimp_state
/* core state */ /* core state */
drccache * cache; /* pointer to the DRC code cache */ drccache * cache; /* pointer to the DRC code cache */
drcuml_state * drcuml; /* DRC UML generator state */ 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 */ UINT32 drcoptions; /* configurable DRC options */
/* parameters for subroutines */ /* 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) 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; powerpc_state *ppc;
drcbe_info beinfo; drcbe_info beinfo;
UINT32 flags = 0; 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"); 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 */ /* initialize the front-end helper */
if (SINGLE_INSTRUCTION_MODE) ppc->impstate->drcfe = auto_alloc(device->machine, ppc_frontend(*ppc, COMPILE_BACKWARDS_BYTES, COMPILE_FORWARDS_BYTES, SINGLE_INSTRUCTION_MODE ? 1 : COMPILE_MAX_SEQUENCE));
feconfig.max_sequence = 1;
ppc->impstate->drcfe = drcfe_init(device, &feconfig, ppc);
/* initialize the implementation state tables */ /* initialize the implementation state tables */
memcpy(ppc->impstate->fpmode, fpmode_source, sizeof(fpmode_source)); memcpy(ppc->impstate->fpmode, fpmode_source, sizeof(fpmode_source));
@ -738,7 +729,7 @@ static CPU_EXIT( ppcdrc )
ppccom_exit(ppc); ppccom_exit(ppc);
/* clean up the DRC */ /* clean up the DRC */
drcfe_exit(ppc->impstate->drcfe); auto_free(device->machine, ppc->impstate->drcfe);
drcuml_free(ppc->impstate->drcuml); drcuml_free(ppc->impstate->drcuml);
drccache_free(ppc->impstate->cache); 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); g_profiler.start(PROFILER_DRC_COMPILE);
/* get a description of this sequence */ /* 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) if (LOG_UML || LOG_NATIVE)
log_opcode_desc(drcuml, desclist, 0); 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); block = drcuml_block_begin(drcuml, 4096, &errorbuf);
/* loop until we get through all instruction sequences */ /* 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; const opcode_desc *curdesc;
UINT32 nextpc; UINT32 nextpc;
@ -972,7 +963,7 @@ static void code_compile_block(powerpc_state *ppc, UINT8 mode, offs_t pc)
UML_COMMENT(block, "-------------------------"); // comment UML_COMMENT(block, "-------------------------"); // comment
/* determine the last instruction in this sequence */ /* 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) if (seqlast->flags & OPFLAG_END_SEQUENCE)
break; break;
assert(seqlast != NULL); 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 UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc | 0x80000000
/* iterate over instructions in the sequence and compile them */ /* 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> generate_sequence_instruction(ppc, block, &compiler, curdesc); // <instruction>
/* if we need to return to the start, do it */ /* 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 the last instruction can change modes, use a variable mode; otherwise, assume the same mode */
if (seqlast->flags & OPFLAG_CAN_CHANGE_MODES) if (seqlast->flags & OPFLAG_CAN_CHANGE_MODES)
UML_HASHJMP(block, MEM(&ppc->impstate->mode), IMM(nextpc), ppc->impstate->nocode);// hashjmp <mode>,nextpc,nocode 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 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 UML_COMMENT(block, "[Validation for %08X]", seqhead->pc); // comment
/* loose verify or single instruction: just compare and fail */ /* 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)) if (!(seqhead->flags & OPFLAG_VIRTUAL_NOOP))
{ {
@ -2108,7 +2099,7 @@ static void generate_checksum_block(powerpc_state *ppc, drcuml_block *block, com
else else
{ {
#if 0 #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)) if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP))
{ {
void *base = ppc->direct->read_decrypted_ptr(seqhead->physpc, ppc->codexor); 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); void *base = ppc->direct->read_decrypted_ptr(seqhead->physpc, ppc->codexor);
UML_LOAD(block, IREG(0), base, IMM(0), DWORD); // load i0,base,dword UML_LOAD(block, IREG(0), base, IMM(0), DWORD); // load i0,base,dword
sum += seqhead->opptr.l[0]; 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)) if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP))
{ {
base = ppc->direct->read_decrypted_ptr(curdesc->physpc, ppc->codexor); 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); drcuml_log_printf(drcuml, "\nDescriptor list @ %08X\n", desclist->pc);
/* output each descriptor */ /* output each descriptor */
for ( ; desclist != NULL; desclist = desclist->next) for ( ; desclist != NULL; desclist = desclist->next())
{ {
char buffer[100]; 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"); drcuml_log_printf(drcuml, "\n");
/* if we have a delay slot, output it recursively */ /* if we have a delay slot, output it recursively */
if (desclist->delay != NULL) if (desclist->delay.first() != NULL)
log_opcode_desc(drcuml, desclist->delay, indent + 1); log_opcode_desc(drcuml, desclist->delay.first(), indent + 1);
/* at the end of a sequence add a dividing line */ /* at the end of a sequence add a dividing line */
if (desclist->flags & OPFLAG_END_SEQUENCE) if (desclist->flags & OPFLAG_END_SEQUENCE)

File diff suppressed because it is too large Load Diff

View File

@ -4,34 +4,62 @@
Front-end for PowerPC recompiler Front-end for PowerPC recompiler
****************************************************************************
Copyright Aaron Giles Copyright Aaron Giles
Released for general non-commercial use under the MAME license All rights reserved.
Visit http://mamedev.org for licensing and usage restrictions.
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__ #ifndef __PPCFE_H__
#define __PPCFE_H__ #define __PPCFE_H__
#include "ppccom.h"
#include "cpu/drcfe.h" #include "cpu/drcfe.h"
/*************************************************************************** //**************************************************************************
CONSTANTS // MACROS
***************************************************************************/ //**************************************************************************
/* register flags 0 */ // register flags 0
#define REGFLAG_R(n) (1 << (n)) #define REGFLAG_R(n) (1 << (n))
#define REGFLAG_RZ(n) (((n) == 0) ? 0 : REGFLAG_R(n)) #define REGFLAG_RZ(n) (((n) == 0) ? 0 : REGFLAG_R(n))
/* register flags 1 */ // register flags 1
#define REGFLAG_FR(n) (1 << (n)) #define REGFLAG_FR(n) (1 << (n))
/* register flags 2 */ // register flags 2
#define REGFLAG_CR(n) (0xf0000000 >> (4 * (n))) #define REGFLAG_CR(n) (0xf0000000 >> (4 * (n)))
#define REGFLAG_CR_BIT(n) (0x80000000 >> (n)) #define REGFLAG_CR_BIT(n) (0x80000000 >> (n))
/* register flags 3 */ // register flags 3
#define REGFLAG_XER_CA (1 << 0) #define REGFLAG_XER_CA (1 << 0)
#define REGFLAG_XER_OV (1 << 1) #define REGFLAG_XER_OV (1 << 1)
#define REGFLAG_XER_SO (1 << 2) #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__ */ #endif /* __PPCFE_H__ */

View File

@ -106,7 +106,7 @@ struct _rspimp_state
/* core state */ /* core state */
drccache * cache; /* pointer to the DRC code cache */ drccache * cache; /* pointer to the DRC code cache */
drcuml_state * drcuml; /* DRC UML generator state */ 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 */ UINT32 drcoptions; /* configurable DRC options */
/* internal stuff */ /* internal stuff */
@ -603,13 +603,6 @@ static void rspcom_init(rsp_state *rsp, legacy_cpu_device *device, device_irq_ca
static CPU_INIT( rsp ) 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; rsp_state *rsp;
drccache *cache; drccache *cache;
UINT32 flags = 0; 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"); drcuml_symbol_add(rsp->impstate->drcuml, &rsp->impstate->numcycles, sizeof(rsp->impstate->numcycles), "numcycles");
/* initialize the front-end helper */ /* initialize the front-end helper */
if (SINGLE_INSTRUCTION_MODE) rsp->impstate->drcfe = auto_alloc(device->machine, rsp_frontend(*rsp, COMPILE_BACKWARDS_BYTES, COMPILE_FORWARDS_BYTES, SINGLE_INSTRUCTION_MODE ? 1 : COMPILE_MAX_SEQUENCE));
{
feconfig.max_sequence = 1;
}
rsp->impstate->drcfe = drcfe_init(device, &feconfig, rsp);
/* compute the register parameters */ /* compute the register parameters */
for (regnum = 0; regnum < 32; regnum++) for (regnum = 0; regnum < 32; regnum++)
@ -721,7 +710,7 @@ static CPU_EXIT( rsp )
rsp_state *rsp = get_safe_token(device); rsp_state *rsp = get_safe_token(device);
/* clean up the DRC */ /* clean up the DRC */
drcfe_exit(rsp->impstate->drcfe); auto_free(device->machine, rsp->impstate->drcfe);
drcuml_free(rsp->impstate->drcuml); drcuml_free(rsp->impstate->drcuml);
drccache_free(rsp->impstate->cache); 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); g_profiler.start(PROFILER_DRC_COMPILE);
/* get a description of this sequence */ /* 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 we get an error back, flush the cache and try again */
if (setjmp(errorbuf) != 0) 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); block = drcuml_block_begin(drcuml, 8192, &errorbuf);
/* loop until we get through all instruction sequences */ /* 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; const opcode_desc *curdesc;
UINT32 nextpc; UINT32 nextpc;
@ -3501,7 +3490,7 @@ static void code_compile_block(rsp_state *rsp, offs_t pc)
UML_COMMENT(block, "-------------------------"); // comment UML_COMMENT(block, "-------------------------"); // comment
/* determine the last instruction in this sequence */ /* 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) if (seqlast->flags & OPFLAG_END_SEQUENCE)
break; break;
assert(seqlast != NULL); 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 UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc
/* iterate over instructions in the sequence and compile them */ /* 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); generate_sequence_instruction(rsp, block, &compiler, curdesc);
/* if we need to return to the start, do it */ /* 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> 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 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 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 UML_COMMENT(block, "[Validation for %08X]", seqhead->pc | 0x1000); // comment
} }
/* loose verify or single instruction: just compare and fail */ /* 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)) 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); void *base = rsp->direct->read_decrypted_ptr(seqhead->physpc | 0x1000);
UML_LOAD(block, IREG(0), base, IMM(0), DWORD); // load i0,base,0,dword UML_LOAD(block, IREG(0), base, IMM(0), DWORD); // load i0,base,0,dword
sum += seqhead->opptr.l[0]; 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)) if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP))
{ {
base = rsp->direct->read_decrypted_ptr(curdesc->physpc | 0x1000); 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 */ /* compile the delay slot using temporary compiler state */
assert(desc->delay != NULL); 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 */ /* update the cycles and jump through the hash table to the target */
if (desc->targetpc != BRANCH_TARGET_DYNAMIC) if (desc->targetpc != BRANCH_TARGET_DYNAMIC)

View File

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

View File

@ -15,20 +15,44 @@
#ifndef __RSPFE_H__ #ifndef __RSPFE_H__
#define __RSPFE_H__ #define __RSPFE_H__
#include "rsp.h"
#include "cpu/drcfe.h" #include "cpu/drcfe.h"
/*************************************************************************** //**************************************************************************
CONSTANTS // CONSTANTS
***************************************************************************/ //**************************************************************************
/* register flags 0 */ // register flags 0
#define REGFLAG_R(n) (((n) == 0) ? 0 : (1 << (n))) #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__ */ #endif /* __RSPFE_H__ */

View File

@ -21,6 +21,7 @@
#include "cpu/drcfe.h" #include "cpu/drcfe.h"
#include "cpu/drcuml.h" #include "cpu/drcuml.h"
#include "cpu/drcumlsh.h" #include "cpu/drcumlsh.h"
class sh2_frontend;
#endif #endif
#define SH2_CODE_XOR(a) ((a) ^ NATIVE_ENDIAN_VALUE_LE_BE(2,0)) #define SH2_CODE_XOR(a) ((a) ^ NATIVE_ENDIAN_VALUE_LE_BE(2,0))
@ -155,7 +156,7 @@ typedef struct
#ifdef USE_SH2DRC #ifdef USE_SH2DRC
drccache * cache; /* pointer to the DRC code cache */ drccache * cache; /* pointer to the DRC code cache */
drcuml_state * drcuml; /* DRC UML generator state */ 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 */ UINT32 drcoptions; /* configurable DRC options */
/* internal stuff */ /* internal stuff */
@ -184,6 +185,28 @@ typedef struct
#endif #endif
} sh2_state; } 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_common_init(sh2_state *sh2, legacy_cpu_device *device, device_irq_callback irqcallback);
void sh2_recalc_irq(sh2_state *sh2); void sh2_recalc_irq(sh2_state *sh2);
void sh2_set_irq_line(sh2_state *sh2, int irqline, int state); void sh2_set_irq_line(sh2_state *sh2, int irqline, int state);

View File

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

File diff suppressed because it is too large Load Diff