mirror of
https://github.com/holub/mame
synced 2025-07-04 01:18:59 +03:00
C++-ified drcfe and the associated frontends. You now create a
frontend by deriving from drc_frontend and implementing the describe method. RB, if you send me your latest SH4 WIP, I'll convert it for you if this makes you cranky. :)
This commit is contained in:
parent
68ebcf0254
commit
9e5207ce91
@ -4,9 +4,36 @@
|
|||||||
|
|
||||||
Generic dynamic recompiler frontend structures and utilities.
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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__ */
|
||||||
|
@ -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
@ -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__ */
|
||||||
|
@ -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
@ -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__ */
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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__ */
|
||||||
|
@ -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);
|
||||||
|
@ -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
Loading…
Reference in New Issue
Block a user