diff options
author | 2011-01-04 15:54:16 +0000 | |
---|---|---|
committer | 2011-01-04 15:54:16 +0000 | |
commit | 9e5207ce91c362e4c9f51443ebcb7ffb7119cb76 (patch) | |
tree | 0052cd14a788e4b576a5852763d95f88017c8759 | |
parent | 68ebcf02543e03d9e051e26884bb226a4d5c78b3 (diff) |
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. :)
-rw-r--r-- | src/emu/cpu/drcfe.c | 508 | ||||
-rw-r--r-- | src/emu/cpu/drcfe.h | 224 | ||||
-rw-r--r-- | src/emu/cpu/mips/mips3drc.c | 78 | ||||
-rw-r--r-- | src/emu/cpu/mips/mips3fe.c | 1234 | ||||
-rw-r--r-- | src/emu/cpu/mips/mips3fe.h | 75 | ||||
-rw-r--r-- | src/emu/cpu/powerpc/ppcdrc.c | 37 | ||||
-rw-r--r-- | src/emu/cpu/powerpc/ppcfe.c | 1456 | ||||
-rw-r--r-- | src/emu/cpu/powerpc/ppcfe.h | 81 | ||||
-rw-r--r-- | src/emu/cpu/rsp/rspdrc.c | 33 | ||||
-rw-r--r-- | src/emu/cpu/rsp/rspfe.c | 431 | ||||
-rw-r--r-- | src/emu/cpu/rsp/rspfe.h | 40 | ||||
-rw-r--r-- | src/emu/cpu/sh2/sh2comn.h | 25 | ||||
-rw-r--r-- | src/emu/cpu/sh2/sh2drc.c | 37 | ||||
-rw-r--r-- | src/emu/cpu/sh2/sh2fe.c | 716 |
14 files changed, 2509 insertions, 2466 deletions
diff --git a/src/emu/cpu/drcfe.c b/src/emu/cpu/drcfe.c index c4dee7cc9aa..f39bfaf0bb1 100644 --- a/src/emu/cpu/drcfe.c +++ b/src/emu/cpu/drcfe.c @@ -4,9 +4,36 @@ Generic dynamic recompiler frontend structures and utilities. +**************************************************************************** + Copyright Aaron Giles - Released for general non-commercial use under the MAME license - Visit http://mamedev.org for licensing and usage restrictions. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name 'MAME' nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. **************************************************************************** @@ -21,219 +48,120 @@ #include "drcfe.h" -/*************************************************************************** - CONSTANTS -***************************************************************************/ +//************************************************************************** +// CONSTANTS +//************************************************************************** -#define MAX_STACK_DEPTH 100 +const UINT32 MAX_STACK_DEPTH = 100; -/*************************************************************************** - TYPE DEFINITIONS -***************************************************************************/ +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** -/* an entry that maps branches for our code walking */ -typedef struct _pc_stack_entry pc_stack_entry; -struct _pc_stack_entry +// an entry that maps branches for our code walking +struct pc_stack_entry { offs_t targetpc; offs_t srcpc; }; -/* internal state */ -struct _drcfe_state -{ - /* 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; -} +//************************************************************************** +// DRC FRONTEND +//************************************************************************** +//------------------------------------------------- +// drc_frontend - constructor +//------------------------------------------------- -/*------------------------------------------------- - desc_free - free an opcode description --------------------------------------------------*/ - -INLINE void desc_free(drcfe_state *drcfe, opcode_desc *desc) +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)) { - /* just put ourselves on the free list */ - desc->next = drcfe->desc_free_list; - drcfe->desc_free_list = desc; } +//------------------------------------------------- +// ~drc_frontend - destructor +//------------------------------------------------- -/*************************************************************************** - CORE IMPLEMENTATION -***************************************************************************/ - -/*------------------------------------------------- - drcfe_init - initializate the drcfe state --------------------------------------------------*/ - -drcfe_state *drcfe_init(device_t *cpu, const drcfe_config *config, void *param) +drc_frontend::~drc_frontend() { - drcfe_state *drcfe; - - /* allocate some memory to hold the state */ - drcfe = auto_alloc_clear(cpu->machine, drcfe_state); - - /* allocate the description array */ - drcfe->desc_array = auto_alloc_array_clear(cpu->machine, opcode_desc *, config->window_end + config->window_start + 2); - - /* copy in configuration information */ - drcfe->window_start = config->window_start; - drcfe->window_end = config->window_end; - drcfe->max_sequence = config->max_sequence; - drcfe->describe = config->describe; - drcfe->param = param; + // release any descriptions we've accumulated + release_descriptions(); - /* 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; + // free the description array + auto_free(m_cpudevice.machine, m_desc_array); } -/*------------------------------------------------- - drcfe_exit - clean up after ourselves --------------------------------------------------*/ +//------------------------------------------------- +// describe_code - describe a sequence of code +// that falls within the configured window +// relative to the specified startpc +//------------------------------------------------- -void drcfe_exit(drcfe_state *drcfe) +const opcode_desc *drc_frontend::describe_code(offs_t startpc) { - /* 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); -} - + // release any descriptions we've accumulated + release_descriptions(); -/*------------------------------------------------- - drcfe_describe_code - describe a sequence of - code that falls within the configured window - relative to the specified startpc --------------------------------------------------*/ - -const opcode_desc *drcfe_describe_code(drcfe_state *drcfe, offs_t startpc) -{ - offs_t minpc = startpc - MIN(drcfe->window_start, startpc); - offs_t maxpc = startpc + MIN(drcfe->window_end, 0xffffffff - startpc); + // add the initial PC to the stack pc_stack_entry pcstack[MAX_STACK_DEPTH]; pc_stack_entry *pcstackptr = &pcstack[0]; - opcode_desc **tailptr; - - /* release any descriptions we've accumulated */ - release_descriptions(drcfe, drcfe->desc_live_list); - drcfe->desc_live_list = NULL; - - /* add the initial PC to the stack */ pcstackptr->srcpc = 0; pcstackptr->targetpc = startpc; pcstackptr++; - /* loop while we still have a stack */ + // loop while we still have a stack + offs_t minpc = startpc - MIN(m_window_start, startpc); + offs_t maxpc = startpc + MIN(m_window_end, 0xffffffff - startpc); while (pcstackptr != &pcstack[0]) { + // if we've already hit this PC, just mark it a branch target and continue pc_stack_entry *curstack = --pcstackptr; - opcode_desc *curdesc; - offs_t curpc; - - /* if we've already hit this PC, just mark it a branch target and continue */ - curdesc = drcfe->desc_array[curstack->targetpc - minpc]; + opcode_desc *curdesc = m_desc_array[curstack->targetpc - minpc]; if (curdesc != NULL) { curdesc->flags |= OPFLAG_IS_BRANCH_TARGET; - /* if the branch crosses a page boundary, mark the target as needing to revalidate */ - if (drcfe->pageshift != 0 && ((curstack->srcpc ^ curdesc->pc) >> drcfe->pageshift) != 0) + // if the branch crosses a page boundary, mark the target as needing to revalidate + if (m_pageshift != 0 && ((curstack->srcpc ^ curdesc->pc) >> m_pageshift) != 0) curdesc->flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION; - /* continue processing */ + // continue processing continue; } - /* loop until we exit the block */ - for (curpc = curstack->targetpc; curpc >= minpc && curpc < maxpc && drcfe->desc_array[curpc - minpc] == NULL; curpc += drcfe->desc_array[curpc - minpc]->length) + // loop until we exit the block + for (offs_t curpc = curstack->targetpc; curpc >= minpc && curpc < maxpc && m_desc_array[curpc - minpc] == NULL; curpc += m_desc_array[curpc - minpc]->length) { - /* allocate a new description and describe this instruction */ - drcfe->desc_array[curpc - minpc] = curdesc = describe_one(drcfe, curpc, curdesc); + // allocate a new description and describe this instruction + m_desc_array[curpc - minpc] = curdesc = describe_one(curpc, curdesc); - /* first instruction in a sequence is always a branch target */ + // first instruction in a sequence is always a branch target if (curpc == curstack->targetpc) curdesc->flags |= OPFLAG_IS_BRANCH_TARGET; - /* stop if we hit a page fault */ + // stop if we hit a page fault if (curdesc->flags & OPFLAG_COMPILER_PAGE_FAULT) break; - /* if we are the first instruction in the whole window, we must validate the TLB */ - if (curpc == startpc && drcfe->pageshift != 0) + // if we are the first instruction in the whole window, we must validate the TLB + if (curpc == startpc && m_pageshift != 0) curdesc->flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION; - /* if we are a branch within the block range, add the branch target to our stack */ + // if we are a branch within the block range, add the branch target to our stack if ((curdesc->flags & OPFLAG_IS_BRANCH) && curdesc->targetpc >= minpc && curdesc->targetpc < maxpc && pcstackptr < &pcstack[MAX_STACK_DEPTH]) { curdesc->flags |= OPFLAG_INTRABLOCK_BRANCH; @@ -242,131 +170,113 @@ const opcode_desc *drcfe_describe_code(drcfe_state *drcfe, offs_t startpc) pcstackptr++; } - /* if we're done, we're done */ + // if we're done, we're done if (curdesc->flags & OPFLAG_END_SEQUENCE) break; } } - /* now build the list of descriptions in order */ - /* first from startpc -> maxpc, then from minpc -> startpc */ - tailptr = build_sequence(drcfe, &drcfe->desc_live_list, startpc - minpc, maxpc - minpc, OPFLAG_REDISPATCH); - tailptr = build_sequence(drcfe, tailptr, minpc - minpc, startpc - minpc, OPFLAG_RETURN_TO_START); - return drcfe->desc_live_list; + // now build the list of descriptions in order + // first from startpc -> maxpc, then from minpc -> startpc + build_sequence(startpc - minpc, maxpc - minpc, OPFLAG_REDISPATCH); + build_sequence(minpc - minpc, startpc - minpc, OPFLAG_RETURN_TO_START); + return m_desc_live_list.first(); } +//------------------------------------------------- +// describe_one - describe a single instruction, +// recursively describing opcodes in delay +// slots of branches as well +//------------------------------------------------- -/*************************************************************************** - INTERNAL HELPERS -***************************************************************************/ - -/*------------------------------------------------- - describe_one - describe a single instruction, - recursively describing opcodes in delay - slots of branches as well --------------------------------------------------*/ - -static opcode_desc *describe_one(drcfe_state *drcfe, offs_t curpc, const opcode_desc *prevdesc) +opcode_desc *drc_frontend::describe_one(offs_t curpc, const opcode_desc *prevdesc) { - opcode_desc *desc = desc_alloc(drcfe); - - /* initialize the description */ + // initialize the description + opcode_desc *desc = m_desc_allocator.alloc(); memset(desc, 0, sizeof(*desc)); desc->pc = curpc; desc->physpc = curpc; desc->targetpc = BRANCH_TARGET_DYNAMIC; - /* call the callback to describe an instruction */ - if (!(*drcfe->describe)(drcfe->param, desc, prevdesc)) + // call the callback to describe an instruction + if (!describe(*desc, prevdesc)) { desc->flags |= OPFLAG_WILL_CAUSE_EXCEPTION | OPFLAG_INVALID_OPCODE; return desc; } - /* validate the TLB if we are exactly at the start of a page, or if we cross a page boundary */ - if (drcfe->pageshift != 0 && (((curpc - 1) ^ (curpc + desc->length - 1)) >> drcfe->pageshift) != 0) + // validate the TLB if we are exactly at the start of a page, or if we cross a page boundary + if (m_pageshift != 0 && (((curpc - 1) ^ (curpc + desc->length - 1)) >> m_pageshift) != 0) desc->flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION; - /* validate stuff */ + // validate stuff assert(desc->length > 0 || (desc->flags & OPFLAG_VIRTUAL_NOOP) != 0); - /* if we are a branch with delay slots, recursively walk those */ + // if we are a branch with delay slots, recursively walk those if (desc->flags & OPFLAG_IS_BRANCH) { - opcode_desc **tailptr = &desc->delay; + // iterate over slots and describe them offs_t delaypc = curpc + desc->length; opcode_desc *prev = desc; - UINT8 slotnum; - - /* iterate over slots and describe them */ - for (slotnum = 0; slotnum < desc->delayslots; slotnum++) + for (UINT8 slotnum = 0; slotnum < desc->delayslots; slotnum++) { - /* recursively describe the next instruction */ - *tailptr = describe_one(drcfe, delaypc, prev); - if (*tailptr == NULL) + // recursively describe the next instruction + opcode_desc *delaydesc = describe_one(delaypc, prev); + if (delaydesc == NULL) break; + desc->delay.append(*delaydesc); + prev = desc; - /* set the delay slot flag and a pointer back to the original branch */ - (*tailptr)->flags |= OPFLAG_IN_DELAY_SLOT; - (*tailptr)->branch = desc; - (*tailptr)->prev = prev; - prev = *tailptr; + // 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 ((*tailptr)->flags & OPFLAG_COMPILER_PAGE_FAULT) + // stop if we hit a page fault + if (delaydesc->flags & OPFLAG_COMPILER_PAGE_FAULT) break; - /* otherwise, advance */ - delaypc += (*tailptr)->length; - tailptr = &(*tailptr)->next; + // otherwise, advance + delaypc += delaydesc->length; } } - return desc; } -/*------------------------------------------------- - build_sequence - build an ordered sequence - of instructions --------------------------------------------------*/ +//------------------------------------------------- +// build_sequence - build an ordered sequence +// of instructions +//------------------------------------------------- -static opcode_desc **build_sequence(drcfe_state *drcfe, opcode_desc **tailptr, int start, int end, UINT32 endflag) +void drc_frontend::build_sequence(int start, int end, UINT32 endflag) { - opcode_desc *prev = NULL; + // iterate in order from start to end, picking up all non-NULL instructions int consecutive = 0; int seqstart = -1; int skipsleft = 0; - int descnum; - - /* iterate in order from start to end, picking up all non-NULL instructions */ - for (descnum = start; descnum < end; descnum++) - if (drcfe->desc_array[descnum] != NULL) + for (int descnum = start; descnum < end; descnum++) + if (m_desc_array[descnum] != NULL) { - opcode_desc *curdesc = drcfe->desc_array[descnum]; - opcode_desc *nextdesc = NULL; - int nextdescnum; - UINT8 skipnum; - - /* determine the next instruction, taking skips into account */ - nextdescnum = descnum + curdesc->length; - nextdesc = (nextdescnum < end) ? drcfe->desc_array[nextdescnum] : NULL; - for (skipnum = 0; skipnum < curdesc->skipslots && nextdesc != NULL; skipnum++) + // determine the next instruction, taking skips into account + opcode_desc *curdesc = m_desc_array[descnum]; + int nextdescnum = descnum + curdesc->length; + opcode_desc *nextdesc = (nextdescnum < end) ? m_desc_array[nextdescnum] : NULL; + for (UINT8 skipnum = 0; skipnum < curdesc->skipslots && nextdesc != NULL; skipnum++) { nextdescnum = nextdescnum + nextdesc->length; - nextdesc = (nextdescnum < end) ? drcfe->desc_array[nextdescnum] : NULL; + nextdesc = (nextdescnum < end) ? m_desc_array[nextdescnum] : NULL; } - /* start a new sequence if we aren't already in the middle of one */ + // start a new sequence if we aren't already in the middle of one if (seqstart == -1 && skipsleft == 0) { - /* tag all start-of-sequence instructions as needing TLB verification */ + // tag all start-of-sequence instructions as needing TLB verification curdesc->flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION; seqstart = descnum; } - /* if we are the last instruction, indicate end-of-sequence and redispatch */ + // if we are the last instruction, indicate end-of-sequence and redispatch if (nextdesc == NULL) { curdesc->flags |= OPFLAG_END_SEQUENCE; @@ -374,134 +284,118 @@ static opcode_desc **build_sequence(drcfe_state *drcfe, opcode_desc **tailptr, i curdesc->flags |= endflag; } - /* otherwise, do some analysis based on the next instruction */ + // otherwise, do some analysis based on the next instruction else { - opcode_desc *scandesc = NULL; + // if there are instructions between us and the next instruction, we must end our sequence here int scandescnum; - - /* if there are instructions between us and the next instruction, we must end our sequence here */ + opcode_desc *scandesc = NULL; for (scandescnum = descnum + 1; scandescnum < end; scandescnum++) { - scandesc = drcfe->desc_array[scandescnum]; + scandesc = m_desc_array[scandescnum]; if (scandesc != NULL || scandesc == nextdesc) break; } if (scandesc != nextdesc) curdesc->flags |= OPFLAG_END_SEQUENCE; - /* if the next instruction is a branch target, mark this instruction as end of sequence */ + // if the next instruction is a branch target, mark this instruction as end of sequence if (nextdesc->flags & OPFLAG_IS_BRANCH_TARGET) curdesc->flags |= OPFLAG_END_SEQUENCE; } - /* if we exceed the maximum consecutive count, cut off the sequence */ - if (++consecutive >= drcfe->max_sequence) + // if we exceed the maximum consecutive count, cut off the sequence + if (++consecutive >= m_max_sequence) curdesc->flags |= OPFLAG_END_SEQUENCE; if (curdesc->flags & OPFLAG_END_SEQUENCE) consecutive = 0; - /* if this is the end of a sequence, work backwards */ + // if this is the end of a sequence, work backwards if (curdesc->flags & OPFLAG_END_SEQUENCE) { + // figure out which registers we *must* generate, assuming at the end all must be UINT32 reqmask[4] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }; - int backdesc; - - /* figure out which registers we *must* generate, assuming at the end all must be */ if (seqstart != -1) - for (backdesc = descnum; backdesc != seqstart - 1; backdesc--) - if (drcfe->desc_array[backdesc] != NULL) - accumulate_required_backwards(drcfe->desc_array[backdesc], reqmask); + for (int backdesc = descnum; backdesc != seqstart - 1; backdesc--) + if (m_desc_array[backdesc] != NULL) + accumulate_required_backwards(*m_desc_array[backdesc], reqmask); - /* reset the register states */ + // reset the register states seqstart = -1; } - /* if we have instructions remaining to be skipped, and this instruction is a branch target */ - /* belay the skip order */ + // if we have instructions remaining to be skipped, and this instruction is a branch target + // belay the skip order if (skipsleft > 0 && (curdesc->flags & OPFLAG_IS_BRANCH_TARGET)) skipsleft = 0; - /* if we're not getting skipped, add us to the end of the list and clear our array slot */ + // if we're not getting skipped, add us to the end of the list and clear our array slot if (skipsleft == 0) - { - *tailptr = curdesc; - tailptr = &curdesc->next; - curdesc->prev = prev; - prev = curdesc; - } + m_desc_live_list.append(*curdesc); else - desc_free(drcfe, curdesc); + m_desc_allocator.reclaim(*curdesc); - /* if the current instruction starts skipping, reset our skip count */ - /* otherwise, just decrement */ + // if the current instruction starts skipping, reset our skip count + // otherwise, just decrement if (curdesc->skipslots > 0) skipsleft = curdesc->skipslots; else if (skipsleft > 0) skipsleft--; } - /* zap the array */ - memset(&drcfe->desc_array[start], 0, (end - start) * sizeof(drcfe->desc_array[0])); - - /* return the final tailptr */ - return tailptr; + // zap the array + memset(&m_desc_array[start], 0, (end - start) * sizeof(m_desc_array[0])); } -/*------------------------------------------------- - accumulate_required_backwards - recursively - accumulate live register liveness information - walking in a backwards direction --------------------------------------------------*/ +//------------------------------------------------- +// accumulate_required_backwards - recursively +// accumulate live register liveness information +// walking in a backwards direction +//------------------------------------------------- -static void accumulate_required_backwards(opcode_desc *desc, UINT32 *reqmask) +void drc_frontend::accumulate_required_backwards(opcode_desc &desc, UINT32 *reqmask) { - /* recursively handle delay slots */ - if (desc->delay != NULL) - accumulate_required_backwards(desc->delay, reqmask); + // recursively handle delay slots + if (desc.delay.first() != NULL) + accumulate_required_backwards(*desc.delay.first(), reqmask); - /* if this is a branch, we have to reset our requests */ - if (desc->flags & OPFLAG_IS_BRANCH) + // if this is a branch, we have to reset our requests + if (desc.flags & OPFLAG_IS_BRANCH) reqmask[0] = reqmask[1] = reqmask[2] = reqmask[3] = 0xffffffff; - /* determine the required registers */ - desc->regreq[0] = desc->regout[0] & reqmask[0]; - desc->regreq[1] = desc->regout[1] & reqmask[1]; - desc->regreq[2] = desc->regout[2] & reqmask[2]; - desc->regreq[3] = desc->regout[3] & reqmask[3]; - - /* any registers modified by this instruction aren't required upstream until referenced */ - reqmask[0] &= ~desc->regout[0]; - reqmask[1] &= ~desc->regout[1]; - reqmask[2] &= ~desc->regout[2]; - reqmask[3] &= ~desc->regout[3]; - - /* any registers required by this instruction now get marked required */ - reqmask[0] |= desc->regin[0]; - reqmask[1] |= desc->regin[1]; - reqmask[2] |= desc->regin[2]; - reqmask[3] |= desc->regin[3]; + // determine the required registers + desc.regreq[0] = desc.regout[0] & reqmask[0]; + desc.regreq[1] = desc.regout[1] & reqmask[1]; + desc.regreq[2] = desc.regout[2] & reqmask[2]; + desc.regreq[3] = desc.regout[3] & reqmask[3]; + + // any registers modified by this instruction aren't required upstream until referenced + reqmask[0] &= ~desc.regout[0]; + reqmask[1] &= ~desc.regout[1]; + reqmask[2] &= ~desc.regout[2]; + reqmask[3] &= ~desc.regout[3]; + + // any registers required by this instruction now get marked required + reqmask[0] |= desc.regin[0]; + reqmask[1] |= desc.regin[1]; + reqmask[2] |= desc.regin[2]; + reqmask[3] |= desc.regin[3]; } -/*------------------------------------------------- - release_descriptions - release any - descriptions we've allocated back to the - free list -------------------------------------------------*/ +//------------------------------------------------- +// release_descriptions - release any +// descriptions we've allocated back to the +// free list +//------------------------------------------------ -static void release_descriptions(drcfe_state *drcfe, opcode_desc *desc) +void drc_frontend::release_descriptions() { - /* loop while we still have valid entries */ - while (desc != NULL) - { - opcode_desc *freeme = desc; - - /* recursively release delay slots */ - if (desc->delay != NULL) - release_descriptions(drcfe, desc->delay); - desc = desc->next; - desc_free(drcfe, freeme); - } + // release all delay slots first + for (opcode_desc *curdesc = m_desc_live_list.first(); curdesc != NULL; curdesc = curdesc->next()) + m_desc_allocator.reclaim_all(curdesc->delay); + + // reclaim all the descriptors + m_desc_allocator.reclaim_all(m_desc_live_list); } diff --git a/src/emu/cpu/drcfe.h b/src/emu/cpu/drcfe.h index 38de85a6ccf..7849aed73c9 100644 --- a/src/emu/cpu/drcfe.h +++ b/src/emu/cpu/drcfe.h @@ -4,9 +4,36 @@ Generic dynamic recompiler frontend structures and utilities. +**************************************************************************** + Copyright Aaron Giles - Released for general non-commercial use under the MAME license - Visit http://mamedev.org for licensing and usage restrictions. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name 'MAME' nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. **************************************************************************** @@ -37,125 +64,130 @@ #define __DRCFE_H__ -/*************************************************************************** - CONSTANTS -***************************************************************************/ +//************************************************************************** +// CONSTANTS +//************************************************************************** -/* this defines a branch targetpc that is dynamic at runtime */ -#define BRANCH_TARGET_DYNAMIC (~0) +// this defines a branch targetpc that is dynamic at runtime +const offs_t BRANCH_TARGET_DYNAMIC = ~0; -/* opcode branch flags */ -#define OPFLAG_IS_UNCONDITIONAL_BRANCH 0x00000001 /* instruction is unconditional branch */ -#define OPFLAG_IS_CONDITIONAL_BRANCH 0x00000002 /* instruction is conditional branch */ -#define OPFLAG_IS_BRANCH (OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_IS_CONDITIONAL_BRANCH) -#define OPFLAG_IS_BRANCH_TARGET 0x00000004 /* instruction is the target of a branch */ -#define OPFLAG_IN_DELAY_SLOT 0x00000008 /* instruction is in the delay slot of a branch */ -#define OPFLAG_INTRABLOCK_BRANCH 0x00000010 /* instruction branches within the block */ +// opcode branch flags +const UINT32 OPFLAG_IS_UNCONDITIONAL_BRANCH = 0x00000001; // instruction is unconditional branch +const UINT32 OPFLAG_IS_CONDITIONAL_BRANCH = 0x00000002; // instruction is conditional branch +const UINT32 OPFLAG_IS_BRANCH = (OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_IS_CONDITIONAL_BRANCH); +const UINT32 OPFLAG_IS_BRANCH_TARGET = 0x00000004; // instruction is the target of a branch +const UINT32 OPFLAG_IN_DELAY_SLOT = 0x00000008; // instruction is in the delay slot of a branch +const UINT32 OPFLAG_INTRABLOCK_BRANCH = 0x00000010; // instruction branches within the block -/* opcode exception flags */ -#define OPFLAG_CAN_TRIGGER_SW_INT 0x00000020 /* instruction can trigger a software interrupt */ -#define OPFLAG_CAN_EXPOSE_EXTERNAL_INT 0x00000040 /* instruction can expose an external interrupt */ -#define OPFLAG_CAN_CAUSE_EXCEPTION 0x00000080 /* instruction may generate exception */ -#define OPFLAG_WILL_CAUSE_EXCEPTION 0x00000100 /* instruction will generate exception */ -#define OPFLAG_PRIVILEGED 0x00000200 /* instruction is privileged */ +// opcode exception flags +const UINT32 OPFLAG_CAN_TRIGGER_SW_INT = 0x00000020; // instruction can trigger a software interrupt +const UINT32 OPFLAG_CAN_EXPOSE_EXTERNAL_INT = 0x00000040; // instruction can expose an external interrupt +const UINT32 OPFLAG_CAN_CAUSE_EXCEPTION = 0x00000080; // instruction may generate exception +const UINT32 OPFLAG_WILL_CAUSE_EXCEPTION = 0x00000100; // instruction will generate exception +const UINT32 OPFLAG_PRIVILEGED = 0x00000200; // instruction is privileged -/* opcode virtual->physical translation flags */ -#define OPFLAG_VALIDATE_TLB 0x00000400 /* instruction must validate TLB before execution */ -#define OPFLAG_MODIFIES_TRANSLATION 0x00000800 /* instruction modifies the TLB */ -#define OPFLAG_COMPILER_PAGE_FAULT 0x00001000 /* compiler hit a page fault when parsing */ -#define OPFLAG_COMPILER_UNMAPPED 0x00002000 /* compiler hit unmapped memory when parsing */ +// opcode virtual->physical translation flags +const UINT32 OPFLAG_VALIDATE_TLB = 0x00000400; // instruction must validate TLB before execution +const UINT32 OPFLAG_MODIFIES_TRANSLATION = 0x00000800; // instruction modifies the TLB +const UINT32 OPFLAG_COMPILER_PAGE_FAULT = 0x00001000; // compiler hit a page fault when parsing +const UINT32 OPFLAG_COMPILER_UNMAPPED = 0x00002000; // compiler hit unmapped memory when parsing -/* opcode flags */ -#define OPFLAG_INVALID_OPCODE 0x00004000 /* instruction is invalid */ -#define OPFLAG_VIRTUAL_NOOP 0x00008000 /* instruction is a virtual no-op */ +// opcode flags +const UINT32 OPFLAG_INVALID_OPCODE = 0x00004000; // instruction is invalid +const UINT32 OPFLAG_VIRTUAL_NOOP = 0x00008000; // instruction is a virtual no-op -/* opcode sequence flow flags */ -#define OPFLAG_REDISPATCH 0x00010000 /* instruction must redispatch after completion */ -#define OPFLAG_RETURN_TO_START 0x00020000 /* instruction must jump back to the beginning after completion */ -#define OPFLAG_END_SEQUENCE 0x00040000 /* this is the last instruction in a sequence */ -#define OPFLAG_CAN_CHANGE_MODES 0x00080000 /* instruction can change modes */ +// opcode sequence flow flags +const UINT32 OPFLAG_REDISPATCH = 0x00010000; // instruction must redispatch after completion +const UINT32 OPFLAG_RETURN_TO_START = 0x00020000; // instruction must jump back to the beginning after completion +const UINT32 OPFLAG_END_SEQUENCE = 0x00040000; // this is the last instruction in a sequence +const UINT32 OPFLAG_CAN_CHANGE_MODES = 0x00080000; // instruction can change modes -/* execution semantics */ -#define OPFLAG_READS_MEMORY 0x00100000 /* instruction reads memory */ -#define OPFLAG_WRITES_MEMORY 0x00200000 /* instruction writes memory */ +// execution semantics +const UINT32 OPFLAG_READS_MEMORY = 0x00100000; // instruction reads memory +const UINT32 OPFLAG_WRITES_MEMORY = 0x00200000; // instruction writes memory -/*************************************************************************** - TYPE DEFINITIONS -***************************************************************************/ +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** -/* opaque internal state */ -typedef struct _drcfe_state drcfe_state; +// description of a given opcode +struct opcode_desc +{ + opcode_desc *next() const { return m_next; } + // links to other descriptions + opcode_desc * m_next; // pointer to next description + opcode_desc * branch; // pointer back to branch description for delay slots + simple_list<opcode_desc> delay; // pointer to delay slot description -/* description of a given opcode */ -typedef struct _opcode_desc opcode_desc; -struct _opcode_desc -{ - /* links to other descriptions */ - opcode_desc * next; /* pointer to next description */ - opcode_desc * prev; /* pointer to previous description */ - opcode_desc * branch; /* pointer back to branch description for delay slots */ - opcode_desc * delay; /* pointer to delay slot description */ - - /* 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 */ + // information about the current PC + offs_t pc; // PC of this opcode + offs_t physpc; // physical PC of this opcode + offs_t targetpc; // target PC if we are a branch, or BRANCH_TARGET_DYNAMIC + + // copy of up to 16 bytes of opcode union { UINT8 b[16]; UINT16 w[8]; UINT32 l[4]; UINT64 q[2]; - } opptr; /* pointer to opcode memory */ - - /* information about this instruction's execution */ - UINT8 length; /* length in bytes of this opcode */ - UINT8 delayslots; /* number of delay slots (for branches) */ - UINT8 skipslots; /* number of skip slots (for branches) */ - UINT32 flags; /* OPFLAG_* opcode flags */ - UINT32 cycles; /* number of cycles needed to execute */ - - /* register usage information */ - UINT32 regin[4]; /* input registers */ - UINT32 regout[4]; /* output registers */ - UINT32 regreq[4]; /* required output registers */ + } opptr; // pointer to opcode memory + + // information about this instruction's execution + UINT8 length; // length in bytes of this opcode + UINT8 delayslots; // number of delay slots (for branches) + UINT8 skipslots; // number of skip slots (for branches) + UINT32 flags; // OPFLAG_* opcode flags + UINT32 cycles; // number of cycles needed to execute + + // register usage information + UINT32 regin[4]; // input registers + UINT32 regout[4]; // output registers + UINT32 regreq[4]; // required output registers }; -/* callback function that is used to describe a single opcode */ -typedef int (*drcfe_describe_func)(void *param, opcode_desc *desc, const opcode_desc *prev); - - -/* description of a given opcode */ -typedef struct _drcfe_config drcfe_config; -struct _drcfe_config +// DRC frontend state +class drc_frontend { - UINT32 window_start; /* code window start offset = startpc - window_start */ - UINT32 window_end; /* code window end offset = startpc + window_end */ - UINT32 max_sequence; /* maximum instructions to include in a sequence */ - drcfe_describe_func describe; /* callback to describe a single instruction */ +public: + // construction/destruction + drc_frontend(device_t &cpu, UINT32 window_start, UINT32 window_end, UINT32 max_sequence); + virtual ~drc_frontend(); + + // describe a block + const opcode_desc *describe_code(offs_t startpc); + +protected: + // required overrides + virtual bool describe(opcode_desc &desc, const opcode_desc *prev) = 0; + +private: + // internal helpers + opcode_desc *describe_one(offs_t curpc, const opcode_desc *prevdesc); + void build_sequence(int start, int end, UINT32 endflag); + void accumulate_required_backwards(opcode_desc &desc, UINT32 *reqmask); + void release_descriptions(); + + // configuration parameters + UINT32 m_window_start; // code window start offset = startpc - window_start + UINT32 m_window_end; // code window end offset = startpc + window_end + UINT32 m_max_sequence; // maximum instructions to include in a sequence + + // CPU parameters + cpu_device & m_cpudevice; // CPU device object + address_space * m_program; // program address space for this CPU + offs_t m_pageshift; // shift to convert address to a page index + + // opcode descriptor arrays + simple_list<opcode_desc> m_desc_live_list; // list of live descriptions + fixed_allocator<opcode_desc> m_desc_allocator; // fixed allocator for descriptions + opcode_desc ** m_desc_array; // array of descriptions in PC order }; - -/*************************************************************************** - FUNCTION PROTOTYPES -***************************************************************************/ - -/* initializate the drcfe state */ -drcfe_state *drcfe_init(device_t *cpu, const drcfe_config *config, void *param); - -/* clean up after ourselves */ -void drcfe_exit(drcfe_state *drcfe); - -/* describe a sequence of code that falls within the configured window relative to the specified startpc */ -const opcode_desc *drcfe_describe_code(drcfe_state *drcfe, offs_t startpc); - - #endif /* __DRCFE_H__ */ diff --git a/src/emu/cpu/mips/mips3drc.c b/src/emu/cpu/mips/mips3drc.c index 69c1d07e1ac..86e12e91a9d 100644 --- a/src/emu/cpu/mips/mips3drc.c +++ b/src/emu/cpu/mips/mips3drc.c @@ -4,9 +4,36 @@ Universal machine language-based MIPS III/IV emulator. +**************************************************************************** + Copyright Aaron Giles - Released for general non-commercial use under the MAME license - Visit http://mamedev.org for licensing and usage restrictions. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name 'MAME' nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. **************************************************************************** @@ -159,7 +186,7 @@ struct _mips3imp_state /* core state */ drccache * cache; /* pointer to the DRC code cache */ drcuml_state * drcuml; /* DRC UML generator state */ - drcfe_state * drcfe; /* pointer to the DRC front-end state */ + mips3_frontend * drcfe; /* pointer to the DRC front-end state */ UINT32 drcoptions; /* configurable DRC options */ /* internal stuff */ @@ -360,13 +387,6 @@ INLINE void save_fast_iregs(mips3_state *mips3, drcuml_block *block) static void mips3_init(mips3_flavor flavor, int bigendian, legacy_cpu_device *device, device_irq_callback irqcallback) { - drcfe_config feconfig = - { - COMPILE_BACKWARDS_BYTES, /* code window start offset = startpc - window_start */ - COMPILE_FORWARDS_BYTES, /* code window end offset = startpc + window_end */ - COMPILE_MAX_SEQUENCE, /* maximum instructions to include in a sequence */ - mips3fe_describe /* callback to describe a single instruction */ - }; mips3_state *mips3; drccache *cache; drcbe_info beinfo; @@ -445,9 +465,7 @@ static void mips3_init(mips3_flavor flavor, int bigendian, legacy_cpu_device *de drcuml_symbol_add(mips3->impstate->drcuml, &mips3->impstate->fpmode, sizeof(mips3->impstate->fpmode), "fpmode"); /* initialize the front-end helper */ - if (SINGLE_INSTRUCTION_MODE) - feconfig.max_sequence = 1; - mips3->impstate->drcfe = drcfe_init(device, &feconfig, mips3); + mips3->impstate->drcfe = auto_alloc(device->machine, mips3_frontend(*mips3, COMPILE_BACKWARDS_BYTES, COMPILE_FORWARDS_BYTES, SINGLE_INSTRUCTION_MODE ? 1 : COMPILE_MAX_SEQUENCE)); /* allocate memory for cache-local state and initialize it */ memcpy(mips3->impstate->fpmode, fpmode_source, sizeof(fpmode_source)); @@ -546,7 +564,7 @@ static CPU_EXIT( mips3 ) mips3com_exit(mips3); /* clean up the DRC */ - drcfe_exit(mips3->impstate->drcfe); + auto_free(device->machine, mips3->impstate->drcfe); drcuml_free(mips3->impstate->drcuml); drccache_free(mips3->impstate->cache); } @@ -745,7 +763,7 @@ static void code_compile_block(mips3_state *mips3, UINT8 mode, offs_t pc) g_profiler.start(PROFILER_DRC_COMPILE); /* get a description of this sequence */ - desclist = drcfe_describe_code(mips3->impstate->drcfe, pc); + desclist = mips3->impstate->drcfe->describe_code(pc); if (LOG_UML || LOG_NATIVE) log_opcode_desc(drcuml, desclist, 0); @@ -757,7 +775,7 @@ static void code_compile_block(mips3_state *mips3, UINT8 mode, offs_t pc) block = drcuml_block_begin(drcuml, 4096, &errorbuf); /* loop until we get through all instruction sequences */ - for (seqhead = desclist; seqhead != NULL; seqhead = seqlast->next) + for (seqhead = desclist; seqhead != NULL; seqhead = seqlast->next()) { const opcode_desc *curdesc; UINT32 nextpc; @@ -767,7 +785,7 @@ static void code_compile_block(mips3_state *mips3, UINT8 mode, offs_t pc) UML_COMMENT(block, "-------------------------"); // comment /* determine the last instruction in this sequence */ - for (seqlast = seqhead; seqlast != NULL; seqlast = seqlast->next) + for (seqlast = seqhead; seqlast != NULL; seqlast = seqlast->next()) if (seqlast->flags & OPFLAG_END_SEQUENCE) break; assert(seqlast != NULL); @@ -802,7 +820,7 @@ static void code_compile_block(mips3_state *mips3, UINT8 mode, offs_t pc) UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc | 0x80000000 /* iterate over instructions in the sequence and compile them */ - for (curdesc = seqhead; curdesc != seqlast->next; curdesc = curdesc->next) + for (curdesc = seqhead; curdesc != seqlast->next(); curdesc = curdesc->next()) generate_sequence_instruction(mips3, block, &compiler, curdesc); /* if we need to return to the start, do it */ @@ -820,7 +838,7 @@ static void code_compile_block(mips3_state *mips3, UINT8 mode, offs_t pc) if (seqlast->flags & OPFLAG_CAN_CHANGE_MODES) UML_HASHJMP(block, MEM(&mips3->impstate->mode), IMM(nextpc), mips3->impstate->nocode); // hashjmp <mode>,nextpc,nocode - else if (seqlast->next == NULL || seqlast->next->pc != nextpc) + else if (seqlast->next() == NULL || seqlast->next()->pc != nextpc) UML_HASHJMP(block, IMM(mips3->impstate->mode), IMM(nextpc), mips3->impstate->nocode); // hashjmp <mode>,nextpc,nocode } @@ -1521,7 +1539,7 @@ static void generate_checksum_block(mips3_state *mips3, drcuml_block *block, com UML_COMMENT(block, "[Validation for %08X]", seqhead->pc); // comment /* loose verify or single instruction: just compare and fail */ - if (!(mips3->impstate->drcoptions & MIPS3DRC_STRICT_VERIFY) || seqhead->next == NULL) + if (!(mips3->impstate->drcoptions & MIPS3DRC_STRICT_VERIFY) || seqhead->next() == NULL) { if (!(seqhead->flags & OPFLAG_VIRTUAL_NOOP)) { @@ -1536,7 +1554,7 @@ static void generate_checksum_block(mips3_state *mips3, drcuml_block *block, com else { #if 0 - for (curdesc = seqhead->next; curdesc != seqlast->next; curdesc = curdesc->next) + for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next()) if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP)) { void *base = mips3->direct->read_decrypted_ptr(seqhead->physpc); @@ -1549,7 +1567,7 @@ static void generate_checksum_block(mips3_state *mips3, drcuml_block *block, com void *base = mips3->direct->read_decrypted_ptr(seqhead->physpc); UML_LOAD(block, IREG(0), base, IMM(0), DWORD); // load i0,base,0,dword sum += seqhead->opptr.l[0]; - for (curdesc = seqhead->next; curdesc != seqlast->next; curdesc = curdesc->next) + for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next()) if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP)) { base = mips3->direct->read_decrypted_ptr(curdesc->physpc); @@ -1557,12 +1575,12 @@ static void generate_checksum_block(mips3_state *mips3, drcuml_block *block, com UML_ADD(block, IREG(0), IREG(0), IREG(1)); // add i0,i0,i1 sum += curdesc->opptr.l[0]; - if (curdesc->delay != NULL && (curdesc == seqlast || (curdesc->next != NULL && curdesc->next->physpc != curdesc->delay->physpc))) + if (curdesc->delay.first() != NULL && (curdesc == seqlast || (curdesc->next() != NULL && curdesc->next()->physpc != curdesc->delay.first()->physpc))) { - base = mips3->direct->read_decrypted_ptr(curdesc->delay->physpc); + base = mips3->direct->read_decrypted_ptr(curdesc->delay.first()->physpc); UML_LOAD(block, IREG(1), base, IMM(0), DWORD); // load i1,base,dword UML_ADD(block, IREG(0), IREG(0), IREG(1)); // add i0,i0,i1 - sum += curdesc->delay->opptr.l[0]; + sum += curdesc->delay.first()->opptr.l[0]; } } UML_CMP(block, IREG(0), IMM(sum)); // cmp i0,sum @@ -1710,8 +1728,8 @@ static void generate_delay_slot_and_branch(mips3_state *mips3, drcuml_block *blo UML_DMOV(block, R64(linkreg), IMM((INT32)(desc->pc + 8))); // dmov <linkreg>,desc->pc + 8 /* compile the delay slot using temporary compiler state */ - assert(desc->delay != NULL); - generate_sequence_instruction(mips3, block, &compiler_temp, desc->delay); // <next instruction> + assert(desc->delay.first() != NULL); + generate_sequence_instruction(mips3, block, &compiler_temp, desc->delay.first()); // <next instruction> /* update the cycles and jump through the hash table to the target */ if (desc->targetpc != BRANCH_TARGET_DYNAMIC) @@ -3648,7 +3666,7 @@ static void log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, i drcuml_log_printf(drcuml, "\nDescriptor list @ %08X\n", desclist->pc); /* output each descriptor */ - for ( ; desclist != NULL; desclist = desclist->next) + for ( ; desclist != NULL; desclist = desclist->next()) { char buffer[100]; @@ -3669,8 +3687,8 @@ static void log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, i drcuml_log_printf(drcuml, "\n"); /* if we have a delay slot, output it recursively */ - if (desclist->delay != NULL) - log_opcode_desc(drcuml, desclist->delay, indent + 1); + if (desclist->delay.first() != NULL) + log_opcode_desc(drcuml, desclist->delay.first(), indent + 1); /* at the end of a sequence add a dividing line */ if (desclist->flags & OPFLAG_END_SEQUENCE) diff --git a/src/emu/cpu/mips/mips3fe.c b/src/emu/cpu/mips/mips3fe.c index b7254c27b4a..dbc5b8f40bd 100644 --- a/src/emu/cpu/mips/mips3fe.c +++ b/src/emu/cpu/mips/mips3fe.c @@ -4,9 +4,36 @@ Front-end for MIPS3 recompiler +**************************************************************************** + Copyright Aaron Giles - Released for general non-commercial use under the MAME license - Visit http://mamedev.org for licensing and usage restrictions. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name 'MAME' nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. ***************************************************************************/ @@ -15,740 +42,729 @@ #include "mips3com.h" -/*************************************************************************** - FUNCTION PROTOTYPES -***************************************************************************/ - -static int describe_instruction_special(mips3_state *mips, UINT32 op, opcode_desc *desc); -static int describe_instruction_regimm(mips3_state *mips, UINT32 op, opcode_desc *desc); -static int describe_instruction_idt(mips3_state *mips, UINT32 op, opcode_desc *desc); -static int describe_instruction_cop0(mips3_state *mips, UINT32 op, opcode_desc *desc); -static int describe_instruction_cop1(mips3_state *mips, UINT32 op, opcode_desc *desc); -static int describe_instruction_cop1x(mips3_state *mips, UINT32 op, opcode_desc *desc); -static int describe_instruction_cop2(mips3_state *mips, UINT32 op, opcode_desc *desc); +//************************************************************************** +// MIPS3 FRONTEND +//************************************************************************** +//------------------------------------------------- +// mips3_frontend - constructor +//------------------------------------------------- +mips3_frontend::mips3_frontend(mips3_state &state, UINT32 window_start, UINT32 window_end, UINT32 max_sequence) + : drc_frontend(*state.device, window_start, window_end, max_sequence), + m_context(state) +{ +} -/*************************************************************************** - INSTRUCTION PARSERS -***************************************************************************/ -/*------------------------------------------------- - describe_instruction - build a description - of a single instruction --------------------------------------------------*/ +//------------------------------------------------- +// describe - build a description of a single +// instruction +//------------------------------------------------- -int mips3fe_describe(void *param, opcode_desc *desc, const opcode_desc *prev) +bool mips3_frontend::describe(opcode_desc &desc, const opcode_desc *prev) { - mips3_state *mips = (mips3_state *)param; UINT32 op, opswitch; - /* compute the physical PC */ - assert((desc->physpc & 3) == 0); - if (!mips3com_translate_address(mips, ADDRESS_SPACE_PROGRAM, TRANSLATE_FETCH, &desc->physpc)) + // compute the physical PC + assert((desc.physpc & 3) == 0); + if (!mips3com_translate_address(&m_context, ADDRESS_SPACE_PROGRAM, TRANSLATE_FETCH, &desc.physpc)) { - /* uh-oh: a page fault; leave the description empty and just if this is the first instruction, leave it empty and */ - /* mark as needing to validate; otherwise, just end the sequence here */ - desc->flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_COMPILER_PAGE_FAULT | OPFLAG_VIRTUAL_NOOP | OPFLAG_END_SEQUENCE; - return TRUE; + // uh-oh: a page fault; leave the description empty and just if this is the first instruction, leave it empty and + // mark as needing to validate; otherwise, just end the sequence here + desc.flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_COMPILER_PAGE_FAULT | OPFLAG_VIRTUAL_NOOP | OPFLAG_END_SEQUENCE; + return true; } - /* fetch the opcode */ - assert((desc->physpc & 3) == 0); - op = desc->opptr.l[0] = mips->direct->read_decrypted_dword(desc->physpc); + // fetch the opcode + assert((desc.physpc & 3) == 0); + op = desc.opptr.l[0] = m_context.direct->read_decrypted_dword(desc.physpc); - /* all instructions are 4 bytes and default to a single cycle each */ - desc->length = 4; - desc->cycles = 1; + // all instructions are 4 bytes and default to a single cycle each + desc.length = 4; + desc.cycles = 1; - /* parse the instruction */ + // parse the instruction opswitch = op >> 26; switch (opswitch) { - case 0x00: /* SPECIAL */ - return describe_instruction_special(mips, op, desc); - - case 0x01: /* REGIMM */ - return describe_instruction_regimm(mips, op, desc); - - case 0x10: /* COP0 */ - return describe_instruction_cop0(mips, op, desc); - - case 0x11: /* COP1 */ - return describe_instruction_cop1(mips, op, desc); - - case 0x12: /* COP2 */ - return describe_instruction_cop2(mips, op, desc); - - case 0x13: /* COP1X - MIPS IV */ - if (mips->flavor < MIPS3_TYPE_MIPS_IV) - return FALSE; - return describe_instruction_cop1x(mips, op, desc); - - case 0x1c: /* IDT-specific opcodes: mad/madu/mul on R4640/4650, msub on RC32364 */ - return describe_instruction_idt(mips, op, desc); - - case 0x02: /* J */ - desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; - desc->targetpc = (desc->pc & 0xf0000000) | (LIMMVAL << 2); - desc->delayslots = 1; - return TRUE; - - case 0x03: /* JAL */ - desc->regout[0] |= REGFLAG_R(31); - desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; - desc->targetpc = (desc->pc & 0xf0000000) | (LIMMVAL << 2); - desc->delayslots = 1; - return TRUE; - - case 0x04: /* BEQ */ - case 0x05: /* BNE */ - case 0x14: /* BEQL */ - case 0x15: /* BNEL */ + case 0x00: // SPECIAL + return describe_special(op, desc); + + case 0x01: // REGIMM + return describe_regimm(op, desc); + + case 0x10: // COP0 + return describe_cop0(op, desc); + + case 0x11: // COP1 + return describe_cop1(op, desc); + + case 0x12: // COP2 + return describe_cop2(op, desc); + + case 0x13: // COP1X - MIPS IV + if (m_context.flavor < MIPS3_TYPE_MIPS_IV) + return false; + return describe_cop1x(op, desc); + + case 0x1c: // IDT-specific opcodes: mad/madu/mul on R4640/4650, msub on RC32364 + return describe_idt(op, desc); + + case 0x02: // J + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = (desc.pc & 0xf0000000) | (LIMMVAL << 2); + desc.delayslots = 1; + return true; + + case 0x03: // JAL + desc.regout[0] |= REGFLAG_R(31); + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = (desc.pc & 0xf0000000) | (LIMMVAL << 2); + desc.delayslots = 1; + return true; + + case 0x04: // BEQ + case 0x05: // BNE + case 0x14: // BEQL + case 0x15: // BNEL if ((opswitch == 0x04 || opswitch == 0x14) && RSREG == RTREG) - desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; else { - desc->regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); - desc->flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; } - desc->targetpc = desc->pc + 4 + (SIMMVAL << 2); - desc->delayslots = 1; - desc->skipslots = (opswitch & 0x10) ? 1 : 0; - return TRUE; - - case 0x06: /* BLEZ */ - case 0x07: /* BGTZ */ - case 0x16: /* BLEZL */ - case 0x17: /* BGTZL */ + desc.targetpc = desc.pc + 4 + (SIMMVAL << 2); + desc.delayslots = 1; + desc.skipslots = (opswitch & 0x10) ? 1 : 0; + return true; + + case 0x06: // BLEZ + case 0x07: // BGTZ + case 0x16: // BLEZL + case 0x17: // BGTZL if ((opswitch == 0x06 || opswitch == 0x16) && RSREG == 0) - desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; else { - desc->regin[0] |= REGFLAG_R(RSREG); - desc->flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + desc.regin[0] |= REGFLAG_R(RSREG); + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; } - desc->targetpc = desc->pc + 4 + (SIMMVAL << 2); - desc->delayslots = 1; - desc->skipslots = (opswitch & 0x10) ? 1 : 0; - return TRUE; - - case 0x08: /* ADDI */ - case 0x18: /* DADDI */ - desc->regin[0] |= REGFLAG_R(RSREG); - desc->regout[0] |= REGFLAG_R(RTREG); - desc->flags |= OPFLAG_CAN_CAUSE_EXCEPTION; - return TRUE; - - case 0x09: /* ADDIU */ - case 0x0a: /* SLTI */ - case 0x0b: /* SLTIU */ - case 0x0c: /* ANDI */ - case 0x0d: /* ORI */ - case 0x0e: /* XORI */ - case 0x19: /* DADDIU */ - desc->regin[0] |= REGFLAG_R(RSREG); - desc->regout[0] |= REGFLAG_R(RTREG); - return TRUE; - - case 0x0f: /* LUI */ - desc->regout[0] |= REGFLAG_R(RTREG); - return TRUE; - - case 0x1a: /* LDL */ - case 0x1b: /* LDR */ - case 0x22: /* LWL */ - case 0x26: /* LWR */ - desc->regin[0] |= REGFLAG_R(RTREG); - case 0x20: /* LB */ - case 0x21: /* LH */ - case 0x23: /* LW */ - case 0x24: /* LBU */ - case 0x25: /* LHU */ - case 0x27: /* LWU */ - case 0x30: /* LL */ - case 0x34: /* LLD */ - case 0x37: /* LD */ - desc->regin[0] |= REGFLAG_R(RSREG); - desc->regout[0] |= REGFLAG_R(RTREG); - desc->flags |= OPFLAG_READS_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION; - return TRUE; - - case 0x28: /* SB */ - case 0x29: /* SH */ - case 0x2a: /* SWL */ - case 0x2b: /* SW */ - case 0x2c: /* SDL */ - case 0x2d: /* SDR */ - case 0x2e: /* SWR */ - case 0x3f: /* SD */ - desc->regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); - desc->flags |= OPFLAG_WRITES_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION; - return TRUE; - - case 0x38: /* SC */ - case 0x3c: /* SCD */ - desc->regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); - desc->regout[0] |= REGFLAG_R(RTREG); - desc->flags |= OPFLAG_WRITES_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION; - return TRUE; - - case 0x31: /* LWC1 */ - case 0x35: /* LDC1 */ - desc->regin[0] |= REGFLAG_R(RSREG); - desc->regout[1] |= REGFLAG_CPR1(RTREG); - desc->flags |= OPFLAG_READS_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION; - return TRUE; - - case 0x39: /* SWC1 */ - case 0x3d: /* SDC1 */ - desc->regin[0] |= REGFLAG_R(RSREG); - desc->regin[1] |= REGFLAG_CPR1(RTREG); - desc->flags |= OPFLAG_WRITES_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION; - return TRUE; - - case 0x32: /* LWC2 */ - case 0x36: /* LDC2 */ - desc->regin[0] |= REGFLAG_R(RSREG); - desc->flags |= OPFLAG_READS_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION; - return TRUE; - - case 0x3a: /* SWC2 */ - case 0x3e: /* SDC2 */ - desc->regin[0] |= REGFLAG_R(RSREG); - desc->flags |= OPFLAG_WRITES_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION; - return TRUE; - - case 0x33: /* PREF */ - if (mips->flavor < MIPS3_TYPE_MIPS_IV) - return FALSE; - case 0x2f: /* CACHE */ - /* effective no-op */ - return TRUE; + desc.targetpc = desc.pc + 4 + (SIMMVAL << 2); + desc.delayslots = 1; + desc.skipslots = (opswitch & 0x10) ? 1 : 0; + return true; + + case 0x08: // ADDI + case 0x18: // DADDI + desc.regin[0] |= REGFLAG_R(RSREG); + desc.regout[0] |= REGFLAG_R(RTREG); + desc.flags |= OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x09: // ADDIU + case 0x0a: // SLTI + case 0x0b: // SLTIU + case 0x0c: // ANDI + case 0x0d: // ORI + case 0x0e: // XORI + case 0x19: // DADDIU + desc.regin[0] |= REGFLAG_R(RSREG); + desc.regout[0] |= REGFLAG_R(RTREG); + return true; + + case 0x0f: // LUI + desc.regout[0] |= REGFLAG_R(RTREG); + return true; + + case 0x1a: // LDL + case 0x1b: // LDR + case 0x22: // LWL + case 0x26: // LWR + desc.regin[0] |= REGFLAG_R(RTREG); + case 0x20: // LB + case 0x21: // LH + case 0x23: // LW + case 0x24: // LBU + case 0x25: // LHU + case 0x27: // LWU + case 0x30: // LL + case 0x34: // LLD + case 0x37: // LD + desc.regin[0] |= REGFLAG_R(RSREG); + desc.regout[0] |= REGFLAG_R(RTREG); + desc.flags |= OPFLAG_READS_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x28: // SB + case 0x29: // SH + case 0x2a: // SWL + case 0x2b: // SW + case 0x2c: // SDL + case 0x2d: // SDR + case 0x2e: // SWR + case 0x3f: // SD + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.flags |= OPFLAG_WRITES_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x38: // SC + case 0x3c: // SCD + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.regout[0] |= REGFLAG_R(RTREG); + desc.flags |= OPFLAG_WRITES_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x31: // LWC1 + case 0x35: // LDC1 + desc.regin[0] |= REGFLAG_R(RSREG); + desc.regout[1] |= REGFLAG_CPR1(RTREG); + desc.flags |= OPFLAG_READS_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x39: // SWC1 + case 0x3d: // SDC1 + desc.regin[0] |= REGFLAG_R(RSREG); + desc.regin[1] |= REGFLAG_CPR1(RTREG); + desc.flags |= OPFLAG_WRITES_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x32: // LWC2 + case 0x36: // LDC2 + desc.regin[0] |= REGFLAG_R(RSREG); + desc.flags |= OPFLAG_READS_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x3a: // SWC2 + case 0x3e: // SDC2 + desc.regin[0] |= REGFLAG_R(RSREG); + desc.flags |= OPFLAG_WRITES_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x33: // PREF + if (m_context.flavor < MIPS3_TYPE_MIPS_IV) + return false; + case 0x2f: // CACHE + // effective no-op + return true; } - return FALSE; + return false; } -/*------------------------------------------------- - describe_instruction_special - build a - description of a single instruction in the - 'special' group --------------------------------------------------*/ +//------------------------------------------------- +// describe_special - build a description of a +// single instruction in the 'special' group +//------------------------------------------------- -static int describe_instruction_special(mips3_state *mips, UINT32 op, opcode_desc *desc) +bool mips3_frontend::describe_special(UINT32 op, opcode_desc &desc) { switch (op & 63) { - case 0x00: /* SLL */ - case 0x02: /* SRL */ - case 0x03: /* SRA */ - case 0x38: /* DSLL */ - case 0x3a: /* DSRL */ - case 0x3b: /* DSRA */ - case 0x3c: /* DSLL32 */ - case 0x3e: /* DSRL32 */ - case 0x3f: /* DSRA32 */ - desc->regin[0] |= REGFLAG_R(RTREG); - desc->regout[0] |= REGFLAG_R(RDREG); - return TRUE; - - case 0x0a: /* MOVZ - MIPS IV */ - case 0x0b: /* MOVN - MIPS IV */ - if (mips->flavor < MIPS3_TYPE_MIPS_IV) - return FALSE; - desc->regin[0] |= REGFLAG_R(RDREG); - case 0x04: /* SLLV */ - case 0x06: /* SRLV */ - case 0x07: /* SRAV */ - case 0x14: /* DSLLV */ - case 0x16: /* DSRLV */ - case 0x17: /* DSRAV */ - case 0x21: /* ADDU */ - case 0x23: /* SUBU */ - case 0x24: /* AND */ - case 0x25: /* OR */ - case 0x26: /* XOR */ - case 0x27: /* NOR */ - case 0x2a: /* SLT */ - case 0x2b: /* SLTU */ - case 0x2d: /* DADDU */ - case 0x2f: /* DSUBU */ - desc->regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); - desc->regout[0] |= REGFLAG_R(RDREG); - return TRUE; - - case 0x20: /* ADD */ - case 0x22: /* SUB */ - case 0x2c: /* DADD */ - case 0x2e: /* DSUB */ - desc->regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); - desc->regout[0] |= REGFLAG_R(RDREG); - desc->flags |= OPFLAG_CAN_CAUSE_EXCEPTION; - return TRUE; - - case 0x30: /* TGE */ - case 0x31: /* TGEU */ - case 0x32: /* TLT */ - case 0x33: /* TLTU */ - case 0x34: /* TEQ */ - case 0x36: /* TNE */ - desc->regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); - desc->flags |= OPFLAG_CAN_CAUSE_EXCEPTION; - return TRUE; - - case 0x01: /* MOVF - MIPS IV */ - if (mips->flavor < MIPS3_TYPE_MIPS_IV) - return FALSE; - desc->regin[0] |= REGFLAG_R(RSREG); - desc->regin[2] |= REGFLAG_FCC; - desc->regout[0] |= REGFLAG_R(RDREG); - return TRUE; - - case 0x08: /* JR */ - desc->regin[0] |= REGFLAG_R(RSREG); - desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; - desc->targetpc = BRANCH_TARGET_DYNAMIC; - desc->delayslots = 1; - return TRUE; - - case 0x09: /* JALR */ - desc->regin[0] |= REGFLAG_R(RSREG); - desc->regout[0] |= REGFLAG_R(RDREG); - desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; - desc->targetpc = BRANCH_TARGET_DYNAMIC; - desc->delayslots = 1; - return TRUE; - - case 0x10: /* MFHI */ - desc->regin[0] |= REGFLAG_HI; - desc->regout[0] |= REGFLAG_R(RDREG); - return TRUE; - - case 0x11: /* MTHI */ - desc->regin[0] |= REGFLAG_R(RSREG); - desc->regout[0] |= REGFLAG_HI; - return TRUE; - - case 0x12: /* MFLO */ - desc->regin[2] |= REGFLAG_LO; - desc->regout[0] |= REGFLAG_R(RDREG); - return TRUE; - - case 0x13: /* MTLO */ - desc->regin[0] |= REGFLAG_R(RSREG); - desc->regout[2] |= REGFLAG_LO; - return TRUE; - - case 0x18: /* MULT */ - case 0x19: /* MULTU */ - desc->regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); - desc->regout[2] |= REGFLAG_LO | REGFLAG_HI; - desc->cycles = 3; - return TRUE; - - case 0x1a: /* DIV */ - case 0x1b: /* DIVU */ - desc->regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); - desc->regout[2] |= REGFLAG_LO | REGFLAG_HI; - desc->cycles = 35; - return TRUE; - - case 0x1c: /* DMULT */ - case 0x1d: /* DMULTU */ - desc->regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); - desc->regout[2] |= REGFLAG_LO | REGFLAG_HI; - desc->cycles = 7; - return TRUE; - - case 0x1e: /* DDIV */ - case 0x1f: /* DDIVU */ - desc->regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); - desc->regout[2] |= REGFLAG_LO | REGFLAG_HI; - desc->cycles = 67; - return TRUE; - - case 0x0c: /* SYSCALL */ - case 0x0d: /* BREAK */ - desc->flags |= OPFLAG_WILL_CAUSE_EXCEPTION | OPFLAG_END_SEQUENCE; - return TRUE; - - case 0x0f: /* SYNC */ - /* effective no-op */ - return TRUE; + case 0x00: // SLL + case 0x02: // SRL + case 0x03: // SRA + case 0x38: // DSLL + case 0x3a: // DSRL + case 0x3b: // DSRA + case 0x3c: // DSLL32 + case 0x3e: // DSRL32 + case 0x3f: // DSRA32 + desc.regin[0] |= REGFLAG_R(RTREG); + desc.regout[0] |= REGFLAG_R(RDREG); + return true; + + case 0x0a: // MOVZ - MIPS IV + case 0x0b: // MOVN - MIPS IV + if (m_context.flavor < MIPS3_TYPE_MIPS_IV) + return false; + desc.regin[0] |= REGFLAG_R(RDREG); + case 0x04: // SLLV + case 0x06: // SRLV + case 0x07: // SRAV + case 0x14: // DSLLV + case 0x16: // DSRLV + case 0x17: // DSRAV + case 0x21: // ADDU + case 0x23: // SUBU + case 0x24: // AND + case 0x25: // OR + case 0x26: // XOR + case 0x27: // NOR + case 0x2a: // SLT + case 0x2b: // SLTU + case 0x2d: // DADDU + case 0x2f: // DSUBU + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.regout[0] |= REGFLAG_R(RDREG); + return true; + + case 0x20: // ADD + case 0x22: // SUB + case 0x2c: // DADD + case 0x2e: // DSUB + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.regout[0] |= REGFLAG_R(RDREG); + desc.flags |= OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x30: // TGE + case 0x31: // TGEU + case 0x32: // TLT + case 0x33: // TLTU + case 0x34: // TEQ + case 0x36: // TNE + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.flags |= OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x01: // MOVF - MIPS IV + if (m_context.flavor < MIPS3_TYPE_MIPS_IV) + return false; + desc.regin[0] |= REGFLAG_R(RSREG); + desc.regin[2] |= REGFLAG_FCC; + desc.regout[0] |= REGFLAG_R(RDREG); + return true; + + case 0x08: // JR + desc.regin[0] |= REGFLAG_R(RSREG); + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + desc.delayslots = 1; + return true; + + case 0x09: // JALR + desc.regin[0] |= REGFLAG_R(RSREG); + desc.regout[0] |= REGFLAG_R(RDREG); + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + desc.delayslots = 1; + return true; + + case 0x10: // MFHI + desc.regin[0] |= REGFLAG_HI; + desc.regout[0] |= REGFLAG_R(RDREG); + return true; + + case 0x11: // MTHI + desc.regin[0] |= REGFLAG_R(RSREG); + desc.regout[0] |= REGFLAG_HI; + return true; + + case 0x12: // MFLO + desc.regin[2] |= REGFLAG_LO; + desc.regout[0] |= REGFLAG_R(RDREG); + return true; + + case 0x13: // MTLO + desc.regin[0] |= REGFLAG_R(RSREG); + desc.regout[2] |= REGFLAG_LO; + return true; + + case 0x18: // MULT + case 0x19: // MULTU + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.regout[2] |= REGFLAG_LO | REGFLAG_HI; + desc.cycles = 3; + return true; + + case 0x1a: // DIV + case 0x1b: // DIVU + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.regout[2] |= REGFLAG_LO | REGFLAG_HI; + desc.cycles = 35; + return true; + + case 0x1c: // DMULT + case 0x1d: // DMULTU + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.regout[2] |= REGFLAG_LO | REGFLAG_HI; + desc.cycles = 7; + return true; + + case 0x1e: // DDIV + case 0x1f: // DDIVU + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.regout[2] |= REGFLAG_LO | REGFLAG_HI; + desc.cycles = 67; + return true; + + case 0x0c: // SYSCALL + case 0x0d: // BREAK + desc.flags |= OPFLAG_WILL_CAUSE_EXCEPTION | OPFLAG_END_SEQUENCE; + return true; + + case 0x0f: // SYNC + // effective no-op + return true; } - return FALSE; + return false; } -/*------------------------------------------------- - describe_instruction_regimm - build a - description of a single instruction in the - 'regimm' group --------------------------------------------------*/ +//------------------------------------------------- +// describe_regimm - build a description of a +// single instruction in the 'regimm' group +//------------------------------------------------- -static int describe_instruction_regimm(mips3_state *mips, UINT32 op, opcode_desc *desc) +bool mips3_frontend::describe_regimm(UINT32 op, opcode_desc &desc) { switch (RTREG) { - case 0x00: /* BLTZ */ - case 0x01: /* BGEZ */ - case 0x02: /* BLTZL */ - case 0x03: /* BGEZL */ + case 0x00: // BLTZ + case 0x01: // BGEZ + case 0x02: // BLTZL + case 0x03: // BGEZL if (RTREG == 0x01 && RSREG == 0) - desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; else { - desc->regin[0] |= REGFLAG_R(RSREG); - desc->flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + desc.regin[0] |= REGFLAG_R(RSREG); + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; } - desc->targetpc = desc->pc + 4 + (SIMMVAL << 2); - desc->delayslots = 1; - desc->skipslots = (RTREG & 0x02) ? 1 : 0; - return TRUE; - - case 0x08: /* TGEI */ - case 0x09: /* TGEIU */ - case 0x0a: /* TLTI */ - case 0x0b: /* TLTIU */ - case 0x0c: /* TEQI */ - case 0x0e: /* TNEI */ - desc->regin[0] |= REGFLAG_R(RSREG); - desc->flags |= OPFLAG_CAN_CAUSE_EXCEPTION; - return TRUE; - - case 0x10: /* BLTZAL */ - case 0x11: /* BGEZAL */ - case 0x12: /* BLTZALL */ - case 0x13: /* BGEZALL */ + desc.targetpc = desc.pc + 4 + (SIMMVAL << 2); + desc.delayslots = 1; + desc.skipslots = (RTREG & 0x02) ? 1 : 0; + return true; + + case 0x08: // TGEI + case 0x09: // TGEIU + case 0x0a: // TLTI + case 0x0b: // TLTIU + case 0x0c: // TEQI + case 0x0e: // TNEI + desc.regin[0] |= REGFLAG_R(RSREG); + desc.flags |= OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x10: // BLTZAL + case 0x11: // BGEZAL + case 0x12: // BLTZALL + case 0x13: // BGEZALL if (RTREG == 0x11 && RSREG == 0) - desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; else { - desc->regin[0] |= REGFLAG_R(RSREG); - desc->flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + desc.regin[0] |= REGFLAG_R(RSREG); + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; } - desc->regout[0] |= REGFLAG_R(31); - desc->targetpc = desc->pc + 4 + (SIMMVAL << 2); - desc->delayslots = 1; - desc->skipslots = (RTREG & 0x02) ? 1 : 0; - return TRUE; + desc.regout[0] |= REGFLAG_R(31); + desc.targetpc = desc.pc + 4 + (SIMMVAL << 2); + desc.delayslots = 1; + desc.skipslots = (RTREG & 0x02) ? 1 : 0; + return true; } - return FALSE; + return false; } -/*------------------------------------------------- - describe_instruction_idt - build a - description of a single instruction in the - IDT-specific group --------------------------------------------------*/ +//------------------------------------------------- +// describe_idt - build a description of a single +// instruction in the IDT-specific group +//------------------------------------------------- -static int describe_instruction_idt(mips3_state *mips, UINT32 op, opcode_desc *desc) +bool mips3_frontend::describe_idt(UINT32 op, opcode_desc &desc) { - /* only on the R4650 */ - if (mips->flavor != MIPS3_TYPE_R4650) - return FALSE; + // only on the R4650 + if (m_context.flavor != MIPS3_TYPE_R4650) + return false; switch (op & 0x1f) { - case 0: /* MAD */ - case 1: /* MADU */ - desc->regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); - desc->regin[2] |= REGFLAG_LO | REGFLAG_HI; - desc->regout[2] |= REGFLAG_LO | REGFLAG_HI; - return TRUE; - - case 2: /* MUL */ - desc->regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); - desc->regout[0] |= REGFLAG_R(RDREG); - desc->cycles = 3; - return TRUE; + case 0: // MAD + case 1: // MADU + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.regin[2] |= REGFLAG_LO | REGFLAG_HI; + desc.regout[2] |= REGFLAG_LO | REGFLAG_HI; + return true; + + case 2: // MUL + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.regout[0] |= REGFLAG_R(RDREG); + desc.cycles = 3; + return true; } - return FALSE; + return false; } -/*------------------------------------------------- - describe_instruction_cop0 - build a - description of a single instruction in the - COP0 group --------------------------------------------------*/ +//------------------------------------------------- +// describe_cop0 - build a description of a +// single instruction in the COP0 group +//------------------------------------------------- -static int describe_instruction_cop0(mips3_state *mips, UINT32 op, opcode_desc *desc) +bool mips3_frontend::describe_cop0(UINT32 op, opcode_desc &desc) { - /* any COP0 instruction can potentially cause an exception */ - desc->flags |= OPFLAG_CAN_CAUSE_EXCEPTION; + // any COP0 instruction can potentially cause an exception + desc.flags |= OPFLAG_CAN_CAUSE_EXCEPTION; switch (RSREG) { - case 0x00: /* MFCz */ - case 0x01: /* DMFCz */ + case 0x00: // MFCz + case 0x01: // DMFCz if (RDREG == COP0_Count) - desc->cycles += MIPS3_COUNT_READ_CYCLES; + desc.cycles += MIPS3_COUNT_READ_CYCLES; if (RDREG == COP0_Cause) - desc->cycles += MIPS3_CAUSE_READ_CYCLES; - desc->regout[0] |= REGFLAG_R(RTREG); - return TRUE; - - case 0x02: /* CFCz */ - desc->regout[0] |= REGFLAG_R(RTREG); - return TRUE; - - case 0x04: /* MTCz */ - case 0x05: /* DMTCz */ - case 0x06: /* CTCz */ - desc->regin[0] |= REGFLAG_R(RTREG); + desc.cycles += MIPS3_CAUSE_READ_CYCLES; + desc.regout[0] |= REGFLAG_R(RTREG); + return true; + + case 0x02: // CFCz + desc.regout[0] |= REGFLAG_R(RTREG); + return true; + + case 0x04: // MTCz + case 0x05: // DMTCz + case 0x06: // CTCz + desc.regin[0] |= REGFLAG_R(RTREG); if (RSREG == 0x04 || RSREG == 0x05) { if (RDREG == COP0_Cause) - desc->flags |= OPFLAG_CAN_TRIGGER_SW_INT; + desc.flags |= OPFLAG_CAN_TRIGGER_SW_INT; if (RDREG == COP0_Status) - desc->flags |= OPFLAG_CAN_EXPOSE_EXTERNAL_INT | OPFLAG_CAN_CHANGE_MODES | OPFLAG_END_SEQUENCE; + desc.flags |= OPFLAG_CAN_EXPOSE_EXTERNAL_INT | OPFLAG_CAN_CHANGE_MODES | OPFLAG_END_SEQUENCE; } - return TRUE; + return true; - case 0x08: /* BC */ + case 0x08: // BC switch (RTREG) { - case 0x00: /* BCzF */ - case 0x01: /* BCzT */ - desc->flags |= OPFLAG_IS_CONDITIONAL_BRANCH; - desc->targetpc = desc->pc + 4 + (SIMMVAL << 2); - desc->delayslots = 1; - return TRUE; + case 0x00: // BCzF + case 0x01: // BCzT + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + desc.targetpc = desc.pc + 4 + (SIMMVAL << 2); + desc.delayslots = 1; + return true; } - return FALSE; + return false; case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: - case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: /* COP */ + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: // COP switch (op & 0x01ffffff) { - case 0x01: /* TLBR */ - case 0x08: /* TLBP */ - case 0x20: /* WAIT */ - return TRUE; - - case 0x02: /* TLBWI */ - case 0x06: /* TLBWR */ - desc->flags |= OPFLAG_MODIFIES_TRANSLATION; - return TRUE; - - case 0x18: /* ERET */ - desc->flags |= OPFLAG_CAN_CHANGE_MODES | OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; - return TRUE; + case 0x01: // TLBR + case 0x08: // TLBP + case 0x20: // WAIT + return true; + + case 0x02: // TLBWI + case 0x06: // TLBWR + desc.flags |= OPFLAG_MODIFIES_TRANSLATION; + return true; + + case 0x18: // ERET + desc.flags |= OPFLAG_CAN_CHANGE_MODES | OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + return true; } - return FALSE; + return false; } - return FALSE; + return false; } -/*------------------------------------------------- - describe_instruction_cop1 - build a - description of a single instruction in the - COP1 group --------------------------------------------------*/ +//------------------------------------------------- +// describe_cop1 - build a description of a +// single instruction in the COP1 group +//------------------------------------------------- -static int describe_instruction_cop1(mips3_state *mips, UINT32 op, opcode_desc *desc) +bool mips3_frontend::describe_cop1(UINT32 op, opcode_desc &desc) { - /* any COP1 instruction can potentially cause an exception */ -// desc->flags |= OPFLAG_CAN_CAUSE_EXCEPTION; + // any COP1 instruction can potentially cause an exception +// desc.flags |= OPFLAG_CAN_CAUSE_EXCEPTION; switch (RSREG) { - case 0x00: /* MFCz */ - case 0x01: /* DMFCz */ - desc->regin[1] |= REGFLAG_CPR1(RDREG); - desc->regout[0] |= REGFLAG_R(RTREG); - return TRUE; - - case 0x02: /* CFCz */ - desc->regout[0] |= REGFLAG_R(RTREG); - return TRUE; - - case 0x04: /* MTCz */ - case 0x05: /* DMTCz */ - desc->regin[0] |= REGFLAG_R(RTREG); - desc->regout[1] |= REGFLAG_CPR1(RDREG); - return TRUE; - - case 0x06: /* CTCz */ - desc->regin[0] |= REGFLAG_R(RTREG); - return TRUE; - - case 0x08: /* BC */ + case 0x00: // MFCz + case 0x01: // DMFCz + desc.regin[1] |= REGFLAG_CPR1(RDREG); + desc.regout[0] |= REGFLAG_R(RTREG); + return true; + + case 0x02: // CFCz + desc.regout[0] |= REGFLAG_R(RTREG); + return true; + + case 0x04: // MTCz + case 0x05: // DMTCz + desc.regin[0] |= REGFLAG_R(RTREG); + desc.regout[1] |= REGFLAG_CPR1(RDREG); + return true; + + case 0x06: // CTCz + desc.regin[0] |= REGFLAG_R(RTREG); + return true; + + case 0x08: // BC switch (RTREG & 3) { - case 0x00: /* BCzF */ - case 0x01: /* BCzT */ - case 0x02: /* BCzFL */ - case 0x03: /* BCzTL */ - desc->regin[2] |= REGFLAG_FCC; - desc->flags |= OPFLAG_IS_CONDITIONAL_BRANCH; - desc->targetpc = desc->pc + 4 + (SIMMVAL << 2); - desc->delayslots = 1; - desc->skipslots = (RTREG & 0x02) ? 1 : 0; - return TRUE; + case 0x00: // BCzF + case 0x01: // BCzT + case 0x02: // BCzFL + case 0x03: // BCzTL + desc.regin[2] |= REGFLAG_FCC; + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + desc.targetpc = desc.pc + 4 + (SIMMVAL << 2); + desc.delayslots = 1; + desc.skipslots = (RTREG & 0x02) ? 1 : 0; + return true; } - return FALSE; + return false; case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: - case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: /* COP */ + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: // COP switch (op & 0x3f) { - case 0x12: /* MOVZ - MIPS IV */ - case 0x13: /* MOVN - MIPS IV */ - if (mips->flavor < MIPS3_TYPE_MIPS_IV) - return FALSE; - case 0x00: /* ADD */ - case 0x01: /* SUB */ - case 0x02: /* MUL */ - case 0x03: /* DIV */ - desc->regin[1] |= REGFLAG_CPR1(FSREG) | REGFLAG_CPR1(FTREG); - desc->regout[1] |= REGFLAG_CPR1(FDREG); - return TRUE; - - case 0x15: /* RECIP - MIPS IV */ - case 0x16: /* RSQRT - MIPS IV */ - if (mips->flavor < MIPS3_TYPE_MIPS_IV) - return FALSE; - case 0x04: /* SQRT */ - case 0x05: /* ABS */ - case 0x06: /* MOV */ - case 0x07: /* NEG */ - case 0x08: /* ROUND.L */ - case 0x09: /* TRUNC.L */ - case 0x0a: /* CEIL.L */ - case 0x0b: /* FLOOR.L */ - case 0x0c: /* ROUND.W */ - case 0x0d: /* TRUNC.W */ - case 0x0e: /* CEIL.W */ - case 0x0f: /* FLOOR.W */ - case 0x20: /* CVT.S */ - case 0x21: /* CVT.D */ - case 0x24: /* CVT.W */ - case 0x25: /* CVT.L */ - desc->regin[1] |= REGFLAG_CPR1(FSREG); - desc->regout[1] |= REGFLAG_CPR1(FDREG); - return TRUE; - - case 0x11: /* MOVT/F - MIPS IV */ - if (mips->flavor < MIPS3_TYPE_MIPS_IV) - return FALSE; - desc->regin[1] |= REGFLAG_CPR1(FSREG); - desc->regin[2] |= REGFLAG_FCC; - desc->regout[1] |= REGFLAG_CPR1(FDREG); - return TRUE; - - case 0x30: case 0x38: /* C.F */ - case 0x31: case 0x39: /* C.UN */ - desc->regout[2] |= REGFLAG_FCC; - return TRUE; - - case 0x32: case 0x3a: /* C.EQ */ - case 0x33: case 0x3b: /* C.UEQ */ - case 0x34: case 0x3c: /* C.OLT */ - case 0x35: case 0x3d: /* C.ULT */ - case 0x36: case 0x3e: /* C.OLE */ - case 0x37: case 0x3f: /* C.ULE */ - desc->regin[1] |= REGFLAG_CPR1(FSREG) | REGFLAG_CPR1(FTREG); - desc->regout[2] |= REGFLAG_FCC; - return TRUE; + case 0x12: // MOVZ - MIPS IV + case 0x13: // MOVN - MIPS IV + if (m_context.flavor < MIPS3_TYPE_MIPS_IV) + return false; + case 0x00: // ADD + case 0x01: // SUB + case 0x02: // MUL + case 0x03: // DIV + desc.regin[1] |= REGFLAG_CPR1(FSREG) | REGFLAG_CPR1(FTREG); + desc.regout[1] |= REGFLAG_CPR1(FDREG); + return true; + + case 0x15: // RECIP - MIPS IV + case 0x16: // RSQRT - MIPS IV + if (m_context.flavor < MIPS3_TYPE_MIPS_IV) + return false; + case 0x04: // SQRT + case 0x05: // ABS + case 0x06: // MOV + case 0x07: // NEG + case 0x08: // ROUND.L + case 0x09: // TRUNC.L + case 0x0a: // CEIL.L + case 0x0b: // FLOOR.L + case 0x0c: // ROUND.W + case 0x0d: // TRUNC.W + case 0x0e: // CEIL.W + case 0x0f: // FLOOR.W + case 0x20: // CVT.S + case 0x21: // CVT.D + case 0x24: // CVT.W + case 0x25: // CVT.L + desc.regin[1] |= REGFLAG_CPR1(FSREG); + desc.regout[1] |= REGFLAG_CPR1(FDREG); + return true; + + case 0x11: // MOVT/F - MIPS IV + if (m_context.flavor < MIPS3_TYPE_MIPS_IV) + return false; + desc.regin[1] |= REGFLAG_CPR1(FSREG); + desc.regin[2] |= REGFLAG_FCC; + desc.regout[1] |= REGFLAG_CPR1(FDREG); + return true; + + case 0x30: case 0x38: // C.F + case 0x31: case 0x39: // C.UN + desc.regout[2] |= REGFLAG_FCC; + return true; + + case 0x32: case 0x3a: // C.EQ + case 0x33: case 0x3b: // C.UEQ + case 0x34: case 0x3c: // C.OLT + case 0x35: case 0x3d: // C.ULT + case 0x36: case 0x3e: // C.OLE + case 0x37: case 0x3f: // C.ULE + desc.regin[1] |= REGFLAG_CPR1(FSREG) | REGFLAG_CPR1(FTREG); + desc.regout[2] |= REGFLAG_FCC; + return true; } - return FALSE; + return false; } - return FALSE; + return false; } -/*------------------------------------------------- - describe_instruction_cop1x - build a - description of a single instruction in the - COP1X group --------------------------------------------------*/ +//------------------------------------------------- +// describe_cop1x - build a description of a +// single instruction in the COP1X group +//------------------------------------------------- -static int describe_instruction_cop1x(mips3_state *mips, UINT32 op, opcode_desc *desc) +bool mips3_frontend::describe_cop1x(UINT32 op, opcode_desc &desc) { - /* any COP1 instruction can potentially cause an exception */ -// desc->flags |= OPFLAG_CAN_CAUSE_EXCEPTION; + // any COP1 instruction can potentially cause an exception +// desc.flags |= OPFLAG_CAN_CAUSE_EXCEPTION; switch (op & 0x3f) { - case 0x00: /* LWXC1 */ - case 0x01: /* LDXC1 */ - desc->regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); - desc->regout[1] |= REGFLAG_CPR1(FDREG); - desc->flags |= OPFLAG_READS_MEMORY; - return TRUE; - - case 0x08: /* SWXC1 */ - case 0x09: /* SDXC1 */ - desc->regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); - desc->regin[1] |= REGFLAG_CPR1(FDREG); - desc->flags |= OPFLAG_WRITES_MEMORY; - return TRUE; - - case 0x0f: /* PREFX */ - /* effective no-op */ - return TRUE; - - case 0x20: case 0x21: /* MADD */ - case 0x28: case 0x29: /* MSUB */ - case 0x30: case 0x31: /* NMADD */ - case 0x38: case 0x39: /* NMSUB */ - desc->regin[1] |= REGFLAG_CPR1(FSREG) | REGFLAG_CPR1(FTREG) | REGFLAG_CPR1(FRREG); - desc->regout[1] |= REGFLAG_CPR1(FDREG); - return TRUE; + case 0x00: // LWXC1 + case 0x01: // LDXC1 + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.regout[1] |= REGFLAG_CPR1(FDREG); + desc.flags |= OPFLAG_READS_MEMORY; + return true; + + case 0x08: // SWXC1 + case 0x09: // SDXC1 + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.regin[1] |= REGFLAG_CPR1(FDREG); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; + + case 0x0f: // PREFX + // effective no-op + return true; + + case 0x20: case 0x21: // MADD + case 0x28: case 0x29: // MSUB + case 0x30: case 0x31: // NMADD + case 0x38: case 0x39: // NMSUB + desc.regin[1] |= REGFLAG_CPR1(FSREG) | REGFLAG_CPR1(FTREG) | REGFLAG_CPR1(FRREG); + desc.regout[1] |= REGFLAG_CPR1(FDREG); + return true; } - return FALSE; + return false; } -/*------------------------------------------------- - describe_instruction_cop2 - build a - description of a single instruction in the - COP2 group --------------------------------------------------*/ +//------------------------------------------------- +// describe_cop2 - build a description of a +// single instruction in the COP2 group +//------------------------------------------------- -static int describe_instruction_cop2(mips3_state *mips, UINT32 op, opcode_desc *desc) +bool mips3_frontend::describe_cop2(UINT32 op, opcode_desc &desc) { - /* any COP2 instruction can potentially cause an exception */ - desc->flags |= OPFLAG_CAN_CAUSE_EXCEPTION; + // any COP2 instruction can potentially cause an exception + desc.flags |= OPFLAG_CAN_CAUSE_EXCEPTION; switch (RSREG) { - case 0x00: /* MFCz */ - case 0x01: /* DMFCz */ - case 0x02: /* CFCz */ - desc->regout[0] |= REGFLAG_R(RTREG); - return TRUE; - - case 0x04: /* MTCz */ - case 0x05: /* DMTCz */ - case 0x06: /* CTCz */ - desc->regin[0] |= REGFLAG_R(RTREG); - return TRUE; - - case 0x08: /* BC */ + case 0x00: // MFCz + case 0x01: // DMFCz + case 0x02: // CFCz + desc.regout[0] |= REGFLAG_R(RTREG); + return true; + + case 0x04: // MTCz + case 0x05: // DMTCz + case 0x06: // CTCz + desc.regin[0] |= REGFLAG_R(RTREG); + return true; + + case 0x08: // BC switch (RTREG) { - case 0x00: /* BCzF */ - case 0x01: /* BCzT */ - desc->flags |= OPFLAG_IS_CONDITIONAL_BRANCH; - desc->targetpc = desc->pc + 4 + (SIMMVAL << 2); - desc->delayslots = 1; - return TRUE; + case 0x00: // BCzF + case 0x01: // BCzT + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + desc.targetpc = desc.pc + 4 + (SIMMVAL << 2); + desc.delayslots = 1; + return true; } - return FALSE; + return false; } - return FALSE; + return false; } diff --git a/src/emu/cpu/mips/mips3fe.h b/src/emu/cpu/mips/mips3fe.h index 6ba3cc2c21f..aefcc676795 100644 --- a/src/emu/cpu/mips/mips3fe.h +++ b/src/emu/cpu/mips/mips3fe.h @@ -4,9 +4,36 @@ Front-end for MIPS3 recompiler +**************************************************************************** + Copyright Aaron Giles - Released for general non-commercial use under the MAME license - Visit http://mamedev.org for licensing and usage restrictions. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name 'MAME' nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. ***************************************************************************/ @@ -15,30 +42,54 @@ #ifndef __MIPS3FE_H__ #define __MIPS3FE_H__ +#include "mips3com.h" #include "cpu/drcfe.h" -/*************************************************************************** - CONSTANTS -***************************************************************************/ +//************************************************************************** +// MACROS +//************************************************************************** -/* register flags 0 */ +// register flags 0 #define REGFLAG_R(n) (((n) == 0) ? 0 : (1 << (n))) -/* register flags 1 */ +// register flags 1 #define REGFLAG_CPR1(n) (1 << (n)) -/* register flags 2 */ +// register flags 2 #define REGFLAG_LO (1 << 0) #define REGFLAG_HI (1 << 1) #define REGFLAG_FCC (1 << 2) -/*************************************************************************** - FUNCTION PROTOTYPES -***************************************************************************/ +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class mips3_frontend : public drc_frontend +{ +public: + // construction/destruction + mips3_frontend(mips3_state &state, UINT32 window_start, UINT32 window_end, UINT32 max_sequence); + +protected: + // required overrides + virtual bool describe(opcode_desc &desc, const opcode_desc *prev); + +private: + // internal helpers + bool describe_special(UINT32 op, opcode_desc &desc); + bool describe_regimm(UINT32 op, opcode_desc &desc); + bool describe_idt(UINT32 op, opcode_desc &desc); + bool describe_cop0(UINT32 op, opcode_desc &desc); + bool describe_cop1(UINT32 op, opcode_desc &desc); + bool describe_cop1x(UINT32 op, opcode_desc &desc); + bool describe_cop2(UINT32 op, opcode_desc &desc); + + // internal state + mips3_state &m_context; +}; -int mips3fe_describe(void *param, opcode_desc *desc, const opcode_desc *prev); #endif /* __MIPS3FE_H__ */ diff --git a/src/emu/cpu/powerpc/ppcdrc.c b/src/emu/cpu/powerpc/ppcdrc.c index 067443a1bc8..520b0729743 100644 --- a/src/emu/cpu/powerpc/ppcdrc.c +++ b/src/emu/cpu/powerpc/ppcdrc.c @@ -165,7 +165,7 @@ struct _ppcimp_state /* core state */ drccache * cache; /* pointer to the DRC code cache */ drcuml_state * drcuml; /* DRC UML generator state */ - drcfe_state * drcfe; /* pointer to the DRC front-end state */ + ppc_frontend * drcfe; /* pointer to the DRC front-end state */ UINT32 drcoptions; /* configurable DRC options */ /* parameters for subroutines */ @@ -548,13 +548,6 @@ INLINE UINT32 compute_spr(UINT32 spr) static void ppcdrc_init(powerpc_flavor flavor, UINT8 cap, int tb_divisor, legacy_cpu_device *device, device_irq_callback irqcallback) { - drcfe_config feconfig = - { - COMPILE_BACKWARDS_BYTES, /* code window start offset = startpc - window_start */ - COMPILE_FORWARDS_BYTES, /* code window end offset = startpc + window_end */ - COMPILE_MAX_SEQUENCE, /* maximum instructions to include in a sequence */ - ppcfe_describe /* callback to describe a single instruction */ - }; powerpc_state *ppc; drcbe_info beinfo; UINT32 flags = 0; @@ -633,9 +626,7 @@ static void ppcdrc_init(powerpc_flavor flavor, UINT8 cap, int tb_divisor, legacy drcuml_symbol_add(ppc->impstate->drcuml, &ppc->impstate->fcmp_cr_table, sizeof(ppc->impstate->fcmp_cr_table), "fcmp_cr_table"); /* initialize the front-end helper */ - if (SINGLE_INSTRUCTION_MODE) - feconfig.max_sequence = 1; - ppc->impstate->drcfe = drcfe_init(device, &feconfig, ppc); + ppc->impstate->drcfe = auto_alloc(device->machine, ppc_frontend(*ppc, COMPILE_BACKWARDS_BYTES, COMPILE_FORWARDS_BYTES, SINGLE_INSTRUCTION_MODE ? 1 : COMPILE_MAX_SEQUENCE)); /* initialize the implementation state tables */ memcpy(ppc->impstate->fpmode, fpmode_source, sizeof(fpmode_source)); @@ -738,7 +729,7 @@ static CPU_EXIT( ppcdrc ) ppccom_exit(ppc); /* clean up the DRC */ - drcfe_exit(ppc->impstate->drcfe); + auto_free(device->machine, ppc->impstate->drcfe); drcuml_free(ppc->impstate->drcuml); drccache_free(ppc->impstate->cache); } @@ -950,7 +941,7 @@ static void code_compile_block(powerpc_state *ppc, UINT8 mode, offs_t pc) g_profiler.start(PROFILER_DRC_COMPILE); /* get a description of this sequence */ - desclist = drcfe_describe_code(ppc->impstate->drcfe, pc); + desclist = ppc->impstate->drcfe->describe_code(pc); if (LOG_UML || LOG_NATIVE) log_opcode_desc(drcuml, desclist, 0); @@ -962,7 +953,7 @@ static void code_compile_block(powerpc_state *ppc, UINT8 mode, offs_t pc) block = drcuml_block_begin(drcuml, 4096, &errorbuf); /* loop until we get through all instruction sequences */ - for (seqhead = desclist; seqhead != NULL; seqhead = seqlast->next) + for (seqhead = desclist; seqhead != NULL; seqhead = seqlast->next()) { const opcode_desc *curdesc; UINT32 nextpc; @@ -972,7 +963,7 @@ static void code_compile_block(powerpc_state *ppc, UINT8 mode, offs_t pc) UML_COMMENT(block, "-------------------------"); // comment /* determine the last instruction in this sequence */ - for (seqlast = seqhead; seqlast != NULL; seqlast = seqlast->next) + for (seqlast = seqhead; seqlast != NULL; seqlast = seqlast->next()) if (seqlast->flags & OPFLAG_END_SEQUENCE) break; assert(seqlast != NULL); @@ -1007,7 +998,7 @@ static void code_compile_block(powerpc_state *ppc, UINT8 mode, offs_t pc) UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc | 0x80000000 /* iterate over instructions in the sequence and compile them */ - for (curdesc = seqhead; curdesc != seqlast->next; curdesc = curdesc->next) + for (curdesc = seqhead; curdesc != seqlast->next(); curdesc = curdesc->next()) generate_sequence_instruction(ppc, block, &compiler, curdesc); // <instruction> /* if we need to return to the start, do it */ @@ -1024,7 +1015,7 @@ static void code_compile_block(powerpc_state *ppc, UINT8 mode, offs_t pc) /* if the last instruction can change modes, use a variable mode; otherwise, assume the same mode */ if (seqlast->flags & OPFLAG_CAN_CHANGE_MODES) UML_HASHJMP(block, MEM(&ppc->impstate->mode), IMM(nextpc), ppc->impstate->nocode);// hashjmp <mode>,nextpc,nocode - else if (seqlast->next == NULL || seqlast->next->pc != nextpc) + else if (seqlast->next() == NULL || seqlast->next()->pc != nextpc) UML_HASHJMP(block, IMM(ppc->impstate->mode), IMM(nextpc), ppc->impstate->nocode);// hashjmp <mode>,nextpc,nocode } @@ -2093,7 +2084,7 @@ static void generate_checksum_block(powerpc_state *ppc, drcuml_block *block, com UML_COMMENT(block, "[Validation for %08X]", seqhead->pc); // comment /* loose verify or single instruction: just compare and fail */ - if (!(ppc->impstate->drcoptions & PPCDRC_STRICT_VERIFY) || seqhead->next == NULL) + if (!(ppc->impstate->drcoptions & PPCDRC_STRICT_VERIFY) || seqhead->next() == NULL) { if (!(seqhead->flags & OPFLAG_VIRTUAL_NOOP)) { @@ -2108,7 +2099,7 @@ static void generate_checksum_block(powerpc_state *ppc, drcuml_block *block, com else { #if 0 - for (curdesc = seqhead->next; curdesc != seqlast->next; curdesc = curdesc->next) + for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next()) if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP)) { void *base = ppc->direct->read_decrypted_ptr(seqhead->physpc, ppc->codexor); @@ -2121,7 +2112,7 @@ static void generate_checksum_block(powerpc_state *ppc, drcuml_block *block, com void *base = ppc->direct->read_decrypted_ptr(seqhead->physpc, ppc->codexor); UML_LOAD(block, IREG(0), base, IMM(0), DWORD); // load i0,base,dword sum += seqhead->opptr.l[0]; - for (curdesc = seqhead->next; curdesc != seqlast->next; curdesc = curdesc->next) + for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next()) if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP)) { base = ppc->direct->read_decrypted_ptr(curdesc->physpc, ppc->codexor); @@ -4240,7 +4231,7 @@ static void log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, i drcuml_log_printf(drcuml, "\nDescriptor list @ %08X\n", desclist->pc); /* output each descriptor */ - for ( ; desclist != NULL; desclist = desclist->next) + for ( ; desclist != NULL; desclist = desclist->next()) { char buffer[100]; @@ -4263,8 +4254,8 @@ static void log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, i drcuml_log_printf(drcuml, "\n"); /* if we have a delay slot, output it recursively */ - if (desclist->delay != NULL) - log_opcode_desc(drcuml, desclist->delay, indent + 1); + if (desclist->delay.first() != NULL) + log_opcode_desc(drcuml, desclist->delay.first(), indent + 1); /* at the end of a sequence add a dividing line */ if (desclist->flags & OPFLAG_END_SEQUENCE) diff --git a/src/emu/cpu/powerpc/ppcfe.c b/src/emu/cpu/powerpc/ppcfe.c index dcd0336ccf5..b27cc783331 100644 --- a/src/emu/cpu/powerpc/ppcfe.c +++ b/src/emu/cpu/powerpc/ppcfe.c @@ -4,9 +4,36 @@ Front-end for PowerPC recompiler +**************************************************************************** + Copyright Aaron Giles - Released for general non-commercial use under the MAME license - Visit http://mamedev.org for licensing and usage restrictions. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name 'MAME' nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. ***************************************************************************/ @@ -15,204 +42,147 @@ #include "ppccom.h" -/*************************************************************************** - MACROS -***************************************************************************/ - -#define GPR_USED(desc, x) do { (desc)->regin[0] |= REGFLAG_R(x); } while (0) -#define GPR_USED_OR_ZERO(desc, x) do { (desc)->regin[0] |= ((x) == 0 ? 0 : REGFLAG_R(x)); } while (0) -#define GPR_MODIFIED(desc, x) do { (desc)->regout[0] |= REGFLAG_R(x); } while (0) - -#define FPR_USED(desc, x) do { (desc)->regin[1] |= REGFLAG_FR(x); } while (0) -#define FPR_MODIFIED(desc, x) do { (desc)->regout[1] |= REGFLAG_FR(x); } while (0) - -#define CR_USED(desc, x) do { (desc)->regin[2] |= REGFLAG_CR(x); } while (0) -#define CR_BIT_USED(desc, x) do { (desc)->regin[2] |= REGFLAG_CR_BIT(x); } while (0) -#define CR_MODIFIED(desc, x) do { (desc)->regout[2] |= REGFLAG_CR(x); } while (0) -#define CR_BIT_MODIFIED(desc, x) do { (desc)->regout[2] |= REGFLAG_CR_BIT(x); } while (0) +//************************************************************************** +// MACROS +//************************************************************************** -#define XER_CA_USED(desc) do { (desc)->regin[3] |= REGFLAG_XER_CA; } while (0) -#define XER_OV_USED(desc) do { (desc)->regin[3] |= REGFLAG_XER_OV; } while (0) -#define XER_SO_USED(desc) do { (desc)->regin[3] |= REGFLAG_XER_SO; } while (0) -#define XER_COUNT_USED(desc) do { (desc)->regin[3] |= REGFLAG_XER_COUNT; } while (0) -#define XER_CA_MODIFIED(desc) do { (desc)->regout[3] |= REGFLAG_XER_CA; } while (0) -#define XER_OV_MODIFIED(desc) do { (desc)->regout[3] |= REGFLAG_XER_OV; } while (0) -#define XER_SO_MODIFIED(desc) do { (desc)->regout[3] |= REGFLAG_XER_SO; } while (0) -#define XER_COUNT_MODIFIED(desc) do { (desc)->regout[3] |= REGFLAG_XER_COUNT; } while (0) +#define GPR_USED(desc, x) do { (desc).regin[0] |= REGFLAG_R(x); } while (0) +#define GPR_USED_OR_ZERO(desc, x) do { (desc).regin[0] |= ((x) == 0 ? 0 : REGFLAG_R(x)); } while (0) +#define GPR_MODIFIED(desc, x) do { (desc).regout[0] |= REGFLAG_R(x); } while (0) -#define CTR_USED(desc) do { (desc)->regin[3] |= REGFLAG_CTR; } while (0) -#define CTR_MODIFIED(desc) do { (desc)->regout[3] |= REGFLAG_CTR; } while (0) -#define LR_USED(desc) do { (desc)->regin[3] |= REGFLAG_LR; } while (0) -#define LR_MODIFIED(desc) do { (desc)->regout[3] |= REGFLAG_LR; } while (0) - -#define FPSCR_USED(desc, x) do { (desc)->regin[3] |= REGFLAG_FPSCR(x); } while (0) -#define FPSCR_MODIFIED(desc, x) do { (desc)->regout[3] |= REGFLAG_FPSCR(x); } while (0) - - - -/*************************************************************************** - FUNCTION PROTOTYPES -***************************************************************************/ +#define FPR_USED(desc, x) do { (desc).regin[1] |= REGFLAG_FR(x); } while (0) +#define FPR_MODIFIED(desc, x) do { (desc).regout[1] |= REGFLAG_FR(x); } while (0) -static int describe_instruction_13(powerpc_state *ppc, UINT32 op, opcode_desc *desc, const opcode_desc *prev); -static int describe_instruction_1f(powerpc_state *ppc, UINT32 op, opcode_desc *desc, const opcode_desc *prev); -static int describe_instruction_3b(powerpc_state *ppc, UINT32 op, opcode_desc *desc, const opcode_desc *prev); -static int describe_instruction_3f(powerpc_state *ppc, UINT32 op, opcode_desc *desc, const opcode_desc *prev); +#define CR_USED(desc, x) do { (desc).regin[2] |= REGFLAG_CR(x); } while (0) +#define CR_BIT_USED(desc, x) do { (desc).regin[2] |= REGFLAG_CR_BIT(x); } while (0) +#define CR_MODIFIED(desc, x) do { (desc).regout[2] |= REGFLAG_CR(x); } while (0) +#define CR_BIT_MODIFIED(desc, x) do { (desc).regout[2] |= REGFLAG_CR_BIT(x); } while (0) +#define XER_CA_USED(desc) do { (desc).regin[3] |= REGFLAG_XER_CA; } while (0) +#define XER_OV_USED(desc) do { (desc).regin[3] |= REGFLAG_XER_OV; } while (0) +#define XER_SO_USED(desc) do { (desc).regin[3] |= REGFLAG_XER_SO; } while (0) +#define XER_COUNT_USED(desc) do { (desc).regin[3] |= REGFLAG_XER_COUNT; } while (0) +#define XER_CA_MODIFIED(desc) do { (desc).regout[3] |= REGFLAG_XER_CA; } while (0) +#define XER_OV_MODIFIED(desc) do { (desc).regout[3] |= REGFLAG_XER_OV; } while (0) +#define XER_SO_MODIFIED(desc) do { (desc).regout[3] |= REGFLAG_XER_SO; } while (0) +#define XER_COUNT_MODIFIED(desc) do { (desc).regout[3] |= REGFLAG_XER_COUNT; } while (0) +#define CTR_USED(desc) do { (desc).regin[3] |= REGFLAG_CTR; } while (0) +#define CTR_MODIFIED(desc) do { (desc).regout[3] |= REGFLAG_CTR; } while (0) +#define LR_USED(desc) do { (desc).regin[3] |= REGFLAG_LR; } while (0) +#define LR_MODIFIED(desc) do { (desc).regout[3] |= REGFLAG_LR; } while (0) -/*************************************************************************** - INLINE FUNCTIONS -***************************************************************************/ +#define FPSCR_USED(desc, x) do { (desc).regin[3] |= REGFLAG_FPSCR(x); } while (0) +#define FPSCR_MODIFIED(desc, x) do { (desc).regout[3] |= REGFLAG_FPSCR(x); } while (0) -/*------------------------------------------------- - compute_spr - compute the SPR index from the - SPR field of an opcode --------------------------------------------------*/ -INLINE UINT32 compute_spr(UINT32 spr) -{ - return ((spr >> 5) | (spr << 5)) & 0x3ff; -} +//************************************************************************** +// PPC FRONTEND +//************************************************************************** -/*------------------------------------------------- - is_403_class - are we one of the 403 variants? --------------------------------------------------*/ +//------------------------------------------------- +// ppc_frontend - constructor +//------------------------------------------------- -INLINE int is_403_class(const powerpc_state *ppc) +ppc_frontend::ppc_frontend(powerpc_state &state, UINT32 window_start, UINT32 window_end, UINT32 max_sequence) + : drc_frontend(*state.device, window_start, window_end, max_sequence), + m_context(state) { - return (ppc->flavor == PPC_MODEL_403GA || ppc->flavor == PPC_MODEL_403GB || ppc->flavor == PPC_MODEL_403GC || ppc->flavor == PPC_MODEL_403GCX || ppc->flavor == PPC_MODEL_405GP); } -/*------------------------------------------------- - is_601_class - are we one of the 601 variants? --------------------------------------------------*/ - -INLINE int is_601_class(const powerpc_state *ppc) -{ - return (ppc->flavor == PPC_MODEL_601); -} - - -/*------------------------------------------------- - is_602_class - are we one of the 602 variants? --------------------------------------------------*/ - -INLINE int is_602_class(const powerpc_state *ppc) -{ - return (ppc->flavor == PPC_MODEL_602); -} - - -/*------------------------------------------------- - is_603_class - are we one of the 603 variants? --------------------------------------------------*/ - -INLINE int is_603_class(const powerpc_state *ppc) -{ - return (ppc->flavor == PPC_MODEL_603 || ppc->flavor == PPC_MODEL_603E || ppc->flavor == PPC_MODEL_603EV || ppc->flavor == PPC_MODEL_603R); -} - - - -/*************************************************************************** - INSTRUCTION PARSERS -***************************************************************************/ - -/*------------------------------------------------- - ppcfe_describe - build a description - of a single instruction --------------------------------------------------*/ +//------------------------------------------------- +// describe - build a description of a single +// instruction +//------------------------------------------------- -int ppcfe_describe(void *param, opcode_desc *desc, const opcode_desc *prev) +bool ppc_frontend::describe(opcode_desc &desc, const opcode_desc *prev) { - powerpc_state *ppc = (powerpc_state *)param; UINT32 op, opswitch; int regnum; - /* compute the physical PC */ - if (!ppccom_translate_address(ppc, ADDRESS_SPACE_PROGRAM, TRANSLATE_FETCH, &desc->physpc)) + // compute the physical PC + if (!ppccom_translate_address(&m_context, ADDRESS_SPACE_PROGRAM, TRANSLATE_FETCH, &desc.physpc)) { - /* uh-oh: a page fault; leave the description empty and just if this is the first instruction, leave it empty and */ - /* mark as needing to validate; otherwise, just end the sequence here */ - desc->flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_COMPILER_PAGE_FAULT | OPFLAG_VIRTUAL_NOOP | OPFLAG_END_SEQUENCE; - return TRUE; + // uh-oh: a page fault; leave the description empty and just if this is the first instruction, leave it empty and + // mark as needing to validate; otherwise, just end the sequence here + desc.flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_COMPILER_PAGE_FAULT | OPFLAG_VIRTUAL_NOOP | OPFLAG_END_SEQUENCE; + return true; } - /* fetch the opcode */ - op = desc->opptr.l[0] = ppc->direct->read_decrypted_dword(desc->physpc, ppc->codexor); + // fetch the opcode + op = desc.opptr.l[0] = m_context.direct->read_decrypted_dword(desc.physpc, m_context.codexor); - /* all instructions are 4 bytes and default to a single cycle each */ - desc->length = 4; - desc->cycles = 1; + // all instructions are 4 bytes and default to a single cycle each + desc.length = 4; + desc.cycles = 1; - /* parse the instruction */ + // parse the instruction opswitch = op >> 26; switch (opswitch) { - case 0x02: /* TDI - 64-bit only */ - case 0x1e: /* 0x1e group - 64-bit only */ - case 0x3a: /* 0x3a group - 64-bit only */ - case 0x3e: /* 0x3e group - 64-bit only */ - return FALSE; + case 0x02: // TDI - 64-bit only + case 0x1e: // 0x1e group - 64-bit only + case 0x3a: // 0x3a group - 64-bit only + case 0x3e: // 0x3e group - 64-bit only + return false; - case 0x03: /* TWI */ + case 0x03: // TWI GPR_USED(desc, G_RA(op)); - desc->flags |= OPFLAG_CAN_CAUSE_EXCEPTION; - if (is_603_class(ppc)) - desc->cycles = 2; /* 603 */ - return TRUE; + desc.flags |= OPFLAG_CAN_CAUSE_EXCEPTION; + if (is_603_class()) + desc.cycles = 2; // 603 + return true; - case 0x07: /* MULLI */ + case 0x07: // MULLI GPR_USED(desc, G_RA(op)); GPR_MODIFIED(desc, G_RD(op)); - if (is_403_class(ppc)) - desc->cycles = 4; /* 4XX */ - else if (is_601_class(ppc)) - desc->cycles = 5; /* 601 */ - else if (is_603_class(ppc)) - desc->cycles = 2; /* 603: 2-3 */ + if (is_403_class()) + desc.cycles = 4; // 4XX + else if (is_601_class()) + desc.cycles = 5; // 601 + else if (is_603_class()) + desc.cycles = 2; // 603: 2-3 else - desc->cycles = 2; /* ??? */ - return TRUE; + desc.cycles = 2; // ??? + return true; - case 0x0e: /* ADDI */ - case 0x0f: /* ADDIS */ + case 0x0e: // ADDI + case 0x0f: // ADDIS GPR_USED_OR_ZERO(desc, G_RA(op)); GPR_MODIFIED(desc, G_RD(op)); - return TRUE; + return true; - case 0x0a: /* CMPLI */ - case 0x0b: /* CMPI */ + case 0x0a: // CMPLI + case 0x0b: // CMPI GPR_USED(desc, G_RA(op)); XER_SO_USED(desc); CR_MODIFIED(desc, G_CRFD(op)); - return TRUE; + return true; - case 0x08: /* SUBFIC */ - case 0x0c: /* ADDIC */ + case 0x08: // SUBFIC + case 0x0c: // ADDIC GPR_USED(desc, G_RA(op)); GPR_MODIFIED(desc, G_RD(op)); XER_CA_MODIFIED(desc); - return TRUE; + return true; - case 0x0d: /* ADDIC. */ + case 0x0d: // ADDIC. GPR_USED(desc, G_RA(op)); XER_SO_USED(desc); GPR_MODIFIED(desc, G_RT(op)); XER_CA_MODIFIED(desc); CR_MODIFIED(desc, 0); - return TRUE; + return true; - case 0x10: /* BCx */ + case 0x10: // BCx if (!(G_BO(op) & 0x10)) { CR_BIT_USED(desc, G_BI(op)); - /* branch folding */ + // branch folding if (prev == NULL || prev->regout[2] == 0) - desc->cycles = 0; + desc.cycles = 0; } if (!(G_BO(op) & 0x04)) { @@ -222,40 +192,40 @@ int ppcfe_describe(void *param, opcode_desc *desc, const opcode_desc *prev) if (op & M_LK) LR_MODIFIED(desc); if ((G_BO(op) & 0x14) == 0x14) - desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; else - desc->flags |= OPFLAG_IS_CONDITIONAL_BRANCH; - desc->targetpc = (INT16)(G_BD(op) << 2) + ((op & M_AA) ? 0 : desc->pc); - if (desc->targetpc == desc->pc && desc->cycles == 0) - desc->cycles = 1; - return TRUE; - - case 0x11: /* SC */ - if (!(ppc->cap & (PPCCAP_OEA | PPCCAP_4XX))) - return FALSE; - desc->flags |= OPFLAG_WILL_CAUSE_EXCEPTION; - if (is_601_class(ppc)) - desc->cycles = 16; /* 601 */ - else if (is_603_class(ppc)) - desc->cycles = 3; /* 603 */ + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + desc.targetpc = (INT16)(G_BD(op) << 2) + ((op & M_AA) ? 0 : desc.pc); + if (desc.targetpc == desc.pc && desc.cycles == 0) + desc.cycles = 1; + return true; + + case 0x11: // SC + if (!(m_context.cap & (PPCCAP_OEA | PPCCAP_4XX))) + return false; + desc.flags |= OPFLAG_WILL_CAUSE_EXCEPTION; + if (is_601_class()) + desc.cycles = 16; // 601 + else if (is_603_class()) + desc.cycles = 3; // 603 else - desc->cycles = 3; /* ??? */ - return TRUE; + desc.cycles = 3; // ??? + return true; - case 0x12: /* Bx */ + case 0x12: // Bx if (op & M_LK) LR_MODIFIED(desc); - desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; - desc->targetpc = ((INT32)(G_LI(op) << 8) >> 6) + ((op & M_AA) ? 0 : desc->pc); - /* branch folding */ - if (desc->targetpc != desc->pc) - desc->cycles = 0; - return TRUE; + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = ((INT32)(G_LI(op) << 8) >> 6) + ((op & M_AA) ? 0 : desc.pc); + // branch folding + if (desc.targetpc != desc.pc) + desc.cycles = 0; + return true; - case 0x13: /* 0x13 group */ - return describe_instruction_13(ppc, op, desc, prev); + case 0x13: // 0x13 group + return describe_13(op, desc, prev); - case 0x14: /* RLWIMIx */ + case 0x14: // RLWIMIx GPR_USED(desc, G_RS(op)); GPR_USED(desc, G_RA(op)); GPR_MODIFIED(desc, G_RA(op)); @@ -264,9 +234,9 @@ int ppcfe_describe(void *param, opcode_desc *desc, const opcode_desc *prev) XER_SO_USED(desc); CR_MODIFIED(desc, 0); } - return TRUE; + return true; - case 0x15: /* RLWINMx */ + case 0x15: // RLWINMx GPR_USED(desc, G_RS(op)); GPR_MODIFIED(desc, G_RA(op)); if (op & M_RC) @@ -274,9 +244,9 @@ int ppcfe_describe(void *param, opcode_desc *desc, const opcode_desc *prev) XER_SO_USED(desc); CR_MODIFIED(desc, 0); } - return TRUE; + return true; - case 0x17: /* RLWNMx */ + case 0x17: // RLWNMx GPR_USED(desc, G_RS(op)); GPR_USED(desc, G_RB(op)); GPR_MODIFIED(desc, G_RA(op)); @@ -285,133 +255,133 @@ int ppcfe_describe(void *param, opcode_desc *desc, const opcode_desc *prev) XER_SO_USED(desc); CR_MODIFIED(desc, 0); } - return TRUE; + return true; - case 0x18: /* ORI */ - case 0x19: /* ORIS */ - case 0x1a: /* XORI */ - case 0x1b: /* XORIS */ + case 0x18: // ORI + case 0x19: // ORIS + case 0x1a: // XORI + case 0x1b: // XORIS GPR_USED(desc, G_RS(op)); GPR_MODIFIED(desc, G_RA(op)); - return TRUE; + return true; - case 0x1c: /* ANDI. */ - case 0x1d: /* ANDIS. */ + case 0x1c: // ANDI. + case 0x1d: // ANDIS. GPR_USED(desc, G_RS(op)); XER_SO_USED(desc); GPR_MODIFIED(desc, G_RA(op)); CR_MODIFIED(desc, 0); - return TRUE; + return true; - case 0x1f: /* 0x1f group */ - return describe_instruction_1f(ppc, op, desc, prev); + case 0x1f: // 0x1f group + return describe_1f(op, desc, prev); - case 0x20: /* LWZ */ - case 0x22: /* LBZ */ - case 0x28: /* LHZ */ - case 0x2a: /* LHA */ + case 0x20: // LWZ + case 0x22: // LBZ + case 0x28: // LHZ + case 0x2a: // LHA GPR_USED_OR_ZERO(desc, G_RA(op)); GPR_MODIFIED(desc, G_RD(op)); - desc->flags |= OPFLAG_READS_MEMORY; - return TRUE; + desc.flags |= OPFLAG_READS_MEMORY; + return true; - case 0x21: /* LWZU */ - case 0x23: /* LBZU */ - case 0x29: /* LHZU */ - case 0x2b: /* LHAU */ + case 0x21: // LWZU + case 0x23: // LBZU + case 0x29: // LHZU + case 0x2b: // LHAU if (G_RA(op) == 0 || G_RA(op) == G_RD(op)) - return FALSE; + return false; GPR_USED(desc, G_RA(op)); GPR_MODIFIED(desc, G_RD(op)); GPR_MODIFIED(desc, G_RA(op)); - desc->flags |= OPFLAG_READS_MEMORY; - return TRUE; + desc.flags |= OPFLAG_READS_MEMORY; + return true; - case 0x24: /* STW */ - case 0x26: /* STB */ - case 0x2c: /* STH */ + case 0x24: // STW + case 0x26: // STB + case 0x2c: // STH GPR_USED_OR_ZERO(desc, G_RA(op)); GPR_USED(desc, G_RS(op)); - desc->flags |= OPFLAG_WRITES_MEMORY; - return TRUE; + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; - case 0x25: /* STWU */ - case 0x27: /* STBU */ - case 0x2d: /* STHU */ + case 0x25: // STWU + case 0x27: // STBU + case 0x2d: // STHU if (G_RA(op) == 0) - return FALSE; + return false; GPR_USED(desc, G_RA(op)); GPR_USED(desc, G_RS(op)); GPR_MODIFIED(desc, G_RA(op)); - desc->flags |= OPFLAG_WRITES_MEMORY; - return TRUE; + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; - case 0x2e: /* LMW */ + case 0x2e: // LMW GPR_USED_OR_ZERO(desc, G_RA(op)); for (regnum = G_RD(op); regnum < 32; regnum++) GPR_MODIFIED(desc, regnum); - desc->flags |= OPFLAG_READS_MEMORY; - desc->cycles = 32 - G_RD(op); - return TRUE; + desc.flags |= OPFLAG_READS_MEMORY; + desc.cycles = 32 - G_RD(op); + return true; - case 0x2f: /* STMW */ + case 0x2f: // STMW GPR_USED_OR_ZERO(desc, G_RA(op)); for (regnum = G_RS(op); regnum < 32; regnum++) GPR_USED(desc, regnum); - desc->flags |= OPFLAG_WRITES_MEMORY; - desc->cycles = 32 - G_RS(op); - return TRUE; - - case 0x30: /* LFS */ - case 0x32: /* LFD */ - if (!(ppc->cap & PPCCAP_FPU)) - return FALSE; + desc.flags |= OPFLAG_WRITES_MEMORY; + desc.cycles = 32 - G_RS(op); + return true; + + case 0x30: // LFS + case 0x32: // LFD + if (!(m_context.cap & PPCCAP_FPU)) + return false; GPR_USED_OR_ZERO(desc, G_RA(op)); FPR_MODIFIED(desc, G_RD(op)); - desc->flags |= OPFLAG_READS_MEMORY; - return TRUE; + desc.flags |= OPFLAG_READS_MEMORY; + return true; - case 0x31: /* LFSU */ - case 0x33: /* LFDU */ - if (!(ppc->cap & PPCCAP_FPU)) - return FALSE; + case 0x31: // LFSU + case 0x33: // LFDU + if (!(m_context.cap & PPCCAP_FPU)) + return false; if (G_RA(op) == 0) - return FALSE; + return false; GPR_USED(desc, G_RA(op)); GPR_MODIFIED(desc, G_RA(op)); FPR_MODIFIED(desc, G_RD(op)); - desc->flags |= OPFLAG_READS_MEMORY; - return TRUE; + desc.flags |= OPFLAG_READS_MEMORY; + return true; - case 0x34: /* STFS */ - case 0x36: /* STFD */ - if (!(ppc->cap & PPCCAP_FPU)) - return FALSE; + case 0x34: // STFS + case 0x36: // STFD + if (!(m_context.cap & PPCCAP_FPU)) + return false; GPR_USED_OR_ZERO(desc, G_RA(op)); FPR_USED(desc, G_RS(op)); - desc->flags |= OPFLAG_WRITES_MEMORY; - return TRUE; + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; - case 0x35: /* STFSU */ - case 0x37: /* STFDU */ - if (!(ppc->cap & PPCCAP_FPU)) - return FALSE; + case 0x35: // STFSU + case 0x37: // STFDU + if (!(m_context.cap & PPCCAP_FPU)) + return false; if (G_RA(op) == 0) - return FALSE; + return false; GPR_USED(desc, G_RA(op)); GPR_MODIFIED(desc, G_RA(op)); FPR_USED(desc, G_RS(op)); - desc->flags |= OPFLAG_WRITES_MEMORY; - return TRUE; + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; - case 0x3b: /* 0x3b group */ - return describe_instruction_3b(ppc, op, desc, prev); + case 0x3b: // 0x3b group + return describe_3b(op, desc, prev); - case 0x3f: /* 0x3f group */ - return describe_instruction_3f(ppc, op, desc, prev); + case 0x3f: // 0x3f group + return describe_3f(op, desc, prev); } - return FALSE; + return false; } @@ -421,21 +391,21 @@ int ppcfe_describe(void *param, opcode_desc *desc, const opcode_desc *prev) 0x13 group -------------------------------------------------*/ -static int describe_instruction_13(powerpc_state *ppc, UINT32 op, opcode_desc *desc, const opcode_desc *prev) +bool ppc_frontend::describe_13(UINT32 op, opcode_desc &desc, const opcode_desc *prev) { UINT32 opswitch = (op >> 1) & 0x3ff; switch (opswitch) { - case 0x000: /* MTCRF */ + case 0x000: // MTCRF CR_USED(desc, G_CRFS(op)); CR_MODIFIED(desc, G_CRFD(op)); - /* CR logical folding */ + // CR logical folding if (prev == NULL || prev->regout[2] == 0) - desc->cycles = 0; - return TRUE; + desc.cycles = 0; + return true; - case 0x010: /* BCLRx */ + case 0x010: // BCLRx LR_USED(desc); if (!(G_BO(op) & 0x10)) CR_BIT_USED(desc, G_BI(op)); @@ -447,72 +417,72 @@ static int describe_instruction_13(powerpc_state *ppc, UINT32 op, opcode_desc *d if (op & M_LK) LR_MODIFIED(desc); if ((G_BO(op) & 0x14) == 0x14) - desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; else - desc->flags |= OPFLAG_IS_CONDITIONAL_BRANCH; - desc->targetpc = BRANCH_TARGET_DYNAMIC; - return TRUE; - - case 0x021: /* CRNOR */ - case 0x081: /* CRANDC */ - case 0x0c1: /* CRXOR */ - case 0x0e1: /* CRNAND */ - case 0x101: /* CRAND */ - case 0x121: /* CREQV */ - case 0x1a1: /* CRORC */ - case 0x1c1: /* CROR */ + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + return true; + + case 0x021: // CRNOR + case 0x081: // CRANDC + case 0x0c1: // CRXOR + case 0x0e1: // CRNAND + case 0x101: // CRAND + case 0x121: // CREQV + case 0x1a1: // CRORC + case 0x1c1: // CROR CR_BIT_USED(desc, G_CRBA(op)); CR_BIT_USED(desc, G_CRBB(op)); CR_BIT_MODIFIED(desc, G_CRBD(op)); - /* CR logical folding */ + // CR logical folding if (prev == NULL || prev->regout[2] == 0) - desc->cycles = 0; - return TRUE; - - case 0x032: /* RFI */ - if (!(ppc->cap & (PPCCAP_OEA | PPCCAP_4XX))) - return FALSE; - desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CHANGE_MODES | OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE | OPFLAG_CAN_CAUSE_EXCEPTION; - desc->targetpc = BRANCH_TARGET_DYNAMIC; - if (is_601_class(ppc)) - desc->cycles = 13; /* 601 */ - else if (is_603_class(ppc)) - desc->cycles = 3; /* 603 */ + desc.cycles = 0; + return true; + + case 0x032: // RFI + if (!(m_context.cap & (PPCCAP_OEA | PPCCAP_4XX))) + return false; + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CHANGE_MODES | OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE | OPFLAG_CAN_CAUSE_EXCEPTION; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + if (is_601_class()) + desc.cycles = 13; // 601 + else if (is_603_class()) + desc.cycles = 3; // 603 else - desc->cycles = 3; /* ??? */ - return TRUE; - - case 0x033: /* RFCI */ - if (!(ppc->cap & PPCCAP_4XX)) - return FALSE; - desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CHANGE_MODES | OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE | OPFLAG_CAN_CAUSE_EXCEPTION; - desc->targetpc = BRANCH_TARGET_DYNAMIC; - return TRUE; - - case 0x096: /* ISYNC */ - if (!(ppc->cap & (PPCCAP_VEA | PPCCAP_4XX))) - return FALSE; - if (is_601_class(ppc)) - desc->cycles = 6; /* 601 */ - return TRUE; - - case 0x210: /* BCCTRx */ + desc.cycles = 3; // ??? + return true; + + case 0x033: // RFCI + if (!(m_context.cap & PPCCAP_4XX)) + return false; + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CHANGE_MODES | OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE | OPFLAG_CAN_CAUSE_EXCEPTION; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + return true; + + case 0x096: // ISYNC + if (!(m_context.cap & (PPCCAP_VEA | PPCCAP_4XX))) + return false; + if (is_601_class()) + desc.cycles = 6; // 601 + return true; + + case 0x210: // BCCTRx CTR_USED(desc); if (!(G_BO(op) & 0x10)) CR_BIT_USED(desc, G_BI(op)); if (!(G_BO(op) & 0x04)) - return FALSE; + return false; if (op & M_LK) LR_MODIFIED(desc); if ((G_BO(op) & 0x14) == 0x14) - desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; else - desc->flags |= OPFLAG_IS_CONDITIONAL_BRANCH; - desc->targetpc = BRANCH_TARGET_DYNAMIC; - return TRUE; + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + return true; } - return FALSE; + return false; } @@ -522,59 +492,59 @@ static int describe_instruction_13(powerpc_state *ppc, UINT32 op, opcode_desc *d 0x1f group -------------------------------------------------*/ -static int describe_instruction_1f(powerpc_state *ppc, UINT32 op, opcode_desc *desc, const opcode_desc *prev) +bool ppc_frontend::describe_1f(UINT32 op, opcode_desc &desc, const opcode_desc *prev) { UINT32 opswitch = (op >> 1) & 0x3ff; int spr, regnum; switch (opswitch) { - case 0x009: /* MULHDUx - 64-bit only */ - case 0x015: /* LDX - 64-bit only */ - case 0x01b: /* SLDx - 64-bit only */ - case 0x035: /* LDUX - 64-bit only */ - case 0x03a: /* CNTLZDx - 64-bit only */ - case 0x044: /* TD - 64-bit only */ - case 0x049: /* MULHDx - 64-bit only */ - case 0x054: /* LDARX - 64-bit only */ - case 0x095: /* STDX - 64-bit only */ - case 0x0b5: /* STDUX - 64-bit only */ - case 0x0d6: /* STDCX. - 64-bit only */ - case 0x0e9: /* MULLD - 64-bit only */ - case 0x2e9: /* MULLDO - 64-bit only */ - case 0x155: /* LWAX - 64-bit only */ - case 0x175: /* LWAUX - 64-bit only */ - case 0x33a: /* SRADIx - 64-bit only */ - case 0x33b: /* SRADIx - 64-bit only */ - case 0x1b2: /* SLBIE - 64-bit only */ - case 0x1c9: /* DIVDUx - 64-bit only */ - case 0x3c9: /* DIVDUOx - 64-bit only */ - case 0x1e9: /* DIVDx - 64-bit only */ - case 0x3e9: /* DIVDOx - 64-bit only */ - case 0x1f2: /* SLBIA - 64-bit only */ - case 0x21b: /* SRDx - 64-bit only */ - case 0x31a: /* SRADx - 64-bit only */ - case 0x3da: /* EXTSW - 64-bit only */ - return FALSE; - - case 0x000: /* CMP */ - case 0x020: /* CMPL */ + case 0x009: // MULHDUx - 64-bit only + case 0x015: // LDX - 64-bit only + case 0x01b: // SLDx - 64-bit only + case 0x035: // LDUX - 64-bit only + case 0x03a: // CNTLZDx - 64-bit only + case 0x044: // TD - 64-bit only + case 0x049: // MULHDx - 64-bit only + case 0x054: // LDARX - 64-bit only + case 0x095: // STDX - 64-bit only + case 0x0b5: // STDUX - 64-bit only + case 0x0d6: // STDCX. - 64-bit only + case 0x0e9: // MULLD - 64-bit only + case 0x2e9: // MULLDO - 64-bit only + case 0x155: // LWAX - 64-bit only + case 0x175: // LWAUX - 64-bit only + case 0x33a: // SRADIx - 64-bit only + case 0x33b: // SRADIx - 64-bit only + case 0x1b2: // SLBIE - 64-bit only + case 0x1c9: // DIVDUx - 64-bit only + case 0x3c9: // DIVDUOx - 64-bit only + case 0x1e9: // DIVDx - 64-bit only + case 0x3e9: // DIVDOx - 64-bit only + case 0x1f2: // SLBIA - 64-bit only + case 0x21b: // SRDx - 64-bit only + case 0x31a: // SRADx - 64-bit only + case 0x3da: // EXTSW - 64-bit only + return false; + + case 0x000: // CMP + case 0x020: // CMPL GPR_USED(desc, G_RA(op)); GPR_USED(desc, G_RB(op)); XER_SO_USED(desc); CR_MODIFIED(desc, G_CRFD(op)); - return TRUE; + return true; - case 0x004: /* TW */ + case 0x004: // TW GPR_USED(desc, G_RA(op)); GPR_USED(desc, G_RB(op)); - desc->flags |= OPFLAG_CAN_CAUSE_EXCEPTION; - if (is_603_class(ppc)) - desc->cycles = 2; /* 603 */ - return TRUE; + desc.flags |= OPFLAG_CAN_CAUSE_EXCEPTION; + if (is_603_class()) + desc.cycles = 2; // 603 + return true; - case 0x008: /* SUBFCx */ - case 0x00a: /* ADDCx */ + case 0x008: // SUBFCx + case 0x00a: // ADDCx GPR_USED(desc, G_RA(op)); GPR_USED(desc, G_RB(op)); GPR_MODIFIED(desc, G_RD(op)); @@ -584,10 +554,10 @@ static int describe_instruction_1f(powerpc_state *ppc, UINT32 op, opcode_desc *d XER_SO_USED(desc); CR_MODIFIED(desc, 0); } - return TRUE; + return true; - case 0x088: /* SUBFEx */ - case 0x08a: /* ADDEx */ + case 0x088: // SUBFEx + case 0x08a: // ADDEx GPR_USED(desc, G_RA(op)); GPR_USED(desc, G_RB(op)); XER_CA_USED(desc); @@ -598,12 +568,12 @@ static int describe_instruction_1f(powerpc_state *ppc, UINT32 op, opcode_desc *d XER_SO_USED(desc); CR_MODIFIED(desc, 0); } - return TRUE; + return true; - case 0x0c8: /* SUBFZEx */ - case 0x0ca: /* ADDZEx */ - case 0x0e8: /* SUBFMEx */ - case 0x0ea: /* ADDMEx */ + case 0x0c8: // SUBFZEx + case 0x0ca: // ADDZEx + case 0x0e8: // SUBFMEx + case 0x0ea: // ADDMEx GPR_USED(desc, G_RA(op)); XER_CA_USED(desc); GPR_MODIFIED(desc, G_RD(op)); @@ -613,11 +583,11 @@ static int describe_instruction_1f(powerpc_state *ppc, UINT32 op, opcode_desc *d XER_SO_USED(desc); CR_MODIFIED(desc, 0); } - return TRUE; + return true; - case 0x00b: /* MULHWUx */ - case 0x04b: /* MULHWx */ - case 0x0eb: /* MULLWx */ + case 0x00b: // MULHWUx + case 0x04b: // MULHWx + case 0x0eb: // MULLWx GPR_USED(desc, G_RA(op)); GPR_USED(desc, G_RB(op)); GPR_MODIFIED(desc, G_RD(op)); @@ -626,18 +596,18 @@ static int describe_instruction_1f(powerpc_state *ppc, UINT32 op, opcode_desc *d XER_SO_USED(desc); CR_MODIFIED(desc, 0); } - if (is_403_class(ppc)) - desc->cycles = 4; /* 4XX */ - else if (is_601_class(ppc)) - desc->cycles = 5; /* 601: 5/9/10 */ - else if (is_603_class(ppc)) - desc->cycles = 2; /* 603: 2,3,4,5,6 */ + if (is_403_class()) + desc.cycles = 4; // 4XX + else if (is_601_class()) + desc.cycles = 5; // 601: 5/9/10 + else if (is_603_class()) + desc.cycles = 2; // 603: 2,3,4,5,6 else - desc->cycles = 2; /* ??? */ - return TRUE; + desc.cycles = 2; // ??? + return true; - case 0x1cb: /* DIVWUx */ - case 0x1eb: /* DIVWx */ + case 0x1cb: // DIVWUx + case 0x1eb: // DIVWx GPR_USED(desc, G_RA(op)); GPR_USED(desc, G_RB(op)); GPR_MODIFIED(desc, G_RD(op)); @@ -646,18 +616,18 @@ static int describe_instruction_1f(powerpc_state *ppc, UINT32 op, opcode_desc *d XER_SO_USED(desc); CR_MODIFIED(desc, 0); } - if (is_403_class(ppc)) - desc->cycles = 33; /* 4XX */ - else if (is_601_class(ppc)) - desc->cycles = 36; /* 601 */ - else if (is_603_class(ppc)) - desc->cycles = 37; /* 603 */ + if (is_403_class()) + desc.cycles = 33; // 4XX + else if (is_601_class()) + desc.cycles = 36; // 601 + else if (is_603_class()) + desc.cycles = 37; // 603 else - desc->cycles = 33; /* ??? */ - return TRUE; + desc.cycles = 33; // ??? + return true; - case 0x028: /* SUBFx */ - case 0x10a: /* ADDx */ + case 0x028: // SUBFx + case 0x10a: // ADDx GPR_USED(desc, G_RA(op)); GPR_USED(desc, G_RB(op)); GPR_MODIFIED(desc, G_RD(op)); @@ -666,10 +636,10 @@ static int describe_instruction_1f(powerpc_state *ppc, UINT32 op, opcode_desc *d XER_SO_USED(desc); CR_MODIFIED(desc, 0); } - return TRUE; + return true; - case 0x208: /* SUBFCOx */ - case 0x20a: /* ADDCOx */ + case 0x208: // SUBFCOx + case 0x20a: // ADDCOx GPR_USED(desc, G_RA(op)); GPR_USED(desc, G_RB(op)); GPR_MODIFIED(desc, G_RD(op)); @@ -678,10 +648,10 @@ static int describe_instruction_1f(powerpc_state *ppc, UINT32 op, opcode_desc *d XER_CA_MODIFIED(desc); if (op & M_RC) CR_MODIFIED(desc, 0); - return TRUE; + return true; - case 0x288: /* SUBFEOx */ - case 0x28a: /* ADDEOx */ + case 0x288: // SUBFEOx + case 0x28a: // ADDEOx GPR_USED(desc, G_RA(op)); GPR_USED(desc, G_RB(op)); XER_CA_USED(desc); @@ -691,12 +661,12 @@ static int describe_instruction_1f(powerpc_state *ppc, UINT32 op, opcode_desc *d XER_CA_MODIFIED(desc); if (op & M_RC) CR_MODIFIED(desc, 0); - return TRUE; + return true; - case 0x2c8: /* SUBFZEOx */ - case 0x2ca: /* ADDZEOx */ - case 0x2e8: /* SUBFMEOx */ - case 0x2ea: /* ADDMEOx */ + case 0x2c8: // SUBFZEOx + case 0x2ca: // ADDZEOx + case 0x2e8: // SUBFMEOx + case 0x2ea: // ADDMEOx GPR_USED(desc, G_RA(op)); XER_CA_USED(desc); GPR_MODIFIED(desc, G_RD(op)); @@ -705,9 +675,9 @@ static int describe_instruction_1f(powerpc_state *ppc, UINT32 op, opcode_desc *d XER_CA_MODIFIED(desc); if (op & M_RC) CR_MODIFIED(desc, 0); - return TRUE; + return true; - case 0x2eb: /* MULLWOx */ + case 0x2eb: // MULLWOx GPR_USED(desc, G_RA(op)); GPR_USED(desc, G_RB(op)); GPR_MODIFIED(desc, G_RD(op)); @@ -715,18 +685,18 @@ static int describe_instruction_1f(powerpc_state *ppc, UINT32 op, opcode_desc *d XER_SO_MODIFIED(desc); if (op & M_RC) CR_MODIFIED(desc, 0); - if (is_403_class(ppc)) - desc->cycles = 4; /* 4XX */ - else if (is_601_class(ppc)) - desc->cycles = 5; /* 601: 5/9/10 */ - else if (is_603_class(ppc)) - desc->cycles = 2; /* 603: 2,3,4,5,6 */ + if (is_403_class()) + desc.cycles = 4; // 4XX + else if (is_601_class()) + desc.cycles = 5; // 601: 5/9/10 + else if (is_603_class()) + desc.cycles = 2; // 603: 2,3,4,5,6 else - desc->cycles = 2; /* ??? */ - return TRUE; + desc.cycles = 2; // ??? + return true; - case 0x3cb: /* DIVWUOx */ - case 0x3eb: /* DIVWOx */ + case 0x3cb: // DIVWUOx + case 0x3eb: // DIVWOx GPR_USED(desc, G_RA(op)); GPR_USED(desc, G_RB(op)); GPR_MODIFIED(desc, G_RD(op)); @@ -734,18 +704,18 @@ static int describe_instruction_1f(powerpc_state *ppc, UINT32 op, opcode_desc *d XER_SO_MODIFIED(desc); if (op & M_RC) CR_MODIFIED(desc, 0); - if (is_403_class(ppc)) - desc->cycles = 33; /* 4XX */ - else if (is_601_class(ppc)) - desc->cycles = 36; /* 601 */ - else if (is_603_class(ppc)) - desc->cycles = 37; /* 603 */ + if (is_403_class()) + desc.cycles = 33; // 4XX + else if (is_601_class()) + desc.cycles = 36; // 601 + else if (is_603_class()) + desc.cycles = 37; // 603 else - desc->cycles = 33; /* ??? */ - return TRUE; + desc.cycles = 33; // ??? + return true; - case 0x228: /* SUBFOx */ - case 0x30a: /* ADDOx */ + case 0x228: // SUBFOx + case 0x30a: // ADDOx GPR_USED(desc, G_RA(op)); GPR_USED(desc, G_RB(op)); GPR_MODIFIED(desc, G_RD(op)); @@ -753,9 +723,9 @@ static int describe_instruction_1f(powerpc_state *ppc, UINT32 op, opcode_desc *d XER_SO_MODIFIED(desc); if (op & M_RC) CR_MODIFIED(desc, 0); - return TRUE; + return true; - case 0x013: /* MFCR */ + case 0x013: // MFCR CR_USED(desc, 0); CR_USED(desc, 1); CR_USED(desc, 2); @@ -765,33 +735,33 @@ static int describe_instruction_1f(powerpc_state *ppc, UINT32 op, opcode_desc *d CR_USED(desc, 6); CR_USED(desc, 7); GPR_MODIFIED(desc, G_RD(op)); - return TRUE; - - case 0x136: /* ECIWX */ - if (!(ppc->cap & PPCCAP_VEA)) - return FALSE; - case 0x014: /* LWARX */ - case 0x017: /* LWZX */ - case 0x057: /* LBZX */ - case 0x117: /* LHZX */ - case 0x157: /* LHAX */ - case 0x216: /* LWBRX */ - case 0x316: /* LHBRX */ + return true; + + case 0x136: // ECIWX + if (!(m_context.cap & PPCCAP_VEA)) + return false; + case 0x014: // LWARX + case 0x017: // LWZX + case 0x057: // LBZX + case 0x117: // LHZX + case 0x157: // LHAX + case 0x216: // LWBRX + case 0x316: // LHBRX GPR_USED_OR_ZERO(desc, G_RA(op)); GPR_USED(desc, G_RB(op)); GPR_MODIFIED(desc, G_RD(op)); - desc->flags |= OPFLAG_READS_MEMORY; - return TRUE; - - case 0x018: /* SLWx */ - case 0x01c: /* ANDx */ - case 0x03c: /* ANDCx */ - case 0x07c: /* NORx */ - case 0x11c: /* EQVx */ - case 0x13c: /* XORx */ - case 0x19c: /* ORCx */ - case 0x1bc: /* ORx */ - case 0x1dc: /* NANDx */ + desc.flags |= OPFLAG_READS_MEMORY; + return true; + + case 0x018: // SLWx + case 0x01c: // ANDx + case 0x03c: // ANDCx + case 0x07c: // NORx + case 0x11c: // EQVx + case 0x13c: // XORx + case 0x19c: // ORCx + case 0x1bc: // ORx + case 0x1dc: // NANDx GPR_USED(desc, G_RS(op)); GPR_USED(desc, G_RB(op)); GPR_MODIFIED(desc, G_RA(op)); @@ -800,10 +770,10 @@ static int describe_instruction_1f(powerpc_state *ppc, UINT32 op, opcode_desc *d XER_SO_USED(desc); CR_MODIFIED(desc, 0); } - return TRUE; + return true; - case 0x218: /* SRWx */ - case 0x318: /* SRAWx */ + case 0x218: // SRWx + case 0x318: // SRAWx GPR_USED(desc, G_RS(op)); GPR_USED(desc, G_RB(op)); GPR_MODIFIED(desc, G_RA(op)); @@ -813,11 +783,11 @@ static int describe_instruction_1f(powerpc_state *ppc, UINT32 op, opcode_desc *d XER_SO_USED(desc); CR_MODIFIED(desc, 0); } - return TRUE; + return true; - case 0x01a: /* CNTLZWx */ - case 0x39a: /* EXTSHx */ - case 0x3ba: /* EXTSBx */ + case 0x01a: // CNTLZWx + case 0x39a: // EXTSHx + case 0x3ba: // EXTSBx GPR_USED(desc, G_RS(op)); GPR_MODIFIED(desc, G_RA(op)); if (op & M_RC) @@ -825,42 +795,42 @@ static int describe_instruction_1f(powerpc_state *ppc, UINT32 op, opcode_desc *d XER_SO_USED(desc); CR_MODIFIED(desc, 0); } - return TRUE; - - case 0x036: /* DCBST */ - case 0x056: /* DCBF */ - case 0x0f6: /* DCBTST */ - case 0x116: /* DCBT */ - case 0x2f6: /* DCBA */ - case 0x3d6: /* ICBI */ - if (!(ppc->cap & (PPCCAP_VEA | PPCCAP_4XX))) - return FALSE; + return true; + + case 0x036: // DCBST + case 0x056: // DCBF + case 0x0f6: // DCBTST + case 0x116: // DCBT + case 0x2f6: // DCBA + case 0x3d6: // ICBI + if (!(m_context.cap & (PPCCAP_VEA | PPCCAP_4XX))) + return false; GPR_USED_OR_ZERO(desc, G_RA(op)); GPR_USED(desc, G_RB(op)); - return TRUE; + return true; - case 0x1d6: /* DCBI */ - if (!(ppc->cap & (PPCCAP_OEA | PPCCAP_4XX))) - return FALSE; + case 0x1d6: // DCBI + if (!(m_context.cap & (PPCCAP_OEA | PPCCAP_4XX))) + return false; GPR_USED_OR_ZERO(desc, G_RA(op)); GPR_USED(desc, G_RB(op)); - desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; - return TRUE; + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; - case 0x037: /* LWZUX */ - case 0x077: /* LBZUX */ - case 0x137: /* LHZUX */ - case 0x177: /* LHAUX */ + case 0x037: // LWZUX + case 0x077: // LBZUX + case 0x137: // LHZUX + case 0x177: // LHAUX if (G_RA(op) == 0 || G_RA(op) == G_RD(op)) - return FALSE; + return false; GPR_USED(desc, G_RA(op)); GPR_USED(desc, G_RB(op)); GPR_MODIFIED(desc, G_RD(op)); GPR_MODIFIED(desc, G_RA(op)); - desc->flags |= OPFLAG_READS_MEMORY; - return TRUE; + desc.flags |= OPFLAG_READS_MEMORY; + return true; - case 0x153: /* MFSPR */ + case 0x153: // MFSPR GPR_MODIFIED(desc, G_RD(op)); spr = compute_spr(G_SPR(op)); if (spr == SPR_LR) @@ -875,43 +845,43 @@ static int describe_instruction_1f(powerpc_state *ppc, UINT32 op, opcode_desc *d XER_SO_USED(desc); } if (spr & 0x010) - desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; - if ((ppc->cap & PPCCAP_4XX) && spr == SPR4XX_TBLU) - desc->cycles = POWERPC_COUNT_READ_TBL; - else if ((ppc->cap & PPCCAP_VEA) && spr == SPRVEA_TBL_R) - desc->cycles = POWERPC_COUNT_READ_TBL; - else if ((ppc->cap & PPCCAP_OEA) && spr == SPROEA_DEC) - desc->cycles = POWERPC_COUNT_READ_DEC; - return TRUE; - - case 0x053: /* MFMSR */ + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + if ((m_context.cap & PPCCAP_4XX) && spr == SPR4XX_TBLU) + desc.cycles = POWERPC_COUNT_READ_TBL; + else if ((m_context.cap & PPCCAP_VEA) && spr == SPRVEA_TBL_R) + desc.cycles = POWERPC_COUNT_READ_TBL; + else if ((m_context.cap & PPCCAP_OEA) && spr == SPROEA_DEC) + desc.cycles = POWERPC_COUNT_READ_DEC; + return true; + + case 0x053: // MFMSR GPR_MODIFIED(desc, G_RD(op)); - desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_CAN_EXPOSE_EXTERNAL_INT; - if (is_601_class(ppc)) - desc->cycles = 2; /* 601 */ - return TRUE; + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_CAN_EXPOSE_EXTERNAL_INT; + if (is_601_class()) + desc.cycles = 2; // 601 + return true; - case 0x253: /* MFSR */ + case 0x253: // MFSR GPR_MODIFIED(desc, G_RD(op)); - desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; - return TRUE; + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; - case 0x293: /* MFSRIN */ + case 0x293: // MFSRIN GPR_USED(desc, G_RB(op)); GPR_MODIFIED(desc, G_RD(op)); - desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; - return TRUE; + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; - case 0x173: /* MFTB */ - if (!(ppc->cap & PPCCAP_VEA)) - return FALSE; + case 0x173: // MFTB + if (!(m_context.cap & PPCCAP_VEA)) + return false; GPR_MODIFIED(desc, G_RD(op)); spr = compute_spr(G_SPR(op)); if (spr == SPRVEA_TBL_R) - desc->cycles = POWERPC_COUNT_READ_TBL; - return TRUE; + desc.cycles = POWERPC_COUNT_READ_TBL; + return true; - case 0x068: /* NEGx */ + case 0x068: // NEGx GPR_USED(desc, G_RA(op)); GPR_MODIFIED(desc, G_RD(op)); if (op & M_RC) @@ -919,18 +889,18 @@ static int describe_instruction_1f(powerpc_state *ppc, UINT32 op, opcode_desc *d XER_SO_USED(desc); CR_MODIFIED(desc, 0); } - return TRUE; + return true; - case 0x268: /* NEGOx */ + case 0x268: // NEGOx GPR_USED(desc, G_RA(op)); GPR_MODIFIED(desc, G_RD(op)); XER_OV_MODIFIED(desc); XER_SO_MODIFIED(desc); if (op & M_RC) CR_MODIFIED(desc, 0); - return TRUE; + return true; - case 0x090: /* MTCRF */ + case 0x090: // MTCRF GPR_USED(desc, G_RS(op)); if (G_CRM(op) & 0x80) CR_MODIFIED(desc, 0); if (G_CRM(op) & 0x40) CR_MODIFIED(desc, 1); @@ -940,25 +910,25 @@ static int describe_instruction_1f(powerpc_state *ppc, UINT32 op, opcode_desc *d if (G_CRM(op) & 0x04) CR_MODIFIED(desc, 5); if (G_CRM(op) & 0x02) CR_MODIFIED(desc, 6); if (G_CRM(op) & 0x01) CR_MODIFIED(desc, 7); - return TRUE; + return true; - case 0x092: /* MTMSR */ + case 0x092: // MTMSR GPR_USED(desc, G_RS(op)); - desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_CAN_CHANGE_MODES | OPFLAG_END_SEQUENCE; - if (is_601_class(ppc)) - desc->cycles = 17; /* 601 */ - else if (is_603_class(ppc)) - desc->cycles = 2; /* 603 */ - return TRUE; - - case 0x0d2: /* MTSR */ - if (!(ppc->cap & PPCCAP_OEA)) - return FALSE; + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_CAN_CHANGE_MODES | OPFLAG_END_SEQUENCE; + if (is_601_class()) + desc.cycles = 17; // 601 + else if (is_603_class()) + desc.cycles = 2; // 603 + return true; + + case 0x0d2: // MTSR + if (!(m_context.cap & PPCCAP_OEA)) + return false; GPR_USED(desc, G_RS(op)); - desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; - return TRUE; + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; - case 0x1d3: /* MTSPR */ + case 0x1d3: // MTSPR GPR_USED(desc, G_RS(op)); spr = compute_spr(G_SPR(op)); if (spr == SPR_LR) @@ -973,65 +943,65 @@ static int describe_instruction_1f(powerpc_state *ppc, UINT32 op, opcode_desc *d XER_SO_MODIFIED(desc); } if (spr & 0x010) - desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; - return TRUE; - - case 0x1b6: /* ECOWX */ - if (!(ppc->cap & PPCCAP_VEA)) - return FALSE; - case 0x096: /* STWCX. */ - case 0x097: /* STWX */ - case 0x0d7: /* STBX */ - case 0x197: /* STHX */ - case 0x296: /* STWBRX */ - case 0x396: /* STHBRX */ + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x1b6: // ECOWX + if (!(m_context.cap & PPCCAP_VEA)) + return false; + case 0x096: // STWCX. + case 0x097: // STWX + case 0x0d7: // STBX + case 0x197: // STHX + case 0x296: // STWBRX + case 0x396: // STHBRX GPR_USED_OR_ZERO(desc, G_RA(op)); GPR_USED(desc, G_RB(op)); GPR_USED(desc, G_RS(op)); - desc->flags |= OPFLAG_WRITES_MEMORY; - return TRUE; + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; - case 0x0b7: /* STWUX */ - case 0x0f7: /* STBUX */ - case 0x1b7: /* STHUX */ + case 0x0b7: // STWUX + case 0x0f7: // STBUX + case 0x1b7: // STHUX if (G_RA(op) == 0) - return FALSE; + return false; GPR_USED(desc, G_RA(op)); GPR_USED(desc, G_RB(op)); GPR_USED(desc, G_RS(op)); GPR_MODIFIED(desc, G_RA(op)); - desc->flags |= OPFLAG_WRITES_MEMORY; - return TRUE; + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; - case 0x0f2: /* MTSRIN */ - if (!(ppc->cap & PPCCAP_OEA)) - return FALSE; + case 0x0f2: // MTSRIN + if (!(m_context.cap & PPCCAP_OEA)) + return false; GPR_USED(desc, G_RS(op)); GPR_USED(desc, G_RB(op)); - desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; - return TRUE; + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; - case 0x132: /* TLBIE */ - if (!(ppc->cap & PPCCAP_OEA)) - return FALSE; + case 0x132: // TLBIE + if (!(m_context.cap & PPCCAP_OEA)) + return false; GPR_USED(desc, G_RB(op)); - desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; - return TRUE; - - case 0x172: /* TLBIA */ - if (!(ppc->cap & PPCCAP_OEA) || (ppc->cap & PPCCAP_603_MMU)) - return FALSE; - desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; - return TRUE; - - case 0x3d2: /* TLBLD */ - case 0x3f2: /* TLBLI */ - if (!(ppc->cap & PPCCAP_603_MMU) && !is_602_class(ppc)) - return FALSE; - desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; - return TRUE; - - case 0x200: /* MCRXR */ + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x172: // TLBIA + if (!(m_context.cap & PPCCAP_OEA) || (m_context.cap & PPCCAP_603_MMU)) + return false; + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x3d2: // TLBLD + case 0x3f2: // TLBLI + if (!(m_context.cap & PPCCAP_603_MMU) && !is_602_class()) + return false; + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x200: // MCRXR XER_CA_USED(desc); XER_OV_USED(desc); XER_SO_USED(desc); @@ -1039,104 +1009,104 @@ static int describe_instruction_1f(powerpc_state *ppc, UINT32 op, opcode_desc *d XER_CA_MODIFIED(desc); XER_OV_MODIFIED(desc); XER_SO_MODIFIED(desc); - return TRUE; + return true; - case 0x215: /* LSWX */ + case 0x215: // LSWX GPR_USED_OR_ZERO(desc, G_RA(op)); GPR_USED(desc, G_RB(op)); XER_COUNT_USED(desc); for (regnum = 0; regnum < 32; regnum++) GPR_MODIFIED(desc, regnum); - desc->flags |= OPFLAG_READS_MEMORY; - return TRUE; + desc.flags |= OPFLAG_READS_MEMORY; + return true; - case 0x217: /* LFSX */ - case 0x257: /* LFDX */ - if (!(ppc->cap & PPCCAP_FPU)) - return FALSE; + case 0x217: // LFSX + case 0x257: // LFDX + if (!(m_context.cap & PPCCAP_FPU)) + return false; GPR_USED_OR_ZERO(desc, G_RA(op)); GPR_USED(desc, G_RB(op)); FPR_MODIFIED(desc, G_RD(op)); - desc->flags |= OPFLAG_READS_MEMORY; - return TRUE; - - case 0x236: /* TLBSYNC */ - if (!(ppc->cap & PPCCAP_OEA)) - return FALSE; - desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; - return TRUE; - - case 0x256: /* SYNC */ - return TRUE; - - case 0x356: /* EIEIO */ - if (!(ppc->cap & PPCCAP_VEA)) - return FALSE; - return TRUE; - - case 0x237: /* LFSUX */ - case 0x277: /* LFDUX */ - if (!(ppc->cap & PPCCAP_FPU)) - return FALSE; + desc.flags |= OPFLAG_READS_MEMORY; + return true; + + case 0x236: // TLBSYNC + if (!(m_context.cap & PPCCAP_OEA)) + return false; + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x256: // SYNC + return true; + + case 0x356: // EIEIO + if (!(m_context.cap & PPCCAP_VEA)) + return false; + return true; + + case 0x237: // LFSUX + case 0x277: // LFDUX + if (!(m_context.cap & PPCCAP_FPU)) + return false; if (G_RA(op) == 0) - return FALSE; + return false; GPR_USED(desc, G_RA(op)); GPR_USED(desc, G_RB(op)); GPR_MODIFIED(desc, G_RA(op)); FPR_MODIFIED(desc, G_RD(op)); - desc->flags |= OPFLAG_READS_MEMORY; - return TRUE; + desc.flags |= OPFLAG_READS_MEMORY; + return true; - case 0x255: /* LSWI */ + case 0x255: // LSWI GPR_USED_OR_ZERO(desc, G_RA(op)); for (regnum = 0; regnum < ((G_NB(op) - 1) & 0x1f) + 1; regnum += 4) GPR_MODIFIED(desc, (G_RD(op) + regnum / 4) % 32); - desc->flags |= OPFLAG_READS_MEMORY; - desc->cycles = (((G_NB(op) - 1) & 0x1f) + 1 + 3) / 4; - return TRUE; + desc.flags |= OPFLAG_READS_MEMORY; + desc.cycles = (((G_NB(op) - 1) & 0x1f) + 1 + 3) / 4; + return true; - case 0x295: /* STSWX */ + case 0x295: // STSWX GPR_USED_OR_ZERO(desc, G_RA(op)); GPR_USED(desc, G_RB(op)); XER_COUNT_USED(desc); for (regnum = 0; regnum < 32; regnum++) GPR_USED(desc, regnum); - desc->flags |= OPFLAG_WRITES_MEMORY; - return TRUE; + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; - case 0x2d5: /* STSWI */ + case 0x2d5: // STSWI GPR_USED_OR_ZERO(desc, G_RA(op)); for (regnum = 0; regnum < ((G_NB(op) - 1) & 0x1f) + 1; regnum += 4) GPR_USED(desc, (G_RD(op) + regnum / 4) % 32); - desc->flags |= OPFLAG_WRITES_MEMORY; - desc->cycles = (((G_NB(op) - 1) & 0x1f) + 1 + 3) / 4; - return TRUE; - - case 0x297: /* STFSX */ - case 0x2d7: /* STFDX */ - case 0x3d7: /* STFIWX */ - if (!(ppc->cap & PPCCAP_FPU)) - return FALSE; + desc.flags |= OPFLAG_WRITES_MEMORY; + desc.cycles = (((G_NB(op) - 1) & 0x1f) + 1 + 3) / 4; + return true; + + case 0x297: // STFSX + case 0x2d7: // STFDX + case 0x3d7: // STFIWX + if (!(m_context.cap & PPCCAP_FPU)) + return false; GPR_USED_OR_ZERO(desc, G_RA(op)); GPR_USED(desc, G_RB(op)); FPR_USED(desc, G_RS(op)); - desc->flags |= OPFLAG_WRITES_MEMORY; - return TRUE; + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; - case 0x2b7: /* STFSUX */ - case 0x2f7: /* STFDUX */ - if (!(ppc->cap & PPCCAP_FPU)) - return FALSE; + case 0x2b7: // STFSUX + case 0x2f7: // STFDUX + if (!(m_context.cap & PPCCAP_FPU)) + return false; if (G_RA(op) == 0) - return FALSE; + return false; GPR_USED_OR_ZERO(desc, G_RA(op)); GPR_USED(desc, G_RB(op)); GPR_MODIFIED(desc, G_RA(op)); FPR_USED(desc, G_RS(op)); - desc->flags |= OPFLAG_WRITES_MEMORY; - return TRUE; + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; - case 0x338: /* SRAWIx */ + case 0x338: // SRAWIx GPR_USED(desc, G_RS(op)); GPR_MODIFIED(desc, G_RA(op)); XER_CA_MODIFIED(desc); @@ -1145,73 +1115,73 @@ static int describe_instruction_1f(powerpc_state *ppc, UINT32 op, opcode_desc *d XER_SO_USED(desc); CR_MODIFIED(desc, 0); } - return TRUE; + return true; - case 0x3f6: /* DCBZ */ - if (!(ppc->cap & (PPCCAP_VEA | PPCCAP_4XX))) - return FALSE; + case 0x3f6: // DCBZ + if (!(m_context.cap & (PPCCAP_VEA | PPCCAP_4XX))) + return false; GPR_USED_OR_ZERO(desc, G_RA(op)); GPR_USED(desc, G_RB(op)); - desc->flags |= OPFLAG_WRITES_MEMORY; - return TRUE; - - case 0x106: /* ICBT */ - case 0x1c6: /* DCCCI */ - case 0x3c6: /* ICCCI */ - if (!(ppc->cap & PPCCAP_4XX)) - return FALSE; + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; + + case 0x106: // ICBT + case 0x1c6: // DCCCI + case 0x3c6: // ICCCI + if (!(m_context.cap & PPCCAP_4XX)) + return false; GPR_USED_OR_ZERO(desc, G_RA(op)); GPR_USED(desc, G_RB(op)); - desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; - return TRUE; + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; - case 0x1e6: /* DCREAD */ - case 0x3e6: /* ICREAD */ - if (!(ppc->cap & PPCCAP_4XX)) - return FALSE; + case 0x1e6: // DCREAD + case 0x3e6: // ICREAD + if (!(m_context.cap & PPCCAP_4XX)) + return false; GPR_USED_OR_ZERO(desc, G_RA(op)); GPR_USED(desc, G_RB(op)); GPR_MODIFIED(desc, G_RT(op)); - desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; - return TRUE; + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; - case 0x143: /* MFDCR */ - if (!(ppc->cap & PPCCAP_4XX)) - return FALSE; + case 0x143: // MFDCR + if (!(m_context.cap & PPCCAP_4XX)) + return false; GPR_MODIFIED(desc, G_RD(op)); - desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; - return TRUE; + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; - case 0x1c3: /* MTDCR */ - if (!(ppc->cap & PPCCAP_4XX)) - return FALSE; + case 0x1c3: // MTDCR + if (!(m_context.cap & PPCCAP_4XX)) + return false; GPR_USED(desc, G_RS(op)); - desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_CAN_EXPOSE_EXTERNAL_INT; - return TRUE; + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_CAN_EXPOSE_EXTERNAL_INT; + return true; - case 0x083: /* WRTEE */ - if (!(ppc->cap & PPCCAP_4XX)) - return FALSE; + case 0x083: // WRTEE + if (!(m_context.cap & PPCCAP_4XX)) + return false; GPR_USED(desc, G_RS(op)); - desc->flags |= OPFLAG_CAN_EXPOSE_EXTERNAL_INT; - return TRUE; + desc.flags |= OPFLAG_CAN_EXPOSE_EXTERNAL_INT; + return true; - case 0x0a3: /* WRTEEI */ - if (!(ppc->cap & PPCCAP_4XX)) - return FALSE; + case 0x0a3: // WRTEEI + if (!(m_context.cap & PPCCAP_4XX)) + return false; if (op & MSR_EE) - desc->flags |= OPFLAG_CAN_EXPOSE_EXTERNAL_INT; - return TRUE; - - case 0x254: /* ESA */ - case 0x274: /* DSA */ - if (!is_602_class(ppc)) - return FALSE; - desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; - return TRUE; + desc.flags |= OPFLAG_CAN_EXPOSE_EXTERNAL_INT; + return true; + + case 0x254: // ESA + case 0x274: // DSA + if (!is_602_class()) + return false; + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; } - return FALSE; + return false; } @@ -1221,62 +1191,62 @@ static int describe_instruction_1f(powerpc_state *ppc, UINT32 op, opcode_desc *d 0x3b group -------------------------------------------------*/ -static int describe_instruction_3b(powerpc_state *ppc, UINT32 op, opcode_desc *desc, const opcode_desc *prev) +bool ppc_frontend::describe_3b(UINT32 op, opcode_desc &desc, const opcode_desc *prev) { UINT32 opswitch = (op >> 1) & 0x1f; - if (!(ppc->cap & PPCCAP_FPU)) - return FALSE; + if (!(m_context.cap & PPCCAP_FPU)) + return false; switch (opswitch) { - case 0x12: /* FDIVSx */ + case 0x12: // FDIVSx FPR_USED(desc, G_RA(op)); FPR_USED(desc, G_RB(op)); FPR_MODIFIED(desc, G_RD(op)); if (op & M_RC) CR_MODIFIED(desc, 1); - if (is_601_class(ppc)) - desc->cycles = 17; /* 601 */ - else if (is_603_class(ppc)) - desc->cycles = 18; /* 603 */ + if (is_601_class()) + desc.cycles = 17; // 601 + else if (is_603_class()) + desc.cycles = 18; // 603 else - desc->cycles = 17; /* ??? */ + desc.cycles = 17; // ??? FPSCR_MODIFIED(desc, 4); - return TRUE; + return true; - case 0x14: /* FSUBSx */ - case 0x15: /* FADDSx */ + case 0x14: // FSUBSx + case 0x15: // FADDSx FPR_USED(desc, G_RA(op)); FPR_USED(desc, G_RB(op)); FPR_MODIFIED(desc, G_RD(op)); if (op & M_RC) CR_MODIFIED(desc, 1); FPSCR_MODIFIED(desc, 4); - return TRUE; + return true; - case 0x19: /* FMULSx - not the same form as FSUB/FADD! */ + case 0x19: // FMULSx - not the same form as FSUB/FADD! FPR_USED(desc, G_RA(op)); FPR_USED(desc, G_REGC(op)); FPR_MODIFIED(desc, G_RD(op)); if (op & M_RC) CR_MODIFIED(desc, 1); FPSCR_MODIFIED(desc, 4); - return TRUE; + return true; - case 0x16: /* FSQRTSx */ - case 0x18: /* FRESx */ + case 0x16: // FSQRTSx + case 0x18: // FRESx FPR_USED(desc, G_RB(op)); FPR_MODIFIED(desc, G_RD(op)); if (op & M_RC) CR_MODIFIED(desc, 1); FPSCR_MODIFIED(desc, 4); - return TRUE; + return true; - case 0x1c: /* FMSUBSx */ - case 0x1d: /* FMADDSx */ - case 0x1e: /* FNMSUBSx */ - case 0x1f: /* FNMADDSx */ + case 0x1c: // FMSUBSx + case 0x1d: // FMADDSx + case 0x1e: // FNMSUBSx + case 0x1f: // FNMADDSx FPR_USED(desc, G_RA(op)); FPR_USED(desc, G_RB(op)); FPR_USED(desc, G_REGC(op)); @@ -1284,10 +1254,10 @@ static int describe_instruction_3b(powerpc_state *ppc, UINT32 op, opcode_desc *d if (op & M_RC) CR_MODIFIED(desc, 1); FPSCR_MODIFIED(desc, 4); - return TRUE; + return true; } - return FALSE; + return false; } @@ -1297,132 +1267,132 @@ static int describe_instruction_3b(powerpc_state *ppc, UINT32 op, opcode_desc *d 0x3f group -------------------------------------------------*/ -static int describe_instruction_3f(powerpc_state *ppc, UINT32 op, opcode_desc *desc, const opcode_desc *prev) +bool ppc_frontend::describe_3f(UINT32 op, opcode_desc &desc, const opcode_desc *prev) { UINT32 opswitch = (op >> 1) & 0x3ff; - if (!(ppc->cap & PPCCAP_FPU)) - return FALSE; + if (!(m_context.cap & PPCCAP_FPU)) + return false; if (opswitch & 0x10) { opswitch &= 0x1f; switch (opswitch) { - case 0x12: /* FDIVx */ + case 0x12: // FDIVx FPR_USED(desc, G_RA(op)); FPR_USED(desc, G_RB(op)); FPR_MODIFIED(desc, G_RD(op)); if (op & M_RC) CR_MODIFIED(desc, 1); - if (is_601_class(ppc)) - desc->cycles = 31; /* 601 */ - else if (is_603_class(ppc)) - desc->cycles = 33; /* 603 */ + if (is_601_class()) + desc.cycles = 31; // 601 + else if (is_603_class()) + desc.cycles = 33; // 603 else - desc->cycles = 31; /* ??? */ + desc.cycles = 31; // ??? FPSCR_MODIFIED(desc, 4); - return TRUE; + return true; - case 0x19: /* FMULx */ + case 0x19: // FMULx FPR_USED(desc, G_RA(op)); FPR_USED(desc, G_REGC(op)); FPR_MODIFIED(desc, G_RD(op)); if (op & M_RC) CR_MODIFIED(desc, 1); - desc->cycles = 2; /* 601/603 */ + desc.cycles = 2; // 601/603 FPSCR_MODIFIED(desc, 4); - return TRUE; + return true; - case 0x14: /* FSUBx */ - case 0x15: /* FADDx */ + case 0x14: // FSUBx + case 0x15: // FADDx FPR_USED(desc, G_RA(op)); FPR_USED(desc, G_RB(op)); FPR_MODIFIED(desc, G_RD(op)); if (op & M_RC) CR_MODIFIED(desc, 1); FPSCR_MODIFIED(desc, 4); - return TRUE; + return true; - case 0x16: /* FSQRTx */ - case 0x1a: /* FSQRTEx */ + case 0x16: // FSQRTx + case 0x1a: // FSQRTEx FPR_USED(desc, G_RB(op)); FPR_MODIFIED(desc, G_RD(op)); if (op & M_RC) CR_MODIFIED(desc, 1); FPSCR_MODIFIED(desc, 4); - return TRUE; + return true; - case 0x17: /* FSELx */ + case 0x17: // FSELx FPR_USED(desc, G_RA(op)); FPR_USED(desc, G_RB(op)); FPR_USED(desc, G_REGC(op)); FPR_MODIFIED(desc, G_RD(op)); if (op & M_RC) CR_MODIFIED(desc, 1); - desc->cycles = 2; /* 601/603 */ - return TRUE; + desc.cycles = 2; // 601/603 + return true; - case 0x1c: /* FMSUBx */ - case 0x1d: /* FMADDx */ - case 0x1e: /* FNMSUBx */ - case 0x1f: /* FNMADDx */ + case 0x1c: // FMSUBx + case 0x1d: // FMADDx + case 0x1e: // FNMSUBx + case 0x1f: // FNMADDx FPR_USED(desc, G_RA(op)); FPR_USED(desc, G_RB(op)); FPR_USED(desc, G_REGC(op)); FPR_MODIFIED(desc, G_RD(op)); if (op & M_RC) CR_MODIFIED(desc, 1); - desc->cycles = 2; /* 601/603 */ + desc.cycles = 2; // 601/603 FPSCR_MODIFIED(desc, 4); - return TRUE; + return true; } } else { switch (opswitch) { - case 0x32e: /* FCTIDx - 64-bit only */ - case 0x32f: /* FCTIDZx - 64-bit only */ - case 0x34e: /* FCFIDx - 64-bit only */ - return FALSE; + case 0x32e: // FCTIDx - 64-bit only + case 0x32f: // FCTIDZx - 64-bit only + case 0x34e: // FCFIDx - 64-bit only + return false; - case 0x000: /* FCMPU */ - case 0x020: /* FCMPO */ + case 0x000: // FCMPU + case 0x020: // FCMPO FPR_USED(desc, G_RA(op)); FPR_USED(desc, G_RB(op)); CR_MODIFIED(desc, G_CRFD(op)); - return TRUE; + return true; - case 0x00c: /* FRSPx */ - case 0x00e: /* FCTIWx */ - case 0x00f: /* FCTIWZx */ + case 0x00c: // FRSPx + case 0x00e: // FCTIWx + case 0x00f: // FCTIWZx FPSCR_MODIFIED(desc, 4); - case 0x028: /* FNEGx */ - case 0x048: /* FMRx */ - case 0x088: /* FNABSx */ - case 0x108: /* FABSx */ + case 0x028: // FNEGx + case 0x048: // FMRx + case 0x088: // FNABSx + case 0x108: // FABSx FPR_USED(desc, G_RB(op)); FPR_MODIFIED(desc, G_RD(op)); if (op & M_RC) CR_MODIFIED(desc, 1); - return TRUE; + return true; - case 0x026: /* MTFSB1x */ - case 0x046: /* MTFSB0x */ + case 0x026: // MTFSB1x + case 0x046: // MTFSB0x FPSCR_MODIFIED(desc, G_CRBD(op) / 4); - return TRUE; + return true; - case 0x040: /* MCRFS */ + case 0x040: // MCRFS FPSCR_USED(desc, G_CRFS(op)); CR_MODIFIED(desc, G_CRFD(op)); - return TRUE; + return true; - case 0x086: /* MTFSFIx */ + case 0x086: // MTFSFIx FPSCR_MODIFIED(desc, G_CRFD(op)); - return TRUE; + return true; - case 0x247: /* MFFSx */ + case 0x247: // MFFSx FPSCR_USED(desc, 0); FPSCR_USED(desc, 1); FPSCR_USED(desc, 2); @@ -1432,9 +1402,9 @@ static int describe_instruction_3f(powerpc_state *ppc, UINT32 op, opcode_desc *d FPSCR_USED(desc, 6); FPSCR_USED(desc, 7); FPR_MODIFIED(desc, G_RD(op)); - return TRUE; + return true; - case 0x2c7: /* MTFSFx */ + case 0x2c7: // MTFSFx FPR_USED(desc, G_RB(op)); if (G_CRM(op) & 0x80) FPSCR_MODIFIED(desc, 0); if (G_CRM(op) & 0x40) FPSCR_MODIFIED(desc, 1); @@ -1444,9 +1414,9 @@ static int describe_instruction_3f(powerpc_state *ppc, UINT32 op, opcode_desc *d if (G_CRM(op) & 0x04) FPSCR_MODIFIED(desc, 5); if (G_CRM(op) & 0x02) FPSCR_MODIFIED(desc, 6); if (G_CRM(op) & 0x01) FPSCR_MODIFIED(desc, 7); - return TRUE; + return true; } } - return FALSE; + return false; } diff --git a/src/emu/cpu/powerpc/ppcfe.h b/src/emu/cpu/powerpc/ppcfe.h index 27886e1806a..b3209e4358c 100644 --- a/src/emu/cpu/powerpc/ppcfe.h +++ b/src/emu/cpu/powerpc/ppcfe.h @@ -4,34 +4,62 @@ Front-end for PowerPC recompiler +**************************************************************************** + Copyright Aaron Giles - Released for general non-commercial use under the MAME license - Visit http://mamedev.org for licensing and usage restrictions. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name 'MAME' nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. ***************************************************************************/ #ifndef __PPCFE_H__ #define __PPCFE_H__ +#include "ppccom.h" #include "cpu/drcfe.h" -/*************************************************************************** - CONSTANTS -***************************************************************************/ +//************************************************************************** +// MACROS +//************************************************************************** -/* register flags 0 */ +// register flags 0 #define REGFLAG_R(n) (1 << (n)) #define REGFLAG_RZ(n) (((n) == 0) ? 0 : REGFLAG_R(n)) -/* register flags 1 */ +// register flags 1 #define REGFLAG_FR(n) (1 << (n)) -/* register flags 2 */ +// register flags 2 #define REGFLAG_CR(n) (0xf0000000 >> (4 * (n))) #define REGFLAG_CR_BIT(n) (0x80000000 >> (n)) -/* register flags 3 */ +// register flags 3 #define REGFLAG_XER_CA (1 << 0) #define REGFLAG_XER_OV (1 << 1) #define REGFLAG_XER_SO (1 << 2) @@ -42,10 +70,37 @@ -/*************************************************************************** - FUNCTION PROTOTYPES -***************************************************************************/ +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class ppc_frontend : public drc_frontend +{ +public: + // construction/destruction + ppc_frontend(powerpc_state &state, UINT32 window_start, UINT32 window_end, UINT32 max_sequence); + +protected: + // required overrides + virtual bool describe(opcode_desc &desc, const opcode_desc *prev); + +private: + // inlines + UINT32 compute_spr(UINT32 spr) const { return ((spr >> 5) | (spr << 5)) & 0x3ff; } + bool is_403_class() const { return (m_context.flavor == PPC_MODEL_403GA || m_context.flavor == PPC_MODEL_403GB || m_context.flavor == PPC_MODEL_403GC || m_context.flavor == PPC_MODEL_403GCX || m_context.flavor == PPC_MODEL_405GP); } + bool is_601_class() const { return (m_context.flavor == PPC_MODEL_601); } + bool is_602_class() const { return (m_context.flavor == PPC_MODEL_602); } + bool is_603_class() const { return (m_context.flavor == PPC_MODEL_603 || m_context.flavor == PPC_MODEL_603E || m_context.flavor == PPC_MODEL_603EV || m_context.flavor == PPC_MODEL_603R); } + + // internal helpers + bool describe_13(UINT32 op, opcode_desc &desc, const opcode_desc *prev); + bool describe_1f(UINT32 op, opcode_desc &desc, const opcode_desc *prev); + bool describe_3b(UINT32 op, opcode_desc &desc, const opcode_desc *prev); + bool describe_3f(UINT32 op, opcode_desc &desc, const opcode_desc *prev); + + // internal state + powerpc_state &m_context; +}; -int ppcfe_describe(void *param, opcode_desc *desc, const opcode_desc *prev); #endif /* __PPCFE_H__ */ diff --git a/src/emu/cpu/rsp/rspdrc.c b/src/emu/cpu/rsp/rspdrc.c index 84a39f46b78..10a65bb74f5 100644 --- a/src/emu/cpu/rsp/rspdrc.c +++ b/src/emu/cpu/rsp/rspdrc.c @@ -106,7 +106,7 @@ struct _rspimp_state /* core state */ drccache * cache; /* pointer to the DRC code cache */ drcuml_state * drcuml; /* DRC UML generator state */ - drcfe_state * drcfe; /* pointer to the DRC front-end state */ + rsp_frontend * drcfe; /* pointer to the DRC front-end state */ UINT32 drcoptions; /* configurable DRC options */ /* internal stuff */ @@ -603,13 +603,6 @@ static void rspcom_init(rsp_state *rsp, legacy_cpu_device *device, device_irq_ca static CPU_INIT( rsp ) { - drcfe_config feconfig = - { - COMPILE_BACKWARDS_BYTES, /* code window start offset = startpc - window_start */ - COMPILE_FORWARDS_BYTES, /* code window end offset = startpc + window_end */ - COMPILE_MAX_SEQUENCE, /* maximum instructions to include in a sequence */ - rspfe_describe /* callback to describe a single instruction */ - }; rsp_state *rsp; drccache *cache; UINT32 flags = 0; @@ -669,11 +662,7 @@ static CPU_INIT( rsp ) drcuml_symbol_add(rsp->impstate->drcuml, &rsp->impstate->numcycles, sizeof(rsp->impstate->numcycles), "numcycles"); /* initialize the front-end helper */ - if (SINGLE_INSTRUCTION_MODE) - { - feconfig.max_sequence = 1; - } - rsp->impstate->drcfe = drcfe_init(device, &feconfig, rsp); + rsp->impstate->drcfe = auto_alloc(device->machine, rsp_frontend(*rsp, COMPILE_BACKWARDS_BYTES, COMPILE_FORWARDS_BYTES, SINGLE_INSTRUCTION_MODE ? 1 : COMPILE_MAX_SEQUENCE)); /* compute the register parameters */ for (regnum = 0; regnum < 32; regnum++) @@ -721,7 +710,7 @@ static CPU_EXIT( rsp ) rsp_state *rsp = get_safe_token(device); /* clean up the DRC */ - drcfe_exit(rsp->impstate->drcfe); + auto_free(device->machine, rsp->impstate->drcfe); drcuml_free(rsp->impstate->drcuml); drccache_free(rsp->impstate->cache); } @@ -3479,7 +3468,7 @@ static void code_compile_block(rsp_state *rsp, offs_t pc) g_profiler.start(PROFILER_DRC_COMPILE); /* get a description of this sequence */ - desclist = drcfe_describe_code(rsp->impstate->drcfe, pc); + desclist = rsp->impstate->drcfe->describe_code(pc); /* if we get an error back, flush the cache and try again */ if (setjmp(errorbuf) != 0) @@ -3491,7 +3480,7 @@ static void code_compile_block(rsp_state *rsp, offs_t pc) block = drcuml_block_begin(drcuml, 8192, &errorbuf); /* loop until we get through all instruction sequences */ - for (seqhead = desclist; seqhead != NULL; seqhead = seqlast->next) + for (seqhead = desclist; seqhead != NULL; seqhead = seqlast->next()) { const opcode_desc *curdesc; UINT32 nextpc; @@ -3501,7 +3490,7 @@ static void code_compile_block(rsp_state *rsp, offs_t pc) UML_COMMENT(block, "-------------------------"); // comment /* determine the last instruction in this sequence */ - for (seqlast = seqhead; seqlast != NULL; seqlast = seqlast->next) + for (seqlast = seqhead; seqlast != NULL; seqlast = seqlast->next()) if (seqlast->flags & OPFLAG_END_SEQUENCE) break; assert(seqlast != NULL); @@ -3536,7 +3525,7 @@ static void code_compile_block(rsp_state *rsp, offs_t pc) UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc /* iterate over instructions in the sequence and compile them */ - for (curdesc = seqhead; curdesc != seqlast->next; curdesc = curdesc->next) + for (curdesc = seqhead; curdesc != seqlast->next(); curdesc = curdesc->next()) generate_sequence_instruction(rsp, block, &compiler, curdesc); /* if we need to return to the start, do it */ @@ -3551,7 +3540,7 @@ static void code_compile_block(rsp_state *rsp, offs_t pc) generate_update_cycles(rsp, block, &compiler, IMM(nextpc), TRUE); // <subtract cycles> /* if the last instruction can change modes, use a variable mode; otherwise, assume the same mode */ - if (seqlast->next == NULL || seqlast->next->pc != nextpc) + if (seqlast->next() == NULL || seqlast->next()->pc != nextpc) UML_HASHJMP(block, IMM(0), IMM(nextpc), rsp->impstate->nocode); // hashjmp <mode>,nextpc,nocode } @@ -3800,7 +3789,7 @@ static void generate_checksum_block(rsp_state *rsp, drcuml_block *block, compile UML_COMMENT(block, "[Validation for %08X]", seqhead->pc | 0x1000); // comment } /* loose verify or single instruction: just compare and fail */ - if (!(rsp->impstate->drcoptions & RSPDRC_STRICT_VERIFY) || seqhead->next == NULL) + if (!(rsp->impstate->drcoptions & RSPDRC_STRICT_VERIFY) || seqhead->next() == NULL) { if (!(seqhead->flags & OPFLAG_VIRTUAL_NOOP)) { @@ -3818,7 +3807,7 @@ static void generate_checksum_block(rsp_state *rsp, drcuml_block *block, compile void *base = rsp->direct->read_decrypted_ptr(seqhead->physpc | 0x1000); UML_LOAD(block, IREG(0), base, IMM(0), DWORD); // load i0,base,0,dword sum += seqhead->opptr.l[0]; - for (curdesc = seqhead->next; curdesc != seqlast->next; curdesc = curdesc->next) + for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next()) if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP)) { base = rsp->direct->read_decrypted_ptr(curdesc->physpc | 0x1000); @@ -3910,7 +3899,7 @@ static void generate_delay_slot_and_branch(rsp_state *rsp, drcuml_block *block, /* compile the delay slot using temporary compiler state */ assert(desc->delay != NULL); - generate_sequence_instruction(rsp, block, &compiler_temp, desc->delay); // <next instruction> + generate_sequence_instruction(rsp, block, &compiler_temp, desc->delay.first()); // <next instruction> /* update the cycles and jump through the hash table to the target */ if (desc->targetpc != BRANCH_TARGET_DYNAMIC) diff --git a/src/emu/cpu/rsp/rspfe.c b/src/emu/cpu/rsp/rspfe.c index 9fcad914577..225d1d551ff 100644 --- a/src/emu/cpu/rsp/rspfe.c +++ b/src/emu/cpu/rsp/rspfe.c @@ -1,4 +1,4 @@ - /*************************************************************************** +/*************************************************************************** rspfe.c @@ -14,294 +14,291 @@ #include "rspfe.h" #include "rsp.h" -/*************************************************************************** - FUNCTION PROTOTYPES -***************************************************************************/ +//************************************************************************** +// RSP FRONTEND +//************************************************************************** -static int describe_instruction_special(rsp_state *rsp, UINT32 op, opcode_desc *desc); -static int describe_instruction_regimm(rsp_state *rsp, UINT32 op, opcode_desc *desc); -static int describe_instruction_cop0(rsp_state *rsp, UINT32 op, opcode_desc *desc); -static int describe_instruction_cop2(rsp_state *rsp, UINT32 op, opcode_desc *desc); +//------------------------------------------------- +// rsp_frontend - constructor +//------------------------------------------------- + +rsp_frontend::rsp_frontend(rsp_state &state, UINT32 window_start, UINT32 window_end, UINT32 max_sequence) + : drc_frontend(*state.device, window_start, window_end, max_sequence), + m_context(state) +{ +} -/*************************************************************************** - INSTRUCTION PARSERS -***************************************************************************/ -/*------------------------------------------------- - describe_instruction - build a description - of a single instruction --------------------------------------------------*/ +//------------------------------------------------- +// describe - build a description of a single +// instruction +//------------------------------------------------- -int rspfe_describe(void *param, opcode_desc *desc, const opcode_desc *prev) +bool rsp_frontend::describe(opcode_desc &desc, const opcode_desc *prev) { - rsp_state *rsp = (rsp_state *)param; UINT32 op, opswitch; - /* fetch the opcode */ - op = desc->opptr.l[0] = rsp->direct->read_decrypted_dword(desc->physpc | 0x1000); + // fetch the opcode + op = desc.opptr.l[0] = m_context.direct->read_decrypted_dword(desc.physpc | 0x1000); - /* all instructions are 4 bytes and default to a single cycle each */ - desc->length = 4; - desc->cycles = 1; + // all instructions are 4 bytes and default to a single cycle each + desc.length = 4; + desc.cycles = 1; - /* parse the instruction */ + // parse the instruction opswitch = op >> 26; switch (opswitch) { - case 0x00: /* SPECIAL */ - return describe_instruction_special(rsp, op, desc); + case 0x00: // SPECIAL + return describe_special(op, desc); - case 0x01: /* REGIMM */ - return describe_instruction_regimm(rsp, op, desc); + case 0x01: // REGIMM + return describe_regimm(op, desc); - case 0x10: /* COP0 */ - return describe_instruction_cop0(rsp, op, desc); + case 0x10: // COP0 + return describe_cop0(op, desc); - case 0x12: /* COP2 */ - return describe_instruction_cop2(rsp, op, desc); + case 0x12: // COP2 + return describe_cop2(op, desc); - case 0x02: /* J */ - desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; - desc->targetpc = ((LIMMVAL << 2) & 0x00000fff) | 0x1000; - desc->delayslots = 1; - return TRUE; + case 0x02: // J + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = ((LIMMVAL << 2) & 0x00000fff) | 0x1000; + desc.delayslots = 1; + return true; - case 0x03: /* JAL */ - desc->regout[0] |= REGFLAG_R(31); - desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; - desc->targetpc = ((LIMMVAL << 2) & 0x00000fff) | 0x1000; - desc->delayslots = 1; - return TRUE; + case 0x03: // JAL + desc.regout[0] |= REGFLAG_R(31); + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = ((LIMMVAL << 2) & 0x00000fff) | 0x1000; + desc.delayslots = 1; + return true; - case 0x04: /* BEQ */ - case 0x05: /* BNE */ + case 0x04: // BEQ + case 0x05: // BNE if ((opswitch == 0x04 || opswitch == 0x14) && RSREG == RTREG) - desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; else { - desc->regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); - desc->flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; } - desc->targetpc = ((desc->pc + 4 + (SIMMVAL << 2)) & 0x00000fff) | 0x1000; - desc->delayslots = 1; - desc->skipslots = (opswitch & 0x10) ? 1 : 0; - return TRUE; + desc.targetpc = ((desc.pc + 4 + (SIMMVAL << 2)) & 0x00000fff) | 0x1000; + desc.delayslots = 1; + desc.skipslots = (opswitch & 0x10) ? 1 : 0; + return true; - case 0x06: /* BLEZ */ - case 0x07: /* BGTZ */ + case 0x06: // BLEZ + case 0x07: // BGTZ if ((opswitch == 0x06 || opswitch == 0x16) && RSREG == 0) - desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; else { - desc->regin[0] |= REGFLAG_R(RSREG); - desc->flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + desc.regin[0] |= REGFLAG_R(RSREG); + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; } - desc->targetpc = ((desc->pc + 4 + (SIMMVAL << 2)) & 0x00000fff) | 0x1000; - desc->delayslots = 1; - desc->skipslots = (opswitch & 0x10) ? 1 : 0; - return TRUE; - - case 0x08: /* ADDI */ - desc->regin[0] |= REGFLAG_R(RSREG); - desc->regout[0] |= REGFLAG_R(RTREG); - return TRUE; - - case 0x09: /* ADDIU */ - case 0x0a: /* SLTI */ - case 0x0b: /* SLTIU */ - case 0x0c: /* ANDI */ - case 0x0d: /* ORI */ - case 0x0e: /* XORI */ - desc->regin[0] |= REGFLAG_R(RSREG); - desc->regout[0] |= REGFLAG_R(RTREG); - return TRUE; - - case 0x0f: /* LUI */ - desc->regout[0] |= REGFLAG_R(RTREG); - return TRUE; - - case 0x20: /* LB */ - case 0x21: /* LH */ - case 0x23: /* LW */ - case 0x24: /* LBU */ - case 0x25: /* LHU */ - case 0x27: /* LWU */ - desc->regin[0] |= REGFLAG_R(RSREG); - desc->regout[0] |= REGFLAG_R(RTREG); - desc->flags |= OPFLAG_READS_MEMORY; - return TRUE; - - case 0x28: /* SB */ - case 0x29: /* SH */ - case 0x2b: /* SW */ - desc->regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); - desc->flags |= OPFLAG_WRITES_MEMORY; - return TRUE; - - case 0x32: /* LWC2 */ - desc->regin[0] |= REGFLAG_R(RSREG); - desc->flags |= OPFLAG_READS_MEMORY; - return TRUE; - - case 0x3a: /* SWC2 */ - desc->regin[0] |= REGFLAG_R(RSREG); - desc->flags |= OPFLAG_WRITES_MEMORY; - return TRUE; + desc.targetpc = ((desc.pc + 4 + (SIMMVAL << 2)) & 0x00000fff) | 0x1000; + desc.delayslots = 1; + desc.skipslots = (opswitch & 0x10) ? 1 : 0; + return true; + + case 0x08: // ADDI + desc.regin[0] |= REGFLAG_R(RSREG); + desc.regout[0] |= REGFLAG_R(RTREG); + return true; + + case 0x09: // ADDIU + case 0x0a: // SLTI + case 0x0b: // SLTIU + case 0x0c: // ANDI + case 0x0d: // ORI + case 0x0e: // XORI + desc.regin[0] |= REGFLAG_R(RSREG); + desc.regout[0] |= REGFLAG_R(RTREG); + return true; + + case 0x0f: // LUI + desc.regout[0] |= REGFLAG_R(RTREG); + return true; + + case 0x20: // LB + case 0x21: // LH + case 0x23: // LW + case 0x24: // LBU + case 0x25: // LHU + case 0x27: // LWU + desc.regin[0] |= REGFLAG_R(RSREG); + desc.regout[0] |= REGFLAG_R(RTREG); + desc.flags |= OPFLAG_READS_MEMORY; + return true; + + case 0x28: // SB + case 0x29: // SH + case 0x2b: // SW + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; + + case 0x32: // LWC2 + desc.regin[0] |= REGFLAG_R(RSREG); + desc.flags |= OPFLAG_READS_MEMORY; + return true; + + case 0x3a: // SWC2 + desc.regin[0] |= REGFLAG_R(RSREG); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; } - return FALSE; + return false; } -/*------------------------------------------------- - describe_instruction_special - build a - description of a single instruction in the - 'special' group --------------------------------------------------*/ +//------------------------------------------------- +// describe_special - build a description of a +// single instruction in the 'special' group +//------------------------------------------------- -static int describe_instruction_special(rsp_state *rsp, UINT32 op, opcode_desc *desc) +bool rsp_frontend::describe_special(UINT32 op, opcode_desc &desc) { switch (op & 63) { - case 0x00: /* SLL */ - case 0x02: /* SRL */ - case 0x03: /* SRA */ - desc->regin[0] |= REGFLAG_R(RTREG); - desc->regout[0] |= REGFLAG_R(RDREG); - return TRUE; - - case 0x04: /* SLLV */ - case 0x06: /* SRLV */ - case 0x07: /* SRAV */ - case 0x21: /* ADDU */ - case 0x23: /* SUBU */ - case 0x24: /* AND */ - case 0x25: /* OR */ - case 0x26: /* XOR */ - case 0x27: /* NOR */ - case 0x2a: /* SLT */ - case 0x2b: /* SLTU */ - desc->regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); - desc->regout[0] |= REGFLAG_R(RDREG); - return TRUE; - - case 0x20: /* ADD */ - case 0x22: /* SUB */ - desc->regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); - desc->regout[0] |= REGFLAG_R(RDREG); - return TRUE; - - case 0x08: /* JR */ - desc->regin[0] |= REGFLAG_R(RSREG); - desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; - desc->targetpc = BRANCH_TARGET_DYNAMIC; - desc->delayslots = 1; - return TRUE; - - case 0x09: /* JALR */ - desc->regin[0] |= REGFLAG_R(RSREG); - desc->regout[0] |= REGFLAG_R(RDREG); - desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; - desc->targetpc = BRANCH_TARGET_DYNAMIC; - desc->delayslots = 1; - return TRUE; - - case 0x0d: /* BREAK */ - desc->flags |= OPFLAG_END_SEQUENCE; - desc->targetpc = BRANCH_TARGET_DYNAMIC; - return TRUE; + case 0x00: // SLL + case 0x02: // SRL + case 0x03: // SRA + desc.regin[0] |= REGFLAG_R(RTREG); + desc.regout[0] |= REGFLAG_R(RDREG); + return true; + + case 0x04: // SLLV + case 0x06: // SRLV + case 0x07: // SRAV + case 0x21: // ADDU + case 0x23: // SUBU + case 0x24: // AND + case 0x25: // OR + case 0x26: // XOR + case 0x27: // NOR + case 0x2a: // SLT + case 0x2b: // SLTU + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.regout[0] |= REGFLAG_R(RDREG); + return true; + + case 0x20: // ADD + case 0x22: // SUB + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.regout[0] |= REGFLAG_R(RDREG); + return true; + + case 0x08: // JR + desc.regin[0] |= REGFLAG_R(RSREG); + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + desc.delayslots = 1; + return true; + + case 0x09: // JALR + desc.regin[0] |= REGFLAG_R(RSREG); + desc.regout[0] |= REGFLAG_R(RDREG); + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + desc.delayslots = 1; + return true; + + case 0x0d: // BREAK + desc.flags |= OPFLAG_END_SEQUENCE; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + return true; } - return FALSE; + return false; } -/*------------------------------------------------- - describe_instruction_regimm - build a - description of a single instruction in the - 'regimm' group --------------------------------------------------*/ +//------------------------------------------------- +// describe_regimm - build a description of a +// single instruction in the 'regimm' group +//------------------------------------------------- -static int describe_instruction_regimm(rsp_state *rsp, UINT32 op, opcode_desc *desc) +bool rsp_frontend::describe_regimm(UINT32 op, opcode_desc &desc) { switch (RTREG) { - case 0x00: /* BLTZ */ - case 0x01: /* BGEZ */ + case 0x00: // BLTZ + case 0x01: // BGEZ if (RTREG == 0x01 && RSREG == 0) - desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; else { - desc->regin[0] |= REGFLAG_R(RSREG); - desc->flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + desc.regin[0] |= REGFLAG_R(RSREG); + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; } - desc->targetpc = ((desc->pc + 4 + (SIMMVAL << 2)) & 0x00000fff) | 0x1000; - desc->delayslots = 1; - desc->skipslots = (RTREG & 0x02) ? 1 : 0; - return TRUE; + desc.targetpc = ((desc.pc + 4 + (SIMMVAL << 2)) & 0x00000fff) | 0x1000; + desc.delayslots = 1; + desc.skipslots = (RTREG & 0x02) ? 1 : 0; + return true; - case 0x10: /* BLTZAL */ - case 0x11: /* BGEZAL */ + case 0x10: // BLTZAL + case 0x11: // BGEZAL if (RTREG == 0x11 && RSREG == 0) - desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; else { - desc->regin[0] |= REGFLAG_R(RSREG); - desc->flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + desc.regin[0] |= REGFLAG_R(RSREG); + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; } - desc->regout[0] |= REGFLAG_R(31); - desc->targetpc = ((desc->pc + 4 + (SIMMVAL << 2)) & 0x00000fff) | 0x1000; - desc->delayslots = 1; - desc->skipslots = (RTREG & 0x02) ? 1 : 0; - return TRUE; + desc.regout[0] |= REGFLAG_R(31); + desc.targetpc = ((desc.pc + 4 + (SIMMVAL << 2)) & 0x00000fff) | 0x1000; + desc.delayslots = 1; + desc.skipslots = (RTREG & 0x02) ? 1 : 0; + return true; } - return FALSE; + return false; } -/*------------------------------------------------- - describe_instruction_cop0 - build a - description of a single instruction in the - COP0 group --------------------------------------------------*/ +//------------------------------------------------- +// describe_cop0 - build a description of a +// single instruction in the COP0 group +//------------------------------------------------- -static int describe_instruction_cop0(rsp_state *rsp, UINT32 op, opcode_desc *desc) +bool rsp_frontend::describe_cop0(UINT32 op, opcode_desc &desc) { switch (RSREG) { - case 0x00: /* MFCz */ - desc->regout[0] |= REGFLAG_R(RTREG); - return TRUE; + case 0x00: // MFCz + desc.regout[0] |= REGFLAG_R(RTREG); + return true; - case 0x04: /* MTCz */ - desc->regin[0] |= REGFLAG_R(RTREG); - return TRUE; + case 0x04: // MTCz + desc.regin[0] |= REGFLAG_R(RTREG); + return true; } - return FALSE; + return false; } -/*------------------------------------------------- - describe_instruction_cop2 - build a - description of a single instruction in the - COP2 group --------------------------------------------------*/ +//------------------------------------------------- +// describe_cop2 - build a description of a +// single instruction in the COP2 group +//------------------------------------------------- -static int describe_instruction_cop2(rsp_state *rsp, UINT32 op, opcode_desc *desc) +bool rsp_frontend::describe_cop2(UINT32 op, opcode_desc &desc) { switch (RSREG) { - case 0x00: /* MFCz */ - case 0x02: /* CFCz */ - desc->regout[0] |= REGFLAG_R(RTREG); - return TRUE; - - case 0x04: /* MTCz */ - case 0x06: /* CTCz */ - desc->regin[0] |= REGFLAG_R(RTREG); - return TRUE; + case 0x00: // MFCz + case 0x02: // CFCz + desc.regout[0] |= REGFLAG_R(RTREG); + return true; + + case 0x04: // MTCz + case 0x06: // CTCz + desc.regin[0] |= REGFLAG_R(RTREG); + return true; } - return FALSE; + return false; } diff --git a/src/emu/cpu/rsp/rspfe.h b/src/emu/cpu/rsp/rspfe.h index 176351b8b12..b032c306b2b 100644 --- a/src/emu/cpu/rsp/rspfe.h +++ b/src/emu/cpu/rsp/rspfe.h @@ -15,20 +15,44 @@ #ifndef __RSPFE_H__ #define __RSPFE_H__ +#include "rsp.h" #include "cpu/drcfe.h" -/*************************************************************************** - CONSTANTS -***************************************************************************/ +//************************************************************************** +// CONSTANTS +//************************************************************************** -/* register flags 0 */ +// register flags 0 #define REGFLAG_R(n) (((n) == 0) ? 0 : (1 << (n))) -/*************************************************************************** - FUNCTION PROTOTYPES -***************************************************************************/ -int rspfe_describe(void *param, opcode_desc *desc, const opcode_desc *prev); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class rsp_frontend : public drc_frontend +{ +public: + // construction/destruction + rsp_frontend(rsp_state &state, UINT32 window_start, UINT32 window_end, UINT32 max_sequence); + +protected: + // required overrides + virtual bool describe(opcode_desc &desc, const opcode_desc *prev); + +private: + // internal helpers + bool describe_special(UINT32 op, opcode_desc &desc); + bool describe_regimm(UINT32 op, opcode_desc &desc); + bool describe_cop0(UINT32 op, opcode_desc &desc); + bool describe_cop2(UINT32 op, opcode_desc &desc); + + // internal state + rsp_state &m_context; +}; + + #endif /* __RSPFE_H__ */ diff --git a/src/emu/cpu/sh2/sh2comn.h b/src/emu/cpu/sh2/sh2comn.h index e70ea929ed0..cf72e90df48 100644 --- a/src/emu/cpu/sh2/sh2comn.h +++ b/src/emu/cpu/sh2/sh2comn.h @@ -21,6 +21,7 @@ #include "cpu/drcfe.h" #include "cpu/drcuml.h" #include "cpu/drcumlsh.h" +class sh2_frontend; #endif #define SH2_CODE_XOR(a) ((a) ^ NATIVE_ENDIAN_VALUE_LE_BE(2,0)) @@ -155,7 +156,7 @@ typedef struct #ifdef USE_SH2DRC drccache * cache; /* pointer to the DRC code cache */ drcuml_state * drcuml; /* DRC UML generator state */ - drcfe_state * drcfe; /* pointer to the DRC front-end state */ + sh2_frontend * drcfe; /* pointer to the DRC front-end state */ UINT32 drcoptions; /* configurable DRC options */ /* internal stuff */ @@ -184,6 +185,28 @@ typedef struct #endif } sh2_state; +#ifdef USE_SH2DRC +class sh2_frontend : public drc_frontend +{ +public: + sh2_frontend(sh2_state &state, UINT32 window_start, UINT32 window_end, UINT32 max_sequence); + +protected: + virtual bool describe(opcode_desc &desc, const opcode_desc *prev); + +private: + bool describe_group_0(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode); + bool describe_group_2(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode); + bool describe_group_3(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode); + bool describe_group_4(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode); + bool describe_group_6(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode); + bool describe_group_8(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode); + bool describe_group_12(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode); + + sh2_state &m_context; +}; +#endif + void sh2_common_init(sh2_state *sh2, legacy_cpu_device *device, device_irq_callback irqcallback); void sh2_recalc_irq(sh2_state *sh2); void sh2_set_irq_line(sh2_state *sh2, int irqline, int state); diff --git a/src/emu/cpu/sh2/sh2drc.c b/src/emu/cpu/sh2/sh2drc.c index fa1745332e2..d340426b076 100644 --- a/src/emu/cpu/sh2/sh2drc.c +++ b/src/emu/cpu/sh2/sh2drc.c @@ -674,13 +674,6 @@ static void cfunc_SUBV(void *param) static CPU_INIT( sh2 ) { - drcfe_config feconfig = - { - COMPILE_BACKWARDS_BYTES, /* code window start offset = startpc - window_start */ - COMPILE_FORWARDS_BYTES, /* code window end offset = startpc + window_end */ - COMPILE_MAX_SEQUENCE, /* maximum instructions to include in a sequence */ - sh2_describe /* callback to describe a single instruction */ - }; sh2_state *sh2 = get_safe_token(device); drccache *cache; drcbe_info beinfo; @@ -733,9 +726,7 @@ static CPU_INIT( sh2 ) drcuml_symbol_add(sh2->drcuml, &sh2->mach, sizeof(sh2->macl), "mach"); /* initialize the front-end helper */ - if (SINGLE_INSTRUCTION_MODE) - feconfig.max_sequence = 1; - sh2->drcfe = drcfe_init(device, &feconfig, sh2); + sh2->drcfe = auto_alloc(device->machine, sh2_frontend(*sh2, COMPILE_BACKWARDS_BYTES, COMPILE_FORWARDS_BYTES, SINGLE_INSTRUCTION_MODE ? 1 : COMPILE_MAX_SEQUENCE)); /* compute the register parameters */ for (regnum = 0; regnum < 16; regnum++) @@ -779,7 +770,7 @@ static CPU_EXIT( sh2 ) sh2_state *sh2 = get_safe_token(device); /* clean up the DRC */ - drcfe_exit(sh2->drcfe); + auto_free(device->machine, sh2->drcfe); drcuml_free(sh2->drcuml); drccache_free(sh2->cache); } @@ -941,7 +932,7 @@ static void code_compile_block(sh2_state *sh2, UINT8 mode, offs_t pc) g_profiler.start(PROFILER_DRC_COMPILE); /* get a description of this sequence */ - desclist = drcfe_describe_code(sh2->drcfe, pc); + desclist = sh2->drcfe->describe_code(pc); if (LOG_UML || LOG_NATIVE) log_opcode_desc(drcuml, desclist, 0); @@ -953,7 +944,7 @@ static void code_compile_block(sh2_state *sh2, UINT8 mode, offs_t pc) block = drcuml_block_begin(drcuml, 4096, &errorbuf); /* loop until we get through all instruction sequences */ - for (seqhead = desclist; seqhead != NULL; seqhead = seqlast->next) + for (seqhead = desclist; seqhead != NULL; seqhead = seqlast->next()) { const opcode_desc *curdesc; UINT32 nextpc; @@ -963,7 +954,7 @@ static void code_compile_block(sh2_state *sh2, UINT8 mode, offs_t pc) UML_COMMENT(block, "-------------------------"); // comment /* determine the last instruction in this sequence */ - for (seqlast = seqhead; seqlast != NULL; seqlast = seqlast->next) + for (seqlast = seqhead; seqlast != NULL; seqlast = seqlast->next()) if (seqlast->flags & OPFLAG_END_SEQUENCE) break; assert(seqlast != NULL); @@ -1000,7 +991,7 @@ static void code_compile_block(sh2_state *sh2, UINT8 mode, offs_t pc) } /* iterate over instructions in the sequence and compile them */ - for (curdesc = seqhead; curdesc != seqlast->next; curdesc = curdesc->next) + for (curdesc = seqhead; curdesc != seqlast->next(); curdesc = curdesc->next()) { generate_sequence_instruction(sh2, block, &compiler, curdesc, 0xffffffff); } @@ -1020,7 +1011,7 @@ static void code_compile_block(sh2_state *sh2, UINT8 mode, offs_t pc) generate_update_cycles(sh2, block, &compiler, IMM(nextpc), TRUE); // <subtract cycles> /* SH2 has no modes */ - if (seqlast->next == NULL || seqlast->next->pc != nextpc) + if (seqlast->next() == NULL || seqlast->next()->pc != nextpc) { UML_HASHJMP(block, IMM(0), IMM(nextpc), sh2->nocode); } @@ -1390,7 +1381,7 @@ static void log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, i drcuml_log_printf(drcuml, "\nDescriptor list @ %08X\n", desclist->pc); /* output each descriptor */ - for ( ; desclist != NULL; desclist = desclist->next) + for ( ; desclist != NULL; desclist = desclist->next()) { char buffer[100]; @@ -1411,8 +1402,8 @@ static void log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, i drcuml_log_printf(drcuml, "\n"); /* if we have a delay slot, output it recursively */ - if (desclist->delay != NULL) - log_opcode_desc(drcuml, desclist->delay, indent + 1); + if (desclist->delay.first() != NULL) + log_opcode_desc(drcuml, desclist->delay.first(), indent + 1); /* at the end of a sequence add a dividing line */ if (desclist->flags & OPFLAG_END_SEQUENCE) @@ -1524,7 +1515,7 @@ static void generate_checksum_block(sh2_state *sh2, drcuml_block *block, compile UML_COMMENT(block, "[Validation for %08X]", seqhead->pc); // comment /* loose verify or single instruction: just compare and fail */ - if (!(sh2->drcoptions & SH2DRC_STRICT_VERIFY) || seqhead->next == NULL) + if (!(sh2->drcoptions & SH2DRC_STRICT_VERIFY) || seqhead->next() == NULL) { if (!(seqhead->flags & OPFLAG_VIRTUAL_NOOP)) { @@ -1539,7 +1530,7 @@ static void generate_checksum_block(sh2_state *sh2, drcuml_block *block, compile else { #if 0 - for (curdesc = seqhead->next; curdesc != seqlast->next; curdesc = curdesc->next) + for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next()) if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP)) { base = sh2->direct->read_decrypted_ptr(curdesc->physpc, SH2_CODE_XOR(0)); @@ -1552,7 +1543,7 @@ static void generate_checksum_block(sh2_state *sh2, drcuml_block *block, compile void *base = sh2->direct->read_decrypted_ptr(seqhead->physpc, SH2_CODE_XOR(0)); UML_LOAD(block, IREG(0), base, IMM(0), WORD); // load i0,base,word sum += seqhead->opptr.w[0]; - for (curdesc = seqhead->next; curdesc != seqlast->next; curdesc = curdesc->next) + for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next()) if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP)) { base = sh2->direct->read_decrypted_ptr(curdesc->physpc, SH2_CODE_XOR(0)); @@ -1662,7 +1653,7 @@ static void generate_delay_slot(sh2_state *sh2, drcuml_block *block, compiler_st /* compile the delay slot using temporary compiler state */ assert(desc->delay != NULL); - generate_sequence_instruction(sh2, block, &compiler_temp, desc->delay, ovrpc); // <next instruction> + generate_sequence_instruction(sh2, block, &compiler_temp, desc->delay.first(), ovrpc); // <next instruction> /* update the label */ compiler->labelnum = compiler_temp.labelnum; diff --git a/src/emu/cpu/sh2/sh2fe.c b/src/emu/cpu/sh2/sh2fe.c index f4c18d61eea..fa02e66b7af 100644 --- a/src/emu/cpu/sh2/sh2fe.c +++ b/src/emu/cpu/sh2/sh2fe.c @@ -14,116 +14,108 @@ #include "sh2comn.h" #include "cpu/drcfe.h" -/*************************************************************************** - FUNCTION PROTOTYPES -***************************************************************************/ - -static int describe_group_0(sh2_state *context, opcode_desc *desc, const opcode_desc *prev, UINT16 opcode); -static int describe_group_2(sh2_state *context, opcode_desc *desc, const opcode_desc *prev, UINT16 opcode); -static int describe_group_3(sh2_state *context, opcode_desc *desc, const opcode_desc *prev, UINT16 opcode); -static int describe_group_4(sh2_state *context, opcode_desc *desc, const opcode_desc *prev, UINT16 opcode); -static int describe_group_6(sh2_state *context, opcode_desc *desc, const opcode_desc *prev, UINT16 opcode); -static int describe_group_8(sh2_state *context, opcode_desc *desc, const opcode_desc *prev, UINT16 opcode); -static int describe_group_12(sh2_state *context, opcode_desc *desc, const opcode_desc *prev, UINT16 opcode); - - /*************************************************************************** INSTRUCTION PARSERS ***************************************************************************/ +sh2_frontend::sh2_frontend(sh2_state &state, UINT32 window_start, UINT32 window_end, UINT32 max_sequence) + : drc_frontend(*state.device, window_start, window_end, max_sequence), + m_context(state) +{ +} + /*------------------------------------------------- describe_instruction - build a description of a single instruction -------------------------------------------------*/ -int sh2_describe(void *param, opcode_desc *desc, const opcode_desc *prev) +bool sh2_frontend::describe(opcode_desc &desc, const opcode_desc *prev) { - sh2_state *context = (sh2_state *)param; UINT16 opcode; /* fetch the opcode */ - opcode = desc->opptr.w[0] = context->direct->read_decrypted_word(desc->physpc, SH2_CODE_XOR(0)); + opcode = desc.opptr.w[0] = m_context.direct->read_decrypted_word(desc.physpc, SH2_CODE_XOR(0)); /* all instructions are 2 bytes and most are a single cycle */ - desc->length = 2; - desc->cycles = 1; + desc.length = 2; + desc.cycles = 1; switch (opcode>>12) { case 0: - return describe_group_0(context, desc, prev, opcode); + return describe_group_0(desc, prev, opcode); case 1: // MOVLS4 - desc->regin[0] |= REGFLAG_R(Rn) | REGFLAG_R(Rm); - desc->flags |= OPFLAG_WRITES_MEMORY; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rn) | REGFLAG_R(Rm); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; case 2: - return describe_group_2(context, desc, prev, opcode); + return describe_group_2(desc, prev, opcode); case 3: - return describe_group_3(context, desc, prev, opcode); + return describe_group_3(desc, prev, opcode); case 4: - return describe_group_4(context, desc, prev, opcode); + return describe_group_4(desc, prev, opcode); case 5: // MOVLL4 - desc->regin[0] |= REGFLAG_R(Rm); - desc->regout[0] |= REGFLAG_R(Rn); - desc->flags |= OPFLAG_READS_MEMORY; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rm); + desc.regout[0] |= REGFLAG_R(Rn); + desc.flags |= OPFLAG_READS_MEMORY; + return true; case 6: - return describe_group_6(context, desc, prev, opcode); + return describe_group_6(desc, prev, opcode); case 7: // ADDI - desc->regin[0] |= REGFLAG_R(Rn); - desc->regout[0] |= REGFLAG_R(Rn); - return TRUE; + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + return true; case 8: - return describe_group_8(context, desc, prev, opcode); + return describe_group_8(desc, prev, opcode); case 9: // MOVWI - desc->regout[0] |= REGFLAG_R(Rn); - desc->flags |= OPFLAG_READS_MEMORY; - return TRUE; + desc.regout[0] |= REGFLAG_R(Rn); + desc.flags |= OPFLAG_READS_MEMORY; + return true; case 11: // BSR - desc->regout[1] |= REGFLAG_PR; + desc.regout[1] |= REGFLAG_PR; // (intentional fallthrough - BSR is BRA with the addition of PR = the return address) case 10: // BRA { INT32 disp = ((INT32)opcode << 20) >> 20; - desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; - desc->targetpc = (desc->pc + 2) + disp * 2 + 2; - desc->delayslots = 1; - desc->cycles = 2; - return TRUE; + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = (desc.pc + 2) + disp * 2 + 2; + desc.delayslots = 1; + desc.cycles = 2; + return true; } case 12: - return describe_group_12(context, desc, prev, opcode); + return describe_group_12(desc, prev, opcode); case 13: // MOVLI - desc->regout[0] |= REGFLAG_R(Rn); - desc->flags |= OPFLAG_READS_MEMORY; - return TRUE; + desc.regout[0] |= REGFLAG_R(Rn); + desc.flags |= OPFLAG_READS_MEMORY; + return true; case 14: // MOVI - desc->regout[0] |= REGFLAG_R(Rn); - return TRUE; + desc.regout[0] |= REGFLAG_R(Rn); + return true; case 15: // NOP - return TRUE; + return true; } - return FALSE; + return false; } -static int describe_group_0(sh2_state *context, opcode_desc *desc, const opcode_desc *prev, UINT16 opcode) +bool sh2_frontend::describe_group_0(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode) { switch (opcode & 0x3F) { @@ -143,20 +135,20 @@ static int describe_group_0(sh2_state *context, opcode_desc *desc, const opcode_ case 0x39: // NOP(); case 0x3a: // NOP(); case 0x3b: // NOP(); - return TRUE; + return true; case 0x02: // STCSR(Rn); - desc->regout[0] |= REGFLAG_R(Rn); - return TRUE; + desc.regout[0] |= REGFLAG_R(Rn); + return true; case 0x03: // BSRF(Rn); - desc->regout[1] |= REGFLAG_PR; + desc.regout[1] |= REGFLAG_PR; - desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; - desc->targetpc = BRANCH_TARGET_DYNAMIC; - desc->delayslots = 1; + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + desc.delayslots = 1; - return TRUE; + return true; case 0x04: // MOVBS0(Rm, Rn); case 0x05: // MOVWS0(Rm, Rn); @@ -170,37 +162,37 @@ static int describe_group_0(sh2_state *context, opcode_desc *desc, const opcode_ case 0x34: // MOVBS0(Rm, Rn); case 0x35: // MOVWS0(Rm, Rn); case 0x36: // MOVLS0(Rm, Rn); - desc->regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn) | REGFLAG_R(0); - desc->flags |= OPFLAG_READS_MEMORY; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn) | REGFLAG_R(0); + desc.flags |= OPFLAG_READS_MEMORY; + return true; case 0x07: // MULL(Rm, Rn); case 0x17: // MULL(Rm, Rn); case 0x27: // MULL(Rm, Rn); case 0x37: // MULL(Rm, Rn); - desc->regin[0] |= REGFLAG_R(Rn) | REGFLAG_R(Rm); - desc->regout[1] |= REGFLAG_MACL; - desc->cycles = 2; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rn) | REGFLAG_R(Rm); + desc.regout[1] |= REGFLAG_MACL; + desc.cycles = 2; + return true; case 0x08: // CLRT(); - desc->regout[1] |= REGFLAG_SR; - return TRUE; + desc.regout[1] |= REGFLAG_SR; + return true; case 0x0a: // STSMACH(Rn); - desc->regout[0] |= REGFLAG_R(Rn); - desc->regout[1] |= REGFLAG_MACH; - return TRUE; + desc.regout[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_MACH; + return true; case 0x0b: // RTS(); - desc->regin[1] |= REGFLAG_PR; + desc.regin[1] |= REGFLAG_PR; - desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; - desc->targetpc = BRANCH_TARGET_DYNAMIC; - desc->delayslots = 1; - desc->cycles = 2; + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + desc.delayslots = 1; + desc.cycles = 2; - return TRUE; + return true; case 0x0c: // MOVBL0(Rm, Rn); case 0x0d: // MOVWL0(Rm, Rn); @@ -214,133 +206,133 @@ static int describe_group_0(sh2_state *context, opcode_desc *desc, const opcode_ case 0x3c: // MOVBL0(Rm, Rn); case 0x3d: // MOVWL0(Rm, Rn); case 0x3e: // MOVLL0(Rm, Rn); - desc->regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(0); - desc->regout[0] |= REGFLAG_R(Rn); - desc->flags |= OPFLAG_READS_MEMORY; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(0); + desc.regout[0] |= REGFLAG_R(Rn); + desc.flags |= OPFLAG_READS_MEMORY; + return true; case 0x0f: // MAC_L(Rm, Rn); case 0x1f: // MAC_L(Rm, Rn); case 0x2f: // MAC_L(Rm, Rn); case 0x3f: // MAC_L(Rm, Rn); - desc->regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); - desc->regout[1] |= REGFLAG_MACL | REGFLAG_MACH; - desc->cycles = 3; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_MACL | REGFLAG_MACH; + desc.cycles = 3; + return true; case 0x12: // STCGBR(Rn); - desc->regout[0] |= REGFLAG_R(Rn); - desc->regin[1] |= REGFLAG_GBR; - return TRUE; + desc.regout[0] |= REGFLAG_R(Rn); + desc.regin[1] |= REGFLAG_GBR; + return true; case 0x18: // SETT(); - desc->regout[1] |= REGFLAG_SR; - return TRUE; + desc.regout[1] |= REGFLAG_SR; + return true; case 0x19: // DIV0U(); - desc->regout[1] |= REGFLAG_SR; - return TRUE; + desc.regout[1] |= REGFLAG_SR; + return true; case 0x1a: // STSMACL(Rn); - desc->regin[1] |= REGFLAG_MACL; - desc->regout[0] |= REGFLAG_R(Rn); - return TRUE; + desc.regin[1] |= REGFLAG_MACL; + desc.regout[0] |= REGFLAG_R(Rn); + return true; case 0x1b: // SLEEP(); - desc->cycles = 3; - return TRUE; + desc.cycles = 3; + return true; case 0x22: // STCVBR(Rn); - desc->regin[0] |= REGFLAG_R(Rn); - desc->regout[1] |= REGFLAG_VBR; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_VBR; + return true; case 0x23: // BRAF(Rn); - desc->regin[0] |= REGFLAG_R(Rm); - desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; - desc->targetpc = BRANCH_TARGET_DYNAMIC; - desc->delayslots = 1; - desc->cycles = 2; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rm); + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + desc.delayslots = 1; + desc.cycles = 2; + return true; case 0x28: // CLRMAC(); - desc->regout[1] |= REGFLAG_MACL | REGFLAG_MACH; - return TRUE; + desc.regout[1] |= REGFLAG_MACL | REGFLAG_MACH; + return true; case 0x29: // MOVT(Rn); - desc->regin[1] |= REGFLAG_SR; - desc->regout[0] |= REGFLAG_R(Rn); - return TRUE; + desc.regin[1] |= REGFLAG_SR; + desc.regout[0] |= REGFLAG_R(Rn); + return true; case 0x2a: // STSPR(Rn); - desc->regin[1] |= REGFLAG_PR; - desc->regout[0] |= REGFLAG_R(Rn); - return TRUE; + desc.regin[1] |= REGFLAG_PR; + desc.regout[0] |= REGFLAG_R(Rn); + return true; case 0x2b: // RTE(); - desc->regin[0] |= REGFLAG_R(15); - desc->regout[0] |= REGFLAG_R(15); + desc.regin[0] |= REGFLAG_R(15); + desc.regout[0] |= REGFLAG_R(15); - desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE | OPFLAG_CAN_EXPOSE_EXTERNAL_INT; - desc->targetpc = BRANCH_TARGET_DYNAMIC; - desc->delayslots = 1; - desc->cycles = 4; + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE | OPFLAG_CAN_EXPOSE_EXTERNAL_INT; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + desc.delayslots = 1; + desc.cycles = 4; - return TRUE; + return true; } - return FALSE; + return false; } -static int describe_group_2(sh2_state *context, opcode_desc *desc, const opcode_desc *prev, UINT16 opcode) +bool sh2_frontend::describe_group_2(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode) { switch (opcode & 15) { case 0: // MOVBS(Rm, Rn); case 1: // MOVWS(Rm, Rn); case 2: // MOVLS(Rm, Rn); - desc->regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); - desc->flags |= OPFLAG_WRITES_MEMORY; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; case 3: // NOP(); - return TRUE; + return true; case 4: // MOVBM(Rm, Rn); case 5: // MOVWM(Rm, Rn); case 6: // MOVLM(Rm, Rn); case 13: // XTRCT(Rm, Rn); - desc->regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); - desc->regout[0] |= REGFLAG_R(Rn); - desc->flags |= OPFLAG_WRITES_MEMORY; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; case 7: // DIV0S(Rm, Rn); case 8: // TST(Rm, Rn); case 12: // CMPSTR(Rm, Rn); - desc->regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); - desc->regout[1] |= REGFLAG_SR; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_SR; + return true; case 9: // AND(Rm, Rn); case 10: // XOR(Rm, Rn); case 11: // OR(Rm, Rn); - desc->regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); - desc->regout[0] |= REGFLAG_R(Rn); - return TRUE; + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + return true; case 14: // MULU(Rm, Rn); case 15: // MULS(Rm, Rn); - desc->regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); - desc->regout[1] |= REGFLAG_MACL | REGFLAG_MACH; - desc->cycles = 2; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_MACL | REGFLAG_MACH; + desc.cycles = 2; + return true; } - return FALSE; + return false; } -static int describe_group_3(sh2_state *context, opcode_desc *desc, const opcode_desc *prev, UINT16 opcode) +bool sh2_frontend::describe_group_3(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode) { switch (opcode & 15) { @@ -349,47 +341,47 @@ static int describe_group_3(sh2_state *context, opcode_desc *desc, const opcode_ case 3: // CMPGE(Rm, Rn); case 6: // CMPHI(Rm, Rn); case 7: // CMPGT(Rm, Rn); - desc->regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); - desc->regout[1] |= REGFLAG_SR; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_SR; + return true; case 1: // NOP(); case 9: // NOP(); - return TRUE; + return true; case 4: // DIV1(Rm, Rn); - desc->regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); - desc->regout[0] |= REGFLAG_R(Rn); - desc->regout[1] |= REGFLAG_SR; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_SR; + return true; case 5: // DMULU(Rm, Rn); case 13: // DMULS(Rm, Rn); - desc->regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); - desc->regout[1] |= REGFLAG_MACL | REGFLAG_MACH; - desc->cycles = 2; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_MACL | REGFLAG_MACH; + desc.cycles = 2; + return true; case 8: // SUB(Rm, Rn); case 12: // ADD(Rm, Rn); - desc->regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); - desc->regout[0] |= REGFLAG_R(Rn); - return TRUE; + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + return true; case 10: // SUBC(Rm, Rn); case 11: // SUBV(Rm, Rn); case 14: // ADDC(Rm, Rn); case 15: // ADDV(Rm, Rn); - desc->regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); - desc->regin[1] |= REGFLAG_SR; - desc->regout[0] |= REGFLAG_R(Rn); - desc->regout[1] |= REGFLAG_SR; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regin[1] |= REGFLAG_SR; + desc.regout[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_SR; + return true; } - return FALSE; + return false; } -static int describe_group_4(sh2_state *context, opcode_desc *desc, const opcode_desc *prev, UINT16 opcode) +bool sh2_frontend::describe_group_4(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode) { switch (opcode & 0x3F) { @@ -397,39 +389,39 @@ static int describe_group_4(sh2_state *context, opcode_desc *desc, const opcode_ case 0x01: // SHLR(Rn); case 0x04: // ROTL(Rn); case 0x05: // ROTR(Rn); - desc->regin[0] |= REGFLAG_R(Rn); - desc->regout[0] |= REGFLAG_R(Rn); - desc->regout[1] |= REGFLAG_SR; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_SR; + return true; case 0x02: // STSMMACH(Rn); - desc->regin[0] |= REGFLAG_R(Rn); - desc->regin[1] |= REGFLAG_MACH; - desc->regout[0] |= REGFLAG_R(Rn); - desc->flags |= OPFLAG_WRITES_MEMORY; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rn); + desc.regin[1] |= REGFLAG_MACH; + desc.regout[0] |= REGFLAG_R(Rn); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; case 0x03: // STCMSR(Rn); - desc->regin[0] |= REGFLAG_R(Rn); - desc->regout[0] |= REGFLAG_R(Rn); - desc->cycles = 2; - desc->flags |= OPFLAG_WRITES_MEMORY; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + desc.cycles = 2; + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; case 0x06: // LDSMMACH(Rn); - desc->regin[0] |= REGFLAG_R(Rn); - desc->regout[0] |= REGFLAG_R(Rn); - desc->regout[1] |= REGFLAG_MACH; - desc->flags |= OPFLAG_READS_MEMORY; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_MACH; + desc.flags |= OPFLAG_READS_MEMORY; + return true; case 0x07: // LDCMSR(Rn); - desc->regin[0] |= REGFLAG_R(Rn); - desc->regout[0] |= REGFLAG_R(Rn); - desc->regout[1] |= REGFLAG_SR; - desc->cycles = 3; - desc->flags |= OPFLAG_READS_MEMORY | OPFLAG_CAN_EXPOSE_EXTERNAL_INT | OPFLAG_END_SEQUENCE; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_SR; + desc.cycles = 3; + desc.flags |= OPFLAG_READS_MEMORY | OPFLAG_CAN_EXPOSE_EXTERNAL_INT | OPFLAG_END_SEQUENCE; + return true; case 0x08: // SHLL2(Rn); case 0x09: // SHLR2(Rn); @@ -437,159 +429,159 @@ static int describe_group_4(sh2_state *context, opcode_desc *desc, const opcode_ case 0x19: // SHLR8(Rn); case 0x28: // SHLL16(Rn); case 0x29: // SHLR16(Rn); - desc->regin[0] |= REGFLAG_R(Rn); - desc->regout[0] |= REGFLAG_R(Rn); - return TRUE; + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + return true; case 0x0a: // LDSMACH(Rn); - desc->regin[0] |= REGFLAG_R(Rn); - desc->regout[1] |= REGFLAG_MACH; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_MACH; + return true; case 0x0b: // JSR(Rn); - desc->regin[0] |= REGFLAG_R(Rn); - desc->regout[1] |= REGFLAG_PR; - desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; - desc->targetpc = BRANCH_TARGET_DYNAMIC; - desc->delayslots = 1; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_PR; + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + desc.delayslots = 1; + return true; case 0x0e: // LDCSR(Rn); - desc->regin[0] |= REGFLAG_R(Rn); - desc->regout[1] |= REGFLAG_SR; - desc->flags |= OPFLAG_CAN_EXPOSE_EXTERNAL_INT | OPFLAG_END_SEQUENCE; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_SR; + desc.flags |= OPFLAG_CAN_EXPOSE_EXTERNAL_INT | OPFLAG_END_SEQUENCE; + return true; case 0x0f: // MAC_W(Rm, Rn); case 0x1f: // MAC_W(Rm, Rn); case 0x2f: // MAC_W(Rm, Rn); case 0x3f: // MAC_W(Rm, Rn); - desc->regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); - desc->regin[1] |= REGFLAG_MACL | REGFLAG_MACH; - desc->regout[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); - desc->regout[1] |= REGFLAG_MACL | REGFLAG_MACH; - desc->cycles = 3; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regin[1] |= REGFLAG_MACL | REGFLAG_MACH; + desc.regout[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_MACL | REGFLAG_MACH; + desc.cycles = 3; + return true; case 0x10: // DT(Rn); - desc->regin[0] |= REGFLAG_R(Rn); - desc->regin[1] |= REGFLAG_SR; - desc->regout[0] |= REGFLAG_R(Rn); - desc->regout[1] |= REGFLAG_SR; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rn); + desc.regin[1] |= REGFLAG_SR; + desc.regout[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_SR; + return true; case 0x11: // CMPPZ(Rn); case 0x15: // CMPPL(Rn); - desc->regin[0] |= REGFLAG_R(Rn); - desc->regin[1] |= REGFLAG_SR; - desc->regout[1] |= REGFLAG_SR; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rn); + desc.regin[1] |= REGFLAG_SR; + desc.regout[1] |= REGFLAG_SR; + return true; case 0x12: // STSMMACL(Rn); - desc->regin[0] |= REGFLAG_R(Rn); - desc->regin[1] |= REGFLAG_MACL; - desc->regout[0] |= REGFLAG_R(Rn); - desc->flags |= OPFLAG_WRITES_MEMORY; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rn); + desc.regin[1] |= REGFLAG_MACL; + desc.regout[0] |= REGFLAG_R(Rn); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; case 0x13: // STCMGBR(Rn); - desc->regin[0] |= REGFLAG_R(Rn); - desc->regin[1] |= REGFLAG_GBR; - desc->regout[0] |= REGFLAG_R(Rn); - desc->flags |= OPFLAG_WRITES_MEMORY; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rn); + desc.regin[1] |= REGFLAG_GBR; + desc.regout[0] |= REGFLAG_R(Rn); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; case 0x16: // LDSMMACL(Rn); - desc->regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); - desc->regout[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); - desc->regout[1] |= REGFLAG_MACL; - desc->flags |= OPFLAG_READS_MEMORY; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_MACL; + desc.flags |= OPFLAG_READS_MEMORY; + return true; case 0x17: // LDCMGBR(Rn); - desc->regin[0] |= REGFLAG_R(Rn); - desc->regout[0] |= REGFLAG_R(Rn); - desc->regout[1] |= REGFLAG_GBR; - desc->flags |= OPFLAG_READS_MEMORY; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_GBR; + desc.flags |= OPFLAG_READS_MEMORY; + return true; case 0x1a: // LDSMACL(Rn); - desc->regin[0] |= REGFLAG_R(Rn); - desc->regout[1] |= REGFLAG_MACL; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_MACL; + return true; case 0x1b: // TAS(Rn); - desc->regin[0] |= REGFLAG_R(Rn); - desc->regin[1] |= REGFLAG_SR; - desc->regout[1] |= REGFLAG_SR; - desc->cycles = 4; - desc->flags |= OPFLAG_READS_MEMORY | OPFLAG_WRITES_MEMORY; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rn); + desc.regin[1] |= REGFLAG_SR; + desc.regout[1] |= REGFLAG_SR; + desc.cycles = 4; + desc.flags |= OPFLAG_READS_MEMORY | OPFLAG_WRITES_MEMORY; + return true; case 0x1e: // LDCGBR(Rn); - desc->regin[0] |= REGFLAG_R(Rn); - desc->regout[1] |= REGFLAG_GBR; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_GBR; + return true; case 0x20: // SHAL(Rn); case 0x21: // SHAR(Rn); - desc->regin[0] |= REGFLAG_R(Rn); - desc->regout[0] |= REGFLAG_R(Rn); - desc->regout[1] |= REGFLAG_SR; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_SR; + return true; case 0x22: // STSMPR(Rn); - desc->regin[0] |= REGFLAG_R(Rn); - desc->regin[1] |= REGFLAG_PR; - desc->regout[0] |= REGFLAG_R(Rn); - desc->flags |= OPFLAG_WRITES_MEMORY; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rn); + desc.regin[1] |= REGFLAG_PR; + desc.regout[0] |= REGFLAG_R(Rn); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; case 0x23: // STCMVBR(Rn); - desc->regin[0] |= REGFLAG_R(Rn); - desc->regin[1] |= REGFLAG_VBR; - desc->regout[0] |= REGFLAG_R(Rn); - desc->flags |= OPFLAG_WRITES_MEMORY; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rn); + desc.regin[1] |= REGFLAG_VBR; + desc.regout[0] |= REGFLAG_R(Rn); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; case 0x24: // ROTCL(Rn); case 0x25: // ROTCR(Rn); - desc->regin[0] |= REGFLAG_R(Rn); - desc->regin[1] |= REGFLAG_SR; - desc->regout[0] |= REGFLAG_R(Rn); - desc->regout[1] |= REGFLAG_SR; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rn); + desc.regin[1] |= REGFLAG_SR; + desc.regout[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_SR; + return true; case 0x26: // LDSMPR(Rn); - desc->regin[0] |= REGFLAG_R(Rn); - desc->regout[0] |= REGFLAG_R(Rn); - desc->regout[1] |= REGFLAG_PR; - desc->flags |= OPFLAG_READS_MEMORY; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_PR; + desc.flags |= OPFLAG_READS_MEMORY; + return true; case 0x27: // LDCMVBR(Rn); - desc->regin[0] |= REGFLAG_R(Rn); - desc->regout[0] |= REGFLAG_R(Rn); - desc->regout[1] |= REGFLAG_VBR; - desc->flags |= OPFLAG_READS_MEMORY; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_VBR; + desc.flags |= OPFLAG_READS_MEMORY; + return true; case 0x2a: // LDSPR(Rn); - desc->regin[0] |= REGFLAG_R(Rn); - desc->regout[1] |= REGFLAG_PR; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_PR; + return true; case 0x2b: // JMP(Rm); - desc->regin[0] |= REGFLAG_R(Rm); - desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; - desc->targetpc = BRANCH_TARGET_DYNAMIC; - desc->delayslots = 1; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rm); + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + desc.delayslots = 1; + return true; case 0x2e: // LDCVBR(Rn); - desc->regin[0] |= REGFLAG_R(Rn); - desc->regout[1] |= REGFLAG_VBR; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_VBR; + return true; case 0x0c: // NOP(); case 0x0d: // NOP(); @@ -613,13 +605,13 @@ static int describe_group_4(sh2_state *context, opcode_desc *desc, const opcode_ case 0x3c: // NOP(); case 0x3d: // NOP(); case 0x3e: // NOP(); - return TRUE; + return true; } - return FALSE; + return false; } -static int describe_group_6(sh2_state *context, opcode_desc *desc, const opcode_desc *prev, UINT16 opcode) +bool sh2_frontend::describe_group_6(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode) { switch (opcode & 15) { @@ -634,33 +626,33 @@ static int describe_group_6(sh2_state *context, opcode_desc *desc, const opcode_ case 13: // EXTUW(Rm, Rn); case 14: // EXTSB(Rm, Rn); case 15: // EXTSW(Rm, Rn); - desc->regin[0] |= REGFLAG_R(Rm); - desc->regout[0] |= REGFLAG_R(Rn); - return TRUE; + desc.regin[0] |= REGFLAG_R(Rm); + desc.regout[0] |= REGFLAG_R(Rn); + return true; case 4: // MOVBP(Rm, Rn); case 5: // MOVWP(Rm, Rn); case 6: // MOVLP(Rm, Rn); - desc->regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); - desc->regout[0] |= REGFLAG_R(Rn); - desc->flags |= OPFLAG_READS_MEMORY; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + desc.flags |= OPFLAG_READS_MEMORY; + return true; case 8: // SWAPB(Rm, Rn); - desc->regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); - desc->regout[0] |= REGFLAG_R(Rn); - return TRUE; + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + return true; case 10: // NEGC(Rm, Rn); - desc->regin[0] |= REGFLAG_R(Rm); - desc->regout[0] |= REGFLAG_R(Rn); - desc->regout[1] |= REGFLAG_SR; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rm); + desc.regout[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_SR; + return true; } - return FALSE; + return false; } -static int describe_group_8(sh2_state *context, opcode_desc *desc, const opcode_desc *prev, UINT16 opcode) +bool sh2_frontend::describe_group_8(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode) { INT32 disp; @@ -668,9 +660,9 @@ static int describe_group_8(sh2_state *context, opcode_desc *desc, const opcode_ { case 0 << 8: // MOVBS4(opcode & 0x0f, Rm); case 1 << 8: // MOVWS4(opcode & 0x0f, Rm); - desc->regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(0); - desc->flags |= OPFLAG_WRITES_MEMORY; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(0); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; case 2<< 8: // NOP(); case 3<< 8: // NOP(); @@ -679,94 +671,94 @@ static int describe_group_8(sh2_state *context, opcode_desc *desc, const opcode_ case 10<< 8: // NOP(); case 12<< 8: // NOP(); case 14<< 8: // NOP(); - return TRUE; + return true; case 4<< 8: // MOVBL4(Rm, opcode & 0x0f); case 5<< 8: // MOVWL4(Rm, opcode & 0x0f); - desc->regin[0] |= REGFLAG_R(Rm); - desc->regout[0] |= REGFLAG_R(0); - desc->flags |= OPFLAG_READS_MEMORY; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rm); + desc.regout[0] |= REGFLAG_R(0); + desc.flags |= OPFLAG_READS_MEMORY; + return true; case 8<< 8: // CMPIM(opcode & 0xff); - desc->regin[0] |= REGFLAG_R(Rm); - desc->regin[1] |= REGFLAG_SR; - desc->regout[1] |= REGFLAG_SR; - return TRUE; + desc.regin[0] |= REGFLAG_R(Rm); + desc.regin[1] |= REGFLAG_SR; + desc.regout[1] |= REGFLAG_SR; + return true; case 9<< 8: // BT(opcode & 0xff); case 11<< 8: // BF(opcode & 0xff); - desc->flags |= OPFLAG_IS_CONDITIONAL_BRANCH; - desc->cycles = 3; + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + desc.cycles = 3; disp = ((INT32)opcode << 24) >> 24; - desc->targetpc = (desc->pc + 2) + disp * 2 + 2; - return TRUE; + desc.targetpc = (desc.pc + 2) + disp * 2 + 2; + return true; case 13<< 8: // BTS(opcode & 0xff); case 15<< 8: // BFS(opcode & 0xff); - desc->flags |= OPFLAG_IS_CONDITIONAL_BRANCH; - desc->cycles = 2; + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + desc.cycles = 2; disp = ((INT32)opcode << 24) >> 24; - desc->targetpc = (desc->pc + 2) + disp * 2 + 2; - desc->delayslots = 1; - return TRUE; + desc.targetpc = (desc.pc + 2) + disp * 2 + 2; + desc.delayslots = 1; + return true; } - return FALSE; + return false; } -static int describe_group_12(sh2_state *context, opcode_desc *desc, const opcode_desc *prev, UINT16 opcode) +bool sh2_frontend::describe_group_12(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode) { switch (opcode & (15<<8)) { case 0<<8: // MOVBSG(opcode & 0xff); case 1<<8: // MOVWSG(opcode & 0xff); case 2<<8: // MOVLSG(opcode & 0xff); - desc->regin[0] |= REGFLAG_R(0); - desc->flags |= OPFLAG_WRITES_MEMORY; - return TRUE; + desc.regin[0] |= REGFLAG_R(0); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; case 3<<8: // TRAPA(opcode & 0xff); - desc->regin[0] |= REGFLAG_R(15); - desc->regin[1] |= REGFLAG_VBR; - desc->regout[0] |= REGFLAG_R(15); - desc->cycles = 8; - desc->targetpc = BRANCH_TARGET_DYNAMIC; - desc->flags |= OPFLAG_READS_MEMORY | OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; - return TRUE; + desc.regin[0] |= REGFLAG_R(15); + desc.regin[1] |= REGFLAG_VBR; + desc.regout[0] |= REGFLAG_R(15); + desc.cycles = 8; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + desc.flags |= OPFLAG_READS_MEMORY | OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + return true; case 4<<8: // MOVBLG(opcode & 0xff); case 5<<8: // MOVWLG(opcode & 0xff); case 6<<8: // MOVLLG(opcode & 0xff); case 7<<8: // MOVA(opcode & 0xff); - desc->regout[0] |= REGFLAG_R(0); - desc->flags |= OPFLAG_READS_MEMORY; - return TRUE; + desc.regout[0] |= REGFLAG_R(0); + desc.flags |= OPFLAG_READS_MEMORY; + return true; case 8<<8: // TSTI(opcode & 0xff); - desc->regin[0] |= REGFLAG_R(0); - desc->regin[1] |= REGFLAG_SR; - desc->regout[1] |= REGFLAG_SR; - return TRUE; + desc.regin[0] |= REGFLAG_R(0); + desc.regin[1] |= REGFLAG_SR; + desc.regout[1] |= REGFLAG_SR; + return true; case 9<<8: // ANDI(opcode & 0xff); case 10<<8: // XORI(opcode & 0xff); case 11<<8: // ORI(opcode & 0xff); - desc->regin[0] |= REGFLAG_R(0); - desc->regout[0] |= REGFLAG_R(0); - return TRUE; + desc.regin[0] |= REGFLAG_R(0); + desc.regout[0] |= REGFLAG_R(0); + return true; case 12<<8: // TSTM(opcode & 0xff); case 13<<8: // ANDM(opcode & 0xff); case 14<<8: // XORM(opcode & 0xff); case 15<<8: // ORM(opcode & 0xff); - desc->regin[0] |= REGFLAG_R(0); - desc->regin[1] |= REGFLAG_SR | REGFLAG_GBR; - desc->regout[1] |= REGFLAG_SR; - desc->flags |= OPFLAG_READS_MEMORY; - return TRUE; + desc.regin[0] |= REGFLAG_R(0); + desc.regin[1] |= REGFLAG_SR | REGFLAG_GBR; + desc.regout[1] |= REGFLAG_SR; + desc.flags |= OPFLAG_READS_MEMORY; + return true; } - return FALSE; + return false; } |