diff options
author | 2016-05-28 17:46:58 +0300 | |
---|---|---|
committer | 2016-05-28 18:58:54 +0300 | |
commit | 958731ef5aef0e2357bd03f597e0ec06f893d309 (patch) | |
tree | a057c79e7fa3c3d41b88e59a0aa121216f640e08 /src/devices/cpu/sharc/sharcdrc.cpp | |
parent | 9cf8e8ac0ae259901080f8cfce1ae39a310286c6 (diff) |
Added highly experimental SHARC recompiler (disabled by default) [Ville Linde]
Diffstat (limited to 'src/devices/cpu/sharc/sharcdrc.cpp')
-rw-r--r-- | src/devices/cpu/sharc/sharcdrc.cpp | 4909 |
1 files changed, 4909 insertions, 0 deletions
diff --git a/src/devices/cpu/sharc/sharcdrc.cpp b/src/devices/cpu/sharc/sharcdrc.cpp new file mode 100644 index 00000000000..2f7f3e0fbcb --- /dev/null +++ b/src/devices/cpu/sharc/sharcdrc.cpp @@ -0,0 +1,4909 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde + +/****************************************************************************** + + SHARC UML recompiler core + +******************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "sharc.h" +#include "sharcfe.h" +#include "cpu/drcfe.h" +#include "cpu/drcuml.h" +#include "cpu/drcumlsh.h" + +using namespace uml; + +#define USE_SWAPDQ 0 +#define WRITE_SNOOP 0 + + +// 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 + + +#define REG(reg) m_regmap[reg] +#define DM_I(reg) mem(&m_core->dag1.i[reg]) +#define DM_M(reg) mem(&m_core->dag1.m[reg]) +#define DM_L(reg) mem(&m_core->dag1.l[reg]) +#define DM_B(reg) mem(&m_core->dag1.b[reg]) +#define PM_I(reg) mem(&m_core->dag2.i[reg]) +#define PM_M(reg) mem(&m_core->dag2.m[reg]) +#define PM_L(reg) mem(&m_core->dag2.l[reg]) +#define PM_B(reg) mem(&m_core->dag2.b[reg]) +#define ASTAT_AZ mem(&m_core->astat_drc.az) +#define ASTAT_AV mem(&m_core->astat_drc.av) +#define ASTAT_AN mem(&m_core->astat_drc.an) +#define ASTAT_AC mem(&m_core->astat_drc.ac) +#define ASTAT_AS mem(&m_core->astat_drc.as) +#define ASTAT_AI mem(&m_core->astat_drc.ai) +#define ASTAT_AF mem(&m_core->astat_drc.af) +#define ASTAT_MN mem(&m_core->astat_drc.mn) +#define ASTAT_MV mem(&m_core->astat_drc.mv) +#define ASTAT_MU mem(&m_core->astat_drc.mu) +#define ASTAT_MI mem(&m_core->astat_drc.mi) +#define ASTAT_SV mem(&m_core->astat_drc.sv) +#define ASTAT_SZ mem(&m_core->astat_drc.sz) +#define ASTAT_SS mem(&m_core->astat_drc.ss) +#define ASTAT_BTF mem(&m_core->astat_drc.btf) +#define FLAG0 mem(&m_core->flag[0]) +#define FLAG1 mem(&m_core->flag[1]) +#define FLAG2 mem(&m_core->flag[2]) +#define FLAG3 mem(&m_core->flag[3]) +#define CURLCNTR mem(&m_core->curlcntr) +#define LCNTR mem(&m_core->lcntr) +#define PCSTK mem(&m_core->pcstk) +#define PCSTKP mem(&m_core->pcstkp) +#define STKY mem(&m_core->stky) +#define LSTKP mem(&m_core->lstkp) +#define USTAT1 mem(&m_core->ustat1) +#define USTAT2 mem(&m_core->ustat2) +#define IRPTL mem(&m_core->irptl) +#define MODE1 mem(&m_core->mode1) +#define MODE2 mem(&m_core->mode2) +#define IMASK mem(&m_core->imask) +#define IMASKP mem(&m_core->imaskp) +#define MRF mem(&m_core->mrf) +#define MRB mem(&m_core->mrb) + +#define AZ_CALC_REQUIRED ((desc->regreq[0] & 0x00010000) || desc->flags & OPFLAG_IN_DELAY_SLOT) +#define AV_CALC_REQUIRED ((desc->regreq[0] & 0x00020000) || desc->flags & OPFLAG_IN_DELAY_SLOT) +#define AN_CALC_REQUIRED ((desc->regreq[0] & 0x00040000) || desc->flags & OPFLAG_IN_DELAY_SLOT) +#define AC_CALC_REQUIRED ((desc->regreq[0] & 0x00080000) || desc->flags & OPFLAG_IN_DELAY_SLOT) +#define AS_CALC_REQUIRED ((desc->regreq[0] & 0x00100000) || desc->flags & OPFLAG_IN_DELAY_SLOT) +#define AI_CALC_REQUIRED ((desc->regreq[0] & 0x00200000) || desc->flags & OPFLAG_IN_DELAY_SLOT) +#define MN_CALC_REQUIRED ((desc->regreq[0] & 0x00400000) || desc->flags & OPFLAG_IN_DELAY_SLOT) +#define MV_CALC_REQUIRED ((desc->regreq[0] & 0x00800000) || desc->flags & OPFLAG_IN_DELAY_SLOT) +#define MU_CALC_REQUIRED ((desc->regreq[0] & 0x01000000) || desc->flags & OPFLAG_IN_DELAY_SLOT) +#define MI_CALC_REQUIRED ((desc->regreq[0] & 0x02000000) || desc->flags & OPFLAG_IN_DELAY_SLOT) +#define SV_CALC_REQUIRED ((desc->regreq[0] & 0x04000000) || desc->flags & OPFLAG_IN_DELAY_SLOT) +#define SZ_CALC_REQUIRED ((desc->regreq[0] & 0x08000000) || desc->flags & OPFLAG_IN_DELAY_SLOT) +#define SS_CALC_REQUIRED ((desc->regreq[0] & 0x10000000) || desc->flags & OPFLAG_IN_DELAY_SLOT) +#define BTF_CALC_REQUIRED ((desc->regreq[0] & 0x20000000) || desc->flags & OPFLAG_IN_DELAY_SLOT) +#define AF_CALC_REQUIRED ((desc->regreq[0] & 0x40000000) || desc->flags & OPFLAG_IN_DELAY_SLOT) + + +#define IRAM_BLOCK0_START 0x20000 +#define IRAM_BLOCK0_END 0x27fff +#define IRAM_BLOCK1_START 0x28000 +#define IRAM_BLOCK1_END 0x3ffff +#define IRAM_SHORT_BLOCK0_START 0x40000 +#define IRAM_SHORT_BLOCK0_END 0x4ffff +#define IRAM_SHORT_BLOCK1_START 0x50000 +#define IRAM_SHORT_BLOCK1_END 0x7ffff +#define IOP_REGISTER_START 0x00000 +#define IOP_REGISTER_END 0x000ff +#define IRAM_END 0x7ffff + + +inline void adsp21062_device::alloc_handle(drcuml_state *drcuml, code_handle **handleptr, const char *name) +{ + if (*handleptr == nullptr) + *handleptr = drcuml->handle_alloc(name); +} + + + +static void cfunc_unimplemented(void *param) +{ + adsp21062_device *sharc = (adsp21062_device *)param; + sharc->sharc_cfunc_unimplemented(); +} + +static void cfunc_read_iop(void *param) +{ + adsp21062_device *sharc = (adsp21062_device *)param; + sharc->sharc_cfunc_read_iop(); +} + +static void cfunc_write_iop(void *param) +{ + adsp21062_device *sharc = (adsp21062_device *)param; + sharc->sharc_cfunc_write_iop(); +} + +static void cfunc_pcstack_overflow(void *param) +{ + adsp21062_device *sharc = (adsp21062_device *)param; + sharc->sharc_cfunc_pcstack_overflow(); +} + +static void cfunc_pcstack_underflow(void *param) +{ + adsp21062_device *sharc = (adsp21062_device *)param; + sharc->sharc_cfunc_pcstack_underflow(); +} + +static void cfunc_loopstack_overflow(void *param) +{ + adsp21062_device *sharc = (adsp21062_device *)param; + sharc->sharc_cfunc_loopstack_overflow(); +} + +static void cfunc_loopstack_underflow(void *param) +{ + adsp21062_device *sharc = (adsp21062_device *)param; + sharc->sharc_cfunc_loopstack_underflow(); +} + +static void cfunc_statusstack_overflow(void *param) +{ + adsp21062_device *sharc = (adsp21062_device *)param; + sharc->sharc_cfunc_statusstack_overflow(); +} + +static void cfunc_statusstack_underflow(void *param) +{ + adsp21062_device *sharc = (adsp21062_device *)param; + sharc->sharc_cfunc_statusstack_underflow(); +} + +static void cfunc_unimplemented_compute(void *param) +{ + adsp21062_device *sharc = (adsp21062_device *)param; + sharc->sharc_cfunc_unimplemented_compute(); +} + +static void cfunc_unimplemented_shiftimm(void *param) +{ + adsp21062_device *sharc = (adsp21062_device *)param; + sharc->sharc_cfunc_unimplemented_shiftimm(); +} + + +#if WRITE_SNOOP +void adsp21062_device::sharc_cfunc_write_snoop() +{ + printf("Write %08X to %08X at %08X\n", m_core->arg0, m_core->arg1, m_core->arg2); +} + +static void cfunc_write_snoop(void *param) +{ + adsp21062_device *sharc = (adsp21062_device *)param; + sharc->sharc_cfunc_write_snoop(); +} +#endif + + +void adsp21062_device::sharc_cfunc_unimplemented() +{ + UINT64 op = m_core->arg64; + fatalerror("PC=%08X: Unimplemented op %04X%08X\n", m_core->pc, (UINT32)(op >> 32), (UINT32)(op)); +} + +void adsp21062_device::sharc_cfunc_unimplemented_compute() +{ + UINT64 op = m_core->arg64; + fatalerror("PC=%08X: Unimplemented compute %04X%08X\n", m_core->pc, (UINT32)(op >> 32), (UINT32)(op)); +} + +void adsp21062_device::sharc_cfunc_unimplemented_shiftimm() +{ + UINT64 op = m_core->arg64; + fatalerror("PC=%08X: Unimplemented shiftimm %04X%08X\n", m_core->pc, (UINT32)(op >> 32), (UINT32)(op)); +} + +void adsp21062_device::sharc_cfunc_read_iop() +{ + m_core->arg1 = sharc_iop_r(m_core->arg0); +} + +void adsp21062_device::sharc_cfunc_write_iop() +{ + sharc_iop_w(m_core->arg0, m_core->arg1); +} + +void adsp21062_device::sharc_cfunc_pcstack_overflow() +{ + fatalerror("SHARC: PCStack overflow"); +} + +void adsp21062_device::sharc_cfunc_pcstack_underflow() +{ + fatalerror("SHARC: PCStack underflow"); +} + +void adsp21062_device::sharc_cfunc_loopstack_overflow() +{ + fatalerror("SHARC: Loop Stack overflow"); +} + +void adsp21062_device::sharc_cfunc_loopstack_underflow() +{ + fatalerror("SHARC: Loop Stack underflow"); +} + +void adsp21062_device::sharc_cfunc_statusstack_overflow() +{ + fatalerror("SHARC: Status Stack overflow"); +} + +void adsp21062_device::sharc_cfunc_statusstack_underflow() +{ + fatalerror("SHARC: Status Stack underflow"); +} + + +bool adsp21062_device::if_condition_always_true(int condition) +{ + if (condition == 0x1f || condition == 0x1e) + return true; + else + return false; +} + +UINT32 adsp21062_device::do_condition_astat_bits(int condition) +{ + UINT32 r = 0; + switch (condition) + { + case 0x00: r = AZ; break; // EQ + case 0x01: r = AZ | AN; break; // LT + case 0x02: r = AZ | AN; break; // LE + case 0x03: r = AC; break; // AC + case 0x04: r = AV; break; // AV + case 0x05: r = MV; break; // MV + case 0x06: r = MN; break; // MS + case 0x07: r = SV; break; // SV + case 0x08: r = SZ; break; // SZ + case 0x0d: r = BTF; break; // TF + case 0x10: r = AZ; break; // NOT EQUAL + case 0x11: r = AZ | AN; break; // GE + case 0x12: r = AZ | AN; break; // GT + case 0x13: r = AC; break; // NOT AC + case 0x14: r = AV; break; // NOT AV + case 0x15: r = MV; break; // NOT MV + case 0x16: r = MN; break; // NOT MS + case 0x17: r = SV; break; // NOT SV + case 0x18: r = SZ; break; // NOT SZ + case 0x1d: r = BTF; break; // NOT TF + } + + return r; +} + + +/*------------------------------------------------- +load_fast_iregs - load any fast integer +registers +-------------------------------------------------*/ + +inline void adsp21062_device::load_fast_iregs(drcuml_block *block) +{ + int regnum; + + for (regnum = 0; regnum < ARRAY_LENGTH(m_regmap); regnum++) + { + if (m_regmap[regnum].is_int_register()) + { + UML_MOV(block, ireg(m_regmap[regnum].ireg() - REG_I0), mem(&m_core->r[regnum])); + } + } +} + + +/*------------------------------------------------- +save_fast_iregs - save any fast integer +registers +-------------------------------------------------*/ + +void adsp21062_device::save_fast_iregs(drcuml_block *block) +{ + int regnum; + + for (regnum = 0; regnum < ARRAY_LENGTH(m_regmap); regnum++) + { + if (m_regmap[regnum].is_int_register()) + { + UML_MOV(block, mem(&m_core->r[regnum]), ireg(m_regmap[regnum].ireg() - REG_I0)); + } + } +} + +void adsp21062_device::static_generate_memory_accessor(MEM_ACCESSOR_TYPE type, const char *name, code_handle *&handleptr) +{ + // I0 = read/write data + // I1 = address + // I2 is trashed + + void* block0 = &m_internal_ram_block0[0]; + void* block0_1 = &m_internal_ram_block0[1]; + void* block0_2 = &m_internal_ram_block0[2]; + void* block1 = &m_internal_ram_block1[0]; + void* block1_1 = &m_internal_ram_block1[1]; + void* block1_2 = &m_internal_ram_block1[2]; + + code_label label = 1; + + drcuml_block *block = m_drcuml->begin_block(1024); + + // add a global entry for this + alloc_handle(m_drcuml.get(), &handleptr, name); + UML_HANDLE(block, *handleptr); // handle *handleptr + + switch (type) + { + case MEM_ACCESSOR_PM_READ48: + UML_CMP(block, I1, IRAM_BLOCK0_START); // cmp i1,IRAM_BLOCK0_START + UML_JMPc(block, COND_B, label); // jb label1 + UML_CMP(block, I1, IRAM_BLOCK0_END); // cmp i1,IRAM_BLOCK0_END + UML_JMPc(block, COND_A, label); // ja label1 + + // 0x20000 ... 0x27fff + UML_AND(block, I1, I1, 0x7fff); // and i1,i1,0x7fff + UML_MULS(block, I1, I1, I1, 3); // muls i1,3 + UML_DLOAD(block, I0, block0, I1, SIZE_WORD, SCALE_x2); // dload i0,[block0],i1,word,scale_x2 + UML_DSHL(block, I0, I0, 32); // dshl i0,i0,32 + UML_DLOAD(block, I2, block0_1, I1, SIZE_WORD, SCALE_x2); // dload i2,[block0_1],i1,word,scale_x2 + UML_DSHL(block, I2, I2, 16); // dshl i2,i2,16 + UML_DOR(block, I0, I0, I2); // dor i0,i0,i2 + UML_DLOAD(block, I2, block0_2, I1, SIZE_WORD, SCALE_x2); // dload i2,[block0_2],i1,word,scale_x2 + UML_DOR(block, I0, I0, I2); // dor i0,i0,i2 + UML_RET(block); // ret + + UML_LABEL(block, label++); // label1: + UML_CMP(block, I1, IRAM_BLOCK1_START); // cmp i1,IRAM_BLOCK1_START + UML_JMPc(block, COND_B, label); // jb label2 + UML_CMP(block, I1, IRAM_BLOCK1_END); // cmp i1,IRAM_BLOCK1_END + UML_JMPc(block, COND_A, label); // ja label2 + + // 0x28000 ... 0x3ffff + UML_AND(block, I1, I1, 0x7fff); // and i1,i1,0x7fff (block 1 is mirrored in 0x28000...2ffff, 0x30000...0x37fff and 0x38000...3ffff) + UML_MULS(block, I1, I1, I1, 3); // muls i1,3 + UML_DLOAD(block, I0, block1, I1, SIZE_WORD, SCALE_x2); // dload i0,[block1],i1,word,scale_x2 + UML_DSHL(block, I0, I0, 32); // dshl i0,i0,32 + UML_DLOAD(block, I2, block1_1, I1, SIZE_WORD, SCALE_x2); // dload i2,[block1_1],i1,word,scale_x2 + UML_DSHL(block, I2, I2, 16); // dshl i2,i2,16 + UML_DOR(block, I0, I0, I2); // dor i0,i0,i2 + UML_DLOAD(block, I2, block1_2, I1, SIZE_WORD, SCALE_x2); // dload i2,[block1_2],i1,word,scale_x2 + UML_DOR(block, I0, I0, I2); // dor i0,i0,i2 + UML_RET(block); // ret + + UML_LABEL(block, label++); // label2: + break; + + case MEM_ACCESSOR_PM_WRITE48: + UML_CMP(block, I1, IRAM_BLOCK0_START); // cmp i1,IRAM_BLOCK0_START + UML_JMPc(block, COND_B, label); // jb label1 + UML_CMP(block, I1, IRAM_BLOCK0_END); // cmp i1,IRAM_BLOCK0_END + UML_JMPc(block, COND_A, label); // ja label1 + + // 0x20000 ... 0x27fff + UML_AND(block, I1, I1, 0x7fff); // and i1,i1,0x7fff + UML_MULS(block, I1, I1, I1, 3); // muls i1,3 + UML_DSTORE(block, block0_2, I1, I0, SIZE_WORD, SCALE_x2); // dstore [block0_2],i1,i0,word,scale_x2 + UML_DSHR(block, I0, I0, 16); // dshr i0,i0,16 + UML_DSTORE(block, block0_1, I1, I0, SIZE_WORD, SCALE_x2); // dstore [block0_1],i1,i0,word,scale_x2 + UML_DSHR(block, I0, I0, 16); // dshr i0,i0,16 + UML_DSTORE(block, block0, I1, I0, SIZE_WORD, SCALE_x2); // dstore [block0],i1,i0,word,scale_x2 + UML_MOV(block, mem(&m_core->force_recompile), 1); + UML_RET(block); // ret + + UML_LABEL(block, label++); // label1: + UML_CMP(block, I1, IRAM_BLOCK1_START); // cmp i1,IRAM_BLOCK1_START + UML_JMPc(block, COND_B, label); // jb label2 + UML_CMP(block, I1, IRAM_BLOCK1_END); // cmp i1,IRAM_BLOCK1_END + UML_JMPc(block, COND_A, label); // ja label2 + + // 0x28000 ... 0x3ffff + UML_AND(block, I1, I1, 0x7fff); // and i1,i1,0x7fff (block 1 is mirrored in 0x28000...2ffff, 0x30000...0x37fff and 0x38000...3ffff) + UML_MULS(block, I1, I1, I1, 3); // muls i1,3 + UML_DSTORE(block, block1_2, I1, I0, SIZE_WORD, SCALE_x2); // dstore [block1_2],i1,i0,word,scale_x2 + UML_DSHR(block, I0, I0, 16); // dshr i0,i0,16 + UML_DSTORE(block, block1_1, I1, I0, SIZE_WORD, SCALE_x2); // dstore [block1_1],i1,i0,word,scale_x2 + UML_DSHR(block, I0, I0, 16); // dshr i0,i0,16 + UML_DSTORE(block, block1, I1, I0, SIZE_WORD, SCALE_x2); // dstore [block1],i1,i0,word,scale_x2 + UML_RET(block); // ret + + UML_LABEL(block, label++); // label2: + break; + + case MEM_ACCESSOR_PM_READ32: + UML_CMP(block, I1, IRAM_BLOCK0_START); // cmp i1,IRAM_BLOCK0_START + UML_JMPc(block, COND_B, label); // jb label1 + UML_CMP(block, I1, IRAM_BLOCK0_END); // cmp i1,IRAM_BLOCK0_END + UML_JMPc(block, COND_A, label); // ja label1 + + // 0x20000 ... 0x27fff + UML_AND(block, I1, I1, 0x7fff); // and i1,i1,0x7fff + UML_MULS(block, I1, I1, I1, 3); // muls i1,3 + UML_LOAD(block, I0, block0, I1, SIZE_WORD, SCALE_x2); // load i0,[block0],i1,word,scale_x2 + UML_SHL(block, I0, I0, 16); // shl i0,i0,16 + UML_LOAD(block, I2, block0_1, I1, SIZE_WORD, SCALE_x2); // load i2,[block0_1],i1,word,scale_x2 + UML_OR(block, I0, I0, I2); // or i0,i0,i2 + UML_RET(block); // ret + + UML_LABEL(block, label++); // label1: + UML_CMP(block, I1, IRAM_BLOCK1_START); // cmp i1,IRAM_BLOCK1_START + UML_JMPc(block, COND_B, label); // jb label2 + UML_CMP(block, I1, IRAM_BLOCK1_END); // cmp i1,IRAM_BLOCK1_END + UML_JMPc(block, COND_A, label); // ja label2 + + // 0x28000 ... 0x3ffff + UML_AND(block, I1, I1, 0x7fff); // and i1,i1,0x7fff (block 1 is mirrored in 0x28000...2ffff, 0x30000...0x37fff and 0x38000...3ffff) + UML_MULS(block, I1, I1, I1, 3); // muls i1,3 + UML_LOAD(block, I0, block1, I1, SIZE_WORD, SCALE_x2); // load i0,[block1],i1,word,scale_x2 + UML_SHL(block, I0, I0, 16); // shl i0,i0,16 + UML_LOAD(block, I2, block1_1, I1, SIZE_WORD, SCALE_x2); // load i2,[block1_1],i1,word,scale_x2 + UML_OR(block, I0, I0, I2); // or i0,i0,i2 + UML_RET(block); // ret + + UML_LABEL(block, label++); // label2: + break; + + case MEM_ACCESSOR_PM_WRITE32: + UML_CMP(block, I1, IRAM_BLOCK0_START); // cmp i1,IRAM_BLOCK0_START + UML_JMPc(block, COND_B, label); // jb label1 + UML_CMP(block, I1, IRAM_BLOCK0_END); // cmp i1,IRAM_BLOCK0_END + UML_JMPc(block, COND_A, label); // ja label1 + + // 0x20000 ... 0x27fff + UML_AND(block, I1, I1, 0x7fff); // and i1,i1,0x7fff + UML_MULS(block, I1, I1, I1, 3); // muls i1,3 + UML_STORE(block, block0_1, I1, I0, SIZE_WORD, SCALE_x2); // store [block0_1],i1,i0,word,scale_x2 + UML_SHR(block, I0, I0, 16); // shr i0,i0,16 + UML_STORE(block, block0, I1, I0, SIZE_WORD, SCALE_x2); // store [block0],i1,i0,word,scale_x2 + UML_RET(block); // ret + + UML_LABEL(block, label++); // label1: + UML_CMP(block, I1, IRAM_BLOCK1_START); // cmp i1,IRAM_BLOCK1_START + UML_JMPc(block, COND_B, label); // jb label2 + UML_CMP(block, I1, IRAM_BLOCK1_END); // cmp i1,IRAM_BLOCK1_END + UML_JMPc(block, COND_A, label); // ja label2 + + // 0x28000 ... 0x3ffff + UML_AND(block, I1, I1, 0x7fff); // and i1,i1,0x7fff (block 1 is mirrored in 0x28000...2ffff, 0x30000...0x37fff and 0x38000...3ffff) + UML_MULS(block, I1, I1, I1, 3); // muls i1,3 + UML_STORE(block, block1_1, I1, I0, SIZE_WORD, SCALE_x2); // store [block1_1],i1,i0,word,scale_x2 + UML_SHR(block, I0, I0, 16); // shr i0,i0,16 + UML_STORE(block, block1, I1, I0, SIZE_WORD, SCALE_x2); // store [block1],i1,i0,word,scale_x2 + UML_RET(block); // ret + + UML_LABEL(block, label++); // label2: + break; + + case MEM_ACCESSOR_DM_READ32: + UML_CMP(block, I1, IRAM_END); // cmp i1,IRAM_END + UML_JMPc(block, COND_BE, label); // jbe label1 + // 0x80000 ... + UML_SHL(block, I1, I1, 2); // shl i1,i1,2 + UML_READ(block, I0, I1, SIZE_DWORD, SPACE_DATA); // read i0,i1,dword,SPACE_DATA + UML_RET(block); + + UML_LABEL(block, label++); // label1: + UML_CMP(block, I1, IRAM_BLOCK0_START); // cmp i1,IRAM_BLOCK0_START + UML_JMPc(block, COND_B, label); // jb label2 + UML_CMP(block, I1, IRAM_BLOCK0_END); // cmp i1,IRAM_BLOCK0_END + UML_JMPc(block, COND_A, label); // ja label2 + // 0x20000 ... 0x27fff + UML_AND(block, I1, I1, 0x7fff); // and i1,i1,0x7fff + UML_LOAD(block, I0, block0, I1, SIZE_WORD, SCALE_x4); // load i0,[block0],i1,word,scale_x4 + UML_SHL(block, I0, I0, 16); // shl i0,i0,16 + UML_LOAD(block, I2, block0_1, I1, SIZE_WORD, SCALE_x4); // load i2,[block0_1],i1,word,scale_x4 + UML_OR(block, I0, I0, I2); // or i0,i0,i2 + UML_RET(block); + + UML_LABEL(block, label++); // label2: + UML_CMP(block, I1, IRAM_BLOCK1_START); // cmp i1,IRAM_BLOCK1_START + UML_JMPc(block, COND_B, label); // jb label3 + UML_CMP(block, I1, IRAM_BLOCK1_END); // cmp i1,IRAM_BLOCK1_END + UML_JMPc(block, COND_A, label); // ja label3 + // 0x28000 ... 0x3ffff + UML_AND(block, I1, I1, 0x7fff); // and i1,i1,0x7fff + UML_LOAD(block, I0, block1, I1, SIZE_WORD, SCALE_x4); // load i0,[block1],i1,word,scale_x4 + UML_SHL(block, I0, I0, 16); // shl i0,i0,16 + UML_LOAD(block, I2, block1_1, I1, SIZE_WORD, SCALE_x4); // load i2,[block1_1],i1,word,scale_x4 + UML_OR(block, I0, I0, I2); // or i0,i0,i2 + UML_RET(block); + + UML_LABEL(block, label++); // Label3: + UML_CMP(block, I1, IOP_REGISTER_END); // cmp i1,IOP_REGISTER_END + UML_JMPc(block, COND_A, label); // ja label4 + // IOP registers + UML_MOV(block, mem(&m_core->arg0), I1); // mov [m_core->arg0],i1 + UML_CALLC(block, cfunc_read_iop, this); // callc cfunc_read_iop + UML_MOV(block, I0, mem(&m_core->arg1)); // mov i0,[m_core->arg1] + UML_RET(block); + + UML_LABEL(block, label++); // label4: + UML_CMP(block, I1, IRAM_SHORT_BLOCK0_START); // cmp i1,IRAM_SHORT_BLOCK0_START + UML_JMPc(block, COND_B, label+1); // jb label6 + UML_CMP(block, I1, IRAM_SHORT_BLOCK0_END); // cmp i1,IRAM_SHORT_BLOCK0_END + UML_JMPc(block, COND_A, label+1); // ja label6 + // 0x40000 ... 0x4ffff + UML_AND(block, I1, I1, 0xffff); // and i1,i1,0xffff + UML_XOR(block, I1, I1, 1); // xor i1,i1,1 + UML_TEST(block, mem(&m_core->mode1), 0x4000); // test [m_core->mode1],0x4000 + UML_JMPc(block, COND_Z, label); // jz label5 + UML_LOADS(block, I0, block0, I1, SIZE_WORD, SCALE_x2); // loads i0,[block0],i1,word,scale_x2 + UML_RET(block); + UML_LABEL(block, label++); // label5: + UML_LOAD(block, I0, block0, I1, SIZE_WORD, SCALE_x2); // load i0,[block0],i1,word,scale_x2 + UML_RET(block); + + UML_LABEL(block, label++); // label6: + UML_CMP(block, I1, IRAM_SHORT_BLOCK1_START); // cmp i1,IRAM_SHORT_BLOCK1_START + UML_JMPc(block, COND_B, label+1); // jb label8 + UML_CMP(block, I1, IRAM_SHORT_BLOCK1_END); // cmp i1,IRAM_SHORT_BLOCK1_END + UML_JMPc(block, COND_A, label+1); // ja label8 + // 0x50000 ... 0x7ffff + UML_AND(block, I1, I1, 0xffff); // and i1,i1,0xffff + UML_XOR(block, I1, I1, 1); // xor i1,i1,1 + UML_TEST(block, mem(&m_core->mode1), 0x4000); // test [m_core->mode1],0x4000 + UML_JMPc(block, COND_Z, label); // jz label7 + UML_LOADS(block, I0, block1, I1, SIZE_WORD, SCALE_x2); // loads i0,[block1],i1,word,scale_x2 + UML_RET(block); + UML_LABEL(block, label++); // label7: + UML_LOAD(block, I0, block1, I1, SIZE_WORD, SCALE_x2); // load i0,[block1],i1,word,scale_x2 + UML_RET(block); + + UML_LABEL(block, label++); // label8: + break; + + case MEM_ACCESSOR_DM_WRITE32: +#if WRITE_SNOOP + //UML_CMP(block, I1, 0x283eb); + UML_CMP(block, I1, 0x2400047); + UML_JMPc(block, COND_NE, label); + UML_MOV(block, mem(&m_core->arg0), I0); + UML_MOV(block, mem(&m_core->arg1), I1); + UML_MOV(block, mem(&m_core->arg2), mem(&m_core->pc)); + UML_CALLC(block, cfunc_write_snoop, this); + UML_LABEL(block, label++); +#endif + + + UML_CMP(block, I1, IRAM_END); // cmp i1,IRAM_END + UML_JMPc(block, COND_BE, label); // jbe label1 + // 0x80000 ... + UML_SHL(block, I1, I1, 2); // shl i1,i1,2 + UML_WRITE(block, I1, I0, SIZE_DWORD, SPACE_DATA); // write i1,i0,dword,SPACE_DATA + UML_RET(block); + + UML_LABEL(block, label++); // label1: + UML_CMP(block, I1, IRAM_BLOCK0_START); // cmp i1,IRAM_BLOCK0_START + UML_JMPc(block, COND_B, label); // jb label2 + UML_CMP(block, I1, IRAM_BLOCK0_END); // cmp i1,IRAM_BLOCK0_END + UML_JMPc(block, COND_A, label); // ja label2 + // 0x20000 ... 0x27fff + UML_AND(block, I1, I1, 0x7fff); // and i1,i1,0x7fff + UML_STORE(block, block0_1, I1, I0, SIZE_WORD, SCALE_x4); // store [block0_1],i1,i0,word,scale_x4 + UML_SHR(block, I0, I0, 16); // shr i0,i0,16 + UML_STORE(block, block0, I1, I0, SIZE_WORD, SCALE_x4); // store [block0],i1,i0,word,scale_x4 + UML_RET(block); + + UML_LABEL(block, label++); // label2: + UML_CMP(block, I1, IRAM_BLOCK1_START); // cmp i1,IRAM_BLOCK1_START + UML_JMPc(block, COND_B, label); // jb label3 + UML_CMP(block, I1, IRAM_BLOCK1_END); // cmp i1,IRAM_BLOCK1_END + UML_JMPc(block, COND_A, label); // ja label3 + // 0x28000 ... 0x3ffff + UML_AND(block, I1, I1, 0x7fff); // and i1,i1,0x7fff + UML_STORE(block, block1_1, I1, I0, SIZE_WORD, SCALE_x4); // store [block1_1],i1,i0,word,scale_x4 + UML_SHR(block, I0, I0, 16); // shr i0,i0,16 + UML_STORE(block, block1, I1, I0, SIZE_WORD, SCALE_x4); // store [block1],i1,i0,word,scale_x4 + UML_RET(block); + + UML_LABEL(block, label++); // Label3: + UML_CMP(block, I1, IOP_REGISTER_END); // cmp i1,IOP_REGISTER_END + UML_JMPc(block, COND_A, label); // ja label4 + // IOP registers + UML_MOV(block, mem(&m_core->arg0), I1); // mov [m_core->arg0],i1 + UML_MOV(block, mem(&m_core->arg1), I0); // mov [m_core->arg1],i0 + UML_CALLC(block, cfunc_write_iop, this); // callc cfunc_write_iop + UML_RET(block); + + UML_LABEL(block, label++); // label4: + UML_CMP(block, I1, IRAM_SHORT_BLOCK0_START); // cmp i1,IRAM_SHORT_BLOCK0_START + UML_JMPc(block, COND_B, label); // jb label5 + UML_CMP(block, I1, IRAM_SHORT_BLOCK0_END); // cmp i1,IRAM_SHORT_BLOCK0_END + UML_JMPc(block, COND_A, label); // ja label5 + // 0x40000 ... 0x4ffff + UML_AND(block, I1, I1, 0xffff); // and i1,i1,0xffff + UML_XOR(block, I1, I1, 1); // xor i1,i1,1 + UML_STORE(block, block0, I1, I0, SIZE_WORD, SCALE_x2); // store [block0],i1,i0,word,scale_x2 + UML_RET(block); + + UML_LABEL(block, label++); // label5: + UML_CMP(block, I1, IRAM_SHORT_BLOCK1_START); // cmp i1,IRAM_SHORT_BLOCK1_START + UML_JMPc(block, COND_B, label); // jb label6 + UML_CMP(block, I1, IRAM_SHORT_BLOCK1_END); // cmp i1,IRAM_SHORT_BLOCK1_END + UML_JMPc(block, COND_A, label); // ja label6 + // 0x50000 ... 0x7ffff + UML_AND(block, I1, I1, 0xffff); // and i1,i1,0xffff + UML_XOR(block, I1, I1, 1); // xor i1,i1,1 + UML_STORE(block, block1, I1, I0, SIZE_WORD, SCALE_x2); // store [block1],i1,i0,word,scale_x2 + UML_RET(block); + + UML_LABEL(block, label++); // label6: + break; + } + + UML_RET(block); + + block->end(); +} + +void adsp21062_device::static_generate_push_pc() +{ + // Push contents of I0 to PC stack + // Trashes I1 + + code_label label = 1; + drcuml_block *block = m_drcuml->begin_block(32); + + // add a global entry for this + alloc_handle(m_drcuml.get(), &m_push_pc, "push_pc"); + UML_HANDLE(block, *m_push_pc); // handle *m_push_pc + + UML_MOV(block, I1, PCSTKP); // mov i1,PCSTKP + UML_ADD(block, I1, I1, 1); // add i1,i1,1 + UML_CMP(block, I1, 32); // cmp i1,32 + UML_JMPc(block, COND_L,label); // jl label1 + UML_CALLC(block, cfunc_pcstack_overflow, this); // callc cfunc_pcstack_overflow + + UML_LABEL(block, label++); // label1: + UML_CMP(block, I1, 0); // cmp i1,0 + UML_JMPc(block, COND_E, label); // je label2 + UML_AND(block, STKY, STKY, ~0x400000); // and STKY,~0x400000 + UML_JMP(block, label + 1); // jmp label3 + UML_LABEL(block, label++); // label2: + UML_OR(block, STKY, STKY, 0x400000); // or STKY,0x400000 + + UML_LABEL(block, label++); // label3: + UML_MOV(block, PCSTK, I0); // mov PCSTK,pc + UML_STORE(block, &m_core->pcstack, I1, I0, SIZE_DWORD, SCALE_x4); // store [m_core->pcstack],i1,i0,dword,scale_x4 + UML_MOV(block, PCSTKP, I1); // mov PCSTKP,i1 + + UML_RET(block); + + block->end(); +} + +void adsp21062_device::static_generate_pop_pc() +{ + // Pop PC stack into I0 + // Trashes I1 + + code_label label = 1; + drcuml_block *block = m_drcuml->begin_block(32); + + // add a global entry for this + alloc_handle(m_drcuml.get(), &m_pop_pc, "pop_pc"); + UML_HANDLE(block, *m_pop_pc); // handle *m_pop_pc + + UML_MOV(block, I1, PCSTKP); // mov i0,PCSTKP + UML_LOAD(block, I0, &m_core->pcstack, I1, SIZE_DWORD, SCALE_x4); // load i1,[m_core->pcstack],i0,dword,scale_x4 + UML_CMP(block, I1, 0); // cmp i1,0 + UML_JMPc(block, COND_NE, label); // jne label1 + UML_CALLC(block, cfunc_pcstack_underflow, this); // callc cfunc_pcstack_underflow + + UML_LABEL(block, label++); // label1: + UML_SUB(block, I1, I1, 1); // sub i1,i1,1 + UML_CMP(block, I1, 0); // cmp i1,0 + UML_JMPc(block, COND_E, label); // je label2 + UML_AND(block, STKY, STKY, ~0x400000); // and STKY,~0x400000 + UML_JMP(block, label + 1); // jmp label3 + UML_LABEL(block, label++); // label2: + UML_OR(block, STKY, STKY, 0x400000); // or STKY,0x400000 + + UML_LABEL(block, label++); // label3: + UML_MOV(block, PCSTKP, I1); // mov PCSTKP,i1 + UML_MOV(block, PCSTK, I0); // mov PCSTK,i0 + + UML_RET(block); + + block->end(); +} + +void adsp21062_device::static_generate_push_loop() +{ + // I0 = counter + // I1 = type/condition/addr + // Trashes I2 + + code_label label = 1; + drcuml_block *block = m_drcuml->begin_block(32); + + // add a global entry for this + alloc_handle(m_drcuml.get(), &m_push_loop, "push_loop"); + UML_HANDLE(block, *m_push_loop); // handle *m_push_loop + + UML_MOV(block, I2, LSTKP); // mov i2,LSTKP + UML_ADD(block, I2, I2, 1); // add i2,1 + UML_CMP(block, I2, 6); // cmp i2,6 + UML_JMPc(block, COND_L, label); // jl label1 + UML_CALLC(block, cfunc_loopstack_overflow, this); // callc cfunc_loopstack_overflow + + UML_LABEL(block, label++); // label1: + UML_CMP(block, I2, 0); // cmp i2,0 + UML_JMPc(block, COND_E, label); // je label2 + UML_AND(block, STKY, STKY, ~0x4000000); // and STKY,~0x4000000 + UML_JMP(block, label + 1); // jmp label3 + UML_LABEL(block, label++); // label2: + UML_OR(block, STKY, STKY, 0x4000000); // or STKY,0x4000000 + + UML_LABEL(block, label++); // label3: + + UML_STORE(block, m_core->lcstack, I2, I0, SIZE_DWORD, SCALE_x4); // store m_core->lcstack,i2,i0,dword,scale_x4 + UML_STORE(block, m_core->lastack, I2, I1, SIZE_DWORD, SCALE_x4); // store m_core->lastack,i2,i1,dword,scale_x4 + UML_MOV(block, CURLCNTR, I0); // mov CURLCNTR,i0 + UML_MOV(block, LSTKP, I2); // mov LSTKP,i2 + + UML_RET(block); + + block->end(); +} + +void adsp21062_device::static_generate_pop_loop() +{ + // Trashes I0,I2 + + code_label label = 1; + drcuml_block *block = m_drcuml->begin_block(32); + + // add a global entry for this + alloc_handle(m_drcuml.get(), &m_pop_loop, "pop_loop"); + UML_HANDLE(block, *m_pop_loop); // handle *m_pop_loop + + UML_MOV(block, I2, LSTKP); // mov i2,LSTKP + UML_CMP(block, I2, 0); // cmp i2,0 + UML_JMPc(block, COND_NE, label); // jne label1 + UML_CALLC(block, cfunc_loopstack_underflow, this); // callc cfunc_loopstack_underflow + + UML_LABEL(block, label++); // label1: + UML_SUB(block, I2, I2, 1); // sub i2,i2,1 + UML_CMP(block, I2, 0); // cmp i2,0 + UML_JMPc(block, COND_E, label); // je label2 + UML_AND(block, STKY, STKY, ~0x4000000); // and STKY,~0x4000000 + UML_JMP(block, label + 1); // jmp label3 + UML_LABEL(block, label++); // label2: + UML_OR(block, STKY, STKY, 0x4000000); // or STKY,0x4000000 + + UML_LABEL(block, label++); // label3: + UML_LOAD(block, I0, m_core->lcstack, I2, SIZE_DWORD, SCALE_x4); // load i0,m_core->lcstack,i2,dword,scale_x4 + UML_MOV(block, CURLCNTR, I0); // mov CURLCNTR,i0 + UML_MOV(block, LSTKP, I2); // mov LSTKP,i2 + + UML_RET(block); + + block->end(); +} + +void adsp21062_device::static_generate_push_status() +{ + // Trashes I2 + + code_label label = 1; + drcuml_block *block = m_drcuml->begin_block(32); + + // add a global entry for this + alloc_handle(m_drcuml.get(), &m_push_status, "push_status"); + UML_HANDLE(block, *m_push_status); // handle *m_push_status + + UML_MOV(block, I2, mem(&m_core->status_stkp)); // mov i2,[status_stkp] + UML_ADD(block, I2, I2, 1); // add i2,1 + UML_CMP(block, I2, 5); // cmp i2,5 + UML_JMPc(block, COND_L, label); // jl label1 + UML_CALLC(block, cfunc_statusstack_overflow, this); // callc cfunc_statusstack_overflow + + UML_LABEL(block, label++); // label1: + UML_CMP(block, I2, 0); // cmp i2,0 + UML_JMPc(block, COND_E, label); // je label2 + UML_AND(block, STKY, STKY, ~0x1000000); // and STKY,~0x1000000 + UML_JMP(block, label + 1); // jmp label3 + UML_LABEL(block, label++); // label2: + UML_OR(block, STKY, STKY, 0x1000000); // or STKY,0x1000000 + + UML_LABEL(block, label++); // label3: + UML_MOV(block, mem(&m_core->status_stkp), I2); // mov [status_stkp],i2 + + //TODO: load MODE1 + //TODO: load ASTAT + + UML_RET(block); + + block->end(); +} + +void adsp21062_device::static_generate_pop_status() +{ + // Trashes I2 + + code_label label = 1; + drcuml_block *block = m_drcuml->begin_block(32); + + // add a global entry for this + alloc_handle(m_drcuml.get(), &m_pop_status, "pop_status"); + UML_HANDLE(block, *m_pop_status); // handle *m_pop_status + + //TODO: store MODE1 + //TODO: store ASTAT + + UML_MOV(block, I2, mem(&m_core->status_stkp)); // mov i2,[status_stkp] + UML_CMP(block, I2, 0); // cmp i2,0 + UML_JMPc(block, COND_NE, label); // jl label1 + UML_CALLC(block, cfunc_statusstack_underflow, this); // callc cfunc_statusstack_underflow + + UML_LABEL(block, label++); // label1: + UML_SUB(block, I2, I2, 1); // sub i2,1 + UML_CMP(block, I2, 0); // cmp i2,0 + UML_JMPc(block, COND_E, label); // je label2 + UML_AND(block, STKY, STKY, ~0x1000000); // and STKY,~0x1000000 + UML_JMP(block, label + 1); // jmp label3 + UML_LABEL(block, label++); // label2: + UML_OR(block, STKY, STKY, 0x1000000); // or STKY,0x1000000 + + UML_LABEL(block, label++); // label3: + UML_MOV(block, mem(&m_core->status_stkp), I2); // mov [status_stkp],i2 + + UML_RET(block); + + block->end(); +} + + +void adsp21062_device::static_generate_exception(UINT8 exception, const char *name) +{ + code_handle *&exception_handle = m_exception[exception]; + + code_label label = 1; + + code_label label_nopush = label++; + + /* begin generating */ + drcuml_block *block = m_drcuml->begin_block(1024); + + /* add a global entry for this */ + alloc_handle(m_drcuml.get(), &exception_handle, name); + UML_HANDLE(block, *exception_handle); // handle name + + UML_AND(block, I3, mem(&m_core->irq_pending), IMASK); // and i3,[irq_pending],IMASK + UML_TZCNT(block, I3, I3); // tzcnt i3,i3 + + UML_MOV(block, I2, 1); // mov i2,1 + UML_SHL(block, I2, I2, I3); // shl i2,i2,i3 + UML_OR(block, IRPTL, IRPTL, I2); // or IRPTL,i2 + UML_XOR(block, mem(&m_core->irq_pending), mem(&m_core->irq_pending), I2); // xor [irq_pending],i2 + UML_MOV(block, mem(&m_core->active_irq_num), I3); // mov [active_irq_num],i3 + UML_MOV(block, mem(&m_core->interrupt_active), 1); // mov [interrupt_active],1 + + UML_CALLH(block, *m_push_pc); // callh m_push_pc + + UML_CMP(block, I3, 6); // cmp i3,6 + UML_JMPc(block, COND_L, label_nopush); // jl label_nopush + UML_CMP(block, I3, 8); // cmp i3,8 + UML_JMPc(block, COND_G, label_nopush); // jg label_nopush + UML_CALLH(block, *m_push_status); // callh m_push_status + + UML_LABEL(block, label_nopush); // label_nopush: + UML_SHL(block, I0, I3, 2); // shl i0,i3,2 + UML_ADD(block, I0, I0, 0x20000); // add i0,0x20000 + UML_HASHJMP(block, 0, I0, *m_nocode); // hashjmp i0,m_nocode + + block->end(); +} + + +void adsp21062_device::static_generate_mode1_ops() +{ + drcuml_block *block; + + // TODO: these could be further optimized with 64-bit or 128-bit swaps + // e.g SWAP128 instruction (swap 128 bits between 2 memory locations) + + block = m_drcuml->begin_block(128); + alloc_handle(m_drcuml.get(), &m_swap_dag1_0_3, "swap_dag1_0_3"); + UML_HANDLE(block, *m_swap_dag1_0_3); // handle name +#if !USE_SWAPDQ + for (int i = 0; i < 4; i++) + { + UML_MOV(block, I0, mem(&m_core->dag1.i[i])); + UML_MOV(block, I1, mem(&m_core->dag1_alt.i[i])); + UML_MOV(block, mem(&m_core->dag1.i[i]), I1); + UML_MOV(block, mem(&m_core->dag1_alt.i[i]), I0); + UML_MOV(block, I0, mem(&m_core->dag1.m[i])); + UML_MOV(block, I1, mem(&m_core->dag1_alt.m[i])); + UML_MOV(block, mem(&m_core->dag1.m[i]), I1); + UML_MOV(block, mem(&m_core->dag1_alt.m[i]), I0); + UML_MOV(block, I0, mem(&m_core->dag1.l[i])); + UML_MOV(block, I1, mem(&m_core->dag1_alt.l[i])); + UML_MOV(block, mem(&m_core->dag1.l[i]), I1); + UML_MOV(block, mem(&m_core->dag1_alt.l[i]), I0); + UML_MOV(block, I0, mem(&m_core->dag1.b[i])); + UML_MOV(block, I1, mem(&m_core->dag1_alt.b[i])); + UML_MOV(block, mem(&m_core->dag1.b[i]), I1); + UML_MOV(block, mem(&m_core->dag1_alt.b[i]), I0); + } +#else + UML_SWAPDQ(block, mem(&m_core->dag1.i[0]), mem(&m_core->dag1_alt.i[0])); + UML_SWAPDQ(block, mem(&m_core->dag1.m[0]), mem(&m_core->dag1_alt.m[0])); + UML_SWAPDQ(block, mem(&m_core->dag1.l[0]), mem(&m_core->dag1_alt.l[0])); + UML_SWAPDQ(block, mem(&m_core->dag1.b[0]), mem(&m_core->dag1_alt.b[0])); +#endif + UML_RET(block); + block->end(); + + block = m_drcuml->begin_block(128); + alloc_handle(m_drcuml.get(), &m_swap_dag1_4_7, "swap_dag1_4_7"); + UML_HANDLE(block, *m_swap_dag1_4_7); // handle name +#if !USE_SWAPDQ + for (int i = 4; i < 8; i++) + { + UML_MOV(block, I0, mem(&m_core->dag1.i[i])); + UML_MOV(block, I1, mem(&m_core->dag1_alt.i[i])); + UML_MOV(block, mem(&m_core->dag1.i[i]), I1); + UML_MOV(block, mem(&m_core->dag1_alt.i[i]), I0); + UML_MOV(block, I0, mem(&m_core->dag1.m[i])); + UML_MOV(block, I1, mem(&m_core->dag1_alt.m[i])); + UML_MOV(block, mem(&m_core->dag1.m[i]), I1); + UML_MOV(block, mem(&m_core->dag1_alt.m[i]), I0); + UML_MOV(block, I0, mem(&m_core->dag1.l[i])); + UML_MOV(block, I1, mem(&m_core->dag1_alt.l[i])); + UML_MOV(block, mem(&m_core->dag1.l[i]), I1); + UML_MOV(block, mem(&m_core->dag1_alt.l[i]), I0); + UML_MOV(block, I0, mem(&m_core->dag1.b[i])); + UML_MOV(block, I1, mem(&m_core->dag1_alt.b[i])); + UML_MOV(block, mem(&m_core->dag1.b[i]), I1); + UML_MOV(block, mem(&m_core->dag1_alt.b[i]), I0); + } +#else + UML_SWAPDQ(block, mem(&m_core->dag1.i[4]), mem(&m_core->dag1_alt.i[4])); + UML_SWAPDQ(block, mem(&m_core->dag1.m[4]), mem(&m_core->dag1_alt.m[4])); + UML_SWAPDQ(block, mem(&m_core->dag1.l[4]), mem(&m_core->dag1_alt.l[4])); + UML_SWAPDQ(block, mem(&m_core->dag1.b[4]), mem(&m_core->dag1_alt.b[4])); +#endif + UML_RET(block); + block->end(); + + block = m_drcuml->begin_block(128); + alloc_handle(m_drcuml.get(), &m_swap_dag2_0_3, "swap_dag2_0_3"); + UML_HANDLE(block, *m_swap_dag2_0_3); // handle name +#if !USE_SWAPDQ + for (int i = 0; i < 4; i++) + { + UML_MOV(block, I0, mem(&m_core->dag2.i[i])); + UML_MOV(block, I1, mem(&m_core->dag2_alt.i[i])); + UML_MOV(block, mem(&m_core->dag2.i[i]), I1); + UML_MOV(block, mem(&m_core->dag2_alt.i[i]), I0); + UML_MOV(block, I0, mem(&m_core->dag2.m[i])); + UML_MOV(block, I1, mem(&m_core->dag2_alt.m[i])); + UML_MOV(block, mem(&m_core->dag2.m[i]), I1); + UML_MOV(block, mem(&m_core->dag2_alt.m[i]), I0); + UML_MOV(block, I0, mem(&m_core->dag2.l[i])); + UML_MOV(block, I1, mem(&m_core->dag2_alt.l[i])); + UML_MOV(block, mem(&m_core->dag2.l[i]), I1); + UML_MOV(block, mem(&m_core->dag2_alt.l[i]), I0); + UML_MOV(block, I0, mem(&m_core->dag2.b[i])); + UML_MOV(block, I1, mem(&m_core->dag2_alt.b[i])); + UML_MOV(block, mem(&m_core->dag2.b[i]), I1); + UML_MOV(block, mem(&m_core->dag2_alt.b[i]), I0); + } +#else + UML_SWAPDQ(block, mem(&m_core->dag2.i[0]), mem(&m_core->dag2_alt.i[0])); + UML_SWAPDQ(block, mem(&m_core->dag2.m[0]), mem(&m_core->dag2_alt.m[0])); + UML_SWAPDQ(block, mem(&m_core->dag2.l[0]), mem(&m_core->dag2_alt.l[0])); + UML_SWAPDQ(block, mem(&m_core->dag2.b[0]), mem(&m_core->dag2_alt.b[0])); +#endif + UML_RET(block); + block->end(); + + block = m_drcuml->begin_block(128); + alloc_handle(m_drcuml.get(), &m_swap_dag2_4_7, "swap_dag2_4_7"); + UML_HANDLE(block, *m_swap_dag2_4_7); // handle name +#if !USE_SWAPDQ + for (int i = 4; i < 8; i++) + { + UML_MOV(block, I0, mem(&m_core->dag2.i[i])); + UML_MOV(block, I1, mem(&m_core->dag2_alt.i[i])); + UML_MOV(block, mem(&m_core->dag2.i[i]), I1); + UML_MOV(block, mem(&m_core->dag2_alt.i[i]), I0); + UML_MOV(block, I0, mem(&m_core->dag2.m[i])); + UML_MOV(block, I1, mem(&m_core->dag2_alt.m[i])); + UML_MOV(block, mem(&m_core->dag2.m[i]), I1); + UML_MOV(block, mem(&m_core->dag2_alt.m[i]), I0); + UML_MOV(block, I0, mem(&m_core->dag2.l[i])); + UML_MOV(block, I1, mem(&m_core->dag2_alt.l[i])); + UML_MOV(block, mem(&m_core->dag2.l[i]), I1); + UML_MOV(block, mem(&m_core->dag2_alt.l[i]), I0); + UML_MOV(block, I0, mem(&m_core->dag2.b[i])); + UML_MOV(block, I1, mem(&m_core->dag2_alt.b[i])); + UML_MOV(block, mem(&m_core->dag2.b[i]), I1); + UML_MOV(block, mem(&m_core->dag2_alt.b[i]), I0); + } +#else + UML_SWAPDQ(block, mem(&m_core->dag2.i[4]), mem(&m_core->dag2_alt.i[4])); + UML_SWAPDQ(block, mem(&m_core->dag2.m[4]), mem(&m_core->dag2_alt.m[4])); + UML_SWAPDQ(block, mem(&m_core->dag2.l[4]), mem(&m_core->dag2_alt.l[4])); + UML_SWAPDQ(block, mem(&m_core->dag2.b[4]), mem(&m_core->dag2_alt.b[4])); +#endif + UML_RET(block); + block->end(); + + block = m_drcuml->begin_block(64); + alloc_handle(m_drcuml.get(), &m_swap_r0_7, "swap_r0_7"); + UML_HANDLE(block, *m_swap_r0_7); // handle name +#if !USE_SWAPDQ + for (int i = 0; i < 8; i++) + { + UML_MOV(block, I0, mem(&m_core->r[i])); + UML_MOV(block, I1, mem(&m_core->reg_alt[i])); + UML_MOV(block, mem(&m_core->r[i]), I1); + UML_MOV(block, mem(&m_core->reg_alt[i]), I0); + } +#else + UML_SWAPDQ(block, mem(&m_core->r[0]), mem(&m_core->reg_alt[0])); + UML_SWAPDQ(block, mem(&m_core->r[4]), mem(&m_core->reg_alt[4])); +#endif + UML_RET(block); + block->end(); + + block = m_drcuml->begin_block(64); + alloc_handle(m_drcuml.get(), &m_swap_r8_15, "swap_r8_15"); + UML_HANDLE(block, *m_swap_r8_15); // handle name +#if !USE_SWAPDQ + for (int i = 8; i < 16; i++) + { + UML_MOV(block, I0, mem(&m_core->r[i])); + UML_MOV(block, I1, mem(&m_core->reg_alt[i])); + UML_MOV(block, mem(&m_core->r[i]), I1); + UML_MOV(block, mem(&m_core->reg_alt[i]), I0); + } +#else + UML_SWAPDQ(block, mem(&m_core->r[8]), mem(&m_core->reg_alt[8])); + UML_SWAPDQ(block, mem(&m_core->r[12]), mem(&m_core->reg_alt[12])); +#endif + UML_RET(block); + block->end(); +} + + + + +void adsp21062_device::execute_run_drc() +{ + drcuml_state *drcuml = m_drcuml.get(); + int execute_result; + +// if (m_cache_dirty) +// printf("SHARC cache reset\n"); + + /* reset the cache if dirty */ + if (m_cache_dirty) + flush_cache(); + + m_cache_dirty = false; + m_core->force_recompile = 0; + + /* execute */ + do + { + execute_result = drcuml->execute(*m_entry); + + /* if we need to recompile, do it */ + if (execute_result == EXECUTE_MISSING_CODE) + { + compile_block(m_core->pc); + } + else if (execute_result == EXECUTE_UNMAPPED_CODE) + { + fatalerror("Attempted to execute unmapped code at PC=%08X\n", m_core->pc); + } + else if (execute_result == EXECUTE_RESET_CACHE) + { + flush_cache(); + } + } while (execute_result != EXECUTE_OUT_OF_CYCLES); +} + + +void adsp21062_device::compile_block(offs_t pc) +{ + compiler_state compiler = { 0 }; + + const opcode_desc *seqhead, *seqlast; + const opcode_desc *desclist; + bool override = false; + + drcuml_block *block; + + desclist = m_drcfe->describe_code(pc); + + bool succeeded = false; + while (!succeeded) + { + try + { + block = m_drcuml->begin_block(4096); + + for (seqhead = desclist; seqhead != nullptr; seqhead = seqlast->next()) + { + const opcode_desc *curdesc; + UINT32 nextpc; + + /* 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; + } + + /* 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); + + + // force recompilation at end of block, if needed + UML_CMP(block, mem(&m_core->force_recompile), 0); + UML_JMPc(block, COND_Z, compiler.labelnum); + UML_MOV(block, mem(&m_cache_dirty), 1); + UML_MOV(block, mem(&m_core->icount), 0); + UML_LABEL(block, compiler.labelnum++); + + + /* count off cycles and go there */ + generate_update_cycles(block, &compiler, nextpc, TRUE); // <subtract cycles> + + if (seqlast->next() == nullptr || seqlast->next()->pc != nextpc) + UML_HASHJMP(block, 0, nextpc, *m_nocode); // hashjmp <mode>,nextpc,nocode + } + + block->end(); + succeeded = true; + } + catch (drcuml_block::abort_compilation &) + { + flush_cache(); + } + } +} + + +void adsp21062_device::flush_cache() +{ + /* empty the transient cache contents */ + m_drcuml->reset(); + + m_drcfe->flush(); + + try + { + // generate the entry point and out-of-cycles handlers + static_generate_entry_point(); + static_generate_nocode_handler(); + static_generate_out_of_cycles(); + + // generate utility functions + static_generate_push_pc(); + static_generate_pop_pc(); + static_generate_push_loop(); + static_generate_pop_loop(); + static_generate_push_status(); + static_generate_pop_status(); + static_generate_mode1_ops(); + + // generate exception handlers + static_generate_exception(EXCEPTION_INTERRUPT, "exception_interrupt"); + + // generate memory accessors + static_generate_memory_accessor(MEM_ACCESSOR_PM_READ48, "pm_read48", m_pm_read48); + static_generate_memory_accessor(MEM_ACCESSOR_PM_WRITE48, "pm_write48", m_pm_write48); + static_generate_memory_accessor(MEM_ACCESSOR_PM_READ32, "pm_read32", m_pm_read32); + static_generate_memory_accessor(MEM_ACCESSOR_PM_WRITE32, "pm_write32", m_pm_write32); + static_generate_memory_accessor(MEM_ACCESSOR_DM_READ32, "dm_read32", m_dm_read32); + static_generate_memory_accessor(MEM_ACCESSOR_DM_WRITE32, "dm_write32", m_dm_write32); + } + catch (drcuml_block::abort_compilation &) + { + fatalerror("Error generating SHARC static handlers\n"); + } +} + + +void adsp21062_device::static_generate_entry_point() +{ + code_label skip = 1; + drcuml_block *block; + + /* begin generating */ + block = m_drcuml->begin_block(20); + + /* forward references */ + alloc_handle(m_drcuml.get(), &m_nocode, "nocode"); + alloc_handle(m_drcuml.get(), &m_exception[EXCEPTION_INTERRUPT], "exception_interrupt"); + + alloc_handle(m_drcuml.get(), &m_entry, "entry"); + UML_HANDLE(block, *m_entry); // handle entry + + load_fast_iregs(block); // <load fastregs> + + /* check for interrupts */ + UML_CMP(block, mem(&m_core->irq_pending), 0); // cmp [irq_pending],0 + UML_JMPc(block, COND_E, skip); // je skip + UML_CMP(block, mem(&m_core->interrupt_active), 0); // cmp [interrupt_active],0 + UML_JMPc(block, COND_NE, skip); // jne skip + UML_TEST(block, mem(&m_core->irq_pending), IMASK); // test [irq_pending],IMASK + UML_JMPc(block, COND_Z, skip); // jz skip + UML_TEST(block, mem(&m_core->mode1), MODE1_IRPTEN); // test MODE1,MODE1_IRPTEN + UML_JMPc(block, COND_Z, skip); // jz skip + + UML_MOV(block, I0, mem(&m_core->pc)); // mov i0,nextpc + UML_MOV(block, I1, 0); // mov i1,0 + UML_CALLH(block, *m_exception[EXCEPTION_INTERRUPT]); // callh m_exception[EXCEPTION_INTERRUPT] + + UML_LABEL(block, skip); + + /* generate a hash jump via the current mode and PC */ + UML_HASHJMP(block, 0, mem(&m_core->pc), *m_nocode); // hashjmp <mode>,<pc>,nocode + + block->end(); +} + + +void adsp21062_device::static_generate_nocode_handler() +{ + drcuml_block *block; + + /* begin generating */ + block = m_drcuml->begin_block(10); + + /* generate a hash jump via the current mode and PC */ + alloc_handle(m_drcuml.get(), &m_nocode, "nocode"); + UML_HANDLE(block, *m_nocode); // handle nocode + UML_GETEXP(block, I0); // getexp i0 + UML_MOV(block, mem(&m_core->pc), I0); // mov [pc],i0 + save_fast_iregs(block); // <save fastregs> + UML_EXIT(block, EXECUTE_MISSING_CODE); // exit EXECUTE_MISSING_CODE + + block->end(); +} + +void adsp21062_device::static_generate_out_of_cycles() +{ + drcuml_block *block; + + /* begin generating */ + block = m_drcuml->begin_block(10); + + /* generate a hash jump via the current mode and PC */ + alloc_handle(m_drcuml.get(), &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_core->pc), I0); // mov <pc>,i0 + save_fast_iregs(block); // <save fastregs> + UML_EXIT(block, EXECUTE_OUT_OF_CYCLES); // exit EXECUTE_OUT_OF_CYCLES + + block->end(); +} + + +void adsp21062_device::generate_sequence_instruction(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + /* 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 */ + UML_MAPVAR(block, MAPVAR_PC, desc->pc); // mapvar PC,desc->pc + + /* 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_core->pc), desc->pc); // mov [pc],desc->pc + save_fast_iregs(block); // <save fastregs> + UML_DEBUG(block, desc->pc); // debug desc->pc + } + + /* if we hit an unmapped address, fatal error */ + if (desc->flags & OPFLAG_COMPILER_UNMAPPED) + { + UML_MOV(block, mem(&m_core->pc), desc->pc); // mov [pc],desc->pc + save_fast_iregs(block); // <save fastregs> + UML_EXIT(block, EXECUTE_UNMAPPED_CODE); // exit EXECUTE_UNMAPPED_CODE + } + + /* if this is an invalid opcode, generate the exception now */ +// if (desc->flags & OPFLAG_INVALID_OPCODE) +// UML_EXH(block, *m_exception[EXCEPTION_PROGRAM], 0x80000); // exh exception_program,0x80000 + + /* unless this is a virtual no-op, it's a regular instruction */ + if (!(desc->flags & OPFLAG_VIRTUAL_NOOP)) + { + /* compile the instruction */ + if (!generate_opcode(block, compiler, desc)) + { + UML_MOV(block, mem(&m_core->pc), desc->pc); // mov [pc],desc->pc + UML_DMOV(block, mem(&m_core->arg64), desc->opptr.q[0]); // dmov [arg64],*desc->opptr.q + UML_CALLC(block, cfunc_unimplemented, this); // callc cfunc_unimplemented,ppc + } + } + + + // insert delayed MODE1 operation if needed + if (compiler->mode1_delay.counter > 0) + { + compiler->mode1_delay.counter--; + if (compiler->mode1_delay.counter <= 0) + { + switch (compiler->mode1_delay.mode) + { + case MODE1_WRITE_IMM: + generate_write_mode1_imm(block, compiler, desc, compiler->mode1_delay.data); + break; + case MODE1_WRITE_REG: + fatalerror("MODE1 delay REG"); + break; + case MODE1_SET: + generate_set_mode1_imm(block, compiler, desc, compiler->mode1_delay.data); + break; + case MODE1_CLEAR: + generate_clear_mode1_imm(block, compiler, desc, compiler->mode1_delay.data); + break; + case MODE1_TOGGLE: + fatalerror("MODE1 delay TOGGLE"); + break; + } + } + } + + + // insert loop check at this instruction if needed + if (desc->userflags & OP_USERFLAG_COUNTER_LOOP) + { + code_label label_expire = compiler->labelnum++; + UML_MOV(block, I1, mem(&m_core->lstkp)); // mov i1,[m_core->lstkp] + UML_LOAD(block, I0, m_core->lcstack, I1, SIZE_DWORD, SCALE_x4); // load i0,m_core->lcstack,i1,dword,scale_x4 + UML_SUB(block, I0, I0, 1); // sub i0,1 + UML_STORE(block, m_core->lcstack, I1, I0, SIZE_DWORD, SCALE_x4); // store m_core->lcstack,i1,i0,dword,scale_x4 + UML_SUB(block, CURLCNTR, CURLCNTR, 1); // sub CURLCNTR,1 + UML_JMPc(block, COND_E, label_expire); // jne label_expire + + generate_jump(block, compiler, desc, false, false, false); + + UML_LABEL(block, label_expire); // label_expire: + UML_CALLH(block, *m_pop_pc); // callh m_pop_pc + UML_CALLH(block, *m_pop_loop); // callh m_pop_loop + } + if (desc->userflags & OP_USERFLAG_COND_LOOP) + { + code_label label_expire = compiler->labelnum++; + + int condition = (desc->userflags & OP_USERFLAG_COND_FIELD) >> OP_USERFLAG_COND_FIELD_SHIFT; + generate_do_condition(block, compiler, desc, condition, label_expire, m_core->astat_delay_copy); + + generate_jump(block, compiler, desc, false, false, false); + + UML_LABEL(block, label_expire); + UML_CALLH(block, *m_pop_pc); + UML_CALLH(block, *m_pop_loop); + } + + // copy ASTAT bits over for conditional loop + if (desc->userflags & OP_USERFLAG_ASTAT_DELAY_COPY) + { + if (desc->userflags & OP_USERFLAG_ASTAT_DELAY_COPY_AZ) + UML_MOV(block, mem(&m_core->astat_delay_copy.az), mem(&m_core->astat_drc.az)); + if (desc->userflags & OP_USERFLAG_ASTAT_DELAY_COPY_AN) + UML_MOV(block, mem(&m_core->astat_delay_copy.an), mem(&m_core->astat_drc.an)); + if (desc->userflags & OP_USERFLAG_ASTAT_DELAY_COPY_AV) + UML_MOV(block, mem(&m_core->astat_delay_copy.av), mem(&m_core->astat_drc.av)); + if (desc->userflags & OP_USERFLAG_ASTAT_DELAY_COPY_AC) + UML_MOV(block, mem(&m_core->astat_delay_copy.ac), mem(&m_core->astat_drc.ac)); + if (desc->userflags & OP_USERFLAG_ASTAT_DELAY_COPY_MN) + UML_MOV(block, mem(&m_core->astat_delay_copy.mn), mem(&m_core->astat_drc.mn)); + if (desc->userflags & OP_USERFLAG_ASTAT_DELAY_COPY_MV) + UML_MOV(block, mem(&m_core->astat_delay_copy.mv), mem(&m_core->astat_drc.mv)); + if (desc->userflags & OP_USERFLAG_ASTAT_DELAY_COPY_SV) + UML_MOV(block, mem(&m_core->astat_delay_copy.sv), mem(&m_core->astat_drc.sv)); + if (desc->userflags & OP_USERFLAG_ASTAT_DELAY_COPY_SZ) + UML_MOV(block, mem(&m_core->astat_delay_copy.sz), mem(&m_core->astat_drc.sz)); + if (desc->userflags & OP_USERFLAG_ASTAT_DELAY_COPY_BTF) + UML_MOV(block, mem(&m_core->astat_delay_copy.btf), mem(&m_core->astat_drc.btf)); + } +} + +void adsp21062_device::generate_update_cycles(drcuml_block *block, compiler_state *compiler, uml::parameter param, int allow_exception) +{ + /* check full interrupts if pending */ + if (compiler->checkints) + { + code_label skip = compiler->labelnum++; + compiler->checkints = FALSE; + + UML_CMP(block, mem(&m_core->irq_pending), 0); // cmp [irq_pending],0 + UML_JMPc(block, COND_E, skip); // je skip + UML_CMP(block, mem(&m_core->interrupt_active), 0); // cmp [interrupt_active],0 + UML_JMPc(block, COND_NE, skip); // jne skip + UML_TEST(block, mem(&m_core->irq_pending), IMASK); // test [irq_pending],IMASK + UML_JMPc(block, COND_Z, skip); // jz skip + UML_TEST(block, mem(&m_core->mode1), MODE1_IRPTEN); // test MODE1,MODE1_IRPTEN + UML_JMPc(block, COND_Z, skip); // jz skip + + UML_MOV(block, I0, param); // mov i0,nextpc + UML_MOV(block, I1, compiler->cycles); // mov i1,cycles + UML_CALLH(block, *m_exception[EXCEPTION_INTERRUPT]); // callh m_exception[EXCEPTION_INTERRUPT] + + UML_LABEL(block, skip); + } + + /* account for cycles */ + if (compiler->cycles > 0) + { + UML_SUB(block, mem(&m_core->icount), mem(&m_core->icount), MAPVAR_CYCLES); // sub icount,icount,cycles + UML_MAPVAR(block, MAPVAR_CYCLES, 0); // mapvar cycles,0 + if (allow_exception) + UML_EXHc(block, COND_S, *m_out_of_cycles, param); // exh out_of_cycles,nextpc + } + compiler->cycles = 0; +} + +void adsp21062_device::generate_write_mode1_imm(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT32 data) +{ + code_label skip; + + // TODO: swap effects + if (data & 0x1) + fatalerror("generate_write_mode1_imm: tried to enable I8 bit reversing"); + if (data & 0x2) + fatalerror("generate_write_mode1_imm: tried to enable I0 bit reversing"); + if (data & 0x4) + fatalerror("generate_write_mode1_imm: tried to enable MR alternate"); + + // DAG1 regs 4-7 + skip = compiler->labelnum++; + UML_TEST(block, MODE1, 0x8); + UML_JMPc(block, (data & 0x8) ? COND_NZ : COND_Z, skip); // don't swap if the bits are same + UML_CALLH(block, *m_swap_dag1_4_7); + UML_LABEL(block, skip); + + // DAG1 regs 0-3 + skip = compiler->labelnum++; + UML_TEST(block, MODE1, 0x10); + UML_JMPc(block, (data & 0x10) ? COND_NZ : COND_Z, skip); // don't swap if the bits are same + UML_CALLH(block, *m_swap_dag1_0_3); + UML_LABEL(block, skip); + + // DAG2 regs 4-7 + skip = compiler->labelnum++; + UML_TEST(block, MODE1, 0x20); + UML_JMPc(block, (data & 0x20) ? COND_NZ : COND_Z, skip); // don't swap if the bits are same + UML_CALLH(block, *m_swap_dag2_4_7); + UML_LABEL(block, skip); + + // DAG2 regs 0-3 + skip = compiler->labelnum++; + UML_TEST(block, MODE1, 0x40); + UML_JMPc(block, (data & 0x40) ? COND_NZ : COND_Z, skip); // don't swap if the bits are same + UML_CALLH(block, *m_swap_dag2_0_3); + UML_LABEL(block, skip); + + // REG 8-15 + skip = compiler->labelnum++; + UML_TEST(block, MODE1, 0x80); + UML_JMPc(block, (data & 0x80) ? COND_NZ : COND_Z, skip); // don't swap if the bits are same + UML_CALLH(block, *m_swap_r8_15); + UML_LABEL(block, skip); + + // REG 0-7 + skip = compiler->labelnum++; + UML_TEST(block, MODE1, 0x400); + UML_JMPc(block, (data & 0x400) ? COND_NZ : COND_Z, skip); // don't swap if the bits are same + UML_CALLH(block, *m_swap_r0_7); + UML_LABEL(block, skip); + + UML_MOV(block, MODE1, data); +} + +void adsp21062_device::generate_set_mode1_imm(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT32 data) +{ + if (data & 0x1) + fatalerror("generate_set_mode1_imm: tried to enable I8 bit reversing"); + if (data & 0x2) + fatalerror("generate_set_mode1_imm: tried to enable I0 bit reversing"); + if (data & 0x4) + fatalerror("generate_set_mode1_imm: tried to enable MR alternate"); + if (data & 0x8) // DAG1 regs 4-7 + { + code_label skip = compiler->labelnum++; + UML_TEST(block, MODE1, 0x8); + UML_JMPc(block, COND_NZ, skip); // don't swap if the bit is already 1 + UML_CALLH(block, *m_swap_dag1_4_7); + UML_LABEL(block, skip); + } + if (data & 0x10) // DAG1 regs 0-3 + { + code_label skip = compiler->labelnum++; + UML_TEST(block, MODE1, 0x10); + UML_JMPc(block, COND_NZ, skip); // don't swap if the bit is already 1 + UML_CALLH(block, *m_swap_dag1_0_3); + UML_LABEL(block, skip); + } + if (data & 0x20) // DAG2 regs 4-7 + { + code_label skip = compiler->labelnum++; + UML_TEST(block, MODE1, 0x20); + UML_JMPc(block, COND_NZ, skip); // don't swap if the bit is already 1 + UML_CALLH(block, *m_swap_dag2_4_7); + UML_LABEL(block, skip); + } + if (data & 0x40) // DAG1 regs 0-3 + { + code_label skip = compiler->labelnum++; + UML_TEST(block, MODE1, 0x40); + UML_JMPc(block, COND_NZ, skip); // don't swap if the bit is already 1 + UML_CALLH(block, *m_swap_dag2_0_3); + UML_LABEL(block, skip); + } + if (data & 0x80) // REG 8-15 + { + code_label skip = compiler->labelnum++; + UML_TEST(block, MODE1, 0x80); + UML_JMPc(block, COND_NZ, skip); // don't swap if the bit is already 1 + UML_CALLH(block, *m_swap_r8_15); + UML_LABEL(block, skip); + } + if (data & 0x400) // REG 0-7 + { + code_label skip = compiler->labelnum++; + UML_TEST(block, MODE1, 0x400); + UML_JMPc(block, COND_NZ, skip); // don't swap if the bit is already 1 + UML_CALLH(block, *m_swap_r0_7); + UML_LABEL(block, skip); + } + + UML_OR(block, MODE1, MODE1, data); +} + +void adsp21062_device::generate_clear_mode1_imm(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT32 data) +{ + if (data & 0x1) + fatalerror("generate_clear_mode1_imm: tried to disable I8 bit reversing"); + if (data & 0x2) + fatalerror("generate_clear_mode1_imm: tried to disable I0 bit reversing"); + if (data & 0x4) + fatalerror("generate_clear_mode1_imm: tried to disable MR alternate"); + if (data & 0x8) // DAG1 regs 4-7 + { + code_label skip = compiler->labelnum++; + UML_TEST(block, MODE1, 0x8); + UML_JMPc(block, COND_Z, skip); // don't swap if the bit is already 0 + UML_CALLH(block, *m_swap_dag1_4_7); + UML_LABEL(block, skip); + } + if (data & 0x10) // DAG1 regs 0-3 + { + code_label skip = compiler->labelnum++; + UML_TEST(block, MODE1, 0x10); + UML_JMPc(block, COND_Z, skip); // don't swap if the bit is already 0 + UML_CALLH(block, *m_swap_dag1_0_3); + UML_LABEL(block, skip); + } + if (data & 0x20) // DAG2 regs 4-7 + { + code_label skip = compiler->labelnum++; + UML_TEST(block, MODE1, 0x20); + UML_JMPc(block, COND_Z, skip); // don't swap if the bit is already 0 + UML_CALLH(block, *m_swap_dag2_4_7); + UML_LABEL(block, skip); + } + if (data & 0x40) // DAG1 regs 0-3 + { + code_label skip = compiler->labelnum++; + UML_TEST(block, MODE1, 0x40); + UML_JMPc(block, COND_Z, skip); // don't swap if the bit is already 0 + UML_CALLH(block, *m_swap_dag2_0_3); + UML_LABEL(block, skip); + } + if (data & 0x80) // REG 8-15 + { + code_label skip = compiler->labelnum++; + UML_TEST(block, MODE1, 0x80); + UML_JMPc(block, COND_Z, skip); // don't swap if the bit is already 0 + UML_CALLH(block, *m_swap_r8_15); + UML_LABEL(block, skip); + } + if (data & 0x400) // REG 0-7 + { + code_label skip = compiler->labelnum++; + UML_TEST(block, MODE1, 0x400); + UML_JMPc(block, COND_Z, skip); // don't swap if the bit is already 0 + UML_CALLH(block, *m_swap_r0_7); + UML_LABEL(block, skip); + } + + UML_AND(block, MODE1, MODE1, ~data); +} + + + +void adsp21062_device::generate_update_circular_buffer(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int g, int i) +{ + // TODO +} + +void adsp21062_device::generate_astat_copy(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UML_MOV(block, mem(&m_core->astat_drc_copy.az), ASTAT_AZ); + UML_MOV(block, mem(&m_core->astat_drc_copy.av), ASTAT_AV); + UML_MOV(block, mem(&m_core->astat_drc_copy.an), ASTAT_AN); + UML_MOV(block, mem(&m_core->astat_drc_copy.av), ASTAT_AV); + UML_MOV(block, mem(&m_core->astat_drc_copy.as), ASTAT_AS); + UML_MOV(block, mem(&m_core->astat_drc_copy.ai), ASTAT_AI); + UML_MOV(block, mem(&m_core->astat_drc_copy.af), ASTAT_AF); + UML_MOV(block, mem(&m_core->astat_drc_copy.mn), ASTAT_MN); + UML_MOV(block, mem(&m_core->astat_drc_copy.mv), ASTAT_MV); + UML_MOV(block, mem(&m_core->astat_drc_copy.mu), ASTAT_MU); + UML_MOV(block, mem(&m_core->astat_drc_copy.mi), ASTAT_MI); + UML_MOV(block, mem(&m_core->astat_drc_copy.sv), ASTAT_SV); + UML_MOV(block, mem(&m_core->astat_drc_copy.sz), ASTAT_SZ); + UML_MOV(block, mem(&m_core->astat_drc_copy.ss), ASTAT_SS); + UML_MOV(block, mem(&m_core->astat_drc_copy.btf), ASTAT_BTF); + UML_MOV(block, mem(&m_core->astat_drc_copy.cacc), mem(&m_core->astat_drc.cacc)); +} + + + +void adsp21062_device::generate_call(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, bool delayslot) +{ + // I0 = target pc for dynamic branches + + compiler_state compiler_temp = *compiler; + + // save branch target + if (desc->targetpc == BRANCH_TARGET_DYNAMIC) + { + UML_MOV(block, mem(&m_core->jmpdest), I0); // mov [jmpdest],i0 + } + + // compile delay slots if needed + if (delayslot) + { + generate_sequence_instruction(block, &compiler_temp, desc->delay.first()); + generate_sequence_instruction(block, &compiler_temp, desc->delay.last()); + } + + if (delayslot) + UML_MOV(block, I0, desc->pc + 3); + else + UML_MOV(block, I0, desc->pc + 1); + UML_CALLH(block, *m_push_pc); + + // update cycles and hash jump + if (desc->targetpc != BRANCH_TARGET_DYNAMIC) + { + generate_update_cycles(block, &compiler_temp, desc->targetpc, TRUE); + if (desc->flags & OPFLAG_INTRABLOCK_BRANCH) + UML_JMP(block, desc->targetpc | 0x80000000); // jmp targetpc | 0x80000000 + else + UML_HASHJMP(block, 0, desc->targetpc, *m_nocode); // hashjmp 0,targetpc,nocode + } + else + { + generate_update_cycles(block, &compiler_temp, mem(&m_core->jmpdest), TRUE); + UML_HASHJMP(block, 0, mem(&m_core->jmpdest), *m_nocode); // hashjmp 0,jmpdest,nocode + } + + // update compiler 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 +} + +void adsp21062_device::generate_jump(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, bool delayslot, bool loopabort, bool clearint) +{ + // I0 = target pc for dynamic branches + + compiler_state compiler_temp = *compiler; + + // save branch target + if (desc->targetpc == BRANCH_TARGET_DYNAMIC) + { + UML_MOV(block, mem(&m_core->jmpdest), I0); // mov [jmpdest],i0 + } + + // compile delay slots if needed + if (delayslot) + { + generate_sequence_instruction(block, &compiler_temp, desc->delay.first()); + generate_sequence_instruction(block, &compiler_temp, desc->delay.last()); + } + + // update cycles and hash jump + if (desc->targetpc != BRANCH_TARGET_DYNAMIC) + { + generate_update_cycles(block, &compiler_temp, desc->targetpc, TRUE); + if (desc->flags & OPFLAG_INTRABLOCK_BRANCH) + UML_JMP(block, desc->targetpc | 0x80000000); // jmp targetpc | 0x80000000 + else + UML_HASHJMP(block, 0, desc->targetpc, *m_nocode); // hashjmp 0,targetpc,nocode + } + else + { + generate_update_cycles(block, &compiler_temp, mem(&m_core->jmpdest), TRUE); + UML_HASHJMP(block, 0, mem(&m_core->jmpdest), *m_nocode); // hashjmp 0,jmpdest,nocode + } + + // update compiler 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 +} + +/*------------------------------------------------- +generate_write_ureg - UREG is read into I0 +-------------------------------------------------*/ + +void adsp21062_device::generate_read_ureg(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int ureg, bool has_compute) +{ + // UREG is read into I0 + + switch (ureg) + { + // REG 0-15 + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + UML_MOV(block, I0, REG(ureg & 0xf)); + break; + // I0-7 + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + UML_MOV(block, I0, mem(&m_core->dag1.i[ureg & 7])); + break; + // I8-15 + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + UML_MOV(block, I0, mem(&m_core->dag2.i[ureg & 7])); + break; + // M0-7 + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + UML_MOV(block, I0, mem(&m_core->dag1.m[ureg & 7])); + break; + // M8-15 + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + UML_MOV(block, I0, mem(&m_core->dag2.m[ureg & 7])); + break; + // L0-7 + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: + UML_MOV(block, I0, mem(&m_core->dag1.l[ureg & 7])); + break; + // L8-15 + case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: + UML_MOV(block, I0, mem(&m_core->dag2.l[ureg & 7])); + break; + // B0-7 + case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: + UML_MOV(block, I0, mem(&m_core->dag1.b[ureg & 7])); + break; + // B8-15 + case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: + UML_MOV(block, I0, mem(&m_core->dag2.b[ureg & 7])); + break; + + case 0x64: // PCSTK + fatalerror("generate_read_ureg: PCSTK"); + break; + case 0x70: // USTAT1 + UML_MOV(block, I0, mem(&m_core->ustat1)); + break; + case 0x71: // USTAT2 + UML_MOV(block, I0, mem(&m_core->ustat2)); + break; + case 0x79: // IRPTL + UML_MOV(block, I0, mem(&m_core->irptl)); + break; + case 0x7a: // MODE2 + UML_MOV(block, I0, mem(&m_core->mode2)); + break; + case 0x7b: // MODE1 + UML_MOV(block, I0, mem(&m_core->mode1)); + break; + case 0x7c: // ASTAT + // construct from bits + if (!has_compute) + { + // no compute, just read normally from ASTAT + UML_XOR(block, I0, I0, I0); + UML_OR(block, I0, I0, ASTAT_AZ); + UML_SHL(block, I1, ASTAT_AV, 1); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, ASTAT_AN, 2); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, ASTAT_AC, 3); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, ASTAT_AS, 4); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, ASTAT_AI, 5); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, ASTAT_MN, 6); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, ASTAT_MV, 7); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, ASTAT_MU, 8); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, ASTAT_MI, 9); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, ASTAT_AF, 10); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, ASTAT_SV, 11); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, ASTAT_SZ, 12); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, ASTAT_SS, 13); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, ASTAT_BTF, 18); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, FLAG0, 19); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, FLAG1, 20); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, FLAG2, 21); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, FLAG3, 22); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, mem(&m_core->astat_drc.cacc), 24); + UML_OR(block, I0, I0, I1); + } + else + { + // read from ASTAT copy if this opcode also does compute + UML_XOR(block, I0, I0, I0); + UML_OR(block, I0, I0, mem(&m_core->astat_drc_copy.az)); + UML_SHL(block, I1, mem(&m_core->astat_drc_copy.av), 1); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, mem(&m_core->astat_drc_copy.an), 2); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, mem(&m_core->astat_drc_copy.ac), 3); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, mem(&m_core->astat_drc_copy.as), 4); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, mem(&m_core->astat_drc_copy.ai), 5); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, mem(&m_core->astat_drc_copy.mn), 6); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, mem(&m_core->astat_drc_copy.mv), 7); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, mem(&m_core->astat_drc_copy.mu), 8); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, mem(&m_core->astat_drc_copy.mi), 9); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, mem(&m_core->astat_drc_copy.af), 10); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, mem(&m_core->astat_drc_copy.sv), 11); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, mem(&m_core->astat_drc_copy.sz), 12); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, mem(&m_core->astat_drc_copy.ss), 13); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, mem(&m_core->astat_drc_copy.btf), 18); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, FLAG0, 19); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, FLAG1, 20); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, FLAG2, 21); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, FLAG3, 22); + UML_OR(block, I0, I0, I1); + UML_SHL(block, I1, mem(&m_core->astat_drc_copy.cacc), 24); + UML_OR(block, I0, I0, I1); + } + break; + case 0x7d: // IMASK + UML_MOV(block, I0, mem(&m_core->imask)); + break; + case 0x7e: // STKY + UML_MOV(block, I0, mem(&m_core->stky)); + break; + case 0xdb: // PX + UML_DMOV(block, I0, mem(&m_core->px)); // NOTE: this returns 64 bits + break; + case 0xdc: // PX1 (bits 0-15 of PX) + UML_MOV(block, I0, mem(&m_core->px)); + UML_AND(block, I0, I0, 0xffff); + break; + case 0xdd: // PX2 (bits 16-47 of PX) + UML_DMOV(block, I0, mem(&m_core->px)); + UML_DSHR(block, I0, I0, 16); + UML_DAND(block, I0, I0, 0xffffffff); + break; + + default: + fatalerror("generate_read_ureg %02X", ureg); + break; + } +} + + +/*------------------------------------------------- + generate_write_ureg - contents of register I0 or 32-bit immediate data are written into UREG +-------------------------------------------------*/ + +void adsp21062_device::generate_write_ureg(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int ureg, bool imm, UINT32 data) +{ + switch (ureg) + { + // REG 0-15 + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + UML_MOV(block, REG(ureg & 0xf), imm ? data : I0); + break; + // I0-7 + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + UML_MOV(block, DM_I(ureg & 7), imm ? data : I0); + break; + // I8-15 + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + UML_MOV(block, PM_I(ureg & 7), imm ? data : I0); + break; + // M0-7 + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + UML_MOV(block, DM_M(ureg & 7), imm ? data : I0); + break; + // M8-15 + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + UML_MOV(block, PM_M(ureg & 7), imm ? data : I0); + break; + // L0-7 + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: + UML_MOV(block, DM_L(ureg & 7), imm ? data : I0); + break; + // L8-15 + case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: + UML_MOV(block, PM_L(ureg & 7), imm ? data : I0); + break; + // B0-7 + case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: + // Note: loading B also loads the same value in I + UML_MOV(block, DM_B(ureg & 7), imm ? data : I0); + UML_MOV(block, DM_I(ureg & 7), imm ? data : I0); + break; + // B8-15 + case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: + // Note: loading B also loads the same value in I + UML_MOV(block, PM_B(ureg & 7), imm ? data : I0); + UML_MOV(block, PM_B(ureg & 7), imm ? data : I0); + break; + + case 0x64: // PCSTK + fatalerror("generate_write_ureg: PCSTK"); + break; + case 0x70: // USTAT1 + UML_MOV(block, mem(&m_core->ustat1), imm ? data : I0); + break; + case 0x71: // USTAT2 + UML_MOV(block, mem(&m_core->ustat2), imm ? data : I0); + break; + case 0x79: // IRPTL + UML_MOV(block, mem(&m_core->irptl), imm ? data : I0); + break; + case 0x7a: // MODE2 + UML_MOV(block, mem(&m_core->mode2), imm ? data : I0); + break; + case 0x7b: // MODE1 + // MODE1 needs to be written delayed + if (imm) + { + compiler->mode1_delay.counter = 2; + compiler->mode1_delay.data = data; + compiler->mode1_delay.mode = MODE1_WRITE_IMM; + } + else + { + compiler->mode1_delay.counter = 2; + compiler->mode1_delay.mode = MODE1_WRITE_REG; + UML_MOV(block, mem(&m_core->mode1_delay_data), I0); + } + break; + case 0x7c: // ASTAT + // TODO: needs bit break up + fatalerror("generate_write_ureg: ASTAT"); + break; + case 0x7d: // IMASK + UML_MOV(block, mem(&m_core->imask), imm ? data : I0); + break; + case 0x7e: // STKY + UML_MOV(block, mem(&m_core->stky), imm ? data : I0); + break; + case 0xdb: // PX + if (imm) + { + fatalerror("generate_write_ureg %02X with immediate!", ureg); + } + else + { + UML_DMOV(block, mem(&m_core->px), I0); + } + break; + case 0xdc: // PX1 (bits 0-15 of PX) + if (imm) + { + UML_DAND(block, mem(&m_core->px), mem(&m_core->px), ~0xffff); + UML_DOR(block, mem(&m_core->px), mem(&m_core->px), (UINT64)(data)); + } + else + { + UML_DAND(block, mem(&m_core->px), mem(&m_core->px), ~0xffff); + UML_DXOR(block, I1, I1, I1); + UML_DAND(block, I1, I0, 0xffff); + UML_DOR(block, mem(&m_core->px), mem(&m_core->px), I1); + } + break; + case 0xdd: // PX2 (bits 16-47 of PX) + if (imm) + { + UML_DAND(block, mem(&m_core->px), mem(&m_core->px), 0xffff); + UML_DOR(block, mem(&m_core->px), mem(&m_core->px), (UINT64)(data) << 16); + } + else + { + UML_DAND(block, mem(&m_core->px), mem(&m_core->px), 0xffff); + UML_DSHL(block, I0, I0, 16); + UML_DOR(block, mem(&m_core->px), mem(&m_core->px), I0); + } + break; + + default: + fatalerror("generate_write_ureg %02X", ureg); + break; + } +} + +int adsp21062_device::generate_opcode(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT64 opcode = desc->opptr.q[0]; + + switch ((opcode >> 45) & 7) + { + case 0: // subops + { + UINT32 subop = (opcode >> 40) & 0x1f; + switch (subop) + { + case 0x00: // NOP / idle |000|00000| + if (opcode & U64(0x008000000000)) + { + // IDLE + UML_MOV(block, mem(&m_core->idle), 1); + UML_MOV(block, mem(&m_core->icount), 0); + return TRUE; + } + else + { + // NOP + return TRUE; + } + break; + + case 0x01: // compute |000|00001| + { + int cond = (opcode >> 33) & 0x1f; + + bool has_condition = !if_condition_always_true(cond); + int skip_label = 0; + + if (has_condition) + { + skip_label = compiler->labelnum++; + generate_if_condition(block, compiler, desc, cond, skip_label); + } + + generate_compute(block, compiler, desc); + + if (has_condition) + UML_LABEL(block, skip_label); + return TRUE; + } + + case 0x02: // immediate shift |000|00010| + { + int shiftop = (opcode >> 16) & 0x3f; + int rn = (opcode >> 4) & 0xf; + int rx = (opcode & 0xf); + int cond = (opcode >> 33) & 0x1f; + int data = ((opcode >> 8) & 0xff) | ((opcode >> 19) & 0xf00); + + bool has_condition = !if_condition_always_true(cond); + int skip_label = 0; + + if (has_condition) + { + skip_label = compiler->labelnum++; + generate_if_condition(block, compiler, desc, cond, skip_label); + } + + generate_shift_imm(block, compiler, desc, data, shiftop, rn, rx); + + if (has_condition) + UML_LABEL(block, skip_label); + return TRUE; + } + + case 0x04: // compute / modify |000|00100| + { + int cond = (opcode >> 33) & 0x1f; + int compute = opcode & 0x7fffff; + int g = (opcode >> 38) & 0x1; + int m = (opcode >> 27) & 0x7; + int i = (opcode >> 30) & 0x7; + + bool has_condition = !if_condition_always_true(cond); + int skip_label = 0; + + if (has_condition) + { + skip_label = compiler->labelnum++; + generate_if_condition(block, compiler, desc, cond, skip_label); + } + + generate_compute(block, compiler, desc); + + if (g) + { + // PM + UML_ADD(block, PM_I(i), PM_I(i), PM_M(m)); + } + else + { + // DM + UML_ADD(block, DM_I(i), DM_I(i), DM_M(m)); + } + + generate_update_circular_buffer(block, compiler, desc, g, i); + + if (has_condition) + UML_LABEL(block, skip_label); + + return TRUE; + } + + case 0x06: // direct jump|call |000|00110| + { + int b = (opcode >> 39) & 0x1; + int j = (opcode >> 26) & 0x1; + int la = (opcode >> 38) & 0x1; + int ci = (opcode >> 24) & 0x1; + int cond = (opcode >> 33) & 0x1f; + + bool has_condition = !if_condition_always_true(cond); + int skip_label = 0; + + if (has_condition) + { + skip_label = compiler->labelnum++; + generate_if_condition(block, compiler, desc, cond, skip_label); + } + if (b) // call + { + generate_call(block, compiler, desc, j != 0); + } + else // jump + { + generate_jump(block, compiler, desc, j != 0, la != 0, ci != 0); + } + if (has_condition) + UML_LABEL(block, skip_label); + return TRUE; + } + + case 0x07: // direct jump|call |000|00111| + { + int b = (opcode >> 39) & 0x1; + int j = (opcode >> 26) & 0x1; + int la = (opcode >> 38) & 0x1; + int ci = (opcode >> 24) & 0x1; + int cond = (opcode >> 33) & 0x1f; + + bool has_condition = !if_condition_always_true(cond); + int skip_label = 0; + + if (has_condition) + { + skip_label = compiler->labelnum++; + generate_if_condition(block, compiler, desc, cond, skip_label); + } + if (b) // call + { + generate_call(block, compiler, desc, j != 0); + } + else // jump + { + generate_jump(block, compiler, desc, j != 0, la != 0, ci != 0); + } + if (has_condition) + UML_LABEL(block, skip_label); + return TRUE; + } + + case 0x08: // indirect jump|call / compute |000|01000| + { + int la = (opcode >> 38) & 0x1; + int ci = (opcode >> 24) & 0x1; + int b = (opcode >> 39) & 0x1; + int j = (opcode >> 26) & 0x1; + int e = (opcode >> 25) & 0x1; + int pmi = (opcode >> 30) & 0x7; + int pmm = (opcode >> 27) & 0x7; + int cond = (opcode >> 33) & 0x1f; + int compute = opcode & 0x7fffff; + + if (e) + { + // IF ... ELSE + + int label_else = compiler->labelnum++; + generate_if_condition(block, compiler, desc, cond, label_else); + + UML_ADD(block, I0, PM_I(pmi), PM_M(pmm)); + + if (b) // call + { + generate_call(block, compiler, desc, j != 0); + } + else // jump + { + generate_jump(block, compiler, desc, j != 0, la != 0, ci != 0); + } + + UML_LABEL(block, label_else); + generate_compute(block, compiler, desc); + } + else + { + // IF + bool has_condition = !if_condition_always_true(cond); + int skip_label = 0; + + if (has_condition) + { + skip_label = compiler->labelnum++; + generate_if_condition(block, compiler, desc, cond, skip_label); + } + generate_compute(block, compiler, desc); + + UML_ADD(block, I0, PM_I(pmi), PM_M(pmm)); + + if (b) // call + { + generate_call(block, compiler, desc, j != 0); + } + else // jump + { + generate_jump(block, compiler, desc, j != 0, la != 0, ci != 0); + } + + if (has_condition) + UML_LABEL(block, skip_label); + } + + return TRUE; + } + + case 0x09: // indirect jump|call / compute |000|01001| + { + int la = (opcode >> 38) & 0x1; + int ci = (opcode >> 24) & 0x1; + int b = (opcode >> 39) & 0x1; + int j = (opcode >> 26) & 0x1; + int e = (opcode >> 25) & 0x1; + int cond = (opcode >> 33) & 0x1f; + int compute = opcode & 0x7fffff; + + if (e) + { + // IF ... ELSE + + int label_else = compiler->labelnum++; + generate_if_condition(block, compiler, desc, cond, label_else); + + if (b) // call + { + generate_call(block, compiler, desc, j != 0); + } + else // jump + { + generate_jump(block, compiler, desc, j != 0, la != 0, ci != 0); + } + + UML_LABEL(block, label_else); + generate_compute(block, compiler, desc); + } + else + { + // IF + bool has_condition = !if_condition_always_true(cond); + int skip_label = 0; + + if (has_condition) + { + skip_label = compiler->labelnum++; + generate_if_condition(block, compiler, desc, cond, skip_label); + } + generate_compute(block, compiler, desc); + + if (b) // call + { + generate_call(block, compiler, desc, j != 0); + } + else // jump + { + generate_jump(block, compiler, desc, j != 0, la != 0, ci != 0); + } + + if (has_condition) + UML_LABEL(block, skip_label); + } + + return TRUE; + } + + case 0x0a: // return from subroutine / compute |000|01010| + { + int cond = (opcode >> 33) & 0x1f; + int j = (opcode >> 26) & 0x1; + int e = (opcode >> 25) & 0x1; + //int lr = (opcode >> 24) & 0x1; + int compute = opcode & 0x7fffff; + + // TODO: loop re-entry + + if (e) + { + // IF ... ELSE + + int label_else = compiler->labelnum++; + generate_if_condition(block, compiler, desc, cond, label_else); + + UML_CALLH(block, *m_pop_pc); + generate_jump(block, compiler, desc, j != 0, false, false); + + UML_LABEL(block, label_else); + generate_compute(block, compiler, desc); + } + else + { + // IF + bool has_condition = !if_condition_always_true(cond); + int skip_label = 0; + + if (has_condition) + { + skip_label = compiler->labelnum++; + generate_if_condition(block, compiler, desc, cond, skip_label); + } + generate_compute(block, compiler, desc); + + UML_CALLH(block, *m_pop_pc); + generate_jump(block, compiler, desc, j != 0, false, false); + + if (has_condition) + UML_LABEL(block, skip_label); + } + + return TRUE; + } + + case 0x0b: // return from interrupt / compute |000|01011| + { + int cond = (opcode >> 33) & 0x1f; + int j = (opcode >> 26) & 0x1; + int e = (opcode >> 25) & 0x1; + int compute = opcode & 0x7fffff; + + + code_label skip_pop = compiler->labelnum++; + + UML_MOV(block, mem(&m_core->interrupt_active), 0); // mov [interrupt_active],0 + UML_MOV(block, I0, 1); // mov i0,1 + UML_SHL(block, I0, I0, mem(&m_core->active_irq_num)); // shl i0,[active_irq_num] + UML_XOR(block, IRPTL, IRPTL, I0); // xor IRPTL,i0 + UML_CMP(block, mem(&m_core->status_stkp), 0); // cmp [status_stkp],0 + UML_JMPc(block, COND_Z, skip_pop); // jz skip_pop + UML_CALLH(block, *m_pop_status); // callh m_pop_status + + UML_LABEL(block, skip_pop); // skip_pop: + + // TODO: check interrupts + + if (e) + { + // IF ... ELSE + + code_label label_else = compiler->labelnum++; + generate_if_condition(block, compiler, desc, cond, label_else); + + UML_CALLH(block, *m_pop_pc); + generate_jump(block, compiler, desc, j != 0, false, false); + + UML_LABEL(block, label_else); + generate_compute(block, compiler, desc); + } + else + { + // IF + bool has_condition = !if_condition_always_true(cond); + code_label skip_label = 0; + + if (has_condition) + { + skip_label = compiler->labelnum++; + generate_if_condition(block, compiler, desc, cond, skip_label); + } + generate_compute(block, compiler, desc); + + UML_CALLH(block, *m_pop_pc); + generate_jump(block, compiler, desc, j != 0, false, false); + + if (has_condition) + UML_LABEL(block, skip_label); + } + + return TRUE; + } + + case 0x0c: // do until counter expired |000|01100| + { + UINT16 data = (UINT16)(opcode >> 24); + int offset = SIGN_EXTEND24(opcode & 0xffffff); + UINT32 address = desc->pc + offset; + + UML_MOV(block, LCNTR, data); + if (data > 0) + { + // push pc + UML_MOV(block, I0, desc->pc + 1); + UML_CALLH(block, *m_push_pc); + + // push loop + UML_MOV(block, I0, data); + UML_MOV(block, I1, address); + UML_CALLH(block, *m_push_loop); + } + return TRUE; + } + + case 0x0d: // do until counter expired |000|01101| + { + int ureg = (opcode >> 32) & 0xff; + int offset = SIGN_EXTEND24(opcode & 0xffffff); + UINT32 address = desc->pc + offset; + + generate_read_ureg(block, compiler, desc, ureg, false); + + UML_AND(block, I3, I0, 0xffff); + UML_MOV(block, LCNTR, I3); + + // push pc + UML_MOV(block, I0, desc->pc + 1); + UML_CALLH(block, *m_push_pc); + + // push loop + UML_MOV(block, I0, I3); + UML_MOV(block, I1, address); + UML_CALLH(block, *m_push_loop); + return TRUE; + } + + case 0x0e: // do until |000|01110| + { + int offset = SIGN_EXTEND24(opcode & 0xffffff); + UINT32 address = desc->pc + offset; + + // push pc + UML_MOV(block, I0, desc->pc + 1); + UML_CALLH(block, *m_push_pc); + + // push loop + UML_MOV(block, I0, 0); + UML_MOV(block, I1, address); + UML_CALLH(block, *m_push_loop); + return TRUE; + } + + case 0x0f: // immediate data -> ureg |000|01111| + { + int ureg = (opcode >> 32) & 0xff; + UINT32 data = (UINT32)opcode; + + generate_write_ureg(block, compiler, desc, ureg, true, data); + return TRUE; + } + + case 0x10: // ureg <-> DM|PM (direct) |000|100|G|D| + case 0x11: + case 0x12: + case 0x13: + { + int ureg = (opcode >> 32) & 0xff; + UINT32 address = (UINT32)(opcode); + int d = (opcode >> 40) & 1; + int g = (opcode >> 41) & 1; + + UML_MOV(block, I1, address); + if (d) + { + generate_read_ureg(block, compiler, desc, ureg, false); + + // write + if (g) + { + // PM + if (ureg == 0xdb) // PX is 48-bit + UML_CALLH(block, *m_pm_write48); + else + UML_CALLH(block, *m_pm_write32); + } + else + { + // DM + UML_CALLH(block, *m_dm_write32); + } + } + else + { + // read + if (g) + { + // PM + if (ureg == 0xdb) // PX is 48-bit + UML_CALLH(block, *m_pm_read48); + else + UML_CALLH(block, *m_pm_read32); + } + else + { + // DM + UML_CALLH(block, *m_dm_read32); + } + + generate_write_ureg(block, compiler, desc, ureg, false, 0); + } + return TRUE; + } + + case 0x14: // system register bit manipulation |000|10100| + { + int bop = (opcode >> 37) & 0x7; + int sreg = (opcode >> 32) & 0xf; + UINT32 data = (UINT32)opcode; + + switch (bop) + { + case 0: // SET + { + switch (sreg) + { + case 0x0: // USTAT1 + UML_OR(block, USTAT1, USTAT1, data); + break; + case 0x1: // USTAT2 + UML_OR(block, USTAT2, USTAT2, data); + break; + case 0x9: // IRPTL + UML_OR(block, IRPTL, IRPTL, data); + break; + case 0xa: // MODE2 + UML_OR(block, MODE2, MODE2, data); + break; + case 0xb: // MODE1 + compiler->mode1_delay.counter = 2; + compiler->mode1_delay.data = data; + compiler->mode1_delay.mode = MODE1_SET; + break; + case 0xc: // ASTAT + return FALSE; + case 0xd: // IMASK + UML_OR(block, IMASK, IMASK, data); + break; + case 0xe: // STKY + UML_OR(block, STKY, STKY, data); + break; + case 0xf: // IMASKP + UML_OR(block, IMASKP, IMASKP, data); + break; + + default: + return FALSE; + } + return TRUE; + } + case 1: // CLEAR + { + switch (sreg) + { + case 0x0: // USTAT1 + UML_AND(block, USTAT1, USTAT1, ~data); + break; + case 0x1: // USTAT2 + UML_AND(block, USTAT2, USTAT2, ~data); + break; + case 0x9: // IRPTL + UML_AND(block, IRPTL, IRPTL, ~data); + break; + case 0xa: // MODE2 + UML_AND(block, MODE2, MODE2, ~data); + break; + case 0xb: // MODE1 + compiler->mode1_delay.counter = 2; + compiler->mode1_delay.data = data; + compiler->mode1_delay.mode = MODE1_CLEAR; + break; + case 0xc: // ASTAT + return FALSE; + case 0xd: // IMASK + UML_AND(block, IMASK, IMASK, ~data); + break; + case 0xe: // STKY + UML_AND(block, STKY, STKY, ~data); + break; + case 0xf: // IMASKP + UML_AND(block, IMASKP, IMASKP, ~data); + break; + + default: + return FALSE; + } + return TRUE; + } + case 2: // TOGGLE + { + switch (sreg) + { + case 0x0: // USTAT1 + UML_XOR(block, USTAT1, USTAT1, data); + break; + case 0x1: // USTAT2 + UML_XOR(block, USTAT2, USTAT2, data); + break; + case 0x9: // IRPTL + UML_XOR(block, IRPTL, IRPTL, data); + break; + case 0xa: // MODE2 + UML_XOR(block, MODE2, MODE2, data); + break; + case 0xb: // MODE1 + compiler->mode1_delay.counter = 2; + compiler->mode1_delay.data = data; + compiler->mode1_delay.mode = MODE1_TOGGLE; + break; + case 0xc: // ASTAT + return FALSE; + case 0xd: // IMASK + UML_XOR(block, IMASK, IMASK, data); + break; + case 0xe: // STKY + UML_XOR(block, STKY, STKY, data); + break; + case 0xf: // IMASKP + UML_XOR(block, IMASKP, IMASKP, data); + break; + + default: + return FALSE; + } + return TRUE; + } + case 4: // TEST + { + switch (sreg) + { + case 0x0: // USTAT1 + UML_AND(block, I0, USTAT1, data); + UML_CMP(block, I0, data); + UML_SETc(block, COND_E, ASTAT_BTF); + break; + case 0x1: // USTAT2 + UML_AND(block, I0, USTAT2, data); + UML_CMP(block, I0, data); + UML_SETc(block, COND_E, ASTAT_BTF); + break; + case 0x9: // IRPTL + UML_AND(block, I0, IRPTL, data); + UML_CMP(block, I0, data); + UML_SETc(block, COND_E, ASTAT_BTF); + break; + case 0xa: // MODE2 + UML_AND(block, I0, MODE2, data); + UML_CMP(block, I0, data); + UML_SETc(block, COND_E, ASTAT_BTF); + break; + case 0xb: // MODE1 + UML_AND(block, I0, MODE1, data); + UML_CMP(block, I0, data); + UML_SETc(block, COND_E, ASTAT_BTF); + break; + case 0xc: // ASTAT + return FALSE; + case 0xd: // IMASK + UML_AND(block, I0, IMASK, data); + UML_CMP(block, I0, data); + UML_SETc(block, COND_E, ASTAT_BTF); + break; + case 0xe: // STKY + UML_AND(block, I0, STKY, data); + UML_CMP(block, I0, data); + UML_SETc(block, COND_E, ASTAT_BTF); + break; + case 0xf: // IMASKP + UML_AND(block, I0, IMASKP, data); + UML_CMP(block, I0, data); + UML_SETc(block, COND_E, ASTAT_BTF); + break; + + default: + return FALSE; + } + return TRUE; + } + case 5: // XOR + { + return FALSE; + } + + default: + return FALSE; + } + return TRUE; + } + + case 0x16: // I register modify / bit-reverse |000|10110| + { + if (opcode & U64(0x008000000000)) // bit reverse + { + return FALSE; + } + else // modify + { + int g = (opcode >> 38) & 0x1; + int i = (opcode >> 32) & 0x7; + INT32 data = (INT32)(opcode); + + if (g) + { + // PM + UML_ADD(block, PM_I(i), PM_I(i), data); + } + else + { + // DM + UML_ADD(block, DM_I(i), DM_I(i), data); + } + generate_update_circular_buffer(block, compiler, desc, g, i); + return TRUE; + } + } + + case 0x17: // push|pop stacks / flush cache |000|10111| + return FALSE; + + case 0x18: // cjump |000|11000| + return FALSE; + + case 0x19: // rframe |000|11001| + return FALSE; + + default: + return FALSE; + } + break; + } + + case 1: // compute / dreg <-> DM / dreg <-> PM |001| + { + return FALSE; + } + + case 2: // compute / ureg <-> DM|PM, register modify |010| + { + int u = (opcode >> 44) & 0x1; + int i = (opcode >> 41) & 0x7; + int m = (opcode >> 38) & 0x7; + int cond = (opcode >> 33) & 0x1f; + int g = (opcode >> 32) & 0x1; + int d = (opcode >> 31) & 0x1; + int ureg = (opcode >> 23) & 0xff; + int compute = opcode & 0x7fffff; + + bool ureg_is_dreg = (ureg >= 0 && ureg < 16); + bool has_condition = !if_condition_always_true(cond); + int skip_label = 0; + + bool ureg_is_astat = (ureg == 0x7c); + + if (has_condition) + { + skip_label = compiler->labelnum++; + generate_if_condition(block, compiler, desc, cond, skip_label); + } + + if (d) + { + // UREG -> DM|PM + bool temp_ureg = false; + + // save UREG if compute writes to it + if (compute != 0 && ureg_is_dreg && desc->regout[0] & (1 << (ureg & 0xf))) + { + UML_MOV(block, mem(&m_core->dreg_temp), REG(ureg & 0xf)); + temp_ureg = true; + } + + // save a copy of ASTAT if we need to read it + if (ureg_is_astat) + generate_astat_copy(block, compiler, desc); + + // compute + generate_compute(block, compiler, desc); + + // transfer + UML_MOV(block, I1, (g) ? PM_I(i) : DM_I(i)); // mov i1,dm|pm[i] + if (u == 0) // pre-modify without update + UML_ADD(block, I1, I1, (g) ? PM_M(m) : DM_M(m)); // add i1,i1,dm|pm[m] + if (temp_ureg) + UML_MOV(block, I0, mem(&m_core->dreg_temp)); // mov i0,[m_core->dreg_temp] + else + generate_read_ureg(block, compiler, desc, ureg, ureg_is_astat); + + if (ureg == 0xdb && (g)) // PX is 48-bit when writing to PM + UML_CALLH(block, *m_pm_write48); // callh pm_write48 + else + UML_CALLH(block, (g) ? *m_pm_write32 : *m_dm_write32); // callh dm|pm_write32 + } + else + { + // DM|PM -> UREG + + // compute + generate_compute(block, compiler, desc); + + // transfer + UML_MOV(block, I1, (g) ? PM_I(i) : DM_I(i)); // mov i1,dm|pm[i] + if (u == 0) // pre-modify without update + UML_ADD(block, I1, I1, (g) ? PM_M(m) : DM_M(m)); // add i1,i1,dm|pm[m] + + if (ureg == 0xdb && (g)) // PX is 48-bit when reading from PM + UML_CALLH(block, *m_pm_read48); // callh pm_read48 + else + UML_CALLH(block, (g) ? *m_pm_read32 : *m_dm_read32); // callh dm|pm_read32 + generate_write_ureg(block, compiler, desc, ureg, false, 0); + } + + if (u != 0) // post-modify with update + { + if (g) + UML_ADD(block, PM_I(i), PM_I(i), PM_M(m)); // add pm[i],pm[m] + else + UML_ADD(block, DM_I(i), DM_I(i), DM_M(m)); // add dm[i],dm[m] + + generate_update_circular_buffer(block, compiler, desc, g, i); + } + + if (has_condition) + UML_LABEL(block, skip_label); + + return TRUE; + } + + case 3: + { + if (opcode & U64(0x100000000000)) // compute / ureg <-> ureg |011|1| + { + int src_ureg = (opcode >> 36) & 0xff; + int dst_ureg = (opcode >> 23) & 0xff; + int cond = (opcode >> 31) & 0x1f; + int compute = opcode & 0x7fffff; + + bool has_condition = !if_condition_always_true(cond); + bool src_is_dreg = (src_ureg >= 0 && src_ureg < 16); + int skip_label = 0; + + bool src_ureg_is_astat = (src_ureg == 0x7c); + + if (has_condition) + { + skip_label = compiler->labelnum++; + generate_if_condition(block, compiler, desc, cond, skip_label); + } + + bool temp_ureg = false; + // save UREG if compute writes to it + if (compute != 0 && src_is_dreg && desc->regout[0] & (1 << (src_ureg & 0xf))) + { + UML_MOV(block, mem(&m_core->dreg_temp), REG(src_ureg & 0xf)); + temp_ureg = true; + } + + // save a copy of ASTAT if we need to read it + if (src_ureg_is_astat) + generate_astat_copy(block, compiler, desc); + + generate_compute(block, compiler, desc); + + if (temp_ureg) + { + UML_MOV(block, I0, mem(&m_core->dreg_temp)); + } + else + { + generate_read_ureg(block, compiler, desc, src_ureg, src_ureg_is_astat); + } + generate_write_ureg(block, compiler, desc, dst_ureg, false, 0); + + if (has_condition) + UML_LABEL(block, skip_label); + + return TRUE; + } + else // compute / dreg <-> DM|PM, immediate modify |011|0| + { + int cond = (opcode >> 33) & 0x1f; + int u = (opcode >> 38) & 0x1; + int d = (opcode >> 39) & 0x1; + int g = (opcode >> 40) & 0x1; + int dreg = (opcode >> 23) & 0xf; + int i = (opcode >> 41) & 0x7; + int mod = SIGN_EXTEND6((opcode >> 27) & 0x3f); + int compute = opcode & 0x7fffff; + + bool has_condition = !if_condition_always_true(cond); + int skip_label = 0; + + if (has_condition) + { + skip_label = compiler->labelnum++; + generate_if_condition(block, compiler, desc, cond, skip_label); + } + if (d) + { + // DREG -> DM|PM + bool temp_dreg = false; + + // save dreg if compute writes to it + if (compute != 0 && desc->regout[0] & (1 << dreg)) + { + UML_MOV(block, mem(&m_core->dreg_temp), REG(dreg)); + temp_dreg = true; + } + // compute + generate_compute(block, compiler, desc); + + // transfer + UML_MOV(block, I1, (g) ? PM_I(i) : DM_I(i)); // mov i1,dm|pm[i] + if (u == 0) // pre-modify without update + UML_ADD(block, I1, I1, mod); // add i1,i1,mod + if (temp_dreg) + UML_MOV(block, I0, mem(&m_core->dreg_temp)); // mov i0,[m_core->dreg_temp] + else + UML_MOV(block, I0, REG(dreg)); // mov i0,reg[dreg] + UML_CALLH(block, (g) ? *m_pm_write32 : *m_dm_write32); // callh dm|pm_write32 + } + else + { + // DM|PM -> DREG + + // compute + generate_compute(block, compiler, desc); + + // transfer + UML_MOV(block, I1, (g) ? PM_I(i) : DM_I(i)); // mov i1,dm|pm[i] + if (u == 0) // pre-modify without update + UML_ADD(block, I1, I1, mod); // add i1,i1,mod + UML_CALLH(block, (g) ? *m_pm_read32 : *m_dm_read32); // callh dm|pm_read32 + UML_MOV(block, REG(dreg), I0); // mov reg[dreg],i0 + } + + if (u != 0) // post-modify with update + { + if (g) + UML_ADD(block, PM_I(i), PM_I(i), mod); // add pm[i],mod + else + UML_ADD(block, DM_I(i), DM_I(i), mod); // add dm[i],mod + + generate_update_circular_buffer(block, compiler, desc, g, i); + } + if (has_condition) + UML_LABEL(block, skip_label); + + return TRUE; + } + break; + } + + case 4: + { + if (opcode & U64(0x100000000000)) // immediate data -> DM|PM |100|1| + { + return FALSE; + } + else // immediate shift / dreg <-> DM|PM |100|0| + { + int i = (opcode >> 41) & 0x7; + int m = (opcode >> 38) & 0x7; + int g = (opcode >> 32) & 0x1; + int d = (opcode >> 31) & 0x1; + int dreg = (opcode >> 23) & 0xf; + int cond = (opcode >> 33) & 0x1f; + int data = ((opcode >> 8) & 0xff) | ((opcode >> 19) & 0xf00); + int shiftop = (opcode >> 16) & 0x3f; + int rn = (opcode >> 4) & 0xf; + int rx = (opcode & 0xf); + + bool has_condition = !if_condition_always_true(cond); + int skip_label = 0; + + if (has_condition) + { + skip_label = compiler->labelnum++; + generate_if_condition(block, compiler, desc, cond, skip_label); + } + if (d) + { + // DREG -> DM|PM + bool temp_dreg = false; + + // save dreg if shiftop writes to it + if (desc->regout[0] & (1 << dreg)) + { + UML_MOV(block, mem(&m_core->dreg_temp), REG(dreg)); + temp_dreg = true; + } + // shiftop + generate_shift_imm(block, compiler, desc, data, shiftop, rn, rx); + + // transfer + UML_MOV(block, I1, (g) ? PM_I(i) : DM_I(i)); // mov i1,dm|pm[i] + if (temp_dreg) + UML_MOV(block, I0, mem(&m_core->dreg_temp)); // mov i0,[m_core->dreg_temp] + else + UML_MOV(block, I0, REG(dreg)); // mov i0,reg[dreg] + UML_CALLH(block, (g) ? *m_pm_write32 : *m_dm_write32); // callh dm|pm_write32 + } + else + { + // DM|PM -> DREG + + // shiftop + generate_shift_imm(block, compiler, desc, data, shiftop, rn, rx); + + // transfer + UML_MOV(block, I1, (g) ? PM_I(i) : DM_I(i)); // mov i1,dm|pm[i] + UML_CALLH(block, (g) ? *m_pm_read32 : *m_dm_read32); // callh dm|pm_read32 + UML_MOV(block, REG(dreg), I0); // mov reg[dreg],i0 + } + + // update I + if (g) + UML_ADD(block, PM_I(i), PM_I(i), PM_M(m)); + else + UML_ADD(block, DM_I(i), DM_I(i), DM_M(m)); + + generate_update_circular_buffer(block, compiler, desc, g, i); + + if (has_condition) + UML_LABEL(block, skip_label); + + return TRUE; + } + break; + } + + case 5: // ureg <-> DM|PM (indirect) |101| + { + int g = (opcode >> 44) & 1; + int d = (opcode >> 40) & 1; + int i = (opcode >> 41) & 0x7; + int ureg = (opcode >> 32) & 0xff; + UINT32 offset = (UINT32)opcode; + + if (d) + { + // UREG -> DM|PM + UML_ADD(block, I1, (g) ? PM_I(i) : DM_I(i), offset); // add i1,dm|pm[i],offset + + generate_read_ureg(block, compiler, desc, ureg, false); + + if (ureg == 0xdb && (g)) // PX is 48-bit when writing to PM + UML_CALLH(block, *m_pm_write48); // callh pm_write48 + else + UML_CALLH(block, (g) ? *m_pm_write32 : *m_dm_write32); // callh dm|pm_write32 + } + else + { + // DM|PM -> UREG + UML_ADD(block, I1, (g) ? PM_I(i) : DM_I(i), offset); // add i1,dm|pm[i],offset + + if (ureg == 0xdb && (g)) // PX is 48-bit when reading from PM + UML_CALLH(block, *m_pm_read48); // callh pm_read48 + else + UML_CALLH(block, (g) ? *m_pm_read32 : *m_dm_read32); // callh dm|pm_read32 + + generate_write_ureg(block, compiler, desc, ureg, false, 0); + } + return TRUE; + } + + case 6: // indirect jump / compute / dreg <-> DM |110| + { + return FALSE; + } + + case 7: // indirect jump / compute / dreg <-> DM |111| + { + return FALSE; + } + } + + return FALSE; +} + +void adsp21062_device::generate_unimplemented_compute(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UML_MOV(block, mem(&m_core->pc), desc->pc); + UML_DMOV(block, mem(&m_core->arg64), desc->opptr.q[0]); + UML_CALLC(block, cfunc_unimplemented_compute, this); +} + +void adsp21062_device::generate_compute(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT64 opcode = desc->opptr.q[0]; + if ((opcode & 0x7fffff) == 0) + return; + + int rs = (opcode >> 12) & 0xf; + int rn = (opcode >> 8) & 0xf; + int ra = rn; + int rx = (opcode >> 4) & 0xf; + int ry = (opcode >> 0) & 0xf; + int ps = (opcode >> 16) & 0xf; + + if (opcode & 0x400000) // multi-function operation + { + UINT32 multiop = (opcode >> 16) & 0x3f; + int fm = rs; + int fa = rn; + int fxm = (opcode >> 6) & 0x3; // registers 0 - 3 + int fym = ((opcode >> 4) & 0x3) + 4; // registers 4 - 7 + int fxa = ((opcode >> 2) & 0x3) + 8; // registers 8 - 11 + int fya = (opcode & 0x3) + 12; // registers 12 - 15 + + switch (multiop) + { + case 0x00: // Rn = MRxx + { + generate_unimplemented_compute(block, compiler, desc); + return; + } + + case 0x01: // MRxx = Rn + { + int ai = rs; + switch (ai) + { + case 0x00: // MR0F + UML_DAND(block, MRF, MRF, U64(0xffffffff00000000)); + UML_AND(block, I0, REG(rn), 0xffffffff); + UML_DOR(block, MRF, MRF, I0); + break; + case 0x01: // MR1F + UML_DAND(block, MRF, MRF, U64(0x00000000ffffffff)); + UML_DSHL(block, I0, REG(rn), 32); + UML_DOR(block, MRF, MRF, I0); + break; + case 0x04: // MR0B + UML_DAND(block, MRB, MRB, U64(0xffffffff00000000)); + UML_AND(block, I0, REG(rn), 0xffffffff); + UML_DOR(block, MRB, MRB, I0); + break; + case 0x05: // MR1B + UML_DAND(block, MRB, MRB, U64(0x00000000ffffffff)); + UML_DSHL(block, I0, REG(rn), 32); + UML_DOR(block, MRB, MRB, I0); + break; + + case 0x02: // MR2F + case 0x06: // MR2B + generate_unimplemented_compute(block, compiler, desc); + return; + } + return; + } + + case 0x07: // Ra = Rx + Ry, Rs = Rx - Ry + case 0x0f: // Fa = Fx + Fy, Fs = Fx - Fy + case 0x04: // Rm = R3-0 * R7-4 (SSFR), Ra = R11-8 + R15-12 + case 0x05: // Rm = R3-0 * R7-4 (SSFR), Ra = R11-8 - R15-12 + case 0x06: // Rm = R3-0 * R7-4 (SSFR), Ra = (R11-8 + R15-12) / 2 + case 0x08: // MRF = MRF + R3-0 * R7-4 (SSF), Ra = R11-8 + R15-12 + case 0x09: // MRF = MRF + R3-0 * R7-4 (SSF), Ra = R11-8 - R15-12 + case 0x0a: // MRF = MRF + R3-0 * R7-4 (SSF), Ra = (R11-8 + R15-12) / 2 + case 0x0c: // Rm = MRF + R3-0 * R7-4 (SSFR), Ra = R11-8 + R15-12 + case 0x0d: // Rm = MRF + R3-0 * R7-4 (SSFR), Ra = R11-8 - R15-12 + case 0x0e: // Rm = MRF + R3-0 * R7-4 (SSFR), Ra = (R11-8 + R15-12) / 2 + case 0x10: // MRF = MRF - R3-0 * R7-4 (SSF), Ra = R11-8 + R15-12 + case 0x11: // MRF = MRF - R3-0 * R7-4 (SSF), Ra = R11-8 - R15-12 + case 0x12: // MRF = MRF - R3-0 * R7-4 (SSF), Ra = (R11-8 + R15-12) / 2 + case 0x14: // Rm = MRF - R3-0 * R7-4 (SSFR), Ra = R11-8 + R15-12 + case 0x15: // Rm = MRF - R3-0 * R7-4 (SSFR), Ra = R11-8 - R15-12 + case 0x16: // Rm = MRF - R3-0 * R7-4 (SSFR), Ra = (R11-8 + R15-12) / 2 + generate_unimplemented_compute(block, compiler, desc); + return; + + case 0x1c: // Fm = F3-0 * F7-4, Fa = (F11-8 + F15-12) / 2 + generate_unimplemented_compute(block, compiler, desc); + return; + + case 0x1d: // Fm = F3-0 * F7-4, Fa = ABS F11-8 + generate_unimplemented_compute(block, compiler, desc); + return; + + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + // Rm = R3-0 * R7-4 (SSFR), Ra = R11-8 + R15-12, Rs = R11-8 - R15-12 + generate_unimplemented_compute(block, compiler, desc); + return; + + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: + case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: + // Fm = F3-0 * F7-4, Fa = F11-8 + F15-12, Fs = F11-8 - F15-12 + // TODO: denormals + UML_FSCOPYI(block, F0, REG(fxm)); + UML_FSCOPYI(block, F1, REG(fym)); + UML_FSCOPYI(block, F2, REG(fxa)); + UML_FSCOPYI(block, F3, REG(fya)); + UML_FSMUL(block, F0, F0, F1); + UML_FSADD(block, F4, F2, F3); + UML_FSSUB(block, F5, F2, F3); + + if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED) + UML_FSCMP(block, F4, mem(&m_core->fp0)); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AN); + + if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED) + UML_FSCMP(block, F5, mem(&m_core->fp0)); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, I0); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, I1); + if (AZ_CALC_REQUIRED) UML_OR(block, ASTAT_AZ, ASTAT_AZ, I0); + if (AN_CALC_REQUIRED) UML_OR(block, ASTAT_AN, ASTAT_AN, I1); + + if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0); // TODO + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); // TODO + + if (MN_CALC_REQUIRED) + UML_FSCMP(block, F0, mem(&m_core->fp0)); + if (MN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_MN); + // TODO: MV, MU, MI flags + + UML_ICOPYFS(block, REG(fm), F0); + UML_ICOPYFS(block, REG(fa), F4); + UML_ICOPYFS(block, REG(ps), F5); + return; + + case 0x18: // Fm = F3-0 * F7-4, Fa = F11-8 + F15-12 + // TODO: denormals + UML_FSCOPYI(block, F0, REG(fxm)); + UML_FSCOPYI(block, F1, REG(fym)); + UML_FSCOPYI(block, F2, REG(fxa)); + UML_FSCOPYI(block, F3, REG(fya)); + UML_FSMUL(block, F0, F0, F1); + UML_FSADD(block, F2, F2, F3); + + if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED) + UML_FSCMP(block, F2, mem(&m_core->fp0)); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AN); + if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0); // TODO + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); // TODO + + if (MN_CALC_REQUIRED) + UML_FSCMP(block, F0, mem(&m_core->fp0)); + if (MN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_MN); + // TODO: MV, MU, MI flags + + UML_ICOPYFS(block, REG(fm), F0); + UML_ICOPYFS(block, REG(fa), F2); + return; + + case 0x19: // Fm = F3-0 * F7-4, Fa = F11-8 - F15-12 + // TODO: denormals + UML_FSCOPYI(block, F0, REG(fxm)); + UML_FSCOPYI(block, F1, REG(fym)); + UML_FSCOPYI(block, F2, REG(fxa)); + UML_FSCOPYI(block, F3, REG(fya)); + UML_FSMUL(block, F0, F0, F1); + UML_FSSUB(block, F2, F2, F3); + + if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED) + UML_FSCMP(block, F2, mem(&m_core->fp0)); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AN); + if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0); // TODO + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); // TODO + + if (MN_CALC_REQUIRED) + UML_FSCMP(block, F0, mem(&m_core->fp0)); + if (MN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_MN); + // TODO: MV, MU, MI flags + + UML_ICOPYFS(block, REG(fm), F0); + UML_ICOPYFS(block, REG(fa), F2); + return; + + case 0x1a: // Fm = F3-0 * F7-4, Fa = FLOAT F11-8 BY R15-12 + { + code_label denormal = compiler->labelnum++; + code_label end = compiler->labelnum++; + + // TODO: denormals + UML_FSCOPYI(block, F0, REG(fxm)); + UML_FSCOPYI(block, F1, REG(fym)); + UML_FSMUL(block, F0, F0, F1); + + UML_FSFRINT(block, F2, REG(fxa), SIZE_DWORD); + UML_ICOPYFS(block, I1, F2); + UML_AND(block, I0, I1, 0x7f800000); + UML_AND(block, I1, I1, 0x807fffff); + UML_SHR(block, I0, I0, 23); + UML_SUB(block, I0, I0, 127); + UML_ADD(block, I0, I0, REG(fya)); + UML_CMP(block, I0, -126); + UML_JMPc(block, COND_L, denormal); + + UML_ADD(block, I0, I0, 127); + UML_AND(block, I0, I0, 0xff); + UML_SHL(block, I0, I0, 23); + UML_OR(block, I0, I0, I1); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN); + if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0); // TODO + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); + UML_JMP(block, end); + + UML_LABEL(block, denormal); + UML_AND(block, I0, I1, 0x80000000); + if (AZ_CALC_REQUIRED) UML_MOV(block, ASTAT_AZ, 1); + if (AN_CALC_REQUIRED) UML_MOV(block, ASTAT_AN, 0); + if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0); // TODO + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); + + UML_LABEL(block, end); + + if (MN_CALC_REQUIRED) + UML_FSCMP(block, F0, mem(&m_core->fp0)); + if (MN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_MN); + // TODO: MV, MU, MI flags + + UML_ICOPYFS(block, REG(fm), F0); + UML_MOV(block, REG(fa), I0); + return; + } + + case 0x1b: // Fm = F3-0 * F7-4, Fa = FIX F11-8 BY R15-12 + { + code_label denormal = compiler->labelnum++; + code_label end = compiler->labelnum++; + + // TODO: denormals + UML_FSCOPYI(block, F0, REG(fxm)); + UML_FSCOPYI(block, F1, REG(fym)); + UML_FSMUL(block, F0, F0, F1); + + UML_MOV(block, I1, REG(fxa)); + UML_AND(block, I0, I1, 0x7f800000); + UML_AND(block, I1, I1, 0x807fffff); + UML_SHR(block, I0, I0, 23); + UML_SUB(block, I0, I0, 127); + UML_ADD(block, I0, I0, REG(fya)); + UML_CMP(block, I0, -126); + UML_JMPc(block, COND_L, denormal); + + UML_ADD(block, I0, I0, 127); + UML_AND(block, I0, I0, 0xff); + UML_SHL(block, I0, I0, 23); + UML_OR(block, I0, I0, I1); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN); + if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0); // TODO + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); + UML_JMP(block, end); + + UML_LABEL(block, denormal); + UML_AND(block, I0, I1, 0x80000000); + if (AZ_CALC_REQUIRED) UML_MOV(block, ASTAT_AZ, 1); + if (AN_CALC_REQUIRED) UML_MOV(block, ASTAT_AN, 0); + if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0); // TODO + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); + + UML_LABEL(block, end); + + UML_FSCOPYI(block, F2, I0); + UML_TEST(block, MODE1, MODE1_TRUNCATE); + UML_JMPc(block, COND_Z, compiler->labelnum); + UML_FSTOINT(block, I0, F2, SIZE_DWORD, ROUND_TRUNC); + UML_JMP(block, compiler->labelnum + 1); + UML_LABEL(block, compiler->labelnum++); + UML_FSTOINT(block, I0, F2, SIZE_DWORD, ROUND_ROUND); + UML_LABEL(block, compiler->labelnum++); + + if (MN_CALC_REQUIRED) + UML_FSCMP(block, F0, mem(&m_core->fp0)); + if (MN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_MN); + // TODO: MV, MU, MI flags + + UML_ICOPYFS(block, REG(fm), F0); + UML_MOV(block, REG(fa), I0); + return; + } + + case 0x1e: // Fm = F3-0 * F7-4, Fa = MAX(F11-8, F15-12) + // TODO: denormals + UML_FSCOPYI(block, F0, REG(fxm)); + UML_FSCOPYI(block, F1, REG(fym)); + UML_FSCOPYI(block, F2, REG(fxa)); + UML_FSCOPYI(block, F3, REG(fya)); + UML_FSMUL(block, F0, F0, F1); + + UML_FSMOV(block, F4, F2); + UML_FSCMP(block, F2, F3); + UML_FSMOVc(block, COND_C, F4, F3); + + if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED) + UML_FSCMP(block, F4, mem(&m_core->fp0)); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AN); + if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0); // TODO + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); // TODO + + if (MN_CALC_REQUIRED) + UML_FSCMP(block, F0, mem(&m_core->fp0)); + if (MN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_MN); + // TODO: MV, MU, MI flags + + UML_ICOPYFS(block, REG(fm), F0); + UML_ICOPYFS(block, REG(fa), F4); + return; + + case 0x1f: // Fm = F3-0 * F7-4, Fa = MIN(F11-8, F15-12) + // TODO: denormals + UML_FSCOPYI(block, F0, REG(fxm)); + UML_FSCOPYI(block, F1, REG(fym)); + UML_FSCOPYI(block, F2, REG(fxa)); + UML_FSCOPYI(block, F3, REG(fya)); + UML_FSMUL(block, F0, F0, F1); + + UML_FSMOV(block, F4, F2); + UML_FSCMP(block, F3, F2); + UML_FSMOVc(block, COND_C, F4, F3); + + if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED) + UML_FSCMP(block, F4, mem(&m_core->fp0)); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AN); + if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0); // TODO + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); // TODO + + if (MN_CALC_REQUIRED) + UML_FSCMP(block, F0, mem(&m_core->fp0)); + if (MN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_MN); + // TODO: MV, MU, MI flags + + UML_ICOPYFS(block, REG(fm), F0); + UML_ICOPYFS(block, REG(fa), F4); + return; + + default: + generate_unimplemented_compute(block, compiler, desc); + return; + } + } + else // single-function operation + { + UINT32 operation = (opcode >> 12) & 0xff; + + switch ((opcode >> 20) & 3) + { + case 0: // ALU operations + { + switch (operation) + { + case 0x09: // Rn = (Rx + Ry) / 2 + case 0x61: // Rn = MIN(Rx, Ry) + case 0x63: // Rn = CLIP Rx BY Ry + case 0x92: // Fn = ABS(Fx - Fy) + case 0x89: // Fn = (Fx + Fy) / 2 + case 0xdd: // Rn = TRUNC Fx BY Ry + case 0xe3: // Fn = CLIP Fx BY Fy + case 0xe0: // Fn = Fx COPYSIGN Fy + case 0x05: // Rn = Rx + Ry + CI + case 0x06: // Rn = Rx - Ry + CI - 1 + case 0x25: // Rn = Rx + CI + case 0x26: // Rn = Rx + CI - 1 + case 0x30: // Rn = ABS Rx + case 0x43: // Rn = NOT Rx + case 0xb0: // Fn = ABS(Fx) + case 0xa5: // Fn = RND Fx + case 0xad: // Rn = MANT Fx + case 0xc9: // Rn = FIX Fx + case 0xcd: // Rn = TRUNC Fx + generate_unimplemented_compute(block, compiler, desc); + return; + + case 0x01: // Rn = Rx + Ry + UML_ADD(block, REG(rn), REG(rx), REG(ry)); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN); + if (AV_CALC_REQUIRED) UML_SETc(block, COND_V, ASTAT_AV); + if (AC_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AC); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); + return; + + case 0x02: // Rn = Rx - Ry + UML_SUB(block, REG(rn), REG(rx), REG(ry)); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN); + if (AV_CALC_REQUIRED) UML_SETc(block, COND_V, ASTAT_AV); + if (AC_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AC); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); + return; + + case 0x0a: // COMP(Rx, Ry) + UML_CMP(block, REG(rx), REG(ry)); + UML_SETc(block, COND_Z, I0); + UML_SETc(block, COND_L, I1); + UML_MOV(block, ASTAT_AZ, I0); + UML_MOV(block, ASTAT_AN, I1); + UML_XOR(block, I0, I0, 1); + UML_XOR(block, I1, I1, 1); + UML_AND(block, I0, I0, I1); + UML_SHL(block, I0, I0, 7); + + UML_MOV(block, I2, mem(&m_core->astat_drc.cacc)); + UML_SHR(block, I2, I2, 1); + UML_OR(block, I2, I2, I0); + UML_MOV(block, mem(&m_core->astat_drc.cacc), I2); + + if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0); + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); + return; + + case 0x21: // Rn = PASS Rx + UML_MOV(block, REG(rn), REG(rx)); + if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED) + UML_CMP(block, REG(rn), 0); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN); + if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0); + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); + return; + + case 0x22: // Rn = -Rx + UML_SUB(block, REG(rn), 0, REG(rx)); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN); + if (AV_CALC_REQUIRED) UML_SETc(block, COND_V, ASTAT_AV); + if (AC_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AC); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); + return; + + case 0x29: // Rn = Rx + 1 + UML_ADD(block, REG(rn), REG(rx), 1); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN); + if (AV_CALC_REQUIRED) UML_SETc(block, COND_V, ASTAT_AV); + if (AC_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AC); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); + return; + + case 0x2a: // Rn = Rx - 1 + UML_SUB(block, REG(rn), REG(rx), 1); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN); + if (AV_CALC_REQUIRED) UML_SETc(block, COND_V, ASTAT_AV); + if (AC_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AC); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); + return; + + case 0x40: // Rn = Rx AND Ry + UML_AND(block, REG(rn), REG(rx), REG(ry)); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN); + if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0); + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); + return; + + case 0x41: // Rn = Rx OR Ry + UML_OR(block, REG(rn), REG(rx), REG(ry)); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN); + if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0); + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); + return; + + case 0x42: // Rn = Rx XOR Ry + UML_XOR(block, REG(rn), REG(rx), REG(ry)); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN); + if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0); + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); + return; + + case 0x62: // Rn = MAX(Rx, Ry) + UML_MOV(block, REG(rn), REG(rx)); + UML_CMP(block, REG(rx), REG(ry)); + UML_MOVc(block, COND_L, REG(rn), REG(ry)); + if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED) + UML_CMP(block, REG(rn), 0); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN); + if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0); + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); + return; + + case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: + { + /* Fixed-point Dual Add/Subtract */ + UML_ADD(block, I0, REG(rx), REG(ry)); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN); + if (AV_CALC_REQUIRED) UML_SETc(block, COND_V, ASTAT_AV); + if (AC_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AC); + UML_SUB(block, I1, REG(rx), REG(ry)); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, mem(&m_core->arg0)); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, mem(&m_core->arg1)); + if (AV_CALC_REQUIRED) UML_SETc(block, COND_V, mem(&m_core->arg2)); + if (AC_CALC_REQUIRED) UML_SETc(block, COND_C, mem(&m_core->arg3)); + if (AZ_CALC_REQUIRED) UML_OR(block, ASTAT_AZ, ASTAT_AZ, mem(&m_core->arg0)); + if (AN_CALC_REQUIRED) UML_OR(block, ASTAT_AN, ASTAT_AN, mem(&m_core->arg1)); + if (AV_CALC_REQUIRED) UML_OR(block, ASTAT_AV, ASTAT_AV, mem(&m_core->arg2)); + if (AC_CALC_REQUIRED) UML_OR(block, ASTAT_AC, ASTAT_AC, mem(&m_core->arg3)); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); + UML_MOV(block, REG(ra), I0); + UML_MOV(block, REG(rs), I1); + return; + } + + case 0x81: // Fn = Fx + Fy + // TODO: denormals + UML_FSCOPYI(block, F0, REG(rx)); + UML_FSCOPYI(block, F1, REG(ry)); + UML_FSADD(block, F0, F0, F1); + if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED) + UML_FSCMP(block, F0, mem(&m_core->fp0)); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AN); + if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0); // TODO + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); // TODO + UML_ICOPYFS(block, REG(rn), F0); + return; + + case 0x82: // Fn = Fx - Fy + // TODO: denormals + UML_FSCOPYI(block, F0, REG(rx)); + UML_FSCOPYI(block, F1, REG(ry)); + UML_FSSUB(block, F0, F0, F1); + if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED) + UML_FSCMP(block, F0, mem(&m_core->fp0)); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AN); + if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0); // TODO + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); // TODO + UML_ICOPYFS(block, REG(rn), F0); + return; + + case 0x8a: // COMP(Fx, Fy) + UML_FSCOPYI(block, F0, REG(rx)); + UML_FSCOPYI(block, F1, REG(ry)); + UML_FSCMP(block, F0, F1); + UML_SETc(block, COND_Z, I0); + UML_SETc(block, COND_C, I1); + UML_MOV(block, ASTAT_AZ, I0); + UML_MOV(block, ASTAT_AN, I1); + UML_XOR(block, I0, I0, 1); + UML_XOR(block, I1, I1, 1); + UML_AND(block, I0, I0, I1); + UML_SHL(block, I0, I0, 7); + + UML_MOV(block, I2, mem(&m_core->astat_drc.cacc)); + UML_SHR(block, I2, I2, 1); + UML_OR(block, I2, I2, I0); + UML_MOV(block, mem(&m_core->astat_drc.cacc), I2); + + if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0); + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); // TODO + return; + + case 0x91: // Fn = ABS(Fx + Fy) + // TODO: denormals + UML_FSCOPYI(block, F0, REG(rx)); + UML_FSCOPYI(block, F1, REG(ry)); + UML_FSADD(block, F0, F0, F1); + UML_FSABS(block, F0, F0); + UML_ICOPYFS(block, REG(rn), F0); + if (AZ_CALC_REQUIRED) UML_MOV(block, ASTAT_AZ, 0); // TODO + if (AN_CALC_REQUIRED) UML_MOV(block, ASTAT_AN, 0); + if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0); // TODO + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); // TODO + return; + + case 0xa1: // Fn = PASS Fx + UML_MOV(block, REG(rn), REG(rx)); + if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED) + { + UML_FSCOPYI(block, F0, REG(rn)); + UML_FSCMP(block, F0, mem(&m_core->fp0)); + } + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AN); + if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0); + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); // TODO + return; + + case 0xa2: // Fn = -Fx + UML_FSCOPYI(block, F0, REG(rx)); + UML_FSNEG(block, F0, F0); + UML_ICOPYFS(block, REG(rn), F0); + if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED) + UML_FSCMP(block, F0, mem(&m_core->fp0)); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AN); + if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0); + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); // TODO + return; + + case 0xbd: // Fn = SCALB Fx BY Ry + // TODO: source = nan, result = denormal + UML_MOV(block, I1, REG(rx)); + UML_AND(block, I0, I1, 0x7f800000); + UML_AND(block, I1, I1, 0x807fffff); + UML_SHR(block, I0, I0, 23); + UML_SUB(block, I0, I0, 127); + UML_ADD(block, I0, I0, REG(ry)); + UML_ADD(block, I0, I0, 127); + UML_AND(block, I0, I0, 0xff); + UML_SHL(block, I0, I0, 23); + UML_OR(block, REG(rn), I0, I1); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN); + if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0); // TODO + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); // TODO + return; + + case 0xc1: // Rn = LOGB Fx + // TODO: source = zero, infinity, nan + UML_SHR(block, I0, REG(rx), 23); + UML_AND(block, I0, I0, 0xff); + UML_SUB(block, REG(rn), I0, 127); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN); + if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0); // TODO + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); + return; + + case 0xc4: // Fn = RECIPS Fx + // TODO: denormals + // TODO: use the bit accurate method from interpreter? + UML_FSCOPYI(block, F0, REG(rx)); + if (AN_CALC_REQUIRED || AV_CALC_REQUIRED) + UML_FSCMP(block, F0, mem(&m_core->fp0)); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AN); + if (AV_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AV); + UML_FSCMP(block, F0, mem(&m_core->fp0)); + UML_JMPc(block, COND_Z, compiler->labelnum); + UML_FSRECIP(block, F0, F0); + UML_LABEL(block, compiler->labelnum++); + if (AZ_CALC_REQUIRED) + UML_FSCMP(block, F0, mem(&m_core->fp0)); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ); + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); // TODO + UML_ICOPYFS(block, REG(rn), F0); + return; + + case 0xc5: // Fn = RSQRTS Fx + // TODO: denormals + // TODO: use the bit accurate method from interpreter? + UML_FSCOPYI(block, F0, REG(rx)); + UML_FSCMP(block, F0, mem(&m_core->fp0)); + UML_JMPc(block, COND_Z, compiler->labelnum); + UML_FSRSQRT(block, F0, F0); + UML_LABEL(block, compiler->labelnum++); + UML_ICOPYFS(block, REG(rn), F0); + // TODO: flags! + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + return; + + case 0xca: // Fn = FLOAT Rx + UML_FSFRINT(block, F0, REG(rx), SIZE_DWORD); + UML_ICOPYFS(block, REG(rn), F0); + if (AZ_CALC_REQUIRED) + UML_FSCMP(block, F0, mem(&m_core->fp0)); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AN); + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); + return; + + case 0xd9: // Rn = FIX Fx BY Ry + { + code_label denormal = compiler->labelnum++; + code_label end = compiler->labelnum++; + + UML_MOV(block, I1, REG(rx)); + UML_AND(block, I0, I1, 0x7f800000); + UML_AND(block, I1, I1, 0x807fffff); + UML_SHR(block, I0, I0, 23); + UML_SUB(block, I0, I0, 127); + UML_ADD(block, I0, I0, REG(ry)); + UML_CMP(block, I0, -126); + UML_JMPc(block, COND_L, denormal); + + UML_ADD(block, I0, I0, 127); + UML_AND(block, I0, I0, 0xff); + UML_SHL(block, I0, I0, 23); + UML_OR(block, I0, I0, I1); + + UML_FSCOPYI(block, F2, I0); + UML_TEST(block, MODE1, MODE1_TRUNCATE); + UML_JMPc(block, COND_Z, compiler->labelnum); + UML_FSTOINT(block, I0, F2, SIZE_DWORD, ROUND_TRUNC); + UML_JMP(block, compiler->labelnum + 1); + UML_LABEL(block, compiler->labelnum++); + UML_FSTOINT(block, I0, F2, SIZE_DWORD, ROUND_ROUND); + UML_LABEL(block, compiler->labelnum++); + + if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED) + UML_CMP(block, I0, 0); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN); + if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0); // TODO + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); // TODO + UML_MOV(block, REG(rn), I0); + UML_JMP(block, end); + + UML_LABEL(block, denormal); + UML_AND(block, I0, I1, 0x80000000); + if (AZ_CALC_REQUIRED) UML_MOV(block, ASTAT_AZ, 1); + if (AN_CALC_REQUIRED) UML_MOV(block, ASTAT_AN, 0); + if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0); // TODO + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); + UML_MOV(block, REG(rn), I0); + + UML_LABEL(block, end); + return; + } + + case 0xda: // Fn = FLOAT Rx BY Ry + { + code_label denormal = compiler->labelnum++; + code_label end = compiler->labelnum++; + UML_FSFRINT(block, F0, REG(rx), SIZE_DWORD); + UML_ICOPYFS(block, I1, F0); + UML_AND(block, I0, I1, 0x7f800000); + UML_AND(block, I1, I1, 0x807fffff); + UML_SHR(block, I0, I0, 23); + UML_SUB(block, I0, I0, 127); + UML_ADD(block, I0, I0, REG(ry)); + UML_CMP(block, I0, -126); + UML_JMPc(block, COND_L, denormal); + + UML_ADD(block, I0, I0, 127); + UML_AND(block, I0, I0, 0xff); + UML_SHL(block, I0, I0, 23); + UML_OR(block, REG(rn), I0, I1); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_S, ASTAT_AN); + if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0); // TODO + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); + UML_JMP(block, end); + + UML_LABEL(block, denormal); + UML_AND(block, I0, I1, 0x80000000); + if (AZ_CALC_REQUIRED) UML_MOV(block, ASTAT_AZ, 1); + if (AN_CALC_REQUIRED) UML_MOV(block, ASTAT_AN, 0); + if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0); // TODO + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); + UML_MOV(block, REG(rn), I0); + + UML_LABEL(block, end); + return; + } + + case 0xe1: // Fn = MIN(Fx, Fy) + UML_FSCOPYI(block, F2, REG(rx)); + UML_FSCOPYI(block, F3, REG(ry)); + UML_FSMOV(block, F4, F2); + UML_FSCMP(block, F3, F2); + UML_FSMOVc(block, COND_C, F4, F3); + + if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED) + UML_FSCMP(block, F4, mem(&m_core->fp0)); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AN); + if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0); // TODO + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); // TODO + UML_ICOPYFS(block, REG(rn), F4); + return; + + case 0xe2: // Fn = MAX(Fx, Fy) + UML_FSCOPYI(block, F2, REG(rx)); + UML_FSCOPYI(block, F3, REG(ry)); + UML_FSMOV(block, F4, F2); + UML_FSCMP(block, F2, F3); + UML_FSMOVc(block, COND_C, F4, F3); + + if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED) + UML_FSCMP(block, F4, mem(&m_core->fp0)); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AN); + if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0); // TODO + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); // TODO + UML_ICOPYFS(block, REG(rn), F4); + return; + + case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff: + { + /* Floating-point Dual Add/Subtract */ + UML_FSCOPYI(block, F0, REG(rx)); + UML_FSCOPYI(block, F1, REG(ry)); + UML_FSADD(block, F2, F0, F1); + if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED) + UML_FSCMP(block, F2, mem(&m_core->fp0)); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_AZ); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_AN); + UML_FSSUB(block, F3, F0, F1); + if (AZ_CALC_REQUIRED || AN_CALC_REQUIRED) + UML_FSCMP(block, F2, mem(&m_core->fp0)); + if (AZ_CALC_REQUIRED) UML_SETc(block, COND_Z, I0); + if (AN_CALC_REQUIRED) UML_SETc(block, COND_C, I1); + if (AZ_CALC_REQUIRED) UML_OR(block, ASTAT_AZ, ASTAT_AZ, I0); + if (AN_CALC_REQUIRED) UML_OR(block, ASTAT_AN, ASTAT_AN, I1); + if (AV_CALC_REQUIRED) UML_MOV(block, ASTAT_AV, 0); // TODO + if (AC_CALC_REQUIRED) UML_MOV(block, ASTAT_AC, 0); + if (AS_CALC_REQUIRED) UML_MOV(block, ASTAT_AS, 0); + if (AI_CALC_REQUIRED) UML_MOV(block, ASTAT_AI, 0); // TODO + UML_ICOPYFS(block, REG(ra), F2); + UML_ICOPYFS(block, REG(rs), F3); + return; + } + + default: + generate_unimplemented_compute(block, compiler, desc); + return; + } + break; + } + + case 1: // multiplier operations + { + switch (operation) + { + case 0x48: // Rn = Rx * Ry (UUF) + case 0x49: // Rn = Rx * Ry (UUFR) + case 0x50: // Rn = Rx * Ry (SUI) + case 0x58: // Rn = Rx * Ry (SUF) + case 0x59: // Rn = Rx * Ry (SUFR) + case 0x60: // Rn = Rx * Ry (USI) + case 0x68: // Rn = Rx * Ry (USF) + case 0x69: // Rn = Rx * Ry (USFR) + case 0x70: // Rn = Rx * Ry (SSI) + case 0x78: // Rn = Rx * Ry (SSF) + case 0x79: // Rn = Rx * Ry (SSFR) + case 0x44: // MRF = Rx * Ry (UUI) + case 0x4c: // MRF = Rx * Ry (UUF) + case 0x4d: // MRF = Rx * Ry (UUFR) + case 0x54: // MRF = Rx * Ry (SUI) + case 0x5c: // MRF = Rx * Ry (SUF) + case 0x5d: // MRF = Rx * Ry (SUFR) + case 0x64: // MRF = Rx * Ry (USI) + case 0x6c: // MRF = Rx * Ry (USF) + case 0x6d: // MRF = Rx * Ry (USFR) + case 0x74: // MRF = Rx * Ry (SSI) + case 0x7c: // MRF = Rx * Ry (SSF) + case 0x7d: // MRF = Rx * Ry (SSFR) + case 0x46: // MRB = Rx * Ry (UUI) + case 0x4e: // MRB = Rx * Ry (UUF) + case 0x4f: // MRB = Rx * Ry (UUFR) + case 0x56: // MRB = Rx * Ry (SUI) + case 0x5e: // MRB = Rx * Ry (SUF) + case 0x5f: // MRB = Rx * Ry (SUFR) + case 0x66: // MRB = Rx * Ry (USI) + case 0x6e: // MRB = Rx * Ry (USF) + case 0x6f: // MRB = Rx * Ry (USFR) + case 0x76: // MRB = Rx * Ry (SSI) + case 0x7e: // MRB = Rx * Ry (SSF) + case 0x7f: // MRB = Rx * Ry (SSFR) + case 0x80: // Rn = MRF + Rx * Ry (UUI) + case 0x88: // Rn = MRF + Rx * Ry (UUF) + case 0x89: // Rn = MRF + Rx * Ry (UUFR) + case 0x90: // Rn = MRF + Rx * Ry (SUI) + case 0x98: // Rn = MRF + Rx * Ry (SUF) + case 0x99: // Rn = MRF + Rx * Ry (SUFR) + case 0xa0: // Rn = MRF + Rx * Ry (USI) + case 0xa8: // Rn = MRF + Rx * Ry (USF) + case 0xa9: // Rn = MRF + Rx * Ry (USFR) + case 0xb8: // Rn = MRF + Rx * Ry (SSF) + case 0xb9: // Rn = MRF + Rx * Ry (SSFR) + case 0x82: // Rn = MRB + Rx * Ry (UUI) + case 0x8a: // Rn = MRB + Rx * Ry (UUF) + case 0x8b: // Rn = MRB + Rx * Ry (UUFR) + case 0x92: // Rn = MRB + Rx * Ry (SUI) + case 0x9a: // Rn = MRB + Rx * Ry (SUF) + case 0x9b: // Rn = MRB + Rx * Ry (SUFR) + case 0xa2: // Rn = MRB + Rx * Ry (USI) + case 0xaa: // Rn = MRB + Rx * Ry (USF) + case 0xab: // Rn = MRB + Rx * Ry (USFR) + case 0xba: // Rn = MRB + Rx * Ry (SSF) + case 0xbb: // Rn = MRB + Rx * Ry (SSFR) + case 0x84: // MRF = MRF + Rx * Ry (UUI) + case 0x8c: // MRF = MRF + Rx * Ry (UUF) + case 0x8d: // MRF = MRF + Rx * Ry (UUFR) + case 0x94: // MRF = MRF + Rx * Ry (SUI) + case 0x9c: // MRF = MRF + Rx * Ry (SUF) + case 0x9d: // MRF = MRF + Rx * Ry (SUFR) + case 0xa4: // MRF = MRF + Rx * Ry (USI) + case 0xac: // MRF = MRF + Rx * Ry (USF) + case 0xad: // MRF = MRF + Rx * Ry (USFR) + case 0xb4: // MRF = MRF + Rx * Ry (SSI) + case 0xbc: // MRF = MRF + Rx * Ry (SSF) + case 0xbd: // MRF = MRF + Rx * Ry (SSFR) + case 0x86: // MRB = MRB + Rx * Ry (UUI) + case 0x8e: // MRB = MRB + Rx * Ry (UUF) + case 0x8f: // MRB = MRB + Rx * Ry (UUFR) + case 0x96: // MRB = MRB + Rx * Ry (SUI) + case 0x9e: // MRB = MRB + Rx * Ry (SUF) + case 0x9f: // MRB = MRB + Rx * Ry (SUFR) + case 0xa6: // MRB = MRB + Rx * Ry (USI) + case 0xae: // MRB = MRB + Rx * Ry (USF) + case 0xaf: // MRB = MRB + Rx * Ry (USFR) + case 0xb6: // MRB = MRB + Rx * Ry (SSI) + case 0xbe: // MRB = MRB + Rx * Ry (SSF) + case 0xbf: // MRB = MRB + Rx * Ry (SSFR) + case 0xc0: // Rn = MRF - Rx * Ry (UUI) + case 0xc8: // Rn = MRF - Rx * Ry (UUF) + case 0xc9: // Rn = MRF - Rx * Ry (UUFR) + case 0xd0: // Rn = MRF - Rx * Ry (SUI) + case 0xd8: // Rn = MRF - Rx * Ry (SUF) + case 0xd9: // Rn = MRF - Rx * Ry (SUFR) + case 0xe0: // Rn = MRF - Rx * Ry (USI) + case 0xe8: // Rn = MRF - Rx * Ry (USF) + case 0xe9: // Rn = MRF - Rx * Ry (USFR) + case 0xf0: // Rn = MRF - Rx * Ry (SSI) + case 0xf8: // Rn = MRF - Rx * Ry (SSF) + case 0xf9: // Rn = MRF - Rx * Ry (SSFR) + case 0xc2: // Rn = MRB - Rx * Ry (UUI) + case 0xca: // Rn = MRB - Rx * Ry (UUF) + case 0xcb: // Rn = MRB - Rx * Ry (UUFR) + case 0xd2: // Rn = MRB - Rx * Ry (SUI) + case 0xda: // Rn = MRB - Rx * Ry (SUF) + case 0xdb: // Rn = MRB - Rx * Ry (SUFR) + case 0xe2: // Rn = MRB - Rx * Ry (USI) + case 0xea: // Rn = MRB - Rx * Ry (USF) + case 0xeb: // Rn = MRB - Rx * Ry (USFR) + case 0xf2: // Rn = MRB - Rx * Ry (SSI) + case 0xfa: // Rn = MRB - Rx * Ry (SSF) + case 0xfb: // Rn = MRB - Rx * Ry (SSFR) + case 0xc4: // MRF = MRF - Rx * Ry (UUI) + case 0xcc: // MRF = MRF - Rx * Ry (UUF) + case 0xcd: // MRF = MRF - Rx * Ry (UUFR) + case 0xd4: // MRF = MRF - Rx * Ry (SUI) + case 0xdc: // MRF = MRF - Rx * Ry (SUF) + case 0xdd: // MRF = MRF - Rx * Ry (SUFR) + case 0xe4: // MRF = MRF - Rx * Ry (USI) + case 0xec: // MRF = MRF - Rx * Ry (USF) + case 0xed: // MRF = MRF - Rx * Ry (USFR) + case 0xf4: // MRF = MRF - Rx * Ry (SSI) + case 0xfc: // MRF = MRF - Rx * Ry (SSF) + case 0xfd: // MRF = MRF - Rx * Ry (SSFR) + case 0xc6: // MRB = MRB - Rx * Ry (UUI) + case 0xce: // MRB = MRB - Rx * Ry (UUF) + case 0xcf: // MRB = MRB - Rx * Ry (UUFR) + case 0xd6: // MRB = MRB - Rx * Ry (SUI) + case 0xde: // MRB = MRB - Rx * Ry (SUF) + case 0xdf: // MRB = MRB - Rx * Ry (SUFR) + case 0xe6: // MRB = MRB - Rx * Ry (USI) + case 0xee: // MRB = MRB - Rx * Ry (USF) + case 0xef: // MRB = MRB - Rx * Ry (USFR) + case 0xf6: // MRB = MRB - Rx * Ry (SSI) + case 0xfe: // MRB = MRB - Rx * Ry (SSF) + case 0xff: // MRB = MRB - Rx * Ry (SSFR) + case 0x00: // Rn = SAT MRF (UI) + case 0x01: // Rn = SAT MRF (SI) + case 0x08: // Rn = SAT MRF (UF) + case 0x09: // Rn = SAT MRF (SF) + case 0x02: // Rn = SAT MRB (UI) + case 0x03: // Rn = SAT MRB (SI) + case 0x0a: // Rn = SAT MRB (UF) + case 0x0b: // Rn = SAT MRB (SF) + case 0x04: // MRF = SAT MRF (UI) + case 0x05: // MRF = SAT MRF (SI) + case 0x0c: // MRF = SAT MRF (UF) + case 0x0d: // MRF = SAT MRF (SF) + case 0x06: // MRB = SAT MRB (UI) + case 0x07: // MRB = SAT MRB (SI) + case 0x0e: // MRB = SAT MRB (UF) + case 0x0f: // MRB = SAT MRB (SF) + case 0x18: // Rn = RND MRF (U) + case 0x19: // Rn = RND MRF (S) + case 0x1a: // Rn = RND MRB (U) + case 0x1b: // Rn = RND MRB (S) + case 0x1c: // MRF = RND MRF (U) + case 0x1d: // MRF = RND MRF (S) + case 0x1e: // MRB = RND MRB (U) + case 0x1f: // MRB = RND MRB (S) + generate_unimplemented_compute(block, compiler, desc); + return; + + case 0x14: // MRF = 0 + UML_DMOV(block, mem(&m_core->mrf), 0); + if (MN_CALC_REQUIRED) UML_MOV(block, ASTAT_MN, 0); + if (MV_CALC_REQUIRED) UML_MOV(block, ASTAT_MV, 0); + if (MU_CALC_REQUIRED) UML_MOV(block, ASTAT_MU, 0); + if (MI_CALC_REQUIRED) UML_MOV(block, ASTAT_MI, 0); + return; + + case 0x16: // MRB = 0 + UML_DMOV(block, mem(&m_core->mrb), 0); + if (MN_CALC_REQUIRED) UML_MOV(block, ASTAT_MN, 0); + if (MV_CALC_REQUIRED) UML_MOV(block, ASTAT_MV, 0); + if (MU_CALC_REQUIRED) UML_MOV(block, ASTAT_MU, 0); + if (MI_CALC_REQUIRED) UML_MOV(block, ASTAT_MI, 0); + return; + + case 0x30: // Fn = Fx * Fy + UML_FSCOPYI(block, F0, REG(rx)); + UML_FSCOPYI(block, F1, REG(ry)); + UML_FSMUL(block, F0, F0, F1); + UML_ICOPYFS(block, REG(rn), F0); + if (MN_CALC_REQUIRED) + UML_FSCMP(block, F0, mem(&m_core->fp0)); + if (MN_CALC_REQUIRED) UML_SETc(block, COND_C, ASTAT_MN); + // TODO: MV, MU, MI flags + return; + + case 0x40: // Rn = Rx * Ry (UUI) + UML_MULU(block, I0, I0, REG(rx), REG(ry)); + UML_MOV(block, REG(rn), I0); + // TODO: flags + return; + + case 0xb0: // Rn = MRF + Rx * Ry (SSI) + UML_DSEXT(block, I0, REG(rx), SIZE_DWORD); + UML_DSEXT(block, I1, REG(ry), SIZE_DWORD); + UML_DMULS(block, I0, I0, I0, I1); + UML_DADD(block, I0, I0, mem(&m_core->mrf)); + UML_MOV(block, REG(rn), I0); + // TODO: flags! + return; + + case 0xb2: // Rn = MRB + Rx * Ry (SSI) + UML_DSEXT(block, I0, REG(rx), SIZE_DWORD); + UML_DSEXT(block, I1, REG(ry), SIZE_DWORD); + UML_DMULS(block, I0, I0, I0, I1); + UML_DADD(block, I0, I0, mem(&m_core->mrb)); + UML_MOV(block, REG(rn), I0); + // TODO: flags! + return; + + default: + generate_unimplemented_compute(block, compiler, desc); + return; + } + break; + } + + case 2: // shifter operations + { + switch (operation) + { + case 0x00: // Rn = LSHIFT Rx BY Ry | <data8> + case 0x04: // Rn = ASHIFT Rx BY Ry | <data8> + case 0xc4: // Rn = BCLR Rx BY Ry | <data8> + case 0x44: // Rn = FDEP Rx BY Ry | <bit6>:<len6> + case 0x4c: // Rn = FDEP Rx BY Ry | <bit6>:<len6> (SE) + case 0x48: // Rn = FEXT Rx BY Ry | <bit6>:<len6> (SE) + case 0x24: // Rn = Rn OR ASHIFT Rx BY Ry | <data8> + case 0x64: // Rn = Rn OR FDEP Rx BY Ry | <bit6>:<len6> + case 0x6c: // Rn = Rn OR FDEP Rx BY Ry | <bit6>:<len6> (SE) + case 0x80: // Rn = EXP Rx + case 0x84: // Rn = EXP Rx (EX) + case 0x88: // Rn = LEFTZ Rx + case 0x8c: // Rn = LEFTO Rx + case 0x90: // Rn = FPACK Fx + case 0x94: // Fn = FUNPACK Rx + generate_unimplemented_compute(block, compiler, desc); + return; + + case 0x08: // Rn = ROT Rx BY Ry | <data8> + { + code_label shift_neg = compiler->labelnum++; + code_label shift_end = compiler->labelnum++; + + UML_MOV(block, I0, REG(ry)); + UML_CMP(block, I0, 0); + UML_JMPc(block, COND_L, shift_neg); + UML_ROL(block, I1, REG(rx), I0); + UML_JMP(block, shift_end); + UML_LABEL(block, shift_neg); + UML_SUB(block, I2, 0, I0); + UML_ROR(block, I1, REG(rx), I2); + UML_LABEL(block, shift_end); + if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ); + if (SV_CALC_REQUIRED) UML_MOV(block, ASTAT_SV, 0); + if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0); + UML_MOV(block, REG(rn), I1); + return; + } + + case 0x20: // Rn = Rn OR LSHIFT Rx BY Ry | <data8> + { + code_label shift_neg = compiler->labelnum++; + code_label shift_end = compiler->labelnum++; + + UML_MOV(block, I0, REG(ry)); + UML_CMP(block, I0, 0); + UML_JMPc(block, COND_L, shift_neg); + UML_SHL(block, I1, REG(rx), I0); + UML_JMP(block, shift_end); + UML_LABEL(block, shift_neg); + UML_SUB(block, I2, 0, I0); + UML_SHR(block, I1, REG(rx), I2); + UML_LABEL(block, shift_end); + if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ); + if (SV_CALC_REQUIRED) + { + UML_CMP(block, I0, 0); + UML_SETc(block, COND_NZ, ASTAT_SV); + } + if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0); + UML_OR(block, REG(rn), REG(rn), I1); + + return; + } + + case 0x40: // Rn = FEXT Rx BY Ry | <bit6>:<len6> + // extraction mask + UML_MOV(block, I0, REG(ry)); + UML_SHR(block, I1, I0, 6); + UML_AND(block, I1, I1, 0x3f); // i1 = len6 + UML_AND(block, I0, I0, 0x3f); // i0 = bit6 + UML_MOV(block, I3, 0xffffffff); + UML_SUB(block, I2, 32, I1); + UML_SHR(block, I3, I3, I2); + UML_SHL(block, I3, I3, I0); + + UML_AND(block, I2, REG(rx), I3); + UML_SHR(block, REG(rn), I2, I0); + if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ); + if (SV_CALC_REQUIRED) + { + UML_ADD(block, I0, I0, I1); + UML_CMP(block, I0, 32); + UML_SETc(block, COND_G, ASTAT_SV); + } + if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0); + return; + + case 0xc0: // Rn = BSET Rx BY Ry | <data8> + { + UML_MOV(block, I0, REG(ry)); + UML_MOV(block, I1, 1); + UML_SHL(block, I1, I1, I0); + UML_OR(block, REG(rn), REG(rn), I1); + if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ); + if (SV_CALC_REQUIRED) + { + UML_CMP(block, I0, 31); + UML_SETc(block, COND_G, ASTAT_SV); + } + if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0); + return; + } + + case 0xcc: // BTST Rx BY Ry | <data8> + { + UML_MOV(block, I0, REG(ry)); + UML_MOV(block, I1, 1); + UML_SHL(block, I1, I1, I0); + UML_TEST(block, REG(rx), I1); + if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ); + if (SV_CALC_REQUIRED) + UML_CMP(block, I0, 31); + if (SV_CALC_REQUIRED) UML_SETc(block, COND_G, ASTAT_SV); + if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0); + return; + } + + default: + generate_unimplemented_compute(block, compiler, desc); + return; + } + break; + } + + default: + generate_unimplemented_compute(block, compiler, desc); + return; + } + } +} + +void adsp21062_device::generate_if_condition(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int condition, int skip_label) +{ + // Jump to skip_label if condition is not true + code_label not_skip; + + switch (condition) + { + case 0x00: /* EQ */ + UML_TEST(block, ASTAT_AZ, 1); + UML_JMPc(block, COND_E, skip_label); + break; + case 0x01: /* LT */ + UML_TEST(block, ASTAT_AZ, 1); + UML_JMPc(block, COND_NE, skip_label); + UML_TEST(block, ASTAT_AN, 1); + UML_JMPc(block, COND_E, skip_label); + break; + case 0x02: /* LE */ + not_skip = compiler->labelnum++; + UML_TEST(block, ASTAT_AZ, 1); + UML_JMPc(block, COND_NZ, not_skip); + UML_TEST(block, ASTAT_AN, 1); + UML_JMPc(block, COND_NZ, not_skip); + UML_JMP(block, skip_label); + UML_LABEL(block, not_skip); + break; + case 0x03: /* AC */ + UML_TEST(block, ASTAT_AC, 1); + UML_JMPc(block, COND_E, skip_label); + break; + case 0x04: /* AV */ + UML_TEST(block, ASTAT_AV, 1); + UML_JMPc(block, COND_E, skip_label); + break; + case 0x05: /* MV */ + UML_TEST(block, ASTAT_MV, 1); + UML_JMPc(block, COND_E, skip_label); + break; + case 0x06: /* MS */ + UML_TEST(block, ASTAT_MN, 1); + UML_JMPc(block, COND_E, skip_label); + break; + case 0x07: /* SV */ + UML_TEST(block, ASTAT_SV, 1); + UML_JMPc(block, COND_E, skip_label); + break; + case 0x08: /* SZ */ + UML_TEST(block, ASTAT_SZ, 1); + UML_JMPc(block, COND_E, skip_label); + break; + case 0x09: /* FLAG0 */ + UML_CMP(block, FLAG0, 0); + UML_JMPc(block, COND_E, skip_label); + break; + case 0x0a: /* FLAG1 */ + UML_CMP(block, FLAG1, 0); + UML_JMPc(block, COND_E, skip_label); + break; + case 0x0b: /* FLAG2 */ + UML_CMP(block, FLAG2, 0); + UML_JMPc(block, COND_E, skip_label); + break; + case 0x0c: /* FLAG3 */ + UML_CMP(block, FLAG3, 0); + UML_JMPc(block, COND_E, skip_label); + break; + case 0x0d: /* TF */ + UML_TEST(block, ASTAT_BTF, 1); + UML_JMPc(block, COND_E, skip_label); + case 0x0e: /* BM */ + UML_JMP(block, skip_label); + case 0x0f: /* NOT LCE */ + UML_CMP(block, CURLCNTR, 1); + UML_JMPc(block, COND_E, skip_label); + break; + case 0x10: /* NOT EQUAL */ + UML_TEST(block, ASTAT_AZ, 1); + UML_JMPc(block, COND_NE, skip_label); + break; + case 0x11: /* GE */ + not_skip = compiler->labelnum++; + UML_TEST(block, ASTAT_AZ, 1); + UML_JMPc(block, COND_NZ, not_skip); + UML_TEST(block, ASTAT_AN, 1); + UML_JMPc(block, COND_Z, not_skip); + UML_JMP(block, skip_label); + UML_LABEL(block, not_skip); + break; + case 0x12: /* GT */ + UML_TEST(block, ASTAT_AZ, 1); + UML_JMPc(block, COND_NZ, skip_label); + UML_TEST(block, ASTAT_AN, 1); + UML_JMPc(block, COND_NZ, skip_label); + break; + case 0x13: /* NOT AC */ + UML_TEST(block, ASTAT_AC, 1); + UML_JMPc(block, COND_NE, skip_label); + break; + case 0x14: /* NOT AV */ + UML_TEST(block, ASTAT_AV, 1); + UML_JMPc(block, COND_NE, skip_label); + break; + case 0x15: /* NOT MV */ + UML_TEST(block, ASTAT_MV, 1); + UML_JMPc(block, COND_NE, skip_label); + break; + case 0x16: /* NOT MS */ + UML_TEST(block, ASTAT_MN, 1); + UML_JMPc(block, COND_NE, skip_label); + break; + case 0x17: /* NOT SV */ + UML_TEST(block, ASTAT_SV, 1); + UML_JMPc(block, COND_NE, skip_label); + break; + case 0x18: /* NOT SZ */ + UML_TEST(block, ASTAT_SZ, 1); + UML_JMPc(block, COND_NE, skip_label); + break; + case 0x19: /* NOT FLAG0 */ + UML_CMP(block, FLAG0, 0); + UML_JMPc(block, COND_NE, skip_label); + break; + case 0x1a: /* NOT FLAG1 */ + UML_CMP(block, FLAG1, 0); + UML_JMPc(block, COND_NE, skip_label); + break; + case 0x1b: /* NOT FLAG2 */ + UML_CMP(block, FLAG2, 0); + UML_JMPc(block, COND_NE, skip_label); + break; + case 0x1c: /* NOT FLAG3 */ + UML_CMP(block, FLAG3, 0); + UML_JMPc(block, COND_NE, skip_label); + break; + case 0x1d: /* NOT TF */ + UML_TEST(block, ASTAT_BTF, 1); + UML_JMPc(block, COND_NE, skip_label); + break; + case 0x1e: /* NOT BM */ + fatalerror("generate_if_condition 0x1e"); // should not happen + break; + case 0x1f: /* TRUE */ + fatalerror("generate_if_condition 0x1f"); // should not happen + break; + } +} + +void adsp21062_device::generate_do_condition(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int condition, int skip_label, ASTAT_DRC &astat) +{ + // Jump to skip_label if condition is true + code_label not_skip; + + UML_JMP(block, skip_label); + return; + + switch (condition) + { + case 0x00: /* EQ */ + UML_TEST(block, ASTAT_AZ, 1); + UML_JMPc(block, COND_NZ, skip_label); + break; + case 0x01: /* LT */ + not_skip = compiler->labelnum++; + UML_TEST(block, ASTAT_AZ, 1); + UML_JMPc(block, COND_NZ, not_skip); + UML_TEST(block, ASTAT_AN, 1); + UML_JMPc(block, COND_Z, not_skip); + UML_JMP(block, skip_label); + UML_LABEL(block, not_skip); + break; + case 0x02: /* LE */ + UML_TEST(block, ASTAT_AZ, 1); + UML_JMPc(block, COND_NZ, skip_label); + UML_TEST(block, ASTAT_AN, 1); + UML_JMPc(block, COND_NZ, skip_label); + break; + case 0x03: /* AC */ + UML_TEST(block, ASTAT_AC, 1); + UML_JMPc(block, COND_NZ, skip_label); + break; + case 0x04: /* AV */ + UML_TEST(block, ASTAT_AV, 1); + UML_JMPc(block, COND_NZ, skip_label); + break; + case 0x05: /* MV */ + UML_TEST(block, ASTAT_MV, 1); + UML_JMPc(block, COND_NZ, skip_label); + break; + case 0x06: /* MS */ + UML_TEST(block, ASTAT_MN, 1); + UML_JMPc(block, COND_NZ, skip_label); + break; + case 0x07: /* SV */ + UML_TEST(block, ASTAT_SV, 1); + UML_JMPc(block, COND_NZ, skip_label); + break; + case 0x08: /* SZ */ + UML_TEST(block, ASTAT_SZ, 1); + UML_JMPc(block, COND_NZ, skip_label); + break; + case 0x09: /* FLAG0 */ + UML_CMP(block, FLAG0, 0); + UML_JMPc(block, COND_NE, skip_label); + break; + case 0x0a: /* FLAG1 */ + UML_CMP(block, FLAG1, 0); + UML_JMPc(block, COND_NE, skip_label); + break; + case 0x0b: /* FLAG2 */ + UML_CMP(block, FLAG2, 0); + UML_JMPc(block, COND_NE, skip_label); + break; + case 0x0c: /* FLAG3 */ + UML_CMP(block, FLAG3, 0); + UML_JMPc(block, COND_NE, skip_label); + break; + case 0x0d: /* TF */ + UML_TEST(block, ASTAT_BTF, 1); + UML_JMPc(block, COND_NZ, skip_label); + break; + case 0x0e: /* BM */ + // infinite loop + break; + case 0x0f: /* LCE */ + fatalerror("generate_do_condition 0x0f"); // this should only be used with counter loops + break; + case 0x10: /* NOT EQUAL */ + UML_TEST(block, ASTAT_AZ, 1); + UML_JMPc(block, COND_Z, skip_label); + break; + case 0x11: /* GE */ + UML_TEST(block, ASTAT_AZ, 1); + UML_JMPc(block, COND_NZ, skip_label); + UML_TEST(block, ASTAT_AN, 1); + UML_JMPc(block, COND_Z, skip_label); + break; + case 0x12: /* GT */ + not_skip = compiler->labelnum++; + UML_TEST(block, ASTAT_AZ, 1); + UML_JMPc(block, COND_NZ, not_skip); + UML_TEST(block, ASTAT_AN, 1); + UML_JMPc(block, COND_NZ, not_skip); + UML_JMP(block, skip_label); + UML_LABEL(block, not_skip); + break; + case 0x13: /* NOT AC */ + UML_TEST(block, ASTAT_AC, 1); + UML_JMPc(block, COND_Z, skip_label); + break; + case 0x14: /* NOT AV */ + UML_TEST(block, ASTAT_AV, 1); + UML_JMPc(block, COND_Z, skip_label); + break; + case 0x15: /* NOT MV */ + UML_TEST(block, ASTAT_MV, 1); + UML_JMPc(block, COND_Z, skip_label); + break; + case 0x16: /* NOT MS */ + UML_TEST(block, ASTAT_MN, 1); + UML_JMPc(block, COND_Z, skip_label); + break; + case 0x17: /* NOT SV */ + UML_TEST(block, ASTAT_SV, 1); + UML_JMPc(block, COND_Z, skip_label); + break; + case 0x18: /* NOT SZ */ + UML_TEST(block, ASTAT_SZ, 1); + UML_JMPc(block, COND_Z, skip_label); + break; + case 0x19: /* NOT FLAG0 */ + UML_CMP(block, FLAG0, 0); + UML_JMPc(block, COND_E, skip_label); + break; + case 0x1a: /* NOT FLAG1 */ + UML_CMP(block, FLAG1, 0); + UML_JMPc(block, COND_E, skip_label); + break; + case 0x1b: /* NOT FLAG2 */ + UML_CMP(block, FLAG2, 0); + UML_JMPc(block, COND_E, skip_label); + break; + case 0x1c: /* NOT FLAG3 */ + UML_CMP(block, FLAG3, 0); + UML_JMPc(block, COND_E, skip_label); + break; + case 0x1d: /* NOT TF */ + UML_TEST(block, ASTAT_BTF, 1); + UML_JMPc(block, COND_Z, skip_label); + break; + case 0x1e: /* NOT BM */ + // always true + UML_JMP(block, skip_label); + break; + case 0x1f: /* FALSE (FOREVER) */ + // infinite loop + break; + } +} + +void adsp21062_device::generate_shift_imm(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int data, int shiftop, int rn, int rx) +{ + INT8 shift = data & 0xff; + int bit = data & 0x3f; + int len = (data >> 6) & 0x3f; + + switch (shiftop) + { + case 0x01: // ASHIFT Rx BY <data8> + case 0x11: // FDEP Rx BY <bit6>:<len6> + case 0x13: // FDEP Rx BY <bit6>:<len6> (SE) + case 0x1b: // Rn = Rn OR FDEP Rx BY <bit6>:<len6> (SE) + UML_MOV(block, mem(&m_core->pc), desc->pc); + UML_DMOV(block, mem(&m_core->arg64), desc->opptr.q[0]); + UML_CALLC(block, cfunc_unimplemented_shiftimm, this); + break; + + case 0x00: // LSHIFT Rx BY <data8> + if (abs(shift) >= 32) + { + UML_MOV(block, REG(rn), 0); + if (SZ_CALC_REQUIRED) UML_MOV(block, ASTAT_SZ, 1); + if (SV_CALC_REQUIRED) UML_MOV(block, ASTAT_SV, 1); + if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0); + } + else + { + if (shift < 0) + UML_SHR(block, REG(rn), REG(rx), -shift); + else + UML_SHL(block, REG(rn), REG(rx), shift); + if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ); + if (SV_CALC_REQUIRED && shift != 0) UML_MOV(block, ASTAT_SV, 1); + if (SV_CALC_REQUIRED && shift == 0) UML_MOV(block, ASTAT_SV, 0); + if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0); + } + return; + + case 0x02: // ROT Rx BY <data8> + UML_ROL(block, REG(rn), REG(rx), (shift < 0) ? 31 - ((-shift) & 0x1f) : shift & 0x1f); + if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ); + if (SV_CALC_REQUIRED) UML_MOV(block, ASTAT_SV, 0); + if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0); + return; + + case 0x08: // Rn = Rn OR LSHIFT Rx BY <data8> + if (abs(shift) >= 32) + { + UML_MOV(block, I0, 0); + if (SZ_CALC_REQUIRED) UML_MOV(block, ASTAT_SZ, 1); + if (SV_CALC_REQUIRED) UML_MOV(block, ASTAT_SV, 1); + if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0); + UML_OR(block, REG(rn), REG(rn), I0); + } + else + { + if (shift < 0) + UML_SHR(block, I0, REG(rx), -shift); + else + UML_SHL(block, I0, REG(rx), shift); + if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ); + if (SV_CALC_REQUIRED && shift != 0) UML_MOV(block, ASTAT_SV, 1); + if (SV_CALC_REQUIRED && shift == 0) UML_MOV(block, ASTAT_SV, 0); + if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0); + UML_OR(block, REG(rn), REG(rn), I0); + } + return; + + case 0x10: // FEXT Rx BY <bit6>:<len6> + if (bit == 0) + { + UML_AND(block, REG(rn), REG(rx), MAKE_EXTRACT_MASK(bit, len)); + } + else + { + UML_AND(block, I0, REG(rx), MAKE_EXTRACT_MASK(bit, len)); + UML_SHR(block, REG(rn), I0, bit); + } + if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ); + if (SV_CALC_REQUIRED && (bit + len) > 32) UML_MOV(block, ASTAT_SV, 1); + if (SV_CALC_REQUIRED && (bit + len) <= 32) UML_MOV(block, ASTAT_SV, 0); + if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0); + return; + + case 0x12: // FEXT Rx BY <bit6>:<len6> (SE) + UML_AND(block, I0, REG(rx), MAKE_EXTRACT_MASK(bit, len)); + UML_SHL(block, I0, I0, 32 - (bit + len)); + UML_SAR(block, REG(rn), I0, 32 - (bit + len) + bit); + if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ); + if (SV_CALC_REQUIRED && (bit + len) > 32) UML_MOV(block, ASTAT_SV, 1); + if (SV_CALC_REQUIRED && (bit + len) <= 32) UML_MOV(block, ASTAT_SV, 0); + if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0); + return; + + case 0x19: // Rn = Rn OR FDEP Rx BY <bit6>:<len6> + UML_AND(block, I0, REG(rx), MAKE_EXTRACT_MASK(0, len)); + if (bit > 0) + UML_SHL(block, I0, I0, bit); + UML_OR(block, REG(rn), REG(rn), I0); + + if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ); + if (SV_CALC_REQUIRED && (bit + len) > 32) UML_MOV(block, ASTAT_SV, 1); + if (SV_CALC_REQUIRED && (bit + len) <= 32) UML_MOV(block, ASTAT_SV, 0); + if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0); + return; + + case 0x30: // BSET Rx BY <data8> + UML_OR(block, REG(rn), REG(rx), 1 << data); + if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ); + if (SV_CALC_REQUIRED && data > 31) UML_MOV(block, ASTAT_SV, 1); + if (SV_CALC_REQUIRED && data <= 31) UML_MOV(block, ASTAT_SV, 0); + if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0); + return; + + case 0x31: // BCLR Rx By <data8> + UML_AND(block, REG(rn), REG(rx), ~(1 << data)); + if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ); + if (SV_CALC_REQUIRED && data > 31) UML_MOV(block, ASTAT_SV, 1); + if (SV_CALC_REQUIRED && data <= 31) UML_MOV(block, ASTAT_SV, 0); + if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0); + return; + + case 0x32: // BTGL Rx BY <data8> + UML_XOR(block, REG(rn), REG(rx), 1 << data); + if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ); + if (SV_CALC_REQUIRED && data > 31) UML_MOV(block, ASTAT_SV, 1); + if (SV_CALC_REQUIRED && data <= 31) UML_MOV(block, ASTAT_SV, 0); + if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0); + return; + + case 0x33: // BTST Rx BY <data8> + UML_TEST(block, REG(rx), 1 << data); + if (SZ_CALC_REQUIRED) UML_SETc(block, COND_Z, ASTAT_SZ); + if (SV_CALC_REQUIRED && data > 31) UML_MOV(block, ASTAT_SV, 1); + if (SV_CALC_REQUIRED && data <= 31) UML_MOV(block, ASTAT_SV, 0); + if (SS_CALC_REQUIRED) UML_MOV(block, ASTAT_SS, 0); + return; + + default: + UML_MOV(block, mem(&m_core->pc), desc->pc); + UML_DMOV(block, mem(&m_core->arg64), desc->opptr.q[0]); + UML_CALLC(block, cfunc_unimplemented_compute, this); + return; + } +}
\ No newline at end of file |