summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/rsp/rspdrc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/rsp/rspdrc.cpp')
-rw-r--r--src/devices/cpu/rsp/rspdrc.cpp1279
1 files changed, 0 insertions, 1279 deletions
diff --git a/src/devices/cpu/rsp/rspdrc.cpp b/src/devices/cpu/rsp/rspdrc.cpp
deleted file mode 100644
index d2e89b4a77a..00000000000
--- a/src/devices/cpu/rsp/rspdrc.cpp
+++ /dev/null
@@ -1,1279 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Ryan Holtz
-/***************************************************************************
-
- rspdrc.c
-
- Universal machine language-based Nintendo/SGI RSP emulator.
- Written by Ryan Holtz
- SIMD versions of vector multiplication opcodes provided by Marathon Man
- of the CEN64 team.
-
-****************************************************************************
-
- Future improvements/changes:
-
- * Confer with Aaron Giles about adding a memory hash-based caching
- system and static recompilation for maximum overhead minimization
-
-***************************************************************************/
-
-#include "emu.h"
-#include "rsp.h"
-#include "rsp_dasm.h"
-
-#include "rspfe.h"
-#include "rspcp2.h"
-#include "cpu/drcfe.h"
-#include "cpu/drcuml.h"
-#include "cpu/drcumlsh.h"
-
-#include "debugger.h"
-
-#include "rspdefs.h"
-
-
-/***************************************************************************
- CONSTANTS
-***************************************************************************/
-
-/* map variables */
-#define MAPVAR_PC M0
-#define MAPVAR_CYCLES M1
-
-/* exit codes */
-#define EXECUTE_OUT_OF_CYCLES 0
-#define EXECUTE_MISSING_CODE 1
-#define EXECUTE_UNMAPPED_CODE 2
-#define EXECUTE_RESET_CACHE 3
-
-
-
-/***************************************************************************
- Macros
-***************************************************************************/
-
-#define R32(reg) m_regmap[reg]
-
-/***************************************************************************
- Inline Functions
-***************************************************************************/
-
-/*-------------------------------------------------
- epc - compute the exception PC from a
- descriptor
--------------------------------------------------*/
-
-static inline uint32_t epc(const opcode_desc *desc)
-{
- return ((desc->flags & OPFLAG_IN_DELAY_SLOT) ? (desc->pc - 3) : desc->pc) | 0x1000;
-}
-
-
-/*-------------------------------------------------
- alloc_handle - allocate a handle if not
- already allocated
--------------------------------------------------*/
-
-static inline void alloc_handle(drcuml_state &drcuml, uml::code_handle *&handleptr, const char *name)
-{
- if (!handleptr)
- handleptr = drcuml.handle_alloc(name);
-}
-
-
-/*-------------------------------------------------
- load_fast_iregs - load any fast integer
- registers
--------------------------------------------------*/
-
-inline void rsp_device::load_fast_iregs(drcuml_block &block)
-{
- int regnum;
-
- for (regnum = 0; regnum < std::size(m_regmap); regnum++)
- if (m_regmap[regnum].is_int_register())
- UML_MOV(block, ireg(m_regmap[regnum].ireg() - REG_I0), mem(&m_rsp_state->r[regnum]));
-}
-
-
-/*-------------------------------------------------
- save_fast_iregs - save any fast integer
- registers
--------------------------------------------------*/
-
-inline void rsp_device::save_fast_iregs(drcuml_block &block)
-{
- int regnum;
-
- for (regnum = 0; regnum < std::size(m_regmap); regnum++)
- if (m_regmap[regnum].is_int_register())
- UML_MOV(block, mem(&m_rsp_state->r[regnum]), ireg(m_regmap[regnum].ireg() - REG_I0));
-}
-
-/***************************************************************************
- CORE CALLBACKS
-***************************************************************************/
-
-inline void rsp_device::ccfunc_read8()
-{
- m_rsp_state->arg0 = DM_READ8(m_rsp_state->arg0);
-}
-
-static void cfunc_read8(void *param)
-{
- ((rsp_device *)param)->ccfunc_read8();
-}
-
-inline void rsp_device::ccfunc_read16()
-{
- m_rsp_state->arg0 = DM_READ16(m_rsp_state->arg0);
-}
-
-static void cfunc_read16(void *param)
-{
- ((rsp_device *)param)->ccfunc_read16();
-}
-
-inline void rsp_device::ccfunc_read32()
-{
- m_rsp_state->arg0 = DM_READ32(m_rsp_state->arg0);
-}
-
-static void cfunc_read32(void *param)
-{
- ((rsp_device *)param)->ccfunc_read32();
-}
-
-inline void rsp_device::ccfunc_write8()
-{
- DM_WRITE8(m_rsp_state->arg0, m_rsp_state->arg1);
-}
-
-static void cfunc_write8(void *param)
-{
- ((rsp_device *)param)->ccfunc_write8();
-}
-
-inline void rsp_device::ccfunc_write16()
-{
- DM_WRITE16(m_rsp_state->arg0, m_rsp_state->arg1);
-}
-
-static void cfunc_write16(void *param)
-{
- ((rsp_device *)param)->ccfunc_write16();
-}
-
-inline void rsp_device::ccfunc_write32()
-{
- DM_WRITE32(m_rsp_state->arg0, m_rsp_state->arg1);
-}
-
-static void cfunc_write32(void *param)
-{
- ((rsp_device *)param)->ccfunc_write32();
-}
-
-/*****************************************************************************/
-
-/*-------------------------------------------------
- rspdrc_set_options - configure DRC options
--------------------------------------------------*/
-
-void rsp_device::rspdrc_set_options(uint32_t options)
-{
- if (!allow_drc()) return;
- m_drcoptions = options;
-}
-
-
-inline void rsp_device::ccfunc_get_cop0_reg()
-{
- int reg = m_rsp_state->arg0;
- int dest = m_rsp_state->arg1;
-
- if (reg >= 0 && reg < 8)
- {
- if(dest)
- {
- m_rsp_state->r[dest] = m_sp_reg_r_func(reg, 0xffffffff);
- }
- }
- else if (reg >= 8 && reg < 16)
- {
- if(dest)
- {
- m_rsp_state->r[dest] = m_dp_reg_r_func(reg - 8, 0xffffffff);
- }
- }
- else
- {
- fatalerror("RSP: cfunc_get_cop0_reg: %d\n", reg);
- }
-}
-
-static void cfunc_get_cop0_reg(void *param)
-{
- ((rsp_device *)param)->ccfunc_get_cop0_reg();
-}
-
-inline void rsp_device::ccfunc_set_cop0_reg()
-{
- int reg = m_rsp_state->arg0;
- uint32_t data = m_rsp_state->arg1;
-
- if (reg >= 0 && reg < 8)
- {
- m_sp_reg_w_func(reg, data, 0xffffffff);
- }
- else if (reg >= 8 && reg < 16)
- {
- m_dp_reg_w_func(reg - 8, data, 0xffffffff);
- }
- else
- {
- fatalerror("RSP: set_cop0_reg: %d, %08X\n", reg, data);
- }
-}
-
-static void cfunc_set_cop0_reg(void *param)
-{
- ((rsp_device *)param)->ccfunc_set_cop0_reg();
-}
-
-/*****************************************************************************/
-
-void rsp_device::rspcom_init()
-{
-}
-
-inline void rsp_device::ccfunc_sp_set_status_cb()
-{
- m_sp_set_status_func(0, m_rsp_state->arg0, 0xffffffff);
-}
-
-void cfunc_sp_set_status_cb(void *param)
-{
- ((rsp_device *)param)->ccfunc_sp_set_status_cb();
-}
-
-void rsp_device::execute_run_drc()
-{
- int execute_result;
-
- /* reset the cache if dirty */
- if (m_cache_dirty)
- code_flush_cache();
- m_cache_dirty = false;
-
- /* execute */
- do
- {
- if( m_sr & ( RSP_STATUS_HALT | RSP_STATUS_BROKE ) )
- {
- m_rsp_state->icount = std::min(m_rsp_state->icount, 0);
- break;
- }
-
- /* run as much as we can */
- execute_result = m_drcuml->execute(*m_entry);
-
- /* if we need to recompile, do it */
- if (execute_result == EXECUTE_MISSING_CODE)
- {
- code_compile_block(m_rsp_state->pc);
- }
- else if (execute_result == EXECUTE_UNMAPPED_CODE)
- {
- fatalerror("Attempted to execute unmapped code at PC=%08X\n", m_rsp_state->pc);
- }
- else if (execute_result == EXECUTE_RESET_CACHE)
- {
- code_flush_cache();
- }
- } while (execute_result != EXECUTE_OUT_OF_CYCLES);
-}
-
-/***************************************************************************
- CACHE MANAGEMENT
-***************************************************************************/
-
-/*-------------------------------------------------
- rspdrc_flush_drc_cache - outward-facing
- accessor to code_flush_cache
--------------------------------------------------*/
-
-void rsp_device::rspdrc_flush_drc_cache()
-{
- if (!allow_drc()) return;
- m_cache_dirty = true;
-}
-
-/*-------------------------------------------------
- code_flush_cache - flush the cache and
- regenerate static code
--------------------------------------------------*/
-
-void rsp_device::code_flush_cache()
-{
- /* empty the transient cache contents */
- m_drcuml->reset();
-
- try
- {
- /* generate the entry point and out-of-cycles handlers */
- static_generate_entry_point();
- static_generate_nocode_handler();
- static_generate_out_of_cycles();
-
- /* add subroutines for memory accesses */
- static_generate_memory_accessor(1, false, "read8", m_read8);
- static_generate_memory_accessor(1, true, "write8", m_write8);
- static_generate_memory_accessor(2, false, "read16", m_read16);
- static_generate_memory_accessor(2, true, "write16", m_write16);
- static_generate_memory_accessor(4, false, "read32", m_read32);
- static_generate_memory_accessor(4, true, "write32", m_write32);
- }
- catch (drcuml_block::abort_compilation &)
- {
- fatalerror("Unable to generate static RSP code\n");
- }
-}
-
-
-/*-------------------------------------------------
- code_compile_block - compile a block of the
- given mode at the specified pc
--------------------------------------------------*/
-
-void rsp_device::code_compile_block(offs_t pc)
-{
- compiler_state compiler = { 0 };
- const opcode_desc *seqhead, *seqlast;
- const opcode_desc *desclist;
- int override = false;
-
- g_profiler.start(PROFILER_DRC_COMPILE);
-
- /* get a description of this sequence */
- desclist = m_drcfe->describe_code(pc);
-
- bool succeeded = false;
- while (!succeeded)
- {
- try
- {
- /* start the block */
- drcuml_block &block(m_drcuml->begin_block(4096));
-
- /* loop until we get through all instruction sequences */
- for (seqhead = desclist; seqhead != nullptr; seqhead = seqlast->next())
- {
- const opcode_desc *curdesc;
- uint32_t nextpc;
-
- /* add a code log entry */
- if (m_drcuml->logging())
- block.append_comment("-------------------------"); // comment
-
- /* determine the last instruction in this sequence */
- for (seqlast = seqhead; seqlast != nullptr; seqlast = seqlast->next())
- if (seqlast->flags & OPFLAG_END_SEQUENCE)
- break;
- assert(seqlast != nullptr);
-
- /* if we don't have a hash for this mode/pc, or if we are overriding all, add one */
- if (override || !m_drcuml->hash_exists(0, seqhead->pc))
- UML_HASH(block, 0, seqhead->pc); // hash mode,pc
-
- /* if we already have a hash, and this is the first sequence, assume that we */
- /* are recompiling due to being out of sync and allow future overrides */
- else if (seqhead == desclist)
- {
- override = true;
- UML_HASH(block, 0, seqhead->pc); // hash mode,pc
- }
-
- /* otherwise, redispatch to that fixed PC and skip the rest of the processing */
- else
- {
- UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc
- UML_HASHJMP(block, 0, seqhead->pc, *m_nocode);
- // hashjmp <0>,seqhead->pc,nocode
- continue;
- }
-
- /* validate this code block if we're not pointing into ROM */
- if (m_program.space().get_write_ptr(seqhead->physpc) != nullptr)
- generate_checksum_block(block, compiler, seqhead, seqlast);
-
- /* label this instruction, if it may be jumped to locally */
- if (seqhead->flags & OPFLAG_IS_BRANCH_TARGET)
- 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())
- generate_sequence_instruction(block, compiler, curdesc);
-
- /* if we need to return to the start, do it */
- if (seqlast->flags & OPFLAG_RETURN_TO_START)
- nextpc = pc;
-
- /* otherwise we just go to the next instruction */
- else
- nextpc = seqlast->pc + (seqlast->skipslots + 1) * 4;
-
- /* count off cycles and go there */
- generate_update_cycles(block, compiler, nextpc, true); // <subtract cycles>
-
- /* if the last instruction can change modes, use a variable mode; otherwise, assume the same mode */
- if (seqlast->next() == nullptr || seqlast->next()->pc != nextpc)
- UML_HASHJMP(block, 0, nextpc, *m_nocode); // hashjmp <mode>,nextpc,nocode
- }
-
- /* end the sequence */
- block.end();
- g_profiler.stop();
- succeeded = true;
- }
- catch (drcuml_block::abort_compilation &)
- {
- code_flush_cache();
- }
- }
-}
-
-/***************************************************************************
- C FUNCTION CALLBACKS
-***************************************************************************/
-
-/*-------------------------------------------------
- cfunc_unimplemented - handler for
- unimplemented opcdes
--------------------------------------------------*/
-
-inline void rsp_device::ccfunc_unimplemented()
-{
- uint32_t opcode = m_rsp_state->arg0;
- fatalerror("PC=%08X: Unimplemented op %08X (%02X,%02X)\n", m_rsp_state->pc, opcode, opcode >> 26, opcode & 0x3f);
-}
-
-static void cfunc_unimplemented(void *param)
-{
- ((rsp_device *)param)->ccfunc_unimplemented();
-}
-
-/*-------------------------------------------------
- cfunc_fatalerror - a generic fatalerror call
--------------------------------------------------*/
-
-#ifdef UNUSED_CODE
-static void cfunc_fatalerror(void *param)
-{
- fatalerror("fatalerror\n");
-}
-#endif
-
-
-/***************************************************************************
- STATIC CODEGEN
-***************************************************************************/
-
-/*-------------------------------------------------
- ferate_entry_point - generate a
- static entry point
--------------------------------------------------*/
-
-void rsp_device::static_generate_entry_point()
-{
- /* begin generating */
- drcuml_block &block(m_drcuml->begin_block(20));
-
- /* forward references */
- alloc_handle(*m_drcuml, m_nocode, "nocode");
-
- alloc_handle(*m_drcuml, m_entry, "entry");
- UML_HANDLE(block, *m_entry); // handle entry
-
- /* load fast integer registers */
- load_fast_iregs(block);
-
- /* generate a hash jump via the current mode and PC */
- UML_HASHJMP(block, 0, mem(&m_rsp_state->pc), *m_nocode); // hashjmp <mode>,<pc>,nocode
- block.end();
-}
-
-
-/*-------------------------------------------------
- static_generate_nocode_handler - generate an
- exception handler for "out of code"
--------------------------------------------------*/
-
-void rsp_device::static_generate_nocode_handler()
-{
- /* begin generating */
- drcuml_block &block(m_drcuml->begin_block(10));
-
- /* generate a hash jump via the current mode and PC */
- alloc_handle(*m_drcuml, m_nocode, "nocode");
- UML_HANDLE(block, *m_nocode); // handle nocode
- UML_GETEXP(block, I0); // getexp i0
- UML_MOV(block, mem(&m_rsp_state->pc), I0); // mov [pc],i0
- save_fast_iregs(block);
- UML_EXIT(block, EXECUTE_MISSING_CODE); // exit EXECUTE_MISSING_CODE
-
- block.end();
-}
-
-
-/*-------------------------------------------------
- static_generate_out_of_cycles - generate an
- out of cycles exception handler
--------------------------------------------------*/
-
-void rsp_device::static_generate_out_of_cycles()
-{
- /* begin generating */
- drcuml_block &block(m_drcuml->begin_block(10));
-
- /* generate a hash jump via the current mode and PC */
- alloc_handle(*m_drcuml, m_out_of_cycles, "out_of_cycles");
- UML_HANDLE(block, *m_out_of_cycles); // handle out_of_cycles
- UML_GETEXP(block, I0); // getexp i0
- UML_MOV(block, mem(&m_rsp_state->pc), I0); // mov <pc>,i0
- save_fast_iregs(block);
- UML_EXIT(block, EXECUTE_OUT_OF_CYCLES); // exit EXECUTE_OUT_OF_CYCLES
-
- block.end();
-}
-
-/*------------------------------------------------------------------
- static_generate_memory_accessor
-------------------------------------------------------------------*/
-
-void rsp_device::static_generate_memory_accessor(int size, int iswrite, const char *name, uml::code_handle *&handleptr)
-{
- /* on entry, address is in I0; data for writes is in I1 */
- /* on exit, read result is in I0 */
- /* routine trashes I0-I1 */
-
- /* begin generating */
- drcuml_block &block(m_drcuml->begin_block(1024));
-
- /* add a global entry for this */
- alloc_handle(*m_drcuml, handleptr, name);
- UML_HANDLE(block, *handleptr); // handle *handleptr
-
- // write:
- if (iswrite)
- {
- if (size == 1)
- {
- UML_MOV(block, mem(&m_rsp_state->arg0), I0); // mov [arg0],i0 ; address
- UML_MOV(block, mem(&m_rsp_state->arg1), I1); // mov [arg1],i1 ; data
- UML_CALLC(block, cfunc_write8, this); // callc cfunc_write8
- }
- else if (size == 2)
- {
- UML_MOV(block, mem(&m_rsp_state->arg0), I0); // mov [arg0],i0 ; address
- UML_MOV(block, mem(&m_rsp_state->arg1), I1); // mov [arg1],i1 ; data
- UML_CALLC(block, cfunc_write16, this); // callc cfunc_write16
- }
- else if (size == 4)
- {
- UML_MOV(block, mem(&m_rsp_state->arg0), I0); // mov [arg0],i0 ; address
- UML_MOV(block, mem(&m_rsp_state->arg1), I1); // mov [arg1],i1 ; data
- UML_CALLC(block, cfunc_write32, this); // callc cfunc_write32
- }
- }
- else
- {
- if (size == 1)
- {
- UML_MOV(block, mem(&m_rsp_state->arg0), I0); // mov [arg0],i0 ; address
- UML_CALLC(block, cfunc_read8, this); // callc read8
- UML_MOV(block, I0, mem(&m_rsp_state->arg0)); // mov i0,[arg0],i0 ; result
- }
- else if (size == 2)
- {
- UML_MOV(block, mem(&m_rsp_state->arg0), I0); // mov [arg0],i0 ; address
- UML_CALLC(block, cfunc_read16, this); // callc cfunc_read16
- UML_MOV(block, I0, mem(&m_rsp_state->arg0)); // mov i0,[arg0],i0 ; result
- }
- else if (size == 4)
- {
- UML_MOV(block, mem(&m_rsp_state->arg0), I0); // mov [arg0],i0 ; address
- UML_CALLC(block, cfunc_read32, this); // callc cfunc_read32
- UML_MOV(block, I0, mem(&m_rsp_state->arg0)); // mov i0,[arg0],i0 ; result
- }
- }
- UML_RET(block);
-
- block.end();
-}
-
-
-
-/***************************************************************************
- CODE GENERATION
-***************************************************************************/
-
-/*-------------------------------------------------
- generate_update_cycles - generate code to
- subtract cycles from the icount and generate
- an exception if out
--------------------------------------------------*/
-void rsp_device::generate_update_cycles(drcuml_block &block, compiler_state &compiler, uml::parameter param, bool allow_exception)
-{
- /* account for cycles */
- if (compiler.cycles > 0)
- {
- UML_SUB(block, mem(&m_rsp_state->icount), mem(&m_rsp_state->icount), MAPVAR_CYCLES); // sub icount,icount,cycles
- UML_MAPVAR(block, MAPVAR_CYCLES, 0); // mapvar cycles,0
- UML_EXHc(block, COND_S, *m_out_of_cycles, param);
- }
- compiler.cycles = 0;
-}
-
-/*-------------------------------------------------
- generate_checksum_block - generate code to
- validate a sequence of opcodes
--------------------------------------------------*/
-
-void rsp_device::generate_checksum_block(drcuml_block &block, compiler_state &compiler, const opcode_desc *seqhead, const opcode_desc *seqlast)
-{
- const opcode_desc *curdesc;
- if (m_drcuml->logging())
- {
- block.append_comment("[Validation for %08X]", seqhead->pc | 0x1000); // comment
- }
- /* loose verify or single instruction: just compare and fail */
- if (!(m_drcoptions & RSPDRC_STRICT_VERIFY) || seqhead->next() == nullptr)
- {
- if (!(seqhead->flags & OPFLAG_VIRTUAL_NOOP))
- {
- uint32_t sum = seqhead->opptr.l[0];
- void *base = m_pcache.read_ptr(seqhead->physpc | 0x1000);
- UML_LOAD(block, I0, base, 0, SIZE_DWORD, SCALE_x4); // load i0,base,0,dword
-
- if (seqhead->delay.first() != nullptr && seqhead->physpc != seqhead->delay.first()->physpc)
- {
- base = m_pcache.read_ptr((seqhead->delay.first()->physpc & 0x00000fff) | 0x1000);
- assert(base != nullptr);
- UML_LOAD(block, I1, base, 0, SIZE_DWORD, SCALE_x4); // load i1,base,dword
- UML_ADD(block, I0, I0, I1); // add i0,i0,i1
-
- sum += seqhead->delay.first()->opptr.l[0];
- }
-
- UML_CMP(block, I0, sum); // cmp i0,opptr[0]
- UML_EXHc(block, COND_NE, *m_nocode, epc(seqhead)); // exne nocode,seqhead->pc
- }
- }
-
- /* full verification; sum up everything */
- else
- {
- uint32_t sum = 0;
- void *base = m_pcache.read_ptr(seqhead->physpc | 0x1000);
- UML_LOAD(block, I0, base, 0, SIZE_DWORD, SCALE_x4); // load i0,base,0,dword
- sum += seqhead->opptr.l[0];
- for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next())
- if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP))
- {
- base = m_pcache.read_ptr(curdesc->physpc | 0x1000);
- assert(base != nullptr);
- UML_LOAD(block, I1, base, 0, SIZE_DWORD, SCALE_x4); // load i1,base,dword
- UML_ADD(block, I0, I0, I1); // add i0,i0,i1
- sum += curdesc->opptr.l[0];
-
- if (curdesc->delay.first() != nullptr && (curdesc == seqlast || (curdesc->next() != nullptr && curdesc->next()->physpc != curdesc->delay.first()->physpc)))
- {
- base = m_pcache.read_ptr((curdesc->delay.first()->physpc & 0x00000fff) | 0x1000);
- assert(base != nullptr);
- UML_LOAD(block, I1, base, 0, SIZE_DWORD, SCALE_x4); // load i1,base,dword
- UML_ADD(block, I0, I0, I1); // add i0,i0,i1
-
- sum += curdesc->delay.first()->opptr.l[0];
- }
- }
- UML_CMP(block, I0, sum); // cmp i0,sum
- UML_EXHc(block, COND_NE, *m_nocode, epc(seqhead)); // exne nocode,seqhead->pc
- }
-}
-
-
-/*-------------------------------------------------
- generate_sequence_instruction - generate code
- for a single instruction in a sequence
--------------------------------------------------*/
-
-void rsp_device::generate_sequence_instruction(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
-{
- offs_t expc;
-
- /* add an entry for the log */
- if (m_drcuml->logging() && !(desc->flags & OPFLAG_VIRTUAL_NOOP))
- log_add_disasm_comment(block, desc->pc, desc->opptr.l[0]);
-
- /* set the PC map variable */
- expc = (desc->flags & OPFLAG_IN_DELAY_SLOT) ? desc->pc - 3 : desc->pc;
- UML_MAPVAR(block, MAPVAR_PC, expc); // mapvar PC,expc
-
- /* accumulate total cycles */
- compiler.cycles += desc->cycles;
-
- /* update the icount map variable */
- UML_MAPVAR(block, MAPVAR_CYCLES, compiler.cycles); // mapvar CYCLES,compiler.cycles
-
- /* if we are debugging, call the debugger */
- if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0)
- {
- UML_MOV(block, mem(&m_rsp_state->pc), desc->pc); // mov [pc],desc->pc
- save_fast_iregs(block);
- UML_DEBUG(block, desc->pc); // debug desc->pc
- }
-
- /* if we hit an unmapped address, fatal error */
-#if 0
- if (desc->flags & OPFLAG_COMPILER_UNMAPPED)
- {
- UML_MOV(block, mem(&m_rsp_state->pc), desc->pc); // mov [pc],desc->pc
- save_fast_iregs(block);
- UML_EXIT(block, EXECUTE_UNMAPPED_CODE); // exit EXECUTE_UNMAPPED_CODE
- }
-#endif
-
- /* otherwise, unless this is a virtual no-op, it's a regular instruction */
- /*else*/ if (!(desc->flags & OPFLAG_VIRTUAL_NOOP))
- {
- /* compile the instruction */
- if (!generate_opcode(block, compiler, desc))
- {
- UML_MOV(block, mem(&m_rsp_state->pc), desc->pc); // mov [pc],desc->pc
- UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l
- UML_CALLC(block, cfunc_unimplemented, this); // callc cfunc_unimplemented
- }
- }
-}
-
-/*------------------------------------------------------------------
- generate_branch
-------------------------------------------------------------------*/
-
-void rsp_device::generate_branch(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
-{
- compiler_state compiler_temp(compiler);
-
- /* update the cycles and jump through the hash table to the target */
- if (desc->targetpc != BRANCH_TARGET_DYNAMIC)
- {
- generate_update_cycles(block, compiler_temp, desc->targetpc, true); // <subtract cycles>
- if (desc->flags & OPFLAG_INTRABLOCK_BRANCH)
- UML_JMP(block, desc->targetpc | 0x80000000); // jmp desc->targetpc
- else
- UML_HASHJMP(block, 0, desc->targetpc, *m_nocode); // hashjmp <mode>,desc->targetpc,nocode
- }
- else
- {
- generate_update_cycles(block, compiler_temp, uml::mem(&m_rsp_state->jmpdest), true); // <subtract cycles>
- UML_HASHJMP(block, 0, mem(&m_rsp_state->jmpdest), *m_nocode); // hashjmp <mode>,<rsreg>,nocode
- }
-}
-
-/*------------------------------------------------------------------
- generate_delay_slot_and_branch
-------------------------------------------------------------------*/
-
-void rsp_device::generate_delay_slot_and_branch(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc, uint8_t linkreg)
-{
- compiler_state compiler_temp(compiler);
- uint32_t op = desc->opptr.l[0];
-
- /* fetch the target register if dynamic, in case it is modified by the delay slot */
- if (desc->targetpc == BRANCH_TARGET_DYNAMIC)
- {
- UML_AND(block, mem(&m_rsp_state->jmpdest), R32(RSREG), 0x00000fff);
- UML_OR(block, mem(&m_rsp_state->jmpdest), mem(&m_rsp_state->jmpdest), 0x1000);
- }
-
- /* set the link if needed -- before the delay slot */
- if (linkreg != 0)
- {
- UML_MOV(block, R32(linkreg), (int32_t)((desc->pc + 8) & 0x0000fff)); // mov <linkreg>,desc->pc + 8
- }
-
- /* compile the delay slot using temporary compiler state */
- assert(desc->delay.first() != nullptr);
- generate_sequence_instruction(block, compiler_temp, desc->delay.first()); // <next instruction>
-
- generate_branch(block, compiler, desc);
-
- /* update the label */
- compiler.labelnum = compiler_temp.labelnum;
-
- /* reset the mapvar to the current cycles and account for skipped slots */
- compiler.cycles += desc->skipslots;
- UML_MAPVAR(block, MAPVAR_CYCLES, compiler.cycles); // mapvar CYCLES,compiler.cycles
-}
-
-bool rsp_device::generate_opcode(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
-{
- int in_delay_slot = ((desc->flags & OPFLAG_IN_DELAY_SLOT) != 0);
- uint32_t op = desc->opptr.l[0];
- uint8_t opswitch = op >> 26;
- uml::code_label skip;
-
- switch (opswitch)
- {
- /* ----- sub-groups ----- */
-
- case 0x00: /* SPECIAL - MIPS I */
- return generate_special(block, compiler, desc);
-
- case 0x01: /* REGIMM - MIPS I */
- return generate_regimm(block, compiler, desc);
-
- /* ----- jumps and branches ----- */
-
- case 0x02: /* J - MIPS I */
- generate_delay_slot_and_branch(block, compiler, desc, 0); // <next instruction + hashjmp>
- return true;
-
- case 0x03: /* JAL - MIPS I */
- generate_delay_slot_and_branch(block, compiler, desc, 31); // <next instruction + hashjmp>
- return true;
-
- case 0x04: /* BEQ - MIPS I */
- UML_CMP(block, R32(RSREG), R32(RTREG)); // cmp <rsreg>,<rtreg>
- UML_JMPc(block, COND_NE, skip = compiler.labelnum++); // jmp skip,NE
- generate_delay_slot_and_branch(block, compiler, desc, 0); // <next instruction + hashjmp>
- UML_LABEL(block, skip); // skip:
- return true;
-
- case 0x05: /* BNE - MIPS I */
- UML_CMP(block, R32(RSREG), R32(RTREG)); // dcmp <rsreg>,<rtreg>
- UML_JMPc(block, COND_E, skip = compiler.labelnum++); // jmp skip,E
- generate_delay_slot_and_branch(block, compiler, desc, 0); // <next instruction + hashjmp>
- UML_LABEL(block, skip); // skip:
- return true;
-
- case 0x06: /* BLEZ - MIPS I */
- if (RSREG != 0)
- {
- UML_CMP(block, R32(RSREG), 0); // dcmp <rsreg>,0
- UML_JMPc(block, COND_G, skip = compiler.labelnum++); // jmp skip,G
- generate_delay_slot_and_branch(block, compiler, desc, 0); // <next instruction + hashjmp>
- UML_LABEL(block, skip); // skip:
- }
- else
- generate_delay_slot_and_branch(block, compiler, desc, 0); // <next instruction + hashjmp>
- return true;
-
- case 0x07: /* BGTZ - MIPS I */
- UML_CMP(block, R32(RSREG), 0); // dcmp <rsreg>,0
- UML_JMPc(block, COND_LE, skip = compiler.labelnum++); // jmp skip,LE
- generate_delay_slot_and_branch(block, compiler, desc, 0); // <next instruction + hashjmp>
- UML_LABEL(block, skip); // skip:
- return true;
-
-
- /* ----- immediate arithmetic ----- */
-
- case 0x0f: /* LUI - MIPS I */
- if (RTREG != 0)
- UML_MOV(block, R32(RTREG), SIMMVAL << 16); // dmov <rtreg>,SIMMVAL << 16
- return true;
-
- case 0x08: /* ADDI - MIPS I */
- case 0x09: /* ADDIU - MIPS I */
- if (RTREG != 0)
- {
- UML_ADD(block, R32(RTREG), R32(RSREG), SIMMVAL); // add i0,<rsreg>,SIMMVAL,V
- }
- return true;
-
- case 0x0a: /* SLTI - MIPS I */
- if (RTREG != 0)
- {
- UML_CMP(block, R32(RSREG), SIMMVAL); // dcmp <rsreg>,SIMMVAL
- UML_SETc(block, COND_L, R32(RTREG)); // dset <rtreg>,l
- }
- return true;
-
- case 0x0b: /* SLTIU - MIPS I */
- if (RTREG != 0)
- {
- UML_CMP(block, R32(RSREG), SIMMVAL); // dcmp <rsreg>,SIMMVAL
- UML_SETc(block, COND_B, R32(RTREG)); // dset <rtreg>,b
- }
- return true;
-
-
- case 0x0c: /* ANDI - MIPS I */
- if (RTREG != 0)
- UML_AND(block, R32(RTREG), R32(RSREG), UIMMVAL); // dand <rtreg>,<rsreg>,UIMMVAL
- return true;
-
- case 0x0d: /* ORI - MIPS I */
- if (RTREG != 0)
- UML_OR(block, R32(RTREG), R32(RSREG), UIMMVAL); // dor <rtreg>,<rsreg>,UIMMVAL
- return true;
-
- case 0x0e: /* XORI - MIPS I */
- if (RTREG != 0)
- UML_XOR(block, R32(RTREG), R32(RSREG), UIMMVAL); // dxor <rtreg>,<rsreg>,UIMMVAL
- return true;
-
- /* ----- memory load operations ----- */
-
- case 0x20: /* LB - MIPS I */
- UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,<rsreg>,SIMMVAL
- UML_CALLH(block, *m_read8); // callh read8
- if (RTREG != 0)
- UML_SEXT(block, R32(RTREG), I0, SIZE_BYTE); // dsext <rtreg>,i0,byte
- if (!in_delay_slot)
- generate_update_cycles(block, compiler, desc->pc + 4, true);
- return true;
-
- case 0x21: /* LH - MIPS I */
- UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,<rsreg>,SIMMVAL
- UML_CALLH(block, *m_read16); // callh read16
- if (RTREG != 0)
- UML_SEXT(block, R32(RTREG), I0, SIZE_WORD); // dsext <rtreg>,i0,word
- if (!in_delay_slot)
- generate_update_cycles(block, compiler, desc->pc + 4, true);
- return true;
-
- case 0x23: /* LW - MIPS I */
- UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,<rsreg>,SIMMVAL
- UML_CALLH(block, *m_read32); // callh read32
- if (RTREG != 0)
- UML_MOV(block, R32(RTREG), I0);
- if (!in_delay_slot)
- generate_update_cycles(block, compiler, desc->pc + 4, true);
- return true;
-
- case 0x24: /* LBU - MIPS I */
- UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,<rsreg>,SIMMVAL
- UML_CALLH(block, *m_read8); // callh read8
- if (RTREG != 0)
- UML_AND(block, R32(RTREG), I0, 0xff); // dand <rtreg>,i0,0xff
- if (!in_delay_slot)
- generate_update_cycles(block, compiler, desc->pc + 4, true);
- return true;
-
- case 0x25: /* LHU - MIPS I */
- UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,<rsreg>,SIMMVAL
- UML_CALLH(block, *m_read16); // callh read16
- if (RTREG != 0)
- UML_AND(block, R32(RTREG), I0, 0xffff); // dand <rtreg>,i0,0xffff
- if (!in_delay_slot)
- generate_update_cycles(block, compiler, desc->pc + 4, true);
- return true;
-
- case 0x32: /* LWC2 - MIPS I */
- return m_cop2->generate_lwc2(block, compiler, desc);
-
-
- /* ----- memory store operations ----- */
-
- case 0x28: /* SB - MIPS I */
- UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,<rsreg>,SIMMVAL
- UML_MOV(block, I1, R32(RTREG)); // mov i1,<rtreg>
- UML_CALLH(block, *m_write8); // callh write8
- if (!in_delay_slot)
- generate_update_cycles(block, compiler, desc->pc + 4, true);
- return true;
-
- case 0x29: /* SH - MIPS I */
- UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,<rsreg>,SIMMVAL
- UML_MOV(block, I1, R32(RTREG)); // mov i1,<rtreg>
- UML_CALLH(block, *m_write16); // callh write16
- if (!in_delay_slot)
- generate_update_cycles(block, compiler, desc->pc + 4, true);
- return true;
-
- case 0x2b: /* SW - MIPS I */
- UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,<rsreg>,SIMMVAL
- UML_MOV(block, I1, R32(RTREG)); // mov i1,<rtreg>
- UML_CALLH(block, *m_write32); // callh write32
- if (!in_delay_slot)
- generate_update_cycles(block, compiler, desc->pc + 4, true);
- return true;
-
- case 0x3a: /* SWC2 - MIPS I */
- return m_cop2->generate_swc2(block, compiler, desc);
-
- /* ----- coprocessor instructions ----- */
-
- case 0x10: /* COP0 - MIPS I */
- return generate_cop0(block, compiler, desc);
-
- case 0x12: /* COP2 - MIPS I */
- return m_cop2->generate_cop2(block, compiler, desc);
-
-
- /* ----- unimplemented/illegal instructions ----- */
-
- //default: /* ??? */ invalid_instruction(op); break;
- }
-
- return false;
-}
-
-
-/*-------------------------------------------------
- generate_special - compile opcodes in the
- 'SPECIAL' group
--------------------------------------------------*/
-
-bool rsp_device::generate_special(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
-{
- uint32_t op = desc->opptr.l[0];
- uint8_t opswitch = op & 63;
- //uml::code_label skip;
-
- switch (opswitch)
- {
- /* ----- shift instructions ----- */
-
- case 0x00: /* SLL - MIPS I */
- if (RDREG != 0)
- {
- UML_SHL(block, R32(RDREG), R32(RTREG), SHIFT);
- }
- return true;
-
- case 0x02: /* SRL - MIPS I */
- if (RDREG != 0)
- {
- UML_SHR(block, R32(RDREG), R32(RTREG), SHIFT);
- }
- return true;
-
- case 0x03: /* SRA - MIPS I */
- if (RDREG != 0)
- {
- UML_SAR(block, R32(RDREG), R32(RTREG), SHIFT);
- }
- return true;
-
- case 0x04: /* SLLV - MIPS I */
- if (RDREG != 0)
- {
- UML_SHL(block, R32(RDREG), R32(RTREG), R32(RSREG));
- }
- return true;
-
- case 0x06: /* SRLV - MIPS I */
- if (RDREG != 0)
- {
- UML_SHR(block, R32(RDREG), R32(RTREG), R32(RSREG));
- }
- return true;
-
- case 0x07: /* SRAV - MIPS I */
- if (RDREG != 0)
- {
- UML_SAR(block, R32(RDREG), R32(RTREG), R32(RSREG));
- }
- return true;
-
- /* ----- basic arithmetic ----- */
-
- case 0x20: /* ADD - MIPS I */
- case 0x21: /* ADDU - MIPS I */
- if (RDREG != 0)
- {
- UML_ADD(block, R32(RDREG), R32(RSREG), R32(RTREG));
- }
- return true;
-
- case 0x22: /* SUB - MIPS I */
- case 0x23: /* SUBU - MIPS I */
- if (RDREG != 0)
- {
- UML_SUB(block, R32(RDREG), R32(RSREG), R32(RTREG));
- }
- return true;
-
- /* ----- basic logical ops ----- */
-
- case 0x24: /* AND - MIPS I */
- if (RDREG != 0)
- {
- UML_AND(block, R32(RDREG), R32(RSREG), R32(RTREG)); // dand <rdreg>,<rsreg>,<rtreg>
- }
- return true;
-
- case 0x25: /* OR - MIPS I */
- if (RDREG != 0)
- {
- UML_OR(block, R32(RDREG), R32(RSREG), R32(RTREG)); // dor <rdreg>,<rsreg>,<rtreg>
- }
- return true;
-
- case 0x26: /* XOR - MIPS I */
- if (RDREG != 0)
- {
- UML_XOR(block, R32(RDREG), R32(RSREG), R32(RTREG)); // dxor <rdreg>,<rsreg>,<rtreg>
- }
- return true;
-
- case 0x27: /* NOR - MIPS I */
- if (RDREG != 0)
- {
- UML_OR(block, I0, R32(RSREG), R32(RTREG)); // dor i0,<rsreg>,<rtreg>
- UML_XOR(block, R32(RDREG), I0, (uint64_t)~0); // dxor <rdreg>,i0,~0
- }
- return true;
-
-
- /* ----- basic comparisons ----- */
-
- case 0x2a: /* SLT - MIPS I */
- if (RDREG != 0)
- {
- UML_CMP(block, R32(RSREG), R32(RTREG)); // dcmp <rsreg>,<rtreg>
- UML_SETc(block, COND_L, R32(RDREG)); // dset <rdreg>,l
- }
- return true;
-
- case 0x2b: /* SLTU - MIPS I */
- if (RDREG != 0)
- {
- UML_CMP(block, R32(RSREG), R32(RTREG)); // dcmp <rsreg>,<rtreg>
- UML_SETc(block, COND_B, R32(RDREG)); // dset <rdreg>,b
- }
- return true;
-
-
- /* ----- jumps and branches ----- */
-
- case 0x08: /* JR - MIPS I */
- generate_delay_slot_and_branch(block, compiler, desc, 0); // <next instruction + hashjmp>
- return true;
-
- case 0x09: /* JALR - MIPS I */
- generate_delay_slot_and_branch(block, compiler, desc, RDREG); // <next instruction + hashjmp>
- return true;
-
-
- /* ----- system calls ----- */
-
- case 0x0d: /* BREAK - MIPS I */
- UML_MOV(block, mem(&m_rsp_state->arg0), 3); // mov [arg0],3
- UML_CALLC(block, cfunc_sp_set_status_cb, this); // callc cfunc_sp_set_status_cb
- UML_MOV(block, mem(&m_rsp_state->icount), 0); // mov icount, #0
- UML_MOV(block, mem(&m_rsp_state->jmpdest), desc->targetpc);
-
- generate_branch(block, compiler, desc);
-
- UML_EXIT(block, EXECUTE_OUT_OF_CYCLES);
- return true;
- }
- return false;
-}
-
-
-
-/*-------------------------------------------------
- generate_regimm - compile opcodes in the
- 'REGIMM' group
--------------------------------------------------*/
-
-bool rsp_device::generate_regimm(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
-{
- uint32_t op = desc->opptr.l[0];
- uint8_t opswitch = RTREG;
- uml::code_label skip;
-
- switch (opswitch)
- {
- case 0x00: /* BLTZ */
- case 0x10: /* BLTZAL */
- if (RSREG != 0)
- {
- UML_CMP(block, R32(RSREG), 0); // dcmp <rsreg>,0
- UML_JMPc(block, COND_GE, skip = compiler.labelnum++); // jmp skip,GE
- generate_delay_slot_and_branch(block, compiler, desc, (opswitch & 0x10) ? 31 : 0);
- // <next instruction + hashjmp>
- UML_LABEL(block, skip); // skip:
- }
- return true;
-
- case 0x01: /* BGEZ */
- case 0x11: /* BGEZAL */
- if (RSREG != 0)
- {
- UML_CMP(block, R32(RSREG), 0); // dcmp <rsreg>,0
- UML_JMPc(block, COND_L, skip = compiler.labelnum++); // jmp skip,L
- generate_delay_slot_and_branch(block, compiler, desc, (opswitch & 0x10) ? 31 : 0);
- // <next instruction + hashjmp>
- UML_LABEL(block, skip); // skip:
- }
- else
- generate_delay_slot_and_branch(block, compiler, desc, (opswitch & 0x10) ? 31 : 0);
- // <next instruction + hashjmp>
- return true;
- }
- return false;
-}
-
-
-/*-------------------------------------------------
- generate_cop0 - compile COP0 opcodes
--------------------------------------------------*/
-
-bool rsp_device::generate_cop0(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
-{
- uint32_t op = desc->opptr.l[0];
- uint8_t opswitch = RSREG;
-
- switch (opswitch)
- {
- case 0x00: /* MFCz */
- if (RTREG != 0)
- {
- UML_MOV(block, mem(&m_rsp_state->arg0), RDREG); // mov [arg0],<rdreg>
- UML_MOV(block, mem(&m_rsp_state->arg1), RTREG); // mov [arg1],<rtreg>
- UML_CALLC(block, cfunc_get_cop0_reg, this); // callc cfunc_get_cop0_reg
- if(RDREG == 2)
- {
- generate_update_cycles(block, compiler, uml::mem(&m_rsp_state->pc), true);
- UML_HASHJMP(block, 0, mem(&m_rsp_state->pc), *m_nocode);
- }
- }
- return true;
-
- case 0x04: /* MTCz */
- UML_MOV(block, mem(&m_rsp_state->arg0), RDREG); // mov [arg0],<rdreg>
- UML_MOV(block, mem(&m_rsp_state->arg1), R32(RTREG)); // mov [arg1],rtreg
- UML_CALLC(block, cfunc_set_cop0_reg, this); // callc cfunc_set_cop0_reg
- return true;
- }
-
- return false;
-}
-
-/***************************************************************************
- CODE LOGGING HELPERS
-***************************************************************************/
-
-/*-------------------------------------------------
- log_add_disasm_comment - add a comment
- including disassembly of a RSP instruction
--------------------------------------------------*/
-
-void rsp_device::log_add_disasm_comment(drcuml_block &block, uint32_t pc, uint32_t op)
-{
- if (m_drcuml->logging())
- {
- rsp_disassembler rspd;
- std::ostringstream buffer;
- rspd.dasm_one(buffer, pc, op);
- block.append_comment("%08X: %s", pc, buffer.str()); // comment
- }
-}