diff options
author | 2021-08-10 03:06:08 +0200 | |
---|---|---|
committer | 2021-08-09 21:06:08 -0400 | |
commit | 7fe8f9f74c8a8aca5e0ca949dafcac13504c3013 (patch) | |
tree | 3cd6d926ab025b2b965c01ff02dbfee69488abec /src/devices/cpu/rsp | |
parent | 1fc8bf7fcd88b672f1c9ab7427d80f0356358d85 (diff) |
Assorted N64 fixes (#8415)
* -rdp: Fixed incorrect channel swapping on 32-bit resampled framebuffers. [Ryan Holtz]
* -rsp: Fixed LWV and VMOV behavior. Added reserved instructions V056, V057, V073, and VNULL. [Ryan Holtz, krom]
* -rdp: Temporarily adjusted framebuffer resampling to not exceed screen bounds in some games. [Ryan Holtz]
* -n64: Fixed SP DMA behavior based on hardware tests. [Ryan Holtz]
* -rsp: Removed unused DRC and SIMD support. General code cleanup. [Ryan Holtz]
* -n64: Pass K4 and K5 factors to threaded drawing code. Fixes black geometry in Conker's Bad Fur Day. [Ryan Holtz]
* -aleck64: Fixed compile issue with previous commits. [Ryan Holtz]
Diffstat (limited to 'src/devices/cpu/rsp')
36 files changed, 2699 insertions, 11201 deletions
diff --git a/src/devices/cpu/rsp/clamp.h b/src/devices/cpu/rsp/clamp.h deleted file mode 100644 index 5b69b746a7d..00000000000 --- a/src/devices/cpu/rsp/clamp.h +++ /dev/null @@ -1,37 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Tyler J. Stachecki,Ryan Holtz - -static inline rsp_vec_t sclamp_acc_to_mid(rsp_vec_t acc_mid, rsp_vec_t acc_hi) -{ - return _mm_packs_epi32( - _mm_unpacklo_epi16(acc_mid, acc_hi), - _mm_unpackhi_epi16(acc_mid, acc_hi) - ); -} - -static inline rsp_vec_t uclamp_acc(rsp_vec_t val, rsp_vec_t acc_mid, rsp_vec_t acc_hi, rsp_vec_t zero) -{ - rsp_vec_t hi_negative = _mm_srai_epi16(acc_hi, 15); // 0x0000 - rsp_vec_t mid_negative = _mm_srai_epi16(acc_mid, 15); // 0xffff - - // We don't have to clamp if the HI part of the - // accumulator is sign-extended down to the MD part. - rsp_vec_t hi_sign_check = _mm_cmpeq_epi16(hi_negative, acc_hi); // 0x0000 - rsp_vec_t mid_sign_check = _mm_cmpeq_epi16(hi_negative, mid_negative); // 0x0000 - rsp_vec_t clamp_mask = _mm_and_si128(mid_sign_check, hi_sign_check); // 0x0000 - - // Generate the value in the event we need to clamp. - // * hi_negative, mid_sign => xxxx - // * hi_negative, !mid_sign => 0000 - // * !hi_negative, mid_sign => FFFF - // * !hi_negative, !mid_sign => xxxx - rsp_vec_t clamped_val = _mm_cmpeq_epi16(hi_negative, zero); // 0xffff - -#if (defined(__SSE4_1__) || defined(_MSC_VER)) - return _mm_blendv_epi8(clamped_val, val, clamp_mask); -#else - clamped_val = _mm_and_si128(clamp_mask, val); - val = _mm_andnot_si128(clamp_mask, clamped_val); - return _mm_or_si128(val, clamped_val); -#endif -} diff --git a/src/devices/cpu/rsp/rsp.cpp b/src/devices/cpu/rsp/rsp.cpp index 07deffc6e10..5d8cccff5af 100644 --- a/src/devices/cpu/rsp/rsp.cpp +++ b/src/devices/cpu/rsp/rsp.cpp @@ -9,13 +9,10 @@ #include "emu.h" #include "rsp.h" -#include "rspfe.h" -#include "rspcp2.h" -#include "rspcp2d.h" - #include "debugger.h" #include "rspdefs.h" +#include "rspdiv.h" #include "rsp_dasm.h" @@ -27,59 +24,72 @@ DEFINE_DEVICE_TYPE(RSP, rsp_device, "rsp", "Nintendo & SGI Reality Signal Proces #define SAVE_DMEM 0 #define RSP_TEST_SYNC 0 -#define PRINT_VECREG(x) osd_printf_debug("V%d: %04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X\n", (x), \ - (uint16_t)VREG_S((x),0), (uint16_t)VREG_S((x),1), \ - (uint16_t)VREG_S((x),2), (uint16_t)VREG_S((x),3), \ - (uint16_t)VREG_S((x),4), (uint16_t)VREG_S((x),5), \ - (uint16_t)VREG_S((x),6), (uint16_t)VREG_S((x),7)) +#define PRINT_VECREG(x) osd_printf_debug("V%d: %04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X\n", x, \ + m_v[x].w[0], m_v[x].w[1], m_v[x].w[2], m_v[x].w[3], \ + m_v[x].w[4], m_v[x].w[5], m_v[x].w[6], m_v[x].w[7]) -#define PRINT_ACCUM(x) osd_printf_debug("A%d: %08X|%08X\n", (x), \ - (uint32_t)( ( ACCUM(x) >> 32 ) & 0x00000000ffffffff ), \ - (uint32_t)( ACCUM(x) & 0x00000000ffffffff )) +#define PRINT_ACCUM(x) osd_printf_debug("A%d: %08X|%08X\n", x, (uint32_t)(m_accum[x].q >> 32), (uint32_t)m_accum[x].q); #define SIMM16 ((int32_t)(int16_t)(op)) #define UIMM16 ((uint16_t)(op)) #define UIMM26 (op & 0x03ffffff) -#define RSVAL (m_rsp_state->r[RSREG]) -#define RTVAL (m_rsp_state->r[RTREG]) -#define RDVAL (m_rsp_state->r[RDREG]) - -#define JUMP_ABS(addr) { m_nextpc = 0x04001000 | (((addr) << 2) & 0xfff); } -#define JUMP_ABS_L(addr,l) { m_nextpc = 0x04001000 | (((addr) << 2) & 0xfff); m_rsp_state->r[l] = m_rsp_state->pc + 4; } -#define JUMP_REL(offset) { m_nextpc = 0x04001000 | ((m_rsp_state->pc + ((offset) << 2)) & 0xfff); } -#define JUMP_REL_L(offset,l) { m_nextpc = 0x04001000 | ((m_rsp_state->pc + ((offset) << 2)) & 0xfff); m_rsp_state->r[l] = m_rsp_state->pc + 4; } -#define JUMP_PC(addr) { m_nextpc = 0x04001000 | ((addr) & 0xfff); } -#define JUMP_PC_L(addr,l) { m_nextpc = 0x04001000 | ((addr) & 0xfff); m_rsp_state->r[l] = m_rsp_state->pc + 4; } -#define LINK(l) { m_rsp_state->r[l] = m_rsp_state->pc + 4; } - -#define CARRY_FLAG(x) (m_vflag[CARRY][x & 7] != 0 ? 0xffff : 0) -#define COMPARE_FLAG(x) (m_vflag[COMPARE][x & 7] != 0 ? 0xffff : 0) -#define CLIP1_FLAG(x) (m_vflag[CLIP1][x & 7] != 0 ? 0xffff : 0) -#define ZERO_FLAG(x) (m_vflag[ZERO][x & 7] != 0 ? 0xffff : 0) -#define CLIP2_FLAG(x) (m_vflag[CLIP2][x & 7] != 0 ? 0xffff : 0) - -#define CLEAR_CARRY_FLAGS() { memset(m_vflag[CARRY], 0, 16); } -#define CLEAR_COMPARE_FLAGS() { memset(m_vflag[COMPARE], 0, 16); } -#define CLEAR_CLIP1_FLAGS() { memset(m_vflag[CLIP1], 0, 16); } -#define CLEAR_ZERO_FLAGS() { memset(m_vflag[ZERO], 0, 16); } -#define CLEAR_CLIP2_FLAGS() { memset(m_vflag[CLIP2], 0, 16); } - -#define SET_CARRY_FLAG(x) { m_vflag[CARRY][x & 7] = 0xffff; } -#define SET_COMPARE_FLAG(x) { m_vflag[COMPARE][x & 7] = 0xffff; } -#define SET_CLIP1_FLAG(x) { m_vflag[CLIP1][x & 7] = 0xffff; } -#define SET_ZERO_FLAG(x) { m_vflag[ZERO][x & 7] = 0xffff; } -#define SET_CLIP2_FLAG(x) { m_vflag[CLIP2][x & 7] = 0xffff; } - -#define CLEAR_CARRY_FLAG(x) { m_vflag[CARRY][x & 7] = 0; } -#define CLEAR_COMPARE_FLAG(x) { m_vflag[COMPARE][x & 7] = 0; } -#define CLEAR_CLIP1_FLAG(x) { m_vflag[CLIP1][x & 7] = 0; } -#define CLEAR_ZERO_FLAG(x) { m_vflag[ZERO][x & 7] = 0; } -#define CLEAR_CLIP2_FLAG(x) { m_vflag[CLIP2][x & 7] = 0; } - -#define ROPCODE(pc) m_pcache.read_dword(pc) +#define JUMP_ABS(addr) { m_nextpc = (addr) << 2; } +#define JUMP_ABS_L(addr,l) { m_nextpc = (addr) << 2; m_r[l] = m_pc + 4; } +#define JUMP_REL(offset) { m_nextpc = m_pc + ((offset) << 2); } +#define JUMP_REL_L(offset,l) { m_nextpc = m_pc + ((offset) << 2); m_r[l] = m_pc + 4; } +#define JUMP_PC(addr) { m_nextpc = addr; } +#define JUMP_PC_L(addr,l) { m_nextpc = addr; m_r[l] = m_pc + 4; } +#define ROPCODE(pc) m_icache.read_dword(pc & 0xfff) + +/*************************************************************************** + Helpful Vector Defines +***************************************************************************/ + +#define VDREG ((op >> 6) & 0x1f) +#define VS1REG ((op >> 11) & 0x1f) +#define VS2REG ((op >> 16) & 0x1f) +#define EL ((op >> 21) & 0xf) + +#define VREG_B(reg, offset) m_v[(reg)].b[(offset)^1] +#define W_VREG_B(reg, offset, val) (m_v[(reg)].b[(offset)^1] = val) + +#define VEC_EL_2(x,z) (vector_elements_2[(x)][(z)]) + +#define CARRY 0 +#define COMPARE 1 +#define CLIP1 2 +#define ZERO 3 +#define CLIP2 4 + +#define SLICE_H 3 +#define SLICE_M 2 +#define SLICE_L 1 +#define SLICE_LL 0 + +#define WRITEBACK_RESULT() memcpy(m_v[VDREG].s, vres, sizeof(uint16_t) * 8); + +static const int vector_elements_2[16][8] = +{ + { 0, 1, 2, 3, 4, 5, 6, 7 }, // none + { 0, 1, 2, 3, 4, 5, 6, 7 }, // ??? + { 0, 0, 2, 2, 4, 4, 6, 6 }, // 0q + { 1, 1, 3, 3, 5, 5, 7, 7 }, // 1q + { 0, 0, 0, 0, 4, 4, 4, 4 }, // 0h + { 1, 1, 1, 1, 5, 5, 5, 5 }, // 1h + { 2, 2, 2, 2, 6, 6, 6, 6 }, // 2h + { 3, 3, 3, 3, 7, 7, 7, 7 }, // 3h + { 0, 0, 0, 0, 0, 0, 0, 0 }, // 0 + { 1, 1, 1, 1, 1, 1, 1, 1 }, // 1 + { 2, 2, 2, 2, 2, 2, 2, 2 }, // 2 + { 3, 3, 3, 3, 3, 3, 3, 3 }, // 3 + { 4, 4, 4, 4, 4, 4, 4, 4 }, // 4 + { 5, 5, 5, 5, 5, 5, 5, 5 }, // 5 + { 6, 6, 6, 6, 6, 6, 6, 6 }, // 6 + { 7, 7, 7, 7, 7, 7, 7, 7 }, // 7 +}; /*************************************************************************** DEBUGGING @@ -103,39 +113,17 @@ DEFINE_DEVICE_TYPE(RSP, rsp_device, "rsp", "Nintendo & SGI Reality Signal Proces rsp_device::rsp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : cpu_device(mconfig, RSP, tag, owner, clock) - , m_program_config("program", ENDIANNESS_BIG, 32, 32) - , m_cache(CACHE_SIZE + sizeof(internal_rsp_state)) - , m_drcuml(nullptr) -// , m_drcuml(*this, m_cache, 0, 8, 32, 2) - , m_drcfe(nullptr) - , m_drcoptions(0) - , m_cache_dirty(true) - , m_numcycles(0) - , m_format(nullptr) - , m_arg2(0) - , m_arg3(0) - , m_entry(nullptr) - , m_nocode(nullptr) - , m_out_of_cycles(nullptr) - , m_read8(nullptr) - , m_write8(nullptr) - , m_read16(nullptr) - , m_write16(nullptr) - , m_read32(nullptr) - , m_write32(nullptr) - , m_rsp_state(nullptr) + , m_imem_config("imem", ENDIANNESS_BIG, 32, 12) + , m_dmem_config("dmem", ENDIANNESS_BIG, 32, 12) , m_exec_output(nullptr) , m_sr(0) , m_step_count(0) , m_ppc(0) - , m_nextpc(0) - , m_dmem32(nullptr) - , m_dmem16(nullptr) - , m_dmem8(nullptr) - , m_imem32(nullptr) - , m_imem16(nullptr) - , m_imem8(nullptr) + , m_nextpc(0xffff) , m_debugger_temp(0) + , m_pc_temp(0) + , m_ppc_temp(0) + , m_nextpc_temp(0xffff) , m_dp_reg_r_func(*this) , m_dp_reg_w_func(*this) , m_sp_reg_r_func(*this) @@ -151,7 +139,8 @@ rsp_device::~rsp_device() device_memory_interface::space_config_vector rsp_device::memory_space_config() const { return space_config_vector { - std::make_pair(AS_PROGRAM, &m_program_config) + std::make_pair(AS_PROGRAM, &m_imem_config), + std::make_pair(AS_DATA, &m_dmem_config) }; } @@ -160,133 +149,34 @@ std::unique_ptr<util::disasm_interface> rsp_device::create_disassembler() return std::make_unique<rsp_disassembler>(); } -void rsp_device::rsp_add_imem(uint32_t *base) -{ - m_imem32 = base; - m_imem16 = (uint16_t*)base; - m_imem8 = (uint8_t*)base; -} - -void rsp_device::rsp_add_dmem(uint32_t *base) -{ - m_dmem32 = base; - m_dmem16 = (uint16_t*)base; - m_dmem8 = (uint8_t*)base; -} - -uint8_t rsp_device::DM_READ8(uint32_t address) -{ - uint8_t ret = m_dmem8[BYTE4_XOR_BE(address & 0xfff)]; - //printf("R8:%08x=%02x\n", address, ret); - return ret; -} - -uint16_t rsp_device::DM_READ16(uint32_t address) -{ - uint16_t ret; - address &= 0xfff; - ret = m_dmem8[BYTE4_XOR_BE(address)] << 8; - ret |= m_dmem8[BYTE4_XOR_BE(address + 1)]; - //printf("R16:%08x=%04x\n", address, ret); - return ret; -} - -uint32_t rsp_device::DM_READ32(uint32_t address) -{ - uint32_t ret; - address &= 0xfff; - ret = m_dmem8[BYTE4_XOR_BE(address)] << 24; - ret |= m_dmem8[BYTE4_XOR_BE(address + 1)] << 16; - ret |= m_dmem8[BYTE4_XOR_BE(address + 2)] << 8; - ret |= m_dmem8[BYTE4_XOR_BE(address + 3)]; - //printf("R32:%08x=%08x\n", address, ret); - return ret; -} - -void rsp_device::DM_WRITE8(uint32_t address, uint8_t data) -{ - address &= 0xfff; - m_dmem8[BYTE4_XOR_BE(address)] = data; - //printf("W8:%08x=%02x\n", address, data); -} - -void rsp_device::DM_WRITE16(uint32_t address, uint16_t data) +uint8_t rsp_device::read_dmem_byte(uint32_t address) { - address &= 0xfff; - m_dmem8[BYTE4_XOR_BE(address)] = data >> 8; - m_dmem8[BYTE4_XOR_BE(address + 1)] = data & 0xff; - //printf("W16:%08x=%04x\n", address, data); + return m_dcache.read_byte(address); } -void rsp_device::DM_WRITE32(uint32_t address, uint32_t data) +uint16_t rsp_device::read_dmem_word(uint32_t address) { - address &= 0xfff; - m_dmem8[BYTE4_XOR_BE(address)] = data >> 24; - m_dmem8[BYTE4_XOR_BE(address + 1)] = (data >> 16) & 0xff; - m_dmem8[BYTE4_XOR_BE(address + 2)] = (data >> 8) & 0xff; - m_dmem8[BYTE4_XOR_BE(address + 3)] = data & 0xff; - //printf("W32:%08x=%08x\n", address, data); + return m_dcache.read_word_unaligned(address); } -uint8_t rsp_device::READ8(uint32_t address) +uint32_t rsp_device::read_dmem_dword(uint32_t address) { - uint8_t ret; - address &= 0xfff; - ret = m_program.read_byte(address); - //printf("R8:%08x=%02x\n", address, ret); - return ret; + return m_dcache.read_dword_unaligned(address); } -uint16_t rsp_device::READ16(uint32_t address) +void rsp_device::write_dmem_byte(uint32_t address, uint8_t data) { - uint16_t ret; - address &= 0xfff; - - ret = (m_program.read_byte(address) << 8) | (m_program.read_byte(address + 1) & 0xff); - - //printf("R16:%08x=%04x\n", address, ret); - return ret; -} - -uint32_t rsp_device::READ32(uint32_t address) -{ - uint32_t ret; - address &= 0xfff; - - ret = (m_program.read_byte(address) << 24) | - (m_program.read_byte(address + 1) << 16) | - (m_program.read_byte(address + 2) << 8) | - (m_program.read_byte(address + 3) << 0); - - //printf("R32:%08x=%08x\n", address, ret); - return ret; + m_dcache.write_byte(address, data); } -void rsp_device::WRITE8(uint32_t address, uint8_t data) +void rsp_device::write_dmem_word(uint32_t address, uint16_t data) { - address &= 0xfff; - m_program.write_byte(address, data); - //printf("W8:%08x=%02x\n", address, data); + m_dcache.write_word_unaligned(address, data); } -void rsp_device::WRITE16(uint32_t address, uint16_t data) +void rsp_device::write_dmem_dword(uint32_t address, uint32_t data) { - address &= 0xfff; - - m_program.write_byte(address, data >> 8); - m_program.write_byte(address + 1, data & 0xff); - //printf("W16:%08x=%04x\n", address, data); -} - -void rsp_device::WRITE32(uint32_t address, uint32_t data) -{ - address &= 0xfff; - - m_program.write_byte(address, data >> 24); - m_program.write_byte(address + 1, (data >> 16) & 0xff); - m_program.write_byte(address + 2, (data >> 8) & 0xff); - m_program.write_byte(address + 3, data & 0xff); - //printf("W32:%08x=%08x\n", address, data); + m_dcache.write_dword_unaligned(address, data); } /*****************************************************************************/ @@ -353,7 +243,7 @@ void rsp_device::unimplemented_opcode(uint32_t op) for (i=0; i < 0x1000; i++) { - fputc(READ8(rsp, 0x04000000 + i), dmem); + fputc(read_dmem_byte(i), dmem); } fclose(dmem); } @@ -375,97 +265,82 @@ void rsp_device::resolve_cb() void rsp_device::device_start() { - m_isdrc = allow_drc(); - m_rsp_state = (internal_rsp_state *)m_cache.alloc_near(sizeof(internal_rsp_state)); - if (LOG_INSTRUCTION_EXECUTION) m_exec_output = fopen("rsp_execute.txt", "wt"); - space(AS_PROGRAM).cache(m_pcache); - space(AS_PROGRAM).specific(m_program); + space(AS_PROGRAM).cache(m_icache); + space(AS_PROGRAM).specific(m_imem); + space(AS_DATA).cache(m_dcache); + space(AS_DATA).specific(m_dmem); resolve_cb(); - if (m_isdrc) - m_cop2 = std::make_unique<cop2_drc>(*this, machine()); - else - m_cop2 = std::make_unique<cop2>(*this, machine()); - - m_cop2->init(); - m_cop2->start(); - - // RSP registers should power on to a random state for (int regIdx = 0; regIdx < 32; regIdx++) - m_rsp_state->r[regIdx] = 0; - - m_sr = RSP_STATUS_HALT; - m_step_count = 0; + m_r[regIdx] = 0; - /* initialize the UML generator */ - uint32_t drc_flags = 0; - m_drcuml = std::make_unique<drcuml_state>(*this, m_cache, drc_flags, 8, 32, 2); - - /* add symbols for our stuff */ - m_drcuml->symbol_add(&m_rsp_state->pc, sizeof(m_rsp_state->pc), "pc"); - m_drcuml->symbol_add(&m_rsp_state->icount, sizeof(m_rsp_state->icount), "icount"); - for (int regnum = 0; regnum < 32; regnum++) + for(auto & elem : m_v) { - char buf[10]; - sprintf(buf, "r%d", regnum); - m_drcuml->symbol_add(&m_rsp_state->r[regnum], sizeof(m_rsp_state->r[regnum]), buf); + elem.d[0] = 0; + elem.d[1] = 0; } - m_drcuml->symbol_add(&m_rsp_state->arg0, sizeof(m_rsp_state->arg0), "arg0"); - m_drcuml->symbol_add(&m_rsp_state->arg1, sizeof(m_rsp_state->arg1), "arg1"); - m_drcuml->symbol_add(&m_arg2, sizeof(m_arg2), "arg2"); - m_drcuml->symbol_add(&m_arg3, sizeof(m_arg3), "arg3"); - m_drcuml->symbol_add(&m_numcycles, sizeof(m_numcycles), "numcycles"); - /* initialize the front-end helper */ - m_drcfe = std::make_unique<frontend>(*this, COMPILE_BACKWARDS_BYTES, COMPILE_FORWARDS_BYTES, SINGLE_INSTRUCTION_MODE ? 1 : COMPILE_MAX_SEQUENCE); + m_vcarry = 0; + m_vcompare = 0; + m_vclip1 = 0; + m_vzero = 0; + m_vclip2 = 0; + + m_reciprocal_res = 0; + m_reciprocal_high = 0; + m_ideduct = 0; + m_scalar_busy = false; + m_vector_busy = false; + m_paired_busy = false; - /* compute the register parameters */ - for (int regnum = 0; regnum < 32; regnum++) + for(auto & elem : m_accum) { - m_regmap[regnum] = (regnum == 0) ? uml::parameter(0) : uml::parameter::make_memory(&m_rsp_state->r[regnum]); + elem.q = 0; } - /* mark the cache dirty so it is updated on next execute */ - m_cache_dirty = true; - - state_add( RSP_PC, "PC", m_debugger_temp).callimport().callexport().formatstr("%08X"); - state_add( RSP_R0, "R0", m_rsp_state->r[0]).formatstr("%08X"); - state_add( RSP_R1, "R1", m_rsp_state->r[1]).formatstr("%08X"); - state_add( RSP_R2, "R2", m_rsp_state->r[2]).formatstr("%08X"); - state_add( RSP_R3, "R3", m_rsp_state->r[3]).formatstr("%08X"); - state_add( RSP_R4, "R4", m_rsp_state->r[4]).formatstr("%08X"); - state_add( RSP_R5, "R5", m_rsp_state->r[5]).formatstr("%08X"); - state_add( RSP_R6, "R6", m_rsp_state->r[6]).formatstr("%08X"); - state_add( RSP_R7, "R7", m_rsp_state->r[7]).formatstr("%08X"); - state_add( RSP_R8, "R8", m_rsp_state->r[8]).formatstr("%08X"); - state_add( RSP_R9, "R9", m_rsp_state->r[9]).formatstr("%08X"); - state_add( RSP_R10, "R10", m_rsp_state->r[10]).formatstr("%08X"); - state_add( RSP_R11, "R11", m_rsp_state->r[11]).formatstr("%08X"); - state_add( RSP_R12, "R12", m_rsp_state->r[12]).formatstr("%08X"); - state_add( RSP_R13, "R13", m_rsp_state->r[13]).formatstr("%08X"); - state_add( RSP_R14, "R14", m_rsp_state->r[14]).formatstr("%08X"); - state_add( RSP_R15, "R15", m_rsp_state->r[15]).formatstr("%08X"); - state_add( RSP_R16, "R16", m_rsp_state->r[16]).formatstr("%08X"); - state_add( RSP_R17, "R17", m_rsp_state->r[17]).formatstr("%08X"); - state_add( RSP_R18, "R18", m_rsp_state->r[18]).formatstr("%08X"); - state_add( RSP_R19, "R19", m_rsp_state->r[19]).formatstr("%08X"); - state_add( RSP_R20, "R20", m_rsp_state->r[20]).formatstr("%08X"); - state_add( RSP_R21, "R21", m_rsp_state->r[21]).formatstr("%08X"); - state_add( RSP_R22, "R22", m_rsp_state->r[22]).formatstr("%08X"); - state_add( RSP_R23, "R23", m_rsp_state->r[23]).formatstr("%08X"); - state_add( RSP_R24, "R24", m_rsp_state->r[24]).formatstr("%08X"); - state_add( RSP_R25, "R25", m_rsp_state->r[25]).formatstr("%08X"); - state_add( RSP_R26, "R26", m_rsp_state->r[26]).formatstr("%08X"); - state_add( RSP_R27, "R27", m_rsp_state->r[27]).formatstr("%08X"); - state_add( RSP_R28, "R28", m_rsp_state->r[28]).formatstr("%08X"); - state_add( RSP_R29, "R29", m_rsp_state->r[29]).formatstr("%08X"); - state_add( RSP_R30, "R30", m_rsp_state->r[30]).formatstr("%08X"); - state_add( RSP_R31, "R31", m_rsp_state->r[31]).formatstr("%08X"); + m_pc = 0; + m_nextpc = 0xffff; + m_sr = RSP_STATUS_HALT; + m_step_count = 0; + + state_add( RSP_PC, "PC", m_pc).callimport().callexport().formatstr("%08X"); + state_add( RSP_R0, "R0", m_r[0]).formatstr("%08X"); + state_add( RSP_R1, "R1", m_r[1]).formatstr("%08X"); + state_add( RSP_R2, "R2", m_r[2]).formatstr("%08X"); + state_add( RSP_R3, "R3", m_r[3]).formatstr("%08X"); + state_add( RSP_R4, "R4", m_r[4]).formatstr("%08X"); + state_add( RSP_R5, "R5", m_r[5]).formatstr("%08X"); + state_add( RSP_R6, "R6", m_r[6]).formatstr("%08X"); + state_add( RSP_R7, "R7", m_r[7]).formatstr("%08X"); + state_add( RSP_R8, "R8", m_r[8]).formatstr("%08X"); + state_add( RSP_R9, "R9", m_r[9]).formatstr("%08X"); + state_add( RSP_R10, "R10", m_r[10]).formatstr("%08X"); + state_add( RSP_R11, "R11", m_r[11]).formatstr("%08X"); + state_add( RSP_R12, "R12", m_r[12]).formatstr("%08X"); + state_add( RSP_R13, "R13", m_r[13]).formatstr("%08X"); + state_add( RSP_R14, "R14", m_r[14]).formatstr("%08X"); + state_add( RSP_R15, "R15", m_r[15]).formatstr("%08X"); + state_add( RSP_R16, "R16", m_r[16]).formatstr("%08X"); + state_add( RSP_R17, "R17", m_r[17]).formatstr("%08X"); + state_add( RSP_R18, "R18", m_r[18]).formatstr("%08X"); + state_add( RSP_R19, "R19", m_r[19]).formatstr("%08X"); + state_add( RSP_R20, "R20", m_r[20]).formatstr("%08X"); + state_add( RSP_R21, "R21", m_r[21]).formatstr("%08X"); + state_add( RSP_R22, "R22", m_r[22]).formatstr("%08X"); + state_add( RSP_R23, "R23", m_r[23]).formatstr("%08X"); + state_add( RSP_R24, "R24", m_r[24]).formatstr("%08X"); + state_add( RSP_R25, "R25", m_r[25]).formatstr("%08X"); + state_add( RSP_R26, "R26", m_r[26]).formatstr("%08X"); + state_add( RSP_R27, "R27", m_r[27]).formatstr("%08X"); + state_add( RSP_R28, "R28", m_r[28]).formatstr("%08X"); + state_add( RSP_R29, "R29", m_r[29]).formatstr("%08X"); + state_add( RSP_R30, "R30", m_r[30]).formatstr("%08X"); + state_add( RSP_R31, "R31", m_r[31]).formatstr("%08X"); state_add( RSP_SR, "SR", m_sr).formatstr("%08X"); - state_add( RSP_NEXTPC, "NPC", m_debugger_temp).callimport().callexport().formatstr("%08X"); + state_add( RSP_NEXTPC, "NPC", m_nextpc).callimport().callexport().formatstr("%04X"); state_add( RSP_STEPCNT, "STEP", m_step_count).formatstr("%08X"); state_add( RSP_V0, "V0", m_debugger_temp).formatstr("%39s"); @@ -501,12 +376,12 @@ void rsp_device::device_start() state_add( RSP_V30, "V30", m_debugger_temp).formatstr("%39s"); state_add( RSP_V31, "V31", m_debugger_temp).formatstr("%39s"); - state_add( STATE_GENPC, "GENPC", m_debugger_temp).callimport().callexport().noshow(); - state_add( STATE_GENPCBASE, "CURPC", m_rsp_state->pc).noshow(); - state_add( STATE_GENFLAGS, "GENFLAGS", m_debugger_temp).formatstr("%1s").noshow(); - state_add( STATE_GENSP, "GENSP", m_rsp_state->r[31]).noshow(); + state_add( STATE_GENPC, "GENPC", m_pc).noshow(); + state_add( STATE_GENPCBASE, "CURPC", m_pc).noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_r[31]).formatstr("%1s").noshow(); + state_add( STATE_GENSP, "GENSP", m_r[31]).noshow(); - set_icountptr(m_rsp_state->icount); + set_icountptr(m_icount); } void rsp_device::state_import(const device_state_entry &entry) @@ -515,15 +390,15 @@ void rsp_device::state_import(const device_state_entry &entry) { case STATE_GENPC: case RSP_PC: - m_rsp_state->pc = m_debugger_temp; + m_pc = (uint16_t)m_pc_temp; break; case STATE_GENPCBASE: - m_ppc = m_debugger_temp; + m_ppc = (uint16_t)m_ppc_temp; break; case RSP_NEXTPC: - m_nextpc = m_debugger_temp; + m_nextpc = (uint16_t)m_nextpc_temp; break; } } @@ -535,15 +410,15 @@ void rsp_device::state_export(const device_state_entry &entry) { case STATE_GENPC: case RSP_PC: - m_debugger_temp = m_rsp_state->pc | 0x04000000; + m_pc_temp = m_pc; break; case STATE_GENPCBASE: - m_debugger_temp = m_ppc | 0x04000000; + m_ppc_temp = m_ppc; break; case RSP_NEXTPC: - m_debugger_temp = m_nextpc | 0x04000000; + m_nextpc_temp = m_nextpc; break; } } @@ -551,13 +426,75 @@ void rsp_device::state_export(const device_state_entry &entry) void rsp_device::state_string_export(const device_state_entry &entry, std::string &str) const { const int index = entry.index(); - if (index >= RSP_V0 && index <= RSP_V31) - { - m_cop2->state_string_export(index, str); - } - else if (index == STATE_GENFLAGS) + switch (index) { - str = ""; + case RSP_V0: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[ 0].w[0], m_v[ 0].w[1], m_v[ 0].w[2], m_v[ 0].w[3], m_v[ 0].w[4], m_v[ 0].w[5], m_v[ 0].w[6], m_v[ 0].w[7]); break; + case RSP_V1: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[ 1].w[0], m_v[ 1].w[1], m_v[ 1].w[2], m_v[ 1].w[3], m_v[ 1].w[4], m_v[ 1].w[5], m_v[ 1].w[6], m_v[ 1].w[7]); break; + case RSP_V2: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[ 2].w[0], m_v[ 2].w[1], m_v[ 2].w[2], m_v[ 2].w[3], m_v[ 2].w[4], m_v[ 2].w[5], m_v[ 2].w[6], m_v[ 2].w[7]); break; + case RSP_V3: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[ 3].w[0], m_v[ 3].w[1], m_v[ 3].w[2], m_v[ 3].w[3], m_v[ 3].w[4], m_v[ 3].w[5], m_v[ 3].w[6], m_v[ 3].w[7]); break; + case RSP_V4: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[ 4].w[0], m_v[ 4].w[1], m_v[ 4].w[2], m_v[ 4].w[3], m_v[ 4].w[4], m_v[ 4].w[5], m_v[ 4].w[6], m_v[ 4].w[7]); break; + case RSP_V5: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[ 5].w[0], m_v[ 5].w[1], m_v[ 5].w[2], m_v[ 5].w[3], m_v[ 5].w[4], m_v[ 5].w[5], m_v[ 5].w[6], m_v[ 5].w[7]); break; + case RSP_V6: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[ 6].w[0], m_v[ 6].w[1], m_v[ 6].w[2], m_v[ 6].w[3], m_v[ 6].w[4], m_v[ 6].w[5], m_v[ 6].w[6], m_v[ 6].w[7]); break; + case RSP_V7: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[ 7].w[0], m_v[ 7].w[1], m_v[ 7].w[2], m_v[ 7].w[3], m_v[ 7].w[4], m_v[ 7].w[5], m_v[ 7].w[6], m_v[ 7].w[7]); break; + case RSP_V8: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[ 8].w[0], m_v[ 8].w[1], m_v[ 8].w[2], m_v[ 8].w[3], m_v[ 8].w[4], m_v[ 8].w[5], m_v[ 8].w[6], m_v[ 8].w[7]); break; + case RSP_V9: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[ 9].w[0], m_v[ 9].w[1], m_v[ 9].w[2], m_v[ 9].w[3], m_v[ 9].w[4], m_v[ 9].w[5], m_v[ 9].w[6], m_v[ 9].w[7]); break; + case RSP_V10: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[10].w[0], m_v[10].w[1], m_v[10].w[2], m_v[10].w[3], m_v[10].w[4], m_v[10].w[5], m_v[10].w[6], m_v[10].w[7]); break; + case RSP_V11: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[11].w[0], m_v[11].w[1], m_v[11].w[2], m_v[11].w[3], m_v[11].w[4], m_v[11].w[5], m_v[11].w[6], m_v[11].w[7]); break; + case RSP_V12: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[12].w[0], m_v[12].w[1], m_v[12].w[2], m_v[12].w[3], m_v[12].w[4], m_v[12].w[5], m_v[12].w[6], m_v[12].w[7]); break; + case RSP_V13: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[13].w[0], m_v[13].w[1], m_v[13].w[2], m_v[13].w[3], m_v[13].w[4], m_v[13].w[5], m_v[13].w[6], m_v[13].w[7]); break; + case RSP_V14: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[14].w[0], m_v[14].w[1], m_v[14].w[2], m_v[14].w[3], m_v[14].w[4], m_v[14].w[5], m_v[14].w[6], m_v[14].w[7]); break; + case RSP_V15: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[15].w[0], m_v[15].w[1], m_v[15].w[2], m_v[15].w[3], m_v[15].w[4], m_v[15].w[5], m_v[15].w[6], m_v[15].w[7]); break; + case RSP_V16: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[16].w[0], m_v[16].w[1], m_v[16].w[2], m_v[16].w[3], m_v[16].w[4], m_v[16].w[5], m_v[16].w[6], m_v[16].w[7]); break; + case RSP_V17: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[17].w[0], m_v[17].w[1], m_v[17].w[2], m_v[17].w[3], m_v[17].w[4], m_v[17].w[5], m_v[17].w[6], m_v[17].w[7]); break; + case RSP_V18: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[18].w[0], m_v[18].w[1], m_v[18].w[2], m_v[18].w[3], m_v[18].w[4], m_v[18].w[5], m_v[18].w[6], m_v[18].w[7]); break; + case RSP_V19: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[19].w[0], m_v[19].w[1], m_v[19].w[2], m_v[19].w[3], m_v[19].w[4], m_v[19].w[5], m_v[19].w[6], m_v[19].w[7]); break; + case RSP_V20: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[20].w[0], m_v[20].w[1], m_v[20].w[2], m_v[20].w[3], m_v[20].w[4], m_v[20].w[5], m_v[20].w[6], m_v[20].w[7]); break; + case RSP_V21: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[21].w[0], m_v[21].w[1], m_v[21].w[2], m_v[21].w[3], m_v[21].w[4], m_v[21].w[5], m_v[21].w[6], m_v[21].w[7]); break; + case RSP_V22: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[22].w[0], m_v[22].w[1], m_v[22].w[2], m_v[22].w[3], m_v[22].w[4], m_v[22].w[5], m_v[22].w[6], m_v[22].w[7]); break; + case RSP_V23: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[23].w[0], m_v[23].w[1], m_v[23].w[2], m_v[23].w[3], m_v[23].w[4], m_v[23].w[5], m_v[23].w[6], m_v[23].w[7]); break; + case RSP_V24: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[24].w[0], m_v[24].w[1], m_v[24].w[2], m_v[24].w[3], m_v[24].w[4], m_v[24].w[5], m_v[24].w[6], m_v[24].w[7]); break; + case RSP_V25: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[25].w[0], m_v[25].w[1], m_v[25].w[2], m_v[25].w[3], m_v[25].w[4], m_v[25].w[5], m_v[25].w[6], m_v[25].w[7]); break; + case RSP_V26: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[26].w[0], m_v[26].w[1], m_v[26].w[2], m_v[26].w[3], m_v[26].w[4], m_v[26].w[5], m_v[26].w[6], m_v[26].w[7]); break; + case RSP_V27: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[27].w[0], m_v[27].w[1], m_v[27].w[2], m_v[27].w[3], m_v[27].w[4], m_v[27].w[5], m_v[27].w[6], m_v[27].w[7]); break; + case RSP_V28: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[28].w[0], m_v[28].w[1], m_v[28].w[2], m_v[28].w[3], m_v[28].w[4], m_v[28].w[5], m_v[28].w[6], m_v[28].w[7]); break; + case RSP_V29: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[29].w[0], m_v[29].w[1], m_v[29].w[2], m_v[29].w[3], m_v[29].w[4], m_v[29].w[5], m_v[29].w[6], m_v[29].w[7]); break; + case RSP_V30: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[30].w[0], m_v[30].w[1], m_v[30].w[2], m_v[30].w[3], m_v[30].w[4], m_v[30].w[5], m_v[30].w[6], m_v[30].w[7]); break; + case RSP_V31: + str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[31].w[0], m_v[31].w[1], m_v[31].w[2], m_v[31].w[3], m_v[31].w[4], m_v[31].w[5], m_v[31].w[6], m_v[31].w[7]); break; + case STATE_GENFLAGS: + str = ""; + break; } } @@ -582,21 +519,11 @@ void rsp_device::device_stop() #if SAVE_DMEM { int i; - FILE *dmem; -#if 0 - dmem = fopen("rsp_dmem.txt", "wt"); - - for (i=0; i < 0x1000; i+=4) - { - fprintf(dmem, "%08X: %08X\n", 0x04000000 + i, READ32(0x04000000 + i)); - } - fclose(dmem); -#endif - dmem = fopen("rsp_dmem.bin", "wb"); + FILE *dmem = fopen("rsp_dmem.bin", "wb"); for (i=0; i < 0x1000; i++) { - fputc(READ8(0x04000000 + i), dmem); + fputc(read_dmem_byte(i), dmem); } fclose(dmem); } @@ -609,70 +536,2383 @@ void rsp_device::device_stop() void rsp_device::device_reset() { - m_nextpc = ~0; + m_nextpc = 0xffff; } -void rsp_device::execute_run() +uint16_t rsp_device::SATURATE_ACCUM(int accum, int slice, uint16_t negative, uint16_t positive) { - if (m_isdrc) + if ((int16_t)m_accum[accum].w[SLICE_H] < 0) + { + if ((uint16_t)m_accum[accum].w[SLICE_H] != 0xffff) + { + return negative; + } + else + { + if ((int16_t)m_accum[accum].w[SLICE_M] >= 0) + { + return negative; + } + else + { + if (slice == 0) + { + return m_accum[accum].w[SLICE_L]; + } + else if (slice == 1) + { + return m_accum[accum].w[SLICE_M]; + } + } + } + } + else { - execute_run_drc(); - return; + if ((uint16_t)m_accum[accum].w[SLICE_H] != 0) + { + return positive; + } + else + { + if ((int16_t)m_accum[accum].w[SLICE_M] < 0) + { + return positive; + } + else + { + if (slice == 0) + { + return m_accum[accum].w[SLICE_L]; + } + else + { + return m_accum[accum].w[SLICE_M]; + } + } + } } + return 0; +} + +void rsp_device::handle_vector_ops(uint32_t op) +{ + uint16_t vres[8]; - m_rsp_state->pc = 0x4001000 | (m_rsp_state->pc & 0xfff); + // Opcode legend: + // E = VS2 element type + // S = VS1, Source vector 1 + // T = VS2, Source vector 2 + // D = Destination vector - if( m_sr & ( RSP_STATUS_HALT | RSP_STATUS_BROKE ) ) + switch (op & 0x3f) { - m_rsp_state->icount = std::min(m_rsp_state->icount, 0); + case 0x00: /* VMULF */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000000 | + // ------------------------------------------------------ + // + // Multiplies signed integer by signed integer * 2 + + for (int i = 0; i < 8; i++) + { + int32_t s1 = m_v[VS1REG].s[i]; + int32_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)]; + + if (s1 == -32768 && s2 == -32768) + { + // overflow + m_accum[i].w[SLICE_H] = 0; + m_accum[i].w[SLICE_M] = -32768; + m_accum[i].w[SLICE_L] = -32768; + vres[i] = 0x7fff; + } + else + { + int64_t r = s1 * s2 * 2; + r += 0x8000; // rounding ? + m_accum[i].w[SLICE_H] = (r < 0) ? 0xffff : 0; // Sign-extend to 48-bit + m_accum[i].w[SLICE_M] = (int16_t)(r >> 16); + m_accum[i].w[SLICE_L] = (uint16_t)r; + vres[i] = m_accum[i].w[SLICE_M]; + } + } + WRITEBACK_RESULT(); + break; + } + + case 0x01: /* VMULU */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000001 | + // ------------------------------------------------------ + // + + for (int i = 0; i < 8; i++) + { + int32_t s1 = m_v[VS1REG].s[i]; + int32_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)]; + + int64_t r = s1 * s2 * 2; + r += 0x8000; // rounding ? + + m_accum[i].w[SLICE_H] = (uint16_t)(r >> 32); + m_accum[i].w[SLICE_M] = (uint16_t)(r >> 16); + m_accum[i].w[SLICE_L] = (uint16_t)r; + + if (r < 0) + { + vres[i] = 0; + } + else if (((int16_t)m_accum[i].w[SLICE_H] ^ (int16_t)m_accum[i].w[SLICE_M]) < 0) + { + vres[i] = -1; + } + else + { + vres[i] = m_accum[i].w[SLICE_M]; + } + } + WRITEBACK_RESULT(); + break; + } + + case 0x04: /* VMUDL */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000100 | + // ------------------------------------------------------ + // + // Multiplies unsigned fraction by unsigned fraction + // Stores the higher 16 bits of the 32-bit result to accumulator + // The low slice of accumulator is stored into destination element + + for (int i = 0; i < 8; i++) + { + uint32_t s1 = m_v[VS1REG].w[i]; + uint32_t s2 = m_v[VS2REG].w[VEC_EL_2(EL, i)]; + uint32_t r = s1 * s2; + + m_accum[i].w[SLICE_H] = 0; + m_accum[i].w[SLICE_M] = 0; + m_accum[i].w[SLICE_L] = (uint16_t)(r >> 16); + + vres[i] = m_accum[i].w[SLICE_L]; + } + WRITEBACK_RESULT(); + break; + } + + case 0x05: /* VMUDM */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000101 | + // ------------------------------------------------------ + // + // Multiplies signed integer by unsigned fraction + // The result is stored into accumulator + // The middle slice of accumulator is stored into destination element + + for (int i = 0; i < 8; i++) + { + int32_t s1 = m_v[VS1REG].s[i]; + int32_t s2 = m_v[VS2REG].w[VEC_EL_2(EL, i)]; // not sign-extended + int32_t r = s1 * s2; + + m_accum[i].w[SLICE_H] = (r < 0) ? 0xffff : 0; // sign-extend to 48-bit + m_accum[i].w[SLICE_M] = (int16_t)(r >> 16); + m_accum[i].w[SLICE_L] = (uint16_t)r; + + vres[i] = m_accum[i].w[SLICE_M]; + } + WRITEBACK_RESULT(); + break; + } + + case 0x06: /* VMUDN */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000110 | + // ------------------------------------------------------ + // + // Multiplies unsigned fraction by signed integer + // The result is stored into accumulator + // The low slice of accumulator is stored into destination element + + for (int i = 0; i < 8; i++) + { + int32_t s1 = m_v[VS1REG].w[i]; // not sign-extended + int32_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)]; + int32_t r = s1 * s2; + + m_accum[i].w[SLICE_H] = (r < 0) ? 0xffff : 0; // sign-extend to 48-bit + m_accum[i].w[SLICE_M] = (int16_t)(r >> 16); + m_accum[i].w[SLICE_L] = (uint16_t)(r); + + vres[i] = m_accum[i].w[SLICE_L]; + } + WRITEBACK_RESULT(); + break; + } + + case 0x07: /* VMUDH */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000111 | + // ------------------------------------------------------ + // + // Multiplies signed integer by signed integer + // The result is stored into highest 32 bits of accumulator, the low slice is zero + // The highest 32 bits of accumulator is saturated into destination element + + for (int i = 0; i < 8; i++) + { + int32_t s1 = m_v[VS1REG].s[i]; + int32_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)]; + int32_t r = s1 * s2; + + m_accum[i].w[SLICE_H] = (int16_t)(r >> 16); + m_accum[i].w[SLICE_M] = (uint16_t)(r); + m_accum[i].w[SLICE_L] = 0; + + if (r < -32768) r = -32768; + if (r > 32767) r = 32767; + vres[i] = (int16_t)(r); + } + WRITEBACK_RESULT(); + break; + } + + case 0x08: /* VMACF */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001000 | + // ------------------------------------------------------ + // + // Multiplies signed integer by signed integer * 2 + // The result is added to accumulator + + for (int i = 0; i < 8; i++) + { + int32_t s1 = m_v[VS1REG].s[i]; + int32_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)]; + int32_t r = s1 * s2; + + uint64_t q = (uint64_t)(uint16_t)m_accum[i].w[SLICE_LL]; + q |= (((uint64_t)(uint16_t)m_accum[i].w[SLICE_L]) << 16); + q |= (((uint64_t)(uint16_t)m_accum[i].w[SLICE_M]) << 32); + q |= (((uint64_t)(uint16_t)m_accum[i].w[SLICE_H]) << 48); + + q += (int64_t)(r) << 17; + + m_accum[i].w[SLICE_LL] = (uint16_t)q; + m_accum[i].w[SLICE_L] = (uint16_t)(q >> 16); + m_accum[i].w[SLICE_M] = (uint16_t)(q >> 32); + m_accum[i].w[SLICE_H] = (uint16_t)(q >> 48); + + vres[i] = SATURATE_ACCUM(i, 1, 0x8000, 0x7fff); + } + WRITEBACK_RESULT(); + break; + } + + case 0x09: /* VMACU */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001001 | + // ------------------------------------------------------ + // + + for (int i = 0; i < 8; i++) + { + int32_t s1 = m_v[VS1REG].s[i]; + int32_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)]; + int32_t r1 = s1 * s2; + uint32_t r2 = m_accum[i].w[SLICE_L] + ((uint16_t)r1 * 2); + uint32_t r3 = m_accum[i].w[SLICE_M] + (uint16_t)((r1 >> 16) * 2) + (uint16_t)(r2 >> 16); + + m_accum[i].w[SLICE_L] = (uint16_t)r2; + m_accum[i].w[SLICE_M] = (uint16_t)r3; + m_accum[i].w[SLICE_H] += (uint16_t)(r3 >> 16) + (uint16_t)(r1 >> 31); + + if ((int16_t)m_accum[i].w[SLICE_H] < 0) + { + vres[i] = 0; + } + else + { + if (m_accum[i].w[SLICE_H] != 0) + { + vres[i] = 0xffff; + } + else + { + if ((int16_t)m_accum[i].w[SLICE_M] < 0) + { + vres[i] = 0xffff; + } + else + { + vres[i] = m_accum[i].w[SLICE_M]; + } + } + } + } + WRITEBACK_RESULT(); + break; + } + + case 0x0c: /* VMADL */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001100 | + // ------------------------------------------------------ + // + // Multiplies unsigned fraction by unsigned fraction + // Adds the higher 16 bits of the 32-bit result to accumulator + // The low slice of accumulator is stored into destination element + + for (int i = 0; i < 8; i++) + { + uint32_t s1 = m_v[VS1REG].w[i]; + uint32_t s2 = m_v[VS2REG].w[VEC_EL_2(EL, i)]; + uint32_t r1 = s1 * s2; + uint32_t r2 = m_accum[i].w[SLICE_L] + (r1 >> 16); + uint32_t r3 = m_accum[i].w[SLICE_M] + (r2 >> 16); + + m_accum[i].w[SLICE_L] = (uint16_t)r2; + m_accum[i].w[SLICE_M] = (uint16_t)r3; + m_accum[i].w[SLICE_H] += (int16_t)(r3 >> 16); + + vres[i] = SATURATE_ACCUM(i, 0, 0x0000, 0xffff); + } + WRITEBACK_RESULT(); + break; + } + + case 0x0d: /* VMADM */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001101 | + // ------------------------------------------------------ + // + // Multiplies signed integer by unsigned fraction + // The result is added into accumulator + // The middle slice of accumulator is stored into destination element + + for (int i = 0; i < 8; i++) + { + uint32_t s1 = m_v[VS1REG].s[i]; + uint32_t s2 = m_v[VS2REG].w[VEC_EL_2(EL, i)]; // not sign-extended + uint32_t r1 = s1 * s2; + uint32_t r2 = (uint16_t)m_accum[i].w[SLICE_L] + (uint16_t)(r1); + uint32_t r3 = (uint16_t)m_accum[i].w[SLICE_M] + (r1 >> 16) + (r2 >> 16); + + m_accum[i].w[SLICE_L] = (uint16_t)r2; + m_accum[i].w[SLICE_M] = (uint16_t)r3; + m_accum[i].w[SLICE_H] += (uint16_t)(r3 >> 16); + if ((int32_t)r1 < 0) + m_accum[i].w[SLICE_H] -= 1; + + vres[i] = SATURATE_ACCUM(i, 1, 0x8000, 0x7fff); + } + WRITEBACK_RESULT(); + break; + } + + case 0x0e: /* VMADN */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001110 | + // ------------------------------------------------------ + // + // Multiplies unsigned fraction by signed integer + // The result is added into accumulator + // The low slice of accumulator is stored into destination element + + for (int i = 0; i < 8; i++) + { + int32_t s1 = m_v[VS1REG].w[i]; // not sign-extended + int32_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)]; + + uint64_t q = (uint64_t)m_accum[i].w[SLICE_LL]; + q |= (((uint64_t)m_accum[i].w[SLICE_L]) << 16); + q |= (((uint64_t)m_accum[i].w[SLICE_M]) << 32); + q |= (((uint64_t)m_accum[i].w[SLICE_H]) << 48); + q += (int64_t)(s1*s2) << 16; + + m_accum[i].w[SLICE_LL] = (uint16_t)q; + m_accum[i].w[SLICE_L] = (uint16_t)(q >> 16); + m_accum[i].w[SLICE_M] = (uint16_t)(q >> 32); + m_accum[i].w[SLICE_H] = (uint16_t)(q >> 48); + + vres[i] = SATURATE_ACCUM(i, 0, 0x0000, 0xffff); + } + WRITEBACK_RESULT(); + + break; + } + + case 0x0f: /* VMADH */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001111 | + // ------------------------------------------------------ + // + // Multiplies signed integer by signed integer + // The result is added into highest 32 bits of accumulator, the low slice is zero + // The highest 32 bits of accumulator is saturated into destination element + + for (int i = 0; i < 8; i++) + { + int32_t s1 = m_v[VS1REG].s[i]; + int32_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)]; + + int32_t accum = (uint32_t)(uint16_t)m_accum[i].w[SLICE_M]; + accum |= ((uint32_t)((uint16_t)m_accum[i].w[SLICE_H])) << 16; + accum += s1 * s2; + + m_accum[i].w[SLICE_H] = (uint16_t)(accum >> 16); + m_accum[i].w[SLICE_M] = (uint16_t)accum; + + vres[i] = SATURATE_ACCUM(i, 1, 0x8000, 0x7fff); + } + WRITEBACK_RESULT(); + break; + } + + case 0x10: /* VADD */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010000 | + // ------------------------------------------------------ + // + // Adds two vector registers and carry flag, the result is saturated to 32767 + + // TODO: check VS2REG == VDREG + + for (int i = 0; i < 8; i++) + { + int32_t s1 = m_v[VS1REG].s[i]; + int32_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)]; + int32_t r = s1 + s2 + BIT(m_vcarry, i); + + m_accum[i].w[SLICE_L] = (int16_t)r; + + if (r > 32767) r = 32767; + if (r < -32768) r = -32768; + vres[i] = (int16_t)(r); + } + m_vzero = 0; + m_vcarry = 0; + WRITEBACK_RESULT(); + break; + } + + case 0x11: /* VSUB */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010001 | + // ------------------------------------------------------ + // + // Subtracts two vector registers and carry flag, the result is saturated to -32768 + + // TODO: check VS2REG == VDREG + + for (int i = 0; i < 8; i++) + { + int32_t s1 = m_v[VS1REG].s[i]; + int32_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)]; + int32_t r = s1 - s2 - BIT(m_vcarry, i); + + m_accum[i].w[SLICE_L] = (int16_t)r; + + if (r > 32767) r = 32767; + if (r < -32768) r = -32768; + + vres[i] = (int16_t)(r); + } + m_vzero = 0; + m_vcarry = 0; + WRITEBACK_RESULT(); + break; + } + + case 0x13: /* VABS */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010011 | + // ------------------------------------------------------ + // + // Changes the sign of source register 2 if source register 1 is negative and stores + // the result to destination register + + for (int i = 0; i < 8; i++) + { + int16_t s1 = m_v[VS1REG].s[i]; + int16_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)]; + + if (s1 < 0) + { + if (s2 == -32768) + { + vres[i] = 32767; + } + else + { + vres[i] = -s2; + } + } + else if (s1 > 0) + { + vres[i] = s2; + } + else + { + vres[i] = 0; + } + + m_accum[i].w[SLICE_L] = vres[i]; + } + WRITEBACK_RESULT(); + break; + } + + case 0x14: /* VADDC */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010100 | + // ------------------------------------------------------ + // + // Adds two vector registers, the carry out is stored into carry register + + // TODO: check VS2REG = VDREG + + m_vzero = 0; + m_vcarry = 0; + + for (int i = 0; i < 8; i++) + { + int32_t s1 = m_v[VS1REG].w[i]; + int32_t s2 = m_v[VS2REG].w[VEC_EL_2(EL, i)]; + int32_t r = s1 + s2; + + vres[i] = (int16_t)r; + m_accum[i].w[SLICE_L] = (int16_t)r; + + if (r & 0xffff0000) + { + m_vcarry |= 1 << i; + } + } + WRITEBACK_RESULT(); + break; + } + + case 0x15: /* VSUBC */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010101 | + // ------------------------------------------------------ + // + // Subtracts two vector registers, the carry out is stored into carry register + + // TODO: check VS2REG = VDREG + + m_vzero = 0; + m_vcarry = 0; + + for (int i = 0; i < 8; i++) + { + int32_t s1 = m_v[VS1REG].w[i]; + int32_t s2 = m_v[VS2REG].w[VEC_EL_2(EL, i)]; + int32_t r = s1 - s2; + + vres[i] = (int16_t)(r); + m_accum[i].w[SLICE_L] = (uint16_t)r; + + if ((uint16_t)r != 0) + { + m_vzero |= 1 << i; + } + if (r & 0xffff0000) + { + m_vcarry |= 1 << i; + } + } + WRITEBACK_RESULT(); + break; + } + + case 0x1d: /* VSAW */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 011101 | + // ------------------------------------------------------ + // + // Stores high, middle or low slice of accumulator to destination vector + + switch (EL) + { + case 0x08: // VSAWH + { + for (int i = 0; i < 8; i++) + { + m_v[VDREG].w[i] = m_accum[i].w[SLICE_H]; + } + break; + } + case 0x09: // VSAWM + { + for (int i = 0; i < 8; i++) + { + m_v[VDREG].w[i] = m_accum[i].w[SLICE_M]; + } + break; + } + case 0x0a: // VSAWL + { + for (int i = 0; i < 8; i++) + { + m_v[VDREG].w[i] = m_accum[i].w[SLICE_L]; + } + break; + } + default: + printf("RSP: VSAW: el = %d\n", EL); + break; + } + break; + } + + case 0x20: /* VLT */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100000 | + // ------------------------------------------------------ + // + // Sets compare flags if elements in VS1 are less than VS2 + // Moves the element in VS2 to destination vector + + m_vcompare = 0; + m_vclip2 = 0; + + for (int i = 0; i < 8; i++) + { + int16_t s1 = m_v[VS1REG].s[i]; + int16_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)]; + if (s1 < s2) + { + m_vcompare |= 1 << i; + } + else if (s1 == s2) + { + if (BIT(m_vzero & m_vcarry, i)) + { + m_vcompare |= 1 << i; + } + } + + if (BIT(m_vcompare, i)) + { + vres[i] = s1; + } + else + { + vres[i] = s2; + } + + m_accum[i].w[SLICE_L] = vres[i]; + } + + m_vzero = 0; + m_vcarry = 0; + WRITEBACK_RESULT(); + break; + } + + case 0x21: /* VEQ */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100001 | + // ------------------------------------------------------ + // + // Sets compare flags if elements in VS1 are equal with VS2 + // Moves the element in VS2 to destination vector + + m_vcompare = 0; + m_vclip2 = 0; + + for (int i = 0; i < 8; i++) + { + int16_t s1 = m_v[VS1REG].s[i]; + int16_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)]; + + if ((s1 == s2) && !BIT(m_vzero, i)) + { + m_vcompare |= 1 << i; + vres[i] = s1; + } + else + { + vres[i] = s2; + } + m_accum[i].w[SLICE_L] = vres[i]; + } + + m_vzero = 0; + m_vcarry = 0; + WRITEBACK_RESULT(); + break; + } + + case 0x22: /* VNE */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100010 | + // ------------------------------------------------------ + // + // Sets compare flags if elements in VS1 are not equal with VS2 + // Moves the element in VS2 to destination vector + + m_vcompare = 0; + m_vclip2 = 0; + + for (int i = 0; i < 8; i++) + { + int16_t s1 = m_v[VS1REG].s[i]; + int16_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)]; + + if (s1 != s2 || BIT(m_vzero, i)) + { + m_vcompare |= 1 << i; + vres[i] = s1; + } + else + { + vres[i] = s2; + } + + m_accum[i].w[SLICE_L] = vres[i]; + } + + m_vzero = 0; + m_vcarry = 0; + WRITEBACK_RESULT(); + break; + } + + case 0x23: /* VGE */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100011 | + // ------------------------------------------------------ + // + // Sets compare flags if elements in VS1 are greater or equal with VS2 + // Moves the element in VS2 to destination vector + + m_vcompare = 0; + m_vclip2 = 0; + + for (int i = 0; i < 8; i++) + { + int16_t s1 = m_v[VS1REG].s[i]; + int16_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)]; + + if ((s1 == s2 && (!BIT(m_vzero, i) || !BIT(m_vcarry, i))) || s1 > s2) + { + m_vcompare |= 1 << i; + vres[i] = s1; + } + else + { + vres[i] = s2; + } + + m_accum[i].w[SLICE_L] = vres[i]; + } + + m_vzero = 0; + m_vcarry = 0; + WRITEBACK_RESULT(); + break; + } + + case 0x24: /* VCL */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100100 | + // ------------------------------------------------------ + // + // Vector clip low + + for (int i = 0; i < 8; i++) + { + int16_t s1 = m_v[VS1REG].s[i]; + int16_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)]; + + if (BIT(m_vcarry, i)) // vco_lo + { + if (BIT(m_vzero, i)) // vco_hi + { + if (BIT(m_vcompare, i)) // vcc_lo + { + m_accum[i].w[SLICE_L] = -(uint16_t)s2; + } + else + { + m_accum[i].w[SLICE_L] = s1; + } + } + else + { + if (BIT(m_vclip1, i)) // vce + { + if (((uint32_t)(uint16_t)(s1) + (uint32_t)(uint16_t)(s2)) > 0x10000) + { + m_accum[i].w[SLICE_L] = s1; + m_vcompare &= ~(1 << i); + } + else + { + m_accum[i].w[SLICE_L] = -(uint16_t)s2; + m_vcompare |= 1 << i; + } + } + else + { + if (((uint32_t)(uint16_t)(s1) + (uint32_t)(uint16_t)(s2)) != 0) + { + m_accum[i].w[SLICE_L] = s1; + m_vcompare &= ~(1 << i); + } + else + { + m_accum[i].w[SLICE_L] = -(uint16_t)s2; + m_vcompare |= 1 << i; + } + } + } + } + else + { + if (BIT(m_vzero, i)) // vco_hi + { + if (BIT(m_vclip2, i)) // vcc_hi + { + m_accum[i].w[SLICE_L] = s2; + } + else + { + m_accum[i].w[SLICE_L] = s1; + } + } + else + { + if (((int32_t)(uint16_t)s1 - (int32_t)(uint16_t)s2) >= 0) + { + m_accum[i].w[SLICE_L] = s2; + m_vclip2 |= 1 << i; + } + else + { + m_accum[i].w[SLICE_L] = s1; + m_vclip2 &= ~(1 << i); + } + } + } + + vres[i] = m_accum[i].w[SLICE_L]; + } + + m_vzero = 0; + m_vcarry = 0; + m_vclip1 = 0; + WRITEBACK_RESULT(); + break; + } + + case 0x25: /* VCH */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100101 | + // ------------------------------------------------------ + // + // Vector clip high + + m_vcarry = 0; + m_vcompare = 0; + m_vclip1 = 0; + m_vzero = 0; + m_vclip2 = 0; + uint32_t vce; + + for (int i = 0; i < 8; i++) + { + int16_t s1 = m_v[VS1REG].s[i]; + int16_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)]; + + if ((s1 ^ s2) < 0) + { + vce = (s1 + s2 == -1); + m_vcarry |= 1 << i; + if (s2 < 0) + { + m_vclip2 |= 1 << i; + } + + if (s1 + s2 <= 0) + { + m_vcompare |= 1 << i; + vres[i] = -((uint16_t)s2); + } + else + { + vres[i] = s1; + } + + if (s1 + s2 != 0) + { + if (s1 != ~s2) + { + m_vzero |= 1 << i; + } + } + } + else + { + vce = 0; + if (s2 < 0) + { + m_vcompare |= 1 << i; + } + if (s1 - s2 >= 0) + { + m_vclip2 |= 1 << i; + vres[i] = s2; + } + else + { + vres[i] = s1; + } + + if ((s1 - s2) != 0) + { + if (s1 != ~s2) + { + m_vzero |= 1 << i; + } + } + } + + if (vce != 0) + { + m_vclip1 |= 1 << i; + } + + m_accum[i].w[SLICE_L] = vres[i]; + } + WRITEBACK_RESULT(); + break; + } + + case 0x26: /* VCR */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100110 | + // ------------------------------------------------------ + // + // Vector clip reverse + + m_vcarry = 0; + m_vcompare = 0; + m_vclip1 = 0; + m_vzero = 0; + m_vclip2 = 0; + + for (int i = 0; i < 8; i++) + { + int16_t s1 = m_v[VS1REG].s[i]; + int16_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)]; + + if ((int16_t)(s1 ^ s2) < 0) + { + if (s2 < 0) + { + m_vclip2 |= 1 << i; + } + if ((s1 + s2) <= 0) + { + m_accum[i].w[SLICE_L] = ~(uint16_t)s2; + m_vcompare |= 1 << i; + } + else + { + m_accum[i].w[SLICE_L] = s1; + } + } + else + { + if (s2 < 0) + { + m_vcompare |= 1 << i; + } + if ((s1 - s2) >= 0) + { + m_accum[i].w[SLICE_L] = s2; + m_vclip2 |= 1 << i; + } + else + { + m_accum[i].w[SLICE_L] = s1; + } + } + + vres[i] = m_accum[i].w[SLICE_L]; + } + WRITEBACK_RESULT(); + break; + } + + case 0x27: /* VMRG */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100111 | + // ------------------------------------------------------ + // + // Merges two vectors according to compare flags + + for (int i = 0; i < 8; i++) + { + if (BIT(m_vcompare, i)) + { + vres[i] = m_v[VS1REG].s[i]; + } + else + { + vres[i] = m_v[VS2REG].s[VEC_EL_2(EL, i)]; + } + + m_accum[i].w[SLICE_L] = vres[i]; + } + WRITEBACK_RESULT(); + break; + } + + case 0x28: /* VAND */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101000 | + // ------------------------------------------------------ + // + // Bitwise AND of two vector registers + + for (int i = 0; i < 8; i++) + { + vres[i] = m_v[VS1REG].w[i] & m_v[VS2REG].w[VEC_EL_2(EL, i)]; + m_accum[i].w[SLICE_L] = vres[i]; + } + WRITEBACK_RESULT(); + break; + } + + case 0x29: /* VNAND */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101001 | + // ------------------------------------------------------ + // + // Bitwise NOT AND of two vector registers + + for (int i = 0; i < 8; i++) + { + vres[i] = ~(m_v[VS1REG].w[i] & m_v[VS2REG].w[VEC_EL_2(EL, i)]); + m_accum[i].w[SLICE_L] = vres[i]; + } + WRITEBACK_RESULT(); + break; + } + + case 0x2a: /* VOR */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101010 | + // ------------------------------------------------------ + // + // Bitwise OR of two vector registers + + for (int i = 0; i < 8; i++) + { + vres[i] = m_v[VS1REG].w[i] | m_v[VS2REG].w[VEC_EL_2(EL, i)]; + m_accum[i].w[SLICE_L] = vres[i]; + } + WRITEBACK_RESULT(); + break; + } + + case 0x2b: /* VNOR */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101011 | + // ------------------------------------------------------ + // + // Bitwise NOT OR of two vector registers + + for (int i = 0; i < 8; i++) + { + vres[i] = ~(m_v[VS1REG].w[i] | m_v[VS2REG].w[VEC_EL_2(EL, i)]); + m_accum[i].w[SLICE_L] = vres[i]; + } + WRITEBACK_RESULT(); + break; + } + + case 0x2c: /* VXOR */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101100 | + // ------------------------------------------------------ + // + // Bitwise XOR of two vector registers + + for (int i = 0; i < 8; i++) + { + vres[i] = m_v[VS1REG].w[i] ^ m_v[VS2REG].w[VEC_EL_2(EL, i)]; + m_accum[i].w[SLICE_L] = vres[i]; + } + WRITEBACK_RESULT(); + break; + } + + case 0x2d: /* VNXOR */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101101 | + // ------------------------------------------------------ + // + // Bitwise NOT XOR of two vector registers + + for (int i = 0; i < 8; i++) + { + vres[i] = ~(m_v[VS1REG].w[i] ^ m_v[VS2REG].w[VEC_EL_2(EL, i)]); + m_accum[i].w[SLICE_L] = vres[i]; + } + WRITEBACK_RESULT(); + break; + } + + case 0x2e: /* V056 (Reserved) */ + case 0x2f: /* V057 (Reserved) */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101101 | + // ------------------------------------------------------ + // + // Reserved Opcode + // Appears to simply store the unsigned 16-bit sum of vector elements into low accumulator slice. + // Zeroes destination vector. + + for (int i = 0; i < 8; i++) + { + vres[i] = 0; + uint16_t e1 = m_v[VS1REG].w[i]; + uint16_t e2 = m_v[VS2REG].w[VEC_EL_2(EL, i)]; + m_accum[i].w[SLICE_L] = e1 + e2; + } + WRITEBACK_RESULT(); + break; + } + + case 0x30: /* VRCP */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110000 | + // ------------------------------------------------------ + // + // Calculates reciprocal + + int32_t shifter = 0; + + int32_t rec = m_v[VS2REG].s[EL & 7]; + int32_t datainput = (rec < 0) ? (-rec) : rec; + if (datainput) + { + for (int i = 0; i < 32; i++) + { + if (datainput & (1 << ((~i) & 0x1f))) + { + shifter = i; + break; + } + } + } + else + { + shifter = 0x10; + } + + int32_t address = ((datainput << shifter) & 0x7fc00000) >> 22; + int32_t fetchval = rsp_divtable[address]; + int32_t temp = (0x40000000 | (fetchval << 14)) >> ((~shifter) & 0x1f); + if (rec < 0) + { + temp = ~temp; + } + if (!rec) + { + temp = 0x7fffffff; + } + else if (rec == 0xffff8000) + { + temp = 0xffff0000; + } + rec = temp; + + m_reciprocal_res = rec; + m_dp_allowed = 0; + + m_v[VDREG].w[VS1REG & 7] = (uint16_t)(rec & 0xffff); + + for (int i = 0; i < 8; i++) + { + m_accum[i].w[SLICE_L] = m_v[VS2REG].w[VEC_EL_2(EL, i)]; + } + break; + } + + case 0x31: /* VRCPL */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110001 | + // ------------------------------------------------------ + // + // Calculates reciprocal low part + + int32_t shifter = 0; + + int32_t rec = m_v[VS2REG].s[EL & 7]; + int32_t datainput = rec; + + if (m_dp_allowed) + { + rec = (rec & 0x0000ffff) | m_reciprocal_high; + datainput = rec; + + if (rec < 0) + { + if (rec < -32768) + { + datainput = ~datainput; + } + else + { + datainput = -datainput; + } + } + } + else if (datainput < 0) + { + datainput = -datainput; + + shifter = 0x10; + } + + + for (int i = 0; i < 32; i++) + { + if (datainput & (1 << ((~i) & 0x1f))) + { + shifter = i; + break; + } + } + + int32_t address = ((datainput << shifter) & 0x7fc00000) >> 22; + int32_t fetchval = rsp_divtable[address]; + int32_t temp = (0x40000000 | (fetchval << 14)) >> ((~shifter) & 0x1f); + temp ^= rec >> 31; + + if (!rec) + { + temp = 0x7fffffff; + } + else if (rec == 0xffff8000) + { + temp = 0xffff0000; + } + rec = temp; + + m_reciprocal_res = rec; + m_dp_allowed = 0; + + m_v[VDREG].w[VS1REG & 7] = (uint16_t)(rec & 0xffff); + + for (int i = 0; i < 8; i++) + { + m_accum[i].w[SLICE_L] = m_v[VS2REG].w[VEC_EL_2(EL, i)]; + } + break; + } + + case 0x32: /* VRCPH */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110010 | + // ------------------------------------------------------ + // + // Calculates reciprocal high part + + m_reciprocal_high = m_v[VS2REG].w[EL & 7] << 16; + m_dp_allowed = 1; + + for (int i = 0; i < 8; i++) + { + m_accum[i].w[SLICE_L] = m_v[VS2REG].w[VEC_EL_2(EL, i)]; + } + + m_v[VDREG].s[VS1REG & 7] = (int16_t)(m_reciprocal_res >> 16); + break; + } + + case 0x33: /* VMOV */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110011 | + // ------------------------------------------------------ + // + // Moves element from vector to destination vector + + m_v[VDREG].w[VS1REG & 7] = m_v[VS2REG].w[VEC_EL_2(EL, VS1REG & 7)]; + for (int i = 0; i < 8; i++) + { + m_accum[i].w[SLICE_L] = m_v[VS2REG].w[i]; + } + break; + } + + case 0x34: /* VRSQ */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110100 | + // ------------------------------------------------------ + // + // Calculates reciprocal square-root + + int32_t shifter = 0; + + int32_t rec = m_v[VS2REG].s[EL & 7]; + int32_t datainput = (rec < 0) ? (-rec) : rec; + if (datainput) + { + for (int i = 0; i < 32; i++) + { + if (datainput & (1 << (~i & 0x1f))) + { + shifter = i; + break; + } + } + } + else + { + shifter = 0x10; + } + + int32_t address = ((datainput << shifter) & 0x7fc00000) >> 22; + address = ((address | 0x200) & 0x3fe) | (shifter & 1); + + int32_t fetchval = rsp_divtable[address]; + int32_t temp = (0x40000000 | (fetchval << 14)) >> (((~shifter) & 0x1f) >> 1); + if (rec < 0) + { + temp = ~temp; + } + if (!rec) + { + temp = 0x7fffffff; + } + else if (rec == 0xffff8000) + { + temp = 0xffff0000; + } + rec = temp; + + m_reciprocal_res = rec; + m_dp_allowed = 0; + + m_v[VDREG].w[VS1REG & 7] = (uint16_t)(rec & 0xffff); + + for (int i = 0; i < 8; i++) + { + m_accum[i].w[SLICE_L] = m_v[VS2REG].w[VEC_EL_2(EL, i)]; + } + + break; + } + + case 0x35: /* VRSQL */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110101 | + // ------------------------------------------------------ + // + // Calculates reciprocal square-root low part + + int32_t shifter = 0; + int32_t rec = m_v[VS2REG].s[EL & 7]; + int32_t datainput = rec; + + if (m_dp_allowed) + { + rec = (rec & 0x0000ffff) | m_reciprocal_high; + datainput = rec; + + if (rec < 0) + { + if (rec < -32768) + { + datainput = ~datainput; + } + else + { + datainput = -datainput; + } + } + } + else if (datainput < 0) + { + datainput = -datainput; + + shifter = 0x10; + } + + if (datainput) + { + for (int i = 0; i < 32; i++) + { + if (datainput & (1 << ((~i) & 0x1f))) + { + shifter = i; + break; + } + } + } + + int32_t address = ((datainput << shifter) & 0x7fc00000) >> 22; + address = ((address | 0x200) & 0x3fe) | (shifter & 1); + + int32_t fetchval = rsp_divtable[address]; + int32_t temp = (0x40000000 | (fetchval << 14)) >> (((~shifter) & 0x1f) >> 1); + temp ^= rec >> 31; + + if (!rec) + { + temp = 0x7fffffff; + } + else if (rec == 0xffff8000) + { + temp = 0xffff0000; + } + rec = temp; + + m_reciprocal_res = rec; + m_dp_allowed = 0; + + m_v[VDREG].w[VS1REG & 7] = (uint16_t)(rec & 0xffff); + + for (int i = 0; i < 8; i++) + { + m_accum[i].w[SLICE_L] = m_v[VS2REG].w[VEC_EL_2(EL, i)]; + } + + break; + } + + case 0x36: /* VRSQH */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110110 | + // ------------------------------------------------------ + // + // Calculates reciprocal square-root high part + + m_reciprocal_high = m_v[VS2REG].w[EL & 7] << 16; + m_dp_allowed = 1; + + for (int i = 0; i < 8; i++) + { + m_accum[i].w[SLICE_L] = m_v[VS2REG].w[VEC_EL_2(EL, i)]; + } + + m_v[VDREG].s[VS1REG & 7] = (int16_t)(m_reciprocal_res >> 16); // store high part + break; + } + + case 0x37: /* VNOP */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110111 | + // ------------------------------------------------------ + // + // Vector null instruction + + break; + } + + case 0x3b: /* V073 (Reserved) */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101101 | + // ------------------------------------------------------ + // + // Reserved Opcode + // Appears to simply store the unsigned 16-bit sum of vector elements into low accumulator slice. + // Zeroes destination vector. + + for (int i = 0; i < 8; i++) + { + vres[i] = 0; + uint16_t e1 = m_v[VS1REG].w[i]; + uint16_t e2 = m_v[VS2REG].w[VEC_EL_2(EL, i)]; + m_accum[i].w[SLICE_L] = e1 + e2; + } + WRITEBACK_RESULT(); + break; + } + + case 0x3f: /* VNULL (Reserved) */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101101 | + // ------------------------------------------------------ + // + // Reserved Opcode + // Appears to simply store the unsigned 16-bit sum of vector elements into low accumulator slice. + // Zeroes destination vector. + + for (int i = 0; i < 8; i++) + { + vres[i] = m_v[VS1REG].w[i]; + m_accum[i].w[SLICE_L] = 0; + } + WRITEBACK_RESULT(); + break; + } + + default: unimplemented_opcode(op); break; + } +} + +void rsp_device::handle_cop2(uint32_t op) +{ + switch ((op >> 21) & 0x1f) + { + case 0x00: /* MFC2 */ + { + // 31 25 20 15 10 6 0 + // --------------------------------------------------- + // | 010010 | 00000 | TTTTT | DDDDD | IIII | 0000000 | + // --------------------------------------------------- + + int el = (op >> 7) & 0xf; + uint16_t b1 = VREG_B(RDREG, (el+0) & 0xf); + uint16_t b2 = VREG_B(RDREG, (el+1) & 0xf); + if (RTREG) m_r[RTREG] = (int32_t)(int16_t)((b1 << 8) | (b2)); + break; + } + + case 0x02: /* CFC2 */ + { + // 31 25 20 15 10 0 + // ------------------------------------------------ + // | 010010 | 00010 | TTTTT | DDDDD | 00000000000 | + // ------------------------------------------------ + + if (RTREG) + { + switch (RDREG) + { + case 0: + m_r[RTREG] = (m_vzero << 8) | m_vcarry; + if (m_r[RTREG] & 0x8000) m_r[RTREG] |= 0xffff0000; + break; + case 1: + m_r[RTREG] = (m_vclip2 << 8) | m_vcompare; + if (m_r[RTREG] & 0x8000) m_r[RTREG] |= 0xffff0000; + break; + case 2: + // Anciliary clipping flags + m_r[RTREG] = m_vclip1; + break; + } + } + break; + } + + case 0x04: /* MTC2 */ + { + // 31 25 20 15 10 6 0 + // --------------------------------------------------- + // | 010010 | 00100 | TTTTT | DDDDD | IIII | 0000000 | + // --------------------------------------------------- + + int el = (op >> 7) & 0xf; + W_VREG_B(RDREG, (el+0) & 0xf, (m_r[RTREG] >> 8) & 0xff); + W_VREG_B(RDREG, (el+1) & 0xf, (m_r[RTREG] >> 0) & 0xff); + break; + } + + case 0x06: /* CTC2 */ + { + // 31 25 20 15 10 0 + // ------------------------------------------------ + // | 010010 | 00110 | TTTTT | DDDDD | 00000000000 | + // ------------------------------------------------ + + switch (RDREG) + { + case 0: + m_vcarry = (uint8_t)m_r[RTREG]; + m_vzero = (uint8_t)(m_r[RTREG] >> 8); + break; + + case 1: + m_vcompare = (uint8_t)m_r[RTREG]; + m_vclip2 = (uint8_t)(m_r[RTREG] >> 8); + break; + + case 2: + m_vclip1 = (uint8_t)m_r[RTREG]; + break; + } + break; + } + + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + handle_vector_ops(op); + break; + + default: + unimplemented_opcode(op); + break; + } +} + +void rsp_device::handle_lwc2(uint32_t op) +{ + int base = (op >> 21) & 0x1f; + int dest = (op >> 16) & 0x1f; + int index = (op >> 7) & 0xf; + int offset = (op & 0x7f); + offset = (offset << 25) >> 25; + + switch ((op >> 11) & 0x1f) + { + case 0x00: /* LBV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 110010 | BBBBB | TTTTT | 00000 | IIII | Offset | + // -------------------------------------------------- + // + // Load 1 byte to vector byte index + + uint32_t ea = (base) ? m_r[base] + offset : offset; + VREG_B(dest, index) = read_dmem_byte(ea); + break; + } + + case 0x01: /* LSV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 110010 | BBBBB | TTTTT | 00001 | IIII | Offset | + // -------------------------------------------------- + // + // Loads 2 bytes starting from vector byte index + + uint32_t ea = (base) ? m_r[base] + (offset * 2) : (offset * 2); + + for (int i = index; i < index + 2; i++) + { + VREG_B(dest, i) = read_dmem_byte(ea); + ea++; + } + break; + } + + case 0x02: /* LLV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 110010 | BBBBB | TTTTT | 00010 | IIII | Offset | + // -------------------------------------------------- + // + // Loads 4 bytes starting from vector byte index + + uint32_t ea = (base) ? m_r[base] + (offset * 4) : (offset * 4); + + for (int i = index; i < index + 4; i++) + { + VREG_B(dest, i) = read_dmem_byte(ea); + ea++; + } + break; + } + + case 0x03: /* LDV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 110010 | BBBBB | TTTTT | 00011 | IIII | Offset | + // -------------------------------------------------- + // + // Loads 8 bytes starting from vector byte index + + uint32_t ea = (base) ? m_r[base] + (offset * 8) : (offset * 8); + + for (int i = index; i < index + 8; i++) + { + VREG_B(dest, i) = read_dmem_byte(ea); + ea++; + } + break; + } + + case 0x04: /* LQV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 110010 | BBBBB | TTTTT | 00100 | IIII | Offset | + // -------------------------------------------------- + // + // Loads up to 16 bytes starting from vector byte index + + uint32_t ea = (base) ? m_r[base] + (offset * 16) : (offset * 16); + + int end = index + (16 - (ea & 0xf)); + if (end > 16) end = 16; + + for (int i = index; i < end; i++) + { + VREG_B(dest, i) = read_dmem_byte(ea); + ea++; + } + break; + } + + case 0x05: /* LRV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 110010 | BBBBB | TTTTT | 00101 | IIII | Offset | + // -------------------------------------------------- + // + // Stores up to 16 bytes starting from right side until 16-byte boundary + + uint32_t ea = (base) ? m_r[base] + (offset * 16) : (offset * 16); + + index = 16 - ((ea & 0xf) - index); + ea &= ~0xf; + + for (int i = index; i < 16; i++) + { + VREG_B(dest, i) = read_dmem_byte(ea); + ea++; + } + break; + } + + case 0x06: /* LPV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 110010 | BBBBB | TTTTT | 00110 | IIII | Offset | + // -------------------------------------------------- + // + // Loads a byte as the upper 8 bits of each element + + uint32_t ea = (base) ? m_r[base] + (offset * 8) : (offset * 8); + + for (int i = 0; i < 8; i++) + { + m_v[dest].w[i] = read_dmem_byte(ea + (((16-index) + i) & 0xf)) << 8; + } + break; + } + + case 0x07: /* LUV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 110010 | BBBBB | TTTTT | 00111 | IIII | Offset | + // -------------------------------------------------- + // + // Loads a byte as the bits 14-7 of each element + + uint32_t ea = (base) ? m_r[base] + (offset * 8) : (offset * 8); + + for (int i = 0; i < 8; i++) + { + m_v[dest].w[i] = read_dmem_byte(ea + (((16-index) + i) & 0xf)) << 7; + } + break; + } + + case 0x08: /* LHV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 110010 | BBBBB | TTTTT | 01000 | IIII | Offset | + // -------------------------------------------------- + // + // Loads a byte as the bits 14-7 of each element, with 2-byte stride + + uint32_t ea = (base) ? m_r[base] + (offset * 16) : (offset * 16); + + for (int i = 0; i < 8; i++) + { + m_v[dest].w[i] = read_dmem_byte(ea + (((16-index) + (i<<1)) & 0xf)) << 7; + } + break; + } + + case 0x09: /* LFV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 110010 | BBBBB | TTTTT | 01001 | IIII | Offset | + // -------------------------------------------------- + // + // Loads a byte as the bits 14-7 of upper or lower quad, with 4-byte stride + + uint32_t ea = (base) ? m_r[base] + (offset * 16) : (offset * 16); + + // NOTE: Not sure what happens if 16-byte boundary is crossed + + int end = (index >> 1) + 4; + + for (int i = index >> 1; i < end; i++) + { + m_v[dest].w[i] = read_dmem_byte(ea) << 7; + ea += 4; + } + break; + } + + case 0x0a: /* LWV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 110010 | BBBBB | TTTTT | 01010 | IIII | Offset | + // -------------------------------------------------- + // + // Intended instruction behavior: + // Loads the full 128-bit vector starting from vector byte index and wrapping to index 0 + // after byte index 15 + // + // Actual instruction behavior: + // Loads the full 128-bit vector starting from vector byte index 0. + // + // Hardware testing has proven that the vector index is ignored when executing LWV. + // By contrast, SWV will function as intended when provided an index. + + uint32_t ea = (base) ? m_r[base] + (offset * 16) : (offset * 16); + + for (int i = 0; i < 16; i++) + { + VREG_B(dest, i) = read_dmem_byte(ea); + ea++; + } + break; + } + + case 0x0b: /* LTV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 110010 | BBBBB | TTTTT | 01011 | IIII | Offset | + // -------------------------------------------------- + // + // Loads one element to maximum of 8 vectors, while incrementing element index + + // FIXME: has a small problem with odd indices + + int32_t vs = (op >> 16) & 0x1f; + int32_t ve = vs + 8; + if (ve > 32) + ve = 32; + + if (index & 1) fatalerror("RSP: LTV: index = %d\n", index); + + uint32_t ea = (base) ? m_r[base] + (offset * 16) : (offset * 16); + ea = ((ea + 8) & ~0xf) + (index & 1); + + for (int32_t i = vs; i < ve; i++) + { + int32_t element = ((8 - (index >> 1) + (i-vs)) << 1); + VREG_B(i, (element & 0xf)) = read_dmem_byte(ea); + VREG_B(i, ((element + 1) & 0xf)) = read_dmem_byte(ea + 1); + + ea += 2; + } + break; + } + + default: + { + unimplemented_opcode(op); + break; + } } +} + + +/*************************************************************************** + Vector Store Instructions +***************************************************************************/ + +void rsp_device::handle_swc2(uint32_t op) +{ + int base = (op >> 21) & 0x1f; + int dest = (op >> 16) & 0x1f; + int index = (op >> 7) & 0xf; + int offset = (op & 0x7f); + offset = (offset << 25) >> 25; - while (m_rsp_state->icount > 0) + switch ((op >> 11) & 0x1f) { - m_ppc = m_rsp_state->pc; - debugger_instruction_hook(m_rsp_state->pc); + case 0x00: /* SBV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 111010 | BBBBB | TTTTT | 00000 | IIII | Offset | + // -------------------------------------------------- + // + // Stores 1 byte from vector byte index + + uint32_t ea = (base) ? m_r[base] + offset : offset; + write_dmem_byte(ea, VREG_B(dest, index)); + break; + } + + case 0x01: /* SSV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 111010 | BBBBB | TTTTT | 00001 | IIII | Offset | + // -------------------------------------------------- + // + // Stores 2 bytes starting from vector byte index + + uint32_t ea = (base) ? m_r[base] + (offset * 2) : (offset * 2); + + for (int i = index; i < index + 2; i++) + { + write_dmem_byte(ea, VREG_B(dest, i)); + ea++; + } + break; + } + + case 0x02: /* SLV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 111010 | BBBBB | TTTTT | 00010 | IIII | Offset | + // -------------------------------------------------- + // + // Stores 4 bytes starting from vector byte index + + uint32_t ea = (base) ? m_r[base] + (offset * 4) : (offset * 4); + + for (int i = index; i < index + 4; i++) + { + write_dmem_byte(ea, VREG_B(dest, i)); + ea++; + } + break; + } - uint32_t op = ROPCODE(m_rsp_state->pc); - if (m_nextpc != ~0) + case 0x03: /* SDV */ { - m_rsp_state->pc = m_nextpc; - m_nextpc = ~0; + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 111010 | BBBBB | TTTTT | 00011 | IIII | Offset | + // -------------------------------------------------- + // + // Stores 8 bytes starting from vector byte index + + uint32_t ea = (base) ? m_r[base] + (offset * 8) : (offset * 8); + + for (int i = index; i < index + 8; i++) + { + write_dmem_byte(ea, VREG_B(dest, i)); + ea++; + } + break; + } + + case 0x04: /* SQV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 111010 | BBBBB | TTTTT | 00100 | IIII | Offset | + // -------------------------------------------------- + // + // Stores up to 16 bytes starting from vector byte index until 16-byte boundary + + uint32_t ea = (base) ? m_r[base] + (offset * 16) : (offset * 16); + int end = index + (16 - (ea & 0xf)); + + for (int i = index; i < end; i++) + { + write_dmem_byte(ea, VREG_B(dest, i & 0xf)); + ea++; + } + break; + } + + case 0x05: /* SRV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 111010 | BBBBB | TTTTT | 00101 | IIII | Offset | + // -------------------------------------------------- + // + // Stores up to 16 bytes starting from right side until 16-byte boundary + + uint32_t ea = (base) ? m_r[base] + (offset * 16) : (offset * 16); + + int end = index + (ea & 0xf); + int o = (16 - (ea & 0xf)) & 0xf; + ea &= ~0xf; + + for (int i = index; i < end; i++) + { + write_dmem_byte(ea, VREG_B(dest, ((i + o) & 0xf))); + ea++; + } + break; + } + + case 0x06: /* SPV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 111010 | BBBBB | TTTTT | 00110 | IIII | Offset | + // -------------------------------------------------- + // + // Stores upper 8 bits of each element + + uint32_t ea = (base) ? m_r[base] + (offset * 8) : (offset * 8); + + for (int i = index; i < index + 8; i++) + { + if ((i & 0xf) < 8) + { + write_dmem_byte(ea, VREG_B(dest, ((i & 0xf) << 1))); + } + else + { + write_dmem_byte(ea, m_v[dest].s[i & 0x7] >> 7); + } + ea++; + } + break; + } + + case 0x07: /* SUV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 111010 | BBBBB | TTTTT | 00111 | IIII | Offset | + // -------------------------------------------------- + // + // Stores bits 14-7 of each element + + uint32_t ea = (base) ? m_r[base] + (offset * 8) : (offset * 8); + + for (int i = index; i < index + 8; i++) + { + if ((i & 0xf) < 8) + { + write_dmem_byte(ea, m_v[dest].s[i & 0x7] >> 7); + } + else + { + write_dmem_byte(ea, VREG_B(dest, ((i & 0x7) << 1))); + } + ea++; + } + break; + } + + case 0x08: /* SHV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 111010 | BBBBB | TTTTT | 01000 | IIII | Offset | + // -------------------------------------------------- + // + // Stores bits 14-7 of each element, with 2-byte stride + + uint32_t ea = (base) ? m_r[base] + (offset * 16) : (offset * 16); + + for (int i = 0; i < 8; i++) + { + uint8_t d = ((VREG_B(dest, ((index + (i << 1) + 0) & 0xf))) << 1) | + ((VREG_B(dest, ((index + (i << 1) + 1) & 0xf))) >> 7); + + write_dmem_byte(ea, d); + ea += 2; + } + break; + } + + case 0x09: /* SFV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 111010 | BBBBB | TTTTT | 01001 | IIII | Offset | + // -------------------------------------------------- + // + // Stores bits 14-7 of upper or lower quad, with 4-byte stride + + // FIXME: only works for index 0 and index 8 + + uint32_t ea = (base) ? m_r[base] + (offset * 16) : (offset * 16); + + int eaoffset = ea & 0xf; + ea &= ~0xf; + + int end = (index >> 1) + 4; + + for (int i = index >> 1; i < end; i++) + { + write_dmem_byte(ea + (eaoffset & 0xf), m_v[dest].s[i] >> 7); + eaoffset += 4; + } + break; + } + + case 0x0a: /* SWV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 111010 | BBBBB | TTTTT | 01010 | IIII | Offset | + // -------------------------------------------------- + // + // Stores the full 128-bit vector starting from vector byte index and wrapping to index 0 + // after byte index 15 + + uint32_t ea = (base) ? m_r[base] + (offset * 16) : (offset * 16); + + int eaoffset = ea & 0xf; + ea &= ~0xf; + + for (int i = index; i < index + 16; i++) + { + write_dmem_byte(ea + (eaoffset & 0xf), VREG_B(dest, i & 0xf)); + eaoffset++; + } + break; + } + + case 0x0b: /* STV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 111010 | BBBBB | TTTTT | 01011 | IIII | Offset | + // -------------------------------------------------- + // + // Stores one element from maximum of 8 vectors, while incrementing element index + + int32_t vs = (op >> 16) & 0x1f; + int32_t ve = vs + 8; + if (ve > 32) + ve = 32; + + int32_t element = 8 - (index >> 1); + + uint32_t ea = (base) ? m_r[base] + (offset * 16) : (offset * 16); + + int32_t eaoffset = (ea & 0xf) + (element * 2); + ea &= ~0xf; + + for (int32_t i = vs; i < ve; i++) + { + write_dmem_word(ea + (eaoffset & 0xf), m_v[i].w[element & 0x7]); + eaoffset += 2; + element++; + } + break; + } + + default: + unimplemented_opcode(op); + break; + } +} + +void rsp_device::update_scalar_op_deduction() +{ + /*if (m_paired_busy) + { + m_scalar_busy = false; + m_vector_busy = false; + m_paired_busy = false; + m_ideduct = 1; + } + else if (m_vector_busy) + { + m_scalar_busy = true; + m_paired_busy = true; + m_ideduct = 0; + } + else if (m_scalar_busy) + { + m_ideduct = 1; + } + else + { + m_scalar_busy = true; + m_ideduct = 0; + }*/ +} + +void rsp_device::update_vector_op_deduction() +{ + /*if (m_paired_busy) + { + m_scalar_busy = false; + m_vector_busy = false; + m_paired_busy = false; + m_ideduct = 1; + } + else if (m_scalar_busy) + { + m_vector_busy = true; + m_paired_busy = true; + m_ideduct = 0; + } + else if (m_vector_busy) + { + m_ideduct = 1; + } + else + { + m_vector_busy = true; + m_ideduct = 0; + }*/ +} + +void rsp_device::execute_run() +{ + if (m_sr & (RSP_STATUS_HALT | RSP_STATUS_BROKE)) + { + m_ideduct = 0; + m_scalar_busy = false; + m_vector_busy = false; + m_paired_busy = false; + m_icount = std::min(m_icount, 0); + } + + while (m_icount > 0) + { + m_ppc = m_pc; + debugger_instruction_hook(m_pc); + + uint32_t op = ROPCODE(m_pc); + if (m_nextpc != 0xffff) + { + m_pc = m_nextpc; + m_nextpc = 0xffff; } else { - m_rsp_state->pc += 4; + m_pc += 4; } switch (op >> 26) { case 0x00: /* SPECIAL */ { + update_scalar_op_deduction(); switch (op & 0x3f) { - case 0x00: /* SLL */ if (RDREG) RDVAL = (uint32_t)RTVAL << SHIFT; break; - case 0x02: /* SRL */ if (RDREG) RDVAL = (uint32_t)RTVAL >> SHIFT; break; - case 0x03: /* SRA */ if (RDREG) RDVAL = (int32_t)RTVAL >> SHIFT; break; - case 0x04: /* SLLV */ if (RDREG) RDVAL = (uint32_t)RTVAL << (RSVAL & 0x1f); break; - case 0x06: /* SRLV */ if (RDREG) RDVAL = (uint32_t)RTVAL >> (RSVAL & 0x1f); break; - case 0x07: /* SRAV */ if (RDREG) RDVAL = (int32_t)RTVAL >> (RSVAL & 0x1f); break; - case 0x08: /* JR */ JUMP_PC(RSVAL); break; - case 0x09: /* JALR */ JUMP_PC_L(RSVAL, RDREG); break; + case 0x00: /* SLL */ if (RDREG) m_r[RDREG] = m_r[RTREG] << SHIFT; break; + case 0x02: /* SRL */ if (RDREG) m_r[RDREG] = m_r[RTREG] >> SHIFT; break; + case 0x03: /* SRA */ if (RDREG) m_r[RDREG] = (int32_t)m_r[RTREG] >> SHIFT; break; + case 0x04: /* SLLV */ if (RDREG) m_r[RDREG] = m_r[RTREG] << (m_r[RSREG] & 0x1f); break; + case 0x06: /* SRLV */ if (RDREG) m_r[RDREG] = m_r[RTREG] >> (m_r[RSREG] & 0x1f); break; + case 0x07: /* SRAV */ if (RDREG) m_r[RDREG] = (int32_t)m_r[RTREG] >> (m_r[RSREG] & 0x1f); break; + case 0x08: /* JR */ JUMP_PC(m_r[RSREG]); break; + case 0x09: /* JALR */ JUMP_PC_L(m_r[RSREG], RDREG); break; case 0x0d: /* BREAK */ { + m_ideduct = 1; + m_scalar_busy = false; + m_vector_busy = false; + m_paired_busy = false; m_sp_set_status_func(0, 0x3, 0xffffffff); - m_rsp_state->icount = std::min(m_rsp_state->icount, 1); + m_icount = std::min(m_icount, 1); break; } - case 0x20: /* ADD */ if (RDREG) RDVAL = (int32_t)(RSVAL + RTVAL); break; - case 0x21: /* ADDU */ if (RDREG) RDVAL = (int32_t)(RSVAL + RTVAL); break; - case 0x22: /* SUB */ if (RDREG) RDVAL = (int32_t)(RSVAL - RTVAL); break; - case 0x23: /* SUBU */ if (RDREG) RDVAL = (int32_t)(RSVAL - RTVAL); break; - case 0x24: /* AND */ if (RDREG) RDVAL = RSVAL & RTVAL; break; - case 0x25: /* OR */ if (RDREG) RDVAL = RSVAL | RTVAL; break; - case 0x26: /* XOR */ if (RDREG) RDVAL = RSVAL ^ RTVAL; break; - case 0x27: /* NOR */ if (RDREG) RDVAL = ~(RSVAL | RTVAL); break; - case 0x2a: /* SLT */ if (RDREG) RDVAL = (int32_t)RSVAL < (int32_t)RTVAL; break; - case 0x2b: /* SLTU */ if (RDREG) RDVAL = (uint32_t)RSVAL < (uint32_t)RTVAL; break; + case 0x20: /* ADD */ if (RDREG) m_r[RDREG] = (int32_t)(m_r[RSREG] + m_r[RTREG]); break; + case 0x21: /* ADDU */ if (RDREG) m_r[RDREG] = (int32_t)(m_r[RSREG] + m_r[RTREG]); break; + case 0x22: /* SUB */ if (RDREG) m_r[RDREG] = (int32_t)(m_r[RSREG] - m_r[RTREG]); break; + case 0x23: /* SUBU */ if (RDREG) m_r[RDREG] = (int32_t)(m_r[RSREG] - m_r[RTREG]); break; + case 0x24: /* AND */ if (RDREG) m_r[RDREG] = m_r[RSREG] & m_r[RTREG]; break; + case 0x25: /* OR */ if (RDREG) m_r[RDREG] = m_r[RSREG] | m_r[RTREG]; break; + case 0x26: /* XOR */ if (RDREG) m_r[RDREG] = m_r[RSREG] ^ m_r[RTREG]; break; + case 0x27: /* NOR */ if (RDREG) m_r[RDREG] = ~(m_r[RSREG] | m_r[RTREG]); break; + case 0x2a: /* SLT */ if (RDREG) m_r[RDREG] = (int32_t)m_r[RSREG] < (int32_t)m_r[RTREG]; break; + case 0x2b: /* SLTU */ if (RDREG) m_r[RDREG] = m_r[RSREG] < m_r[RTREG]; break; default: unimplemented_opcode(op); break; } break; @@ -680,38 +2920,40 @@ void rsp_device::execute_run() case 0x01: /* REGIMM */ { + update_scalar_op_deduction(); switch (RTREG) { - case 0x00: /* BLTZ */ if ((int32_t)(RSVAL) < 0) JUMP_REL(SIMM16); break; - case 0x01: /* BGEZ */ if ((int32_t)(RSVAL) >= 0) JUMP_REL(SIMM16); break; - case 0x10: /* BLTZAL */ if ((int32_t)(RSVAL) < 0) JUMP_REL_L(SIMM16, 31); break; - case 0x11: /* BGEZAL */ if ((int32_t)(RSVAL) >= 0) JUMP_REL_L(SIMM16, 31); break; + case 0x00: /* BLTZ */ if ((int32_t)m_r[RSREG] < 0) JUMP_REL(SIMM16); break; + case 0x01: /* BGEZ */ if ((int32_t)m_r[RSREG] >= 0) JUMP_REL(SIMM16); break; + case 0x10: /* BLTZAL */ if ((int32_t)m_r[RSREG] < 0) JUMP_REL_L(SIMM16, 31); break; + case 0x11: /* BGEZAL */ if ((int32_t)m_r[RSREG] >= 0) JUMP_REL_L(SIMM16, 31); break; default: unimplemented_opcode(op); break; } break; } - case 0x02: /* J */ JUMP_ABS(UIMM26); break; - case 0x03: /* JAL */ JUMP_ABS_L(UIMM26, 31); break; - case 0x04: /* BEQ */ if (RSVAL == RTVAL) JUMP_REL(SIMM16); break; - case 0x05: /* BNE */ if (RSVAL != RTVAL) JUMP_REL(SIMM16); break; - case 0x06: /* BLEZ */ if ((int32_t)RSVAL <= 0) JUMP_REL(SIMM16); break; - case 0x07: /* BGTZ */ if ((int32_t)RSVAL > 0) JUMP_REL(SIMM16); break; - case 0x08: /* ADDI */ if (RTREG) RTVAL = (int32_t)(RSVAL + SIMM16); break; - case 0x09: /* ADDIU */ if (RTREG) RTVAL = (int32_t)(RSVAL + SIMM16); break; - case 0x0a: /* SLTI */ if (RTREG) RTVAL = (int32_t)(RSVAL) < ((int32_t)SIMM16); break; - case 0x0b: /* SLTIU */ if (RTREG) RTVAL = (uint32_t)(RSVAL) < (uint32_t)((int32_t)SIMM16); break; - case 0x0c: /* ANDI */ if (RTREG) RTVAL = RSVAL & UIMM16; break; - case 0x0d: /* ORI */ if (RTREG) RTVAL = RSVAL | UIMM16; break; - case 0x0e: /* XORI */ if (RTREG) RTVAL = RSVAL ^ UIMM16; break; - case 0x0f: /* LUI */ if (RTREG) RTVAL = UIMM16 << 16; break; + case 0x02: /* J */ update_scalar_op_deduction(); JUMP_ABS(UIMM26); break; + case 0x03: /* JAL */ update_scalar_op_deduction(); JUMP_ABS_L(UIMM26, 31); break; + case 0x04: /* BEQ */ update_scalar_op_deduction(); if (m_r[RSREG] == m_r[RTREG]) JUMP_REL(SIMM16); break; + case 0x05: /* BNE */ update_scalar_op_deduction(); if (m_r[RSREG] != m_r[RTREG]) JUMP_REL(SIMM16); break; + case 0x06: /* BLEZ */ update_scalar_op_deduction(); if ((int32_t)m_r[RSREG] <= 0) JUMP_REL(SIMM16); break; + case 0x07: /* BGTZ */ update_scalar_op_deduction(); if ((int32_t)m_r[RSREG] > 0) JUMP_REL(SIMM16); break; + case 0x08: /* ADDI */ update_scalar_op_deduction(); if (RTREG) m_r[RTREG] = (int32_t)m_r[RSREG] + SIMM16; break; + case 0x09: /* ADDIU */ update_scalar_op_deduction(); if (RTREG) m_r[RTREG] = (int32_t)m_r[RSREG] + SIMM16; break; + case 0x0a: /* SLTI */ update_scalar_op_deduction(); if (RTREG) m_r[RTREG] = (int32_t)m_r[RSREG] < (int32_t)SIMM16; break; + case 0x0b: /* SLTIU */ update_scalar_op_deduction(); if (RTREG) m_r[RTREG] = m_r[RSREG] < UIMM16; break; + case 0x0c: /* ANDI */ update_scalar_op_deduction(); if (RTREG) m_r[RTREG] = m_r[RSREG] & UIMM16; break; + case 0x0d: /* ORI */ update_scalar_op_deduction(); if (RTREG) m_r[RTREG] = m_r[RSREG] | UIMM16; break; + case 0x0e: /* XORI */ update_scalar_op_deduction(); if (RTREG) m_r[RTREG] = m_r[RSREG] ^ UIMM16; break; + case 0x0f: /* LUI */ update_scalar_op_deduction(); if (RTREG) m_r[RTREG] = UIMM16 << 16; break; case 0x10: /* COP0 */ { + update_scalar_op_deduction(); switch ((op >> 21) & 0x1f) { - case 0x00: /* MFC0 */ if (RTREG) RTVAL = get_cop0_reg(RDREG); break; - case 0x04: /* MTC0 */ set_cop0_reg(RDREG, RTVAL); break; + case 0x00: /* MFC0 */ if (RTREG) m_r[RTREG] = get_cop0_reg(RDREG); break; + case 0x04: /* MTC0 */ set_cop0_reg(RDREG, m_r[RTREG]); break; default: unimplemented_opcode(op); break; } break; @@ -719,20 +2961,21 @@ void rsp_device::execute_run() case 0x12: /* COP2 */ { - m_cop2->handle_cop2(op); + update_vector_op_deduction(); + handle_cop2(op); break; } - case 0x20: /* LB */ if (RTREG) RTVAL = (int32_t)(int8_t)READ8(RSVAL + SIMM16); break; - case 0x21: /* LH */ if (RTREG) RTVAL = (int32_t)(int16_t)READ16(RSVAL + SIMM16); break; - case 0x23: /* LW */ if (RTREG) RTVAL = READ32(RSVAL + SIMM16); break; - case 0x24: /* LBU */ if (RTREG) RTVAL = (uint8_t)READ8(RSVAL + SIMM16); break; - case 0x25: /* LHU */ if (RTREG) RTVAL = (uint16_t)READ16(RSVAL + SIMM16); break; - case 0x28: /* SB */ WRITE8(RSVAL + SIMM16, RTVAL); break; - case 0x29: /* SH */ WRITE16(RSVAL + SIMM16, RTVAL); break; - case 0x2b: /* SW */ WRITE32(RSVAL + SIMM16, RTVAL); break; - case 0x32: /* LWC2 */ m_cop2->handle_lwc2(op); break; - case 0x3a: /* SWC2 */ m_cop2->handle_swc2(op); break; + case 0x20: /* LB */ update_scalar_op_deduction(); if (RTREG) m_r[RTREG] = (int32_t)(int8_t)read_dmem_byte(m_r[RSREG] + SIMM16); break; + case 0x21: /* LH */ update_scalar_op_deduction(); if (RTREG) m_r[RTREG] = (int32_t)(int16_t)read_dmem_word(m_r[RSREG] + SIMM16); break; + case 0x23: /* LW */ update_scalar_op_deduction(); if (RTREG) m_r[RTREG] = read_dmem_dword(m_r[RSREG] + SIMM16); break; + case 0x24: /* LBU */ update_scalar_op_deduction(); if (RTREG) m_r[RTREG] = read_dmem_byte(m_r[RSREG] + SIMM16); break; + case 0x25: /* LHU */ update_scalar_op_deduction(); if (RTREG) m_r[RTREG] = read_dmem_word(m_r[RSREG] + SIMM16); break; + case 0x28: /* SB */ update_scalar_op_deduction(); write_dmem_byte(m_r[RSREG] + SIMM16, m_r[RTREG]); break; + case 0x29: /* SH */ update_scalar_op_deduction(); write_dmem_word(m_r[RSREG] + SIMM16, m_r[RTREG]); break; + case 0x2b: /* SW */ update_scalar_op_deduction(); write_dmem_dword(m_r[RSREG] + SIMM16, m_r[RTREG]); break; + case 0x32: /* LWC2 */ update_scalar_op_deduction(); handle_lwc2(op); break; + case 0x3a: /* SWC2 */ update_scalar_op_deduction(); handle_swc2(op); break; default: { @@ -743,8 +2986,8 @@ void rsp_device::execute_run() if (LOG_INSTRUCTION_EXECUTION) { - int i, l; static uint32_t prev_regs[32]; + static VECTOR_REG prev_vecs[32]; rsp_disassembler rspd; std::ostringstream string; @@ -752,10 +2995,10 @@ void rsp_device::execute_run() fprintf(m_exec_output, "%08X: %s", m_ppc, string.str().c_str()); - l = string.str().size(); + int l = string.str().size(); if (l < 36) { - for (i=l; i < 36; i++) + for (int i = l; i < 36; i++) { fprintf(m_exec_output, " "); } @@ -763,26 +3006,36 @@ void rsp_device::execute_run() fprintf(m_exec_output, "| "); - for (i=0; i < 32; i++) + for (int i = 0; i < 32; i++) { - if (m_rsp_state->r[i] != prev_regs[i]) + if (m_r[i] != prev_regs[i]) { - fprintf(m_exec_output, "R%d: %08X ", i, m_rsp_state->r[i]); + fprintf(m_exec_output, "R%d: %08X ", i, m_r[i]); } - prev_regs[i] = m_rsp_state->r[i]; + prev_regs[i] = m_r[i]; } - m_cop2->log_instruction_execution(); + for (int i = 0; i < 32; i++) + { + if (m_v[i].d[0] != prev_vecs[i].d[0] || m_v[i].d[1] != prev_vecs[i].d[1]) + { + fprintf(m_exec_output, "V%d: %04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X ", i, + m_v[i].w[0], m_v[i].w[1], m_v[i].w[2], m_v[i].w[3], m_v[i].w[4], m_v[i].w[5], m_v[i].w[6], m_v[i].w[7]); + } + prev_vecs[i].d[0] = m_v[i].d[0]; + prev_vecs[i].d[1] = m_v[i].d[1]; + } fprintf(m_exec_output, "\n"); } - --m_rsp_state->icount; + //m_icount -= m_ideduct; + --m_icount; - if( m_sr & RSP_STATUS_SSTEP ) + if (m_sr & RSP_STATUS_SSTEP) { - if( m_step_count ) + if (m_step_count) { m_step_count--; } @@ -792,14 +3045,13 @@ void rsp_device::execute_run() } } - if( m_sr & ( RSP_STATUS_HALT | RSP_STATUS_BROKE ) ) + if (m_sr & (RSP_STATUS_HALT | RSP_STATUS_BROKE)) { - m_rsp_state->icount = std::min(m_rsp_state->icount, 0); + m_ideduct = 0; + m_scalar_busy = false; + m_vector_busy = false; + m_paired_busy = false; + m_icount = std::min(m_icount, 0); } - /*m_cop2->dump(op); - if (((op >> 26) & 0x3f) == 0x3a) - { - m_cop2->dump_dmem(); - }*/ } } diff --git a/src/devices/cpu/rsp/rsp.h b/src/devices/cpu/rsp/rsp.h index 5383889cdd3..b33012bddda 100644 --- a/src/devices/cpu/rsp/rsp.h +++ b/src/devices/cpu/rsp/rsp.h @@ -14,9 +14,6 @@ #pragma once -#include "cpu/drcfe.h" -#include "cpu/drcuml.h" - /*************************************************************************** REGISTER ENUMERATION ***************************************************************************/ @@ -81,14 +78,9 @@ enum #define RSP_STATUS_SIGNAL6 0x2000 #define RSP_STATUS_SIGNAL7 0x4000 -#define RSPDRC_STRICT_VERIFY 0x0001 /* verify all instructions */ - - class rsp_device : public cpu_device { - class frontend; class cop2; - class cop2_drc; public: // construction/destruction @@ -102,24 +94,6 @@ public: auto sp_reg_w() { return m_sp_reg_w_func.bind(); } auto status_set() { return m_sp_set_status_func.bind(); } - void rspdrc_flush_drc_cache(); - void rspdrc_set_options(uint32_t options); - void rsp_add_dmem(uint32_t *base); - void rsp_add_imem(uint32_t *base); - - void ccfunc_read8(); - void ccfunc_read16(); - void ccfunc_read32(); - void ccfunc_write8(); - void ccfunc_write16(); - void ccfunc_write32(); - void ccfunc_get_cop0_reg(); - void ccfunc_set_cop0_reg(); - void ccfunc_sp_set_status_cb(); - void ccfunc_unimplemented(); - - uint8_t* get_dmem() { return m_dmem8; } - protected: // device-level overrides virtual void device_start() override; @@ -146,95 +120,56 @@ protected: void unimplemented_opcode(uint32_t op); - /* internal compiler state */ - struct compiler_state - { - compiler_state &operator=(compiler_state &) = delete; - - uint32_t cycles; /* accumulated cycles */ - uint8_t checkints; /* need to check interrupts before next instruction */ - uint8_t checksoftints; /* need to check software interrupts before next instruction */ - uml::code_label labelnum; /* index for local labels */ - }; - private: - address_space_config m_program_config; - - /* fast RAM info */ - struct fast_ram_info - { - offs_t start; /* start of the RAM block */ - offs_t end; /* end of the RAM block */ - bool readonly; /* true if read-only */ - void * base; /* base in memory where the RAM lives */ - }; + address_space_config m_imem_config; + address_space_config m_dmem_config; - /* core state */ - drc_cache m_cache; /* pointer to the DRC code cache */ - std::unique_ptr<drcuml_state> m_drcuml; /* DRC UML generator state */ - std::unique_ptr<frontend> m_drcfe; /* pointer to the DRC front-end state */ - uint32_t m_drcoptions; /* configurable DRC options */ - - /* internal stuff */ - uint8_t m_cache_dirty; /* true if we need to flush the cache */ - - /* parameters for subroutines */ - uint64_t m_numcycles; /* return value from gettotalcycles */ - const char * m_format; /* format string for print_debug */ - uint32_t m_arg2; /* print_debug argument 3 */ - uint32_t m_arg3; /* print_debug argument 4 */ - - /* register mappings */ - uml::parameter m_regmap[34]; /* parameter to register mappings for all 32 integer registers */ - - /* subroutines */ - uml::code_handle * m_entry; /* entry point */ - uml::code_handle * m_nocode; /* nocode exception handler */ - uml::code_handle * m_out_of_cycles; /* out of cycles exception handler */ - uml::code_handle * m_read8; /* read byte */ - uml::code_handle * m_write8; /* write byte */ - uml::code_handle * m_read16; /* read half */ - uml::code_handle * m_write16; /* write half */ - uml::code_handle * m_read32; /* read word */ - uml::code_handle * m_write32; /* write word */ - - struct internal_rsp_state - { - uint32_t pc; - uint32_t r[35]; - uint32_t arg0; - uint32_t arg1; - uint32_t jmpdest; - int icount; - }; + uint16_t m_pc; + uint32_t m_r[35]; + int m_icount; + int m_ideduct; + bool m_scalar_busy; + bool m_vector_busy; + bool m_paired_busy; - internal_rsp_state *m_rsp_state; + void update_scalar_op_deduction(); + void update_vector_op_deduction(); FILE *m_exec_output; uint32_t m_sr; uint32_t m_step_count; - uint32_t m_ppc; - uint32_t m_nextpc; + uint16_t m_ppc; + uint16_t m_nextpc; protected: - memory_access<32, 2, 0, ENDIANNESS_BIG>::cache m_pcache; - memory_access<32, 2, 0, ENDIANNESS_BIG>::specific m_program; + memory_access<12, 2, 0, ENDIANNESS_BIG>::cache m_icache; + memory_access<12, 2, 0, ENDIANNESS_BIG>::specific m_imem; + memory_access<12, 2, 0, ENDIANNESS_BIG>::cache m_dcache; + memory_access<12, 2, 0, ENDIANNESS_BIG>::specific m_dmem; private: - std::unique_ptr<cop2> m_cop2; - - uint32_t *m_dmem32; - uint16_t *m_dmem16; - uint8_t *m_dmem8; + union VECTOR_REG + { + uint64_t d[2]; + uint32_t l[4]; + uint16_t w[8]; + int16_t s[8]; + uint8_t b[16]; + }; - uint32_t *m_imem32; - uint16_t *m_imem16; - uint8_t *m_imem8; + union ACCUMULATOR_REG + { + uint64_t q; + uint32_t l[2]; + uint16_t w[4]; + }; uint32_t m_debugger_temp; - bool m_isdrc; + uint16_t m_pc_temp; + uint16_t m_ppc_temp; + uint16_t m_nextpc_temp; devcb_read32 m_dp_reg_r_func; devcb_write32 m_dp_reg_w_func; @@ -242,42 +177,40 @@ private: devcb_write32 m_sp_reg_w_func; devcb_write32 m_sp_set_status_func; - uint8_t READ8(uint32_t address); - uint16_t READ16(uint32_t address); - uint32_t READ32(uint32_t address); - void WRITE8(uint32_t address, uint8_t data); - void WRITE16(uint32_t address, uint16_t data); - void WRITE32(uint32_t address, uint32_t data); + uint8_t read_dmem_byte(uint32_t address); + uint16_t read_dmem_word(uint32_t address); + uint32_t read_dmem_dword(uint32_t address); + void write_dmem_byte(uint32_t address, uint8_t data); + void write_dmem_word(uint32_t address, uint16_t data); + void write_dmem_dword(uint32_t address, uint32_t data); uint32_t get_cop0_reg(int reg); void set_cop0_reg(int reg, uint32_t data); - void load_fast_iregs(drcuml_block &block); - void save_fast_iregs(drcuml_block &block); - uint8_t DM_READ8(uint32_t address); - uint16_t DM_READ16(uint32_t address); - uint32_t DM_READ32(uint32_t address); - void DM_WRITE8(uint32_t address, uint8_t data); - void DM_WRITE16(uint32_t address, uint16_t data); - void DM_WRITE32(uint32_t address, uint32_t data); void rspcom_init(); - void execute_run_drc(); - void code_flush_cache(); - void code_compile_block(offs_t pc); - void static_generate_entry_point(); - void static_generate_nocode_handler(); - void static_generate_out_of_cycles(); - void static_generate_memory_accessor(int size, int iswrite, const char *name, uml::code_handle *&handleptr); - void generate_update_cycles(drcuml_block &block, compiler_state &compiler, uml::parameter param, bool allow_exception); - void generate_checksum_block(drcuml_block &block, compiler_state &compiler, const opcode_desc *seqhead, const opcode_desc *seqlast); - void generate_sequence_instruction(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc); - void generate_delay_slot_and_branch(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc, uint8_t linkreg); - void generate_branch(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc); - bool generate_opcode(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc); - bool generate_special(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc); - bool generate_regimm(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc); - bool generate_cop0(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc); - void log_add_disasm_comment(drcuml_block &block, uint32_t pc, uint32_t op); -}; + // COP2 (vectors) + uint16_t SATURATE_ACCUM(int accum, int slice, uint16_t negative, uint16_t positive); + + uint16_t m_vres[8]; + VECTOR_REG m_v[32]; + ACCUMULATOR_REG m_accum[8]; + uint8_t m_vcarry; + uint8_t m_vcompare; + uint8_t m_vclip1; + uint8_t m_vzero; + uint8_t m_vclip2; + + int32_t m_reciprocal_res; + uint32_t m_reciprocal_high; + int32_t m_dp_allowed; + + void handle_cop2(uint32_t op); + void handle_lwc2(uint32_t op); + void handle_swc2(uint32_t op); + void handle_vector_ops(uint32_t op); + + uint32_t m_div_in; + uint32_t m_div_out; +}; DECLARE_DEVICE_TYPE(RSP, rsp_device) diff --git a/src/devices/cpu/rsp/rsp_dasm.cpp b/src/devices/cpu/rsp/rsp_dasm.cpp index 6db58a28f4a..84647274764 100644 --- a/src/devices/cpu/rsp/rsp_dasm.cpp +++ b/src/devices/cpu/rsp/rsp_dasm.cpp @@ -157,6 +157,8 @@ void rsp_disassembler::disasm_cop2(std::ostream &stream, uint32_t op) case 0x2b: util::stream_format(stream, "vnor %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; case 0x2c: util::stream_format(stream, "vxor %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; case 0x2d: util::stream_format(stream, "vnxor %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x2e: util::stream_format(stream, "v056 %s, %s[%c]", vreg[dest], vreg[s2], element2[el][s1 & 7]); break; + case 0x2f: util::stream_format(stream, "v057 %s, %s[%c]", vreg[dest], vreg[s2], element2[el][s1 & 7]); break; case 0x30: util::stream_format(stream, "vrcp %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break; case 0x31: util::stream_format(stream, "vrcpl %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break; case 0x32: util::stream_format(stream, "vrcph %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break; @@ -165,6 +167,8 @@ void rsp_disassembler::disasm_cop2(std::ostream &stream, uint32_t op) case 0x35: util::stream_format(stream, "vrsql %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break; case 0x36: util::stream_format(stream, "vrsqh %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break; case 0x37: util::stream_format(stream, "vnop"); break; + case 0x3b: util::stream_format(stream, "v073 %s, %s[%c]", vreg[dest], vreg[s2], element2[el][s1 & 7]); break; + case 0x3f: util::stream_format(stream, "vnull"); break; default: util::stream_format(stream, "??? (VECTOR OP)"); break; } break; diff --git a/src/devices/cpu/rsp/rspcp2.cpp b/src/devices/cpu/rsp/rspcp2.cpp deleted file mode 100644 index 3180d7103f6..00000000000 --- a/src/devices/cpu/rsp/rspcp2.cpp +++ /dev/null @@ -1,4223 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Ryan Holtz,Tyler J. Stachecki -/*************************************************************************** - - rspcp2.c - - Universal machine language-based Nintendo/SGI RSP COP2 emulator. - Written by Ryan Holtz of the MAME team. - -***************************************************************************/ - -#include "emu.h" -#include "rspcp2.h" - -#include "rsp.h" -#include "rspdefs.h" - - -#if USE_SIMD -#include <emmintrin.h> - -const rsp_device::cop2::vec_helpers_t rsp_device::cop2::m_vec_helpers = { - { 0 }, - { // logic_mask - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff } - }, - { // vrsq_mask_table - { 0xffff, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0xffff, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0xffff, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0xffff, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0xffff, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0xffff, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0xffff, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0xffff } - }, - { // shuffle_keys - { 0x0100, 0x0302, 0x0504, 0x0706, 0x0908, 0x0b0a, 0x0d0c, 0x0f0e }, /* -- */ - { 0x0100, 0x0302, 0x0504, 0x0706, 0x0908, 0x0b0a, 0x0d0c, 0x0f0e }, /* -- */ - - { 0x0100, 0x0100, 0x0504, 0x0504, 0x0908, 0x0908, 0x0d0c, 0x0d0c }, /* 0q */ - { 0x0302, 0x0302, 0x0706, 0x0706, 0x0b0a, 0x0b0a, 0x0f0e, 0x0f0e }, /* 1q */ - - { 0x0100, 0x0100, 0x0100, 0x0100, 0x0908, 0x0908, 0x0908, 0x0908 }, /* 0h */ - { 0x0302, 0x0302, 0x0302, 0x0302, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a }, /* 1h */ - { 0x0504, 0x0504, 0x0504, 0x0504, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c }, /* 2h */ - { 0x0706, 0x0706, 0x0706, 0x0706, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e }, /* 3h */ - - { 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100 }, /* 0w */ - { 0x0302, 0x0302, 0x0302, 0x0302, 0x0302, 0x0302, 0x0302, 0x0302 }, /* 1w */ - { 0x0504, 0x0504, 0x0504, 0x0504, 0x0504, 0x0504, 0x0504, 0x0504 }, /* 2w */ - { 0x0706, 0x0706, 0x0706, 0x0706, 0x0706, 0x0706, 0x0706, 0x0706 }, /* 3w */ - { 0x0908, 0x0908, 0x0908, 0x0908, 0x0908, 0x0908, 0x0908, 0x0908 }, /* 4w */ - { 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a }, /* 5w */ - { 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c }, /* 6w */ - { 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e } /* 7w */ - }, - { // sll_b2l_keys - { 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c }, - { 0x8003, 0x0201, 0x0007, 0x0605, 0x040b, 0x0a09, 0x080f, 0x0e0d }, - { 0x8080, 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e }, - { 0x8080, 0x8003, 0x0201, 0x0007, 0x0605, 0x040b, 0x0a09, 0x080f }, - - { 0x8080, 0x8080, 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908 }, - { 0x8080, 0x8080, 0x8003, 0x0201, 0x0007, 0x0605, 0x040b, 0x0a09 }, - { 0x8080, 0x8080, 0x8080, 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a }, - { 0x8080, 0x8080, 0x8080, 0x8003, 0x0201, 0x0007, 0x0605, 0x040b }, - - { 0x8080, 0x8080, 0x8080, 0x8080, 0x0302, 0x0100, 0x0706, 0x0504 }, - { 0x8080, 0x8080, 0x8080, 0x8080, 0x8003, 0x0201, 0x0007, 0x0605 }, - { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0302, 0x0100, 0x0706 }, - { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8003, 0x0201, 0x0007 }, - - { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0302, 0x0100 }, - { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8003, 0x0201 }, - { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0302 }, - { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8003 }, - }, - { // sll_l2b_keys - { 0x0100, 0x0302, 0x0504, 0x0706, 0x0908, 0x0b0a, 0x0d0c, 0x0f0e }, - { 0x0201, 0x8003, 0x0605, 0x0007, 0x0a09, 0x040b, 0x0e0d, 0x080f }, - { 0x0302, 0x8080, 0x0706, 0x0100, 0x0b0a, 0x0504, 0x0f0e, 0x0908 }, - { 0x8003, 0x8080, 0x0007, 0x0201, 0x040b, 0x0605, 0x080f, 0x0a09 }, - - { 0x8080, 0x8080, 0x0100, 0x0302, 0x0504, 0x0706, 0x0908, 0x0b0a }, - { 0x8080, 0x8080, 0x0201, 0x8003, 0x0605, 0x0007, 0x0a09, 0x040b }, - { 0x8080, 0x8080, 0x0302, 0x8080, 0x0706, 0x0100, 0x0b0a, 0x0504 }, - { 0x8080, 0x8080, 0x8003, 0x8080, 0x0007, 0x0201, 0x040b, 0x0605 }, - - { 0x8080, 0x8080, 0x8080, 0x8080, 0x0100, 0x0302, 0x0504, 0x0706 }, - { 0x8080, 0x8080, 0x8080, 0x8080, 0x0201, 0x8003, 0x0605, 0x0007 }, - { 0x8080, 0x8080, 0x8080, 0x8080, 0x0302, 0x8080, 0x0706, 0x0100 }, - { 0x8080, 0x8080, 0x8080, 0x8080, 0x8003, 0x8080, 0x0007, 0x0201 }, - - { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0100, 0x0302 }, - { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0201, 0x8003 }, - { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0302, 0x8080 }, - { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8003, 0x8080 }, - }, - { // srl_b2l_keys - { 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c }, - { 0x0201, 0x0007, 0x0605, 0x040b, 0x0a09, 0x080f, 0x0e0d, 0x0c80 }, - { 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x8080 }, - { 0x0007, 0x0605, 0x040b, 0x0a09, 0x080f, 0x0e0d, 0x0c80, 0x8080 }, - - { 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x8080, 0x8080 }, - { 0x0605, 0x040b, 0x0a09, 0x080f, 0x0e0d, 0x0c80, 0x8080, 0x8080 }, - { 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x8080, 0x8080, 0x8080 }, - { 0x040b, 0x0a09, 0x080f, 0x0e0d, 0x0c80, 0x8080, 0x8080, 0x8080 }, - - { 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x8080, 0x8080, 0x8080, 0x8080 }, - { 0x0a09, 0x080f, 0x0e0d, 0x0c80, 0x8080, 0x8080, 0x8080, 0x8080 }, - { 0x0908, 0x0f0e, 0x0d0c, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080 }, - { 0x080f, 0x0e0d, 0x0c80, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080 }, - - { 0x0f0e, 0x0d0c, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080 }, - { 0x0e0d, 0x0c80, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080 }, - { 0x0d0c, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080 }, - { 0x0c80, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080 }, - }, - { // ror_b2l_keys - { 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c }, - { 0x0201, 0x0007, 0x0605, 0x040b, 0x0a09, 0x080f, 0x0e0d, 0x0c03 }, - { 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x0302 }, - { 0x0007, 0x0605, 0x040b, 0x0a09, 0x080f, 0x0e0d, 0x0c03, 0x0201 }, - - { 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x0302, 0x0100 }, - { 0x0605, 0x040b, 0x0a09, 0x080f, 0x0e0d, 0x0c03, 0x0201, 0x0007 }, - { 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x0302, 0x0100, 0x0706 }, - { 0x040b, 0x0a09, 0x080f, 0x0e0d, 0x0c03, 0x0201, 0x0007, 0x0605 }, - - { 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x0302, 0x0100, 0x0706, 0x0504 }, - { 0x0a09, 0x080f, 0x0e0d, 0x0c03, 0x0201, 0x0007, 0x0605, 0x040b }, - { 0x0908, 0x0f0e, 0x0d0c, 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a }, - { 0x080f, 0x0e0d, 0x0c03, 0x0201, 0x0007, 0x0605, 0x040b, 0x0a09 }, - - { 0x0f0e, 0x0d0c, 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908 }, - { 0x0e0d, 0x0c03, 0x0201, 0x0007, 0x0605, 0x040b, 0x0a09, 0x080f }, - { 0x0d0c, 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e }, - { 0x0c03, 0x0201, 0x0007, 0x0605, 0x040b, 0x0a09, 0x080f, 0x0e0d }, - }, - { // rol_l2b_keys - { 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c }, - { 0x0003, 0x0e01, 0x0407, 0x0205, 0x080b, 0x0609, 0x0c0f, 0x0a0d }, - { 0x0100, 0x0f0e, 0x0504, 0x0302, 0x0908, 0x0706, 0x0d0c, 0x0b0a }, - { 0x0e01, 0x0c0f, 0x0205, 0x0003, 0x0609, 0x0407, 0x0a0d, 0x080b }, - - { 0x0f0e, 0x0d0c, 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908 }, - { 0x0c0f, 0x0a0d, 0x0003, 0x0e01, 0x0407, 0x0205, 0x080b, 0x0609 }, - { 0x0d0c, 0x0b0a, 0x0100, 0x0f0e, 0x0504, 0x0302, 0x0908, 0x0706 }, - { 0x0a0d, 0x080b, 0x0e01, 0x0c0f, 0x0205, 0x0003, 0x0609, 0x0407 }, - - { 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x0302, 0x0100, 0x0706, 0x0504 }, - { 0x080b, 0x0609, 0x0c0f, 0x0a0d, 0x0003, 0x0e01, 0x0407, 0x0205 }, - { 0x0908, 0x0706, 0x0d0c, 0x0b0a, 0x0100, 0x0f0e, 0x0504, 0x0302 }, - { 0x0609, 0x0407, 0x0a0d, 0x080b, 0x0e01, 0x0c0f, 0x0205, 0x0003 }, - - { 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x0302, 0x0100 }, - { 0x0407, 0x0205, 0x080b, 0x0609, 0x0c0f, 0x0a0d, 0x0003, 0x0e01 }, - { 0x0504, 0x0302, 0x0908, 0x0706, 0x0d0c, 0x0b0a, 0x0100, 0x0f0e }, - { 0x0205, 0x0003, 0x0609, 0x0407, 0x0a0d, 0x080b, 0x0e01, 0x0c0f }, - }, - { // ror_l2b_keys - { 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c }, - { 0x0205, 0x0003, 0x0609, 0x0407, 0x0a0d, 0x080b, 0x0e01, 0x0c0f }, - { 0x0504, 0x0302, 0x0908, 0x0706, 0x0d0c, 0x0b0a, 0x0100, 0x0f0e }, - { 0x0407, 0x0205, 0x080b, 0x0609, 0x0c0f, 0x0a0d, 0x0003, 0x0e01 }, - - { 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x0302, 0x0100 }, - { 0x0609, 0x0407, 0x0a0d, 0x080b, 0x0e01, 0x0c0f, 0x0205, 0x0003 }, - { 0x0908, 0x0706, 0x0d0c, 0x0b0a, 0x0100, 0x0f0e, 0x0504, 0x0302 }, - { 0x080b, 0x0609, 0x0c0f, 0x0a0d, 0x0003, 0x0e01, 0x0407, 0x0205 }, - - { 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x0302, 0x0100, 0x0706, 0x0504 }, - { 0x0a0d, 0x080b, 0x0e01, 0x0c0f, 0x0205, 0x0003, 0x0609, 0x0407 }, - { 0x0d0c, 0x0b0a, 0x0100, 0x0f0e, 0x0504, 0x0302, 0x0908, 0x0706 }, - { 0x0c0f, 0x0a0d, 0x0003, 0x0e01, 0x0407, 0x0205, 0x080b, 0x0609 }, - - { 0x0f0e, 0x0d0c, 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908 }, - { 0x0e01, 0x0c0f, 0x0205, 0x0003, 0x0609, 0x0407, 0x0a0d, 0x080b }, - { 0x0100, 0x0f0e, 0x0504, 0x0302, 0x0908, 0x0706, 0x0d0c, 0x0b0a }, - { 0x0003, 0x0e01, 0x0407, 0x0205, 0x080b, 0x0609, 0x0c0f, 0x0a0d }, - }, - { // qr_lut - { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, - { 0xffff, 0xff00, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, - { 0xffff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, - { 0xff00, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, - - { 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, - { 0x0000, 0x0000, 0xffff, 0xff00, 0xffff, 0xffff, 0xffff, 0xffff }, - { 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff }, - { 0x0000, 0x0000, 0xff00, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff }, - - { 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff }, - { 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0xff00, 0xffff, 0xffff }, - { 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0xffff }, - { 0x0000, 0x0000, 0x0000, 0x0000, 0xff00, 0x0000, 0xffff, 0xffff }, - - { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff }, - { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0xff00 }, - { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000 }, - { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xff00, 0x0000 } - }, - { // bdls_lut - mask to denote which part of the vector to load/store. - { 0x0000, 0xff00, 0x0000, 0x0000 }, // B - { 0x0000, 0xffff, 0x0000, 0x0000 }, // S - { 0xffff, 0xffff, 0x0000, 0x0000 }, // L - { 0xffff, 0xffff, 0xffff, 0xffff } // D - }, - { // word_reverse - 0x0203, 0x0001, 0x0607, 0x0405, 0x0a0b, 0x0809, 0x0e0f, 0x0c0d - } -}; - -#if !(defined(__SSSE3__) || defined(_MSC_VER)) -// TODO: Highly optimized. More of a stopgap measure. -static inline rsp_vec_t sse2_pshufb(rsp_vec_t v, const uint16_t *keys) -{ - uint8_t dest[16]; - uint8_t temp[16]; - - _mm_storeu_si128((rsp_vec_t *) temp, v); - - for (uint32_t j = 0; j < 8; j++) - { - uint16_t key = keys[j]; - uint8_t key_hi = key >> 8; - uint8_t key_lo = key >> 0; - - dest[(j << 1) + 1] = key_hi == 0x80 ? 0x00 : temp[key_hi]; - dest[(j << 1) + 0] = key_lo == 0x80 ? 0x00 : temp[key_lo]; - } - - return _mm_loadu_si128((rsp_vec_t *) dest); -} - -rsp_vec_t rsp_device::cop2::vec_load_and_shuffle_operand(const uint16_t* src, uint32_t element) -{ - if (element >= 8) // element => 0w ... 7w - { - uint16_t word_lo; - - memcpy(&word_lo, src + (element - 8), sizeof(word_lo)); - uint64_t dword = word_lo | ((uint32_t) word_lo << 16); - - return _mm_shuffle_epi32(_mm_loadl_epi64((rsp_vec_t*) &dword), _MM_SHUFFLE(0,0,0,0)); - } - else if (element >= 4) // element => 0h ... 3h - { - uint16_t word_lo; - uint16_t word_hi; - - memcpy(&word_hi, src + element - 0, sizeof(word_hi)); - memcpy(&word_lo, src + element - 4, sizeof(word_lo)); - uint64_t dword = word_lo | ((uint32_t) word_hi << 16); - - rsp_vec_t v = _mm_loadl_epi64((rsp_vec_t*) &dword); - v = _mm_shufflelo_epi16(v, _MM_SHUFFLE(1,1,0,0)); - return _mm_shuffle_epi32(v, _MM_SHUFFLE(1,1,0,0)); - } - else if (element >= 2) // element => 0q ... 1q - { - rsp_vec_t v = vec_load_unshuffled_operand(src); - - if (element == 2) { - v = _mm_shufflelo_epi16(v, _MM_SHUFFLE(3,3,1,1)); - v = _mm_shufflehi_epi16(v, _MM_SHUFFLE(3,3,1,1)); - } - else - { - v = _mm_shufflelo_epi16(v, _MM_SHUFFLE(2,2,0,0)); - v = _mm_shufflehi_epi16(v, _MM_SHUFFLE(2,2,0,0)); - } - - return v; - } - - return vec_load_unshuffled_operand(src); -} -#else -rsp_vec_t rsp_device::cop2::vec_load_and_shuffle_operand(const uint16_t* src, uint32_t element) -{ - rsp_vec_t operand = _mm_load_si128((rsp_vec_t*) src); - rsp_vec_t key = _mm_load_si128((rsp_vec_t*) m_vec_helpers.shuffle_keys[element]); - - return _mm_shuffle_epi8(operand, key); -} -#endif -// -// SSSE3+ accelerated loads for group I. Byteswap big-endian to 2-byte -// little-endian vector. Start at vector element offset, discarding any -// wraparound as necessary. -// -// TODO: Reverse-engineer what happens when loads to vector elements must -// wraparound. Do we just discard the data, as below, or does the -// data effectively get rotated around the edge of the vector? -// -void rsp_device::cop2::vec_load_group1(uint32_t addr, uint32_t element, uint16_t *regp, rsp_vec_t reg, rsp_vec_t dqm) -{ - uint32_t offset = addr & 0x7; - uint32_t ror = offset - element; - - // Always load in 8-byte chunks to emulate wraparound. - rsp_vec_t data; - if (offset) { - uint32_t aligned_addr_lo = addr & ~0x7; - uint32_t aligned_addr_hi = (aligned_addr_lo + 8) & 0xFFF; - - data = _mm_loadl_epi64((rsp_vec_t *) (m_rsp.get_dmem() + aligned_addr_lo)); - rsp_vec_t temp = _mm_loadl_epi64((rsp_vec_t *) (m_rsp.get_dmem() + aligned_addr_hi)); - data = _mm_unpacklo_epi64(data, temp); - } - else - { - data = _mm_loadl_epi64((rsp_vec_t *) (m_rsp.get_dmem() + addr)); - } - - // Shift the DQM up to the point where we mux in the data. -#if !(defined(__SSSE3__) || defined(_MSC_VER)) - dqm = sse2_pshufb(dqm, m_vec_helpers.sll_b2l_keys[element]); -#else - rsp_vec_t ekey = _mm_load_si128((rsp_vec_t *) (m_vec_helpers.sll_b2l_keys[element])); - dqm = _mm_shuffle_epi8(dqm, ekey); -#endif - - // Align the data to the DQM so we can mask it in. -#if !(defined(__SSSE3__) || defined(_MSC_VER)) - data = sse2_pshufb(data, m_vec_helpers.ror_b2l_keys[ror & 0xF]); -#else - ekey = _mm_load_si128((rsp_vec_t *) (m_vec_helpers.ror_b2l_keys[ror & 0xF])); - data = _mm_shuffle_epi8(data, ekey); -#endif - - // Mask and mux in the data. -#if (defined(__SSE4_1__) || defined(_MSC_VER)) - reg = _mm_blendv_epi8(reg, data, dqm); -#else - data = _mm_and_si128(dqm, data); - reg = _mm_andnot_si128(dqm, reg); - reg = _mm_or_si128(data, reg); -#endif - - _mm_store_si128((rsp_vec_t *) regp, reg); -} - -// -// SSSE3+ accelerated loads for group II. -// -// TODO: Reverse-engineer what happens when loads to vector elements must -// wraparound. Do we just discard the data, as below, or does the -// data effectively get rotated around the edge of the vector? -// -// TODO: Reverse-engineer what happens when element != 0. -// -void rsp_device::cop2::vec_load_group2(uint32_t addr, uint32_t element, uint16_t *regp, rsp_vec_t reg, rsp_vec_t dqm, rsp_mem_request_type request_type) { - uint32_t offset = addr & 0x7; - rsp_vec_t data; - - // Always load in 8-byte chunks to emulate wraparound. - if (offset) { - uint32_t aligned_addr_lo = addr & ~0x7; - uint32_t aligned_addr_hi = (aligned_addr_lo + 8) & 0xFFF; - uint64_t datalow, datahigh; - - memcpy(&datalow, m_rsp.get_dmem() + aligned_addr_lo, sizeof(datalow)); - memcpy(&datahigh, m_rsp.get_dmem() + aligned_addr_hi, sizeof(datahigh)); - - // TODO: Test for endian issues? - datahigh >>= ((8 - offset) << 3); - datalow <<= (offset << 3); - datalow = datahigh | datalow; - - data = _mm_loadl_epi64((rsp_vec_t *) &datalow); - } - else - { - data = _mm_loadl_epi64((rsp_vec_t *) (m_rsp.get_dmem() + addr)); - } - - // "Unpack" the data. - rsp_vec_t zero = _mm_setzero_si128(); - data = _mm_unpacklo_epi8(zero, data); - - if (request_type != RSP_MEM_REQUEST_PACK) - { - data = _mm_srli_epi16(data, 1); - } - - data = _mm_shufflehi_epi16(data, _MM_SHUFFLE(0, 1, 2, 3)); - data = _mm_shufflelo_epi16(data, _MM_SHUFFLE(0, 1, 2, 3)); - - _mm_store_si128((rsp_vec_t *) regp, data); -} - -// -// SSSE3+ accelerated loads for group IV. Byteswap big-endian to 2-byte -// little-endian vector. Stop loading at quadword boundaries. -// -// TODO: Reverse-engineer what happens when loads from vector elements -// must wraparound (i.e., the address offset is small, starting -// element is large). -// -void rsp_device::cop2::vec_load_group4(uint32_t addr, uint32_t element, uint16_t *regp, rsp_vec_t reg, rsp_vec_t dqm, rsp_mem_request_type request_type) -{ - uint32_t aligned_addr = addr & 0xFF0; - uint32_t offset = addr & 0xF; - static uint32_t call_count = 0; - - rsp_vec_t data = _mm_load_si128((rsp_vec_t *) (m_rsp.get_dmem() + aligned_addr)); - - uint32_t ror; - if (request_type == RSP_MEM_REQUEST_QUAD) - { - ror = 16 - element + offset; - } - else - { - // TODO: How is this adjusted for LRV when e != 0? - dqm = _mm_cmpeq_epi8(_mm_setzero_si128(), dqm); - ror = 16 - offset; - } - -#if !(defined(__SSSE3__) || defined(_MSC_VER)) - data = sse2_pshufb(data, m_vec_helpers.ror_b2l_keys[ror & 0xF]); - dqm = sse2_pshufb(dqm, m_vec_helpers.ror_b2l_keys[ror & 0xF]); -#else - rsp_vec_t dkey = _mm_load_si128((rsp_vec_t *) (m_vec_helpers.ror_b2l_keys[ror & 0xF])); - data = _mm_shuffle_epi8(data, dkey); - dqm = _mm_shuffle_epi8(dqm, dkey); -#endif - - // Mask and mux in the data. -#if (defined(__SSE4_1__) || defined(_MSC_VER)) - data = _mm_blendv_epi8(reg, data, dqm); -#else - data = _mm_and_si128(dqm, data); - reg = _mm_andnot_si128(dqm, reg); - data = _mm_or_si128(data, reg); -#endif - - _mm_store_si128((rsp_vec_t *) regp, data); - - call_count++; -} - -// -// SSE3+ accelerated stores for group I. Byteswap 2-byte little-endian -// vector back to big-endian. Start at vector element offset, wrapping -// around the edge of the vector as necessary. -// -// TODO: Reverse-engineer what happens when stores from vector elements -// must wraparound. Do we just stop storing the data, or do we -// continue storing from the front of the vector, as below? -// -void rsp_device::cop2::vec_store_group1(uint32_t addr, uint32_t element, uint16_t *regp, rsp_vec_t reg, rsp_vec_t dqm) -{ - uint32_t offset = addr & 0x7; - uint32_t ror = element - offset; - - // Shift the DQM up to the point where we mux in the data. -#if !(defined(__SSSE3__) || defined(_MSC_VER)) - dqm = sse2_pshufb(dqm, m_vec_helpers.sll_l2b_keys[offset]); -#else - rsp_vec_t ekey = _mm_load_si128((rsp_vec_t *) (m_vec_helpers.sll_l2b_keys[offset])); - dqm = _mm_shuffle_epi8(dqm, ekey); -#endif - - // Rotate the reg to align with the DQM. -#if !(defined(__SSSE3__) || defined(_MSC_VER)) - reg = sse2_pshufb(reg, m_vec_helpers.ror_l2b_keys[ror & 0xF]); -#else - ekey = _mm_load_si128((rsp_vec_t *) (m_vec_helpers.ror_l2b_keys[ror & 0xF])); - reg = _mm_shuffle_epi8(reg, ekey); -#endif - - // Always load in 8-byte chunks to emulate wraparound. - rsp_vec_t data; - if (offset) - { - uint32_t aligned_addr_lo = addr & ~0x7; - uint32_t aligned_addr_hi = (aligned_addr_lo + 8) & 0xFFF; - - data = _mm_loadl_epi64((rsp_vec_t *) (m_rsp.get_dmem() + aligned_addr_lo)); - rsp_vec_t temp = _mm_loadl_epi64((rsp_vec_t *) (m_rsp.get_dmem() + aligned_addr_hi)); - data = _mm_unpacklo_epi64(data, temp); - - // Mask and mux in the data. -#if (defined(__SSE4_1__) || defined(_MSC_VER)) - data = _mm_blendv_epi8(data, reg, dqm); -#else - data = _mm_andnot_si128(dqm, data); - reg = _mm_and_si128(dqm, reg); - data = _mm_or_si128(data, reg); -#endif - - _mm_storel_epi64((rsp_vec_t *) (m_rsp.get_dmem() + aligned_addr_lo), data); - - data = _mm_srli_si128(data, 8); - _mm_storel_epi64((rsp_vec_t *) (m_rsp.get_dmem() + aligned_addr_hi), data); - } - else - { - data = _mm_loadl_epi64((rsp_vec_t *) (m_rsp.get_dmem() + addr)); - - // Mask and mux in the data. -#if (defined(__SSE4_1__) || defined(_MSC_VER)) - data = _mm_blendv_epi8(data, reg, dqm); -#else - data = _mm_andnot_si128(dqm, data); - reg = _mm_and_si128(dqm, reg); - data = _mm_or_si128(data, reg); -#endif - - _mm_storel_epi64((rsp_vec_t *) (m_rsp.get_dmem() + addr), data); - } -} - -// -// SSE3+ accelerated stores for group II. Byteswap 2-byte little-endian -// vector back to big-endian. Start at vector element offset, wrapping -// around the edge of the vector as necessary. -// -// TODO: Reverse-engineer what happens when stores from vector elements -// must wraparound. Do we just stop storing the data, or do we -// continue storing from the front of the vector, as below? -// -// TODO: Reverse-engineer what happens when element != 0. -// -void rsp_device::cop2::vec_store_group2(uint32_t addr, uint32_t element, uint16_t *regp, rsp_vec_t reg, rsp_vec_t dqm, rsp_mem_request_type request_type) { - // "Pack" the data. - if (request_type != RSP_MEM_REQUEST_PACK) - { - reg = _mm_slli_epi16(reg, 1); - } - - reg = _mm_srai_epi16(reg, 8); - reg = _mm_packs_epi16(reg, reg); - -#if !(defined(__SSSE3__) || defined(_MSC_VER)) - reg = sse2_pshufb(reg, m_vec_helpers.word_reverse); -#else - rsp_vec_t dkey = _mm_load_si128((rsp_vec_t *) (m_vec_helpers.word_reverse)); - reg = _mm_shuffle_epi8(reg, dkey); -#endif - - // TODO: Always store in 8-byte chunks to emulate wraparound. - _mm_storel_epi64((rsp_vec_t *) (m_rsp.get_dmem() + addr), reg); -} - -// -// SSE3+ accelerated stores for group IV. Byteswap 2-byte little-endian -// vector back to big-endian. Stop storing at quadword boundaries. -// -void rsp_device::cop2::vec_store_group4(uint32_t addr, uint32_t element, uint16_t *regp, rsp_vec_t reg, rsp_vec_t dqm, rsp_mem_request_type request_type) { - uint32_t aligned_addr = addr & 0xFF0; - uint32_t offset = addr & 0xF; - uint32_t rol = offset; - - rsp_vec_t data = _mm_load_si128((rsp_vec_t *) (m_rsp.get_dmem() + aligned_addr)); - - if (request_type == RSP_MEM_REQUEST_QUAD) - { - rol -= element; - } - else - { - // TODO: How is this adjusted for SRV when e != 0? - dqm = _mm_cmpeq_epi8(_mm_setzero_si128(), dqm); - } - -#if !(defined(__SSSE3__) || defined(_MSC_VER)) - reg = sse2_pshufb(reg, m_vec_helpers.rol_l2b_keys[rol & 0xF]); -#else - rsp_vec_t ekey = _mm_load_si128((rsp_vec_t *) (m_vec_helpers.rol_l2b_keys[rol & 0xF])); - reg = _mm_shuffle_epi8(reg, ekey); -#endif - - // Mask and mux out the data, write. -#if (defined(__SSE4_1__) || defined(_MSC_VER)) - data = _mm_blendv_epi8(data, reg, dqm); -#else - reg = _mm_and_si128(dqm, reg); - data = _mm_andnot_si128(dqm, data); - data = _mm_or_si128(data, reg); -#endif - - _mm_store_si128((rsp_vec_t *) (m_rsp.get_dmem() + aligned_addr), data); -} -#endif - -/*************************************************************************** - Helpful Defines -***************************************************************************/ - -#define VDREG ((op >> 6) & 0x1f) -#define VS1REG ((op >> 11) & 0x1f) -#define VS2REG ((op >> 16) & 0x1f) -#define EL ((op >> 21) & 0xf) - -#define RSVAL (m_rsp.m_rsp_state->r[RSREG]) -#define RTVAL (m_rsp.m_rsp_state->r[RTREG]) -#define RDVAL (m_rsp.m_rsp_state->r[RDREG]) - -#define VREG_B(reg, offset) m_v[(reg)].b[(offset)^1] -#define VREG_S(reg, offset) m_v[(reg)].s[(offset)] -#define VREG_L(reg, offset) m_v[(reg)].l[(offset)] - -#define R_VREG_B(reg, offset) m_v[(reg)].b[(offset)^1] -#define R_VREG_S(reg, offset) (int16_t)m_v[(reg)].s[(offset)] -#define R_VREG_L(reg, offset) m_v[(reg)].l[(offset)] - -#define W_VREG_B(reg, offset, val) (m_v[(reg)].b[(offset)^1] = val) -#define W_VREG_S(reg, offset, val) (m_v[(reg)].s[(offset)] = val) -#define W_VREG_L(reg, offset, val) (m_v[(reg)].l[(offset)] = val) - -#define VEC_EL_2(x,z) (vector_elements_2[(x)][(z)]) - -#define CARRY 0 -#define COMPARE 1 -#define CLIP1 2 -#define ZERO 3 -#define CLIP2 4 - -#define ACCUM(x) m_accum[x].q -#define ACCUM_H(x) (uint16_t)m_accum[x].w[3] -#define ACCUM_M(x) (uint16_t)m_accum[x].w[2] -#define ACCUM_L(x) (uint16_t)m_accum[x].w[1] -#define ACCUM_LL(x) (uint16_t)m_accum[x].w[0] - -#define SET_ACCUM_H(v, x) m_accum[x].w[3] = v; -#define SET_ACCUM_M(v, x) m_accum[x].w[2] = v; -#define SET_ACCUM_L(v, x) m_accum[x].w[1] = v; -#define SET_ACCUM_LL(v, x) m_accum[x].w[0] = v; - -#define CARRY_FLAG(x) (m_vflag[CARRY][x & 7] != 0 ? 0xffff : 0) -#define COMPARE_FLAG(x) (m_vflag[COMPARE][x & 7] != 0 ? 0xffff : 0) -#define CLIP1_FLAG(x) (m_vflag[CLIP1][x & 7] != 0 ? 0xffff : 0) -#define ZERO_FLAG(x) (m_vflag[ZERO][x & 7] != 0 ? 0xffff : 0) -#define CLIP2_FLAG(x) (m_vflag[CLIP2][x & 7] != 0 ? 0xffff : 0) - -#define CLEAR_CARRY_FLAGS() { memset(m_vflag[CARRY], 0, 16); } -#define CLEAR_COMPARE_FLAGS() { memset(m_vflag[COMPARE], 0, 16); } -#define CLEAR_CLIP1_FLAGS() { memset(m_vflag[CLIP1], 0, 16); } -#define CLEAR_ZERO_FLAGS() { memset(m_vflag[ZERO], 0, 16); } -#define CLEAR_CLIP2_FLAGS() { memset(m_vflag[CLIP2], 0, 16); } - -#define SET_CARRY_FLAG(x) { m_vflag[CARRY][x & 7] = 0xffff; } -#define SET_COMPARE_FLAG(x) { m_vflag[COMPARE][x & 7] = 0xffff; } -#define SET_CLIP1_FLAG(x) { m_vflag[CLIP1][x & 7] = 0xffff; } -#define SET_ZERO_FLAG(x) { m_vflag[ZERO][x & 7] = 0xffff; } -#define SET_CLIP2_FLAG(x) { m_vflag[CLIP2][x & 7] = 0xffff; } - -#define CLEAR_CARRY_FLAG(x) { m_vflag[CARRY][x & 7] = 0; } -#define CLEAR_COMPARE_FLAG(x) { m_vflag[COMPARE][x & 7] = 0; } -#define CLEAR_CLIP1_FLAG(x) { m_vflag[CLIP1][x & 7] = 0; } -#define CLEAR_ZERO_FLAG(x) { m_vflag[ZERO][x & 7] = 0; } -#define CLEAR_CLIP2_FLAG(x) { m_vflag[CLIP2][x & 7] = 0; } - -#define WRITEBACK_RESULT() { \ - VREG_S(VDREG, 0) = m_vres[0]; \ - VREG_S(VDREG, 1) = m_vres[1]; \ - VREG_S(VDREG, 2) = m_vres[2]; \ - VREG_S(VDREG, 3) = m_vres[3]; \ - VREG_S(VDREG, 4) = m_vres[4]; \ - VREG_S(VDREG, 5) = m_vres[5]; \ - VREG_S(VDREG, 6) = m_vres[6]; \ - VREG_S(VDREG, 7) = m_vres[7]; \ -} - -#if !USE_SIMD -static const int vector_elements_2[16][8] = -{ - { 0, 1, 2, 3, 4, 5, 6, 7 }, // none - { 0, 1, 2, 3, 4, 5, 6, 7 }, // ??? - { 0, 0, 2, 2, 4, 4, 6, 6 }, // 0q - { 1, 1, 3, 3, 5, 5, 7, 7 }, // 1q - { 0, 0, 0, 0, 4, 4, 4, 4 }, // 0h - { 1, 1, 1, 1, 5, 5, 5, 5 }, // 1h - { 2, 2, 2, 2, 6, 6, 6, 6 }, // 2h - { 3, 3, 3, 3, 7, 7, 7, 7 }, // 3h - { 0, 0, 0, 0, 0, 0, 0, 0 }, // 0 - { 1, 1, 1, 1, 1, 1, 1, 1 }, // 1 - { 2, 2, 2, 2, 2, 2, 2, 2 }, // 2 - { 3, 3, 3, 3, 3, 3, 3, 3 }, // 3 - { 4, 4, 4, 4, 4, 4, 4, 4 }, // 4 - { 5, 5, 5, 5, 5, 5, 5, 5 }, // 5 - { 6, 6, 6, 6, 6, 6, 6, 6 }, // 6 - { 7, 7, 7, 7, 7, 7, 7, 7 }, // 7 -}; -#endif - -rsp_device::cop2::cop2(rsp_device &rsp, running_machine &machine) - : m_rsp(rsp) - , m_machine(machine) - , m_reciprocal_res(0) - , m_reciprocal_high(0) - , m_dp_allowed(0) -{ - memset(m_vres, 0, sizeof(m_vres)); - memset(m_v, 0, sizeof(m_v)); - memset(m_vflag, 0, sizeof(m_vflag)); - memset(m_accum, 0, sizeof(m_accum)); -#if USE_SIMD - memset(&m_acc, 0, sizeof(m_acc)); - memset(&m_flags, 0, sizeof(aligned_rsp_2vect_t) * 3); - m_div_out = 0; - m_div_in = 0; -#endif - m_rspcop2_state = (internal_rspcop2_state *)rsp.m_cache.alloc_near(sizeof(internal_rspcop2_state)); -} - -rsp_device::cop2::~cop2() -{ -} - -void rsp_device::cop2::init() -{ - CLEAR_CARRY_FLAGS(); - CLEAR_COMPARE_FLAGS(); - CLEAR_CLIP1_FLAGS(); - CLEAR_ZERO_FLAGS(); - CLEAR_CLIP2_FLAGS(); -} - -void rsp_device::cop2::start() -{ - for(auto & elem : m_v) - { - elem.d[0] = 0; - elem.d[1] = 0; - } - - CLEAR_CARRY_FLAGS(); - CLEAR_COMPARE_FLAGS(); - CLEAR_CLIP1_FLAGS(); - CLEAR_ZERO_FLAGS(); - CLEAR_CLIP2_FLAGS(); - m_reciprocal_res = 0; - m_reciprocal_high = 0; - - // Accumulators do not power on to a random state - for(auto & elem : m_accum) - { - elem.q = 0; - } -} - -void rsp_device::cop2::state_string_export(const int index, std::string &str) const -{ - switch (index) - { - case RSP_V0: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S( 0, 0), (uint16_t)VREG_S( 0, 1), (uint16_t)VREG_S( 0, 2), (uint16_t)VREG_S( 0, 3), (uint16_t)VREG_S( 0, 4), (uint16_t)VREG_S( 0, 5), (uint16_t)VREG_S( 0, 6), (uint16_t)VREG_S( 0, 7)); - break; - case RSP_V1: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S( 1, 0), (uint16_t)VREG_S( 1, 1), (uint16_t)VREG_S( 1, 2), (uint16_t)VREG_S( 1, 3), (uint16_t)VREG_S( 1, 4), (uint16_t)VREG_S( 1, 5), (uint16_t)VREG_S( 1, 6), (uint16_t)VREG_S( 1, 7)); - break; - case RSP_V2: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S( 2, 0), (uint16_t)VREG_S( 2, 1), (uint16_t)VREG_S( 2, 2), (uint16_t)VREG_S( 2, 3), (uint16_t)VREG_S( 2, 4), (uint16_t)VREG_S( 2, 5), (uint16_t)VREG_S( 2, 6), (uint16_t)VREG_S( 2, 7)); - break; - case RSP_V3: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S( 3, 0), (uint16_t)VREG_S( 3, 1), (uint16_t)VREG_S( 3, 2), (uint16_t)VREG_S( 3, 3), (uint16_t)VREG_S( 3, 4), (uint16_t)VREG_S( 3, 5), (uint16_t)VREG_S( 3, 6), (uint16_t)VREG_S( 3, 7)); - break; - case RSP_V4: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S( 4, 0), (uint16_t)VREG_S( 4, 1), (uint16_t)VREG_S( 4, 2), (uint16_t)VREG_S( 4, 3), (uint16_t)VREG_S( 4, 4), (uint16_t)VREG_S( 4, 5), (uint16_t)VREG_S( 4, 6), (uint16_t)VREG_S( 4, 7)); - break; - case RSP_V5: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S( 5, 0), (uint16_t)VREG_S( 5, 1), (uint16_t)VREG_S( 5, 2), (uint16_t)VREG_S( 5, 3), (uint16_t)VREG_S( 5, 4), (uint16_t)VREG_S( 5, 5), (uint16_t)VREG_S( 5, 6), (uint16_t)VREG_S( 5, 7)); - break; - case RSP_V6: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S( 6, 0), (uint16_t)VREG_S( 6, 1), (uint16_t)VREG_S( 6, 2), (uint16_t)VREG_S( 6, 3), (uint16_t)VREG_S( 6, 4), (uint16_t)VREG_S( 6, 5), (uint16_t)VREG_S( 6, 6), (uint16_t)VREG_S( 6, 7)); - break; - case RSP_V7: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S( 7, 0), (uint16_t)VREG_S( 7, 1), (uint16_t)VREG_S( 7, 2), (uint16_t)VREG_S( 7, 3), (uint16_t)VREG_S( 7, 4), (uint16_t)VREG_S( 7, 5), (uint16_t)VREG_S( 7, 6), (uint16_t)VREG_S( 7, 7)); - break; - case RSP_V8: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S( 8, 0), (uint16_t)VREG_S( 8, 1), (uint16_t)VREG_S( 8, 2), (uint16_t)VREG_S( 8, 3), (uint16_t)VREG_S( 8, 4), (uint16_t)VREG_S( 8, 5), (uint16_t)VREG_S( 8, 6), (uint16_t)VREG_S( 8, 7)); - break; - case RSP_V9: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S( 9, 0), (uint16_t)VREG_S( 9, 1), (uint16_t)VREG_S( 9, 2), (uint16_t)VREG_S( 9, 3), (uint16_t)VREG_S( 9, 4), (uint16_t)VREG_S( 9, 5), (uint16_t)VREG_S( 9, 6), (uint16_t)VREG_S( 9, 7)); - break; - case RSP_V10: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(10, 0), (uint16_t)VREG_S(10, 1), (uint16_t)VREG_S(10, 2), (uint16_t)VREG_S(10, 3), (uint16_t)VREG_S(10, 4), (uint16_t)VREG_S(10, 5), (uint16_t)VREG_S(10, 6), (uint16_t)VREG_S(10, 7)); - break; - case RSP_V11: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(11, 0), (uint16_t)VREG_S(11, 1), (uint16_t)VREG_S(11, 2), (uint16_t)VREG_S(11, 3), (uint16_t)VREG_S(11, 4), (uint16_t)VREG_S(11, 5), (uint16_t)VREG_S(11, 6), (uint16_t)VREG_S(11, 7)); - break; - case RSP_V12: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(12, 0), (uint16_t)VREG_S(12, 1), (uint16_t)VREG_S(12, 2), (uint16_t)VREG_S(12, 3), (uint16_t)VREG_S(12, 4), (uint16_t)VREG_S(12, 5), (uint16_t)VREG_S(12, 6), (uint16_t)VREG_S(12, 7)); - break; - case RSP_V13: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(13, 0), (uint16_t)VREG_S(13, 1), (uint16_t)VREG_S(13, 2), (uint16_t)VREG_S(13, 3), (uint16_t)VREG_S(13, 4), (uint16_t)VREG_S(13, 5), (uint16_t)VREG_S(13, 6), (uint16_t)VREG_S(13, 7)); - break; - case RSP_V14: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(14, 0), (uint16_t)VREG_S(14, 1), (uint16_t)VREG_S(14, 2), (uint16_t)VREG_S(14, 3), (uint16_t)VREG_S(14, 4), (uint16_t)VREG_S(14, 5), (uint16_t)VREG_S(14, 6), (uint16_t)VREG_S(14, 7)); - break; - case RSP_V15: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(15, 0), (uint16_t)VREG_S(15, 1), (uint16_t)VREG_S(15, 2), (uint16_t)VREG_S(15, 3), (uint16_t)VREG_S(15, 4), (uint16_t)VREG_S(15, 5), (uint16_t)VREG_S(15, 6), (uint16_t)VREG_S(15, 7)); - break; - case RSP_V16: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(16, 0), (uint16_t)VREG_S(16, 1), (uint16_t)VREG_S(16, 2), (uint16_t)VREG_S(16, 3), (uint16_t)VREG_S(16, 4), (uint16_t)VREG_S(16, 5), (uint16_t)VREG_S(16, 6), (uint16_t)VREG_S(16, 7)); - break; - case RSP_V17: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(17, 0), (uint16_t)VREG_S(17, 1), (uint16_t)VREG_S(17, 2), (uint16_t)VREG_S(17, 3), (uint16_t)VREG_S(17, 4), (uint16_t)VREG_S(17, 5), (uint16_t)VREG_S(17, 6), (uint16_t)VREG_S(17, 7)); - break; - case RSP_V18: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(18, 0), (uint16_t)VREG_S(18, 1), (uint16_t)VREG_S(18, 2), (uint16_t)VREG_S(18, 3), (uint16_t)VREG_S(18, 4), (uint16_t)VREG_S(18, 5), (uint16_t)VREG_S(18, 6), (uint16_t)VREG_S(18, 7)); - break; - case RSP_V19: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(19, 0), (uint16_t)VREG_S(19, 1), (uint16_t)VREG_S(19, 2), (uint16_t)VREG_S(19, 3), (uint16_t)VREG_S(19, 4), (uint16_t)VREG_S(19, 5), (uint16_t)VREG_S(19, 6), (uint16_t)VREG_S(19, 7)); - break; - case RSP_V20: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(20, 0), (uint16_t)VREG_S(20, 1), (uint16_t)VREG_S(20, 2), (uint16_t)VREG_S(20, 3), (uint16_t)VREG_S(20, 4), (uint16_t)VREG_S(20, 5), (uint16_t)VREG_S(20, 6), (uint16_t)VREG_S(20, 7)); - break; - case RSP_V21: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(21, 0), (uint16_t)VREG_S(21, 1), (uint16_t)VREG_S(21, 2), (uint16_t)VREG_S(21, 3), (uint16_t)VREG_S(21, 4), (uint16_t)VREG_S(21, 5), (uint16_t)VREG_S(21, 6), (uint16_t)VREG_S(21, 7)); - break; - case RSP_V22: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(22, 0), (uint16_t)VREG_S(22, 1), (uint16_t)VREG_S(22, 2), (uint16_t)VREG_S(22, 3), (uint16_t)VREG_S(22, 4), (uint16_t)VREG_S(22, 5), (uint16_t)VREG_S(22, 6), (uint16_t)VREG_S(22, 7)); - break; - case RSP_V23: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(23, 0), (uint16_t)VREG_S(23, 1), (uint16_t)VREG_S(23, 2), (uint16_t)VREG_S(23, 3), (uint16_t)VREG_S(23, 4), (uint16_t)VREG_S(23, 5), (uint16_t)VREG_S(23, 6), (uint16_t)VREG_S(23, 7)); - break; - case RSP_V24: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(24, 0), (uint16_t)VREG_S(24, 1), (uint16_t)VREG_S(24, 2), (uint16_t)VREG_S(24, 3), (uint16_t)VREG_S(24, 4), (uint16_t)VREG_S(24, 5), (uint16_t)VREG_S(24, 6), (uint16_t)VREG_S(24, 7)); - break; - case RSP_V25: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(25, 0), (uint16_t)VREG_S(25, 1), (uint16_t)VREG_S(25, 2), (uint16_t)VREG_S(25, 3), (uint16_t)VREG_S(25, 4), (uint16_t)VREG_S(25, 5), (uint16_t)VREG_S(25, 6), (uint16_t)VREG_S(25, 7)); - break; - case RSP_V26: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(26, 0), (uint16_t)VREG_S(26, 1), (uint16_t)VREG_S(26, 2), (uint16_t)VREG_S(26, 3), (uint16_t)VREG_S(26, 4), (uint16_t)VREG_S(26, 5), (uint16_t)VREG_S(26, 6), (uint16_t)VREG_S(26, 7)); - break; - case RSP_V27: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(27, 0), (uint16_t)VREG_S(27, 1), (uint16_t)VREG_S(27, 2), (uint16_t)VREG_S(27, 3), (uint16_t)VREG_S(27, 4), (uint16_t)VREG_S(27, 5), (uint16_t)VREG_S(27, 6), (uint16_t)VREG_S(27, 7)); - break; - case RSP_V28: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(28, 0), (uint16_t)VREG_S(28, 1), (uint16_t)VREG_S(28, 2), (uint16_t)VREG_S(28, 3), (uint16_t)VREG_S(28, 4), (uint16_t)VREG_S(28, 5), (uint16_t)VREG_S(28, 6), (uint16_t)VREG_S(28, 7)); - break; - case RSP_V29: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(29, 0), (uint16_t)VREG_S(29, 1), (uint16_t)VREG_S(29, 2), (uint16_t)VREG_S(29, 3), (uint16_t)VREG_S(29, 4), (uint16_t)VREG_S(29, 5), (uint16_t)VREG_S(29, 6), (uint16_t)VREG_S(29, 7)); - break; - case RSP_V30: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(30, 0), (uint16_t)VREG_S(30, 1), (uint16_t)VREG_S(30, 2), (uint16_t)VREG_S(30, 3), (uint16_t)VREG_S(30, 4), (uint16_t)VREG_S(30, 5), (uint16_t)VREG_S(30, 6), (uint16_t)VREG_S(30, 7)); - break; - case RSP_V31: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(31, 0), (uint16_t)VREG_S(31, 1), (uint16_t)VREG_S(31, 2), (uint16_t)VREG_S(31, 3), (uint16_t)VREG_S(31, 4), (uint16_t)VREG_S(31, 5), (uint16_t)VREG_S(31, 6), (uint16_t)VREG_S(31, 7)); - break; - } -} - -/*************************************************************************** - Vector Load Instructions -***************************************************************************/ - -void rsp_device::cop2::handle_lwc2(uint32_t op) -{ - int base = (op >> 21) & 0x1f; -#if !USE_SIMD - int i, end; - uint32_t ea; - int dest = (op >> 16) & 0x1f; - int index = (op >> 7) & 0xf; - int offset = (op & 0x7f); - if (offset & 0x40) - offset |= 0xffffffc0; -#endif - - switch ((op >> 11) & 0x1f) - { - case 0x00: /* LBV */ - { - // 31 25 20 15 10 6 0 - // -------------------------------------------------- - // | 110010 | BBBBB | TTTTT | 00000 | IIII | Offset | - // -------------------------------------------------- - // - // Load 1 byte to vector byte index - - //printf("LBV "); -#if USE_SIMD - vec_lbdlsv_sbdlsv(op, m_rsp.m_rsp_state->r[base]); -#else - ea = (base) ? m_rsp.m_rsp_state->r[base] + offset : offset; - VREG_B(dest, index) = m_rsp.READ8(ea); -#endif - // - break; - } - case 0x01: /* LSV */ - { - // 31 25 20 15 10 6 0 - // -------------------------------------------------- - // | 110010 | BBBBB | TTTTT | 00001 | IIII | Offset | - // -------------------------------------------------- - // - // Loads 2 bytes starting from vector byte index - - //printf("LSV "); -#if USE_SIMD - vec_lbdlsv_sbdlsv(op, m_rsp.m_rsp_state->r[base]); -#else - ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 2) : (offset * 2); - - end = index + 2; - - for (i=index; i < end; i++) - { - VREG_B(dest, i) = m_rsp.READ8(ea); - ea++; - } -#endif - // - break; - } - case 0x02: /* LLV */ - { - // 31 25 20 15 10 6 0 - // -------------------------------------------------- - // | 110010 | BBBBB | TTTTT | 00010 | IIII | Offset | - // -------------------------------------------------- - // - // Loads 4 bytes starting from vector byte index - - //printf("LLV "); -#if USE_SIMD - vec_lbdlsv_sbdlsv(op, m_rsp.m_rsp_state->r[base]); -#else - ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 4) : (offset * 4); - - end = index + 4; - - for (i=index; i < end; i++) - { - VREG_B(dest, i) = m_rsp.READ8(ea); - ea++; - } -#endif - // - break; - } - case 0x03: /* LDV */ - { - // 31 25 20 15 10 6 0 - // -------------------------------------------------- - // | 110010 | BBBBB | TTTTT | 00011 | IIII | Offset | - // -------------------------------------------------- - // - // Loads 8 bytes starting from vector byte index - - //printf("LDV "); -#if USE_SIMD - vec_lbdlsv_sbdlsv(op, m_rsp.m_rsp_state->r[base]); -#else - ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); - - end = index + 8; - - for (i=index; i < end; i++) - { - VREG_B(dest, i) = m_rsp.READ8(ea); - ea++; - } -#endif - // - break; - } - case 0x04: /* LQV */ - { - // 31 25 20 15 10 6 0 - // -------------------------------------------------- - // | 110010 | BBBBB | TTTTT | 00100 | IIII | Offset | - // -------------------------------------------------- - // - // Loads up to 16 bytes starting from vector byte index - - //printf("LQV "); -#if USE_SIMD - vec_lqrv_sqrv(op, m_rsp.m_rsp_state->r[base]); -#else - ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); - - end = index + (16 - (ea & 0xf)); - if (end > 16) end = 16; - - for (i=index; i < end; i++) - { - VREG_B(dest, i) = m_rsp.READ8(ea); - ea++; - } -#endif - // - break; - } - case 0x05: /* LRV */ - { - // 31 25 20 15 10 6 0 - // -------------------------------------------------- - // | 110010 | BBBBB | TTTTT | 00101 | IIII | Offset | - // -------------------------------------------------- - // - // Stores up to 16 bytes starting from right side until 16-byte boundary - - //printf("LRV "); -#if USE_SIMD - vec_lqrv_sqrv(op, m_rsp.m_rsp_state->r[base]); -#else - ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); - - index = 16 - ((ea & 0xf) - index); - end = 16; - ea &= ~0xf; - - for (i=index; i < end; i++) - { - VREG_B(dest, i) = m_rsp.READ8(ea); - ea++; - } -#endif - // - break; - } - case 0x06: /* LPV */ - { - // 31 25 20 15 10 6 0 - // -------------------------------------------------- - // | 110010 | BBBBB | TTTTT | 00110 | IIII | Offset | - // -------------------------------------------------- - // - // Loads a byte as the upper 8 bits of each element - - //printf("LPV "); -#if USE_SIMD - vec_lfhpuv_sfhpuv(op, m_rsp.m_rsp_state->r[base]); -#else - ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); - - for (i=0; i < 8; i++) - { - VREG_S(dest, i) = m_rsp.READ8(ea + (((16-index) + i) & 0xf)) << 8; - } -#endif - // - break; - } - case 0x07: /* LUV */ - { - // 31 25 20 15 10 6 0 - // -------------------------------------------------- - // | 110010 | BBBBB | TTTTT | 00111 | IIII | Offset | - // -------------------------------------------------- - // - // Loads a byte as the bits 14-7 of each element - - //printf("LUV "); -#if USE_SIMD - vec_lfhpuv_sfhpuv(op, m_rsp.m_rsp_state->r[base]); -#else - ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); - - for (i=0; i < 8; i++) - { - VREG_S(dest, i) = m_rsp.READ8(ea + (((16-index) + i) & 0xf)) << 7; - } -#endif - // - break; - } - case 0x08: /* LHV */ - { - // 31 25 20 15 10 6 0 - // -------------------------------------------------- - // | 110010 | BBBBB | TTTTT | 01000 | IIII | Offset | - // -------------------------------------------------- - // - // Loads a byte as the bits 14-7 of each element, with 2-byte stride - - //printf("LHV "); -#if USE_SIMD - vec_lfhpuv_sfhpuv(op, m_rsp.m_rsp_state->r[base]); -#else - ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); - - for (i=0; i < 8; i++) - { - VREG_S(dest, i) = m_rsp.READ8(ea + (((16-index) + (i<<1)) & 0xf)) << 7; - } -#endif - // - break; - } - case 0x09: /* LFV */ - { - // 31 25 20 15 10 6 0 - // -------------------------------------------------- - // | 110010 | BBBBB | TTTTT | 01001 | IIII | Offset | - // -------------------------------------------------- - // - // Loads a byte as the bits 14-7 of upper or lower quad, with 4-byte stride - - //printf("LFV "); -#if USE_SIMD - vec_lfhpuv_sfhpuv(op, m_rsp.m_rsp_state->r[base]); -#else - ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); - - // not sure what happens if 16-byte boundary is crossed... - - end = (index >> 1) + 4; - - for (i=index >> 1; i < end; i++) - { - VREG_S(dest, i) = m_rsp.READ8(ea) << 7; - ea += 4; - } -#endif - // - break; - } - case 0x0a: /* LWV */ - { - // 31 25 20 15 10 6 0 - // -------------------------------------------------- - // | 110010 | BBBBB | TTTTT | 01010 | IIII | Offset | - // -------------------------------------------------- - // - // Loads the full 128-bit vector starting from vector byte index and wrapping to index 0 - // after byte index 15 - - //printf("LWV "); -#if USE_SIMD -#else - ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); - - end = (16 - index) + 16; - - for (i=(16 - index); i < end; i++) - { - VREG_B(dest, i & 0xf) = m_rsp.READ8(ea); - ea += 4; - } -#endif - // - break; - } - case 0x0b: /* LTV */ - { - // 31 25 20 15 10 6 0 - // -------------------------------------------------- - // | 110010 | BBBBB | TTTTT | 01011 | IIII | Offset | - // -------------------------------------------------- - // - // Loads one element to maximum of 8 vectors, while incrementing element index - - // FIXME: has a small problem with odd indices - - //printf("LTV "); -#if 0 -#else - int32_t index = (op >> 7) & 0xf; - int32_t offset = (op & 0x7f); - if (offset & 0x40) - offset |= 0xffffffc0; - - int32_t vs = (op >> 16) & 0x1f; - int32_t ve = vs + 8; - if (ve > 32) - ve = 32; - - int32_t element; - - if (index & 1) fatalerror("RSP: LTV: index = %d\n", index); - - uint32_t ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); - - ea = ((ea + 8) & ~0xf) + (index & 1); - for (int32_t i = vs; i < ve; i++) - { - element = ((8 - (index >> 1) + (i-vs)) << 1); - VREG_B(i, (element & 0xf)) = m_rsp.READ8(ea); - VREG_B(i, ((element + 1) & 0xf)) = m_rsp.READ8(ea + 1); - - ea += 2; - } -#endif - // - break; - } - - default: - { - m_rsp.unimplemented_opcode(op); - break; - } - } -} - - -/*************************************************************************** - Vector Store Instructions -***************************************************************************/ - -void rsp_device::cop2::handle_swc2(uint32_t op) -{ - int base = (op >> 21) & 0x1f; -#if !USE_SIMD - int i, end; - int eaoffset; - uint32_t ea; - int dest = (op >> 16) & 0x1f; - int index = (op >> 7) & 0xf; - int offset = (op & 0x7f); - if (offset & 0x40) - offset |= 0xffffffc0; -#endif - - switch ((op >> 11) & 0x1f) - { - case 0x00: /* SBV */ - { - // 31 25 20 15 10 6 0 - // -------------------------------------------------- - // | 111010 | BBBBB | TTTTT | 00000 | IIII | Offset | - // -------------------------------------------------- - // - // Stores 1 byte from vector byte index - - //printf("SBV "); -#if USE_SIMD - vec_lbdlsv_sbdlsv(op, m_rsp.m_rsp_state->r[base]); -#else - ea = (base) ? m_rsp.m_rsp_state->r[base] + offset : offset; - m_rsp.WRITE8(ea, VREG_B(dest, index)); -#endif - // - break; - } - case 0x01: /* SSV */ - { - // 31 25 20 15 10 6 0 - // -------------------------------------------------- - // | 111010 | BBBBB | TTTTT | 00001 | IIII | Offset | - // -------------------------------------------------- - // - // Stores 2 bytes starting from vector byte index - - //printf("SSV "); -#if USE_SIMD - vec_lbdlsv_sbdlsv(op, m_rsp.m_rsp_state->r[base]); -#else - ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 2) : (offset * 2); - - end = index + 2; - - for (i=index; i < end; i++) - { - m_rsp.WRITE8(ea, VREG_B(dest, i)); - ea++; - } -#endif - // - break; - } - case 0x02: /* SLV */ - { - // 31 25 20 15 10 6 0 - // -------------------------------------------------- - // | 111010 | BBBBB | TTTTT | 00010 | IIII | Offset | - // -------------------------------------------------- - // - // Stores 4 bytes starting from vector byte index - - //printf("SLV "); -#if USE_SIMD - vec_lbdlsv_sbdlsv(op, m_rsp.m_rsp_state->r[base]); -#else - ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 4) : (offset * 4); - - end = index + 4; - - for (i=index; i < end; i++) - { - m_rsp.WRITE8(ea, VREG_B(dest, i)); - ea++; - } -#endif - // - break; - } - case 0x03: /* SDV */ - { - // 31 25 20 15 10 6 0 - // -------------------------------------------------- - // | 111010 | BBBBB | TTTTT | 00011 | IIII | Offset | - // -------------------------------------------------- - // - // Stores 8 bytes starting from vector byte index - - //printf("SDV "); -#if USE_SIMD - vec_lbdlsv_sbdlsv(op, m_rsp.m_rsp_state->r[base]); -#else - ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); - - end = index + 8; - - for (i=index; i < end; i++) - { - m_rsp.WRITE8(ea, VREG_B(dest, i)); - ea++; - } -#endif - // - break; - } - case 0x04: /* SQV */ - { - // 31 25 20 15 10 6 0 - // -------------------------------------------------- - // | 111010 | BBBBB | TTTTT | 00100 | IIII | Offset | - // -------------------------------------------------- - // - // Stores up to 16 bytes starting from vector byte index until 16-byte boundary - - //printf("SQV "); -#if USE_SIMD - vec_lqrv_sqrv(op, m_rsp.m_rsp_state->r[base]); -#else - ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); - - end = index + (16 - (ea & 0xf)); - - for (i=index; i < end; i++) - { - m_rsp.WRITE8(ea, VREG_B(dest, i & 0xf)); - ea++; - } -#endif - // - break; - } - case 0x05: /* SRV */ - { - // 31 25 20 15 10 6 0 - // -------------------------------------------------- - // | 111010 | BBBBB | TTTTT | 00101 | IIII | Offset | - // -------------------------------------------------- - // - // Stores up to 16 bytes starting from right side until 16-byte boundary - - //printf("SRV "); -#if USE_SIMD - vec_lqrv_sqrv(op, m_rsp.m_rsp_state->r[base]); -#else - int o; - ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); - - end = index + (ea & 0xf); - o = (16 - (ea & 0xf)) & 0xf; - ea &= ~0xf; - - for (i=index; i < end; i++) - { - m_rsp.WRITE8(ea, VREG_B(dest, ((i + o) & 0xf))); - ea++; - } -#endif - // - break; - } - case 0x06: /* SPV */ - { - // 31 25 20 15 10 6 0 - // -------------------------------------------------- - // | 111010 | BBBBB | TTTTT | 00110 | IIII | Offset | - // -------------------------------------------------- - // - // Stores upper 8 bits of each element - - //printf("SPV "); -#if USE_SIMD - vec_lfhpuv_sfhpuv(op, m_rsp.m_rsp_state->r[base]); -#else - ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); - end = index + 8; - - for (i=index; i < end; i++) - { - if ((i & 0xf) < 8) - { - m_rsp.WRITE8(ea, VREG_B(dest, ((i & 0xf) << 1))); - } - else - { - m_rsp.WRITE8(ea, VREG_S(dest, (i & 0x7)) >> 7); - } - ea++; - } -#endif - // - break; - } - case 0x07: /* SUV */ - { - // 31 25 20 15 10 6 0 - // -------------------------------------------------- - // | 111010 | BBBBB | TTTTT | 00111 | IIII | Offset | - // -------------------------------------------------- - // - // Stores bits 14-7 of each element - - //printf("SUV "); -#if USE_SIMD - vec_lfhpuv_sfhpuv(op, m_rsp.m_rsp_state->r[base]); -#else - ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); - end = index + 8; - - for (i=index; i < end; i++) - { - if ((i & 0xf) < 8) - { - m_rsp.WRITE8(ea, VREG_S(dest, (i & 0x7)) >> 7); - } - else - { - m_rsp.WRITE8(ea, VREG_B(dest, ((i & 0x7) << 1))); - } - ea++; - } -#endif - // - break; - } - case 0x08: /* SHV */ - { - // 31 25 20 15 10 6 0 - // -------------------------------------------------- - // | 111010 | BBBBB | TTTTT | 01000 | IIII | Offset | - // -------------------------------------------------- - // - // Stores bits 14-7 of each element, with 2-byte stride - - //printf("SHV "); -#if USE_SIMD - vec_lfhpuv_sfhpuv(op, m_rsp.m_rsp_state->r[base]); -#else - ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); - - for (i=0; i < 8; i++) - { - uint8_t d = ((VREG_B(dest, ((index + (i << 1) + 0) & 0xf))) << 1) | - ((VREG_B(dest, ((index + (i << 1) + 1) & 0xf))) >> 7); - - m_rsp.WRITE8(ea, d); - ea += 2; - } -#endif - // - break; - } - case 0x09: /* SFV */ - { - // 31 25 20 15 10 6 0 - // -------------------------------------------------- - // | 111010 | BBBBB | TTTTT | 01001 | IIII | Offset | - // -------------------------------------------------- - // - // Stores bits 14-7 of upper or lower quad, with 4-byte stride - - // FIXME: only works for index 0 and index 8 - - //printf("SFV "); -#if USE_SIMD - vec_lfhpuv_sfhpuv(op, m_rsp.m_rsp_state->r[base]); -#else - ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); - - eaoffset = ea & 0xf; - ea &= ~0xf; - - end = (index >> 1) + 4; - - for (i=index >> 1; i < end; i++) - { - m_rsp.WRITE8(ea + (eaoffset & 0xf), VREG_S(dest, i) >> 7); - eaoffset += 4; - } -#endif - // - break; - } - case 0x0a: /* SWV */ - { - // 31 25 20 15 10 6 0 - // -------------------------------------------------- - // | 111010 | BBBBB | TTTTT | 01010 | IIII | Offset | - // -------------------------------------------------- - // - // Stores the full 128-bit vector starting from vector byte index and wrapping to index 0 - // after byte index 15 - - //printf("SWV "); -#if USE_SIMD -#else - ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); - - eaoffset = ea & 0xf; - ea &= ~0xf; - - end = index + 16; - - for (i=index; i < end; i++) - { - m_rsp.WRITE8(ea + (eaoffset & 0xf), VREG_B(dest, i & 0xf)); - eaoffset++; - } -#endif - // - break; - } - case 0x0b: /* STV */ - { - // 31 25 20 15 10 6 0 - // -------------------------------------------------- - // | 111010 | BBBBB | TTTTT | 01011 | IIII | Offset | - // -------------------------------------------------- - // - // Stores one element from maximum of 8 vectors, while incrementing element index - - //printf("STV "); -#if 0 -#else - int32_t index = (op >> 7) & 0xf; - int32_t offset = (op & 0x7f); - if (offset & 0x40) - offset |= 0xffffffc0; - - int32_t vs = (op >> 16) & 0x1f; - int32_t ve = vs + 8; - if (ve > 32) - ve = 32; - - int32_t element = 8 - (index >> 1); - - uint32_t ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); - - int32_t eaoffset = (ea & 0xf) + (element * 2); - ea &= ~0xf; - - for (int32_t i = vs; i < ve; i++) - { - m_rsp.WRITE16(ea + (eaoffset & 0xf), VREG_S(i, element & 0x7)); - eaoffset += 2; - element++; - } -#endif - // - break; - } - - default: - { - m_rsp.unimplemented_opcode(op); - break; - } - } -} - -/*************************************************************************** - Vector Accumulator Helpers -***************************************************************************/ - -uint16_t rsp_device::cop2::SATURATE_ACCUM(int accum, int slice, uint16_t negative, uint16_t positive) -{ - if ((int16_t)ACCUM_H(accum) < 0) - { - if ((uint16_t)(ACCUM_H(accum)) != 0xffff) - { - return negative; - } - else - { - if ((int16_t)ACCUM_M(accum) >= 0) - { - return negative; - } - else - { - if (slice == 0) - { - return ACCUM_L(accum); - } - else if (slice == 1) - { - return ACCUM_M(accum); - } - } - } - } - else - { - if ((uint16_t)(ACCUM_H(accum)) != 0) - { - return positive; - } - else - { - if ((int16_t)ACCUM_M(accum) < 0) - { - return positive; - } - else - { - if (slice == 0) - { - return ACCUM_L(accum); - } - else - { - return ACCUM_M(accum); - } - } - } - } - return 0; -} - - -/*************************************************************************** - Vector Opcodes -***************************************************************************/ - -void rsp_device::cop2::handle_vector_ops(uint32_t op) -{ -#if !USE_SIMD - int i; -#endif - - // Opcode legend: - // E = VS2 element type - // S = VS1, Source vector 1 - // T = VS2, Source vector 2 - // D = Destination vector - - switch (op & 0x3f) - { - case 0x00: /* VMULF */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000000 | - // ------------------------------------------------------ - // - // Multiplies signed integer by signed integer * 2 - - //printf("MULF "); -#if USE_SIMD - uint16_t *acc = m_acc.s; - rsp_vec_t acc_lo, acc_mid, acc_hi; - - rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); - rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); - - m_v[VDREG].v = vec_vmulf_vmulu(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); - - write_acc_lo(acc, acc_lo); - write_acc_mid(acc, acc_mid); - write_acc_hi(acc, acc_hi); -#else - for (i=0; i < 8; i++) - { - int32_t s1 = (int32_t)(int16_t)VREG_S(VS1REG, i); - int32_t s2 = (int32_t)(int16_t)VREG_S(VS2REG, VEC_EL_2(EL, i)); - - if (s1 == -32768 && s2 == -32768) - { - // overflow - SET_ACCUM_H(0, i); - SET_ACCUM_M(-32768, i); - SET_ACCUM_L(-32768, i); - m_vres[i] = 0x7fff; - } - else - { - int64_t r = s1 * s2 * 2; - r += 0x8000; // rounding ? - SET_ACCUM_H((r < 0) ? 0xffff : 0, i); // sign-extend to 48-bit - SET_ACCUM_M((int16_t)(r >> 16), i); - SET_ACCUM_L((uint16_t)(r), i); - m_vres[i] = ACCUM_M(i); - } - } - WRITEBACK_RESULT(); -#endif - // - break; - - } - - case 0x01: /* VMULU */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000001 | - // ------------------------------------------------------ - // - - //printf("MULU "); -#if USE_SIMD - uint16_t *acc = m_acc.s; - rsp_vec_t acc_lo, acc_mid, acc_hi; - - rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); - rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); - - m_v[VDREG].v = vec_vmulf_vmulu(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); - - write_acc_lo(acc, acc_lo); - write_acc_mid(acc, acc_mid); - write_acc_hi(acc, acc_hi); -#else - for (i=0; i < 8; i++) - { - int32_t s1 = (int32_t)(int16_t)VREG_S(VS1REG, i); - int32_t s2 = (int32_t)(int16_t)VREG_S(VS2REG, VEC_EL_2(EL, i)); - - int64_t r = s1 * s2 * 2; - r += 0x8000; // rounding ? - - SET_ACCUM_H((uint16_t)(r >> 32), i); - SET_ACCUM_M((uint16_t)(r >> 16), i); - SET_ACCUM_L((uint16_t)(r), i); - - if (r < 0) - { - m_vres[i] = 0; - } - else if (((int16_t)(ACCUM_H(i)) ^ (int16_t)(ACCUM_M(i))) < 0) - { - m_vres[i] = -1; - } - else - { - m_vres[i] = ACCUM_M(i); - } - } - WRITEBACK_RESULT(); -#endif - // - break; - } - - case 0x04: /* VMUDL */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000100 | - // ------------------------------------------------------ - // - // Multiplies unsigned fraction by unsigned fraction - // Stores the higher 16 bits of the 32-bit result to accumulator - // The low slice of accumulator is stored into destination element - - //printf("MUDL "); -#if USE_SIMD - uint16_t *acc = m_acc.s; - rsp_vec_t acc_lo, acc_mid, acc_hi; - - acc_lo = read_acc_lo(acc); - acc_mid = read_acc_mid(acc); - acc_hi = read_acc_hi(acc); - - rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); - rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); - - m_v[VDREG].v = vec_vmadl_vmudl(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); - - write_acc_lo(acc, acc_lo); - write_acc_mid(acc, acc_mid); - write_acc_hi(acc, acc_hi); -#else - for (i=0; i < 8; i++) - { - uint32_t s1 = (uint32_t)(uint16_t)VREG_S(VS1REG, i); - uint32_t s2 = (uint32_t)(uint16_t)VREG_S(VS2REG, VEC_EL_2(EL, i)); - uint32_t r = s1 * s2; - - SET_ACCUM_H(0, i); - SET_ACCUM_M(0, i); - SET_ACCUM_L((uint16_t)(r >> 16), i); - - m_vres[i] = ACCUM_L(i); - } - WRITEBACK_RESULT(); -#endif - // - break; - } - - case 0x05: /* VMUDM */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000101 | - // ------------------------------------------------------ - // - // Multiplies signed integer by unsigned fraction - // The result is stored into accumulator - // The middle slice of accumulator is stored into destination element - - //printf("MUDM "); -#if USE_SIMD - uint16_t *acc = m_acc.s; - rsp_vec_t acc_lo, acc_mid, acc_hi; - - acc_lo = read_acc_lo(acc); - acc_mid = read_acc_mid(acc); - acc_hi = read_acc_hi(acc); - - rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); - rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); - - m_v[VDREG].v = vec_vmadm_vmudm(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); - - write_acc_lo(acc, acc_lo); - write_acc_mid(acc, acc_mid); - write_acc_hi(acc, acc_hi); -#else - for (i=0; i < 8; i++) - { - int32_t s1 = (int32_t)(int16_t)VREG_S(VS1REG, i); - int32_t s2 = (uint16_t)VREG_S(VS2REG, VEC_EL_2(EL, i)); // not sign-extended - int32_t r = s1 * s2; - - SET_ACCUM_H((r < 0) ? 0xffff : 0, i); // sign-extend to 48-bit - SET_ACCUM_M((int16_t)(r >> 16), i); - SET_ACCUM_L((uint16_t)(r), i); - - m_vres[i] = ACCUM_M(i); - } - WRITEBACK_RESULT(); -#endif - // - break; - - } - - case 0x06: /* VMUDN */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000110 | - // ------------------------------------------------------ - // - // Multiplies unsigned fraction by signed integer - // The result is stored into accumulator - // The low slice of accumulator is stored into destination element - - //printf("MUDN "); -#if USE_SIMD - uint16_t *acc = m_acc.s; - rsp_vec_t acc_lo = read_acc_lo(acc); - rsp_vec_t acc_mid = read_acc_mid(acc); - rsp_vec_t acc_hi = read_acc_hi(acc); - - rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); - rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); - - m_v[VDREG].v = vec_vmadn_vmudn(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); - - write_acc_lo(acc, acc_lo); - write_acc_mid(acc, acc_mid); - write_acc_hi(acc, acc_hi); -#else - for (i=0; i < 8; i++) - { - int32_t s1 = (uint16_t)VREG_S(VS1REG, i); // not sign-extended - int32_t s2 = (int32_t)(int16_t)VREG_S(VS2REG, VEC_EL_2(EL, i)); - int32_t r = s1 * s2; - - SET_ACCUM_H((r < 0) ? 0xffff : 0, i); // sign-extend to 48-bit - SET_ACCUM_M((int16_t)(r >> 16), i); - SET_ACCUM_L((uint16_t)(r), i); - - m_vres[i] = ACCUM_L(i); - } - WRITEBACK_RESULT(); -#endif - // - break; - } - - case 0x07: /* VMUDH */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000111 | - // ------------------------------------------------------ - // - // Multiplies signed integer by signed integer - // The result is stored into highest 32 bits of accumulator, the low slice is zero - // The highest 32 bits of accumulator is saturated into destination element - - //printf("MUDH "); -#if USE_SIMD - uint16_t *acc = m_acc.s; - rsp_vec_t acc_lo, acc_mid, acc_hi; - - acc_lo = read_acc_lo(acc); - acc_mid = read_acc_mid(acc); - acc_hi = read_acc_hi(acc); - - rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); - rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); - - m_v[VDREG].v = vec_vmadh_vmudh(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); - - write_acc_lo(acc, acc_lo); - write_acc_mid(acc, acc_mid); - write_acc_hi(acc, acc_hi); -#else - for (i=0; i < 8; i++) - { - int32_t s1 = (int32_t)(int16_t)VREG_S(VS1REG, i); - int32_t s2 = (int32_t)(int16_t)VREG_S(VS2REG, VEC_EL_2(EL, i)); - int32_t r = s1 * s2; - - SET_ACCUM_H((int16_t)(r >> 16), i); - SET_ACCUM_M((uint16_t)(r), i); - SET_ACCUM_L(0, i); - - if (r < -32768) r = -32768; - if (r > 32767) r = 32767; - m_vres[i] = (int16_t)(r); - } - WRITEBACK_RESULT(); -#endif - // - break; - } - - case 0x08: /* VMACF */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001000 | - // ------------------------------------------------------ - // - // Multiplies signed integer by signed integer * 2 - // The result is added to accumulator - - //printf("MACF "); -#if USE_SIMD - uint16_t *acc = m_acc.s; - rsp_vec_t acc_lo, acc_mid, acc_hi; - - acc_lo = read_acc_lo(acc); - acc_mid = read_acc_mid(acc); - acc_hi = read_acc_hi(acc); - - rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); - rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); - - m_v[VDREG].v = vec_vmacf_vmacu(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); - - write_acc_lo(acc, acc_lo); - write_acc_mid(acc, acc_mid); - write_acc_hi(acc, acc_hi); -#else - for (i=0; i < 8; i++) - { - int32_t s1 = (int32_t)(int16_t)VREG_S(VS1REG, i); - int32_t s2 = (int32_t)(int16_t)VREG_S(VS2REG, VEC_EL_2(EL, i)); - int32_t r = s1 * s2; - - uint64_t q = (uint64_t)(uint16_t)ACCUM_LL(i); - q |= (((uint64_t)(uint16_t)ACCUM_L(i)) << 16); - q |= (((uint64_t)(uint16_t)ACCUM_M(i)) << 32); - q |= (((uint64_t)(uint16_t)ACCUM_H(i)) << 48); - - q += (int64_t)(r) << 17; - - SET_ACCUM_LL((uint16_t)q, i); - SET_ACCUM_L((uint16_t)(q >> 16), i); - SET_ACCUM_M((uint16_t)(q >> 32), i); - SET_ACCUM_H((uint16_t)(q >> 48), i); - - m_vres[i] = SATURATE_ACCUM(i, 1, 0x8000, 0x7fff); - } - WRITEBACK_RESULT(); -#endif - // - break; - } - case 0x09: /* VMACU */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001001 | - // ------------------------------------------------------ - // - - //printf("MACU "); -#if USE_SIMD - uint16_t *acc = m_acc.s; - rsp_vec_t acc_lo, acc_mid, acc_hi; - - acc_lo = read_acc_lo(acc); - acc_mid = read_acc_mid(acc); - acc_hi = read_acc_hi(acc); - - rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); - rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); - - m_v[VDREG].v = vec_vmacf_vmacu(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); - - write_acc_lo(acc, acc_lo); - write_acc_mid(acc, acc_mid); - write_acc_hi(acc, acc_hi); -#else - for (i = 0; i < 8; i++) - { - int32_t s1 = (int32_t)(int16_t)VREG_S(VS1REG, i); - int32_t s2 = (int32_t)(int16_t)VREG_S(VS2REG, VEC_EL_2(EL, i)); - int32_t r1 = s1 * s2; - uint32_t r2 = (uint16_t)ACCUM_L(i) + ((uint16_t)(r1) * 2); - uint32_t r3 = (uint16_t)ACCUM_M(i) + (uint16_t)((r1 >> 16) * 2) + (uint16_t)(r2 >> 16); - - SET_ACCUM_L((uint16_t)(r2), i); - SET_ACCUM_M((uint16_t)(r3), i); - SET_ACCUM_H(ACCUM_H(i) + (uint16_t)(r3 >> 16) + (uint16_t)(r1 >> 31), i); - - if ((int16_t)ACCUM_H(i) < 0) - { - m_vres[i] = 0; - } - else - { - if (ACCUM_H(i) != 0) - { - m_vres[i] = 0xffff; - } - else - { - if ((int16_t)ACCUM_M(i) < 0) - { - m_vres[i] = 0xffff; - } - else - { - m_vres[i] = ACCUM_M(i); - } - } - } - } - WRITEBACK_RESULT(); -#endif - // - break; - } - - case 0x0c: /* VMADL */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001100 | - // ------------------------------------------------------ - // - // Multiplies unsigned fraction by unsigned fraction - // Adds the higher 16 bits of the 32-bit result to accumulator - // The low slice of accumulator is stored into destination element - - //printf("MADL "); -#if USE_SIMD - uint16_t *acc = m_acc.s; - rsp_vec_t acc_lo, acc_mid, acc_hi; - - acc_lo = read_acc_lo(acc); - acc_mid = read_acc_mid(acc); - acc_hi = read_acc_hi(acc); - - rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); - rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); - - m_v[VDREG].v = vec_vmadl_vmudl(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); - - write_acc_lo(acc, acc_lo); - write_acc_mid(acc, acc_mid); - write_acc_hi(acc, acc_hi); -#else - for (i = 0; i < 8; i++) - { - uint32_t s1 = (uint32_t)(uint16_t)VREG_S(VS1REG, i); - uint32_t s2 = (uint32_t)(uint16_t)VREG_S(VS2REG, VEC_EL_2(EL, i)); - uint32_t r1 = s1 * s2; - uint32_t r2 = (uint16_t)ACCUM_L(i) + (r1 >> 16); - uint32_t r3 = (uint16_t)ACCUM_M(i) + (r2 >> 16); - - SET_ACCUM_L((uint16_t)(r2), i); - SET_ACCUM_M((uint16_t)(r3), i); - SET_ACCUM_H(ACCUM_H(i) + (int16_t)(r3 >> 16), i); - - m_vres[i] = SATURATE_ACCUM(i, 0, 0x0000, 0xffff); - } - WRITEBACK_RESULT(); -#endif - // - break; - } - - case 0x0d: /* VMADM */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001101 | - // ------------------------------------------------------ - // - // Multiplies signed integer by unsigned fraction - // The result is added into accumulator - // The middle slice of accumulator is stored into destination element - - //printf("MADM "); -#if USE_SIMD - uint16_t *acc = m_acc.s; - rsp_vec_t acc_lo, acc_mid, acc_hi; - - acc_lo = read_acc_lo(acc); - acc_mid = read_acc_mid(acc); - acc_hi = read_acc_hi(acc); - - rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); - rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); - - m_v[VDREG].v = vec_vmadm_vmudm(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); - - write_acc_lo(acc, acc_lo); - write_acc_mid(acc, acc_mid); - write_acc_hi(acc, acc_hi); -#else - for (i=0; i < 8; i++) - { - uint32_t s1 = (int32_t)(int16_t)VREG_S(VS1REG, i); - uint32_t s2 = (uint16_t)VREG_S(VS2REG, VEC_EL_2(EL, i)); // not sign-extended - uint32_t r1 = s1 * s2; - uint32_t r2 = (uint16_t)ACCUM_L(i) + (uint16_t)(r1); - uint32_t r3 = (uint16_t)ACCUM_M(i) + (r1 >> 16) + (r2 >> 16); - - SET_ACCUM_L((uint16_t)(r2), i); - SET_ACCUM_M((uint16_t)(r3), i); - SET_ACCUM_H(ACCUM_H(i) + (uint16_t)(r3 >> 16), i); - if ((int32_t)(r1) < 0) - SET_ACCUM_H(ACCUM_H(i) - 1, i); - - m_vres[i] = SATURATE_ACCUM(i, 1, 0x8000, 0x7fff); - } - WRITEBACK_RESULT(); -#endif - // - break; - } - - case 0x0e: /* VMADN */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001110 | - // ------------------------------------------------------ - // - // Multiplies unsigned fraction by signed integer - // The result is added into accumulator - // The low slice of accumulator is stored into destination element - - //printf("MADN "); -#if USE_SIMD - uint16_t *acc = m_acc.s; - rsp_vec_t acc_lo, acc_mid, acc_hi; - - acc_lo = read_acc_lo(acc); - acc_mid = read_acc_mid(acc); - acc_hi = read_acc_hi(acc); - - rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); - rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); - - m_v[VDREG].v = vec_vmadn_vmudn(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); - - write_acc_lo(acc, acc_lo); - write_acc_mid(acc, acc_mid); - write_acc_hi(acc, acc_hi); -#else - for (i=0; i < 8; i++) - { - int32_t s1 = (uint16_t)VREG_S(VS1REG, i); // not sign-extended - int32_t s2 = (int32_t)(int16_t)VREG_S(VS2REG, VEC_EL_2(EL, i)); - - uint64_t q = (uint64_t)ACCUM_LL(i); - q |= (((uint64_t)ACCUM_L(i)) << 16); - q |= (((uint64_t)ACCUM_M(i)) << 32); - q |= (((uint64_t)ACCUM_H(i)) << 48); - q += (int64_t)(s1*s2) << 16; - - SET_ACCUM_LL((uint16_t)q, i); - SET_ACCUM_L((uint16_t)(q >> 16), i); - SET_ACCUM_M((uint16_t)(q >> 32), i); - SET_ACCUM_H((uint16_t)(q >> 48), i); - - m_vres[i] = SATURATE_ACCUM(i, 0, 0x0000, 0xffff); - } - WRITEBACK_RESULT(); - -#endif - // - break; - } - - case 0x0f: /* VMADH */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001111 | - // ------------------------------------------------------ - // - // Multiplies signed integer by signed integer - // The result is added into highest 32 bits of accumulator, the low slice is zero - // The highest 32 bits of accumulator is saturated into destination element - - //printf("MADH "); -#if USE_SIMD - uint16_t *acc = m_acc.s; - rsp_vec_t acc_lo, acc_mid, acc_hi; - - acc_lo = read_acc_lo(acc); - acc_mid = read_acc_mid(acc); - acc_hi = read_acc_hi(acc); - - rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); - rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); - - m_v[VDREG].v = vec_vmadh_vmudh(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); - - write_acc_lo(acc, acc_lo); - write_acc_mid(acc, acc_mid); - write_acc_hi(acc, acc_hi); -#else - for (i = 0; i < 8; i++) - { - int32_t s1 = (int32_t)(int16_t)VREG_S(VS1REG, i); - int32_t s2 = (int32_t)(int16_t)VREG_S(VS2REG, VEC_EL_2(EL, i)); - - int32_t accum = (uint32_t)(uint16_t)ACCUM_M(i); - accum |= ((uint32_t)((uint16_t)ACCUM_H(i))) << 16; - accum += s1 * s2; - - SET_ACCUM_H((uint16_t)(accum >> 16), i); - SET_ACCUM_M((uint16_t)accum, i); - - m_vres[i] = SATURATE_ACCUM(i, 1, 0x8000, 0x7fff); - } - WRITEBACK_RESULT(); - -#endif - // - break; - } - - case 0x10: /* VADD */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010000 | - // ------------------------------------------------------ - // - // Adds two vector registers and carry flag, the result is saturated to 32767 - - // TODO: check VS2REG == VDREG - - //printf("ADD "); -#if USE_SIMD - rsp_vec_t acc_lo; - uint16_t *acc = m_acc.s; - rsp_vec_t carry = read_vco_lo(m_flags[RSP_VCO].s); - - rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); - rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); - - m_v[VDREG].v = vec_vadd(vs, vt_shuffle, carry, &acc_lo); - - write_vco_hi(m_flags[RSP_VCO].s, vec_zero()); - write_vco_lo(m_flags[RSP_VCO].s, vec_zero()); - write_acc_lo(acc, acc_lo); -#else - for (i=0; i < 8; i++) - { - int32_t s1 = (int32_t)(int16_t)VREG_S(VS1REG, i); - int32_t s2 = (int32_t)(int16_t)VREG_S(VS2REG, VEC_EL_2(EL, i)); - int32_t r = s1 + s2 + (CARRY_FLAG(i) != 0 ? 1 : 0); - - SET_ACCUM_L((int16_t)(r), i); - - if (r > 32767) r = 32767; - if (r < -32768) r = -32768; - m_vres[i] = (int16_t)(r); - } - CLEAR_ZERO_FLAGS(); - CLEAR_CARRY_FLAGS(); - WRITEBACK_RESULT(); -#endif - // - break; - } - - case 0x11: /* VSUB */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010001 | - // ------------------------------------------------------ - // - // Subtracts two vector registers and carry flag, the result is saturated to -32768 - - // TODO: check VS2REG == VDREG - - //printf("SUB "); -#if USE_SIMD - rsp_vec_t acc_lo; - uint16_t *acc = m_acc.s; - rsp_vec_t carry = read_vco_lo(m_flags[RSP_VCO].s); - - rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); - rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); - - m_v[VDREG].v = vec_vsub(vs, vt_shuffle, carry, &acc_lo); - - write_vco_hi(m_flags[RSP_VCO].s, vec_zero()); - write_vco_lo(m_flags[RSP_VCO].s, vec_zero()); - write_acc_lo(acc, acc_lo); -#else - for (i = 0; i < 8; i++) - { - int32_t s1 = (int32_t)(int16_t)VREG_S(VS1REG, i); - int32_t s2 = (int32_t)(int16_t)VREG_S(VS2REG, VEC_EL_2(EL, i)); - int32_t r = s1 - s2 - (CARRY_FLAG(i) != 0 ? 1 : 0); - - SET_ACCUM_L((int16_t)(r), i); - - if (r > 32767) r = 32767; - if (r < -32768) r = -32768; - - m_vres[i] = (int16_t)(r); - } - CLEAR_ZERO_FLAGS(); - CLEAR_CARRY_FLAGS(); - WRITEBACK_RESULT(); -#endif - // - break; - } - - case 0x13: /* VABS */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010011 | - // ------------------------------------------------------ - // - // Changes the sign of source register 2 if source register 1 is negative and stores - // the result to destination register - - //printf("ABS "); -#if USE_SIMD - rsp_vec_t acc_lo; - uint16_t *acc = m_acc.s; - - rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); - rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); - - m_v[VDREG].v = vec_vabs(vs, vt_shuffle, vec_zero(), &acc_lo); - - write_acc_lo(acc, acc_lo); -#else - for (i=0; i < 8; i++) - { - int16_t s1 = (int16_t)VREG_S(VS1REG, i); - int16_t s2 = (int16_t)VREG_S(VS2REG, VEC_EL_2(EL, i)); - - if (s1 < 0) - { - if (s2 == -32768) - { - m_vres[i] = 32767; - } - else - { - m_vres[i] = -s2; - } - } - else if (s1 > 0) - { - m_vres[i] = s2; - } - else - { - m_vres[i] = 0; - } - - SET_ACCUM_L(m_vres[i], i); - } - WRITEBACK_RESULT(); -#endif - // - break; - } - - case 0x14: /* VADDC */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010100 | - // ------------------------------------------------------ - // - // Adds two vector registers, the carry out is stored into carry register - - // TODO: check VS2REG = VDREG - - //printf("ADDC "); -#if USE_SIMD - uint16_t *acc = m_acc.s; - rsp_vec_t sn; - - rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); - rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); - - m_v[VDREG].v = vec_vaddc(vs, vt_shuffle, vec_zero(), &sn); - - write_vco_hi(m_flags[RSP_VCO].s, vec_zero()); - write_vco_lo(m_flags[RSP_VCO].s, sn); - write_acc_lo(acc, m_v[VDREG].v); -#else - CLEAR_ZERO_FLAGS(); - CLEAR_CARRY_FLAGS(); - - for (i=0; i < 8; i++) - { - int32_t s1 = (uint32_t)(uint16_t)VREG_S(VS1REG, i); - int32_t s2 = (uint32_t)(uint16_t)VREG_S(VS2REG, VEC_EL_2(EL, i)); - int32_t r = s1 + s2; - - m_vres[i] = (int16_t)(r); - SET_ACCUM_L((int16_t)(r), i); - - if (r & 0xffff0000) - { - SET_CARRY_FLAG(i); - } - } - WRITEBACK_RESULT(); -#endif - // - break; - } - - case 0x15: /* VSUBC */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010101 | - // ------------------------------------------------------ - // - // Subtracts two vector registers, the carry out is stored into carry register - - // TODO: check VS2REG = VDREG - - //printf("SUBC "); -#if USE_SIMD - uint16_t *acc = m_acc.s; - rsp_vec_t eq, sn; - - rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); - rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); - - m_v[VDREG].v = vec_vsubc(vs, vt_shuffle, vec_zero(), &eq, &sn); - - write_vco_hi(m_flags[RSP_VCO].s, eq); - write_vco_lo(m_flags[RSP_VCO].s, sn); - write_acc_lo(acc, m_v[VDREG].v); -#else - CLEAR_ZERO_FLAGS(); - CLEAR_CARRY_FLAGS(); - - for (i=0; i < 8; i++) - { - int32_t s1 = (uint32_t)(uint16_t)VREG_S(VS1REG, i); - int32_t s2 = (uint32_t)(uint16_t)VREG_S(VS2REG, VEC_EL_2(EL, i)); - int32_t r = s1 - s2; - - m_vres[i] = (int16_t)(r); - SET_ACCUM_L((uint16_t)(r), i); - - if ((uint16_t)(r) != 0) - { - SET_ZERO_FLAG(i); - } - if (r & 0xffff0000) - { - SET_CARRY_FLAG(i); - } - } - WRITEBACK_RESULT(); -#endif - // - break; - } - - case 0x1d: /* VSAW */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 011101 | - // ------------------------------------------------------ - // - // Stores high, middle or low slice of accumulator to destination vector - - //printf("SAW "); -#if USE_SIMD - uint16_t *acc = m_acc.s; - switch (EL) - { - case 8: - m_v[VDREG].v = read_acc_hi(acc); - break; - case 9: - m_v[VDREG].v = read_acc_mid(acc); - break; - case 10: - m_v[VDREG].v = read_acc_lo(acc); - break; - - default: - m_v[VDREG].v = _mm_setzero_si128(); - break; - } -#else - switch (EL) - { - case 0x08: // VSAWH - { - for (i=0; i < 8; i++) - { - VREG_S(VDREG, i) = ACCUM_H(i); - } - break; - } - case 0x09: // VSAWM - { - for (i=0; i < 8; i++) - { - VREG_S(VDREG, i) = ACCUM_M(i); - } - break; - } - case 0x0a: // VSAWL - { - for (i=0; i < 8; i++) - { - VREG_S(VDREG, i) = ACCUM_L(i); - } - break; - } - default: //fatalerror("RSP: VSAW: el = %d\n", EL);//??????? - printf("RSP: VSAW: el = %d\n", EL);//??? ??? - exit(0); - } -#endif - // - break; - } - - case 0x20: /* VLT */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100000 | - // ------------------------------------------------------ - // - // Sets compare flags if elements in VS1 are less than VS2 - // Moves the element in VS2 to destination vector - - //printf("LT "); -#if USE_SIMD - uint16_t *acc = m_acc.s; - rsp_vec_t le; - - rsp_vec_t eq = read_vco_hi(m_flags[RSP_VCO].s); - rsp_vec_t sign = read_vco_lo(m_flags[RSP_VCO].s); - - rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); - rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); - - m_v[VDREG].v = vec_veq_vge_vlt_vne(op, vs, vt_shuffle, vec_zero(), &le, eq, sign); - - write_vcc_hi(m_flags[RSP_VCC].s, vec_zero()); - write_vcc_lo(m_flags[RSP_VCC].s, le); - write_vco_hi(m_flags[RSP_VCO].s, vec_zero()); - write_vco_lo(m_flags[RSP_VCO].s, vec_zero()); - write_acc_lo(acc, m_v[VDREG].v); -#else - CLEAR_COMPARE_FLAGS(); - CLEAR_CLIP2_FLAGS(); - - for (i=0; i < 8; i++) - { - int16_t s1, s2; - s1 = VREG_S(VS1REG, i); - s2 = VREG_S(VS2REG, VEC_EL_2(EL, i)); - if (s1 < s2) - { - SET_COMPARE_FLAG(i); - } - else if (s1 == s2) - { - if (ZERO_FLAG(i) != 0 && CARRY_FLAG(i) != 0) - { - SET_COMPARE_FLAG(i); - } - } - - if (COMPARE_FLAG(i) != 0) - { - m_vres[i] = s1; - } - else - { - m_vres[i] = s2; - } - - SET_ACCUM_L(m_vres[i], i); - } - - CLEAR_CARRY_FLAGS(); - CLEAR_ZERO_FLAGS(); - WRITEBACK_RESULT(); -#endif - // - break; - } - - case 0x21: /* VEQ */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100001 | - // ------------------------------------------------------ - // - // Sets compare flags if elements in VS1 are equal with VS2 - // Moves the element in VS2 to destination vector - - //printf("EQ "); -#if USE_SIMD - uint16_t *acc = m_acc.s; - rsp_vec_t le; - - rsp_vec_t eq = read_vco_hi(m_flags[RSP_VCO].s); - rsp_vec_t sign = read_vco_lo(m_flags[RSP_VCO].s); - - rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); - rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); - - m_v[VDREG].v = vec_veq_vge_vlt_vne(op, vs, vt_shuffle, vec_zero(), &le, eq, sign); - - write_vcc_hi(m_flags[RSP_VCC].s, vec_zero()); - write_vcc_lo(m_flags[RSP_VCC].s, le); - write_vco_hi(m_flags[RSP_VCO].s, vec_zero()); - write_vco_lo(m_flags[RSP_VCO].s, vec_zero()); - write_acc_lo(acc, m_v[VDREG].v); -#else - CLEAR_COMPARE_FLAGS(); - CLEAR_CLIP2_FLAGS(); - - for (i = 0; i < 8; i++) - { - int16_t s1 = VREG_S(VS1REG, i); - int16_t s2 = VREG_S(VS2REG, VEC_EL_2(EL, i)); - - if ((s1 == s2) && ZERO_FLAG(i) == 0) - { - SET_COMPARE_FLAG(i); - m_vres[i] = s1; - } - else - { - m_vres[i] = s2; - } - SET_ACCUM_L(m_vres[i], i); - } - - CLEAR_ZERO_FLAGS(); - CLEAR_CARRY_FLAGS(); - WRITEBACK_RESULT(); -#endif - // - break; - } - - case 0x22: /* VNE */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100010 | - // ------------------------------------------------------ - // - // Sets compare flags if elements in VS1 are not equal with VS2 - // Moves the element in VS2 to destination vector - - //printf("NE "); -#if USE_SIMD - uint16_t *acc = m_acc.s; - rsp_vec_t le; - - rsp_vec_t eq = read_vco_hi(m_flags[RSP_VCO].s); - rsp_vec_t sign = read_vco_lo(m_flags[RSP_VCO].s); - - rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); - rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); - - m_v[VDREG].v = vec_veq_vge_vlt_vne(op, vs, vt_shuffle, vec_zero(), &le, eq, sign); - - write_vcc_hi(m_flags[RSP_VCC].s, vec_zero()); - write_vcc_lo(m_flags[RSP_VCC].s, le); - write_vco_hi(m_flags[RSP_VCO].s, vec_zero()); - write_vco_lo(m_flags[RSP_VCO].s, vec_zero()); - write_acc_lo(acc, m_v[VDREG].v); -#else - CLEAR_COMPARE_FLAGS(); - CLEAR_CLIP2_FLAGS(); - - for (i = 0; i < 8; i++) - { - int16_t s1 = VREG_S(VS1REG, i); - int16_t s2 = VREG_S(VS2REG, VEC_EL_2(EL, i)); - - if (s1 != s2 || ZERO_FLAG(i) != 0) - { - SET_COMPARE_FLAG(i); - m_vres[i] = s1; - } - else - { - m_vres[i] = s2; - } - - SET_ACCUM_L(m_vres[i], i); - } - - CLEAR_CARRY_FLAGS(); - CLEAR_ZERO_FLAGS(); - WRITEBACK_RESULT(); -#endif - // - break; - } - - case 0x23: /* VGE */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100011 | - // ------------------------------------------------------ - // - // Sets compare flags if elements in VS1 are greater or equal with VS2 - // Moves the element in VS2 to destination vector - - //printf("GE "); -#if USE_SIMD - uint16_t *acc = m_acc.s; - rsp_vec_t le; - - rsp_vec_t eq = read_vco_hi(m_flags[RSP_VCO].s); - rsp_vec_t sign = read_vco_lo(m_flags[RSP_VCO].s); - - rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); - rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); - - m_v[VDREG].v = vec_veq_vge_vlt_vne(op, vs, vt_shuffle, vec_zero(), &le, eq, sign); - - write_vcc_hi(m_flags[RSP_VCC].s, vec_zero()); - write_vcc_lo(m_flags[RSP_VCC].s, le); - write_vco_hi(m_flags[RSP_VCO].s, vec_zero()); - write_vco_lo(m_flags[RSP_VCO].s, vec_zero()); - write_acc_lo(acc, m_v[VDREG].v); -#else - CLEAR_COMPARE_FLAGS(); - CLEAR_CLIP2_FLAGS(); - - for (i=0; i < 8; i++) - { - int16_t s1 = VREG_S(VS1REG, i); - int16_t s2 = VREG_S(VS2REG, VEC_EL_2(EL, i)); - - if ((s1 == s2 && (ZERO_FLAG(i) == 0 || CARRY_FLAG(i) == 0)) || s1 > s2) - { - SET_COMPARE_FLAG(i); - m_vres[i] = s1; - } - else - { - m_vres[i] = s2; - } - - SET_ACCUM_L(m_vres[i], i); - } - - CLEAR_CARRY_FLAGS(); - CLEAR_ZERO_FLAGS(); - WRITEBACK_RESULT(); -#endif - // - break; - } - - case 0x24: /* VCL */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100100 | - // ------------------------------------------------------ - // - // Vector clip low - - //printf("CL "); -#if USE_SIMD - uint16_t *acc = m_acc.s; - - rsp_vec_t ge = read_vcc_hi(m_flags[RSP_VCC].s); - rsp_vec_t le = read_vcc_lo(m_flags[RSP_VCC].s); - rsp_vec_t eq = read_vco_hi(m_flags[RSP_VCO].s); - rsp_vec_t sign = read_vco_lo(m_flags[RSP_VCO].s); - rsp_vec_t vce = read_vce(m_flags[RSP_VCE].s); - - rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); - rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); - m_v[VDREG].v = vec_vcl(vs, vt_shuffle, vec_zero(), &ge, &le, eq, sign, vce); - - write_vcc_hi(m_flags[RSP_VCC].s, ge); - write_vcc_lo(m_flags[RSP_VCC].s, le); - write_vco_hi(m_flags[RSP_VCO].s, vec_zero()); - write_vco_lo(m_flags[RSP_VCO].s, vec_zero()); - write_vce(m_flags[RSP_VCE].s, vec_zero()); - write_acc_lo(acc, m_v[VDREG].v); -#else - for (i = 0; i < 8; i++) - { - int16_t s1 = VREG_S(VS1REG, i); - int16_t s2 = VREG_S(VS2REG, VEC_EL_2(EL, i)); - - if (CARRY_FLAG(i) != 0) // vco_lo - { - if (ZERO_FLAG(i) != 0) // vco_hi - { - if (COMPARE_FLAG(i) != 0) // vcc_lo - { - SET_ACCUM_L(-(uint16_t)s2, i); - } - else - { - SET_ACCUM_L(s1, i); - } - } - else - { - if (CLIP1_FLAG(i) != 0) // vce - { - if (((uint32_t)(uint16_t)(s1) + (uint32_t)(uint16_t)(s2)) > 0x10000) - { - SET_ACCUM_L(s1, i); - CLEAR_COMPARE_FLAG(i); - } - else - { - SET_ACCUM_L(-((uint16_t)s2), i); - SET_COMPARE_FLAG(i); - } - } - else - { - if (((uint32_t)(uint16_t)(s1) + (uint32_t)(uint16_t)(s2)) != 0) - { - SET_ACCUM_L(s1, i); - CLEAR_COMPARE_FLAG(i); - } - else - { - SET_ACCUM_L(-((uint16_t)s2), i); - SET_COMPARE_FLAG(i); - } - } - } - } - else - { - if (ZERO_FLAG(i) != 0) // vco_hi - { - if (CLIP2_FLAG(i) != 0) // vcc_hi - { - SET_ACCUM_L(s2, i); - } - else - { - SET_ACCUM_L(s1, i); - } - } - else - { - if (((int32_t)(uint16_t)s1 - (int32_t)(uint16_t)s2) >= 0) - { - SET_ACCUM_L(s2, i); - SET_CLIP2_FLAG(i); - } - else - { - SET_ACCUM_L(s1, i); - CLEAR_CLIP2_FLAG(i); - } - } - } - - m_vres[i] = ACCUM_L(i); - } - CLEAR_CARRY_FLAGS(); // vco_lo - CLEAR_ZERO_FLAGS(); // vco_hi - CLEAR_CLIP1_FLAGS(); // vce - WRITEBACK_RESULT(); -#endif - // - break; - } - - case 0x25: /* VCH */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100101 | - // ------------------------------------------------------ - // - // Vector clip high - - //printf("CH "); -#if USE_SIMD - uint16_t *acc = m_acc.s; - rsp_vec_t ge, le, sign, eq, vce; - - rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); - rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); - - m_v[VDREG].v = vec_vch(vs, vt_shuffle, vec_zero(), &ge, &le, &eq, &sign, &vce); - - write_vcc_hi(m_flags[RSP_VCC].s, ge); - write_vcc_lo(m_flags[RSP_VCC].s, le); - write_vco_hi(m_flags[RSP_VCO].s, eq); - write_vco_lo(m_flags[RSP_VCO].s, sign); - write_vce(m_flags[RSP_VCE].s, vce); - write_acc_lo(acc, m_v[VDREG].v); -#else - CLEAR_CARRY_FLAGS(); - CLEAR_COMPARE_FLAGS(); - CLEAR_CLIP1_FLAGS(); - CLEAR_ZERO_FLAGS(); - CLEAR_CLIP2_FLAGS(); - uint32_t vce; - - for (i=0; i < 8; i++) - { - int16_t s1 = VREG_S(VS1REG, i); - int16_t s2 = VREG_S(VS2REG, VEC_EL_2(EL, i)); - - if ((s1 ^ s2) < 0) - { - vce = (s1 + s2 == -1); - SET_CARRY_FLAG(i); - if (s2 < 0) - { - SET_CLIP2_FLAG(i); - } - - if (s1 + s2 <= 0) - { - SET_COMPARE_FLAG(i); - m_vres[i] = -((uint16_t)s2); - } - else - { - m_vres[i] = s1; - } - - if (s1 + s2 != 0) - { - if (s1 != ~s2) - { - SET_ZERO_FLAG(i); - } - } - } - else - { - vce = 0; - if (s2 < 0) - { - SET_COMPARE_FLAG(i); - } - if (s1 - s2 >= 0) - { - SET_CLIP2_FLAG(i); - m_vres[i] = s2; - } - else - { - m_vres[i] = s1; - } - - if ((s1 - s2) != 0) - { - if (s1 != ~s2) - { - SET_ZERO_FLAG(i); - } - } - } - if (vce != 0) - { - SET_CLIP1_FLAG(i); - } - - SET_ACCUM_L(m_vres[i], i); - } - WRITEBACK_RESULT(); -#endif - // - break; - } - - case 0x26: /* VCR */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100110 | - // ------------------------------------------------------ - // - // Vector clip reverse - - //printf("CR "); -#if USE_SIMD - uint16_t *acc = m_acc.s; - rsp_vec_t ge, le; - - rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); - rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); - - m_v[VDREG].v = vec_vcr(vs, vt_shuffle, vec_zero(), &ge, &le); - - write_vcc_hi(m_flags[RSP_VCC].s, ge); - write_vcc_lo(m_flags[RSP_VCC].s, le); - write_vco_hi(m_flags[RSP_VCO].s, vec_zero()); - write_vco_lo(m_flags[RSP_VCO].s, vec_zero()); - write_vce(m_flags[RSP_VCE].s, vec_zero()); - write_acc_lo(acc, m_v[VDREG].v); -#else - CLEAR_CARRY_FLAGS(); - CLEAR_COMPARE_FLAGS(); - CLEAR_CLIP1_FLAGS(); - CLEAR_ZERO_FLAGS(); - CLEAR_CLIP2_FLAGS(); - - for (i=0; i < 8; i++) - { - int16_t s1 = VREG_S(VS1REG, i); - int16_t s2 = VREG_S(VS2REG, VEC_EL_2(EL, i)); - - if ((int16_t)(s1 ^ s2) < 0) - { - if (s2 < 0) - { - SET_CLIP2_FLAG(i); - } - if ((s1 + s2) <= 0) - { - SET_ACCUM_L(~((uint16_t)s2), i); - SET_COMPARE_FLAG(i); - } - else - { - SET_ACCUM_L(s1, i); - } - } - else - { - if (s2 < 0) - { - SET_COMPARE_FLAG(i); - } - if ((s1 - s2) >= 0) - { - SET_ACCUM_L(s2, i); - SET_CLIP2_FLAG(i); - } - else - { - SET_ACCUM_L(s1, i); - } - } - - m_vres[i] = ACCUM_L(i); - } - WRITEBACK_RESULT(); -#endif - // - break; - } - - case 0x27: /* VMRG */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100111 | - // ------------------------------------------------------ - // - // Merges two vectors according to compare flags - - //printf("MRG "); -#if USE_SIMD - uint16_t *acc = m_acc.s; - rsp_vec_t le = read_vcc_lo(m_flags[RSP_VCC].s); - - rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); - rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); - - m_v[VDREG].v = vec_vmrg(vs, vt_shuffle, le); - - write_vco_hi(m_flags[RSP_VCO].s, vec_zero()); - write_vco_lo(m_flags[RSP_VCO].s, vec_zero()); - write_acc_lo(acc, m_v[VDREG].v); -#else - for (i = 0; i < 8; i++) - { - if (COMPARE_FLAG(i) != 0) - { - m_vres[i] = VREG_S(VS1REG, i); - } - else - { - m_vres[i] = VREG_S(VS2REG, VEC_EL_2(EL, i)); - } - - SET_ACCUM_L(m_vres[i], i); - } - WRITEBACK_RESULT(); -#endif - // - break; - } - case 0x28: /* VAND */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101000 | - // ------------------------------------------------------ - // - // Bitwise AND of two vector registers - - //printf("AND "); -#if USE_SIMD - uint16_t *acc = m_acc.s; - - rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); - rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); - - m_v[VDREG].v = vec_vand_vnand(op, vs, vt_shuffle); - - write_acc_lo(acc, m_v[VDREG].v); -#else - for (i = 0; i < 8; i++) - { - m_vres[i] = VREG_S(VS1REG, i) & VREG_S(VS2REG, VEC_EL_2(EL, i)); - SET_ACCUM_L(m_vres[i], i); - } - WRITEBACK_RESULT(); -#endif - // - break; - } - case 0x29: /* VNAND */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101001 | - // ------------------------------------------------------ - // - // Bitwise NOT AND of two vector registers - - //printf("NAND "); -#if USE_SIMD - uint16_t *acc = m_acc.s; - - rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); - rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); - - m_v[VDREG].v = vec_vand_vnand(op, vs, vt_shuffle); - - write_acc_lo(acc, m_v[VDREG].v); -#else - for (i = 0; i < 8; i++) - { - m_vres[i] = ~((VREG_S(VS1REG, i) & VREG_S(VS2REG, VEC_EL_2(EL, i)))); - SET_ACCUM_L(m_vres[i], i); - } - WRITEBACK_RESULT(); -#endif - // - break; - } - case 0x2a: /* VOR */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101010 | - // ------------------------------------------------------ - // - // Bitwise OR of two vector registers - - //printf("OR "); -#if USE_SIMD - uint16_t *acc = m_acc.s; - - rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); - rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); - - m_v[VDREG].v = vec_vor_vnor(op, vs, vt_shuffle); - - write_acc_lo(acc, m_v[VDREG].v); -#else - for (i = 0; i < 8; i++) - { - m_vres[i] = VREG_S(VS1REG, i) | VREG_S(VS2REG, VEC_EL_2(EL, i)); - SET_ACCUM_L(m_vres[i], i); - } - WRITEBACK_RESULT(); -#endif - // - break; - } - case 0x2b: /* VNOR */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101011 | - // ------------------------------------------------------ - // - // Bitwise NOT OR of two vector registers - - //printf("NOR "); -#if USE_SIMD - uint16_t *acc = m_acc.s; - - rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); - rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); - - m_v[VDREG].v = vec_vor_vnor(op, vs, vt_shuffle); - - write_acc_lo(acc, m_v[VDREG].v); -#else - for (i=0; i < 8; i++) - { - m_vres[i] = ~((VREG_S(VS1REG, i) | VREG_S(VS2REG, VEC_EL_2(EL, i)))); - SET_ACCUM_L(m_vres[i], i); - } - WRITEBACK_RESULT(); -#endif - // - break; - } - case 0x2c: /* VXOR */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101100 | - // ------------------------------------------------------ - // - // Bitwise XOR of two vector registers - - //printf("XOR "); -#if USE_SIMD - uint16_t *acc = m_acc.s; - - rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); - rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); - - m_v[VDREG].v = vec_vxor_vnxor(op, vs, vt_shuffle); - - write_acc_lo(acc, m_v[VDREG].v); -#else - for (i=0; i < 8; i++) - { - m_vres[i] = VREG_S(VS1REG, i) ^ VREG_S(VS2REG, VEC_EL_2(EL, i)); - SET_ACCUM_L(m_vres[i], i); - } - WRITEBACK_RESULT(); -#endif - // - break; - } - case 0x2d: /* VNXOR */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101101 | - // ------------------------------------------------------ - // - // Bitwise NOT XOR of two vector registers - - //printf("NXOR "); -#if USE_SIMD - uint16_t *acc = m_acc.s; - - rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); - rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); - - m_v[VDREG].v = vec_vxor_vnxor(op, vs, vt_shuffle); - - write_acc_lo(acc, m_v[VDREG].v); -#else - for (i=0; i < 8; i++) - { - m_vres[i] = ~((VREG_S(VS1REG, i) ^ VREG_S(VS2REG, VEC_EL_2(EL, i)))); - SET_ACCUM_L(m_vres[i], i); - } - WRITEBACK_RESULT(); -#endif - // - break; - } - - case 0x30: /* VRCP */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110000 | - // ------------------------------------------------------ - // - // Calculates reciprocal - - //printf("RCP "); -#if USE_SIMD - write_acc_lo(m_acc.s, vec_load_and_shuffle_operand(m_v[VS2REG].s, EL)); - - int32_t dp = op & m_dp_flag; - m_dp_flag = 0; - - m_v[VDREG].v = vec_vrcp_vrsq(op, dp, VS2REG, EL, VDREG, VS1REG); -#else - int32_t shifter = 0; - - int32_t rec = (int16_t)(VREG_S(VS2REG, EL & 7)); - int32_t datainput = (rec < 0) ? (-rec) : rec; - if (datainput) - { - for (i = 0; i < 32; i++) - { - if (datainput & (1 << ((~i) & 0x1f))) - { - shifter = i; - break; - } - } - } - else - { - shifter = 0x10; - } - - int32_t address = ((datainput << shifter) & 0x7fc00000) >> 22; - int32_t fetchval = rsp_divtable[address]; - int32_t temp = (0x40000000 | (fetchval << 14)) >> ((~shifter) & 0x1f); - if (rec < 0) - { - temp = ~temp; - } - if (!rec) - { - temp = 0x7fffffff; - } - else if (rec == 0xffff8000) - { - temp = 0xffff0000; - } - rec = temp; - - m_reciprocal_res = rec; - m_dp_allowed = 0; - - VREG_S(VDREG, VS1REG & 7) = (uint16_t)(rec & 0xffff); - - for (i = 0; i < 8; i++) - { - SET_ACCUM_L(VREG_S(VS2REG, VEC_EL_2(EL, i)), i); - } - - -#endif - // - break; - } - - case 0x31: /* VRCPL */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110001 | - // ------------------------------------------------------ - // - // Calculates reciprocal low part - - //printf("RCPL "); -#if USE_SIMD - write_acc_lo(m_acc.s, vec_load_and_shuffle_operand(m_v[VS2REG].s, EL)); - - int32_t dp = op & m_dp_flag; - m_dp_flag = 0; - - m_v[VDREG].v = vec_vrcp_vrsq(op, dp, VS2REG, EL, VDREG, VS1REG); -#else - int32_t shifter = 0; - - int32_t rec = (int16_t)VREG_S(VS2REG, EL & 7); - int32_t datainput = rec; - - if (m_dp_allowed) - { - rec = (rec & 0x0000ffff) | m_reciprocal_high; - datainput = rec; - - if (rec < 0) - { - if (rec < -32768) - { - datainput = ~datainput; - } - else - { - datainput = -datainput; - } - } - } - else if (datainput < 0) - { - datainput = -datainput; - - shifter = 0x10; - } - - - for (i = 0; i < 32; i++) - { - if (datainput & (1 << ((~i) & 0x1f))) - { - shifter = i; - break; - } - } - - int32_t address = ((datainput << shifter) & 0x7fc00000) >> 22; - int32_t fetchval = rsp_divtable[address]; - int32_t temp = (0x40000000 | (fetchval << 14)) >> ((~shifter) & 0x1f); - temp ^= rec >> 31; - - if (!rec) - { - temp = 0x7fffffff; - } - else if (rec == 0xffff8000) - { - temp = 0xffff0000; - } - rec = temp; - - m_reciprocal_res = rec; - m_dp_allowed = 0; - - VREG_S(VDREG, VS1REG & 7) = (uint16_t)(rec & 0xffff); - - for (i = 0; i < 8; i++) - { - SET_ACCUM_L(VREG_S(VS2REG, VEC_EL_2(EL, i)), i); - } - -#endif - // - break; - } - - case 0x32: /* VRCPH */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110010 | - // ------------------------------------------------------ - // - // Calculates reciprocal high part - - //printf("RCPH "); -#if USE_SIMD - write_acc_lo(m_acc.s, vec_load_and_shuffle_operand(m_v[VS2REG].s, EL)); - - m_dp_flag = 1; - - m_v[VDREG].v = vec_vdivh(VS2REG, EL, VDREG, VS1REG); -#else - m_reciprocal_high = (VREG_S(VS2REG, EL & 7)) << 16; - m_dp_allowed = 1; - - for (i = 0; i < 8; i++) - { - SET_ACCUM_L(VREG_S(VS2REG, VEC_EL_2(EL, i)), i); - } - - VREG_S(VDREG, VS1REG & 7) = (int16_t)(m_reciprocal_res >> 16); - -#endif - // - break; - } - - case 0x33: /* VMOV */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110011 | - // ------------------------------------------------------ - // - // Moves element from vector to destination vector - - //printf("MOV "); -#if USE_SIMD - write_acc_lo(m_acc.s, vec_load_and_shuffle_operand(m_v[VS2REG].s, EL)); - m_v[VDREG].v = vec_vmov(VS2REG, EL, VDREG, VS1REG); -#else - VREG_S(VDREG, VS1REG & 7) = VREG_S(VS2REG, EL & 7); - for (i = 0; i < 8; i++) - { - SET_ACCUM_L(VREG_S(VS2REG, VEC_EL_2(EL, i)), i); - } -#endif - // - break; - } - - case 0x34: /* VRSQ */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110100 | - // ------------------------------------------------------ - // - // Calculates reciprocal square-root - - //printf("RSQ "); -#if USE_SIMD - write_acc_lo(m_acc.s, vec_load_and_shuffle_operand(m_v[VS2REG].s, EL)); - - int32_t dp = op & m_dp_flag; - m_dp_flag = 0; - - m_v[VDREG].v = vec_vrcp_vrsq(op, dp, VS2REG, EL, VDREG, VS1REG); -#else - int32_t shifter = 0; - - int32_t rec = (int16_t)(VREG_S(VS2REG, EL & 7)); - int32_t datainput = (rec < 0) ? (-rec) : rec; - if (datainput) - { - for (i = 0; i < 32; i++) - { - if (datainput & (1 << ((~i) & 0x1f)))//?.?.??? 31 - i - { - shifter = i; - break; - } - } - } - else - { - shifter = 0x10; - } - - int32_t address = ((datainput << shifter) & 0x7fc00000) >> 22; - address = ((address | 0x200) & 0x3fe) | (shifter & 1); - - int32_t fetchval = rsp_divtable[address]; - int32_t temp = (0x40000000 | (fetchval << 14)) >> (((~shifter) & 0x1f) >> 1); - if (rec < 0) - { - temp = ~temp; - } - if (!rec) - { - temp = 0x7fffffff; - } - else if (rec == 0xffff8000) - { - temp = 0xffff0000; - } - rec = temp; - - m_reciprocal_res = rec; - m_dp_allowed = 0; - - VREG_S(VDREG, VS1REG & 7) = (uint16_t)(rec & 0xffff); - - for (i = 0; i < 8; i++) - { - SET_ACCUM_L(VREG_S(VS2REG, VEC_EL_2(EL, i)), i); - } - -#endif - // - break; - } - - case 0x35: /* VRSQL */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110101 | - // ------------------------------------------------------ - // - // Calculates reciprocal square-root low part - - //printf("RSQL "); -#if USE_SIMD - write_acc_lo(m_acc.s, vec_load_and_shuffle_operand(m_v[VS2REG].s, EL)); - - int32_t dp = op & m_dp_flag; - m_dp_flag = 0; - - m_v[VDREG].v = vec_vrcp_vrsq(op, dp, VS2REG, EL, VDREG, VS1REG); -#else - int32_t shifter = 0; - int32_t rec = (int16_t)VREG_S(VS2REG, EL & 7); - int32_t datainput = rec; - - if (m_dp_allowed) - { - rec = (rec & 0x0000ffff) | m_reciprocal_high; - datainput = rec; - - if (rec < 0) - { - if (rec < -32768) - { - datainput = ~datainput; - } - else - { - datainput = -datainput; - } - } - } - else if (datainput < 0) - { - datainput = -datainput; - - shifter = 0x10; - } - - if (datainput) - { - for (i = 0; i < 32; i++) - { - if (datainput & (1 << ((~i) & 0x1f))) - { - shifter = i; - break; - } - } - } - - int32_t address = ((datainput << shifter) & 0x7fc00000) >> 22; - address = ((address | 0x200) & 0x3fe) | (shifter & 1); - - int32_t fetchval = rsp_divtable[address]; - int32_t temp = (0x40000000 | (fetchval << 14)) >> (((~shifter) & 0x1f) >> 1); - temp ^= rec >> 31; - - if (!rec) - { - temp = 0x7fffffff; - } - else if (rec == 0xffff8000) - { - temp = 0xffff0000; - } - rec = temp; - - m_reciprocal_res = rec; - m_dp_allowed = 0; - - VREG_S(VDREG, VS1REG & 7) = (uint16_t)(rec & 0xffff); - - for (i = 0; i < 8; i++) - { - SET_ACCUM_L(VREG_S(VS2REG, VEC_EL_2(EL, i)), i); - } - -#endif - // - break; - } - - case 0x36: /* VRSQH */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110110 | - // ------------------------------------------------------ - // - // Calculates reciprocal square-root high part - - //printf("RSQH "); -#if USE_SIMD - write_acc_lo(m_acc.s, vec_load_and_shuffle_operand(m_v[VS2REG].s, EL)); - - m_dp_flag = 1; - - m_v[VDREG].v = vec_vdivh(VS2REG, EL, VDREG, VS1REG); -#else - m_reciprocal_high = (VREG_S(VS2REG, EL & 7)) << 16; - m_dp_allowed = 1; - - for (i=0; i < 8; i++) - { - SET_ACCUM_L(VREG_S(VS2REG, VEC_EL_2(EL, i)), i); - } - - VREG_S(VDREG, VS1REG & 7) = (int16_t)(m_reciprocal_res >> 16); // store high part -#endif - // - break; - } - - case 0x37: /* VNOP */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110111 | - // ------------------------------------------------------ - // - // Vector null instruction - - //printf("NOP "); - break; - } - - default: m_rsp.unimplemented_opcode(op); break; - } -} - -/*************************************************************************** - Vector Flag Reading/Writing -***************************************************************************/ - -void rsp_device::cop2::handle_cop2(uint32_t op) -{ - switch ((op >> 21) & 0x1f) - { - case 0x00: /* MFC2 */ - { - // 31 25 20 15 10 6 0 - // --------------------------------------------------- - // | 010010 | 00000 | TTTTT | DDDDD | IIII | 0000000 | - // --------------------------------------------------- - // - //printf("MFC2 "); - int el = (op >> 7) & 0xf; - uint16_t b1 = VREG_B(RDREG, (el+0) & 0xf); - uint16_t b2 = VREG_B(RDREG, (el+1) & 0xf); - if (RTREG) RTVAL = (int32_t)(int16_t)((b1 << 8) | (b2)); - break; - } - - case 0x02: /* CFC2 */ - { - // 31 25 20 15 10 0 - // ------------------------------------------------ - // | 010010 | 00010 | TTTTT | DDDDD | 00000000000 | - // ------------------------------------------------ - // - //printf("CFC2 "); - if (RTREG) - { -#if USE_SIMD - int32_t src = RDREG & 3; - if (src == 3) { - src = 2; - } - RTVAL = get_flags(m_flags[src].s); -#else - switch(RDREG) - { - case 0: - RTVAL = ((CARRY_FLAG(0) & 1) << 0) | - ((CARRY_FLAG(1) & 1) << 1) | - ((CARRY_FLAG(2) & 1) << 2) | - ((CARRY_FLAG(3) & 1) << 3) | - ((CARRY_FLAG(4) & 1) << 4) | - ((CARRY_FLAG(5) & 1) << 5) | - ((CARRY_FLAG(6) & 1) << 6) | - ((CARRY_FLAG(7) & 1) << 7) | - ((ZERO_FLAG(0) & 1) << 8) | - ((ZERO_FLAG(1) & 1) << 9) | - ((ZERO_FLAG(2) & 1) << 10) | - ((ZERO_FLAG(3) & 1) << 11) | - ((ZERO_FLAG(4) & 1) << 12) | - ((ZERO_FLAG(5) & 1) << 13) | - ((ZERO_FLAG(6) & 1) << 14) | - ((ZERO_FLAG(7) & 1) << 15); - if (RTVAL & 0x8000) RTVAL |= 0xffff0000; - break; - case 1: - RTVAL = ((COMPARE_FLAG(0) & 1) << 0) | - ((COMPARE_FLAG(1) & 1) << 1) | - ((COMPARE_FLAG(2) & 1) << 2) | - ((COMPARE_FLAG(3) & 1) << 3) | - ((COMPARE_FLAG(4) & 1) << 4) | - ((COMPARE_FLAG(5) & 1) << 5) | - ((COMPARE_FLAG(6) & 1) << 6) | - ((COMPARE_FLAG(7) & 1) << 7) | - ((CLIP2_FLAG(0) & 1) << 8) | - ((CLIP2_FLAG(1) & 1) << 9) | - ((CLIP2_FLAG(2) & 1) << 10) | - ((CLIP2_FLAG(3) & 1) << 11) | - ((CLIP2_FLAG(4) & 1) << 12) | - ((CLIP2_FLAG(5) & 1) << 13) | - ((CLIP2_FLAG(6) & 1) << 14) | - ((CLIP2_FLAG(7) & 1) << 15); - if (RTVAL & 0x8000) RTVAL |= 0xffff0000; - break; - case 2: - // Anciliary clipping flags - RTVAL = ((CLIP1_FLAG(0) & 1) << 0) | - ((CLIP1_FLAG(1) & 1) << 1) | - ((CLIP1_FLAG(2) & 1) << 2) | - ((CLIP1_FLAG(3) & 1) << 3) | - ((CLIP1_FLAG(4) & 1) << 4) | - ((CLIP1_FLAG(5) & 1) << 5) | - ((CLIP1_FLAG(6) & 1) << 6) | - ((CLIP1_FLAG(7) & 1) << 7); - } -#endif - } - break; - } - - case 0x04: /* MTC2 */ - { - // 31 25 20 15 10 6 0 - // --------------------------------------------------- - // | 010010 | 00100 | TTTTT | DDDDD | IIII | 0000000 | - // --------------------------------------------------- - // - //printf("MTC2 "); - int el = (op >> 7) & 0xf; - W_VREG_B(RDREG, (el+0) & 0xf, (RTVAL >> 8) & 0xff); - W_VREG_B(RDREG, (el+1) & 0xf, (RTVAL >> 0) & 0xff); - break; - } - - case 0x06: /* CTC2 */ - { - // 31 25 20 15 10 0 - // ------------------------------------------------ - // | 010010 | 00110 | TTTTT | DDDDD | 00000000000 | - // ------------------------------------------------ - // - switch(RDREG) - { -#if USE_SIMD - case 0: - case 1: - case 2: - uint16_t r0 = (RTVAL & (1 << 0)) ? 0xffff : 0; - uint16_t r1 = (RTVAL & (1 << 1)) ? 0xffff : 0; - uint16_t r2 = (RTVAL & (1 << 2)) ? 0xffff : 0; - uint16_t r3 = (RTVAL & (1 << 3)) ? 0xffff : 0; - uint16_t r4 = (RTVAL & (1 << 4)) ? 0xffff : 0; - uint16_t r5 = (RTVAL & (1 << 5)) ? 0xffff : 0; - uint16_t r6 = (RTVAL & (1 << 6)) ? 0xffff : 0; - uint16_t r7 = (RTVAL & (1 << 7)) ? 0xffff : 0; - m_flags[RDREG].__align[0] = _mm_set_epi16(r7, r6, r5, r4, r3, r2, r1, r0); - r0 = (RTVAL & (1 << 8)) ? 0xffff : 0; - r1 = (RTVAL & (1 << 9)) ? 0xffff : 0; - r2 = (RTVAL & (1 << 10)) ? 0xffff : 0; - r3 = (RTVAL & (1 << 11)) ? 0xffff : 0; - r4 = (RTVAL & (1 << 12)) ? 0xffff : 0; - r5 = (RTVAL & (1 << 13)) ? 0xffff : 0; - r6 = (RTVAL & (1 << 14)) ? 0xffff : 0; - r7 = (RTVAL & (1 << 15)) ? 0xffff : 0; - m_flags[RDREG].__align[1] = _mm_set_epi16(r7, r6, r5, r4, r3, r2, r1, r0); - break; -#else - case 0: - CLEAR_CARRY_FLAGS(); - CLEAR_ZERO_FLAGS(); - if (RTVAL & (1 << 0)) { SET_CARRY_FLAG(0); } - if (RTVAL & (1 << 1)) { SET_CARRY_FLAG(1); } - if (RTVAL & (1 << 2)) { SET_CARRY_FLAG(2); } - if (RTVAL & (1 << 3)) { SET_CARRY_FLAG(3); } - if (RTVAL & (1 << 4)) { SET_CARRY_FLAG(4); } - if (RTVAL & (1 << 5)) { SET_CARRY_FLAG(5); } - if (RTVAL & (1 << 6)) { SET_CARRY_FLAG(6); } - if (RTVAL & (1 << 7)) { SET_CARRY_FLAG(7); } - if (RTVAL & (1 << 8)) { SET_ZERO_FLAG(0); } - if (RTVAL & (1 << 9)) { SET_ZERO_FLAG(1); } - if (RTVAL & (1 << 10)) { SET_ZERO_FLAG(2); } - if (RTVAL & (1 << 11)) { SET_ZERO_FLAG(3); } - if (RTVAL & (1 << 12)) { SET_ZERO_FLAG(4); } - if (RTVAL & (1 << 13)) { SET_ZERO_FLAG(5); } - if (RTVAL & (1 << 14)) { SET_ZERO_FLAG(6); } - if (RTVAL & (1 << 15)) { SET_ZERO_FLAG(7); } - break; - - case 1: - CLEAR_COMPARE_FLAGS(); - CLEAR_CLIP2_FLAGS(); - if (RTVAL & (1 << 0)) { SET_COMPARE_FLAG(0); } - if (RTVAL & (1 << 1)) { SET_COMPARE_FLAG(1); } - if (RTVAL & (1 << 2)) { SET_COMPARE_FLAG(2); } - if (RTVAL & (1 << 3)) { SET_COMPARE_FLAG(3); } - if (RTVAL & (1 << 4)) { SET_COMPARE_FLAG(4); } - if (RTVAL & (1 << 5)) { SET_COMPARE_FLAG(5); } - if (RTVAL & (1 << 6)) { SET_COMPARE_FLAG(6); } - if (RTVAL & (1 << 7)) { SET_COMPARE_FLAG(7); } - if (RTVAL & (1 << 8)) { SET_CLIP2_FLAG(0); } - if (RTVAL & (1 << 9)) { SET_CLIP2_FLAG(1); } - if (RTVAL & (1 << 10)) { SET_CLIP2_FLAG(2); } - if (RTVAL & (1 << 11)) { SET_CLIP2_FLAG(3); } - if (RTVAL & (1 << 12)) { SET_CLIP2_FLAG(4); } - if (RTVAL & (1 << 13)) { SET_CLIP2_FLAG(5); } - if (RTVAL & (1 << 14)) { SET_CLIP2_FLAG(6); } - if (RTVAL & (1 << 15)) { SET_CLIP2_FLAG(7); } - break; - - case 2: - CLEAR_CLIP1_FLAGS(); - if (RTVAL & (1 << 0)) { SET_CLIP1_FLAG(0); } - if (RTVAL & (1 << 1)) { SET_CLIP1_FLAG(1); } - if (RTVAL & (1 << 2)) { SET_CLIP1_FLAG(2); } - if (RTVAL & (1 << 3)) { SET_CLIP1_FLAG(3); } - if (RTVAL & (1 << 4)) { SET_CLIP1_FLAG(4); } - if (RTVAL & (1 << 5)) { SET_CLIP1_FLAG(5); } - if (RTVAL & (1 << 6)) { SET_CLIP1_FLAG(6); } - if (RTVAL & (1 << 7)) { SET_CLIP1_FLAG(7); } - break; -#endif - } - break; - } - - case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: - case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: - { - //printf("V"); - handle_vector_ops(op); - break; - } - - default: - m_rsp.unimplemented_opcode(op); - break; - } - //dump(op); -} - -inline void rsp_device::cop2::mfc2() -{ - uint32_t op = m_rspcop2_state->op; - int el = (op >> 7) & 0xf; - - uint16_t b1 = VREG_B(VS1REG, (el+0) & 0xf); - uint16_t b2 = VREG_B(VS1REG, (el+1) & 0xf); - if (RTREG) RTVAL = (int32_t)(int16_t)((b1 << 8) | (b2)); -} - -inline void rsp_device::cop2::cfc2() -{ - uint32_t op = m_rspcop2_state->op; - if (RTREG) - { - switch(RDREG) - { - case 0: - RTVAL = ((CARRY_FLAG(0) & 1) << 0) | - ((CARRY_FLAG(1) & 1) << 1) | - ((CARRY_FLAG(2) & 1) << 2) | - ((CARRY_FLAG(3) & 1) << 3) | - ((CARRY_FLAG(4) & 1) << 4) | - ((CARRY_FLAG(5) & 1) << 5) | - ((CARRY_FLAG(6) & 1) << 6) | - ((CARRY_FLAG(7) & 1) << 7) | - ((ZERO_FLAG(0) & 1) << 8) | - ((ZERO_FLAG(1) & 1) << 9) | - ((ZERO_FLAG(2) & 1) << 10) | - ((ZERO_FLAG(3) & 1) << 11) | - ((ZERO_FLAG(4) & 1) << 12) | - ((ZERO_FLAG(5) & 1) << 13) | - ((ZERO_FLAG(6) & 1) << 14) | - ((ZERO_FLAG(7) & 1) << 15); - if (RTVAL & 0x8000) RTVAL |= 0xffff0000; - break; - case 1: - RTVAL = ((COMPARE_FLAG(0) & 1) << 0) | - ((COMPARE_FLAG(1) & 1) << 1) | - ((COMPARE_FLAG(2) & 1) << 2) | - ((COMPARE_FLAG(3) & 1) << 3) | - ((COMPARE_FLAG(4) & 1) << 4) | - ((COMPARE_FLAG(5) & 1) << 5) | - ((COMPARE_FLAG(6) & 1) << 6) | - ((COMPARE_FLAG(7) & 1) << 7) | - ((CLIP2_FLAG(0) & 1) << 8) | - ((CLIP2_FLAG(1) & 1) << 9) | - ((CLIP2_FLAG(2) & 1) << 10) | - ((CLIP2_FLAG(3) & 1) << 11) | - ((CLIP2_FLAG(4) & 1) << 12) | - ((CLIP2_FLAG(5) & 1) << 13) | - ((CLIP2_FLAG(6) & 1) << 14) | - ((CLIP2_FLAG(7) & 1) << 15); - if (RTVAL & 0x8000) RTVAL |= 0xffff0000; - break; - case 2: - RTVAL = ((CLIP1_FLAG(0) & 1) << 0) | - ((CLIP1_FLAG(1) & 1) << 1) | - ((CLIP1_FLAG(2) & 1) << 2) | - ((CLIP1_FLAG(3) & 1) << 3) | - ((CLIP1_FLAG(4) & 1) << 4) | - ((CLIP1_FLAG(5) & 1) << 5) | - ((CLIP1_FLAG(6) & 1) << 6) | - ((CLIP1_FLAG(7) & 1) << 7); - break; - } - } -} - -inline void rsp_device::cop2::mtc2() -{ - uint32_t op = m_rspcop2_state->op; - int el = (op >> 7) & 0xf; - VREG_B(VS1REG, (el+0) & 0xf) = (RTVAL >> 8) & 0xff; - VREG_B(VS1REG, (el+1) & 0xf) = (RTVAL >> 0) & 0xff; -} - -inline void rsp_device::cop2::ctc2() -{ - uint32_t op = m_rspcop2_state->op; - switch(RDREG) - { - case 0: - CLEAR_CARRY_FLAGS(); - CLEAR_ZERO_FLAGS(); - m_vflag[0][0] = ((RTVAL >> 0) & 1) ? 0xffff : 0; - m_vflag[0][1] = ((RTVAL >> 1) & 1) ? 0xffff : 0; - m_vflag[0][2] = ((RTVAL >> 2) & 1) ? 0xffff : 0; - m_vflag[0][3] = ((RTVAL >> 3) & 1) ? 0xffff : 0; - m_vflag[0][4] = ((RTVAL >> 4) & 1) ? 0xffff : 0; - m_vflag[0][5] = ((RTVAL >> 5) & 1) ? 0xffff : 0; - m_vflag[0][6] = ((RTVAL >> 6) & 1) ? 0xffff : 0; - m_vflag[0][7] = ((RTVAL >> 7) & 1) ? 0xffff : 0; - if (RTVAL & (1 << 0)) { SET_CARRY_FLAG(0); } - if (RTVAL & (1 << 1)) { SET_CARRY_FLAG(1); } - if (RTVAL & (1 << 2)) { SET_CARRY_FLAG(2); } - if (RTVAL & (1 << 3)) { SET_CARRY_FLAG(3); } - if (RTVAL & (1 << 4)) { SET_CARRY_FLAG(4); } - if (RTVAL & (1 << 5)) { SET_CARRY_FLAG(5); } - if (RTVAL & (1 << 6)) { SET_CARRY_FLAG(6); } - if (RTVAL & (1 << 7)) { SET_CARRY_FLAG(7); } - m_vflag[3][0] = ((RTVAL >> 8) & 1) ? 0xffff : 0; - m_vflag[3][1] = ((RTVAL >> 9) & 1) ? 0xffff : 0; - m_vflag[3][2] = ((RTVAL >> 10) & 1) ? 0xffff : 0; - m_vflag[3][3] = ((RTVAL >> 11) & 1) ? 0xffff : 0; - m_vflag[3][4] = ((RTVAL >> 12) & 1) ? 0xffff : 0; - m_vflag[3][5] = ((RTVAL >> 13) & 1) ? 0xffff : 0; - m_vflag[3][6] = ((RTVAL >> 14) & 1) ? 0xffff : 0; - m_vflag[3][7] = ((RTVAL >> 15) & 1) ? 0xffff : 0; - if (RTVAL & (1 << 8)) { SET_ZERO_FLAG(0); } - if (RTVAL & (1 << 9)) { SET_ZERO_FLAG(1); } - if (RTVAL & (1 << 10)) { SET_ZERO_FLAG(2); } - if (RTVAL & (1 << 11)) { SET_ZERO_FLAG(3); } - if (RTVAL & (1 << 12)) { SET_ZERO_FLAG(4); } - if (RTVAL & (1 << 13)) { SET_ZERO_FLAG(5); } - if (RTVAL & (1 << 14)) { SET_ZERO_FLAG(6); } - if (RTVAL & (1 << 15)) { SET_ZERO_FLAG(7); } - break; - case 1: - CLEAR_COMPARE_FLAGS(); - CLEAR_CLIP2_FLAGS(); - m_vflag[1][0] = ((RTVAL >> 0) & 1) ? 0xffff : 0; - m_vflag[1][1] = ((RTVAL >> 1) & 1) ? 0xffff : 0; - m_vflag[1][2] = ((RTVAL >> 2) & 1) ? 0xffff : 0; - m_vflag[1][3] = ((RTVAL >> 3) & 1) ? 0xffff : 0; - m_vflag[1][4] = ((RTVAL >> 4) & 1) ? 0xffff : 0; - m_vflag[1][5] = ((RTVAL >> 5) & 1) ? 0xffff : 0; - m_vflag[1][6] = ((RTVAL >> 6) & 1) ? 0xffff : 0; - m_vflag[1][7] = ((RTVAL >> 7) & 1) ? 0xffff : 0; - if (RTVAL & (1 << 0)) { SET_COMPARE_FLAG(0); } - if (RTVAL & (1 << 1)) { SET_COMPARE_FLAG(1); } - if (RTVAL & (1 << 2)) { SET_COMPARE_FLAG(2); } - if (RTVAL & (1 << 3)) { SET_COMPARE_FLAG(3); } - if (RTVAL & (1 << 4)) { SET_COMPARE_FLAG(4); } - if (RTVAL & (1 << 5)) { SET_COMPARE_FLAG(5); } - if (RTVAL & (1 << 6)) { SET_COMPARE_FLAG(6); } - if (RTVAL & (1 << 7)) { SET_COMPARE_FLAG(7); } - m_vflag[4][0] = ((RTVAL >> 8) & 1) ? 0xffff : 0; - m_vflag[4][1] = ((RTVAL >> 9) & 1) ? 0xffff : 0; - m_vflag[4][2] = ((RTVAL >> 10) & 1) ? 0xffff : 0; - m_vflag[4][3] = ((RTVAL >> 11) & 1) ? 0xffff : 0; - m_vflag[4][4] = ((RTVAL >> 12) & 1) ? 0xffff : 0; - m_vflag[4][5] = ((RTVAL >> 13) & 1) ? 0xffff : 0; - m_vflag[4][6] = ((RTVAL >> 14) & 1) ? 0xffff : 0; - m_vflag[4][7] = ((RTVAL >> 15) & 1) ? 0xffff : 0; - if (RTVAL & (1 << 8)) { SET_CLIP2_FLAG(0); } - if (RTVAL & (1 << 9)) { SET_CLIP2_FLAG(1); } - if (RTVAL & (1 << 10)) { SET_CLIP2_FLAG(2); } - if (RTVAL & (1 << 11)) { SET_CLIP2_FLAG(3); } - if (RTVAL & (1 << 12)) { SET_CLIP2_FLAG(4); } - if (RTVAL & (1 << 13)) { SET_CLIP2_FLAG(5); } - if (RTVAL & (1 << 14)) { SET_CLIP2_FLAG(6); } - if (RTVAL & (1 << 15)) { SET_CLIP2_FLAG(7); } - break; - case 2: - CLEAR_CLIP1_FLAGS(); - m_vflag[2][0] = ((RTVAL >> 0) & 1) ? 0xffff : 0; - m_vflag[2][1] = ((RTVAL >> 1) & 1) ? 0xffff : 0; - m_vflag[2][2] = ((RTVAL >> 2) & 1) ? 0xffff : 0; - m_vflag[2][3] = ((RTVAL >> 3) & 1) ? 0xffff : 0; - m_vflag[2][4] = ((RTVAL >> 4) & 1) ? 0xffff : 0; - m_vflag[2][5] = ((RTVAL >> 5) & 1) ? 0xffff : 0; - m_vflag[2][6] = ((RTVAL >> 6) & 1) ? 0xffff : 0; - m_vflag[2][7] = ((RTVAL >> 7) & 1) ? 0xffff : 0; - if (RTVAL & (1 << 0)) { SET_CLIP1_FLAG(0); } - if (RTVAL & (1 << 1)) { SET_CLIP1_FLAG(1); } - if (RTVAL & (1 << 2)) { SET_CLIP1_FLAG(2); } - if (RTVAL & (1 << 3)) { SET_CLIP1_FLAG(3); } - if (RTVAL & (1 << 4)) { SET_CLIP1_FLAG(4); } - if (RTVAL & (1 << 5)) { SET_CLIP1_FLAG(5); } - if (RTVAL & (1 << 6)) { SET_CLIP1_FLAG(6); } - if (RTVAL & (1 << 7)) { SET_CLIP1_FLAG(7); } - break; - } -} - -void rsp_device::cop2::log_instruction_execution() -{ - static VECTOR_REG prev_vecs[32]; - - for (int i = 0; i < 32; i++) - { - if (m_v[i].d[0] != prev_vecs[i].d[0] || m_v[i].d[1] != prev_vecs[i].d[1]) - { - fprintf(m_rsp.m_exec_output, "V%d: %04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X ", i, - (uint16_t)VREG_S(i,0), (uint16_t)VREG_S(i,1), (uint16_t)VREG_S(i,2), (uint16_t)VREG_S(i,3), (uint16_t)VREG_S(i,4), (uint16_t)VREG_S(i,5), (uint16_t)VREG_S(i,6), (uint16_t)VREG_S(i,7)); - } - prev_vecs[i].d[0] = m_v[i].d[0]; - prev_vecs[i].d[1] = m_v[i].d[1]; - } -} - -void rsp_device::cop2::dump(uint32_t op) -{ - printf("%08x ", op); - for (int i = 0; i < 32; i++) - { - printf("%08x ", m_rsp.m_rsp_state->r[i]); - } - printf("\n"); - - for (int i = 0; i < 32; i++) - { - printf("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", VREG_B(i, 0), VREG_B(i, 1), VREG_B(i, 2), VREG_B(i, 3), VREG_B(i, 4), VREG_B(i, 5), VREG_B(i, 6), VREG_B(i, 7), VREG_B(i, 8), VREG_B(i, 9), VREG_B(i, 10), VREG_B(i, 11), VREG_B(i, 12), VREG_B(i, 13), VREG_B(i, 14), VREG_B(i, 15)); - } - -#if USE_SIMD - printf("acc_h: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_acc.s[0], m_acc.s[1], m_acc.s[2], m_acc.s[3], m_acc.s[4], m_acc.s[5], m_acc.s[6], m_acc.s[7]); - printf("acc_m: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_acc.s[8], m_acc.s[9], m_acc.s[10], m_acc.s[11], m_acc.s[12], m_acc.s[13], m_acc.s[14], m_acc.s[15]); - printf("acc_l: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_acc.s[16], m_acc.s[17], m_acc.s[18], m_acc.s[19], m_acc.s[20], m_acc.s[21], m_acc.s[22], m_acc.s[23]); - printf("vcc_hi: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_flags[RSP_VCC].s[0], m_flags[RSP_VCC].s[1], m_flags[RSP_VCC].s[2], m_flags[RSP_VCC].s[3], m_flags[RSP_VCC].s[4], m_flags[RSP_VCC].s[5], m_flags[RSP_VCC].s[6], m_flags[RSP_VCC].s[7]); - printf("vcc_lo: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_flags[RSP_VCC].s[8], m_flags[RSP_VCC].s[9], m_flags[RSP_VCC].s[10], m_flags[RSP_VCC].s[11], m_flags[RSP_VCC].s[12], m_flags[RSP_VCC].s[13], m_flags[RSP_VCC].s[14], m_flags[RSP_VCC].s[15]); - printf("vco_hi: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_flags[RSP_VCO].s[0], m_flags[RSP_VCO].s[1], m_flags[RSP_VCO].s[2], m_flags[RSP_VCO].s[3], m_flags[RSP_VCO].s[4], m_flags[RSP_VCO].s[5], m_flags[RSP_VCO].s[6], m_flags[RSP_VCO].s[7]); - printf("vco_lo: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_flags[RSP_VCO].s[8], m_flags[RSP_VCO].s[9], m_flags[RSP_VCO].s[10], m_flags[RSP_VCO].s[11], m_flags[RSP_VCO].s[12], m_flags[RSP_VCO].s[13], m_flags[RSP_VCO].s[14], m_flags[RSP_VCO].s[15]); - printf("vce: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_flags[RSP_VCE].s[0], m_flags[RSP_VCE].s[1], m_flags[RSP_VCE].s[2], m_flags[RSP_VCE].s[3], m_flags[RSP_VCE].s[4], m_flags[RSP_VCE].s[5], m_flags[RSP_VCE].s[6], m_flags[RSP_VCE].s[7]); -#else - printf("acc_h: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", ACCUM_H(0), ACCUM_H(1), ACCUM_H(2), ACCUM_H(3), ACCUM_H(4), ACCUM_H(5), ACCUM_H(6), ACCUM_H(7)); - printf("acc_m: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", ACCUM_M(0), ACCUM_M(1), ACCUM_M(2), ACCUM_M(3), ACCUM_M(4), ACCUM_M(5), ACCUM_M(6), ACCUM_M(7)); - printf("acc_l: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", ACCUM_L(0), ACCUM_L(1), ACCUM_L(2), ACCUM_L(3), ACCUM_L(4), ACCUM_L(5), ACCUM_L(6), ACCUM_L(7)); - printf("vcc_hi: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_vflag[4][0], m_vflag[4][1], m_vflag[4][2], m_vflag[4][3], m_vflag[4][4], m_vflag[4][5], m_vflag[4][6], m_vflag[4][7]); - printf("vcc_lo: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_vflag[1][0], m_vflag[1][1], m_vflag[1][2], m_vflag[1][3], m_vflag[1][4], m_vflag[1][5], m_vflag[1][6], m_vflag[1][7]); - printf("vco_hi: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_vflag[3][0], m_vflag[3][1], m_vflag[3][2], m_vflag[3][3], m_vflag[3][4], m_vflag[3][5], m_vflag[3][6], m_vflag[3][7]); - printf("vco_lo: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_vflag[0][0], m_vflag[0][1], m_vflag[0][2], m_vflag[0][3], m_vflag[0][4], m_vflag[0][5], m_vflag[0][6], m_vflag[0][7]); - printf("vce: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_vflag[2][0], m_vflag[2][1], m_vflag[2][2], m_vflag[2][3], m_vflag[2][4], m_vflag[2][5], m_vflag[2][6], m_vflag[2][7]); -#endif -} - -void rsp_device::cop2::dump_dmem() -{ - uint8_t* dmem = m_rsp.get_dmem(); - printf("\n"); - for (int i = 0; i < 0x1000; i += 32) - { - printf("%04x: ", i); - for (int j = 0; j < 32; j++) - { - printf("%02x ", dmem[i + j]); - } - printf("\n"); - } - printf("\n"); -} diff --git a/src/devices/cpu/rsp/rspcp2.h b/src/devices/cpu/rsp/rspcp2.h deleted file mode 100644 index 7e374e71ae3..00000000000 --- a/src/devices/cpu/rsp/rspcp2.h +++ /dev/null @@ -1,395 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Ryan Holtz,Tyler J. Stachecki -/*************************************************************************** - - rspcp2.h - - Interface file for Reality Signal Processor (RSP) vector extensions. - -***************************************************************************/ -#ifndef MAME_CPU_RSP_RSPCP2_H -#define MAME_CPU_RSP_RSPCP2_H - -#pragma once - -#include "rsp.h" -#include "rspdiv.h" -#include "cpu/drcuml.h" - -#define SIMD_OFF (1) - -#if (defined(__SSE2__) || defined(__SSE3__) || defined(__SSSE3__) || defined(__SSE4_1__) || defined(__SSE4_2__)) -#define SSE_AVAILABLE (1) -#else -#define SSE_AVAILABLE (0) -#endif - -#if (SSE_AVAILABLE || defined(_MSC_VER)) && defined(PTR64) && !SIMD_OFF -#define USE_SIMD (1) -#else -#define USE_SIMD (0) -#endif - -#if USE_SIMD - -#ifdef _MSC_VER -#define __align16 __declspec(align(16)) -#else -#define __align16 __attribute__((aligned(16))) -#endif - -#if (defined(__SSE4_2__) || defined(_MSC_VER)) -#include <nmmintrin.h> -#elif (defined(__SSE4_1__) || defined(_MSC_VER)) -#include <smmintrin.h> -#elif (defined(__SSSE3__) || defined(_MSC_VER)) -#include <tmmintrin.h> -#elif (defined(__SSE3__ ) || defined(_MSC_VER)) -#include <pmmintrin.h> -#else -#include <emmintrin.h> -#endif - -typedef __m128i rsp_vec_t; -#endif - -union VECTOR_REG -{ - uint64_t d[2]; - uint32_t l[4]; - uint16_t s[8]; - uint8_t b[16]; -#if USE_SIMD - rsp_vec_t v; -#endif -}; - -union ACCUMULATOR_REG -{ - uint64_t q; - uint32_t l[2]; - uint16_t w[4]; -}; - -struct compiler_state; - -class rsp_device::cop2 -{ - friend class rsp_device; - -public: - cop2(rsp_device &rsp, running_machine &machine); - -protected: - virtual void init(); - virtual void start(); - - virtual bool generate_cop2(drcuml_block &block, rsp_device::compiler_state &compiler, const opcode_desc *desc) { return true; } - virtual bool generate_lwc2(drcuml_block &block, rsp_device::compiler_state &compiler, const opcode_desc *desc) { return true; } - virtual bool generate_swc2(drcuml_block &block, rsp_device::compiler_state &compiler, const opcode_desc *desc) { return true; } - - virtual void state_string_export(const int index, std::string &str) const; - -public: - virtual ~cop2(); - - virtual void lbv() { } - virtual void lsv() { } - virtual void llv() { } - virtual void ldv() { } - virtual void lqv() { } - virtual void lrv() { } - virtual void lpv() { } - virtual void luv() { } - virtual void lhv() { } - virtual void lfv() { } - virtual void lwv() { } - virtual void ltv() { } - virtual void sbv() { } - virtual void ssv() { } - virtual void slv() { } - virtual void sdv() { } - virtual void sqv() { } - virtual void srv() { } - virtual void spv() { } - virtual void suv() { } - virtual void shv() { } - virtual void sfv() { } - virtual void swv() { } - virtual void stv() { } - virtual void vmulf() { } - virtual void vmulu() { } - virtual void vmudl() { } - virtual void vmudm() { } - virtual void vmudn() { } - virtual void vmudh() { } - virtual void vmacf() { } - virtual void vmacu() { } - virtual void vmadl() { } - virtual void vmadm() { } - virtual void vmadn() { } - virtual void vmadh() { } - virtual void vadd() { } - virtual void vsub() { } - virtual void vabs() { } - virtual void vaddc() { } - virtual void vsubc() { } - virtual void vaddb() { } - virtual void vsaw() { } - virtual void vlt() { } - virtual void veq() { } - virtual void vne() { } - virtual void vge() { } - virtual void vcl() { } - virtual void vch() { } - virtual void vcr() { } - virtual void vmrg() { } - virtual void vand() { } - virtual void vnand() { } - virtual void vor() { } - virtual void vnor() { } - virtual void vxor() { } - virtual void vnxor() { } - virtual void vrcp() { } - virtual void vrcpl() { } - virtual void vrcph() { } - virtual void vmov() { } - virtual void vrsql() { } - virtual void vrsqh() { } - virtual void vrsq() { } - virtual void mfc2(); - virtual void cfc2(); - virtual void mtc2(); - virtual void ctc2(); - - virtual void handle_cop2(uint32_t op); - - void log_instruction_execution(); - virtual void cfunc_unimplemented_opcode() { } - - void dump(uint32_t op); - void dump_dmem(); - -protected: - virtual bool generate_vector_opcode(drcuml_block &block, rsp_device::compiler_state &compiler, const opcode_desc *desc) { return true; } - - uint16_t SATURATE_ACCUM(int accum, int slice, uint16_t negative, uint16_t positive); - - // Data that needs to be stored close to the generated DRC code - struct internal_rspcop2_state - { - uint32_t op; - }; - - internal_rspcop2_state *m_rspcop2_state; - rsp_device& m_rsp; - running_machine& m_machine; - uint32_t m_vres[8]; /* used for temporary vector results */ - -#if USE_SIMD - __align16 VECTOR_REG m_v[32]; -#else - VECTOR_REG m_v[32]; -#endif - ACCUMULATOR_REG m_accum[8]; - uint16_t m_vflag[6][8]; - - int32_t m_reciprocal_res; - uint32_t m_reciprocal_high; - int32_t m_dp_allowed; - -#if USE_SIMD - enum rsp_flags_t { - RSP_VCO = 0, - RSP_VCC = 1, - RSP_VCE = 2 - }; - - enum rsp_acc_t { - RSP_ACC_LO = 16, - RSP_ACC_MD = 8, - RSP_ACC_HI = 0, - }; - - enum rsp_mem_request_type { - RSP_MEM_REQUEST_NONE, - RSP_MEM_REQUEST_INT_MEM, - RSP_MEM_REQUEST_VECTOR, - RSP_MEM_REQUEST_FOURTH, - RSP_MEM_REQUEST_HALF, - RSP_MEM_REQUEST_PACK, - RSP_MEM_REQUEST_QUAD, - RSP_MEM_REQUEST_REST, - RSP_MEM_REQUEST_UPACK - }; - - union aligned_rsp_1vect_t { - rsp_vec_t __align; - uint16_t s[8]; - }; - - union aligned_rsp_2vect_t { - rsp_vec_t __align[2]; - uint16_t s[16]; - }; - - union aligned_rsp_3vect_t { - rsp_vec_t __align[3]; - uint16_t s[24]; - }; - - __align16 aligned_rsp_1vect_t m_vdqm; - __align16 aligned_rsp_2vect_t m_flags[3]; - __align16 aligned_rsp_3vect_t m_acc; - uint32_t m_dp_flag; - - typedef struct - { - rsp_vec_t dummy_for_alignment; - const uint16_t logic_mask[2][8]; - const uint16_t vrsq_mask_table[8][8]; - const uint16_t shuffle_keys[16][8]; - const uint16_t sll_b2l_keys[16][8]; - const uint16_t sll_l2b_keys[16][8]; - const uint16_t srl_b2l_keys[16][8]; - const uint16_t ror_b2l_keys[16][8]; - const uint16_t rol_l2b_keys[16][8]; - const uint16_t ror_l2b_keys[16][8]; - const uint16_t qr_lut[16][8]; - const uint16_t bdls_lut[4][4]; - const uint16_t word_reverse[8]; - } vec_helpers_t; - - static const vec_helpers_t m_vec_helpers; - - rsp_vec_t vec_load_and_shuffle_operand(const uint16_t* src, uint32_t element); - static inline uint32_t sign_extend_6(int32_t i) { - return ((i << (32 - 7)) >> (32 - 7)) & 0xfff; - } - static inline rsp_vec_t vec_load_unshuffled_operand(const void* src) - { - return _mm_load_si128((rsp_vec_t*) src); - } - static inline void vec_write_operand(uint16_t* dest, rsp_vec_t src) - { - _mm_store_si128((rsp_vec_t*) dest, src); - } - static inline rsp_vec_t read_acc_lo(const uint16_t* acc) - { - return vec_load_unshuffled_operand(acc + sizeof(rsp_vec_t)); - } - static inline rsp_vec_t read_acc_mid(const uint16_t* acc) - { - return vec_load_unshuffled_operand(acc + (sizeof(rsp_vec_t) >> 1)); - } - static inline rsp_vec_t read_acc_hi(const void* acc) - { - return vec_load_unshuffled_operand(acc); - } - static inline rsp_vec_t read_vcc_lo(const uint16_t *vcc) - { - return vec_load_unshuffled_operand(vcc + (sizeof(rsp_vec_t) >> 1)); - } - static inline rsp_vec_t read_vcc_hi(const uint16_t *vcc) - { - return vec_load_unshuffled_operand(vcc); - } - static inline rsp_vec_t read_vco_lo(const uint16_t *vco) - { - return vec_load_unshuffled_operand(vco + (sizeof(rsp_vec_t) >> 1)); - } - static inline rsp_vec_t read_vco_hi(const uint16_t *vco) - { - return vec_load_unshuffled_operand(vco); - } - static inline rsp_vec_t read_vce(const uint16_t *vce) - { - return vec_load_unshuffled_operand(vce + (sizeof(rsp_vec_t) >> 1)); - } - static inline void write_acc_lo(uint16_t *acc, rsp_vec_t acc_lo) - { - return vec_write_operand(acc + sizeof(rsp_vec_t), acc_lo); - } - static inline void write_acc_mid(uint16_t *acc, rsp_vec_t acc_mid) - { - return vec_write_operand(acc + (sizeof(rsp_vec_t) >> 1), acc_mid); - } - static inline void write_acc_hi(uint16_t *acc, rsp_vec_t acc_hi) - { - return vec_write_operand(acc, acc_hi); - } - static inline void write_vcc_lo(uint16_t *vcc, rsp_vec_t vcc_lo) - { - return vec_write_operand(vcc + (sizeof(rsp_vec_t) >> 1), vcc_lo); - } - static inline void write_vcc_hi(uint16_t *vcc, rsp_vec_t vcc_hi) - { - return vec_write_operand(vcc, vcc_hi); - } - static inline void write_vco_lo(uint16_t *vcc, rsp_vec_t vco_lo) - { - return vec_write_operand(vcc + (sizeof(rsp_vec_t) >> 1), vco_lo); - } - static inline void write_vco_hi(uint16_t *vcc, rsp_vec_t vco_hi) - { - return vec_write_operand(vcc, vco_hi); - } - static inline void write_vce(uint16_t *vce, rsp_vec_t vce_r) - { - return vec_write_operand(vce + (sizeof(rsp_vec_t) >> 1), vce_r); - } - - static inline int16_t get_flags(const uint16_t *flags) - { - return _mm_movemask_epi8(_mm_packs_epi16(_mm_load_si128((rsp_vec_t*) (flags + (sizeof(rsp_vec_t) >> 1))), _mm_load_si128((rsp_vec_t*) flags))); - } - - static inline rsp_vec_t vec_zero() - { - return _mm_setzero_si128(); - } - - void vec_load_group1(uint32_t addr, uint32_t element, uint16_t* regp, rsp_vec_t reg, rsp_vec_t dqm); - void vec_load_group2(uint32_t addr, uint32_t element, uint16_t* regp, rsp_vec_t reg, rsp_vec_t dqm, rsp_mem_request_type request_type); - void vec_load_group4(uint32_t addr, uint32_t element, uint16_t* regp, rsp_vec_t reg, rsp_vec_t dqm, rsp_mem_request_type request_type); - void vec_store_group1(uint32_t addr, uint32_t element, uint16_t* regp, rsp_vec_t reg, rsp_vec_t dqm); - void vec_store_group2(uint32_t addr, uint32_t element, uint16_t* regp, rsp_vec_t reg, rsp_vec_t dqm, rsp_mem_request_type request_type); - void vec_store_group4(uint32_t addr, uint32_t element, uint16_t* regp, rsp_vec_t reg, rsp_vec_t dqm, rsp_mem_request_type request_type); - -#include "clamp.h" -#include "vabs.h" -#include "vadd.h" -#include "vaddc.h" -#include "vand.h" -#include "vch.h" -#include "vcmp.h" -#include "vcl.h" -#include "vcr.h" -#include "vdivh.h" -#include "vmac.h" -#include "vmov.h" -#include "vmrg.h" -#include "vmul.h" -#include "vmulh.h" -#include "vmull.h" -#include "vmulm.h" -#include "vmuln.h" -#include "vor.h" -#include "vrcpsq.h" -#include "vrsq.h" -#include "vsub.h" -#include "vsubc.h" -#include "vxor.h" -#include "vldst.h" -#endif - -private: - void handle_lwc2(uint32_t op); - void handle_swc2(uint32_t op); - void handle_vector_ops(uint32_t op); - - uint32_t m_div_in; - uint32_t m_div_out; -}; - -#endif // MAME_CPU_RSP_RSPCP2_H diff --git a/src/devices/cpu/rsp/rspcp2d.cpp b/src/devices/cpu/rsp/rspcp2d.cpp deleted file mode 100644 index a77ab072cab..00000000000 --- a/src/devices/cpu/rsp/rspcp2d.cpp +++ /dev/null @@ -1,3388 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Ryan Holtz -/*************************************************************************** - - rspcp2d.c - - Universal machine language-based Nintendo/SGI RSP COP2 emulator. - Written by Ryan Holtz - -***************************************************************************/ - -#include "emu.h" -#include "rspcp2d.h" - -#include "rsp_dasm.h" - -#include "cpu/drcfe.h" -#include "cpu/drcuml.h" -#include "cpu/drcumlsh.h" - -#include "rspdefs.h" - - -/*************************************************************************** - Helpful Defines -***************************************************************************/ - -#define VDREG ((op >> 6) & 0x1f) -#define VS1REG ((op >> 11) & 0x1f) -#define VS2REG ((op >> 16) & 0x1f) -#define EL ((op >> 21) & 0xf) - -#define RSVAL (m_rsp.m_rsp_state->r[RSREG]) -#define RTVAL (m_rsp.m_rsp_state->r[RTREG]) -#define RDVAL (m_rsp.m_rsp_state->r[RDREG]) - -#define VREG_B(reg, offset) m_v[(reg)].b[(offset)^1] -#define W_VREG_S(reg, offset) m_v[(reg)].s[(offset)] -#define VREG_S(reg, offset) (int16_t)m_v[(reg)].s[(offset)] - -#define VEC_EL_2(x,z) (vector_elements_2[(x)][(z)]) - -#define ACCUM(x) m_accum[x].q - -#define CARRY 0 -#define COMPARE 1 -#define CLIP1 2 -#define ZERO 3 -#define CLIP2 4 - -#define ACCUM_H(x) (uint16_t)m_accum[x].w[3] -#define ACCUM_M(x) (uint16_t)m_accum[x].w[2] -#define ACCUM_L(x) (uint16_t)m_accum[x].w[1] -#define ACCUM_LL(x) (uint16_t)m_accum[x].w[0] -#define ACCUM(x) m_accum[x].q - -#define SET_ACCUM_H(v, x) m_accum[x].w[3] = v; -#define SET_ACCUM_M(v, x) m_accum[x].w[2] = v; -#define SET_ACCUM_L(v, x) m_accum[x].w[1] = v; -#define SET_ACCUM_LL(v, x) m_accum[x].w[0] = v; -#define SET_ACCUM(v, x) m_accum[x].q = v; - -#define GET_VS1(out, i) out = VREG_S(vs1reg, i) -#define GET_VS2(out, i) out = VREG_S(vs2reg, VEC_EL_2(el, i)) - -#define CARRY_FLAG(x) (m_vflag[CARRY][x & 7] != 0 ? 0xffff : 0) -#define COMPARE_FLAG(x) (m_vflag[COMPARE][x & 7] != 0 ? 0xffff : 0) -#define CLIP1_FLAG(x) (m_vflag[CLIP1][x & 7] != 0 ? 0xffff : 0) -#define ZERO_FLAG(x) (m_vflag[ZERO][x & 7] != 0 ? 0xffff : 0) -#define CLIP2_FLAG(x) (m_vflag[CLIP2][x & 7] != 0 ? 0xffff : 0) - -#define CLEAR_CARRY_FLAGS() { memset(m_vflag[CARRY], 0, 16); } -#define CLEAR_COMPARE_FLAGS() { memset(m_vflag[COMPARE], 0, 16); } -#define CLEAR_CLIP1_FLAGS() { memset(m_vflag[CLIP1], 0, 16); } -#define CLEAR_ZERO_FLAGS() { memset(m_vflag[ZERO], 0, 16); } -#define CLEAR_CLIP2_FLAGS() { memset(m_vflag[CLIP2], 0, 16); } - -#define SET_CARRY_FLAG(x) { m_vflag[CARRY][x & 7] = 0xffff; } -#define SET_COMPARE_FLAG(x) { m_vflag[COMPARE][x & 7] = 0xffff; } -#define SET_CLIP1_FLAG(x) { m_vflag[CLIP1][x & 7] = 0xffff; } -#define SET_ZERO_FLAG(x) { m_vflag[ZERO][x & 7] = 0xffff; } -#define SET_CLIP2_FLAG(x) { m_vflag[CLIP2][x & 7] = 0xffff; } - -#define CLEAR_CARRY_FLAG(x) { m_vflag[CARRY][x & 7] = 0; } -#define CLEAR_COMPARE_FLAG(x) { m_vflag[COMPARE][x & 7] = 0; } -#define CLEAR_CLIP1_FLAG(x) { m_vflag[CLIP1][x & 7] = 0; } -#define CLEAR_ZERO_FLAG(x) { m_vflag[ZERO][x & 7] = 0; } -#define CLEAR_CLIP2_FLAG(x) { m_vflag[CLIP2][x & 7] = 0; } - -#define CACHE_VALUES() \ - const int op = m_rspcop2_state->op; \ - const int vdreg = VDREG; \ - const int vs1reg = VS1REG; \ - const int vs2reg = VS2REG; \ - const int el = EL; - -#define WRITEBACK_RESULT() { \ - W_VREG_S(vdreg, 0) = m_vres[0]; \ - W_VREG_S(vdreg, 1) = m_vres[1]; \ - W_VREG_S(vdreg, 2) = m_vres[2]; \ - W_VREG_S(vdreg, 3) = m_vres[3]; \ - W_VREG_S(vdreg, 4) = m_vres[4]; \ - W_VREG_S(vdreg, 5) = m_vres[5]; \ - W_VREG_S(vdreg, 6) = m_vres[6]; \ - W_VREG_S(vdreg, 7) = m_vres[7]; \ -} - -static const int vector_elements_2[16][8] = -{ - { 0, 1, 2, 3, 4, 5, 6, 7 }, // none - { 0, 1, 2, 3, 4, 5, 6, 7 }, // ??? - { 0, 0, 2, 2, 4, 4, 6, 6 }, // 0q - { 1, 1, 3, 3, 5, 5, 7, 7 }, // 1q - { 0, 0, 0, 0, 4, 4, 4, 4 }, // 0h - { 1, 1, 1, 1, 5, 5, 5, 5 }, // 1h - { 2, 2, 2, 2, 6, 6, 6, 6 }, // 2h - { 3, 3, 3, 3, 7, 7, 7, 7 }, // 3h - { 0, 0, 0, 0, 0, 0, 0, 0 }, // 0 - { 1, 1, 1, 1, 1, 1, 1, 1 }, // 1 - { 2, 2, 2, 2, 2, 2, 2, 2 }, // 2 - { 3, 3, 3, 3, 3, 3, 3, 3 }, // 3 - { 4, 4, 4, 4, 4, 4, 4, 4 }, // 4 - { 5, 5, 5, 5, 5, 5, 5, 5 }, // 5 - { 6, 6, 6, 6, 6, 6, 6, 6 }, // 6 - { 7, 7, 7, 7, 7, 7, 7, 7 }, // 7 -}; - -void rsp_device::cop2_drc::cfunc_unimplemented_opcode() -{ - const uint32_t ppc = m_rsp.m_ppc; - if ((m_machine.debug_flags & DEBUG_FLAG_ENABLED) != 0) - { - rsp_disassembler rspd; - std::ostringstream stream; - rspd.dasm_one(stream, ppc, m_rspcop2_state->op); - const std::string stream_string = stream.str(); - osd_printf_debug("%08X: %s\n", ppc, stream_string); - } - fatalerror("RSP: unknown opcode %02X (%08X) at %08X\n", m_rspcop2_state->op >> 26, m_rspcop2_state->op, ppc); -} - -void rsp_device::cop2_drc::state_string_export(const int index, std::string &str) const -{ - switch (index) - { - case RSP_V0: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S( 0, 0), (uint16_t)VREG_S( 0, 1), (uint16_t)VREG_S( 0, 2), (uint16_t)VREG_S( 0, 3), (uint16_t)VREG_S( 0, 4), (uint16_t)VREG_S( 0, 5), (uint16_t)VREG_S( 0, 6), (uint16_t)VREG_S( 0, 7)); - break; - case RSP_V1: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S( 1, 0), (uint16_t)VREG_S( 1, 1), (uint16_t)VREG_S( 1, 2), (uint16_t)VREG_S( 1, 3), (uint16_t)VREG_S( 1, 4), (uint16_t)VREG_S( 1, 5), (uint16_t)VREG_S( 1, 6), (uint16_t)VREG_S( 1, 7)); - break; - case RSP_V2: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S( 2, 0), (uint16_t)VREG_S( 2, 1), (uint16_t)VREG_S( 2, 2), (uint16_t)VREG_S( 2, 3), (uint16_t)VREG_S( 2, 4), (uint16_t)VREG_S( 2, 5), (uint16_t)VREG_S( 2, 6), (uint16_t)VREG_S( 2, 7)); - break; - case RSP_V3: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S( 3, 0), (uint16_t)VREG_S( 3, 1), (uint16_t)VREG_S( 3, 2), (uint16_t)VREG_S( 3, 3), (uint16_t)VREG_S( 3, 4), (uint16_t)VREG_S( 3, 5), (uint16_t)VREG_S( 3, 6), (uint16_t)VREG_S( 3, 7)); - break; - case RSP_V4: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S( 4, 0), (uint16_t)VREG_S( 4, 1), (uint16_t)VREG_S( 4, 2), (uint16_t)VREG_S( 4, 3), (uint16_t)VREG_S( 4, 4), (uint16_t)VREG_S( 4, 5), (uint16_t)VREG_S( 4, 6), (uint16_t)VREG_S( 4, 7)); - break; - case RSP_V5: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S( 5, 0), (uint16_t)VREG_S( 5, 1), (uint16_t)VREG_S( 5, 2), (uint16_t)VREG_S( 5, 3), (uint16_t)VREG_S( 5, 4), (uint16_t)VREG_S( 5, 5), (uint16_t)VREG_S( 5, 6), (uint16_t)VREG_S( 5, 7)); - break; - case RSP_V6: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S( 6, 0), (uint16_t)VREG_S( 6, 1), (uint16_t)VREG_S( 6, 2), (uint16_t)VREG_S( 6, 3), (uint16_t)VREG_S( 6, 4), (uint16_t)VREG_S( 6, 5), (uint16_t)VREG_S( 6, 6), (uint16_t)VREG_S( 6, 7)); - break; - case RSP_V7: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S( 7, 0), (uint16_t)VREG_S( 7, 1), (uint16_t)VREG_S( 7, 2), (uint16_t)VREG_S( 7, 3), (uint16_t)VREG_S( 7, 4), (uint16_t)VREG_S( 7, 5), (uint16_t)VREG_S( 7, 6), (uint16_t)VREG_S( 7, 7)); - break; - case RSP_V8: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S( 8, 0), (uint16_t)VREG_S( 8, 1), (uint16_t)VREG_S( 8, 2), (uint16_t)VREG_S( 8, 3), (uint16_t)VREG_S( 8, 4), (uint16_t)VREG_S( 8, 5), (uint16_t)VREG_S( 8, 6), (uint16_t)VREG_S( 8, 7)); - break; - case RSP_V9: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S( 9, 0), (uint16_t)VREG_S( 9, 1), (uint16_t)VREG_S( 9, 2), (uint16_t)VREG_S( 9, 3), (uint16_t)VREG_S( 9, 4), (uint16_t)VREG_S( 9, 5), (uint16_t)VREG_S( 9, 6), (uint16_t)VREG_S( 9, 7)); - break; - case RSP_V10: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(10, 0), (uint16_t)VREG_S(10, 1), (uint16_t)VREG_S(10, 2), (uint16_t)VREG_S(10, 3), (uint16_t)VREG_S(10, 4), (uint16_t)VREG_S(10, 5), (uint16_t)VREG_S(10, 6), (uint16_t)VREG_S(10, 7)); - break; - case RSP_V11: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(11, 0), (uint16_t)VREG_S(11, 1), (uint16_t)VREG_S(11, 2), (uint16_t)VREG_S(11, 3), (uint16_t)VREG_S(11, 4), (uint16_t)VREG_S(11, 5), (uint16_t)VREG_S(11, 6), (uint16_t)VREG_S(11, 7)); - break; - case RSP_V12: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(12, 0), (uint16_t)VREG_S(12, 1), (uint16_t)VREG_S(12, 2), (uint16_t)VREG_S(12, 3), (uint16_t)VREG_S(12, 4), (uint16_t)VREG_S(12, 5), (uint16_t)VREG_S(12, 6), (uint16_t)VREG_S(12, 7)); - break; - case RSP_V13: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(13, 0), (uint16_t)VREG_S(13, 1), (uint16_t)VREG_S(13, 2), (uint16_t)VREG_S(13, 3), (uint16_t)VREG_S(13, 4), (uint16_t)VREG_S(13, 5), (uint16_t)VREG_S(13, 6), (uint16_t)VREG_S(13, 7)); - break; - case RSP_V14: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(14, 0), (uint16_t)VREG_S(14, 1), (uint16_t)VREG_S(14, 2), (uint16_t)VREG_S(14, 3), (uint16_t)VREG_S(14, 4), (uint16_t)VREG_S(14, 5), (uint16_t)VREG_S(14, 6), (uint16_t)VREG_S(14, 7)); - break; - case RSP_V15: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(15, 0), (uint16_t)VREG_S(15, 1), (uint16_t)VREG_S(15, 2), (uint16_t)VREG_S(15, 3), (uint16_t)VREG_S(15, 4), (uint16_t)VREG_S(15, 5), (uint16_t)VREG_S(15, 6), (uint16_t)VREG_S(15, 7)); - break; - case RSP_V16: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(16, 0), (uint16_t)VREG_S(16, 1), (uint16_t)VREG_S(16, 2), (uint16_t)VREG_S(16, 3), (uint16_t)VREG_S(16, 4), (uint16_t)VREG_S(16, 5), (uint16_t)VREG_S(16, 6), (uint16_t)VREG_S(16, 7)); - break; - case RSP_V17: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(17, 0), (uint16_t)VREG_S(17, 1), (uint16_t)VREG_S(17, 2), (uint16_t)VREG_S(17, 3), (uint16_t)VREG_S(17, 4), (uint16_t)VREG_S(17, 5), (uint16_t)VREG_S(17, 6), (uint16_t)VREG_S(17, 7)); - break; - case RSP_V18: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(18, 0), (uint16_t)VREG_S(18, 1), (uint16_t)VREG_S(18, 2), (uint16_t)VREG_S(18, 3), (uint16_t)VREG_S(18, 4), (uint16_t)VREG_S(18, 5), (uint16_t)VREG_S(18, 6), (uint16_t)VREG_S(18, 7)); - break; - case RSP_V19: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(19, 0), (uint16_t)VREG_S(19, 1), (uint16_t)VREG_S(19, 2), (uint16_t)VREG_S(19, 3), (uint16_t)VREG_S(19, 4), (uint16_t)VREG_S(19, 5), (uint16_t)VREG_S(19, 6), (uint16_t)VREG_S(19, 7)); - break; - case RSP_V20: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(20, 0), (uint16_t)VREG_S(20, 1), (uint16_t)VREG_S(20, 2), (uint16_t)VREG_S(20, 3), (uint16_t)VREG_S(20, 4), (uint16_t)VREG_S(20, 5), (uint16_t)VREG_S(20, 6), (uint16_t)VREG_S(20, 7)); - break; - case RSP_V21: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(21, 0), (uint16_t)VREG_S(21, 1), (uint16_t)VREG_S(21, 2), (uint16_t)VREG_S(21, 3), (uint16_t)VREG_S(21, 4), (uint16_t)VREG_S(21, 5), (uint16_t)VREG_S(21, 6), (uint16_t)VREG_S(21, 7)); - break; - case RSP_V22: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(22, 0), (uint16_t)VREG_S(22, 1), (uint16_t)VREG_S(22, 2), (uint16_t)VREG_S(22, 3), (uint16_t)VREG_S(22, 4), (uint16_t)VREG_S(22, 5), (uint16_t)VREG_S(22, 6), (uint16_t)VREG_S(22, 7)); - break; - case RSP_V23: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(23, 0), (uint16_t)VREG_S(23, 1), (uint16_t)VREG_S(23, 2), (uint16_t)VREG_S(23, 3), (uint16_t)VREG_S(23, 4), (uint16_t)VREG_S(23, 5), (uint16_t)VREG_S(23, 6), (uint16_t)VREG_S(23, 7)); - break; - case RSP_V24: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(24, 0), (uint16_t)VREG_S(24, 1), (uint16_t)VREG_S(24, 2), (uint16_t)VREG_S(24, 3), (uint16_t)VREG_S(24, 4), (uint16_t)VREG_S(24, 5), (uint16_t)VREG_S(24, 6), (uint16_t)VREG_S(24, 7)); - break; - case RSP_V25: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(25, 0), (uint16_t)VREG_S(25, 1), (uint16_t)VREG_S(25, 2), (uint16_t)VREG_S(25, 3), (uint16_t)VREG_S(25, 4), (uint16_t)VREG_S(25, 5), (uint16_t)VREG_S(25, 6), (uint16_t)VREG_S(25, 7)); - break; - case RSP_V26: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(26, 0), (uint16_t)VREG_S(26, 1), (uint16_t)VREG_S(26, 2), (uint16_t)VREG_S(26, 3), (uint16_t)VREG_S(26, 4), (uint16_t)VREG_S(26, 5), (uint16_t)VREG_S(26, 6), (uint16_t)VREG_S(26, 7)); - break; - case RSP_V27: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(27, 0), (uint16_t)VREG_S(27, 1), (uint16_t)VREG_S(27, 2), (uint16_t)VREG_S(27, 3), (uint16_t)VREG_S(27, 4), (uint16_t)VREG_S(27, 5), (uint16_t)VREG_S(27, 6), (uint16_t)VREG_S(27, 7)); - break; - case RSP_V28: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(28, 0), (uint16_t)VREG_S(28, 1), (uint16_t)VREG_S(28, 2), (uint16_t)VREG_S(28, 3), (uint16_t)VREG_S(28, 4), (uint16_t)VREG_S(28, 5), (uint16_t)VREG_S(28, 6), (uint16_t)VREG_S(28, 7)); - break; - case RSP_V29: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(29, 0), (uint16_t)VREG_S(29, 1), (uint16_t)VREG_S(29, 2), (uint16_t)VREG_S(29, 3), (uint16_t)VREG_S(29, 4), (uint16_t)VREG_S(29, 5), (uint16_t)VREG_S(29, 6), (uint16_t)VREG_S(29, 7)); - break; - case RSP_V30: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(30, 0), (uint16_t)VREG_S(30, 1), (uint16_t)VREG_S(30, 2), (uint16_t)VREG_S(30, 3), (uint16_t)VREG_S(30, 4), (uint16_t)VREG_S(30, 5), (uint16_t)VREG_S(30, 6), (uint16_t)VREG_S(30, 7)); - break; - case RSP_V31: - str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (uint16_t)VREG_S(31, 0), (uint16_t)VREG_S(31, 1), (uint16_t)VREG_S(31, 2), (uint16_t)VREG_S(31, 3), (uint16_t)VREG_S(31, 4), (uint16_t)VREG_S(31, 5), (uint16_t)VREG_S(31, 6), (uint16_t)VREG_S(31, 7)); - break; - } -} - - -/*************************************************************************** - Vector Load Instructions -***************************************************************************/ - -// LBV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 110010 | BBBBB | TTTTT | 00000 | IIII | Offset | -// -------------------------------------------------- -// -// Load 1 byte to vector byte index - -void rsp_device::cop2_drc::lbv() -{ - uint32_t op = m_rspcop2_state->op; - - uint32_t ea; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int index = (op >> 7) & 0xf; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - ea = (base) ? m_rsp.m_rsp_state->r[base] + offset : offset; - VREG_B(dest, index) = m_rsp.DM_READ8(ea); -} - - -// LSV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 110010 | BBBBB | TTTTT | 00001 | IIII | Offset | -// -------------------------------------------------- -// -// Loads 2 bytes starting from vector byte index - -void rsp_device::cop2_drc::lsv() -{ - uint32_t op = m_rspcop2_state->op; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int index = (op >> 7) & 0xf; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - uint32_t ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 2) : (offset * 2); - int end = index + 2; - for (int i = index; i < end; i++) - { - VREG_B(dest, i) = m_rsp.DM_READ8(ea); - ea++; - } -} - - -// LLV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 110010 | BBBBB | TTTTT | 00010 | IIII | Offset | -// -------------------------------------------------- -// -// Loads 4 bytes starting from vector byte index - -void rsp_device::cop2_drc::llv() -{ - uint32_t op = m_rspcop2_state->op; - uint32_t ea; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int index = (op >> 7) & 0xf; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 4) : (offset * 4); - - int end = index + 4; - - for (int i = index; i < end; i++) - { - VREG_B(dest, i) = m_rsp.DM_READ8(ea); - ea++; - } -} - - -// LDV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 110010 | BBBBB | TTTTT | 00011 | IIII | Offset | -// -------------------------------------------------- -// -// Loads 8 bytes starting from vector byte index - -void rsp_device::cop2_drc::ldv() -{ - uint32_t op = m_rspcop2_state->op; - uint32_t ea; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int index = (op >> 7) & 0xf; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); - - int end = index + 8; - - for (int i = index; i < end; i++) - { - VREG_B(dest, i) = m_rsp.DM_READ8(ea); - ea++; - } -} - - -// LQV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 110010 | BBBBB | TTTTT | 00100 | IIII | Offset | -// -------------------------------------------------- -// -// Loads up to 16 bytes starting from vector byte index - -void rsp_device::cop2_drc::lqv() -{ - uint32_t op = m_rspcop2_state->op; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - uint32_t ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); - - int end = 16 - (ea & 0xf); - if (end > 16) end = 16; - - for (int i = 0; i < end; i++) - { - VREG_B(dest, i) = m_rsp.DM_READ8(ea); - ea++; - } -} - - -// LRV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 110010 | BBBBB | TTTTT | 00101 | IIII | Offset | -// -------------------------------------------------- -// -// Stores up to 16 bytes starting from right side until 16-byte boundary - -void rsp_device::cop2_drc::lrv() -{ - uint32_t op = m_rspcop2_state->op; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int index = (op >> 7) & 0xf; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - uint32_t ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); - - index = 16 - ((ea & 0xf) - index); - ea &= ~0xf; - - for (int i = index; i < 16; i++) - { - VREG_B(dest, i) = m_rsp.DM_READ8(ea); - ea++; - } -} - - -// LPV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 110010 | BBBBB | TTTTT | 00110 | IIII | Offset | -// -------------------------------------------------- -// -// Loads a byte as the upper 8 bits of each element - -void rsp_device::cop2_drc::lpv() -{ - uint32_t op = m_rspcop2_state->op; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int index = (op >> 7) & 0xf; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - uint32_t ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); - - for (int i = 0; i < 8; i++) - { - W_VREG_S(dest, i) = m_rsp.DM_READ8(ea + (((16-index) + i) & 0xf)) << 8; - } -} - - -// LUV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 110010 | BBBBB | TTTTT | 00111 | IIII | Offset | -// -------------------------------------------------- -// -// Loads a byte as the bits 14-7 of each element - -void rsp_device::cop2_drc::luv() -{ - uint32_t op = m_rspcop2_state->op; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int index = (op >> 7) & 0xf; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - uint32_t ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); - - for (int i = 0; i < 8; i++) - { - W_VREG_S(dest, i) = m_rsp.DM_READ8(ea + (((16-index) + i) & 0xf)) << 7; - } -} - - -// LHV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 110010 | BBBBB | TTTTT | 01000 | IIII | Offset | -// -------------------------------------------------- -// -// Loads a byte as the bits 14-7 of each element, with 2-byte stride - -void rsp_device::cop2_drc::lhv() -{ - uint32_t op = m_rspcop2_state->op; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int index = (op >> 7) & 0xf; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - uint32_t ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); - - for (int i = 0; i < 8; i++) - { - W_VREG_S(dest, i) = m_rsp.DM_READ8(ea + (((16-index) + (i<<1)) & 0xf)) << 7; - } -} - - -// LFV -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 110010 | BBBBB | TTTTT | 01001 | IIII | Offset | -// -------------------------------------------------- -// -// Loads a byte as the bits 14-7 of upper or lower quad, with 4-byte stride - -void rsp_device::cop2_drc::lfv() -{ - uint32_t op = m_rspcop2_state->op; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int index = (op >> 7) & 0xf; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - uint32_t ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); - - // not sure what happens if 16-byte boundary is crossed... - - int end = (index >> 1) + 4; - - for (int i = index >> 1; i < end; i++) - { - W_VREG_S(dest, i) = m_rsp.DM_READ8(ea) << 7; - ea += 4; - } -} - - -// LWV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 110010 | BBBBB | TTTTT | 01010 | IIII | Offset | -// -------------------------------------------------- -// -// Loads the full 128-bit vector starting from vector byte index and wrapping to index 0 -// after byte index 15 - -void rsp_device::cop2_drc::lwv() -{ - uint32_t op = m_rspcop2_state->op; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int index = (op >> 7) & 0xf; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - uint32_t ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); - int end = (16 - index) + 16; - - for (int i = (16 - index); i < end; i++) - { - VREG_B(dest, i & 0xf) = m_rsp.DM_READ8(ea); - ea += 4; - } -} - - -// LTV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 110010 | BBBBB | TTTTT | 01011 | IIII | Offset | -// -------------------------------------------------- -// -// Loads one element to maximum of 8 vectors, while incrementing element index - -void rsp_device::cop2_drc::ltv() -{ - uint32_t op = m_rspcop2_state->op; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int index = (op >> 7) & 0xf; - int offset = (op & 0x7f); - - // FIXME: has a small problem with odd indices - - int vs = dest; - int ve = dest + 8; - if (ve > 32) - { - ve = 32; - } - - int element; - - uint32_t ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); - - ea = ((ea + 8) & ~0xf) + (index & 1); - for (int i = vs; i < ve; i++) - { - element = (8 - (index >> 1) + (i - vs)) << 1; - VREG_B(i, (element & 0xf)) = m_rsp.DM_READ8(ea); - VREG_B(i, ((element + 1) & 0xf)) = m_rsp.DM_READ8(ea + 1); - ea += 2; - } -} - - -bool rsp_device::cop2_drc::generate_lwc2(drcuml_block &block, rsp_device::compiler_state &compiler, const opcode_desc *desc) -{ - uint32_t op = desc->opptr.l[0]; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - switch ((op >> 11) & 0x1f) - { - case 0x00: /* LBV */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [m_rspcop2_state->op],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_lbv, this); - return true; - - case 0x01: /* LSV */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [m_rspcop2_state->op],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_lsv, this); - return true; - - case 0x02: /* LLV */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [m_rspcop2_state->op],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_llv, this); - return true; - - case 0x03: /* LDV */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [m_rspcop2_state->op],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_ldv, this); - return true; - - case 0x04: /* LQV */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [m_rspcop2_state->op],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_lqv, this); - return true; - - case 0x05: /* LRV */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [m_rspcop2_state->op],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_lrv, this); - return true; - - case 0x06: /* LPV */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [m_rspcop2_state->op],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_lpv, this); - return true; - - case 0x07: /* LUV */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [m_rspcop2_state->op],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_luv, this); - return true; - - case 0x08: /* LHV */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [m_rspcop2_state->op],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_lhv, this); - return true; - - case 0x09: /* LFV */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [m_rspcop2_state->op],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_lfv, this); - return true; - - case 0x0a: /* LWV */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [m_rspcop2_state->op],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_lwv, this); - return true; - - case 0x0b: /* LTV */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [m_rspcop2_state->op],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_ltv, this); - return true; - - default: - return false; - } -} - - -/*************************************************************************** - Vector Store Instructions -***************************************************************************/ - -// SBV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 111010 | BBBBB | TTTTT | 00000 | IIII | Offset | -// -------------------------------------------------- -// -// Stores 1 byte from vector byte index - -void rsp_device::cop2_drc::sbv() -{ - uint32_t op = m_rspcop2_state->op; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int index = (op >> 7) & 0xf; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - uint32_t ea = (base) ? m_rsp.m_rsp_state->r[base] + offset : offset; - m_rsp.DM_WRITE8(ea, VREG_B(dest, index)); -} - - -// SSV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 111010 | BBBBB | TTTTT | 00001 | IIII | Offset | -// -------------------------------------------------- -// -// Stores 2 bytes starting from vector byte index - -void rsp_device::cop2_drc::ssv() -{ - uint32_t op = m_rspcop2_state->op; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int index = (op >> 7) & 0xf; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - uint32_t ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 2) : (offset * 2); - - int end = index + 2; - for (int i = index; i < end; i++) - { - m_rsp.DM_WRITE8(ea, VREG_B(dest, i)); - ea++; - } -} - - -// SLV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 111010 | BBBBB | TTTTT | 00010 | IIII | Offset | -// -------------------------------------------------- -// -// Stores 4 bytes starting from vector byte index - -void rsp_device::cop2_drc::slv() -{ - uint32_t op = m_rspcop2_state->op; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int index = (op >> 7) & 0xf; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - uint32_t ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 4) : (offset * 4); - - int end = index + 4; - for (int i = index; i < end; i++) - { - m_rsp.DM_WRITE8(ea, VREG_B(dest, i)); - ea++; - } -} - - -// SDV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 111010 | BBBBB | TTTTT | 00011 | IIII | Offset | -// -------------------------------------------------- -// -// Stores 8 bytes starting from vector byte index - -void rsp_device::cop2_drc::sdv() -{ - uint32_t op = m_rspcop2_state->op; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int index = (op >> 7) & 0xf; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - uint32_t ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); - - int end = index + 8; - for (int i = index; i < end; i++) - { - m_rsp.DM_WRITE8(ea, VREG_B(dest, i)); - ea++; - } -} - - -// SQV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 111010 | BBBBB | TTTTT | 00100 | IIII | Offset | -// -------------------------------------------------- -// -// Stores up to 16 bytes starting from vector byte index until 16-byte boundary - -void rsp_device::cop2_drc::sqv() -{ - uint32_t op = m_rspcop2_state->op; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int index = (op >> 7) & 0xf; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - uint32_t ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); - int end = index + (16 - (ea & 0xf)); - for (int i=index; i < end; i++) - { - m_rsp.DM_WRITE8(ea, VREG_B(dest, i & 0xf)); - ea++; - } -} - - -// SRV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 111010 | BBBBB | TTTTT | 00101 | IIII | Offset | -// -------------------------------------------------- -// -// Stores up to 16 bytes starting from right side until 16-byte boundary - -void rsp_device::cop2_drc::srv() -{ - uint32_t op = m_rspcop2_state->op; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int index = (op >> 7) & 0xf; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - uint32_t ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); - - int end = index + (ea & 0xf); - int o = (16 - (ea & 0xf)) & 0xf; - ea &= ~0xf; - - for (int i = index; i < end; i++) - { - m_rsp.DM_WRITE8(ea, VREG_B(dest, ((i + o) & 0xf))); - ea++; - } -} - - -// SPV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 111010 | BBBBB | TTTTT | 00110 | IIII | Offset | -// -------------------------------------------------- -// -// Stores upper 8 bits of each element - -void rsp_device::cop2_drc::spv() -{ - uint32_t op = m_rspcop2_state->op; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int index = (op >> 7) & 0xf; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - uint32_t ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); - int end = index + 8; - for (int i=index; i < end; i++) - { - if ((i & 0xf) < 8) - { - m_rsp.DM_WRITE8(ea, VREG_B(dest, (i & 0xf) << 1)); - } - else - { - m_rsp.DM_WRITE8(ea, VREG_S(dest, (i & 0x7)) >> 7); - } - ea++; - } -} - - -// SUV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 111010 | BBBBB | TTTTT | 00111 | IIII | Offset | -// -------------------------------------------------- -// -// Stores bits 14-7 of each element - -void rsp_device::cop2_drc::suv() -{ - uint32_t op = m_rspcop2_state->op; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int index = (op >> 7) & 0xf; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - uint32_t ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); - int end = index + 8; - for (int i=index; i < end; i++) - { - if ((i & 0xf) < 8) - { - m_rsp.DM_WRITE8(ea, VREG_S(dest, (i & 0x7)) >> 7); - } - else - { - m_rsp.DM_WRITE8(ea, VREG_B(dest, ((i & 0x7) << 1))); - } - ea++; - } -} - - -// SHV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 111010 | BBBBB | TTTTT | 01000 | IIII | Offset | -// -------------------------------------------------- -// -// Stores bits 14-7 of each element, with 2-byte stride - -void rsp_device::cop2_drc::shv() -{ - uint32_t op = m_rspcop2_state->op; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int index = (op >> 7) & 0xf; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - uint32_t ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); - for (int i=0; i < 8; i++) - { - int element = index + (i << 1); - uint8_t d = (VREG_B(dest, (element & 0xf)) << 1) | - (VREG_B(dest, ((element + 1) & 0xf)) >> 7); - m_rsp.DM_WRITE8(ea, d); - ea += 2; - } -} - - -// SFV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 111010 | BBBBB | TTTTT | 01001 | IIII | Offset | -// -------------------------------------------------- -// -// Stores bits 14-7 of upper or lower quad, with 4-byte stride - -void rsp_device::cop2_drc::sfv() -{ - uint32_t op = m_rspcop2_state->op; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int index = (op >> 7) & 0xf; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - uint32_t ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); - int eaoffset = ea & 0xf; - ea &= ~0xf; - - int end = (index >> 1) + 4; - - for (int i = index>>1; i < end; i++) - { - m_rsp.DM_WRITE8(ea + (eaoffset & 0xf), VREG_S(dest, i) >> 7); - eaoffset += 4; - } -} - - -// SWV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 111010 | BBBBB | TTTTT | 01010 | IIII | Offset | -// -------------------------------------------------- -// -// Stores the full 128-bit vector starting from vector byte index and wrapping to index 0 -// after byte index 15 - -void rsp_device::cop2_drc::swv() -{ - uint32_t op = m_rspcop2_state->op; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int index = (op >> 7) & 0xf; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - uint32_t ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); - int eaoffset = ea & 0xf; - ea &= ~0xf; - - int end = index + 16; - for (int i = index; i < end; i++) - { - m_rsp.DM_WRITE8(ea + (eaoffset & 0xf), VREG_B(dest, i & 0xf)); - eaoffset++; - } -} - - -// STV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 111010 | BBBBB | TTTTT | 01011 | IIII | Offset | -// -------------------------------------------------- -// -// Stores one element from maximum of 8 vectors, while incrementing element index - -void rsp_device::cop2_drc::stv() -{ - uint32_t op = m_rspcop2_state->op; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int index = (op >> 7) & 0xf; - int offset = (op & 0x7f); - - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - int vs = dest; - int ve = dest + 8; - if (ve > 32) - { - ve = 32; - } - - int element = 8 - (index >> 1); - - uint32_t ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); - int eaoffset = (ea & 0xf) + (element * 2); - ea &= ~0xf; - - for (int i = vs; i < ve; i++) - { - m_rsp.DM_WRITE16(ea + (eaoffset & 0xf), VREG_S(i, element & 0x7)); - eaoffset += 2; - element++; - } -} - -bool rsp_device::cop2_drc::generate_swc2(drcuml_block &block, rsp_device::compiler_state &compiler, const opcode_desc *desc) -{ - uint32_t op = desc->opptr.l[0]; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - switch ((op >> 11) & 0x1f) - { - case 0x00: /* SBV */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_sbv, this); - return true; - - case 0x01: /* SSV */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_ssv, this); - return true; - - case 0x02: /* SLV */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_slv, this); - return true; - - case 0x03: /* SDV */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_sdv, this); - return true; - - case 0x04: /* SQV */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_sqv, this); - return true; - - case 0x05: /* SRV */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_srv, this); - return true; - - case 0x06: /* SPV */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_spv, this); - return true; - - case 0x07: /* SUV */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_suv, this); - return true; - - case 0x08: /* SHV */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_shv, this); - return true; - - case 0x09: /* SFV */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_sfv, this); - return true; - - case 0x0a: /* SWV */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_swv, this); - return true; - - case 0x0b: /* STV */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_stv, this); - return true; - - default: - m_rsp.unimplemented_opcode(op); - return false; - } - - return true; -} - - -/*************************************************************************** - Vector Opcodes -***************************************************************************/ - -// VMULF -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000000 | -// ------------------------------------------------------ -// -// Multiplies signed integer by signed integer * 2 - -void rsp_device::cop2_drc::vmulf() -{ - CACHE_VALUES(); - - for (int i = 0; i < 8; i++) - { - uint16_t w1, w2; - GET_VS1(w1, i); - GET_VS2(w2, i); - int32_t s1 = (int32_t)(int16_t)w1; - int32_t s2 = (int32_t)(int16_t)w2; - - if (s1 == -32768 && s2 == -32768) - { - // overflow - ACCUM(i) = s64(0x0000800080000000U); - m_vres[i] = 0x7fff; - } - else - { - ACCUM(i) = (int64_t)(s1 * s2 * 2 + 0x8000) << 16; // rounding? - m_vres[i] = ACCUM_M(i); - } - } - WRITEBACK_RESULT(); -} - - -// VMULU -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000001 | -// ------------------------------------------------------ -// - -void rsp_device::cop2_drc::vmulu() -{ - CACHE_VALUES(); - - for (int i = 0; i < 8; i++) - { - uint16_t w1, w2; - GET_VS1(w1, i); - GET_VS2(w2, i); - int32_t s1 = (int32_t)(int16_t)w1; - int32_t s2 = (int32_t)(int16_t)w2; - - int64_t r = s1 * s2 * 2 + 0x8000; // rounding? - - ACCUM(i) = r << 16; - - if (r < 0) - { - m_vres[i] = 0; - } - else if (((int16_t)(ACCUM_H(i)) ^ (int16_t)(ACCUM_M(i))) < 0) - { - m_vres[i] = -1; - } - else - { - m_vres[i] = ACCUM_M(i); - } - } - WRITEBACK_RESULT(); -} - - -// VMUDL -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001101 | -// ------------------------------------------------------ -// -// Multiplies signed integer by unsigned fraction -// The result is added into accumulator -// The middle slice of accumulator is stored into destination element - -void rsp_device::cop2_drc::vmudl() -{ - CACHE_VALUES(); - - for (int i = 0; i < 8; i++) - { - uint16_t w1, w2; - GET_VS1(w1, i); - GET_VS2(w2, i); - uint32_t s1 = (uint32_t)(uint16_t)w1; - uint32_t s2 = (uint32_t)(uint16_t)w2; - - ACCUM(i) = s1 * s2; - - m_vres[i] = ACCUM_L(i); - } - WRITEBACK_RESULT(); -} - - -// VMUDM -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000101 | -// ------------------------------------------------------ -// -// Multiplies signed integer by unsigned fraction -// The result is stored into accumulator -// The middle slice of accumulator is stored into destination element - -void rsp_device::cop2_drc::vmudm() -{ - CACHE_VALUES(); - - for (int i = 0; i < 8; i++) - { - uint16_t w1, w2; - GET_VS1(w1, i); - GET_VS2(w2, i); - int32_t s1 = (int32_t)(int16_t)w1; - int32_t s2 = (uint16_t)w2; - - ACCUM(i) = (int64_t)(s1 * s2) << 16; - - m_vres[i] = ACCUM_M(i); - } - WRITEBACK_RESULT(); -} - - -// VMUDN -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000110 | -// ------------------------------------------------------ -// -// Multiplies unsigned fraction by signed integer -// The result is stored into accumulator -// The low slice of accumulator is stored into destination element - -void rsp_device::cop2_drc::vmudn() -{ - CACHE_VALUES(); - - for (int i = 0; i < 8; i++) - { - uint16_t w1, w2; - GET_VS1(w1, i); - GET_VS2(w2, i); - int32_t s1 = (uint16_t)w1; - int32_t s2 = (int32_t)(int16_t)w2; - - int32_t r = s1 * s2; - - ACCUM(i) = (int64_t)(s1 * s2) << 16; - - m_vres[i] = (uint16_t)(r); - } - WRITEBACK_RESULT(); -} - - -// VMUDH -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000111 | -// ------------------------------------------------------ -// -// Multiplies signed integer by signed integer -// The result is stored into highest 32 bits of accumulator, the low slice is zero -// The highest 32 bits of accumulator is saturated into destination element - -void rsp_device::cop2_drc::vmudh() -{ - CACHE_VALUES(); - - for (int i = 0; i < 8; i++) - { - uint16_t w1, w2; - GET_VS1(w1, i); - GET_VS2(w2, i); - int32_t s1 = (int32_t)(int16_t)w1; - int32_t s2 = (int32_t)(int16_t)w2; - - int32_t r = s1 * s2; - - ACCUM(i) = (int64_t)r << 32; - - if (r < -32768) r = -32768; - if (r > 32767) r = 32767; - m_vres[i] = (int16_t)(r); - } - WRITEBACK_RESULT(); -} - - -// VMACF -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001000 | -// ------------------------------------------------------ -// - -void rsp_device::cop2_drc::vmacf() -{ - CACHE_VALUES(); - - for (int i = 0; i < 8; i++) - { - uint16_t w1, w2; - GET_VS1(w1, i); - GET_VS2(w2, i); - int32_t s1 = (int32_t)(int16_t)w1; - int32_t s2 = (int32_t)(int16_t)w2; - - ACCUM(i) += (int64_t)(s1 * s2 * 2) << 16; - - m_vres[i] = SATURATE_ACCUM(i, 1, 0x8000, 0x7fff); - } - WRITEBACK_RESULT(); -} - - -// VMACU -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001001 | -// ------------------------------------------------------ -// - -void rsp_device::cop2_drc::vmacu() -{ - CACHE_VALUES(); - - for (int i = 0; i < 8; i++) - { - uint16_t w1, w2; - GET_VS1(w1, i); - GET_VS2(w2, i); - int32_t s1 = (int32_t)(int16_t)w1; - int32_t s2 = (int32_t)(int16_t)w2; - - ACCUM(i) += (int64_t)(s1 * s2 * 2) << 16; - - if ((int16_t)ACCUM_H(i) < 0) - { - m_vres[i] = 0; - } - else - { - if (ACCUM_H(i) != 0) - { - m_vres[i] = (int16_t)0xffff; - } - else - { - if ((int16_t)ACCUM_M(i) < 0) - { - m_vres[i] = (int16_t)0xffff; - } - else - { - m_vres[i] = ACCUM_M(i); - } - } - } - } - WRITEBACK_RESULT(); -} - - -// VMADL -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001100 | -// ------------------------------------------------------ -// -// Multiplies unsigned fraction by unsigned fraction -// Adds the higher 16 bits of the 32-bit result to accumulator -// The low slice of accumulator is stored into destination element - -void rsp_device::cop2_drc::vmadl() -{ - CACHE_VALUES(); - - for (int i = 0; i < 8; i++) - { - uint16_t w1, w2; - GET_VS1(w1, i); - GET_VS2(w2, i); - uint32_t s1 = w1; - uint32_t s2 = w2; - - ACCUM(i) += (s1 * s2) & 0xffff0000; - - m_vres[i] = SATURATE_ACCUM(i, 0, 0x0000, 0xffff); - } - WRITEBACK_RESULT(); -} - - -// VMADM -// - -void rsp_device::cop2_drc::vmadm() -{ - CACHE_VALUES(); - - for (int i = 0; i < 8; i++) - { - uint16_t w1, w2; - GET_VS1(w1, i); - GET_VS2(w2, i); - uint32_t s1 = (int32_t)(int16_t)w1; - uint32_t s2 = (uint16_t)w2; - - ACCUM(i) += (int64_t)(int32_t)(s1 * s2) << 16; - - m_vres[i] = SATURATE_ACCUM(i, 1, 0x8000, 0x7fff); - } - WRITEBACK_RESULT(); -} - - -// VMADN -// - -void rsp_device::cop2_drc::vmadn() -{ - CACHE_VALUES(); - - for (int i = 0; i < 8; i++) - { - uint16_t w1, w2; - GET_VS1(w1, i); - GET_VS2(w2, i); - int32_t s1 = (uint16_t)w1; - int32_t s2 = (int32_t)(int16_t)w2; - - ACCUM(i) += (int64_t)(s1 * s2) << 16; - - m_vres[i] = SATURATE_ACCUM(i, 0, 0x0000, 0xffff); - } - WRITEBACK_RESULT(); -} - - -// VMADH -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001111 | -// ------------------------------------------------------ -// -// Multiplies signed integer by signed integer -// The result is added into highest 32 bits of accumulator, the low slice is zero -// The highest 32 bits of accumulator is saturated into destination element - -void rsp_device::cop2_drc::vmadh() -{ - CACHE_VALUES(); - - for (int i = 0; i < 8; i++) - { - int16_t w1, w2; - GET_VS1(w1, i); - GET_VS2(w2, i); - int32_t s1 = (int32_t)(int16_t)w1; - int32_t s2 = (int32_t)(int16_t)w2; - - ACCUM(i) += (int64_t)(s1 * s2) << 32; - - m_vres[i] = SATURATE_ACCUM(i, 1, 0x8000, 0x7fff); - } - WRITEBACK_RESULT(); -} - - -// VADD -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010000 | -// ------------------------------------------------------ -// -// Adds two vector registers and carry flag, the result is saturated to 32767 - -void rsp_device::cop2_drc::vadd() -{ - CACHE_VALUES(); - - for (int i = 0; i < 8; i++) - { - int16_t w1, w2; - GET_VS1(w1, i); - GET_VS2(w2, i); - int32_t s1 = (int32_t)(int16_t)w1; - int32_t s2 = (int32_t)(int16_t)w2; - int32_t r = s1 + s2 + (((CARRY_FLAG(i)) != 0) ? 1 : 0); - - SET_ACCUM_L((int16_t)(r), i); - - if (r > 32767) r = 32767; - if (r < -32768) r = -32768; - m_vres[i] = (int16_t)(r); - } - CLEAR_ZERO_FLAGS(); - CLEAR_CARRY_FLAGS(); - WRITEBACK_RESULT(); -} - - -// VSUB -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010001 | -// ------------------------------------------------------ -// -// Subtracts two vector registers and carry flag, the result is saturated to -32768 -// TODO: check VS2REG == VDREG - -void rsp_device::cop2_drc::vsub() -{ - CACHE_VALUES(); - - for (int i = 0; i < 8; i++) - { - int16_t w1, w2; - GET_VS1(w1, i); - GET_VS2(w2, i); - int32_t s1 = (int32_t)(int16_t)w1; - int32_t s2 = (int32_t)(int16_t)w2; - int32_t r = s1 - s2 - (((CARRY_FLAG(i)) != 0) ? 1 : 0); - - SET_ACCUM_L((int16_t)(r), i); - - if (r > 32767) r = 32767; - if (r < -32768) r = -32768; - - m_vres[i] = (int16_t)(r); - } - CLEAR_ZERO_FLAGS(); - CLEAR_CARRY_FLAGS(); - WRITEBACK_RESULT(); -} - - -// VABS -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010011 | -// ------------------------------------------------------ -// -// Changes the sign of source register 2 if source register 1 is negative and stores the result to destination register - -void rsp_device::cop2_drc::vabs() -{ - CACHE_VALUES(); - - for (int i = 0; i < 8; i++) - { - int16_t s1, s2; - GET_VS1(s1, i); - GET_VS2(s2, i); - - if (s1 < 0) - { - if (s2 == -32768) - { - m_vres[i] = 32767; - } - else - { - m_vres[i] = -s2; - } - } - else if (s1 > 0) - { - m_vres[i] = s2; - } - else - { - m_vres[i] = 0; - } - - SET_ACCUM_L(m_vres[i], i); - } - WRITEBACK_RESULT(); -} - - -// VADDC -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010100 | -// ------------------------------------------------------ -// -// Adds two vector registers, the carry out is stored into carry register -// TODO: check VS2REG = VDREG - -void rsp_device::cop2_drc::vaddc() -{ - CACHE_VALUES(); - - CLEAR_ZERO_FLAGS(); - CLEAR_CARRY_FLAGS(); - - for (int i = 0; i < 8; i++) - { - int16_t w1, w2; - GET_VS1(w1, i); - GET_VS2(w2, i); - int32_t s1 = (uint32_t)(uint16_t)w1; - int32_t s2 = (uint32_t)(uint16_t)w2; - int32_t r = s1 + s2; - - m_vres[i] = (int16_t)(r); - SET_ACCUM_L((int16_t)r, i); - - if (r & 0xffff0000) - { - SET_CARRY_FLAG(i); - } - } - WRITEBACK_RESULT(); -} - - -// VSUBC -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010101 | -// ------------------------------------------------------ -// -// Subtracts two vector registers, the carry out is stored into carry register -// TODO: check VS2REG = VDREG - -void rsp_device::cop2_drc::vsubc() -{ - CACHE_VALUES(); - - CLEAR_ZERO_FLAGS(); - CLEAR_CARRY_FLAGS(); - - for (int i = 0; i < 8; i++) - { - int16_t w1, w2; - GET_VS1(w1, i); - GET_VS2(w2, i); - int32_t s1 = (uint32_t)(uint16_t)w1; - int32_t s2 = (uint32_t)(uint16_t)w2; - int32_t r = s1 - s2; - - m_vres[i] = (int16_t)(r); - SET_ACCUM_L((uint16_t)r, i); - - if ((uint16_t)(r) != 0) - { - SET_ZERO_FLAG(i); - } - if (r & 0xffff0000) - { - SET_CARRY_FLAG(i); - } - } - WRITEBACK_RESULT(); -} - - -// VADDB -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010110 | -// ------------------------------------------------------ -// -// Adds two vector registers bytewise with rounding - -void rsp_device::cop2_drc::vaddb() -{ - CACHE_VALUES(); - const int round = (el == 0) ? 0 : (1 << (el - 1)); - - for (int i = 0; i < 8; i++) - { - uint16_t w1, w2; - GET_VS1(w1, i); - GET_VS2(w2, i); - - uint8_t hb1 = w1 >> 8; - uint8_t lb1 = w1 & 0xff; - uint8_t hb2 = w2 >> 8; - uint8_t lb2 = w2 & 0xff; - - uint16_t hs = hb1 + hb2 + round; - uint16_t ls = lb1 + lb2 + round; - - SET_ACCUM_L((hs << 8) | ls, i); - - hs >>= EL; - if (hs > 255) - { - hs = 255; - } - - ls >>= EL; - if (ls > 255) - { - ls = 255; - } - - m_vres[i] = 0; // VD writeback disabled on production hardware - // m_vres[i] = (hs << 8) | ls; - } - WRITEBACK_RESULT(); -} - - -// VSAW -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 011101 | -// ------------------------------------------------------ -// -// Stores high, middle or low slice of accumulator to destination vector - -void rsp_device::cop2_drc::vsaw() -{ - const int op = m_rspcop2_state->op; - const int vdreg = VDREG; - const int el = EL; - - switch (el) - { - case 0x08: // VSAWH - for (int i = 0; i < 8; i++) - { - W_VREG_S(vdreg, i) = ACCUM_H(i); - } - break; - case 0x09: // VSAWM - for (int i = 0; i < 8; i++) - { - W_VREG_S(vdreg, i) = ACCUM_M(i); - } - break; - case 0x0a: // VSAWL - for (int i = 0; i < 8; i++) - { - W_VREG_S(vdreg, i) = ACCUM_L(i); - } - break; - default: // Unsupported - { - for (int i = 0; i < 8; i++) - { - W_VREG_S(vdreg, i) = 0; - } - } - } -} - - -// VLT -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100000 | -// ------------------------------------------------------ -// -// Sets compare flags if elements in VS1 are less than VS2 -// Moves the element in VS2 to destination vector - -void rsp_device::cop2_drc::vlt() -{ - CACHE_VALUES(); - - CLEAR_COMPARE_FLAGS(); - CLEAR_CLIP2_FLAGS(); - - for (int i = 0; i < 8; i++) - { - int16_t s1, s2; - GET_VS1(s1, i); - GET_VS2(s2, i); - - if (s1 < s2) - { - SET_COMPARE_FLAG(i); - } - else if (s1 == s2) - { - if (ZERO_FLAG(i) != 0 && CARRY_FLAG(i) != 0) - { - SET_COMPARE_FLAG(i); - } - } - - if (COMPARE_FLAG(i) != 0) - { - m_vres[i] = s1; - } - else - { - m_vres[i] = s2; - } - - SET_ACCUM_L(m_vres[i], i); - } - - CLEAR_ZERO_FLAGS(); - CLEAR_CARRY_FLAGS(); - WRITEBACK_RESULT(); -} - - -// VEQ -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100001 | -// ------------------------------------------------------ -// -// Sets compare flags if elements in VS1 are equal with VS2 -// Moves the element in VS2 to destination vector - -void rsp_device::cop2_drc::veq() -{ - CACHE_VALUES(); - - CLEAR_COMPARE_FLAGS(); - CLEAR_CLIP2_FLAGS(); - - for (int i = 0; i < 8; i++) - { - int16_t s1, s2; - GET_VS1(s1, i); - GET_VS2(s2, i); - - if ((s1 == s2) && ZERO_FLAG(i) == 0) - { - SET_COMPARE_FLAG(i); - m_vres[i] = s1; - } - else - { - m_vres[i] = s2; - } - - SET_ACCUM_L(m_vres[i], i); - } - - CLEAR_ZERO_FLAGS(); - CLEAR_CARRY_FLAGS(); - WRITEBACK_RESULT(); -} - - -// VNE -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100010 | -// ------------------------------------------------------ -// -// Sets compare flags if elements in VS1 are not equal with VS2 -// Moves the element in VS2 to destination vector - -void rsp_device::cop2_drc::vne() -{ - CACHE_VALUES(); - - CLEAR_COMPARE_FLAGS(); - CLEAR_CLIP2_FLAGS(); - - for (int i = 0; i < 8; i++) - { - int16_t s1, s2; - GET_VS1(s1, i); - GET_VS2(s2, i); - - if (s1 != s2 || ZERO_FLAG(i) != 0) - { - SET_COMPARE_FLAG(i); - m_vres[i] = s1; - } - else - { - m_vres[i] = s2; - } - - SET_ACCUM_L(m_vres[i], i); - } - - CLEAR_ZERO_FLAGS(); - CLEAR_CARRY_FLAGS(); - WRITEBACK_RESULT(); -} - - -// VGE -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100011 | -// ------------------------------------------------------ -// -// Sets compare flags if elements in VS1 are greater or equal with VS2 -// Moves the element in VS2 to destination vector - -void rsp_device::cop2_drc::vge() -{ - CACHE_VALUES(); - - CLEAR_COMPARE_FLAGS(); - CLEAR_CLIP2_FLAGS(); - - for (int i = 0; i < 8; i++) - { - int16_t s1, s2; - GET_VS1(s1, i); - GET_VS2(s2, i); - if ((s1 == s2 && (ZERO_FLAG(i) == 0 || CARRY_FLAG(i) == 0)) || s1 > s2) - { - SET_COMPARE_FLAG(i); - m_vres[i] = s1; - } - else - { - m_vres[i] = s2; - } - - SET_ACCUM_L(m_vres[i], i); - } - - CLEAR_ZERO_FLAGS(); - CLEAR_CARRY_FLAGS(); - WRITEBACK_RESULT(); -} - - -// VCL -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100100 | -// ------------------------------------------------------ -// -// Vector clip low - -void rsp_device::cop2_drc::vcl() -{ - CACHE_VALUES(); - - for (int i = 0; i < 8; i++) - { - int16_t s1, s2; - GET_VS1(s1, i); - GET_VS2(s2, i); - - if (CARRY_FLAG(i) != 0) - { - if (ZERO_FLAG(i) != 0) - { - if (COMPARE_FLAG(i) != 0) - { - SET_ACCUM_L(-(uint16_t)s2, i); - } - else - { - SET_ACCUM_L(s1, i); - } - } - else - { - if (CLIP1_FLAG(i) != 0) - { - if (((uint32_t)(uint16_t)(s1) + (uint32_t)(uint16_t)(s2)) > 0x10000) - { - SET_ACCUM_L(s1, i); - CLEAR_COMPARE_FLAG(i); - } - else - { - SET_ACCUM_L(-((uint16_t)s2), i); - SET_COMPARE_FLAG(i); - } - } - else - { - if (((uint32_t)(uint16_t)(s1) + (uint32_t)(uint16_t)(s2)) != 0) - { - SET_ACCUM_L(s1, i); - CLEAR_COMPARE_FLAG(i); - } - else - { - SET_ACCUM_L(-((uint16_t)s2), i); - SET_COMPARE_FLAG(i); - } - } - } - } - else - { - if (ZERO_FLAG(i) != 0) - { - if (CLIP2_FLAG(i) != 0) - { - SET_ACCUM_L(s2, i); - } - else - { - SET_ACCUM_L(s1, i); - } - } - else - { - if (((int32_t)(uint16_t)s1 - (int32_t)(uint16_t)s2) >= 0) - { - SET_ACCUM_L(s2, i); - SET_CLIP2_FLAG(i); - } - else - { - SET_ACCUM_L(s1, i); - CLEAR_CLIP2_FLAG(i); - } - } - } - m_vres[i] = ACCUM_L(i); - } - CLEAR_ZERO_FLAGS(); - CLEAR_CARRY_FLAGS(); - CLEAR_CLIP1_FLAGS(); - WRITEBACK_RESULT(); -} - - -// VCH -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100101 | -// ------------------------------------------------------ -// -// Vector clip high - -void rsp_device::cop2_drc::vch() -{ - CACHE_VALUES(); - - CLEAR_CARRY_FLAGS(); - CLEAR_COMPARE_FLAGS(); - CLEAR_CLIP1_FLAGS(); - CLEAR_ZERO_FLAGS(); - CLEAR_CLIP2_FLAGS(); - - uint32_t vce; - for (int i = 0; i < 8; i++) - { - int16_t s1, s2; - GET_VS1(s1, i); - GET_VS2(s2, i); - - if ((s1 ^ s2) < 0) - { - vce = (s1 + s2 == -1); - SET_CARRY_FLAG(i); - if (s2 < 0) - { - SET_CLIP2_FLAG(i); - } - - if ((s1 + s2) <= 0) - { - SET_COMPARE_FLAG(i); - m_vres[i] = -((uint16_t)s2); - } - else - { - m_vres[i] = s1; - } - - if ((s1 + s2) != 0 && s1 != ~s2) - { - SET_ZERO_FLAG(i); - } - }//sign - else - { - vce = 0; - if (s2 < 0) - { - SET_COMPARE_FLAG(i); - } - if ((s1 - s2) >= 0) - { - SET_CLIP2_FLAG(i); - m_vres[i] = s2; - } - else - { - m_vres[i] = s1; - } - - if ((s1 - s2) != 0 && s1 != ~s2) - { - SET_ZERO_FLAG(i); - } - } - if (vce) - { - SET_CLIP1_FLAG(i); - } - SET_ACCUM_L(m_vres[i], i); - } - WRITEBACK_RESULT(); -} - - -// VCR -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100110 | -// ------------------------------------------------------ -// -// Vector clip reverse - -void rsp_device::cop2_drc::vcr() -{ - CACHE_VALUES(); - - CLEAR_CARRY_FLAGS(); - CLEAR_COMPARE_FLAGS(); - CLEAR_CLIP1_FLAGS(); - CLEAR_ZERO_FLAGS(); - CLEAR_CLIP2_FLAGS(); - - for (int i = 0; i < 8; i++) - { - int16_t s1, s2; - GET_VS1(s1, i); - GET_VS2(s2, i); - - if ((int16_t)(s1 ^ s2) < 0) - { - if (s2 < 0) - { - SET_CLIP2_FLAG(i); - } - if ((s1 + s2) <= 0) - { - SET_ACCUM_L(~((uint16_t)s2), i); - SET_COMPARE_FLAG(i); - } - else - { - SET_ACCUM_L(s1, i); - } - } - else - { - if (s2 < 0) - { - SET_COMPARE_FLAG(i); - } - if ((s1 - s2) >= 0) - { - SET_ACCUM_L(s2, i); - SET_CLIP2_FLAG(i); - } - else - { - SET_ACCUM_L(s1, i); - } - } - - m_vres[i] = ACCUM_L(i); - } - WRITEBACK_RESULT(); -} - - -// VMRG -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100111 | -// ------------------------------------------------------ -// -// Merges two vectors according to compare flags - -void rsp_device::cop2_drc::vmrg() -{ - CACHE_VALUES(); - - for (int i = 0; i < 8; i++) - { - int16_t s1, s2; - GET_VS1(s1, i); - GET_VS2(s2, i); - if (COMPARE_FLAG(i) != 0) - { - m_vres[i] = s1; - } - else - { - m_vres[i] = s2; - } - - SET_ACCUM_L(m_vres[i], i); - } - WRITEBACK_RESULT(); -} - - -// VAND -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101000 | -// ------------------------------------------------------ -// -// Bitwise AND of two vector registers - -void rsp_device::cop2_drc::vand() -{ - CACHE_VALUES(); - - for (int i = 0; i < 8; i++) - { - uint16_t s1, s2; - GET_VS1(s1, i); - GET_VS2(s2, i); - m_vres[i] = s1 & s2; - SET_ACCUM_L(m_vres[i], i); - } - WRITEBACK_RESULT(); -} - - -// VNAND -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101001 | -// ------------------------------------------------------ -// -// Bitwise NOT AND of two vector registers - -void rsp_device::cop2_drc::vnand() -{ - CACHE_VALUES(); - - for (int i = 0; i < 8; i++) - { - uint16_t s1, s2; - GET_VS1(s1, i); - GET_VS2(s2, i); - m_vres[i] = ~((s1 & s2)); - SET_ACCUM_L(m_vres[i], i); - } - WRITEBACK_RESULT(); -} - - -// VOR -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101010 | -// ------------------------------------------------------ -// -// Bitwise OR of two vector registers - -void rsp_device::cop2_drc::vor() -{ - CACHE_VALUES(); - - for (int i = 0; i < 8; i++) - { - uint16_t s1, s2; - GET_VS1(s1, i); - GET_VS2(s2, i); - m_vres[i] = s1 | s2; - SET_ACCUM_L(m_vres[i], i); - } - WRITEBACK_RESULT(); -} - - -// VNOR -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101011 | -// ------------------------------------------------------ -// -// Bitwise NOT OR of two vector registers - -void rsp_device::cop2_drc::vnor() -{ - CACHE_VALUES(); - - for (int i = 0; i < 8; i++) - { - uint16_t s1, s2; - GET_VS1(s1, i); - GET_VS2(s2, i); - m_vres[i] = ~(s1 | s2); - SET_ACCUM_L(m_vres[i], i); - } - WRITEBACK_RESULT(); -} - - -// VXOR -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101100 | -// ------------------------------------------------------ -// -// Bitwise XOR of two vector registers - -void rsp_device::cop2_drc::vxor() -{ - CACHE_VALUES(); - - for (int i = 0; i < 8; i++) - { - uint16_t s1, s2; - GET_VS1(s1, i); - GET_VS2(s2, i); - m_vres[i] = s1 ^ s2; - SET_ACCUM_L(m_vres[i], i); - } - WRITEBACK_RESULT(); -} - - -// VNXOR -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101101 | -// ------------------------------------------------------ -// -// Bitwise NOT XOR of two vector registers - -void rsp_device::cop2_drc::vnxor() -{ - CACHE_VALUES(); - - for (int i = 0; i < 8; i++) - { - uint16_t s1, s2; - GET_VS1(s1, i); - GET_VS2(s2, i); - m_vres[i] = ~(s1 ^ s2); - SET_ACCUM_L(m_vres[i], i); - } - WRITEBACK_RESULT(); -} - - -// VRCP -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110000 | -// ------------------------------------------------------ -// -// Calculates reciprocal - -void rsp_device::cop2_drc::vrcp() -{ - CACHE_VALUES(); - - int32_t shifter = 0; - int32_t rec = (int16_t)(VREG_S(vs2reg, el & 7)); - int32_t datainput = (rec < 0) ? (-rec) : rec; - if (datainput) - { - for (int i = 0; i < 32; i++) - { - if (datainput & (1 << ((~i) & 0x1f))) - { - shifter = i; - break; - } - } - } - else - { - shifter = 0x10; - } - - int32_t address = ((datainput << shifter) & 0x7fc00000) >> 22; - int32_t fetchval = rsp_divtable[address]; - int32_t temp = (0x40000000 | (fetchval << 14)) >> ((~shifter) & 0x1f); - if (rec < 0) - { - temp = ~temp; - } - if (!rec) - { - temp = 0x7fffffff; - } - else if (rec == 0xffff8000) - { - temp = 0xffff0000; - } - rec = temp; - - m_reciprocal_res = rec; - m_dp_allowed = 0; - - W_VREG_S(vdreg, vs1reg & 7) = (uint16_t)rec; - for (int i = 0; i < 8; i++) - { - SET_ACCUM_L(VREG_S(vs2reg, VEC_EL_2(el, i)), i); - } -} - - -// VRCPL -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110001 | -// ------------------------------------------------------ -// -// Calculates reciprocal low part - -void rsp_device::cop2_drc::vrcpl() -{ - CACHE_VALUES(); - - int32_t shifter = 0; - int32_t rec = (int16_t)VREG_S(vs2reg, el & 7); - int32_t datainput = rec; - - if (m_dp_allowed) - { - rec = (rec & 0x0000ffff) | m_reciprocal_high; - datainput = rec; - - if (rec < 0) - { - if (rec < -32768) - { - datainput = ~datainput; - } - else - { - datainput = -datainput; - } - } - } - else if (datainput < 0) - { - datainput = -datainput; - - shifter = 0x10; - } - - if (datainput) - { - for (int i = 0; i < 32; i++) - { - if (datainput & (1 << ((~i) & 0x1f))) - { - shifter = i; - break; - } - } - } - - uint32_t address = (datainput << shifter) >> 22; - int32_t fetchval = rsp_divtable[address & 0x1ff]; - int32_t temp = (0x40000000 | (fetchval << 14)) >> ((~shifter) & 0x1f); - temp ^= rec >> 31; - - if (!rec) - { - temp = 0x7fffffff; - } - else if (rec == 0xffff8000) - { - temp = 0xffff0000; - } - rec = temp; - - m_reciprocal_res = rec; - m_dp_allowed = 0; - - W_VREG_S(vdreg, vs1reg & 7) = (uint16_t)rec; - - for (int i = 0; i < 8; i++) - { - SET_ACCUM_L(VREG_S(vs2reg, VEC_EL_2(el, i)), i); - } -} - - -// VRCPH -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110010 | -// ------------------------------------------------------ -// -// Calculates reciprocal high part - -void rsp_device::cop2_drc::vrcph() -{ - CACHE_VALUES(); - - m_reciprocal_high = (VREG_S(vs2reg, el & 7)) << 16; - m_dp_allowed = 1; - - for (int i = 0; i < 8; i++) - { - SET_ACCUM_L(VREG_S(vs2reg, VEC_EL_2(el, i)), i); - } - - W_VREG_S(vdreg, vs1reg & 7) = (int16_t)(m_reciprocal_res >> 16); -} - - -// VMOV -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110011 | -// ------------------------------------------------------ -// -// Moves element from vector to destination vector - -void rsp_device::cop2_drc::vmov() -{ - CACHE_VALUES(); - - W_VREG_S(vdreg, vs1reg & 7) = VREG_S(vs2reg, el & 7); - for (int i = 0; i < 8; i++) - { - SET_ACCUM_L(VREG_S(vs2reg, VEC_EL_2(el, i)), i); - } -} - - -// VRSQ -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110100 | -// ------------------------------------------------------ -// -// Calculates reciprocal square-root - -void rsp_device::cop2_drc::vrsq() -{ - CACHE_VALUES(); - - int32_t shifter = 0; - int32_t rec = (int16_t)VREG_S(vs2reg, el & 7); - int32_t datainput = (rec < 0) ? (-rec) : (rec); - - if (rec < 0) - { - if (rec < -32768) - { - datainput = ~datainput; - } - else - { - datainput = -datainput; - } - } - - if (datainput) - { - for (int i = 0; i < 32; i++) - { - if (datainput & (1 << ((~i) & 0x1f))) - { - shifter = i; - break; - } - } - } - else - { - shifter = 0; - } - - int32_t address = ((datainput << shifter) & 0x7fc00000) >> 22; - address = ((address | 0x200) & 0x3fe) | (shifter & 1); - - int32_t fetchval = rsp_divtable[address]; - int32_t temp = (0x40000000 | (fetchval << 14)) >> (((~shifter) & 0x1f) >> 1); - if (rec < 0) - { - temp = ~temp; - } - if (!rec) - { - temp = 0x7fffffff; - } - else if (rec == 0xffff8000) - { - temp = 0xffff0000; - } - rec = temp; - - if (rec < 0) - { - if (m_dp_allowed) - { - if (rec < -32768) - { - datainput = ~datainput; - } - else - { - datainput = -datainput; - } - } - else - { - datainput = -datainput; - } - } - - if (datainput) - { - for (int i = 0; i < 32; i++) - { - if (datainput & (1 << ((~i) & 0x1f))) - { - shifter = i; - break; - } - } - } - else - { - shifter = 0; - } - - address = ((datainput << shifter) & 0x7fc00000) >> 22; - address = ((address | 0x200) & 0x3fe) | (shifter & 1); - - fetchval = rsp_divtable[address]; - temp = (0x40000000 | (fetchval << 14)) >> (((~shifter) & 0x1f) >> 1); - if (rec < 0) - { - temp = ~temp; - } - if (!rec) - { - temp = 0x7fff; - } - else if (rec == 0xffff8000) - { - temp = 0x0000; - } - rec = temp; - - W_VREG_S(vdreg, vs1reg & 7) = (uint16_t)rec; - for (int i = 0; i < 8; i++) - { - SET_ACCUM_L(VREG_S(vs2reg, VEC_EL_2(el, i)), i); - } -} - - -// VRSQL -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110101 | -// ------------------------------------------------------ -// -// Calculates reciprocal square-root low part - -void rsp_device::cop2_drc::vrsql() -{ - CACHE_VALUES(); - - int32_t shifter = 0; - int32_t rec = (int16_t)VREG_S(vs2reg, el & 7); - int32_t datainput = rec; - - if (m_dp_allowed) - { - rec = (rec & 0x0000ffff) | m_reciprocal_high; - datainput = rec; - - if (rec < 0) - { - if (rec < -32768) - { - datainput = ~datainput; - } - else - { - datainput = -datainput; - } - } - } - else if (datainput < 0) - { - datainput = -datainput; - - shifter = 0x10; - } - - if (datainput) - { - for (int i = 0; i < 32; i++) - { - if (datainput & (1 << ((~i) & 0x1f))) - { - shifter = i; - break; - } - } - } - - int32_t address = ((datainput << shifter) & 0x7fc00000) >> 22; - address = ((address | 0x200) & 0x3fe) | (shifter & 1); - - int32_t fetchval = rsp_divtable[address]; - int32_t temp = (0x40000000 | (fetchval << 14)) >> (((~shifter) & 0x1f) >> 1); - temp ^= rec >> 31; - - if (!rec) - { - temp = 0x7fffffff; - } - else if (rec == 0xffff8000) - { - temp = 0xffff0000; - } - rec = temp; - - m_reciprocal_res = rec; - m_dp_allowed = 0; - - W_VREG_S(vdreg, vs1reg & 7) = (uint16_t)(rec & 0xffff); - for (int i = 0; i < 8; i++) - { - SET_ACCUM_L(VREG_S(vs2reg, VEC_EL_2(el, i)), i); - } -} - - -// VRSQH -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110110 | -// ------------------------------------------------------ -// -// Calculates reciprocal square-root high part - -void rsp_device::cop2_drc::vrsqh() -{ - CACHE_VALUES(); - - m_reciprocal_high = (VREG_S(vs2reg, el & 7)) << 16; - m_dp_allowed = 1; - - for (int i = 0; i < 8; i++) - { - SET_ACCUM_L(VREG_S(vs2reg, VEC_EL_2(el, i)), i); - } - - W_VREG_S(vdreg, vs1reg & 7) = (int16_t)(m_reciprocal_res >> 16); // store high part -} - - -/*------------------------------------------------- - generate_vector_opcode - generate code for a - vector opcode --------------------------------------------------*/ - -bool rsp_device::cop2_drc::generate_vector_opcode(drcuml_block &block, rsp_device::compiler_state &compiler, const opcode_desc *desc) -{ - uint32_t op = desc->opptr.l[0]; - // Opcode legend: - // E = VS2 element type - // S = VS1, Source vector 1 - // T = VS2, Source vector 2 - // D = Destination vector - - switch (op & 0x3f) - { - case 0x00: /* VMULF */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vmulf, this); - return true; - - case 0x01: /* VMULU */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vmulu, this); - return true; - - case 0x04: /* VMUDL */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vmudl, this); - return true; - - case 0x05: /* VMUDM */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vmudm, this); - return true; - - case 0x06: /* VMUDN */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vmudn, this); - return true; - - case 0x07: /* VMUDH */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vmudh, this); - return true; - - case 0x08: /* VMACF */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vmacf, this); - return true; - - case 0x09: /* VMACU */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vmacu, this); - return true; - - case 0x0c: /* VMADL */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vmadl, this); - return true; - - case 0x0d: /* VMADM */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vmadm, this); - return true; - - case 0x0e: /* VMADN */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vmadn, this); - return true; - - case 0x0f: /* VMADH */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vmadh, this); - return true; - - case 0x10: /* VADD */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vadd, this); - return true; - - case 0x11: /* VSUB */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vsub, this); - return true; - - case 0x13: /* VABS */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vabs, this); - return true; - - case 0x14: /* VADDC */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vaddc, this); - return true; - - case 0x15: /* VSUBC */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vsubc, this); - return true; - - case 0x16: /* VADDB */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vaddb, this); - return true; - - case 0x17: /* VSUBB (reserved, functionally identical to VADDB) */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vaddb, this); - return true; - - case 0x18: /* VACCB (reserved, functionally identical to VADDB) */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vaddb, this); - return true; - - case 0x19: /* VSUCB (reserved, functionally identical to VADDB) */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vaddb, this); - return true; - - case 0x1d: /* VSAW */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vsaw, this); - return true; - - case 0x20: /* VLT */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vlt, this); - return true; - - case 0x21: /* VEQ */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_veq, this); - return true; - - case 0x22: /* VNE */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vne, this); - return true; - - case 0x23: /* VGE */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vge, this); - return true; - - case 0x24: /* VCL */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vcl, this); - return true; - - case 0x25: /* VCH */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vch, this); - return true; - - case 0x26: /* VCR */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vcr, this); - return true; - - case 0x27: /* VMRG */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vmrg, this); - return true; - - case 0x28: /* VAND */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vand, this); - return true; - - case 0x29: /* VNAND */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vnand, this); - return true; - - case 0x2a: /* VOR */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vor, this); - return true; - - case 0x2b: /* VNOR */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vnor, this); - return true; - - case 0x2c: /* VXOR */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vxor, this); - return true; - - case 0x2d: /* VNXOR */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vnxor, this); - return true; - - case 0x30: /* VRCP */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vrcp, this); - return true; - - case 0x31: /* VRCPL */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vrcpl, this); - return true; - - case 0x32: /* VRCPH */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vrcph, this); - return true; - - case 0x33: /* VMOV */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vmov, this); - return true; - - case 0x34: /* VRSQ */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vrsq, this); - return true; - - case 0x35: /* VRSQL */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vrsql, this); - return true; - - case 0x36: /* VRSQH */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_vrsqh, this); - return true; - - case 0x37: /* VNOP */ - case 0x3F: /* VNULL */ - return true; - - default: - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::unimplemented_opcode, &m_rsp); - return false; - } -} - - -/*************************************************************************** - Vector Flag Reading/Writing -***************************************************************************/ - -void rsp_device::cop2_drc::mfc2() -{ - uint32_t op = m_rspcop2_state->op; - int el = (op >> 7) & 0xf; - - uint16_t b1 = VREG_B(VS1REG, (el+0) & 0xf); - uint16_t b2 = VREG_B(VS1REG, (el+1) & 0xf); - if (RTREG) RTVAL = (int32_t)(int16_t)((b1 << 8) | (b2)); -} - -void rsp_device::cop2_drc::cfc2() -{ - uint32_t op = m_rspcop2_state->op; - if (RTREG) - { - switch(RDREG) - { - case 0: - RTVAL = ((CARRY_FLAG(0) & 1) << 0) | - ((CARRY_FLAG(1) & 1) << 1) | - ((CARRY_FLAG(2) & 1) << 2) | - ((CARRY_FLAG(3) & 1) << 3) | - ((CARRY_FLAG(4) & 1) << 4) | - ((CARRY_FLAG(5) & 1) << 5) | - ((CARRY_FLAG(6) & 1) << 6) | - ((CARRY_FLAG(7) & 1) << 7) | - ((ZERO_FLAG(0) & 1) << 8) | - ((ZERO_FLAG(1) & 1) << 9) | - ((ZERO_FLAG(2) & 1) << 10) | - ((ZERO_FLAG(3) & 1) << 11) | - ((ZERO_FLAG(4) & 1) << 12) | - ((ZERO_FLAG(5) & 1) << 13) | - ((ZERO_FLAG(6) & 1) << 14) | - ((ZERO_FLAG(7) & 1) << 15); - if (RTVAL & 0x8000) RTVAL |= 0xffff0000; - break; - case 1: - RTVAL = ((COMPARE_FLAG(0) & 1) << 0) | - ((COMPARE_FLAG(1) & 1) << 1) | - ((COMPARE_FLAG(2) & 1) << 2) | - ((COMPARE_FLAG(3) & 1) << 3) | - ((COMPARE_FLAG(4) & 1) << 4) | - ((COMPARE_FLAG(5) & 1) << 5) | - ((COMPARE_FLAG(6) & 1) << 6) | - ((COMPARE_FLAG(7) & 1) << 7) | - ((CLIP2_FLAG(0) & 1) << 8) | - ((CLIP2_FLAG(1) & 1) << 9) | - ((CLIP2_FLAG(2) & 1) << 10) | - ((CLIP2_FLAG(3) & 1) << 11) | - ((CLIP2_FLAG(4) & 1) << 12) | - ((CLIP2_FLAG(5) & 1) << 13) | - ((CLIP2_FLAG(6) & 1) << 14) | - ((CLIP2_FLAG(7) & 1) << 15); - if (RTVAL & 0x8000) RTVAL |= 0xffff0000; - break; - case 2: - RTVAL = ((CLIP1_FLAG(0) & 1) << 0) | - ((CLIP1_FLAG(1) & 1) << 1) | - ((CLIP1_FLAG(2) & 1) << 2) | - ((CLIP1_FLAG(3) & 1) << 3) | - ((CLIP1_FLAG(4) & 1) << 4) | - ((CLIP1_FLAG(5) & 1) << 5) | - ((CLIP1_FLAG(6) & 1) << 6) | - ((CLIP1_FLAG(7) & 1) << 7); - break; - } - } -} - - -void rsp_device::cop2_drc::mtc2() -{ - uint32_t op = m_rspcop2_state->op; - int el = (op >> 7) & 0xf; - VREG_B(VS1REG, (el+0) & 0xf) = (RTVAL >> 8) & 0xff; - VREG_B(VS1REG, (el+1) & 0xf) = (RTVAL >> 0) & 0xff; -} - - -void rsp_device::cop2_drc::ctc2() -{ - uint32_t op = m_rspcop2_state->op; - switch(RDREG) - { - case 0: - CLEAR_CARRY_FLAGS(); - CLEAR_ZERO_FLAGS(); - m_vflag[0][0] = ((RTVAL >> 0) & 1) ? 0xffff : 0; - m_vflag[0][1] = ((RTVAL >> 1) & 1) ? 0xffff : 0; - m_vflag[0][2] = ((RTVAL >> 2) & 1) ? 0xffff : 0; - m_vflag[0][3] = ((RTVAL >> 3) & 1) ? 0xffff : 0; - m_vflag[0][4] = ((RTVAL >> 4) & 1) ? 0xffff : 0; - m_vflag[0][5] = ((RTVAL >> 5) & 1) ? 0xffff : 0; - m_vflag[0][6] = ((RTVAL >> 6) & 1) ? 0xffff : 0; - m_vflag[0][7] = ((RTVAL >> 7) & 1) ? 0xffff : 0; - if (RTVAL & (1 << 0)) { SET_CARRY_FLAG(0); } - if (RTVAL & (1 << 1)) { SET_CARRY_FLAG(1); } - if (RTVAL & (1 << 2)) { SET_CARRY_FLAG(2); } - if (RTVAL & (1 << 3)) { SET_CARRY_FLAG(3); } - if (RTVAL & (1 << 4)) { SET_CARRY_FLAG(4); } - if (RTVAL & (1 << 5)) { SET_CARRY_FLAG(5); } - if (RTVAL & (1 << 6)) { SET_CARRY_FLAG(6); } - if (RTVAL & (1 << 7)) { SET_CARRY_FLAG(7); } - m_vflag[3][0] = ((RTVAL >> 8) & 1) ? 0xffff : 0; - m_vflag[3][1] = ((RTVAL >> 9) & 1) ? 0xffff : 0; - m_vflag[3][2] = ((RTVAL >> 10) & 1) ? 0xffff : 0; - m_vflag[3][3] = ((RTVAL >> 11) & 1) ? 0xffff : 0; - m_vflag[3][4] = ((RTVAL >> 12) & 1) ? 0xffff : 0; - m_vflag[3][5] = ((RTVAL >> 13) & 1) ? 0xffff : 0; - m_vflag[3][6] = ((RTVAL >> 14) & 1) ? 0xffff : 0; - m_vflag[3][7] = ((RTVAL >> 15) & 1) ? 0xffff : 0; - if (RTVAL & (1 << 8)) { SET_ZERO_FLAG(0); } - if (RTVAL & (1 << 9)) { SET_ZERO_FLAG(1); } - if (RTVAL & (1 << 10)) { SET_ZERO_FLAG(2); } - if (RTVAL & (1 << 11)) { SET_ZERO_FLAG(3); } - if (RTVAL & (1 << 12)) { SET_ZERO_FLAG(4); } - if (RTVAL & (1 << 13)) { SET_ZERO_FLAG(5); } - if (RTVAL & (1 << 14)) { SET_ZERO_FLAG(6); } - if (RTVAL & (1 << 15)) { SET_ZERO_FLAG(7); } - break; - case 1: - CLEAR_COMPARE_FLAGS(); - CLEAR_CLIP2_FLAGS(); - m_vflag[1][0] = ((RTVAL >> 0) & 1) ? 0xffff : 0; - m_vflag[1][1] = ((RTVAL >> 1) & 1) ? 0xffff : 0; - m_vflag[1][2] = ((RTVAL >> 2) & 1) ? 0xffff : 0; - m_vflag[1][3] = ((RTVAL >> 3) & 1) ? 0xffff : 0; - m_vflag[1][4] = ((RTVAL >> 4) & 1) ? 0xffff : 0; - m_vflag[1][5] = ((RTVAL >> 5) & 1) ? 0xffff : 0; - m_vflag[1][6] = ((RTVAL >> 6) & 1) ? 0xffff : 0; - m_vflag[1][7] = ((RTVAL >> 7) & 1) ? 0xffff : 0; - if (RTVAL & (1 << 0)) { SET_COMPARE_FLAG(0); } - if (RTVAL & (1 << 1)) { SET_COMPARE_FLAG(1); } - if (RTVAL & (1 << 2)) { SET_COMPARE_FLAG(2); } - if (RTVAL & (1 << 3)) { SET_COMPARE_FLAG(3); } - if (RTVAL & (1 << 4)) { SET_COMPARE_FLAG(4); } - if (RTVAL & (1 << 5)) { SET_COMPARE_FLAG(5); } - if (RTVAL & (1 << 6)) { SET_COMPARE_FLAG(6); } - if (RTVAL & (1 << 7)) { SET_COMPARE_FLAG(7); } - m_vflag[4][0] = ((RTVAL >> 8) & 1) ? 0xffff : 0; - m_vflag[4][1] = ((RTVAL >> 9) & 1) ? 0xffff : 0; - m_vflag[4][2] = ((RTVAL >> 10) & 1) ? 0xffff : 0; - m_vflag[4][3] = ((RTVAL >> 11) & 1) ? 0xffff : 0; - m_vflag[4][4] = ((RTVAL >> 12) & 1) ? 0xffff : 0; - m_vflag[4][5] = ((RTVAL >> 13) & 1) ? 0xffff : 0; - m_vflag[4][6] = ((RTVAL >> 14) & 1) ? 0xffff : 0; - m_vflag[4][7] = ((RTVAL >> 15) & 1) ? 0xffff : 0; - if (RTVAL & (1 << 8)) { SET_CLIP2_FLAG(0); } - if (RTVAL & (1 << 9)) { SET_CLIP2_FLAG(1); } - if (RTVAL & (1 << 10)) { SET_CLIP2_FLAG(2); } - if (RTVAL & (1 << 11)) { SET_CLIP2_FLAG(3); } - if (RTVAL & (1 << 12)) { SET_CLIP2_FLAG(4); } - if (RTVAL & (1 << 13)) { SET_CLIP2_FLAG(5); } - if (RTVAL & (1 << 14)) { SET_CLIP2_FLAG(6); } - if (RTVAL & (1 << 15)) { SET_CLIP2_FLAG(7); } - break; - case 2: - CLEAR_CLIP1_FLAGS(); - m_vflag[2][0] = ((RTVAL >> 0) & 1) ? 0xffff : 0; - m_vflag[2][1] = ((RTVAL >> 1) & 1) ? 0xffff : 0; - m_vflag[2][2] = ((RTVAL >> 2) & 1) ? 0xffff : 0; - m_vflag[2][3] = ((RTVAL >> 3) & 1) ? 0xffff : 0; - m_vflag[2][4] = ((RTVAL >> 4) & 1) ? 0xffff : 0; - m_vflag[2][5] = ((RTVAL >> 5) & 1) ? 0xffff : 0; - m_vflag[2][6] = ((RTVAL >> 6) & 1) ? 0xffff : 0; - m_vflag[2][7] = ((RTVAL >> 7) & 1) ? 0xffff : 0; - if (RTVAL & (1 << 0)) { SET_CLIP1_FLAG(0); } - if (RTVAL & (1 << 1)) { SET_CLIP1_FLAG(1); } - if (RTVAL & (1 << 2)) { SET_CLIP1_FLAG(2); } - if (RTVAL & (1 << 3)) { SET_CLIP1_FLAG(3); } - if (RTVAL & (1 << 4)) { SET_CLIP1_FLAG(4); } - if (RTVAL & (1 << 5)) { SET_CLIP1_FLAG(5); } - if (RTVAL & (1 << 6)) { SET_CLIP1_FLAG(6); } - if (RTVAL & (1 << 7)) { SET_CLIP1_FLAG(7); } - break; - } -} - -/*************************************************************************** - COP2 Opcode Compilation -***************************************************************************/ - -bool rsp_device::cop2_drc::generate_cop2(drcuml_block &block, rsp_device::compiler_state &compiler, const opcode_desc *desc) -{ - uint32_t op = desc->opptr.l[0]; - uint8_t opswitch = RSREG; - - switch (opswitch) - { - case 0x00: /* MFCz */ - if (RTREG != 0) - { - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_mfc2, this); // callc mfc2 - } - return true; - - case 0x02: /* CFCz */ - if (RTREG != 0) - { - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_cfc2, this); // callc cfc2 - } - return true; - - case 0x04: /* MTCz */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_mtc2, this); // callc mtc2 - return true; - - case 0x06: /* CTCz */ - UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, &cop2_drc::cfunc_ctc2, this); // callc ctc2 - return true; - - case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: - case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: - return generate_vector_opcode(block, compiler, desc); - } - return false; -} diff --git a/src/devices/cpu/rsp/rspcp2d.h b/src/devices/cpu/rsp/rspcp2d.h deleted file mode 100644 index 09263a39cdf..00000000000 --- a/src/devices/cpu/rsp/rspcp2d.h +++ /dev/null @@ -1,179 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Ryan Holtz -/*************************************************************************** - - rspcp2d.h - - Interface file for Reality Signal Processor (RSP) vector extensions - using Universal Machine Language (UML) dynamic recompilation. - -***************************************************************************/ -#ifndef MAME_CPU_RSP_RSPCP2D_H -#define MAME_CPU_RSP_RSPCP2D_H - -#pragma once - -#include "rsp.h" -#include "rspcp2.h" -#include "cpu/drcuml.h" - - -class rsp_device::cop2_drc : public rsp_device::cop2 -{ - friend class rsp_device; -public: - cop2_drc(rsp_device &rsp, running_machine &machine) : cop2(rsp, machine) { } -private: - virtual bool generate_cop2(drcuml_block &block, rsp_device::compiler_state &compiler, const opcode_desc *desc) override; - virtual bool generate_lwc2(drcuml_block &block, rsp_device::compiler_state &compiler, const opcode_desc *desc) override; - virtual bool generate_swc2(drcuml_block &block, rsp_device::compiler_state &compiler, const opcode_desc *desc) override; - - virtual void state_string_export(const int index, std::string &str) const override; - - void cfunc_unimplemented_opcode() override; - - static void unimplemented_opcode(void *param) { ((cop2 *)param)->cfunc_unimplemented_opcode(); } - static void cfunc_lbv(void *param) { ((cop2 *)param)->lbv(); } - static void cfunc_lsv(void *param) { ((cop2 *)param)->lsv(); } - static void cfunc_llv(void *param) { ((cop2 *)param)->llv(); } - static void cfunc_ldv(void *param) { ((cop2 *)param)->ldv(); } - static void cfunc_lqv(void *param) { ((cop2 *)param)->lqv(); } - static void cfunc_lrv(void *param) { ((cop2 *)param)->lrv(); } - static void cfunc_lpv(void *param) { ((cop2 *)param)->lpv(); } - static void cfunc_luv(void *param) { ((cop2 *)param)->luv(); } - static void cfunc_lhv(void *param) { ((cop2 *)param)->lhv(); } - static void cfunc_lfv(void *param) { ((cop2 *)param)->lfv(); } - static void cfunc_lwv(void *param) { ((cop2 *)param)->lwv(); } - static void cfunc_ltv(void *param) { ((cop2 *)param)->ltv(); } - static void cfunc_sbv(void *param) { ((cop2 *)param)->sbv(); } - static void cfunc_ssv(void *param) { ((cop2 *)param)->ssv(); } - static void cfunc_slv(void *param) { ((cop2 *)param)->slv(); } - static void cfunc_sdv(void *param) { ((cop2 *)param)->sdv(); } - static void cfunc_sqv(void *param) { ((cop2 *)param)->sqv(); } - static void cfunc_srv(void *param) { ((cop2 *)param)->srv(); } - static void cfunc_spv(void *param) { ((cop2 *)param)->spv(); } - static void cfunc_suv(void *param) { ((cop2 *)param)->suv(); } - static void cfunc_shv(void *param) { ((cop2 *)param)->shv(); } - static void cfunc_sfv(void *param) { ((cop2 *)param)->sfv(); } - static void cfunc_swv(void *param) { ((cop2 *)param)->swv(); } - static void cfunc_stv(void *param) { ((cop2 *)param)->stv(); } - static void cfunc_vmulf(void *param) { ((cop2 *)param)->vmulf(); } - static void cfunc_vmulu(void *param) { ((cop2 *)param)->vmulu(); } - static void cfunc_vmudl(void *param) { ((cop2 *)param)->vmudl(); } - static void cfunc_vmudm(void *param) { ((cop2 *)param)->vmudm(); } - static void cfunc_vmudn(void *param) { ((cop2 *)param)->vmudn(); } - static void cfunc_vmudh(void *param) { ((cop2 *)param)->vmudh(); } - static void cfunc_vmacf(void *param) { ((cop2 *)param)->vmacf(); } - static void cfunc_vmacu(void *param) { ((cop2 *)param)->vmacu(); } - static void cfunc_vmadl(void *param) { ((cop2 *)param)->vmadl(); } - static void cfunc_vmadm(void *param) { ((cop2 *)param)->vmadm(); } - static void cfunc_vmadn(void *param) { ((cop2 *)param)->vmadn(); } - static void cfunc_vmadh(void *param) { ((cop2 *)param)->vmadh(); } - static void cfunc_vadd(void *param) { ((cop2 *)param)->vadd(); } - static void cfunc_vsub(void *param) { ((cop2 *)param)->vsub(); } - static void cfunc_vabs(void *param) { ((cop2 *)param)->vabs(); } - static void cfunc_vaddc(void *param) { ((cop2 *)param)->vaddc(); } - static void cfunc_vsubc(void *param) { ((cop2 *)param)->vsubc(); } - static void cfunc_vaddb(void *param) { ((cop2 *)param)->vaddb(); } - static void cfunc_vsaw(void *param) { ((cop2 *)param)->vsaw(); } - static void cfunc_vlt(void *param) { ((cop2 *)param)->vlt(); } - static void cfunc_veq(void *param) { ((cop2 *)param)->veq(); } - static void cfunc_vne(void *param) { ((cop2 *)param)->vne(); } - static void cfunc_vge(void *param) { ((cop2 *)param)->vge(); } - static void cfunc_vcl(void *param) { ((cop2 *)param)->vcl(); } - static void cfunc_vch(void *param) { ((cop2 *)param)->vch(); } - static void cfunc_vcr(void *param) { ((cop2 *)param)->vcr(); } - static void cfunc_vmrg(void *param) { ((cop2 *)param)->vmrg(); } - static void cfunc_vand(void *param) { ((cop2 *)param)->vand(); } - static void cfunc_vnand(void *param) { ((cop2 *)param)->vnand(); } - static void cfunc_vor(void *param) { ((cop2 *)param)->vor(); } - static void cfunc_vnor(void *param) { ((cop2 *)param)->vnor(); } - static void cfunc_vxor(void *param) { ((cop2 *)param)->vxor(); } - static void cfunc_vnxor(void *param) { ((cop2 *)param)->vnxor(); } - static void cfunc_vrcp(void *param) { ((cop2 *)param)->vrcp(); } - static void cfunc_vrcpl(void *param) { ((cop2 *)param)->vrcpl(); } - static void cfunc_vrcph(void *param) { ((cop2 *)param)->vrcph(); } - static void cfunc_vmov(void *param) { ((cop2 *)param)->vmov(); } - static void cfunc_vrsq(void *param) { ((cop2 *)param)->vrsq(); } - static void cfunc_vrsql(void *param) { ((cop2 *)param)->vrsql(); } - static void cfunc_vrsqh(void *param) { ((cop2 *)param)->vrsqh(); } - static void cfunc_mfc2(void *param) { ((cop2 *)param)->mfc2(); } - static void cfunc_cfc2(void *param) { ((cop2 *)param)->cfc2(); } - static void cfunc_mtc2(void *param) { ((cop2 *)param)->mtc2(); } - static void cfunc_ctc2(void *param) { ((cop2 *)param)->ctc2(); } - -public: - virtual void lbv() override; - virtual void lsv() override; - virtual void llv() override; - virtual void ldv() override; - virtual void lqv() override; - virtual void lrv() override; - virtual void lpv() override; - virtual void luv() override; - virtual void lhv() override; - virtual void lfv() override; - virtual void lwv() override; - virtual void ltv() override; - virtual void sbv() override; - virtual void ssv() override; - virtual void slv() override; - virtual void sdv() override; - virtual void sqv() override; - virtual void srv() override; - virtual void spv() override; - virtual void suv() override; - virtual void shv() override; - virtual void sfv() override; - virtual void swv() override; - virtual void stv() override; - virtual void vmulf() override; - virtual void vmulu() override; - virtual void vmudl() override; - virtual void vmudm() override; - virtual void vmudn() override; - virtual void vmudh() override; - virtual void vmacf() override; - virtual void vmacu() override; - virtual void vmadl() override; - virtual void vmadm() override; - virtual void vmadn() override; - virtual void vmadh() override; - virtual void vadd() override; - virtual void vsub() override; - virtual void vabs() override; - virtual void vaddc() override; - virtual void vsubc() override; - virtual void vaddb() override; - virtual void vsaw() override; - virtual void vlt() override; - virtual void veq() override; - virtual void vne() override; - virtual void vge() override; - virtual void vcl() override; - virtual void vch() override; - virtual void vcr() override; - virtual void vmrg() override; - virtual void vand() override; - virtual void vnand() override; - virtual void vor() override; - virtual void vnor() override; - virtual void vxor() override; - virtual void vnxor() override; - virtual void vrcp() override; - virtual void vrcpl() override; - virtual void vrcph() override; - virtual void vmov() override; - virtual void vrsql() override; - virtual void vrsqh() override; - virtual void vrsq() override; - virtual void mfc2() override; - virtual void cfc2() override; - virtual void mtc2() override; - virtual void ctc2() override; - -private: - virtual bool generate_vector_opcode(drcuml_block &block, rsp_device::compiler_state &compiler, const opcode_desc *desc) override; -}; - -#endif // MAME_CPU_RSP_RSPCP2D_H diff --git a/src/devices/cpu/rsp/rspdrc.cpp b/src/devices/cpu/rsp/rspdrc.cpp deleted file mode 100644 index d2e89b4a77a..00000000000 --- a/src/devices/cpu/rsp/rspdrc.cpp +++ /dev/null @@ -1,1279 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Ryan Holtz -/*************************************************************************** - - rspdrc.c - - Universal machine language-based Nintendo/SGI RSP emulator. - Written by Ryan Holtz - SIMD versions of vector multiplication opcodes provided by Marathon Man - of the CEN64 team. - -**************************************************************************** - - Future improvements/changes: - - * Confer with Aaron Giles about adding a memory hash-based caching - system and static recompilation for maximum overhead minimization - -***************************************************************************/ - -#include "emu.h" -#include "rsp.h" -#include "rsp_dasm.h" - -#include "rspfe.h" -#include "rspcp2.h" -#include "cpu/drcfe.h" -#include "cpu/drcuml.h" -#include "cpu/drcumlsh.h" - -#include "debugger.h" - -#include "rspdefs.h" - - -/*************************************************************************** - CONSTANTS -***************************************************************************/ - -/* map variables */ -#define MAPVAR_PC M0 -#define MAPVAR_CYCLES M1 - -/* exit codes */ -#define EXECUTE_OUT_OF_CYCLES 0 -#define EXECUTE_MISSING_CODE 1 -#define EXECUTE_UNMAPPED_CODE 2 -#define EXECUTE_RESET_CACHE 3 - - - -/*************************************************************************** - Macros -***************************************************************************/ - -#define R32(reg) m_regmap[reg] - -/*************************************************************************** - Inline Functions -***************************************************************************/ - -/*------------------------------------------------- - epc - compute the exception PC from a - descriptor --------------------------------------------------*/ - -static inline uint32_t epc(const opcode_desc *desc) -{ - return ((desc->flags & OPFLAG_IN_DELAY_SLOT) ? (desc->pc - 3) : desc->pc) | 0x1000; -} - - -/*------------------------------------------------- - alloc_handle - allocate a handle if not - already allocated --------------------------------------------------*/ - -static inline void alloc_handle(drcuml_state &drcuml, uml::code_handle *&handleptr, const char *name) -{ - if (!handleptr) - handleptr = drcuml.handle_alloc(name); -} - - -/*------------------------------------------------- - load_fast_iregs - load any fast integer - registers --------------------------------------------------*/ - -inline void rsp_device::load_fast_iregs(drcuml_block &block) -{ - int regnum; - - for (regnum = 0; regnum < std::size(m_regmap); regnum++) - if (m_regmap[regnum].is_int_register()) - UML_MOV(block, ireg(m_regmap[regnum].ireg() - REG_I0), mem(&m_rsp_state->r[regnum])); -} - - -/*------------------------------------------------- - save_fast_iregs - save any fast integer - registers --------------------------------------------------*/ - -inline void rsp_device::save_fast_iregs(drcuml_block &block) -{ - int regnum; - - for (regnum = 0; regnum < std::size(m_regmap); regnum++) - if (m_regmap[regnum].is_int_register()) - UML_MOV(block, mem(&m_rsp_state->r[regnum]), ireg(m_regmap[regnum].ireg() - REG_I0)); -} - -/*************************************************************************** - CORE CALLBACKS -***************************************************************************/ - -inline void rsp_device::ccfunc_read8() -{ - m_rsp_state->arg0 = DM_READ8(m_rsp_state->arg0); -} - -static void cfunc_read8(void *param) -{ - ((rsp_device *)param)->ccfunc_read8(); -} - -inline void rsp_device::ccfunc_read16() -{ - m_rsp_state->arg0 = DM_READ16(m_rsp_state->arg0); -} - -static void cfunc_read16(void *param) -{ - ((rsp_device *)param)->ccfunc_read16(); -} - -inline void rsp_device::ccfunc_read32() -{ - m_rsp_state->arg0 = DM_READ32(m_rsp_state->arg0); -} - -static void cfunc_read32(void *param) -{ - ((rsp_device *)param)->ccfunc_read32(); -} - -inline void rsp_device::ccfunc_write8() -{ - DM_WRITE8(m_rsp_state->arg0, m_rsp_state->arg1); -} - -static void cfunc_write8(void *param) -{ - ((rsp_device *)param)->ccfunc_write8(); -} - -inline void rsp_device::ccfunc_write16() -{ - DM_WRITE16(m_rsp_state->arg0, m_rsp_state->arg1); -} - -static void cfunc_write16(void *param) -{ - ((rsp_device *)param)->ccfunc_write16(); -} - -inline void rsp_device::ccfunc_write32() -{ - DM_WRITE32(m_rsp_state->arg0, m_rsp_state->arg1); -} - -static void cfunc_write32(void *param) -{ - ((rsp_device *)param)->ccfunc_write32(); -} - -/*****************************************************************************/ - -/*------------------------------------------------- - rspdrc_set_options - configure DRC options --------------------------------------------------*/ - -void rsp_device::rspdrc_set_options(uint32_t options) -{ - if (!allow_drc()) return; - m_drcoptions = options; -} - - -inline void rsp_device::ccfunc_get_cop0_reg() -{ - int reg = m_rsp_state->arg0; - int dest = m_rsp_state->arg1; - - if (reg >= 0 && reg < 8) - { - if(dest) - { - m_rsp_state->r[dest] = m_sp_reg_r_func(reg, 0xffffffff); - } - } - else if (reg >= 8 && reg < 16) - { - if(dest) - { - m_rsp_state->r[dest] = m_dp_reg_r_func(reg - 8, 0xffffffff); - } - } - else - { - fatalerror("RSP: cfunc_get_cop0_reg: %d\n", reg); - } -} - -static void cfunc_get_cop0_reg(void *param) -{ - ((rsp_device *)param)->ccfunc_get_cop0_reg(); -} - -inline void rsp_device::ccfunc_set_cop0_reg() -{ - int reg = m_rsp_state->arg0; - uint32_t data = m_rsp_state->arg1; - - if (reg >= 0 && reg < 8) - { - m_sp_reg_w_func(reg, data, 0xffffffff); - } - else if (reg >= 8 && reg < 16) - { - m_dp_reg_w_func(reg - 8, data, 0xffffffff); - } - else - { - fatalerror("RSP: set_cop0_reg: %d, %08X\n", reg, data); - } -} - -static void cfunc_set_cop0_reg(void *param) -{ - ((rsp_device *)param)->ccfunc_set_cop0_reg(); -} - -/*****************************************************************************/ - -void rsp_device::rspcom_init() -{ -} - -inline void rsp_device::ccfunc_sp_set_status_cb() -{ - m_sp_set_status_func(0, m_rsp_state->arg0, 0xffffffff); -} - -void cfunc_sp_set_status_cb(void *param) -{ - ((rsp_device *)param)->ccfunc_sp_set_status_cb(); -} - -void rsp_device::execute_run_drc() -{ - int execute_result; - - /* reset the cache if dirty */ - if (m_cache_dirty) - code_flush_cache(); - m_cache_dirty = false; - - /* execute */ - do - { - if( m_sr & ( RSP_STATUS_HALT | RSP_STATUS_BROKE ) ) - { - m_rsp_state->icount = std::min(m_rsp_state->icount, 0); - break; - } - - /* run as much as we can */ - execute_result = m_drcuml->execute(*m_entry); - - /* if we need to recompile, do it */ - if (execute_result == EXECUTE_MISSING_CODE) - { - code_compile_block(m_rsp_state->pc); - } - else if (execute_result == EXECUTE_UNMAPPED_CODE) - { - fatalerror("Attempted to execute unmapped code at PC=%08X\n", m_rsp_state->pc); - } - else if (execute_result == EXECUTE_RESET_CACHE) - { - code_flush_cache(); - } - } while (execute_result != EXECUTE_OUT_OF_CYCLES); -} - -/*************************************************************************** - CACHE MANAGEMENT -***************************************************************************/ - -/*------------------------------------------------- - rspdrc_flush_drc_cache - outward-facing - accessor to code_flush_cache --------------------------------------------------*/ - -void rsp_device::rspdrc_flush_drc_cache() -{ - if (!allow_drc()) return; - m_cache_dirty = true; -} - -/*------------------------------------------------- - code_flush_cache - flush the cache and - regenerate static code --------------------------------------------------*/ - -void rsp_device::code_flush_cache() -{ - /* empty the transient cache contents */ - m_drcuml->reset(); - - try - { - /* generate the entry point and out-of-cycles handlers */ - static_generate_entry_point(); - static_generate_nocode_handler(); - static_generate_out_of_cycles(); - - /* add subroutines for memory accesses */ - static_generate_memory_accessor(1, false, "read8", m_read8); - static_generate_memory_accessor(1, true, "write8", m_write8); - static_generate_memory_accessor(2, false, "read16", m_read16); - static_generate_memory_accessor(2, true, "write16", m_write16); - static_generate_memory_accessor(4, false, "read32", m_read32); - static_generate_memory_accessor(4, true, "write32", m_write32); - } - catch (drcuml_block::abort_compilation &) - { - fatalerror("Unable to generate static RSP code\n"); - } -} - - -/*------------------------------------------------- - code_compile_block - compile a block of the - given mode at the specified pc --------------------------------------------------*/ - -void rsp_device::code_compile_block(offs_t pc) -{ - compiler_state compiler = { 0 }; - const opcode_desc *seqhead, *seqlast; - const opcode_desc *desclist; - int override = false; - - g_profiler.start(PROFILER_DRC_COMPILE); - - /* get a description of this sequence */ - desclist = m_drcfe->describe_code(pc); - - bool succeeded = false; - while (!succeeded) - { - try - { - /* start the block */ - drcuml_block &block(m_drcuml->begin_block(4096)); - - /* loop until we get through all instruction sequences */ - for (seqhead = desclist; seqhead != nullptr; seqhead = seqlast->next()) - { - const opcode_desc *curdesc; - uint32_t nextpc; - - /* add a code log entry */ - if (m_drcuml->logging()) - block.append_comment("-------------------------"); // comment - - /* determine the last instruction in this sequence */ - for (seqlast = seqhead; seqlast != nullptr; seqlast = seqlast->next()) - if (seqlast->flags & OPFLAG_END_SEQUENCE) - break; - assert(seqlast != nullptr); - - /* if we don't have a hash for this mode/pc, or if we are overriding all, add one */ - if (override || !m_drcuml->hash_exists(0, seqhead->pc)) - UML_HASH(block, 0, seqhead->pc); // hash mode,pc - - /* if we already have a hash, and this is the first sequence, assume that we */ - /* are recompiling due to being out of sync and allow future overrides */ - else if (seqhead == desclist) - { - override = true; - UML_HASH(block, 0, seqhead->pc); // hash mode,pc - } - - /* otherwise, redispatch to that fixed PC and skip the rest of the processing */ - else - { - UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc - UML_HASHJMP(block, 0, seqhead->pc, *m_nocode); - // hashjmp <0>,seqhead->pc,nocode - continue; - } - - /* validate this code block if we're not pointing into ROM */ - if (m_program.space().get_write_ptr(seqhead->physpc) != nullptr) - generate_checksum_block(block, compiler, seqhead, seqlast); - - /* label this instruction, if it may be jumped to locally */ - if (seqhead->flags & OPFLAG_IS_BRANCH_TARGET) - UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc - - /* iterate over instructions in the sequence and compile them */ - for (curdesc = seqhead; curdesc != seqlast->next(); curdesc = curdesc->next()) - generate_sequence_instruction(block, compiler, curdesc); - - /* if we need to return to the start, do it */ - if (seqlast->flags & OPFLAG_RETURN_TO_START) - nextpc = pc; - - /* otherwise we just go to the next instruction */ - else - nextpc = seqlast->pc + (seqlast->skipslots + 1) * 4; - - /* count off cycles and go there */ - generate_update_cycles(block, compiler, nextpc, true); // <subtract cycles> - - /* if the last instruction can change modes, use a variable mode; otherwise, assume the same mode */ - if (seqlast->next() == nullptr || seqlast->next()->pc != nextpc) - UML_HASHJMP(block, 0, nextpc, *m_nocode); // hashjmp <mode>,nextpc,nocode - } - - /* end the sequence */ - block.end(); - g_profiler.stop(); - succeeded = true; - } - catch (drcuml_block::abort_compilation &) - { - code_flush_cache(); - } - } -} - -/*************************************************************************** - C FUNCTION CALLBACKS -***************************************************************************/ - -/*------------------------------------------------- - cfunc_unimplemented - handler for - unimplemented opcdes --------------------------------------------------*/ - -inline void rsp_device::ccfunc_unimplemented() -{ - uint32_t opcode = m_rsp_state->arg0; - fatalerror("PC=%08X: Unimplemented op %08X (%02X,%02X)\n", m_rsp_state->pc, opcode, opcode >> 26, opcode & 0x3f); -} - -static void cfunc_unimplemented(void *param) -{ - ((rsp_device *)param)->ccfunc_unimplemented(); -} - -/*------------------------------------------------- - cfunc_fatalerror - a generic fatalerror call --------------------------------------------------*/ - -#ifdef UNUSED_CODE -static void cfunc_fatalerror(void *param) -{ - fatalerror("fatalerror\n"); -} -#endif - - -/*************************************************************************** - STATIC CODEGEN -***************************************************************************/ - -/*------------------------------------------------- - ferate_entry_point - generate a - static entry point --------------------------------------------------*/ - -void rsp_device::static_generate_entry_point() -{ - /* begin generating */ - drcuml_block &block(m_drcuml->begin_block(20)); - - /* forward references */ - alloc_handle(*m_drcuml, m_nocode, "nocode"); - - alloc_handle(*m_drcuml, m_entry, "entry"); - UML_HANDLE(block, *m_entry); // handle entry - - /* load fast integer registers */ - load_fast_iregs(block); - - /* generate a hash jump via the current mode and PC */ - UML_HASHJMP(block, 0, mem(&m_rsp_state->pc), *m_nocode); // hashjmp <mode>,<pc>,nocode - block.end(); -} - - -/*------------------------------------------------- - static_generate_nocode_handler - generate an - exception handler for "out of code" --------------------------------------------------*/ - -void rsp_device::static_generate_nocode_handler() -{ - /* begin generating */ - drcuml_block &block(m_drcuml->begin_block(10)); - - /* generate a hash jump via the current mode and PC */ - alloc_handle(*m_drcuml, m_nocode, "nocode"); - UML_HANDLE(block, *m_nocode); // handle nocode - UML_GETEXP(block, I0); // getexp i0 - UML_MOV(block, mem(&m_rsp_state->pc), I0); // mov [pc],i0 - save_fast_iregs(block); - UML_EXIT(block, EXECUTE_MISSING_CODE); // exit EXECUTE_MISSING_CODE - - block.end(); -} - - -/*------------------------------------------------- - static_generate_out_of_cycles - generate an - out of cycles exception handler --------------------------------------------------*/ - -void rsp_device::static_generate_out_of_cycles() -{ - /* begin generating */ - drcuml_block &block(m_drcuml->begin_block(10)); - - /* generate a hash jump via the current mode and PC */ - alloc_handle(*m_drcuml, m_out_of_cycles, "out_of_cycles"); - UML_HANDLE(block, *m_out_of_cycles); // handle out_of_cycles - UML_GETEXP(block, I0); // getexp i0 - UML_MOV(block, mem(&m_rsp_state->pc), I0); // mov <pc>,i0 - save_fast_iregs(block); - UML_EXIT(block, EXECUTE_OUT_OF_CYCLES); // exit EXECUTE_OUT_OF_CYCLES - - block.end(); -} - -/*------------------------------------------------------------------ - static_generate_memory_accessor -------------------------------------------------------------------*/ - -void rsp_device::static_generate_memory_accessor(int size, int iswrite, const char *name, uml::code_handle *&handleptr) -{ - /* on entry, address is in I0; data for writes is in I1 */ - /* on exit, read result is in I0 */ - /* routine trashes I0-I1 */ - - /* begin generating */ - drcuml_block &block(m_drcuml->begin_block(1024)); - - /* add a global entry for this */ - alloc_handle(*m_drcuml, handleptr, name); - UML_HANDLE(block, *handleptr); // handle *handleptr - - // write: - if (iswrite) - { - if (size == 1) - { - UML_MOV(block, mem(&m_rsp_state->arg0), I0); // mov [arg0],i0 ; address - UML_MOV(block, mem(&m_rsp_state->arg1), I1); // mov [arg1],i1 ; data - UML_CALLC(block, cfunc_write8, this); // callc cfunc_write8 - } - else if (size == 2) - { - UML_MOV(block, mem(&m_rsp_state->arg0), I0); // mov [arg0],i0 ; address - UML_MOV(block, mem(&m_rsp_state->arg1), I1); // mov [arg1],i1 ; data - UML_CALLC(block, cfunc_write16, this); // callc cfunc_write16 - } - else if (size == 4) - { - UML_MOV(block, mem(&m_rsp_state->arg0), I0); // mov [arg0],i0 ; address - UML_MOV(block, mem(&m_rsp_state->arg1), I1); // mov [arg1],i1 ; data - UML_CALLC(block, cfunc_write32, this); // callc cfunc_write32 - } - } - else - { - if (size == 1) - { - UML_MOV(block, mem(&m_rsp_state->arg0), I0); // mov [arg0],i0 ; address - UML_CALLC(block, cfunc_read8, this); // callc read8 - UML_MOV(block, I0, mem(&m_rsp_state->arg0)); // mov i0,[arg0],i0 ; result - } - else if (size == 2) - { - UML_MOV(block, mem(&m_rsp_state->arg0), I0); // mov [arg0],i0 ; address - UML_CALLC(block, cfunc_read16, this); // callc cfunc_read16 - UML_MOV(block, I0, mem(&m_rsp_state->arg0)); // mov i0,[arg0],i0 ; result - } - else if (size == 4) - { - UML_MOV(block, mem(&m_rsp_state->arg0), I0); // mov [arg0],i0 ; address - UML_CALLC(block, cfunc_read32, this); // callc cfunc_read32 - UML_MOV(block, I0, mem(&m_rsp_state->arg0)); // mov i0,[arg0],i0 ; result - } - } - UML_RET(block); - - block.end(); -} - - - -/*************************************************************************** - CODE GENERATION -***************************************************************************/ - -/*------------------------------------------------- - generate_update_cycles - generate code to - subtract cycles from the icount and generate - an exception if out --------------------------------------------------*/ -void rsp_device::generate_update_cycles(drcuml_block &block, compiler_state &compiler, uml::parameter param, bool allow_exception) -{ - /* account for cycles */ - if (compiler.cycles > 0) - { - UML_SUB(block, mem(&m_rsp_state->icount), mem(&m_rsp_state->icount), MAPVAR_CYCLES); // sub icount,icount,cycles - UML_MAPVAR(block, MAPVAR_CYCLES, 0); // mapvar cycles,0 - UML_EXHc(block, COND_S, *m_out_of_cycles, param); - } - compiler.cycles = 0; -} - -/*------------------------------------------------- - generate_checksum_block - generate code to - validate a sequence of opcodes --------------------------------------------------*/ - -void rsp_device::generate_checksum_block(drcuml_block &block, compiler_state &compiler, const opcode_desc *seqhead, const opcode_desc *seqlast) -{ - const opcode_desc *curdesc; - if (m_drcuml->logging()) - { - block.append_comment("[Validation for %08X]", seqhead->pc | 0x1000); // comment - } - /* loose verify or single instruction: just compare and fail */ - if (!(m_drcoptions & RSPDRC_STRICT_VERIFY) || seqhead->next() == nullptr) - { - if (!(seqhead->flags & OPFLAG_VIRTUAL_NOOP)) - { - uint32_t sum = seqhead->opptr.l[0]; - void *base = m_pcache.read_ptr(seqhead->physpc | 0x1000); - UML_LOAD(block, I0, base, 0, SIZE_DWORD, SCALE_x4); // load i0,base,0,dword - - if (seqhead->delay.first() != nullptr && seqhead->physpc != seqhead->delay.first()->physpc) - { - base = m_pcache.read_ptr((seqhead->delay.first()->physpc & 0x00000fff) | 0x1000); - assert(base != nullptr); - UML_LOAD(block, I1, base, 0, SIZE_DWORD, SCALE_x4); // load i1,base,dword - UML_ADD(block, I0, I0, I1); // add i0,i0,i1 - - sum += seqhead->delay.first()->opptr.l[0]; - } - - UML_CMP(block, I0, sum); // cmp i0,opptr[0] - UML_EXHc(block, COND_NE, *m_nocode, epc(seqhead)); // exne nocode,seqhead->pc - } - } - - /* full verification; sum up everything */ - else - { - uint32_t sum = 0; - void *base = m_pcache.read_ptr(seqhead->physpc | 0x1000); - UML_LOAD(block, I0, base, 0, SIZE_DWORD, SCALE_x4); // load i0,base,0,dword - sum += seqhead->opptr.l[0]; - for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next()) - if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP)) - { - base = m_pcache.read_ptr(curdesc->physpc | 0x1000); - assert(base != nullptr); - UML_LOAD(block, I1, base, 0, SIZE_DWORD, SCALE_x4); // load i1,base,dword - UML_ADD(block, I0, I0, I1); // add i0,i0,i1 - sum += curdesc->opptr.l[0]; - - if (curdesc->delay.first() != nullptr && (curdesc == seqlast || (curdesc->next() != nullptr && curdesc->next()->physpc != curdesc->delay.first()->physpc))) - { - base = m_pcache.read_ptr((curdesc->delay.first()->physpc & 0x00000fff) | 0x1000); - assert(base != nullptr); - UML_LOAD(block, I1, base, 0, SIZE_DWORD, SCALE_x4); // load i1,base,dword - UML_ADD(block, I0, I0, I1); // add i0,i0,i1 - - sum += curdesc->delay.first()->opptr.l[0]; - } - } - UML_CMP(block, I0, sum); // cmp i0,sum - UML_EXHc(block, COND_NE, *m_nocode, epc(seqhead)); // exne nocode,seqhead->pc - } -} - - -/*------------------------------------------------- - generate_sequence_instruction - generate code - for a single instruction in a sequence --------------------------------------------------*/ - -void rsp_device::generate_sequence_instruction(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc) -{ - offs_t expc; - - /* add an entry for the log */ - if (m_drcuml->logging() && !(desc->flags & OPFLAG_VIRTUAL_NOOP)) - log_add_disasm_comment(block, desc->pc, desc->opptr.l[0]); - - /* set the PC map variable */ - expc = (desc->flags & OPFLAG_IN_DELAY_SLOT) ? desc->pc - 3 : desc->pc; - UML_MAPVAR(block, MAPVAR_PC, expc); // mapvar PC,expc - - /* accumulate total cycles */ - compiler.cycles += desc->cycles; - - /* update the icount map variable */ - UML_MAPVAR(block, MAPVAR_CYCLES, compiler.cycles); // mapvar CYCLES,compiler.cycles - - /* if we are debugging, call the debugger */ - if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) - { - UML_MOV(block, mem(&m_rsp_state->pc), desc->pc); // mov [pc],desc->pc - save_fast_iregs(block); - UML_DEBUG(block, desc->pc); // debug desc->pc - } - - /* if we hit an unmapped address, fatal error */ -#if 0 - if (desc->flags & OPFLAG_COMPILER_UNMAPPED) - { - UML_MOV(block, mem(&m_rsp_state->pc), desc->pc); // mov [pc],desc->pc - save_fast_iregs(block); - UML_EXIT(block, EXECUTE_UNMAPPED_CODE); // exit EXECUTE_UNMAPPED_CODE - } -#endif - - /* otherwise, unless this is a virtual no-op, it's a regular instruction */ - /*else*/ if (!(desc->flags & OPFLAG_VIRTUAL_NOOP)) - { - /* compile the instruction */ - if (!generate_opcode(block, compiler, desc)) - { - UML_MOV(block, mem(&m_rsp_state->pc), desc->pc); // mov [pc],desc->pc - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_unimplemented, this); // callc cfunc_unimplemented - } - } -} - -/*------------------------------------------------------------------ - generate_branch -------------------------------------------------------------------*/ - -void rsp_device::generate_branch(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc) -{ - compiler_state compiler_temp(compiler); - - /* update the cycles and jump through the hash table to the target */ - if (desc->targetpc != BRANCH_TARGET_DYNAMIC) - { - generate_update_cycles(block, compiler_temp, desc->targetpc, true); // <subtract cycles> - if (desc->flags & OPFLAG_INTRABLOCK_BRANCH) - UML_JMP(block, desc->targetpc | 0x80000000); // jmp desc->targetpc - else - UML_HASHJMP(block, 0, desc->targetpc, *m_nocode); // hashjmp <mode>,desc->targetpc,nocode - } - else - { - generate_update_cycles(block, compiler_temp, uml::mem(&m_rsp_state->jmpdest), true); // <subtract cycles> - UML_HASHJMP(block, 0, mem(&m_rsp_state->jmpdest), *m_nocode); // hashjmp <mode>,<rsreg>,nocode - } -} - -/*------------------------------------------------------------------ - generate_delay_slot_and_branch -------------------------------------------------------------------*/ - -void rsp_device::generate_delay_slot_and_branch(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc, uint8_t linkreg) -{ - compiler_state compiler_temp(compiler); - uint32_t op = desc->opptr.l[0]; - - /* fetch the target register if dynamic, in case it is modified by the delay slot */ - if (desc->targetpc == BRANCH_TARGET_DYNAMIC) - { - UML_AND(block, mem(&m_rsp_state->jmpdest), R32(RSREG), 0x00000fff); - UML_OR(block, mem(&m_rsp_state->jmpdest), mem(&m_rsp_state->jmpdest), 0x1000); - } - - /* set the link if needed -- before the delay slot */ - if (linkreg != 0) - { - UML_MOV(block, R32(linkreg), (int32_t)((desc->pc + 8) & 0x0000fff)); // mov <linkreg>,desc->pc + 8 - } - - /* compile the delay slot using temporary compiler state */ - assert(desc->delay.first() != nullptr); - generate_sequence_instruction(block, compiler_temp, desc->delay.first()); // <next instruction> - - generate_branch(block, compiler, desc); - - /* update the label */ - compiler.labelnum = compiler_temp.labelnum; - - /* reset the mapvar to the current cycles and account for skipped slots */ - compiler.cycles += desc->skipslots; - UML_MAPVAR(block, MAPVAR_CYCLES, compiler.cycles); // mapvar CYCLES,compiler.cycles -} - -bool rsp_device::generate_opcode(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc) -{ - int in_delay_slot = ((desc->flags & OPFLAG_IN_DELAY_SLOT) != 0); - uint32_t op = desc->opptr.l[0]; - uint8_t opswitch = op >> 26; - uml::code_label skip; - - switch (opswitch) - { - /* ----- sub-groups ----- */ - - case 0x00: /* SPECIAL - MIPS I */ - return generate_special(block, compiler, desc); - - case 0x01: /* REGIMM - MIPS I */ - return generate_regimm(block, compiler, desc); - - /* ----- jumps and branches ----- */ - - case 0x02: /* J - MIPS I */ - generate_delay_slot_and_branch(block, compiler, desc, 0); // <next instruction + hashjmp> - return true; - - case 0x03: /* JAL - MIPS I */ - generate_delay_slot_and_branch(block, compiler, desc, 31); // <next instruction + hashjmp> - return true; - - case 0x04: /* BEQ - MIPS I */ - UML_CMP(block, R32(RSREG), R32(RTREG)); // cmp <rsreg>,<rtreg> - UML_JMPc(block, COND_NE, skip = compiler.labelnum++); // jmp skip,NE - generate_delay_slot_and_branch(block, compiler, desc, 0); // <next instruction + hashjmp> - UML_LABEL(block, skip); // skip: - return true; - - case 0x05: /* BNE - MIPS I */ - UML_CMP(block, R32(RSREG), R32(RTREG)); // dcmp <rsreg>,<rtreg> - UML_JMPc(block, COND_E, skip = compiler.labelnum++); // jmp skip,E - generate_delay_slot_and_branch(block, compiler, desc, 0); // <next instruction + hashjmp> - UML_LABEL(block, skip); // skip: - return true; - - case 0x06: /* BLEZ - MIPS I */ - if (RSREG != 0) - { - UML_CMP(block, R32(RSREG), 0); // dcmp <rsreg>,0 - UML_JMPc(block, COND_G, skip = compiler.labelnum++); // jmp skip,G - generate_delay_slot_and_branch(block, compiler, desc, 0); // <next instruction + hashjmp> - UML_LABEL(block, skip); // skip: - } - else - generate_delay_slot_and_branch(block, compiler, desc, 0); // <next instruction + hashjmp> - return true; - - case 0x07: /* BGTZ - MIPS I */ - UML_CMP(block, R32(RSREG), 0); // dcmp <rsreg>,0 - UML_JMPc(block, COND_LE, skip = compiler.labelnum++); // jmp skip,LE - generate_delay_slot_and_branch(block, compiler, desc, 0); // <next instruction + hashjmp> - UML_LABEL(block, skip); // skip: - return true; - - - /* ----- immediate arithmetic ----- */ - - case 0x0f: /* LUI - MIPS I */ - if (RTREG != 0) - UML_MOV(block, R32(RTREG), SIMMVAL << 16); // dmov <rtreg>,SIMMVAL << 16 - return true; - - case 0x08: /* ADDI - MIPS I */ - case 0x09: /* ADDIU - MIPS I */ - if (RTREG != 0) - { - UML_ADD(block, R32(RTREG), R32(RSREG), SIMMVAL); // add i0,<rsreg>,SIMMVAL,V - } - return true; - - case 0x0a: /* SLTI - MIPS I */ - if (RTREG != 0) - { - UML_CMP(block, R32(RSREG), SIMMVAL); // dcmp <rsreg>,SIMMVAL - UML_SETc(block, COND_L, R32(RTREG)); // dset <rtreg>,l - } - return true; - - case 0x0b: /* SLTIU - MIPS I */ - if (RTREG != 0) - { - UML_CMP(block, R32(RSREG), SIMMVAL); // dcmp <rsreg>,SIMMVAL - UML_SETc(block, COND_B, R32(RTREG)); // dset <rtreg>,b - } - return true; - - - case 0x0c: /* ANDI - MIPS I */ - if (RTREG != 0) - UML_AND(block, R32(RTREG), R32(RSREG), UIMMVAL); // dand <rtreg>,<rsreg>,UIMMVAL - return true; - - case 0x0d: /* ORI - MIPS I */ - if (RTREG != 0) - UML_OR(block, R32(RTREG), R32(RSREG), UIMMVAL); // dor <rtreg>,<rsreg>,UIMMVAL - return true; - - case 0x0e: /* XORI - MIPS I */ - if (RTREG != 0) - UML_XOR(block, R32(RTREG), R32(RSREG), UIMMVAL); // dxor <rtreg>,<rsreg>,UIMMVAL - return true; - - /* ----- memory load operations ----- */ - - case 0x20: /* LB - MIPS I */ - UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,<rsreg>,SIMMVAL - UML_CALLH(block, *m_read8); // callh read8 - if (RTREG != 0) - UML_SEXT(block, R32(RTREG), I0, SIZE_BYTE); // dsext <rtreg>,i0,byte - if (!in_delay_slot) - generate_update_cycles(block, compiler, desc->pc + 4, true); - return true; - - case 0x21: /* LH - MIPS I */ - UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,<rsreg>,SIMMVAL - UML_CALLH(block, *m_read16); // callh read16 - if (RTREG != 0) - UML_SEXT(block, R32(RTREG), I0, SIZE_WORD); // dsext <rtreg>,i0,word - if (!in_delay_slot) - generate_update_cycles(block, compiler, desc->pc + 4, true); - return true; - - case 0x23: /* LW - MIPS I */ - UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,<rsreg>,SIMMVAL - UML_CALLH(block, *m_read32); // callh read32 - if (RTREG != 0) - UML_MOV(block, R32(RTREG), I0); - if (!in_delay_slot) - generate_update_cycles(block, compiler, desc->pc + 4, true); - return true; - - case 0x24: /* LBU - MIPS I */ - UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,<rsreg>,SIMMVAL - UML_CALLH(block, *m_read8); // callh read8 - if (RTREG != 0) - UML_AND(block, R32(RTREG), I0, 0xff); // dand <rtreg>,i0,0xff - if (!in_delay_slot) - generate_update_cycles(block, compiler, desc->pc + 4, true); - return true; - - case 0x25: /* LHU - MIPS I */ - UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,<rsreg>,SIMMVAL - UML_CALLH(block, *m_read16); // callh read16 - if (RTREG != 0) - UML_AND(block, R32(RTREG), I0, 0xffff); // dand <rtreg>,i0,0xffff - if (!in_delay_slot) - generate_update_cycles(block, compiler, desc->pc + 4, true); - return true; - - case 0x32: /* LWC2 - MIPS I */ - return m_cop2->generate_lwc2(block, compiler, desc); - - - /* ----- memory store operations ----- */ - - case 0x28: /* SB - MIPS I */ - UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,<rsreg>,SIMMVAL - UML_MOV(block, I1, R32(RTREG)); // mov i1,<rtreg> - UML_CALLH(block, *m_write8); // callh write8 - if (!in_delay_slot) - generate_update_cycles(block, compiler, desc->pc + 4, true); - return true; - - case 0x29: /* SH - MIPS I */ - UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,<rsreg>,SIMMVAL - UML_MOV(block, I1, R32(RTREG)); // mov i1,<rtreg> - UML_CALLH(block, *m_write16); // callh write16 - if (!in_delay_slot) - generate_update_cycles(block, compiler, desc->pc + 4, true); - return true; - - case 0x2b: /* SW - MIPS I */ - UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,<rsreg>,SIMMVAL - UML_MOV(block, I1, R32(RTREG)); // mov i1,<rtreg> - UML_CALLH(block, *m_write32); // callh write32 - if (!in_delay_slot) - generate_update_cycles(block, compiler, desc->pc + 4, true); - return true; - - case 0x3a: /* SWC2 - MIPS I */ - return m_cop2->generate_swc2(block, compiler, desc); - - /* ----- coprocessor instructions ----- */ - - case 0x10: /* COP0 - MIPS I */ - return generate_cop0(block, compiler, desc); - - case 0x12: /* COP2 - MIPS I */ - return m_cop2->generate_cop2(block, compiler, desc); - - - /* ----- unimplemented/illegal instructions ----- */ - - //default: /* ??? */ invalid_instruction(op); break; - } - - return false; -} - - -/*------------------------------------------------- - generate_special - compile opcodes in the - 'SPECIAL' group --------------------------------------------------*/ - -bool rsp_device::generate_special(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc) -{ - uint32_t op = desc->opptr.l[0]; - uint8_t opswitch = op & 63; - //uml::code_label skip; - - switch (opswitch) - { - /* ----- shift instructions ----- */ - - case 0x00: /* SLL - MIPS I */ - if (RDREG != 0) - { - UML_SHL(block, R32(RDREG), R32(RTREG), SHIFT); - } - return true; - - case 0x02: /* SRL - MIPS I */ - if (RDREG != 0) - { - UML_SHR(block, R32(RDREG), R32(RTREG), SHIFT); - } - return true; - - case 0x03: /* SRA - MIPS I */ - if (RDREG != 0) - { - UML_SAR(block, R32(RDREG), R32(RTREG), SHIFT); - } - return true; - - case 0x04: /* SLLV - MIPS I */ - if (RDREG != 0) - { - UML_SHL(block, R32(RDREG), R32(RTREG), R32(RSREG)); - } - return true; - - case 0x06: /* SRLV - MIPS I */ - if (RDREG != 0) - { - UML_SHR(block, R32(RDREG), R32(RTREG), R32(RSREG)); - } - return true; - - case 0x07: /* SRAV - MIPS I */ - if (RDREG != 0) - { - UML_SAR(block, R32(RDREG), R32(RTREG), R32(RSREG)); - } - return true; - - /* ----- basic arithmetic ----- */ - - case 0x20: /* ADD - MIPS I */ - case 0x21: /* ADDU - MIPS I */ - if (RDREG != 0) - { - UML_ADD(block, R32(RDREG), R32(RSREG), R32(RTREG)); - } - return true; - - case 0x22: /* SUB - MIPS I */ - case 0x23: /* SUBU - MIPS I */ - if (RDREG != 0) - { - UML_SUB(block, R32(RDREG), R32(RSREG), R32(RTREG)); - } - return true; - - /* ----- basic logical ops ----- */ - - case 0x24: /* AND - MIPS I */ - if (RDREG != 0) - { - UML_AND(block, R32(RDREG), R32(RSREG), R32(RTREG)); // dand <rdreg>,<rsreg>,<rtreg> - } - return true; - - case 0x25: /* OR - MIPS I */ - if (RDREG != 0) - { - UML_OR(block, R32(RDREG), R32(RSREG), R32(RTREG)); // dor <rdreg>,<rsreg>,<rtreg> - } - return true; - - case 0x26: /* XOR - MIPS I */ - if (RDREG != 0) - { - UML_XOR(block, R32(RDREG), R32(RSREG), R32(RTREG)); // dxor <rdreg>,<rsreg>,<rtreg> - } - return true; - - case 0x27: /* NOR - MIPS I */ - if (RDREG != 0) - { - UML_OR(block, I0, R32(RSREG), R32(RTREG)); // dor i0,<rsreg>,<rtreg> - UML_XOR(block, R32(RDREG), I0, (uint64_t)~0); // dxor <rdreg>,i0,~0 - } - return true; - - - /* ----- basic comparisons ----- */ - - case 0x2a: /* SLT - MIPS I */ - if (RDREG != 0) - { - UML_CMP(block, R32(RSREG), R32(RTREG)); // dcmp <rsreg>,<rtreg> - UML_SETc(block, COND_L, R32(RDREG)); // dset <rdreg>,l - } - return true; - - case 0x2b: /* SLTU - MIPS I */ - if (RDREG != 0) - { - UML_CMP(block, R32(RSREG), R32(RTREG)); // dcmp <rsreg>,<rtreg> - UML_SETc(block, COND_B, R32(RDREG)); // dset <rdreg>,b - } - return true; - - - /* ----- jumps and branches ----- */ - - case 0x08: /* JR - MIPS I */ - generate_delay_slot_and_branch(block, compiler, desc, 0); // <next instruction + hashjmp> - return true; - - case 0x09: /* JALR - MIPS I */ - generate_delay_slot_and_branch(block, compiler, desc, RDREG); // <next instruction + hashjmp> - return true; - - - /* ----- system calls ----- */ - - case 0x0d: /* BREAK - MIPS I */ - UML_MOV(block, mem(&m_rsp_state->arg0), 3); // mov [arg0],3 - UML_CALLC(block, cfunc_sp_set_status_cb, this); // callc cfunc_sp_set_status_cb - UML_MOV(block, mem(&m_rsp_state->icount), 0); // mov icount, #0 - UML_MOV(block, mem(&m_rsp_state->jmpdest), desc->targetpc); - - generate_branch(block, compiler, desc); - - UML_EXIT(block, EXECUTE_OUT_OF_CYCLES); - return true; - } - return false; -} - - - -/*------------------------------------------------- - generate_regimm - compile opcodes in the - 'REGIMM' group --------------------------------------------------*/ - -bool rsp_device::generate_regimm(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc) -{ - uint32_t op = desc->opptr.l[0]; - uint8_t opswitch = RTREG; - uml::code_label skip; - - switch (opswitch) - { - case 0x00: /* BLTZ */ - case 0x10: /* BLTZAL */ - if (RSREG != 0) - { - UML_CMP(block, R32(RSREG), 0); // dcmp <rsreg>,0 - UML_JMPc(block, COND_GE, skip = compiler.labelnum++); // jmp skip,GE - generate_delay_slot_and_branch(block, compiler, desc, (opswitch & 0x10) ? 31 : 0); - // <next instruction + hashjmp> - UML_LABEL(block, skip); // skip: - } - return true; - - case 0x01: /* BGEZ */ - case 0x11: /* BGEZAL */ - if (RSREG != 0) - { - UML_CMP(block, R32(RSREG), 0); // dcmp <rsreg>,0 - UML_JMPc(block, COND_L, skip = compiler.labelnum++); // jmp skip,L - generate_delay_slot_and_branch(block, compiler, desc, (opswitch & 0x10) ? 31 : 0); - // <next instruction + hashjmp> - UML_LABEL(block, skip); // skip: - } - else - generate_delay_slot_and_branch(block, compiler, desc, (opswitch & 0x10) ? 31 : 0); - // <next instruction + hashjmp> - return true; - } - return false; -} - - -/*------------------------------------------------- - generate_cop0 - compile COP0 opcodes --------------------------------------------------*/ - -bool rsp_device::generate_cop0(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc) -{ - uint32_t op = desc->opptr.l[0]; - uint8_t opswitch = RSREG; - - switch (opswitch) - { - case 0x00: /* MFCz */ - if (RTREG != 0) - { - UML_MOV(block, mem(&m_rsp_state->arg0), RDREG); // mov [arg0],<rdreg> - UML_MOV(block, mem(&m_rsp_state->arg1), RTREG); // mov [arg1],<rtreg> - UML_CALLC(block, cfunc_get_cop0_reg, this); // callc cfunc_get_cop0_reg - if(RDREG == 2) - { - generate_update_cycles(block, compiler, uml::mem(&m_rsp_state->pc), true); - UML_HASHJMP(block, 0, mem(&m_rsp_state->pc), *m_nocode); - } - } - return true; - - case 0x04: /* MTCz */ - UML_MOV(block, mem(&m_rsp_state->arg0), RDREG); // mov [arg0],<rdreg> - UML_MOV(block, mem(&m_rsp_state->arg1), R32(RTREG)); // mov [arg1],rtreg - UML_CALLC(block, cfunc_set_cop0_reg, this); // callc cfunc_set_cop0_reg - return true; - } - - return false; -} - -/*************************************************************************** - CODE LOGGING HELPERS -***************************************************************************/ - -/*------------------------------------------------- - log_add_disasm_comment - add a comment - including disassembly of a RSP instruction --------------------------------------------------*/ - -void rsp_device::log_add_disasm_comment(drcuml_block &block, uint32_t pc, uint32_t op) -{ - if (m_drcuml->logging()) - { - rsp_disassembler rspd; - std::ostringstream buffer; - rspd.dasm_one(buffer, pc, op); - block.append_comment("%08X: %s", pc, buffer.str()); // comment - } -} diff --git a/src/devices/cpu/rsp/rspfe.cpp b/src/devices/cpu/rsp/rspfe.cpp deleted file mode 100644 index 83778386a0e..00000000000 --- a/src/devices/cpu/rsp/rspfe.cpp +++ /dev/null @@ -1,307 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Ryan Holtz -/*************************************************************************** - - rspfe.c - - Front-end for RSP recompiler - -***************************************************************************/ - -#include "emu.h" -#include "rspfe.h" - -#include "rspdefs.h" - - -//************************************************************************** -// RSP FRONTEND -//************************************************************************** - -//------------------------------------------------- -// rsp_device::frontend - constructor -//------------------------------------------------- - -rsp_device::frontend::frontend(rsp_device &rsp, uint32_t window_start, uint32_t window_end, uint32_t max_sequence) - : drc_frontend(rsp, window_start, window_end, max_sequence), m_rsp(rsp) -{ -} - - -//------------------------------------------------- -// describe - build a description of a single -// instruction -//------------------------------------------------- - -bool rsp_device::frontend::describe(opcode_desc &desc, const opcode_desc *prev) -{ - uint32_t op, opswitch; - - // fetch the opcode - op = desc.opptr.l[0] = m_rsp.m_pcache.read_dword((desc.physpc & 0x00000fff) | 0x1000); - - // all instructions are 4 bytes and default to a single cycle each - desc.length = 4; - desc.cycles = 1; - - // parse the instruction - opswitch = op >> 26; - switch (opswitch) - { - case 0x00: // SPECIAL - return describe_special(op, desc); - - case 0x01: // REGIMM - return describe_regimm(op, desc); - - case 0x10: // COP0 - return describe_cop0(op, desc); - - case 0x12: // COP2 - return describe_cop2(op, desc); - - case 0x02: // J - desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; - desc.targetpc = ((LIMMVAL << 2) & 0x00000fff) | 0x1000; - desc.delayslots = 1; - return true; - - case 0x03: // JAL - desc.regout[0] |= REGFLAG_R(31); - desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; - desc.targetpc = ((LIMMVAL << 2) & 0x00000fff) | 0x1000; - desc.delayslots = 1; - return true; - - case 0x04: // BEQ - case 0x05: // BNE - if ((opswitch == 0x04 || opswitch == 0x14) && RSREG == RTREG) - desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; - else - { - desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); - desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; - } - desc.targetpc = ((desc.pc + 4 + SIMMVAL * 4) & 0x00000fff) | 0x1000; - desc.delayslots = 1; - desc.skipslots = (opswitch & 0x10) ? 1 : 0; - return true; - - case 0x06: // BLEZ - case 0x07: // BGTZ - if ((opswitch == 0x06 || opswitch == 0x16) && RSREG == 0) - desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; - else - { - desc.regin[0] |= REGFLAG_R(RSREG); - desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; - } - desc.targetpc = ((desc.pc + 4 + SIMMVAL * 4) & 0x00000fff) | 0x1000; - desc.delayslots = 1; - desc.skipslots = (opswitch & 0x10) ? 1 : 0; - return true; - - case 0x08: // ADDI - desc.regin[0] |= REGFLAG_R(RSREG); - desc.regout[0] |= REGFLAG_R(RTREG); - return true; - - case 0x09: // ADDIU - case 0x0a: // SLTI - case 0x0b: // SLTIU - case 0x0c: // ANDI - case 0x0d: // ORI - case 0x0e: // XORI - desc.regin[0] |= REGFLAG_R(RSREG); - desc.regout[0] |= REGFLAG_R(RTREG); - return true; - - case 0x0f: // LUI - desc.regout[0] |= REGFLAG_R(RTREG); - return true; - - case 0x20: // LB - case 0x21: // LH - case 0x23: // LW - case 0x24: // LBU - case 0x25: // LHU - case 0x27: // LWU - desc.regin[0] |= REGFLAG_R(RSREG); - desc.regout[0] |= REGFLAG_R(RTREG); - desc.flags |= OPFLAG_READS_MEMORY; - return true; - - case 0x28: // SB - case 0x29: // SH - case 0x2b: // SW - desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); - desc.flags |= OPFLAG_WRITES_MEMORY; - return true; - - case 0x32: // LWC2 - desc.regin[0] |= REGFLAG_R(RSREG); - desc.flags |= OPFLAG_READS_MEMORY; - return true; - - case 0x3a: // SWC2 - desc.regin[0] |= REGFLAG_R(RSREG); - desc.flags |= OPFLAG_WRITES_MEMORY; - return true; - } - - return false; -} - - -//------------------------------------------------- -// describe_special - build a description of a -// single instruction in the 'special' group -//------------------------------------------------- - -bool rsp_device::frontend::describe_special(uint32_t op, opcode_desc &desc) -{ - switch (op & 63) - { - case 0x00: // SLL - case 0x02: // SRL - case 0x03: // SRA - desc.regin[0] |= REGFLAG_R(RTREG); - desc.regout[0] |= REGFLAG_R(RDREG); - return true; - - case 0x04: // SLLV - case 0x06: // SRLV - case 0x07: // SRAV - case 0x21: // ADDU - case 0x23: // SUBU - case 0x24: // AND - case 0x25: // OR - case 0x26: // XOR - case 0x27: // NOR - case 0x2a: // SLT - case 0x2b: // SLTU - desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); - desc.regout[0] |= REGFLAG_R(RDREG); - return true; - - case 0x20: // ADD - case 0x22: // SUB - desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); - desc.regout[0] |= REGFLAG_R(RDREG); - return true; - - case 0x08: // JR - desc.regin[0] |= REGFLAG_R(RSREG); - desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; - desc.targetpc = BRANCH_TARGET_DYNAMIC; - desc.delayslots = 1; - return true; - - case 0x09: // JALR - desc.regin[0] |= REGFLAG_R(RSREG); - desc.regout[0] |= REGFLAG_R(RDREG); - desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; - desc.targetpc = BRANCH_TARGET_DYNAMIC; - desc.delayslots = 1; - return true; - - case 0x0d: // BREAK - desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; - desc.targetpc = (op >> 5) & 0x000fffff; - return true; - } - - return false; -} - - -//------------------------------------------------- -// describe_regimm - build a description of a -// single instruction in the 'regimm' group -//------------------------------------------------- - -bool rsp_device::frontend::describe_regimm(uint32_t op, opcode_desc &desc) -{ - switch (RTREG) - { - case 0x00: // BLTZ - case 0x01: // BGEZ - if (RTREG == 0x01 && RSREG == 0) - desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; - else - { - desc.regin[0] |= REGFLAG_R(RSREG); - desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; - } - desc.targetpc = ((desc.pc + 4 + SIMMVAL * 4) & 0x00000fff) | 0x1000; - desc.delayslots = 1; - desc.skipslots = (RTREG & 0x02) ? 1 : 0; - return true; - - case 0x10: // BLTZAL - case 0x11: // BGEZAL - if (RTREG == 0x11 && RSREG == 0) - desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; - else - { - desc.regin[0] |= REGFLAG_R(RSREG); - desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; - } - desc.regout[0] |= REGFLAG_R(31); - desc.targetpc = ((desc.pc + 4 + SIMMVAL * 4) & 0x00000fff) | 0x1000; - desc.delayslots = 1; - desc.skipslots = (RTREG & 0x02) ? 1 : 0; - return true; - } - - return false; -} - - -//------------------------------------------------- -// describe_cop0 - build a description of a -// single instruction in the COP0 group -//------------------------------------------------- - -bool rsp_device::frontend::describe_cop0(uint32_t op, opcode_desc &desc) -{ - switch (RSREG) - { - case 0x00: // MFCz - desc.regout[0] |= REGFLAG_R(RTREG); - return true; - - case 0x04: // MTCz - desc.regin[0] |= REGFLAG_R(RTREG); - if(RDREG == 2) // SP_RD_LEN, initiating DMA - { - desc.flags |= OPFLAG_END_SEQUENCE; - } - return true; - } - - return false; -} - -//------------------------------------------------- -// describe_cop2 - build a description of a -// single instruction in the COP2 group -//------------------------------------------------- - -bool rsp_device::frontend::describe_cop2(uint32_t op, opcode_desc &desc) -{ - switch (RSREG) - { - case 0x00: // MFCz - case 0x02: // CFCz - desc.regout[0] |= REGFLAG_R(RTREG); - return true; - - case 0x04: // MTCz - case 0x06: // CTCz - desc.regin[0] |= REGFLAG_R(RTREG); - return true; - } - - return false; -} diff --git a/src/devices/cpu/rsp/rspfe.h b/src/devices/cpu/rsp/rspfe.h deleted file mode 100644 index 5f965a96e11..00000000000 --- a/src/devices/cpu/rsp/rspfe.h +++ /dev/null @@ -1,55 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Ryan Holtz -/*************************************************************************** - - rspfe.h - - Front-end for RSP recompiler - -***************************************************************************/ -#ifndef MAME_CPU_RSP_RSPFE_H -#define MAME_CPU_RSP_RSPFE_H - -#pragma once - -#include "rsp.h" -#include "cpu/drcfe.h" - - -//************************************************************************** -// CONSTANTS -//************************************************************************** - -// register flags 0 -#define REGFLAG_R(n) (((n) == 0) ? 0 : (1 << (n))) - - - -//************************************************************************** -// TYPE DEFINITIONS -//************************************************************************** - -class rsp_device::frontend : public drc_frontend -{ -public: - // construction/destruction - frontend(rsp_device &rsp, uint32_t window_start, uint32_t window_end, uint32_t max_sequence); - -protected: - // required overrides - virtual bool describe(opcode_desc &desc, const opcode_desc *prev) override; - -private: - // internal helpers - bool describe_special(uint32_t op, opcode_desc &desc); - bool describe_regimm(uint32_t op, opcode_desc &desc); - bool describe_cop0(uint32_t op, opcode_desc &desc); - bool describe_cop2(uint32_t op, opcode_desc &desc); - - // internal state - rsp_device &m_rsp; -}; - - - -#endif // MAME_CPU_RSP_RSPFE_H diff --git a/src/devices/cpu/rsp/vabs.h b/src/devices/cpu/rsp/vabs.h deleted file mode 100644 index 273841b9610..00000000000 --- a/src/devices/cpu/rsp/vabs.h +++ /dev/null @@ -1,15 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Tyler J. Stachecki,Ryan Holtz - -inline rsp_vec_t vec_vabs(rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t zero, rsp_vec_t *acc_lo) -{ - rsp_vec_t vs_zero = _mm_cmpeq_epi16(vs, zero); - rsp_vec_t sign_lt = _mm_srai_epi16(vs, 15); - rsp_vec_t vd = _mm_andnot_si128(vs_zero, vt); - - // Careful: if VT = 0x8000 and VS is negative, - // acc_lo will be 0x8000 but vd will be 0x7FFF. - vd = _mm_xor_si128(vd, sign_lt); - *acc_lo = _mm_sub_epi16(vd, sign_lt); - return _mm_subs_epi16(vd, sign_lt); -} diff --git a/src/devices/cpu/rsp/vadd.h b/src/devices/cpu/rsp/vadd.h deleted file mode 100644 index 16009e53287..00000000000 --- a/src/devices/cpu/rsp/vadd.h +++ /dev/null @@ -1,16 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Tyler J. Stachecki,Ryan Holtz - -inline rsp_vec_t vec_vadd(rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t carry, rsp_vec_t *acc_lo) -{ - // VCC uses unsaturated arithmetic. - rsp_vec_t vd = _mm_add_epi16(vs, vt); - *acc_lo = _mm_sub_epi16(vd, carry); - - // VD is the signed sum of the two sources and the carry. Since we - // have to saturate the sum of all three, we have to be clever. - rsp_vec_t minimum = _mm_min_epi16(vs, vt); - rsp_vec_t maximum = _mm_max_epi16(vs, vt); - minimum = _mm_subs_epi16(minimum, carry); - return _mm_adds_epi16(minimum, maximum); -} diff --git a/src/devices/cpu/rsp/vaddc.h b/src/devices/cpu/rsp/vaddc.h deleted file mode 100644 index 0ebd30cbd31..00000000000 --- a/src/devices/cpu/rsp/vaddc.h +++ /dev/null @@ -1,13 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Tyler J. Stachecki,Ryan Holtz - -inline rsp_vec_t vec_vaddc(rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t zero, rsp_vec_t *sn) -{ - rsp_vec_t sat_sum = _mm_adds_epu16(vs, vt); - rsp_vec_t unsat_sum = _mm_add_epi16(vs, vt); - - *sn = _mm_cmpeq_epi16(sat_sum, unsat_sum); - *sn = _mm_cmpeq_epi16(*sn, zero); - - return unsat_sum; -} diff --git a/src/devices/cpu/rsp/vand.h b/src/devices/cpu/rsp/vand.h deleted file mode 100644 index 8f638330e2a..00000000000 --- a/src/devices/cpu/rsp/vand.h +++ /dev/null @@ -1,9 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Tyler J. Stachecki,Ryan Holtz - -inline rsp_vec_t vec_vand_vnand(uint32_t iw, rsp_vec_t vs, rsp_vec_t vt) { - rsp_vec_t vmask = _mm_load_si128((rsp_vec_t *) m_vec_helpers.logic_mask[iw & 0x1]); - - rsp_vec_t vd = _mm_and_si128(vs, vt); - return _mm_xor_si128(vd, vmask); -} diff --git a/src/devices/cpu/rsp/vch.h b/src/devices/cpu/rsp/vch.h deleted file mode 100644 index 6abac437a2c..00000000000 --- a/src/devices/cpu/rsp/vch.h +++ /dev/null @@ -1,57 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Tyler J. Stachecki,Ryan Holtz - -inline rsp_vec_t vec_vch(rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t zero, rsp_vec_t *ge, rsp_vec_t *le, rsp_vec_t *eq, rsp_vec_t *sign, rsp_vec_t *vce) { - // sign = (vs ^ vt) < 0 - *sign = _mm_xor_si128(vs, vt); - *sign = _mm_cmplt_epi16(*sign, zero); - - // sign_negvt = sign ? -vt : vt - rsp_vec_t sign_negvt = _mm_xor_si128(vt, *sign); - sign_negvt = _mm_sub_epi16(sign_negvt, *sign); - - // Compute diff, diff_zero: - rsp_vec_t diff = _mm_sub_epi16(vs, sign_negvt); - rsp_vec_t diff_zero = _mm_cmpeq_epi16(diff, zero); - - // Compute le/ge: - rsp_vec_t vt_neg = _mm_cmplt_epi16(vt, zero); - rsp_vec_t diff_lez = _mm_cmpgt_epi16(diff, zero); - rsp_vec_t diff_gez = _mm_or_si128(diff_lez, diff_zero); - diff_lez = _mm_cmpeq_epi16(zero, diff_lez); - -#if (defined(__SSE4_1__) || defined(_MSC_VER)) - *ge = _mm_blendv_epi8(diff_gez, vt_neg, *sign); - *le = _mm_blendv_epi8(vt_neg, diff_lez, *sign); -#else - *ge = _mm_and_si128(*sign, vt_neg); - diff_gez = _mm_andnot_si128(*sign, diff_gez); - *ge = _mm_or_si128(*ge, diff_gez); - - *le = _mm_and_si128(*sign, diff_lez); - diff_lez = _mm_andnot_si128(*sign, vt_neg); - *le = _mm_or_si128(*le, diff_lez); -#endif - - // Compute vce: - *vce = _mm_cmpeq_epi16(diff, *sign); - *vce = _mm_and_si128(*vce, *sign); - - // Compute !eq: - *eq = _mm_or_si128(diff_zero, *vce); - *eq = _mm_cmpeq_epi16(*eq, zero); - - // Compute result: -#if (defined(__SSE4_1__) || defined(_MSC_VER)) - rsp_vec_t diff_sel_mask = _mm_blendv_epi8(*ge, *le, *sign); - return _mm_blendv_epi8(vs, sign_negvt, diff_sel_mask); -#else - diff_lez = _mm_and_si128(*sign, *le); - diff_gez = _mm_andnot_si128(*sign, *ge); - rsp_vec_t diff_sel_mask = _mm_or_si128(diff_lez, diff_gez); - - diff_lez = _mm_and_si128(diff_sel_mask, sign_negvt); - diff_gez = _mm_andnot_si128(diff_sel_mask, vs); - return _mm_or_si128(diff_lez, diff_gez); -#endif -} diff --git a/src/devices/cpu/rsp/vcl.h b/src/devices/cpu/rsp/vcl.h deleted file mode 100644 index e09a13d5a8e..00000000000 --- a/src/devices/cpu/rsp/vcl.h +++ /dev/null @@ -1,65 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Tyler J. Stachecki,Ryan Holtz - -inline rsp_vec_t vec_vcl(rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t zero, rsp_vec_t *ge, rsp_vec_t *le, rsp_vec_t eq, rsp_vec_t sign, rsp_vec_t vce) -{ - // sign_negvt = sign ? -vt : vt - rsp_vec_t sign_negvt = _mm_xor_si128(vt, sign); - sign_negvt = _mm_sub_epi16(sign_negvt, sign); - - // Compute diff, diff_zero, ncarry, and nvce: - // Note: diff = sign ? (vs + vt) : (vs - vt). - rsp_vec_t diff = _mm_sub_epi16(vs, sign_negvt); - rsp_vec_t ncarry = _mm_adds_epu16(vs, vt); - ncarry = _mm_cmpeq_epi16(diff, ncarry); - rsp_vec_t nvce = _mm_cmpeq_epi16(vce, zero); - rsp_vec_t diff_zero = _mm_cmpeq_epi16(diff, zero); - - // Compute results for if (sign && ne): - rsp_vec_t le_case1 = _mm_and_si128(diff_zero, ncarry); - le_case1 = _mm_and_si128(nvce, le_case1); - rsp_vec_t le_case2 = _mm_or_si128(diff_zero, ncarry); - le_case2 = _mm_and_si128(vce, le_case2); - rsp_vec_t le_eq = _mm_or_si128(le_case1, le_case2); - - // Compute results for if (!sign && ne): - rsp_vec_t ge_eq = _mm_subs_epu16(vt, vs); - ge_eq = _mm_cmpeq_epi16(ge_eq, zero); - - // Blend everything together. Caveat: we don't update - // the results of ge/le if ne is false, so be careful. - rsp_vec_t do_le = _mm_andnot_si128(eq, sign); -#if (defined(__SSE4_1__) || defined(_MSC_VER)) - *le = _mm_blendv_epi8(*le, le_eq, do_le); -#else - le_eq = _mm_and_si128(do_le, le_eq); - *le = _mm_andnot_si128(do_le, *le); - *le = _mm_or_si128(le_eq, *le); -#endif - - rsp_vec_t do_ge = _mm_or_si128(sign, eq); -#if (defined(__SSE4_1__) || defined(_MSC_VER)) - *ge = _mm_blendv_epi8(ge_eq, *ge, do_ge); -#else - *ge = _mm_and_si128(do_ge, *ge); - ge_eq = _mm_andnot_si128(do_ge, ge_eq); - *ge = _mm_or_si128(ge_eq, *ge); -#endif - - // Mux the result based on the value of sign. -#if (defined(__SSE4_1__) || defined(_MSC_VER)) - rsp_vec_t mux_mask = _mm_blendv_epi8(*ge, *le, sign); -#else - do_le = _mm_and_si128(sign, *le); - do_ge = _mm_andnot_si128(sign, *ge); - rsp_vec_t mux_mask = _mm_or_si128(do_le, do_ge); -#endif - -#if (defined(__SSE4_1__) || defined(_MSC_VER)) - return _mm_blendv_epi8(vs, sign_negvt, mux_mask); -#else - sign_negvt = _mm_and_si128(mux_mask, sign_negvt); - vs = _mm_andnot_si128(mux_mask, vs); - return _mm_or_si128(sign_negvt, vs); -#endif -} diff --git a/src/devices/cpu/rsp/vcmp.h b/src/devices/cpu/rsp/vcmp.h deleted file mode 100644 index 7838322d26e..00000000000 --- a/src/devices/cpu/rsp/vcmp.h +++ /dev/null @@ -1,49 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Tyler J. Stachecki,Ryan Holtz - -inline rsp_vec_t vec_veq_vge_vlt_vne(uint32_t iw, rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t zero, rsp_vec_t *le, rsp_vec_t eq, rsp_vec_t sign) -{ - rsp_vec_t equal = _mm_cmpeq_epi16(vs, vt); - - if (iw & 0x2) // VNE & VGE - { - if (iw & 0x1) // VGE - { - rsp_vec_t gt = _mm_cmpgt_epi16(vs, vt); - rsp_vec_t equalsign = _mm_and_si128(eq, sign); - - equal = _mm_andnot_si128(equalsign, equal); - *le = _mm_or_si128(gt, equal); - } - else // VNE - { - rsp_vec_t nequal = _mm_cmpeq_epi16(equal, zero); - - *le = _mm_and_si128(eq, equal); - *le = _mm_or_si128(*le, nequal); - } - } - else // VEQ & VLT - { - if (iw & 0x1) // VEQ - { - *le = _mm_andnot_si128(eq, equal); - } - else // VLT - { - rsp_vec_t lt = _mm_cmplt_epi16(vs, vt); - - equal = _mm_and_si128(eq, equal); - equal = _mm_and_si128(sign, equal); - *le = _mm_or_si128(lt, equal); - } - } - -#if (defined(__SSE4_1__) || defined(_MSC_VER)) - return _mm_blendv_epi8(vt, vs, *le); -#else - vs = _mm_and_si128(*le, vs); - vt = _mm_andnot_si128(*le, vt); - return _mm_or_si128(vs, vt); -#endif -} diff --git a/src/devices/cpu/rsp/vcr.h b/src/devices/cpu/rsp/vcr.h deleted file mode 100644 index 78f78c66244..00000000000 --- a/src/devices/cpu/rsp/vcr.h +++ /dev/null @@ -1,35 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Tyler J. Stachecki,Ryan Holtz - -inline rsp_vec_t vec_vcr(rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t zero, rsp_vec_t *ge, rsp_vec_t *le) { - // sign = (vs ^ vt) < 0 - rsp_vec_t sign = _mm_xor_si128(vs, vt); - sign = _mm_srai_epi16(sign, 15); - - // Compute le - rsp_vec_t diff_lez = _mm_and_si128(vs, sign); - diff_lez = _mm_add_epi16(diff_lez, vt); - *le = _mm_srai_epi16(diff_lez, 15); - - // Compute ge - rsp_vec_t diff_gez = _mm_or_si128(vs, sign); - diff_gez = _mm_min_epi16(diff_gez, vt); - *ge = _mm_cmpeq_epi16(diff_gez, vt); - - // sign_notvt = sn ? ~vt : vt - rsp_vec_t sign_notvt = _mm_xor_si128(vt, sign); - - // Compute result: -#if (defined(__SSE4_1__) || defined(_MSC_VER)) - rsp_vec_t diff_sel_mask = _mm_blendv_epi8(*ge, *le, sign); - return _mm_blendv_epi8(vs, sign_notvt, diff_sel_mask); -#else - rsp_vec_t diff_sel_mask = _mm_sub_epi16(*le, *ge); - diff_sel_mask = _mm_and_si128(diff_sel_mask, sign); - diff_sel_mask = _mm_add_epi16(diff_sel_mask, *ge); - - zero = _mm_sub_epi16(sign_notvt, vs); - zero = _mm_and_si128(zero, diff_sel_mask); - return _mm_add_epi16(zero, vs); -#endif -} diff --git a/src/devices/cpu/rsp/vdivh.h b/src/devices/cpu/rsp/vdivh.h deleted file mode 100644 index 5bd4093f6b4..00000000000 --- a/src/devices/cpu/rsp/vdivh.h +++ /dev/null @@ -1,12 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Tyler J. Stachecki,Ryan Holtz - -inline rsp_vec_t vec_vdivh(uint32_t src, uint32_t e, uint32_t dest, uint32_t de) -{ - // Get the element from VT. - m_div_in = m_v[src].s[e & 0x7]; - - // Write out the upper part of the result. - m_v[dest].s[de & 0x7] = m_div_out; - return vec_load_unshuffled_operand(m_v[dest].s); -} diff --git a/src/devices/cpu/rsp/vldst.h b/src/devices/cpu/rsp/vldst.h deleted file mode 100644 index fadc8be63c0..00000000000 --- a/src/devices/cpu/rsp/vldst.h +++ /dev/null @@ -1,69 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Tyler J. Stachecki,Ryan Holtz - -// LBV, LDV, LLV, LSV, SBV, SDV, SLV, SSV -inline void vec_lbdlsv_sbdlsv(uint32_t iw, uint32_t rs) -{ - const uint32_t shift_and_idx = (iw >> 11) & 0x3; - rsp_vec_t dqm = _mm_loadl_epi64((rsp_vec_t *) (m_vec_helpers.bdls_lut[shift_and_idx])); - - const uint32_t addr = (rs + (sign_extend_6(iw) << shift_and_idx)) & 0xfff; - const uint32_t element = (iw >> 7) & 0xf; - uint16_t* regp = m_v[(iw >> 16) & 0x1f].s; - - if (iw >> 29 & 0x1) - { - vec_store_group1(addr, element, regp, vec_load_unshuffled_operand(regp), dqm); - } - else - { - vec_load_group1(addr, element, regp, vec_load_unshuffled_operand(regp), dqm); - } -} - -// LPV, LUV, SPV, SUV -inline void vec_lfhpuv_sfhpuv(uint32_t iw, uint32_t rs) -{ - static const enum rsp_mem_request_type fhpu_type_lut[4] = { - RSP_MEM_REQUEST_PACK, - RSP_MEM_REQUEST_UPACK, - RSP_MEM_REQUEST_HALF, - RSP_MEM_REQUEST_FOURTH - }; - - const uint32_t addr = (rs + (sign_extend_6(iw) << 3)) & 0xfff; - const uint32_t element = (iw >> 7) & 0xf; - uint16_t* regp = m_v[(iw >> 16) & 0x1f].s; - - rsp_mem_request_type request_type = fhpu_type_lut[((iw >> 11) & 0x1f) - 6]; - if ((iw >> 29) & 0x1) - { - vec_store_group2(addr, element, regp, vec_load_unshuffled_operand(regp), _mm_setzero_si128(), request_type); - } - else - { - vec_load_group2(addr, element, regp, vec_load_unshuffled_operand(regp), _mm_setzero_si128(), request_type); - } -} - -// LQV, LRV, SQV, SRV -inline void vec_lqrv_sqrv(uint32_t iw, uint32_t rs) -{ - rs &= 0xfff; - - const uint32_t addr = rs + (sign_extend_6(iw) << 4); - const uint32_t element = (iw >> 7) & 0xf; - uint16_t* regp = m_v[(iw >> 16) & 0x1f].s; - - memcpy(m_vdqm.s, m_vec_helpers.qr_lut[addr & 0xf], sizeof(m_vdqm.s)); - - rsp_mem_request_type request_type = (iw >> 11 & 0x1) ? RSP_MEM_REQUEST_REST : RSP_MEM_REQUEST_QUAD; - if ((iw >> 29) & 0x1) - { - vec_store_group4(addr, element, regp, vec_load_unshuffled_operand(regp), vec_load_unshuffled_operand(m_vdqm.s), request_type); - } - else - { - vec_load_group4(addr, element, regp, vec_load_unshuffled_operand(regp), vec_load_unshuffled_operand(m_vdqm.s), request_type); - } -} diff --git a/src/devices/cpu/rsp/vmac.h b/src/devices/cpu/rsp/vmac.h deleted file mode 100644 index ade43511daa..00000000000 --- a/src/devices/cpu/rsp/vmac.h +++ /dev/null @@ -1,57 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Tyler J. Stachecki,Ryan Holtz - -inline rsp_vec_t vec_vmacf_vmacu(uint32_t iw, rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t zero, rsp_vec_t *acc_lo, rsp_vec_t *acc_mid, rsp_vec_t *acc_hi) -{ - // Get the product and shift it over - // being sure to save the carries. - rsp_vec_t lo = _mm_mullo_epi16(vs, vt); - rsp_vec_t hi = _mm_mulhi_epi16(vs, vt); - - rsp_vec_t mid = _mm_slli_epi16(hi, 1); - rsp_vec_t carry = _mm_srli_epi16(lo, 15); - hi = _mm_srai_epi16(hi, 15); - mid = _mm_or_si128(mid, carry); - lo = _mm_slli_epi16(lo, 1); - - // Tricky part: start accumulating everything. - // Get/keep the carry as we'll add it in later. - rsp_vec_t overflow_mask = _mm_adds_epu16(*acc_lo, lo); - *acc_lo = _mm_add_epi16(*acc_lo, lo); - - overflow_mask = _mm_cmpeq_epi16(*acc_lo, overflow_mask); - overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero); - - // Add in the carry. If the middle portion is - // already 0xFFFF and we have a carry, we have - // to carry the all the way up to hi. - mid = _mm_sub_epi16(mid, overflow_mask); - carry = _mm_cmpeq_epi16(mid, zero); - carry = _mm_and_si128(carry, overflow_mask); - hi = _mm_sub_epi16(hi, carry); - - // Accumulate the middle portion. - overflow_mask = _mm_adds_epu16(*acc_mid, mid); - *acc_mid = _mm_add_epi16(*acc_mid, mid); - - overflow_mask = _mm_cmpeq_epi16(*acc_mid, overflow_mask); - overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero); - - // Finish up the accumulation of the... accumulator. - *acc_hi = _mm_add_epi16(*acc_hi, hi); - *acc_hi = _mm_sub_epi16(*acc_hi, overflow_mask); - - if (iw & 0x1) // VMACU - { - rsp_vec_t overflow_hi_mask = _mm_srai_epi16(*acc_hi, 15); - rsp_vec_t overflow_mid_mask = _mm_srai_epi16(*acc_mid, 15); - mid = _mm_or_si128(overflow_mid_mask, *acc_mid); - overflow_mask = _mm_cmpgt_epi16(*acc_hi, zero); - mid = _mm_andnot_si128(overflow_hi_mask, mid); - return _mm_or_si128(overflow_mask, mid); - } - else // VMACF - { - return sclamp_acc_to_mid(*acc_mid, *acc_hi); - } -} diff --git a/src/devices/cpu/rsp/vmov.h b/src/devices/cpu/rsp/vmov.h deleted file mode 100644 index 59e02e8b118..00000000000 --- a/src/devices/cpu/rsp/vmov.h +++ /dev/null @@ -1,9 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Tyler J. Stachecki,Ryan Holtz - -inline rsp_vec_t vec_vmov(uint32_t src, uint32_t e, uint32_t dest, uint32_t de) -{ - // Get the element from VT and write out the upper part of the result. - m_v[dest].s[de & 0x7] = m_v[src].s[e & 0x7]; - return vec_load_unshuffled_operand(m_v[dest].s); -} diff --git a/src/devices/cpu/rsp/vmrg.h b/src/devices/cpu/rsp/vmrg.h deleted file mode 100644 index ab9be63ef16..00000000000 --- a/src/devices/cpu/rsp/vmrg.h +++ /dev/null @@ -1,13 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Tyler J. Stachecki,Ryan Holtz - -inline rsp_vec_t vec_vmrg(rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t le) -{ -#if (defined(__SSE4_1__) || defined(_MSC_VER)) - return _mm_blendv_epi8(vt, vs, le); -#else - vs = _mm_and_si128(le, vs); - vt = _mm_andnot_si128(le, vt); - return _mm_or_si128(vs, vt); -#endif -} diff --git a/src/devices/cpu/rsp/vmudh.h b/src/devices/cpu/rsp/vmudh.h deleted file mode 100644 index 71c3a38f4fb..00000000000 --- a/src/devices/cpu/rsp/vmudh.h +++ /dev/null @@ -1,10 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Tyler J. Stachecki,Ryan Holtz - -inline rsp_vec_t rsp_vmudh(rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t *acc_md, rsp_vec_t *acc_hi) -{ - *acc_md = _mm_mullo_epi16(vs, vt); - *acc_hi = _mm_mulhi_epi16(vs, vt); - - return sclamp_acc_to_mid(*acc_md, *acc_hi); -} diff --git a/src/devices/cpu/rsp/vmul.h b/src/devices/cpu/rsp/vmul.h deleted file mode 100644 index dc09e81768a..00000000000 --- a/src/devices/cpu/rsp/vmul.h +++ /dev/null @@ -1,39 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Tyler J. Stachecki,Ryan Holtz - -// -// TODO: CHECK ME. -// - -inline rsp_vec_t vec_vmulf_vmulu(uint32_t iw, rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t zero, rsp_vec_t *acc_lo, rsp_vec_t *acc_md, rsp_vec_t *acc_hi) -{ - rsp_vec_t lo = _mm_mullo_epi16(vs, vt); - rsp_vec_t round = _mm_cmpeq_epi16(zero, zero); - rsp_vec_t sign1 = _mm_srli_epi16(lo, 15); - lo = _mm_add_epi16(lo, lo); - round = _mm_slli_epi16(round, 15); - rsp_vec_t hi = _mm_mulhi_epi16(vs, vt); - rsp_vec_t sign2 = _mm_srli_epi16(lo, 15); - *acc_lo = _mm_add_epi16(round, lo); - sign1 = _mm_add_epi16(sign1, sign2); - - hi = _mm_slli_epi16(hi, 1); - rsp_vec_t eq = _mm_cmpeq_epi16(vs, vt); - rsp_vec_t neq = eq; - *acc_md = _mm_add_epi16(hi, sign1); - - rsp_vec_t neg = _mm_srai_epi16(*acc_md, 15); - - if (iw & 0x1) // VMULU - { - *acc_hi = _mm_andnot_si128(eq, neg); - hi =_mm_or_si128(*acc_md, neg); - return _mm_andnot_si128(*acc_hi, hi); - } - else // VMULF - { - eq = _mm_and_si128(eq, neg); - *acc_hi = _mm_andnot_si128(neq, neg); - return _mm_add_epi16(*acc_md, eq); - } -} diff --git a/src/devices/cpu/rsp/vmulh.h b/src/devices/cpu/rsp/vmulh.h deleted file mode 100644 index 6265961f5a0..00000000000 --- a/src/devices/cpu/rsp/vmulh.h +++ /dev/null @@ -1,30 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Tyler J. Stachecki,Ryan Holtz - -inline rsp_vec_t vec_vmadh_vmudh(uint32_t iw, rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t zero, rsp_vec_t *acc_lo, rsp_vec_t *acc_md, rsp_vec_t *acc_hi) -{ - rsp_vec_t lo = _mm_mullo_epi16(vs, vt); - rsp_vec_t hi = _mm_mulhi_epi16(vs, vt); - - if (iw & 0x8) // VMADH - { - // Tricky part: start accumulating everything. - // Get/keep the carry as we'll add it in later. - rsp_vec_t overflow_mask = _mm_adds_epu16(*acc_md, lo); - *acc_md = _mm_add_epi16(*acc_md, lo); - - overflow_mask = _mm_cmpeq_epi16(*acc_md, overflow_mask); - overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero); - - hi = _mm_sub_epi16(hi, overflow_mask); - *acc_hi = _mm_add_epi16(*acc_hi, hi); - } - else // VMUDH - { - *acc_lo = zero; - *acc_md = lo; - *acc_hi = hi; - } - - return sclamp_acc_to_mid(*acc_md, *acc_hi); -} diff --git a/src/devices/cpu/rsp/vmull.h b/src/devices/cpu/rsp/vmull.h deleted file mode 100644 index e54399b01da..00000000000 --- a/src/devices/cpu/rsp/vmull.h +++ /dev/null @@ -1,44 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Tyler J. Stachecki,Ryan Holtz - -inline rsp_vec_t vec_vmadl_vmudl(uint32_t iw, rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t zero, rsp_vec_t *acc_lo, rsp_vec_t *acc_md, rsp_vec_t *acc_hi) -{ - rsp_vec_t hi = _mm_mulhi_epu16(vs, vt); - - if (iw & 0x8) // VMADL - { - // Tricky part: start accumulating everything. - // Get/keep the carry as we'll add it in later. - rsp_vec_t overflow_mask = _mm_adds_epu16(*acc_lo, hi); - *acc_lo = _mm_add_epi16(*acc_lo, hi); - - overflow_mask = _mm_cmpeq_epi16(*acc_lo, overflow_mask); - overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero); - hi = _mm_sub_epi16(zero, overflow_mask); - - // Check for overflow of the upper sum. - // - // TODO: Since hi can only be {0,1}, we should - // be able to generalize this for performance. - overflow_mask = _mm_adds_epu16(*acc_md, hi); - *acc_md = _mm_add_epi16(*acc_md, hi); - - overflow_mask = _mm_cmpeq_epi16(*acc_md, overflow_mask); - overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero); - - // Finish up the accumulation of the... accumulator. - // Since the product was unsigned, only worry about - // positive overflow (i.e.: borrowing not possible). - *acc_hi = _mm_sub_epi16(*acc_hi, overflow_mask); - - return uclamp_acc(*acc_lo, *acc_md, *acc_hi, zero); - } - else // VMUDL - { - *acc_lo = hi; - *acc_md = zero; - *acc_hi = zero; - - return hi; - } -} diff --git a/src/devices/cpu/rsp/vmulm.h b/src/devices/cpu/rsp/vmulm.h deleted file mode 100644 index df76833ed0c..00000000000 --- a/src/devices/cpu/rsp/vmulm.h +++ /dev/null @@ -1,56 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Tyler J. Stachecki,Ryan Holtz - -inline rsp_vec_t vec_vmadm_vmudm(uint32_t iw, rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t zero, rsp_vec_t *acc_lo, rsp_vec_t *acc_md, rsp_vec_t *acc_hi) -{ - rsp_vec_t lo = _mm_mullo_epi16(vs, vt); - rsp_vec_t hi = _mm_mulhi_epu16(vs, vt); - - // What we really want to do is unsigned vs * signed vt. - // However, we have no such instructions to do so. - // - // There's a trick to "fix" an unsigned product, though: - // If vt was negative, take the upper 16-bits of the product - // and subtract vs. - rsp_vec_t sign = _mm_srai_epi16(vs, 15); - vt = _mm_and_si128(vt, sign); - hi = _mm_sub_epi16(hi, vt); - - if (iw & 0x8) // VMADM - { - // Tricky part: start accumulating everything. - // Get/keep the carry as we'll add it in later. - rsp_vec_t overflow_mask = _mm_adds_epu16(*acc_lo, lo); - *acc_lo = _mm_add_epi16(*acc_lo, lo); - - overflow_mask = _mm_cmpeq_epi16(*acc_lo, overflow_mask); - overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero); - - // This is REALLY clever. Since the product results from - // two 16-bit components, one positive and one negative, - // we don't have to worry about carrying the 1 (we can - // only borrow) past 32-bits. So we can just add it here. - hi = _mm_sub_epi16(hi, overflow_mask); - - // Check for overflow of the upper sum. - overflow_mask = _mm_adds_epu16(*acc_md, hi); - *acc_md = _mm_add_epi16(*acc_md, hi); - - overflow_mask = _mm_cmpeq_epi16(*acc_md, overflow_mask); - overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero); - - // Finish up the accumulation of the... accumulator. - *acc_hi = _mm_add_epi16(*acc_hi, _mm_srai_epi16(hi, 15)); - *acc_hi = _mm_sub_epi16(*acc_hi, overflow_mask); - - return sclamp_acc_to_mid(*acc_md, *acc_hi); - } - else // VMUDM - { - *acc_lo = lo; - *acc_md = hi; - *acc_hi = _mm_srai_epi16(hi, 15); - - return hi; - } -} diff --git a/src/devices/cpu/rsp/vmuln.h b/src/devices/cpu/rsp/vmuln.h deleted file mode 100644 index 07453b631a8..00000000000 --- a/src/devices/cpu/rsp/vmuln.h +++ /dev/null @@ -1,55 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Tyler J. Stachecki,Ryan Holtz - -inline rsp_vec_t vec_vmadn_vmudn(uint32_t iw, rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t zero, rsp_vec_t *acc_lo, rsp_vec_t *acc_md, rsp_vec_t *acc_hi) -{ - rsp_vec_t lo = _mm_mullo_epi16(vs, vt); - rsp_vec_t hi = _mm_mulhi_epu16(vs, vt); - - // What we really want to do is unsigned vs * signed vt. - // However, we have no such instructions to do so. - // - // There's a trick to "fix" an unsigned product, though: - // If vt was negative, take the upper 16-bits of the product - // and subtract vs. - rsp_vec_t sign = _mm_srai_epi16(vt, 15); - vs = _mm_and_si128(vs, sign); - hi = _mm_sub_epi16(hi, vs); - - if (iw & 0x8) // VMADN - { - // Tricky part: start accumulating everything. - // Get/keep the carry as we'll add it in later. - rsp_vec_t overflow_mask = _mm_adds_epu16(*acc_lo, lo); - *acc_lo = _mm_add_epi16(*acc_lo, lo); - - overflow_mask = _mm_cmpeq_epi16(*acc_lo, overflow_mask); - overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero); - - // This is REALLY clever. Since the product results from - // two 16-bit components, one positive and one negative, - // we don't have to worry about carrying the 1 (we can - // only borrow) past 32-bits. So we can just add it here. - hi = _mm_sub_epi16(hi, overflow_mask); - - // Check for overflow of the upper sum. - overflow_mask = _mm_adds_epu16(*acc_md, hi); - *acc_md = _mm_add_epi16(*acc_md, hi); - - overflow_mask = _mm_cmpeq_epi16(*acc_md, overflow_mask); - overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero); - - // Finish up the accumulation of the... accumulator. - *acc_hi = _mm_add_epi16(*acc_hi, _mm_srai_epi16(hi, 15)); - *acc_hi = _mm_sub_epi16(*acc_hi, overflow_mask); - return uclamp_acc(*acc_lo, *acc_md, *acc_hi, zero); - } - else // VMUDN - { - *acc_lo = lo; - *acc_md = hi; - *acc_hi = _mm_srai_epi16(hi, 15); - - return lo; - } -} diff --git a/src/devices/cpu/rsp/vor.h b/src/devices/cpu/rsp/vor.h deleted file mode 100644 index 07cbb57164c..00000000000 --- a/src/devices/cpu/rsp/vor.h +++ /dev/null @@ -1,10 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Tyler J. Stachecki,Ryan Holtz - -inline rsp_vec_t vec_vor_vnor(uint32_t iw, rsp_vec_t vs, rsp_vec_t vt) -{ - rsp_vec_t vmask = _mm_load_si128((rsp_vec_t *) m_vec_helpers.logic_mask[iw & 0x1]); - - rsp_vec_t vd = _mm_or_si128(vs, vt); - return _mm_xor_si128(vd, vmask); -} diff --git a/src/devices/cpu/rsp/vrcpsq.h b/src/devices/cpu/rsp/vrcpsq.h deleted file mode 100644 index 4897e536193..00000000000 --- a/src/devices/cpu/rsp/vrcpsq.h +++ /dev/null @@ -1,58 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Tyler J. Stachecki,Ryan Holtz - -inline rsp_vec_t vec_vrcp_vrsq(uint32_t iw, int32_t dp, uint32_t src, uint32_t e, uint32_t dest, uint32_t de) -{ - // Get the element from VT. - int16_t vt = m_v[src].s[e & 0x7]; - - uint32_t dp_input = ((uint32_t) m_div_in << 16) | (uint16_t) vt; - uint32_t sp_input = vt; - - int32_t input = (dp) ? dp_input : sp_input; - int32_t input_mask = input >> 31; - int32_t data = input ^ input_mask; - - if (input > -32768) - { - data -= input_mask; - } - - // Handle edge cases. - int32_t result; - if (data == 0) - { - result = 0x7fffffff; - } - else if (input == -32768) - { - result = 0xffff0000; - } - else // Main case: compute the reciprocal. - { - uint32_t shift = count_leading_zeros(data); - uint32_t idx = (((uint64_t) data << shift) & 0x7FC00000) >> 22; - - if (iw & 0x4) // VRSQ - { - idx = ((idx | 0x200) & 0x3fe) | (shift % 2); - result = rsp_divtable[idx]; - - result = ((0x10000 | result) << 14) >> ((31 - shift) >> 1); - } - else // VRCP - { - result = rsp_divtable[idx]; - - result = ((0x10000 | result) << 14) >> (31 - shift); - } - - result = result ^ input_mask; - } - - // Write out the results. - m_div_out = result >> 16; - m_v[dest].s[de & 0x7] = result; - - return vec_load_unshuffled_operand(m_v[dest].s); -} diff --git a/src/devices/cpu/rsp/vrsq.h b/src/devices/cpu/rsp/vrsq.h deleted file mode 100644 index d4bdb190fec..00000000000 --- a/src/devices/cpu/rsp/vrsq.h +++ /dev/null @@ -1,66 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Tyler J. Stachecki,Ryan Holtz - -rsp_vec_t vec_vrsq(int32_t dp, uint32_t src, uint32_t e, uint32_t dest, uint32_t de) -{ - // Get the element from VT. - int16_t vt = m_v[src].s[e & 0x7]; - - uint32_t dp_input = ((uint32_t) m_div_in << 16) | (uint16_t) vt; - uint32_t sp_input = vt; - - int32_t input = (dp) ? dp_input : sp_input; - int32_t input_mask = input >> 31; - int32_t data = input ^ input_mask; - - if (input > -32768) - { - data -= input_mask; - } - - // Handle edge cases. - int32_t result; - if (data == 0) - { - result = 0x7fffffff; - } - else if (input == -32768) - { - result = 0xffff0000; - } - else // Main case: compute the reciprocal. - { - uint32_t shift = count_leading_zeros(data); - - uint32_t idx = (((uint64_t) data << shift) & 0x7fc00000) >> 22; - idx = ((idx | 0x200) & 0x3fe) | (shift % 2); - result = rsp_divtable[idx]; - - result = ((0x10000 | result) << 14) >> ((31 - shift) >> 1); - result = result ^ input_mask; - } - - // Write out the results. - m_div_out = result >> 16; - m_v[dest].s[de & 0x7] = result; - - return vec_load_unshuffled_operand(m_v[dest].s); -} - -rsp_vec_t vec_vrsqh(uint32_t src, uint32_t e, uint32_t dest, uint32_t de) -{ - int16_t elements[8]; - - // Get the element from VT. - memcpy(elements, &m_v[src], sizeof(rsp_vec_t)); - m_div_in = elements[e]; - - // Write out the upper part of the result. - rsp_vec_t vd_mask = _mm_load_si128((rsp_vec_t *) m_vec_helpers.vrsq_mask_table[de]); - rsp_vec_t vd = _mm_load_si128((rsp_vec_t *) &m_v[dest]); - vd = _mm_andnot_si128(vd_mask, vd); - - rsp_vec_t b_result = _mm_set1_epi16(m_div_out); - b_result = _mm_and_si128(vd_mask, b_result); - return _mm_or_si128(b_result, vd); -} diff --git a/src/devices/cpu/rsp/vsub.h b/src/devices/cpu/rsp/vsub.h deleted file mode 100644 index c3df93627c8..00000000000 --- a/src/devices/cpu/rsp/vsub.h +++ /dev/null @@ -1,17 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Tyler J. Stachecki,Ryan Holtz - -inline rsp_vec_t vec_vsub(rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t carry, rsp_vec_t *acc_lo) -{ - // acc_lo uses saturated arithmetic. - rsp_vec_t unsat_diff = _mm_sub_epi16(vt, carry); - rsp_vec_t sat_diff = _mm_subs_epi16(vt, carry); - - *acc_lo = _mm_sub_epi16(vs, unsat_diff); - rsp_vec_t vd = _mm_subs_epi16(vs, sat_diff); - - // VD is the signed diff of the two sources and the carry. Since we - // have to saturate the diff of all three, we have to be clever. - rsp_vec_t overflow = _mm_cmpgt_epi16(sat_diff, unsat_diff); - return _mm_adds_epi16(vd, overflow); -} diff --git a/src/devices/cpu/rsp/vsubc.h b/src/devices/cpu/rsp/vsubc.h deleted file mode 100644 index 8632b9462d9..00000000000 --- a/src/devices/cpu/rsp/vsubc.h +++ /dev/null @@ -1,14 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Tyler J. Stachecki,Ryan Holtz - -inline rsp_vec_t vec_vsubc(rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t zero, rsp_vec_t *eq, rsp_vec_t *sn) -{ - rsp_vec_t sat_udiff = _mm_subs_epu16(vs, vt); - rsp_vec_t equal = _mm_cmpeq_epi16(vs, vt); - rsp_vec_t sat_udiff_zero = _mm_cmpeq_epi16(sat_udiff, zero); - - *eq = _mm_cmpeq_epi16(equal, zero); - *sn = _mm_andnot_si128(equal, sat_udiff_zero); - - return _mm_sub_epi16(vs, vt); -} diff --git a/src/devices/cpu/rsp/vxor.h b/src/devices/cpu/rsp/vxor.h deleted file mode 100644 index 9f7f62853c5..00000000000 --- a/src/devices/cpu/rsp/vxor.h +++ /dev/null @@ -1,10 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Tyler J. Stachecki,Ryan Holtz - -inline rsp_vec_t vec_vxor_vnxor(uint32_t iw, rsp_vec_t vs, rsp_vec_t vt) -{ - rsp_vec_t vmask = _mm_load_si128((rsp_vec_t *) m_vec_helpers.logic_mask[iw & 0x1]); - - rsp_vec_t vd = _mm_xor_si128(vs, vt); - return _mm_xor_si128(vd, vmask); -} |